https://github.com/badumbatish updated 
https://github.com/llvm/llvm-project/pull/166037

>From 6b6f0f523d9c52f912937e206c374ee4001ad583 Mon Sep 17 00:00:00 2001
From: Jasmine Tang <[email protected]>
Date: Sat, 1 Nov 2025 20:32:55 -0700
Subject: [PATCH 1/7] Initial implementation for isfpclass and related builtins

Add lowering test
---
 .../CIR/Dialect/Builder/CIRBaseBuilder.h      |  16 +++
 clang/include/clang/CIR/Dialect/IR/CIROps.td  |  33 +++++
 clang/include/clang/CIR/Dialect/IR/FPEnv.h    |  50 +++++++
 clang/include/clang/CIR/MissingFeatures.h     |   3 +
 clang/lib/CIR/CodeGen/CIRGenBuilder.h         |  59 ++++++++
 clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp       | 115 +++++++++++++++-
 clang/lib/CIR/CodeGen/CIRGenFunction.cpp      |  69 ++++++++++
 clang/lib/CIR/CodeGen/CIRGenFunction.h        |  16 +++
 clang/lib/CIR/Dialect/IR/CMakeLists.txt       |   1 +
 clang/lib/CIR/Dialect/IR/FPEnv.cpp            |  64 +++++++++
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp |  11 ++
 clang/test/CIR/CodeGen/builtin-isfpclass.c    | 129 ++++++++++++++++++
 clang/test/CIR/Lowering/builtin_isfpclass.c   | 125 +++++++++++++++++
 13 files changed, 690 insertions(+), 1 deletion(-)
 create mode 100644 clang/include/clang/CIR/Dialect/IR/FPEnv.h
 create mode 100644 clang/lib/CIR/Dialect/IR/FPEnv.cpp
 create mode 100644 clang/test/CIR/CodeGen/builtin-isfpclass.c
 create mode 100644 clang/test/CIR/Lowering/builtin_isfpclass.c

diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h 
b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
index be9965ae3101f..bf14a96aeec07 100644
--- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
+++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
@@ -431,6 +431,22 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
     return createCast(cir::CastKind::ptr_to_bool, v, getBoolTy());
   }
 
+  // TODO(cir): the following function was introduced to keep in sync with LLVM
+  // codegen. CIR does not have "zext" operations. It should eventually be
+  // renamed or removed. For now, we just add whatever cast is required here.
+  mlir::Value createZExtOrBitCast(mlir::Location loc, mlir::Value src,
+                                  mlir::Type newTy) {
+    auto srcTy = src.getType();
+
+    if (srcTy == newTy)
+      return src;
+
+    if (mlir::isa<cir::BoolType>(srcTy) && mlir::isa<cir::IntType>(newTy))
+      return createBoolToInt(src, newTy);
+
+    llvm_unreachable("unhandled extension cast");
+  }
+
   mlir::Value createBoolToInt(mlir::Value src, mlir::Type newTy) {
     return createCast(cir::CastKind::bool_to_int, src, newTy);
   }
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index e612d6a0ba886..a1231cc3305d8 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -4018,6 +4018,39 @@ def CIR_RotateOp : CIR_Op<"rotate", [Pure, 
SameOperandsAndResultType]> {
   let hasFolder = 1;
 }
 
+def CIR_IsFPClassOp : CIR_Op<"is_fp_class"> {
+  let summary = "Corresponding to the `__builtin_fpclassify` builtin function 
in clang";
+
+  let description = [{
+    The `cir.is_fp_class` operation takes a floating-point value as its first
+    argument and a bitfield of flags as its second argument. The operation
+    returns a boolean value indicating whether the floating-point value
+    satisfies the given flags.
+
+    The flags must be a compile time constant and the values are:
+
+    | Bit # | floating-point class |
+    | -------- | ------- |
+    | 0 | Signaling NaN      |
+    | 1 | Quiet NaN          |
+    | 2 | Negative infinity  |
+    | 3 | Negative normal    |
+    | 4 | Negative subnormal |
+    | 5 | Negative zero      |
+    | 6 | Positive zero      |
+    | 7 | Positive subnormal |
+    | 8 | Positive normal    |
+    | 9 | Positive infinity  |
+  }];
+
+  let arguments = (ins CIR_AnyFloatType:$src,
+                       I32Attr:$flags);
+  let results = (outs CIR_BoolType:$result);
+  let assemblyFormat = [{
+    $src `,` $flags `:` functional-type($src, $result) attr-dict
+  }];
+}
+
 
//===----------------------------------------------------------------------===//
 // Assume Operations
 
//===----------------------------------------------------------------------===//
diff --git a/clang/include/clang/CIR/Dialect/IR/FPEnv.h 
b/clang/include/clang/CIR/Dialect/IR/FPEnv.h
new file mode 100644
index 0000000000000..aceba9ee57d05
--- /dev/null
+++ b/clang/include/clang/CIR/Dialect/IR/FPEnv.h
@@ -0,0 +1,50 @@
+//===- FPEnv.h ---- FP Environment ------------------------------*- C++ 
-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+/// @file
+/// This file contains the declarations of entities that describe floating
+/// point environment and related functions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_CIR_DIALECT_IR_FPENV_H
+#define CLANG_CIR_DIALECT_IR_FPENV_H
+
+#include "llvm/ADT/FloatingPointMode.h"
+
+#include <optional>
+
+namespace cir {
+
+namespace fp {
+
+/// Exception behavior used for floating point operations.
+///
+/// Each of these values corresponds to some LLVMIR metadata argument value of 
a
+/// constrained floating point intrinsic. See the LLVM Language Reference 
Manual
+/// for details.
+enum ExceptionBehavior : uint8_t {
+  ebIgnore,  ///< This corresponds to "fpexcept.ignore".
+  ebMayTrap, ///< This corresponds to "fpexcept.maytrap".
+  ebStrict,  ///< This corresponds to "fpexcept.strict".
+};
+
+} // namespace fp
+
+/// For any RoundingMode enumerator, returns a string valid as input in
+/// constrained intrinsic rounding mode metadata.
+std::optional<llvm::StringRef> convertRoundingModeToStr(llvm::RoundingMode);
+
+/// For any ExceptionBehavior enumerator, returns a string valid as input in
+/// constrained intrinsic exception behavior metadata.
+std::optional<llvm::StringRef>
+    convertExceptionBehaviorToStr(fp::ExceptionBehavior);
+
+} // namespace cir
+
+#endif
diff --git a/clang/include/clang/CIR/MissingFeatures.h 
b/clang/include/clang/CIR/MissingFeatures.h
index 6b5c34d28ce2a..4cad360e1ba31 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -265,7 +265,10 @@ struct MissingFeatures {
   static bool emitNullabilityCheck() { return false; }
   static bool emitTypeCheck() { return false; }
   static bool emitTypeMetadataCodeForVCall() { return false; }
+  static bool fastMathGuard() { return false; }
   static bool fastMathFlags() { return false; }
+  static bool fastMathFuncAttributes() { return false; }
+
   static bool fpConstraints() { return false; }
   static bool generateDebugInfo() { return false; }
   static bool globalViewIndices() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h 
b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
index 5ab1d0e05cf8a..b40b252b2af12 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -16,6 +16,7 @@
 #include "mlir/IR/BuiltinAttributes.h"
 #include "mlir/Support/LLVM.h"
 #include "clang/CIR/Dialect/IR/CIRDataLayout.h"
+#include "clang/CIR/Dialect/IR/FPEnv.h"
 #include "clang/CIR/MissingFeatures.h"
 
 #include "clang/CIR/Dialect/Builder/CIRBaseBuilder.h"
@@ -29,6 +30,9 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
   const CIRGenTypeCache &typeCache;
   llvm::StringMap<unsigned> recordNames;
   llvm::StringMap<unsigned> globalsVersioning;
+  bool isFpConstrained = false;
+  cir::fp::ExceptionBehavior defaultConstrainedExcept = cir::fp::ebStrict;
+  llvm::RoundingMode defaultConstrainedRounding = llvm::RoundingMode::Dynamic;
 
 public:
   CIRGenBuilderTy(mlir::MLIRContext &mlirContext, const CIRGenTypeCache &tc)
@@ -66,6 +70,56 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
                                     cir::ArrayType arrayTy) const {
     return cir::ConstArrayAttr::get(arrayTy, attrs);
   }
+  //
+  // Floating point specific helpers
+  // -------------------------------
+  //
+
+  /// Enable/Disable use of constrained floating point math. When enabled the
+  /// CreateF<op>() calls instead create constrained floating point intrinsic
+  /// calls. Fast math flags are unaffected by this setting.
+  void setIsFPConstrained(bool isCon) {
+    if (isCon)
+      llvm_unreachable("Constrained FP NYI");
+    isFpConstrained = isCon;
+  }
+
+  /// Query for the use of constrained floating point math
+  bool getIsFPConstrained() {
+    if (isFpConstrained)
+      llvm_unreachable("Constrained FP NYI");
+    return isFpConstrained;
+  }
+  ///
+  /// Set the exception handling to be used with constrained floating point
+  void setDefaultConstrainedExcept(cir::fp::ExceptionBehavior newExcept) {
+#ifndef NDEBUG
+    std::optional<llvm::StringRef> exceptStr =
+        cir::convertExceptionBehaviorToStr(newExcept);
+    assert(exceptStr && "Garbage strict exception behavior!");
+#endif
+    defaultConstrainedExcept = newExcept;
+  }
+
+  /// Set the rounding mode handling to be used with constrained floating point
+  void setDefaultConstrainedRounding(llvm::RoundingMode newRounding) {
+#ifndef NDEBUG
+    std::optional<llvm::StringRef> roundingStr =
+        cir::convertRoundingModeToStr(newRounding);
+    assert(roundingStr && "Garbage strict rounding mode!");
+#endif
+    defaultConstrainedRounding = newRounding;
+  }
+
+  /// Get the exception handling used with constrained floating point
+  cir::fp::ExceptionBehavior getDefaultConstrainedExcept() {
+    return defaultConstrainedExcept;
+  }
+
+  /// Get the rounding mode handling used with constrained floating point
+  llvm::RoundingMode getDefaultConstrainedRounding() {
+    return defaultConstrainedRounding;
+  }
 
   mlir::Attribute getConstRecordOrZeroAttr(mlir::ArrayAttr arrayAttr,
                                            bool packed = false,
@@ -334,6 +388,11 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
     llvm_unreachable("negation for the given type is NYI");
   }
 
