[llvm] [KnownFPClass] Improve KnownFPClass::toKnownBits deductions for IEEE types (PR #223204)
Eric Ross via llvm-commits
llvm-commits at lists.llvm.org
Sun Sep 13 16:58:30 PDT 2026
https://github.com/ZERICO2005 updated https://github.com/llvm/llvm-project/pull/223204
>From bb3d9e1db73f846aab130ef57dbc57eb9d2221f8 Mon Sep 17 00:00:00 2001
From: zerico <zerico2005 at gmail.com>
Date: Fri, 4 Sep 2026 21:33:01 -0600
Subject: [PATCH] [KnownFPClass] Improve KnownFPClass::toKnownBits deductions
for IEEE types
---
llvm/lib/Support/KnownFPClass.cpp | 71 ++++-
.../InstCombine/known-bits-bitcast-from-fp.ll | 249 ++++++++++++++++--
2 files changed, 302 insertions(+), 18 deletions(-)
diff --git a/llvm/lib/Support/KnownFPClass.cpp b/llvm/lib/Support/KnownFPClass.cpp
index b23a0dbbac4fb..af88358936d25 100644
--- a/llvm/lib/Support/KnownFPClass.cpp
+++ b/llvm/lib/Support/KnownFPClass.cpp
@@ -338,7 +338,68 @@ KnownBits KnownFPClass::toKnownBits(const fltSemantics &FltSemantics) const {
if (!IsSupported(FltSemantics))
return Known;
- if (isKnownNever(fcNormal | fcSubnormal | fcNan)) {
+ switch (APFloat::SemanticsToEnum(FltSemantics)) {
+ case APFloatBase::S_IEEEhalf:
+ case APFloatBase::S_BFloat:
+ case APFloatBase::S_IEEEsingle:
+ case APFloatBase::S_IEEEdouble:
+ case APFloatBase::S_IEEEquad: {
+ // For ieee types, we cannot deduce anything if the source could be normal.
+ if (FPClasses & fcNormal)
+ break;
+
+ Known.setAllConflict();
+
+ const unsigned BitWidth = FltSemantics.sizeInBits;
+ const unsigned MantissaBits = FltSemantics.precision - 1;
+ const unsigned ExponentBits = BitWidth - MantissaBits - 1;
+
+ APInt MantissaMask = APInt::getLowBitsSet(BitWidth, MantissaBits);
+ APInt ExponentMask =
+ APInt::getBitsSet(BitWidth, MantissaBits, MantissaBits + ExponentBits);
+
+ const unsigned QuietBitIndex = MantissaBits - 1;
+ APInt PayloadMask = MantissaMask;
+ PayloadMask.clearBit(QuietBitIndex);
+
+ if (FPClasses & fcNan) {
+ // Exponent bits cannot be zeros.
+ Known.Zero &= ~ExponentMask;
+ // No individual payload bit is known.
+ Known.Zero &= ~PayloadMask;
+ Known.One &= ~PayloadMask;
+
+ if (FPClasses & fcQNan)
+ Known.Zero.clearBit(QuietBitIndex);
+ if (FPClasses & fcSNan)
+ Known.One.clearBit(QuietBitIndex);
+ }
+ if (FPClasses & fcInf) {
+ // Exponent bits cannot be zeros.
+ Known.Zero &= ~ExponentMask;
+ // Mantissa bits cannot be ones.
+ Known.One &= ~MantissaMask;
+ }
+ if (FPClasses & fcSubnormal) {
+ // Exponent bits cannot be ones.
+ Known.One &= ~ExponentMask;
+ // Unknown mantissa.
+ Known.One &= ~MantissaMask;
+ Known.Zero &= ~MantissaMask;
+ }
+ if (FPClasses & fcZero) {
+ // Exponent bits cannot be ones.
+ Known.One &= ~ExponentMask;
+ // Mantissa cannot be ones.
+ Known.One &= ~MantissaMask;
+ }
+
+ break;
+ }
+ case APFloatBase::S_x87DoubleExtended: {
+ if (!isKnownNever(fcNormal | fcSubnormal | fcNan))
+ break;
+
Known.setAllConflict();
if (FPClasses & fcInf)
@@ -349,10 +410,14 @@ KnownBits KnownFPClass::toKnownBits(const fltSemantics &FltSemantics) const {
Known = Known.intersectWith(
KnownBits::makeConstant(APInt::getZero(FltSemantics.sizeInBits)));
- Known.Zero.clearSignBit();
- Known.One.clearSignBit();
+ break;
+ }
+ default:
+ llvm_unreachable("unhandled supported semantics");
}
+ Known.Zero.clearSignBit();
+ Known.One.clearSignBit();
if (std::optional<bool> Sign = getSignBit()) {
if (*Sign)
Known.makeNegative();
diff --git a/llvm/test/Transforms/InstCombine/known-bits-bitcast-from-fp.ll b/llvm/test/Transforms/InstCombine/known-bits-bitcast-from-fp.ll
index ff707b8824365..10ea9fd50dca8 100644
--- a/llvm/test/Transforms/InstCombine/known-bits-bitcast-from-fp.ll
+++ b/llvm/test/Transforms/InstCombine/known-bits-bitcast-from-fp.ll
@@ -104,9 +104,7 @@ define i80 @test_zero_only_non_ieee(x86_fp80 nofpclass(nan sub norm inf) %x) {
define i32 @test_inf_nan_only(float nofpclass(sub norm zero) %x) {
; CHECK-LABEL: @test_inf_nan_only(
-; CHECK-NEXT: [[Y:%.*]] = bitcast float [[X:%.*]] to i32
-; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y]], 2130706432
-; CHECK-NEXT: ret i32 [[AND]]
+; CHECK-NEXT: ret i32 2130706432
;
%y = bitcast float %x to i32
%and = and i32 %y, 2130706432
@@ -115,9 +113,7 @@ define i32 @test_inf_nan_only(float nofpclass(sub norm zero) %x) {
define i32 @test_sub_zero_only(float nofpclass(nan norm inf) %x) {
; CHECK-LABEL: @test_sub_zero_only(
-; CHECK-NEXT: [[Y:%.*]] = bitcast float [[X:%.*]] to i32
-; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y]], 2130706432
-; CHECK-NEXT: ret i32 [[AND]]
+; CHECK-NEXT: ret i32 0
;
%y = bitcast float %x to i32
%and = and i32 %y, 2130706432
@@ -170,9 +166,7 @@ define i1 @test_simplify_icmp(i32 %x) {
define i32 @test_snan_quiet_bit1(float nofpclass(sub norm inf qnan) %x) {
; CHECK-LABEL: @test_snan_quiet_bit1(
-; CHECK-NEXT: [[BITS:%.*]] = bitcast float [[X:%.*]] to i32
-; CHECK-NEXT: [[MASKED:%.*]] = and i32 [[BITS]], 4194304
-; CHECK-NEXT: ret i32 [[MASKED]]
+; CHECK-NEXT: ret i32 0
;
%bits = bitcast float %x to i32
%masked = and i32 %bits, 4194304
@@ -212,6 +206,186 @@ define i32 @test_qnan_quiet_bit2(float nofpclass(sub norm inf snan) %x) {
ret i32 %masked
}
+define i16 @test_f16_quiet_bit_clear(half nofpclass(qnan norm sub) %x) {
+; CHECK-LABEL: @test_f16_quiet_bit_clear(
+; CHECK-NEXT: ret i16 0
+;
+ %bits = bitcast half %x to i16
+ %masked = and i16 %bits, u0x0200
+ ret i16 %masked
+}
+
+define i16 @test_f16_quiet_bit_set(half nofpclass(snan inf zero norm sub) %x) {
+; CHECK-LABEL: @test_f16_quiet_bit_set(
+; CHECK-NEXT: ret i16 512
+;
+ %bits = bitcast half %x to i16
+ %masked = and i16 %bits, u0x0200
+ ret i16 %masked
+}
+
+define i16 @test_f16_all_zeros_exponent(half nofpclass(nan inf norm) %x) {
+; CHECK-LABEL: @test_f16_all_zeros_exponent(
+; CHECK-NEXT: ret i16 0
+;
+ %bits = bitcast half %x to i16
+ %masked = and i16 %bits, u0x7C00
+ ret i16 %masked
+}
+
+define i16 @test_f16_all_ones_exponent(half nofpclass(zero norm sub) %x) {
+; CHECK-LABEL: @test_f16_all_ones_exponent(
+; CHECK-NEXT: ret i16 31744
+;
+ %bits = bitcast half %x to i16
+ %masked = and i16 %bits, u0x7C00
+ ret i16 %masked
+}
+
+define i16 @test_bf16_quiet_bit_clear(bfloat nofpclass(qnan norm sub) %x) {
+; CHECK-LABEL: @test_bf16_quiet_bit_clear(
+; CHECK-NEXT: ret i16 0
+;
+ %bits = bitcast bfloat %x to i16
+ %masked = and i16 %bits, u0x0040
+ ret i16 %masked
+}
+
+define i16 @test_bf16_quiet_bit_set(bfloat nofpclass(snan inf zero norm sub) %x) {
+; CHECK-LABEL: @test_bf16_quiet_bit_set(
+; CHECK-NEXT: ret i16 64
+;
+ %bits = bitcast bfloat %x to i16
+ %masked = and i16 %bits, u0x0040
+ ret i16 %masked
+}
+
+define i16 @test_bf16_all_zeros_exponent(bfloat nofpclass(nan inf norm) %x) {
+; CHECK-LABEL: @test_bf16_all_zeros_exponent(
+; CHECK-NEXT: ret i16 0
+;
+ %bits = bitcast bfloat %x to i16
+ %masked = and i16 %bits, u0x7F80
+ ret i16 %masked
+}
+
+define i16 @test_bf16_all_ones_exponent(bfloat nofpclass(zero norm sub) %x) {
+; CHECK-LABEL: @test_bf16_all_ones_exponent(
+; CHECK-NEXT: ret i16 32640
+;
+ %bits = bitcast bfloat %x to i16
+ %masked = and i16 %bits, u0x7F80
+ ret i16 %masked
+}
+
+define i32 @test_f32_quiet_bit_clear(float nofpclass(qnan norm sub) %x) {
+; CHECK-LABEL: @test_f32_quiet_bit_clear(
+; CHECK-NEXT: ret i32 0
+;
+ %bits = bitcast float %x to i32
+ %masked = and i32 %bits, u0x00400000
+ ret i32 %masked
+}
+
+define i32 @test_f32_quiet_bit_set(float nofpclass(snan inf zero norm sub) %x) {
+; CHECK-LABEL: @test_f32_quiet_bit_set(
+; CHECK-NEXT: ret i32 4194304
+;
+ %bits = bitcast float %x to i32
+ %masked = and i32 %bits, u0x00400000
+ ret i32 %masked
+}
+
+define i32 @test_f32_all_zeros_exponent(float nofpclass(nan inf norm) %x) {
+; CHECK-LABEL: @test_f32_all_zeros_exponent(
+; CHECK-NEXT: ret i32 0
+;
+ %bits = bitcast float %x to i32
+ %masked = and i32 %bits, u0x7F800000
+ ret i32 %masked
+}
+
+define i32 @test_f32_all_ones_exponent(float nofpclass(zero norm sub) %x) {
+; CHECK-LABEL: @test_f32_all_ones_exponent(
+; CHECK-NEXT: ret i32 2139095040
+;
+ %bits = bitcast float %x to i32
+ %masked = and i32 %bits, u0x7F800000
+ ret i32 %masked
+}
+
+define i64 @test_f64_quiet_bit_clear(double nofpclass(qnan norm sub) %x) {
+; CHECK-LABEL: @test_f64_quiet_bit_clear(
+; CHECK-NEXT: ret i64 0
+;
+ %bits = bitcast double %x to i64
+ %masked = and i64 %bits, u0x0008000000000000
+ ret i64 %masked
+}
+
+define i64 @test_f64_quiet_bit_set(double nofpclass(snan inf zero norm sub) %x) {
+; CHECK-LABEL: @test_f64_quiet_bit_set(
+; CHECK-NEXT: ret i64 2251799813685248
+;
+ %bits = bitcast double %x to i64
+ %masked = and i64 %bits, u0x0008000000000000
+ ret i64 %masked
+}
+
+define i64 @test_f64_all_zeros_exponent(double nofpclass(nan inf norm) %x) {
+; CHECK-LABEL: @test_f64_all_zeros_exponent(
+; CHECK-NEXT: ret i64 0
+;
+ %bits = bitcast double %x to i64
+ %masked = and i64 %bits, u0x7FF0000000000000
+ ret i64 %masked
+}
+
+define i64 @test_f64_all_ones_exponent(double nofpclass(zero norm sub) %x) {
+; CHECK-LABEL: @test_f64_all_ones_exponent(
+; CHECK-NEXT: ret i64 9218868437227405312
+;
+ %bits = bitcast double %x to i64
+ %masked = and i64 %bits, u0x7FF0000000000000
+ ret i64 %masked
+}
+
+define i128 @test_f128_quiet_bit_clear(fp128 nofpclass(qnan norm sub) %x) {
+; CHECK-LABEL: @test_f128_quiet_bit_clear(
+; CHECK-NEXT: ret i128 0
+;
+ %bits = bitcast fp128 %x to i128
+ %masked = and i128 %bits, u0x00008000000000000000000000000000
+ ret i128 %masked
+}
+
+define i128 @test_f128_quiet_bit_set(fp128 nofpclass(snan inf zero norm sub) %x) {
+; CHECK-LABEL: @test_f128_quiet_bit_set(
+; CHECK-NEXT: ret i128 2596148429267413814265248164610048
+;
+ %bits = bitcast fp128 %x to i128
+ %masked = and i128 %bits, u0x00008000000000000000000000000000
+ ret i128 %masked
+}
+
+define i128 @test_f128_all_zeros_exponent(fp128 nofpclass(nan inf norm) %x) {
+; CHECK-LABEL: @test_f128_all_zeros_exponent(
+; CHECK-NEXT: ret i128 0
+;
+ %bits = bitcast fp128 %x to i128
+ %masked = and i128 %bits, u0x7FFF0000000000000000000000000000
+ ret i128 %masked
+}
+
+define i128 @test_f128_all_ones_exponent(fp128 nofpclass(zero norm sub) %x) {
+; CHECK-LABEL: @test_f128_all_ones_exponent(
+; CHECK-NEXT: ret i128 170135991163610696904058773219554885632
+;
+ %bits = bitcast fp128 %x to i128
+ %masked = and i128 %bits, u0x7FFF0000000000000000000000000000
+ ret i128 %masked
+}
+
define i16 @test_simplify_mask(i32 %ui, float %x) {
; CHECK-LABEL: @test_simplify_mask(
; CHECK-NEXT: [[CONV:%.*]] = uitofp i32 [[UI:%.*]] to float
@@ -261,25 +435,70 @@ if.else:
ret i1 false
}
-define i32 @test_snan_only(float nofpclass(qnan sub norm zero inf) %x) {
+define i32 @test_snan_only(float nofpclass(qnan inf zero norm sub) %x) {
; CHECK-LABEL: @test_snan_only(
+; CHECK-NEXT: ret i32 2139095040
+;
+ %y = bitcast float %x to i32
+ %and = and i32 %y, u0x7FC00000
+ ret i32 %and
+}
+
+define i32 @test_qnan_only(float nofpclass(snan inf zero norm sub) %x) {
+; CHECK-LABEL: @test_qnan_only(
+; CHECK-NEXT: ret i32 2143289344
+;
+ %y = bitcast float %x to i32
+ %and = and i32 %y, u0x7FC00000
+ ret i32 %and
+}
+
+define i32 @test_nan_only_include_quiet_bit(float nofpclass(inf zero norm sub) %x) {
+; CHECK-LABEL: @test_nan_only_include_quiet_bit(
; CHECK-NEXT: [[Y:%.*]] = bitcast float [[X:%.*]] to i32
-; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y]], 4194304
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y]], 2143289344
; CHECK-NEXT: ret i32 [[AND]]
;
%y = bitcast float %x to i32
- %and = and i32 %y, 4194304
+ %and = and i32 %y, u0x7FC00000
ret i32 %and
}
-define i32 @test_qnan_only(float nofpclass(snan sub norm zero inf) %x) {
-; CHECK-LABEL: @test_qnan_only(
+define i32 @test_nan_only_exclude_quiet_bit(float nofpclass(inf zero norm sub) %x) {
+; CHECK-LABEL: @test_nan_only_exclude_quiet_bit(
+; CHECK-NEXT: ret i32 2139095040
+;
+ %y = bitcast float %x to i32
+ %and = and i32 %y, u0x7F800000
+ ret i32 %and
+}
+
+define i32 @test_normal_only(float nofpclass(nan inf zero sub) %x) {
+; CHECK-LABEL: @test_normal_only(
; CHECK-NEXT: [[Y:%.*]] = bitcast float [[X:%.*]] to i32
; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y]], 4194304
; CHECK-NEXT: ret i32 [[AND]]
;
%y = bitcast float %x to i32
- %and = and i32 %y, 4194304
+ %and = and i32 %y, u0x00400000
+ ret i32 %and
+}
+
+define i32 @test_pos_normal_only(float nofpclass(nan inf zero nnorm sub) %x) {
+; CHECK-LABEL: @test_pos_normal_only(
+; CHECK-NEXT: ret i32 0
+;
+ %y = bitcast float %x to i32
+ %and = and i32 %y, u0x80000000
+ ret i32 %and
+}
+
+define i32 @test_neg_normal_only(float nofpclass(nan inf zero pnorm sub) %x) {
+; CHECK-LABEL: @test_neg_normal_only(
+; CHECK-NEXT: ret i32 -2147483648
+;
+ %y = bitcast float %x to i32
+ %and = and i32 %y, u0x80000000
ret i32 %and
}
More information about the llvm-commits
mailing list