https://github.com/YeonguChoe updated 
https://github.com/llvm/llvm-project/pull/183430

>From 259a971ebfce122ab788776e8de6464a3330ab38 Mon Sep 17 00:00:00 2001
From: YeonguChoe <[email protected]>
Date: Wed, 25 Feb 2026 20:29:01 -0500
Subject: [PATCH 1/2] [Clang][CodeGen] Fix builtin_fpclassify with
 llvm.is.fpclass

- Made fpclassify function to classify floating point number using LLVM IR 
operation
- Reference: https://llvm.org/docs/LangRef.html#floating-point-test-intrinsics
---
 clang/lib/CodeGen/CGBuiltin.cpp        | 78 ++++++++++++--------------
 clang/test/CodeGen/strictfp_builtins.c | 27 +++++----
 2 files changed, 50 insertions(+), 55 deletions(-)

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 38010cad75244..cee874730a3c3 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -4414,60 +4414,56 @@ RValue CodeGenFunction::EmitBuiltinExpr(const 
GlobalDecl GD, unsigned BuiltinID,
 
   case Builtin::BI__builtin_fpclassify: {
     CodeGenFunction::CGFPOptionsRAII FPOptsRAII(*this, E);
-    // FIXME: for strictfp/IEEE-754 we need to not trap on SNaN here.
     Value *V = EmitScalarExpr(E->getArg(5));
-    llvm::Type *Ty = ConvertType(E->getArg(5)->getType());
-
-    // Create Result
-    BasicBlock *Begin = Builder.GetInsertBlock();
-    BasicBlock *End = createBasicBlock("fpclassify_end", this->CurFn);
-    Builder.SetInsertPoint(End);
-    PHINode *Result =
-      Builder.CreatePHI(ConvertType(E->getArg(0)->getType()), 4,
-                        "fpclassify_result");
 
-    // if (V==0) return FP_ZERO
-    Builder.SetInsertPoint(Begin);
-    Value *IsZero = Builder.CreateFCmpOEQ(V, Constant::getNullValue(Ty),
-                                          "iszero");
+    Value *NanLiteral = EmitScalarExpr(E->getArg(0));
+    Value *InfLiteral = EmitScalarExpr(E->getArg(1));
+    Value *NormalLiteral = EmitScalarExpr(E->getArg(2));
+    Value *SubnormalLiteral = EmitScalarExpr(E->getArg(3));
     Value *ZeroLiteral = EmitScalarExpr(E->getArg(4));
-    BasicBlock *NotZero = createBasicBlock("fpclassify_not_zero", this->CurFn);
-    Builder.CreateCondBr(IsZero, End, NotZero);
-    Result->addIncoming(ZeroLiteral, Begin);
 
-    // if (V != V) return FP_NAN
-    Builder.SetInsertPoint(NotZero);
-    Value *IsNan = Builder.CreateFCmpUNO(V, V, "cmp");
-    Value *NanLiteral = EmitScalarExpr(E->getArg(0));
-    BasicBlock *NotNan = createBasicBlock("fpclassify_not_nan", this->CurFn);
+    Value *IsNan = Builder.createIsFPClass(V, 0b0000000011);
+    Value *IsInf = Builder.createIsFPClass(V, 0b1000000100);
+    Value *IsNormal = Builder.createIsFPClass(V, 0b0100001000);
+    Value *IsSubnormal = Builder.createIsFPClass(V, 0b0010010000);
+
+    BasicBlock *Entry = Builder.GetInsertBlock();
+
+    BasicBlock *End = createBasicBlock("fpclassify_end", CurFn);
+    Builder.SetInsertPoint(End);
+    PHINode *Result = Builder.CreatePHI(ConvertType(E->getArg(0)->getType()), 
5,
+                                        "fpclassify_result");
+
+    // Check if V is NaN
+    Builder.SetInsertPoint(Entry);
+    BasicBlock *NotNan = createBasicBlock("fpclassify_not_nan", CurFn);
     Builder.CreateCondBr(IsNan, End, NotNan);
-    Result->addIncoming(NanLiteral, NotZero);
+    Result->addIncoming(NanLiteral, Entry);
 
-    // if (fabs(V) == infinity) return FP_INFINITY
+    // Check if V is infinity
     Builder.SetInsertPoint(NotNan);
-    Value *VAbs = EmitFAbs(*this, V);
-    Value *IsInf =
-      Builder.CreateFCmpOEQ(VAbs, ConstantFP::getInfinity(V->getType()),
-                            "isinf");
-    Value *InfLiteral = EmitScalarExpr(E->getArg(1));
-    BasicBlock *NotInf = createBasicBlock("fpclassify_not_inf", this->CurFn);
+    BasicBlock *NotInf = createBasicBlock("fpclassify_not_inf", CurFn);
     Builder.CreateCondBr(IsInf, End, NotInf);
     Result->addIncoming(InfLiteral, NotNan);
 
-    // if (fabs(V) >= MIN_NORMAL) return FP_NORMAL else FP_SUBNORMAL
+    // Check if V is normal
     Builder.SetInsertPoint(NotInf);
-    APFloat Smallest = APFloat::getSmallestNormalized(
-        getContext().getFloatTypeSemantics(E->getArg(5)->getType()));
-    Value *IsNormal =
-      Builder.CreateFCmpUGE(VAbs, ConstantFP::get(V->getContext(), Smallest),
-                            "isnormal");
-    Value *NormalResult =
-      Builder.CreateSelect(IsNormal, EmitScalarExpr(E->getArg(2)),
-                           EmitScalarExpr(E->getArg(3)));
+    BasicBlock *NotNormal = createBasicBlock("fpclassify_not_normal", CurFn);
+    Builder.CreateCondBr(IsNormal, End, NotNormal);
+    Result->addIncoming(NormalLiteral, NotInf);
+
+    // Check if V is subnormal
+    Builder.SetInsertPoint(NotNormal);
+    BasicBlock *NotSubnormal =
+        createBasicBlock("fpclassify_not_subnormal", CurFn);
+    Builder.CreateCondBr(IsSubnormal, End, NotSubnormal);
+    Result->addIncoming(SubnormalLiteral, NotNormal);
+
+    // If V is not one of the above, it is zero
+    Builder.SetInsertPoint(NotSubnormal);
     Builder.CreateBr(End);
-    Result->addIncoming(NormalResult, NotInf);
+    Result->addIncoming(ZeroLiteral, NotSubnormal);
 
-    // return Result
     Builder.SetInsertPoint(End);
     return RValue::get(Result);
   }
diff --git a/clang/test/CodeGen/strictfp_builtins.c 
b/clang/test/CodeGen/strictfp_builtins.c
index 58815c7de4fa9..d965767be095b 100644
--- a/clang/test/CodeGen/strictfp_builtins.c
+++ b/clang/test/CodeGen/strictfp_builtins.c
@@ -3,7 +3,6 @@
 
 // Test that the constrained intrinsics are picking up the exception
 // metadata from the AST instead of the global default from the command line.
-// FIXME: these functions shouldn't trap on SNaN.
 
 #pragma float_control(except, on)
 
@@ -31,22 +30,22 @@ void p(char *str, int x) {
 // CHECK-NEXT:    [[D_ADDR:%.*]] = alloca double, align 8
 // CHECK-NEXT:    store double [[D:%.*]], ptr [[D_ADDR]], align 8
 // CHECK-NEXT:    [[TMP0:%.*]] = load double, ptr [[D_ADDR]], align 8
-// CHECK-NEXT:    [[ISZERO:%.*]] = call i1 
@llvm.experimental.constrained.fcmp.f64(double [[TMP0]], double 0.000000e+00, 
metadata !"oeq", metadata !"fpexcept.strict") #[[ATTR4]]
-// CHECK-NEXT:    br i1 [[ISZERO]], label [[FPCLASSIFY_END:%.*]], label 
[[FPCLASSIFY_NOT_ZERO:%.*]]
+// CHECK-NEXT:    [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f64(double [[TMP0]], 
i32 3) #[[ATTR4]]
+// CHECK-NEXT:    [[TMP2:%.*]] = call i1 @llvm.is.fpclass.f64(double [[TMP0]], 
i32 516) #[[ATTR4]]
+// CHECK-NEXT:    [[TMP3:%.*]] = call i1 @llvm.is.fpclass.f64(double [[TMP0]], 
i32 264) #[[ATTR4]]
+// CHECK-NEXT:    [[TMP4:%.*]] = call i1 @llvm.is.fpclass.f64(double [[TMP0]], 
i32 144) #[[ATTR4]]
+// CHECK-NEXT:    br i1 [[TMP1]], label [[FPCLASSIFY_END:%.*]], label 
[[FPCLASSIFY_NOT_NAN:%.*]]
 // CHECK:       fpclassify_end:
