diff options
Diffstat (limited to 'unittests')
22 files changed, 1387 insertions, 236 deletions
diff --git a/unittests/ADT/APFloatTest.cpp b/unittests/ADT/APFloatTest.cpp index 2789835..e1b9158 100644 --- a/unittests/ADT/APFloatTest.cpp +++ b/unittests/ADT/APFloatTest.cpp @@ -33,6 +33,449 @@ static std::string convertToString(double d, unsigned Prec, unsigned Pad) { namespace { +TEST(APFloatTest, isSignaling) { + // We test qNaN, -qNaN, +sNaN, -sNaN with and without payloads. *NOTE* The + // positive/negative distinction is included only since the getQNaN/getSNaN + // API provides the option. + APInt payload = APInt::getOneBitSet(4, 2); + EXPECT_FALSE(APFloat::getQNaN(APFloat::IEEEsingle, false).isSignaling()); + EXPECT_FALSE(APFloat::getQNaN(APFloat::IEEEsingle, true).isSignaling()); + EXPECT_FALSE(APFloat::getQNaN(APFloat::IEEEsingle, false, &payload).isSignaling()); + EXPECT_FALSE(APFloat::getQNaN(APFloat::IEEEsingle, true, &payload).isSignaling()); + EXPECT_TRUE(APFloat::getSNaN(APFloat::IEEEsingle, false).isSignaling()); + EXPECT_TRUE(APFloat::getSNaN(APFloat::IEEEsingle, true).isSignaling()); + EXPECT_TRUE(APFloat::getSNaN(APFloat::IEEEsingle, false, &payload).isSignaling()); + EXPECT_TRUE(APFloat::getSNaN(APFloat::IEEEsingle, true, &payload).isSignaling()); +} + +TEST(APFloatTest, next) { + + APFloat test(APFloat::IEEEquad, APFloat::uninitialized); + APFloat expected(APFloat::IEEEquad, APFloat::uninitialized); + + // 1. Test Special Cases Values. + // + // Test all special values for nextUp and nextDown perscribed by IEEE-754R + // 2008. These are: + // 1. +inf + // 2. -inf + // 3. getLargest() + // 4. -getLargest() + // 5. getSmallest() + // 6. -getSmallest() + // 7. qNaN + // 8. sNaN + // 9. +0 + // 10. -0 + + // nextUp(+inf) = +inf. + test = APFloat::getInf(APFloat::IEEEquad, false); + expected = APFloat::getInf(APFloat::IEEEquad, false); + EXPECT_EQ(test.next(false), APFloat::opOK); + EXPECT_TRUE(test.isInfinity()); + EXPECT_TRUE(!test.isNegative()); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + // nextDown(+inf) = -nextUp(-inf) = -(-getLargest()) = getLargest() + test = APFloat::getInf(APFloat::IEEEquad, false); + expected = APFloat::getLargest(APFloat::IEEEquad, false); + EXPECT_EQ(test.next(true), APFloat::opOK); + EXPECT_TRUE(!test.isNegative()); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + // nextUp(-inf) = -getLargest() + test = APFloat::getInf(APFloat::IEEEquad, true); + expected = APFloat::getLargest(APFloat::IEEEquad, true); + EXPECT_EQ(test.next(false), APFloat::opOK); + EXPECT_TRUE(test.isNegative()); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + // nextDown(-inf) = -nextUp(+inf) = -(+inf) = -inf. + test = APFloat::getInf(APFloat::IEEEquad, true); + expected = APFloat::getInf(APFloat::IEEEquad, true); + EXPECT_EQ(test.next(true), APFloat::opOK); + EXPECT_TRUE(test.isInfinity() && test.isNegative()); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + // nextUp(getLargest()) = +inf + test = APFloat::getLargest(APFloat::IEEEquad, false); + expected = APFloat::getInf(APFloat::IEEEquad, false); + EXPECT_EQ(test.next(false), APFloat::opOK); + EXPECT_TRUE(test.isInfinity() && !test.isNegative()); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + // nextDown(getLargest()) = -nextUp(-getLargest()) + // = -(-getLargest() + inc) + // = getLargest() - inc. + test = APFloat::getLargest(APFloat::IEEEquad, false); + expected = APFloat(APFloat::IEEEquad, + "0x1.fffffffffffffffffffffffffffep+16383"); + EXPECT_EQ(test.next(true), APFloat::opOK); + EXPECT_TRUE(!test.isInfinity() && !test.isNegative()); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + // nextUp(-getLargest()) = -getLargest() + inc. + test = APFloat::getLargest(APFloat::IEEEquad, true); + expected = APFloat(APFloat::IEEEquad, + "-0x1.fffffffffffffffffffffffffffep+16383"); + EXPECT_EQ(test.next(false), APFloat::opOK); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + // nextDown(-getLargest()) = -nextUp(getLargest()) = -(inf) = -inf. + test = APFloat::getLargest(APFloat::IEEEquad, true); + expected = APFloat::getInf(APFloat::IEEEquad, true); + EXPECT_EQ(test.next(true), APFloat::opOK); + EXPECT_TRUE(test.isInfinity() && test.isNegative()); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + // nextUp(getSmallest()) = getSmallest() + inc. + test = APFloat(APFloat::IEEEquad, "0x0.0000000000000000000000000001p-16382"); + expected = APFloat(APFloat::IEEEquad, + "0x0.0000000000000000000000000002p-16382"); + EXPECT_EQ(test.next(false), APFloat::opOK); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + // nextDown(getSmallest()) = -nextUp(-getSmallest()) = -(-0) = +0. + test = APFloat(APFloat::IEEEquad, "0x0.0000000000000000000000000001p-16382"); + expected = APFloat::getZero(APFloat::IEEEquad, false); + EXPECT_EQ(test.next(true), APFloat::opOK); + EXPECT_TRUE(test.isZero() && !test.isNegative()); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + // nextUp(-getSmallest()) = -0. + test = APFloat(APFloat::IEEEquad, "-0x0.0000000000000000000000000001p-16382"); + expected = APFloat::getZero(APFloat::IEEEquad, true); + EXPECT_EQ(test.next(false), APFloat::opOK); + EXPECT_TRUE(test.isZero() && test.isNegative()); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + // nextDown(-getSmallest()) = -nextUp(getSmallest()) = -getSmallest() - inc. + test = APFloat(APFloat::IEEEquad, "-0x0.0000000000000000000000000001p-16382"); + expected = APFloat(APFloat::IEEEquad, + "-0x0.0000000000000000000000000002p-16382"); + EXPECT_EQ(test.next(true), APFloat::opOK); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + // nextUp(qNaN) = qNaN + test = APFloat::getQNaN(APFloat::IEEEquad, false); + expected = APFloat::getQNaN(APFloat::IEEEquad, false); + EXPECT_EQ(test.next(false), APFloat::opOK); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + // nextDown(qNaN) = qNaN + test = APFloat::getQNaN(APFloat::IEEEquad, false); + expected = APFloat::getQNaN(APFloat::IEEEquad, false); + EXPECT_EQ(test.next(true), APFloat::opOK); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + // nextUp(sNaN) = qNaN + test = APFloat::getSNaN(APFloat::IEEEquad, false); + expected = APFloat::getQNaN(APFloat::IEEEquad, false); + EXPECT_EQ(test.next(false), APFloat::opInvalidOp); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + // nextDown(sNaN) = qNaN + test = APFloat::getSNaN(APFloat::IEEEquad, false); + expected = APFloat::getQNaN(APFloat::IEEEquad, false); + EXPECT_EQ(test.next(true), APFloat::opInvalidOp); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + // nextUp(+0) = +getSmallest() + test = APFloat::getZero(APFloat::IEEEquad, false); + expected = APFloat::getSmallest(APFloat::IEEEquad, false); + EXPECT_EQ(test.next(false), APFloat::opOK); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + // nextDown(+0) = -nextUp(-0) = -getSmallest() + test = APFloat::getZero(APFloat::IEEEquad, false); + expected = APFloat::getSmallest(APFloat::IEEEquad, true); + EXPECT_EQ(test.next(true), APFloat::opOK); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + // nextUp(-0) = +getSmallest() + test = APFloat::getZero(APFloat::IEEEquad, true); + expected = APFloat::getSmallest(APFloat::IEEEquad, false); + EXPECT_EQ(test.next(false), APFloat::opOK); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + // nextDown(-0) = -nextUp(0) = -getSmallest() + test = APFloat::getZero(APFloat::IEEEquad, true); + expected = APFloat::getSmallest(APFloat::IEEEquad, true); + EXPECT_EQ(test.next(true), APFloat::opOK); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + // 2. Binade Boundary Tests. + + // 2a. Test denormal <-> normal binade boundaries. + // * nextUp(+Largest Denormal) -> +Smallest Normal. + // * nextDown(-Largest Denormal) -> -Smallest Normal. + // * nextUp(-Smallest Normal) -> -Largest Denormal. + // * nextDown(+Smallest Normal) -> +Largest Denormal. + + // nextUp(+Largest Denormal) -> +Smallest Normal. + test = APFloat(APFloat::IEEEquad, "0x0.ffffffffffffffffffffffffffffp-16382"); + expected = APFloat(APFloat::IEEEquad, + "0x1.0000000000000000000000000000p-16382"); + EXPECT_EQ(test.next(false), APFloat::opOK); + EXPECT_FALSE(test.isDenormal()); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + // nextDown(-Largest Denormal) -> -Smallest Normal. + test = APFloat(APFloat::IEEEquad, + "-0x0.ffffffffffffffffffffffffffffp-16382"); + expected = APFloat(APFloat::IEEEquad, + "-0x1.0000000000000000000000000000p-16382"); + EXPECT_EQ(test.next(true), APFloat::opOK); + EXPECT_FALSE(test.isDenormal()); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + // nextUp(-Smallest Normal) -> -LargestDenormal. + test = APFloat(APFloat::IEEEquad, + "-0x1.0000000000000000000000000000p-16382"); + expected = APFloat(APFloat::IEEEquad, + "-0x0.ffffffffffffffffffffffffffffp-16382"); + EXPECT_EQ(test.next(false), APFloat::opOK); + EXPECT_TRUE(test.isDenormal()); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + // nextDown(+Smallest Normal) -> +Largest Denormal. + test = APFloat(APFloat::IEEEquad, + "+0x1.0000000000000000000000000000p-16382"); + expected = APFloat(APFloat::IEEEquad, + "+0x0.ffffffffffffffffffffffffffffp-16382"); + EXPECT_EQ(test.next(true), APFloat::opOK); + EXPECT_TRUE(test.isDenormal()); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + // 2b. Test normal <-> normal binade boundaries. + // * nextUp(-Normal Binade Boundary) -> -Normal Binade Boundary + 1. + // * nextDown(+Normal Binade Boundary) -> +Normal Binade Boundary - 1. + // * nextUp(+Normal Binade Boundary - 1) -> +Normal Binade Boundary. + // * nextDown(-Normal Binade Boundary + 1) -> -Normal Binade Boundary. + + // nextUp(-Normal Binade Boundary) -> -Normal Binade Boundary + 1. + test = APFloat(APFloat::IEEEquad, "-0x1p+1"); + expected = APFloat(APFloat::IEEEquad, + "-0x1.ffffffffffffffffffffffffffffp+0"); + EXPECT_EQ(test.next(false), APFloat::opOK); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + // nextDown(+Normal Binade Boundary) -> +Normal Binade Boundary - 1. + test = APFloat(APFloat::IEEEquad, "0x1p+1"); + expected = APFloat(APFloat::IEEEquad, "0x1.ffffffffffffffffffffffffffffp+0"); + EXPECT_EQ(test.next(true), APFloat::opOK); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + // nextUp(+Normal Binade Boundary - 1) -> +Normal Binade Boundary. + test = APFloat(APFloat::IEEEquad, "0x1.ffffffffffffffffffffffffffffp+0"); + expected = APFloat(APFloat::IEEEquad, "0x1p+1"); + EXPECT_EQ(test.next(false), APFloat::opOK); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + // nextDown(-Normal Binade Boundary + 1) -> -Normal Binade Boundary. + test = APFloat(APFloat::IEEEquad, "-0x1.ffffffffffffffffffffffffffffp+0"); + expected = APFloat(APFloat::IEEEquad, "-0x1p+1"); + EXPECT_EQ(test.next(true), APFloat::opOK); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + // 2c. Test using next at binade boundaries with a direction away from the + // binade boundary. Away from denormal <-> normal boundaries. + // + // This is to make sure that even though we are at a binade boundary, since + // we are rounding away, we do not trigger the binade boundary code. Thus we + // test: + // * nextUp(-Largest Denormal) -> -Largest Denormal + inc. + // * nextDown(+Largest Denormal) -> +Largest Denormal - inc. + // * nextUp(+Smallest Normal) -> +Smallest Normal + inc. + // * nextDown(-Smallest Normal) -> -Smallest Normal - inc. + + // nextUp(-Largest Denormal) -> -Largest Denormal + inc. + test = APFloat(APFloat::IEEEquad, "-0x0.ffffffffffffffffffffffffffffp-16382"); + expected = APFloat(APFloat::IEEEquad, + "-0x0.fffffffffffffffffffffffffffep-16382"); + EXPECT_EQ(test.next(false), APFloat::opOK); + EXPECT_TRUE(test.isDenormal()); + EXPECT_TRUE(test.isNegative()); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + // nextDown(+Largest Denormal) -> +Largest Denormal - inc. + test = APFloat(APFloat::IEEEquad, "0x0.ffffffffffffffffffffffffffffp-16382"); + expected = APFloat(APFloat::IEEEquad, + "0x0.fffffffffffffffffffffffffffep-16382"); + EXPECT_EQ(test.next(true), APFloat::opOK); + EXPECT_TRUE(test.isDenormal()); + EXPECT_TRUE(!test.isNegative()); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + // nextUp(+Smallest Normal) -> +Smallest Normal + inc. + test = APFloat(APFloat::IEEEquad, "0x1.0000000000000000000000000000p-16382"); + expected = APFloat(APFloat::IEEEquad, + "0x1.0000000000000000000000000001p-16382"); + EXPECT_EQ(test.next(false), APFloat::opOK); + EXPECT_TRUE(!test.isDenormal()); + EXPECT_TRUE(!test.isNegative()); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + // nextDown(-Smallest Normal) -> -Smallest Normal - inc. + test = APFloat(APFloat::IEEEquad, "-0x1.0000000000000000000000000000p-16382"); + expected = APFloat(APFloat::IEEEquad, + "-0x1.0000000000000000000000000001p-16382"); + EXPECT_EQ(test.next(true), APFloat::opOK); + EXPECT_TRUE(!test.isDenormal()); + EXPECT_TRUE(test.isNegative()); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + // 2d. Test values which cause our exponent to go to min exponent. This + // is to ensure that guards in the code to check for min exponent + // trigger properly. + // * nextUp(-0x1p-16381) -> -0x1.ffffffffffffffffffffffffffffp-16382 + // * nextDown(-0x1.ffffffffffffffffffffffffffffp-16382) -> + // -0x1p-16381 + // * nextUp(0x1.ffffffffffffffffffffffffffffp-16382) -> 0x1p-16382 + // * nextDown(0x1p-16382) -> 0x1.ffffffffffffffffffffffffffffp-16382 + + // nextUp(-0x1p-16381) -> -0x1.ffffffffffffffffffffffffffffp-16382 + test = APFloat(APFloat::IEEEquad, "-0x1p-16381"); + expected = APFloat(APFloat::IEEEquad, + "-0x1.ffffffffffffffffffffffffffffp-16382"); + EXPECT_EQ(test.next(false), APFloat::opOK); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + // nextDown(-0x1.ffffffffffffffffffffffffffffp-16382) -> + // -0x1p-16381 + test = APFloat(APFloat::IEEEquad, "-0x1.ffffffffffffffffffffffffffffp-16382"); + expected = APFloat(APFloat::IEEEquad, "-0x1p-16381"); + EXPECT_EQ(test.next(true), APFloat::opOK); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + // nextUp(0x1.ffffffffffffffffffffffffffffp-16382) -> 0x1p-16381 + test = APFloat(APFloat::IEEEquad, "0x1.ffffffffffffffffffffffffffffp-16382"); + expected = APFloat(APFloat::IEEEquad, "0x1p-16381"); + EXPECT_EQ(test.next(false), APFloat::opOK); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + // nextDown(0x1p-16381) -> 0x1.ffffffffffffffffffffffffffffp-16382 + test = APFloat(APFloat::IEEEquad, "0x1p-16381"); + expected = APFloat(APFloat::IEEEquad, + "0x1.ffffffffffffffffffffffffffffp-16382"); + EXPECT_EQ(test.next(true), APFloat::opOK); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + // 3. Now we test both denormal/normal computation which will not cause us + // to go across binade boundaries. Specifically we test: + // * nextUp(+Denormal) -> +Denormal. + // * nextDown(+Denormal) -> +Denormal. + // * nextUp(-Denormal) -> -Denormal. + // * nextDown(-Denormal) -> -Denormal. + // * nextUp(+Normal) -> +Normal. + // * nextDown(+Normal) -> +Normal. + // * nextUp(-Normal) -> -Normal. + // * nextDown(-Normal) -> -Normal. + + // nextUp(+Denormal) -> +Denormal. + test = APFloat(APFloat::IEEEquad, + "0x0.ffffffffffffffffffffffff000cp-16382"); + expected = APFloat(APFloat::IEEEquad, + "0x0.ffffffffffffffffffffffff000dp-16382"); + EXPECT_EQ(test.next(false), APFloat::opOK); + EXPECT_TRUE(test.isDenormal()); + EXPECT_TRUE(!test.isNegative()); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + // nextDown(+Denormal) -> +Denormal. + test = APFloat(APFloat::IEEEquad, + "0x0.ffffffffffffffffffffffff000cp-16382"); + expected = APFloat(APFloat::IEEEquad, + "0x0.ffffffffffffffffffffffff000bp-16382"); + EXPECT_EQ(test.next(true), APFloat::opOK); + EXPECT_TRUE(test.isDenormal()); + EXPECT_TRUE(!test.isNegative()); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + // nextUp(-Denormal) -> -Denormal. + test = APFloat(APFloat::IEEEquad, + "-0x0.ffffffffffffffffffffffff000cp-16382"); + expected = APFloat(APFloat::IEEEquad, + "-0x0.ffffffffffffffffffffffff000bp-16382"); + EXPECT_EQ(test.next(false), APFloat::opOK); + EXPECT_TRUE(test.isDenormal()); + EXPECT_TRUE(test.isNegative()); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + // nextDown(-Denormal) -> -Denormal + test = APFloat(APFloat::IEEEquad, + "-0x0.ffffffffffffffffffffffff000cp-16382"); + expected = APFloat(APFloat::IEEEquad, + "-0x0.ffffffffffffffffffffffff000dp-16382"); + EXPECT_EQ(test.next(true), APFloat::opOK); + EXPECT_TRUE(test.isDenormal()); + EXPECT_TRUE(test.isNegative()); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + // nextUp(+Normal) -> +Normal. + test = APFloat(APFloat::IEEEquad, + "0x1.ffffffffffffffffffffffff000cp-16000"); + expected = APFloat(APFloat::IEEEquad, + "0x1.ffffffffffffffffffffffff000dp-16000"); + EXPECT_EQ(test.next(false), APFloat::opOK); + EXPECT_TRUE(!test.isDenormal()); + EXPECT_TRUE(!test.isNegative()); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + // nextDown(+Normal) -> +Normal. + test = APFloat(APFloat::IEEEquad, + "0x1.ffffffffffffffffffffffff000cp-16000"); + expected = APFloat(APFloat::IEEEquad, + "0x1.ffffffffffffffffffffffff000bp-16000"); + EXPECT_EQ(test.next(true), APFloat::opOK); + EXPECT_TRUE(!test.isDenormal()); + EXPECT_TRUE(!test.isNegative()); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + // nextUp(-Normal) -> -Normal. + test = APFloat(APFloat::IEEEquad, + "-0x1.ffffffffffffffffffffffff000cp-16000"); + expected = APFloat(APFloat::IEEEquad, + "-0x1.ffffffffffffffffffffffff000bp-16000"); + EXPECT_EQ(test.next(false), APFloat::opOK); + EXPECT_TRUE(!test.isDenormal()); + EXPECT_TRUE(test.isNegative()); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + // nextDown(-Normal) -> -Normal. + test = APFloat(APFloat::IEEEquad, + "-0x1.ffffffffffffffffffffffff000cp-16000"); + expected = APFloat(APFloat::IEEEquad, + "-0x1.ffffffffffffffffffffffff000dp-16000"); + EXPECT_EQ(test.next(true), APFloat::opOK); + EXPECT_TRUE(!test.isDenormal()); + EXPECT_TRUE(test.isNegative()); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); +} + +TEST(APFloatTest, FMA) { + APFloat::roundingMode rdmd = APFloat::rmNearestTiesToEven; + + { + APFloat f1(14.5f); + APFloat f2(-14.5f); + APFloat f3(225.0f); + f1.fusedMultiplyAdd(f2, f3, APFloat::rmNearestTiesToEven); + EXPECT_EQ(14.75f, f1.convertToFloat()); + } + + { + APFloat Val2(2.0f); + APFloat f1((float)1.17549435e-38F); + APFloat f2((float)1.17549435e-38F); + f1.divide(Val2, rdmd); + f2.divide(Val2, rdmd); + APFloat f3(12.0f); + f1.fusedMultiplyAdd(f2, f3, APFloat::rmNearestTiesToEven); + EXPECT_EQ(12.0f, f1.convertToFloat()); + } +} + TEST(APFloatTest, Denormal) { APFloat::roundingMode rdmd = APFloat::rmNearestTiesToEven; @@ -771,6 +1214,103 @@ TEST(APFloatTest, getLargest) { EXPECT_EQ(1.7976931348623158e+308, APFloat::getLargest(APFloat::IEEEdouble).convertToDouble()); } +TEST(APFloatTest, getSmallest) { + APFloat test = APFloat::getSmallest(APFloat::IEEEsingle, false); + APFloat expected = APFloat(APFloat::IEEEsingle, "0x0.000002p-126"); + EXPECT_FALSE(test.isNegative()); + EXPECT_TRUE(test.isNormal()); + EXPECT_TRUE(test.isDenormal()); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + test = APFloat::getSmallest(APFloat::IEEEsingle, true); + expected = APFloat(APFloat::IEEEsingle, "-0x0.000002p-126"); + EXPECT_TRUE(test.isNegative()); + EXPECT_TRUE(test.isNormal()); + EXPECT_TRUE(test.isDenormal()); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + test = APFloat::getSmallest(APFloat::IEEEquad, false); + expected = APFloat(APFloat::IEEEquad, "0x0.0000000000000000000000000001p-16382"); + EXPECT_FALSE(test.isNegative()); + EXPECT_TRUE(test.isNormal()); + EXPECT_TRUE(test.isDenormal()); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + test = APFloat::getSmallest(APFloat::IEEEquad, true); + expected = APFloat(APFloat::IEEEquad, "-0x0.0000000000000000000000000001p-16382"); + EXPECT_TRUE(test.isNegative()); + EXPECT_TRUE(test.isNormal()); + EXPECT_TRUE(test.isDenormal()); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); +} + +TEST(APFloatTest, getSmallestNormalized) { + APFloat test = APFloat::getSmallestNormalized(APFloat::IEEEsingle, false); + APFloat expected = APFloat(APFloat::IEEEsingle, "0x1p-126"); + EXPECT_FALSE(test.isNegative()); + EXPECT_TRUE(test.isNormal()); + EXPECT_FALSE(test.isDenormal()); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + test = APFloat::getSmallestNormalized(APFloat::IEEEsingle, true); + expected = APFloat(APFloat::IEEEsingle, "-0x1p-126"); + EXPECT_TRUE(test.isNegative()); + EXPECT_TRUE(test.isNormal()); + EXPECT_FALSE(test.isDenormal()); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + test = APFloat::getSmallestNormalized(APFloat::IEEEquad, false); + expected = APFloat(APFloat::IEEEquad, "0x1p-16382"); + EXPECT_FALSE(test.isNegative()); + EXPECT_TRUE(test.isNormal()); + EXPECT_FALSE(test.isDenormal()); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + + test = APFloat::getSmallestNormalized(APFloat::IEEEquad, true); + expected = APFloat(APFloat::IEEEquad, "-0x1p-16382"); + EXPECT_TRUE(test.isNegative()); + EXPECT_TRUE(test.isNormal()); + EXPECT_FALSE(test.isDenormal()); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); +} + +TEST(APFloatTest, getZero) { + struct { + const fltSemantics *semantics; + const bool sign; + const unsigned long long bitPattern[2]; + const unsigned bitPatternLength; + } const GetZeroTest[] = { + { &APFloat::IEEEhalf, false, {0, 0}, 1}, + { &APFloat::IEEEhalf, true, {0x8000ULL, 0}, 1}, + { &APFloat::IEEEsingle, false, {0, 0}, 1}, + { &APFloat::IEEEsingle, true, {0x80000000ULL, 0}, 1}, + { &APFloat::IEEEdouble, false, {0, 0}, 1}, + { &APFloat::IEEEdouble, true, {0x8000000000000000ULL, 0}, 1}, + { &APFloat::IEEEquad, false, {0, 0}, 2}, + { &APFloat::IEEEquad, true, {0, 0x8000000000000000ULL}, 2}, + { &APFloat::PPCDoubleDouble, false, {0, 0}, 2}, + { &APFloat::PPCDoubleDouble, true, {0x8000000000000000ULL, 0}, 2}, + { &APFloat::x87DoubleExtended, false, {0, 0}, 2}, + { &APFloat::x87DoubleExtended, true, {0, 0x8000ULL}, 2}, + }; + const unsigned NumGetZeroTests = 12; + for (unsigned i = 0; i < NumGetZeroTests; ++i) { + APFloat test = APFloat::getZero(*GetZeroTest[i].semantics, + GetZeroTest[i].sign); + const char *pattern = GetZeroTest[i].sign? "-0x0p+0" : "0x0p+0"; + APFloat expected = APFloat(*GetZeroTest[i].semantics, + pattern); + EXPECT_TRUE(test.isZero()); + EXPECT_TRUE(GetZeroTest[i].sign? test.isNegative() : !test.isNegative()); + EXPECT_TRUE(test.bitwiseIsEqual(expected)); + for (unsigned j = 0, je = GetZeroTest[i].bitPatternLength; j < je; ++j) { + EXPECT_EQ(GetZeroTest[i].bitPattern[j], + test.bitcastToAPInt().getRawData()[j]); + } + } +} + TEST(APFloatTest, convert) { bool losesInfo; APFloat test(APFloat::IEEEdouble, "1.0"); @@ -857,4 +1397,65 @@ TEST(APFloatTest, PPCDoubleDouble) { EXPECT_EQ(0x0000000000000000ull, test.bitcastToAPInt().getRawData()[1]); #endif } + +TEST(APFloatTest, isNegative) { + APFloat t(APFloat::IEEEsingle, "0x1p+0"); + EXPECT_FALSE(t.isNegative()); + t = APFloat(APFloat::IEEEsingle, "-0x1p+0"); + EXPECT_TRUE(t.isNegative()); + + EXPECT_FALSE(APFloat::getInf(APFloat::IEEEsingle, false).isNegative()); + EXPECT_TRUE(APFloat::getInf(APFloat::IEEEsingle, true).isNegative()); + + EXPECT_FALSE(APFloat::getZero(APFloat::IEEEsingle, false).isNegative()); + EXPECT_TRUE(APFloat::getZero(APFloat::IEEEsingle, true).isNegative()); + + EXPECT_FALSE(APFloat::getNaN(APFloat::IEEEsingle, false).isNegative()); + EXPECT_TRUE(APFloat::getNaN(APFloat::IEEEsingle, true).isNegative()); + + EXPECT_FALSE(APFloat::getSNaN(APFloat::IEEEsingle, false).isNegative()); + EXPECT_TRUE(APFloat::getSNaN(APFloat::IEEEsingle, true).isNegative()); +} + +TEST(APFloatTest, isIEEENormal) { + APFloat t(APFloat::IEEEsingle, "0x1p+0"); + EXPECT_TRUE(t.isIEEENormal()); + + EXPECT_FALSE(APFloat::getInf(APFloat::IEEEsingle, false).isIEEENormal()); + EXPECT_FALSE(APFloat::getZero(APFloat::IEEEsingle, false).isIEEENormal()); + EXPECT_FALSE(APFloat::getNaN(APFloat::IEEEsingle, false).isIEEENormal()); + EXPECT_FALSE(APFloat::getSNaN(APFloat::IEEEsingle, false).isIEEENormal()); + EXPECT_FALSE(APFloat(APFloat::IEEEsingle, "0x1p-159").isIEEENormal()); +} + +TEST(APFloatTest, isFinite) { + APFloat t(APFloat::IEEEsingle, "0x1p+0"); + EXPECT_TRUE(t.isFinite()); + EXPECT_FALSE(APFloat::getInf(APFloat::IEEEsingle, false).isFinite()); + EXPECT_TRUE(APFloat::getZero(APFloat::IEEEsingle, false).isFinite()); + EXPECT_FALSE(APFloat::getNaN(APFloat::IEEEsingle, false).isFinite()); + EXPECT_FALSE(APFloat::getSNaN(APFloat::IEEEsingle, false).isFinite()); + EXPECT_TRUE(APFloat(APFloat::IEEEsingle, "0x1p-159").isFinite()); +} + +TEST(APFloatTest, isInfinity) { + APFloat t(APFloat::IEEEsingle, "0x1p+0"); + EXPECT_FALSE(t.isInfinity()); + EXPECT_TRUE(APFloat::getInf(APFloat::IEEEsingle, false).isInfinity()); + EXPECT_FALSE(APFloat::getZero(APFloat::IEEEsingle, false).isInfinity()); + EXPECT_FALSE(APFloat::getNaN(APFloat::IEEEsingle, false).isInfinity()); + EXPECT_FALSE(APFloat::getSNaN(APFloat::IEEEsingle, false).isInfinity()); + EXPECT_FALSE(APFloat(APFloat::IEEEsingle, "0x1p-159").isInfinity()); +} + +TEST(APFloatTest, isNaN) { + APFloat t(APFloat::IEEEsingle, "0x1p+0"); + EXPECT_FALSE(t.isNaN()); + EXPECT_FALSE(APFloat::getInf(APFloat::IEEEsingle, false).isNaN()); + EXPECT_FALSE(APFloat::getZero(APFloat::IEEEsingle, false).isNaN()); + EXPECT_TRUE(APFloat::getNaN(APFloat::IEEEsingle, false).isNaN()); + EXPECT_TRUE(APFloat::getSNaN(APFloat::IEEEsingle, false).isNaN()); + EXPECT_FALSE(APFloat(APFloat::IEEEsingle, "0x1p-159").isNaN()); +} + } diff --git a/unittests/ADT/APIntTest.cpp b/unittests/ADT/APIntTest.cpp index f129fa7..3c0dfe1 100644 --- a/unittests/ADT/APIntTest.cpp +++ b/unittests/ADT/APIntTest.cpp @@ -532,4 +532,69 @@ TEST(APIntTest, Splat) { EXPECT_EQ(APInt(15, 0xDB6D), APInt::getSplat(15, ValB)); } +TEST(APIntTest, tcDecrement) { + // Test single word decrement. + + // No out borrow. + { + integerPart singleWord = ~integerPart(0) << (integerPartWidth - 1); + integerPart carry = APInt::tcDecrement(&singleWord, 1); + EXPECT_EQ(carry, integerPart(0)); + EXPECT_EQ(singleWord, ~integerPart(0) >> 1); + } + + // With out borrow. + { + integerPart singleWord = 0; + integerPart carry = APInt::tcDecrement(&singleWord, 1); + EXPECT_EQ(carry, integerPart(1)); + EXPECT_EQ(singleWord, ~integerPart(0)); + } + + // Test multiword decrement. + + // No across word borrow, no out borrow. + { + integerPart test[4] = {0x1, 0x1, 0x1, 0x1}; + integerPart expected[4] = {0x0, 0x1, 0x1, 0x1}; + APInt::tcDecrement(test, 4); + EXPECT_EQ(APInt::tcCompare(test, expected, 4), 0); + } + + // 1 across word borrow, no out borrow. + { + integerPart test[4] = {0x0, 0xF, 0x1, 0x1}; + integerPart expected[4] = {~integerPart(0), 0xE, 0x1, 0x1}; + integerPart carry = APInt::tcDecrement(test, 4); + EXPECT_EQ(carry, integerPart(0)); + EXPECT_EQ(APInt::tcCompare(test, expected, 4), 0); + } + + // 2 across word borrow, no out borrow. + { + integerPart test[4] = {0x0, 0x0, 0xC, 0x1}; + integerPart expected[4] = {~integerPart(0), ~integerPart(0), 0xB, 0x1}; + integerPart carry = APInt::tcDecrement(test, 4); + EXPECT_EQ(carry, integerPart(0)); + EXPECT_EQ(APInt::tcCompare(test, expected, 4), 0); + } + + // 3 across word borrow, no out borrow. + { + integerPart test[4] = {0x0, 0x0, 0x0, 0x1}; + integerPart expected[4] = {~integerPart(0), ~integerPart(0), ~integerPart(0), 0x0}; + integerPart carry = APInt::tcDecrement(test, 4); + EXPECT_EQ(carry, integerPart(0)); + EXPECT_EQ(APInt::tcCompare(test, expected, 4), 0); + } + + // 3 across word borrow, with out borrow. + { + integerPart test[4] = {0x0, 0x0, 0x0, 0x0}; + integerPart expected[4] = {~integerPart(0), ~integerPart(0), ~integerPart(0), ~integerPart(0)}; + integerPart carry = APInt::tcDecrement(test, 4); + EXPECT_EQ(carry, integerPart(1)); + EXPECT_EQ(APInt::tcCompare(test, expected, 4), 0); + } +} } diff --git a/unittests/ADT/BitVectorTest.cpp b/unittests/ADT/BitVectorTest.cpp index dc298a8..85e1594 100644 --- a/unittests/ADT/BitVectorTest.cpp +++ b/unittests/ADT/BitVectorTest.cpp @@ -141,6 +141,30 @@ TYPED_TEST(BitVectorTest, TrivialOperation) { EXPECT_TRUE(Vec.none()); EXPECT_FALSE(Vec.empty()); + Vec.flip(); + EXPECT_EQ(130U, Vec.count()); + EXPECT_EQ(130U, Vec.size()); + EXPECT_TRUE(Vec.any()); + EXPECT_TRUE(Vec.all()); + EXPECT_FALSE(Vec.none()); + EXPECT_FALSE(Vec.empty()); + + Vec.resize(64); + EXPECT_EQ(64U, Vec.count()); + EXPECT_EQ(64U, Vec.size()); + EXPECT_TRUE(Vec.any()); + EXPECT_TRUE(Vec.all()); + EXPECT_FALSE(Vec.none()); + EXPECT_FALSE(Vec.empty()); + + Vec.flip(); + EXPECT_EQ(0U, Vec.count()); + EXPECT_EQ(64U, Vec.size()); + EXPECT_FALSE(Vec.any()); + EXPECT_FALSE(Vec.all()); + EXPECT_TRUE(Vec.none()); + EXPECT_FALSE(Vec.empty()); + Inv = TypeParam().flip(); EXPECT_EQ(0U, Inv.count()); EXPECT_EQ(0U, Inv.size()); diff --git a/unittests/ExecutionEngine/JIT/JITEventListenerTest.cpp b/unittests/ExecutionEngine/JIT/JITEventListenerTest.cpp index 6ba8bc4..87f4824 100644 --- a/unittests/ExecutionEngine/JIT/JITEventListenerTest.cpp +++ b/unittests/ExecutionEngine/JIT/JITEventListenerTest.cpp @@ -74,6 +74,8 @@ class JITEventListenerTest : public testing::Test { const OwningPtr<ExecutionEngine> EE; }; +// Tests on SystemZ disabled as we're running the old JIT +#if !defined(__s390__) Function *buildFunction(Module *M) { Function *Result = Function::Create( TypeBuilder<int32_t(int32_t), false>::get(getGlobalContext()), @@ -224,6 +226,7 @@ TEST_F(JITEventListenerTest, MatchesMachineCodeInfo) { EXPECT_EQ(1U, Listener.FreedEvents[0].Index); EXPECT_EQ(F_addr, Listener.FreedEvents[0].Code); } +#endif class JITEnvironment : public testing::Environment { virtual void SetUp() { diff --git a/unittests/ExecutionEngine/JIT/JITTest.cpp b/unittests/ExecutionEngine/JIT/JITTest.cpp index 30dadc9..3b94d76 100644 --- a/unittests/ExecutionEngine/JIT/JITTest.cpp +++ b/unittests/ExecutionEngine/JIT/JITTest.cpp @@ -33,8 +33,27 @@ using namespace llvm; +// This variable is intentionally defined differently in the statically-compiled +// program from the IR input to the JIT to assert that the JIT doesn't use its +// definition. Note that this variable must be defined even on platforms where +// JIT tests are disabled as it is referenced from the .def file. +extern "C" int32_t JITTest_AvailableExternallyGlobal; +int32_t JITTest_AvailableExternallyGlobal LLVM_ATTRIBUTE_USED = 42; + +// This function is intentionally defined differently in the statically-compiled +// program from the IR input to the JIT to assert that the JIT doesn't use its +// definition. Note that this function must be defined even on platforms where +// JIT tests are disabled as it is referenced from the .def file. +extern "C" int32_t JITTest_AvailableExternallyFunction() LLVM_ATTRIBUTE_USED; +extern "C" int32_t JITTest_AvailableExternallyFunction() { + return 42; +} + namespace { +// Tests on ARM, PowerPC and SystemZ disabled as we're running the old jit +#if !defined(__arm__) && !defined(__powerpc__) && !defined(__s390__) + Function *makeReturnGlobal(std::string Name, GlobalVariable *G, Module *M) { std::vector<Type*> params; FunctionType *FTy = FunctionType::get(G->getType()->getElementType(), @@ -124,7 +143,7 @@ public: unsigned SectionID) { return Base->allocateCodeSection(Size, Alignment, SectionID); } - virtual bool applyPermissions(std::string *ErrMsg) { return false; } + virtual bool finalizeMemory(std::string *ErrMsg) { return false; } virtual uint8_t *allocateSpace(intptr_t Size, unsigned Alignment) { return Base->allocateSpace(Size, Alignment); } @@ -140,54 +159,6 @@ public: deallocateFunctionBodyCalls.push_back(DeallocateFunctionBodyCall(Body)); Base->deallocateFunctionBody(Body); } - struct DeallocateExceptionTableCall { - DeallocateExceptionTableCall(const void *ET) : ET(ET) {} - const void *ET; - }; - std::vector<DeallocateExceptionTableCall> deallocateExceptionTableCalls; - virtual void deallocateExceptionTable(void *ET) { - deallocateExceptionTableCalls.push_back(DeallocateExceptionTableCall(ET)); - Base->deallocateExceptionTable(ET); - } - struct StartExceptionTableCall { - StartExceptionTableCall(uint8_t *Result, const Function *F, - uintptr_t ActualSize, uintptr_t ActualSizeResult) - : Result(Result), F(F), F_dump(DumpFunction(F)), - ActualSize(ActualSize), ActualSizeResult(ActualSizeResult) {} - uint8_t *Result; - const Function *F; - std::string F_dump; - uintptr_t ActualSize; - uintptr_t ActualSizeResult; - }; - std::vector<StartExceptionTableCall> startExceptionTableCalls; - virtual uint8_t *startExceptionTable(const Function *F, - uintptr_t &ActualSize) { - uintptr_t InitialActualSize = ActualSize; - uint8_t *Result = Base->startExceptionTable(F, ActualSize); - startExceptionTableCalls.push_back( - StartExceptionTableCall(Result, F, InitialActualSize, ActualSize)); - return Result; - } - struct EndExceptionTableCall { - EndExceptionTableCall(const Function *F, uint8_t *TableStart, - uint8_t *TableEnd, uint8_t* FrameRegister) - : F(F), F_dump(DumpFunction(F)), - TableStart(TableStart), TableEnd(TableEnd), - FrameRegister(FrameRegister) {} - const Function *F; - std::string F_dump; - uint8_t *TableStart; - uint8_t *TableEnd; - uint8_t *FrameRegister; - }; - std::vector<EndExceptionTableCall> endExceptionTableCalls; - virtual void endExceptionTable(const Function *F, uint8_t *TableStart, - uint8_t *TableEnd, uint8_t* FrameRegister) { - endExceptionTableCalls.push_back( - EndExceptionTableCall(F, TableStart, TableEnd, FrameRegister)); - return Base->endExceptionTable(F, TableStart, TableEnd, FrameRegister); - } }; bool LoadAssemblyInto(Module *M, const char *assembly) { @@ -213,7 +184,6 @@ class JITTest : public testing::Test { RJMM->setPoisonMemory(true); std::string Error; TargetOptions Options; - Options.JITExceptionHandling = true; TheJIT.reset(EngineBuilder(M).setEngineKind(EngineKind::JIT) .setJITMemoryManager(RJMM) .setErrorStr(&Error) @@ -231,9 +201,6 @@ class JITTest : public testing::Test { OwningPtr<ExecutionEngine> TheJIT; }; -// Tests on ARM and PowerPC disabled as we're running the old jit -#if !defined(__arm__) && !defined(__powerpc__) - // Regression test for a bug. The JIT used to allocate globals inside the same // memory block used for the function, and when the function code was freed, // the global was left in the same place. This test allocates a function @@ -302,54 +269,10 @@ TEST(JIT, GlobalInFunction) { EXPECT_EQ(3, *GPtr); } -#endif // !defined(__arm__) && !defined(__powerpc__) - -// Regression test for a bug. The JITEmitter wasn't checking to verify that -// it hadn't run out of space while generating the DWARF exception information -// for an emitted function. - -class ExceptionMemoryManagerMock : public RecordingJITMemoryManager { - public: - virtual uint8_t *startExceptionTable(const Function *F, - uintptr_t &ActualSize) { - // force an insufficient size the first time through. - bool ChangeActualSize = false; - if (ActualSize == 0) - ChangeActualSize = true;; - uint8_t *result = - RecordingJITMemoryManager::startExceptionTable(F, ActualSize); - if (ChangeActualSize) - ActualSize = 1; - return result; - } -}; - -class JITExceptionMemoryTest : public JITTest { - protected: - virtual RecordingJITMemoryManager *createMemoryManager() { - return new ExceptionMemoryManagerMock; - } -}; - -TEST_F(JITExceptionMemoryTest, ExceptionTableOverflow) { - Function *F = Function::Create(TypeBuilder<void(void), false>::get(Context), - Function::ExternalLinkage, - "func1", M); - BasicBlock *Block = BasicBlock::Create(Context, "block", F); - IRBuilder<> Builder(Block); - Builder.CreateRetVoid(); - TheJIT->getPointerToFunction(F); - ASSERT_TRUE(RJMM->startExceptionTableCalls.size() == 2); - ASSERT_TRUE(RJMM->deallocateExceptionTableCalls.size() == 1); - ASSERT_TRUE(RJMM->endExceptionTableCalls.size() == 1); -} - int PlusOne(int arg) { return arg + 1; } -// ARM and PowerPC tests disabled pending fix for PR10783. -#if !defined(__arm__) && !defined(__powerpc__) TEST_F(JITTest, FarCallToKnownFunction) { // x86-64 can only make direct calls to functions within 32 bits of // the current PC. To call anything farther away, we have to load @@ -505,29 +428,7 @@ TEST_F(JITTest, ModuleDeletion) { } EXPECT_EQ(RJMM->startFunctionBodyCalls.size(), RJMM->deallocateFunctionBodyCalls.size()); - - SmallPtrSet<const void*, 2> ExceptionTablesDeallocated; - unsigned NumTablesDeallocated = 0; - for (unsigned i = 0, e = RJMM->deallocateExceptionTableCalls.size(); - i != e; ++i) { - ExceptionTablesDeallocated.insert( - RJMM->deallocateExceptionTableCalls[i].ET); - if (RJMM->deallocateExceptionTableCalls[i].ET != NULL) { - // If JITEmitDebugInfo is off, we'll "deallocate" NULL, which doesn't - // appear in startExceptionTableCalls. - NumTablesDeallocated++; - } - } - for (unsigned i = 0, e = RJMM->startExceptionTableCalls.size(); i != e; ++i) { - EXPECT_TRUE(ExceptionTablesDeallocated.count( - RJMM->startExceptionTableCalls[i].Result)) - << "Function's exception table leaked: \n" - << RJMM->startExceptionTableCalls[i].F_dump; - } - EXPECT_EQ(RJMM->startExceptionTableCalls.size(), - NumTablesDeallocated); } -#endif // !defined(__arm__) && !defined(__powerpc__) // ARM, MIPS and PPC still emit stubs for calls since the target may be // too far away to call directly. This #if can probably be removed when @@ -573,9 +474,6 @@ TEST_F(JITTest, NoStubs) { } #endif // !ARM && !PPC -// Tests on ARM and PowerPC disabled as we're running the old jit -#if !defined(__arm__) && !defined(__powerpc__) - TEST_F(JITTest, FunctionPointersOutliveTheirCreator) { TheJIT->DisableLazyCompilation(true); LoadAssembly("define i8()* @get_foo_addr() { " @@ -610,13 +508,9 @@ TEST_F(JITTest, FunctionPointersOutliveTheirCreator) { #endif } -#endif //!defined(__arm__) && !defined(__powerpc__) - -// Tests on ARM and PowerPC disabled as we're running the old jit -// In addition, ARM does not have an implementation -// of replaceMachineCodeForFunction(), so recompileAndRelinkFunction -// doesn't work. -#if !defined(__arm__) && !defined(__powerpc__) +// ARM does not have an implementation of replaceMachineCodeForFunction(), +// so recompileAndRelinkFunction doesn't work. +#if !defined(__arm__) TEST_F(JITTest, FunctionIsRecompiledAndRelinked) { Function *F = Function::Create(TypeBuilder<int(void), false>::get(Context), GlobalValue::ExternalLinkage, "test", M); @@ -647,18 +541,7 @@ TEST_F(JITTest, FunctionIsRecompiledAndRelinked) { EXPECT_EQ(2, OrigFPtr()) << "The old pointer's target should now jump to the new version"; } -#endif // !defined(__arm__) && !defined(__powerpc__) - -} // anonymous namespace -// This variable is intentionally defined differently in the statically-compiled -// program from the IR input to the JIT to assert that the JIT doesn't use its -// definition. -extern "C" int32_t JITTest_AvailableExternallyGlobal; -int32_t JITTest_AvailableExternallyGlobal LLVM_ATTRIBUTE_USED = 42; -namespace { - -// Tests on ARM and PowerPC disabled as we're running the old jit -#if !defined(__arm__) && !defined(__powerpc__) +#endif // !defined(__arm__) TEST_F(JITTest, AvailableExternallyGlobalIsntEmitted) { TheJIT->DisableLazyCompilation(true); @@ -676,19 +559,7 @@ TEST_F(JITTest, AvailableExternallyGlobalIsntEmitted) { EXPECT_EQ(42, loader()) << "func should return 42 from the external global," << " not 7 from the IR version."; } -#endif //!defined(__arm__) && !defined(__powerpc__) -} // anonymous namespace -// This function is intentionally defined differently in the statically-compiled -// program from the IR input to the JIT to assert that the JIT doesn't use its -// definition. -extern "C" int32_t JITTest_AvailableExternallyFunction() LLVM_ATTRIBUTE_USED; -extern "C" int32_t JITTest_AvailableExternallyFunction() { - return 42; -} -namespace { -// ARM and PowerPC tests disabled pending fix for PR10783. -#if !defined(__arm__) && !defined(__powerpc__) TEST_F(JITTest, AvailableExternallyFunctionIsntCompiled) { TheJIT->DisableLazyCompilation(true); LoadAssembly("define available_externally i32 " @@ -844,7 +715,7 @@ TEST(LazyLoadedJITTest, EagerCompiledRecursionThroughGhost) { (intptr_t)TheJIT->getPointerToFunction(recur1IR)); EXPECT_EQ(3, recur1(4)); } -#endif // !defined(__arm__) && !defined(__powerpc__) +#endif // !defined(__arm__) && !defined(__powerpc__) && !defined(__s390__) // This code is copied from JITEventListenerTest, but it only runs once for all // the tests in this directory. Everything seems fine, but that's strange diff --git a/unittests/ExecutionEngine/JIT/MultiJITTest.cpp b/unittests/ExecutionEngine/JIT/MultiJITTest.cpp index 5301467..4018cd5 100644 --- a/unittests/ExecutionEngine/JIT/MultiJITTest.cpp +++ b/unittests/ExecutionEngine/JIT/MultiJITTest.cpp @@ -20,6 +20,9 @@ using namespace llvm; namespace { +// ARM, PowerPC and SystemZ tests disabled pending fix for PR10783. +#if !defined(__arm__) && !defined(__powerpc__) && !defined(__s390__) + bool LoadAssemblyInto(Module *M, const char *assembly) { SMDiagnostic Error; bool success = @@ -65,9 +68,6 @@ void createModule2(LLVMContext &Context2, Module *&M2, Function *&FooF2) { FooF2 = M2->getFunction("foo2"); } -// ARM and PowerPC tests disabled pending fix for PR10783. -#if !defined(__arm__) && !defined(__powerpc__) - TEST(MultiJitTest, EagerMode) { LLVMContext Context1; Module *M1 = 0; @@ -176,6 +176,6 @@ TEST(MultiJitTest, JitPool) { #endif EXPECT_TRUE(sa == fa); } -#endif // !defined(__arm__) && !defined(__powerpc__) +#endif // !defined(__arm__) && !defined(__powerpc__) && !defined(__s390__) } // anonymous namespace diff --git a/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp b/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp index d8cf6c5..c434a7c 100644 --- a/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp +++ b/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp @@ -17,79 +17,176 @@ #include "llvm-c/ExecutionEngine.h" #include "llvm-c/Target.h" #include "llvm-c/Transforms/Scalar.h" +#include "llvm/ExecutionEngine/SectionMemoryManager.h" #include "llvm/Support/Host.h" #include "MCJITTestAPICommon.h" #include "gtest/gtest.h" using namespace llvm; +static bool didCallAllocateCodeSection; + +static uint8_t *roundTripAllocateCodeSection(void *object, uintptr_t size, + unsigned alignment, + unsigned sectionID) { + didCallAllocateCodeSection = true; + return static_cast<SectionMemoryManager*>(object)->allocateCodeSection( + size, alignment, sectionID); +} + +static uint8_t *roundTripAllocateDataSection(void *object, uintptr_t size, + unsigned alignment, + unsigned sectionID, + LLVMBool isReadOnly) { + return static_cast<SectionMemoryManager*>(object)->allocateDataSection( + size, alignment, sectionID, isReadOnly); +} + +static LLVMBool roundTripFinalizeMemory(void *object, char **errMsg) { + std::string errMsgString; + bool result = + static_cast<SectionMemoryManager*>(object)->finalizeMemory(&errMsgString); + if (result) { + *errMsg = LLVMCreateMessage(errMsgString.c_str()); + return 1; + } + return 0; +} + +static void roundTripDestroy(void *object) { + delete static_cast<SectionMemoryManager*>(object); +} + class MCJITCAPITest : public testing::Test, public MCJITTestAPICommon { protected: MCJITCAPITest() { // The architectures below are known to be compatible with MCJIT as they // are copied from test/ExecutionEngine/MCJIT/lit.local.cfg and should be // kept in sync. + SupportedArchs.push_back(Triple::aarch64); SupportedArchs.push_back(Triple::arm); SupportedArchs.push_back(Triple::mips); SupportedArchs.push_back(Triple::x86); SupportedArchs.push_back(Triple::x86_64); + // Some architectures have sub-architectures in which tests will fail, like + // ARM. These two vectors will define if they do have sub-archs (to avoid + // extra work for those who don't), and if so, if they are listed to work + HasSubArchs.push_back(Triple::arm); + SupportedSubArchs.push_back("armv6"); + SupportedSubArchs.push_back("armv7"); + // The operating systems below are known to be sufficiently incompatible // that they will fail the MCJIT C API tests. UnsupportedOSs.push_back(Triple::Cygwin); } -}; - -TEST_F(MCJITCAPITest, simple_function) { - SKIP_UNSUPPORTED_PLATFORM; - char *error = 0; + virtual void SetUp() { + didCallAllocateCodeSection = false; + Module = 0; + Function = 0; + Engine = 0; + Error = 0; + } - // Creates a function that returns 42, compiles it, and runs it. + virtual void TearDown() { + if (Engine) + LLVMDisposeExecutionEngine(Engine); + else if (Module) + LLVMDisposeModule(Module); + } - LLVMModuleRef module = LLVMModuleCreateWithName("simple_module"); + void buildSimpleFunction() { + Module = LLVMModuleCreateWithName("simple_module"); + + LLVMSetTarget(Module, HostTriple.c_str()); + + Function = LLVMAddFunction( + Module, "simple_function", LLVMFunctionType(LLVMInt32Type(), 0, 0, 0)); + LLVMSetFunctionCallConv(Function, LLVMCCallConv); + + LLVMBasicBlockRef entry = LLVMAppendBasicBlock(Function, "entry"); + LLVMBuilderRef builder = LLVMCreateBuilder(); + LLVMPositionBuilderAtEnd(builder, entry); + LLVMBuildRet(builder, LLVMConstInt(LLVMInt32Type(), 42, 0)); + + LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error); + LLVMDisposeMessage(Error); + + LLVMDisposeBuilder(builder); + } - LLVMValueRef function = LLVMAddFunction( - module, "simple_function", LLVMFunctionType(LLVMInt32Type(), 0, 0, 0)); - LLVMSetFunctionCallConv(function, LLVMCCallConv); + void buildMCJITOptions() { + LLVMInitializeMCJITCompilerOptions(&Options, sizeof(Options)); + Options.OptLevel = 2; + + // Just ensure that this field still exists. + Options.NoFramePointerElim = false; + } - LLVMBasicBlockRef entry = LLVMAppendBasicBlock(function, "entry"); - LLVMBuilderRef builder = LLVMCreateBuilder(); - LLVMPositionBuilderAtEnd(builder, entry); - LLVMBuildRet(builder, LLVMConstInt(LLVMInt32Type(), 42, 0)); + void useRoundTripSectionMemoryManager() { + Options.MCJMM = LLVMCreateSimpleMCJITMemoryManager( + new SectionMemoryManager(), + roundTripAllocateCodeSection, + roundTripAllocateDataSection, + roundTripFinalizeMemory, + roundTripDestroy); + } - LLVMVerifyModule(module, LLVMAbortProcessAction, &error); - LLVMDisposeMessage(error); + void buildMCJITEngine() { + ASSERT_EQ( + 0, LLVMCreateMCJITCompilerForModule(&Engine, Module, &Options, + sizeof(Options), &Error)); + } - LLVMDisposeBuilder(builder); + void buildAndRunPasses() { + LLVMPassManagerRef pass = LLVMCreatePassManager(); + LLVMAddTargetData(LLVMGetExecutionEngineTargetData(Engine), pass); + LLVMAddConstantPropagationPass(pass); + LLVMAddInstructionCombiningPass(pass); + LLVMRunPassManager(pass, Module); + LLVMDisposePassManager(pass); + } - LLVMMCJITCompilerOptions options; - LLVMInitializeMCJITCompilerOptions(&options, sizeof(options)); - options.OptLevel = 2; + LLVMModuleRef Module; + LLVMValueRef Function; + LLVMMCJITCompilerOptions Options; + LLVMExecutionEngineRef Engine; + char *Error; +}; + +TEST_F(MCJITCAPITest, simple_function) { + SKIP_UNSUPPORTED_PLATFORM; - // Just ensure that this field still exists. - options.NoFramePointerElim = false; + buildSimpleFunction(); + buildMCJITOptions(); + buildMCJITEngine(); + buildAndRunPasses(); + + union { + void *raw; + int (*usable)(); + } functionPointer; + functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function); - LLVMExecutionEngineRef engine; - ASSERT_EQ( - 0, LLVMCreateMCJITCompilerForModule(&engine, module, &options, - sizeof(options), &error)); + EXPECT_EQ(42, functionPointer.usable()); +} + +TEST_F(MCJITCAPITest, custom_memory_manager) { + SKIP_UNSUPPORTED_PLATFORM; - LLVMPassManagerRef pass = LLVMCreatePassManager(); - LLVMAddTargetData(LLVMGetExecutionEngineTargetData(engine), pass); - LLVMAddConstantPropagationPass(pass); - LLVMAddInstructionCombiningPass(pass); - LLVMRunPassManager(pass, module); - LLVMDisposePassManager(pass); + buildSimpleFunction(); + buildMCJITOptions(); + useRoundTripSectionMemoryManager(); + buildMCJITEngine(); + buildAndRunPasses(); union { void *raw; int (*usable)(); } functionPointer; - functionPointer.raw = LLVMGetPointerToGlobal(engine, function); + functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function); EXPECT_EQ(42, functionPointer.usable()); - - LLVMDisposeExecutionEngine(engine); + EXPECT_TRUE(didCallAllocateCodeSection); } - diff --git a/unittests/ExecutionEngine/MCJIT/MCJITMemoryManagerTest.cpp b/unittests/ExecutionEngine/MCJIT/MCJITMemoryManagerTest.cpp index ab09aca..9e0b353 100644 --- a/unittests/ExecutionEngine/MCJIT/MCJITMemoryManagerTest.cpp +++ b/unittests/ExecutionEngine/MCJIT/MCJITMemoryManagerTest.cpp @@ -46,7 +46,7 @@ TEST(MCJITMemoryManagerTest, BasicAllocations) { }
std::string Error;
- EXPECT_FALSE(MemMgr->applyPermissions(&Error));
+ EXPECT_FALSE(MemMgr->finalizeMemory(&Error));
}
TEST(MCJITMemoryManagerTest, LargeAllocations) {
@@ -79,7 +79,7 @@ TEST(MCJITMemoryManagerTest, LargeAllocations) { }
std::string Error;
- EXPECT_FALSE(MemMgr->applyPermissions(&Error));
+ EXPECT_FALSE(MemMgr->finalizeMemory(&Error));
}
TEST(MCJITMemoryManagerTest, ManyAllocations) {
@@ -114,7 +114,7 @@ TEST(MCJITMemoryManagerTest, ManyAllocations) { }
std::string Error;
- EXPECT_FALSE(MemMgr->applyPermissions(&Error));
+ EXPECT_FALSE(MemMgr->finalizeMemory(&Error));
}
TEST(MCJITMemoryManagerTest, ManyVariedAllocations) {
diff --git a/unittests/ExecutionEngine/MCJIT/MCJITObjectCacheTest.cpp b/unittests/ExecutionEngine/MCJIT/MCJITObjectCacheTest.cpp index 0061e30..32fc292 100644 --- a/unittests/ExecutionEngine/MCJIT/MCJITObjectCacheTest.cpp +++ b/unittests/ExecutionEngine/MCJIT/MCJITObjectCacheTest.cpp @@ -98,14 +98,13 @@ protected: void compileAndRun(int ExpectedRC = OriginalRC) { // This function shouldn't be called until after SetUp. - ASSERT_TRUE(0 != TheJIT); + ASSERT_TRUE(TheJIT.isValid()); ASSERT_TRUE(0 != Main); + // We may be using a null cache, so ensure compilation is valid. TheJIT->finalizeObject(); void *vPtr = TheJIT->getPointerToFunction(Main); - static_cast<SectionMemoryManager*>(MM)->invalidateInstructionCache(); - EXPECT_TRUE(0 != vPtr) << "Unable to get pointer to main() from JIT"; diff --git a/unittests/ExecutionEngine/MCJIT/MCJITTest.cpp b/unittests/ExecutionEngine/MCJIT/MCJITTest.cpp index e9cf904..43a8298 100644 --- a/unittests/ExecutionEngine/MCJIT/MCJITTest.cpp +++ b/unittests/ExecutionEngine/MCJIT/MCJITTest.cpp @@ -34,6 +34,7 @@ namespace { /* TEST_F(MCJITTest, empty_module) { createJIT(M.take()); + TheJIT->finalizeObject(); //EXPECT_NE(0, TheJIT->getObjectImage()) // << "Unable to generate executable loaded object image"; } @@ -46,8 +47,7 @@ TEST_F(MCJITTest, global_variable) { GlobalValue *Global = insertGlobalInt32(M.get(), "test_global", initialValue); createJIT(M.take()); void *globalPtr = TheJIT->getPointerToGlobal(Global); - MM->applyPermissions(); - static_cast<SectionMemoryManager*>(MM)->invalidateInstructionCache(); + TheJIT->finalizeObject(); EXPECT_TRUE(0 != globalPtr) << "Unable to get pointer to global value from JIT"; @@ -61,8 +61,7 @@ TEST_F(MCJITTest, add_function) { Function *F = insertAddFunction(M.get()); createJIT(M.take()); void *addPtr = TheJIT->getPointerToFunction(F); - MM->applyPermissions(); - static_cast<SectionMemoryManager*>(MM)->invalidateInstructionCache(); + TheJIT->finalizeObject(); EXPECT_TRUE(0 != addPtr) << "Unable to get pointer to function from JIT"; @@ -79,8 +78,7 @@ TEST_F(MCJITTest, run_main) { Function *Main = insertMainFunction(M.get(), 6); createJIT(M.take()); void *vPtr = TheJIT->getPointerToFunction(Main); - MM->applyPermissions(); - static_cast<SectionMemoryManager*>(MM)->invalidateInstructionCache(); + TheJIT->finalizeObject(); EXPECT_TRUE(0 != vPtr) << "Unable to get pointer to main() from JIT"; @@ -102,8 +100,7 @@ TEST_F(MCJITTest, return_global) { createJIT(M.take()); void *rgvPtr = TheJIT->getPointerToFunction(ReturnGlobal); - MM->applyPermissions(); - static_cast<SectionMemoryManager*>(MM)->invalidateInstructionCache(); + TheJIT->finalizeObject(); EXPECT_TRUE(0 != rgvPtr); int32_t(*FuncPtr)(void) = (int32_t(*)(void))(intptr_t)rgvPtr; @@ -134,6 +131,7 @@ TEST_F(MCJITTest, increment_global) { createJIT(M.take()); void *gvPtr = TheJIT->getPointerToGlobal(GV); + TheJIT->finalizeObject(); EXPECT_EQ(initialNum, *(int32_t*)gvPtr); void *vPtr = TheJIT->getPointerToFunction(IncrementGlobal); @@ -150,6 +148,9 @@ TEST_F(MCJITTest, increment_global) { } */ +// PR16013: XFAIL this test on ARM, which currently can't handle multiple relocations. +#if !defined(__arm__) + TEST_F(MCJITTest, multiple_functions) { SKIP_UNSUPPORTED_PLATFORM; @@ -172,8 +173,7 @@ TEST_F(MCJITTest, multiple_functions) { createJIT(M.take()); void *vPtr = TheJIT->getPointerToFunction(Outer); - MM->applyPermissions(); - static_cast<SectionMemoryManager*>(MM)->invalidateInstructionCache(); + TheJIT->finalizeObject(); EXPECT_TRUE(0 != vPtr) << "Unable to get pointer to outer function from JIT"; @@ -182,6 +182,8 @@ TEST_F(MCJITTest, multiple_functions) { << "Incorrect result returned from function"; } +#endif /*!defined(__arm__)*/ + // FIXME: ExecutionEngine has no support empty modules /* TEST_F(MCJITTest, multiple_empty_modules) { @@ -219,6 +221,7 @@ TEST_F(MCJITTest, multiple_modules) { // get a function pointer in a module that was not used in EE construction void *vPtr = TheJIT->getPointerToFunction(Caller); + TheJIT->finalizeObject(); EXPECT_NE(0, vPtr) << "Unable to get pointer to caller function from JIT"; diff --git a/unittests/ExecutionEngine/MCJIT/MCJITTestAPICommon.h b/unittests/ExecutionEngine/MCJIT/MCJITTestAPICommon.h index 8160a18..7b6e39f 100644 --- a/unittests/ExecutionEngine/MCJIT/MCJITTestAPICommon.h +++ b/unittests/ExecutionEngine/MCJIT/MCJITTestAPICommon.h @@ -49,11 +49,23 @@ protected: /// Returns true if the host architecture is known to support MCJIT bool ArchSupportsMCJIT() { Triple Host(HostTriple); + // If ARCH is not supported, bail if (std::find(SupportedArchs.begin(), SupportedArchs.end(), Host.getArch()) - == SupportedArchs.end()) { + == SupportedArchs.end()) return false; - } - return true; + + // If ARCH is supported and has no specific sub-arch support + if (std::find(HasSubArchs.begin(), HasSubArchs.end(), Host.getArch()) + == HasSubArchs.end()) + return true; + + // If ARCH has sub-arch support, find it + SmallVectorImpl<std::string>::const_iterator I = SupportedSubArchs.begin(); + for(; I != SupportedSubArchs.end(); ++I) + if (Host.getArchName().startswith(I->c_str())) + return true; + + return false; } /// Returns true if the host OS is known to support MCJIT @@ -68,6 +80,8 @@ protected: std::string HostTriple; SmallVector<Triple::ArchType, 4> SupportedArchs; + SmallVector<Triple::ArchType, 1> HasSubArchs; + SmallVector<std::string, 2> SupportedSubArchs; // We need to own the memory SmallVector<Triple::OSType, 4> UnsupportedOSs; }; diff --git a/unittests/ExecutionEngine/MCJIT/MCJITTestBase.h b/unittests/ExecutionEngine/MCJIT/MCJITTestBase.h index b0e98a8..95a5c8b 100644 --- a/unittests/ExecutionEngine/MCJIT/MCJITTestBase.h +++ b/unittests/ExecutionEngine/MCJIT/MCJITTestBase.h @@ -44,11 +44,19 @@ protected: // The architectures below are known to be compatible with MCJIT as they // are copied from test/ExecutionEngine/MCJIT/lit.local.cfg and should be // kept in sync. + SupportedArchs.push_back(Triple::aarch64); SupportedArchs.push_back(Triple::arm); SupportedArchs.push_back(Triple::mips); SupportedArchs.push_back(Triple::x86); SupportedArchs.push_back(Triple::x86_64); + // Some architectures have sub-architectures in which tests will fail, like + // ARM. These two vectors will define if they do have sub-archs (to avoid + // extra work for those who don't), and if so, if they are listed to work + HasSubArchs.push_back(Triple::arm); + SupportedSubArchs.push_back("armv6"); + SupportedSubArchs.push_back("armv7"); + // The operating systems below are known to be incompatible with MCJIT as // they are copied from the test/ExecutionEngine/MCJIT/lit.local.cfg and // should be kept in sync. @@ -165,7 +173,7 @@ protected: std::string Error; TheJIT.reset(EB.setEngineKind(EngineKind::JIT) .setUseMCJIT(true) /* can this be folded into the EngineKind enum? */ - .setJITMemoryManager(MM) + .setMCJITMemoryManager(MM) .setErrorStr(&Error) .setOptLevel(CodeGenOpt::None) .setAllocateGVsWithCode(false) /*does this do anything?*/ @@ -185,10 +193,9 @@ protected: CodeModel::Model CodeModel; StringRef MArch; SmallVector<std::string, 1> MAttrs; - OwningPtr<TargetMachine> TM; OwningPtr<ExecutionEngine> TheJIT; IRBuilder<> Builder; - JITMemoryManager *MM; + RTDyldMemoryManager *MM; OwningPtr<Module> M; }; diff --git a/unittests/IR/CMakeLists.txt b/unittests/IR/CMakeLists.txt index b6098c7..c53043e 100644 --- a/unittests/IR/CMakeLists.txt +++ b/unittests/IR/CMakeLists.txt @@ -13,6 +13,7 @@ set(IRSources MDBuilderTest.cpp MetadataTest.cpp PassManagerTest.cpp + PatternMatch.cpp TypeBuilderTest.cpp TypesTest.cpp ValueMapTest.cpp diff --git a/unittests/IR/PatternMatch.cpp b/unittests/IR/PatternMatch.cpp new file mode 100644 index 0000000..7c6d8ce --- /dev/null +++ b/unittests/IR/PatternMatch.cpp @@ -0,0 +1,265 @@ +//===---- llvm/unittest/IR/PatternMatch.cpp - PatternMatch unit tests ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/STLExtras.h" +#include "llvm/Analysis/ValueTracking.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/MDBuilder.h" +#include "llvm/IR/Operator.h" +#include "llvm/Support/NoFolder.h" +#include "llvm/Support/PatternMatch.h" +#include "gtest/gtest.h" + +using namespace llvm::PatternMatch; + +namespace llvm { +namespace { + +/// Ordered floating point minimum/maximum tests. + +static void m_OrdFMin_expect_match_and_delete(Value *Cmp, Value *Select, + Value *L, Value *R) { + Value *MatchL, *MatchR; + EXPECT_TRUE(m_OrdFMin(m_Value(MatchL), m_Value(MatchR)).match(Select)); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + delete Select; + delete Cmp; +} + +static void m_OrdFMin_expect_nomatch_and_delete(Value *Cmp, Value *Select, + Value *L, Value *R) { + Value *MatchL, *MatchR; + EXPECT_FALSE(m_OrdFMin(m_Value(MatchL), m_Value(MatchR)).match(Select)); + delete Select; + delete Cmp; +} + +static void m_OrdFMax_expect_match_and_delete(Value *Cmp, Value *Select, + Value *L, Value *R) { + Value *MatchL, *MatchR; + EXPECT_TRUE(m_OrdFMax(m_Value(MatchL), m_Value(MatchR)).match(Select)); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + delete Select; + delete Cmp; +} + +static void m_OrdFMax_expect_nomatch_and_delete(Value *Cmp, Value *Select, + Value *L, Value *R) { + Value *MatchL, *MatchR; + EXPECT_FALSE(m_OrdFMax(m_Value(MatchL), m_Value(MatchR)).match(Select)); + delete Select; + delete Cmp; +} + + + +TEST(PatternMatchTest, FloatingPointOrderedMin) { + LLVMContext &C(getGlobalContext()); + IRBuilder<true, NoFolder> Builder(C); + + Type *FltTy = Builder.getFloatTy(); + Value *L = ConstantFP::get(FltTy, 1.0); + Value *R = ConstantFP::get(FltTy, 2.0); + + // Test OLT. + Value *Cmp = Builder.CreateFCmpOLT(L, R); + Value *Select = Builder.CreateSelect(Cmp, L, R); + m_OrdFMin_expect_match_and_delete(Cmp, Select, L, R); + + // Test OLE. + Cmp = Builder.CreateFCmpOLE(L, R); + Select = Builder.CreateSelect(Cmp, L, R); + m_OrdFMin_expect_match_and_delete(Cmp, Select, L, R); + + // Test no match on OGE. + Cmp = Builder.CreateFCmpOGE(L, R); + Select = Builder.CreateSelect(Cmp, L, R); + m_OrdFMin_expect_nomatch_and_delete(Cmp, Select, L, R); + + // Test no match on OGT. + Cmp = Builder.CreateFCmpOGT(L, R); + Select = Builder.CreateSelect(Cmp, L, R); + m_OrdFMin_expect_nomatch_and_delete(Cmp, Select, L, R); + + // Test match on OGE with inverted select. + Cmp = Builder.CreateFCmpOGE(L, R); + Select = Builder.CreateSelect(Cmp, R, L); + m_OrdFMin_expect_match_and_delete(Cmp, Select, L, R); + + // Test match on OGT with inverted select. + Cmp = Builder.CreateFCmpOGT(L, R); + Select = Builder.CreateSelect(Cmp, R, L); + m_OrdFMin_expect_match_and_delete(Cmp, Select, L, R); +} + +TEST(PatternMatchTest, FloatingPointOrderedMax) { + LLVMContext &C(getGlobalContext()); + IRBuilder<true, NoFolder> Builder(C); + + Type *FltTy = Builder.getFloatTy(); + Value *L = ConstantFP::get(FltTy, 1.0); + Value *R = ConstantFP::get(FltTy, 2.0); + + // Test OGT. + Value *Cmp = Builder.CreateFCmpOGT(L, R); + Value *Select = Builder.CreateSelect(Cmp, L, R); + m_OrdFMax_expect_match_and_delete(Cmp, Select, L, R); + + // Test OGE. + Cmp = Builder.CreateFCmpOGE(L, R); + Select = Builder.CreateSelect(Cmp, L, R); + m_OrdFMax_expect_match_and_delete(Cmp, Select, L, R); + + // Test no match on OLE. + Cmp = Builder.CreateFCmpOLE(L, R); + Select = Builder.CreateSelect(Cmp, L, R); + m_OrdFMax_expect_nomatch_and_delete(Cmp, Select, L, R); + + // Test no match on OLT. + Cmp = Builder.CreateFCmpOLT(L, R); + Select = Builder.CreateSelect(Cmp, L, R); + m_OrdFMax_expect_nomatch_and_delete(Cmp, Select, L, R); + + // Test match on OLE with inverted select. + Cmp = Builder.CreateFCmpOLE(L, R); + Select = Builder.CreateSelect(Cmp, R, L); + m_OrdFMax_expect_match_and_delete(Cmp, Select, L, R); + + // Test match on OLT with inverted select. + Cmp = Builder.CreateFCmpOLT(L, R); + Select = Builder.CreateSelect(Cmp, R, L); + m_OrdFMax_expect_match_and_delete(Cmp, Select, L, R); +} + +/// Unordered floating point minimum/maximum tests. + +static void m_UnordFMin_expect_match_and_delete(Value *Cmp, Value *Select, + Value *L, Value *R) { + Value *MatchL, *MatchR; + EXPECT_TRUE(m_UnordFMin(m_Value(MatchL), m_Value(MatchR)).match(Select)); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + delete Select; + delete Cmp; +} + +static void m_UnordFMin_expect_nomatch_and_delete(Value *Cmp, Value *Select, + Value *L, Value *R) { + Value *MatchL, *MatchR; + EXPECT_FALSE(m_UnordFMin(m_Value(MatchL), m_Value(MatchR)).match(Select)); + delete Select; + delete Cmp; +} + +static void m_UnordFMax_expect_match_and_delete(Value *Cmp, Value *Select, + Value *L, Value *R) { + Value *MatchL, *MatchR; + EXPECT_TRUE(m_UnordFMax(m_Value(MatchL), m_Value(MatchR)).match(Select)); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + delete Select; + delete Cmp; +} + +static void m_UnordFMax_expect_nomatch_and_delete(Value *Cmp, Value *Select, + Value *L, Value *R) { + Value *MatchL, *MatchR; + EXPECT_FALSE(m_UnordFMax(m_Value(MatchL), m_Value(MatchR)).match(Select)); + delete Select; + delete Cmp; +} + +TEST(PatternMatchTest, FloatingPointUnorderedMin) { + LLVMContext &C(getGlobalContext()); + IRBuilder<true, NoFolder> Builder(C); + + Type *FltTy = Builder.getFloatTy(); + Value *L = ConstantFP::get(FltTy, 1.0); + Value *R = ConstantFP::get(FltTy, 2.0); + + // Test ULT. + Value *Cmp = Builder.CreateFCmpULT(L, R); + Value *Select = Builder.CreateSelect(Cmp, L, R); + m_UnordFMin_expect_match_and_delete(Cmp, Select, L, R); + + // Test ULE. + Cmp = Builder.CreateFCmpULE(L, R); + Select = Builder.CreateSelect(Cmp, L, R); + m_UnordFMin_expect_match_and_delete(Cmp, Select, L, R); + + // Test no match on UGE. + Cmp = Builder.CreateFCmpUGE(L, R); + Select = Builder.CreateSelect(Cmp, L, R); + m_UnordFMin_expect_nomatch_and_delete(Cmp, Select, L, R); + + // Test no match on UGT. + Cmp = Builder.CreateFCmpUGT(L, R); + Select = Builder.CreateSelect(Cmp, L, R); + m_UnordFMin_expect_nomatch_and_delete(Cmp, Select, L, R); + + // Test match on UGE with inverted select. + Cmp = Builder.CreateFCmpUGE(L, R); + Select = Builder.CreateSelect(Cmp, R, L); + m_UnordFMin_expect_match_and_delete(Cmp, Select, L, R); + + // Test match on UGT with inverted select. + Cmp = Builder.CreateFCmpUGT(L, R); + Select = Builder.CreateSelect(Cmp, R, L); + m_UnordFMin_expect_match_and_delete(Cmp, Select, L, R); +} + +TEST(PatternMatchTest, FloatingPointUnorderedMax) { + LLVMContext &C(getGlobalContext()); + IRBuilder<true, NoFolder> Builder(C); + + Type *FltTy = Builder.getFloatTy(); + Value *L = ConstantFP::get(FltTy, 1.0); + Value *R = ConstantFP::get(FltTy, 2.0); + + // Test UGT. + Value *Cmp = Builder.CreateFCmpUGT(L, R); + Value *Select = Builder.CreateSelect(Cmp, L, R); + m_UnordFMax_expect_match_and_delete(Cmp, Select, L, R); + + // Test UGE. + Cmp = Builder.CreateFCmpUGE(L, R); + Select = Builder.CreateSelect(Cmp, L, R); + m_UnordFMax_expect_match_and_delete(Cmp, Select, L, R); + + // Test no match on ULE. + Cmp = Builder.CreateFCmpULE(L, R); + Select = Builder.CreateSelect(Cmp, L, R); + m_UnordFMax_expect_nomatch_and_delete(Cmp, Select, L, R); + + // Test no match on ULT. + Cmp = Builder.CreateFCmpULT(L, R); + Select = Builder.CreateSelect(Cmp, L, R); + m_UnordFMax_expect_nomatch_and_delete(Cmp, Select, L, R); + + // Test match on ULE with inverted select. + Cmp = Builder.CreateFCmpULE(L, R); + Select = Builder.CreateSelect(Cmp, R, L); + m_UnordFMax_expect_match_and_delete(Cmp, Select, L, R); + + // Test match on ULT with inverted select. + Cmp = Builder.CreateFCmpULT(L, R); + Select = Builder.CreateSelect(Cmp, R, L); + m_UnordFMax_expect_match_and_delete(Cmp, Select, L, R); +} + +} // anonymous namespace. +} // llvm namespace. diff --git a/unittests/Support/CMakeLists.txt b/unittests/Support/CMakeLists.txt index e6cafbc..b66c5db 100644 --- a/unittests/Support/CMakeLists.txt +++ b/unittests/Support/CMakeLists.txt @@ -20,6 +20,7 @@ add_llvm_unittest(SupportTests LeakDetectorTest.cpp ManagedStatic.cpp MathExtrasTest.cpp + MD5Test.cpp MemoryBufferTest.cpp MemoryTest.cpp Path.cpp diff --git a/unittests/Support/CommandLineTest.cpp b/unittests/Support/CommandLineTest.cpp index 43c8cbd..cd235d2 100644 --- a/unittests/Support/CommandLineTest.cpp +++ b/unittests/Support/CommandLineTest.cpp @@ -41,6 +41,45 @@ class TempEnvVar { const char *const name; }; +cl::OptionCategory TestCategory("Test Options", "Description"); +cl::opt<int> TestOption("test-option", cl::desc("old description")); +TEST(CommandLineTest, ModifyExisitingOption) { + const char Description[] = "New description"; + const char ArgString[] = "new-test-option"; + const char ValueString[] = "Integer"; + + StringMap<cl::Option*> Map; + cl::getRegisteredOptions(Map); + + ASSERT_TRUE(Map.count("test-option") == 1) << + "Could not find option in map."; + + cl::Option *Retrieved = Map["test-option"]; + ASSERT_EQ(&TestOption, Retrieved) << "Retrieved wrong option."; + + ASSERT_EQ(&cl::GeneralCategory,Retrieved->Category) << + "Incorrect default option category."; + + Retrieved->setCategory(TestCategory); + ASSERT_EQ(&TestCategory,Retrieved->Category) << + "Failed to modify option's option category."; + + Retrieved->setDescription(Description); + ASSERT_STREQ(Retrieved->HelpStr, Description) << + "Changing option description failed."; + + Retrieved->setArgStr(ArgString); + ASSERT_STREQ(ArgString, Retrieved->ArgStr) << + "Failed to modify option's Argument string."; + + Retrieved->setValueStr(ValueString); + ASSERT_STREQ(Retrieved->ValueStr, ValueString) << + "Failed to modify option's Value string."; + + Retrieved->setHiddenFlag(cl::Hidden); + ASSERT_EQ(cl::Hidden, TestOption.getOptionHiddenFlag()) << + "Failed to modify option's hidden flag."; +} #ifndef SKIP_ENVIRONMENT_TESTS const char test_env_var[] = "LLVM_TEST_COMMAND_LINE_FLAGS"; @@ -55,6 +94,12 @@ TEST(CommandLineTest, ParseEnvironment) { // This test used to make valgrind complain // ("Conditional jump or move depends on uninitialised value(s)") +// +// Warning: Do not run any tests after this one that try to gain access to +// registered command line options because this will likely result in a +// SEGFAULT. This can occur because the cl::opt in the test below is declared +// on the stack which will be destroyed after the test completes but the +// command line system will still hold a pointer to a deallocated cl::Option. TEST(CommandLineTest, ParseEnvironmentToLocalVar) { // Put cl::opt on stack to check for proper initialization of fields. cl::opt<std::string> EnvironmentTestOptionLocal("env-test-opt-local"); @@ -66,4 +111,11 @@ TEST(CommandLineTest, ParseEnvironmentToLocalVar) { #endif // SKIP_ENVIRONMENT_TESTS +TEST(CommandLineTest, UseOptionCategory) { + cl::opt<int> TestOption2("test-option", cl::cat(TestCategory)); + + ASSERT_EQ(&TestCategory,TestOption2.Category) << "Failed to assign Option " + "Category."; +} + } // anonymous namespace diff --git a/unittests/Support/FileOutputBufferTest.cpp b/unittests/Support/FileOutputBufferTest.cpp index 80d7245..c7ca1ab 100644 --- a/unittests/Support/FileOutputBufferTest.cpp +++ b/unittests/Support/FileOutputBufferTest.cpp @@ -11,7 +11,7 @@ #include "llvm/ADT/OwningPtr.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" -#include "llvm/Support/PathV2.h" +#include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include "gtest/gtest.h" diff --git a/unittests/Support/MD5Test.cpp b/unittests/Support/MD5Test.cpp new file mode 100644 index 0000000..7c1331b --- /dev/null +++ b/unittests/Support/MD5Test.cpp @@ -0,0 +1,60 @@ +//===- llvm/unittest/Support/MD5Test.cpp - MD5 tests ----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements unit tests for the MD5 functions. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/MD5.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { +/// \brief Tests an arbitrary set of bytes passed as \p Input. +void TestMD5Sum(ArrayRef<uint8_t> Input, StringRef Final) { + MD5 Hash; + Hash.update(Input); + MD5::MD5Result MD5Res; + Hash.final(MD5Res); + SmallString<32> Res; + MD5::stringifyResult(MD5Res, Res); + EXPECT_EQ(Res, Final); +} + +void TestMD5Sum(StringRef Input, StringRef Final) { + MD5 Hash; + Hash.update(Input); + MD5::MD5Result MD5Res; + Hash.final(MD5Res); + SmallString<32> Res; + MD5::stringifyResult(MD5Res, Res); + EXPECT_EQ(Res, Final); +} + +TEST(MD5Test, MD5) { + TestMD5Sum(ArrayRef<uint8_t>((const uint8_t *)"", (size_t) 0), + "d41d8cd98f00b204e9800998ecf8427e"); + TestMD5Sum(ArrayRef<uint8_t>((const uint8_t *)"a", (size_t) 1), + "0cc175b9c0f1b6a831c399e269772661"); + TestMD5Sum(ArrayRef<uint8_t>((const uint8_t *)"abcdefghijklmnopqrstuvwxyz", + (size_t) 26), + "c3fcd3d76192e4007dfb496cca67e13b"); + TestMD5Sum(ArrayRef<uint8_t>((const uint8_t *)"\0", (size_t) 1), + "93b885adfe0da089cdf634904fd59f71"); + TestMD5Sum(ArrayRef<uint8_t>((const uint8_t *)"a\0", (size_t) 2), + "4144e195f46de78a3623da7364d04f11"); + TestMD5Sum(ArrayRef<uint8_t>((const uint8_t *)"abcdefghijklmnopqrstuvwxyz\0", + (size_t) 27), + "81948d1f1554f58cd1a56ebb01f808cb"); + TestMD5Sum("abcdefghijklmnopqrstuvwxyz", "c3fcd3d76192e4007dfb496cca67e13b"); +} +} diff --git a/unittests/Support/ManagedStatic.cpp b/unittests/Support/ManagedStatic.cpp index 8ddad38..1497f4e 100644 --- a/unittests/Support/ManagedStatic.cpp +++ b/unittests/Support/ManagedStatic.cpp @@ -19,7 +19,8 @@ using namespace llvm; namespace { -#if defined(HAVE_PTHREAD_H) && !__has_feature(memory_sanitizer) +#if LLVM_ENABLE_THREADS != 0 && defined(HAVE_PTHREAD_H) && \ + !__has_feature(memory_sanitizer) namespace test1 { llvm::ManagedStatic<int> ms; void *helper(void*) { diff --git a/unittests/Support/MathExtrasTest.cpp b/unittests/Support/MathExtrasTest.cpp index 0a6724c..93a38cb 100644 --- a/unittests/Support/MathExtrasTest.cpp +++ b/unittests/Support/MathExtrasTest.cpp @@ -14,6 +14,109 @@ using namespace llvm; namespace { +TEST(MathExtras, countTrailingZeros) { + uint8_t Z8 = 0; + uint16_t Z16 = 0; + uint32_t Z32 = 0; + uint64_t Z64 = 0; + EXPECT_EQ(8u, countTrailingZeros(Z8)); + EXPECT_EQ(16u, countTrailingZeros(Z16)); + EXPECT_EQ(32u, countTrailingZeros(Z32)); + EXPECT_EQ(64u, countTrailingZeros(Z64)); + + uint8_t NZ8 = 42; + uint16_t NZ16 = 42; + uint32_t NZ32 = 42; + uint64_t NZ64 = 42; + EXPECT_EQ(1u, countTrailingZeros(NZ8)); + EXPECT_EQ(1u, countTrailingZeros(NZ16)); + EXPECT_EQ(1u, countTrailingZeros(NZ32)); + EXPECT_EQ(1u, countTrailingZeros(NZ64)); +} + +TEST(MathExtras, countLeadingZeros) { + uint8_t Z8 = 0; + uint16_t Z16 = 0; + uint32_t Z32 = 0; + uint64_t Z64 = 0; + EXPECT_EQ(8u, countLeadingZeros(Z8)); + EXPECT_EQ(16u, countLeadingZeros(Z16)); + EXPECT_EQ(32u, countLeadingZeros(Z32)); + EXPECT_EQ(64u, countLeadingZeros(Z64)); + + uint8_t NZ8 = 42; + uint16_t NZ16 = 42; + uint32_t NZ32 = 42; + uint64_t NZ64 = 42; + EXPECT_EQ(2u, countLeadingZeros(NZ8)); + EXPECT_EQ(10u, countLeadingZeros(NZ16)); + EXPECT_EQ(26u, countLeadingZeros(NZ32)); + EXPECT_EQ(58u, countLeadingZeros(NZ64)); + + EXPECT_EQ(8u, countLeadingZeros(0x00F000FFu)); + EXPECT_EQ(8u, countLeadingZeros(0x00F12345u)); + for (unsigned i = 0; i <= 30; ++i) { + EXPECT_EQ(31 - i, countLeadingZeros(1u << i)); + } + + EXPECT_EQ(8u, countLeadingZeros(0x00F1234500F12345ULL)); + EXPECT_EQ(1u, countLeadingZeros(1ULL << 62)); + for (unsigned i = 0; i <= 62; ++i) { + EXPECT_EQ(63 - i, countLeadingZeros(1ULL << i)); + } +} + +TEST(MathExtras, findFirstSet) { + uint8_t Z8 = 0; + uint16_t Z16 = 0; + uint32_t Z32 = 0; + uint64_t Z64 = 0; + EXPECT_EQ(0xFFULL, findFirstSet(Z8)); + EXPECT_EQ(0xFFFFULL, findFirstSet(Z16)); + EXPECT_EQ(0xFFFFFFFFULL, findFirstSet(Z32)); + EXPECT_EQ(0xFFFFFFFFFFFFFFFFULL, findFirstSet(Z64)); + + uint8_t NZ8 = 42; + uint16_t NZ16 = 42; + uint32_t NZ32 = 42; + uint64_t NZ64 = 42; + EXPECT_EQ(1u, findFirstSet(NZ8)); + EXPECT_EQ(1u, findFirstSet(NZ16)); + EXPECT_EQ(1u, findFirstSet(NZ32)); + EXPECT_EQ(1u, findFirstSet(NZ64)); +} + +TEST(MathExtras, findLastSet) { + uint8_t Z8 = 0; + uint16_t Z16 = 0; + uint32_t Z32 = 0; + uint64_t Z64 = 0; + EXPECT_EQ(0xFFULL, findLastSet(Z8)); + EXPECT_EQ(0xFFFFULL, findLastSet(Z16)); + EXPECT_EQ(0xFFFFFFFFULL, findLastSet(Z32)); + EXPECT_EQ(0xFFFFFFFFFFFFFFFFULL, findLastSet(Z64)); + + uint8_t NZ8 = 42; + uint16_t NZ16 = 42; + uint32_t NZ32 = 42; + uint64_t NZ64 = 42; + EXPECT_EQ(5u, findLastSet(NZ8)); + EXPECT_EQ(5u, findLastSet(NZ16)); + EXPECT_EQ(5u, findLastSet(NZ32)); + EXPECT_EQ(5u, findLastSet(NZ64)); +} + +TEST(MathExtras, reverseBits) { + uint8_t NZ8 = 42; + uint16_t NZ16 = 42; + uint32_t NZ32 = 42; + uint64_t NZ64 = 42; + EXPECT_EQ(0x54ULL, reverseBits(NZ8)); + EXPECT_EQ(0x5400ULL, reverseBits(NZ16)); + EXPECT_EQ(0x54000000ULL, reverseBits(NZ32)); + EXPECT_EQ(0x5400000000000000ULL, reverseBits(NZ64)); +} + TEST(MathExtras, isPowerOf2_32) { EXPECT_TRUE(isPowerOf2_32(1 << 6)); EXPECT_TRUE(isPowerOf2_32(1 << 12)); @@ -38,22 +141,6 @@ TEST(MathExtras, ByteSwap_64) { EXPECT_EQ(0x1100FFEEDDCCBBAAULL, ByteSwap_64(0xAABBCCDDEEFF0011LL)); } -TEST(MathExtras, CountLeadingZeros_32) { - EXPECT_EQ(8u, CountLeadingZeros_32(0x00F000FF)); - EXPECT_EQ(8u, CountLeadingZeros_32(0x00F12345)); - for (unsigned i = 0; i <= 30; ++i) { - EXPECT_EQ(31 - i, CountLeadingZeros_32(1 << i)); - } -} - -TEST(MathExtras, CountLeadingZeros_64) { - EXPECT_EQ(8u, CountLeadingZeros_64(0x00F1234500F12345LL)); - EXPECT_EQ(1u, CountLeadingZeros_64(1LL << 62)); - for (unsigned i = 0; i <= 62; ++i) { - EXPECT_EQ(63 - i, CountLeadingZeros_64(1LL << i)); - } -} - TEST(MathExtras, CountLeadingOnes_32) { for (int i = 30; i >= 0; --i) { // Start with all ones and unset some bit. diff --git a/unittests/Support/Path.cpp b/unittests/Support/Path.cpp index eec8c62..2f820b9 100644 --- a/unittests/Support/Path.cpp +++ b/unittests/Support/Path.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Support/PathV2.h" +#include "llvm/Support/Path.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/raw_ostream.h" diff --git a/unittests/Support/ProcessTest.cpp b/unittests/Support/ProcessTest.cpp index e57c0e6..eff9c71 100644 --- a/unittests/Support/ProcessTest.cpp +++ b/unittests/Support/ProcessTest.cpp @@ -26,7 +26,7 @@ TEST(ProcessTest, SelfProcess) { #if defined(LLVM_ON_UNIX) EXPECT_EQ(getpid(), process::get_self()->get_id()); #elif defined(LLVM_ON_WIN32) - EXPECT_EQ(GetCurrentProcess(), process::get_self()->get_id()); + EXPECT_EQ(GetCurrentProcessId(), process::get_self()->get_id()); #endif EXPECT_LT(1u, process::get_self()->page_size()); |