//===- llvm/Support/FloatingPointMode.h -------------------------*- C++ -*-===//
 
//
 
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 
// See https://llvm.org/LICENSE.txt for license information.
 
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 
//
 
//===----------------------------------------------------------------------===//
 
///
 
/// \file
 
/// Utilities for dealing with flags related to floating point properties and
 
/// mode controls.
 
///
 
//===----------------------------------------------------------------------===/
 
 
 
#ifndef LLVM_ADT_FLOATINGPOINTMODE_H
 
#define LLVM_ADT_FLOATINGPOINTMODE_H
 
 
 
#include "llvm/ADT/StringSwitch.h"
 
#include "llvm/Support/raw_ostream.h"
 
 
 
namespace llvm {
 
 
 
/// Rounding mode.
 
///
 
/// Enumerates supported rounding modes, as well as some special values. The set
 
/// of the modes must agree with IEEE-754, 4.3.1 and 4.3.2. The constants
 
/// assigned to the IEEE rounding modes must agree with the values used by
 
/// FLT_ROUNDS (C11, 5.2.4.2.2p8).
 
///
 
/// This value is packed into bitfield in some cases, including \c FPOptions, so
 
/// the rounding mode values and the special value \c Dynamic must fit into the
 
/// the bit field (now - 3 bits). The value \c Invalid is used only in values
 
/// returned by intrinsics to indicate errors, it should never be stored as
 
/// rounding mode value, so it does not need to fit the bit fields.
 
///
 
enum class RoundingMode : int8_t {
 
  // Rounding mode defined in IEEE-754.
 
  TowardZero        = 0,    ///< roundTowardZero.
 
  NearestTiesToEven = 1,    ///< roundTiesToEven.
 
  TowardPositive    = 2,    ///< roundTowardPositive.
 
  TowardNegative    = 3,    ///< roundTowardNegative.
 
  NearestTiesToAway = 4,    ///< roundTiesToAway.
 
 
 
  // Special values.
 
  Dynamic = 7,    ///< Denotes mode unknown at compile time.
 
  Invalid = -1    ///< Denotes invalid value.
 
};
 
 
 
/// Returns text representation of the given rounding mode.
 
inline StringRef spell(RoundingMode RM) {
 
  switch (RM) {
 
  case RoundingMode::TowardZero: return "towardzero";
 
  case RoundingMode::NearestTiesToEven: return "tonearest";
 
  case RoundingMode::TowardPositive: return "upward";
 
  case RoundingMode::TowardNegative: return "downward";
 
  case RoundingMode::NearestTiesToAway: return "tonearestaway";
 
  case RoundingMode::Dynamic: return "dynamic";
 
  default: return "invalid";
 
  }
 
}
 
 
 
inline raw_ostream &operator << (raw_ostream &OS, RoundingMode RM) {
 
  OS << spell(RM);
 
  return OS;
 
}
 
 
 
/// Represent subnormal handling kind for floating point instruction inputs and
 
/// outputs.
 
struct DenormalMode {
 
  /// Represent handled modes for denormal (aka subnormal) modes in the floating
 
  /// point environment.
 
  enum DenormalModeKind : int8_t {
 
    Invalid = -1,
 
 
 
    /// IEEE-754 denormal numbers preserved.
 
    IEEE,
 
 
 
    /// The sign of a flushed-to-zero number is preserved in the sign of 0
 
    PreserveSign,
 
 
 
    /// Denormals are flushed to positive zero.
 
    PositiveZero
 
  };
 
 
 
  /// Denormal flushing mode for floating point instruction results in the
 
  /// default floating point environment.
 
  DenormalModeKind Output = DenormalModeKind::Invalid;
 
 
 
  /// Denormal treatment kind for floating point instruction inputs in the
 
  /// default floating-point environment. If this is not DenormalModeKind::IEEE,
 
  /// floating-point instructions implicitly treat the input value as 0.
 
  DenormalModeKind Input = DenormalModeKind::Invalid;
 
 
 
  constexpr DenormalMode() = default;
 
  constexpr DenormalMode(DenormalModeKind Out, DenormalModeKind In) :
 
    Output(Out), Input(In) {}
 
 
 
 
 
  static constexpr DenormalMode getInvalid() {
 
    return DenormalMode(DenormalModeKind::Invalid, DenormalModeKind::Invalid);
 
  }
 
 
 
  static constexpr DenormalMode getIEEE() {
 
    return DenormalMode(DenormalModeKind::IEEE, DenormalModeKind::IEEE);
 
  }
 
 
 
