[clang] [Clang] Reimplement __builtin_fpclassify using llvm.is.fpclass to fix FE_INVALID exception on sNaN (PR #190848)

Yeongu Choe via cfe-commits cfe-commits at lists.llvm.org
Sat May 2 21:56:49 PDT 2026


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

>From 7e4320f5e120bc32d94572c6cd2e7d1c06942bbd Mon Sep 17 00:00:00 2001
From: YeonguChoe <yeongu.choe at icloud.com>
Date: Tue, 7 Apr 2026 16:31:28 -0400
Subject: [PATCH 1/3] [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

>From b13bbd7198eb3ccdc88bff4f59ee382cef06f51f Mon Sep 17 00:00:00 2001
From: YeonguChoe <yeongu.choe at icloud.com>
Date: Tue, 7 Apr 2026 17:23:44 -0400
Subject: [PATCH 2/3] Change FileCheck test code that uses fpclassify

---
 clang/test/CodeGen/strictfp_builtins.c | 43 ++++++++++++++------------
 1 file changed, 24 insertions(+), 19 deletions(-)

diff --git a/clang/test/CodeGen/strictfp_builtins.c b/clang/test/CodeGen/strictfp_builtins.c
index 58815c7de4fa9..6cb76e431bea7 100644
--- a/clang/test/CodeGen/strictfp_builtins.c
+++ b/clang/test/CodeGen/strictfp_builtins.c
@@ -28,26 +28,26 @@ void p(char *str, int x) {
 
 // CHECK-LABEL: @test_fpclassify(
 // CHECK-NEXT:  entry:
-// 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:    {{.*}} = alloca double, align 8
+// CHECK-NEXT:    store double {{.*}}, ptr {{.*}}, align 8
+// CHECK-NEXT:    {{.*}} = load double, ptr {{.*}}, align 8
+// CHECK-NEXT:    {{.*}} = call i1 @llvm.is.fpclass.f64(double {{.*}}, i32 3) #[[ATTR4]]
+// CHECK-NEXT:    br i1 {{.*}}, label {{.*}}, label {{.*}}
+// CHECK:       fpclassify_not_nan:
+// CHECK-NEXT:    {{.*}} = call i1 @llvm.is.fpclass.f64(double {{.*}}, i32 516) #[[ATTR4]]
+// CHECK-NEXT:    br i1 {{.*}}, label {{.*}}, label {{.*}}
+// CHECK:       fpclassify_not_infinite:
+// CHECK-NEXT:    {{.*}} = call i1 @llvm.is.fpclass.f64(double {{.*}}, i32 264) #[[ATTR4]]
+// CHECK-NEXT:    br i1 {{.*}}, label {{.*}}, label {{.*}}
+// CHECK:       fpclassify_not_normal:
+// CHECK-NEXT:    {{.*}} = call i1 @llvm.is.fpclass.f64(double {{.*}}, i32 144) #[[ATTR4]]
+// CHECK-NEXT:    br i1 {{.*}}, label {{.*}}, label {{.*}}
+// CHECK:       fpclassify_not_subnormal:
+// CHECK-NEXT:    br label {{.*}}
 // 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:    call void @p(ptr noundef @.str.1, i32 noundef [[FPCLASSIFY_RESULT]]) #[[ATTR4]]
+// CHECK-NEXT:    {{.*}} = phi i32 [ 0, {{.*}} ], [ 1, {{.*}} ], [ 2, {{.*}} ], [ 3, {{.*}} ], [ 4, {{.*}} ]
+// CHECK-NEXT:    call void @p(ptr noundef @.str.1, i32 noundef {{.*}}) #[[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:       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 label [[FPCLASSIFY_END]]
 //
 void test_fpclassify(double d) {
   P(fpclassify, (0, 1, 2, 3, 4, d));
@@ -156,7 +156,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]]) #[[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:    [[TMP2:%.*]] = bitcast double [[TMP0]] to i64
 // CHECK-NEXT:    [[TMP3:%.*]] = icmp slt i64 [[TMP2]], 0
@@ -234,3 +234,8 @@ void test_isnormal(double d) {
 
   return;
 }
+
+//.
+//. CHECK: attributes #[[ATTR4]] = { strictfp }
+//. CHECK: attributes #[[ATTR5]] = { strictfp memory(none) }
+//.

>From 53c51ddafc48d70acb49c4195f0a568543402410 Mon Sep 17 00:00:00 2001
From: YeonguChoe <yeongu.choe at icloud.com>
Date: Sun, 3 May 2026 00:55:14 -0400
Subject: [PATCH 3/3] Fix nit

- Move argument read code to right above where it is needed (EmitScalarExpr(E->getArg())).
- Make FileCheck to test check code generation without checking specific values.
---
 clang/lib/CodeGen/CGBuiltin.cpp         |  21 ++--
 clang/test/CodeGen/builtin-fpclassify.c | 158 ++++++++++++------------
 2 files changed, 89 insertions(+), 90 deletions(-)

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index b260a36e877b5..dd69a78931f15 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -4416,13 +4416,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
   case Builtin::BI__builtin_fpclassify: {
     CodeGenFunction::CGFPOptionsRAII FPOptsRAII(*this, E);
 
-    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));
-
     BasicBlock *Entry = Builder.GetInsertBlock();
     BasicBlock *NotNan = createBasicBlock("fpclassify_not_nan", CurFn);
     BasicBlock *NotInfinite =
