[flang-commits] [flang] [llvm] [flang][PPC] Implement ieee_set_status and ieee_get_status for AIX (PR #215618)
Eugene Epshteyn via flang-commits
flang-commits at lists.llvm.org
Mon Aug 17 20:55:58 PDT 2026
================
@@ -5210,11 +5210,80 @@ 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);
+ }
+ }
----------------
eugeneepshteyn wrote:
(This comment was definitely generated by AI.)
This `else` branch routes every non-AIX target through a direct `fegetenv`/`fesetenv` on the 32-byte `__data` component, which silently drops two things the shared path below deliberately provides for status:
1. The SPARC runtime-sized heap mechanism added by #121949 and documented as a design contract in `flang/include/flang/Runtime/magic-numbers.h`: on Solaris/SPARC, `fenv_t` is far larger than 32 bytes (an array of exception-handler entries plus the FSR), so `fegetenv` now writes past the end of `__data`, silently corrupting the adjacent `__allocatable_data` descriptor and beyond. Compile-only reproducer on an x86 host with the Sparc target registered:
```
flang -fc1 -triple sparcv9-sun-solaris2.11 -emit-llvm status.f90 -o -
# before this PR: calls _FortranAGetStatusTypeSize + malloc
# after this PR: fegetenv straight into the 32-byte global
```
Note that the *modes* path on the same triple still heap-allocates after this PR, so the two sibling intrinsics now disagree about the platform's contract.
2. The `__GLIBC_USE_IEC_60559_BFP_EXT` guard: on non-glibc-hosted builds, `ieee_get_status`/`ieee_set_status` previously produced a clean TODO error; now they lower unconditionally.
Suggested fix shape: make the new code an AIX-only early branch — `if (triple.isOSAIX()) { ...the new fegetenv/readflm code...; return; }` — and delete this non-AIX `else`, letting non-AIX status fall through to the pre-existing shared modes/status lowering (i.e. restore the `isModes ? ... : ...` ternaries below). That keeps the AIX fix fully intact and restores the SPARC heap path, the non-glibc TODO, and the compiler-side caller of `GetStatusTypeSize`.
https://github.com/llvm/llvm-project/pull/215618
More information about the flang-commits
mailing list