[flang-commits] [flang] [llvm] [flang][PPC] Implement ieee_set_status and ieee_get_status for AIX (PR #215618)

Kelvin Li via flang-commits flang-commits at lists.llvm.org
Thu Aug 20 19:04:22 PDT 2026


https://github.com/kkwli updated https://github.com/llvm/llvm-project/pull/215618

>From 43c92b774bc159062111afe073efe4e312b3a222 Mon Sep 17 00:00:00 2001
From: Kelvin Li <kli at ca.ibm.com>
Date: Fri, 7 Aug 2026 16:22:04 -0400
Subject: [PATCH 1/5] [flang][PPC] Implement ieee_set_status and
 ieee_get_status for AIX and Linux

Assisted-by: IBM Bob
---
 flang-rt/lib/runtime/exceptions.cpp           |  8 +-
 flang-rt/unittests/Runtime/Exceptions.cpp     | 16 ++++
 .../Optimizer/Builder/LowLevelIntrinsics.h    |  6 ++
 flang/lib/Optimizer/Builder/IntrinsicCall.cpp | 83 +++++++++++++++++--
 .../Optimizer/Builder/LowLevelIntrinsics.cpp  | 17 ++++
 flang/test/Lower/Intrinsics/ieee_status.f90   | 43 ++++++++++
 6 files changed, 164 insertions(+), 9 deletions(-)
 create mode 100644 flang/test/Lower/Intrinsics/ieee_status.f90

diff --git a/flang-rt/lib/runtime/exceptions.cpp b/flang-rt/lib/runtime/exceptions.cpp
index 5fb83f0375227..33cb9945c863a 100644
--- a/flang-rt/lib/runtime/exceptions.cpp
+++ b/flang-rt/lib/runtime/exceptions.cpp
@@ -231,7 +231,13 @@ size_t RTNAME(GetModesTypeSize)(void) {
 #endif
 }
 size_t RTNAME(GetStatusTypeSize)(void) {
-  return sizeof(fenv_t); // byte size of ieee_status_type data
+  // byte size of ieee_status_type data
+#if defined(_AIX)
+  // the raw FPSCR double is needed for trap-enable bit round-trip
+  return sizeof(fenv_t) + sizeof(double);
+#else
+  return sizeof(fenv_t);
+#endif
 }
 
 } // extern "C"
diff --git a/flang-rt/unittests/Runtime/Exceptions.cpp b/flang-rt/unittests/Runtime/Exceptions.cpp
index d6514ea9faae9..e2f247c1cb62d 100644
--- a/flang-rt/unittests/Runtime/Exceptions.cpp
+++ b/flang-rt/unittests/Runtime/Exceptions.cpp
@@ -142,3 +142,19 @@ TEST(Exceptions, ClearOneLeavesOthersAlone) {
   GTEST_SKIP() << "FE_OVERFLOW and FE_INVALID required for this test";
 #endif
 }
+
+TEST(Exceptions, GetStatusTypeSizeMatchesPlatformLayout) {
+  const std::size_t sz{RTNAME(GetStatusTypeSize)()};
+#if defined(_AIX)
+  EXPECT_EQ(sz, sizeof(std::fenv_t) + sizeof(double))
+      << "expected sizeof(fenv_t)+sizeof(double)="
+      << sizeof(std::fenv_t) + sizeof(double);
+#else
+  EXPECT_EQ(sz, sizeof(std::fenv_t))
+      << "expected sizeof(fenv_t)=" << sizeof(std::fenv_t);
+#endif
+  // The size must fit in ieee_status_type.__data as integer(4) with
+  // extent _FORTRAN_RUNTIME_IEEE_FENV_T_EXTENT.
+  EXPECT_LE(sz, 32u)
+      << "GetStatusTypeSize exceeds the 32-byte ieee_status_type.__data field";
+}
diff --git a/flang/include/flang/Optimizer/Builder/LowLevelIntrinsics.h b/flang/include/flang/Optimizer/Builder/LowLevelIntrinsics.h
index de945a2ceb47d..be742fa57e7a5 100644
--- a/flang/include/flang/Optimizer/Builder/LowLevelIntrinsics.h
+++ b/flang/include/flang/Optimizer/Builder/LowLevelIntrinsics.h
@@ -30,6 +30,12 @@ mlir::func::FuncOp getLlvmGetRounding(FirOpBuilder &builder);
 /// Get the `llvm.set.rounding` intrinsic.
 mlir::func::FuncOp getLlvmSetRounding(FirOpBuilder &builder);
 