@@ -4439,30 +4432,36 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
 
     // Entry Block
     Builder.SetInsertPoint(Entry);
-    Value *IsNan = Builder.createIsFPClass(V, FPClassTest::fcNan);
+    Value *NanLiteral = EmitScalarExpr(E->getArg(0));
     Result->addIncoming(NanLiteral, Entry);
+    Value *V = EmitScalarExpr(E->getArg(5));
+    Value *IsNan = Builder.createIsFPClass(V, FPClassTest::fcNan);
     Builder.CreateCondBr(IsNan, End, NotNan);
 
     // NotNan Block
     Builder.SetInsertPoint(NotNan);
-    Value *IsInfinite = Builder.createIsFPClass(V, FPClassTest::fcInf);
+    Value *InfiniteLiteral = EmitScalarExpr(E->getArg(1));
     Result->addIncoming(InfiniteLiteral, NotNan);
+    Value *IsInfinite = Builder.createIsFPClass(V, FPClassTest::fcInf);
     Builder.CreateCondBr(IsInfinite, End, NotInfinite);
 
     // NotInfinite Block
     Builder.SetInsertPoint(NotInfinite);
-    Value *IsNormal = Builder.createIsFPClass(V, FPClassTest::fcNormal);
+    Value *NormalLiteral = EmitScalarExpr(E->getArg(2));
     Result->addIncoming(NormalLiteral, NotInfinite);
+    Value *IsNormal = Builder.createIsFPClass(V, FPClassTest::fcNormal);
     Builder.CreateCondBr(IsNormal, End, NotNormal);
 
     // NotNormal Block
     Builder.SetInsertPoint(NotNormal);
-    Value *IsSubnormal = Builder.createIsFPClass(V, FPClassTest::fcSubnormal);
+    Value *SubnormalLiteral = EmitScalarExpr(E->getArg(3));
     Result->addIncoming(SubnormalLiteral, NotNormal);
+    Value *IsSubnormal = Builder.createIsFPClass(V, FPClassTest::fcSubnormal);
     Builder.CreateCondBr(IsSubnormal, End, NotSubnormal);
 
     // NotSubnormal Block
     Builder.SetInsertPoint(NotSubnormal);
+    Value *ZeroLiteral = EmitScalarExpr(E->getArg(4));
     Result->addIncoming(ZeroLiteral, NotSubnormal);
     Builder.CreateBr(End);
 
diff --git a/clang/test/CodeGen/builtin-fpclassify.c b/clang/test/CodeGen/builtin-fpclassify.c
index d9ae3d1a5218a..e11c1e1259987 100644
--- a/clang/test/CodeGen/builtin-fpclassify.c
+++ b/clang/test/CodeGen/builtin-fpclassify.c
@@ -1,3 +1,4 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 6
 // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o - | FileCheck %s
 
 #define FP_NAN 3
@@ -6,87 +7,86 @@
 #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 ]
