Skip to content

Conversation

@vdonaldson
Copy link
Contributor

Add support for the nonstandard ieee_denorm exception for real kinds 3, 4, 8 on x86 processors.

Add support for the nonstandard ieee_denorm exception for real
kinds 3, 4, 8 on x86 processors.
@vdonaldson vdonaldson requested a review from jeanPerier March 20, 2025 23:31
@llvmbot llvmbot added flang Flang issues not falling into any other category flang:fir-hlfir flang:semantics labels Mar 20, 2025
@llvmbot
Copy link
Member

llvmbot commented Mar 20, 2025

@llvm/pr-subscribers-flang-fir-hlfir

Author: None (vdonaldson)

Changes

Add support for the nonstandard ieee_denorm exception for real kinds 3, 4, 8 on x86 processors.


Patch is 105.77 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/132307.diff

18 Files Affected:

  • (modified) flang-rt/lib/runtime/exceptions.cpp (+52-8)
  • (modified) flang/include/flang/Evaluate/target.h (+8)
  • (modified) flang/include/flang/Optimizer/Builder/Runtime/Exceptions.h (+17)
  • (modified) flang/include/flang/Runtime/exceptions.h (+11-1)
  • (modified) flang/include/flang/Tools/TargetSetup.h (+4)
  • (modified) flang/lib/Evaluate/fold-logical.cpp (+32-2)
  • (modified) flang/lib/Evaluate/target.cpp (+24)
  • (modified) flang/lib/Optimizer/Builder/IntrinsicCall.cpp (+61-23)
  • (modified) flang/lib/Optimizer/Builder/Runtime/Exceptions.cpp (+43)
  • (modified) flang/test/Lower/Intrinsics/ieee_compare.f90 (+12-12)
  • (modified) flang/test/Lower/Intrinsics/ieee_flag.f90 (+42-42)
  • (modified) flang/test/Lower/Intrinsics/ieee_logb.f90 (+4-4)
  • (modified) flang/test/Lower/Intrinsics/ieee_max_min.f90 (+32-32)
  • (modified) flang/test/Lower/Intrinsics/ieee_next.f90 (+15-15)
  • (modified) flang/test/Lower/Intrinsics/ieee_real.f90 (+8-8)
  • (modified) flang/test/Lower/Intrinsics/ieee_rem.f90 (+3-3)
  • (modified) flang/test/Lower/Intrinsics/ieee_rint_int.f90 (+10-10)
  • (modified) flang/test/Lower/Intrinsics/nearest.f90 (+19-19)
diff --git a/flang-rt/lib/runtime/exceptions.cpp b/flang-rt/lib/runtime/exceptions.cpp
index d25a67c8e9cb5..a3ebd16dcd3ad 100644
--- a/flang-rt/lib/runtime/exceptions.cpp
+++ b/flang-rt/lib/runtime/exceptions.cpp
@@ -76,22 +76,66 @@ uint32_t RTNAME(MapException)(uint32_t excepts) {
   return except_value;
 }
 
