Author: adams381
Date: 2026-06-29T15:04:43-05:00
New Revision: b81dc125427ae769a270d160fe731e7ae40343c5

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

LOG: [CIR] Model cir.is_fp_class flags as a bit-enum

`__builtin_isfpclass(x, flags)` takes an arbitrary 10-bit floating-point class 
mask, but `cir.is_fp_class` modeled its `flags` operand as a closed 
`I32EnumAttr` that only accepted the enumerated values. The generated 
`FPClassTestAttr::get` casts an `IntegerAttr` to `FPClassTestAttr`, and its 
`classof` rejects any non-enumerated mask, so CIRGen aborted on something as 
simple as `__builtin_isfpclass(x, 5)` (`fcSNan|fcNegInf`). The named 
classification builtins (`isnan`, `isinf`, `isfinite`, ...) dodged it only 
because they pass values that happen to be enumerated composites.

This remodels `FPClassTestEnum` as a bit-enum. The ten classes become 
single-bit cases at positions 0-9 (matching `llvm::FPClassTest`), with `fcNone` 
as the zero case and the composite aliases (`fcNan`, `fcInf`, `fcFinite`, and 
the rest) as case groups, so the generated `cir::FPClassTest::X` members and 
every existing call site keep working unchanged. Any mask in 0-1023 is now 
representable, and flags print pipe-delimited (`"fcSNan|fcNegInf"`) with 
`printBitEnumPrimaryGroups` so an exact group still prints as its keyword 
(`"fcInf"`). It adds a small `CIR_I32BitEnumAttr` wrapper, the dialect's first 
bit-enum.

`createIsFPClass` masks the flags to the valid 0-9 range (and asserts on stray 
bits) so the op cannot be built with an out-of-range mask; Sema already bounds 
the `__builtin_isfpclass` argument to `fcAllFlags`, so that path only guards 
against an internal slip.

@erichkeane suggested the bit-enum approach over a plain integer attribute; 
this follows that. `builtin-isfpclass.c` picks up non-enumerated-mask coverage, 
and the printed-flag form in the other `is_fp_class` tests is updated for the 
new syntax.

Added: 
    

Modified: 
    clang/include/clang/CIR/Dialect/IR/CIREnumAttr.td
    clang/include/clang/CIR/Dialect/IR/CIROps.td
    clang/lib/CIR/CodeGen/CIRGenBuilder.h
    clang/test/CIR/CodeGenBuiltins/builtin-fpclassify.c
    clang/test/CIR/CodeGenBuiltins/builtin-isfpclass.c
    clang/test/CIR/CodeGenBuiltins/builtin-isinf-sign.c

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/CIR/Dialect/IR/CIREnumAttr.td 
b/clang/include/clang/CIR/Dialect/IR/CIREnumAttr.td
index cc6f256ddfef4..f75598d6ca75c 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIREnumAttr.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIREnumAttr.td
@@ -26,6 +26,12 @@ class CIR_I64EnumAttr<string name, string summary, 
list<I64EnumAttrCase> cases>
   let cppNamespace = "::cir";
 }
 
+class CIR_I32BitEnumAttr<string name, string summary,
+                         list<BitEnumCaseBase> cases>
+    : I32BitEnumAttr<name, summary, cases> {
+  let cppNamespace = "::cir";
+}
+
 class CIR_EnumAttr<EnumAttrInfo info, string name = "", list<Trait> traits = 