  static constexpr DenormalMode getPreserveSign() {
 
    return DenormalMode(DenormalModeKind::PreserveSign,
 
                        DenormalModeKind::PreserveSign);
 
  }
 
 
 
  static constexpr DenormalMode getPositiveZero() {
 
    return DenormalMode(DenormalModeKind::PositiveZero,
 
                        DenormalModeKind::PositiveZero);
 
  }
 
 
 
  bool operator==(DenormalMode Other) const {
 
    return Output == Other.Output && Input == Other.Input;
 
  }
 
 
 
  bool operator!=(DenormalMode Other) const {
 
    return !(*this == Other);
 
  }
 
 
 
  bool isSimple() const {
 
    return Input == Output;
 
  }
 
 
 
  bool isValid() const {
 
    return Output != DenormalModeKind::Invalid &&
 
           Input != DenormalModeKind::Invalid;
 
  }
 
 
 
  inline void print(raw_ostream &OS) const;
 
 
 
  inline std::string str() const {
 
    std::string storage;
 
    raw_string_ostream OS(storage);
 
    print(OS);
 
    return OS.str();
 
  }
 
};
 
 
 
inline raw_ostream& operator<<(raw_ostream &OS, DenormalMode Mode) {
 
  Mode.print(OS);
 
  return OS;
 
}
 
 
 
/// Parse the expected names from the denormal-fp-math attribute.
 
inline DenormalMode::DenormalModeKind
 
parseDenormalFPAttributeComponent(StringRef Str) {
 
  // Assume ieee on unspecified attribute.
 
  return StringSwitch<DenormalMode::DenormalModeKind>(Str)
 
    .Cases("", "ieee", DenormalMode::IEEE)
 
    .Case("preserve-sign", DenormalMode::PreserveSign)
 
    .Case("positive-zero", DenormalMode::PositiveZero)
 
    .Default(DenormalMode::Invalid);
 
}
 
 
 
/// Return the name used for the denormal handling mode used by the the
 
/// expected names from the denormal-fp-math attribute.
 
inline StringRef denormalModeKindName(DenormalMode::DenormalModeKind Mode) {
 
  switch (Mode) {
 
  case DenormalMode::IEEE:
 
    return "ieee";
 
  case DenormalMode::PreserveSign:
 
    return "preserve-sign";
 
  case DenormalMode::PositiveZero:
 
    return "positive-zero";
 
  default:
 
    return "";
 
  }
 
}
 
 
 
/// Returns the denormal mode to use for inputs and outputs.
 
inline DenormalMode parseDenormalFPAttribute(StringRef Str) {
 
  StringRef OutputStr, InputStr;
 
  std::tie(OutputStr, InputStr) = Str.split(',');
 
 
 
  DenormalMode Mode;
 
  Mode.Output = parseDenormalFPAttributeComponent(OutputStr);
 
 
 
  // Maintain compatability with old form of the attribute which only specified
 
  // one component.
 
  Mode.Input = InputStr.empty() ? Mode.Output  :
 
               parseDenormalFPAttributeComponent(InputStr);
 
 
 
  return Mode;
 
}
 
 
 
void DenormalMode::print(raw_ostream &OS) const {
 
  OS << denormalModeKindName(Output) << ',' << denormalModeKindName(Input);
 
}
 
 
 
}
 
 
 
/// Floating-point class tests, supported by 'is_fpclass' intrinsic. Actual
 
/// test may be an OR combination of basic tests.
 
enum FPClassTest {
 
  fcSNan = 0x0001,
 
  fcQNan = 0x0002,
 
  fcNegInf = 0x0004,
 
  fcNegNormal = 0x0008,
 
  fcNegSubnormal = 0x0010,
 
  fcNegZero = 0x0020,
 
  fcPosZero = 0x0040,
 
  fcPosSubnormal = 0x0080,
 
  fcPosNormal = 0x0100,
 
  fcPosInf = 0x0200,
 
 
 
  fcNan = fcSNan | fcQNan,
 
  fcInf = fcPosInf | fcNegInf,
 
  fcNormal = fcPosNormal | fcNegNormal,
 
  fcSubnormal = fcPosSubnormal | fcNegSubnormal,
 
  fcZero = fcPosZero | fcNegZero,
 
  fcPosFinite = fcPosNormal | fcPosSubnormal | fcPosZero,
 
  fcNegFinite = fcNegNormal | fcNegSubnormal | fcNegZero,
 
  fcFinite = fcPosFinite | fcNegFinite,
 
  fcAllFlags = fcNan | fcInf | fcFinite
 
};
 
 
 
#endif // LLVM_ADT_FLOATINGPOINTMODE_H