|
8 | 8 |
|
9 | 9 | #include "llvm/IR/ConstantFPRange.h" |
10 | 10 | #include "llvm/ADT/APFloat.h" |
| 11 | +#include "llvm/ADT/FloatingPointMode.h" |
11 | 12 | #include "llvm/IR/Instructions.h" |
12 | 13 | #include "llvm/IR/Operator.h" |
13 | 14 | #include "gtest/gtest.h" |
@@ -1065,4 +1066,70 @@ TEST_F(ConstantFPRangeTest, sub) { |
1065 | 1066 | #endif |
1066 | 1067 | } |
1067 | 1068 |
|
| 1069 | +TEST_F(ConstantFPRangeTest, flushDenormals) { |
| 1070 | + const fltSemantics &FP8Sem = APFloat::Float8E4M3(); |
| 1071 | + APFloat NormalVal = APFloat::getSmallestNormalized(FP8Sem); |
| 1072 | + APFloat Subnormal1 = NormalVal; |
| 1073 | + Subnormal1.next(/*nextDown=*/true); |
| 1074 | + APFloat Subnormal2 = APFloat::getSmallest(FP8Sem); |
| 1075 | + APFloat ZeroVal = APFloat::getZero(FP8Sem); |
| 1076 | + APFloat EdgeValues[8] = {-NormalVal, -Subnormal1, -Subnormal2, -ZeroVal, |
| 1077 | + ZeroVal, Subnormal2, Subnormal1, NormalVal}; |
| 1078 | + constexpr DenormalMode::DenormalModeKind Modes[4] = { |
| 1079 | + DenormalMode::IEEE, DenormalMode::PreserveSign, |
| 1080 | + DenormalMode::PositiveZero, DenormalMode::Dynamic}; |
| 1081 | + for (uint32_t I = 0; I != 8; ++I) { |
| 1082 | + for (uint32_t J = I; J != 8; ++J) { |
| 1083 | + ConstantFPRange OriginCR = |
| 1084 | + ConstantFPRange::getNonNaN(EdgeValues[I], EdgeValues[J]); |
| 1085 | + for (auto Mode : Modes) { |
| 1086 | + StringRef ModeName = denormalModeKindName(Mode); |
| 1087 | + ConstantFPRange FlushedCR = OriginCR; |
| 1088 | + FlushedCR.flushDenormals(Mode); |
| 1089 | + |
| 1090 | + ConstantFPRange Expected = ConstantFPRange::getEmpty(FP8Sem); |
| 1091 | + auto CheckFlushedV = [&](const APFloat &V, const APFloat &FlushedV) { |
| 1092 | + EXPECT_TRUE(FlushedCR.contains(FlushedV)) |
| 1093 | + << "Wrong result for flushDenormal(" << V << ", " << ModeName |
| 1094 | + << "). The result " << FlushedCR << " should contain " |
| 1095 | + << FlushedV; |
| 1096 | + if (!Expected.contains(FlushedV)) |
| 1097 | + Expected = Expected.unionWith(ConstantFPRange(FlushedV)); |
| 1098 | + }; |
| 1099 | + EnumerateValuesInConstantFPRange( |
| 1100 | + OriginCR, |
| 1101 | + [&](const APFloat &V) { |
| 1102 | + if (V.isDenormal()) { |
| 1103 | + switch (Mode) { |
| 1104 | + case DenormalMode::IEEE: |
| 1105 | + break; |
| 1106 | + case DenormalMode::PreserveSign: |
| 1107 | + CheckFlushedV(V, APFloat::getZero(FP8Sem, V.isNegative())); |
| 1108 | + break; |
| 1109 | + case DenormalMode::PositiveZero: |
| 1110 | + CheckFlushedV(V, APFloat::getZero(FP8Sem)); |
| 1111 | + break; |
| 1112 | + case DenormalMode::Dynamic: |
| 1113 | + // PreserveSign |
| 1114 | + CheckFlushedV(V, APFloat::getZero(FP8Sem, V.isNegative())); |
| 1115 | + // PositiveZero |
| 1116 | + CheckFlushedV(V, APFloat::getZero(FP8Sem)); |
| 1117 | + break; |
| 1118 | + default: |
| 1119 | + llvm_unreachable("unknown denormal mode"); |
| 1120 | + } |
| 1121 | + } |
| 1122 | + // It is not mandated that flushing to zero occurs. |
| 1123 | + CheckFlushedV(V, V); |
| 1124 | + }, |
| 1125 | + /*IgnoreNaNPayload=*/true); |
| 1126 | + EXPECT_EQ(FlushedCR, Expected) |
| 1127 | + << "Suboptimal result for flushDenormal(" << OriginCR << ", " |
| 1128 | + << ModeName << "). Expected " << Expected << ", but got " |
| 1129 | + << FlushedCR; |
| 1130 | + } |
| 1131 | + } |
| 1132 | + } |
| 1133 | +} |
| 1134 | + |
1068 | 1135 | } // anonymous namespace |
0 commit comments