+// The following exception processing routines have a libm call component,
+// and where available, an additional component for handling the nonstandard
+// ieee_denorm exception. The denorm component does not subsume the libm
+// component; both are needed.
+
+void RTNAME(feclearexcept)(uint32_t excepts) {
+  feclearexcept(excepts);
+#if defined(_MM_EXCEPT_DENORM)
+  _mm_setcsr(_mm_getcsr() & ~(excepts & _MM_EXCEPT_MASK));
+#endif
+}
+void RTNAME(feraiseexcept)(uint32_t excepts) {
+  feraiseexcept(excepts);
+#if defined(_MM_EXCEPT_DENORM)
+  _mm_setcsr(_mm_getcsr() | (excepts & _MM_EXCEPT_MASK));
+#endif
+}
+uint32_t RTNAME(fetestexcept)(uint32_t excepts) {
+#if defined(_MM_EXCEPT_DENORM)
+  return (_mm_getcsr() & _MM_EXCEPT_MASK & excepts) | fetestexcept(excepts);
+#else
+  return fetestexcept(excepts);
+#endif
+}
+void RTNAME(fedisableexcept)(uint32_t excepts) {
+  fedisableexcept(excepts);
+#if defined(_MM_EXCEPT_DENORM)
+  _mm_setcsr(_mm_getcsr() | ((excepts & _MM_EXCEPT_MASK) << 7));
+#endif
+}
+void RTNAME(feenableexcept)(uint32_t excepts) {
+  feenableexcept(excepts);
+#if defined(_MM_EXCEPT_DENORM)
+  _mm_setcsr(_mm_getcsr() & ~((excepts & _MM_EXCEPT_MASK) << 7));
+#endif
+}
+uint32_t RTNAME(fegetexcept)() {
+#if defined(_MM_EXCEPT_DENORM)
+  return (63 - ((_mm_getcsr() >> 7) & _MM_EXCEPT_MASK)) | fegetexcept();
+#else
+  return fegetexcept();
+#endif
+}
+
 // Check if the processor has the ability to control whether to halt or
 // continue execution when a given exception is raised.
 bool RTNAME(SupportHalting)([[maybe_unused]] uint32_t except) {
 #ifdef __USE_GNU
   except = RTNAME(MapException)(except);
-  int currentSet = fegetexcept(), flipSet, ok;
+  int currentSet = RTNAME(fegetexcept)(), flipSet;
   if (currentSet & except) {
-    ok = fedisableexcept(except);
-    flipSet = fegetexcept();
-    ok |= feenableexcept(except);
+    RTNAME(fedisableexcept)(except);
+    flipSet = RTNAME(fegetexcept)();
+    RTNAME(feenableexcept)(except);
   } else {
-    ok = feenableexcept(except);
-    flipSet = fegetexcept();
-    ok |= fedisableexcept(except);
+    RTNAME(feenableexcept)(except);
+    flipSet = RTNAME(fegetexcept)();
+    RTNAME(fedisableexcept)(except);
   }
-  return ok != -1 && currentSet != flipSet;
+  return currentSet != flipSet;
 #else
   return false;
 #endif
diff --git a/flang/include/flang/Evaluate/target.h b/flang/include/flang/Evaluate/target.h
index ead4481c32e12..7b1593ca270db 100644
--- a/flang/include/flang/Evaluate/target.h
+++ b/flang/include/flang/Evaluate/target.h
@@ -54,6 +54,13 @@ class TargetCharacteristics {
   bool hasSubnormalFlushingControl(bool any = false) const;
   void set_hasSubnormalFlushingControl(int kind, bool yes = true);
 
+  // Check if a given real kind has support for raising a nonstandard
+  // ieee_denorm exception.
+  bool hasSubnormalExceptionSupport(int kind) const;
+  // Check if all real kinds have support for the ieee_denorm exception.
+  bool hasSubnormalExceptionSupport() const;
+  void set_hasSubnormalExceptionSupport(int kind, bool yes = true);
+
   Rounding roundingMode() const { return roundingMode_; }
   void set_roundingMode(Rounding);
 
@@ -134,6 +141,7 @@ class TargetCharacteristics {
   bool haltingSupportIsUnknownAtCompileTime_{false};
   bool areSubnormalsFlushedToZero_{false};
   bool hasSubnormalFlushingControl_[maxKind + 1]{};
+  bool hasSubnormalExceptionSupport_[maxKind + 1]{};
   Rounding roundingMode_{defaultRounding};
   std::size_t procedurePointerByteSize_{8};
   std::size_t procedurePointerAlignment_{8};
diff --git a/flang/include/flang/Optimizer/Builder/Runtime/Exceptions.h b/flang/include/flang/Optimizer/Builder/Runtime/Exceptions.h
index 7487444f3a7a9..1d6e29beacb50 100644
--- a/flang/include/flang/Optimizer/Builder/Runtime/Exceptions.h
+++ b/flang/include/flang/Optimizer/Builder/Runtime/Exceptions.h
@@ -26,6 +26,23 @@ namespace fir::runtime {
 mlir::Value genMapExcept(fir::FirOpBuilder &builder, mlir::Location loc,
                          mlir::Value excepts);
 
+void genFeclearexcept(fir::FirOpBuilder &builder, mlir::Location loc,
+                      mlir::Value excepts);
+
+void genFeraiseexcept(fir::FirOpBuilder &builder, mlir::Location loc,
+                      mlir::Value excepts);
+
+mlir::Value genFetestexcept(fir::FirOpBuilder &builder, mlir::Location loc,
+                            mlir::Value excepts);
+
+void genFedisableexcept(fir::FirOpBuilder &builder, mlir::Location loc,
+                        mlir::Value excepts);
+
+void genFeenableexcept(fir::FirOpBuilder &builder, mlir::Location loc,
+                       mlir::Value excepts);
+
+mlir::Value genFegetexcept(fir::FirOpBuilder &builder, mlir::Location loc);
+
 mlir::Value genSupportHalting(fir::FirOpBuilder &builder, mlir::Location loc,
                               mlir::Value excepts);
 
diff --git a/flang/include/flang/Runtime/exceptions.h b/flang/include/flang/Runtime/exceptions.h
index 62c21f01c1289..c76376e36ed6d 100644
--- a/flang/include/flang/Runtime/exceptions.h
+++ b/flang/include/flang/Runtime/exceptions.h
@@ -6,7 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-// Map Fortran ieee_arithmetic module exceptions to fenv.h exceptions.
+// Support for floating point exceptions and related floating point environment
+// functionality.
 
 #ifndef FORTRAN_RUNTIME_EXCEPTIONS_H_
 #define FORTRAN_RUNTIME_EXCEPTIONS_H_
@@ -25,6 +26,15 @@ extern "C" {
 // This mapping is done at runtime to support cross compilation.
 std::uint32_t RTNAME(MapException)(std::uint32_t excepts);
 
+// Exception processing functions that call the corresponding libm functions,
+// and also include support for denormal exceptions where available.
+void RTNAME(feclearexcept)(std::uint32_t excepts);
+void RTNAME(feraiseexcept)(std::uint32_t excepts);
+std::uint32_t RTNAME(fetestexcept)(std::uint32_t excepts);
+void RTNAME(fedisableexcept)(std::uint32_t excepts);
+void RTNAME(feenableexcept)(std::uint32_t excepts);
+std::uint32_t RTNAME(fegetexcept)(void);
+
 // Check if the processor has the ability to control whether to halt
 // or continue exeuction when a given exception is raised.
 bool RTNAME(SupportHalting)(uint32_t except);
diff --git a/flang/include/flang/Tools/TargetSetup.h b/flang/include/flang/Tools/TargetSetup.h
index ee05d891db353..d981364a1a8fd 100644
--- a/flang/include/flang/Tools/TargetSetup.h
+++ b/flang/include/flang/Tools/TargetSetup.h
@@ -29,6 +29,10 @@ namespace Fortran::tools {
     targetCharacteristics.set_hasSubnormalFlushingControl(/*kind=*/3);
     targetCharacteristics.set_hasSubnormalFlushingControl(/*kind=*/4);
     targetCharacteristics.set_hasSubnormalFlushingControl(/*kind=*/8);
+    // ieee_denorm exception support is nonstandard.
+    targetCharacteristics.set_hasSubnormalExceptionSupport(/*kind=*/3);
+    targetCharacteristics.set_hasSubnormalExceptionSupport(/*kind=*/4);
+    targetCharacteristics.set_hasSubnormalExceptionSupport(/*kind=*/8);
   }
 
   if (targetTriple.isARM() || targetTriple.isAArch64()) {
diff --git a/flang/lib/Evaluate/fold-logical.cpp b/flang/lib/Evaluate/fold-logical.cpp
index 2e060ac94e34f..6950caf327419 100644
--- a/flang/lib/Evaluate/fold-logical.cpp
+++ b/flang/lib/Evaluate/fold-logical.cpp
@@ -875,8 +875,38 @@ Expr<Type<TypeCategory::Logical, KIND>> FoldIntrinsicFunction(
     return Expr<T>{context.targetCharacteristics().ieeeFeatures().test(
         IeeeFeature::Divide)};
   } else if (name == "__builtin_ieee_support_flag") {
-    return Expr<T>{context.targetCharacteristics().ieeeFeatures().test(
-        IeeeFeature::Flags)};
+    if (context.targetCharacteristics().ieeeFeatures().test(
+            IeeeFeature::Flags)) {
+      if (args[0]) {
+        if (const auto *cst{UnwrapExpr<Constant<SomeDerived>>(args[0])}) {
+          if (auto constr{cst->GetScalarValue()}) {
+            if (StructureConstructorValues & values{constr->values()};
+                values.size() == 1) {
+              const Expr<SomeType> &value{values.begin()->second.value()};
+              if (auto flag{ToInt64(value)}) {
+                if (flag != _FORTRAN_RUNTIME_IEEE_DENORM) {
+                  // Check for suppport for standard exceptions.
+                  return Expr<T>{
+                      context.targetCharacteristics().ieeeFeatures().test(
+                          IeeeFeature::Flags)};
+                } else if (args[1]) {
+                  // Check for nonstandard ieee_denorm exception support for
+                  // a given kind.
+                  return Expr<T>{context.targetCharacteristics()
+                          .hasSubnormalExceptionSupport(
+                              args[1]->GetType().value().kind())};
+                } else {
+                  // Check for nonstandard ieee_denorm exception support for
+                  // all kinds.
+                  return Expr<T>{context.targetCharacteristics()
+                          .hasSubnormalExceptionSupport()};
+                }
+              }
+            }
+          }
+        }
+      }
+    }
   } else if (name == "__builtin_ieee_support_halting") {
     if (!context.targetCharacteristics()
             .haltingSupportIsUnknownAtCompileTime()) {
diff --git a/flang/lib/Evaluate/target.cpp b/flang/lib/Evaluate/target.cpp
index 94dc35ecd5900..ba768f38c0ba4 100644
--- a/flang/lib/Evaluate/target.cpp
+++ b/flang/lib/Evaluate/target.cpp
@@ -134,6 +134,30 @@ void TargetCharacteristics::set_hasSubnormalFlushingControl(
   hasSubnormalFlushingControl_[kind] = yes;
 }
 
+// Check if a given real kind has (nonstandard) ieee_denorm exception control.
+bool TargetCharacteristics::hasSubnormalExceptionSupport(int kind) const {
+  CHECK(kind > 0 && kind <= maxKind);
+  CHECK(CanSupportType(TypeCategory::Real, kind));
+  return hasSubnormalExceptionSupport_[kind];
+}
+
+// Check if all real kinds have support for the ieee_denorm exception.
+bool TargetCharacteristics::hasSubnormalExceptionSupport() const {
+  for (int kind{1}; kind <= maxKind; ++kind) {
+    if (CanSupportType(TypeCategory::Real, kind) &&
+        !hasSubnormalExceptionSupport_[kind]) {
+      return false;
+    }
+  }
+  return true;
+}
+
+void TargetCharacteristics::set_hasSubnormalExceptionSupport(
+    int kind, bool yes) {
+  CHECK(kind > 0 && kind <= maxKind);
+  hasSubnormalExceptionSupport_[kind] = yes;
+}
+
 void TargetCharacteristics::set_roundingMode(Rounding rounding) {
   roundingMode_ = rounding;
 }
diff --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
index f57ed41fd785d..a37385dc168fb 100644
--- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
+++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
@@ -4571,8 +4571,8 @@ void IntrinsicLibrary::genRaiseExcept(int excepts, mlir::Value cond) {
     builder.setInsertionPointToStart(&ifOp.getThenRegion().front());
   }
   mlir::Type i32Ty = builder.getIntegerType(32);
-  genRuntimeCall(
-      "feraiseexcept", i32Ty,
+  fir::runtime::genFeraiseexcept(
+      builder, loc,
       fir::runtime::genMapExcept(
           builder, loc, builder.createIntegerConstant(loc, i32Ty, excepts)));
   if (cond)
@@ -4939,8 +4939,8 @@ void IntrinsicLibrary::genIeeeGetFlag(llvm::ArrayRef<fir::ExtendedValue> args) {
   mlir::Value zero = builder.createIntegerConstant(loc, i32Ty, 0);
   auto [fieldRef, ignore] = getFieldRef(builder, loc, flag);
   mlir::Value field = builder.create<fir::LoadOp>(loc, fieldRef);
-  mlir::Value excepts = IntrinsicLibrary::genRuntimeCall(
-      "fetestexcept", i32Ty,
+  mlir::Value excepts = fir::runtime::genFetestexcept(
+      builder, loc,
       fir::runtime::genMapExcept(
           builder, loc, builder.create<fir::ConvertOp>(loc, i32Ty, field)));
   mlir::Value logicalResult = builder.create<fir::ConvertOp>(
@@ -4963,8 +4963,7 @@ void IntrinsicLibrary::genIeeeGetHaltingMode(
   mlir::Value zero = builder.createIntegerConstant(loc, i32Ty, 0);
   auto [fieldRef, ignore] = getFieldRef(builder, loc, flag);
   mlir::Value field = builder.create<fir::LoadOp>(loc, fieldRef);
-  mlir::Value haltSet =
-      IntrinsicLibrary::genRuntimeCall("fegetexcept", i32Ty, {});
+  mlir::Value haltSet = fir::runtime::genFegetexcept(builder, loc);
   mlir::Value intResult = builder.create<mlir::arith::AndIOp>(
       loc, haltSet,
       fir::runtime::genMapExcept(
@@ -5712,9 +5711,11 @@ void IntrinsicLibrary::genIeeeSetFlagOrHaltingMode(
       loc, builder.create<fir::ConvertOp>(loc, i1Ty, getBase(args[1])),
       /*withElseRegion=*/true);
   builder.setInsertionPointToStart(&ifOp.getThenRegion().front());
-  genRuntimeCall(isFlag ? "feraiseexcept" : "feenableexcept", i32Ty, except);
+  (isFlag ? fir::runtime::genFeraiseexcept : fir::runtime::genFeenableexcept)(
+      builder, loc, builder.create<fir::ConvertOp>(loc, i32Ty, except));
   builder.setInsertionPointToStart(&ifOp.getElseRegion().front());
-  genRuntimeCall(isFlag ? "feclearexcept" : "fedisableexcept", i32Ty, except);
+  (isFlag ? fir::runtime::genFeclearexcept : fir::runtime::genFedisableexcept)(
+      builder, loc, builder.create<fir::ConvertOp>(loc, i32Ty, except));
   builder.setInsertionPointAfter(ifOp);
 }
 
@@ -5805,24 +5806,61 @@ mlir::Value IntrinsicLibrary::genIeeeSignbit(mlir::Type resultType,
 fir::ExtendedValue
 IntrinsicLibrary::genIeeeSupportFlag(mlir::Type resultType,
                                      llvm::ArrayRef<fir::ExtendedValue> args) {
-  // Check if a floating point exception flag is supported. A flag is
-  // supported either for all type kinds or none. An optional kind argument X
-  // is therefore ignored. Standard flags are all supported. The nonstandard
-  // DENORM extension is not supported, at least for now.
+  // Check if a floating point exception flag is supported.
   assert(args.size() == 1 || args.size() == 2);
+  mlir::Type i1Ty = builder.getI1Type();
+  mlir::Type i32Ty = builder.getIntegerType(32);
   auto [fieldRef, fieldTy] = getFieldRef(builder, loc, getBase(args[0]));
   mlir::Value flag = builder.create<fir::LoadOp>(loc, fieldRef);
-  mlir::Value mask = builder.createIntegerConstant( // values are powers of 2
+  mlir::Value standardFlagMask = builder.createIntegerConstant(
       loc, fieldTy,
       _FORTRAN_RUNTIME_IEEE_INVALID | _FORTRAN_RUNTIME_IEEE_DIVIDE_BY_ZERO |
           _FORTRAN_RUNTIME_IEEE_OVERFLOW | _FORTRAN_RUNTIME_IEEE_UNDERFLOW |
           _FORTRAN_RUNTIME_IEEE_INEXACT);
-  return builder.createConvert(
-      loc, resultType,
-      builder.create<mlir::arith::CmpIOp>(
-          loc, mlir::arith::CmpIPredicate::ne,
-          builder.create<mlir::arith::AndIOp>(loc, flag, mask),
-          builder.createIntegerConstant(loc, fieldTy, 0)));
+  mlir::Value isStandardFlag = builder.create<mlir::arith::CmpIOp>(
+      loc, mlir::arith::CmpIPredicate::ne,
+      builder.create<mlir::arith::AndIOp>(loc, flag, standardFlagMask),
+      builder.createIntegerConstant(loc, fieldTy, 0));
+  fir::IfOp ifOp = builder.create<fir::IfOp>(loc, i1Ty, isStandardFlag,
+                                             /*withElseRegion=*/true);
+  // Standard flags are supported.
+  builder.setInsertionPointToStart(&ifOp.getThenRegion().front());
+  builder.create<fir::ResultOp>(loc, builder.createBool(loc, true));
+
+  // TargetCharacteristics information for the nonstandard ieee_denorm flag
+  // is not available here. So use a runtime check restricted to possibly
+  // supported kinds.
+  builder.setInsertionPointToStart(&ifOp.getElseRegion().front());
+  bool mayBeSupported = false;
+  if (mlir::Value arg1 = getBase(args[1])) {
+    mlir::Type arg1Ty = arg1.getType();
+    if (fir::ReferenceType refTy = mlir::dyn_cast<fir::ReferenceType>(arg1Ty))
+      arg1Ty = refTy.getEleTy();
+    switch (mlir::dyn_cast<mlir::FloatType>(arg1Ty).getWidth()) {
+    case 16:
+      mayBeSupported = arg1Ty.isBF16(); // kind=3
+      break;
+    case 32: // kind=4
+    case 64: // kind=8
+      mayBeSupported = true;
+      break;
+    }
+  }
+  if (mayBeSupported) {
+    mlir::Value result = builder.create<mlir::arith::AndIOp>(
+        loc,
+        builder.create<mlir::arith::CmpIOp>(
+            loc, mlir::arith::CmpIPredicate::eq, flag,
+            builder.createIntegerConstant(loc, fieldTy,
+                                          _FORTRAN_RUNTIME_IEEE_DENORM)),
+        fir::runtime::genSupportHalting(
+            builder, loc, builder.create<fir::ConvertOp>(loc, i32Ty, flag)));
+    builder.create<fir::ResultOp>(loc, result);
+  } else {
+    builder.create<fir::ResultOp>(loc, builder.createBool(loc, false));
+  }
+  builder.setInsertionPointAfter(ifOp);
+  return builder.createConvert(loc, resultType, ifOp.getResult(0));
 }
 
 // IEEE_SUPPORT_HALTING
@@ -5838,7 +5876,7 @@ fir::ExtendedValue IntrinsicLibrary::genIeeeSupportHalting(
   return builder.createConvert(
       loc, resultType,
       fir::runtime::genSupportHalting(
-          builder, loc, {builder.create<fir::ConvertOp>(loc, i32Ty, field)}));
+          builder, loc, builder.create<fir::ConvertOp>(loc, i32Ty, field)));
 }
 
 // IEEE_SUPPORT_ROUNDING
@@ -5874,10 +5912,10 @@ fir::ExtendedValue IntrinsicLibrary::genIeeeSupportStandard(
   // if halting control is supported, as that is the only support component
   // that may not be available.
   assert(args.size() <= 1);
-  mlir::Value nearest = builder.createIntegerConstant(
-      loc, builder.getIntegerType(32), _FORTRAN_RUNTIME_IEEE_NEAREST);
+  mlir::Value overflow = builder.createIntegerConstant(
+      loc, builder.getIntegerType(32), _FORTRAN_RUNTIME_IEEE_OVERFLOW);
   return builder.createConvert(
-      loc, resultType, fir::runtime::genSupportHalting(builder, loc, nearest));
+      loc, resultType, fir::runtime::genSupportHalting(builder, loc, overflow));
 }
 
 // IEEE_UNORDERED
diff --git a/flang/lib/Optimizer/Builder/Runtime/Exceptions.cpp b/flang/lib/Optimizer/Builder/Runtime/Exceptions.cpp
index c545b3d00b4d7..0f66315696ac7 100644
--- a/flang/lib/Optimizer/Builder/Runtime/Exceptions.cpp
+++ b/flang/lib/Optimizer/Builder/Runtime/Exceptions.cpp
@@ -21,6 +21,49 @@ mlir::Value fir::runtime::genMapExcept(fir::FirOpBuilder &builder,
   return builder.create<fir::CallOp>(loc, func, excepts).getResult(0);
 }
 
+void fir::runtime::genFeclearexcept(fir::FirOpBuilder &builder,
+                                    mlir::Location loc, mlir::Value excepts) {
+  mlir::func::FuncOp func{
+      fir::runtime::getRuntimeFunc<mkRTKey(feclearexcept)>(loc, builder)};
+  builder.create<fir::CallOp>(loc, func, excepts);
+}
+
+void fir::runtime::genFeraiseexcept(fir::FirOpBuilder &builder,
+                                    mlir::Location loc, mlir::Value excepts) {
+  mlir::func::FuncOp func{
+      fir::runtime::getRuntimeFunc<mkRTKey(feraiseexcept)>(loc, builder)};
+  builder.create<fir::CallOp>(loc, func, excepts);
+}
+
+mlir::Value fir::runtime::genFetestexcept(fir::FirOpBuilder &builder,
+                                          mlir::Location loc,
+                                          mlir::Value excepts) {
+  mlir::func::FuncOp func{
+      fir::runtime::getRuntimeFunc<mkRTKey(fetestexcept)>(loc, builder)};
+  return builder.create<fir::CallOp>(loc, func, excepts).getResult(0);
+}
+
+void fir::runtime::genFedisableexcept(fir::FirOpBuilder &builder,
+                                      mlir::Location loc, mlir::Value excepts) {
+  mlir::func::FuncOp func{
+      fir::runtime::getRuntimeFunc<mkRTKey(fedisableexcept)>(loc, builder)};
+  builder.create<fir::CallOp>(loc, func, excepts);
+}
+
+void fir::runtime::genFeenableexcept(fir::FirOpBuilder &builder,
+                                     mlir::Location loc, mlir::Value excepts) {
+  mlir::func::FuncOp func{
+      fir::runtime::getRuntimeFunc<mkRTKey(feenableexcept)>(loc, builder)};
+  builder.create<fir::CallOp>(loc, func, excepts);
+}
+
+mlir::Value fir::runtime::genFegetexcept(fir::FirOpBuilder &builder,
+                                         mlir::Location loc) {
+  mlir::func::FuncOp func{
+      fir::runtime::getRuntimeFunc<mkRTKey(fegetexcept)>(loc, builder)};
+  return builder.create<fir::CallOp>...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented Mar 20, 2025

@llvm/pr-subscribers-flang-semantics

Author: None (vdonaldson)

Changes

Add support for the nonstandard ieee_denorm exception for real kinds 3, 4, 8 on x86 processors.


Patch is 105.77 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/132307.diff

18 Files Affected:

  • (modified) flang-rt/lib/runtime/exceptions.cpp (+52-8)
  • (modified) flang/include/flang/Evaluate/target.h (+8)
  • (modified) flang/include/flang/Optimizer/Builder/Runtime/Exceptions.h (+17)
  • (modified) flang/include/flang/Runtime/exceptions.h (+11-1)
  • (modified) flang/include/flang/Tools/TargetSetup.h (+4)
  • (modified) flang/lib/Evaluate/fold-logical.cpp (+32-2)
  • (modified) flang/lib/Evaluate/target.cpp (+24)
  • (modified) flang/lib/Optimizer/Builder/IntrinsicCall.cpp (+61-23)
  • (modified) flang/lib/Optimizer/Builder/Runtime/Exceptions.cpp (+43)
  • (modified) flang/test/Lower/Intrinsics/ieee_compare.f90 (+12-12)
  • (modified) flang/test/Lower/Intrinsics/ieee_flag.f90 (+42-42)
  • (modified) flang/test/Lower/Intrinsics/ieee_logb.f90 (+4-4)
  • (modified) flang/test/Lower/Intrinsics/ieee_max_min.f90 (+32-32)
  • (modified) flang/test/Lower/Intrinsics/ieee_next.f90 (+15-15)
  • (modified) flang/test/Lower/Intrinsics/ieee_real.f90 (+8-8)
  • (modified) flang/test/Lower/Intrinsics/ieee_rem.f90 (+3-3)
  • (modified) flang/test/Lower/Intrinsics/ieee_rint_int.f90 (+10-10)
  • (modified) flang/test/Lower/Intrinsics/nearest.f90 (+19-19)
diff --git a/flang-rt/lib/runtime/exceptions.cpp b/flang-rt/lib/runtime/exceptions.cpp
index d25a67c8e9cb5..a3ebd16dcd3ad 100644
--- a/flang-rt/lib/runtime/exceptions.cpp
+++ b/flang-rt/lib/runtime/exceptions.cpp
@@ -76,22 +76,66 @@ uint32_t RTNAME(MapException)(uint32_t excepts) {
   return except_value;
 }
 
+// The following exception processing routines have a libm call component,
+// and where available, an additional component for handling the nonstandard
+// ieee_denorm exception. The denorm component does not subsume the libm
+// component; both are needed.
+
+void RTNAME(feclearexcept)(uint32_t excepts) {
+  feclearexcept(excepts);
+#if defined(_MM_EXCEPT_DENORM)
+  _mm_setcsr(_mm_getcsr() & ~(excepts & _MM_EXCEPT_MASK));
+#endif
+}
+void RTNAME(feraiseexcept)(uint32_t excepts) {
+  feraiseexcept(excepts);
+#if defined(_MM_EXCEPT_DENORM)
+  _mm_setcsr(_mm_getcsr() | (excepts & _MM_EXCEPT_MASK));
+#endif
+}
+uint32_t RTNAME(fetestexcept)(uint32_t excepts) {
+#if defined(_MM_EXCEPT_DENORM)
+  return (_mm_getcsr() & _MM_EXCEPT_MASK & excepts) | fetestexcept(excepts);
+#else
+  return fetestexcept(excepts);
+#endif
+}
+void RTNAME(fedisableexcept)(uint32_t excepts) {
+  fedisableexcept(excepts);
+#if defined(_MM_EXCEPT_DENORM)
+  _mm_setcsr(_mm_getcsr() | ((excepts & _MM_EXCEPT_MASK) << 7));
+#endif
+}
+void RTNAME(feenableexcept)(uint32_t excepts) {
+  feenableexcept(excepts);
+#if defined(_MM_EXCEPT_DENORM)
+  _mm_setcsr(_mm_getcsr() & ~((excepts & _MM_EXCEPT_MASK) << 7));
+#endif
+}
+uint32_t RTNAME(fegetexcept)() {
+#if defined(_MM_EXCEPT_DENORM)
+  return (63 - ((_mm_getcsr() >> 7) & _MM_EXCEPT_MASK)) | fegetexcept();
+#else
+  return fegetexcept();
+#endif
+}
+
 // Check if the processor has the ability to control whether to halt or
 // continue execution when a given exception is raised.
 bool RTNAME(SupportHalting)([[maybe_unused]] uint32_t except) {
 #ifdef __USE_GNU
   except = RTNAME(MapException)(except);
-  int currentSet = fegetexcept(), flipSet, ok;
+  int currentSet = RTNAME(fegetexcept)(), flipSet;
   if (currentSet & except) {
-    ok = fedisableexcept(except);
-    flipSet = fegetexcept();
-    ok |= feenableexcept(except);
+    RTNAME(fedisableexcept)(except);
+    flipSet = RTNAME(fegetexcept)();
+    RTNAME(feenableexcept)(except);
   } else {
-    ok = feenableexcept(except);
-    flipSet = fegetexcept();
-    ok |= fedisableexcept(except);
+    RTNAME(feenableexcept)(except);
+    flipSet = RTNAME(fegetexcept)();
+    RTNAME(fedisableexcept)(except);
   }
-  return ok != -1 && currentSet != flipSet;
+  return currentSet != flipSet;
 #else
   return false;
 #endif
diff --git a/flang/include/flang/Evaluate/target.h b/flang/include/flang/Evaluate/target.h
index ead4481c32e12..7b1593ca270db 100644
--- a/flang/include/flang/Evaluate/target.h
+++ b/flang/include/flang/Evaluate/target.h
@@ -54,6 +54,13 @@ class TargetCharacteristics {
   bool hasSubnormalFlushingControl(bool any = false) const;
   void set_hasSubnormalFlushingControl(int kind, bool yes = true);
 
+  // Check if a given real kind has support for raising a nonstandard
+  // ieee_denorm exception.
+  bool hasSubnormalExceptionSupport(int kind) const;
+  // Check if all real kinds have support for the ieee_denorm exception.
+  bool hasSubnormalExceptionSupport() const;
+  void set_hasSubnormalExceptionSupport(int kind, bool yes = true);
+
   Rounding roundingMode() const { return roundingMode_; }
   void set_roundingMode(Rounding);
 
@@ -134,6 +141,7 @@ class TargetCharacteristics {
   bool haltingSupportIsUnknownAtCompileTime_{false};
   bool areSubnormalsFlushedToZero_{false};
   bool hasSubnormalFlushingControl_[maxKind + 1]{};
+  bool hasSubnormalExceptionSupport_[maxKind + 1]{};
   Rounding roundingMode_{defaultRounding};
   std::size_t procedurePointerByteSize_{8};
   std::size_t procedurePointerAlignment_{8};
diff --git a/flang/include/flang/Optimizer/Builder/Runtime/Exceptions.h b/flang/include/flang/Optimizer/Builder/Runtime/Exceptions.h
index 7487444f3a7a9..1d6e29beacb50 100644
--- a/flang/include/flang/Optimizer/Builder/Runtime/Exceptions.h
+++ b/flang/include/flang/Optimizer/Builder/Runtime/Exceptions.h
@@ -26,6 +26,23 @@ namespace fir::runtime {
 mlir::Value genMapExcept(fir::FirOpBuilder &builder, mlir::Location loc,
                          mlir::Value excepts);
 
+void genFeclearexcept(fir::FirOpBuilder &builder, mlir::Location loc,
+                      mlir::Value excepts);
+
+void genFeraiseexcept(fir::FirOpBuilder &builder, mlir::Location loc,
+                      mlir::Value excepts);
+
+mlir::Value genFetestexcept(fir::FirOpBuilder &builder, mlir::Location loc,
+                            mlir::Value excepts);
+
+void genFedisableexcept(fir::FirOpBuilder &builder, mlir::Location loc,
+                        mlir::Value excepts);
+
+void genFeenableexcept(fir::FirOpBuilder &builder, mlir::Location loc,
+                       mlir::Value excepts);
+
+mlir::Value genFegetexcept(fir::FirOpBuilder &builder, mlir::Location loc);
+
 mlir::Value genSupportHalting(fir::FirOpBuilder &builder, mlir::Location loc,
                               mlir::Value excepts);
 
diff --git a/flang/include/flang/Runtime/exceptions.h b/flang/include/flang/Runtime/exceptions.h
index 62c21f01c1289..c76376e36ed6d 100644
--- a/flang/include/flang/Runtime/exceptions.h
+++ b/flang/include/flang/Runtime/exceptions.h
@@ -6,7 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-// Map Fortran ieee_arithmetic module exceptions to fenv.h exceptions.
+// Support for floating point exceptions and related floating point environment
+// functionality.
 
 #ifndef FORTRAN_RUNTIME_EXCEPTIONS_H_
 #define FORTRAN_RUNTIME_EXCEPTIONS_H_
@@ -25,6 +26,15 @@ extern "C" {
 // This mapping is done at runtime to support cross compilation.
 std::uint32_t RTNAME(MapException)(std::uint32_t excepts);
 
+// Exception processing functions that call the corresponding libm functions,
+// and also include support for denormal exceptions where available.
+void RTNAME(feclearexcept)(std::uint32_t excepts);
+void RTNAME(feraiseexcept)(std::uint32_t excepts);
+std::uint32_t RTNAME(fetestexcept)(std::uint32_t excepts);
+void RTNAME(fedisableexcept)(std::uint32_t excepts);
+void RTNAME(feenableexcept)(std::uint32_t excepts);
+std::uint32_t RTNAME(fegetexcept)(void);
+
 // Check if the processor has the ability to control whether to halt
 // or continue exeuction when a given exception is raised.
 bool RTNAME(SupportHalting)(uint32_t except);
diff --git a/flang/include/flang/Tools/TargetSetup.h b/flang/include/flang/Tools/TargetSetup.h
index ee05d891db353..d981364a1a8fd 100644
--- a/flang/include/flang/Tools/TargetSetup.h
+++ b/flang/include/flang/Tools/TargetSetup.h
@@ -29,6 +29,10 @@ namespace Fortran::tools {
     targetCharacteristics.set_hasSubnormalFlushingControl(/*kind=*/3);
     targetCharacteristics.set_hasSubnormalFlushingControl(/*kind=*/4);
     targetCharacteristics.set_hasSubnormalFlushingControl(/*kind=*/8);
+    // ieee_denorm exception support is nonstandard.
+    targetCharacteristics.set_hasSubnormalExceptionSupport(/*kind=*/3);
+    targetCharacteristics.set_hasSubnormalExceptionSupport(/*kind=*/4);
+    targetCharacteristics.set_hasSubnormalExceptionSupport(/*kind=*/8);
   }
 
   if (targetTriple.isARM() || targetTriple.isAArch64()) {
diff --git a/flang/lib/Evaluate/fold-logical.cpp b/flang/lib/Evaluate/fold-logical.cpp
index 2e060ac94e34f..6950caf327419 100644
--- a/flang/lib/Evaluate/fold-logical.cpp
+++ b/flang/lib/Evaluate/fold-logical.cpp
@@ -875,8 +875,38 @@ Expr<Type<TypeCategory::Logical, KIND>> FoldIntrinsicFunction(
     return Expr<T>{context.targetCharacteristics().ieeeFeatures().test(
         IeeeFeature::Divide)};
   } else if (name == "__builtin_ieee_support_flag") {
-    return Expr<T>{context.targetCharacteristics().ieeeFeatures().test(
-        IeeeFeature::Flags)};
+    if (context.targetCharacteristics().ieeeFeatures().test(
+            IeeeFeature::Flags)) {
+      if (args[0]) {
+        if (const auto *cst{UnwrapExpr<Constant<SomeDerived>>(args[0])}) {
+          if (auto constr{cst->GetScalarValue()}) {
+            if (StructureConstructorValues & values{constr->values()};
+                values.size() == 1) {
+              const Expr<SomeType> &value{values.begin()->second.value()};
+              if (auto flag{ToInt64(value)}) {
+                if (flag != _FORTRAN_RUNTIME_IEEE_DENORM) {
+                  // Check for suppport for standard exceptions.
+                  return Expr<T>{
+                      context.targetCharacteristics().ieeeFeatures().test(
+                          IeeeFeature::Flags)};
+                } else if (args[1]) {
+                  // Check for nonstandard ieee_denorm exception support for
+                  // a given kind.
+                  return Expr<T>{context.targetCharacteristics()
+                          .hasSubnormalExceptionSupport(
+                              args[1]->GetType().value().kind())};
+                } else {
+                  // Check for nonstandard ieee_denorm exception support for
+                  // all kinds.
+                  return Expr<T>{context.targetCharacteristics()
+                          .hasSubnormalExceptionSupport()};
+                }
+              }
+            }
+          }
+        }
+      }
+    }
   } else if (name == "__builtin_ieee_support_halting") {
     if (!context.targetCharacteristics()
             .haltingSupportIsUnknownAtCompileTime()) {
diff --git a/flang/lib/Evaluate/target.cpp b/flang/lib/Evaluate/target.cpp
index 94dc35ecd5900..ba768f38c0ba4 100644
--- a/flang/lib/Evaluate/target.cpp
+++ b/flang/lib/Evaluate/target.cpp
@@ -134,6 +134,30 @@ void TargetCharacteristics::set_hasSubnormalFlushingControl(
   hasSubnormalFlushingControl_[kind] = yes;
 }
 
+// Check if a given real kind has (nonstandard) ieee_denorm exception control.
+bool TargetCharacteristics::hasSubnormalExceptionSupport(int kind) const {
+  CHECK(kind > 0 && kind <= maxKind);
+  CHECK(CanSupportType(TypeCategory::Real, kind));
+  return hasSubnormalExceptionSupport_[kind];
+}
+
+// Check if all real kinds have support for the ieee_denorm exception.
+bool TargetCharacteristics::hasSubnormalExceptionSupport() const {
+  for (int kind{1}; kind <= maxKind; ++kind) {
+    if (CanSupportType(TypeCategory::Real, kind) &&
+        !hasSubnormalExceptionSupport_[kind]) {
+      return false;
+    }
+  }
+  return true;
+}
+
+void TargetCharacteristics::set_hasSubnormalExceptionSupport(
+    int kind, bool yes) {
+  CHECK(kind > 0 && kind <= maxKind);
+  hasSubnormalExceptionSupport_[kind] = yes;
+}
+
 void TargetCharacteristics::set_roundingMode(Rounding rounding) {
   roundingMode_ = rounding;
 }
diff --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
index f57ed41fd785d..a37385dc168fb 100644
--- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
+++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
@@ -4571,8 +4571,8 @@ void IntrinsicLibrary::genRaiseExcept(int excepts, mlir::Value cond) {
     builder.setInsertionPointToStart(&ifOp.getThenRegion().front());
   }
   mlir::Type i32Ty = builder.getIntegerType(32);
-  genRuntimeCall(
-      "feraiseexcept", i32Ty,
+  fir::runtime::genFeraiseexcept(
+      builder, loc,
       fir::runtime::genMapExcept(
           builder, loc, builder.createIntegerConstant(loc, i32Ty, excepts)));
   if (cond)
@@ -4939,8 +4939,8 @@ void IntrinsicLibrary::genIeeeGetFlag(llvm::ArrayRef<fir::ExtendedValue> args) {
   mlir::Value zero = builder.createIntegerConstant(loc, i32Ty, 0);
   auto [fieldRef, ignore] = getFieldRef(builder, loc, flag);
   mlir::Value field = builder.create<fir::LoadOp>(loc, fieldRef);
-  mlir::Value excepts = IntrinsicLibrary::genRuntimeCall(
-      "fetestexcept", i32Ty,
+  mlir::Value excepts = fir::runtime::genFetestexcept(
+      builder, loc,
       fir::runtime::genMapExcept(
           builder, loc, builder.create<fir::ConvertOp>(loc, i32Ty, field)));
   mlir::Value logicalResult = builder.create<fir::ConvertOp>(
@@ -4963,8 +4963,7 @@ void IntrinsicLibrary::genIeeeGetHaltingMode(
   mlir::Value zero = builder.createIntegerConstant(loc, i32Ty, 0);
   auto [fieldRef, ignore] = getFieldRef(builder, loc, flag);
   mlir::Value field = builder.create<fir::LoadOp>(loc, fieldRef);
-  mlir::Value haltSet =
-      IntrinsicLibrary::genRuntimeCall("fegetexcept", i32Ty, {});
+  mlir::Value haltSet = fir::runtime::genFegetexcept(builder, loc);
   mlir::Value intResult = builder.create<mlir::arith::AndIOp>(
       loc, haltSet,
       fir::runtime::genMapExcept(
@@ -5712,9 +5711,11 @@ void IntrinsicLibrary::genIeeeSetFlagOrHaltingMode(
       loc, builder.create<fir::ConvertOp>(loc, i1Ty, getBase(args[1])),
       /*withElseRegion=*/true);
   builder.setInsertionPointToStart(&ifOp.getThenRegion().front());
-  genRuntimeCall(isFlag ? "feraiseexcept" : "feenableexcept", i32Ty, except);
+  (isFlag ? fir::runtime::genFeraiseexcept : fir::runtime::genFeenableexcept)(
+      builder, loc, builder.create<fir::ConvertOp>(loc, i32Ty, except));
   builder.setInsertionPointToStart(&ifOp.getElseRegion().front());
-  genRuntimeCall(isFlag ? "feclearexcept" : "fedisableexcept", i32Ty, except);
+  (isFlag ? fir::runtime::genFeclearexcept : fir::runtime::genFedisableexcept)(
+      builder, loc, builder.create<fir::ConvertOp>(loc, i32Ty, except));
   builder.setInsertionPointAfter(ifOp);
 }
 
@@ -5805,24 +5806,61 @@ mlir::Value IntrinsicLibrary::genIeeeSignbit(mlir::Type resultType,
 fir::ExtendedValue
 IntrinsicLibrary::genIeeeSupportFlag(mlir::Type resultType,
                                      llvm::ArrayRef<fir::ExtendedValue> args) {
-  // Check if a floating point exception flag is supported. A flag is
-  // supported either for all type kinds or none. An optional kind argument X
-  // is therefore ignored. Standard flags are all supported. The nonstandard
-  // DENORM extension is not supported, at least for now.
+  // Check if a floating point exception flag is supported.
   assert(args.size() == 1 || args.size() == 2);
+  mlir::Type i1Ty = builder.getI1Type();
+  mlir::Type i32Ty = builder.getIntegerType(32);
   auto [fieldRef, fieldTy] = getFieldRef(builder, loc, getBase(args[0]));
   mlir::Value flag = builder.create<fir::LoadOp>(loc, fieldRef);
-  mlir::Value mask = builder.createIntegerConstant( // values are powers of 2
+  mlir::Value standardFlagMask = builder.createIntegerConstant(
       loc, fieldTy,
       _FORTRAN_RUNTIME_IEEE_INVALID | _FORTRAN_RUNTIME_IEEE_DIVIDE_BY_ZERO |
           _FORTRAN_RUNTIME_IEEE_OVERFLOW | _FORTRAN_RUNTIME_IEEE_UNDERFLOW |
           _FORTRAN_RUNTIME_IEEE_INEXACT);
-  return builder.createConvert(
-      loc, resultType,
-      builder.create<mlir::arith::CmpIOp>(
-          loc, mlir::arith::CmpIPredicate::ne,
-          builder.create<mlir::arith::AndIOp>(loc, flag, mask),
-          builder.createIntegerConstant(loc, fieldTy, 0)));
+  mlir::Value isStandardFlag = builder.create<mlir::arith::CmpIOp>(
+      loc, mlir::arith::CmpIPredicate::ne,
+      builder.create<mlir::arith::AndIOp>(loc, flag, standardFlagMask),
+      builder.createIntegerConstant(loc, fieldTy, 0));
+  fir::IfOp ifOp = builder.create<fir::IfOp>(loc, i1Ty, isStandardFlag,
+                                             /*withElseRegion=*/true);
+  // Standard flags are supported.
+  builder.setInsertionPointToStart(&ifOp.getThenRegion().front());
+  builder.create<fir::ResultOp>(loc, builder.createBool(loc, true));
+
+  // TargetCharacteristics information for the nonstandard ieee_denorm flag
+  // is not available here. So use a runtime check restricted to possibly
+  // supported kinds.
+  builder.setInsertionPointToStart(&ifOp.getElseRegion().front());
+  bool mayBeSupported = false;
+  if (mlir::Value arg1 = getBase(args[1])) {
+    mlir::Type arg1Ty = arg1.getType();
+    if (fir::ReferenceType refTy = mlir::dyn_cast<fir::ReferenceType>(arg1Ty))
+      arg1Ty = refTy.getEleTy();
+    switch (mlir::dyn_cast<mlir::FloatType>(arg1Ty).getWidth()) {
+    case 16:
+      mayBeSupported = arg1Ty.isBF16(); // kind=3
+      break;
+    case 32: // kind=4
+    case 64: // kind=8
+      mayBeSupported = true;
+      break;
+    }
+  }
+  if (mayBeSupported) {
+    mlir::Value result = builder.create<mlir::arith::AndIOp>(
+        loc,
+        builder.create<mlir::arith::CmpIOp>(
+            loc, mlir::arith::CmpIPredicate::eq, flag,
+            builder.createIntegerConstant(loc, fieldTy,
+                                          _FORTRAN_RUNTIME_IEEE_DENORM)),
+        fir::runtime::genSupportHalting(
+            builder, loc, builder.create<fir::ConvertOp>(loc, i32Ty, flag)));
+    builder.create<fir::ResultOp>(loc, result);
+  } else {
+    builder.create<fir::ResultOp>(loc, builder.createBool(loc, false));
+  }
+  builder.setInsertionPointAfter(ifOp);
+  return builder.createConvert(loc, resultType, ifOp.getResult(0));
 }
 
 // IEEE_SUPPORT_HALTING
@@ -5838,7 +5876,7 @@ fir::ExtendedValue IntrinsicLibrary::genIeeeSupportHalting(
   return builder.createConvert(
       loc, resultType,
       fir::runtime::genSupportHalting(
-          builder, loc, {builder.create<fir::ConvertOp>(loc, i32Ty, field)}));
+          builder, loc, builder.create<fir::ConvertOp>(loc, i32Ty, field)));
 }
 
 // IEEE_SUPPORT_ROUNDING
@@ -5874,10 +5912,10 @@ fir::ExtendedValue IntrinsicLibrary::genIeeeSupportStandard(
   // if halting control is supported, as that is the only support component
   // that may not be available.
   assert(args.size() <= 1);
-  mlir::Value nearest = builder.createIntegerConstant(
-      loc, builder.getIntegerType(32), _FORTRAN_RUNTIME_IEEE_NEAREST);
+  mlir::Value overflow = builder.createIntegerConstant(
+      loc, builder.getIntegerType(32), _FORTRAN_RUNTIME_IEEE_OVERFLOW);
   return builder.createConvert(
-      loc, resultType, fir::runtime::genSupportHalting(builder, loc, nearest));
+      loc, resultType, fir::runtime::genSupportHalting(builder, loc, overflow));
 }
 
 // IEEE_UNORDERED
diff --git a/flang/lib/Optimizer/Builder/Runtime/Exceptions.cpp b/flang/lib/Optimizer/Builder/Runtime/Exceptions.cpp
index c545b3d00b4d7..0f66315696ac7 100644
--- a/flang/lib/Optimizer/Builder/Runtime/Exceptions.cpp
+++ b/flang/lib/Optimizer/Builder/Runtime/Exceptions.cpp
@@ -21,6 +21,49 @@ mlir::Value fir::runtime::genMapExcept(fir::FirOpBuilder &builder,
   return builder.create<fir::CallOp>(loc, func, excepts).getResult(0);
 }
 
+void fir::runtime::genFeclearexcept(fir::FirOpBuilder &builder,
+                                    mlir::Location loc, mlir::Value excepts) {
+  mlir::func::FuncOp func{
+      fir::runtime::getRuntimeFunc<mkRTKey(feclearexcept)>(loc, builder)};
+  builder.create<fir::CallOp>(loc, func, excepts);
+}
+
+void fir::runtime::genFeraiseexcept(fir::FirOpBuilder &builder,
+                                    mlir::Location loc, mlir::Value excepts) {
+  mlir::func::FuncOp func{
+      fir::runtime::getRuntimeFunc<mkRTKey(feraiseexcept)>(loc, builder)};
+  builder.create<fir::CallOp>(loc, func, excepts);
+}
+
+mlir::Value fir::runtime::genFetestexcept(fir::FirOpBuilder &builder,
+                                          mlir::Location loc,
+                                          mlir::Value excepts) {
+  mlir::func::FuncOp func{
+      fir::runtime::getRuntimeFunc<mkRTKey(fetestexcept)>(loc, builder)};
+  return builder.create<fir::CallOp>(loc, func, excepts).getResult(0);
+}
+
+void fir::runtime::genFedisableexcept(fir::FirOpBuilder &builder,
+                                      mlir::Location loc, mlir::Value excepts) {
+  mlir::func::FuncOp func{
+      fir::runtime::getRuntimeFunc<mkRTKey(fedisableexcept)>(loc, builder)};
+  builder.create<fir::CallOp>(loc, func, excepts);
+}
+
+void fir::runtime::genFeenableexcept(fir::FirOpBuilder &builder,
+                                     mlir::Location loc, mlir::Value excepts) {
+  mlir::func::FuncOp func{
+      fir::runtime::getRuntimeFunc<mkRTKey(feenableexcept)>(loc, builder)};
+  builder.create<fir::CallOp>(loc, func, excepts);
+}
+
+mlir::Value fir::runtime::genFegetexcept(fir::FirOpBuilder &builder,
+                                         mlir::Location loc) {
+  mlir::func::FuncOp func{
+      fir::runtime::getRuntimeFunc<mkRTKey(fegetexcept)>(loc, builder)};
+  return builder.create<fir::CallOp>...
[truncated]

Copy link
Contributor

@jeanPerier jeanPerier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Val! This looks great, please double check whether you need to move the #ifdef __USE_GNU or not.

@vdonaldson vdonaldson merged commit 92e0560 into llvm:main Mar 25, 2025
11 checks passed
@vdonaldson vdonaldson deleted the vkd1 branch March 25, 2025 19:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

flang:fir-hlfir flang:semantics flang Flang issues not falling into any other category

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants