https://github.com/YeonguChoe created 
https://github.com/llvm/llvm-project/pull/187977

I implemented CIR version of __builtin_fpclassify function.

Reference
- 
https://gcc.gnu.org/onlinedocs/gcc/Floating-Point-Format-Builtins.html#index-_005f_005fbuiltin_005ffpclassify
- https://en.cppreference.com/w/cpp/numeric/math/fpclassify.html

>From 30de15cb2a794c602f95cfe8040ad3fbe2a609f5 Mon Sep 17 00:00:00 2001
From: YeonguChoe <[email protected]>
Date: Mon, 23 Mar 2026 02:00:14 -0400
Subject: [PATCH] [CIR][CodeGen] Implement __builtin_fpclassify

__builtin_fpclassify is a function that classifies a floating-point value as 
NaN, infinite, zero, subnormal, or normal.
---
 clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp       |  64 +++-
 .../CIR/CodeGenBuiltins/builtin-fpclassify.c  | 356 ++++++++++++++++++
 2 files changed, 419 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/CIR/CodeGenBuiltins/builtin-fpclassify.c

diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp 
b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index 1c62543d40bb3..1c2120b4b04f1 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -1582,8 +1582,70 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl 
&gd, unsigned builtinID,
   }
   case Builtin::BI__builtin_flt_rounds:
   case Builtin::BI__builtin_set_flt_rounds:
-  case Builtin::BI__builtin_fpclassify:
     return errorBuiltinNYI(*this, e, builtinID);
+  case Builtin::BI__builtin_fpclassify: {
+    CIRGenFunction::CIRGenFPOptionsRAII fPOptsRAII(*this, e);
+    mlir::Location loc = getLoc(e->getBeginLoc());
+    mlir::Value value = emitScalarExpr(e->getArg(5));
+    mlir::Type resultTy = convertType(e->getType());
+    auto isZero =
+        cir::IsFPClassOp::create(builder, loc, value, cir::FPClassTest::Zero);
+    mlir::Value result =
+        cir::TernaryOp::create(
+            builder, loc, isZero,
+            [&](mlir::OpBuilder &opBuilder, mlir::Location location) {
+              mlir::Value zeroLiteral = emitScalarExpr(e->getArg(4));
+              cir::YieldOp::create(opBuilder, location, zeroLiteral);
+            },
+            [&](mlir::OpBuilder &opBuilder, mlir::Location location) {
+              auto isNan = cir::IsFPClassOp::create(opBuilder, location, value,
+                                                    cir::FPClassTest::Nan);
+              mlir::Value nanResult =
+                  cir::TernaryOp::create(
+                      opBuilder, location, isNan,
+                      [&](mlir::OpBuilder &opBuilder, mlir::Location location) 
{
+                        mlir::Value nanLiteral = emitScalarExpr(e->getArg(0));
+                        cir::YieldOp::create(opBuilder, location, nanLiteral);
+                      },
+                      [&](mlir::OpBuilder &opBuilder, mlir::Location location) 
{
+                        auto isInfinity = cir::IsFPClassOp::create(
+                            opBuilder, location, value,
+                            cir::FPClassTest::Infinity);
+                        mlir::Value infResult =
+                            cir::TernaryOp::create(
+                                opBuilder, location, isInfinity,
+                                [&](mlir::OpBuilder &opBuilder,
+                                    mlir::Location location) {
+                                  mlir::Value infinityLiteral =
+                                      emitScalarExpr(e->getArg(1));
+                                  cir::YieldOp::create(opBuilder, location,
+                                                       infinityLiteral);
+                                },
+                                [&](mlir::OpBuilder &opBuilder,
+                                    mlir::Location location) {
+                                  auto isNormal = cir::IsFPClassOp::create(
+                                      opBuilder, location, value,
+                                      cir::FPClassTest::Normal);
+                                  mlir::Value fpNormal =
+                                      emitScalarExpr(e->getArg(2));
+                                  mlir::Value fpSubnormal =
+                                      emitScalarExpr(e->getArg(3));
+                                  mlir::Value returnValue =
+                                      cir::SelectOp::create(
+                                          opBuilder, location, resultTy,
+                                          isNormal, fpNormal, fpSubnormal);
+                                  cir::YieldOp::create(opBuilder, location,
+                                                       returnValue);
+                                })
+                                .getResult();
+                        cir::YieldOp::create(opBuilder, location, infResult);
+                      })
+                      .getResult();
+              cir::YieldOp::create(opBuilder, location, nanResult);
+            })
+            .getResult();
+    return RValue::get(result);
+  }
   case Builtin::BIalloca:
   case Builtin::BI_alloca:
   case Builtin::BI__builtin_alloca_uninitialized:
