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 // Utilities for dealing with flags related to floating point mode controls.
10 //
11 //===----------------------------------------------------------------------===/
12 
13 #ifndef LLVM_FLOATINGPOINTMODE_H
14 #define LLVM_FLOATINGPOINTMODE_H
15 
16 #include "llvm/ADT/StringSwitch.h"
17 #include "llvm/Support/raw_ostream.h"
18 
19 namespace llvm {
20 
21 /// Rounding mode.
22 ///
23 /// Enumerates supported rounding modes, as well as some special values. The set
24 /// of the modes must agree with IEEE-754, 4.3.1 and 4.3.2. The constants
25 /// assigned to the IEEE rounding modes must agree with the values used by
26 /// FLT_ROUNDS (C11, 5.2.4.2.2p8).
27 ///
28 /// This value is packed into bitfield in some cases, including \c FPOptions, so
29 /// the rounding mode values and the special value \c Dynamic must fit into the
30 /// the bit field (now - 3 bits). The value \c Invalid is used only in values
31 /// returned by intrinsics to indicate errors, it should never be stored as
32 /// rounding mode value, so it does not need to fit the bit fields.
33 ///
34 enum class RoundingMode : int8_t {
35   // Rounding mode defined in IEEE-754.
36   TowardZero        = 0,    ///< roundTowardZero.
37   NearestTiesToEven = 1,    ///< roundTiesToEven.
38   TowardPositive    = 2,    ///< roundTowardPositive.
39   TowardNegative    = 3,    ///< roundTowardNegative.
40   NearestTiesToAway = 4,    ///< roundTiesToAway.
41 
42   // Special values.
43   Dynamic = 7,    ///< Denotes mode unknown at compile time.
44   Invalid = -1    ///< Denotes invalid value.
45 };
46 
47 /// Represent subnormal handling kind for floating point instruction inputs and
48 /// outputs.
49 struct DenormalMode {
50   /// Represent handled modes for denormal (aka subnormal) modes in the floating
51   /// point environment.
52   enum DenormalModeKind : int8_t {
53     Invalid = -1,
54 
55     /// IEEE-754 denormal numbers preserved.
56     IEEE,
57 
58     /// The sign of a flushed-to-zero number is preserved in the sign of 0
59     PreserveSign,
60 
61     /// Denormals are flushed to positive zero.
62     PositiveZero
63   };
64 
65   /// Denormal flushing mode for floating point instruction results in the
66   /// default floating point environment.
67   DenormalModeKind Output = DenormalModeKind::Invalid;
68 
69   /// Denormal treatment kind for floating point instruction inputs in the
70   /// default floating-point environment. If this is not DenormalModeKind::IEEE,
71   /// floating-point instructions implicitly treat the input value as 0.
72   DenormalModeKind Input = DenormalModeKind::Invalid;
73 
74   constexpr DenormalMode() = default;
75   constexpr DenormalMode(DenormalModeKind Out, DenormalModeKind In) :
76     Output(Out), Input(In) {}
77 
78 
79   static constexpr DenormalMode getInvalid() {
80     return DenormalMode(DenormalModeKind::Invalid, DenormalModeKind::Invalid);
81   }
82 
83   static constexpr DenormalMode getIEEE() {
84     return DenormalMode(DenormalModeKind::IEEE, DenormalModeKind::IEEE);
85   }
86 
87   static constexpr DenormalMode getPreserveSign() {
88     return DenormalMode(DenormalModeKind::PreserveSign,
89                         DenormalModeKind::PreserveSign);
90   }
91 
92   static constexpr DenormalMode getPositiveZero() {
93     return DenormalMode(DenormalModeKind::PositiveZero,
94                         DenormalModeKind::PositiveZero);
95   }
96 
97   bool operator==(DenormalMode Other) const {
98     return Output == Other.Output && Input == Other.Input;
99   }
100 
101   bool operator!=(DenormalMode Other) const {
102     return !(*this == Other);
103   }
104 
105   bool isSimple() const {
106     return Input == Output;
107   }
108 
109   bool isValid() const {
110     return Output != DenormalModeKind::Invalid &&
111            Input != DenormalModeKind::Invalid;
112   }
113 
114   inline void print(raw_ostream &OS) const;
115 
116   inline std::string str() const {
117     std::string storage;
118     raw_string_ostream OS(storage);
119     print(OS);
120     return OS.str();
121   }
122 };
123 
124 inline raw_ostream& operator<<(raw_ostream &OS, DenormalMode Mode) {
125   Mode.print(OS);
126   return OS;
127 }
128 
129 /// Parse the expected names from the denormal-fp-math attribute.
130 inline DenormalMode::DenormalModeKind
131 parseDenormalFPAttributeComponent(StringRef Str) {
132   // Assume ieee on unspecified attribute.
133   return StringSwitch<DenormalMode::DenormalModeKind>(Str)
134     .Cases("", "ieee", DenormalMode::IEEE)
135     .Case("preserve-sign", DenormalMode::PreserveSign)
136     .Case("positive-zero", DenormalMode::PositiveZero)
137     .Default(DenormalMode::Invalid);
138 }
139 
140 /// Return the name used for the denormal handling mode used by the the
141 /// expected names from the denormal-fp-math attribute.
142 inline StringRef denormalModeKindName(DenormalMode::DenormalModeKind Mode) {
143   switch (Mode) {
144   case DenormalMode::IEEE:
145     return "ieee";
146   case DenormalMode::PreserveSign:
147     return "preserve-sign";
148   case DenormalMode::PositiveZero:
149     return "positive-zero";
150   default:
151     return "";
152   }
153 }
154 
155 /// Returns the denormal mode to use for inputs and outputs.
156 inline DenormalMode parseDenormalFPAttribute(StringRef Str) {
157   StringRef OutputStr, InputStr;
158   std::tie(OutputStr, InputStr) = Str.split(',');
159 
160   DenormalMode Mode;
161   Mode.Output = parseDenormalFPAttributeComponent(OutputStr);
162 
163   // Maintain compatability with old form of the attribute which only specified
164   // one component.
165   Mode.Input = InputStr.empty() ? Mode.Output  :
166                parseDenormalFPAttributeComponent(InputStr);
167 
168   return Mode;
169 }
170 
171 void DenormalMode::print(raw_ostream &OS) const {
172   OS << denormalModeKindName(Output) << ',' << denormalModeKindName(Input);
173 }
174 
175 }
176 
177 #endif // LLVM_FLOATINGPOINTMODE_H
178