[]>
     : EnumAttr<CIR_Dialect, info, name, traits> {
   let assemblyFormat = "`<` $value `>`";

diff  --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 7d1c48b994b27..2c3bf51f5cc8d 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -6431,33 +6431,55 @@ def CIR_RotateOp : CIR_Op<"rotate", [Pure, 
SameOperandsAndResultType]> {
 // FPClass Test Flags
 
//===----------------------------------------------------------------------===//
 
-def FPClassTestEnum : CIR_I32EnumAttr<"FPClassTest", "floating-point class 
test flags", [
-  // Basic flags
-  I32EnumAttrCase<"SignalingNaN", 1, "fcSNan">,
-  I32EnumAttrCase<"QuietNaN", 2, "fcQNan">,
-  I32EnumAttrCase<"NegativeInfinity", 4, "fcNegInf">,
-  I32EnumAttrCase<"NegativeNormal", 8, "fcNegNormal">,
-  I32EnumAttrCase<"NegativeSubnormal", 16, "fcNegSubnormal">,
-  I32EnumAttrCase<"NegativeZero", 32, "fcNegZero">,
-  I32EnumAttrCase<"PositiveZero", 64, "fcPosZero">,
-  I32EnumAttrCase<"PositiveSubnormal", 128, "fcPosSubnormal">,
-  I32EnumAttrCase<"PositiveNormal", 256, "fcPosNormal">,
-  I32EnumAttrCase<"PositiveInfinity", 512, "fcPosInf">,
-
-  // Composite flags
-  I32EnumAttrCase<"Nan", 3, "fcNan">,                   // fcSNan | fcQNan
-  I32EnumAttrCase<"Infinity", 516, "fcInf">,            // fcPosInf | fcNegInf
-  I32EnumAttrCase<"Normal", 264, "fcNormal">,           // fcPosNormal | 
fcNegNormal
-  I32EnumAttrCase<"Subnormal", 144, "fcSubnormal">,     // fcPosSubnormal | 
fcNegSubnormal
-  I32EnumAttrCase<"Zero", 96, "fcZero">,                // fcPosZero | 
fcNegZero
-  I32EnumAttrCase<"PositiveFinite", 448, "fcPosFinite">,// fcPosNormal | 
fcPosSubnormal | fcPosZero
-  I32EnumAttrCase<"NegativeFinite", 56, "fcNegFinite">, // fcNegNormal | 
fcNegSubnormal | fcNegZero
-  I32EnumAttrCase<"Finite", 504, "fcFinite">,           // fcPosFinite | 
fcNegFinite
-  I32EnumAttrCase<"Positive", 960, "fcPositive">,       // fcPosFinite | 
fcPosInf
-  I32EnumAttrCase<"Negative", 60, "fcNegative">,        // fcNegFinite | 
fcNegInf
-  I32EnumAttrCase<"All", 1023, "fcAllFlags">,           // fcNan | fcInf | 
fcFinite
-]> {
-  let cppNamespace = "::cir";
+// Individual floating-point classes, one per bit (positions 0-9), matching
+// LLVM's `FPClassTest` bit layout (`llvm/ADT/FloatingPointMode.h`).  Modeled
+// as a bit-enum so `__builtin_isfpclass` can pass any combination of bits.
+def FPClass_None     : I32BitEnumAttrCaseNone<"None", "fcNone">;
+def FPClass_SNan     : I32BitEnumAttrCaseBit<"SignalingNaN", 0, "fcSNan">;
+def FPClass_QNan     : I32BitEnumAttrCaseBit<"QuietNaN", 1, "fcQNan">;
+def FPClass_NegInf   : I32BitEnumAttrCaseBit<"NegativeInfinity", 2, 
"fcNegInf">;
+def FPClass_NegNorm  : I32BitEnumAttrCaseBit<"NegativeNormal", 3, 
"fcNegNormal">;
+def FPClass_NegSub   : I32BitEnumAttrCaseBit<"NegativeSubnormal", 4,
+                                             "fcNegSubnormal">;
+def FPClass_NegZero  : I32BitEnumAttrCaseBit<"NegativeZero", 5, "fcNegZero">;
+def FPClass_PosZero  : I32BitEnumAttrCaseBit<"PositiveZero", 6, "fcPosZero">;
+def FPClass_PosSub   : I32BitEnumAttrCaseBit<"PositiveSubnormal", 7,
+                                             "fcPosSubnormal">;
+def FPClass_PosNorm  : I32BitEnumAttrCaseBit<"PositiveNormal", 8, 
"fcPosNormal">;
+def FPClass_PosInf   : I32BitEnumAttrCaseBit<"PositiveInfinity", 9, 
"fcPosInf">;
+
+// Composite groups (aliases for combinations of the individual classes).
+def FPClass_Nan      : I32BitEnumAttrCaseGroup<"Nan",
+    [FPClass_SNan, FPClass_QNan], "fcNan">;
+def FPClass_Inf      : I32BitEnumAttrCaseGroup<"Infinity",
+    [FPClass_NegInf, FPClass_PosInf], "fcInf">;
+def FPClass_Norm     : I32BitEnumAttrCaseGroup<"Normal",
+    [FPClass_NegNorm, FPClass_PosNorm], "fcNormal">;
+def FPClass_Sub      : I32BitEnumAttrCaseGroup<"Subnormal",
+    [FPClass_NegSub, FPClass_PosSub], "fcSubnormal">;
+def FPClass_Zero     : I32BitEnumAttrCaseGroup<"Zero",
+    [FPClass_NegZero, FPClass_PosZero], "fcZero">;
+def FPClass_PosFin   : I32BitEnumAttrCaseGroup<"PositiveFinite",
+    [FPClass_PosNorm, FPClass_PosSub, FPClass_PosZero], "fcPosFinite">;
+def FPClass_NegFin   : I32BitEnumAttrCaseGroup<"NegativeFinite",
+    [FPClass_NegNorm, FPClass_NegSub, FPClass_NegZero], "fcNegFinite">;
+def FPClass_Fin      : I32BitEnumAttrCaseGroup<"Finite",
+    [FPClass_PosFin, FPClass_NegFin], "fcFinite">;
+def FPClass_Pos      : I32BitEnumAttrCaseGroup<"Positive",
+    [FPClass_PosFin, FPClass_PosInf], "fcPositive">;
+def FPClass_Neg      : I32BitEnumAttrCaseGroup<"Negative",
+    [FPClass_NegFin, FPClass_NegInf], "fcNegative">;
+def FPClass_All      : I32BitEnumAttrCaseGroup<"All",
+    [FPClass_Nan, FPClass_Inf, FPClass_Fin], "fcAllFlags">;
+
+def FPClassTestEnum
+    : CIR_I32BitEnumAttr<"FPClassTest", "floating-point class test flags", [
+  FPClass_None, FPClass_SNan, FPClass_QNan, FPClass_NegInf, FPClass_NegNorm,
+  FPClass_NegSub, FPClass_NegZero, FPClass_PosZero, FPClass_PosSub,
+  FPClass_PosNorm, FPClass_PosInf, FPClass_Nan, FPClass_Inf, FPClass_Norm,
+  FPClass_Sub, FPClass_Zero, FPClass_PosFin, FPClass_NegFin, FPClass_Fin,
+  FPClass_Pos, FPClass_Neg, FPClass_All]> {
+  let printBitEnumPrimaryGroups = 1;
 }
 
 def CIR_IsFPClassOp : CIR_Op<"is_fp_class", [Pure]> {

diff  --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h 
b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
index cc1ff1e32521f..d588da06d4669 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -561,6 +561,13 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
   
//===--------------------------------------------------------------------===//
   cir::IsFPClassOp createIsFPClass(mlir::Location loc, mlir::Value src,
                                    cir::FPClassTest flags) {
+    // FPClassTest occupies bits 0-9 (fcAllFlags).  Sema rejects an
+    // out-of-range __builtin_isfpclass mask, so any extra bit here is an
+    // internal error; assert and mask it off so lowering stays well-formed.
+    uint32_t raw = static_cast<uint32_t>(flags);
+    uint32_t all = static_cast<uint32_t>(cir::FPClassTest::All);
+    assert((raw & ~all) == 0 && "FPClassTest mask has bits outside 0-9");
+    flags = static_cast<cir::FPClassTest>(raw & all);
     return cir::IsFPClassOp::create(*this, loc, src, flags);
   }
 

diff  --git a/clang/test/CIR/CodeGenBuiltins/builtin-fpclassify.c 
b/clang/test/CIR/CodeGenBuiltins/builtin-fpclassify.c
index bad83c4f0ef4c..7ebc3c7b2fdfc 100644
--- a/clang/test/CIR/CodeGenBuiltins/builtin-fpclassify.c
+++ b/clang/test/CIR/CodeGenBuiltins/builtin-fpclassify.c
@@ -15,16 +15,16 @@ void test_fpclassify_nan(){
     float nanValue = 0.0f / 0.0f;
     __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL,
                                          FP_SUBNORMAL, FP_ZERO, nanValue);
-// CIR: %[[IS_ZERO:.+]] = cir.is_fp_class %{{.+}}, fcZero : (!cir.float) -> 
!cir.bool
+// CIR: %[[IS_ZERO:.+]] = cir.is_fp_class %{{.+}}, "fcZero" : (!cir.float) -> 
!cir.bool
 // CIR: cir.ternary(%[[IS_ZERO]], true {
 // CIR: cir.const #cir.int<96> : !s32i
-// CIR: %[[IS_NAN:.+]] = cir.is_fp_class %{{.+}}, fcNan : (!cir.float) -> 
!cir.bool
+// CIR: %[[IS_NAN:.+]] = cir.is_fp_class %{{.+}}, "fcNan" : (!cir.float) -> 
!cir.bool
 // CIR: cir.ternary(%[[IS_NAN]], true {
 // CIR: cir.const #cir.int<3> : !s32i
-// CIR: %[[IS_INF:.+]] = cir.is_fp_class %{{.+}}, fcInf : (!cir.float) -> 
!cir.bool
+// CIR: %[[IS_INF:.+]] = cir.is_fp_class %{{.+}}, "fcInf" : (!cir.float) -> 
!cir.bool
 // CIR: cir.ternary(%[[IS_INF]], true {
 // CIR: cir.const #cir.int<516> : !s32i
-// CIR: %[[IS_NORMAL:.+]] = cir.is_fp_class %{{.+}}, fcNormal : (!cir.float) 
-> !cir.bool
+// CIR: %[[IS_NORMAL:.+]] = cir.is_fp_class %{{.+}}, "fcNormal" : (!cir.float) 
-> !cir.bool
 // CIR: %[[NORMAL_VAL:.+]] = cir.const #cir.int<264> : !s32i
 // CIR: %[[SUBNORMAL_VAL:.+]] = cir.const #cir.int<144> : !s32i
 // CIR: cir.select if %[[IS_NORMAL]] then %[[NORMAL_VAL]] else 
%[[SUBNORMAL_VAL]] : (!cir.bool, !s32i, !s32i) -> !s32i
@@ -84,16 +84,16 @@ void test_fpclassify_inf(){
     float infValue = 1.0f / 0.0f;
     __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL,
                                          FP_SUBNORMAL, FP_ZERO, infValue);
-// CIR: %[[IS_ZERO:.+]] = cir.is_fp_class %{{.+}}, fcZero : (!cir.float) -> 
!cir.bool
+// CIR: %[[IS_ZERO:.+]] = cir.is_fp_class %{{.+}}, "fcZero" : (!cir.float) -> 
!cir.bool
 // CIR: cir.ternary(%[[IS_ZERO]], true {
 // CIR: cir.const #cir.int<96> : !s32i
-// CIR: %[[IS_NAN:.+]] = cir.is_fp_class %{{.+}}, fcNan : (!cir.float) -> 
!cir.bool
+// CIR: %[[IS_NAN:.+]] = cir.is_fp_class %{{.+}}, "fcNan" : (!cir.float) -> 
!cir.bool
 // CIR: cir.ternary(%[[IS_NAN]], true {
 // CIR: cir.const #cir.int<3> : !s32i
-// CIR: %[[IS_INF:.+]] = cir.is_fp_class %{{.+}}, fcInf : (!cir.float) -> 
!cir.bool
+// CIR: %[[IS_INF:.+]] = cir.is_fp_class %{{.+}}, "fcInf" : (!cir.float) -> 
!cir.bool
 // CIR: cir.ternary(%[[IS_INF]], true {
 // CIR: cir.const #cir.int<516> : !s32i
-// CIR: %[[IS_NORMAL:.+]] = cir.is_fp_class %{{.+}}, fcNormal : (!cir.float) 
-> !cir.bool
+// CIR: %[[IS_NORMAL:.+]] = cir.is_fp_class %{{.+}}, "fcNormal" : (!cir.float) 
-> !cir.bool
 // CIR: %[[NORMAL_VAL:.+]] = cir.const #cir.int<264> : !s32i
 // CIR: %[[SUBNORMAL_VAL:.+]] = cir.const #cir.int<144> : !s32i
 // CIR: cir.select if %[[IS_NORMAL]] then %[[NORMAL_VAL]] else 
%[[SUBNORMAL_VAL]] : (!cir.bool, !s32i, !s32i) -> !s32i
@@ -152,16 +152,16 @@ void test_fpclassify_normal(){
     float normalValue = 1.0f;
     __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL,
                                             FP_SUBNORMAL, FP_ZERO, 
normalValue);
-// CIR: %[[IS_ZERO:.+]] = cir.is_fp_class %{{.+}}, fcZero : (!cir.float) -> 
!cir.bool
+// CIR: %[[IS_ZERO:.+]] = cir.is_fp_class %{{.+}}, "fcZero" : (!cir.float) -> 
!cir.bool
 // CIR: cir.ternary(%[[IS_ZERO]], true {
 // CIR: cir.const #cir.int<96> : !s32i
-// CIR: %[[IS_NAN:.+]] = cir.is_fp_class %{{.+}}, fcNan : (!cir.float) -> 
!cir.bool
+// CIR: %[[IS_NAN:.+]] = cir.is_fp_class %{{.+}}, "fcNan" : (!cir.float) -> 
!cir.bool
 // CIR: cir.ternary(%[[IS_NAN]], true {
 // CIR: cir.const #cir.int<3> : !s32i
-// CIR: %[[IS_INF:.+]] = cir.is_fp_class %{{.+}}, fcInf : (!cir.float) -> 
!cir.bool
+// CIR: %[[IS_INF:.+]] = cir.is_fp_class %{{.+}}, "fcInf" : (!cir.float) -> 
!cir.bool
 // CIR: cir.ternary(%[[IS_INF]], true {
 // CIR: cir.const #cir.int<516> : !s32i
-// CIR: %[[IS_NORMAL:.+]] = cir.is_fp_class %{{.+}}, fcNormal : (!cir.float) 
-> !cir.bool
+// CIR: %[[IS_NORMAL:.+]] = cir.is_fp_class %{{.+}}, "fcNormal" : (!cir.float) 
-> !cir.bool
 // CIR: %[[NORMAL_VAL:.+]] = cir.const #cir.int<264> : !s32i
 // CIR: %[[SUBNORMAL_VAL:.+]] = cir.const #cir.int<144> : !s32i
 // CIR: cir.select if %[[IS_NORMAL]] then %[[NORMAL_VAL]] else 
%[[SUBNORMAL_VAL]] : (!cir.bool, !s32i, !s32i) -> !s32i
@@ -221,16 +221,16 @@ void test_fpclassify_subnormal(){
     float subnormalValue = 1.0e-40f;
     __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL,
                                                FP_SUBNORMAL, FP_ZERO, 
subnormalValue);
-// CIR: %[[IS_ZERO:.+]] = cir.is_fp_class %{{.+}}, fcZero : (!cir.float) -> 
!cir.bool
+// CIR: %[[IS_ZERO:.+]] = cir.is_fp_class %{{.+}}, "fcZero" : (!cir.float) -> 
!cir.bool
 // CIR: cir.ternary(%[[IS_ZERO]], true {
 // CIR: cir.const #cir.int<96> : !s32i
-// CIR: %[[IS_NAN:.+]] = cir.is_fp_class %{{.+}}, fcNan : (!cir.float) -> 
!cir.bool
+// CIR: %[[IS_NAN:.+]] = cir.is_fp_class %{{.+}}, "fcNan" : (!cir.float) -> 
!cir.bool
 // CIR: cir.ternary(%[[IS_NAN]], true {
 // CIR: cir.const #cir.int<3> : !s32i
-// CIR: %[[IS_INF:.+]] = cir.is_fp_class %{{.+}}, fcInf : (!cir.float) -> 
!cir.bool
+// CIR: %[[IS_INF:.+]] = cir.is_fp_class %{{.+}}, "fcInf" : (!cir.float) -> 
!cir.bool
 // CIR: cir.ternary(%[[IS_INF]], true {
 // CIR: cir.const #cir.int<516> : !s32i
-// CIR: %[[IS_NORMAL:.+]] = cir.is_fp_class %{{.+}}, fcNormal : (!cir.float) 
-> !cir.bool
+// CIR: %[[IS_NORMAL:.+]] = cir.is_fp_class %{{.+}}, "fcNormal" : (!cir.float) 
-> !cir.bool
 // CIR: %[[NORMAL_VAL:.+]] = cir.const #cir.int<264> : !s32i
 // CIR: %[[SUBNORMAL_VAL:.+]] = cir.const #cir.int<144> : !s32i
 // CIR: cir.select if %[[IS_NORMAL]] then %[[NORMAL_VAL]] else 
%[[SUBNORMAL_VAL]] : (!cir.bool, !s32i, !s32i) -> !s32i
@@ -290,16 +290,16 @@ void test_fpclassify_zero(){
     float zeroValue = 0.0f;
     __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL,
                                           FP_SUBNORMAL, FP_ZERO, zeroValue);
-// CIR: %[[IS_ZERO:.+]] = cir.is_fp_class %{{.+}}, fcZero : (!cir.float) -> 
!cir.bool
+// CIR: %[[IS_ZERO:.+]] = cir.is_fp_class %{{.+}}, "fcZero" : (!cir.float) -> 
!cir.bool
 // CIR: cir.ternary(%[[IS_ZERO]], true {
 // CIR: cir.const #cir.int<96> : !s32i
-// CIR: %[[IS_NAN:.+]] = cir.is_fp_class %{{.+}}, fcNan : (!cir.float) -> 
!cir.bool
+// CIR: %[[IS_NAN:.+]] = cir.is_fp_class %{{.+}}, "fcNan" : (!cir.float) -> 
!cir.bool
 // CIR: cir.ternary(%[[IS_NAN]], true {
 // CIR: cir.const #cir.int<3> : !s32i
-// CIR: %[[IS_INF:.+]] = cir.is_fp_class %{{.+}}, fcInf : (!cir.float) -> 
!cir.bool
+// CIR: %[[IS_INF:.+]] = cir.is_fp_class %{{.+}}, "fcInf" : (!cir.float) -> 
!cir.bool
 // CIR: cir.ternary(%[[IS_INF]], true {
 // CIR: cir.const #cir.int<516> : !s32i
-// CIR: %[[IS_NORMAL:.+]] = cir.is_fp_class %{{.+}}, fcNormal : (!cir.float) 
-> !cir.bool
+// CIR: %[[IS_NORMAL:.+]] = cir.is_fp_class %{{.+}}, "fcNormal" : (!cir.float) 
-> !cir.bool
 // CIR: %[[NORMAL_VAL:.+]] = cir.const #cir.int<264> : !s32i
 // CIR: %[[SUBNORMAL_VAL:.+]] = cir.const #cir.int<144> : !s32i
 // CIR: cir.select if %[[IS_NORMAL]] then %[[NORMAL_VAL]] else 
%[[SUBNORMAL_VAL]] : (!cir.bool, !s32i, !s32i) -> !s32i

diff  --git a/clang/test/CIR/CodeGenBuiltins/builtin-isfpclass.c 
b/clang/test/CIR/CodeGenBuiltins/builtin-isfpclass.c
index a8dea4dfb7d77..d45a1c4ac179e 100644
--- a/clang/test/CIR/CodeGenBuiltins/builtin-isfpclass.c
+++ b/clang/test/CIR/CodeGenBuiltins/builtin-isfpclass.c
@@ -10,55 +10,55 @@ int finite(double);
 void test_is_finite(__fp16 *H, float F, double D, long double LD) {
     volatile int res;
     res = __builtin_isinf(*H);
-    // CIR: cir.is_fp_class %{{.*}}, fcInf : (!cir.f16) -> !cir.bool
+    // CIR: cir.is_fp_class %{{.*}}, "fcInf" : (!cir.f16) -> !cir.bool
     // LLVM: call i1 @llvm.is.fpclass.f16(half {{.*}}, i32 516)
     // OGCG: call i1 @llvm.is.fpclass.f16(half {{.*}}, i32 516)
 
     res = __builtin_isinf(F);
-    // CIR: cir.is_fp_class %{{.*}}, fcInf : (!cir.float) -> !cir.bool
+    // CIR: cir.is_fp_class %{{.*}}, "fcInf" : (!cir.float) -> !cir.bool
     // LLVM: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 516)
     // OGCG: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 516)
 
     res = __builtin_isinf(D);
-    // CIR: cir.is_fp_class %{{.*}}, fcInf : (!cir.double) -> !cir.bool
+    // CIR: cir.is_fp_class %{{.*}}, "fcInf" : (!cir.double) -> !cir.bool
     // LLVM: call i1 @llvm.is.fpclass.f64(double {{.*}}, i32 516)
     // OGCG: call i1 @llvm.is.fpclass.f64(double {{.*}}, i32 516)
 
     res = __builtin_isinf(LD);
-    // CIR: cir.is_fp_class %{{.*}}, fcInf : (!cir.long_double<!cir.f80>) -> 
!cir.bool
+    // CIR: cir.is_fp_class %{{.*}}, "fcInf" : (!cir.long_double<!cir.f80>) -> 
!cir.bool
     // LLVM: call i1 @llvm.is.fpclass.f80(x86_fp80 {{.*}}, i32 516)
     // OGCG: call i1 @llvm.is.fpclass.f80(x86_fp80 {{.*}}, i32 516)
 
     res = __builtin_isfinite(*H);
-    // CIR: cir.is_fp_class %{{.*}}, fcFinite : (!cir.f16) -> !cir.bool
+    // CIR: cir.is_fp_class %{{.*}}, "fcFinite" : (!cir.f16) -> !cir.bool
     // LLVM: call i1 @llvm.is.fpclass.f16(half {{.*}}, i32 504)
     // OGCG: call i1 @llvm.is.fpclass.f16(half {{.*}}, i32 504)
 
     res = __builtin_isfinite(F);
-    // CIR: cir.is_fp_class %{{.*}}, fcFinite : (!cir.float) -> !cir.bool
+    // CIR: cir.is_fp_class %{{.*}}, "fcFinite" : (!cir.float) -> !cir.bool
     // LLVM: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 504)
     // OGCG: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 504)
 
     res = finite(D);
-    // CIR: cir.is_fp_class %{{.*}}, fcFinite : (!cir.double) -> !cir.bool
+    // CIR: cir.is_fp_class %{{.*}}, "fcFinite" : (!cir.double) -> !cir.bool
     // LLVM: call i1 @llvm.is.fpclass.f64(double {{.*}}, i32 504)
     // OGCG: call i1 @llvm.is.fpclass.f64(double %20, i32 504)
     res = __builtin_isnormal(*H);
-    // CIR: cir.is_fp_class %{{.*}}, fcNormal : (!cir.f16) -> !cir.bool
+    // CIR: cir.is_fp_class %{{.*}}, "fcNormal" : (!cir.f16) -> !cir.bool
     // LLVM: call i1 @llvm.is.fpclass.f16(half {{.*}}, i32 264)
     // OGCG: call i1 @llvm.is.fpclass.f16(half {{.*}}, i32 264)
 
     res = __builtin_isnormal(F);
-    // CIR: cir.is_fp_class %{{.*}}, fcNormal : (!cir.float) -> !cir.bool
+    // CIR: cir.is_fp_class %{{.*}}, "fcNormal" : (!cir.float) -> !cir.bool
     // LLVM: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 264)
     // OGCG: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 264)
 
     res = __builtin_issubnormal(F);
-    // CIR: cir.is_fp_class %{{.*}}, fcSubnormal : (!cir.float) -> !cir.bool
+    // CIR: cir.is_fp_class %{{.*}}, "fcSubnormal" : (!cir.float) -> !cir.bool
     // LLVM: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 144)
     // OGCG: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 144)
     res = __builtin_iszero(F);
-    // CIR: cir.is_fp_class %{{.*}}, fcZero : (!cir.float) -> !cir.bool
+    // CIR: cir.is_fp_class %{{.*}}, "fcZero" : (!cir.float) -> !cir.bool
     // LLVM: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 96)
     // OGCG: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 96)
     res = __builtin_issignaling(F);
@@ -72,7 +72,7 @@ _Bool check_isfpclass_finite(float x) {
 }
 
 // CIR: cir.func {{.*}}@check_isfpclass_finite
-// CIR: cir.is_fp_class %{{.*}}, fcFinite : (!cir.float)
+// CIR: cir.is_fp_class %{{.*}}, "fcFinite" : (!cir.float)
 // LLVM: @check_isfpclass_finite
 // LLVM: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 504)
 // OGCG: @check_isfpclass_finite
@@ -83,7 +83,7 @@ _Bool check_isfpclass_nan_f32(float x) {
 }
 
 // CIR: cir.func {{.*}}@check_isfpclass_nan_f32
-// CIR: cir.is_fp_class %{{.*}}, fcNan : (!cir.float)
+// CIR: cir.is_fp_class %{{.*}}, "fcNan" : (!cir.float)
 // LLVM: @check_isfpclass_nan_f32
 // LLVM: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 3)
 // OGCG: @check_isfpclass_nan_f32
@@ -107,12 +107,34 @@ _Bool check_isfpclass_zero_f16(_Float16 x) {
 }
 
 // CIR: cir.func {{.*}}@check_isfpclass_zero_f16
-// CIR: cir.is_fp_class %{{.*}}, fcZero : (!cir.f16)
+// CIR: cir.is_fp_class %{{.*}}, "fcZero" : (!cir.f16)
 // LLVM: @check_isfpclass_zero_f16
 // LLVM: call i1 @llvm.is.fpclass.f16(half {{.*}}, i32 96)
 // OGCG: @check_isfpclass_zero_f16
 // OGCG: call i1 @llvm.is.fpclass.f16(half {{.*}}, i32 96)
 
+_Bool check_isfpclass_snan_neginf(double x) {
+  return __builtin_isfpclass(x, 5 /*fcSNan|fcNegInf*/);
+}
+
+// CIR: cir.func {{.*}}@check_isfpclass_snan_neginf
+// CIR: cir.is_fp_class %{{.*}}, "fcSNan|fcNegInf" : (!cir.double)
+// LLVM: @check_isfpclass_snan_neginf
+// LLVM: call i1 @llvm.is.fpclass.f64(double {{.*}}, i32 5)
+// OGCG: @check_isfpclass_snan_neginf
+// OGCG: call i1 @llvm.is.fpclass.f64(double {{.*}}, i32 5)
+
+_Bool check_isfpclass_multi(float x) {
+  return __builtin_isfpclass(x, 1022 /*all but fcSNan (fcQNan still set)*/);
+}
+
+// CIR: cir.func {{.*}}@check_isfpclass_multi
+// CIR: cir.is_fp_class %{{.*}}, "fcNegative|fcPositive|fcQNan" : (!cir.float)
+// LLVM: @check_isfpclass_multi
+// LLVM: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 1022)
+// OGCG: @check_isfpclass_multi
+// OGCG: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 1022)
+
 // Update when we support FP pragma in functions and can convert BoolType in 
prvalue to i1.
 
 // _Bool check_isfpclass_finite_strict(float x) {

diff  --git a/clang/test/CIR/CodeGenBuiltins/builtin-isinf-sign.c 
b/clang/test/CIR/CodeGenBuiltins/builtin-isinf-sign.c
index 91f9b4cc99e1a..428b368685a82 100644
--- a/clang/test/CIR/CodeGenBuiltins/builtin-isinf-sign.c
+++ b/clang/test/CIR/CodeGenBuiltins/builtin-isinf-sign.c
@@ -8,7 +8,7 @@
 int test_float_isinf_sign(float x) {
   // CIR-LABEL: test_float_isinf_sign
   // CIR: %[[ARG:.*]] = cir.load align(4) %{{.*}} : !cir.ptr<!cir.float>, 
!cir.float
-  // CIR: %[[IS_INF:.*]] = cir.is_fp_class %[[ARG]], fcInf : (!cir.float) -> 
!cir.bool
+  // CIR: %[[IS_INF:.*]] = cir.is_fp_class %[[ARG]], "fcInf" : (!cir.float) -> 
!cir.bool
   // CIR: %[[IS_NEG:.*]] = cir.signbit %[[ARG]] : !cir.float -> !cir.bool
   // CIR: %[[C_0:.*]] = cir.const #cir.int<0> : !s32i
   // CIR: %[[C_1:.*]] = cir.const #cir.int<1> : !s32i


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to