Skip to content

Commit cfc1942

Browse files
committed
[flang] Modifications to ieee_support_halting
The F23 standard requires that a call to intrinsic module procedure ieee_support_halting be foldable to a constant at compile time in some contexts. See for example F23 Clause 10.1.11 [Specification expression] list item (13), Clause 1.1.12 [Constant expression] list item (11), and references to specification and constant expressions elsewhere, such as constraints C1012, C853, and C704. Some Arm processors allow a user to control processor behavior when an arithmetic exception is signaled, and some Arm processors do not have this capability. An Arm executable will run on either type of processor, so it is effectively unknown at compile time whether or not this support will be available at runtime. This in conflict with the standard requirement. This patch addresses this conflict by implementing ieee_support_halting calls on Arm processors to check if this capability is present at runtime. A call to ieee_support_halting in a constant context, such as in the specification part of a program unit, will generate a compile time "cannot be computed as a constant value" error. The expectation is that such calls are unlikely to appear in production code. Code generation for other processors will continue to generate a compile time constant result for ieee_support_halting calls.
1 parent b05071d commit cfc1942

File tree

12 files changed

+113
-23
lines changed

12 files changed

+113
-23
lines changed

flang/docs/Extensions.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,18 @@ end
141141
This interpretation has usability advantages and is what six other
142142
Fortran compilers do, but is not conforming now that J3 approved an
143143
"interp" in June 2024 to the contrary.
144+
* Arm has processors that allow a user to control what happens when an
145+
arithmetic exception is signaled, as well as processors that do not
146+
have this capability. An Arm executable will run on either type of
147+
processor, so it is effectively unknown at compile time whether or
148+
not this support will be available at runtime. The standard requires
149+
that a call to intrinsic module procedure `IEEE_SUPPORT_HALTING` with
150+
a constant argument has a compile time constant result in `constant
151+
expression` and `specification expression` contexts. In compilations
152+
where this information is not known at compile time, f18 generates code
153+
to determine the absence or presence of this capability at runtime.
154+
A call to `IEEE_SUPPORT_HALTING` in contexts that the standard requires
155+
to be constant will generate a compilation error.
144156

145157
## Extensions, deletions, and legacy features supported by default
146158

flang/include/flang/Evaluate/target.h

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,13 @@ class TargetCharacteristics {
3636
bool isBigEndian() const { return isBigEndian_; }
3737
void set_isBigEndian(bool isBig = true);
3838

39+
bool haltingSupportIsUnknownAtCompileTime() const {
40+
return haltingSupportIsUnknownAtCompileTime_;
41+
}
42+
void set_haltingSupportIsUnknownAtCompileTime(bool yes = true) {
43+
haltingSupportIsUnknownAtCompileTime_ = yes;
44+
}
45+
3946
bool areSubnormalsFlushedToZero() const {
4047
return areSubnormalsFlushedToZero_;
4148
}
@@ -50,6 +57,14 @@ class TargetCharacteristics {
5057
Rounding roundingMode() const { return roundingMode_; }
5158
void set_roundingMode(Rounding);
5259

60+
void set_ieeeFeature(IeeeFeature ieeeFeature, bool yes = true) {
61+
if (yes) {
62+
ieeeFeatures_.set(ieeeFeature);
63+
} else {
64+
ieeeFeatures_.reset(ieeeFeature);
65+
}
66+
}
67+
5368
std::size_t procedurePointerByteSize() const {
5469
return procedurePointerByteSize_;
5570
}
@@ -112,6 +127,7 @@ class TargetCharacteristics {
112127
bool isBigEndian_{false};
113128
bool isPPC_{false};
114129
bool isOSWindows_{false};
130+
bool haltingSupportIsUnknownAtCompileTime_{false};
115131
bool areSubnormalsFlushedToZero_{false};
116132
bool hasSubnormalFlushingControl_[maxKind + 1]{};
117133
Rounding roundingMode_{defaultRounding};
@@ -123,10 +139,9 @@ class TargetCharacteristics {
123139
std::string compilerOptionsString_;
124140
std::string compilerVersionString_;
125141
IeeeFeatures ieeeFeatures_{IeeeFeature::Denormal, IeeeFeature::Divide,
126-
IeeeFeature::Flags, IeeeFeature::Halting, IeeeFeature::Inf,
127-
IeeeFeature::Io, IeeeFeature::NaN, IeeeFeature::Rounding,
128-
IeeeFeature::Sqrt, IeeeFeature::Standard, IeeeFeature::Subnormal,
129-
IeeeFeature::UnderflowControl};
142+
IeeeFeature::Flags, IeeeFeature::Inf, IeeeFeature::Io, IeeeFeature::NaN,
143+
IeeeFeature::Rounding, IeeeFeature::Sqrt, IeeeFeature::Standard,
144+
IeeeFeature::Subnormal, IeeeFeature::UnderflowControl};
130145
};
131146

132147
} // namespace Fortran::evaluate

flang/include/flang/Optimizer/Builder/IntrinsicCall.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -296,9 +296,10 @@ struct IntrinsicLibrary {
296296
mlir::Value genIeeeSignalingCompare(mlir::Type resultType,
297297
llvm::ArrayRef<mlir::Value>);
298298
mlir::Value genIeeeSignbit(mlir::Type, llvm::ArrayRef<mlir::Value>);
299-
fir::ExtendedValue
300-
genIeeeSupportFlagOrHalting(mlir::Type,
301-
llvm::ArrayRef<fir::ExtendedValue>);
299+
fir::ExtendedValue genIeeeSupportFlag(mlir::Type,
300+
llvm::ArrayRef<fir::ExtendedValue>);
301+
fir::ExtendedValue genIeeeSupportHalting(mlir::Type,
302+
llvm::ArrayRef<fir::ExtendedValue>);
302303
mlir::Value genIeeeSupportRounding(mlir::Type, llvm::ArrayRef<mlir::Value>);
303304
template <mlir::arith::CmpIPredicate pred>
304305
mlir::Value genIeeeTypeCompare(mlir::Type, llvm::ArrayRef<mlir::Value>);

flang/include/flang/Optimizer/Builder/Runtime/Exceptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ namespace fir::runtime {
2626
mlir::Value genMapExcept(fir::FirOpBuilder &builder, mlir::Location loc,
2727
mlir::Value excepts);
2828

29+
mlir::Value genSupportHalting(fir::FirOpBuilder &builder, mlir::Location loc,
30+
mlir::Value excepts);
31+
2932
mlir::Value genGetUnderflowMode(fir::FirOpBuilder &builder, mlir::Location loc);
3033
void genSetUnderflowMode(fir::FirOpBuilder &builder, mlir::Location loc,
3134
mlir::Value bit);

flang/include/flang/Runtime/exceptions.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ extern "C" {
2424
// This mapping is done at runtime to support cross compilation.
2525
std::uint32_t RTNAME(MapException)(std::uint32_t excepts);
2626

27+
// Check if the processor has the ability to control whether to halt
28+
// or continue exeuction when a given exception is raised.
29+
bool RTNAME(SupportHalting)(uint32_t except);
30+
2731
// Get and set the ieee underflow mode if supported; otherwise nops.
2832
bool RTNAME(GetUnderflowMode)(void);
2933
void RTNAME(SetUnderflowMode)(bool flag);

flang/include/flang/Tools/TargetSetup.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ namespace Fortran::tools {
3434
targetCharacteristics.set_hasSubnormalFlushingControl(/*kind=*/4);
3535
targetCharacteristics.set_hasSubnormalFlushingControl(/*kind=*/8);
3636
}
37+
if (targetTriple.isARM() || targetTriple.isAArch64()) {
38+
targetCharacteristics.set_haltingSupportIsUnknownAtCompileTime();
39+
targetCharacteristics.set_ieeeFeature(
40+
evaluate::IeeeFeature::Halting, false);
41+
} else {
42+
targetCharacteristics.set_ieeeFeature(evaluate::IeeeFeature::Halting);
43+
}
3744

3845
// Figure out if we can support F128: see
3946
// flang/runtime/Float128Math/math-entries.h

flang/lib/Evaluate/fold-logical.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -881,8 +881,11 @@ Expr<Type<TypeCategory::Logical, KIND>> FoldIntrinsicFunction(
881881
return Expr<T>{context.targetCharacteristics().ieeeFeatures().test(
882882
IeeeFeature::Flags)};
883883
} else if (name == "__builtin_ieee_support_halting") {
884-
return Expr<T>{context.targetCharacteristics().ieeeFeatures().test(
885-
IeeeFeature::Halting)};
884+
if (!context.targetCharacteristics()
885+
.haltingSupportIsUnknownAtCompileTime()) {
886+
return Expr<T>{context.targetCharacteristics().ieeeFeatures().test(
887+
IeeeFeature::Halting)};
888+
}
886889
} else if (name == "__builtin_ieee_support_inf") {
887890
return Expr<T>{
888891
context.targetCharacteristics().ieeeFeatures().test(IeeeFeature::Inf)};

flang/lib/Optimizer/Builder/IntrinsicCall.cpp

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -389,10 +389,10 @@ static constexpr IntrinsicHandler handlers[]{
389389
&I::genIeeeSignalingCompare<mlir::arith::CmpFPredicate::UNE>},
390390
{"ieee_signbit", &I::genIeeeSignbit},
391391
{"ieee_support_flag",
392-
&I::genIeeeSupportFlagOrHalting,
392+
&I::genIeeeSupportFlag,
393393
{{{"flag", asValue}, {"x", asInquired, handleDynamicOptional}}},
394394
/*isElemental=*/false},
395-
{"ieee_support_halting", &I::genIeeeSupportFlagOrHalting},
395+
{"ieee_support_halting", &I::genIeeeSupportHalting},
396396
{"ieee_support_rounding", &I::genIeeeSupportRounding},
397397
{"ieee_unordered", &I::genIeeeUnordered},
398398
{"ieee_value", &I::genIeeeValue},
@@ -5259,14 +5259,14 @@ mlir::Value IntrinsicLibrary::genIeeeSignbit(mlir::Type resultType,
52595259
return builder.createConvert(loc, resultType, sign);
52605260
}
52615261

5262-
// IEEE_SUPPORT_FLAG, IEEE_SUPPORT_HALTING
5263-
fir::ExtendedValue IntrinsicLibrary::genIeeeSupportFlagOrHalting(
5264-
mlir::Type resultType, llvm::ArrayRef<fir::ExtendedValue> args) {
5265-
// Check if a floating point exception or halting mode FLAG is supported.
5266-
// An IEEE_SUPPORT_FLAG flag is supported either for all type kinds or none.
5267-
// An optional kind argument X is therefore ignored.
5268-
// Standard flags are all supported.
5269-
// The nonstandard DENORM extension is not supported. (At least for now.)
5262+
// IEEE_SUPPORT_FLAG
5263+
fir::ExtendedValue
5264+
IntrinsicLibrary::genIeeeSupportFlag(mlir::Type resultType,
5265+
llvm::ArrayRef<fir::ExtendedValue> args) {
5266+
// Check if a floating point exception flag is supported. A flag is
5267+
// supported either for all type kinds or none. An optional kind argument X
5268+
// is therefore ignored. Standard flags are all supported. The nonstandard
5269+
// DENORM extension is not supported, at least for now.
52705270
assert(args.size() == 1 || args.size() == 2);
52715271
auto [fieldRef, fieldTy] = getFieldRef(builder, loc, fir::getBase(args[0]));
52725272
mlir::Value flag = builder.create<fir::LoadOp>(loc, fieldRef);
@@ -5283,6 +5283,22 @@ fir::ExtendedValue IntrinsicLibrary::genIeeeSupportFlagOrHalting(
52835283
builder.createIntegerConstant(loc, fieldTy, 0)));
52845284
}
52855285

5286+
// IEEE_SUPPORT_HALTING
5287+
fir::ExtendedValue IntrinsicLibrary::genIeeeSupportHalting(
5288+
mlir::Type resultType, llvm::ArrayRef<fir::ExtendedValue> args) {
5289+
// Check if halting is supported for a floating point exception flag.
5290+
// Standard flags are all supported. The nonstandard DENORM extension is
5291+
// not supported, at least for now.
5292+
assert(args.size() == 1);
5293+
mlir::Type i32Ty = builder.getIntegerType(32);
5294+
auto [fieldRef, ignore] = getFieldRef(builder, loc, getBase(args[0]));
5295+
mlir::Value field = builder.create<fir::LoadOp>(loc, fieldRef);
5296+
return builder.createConvert(
5297+
loc, resultType,
5298+
fir::runtime::genSupportHalting(
5299+
builder, loc, {builder.create<fir::ConvertOp>(loc, i32Ty, field)}));
5300+
}
5301+
52865302
// IEEE_SUPPORT_ROUNDING
52875303
mlir::Value
52885304
IntrinsicLibrary::genIeeeSupportRounding(mlir::Type resultType,

flang/lib/Optimizer/Builder/Runtime/Exceptions.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@ mlir::Value fir::runtime::genMapExcept(fir::FirOpBuilder &builder,
2121
return builder.create<fir::CallOp>(loc, func, excepts).getResult(0);
2222
}
2323

24+
mlir::Value fir::runtime::genSupportHalting(fir::FirOpBuilder &builder,
25+
mlir::Location loc,
26+
mlir::Value excepts) {
27+
mlir::func::FuncOp func{
28+
fir::runtime::getRuntimeFunc<mkRTKey(SupportHalting)>(loc, builder)};
29+
return builder.create<fir::CallOp>(loc, func, excepts).getResult(0);
30+
}
31+
2432
mlir::Value fir::runtime::genGetUnderflowMode(fir::FirOpBuilder &builder,
2533
mlir::Location loc) {
2634
mlir::func::FuncOp func{

flang/runtime/exceptions.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,23 @@ uint32_t RTNAME(MapException)(uint32_t excepts) {
8181
// on some systems, e.g. Solaris, so omit object size comparison for now.
8282
// TODO: consider femode_t object size comparison once its more mature.
8383

84+
// Check if the processor has the ability to control whether to halt or
85+
// continue execution when a given exception is raised.
86+
bool RTNAME(SupportHalting)(uint32_t except) {
87+
except = RTNAME(MapException)(except);
88+
int currentSet = fegetexcept(), flipSet, ok;
89+
if (currentSet & except) {
90+
ok = fedisableexcept(except);
91+
flipSet = fegetexcept();
92+
ok |= feenableexcept(except);
93+
} else {
94+
ok = feenableexcept(except);
95+
flipSet = fegetexcept();
96+
ok |= fedisableexcept(except);
97+
}
98+
return ok != -1 && currentSet != flipSet;
99+
}
100+
84101
bool RTNAME(GetUnderflowMode)(void) {
85102
#if __x86_64__
86103
// The MXCSR Flush to Zero flag is the negation of the ieee_get_underflow_mode

flang/test/Evaluate/fold-ieee.f90

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,13 @@ module m
2626
logical, parameter :: test_fl_ix_all = ieee_support_flag(ieee_inexact)
2727
logical, parameter :: test_fl_ix_4 = ieee_support_flag(ieee_inexact, 1.)
2828
logical, parameter :: test_fl_ix_8 = ieee_support_flag(ieee_inexact, 1.d0)
29+
#if __x86_64__
2930
logical, parameter :: test_halt_in = ieee_support_halting(ieee_invalid)
3031
logical, parameter :: test_halt_ov = ieee_support_halting(ieee_overflow)
3132
logical, parameter :: test_halt_d0 = ieee_support_halting(ieee_divide_by_zero)
3233
logical, parameter :: test_halt_un = ieee_support_halting(ieee_underflow)
3334
logical, parameter :: test_halt_ix = ieee_support_halting(ieee_inexact)
35+
#endif
3436
logical, parameter :: test_inf_all = ieee_support_inf()
3537
logical, parameter :: test_inf_4 = ieee_support_inf(1.)
3638
logical, parameter :: test_inf_8 = ieee_support_inf(1.d0)
@@ -58,7 +60,9 @@ module m
5860
logical, parameter :: test_sn_all = ieee_support_subnormal()
5961
logical, parameter :: test_sn_4 = ieee_support_subnormal(1.)
6062
logical, parameter :: test_sn_8 = ieee_support_subnormal(1.d0)
61-
! logical, parameter :: test_uc_all = .not. ieee_support_underflow_control()
62-
! logical, parameter :: test_uc_4 = ieee_support_underflow_control(1.)
63-
! logical, parameter :: test_uc_8 = ieee_support_underflow_control(1.d0)
63+
#if __x86_64__
64+
logical, parameter :: test_uc_all = .not. ieee_support_underflow_control()
65+
logical, parameter :: test_uc_4 = ieee_support_underflow_control(1.)
66+
logical, parameter :: test_uc_8 = ieee_support_underflow_control(1.d0)
67+
#endif
6468
end

flang/test/Lower/Intrinsics/ieee_flag.f90

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@
271271
print*, 'Halting'
272272

273273
! CHECK: %[[V_211:[0-9]+]] = fir.call @_FortranAioBeginExternalListOutput
274-
! CHECK: %[[V_220:[0-9]+]] = fir.call @_FortranAioOutputLogical(%[[V_211]], %true) fastmath<contract> : (!fir.ref<i8>, i1) -> i1
274+
! CHECK: %[[V_220:[0-9]+]] = fir.call @_FortranAioOutputLogical(%[[V_211]]
275275
print*, 'support invalid: ', ieee_support_halting(ieee_invalid)
276276

277277
! CHECK: %[[V_222:[0-9]+]] = fir.declare %[[V_80]] {fortran_attrs = #fir.var_attrs<parameter>, uniq_name = "_QQro._QM__fortran_builtinsT__builtin_ieee_flag_type.0"} : (!fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_ieee_flag_type{_QM__fortran_builtinsT__builtin_ieee_flag_type.flag:i8}>>) -> !fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_ieee_flag_type{_QM__fortran_builtinsT__builtin_ieee_flag_type.flag:i8}>>

0 commit comments

Comments
 (0)