+/// Get the `llvm.ppc.readflm` intrinsic (reads FPSCR, returns f64).
+mlir::func::FuncOp getLlvmPpcReadflm(FirOpBuilder &builder);
+
+/// Get the `llvm.ppc.setflm` intrinsic (sets FPSCR from f64).
+mlir::func::FuncOp getLlvmPpcSetflm(FirOpBuilder &builder);
+
 /// Get the `llvm.init.trampoline` intrinsic.
 mlir::func::FuncOp getLlvmInitTrampoline(FirOpBuilder &builder);
 
diff --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
index f349d41888780..e70a261dab23b 100644
--- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
+++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
@@ -5210,11 +5210,81 @@ template <bool isGet, bool isModes>
 void IntrinsicLibrary::genIeeeGetOrSetModesOrStatus(
     llvm::ArrayRef<fir::ExtendedValue> args) {
   assert(args.size() == 1);
+  if constexpr (!isModes) {
+    llvm::Triple triple = fir::getTargetTriple(builder.getModule());
+    mlir::Type i32Ty = builder.getIntegerType(32);
+    mlir::Type i32PtrTy = builder.getRefType(i32Ty);
+    if (triple.isOSAIX()) {
+      // On AIX, fegetenv/fesetenv does not round-trip the FPSCR trap-enable
+      // bits [7:3].
+      //
+      // ieee_status_type.__data layout:
+      //   bytes  [0, 20) - fenv_t saved by fegetenv / restored by fesetenv
+      //   bytes [20, 28) - raw FPSCR double from mffs (trap-enable bits [7:3])
+      static constexpr int kAIXFenvTSize = 20; // sizeof(fenv_t) on AIX
+      mlir::Type i8Ty  = builder.getIntegerType(8);
+      mlir::Type f64Ty = builder.getF64Type();
+      mlir::Type idxTy = builder.getIndexType();
+      mlir::Type i8SeqTy = fir::SequenceType::get(
+          {fir::SequenceType::getUnknownExtent()}, i8Ty);
+      mlir::Type i8SeqPtrTy = builder.getRefType(i8SeqTy);
+      mlir::Type f64PtrTy   = builder.getRefType(f64Ty);
+
+      // Cast __data base pointer to !fir.ref<!fir.array<?xi8>> for GEP
+      mlir::Value base = fir::ConvertOp::create(builder, loc, i8SeqPtrTy,
+                                                fir::getBase(args[0]));
+
+      // fenv_t pointer: byte offset 0, cast to !fir.ref<i32> for fe[gs]etenv
+      mlir::Value fenvIdx = builder.createIntegerConstant(loc, idxTy, 0);
+      mlir::Value fenvGep = fir::CoordinateOp::create(
+          builder, loc, builder.getRefType(i8Ty), base, fenvIdx);
+      mlir::Value fenvPtr =
+          fir::ConvertOp::create(builder, loc, i32PtrTy, fenvGep);
+
+      // Raw FPSCR double pointer: byte offset kAIXFenvTSize (20), cast to f64
+      mlir::Value fpIdx =
+          builder.createIntegerConstant(loc, idxTy, kAIXFenvTSize);
+      mlir::Value fpGep = fir::CoordinateOp::create(
+          builder, loc, builder.getRefType(i8Ty), base, fpIdx);
+      mlir::Value fpPtr =
+          fir::ConvertOp::create(builder, loc, f64PtrTy, fpGep);
+
+      if constexpr (isGet) {
+        mlir::func::FuncOp readFlm = fir::factory::getLlvmPpcReadflm(builder);
+        // Save the floating-point environment
+        genRuntimeCall("fegetenv", i32Ty, fenvPtr);
+        // Save the raw FPSCR so that the exception-enable (trap-enable) bits
+        // [7:3] are preserved. On AIX, these bits are not restored by fesetenv.
+        mlir::Value fpscr =
+            fir::CallOp::create(builder, loc, readFlm).getResult(0);
+        // Store the raw FPSCR double at offset kAIXFenvTSize
+        fir::StoreOp::create(builder, loc, fpscr, fpPtr);
+      } else {
+        mlir::func::FuncOp setFlm  = fir::factory::getLlvmPpcSetflm(builder);
+        // Restore the floating-point environment
+        genRuntimeCall("fesetenv", i32Ty, fenvPtr);
+        // Load the raw FPSCR double from offset kAIXFenvTSize
+        mlir::Value fpscr = fir::LoadOp::create(builder, loc, fpPtr);
+        // Restore the FPSCR exception-enable (trap-enable) bits [7:3], which
+        // are not restored by fesetenv on AIX.
+        fir::CallOp::create(builder, loc, setFlm, fpscr);
+      }
+    } else {
+      mlir::Value addr =
+          fir::ConvertOp::create(builder, loc, i32PtrTy, fir::getBase(args[0]));
+      if constexpr (isGet) {
+        genRuntimeCall("fegetenv", i32Ty, addr);
+      } else {
+        genRuntimeCall("fesetenv", i32Ty, addr);
+      }
+    }
+    return;
+  }
+
+// isModes is true
 #ifndef __GLIBC_USE_IEC_60559_BFP_EXT // only use of "#include <cfenv>"
   // No definitions of fegetmode, fesetmode
-  llvm::StringRef func = isModes
-                             ? (isGet ? "ieee_get_modes" : "ieee_set_modes")
-                             : (isGet ? "ieee_get_status" : "ieee_set_status");
+  llvm::StringRef func = isGet ? "ieee_get_modes" : "ieee_set_modes";
   TODO(loc, "intrinsic module procedure: " + func);
 #else
   mlir::Type i32Ty = builder.getIntegerType(32);
@@ -5238,9 +5308,7 @@ void IntrinsicLibrary::genIeeeGetOrSetModesOrStatus(
     builder.setInsertionPointToStart(&ifOp.getThenRegion().front());
     fir::ResultOp::create(builder, loc, addr);
     builder.setInsertionPointToStart(&ifOp.getElseRegion().front());
-    mlir::Value byteSize =
-        isModes ? fir::runtime::genGetModesTypeSize(builder, loc)
-                : fir::runtime::genGetStatusTypeSize(builder, loc);
+    mlir::Value byteSize = fir::runtime::genGetModesTypeSize(builder, loc);
     byteSize = builder.createConvert(loc, builder.getIndexType(), byteSize);
     addr = fir::AllocMemOp::create(builder, loc, extractSequenceType(heapTy),
                                    /*typeparams=*/mlir::ValueRange(), byteSize);
@@ -5255,8 +5323,7 @@ void IntrinsicLibrary::genIeeeGetOrSetModesOrStatus(
     // Place floating point environment data in __data storage.
     addr = fir::ConvertOp::create(builder, loc, ptrTy, getBase(args[0]));
   }
-  llvm::StringRef func = isModes ? (isGet ? "fegetmode" : "fesetmode")
-                                 : (isGet ? "fegetenv" : "fesetenv");
+  llvm::StringRef func = isGet ? "fegetmode" : "fesetmode";
   genRuntimeCall(func, i32Ty, addr);
 #endif
 }
diff --git a/flang/lib/Optimizer/Builder/LowLevelIntrinsics.cpp b/flang/lib/Optimizer/Builder/LowLevelIntrinsics.cpp
index 8f8ceef2480a6..2a081588cebdb 100644
--- a/flang/lib/Optimizer/Builder/LowLevelIntrinsics.cpp
+++ b/flang/lib/Optimizer/Builder/LowLevelIntrinsics.cpp
@@ -37,6 +37,23 @@ fir::factory::getLlvmSetRounding(fir::FirOpBuilder &builder) {
                                 funcTy);
 }
 