+  cir::IsFPClassOp createIsFPClass(mlir::Location loc, mlir::Value src,
+                                   unsigned flags) {
+    return cir::IsFPClassOp::create(*this, loc, src, flags);
+  }
+
   // TODO: split this to createFPExt/createFPTrunc when we have dedicated cast
   // operations.
   mlir::Value createFloatingCast(mlir::Value v, mlir::Type destType) {
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp 
b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index 77f19343653db..0547c883c49cf 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -29,6 +29,16 @@ using namespace clang;
 using namespace clang::CIRGen;
 using namespace llvm;
 
+static mlir::Value tryUseTestFPKind(CIRGenFunction &cgf, unsigned BuiltinID,
+                                    mlir::Value V) {
+  if (cgf.getBuilder().getIsFPConstrained() &&
+      cgf.getBuilder().getDefaultConstrainedExcept() != cir::fp::ebIgnore) {
+    if (mlir::Value Result = cgf.getTargetHooks().testFPKind(
+            V, BuiltinID, cgf.getBuilder(), cgf.cgm))
+      return Result;
+  }
+  return nullptr;
+}
 static RValue emitLibraryCall(CIRGenFunction &cgf, const FunctionDecl *fd,
                               const CallExpr *e, mlir::Operation *calleeValue) 
{
   CIRGenCallee callee = CIRGenCallee::forDirect(calleeValue, GlobalDecl(fd));
@@ -520,14 +530,117 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl 
&gd, unsigned builtinID,
     cir::PrefetchOp::create(builder, loc, address, locality, isWrite);
     return RValue::get(nullptr);
   }
+  // From https://clang.llvm.org/docs/LanguageExtensions.html#builtin-isfpclass
+  // :
+  //
+  //  The `__builtin_isfpclass()` builtin is a generalization of functions
+  //  isnan, isinf, isfinite and some others defined by the C standard. It 
tests
+  //  if the floating-point value, specified by the first argument, falls into
+  //  any of data classes, specified by the second argument.
+  case Builtin::BI__builtin_isnan: {
+    CIRGenFunction::CIRGenFPOptionsRAII fpOptsRaii(*this, e);
+    mlir::Value v = emitScalarExpr(e->getArg(0));
+    if (mlir::Value result = tryUseTestFPKind(*this, builtinID, v))
+      return RValue::get(result);
+    mlir::Location loc = getLoc(e->getBeginLoc());
+    // FIXME: We should use builder.createZExt once createZExt is available.
+    return RValue::get(builder.createZExtOrBitCast(
+        loc, builder.createIsFPClass(loc, v, FPClassTest::fcNan),
+        convertType(e->getType())));
+  }
+
+  case Builtin::BI__builtin_issignaling: {
+    CIRGenFunction::CIRGenFPOptionsRAII fpOptsRaii(*this, e);
+    mlir::Value v = emitScalarExpr(e->getArg(0));
+    mlir::Location loc = getLoc(e->getBeginLoc());
+    // FIXME: We should use builder.createZExt once createZExt is available.
+    return RValue::get(builder.createZExtOrBitCast(
+        loc, builder.createIsFPClass(loc, v, FPClassTest::fcSNan),
+        convertType(e->getType())));
+  }
+
+  case Builtin::BI__builtin_isinf: {
+    CIRGenFunction::CIRGenFPOptionsRAII fpOptsRaii(*this, e);
+    mlir::Value v = emitScalarExpr(e->getArg(0));
+    if (mlir::Value result = tryUseTestFPKind(*this, builtinID, v))
+      return RValue::get(result);
+    mlir::Location loc = getLoc(e->getBeginLoc());
+    // FIXME: We should use builder.createZExt once createZExt is available.
+    return RValue::get(builder.createZExtOrBitCast(
+        loc, builder.createIsFPClass(loc, v, FPClassTest::fcInf),
+        convertType(e->getType())));
+  }
+
+  case Builtin::BIfinite:
+  case Builtin::BI__finite:
+  case Builtin::BIfinitef:
+  case Builtin::BI__finitef:
+  case Builtin::BIfinitel:
+  case Builtin::BI__finitel:
+  case Builtin::BI__builtin_isfinite: {
+    CIRGenFunction::CIRGenFPOptionsRAII fpOptsRaii(*this, e);
+    mlir::Value v = emitScalarExpr(e->getArg(0));
+    if (mlir::Value result = tryUseTestFPKind(*this, builtinID, v))
+      return RValue::get(result);
+    mlir::Location loc = getLoc(e->getBeginLoc());
+    // FIXME: We should use builder.createZExt once createZExt is available.
+    return RValue::get(builder.createZExtOrBitCast(
+        loc, builder.createIsFPClass(loc, v, FPClassTest::fcFinite),
+        convertType(e->getType())));
+  }
+
+  case Builtin::BI__builtin_isnormal: {
+    CIRGenFunction::CIRGenFPOptionsRAII fpOptsRaii(*this, e);
+    mlir::Value v = emitScalarExpr(e->getArg(0));
+    mlir::Location loc = getLoc(e->getBeginLoc());
+    // FIXME: We should use builder.createZExt once createZExt is available.
+    return RValue::get(builder.createZExtOrBitCast(
+        loc, builder.createIsFPClass(loc, v, FPClassTest::fcNormal),
+        convertType(e->getType())));
+  }
+
+  case Builtin::BI__builtin_issubnormal: {
+    CIRGenFunction::CIRGenFPOptionsRAII fpOptsRaii(*this, e);
+    mlir::Value v = emitScalarExpr(e->getArg(0));
+    mlir::Location loc = getLoc(e->getBeginLoc());
+    // FIXME: We should use builder.createZExt once createZExt is available.
+    return RValue::get(builder.createZExtOrBitCast(
+        loc, builder.createIsFPClass(loc, v, FPClassTest::fcSubnormal),
+        convertType(e->getType())));
+  }
+
+  case Builtin::BI__builtin_iszero: {
+    CIRGenFunction::CIRGenFPOptionsRAII fpOptsRaii(*this, e);
+    mlir::Value v = emitScalarExpr(e->getArg(0));
+    mlir::Location loc = getLoc(e->getBeginLoc());
+    // FIXME: We should use builder.createZExt once createZExt is available.
+    return RValue::get(builder.createZExtOrBitCast(
+        loc, builder.createIsFPClass(loc, v, FPClassTest::fcZero),
+        convertType(e->getType())));
+  }
+  case Builtin::BI__builtin_isfpclass: {
+    Expr::EvalResult result;
+    if (!e->getArg(1)->EvaluateAsInt(result, cgm.getASTContext()))
+      break;
+
+    CIRGenFunction::CIRGenFPOptionsRAII fpOptsRaii(*this, e);
+    mlir::Value v = emitScalarExpr(e->getArg(0));
+    uint64_t test = result.Val.getInt().getLimitedValue();
+    mlir::Location loc = getLoc(e->getBeginLoc());
+    //
+    // // FIXME: We should use builder.createZExt once createZExt is available.
+    return RValue::get(builder.createZExtOrBitCast(
+        loc, builder.createIsFPClass(loc, v, test), 
convertType(e->getType())));
+  }
   }
 
   // If this is an alias for a lib function (e.g. __builtin_sin), emit
   // the call using the normal call path, but using the unmangled
   // version of the function name.
-  if (getContext().BuiltinInfo.isLibFunction(builtinID))
+  if (getContext().BuiltinInfo.isLibFunction(builtinID)) {
     return emitLibraryCall(*this, fd, e,
                            cgm.getBuiltinLibFunction(fd, builtinID));
+  }
 
   // Some target-specific builtins can have aggregate return values, e.g.
   // __builtin_arm_mve_vld2q_u32. So if the result is an aggregate, force
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp 
b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index 2739469d7202e..ac48c25435530 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -834,6 +834,22 @@ void CIRGenFunction::emitDestructorBody(FunctionArgList 
&args) {
     cgm.errorNYI(dtor->getSourceRange(), "function-try-block destructor");
 }
 
