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