+mlir::func::FuncOp
+fir::factory::getLlvmPpcReadflm(fir::FirOpBuilder &builder) {
+  auto f64Ty = builder.getF64Type();
+  auto funcTy = mlir::FunctionType::get(builder.getContext(), {}, {f64Ty});
+  return builder.createFunction(builder.getUnknownLoc(), "llvm.ppc.readflm",
+                                funcTy);
+}
+
+mlir::func::FuncOp
+fir::factory::getLlvmPpcSetflm(fir::FirOpBuilder &builder) {
+  auto f64Ty = builder.getF64Type();
+  auto funcTy =
+      mlir::FunctionType::get(builder.getContext(), {f64Ty}, {f64Ty});
+  return builder.createFunction(builder.getUnknownLoc(), "llvm.ppc.setflm",
+                                funcTy);
+}
+
 mlir::func::FuncOp
 fir::factory::getLlvmInitTrampoline(fir::FirOpBuilder &builder) {
   auto ptrTy = builder.getRefType(builder.getIntegerType(8));
diff --git a/flang/test/Lower/Intrinsics/ieee_status.f90 b/flang/test/Lower/Intrinsics/ieee_status.f90
new file mode 100644
index 0000000000000..058d1f30f5ce7
--- /dev/null
+++ b/flang/test/Lower/Intrinsics/ieee_status.f90
@@ -0,0 +1,43 @@
+! Tests HLFIR code generation for ieee_get_status / ieee_set_status on PPC targets.
+!
+! REQUIRES: powerpc-registered-target
+! RUN: %flang_fc1 -triple powerpc64-ibm-aix -emit-hlfir -o - %s | FileCheck %s --check-prefix=CHECK-AIX
+! RUN: %flang_fc1 -triple powerpc64le-unknown-linux-gnu -emit-hlfir -o - %s | FileCheck %s --check-prefix=CHECK-LNX
+
+program test
+  use ieee_arithmetic
+  type(ieee_status_type) :: stat
+! LABEL:   func.func @_QQmain
+
+  call ieee_get_status(stat)
+
+! CHECK-AIX: %[[UUDAT:.*]] = fir.convert {{.*}} : ({{.*}}) -> !fir.ref<!fir.array<?xi8>>
+! CHECK-AIX: %c0 = arith.constant 0 : index
+! CHECK-AIX: %[[UUDAT0:.*]] = fir.coordinate_of %[[UUDAT]], %c0 : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+! CHECK-AIX: %[[FENV:.*]] = fir.convert %[[UUDAT0]] : (!fir.ref<i8>) -> !fir.ref<i32>
+! CHECK-AIX: %c20 = arith.constant 20 : index
+! CHECK-AIX: %[[UUDAT1:.*]] = fir.coordinate_of %[[UUDAT]], %c20 : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+! CHECK-AIX: %[[UUDAT1F:.*]] = fir.convert %[[UUDAT1]] : (!fir.ref<i8>) -> !fir.ref<f64>
+! CHECK-AIX: {{.*}} = fir.call @fegetenv(%[[FENV]]) {{.*}} : (!fir.ref<i32>) -> i32
+! CHECK-AIX: %[[FPS:.*]] = fir.call @llvm.ppc.readflm() {{.*}} : () -> f64
+! CHECK-AIX: fir.store %[[FPS]] to %[[UUDAT1F]] : !fir.ref<f64>
+
+! CHECK-LNX: %[[UUDAT:.*]] = fir.convert {{.*}} : ({{.*}}) -> !fir.ref<i32>
+! CHECK-LNX: {{.*}} = fir.call @fegetenv(%[[UUDAT]]) {{.*}} : (!fir.ref<i32>) -> i32
+
+  call ieee_set_status(stat)
+
+! CHECK-AIX: %[[UUDAT:.*]] = fir.convert {{.*}} : ({{.*}}) -> !fir.ref<!fir.array<?xi8>>
+! CHECK-AIX: %c0_0 = arith.constant 0 : index
+! CHECK-AIX: %[[UUDAT0:.*]] = fir.coordinate_of %[[UUDAT]], %c0_0 : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+! CHECK-AIX: %[[FENV:.*]] = fir.convert %[[UUDAT0]] : (!fir.ref<i8>) -> !fir.ref<i32>
+! CHECK-AIX: %c20_1 = arith.constant 20 : index
+! CHECK-AIX: %[[UUDAT1:.*]] = fir.coordinate_of %[[UUDAT]], %c20_1 : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+! CHECK-AIX: %[[UUDAT1F:.*]] = fir.convert %[[UUDAT1]] : (!fir.ref<i8>) -> !fir.ref<f64>
+! CHECK-AIX: {{.*}} = fir.call @fesetenv(%[[FENV]]) {{.*}} : (!fir.ref<i32>) -> i32
+! CHECK-AIX: %[[FPS:.*]] = fir.load %[[UUDAT1F]] : !fir.ref<f64>
+! CHECK-AIX: fir.call @llvm.ppc.setflm(%[[FPS]]) {{.*}} : (f64) -> f64
+
+! CHECK-LNX: %[[UUDAT:.*]] = fir.convert {{.*}} : ({{.*}}) -> !fir.ref<i32>
+! CHECK-LNX: {{.*}} = fir.call @fesetenv(%[[UUDAT]]) {{.*}} : (!fir.ref<i32>) -> i32
+end program

>From a030ef37a0e52d40c3cd52c75b969320291a686d Mon Sep 17 00:00:00 2001
From: Kelvin Li <kli at ca.ibm.com>
Date: Tue, 11 Aug 2026 13:40:28 -0400
Subject: [PATCH 2/5] formatting

---
 flang/lib/Optimizer/Builder/IntrinsicCall.cpp      | 13 ++++++-------
 flang/lib/Optimizer/Builder/LowLevelIntrinsics.cpp |  6 ++----
 2 files changed, 8 insertions(+), 11 deletions(-)

diff --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
index e70a261dab23b..c6f0d72625c0a 100644
--- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
+++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
@@ -5222,13 +5222,13 @@ void IntrinsicLibrary::genIeeeGetOrSetModesOrStatus(
       //   bytes  [0, 20) - fenv_t saved by fegetenv / restored by fesetenv
       //   bytes [20, 28) - raw FPSCR double from mffs (trap-enable bits [7:3])
       static constexpr int kAIXFenvTSize = 20; // sizeof(fenv_t) on AIX
-      mlir::Type i8Ty  = builder.getIntegerType(8);
+      mlir::Type i8Ty = builder.getIntegerType(8);
       mlir::Type f64Ty = builder.getF64Type();
       mlir::Type idxTy = builder.getIndexType();
-      mlir::Type i8SeqTy = fir::SequenceType::get(
-          {fir::SequenceType::getUnknownExtent()}, i8Ty);
+      mlir::Type i8SeqTy =
+          fir::SequenceType::get({fir::SequenceType::getUnknownExtent()}, i8Ty);
       mlir::Type i8SeqPtrTy = builder.getRefType(i8SeqTy);
-      mlir::Type f64PtrTy   = builder.getRefType(f64Ty);
+      mlir::Type f64PtrTy = builder.getRefType(f64Ty);
 
       // Cast __data base pointer to !fir.ref<!fir.array<?xi8>> for GEP
       mlir::Value base = fir::ConvertOp::create(builder, loc, i8SeqPtrTy,
@@ -5246,8 +5246,7 @@ void IntrinsicLibrary::genIeeeGetOrSetModesOrStatus(
           builder.createIntegerConstant(loc, idxTy, kAIXFenvTSize);
       mlir::Value fpGep = fir::CoordinateOp::create(
           builder, loc, builder.getRefType(i8Ty), base, fpIdx);
-      mlir::Value fpPtr =
-          fir::ConvertOp::create(builder, loc, f64PtrTy, fpGep);
+      mlir::Value fpPtr = fir::ConvertOp::create(builder, loc, f64PtrTy, fpGep);
 
       if constexpr (isGet) {
         mlir::func::FuncOp readFlm = fir::factory::getLlvmPpcReadflm(builder);
@@ -5260,7 +5259,7 @@ void IntrinsicLibrary::genIeeeGetOrSetModesOrStatus(
         // Store the raw FPSCR double at offset kAIXFenvTSize
         fir::StoreOp::create(builder, loc, fpscr, fpPtr);
       } else {
-        mlir::func::FuncOp setFlm  = fir::factory::getLlvmPpcSetflm(builder);
+        mlir::func::FuncOp setFlm = fir::factory::getLlvmPpcSetflm(builder);
         // Restore the floating-point environment
         genRuntimeCall("fesetenv", i32Ty, fenvPtr);
         // Load the raw FPSCR double from offset kAIXFenvTSize
diff --git a/flang/lib/Optimizer/Builder/LowLevelIntrinsics.cpp b/flang/lib/Optimizer/Builder/LowLevelIntrinsics.cpp
index 2a081588cebdb..a8f8269faa539 100644
--- a/flang/lib/Optimizer/Builder/LowLevelIntrinsics.cpp
+++ b/flang/lib/Optimizer/Builder/LowLevelIntrinsics.cpp
@@ -37,16 +37,14 @@ fir::factory::getLlvmSetRounding(fir::FirOpBuilder &builder) {
                                 funcTy);
 }
 
-mlir::func::FuncOp
-fir::factory::getLlvmPpcReadflm(fir::FirOpBuilder &builder) {
+mlir::func::FuncOp fir::factory::getLlvmPpcReadflm(fir::FirOpBuilder &builder) {
   auto f64Ty = builder.getF64Type();
   auto funcTy = mlir::FunctionType::get(builder.getContext(), {}, {f64Ty});
   return builder.createFunction(builder.getUnknownLoc(), "llvm.ppc.readflm",
                                 funcTy);
 }
 
-mlir::func::FuncOp
-fir::factory::getLlvmPpcSetflm(fir::FirOpBuilder &builder) {
+mlir::func::FuncOp fir::factory::getLlvmPpcSetflm(fir::FirOpBuilder &builder) {
   auto f64Ty = builder.getF64Type();
   auto funcTy =
       mlir::FunctionType::get(builder.getContext(), {f64Ty}, {f64Ty});

>From 6197aa3b9c4232f56d2d58d93e86fab1c9948210 Mon Sep 17 00:00:00 2001
From: Kelvin Li <kli at ca.ibm.com>
Date: Tue, 11 Aug 2026 14:17:46 -0400
Subject: [PATCH 3/5] fix format

---
 flang/lib/Optimizer/Builder/LowLevelIntrinsics.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/flang/lib/Optimizer/Builder/LowLevelIntrinsics.cpp b/flang/lib/Optimizer/Builder/LowLevelIntrinsics.cpp
index a8f8269faa539..282a66547f595 100644
--- a/flang/lib/Optimizer/Builder/LowLevelIntrinsics.cpp
+++ b/flang/lib/Optimizer/Builder/LowLevelIntrinsics.cpp
@@ -46,8 +46,7 @@ mlir::func::FuncOp fir::factory::getLlvmPpcReadflm(fir::FirOpBuilder &builder) {
 
 mlir::func::FuncOp fir::factory::getLlvmPpcSetflm(fir::FirOpBuilder &builder) {
   auto f64Ty = builder.getF64Type();
-  auto funcTy =
-      mlir::FunctionType::get(builder.getContext(), {f64Ty}, {f64Ty});
+  auto funcTy = mlir::FunctionType::get(builder.getContext(), {f64Ty}, {f64Ty});
   return builder.createFunction(builder.getUnknownLoc(), "llvm.ppc.setflm",
                                 funcTy);
 }

>From 98a48af785ee40a73b45d8e498d1a7d8bde8c266 Mon Sep 17 00:00:00 2001
From: Kelvin Li <kli at ca.ibm.com>
Date: Thu, 20 Aug 2026 21:44:32 -0400
Subject: [PATCH 4/5] address review comments

---
 flang-rt/unittests/Runtime/Exceptions.cpp     | 10 +++---
 flang/lib/Optimizer/Builder/IntrinsicCall.cpp | 34 ++++++++++---------
 flang/test/Lower/Intrinsics/ieee_status.f90   | 22 +++++++-----
 3 files changed, 37 insertions(+), 29 deletions(-)

diff --git a/flang-rt/unittests/Runtime/Exceptions.cpp b/flang-rt/unittests/Runtime/Exceptions.cpp
index e2f247c1cb62d..22b1288c4b5a2 100644
--- a/flang-rt/unittests/Runtime/Exceptions.cpp
+++ b/flang-rt/unittests/Runtime/Exceptions.cpp
@@ -146,15 +146,17 @@ TEST(Exceptions, ClearOneLeavesOthersAlone) {
 TEST(Exceptions, GetStatusTypeSizeMatchesPlatformLayout) {
   const std::size_t sz{RTNAME(GetStatusTypeSize)()};
 #if defined(_AIX)
+  // The size must match the value (20) hardocded in IntrinsicCall.cpp
+  EXPECT_EQ(sizeof(std::fenv_t), 20u) << "expected size(fenv_t)=20";
   EXPECT_EQ(sz, sizeof(std::fenv_t) + sizeof(double))
       << "expected sizeof(fenv_t)+sizeof(double)="
       << sizeof(std::fenv_t) + sizeof(double);
-#else
-  EXPECT_EQ(sz, sizeof(std::fenv_t))
-      << "expected sizeof(fenv_t)=" << sizeof(std::fenv_t);
-#endif
   // The size must fit in ieee_status_type.__data as integer(4) with
   // extent _FORTRAN_RUNTIME_IEEE_FENV_T_EXTENT.
   EXPECT_LE(sz, 32u)
       << "GetStatusTypeSize exceeds the 32-byte ieee_status_type.__data field";
+#else
+  EXPECT_EQ(sz, sizeof(std::fenv_t))
+      << "expected sizeof(fenv_t)=" << sizeof(std::fenv_t);
+#endif
 }
diff --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
index c6f0d72625c0a..0b8ca9facf1dd 100644
--- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
+++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
@@ -5211,9 +5211,9 @@ void IntrinsicLibrary::genIeeeGetOrSetModesOrStatus(
     llvm::ArrayRef<fir::ExtendedValue> args) {
   assert(args.size() == 1);
   if constexpr (!isModes) {
-    llvm::Triple triple = fir::getTargetTriple(builder.getModule());
     mlir::Type i32Ty = builder.getIntegerType(32);
     mlir::Type i32PtrTy = builder.getRefType(i32Ty);
+    llvm::Triple triple = fir::getTargetTriple(builder.getModule());
     if (triple.isOSAIX()) {
       // On AIX, fegetenv/fesetenv does not round-trip the FPSCR trap-enable
       // bits [7:3].
@@ -5223,12 +5223,12 @@ void IntrinsicLibrary::genIeeeGetOrSetModesOrStatus(
       //   bytes [20, 28) - raw FPSCR double from mffs (trap-enable bits [7:3])
       static constexpr int kAIXFenvTSize = 20; // sizeof(fenv_t) on AIX
       mlir::Type i8Ty = builder.getIntegerType(8);
-      mlir::Type f64Ty = builder.getF64Type();
       mlir::Type idxTy = builder.getIndexType();
+      mlir::Type f64Ty = builder.getF64Type();
+      mlir::Type f64PtrTy = builder.getRefType(f64Ty);
       mlir::Type i8SeqTy =
           fir::SequenceType::get({fir::SequenceType::getUnknownExtent()}, i8Ty);
       mlir::Type i8SeqPtrTy = builder.getRefType(i8SeqTy);
-      mlir::Type f64PtrTy = builder.getRefType(f64Ty);
 
       // Cast __data base pointer to !fir.ref<!fir.array<?xi8>> for GEP
       mlir::Value base = fir::ConvertOp::create(builder, loc, i8SeqPtrTy,
@@ -5268,22 +5268,21 @@ void IntrinsicLibrary::genIeeeGetOrSetModesOrStatus(
         // are not restored by fesetenv on AIX.
         fir::CallOp::create(builder, loc, setFlm, fpscr);
       }
-    } else {
-      mlir::Value addr =
-          fir::ConvertOp::create(builder, loc, i32PtrTy, fir::getBase(args[0]));
-      if constexpr (isGet) {
-        genRuntimeCall("fegetenv", i32Ty, addr);
-      } else {
-        genRuntimeCall("fesetenv", i32Ty, addr);
-      }
+      return;
+    } else if (triple.isPPC()) {
+      // Non-AIX PPC (e.g. powerpc64le)
+      mlir::Value addr = fir::ConvertOp::create(builder, loc, i32PtrTy,
+                                                fir::getBase(args[0]));
+      genRuntimeCall(isGet ? "fegetenv" : "fesetenv", i32Ty, addr);
+      return;
     }
-    return;
   }
 
-// isModes is true
 #ifndef __GLIBC_USE_IEC_60559_BFP_EXT // only use of "#include <cfenv>"
   // No definitions of fegetmode, fesetmode
-  llvm::StringRef func = isGet ? "ieee_get_modes" : "ieee_set_modes";
+  llvm::StringRef func = isModes
+                             ? (isGet ? "ieee_get_modes" : "ieee_set_modes")
+                             : (isGet ? "ieee_get_status" : "ieee_set_status");
   TODO(loc, "intrinsic module procedure: " + func);
 #else
   mlir::Type i32Ty = builder.getIntegerType(32);
@@ -5307,7 +5306,9 @@ void IntrinsicLibrary::genIeeeGetOrSetModesOrStatus(
     builder.setInsertionPointToStart(&ifOp.getThenRegion().front());
     fir::ResultOp::create(builder, loc, addr);
     builder.setInsertionPointToStart(&ifOp.getElseRegion().front());
-    mlir::Value byteSize = fir::runtime::genGetModesTypeSize(builder, loc);
+    mlir::Value byteSize =
+        isModes ? fir::runtime::genGetModesTypeSize(builder, loc)
+                : fir::runtime::genGetStatusTypeSize(builder, loc);
     byteSize = builder.createConvert(loc, builder.getIndexType(), byteSize);
     addr = fir::AllocMemOp::create(builder, loc, extractSequenceType(heapTy),
                                    /*typeparams=*/mlir::ValueRange(), byteSize);
@@ -5322,7 +5323,8 @@ void IntrinsicLibrary::genIeeeGetOrSetModesOrStatus(
     // Place floating point environment data in __data storage.
     addr = fir::ConvertOp::create(builder, loc, ptrTy, getBase(args[0]));
   }
-  llvm::StringRef func = isGet ? "fegetmode" : "fesetmode";
+  llvm::StringRef func = isModes ? (isGet ? "fegetmode" : "fesetmode")
+                                 : (isGet ? "fegetenv" : "fesetenv");
   genRuntimeCall(func, i32Ty, addr);
 #endif
 }
diff --git a/flang/test/Lower/Intrinsics/ieee_status.f90 b/flang/test/Lower/Intrinsics/ieee_status.f90
index 058d1f30f5ce7..f92952dddee3c 100644
--- a/flang/test/Lower/Intrinsics/ieee_status.f90
+++ b/flang/test/Lower/Intrinsics/ieee_status.f90
@@ -7,16 +7,18 @@
 program test
   use ieee_arithmetic
   type(ieee_status_type) :: stat
-! LABEL:   func.func @_QQmain
+
+! CHECK-AIX-LABEL: func.func @_QQmain
+! CHECK-LNX-LABEL: func.func @_QQmain
 
   call ieee_get_status(stat)
 
 ! CHECK-AIX: %[[UUDAT:.*]] = fir.convert {{.*}} : ({{.*}}) -> !fir.ref<!fir.array<?xi8>>
-! CHECK-AIX: %c0 = arith.constant 0 : index
-! CHECK-AIX: %[[UUDAT0:.*]] = fir.coordinate_of %[[UUDAT]], %c0 : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+! CHECK-AIX: %[[C1:.*]] = arith.constant 0 : index
+! CHECK-AIX: %[[UUDAT0:.*]] = fir.coordinate_of %[[UUDAT]], %[[C1]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
 ! CHECK-AIX: %[[FENV:.*]] = fir.convert %[[UUDAT0]] : (!fir.ref<i8>) -> !fir.ref<i32>
-! CHECK-AIX: %c20 = arith.constant 20 : index
-! CHECK-AIX: %[[UUDAT1:.*]] = fir.coordinate_of %[[UUDAT]], %c20 : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+! CHECK-AIX: %[[C2:.*]] = arith.constant 20 : index
+! CHECK-AIX: %[[UUDAT1:.*]] = fir.coordinate_of %[[UUDAT]], %[[C2]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
 ! CHECK-AIX: %[[UUDAT1F:.*]] = fir.convert %[[UUDAT1]] : (!fir.ref<i8>) -> !fir.ref<f64>
 ! CHECK-AIX: {{.*}} = fir.call @fegetenv(%[[FENV]]) {{.*}} : (!fir.ref<i32>) -> i32
 ! CHECK-AIX: %[[FPS:.*]] = fir.call @llvm.ppc.readflm() {{.*}} : () -> f64
@@ -24,15 +26,16 @@ program test
 
 ! CHECK-LNX: %[[UUDAT:.*]] = fir.convert {{.*}} : ({{.*}}) -> !fir.ref<i32>
 ! CHECK-LNX: {{.*}} = fir.call @fegetenv(%[[UUDAT]]) {{.*}} : (!fir.ref<i32>) -> i32
+! CHECK-LNX-NOT: @llvm.ppc.readflm()
 
   call ieee_set_status(stat)
 
 ! CHECK-AIX: %[[UUDAT:.*]] = fir.convert {{.*}} : ({{.*}}) -> !fir.ref<!fir.array<?xi8>>
-! CHECK-AIX: %c0_0 = arith.constant 0 : index
-! CHECK-AIX: %[[UUDAT0:.*]] = fir.coordinate_of %[[UUDAT]], %c0_0 : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+! CHECK-AIX: %[[C3:.*]] = arith.constant 0 : index
+! CHECK-AIX: %[[UUDAT0:.*]] = fir.coordinate_of %[[UUDAT]], %[[C3]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
 ! CHECK-AIX: %[[FENV:.*]] = fir.convert %[[UUDAT0]] : (!fir.ref<i8>) -> !fir.ref<i32>
-! CHECK-AIX: %c20_1 = arith.constant 20 : index
-! CHECK-AIX: %[[UUDAT1:.*]] = fir.coordinate_of %[[UUDAT]], %c20_1 : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+! CHECK-AIX: %[[C4:.*]] = arith.constant 20 : index
+! CHECK-AIX: %[[UUDAT1:.*]] = fir.coordinate_of %[[UUDAT]], %[[C4]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
 ! CHECK-AIX: %[[UUDAT1F:.*]] = fir.convert %[[UUDAT1]] : (!fir.ref<i8>) -> !fir.ref<f64>
 ! CHECK-AIX: {{.*}} = fir.call @fesetenv(%[[FENV]]) {{.*}} : (!fir.ref<i32>) -> i32
 ! CHECK-AIX: %[[FPS:.*]] = fir.load %[[UUDAT1F]] : !fir.ref<f64>
@@ -40,4 +43,5 @@ program test
 
 ! CHECK-LNX: %[[UUDAT:.*]] = fir.convert {{.*}} : ({{.*}}) -> !fir.ref<i32>
 ! CHECK-LNX: {{.*}} = fir.call @fesetenv(%[[UUDAT]]) {{.*}} : (!fir.ref<i32>) -> i32
+! CHECK-LNX-NOT: @llvm.ppc.setflm()
 end program

>From 6e24a8beee480f79ca5e318e8af8c56aa10f976a Mon Sep 17 00:00:00 2001
From: Kelvin Li <kli at ca.ibm.com>
Date: Thu, 20 Aug 2026 22:03:33 -0400
Subject: [PATCH 5/5] fix format

---
 flang/lib/Optimizer/Builder/IntrinsicCall.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
index 0b8ca9facf1dd..4abc241ede078 100644
--- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
+++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
@@ -5271,8 +5271,8 @@ void IntrinsicLibrary::genIeeeGetOrSetModesOrStatus(
       return;
     } else if (triple.isPPC()) {
       // Non-AIX PPC (e.g. powerpc64le)
-      mlir::Value addr = fir::ConvertOp::create(builder, loc, i32PtrTy,
-                                                fir::getBase(args[0]));
+      mlir::Value addr =
+          fir::ConvertOp::create(builder, loc, i32PtrTy, fir::getBase(args[0]));
       genRuntimeCall(isGet ? "fegetenv" : "fesetenv", i32Ty, addr);
       return;
     }



More information about the flang-commits mailing list