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.
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;
95   constexpr DenormalMode(DenormalModeKind Out, DenormalModeKind In) :
96     Output(Out), Input(In) {}
97 
98 
99   static constexpr DenormalMode getInvalid() {
100     return DenormalMode(DenormalModeKind::Invalid, DenormalModeKind::Invalid);
101   }
102 
103   static constexpr DenormalMode getIEEE() {
104     return DenormalMode(DenormalModeKind::IEEE, DenormalModeKind::IEEE);
105   }
106 
107   static constexpr DenormalMode getPreserveSign() {
108     return DenormalMode(DenormalModeKind::PreserveSign,
109                         DenormalModeKind::PreserveSign);
110   }
111 
112   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 
125   bool isSimple() const {
126     return Input == Output;
127   }
128 
129   bool isValid() const {
130     return Output != DenormalModeKind::Invalid &&
131            Input != DenormalModeKind::Invalid;
132   }
133 
134   inline void print(raw_ostream &OS) const;
135 
136   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
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.
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.
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 
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