https://github.com/YeonguChoe created https://github.com/llvm/llvm-project/pull/190848
### Content - `__builtin_fpclassify` is a function classify floating point value into one of `FP_NAN`, `FP_INFINITE`, `FP_NORMAL`, `FP_SUBNORMAL` and `FP_ZERO`. - Applied LLVM IR output to FileCheck test files using `__builtin_fpclassify` function. ### Reference - https://gcc.gnu.org/onlinedocs/gcc/Floating-Point-Format-Builtins.html#index-_005f_005fbuiltin_005ffpclassify >From 7e4320f5e120bc32d94572c6cd2e7d1c06942bbd Mon Sep 17 00:00:00 2001 From: YeonguChoe <[email protected]> Date: Tue, 7 Apr 2026 16:31:28 -0400 Subject: [PATCH] [Clang] Implement __builtin_fpclassify - __builtin_fpclassify is a function classify floating point value into one of FP_NAN, FP_INFINITE, FP_NORMAL, FP_SUBNORMAL and FP_ZERO. - Applied LLVM IR output to FileCheck test files using __builtin_fpclassify function. --- clang/lib/CodeGen/CGBuiltin.cpp | 88 +++-- .../CIR/CodeGenBuiltins/builtin-fpclassify.c | 329 +++++------------- clang/test/CodeGen/builtin-fpclassify.c | 92 +++++ .../test/Headers/nvptx_device_math_macro.cpp | 8 +- 4 files changed, 224 insertions(+), 293 deletions(-) create mode 100644 clang/test/CodeGen/builtin-fpclassify.c diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 4d74d681cd320..b260a36e877b5 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -4415,60 +4415,58 @@ 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 *NanLiteral = EmitScalarExpr(E->getArg(0)); + Value *InfiniteLiteral = EmitScalarExpr(E->getArg(1)); + Value *NormalLiteral = EmitScalarExpr(E->getArg(2)); + Value *SubnormalLiteral = EmitScalarExpr(E->getArg(3)); + Value *ZeroLiteral = EmitScalarExpr(E->getArg(4)); 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); + BasicBlock *Entry = Builder.GetInsertBlock(); + BasicBlock *NotNan = createBasicBlock("fpclassify_not_nan", CurFn); + BasicBlock *NotInfinite = + createBasicBlock("fpclassify_not_infinite", CurFn); + BasicBlock *NotNormal = createBasicBlock("fpclassify_not_normal", CurFn); + BasicBlock *NotSubnormal = + createBasicBlock("fpclassify_not_subnormal", CurFn); + BasicBlock *End = createBasicBlock("fpclassify_end", CurFn); + + // End Block Builder.SetInsertPoint(End); - PHINode *Result = - Builder.CreatePHI(ConvertType(E->getArg(0)->getType()), 4, - "fpclassify_result"); + PHINode *Result = Builder.CreatePHI(ConvertType(E->getArg(0)->getType()), 5, + "fpclassify_result"); - // if (V==0) return FP_ZERO - Builder.SetInsertPoint(Begin); - Value *IsZero = Builder.CreateFCmpOEQ(V, Constant::getNullValue(Ty), - "iszero"); - 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); + // Entry Block + Builder.SetInsertPoint(Entry); + Value *IsNan = Builder.createIsFPClass(V, FPClassTest::fcNan); + Result->addIncoming(NanLiteral, Entry); Builder.CreateCondBr(IsNan, End, NotNan); - Result->addIncoming(NanLiteral, NotZero); - // if (fabs(V) == infinity) return FP_INFINITY + // NotNan Block 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); - Builder.CreateCondBr(IsInf, End, NotInf); - Result->addIncoming(InfLiteral, NotNan); - - // if (fabs(V) >= MIN_NORMAL) return FP_NORMAL else FP_SUBNORMAL - 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))); + Value *IsInfinite = Builder.createIsFPClass(V, FPClassTest::fcInf); + Result->addIncoming(InfiniteLiteral, NotNan); + Builder.CreateCondBr(IsInfinite, End, NotInfinite); + + // NotInfinite Block + Builder.SetInsertPoint(NotInfinite); + Value *IsNormal = Builder.createIsFPClass(V, FPClassTest::fcNormal); + Result->addIncoming(NormalLiteral, NotInfinite); + Builder.CreateCondBr(IsNormal, End, NotNormal); + + // NotNormal Block + Builder.SetInsertPoint(NotNormal); + Value *IsSubnormal = Builder.createIsFPClass(V, FPClassTest::fcSubnormal); + Result->addIncoming(SubnormalLiteral, NotNormal); + Builder.CreateCondBr(IsSubnormal, End, NotSubnormal); + + // NotSubnormal Block + Builder.SetInsertPoint(NotSubnormal); + Result->addIncoming(ZeroLiteral, NotSubnormal); Builder.CreateBr(End); - Result->addIncoming(NormalResult, NotInf); - // return Result + // End Block Builder.SetInsertPoint(End); return RValue::get(Result); } diff --git a/clang/test/CIR/CodeGenBuiltins/builtin-fpclassify.c b/clang/test/CIR/CodeGenBuiltins/builtin-fpclassify.c index bad83c4f0ef4c..39e1b35ba7e1b 100644 --- a/clang/test/CIR/CodeGenBuiltins/builtin-fpclassify.c +++ b/clang/test/CIR/CodeGenBuiltins/builtin-fpclassify.c @@ -29,55 +29,23 @@ void test_fpclassify_nan(){ // 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 -// LLVM: %[[VAL:.*]] = load float, ptr -// LLVM-NEXT: %[[IS_ZERO:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 96) -// LLVM-NEXT: br i1 %[[IS_ZERO]], label %[[BB_ZERO:.*]], label %[[BB_NOT_ZERO:.*]] -// LLVM: [[BB_ZERO]]: -// LLVM-NEXT: br label %[[BB_RET:.*]] -// LLVM: [[BB_NOT_ZERO]]: -// LLVM-NEXT: %[[IS_NAN:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 3) -// LLVM-NEXT: br i1 %[[IS_NAN]], label %[[BB_NAN:.*]], label %[[BB_NOT_NAN:.*]] -// LLVM: [[BB_NAN]]: -// LLVM-NEXT: br label %[[BB_MERGE1:.*]] -// LLVM: [[BB_NOT_NAN]]: -// LLVM-NEXT: %[[IS_INF:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 516) -// LLVM-NEXT: br i1 %[[IS_INF]], label %[[BB_INF:.*]], label %[[BB_NOT_INF:.*]] -// LLVM: [[BB_INF]]: -// LLVM-NEXT: br label %[[BB_MERGE2:.*]] -// LLVM: [[BB_NOT_INF]]: -// LLVM-NEXT: %[[IS_NORMAL:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 264) -// LLVM-NEXT: %[[NORMAL_OR_SUBNORMAL:.*]] = select i1 %[[IS_NORMAL]], i32 264, i32 144 -// LLVM-NEXT: br label %[[BB_MERGE2]] -// LLVM: [[BB_MERGE2]]: -// LLVM-NEXT: %[[PHI_INF_SEL:.*]] = phi i32 [ %[[NORMAL_OR_SUBNORMAL]], %[[BB_NOT_INF]] ], [ 516, %[[BB_INF]] ] -// LLVM-NEXT: br label %[[BB_CONT1:.*]] -// LLVM: [[BB_CONT1]]: -// LLVM-NEXT: br label %[[BB_MERGE1]] -// LLVM: [[BB_MERGE1]]: -// LLVM-NEXT: %[[PHI_NAN_SEL:.*]] = phi i32 [ %[[PHI_INF_SEL]], %[[BB_CONT1]] ], [ 3, %[[BB_NAN]] ] -// LLVM-NEXT: br label %[[BB_CONT2:.*]] -// LLVM: [[BB_CONT2]]: -// LLVM-NEXT: br label %[[BB_RET]] -// LLVM: [[BB_RET]]: -// LLVM-NEXT: %[[PHI_FINAL:.*]] = phi i32 [ %[[PHI_NAN_SEL]], %[[BB_CONT2]] ], [ 96, %[[BB_ZERO]] ] -// LLVM-NEXT: br label %[[BB_EXIT:.*]] -// LLVM: [[BB_EXIT]]: - -// OGCG: %[[CMP_ZERO:.+]] = fcmp oeq float %[[VAL:.+]], -// OGCG-NEXT: br i1 %[[CMP_ZERO]], label %[[BB_RET:.+]], label %[[BB_NOT_ZERO:.+]] -// OGCG: [[BB_RET]]: -// OGCG-NEXT: %[[PHI:.+]] = phi i32 [ 96, %[[BB_ENTRY:.+]] ], [ 3, %[[BB_NOT_ZERO]] ], [ 516, %[[BB_NOT_NAN:.+]] ], [ %[[SEL:.+]], %[[BB_NOT_INF:.+]] ] -// OGCG: [[BB_NOT_ZERO]]: -// OGCG-NEXT: %[[CMP_NAN:.+]] = fcmp uno float %[[VAL]], %[[VAL]] -// OGCG-NEXT: br i1 %[[CMP_NAN]], label %[[BB_RET]], label %[[BB_NOT_NAN]] -// OGCG: [[BB_NOT_NAN]]: -// OGCG-NEXT: %[[FABS:.+]] = call float @llvm.fabs.f32(float %[[VAL]]) -// OGCG-NEXT: %[[CMP_INF:.+]] = fcmp oeq float %[[FABS]], -// OGCG-NEXT: br i1 %[[CMP_INF]], label %[[BB_RET]], label %[[BB_NOT_INF]] -// OGCG: [[BB_NOT_INF]]: -// OGCG-NEXT: %[[CMP_NORMAL:.+]] = fcmp uge float %[[FABS]], -// OGCG-NEXT: %[[SEL]] = select i1 %[[CMP_NORMAL]], i32 264, i32 144 -// OGCG-NEXT: br label %[[BB_RET]] +// LLVM: %[[FPCLASS1:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL:.*]], i32 {{.*}}) +// LLVM: br i1 %[[FPCLASS1]] +// LLVM: %[[FPCLASS2:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 {{.*}}) +// LLVM: br i1 %[[FPCLASS2]] +// LLVM: %[[FPCLASS3:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 {{.*}}) +// LLVM: br i1 %[[FPCLASS3]] +// LLVM: %[[FPCLASS4:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 {{.*}}) +// LLVM: phi i32 + +// OGCG: %[[FPCLASS1:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL:.*]], i32 {{.*}}) +// OGCG: br i1 %[[FPCLASS1]] +// OGCG: %[[FPCLASS2:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 {{.*}}) +// OGCG: br i1 %[[FPCLASS2]] +// OGCG: %[[FPCLASS3:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 {{.*}}) +// OGCG: br i1 %[[FPCLASS3]] +// OGCG: %[[FPCLASS4:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 {{.*}}) +// OGCG: phi i32 } void test_fpclassify_inf(){ @@ -98,54 +66,23 @@ void test_fpclassify_inf(){ // 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 -// LLVM: %[[VAL:.+]] = load float, ptr -// LLVM-NEXT: %[[IS_ZERO:.+]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 96) -// LLVM-NEXT: br i1 %[[IS_ZERO]], label %[[BB_ZERO:.+]], label %[[BB_NOT_ZERO:.+]] -// LLVM: [[BB_ZERO]]: -// LLVM-NEXT: br label %[[BB_RET:.+]] -// LLVM: [[BB_NOT_ZERO]]: -// LLVM-NEXT: %[[IS_NAN:.+]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 3) -// LLVM-NEXT: br i1 %[[IS_NAN]], label %[[BB_NAN:.+]], label %[[BB_NOT_NAN:.+]] -// LLVM: [[BB_NAN]]: -// LLVM-NEXT: br label %[[BB_MERGE1:.+]] -// LLVM: [[BB_NOT_NAN]]: -// LLVM-NEXT: %[[IS_INF:.+]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 516) -// LLVM-NEXT: br i1 %[[IS_INF]], label %[[BB_INF:.+]], label %[[BB_NOT_INF:.+]] -// LLVM: [[BB_INF]]: -// LLVM-NEXT: br label %[[BB_MERGE2:.+]] -// LLVM: [[BB_NOT_INF]]: -// LLVM-NEXT: %[[IS_NORMAL:.+]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 264) -// LLVM-NEXT: %[[SEL:.+]] = select i1 %[[IS_NORMAL]], i32 264, i32 144 -// LLVM-NEXT: br label %[[BB_MERGE2]] -// LLVM: [[BB_MERGE2]]: -// LLVM-NEXT: %[[PHI1:.+]] = phi i32 [ %[[SEL]], %[[BB_NOT_INF]] ], [ 516, %[[BB_INF]] ] -// LLVM-NEXT: br label %[[BB_CONT1:.+]] -// LLVM: [[BB_CONT1]]: -// LLVM-NEXT: br label %[[BB_MERGE1]] -// LLVM: [[BB_MERGE1]]: -// LLVM-NEXT: %[[PHI2:.+]] = phi i32 [ %[[PHI1]], %[[BB_CONT1]] ], [ 3, %[[BB_NAN]] ] -// LLVM-NEXT: br label %[[BB_CONT2:.+]] -// LLVM: [[BB_CONT2]]: -// LLVM-NEXT: br label %[[BB_RET]] -// LLVM: [[BB_RET]]: -// LLVM-NEXT: %[[PHI3:.+]] = phi i32 [ %[[PHI2]], %[[BB_CONT2]] ], [ 96, %[[BB_ZERO]] ] -// LLVM-NEXT: br label - -// OGCG: %[[CMP_ZERO:.+]] = fcmp oeq float %[[VAL:.+]], -// OGCG-NEXT: br i1 %[[CMP_ZERO]], label %[[BB_RET:.+]], label %[[BB_NOT_ZERO:.+]] -// OGCG: [[BB_RET]]: -// OGCG-NEXT: %[[PHI:.+]] = phi i32 [ 96, %[[BB_ENTRY:.+]] ], [ 3, %[[BB_NOT_ZERO]] ], [ 516, %[[BB_NOT_NAN:.+]] ], [ %[[SEL:.+]], %[[BB_NOT_INF:.+]] ] -// OGCG: [[BB_NOT_ZERO]]: -// OGCG-NEXT: %[[CMP_NAN:.+]] = fcmp uno float %[[VAL]], %[[VAL]] -// OGCG-NEXT: br i1 %[[CMP_NAN]], label %[[BB_RET]], label %[[BB_NOT_NAN]] -// OGCG: [[BB_NOT_NAN]]: -// OGCG-NEXT: %[[FABS:.+]] = call float @llvm.fabs.f32(float %[[VAL]]) -// OGCG-NEXT: %[[CMP_INF:.+]] = fcmp oeq float %[[FABS]], -// OGCG-NEXT: br i1 %[[CMP_INF]], label %[[BB_RET]], label %[[BB_NOT_INF]] -// OGCG: [[BB_NOT_INF]]: -// OGCG-NEXT: %[[CMP_NORMAL:.+]] = fcmp uge float %[[FABS]], -// OGCG-NEXT: %[[SEL]] = select i1 %[[CMP_NORMAL]], i32 264, i32 144 -// OGCG-NEXT: br label %[[BB_RET]] +// LLVM: %[[FPCLASS1:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL:.*]], i32 {{.*}}) +// LLVM: br i1 %[[FPCLASS1]] +// LLVM: %[[FPCLASS2:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 {{.*}}) +// LLVM: br i1 %[[FPCLASS2]] +// LLVM: %[[FPCLASS3:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 {{.*}}) +// LLVM: br i1 %[[FPCLASS3]] +// LLVM: %[[FPCLASS4:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 {{.*}}) +// LLVM: phi i32 + +// OGCG: %[[FPCLASS1:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL:.*]], i32 {{.*}}) +// OGCG: br i1 %[[FPCLASS1]] +// OGCG: %[[FPCLASS2:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 {{.*}}) +// OGCG: br i1 %[[FPCLASS2]] +// OGCG: %[[FPCLASS3:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 {{.*}}) +// OGCG: br i1 %[[FPCLASS3]] +// OGCG: %[[FPCLASS4:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 {{.*}}) +// OGCG: phi i32 } void test_fpclassify_normal(){ @@ -166,55 +103,23 @@ void test_fpclassify_normal(){ // 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 -// LLVM: %[[VAL:.*]] = load float, ptr -// LLVM-NEXT: %[[IS_ZERO:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 96) -// LLVM-NEXT: br i1 %[[IS_ZERO]], label %[[BB_ZERO:.*]], label %[[BB_NOT_ZERO:.*]] -// LLVM: [[BB_ZERO]]: -// LLVM-NEXT: br label %[[BB_RET:.*]] -// LLVM: [[BB_NOT_ZERO]]: -// LLVM-NEXT: %[[IS_NAN:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 3) -// LLVM-NEXT: br i1 %[[IS_NAN]], label %[[BB_NAN:.*]], label %[[BB_NOT_NAN:.*]] -// LLVM: [[BB_NAN]]: -// LLVM-NEXT: br label %[[BB_MERGE1:.*]] -// LLVM: [[BB_NOT_NAN]]: -// LLVM-NEXT: %[[IS_INF:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 516) -// LLVM-NEXT: br i1 %[[IS_INF]], label %[[BB_INF:.*]], label %[[BB_NOT_INF:.*]] -// LLVM: [[BB_INF]]: -// LLVM-NEXT: br label %[[BB_MERGE2:.*]] -// LLVM: [[BB_NOT_INF]]: -// LLVM-NEXT: %[[IS_NORMAL:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 264) -// LLVM-NEXT: %[[NORMAL_OR_SUBNORMAL:.*]] = select i1 %[[IS_NORMAL]], i32 264, i32 144 -// LLVM-NEXT: br label %[[BB_MERGE2]] -// LLVM: [[BB_MERGE2]]: -// LLVM-NEXT: %[[PHI_INF_SEL:.*]] = phi i32 [ %[[NORMAL_OR_SUBNORMAL]], %[[BB_NOT_INF]] ], [ 516, %[[BB_INF]] ] -// LLVM-NEXT: br label %[[BB_CONT1:.*]] -// LLVM: [[BB_CONT1]]: -// LLVM-NEXT: br label %[[BB_MERGE1]] -// LLVM: [[BB_MERGE1]]: -// LLVM-NEXT: %[[PHI_NAN_SEL:.*]] = phi i32 [ %[[PHI_INF_SEL]], %[[BB_CONT1]] ], [ 3, %[[BB_NAN]] ] -// LLVM-NEXT: br label %[[BB_CONT2:.*]] -// LLVM: [[BB_CONT2]]: -// LLVM-NEXT: br label %[[BB_RET]] -// LLVM: [[BB_RET]]: -// LLVM-NEXT: %[[PHI_FINAL:.*]] = phi i32 [ %[[PHI_NAN_SEL]], %[[BB_CONT2]] ], [ 96, %[[BB_ZERO]] ] -// LLVM-NEXT: br label %[[BB_EXIT:.*]] -// LLVM: [[BB_EXIT]]: - -// OGCG: %[[CMP_ZERO:.+]] = fcmp oeq float %[[VAL:.+]], -// OGCG-NEXT: br i1 %[[CMP_ZERO]], label %[[BB_RET:.+]], label %[[BB_NOT_ZERO:.+]] -// OGCG: [[BB_RET]]: -// OGCG-NEXT: %[[PHI:.+]] = phi i32 [ 96, %[[BB_ENTRY:.+]] ], [ 3, %[[BB_NOT_ZERO]] ], [ 516, %[[BB_NOT_NAN:.+]] ], [ %[[SEL:.+]], %[[BB_NOT_INF:.+]] ] -// OGCG: [[BB_NOT_ZERO]]: -// OGCG-NEXT: %[[CMP_NAN:.+]] = fcmp uno float %[[VAL]], %[[VAL]] -// OGCG-NEXT: br i1 %[[CMP_NAN]], label %[[BB_RET]], label %[[BB_NOT_NAN]] -// OGCG: [[BB_NOT_NAN]]: -// OGCG-NEXT: %[[FABS:.+]] = call float @llvm.fabs.f32(float %[[VAL]]) -// OGCG-NEXT: %[[CMP_INF:.+]] = fcmp oeq float %[[FABS]], -// OGCG-NEXT: br i1 %[[CMP_INF]], label %[[BB_RET]], label %[[BB_NOT_INF]] -// OGCG: [[BB_NOT_INF]]: -// OGCG-NEXT: %[[CMP_NORMAL:.+]] = fcmp uge float %[[FABS]], -// OGCG-NEXT: %[[SEL]] = select i1 %[[CMP_NORMAL]], i32 264, i32 144 -// OGCG-NEXT: br label %[[BB_RET]] +// LLVM: %[[FPCLASS1:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL:.*]], i32 {{.*}}) +// LLVM: br i1 %[[FPCLASS1]] +// LLVM: %[[FPCLASS2:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 {{.*}}) +// LLVM: br i1 %[[FPCLASS2]] +// LLVM: %[[FPCLASS3:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 {{.*}}) +// LLVM: br i1 %[[FPCLASS3]] +// LLVM: %[[FPCLASS4:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 {{.*}}) +// LLVM: phi i32 + +// OGCG: %[[FPCLASS1:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL:.*]], i32 {{.*}}) +// OGCG: br i1 %[[FPCLASS1]] +// OGCG: %[[FPCLASS2:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 {{.*}}) +// OGCG: br i1 %[[FPCLASS2]] +// OGCG: %[[FPCLASS3:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 {{.*}}) +// OGCG: br i1 %[[FPCLASS3]] +// OGCG: %[[FPCLASS4:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 {{.*}}) +// OGCG: phi i32 } void test_fpclassify_subnormal(){ @@ -235,55 +140,23 @@ void test_fpclassify_subnormal(){ // 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 -// LLVM: %[[VAL:.*]] = load float, ptr -// LLVM-NEXT: %[[IS_ZERO:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 96) -// LLVM-NEXT: br i1 %[[IS_ZERO]], label %[[BB_ZERO:.*]], label %[[BB_NOT_ZERO:.*]] -// LLVM: [[BB_ZERO]]: -// LLVM-NEXT: br label %[[BB_RET:.*]] -// LLVM: [[BB_NOT_ZERO]]: -// LLVM-NEXT: %[[IS_NAN:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 3) -// LLVM-NEXT: br i1 %[[IS_NAN]], label %[[BB_NAN:.*]], label %[[BB_NOT_NAN:.*]] -// LLVM: [[BB_NAN]]: -// LLVM-NEXT: br label %[[BB_MERGE1:.*]] -// LLVM: [[BB_NOT_NAN]]: -// LLVM-NEXT: %[[IS_INF:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 516) -// LLVM-NEXT: br i1 %[[IS_INF]], label %[[BB_INF:.*]], label %[[BB_NOT_INF:.*]] -// LLVM: [[BB_INF]]: -// LLVM-NEXT: br label %[[BB_MERGE2:.*]] -// LLVM: [[BB_NOT_INF]]: -// LLVM-NEXT: %[[IS_NORMAL:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 264) -// LLVM-NEXT: %[[NORMAL_OR_SUBNORMAL:.*]] = select i1 %[[IS_NORMAL]], i32 264, i32 144 -// LLVM-NEXT: br label %[[BB_MERGE2]] -// LLVM: [[BB_MERGE2]]: -// LLVM-NEXT: %[[PHI_INF_SEL:.*]] = phi i32 [ %[[NORMAL_OR_SUBNORMAL]], %[[BB_NOT_INF]] ], [ 516, %[[BB_INF]] ] -// LLVM-NEXT: br label %[[BB_CONT1:.*]] -// LLVM: [[BB_CONT1]]: -// LLVM-NEXT: br label %[[BB_MERGE1]] -// LLVM: [[BB_MERGE1]]: -// LLVM-NEXT: %[[PHI_NAN_SEL:.*]] = phi i32 [ %[[PHI_INF_SEL]], %[[BB_CONT1]] ], [ 3, %[[BB_NAN]] ] -// LLVM-NEXT: br label %[[BB_CONT2:.*]] -// LLVM: [[BB_CONT2]]: -// LLVM-NEXT: br label %[[BB_RET]] -// LLVM: [[BB_RET]]: -// LLVM-NEXT: %[[PHI_FINAL:.*]] = phi i32 [ %[[PHI_NAN_SEL]], %[[BB_CONT2]] ], [ 96, %[[BB_ZERO]] ] -// LLVM-NEXT: br label %[[BB_EXIT:.*]] -// LLVM: [[BB_EXIT]]: - -// OGCG: %[[CMP_ZERO:.+]] = fcmp oeq float %[[VAL:.+]], -// OGCG-NEXT: br i1 %[[CMP_ZERO]], label %[[BB_RET:.+]], label %[[BB_NOT_ZERO:.+]] -// OGCG: [[BB_RET]]: -// OGCG-NEXT: %[[PHI:.+]] = phi i32 [ 96, %[[BB_ENTRY:.+]] ], [ 3, %[[BB_NOT_ZERO]] ], [ 516, %[[BB_NOT_NAN:.+]] ], [ %[[SEL:.+]], %[[BB_NOT_INF:.+]] ] -// OGCG: [[BB_NOT_ZERO]]: -// OGCG-NEXT: %[[CMP_NAN:.+]] = fcmp uno float %[[VAL]], %[[VAL]] -// OGCG-NEXT: br i1 %[[CMP_NAN]], label %[[BB_RET]], label %[[BB_NOT_NAN]] -// OGCG: [[BB_NOT_NAN]]: -// OGCG-NEXT: %[[FABS:.+]] = call float @llvm.fabs.f32(float %[[VAL]]) -// OGCG-NEXT: %[[CMP_INF:.+]] = fcmp oeq float %[[FABS]], -// OGCG-NEXT: br i1 %[[CMP_INF]], label %[[BB_RET]], label %[[BB_NOT_INF]] -// OGCG: [[BB_NOT_INF]]: -// OGCG-NEXT: %[[CMP_NORMAL:.+]] = fcmp uge float %[[FABS]], -// OGCG-NEXT: %[[SEL]] = select i1 %[[CMP_NORMAL]], i32 264, i32 144 -// OGCG-NEXT: br label %[[BB_RET]] +// LLVM: %[[FPCLASS1:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL:.*]], i32 {{.*}}) +// LLVM: br i1 %[[FPCLASS1]] +// LLVM: %[[FPCLASS2:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 {{.*}}) +// LLVM: br i1 %[[FPCLASS2]] +// LLVM: %[[FPCLASS3:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 {{.*}}) +// LLVM: br i1 %[[FPCLASS3]] +// LLVM: %[[FPCLASS4:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 {{.*}}) +// LLVM: phi i32 + +// OGCG: %[[FPCLASS1:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL:.*]], i32 {{.*}}) +// OGCG: br i1 %[[FPCLASS1]] +// OGCG: %[[FPCLASS2:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 {{.*}}) +// OGCG: br i1 %[[FPCLASS2]] +// OGCG: %[[FPCLASS3:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 {{.*}}) +// OGCG: br i1 %[[FPCLASS3]] +// OGCG: %[[FPCLASS4:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 {{.*}}) +// OGCG: phi i32 } void test_fpclassify_zero(){ @@ -304,53 +177,21 @@ void test_fpclassify_zero(){ // 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 -// LLVM: %[[VAL:.*]] = load float, ptr -// LLVM-NEXT: %[[IS_ZERO:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 96) -// LLVM-NEXT: br i1 %[[IS_ZERO]], label %[[BB_ZERO:.*]], label %[[BB_NOT_ZERO:.*]] -// LLVM: [[BB_ZERO]]: -// LLVM-NEXT: br label %[[BB_RET:.*]] -// LLVM: [[BB_NOT_ZERO]]: -// LLVM-NEXT: %[[IS_NAN:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 3) -// LLVM-NEXT: br i1 %[[IS_NAN]], label %[[BB_NAN:.*]], label %[[BB_NOT_NAN:.*]] -// LLVM: [[BB_NAN]]: -// LLVM-NEXT: br label %[[BB_MERGE1:.*]] -// LLVM: [[BB_NOT_NAN]]: -// LLVM-NEXT: %[[IS_INF:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 516) -// LLVM-NEXT: br i1 %[[IS_INF]], label %[[BB_INF:.*]], label %[[BB_NOT_INF:.*]] -// LLVM: [[BB_INF]]: -// LLVM-NEXT: br label %[[BB_MERGE2:.*]] -// LLVM: [[BB_NOT_INF]]: -// LLVM-NEXT: %[[IS_NORMAL:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 264) -// LLVM-NEXT: %[[NORMAL_OR_SUBNORMAL:.*]] = select i1 %[[IS_NORMAL]], i32 264, i32 144 -// LLVM-NEXT: br label %[[BB_MERGE2]] -// LLVM: [[BB_MERGE2]]: -// LLVM-NEXT: %[[PHI_INF_SEL:.*]] = phi i32 [ %[[NORMAL_OR_SUBNORMAL]], %[[BB_NOT_INF]] ], [ 516, %[[BB_INF]] ] -// LLVM-NEXT: br label %[[BB_CONT1:.*]] -// LLVM: [[BB_CONT1]]: -// LLVM-NEXT: br label %[[BB_MERGE1]] -// LLVM: [[BB_MERGE1]]: -// LLVM-NEXT: %[[PHI_NAN_SEL:.*]] = phi i32 [ %[[PHI_INF_SEL]], %[[BB_CONT1]] ], [ 3, %[[BB_NAN]] ] -// LLVM-NEXT: br label %[[BB_CONT2:.*]] -// LLVM: [[BB_CONT2]]: -// LLVM-NEXT: br label %[[BB_RET]] -// LLVM: [[BB_RET]]: -// LLVM-NEXT: %[[PHI_FINAL:.*]] = phi i32 [ %[[PHI_NAN_SEL]], %[[BB_CONT2]] ], [ 96, %[[BB_ZERO]] ] -// LLVM-NEXT: br label %[[BB_EXIT:.*]] -// LLVM: [[BB_EXIT]]: - -// OGCG: %[[CMP_ZERO:.+]] = fcmp oeq float %[[VAL:.+]], -// OGCG-NEXT: br i1 %[[CMP_ZERO]], label %[[BB_RET:.+]], label %[[BB_NOT_ZERO:.+]] -// OGCG: [[BB_RET]]: -// OGCG-NEXT: %[[PHI:.+]] = phi i32 [ 96, %[[BB_ENTRY:.+]] ], [ 3, %[[BB_NOT_ZERO]] ], [ 516, %[[BB_NOT_NAN:.+]] ], [ %[[SEL:.+]], %[[BB_NOT_INF:.+]] ] -// OGCG: [[BB_NOT_ZERO]]: -// OGCG-NEXT: %[[CMP_NAN:.+]] = fcmp uno float %[[VAL]], %[[VAL]] -// OGCG-NEXT: br i1 %[[CMP_NAN]], label %[[BB_RET]], label %[[BB_NOT_NAN]] -// OGCG: [[BB_NOT_NAN]]: -// OGCG-NEXT: %[[FABS:.+]] = call float @llvm.fabs.f32(float %[[VAL]]) -// OGCG-NEXT: %[[CMP_INF:.+]] = fcmp oeq float %[[FABS]], -// OGCG-NEXT: br i1 %[[CMP_INF]], label %[[BB_RET]], label %[[BB_NOT_INF]] -// OGCG: [[BB_NOT_INF]]: -// OGCG-NEXT: %[[CMP_NORMAL:.+]] = fcmp uge float %[[FABS]], -// OGCG-NEXT: %[[SEL]] = select i1 %[[CMP_NORMAL]], i32 264, i32 144 -// OGCG-NEXT: br label %[[BB_RET]] +// LLVM: %[[FPCLASS1:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL:.*]], i32 {{.*}}) +// LLVM: br i1 %[[FPCLASS1]] +// LLVM: %[[FPCLASS2:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 {{.*}}) +// LLVM: br i1 %[[FPCLASS2]] +// LLVM: %[[FPCLASS3:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 {{.*}}) +// LLVM: br i1 %[[FPCLASS3]] +// LLVM: %[[FPCLASS4:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 {{.*}}) +// LLVM: phi i32 + +// OGCG: %[[FPCLASS1:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL:.*]], i32 {{.*}}) +// OGCG: br i1 %[[FPCLASS1]] +// OGCG: %[[FPCLASS2:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 {{.*}}) +// OGCG: br i1 %[[FPCLASS2]] +// OGCG: %[[FPCLASS3:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 {{.*}}) +// OGCG: br i1 %[[FPCLASS3]] +// OGCG: %[[FPCLASS4:.*]] = call i1 @llvm.is.fpclass.f32(float %[[VAL]], i32 {{.*}}) +// OGCG: phi i32 } diff --git a/clang/test/CodeGen/builtin-fpclassify.c b/clang/test/CodeGen/builtin-fpclassify.c new file mode 100644 index 0000000000000..d9ae3d1a5218a --- /dev/null +++ b/clang/test/CodeGen/builtin-fpclassify.c @@ -0,0 +1,92 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o - | FileCheck %s + +#define FP_NAN 3 +#define FP_INFINITE 516 +#define FP_ZERO 96 +#define FP_SUBNORMAL 144 +#define FP_NORMAL 264 + +void test_fpclassify_nan() { + float nanValue = 0.0f / 0.0f; + __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL, FP_SUBNORMAL, FP_ZERO, + nanValue); +// CHECK-LABEL: entry: +// CHECK: call i1 @llvm.is.fpclass.f32(float %{{.*}}, i32 3) +// CHECK: br i1 %{{.*}}, label %fpclassify_end, label %fpclassify_not_nan +// CHECK-LABEL: fpclassify_not_nan: +// CHECK: call i1 @llvm.is.fpclass.f32(float %{{.*}}, i32 516) +// CHECK-LABEL: fpclassify_not_infinite: +// CHECK: call i1 @llvm.is.fpclass.f32(float %{{.*}}, i32 264) +// CHECK-LABEL: fpclassify_not_normal: +// CHECK: call i1 @llvm.is.fpclass.f32(float %{{.*}}, i32 144) +// CHECK-LABEL: fpclassify_end: +// CHECK: %fpclassify_result = phi i32 [ 3, %entry ], [ 516, %fpclassify_not_nan ], [ 264, %fpclassify_not_infinite ], [ 144, %fpclassify_not_normal ], [ 96, %fpclassify_not_subnormal ] +} + +void test_fpclassify_inf() { + float infValue = 1.0f / 0.0f; + __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL, FP_SUBNORMAL, FP_ZERO, + infValue); +// CHECK-LABEL: entry: +// CHECK: call i1 @llvm.is.fpclass.f32(float %{{.*}}, i32 3) +// CHECK: br i1 %{{.*}}, label %fpclassify_end, label %fpclassify_not_nan +// CHECK-LABEL: fpclassify_not_nan: +// CHECK: call i1 @llvm.is.fpclass.f32(float %{{.*}}, i32 516) +// CHECK-LABEL: fpclassify_not_infinite: +// CHECK: call i1 @llvm.is.fpclass.f32(float %{{.*}}, i32 264) +// CHECK-LABEL: fpclassify_not_normal: +// CHECK: call i1 @llvm.is.fpclass.f32(float %{{.*}}, i32 144) +// CHECK-LABEL: fpclassify_end: +// CHECK: %fpclassify_result = phi i32 [ 3, %entry ], [ 516, %fpclassify_not_nan ], [ 264, %fpclassify_not_infinite ], [ 144, %fpclassify_not_normal ], [ 96, %fpclassify_not_subnormal ] +} + +void test_fpclassify_normal() { + float normalValue = 1.0f; + __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL, FP_SUBNORMAL, FP_ZERO, + normalValue); +// CHECK-LABEL: entry: +// CHECK: call i1 @llvm.is.fpclass.f32(float %{{.*}}, i32 3) +// CHECK: br i1 %{{.*}}, label %fpclassify_end, label %fpclassify_not_nan +// CHECK-LABEL: fpclassify_not_nan: +// CHECK: call i1 @llvm.is.fpclass.f32(float %{{.*}}, i32 516) +// CHECK-LABEL: fpclassify_not_infinite: +// CHECK: call i1 @llvm.is.fpclass.f32(float %{{.*}}, i32 264) +// CHECK-LABEL: fpclassify_not_normal: +// CHECK: call i1 @llvm.is.fpclass.f32(float %{{.*}}, i32 144) +// CHECK-LABEL: fpclassify_end: +// CHECK: %fpclassify_result = phi i32 [ 3, %entry ], [ 516, %fpclassify_not_nan ], [ 264, %fpclassify_not_infinite ], [ 144, %fpclassify_not_normal ], [ 96, %fpclassify_not_subnormal ] +} + +void test_fpclassify_subnormal() { + float subnormalValue = 1.0e-40f; + __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL, FP_SUBNORMAL, FP_ZERO, + subnormalValue); +// CHECK-LABEL: entry: +// CHECK: call i1 @llvm.is.fpclass.f32(float %{{.*}}, i32 3) +// CHECK: br i1 %{{.*}}, label %fpclassify_end, label %fpclassify_not_nan +// CHECK-LABEL: fpclassify_not_nan: +// CHECK: call i1 @llvm.is.fpclass.f32(float %{{.*}}, i32 516) +// CHECK-LABEL: fpclassify_not_infinite: +// CHECK: call i1 @llvm.is.fpclass.f32(float %{{.*}}, i32 264) +// CHECK-LABEL: fpclassify_not_normal: +// CHECK: call i1 @llvm.is.fpclass.f32(float %{{.*}}, i32 144) +// CHECK-LABEL: fpclassify_end: +// CHECK: %fpclassify_result = phi i32 [ 3, %entry ], [ 516, %fpclassify_not_nan ], [ 264, %fpclassify_not_infinite ], [ 144, %fpclassify_not_normal ], [ 96, %fpclassify_not_subnormal ] +} + +void test_fpclassify_zero() { + float zeroValue = 0.0f; + __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL, FP_SUBNORMAL, FP_ZERO, + zeroValue); +// CHECK-LABEL: entry: +// CHECK: call i1 @llvm.is.fpclass.f32(float %{{.*}}, i32 3) +// CHECK: br i1 %{{.*}}, label %fpclassify_end, label %fpclassify_not_nan +// CHECK-LABEL: fpclassify_not_nan: +// CHECK: call i1 @llvm.is.fpclass.f32(float %{{.*}}, i32 516) +// CHECK-LABEL: fpclassify_not_infinite: +// CHECK: call i1 @llvm.is.fpclass.f32(float %{{.*}}, i32 264) +// CHECK-LABEL: fpclassify_not_normal: +// CHECK: call i1 @llvm.is.fpclass.f32(float %{{.*}}, i32 144) +// CHECK-LABEL: fpclassify_end: +// CHECK: %fpclassify_result = phi i32 [ 3, %entry ], [ 516, %fpclassify_not_nan ], [ 264, %fpclassify_not_infinite ], [ 144, %fpclassify_not_normal ], [ 96, %fpclassify_not_subnormal ] +} diff --git a/clang/test/Headers/nvptx_device_math_macro.cpp b/clang/test/Headers/nvptx_device_math_macro.cpp index 3faf527daf113..e360401e0e2d3 100644 --- a/clang/test/Headers/nvptx_device_math_macro.cpp +++ b/clang/test/Headers/nvptx_device_math_macro.cpp @@ -8,10 +8,10 @@ #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 return (std::fpclassify(a) != FP_ZERO); +// CHECK: call i1 @llvm.is.fpclass.f64(double {{.*}}, i32 {{.*}}) +// CHECK: call i1 @llvm.is.fpclass.f64(double {{.*}}, i32 {{.*}}) +// CHECK: call i1 @llvm.is.fpclass.f64(double {{.*}}, i32 {{.*}}) +// CHECK: call i1 @llvm.is.fpclass.f64(double {{.*}}, i32 {{.*}}) } #pragma omp end declare target _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
