1 //===- llvm/Support/FloatingPointMode.h -------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 ///
9 /// \file
10 /// Utilities for dealing with flags related to floating point properties and
11 /// mode controls.
12 ///
13 //===----------------------------------------------------------------------===/
14
15 #ifndef LLVM_ADT_FLOATINGPOINTMODE_H
16 #define LLVM_ADT_FLOATINGPOINTMODE_H
17
18 #include "llvm/ADT/StringSwitch.h"
19 #include "llvm/Support/raw_ostream.h"
20
21 namespace llvm {
22
23 /// Rounding mode.
24 ///
25 /// Enumerates supported rounding modes, as well as some special values. The set
26 /// of the modes must agree with IEEE-754, 4.3.1 and 4.3.2. The constants
27 /// assigned to the IEEE rounding modes must agree with the values used by
28 /// FLT_ROUNDS (C11, 5.2.4.2.2p8).
29 ///
30 /// This value is packed into bitfield in some cases, including \c FPOptions, so
31 /// the rounding mode values and the special value \c Dynamic must fit into the
32 /// the bit field (now - 3 bits). The value \c Invalid is used only in values
33 /// returned by intrinsics to indicate errors, it should never be stored as
34 /// rounding mode value, so it does not need to fit the bit fields.
35 ///
36 enum class RoundingMode : int8_t {
37 // Rounding mode defined in IEEE-754.
38 TowardZero = 0, ///< roundTowardZero.
39 NearestTiesToEven = 1, ///< roundTiesToEven.
40 TowardPositive = 2, ///< roundTowardPositive.
41 TowardNegative = 3, ///< roundTowardNegative.
42 NearestTiesToAway = 4, ///< roundTiesToAway.
43
44 // Special values.
45 Dynamic = 7, ///< Denotes mode unknown at compile time.
46 Invalid = -1 ///< Denotes invalid value.
47 };
48
49 /// Returns text representation of the given rounding mode.
spell(RoundingMode RM)50 inline StringRef spell(RoundingMode RM) {
51 switch (RM) {
52 case RoundingMode::TowardZero: return "towardzero";
53 case RoundingMode::NearestTiesToEven: return "tonearest";
54 case RoundingMode::TowardPositive: return "upward";
55 case RoundingMode::TowardNegative: return "downward";
56 case RoundingMode::NearestTiesToAway: return "tonearestaway";
57 case RoundingMode::Dynamic: return "dynamic";
58 default: return "invalid";
59 }
60 }
61
62 inline raw_ostream &operator << (raw_ostream &OS, RoundingMode RM) {
63 OS << spell(RM);
64 return OS;
65 }
66
67 /// Represent subnormal handling kind for floating point instruction inputs and
68 /// outputs.
69 struct DenormalMode {
70 /// Represent handled modes for denormal (aka subnormal) modes in the floating
71 /// point environment.
72 enum DenormalModeKind : int8_t {
73 Invalid = -1,
74
75 /// IEEE-754 denormal numbers preserved.
76 IEEE,
77
78 /// The sign of a flushed-to-zero number is preserved in the sign of 0
79 PreserveSign,
80
81 /// Denormals are flushed to positive zero.
82 PositiveZero
83 };
84
85 /// Denormal flushing mode for floating point instruction results in the
86 /// default floating point environment.
87 DenormalModeKind Output = DenormalModeKind::Invalid;
88
89 /// Denormal treatment kind for floating point instruction inputs in the
90 /// default floating-point environment. If this is not DenormalModeKind::IEEE,
91 /// floating-point instructions implicitly treat the input value as 0.
92 DenormalModeKind Input = DenormalModeKind::Invalid;
93
94 constexpr DenormalMode() = default;
DenormalModeDenormalMode95 constexpr DenormalMode(DenormalModeKind Out, DenormalModeKind In) :
96 Output(Out), Input(In) {}
97
98
getInvalidDenormalMode99 static constexpr DenormalMode getInvalid() {
100 return DenormalMode(DenormalModeKind::Invalid, DenormalModeKind::Invalid);
101 }
102
getIEEEDenormalMode103 static constexpr DenormalMode getIEEE() {
104 return DenormalMode(DenormalModeKind::IEEE, DenormalModeKind::IEEE);
105 }
106
getPreserveSignDenormalMode107 static constexpr DenormalMode getPreserveSign() {
108 return DenormalMode(DenormalModeKind::PreserveSign,
109 DenormalModeKind::PreserveSign);
110 }
111
getPositiveZeroDenormalMode112 static constexpr DenormalMode getPositiveZero() {
113 return DenormalMode(DenormalModeKind::PositiveZero,
114 DenormalModeKind::PositiveZero);
115 }
116
117 bool operator==(DenormalMode Other) const {
118 return Output == Other.Output && Input == Other.Input;
119 }
120
121 bool operator!=(DenormalMode Other) const {
122 return !(*this == Other);
123 }
124
isSimpleDenormalMode125 bool isSimple() const {
126 return Input == Output;
127 }
128
isValidDenormalMode129 bool isValid() const {
130 return Output != DenormalModeKind::Invalid &&
131 Input != DenormalModeKind::Invalid;
132 }
133
134 inline void print(raw_ostream &OS) const;
135
strDenormalMode136 inline std::string str() const {
137 std::string storage;
138 raw_string_ostream OS(storage);
139 print(OS);
140 return OS.str();
141 }
142 };
143
144 inline raw_ostream& operator<<(raw_ostream &OS, DenormalMode Mode) {
145 Mode.print(OS);
146 return OS;
147 }
148
149 /// Parse the expected names from the denormal-fp-math attribute.
150 inline DenormalMode::DenormalModeKind
parseDenormalFPAttributeComponent(StringRef Str)151 parseDenormalFPAttributeComponent(StringRef Str) {
152 // Assume ieee on unspecified attribute.
153 return StringSwitch<DenormalMode::DenormalModeKind>(Str)
154 .Cases("", "ieee", DenormalMode::IEEE)
155 .Case("preserve-sign", DenormalMode::PreserveSign)
156 .Case("positive-zero", DenormalMode::PositiveZero)
157 .Default(DenormalMode::Invalid);
158 }
159
160 /// Return the name used for the denormal handling mode used by the the
161 /// expected names from the denormal-fp-math attribute.
denormalModeKindName(DenormalMode::DenormalModeKind Mode)162 inline StringRef denormalModeKindName(DenormalMode::DenormalModeKind Mode) {
163 switch (Mode) {
164 case DenormalMode::IEEE:
165 return "ieee";
166 case DenormalMode::PreserveSign:
167 return "preserve-sign";
168 case DenormalMode::PositiveZero:
169 return "positive-zero";
170 default:
171 return "";
172 }
173 }
174
175 /// Returns the denormal mode to use for inputs and outputs.
parseDenormalFPAttribute(StringRef Str)176 inline DenormalMode parseDenormalFPAttribute(StringRef Str) {
177 StringRef OutputStr, InputStr;
178 std::tie(OutputStr, InputStr) = Str.split(',');
179
180 DenormalMode Mode;
181 Mode.Output = parseDenormalFPAttributeComponent(OutputStr);
182
183 // Maintain compatability with old form of the attribute which only specified
184 // one component.
185 Mode.Input = InputStr.empty() ? Mode.Output :
186 parseDenormalFPAttributeComponent(InputStr);
187
188 return Mode;
189 }
190
print(raw_ostream & OS)191 void DenormalMode::print(raw_ostream &OS) const {
192 OS << denormalModeKindName(Output) << ',' << denormalModeKindName(Input);
193 }
194
195 }
196
197 /// Floating-point class tests, supported by 'is_fpclass' intrinsic. Actual
198 /// test may be an OR combination of basic tests.
199 enum FPClassTest {
200 fcSNan = 0x0001,
201 fcQNan = 0x0002,
202 fcNegInf = 0x0004,
203 fcNegNormal = 0x0008,
204 fcNegSubnormal = 0x0010,
205 fcNegZero = 0x0020,
206 fcPosZero = 0x0040,
207 fcPosSubnormal = 0x0080,
208 fcPosNormal = 0x0100,
209 fcPosInf = 0x0200,
210
211 fcNan = fcSNan | fcQNan,
212 fcInf = fcPosInf | fcNegInf,
213 fcNormal = fcPosNormal | fcNegNormal,
214 fcSubnormal = fcPosSubnormal | fcNegSubnormal,
215 fcZero = fcPosZero | fcNegZero,
216 fcPosFinite = fcPosNormal | fcPosSubnormal | fcPosZero,
217 fcNegFinite = fcNegNormal | fcNegSubnormal | fcNegZero,
218 fcFinite = fcPosFinite | fcNegFinite,
219 fcAllFlags = fcNan | fcInf | fcFinite
220 };
221
222 #endif // LLVM_ADT_FLOATINGPOINTMODE_H
223