mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 04:02:41 +01:00
Separately track input and output denormal mode
AMDGPU and x86 at least both have separate controls for whether denormal results are flushed on output, and for whether denormals are implicitly treated as 0 as an input. The current DAGCombiner use only really cares about the input treatment of denormals.
This commit is contained in:
parent
25f7d09947
commit
0e9ab3b9f6
@ -1820,12 +1820,21 @@ example:
|
|||||||
not introduce any new floating-point instructions that may trap.
|
not introduce any new floating-point instructions that may trap.
|
||||||
|
|
||||||
``"denormal-fp-math"``
|
``"denormal-fp-math"``
|
||||||
This indicates the denormal (subnormal) handling that may be assumed
|
This indicates the denormal (subnormal) handling that may be
|
||||||
for the default floating-point environment. This may be one of
|
assumed for the default floating-point environment. This is a
|
||||||
``"ieee"``, ``"preserve-sign"``, or ``"positive-zero"``. If this
|
comma separated pair. The elements may be one of ``"ieee"``,
|
||||||
is attribute is not specified, the default is ``"ieee"``. If the
|
``"preserve-sign"``, or ``"positive-zero"``. The first entry
|
||||||
mode is ``"preserve-sign"``, or ``"positive-zero"``, denormal
|
indicates the flushing mode for the result of floating point
|
||||||
outputs may be flushed to zero by standard floating point
|
operations. The second indicates the handling of denormal inputs
|
||||||
|
to floating point instructions. For compatability with older
|
||||||
|
bitcode, if the second value is omitted, both input and output
|
||||||
|
modes will assume the same mode.
|
||||||
|
|
||||||
|
If this is attribute is not specified, the default is
|
||||||
|
``"ieee,ieee"``.
|
||||||
|
|
||||||
|
If the output mode is ``"preserve-sign"``, or ``"positive-zero"``,
|
||||||
|
denormal outputs may be flushed to zero by standard floating-point
|
||||||
operations. It is not mandated that flushing to zero occurs, but if
|
operations. It is not mandated that flushing to zero occurs, but if
|
||||||
a denormal output is flushed to zero, it must respect the sign
|
a denormal output is flushed to zero, it must respect the sign
|
||||||
mode. Not all targets support all modes. While this indicates the
|
mode. Not all targets support all modes. While this indicates the
|
||||||
@ -1834,6 +1843,12 @@ example:
|
|||||||
consistent. User or platform code is expected to set the floating
|
consistent. User or platform code is expected to set the floating
|
||||||
point mode appropriately before function entry.
|
point mode appropriately before function entry.
|
||||||
|
|
||||||
|
If the input mode is ``"preserve-sign"``, or ``"positive-zero"``, a
|
||||||
|
floating-point operation must treat any input denormal value as
|
||||||
|
zero. In some situations, if an instruction does not respect this
|
||||||
|
mode, the input may need to be converted to 0 as if by
|
||||||
|
``@llvm.canonicalize`` during lowering for correctness.
|
||||||
|
|
||||||
``"denormal-fp-math-f32"``
|
``"denormal-fp-math-f32"``
|
||||||
Same as ``"denormal-fp-math"``, but only controls the behavior of
|
Same as ``"denormal-fp-math"``, but only controls the behavior of
|
||||||
the 32-bit float type (or vectors of 32-bit floats). If both are
|
the 32-bit float type (or vectors of 32-bit floats). If both are
|
||||||
@ -15593,9 +15608,9 @@ Each of these intrinsics corresponds to a normal floating-point operation. The
|
|||||||
data arguments and the return value are the same as the corresponding FP
|
data arguments and the return value are the same as the corresponding FP
|
||||||
operation.
|
operation.
|
||||||
|
|
||||||
The rounding mode argument is a metadata string specifying what
|
The rounding mode argument is a metadata string specifying what
|
||||||
assumptions, if any, the optimizer can make when transforming constant
|
assumptions, if any, the optimizer can make when transforming constant
|
||||||
values. Some constrained FP intrinsics omit this argument. If required
|
values. Some constrained FP intrinsics omit this argument. If required
|
||||||
by the intrinsic, this argument must be one of the following strings:
|
by the intrinsic, this argument must be one of the following strings:
|
||||||
|
|
||||||
::
|
::
|
||||||
@ -15911,7 +15926,7 @@ Syntax:
|
|||||||
Overview:
|
Overview:
|
||||||
"""""""""
|
"""""""""
|
||||||
|
|
||||||
The '``llvm.experimental.constrained.fptoui``' intrinsic converts a
|
The '``llvm.experimental.constrained.fptoui``' intrinsic converts a
|
||||||
floating-point ``value`` to its unsigned integer equivalent of type ``ty2``.
|
floating-point ``value`` to its unsigned integer equivalent of type ``ty2``.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
@ -15944,7 +15959,7 @@ Syntax:
|
|||||||
Overview:
|
Overview:
|
||||||
"""""""""
|
"""""""""
|
||||||
|
|
||||||
The '``llvm.experimental.constrained.fptosi``' intrinsic converts
|
The '``llvm.experimental.constrained.fptosi``' intrinsic converts
|
||||||
:ref:`floating-point <t_floating>` ``value`` to type ``ty2``.
|
:ref:`floating-point <t_floating>` ``value`` to type ``ty2``.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
@ -15952,7 +15967,7 @@ Arguments:
|
|||||||
|
|
||||||
The first argument to the '``llvm.experimental.constrained.fptosi``'
|
The first argument to the '``llvm.experimental.constrained.fptosi``'
|
||||||
intrinsic must be :ref:`floating point <t_floating>` or :ref:`vector
|
intrinsic must be :ref:`floating point <t_floating>` or :ref:`vector
|
||||||
<t_vector>` of floating point values.
|
<t_vector>` of floating point values.
|
||||||
|
|
||||||
The second argument specifies the exception behavior as described above.
|
The second argument specifies the exception behavior as described above.
|
||||||
|
|
||||||
@ -16061,7 +16076,7 @@ intrinsic must be :ref:`floating point <t_floating>` or :ref:`vector
|
|||||||
<t_vector>` of floating point values. This argument must be larger in size
|
<t_vector>` of floating point values. This argument must be larger in size
|
||||||
than the result.
|
than the result.
|
||||||
|
|
||||||
The second and third arguments specify the rounding mode and exception
|
The second and third arguments specify the rounding mode and exception
|
||||||
behavior as described above.
|
behavior as described above.
|
||||||
|
|
||||||
Semantics:
|
Semantics:
|
||||||
@ -16085,7 +16100,7 @@ Syntax:
|
|||||||
Overview:
|
Overview:
|
||||||
"""""""""
|
"""""""""
|
||||||
|
|
||||||
The '``llvm.experimental.constrained.fpext``' intrinsic extends a
|
The '``llvm.experimental.constrained.fpext``' intrinsic extends a
|
||||||
floating-point ``value`` to a larger floating-point value.
|
floating-point ``value`` to a larger floating-point value.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
@ -17102,7 +17117,7 @@ Syntax:
|
|||||||
declare <inttype>
|
declare <inttype>
|
||||||
@llvm.experimental.constrained.llround(<fptype> <op1>,
|
@llvm.experimental.constrained.llround(<fptype> <op1>,
|
||||||
metadata <exception behavior>)
|
metadata <exception behavior>)
|
||||||
|
|
||||||
Overview:
|
Overview:
|
||||||
"""""""""
|
"""""""""
|
||||||
|
|
||||||
|
@ -14,28 +14,97 @@
|
|||||||
#define LLVM_FLOATINGPOINTMODE_H
|
#define LLVM_FLOATINGPOINTMODE_H
|
||||||
|
|
||||||
#include "llvm/ADT/StringSwitch.h"
|
#include "llvm/ADT/StringSwitch.h"
|
||||||
|
#include "llvm/Support/raw_ostream.h"
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
|
||||||
/// Represent handled modes for denormal (aka subnormal) modes in the floating
|
/// Represent ssubnormal handling kind for floating point instruction inputs and
|
||||||
/// point environment.
|
/// outputs.
|
||||||
enum class DenormalMode {
|
struct DenormalMode {
|
||||||
Invalid = -1,
|
/// Represent handled modes for denormal (aka subnormal) modes in the floating
|
||||||
|
/// point environment.
|
||||||
|
enum DenormalModeKind : char {
|
||||||
|
Invalid = -1,
|
||||||
|
|
||||||
/// IEEE-754 denormal numbers preserved.
|
/// IEEE-754 denormal numbers preserved.
|
||||||
IEEE,
|
IEEE,
|
||||||
|
|
||||||
/// The sign of a flushed-to-zero number is preserved in the sign of 0
|
/// The sign of a flushed-to-zero number is preserved in the sign of 0
|
||||||
PreserveSign,
|
PreserveSign,
|
||||||
|
|
||||||
/// Denormals are flushed to positive zero.
|
/// Denormals are flushed to positive zero.
|
||||||
PositiveZero
|
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;
|
||||||
|
|
||||||
|
DenormalMode() = default;
|
||||||
|
DenormalMode(DenormalModeKind Out, DenormalModeKind In) :
|
||||||
|
Output(Out), Input(In) {}
|
||||||
|
|
||||||
|
|
||||||
|
static DenormalMode getInvalid() {
|
||||||
|
return DenormalMode(DenormalModeKind::Invalid, DenormalModeKind::Invalid);
|
||||||
|
}
|
||||||
|
|
||||||
|
static DenormalMode getIEEE() {
|
||||||
|
return DenormalMode(DenormalModeKind::IEEE, DenormalModeKind::IEEE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static DenormalMode getPreserveSign() {
|
||||||
|
return DenormalMode(DenormalModeKind::PreserveSign,
|
||||||
|
DenormalModeKind::PreserveSign);
|
||||||
|
}
|
||||||
|
|
||||||
|
static 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.
|
/// Parse the expected names from the denormal-fp-math attribute.
|
||||||
inline DenormalMode parseDenormalFPAttribute(StringRef Str) {
|
inline DenormalMode::DenormalModeKind
|
||||||
|
parseDenormalFPAttributeComponent(StringRef Str) {
|
||||||
// Assume ieee on unspecified attribute.
|
// Assume ieee on unspecified attribute.
|
||||||
return StringSwitch<DenormalMode>(Str)
|
return StringSwitch<DenormalMode::DenormalModeKind>(Str)
|
||||||
.Cases("", "ieee", DenormalMode::IEEE)
|
.Cases("", "ieee", DenormalMode::IEEE)
|
||||||
.Case("preserve-sign", DenormalMode::PreserveSign)
|
.Case("preserve-sign", DenormalMode::PreserveSign)
|
||||||
.Case("positive-zero", DenormalMode::PositiveZero)
|
.Case("positive-zero", DenormalMode::PositiveZero)
|
||||||
@ -44,7 +113,7 @@ inline DenormalMode parseDenormalFPAttribute(StringRef Str) {
|
|||||||
|
|
||||||
/// Return the name used for the denormal handling mode used by the the
|
/// Return the name used for the denormal handling mode used by the the
|
||||||
/// expected names from the denormal-fp-math attribute.
|
/// expected names from the denormal-fp-math attribute.
|
||||||
inline StringRef denormalModeName(DenormalMode Mode) {
|
inline StringRef denormalModeKindName(DenormalMode::DenormalModeKind Mode) {
|
||||||
switch (Mode) {
|
switch (Mode) {
|
||||||
case DenormalMode::IEEE:
|
case DenormalMode::IEEE:
|
||||||
return "ieee";
|
return "ieee";
|
||||||
@ -57,6 +126,26 @@ inline StringRef denormalModeName(DenormalMode Mode) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // LLVM_FLOATINGPOINTMODE_H
|
#endif // LLVM_FLOATINGPOINTMODE_H
|
||||||
|
@ -290,7 +290,7 @@ DenormalMode MachineFunction::getDenormalMode(const fltSemantics &FPType) const
|
|||||||
// target by default.
|
// target by default.
|
||||||
StringRef Val = Attr.getValueAsString();
|
StringRef Val = Attr.getValueAsString();
|
||||||
if (Val.empty())
|
if (Val.empty())
|
||||||
return DenormalMode::Invalid;
|
return DenormalMode::getInvalid();
|
||||||
|
|
||||||
return parseDenormalFPAttribute(Val);
|
return parseDenormalFPAttribute(Val);
|
||||||
}
|
}
|
||||||
|
@ -6605,9 +6605,9 @@ SDValue DAGCombiner::MatchStoreCombine(StoreSDNode *N) {
|
|||||||
if (LegalOperations && !TLI.isOperationLegal(ISD::STORE, VT))
|
if (LegalOperations && !TLI.isOperationLegal(ISD::STORE, VT))
|
||||||
return SDValue();
|
return SDValue();
|
||||||
|
|
||||||
// Check if all the bytes of the combined value we are looking at are stored
|
// Check if all the bytes of the combined value we are looking at are stored
|
||||||
// to the same base address. Collect bytes offsets from Base address into
|
// to the same base address. Collect bytes offsets from Base address into
|
||||||
// ByteOffsets.
|
// ByteOffsets.
|
||||||
SDValue CombinedValue;
|
SDValue CombinedValue;
|
||||||
SmallVector<int64_t, 8> ByteOffsets(Width, INT64_MAX);
|
SmallVector<int64_t, 8> ByteOffsets(Width, INT64_MAX);
|
||||||
int64_t FirstOffset = INT64_MAX;
|
int64_t FirstOffset = INT64_MAX;
|
||||||
@ -6627,15 +6627,15 @@ SDValue DAGCombiner::MatchStoreCombine(StoreSDNode *N) {
|
|||||||
Value.getOpcode() == ISD::SRA) {
|
Value.getOpcode() == ISD::SRA) {
|
||||||
ConstantSDNode *ShiftOffset =
|
ConstantSDNode *ShiftOffset =
|
||||||
dyn_cast<ConstantSDNode>(Value.getOperand(1));
|
dyn_cast<ConstantSDNode>(Value.getOperand(1));
|
||||||
// Trying to match the following pattern. The shift offset must be
|
// Trying to match the following pattern. The shift offset must be
|
||||||
// a constant and a multiple of 8. It is the byte offset in "y".
|
// a constant and a multiple of 8. It is the byte offset in "y".
|
||||||
//
|
//
|
||||||
// x = srl y, offset
|
// x = srl y, offset
|
||||||
// i8 z = trunc x
|
// i8 z = trunc x
|
||||||
// store z, ...
|
// store z, ...
|
||||||
if (!ShiftOffset || (ShiftOffset->getSExtValue() % 8))
|
if (!ShiftOffset || (ShiftOffset->getSExtValue() % 8))
|
||||||
return SDValue();
|
return SDValue();
|
||||||
|
|
||||||
Offset = ShiftOffset->getSExtValue()/8;
|
Offset = ShiftOffset->getSExtValue()/8;
|
||||||
Value = Value.getOperand(0);
|
Value = Value.getOperand(0);
|
||||||
}
|
}
|
||||||
@ -6680,7 +6680,7 @@ SDValue DAGCombiner::MatchStoreCombine(StoreSDNode *N) {
|
|||||||
assert(FirstOffset != INT64_MAX && "First byte offset must be set");
|
assert(FirstOffset != INT64_MAX && "First byte offset must be set");
|
||||||
assert(FirstStore && "First store must be set");
|
assert(FirstStore && "First store must be set");
|
||||||
|
|
||||||
// Check if the bytes of the combined value we are looking at match with
|
// Check if the bytes of the combined value we are looking at match with
|
||||||
// either big or little endian value store.
|
// either big or little endian value store.
|
||||||
Optional<bool> IsBigEndian = isBigEndian(ByteOffsets, FirstOffset);
|
Optional<bool> IsBigEndian = isBigEndian(ByteOffsets, FirstOffset);
|
||||||
if (!IsBigEndian.hasValue())
|
if (!IsBigEndian.hasValue())
|
||||||
@ -8619,7 +8619,7 @@ SDValue DAGCombiner::visitSELECT(SDNode *N) {
|
|||||||
// Create the actual or node if we can generate good code for it.
|
// Create the actual or node if we can generate good code for it.
|
||||||
if (!normalizeToSequence) {
|
if (!normalizeToSequence) {
|
||||||
SDValue Or = DAG.getNode(ISD::OR, DL, N0.getValueType(), N0, N2_0);
|
SDValue Or = DAG.getNode(ISD::OR, DL, N0.getValueType(), N0, N2_0);
|
||||||
return DAG.getNode(ISD::SELECT, DL, N1.getValueType(), Or, N1,
|
return DAG.getNode(ISD::SELECT, DL, N1.getValueType(), Or, N1,
|
||||||
N2_2, Flags);
|
N2_2, Flags);
|
||||||
}
|
}
|
||||||
// Otherwise see if we can optimize to a better pattern.
|
// Otherwise see if we can optimize to a better pattern.
|
||||||
@ -10490,7 +10490,7 @@ SDValue DAGCombiner::ReduceLoadWidth(SDNode *N) {
|
|||||||
|
|
||||||
LoadSDNode *LN0 = cast<LoadSDNode>(N0);
|
LoadSDNode *LN0 = cast<LoadSDNode>(N0);
|
||||||
// Reducing the width of a volatile load is illegal. For atomics, we may be
|
// Reducing the width of a volatile load is illegal. For atomics, we may be
|
||||||
// able to reduce the width provided we never widen again. (see D66309)
|
// able to reduce the width provided we never widen again. (see D66309)
|
||||||
if (!LN0->isSimple() ||
|
if (!LN0->isSimple() ||
|
||||||
!isLegalNarrowLdSt(LN0, ExtType, ExtVT, ShAmt))
|
!isLegalNarrowLdSt(LN0, ExtType, ExtVT, ShAmt))
|
||||||
return SDValue();
|
return SDValue();
|
||||||
@ -20820,7 +20820,10 @@ SDValue DAGCombiner::buildSqrtEstimateImpl(SDValue Op, SDNodeFlags Flags,
|
|||||||
EVT CCVT = getSetCCResultType(VT);
|
EVT CCVT = getSetCCResultType(VT);
|
||||||
ISD::NodeType SelOpcode = VT.isVector() ? ISD::VSELECT : ISD::SELECT;
|
ISD::NodeType SelOpcode = VT.isVector() ? ISD::VSELECT : ISD::SELECT;
|
||||||
DenormalMode DenormMode = DAG.getDenormalMode(VT);
|
DenormalMode DenormMode = DAG.getDenormalMode(VT);
|
||||||
if (DenormMode == DenormalMode::IEEE) {
|
if (DenormMode.Input == DenormalMode::IEEE) {
|
||||||
|
// This is specifically a check for the handling of denormal inputs,
|
||||||
|
// not the result.
|
||||||
|
|
||||||
// fabs(X) < SmallestNormal ? 0.0 : Est
|
// fabs(X) < SmallestNormal ? 0.0 : Est
|
||||||
const fltSemantics &FltSem = DAG.EVTToAPFloatSemantics(VT);
|
const fltSemantics &FltSem = DAG.EVTToAPFloatSemantics(VT);
|
||||||
APFloat SmallestNorm = APFloat::getSmallestNormalized(FltSem);
|
APFloat SmallestNorm = APFloat::getSmallestNormalized(FltSem);
|
||||||
|
@ -123,7 +123,7 @@ bool NVPTXTargetLowering::useF32FTZ(const MachineFunction &MF) const {
|
|||||||
return FtzEnabled;
|
return FtzEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
return MF.getDenormalMode(APFloat::IEEEsingle()) ==
|
return MF.getDenormalMode(APFloat::IEEEsingle()).Output ==
|
||||||
DenormalMode::PreserveSign;
|
DenormalMode::PreserveSign;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1706,7 +1706,8 @@ static Instruction *SimplifyNVVMIntrinsic(IntrinsicInst *II, InstCombiner &IC) {
|
|||||||
StringRef Attr = II->getFunction()
|
StringRef Attr = II->getFunction()
|
||||||
->getFnAttribute("denormal-fp-math-f32")
|
->getFnAttribute("denormal-fp-math-f32")
|
||||||
.getValueAsString();
|
.getValueAsString();
|
||||||
bool FtzEnabled = parseDenormalFPAttribute(Attr) != DenormalMode::IEEE;
|
DenormalMode Mode = parseDenormalFPAttribute(Attr);
|
||||||
|
bool FtzEnabled = Mode.Output != DenormalMode::IEEE;
|
||||||
|
|
||||||
if (FtzEnabled != (Action.FtzRequirement == FTZ_MustBeOn))
|
if (FtzEnabled != (Action.FtzRequirement == FTZ_MustBeOn))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -13,21 +13,122 @@ using namespace llvm;
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
TEST(FloatingPointModeTest, ParseDenormalFPAttribute) {
|
TEST(FloatingPointModeTest, ParseDenormalFPAttributeComponent) {
|
||||||
EXPECT_EQ(DenormalMode::IEEE, parseDenormalFPAttribute("ieee"));
|
EXPECT_EQ(DenormalMode::IEEE, parseDenormalFPAttributeComponent("ieee"));
|
||||||
EXPECT_EQ(DenormalMode::IEEE, parseDenormalFPAttribute(""));
|
EXPECT_EQ(DenormalMode::IEEE, parseDenormalFPAttributeComponent(""));
|
||||||
EXPECT_EQ(DenormalMode::PreserveSign,
|
EXPECT_EQ(DenormalMode::PreserveSign,
|
||||||
parseDenormalFPAttribute("preserve-sign"));
|
parseDenormalFPAttributeComponent("preserve-sign"));
|
||||||
EXPECT_EQ(DenormalMode::PositiveZero,
|
EXPECT_EQ(DenormalMode::PositiveZero,
|
||||||
parseDenormalFPAttribute("positive-zero"));
|
parseDenormalFPAttributeComponent("positive-zero"));
|
||||||
EXPECT_EQ(DenormalMode::Invalid, parseDenormalFPAttribute("foo"));
|
EXPECT_EQ(DenormalMode::Invalid, parseDenormalFPAttributeComponent("foo"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FloatingPointModeTest, DenormalAttributeName) {
|
TEST(FloatingPointModeTest, DenormalAttributeName) {
|
||||||
EXPECT_EQ("ieee", denormalModeName(DenormalMode::IEEE));
|
EXPECT_EQ("ieee", denormalModeKindName(DenormalMode::IEEE));
|
||||||
EXPECT_EQ("preserve-sign", denormalModeName(DenormalMode::PreserveSign));
|
EXPECT_EQ("preserve-sign", denormalModeKindName(DenormalMode::PreserveSign));
|
||||||
EXPECT_EQ("positive-zero", denormalModeName(DenormalMode::PositiveZero));
|
EXPECT_EQ("positive-zero", denormalModeKindName(DenormalMode::PositiveZero));
|
||||||
EXPECT_EQ("", denormalModeName(DenormalMode::Invalid));
|
EXPECT_EQ("", denormalModeKindName(DenormalMode::Invalid));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FloatingPointModeTest, ParseDenormalFPAttribute) {
|
||||||
|
EXPECT_EQ(DenormalMode(DenormalMode::IEEE, DenormalMode::IEEE),
|
||||||
|
parseDenormalFPAttribute("ieee"));
|
||||||
|
EXPECT_EQ(DenormalMode(DenormalMode::IEEE, DenormalMode::IEEE),
|
||||||
|
parseDenormalFPAttribute("ieee,ieee"));
|
||||||
|
EXPECT_EQ(DenormalMode(DenormalMode::IEEE, DenormalMode::IEEE),
|
||||||
|
parseDenormalFPAttribute("ieee,"));
|
||||||
|
EXPECT_EQ(DenormalMode(DenormalMode::IEEE, DenormalMode::IEEE),
|
||||||
|
parseDenormalFPAttribute(""));
|
||||||
|
EXPECT_EQ(DenormalMode(DenormalMode::IEEE, DenormalMode::IEEE),
|
||||||
|
parseDenormalFPAttribute(","));
|
||||||
|
|
||||||
|
EXPECT_EQ(DenormalMode(DenormalMode::PreserveSign, DenormalMode::PreserveSign),
|
||||||
|
parseDenormalFPAttribute("preserve-sign"));
|
||||||
|
EXPECT_EQ(DenormalMode(DenormalMode::PreserveSign, DenormalMode::PreserveSign),
|
||||||
|
parseDenormalFPAttribute("preserve-sign,"));
|
||||||
|
EXPECT_EQ(DenormalMode(DenormalMode::PreserveSign, DenormalMode::PreserveSign),
|
||||||
|
parseDenormalFPAttribute("preserve-sign,preserve-sign"));
|
||||||
|
|
||||||
|
EXPECT_EQ(DenormalMode(DenormalMode::PositiveZero, DenormalMode::PositiveZero),
|
||||||
|
parseDenormalFPAttribute("positive-zero"));
|
||||||
|
EXPECT_EQ(DenormalMode(DenormalMode::PositiveZero, DenormalMode::PositiveZero),
|
||||||
|
parseDenormalFPAttribute("positive-zero,positive-zero"));
|
||||||
|
|
||||||
|
|
||||||
|
EXPECT_EQ(DenormalMode(DenormalMode::IEEE, DenormalMode::PositiveZero),
|
||||||
|
parseDenormalFPAttribute("ieee,positive-zero"));
|
||||||
|
EXPECT_EQ(DenormalMode(DenormalMode::PositiveZero, DenormalMode::IEEE),
|
||||||
|
parseDenormalFPAttribute("positive-zero,ieee"));
|
||||||
|
|
||||||
|
EXPECT_EQ(DenormalMode(DenormalMode::PreserveSign, DenormalMode::IEEE),
|
||||||
|
parseDenormalFPAttribute("preserve-sign,ieee"));
|
||||||
|
EXPECT_EQ(DenormalMode(DenormalMode::IEEE, DenormalMode::PreserveSign),
|
||||||
|
parseDenormalFPAttribute("ieee,preserve-sign"));
|
||||||
|
|
||||||
|
|
||||||
|
EXPECT_EQ(DenormalMode(DenormalMode::Invalid, DenormalMode::Invalid),
|
||||||
|
parseDenormalFPAttribute("foo"));
|
||||||
|
EXPECT_EQ(DenormalMode(DenormalMode::Invalid, DenormalMode::Invalid),
|
||||||
|
parseDenormalFPAttribute("foo,foo"));
|
||||||
|
EXPECT_EQ(DenormalMode(DenormalMode::Invalid, DenormalMode::Invalid),
|
||||||
|
parseDenormalFPAttribute("foo,bar"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FloatingPointModeTest, RenderDenormalFPAttribute) {
|
||||||
|
EXPECT_EQ(DenormalMode(DenormalMode::Invalid, DenormalMode::Invalid),
|
||||||
|
parseDenormalFPAttribute("foo"));
|
||||||
|
|
||||||
|
EXPECT_EQ("ieee,ieee",
|
||||||
|
DenormalMode(DenormalMode::IEEE, DenormalMode::IEEE).str());
|
||||||
|
EXPECT_EQ(",",
|
||||||
|
DenormalMode(DenormalMode::Invalid, DenormalMode::Invalid).str());
|
||||||
|
|
||||||
|
EXPECT_EQ(
|
||||||
|
"preserve-sign,preserve-sign",
|
||||||
|
DenormalMode(DenormalMode::PreserveSign, DenormalMode::PreserveSign).str());
|
||||||
|
|
||||||
|
EXPECT_EQ(
|
||||||
|
"positive-zero,positive-zero",
|
||||||
|
DenormalMode(DenormalMode::PositiveZero, DenormalMode::PositiveZero).str());
|
||||||
|
|
||||||
|
EXPECT_EQ(
|
||||||
|
"ieee,preserve-sign",
|
||||||
|
DenormalMode(DenormalMode::IEEE, DenormalMode::PreserveSign).str());
|
||||||
|
|
||||||
|
EXPECT_EQ(
|
||||||
|
"preserve-sign,ieee",
|
||||||
|
DenormalMode(DenormalMode::PreserveSign, DenormalMode::IEEE).str());
|
||||||
|
|
||||||
|
EXPECT_EQ(
|
||||||
|
"preserve-sign,positive-zero",
|
||||||
|
DenormalMode(DenormalMode::PreserveSign, DenormalMode::PositiveZero).str());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FloatingPointModeTest, DenormalModeIsSimple) {
|
||||||
|
EXPECT_TRUE(DenormalMode(DenormalMode::IEEE, DenormalMode::IEEE).isSimple());
|
||||||
|
EXPECT_FALSE(DenormalMode(DenormalMode::IEEE,
|
||||||
|
DenormalMode::Invalid).isSimple());
|
||||||
|
EXPECT_FALSE(DenormalMode(DenormalMode::PreserveSign,
|
||||||
|
DenormalMode::PositiveZero).isSimple());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FloatingPointModeTest, DenormalModeIsValid) {
|
||||||
|
EXPECT_TRUE(DenormalMode(DenormalMode::IEEE, DenormalMode::IEEE).isValid());
|
||||||
|
EXPECT_FALSE(DenormalMode(DenormalMode::IEEE, DenormalMode::Invalid).isValid());
|
||||||
|
EXPECT_FALSE(DenormalMode(DenormalMode::Invalid, DenormalMode::IEEE).isValid());
|
||||||
|
EXPECT_FALSE(DenormalMode(DenormalMode::Invalid,
|
||||||
|
DenormalMode::Invalid).isValid());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FloatingPointModeTest, DenormalModeConstructor) {
|
||||||
|
EXPECT_EQ(DenormalMode(DenormalMode::Invalid, DenormalMode::Invalid),
|
||||||
|
DenormalMode::getInvalid());
|
||||||
|
EXPECT_EQ(DenormalMode(DenormalMode::IEEE, DenormalMode::IEEE),
|
||||||
|
DenormalMode::getIEEE());
|
||||||
|
EXPECT_EQ(DenormalMode(DenormalMode::PreserveSign, DenormalMode::PreserveSign),
|
||||||
|
DenormalMode::getPreserveSign());
|
||||||
|
EXPECT_EQ(DenormalMode(DenormalMode::PositiveZero, DenormalMode::PositiveZero),
|
||||||
|
DenormalMode::getPositiveZero());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user