Home | History | Annotate | Line # | Download | only in ADT
      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_ADT_FLOATINGPOINTMODE_H
     14 #define LLVM_ADT_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 /// Returns text representation of the given rounding mode.
     48 inline StringRef spell(RoundingMode RM) {
     49   switch (RM) {
     50   case RoundingMode::TowardZero: return "towardzero";
     51   case RoundingMode::NearestTiesToEven: return "tonearest";
     52   case RoundingMode::TowardPositive: return "upward";
     53   case RoundingMode::TowardNegative: return "downward";
     54   case RoundingMode::NearestTiesToAway: return "tonearestaway";
     55   case RoundingMode::Dynamic: return "dynamic";
     56   default: return "invalid";
     57   }
     58 }
     59 
     60 inline raw_ostream &operator << (raw_ostream &OS, RoundingMode RM) {
     61   OS << spell(RM);
     62   return OS;
     63 }
     64 
     65 /// Represent subnormal handling kind for floating point instruction inputs and
     66 /// outputs.
     67 struct DenormalMode {
     68   /// Represent handled modes for denormal (aka subnormal) modes in the floating
     69   /// point environment.
     70   enum DenormalModeKind : int8_t {
     71     Invalid = -1,
     72 
     73     /// IEEE-754 denormal numbers preserved.
     74     IEEE,
     75 
     76     /// The sign of a flushed-to-zero number is preserved in the sign of 0
     77     PreserveSign,
     78 
     79     /// Denormals are flushed to positive zero.
     80     PositiveZero
     81   };
     82 
     83   /// Denormal flushing mode for floating point instruction results in the
     84   /// default floating point environment.
     85   DenormalModeKind Output = DenormalModeKind::Invalid;
     86 
     87   /// Denormal treatment kind for floating point instruction inputs in the
     88   /// default floating-point environment. If this is not DenormalModeKind::IEEE,
     89   /// floating-point instructions implicitly treat the input value as 0.
     90   DenormalModeKind Input = DenormalModeKind::Invalid;
     91 
     92   constexpr DenormalMode() = default;
     93   constexpr DenormalMode(DenormalModeKind Out, DenormalModeKind In) :
     94     Output(Out), Input(In) {}
     95 
     96 
     97   static constexpr DenormalMode getInvalid() {
     98     return DenormalMode(DenormalModeKind::Invalid, DenormalModeKind::Invalid);
     99   }
    100 
    101   static constexpr DenormalMode getIEEE() {
    102     return DenormalMode(DenormalModeKind::IEEE, DenormalModeKind::IEEE);
    103   }
    104 
    105   static constexpr DenormalMode getPreserveSign() {
    106     return DenormalMode(DenormalModeKind::PreserveSign,
    107                         DenormalModeKind::PreserveSign);
    108   }
    109 
    110   static constexpr DenormalMode getPositiveZero() {
    111     return DenormalMode(DenormalModeKind::PositiveZero,
    112                         DenormalModeKind::PositiveZero);
    113   }
    114 
    115   bool operator==(DenormalMode Other) const {
    116     return Output == Other.Output && Input == Other.Input;
    117   }
    118 
    119   bool operator!=(DenormalMode Other) const {
    120     return !(*this == Other);
    121   }
    122 
    123   bool isSimple() const {
    124     return Input == Output;
    125   }
    126 
    127   bool isValid() const {
    128     return Output != DenormalModeKind::Invalid &&
    129            Input != DenormalModeKind::Invalid;
    130   }
    131 
    132   inline void print(raw_ostream &OS) const;
    133 
    134   inline std::string str() const {
    135     std::string storage;
    136     raw_string_ostream OS(storage);
    137     print(OS);
    138     return OS.str();
    139   }
    140 };
    141 
    142 inline raw_ostream& operator<<(raw_ostream &OS, DenormalMode Mode) {
    143   Mode.print(OS);
    144   return OS;
    145 }
    146 
    147 /// Parse the expected names from the denormal-fp-math attribute.
    148 inline DenormalMode::DenormalModeKind
    149 parseDenormalFPAttributeComponent(StringRef Str) {
    150   // Assume ieee on unspecified attribute.
    151   return StringSwitch<DenormalMode::DenormalModeKind>(Str)
    152     .Cases("", "ieee", DenormalMode::IEEE)
    153     .Case("preserve-sign", DenormalMode::PreserveSign)
    154     .Case("positive-zero", DenormalMode::PositiveZero)
    155     .Default(DenormalMode::Invalid);
    156 }
    157 
    158 /// Return the name used for the denormal handling mode used by the the
    159 /// expected names from the denormal-fp-math attribute.
    160 inline StringRef denormalModeKindName(DenormalMode::DenormalModeKind Mode) {
    161   switch (Mode) {
    162   case DenormalMode::IEEE:
    163     return "ieee";
    164   case DenormalMode::PreserveSign:
    165     return "preserve-sign";
    166   case DenormalMode::PositiveZero:
    167     return "positive-zero";
    168   default:
    169     return "";
    170   }
    171 }
    172 
    173 /// Returns the denormal mode to use for inputs and outputs.
    174 inline DenormalMode parseDenormalFPAttribute(StringRef Str) {
    175   StringRef OutputStr, InputStr;
    176   std::tie(OutputStr, InputStr) = Str.split(',');
    177 
    178   DenormalMode Mode;
    179   Mode.Output = parseDenormalFPAttributeComponent(OutputStr);
    180 
    181   // Maintain compatability with old form of the attribute which only specified
    182   // one component.
    183   Mode.Input = InputStr.empty() ? Mode.Output  :
    184                parseDenormalFPAttributeComponent(InputStr);
    185 
    186   return Mode;
    187 }
    188 
    189 void DenormalMode::print(raw_ostream &OS) const {
    190   OS << denormalModeKindName(Output) << ',' << denormalModeKindName(Input);
    191 }
    192 
    193 }
    194 
    195 #endif // LLVM_ADT_FLOATINGPOINTMODE_H
    196