-// CHECK-NEXT:    [[FPCLASSIFY_RESULT:%.*]] = phi i32 [ 4, [[ENTRY:%.*]] ], [ 
0, [[FPCLASSIFY_NOT_ZERO]] ], [ 1, [[FPCLASSIFY_NOT_NAN:%.*]] ], [ 
[[TMP2:%.*]], [[FPCLASSIFY_NOT_INF:%.*]] ]
+// CHECK-NEXT:    [[FPCLASSIFY_RESULT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ 
1, [[FPCLASSIFY_NOT_NAN]] ], [ 2, [[FPCLASSIFY_NOT_INF:%.*]] ], [ 3, 
[[FPCLASSIFY_NOT_NORMAL:%.*]] ], [ 4, [[FPCLASSIFY_NOT_SUBNORMAL:%.*]] ]
 // CHECK-NEXT:    call void @p(ptr noundef @.str.1, i32 noundef 
[[FPCLASSIFY_RESULT]]) #[[ATTR4]]
 // CHECK-NEXT:    ret void
-// CHECK:       fpclassify_not_zero:
-// CHECK-NEXT:    [[CMP:%.*]] = call i1 
@llvm.experimental.constrained.fcmp.f64(double [[TMP0]], double [[TMP0]], 
metadata !"uno", metadata !"fpexcept.strict") #[[ATTR4]]
-// CHECK-NEXT:    br i1 [[CMP]], label [[FPCLASSIFY_END]], label 
[[FPCLASSIFY_NOT_NAN]]
 // CHECK:       fpclassify_not_nan:
