[llvm] ca8f82b - [KnownFPClass] Restrict KnownFPClass::bitcast/toKnownBits deductions to verified FP semantics (#221133)

via llvm-commits llvm-commits at lists.llvm.org
Sat Sep 12 16:10:05 PDT 2026


Author: Eric Ross
Date: 2026-09-12T17:10:00-06:00
New Revision: ca8f82b625494996d4f9f61f30d25b62a5660dca

URL: https://github.com/llvm/llvm-project/commit/ca8f82b625494996d4f9f61f30d25b62a5660dca
DIFF: https://github.com/llvm/llvm-project/commit/ca8f82b625494996d4f9f61f30d25b62a5660dca.diff

LOG: [KnownFPClass] Restrict KnownFPClass::bitcast/toKnownBits deductions to verified FP semantics (#221133)

`KnownFPClass::bitcast` and `KnownFPClass::toKnownBits` previously made
deductions for floating-point semantics whose bit representations had
not been verified.

I have made it so `KnownFPClass::bitcast` and
`KnownFPClass::toKnownBits` return `fcAllFlags`/unknown for any
`APFloat` semantics we have not verified. Currently, this prevents
potentially invalid deductions for `PPCDoubleDouble` (mostly in regards
to the signbit and endianess). It also allows these functions to be
"safely" used with the 4/6/8 bit floating point types since we
conservatively return unknown.

Currently the list of supported/verified semantics for both `bitcast`
and `toKnownBits` are:
```
IEEEhalf
BFloat
IEEEsingle
IEEEdouble
IEEEquad
x87DoubleExtended
```

Added: 
    

Modified: 
    llvm/lib/Support/KnownFPClass.cpp
    llvm/test/Transforms/InstCombine/known-bits.ll
    llvm/unittests/Support/KnownFPClassTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Support/KnownFPClass.cpp b/llvm/lib/Support/KnownFPClass.cpp
index 75636ffc73361..b23a0dbbac4fb 100644
--- a/llvm/lib/Support/KnownFPClass.cpp
+++ b/llvm/lib/Support/KnownFPClass.cpp
@@ -241,6 +241,23 @@ KnownFPClass KnownFPClass::bitcast(const fltSemantics &FltSemantics,
   if (Bits.hasConflict())
     return Known;
 
+  // Return unknown for types we have not validated.
+  auto IsSupported = [](const fltSemantics &Semantics) {
+    switch (APFloat::SemanticsToEnum(Semantics)) {
+    case APFloatBase::S_IEEEhalf:
+    case APFloatBase::S_BFloat:
+    case APFloatBase::S_IEEEsingle:
+    case APFloatBase::S_IEEEdouble:
+    case APFloatBase::S_IEEEquad:
+    case APFloatBase::S_x87DoubleExtended:
+      return true;
+    default:
+      return false;
+    }
+  };
+  if (!IsSupported(FltSemantics))
+    return Known;
+
   // Transfer information from the sign bit.
   if (Bits.isNonNegative())
     Known.signBitMustBeZero();
@@ -304,6 +321,23 @@ KnownBits KnownFPClass::toKnownBits(const fltSemantics &FltSemantics) const {
   if (FPClasses == fcNone)
     return Known;
 
+  // Return unknown for types we have not validated.
+  auto IsSupported = [](const fltSemantics &Semantics) {
+    switch (APFloat::SemanticsToEnum(Semantics)) {
+    case APFloatBase::S_IEEEhalf:
+    case APFloatBase::S_BFloat:
+    case APFloatBase::S_IEEEsingle:
+    case APFloatBase::S_IEEEdouble:
+    case APFloatBase::S_IEEEquad:
+    case APFloatBase::S_x87DoubleExtended:
+      return true;
+    default:
+      return false;
+    }
+  };
+  if (!IsSupported(FltSemantics))
+    return Known;
+
   if (isKnownNever(fcNormal | fcSubnormal | fcNan)) {
     Known.setAllConflict();
 

diff  --git a/llvm/test/Transforms/InstCombine/known-bits.ll b/llvm/test/Transforms/InstCombine/known-bits.ll
index 8582d44fade63..f7d8ff7fffbbe 100644
--- a/llvm/test/Transforms/InstCombine/known-bits.ll
+++ b/llvm/test/Transforms/InstCombine/known-bits.ll
@@ -1539,7 +1539,9 @@ define i16 @test_inf_only_bfloat(bfloat nofpclass(nan sub norm zero) %x) {
 
 define i128 @test_inf_only_ppc_fp128(ppc_fp128 nofpclass(nan sub norm zero) %x) {
 ; CHECK-LABEL: @test_inf_only_ppc_fp128(
-; CHECK-NEXT:    ret i128 9218868437227405312
+; CHECK-NEXT:    [[TMP1:%.*]] = call ppc_fp128 @llvm.fabs.ppcf128(ppc_fp128 [[X:%.*]])
+; CHECK-NEXT:    [[AND:%.*]] = bitcast ppc_fp128 [[TMP1]] to i128
+; CHECK-NEXT:    ret i128 [[AND]]
 ;
   %y = bitcast ppc_fp128 %x to i128
   %and = and i128 %y, 170141183460469231731687303715884105727

diff  --git a/llvm/unittests/Support/KnownFPClassTest.cpp b/llvm/unittests/Support/KnownFPClassTest.cpp
index 4c3e1596b8e33..681b2d27fb547 100644
--- a/llvm/unittests/Support/KnownFPClassTest.cpp
+++ b/llvm/unittests/Support/KnownFPClassTest.cpp
@@ -128,4 +128,75 @@ TEST(KnownFPClassTest, BitcastConstant) {
   }
 }
 
+TEST(KnownFPClassTest, BitcastUnsupported) {
+  auto IsSupported = [](const fltSemantics &Semantics) {
+    switch (APFloat::SemanticsToEnum(Semantics)) {
+    case APFloatBase::S_IEEEhalf:
+    case APFloatBase::S_BFloat:
+    case APFloatBase::S_IEEEsingle:
+    case APFloatBase::S_IEEEdouble:
+    case APFloatBase::S_IEEEquad:
+    case APFloatBase::S_x87DoubleExtended:
+      return true;
+    default:
+      return false;
+    }
+  };
+
+  for (unsigned I = 0; I != APFloat::S_MaxSemantics + 1; ++I) {
+    APFloat::Semantics SemanticsKind = static_cast<APFloat::Semantics>(I);
+    const fltSemantics &Semantics = APFloat::EnumToSemantics(SemanticsKind);
+
+    for (const APInt &ValueBits : {APInt::getZero(Semantics.sizeInBits),
+                                   APInt::getAllOnes(Semantics.sizeInBits)}) {
+      SCOPED_TRACE(testing::Message()
+                   << "Semantics = " << I << ", bits = " << ValueBits);
+      KnownFPClass Known =
+          KnownFPClass::bitcast(Semantics, KnownBits::makeConstant(ValueBits));
+      if (IsSupported(Semantics)) {
+        // We should be able to make at least one deduction for "Supported"
+        // types.
+        EXPECT_FALSE(Known.isUnknown());
+      } else {
+        EXPECT_TRUE(Known.isUnknown());
+      }
+    }
+  }
+}
+
+TEST(KnownFPClassTest, ToKnownBitsUnsupported) {
+  auto IsSupported = [](const fltSemantics &Semantics) {
+    switch (APFloat::SemanticsToEnum(Semantics)) {
+    case APFloatBase::S_IEEEhalf:
+    case APFloatBase::S_BFloat:
+    case APFloatBase::S_IEEEsingle:
+    case APFloatBase::S_IEEEdouble:
+    case APFloatBase::S_IEEEquad:
+    case APFloatBase::S_x87DoubleExtended:
+      return true;
+    default:
+      return false;
+    }
+  };
+
+  for (unsigned I = 0; I != APFloat::S_MaxSemantics + 1; ++I) {
+    APFloat::Semantics SemanticsKind = static_cast<APFloat::Semantics>(I);
+    const fltSemantics &Semantics = APFloat::EnumToSemantics(SemanticsKind);
+
+    for (FPClassTest FPClass : {fcPosZero, fcPosNormal}) {
+      SCOPED_TRACE(testing::Message()
+                   << "Semantics = " << I << ", class = " << FPClass);
+      KnownBits Known = KnownFPClass(FPClass, false).toKnownBits(Semantics);
+      if (IsSupported(Semantics)) {
+        // The following expectations are true for all "supported" types.
+        EXPECT_TRUE(Known.isNonNegative());
+        if (FPClass == fcPosZero)
+          EXPECT_TRUE(Known.isZero());
+      } else {
+        EXPECT_TRUE(Known.isUnknown());
+      }
+    }
+  }
+}
+
 } // end anonymous namespace


        


More information about the llvm-commits mailing list