Skip to content

Commit 8ae756a

Browse files
committed
[flang] Fold IEEE_SUPPORT_xxx() intrinsic functions
All of the IEEE_SUPPORT_xxx() intrinsic functions must fold to constant logical values when they have constant arguments; and since they fold to .TRUE. for currently support architectures, always fold them. But also put in the infrastructure whereby a driver can initialize Evaluate's target information to set some of them to .FALSE. if that becomes necessary.
1 parent 6be6c3a commit 8ae756a

File tree

20 files changed

+500
-395
lines changed

20 files changed

+500
-395
lines changed

flang/include/flang/Common/Fortran.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,14 @@ ENUM_CLASS(
6767
const char *AsFortran(DefinedIo);
6868

6969
// Floating-point rounding modes; these are packed into a byte to save
70-
// room in the runtime's format processing context structure.
70+
// room in the runtime's format processing context structure. These
71+
// enumerators are defined with the corresponding values returned from
72+
// llvm.get.rounding.
7173
enum class RoundingMode : std::uint8_t {
72-
TiesToEven, // ROUND=NEAREST, RN - default IEEE rounding
7374
ToZero, // ROUND=ZERO, RZ - truncation
74-
Down, // ROUND=DOWN, RD
75+
TiesToEven, // ROUND=NEAREST, RN - default IEEE rounding
7576
Up, // ROUND=UP, RU
77+
Down, // ROUND=DOWN, RD
7678
TiesAwayFromZero, // ROUND=COMPATIBLE, RC - ties round away from zero
7779
};
7880

flang/include/flang/Evaluate/common.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,9 @@ static constexpr bool Satisfies(RelationalOperator op, Relation relation) {
128128
return false; // silence g++ warning
129129
}
130130

131-
ENUM_CLASS(
132-
RealFlag, Overflow, DivideByZero, InvalidArgument, Underflow, Inexact)
133-
131+
// These are ordered like the bits in a common fenv.h header file.
132+
ENUM_CLASS(RealFlag, InvalidArgument, Denorm, DivideByZero, Overflow, Underflow,
133+
Inexact)
134134
using RealFlags = common::EnumSet<RealFlag, RealFlag_enumSize>;
135135

136136
template <typename A> struct ValueWithRealFlags {

flang/include/flang/Evaluate/target.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
#define FORTRAN_EVALUATE_TARGET_H_
1414

1515
#include "flang/Common/Fortran.h"
16+
#include "flang/Common/enum-class.h"
17+
#include "flang/Common/enum-set.h"
1618
#include "flang/Evaluate/common.h"
1719
#include <cstdint>
1820

@@ -32,6 +34,11 @@ struct Rounding {
3234
#endif
3335
};
3436

37+
ENUM_CLASS(IeeeFeature, Denormal, Divide, Flags, Halting, Inf, Io, NaN,
38+
Rounding, Sqrt, Standard, Subnormal, UnderflowControl)
39+
40+
using IeeeFeatures = common::EnumSet<IeeeFeature, 16>;
41+
3542
class TargetCharacteristics {
3643
public:
3744
TargetCharacteristics();
@@ -95,6 +102,9 @@ class TargetCharacteristics {
95102
bool isPPC() const { return isPPC_; }
96103
void set_isPPC(bool isPPC = false);
97104

105+
IeeeFeatures &ieeeFeatures() { return ieeeFeatures_; }
106+
const IeeeFeatures &ieeeFeatures() const { return ieeeFeatures_; }
107+
98108
private:
99109
static constexpr int maxKind{32};
100110
std::uint8_t byteSize_[common::TypeCategory_enumSize][maxKind]{};
@@ -110,6 +120,11 @@ class TargetCharacteristics {
110120
std::size_t maxAlignment_{8 /*at least*/};
111121
std::string compilerOptionsString_;
112122
std::string compilerVersionString_;
123+
IeeeFeatures ieeeFeatures_{IeeeFeature::Denormal, IeeeFeature::Divide,
124+
IeeeFeature::Flags, IeeeFeature::Halting, IeeeFeature::Inf,
125+
IeeeFeature::Io, IeeeFeature::NaN, IeeeFeature::Rounding,
126+
IeeeFeature::Sqrt, IeeeFeature::Standard, IeeeFeature::Subnormal,
127+
IeeeFeature::UnderflowControl};
113128
};
114129

115130
} // namespace Fortran::evaluate

flang/include/flang/Evaluate/tools.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1320,6 +1320,10 @@ bool IsBuiltinCPtr(const Symbol &);
13201320
bool IsEventType(const DerivedTypeSpec *);
13211321
bool IsLockType(const DerivedTypeSpec *);
13221322
bool IsNotifyType(const DerivedTypeSpec *);
1323+
// Is this derived type IEEE_FLAG_TYPE from module ISO_IEEE_EXCEPTIONS?
1324+
bool IsIeeeFlagType(const DerivedTypeSpec *);
1325+
// Is this derived type IEEE_ROUND_TYPE from module ISO_IEEE_ARITHMETIC?
1326+
bool IsIeeeRoundType(const DerivedTypeSpec *);
13231327
// Is this derived type TEAM_TYPE from module ISO_FORTRAN_ENV?
13241328
bool IsTeamType(const DerivedTypeSpec *);
13251329
// Is this derived type TEAM_TYPE, C_PTR, or C_FUNPTR?

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

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -275,10 +275,6 @@ struct IntrinsicLibrary {
275275
mlir::Value genIeeeSignalingCompare(mlir::Type resultType,
276276
llvm::ArrayRef<mlir::Value>);
277277
mlir::Value genIeeeSignbit(mlir::Type, llvm::ArrayRef<mlir::Value>);
278-
fir::ExtendedValue
279-
genIeeeSupportFlagOrHalting(mlir::Type,
280-
llvm::ArrayRef<fir::ExtendedValue>);
281-
mlir::Value genIeeeSupportRounding(mlir::Type, llvm::ArrayRef<mlir::Value>);
282278
template <mlir::arith::CmpIPredicate pred>
283279
mlir::Value genIeeeTypeCompare(mlir::Type, llvm::ArrayRef<mlir::Value>);
284280
mlir::Value genIeeeUnordered(mlir::Type, llvm::ArrayRef<mlir::Value>);

flang/lib/Evaluate/fold-logical.cpp

Lines changed: 61 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,24 @@ static Expr<Type<TypeCategory::Logical, KIND>> RewriteOutOfRange(
620620
return AsExpr(std::move(funcRef));
621621
}
622622

623+
static std::optional<common::RoundingMode> GetRoundingMode(
624+
const std::optional<ActualArgument> &arg) {
625+
if (arg) {
626+
if (const auto *cst{UnwrapExpr<Constant<SomeDerived>>(*arg)}) {
627+
if (auto constr{cst->GetScalarValue()}) {
628+
if (StructureConstructorValues & values{constr->values()};
629+
values.size() == 1) {
630+
const Expr<SomeType> &value{values.begin()->second.value()};
631+
if (auto code{ToInt64(value)}) {
632+
return static_cast<common::RoundingMode>(*code);
633+
}
634+
}
635+
}
636+
}
637+
}
638+
return std::nullopt;
639+
}
640+
623641
template <int KIND>
624642
Expr<Type<TypeCategory::Logical, KIND>> FoldIntrinsicFunction(
625643
FoldingContext &context,
@@ -831,17 +849,50 @@ Expr<Type<TypeCategory::Logical, KIND>> FoldIntrinsicFunction(
831849
}
832850
}
833851
}
834-
} else if (name == "__builtin_ieee_support_datatype" ||
835-
name == "__builtin_ieee_support_denormal" ||
836-
name == "__builtin_ieee_support_divide" ||
837-
name == "__builtin_ieee_support_inf" ||
838-
name == "__builtin_ieee_support_io" ||
839-
name == "__builtin_ieee_support_nan" ||
840-
name == "__builtin_ieee_support_sqrt" ||
841-
name == "__builtin_ieee_support_standard" ||
842-
name == "__builtin_ieee_support_subnormal" ||
843-
name == "__builtin_ieee_support_underflow_control") {
852+
} else if (name == "__builtin_ieee_support_datatype") {
844853
return Expr<T>{true};
854+
} else if (name == "__builtin_ieee_support_denormal") {
855+
return Expr<T>{context.targetCharacteristics().ieeeFeatures().test(
856+
IeeeFeature::Denormal)};
857+
} else if (name == "__builtin_ieee_support_divide") {
858+
return Expr<T>{context.targetCharacteristics().ieeeFeatures().test(
859+
IeeeFeature::Divide)};
860+
} else if (name == "__builtin_ieee_support_flag") {
861+
return Expr<T>{context.targetCharacteristics().ieeeFeatures().test(
862+
IeeeFeature::Flags)};
863+
} else if (name == "__builtin_ieee_support_halting") {
864+
return Expr<T>{context.targetCharacteristics().ieeeFeatures().test(
865+
IeeeFeature::Halting)};
866+
} else if (name == "__builtin_ieee_support_inf") {
867+
return Expr<T>{
868+
context.targetCharacteristics().ieeeFeatures().test(IeeeFeature::Inf)};
869+
} else if (name == "__builtin_ieee_support_io") {
870+
return Expr<T>{
871+
context.targetCharacteristics().ieeeFeatures().test(IeeeFeature::Io)};
872+
} else if (name == "__builtin_ieee_support_nan") {
873+
return Expr<T>{
874+
context.targetCharacteristics().ieeeFeatures().test(IeeeFeature::NaN)};
875+
} else if (name == "__builtin_ieee_support_rounding") {
876+
bool result{false};
877+
if (context.targetCharacteristics().ieeeFeatures().test(
878+
IeeeFeature::Rounding)) {
879+
if (auto mode{GetRoundingMode(args[0])}) {
880+
result = mode != common::RoundingMode::TiesAwayFromZero;
881+
}
882+
}
883+
return Expr<T>{result};
884+
} else if (name == "__builtin_ieee_support_sqrt") {
885+
return Expr<T>{
886+
context.targetCharacteristics().ieeeFeatures().test(IeeeFeature::Sqrt)};
887+
} else if (name == "__builtin_ieee_support_standard") {
888+
return Expr<T>{context.targetCharacteristics().ieeeFeatures().test(
889+
IeeeFeature::Standard)};
890+
} else if (name == "__builtin_ieee_support_subnormal") {
891+
return Expr<T>{context.targetCharacteristics().ieeeFeatures().test(
892+
IeeeFeature::Subnormal)};
893+
} else if (name == "__builtin_ieee_support_underflow_control") {
894+
return Expr<T>{context.targetCharacteristics().ieeeFeatures().test(
895+
IeeeFeature::UnderflowControl)};
845896
}
846897
return Expr<T>{std::move(funcRef)};
847898
}

flang/lib/Evaluate/intrinsics.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ ENUM_CLASS(KindCode, none, defaultIntegerKind,
8888
sameKind,
8989
operand, // match any kind, with promotion (non-standard)
9090
typeless, // BOZ literals are INTEGER with this kind
91+
ieeeFlagType, // IEEE_FLAG_TYPE from ISO_FORTRAN_EXCEPTION
92+
ieeeRoundType, // IEEE_ROUND_TYPE from ISO_FORTRAN_ARITHMETIC
9193
teamType, // TEAM_TYPE from module ISO_FORTRAN_ENV (for coarrays)
9294
kindArg, // this argument is KIND=
9395
effectiveKind, // for function results: "kindArg" value, possibly defaulted
@@ -121,6 +123,9 @@ static constexpr TypePattern DefaultChar{CharType, KindCode::defaultCharKind};
121123
static constexpr TypePattern DefaultLogical{
122124
LogicalType, KindCode::defaultLogicalKind};
123125
static constexpr TypePattern BOZ{IntType, KindCode::typeless};
126+
static constexpr TypePattern IeeeFlagType{DerivedType, KindCode::ieeeFlagType};
127+
static constexpr TypePattern IeeeRoundType{
128+
DerivedType, KindCode::ieeeRoundType};
124129
static constexpr TypePattern TeamType{DerivedType, KindCode::teamType};
125130
static constexpr TypePattern DoublePrecision{
126131
RealType, KindCode::doublePrecision};
@@ -940,6 +945,12 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
940945
{"__builtin_ieee_support_divide",
941946
{{"x", AnyReal, Rank::elemental, Optionality::optional}},
942947
DefaultLogical},
948+
{"__builtin_ieee_support_flag",
949+
{{"flag", IeeeFlagType, Rank::scalar},
950+
{"x", AnyReal, Rank::elemental, Optionality::optional}},
951+
DefaultLogical},
952+
{"__builtin_ieee_support_halting", {{"flag", IeeeFlagType, Rank::scalar}},
953+
DefaultLogical},
943954
{"__builtin_ieee_support_inf",
944955
{{"x", AnyReal, Rank::elemental, Optionality::optional}},
945956
DefaultLogical},
@@ -949,6 +960,10 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
949960
{"__builtin_ieee_support_nan",
950961
{{"x", AnyReal, Rank::elemental, Optionality::optional}},
951962
DefaultLogical},
963+
{"__builtin_ieee_support_rounding",
964+
{{"round_value", IeeeRoundType, Rank::scalar},
965+
{"x", AnyReal, Rank::elemental, Optionality::optional}},
966+
DefaultLogical},
952967
{"__builtin_ieee_support_sqrt",
953968
{{"x", AnyReal, Rank::elemental, Optionality::optional}},
954969
DefaultLogical},
@@ -1851,6 +1866,16 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
18511866
case KindCode::typeless:
18521867
argOk = false;
18531868
break;
1869+
case KindCode::ieeeFlagType:
1870+
argOk = !type->IsUnlimitedPolymorphic() &&
1871+
type->category() == TypeCategory::Derived &&
1872+
semantics::IsIeeeFlagType(&type->GetDerivedTypeSpec());
1873+
break;
1874+
case KindCode::ieeeRoundType:
1875+
argOk = !type->IsUnlimitedPolymorphic() &&
1876+
type->category() == TypeCategory::Derived &&
1877+
semantics::IsIeeeRoundType(&type->GetDerivedTypeSpec());
1878+
break;
18541879
case KindCode::teamType:
18551880
argOk = !type->IsUnlimitedPolymorphic() &&
18561881
type->category() == TypeCategory::Derived &&

flang/lib/Evaluate/tools.cpp

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1754,13 +1754,34 @@ bool IsSequenceOrBindCType(const DerivedTypeSpec *derived) {
17541754
derived->typeSymbol().get<DerivedTypeDetails>().sequence());
17551755
}
17561756

1757+
static bool IsSameModule(const Scope *x, const Scope *y) {
1758+
if (x == y) {
1759+
return true;
1760+
} else if (x && y) {
1761+
// Allow for a builtin module to be read from distinct paths
1762+
const Symbol *xSym{x->symbol()};
1763+
const Symbol *ySym{y->symbol()};
1764+
if (xSym && ySym && xSym->name() == ySym->name()) {
1765+
const auto *xMod{xSym->detailsIf<ModuleDetails>()};
1766+
const auto *yMod{ySym->detailsIf<ModuleDetails>()};
1767+
if (xMod && yMod) {
1768+
auto xHash{xMod->moduleFileHash()};
1769+
auto yHash{yMod->moduleFileHash()};
1770+
return xHash && yHash && *xHash == *yHash;
1771+
}
1772+
}
1773+
}
1774+
return false;
1775+
}
1776+
17571777
bool IsBuiltinDerivedType(const DerivedTypeSpec *derived, const char *name) {
1758-
if (!derived) {
1759-
return false;
1760-
} else {
1778+
if (derived) {
17611779
const auto &symbol{derived->typeSymbol()};
1762-
return &symbol.owner() == symbol.owner().context().GetBuiltinsScope() &&
1763-
symbol.name() == "__builtin_"s + name;
1780+
const Scope &scope{symbol.owner()};
1781+
return symbol.name() == "__builtin_"s + name &&
1782+
IsSameModule(&scope, scope.context().GetBuiltinsScope());
1783+
} else {
1784+
return false;
17641785
}
17651786
}
17661787

@@ -1790,6 +1811,14 @@ bool IsNotifyType(const DerivedTypeSpec *derived) {
17901811
return IsBuiltinDerivedType(derived, "notify_type");
17911812
}
17921813

1814+
bool IsIeeeFlagType(const DerivedTypeSpec *derived) {
1815+
return IsBuiltinDerivedType(derived, "ieee_flag_type");
1816+
}
1817+
1818+
bool IsIeeeRoundType(const DerivedTypeSpec *derived) {
1819+
return IsBuiltinDerivedType(derived, "ieee_round_type");
1820+
}
1821+
17931822
bool IsTeamType(const DerivedTypeSpec *derived) {
17941823
return IsBuiltinDerivedType(derived, "team_type");
17951824
}

flang/lib/Optimizer/Builder/IntrinsicCall.cpp

Lines changed: 0 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -373,12 +373,6 @@ static constexpr IntrinsicHandler handlers[]{
373373
{"ieee_signaling_ne",
374374
&I::genIeeeSignalingCompare<mlir::arith::CmpFPredicate::UNE>},
375375
{"ieee_signbit", &I::genIeeeSignbit},
376-
{"ieee_support_flag",
377-
&I::genIeeeSupportFlagOrHalting,
378-
{{{"flag", asValue}, {"x", asInquired, handleDynamicOptional}}},
379-
/*isElemental=*/false},
380-
{"ieee_support_halting", &I::genIeeeSupportFlagOrHalting},
381-
{"ieee_support_rounding", &I::genIeeeSupportRounding},
382376
{"ieee_unordered", &I::genIeeeUnordered},
383377
{"ieee_value", &I::genIeeeValue},
384378
{"ieor", &I::genIeor},
@@ -4710,57 +4704,6 @@ mlir::Value IntrinsicLibrary::genIeeeSignbit(mlir::Type resultType,
47104704
return builder.createConvert(loc, resultType, sign);
47114705
}
47124706

4713-
// IEEE_SUPPORT_FLAG, IEEE_SUPPORT_HALTING
4714-
fir::ExtendedValue IntrinsicLibrary::genIeeeSupportFlagOrHalting(
4715-
mlir::Type resultType, llvm::ArrayRef<fir::ExtendedValue> args) {
4716-
// Check if a floating point exception or halting mode FLAG is supported.
4717-
// An IEEE_SUPPORT_FLAG flag is supported either for all type kinds or none.
4718-
// An optional kind argument X is therefore ignored.
4719-
// Standard flags are all supported.
4720-
// The nonstandard DENORM extension is not supported. (At least for now.)
4721-
assert(args.size() == 1 || args.size() == 2);
4722-
auto [fieldRef, fieldTy] = getFieldRef(builder, loc, fir::getBase(args[0]));
4723-
mlir::Value flag = builder.create<fir::LoadOp>(loc, fieldRef);
4724-
mlir::Value mask = builder.createIntegerConstant( // values are powers of 2
4725-
loc, fieldTy,
4726-
_FORTRAN_RUNTIME_IEEE_INVALID | _FORTRAN_RUNTIME_IEEE_DIVIDE_BY_ZERO |
4727-
_FORTRAN_RUNTIME_IEEE_OVERFLOW | _FORTRAN_RUNTIME_IEEE_UNDERFLOW |
4728-
_FORTRAN_RUNTIME_IEEE_INEXACT);
4729-
return builder.createConvert(
4730-
loc, resultType,
4731-
builder.create<mlir::arith::CmpIOp>(
4732-
loc, mlir::arith::CmpIPredicate::ne,
4733-
builder.create<mlir::arith::AndIOp>(loc, flag, mask),
4734-
builder.createIntegerConstant(loc, fieldTy, 0)));
4735-
}
4736-
4737-
// IEEE_SUPPORT_ROUNDING
4738-
mlir::Value
4739-
IntrinsicLibrary::genIeeeSupportRounding(mlir::Type resultType,
4740-
llvm::ArrayRef<mlir::Value> args) {
4741-
// Check if floating point rounding mode ROUND_VALUE is supported.
4742-
// Rounding is supported either for all type kinds or none.
4743-
// An optional X kind argument is therefore ignored.
4744-
// Values are chosen to match the llvm.get.rounding encoding:
4745-
// 0 - toward zero [supported]
4746-
// 1 - to nearest, ties to even [supported] - default
4747-
// 2 - toward positive infinity [supported]
4748-
// 3 - toward negative infinity [supported]
4749-
// 4 - to nearest, ties away from zero [not supported]
4750-
assert(args.size() == 1 || args.size() == 2);
4751-
auto [fieldRef, fieldTy] = getFieldRef(builder, loc, args[0]);
4752-
mlir::Value mode = builder.create<fir::LoadOp>(loc, fieldRef);
4753-
mlir::Value lbOk = builder.create<mlir::arith::CmpIOp>(
4754-
loc, mlir::arith::CmpIPredicate::sge, mode,
4755-
builder.createIntegerConstant(loc, fieldTy,
4756-
_FORTRAN_RUNTIME_IEEE_TO_ZERO));
4757-
mlir::Value ubOk = builder.create<mlir::arith::CmpIOp>(
4758-
loc, mlir::arith::CmpIPredicate::sle, mode,
4759-
builder.createIntegerConstant(loc, fieldTy, _FORTRAN_RUNTIME_IEEE_DOWN));
4760-
return builder.createConvert(
4761-
loc, resultType, builder.create<mlir::arith::AndIOp>(loc, lbOk, ubOk));
4762-
}
4763-
47644707
// IEEE_UNORDERED
47654708
mlir::Value
47664709
IntrinsicLibrary::genIeeeUnordered(mlir::Type resultType,

0 commit comments

Comments
 (0)