[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