-// CHECK-NEXT:    [[TMP1:%.*]] = call double @llvm.fabs.f64(double [[TMP0]]) 
#[[ATTR5:[0-9]+]]
-// CHECK-NEXT:    [[ISINF:%.*]] = call i1 
@llvm.experimental.constrained.fcmp.f64(double [[TMP1]], double 
0x7FF0000000000000, metadata !"oeq", metadata !"fpexcept.strict") #[[ATTR4]]
-// CHECK-NEXT:    br i1 [[ISINF]], label [[FPCLASSIFY_END]], label 
[[FPCLASSIFY_NOT_INF]]
+// CHECK-NEXT:    br i1 [[TMP2]], label [[FPCLASSIFY_END]], label 
[[FPCLASSIFY_NOT_INF:%.*]]
 // CHECK:       fpclassify_not_inf:
-// CHECK-NEXT:    [[ISNORMAL:%.*]] = call i1 
@llvm.experimental.constrained.fcmp.f64(double [[TMP1]], double 
0x10000000000000, metadata !"uge", metadata !"fpexcept.strict") #[[ATTR4]]
-// CHECK-NEXT:    [[TMP2]] = select i1 [[ISNORMAL]], i32 2, i32 3
+// CHECK-NEXT:    br i1 [[TMP3]], label [[FPCLASSIFY_END]], label 
[[FPCLASSIFY_NOT_NORMAL:%.*]]
+// CHECK:       fpclassify_not_normal:
+// CHECK-NEXT:    br i1 [[TMP4]], label [[FPCLASSIFY_END]], label 
[[FPCLASSIFY_NOT_SUBNORMAL:%.*]]
+// CHECK:       fpclassify_not_subnormal:
 // CHECK-NEXT:    br label [[FPCLASSIFY_END]]
 //
 void test_fpclassify(double d) {
@@ -156,7 +155,7 @@ void test_double_isfinite(double d) {
 // CHECK-NEXT:    [[D_ADDR:%.*]] = alloca double, align 8
 // CHECK-NEXT:    store double [[D:%.*]], ptr [[D_ADDR]], align 8
 // CHECK-NEXT:    [[TMP0:%.*]] = load double, ptr [[D_ADDR]], align 8
-// CHECK-NEXT:    [[TMP1:%.*]] = call double @llvm.fabs.f64(double [[TMP0]]) 
#[[ATTR5]]
+// CHECK-NEXT:    [[TMP1:%.*]] = call double @llvm.fabs.f64(double [[TMP0]]) #5
 // CHECK-NEXT:    [[ISINF:%.*]] = call i1 
@llvm.experimental.constrained.fcmp.f64(double [[TMP1]], double 
0x7FF0000000000000, metadata !"oeq", metadata !"fpexcept.strict") #[[ATTR4]]
 // CHECK-NEXT:    [[TMP2:%.*]] = bitcast double [[TMP0]] to i64
 // CHECK-NEXT:    [[TMP3:%.*]] = icmp slt i64 [[TMP2]], 0
@@ -233,4 +232,4 @@ void test_isnormal(double d) {
   P(isnormal, (d));
 
   return;
-}
+}
\ No newline at end of file

>From ca95bb116483de4f07fd12e514a69e3ec7da8c1a Mon Sep 17 00:00:00 2001
From: YeonguChoe <[email protected]>
Date: Wed, 25 Feb 2026 23:53:02 -0500
Subject: [PATCH 2/2] Fix nvptx_device_math_macro test for llvm.is.fpclass test

---
 clang/test/Headers/nvptx_device_math_macro.cpp | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/clang/test/Headers/nvptx_device_math_macro.cpp 
b/clang/test/Headers/nvptx_device_math_macro.cpp
index 3faf527daf113..11380ba3f7bd3 100644
--- a/clang/test/Headers/nvptx_device_math_macro.cpp
+++ b/clang/test/Headers/nvptx_device_math_macro.cpp
@@ -8,10 +8,11 @@
 #pragma omp declare target
 int use_macro() {
   double a(0);
-// CHECK-NOT:  call {{.*}}
-// CHECK:  call double @llvm.fabs.f64(double
-// CHECK-NOT:  call {{.*}}
-// CHECK:      ret i32 %conv
+// CHECK: call i1 @llvm.is.fpclass.f64(double {{.*}}, i32 3)
+// CHECK: call i1 @llvm.is.fpclass.f64(double {{.*}}, i32 516)
+// CHECK: call i1 @llvm.is.fpclass.f64(double {{.*}}, i32 264)
+// CHECK: call i1 @llvm.is.fpclass.f64(double {{.*}}, i32 144)
+// CHECK: ret i32
   return (std::fpclassify(a) != FP_ZERO);
 }
 #pragma omp end declare target

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

Reply via email to