aboutsummaryrefslogtreecommitdiff
path: root/llvm/unittests
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/unittests')
-rw-r--r--llvm/unittests/ADT/APFloatTest.cpp1152
-rw-r--r--llvm/unittests/ADT/APIntTest.cpp125
-rw-r--r--llvm/unittests/ADT/DenseMapTest.cpp52
-rw-r--r--llvm/unittests/ADT/SmallPtrSetTest.cpp4
-rw-r--r--llvm/unittests/ADT/StringMapTest.cpp54
-rw-r--r--llvm/unittests/Analysis/IR2VecTest.cpp271
-rw-r--r--llvm/unittests/Analysis/ValueTrackingTest.cpp36
-rw-r--r--llvm/unittests/BinaryFormat/MsgPackDocumentTest.cpp96
-rw-r--r--llvm/unittests/BinaryFormat/SFrameTest.cpp44
-rw-r--r--llvm/unittests/CAS/ActionCacheTest.cpp73
-rw-r--r--llvm/unittests/CAS/CASTestConfig.cpp21
-rw-r--r--llvm/unittests/CAS/CASTestConfig.h38
-rw-r--r--llvm/unittests/CAS/CMakeLists.txt13
-rw-r--r--llvm/unittests/CAS/ObjectStoreTest.cpp348
-rw-r--r--llvm/unittests/CGData/StableFunctionMapTest.cpp2
-rw-r--r--llvm/unittests/CMakeLists.txt1
-rw-r--r--llvm/unittests/CodeGen/DroppedVariableStatsMIRTest.cpp28
-rw-r--r--llvm/unittests/CodeGen/GlobalISel/KnownBitsVectorTest.cpp45
-rw-r--r--llvm/unittests/CodeGen/TypeTraitsTest.cpp3
-rw-r--r--llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp20
-rw-r--r--llvm/unittests/ExecutionEngine/Orc/ThreadSafeModuleTest.cpp28
-rw-r--r--llvm/unittests/Frontend/HLSLBindingTest.cpp18
-rw-r--r--llvm/unittests/Frontend/HLSLRootSignatureDumpTest.cpp23
-rw-r--r--llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp24
-rw-r--r--llvm/unittests/IR/CMakeLists.txt1
-rw-r--r--llvm/unittests/IR/ConstantRangeTest.cpp59
-rw-r--r--llvm/unittests/IR/DebugInfoTest.cpp19
-rw-r--r--llvm/unittests/IR/InstructionsTest.cpp17
-rw-r--r--llvm/unittests/IR/PatternMatch.cpp36
-rw-r--r--llvm/unittests/IR/RuntimeLibcallsTest.cpp63
-rw-r--r--llvm/unittests/Object/ELFObjectFileTest.cpp4
-rw-r--r--llvm/unittests/ObjectYAML/DXContainerYAMLTest.cpp40
-rw-r--r--llvm/unittests/Support/AlignOfTest.cpp2
-rw-r--r--llvm/unittests/Support/CMakeLists.txt1
-rw-r--r--llvm/unittests/Support/DebugLogTest.cpp14
-rw-r--r--llvm/unittests/Support/DebugTest.cpp42
-rw-r--r--llvm/unittests/Support/DynamicLibrary/CMakeLists.txt6
-rw-r--r--llvm/unittests/Support/Path.cpp37
-rw-r--r--llvm/unittests/Support/ProgramTest.cpp83
-rw-r--r--llvm/unittests/Support/ThreadPool.cpp14
-rw-r--r--llvm/unittests/Support/raw_ostream_proxy_test.cpp225
-rw-r--r--llvm/unittests/Target/AArch64/CMakeLists.txt1
-rw-r--r--llvm/unittests/Target/AArch64/MCInstrAnalysisTest.cpp191
-rw-r--r--llvm/unittests/Target/AArch64/SMEAttributesTest.cpp6
-rw-r--r--llvm/unittests/Target/AMDGPU/AMDGPUUnitTests.cpp20
-rw-r--r--llvm/unittests/Target/AMDGPU/CSETest.cpp1
-rw-r--r--llvm/unittests/Target/DirectX/PointerTypeAnalysisTests.cpp28
-rw-r--r--llvm/unittests/Target/DirectX/ResourceBindingAnalysisTests.cpp14
-rw-r--r--llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp12
-rw-r--r--llvm/unittests/TargetParser/RISCVISAInfoTest.cpp9
-rw-r--r--llvm/unittests/Transforms/IPO/FunctionSpecializationTest.cpp11
-rw-r--r--llvm/unittests/Transforms/Utils/LocalTest.cpp8
-rw-r--r--llvm/unittests/Transforms/Vectorize/SandboxVectorizer/SeedCollectorTest.cpp47
-rw-r--r--llvm/unittests/Transforms/Vectorize/VPlanHCFGTest.cpp2
-rw-r--r--llvm/unittests/Transforms/Vectorize/VPlanTest.cpp2
-rw-r--r--llvm/unittests/Transforms/Vectorize/VPlanTestBase.h10
-rw-r--r--llvm/unittests/Transforms/Vectorize/VPlanVerifierTest.cpp7
57 files changed, 3221 insertions, 330 deletions
diff --git a/llvm/unittests/ADT/APFloatTest.cpp b/llvm/unittests/ADT/APFloatTest.cpp
index a35594d..141282e 100644
--- a/llvm/unittests/ADT/APFloatTest.cpp
+++ b/llvm/unittests/ADT/APFloatTest.cpp
@@ -1660,6 +1660,90 @@ TEST(APFloatTest, toInteger) {
EXPECT_EQ(APSInt::getMaxValue(5, false), result);
}
+class APFloatConvertFromAPIntParamTest
+ : public ::testing::TestWithParam<const fltSemantics *> {
+protected:
+ // Helper to run a conversion and compare the integer result directly.
+ static void testConversionAndCompareInt(const APInt &InputValue,
+ const bool IsSigned,
+ APFloat::roundingMode RM,
+ const APInt &ExpectedIntValue) {
+ const fltSemantics &Sem = *GetParam();
+ APFloat F(Sem);
+ F.convertFromAPInt(InputValue, /*IsSigned=*/IsSigned, RM);
+
+ APSInt ResultInt(InputValue.getBitWidth(), /*isUnsigned=*/!IsSigned);
+ bool IsExact;
+ F.convertToInteger(ResultInt, APFloat::rmTowardZero, &IsExact);
+
+ EXPECT_TRUE(IsExact);
+ EXPECT_TRUE(ResultInt.eq(ExpectedIntValue))
+ << "InputValue: " << InputValue << "\n"
+ << ResultInt << " vs " << ExpectedIntValue << "\n";
+ }
+};
+
+TEST_P(APFloatConvertFromAPIntParamTest, HalfwayRounding) {
+ const fltSemantics &Sem = *GetParam();
+ const unsigned Precision = APFloat::semanticsPrecision(Sem);
+
+ if (Precision == 0)
+ GTEST_SKIP() << "Skipping test for semantics with no significand.";
+
+ for (bool IsSigned : {false, true}) {
+ const unsigned BitWidth = Precision + 1 + (IsSigned ? 1 : 0);
+
+ const APInt RoundedDownVal = APInt::getOneBitSet(BitWidth, Precision);
+ const APInt HalfwayVal = RoundedDownVal + 1;
+ const APInt RoundedUpVal = RoundedDownVal + 2;
+
+ testConversionAndCompareInt(HalfwayVal, IsSigned,
+ APFloat::rmNearestTiesToEven, RoundedDownVal);
+ testConversionAndCompareInt(HalfwayVal, IsSigned,
+ APFloat::rmNearestTiesToAway, RoundedUpVal);
+ testConversionAndCompareInt(HalfwayVal, IsSigned, APFloat::rmTowardPositive,
+ RoundedUpVal);
+ testConversionAndCompareInt(HalfwayVal, IsSigned, APFloat::rmTowardNegative,
+ RoundedDownVal);
+ testConversionAndCompareInt(HalfwayVal, IsSigned, APFloat::rmTowardZero,
+ RoundedDownVal);
+ }
+}
+
+TEST_P(APFloatConvertFromAPIntParamTest, MaxMagnitude) {
+ const fltSemantics &Sem = *GetParam();
+ const unsigned Precision = APFloat::semanticsPrecision(Sem);
+
+ if (Precision == 0)
+ GTEST_SKIP() << "Skipping test for semantics with no significand.";
+
+ const APFloat Largest = APFloat::getLargest(Sem, /*Negative=*/false);
+ const int Exp = ilogb(Largest);
+ for (bool IsSigned : {false, true}) {
+ const unsigned BitWidth = Exp + 1 + (IsSigned ? 1 : 0);
+
+ bool IsExact;
+ APSInt LargestAsInt{BitWidth, /*IsUnsigned=*/!IsSigned};
+ const APFloat::opStatus ToIntStatus =
+ Largest.convertToInteger(LargestAsInt, APFloat::rmTowardZero, &IsExact);
+ EXPECT_EQ(ToIntStatus, APFloat::opOK);
+
+ for (const APFloat::roundingMode RM :
+ {APFloat::rmNearestTiesToAway, APFloat::rmTowardNegative,
+ APFloat::rmTowardPositive, APFloat::rmTowardZero,
+ APFloat::rmNearestTiesToEven}) {
+ testConversionAndCompareInt(LargestAsInt, IsSigned, RM, LargestAsInt);
+ }
+ }
+}
+
+INSTANTIATE_TEST_SUITE_P(IEEESemantics, APFloatConvertFromAPIntParamTest,
+ ::testing::Values(&APFloat::IEEEhalf(),
+ &APFloat::BFloat(),
+ &APFloat::IEEEsingle(),
+ &APFloat::IEEEdouble(),
+ &APFloat::IEEEquad()));
+
static APInt nanbitsFromAPInt(const fltSemantics &Sem, bool SNaN, bool Negative,
uint64_t payload) {
APInt appayload(64, payload);
@@ -1918,6 +2002,15 @@ TEST(APFloatTest, exactInverse) {
EXPECT_TRUE(inv.bitwiseIsEqual(APFloat(APFloat::PPCDoubleDouble(), "0.5")));
EXPECT_TRUE(APFloat(APFloat::x87DoubleExtended(), "2.0").getExactInverse(&inv));
EXPECT_TRUE(inv.bitwiseIsEqual(APFloat(APFloat::x87DoubleExtended(), "0.5")));
+ // 0x1p1022 has a normal inverse for IEEE 754 binary64: 0x1p-1022.
+ EXPECT_TRUE(APFloat(0x1p1022).getExactInverse(&inv));
+ EXPECT_TRUE(inv.bitwiseIsEqual(APFloat(0x1p-1022)));
+ // With regards to getExactInverse, IEEEdouble and PPCDoubleDouble should
+ // behave the same.
+ EXPECT_TRUE(
+ APFloat(APFloat::PPCDoubleDouble(), "0x1p1022").getExactInverse(&inv));
+ EXPECT_TRUE(
+ inv.bitwiseIsEqual(APFloat(APFloat::PPCDoubleDouble(), "0x1p-1022")));
// FLT_MIN
EXPECT_TRUE(APFloat(1.17549435e-38f).getExactInverse(&inv));
@@ -1929,6 +2022,8 @@ TEST(APFloatTest, exactInverse) {
EXPECT_FALSE(APFloat(0.0).getExactInverse(nullptr));
// Denormalized float
EXPECT_FALSE(APFloat(1.40129846e-45f).getExactInverse(nullptr));
+ // Largest subnormal
+ EXPECT_FALSE(APFloat(0x1p-127f).getExactInverse(nullptr));
}
TEST(APFloatTest, roundToIntegral) {
@@ -2692,9 +2787,7 @@ static APFloat makeDoubleAPFloat(T Hi, U Lo) {
return APFloat(APFloat::PPCDoubleDouble(), Bits);
}
-static APFloat makeDoubleAPFloat(DD X) {
- return makeDoubleAPFloat(X.Hi, X.Lo);
-}
+static APFloat makeDoubleAPFloat(DD X) { return makeDoubleAPFloat(X.Hi, X.Lo); }
TEST(APFloatTest, PPCDoubleDouble) {
APFloat test(APFloat::PPCDoubleDouble(), "1.0");
@@ -5799,6 +5892,363 @@ TEST_P(PPCDoubleDoubleRoundToIntegralValueTest,
}
}
+namespace PPCDoubleDoubleConvertToIntegerTestDetails {
+// Define the rounding modes for easier readability.
+static constexpr auto RNE = APFloat::rmNearestTiesToEven;
+static constexpr auto RNA = APFloat::rmNearestTiesToAway;
+static constexpr auto RTZ = APFloat::rmTowardZero;
+static constexpr auto RUP = APFloat::rmTowardPositive;
+static constexpr auto RDN = APFloat::rmTowardNegative;
+
+struct TestCase {
+ // Structure to hold the expected result of a conversion
+ struct ExpectedConversion {
+ // The expected integer value represented as a string (decimal).
+ // We use a string to easily represent arbitrary precision values in
+ // constexpr. The test runner should parse this into an APSInt matching the
+ // test configuration.
+ const char *ExpectedIntStr;
+ APFloat::opStatus Status;
+ };
+
+ DD Input;
+ unsigned IntegerWidth;
+ bool IsSigned;
+ // Array indexed by the rounding mode enum value.
+ std::array<ExpectedConversion, 5> Rounded = {};
+
+ // Helper to define the expected results for a specific rounding mode.
+ constexpr TestCase &with(APFloat::roundingMode RM, const char *ExpectedStr,
+ APFloat::opStatus Status) {
+ Rounded[static_cast<std::underlying_type_t<APFloat::roundingMode>>(RM)] = {
+ ExpectedStr,
+ Status,
+ };
+ return *this;
+ }
+
+ // Helper to define the same result for all rounding modes.
+ constexpr TestCase &withAll(const char *ExpectedStr,
+ APFloat::opStatus Status) {
+ return with(RNE, ExpectedStr, Status)
+ .with(RNA, ExpectedStr, Status)
+ .with(RTZ, ExpectedStr, Status)
+ .with(RUP, ExpectedStr, Status)
+ .with(RDN, ExpectedStr, Status);
+ }
+};
+
+auto testCases() {
+ // Define the status codes.
+ constexpr auto OK = llvm::APFloat::opOK;
+ constexpr auto Inexact = llvm::APFloat::opInexact;
+ // The API specifies opInvalidOp for out-of-range (overflow/underflow) and
+ // NaN.
+ constexpr auto Invalid = llvm::APFloat::opInvalidOp;
+
+ // Helper constants for constructing specific DD values.
+ constexpr double Infinity = std::numeric_limits<double>::infinity();
+ constexpr double NaN = std::numeric_limits<double>::quiet_NaN();
+ constexpr double DMAX = std::numeric_limits<double>::max();
+
+ // Powers of 2
+ constexpr double P53 = 0x1p53;
+ constexpr double P63 = 0x1p63;
+ constexpr double P64 = 0x1p64;
+ // 2^-100 (A very small delta demonstrating extended precision)
+ constexpr double PM100 = 0x1p-100;
+
+ static constexpr auto ConvertToIntegerTestCases = std::array{
+ // 1. Zeros, NaNs, and Infinities (Target: 64-bit Signed)
+ // INT64_MAX = 9223372036854775807
+ // INT64_MIN = -9223372036854775808
+
+ // Input: Positive Zero (0.0, 0.0)
+ TestCase{{0.0, 0.0}, 64, true}.withAll("0", OK),
+
+ // Input: Negative Zero (-0.0, 0.0)
+ TestCase{{-0.0, 0.0}, 64, true}.withAll("0", OK),
+
+ // Input: NaN. Expected behavior: Invalid, deterministic result of 0.
+ TestCase{{NaN, 0.0}, 64, true}.withAll("0", Invalid),
+
+ // Input: +Infinity. Expected behavior: Invalid, deterministic result of
+ // INT64_MAX.
+ TestCase{{Infinity, 0.0}, 64, true}.withAll("9223372036854775807",
+ Invalid),
+
+ // Input: -Infinity. Expected behavior: Invalid, deterministic result of
+ // INT64_MIN.
+ TestCase{{-Infinity, 0.0}, 64, true}.withAll("-9223372036854775808",
+ Invalid),
+
+ // 2. Basic Rounding and Tie-Breaking (Target: 32-bit Signed)
+
+ // Input: 2.5 (Tie, preceding integer is Even)
+ TestCase{{2.5, 0.0}, 32, true}
+ .with(RTZ, "2", Inexact)
+ .with(RDN, "2", Inexact)
+ .with(RUP, "3", Inexact)
+ .with(RNA, "3", Inexact)
+ .with(RNE, "2", Inexact),
+
+ // Input: 3.5 (Tie, preceding integer is Odd)
+ TestCase{{3.5, 0.0}, 32, true}
+ .with(RTZ, "3", Inexact)
+ .with(RDN, "3", Inexact)
+ .with(RUP, "4", Inexact)
+ .with(RNA, "4", Inexact)
+ .with(RNE, "4", Inexact),
+
+ // Input: -2.5 (Tie, preceding integer is Even)
+ TestCase{{-2.5, 0.0}, 32, true}
+ .with(RTZ, "-2", Inexact)
+ .with(RDN, "-3", Inexact)
+ .with(RUP, "-2", Inexact)
+ .with(RNA, "-3", Inexact)
+ .with(RNE, "-2", Inexact),
+
+ // 3. Double-Double Precision (The role of 'lo')
+ // Testing how extended precision affects rounding decisions.
+
+ // Input: 2.5 + Epsilon (Slightly above tie)
+ TestCase{{2.5, PM100}, 32, true}
+ .with(RTZ, "2", Inexact)
+ .with(RDN, "2", Inexact)
+ .with(RUP, "3", Inexact)
+ .with(RNA, "3", Inexact)
+ .with(RNE, "3", Inexact),
+
+ // Input: 2.5 - Epsilon (Slightly below tie)
+ TestCase{{2.5, -PM100}, 32, true}
+ .with(RTZ, "2", Inexact)
+ .with(RDN, "2", Inexact)
+ .with(RUP, "3", Inexact)
+ .with(RNA, "2", Inexact)
+ .with(RNE, "2", Inexact),
+
+ // Input: 1.0 + Epsilon (Just above 1.0, e.g., 1.00...1)
+ TestCase{{1.0, PM100}, 32, true}
+ .with(RTZ, "1", Inexact)
+ .with(RDN, "1", Inexact)
+ .with(RUP, "2", Inexact)
+ .with(RNA, "1", Inexact)
+ .with(RNE, "1", Inexact),
+
+ // Input: 1.0 - Epsilon (Just below 1.0, e.g. 0.999...)
+ TestCase{{1.0, -PM100}, 32, true}
+ .with(RTZ, "0", Inexact)
+ .with(RDN, "0", Inexact)
+ .with(RUP, "1", Inexact)
+ .with(RNA, "1", Inexact)
+ .with(RNE, "1", Inexact),
+
+ // Input: Large number tie-breaking (Crucial test for DD implementation)
+ // Input: 2^53 + 1.5.
+ // A standard double(2^53 + 1.5) rounds to 2^53 + 2.0.
+ // The DD representation must precisely hold 2^53 + 1.5.
+ // The canonical DD representation is {2^53 + 2.0, -0.5}.
+ // Value is 9007199254740993.5
+ TestCase{{P53 + 2.0, -0.5}, 64, true}
+ .with(RTZ, "9007199254740993", Inexact)
+ .with(RDN, "9007199254740993", Inexact)
+ .with(RUP, "9007199254740994", Inexact)
+ .with(RNA, "9007199254740994", Inexact)
+ .with(RNE, "9007199254740994", Inexact),
+
+ // 4. Overflow Boundaries (Signed)
+
+ // Input: Exactly INT64_MAX. (2^63 - 1)
+ // Represented precisely as (2^63, -1.0)
+ TestCase{{P63, -1.0}, 64, true}.withAll("9223372036854775807", OK),
+
+ // Input: INT64_MAX + 0.3.
+ // Represented as (2^63, -0.7)
+ TestCase{{P63, -0.7}, 64, true}
+ .with(RTZ, "9223372036854775807", Inexact)
+ .with(RDN, "9223372036854775807", Inexact)
+ .with(RNA, "9223372036854775807", Inexact)
+ .with(RNE, "9223372036854775807", Inexact)
+ .with(RUP, "9223372036854775807", Invalid),
+
+ // Input: INT64_MAX + 0.5 (Tie at the boundary)
+ // Represented as (2^63, -0.5). Target integers are MAX (odd) and 2^63
+ // (even).
+ TestCase{{P63, -0.5}, 64, true}
+ .with(RTZ, "9223372036854775807", Inexact)
+ .with(RDN, "9223372036854775807", Inexact)
+ .with(RUP, "9223372036854775807", Invalid)
+ .with(RNA, "9223372036854775807", Invalid)
+ .with(RNE, "9223372036854775807", Invalid),
+
+ // Input: 2^55 - 2^1 - 2^-52 to signed integer.
+ // Represented as (2^55 - 2^2, 2^1 - 2^-1).
+ TestCase{{0x1.fffffffffffffp+54, 0x1.8p0}, 56, true}
+ .with(RTZ, "36028797018963965", Inexact)
+ .with(RDN, "36028797018963965", Inexact)
+ .with(RUP, "36028797018963966", Inexact)
+ .with(RNA, "36028797018963966", Inexact)
+ .with(RNE, "36028797018963966", Inexact),
+
+ // Input: 2^55 - 2^1 - 2^-52 to signed integer.
+ // Represented as (2^55 - 2^2, 2^1 - 2^-52).
+ TestCase{{0x1.fffffffffffffp+54, 0x1.fffffffffffffp0}, 56, true}
+ .with(RTZ, "36028797018963965", Inexact)
+ .with(RDN, "36028797018963965", Inexact)
+ .with(RUP, "36028797018963966", Inexact)
+ .with(RNA, "36028797018963966", Inexact)
+ .with(RNE, "36028797018963966", Inexact),
+
+ // Input: Exactly 2^63 (One past INT64_MAX)
+ TestCase{{P63, 0.0}, 64, true}.withAll("9223372036854775807", Invalid),
+
+ // Input: Exactly INT64_MIN (-2^63)
+ TestCase{{-P63, 0.0}, 64, true}.withAll("-9223372036854775808", OK),
+
+ // Input: INT64_MIN - 0.5 (Tie at the lower boundary)
+ // Target integers are -2^63-1 (odd) and MIN (even).
+ TestCase{{-P63, -0.5}, 64, true}
+ .with(RTZ, "-9223372036854775808", Inexact)
+ .with(RUP, "-9223372036854775808", Inexact)
+ // RDN rounds down, causing overflow.
+ .with(RDN, "-9223372036854775808", Invalid)
+ // RNA rounds away (down), causing overflow.
+ .with(RNA, "-9223372036854775808", Invalid)
+ // RNE rounds to even (up to -2^63), which is OK.
+ .with(RNE, "-9223372036854775808", Inexact),
+
+ // 5. Overflow Boundaries (Unsigned)
+ // UINT64_MAX = 18446744073709551615 (2^64 - 1)
+
+ // Input: Exactly UINT64_MAX. (2^64 - 1)
+ // Represented precisely as (2^64, -1.0)
+ TestCase{{P64, -1.0}, 64, false}.withAll("18446744073709551615", OK),
+
+ // Input: UINT64_MAX + 0.5 (Tie at the boundary)
+ // Represented as (2^64, -0.5)
+ TestCase{{P64, -0.5}, 64, false}
+ .with(RTZ, "18446744073709551615", Inexact)
+ .with(RDN, "18446744073709551615", Inexact)
+ // RUP rounds up (2^64), causing overflow.
+ .with(RUP, "18446744073709551615", Invalid)
+ // RNA rounds away (up), causing overflow.
+ .with(RNA, "18446744073709551615", Invalid)
+ // RNE rounds to even (up to 2^64), causing overflow.
+ .with(RNE, "18446744073709551615", Invalid),
+
+ // Input: 2^55 - 2^1 - 2^-52 to unsigned integer.
+ // Represented as (2^55 - 2^2, 2^1 - 2^-1).
+ TestCase{{0x1.fffffffffffffp+54, 0x1.8p0}, 55, false}
+ .with(RTZ, "36028797018963965", Inexact)
+ .with(RDN, "36028797018963965", Inexact)
+ .with(RUP, "36028797018963966", Inexact)
+ .with(RNA, "36028797018963966", Inexact)
+ .with(RNE, "36028797018963966", Inexact),
+
+ // Input: 2^55 - 2^1 - 2^-52 to unsigned integer.
+ // Represented as (2^55 - 2^2, 2^1 - 2^-52).
+ TestCase{{0x1.fffffffffffffp+54, 0x1.fffffffffffffp0}, 55, false}
+ .with(RTZ, "36028797018963965", Inexact)
+ .with(RDN, "36028797018963965", Inexact)
+ .with(RUP, "36028797018963966", Inexact)
+ .with(RNA, "36028797018963966", Inexact)
+ .with(RNE, "36028797018963966", Inexact),
+
+ // Input: -0.3 (Slightly below zero)
+ TestCase{{-0.3, 0.0}, 64, false}
+ .with(RTZ, "0", Inexact)
+ .with(RUP, "0", Inexact)
+ .with(RNA, "0", Inexact)
+ .with(RNE, "0", Inexact)
+ .with(RDN, "0", Invalid),
+
+ // Input: -0.5 (Tie at zero)
+ TestCase{{-0.5, 0.0}, 64, false}
+ .with(RTZ, "0", Inexact)
+ .with(RUP, "0", Inexact)
+ // RNE rounds to even (0).
+ .with(RNE, "0", Inexact)
+ .with(RDN, "0", Invalid)
+ // RNA rounds away (-1), causing overflow.
+ .with(RNA, "0", Invalid),
+
+ // Input: -1.0 (Negative integer)
+ TestCase{{-1.0, 0.0}, 64, false}.withAll("0", Invalid),
+
+ // 6. High Precision Integers (Target: 128-bit Signed)
+ // INT128_MAX = 170141183460469231731687303715884105727
+
+ // Input: 2^100 (Exactly representable in DD)
+ // 2^100 = 1267650600228229401496703205376.0
+ TestCase{{1267650600228229401496703205376.0, 0.0}, 128, true}.withAll(
+ "1267650600228229401496703205376", OK),
+
+ // Input: DMAX. (Approx 1.8e308).
+ // This is vastly larger than INT128_MAX (Approx 1.7e38).
+ TestCase{{DMAX, 0.0}, 128, true}.withAll(
+ "170141183460469231731687303715884105727", Invalid),
+
+ // Input: Largest semPPCDoubleDoubleLegacy
+ TestCase{{DMAX, 0x1.ffffffffffffep+969}, 128, true}.withAll(
+ "170141183460469231731687303715884105727", Invalid),
+
+ // 7. Round to negative -0
+ TestCase{{-PM100, 0.0}, 32, true}
+ .with(RTZ, "0", Inexact)
+ .with(RUP, "0", Inexact)
+ .with(RNA, "0", Inexact)
+ .with(RNE, "0", Inexact)
+ .with(RDN, "-1", Inexact),
+ };
+ return ConvertToIntegerTestCases;
+}
+} // namespace PPCDoubleDoubleConvertToIntegerTestDetails
+
+class PPCDoubleDoubleConvertToIntegerValueTest
+ : public testing::Test,
+ public ::testing::WithParamInterface<
+ PPCDoubleDoubleConvertToIntegerTestDetails::TestCase> {};
+
+INSTANTIATE_TEST_SUITE_P(
+ PPCDoubleDoubleConvertToIntegerValueParamTests,
+ PPCDoubleDoubleConvertToIntegerValueTest,
+ ::testing::ValuesIn(
+ PPCDoubleDoubleConvertToIntegerTestDetails::testCases()));
+
+TEST_P(PPCDoubleDoubleConvertToIntegerValueTest,
+ PPCDoubleDoubleConvertToInteger) {
+ const PPCDoubleDoubleConvertToIntegerTestDetails::TestCase Params =
+ GetParam();
+ const APFloat Input = makeDoubleAPFloat(Params.Input);
+ EXPECT_FALSE(Input.isDenormal())
+ << Params.Input.Hi << " + " << Params.Input.Lo;
+
+ for (size_t I = 0, E = std::size(Params.Rounded); I != E; ++I) {
+ const auto RM = static_cast<APFloat::roundingMode>(I);
+ const auto &Expected = Params.Rounded[I];
+ APSInt ActualInteger(Params.IntegerWidth, /*isUnsigned=*/!Params.IsSigned);
+
+ APSInt ExpectedInteger{Expected.ExpectedIntStr};
+ EXPECT_LE(ExpectedInteger.getBitWidth(), Params.IntegerWidth);
+ ExpectedInteger = ExpectedInteger.extend(Params.IntegerWidth);
+ if (ExpectedInteger.isUnsigned() && Params.IsSigned) {
+ ExpectedInteger.setIsSigned(Params.IsSigned);
+ EXPECT_FALSE(ExpectedInteger.isNegative());
+ }
+
+ const bool NegativeUnderflow =
+ ExpectedInteger.isZero() && Input.isNegative();
+ const bool ExpectedIsExact =
+ Expected.Status == APFloat::opOK && !NegativeUnderflow;
+ bool ActualIsExact;
+ const auto ActualStatus =
+ Input.convertToInteger(ActualInteger, RM, &ActualIsExact);
+ EXPECT_EQ(ActualStatus, Expected.Status);
+ EXPECT_EQ(ActualIsExact, ExpectedIsExact);
+ EXPECT_EQ(ActualInteger, ExpectedInteger);
+ }
+}
+
TEST(APFloatTest, PPCDoubleDoubleCompare) {
using DataType =
std::tuple<uint64_t, uint64_t, uint64_t, uint64_t, APFloat::cmpResult>;
@@ -5841,6 +6291,102 @@ TEST(APFloatTest, PPCDoubleDoubleCompare) {
}
}
+namespace PPCDoubleDoubleCompareAbsoluteValueTestDetails {
+struct TestCase {
+ DD LHS;
+ DD RHS;
+ APFloat::cmpResult Result;
+};
+
+auto testCases() {
+ static constexpr auto CompareAbsoluteValueTestCases = std::array{
+ TestCase{
+ {1.0, 0.0},
+ {1.0, 0.0},
+ APFloat::cmpEqual,
+ },
+ TestCase{
+ {1.0, -0.0},
+ {1.0, +0.0},
+ APFloat::cmpEqual,
+ },
+ TestCase{
+ {1.0, 0.0},
+ {0x1.0000000000001p+0, 0.0},
+ APFloat::cmpLessThan,
+ },
+ TestCase{
+ {0x1.0000000000001p+0, 0.0},
+ {1.0, 0.0},
+ APFloat::cmpGreaterThan,
+ },
+ TestCase{
+ {0x1.0000000000001p+0, +0x1p-1074},
+ {1.0, -0x1p-1074},
+ APFloat::cmpGreaterThan,
+ },
+ TestCase{
+ {0x1.0000000000001p+0, -0x1p-1074},
+ {1.0, +0x1p-1074},
+ APFloat::cmpGreaterThan,
+ },
+ TestCase{
+ {1.0, 0.0},
+ {1.0, -0x1p-1074},
+ APFloat::cmpGreaterThan,
+ },
+ TestCase{
+ {1.0, 0.0},
+ {1.0, +0x1p-1074},
+ APFloat::cmpLessThan,
+ },
+ TestCase{
+ {1.0, +0x1p-1073},
+ {1.0, -0x1p-1074},
+ APFloat::cmpGreaterThan,
+ },
+ TestCase{
+ {1.0, +0x1p-1074},
+ {1.0, -0x1p-1074},
+ APFloat::cmpGreaterThan,
+ },
+ };
+ return CompareAbsoluteValueTestCases;
+}
+} // namespace PPCDoubleDoubleCompareAbsoluteValueTestDetails
+
+class PPCDoubleDoubleCompareAbsoluteValueValueTest
+ : public testing::Test,
+ public ::testing::WithParamInterface<
+ PPCDoubleDoubleCompareAbsoluteValueTestDetails::TestCase> {};
+
+INSTANTIATE_TEST_SUITE_P(
+ PPCDoubleDoubleCompareAbsoluteValueValueParamTests,
+ PPCDoubleDoubleCompareAbsoluteValueValueTest,
+ ::testing::ValuesIn(
+ PPCDoubleDoubleCompareAbsoluteValueTestDetails::testCases()));
+
+TEST_P(PPCDoubleDoubleCompareAbsoluteValueValueTest,
+ PPCDoubleDoubleCompareAbsoluteValue) {
+ auto Param = GetParam();
+ for (bool LHSNegate : {false, true}) {
+ auto LHS = llvm::detail::DoubleAPFloat{APFloat::PPCDoubleDouble(),
+ APFloat{Param.LHS.Hi},
+ APFloat{Param.LHS.Lo}};
+ if (LHSNegate)
+ LHS.changeSign();
+ for (bool RHSNegate : {false, true}) {
+ auto RHS = llvm::detail::DoubleAPFloat{APFloat::PPCDoubleDouble(),
+ APFloat{Param.RHS.Hi},
+ APFloat{Param.RHS.Lo}};
+ if (RHSNegate)
+ RHS.changeSign();
+
+ EXPECT_EQ(LHS.compareAbsoluteValue(RHS), Param.Result);
+ }
+ }
+}
+
TEST(APFloatTest, PPCDoubleDoubleBitwiseIsEqual) {
using DataType = std::tuple<uint64_t, uint64_t, uint64_t, uint64_t, bool>;
@@ -5994,19 +6540,328 @@ TEST(APFloatTest, PPCDoubleDoubleScalbn) {
EXPECT_EQ(0x3cc8000000000000ull, Result.bitcastToAPInt().getRawData()[1]);
}
-TEST(APFloatTest, PPCDoubleDoubleFrexp) {
- // 3.0 + 3.0 << 53
- uint64_t Input[] = {
- 0x4008000000000000ull, 0x3cb8000000000000ull,
+namespace PPCDoubleDoubleFrexpTestDetails {
+// Define the rounding modes for easier readability.
+static constexpr auto RNE = APFloat::rmNearestTiesToEven;
+static constexpr auto RNA = APFloat::rmNearestTiesToAway;
+static constexpr auto RTZ = APFloat::rmTowardZero;
+static constexpr auto RUP = APFloat::rmTowardPositive;
+static constexpr auto RDN = APFloat::rmTowardNegative;
+
+struct TestCase {
+ // Structure to hold the expected result of a conversion
+ struct ExpectedFractionExponent {
+ DD Fraction;
+ int Exponent;
+ friend APFloat::cmpResult compare(const ExpectedFractionExponent &Lhs,
+ const ExpectedFractionExponent &Rhs) {
+ const APFloat LhsFraction = makeDoubleAPFloat(Lhs.Fraction);
+ const APFloat RhsFraction = makeDoubleAPFloat(Rhs.Fraction);
+ const APFloat::cmpResult FractionRelation =
+ LhsFraction.compare(RhsFraction);
+ if (FractionRelation == APFloat::cmpUnordered)
+ return APFloat::cmpUnordered;
+ if (LhsFraction.isZero() && RhsFraction.isZero())
+ return APFloat::cmpEqual;
+ if (!LhsFraction.isNegative() &&
+ (RhsFraction.isNegative() || RhsFraction.isZero()))
+ return APFloat::cmpGreaterThan;
+ if (!RhsFraction.isNegative() &&
+ (LhsFraction.isNegative() || LhsFraction.isZero()))
+ return APFloat::cmpLessThan;
+ if (Lhs.Exponent > Rhs.Exponent)
+ return LhsFraction.isNegative() ? APFloat::cmpLessThan
+ : APFloat::cmpGreaterThan;
+ if (Lhs.Exponent < Rhs.Exponent)
+ return RhsFraction.isNegative() ? APFloat::cmpGreaterThan
+ : APFloat::cmpLessThan;
+ return FractionRelation;
+ }
};
- int Exp;
- // 0.75 + 0.75 << 53
- APFloat Result =
- frexp(APFloat(APFloat::PPCDoubleDouble(), APInt(128, 2, Input)), Exp,
- APFloat::rmNearestTiesToEven);
- EXPECT_EQ(2, Exp);
- EXPECT_EQ(0x3fe8000000000000ull, Result.bitcastToAPInt().getRawData()[0]);
- EXPECT_EQ(0x3c98000000000000ull, Result.bitcastToAPInt().getRawData()[1]);
+
+ DD Input;
+ // Array indexed by the rounding mode enum value.
+ std::array<ExpectedFractionExponent, 5> Rounded = {};
+
+ // Helper to define the expected results for a specific rounding mode.
+ constexpr TestCase &with(APFloat::roundingMode RM, DD ExpectedDD,
+ int ExpectedExponent) {
+ Rounded[static_cast<std::underlying_type_t<APFloat::roundingMode>>(RM)] = {
+ ExpectedDD,
+ ExpectedExponent,
+ };
+ return *this;
+ }
+
+ // Helper to define the same result for all rounding modes.
+ constexpr TestCase &withAll(DD ExpectedDD, int ExpectedExponent) {
+ return with(RNE, ExpectedDD, ExpectedExponent)
+ .with(RNA, ExpectedDD, ExpectedExponent)
+ .with(RTZ, ExpectedDD, ExpectedExponent)
+ .with(RUP, ExpectedDD, ExpectedExponent)
+ .with(RDN, ExpectedDD, ExpectedExponent);
+ }
+};
+
+auto testCases() {
+ static constexpr auto FrexpTestCases = std::array{
+ // Input: +infinity
+ TestCase{{std::numeric_limits<double>::infinity(), 0.0}}.withAll(
+ {std::numeric_limits<double>::infinity(), 0.0}, INT_MAX),
+
+ // Input: -infinity
+ TestCase{{-std::numeric_limits<double>::infinity(), 0.0}}.withAll(
+ {-std::numeric_limits<double>::infinity(), 0.0}, INT_MAX),
+
+ // Input: NaN
+ TestCase{{std::numeric_limits<double>::quiet_NaN(), 0.0}}.withAll(
+ {std::numeric_limits<double>::quiet_NaN(), 0.0}, INT_MIN),
+
+ // Input: 2^-1074
+ TestCase{{0x1p-1074, 0.0}}.withAll({0x1p-1, 0.0}, -1073),
+ TestCase{{-0x1p-1074, 0.0}}.withAll({-0x1p-1, 0.0}, -1073),
+
+ // Input: (2^1, -2^-1073 + -2^-1074)
+ TestCase{{0x1p1, -0x1.8p-1073}}
+ .withAll({0x1p0, -0x1p-1073}, 1)
+ .with(RNA, {0x1p0, -0x1p-1074}, 1)
+ .with(RUP, {0x1p0, -0x1p-1074}, 1),
+ TestCase{{-0x1p1, 0x1.8p-1073}}
+ .withAll({-0x1p0, 0x1p-1073}, 1)
+ .with(RNA, {-0x1p0, 0x1p-1074}, 1)
+ .with(RDN, {-0x1p0, 0x1p-1074}, 1),
+
+ // Input: (2^1, -2^-1073)
+ TestCase{{0x1p1, -0x1p-1073}}.withAll({0x1p0, -0x1p-1074}, 1),
+
+ // Input: (2^1, -2^-1074)
+ TestCase{{0x1p1, -0x1p-1074}}
+ .withAll({0x1p-1, -0.0}, 2)
+ .with(RDN, {0x1p0, -0x1p-1074}, 1)
+ .with(RTZ, {0x1p0, -0x1p-1074}, 1),
+
+ // Input: (2^2, -2^-1072 + -2^-1073 + -2^-1074)
+ TestCase{{0x1p2, -0x1.cp-1072}}
+ .withAll({0x1p0, -0x1p-1073}, 2)
+ .with(RUP, {0x1p0, -0x1p-1074}, 2),
+
+ // Input: (2^2, -2^-1072 + -2^-1073)
+ TestCase{{0x1p2, -0x1.8p-1072}}
+ .withAll({0x1p0, -0x1p-1073}, 2)
+ .with(RNA, {0x1p0, -0x1p-1074}, 2)
+ .with(RUP, {0x1p0, -0x1p-1074}, 2),
+ TestCase{{-0x1p2, 0x1.8p-1072}}
+ .withAll({-0x1p0, 0x1p-1073}, 2)
+ .with(RNA, {-0x1p0, 0x1p-1074}, 2)
+ .with(RDN, {-0x1p0, 0x1p-1074}, 2),
+
+ // Input: (2^2, -2^-1072 + -2^-1074)
+ TestCase{{0x1p2, -0x1.4cp-1072}}
+ .withAll({0x1p0, -0x1p-1074}, 2)
+ .with(RDN, {0x1p0, -0x1p-1073}, 2)
+ .with(RTZ, {0x1p0, -0x1p-1073}, 2),
+
+ // Input: (2^2, -2^-1072)
+ TestCase{{0x1p2, -0x1p-1072}}.withAll({0x1p0, -0x1p-1074}, 2),
+
+ // Input: (2^2, -2^-1073 + -2^-1074)
+ TestCase{{0x1p2, -0x1.8p-1073}}
+ .withAll({0x1p0, -0x1p-1074}, 2)
+ .with(RUP, {0x1p-1, -0.0}, 3),
+
+ // Input: (2^2, -2^-1073)
+ TestCase{{0x1p2, -0x1p-1073}}
+ .withAll({0x1p-1, -0.0}, 3)
+ .with(RDN, {0x1p0, -0x1p-1074}, 2)
+ .with(RTZ, {0x1p0, -0x1p-1074}, 2),
+
+ // Input: (2^2, -2^-1074)
+ TestCase{{0x1p2, -0x1p-1074}}
+ .withAll({0x1p-1, -0.0}, 3)
+ .with(RDN, {0x1p0, -0x1p-1074}, 2)
+ .with(RTZ, {0x1p0, -0x1p-1074}, 2),
+
+ // Input: 3+3*2^-53 canonicalized to (3+2^-51, -2^-53)
+ // Output: 0.75+0.75*2^-53 canonicalized to (.75+2^-53, -2^-55)
+ TestCase{{0x1.8000000000001p1, -0x1p-53}}.withAll(
+ {0x1.8000000000001p-1, -0x1p-55}, 2),
+ TestCase{{-0x1.8000000000001p1, 0x1p-53}}.withAll(
+ {-0x1.8000000000001p-1, 0x1p-55}, 2),
+
+ // Input: (2^1021+2^969, 2^968-2^915)
+ TestCase{{0x1.0000000000001p1021, 0x1.fffffffffffffp967}}.withAll(
+ {0x1.0000000000001p-1, 0x1.fffffffffffffp-55}, 1022),
+ TestCase{{-0x1.0000000000001p1021, -0x1.fffffffffffffp967}}.withAll(
+ {-0x1.0000000000001p-1, -0x1.fffffffffffffp-55}, 1022),
+
+ // Input: (2^1023, -2^-1)
+ TestCase{{0x1p+1023, -0x1p-1}}.withAll({0x1p0, -0x1p-1024}, 1023),
+ TestCase{{-0x1p+1023, 0x1p-1}}.withAll({-0x1p0, 0x1p-1024}, 1023),
+
+ // Input: (2^1023, -2^-51)
+ TestCase{{0x1p+1023, -0x1p-51}}.withAll({0x1p0, -0x1p-1074}, 1023),
+ TestCase{{-0x1p+1023, 0x1p-51}}.withAll({-0x1p0, 0x1p-1074}, 1023),
+
+ // Input: (2^1023, -2^-52)
+ TestCase{{0x1p+1023, -0x1p-52}}
+ .withAll({0x1p-1, -0x0p0}, 1024)
+ .with(RDN, {0x1p0, -0x1p-1074}, 1023)
+ .with(RTZ, {0x1p0, -0x1p-1074}, 1023),
+ TestCase{{-0x1p+1023, 0x1p-52}}
+ .withAll({-0x1p-1, 0x0p0}, 1024)
+ .with(RUP, {-0x1p0, 0x1p-1074}, 1023)
+ .with(RTZ, {-0x1p0, 0x1p-1074}, 1023),
+
+ // Input: (2^1023, 2^-1074)
+ TestCase{{0x1p+1023, 0x1p-1074}}
+ .withAll({0x1p-1, 0x0p+0}, 1024)
+ .with(RUP, {0x1p-1, 0x1p-1074}, 1024),
+ TestCase{{-0x1p+1023, -0x1p-1074}}
+ .withAll({-0x1p-1, -0x0p+0}, 1024)
+ .with(RDN, {-0x1p-1, -0x1p-1074}, 1024),
+
+ // Input: (2^1024-2^971, 2^970-2^918)
+ TestCase{{0x1.fffffffffffffp+1023, 0x1.ffffffffffffep+969}}.withAll(
+ {0x1.fffffffffffffp-1, 0x1.ffffffffffffep-55}, 1024),
+ TestCase{{-0x1.fffffffffffffp+1023, -0x1.ffffffffffffep+969}}.withAll(
+ {-0x1.fffffffffffffp-1, -0x1.ffffffffffffep-55}, 1024),
+ };
+ return FrexpTestCases;
+}
+} // namespace PPCDoubleDoubleFrexpTestDetails
+
+class PPCDoubleDoubleFrexpValueTest
+ : public testing::Test,
+ public ::testing::WithParamInterface<
+ PPCDoubleDoubleFrexpTestDetails::TestCase> {};
+
+INSTANTIATE_TEST_SUITE_P(
+ PPCDoubleDoubleFrexpValueParamTests, PPCDoubleDoubleFrexpValueTest,
+ ::testing::ValuesIn(PPCDoubleDoubleFrexpTestDetails::testCases()));
+
+TEST_P(PPCDoubleDoubleFrexpValueTest, PPCDoubleDoubleFrexp) {
+ const PPCDoubleDoubleFrexpTestDetails::TestCase Params = GetParam();
+ const APFloat Input = makeDoubleAPFloat(Params.Input);
+ auto RmToIdx = [](APFloat::roundingMode RM) {
+ return static_cast<std::underlying_type_t<APFloat::roundingMode>>(RM);
+ };
+ // First, make sure our expected results are consistent with each other before
+ // bothering to test the implementation.
+ if (Input.isFinite()) {
+ // Make sure the input is canonical.
+ EXPECT_EQ(APFloat{Params.Input.Hi},
+ APFloat{Params.Input.Hi} + APFloat{Params.Input.Lo})
+ << Params.Input.Hi << " + " << Params.Input.Lo;
+
+ const auto Dn = Params.Rounded[RmToIdx(APFloat::rmTowardNegative)];
+ const auto Up = Params.Rounded[RmToIdx(APFloat::rmTowardPositive)];
+ const auto Tz = Params.Rounded[RmToIdx(APFloat::rmTowardZero)];
+ const auto Ne = Params.Rounded[RmToIdx(APFloat::rmNearestTiesToEven)];
+ const auto Na = Params.Rounded[RmToIdx(APFloat::rmNearestTiesToAway)];
+
+ // The rdn result must be no larger than the rup result.
+ const APFloat::cmpResult DnVsUp = compare(Dn, Up);
+ EXPECT_TRUE(DnVsUp == APFloat::cmpLessThan || DnVsUp == APFloat::cmpEqual);
+
+ for (size_t I = 0, E = std::size(Params.Rounded); I != E; ++I) {
+ const APFloat RoundedFraction =
+ makeDoubleAPFloat(Params.Rounded[I].Fraction);
+ // All possible results should be bracketed by [Dn, Up].
+ const APFloat::cmpResult VsDn = compare(Params.Rounded[I], Dn);
+ EXPECT_TRUE(VsDn == APFloat::cmpGreaterThan || VsDn == APFloat::cmpEqual);
+ const APFloat::cmpResult VsUp = compare(Params.Rounded[I], Up);
+ EXPECT_TRUE(VsUp == APFloat::cmpLessThan || VsUp == APFloat::cmpEqual);
+ // A rounding result is either equal to the rup or rdn result.
+ EXPECT_TRUE(VsUp == APFloat::cmpEqual || VsDn == APFloat::cmpEqual);
+ // frexp returns a result whose magnitude is in in [.5, 1) so its exponent
+ // should be -1.
+ if (!RoundedFraction.isZero())
+ EXPECT_EQ(ilogb(RoundedFraction), -1)
+ << static_cast<APFloat::roundingMode>(I);
+ // Decomposition preserves sign.
+ EXPECT_EQ(RoundedFraction.isNegative(), Input.isNegative());
+ // A rounding result must be canonical.
+ EXPECT_EQ(APFloat{Params.Rounded[I].Fraction.Hi},
+ APFloat{Params.Rounded[I].Fraction.Hi} +
+ APFloat{Params.Rounded[I].Fraction.Lo})
+ << Params.Rounded[I].Fraction.Hi << " + "
+ << Params.Rounded[I].Fraction.Lo;
+ }
+
+ // The rtz result must be either rup or rdn depending on the sign.
+ if (Input.isNegative()) {
+ const APFloat::cmpResult TzVsUp = compare(Tz, Up);
+ EXPECT_EQ(TzVsUp, APFloat::cmpEqual);
+ } else {
+ const APFloat::cmpResult TzVsDn = compare(Tz, Dn);
+ EXPECT_EQ(TzVsDn, APFloat::cmpEqual);
+ }
+
+ // The recomposed up should be at least as big as the input.
+ const APFloat RecomposedUp =
+ scalbn(makeDoubleAPFloat(Up.Fraction), Up.Exponent,
+ APFloat::rmNearestTiesToEven);
+ EXPECT_TRUE(RecomposedUp >= Input);
+ // The recomposed down can't be larger than the input.
+ const APFloat RecomposedDn =
+ scalbn(makeDoubleAPFloat(Dn.Fraction), Dn.Exponent,
+ APFloat::rmNearestTiesToEven);
+ EXPECT_TRUE(RecomposedDn <= Input);
+ // The recomposed tz must have a smaller magnitude.
+ const APFloat RecomposedTz =
+ scalbn(makeDoubleAPFloat(Tz.Fraction), Tz.Exponent,
+ APFloat::rmNearestTiesToEven);
+ EXPECT_TRUE(abs(RecomposedTz) <= abs(Input));
+ // Either both or neither of the recomposed round-to-nearest results are
+ // equal to the input.
+ const APFloat RecomposedNe =
+ scalbn(makeDoubleAPFloat(Ne.Fraction), Ne.Exponent,
+ APFloat::rmNearestTiesToEven);
+ const APFloat RecomposedNa =
+ scalbn(makeDoubleAPFloat(Na.Fraction), Na.Exponent,
+ APFloat::rmNearestTiesToEven);
+ EXPECT_EQ(RecomposedNe == Input, RecomposedNa == Input);
+ // Either the ne result equals the na result or the na result has a bigger
+ // magnitude.
+ const APFloat::cmpResult NeVsNa =
+ abs(RecomposedNe).compare(abs(RecomposedNa));
+ EXPECT_TRUE(NeVsNa == APFloat::cmpLessThan || NeVsNa == APFloat::cmpEqual);
+ // ne and na may only disagree if they broke a tie differently.
+ if (NeVsNa == APFloat::cmpLessThan) {
+ // ne's magnitude should be lower than input.
+ const APFloat::cmpResult NeVsInput =
+ abs(RecomposedNe).compare(abs(Input));
+ EXPECT_EQ(NeVsInput, APFloat::cmpLessThan);
+ // na's magnitude should be greater than input.
+ const APFloat::cmpResult NaVsInput =
+ abs(RecomposedNa).compare(abs(Input));
+ EXPECT_EQ(NaVsInput, APFloat::cmpGreaterThan);
+ }
+ // If up or down perfectly reconstructs the input, the round-to-nearest
+ // results should too.
+ if (RecomposedUp == Input || RecomposedDn == Input) {
+ EXPECT_EQ(RecomposedNe, Input);
+ EXPECT_EQ(RecomposedNa, Input);
+ }
+ }
+
+ for (size_t I = 0, E = std::size(Params.Rounded); I != E; ++I) {
+ const auto RM = static_cast<APFloat::roundingMode>(I);
+ const auto &Expected = Params.Rounded[I];
+ const APFloat ExpectedFraction = makeDoubleAPFloat(Expected.Fraction);
+
+ int ActualExponent;
+ const APFloat ActualFraction = frexp(Input, ActualExponent, RM);
+ if (ExpectedFraction.isNaN())
+ EXPECT_TRUE(ActualFraction.isNaN());
+ else
+ EXPECT_EQ(ActualFraction.compare(ExpectedFraction), APFloat::cmpEqual)
+ << ActualFraction << " vs " << ExpectedFraction << " for input "
+ << Params.Input.Hi << " + " << Params.Input.Lo << " RM " << RM;
+ EXPECT_EQ(ActualExponent, Expected.Exponent)
+ << "for input " << Params.Input.Hi << " + " << Params.Input.Lo
+ << " RM " << RM;
+ }
}
TEST(APFloatTest, PPCDoubleDoubleNext) {
@@ -6268,6 +7123,249 @@ TEST(APFloatTest, PPCDoubleDoubleNext) {
EXPECT_FALSE(Test.isDenormal());
}
+TEST(APFloatTest, PPCDoubleDoubleConvertFromAPIntInexact) {
+ // Create an integer which would not be exactly representable in
+ // PPCDoubleDoubleLegacy.
+ for (bool IsSigned : {false, true}) {
+ const unsigned BitWidth =
+ APFloat::semanticsPrecision(APFloat::IEEEdouble()) * 3 +
+ (IsSigned ? 1 : 0);
+
+ for (bool Negative :
+ IsSigned ? std::vector{false, true} : std::vector{false}) {
+ APInt Huge = APInt{BitWidth, 0};
+ // Set the highest bit without making Huge negative..
+ Huge.setBit(BitWidth - (IsSigned ? 2 : 1));
+ // Set the low bit.
+ Huge.setBit(0);
+ if (Negative)
+ Huge.negate();
+ for (const APFloat::roundingMode RM :
+ {APFloat::rmNearestTiesToAway, APFloat::rmTowardNegative,
+ APFloat::rmTowardPositive, APFloat::rmTowardZero,
+ APFloat::rmNearestTiesToEven}) {
+ APFloat F{APFloat::PPCDoubleDouble()};
+ const APFloat::opStatus ConvertFromStatus =
+ F.convertFromAPInt(Huge, /*IsSigned=*/IsSigned, RM);
+ EXPECT_EQ(ConvertFromStatus, APFloat::opOK);
+
+ bool IsExact;
+ APSInt ResultInt{Huge.getBitWidth(), /*isUnsigned=*/!IsSigned};
+ const APFloat::opStatus ConvertToStatus =
+ F.convertToInteger(ResultInt, APFloat::rmTowardZero, &IsExact);
+
+ EXPECT_TRUE(IsExact) << "RM: " << RM;
+ EXPECT_TRUE(ResultInt.eq(Huge)) << ResultInt << " vs " << Huge << "\n";
+ EXPECT_EQ(ConvertToStatus, APFloat::opOK);
+ }
+ }
+ }
+}
+
+TEST(APFloatTest, PPCDoubleDoubleConvertFromAPIntBoundary) {
+ const unsigned Binary64Precision =
+ APFloat::semanticsPrecision(APFloat::IEEEdouble());
+ APSInt Boundary =
+ APSInt::getMaxValue(Binary64Precision + 1, /*Unsigned=*/true);
+ for (const APFloat::roundingMode RM :
+ {APFloat::rmNearestTiesToAway, APFloat::rmTowardNegative,
+ APFloat::rmTowardPositive, APFloat::rmTowardZero,
+ APFloat::rmNearestTiesToEven}) {
+ const APFloat Exact = makeDoubleAPFloat(0x1p54, -0x1p0);
+ APFloat F{APFloat::PPCDoubleDouble()};
+ const APFloat::opStatus ConvertFromStatus =
+ F.convertFromAPInt(Boundary, /*IsSigned=*/false, RM);
+ EXPECT_EQ(ConvertFromStatus, APFloat::opOK);
+ EXPECT_EQ(F, Exact);
+ }
+
+ Boundary = APSInt{APInt::getHighBitsSet(/*numBits=*/128,
+ /*hiBitsSet=*/Binary64Precision + 1),
+ /*isUnsigned=*/true};
+ for (const APFloat::roundingMode RM :
+ {APFloat::rmNearestTiesToAway, APFloat::rmTowardNegative,
+ APFloat::rmTowardPositive, APFloat::rmTowardZero,
+ APFloat::rmNearestTiesToEven}) {
+ const APFloat Exact = makeDoubleAPFloat(0x1p128, -0x1p74);
+ APFloat F{APFloat::PPCDoubleDouble()};
+ const APFloat::opStatus ConvertFromStatus =
+ F.convertFromAPInt(Boundary, /*IsSigned=*/false, RM);
+ EXPECT_EQ(ConvertFromStatus, APFloat::opOK);
+ EXPECT_EQ(F, Exact);
+ }
+}
+
+TEST(APFloatTest, PPCDoubleDoubleConvertFromAPIntEnormous) {
+ APFloat Largest = APFloat::getLargest(APFloat::PPCDoubleDouble());
+ int Exponent = ilogb(Largest);
+ unsigned BitWidth = Exponent + 1;
+ APSInt HugeInt{BitWidth, /*isUnsigned=*/true};
+ bool IsExact;
+ APFloat::opStatus Status =
+ Largest.convertToInteger(HugeInt, APFloat::rmTowardPositive, &IsExact);
+ ASSERT_EQ(Status, APFloat::opOK);
+ ASSERT_TRUE(IsExact);
+
+ for (const APFloat::roundingMode RM :
+ {APFloat::rmNearestTiesToAway, APFloat::rmTowardNegative,
+ APFloat::rmTowardPositive, APFloat::rmTowardZero,
+ APFloat::rmNearestTiesToEven}) {
+ APFloat F{APFloat::PPCDoubleDouble()};
+ const APFloat::opStatus ConvertFromStatus =
+ F.convertFromAPInt(HugeInt, /*IsSigned=*/false, RM);
+ EXPECT_EQ(ConvertFromStatus, APFloat::opOK);
+ EXPECT_EQ(F, Largest);
+ }
+
+ const unsigned MaxExponent =
+ APFloat::semanticsMaxExponent(APFloat::IEEEdouble());
+ const unsigned Binary64Precision =
+ APFloat::semanticsPrecision(APFloat::IEEEdouble());
+ const unsigned UlpOfLargest = MaxExponent - (2 * Binary64Precision);
+ const unsigned HalfUlpOfLargest = UlpOfLargest - 1;
+
+ // Add just under a half-ulp. This should never overflow for
+ // round-ties-to-nearest modes.
+ HugeInt.setLowBits(HalfUlpOfLargest);
+ for (const APFloat::roundingMode RM :
+ {APFloat::rmNearestTiesToAway, APFloat::rmTowardNegative,
+ APFloat::rmTowardPositive, APFloat::rmTowardZero,
+ APFloat::rmNearestTiesToEven}) {
+ APFloat F{APFloat::PPCDoubleDouble()};
+ const APFloat::opStatus ConvertFromStatus =
+ F.convertFromAPInt(HugeInt, /*IsSigned=*/false, RM);
+ if (RM == APFloat::rmTowardPositive) {
+ EXPECT_TRUE(F.isPosInfinity()) << F;
+ EXPECT_EQ(ConvertFromStatus, APFloat::opInexact | APFloat::opOverflow);
+ } else {
+ EXPECT_EQ(F, Largest);
+ EXPECT_EQ(ConvertFromStatus, APFloat::opInexact);
+ }
+ }
+
+ // Now test adding a half-ulp. This should cause overflow for ties-to-away.
+ // ties-to-even will not overflow if the max finite value has a clear low bit.
+ ++HugeInt;
+ for (const APFloat::roundingMode RM :
+ {APFloat::rmNearestTiesToAway, APFloat::rmTowardNegative,
+ APFloat::rmTowardPositive, APFloat::rmTowardZero,
+ APFloat::rmNearestTiesToEven}) {
+ APFloat F{APFloat::PPCDoubleDouble()};
+ const APFloat::opStatus ConvertFromStatus =
+ F.convertFromAPInt(HugeInt, /*IsSigned=*/false, RM);
+ const bool Overflow =
+ RM == APFloat::rmTowardPositive || RM == APFloat::rmNearestTiesToAway ||
+ (RM == APFloat::rmNearestTiesToEven && HugeInt[UlpOfLargest]);
+ if (Overflow) {
+ EXPECT_TRUE(F.isPosInfinity()) << F;
+ EXPECT_EQ(ConvertFromStatus, APFloat::opInexact | APFloat::opOverflow);
+ } else {
+ EXPECT_EQ(F, Largest);
+ EXPECT_EQ(ConvertFromStatus, APFloat::opInexact);
+ }
+ }
+
+ // Now test adding just over a half-ulp. This should break all ties.
+ ++HugeInt;
+ for (const APFloat::roundingMode RM :
+ {APFloat::rmNearestTiesToAway, APFloat::rmTowardNegative,
+ APFloat::rmTowardPositive, APFloat::rmTowardZero,
+ APFloat::rmNearestTiesToEven}) {
+ APFloat F{APFloat::PPCDoubleDouble()};
+ const APFloat::opStatus ConvertFromStatus =
+ F.convertFromAPInt(HugeInt, /*IsSigned=*/false, RM);
+ const bool Overflow = RM == APFloat::rmTowardPositive ||
+ RM == APFloat::rmNearestTiesToAway ||
+ RM == APFloat::rmNearestTiesToEven;
+ if (Overflow) {
+ EXPECT_TRUE(F.isPosInfinity()) << F;
+ EXPECT_EQ(ConvertFromStatus, APFloat::opInexact | APFloat::opOverflow);
+ } else {
+ EXPECT_EQ(F, Largest);
+ EXPECT_EQ(ConvertFromStatus, APFloat::opInexact);
+ }
+ }
+
+ HugeInt.setAllBits();
+ for (const APFloat::roundingMode RM :
+ {APFloat::rmNearestTiesToAway, APFloat::rmTowardNegative,
+ APFloat::rmTowardPositive, APFloat::rmTowardZero,
+ APFloat::rmNearestTiesToEven}) {
+ APFloat F{APFloat::PPCDoubleDouble()};
+ const APFloat::opStatus ConvertFromStatus =
+ F.convertFromAPInt(HugeInt, /*IsSigned=*/false, RM);
+ const bool Overflow = RM == APFloat::rmTowardPositive ||
+ RM == APFloat::rmNearestTiesToAway ||
+ RM == APFloat::rmNearestTiesToEven;
+ if (Overflow) {
+ EXPECT_TRUE(F.isPosInfinity()) << F;
+ EXPECT_EQ(ConvertFromStatus, APFloat::opInexact | APFloat::opOverflow);
+ } else {
+ EXPECT_EQ(F, Largest);
+ EXPECT_EQ(ConvertFromStatus, APFloat::opInexact);
+ }
+ }
+
+ HugeInt.clearAllBits();
+ HugeInt.setBit(2 * Binary64Precision + 1);
+ HugeInt.setLowBits(Binary64Precision + 1);
+ for (const APFloat::roundingMode RM :
+ {APFloat::rmNearestTiesToAway, APFloat::rmTowardNegative,
+ APFloat::rmTowardPositive, APFloat::rmTowardZero,
+ APFloat::rmNearestTiesToEven}) {
+ const APFloat RoundUp = makeDoubleAPFloat(0x1p107, 0x1p54);
+ const APFloat RoundDown = makeDoubleAPFloat(0x1p107, 0x1.fffffffffffffp53);
+ APFloat F{APFloat::PPCDoubleDouble()};
+ const APFloat::opStatus ConvertFromStatus =
+ F.convertFromAPInt(HugeInt, /*IsSigned=*/false, RM);
+ EXPECT_EQ(ConvertFromStatus, APFloat::opInexact);
+
+ if (RM == APFloat::rmNearestTiesToEven ||
+ RM == APFloat::rmNearestTiesToAway || RM == APFloat::rmTowardPositive)
+ EXPECT_EQ(F, RoundUp);
+ else
+ EXPECT_EQ(F, RoundDown);
+ }
+
+ ++HugeInt;
+ // 162259276829213381405976519770112 can be represented exactly.
+ for (const APFloat::roundingMode RM :
+ {APFloat::rmNearestTiesToAway, APFloat::rmTowardNegative,
+ APFloat::rmTowardPositive, APFloat::rmTowardZero,
+ APFloat::rmNearestTiesToEven}) {
+ const APFloat Exact = makeDoubleAPFloat(0x1p107, 0x1p54);
+ APFloat F{APFloat::PPCDoubleDouble()};
+ const APFloat::opStatus ConvertFromStatus =
+ F.convertFromAPInt(HugeInt, /*IsSigned=*/false, RM);
+ EXPECT_EQ(ConvertFromStatus, APFloat::opOK);
+ EXPECT_EQ(F, Exact);
+ }
+
+ ++HugeInt;
+ // 162259276829213381405976519770113 rounds to either:
+ // 162259276829213381405976519770112
+ // 162259276829213381405976519770114
+ for (const APFloat::roundingMode RM :
+ {APFloat::rmNearestTiesToAway, APFloat::rmTowardNegative,
+ APFloat::rmTowardPositive, APFloat::rmTowardZero,
+ APFloat::rmNearestTiesToEven}) {
+ const APFloat RoundUp =
+ makeDoubleAPFloat(0x1.0000000000001p107, -0x1.fffffffffffffp53);
+ const APFloat RoundDown = makeDoubleAPFloat(0x1p107, 0x1p54);
+ EXPECT_LT(RoundDown, RoundUp);
+
+ APFloat F{APFloat::PPCDoubleDouble()};
+ const APFloat::opStatus ConvertFromStatus =
+ F.convertFromAPInt(HugeInt, /*IsSigned=*/false, RM);
+ EXPECT_EQ(ConvertFromStatus, APFloat::opInexact);
+
+ if (RM == APFloat::rmNearestTiesToAway || RM == APFloat::rmTowardPositive)
+ EXPECT_EQ(F, RoundUp);
+ else
+ EXPECT_EQ(F, RoundDown);
+ }
+}
+
TEST(APFloatTest, x87Largest) {
APFloat MaxX87Val = APFloat::getLargest(APFloat::x87DoubleExtended());
EXPECT_TRUE(MaxX87Val.isLargest());
@@ -8259,13 +9357,8 @@ TEST(APFloatTest, getExactLog2) {
continue;
APFloat One(Semantics, "1.0");
-
- if (I == APFloat::S_PPCDoubleDouble) {
- // Not implemented
- EXPECT_EQ(INT_MIN, One.getExactLog2());
- EXPECT_EQ(INT_MIN, One.getExactLog2Abs());
- continue;
- }
+ APFloat Smallest = APFloat::getSmallest(Semantics);
+ APFloat Largest = APFloat::getLargest(Semantics);
int MinExp = APFloat::semanticsMinExponent(Semantics);
int MaxExp = APFloat::semanticsMaxExponent(Semantics);
@@ -8312,16 +9405,15 @@ TEST(APFloatTest, getExactLog2) {
EXPECT_EQ(INT_MIN, APFloat::getNaN(Semantics, true).getExactLog2Abs());
}
- EXPECT_EQ(INT_MIN,
- scalbn(One, MinExp - Precision - 1, APFloat::rmNearestTiesToEven)
- .getExactLog2());
- EXPECT_EQ(INT_MIN,
- scalbn(One, MinExp - Precision, APFloat::rmNearestTiesToEven)
- .getExactLog2());
-
EXPECT_EQ(
INT_MIN,
- scalbn(One, MaxExp + 1, APFloat::rmNearestTiesToEven).getExactLog2());
+ scalbn(Smallest, -2, APFloat::rmNearestTiesToEven).getExactLog2());
+ EXPECT_EQ(
+ INT_MIN,
+ scalbn(Smallest, -1, APFloat::rmNearestTiesToEven).getExactLog2());
+
+ EXPECT_EQ(INT_MIN,
+ scalbn(Largest, 1, APFloat::rmNearestTiesToEven).getExactLog2());
for (int i = MinExp - Precision + 1; i <= MaxExp; ++i) {
EXPECT_EQ(i, scalbn(One, i, APFloat::rmNearestTiesToEven).getExactLog2());
diff --git a/llvm/unittests/ADT/APIntTest.cpp b/llvm/unittests/ADT/APIntTest.cpp
index 4741c7b..116693c 100644
--- a/llvm/unittests/ADT/APIntTest.cpp
+++ b/llvm/unittests/ADT/APIntTest.cpp
@@ -3103,6 +3103,53 @@ TEST(APIntOpsTest, Mulh) {
EXPECT_EQ(APInt(128, "FFEB498812C66C68D4552DB89B8EBF8F", 16), i128Res);
}
+TEST(APIntOpsTest, muli) {
+ APInt u32a(32, 0x0001'E235);
+ APInt u32b(32, 0xF623'55AD);
+ EXPECT_EQ(0x0001'CFA1'7CA0'76D1, APIntOps::muluExtended(u32a, u32b));
+
+ APInt u64a(64, 0x1234'5678'90AB'CDEF);
+ APInt u64b(64, 0xFEDC'BA09'8765'4321);
+ EXPECT_EQ(APInt(128, "121FA000A3723A57C24A442FE55618CF", 16),
+ APIntOps::muluExtended(u64a, u64b));
+
+ APInt u128a(128, "1234567890ABCDEF1234567890ABCDEF", 16);
+ APInt u128b(128, "FEDCBA0987654321FEDCBA0987654321", 16);
+ EXPECT_EQ(
+ APInt(256,
+ "121FA000A3723A57E68984312C3A8D7E96B428606E1E6BF5C24A442FE55618CF",
+ 16),
+ APIntOps::muluExtended(u128a, u128b));
+
+ APInt s32a(32, 0x1234'5678);
+ APInt s32b(32, 0x10AB'CDEF);
+ APInt s32c(32, 0xFEDC'BA09);
+ EXPECT_EQ(0x012F'7D02'2A42'D208, APIntOps::mulsExtended(s32a, s32b));
+ EXPECT_EQ(0xFFEB'4988'09CA'3A38, APIntOps::mulsExtended(s32a, s32c));
+
+ APInt s64a(64, 0x1234'5678'90AB'CDEF);
+ APInt s64b(64, 0x1234'5678'90FE'DCBA);
+ APInt s64c(64, 0xFEDC'BA09'8765'4321);
+ EXPECT_EQ(APInt(128, "014B66DC328E10C1FB99704184EF03A6", 16),
+ APIntOps::mulsExtended(s64a, s64b));
+ EXPECT_EQ(APInt(128, "FFEB498812C66C68C24A442FE55618CF", 16),
+ APIntOps::mulsExtended(s64a, s64c));
+
+ APInt s128a(128, "1234567890ABCDEF1234567890ABCDEF", 16);
+ APInt s128b(128, "1234567890FEDCBA1234567890FEDCBA", 16);
+ APInt s128c(128, "FEDCBA0987654321FEDCBA0987654321", 16);
+ EXPECT_EQ(
+ APInt(256,
+ "014B66DC328E10C1FE303DF9EA0B2529F87E475F3C6C180DFB99704184EF03A6",
+ 16),
+ APIntOps::mulsExtended(s128a, s128b));
+ EXPECT_EQ(
+ APInt(256,
+ "FFEB498812C66C68D4552DB89B8EBF8F96B428606E1E6BF5C24A442FE55618CF",
+ 16),
+ APIntOps::mulsExtended(s128a, s128c));
+}
+
TEST(APIntTest, RoundingUDiv) {
for (uint64_t Ai = 1; Ai <= 255; Ai++) {
APInt A(8, Ai);
@@ -3697,4 +3744,82 @@ TEST(APIntTest, TryExt) {
ASSERT_EQ(42, APInt(128, -1).trySExtValue().value_or(42));
}
+TEST(APIntTest, Fshl) {
+ EXPECT_EQ(
+ APIntOps::fshl(APInt(8, 0), APInt(8, 255), APInt(8, 8)).getZExtValue(),
+ 0U);
+ EXPECT_EQ(
+ APIntOps::fshl(APInt(8, 255), APInt(8, 0), APInt(8, 8)).getZExtValue(),
+ 255U);
+ EXPECT_EQ(
+ APIntOps::fshl(APInt(8, 255), APInt(8, 0), APInt(8, 15)).getZExtValue(),
+ 128U);
+ EXPECT_EQ(
+ APIntOps::fshl(APInt(8, 15), APInt(8, 15), APInt(8, 11)).getZExtValue(),
+ 120U);
+ EXPECT_EQ(
+ APIntOps::fshl(APInt(8, 2), APInt(8, 1), APInt(8, 3)).getZExtValue(),
+ 16U);
+ EXPECT_EQ(
+ APIntOps::fshl(APInt(8, 2), APInt(8, 1), APInt(8, 1)).getZExtValue(),
+ APIntOps::fshl(APInt(8, 2), APInt(8, 1), APInt(8, 9)).getZExtValue());
+ EXPECT_EQ(
+ APIntOps::fshl(APInt(8, 2), APInt(8, 1), APInt(8, 7)).getZExtValue(),
+ APIntOps::fshl(APInt(8, 2), APInt(8, 1), APInt(8, 15)).getZExtValue());
+ EXPECT_EQ(APIntOps::fshl(APInt(32, 0, /*isSigned*/ true),
+ APInt(32, 2147483647, /*isSigned*/ true),
+ APInt(32, 32, /*isSigned*/ true))
+ .getSExtValue(),
+ 0);
+ EXPECT_EQ(APIntOps::fshl(APInt(64, 1, /*isSigned*/ true),
+ APInt(64, 2, /*isSigned*/ true),
+ APInt(64, 3, /*isSigned*/ true))
+ .getSExtValue(),
+ 8);
+ EXPECT_EQ(APIntOps::fshl(APInt(16, -2, /*isSigned*/ true),
+ APInt(16, -1, /*isSigned*/ true),
+ APInt(16, 3, /*isSigned*/ true))
+ .getSExtValue(),
+ -9);
+}
+
+TEST(APIntTest, Fshr) {
+ EXPECT_EQ(
+ APIntOps::fshr(APInt(8, 0), APInt(8, 255), APInt(8, 8)).getZExtValue(),
+ 255U);
+ EXPECT_EQ(
+ APIntOps::fshr(APInt(8, 255), APInt(8, 0), APInt(8, 8)).getZExtValue(),
+ 0U);
+ EXPECT_EQ(
+ APIntOps::fshr(APInt(8, 255), APInt(8, 0), APInt(8, 15)).getZExtValue(),
+ 254U);
+ EXPECT_EQ(
+ APIntOps::fshr(APInt(8, 15), APInt(8, 15), APInt(8, 11)).getZExtValue(),
+ 225U);
+ EXPECT_EQ(
+ APIntOps::fshr(APInt(8, 1), APInt(8, 2), APInt(8, 3)).getZExtValue(),
+ 32U);
+ EXPECT_EQ(
+ APIntOps::fshr(APInt(8, 1), APInt(8, 2), APInt(8, 1)).getZExtValue(),
+ APIntOps::fshr(APInt(8, 1), APInt(8, 2), APInt(8, 9)).getZExtValue());
+ EXPECT_EQ(
+ APIntOps::fshr(APInt(8, 1), APInt(8, 2), APInt(8, 7)).getZExtValue(),
+ APIntOps::fshr(APInt(8, 1), APInt(8, 2), APInt(8, 15)).getZExtValue());
+ EXPECT_EQ(APIntOps::fshr(APInt(64, 0, /*isSigned*/ true),
+ APInt(64, 9223372036854775807, /*isSigned*/ true),
+ APInt(64, 64, /*isSigned*/ true))
+ .getSExtValue(),
+ 9223372036854775807);
+ EXPECT_EQ(APIntOps::fshr(APInt(64, 1, /*isSigned*/ true),
+ APInt(64, 2, /*isSigned*/ true),
+ APInt(64, 3, /*isSigned*/ true))
+ .getSExtValue(),
+ 2305843009213693952);
+ EXPECT_EQ(APIntOps::fshr(APInt(16, -2, /*isSigned*/ true),
+ APInt(16, -1, /*isSigned*/ true),
+ APInt(16, 3, /*isSigned*/ true))
+ .getSExtValue(),
+ -8193);
+}
+
} // end anonymous namespace
diff --git a/llvm/unittests/ADT/DenseMapTest.cpp b/llvm/unittests/ADT/DenseMapTest.cpp
index bdfbc85..785ab16 100644
--- a/llvm/unittests/ADT/DenseMapTest.cpp
+++ b/llvm/unittests/ADT/DenseMapTest.cpp
@@ -10,6 +10,7 @@
#include "CountCopyAndMove.h"
#include "llvm/ADT/DenseMapInfo.h"
#include "llvm/ADT/DenseMapInfoVariant.h"
+#include "llvm/ADT/STLForwardCompat.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/StringRef.h"
#include "gmock/gmock.h"
@@ -249,6 +250,25 @@ TYPED_TEST(DenseMapTest, CopyConstructorNotSmallTest) {
EXPECT_EQ(this->getValue(Key), copyMap[this->getKey(Key)]);
}
+// Test range constructors.
+TYPED_TEST(DenseMapTest, RangeConstructorTest) {
+ using KeyAndValue =
+ std::pair<typename TypeParam::key_type, typename TypeParam::mapped_type>;
+ KeyAndValue PlainArray[] = {{this->getKey(0), this->getValue(0)},
+ {this->getKey(1), this->getValue(1)}};
+
+ TypeParam MapFromRange(llvm::from_range, PlainArray);
+ EXPECT_EQ(2u, MapFromRange.size());
+ EXPECT_EQ(this->getValue(0), MapFromRange[this->getKey(0)]);
+ EXPECT_EQ(this->getValue(1), MapFromRange[this->getKey(1)]);
+
+ TypeParam MapFromInitList({{this->getKey(0), this->getValue(1)},
+ {this->getKey(1), this->getValue(2)}});
+ EXPECT_EQ(2u, MapFromInitList.size());
+ EXPECT_EQ(this->getValue(1), MapFromInitList[this->getKey(0)]);
+ EXPECT_EQ(this->getValue(2), MapFromInitList[this->getKey(1)]);
+}
+
// Test copying from a default-constructed map.
TYPED_TEST(DenseMapTest, CopyConstructorFromDefaultTest) {
TypeParam copyMap(this->Map);
@@ -367,9 +387,16 @@ TYPED_TEST(DenseMapTest, ConstIteratorTest) {
EXPECT_TRUE(cit == cit2);
}
+// TYPED_TEST below cycles through different types. We define UniversalSmallSet
+// here so that we'll use SmallSet or SmallPtrSet depending on whether the
+// element type is a pointer.
+template <typename T, unsigned N>
+using UniversalSmallSet =
+ std::conditional_t<std::is_pointer_v<T>, SmallPtrSet<T, N>, SmallSet<T, N>>;
+
TYPED_TEST(DenseMapTest, KeysValuesIterator) {
- SmallSet<typename TypeParam::key_type, 10> Keys;
- SmallSet<typename TypeParam::mapped_type, 10> Values;
+ UniversalSmallSet<typename TypeParam::key_type, 10> Keys;
+ UniversalSmallSet<typename TypeParam::mapped_type, 10> Values;
for (int I = 0; I < 10; ++I) {
auto K = this->getKey(I);
auto V = this->getValue(I);
@@ -378,8 +405,8 @@ TYPED_TEST(DenseMapTest, KeysValuesIterator) {
this->Map[K] = V;
}
- SmallSet<typename TypeParam::key_type, 10> ActualKeys;
- SmallSet<typename TypeParam::mapped_type, 10> ActualValues;
+ UniversalSmallSet<typename TypeParam::key_type, 10> ActualKeys;
+ UniversalSmallSet<typename TypeParam::mapped_type, 10> ActualValues;
for (auto K : this->Map.keys())
ActualKeys.insert(K);
for (auto V : this->Map.values())
@@ -390,8 +417,8 @@ TYPED_TEST(DenseMapTest, KeysValuesIterator) {
}
TYPED_TEST(DenseMapTest, ConstKeysValuesIterator) {
- SmallSet<typename TypeParam::key_type, 10> Keys;
- SmallSet<typename TypeParam::mapped_type, 10> Values;
+ UniversalSmallSet<typename TypeParam::key_type, 10> Keys;
+ UniversalSmallSet<typename TypeParam::mapped_type, 10> Values;
for (int I = 0; I < 10; ++I) {
auto K = this->getKey(I);
auto V = this->getValue(I);
@@ -401,8 +428,8 @@ TYPED_TEST(DenseMapTest, ConstKeysValuesIterator) {
}
const TypeParam &ConstMap = this->Map;
- SmallSet<typename TypeParam::key_type, 10> ActualKeys;
- SmallSet<typename TypeParam::mapped_type, 10> ActualValues;
+ UniversalSmallSet<typename TypeParam::key_type, 10> ActualKeys;
+ UniversalSmallSet<typename TypeParam::mapped_type, 10> ActualValues;
for (auto K : ConstMap.keys())
ActualKeys.insert(K);
for (auto V : ConstMap.values())
@@ -726,6 +753,15 @@ TEST(DenseMapCustomTest, FindAsTest) {
EXPECT_TRUE(map.find_as("d") == map.end());
}
+TEST(DenseMapCustomTest, SmallDenseMapFromRange) {
+ std::pair<int, StringRef> PlainArray[] = {{0, "0"}, {1, "1"}, {2, "2"}};
+ SmallDenseMap<int, StringRef> M(llvm::from_range, PlainArray);
+ EXPECT_EQ(3u, M.size());
+ using testing::Pair;
+ EXPECT_THAT(M, testing::UnorderedElementsAre(Pair(0, "0"), Pair(1, "1"),
+ Pair(2, "2")));
+}
+
TEST(DenseMapCustomTest, SmallDenseMapInitializerList) {
SmallDenseMap<int, int> M = {{0, 0}, {0, 1}, {1, 2}};
EXPECT_EQ(2u, M.size());
diff --git a/llvm/unittests/ADT/SmallPtrSetTest.cpp b/llvm/unittests/ADT/SmallPtrSetTest.cpp
index 4ea7403..a627091 100644
--- a/llvm/unittests/ADT/SmallPtrSetTest.cpp
+++ b/llvm/unittests/ADT/SmallPtrSetTest.cpp
@@ -475,4 +475,8 @@ TEST(SmallPtrSetTest, Reserve) {
EXPECT_EQ(Set.capacity(), 128u);
EXPECT_EQ(Set.size(), 6u);
EXPECT_THAT(Set, UnorderedElementsAre(&Vals[0], &Vals[1], &Vals[2], &Vals[3], &Vals[4], &Vals[5]));
+
+ // Reserving 192 should result in 256 buckets.
+ Set.reserve(192);
+ EXPECT_EQ(Set.capacity(), 256u);
}
diff --git a/llvm/unittests/ADT/StringMapTest.cpp b/llvm/unittests/ADT/StringMapTest.cpp
index 35135cd..92ae364 100644
--- a/llvm/unittests/ADT/StringMapTest.cpp
+++ b/llvm/unittests/ADT/StringMapTest.cpp
@@ -693,4 +693,58 @@ TEST(StringMapCustomTest, StringMapEntrySize) {
EXPECT_EQ(LargeValue, Key.size());
}
+TEST(StringMapCustomTest, NonConstIterator) {
+ StringMap<int> Map;
+ Map["key"] = 1;
+
+ // Check that Map.begin() returns a non-const iterator.
+ static_assert(
+ std::is_same_v<decltype(Map.begin()), StringMap<int>::iterator>);
+
+ // Check that the value_type of a non-const iterator is not a const type.
+ static_assert(
+ !std::is_const_v<StringMap<int>::iterator::value_type>,
+ "The value_type of a non-const iterator should not be a const type.");
+
+ // Check that pointer and reference types are not const.
+ static_assert(std::is_same_v<StringMap<int>::iterator::pointer,
+ StringMap<int>::iterator::value_type *>);
+ static_assert(std::is_same_v<StringMap<int>::iterator::reference,
+ StringMap<int>::iterator::value_type &>);
+
+ // Check that we can construct a const_iterator from an iterator.
+ static_assert(std::is_constructible_v<StringMap<int>::const_iterator,
+ StringMap<int>::iterator>);
+
+ // Double check that we can actually construct a const_iterator.
+ StringMap<int>::const_iterator const_it = Map.begin();
+ (void)const_it;
+}
+
+TEST(StringMapCustomTest, ConstIterator) {
+ StringMap<int> Map;
+ const StringMap<int> &ConstMap = Map;
+
+ // Check that ConstMap.begin() returns a const_iterator.
+ static_assert(std::is_same_v<decltype(ConstMap.begin()),
+ StringMap<int>::const_iterator>);
+
+ // Check that the value_type of a const iterator is not a const type.
+ static_assert(
+ !std::is_const_v<StringMap<int>::const_iterator::value_type>,
+ "The value_type of a const iterator should not be a const type.");
+
+ // Check that pointer and reference types are const.
+ static_assert(
+ std::is_same_v<StringMap<int>::const_iterator::pointer,
+ const StringMap<int>::const_iterator::value_type *>);
+ static_assert(
+ std::is_same_v<StringMap<int>::const_iterator::reference,
+ const StringMap<int>::const_iterator::value_type &>);
+
+ // Check that we cannot construct an iterator from a const_iterator.
+ static_assert(!std::is_constructible_v<StringMap<int>::iterator,
+ StringMap<int>::const_iterator>);
+}
+
} // end anonymous namespace
diff --git a/llvm/unittests/Analysis/IR2VecTest.cpp b/llvm/unittests/Analysis/IR2VecTest.cpp
index f7838cc4..9c10632 100644
--- a/llvm/unittests/Analysis/IR2VecTest.cpp
+++ b/llvm/unittests/Analysis/IR2VecTest.cpp
@@ -30,7 +30,6 @@ namespace {
class TestableEmbedder : public Embedder {
public:
TestableEmbedder(const Function &F, const Vocabulary &V) : Embedder(F, V) {}
- void computeEmbeddings() const override {}
void computeEmbeddings(const BasicBlock &BB) const override {}
};
@@ -258,6 +257,18 @@ TEST(IR2VecTest, CreateSymbolicEmbedder) {
EXPECT_NE(Emb, nullptr);
}
+TEST(IR2VecTest, CreateFlowAwareEmbedder) {
+ Vocabulary V = Vocabulary(Vocabulary::createDummyVocabForTest());
+
+ LLVMContext Ctx;
+ Module M("M", Ctx);
+ FunctionType *FTy = FunctionType::get(Type::getVoidTy(Ctx), false);
+ Function *F = Function::Create(FTy, Function::ExternalLinkage, "f", M);
+
+ auto Emb = Embedder::create(IR2VecKind::FlowAware, *F, V);
+ EXPECT_NE(Emb, nullptr);
+}
+
TEST(IR2VecTest, CreateInvalidMode) {
Vocabulary V = Vocabulary(Vocabulary::createDummyVocabForTest());
@@ -310,7 +321,7 @@ protected:
}
};
-TEST_F(IR2VecTestFixture, GetInstVecMap) {
+TEST_F(IR2VecTestFixture, GetInstVecMap_Symbolic) {
auto Emb = Embedder::create(IR2VecKind::Symbolic, *F, V);
ASSERT_TRUE(static_cast<bool>(Emb));
@@ -325,11 +336,28 @@ TEST_F(IR2VecTestFixture, GetInstVecMap) {
EXPECT_EQ(AddEmb.size(), 2u);
EXPECT_EQ(RetEmb.size(), 2u);
- EXPECT_TRUE(AddEmb.approximatelyEquals(Embedding(2, 27.9)));
- EXPECT_TRUE(RetEmb.approximatelyEquals(Embedding(2, 17.0)));
+ EXPECT_TRUE(AddEmb.approximatelyEquals(Embedding(2, 25.5)));
+ EXPECT_TRUE(RetEmb.approximatelyEquals(Embedding(2, 15.5)));
+}
+
+TEST_F(IR2VecTestFixture, GetInstVecMap_FlowAware) {
+ auto Emb = Embedder::create(IR2VecKind::FlowAware, *F, V);
+ ASSERT_TRUE(static_cast<bool>(Emb));
+
+ const auto &InstMap = Emb->getInstVecMap();
+
+ EXPECT_EQ(InstMap.size(), 2u);
+ EXPECT_TRUE(InstMap.count(AddInst));
+ EXPECT_TRUE(InstMap.count(RetInst));
+
+ EXPECT_EQ(InstMap.at(AddInst).size(), 2u);
+ EXPECT_EQ(InstMap.at(RetInst).size(), 2u);
+
+ EXPECT_TRUE(InstMap.at(AddInst).approximatelyEquals(Embedding(2, 25.5)));
+ EXPECT_TRUE(InstMap.at(RetInst).approximatelyEquals(Embedding(2, 32.6)));
}
-TEST_F(IR2VecTestFixture, GetBBVecMap) {
+TEST_F(IR2VecTestFixture, GetBBVecMap_Symbolic) {
auto Emb = Embedder::create(IR2VecKind::Symbolic, *F, V);
ASSERT_TRUE(static_cast<bool>(Emb));
@@ -339,22 +367,47 @@ TEST_F(IR2VecTestFixture, GetBBVecMap) {
EXPECT_TRUE(BBMap.count(BB));
EXPECT_EQ(BBMap.at(BB).size(), 2u);
- // BB vector should be sum of add and ret: {27.9, 27.9} + {17.0, 17.0} =
- // {44.9, 44.9}
- EXPECT_TRUE(BBMap.at(BB).approximatelyEquals(Embedding(2, 44.9)));
+ // BB vector should be sum of add and ret: {25.5, 25.5} + {15.5, 15.5} =
+ // {41.0, 41.0}
+ EXPECT_TRUE(BBMap.at(BB).approximatelyEquals(Embedding(2, 41.0)));
}
-TEST_F(IR2VecTestFixture, GetBBVector) {
+TEST_F(IR2VecTestFixture, GetBBVecMap_FlowAware) {
+ auto Emb = Embedder::create(IR2VecKind::FlowAware, *F, V);
+ ASSERT_TRUE(static_cast<bool>(Emb));
+
+ const auto &BBMap = Emb->getBBVecMap();
+
+ EXPECT_EQ(BBMap.size(), 1u);
+ EXPECT_TRUE(BBMap.count(BB));
+ EXPECT_EQ(BBMap.at(BB).size(), 2u);
+
+ // BB vector should be sum of add and ret: {25.5, 25.5} + {32.6, 32.6} =
+ // {58.1, 58.1}
+ EXPECT_TRUE(BBMap.at(BB).approximatelyEquals(Embedding(2, 58.1)));
+}
+
+TEST_F(IR2VecTestFixture, GetBBVector_Symbolic) {
auto Emb = Embedder::create(IR2VecKind::Symbolic, *F, V);
ASSERT_TRUE(static_cast<bool>(Emb));
const auto &BBVec = Emb->getBBVector(*BB);
EXPECT_EQ(BBVec.size(), 2u);
- EXPECT_TRUE(BBVec.approximatelyEquals(Embedding(2, 44.9)));
+ EXPECT_TRUE(BBVec.approximatelyEquals(Embedding(2, 41.0)));
+}
+
+TEST_F(IR2VecTestFixture, GetBBVector_FlowAware) {
+ auto Emb = Embedder::create(IR2VecKind::FlowAware, *F, V);
+ ASSERT_TRUE(static_cast<bool>(Emb));
+
+ const auto &BBVec = Emb->getBBVector(*BB);
+
+ EXPECT_EQ(BBVec.size(), 2u);
+ EXPECT_TRUE(BBVec.approximatelyEquals(Embedding(2, 58.1)));
}
-TEST_F(IR2VecTestFixture, GetFunctionVector) {
+TEST_F(IR2VecTestFixture, GetFunctionVector_Symbolic) {
auto Emb = Embedder::create(IR2VecKind::Symbolic, *F, V);
ASSERT_TRUE(static_cast<bool>(Emb));
@@ -362,24 +415,51 @@ TEST_F(IR2VecTestFixture, GetFunctionVector) {
EXPECT_EQ(FuncVec.size(), 2u);
- // Function vector should match BB vector (only one BB): {44.9, 44.9}
- EXPECT_TRUE(FuncVec.approximatelyEquals(Embedding(2, 44.9)));
+ // Function vector should match BB vector (only one BB): {41.0, 41.0}
+ EXPECT_TRUE(FuncVec.approximatelyEquals(Embedding(2, 41.0)));
+}
+
+TEST_F(IR2VecTestFixture, GetFunctionVector_FlowAware) {
+ auto Emb = Embedder::create(IR2VecKind::FlowAware, *F, V);
+ ASSERT_TRUE(static_cast<bool>(Emb));
+
+ const auto &FuncVec = Emb->getFunctionVector();
+
+ EXPECT_EQ(FuncVec.size(), 2u);
+ // Function vector should match BB vector (only one BB): {58.1, 58.1}
+ EXPECT_TRUE(FuncVec.approximatelyEquals(Embedding(2, 58.1)));
}
static constexpr unsigned MaxOpcodes = Vocabulary::MaxOpcodes;
static constexpr unsigned MaxTypeIDs = Vocabulary::MaxTypeIDs;
+static constexpr unsigned MaxCanonicalTypeIDs = Vocabulary::MaxCanonicalTypeIDs;
static constexpr unsigned MaxOperands = Vocabulary::MaxOperandKinds;
+// Mapping between LLVM Type::TypeID tokens and Vocabulary::CanonicalTypeID
+// names and their canonical string keys.
+#define IR2VEC_HANDLE_TYPE_BIMAP(X) \
+ X(VoidTyID, VoidTy, "VoidTy") \
+ X(IntegerTyID, IntegerTy, "IntegerTy") \
+ X(FloatTyID, FloatTy, "FloatTy") \
+ X(PointerTyID, PointerTy, "PointerTy") \
+ X(FunctionTyID, FunctionTy, "FunctionTy") \
+ X(StructTyID, StructTy, "StructTy") \
+ X(ArrayTyID, ArrayTy, "ArrayTy") \
+ X(FixedVectorTyID, VectorTy, "VectorTy") \
+ X(LabelTyID, LabelTy, "LabelTy") \
+ X(TokenTyID, TokenTy, "TokenTy") \
+ X(MetadataTyID, MetadataTy, "MetadataTy")
+
TEST(IR2VecVocabularyTest, DummyVocabTest) {
for (unsigned Dim = 1; Dim <= 10; ++Dim) {
auto VocabVec = Vocabulary::createDummyVocabForTest(Dim);
-
+ auto VocabVecSize = VocabVec.size();
// All embeddings should have the same dimension
for (const auto &Emb : VocabVec)
EXPECT_EQ(Emb.size(), Dim);
// Should have the correct total number of embeddings
- EXPECT_EQ(VocabVec.size(), MaxOpcodes + MaxTypeIDs + MaxOperands);
+ EXPECT_EQ(VocabVecSize, MaxOpcodes + MaxCanonicalTypeIDs + MaxOperands);
auto ExpectedVocab = VocabVec;
@@ -390,7 +470,7 @@ TEST(IR2VecVocabularyTest, DummyVocabTest) {
Vocabulary Result = VocabAnalysis.run(TestMod, MAM);
EXPECT_TRUE(Result.isValid());
EXPECT_EQ(Result.getDimension(), Dim);
- EXPECT_EQ(Result.size(), MaxOpcodes + MaxTypeIDs + MaxOperands);
+ EXPECT_EQ(Result.getCanonicalSize(), VocabVecSize);
unsigned CurPos = 0;
for (const auto &Entry : Result)
@@ -398,64 +478,68 @@ TEST(IR2VecVocabularyTest, DummyVocabTest) {
}
}
-TEST(IR2VecVocabularyTest, NumericIDMap) {
- // Test getNumericID for opcodes
- EXPECT_EQ(Vocabulary::getNumericID(1u), 0u);
- EXPECT_EQ(Vocabulary::getNumericID(13u), 12u);
- EXPECT_EQ(Vocabulary::getNumericID(MaxOpcodes), MaxOpcodes - 1);
-
- // Test getNumericID for Type IDs
- EXPECT_EQ(Vocabulary::getNumericID(Type::VoidTyID),
- MaxOpcodes + static_cast<unsigned>(Type::VoidTyID));
- EXPECT_EQ(Vocabulary::getNumericID(Type::HalfTyID),
- MaxOpcodes + static_cast<unsigned>(Type::HalfTyID));
- EXPECT_EQ(Vocabulary::getNumericID(Type::FloatTyID),
- MaxOpcodes + static_cast<unsigned>(Type::FloatTyID));
- EXPECT_EQ(Vocabulary::getNumericID(Type::IntegerTyID),
- MaxOpcodes + static_cast<unsigned>(Type::IntegerTyID));
- EXPECT_EQ(Vocabulary::getNumericID(Type::PointerTyID),
- MaxOpcodes + static_cast<unsigned>(Type::PointerTyID));
-
- // Test getNumericID for Value operands
+TEST(IR2VecVocabularyTest, SlotIdxMapping) {
+ // Test getSlotIndex for Opcodes
+#define EXPECT_OPCODE_SLOT(NUM, OPCODE, CLASS) \
+ EXPECT_EQ(Vocabulary::getSlotIndex(NUM), static_cast<unsigned>(NUM - 1));
+#define HANDLE_INST(NUM, OPCODE, CLASS) EXPECT_OPCODE_SLOT(NUM, OPCODE, CLASS)
+#include "llvm/IR/Instruction.def"
+#undef HANDLE_INST
+#undef EXPECT_OPCODE_SLOT
+
+ // Test getSlotIndex for Types
+#define EXPECT_TYPE_SLOT(TypeIDTok, CanonEnum, CanonStr) \
+ EXPECT_EQ(Vocabulary::getSlotIndex(Type::TypeIDTok), \
+ MaxOpcodes + static_cast<unsigned>( \
+ Vocabulary::CanonicalTypeID::CanonEnum));
+
+ IR2VEC_HANDLE_TYPE_BIMAP(EXPECT_TYPE_SLOT)
+
+#undef EXPECT_TYPE_SLOT
+
+ // Test getSlotIndex for Value operands
LLVMContext Ctx;
Module M("TestM", Ctx);
FunctionType *FTy =
FunctionType::get(Type::getVoidTy(Ctx), {Type::getInt32Ty(Ctx)}, false);
Function *F = Function::Create(FTy, Function::ExternalLinkage, "testFunc", M);
+#define EXPECTED_VOCAB_OPERAND_SLOT(X) \
+ MaxOpcodes + MaxCanonicalTypeIDs + static_cast<unsigned>(X)
// Test Function operand
- EXPECT_EQ(Vocabulary::getNumericID(F),
- MaxOpcodes + MaxTypeIDs + 0u); // Function = 0
+ EXPECT_EQ(Vocabulary::getSlotIndex(*F),
+ EXPECTED_VOCAB_OPERAND_SLOT(Vocabulary::OperandKind::FunctionID));
// Test Constant operand
Constant *C = ConstantInt::get(Type::getInt32Ty(Ctx), 42);
- EXPECT_EQ(Vocabulary::getNumericID(C),
- MaxOpcodes + MaxTypeIDs + 2u); // Constant = 2
+ EXPECT_EQ(Vocabulary::getSlotIndex(*C),
+ EXPECTED_VOCAB_OPERAND_SLOT(Vocabulary::OperandKind::ConstantID));
// Test Pointer operand
BasicBlock *BB = BasicBlock::Create(Ctx, "entry", F);
AllocaInst *PtrVal = new AllocaInst(Type::getInt32Ty(Ctx), 0, "ptr", BB);
- EXPECT_EQ(Vocabulary::getNumericID(PtrVal),
- MaxOpcodes + MaxTypeIDs + 1u); // Pointer = 1
+ EXPECT_EQ(Vocabulary::getSlotIndex(*PtrVal),
+ EXPECTED_VOCAB_OPERAND_SLOT(Vocabulary::OperandKind::PointerID));
// Test Variable operand (function argument)
Argument *Arg = F->getArg(0);
- EXPECT_EQ(Vocabulary::getNumericID(Arg),
- MaxOpcodes + MaxTypeIDs + 3u); // Variable = 3
+ EXPECT_EQ(Vocabulary::getSlotIndex(*Arg),
+ EXPECTED_VOCAB_OPERAND_SLOT(Vocabulary::OperandKind::VariableID));
+#undef EXPECTED_VOCAB_OPERAND_SLOT
}
#if GTEST_HAS_DEATH_TEST
#ifndef NDEBUG
TEST(IR2VecVocabularyTest, NumericIDMapInvalidInputs) {
// Test invalid opcode IDs
- EXPECT_DEATH(Vocabulary::getNumericID(0u), "Invalid opcode");
- EXPECT_DEATH(Vocabulary::getNumericID(MaxOpcodes + 1), "Invalid opcode");
+ EXPECT_DEATH(Vocabulary::getSlotIndex(0u), "Invalid opcode");
+ EXPECT_DEATH(Vocabulary::getSlotIndex(MaxOpcodes + 1), "Invalid opcode");
// Test invalid type IDs
- EXPECT_DEATH(Vocabulary::getNumericID(static_cast<Type::TypeID>(MaxTypeIDs)),
+ EXPECT_DEATH(Vocabulary::getSlotIndex(static_cast<Type::TypeID>(MaxTypeIDs)),
"Invalid type ID");
EXPECT_DEATH(
- Vocabulary::getNumericID(static_cast<Type::TypeID>(MaxTypeIDs + 10)),
+ Vocabulary::getSlotIndex(static_cast<Type::TypeID>(MaxTypeIDs + 10)),
"Invalid type ID");
}
#endif // NDEBUG
@@ -465,18 +549,46 @@ TEST(IR2VecVocabularyTest, StringKeyGeneration) {
EXPECT_EQ(Vocabulary::getStringKey(0), "Ret");
EXPECT_EQ(Vocabulary::getStringKey(12), "Add");
- StringRef HalfTypeKey = Vocabulary::getStringKey(MaxOpcodes + 0);
- StringRef FloatTypeKey = Vocabulary::getStringKey(MaxOpcodes + 2);
- StringRef VoidTypeKey = Vocabulary::getStringKey(MaxOpcodes + 7);
- StringRef IntTypeKey = Vocabulary::getStringKey(MaxOpcodes + 12);
-
- EXPECT_EQ(HalfTypeKey, "FloatTy");
- EXPECT_EQ(FloatTypeKey, "FloatTy");
- EXPECT_EQ(VoidTypeKey, "VoidTy");
- EXPECT_EQ(IntTypeKey, "IntegerTy");
-
- StringRef FuncArgKey = Vocabulary::getStringKey(MaxOpcodes + MaxTypeIDs + 0);
- StringRef PtrArgKey = Vocabulary::getStringKey(MaxOpcodes + MaxTypeIDs + 1);
+#define EXPECT_OPCODE(NUM, OPCODE, CLASS) \
+ EXPECT_EQ(Vocabulary::getStringKey(Vocabulary::getSlotIndex(NUM)), \
+ Vocabulary::getVocabKeyForOpcode(NUM));
+#define HANDLE_INST(NUM, OPCODE, CLASS) EXPECT_OPCODE(NUM, OPCODE, CLASS)
+#include "llvm/IR/Instruction.def"
+#undef HANDLE_INST
+#undef EXPECT_OPCODE
+
+ // Verify CanonicalTypeID -> string mapping
+#define EXPECT_CANONICAL_TYPE_NAME(TypeIDTok, CanonEnum, CanonStr) \
+ EXPECT_EQ(Vocabulary::getStringKey( \
+ MaxOpcodes + static_cast<unsigned>( \
+ Vocabulary::CanonicalTypeID::CanonEnum)), \
+ CanonStr);
+
+ IR2VEC_HANDLE_TYPE_BIMAP(EXPECT_CANONICAL_TYPE_NAME)
+
+#undef EXPECT_CANONICAL_TYPE_NAME
+
+#define HANDLE_OPERAND_KINDS(X) \
+ X(FunctionID, "Function") \
+ X(PointerID, "Pointer") \
+ X(ConstantID, "Constant") \
+ X(VariableID, "Variable")
+
+#define EXPECT_OPERAND_KIND(EnumName, Str) \
+ EXPECT_EQ(Vocabulary::getStringKey( \
+ MaxOpcodes + MaxCanonicalTypeIDs + \
+ static_cast<unsigned>(Vocabulary::OperandKind::EnumName)), \
+ Str);
+
+ HANDLE_OPERAND_KINDS(EXPECT_OPERAND_KIND)
+
+#undef EXPECT_OPERAND_KIND
+#undef HANDLE_OPERAND_KINDS
+
+ StringRef FuncArgKey =
+ Vocabulary::getStringKey(MaxOpcodes + MaxCanonicalTypeIDs + 0);
+ StringRef PtrArgKey =
+ Vocabulary::getStringKey(MaxOpcodes + MaxCanonicalTypeIDs + 1);
EXPECT_EQ(FuncArgKey, "Function");
EXPECT_EQ(PtrArgKey, "Pointer");
}
@@ -514,39 +626,14 @@ TEST(IR2VecVocabularyTest, InvalidAccess) {
#endif // GTEST_HAS_DEATH_TEST
TEST(IR2VecVocabularyTest, TypeIDStringKeyMapping) {
- EXPECT_EQ(Vocabulary::getStringKey(MaxOpcodes +
- static_cast<unsigned>(Type::VoidTyID)),
- "VoidTy");
- EXPECT_EQ(Vocabulary::getStringKey(MaxOpcodes +
- static_cast<unsigned>(Type::IntegerTyID)),
- "IntegerTy");
- EXPECT_EQ(Vocabulary::getStringKey(MaxOpcodes +
- static_cast<unsigned>(Type::FloatTyID)),
- "FloatTy");
- EXPECT_EQ(Vocabulary::getStringKey(MaxOpcodes +
- static_cast<unsigned>(Type::PointerTyID)),
- "PointerTy");
- EXPECT_EQ(Vocabulary::getStringKey(MaxOpcodes +
- static_cast<unsigned>(Type::FunctionTyID)),
- "FunctionTy");
- EXPECT_EQ(Vocabulary::getStringKey(MaxOpcodes +
- static_cast<unsigned>(Type::StructTyID)),
- "StructTy");
- EXPECT_EQ(Vocabulary::getStringKey(MaxOpcodes +
- static_cast<unsigned>(Type::ArrayTyID)),
- "ArrayTy");
- EXPECT_EQ(Vocabulary::getStringKey(
- MaxOpcodes + static_cast<unsigned>(Type::FixedVectorTyID)),
- "VectorTy");
- EXPECT_EQ(Vocabulary::getStringKey(MaxOpcodes +
- static_cast<unsigned>(Type::LabelTyID)),
- "LabelTy");
- EXPECT_EQ(Vocabulary::getStringKey(MaxOpcodes +
- static_cast<unsigned>(Type::TokenTyID)),
- "TokenTy");
- EXPECT_EQ(Vocabulary::getStringKey(MaxOpcodes +
- static_cast<unsigned>(Type::MetadataTyID)),
- "MetadataTy");
+#define EXPECT_TYPE_TO_CANONICAL(TypeIDTok, CanonEnum, CanonStr) \
+ EXPECT_EQ( \
+ Vocabulary::getStringKey(Vocabulary::getSlotIndex(Type::TypeIDTok)), \
+ CanonStr);
+
+ IR2VEC_HANDLE_TYPE_BIMAP(EXPECT_TYPE_TO_CANONICAL)
+
+#undef EXPECT_TYPE_TO_CANONICAL
}
TEST(IR2VecVocabularyTest, InvalidVocabularyConstruction) {
diff --git a/llvm/unittests/Analysis/ValueTrackingTest.cpp b/llvm/unittests/Analysis/ValueTrackingTest.cpp
index 6af2006..559a0b7 100644
--- a/llvm/unittests/Analysis/ValueTrackingTest.cpp
+++ b/llvm/unittests/Analysis/ValueTrackingTest.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/Analysis/ValueTracking.h"
+#include "llvm/ADT/FloatingPointMode.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/FloatingPointPredicateUtils.h"
#include "llvm/AsmParser/Parser.h"
@@ -2208,6 +2209,41 @@ TEST_F(ComputeKnownFPClassTest, Constants) {
}
}
+TEST_F(ComputeKnownFPClassTest, fcmpImpliesClass_fabs_zero) {
+ parseAssembly("define float @test(float %x) {\n"
+ " %A = call float @llvm.fabs.f32(float %x)\n"
+ " ret float %A\n"
+ "}\n");
+ EXPECT_EQ(std::get<1>(fcmpImpliesClass(FCmpInst::FCMP_OEQ, *F, A, fcZero)),
+ fcZero);
+ EXPECT_EQ(std::get<1>(fcmpImpliesClass(FCmpInst::FCMP_UEQ, *F, A, fcZero)),
+ fcZero | fcNan);
+ EXPECT_EQ(std::get<1>(fcmpImpliesClass(FCmpInst::FCMP_UNE, *F, A, fcZero)),
+ ~fcZero);
+ EXPECT_EQ(std::get<1>(fcmpImpliesClass(FCmpInst::FCMP_ONE, *F, A, fcZero)),
+ ~fcNan & ~fcZero);
+ EXPECT_EQ(std::get<1>(fcmpImpliesClass(FCmpInst::FCMP_ORD, *F, A, fcZero)),
+ ~fcNan);
+ EXPECT_EQ(std::get<1>(fcmpImpliesClass(FCmpInst::FCMP_UNO, *F, A, fcZero)),
+ fcNan);
+ EXPECT_EQ(std::get<1>(fcmpImpliesClass(FCmpInst::FCMP_OGT, *F, A, fcZero)),
+ fcSubnormal | fcNormal | fcInf);
+ EXPECT_EQ(std::get<1>(fcmpImpliesClass(FCmpInst::FCMP_UGT, *F, A, fcZero)),
+ fcSubnormal | fcNormal | fcInf | fcNan);
+ EXPECT_EQ(std::get<1>(fcmpImpliesClass(FCmpInst::FCMP_OGE, *F, A, fcZero)),
+ ~fcNan);
+ EXPECT_EQ(std::get<1>(fcmpImpliesClass(FCmpInst::FCMP_UGE, *F, A, fcZero)),
+ fcAllFlags);
+ EXPECT_EQ(std::get<1>(fcmpImpliesClass(FCmpInst::FCMP_OLT, *F, A, fcZero)),
+ fcNone);
+ EXPECT_EQ(std::get<1>(fcmpImpliesClass(FCmpInst::FCMP_ULT, *F, A, fcZero)),
+ fcNan);
+ EXPECT_EQ(std::get<1>(fcmpImpliesClass(FCmpInst::FCMP_OLE, *F, A, fcZero)),
+ fcZero);
+ EXPECT_EQ(std::get<1>(fcmpImpliesClass(FCmpInst::FCMP_ULE, *F, A, fcZero)),
+ fcZero | fcNan);
+}
+
TEST_F(ValueTrackingTest, isNonZeroRecurrence) {
parseAssembly(R"(
define i1 @test(i8 %n, i8 %r) {
diff --git a/llvm/unittests/BinaryFormat/MsgPackDocumentTest.cpp b/llvm/unittests/BinaryFormat/MsgPackDocumentTest.cpp
index a8db0f1..6a6ad70 100644
--- a/llvm/unittests/BinaryFormat/MsgPackDocumentTest.cpp
+++ b/llvm/unittests/BinaryFormat/MsgPackDocumentTest.cpp
@@ -22,12 +22,58 @@ TEST(MsgPackDocument, DocNodeTest) {
ASSERT_TRUE(Str1 == Str2);
}
+TEST(MsgPackDocument, TestReadBoolean) {
+ Document Doc1;
+ bool Ok = Doc1.readFromBlob(StringRef("\xC2", 1), /*Multi=*/false);
+ ASSERT_TRUE(Ok);
+ ASSERT_EQ(Doc1.getRoot().getKind(), Type::Boolean);
+ ASSERT_EQ(Doc1.getRoot().getBool(), false);
+ Document Doc2;
+ Ok = Doc2.readFromBlob(StringRef("\xC3", 1), /*Multi=*/false);
+ ASSERT_TRUE(Ok);
+ ASSERT_EQ(Doc2.getRoot().getKind(), Type::Boolean);
+ ASSERT_EQ(Doc2.getRoot().getBool(), true);
+}
+
TEST(MsgPackDocument, TestReadInt) {
- Document Doc;
- bool Ok = Doc.readFromBlob(StringRef("\xd0\x00", 2), /*Multi=*/false);
+ Document Doc1;
+ bool Ok = Doc1.readFromBlob(StringRef("\xD0\x00", 2), /*Multi=*/false);
+ ASSERT_TRUE(Ok);
+ ASSERT_EQ(Doc1.getRoot().getKind(), Type::Int);
+ ASSERT_EQ(Doc1.getRoot().getInt(), 0);
+ Document Doc2;
+ Ok = Doc2.readFromBlob(StringRef("\xFF", 1), /*Multi=*/false);
+ ASSERT_TRUE(Ok);
+ ASSERT_EQ(Doc2.getRoot().getKind(), Type::Int);
+ ASSERT_EQ(Doc2.getRoot().getInt(), -1);
+}
+
+TEST(MsgPackDocument, TestReadUInt) {
+ Document Doc1;
+ bool Ok = Doc1.readFromBlob(StringRef("\xCC\x00", 2), /*Multi=*/false);
+ ASSERT_TRUE(Ok);
+ ASSERT_EQ(Doc1.getRoot().getKind(), Type::UInt);
+ ASSERT_EQ(Doc1.getRoot().getUInt(), 0U);
+ Document Doc2;
+ Ok = Doc2.readFromBlob(StringRef("\x01", 1), /*Multi=*/false);
ASSERT_TRUE(Ok);
- ASSERT_EQ(Doc.getRoot().getKind(), Type::Int);
- ASSERT_EQ(Doc.getRoot().getInt(), 0);
+ ASSERT_EQ(Doc2.getRoot().getKind(), Type::UInt);
+ ASSERT_EQ(Doc2.getRoot().getUInt(), 1U);
+}
+
+TEST(MsgPackDocument, TestReadFloat) {
+ Document Doc1;
+ bool Ok =
+ Doc1.readFromBlob(StringRef("\xCA\x3F\x80\x00\x00", 5), /*Multi=*/false);
+ ASSERT_TRUE(Ok);
+ ASSERT_EQ(Doc1.getRoot().getKind(), Type::Float);
+ ASSERT_EQ(Doc1.getRoot().getFloat(), 1.0);
+ Document Doc2;
+ Ok = Doc2.readFromBlob(StringRef("\xCB\x48\x3D\x63\x29\xF1\xC3\x5C\xA5", 9),
+ /*Multi=*/false);
+ ASSERT_TRUE(Ok);
+ ASSERT_EQ(Doc2.getRoot().getKind(), Type::Float);
+ ASSERT_EQ(Doc2.getRoot().getFloat(), 1e40);
}
TEST(MsgPackDocument, TestReadBinary) {
@@ -192,12 +238,54 @@ TEST(MsgPackDocument, TestReadMergeMap) {
ASSERT_EQ(BayS.getInt(), 8);
}
+TEST(MsgPackDocument, TestWriteBoolean) {
+ Document Doc;
+ Doc.getRoot() = true;
+ std::string Buffer;
+ Doc.writeToBlob(Buffer);
+ ASSERT_EQ(Buffer, "\xc3");
+ Doc.getRoot() = false;
+ Doc.writeToBlob(Buffer);
+ ASSERT_EQ(Buffer, "\xc2");
+}
+
TEST(MsgPackDocument, TestWriteInt) {
Document Doc;
Doc.getRoot() = 1;
std::string Buffer;
Doc.writeToBlob(Buffer);
ASSERT_EQ(Buffer, "\x01");
+ Doc.getRoot() = -1;
+ Doc.writeToBlob(Buffer);
+ ASSERT_EQ(Buffer, "\xFF");
+ Doc.getRoot() = -4096;
+ Doc.writeToBlob(Buffer);
+ ASSERT_EQ(Buffer, StringRef("\xD1\xF0\x00", 3));
+}
+
+TEST(MsgPackDocument, TestWriteUInt) {
+ Document Doc;
+ Doc.getRoot() = 1U;
+ std::string Buffer;
+ Doc.writeToBlob(Buffer);
+ ASSERT_EQ(Buffer, "\x01");
+ Doc.getRoot() = 4096U;
+ Doc.writeToBlob(Buffer);
+ ASSERT_EQ(Buffer, StringRef("\xCD\x10\x00", 3));
+}
+
+TEST(MsgPackDocument, TestWriteFloat) {
+ Document Doc;
+ Doc.getRoot() = 1.0;
+ std::string Buffer;
+ Doc.writeToBlob(Buffer);
+ ASSERT_EQ(Buffer, StringRef("\xCA\x3F\x80\x00\x00", 5));
+ Doc.getRoot() = 1.0f;
+ Doc.writeToBlob(Buffer);
+ ASSERT_EQ(Buffer, StringRef("\xCA\x3F\x80\x00\x00", 5));
+ Doc.getRoot() = 1e40;
+ Doc.writeToBlob(Buffer);
+ ASSERT_EQ(Buffer, "\xCB\x48\x3D\x63\x29\xF1\xC3\x5C\xA5");
}
TEST(MsgPackDocument, TestWriteBinary) {
diff --git a/llvm/unittests/BinaryFormat/SFrameTest.cpp b/llvm/unittests/BinaryFormat/SFrameTest.cpp
index 394e382..ab7b0fe 100644
--- a/llvm/unittests/BinaryFormat/SFrameTest.cpp
+++ b/llvm/unittests/BinaryFormat/SFrameTest.cpp
@@ -54,28 +54,28 @@ TYPED_TEST_SUITE(SFrameTest, Types, NameGenerator);
TYPED_TEST(SFrameTest, FDEFlags) {
FuncDescEntry<TestFixture::Endian> FDE = {};
- EXPECT_EQ(FDE.Info, 0u);
- EXPECT_EQ(FDE.getPAuthKey(), 0);
- EXPECT_EQ(FDE.getFDEType(), FDEType::PCInc);
- EXPECT_EQ(FDE.getFREType(), FREType::Addr1);
-
- FDE.setPAuthKey(1);
- EXPECT_EQ(FDE.Info, 0x20u);
- EXPECT_EQ(FDE.getPAuthKey(), 1);
- EXPECT_EQ(FDE.getFDEType(), FDEType::PCInc);
- EXPECT_EQ(FDE.getFREType(), FREType::Addr1);
-
- FDE.setFDEType(FDEType::PCMask);
- EXPECT_EQ(FDE.Info, 0x30u);
- EXPECT_EQ(FDE.getPAuthKey(), 1);
- EXPECT_EQ(FDE.getFDEType(), FDEType::PCMask);
- EXPECT_EQ(FDE.getFREType(), FREType::Addr1);
-
- FDE.setFREType(FREType::Addr4);
- EXPECT_EQ(FDE.Info, 0x32u);
- EXPECT_EQ(FDE.getPAuthKey(), 1);
- EXPECT_EQ(FDE.getFDEType(), FDEType::PCMask);
- EXPECT_EQ(FDE.getFREType(), FREType::Addr4);
+ EXPECT_EQ(FDE.Info.Info, 0u);
+ EXPECT_EQ(FDE.Info.getPAuthKey(), 0);
+ EXPECT_EQ(FDE.Info.getFDEType(), FDEType::PCInc);
+ EXPECT_EQ(FDE.Info.getFREType(), FREType::Addr1);
+
+ FDE.Info.setPAuthKey(1);
+ EXPECT_EQ(FDE.Info.Info, 0x20u);
+ EXPECT_EQ(FDE.Info.getPAuthKey(), 1);
+ EXPECT_EQ(FDE.Info.getFDEType(), FDEType::PCInc);
+ EXPECT_EQ(FDE.Info.getFREType(), FREType::Addr1);
+
+ FDE.Info.setFDEType(FDEType::PCMask);
+ EXPECT_EQ(FDE.Info.Info, 0x30u);
+ EXPECT_EQ(FDE.Info.getPAuthKey(), 1);
+ EXPECT_EQ(FDE.Info.getFDEType(), FDEType::PCMask);
+ EXPECT_EQ(FDE.Info.getFREType(), FREType::Addr1);
+
+ FDE.Info.setFREType(FREType::Addr4);
+ EXPECT_EQ(FDE.Info.Info, 0x32u);
+ EXPECT_EQ(FDE.Info.getPAuthKey(), 1);
+ EXPECT_EQ(FDE.Info.getFDEType(), FDEType::PCMask);
+ EXPECT_EQ(FDE.Info.getFREType(), FREType::Addr4);
}
TYPED_TEST(SFrameTest, FREFlags) {
diff --git a/llvm/unittests/CAS/ActionCacheTest.cpp b/llvm/unittests/CAS/ActionCacheTest.cpp
new file mode 100644
index 0000000..db67e30
--- /dev/null
+++ b/llvm/unittests/CAS/ActionCacheTest.cpp
@@ -0,0 +1,73 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file implements the tests for ActionCaches.
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm/CAS/ActionCache.h"
+#include "CASTestConfig.h"
+#include "llvm/CAS/ObjectStore.h"
+#include "llvm/Testing/Support/Error.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace llvm::cas;
+
+TEST_P(CASTest, ActionCacheHit) {
+ std::shared_ptr<ObjectStore> CAS = createObjectStore();
+ std::unique_ptr<ActionCache> Cache = createActionCache();
+
+ std::optional<ObjectProxy> ID;
+ ASSERT_THAT_ERROR(CAS->createProxy({}, "1").moveInto(ID), Succeeded());
+ std::optional<CASID> ResultID;
+ ASSERT_THAT_ERROR(Cache->put(*ID, *ID), Succeeded());
+ ASSERT_THAT_ERROR(Cache->get(*ID).moveInto(ResultID), Succeeded());
+ ASSERT_TRUE(ResultID);
+ std::optional<ObjectRef> Result = CAS->getReference(*ResultID);
+ ASSERT_TRUE(Result);
+ ASSERT_EQ(*ID, *Result);
+}
+
+TEST_P(CASTest, ActionCacheMiss) {
+ std::shared_ptr<ObjectStore> CAS = createObjectStore();
+ std::unique_ptr<ActionCache> Cache = createActionCache();
+
+ std::optional<ObjectProxy> ID1, ID2;
+ ASSERT_THAT_ERROR(CAS->createProxy({}, "1").moveInto(ID1), Succeeded());
+ ASSERT_THAT_ERROR(CAS->createProxy({}, "2").moveInto(ID2), Succeeded());
+ ASSERT_THAT_ERROR(Cache->put(*ID1, *ID2), Succeeded());
+ // This is a cache miss for looking up a key doesn't exist.
+ std::optional<CASID> Result1;
+ ASSERT_THAT_ERROR(Cache->get(*ID2).moveInto(Result1), Succeeded());
+ ASSERT_FALSE(Result1);
+
+ ASSERT_THAT_ERROR(Cache->put(*ID2, *ID1), Succeeded());
+ // Cache hit after adding the value.
+ std::optional<CASID> Result2;
+ ASSERT_THAT_ERROR(Cache->get(*ID2).moveInto(Result2), Succeeded());
+ ASSERT_TRUE(Result2);
+ std::optional<ObjectRef> Ref = CAS->getReference(*Result2);
+ ASSERT_TRUE(Ref);
+ ASSERT_EQ(*ID1, *Ref);
+}
+
+TEST_P(CASTest, ActionCacheRewrite) {
+ std::shared_ptr<ObjectStore> CAS = createObjectStore();
+ std::unique_ptr<ActionCache> Cache = createActionCache();
+
+ std::optional<ObjectProxy> ID1, ID2;
+ ASSERT_THAT_ERROR(CAS->createProxy({}, "1").moveInto(ID1), Succeeded());
+ ASSERT_THAT_ERROR(CAS->createProxy({}, "2").moveInto(ID2), Succeeded());
+ ASSERT_THAT_ERROR(Cache->put(*ID1, *ID1), Succeeded());
+ // Writing to the same key with different value is error.
+ ASSERT_THAT_ERROR(Cache->put(*ID1, *ID2), Failed());
+ // Writing the same value multiple times to the same key is fine.
+ ASSERT_THAT_ERROR(Cache->put(*ID1, *ID1), Succeeded());
+}
diff --git a/llvm/unittests/CAS/CASTestConfig.cpp b/llvm/unittests/CAS/CASTestConfig.cpp
new file mode 100644
index 0000000..29e2db4
--- /dev/null
+++ b/llvm/unittests/CAS/CASTestConfig.cpp
@@ -0,0 +1,21 @@
+//===- CASTestConfig.cpp --------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "CASTestConfig.h"
+#include "llvm/CAS/ObjectStore.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace llvm::cas;
+
+static CASTestingEnv createInMemory(int I) {
+ return CASTestingEnv{createInMemoryCAS(), createInMemoryActionCache()};
+}
+
+INSTANTIATE_TEST_SUITE_P(InMemoryCAS, CASTest,
+ ::testing::Values(createInMemory));
diff --git a/llvm/unittests/CAS/CASTestConfig.h b/llvm/unittests/CAS/CASTestConfig.h
new file mode 100644
index 0000000..8093a0b
--- /dev/null
+++ b/llvm/unittests/CAS/CASTestConfig.h
@@ -0,0 +1,38 @@
+//===- CASTestConfig.h ----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/CAS/ActionCache.h"
+#include "llvm/CAS/ObjectStore.h"
+#include "gtest/gtest.h"
+
+#ifndef LLVM_UNITTESTS_CASTESTCONFIG_H
+#define LLVM_UNITTESTS_CASTESTCONFIG_H
+
+struct CASTestingEnv {
+ std::unique_ptr<llvm::cas::ObjectStore> CAS;
+ std::unique_ptr<llvm::cas::ActionCache> Cache;
+};
+
+class CASTest
+ : public testing::TestWithParam<std::function<CASTestingEnv(int)>> {
+protected:
+ std::optional<int> NextCASIndex;
+
+ std::unique_ptr<llvm::cas::ObjectStore> createObjectStore() {
+ auto TD = GetParam()(++(*NextCASIndex));
+ return std::move(TD.CAS);
+ }
+ std::unique_ptr<llvm::cas::ActionCache> createActionCache() {
+ auto TD = GetParam()(++(*NextCASIndex));
+ return std::move(TD.Cache);
+ }
+ void SetUp() { NextCASIndex = 0; }
+ void TearDown() { NextCASIndex = std::nullopt; }
+};
+
+#endif
diff --git a/llvm/unittests/CAS/CMakeLists.txt b/llvm/unittests/CAS/CMakeLists.txt
new file mode 100644
index 0000000..ff08100
--- /dev/null
+++ b/llvm/unittests/CAS/CMakeLists.txt
@@ -0,0 +1,13 @@
+set(LLVM_LINK_COMPONENTS
+ Support
+ CAS
+ TestingSupport
+ )
+
+add_llvm_unittest(CASTests
+ ActionCacheTest.cpp
+ CASTestConfig.cpp
+ ObjectStoreTest.cpp
+ )
+
+target_link_libraries(CASTests PRIVATE LLVMTestingSupport)
diff --git a/llvm/unittests/CAS/ObjectStoreTest.cpp b/llvm/unittests/CAS/ObjectStoreTest.cpp
new file mode 100644
index 0000000..54083fd
--- /dev/null
+++ b/llvm/unittests/CAS/ObjectStoreTest.cpp
@@ -0,0 +1,348 @@
+//===- ObjectStoreTest.cpp ------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/CAS/ObjectStore.h"
+#include "llvm/Config/llvm-config.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/RandomNumberGenerator.h"
+#include "llvm/Support/ThreadPool.h"
+#include "llvm/Testing/Support/Error.h"
+#include "gtest/gtest.h"
+
+#include "CASTestConfig.h"
+
+using namespace llvm;
+using namespace llvm::cas;
+
+TEST_P(CASTest, PrintIDs) {
+ std::unique_ptr<ObjectStore> CAS = createObjectStore();
+
+ std::optional<CASID> ID1, ID2;
+ ASSERT_THAT_ERROR(CAS->createProxy({}, "1").moveInto(ID1), Succeeded());
+ ASSERT_THAT_ERROR(CAS->createProxy({}, "2").moveInto(ID2), Succeeded());
+ EXPECT_NE(ID1, ID2);
+ std::string PrintedID1 = ID1->toString();
+ std::string PrintedID2 = ID2->toString();
+ EXPECT_NE(PrintedID1, PrintedID2);
+
+ std::optional<CASID> ParsedID1, ParsedID2;
+ ASSERT_THAT_ERROR(CAS->parseID(PrintedID1).moveInto(ParsedID1), Succeeded());
+ ASSERT_THAT_ERROR(CAS->parseID(PrintedID2).moveInto(ParsedID2), Succeeded());
+ EXPECT_EQ(ID1, ParsedID1);
+ EXPECT_EQ(ID2, ParsedID2);
+}
+
+TEST_P(CASTest, Blobs) {
+ std::unique_ptr<ObjectStore> CAS1 = createObjectStore();
+ StringRef ContentStrings[] = {
+ "word",
+ "some longer text std::string's local memory",
+ R"(multiline text multiline text multiline text multiline text
+multiline text multiline text multiline text multiline text multiline text
+multiline text multiline text multiline text multiline text multiline text
+multiline text multiline text multiline text multiline text multiline text
+multiline text multiline text multiline text multiline text multiline text
+multiline text multiline text multiline text multiline text multiline text)",
+ };
+
+ SmallVector<CASID> IDs;
+ for (StringRef Content : ContentStrings) {
+ // Use StringRef::str() to create a temporary std::string. This could cause
+ // problems if the CAS is storing references to the input string instead of
+ // copying it.
+ std::optional<ObjectProxy> Blob;
+ ASSERT_THAT_ERROR(CAS1->createProxy({}, Content).moveInto(Blob),
+ Succeeded());
+ IDs.push_back(Blob->getID());
+
+ // Check basic printing of IDs.
+ EXPECT_EQ(IDs.back().toString(), IDs.back().toString());
+ if (IDs.size() > 2)
+ EXPECT_NE(IDs.front().toString(), IDs.back().toString());
+ }
+
+ // Check that the blobs give the same IDs later.
+ for (int I = 0, E = IDs.size(); I != E; ++I) {
+ std::optional<ObjectProxy> Blob;
+ ASSERT_THAT_ERROR(CAS1->createProxy({}, ContentStrings[I]).moveInto(Blob),
+ Succeeded());
+ EXPECT_EQ(IDs[I], Blob->getID());
+ }
+
+ // Run validation on all CASIDs.
+ for (int I = 0, E = IDs.size(); I != E; ++I)
+ ASSERT_THAT_ERROR(CAS1->validate(IDs[I]), Succeeded());
+
+ // Check that the blobs can be retrieved multiple times.
+ for (int I = 0, E = IDs.size(); I != E; ++I) {
+ for (int J = 0, JE = 3; J != JE; ++J) {
+ std::optional<ObjectProxy> Buffer;
+ ASSERT_THAT_ERROR(CAS1->getProxy(IDs[I]).moveInto(Buffer), Succeeded());
+ EXPECT_EQ(ContentStrings[I], Buffer->getData());
+ }
+ }
+
+ // Confirm these blobs don't exist in a fresh CAS instance.
+ std::unique_ptr<ObjectStore> CAS2 = createObjectStore();
+ for (int I = 0, E = IDs.size(); I != E; ++I) {
+ std::optional<ObjectProxy> Proxy;
+ EXPECT_THAT_ERROR(CAS2->getProxy(IDs[I]).moveInto(Proxy), Failed());
+ }
+
+ // Insert into the second CAS and confirm the IDs are stable. Getting them
+ // should work now.
+ for (int I = IDs.size(), E = 0; I != E; --I) {
+ auto &ID = IDs[I - 1];
+ auto &Content = ContentStrings[I - 1];
+ std::optional<ObjectProxy> Blob;
+ ASSERT_THAT_ERROR(CAS2->createProxy({}, Content).moveInto(Blob),
+ Succeeded());
+ EXPECT_EQ(ID, Blob->getID());
+
+ std::optional<ObjectProxy> Buffer;
+ ASSERT_THAT_ERROR(CAS2->getProxy(ID).moveInto(Buffer), Succeeded());
+ EXPECT_EQ(Content, Buffer->getData());
+ }
+}
+
+TEST_P(CASTest, BlobsBig) {
+ // A little bit of validation that bigger blobs are okay. Climb up to 1MB.
+ std::unique_ptr<ObjectStore> CAS = createObjectStore();
+ SmallString<256> String1 = StringRef("a few words");
+ SmallString<256> String2 = StringRef("others");
+ while (String1.size() < 1024U * 1024U) {
+ std::optional<CASID> ID1;
+ std::optional<CASID> ID2;
+ ASSERT_THAT_ERROR(CAS->createProxy({}, String1).moveInto(ID1), Succeeded());
+ ASSERT_THAT_ERROR(CAS->createProxy({}, String1).moveInto(ID2), Succeeded());
+ ASSERT_THAT_ERROR(CAS->validate(*ID1), Succeeded());
+ ASSERT_THAT_ERROR(CAS->validate(*ID2), Succeeded());
+ ASSERT_EQ(ID1, ID2);
+
+ String1.append(String2);
+ ASSERT_THAT_ERROR(CAS->createProxy({}, String2).moveInto(ID1), Succeeded());
+ ASSERT_THAT_ERROR(CAS->createProxy({}, String2).moveInto(ID2), Succeeded());
+ ASSERT_THAT_ERROR(CAS->validate(*ID1), Succeeded());
+ ASSERT_THAT_ERROR(CAS->validate(*ID2), Succeeded());
+ ASSERT_EQ(ID1, ID2);
+ String2.append(String1);
+ }
+
+ // Specifically check near 1MB for objects large enough they're likely to be
+ // stored externally in an on-disk CAS and will be near a page boundary.
+ SmallString<0> Storage;
+ const size_t InterestingSize = 1024U * 1024ULL;
+ const size_t SizeE = InterestingSize + 2;
+ if (Storage.size() < SizeE)
+ Storage.resize(SizeE, '\01');
+ for (size_t Size = InterestingSize - 2; Size != SizeE; ++Size) {
+ StringRef Data(Storage.data(), Size);
+ std::optional<ObjectProxy> Blob;
+ ASSERT_THAT_ERROR(CAS->createProxy({}, Data).moveInto(Blob), Succeeded());
+ ASSERT_EQ(Data, Blob->getData());
+ ASSERT_EQ(0, Blob->getData().end()[0]);
+ }
+}
+
+TEST_P(CASTest, LeafNodes) {
+ std::unique_ptr<ObjectStore> CAS1 = createObjectStore();
+ StringRef ContentStrings[] = {
+ "word",
+ "some longer text std::string's local memory",
+ R"(multiline text multiline text multiline text multiline text
+multiline text multiline text multiline text multiline text multiline text
+multiline text multiline text multiline text multiline text multiline text
+multiline text multiline text multiline text multiline text multiline text
+multiline text multiline text multiline text multiline text multiline text
+multiline text multiline text multiline text multiline text multiline text)",
+ };
+
+ SmallVector<ObjectRef> Nodes;
+ SmallVector<CASID> IDs;
+ for (StringRef Content : ContentStrings) {
+ // Use StringRef::str() to create a temporary std::string. This could cause
+ // problems if the CAS is storing references to the input string instead of
+ // copying it.
+ std::optional<ObjectRef> Node;
+ ASSERT_THAT_ERROR(
+ CAS1->store({}, arrayRefFromStringRef<char>(Content)).moveInto(Node),
+ Succeeded());
+ Nodes.push_back(*Node);
+
+ // Check basic printing of IDs.
+ IDs.push_back(CAS1->getID(*Node));
+ auto ID = CAS1->getID(Nodes.back());
+ EXPECT_EQ(ID.toString(), IDs.back().toString());
+ EXPECT_EQ(*Node, Nodes.back());
+ EXPECT_EQ(ID, IDs.back());
+ if (Nodes.size() <= 1)
+ continue;
+ EXPECT_NE(Nodes.front(), Nodes.back());
+ EXPECT_NE(IDs.front(), IDs.back());
+ }
+
+ // Check that the blobs give the same IDs later.
+ for (int I = 0, E = IDs.size(); I != E; ++I) {
+ std::optional<ObjectRef> Node;
+ ASSERT_THAT_ERROR(
+ CAS1->store({}, arrayRefFromStringRef<char>(ContentStrings[I]))
+ .moveInto(Node),
+ Succeeded());
+ EXPECT_EQ(IDs[I], CAS1->getID(*Node));
+ }
+
+ // Check that the blobs can be retrieved multiple times.
+ for (int I = 0, E = IDs.size(); I != E; ++I) {
+ for (int J = 0, JE = 3; J != JE; ++J) {
+ std::optional<ObjectProxy> Object;
+ ASSERT_THAT_ERROR(CAS1->getProxy(IDs[I]).moveInto(Object), Succeeded());
+ ASSERT_TRUE(Object);
+ EXPECT_EQ(ContentStrings[I], Object->getData());
+ }
+ }
+
+ // Confirm these blobs don't exist in a fresh CAS instance.
+ std::unique_ptr<ObjectStore> CAS2 = createObjectStore();
+ for (int I = 0, E = IDs.size(); I != E; ++I) {
+ std::optional<ObjectProxy> Object;
+ EXPECT_THAT_ERROR(CAS2->getProxy(IDs[I]).moveInto(Object), Failed());
+ }
+
+ // Insert into the second CAS and confirm the IDs are stable. Getting them
+ // should work now.
+ for (int I = IDs.size(), E = 0; I != E; --I) {
+ auto &ID = IDs[I - 1];
+ auto &Content = ContentStrings[I - 1];
+ std::optional<ObjectRef> Node;
+ ASSERT_THAT_ERROR(
+ CAS2->store({}, arrayRefFromStringRef<char>(Content)).moveInto(Node),
+ Succeeded());
+ EXPECT_EQ(ID, CAS2->getID(*Node));
+
+ std::optional<ObjectProxy> Object;
+ ASSERT_THAT_ERROR(CAS2->getProxy(ID).moveInto(Object), Succeeded());
+ ASSERT_TRUE(Object);
+ EXPECT_EQ(Content, Object->getData());
+ }
+}
+
+TEST_P(CASTest, NodesBig) {
+ std::unique_ptr<ObjectStore> CAS = createObjectStore();
+
+ // Specifically check near 1MB for objects large enough they're likely to be
+ // stored externally in an on-disk CAS, and such that one of them will be
+ // near a page boundary.
+ SmallString<0> Storage;
+ constexpr size_t InterestingSize = 1024U * 1024ULL;
+ constexpr size_t WordSize = sizeof(void *);
+
+ // Start much smaller to account for headers.
+ constexpr size_t SizeB = InterestingSize - 8 * WordSize;
+ constexpr size_t SizeE = InterestingSize + 1;
+ if (Storage.size() < SizeE)
+ Storage.resize(SizeE, '\01');
+
+ SmallVector<ObjectRef, 4> CreatedNodes;
+ // Avoid checking every size because this is an expensive test. Just check
+ // for data that is 8B-word-aligned, and one less. Also appending the created
+ // nodes as the references in the next block to check references are created
+ // correctly.
+ for (size_t Size = SizeB; Size < SizeE; Size += WordSize) {
+ for (bool IsAligned : {false, true}) {
+ StringRef Data(Storage.data(), Size - (IsAligned ? 0 : 1));
+ std::optional<ObjectProxy> Node;
+ ASSERT_THAT_ERROR(CAS->createProxy(CreatedNodes, Data).moveInto(Node),
+ Succeeded());
+ ASSERT_EQ(Data, Node->getData());
+ ASSERT_EQ(0, Node->getData().end()[0]);
+ ASSERT_EQ(Node->getNumReferences(), CreatedNodes.size());
+ CreatedNodes.emplace_back(Node->getRef());
+ }
+ }
+
+ for (auto ID : CreatedNodes)
+ ASSERT_THAT_ERROR(CAS->validate(CAS->getID(ID)), Succeeded());
+}
+
+#if LLVM_ENABLE_THREADS
+/// Common test functionality for creating blobs in parallel. You can vary which
+/// cas instances are the same or different, and the size of the created blobs.
+static void testBlobsParallel(ObjectStore &Read1, ObjectStore &Read2,
+ ObjectStore &Write1, ObjectStore &Write2,
+ uint64_t BlobSize) {
+ SCOPED_TRACE("testBlobsParallel");
+ unsigned BlobCount = 100;
+ std::vector<std::string> Blobs;
+ Blobs.reserve(BlobCount);
+ for (unsigned I = 0; I < BlobCount; ++I) {
+ std::string Blob;
+ Blob.resize(BlobSize);
+ getRandomBytes(Blob.data(), BlobSize);
+ Blobs.push_back(std::move(Blob));
+ }
+
+ std::mutex NodesMtx;
+ std::vector<std::optional<CASID>> CreatedNodes(BlobCount);
+
+ auto Producer = [&](unsigned I, ObjectStore *CAS) {
+ std::optional<ObjectProxy> Node;
+ EXPECT_THAT_ERROR(CAS->createProxy({}, Blobs[I]).moveInto(Node),
+ Succeeded());
+ {
+ std::lock_guard<std::mutex> L(NodesMtx);
+ CreatedNodes[I] = Node ? Node->getID() : CASID::getDenseMapTombstoneKey();
+ }
+ };
+
+ auto Consumer = [&](unsigned I, ObjectStore *CAS) {
+ std::optional<CASID> ID;
+ while (!ID) {
+ // Busy wait.
+ std::lock_guard<std::mutex> L(NodesMtx);
+ ID = CreatedNodes[I];
+ }
+ if (ID == CASID::getDenseMapTombstoneKey())
+ // Producer failed; already reported.
+ return;
+
+ std::optional<ObjectProxy> Node;
+ ASSERT_THAT_ERROR(CAS->getProxy(*ID).moveInto(Node), Succeeded());
+ EXPECT_EQ(Node->getData(), Blobs[I]);
+ };
+
+ DefaultThreadPool Threads;
+ for (unsigned I = 0; I < BlobCount; ++I) {
+ Threads.async(Producer, I, &Write1);
+ Threads.async(Producer, I, &Write2);
+ Threads.async(Consumer, I, &Read1);
+ Threads.async(Consumer, I, &Read2);
+ }
+
+ Threads.wait();
+}
+
+static void testBlobsParallel1(ObjectStore &CAS, uint64_t BlobSize) {
+ SCOPED_TRACE("testBlobsParallel1");
+ testBlobsParallel(CAS, CAS, CAS, CAS, BlobSize);
+}
+
+TEST_P(CASTest, BlobsParallel) {
+ std::shared_ptr<ObjectStore> CAS = createObjectStore();
+ uint64_t Size = 1ULL * 1024;
+ ASSERT_NO_FATAL_FAILURE(testBlobsParallel1(*CAS, Size));
+}
+
+#ifdef EXPENSIVE_CHECKS
+TEST_P(CASTest, BlobsBigParallel) {
+ std::shared_ptr<ObjectStore> CAS = createObjectStore();
+ // 100k is large enough to be standalone files in our on-disk cas.
+ uint64_t Size = 100ULL * 1024;
+ ASSERT_NO_FATAL_FAILURE(testBlobsParallel1(*CAS, Size));
+}
+#endif // EXPENSIVE_CHECKS
+#endif // LLVM_ENABLE_THREADS
diff --git a/llvm/unittests/CGData/StableFunctionMapTest.cpp b/llvm/unittests/CGData/StableFunctionMapTest.cpp
index d551ac8..5cf62ae 100644
--- a/llvm/unittests/CGData/StableFunctionMapTest.cpp
+++ b/llvm/unittests/CGData/StableFunctionMapTest.cpp
@@ -117,7 +117,7 @@ TEST(StableFunctionMap, Finalize3) {
Map.finalize();
auto &M = Map.getFunctionMap();
EXPECT_THAT(M, SizeIs(1));
- auto &FuncEntries = M.begin()->second;
+ auto &FuncEntries = M.begin()->second.Entries;
for (auto &FuncEntry : FuncEntries) {
EXPECT_THAT(*FuncEntry->IndexOperandHashMap, SizeIs(1));
ASSERT_THAT(*FuncEntry->IndexOperandHashMap,
diff --git a/llvm/unittests/CMakeLists.txt b/llvm/unittests/CMakeLists.txt
index 81abce5..d22613d 100644
--- a/llvm/unittests/CMakeLists.txt
+++ b/llvm/unittests/CMakeLists.txt
@@ -34,6 +34,7 @@ add_subdirectory(AsmParser)
add_subdirectory(BinaryFormat)
add_subdirectory(Bitcode)
add_subdirectory(Bitstream)
+add_subdirectory(CAS)
add_subdirectory(CGData)
add_subdirectory(CodeGen)
add_subdirectory(DebugInfo)
diff --git a/llvm/unittests/CodeGen/DroppedVariableStatsMIRTest.cpp b/llvm/unittests/CodeGen/DroppedVariableStatsMIRTest.cpp
index e72b4e4..c0cf4ff 100644
--- a/llvm/unittests/CodeGen/DroppedVariableStatsMIRTest.cpp
+++ b/llvm/unittests/CodeGen/DroppedVariableStatsMIRTest.cpp
@@ -158,8 +158,8 @@ frameInfo:
hasTailCall: false
isCalleeSavedInfoValid: false
localFrameSize: 0
- savePoint: ''
- restorePoint: ''
+ savePoint: []
+ restorePoint: []
fixedStack: []
stack: []
entry_values: []
@@ -307,8 +307,8 @@ frameInfo:
hasTailCall: false
isCalleeSavedInfoValid: false
localFrameSize: 0
- savePoint: ''
- restorePoint: ''
+ savePoint: []
+ restorePoint: []
fixedStack: []
stack: []
entry_values: []
@@ -450,8 +450,8 @@ frameInfo:
hasTailCall: false
isCalleeSavedInfoValid: false
localFrameSize: 0
- savePoint: ''
- restorePoint: ''
+ savePoint: []
+ restorePoint: []
fixedStack: []
stack: []
entry_values: []
@@ -593,8 +593,8 @@ frameInfo:
hasTailCall: false
isCalleeSavedInfoValid: false
localFrameSize: 0
- savePoint: ''
- restorePoint: ''
+ savePoint: []
+ restorePoint: []
fixedStack: []
stack: []
entry_values: []
@@ -738,8 +738,8 @@ frameInfo:
hasTailCall: false
isCalleeSavedInfoValid: false
localFrameSize: 0
- savePoint: ''
- restorePoint: ''
+ savePoint: []
+ restorePoint: []
fixedStack: []
stack: []
entry_values: []
@@ -883,8 +883,8 @@ frameInfo:
hasTailCall: false
isCalleeSavedInfoValid: false
localFrameSize: 0
- savePoint: ''
- restorePoint: ''
+ savePoint: []
+ restorePoint: []
fixedStack: []
stack: []
entry_values: []
@@ -1029,8 +1029,8 @@ frameInfo:
hasTailCall: false
isCalleeSavedInfoValid: false
localFrameSize: 0
- savePoint: ''
- restorePoint: ''
+ savePoint: []
+ restorePoint: []
fixedStack: []
stack: []
entry_values: []
diff --git a/llvm/unittests/CodeGen/GlobalISel/KnownBitsVectorTest.cpp b/llvm/unittests/CodeGen/GlobalISel/KnownBitsVectorTest.cpp
index 67e6d14..73ddf0c 100644
--- a/llvm/unittests/CodeGen/GlobalISel/KnownBitsVectorTest.cpp
+++ b/llvm/unittests/CodeGen/GlobalISel/KnownBitsVectorTest.cpp
@@ -1548,48 +1548,3 @@ TEST_F(AArch64GISelMITest, TestNumSignBitsUAddoOverflow) {
// Assert sign-extension from vector boolean
EXPECT_EQ(32u, Info.computeNumSignBits(CopyOverflow));
}
-
-TEST_F(AArch64GISelMITest, TestKnwonBitsUnmergeVectorScalar) {
- StringRef MIRString = R"(
- %copy_x0:_(<2 x s16>) = COPY $w0
- %maskf:_(s16) = G_CONSTANT i16 15
- %x0_x1:_(<2 x s16>) = G_BUILD_VECTOR %maskf, %maskf
- %and:_(<2 x s16>) = G_AND %copy_x0, %x0_x1
- %x0_0:_(s16), %x0_1:_(s16) = G_UNMERGE_VALUES %and
- %result:_(s16) = COPY %x0_0
-)";
-
- setUp(MIRString);
- if (!TM)
- GTEST_SKIP();
-
- Register CopyOverflow = Copies[Copies.size() - 1];
-
- GISelValueTracking Info(*MF);
-
- EXPECT_EQ(0xFFF0u, Info.getKnownBits(CopyOverflow).Zero.getZExtValue());
-}
-
-TEST_F(AArch64GISelMITest, TestKnwonBitsUnmergeVectorVector) {
- StringRef MIRString = R"(
- %copy_x0:_(<4 x s8>) = COPY $w0
- %maskff:_(s8) = G_CONSTANT i8 255
- %maskf:_(s8) = G_CONSTANT i8 15
- %x0_x1:_(<4 x s8>) = G_BUILD_VECTOR %maskf, %maskf, %maskff, %maskff
- %and:_(<4 x s8>) = G_AND %copy_x0, %x0_x1
- %x0_0:_(<2 x s8>), %x0_1:_(<2 x s8>) = G_UNMERGE_VALUES %and
- %result1:_(<2 x s8>) = COPY %x0_0
- %result2:_(<2 x s8>) = COPY %x0_1
-)";
-
- setUp(MIRString);
- if (!TM)
- GTEST_SKIP();
-
- GISelValueTracking Info(*MF);
-
- Register CopyOverflow1 = Copies[Copies.size() - 2];
- EXPECT_EQ(0xF0u, Info.getKnownBits(CopyOverflow1).Zero.getZExtValue());
- Register CopyOverflow2 = Copies[Copies.size() - 1];
- EXPECT_EQ(0x00u, Info.getKnownBits(CopyOverflow2).Zero.getZExtValue());
-}
diff --git a/llvm/unittests/CodeGen/TypeTraitsTest.cpp b/llvm/unittests/CodeGen/TypeTraitsTest.cpp
index 0ca4fa4..dde8628 100644
--- a/llvm/unittests/CodeGen/TypeTraitsTest.cpp
+++ b/llvm/unittests/CodeGen/TypeTraitsTest.cpp
@@ -16,7 +16,6 @@
using namespace llvm;
-#if __has_feature(is_trivially_copyable) || (defined(__GNUC__) && __GNUC__ >= 5)
static_assert(std::is_trivially_copyable_v<PressureChange>,
"trivially copyable");
static_assert(std::is_trivially_copyable_v<SDep>, "trivially copyable");
@@ -24,5 +23,3 @@ static_assert(std::is_trivially_copyable_v<SDValue>, "trivially copyable");
static_assert(std::is_trivially_copyable_v<SlotIndex>, "trivially copyable");
static_assert(std::is_trivially_copyable_v<IdentifyingPassPtr>,
"trivially copyable");
-#endif
-
diff --git a/llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp b/llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp
index 544c39a..78dc850 100644
--- a/llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp
+++ b/llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp
@@ -81,7 +81,7 @@ void checkElementProperties(LVReader *Reader) {
EXPECT_EQ(Language, LVSourceLanguage::DW_LANG_C_plus_plus_14);
EXPECT_EQ(Language.getName(), "DW_LANG_C_plus_plus_14");
- EXPECT_EQ(CompileUnit->lineCount(), 0u);
+ EXPECT_EQ(CompileUnit->lineCount(), 1u);
EXPECT_EQ(CompileUnit->scopeCount(), 1u);
EXPECT_EQ(CompileUnit->symbolCount(), 0u);
EXPECT_EQ(CompileUnit->typeCount(), 7u);
@@ -129,7 +129,7 @@ void checkElementProperties(LVReader *Reader) {
// Lines (debug and assembler) for 'foo'.
const LVLines *Lines = Function->getLines();
ASSERT_NE(Lines, nullptr);
- ASSERT_EQ(Lines->size(), 0x12u);
+ ASSERT_EQ(Lines->size(), 19u);
// Check size of types in CompileUnit.
const LVTypes *Types = CompileUnit->getTypes();
@@ -252,7 +252,7 @@ void checkElementComparison(LVReader *Reference, LVReader *Target) {
// Get comparison table.
LVPassTable PassTable = Compare.getPassTable();
- ASSERT_EQ(PassTable.size(), 5u);
+ ASSERT_EQ(PassTable.size(), 4u);
LVReader *Reader;
LVElement *Element;
@@ -278,18 +278,8 @@ void checkElementComparison(LVReader *Reference, LVReader *Target) {
EXPECT_EQ(Element->getName(), "INTEGER");
EXPECT_EQ(Pass, LVComparePass::Missing);
- // Reference: Missing DebugLine
- std::tie(Reader, Element, Pass) = PassTable[2];
- ASSERT_NE(Reader, nullptr);
- ASSERT_NE(Element, nullptr);
- EXPECT_EQ(Reader, Reference);
- EXPECT_EQ(Element->getLevel(), 3u);
- EXPECT_EQ(Element->getLineNumber(), 8u);
- EXPECT_EQ(Element->getName(), "");
- EXPECT_EQ(Pass, LVComparePass::Missing);
-
// Target: Added Variable 'CONSTANT'
- std::tie(Reader, Element, Pass) = PassTable[3];
+ std::tie(Reader, Element, Pass) = PassTable[2];
ASSERT_NE(Reader, nullptr);
ASSERT_NE(Element, nullptr);
EXPECT_EQ(Reader, Target);
@@ -299,7 +289,7 @@ void checkElementComparison(LVReader *Reference, LVReader *Target) {
EXPECT_EQ(Pass, LVComparePass::Added);
// Target: Added TypeDefinition 'INTEGER'
- std::tie(Reader, Element, Pass) = PassTable[4];
+ std::tie(Reader, Element, Pass) = PassTable[3];
ASSERT_NE(Reader, nullptr);
ASSERT_NE(Element, nullptr);
EXPECT_EQ(Reader, Target);
diff --git a/llvm/unittests/ExecutionEngine/Orc/ThreadSafeModuleTest.cpp b/llvm/unittests/ExecutionEngine/Orc/ThreadSafeModuleTest.cpp
index bbb9e8d..7db561c 100644
--- a/llvm/unittests/ExecutionEngine/Orc/ThreadSafeModuleTest.cpp
+++ b/llvm/unittests/ExecutionEngine/Orc/ThreadSafeModuleTest.cpp
@@ -31,15 +31,21 @@ const llvm::StringRef FooSrc = R"(
}
)";
-static ThreadSafeModule parseModule(llvm::StringRef Source,
- llvm::StringRef Name) {
- auto Ctx = std::make_unique<LLVMContext>();
+static std::unique_ptr<Module>
+parseModuleRaw(llvm::StringRef Source, llvm::StringRef Name, LLVMContext &Ctx) {
SMDiagnostic Err;
- auto M = parseIR(MemoryBufferRef(Source, Name), Err, *Ctx);
+ auto M = parseIR(MemoryBufferRef(Source, Name), Err, Ctx);
if (!M) {
Err.print("Testcase source failed to parse: ", errs());
exit(1);
}
+ return M;
+}
+
+static ThreadSafeModule parseModule(llvm::StringRef Source,
+ llvm::StringRef Name) {
+ auto Ctx = std::make_unique<LLVMContext>();
+ auto M = parseModuleRaw(Source, Name, *Ctx);
return ThreadSafeModule(std::move(M), std::move(Ctx));
}
@@ -128,6 +134,20 @@ TEST(ThreadSafeModuleTest, ConsumingModuleDo) {
TSM.consumingModuleDo([](std::unique_ptr<Module> M) {});
}
+TEST(ThreadSafeModuleTest, CloneExternalModuleToNewContext) {
+ auto Ctx = std::make_unique<LLVMContext>();
+ auto M = parseModuleRaw(FooSrc, "foo.ll", *Ctx);
+ auto TSCtx = ThreadSafeContext(std::make_unique<LLVMContext>());
+ auto TSM = cloneExternalModuleToContext(*M, TSCtx);
+ TSM.withModuleDo([&](Module &NewM) {
+ EXPECT_NE(&NewM.getContext(), Ctx.get());
+ TSCtx.withContextDo(
+ [&](LLVMContext *NewCtx) { EXPECT_EQ(&NewM.getContext(), NewCtx); });
+ EXPECT_FALSE(NewM.empty());
+ EXPECT_FALSE(verifyModule(NewM, &errs()));
+ });
+}
+
TEST(ThreadSafeModuleTest, CloneToNewContext) {
auto TSM1 = parseModule(FooSrc, "foo.ll");
auto TSM2 = cloneToNewContext(TSM1);
diff --git a/llvm/unittests/Frontend/HLSLBindingTest.cpp b/llvm/unittests/Frontend/HLSLBindingTest.cpp
index ca2f7b5..87106c2 100644
--- a/llvm/unittests/Frontend/HLSLBindingTest.cpp
+++ b/llvm/unittests/Frontend/HLSLBindingTest.cpp
@@ -273,3 +273,21 @@ TEST(HLSLBindingTest, TestFindAvailable) {
// In an empty space we find the slot at the beginning.
EXPECT_THAT(V, HasSpecificValue(0u));
}
+
+// Test that add duplicate bindings are correctly de-duplicated
+TEST(HLSLBindingTest, TestNoOverlapWithDuplicates) {
+ hlsl::BindingInfoBuilder Builder;
+
+ // We add the same binding three times, and just use `nullptr` for the cookie
+ // so that they should all be uniqued away.
+ Builder.trackBinding(ResourceClass::SRV, /*Space=*/0, /*LowerBound=*/5,
+ /*UpperBound=*/5, /*Cookie=*/nullptr);
+ Builder.trackBinding(ResourceClass::SRV, /*Space=*/0, /*LowerBound=*/5,
+ /*UpperBound=*/5, /*Cookie=*/nullptr);
+ Builder.trackBinding(ResourceClass::SRV, /*Space=*/0, /*LowerBound=*/5,
+ /*UpperBound=*/5, /*Cookie=*/nullptr);
+ bool HasOverlap;
+ hlsl::BindingInfo Info = Builder.calculateBindingInfo(HasOverlap);
+
+ EXPECT_FALSE(HasOverlap);
+}
diff --git a/llvm/unittests/Frontend/HLSLRootSignatureDumpTest.cpp b/llvm/unittests/Frontend/HLSLRootSignatureDumpTest.cpp
index 98b33fd..1eb03f1 100644
--- a/llvm/unittests/Frontend/HLSLRootSignatureDumpTest.cpp
+++ b/llvm/unittests/Frontend/HLSLRootSignatureDumpTest.cpp
@@ -10,12 +10,13 @@
#include "gtest/gtest.h"
using namespace llvm::hlsl::rootsig;
+using llvm::dxil::ResourceClass;
namespace {
TEST(HLSLRootSignatureTest, DescriptorCBVClauseDump) {
DescriptorTableClause Clause;
- Clause.Type = ClauseType::CBuffer;
+ Clause.Type = ResourceClass::CBuffer;
Clause.Reg = {RegisterType::BReg, 0};
Clause.setDefaultFlags(llvm::dxbc::RootSignatureVersion::V1_1);
@@ -32,7 +33,7 @@ TEST(HLSLRootSignatureTest, DescriptorCBVClauseDump) {
TEST(HLSLRootSignatureTest, DescriptorSRVClauseDump) {
DescriptorTableClause Clause;
- Clause.Type = ClauseType::SRV;
+ Clause.Type = ResourceClass::SRV;
Clause.Reg = {RegisterType::TReg, 0};
Clause.NumDescriptors = NumDescriptorsUnbounded;
Clause.Space = 42;
@@ -52,7 +53,7 @@ TEST(HLSLRootSignatureTest, DescriptorSRVClauseDump) {
TEST(HLSLRootSignatureTest, DescriptorUAVClauseDump) {
using llvm::dxbc::DescriptorRangeFlags;
DescriptorTableClause Clause;
- Clause.Type = ClauseType::UAV;
+ Clause.Type = ResourceClass::UAV;
Clause.Reg = {RegisterType::UReg, 92374};
Clause.NumDescriptors = 3298;
Clause.Space = 932847;
@@ -82,7 +83,7 @@ TEST(HLSLRootSignatureTest, DescriptorUAVClauseDump) {
TEST(HLSLRootSignatureTest, DescriptorSamplerClauseDump) {
DescriptorTableClause Clause;
- Clause.Type = ClauseType::Sampler;
+ Clause.Type = ResourceClass::Sampler;
Clause.Reg = {RegisterType::SReg, 0};
Clause.NumDescriptors = 2;
Clause.Space = 42;
@@ -102,7 +103,7 @@ TEST(HLSLRootSignatureTest, DescriptorSamplerClauseDump) {
TEST(HLSLRootSignatureTest, DescriptorCBVV10ClauseDump) {
DescriptorTableClause Clause;
- Clause.Type = ClauseType::CBuffer;
+ Clause.Type = ResourceClass::CBuffer;
Clause.Reg = {RegisterType::BReg, 0};
Clause.setDefaultFlags(llvm::dxbc::RootSignatureVersion::V1_0);
@@ -119,7 +120,7 @@ TEST(HLSLRootSignatureTest, DescriptorCBVV10ClauseDump) {
TEST(HLSLRootSignatureTest, DescriptorSamplerV10ClauseDump) {
DescriptorTableClause Clause;
- Clause.Type = ClauseType::Sampler;
+ Clause.Type = ResourceClass::Sampler;
Clause.Reg = {RegisterType::SReg, 0};
Clause.setDefaultFlags(llvm::dxbc::RootSignatureVersion::V1_0);
@@ -151,7 +152,7 @@ TEST(HLSLRootSignatureTest, DescriptorTableDump) {
TEST(HLSLRootSignatureTest, RootCBVDump) {
RootDescriptor Descriptor;
- Descriptor.Type = DescriptorType::CBuffer;
+ Descriptor.Type = ResourceClass::CBuffer;
Descriptor.Reg = {RegisterType::BReg, 0};
Descriptor.setDefaultFlags(llvm::dxbc::RootSignatureVersion::V1_1);
@@ -168,7 +169,7 @@ TEST(HLSLRootSignatureTest, RootCBVDump) {
TEST(HLSLRootSignatureTest, RootSRV10Dump) {
RootDescriptor Descriptor;
- Descriptor.Type = DescriptorType::SRV;
+ Descriptor.Type = ResourceClass::SRV;
Descriptor.Reg = {RegisterType::TReg, 0};
Descriptor.setDefaultFlags(llvm::dxbc::RootSignatureVersion::V1_0);
@@ -185,7 +186,7 @@ TEST(HLSLRootSignatureTest, RootSRV10Dump) {
TEST(HLSLRootSignatureTest, RootUAVV10Dump) {
RootDescriptor Descriptor;
- Descriptor.Type = DescriptorType::UAV;
+ Descriptor.Type = ResourceClass::UAV;
Descriptor.Reg = {RegisterType::UReg, 0};
Descriptor.setDefaultFlags(llvm::dxbc::RootSignatureVersion::V1_0);
@@ -202,7 +203,7 @@ TEST(HLSLRootSignatureTest, RootUAVV10Dump) {
TEST(HLSLRootSignatureTest, RootSRVDump) {
RootDescriptor Descriptor;
- Descriptor.Type = DescriptorType::SRV;
+ Descriptor.Type = ResourceClass::SRV;
Descriptor.Reg = {RegisterType::TReg, 0};
Descriptor.Space = 42;
Descriptor.Visibility = llvm::dxbc::ShaderVisibility::Geometry;
@@ -221,7 +222,7 @@ TEST(HLSLRootSignatureTest, RootSRVDump) {
TEST(HLSLRootSignatureTest, RootUAVDump) {
using llvm::dxbc::RootDescriptorFlags;
RootDescriptor Descriptor;
- Descriptor.Type = DescriptorType::UAV;
+ Descriptor.Type = ResourceClass::UAV;
Descriptor.Reg = {RegisterType::UReg, 92374};
Descriptor.Space = 932847;
Descriptor.Visibility = llvm::dxbc::ShaderVisibility::Hull;
diff --git a/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp b/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp
index b7a060b..c13570d 100644
--- a/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp
+++ b/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp
@@ -7852,4 +7852,28 @@ TEST_F(OpenMPIRBuilderTest, splitBB) {
EXPECT_TRUE(DL == AllocaBB->getTerminator()->getStableDebugLoc());
}
+TEST_F(OpenMPIRBuilderTest, spliceBBWithEmptyBB) {
+ OpenMPIRBuilder OMPBuilder(*M);
+ OMPBuilder.Config.IsTargetDevice = false;
+ OMPBuilder.initialize();
+ F->setName("func");
+ IRBuilder<> Builder(BB);
+
+ // Test calling spliceBB with an empty Block (but having trailing debug
+ // records).
+ DIBuilder DIB(*M);
+ DISubprogram *SP = F->getSubprogram();
+ DIType *VoidPtrTy =
+ DIB.createQualifiedType(dwarf::DW_TAG_pointer_type, nullptr);
+ DILocalVariable *Var = DIB.createParameterVariable(
+ SP, "test", /*ArgNo*/ 1, SP->getFile(), /*LineNo=*/0, VoidPtrTy);
+ DIB.insertDeclare(F->getArg(0), Var, DIB.createExpression(), DL,
+ Builder.GetInsertPoint());
+ BasicBlock *New = BasicBlock::Create(Ctx, "", F);
+ spliceBB(Builder.saveIP(), New, true, DL);
+ Instruction *Terminator = BB->getTerminator();
+ EXPECT_NE(Terminator, nullptr);
+ EXPECT_FALSE(Terminator->getDbgRecordRange().empty());
+}
+
} // namespace
diff --git a/llvm/unittests/IR/CMakeLists.txt b/llvm/unittests/IR/CMakeLists.txt
index b66eae9..8b7bd39 100644
--- a/llvm/unittests/IR/CMakeLists.txt
+++ b/llvm/unittests/IR/CMakeLists.txt
@@ -43,6 +43,7 @@ add_llvm_unittest(IRTests
PatternMatch.cpp
ShuffleVectorInstTest.cpp
StructuralHashTest.cpp
+ RuntimeLibcallsTest.cpp
TimePassesTest.cpp
TypesTest.cpp
UseTest.cpp
diff --git a/llvm/unittests/IR/ConstantRangeTest.cpp b/llvm/unittests/IR/ConstantRangeTest.cpp
index bcb5d49..53d581c 100644
--- a/llvm/unittests/IR/ConstantRangeTest.cpp
+++ b/llvm/unittests/IR/ConstantRangeTest.cpp
@@ -451,6 +451,65 @@ TEST_F(ConstantRangeTest, Trunc) {
EXPECT_EQ(SevenOne.truncate(2), ConstantRange(APInt(2, 3), APInt(2, 1)));
}
+TEST_F(ConstantRangeTest, TruncNuw) {
+ auto Range = [](unsigned NumBits, unsigned Lower, unsigned Upper) {
+ return ConstantRange(APInt(NumBits, Lower), APInt(NumBits, Upper));
+ };
+ // trunc([0, 4), 3->2) = full
+ EXPECT_TRUE(
+ Range(3, 0, 4).truncate(2, TruncInst::NoUnsignedWrap).isFullSet());
+ // trunc([0, 3), 3->2) = [0, 3)
+ EXPECT_EQ(Range(3, 0, 3).truncate(2, TruncInst::NoUnsignedWrap),
+ Range(2, 0, 3));
+ // trunc([1, 3), 3->2) = [1, 3)
+ EXPECT_EQ(Range(3, 1, 3).truncate(2, TruncInst::NoUnsignedWrap),
+ Range(2, 1, 3));
+ // trunc([1, 5), 3->2) = [1, 0)
+ EXPECT_EQ(Range(3, 1, 5).truncate(2, TruncInst::NoUnsignedWrap),
+ Range(2, 1, 0));
+ // trunc([4, 7), 3->2) = empty
+ EXPECT_TRUE(
+ Range(3, 4, 7).truncate(2, TruncInst::NoUnsignedWrap).isEmptySet());
+ // trunc([4, 0), 3->2) = empty
+ EXPECT_TRUE(
+ Range(3, 4, 0).truncate(2, TruncInst::NoUnsignedWrap).isEmptySet());
+ // trunc([4, 1), 3->2) = [0, 1)
+ EXPECT_EQ(Range(3, 4, 1).truncate(2, TruncInst::NoUnsignedWrap),
+ Range(2, 0, 1));
+ // trunc([3, 1), 3->2) = [3, 1)
+ EXPECT_EQ(Range(3, 3, 1).truncate(2, TruncInst::NoUnsignedWrap),
+ Range(2, 3, 1));
+ // trunc([3, 0), 3->2) = [3, 0)
+ EXPECT_EQ(Range(3, 3, 0).truncate(2, TruncInst::NoUnsignedWrap),
+ Range(2, 3, 0));
+ // trunc([1, 0), 2->1) = [1, 0)
+ EXPECT_EQ(Range(2, 1, 0).truncate(1, TruncInst::NoUnsignedWrap),
+ Range(1, 1, 0));
+ // trunc([2, 1), 2->1) = [0, 1)
+ EXPECT_EQ(Range(2, 2, 1).truncate(1, TruncInst::NoUnsignedWrap),
+ Range(1, 0, 1));
+}
+
+TEST_F(ConstantRangeTest, TruncNuwExhaustive) {
+ EnumerateConstantRanges(4, [&](const ConstantRange &CR) {
+ unsigned NumBits = 3;
+ ConstantRange Trunc = CR.truncate(NumBits, TruncInst::NoUnsignedWrap);
+ SmallBitVector Elems(1 << NumBits);
+ ForeachNumInConstantRange(CR, [&](const APInt &N) {
+ if (N.isIntN(NumBits))
+ Elems.set(N.getZExtValue());
+ });
+ TestRange(Trunc, Elems, PreferSmallest, {CR});
+ });
+ EnumerateConstantRanges(3, [&](const ConstantRange &CR) {
+ ConstantRange Trunc = CR.truncate(1, TruncInst::NoUnsignedWrap);
+ EXPECT_EQ(CR.contains(APInt::getZero(3)),
+ Trunc.contains(APInt::getZero(1)));
+ EXPECT_EQ(CR.contains(APInt::getOneBitSet(3, 0)),
+ Trunc.contains(APInt::getAllOnes(1)));
+ });
+}
+
TEST_F(ConstantRangeTest, ZExt) {
ConstantRange ZFull = Full.zeroExtend(20);
ConstantRange ZEmpty = Empty.zeroExtend(20);
diff --git a/llvm/unittests/IR/DebugInfoTest.cpp b/llvm/unittests/IR/DebugInfoTest.cpp
index 0065615..03333d5 100644
--- a/llvm/unittests/IR/DebugInfoTest.cpp
+++ b/llvm/unittests/IR/DebugInfoTest.cpp
@@ -553,17 +553,15 @@ TEST(DIBuilder, FixedPointType) {
EXPECT_TRUE(Ty->getTag() == dwarf::DW_TAG_base_type);
}
-TEST(DbgAssignIntrinsicTest, replaceVariableLocationOp) {
+TEST(DbgAssignRecordTest, replaceVariableLocationOp) {
LLVMContext C;
std::unique_ptr<Module> M = parseIR(C, R"(
define dso_local void @fun(i32 %v1, ptr %p1, ptr %p2) !dbg !7 {
entry:
- call void @llvm.dbg.assign(metadata i32 %v1, metadata !14, metadata !DIExpression(), metadata !17, metadata ptr %p1, metadata !DIExpression()), !dbg !16
+ #dbg_assign(i32 %v1, !14, !DIExpression(), !17, ptr %p1, !DIExpression(), !16)
ret void
}
- declare void @llvm.dbg.assign(metadata, metadata, metadata, metadata, metadata, metadata)
-
!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!3}
@@ -629,28 +627,28 @@ TEST(AssignmentTrackingTest, Utils) {
std::unique_ptr<Module> M = parseIR(C, R"(
define dso_local void @fun1() !dbg !7 {
entry:
- call void @llvm.dbg.assign(metadata i32 undef, metadata !10, metadata !DIExpression(), metadata !12, metadata i32 undef, metadata !DIExpression()), !dbg !13
+ #dbg_assign(i32 undef, !10, !DIExpression(), !12, i32 undef, !DIExpression(), !13)
%local = alloca i32, align 4, !DIAssignID !12
- call void @llvm.dbg.assign(metadata i32 undef, metadata !16, metadata !DIExpression(), metadata !12, metadata i32 undef, metadata !DIExpression()), !dbg !15
+ #dbg_assign(i32 undef, !16, !DIExpression(), !12, i32 undef, !DIExpression(), !15)
+ #dbg_assign(i32 undef, !16, !DIExpression(), !25, i32 undef, !DIExpression(), !15)
+ #dbg_assign(i32 undef, !16, !DIExpression(), !25, i32 undef, !DIExpression(), !15)
ret void, !dbg !15
}
define dso_local void @fun2() !dbg !17 {
entry:
%local = alloca i32, align 4, !DIAssignID !20
- call void @llvm.dbg.assign(metadata i32 undef, metadata !18, metadata !DIExpression(), metadata !20, metadata i32 undef, metadata !DIExpression()), !dbg !19
+ #dbg_assign(i32 undef, !18, !DIExpression(), !20, i32 undef, !DIExpression(), !19)
ret void, !dbg !19
}
define dso_local void @fun3() !dbg !21 {
entry:
%local = alloca i32, align 4, !DIAssignID !24
- call void @llvm.dbg.assign(metadata i32 undef, metadata !22, metadata !DIExpression(), metadata !24, metadata i32* undef, metadata !DIExpression()), !dbg !23
+ #dbg_assign(i32 undef, !22, !DIExpression(), !24, i32* undef, !DIExpression(), !23)
ret void
}
- declare void @llvm.dbg.assign(metadata, metadata, metadata, metadata, metadata, metadata)
-
!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!3, !4, !5}
!llvm.ident = !{!6}
@@ -680,6 +678,7 @@ TEST(AssignmentTrackingTest, Utils) {
!22 = !DILocalVariable(name: "local4", scope: !21, file: !1, line: 2, type: !11)
!23 = !DILocation(line: 4, column: 1, scope: !21)
!24 = distinct !DIAssignID()
+ !25 = distinct !DIAssignID()
)");
// Check the test IR isn't malformed.
diff --git a/llvm/unittests/IR/InstructionsTest.cpp b/llvm/unittests/IR/InstructionsTest.cpp
index fd8838e..21d4596 100644
--- a/llvm/unittests/IR/InstructionsTest.cpp
+++ b/llvm/unittests/IR/InstructionsTest.cpp
@@ -1935,5 +1935,22 @@ TEST(InstructionsTest, CmpPredicate) {
EXPECT_EQ(P2, R2);
}
+TEST(InstructionsTest, StripAndAccumulateConstantOffset) {
+ LLVMContext C;
+ DataLayout DL;
+ std::unique_ptr<Module> M = parseIR(C, R"(
+ define void @foo(ptr %ptr, i64 %offset) {
+ %gep = getelementptr inbounds [1 x i8], ptr %ptr, i64 4, i64 %offset
+ ret void
+ })");
+ ASSERT_TRUE(M);
+ Value *GEP = &M->getFunction("foo")->getEntryBlock().front();
+ APInt Offset(DL.getIndexTypeSizeInBits(GEP->getType()), 0);
+ Value *Stripped = GEP->stripAndAccumulateConstantOffsets(
+ DL, Offset, /*AllowNonInBounds=*/true);
+ EXPECT_EQ(Stripped, GEP);
+ EXPECT_TRUE(Offset.isZero());
+}
+
} // end anonymous namespace
} // end namespace llvm
diff --git a/llvm/unittests/IR/PatternMatch.cpp b/llvm/unittests/IR/PatternMatch.cpp
index bb7cc080..972dac8 100644
--- a/llvm/unittests/IR/PatternMatch.cpp
+++ b/llvm/unittests/IR/PatternMatch.cpp
@@ -2621,4 +2621,40 @@ TEST_F(PatternMatchTest, PtrAdd) {
EXPECT_FALSE(match(OtherGEP, m_PtrAdd(m_Value(A), m_Value(B))));
}
+TEST_F(PatternMatchTest, ShiftOrSelf) {
+ Type *I64Ty = Type::getInt64Ty(Ctx);
+ Constant *LHS = ConstantInt::get(I64Ty, 7);
+ Constant *ShAmt = ConstantInt::get(I64Ty, 16);
+ Value *Shl = IRB.CreateShl(LHS, ShAmt);
+ Value *LShr = IRB.CreateLShr(LHS, ShAmt);
+ Value *AShr = IRB.CreateAShr(LHS, ShAmt);
+ Value *Add = IRB.CreateAdd(LHS, LHS);
+
+ uint64_t ShAmtC;
+ Value *A;
+ EXPECT_TRUE(match(Shl, m_ShlOrSelf(m_Value(A), ShAmtC)));
+ EXPECT_EQ(A, LHS);
+ EXPECT_EQ(ShAmtC, 16U);
+
+ EXPECT_TRUE(match(Add, m_ShlOrSelf(m_Value(A), ShAmtC)));
+ EXPECT_EQ(A, Add);
+ EXPECT_EQ(ShAmtC, 0U);
+
+ EXPECT_TRUE(match(LShr, m_LShrOrSelf(m_Value(A), ShAmtC)));
+ EXPECT_EQ(A, LHS);
+ EXPECT_EQ(ShAmtC, 16U);
+
+ EXPECT_TRUE(match(Add, m_LShrOrSelf(m_Value(A), ShAmtC)));
+ EXPECT_EQ(A, Add);
+ EXPECT_EQ(ShAmtC, 0U);
+
+ EXPECT_TRUE(match(AShr, m_AShrOrSelf(m_Value(A), ShAmtC)));
+ EXPECT_EQ(A, LHS);
+ EXPECT_EQ(ShAmtC, 16U);
+
+ EXPECT_TRUE(match(Add, m_AShrOrSelf(m_Value(A), ShAmtC)));
+ EXPECT_EQ(A, Add);
+ EXPECT_EQ(ShAmtC, 0U);
+}
+
} // anonymous namespace.
diff --git a/llvm/unittests/IR/RuntimeLibcallsTest.cpp b/llvm/unittests/IR/RuntimeLibcallsTest.cpp
new file mode 100644
index 0000000..0123168
--- /dev/null
+++ b/llvm/unittests/IR/RuntimeLibcallsTest.cpp
@@ -0,0 +1,63 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/IR/RuntimeLibcalls.h"
+#include "llvm/ADT/STLExtras.h"
+#include "gtest/gtest.h"
+using namespace llvm;
+
+namespace {
+
+TEST(RuntimeLibcallsTest, LibcallImplByName) {
+ EXPECT_TRUE(RTLIB::RuntimeLibcallsInfo::lookupLibcallImplName("").empty());
+ EXPECT_TRUE(
+ RTLIB::RuntimeLibcallsInfo::lookupLibcallImplName("unknown").empty());
+ EXPECT_TRUE(
+ RTLIB::RuntimeLibcallsInfo::lookupLibcallImplName("Unsupported").empty());
+ EXPECT_TRUE(
+ RTLIB::RuntimeLibcallsInfo::lookupLibcallImplName("unsupported").empty());
+
+ for (RTLIB::LibcallImpl LC : RTLIB::libcall_impls()) {
+ StringRef Name = RTLIB::RuntimeLibcallsInfo::getLibcallImplName(LC);
+ EXPECT_TRUE(is_contained(
+ RTLIB::RuntimeLibcallsInfo::lookupLibcallImplName(Name), LC));
+ }
+
+ // Test first libcall name
+ EXPECT_EQ(
+ RTLIB::arm64ec__Unwind_Resume,
+ *RTLIB::RuntimeLibcallsInfo::lookupLibcallImplName("#_Unwind_Resume")
+ .begin());
+ // Test longest libcall names
+ EXPECT_EQ(RTLIB::__hexagon_memcpy_likely_aligned_min32bytes_mult8bytes,
+ *RTLIB::RuntimeLibcallsInfo::lookupLibcallImplName(
+ "__hexagon_memcpy_likely_aligned_min32bytes_mult8bytes")
+ .begin());
+
+ {
+ auto SquirtleSquad =
+ RTLIB::RuntimeLibcallsInfo::lookupLibcallImplName("sqrtl");
+ ASSERT_EQ(size(SquirtleSquad), 3);
+ auto I = SquirtleSquad.begin();
+ EXPECT_EQ(*I++, RTLIB::sqrt_f128);
+ EXPECT_EQ(*I++, RTLIB::sqrt_f80);
+ EXPECT_EQ(*I++, RTLIB::sqrt_ppcf128);
+ }
+
+ // Last libcall
+ {
+ auto Truncs = RTLIB::RuntimeLibcallsInfo::lookupLibcallImplName("truncl");
+ ASSERT_EQ(size(Truncs), 3);
+ auto I = Truncs.begin();
+ EXPECT_EQ(*I++, RTLIB::trunc_f128);
+ EXPECT_EQ(*I++, RTLIB::trunc_f80);
+ EXPECT_EQ(*I++, RTLIB::trunc_ppcf128);
+ }
+}
+
+} // namespace
diff --git a/llvm/unittests/Object/ELFObjectFileTest.cpp b/llvm/unittests/Object/ELFObjectFileTest.cpp
index 25b3907..17d9f50 100644
--- a/llvm/unittests/Object/ELFObjectFileTest.cpp
+++ b/llvm/unittests/Object/ELFObjectFileTest.cpp
@@ -680,7 +680,7 @@ Sections:
- AddressOffset: 0x0
Size: 0x1
Metadata: 0x2
- CallsiteOffsets: [ 0x1 ]
+ CallsiteEndOffsets: [ 0x1 ]
)";
{
@@ -713,7 +713,7 @@ Sections:
AddressOffset: 0x0
Size: 0x1
Metadata: 0x2
- CallsiteOffsets: [ 0x1 , 0x1 ]
+ CallsiteEndOffsets: [ 0x1 , 0x1 ]
- Name: .llvm_bb_addr_map_2
Type: SHT_LLVM_BB_ADDR_MAP
Link: 1
diff --git a/llvm/unittests/ObjectYAML/DXContainerYAMLTest.cpp b/llvm/unittests/ObjectYAML/DXContainerYAMLTest.cpp
index 9e6f7cc..4cf8f61 100644
--- a/llvm/unittests/ObjectYAML/DXContainerYAMLTest.cpp
+++ b/llvm/unittests/ObjectYAML/DXContainerYAMLTest.cpp
@@ -130,7 +130,7 @@ TEST(RootSignature, ParseRootFlags) {
NumRootParameters: 0
RootParametersOffset: 24
NumStaticSamplers: 0
- StaticSamplersOffset: 0
+ StaticSamplersOffset: 24
Parameters: []
AllowInputAssemblerInputLayout: true
)"));
@@ -141,7 +141,7 @@ TEST(RootSignature, ParseRootFlags) {
0x44, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
0x52, 0x54, 0x53, 0x30, 0x18, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
};
EXPECT_EQ(Storage.size(), 68u);
@@ -168,9 +168,9 @@ TEST(RootSignature, HeaderData) {
RootSignature:
Version: 2
NumRootParameters: 1
- RootParametersOffset: 255
+ RootParametersOffset: 24
NumStaticSamplers: 0
- StaticSamplersOffset: 0
+ StaticSamplersOffset: 48
Parameters:
- ParameterType: 1
ShaderVisibility: 2
@@ -187,8 +187,8 @@ TEST(RootSignature, HeaderData) {
0x05, 0x39, 0xe1, 0xfe, 0x31, 0x20, 0xf0, 0xc1, 0x01, 0x00, 0x00, 0x00,
0x85, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
0x52, 0x54, 0x53, 0x30, 0x59, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
0x0e, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -220,9 +220,9 @@ TEST(RootSignature, ParseRootConstants) {
RootSignature:
Version: 2
NumRootParameters: 1
- RootParametersOffset: 36
+ RootParametersOffset: 24
NumStaticSamplers: 0
- StaticSamplersOffset: 0
+ StaticSamplersOffset: 48
Parameters:
- ParameterType: 1
ShaderVisibility: 2
@@ -239,8 +239,8 @@ TEST(RootSignature, ParseRootConstants) {
0x05, 0x39, 0xe1, 0xfe, 0x31, 0x20, 0xf0, 0xc1, 0x01, 0x00, 0x00, 0x00,
0x85, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
0x52, 0x54, 0x53, 0x30, 0x59, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
0x0e, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -274,7 +274,7 @@ TEST(RootSignature, ParseRootDescriptorsV10) {
NumRootParameters: 1
RootParametersOffset: 24
NumStaticSamplers: 0
- StaticSamplersOffset: 60
+ StaticSamplersOffset: 44
Parameters:
- ParameterType: 2 # SRV
ShaderVisibility: 3 # Domain
@@ -291,7 +291,7 @@ TEST(RootSignature, ParseRootDescriptorsV10) {
0x85, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
0x52, 0x54, 0x53, 0x30, 0x59, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3c, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x2c, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -325,7 +325,7 @@ TEST(RootSignature, ParseRootDescriptorsV11) {
NumRootParameters: 1
RootParametersOffset: 24
NumStaticSamplers: 0
- StaticSamplersOffset: 60
+ StaticSamplersOffset: 48
Parameters:
- ParameterType: 2 # SRV
ShaderVisibility: 3 # Domain
@@ -343,7 +343,7 @@ TEST(RootSignature, ParseRootDescriptorsV11) {
0x85, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
0x52, 0x54, 0x53, 0x30, 0x59, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3c, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -377,7 +377,7 @@ TEST(RootSignature, ParseDescriptorTableV10) {
NumRootParameters: 1
RootParametersOffset: 24
NumStaticSamplers: 0
- StaticSamplersOffset: 60
+ StaticSamplersOffset: 64
Parameters:
- ParameterType: 0 # SRV
ShaderVisibility: 3 # Domain
@@ -399,7 +399,7 @@ TEST(RootSignature, ParseDescriptorTableV10) {
0x85, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
0x52, 0x54, 0x53, 0x30, 0x59, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3c, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x40, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00,
0x2a, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00,
@@ -433,7 +433,7 @@ TEST(RootSignature, ParseDescriptorTableV11) {
NumRootParameters: 1
RootParametersOffset: 24
NumStaticSamplers: 0
- StaticSamplersOffset: 60
+ StaticSamplersOffset: 68
Parameters:
- ParameterType: 0 # Descriptor Table
ShaderVisibility: 3 # Domain
@@ -456,7 +456,7 @@ TEST(RootSignature, ParseDescriptorTableV11) {
0x85, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
0x52, 0x54, 0x53, 0x30, 0x59, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3c, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x44, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x2a, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
@@ -487,7 +487,7 @@ Parts:
RootSignature:
Version: 2
NumRootParameters: 0
- RootParametersOffset: 0
+ RootParametersOffset: 24
NumStaticSamplers: 1
StaticSamplersOffset: 24
Parameters: []
@@ -516,7 +516,7 @@ Parts:
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x52, 0x54, 0x53, 0x30, 0x4c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x18, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
0xa4, 0x70, 0x9d, 0x3f, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
diff --git a/llvm/unittests/Support/AlignOfTest.cpp b/llvm/unittests/Support/AlignOfTest.cpp
index f84895c..979f2cf 100644
--- a/llvm/unittests/Support/AlignOfTest.cpp
+++ b/llvm/unittests/Support/AlignOfTest.cpp
@@ -30,7 +30,7 @@ namespace {
#ifdef __clang__
#pragma clang diagnostic ignored "-Wunknown-pragmas"
#pragma clang diagnostic ignored "-Winaccessible-base"
-#elif ((__GNUC__ * 100) + __GNUC_MINOR__) >= 402
+#elif defined(__GNUC__)
// Pragma based warning suppression was introduced in GGC 4.2. Additionally
// this warning is "enabled by default". The warning still appears if -Wall is
// suppressed. Apparently GCC suppresses it when -w is specifed, which is odd.
diff --git a/llvm/unittests/Support/CMakeLists.txt b/llvm/unittests/Support/CMakeLists.txt
index 868c40b..89edfb3 100644
--- a/llvm/unittests/Support/CMakeLists.txt
+++ b/llvm/unittests/Support/CMakeLists.txt
@@ -111,6 +111,7 @@ add_llvm_unittest(SupportTests
formatted_raw_ostream_test.cpp
raw_fd_stream_test.cpp
raw_ostream_test.cpp
+ raw_ostream_proxy_test.cpp
raw_pwrite_stream_test.cpp
raw_sha1_ostream_test.cpp
raw_socket_stream_test.cpp
diff --git a/llvm/unittests/Support/DebugLogTest.cpp b/llvm/unittests/Support/DebugLogTest.cpp
index b28c59c..e087705 100644
--- a/llvm/unittests/Support/DebugLogTest.cpp
+++ b/llvm/unittests/Support/DebugLogTest.cpp
@@ -115,8 +115,18 @@ TEST(DebugLogTest, StreamPrefix) {
ldbg_osA << "5";
EXPECT_EQ(os.str(), expected);
}
- // After destructors, there was a pending newline for stream B.
- EXPECT_EQ(os.str(), expected + "PrefixB ");
+ EXPECT_EQ(os.str(), expected);
+}
+
+TEST(DebugLogTest, DestructorPrefix) {
+ llvm::DebugFlag = true;
+ std::string str;
+ raw_string_ostream os(str);
+ {
+ llvm::impl::raw_ldbg_ostream ldbg_osB("PrefixB ", os);
+ }
+ // After destructors, nothing should have been printed.
+ EXPECT_EQ(os.str(), "");
}
#else
TEST(DebugLogTest, Basic) {
diff --git a/llvm/unittests/Support/DebugTest.cpp b/llvm/unittests/Support/DebugTest.cpp
index e8b7548..ed8bfc6 100644
--- a/llvm/unittests/Support/DebugTest.cpp
+++ b/llvm/unittests/Support/DebugTest.cpp
@@ -50,4 +50,46 @@ TEST(DebugTest, CommaInDebugBlock) {
});
EXPECT_EQ("ZYX", os1.str());
}
+
+TEST(DebugTest, DebugWithType) {
+ llvm::DebugFlag = true;
+
+ // Check if the DEBUG_WITH_TYPE macro is enabled for the given type.
+ auto CheckDebugWithType = [](const char *Type) {
+ bool Visited = false;
+ DEBUG_WITH_TYPE(Type, { Visited = true; });
+ return Visited;
+ };
+
+ {
+ static const char *DT[] = {"A", "B"};
+ setCurrentDebugTypes(DT, sizeof(DT) / sizeof(DT[0]));
+ EXPECT_TRUE(CheckDebugWithType("A"));
+ EXPECT_TRUE(CheckDebugWithType("B"));
+ EXPECT_FALSE(CheckDebugWithType("C"));
+ }
+ {
+ static const char *DT[] = {"A:"};
+ setCurrentDebugTypes(DT, sizeof(DT) / sizeof(DT[0]));
+ EXPECT_FALSE(CheckDebugWithType("A"));
+ EXPECT_TRUE(CheckDebugWithType("B"));
+ EXPECT_TRUE(CheckDebugWithType("C"));
+ }
+ {
+ static const char *DT[] = {"A:", "B"};
+ setCurrentDebugTypes(DT, sizeof(DT) / sizeof(DT[0]));
+ EXPECT_FALSE(CheckDebugWithType("A"));
+ EXPECT_TRUE(CheckDebugWithType("B"));
+ EXPECT_FALSE(CheckDebugWithType("C"));
+ }
+ {
+ static const char *DT[] = {"A:3", "B:", "C"};
+ setCurrentDebugTypes(DT, sizeof(DT) / sizeof(DT[0]));
+ EXPECT_TRUE(CheckDebugWithType("A"));
+ EXPECT_FALSE(isCurrentDebugType("A", 4));
+ EXPECT_FALSE(CheckDebugWithType("B"));
+ EXPECT_TRUE(isCurrentDebugType("C", 10));
+ EXPECT_FALSE(CheckDebugWithType("D"));
+ }
+}
#endif
diff --git a/llvm/unittests/Support/DynamicLibrary/CMakeLists.txt b/llvm/unittests/Support/DynamicLibrary/CMakeLists.txt
index 2366209..98b7f2d 100644
--- a/llvm/unittests/Support/DynamicLibrary/CMakeLists.txt
+++ b/llvm/unittests/Support/DynamicLibrary/CMakeLists.txt
@@ -16,7 +16,7 @@ set_output_directory(DynamicLibraryLib
)
# FIXME: Find out why AIX fails with new DynamicLibrary symbols behavior.
-if(${CMAKE_SYSTEM_NAME} MATCHES "AIX")
+if("${CMAKE_SYSTEM_NAME}" MATCHES "AIX")
add_llvm_unittest(DynamicLibraryTests
DynamicLibraryTest.cpp
)
@@ -28,7 +28,7 @@ else()
)
endif()
target_link_libraries(DynamicLibraryTests PRIVATE DynamicLibraryLib)
-if(${CMAKE_SYSTEM_NAME} MATCHES "AIX")
+if("${CMAKE_SYSTEM_NAME}" MATCHES "AIX")
export_executable_symbols(DynamicLibraryTests)
endif()
@@ -64,7 +64,7 @@ endfunction(dynlib_add_module)
# Revert -Wl,-z,nodelete on this test since it relies on the file
# being unloaded.
-if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+if("${CMAKE_SYSTEM_NAME}" MATCHES "Linux")
string(REPLACE "-Wl,-z,nodelete" "" CMAKE_MODULE_LINKER_FLAGS
${CMAKE_MODULE_LINKER_FLAGS})
endif()
diff --git a/llvm/unittests/Support/Path.cpp b/llvm/unittests/Support/Path.cpp
index 355aa6b..888729b 100644
--- a/llvm/unittests/Support/Path.cpp
+++ b/llvm/unittests/Support/Path.cpp
@@ -1471,6 +1471,43 @@ TEST_F(FileSystemTest, FileMapping) {
ASSERT_NO_ERROR(fs::remove(TempPath));
}
+TEST_F(FileSystemTest, FileMappingSync) {
+ // Create a temp file.
+ SmallString<0> TempPath(TestDirectory);
+ sys::path::append(TempPath, "test-%%%%");
+ auto TempFileOrError = fs::TempFile::create(TempPath);
+ ASSERT_TRUE((bool)TempFileOrError);
+ fs::TempFile File = std::move(*TempFileOrError);
+ StringRef Content("hello there");
+ std::string FileName = File.TmpName;
+ ASSERT_NO_ERROR(
+ fs::resize_file_before_mapping_readwrite(File.FD, Content.size()));
+ {
+ // Map in the file and write some content.
+ std::error_code EC;
+ fs::mapped_file_region MFR(fs::convertFDToNativeFile(File.FD),
+ fs::mapped_file_region::readwrite,
+ Content.size(), 0, EC);
+
+ // Keep the file so it can be read.
+ ASSERT_FALSE((bool)File.keep());
+
+ // Write content through mapped memory.
+ ASSERT_NO_ERROR(EC);
+ std::copy(Content.begin(), Content.end(), MFR.data());
+
+ // Synchronize to file system.
+ ASSERT_FALSE((bool)MFR.sync());
+
+ // Check the file content using file IO APIs.
+ auto Buffer = MemoryBuffer::getFile(FileName);
+ ASSERT_TRUE((bool)Buffer);
+ ASSERT_EQ(Content, Buffer->get()->getBuffer());
+ }
+ // Manually remove the test file.
+ ASSERT_FALSE((bool)fs::remove(FileName));
+}
+
TEST(Support, NormalizePath) {
// Input, Expected Win, Expected Posix
using TestTuple = std::tuple<const char *, const char *, const char *>;
diff --git a/llvm/unittests/Support/ProgramTest.cpp b/llvm/unittests/Support/ProgramTest.cpp
index 693b53b..d30bf45 100644
--- a/llvm/unittests/Support/ProgramTest.cpp
+++ b/llvm/unittests/Support/ProgramTest.cpp
@@ -10,6 +10,7 @@
#include "llvm/Config/llvm-config.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ConvertUTF.h"
+#include "llvm/Support/ExponentialBackoff.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Signals.h"
@@ -573,6 +574,88 @@ TEST_F(ProgramEnvTest, TestLockFile) {
sys::fs::remove(LockedFile);
}
+TEST_F(ProgramEnvTest, TestLockFileExclusive) {
+ using namespace llvm::sys;
+ using namespace std::chrono_literals;
+
+ if (const char *LockedFile = getenv("LLVM_PROGRAM_TEST_LOCKED_FILE")) {
+ // Child process.
+ int FD2;
+ ASSERT_NO_ERROR(fs::openFileForReadWrite(LockedFile, FD2,
+ fs::CD_OpenExisting, fs::OF_None));
+
+ // File should currently be non-exclusive locked by the main process, thus
+ // trying to acquire exclusive lock will fail and trying to acquire
+ // non-exclusive will succeed.
+ EXPECT_TRUE(
+ fs::tryLockFile(FD2, std::chrono::seconds(0), fs::LockKind::Exclusive));
+
+ EXPECT_FALSE(
+ fs::tryLockFile(FD2, std::chrono::seconds(0), fs::LockKind::Shared));
+
+ close(FD2);
+ // Write a file to indicate just finished.
+ std::string FinishFile = std::string(LockedFile) + "-finished";
+ int FD3;
+ ASSERT_NO_ERROR(fs::openFileForReadWrite(FinishFile, FD3, fs::CD_CreateNew,
+ fs::OF_None));
+ close(FD3);
+ exit(0);
+ }
+
+ // Create file that will be locked.
+ SmallString<64> LockedFile;
+ int FD1;
+ ASSERT_NO_ERROR(
+ fs::createUniqueDirectory("TestLockFileExclusive", LockedFile));
+ sys::path::append(LockedFile, "file");
+ ASSERT_NO_ERROR(
+ fs::openFileForReadWrite(LockedFile, FD1, fs::CD_CreateNew, fs::OF_None));
+
+ std::string Executable =
+ sys::fs::getMainExecutable(TestMainArgv0, &ProgramTestStringArg1);
+ StringRef argv[] = {Executable,
+ "--gtest_filter=ProgramEnvTest.TestLockFileExclusive"};
+
+ // Add LLVM_PROGRAM_TEST_LOCKED_FILE to the environment of the child.
+ std::string EnvVar = "LLVM_PROGRAM_TEST_LOCKED_FILE=";
+ EnvVar += LockedFile.str();
+ addEnvVar(EnvVar);
+
+ // Lock the file.
+ ASSERT_NO_ERROR(
+ fs::tryLockFile(FD1, std::chrono::seconds(0), fs::LockKind::Exclusive));
+
+ std::string Error;
+ bool ExecutionFailed;
+ ProcessInfo PI2 = ExecuteNoWait(Executable, argv, getEnviron(), {}, 0, &Error,
+ &ExecutionFailed);
+ ASSERT_FALSE(ExecutionFailed) << Error;
+ ASSERT_TRUE(Error.empty());
+ ASSERT_NE(PI2.Pid, ProcessInfo::InvalidPid) << "Invalid process id";
+
+ std::string FinishFile = std::string(LockedFile) + "-finished";
+ // Wait till child process writes the file to indicate the job finished.
+ bool Finished = false;
+ ExponentialBackoff Backoff(5s); // timeout 5s.
+ do {
+ if (fs::exists(FinishFile)) {
+ Finished = true;
+ break;
+ }
+ } while (Backoff.waitForNextAttempt());
+
+ ASSERT_TRUE(Finished);
+ ASSERT_NO_ERROR(fs::unlockFile(FD1));
+ ProcessInfo WaitResult = llvm::sys::Wait(PI2, /*SecondsToWait=*/1, &Error);
+ ASSERT_TRUE(Error.empty());
+ ASSERT_EQ(0, WaitResult.ReturnCode);
+ ASSERT_EQ(WaitResult.Pid, PI2.Pid);
+ sys::fs::remove(LockedFile);
+ sys::fs::remove(FinishFile);
+ sys::fs::remove_directories(sys::path::parent_path(LockedFile));
+}
+
TEST_F(ProgramEnvTest, TestExecuteWithNoStacktraceHandler) {
using namespace llvm::sys;
diff --git a/llvm/unittests/Support/ThreadPool.cpp b/llvm/unittests/Support/ThreadPool.cpp
index 8dca182..aa7f874 100644
--- a/llvm/unittests/Support/ThreadPool.cpp
+++ b/llvm/unittests/Support/ThreadPool.cpp
@@ -140,7 +140,7 @@ TYPED_TEST(ThreadPoolTest, AsyncBarrier) {
std::atomic_int checked_in{0};
- DefaultThreadPool Pool;
+ TypeParam Pool;
for (size_t i = 0; i < 5; ++i) {
Pool.async([this, &checked_in] {
this->waitForMainThread();
@@ -453,15 +453,19 @@ TYPED_TEST(ThreadPoolTest, AffinityMask) {
[](auto &T) { return T.getData().front() < 16UL; }) &&
"Threads ran on more CPUs than expected! The affinity mask does not "
"seem to work.");
- GTEST_SKIP();
+ return;
}
std::string Executable =
sys::fs::getMainExecutable(TestMainArgv0, &ThreadPoolTestStringArg1);
- StringRef argv[] = {Executable, "--gtest_filter=ThreadPoolTest.AffinityMask"};
+ const auto *TestInfo = testing::UnitTest::GetInstance()->current_test_info();
+ std::string Arg = (Twine("--gtest_filter=") + TestInfo->test_suite_name() +
+ "." + TestInfo->name())
+ .str();
+ StringRef argv[] = {Executable, Arg};
// Add environment variable to the environment of the child process.
int Res = setenv("LLVM_THREADPOOL_AFFINITYMASK", "1", false);
- ASSERT_EQ(Res, 0);
+ ASSERT_EQ(0, Res);
std::string Error;
bool ExecutionFailed;
@@ -470,6 +474,8 @@ TYPED_TEST(ThreadPoolTest, AffinityMask) {
Affinity.set(0, 4); // Use CPUs 0,1,2,3.
int Ret = sys::ExecuteAndWait(Executable, argv, {}, {}, 0, 0, &Error,
&ExecutionFailed, nullptr, &Affinity);
+ Res = setenv("LLVM_THREADPOOL_AFFINITYMASK", "", false);
+ ASSERT_EQ(0, Res);
ASSERT_EQ(0, Ret);
}
diff --git a/llvm/unittests/Support/raw_ostream_proxy_test.cpp b/llvm/unittests/Support/raw_ostream_proxy_test.cpp
new file mode 100644
index 0000000..864dda7
--- /dev/null
+++ b/llvm/unittests/Support/raw_ostream_proxy_test.cpp
@@ -0,0 +1,225 @@
+//===- raw_ostream_proxy_test.cpp - Tests for raw ostream proxies ---------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/raw_ostream_proxy.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+
+/// Naive version of raw_svector_ostream that is buffered (by default) and
+/// doesn't support pwrite.
+class BufferedNoPwriteSmallVectorStream : public raw_ostream {
+public:
+ // Choose a strange buffer size to ensure it doesn't collide with the default
+ // on \a raw_ostream.
+ static constexpr size_t PreferredBufferSize = 63;
+
+ size_t preferred_buffer_size() const override { return PreferredBufferSize; }
+ uint64_t current_pos() const override { return Vector.size(); }
+ void write_impl(const char *Ptr, size_t Size) override {
+ Vector.append(Ptr, Ptr + Size);
+ }
+
+ bool is_displayed() const override { return IsDisplayed; }
+
+ explicit BufferedNoPwriteSmallVectorStream(SmallVectorImpl<char> &Vector)
+ : Vector(Vector) {}
+ ~BufferedNoPwriteSmallVectorStream() override { flush(); }
+
+ SmallVectorImpl<char> &Vector;
+ bool IsDisplayed = false;
+};
+
+constexpr size_t BufferedNoPwriteSmallVectorStream::PreferredBufferSize;
+
+TEST(raw_ostream_proxyTest, write) {
+ // Besides confirming that "write" works, this test confirms that the proxy
+ // takes on the buffer from the stream it's proxying, such that writes to the
+ // proxy are flushed to the underlying stream as if no proxy were present.
+ SmallString<128> Dest;
+ {
+ // Confirm that BufferedNoPwriteSmallVectorStream is buffered by default,
+ // and that setting up a proxy effectively transfers a buffer of the same
+ // size to the proxy.
+ BufferedNoPwriteSmallVectorStream DestOS(Dest);
+ EXPECT_EQ(BufferedNoPwriteSmallVectorStream::PreferredBufferSize,
+ DestOS.GetBufferSize());
+ raw_ostream_proxy ProxyOS(DestOS);
+ EXPECT_EQ(0u, DestOS.GetBufferSize());
+ EXPECT_EQ(BufferedNoPwriteSmallVectorStream::PreferredBufferSize,
+ ProxyOS.GetBufferSize());
+
+ // Flushing should send through to Dest.
+ ProxyOS << "abcd";
+ EXPECT_EQ("", Dest);
+ ProxyOS.flush();
+ EXPECT_EQ("abcd", Dest);
+
+ // Buffer should still work.
+ ProxyOS << "e";
+ EXPECT_EQ("abcd", Dest);
+ }
+
+ // Destructing ProxyOS should flush (and not crash).
+ EXPECT_EQ("abcde", Dest);
+
+ {
+ // Set up another stream, this time unbuffered.
+ BufferedNoPwriteSmallVectorStream DestOS(Dest);
+ DestOS.SetUnbuffered();
+ EXPECT_EQ(0u, DestOS.GetBufferSize());
+ raw_ostream_proxy ProxyOS(DestOS);
+ EXPECT_EQ(0u, DestOS.GetBufferSize());
+ EXPECT_EQ(0u, ProxyOS.GetBufferSize());
+
+ // Flushing should not be required.
+ ProxyOS << "f";
+ EXPECT_EQ("abcdef", Dest);
+ }
+ EXPECT_EQ("abcdef", Dest);
+}
+
+TEST(raw_ostream_proxyTest, pwrite) {
+ // This test confirms that the proxy takes on the buffer from the stream it's
+ // proxying, such that writes to the proxy are flushed to the underlying
+ // stream as if no proxy were present.
+ SmallString<128> Dest;
+ raw_svector_ostream DestOS(Dest);
+ raw_pwrite_stream_proxy ProxyOS(DestOS);
+ EXPECT_EQ(0u, ProxyOS.GetBufferSize());
+
+ // Get some initial data.
+ ProxyOS << "abcd";
+ EXPECT_EQ("abcd", Dest);
+
+ // Confirm that pwrite works.
+ ProxyOS.pwrite("BC", 2, 1);
+ EXPECT_EQ("aBCd", Dest);
+}
+
+TEST(raw_ostream_proxyTest, pwriteWithBuffer) {
+ // This test confirms that when a buffer is configured, pwrite still works.
+ SmallString<128> Dest;
+ raw_svector_ostream DestOS(Dest);
+ DestOS.SetBufferSize(256);
+ EXPECT_EQ(256u, DestOS.GetBufferSize());
+
+ // Confirm that the proxy steals the buffer.
+ raw_pwrite_stream_proxy ProxyOS(DestOS);
+ EXPECT_EQ(0u, DestOS.GetBufferSize());
+ EXPECT_EQ(256u, ProxyOS.GetBufferSize());
+
+ // Check that the buffer is working.
+ ProxyOS << "abcd";
+ EXPECT_EQ("", Dest);
+
+ // Confirm that pwrite flushes.
+ ProxyOS.pwrite("BC", 2, 1);
+ EXPECT_EQ("aBCd", Dest);
+}
+
+class ProxyWithReset : public raw_ostream_proxy_adaptor<> {
+public:
+ ProxyWithReset(raw_ostream &OS) : raw_ostream_proxy_adaptor<>(OS) {}
+
+ // Allow this to be called outside the class.
+ using raw_ostream_proxy_adaptor<>::hasProxiedOS;
+ using raw_ostream_proxy_adaptor<>::getProxiedOS;
+ using raw_ostream_proxy_adaptor<>::resetProxiedOS;
+};
+
+TEST(raw_ostream_proxyTest, resetProxiedOS) {
+ // Confirm that base classes can drop the proxied OS before destruction and
+ // get consistent crashes.
+ SmallString<128> Dest;
+ BufferedNoPwriteSmallVectorStream DestOS(Dest);
+ ProxyWithReset ProxyOS(DestOS);
+ EXPECT_TRUE(ProxyOS.hasProxiedOS());
+ EXPECT_EQ(&DestOS, &ProxyOS.getProxiedOS());
+
+ // Write some data.
+ ProxyOS << "abcd";
+ EXPECT_EQ("", Dest);
+
+ // Reset the underlying stream.
+ ProxyOS.resetProxiedOS();
+ EXPECT_EQ("abcd", Dest);
+ EXPECT_EQ(0u, ProxyOS.GetBufferSize());
+ EXPECT_FALSE(ProxyOS.hasProxiedOS());
+
+#if GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
+ EXPECT_DEATH(ProxyOS << "e", "use after reset");
+ EXPECT_DEATH(ProxyOS.getProxiedOS(), "use after reset");
+#endif
+}
+
+TEST(raw_ostream_proxyTest, ColorMode) {
+ {
+ SmallString<128> Dest;
+ BufferedNoPwriteSmallVectorStream DestOS(Dest);
+ DestOS.IsDisplayed = true;
+ raw_ostream_proxy ProxyOS(DestOS);
+ ProxyOS.enable_colors(true);
+
+ WithColor(ProxyOS, raw_ostream::Colors::RED, /*Bold=*/true, /*BG=*/false,
+ ColorMode::Disable)
+ << "test";
+ EXPECT_EQ("", Dest);
+ ProxyOS.flush();
+ EXPECT_EQ("test", Dest);
+ }
+
+ {
+ SmallString<128> Dest;
+ BufferedNoPwriteSmallVectorStream DestOS(Dest);
+ raw_ostream_proxy ProxyOS(DestOS);
+
+ WithColor(ProxyOS, raw_ostream::Colors::RED, /*Bold=*/true, /*BG=*/false,
+ ColorMode::Auto)
+ << "test";
+ EXPECT_EQ("", Dest);
+ ProxyOS.flush();
+ EXPECT_EQ("test", Dest);
+ }
+
+#ifdef LLVM_ON_UNIX
+ {
+ SmallString<128> Dest;
+ BufferedNoPwriteSmallVectorStream DestOS(Dest);
+ raw_ostream_proxy ProxyOS(DestOS);
+ ProxyOS.enable_colors(true);
+
+ WithColor(ProxyOS, raw_ostream::Colors::RED, /*Bold=*/true, /*BG=*/false,
+ ColorMode::Enable)
+ << "test";
+ EXPECT_EQ("", Dest);
+ ProxyOS.flush();
+ EXPECT_EQ("\x1B[0;1;31mtest\x1B[0m", Dest);
+ }
+
+ {
+ SmallString<128> Dest;
+ BufferedNoPwriteSmallVectorStream DestOS(Dest);
+ DestOS.IsDisplayed = true;
+ raw_ostream_proxy ProxyOS(DestOS);
+ ProxyOS.enable_colors(true);
+
+ WithColor(ProxyOS, HighlightColor::Error, ColorMode::Auto) << "test";
+ EXPECT_EQ("", Dest);
+ ProxyOS.flush();
+ EXPECT_EQ("\x1B[0;1;31mtest\x1B[0m", Dest);
+ }
+#endif
+}
+
+} // end namespace
diff --git a/llvm/unittests/Target/AArch64/CMakeLists.txt b/llvm/unittests/Target/AArch64/CMakeLists.txt
index 9387ca9..3875163 100644
--- a/llvm/unittests/Target/AArch64/CMakeLists.txt
+++ b/llvm/unittests/Target/AArch64/CMakeLists.txt
@@ -34,4 +34,5 @@ add_llvm_target_unittest(AArch64Tests
AArch64SVESchedPseudoTest.cpp
AArch64SelectionDAGTest.cpp
Immediates.cpp
+ MCInstrAnalysisTest.cpp
)
diff --git a/llvm/unittests/Target/AArch64/MCInstrAnalysisTest.cpp b/llvm/unittests/Target/AArch64/MCInstrAnalysisTest.cpp
new file mode 100644
index 0000000..271d19e
--- /dev/null
+++ b/llvm/unittests/Target/AArch64/MCInstrAnalysisTest.cpp
@@ -0,0 +1,191 @@
+//===- MCInstrAnalysisTest.cpp - AArch64MCInstrAnalysis unit tests --------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/MC/MCInstrAnalysis.h"
+#include "MCTargetDesc/AArch64MCTargetDesc.h"
+#include "Utils/AArch64BaseInfo.h"
+#include "llvm/MC/MCInstBuilder.h"
+#include "llvm/MC/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
+
+#include "gtest/gtest.h"
+
+#include <memory>
+
+using namespace llvm;
+
+namespace {
+
+class InstrAnalysisTest : public testing::TestWithParam<const char *> {
+protected:
+ std::unique_ptr<const MCInstrInfo> Info;
+ std::unique_ptr<const MCInstrAnalysis> Analysis;
+
+ static void SetUpTestSuite() {
+ LLVMInitializeAArch64TargetInfo();
+ LLVMInitializeAArch64Target();
+ LLVMInitializeAArch64TargetMC();
+ }
+
+ InstrAnalysisTest() {
+ std::string Error;
+ const Target *TheTarget =
+ TargetRegistry::lookupTarget(Triple::normalize(GetParam()), Error);
+ Info = std::unique_ptr<const MCInstrInfo>(TheTarget->createMCInstrInfo());
+ Analysis = std::unique_ptr<const MCInstrAnalysis>(
+ TheTarget->createMCInstrAnalysis(Info.get()));
+ }
+};
+
+} // namespace
+
+static MCInst beq() {
+ return MCInstBuilder(AArch64::Bcc).addImm(AArch64CC::EQ).addReg(AArch64::X0);
+}
+static MCInst tbz(unsigned Rt = AArch64::X0, unsigned Imm = 0,
+ unsigned Label = 32) {
+ return MCInstBuilder(AArch64::TBZX).addReg(Rt).addImm(Imm).addImm(Label);
+}
+static MCInst cbz(unsigned Rt = AArch64::X0, unsigned Label = 32) {
+ return MCInstBuilder(AArch64::CBZX).addReg(Rt).addImm(Label);
+}
+static MCInst b() { return MCInstBuilder(AArch64::B).addImm(32); }
+static MCInst bl() { return MCInstBuilder(AArch64::BL).addImm(32); }
+static MCInst br(unsigned Rn = AArch64::X0) {
+ return MCInstBuilder(AArch64::BR).addReg(Rn);
+}
+static MCInst blr(unsigned Rn = AArch64::X0) {
+ return MCInstBuilder(AArch64::BLR).addReg(Rn);
+}
+static MCInst ret(unsigned Rn = AArch64::LR) {
+ return MCInstBuilder(AArch64::RET).addReg(Rn);
+}
+static MCInst retaa() { return MCInstBuilder(AArch64::RETAA); }
+static MCInst eret() { return MCInstBuilder(AArch64::ERET); }
+static MCInst hlt() { return MCInstBuilder(AArch64::HLT); }
+static MCInst brk() { return MCInstBuilder(AArch64::BRK); }
+static MCInst svc() { return MCInstBuilder(AArch64::SVC); }
+static MCInst hvc() { return MCInstBuilder(AArch64::HVC); }
+static MCInst smc() { return MCInstBuilder(AArch64::SMC); }
+
+TEST_P(InstrAnalysisTest, IsTerminator) {
+ EXPECT_TRUE(Analysis->isTerminator(beq()));
+ EXPECT_TRUE(Analysis->isTerminator(tbz()));
+ EXPECT_TRUE(Analysis->isTerminator(cbz()));
+ EXPECT_TRUE(Analysis->isTerminator(b()));
+ EXPECT_FALSE(Analysis->isTerminator(bl()));
+ EXPECT_FALSE(Analysis->isTerminator(blr()));
+ EXPECT_TRUE(Analysis->isTerminator(br()));
+ EXPECT_TRUE(Analysis->isTerminator(ret()));
+ EXPECT_TRUE(Analysis->isTerminator(retaa()));
+ EXPECT_TRUE(Analysis->isTerminator(eret()));
+ EXPECT_FALSE(Analysis->isTerminator(hlt()));
+ EXPECT_FALSE(Analysis->isTerminator(brk()));
+ EXPECT_FALSE(Analysis->isTerminator(svc()));
+ EXPECT_FALSE(Analysis->isTerminator(hvc()));
+ EXPECT_FALSE(Analysis->isTerminator(smc()));
+}
+
+TEST_P(InstrAnalysisTest, IsBarrier) {
+ EXPECT_FALSE(Analysis->isBarrier(beq()));
+ EXPECT_FALSE(Analysis->isBarrier(tbz()));
+ EXPECT_FALSE(Analysis->isBarrier(cbz()));
+ EXPECT_TRUE(Analysis->isBarrier(b()));
+ EXPECT_FALSE(Analysis->isBarrier(bl()));
+ EXPECT_FALSE(Analysis->isBarrier(blr()));
+ EXPECT_TRUE(Analysis->isBarrier(br()));
+ EXPECT_TRUE(Analysis->isBarrier(ret()));
+ EXPECT_TRUE(Analysis->isBarrier(retaa()));
+ EXPECT_TRUE(Analysis->isBarrier(eret()));
+ EXPECT_FALSE(Analysis->isBarrier(hlt()));
+ EXPECT_FALSE(Analysis->isBarrier(brk()));
+ EXPECT_FALSE(Analysis->isBarrier(svc()));
+ EXPECT_FALSE(Analysis->isBarrier(hvc()));
+ EXPECT_FALSE(Analysis->isBarrier(smc()));
+}
+
+TEST_P(InstrAnalysisTest, IsCall) {
+ EXPECT_FALSE(Analysis->isCall(beq()));
+ EXPECT_FALSE(Analysis->isCall(tbz()));
+ EXPECT_FALSE(Analysis->isCall(cbz()));
+ EXPECT_FALSE(Analysis->isCall(b()));
+ EXPECT_TRUE(Analysis->isCall(bl()));
+ EXPECT_TRUE(Analysis->isCall(blr()));
+ EXPECT_FALSE(Analysis->isCall(br()));
+ EXPECT_FALSE(Analysis->isCall(ret()));
+ EXPECT_FALSE(Analysis->isCall(retaa()));
+ EXPECT_FALSE(Analysis->isCall(eret()));
+}
+
+TEST_P(InstrAnalysisTest, IsReturn) {
+ EXPECT_FALSE(Analysis->isReturn(beq()));
+ EXPECT_FALSE(Analysis->isReturn(tbz()));
+ EXPECT_FALSE(Analysis->isReturn(cbz()));
+ EXPECT_FALSE(Analysis->isReturn(b()));
+ EXPECT_FALSE(Analysis->isReturn(bl()));
+ EXPECT_FALSE(Analysis->isReturn(br()));
+ EXPECT_FALSE(Analysis->isReturn(blr()));
+ EXPECT_FALSE(Analysis->isReturn(br(AArch64::LR)));
+ EXPECT_TRUE(Analysis->isReturn(ret()));
+ EXPECT_TRUE(Analysis->isReturn(retaa()));
+ EXPECT_TRUE(Analysis->isReturn(eret()));
+}
+
+TEST_P(InstrAnalysisTest, IsBranch) {
+ EXPECT_TRUE(Analysis->isBranch(beq()));
+ EXPECT_TRUE(Analysis->isBranch(tbz()));
+ EXPECT_TRUE(Analysis->isBranch(cbz()));
+ EXPECT_TRUE(Analysis->isBranch(b()));
+ EXPECT_FALSE(Analysis->isBranch(bl()));
+ EXPECT_FALSE(Analysis->isBranch(blr()));
+ EXPECT_TRUE(Analysis->isBranch(br()));
+ EXPECT_FALSE(Analysis->isBranch(ret()));
+ EXPECT_FALSE(Analysis->isBranch(retaa()));
+ EXPECT_FALSE(Analysis->isBranch(eret()));
+}
+
+TEST_P(InstrAnalysisTest, IsConditionalBranch) {
+ EXPECT_TRUE(Analysis->isConditionalBranch(beq()));
+ EXPECT_TRUE(Analysis->isConditionalBranch(tbz()));
+ EXPECT_TRUE(Analysis->isConditionalBranch(cbz()));
+ EXPECT_FALSE(Analysis->isConditionalBranch(b()));
+ EXPECT_FALSE(Analysis->isConditionalBranch(bl()));
+ EXPECT_FALSE(Analysis->isConditionalBranch(blr()));
+ EXPECT_FALSE(Analysis->isConditionalBranch(ret()));
+ EXPECT_FALSE(Analysis->isConditionalBranch(retaa()));
+ EXPECT_FALSE(Analysis->isConditionalBranch(eret()));
+}
+
+TEST_P(InstrAnalysisTest, IsUnconditionalBranch) {
+ EXPECT_FALSE(Analysis->isUnconditionalBranch(beq()));
+ EXPECT_FALSE(Analysis->isUnconditionalBranch(tbz()));
+ EXPECT_FALSE(Analysis->isUnconditionalBranch(cbz()));
+ EXPECT_TRUE(Analysis->isUnconditionalBranch(b()));
+ EXPECT_FALSE(Analysis->isUnconditionalBranch(bl()));
+ EXPECT_FALSE(Analysis->isUnconditionalBranch(blr()));
+ EXPECT_FALSE(Analysis->isUnconditionalBranch(br()));
+ EXPECT_FALSE(Analysis->isUnconditionalBranch(ret()));
+ EXPECT_FALSE(Analysis->isUnconditionalBranch(retaa()));
+ EXPECT_FALSE(Analysis->isUnconditionalBranch(eret()));
+}
+
+TEST_P(InstrAnalysisTest, IsIndirectBranch) {
+ EXPECT_FALSE(Analysis->isIndirectBranch(beq()));
+ EXPECT_FALSE(Analysis->isIndirectBranch(tbz()));
+ EXPECT_FALSE(Analysis->isIndirectBranch(cbz()));
+ EXPECT_FALSE(Analysis->isIndirectBranch(b()));
+ EXPECT_FALSE(Analysis->isIndirectBranch(bl()));
+ EXPECT_FALSE(Analysis->isIndirectBranch(blr()));
+ EXPECT_TRUE(Analysis->isIndirectBranch(br()));
+ EXPECT_FALSE(Analysis->isIndirectBranch(ret()));
+ EXPECT_FALSE(Analysis->isIndirectBranch(retaa()));
+ EXPECT_FALSE(Analysis->isIndirectBranch(eret()));
+}
+
+INSTANTIATE_TEST_SUITE_P(AArch64, InstrAnalysisTest,
+ testing::Values("aarch64"));
diff --git a/llvm/unittests/Target/AArch64/SMEAttributesTest.cpp b/llvm/unittests/Target/AArch64/SMEAttributesTest.cpp
index f13252f..bd0e53c 100644
--- a/llvm/unittests/Target/AArch64/SMEAttributesTest.cpp
+++ b/llvm/unittests/Target/AArch64/SMEAttributesTest.cpp
@@ -78,7 +78,7 @@ TEST(SMEAttributes, Constructors) {
"ret void\n}");
CallBase &Call =
cast<CallBase>((CallModule->getFunction("foo")->begin()->front()));
- ASSERT_TRUE(SMECallAttrs(Call).callsite().hasUndefZT0());
+ ASSERT_TRUE(SMECallAttrs(Call, nullptr).callsite().hasUndefZT0());
// Invalid combinations.
EXPECT_DEBUG_DEATH(SA(SA::SM_Enabled | SA::SM_Compatible),
@@ -309,7 +309,7 @@ TEST(SMEAttributes, Transitions) {
// Shared ZA -> Private ZA Interface
ASSERT_FALSE(CA(ZA_Shared, Private_ZA).requiresDisablingZABeforeCall());
- ASSERT_TRUE(CA(ZA_Shared, Private_ZA).requiresEnablingZAAfterCall());
+ ASSERT_FALSE(CA(ZA_Shared, Private_ZA).requiresEnablingZAAfterCall());
// Shared ZT0 -> Private ZA Interface
ASSERT_TRUE(CA(ZT0_Shared, Private_ZA).requiresDisablingZABeforeCall());
@@ -328,7 +328,7 @@ TEST(SMEAttributes, Transitions) {
// Shared ZA & ZT0 -> Private ZA Interface
ASSERT_FALSE(CA(ZA_ZT0_Shared, Private_ZA).requiresDisablingZABeforeCall());
ASSERT_TRUE(CA(ZA_ZT0_Shared, Private_ZA).requiresPreservingZT0());
- ASSERT_TRUE(CA(ZA_ZT0_Shared, Private_ZA).requiresEnablingZAAfterCall());
+ ASSERT_FALSE(CA(ZA_ZT0_Shared, Private_ZA).requiresEnablingZAAfterCall());
// Shared ZA -> Shared ZA Interface
ASSERT_FALSE(CA(ZA_Shared, ZT0_Shared).requiresDisablingZABeforeCall());
diff --git a/llvm/unittests/Target/AMDGPU/AMDGPUUnitTests.cpp b/llvm/unittests/Target/AMDGPU/AMDGPUUnitTests.cpp
index ac08501..593991c 100644
--- a/llvm/unittests/Target/AMDGPU/AMDGPUUnitTests.cpp
+++ b/llvm/unittests/Target/AMDGPU/AMDGPUUnitTests.cpp
@@ -320,3 +320,23 @@ TEST(AMDGPU, TestReverseComposeSubRegIndices) {
}
}
}
+
+TEST(AMDGPU, TestGetNamedOperandIdx) {
+ std::unique_ptr<const GCNTargetMachine> TM =
+ createAMDGPUTargetMachine("amdgcn-amd-", "gfx900", "");
+ if (!TM)
+ return;
+ const MCInstrInfo *MCII = TM->getMCInstrInfo();
+
+ for (unsigned Opcode = 0, E = MCII->getNumOpcodes(); Opcode != E; ++Opcode) {
+ const MCInstrDesc &Desc = MCII->get(Opcode);
+ for (unsigned Idx = 0; Idx < Desc.getNumOperands(); ++Idx) {
+ AMDGPU::OpName OpName = AMDGPU::getOperandIdxName(Opcode, Idx);
+ if (OpName == AMDGPU::OpName::NUM_OPERAND_NAMES)
+ continue;
+ int16_t RetrievedIdx = AMDGPU::getNamedOperandIdx(Opcode, OpName);
+ EXPECT_EQ(Idx, static_cast<unsigned>(RetrievedIdx))
+ << "Opcode " << Opcode << " (" << MCII->getName(Opcode) << ')';
+ }
+ }
+}
diff --git a/llvm/unittests/Target/AMDGPU/CSETest.cpp b/llvm/unittests/Target/AMDGPU/CSETest.cpp
index 3de5b88..ff44ff1 100644
--- a/llvm/unittests/Target/AMDGPU/CSETest.cpp
+++ b/llvm/unittests/Target/AMDGPU/CSETest.cpp
@@ -10,6 +10,7 @@
#include "AMDGPUUnitTests.h"
#include "llvm/CodeGen/GlobalISel/CSEInfo.h"
#include "llvm/CodeGen/GlobalISel/CSEMIRBuilder.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
#include "gtest/gtest.h"
using namespace llvm;
diff --git a/llvm/unittests/Target/DirectX/PointerTypeAnalysisTests.cpp b/llvm/unittests/Target/DirectX/PointerTypeAnalysisTests.cpp
index 9d41e94..6ae139e 100644
--- a/llvm/unittests/Target/DirectX/PointerTypeAnalysisTests.cpp
+++ b/llvm/unittests/Target/DirectX/PointerTypeAnalysisTests.cpp
@@ -8,6 +8,7 @@
#include "DirectXIRPasses/PointerTypeAnalysis.h"
#include "llvm/AsmParser/Parser.h"
+#include "llvm/IR/Constants.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
@@ -123,6 +124,33 @@ TEST(PointerTypeAnalysis, DiscoverGEP) {
EXPECT_THAT(Map, Contains(Pair(IsA<GetElementPtrInst>(), I64Ptr)));
}
+TEST(PointerTypeAnalysis, DiscoverConstantExprGEP) {
+ StringRef Assembly = R"(
+ @g = internal global [10 x i32] zeroinitializer
+ define i32 @test() {
+ %i = load i32, ptr getelementptr ([10 x i32], ptr @g, i64 0, i64 1)
+ ret i32 %i
+ }
+ )";
+
+ LLVMContext Context;
+ SMDiagnostic Error;
+ auto M = parseAssemblyString(Assembly, Error, Context);
+ ASSERT_TRUE(M) << "Bad assembly?";
+
+ PointerTypeMap Map = PointerTypeAnalysis::run(*M);
+ ASSERT_EQ(Map.size(), 3u);
+ Type *I32Ty = Type::getInt32Ty(Context);
+ Type *I32Ptr = TypedPointerType::get(I32Ty, 0);
+ Type *I32ArrPtr = TypedPointerType::get(ArrayType::get(I32Ty, 10), 0);
+ Type *FnTy = FunctionType::get(I32Ty, {}, false);
+
+ EXPECT_THAT(Map, Contains(Pair(IsA<GlobalVariable>(), I32ArrPtr)));
+ EXPECT_THAT(Map,
+ Contains(Pair(IsA<Function>(), TypedPointerType::get(FnTy, 0))));
+ EXPECT_THAT(Map, Contains(Pair(IsA<ConstantExpr>(), I32Ptr)));
+}
+
TEST(PointerTypeAnalysis, TraceIndirect) {
StringRef Assembly = R"(
define i64 @test(ptr %p) {
diff --git a/llvm/unittests/Target/DirectX/ResourceBindingAnalysisTests.cpp b/llvm/unittests/Target/DirectX/ResourceBindingAnalysisTests.cpp
index d4715be..3211c2c 100644
--- a/llvm/unittests/Target/DirectX/ResourceBindingAnalysisTests.cpp
+++ b/llvm/unittests/Target/DirectX/ResourceBindingAnalysisTests.cpp
@@ -51,7 +51,7 @@ TEST_F(ResourceBindingAnalysisTest, TestTrivialCase) {
StringRef Assembly = R"(
define void @main() {
entry:
- %handle = call target("dx.TypedBuffer", float, 1, 0, 0) @llvm.dx.resource.handlefrombinding(i32 0, i32 5, i32 1, i32 0, i1 false, ptr null)
+ %handle = call target("dx.TypedBuffer", float, 1, 0, 0) @llvm.dx.resource.handlefrombinding(i32 0, i32 5, i32 1, i32 0, ptr null)
ret void
}
)";
@@ -71,8 +71,8 @@ TEST_F(ResourceBindingAnalysisTest, TestOverlap) {
StringRef Assembly = R"(
define void @main() {
entry:
- %handleA = call target("dx.RawBuffer", float, 0, 0) @llvm.dx.resource.handlefrombinding(i32 2, i32 0, i32 -1, i32 100, i1 false, ptr null)
- %handleB = call target("dx.RawBuffer", float, 0, 0) @llvm.dx.resource.handlefrombinding(i32 2, i32 4, i32 1, i32 0, i1 false, ptr null)
+ %handleA = call target("dx.RawBuffer", float, 0, 0) @llvm.dx.resource.handlefrombinding(i32 2, i32 0, i32 -1, i32 100, ptr null)
+ %handleB = call target("dx.RawBuffer", float, 0, 0) @llvm.dx.resource.handlefrombinding(i32 2, i32 4, i32 1, i32 0, ptr null)
ret void
}
)";
@@ -94,8 +94,8 @@ TEST_F(ResourceBindingAnalysisTest, TestExactOverlap) {
@B.str = private unnamed_addr constant [2 x i8] c"B\00", align 1
define void @main() {
entry:
- %handleA = call target("dx.RawBuffer", float, 0, 0) @llvm.dx.resource.handlefrombinding(i32 0, i32 5, i32 1, i32 0, i1 false, ptr @A.str)
- %handleB = call target("dx.RawBuffer", float, 0, 0) @llvm.dx.resource.handlefrombinding(i32 0, i32 5, i32 1, i32 0, i1 false, ptr @B.str)
+ %handleA = call target("dx.RawBuffer", float, 0, 0) @llvm.dx.resource.handlefrombinding(i32 0, i32 5, i32 1, i32 0, ptr @A.str)
+ %handleB = call target("dx.RawBuffer", float, 0, 0) @llvm.dx.resource.handlefrombinding(i32 0, i32 5, i32 1, i32 0, ptr @B.str)
ret void
}
)";
@@ -115,8 +115,8 @@ TEST_F(ResourceBindingAnalysisTest, TestImplicitFlag) {
StringRef Assembly = R"(
define void @main() {
entry:
- %handleA = call target("dx.TypedBuffer", float, 1, 0, 0) @llvm.dx.resource.handlefrombinding(i32 100, i32 5, i32 1, i32 0, i1 false, ptr null)
- %handleB = call target("dx.TypedBuffer", float, 1, 0, 0) @llvm.dx.resource.handlefromimplicitbinding(i32 0, i32 0, i32 1, i32 0, i1 false, ptr null)
+ %handleA = call target("dx.TypedBuffer", float, 1, 0, 0) @llvm.dx.resource.handlefrombinding(i32 100, i32 5, i32 1, i32 0, ptr null)
+ %handleB = call target("dx.TypedBuffer", float, 1, 0, 0) @llvm.dx.resource.handlefromimplicitbinding(i32 0, i32 0, i32 1, i32 0, ptr null)
ret void
}
)";
diff --git a/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp b/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp
index 160a915..5b54c13 100644
--- a/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp
+++ b/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp
@@ -59,7 +59,7 @@ TEST_F(UniqueResourceFromUseTest, TestResourceCounterDecrement) {
StringRef Assembly = R"(
define void @main() {
entry:
- %handle = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding(i32 1, i32 2, i32 3, i32 4, i1 false, ptr null)
+ %handle = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding(i32 1, i32 2, i32 3, i32 4, ptr null)
call i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", float, 1, 0) %handle, i8 -1)
call i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", float, 1, 0) %handle, i8 -1)
call i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", float, 1, 0) %handle, i8 -1)
@@ -89,7 +89,7 @@ TEST_F(UniqueResourceFromUseTest, TestResourceCounterIncrement) {
StringRef Assembly = R"(
define void @main() {
entry:
- %handle = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding(i32 1, i32 2, i32 3, i32 4, i1 false, ptr null)
+ %handle = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding(i32 1, i32 2, i32 3, i32 4, ptr null)
call i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", float, 1, 0) %handle, i8 1)
call i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", float, 1, 0) %handle, i8 1)
call i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", float, 1, 0) %handle, i8 1)
@@ -119,7 +119,7 @@ TEST_F(UniqueResourceFromUseTest, TestResourceCounterUnknown) {
StringRef Assembly = R"(
define void @main() {
entry:
- %handle = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding(i32 1, i32 2, i32 3, i32 4, i1 false, ptr null)
+ %handle = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding(i32 1, i32 2, i32 3, i32 4, ptr null)
ret void
}
)";
@@ -146,8 +146,8 @@ TEST_F(UniqueResourceFromUseTest, TestResourceCounterMultiple) {
StringRef Assembly = R"(
define void @main() {
entry:
- %handle1 = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding(i32 1, i32 2, i32 3, i32 4, i1 false, ptr null)
- %handle2 = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding(i32 4, i32 3, i32 2, i32 1, i1 false, ptr null)
+ %handle1 = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding(i32 1, i32 2, i32 3, i32 4, ptr null)
+ %handle2 = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding(i32 4, i32 3, i32 2, i32 1, ptr null)
call i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", float, 1, 0) %handle1, i8 -1)
call i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", float, 1, 0) %handle2, i8 1)
ret void
@@ -182,7 +182,7 @@ TEST_F(UniqueResourceFromUseTest, TestResourceCounterInvalid) {
StringRef Assembly = R"(
define void @main() {
entry:
- %handle = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding(i32 1, i32 2, i32 3, i32 4, i1 false, ptr null)
+ %handle = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding(i32 1, i32 2, i32 3, i32 4, ptr null)
call i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", float, 1, 0) %handle, i8 -1)
call i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", float, 1, 0) %handle, i8 1)
ret void
diff --git a/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp b/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp
index 319538e..d10dcb6 100644
--- a/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp
+++ b/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp
@@ -1099,6 +1099,7 @@ R"(All available -march extensions for RISC-V
smcdeleg 1.0
smcntrpmf 1.0
smcsrind 1.0
+ smctr 1.0
smdbltrp 1.0
smepmp 1.0
smmpm 1.0
@@ -1111,6 +1112,7 @@ R"(All available -march extensions for RISC-V
sscofpmf 1.0
sscounterenw 1.0
sscsrind 1.0
+ ssctr 1.0
ssdbltrp 1.0
ssnpm 1.0
sspm 1.0
@@ -1144,6 +1146,7 @@ R"(All available -march extensions for RISC-V
xcvsimd 1.0
xmipscbop 1.0
xmipscmov 1.0
+ xmipsexectl 1.0
xmipslsp 1.0
xsfcease 1.0
xsfmm128t 0.6
@@ -1163,6 +1166,7 @@ R"(All available -march extensions for RISC-V
xsfvqmaccqoq 1.0
xsifivecdiscarddlone 1.0
xsifivecflushdlone 1.0
+ xsmtvdot 1.0
xtheadba 1.0
xtheadbb 1.0
xtheadbs 1.0
@@ -1178,15 +1182,14 @@ R"(All available -march extensions for RISC-V
xwchc 2.2
Experimental extensions
- p 0.14
+ p 0.15
zicfilp 1.0 This is a long dummy description
zicfiss 1.0
zalasr 0.1
zvbc32e 0.7
+ zvfbfa 0.1
zvkgs 0.7
zvqdotq 0.0
- smctr 1.0
- ssctr 1.0
svukte 0.3
xqccmp 0.3
xqcia 0.7
diff --git a/llvm/unittests/Transforms/IPO/FunctionSpecializationTest.cpp b/llvm/unittests/Transforms/IPO/FunctionSpecializationTest.cpp
index 9f76e9f..49373d3 100644
--- a/llvm/unittests/Transforms/IPO/FunctionSpecializationTest.cpp
+++ b/llvm/unittests/Transforms/IPO/FunctionSpecializationTest.cpp
@@ -27,12 +27,11 @@ namespace llvm {
static void removeSSACopy(Function &F) {
for (BasicBlock &BB : F) {
for (Instruction &Inst : llvm::make_early_inc_range(BB)) {
- if (auto *II = dyn_cast<IntrinsicInst>(&Inst)) {
- if (II->getIntrinsicID() != Intrinsic::ssa_copy)
- continue;
- Inst.replaceAllUsesWith(II->getOperand(0));
- Inst.eraseFromParent();
- }
+ auto *BC = dyn_cast<BitCastInst>(&Inst);
+ if (!BC || BC->getType() != BC->getOperand(0)->getType())
+ continue;
+ Inst.replaceAllUsesWith(BC->getOperand(0));
+ Inst.eraseFromParent();
}
}
}
diff --git a/llvm/unittests/Transforms/Utils/LocalTest.cpp b/llvm/unittests/Transforms/Utils/LocalTest.cpp
index 0c70feb..4b53cc3 100644
--- a/llvm/unittests/Transforms/Utils/LocalTest.cpp
+++ b/llvm/unittests/Transforms/Utils/LocalTest.cpp
@@ -1057,6 +1057,14 @@ TEST(Local, SimplifyCFGWithNullAC) {
RequireAndPreserveDomTree ? &DTU : nullptr, Options));
}
+TEST(LocalTest, TargetTypeInfoHasNoReplacementProperty) {
+ LLVMContext Ctx;
+ SmallVector<unsigned, 3> Ints = {};
+ auto *TT = llvm::TargetExtType::get(Ctx, "dx.RawBuffer", {}, Ints);
+
+ EXPECT_TRUE(TT->hasProperty(TargetExtType::Property::IsTokenLike));
+}
+
TEST(Local, CanReplaceOperandWithVariable) {
LLVMContext Ctx;
Module M("test_module", Ctx);
diff --git a/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/SeedCollectorTest.cpp b/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/SeedCollectorTest.cpp
index 7f9a59b..31b4a5e 100644
--- a/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/SeedCollectorTest.cpp
+++ b/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/SeedCollectorTest.cpp
@@ -259,10 +259,10 @@ bb:
// Check begin() end() when empty.
EXPECT_EQ(SC.begin(), SC.end());
- SC.insert(S0);
- SC.insert(S1);
- SC.insert(S2);
- SC.insert(S3);
+ SC.insert(S0, /*AllowDiffTypes=*/false);
+ SC.insert(S1, /*AllowDiffTypes=*/false);
+ SC.insert(S2, /*AllowDiffTypes=*/false);
+ SC.insert(S3, /*AllowDiffTypes=*/false);
unsigned Cnt = 0;
SmallVector<sandboxir::SeedBundle *> Bndls;
for (auto &SeedBndl : SC) {
@@ -480,6 +480,45 @@ bb:
ExpectThatElementsAre(SB, {St0, St1, St3});
}
+TEST_F(SeedBundleTest, DiffTypes) {
+ parseIR(C, R"IR(
+define void @foo(ptr noalias %ptr, i8 %v, i16 %v16) {
+bb:
+ %ptr0 = getelementptr i8, ptr %ptr, i32 0
+ %ptr1 = getelementptr i8, ptr %ptr, i32 1
+ %ptr3 = getelementptr i8, ptr %ptr, i32 3
+ store i8 %v, ptr %ptr0
+ store i8 %v, ptr %ptr3
+ store i16 %v16, ptr %ptr1
+ ret void
+}
+)IR");
+ Function &LLVMF = *M->getFunction("foo");
+ DominatorTree DT(LLVMF);
+ TargetLibraryInfoImpl TLII(M->getTargetTriple());
+ TargetLibraryInfo TLI(TLII);
+ DataLayout DL(M->getDataLayout());
+ LoopInfo LI(DT);
+ AssumptionCache AC(LLVMF);
+ ScalarEvolution SE(LLVMF, TLI, AC, DT, LI);
+
+ sandboxir::Context Ctx(C);
+ auto &F = *Ctx.createFunction(&LLVMF);
+ auto BB = F.begin();
+ auto It = std::next(BB->begin(), 3);
+ auto *St0 = &*It++;
+ auto *St3 = &*It++;
+ auto *St1 = &*It++;
+
+ sandboxir::SeedCollector SC(&*BB, SE, /*CollectStores=*/true,
+ /*CollectLoads=*/false, /*AllowDiffTypes=*/true);
+
+ auto StoreSeedsRange = SC.getStoreSeeds();
+ EXPECT_EQ(range_size(StoreSeedsRange), 1u);
+ auto &SB = *StoreSeedsRange.begin();
+ ExpectThatElementsAre(SB, {St0, St1, St3});
+}
+
TEST_F(SeedBundleTest, VectorLoads) {
parseIR(C, R"IR(
define void @foo(ptr noalias %ptr, <2 x float> %val0) {
diff --git a/llvm/unittests/Transforms/Vectorize/VPlanHCFGTest.cpp b/llvm/unittests/Transforms/Vectorize/VPlanHCFGTest.cpp
index e7439397..a943e7ac 100644
--- a/llvm/unittests/Transforms/Vectorize/VPlanHCFGTest.cpp
+++ b/llvm/unittests/Transforms/Vectorize/VPlanHCFGTest.cpp
@@ -203,7 +203,7 @@ TEST_F(VPlanHCFGTest, testVPInstructionToVPRecipesInner) {
VPInstruction::BranchOnCond,
{Plan->getOrAddLiveIn(ConstantInt::getTrue(F->getContext()))}));
VPlanTransforms::tryToConvertVPInstructionsToVPRecipes(
- Plan, [](PHINode *P) { return nullptr; }, *SE, TLI);
+ Plan, [](PHINode *P) { return nullptr; }, TLI);
VPBlockBase *Entry = Plan->getEntry()->getEntryBasicBlock();
EXPECT_EQ(0u, Entry->getNumPredecessors());
diff --git a/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp b/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp
index 94b74d2..db64c75 100644
--- a/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp
+++ b/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp
@@ -1088,7 +1088,7 @@ TEST_F(VPRecipeTest, CastVPInterleaveRecipeToVPUser) {
VPValue *Addr = Plan.getOrAddLiveIn(ConstantInt::get(Int32, 1));
VPValue *Mask = Plan.getOrAddLiveIn(ConstantInt::get(Int32, 2));
InterleaveGroup<Instruction> IG(4, false, Align(4));
- VPInterleaveRecipe Recipe(&IG, Addr, {}, Mask, false, DebugLoc());
+ VPInterleaveRecipe Recipe(&IG, Addr, {}, Mask, false, {}, DebugLoc());
EXPECT_TRUE(isa<VPUser>(&Recipe));
VPRecipeBase *BaseR = &Recipe;
EXPECT_TRUE(isa<VPUser>(BaseR));
diff --git a/llvm/unittests/Transforms/Vectorize/VPlanTestBase.h b/llvm/unittests/Transforms/Vectorize/VPlanTestBase.h
index 7dfd11a..383f79b 100644
--- a/llvm/unittests/Transforms/Vectorize/VPlanTestBase.h
+++ b/llvm/unittests/Transforms/Vectorize/VPlanTestBase.h
@@ -72,10 +72,12 @@ protected:
Loop *L = LI->getLoopFor(LoopHeader);
PredicatedScalarEvolution PSE(*SE, *L);
- auto Plan = VPlanTransforms::buildPlainCFG(L, *LI);
- VFRange R(ElementCount::getFixed(1), ElementCount::getFixed(2));
- VPlanTransforms::prepareForVectorization(*Plan, IntegerType::get(*Ctx, 64),
- PSE, true, false, L, {}, false, R);
+ auto Plan = VPlanTransforms::buildVPlan0(L, *LI, IntegerType::get(*Ctx, 64),
+ {}, PSE);
+
+ VPlanTransforms::handleEarlyExits(*Plan, false);
+ VPlanTransforms::addMiddleCheck(*Plan, true, false);
+
VPlanTransforms::createLoopRegions(*Plan);
return Plan;
}
diff --git a/llvm/unittests/Transforms/Vectorize/VPlanVerifierTest.cpp b/llvm/unittests/Transforms/Vectorize/VPlanVerifierTest.cpp
index b698b28..c2f045b 100644
--- a/llvm/unittests/Transforms/Vectorize/VPlanVerifierTest.cpp
+++ b/llvm/unittests/Transforms/Vectorize/VPlanVerifierTest.cpp
@@ -170,15 +170,14 @@ TEST_F(VPVerifierTest, VPPhiIncomingValueDoesntDominateIncomingBlock) {
EXPECT_FALSE(verifyVPlanIsValid(Plan));
#if GTEST_HAS_STREAM_REDIRECTION
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
- EXPECT_STREQ("Incoming def at index 0 does not dominate incoming block!\n"
+ EXPECT_STREQ("Incoming def does not dominate incoming block!\n"
" EMIT vp<%2> = add ir<0>\n"
" does not dominate preheader for\n"
" EMIT-SCALAR vp<%1> = phi [ vp<%2>, preheader ]",
::testing::internal::GetCapturedStderr().c_str());
#else
- EXPECT_STREQ("Incoming def at index 0 does not dominate incoming block!\n", ::
- testing::internal::GetCapturedStderr()
- .c_str());
+ EXPECT_STREQ("Incoming def does not dominate incoming block!\n",
+ ::testing::internal::GetCapturedStderr().c_str());
#endif
#endif
}