+// CHECK-LABEL: define dso_local i32 @test_fpclassify_float(
+// CHECK-SAME: float noundef [[X:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT:  [[ENTRY:.*]]:
+// CHECK-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-NEXT:    [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f32(float [[TMP0]], i32 3)
+// CHECK-NEXT:    br i1 [[TMP1]], label %[[FPCLASSIFY_END:.*]], label %[[FPCLASSIFY_NOT_NAN:.*]]
+// CHECK:       [[FPCLASSIFY_NOT_NAN]]:
+// CHECK-NEXT:    [[TMP2:%.*]] = call i1 @llvm.is.fpclass.f32(float [[TMP0]], i32 516)
+// CHECK-NEXT:    br i1 [[TMP2]], label %[[FPCLASSIFY_END]], label %[[FPCLASSIFY_NOT_INFINITE:.*]]
+// CHECK:       [[FPCLASSIFY_NOT_INFINITE]]:
+// CHECK-NEXT:    [[TMP3:%.*]] = call i1 @llvm.is.fpclass.f32(float [[TMP0]], i32 264)
+// CHECK-NEXT:    br i1 [[TMP3]], label %[[FPCLASSIFY_END]], label %[[FPCLASSIFY_NOT_NORMAL:.*]]
+// CHECK:       [[FPCLASSIFY_NOT_NORMAL]]:
+// CHECK-NEXT:    [[TMP4:%.*]] = call i1 @llvm.is.fpclass.f32(float [[TMP0]], i32 144)
+// CHECK-NEXT:    br i1 [[TMP4]], label %[[FPCLASSIFY_END]], label %[[FPCLASSIFY_NOT_SUBNORMAL:.*]]
+// CHECK:       [[FPCLASSIFY_NOT_SUBNORMAL]]:
+// CHECK-NEXT:    br label %[[FPCLASSIFY_END]]
+// CHECK:       [[FPCLASSIFY_END]]:
+// CHECK-NEXT:    [[FPCLASSIFY_RESULT:%.*]] = phi i32 [ 3, %[[ENTRY]] ], [ 516, %[[FPCLASSIFY_NOT_NAN]] ], [ 264, %[[FPCLASSIFY_NOT_INFINITE]] ], [ 144, %[[FPCLASSIFY_NOT_NORMAL]] ], [ 96, %[[FPCLASSIFY_NOT_SUBNORMAL]] ]
+// CHECK-NEXT:    ret i32 [[FPCLASSIFY_RESULT]]
+//
+int test_fpclassify_float(float x) {
+  return __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL, FP_SUBNORMAL,
+                              FP_ZERO, x);
 }
 
-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 ]
+// CHECK-LABEL: define dso_local i32 @test_fpclassify_double(
+// CHECK-SAME: double noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*]]:
+// CHECK-NEXT:    [[X_ADDR:%.*]] = alloca double, align 8
+// CHECK-NEXT:    store double [[X]], ptr [[X_ADDR]], align 8
+// CHECK-NEXT:    [[TMP0:%.*]] = load double, ptr [[X_ADDR]], align 8
+// CHECK-NEXT:    [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f64(double [[TMP0]], i32 3)
+// CHECK-NEXT:    br i1 [[TMP1]], label %[[FPCLASSIFY_END:.*]], label %[[FPCLASSIFY_NOT_NAN:.*]]
+// CHECK:       [[FPCLASSIFY_NOT_NAN]]:
+// CHECK-NEXT:    [[TMP2:%.*]] = call i1 @llvm.is.fpclass.f64(double [[TMP0]], i32 516)
+// CHECK-NEXT:    br i1 [[TMP2]], label %[[FPCLASSIFY_END]], label %[[FPCLASSIFY_NOT_INFINITE:.*]]
+// CHECK:       [[FPCLASSIFY_NOT_INFINITE]]:
+// CHECK-NEXT:    [[TMP3:%.*]] = call i1 @llvm.is.fpclass.f64(double [[TMP0]], i32 264)
+// CHECK-NEXT:    br i1 [[TMP3]], label %[[FPCLASSIFY_END]], label %[[FPCLASSIFY_NOT_NORMAL:.*]]
+// CHECK:       [[FPCLASSIFY_NOT_NORMAL]]:
+// CHECK-NEXT:    [[TMP4:%.*]] = call i1 @llvm.is.fpclass.f64(double [[TMP0]], i32 144)
+// CHECK-NEXT:    br i1 [[TMP4]], label %[[FPCLASSIFY_END]], label %[[FPCLASSIFY_NOT_SUBNORMAL:.*]]
+// CHECK:       [[FPCLASSIFY_NOT_SUBNORMAL]]:
+// CHECK-NEXT:    br label %[[FPCLASSIFY_END]]
+// CHECK:       [[FPCLASSIFY_END]]:
+// CHECK-NEXT:    [[FPCLASSIFY_RESULT:%.*]] = phi i32 [ 3, %[[ENTRY]] ], [ 516, %[[FPCLASSIFY_NOT_NAN]] ], [ 264, %[[FPCLASSIFY_NOT_INFINITE]] ], [ 144, %[[FPCLASSIFY_NOT_NORMAL]] ], [ 96, %[[FPCLASSIFY_NOT_SUBNORMAL]] ]
+// CHECK-NEXT:    ret i32 [[FPCLASSIFY_RESULT]]
+//
+int test_fpclassify_double(double x) {
+  return __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL, FP_SUBNORMAL,
+                              FP_ZERO, x);
 }
 
