Skip to content

Commit ed41055

Browse files
klauslerAlexisPerry
authored andcommitted
[flang] Fold IEEE_SUPPORT_xxx() intrinsic functions (llvm#95866)
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 3311eb4 commit ed41055

18 files changed

+498
-334
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/lib/Evaluate/fold-logical.cpp

Lines changed: 59 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,48 @@ 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+
if (context.targetCharacteristics().ieeeFeatures().test(
877+
IeeeFeature::Rounding)) {
878+
if (auto mode{GetRoundingMode(args[0])}) {
879+
return Expr<T>{mode != common::RoundingMode::TiesAwayFromZero};
880+
}
881+
}
882+
} else if (name == "__builtin_ieee_support_sqrt") {
883+
return Expr<T>{
884+
context.targetCharacteristics().ieeeFeatures().test(IeeeFeature::Sqrt)};
885+
} else if (name == "__builtin_ieee_support_standard") {
886+
return Expr<T>{context.targetCharacteristics().ieeeFeatures().test(
887+
IeeeFeature::Standard)};
888+
} else if (name == "__builtin_ieee_support_subnormal") {
889+
return Expr<T>{context.targetCharacteristics().ieeeFeatures().test(
890+
IeeeFeature::Subnormal)};
891+
} else if (name == "__builtin_ieee_support_underflow_control") {
892+
return Expr<T>{context.targetCharacteristics().ieeeFeatures().test(
893+
IeeeFeature::UnderflowControl)};
845894
}
846895
return Expr<T>{std::move(funcRef)};
847896
}

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/module/__fortran_builtins.f90

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
!
77
!===------------------------------------------------------------------------===!
88

9+
include '../include/flang/Runtime/magic-numbers.h'
10+
911
! These naming shenanigans prevent names from Fortran intrinsic modules
1012
! from being usable on INTRINSIC statements, and force the program
1113
! to USE the standard intrinsic modules in order to access the
@@ -49,6 +51,42 @@
4951
integer(kind=int64), private :: __count
5052
end type
5153

54+
type, public :: __builtin_ieee_flag_type
55+
integer(kind=1), private :: flag = 0
56+
end type
57+
58+
type(__builtin_ieee_flag_type), parameter, public :: &
59+
__builtin_ieee_invalid = &
60+
__builtin_ieee_flag_type(_FORTRAN_RUNTIME_IEEE_INVALID), &
61+
__builtin_ieee_overflow = &
62+
__builtin_ieee_flag_type(_FORTRAN_RUNTIME_IEEE_OVERFLOW), &
63+
__builtin_ieee_divide_by_zero = &
64+
__builtin_ieee_flag_type(_FORTRAN_RUNTIME_IEEE_DIVIDE_BY_ZERO), &
65+
__builtin_ieee_underflow = &
66+
__builtin_ieee_flag_type(_FORTRAN_RUNTIME_IEEE_UNDERFLOW), &
67+
__builtin_ieee_inexact = &
68+
__builtin_ieee_flag_type(_FORTRAN_RUNTIME_IEEE_INEXACT), &
69+
__builtin_ieee_denorm = & ! extension
70+
__builtin_ieee_flag_type(_FORTRAN_RUNTIME_IEEE_DENORM)
71+
72+
type, public :: __builtin_ieee_round_type
73+
integer(kind=1), private :: mode = 0
74+
end type
75+
76+
type(__builtin_ieee_round_type), parameter, public :: &
77+
__builtin_ieee_to_zero = &
78+
__builtin_ieee_round_type(_FORTRAN_RUNTIME_IEEE_TO_ZERO), &
79+
__builtin_ieee_nearest = &
80+
__builtin_ieee_round_type(_FORTRAN_RUNTIME_IEEE_NEAREST), &
81+
__builtin_ieee_up = &
82+
__builtin_ieee_round_type(_FORTRAN_RUNTIME_IEEE_UP), &
83+
__builtin_ieee_down = &
84+
__builtin_ieee_round_type(_FORTRAN_RUNTIME_IEEE_DOWN), &
85+
__builtin_ieee_away = &
86+
__builtin_ieee_round_type(_FORTRAN_RUNTIME_IEEE_AWAY), &
87+
__builtin_ieee_other = &
88+
__builtin_ieee_round_type(_FORTRAN_RUNTIME_IEEE_OTHER)
89+
5290
type, public :: __builtin_team_type
5391
integer(kind=int64), private :: __id
5492
end type
@@ -74,8 +112,10 @@
74112
intrinsic :: __builtin_ieee_selected_real_kind
75113
intrinsic :: __builtin_ieee_support_datatype, &
76114
__builtin_ieee_support_denormal, __builtin_ieee_support_divide, &
115+
__builtin_ieee_support_flag, __builtin_ieee_support_halting, &
77116
__builtin_ieee_support_inf, __builtin_ieee_support_io, &
78-
__builtin_ieee_support_nan, __builtin_ieee_support_sqrt, &
117+
__builtin_ieee_support_nan, __builtin_ieee_support_rounding, &
118+
__builtin_ieee_support_sqrt, &
79119
__builtin_ieee_support_standard, __builtin_ieee_support_subnormal, &
80120
__builtin_ieee_support_underflow_control
81121
public :: __builtin_fma
@@ -87,8 +127,10 @@
87127
public :: __builtin_ieee_selected_real_kind
88128
public :: __builtin_ieee_support_datatype, &
89129
__builtin_ieee_support_denormal, __builtin_ieee_support_divide, &
130+
__builtin_ieee_support_flag, __builtin_ieee_support_halting, &
90131
__builtin_ieee_support_inf, __builtin_ieee_support_io, &
91-
__builtin_ieee_support_nan, __builtin_ieee_support_sqrt, &
132+
__builtin_ieee_support_nan, __builtin_ieee_support_rounding, &
133+
__builtin_ieee_support_sqrt, &
92134
__builtin_ieee_support_standard, __builtin_ieee_support_subnormal, &
93135
__builtin_ieee_support_underflow_control
94136

0 commit comments

Comments
 (0)