+// Map the LangOption for exception behavior into the corresponding enum in
+// the IR.
+static cir::fp::ExceptionBehavior
+toConstrainedExceptMd(LangOptions::FPExceptionModeKind kind) {
+  switch (kind) {
+  case LangOptions::FPE_Ignore:
+    return cir::fp::ebIgnore;
+  case LangOptions::FPE_MayTrap:
+    return cir::fp::ebMayTrap;
+  case LangOptions::FPE_Strict:
+    return cir::fp::ebStrict;
+  default:
+    llvm_unreachable("Unsupported FP Exception Behavior");
+  }
+}
+
 /// Given a value of type T* that may not be to a complete object, construct
 /// an l-vlaue withi the natural pointee alignment of T.
 LValue CIRGenFunction::makeNaturalAlignPointeeAddrLValue(mlir::Value val,
@@ -1018,6 +1034,59 @@ void 
CIRGenFunction::emitNullInitialization(mlir::Location loc, Address destPtr,
   builder.createStore(loc, zeroValue, destPtr);
 }
 
+CIRGenFunction::CIRGenFPOptionsRAII::CIRGenFPOptionsRAII(CIRGenFunction &cgf,
+                                                         const clang::Expr *e)
+    : cgf(cgf) {
+  constructorHelper(e->getFPFeaturesInEffect(cgf.getLangOpts()));
+}
+
+CIRGenFunction::CIRGenFPOptionsRAII::CIRGenFPOptionsRAII(CIRGenFunction &cgf,
+                                                         FPOptions fpFeatures)
+    : cgf(cgf) {
+  constructorHelper(fpFeatures);
+}
+
+void CIRGenFunction::CIRGenFPOptionsRAII::constructorHelper(
+    FPOptions fpFeatures) {
+  oldFpFeatures = cgf.curFpFeatures;
+  cgf.curFpFeatures = fpFeatures;
+
+  oldExcept = cgf.builder.getDefaultConstrainedExcept();
+  oldRounding = cgf.builder.getDefaultConstrainedRounding();
+
+  if (oldFpFeatures == fpFeatures)
+    return;
+
+  // TODO(cir): create guard to restore fast math configurations.
+  assert(!cir::MissingFeatures::fastMathGuard());
+
+  llvm::RoundingMode newRoundingBehavior = fpFeatures.getRoundingMode();
+  // TODO(cir): override rounding behaviour once FM configs are guarded.
+  auto newExceptionBehavior =
+      toConstrainedExceptMd(static_cast<LangOptions::FPExceptionModeKind>(
+          fpFeatures.getExceptionMode()));
+  // TODO(cir): override exception behaviour once FM configs are guarded.
+
+  // TODO(cir): override FP flags once FM configs are guarded.
+  assert(!cir::MissingFeatures::fastMathFlags());
+
+  assert((cgf.curFuncDecl == nullptr || cgf.builder.getIsFPConstrained() ||
+          isa<CXXConstructorDecl>(cgf.curFuncDecl) ||
+          isa<CXXDestructorDecl>(cgf.curFuncDecl) ||
+          (newExceptionBehavior == cir::fp::ebIgnore &&
+           newRoundingBehavior == llvm::RoundingMode::NearestTiesToEven)) &&
+         "FPConstrained should be enabled on entire function");
+
+  // TODO(cir): mark CIR function with fast math attributes.
+  assert(!cir::MissingFeatures::fastMathFuncAttributes());
+}
+
+CIRGenFunction::CIRGenFPOptionsRAII::~CIRGenFPOptionsRAII() {
+  cgf.curFpFeatures = oldFpFeatures;
+  cgf.builder.setDefaultConstrainedExcept(oldExcept);
+  cgf.builder.setDefaultConstrainedRounding(oldRounding);
+}
+
 // TODO(cir): should be shared with LLVM codegen.
 bool CIRGenFunction::shouldNullCheckClassCastValue(const CastExpr *ce) {
   const Expr *e = ce->getSubExpr();
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h 
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index b22bf2d87fc10..5080b3ddad7cf 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -31,6 +31,7 @@
 #include "clang/AST/Stmt.h"
 #include "clang/AST/Type.h"
 #include "clang/CIR/Dialect/IR/CIRDialect.h"
+#include "clang/CIR/Dialect/IR/FPEnv.h"
 #include "clang/CIR/MissingFeatures.h"
 #include "clang/CIR/TypeEvaluationKind.h"
 #include "llvm/ADT/ScopedHashTable.h"
@@ -179,6 +180,21 @@ class CIRGenFunction : public CIRGenTypeCache {
   /// Sanitizers enabled for this function.
   clang::SanitizerSet sanOpts;
 
+  class CIRGenFPOptionsRAII {
+  public:
+    CIRGenFPOptionsRAII(CIRGenFunction &cgf, FPOptions fpFeatures);
+    CIRGenFPOptionsRAII(CIRGenFunction &cgf, const clang::Expr *e);
+    ~CIRGenFPOptionsRAII();
+
+  private:
+    void constructorHelper(clang::FPOptions fpFeatures);
+    CIRGenFunction &cgf;
+    clang::FPOptions oldFpFeatures;
+    cir::fp::ExceptionBehavior oldExcept;
+    llvm::RoundingMode oldRounding;
+  };
+  clang::FPOptions curFpFeatures;
+
   /// The symbol table maps a variable name to a value in the current scope.
   /// Entering a function creates a new scope, and the function arguments are
   /// added to the mapping. When the processing of a function is terminated,
diff --git a/clang/lib/CIR/Dialect/IR/CMakeLists.txt 
b/clang/lib/CIR/Dialect/IR/CMakeLists.txt
index 98575941035f2..de3c7d7a1c3b9 100644
--- a/clang/lib/CIR/Dialect/IR/CMakeLists.txt
+++ b/clang/lib/CIR/Dialect/IR/CMakeLists.txt
@@ -4,6 +4,7 @@ add_clang_library(MLIRCIR
   CIRMemorySlot.cpp
   CIRTypes.cpp
   CIRDataLayout.cpp
+  FPEnv.cpp
 
   DEPENDS
   MLIRCIROpsIncGen
diff --git a/clang/lib/CIR/Dialect/IR/FPEnv.cpp 
b/clang/lib/CIR/Dialect/IR/FPEnv.cpp
new file mode 100644
index 0000000000000..719ceb32480c9
--- /dev/null
+++ b/clang/lib/CIR/Dialect/IR/FPEnv.cpp
@@ -0,0 +1,64 @@
+//===-- FPEnv.cpp ---- FP Environment 
-------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+/// @file
+/// This file contains the implementations of entities that describe floating
+/// point environment.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/CIR/Dialect/IR/FPEnv.h"
+
+namespace cir {
+
+std::optional<llvm::StringRef>
+convertRoundingModeToStr(llvm::RoundingMode useRounding) {
+  std::optional<llvm::StringRef> roundingStr;
+  switch (useRounding) {
+  case llvm::RoundingMode::Dynamic:
+    roundingStr = "round.dynamic";
+    break;
+  case llvm::RoundingMode::NearestTiesToEven:
+    roundingStr = "round.tonearest";
+    break;
+  case llvm::RoundingMode::NearestTiesToAway:
+    roundingStr = "round.tonearestaway";
+    break;
+  case llvm::RoundingMode::TowardNegative:
+    roundingStr = "round.downward";
+    break;
+  case llvm::RoundingMode::TowardPositive:
+    roundingStr = "round.upward";
+    break;
+  case llvm::RoundingMode::TowardZero:
+    roundingStr = "round.towardZero";
+    break;
+  default:
+    break;
+  }
+  return roundingStr;
+}
+
+std::optional<llvm::StringRef>
+convertExceptionBehaviorToStr(fp::ExceptionBehavior useExcept) {
+  std::optional<llvm::StringRef> exceptStr;
+  switch (useExcept) {
+  case fp::ebStrict:
+    exceptStr = "fpexcept.strict";
+    break;
+  case fp::ebIgnore:
+    exceptStr = "fpexcept.ignore";
+    break;
+  case fp::ebMayTrap:
+    exceptStr = "fpexcept.maytrap";
+    break;
+  }
+  return exceptStr;
+}
+
+} // namespace cir
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 4912bd197dba4..04cf62ed3bd08 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -670,6 +670,17 @@ mlir::LogicalResult 
CIRToLLVMASinOpLowering::matchAndRewrite(
   return mlir::success();
 }
 
+mlir::LogicalResult CIRToLLVMIsFPClassOpLowering::matchAndRewrite(
+    cir::IsFPClassOp op, OpAdaptor adaptor,
+    mlir::ConversionPatternRewriter &rewriter) const {
+  auto src = adaptor.getSrc();
+  auto flags = adaptor.getFlags();
+  auto retTy = rewriter.getI1Type();
+
+  rewriter.replaceOpWithNewOp<mlir::LLVM::IsFPClass>(op, retTy, src, flags);
+  return mlir::success();
+}
+
 mlir::LogicalResult CIRToLLVMAssumeOpLowering::matchAndRewrite(
     cir::AssumeOp op, OpAdaptor adaptor,
     mlir::ConversionPatternRewriter &rewriter) const {
diff --git a/clang/test/CIR/CodeGen/builtin-isfpclass.c 
b/clang/test/CIR/CodeGen/builtin-isfpclass.c
new file mode 100644
index 0000000000000..b02069fcbb7f5
--- /dev/null
+++ b/clang/test/CIR/CodeGen/builtin-isfpclass.c
@@ -0,0 +1,129 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o 
%t.cir
+// RUN: FileCheck --input-file=%t.cir %s
+
+int finite(double);
+
+// CHECK: cir.func {{.*}}@test_is_finite
+void test_is_finite(__fp16 *H, float F, double D, long double LD) {
+    volatile int res;
+    res = __builtin_isinf(*H);
+    // CHECK: cir.is_fp_class %{{.*}}, 516 : (!cir.f16) -> !cir.bool
+
+    res = __builtin_isinf(F);
+    // CHECK: cir.is_fp_class %{{.*}}, 516 : (!cir.float) -> !cir.bool
+
+    res = __builtin_isinf(D);
+    // CHECK: cir.is_fp_class %{{.*}}, 516 : (!cir.double) -> !cir.bool
+
+    res = __builtin_isinf(LD);
+    // CHECK: cir.is_fp_class %{{.*}}, 516 : (!cir.long_double<!cir.f80>) -> 
!cir.bool
+
+    res = __builtin_isfinite(*H);
+    // CHECK: cir.is_fp_class %{{.*}}, 504 : (!cir.f16) -> !cir.bool
+    res = __builtin_isfinite(F);
+    // CHECK: cir.is_fp_class %{{.*}}, 504 : (!cir.float) -> !cir.bool
+    res = finite(D);
+    // CHECK: cir.call @finite(%{{.*}}) nothrow side_effect(const) : 
(!cir.double) -> !s32i
+
+    res = __builtin_isnormal(*H);
+    // CHECK: cir.is_fp_class %{{.*}}, 264 : (!cir.f16) -> !cir.bool
+    res = __builtin_isnormal(F);
+    // CHECK: cir.is_fp_class %{{.*}}, 264 : (!cir.float) -> !cir.bool
+
+    res = __builtin_issubnormal(F);
+    // CHECK: cir.is_fp_class %{{.*}}, 144 : (!cir.float) -> !cir.bool
+    res = __builtin_iszero(F);
+    // CHECK: cir.is_fp_class %{{.*}}, 96 : (!cir.float) -> !cir.bool
+    res = __builtin_issignaling(F);
+    // CHECK: cir.is_fp_class %{{.*}}, 1 : (!cir.float) -> !cir.bool
+}
+
+_Bool check_isfpclass_finite(float x) {
+  return __builtin_isfpclass(x, 504 /*Finite*/);
+}
+
+// CHECK: cir.func {{.*}}@check_isfpclass_finite
+// CHECK: cir.is_fp_class %{{.*}}, 504 : (!cir.float)
+
+_Bool check_isfpclass_nan_f32(float x) {
+  return __builtin_isfpclass(x, 3 /*NaN*/);
+}
+
+// CHECK: cir.func {{.*}}@check_isfpclass_nan_f32
+// CHECK: cir.is_fp_class %{{.*}}, 3 : (!cir.float)
+
+
+_Bool check_isfpclass_snan_f64(double x) {
+  return __builtin_isfpclass(x, 1 /*SNaN*/);
+}
+
+// CHECK: cir.func {{.*}}@check_isfpclass_snan_f64
+// CHECK: cir.is_fp_class %{{.*}}, 1 : (!cir.double)
+
+
+_Bool check_isfpclass_zero_f16(_Float16 x) {
+  return __builtin_isfpclass(x, 96 /*Zero*/);
+}
+
+// CHECK: cir.func {{.*}}@check_isfpclass_zero_f16
+// CHECK: cir.is_fp_class %{{.*}}, 96 : (!cir.f16)
+
+// Update when we support FP pragma in functions and can convert BoolType in 
prvalue to i1.
+
+// _Bool check_isfpclass_finite_strict(float x) {
+// #pragma STDC FENV_ACCESS ON
+//   return __builtin_isfpclass(x, 504 /*Finite*/);
+// }
+// 
+// _Bool check_isfpclass_nan_f32_strict(float x) {
+// #pragma STDC FENV_ACCESS ON
+//   return __builtin_isfpclass(x, 3 /*NaN*/);
+// }
+// 
+// _Bool check_isfpclass_snan_f64_strict(double x) {
+// #pragma STDC FENV_ACCESS ON
+//   return __builtin_isfpclass(x, 1 /*NaN*/);
+// }
+// 
+// _Bool check_isfpclass_zero_f16_strict(_Float16 x) {
+// #pragma STDC FENV_ACCESS ON
+//   return __builtin_isfpclass(x, 96 /*Zero*/);
+// }
+// 
+// _Bool check_isnan(float x) {
+// #pragma STDC FENV_ACCESS ON
+//   return __builtin_isnan(x);
+// }
+// 
+// _Bool check_isinf(float x) {
+// #pragma STDC FENV_ACCESS ON
+//   return __builtin_isinf(x);
+// }
+// 
+// _Bool check_isfinite(float x) {
+// #pragma STDC FENV_ACCESS ON
+//   return __builtin_isfinite(x);
+// }
+// 
+// _Bool check_isnormal(float x) {
+// #pragma STDC FENV_ACCESS ON
+//   return __builtin_isnormal(x);
+// }
+// 
+// typedef float __attribute__((ext_vector_type(4))) float4;
+// typedef double __attribute__((ext_vector_type(4))) double4;
+// typedef int __attribute__((ext_vector_type(4))) int4;
+// typedef long __attribute__((ext_vector_type(4))) long4;
+// 
+// int4 check_isfpclass_nan_v4f32(float4 x) {
+//   return __builtin_isfpclass(x, 3 /*NaN*/);
+// }
+// 
+// int4 check_isfpclass_nan_strict_v4f32(float4 x) {
+// #pragma STDC FENV_ACCESS ON
+//   return __builtin_isfpclass(x, 3 /*NaN*/);
+// }
+// 
+// long4 check_isfpclass_nan_v4f64(double4 x) {
+//   return __builtin_isfpclass(x, 3 /*NaN*/);
+// }
diff --git a/clang/test/CIR/Lowering/builtin_isfpclass.c 
b/clang/test/CIR/Lowering/builtin_isfpclass.c
new file mode 100644
index 0000000000000..f3b480b492a3f
--- /dev/null
+++ b/clang/test/CIR/Lowering/builtin_isfpclass.c
@@ -0,0 +1,125 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o 
%t.ll
+// RUN: FileCheck --input-file=%t.ll %s
+
+int finite(double);
+
+// CHECK: define {{.*}}@test_is_finite
+void test_is_finite(__fp16 *H, float F, double D, long double LD) {
+    volatile int res;
+    res = __builtin_isinf(*H);
+    // CHECK: call i1 @llvm.is.fpclass.f16(half %{{.*}}, i32 516)
+    res = __builtin_isinf(F);
+    // CHECK: call i1 @llvm.is.fpclass.f32(float %{{.*}}, i32 516)
+    res = __builtin_isinf(D);
+    // CHECK: call i1 @llvm.is.fpclass.f64(double %{{.*}}, i32 516)
+    res = __builtin_isinf(LD);
+    // CHECK: call i1 @llvm.is.fpclass.f80(x86_fp80 %{{.*}}, i32 516)
+
+    res = __builtin_isfinite(*H);
+    // CHECK: call i1 @llvm.is.fpclass.f16(half %{{.*}}, i32 504)
+    res = __builtin_isfinite(F);
+    // CHECK: call i1 @llvm.is.fpclass.f32(float %{{.*}}, i32 504)
+    res = finite(D);
+    // CHECK: call i32 @finite(double %{{.*}})
+
+    res = __builtin_isnormal(*H);
+    // CHECK: call i1 @llvm.is.fpclass.f16(half %{{.*}}, i32 264)
+    res = __builtin_isnormal(F);
+    // CHECK: call i1 @llvm.is.fpclass.f32(float %{{.*}}, i32 264)
+
+    res = __builtin_issubnormal(F);
+    // CHECK: call i1 @llvm.is.fpclass.f32(float %{{.*}}, i32 144)
+    res = __builtin_iszero(F);
+    // CHECK: call i1 @llvm.is.fpclass.f32(float %{{.*}}, i32 96)
+    res = __builtin_issignaling(F);
+    // CHECK: call i1 @llvm.is.fpclass.f32(float %{{.*}}, i32 1)
+}
+
+_Bool check_isfpclass_finite(float x) {
+  return __builtin_isfpclass(x, 504 /*Finite*/);
+}
+
+// CHECK: define {{.*}}@check_isfpclass_finite
+// CHECK: call i1 @llvm.is.fpclass.f32(float %{{.*}}, i32 504)
+
+_Bool check_isfpclass_nan_f32(float x) {
+  return __builtin_isfpclass(x, 3 /*NaN*/);
+}
+
+// CHECK: define {{.*}}@check_isfpclass_nan_f32
+// CHECK: call i1 @llvm.is.fpclass.f32(float %{{.*}}, i32 3)
+
+_Bool check_isfpclass_snan_f64(double x) {
+  return __builtin_isfpclass(x, 1 /*SNaN*/);
+}
+
+// CHECK: define {{.*}}@check_isfpclass_snan_f64
+// CHECK: call i1 @llvm.is.fpclass.f64(double %{{.*}}, i32 1)
+
+
+_Bool check_isfpclass_zero_f16(_Float16 x) {
+  return __builtin_isfpclass(x, 96 /*Zero*/);
+}
+
+// CHECK: define {{.*}}@check_isfpclass_zero_f16
+// CHECK: call i1 @llvm.is.fpclass.f16(half %{{.*}}, i32 96)
+
+// Update when we support FP pragma in functions.
+
+// _Bool check_isfpclass_finite_strict(float x) {
+// #pragma STDC FENV_ACCESS ON
+//   return __builtin_isfpclass(x, 504 /*Finite*/);
+// }
+// 
+// _Bool check_isfpclass_nan_f32_strict(float x) {
+// #pragma STDC FENV_ACCESS ON
+//   return __builtin_isfpclass(x, 3 /*NaN*/);
+// }
+// 
+// _Bool check_isfpclass_snan_f64_strict(double x) {
+// #pragma STDC FENV_ACCESS ON
+//   return __builtin_isfpclass(x, 1 /*NaN*/);
+// }
+// 
+// _Bool check_isfpclass_zero_f16_strict(_Float16 x) {
+// #pragma STDC FENV_ACCESS ON
+//   return __builtin_isfpclass(x, 96 /*Zero*/);
+// }
+// 
+// _Bool check_isnan(float x) {
+// #pragma STDC FENV_ACCESS ON
+//   return __builtin_isnan(x);
+// }
+// 
+// _Bool check_isinf(float x) {
+// #pragma STDC FENV_ACCESS ON
+//   return __builtin_isinf(x);
+// }
+// 
+// _Bool check_isfinite(float x) {
+// #pragma STDC FENV_ACCESS ON
+//   return __builtin_isfinite(x);
+// }
+// 
+// _Bool check_isnormal(float x) {
+// #pragma STDC FENV_ACCESS ON
+//   return __builtin_isnormal(x);
+// }
+// 
+// typedef float __attribute__((ext_vector_type(4))) float4;
+// typedef double __attribute__((ext_vector_type(4))) double4;
+// typedef int __attribute__((ext_vector_type(4))) int4;
+// typedef long __attribute__((ext_vector_type(4))) long4;
+// 
+// int4 check_isfpclass_nan_v4f32(float4 x) {
+//   return __builtin_isfpclass(x, 3 /*NaN*/);
+// }
+// 
+// int4 check_isfpclass_nan_strict_v4f32(float4 x) {
+// #pragma STDC FENV_ACCESS ON
+//   return __builtin_isfpclass(x, 3 /*NaN*/);
+// }
+// 
+// long4 check_isfpclass_nan_v4f64(double4 x) {
+//   return __builtin_isfpclass(x, 3 /*NaN*/);
+// }

>From b036765e665f384f20d6ecf29bed1c8659fbb29f Mon Sep 17 00:00:00 2001
From: Jasmine Tang <[email protected]>
Date: Tue, 11 Nov 2025 15:06:26 -0800
Subject: [PATCH 2/7] Address PR review: remove FP skeleton features, lowering
 test and add OGCG and LLVM test

---
 .../CIR/Dialect/Builder/CIRBaseBuilder.h      |  16 ---
 clang/include/clang/CIR/Dialect/IR/CIROps.td  |  22 +--
 clang/include/clang/CIR/MissingFeatures.h     |   2 -
 clang/lib/CIR/CodeGen/CIRGenBuilder.h         |  50 -------
 clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp       |  78 ++++-------
 clang/lib/CIR/CodeGen/CIRGenFunction.cpp      |  69 ----------
 clang/lib/CIR/CodeGen/CIRGenFunction.h        |  14 --
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp |   6 +-
 clang/test/CIR/CodeGen/builtin-isfpclass.c    |  91 +++++++++----
 clang/test/CIR/Lowering/builtin_isfpclass.c   | 125 ------------------
 10 files changed, 110 insertions(+), 363 deletions(-)
 delete mode 100644 clang/test/CIR/Lowering/builtin_isfpclass.c

diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h 
b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
index bf14a96aeec07..be9965ae3101f 100644
--- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
+++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
@@ -431,22 +431,6 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
     return createCast(cir::CastKind::ptr_to_bool, v, getBoolTy());
   }
 
-  // TODO(cir): the following function was introduced to keep in sync with LLVM
-  // codegen. CIR does not have "zext" operations. It should eventually be
-  // renamed or removed. For now, we just add whatever cast is required here.
-  mlir::Value createZExtOrBitCast(mlir::Location loc, mlir::Value src,
-                                  mlir::Type newTy) {
-    auto srcTy = src.getType();
-
-    if (srcTy == newTy)
-      return src;
-
-    if (mlir::isa<cir::BoolType>(srcTy) && mlir::isa<cir::IntType>(newTy))
-      return createBoolToInt(src, newTy);
-
-    llvm_unreachable("unhandled extension cast");
-  }
-
   mlir::Value createBoolToInt(mlir::Value src, mlir::Type newTy) {
     return createCast(cir::CastKind::bool_to_int, src, newTy);
   }
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index a1231cc3305d8..67fe7e8e1f4a1 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -4030,17 +4030,17 @@ def CIR_IsFPClassOp : CIR_Op<"is_fp_class"> {
     The flags must be a compile time constant and the values are:
 
     | Bit # | floating-point class |
-    | -------- | ------- |
-    | 0 | Signaling NaN      |
-    | 1 | Quiet NaN          |
-    | 2 | Negative infinity  |
-    | 3 | Negative normal    |
-    | 4 | Negative subnormal |
-    | 5 | Negative zero      |
-    | 6 | Positive zero      |
-    | 7 | Positive subnormal |
-    | 8 | Positive normal    |
-    | 9 | Positive infinity  |
+    | ----- | -------------------- |
+    |  0    | Signaling NaN        |
+    |  1    | Quiet NaN            |
+    |  2    | Negative infinity    |
+    |  3    | Negative normal      |
+    |  4    | Negative subnormal   |
+    |  5    | Negative zero        |
+    |  6    | Positive zero        |
+    |  7    | Positive subnormal   |
+    |  8    | Positive normal      |
+    |  9    | Positive infinity    |
   }];
 
   let arguments = (ins CIR_AnyFloatType:$src,
diff --git a/clang/include/clang/CIR/MissingFeatures.h 
b/clang/include/clang/CIR/MissingFeatures.h
index 4cad360e1ba31..2ecde9aa5d56d 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -265,9 +265,7 @@ struct MissingFeatures {
   static bool emitNullabilityCheck() { return false; }
   static bool emitTypeCheck() { return false; }
   static bool emitTypeMetadataCodeForVCall() { return false; }
-  static bool fastMathGuard() { return false; }
   static bool fastMathFlags() { return false; }
-  static bool fastMathFuncAttributes() { return false; }
 
   static bool fpConstraints() { return false; }
   static bool generateDebugInfo() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h 
b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
index b40b252b2af12..d611c0dc3d675 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -70,56 +70,6 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
                                     cir::ArrayType arrayTy) const {
     return cir::ConstArrayAttr::get(arrayTy, attrs);
   }
-  //
-  // Floating point specific helpers
-  // -------------------------------
-  //
-
-  /// Enable/Disable use of constrained floating point math. When enabled the
-  /// CreateF<op>() calls instead create constrained floating point intrinsic
-  /// calls. Fast math flags are unaffected by this setting.
-  void setIsFPConstrained(bool isCon) {
-    if (isCon)
-      llvm_unreachable("Constrained FP NYI");
-    isFpConstrained = isCon;
-  }
-
-  /// Query for the use of constrained floating point math
-  bool getIsFPConstrained() {
-    if (isFpConstrained)
-      llvm_unreachable("Constrained FP NYI");
-    return isFpConstrained;
-  }
-  ///
-  /// Set the exception handling to be used with constrained floating point
-  void setDefaultConstrainedExcept(cir::fp::ExceptionBehavior newExcept) {
-#ifndef NDEBUG
-    std::optional<llvm::StringRef> exceptStr =
-        cir::convertExceptionBehaviorToStr(newExcept);
-    assert(exceptStr && "Garbage strict exception behavior!");
-#endif
-    defaultConstrainedExcept = newExcept;
-  }
-
-  /// Set the rounding mode handling to be used with constrained floating point
-  void setDefaultConstrainedRounding(llvm::RoundingMode newRounding) {
-#ifndef NDEBUG
-    std::optional<llvm::StringRef> roundingStr =
-        cir::convertRoundingModeToStr(newRounding);
-    assert(roundingStr && "Garbage strict rounding mode!");
-#endif
-    defaultConstrainedRounding = newRounding;
-  }
-
-  /// Get the exception handling used with constrained floating point
-  cir::fp::ExceptionBehavior getDefaultConstrainedExcept() {
-    return defaultConstrainedExcept;
-  }
-
-  /// Get the rounding mode handling used with constrained floating point
-  llvm::RoundingMode getDefaultConstrainedRounding() {
-    return defaultConstrainedRounding;
-  }
 
   mlir::Attribute getConstRecordOrZeroAttr(mlir::ArrayAttr arrayAttr,
                                            bool packed = false,
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp 
b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index 0547c883c49cf..14c3ccde80055 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -29,16 +29,6 @@ using namespace clang;
 using namespace clang::CIRGen;
 using namespace llvm;
 
-static mlir::Value tryUseTestFPKind(CIRGenFunction &cgf, unsigned BuiltinID,
-                                    mlir::Value V) {
-  if (cgf.getBuilder().getIsFPConstrained() &&
-      cgf.getBuilder().getDefaultConstrainedExcept() != cir::fp::ebIgnore) {
-    if (mlir::Value Result = cgf.getTargetHooks().testFPKind(
-            V, BuiltinID, cgf.getBuilder(), cgf.cgm))
-      return Result;
-  }
-  return nullptr;
-}
 static RValue emitLibraryCall(CIRGenFunction &cgf, const FunctionDecl *fd,
                               const CallExpr *e, mlir::Operation *calleeValue) 
{
   CIRGenCallee callee = CIRGenCallee::forDirect(calleeValue, GlobalDecl(fd));
@@ -538,36 +528,31 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl 
&gd, unsigned builtinID,
   //  if the floating-point value, specified by the first argument, falls into
   //  any of data classes, specified by the second argument.
   case Builtin::BI__builtin_isnan: {
-    CIRGenFunction::CIRGenFPOptionsRAII fpOptsRaii(*this, e);
+    assert(!cir::MissingFeatures::cgFPOptionsRAII());
     mlir::Value v = emitScalarExpr(e->getArg(0));
-    if (mlir::Value result = tryUseTestFPKind(*this, builtinID, v))
-      return RValue::get(result);
+    assert(!cir::MissingFeatures::fpConstraints());
     mlir::Location loc = getLoc(e->getBeginLoc());
-    // FIXME: We should use builder.createZExt once createZExt is available.
-    return RValue::get(builder.createZExtOrBitCast(
-        loc, builder.createIsFPClass(loc, v, FPClassTest::fcNan),
+    return RValue::get(builder.createBoolToInt(
+        builder.createIsFPClass(loc, v, FPClassTest::fcNan),
         convertType(e->getType())));
   }
 
   case Builtin::BI__builtin_issignaling: {
-    CIRGenFunction::CIRGenFPOptionsRAII fpOptsRaii(*this, e);
+    assert(!cir::MissingFeatures::cgFPOptionsRAII());
     mlir::Value v = emitScalarExpr(e->getArg(0));
     mlir::Location loc = getLoc(e->getBeginLoc());
-    // FIXME: We should use builder.createZExt once createZExt is available.
-    return RValue::get(builder.createZExtOrBitCast(
-        loc, builder.createIsFPClass(loc, v, FPClassTest::fcSNan),
+    return RValue::get(builder.createBoolToInt(
+        builder.createIsFPClass(loc, v, FPClassTest::fcSNan),
         convertType(e->getType())));
   }
 
   case Builtin::BI__builtin_isinf: {
-    CIRGenFunction::CIRGenFPOptionsRAII fpOptsRaii(*this, e);
+    assert(!cir::MissingFeatures::cgFPOptionsRAII());
     mlir::Value v = emitScalarExpr(e->getArg(0));
-    if (mlir::Value result = tryUseTestFPKind(*this, builtinID, v))
-      return RValue::get(result);
+    assert(!cir::MissingFeatures::fpConstraints());
     mlir::Location loc = getLoc(e->getBeginLoc());
-    // FIXME: We should use builder.createZExt once createZExt is available.
-    return RValue::get(builder.createZExtOrBitCast(
-        loc, builder.createIsFPClass(loc, v, FPClassTest::fcInf),
+    return RValue::get(builder.createBoolToInt(
+        builder.createIsFPClass(loc, v, FPClassTest::fcInf),
         convertType(e->getType())));
   }
 
@@ -578,44 +563,39 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl 
&gd, unsigned builtinID,
   case Builtin::BIfinitel:
   case Builtin::BI__finitel:
   case Builtin::BI__builtin_isfinite: {
-    CIRGenFunction::CIRGenFPOptionsRAII fpOptsRaii(*this, e);
+    assert(!cir::MissingFeatures::cgFPOptionsRAII());
     mlir::Value v = emitScalarExpr(e->getArg(0));
-    if (mlir::Value result = tryUseTestFPKind(*this, builtinID, v))
-      return RValue::get(result);
+    assert(!cir::MissingFeatures::fpConstraints());
     mlir::Location loc = getLoc(e->getBeginLoc());
-    // FIXME: We should use builder.createZExt once createZExt is available.
-    return RValue::get(builder.createZExtOrBitCast(
-        loc, builder.createIsFPClass(loc, v, FPClassTest::fcFinite),
+    return RValue::get(builder.createBoolToInt(
+        builder.createIsFPClass(loc, v, FPClassTest::fcFinite),
         convertType(e->getType())));
   }
 
   case Builtin::BI__builtin_isnormal: {
-    CIRGenFunction::CIRGenFPOptionsRAII fpOptsRaii(*this, e);
+    assert(!cir::MissingFeatures::cgFPOptionsRAII());
     mlir::Value v = emitScalarExpr(e->getArg(0));
     mlir::Location loc = getLoc(e->getBeginLoc());
-    // FIXME: We should use builder.createZExt once createZExt is available.
-    return RValue::get(builder.createZExtOrBitCast(
-        loc, builder.createIsFPClass(loc, v, FPClassTest::fcNormal),
+    return RValue::get(builder.createBoolToInt(
+        builder.createIsFPClass(loc, v, FPClassTest::fcNormal),
         convertType(e->getType())));
   }
 
   case Builtin::BI__builtin_issubnormal: {
-    CIRGenFunction::CIRGenFPOptionsRAII fpOptsRaii(*this, e);
+    assert(!cir::MissingFeatures::cgFPOptionsRAII());
     mlir::Value v = emitScalarExpr(e->getArg(0));
     mlir::Location loc = getLoc(e->getBeginLoc());
-    // FIXME: We should use builder.createZExt once createZExt is available.
-    return RValue::get(builder.createZExtOrBitCast(
-        loc, builder.createIsFPClass(loc, v, FPClassTest::fcSubnormal),
+    return RValue::get(builder.createBoolToInt(
+        builder.createIsFPClass(loc, v, FPClassTest::fcSubnormal),
         convertType(e->getType())));
   }
 
   case Builtin::BI__builtin_iszero: {
-    CIRGenFunction::CIRGenFPOptionsRAII fpOptsRaii(*this, e);
+    assert(!cir::MissingFeatures::cgFPOptionsRAII());
     mlir::Value v = emitScalarExpr(e->getArg(0));
     mlir::Location loc = getLoc(e->getBeginLoc());
-    // FIXME: We should use builder.createZExt once createZExt is available.
-    return RValue::get(builder.createZExtOrBitCast(
-        loc, builder.createIsFPClass(loc, v, FPClassTest::fcZero),
+    return RValue::get(builder.createBoolToInt(
+        builder.createIsFPClass(loc, v, FPClassTest::fcZero),
         convertType(e->getType())));
   }
   case Builtin::BI__builtin_isfpclass: {
@@ -623,24 +603,22 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl 
&gd, unsigned builtinID,
     if (!e->getArg(1)->EvaluateAsInt(result, cgm.getASTContext()))
       break;
 
-    CIRGenFunction::CIRGenFPOptionsRAII fpOptsRaii(*this, e);
+    assert(!cir::MissingFeatures::cgFPOptionsRAII());
     mlir::Value v = emitScalarExpr(e->getArg(0));
     uint64_t test = result.Val.getInt().getLimitedValue();
     mlir::Location loc = getLoc(e->getBeginLoc());
     //
-    // // FIXME: We should use builder.createZExt once createZExt is available.
-    return RValue::get(builder.createZExtOrBitCast(
-        loc, builder.createIsFPClass(loc, v, test), 
convertType(e->getType())));
+    return RValue::get(builder.createBoolToInt(
+        builder.createIsFPClass(loc, v, test), convertType(e->getType())));
   }
   }
 
   // If this is an alias for a lib function (e.g. __builtin_sin), emit
   // the call using the normal call path, but using the unmangled
   // version of the function name.
-  if (getContext().BuiltinInfo.isLibFunction(builtinID)) {
+  if (getContext().BuiltinInfo.isLibFunction(builtinID))
     return emitLibraryCall(*this, fd, e,
                            cgm.getBuiltinLibFunction(fd, builtinID));
-  }
 
   // Some target-specific builtins can have aggregate return values, e.g.
   // __builtin_arm_mve_vld2q_u32. So if the result is an aggregate, force
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp 
b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index ac48c25435530..2739469d7202e 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -834,22 +834,6 @@ void CIRGenFunction::emitDestructorBody(FunctionArgList 
&args) {
     cgm.errorNYI(dtor->getSourceRange(), "function-try-block destructor");
 }
 
-// Map the LangOption for exception behavior into the corresponding enum in
-// the IR.
-static cir::fp::ExceptionBehavior
-toConstrainedExceptMd(LangOptions::FPExceptionModeKind kind) {
-  switch (kind) {
-  case LangOptions::FPE_Ignore:
-    return cir::fp::ebIgnore;
-  case LangOptions::FPE_MayTrap:
-    return cir::fp::ebMayTrap;
-  case LangOptions::FPE_Strict:
-    return cir::fp::ebStrict;
-  default:
-    llvm_unreachable("Unsupported FP Exception Behavior");
-  }
-}
-
 /// Given a value of type T* that may not be to a complete object, construct
 /// an l-vlaue withi the natural pointee alignment of T.
 LValue CIRGenFunction::makeNaturalAlignPointeeAddrLValue(mlir::Value val,
@@ -1034,59 +1018,6 @@ void 
CIRGenFunction::emitNullInitialization(mlir::Location loc, Address destPtr,
   builder.createStore(loc, zeroValue, destPtr);
 }
 
-CIRGenFunction::CIRGenFPOptionsRAII::CIRGenFPOptionsRAII(CIRGenFunction &cgf,
-                                                         const clang::Expr *e)
-    : cgf(cgf) {
-  constructorHelper(e->getFPFeaturesInEffect(cgf.getLangOpts()));
-}
-
-CIRGenFunction::CIRGenFPOptionsRAII::CIRGenFPOptionsRAII(CIRGenFunction &cgf,
-                                                         FPOptions fpFeatures)
-    : cgf(cgf) {
-  constructorHelper(fpFeatures);
-}
-
-void CIRGenFunction::CIRGenFPOptionsRAII::constructorHelper(
-    FPOptions fpFeatures) {
-  oldFpFeatures = cgf.curFpFeatures;
-  cgf.curFpFeatures = fpFeatures;
-
-  oldExcept = cgf.builder.getDefaultConstrainedExcept();
-  oldRounding = cgf.builder.getDefaultConstrainedRounding();
-
-  if (oldFpFeatures == fpFeatures)
-    return;
-
-  // TODO(cir): create guard to restore fast math configurations.
-  assert(!cir::MissingFeatures::fastMathGuard());
-
-  llvm::RoundingMode newRoundingBehavior = fpFeatures.getRoundingMode();
-  // TODO(cir): override rounding behaviour once FM configs are guarded.
-  auto newExceptionBehavior =
-      toConstrainedExceptMd(static_cast<LangOptions::FPExceptionModeKind>(
-          fpFeatures.getExceptionMode()));
-  // TODO(cir): override exception behaviour once FM configs are guarded.
-
-  // TODO(cir): override FP flags once FM configs are guarded.
-  assert(!cir::MissingFeatures::fastMathFlags());
-
-  assert((cgf.curFuncDecl == nullptr || cgf.builder.getIsFPConstrained() ||
-          isa<CXXConstructorDecl>(cgf.curFuncDecl) ||
-          isa<CXXDestructorDecl>(cgf.curFuncDecl) ||
-          (newExceptionBehavior == cir::fp::ebIgnore &&
-           newRoundingBehavior == llvm::RoundingMode::NearestTiesToEven)) &&
-         "FPConstrained should be enabled on entire function");
-
-  // TODO(cir): mark CIR function with fast math attributes.
-  assert(!cir::MissingFeatures::fastMathFuncAttributes());
-}
-
-CIRGenFunction::CIRGenFPOptionsRAII::~CIRGenFPOptionsRAII() {
-  cgf.curFpFeatures = oldFpFeatures;
-  cgf.builder.setDefaultConstrainedExcept(oldExcept);
-  cgf.builder.setDefaultConstrainedRounding(oldRounding);
-}
-
 // TODO(cir): should be shared with LLVM codegen.
 bool CIRGenFunction::shouldNullCheckClassCastValue(const CastExpr *ce) {
   const Expr *e = ce->getSubExpr();
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h 
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 5080b3ddad7cf..98e185c11a506 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -180,20 +180,6 @@ class CIRGenFunction : public CIRGenTypeCache {
   /// Sanitizers enabled for this function.
   clang::SanitizerSet sanOpts;
 
-  class CIRGenFPOptionsRAII {
-  public:
-    CIRGenFPOptionsRAII(CIRGenFunction &cgf, FPOptions fpFeatures);
-    CIRGenFPOptionsRAII(CIRGenFunction &cgf, const clang::Expr *e);
-    ~CIRGenFPOptionsRAII();
-
-  private:
-    void constructorHelper(clang::FPOptions fpFeatures);
-    CIRGenFunction &cgf;
-    clang::FPOptions oldFpFeatures;
-    cir::fp::ExceptionBehavior oldExcept;
-    llvm::RoundingMode oldRounding;
-  };
-  clang::FPOptions curFpFeatures;
 
   /// The symbol table maps a variable name to a value in the current scope.
   /// Entering a function creates a new scope, and the function arguments are
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 04cf62ed3bd08..5b818b8cd9a8a 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -673,9 +673,9 @@ mlir::LogicalResult 
CIRToLLVMASinOpLowering::matchAndRewrite(
 mlir::LogicalResult CIRToLLVMIsFPClassOpLowering::matchAndRewrite(
     cir::IsFPClassOp op, OpAdaptor adaptor,
     mlir::ConversionPatternRewriter &rewriter) const {
-  auto src = adaptor.getSrc();
-  auto flags = adaptor.getFlags();
-  auto retTy = rewriter.getI1Type();
+  mlir::Value src = adaptor.getSrc();
+  uint32_t flags = adaptor.getFlags();
+  mlir::IntegerType retTy = rewriter.getI1Type();
 
   rewriter.replaceOpWithNewOp<mlir::LLVM::IsFPClass>(op, retTy, src, flags);
   return mlir::success();
diff --git a/clang/test/CIR/CodeGen/builtin-isfpclass.c 
b/clang/test/CIR/CodeGen/builtin-isfpclass.c
index b02069fcbb7f5..06d473d259e97 100644
--- a/clang/test/CIR/CodeGen/builtin-isfpclass.c
+++ b/clang/test/CIR/CodeGen/builtin-isfpclass.c
@@ -1,72 +1,117 @@
 // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o 
%t.cir
-// RUN: FileCheck --input-file=%t.cir %s
-
+// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o 
%t.cir
+// RUN: FileCheck --input-file=%t.cir %s -check-prefix=LLVM
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s -check-prefix=OGCG
 int finite(double);
 
 // CHECK: cir.func {{.*}}@test_is_finite
 void test_is_finite(__fp16 *H, float F, double D, long double LD) {
     volatile int res;
     res = __builtin_isinf(*H);
-    // CHECK: cir.is_fp_class %{{.*}}, 516 : (!cir.f16) -> !cir.bool
+    // CIR: cir.is_fp_class %{{.*}}, 516 : (!cir.f16) -> !cir.bool
+    // LLVM: call i1 @llvm.is.fpclass.f16(half {{.*}}, i32 516)
+    // OGCG: call i1 @llvm.is.fpclass.f16(half {{.*}}, i32 516)
 
     res = __builtin_isinf(F);
-    // CHECK: cir.is_fp_class %{{.*}}, 516 : (!cir.float) -> !cir.bool
+    // CIR: cir.is_fp_class %{{.*}}, 516 : (!cir.float) -> !cir.bool
+    // LLVM: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 516)
+    // OGCG: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 516)
 
     res = __builtin_isinf(D);
-    // CHECK: cir.is_fp_class %{{.*}}, 516 : (!cir.double) -> !cir.bool
+    // CIR: cir.is_fp_class %{{.*}}, 516 : (!cir.double) -> !cir.bool
+    // LLVM: call i1 @llvm.is.fpclass.f64(double {{.*}}, i32 516)
+    // OGCG: call i1 @llvm.is.fpclass.f64(double {{.*}}, i32 516)
 
     res = __builtin_isinf(LD);
-    // CHECK: cir.is_fp_class %{{.*}}, 516 : (!cir.long_double<!cir.f80>) -> 
!cir.bool
+    // CIR: cir.is_fp_class %{{.*}}, 516 : (!cir.long_double<!cir.f80>) -> 
!cir.bool
+    // LLVM: call i1 @llvm.is.fpclass.f80(x86_fp80 {{.*}}, i32 516)
+    // OGCG: call i1 @llvm.is.fpclass.f80(x86_fp80 {{.*}}, i32 516)
 
     res = __builtin_isfinite(*H);
-    // CHECK: cir.is_fp_class %{{.*}}, 504 : (!cir.f16) -> !cir.bool
+    // CIR: cir.is_fp_class %{{.*}}, 504 : (!cir.f16) -> !cir.bool
+    // LLVM: call i1 @llvm.is.fpclass.f16(half {{.*}}, i32 504)
+    // OGCG: call i1 @llvm.is.fpclass.f16(half {{.*}}, i32 504)
+
     res = __builtin_isfinite(F);
-    // CHECK: cir.is_fp_class %{{.*}}, 504 : (!cir.float) -> !cir.bool
-    res = finite(D);
-    // CHECK: cir.call @finite(%{{.*}}) nothrow side_effect(const) : 
(!cir.double) -> !s32i
+    // CIR: cir.is_fp_class %{{.*}}, 504 : (!cir.float) -> !cir.bool
+    // LLVM: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 504)
+    // OGCG: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 504)
 
+    res = finite(D);
+    // CIR: cir.call @finite(%{{.*}}) nothrow side_effect(const) : 
(!cir.double) -> !s32i
+    // LLVM: call i32 @finite(double {{.*}})
+    // OGCG: call i1 @llvm.is.fpclass.f64(double %20, i32 504)
     res = __builtin_isnormal(*H);
-    // CHECK: cir.is_fp_class %{{.*}}, 264 : (!cir.f16) -> !cir.bool
+    // CIR: cir.is_fp_class %{{.*}}, 264 : (!cir.f16) -> !cir.bool
+    // LLVM: call i1 @llvm.is.fpclass.f16(half {{.*}}, i32 264)
+    // OGCG: call i1 @llvm.is.fpclass.f16(half {{.*}}, i32 264)
+
     res = __builtin_isnormal(F);
-    // CHECK: cir.is_fp_class %{{.*}}, 264 : (!cir.float) -> !cir.bool
+    // CIR: cir.is_fp_class %{{.*}}, 264 : (!cir.float) -> !cir.bool
+    // LLVM: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 264)
+    // OGCG: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 264)
 
     res = __builtin_issubnormal(F);
-    // CHECK: cir.is_fp_class %{{.*}}, 144 : (!cir.float) -> !cir.bool
+    // CIR: cir.is_fp_class %{{.*}}, 144 : (!cir.float) -> !cir.bool
+    // LLVM: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 144)
+    // OGCG: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 144)
     res = __builtin_iszero(F);
-    // CHECK: cir.is_fp_class %{{.*}}, 96 : (!cir.float) -> !cir.bool
+    // CIR: cir.is_fp_class %{{.*}}, 96 : (!cir.float) -> !cir.bool
+    // LLVM: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 96)
+    // OGCG: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 96)
     res = __builtin_issignaling(F);
-    // CHECK: cir.is_fp_class %{{.*}}, 1 : (!cir.float) -> !cir.bool
+    // CIR: cir.is_fp_class %{{.*}}, 1 : (!cir.float) -> !cir.bool
+    // LLVM: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 1)
+    // OGCG: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 1)
 }
 
 _Bool check_isfpclass_finite(float x) {
   return __builtin_isfpclass(x, 504 /*Finite*/);
 }
 
-// CHECK: cir.func {{.*}}@check_isfpclass_finite
-// CHECK: cir.is_fp_class %{{.*}}, 504 : (!cir.float)
+// CIR: cir.func {{.*}}@check_isfpclass_finite
+// CIR: cir.is_fp_class %{{.*}}, 504 : (!cir.float)
+// LLVM: @check_isfpclass_finite
+// LLVM: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 504)
+// OGCG: @check_isfpclass_finite
+// OGCG: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 504)
 
 _Bool check_isfpclass_nan_f32(float x) {
   return __builtin_isfpclass(x, 3 /*NaN*/);
 }
 
-// CHECK: cir.func {{.*}}@check_isfpclass_nan_f32
-// CHECK: cir.is_fp_class %{{.*}}, 3 : (!cir.float)
+// CIR: cir.func {{.*}}@check_isfpclass_nan_f32
+// CIR: cir.is_fp_class %{{.*}}, 3 : (!cir.float)
+// LLVM: @check_isfpclass_nan_f32
+// LLVM: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 3)
+// OGCG: @check_isfpclass_nan_f32
+// OGCG: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 3)
 
 
 _Bool check_isfpclass_snan_f64(double x) {
   return __builtin_isfpclass(x, 1 /*SNaN*/);
 }
 
-// CHECK: cir.func {{.*}}@check_isfpclass_snan_f64
-// CHECK: cir.is_fp_class %{{.*}}, 1 : (!cir.double)
+// CIR: cir.func {{.*}}@check_isfpclass_snan_f64
+// CIR: cir.is_fp_class %{{.*}}, 1 : (!cir.double)
+// LLVM: @check_isfpclass_snan_f64
+// LLVM: call i1 @llvm.is.fpclass.f64(double {{.*}}, i32 1)
+// OGCG: @check_isfpclass_snan_f64
+// OGCG: call i1 @llvm.is.fpclass.f64(double {{.*}}, i32 1)
 
 
 _Bool check_isfpclass_zero_f16(_Float16 x) {
   return __builtin_isfpclass(x, 96 /*Zero*/);
 }
 
-// CHECK: cir.func {{.*}}@check_isfpclass_zero_f16
-// CHECK: cir.is_fp_class %{{.*}}, 96 : (!cir.f16)
+// CIR: cir.func {{.*}}@check_isfpclass_zero_f16
+// CIR: cir.is_fp_class %{{.*}}, 96 : (!cir.f16)
+// LLVM: @check_isfpclass_zero_f16
+// LLVM: call i1 @llvm.is.fpclass.f16(half {{.*}}, i32 96)
+// OGCG: @check_isfpclass_zero_f16
+// OGCG: call i1 @llvm.is.fpclass.f16(half {{.*}}, i32 96)
 
 // Update when we support FP pragma in functions and can convert BoolType in 
prvalue to i1.
 
diff --git a/clang/test/CIR/Lowering/builtin_isfpclass.c 
b/clang/test/CIR/Lowering/builtin_isfpclass.c
deleted file mode 100644
index f3b480b492a3f..0000000000000
--- a/clang/test/CIR/Lowering/builtin_isfpclass.c
+++ /dev/null
@@ -1,125 +0,0 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o 
%t.ll
-// RUN: FileCheck --input-file=%t.ll %s
-
-int finite(double);
-
-// CHECK: define {{.*}}@test_is_finite
-void test_is_finite(__fp16 *H, float F, double D, long double LD) {
-    volatile int res;
-    res = __builtin_isinf(*H);
-    // CHECK: call i1 @llvm.is.fpclass.f16(half %{{.*}}, i32 516)
-    res = __builtin_isinf(F);
-    // CHECK: call i1 @llvm.is.fpclass.f32(float %{{.*}}, i32 516)
-    res = __builtin_isinf(D);
-    // CHECK: call i1 @llvm.is.fpclass.f64(double %{{.*}}, i32 516)
-    res = __builtin_isinf(LD);
-    // CHECK: call i1 @llvm.is.fpclass.f80(x86_fp80 %{{.*}}, i32 516)
-
-    res = __builtin_isfinite(*H);
-    // CHECK: call i1 @llvm.is.fpclass.f16(half %{{.*}}, i32 504)
-    res = __builtin_isfinite(F);
-    // CHECK: call i1 @llvm.is.fpclass.f32(float %{{.*}}, i32 504)
-    res = finite(D);
-    // CHECK: call i32 @finite(double %{{.*}})
-
-    res = __builtin_isnormal(*H);
-    // CHECK: call i1 @llvm.is.fpclass.f16(half %{{.*}}, i32 264)
-    res = __builtin_isnormal(F);
-    // CHECK: call i1 @llvm.is.fpclass.f32(float %{{.*}}, i32 264)
-
-    res = __builtin_issubnormal(F);
-    // CHECK: call i1 @llvm.is.fpclass.f32(float %{{.*}}, i32 144)
-    res = __builtin_iszero(F);
-    // CHECK: call i1 @llvm.is.fpclass.f32(float %{{.*}}, i32 96)
-    res = __builtin_issignaling(F);
-    // CHECK: call i1 @llvm.is.fpclass.f32(float %{{.*}}, i32 1)
-}
-
-_Bool check_isfpclass_finite(float x) {
-  return __builtin_isfpclass(x, 504 /*Finite*/);
-}
-
-// CHECK: define {{.*}}@check_isfpclass_finite
-// CHECK: call i1 @llvm.is.fpclass.f32(float %{{.*}}, i32 504)
-
-_Bool check_isfpclass_nan_f32(float x) {
-  return __builtin_isfpclass(x, 3 /*NaN*/);
-}
-
-// CHECK: define {{.*}}@check_isfpclass_nan_f32
-// CHECK: call i1 @llvm.is.fpclass.f32(float %{{.*}}, i32 3)
-
-_Bool check_isfpclass_snan_f64(double x) {
-  return __builtin_isfpclass(x, 1 /*SNaN*/);
-}
-
-// CHECK: define {{.*}}@check_isfpclass_snan_f64
-// CHECK: call i1 @llvm.is.fpclass.f64(double %{{.*}}, i32 1)
-
-
-_Bool check_isfpclass_zero_f16(_Float16 x) {
-  return __builtin_isfpclass(x, 96 /*Zero*/);
-}
-
-// CHECK: define {{.*}}@check_isfpclass_zero_f16
-// CHECK: call i1 @llvm.is.fpclass.f16(half %{{.*}}, i32 96)
-
-// Update when we support FP pragma in functions.
-
-// _Bool check_isfpclass_finite_strict(float x) {
-// #pragma STDC FENV_ACCESS ON
-//   return __builtin_isfpclass(x, 504 /*Finite*/);
-// }
-// 
-// _Bool check_isfpclass_nan_f32_strict(float x) {
-// #pragma STDC FENV_ACCESS ON
-//   return __builtin_isfpclass(x, 3 /*NaN*/);
-// }
-// 
-// _Bool check_isfpclass_snan_f64_strict(double x) {
-// #pragma STDC FENV_ACCESS ON
-//   return __builtin_isfpclass(x, 1 /*NaN*/);
-// }
-// 
-// _Bool check_isfpclass_zero_f16_strict(_Float16 x) {
-// #pragma STDC FENV_ACCESS ON
-//   return __builtin_isfpclass(x, 96 /*Zero*/);
-// }
-// 
-// _Bool check_isnan(float x) {
-// #pragma STDC FENV_ACCESS ON
-//   return __builtin_isnan(x);
-// }
-// 
-// _Bool check_isinf(float x) {
-// #pragma STDC FENV_ACCESS ON
-//   return __builtin_isinf(x);
-// }
-// 
-// _Bool check_isfinite(float x) {
-// #pragma STDC FENV_ACCESS ON
-//   return __builtin_isfinite(x);
-// }
-// 
-// _Bool check_isnormal(float x) {
-// #pragma STDC FENV_ACCESS ON
-//   return __builtin_isnormal(x);
-// }
-// 
-// typedef float __attribute__((ext_vector_type(4))) float4;
-// typedef double __attribute__((ext_vector_type(4))) double4;
-// typedef int __attribute__((ext_vector_type(4))) int4;
-// typedef long __attribute__((ext_vector_type(4))) long4;
-// 
-// int4 check_isfpclass_nan_v4f32(float4 x) {
-//   return __builtin_isfpclass(x, 3 /*NaN*/);
-// }
-// 
-// int4 check_isfpclass_nan_strict_v4f32(float4 x) {
-// #pragma STDC FENV_ACCESS ON
-//   return __builtin_isfpclass(x, 3 /*NaN*/);
-// }
-// 
-// long4 check_isfpclass_nan_v4f64(double4 x) {
-//   return __builtin_isfpclass(x, 3 /*NaN*/);
-// }

>From 995d9c0677590ef92380bce7cbadde0b5c925ba6 Mon Sep 17 00:00:00 2001
From: Jasmine Tang <[email protected]>
Date: Tue, 11 Nov 2025 15:11:26 -0800
Subject: [PATCH 3/7] Fix formatting

---
 clang/lib/CIR/CodeGen/CIRGenFunction.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h 
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 98e185c11a506..1966424b6993f 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -180,7 +180,6 @@ class CIRGenFunction : public CIRGenTypeCache {
   /// Sanitizers enabled for this function.
   clang::SanitizerSet sanOpts;
 
-
   /// The symbol table maps a variable name to a value in the current scope.
   /// Entering a function creates a new scope, and the function arguments are
   /// added to the mapping. When the processing of a function is terminated,

>From 9715ff884c6bcaf600e5b6bb237fde78659d2f0b Mon Sep 17 00:00:00 2001
From: Jasmine Tang <[email protected]>
Date: Tue, 11 Nov 2025 23:27:09 -0800
Subject: [PATCH 4/7] Remove rest of unused code

---
 clang/lib/CIR/CodeGen/CIRGenBuilder.h | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h 
b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
index d611c0dc3d675..ef702deb2c9ae 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -30,9 +30,6 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
   const CIRGenTypeCache &typeCache;
   llvm::StringMap<unsigned> recordNames;
   llvm::StringMap<unsigned> globalsVersioning;
-  bool isFpConstrained = false;
-  cir::fp::ExceptionBehavior defaultConstrainedExcept = cir::fp::ebStrict;
-  llvm::RoundingMode defaultConstrainedRounding = llvm::RoundingMode::Dynamic;
 
 public:
   CIRGenBuilderTy(mlir::MLIRContext &mlirContext, const CIRGenTypeCache &tc)

>From e96ef8c3b6a5314b551357fd62544ea37776ec9a Mon Sep 17 00:00:00 2001
From: Jasmine Tang <[email protected]>
Date: Wed, 12 Nov 2025 10:05:23 -0800
Subject: [PATCH 5/7] Remove CIR fpenv.h

---
 clang/lib/CIR/CodeGen/CIRGenBuilder.h |  1 -
 clang/lib/CIR/Dialect/IR/FPEnv.cpp    | 64 ---------------------------
 2 files changed, 65 deletions(-)
 delete mode 100644 clang/lib/CIR/Dialect/IR/FPEnv.cpp

diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h 
b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
index ef702deb2c9ae..71c07679d529e 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -16,7 +16,6 @@
 #include "mlir/IR/BuiltinAttributes.h"
 #include "mlir/Support/LLVM.h"
 #include "clang/CIR/Dialect/IR/CIRDataLayout.h"
-#include "clang/CIR/Dialect/IR/FPEnv.h"
 #include "clang/CIR/MissingFeatures.h"
 
 #include "clang/CIR/Dialect/Builder/CIRBaseBuilder.h"
diff --git a/clang/lib/CIR/Dialect/IR/FPEnv.cpp 
b/clang/lib/CIR/Dialect/IR/FPEnv.cpp
deleted file mode 100644
index 719ceb32480c9..0000000000000
--- a/clang/lib/CIR/Dialect/IR/FPEnv.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-//===-- FPEnv.cpp ---- FP Environment 
-------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-/// @file
-/// This file contains the implementations of entities that describe floating
-/// point environment.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/CIR/Dialect/IR/FPEnv.h"
-
-namespace cir {
-
-std::optional<llvm::StringRef>
-convertRoundingModeToStr(llvm::RoundingMode useRounding) {
-  std::optional<llvm::StringRef> roundingStr;
-  switch (useRounding) {
-  case llvm::RoundingMode::Dynamic:
-    roundingStr = "round.dynamic";
-    break;
-  case llvm::RoundingMode::NearestTiesToEven:
-    roundingStr = "round.tonearest";
-    break;
-  case llvm::RoundingMode::NearestTiesToAway:
-    roundingStr = "round.tonearestaway";
-    break;
-  case llvm::RoundingMode::TowardNegative:
-    roundingStr = "round.downward";
-    break;
-  case llvm::RoundingMode::TowardPositive:
-    roundingStr = "round.upward";
-    break;
-  case llvm::RoundingMode::TowardZero:
-    roundingStr = "round.towardZero";
-    break;
-  default:
-    break;
-  }
-  return roundingStr;
-}
-
-std::optional<llvm::StringRef>
-convertExceptionBehaviorToStr(fp::ExceptionBehavior useExcept) {
-  std::optional<llvm::StringRef> exceptStr;
-  switch (useExcept) {
-  case fp::ebStrict:
-    exceptStr = "fpexcept.strict";
-    break;
-  case fp::ebIgnore:
-    exceptStr = "fpexcept.ignore";
-    break;
-  case fp::ebMayTrap:
-    exceptStr = "fpexcept.maytrap";
-    break;
-  }
-  return exceptStr;
-}
-
-} // namespace cir

>From a7d5592a2891a2639c042cb99a2ba3803ae2fc0a Mon Sep 17 00:00:00 2001
From: Jasmine Tang <[email protected]>
Date: Wed, 12 Nov 2025 15:22:46 -0800
Subject: [PATCH 6/7] Remove rest of unused code

---
 clang/include/clang/CIR/Dialect/IR/FPEnv.h | 50 ----------------------
 clang/lib/CIR/CodeGen/CIRGenFunction.h     |  1 -
 clang/lib/CIR/Dialect/IR/CMakeLists.txt    |  1 -
 3 files changed, 52 deletions(-)
 delete mode 100644 clang/include/clang/CIR/Dialect/IR/FPEnv.h

diff --git a/clang/include/clang/CIR/Dialect/IR/FPEnv.h 
b/clang/include/clang/CIR/Dialect/IR/FPEnv.h
deleted file mode 100644
index aceba9ee57d05..0000000000000
--- a/clang/include/clang/CIR/Dialect/IR/FPEnv.h
+++ /dev/null
@@ -1,50 +0,0 @@
-//===- FPEnv.h ---- FP Environment ------------------------------*- C++ 
-*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-/// @file
-/// This file contains the declarations of entities that describe floating
-/// point environment and related functions.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef CLANG_CIR_DIALECT_IR_FPENV_H
-#define CLANG_CIR_DIALECT_IR_FPENV_H
-
-#include "llvm/ADT/FloatingPointMode.h"
-
-#include <optional>
-
-namespace cir {
-
-namespace fp {
-
-/// Exception behavior used for floating point operations.
-///
-/// Each of these values corresponds to some LLVMIR metadata argument value of 
a
-/// constrained floating point intrinsic. See the LLVM Language Reference 
Manual
-/// for details.
-enum ExceptionBehavior : uint8_t {
-  ebIgnore,  ///< This corresponds to "fpexcept.ignore".
-  ebMayTrap, ///< This corresponds to "fpexcept.maytrap".
-  ebStrict,  ///< This corresponds to "fpexcept.strict".
-};
-
-} // namespace fp
-
-/// For any RoundingMode enumerator, returns a string valid as input in
-/// constrained intrinsic rounding mode metadata.
-std::optional<llvm::StringRef> convertRoundingModeToStr(llvm::RoundingMode);
-
-/// For any ExceptionBehavior enumerator, returns a string valid as input in
-/// constrained intrinsic exception behavior metadata.
-std::optional<llvm::StringRef>
-    convertExceptionBehaviorToStr(fp::ExceptionBehavior);
-
-} // namespace cir
-
-#endif
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h 
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 1966424b6993f..b22bf2d87fc10 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -31,7 +31,6 @@
 #include "clang/AST/Stmt.h"
 #include "clang/AST/Type.h"
 #include "clang/CIR/Dialect/IR/CIRDialect.h"
-#include "clang/CIR/Dialect/IR/FPEnv.h"
 #include "clang/CIR/MissingFeatures.h"
 #include "clang/CIR/TypeEvaluationKind.h"
 #include "llvm/ADT/ScopedHashTable.h"
diff --git a/clang/lib/CIR/Dialect/IR/CMakeLists.txt 
b/clang/lib/CIR/Dialect/IR/CMakeLists.txt
index de3c7d7a1c3b9..98575941035f2 100644
--- a/clang/lib/CIR/Dialect/IR/CMakeLists.txt
+++ b/clang/lib/CIR/Dialect/IR/CMakeLists.txt
@@ -4,7 +4,6 @@ add_clang_library(MLIRCIR
   CIRMemorySlot.cpp
   CIRTypes.cpp
   CIRDataLayout.cpp
-  FPEnv.cpp
 
   DEPENDS
   MLIRCIROpsIncGen

>From e54de58f9dcee36af8da20f7b8ab2bb4f3a33460 Mon Sep 17 00:00:00 2001
From: Jasmine Tang <[email protected]>
Date: Tue, 18 Nov 2025 18:55:54 -0800
Subject: [PATCH 7/7] Change to named enum

---
 clang/include/clang/CIR/Dialect/IR/CIROps.td  | 35 ++++++++++++++++++-
 clang/lib/CIR/CodeGen/CIRGenBuilder.h         |  2 +-
 clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp       | 16 ++++-----
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp |  4 +--
 clang/test/CIR/CodeGen/builtin-isfpclass.c    | 30 ++++++++--------
 5 files changed, 60 insertions(+), 27 deletions(-)

diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 67fe7e8e1f4a1..f27c15f29ca97 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -4018,6 +4018,39 @@ def CIR_RotateOp : CIR_Op<"rotate", [Pure, 
SameOperandsAndResultType]> {
   let hasFolder = 1;
 }
 
+//===----------------------------------------------------------------------===//
+// FPClass Test Flags
+//===----------------------------------------------------------------------===//
+
+def FPClassTestEnum : CIR_I32EnumAttr<"FPClassTest", "floating-point class 
test flags", [
+  // Basic flags
+  I32EnumAttrCase<"SignalingNaN", 1, "fcSNan">,
+  I32EnumAttrCase<"QuietNaN", 2, "fcQNan">,
+  I32EnumAttrCase<"NegativeInfinity", 4, "fcNegInf">,
+  I32EnumAttrCase<"NegativeNormal", 8, "fcNegNormal">,
+  I32EnumAttrCase<"NegativeSubnormal", 16, "fcNegSubnormal">,
+  I32EnumAttrCase<"NegativeZero", 32, "fcNegZero">,
+  I32EnumAttrCase<"PositiveZero", 64, "fcPosZero">,
+  I32EnumAttrCase<"PositiveSubnormal", 128, "fcPosSubnormal">,
+  I32EnumAttrCase<"PositiveNormal", 256, "fcPosNormal">,
+  I32EnumAttrCase<"PositiveInfinity", 512, "fcPosInf">,
+
+  // Composite flags
+  I32EnumAttrCase<"Nan", 3, "fcNan">,                   // fcSNan | fcQNan
+  I32EnumAttrCase<"Infinity", 516, "fcInf">,            // fcPosInf | fcNegInf
+  I32EnumAttrCase<"Normal", 264, "fcNormal">,           // fcPosNormal | 
fcNegNormal
+  I32EnumAttrCase<"Subnormal", 144, "fcSubnormal">,     // fcPosSubnormal | 
fcNegSubnormal
+  I32EnumAttrCase<"Zero", 96, "fcZero">,                // fcPosZero | 
fcNegZero
+  I32EnumAttrCase<"PositiveFinite", 448, "fcPosFinite">,// fcPosNormal | 
fcPosSubnormal | fcPosZero
+  I32EnumAttrCase<"NegativeFinite", 56, "fcNegFinite">, // fcNegNormal | 
fcNegSubnormal | fcNegZero
+  I32EnumAttrCase<"Finite", 504, "fcFinite">,           // fcPosFinite | 
fcNegFinite
+  I32EnumAttrCase<"Positive", 960, "fcPositive">,       // fcPosFinite | 
fcPosInf
+  I32EnumAttrCase<"Negative", 60, "fcNegative">,        // fcNegFinite | 
fcNegInf
+  I32EnumAttrCase<"All", 1023, "fcAllFlags">,           // fcNan | fcInf | 
fcFinite
+]> {
+  let cppNamespace = "::cir";
+}
+
 def CIR_IsFPClassOp : CIR_Op<"is_fp_class"> {
   let summary = "Corresponding to the `__builtin_fpclassify` builtin function 
in clang";
 
@@ -4044,7 +4077,7 @@ def CIR_IsFPClassOp : CIR_Op<"is_fp_class"> {
   }];
 
   let arguments = (ins CIR_AnyFloatType:$src,
-                       I32Attr:$flags);
+                       FPClassTestEnum:$flags);
   let results = (outs CIR_BoolType:$result);
   let assemblyFormat = [{
     $src `,` $flags `:` functional-type($src, $result) attr-dict
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h 
b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
index 71c07679d529e..f1e61835f7af9 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -335,7 +335,7 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
   }
 
   cir::IsFPClassOp createIsFPClass(mlir::Location loc, mlir::Value src,
-                                   unsigned flags) {
+                                   cir::FPClassTest flags) {
     return cir::IsFPClassOp::create(*this, loc, src, flags);
   }
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp 
b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index 14c3ccde80055..7b21dc34b3b9d 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -533,7 +533,7 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl 
&gd, unsigned builtinID,
     assert(!cir::MissingFeatures::fpConstraints());
     mlir::Location loc = getLoc(e->getBeginLoc());
     return RValue::get(builder.createBoolToInt(
-        builder.createIsFPClass(loc, v, FPClassTest::fcNan),
+        builder.createIsFPClass(loc, v, cir::FPClassTest::Nan),
         convertType(e->getType())));
   }
 
@@ -542,7 +542,7 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl 
&gd, unsigned builtinID,
     mlir::Value v = emitScalarExpr(e->getArg(0));
     mlir::Location loc = getLoc(e->getBeginLoc());
     return RValue::get(builder.createBoolToInt(
-        builder.createIsFPClass(loc, v, FPClassTest::fcSNan),
+        builder.createIsFPClass(loc, v, cir::FPClassTest::SignalingNaN),
         convertType(e->getType())));
   }
 
@@ -552,7 +552,7 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl 
&gd, unsigned builtinID,
     assert(!cir::MissingFeatures::fpConstraints());
     mlir::Location loc = getLoc(e->getBeginLoc());
     return RValue::get(builder.createBoolToInt(
-        builder.createIsFPClass(loc, v, FPClassTest::fcInf),
+        builder.createIsFPClass(loc, v, cir::FPClassTest::Infinity),
         convertType(e->getType())));
   }
 
@@ -568,7 +568,7 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl 
&gd, unsigned builtinID,
     assert(!cir::MissingFeatures::fpConstraints());
     mlir::Location loc = getLoc(e->getBeginLoc());
     return RValue::get(builder.createBoolToInt(
-        builder.createIsFPClass(loc, v, FPClassTest::fcFinite),
+        builder.createIsFPClass(loc, v, cir::FPClassTest::Finite),
         convertType(e->getType())));
   }
 
@@ -577,7 +577,7 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl 
&gd, unsigned builtinID,
     mlir::Value v = emitScalarExpr(e->getArg(0));
     mlir::Location loc = getLoc(e->getBeginLoc());
     return RValue::get(builder.createBoolToInt(
-        builder.createIsFPClass(loc, v, FPClassTest::fcNormal),
+        builder.createIsFPClass(loc, v, cir::FPClassTest::Normal),
         convertType(e->getType())));
   }
 
@@ -586,7 +586,7 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl 
&gd, unsigned builtinID,
     mlir::Value v = emitScalarExpr(e->getArg(0));
     mlir::Location loc = getLoc(e->getBeginLoc());
     return RValue::get(builder.createBoolToInt(
-        builder.createIsFPClass(loc, v, FPClassTest::fcSubnormal),
+        builder.createIsFPClass(loc, v, cir::FPClassTest::Subnormal),
         convertType(e->getType())));
   }
 
@@ -595,7 +595,7 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl 
&gd, unsigned builtinID,
     mlir::Value v = emitScalarExpr(e->getArg(0));
     mlir::Location loc = getLoc(e->getBeginLoc());
     return RValue::get(builder.createBoolToInt(
-        builder.createIsFPClass(loc, v, FPClassTest::fcZero),
+        builder.createIsFPClass(loc, v, cir::FPClassTest::Zero),
         convertType(e->getType())));
   }
   case Builtin::BI__builtin_isfpclass: {
@@ -609,7 +609,7 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl 
&gd, unsigned builtinID,
     mlir::Location loc = getLoc(e->getBeginLoc());
     //
     return RValue::get(builder.createBoolToInt(
-        builder.createIsFPClass(loc, v, test), convertType(e->getType())));
+        builder.createIsFPClass(loc, v, cir::FPClassTest(test)), 
convertType(e->getType())));
   }
   }
 
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 5b818b8cd9a8a..94fc4a4244148 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -674,10 +674,10 @@ mlir::LogicalResult 
CIRToLLVMIsFPClassOpLowering::matchAndRewrite(
     cir::IsFPClassOp op, OpAdaptor adaptor,
     mlir::ConversionPatternRewriter &rewriter) const {
   mlir::Value src = adaptor.getSrc();
-  uint32_t flags = adaptor.getFlags();
+  cir::FPClassTest flags = adaptor.getFlags();
   mlir::IntegerType retTy = rewriter.getI1Type();
 
-  rewriter.replaceOpWithNewOp<mlir::LLVM::IsFPClass>(op, retTy, src, flags);
+  rewriter.replaceOpWithNewOp<mlir::LLVM::IsFPClass>(op, retTy, src, 
static_cast<uint32_t>(flags));
   return mlir::success();
 }
 
diff --git a/clang/test/CIR/CodeGen/builtin-isfpclass.c 
b/clang/test/CIR/CodeGen/builtin-isfpclass.c
index 06d473d259e97..16d82c905f445 100644
--- a/clang/test/CIR/CodeGen/builtin-isfpclass.c
+++ b/clang/test/CIR/CodeGen/builtin-isfpclass.c
@@ -10,32 +10,32 @@ int finite(double);
 void test_is_finite(__fp16 *H, float F, double D, long double LD) {
     volatile int res;
     res = __builtin_isinf(*H);
-    // CIR: cir.is_fp_class %{{.*}}, 516 : (!cir.f16) -> !cir.bool
+    // CIR: cir.is_fp_class %{{.*}}, fcInf : (!cir.f16) -> !cir.bool
     // LLVM: call i1 @llvm.is.fpclass.f16(half {{.*}}, i32 516)
     // OGCG: call i1 @llvm.is.fpclass.f16(half {{.*}}, i32 516)
 
     res = __builtin_isinf(F);
-    // CIR: cir.is_fp_class %{{.*}}, 516 : (!cir.float) -> !cir.bool
+    // CIR: cir.is_fp_class %{{.*}}, fcInf : (!cir.float) -> !cir.bool
     // LLVM: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 516)
     // OGCG: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 516)
 
     res = __builtin_isinf(D);
-    // CIR: cir.is_fp_class %{{.*}}, 516 : (!cir.double) -> !cir.bool
+    // CIR: cir.is_fp_class %{{.*}}, fcInf : (!cir.double) -> !cir.bool
     // LLVM: call i1 @llvm.is.fpclass.f64(double {{.*}}, i32 516)
     // OGCG: call i1 @llvm.is.fpclass.f64(double {{.*}}, i32 516)
 
     res = __builtin_isinf(LD);
-    // CIR: cir.is_fp_class %{{.*}}, 516 : (!cir.long_double<!cir.f80>) -> 
!cir.bool
+    // CIR: cir.is_fp_class %{{.*}}, fcInf : (!cir.long_double<!cir.f80>) -> 
!cir.bool
     // LLVM: call i1 @llvm.is.fpclass.f80(x86_fp80 {{.*}}, i32 516)
     // OGCG: call i1 @llvm.is.fpclass.f80(x86_fp80 {{.*}}, i32 516)
 
     res = __builtin_isfinite(*H);
-    // CIR: cir.is_fp_class %{{.*}}, 504 : (!cir.f16) -> !cir.bool
+    // CIR: cir.is_fp_class %{{.*}}, fcFinite : (!cir.f16) -> !cir.bool
     // LLVM: call i1 @llvm.is.fpclass.f16(half {{.*}}, i32 504)
     // OGCG: call i1 @llvm.is.fpclass.f16(half {{.*}}, i32 504)
 
     res = __builtin_isfinite(F);
-    // CIR: cir.is_fp_class %{{.*}}, 504 : (!cir.float) -> !cir.bool
+    // CIR: cir.is_fp_class %{{.*}}, fcFinite : (!cir.float) -> !cir.bool
     // LLVM: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 504)
     // OGCG: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 504)
 
@@ -44,25 +44,25 @@ void test_is_finite(__fp16 *H, float F, double D, long 
double LD) {
     // LLVM: call i32 @finite(double {{.*}})
     // OGCG: call i1 @llvm.is.fpclass.f64(double %20, i32 504)
     res = __builtin_isnormal(*H);
-    // CIR: cir.is_fp_class %{{.*}}, 264 : (!cir.f16) -> !cir.bool
+    // CIR: cir.is_fp_class %{{.*}}, fcNormal : (!cir.f16) -> !cir.bool
     // LLVM: call i1 @llvm.is.fpclass.f16(half {{.*}}, i32 264)
     // OGCG: call i1 @llvm.is.fpclass.f16(half {{.*}}, i32 264)
 
     res = __builtin_isnormal(F);
-    // CIR: cir.is_fp_class %{{.*}}, 264 : (!cir.float) -> !cir.bool
+    // CIR: cir.is_fp_class %{{.*}}, fcNormal : (!cir.float) -> !cir.bool
     // LLVM: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 264)
     // OGCG: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 264)
 
     res = __builtin_issubnormal(F);
-    // CIR: cir.is_fp_class %{{.*}}, 144 : (!cir.float) -> !cir.bool
+    // CIR: cir.is_fp_class %{{.*}}, fcSubnormal : (!cir.float) -> !cir.bool
     // LLVM: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 144)
     // OGCG: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 144)
     res = __builtin_iszero(F);
-    // CIR: cir.is_fp_class %{{.*}}, 96 : (!cir.float) -> !cir.bool
+    // CIR: cir.is_fp_class %{{.*}}, fcZero : (!cir.float) -> !cir.bool
     // LLVM: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 96)
     // OGCG: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 96)
     res = __builtin_issignaling(F);
-    // CIR: cir.is_fp_class %{{.*}}, 1 : (!cir.float) -> !cir.bool
+    // CIR: cir.is_fp_class %{{.*}}, fcSNan : (!cir.float) -> !cir.bool
     // LLVM: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 1)
     // OGCG: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 1)
 }
@@ -72,7 +72,7 @@ _Bool check_isfpclass_finite(float x) {
 }
 
 // CIR: cir.func {{.*}}@check_isfpclass_finite
-// CIR: cir.is_fp_class %{{.*}}, 504 : (!cir.float)
+// CIR: cir.is_fp_class %{{.*}}, fcFinite : (!cir.float)
 // LLVM: @check_isfpclass_finite
 // LLVM: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 504)
 // OGCG: @check_isfpclass_finite
@@ -83,7 +83,7 @@ _Bool check_isfpclass_nan_f32(float x) {
 }
 
 // CIR: cir.func {{.*}}@check_isfpclass_nan_f32
-// CIR: cir.is_fp_class %{{.*}}, 3 : (!cir.float)
+// CIR: cir.is_fp_class %{{.*}}, fcNan : (!cir.float)
 // LLVM: @check_isfpclass_nan_f32
 // LLVM: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 3)
 // OGCG: @check_isfpclass_nan_f32
@@ -95,7 +95,7 @@ _Bool check_isfpclass_snan_f64(double x) {
 }
 
 // CIR: cir.func {{.*}}@check_isfpclass_snan_f64
-// CIR: cir.is_fp_class %{{.*}}, 1 : (!cir.double)
+// CIR: cir.is_fp_class %{{.*}}, fcSNan : (!cir.double)
 // LLVM: @check_isfpclass_snan_f64
 // LLVM: call i1 @llvm.is.fpclass.f64(double {{.*}}, i32 1)
 // OGCG: @check_isfpclass_snan_f64
@@ -107,7 +107,7 @@ _Bool check_isfpclass_zero_f16(_Float16 x) {
 }
 
 // CIR: cir.func {{.*}}@check_isfpclass_zero_f16
-// CIR: cir.is_fp_class %{{.*}}, 96 : (!cir.f16)
+// CIR: cir.is_fp_class %{{.*}}, fcZero : (!cir.f16)
 // LLVM: @check_isfpclass_zero_f16
 // LLVM: call i1 @llvm.is.fpclass.f16(half {{.*}}, i32 96)
 // OGCG: @check_isfpclass_zero_f16

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

Reply via email to