-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 ]
+// CHECK-LABEL: define dso_local i32 @test_fpclassify_long_double(
+// CHECK-SAME: x86_fp80 noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*]]:
+// CHECK-NEXT:    [[X_ADDR:%.*]] = alloca x86_fp80, align 16
+// CHECK-NEXT:    store x86_fp80 [[X]], ptr [[X_ADDR]], align 16
+// CHECK-NEXT:    [[TMP0:%.*]] = load x86_fp80, ptr [[X_ADDR]], align 16
+// CHECK-NEXT:    [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f80(x86_fp80 [[TMP0]], i32 3)
+// CHECK-NEXT:    br i1 [[TMP1]], label %[[FPCLASSIFY_END:.*]], label %[[FPCLASSIFY_NOT_NAN:.*]]
+// CHECK:       [[FPCLASSIFY_NOT_NAN]]:
+// CHECK-NEXT:    [[TMP2:%.*]] = call i1 @llvm.is.fpclass.f80(x86_fp80 [[TMP0]], i32 516)
+// CHECK-NEXT:    br i1 [[TMP2]], label %[[FPCLASSIFY_END]], label %[[FPCLASSIFY_NOT_INFINITE:.*]]
+// CHECK:       [[FPCLASSIFY_NOT_INFINITE]]:
+// CHECK-NEXT:    [[TMP3:%.*]] = call i1 @llvm.is.fpclass.f80(x86_fp80 [[TMP0]], i32 264)
+// CHECK-NEXT:    br i1 [[TMP3]], label %[[FPCLASSIFY_END]], label %[[FPCLASSIFY_NOT_NORMAL:.*]]
+// CHECK:       [[FPCLASSIFY_NOT_NORMAL]]:
+// CHECK-NEXT:    [[TMP4:%.*]] = call i1 @llvm.is.fpclass.f80(x86_fp80 [[TMP0]], i32 144)
+// CHECK-NEXT:    br i1 [[TMP4]], label %[[FPCLASSIFY_END]], label %[[FPCLASSIFY_NOT_SUBNORMAL:.*]]
+// CHECK:       [[FPCLASSIFY_NOT_SUBNORMAL]]:
+// CHECK-NEXT:    br label %[[FPCLASSIFY_END]]
+// CHECK:       [[FPCLASSIFY_END]]:
+// CHECK-NEXT:    [[FPCLASSIFY_RESULT:%.*]] = phi i32 [ 3, %[[ENTRY]] ], [ 516, %[[FPCLASSIFY_NOT_NAN]] ], [ 264, %[[FPCLASSIFY_NOT_INFINITE]] ], [ 144, %[[FPCLASSIFY_NOT_NORMAL]] ], [ 96, %[[FPCLASSIFY_NOT_SUBNORMAL]] ]
+// CHECK-NEXT:    ret i32 [[FPCLASSIFY_RESULT]]
+//
+int test_fpclassify_long_double(long double x) {
+  return __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL, FP_SUBNORMAL,
+                              FP_ZERO, x);
 }



More information about the cfe-commits mailing list