diff --git a/clang/test/CIR/CodeGenBuiltins/builtin-fpclassify.c 
b/clang/test/CIR/CodeGenBuiltins/builtin-fpclassify.c
new file mode 100644
index 0000000000000..bad83c4f0ef4c
--- /dev/null
+++ b/clang/test/CIR/CodeGenBuiltins/builtin-fpclassify.c
@@ -0,0 +1,356 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o 
%t.cir
+// RUN: FileCheck %s --check-prefix=CIR --input-file %t.cir
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o 
%t-cir.ll
+// RUN: FileCheck %s --check-prefix=LLVM --input-file %t-cir.ll
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
+// RUN: FileCheck %s --check-prefix=OGCG --input-file %t.ll
+
+#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);
+// CIR: %[[IS_ZERO:.+]] = cir.is_fp_class %{{.+}}, fcZero : (!cir.float) -> 
!cir.bool
+// CIR: cir.ternary(%[[IS_ZERO]], true {
+// CIR: cir.const #cir.int<96> : !s32i
+// CIR: %[[IS_NAN:.+]] = cir.is_fp_class %{{.+}}, fcNan : (!cir.float) -> 
!cir.bool
+// CIR: cir.ternary(%[[IS_NAN]], true {
+// CIR: cir.const #cir.int<3> : !s32i
+// CIR: %[[IS_INF:.+]] = cir.is_fp_class %{{.+}}, fcInf : (!cir.float) -> 
!cir.bool
+// CIR: cir.ternary(%[[IS_INF]], true {
+// CIR: cir.const #cir.int<516> : !s32i
+// CIR: %[[IS_NORMAL:.+]] = cir.is_fp_class %{{.+}}, fcNormal : (!cir.float) 
-> !cir.bool
+// CIR: %[[NORMAL_VAL:.+]] = cir.const #cir.int<264> : !s32i
+// CIR: %[[SUBNORMAL_VAL:.+]] = cir.const #cir.int<144> : !s32i
+// CIR: cir.select if %[[IS_NORMAL]] then %[[NORMAL_VAL]] else 
%[[SUBNORMAL_VAL]] : (!cir.bool, !s32i, !s32i) -> !s32i
+
+// 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]]
+}
+
+void test_fpclassify_inf(){
+    float infValue = 1.0f / 0.0f;
+    __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL,
+                                         FP_SUBNORMAL, FP_ZERO, infValue);
+// CIR: %[[IS_ZERO:.+]] = cir.is_fp_class %{{.+}}, fcZero : (!cir.float) -> 
!cir.bool
+// CIR: cir.ternary(%[[IS_ZERO]], true {
+// CIR: cir.const #cir.int<96> : !s32i
+// CIR: %[[IS_NAN:.+]] = cir.is_fp_class %{{.+}}, fcNan : (!cir.float) -> 
!cir.bool
+// CIR: cir.ternary(%[[IS_NAN]], true {
+// CIR: cir.const #cir.int<3> : !s32i
+// CIR: %[[IS_INF:.+]] = cir.is_fp_class %{{.+}}, fcInf : (!cir.float) -> 
!cir.bool
+// CIR: cir.ternary(%[[IS_INF]], true {
+// CIR: cir.const #cir.int<516> : !s32i
+// CIR: %[[IS_NORMAL:.+]] = cir.is_fp_class %{{.+}}, fcNormal : (!cir.float) 
-> !cir.bool
+// CIR: %[[NORMAL_VAL:.+]] = cir.const #cir.int<264> : !s32i
+// CIR: %[[SUBNORMAL_VAL:.+]] = cir.const #cir.int<144> : !s32i
+// CIR: cir.select if %[[IS_NORMAL]] then %[[NORMAL_VAL]] else 
%[[SUBNORMAL_VAL]] : (!cir.bool, !s32i, !s32i) -> !s32i
+
+// 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]]
+}
+
+void test_fpclassify_normal(){
+    float normalValue = 1.0f;
+    __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL,
+                                            FP_SUBNORMAL, FP_ZERO, 
normalValue);
+// CIR: %[[IS_ZERO:.+]] = cir.is_fp_class %{{.+}}, fcZero : (!cir.float) -> 
!cir.bool
+// CIR: cir.ternary(%[[IS_ZERO]], true {
+// CIR: cir.const #cir.int<96> : !s32i
+// CIR: %[[IS_NAN:.+]] = cir.is_fp_class %{{.+}}, fcNan : (!cir.float) -> 
!cir.bool
+// CIR: cir.ternary(%[[IS_NAN]], true {
+// CIR: cir.const #cir.int<3> : !s32i
+// CIR: %[[IS_INF:.+]] = cir.is_fp_class %{{.+}}, fcInf : (!cir.float) -> 
!cir.bool
+// CIR: cir.ternary(%[[IS_INF]], true {
+// CIR: cir.const #cir.int<516> : !s32i
+// CIR: %[[IS_NORMAL:.+]] = cir.is_fp_class %{{.+}}, fcNormal : (!cir.float) 
-> !cir.bool
+// CIR: %[[NORMAL_VAL:.+]] = cir.const #cir.int<264> : !s32i
+// CIR: %[[SUBNORMAL_VAL:.+]] = cir.const #cir.int<144> : !s32i
+// CIR: cir.select if %[[IS_NORMAL]] then %[[NORMAL_VAL]] else 
%[[SUBNORMAL_VAL]] : (!cir.bool, !s32i, !s32i) -> !s32i
+
+// 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]]
+}
+
+void test_fpclassify_subnormal(){
+    float subnormalValue = 1.0e-40f;
+    __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL,
+                                               FP_SUBNORMAL, FP_ZERO, 
subnormalValue);
+// CIR: %[[IS_ZERO:.+]] = cir.is_fp_class %{{.+}}, fcZero : (!cir.float) -> 
!cir.bool
+// CIR: cir.ternary(%[[IS_ZERO]], true {
+// CIR: cir.const #cir.int<96> : !s32i
+// CIR: %[[IS_NAN:.+]] = cir.is_fp_class %{{.+}}, fcNan : (!cir.float) -> 
!cir.bool
+// CIR: cir.ternary(%[[IS_NAN]], true {
+// CIR: cir.const #cir.int<3> : !s32i
+// CIR: %[[IS_INF:.+]] = cir.is_fp_class %{{.+}}, fcInf : (!cir.float) -> 
!cir.bool
+// CIR: cir.ternary(%[[IS_INF]], true {
+// CIR: cir.const #cir.int<516> : !s32i
+// CIR: %[[IS_NORMAL:.+]] = cir.is_fp_class %{{.+}}, fcNormal : (!cir.float) 
-> !cir.bool
+// CIR: %[[NORMAL_VAL:.+]] = cir.const #cir.int<264> : !s32i
+// CIR: %[[SUBNORMAL_VAL:.+]] = cir.const #cir.int<144> : !s32i
+// CIR: cir.select if %[[IS_NORMAL]] then %[[NORMAL_VAL]] else 
%[[SUBNORMAL_VAL]] : (!cir.bool, !s32i, !s32i) -> !s32i
+
+// 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]]
+}
+
+void test_fpclassify_zero(){
+    float zeroValue = 0.0f;
+    __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL,
+                                          FP_SUBNORMAL, FP_ZERO, zeroValue);
+// CIR: %[[IS_ZERO:.+]] = cir.is_fp_class %{{.+}}, fcZero : (!cir.float) -> 
!cir.bool
+// CIR: cir.ternary(%[[IS_ZERO]], true {
+// CIR: cir.const #cir.int<96> : !s32i
+// CIR: %[[IS_NAN:.+]] = cir.is_fp_class %{{.+}}, fcNan : (!cir.float) -> 
!cir.bool
+// CIR: cir.ternary(%[[IS_NAN]], true {
+// CIR: cir.const #cir.int<3> : !s32i
+// CIR: %[[IS_INF:.+]] = cir.is_fp_class %{{.+}}, fcInf : (!cir.float) -> 
!cir.bool
+// CIR: cir.ternary(%[[IS_INF]], true {
+// CIR: cir.const #cir.int<516> : !s32i
+// CIR: %[[IS_NORMAL:.+]] = cir.is_fp_class %{{.+}}, fcNormal : (!cir.float) 
-> !cir.bool
+// CIR: %[[NORMAL_VAL:.+]] = cir.const #cir.int<264> : !s32i
+// CIR: %[[SUBNORMAL_VAL:.+]] = cir.const #cir.int<144> : !s32i
+// CIR: cir.select if %[[IS_NORMAL]] then %[[NORMAL_VAL]] else 
%[[SUBNORMAL_VAL]] : (!cir.bool, !s32i, !s32i) -> !s32i
+
+// 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]]
+}

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

Reply via email to