summaryrefslogtreecommitdiff
path: root/unittests
diff options
context:
space:
mode:
Diffstat (limited to 'unittests')
-rw-r--r--unittests/ADT/APFloatTest.cpp420
-rw-r--r--unittests/ADT/APIntTest.cpp840
-rw-r--r--unittests/ADT/BitVectorTest.cpp76
-rw-r--r--unittests/ADT/BreadthFirstIteratorTest.cpp74
-rw-r--r--unittests/ADT/CMakeLists.txt1
-rw-r--r--unittests/ADT/DenseMapTest.cpp14
-rw-r--r--unittests/ADT/DenseSetTest.cpp29
-rw-r--r--unittests/ADT/IteratorTest.cpp73
-rw-r--r--unittests/ADT/STLExtrasTest.cpp26
-rw-r--r--unittests/ADT/SmallPtrSetTest.cpp51
-rw-r--r--unittests/ADT/SparseBitVectorTest.cpp39
-rw-r--r--unittests/ADT/StringMapTest.cpp31
-rw-r--r--unittests/ADT/StringRefTest.cpp41
-rw-r--r--unittests/ADT/TinyPtrVectorTest.cpp10
-rw-r--r--unittests/ADT/TripleTest.cpp74
-rw-r--r--unittests/Analysis/BlockFrequencyInfoTest.cpp8
-rw-r--r--unittests/Analysis/CMakeLists.txt8
-rw-r--r--unittests/Analysis/LazyCallGraphTest.cpp622
-rw-r--r--unittests/Analysis/LoopInfoTest.cpp158
-rw-r--r--unittests/Analysis/MemorySSA.cpp (renamed from unittests/Transforms/Utils/MemorySSA.cpp)369
-rw-r--r--unittests/Analysis/ProfileSummaryInfoTest.cpp198
-rw-r--r--unittests/Analysis/ScalarEvolutionTest.cpp118
-rw-r--r--unittests/Analysis/TargetLibraryInfoTest.cpp481
-rw-r--r--unittests/Analysis/UnrollAnalyzer.cpp11
-rw-r--r--unittests/Analysis/ValueTrackingTest.cpp21
-rw-r--r--unittests/CMakeLists.txt1
-rw-r--r--unittests/CodeGen/LowLevelTypeTest.cpp6
-rw-r--r--unittests/DebugInfo/DWARF/CMakeLists.txt1
-rw-r--r--unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp698
-rw-r--r--unittests/DebugInfo/DWARF/DwarfGenerator.cpp14
-rw-r--r--unittests/DebugInfo/DWARF/DwarfGenerator.h3
-rw-r--r--unittests/DebugInfo/PDB/CMakeLists.txt3
-rw-r--r--unittests/DebugInfo/PDB/HashTableTest.cpp168
-rw-r--r--unittests/DebugInfo/PDB/MappedBlockStreamTest.cpp90
-rw-r--r--unittests/DebugInfo/PDB/PDBApiTest.cpp1
-rw-r--r--unittests/DebugInfo/PDB/StringTableBuilderTest.cpp55
-rw-r--r--unittests/DebugInfo/PDB/TypeServerHandlerTest.cpp175
-rw-r--r--unittests/ExecutionEngine/Orc/CMakeLists.txt5
-rw-r--r--unittests/ExecutionEngine/Orc/IndirectionUtilsTest.cpp18
-rw-r--r--unittests/ExecutionEngine/Orc/ObjectTransformLayerTest.cpp4
-rw-r--r--unittests/ExecutionEngine/Orc/OrcTestCommon.cpp2
-rw-r--r--unittests/ExecutionEngine/Orc/OrcTestCommon.h22
-rw-r--r--unittests/ExecutionEngine/Orc/QueueChannel.cpp14
-rw-r--r--unittests/ExecutionEngine/Orc/QueueChannel.h146
-rw-r--r--unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp486
-rw-r--r--unittests/ExecutionEngine/Orc/RTDyldObjectLinkingLayerTest.cpp (renamed from unittests/ExecutionEngine/Orc/ObjectLinkingLayerTest.cpp)28
-rw-r--r--unittests/IR/AttributesTest.cpp20
-rw-r--r--unittests/IR/FunctionTest.cpp21
-rw-r--r--unittests/IR/IRBuilderTest.cpp22
-rw-r--r--unittests/IR/InstructionsTest.cpp167
-rw-r--r--unittests/IR/LegacyPassManagerTest.cpp17
-rw-r--r--unittests/IR/MetadataTest.cpp49
-rw-r--r--unittests/IR/ValueHandleTest.cpp93
-rw-r--r--unittests/IR/ValueTest.cpp2
-rw-r--r--unittests/IR/VerifierTest.cpp6
-rw-r--r--unittests/Linker/LinkModulesTest.cpp18
-rw-r--r--unittests/MI/LiveIntervalTest.cpp270
-rw-r--r--unittests/Object/CMakeLists.txt1
-rw-r--r--unittests/Object/SymbolicFileTest.cpp42
-rw-r--r--unittests/Option/OptionParsingTest.cpp8
-rw-r--r--unittests/ProfileData/CoverageMappingTest.cpp2
-rw-r--r--unittests/Support/ARMAttributeParser.cpp385
-rw-r--r--unittests/Support/AllocatorTest.cpp6
-rw-r--r--unittests/Support/BinaryStreamTest.cpp711
-rw-r--r--unittests/Support/CMakeLists.txt5
-rw-r--r--unittests/Support/CachePruningTest.cpp71
-rw-r--r--unittests/Support/Casting.cpp75
-rw-r--r--unittests/Support/Chrono.cpp31
-rw-r--r--unittests/Support/CommandLineTest.cpp76
-rw-r--r--unittests/Support/CompressionTest.cpp17
-rw-r--r--unittests/Support/ErrorTest.cpp28
-rw-r--r--unittests/Support/FormatVariadicTest.cpp2
-rw-r--r--unittests/Support/Host.cpp92
-rw-r--r--unittests/Support/LEB128Test.cpp47
-rw-r--r--unittests/Support/MD5Test.cpp4
-rw-r--r--unittests/Support/Path.cpp570
-rw-r--r--unittests/Support/ProgramTest.cpp1
-rw-r--r--unittests/Support/TargetParserTest.cpp73
-rw-r--r--unittests/Support/ThreadPool.cpp4
-rw-r--r--unittests/Support/TrailingObjectsTest.cpp21
-rw-r--r--unittests/Support/YAMLIOTest.cpp16
-rw-r--r--unittests/Support/raw_ostream_test.cpp8
-rw-r--r--unittests/Transforms/Scalar/LoopPassManagerTest.cpp399
-rw-r--r--unittests/Transforms/Utils/CMakeLists.txt1
-rw-r--r--unittests/Transforms/Utils/Cloning.cpp65
-rw-r--r--unittests/Transforms/Utils/IntegerDivision.cpp16
-rw-r--r--unittests/XRay/CMakeLists.txt13
-rw-r--r--unittests/XRay/GraphTest.cpp261
88 files changed, 8149 insertions, 1320 deletions
diff --git a/unittests/ADT/APFloatTest.cpp b/unittests/ADT/APFloatTest.cpp
index 83fb213109aa2..378c48d7e0a6b 100644
--- a/unittests/ADT/APFloatTest.cpp
+++ b/unittests/ADT/APFloatTest.cpp
@@ -9,6 +9,7 @@
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APSInt.h"
+#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/raw_ostream.h"
@@ -2829,6 +2830,28 @@ TEST(APFloatTest, abs) {
EXPECT_TRUE(PSmallestNormalized.bitwiseIsEqual(abs(MSmallestNormalized)));
}
+TEST(APFloatTest, neg) {
+ APFloat One = APFloat(APFloat::IEEEsingle(), "1.0");
+ APFloat NegOne = APFloat(APFloat::IEEEsingle(), "-1.0");
+ APFloat Zero = APFloat::getZero(APFloat::IEEEsingle(), false);
+ APFloat NegZero = APFloat::getZero(APFloat::IEEEsingle(), true);
+ APFloat Inf = APFloat::getInf(APFloat::IEEEsingle(), false);
+ APFloat NegInf = APFloat::getInf(APFloat::IEEEsingle(), true);
+ APFloat QNaN = APFloat::getNaN(APFloat::IEEEsingle(), false);
+ APFloat NegQNaN = APFloat::getNaN(APFloat::IEEEsingle(), true);
+
+ EXPECT_TRUE(NegOne.bitwiseIsEqual(neg(One)));
+ EXPECT_TRUE(One.bitwiseIsEqual(neg(NegOne)));
+ EXPECT_TRUE(NegZero.bitwiseIsEqual(neg(Zero)));
+ EXPECT_TRUE(Zero.bitwiseIsEqual(neg(NegZero)));
+ EXPECT_TRUE(NegInf.bitwiseIsEqual(neg(Inf)));
+ EXPECT_TRUE(Inf.bitwiseIsEqual(neg(NegInf)));
+ EXPECT_TRUE(NegInf.bitwiseIsEqual(neg(Inf)));
+ EXPECT_TRUE(Inf.bitwiseIsEqual(neg(NegInf)));
+ EXPECT_TRUE(NegQNaN.bitwiseIsEqual(neg(QNaN)));
+ EXPECT_TRUE(QNaN.bitwiseIsEqual(neg(NegQNaN)));
+}
+
TEST(APFloatTest, ilogb) {
EXPECT_EQ(-1074, ilogb(APFloat::getSmallest(APFloat::IEEEdouble(), false)));
EXPECT_EQ(-1074, ilogb(APFloat::getSmallest(APFloat::IEEEdouble(), true)));
@@ -3169,6 +3192,70 @@ TEST(APFloatTest, frexp) {
EXPECT_TRUE(APFloat(APFloat::IEEEdouble(), "0x1.c60f120d9f87cp-1").bitwiseIsEqual(Frac));
}
+TEST(APFloatTest, mod) {
+ {
+ APFloat f1(APFloat::IEEEdouble(), "1.5");
+ APFloat f2(APFloat::IEEEdouble(), "1.0");
+ APFloat expected(APFloat::IEEEdouble(), "0.5");
+ EXPECT_EQ(f1.mod(f2), APFloat::opOK);
+ EXPECT_TRUE(f1.bitwiseIsEqual(expected));
+ }
+ {
+ APFloat f1(APFloat::IEEEdouble(), "0.5");
+ APFloat f2(APFloat::IEEEdouble(), "1.0");
+ APFloat expected(APFloat::IEEEdouble(), "0.5");
+ EXPECT_EQ(f1.mod(f2), APFloat::opOK);
+ EXPECT_TRUE(f1.bitwiseIsEqual(expected));
+ }
+ {
+ APFloat f1(APFloat::IEEEdouble(), "0x1.3333333333333p-2"); // 0.3
+ APFloat f2(APFloat::IEEEdouble(), "0x1.47ae147ae147bp-7"); // 0.01
+ APFloat expected(APFloat::IEEEdouble(),
+ "0x1.47ae147ae1471p-7"); // 0.009999999999999983
+ EXPECT_EQ(f1.mod(f2), APFloat::opOK);
+ EXPECT_TRUE(f1.bitwiseIsEqual(expected));
+ }
+ {
+ APFloat f1(APFloat::IEEEdouble(), "0x1p64"); // 1.8446744073709552e19
+ APFloat f2(APFloat::IEEEdouble(), "1.5");
+ APFloat expected(APFloat::IEEEdouble(), "1.0");
+ EXPECT_EQ(f1.mod(f2), APFloat::opOK);
+ EXPECT_TRUE(f1.bitwiseIsEqual(expected));
+ }
+ {
+ APFloat f1(APFloat::IEEEdouble(), "0x1p1000");
+ APFloat f2(APFloat::IEEEdouble(), "0x1p-1000");
+ APFloat expected(APFloat::IEEEdouble(), "0.0");
+ EXPECT_EQ(f1.mod(f2), APFloat::opOK);
+ EXPECT_TRUE(f1.bitwiseIsEqual(expected));
+ }
+ {
+ APFloat f1(APFloat::IEEEdouble(), "0.0");
+ APFloat f2(APFloat::IEEEdouble(), "1.0");
+ APFloat expected(APFloat::IEEEdouble(), "0.0");
+ EXPECT_EQ(f1.mod(f2), APFloat::opOK);
+ EXPECT_TRUE(f1.bitwiseIsEqual(expected));
+ }
+ {
+ APFloat f1(APFloat::IEEEdouble(), "1.0");
+ APFloat f2(APFloat::IEEEdouble(), "0.0");
+ EXPECT_EQ(f1.mod(f2), APFloat::opInvalidOp);
+ EXPECT_TRUE(f1.isNaN());
+ }
+ {
+ APFloat f1(APFloat::IEEEdouble(), "0.0");
+ APFloat f2(APFloat::IEEEdouble(), "0.0");
+ EXPECT_EQ(f1.mod(f2), APFloat::opInvalidOp);
+ EXPECT_TRUE(f1.isNaN());
+ }
+ {
+ APFloat f1 = APFloat::getInf(APFloat::IEEEdouble(), false);
+ APFloat f2(APFloat::IEEEdouble(), "1.0");
+ EXPECT_EQ(f1.mod(f2), APFloat::opInvalidOp);
+ EXPECT_TRUE(f1.isNaN());
+ }
+}
+
TEST(APFloatTest, PPCDoubleDoubleAddSpecial) {
using DataType = std::tuple<uint64_t, uint64_t, uint64_t, uint64_t,
APFloat::fltCategory, APFloat::roundingMode>;
@@ -3181,7 +3268,7 @@ TEST(APFloatTest, PPCDoubleDoubleAddSpecial) {
0x7948000000000000ull, 0ull, APFloat::fcInfinity,
APFloat::rmNearestTiesToEven),
// TODO: change the 4th 0x75effffffffffffe to 0x75efffffffffffff when
- // PPCDoubleDoubleImpl is gone.
+ // semPPCDoubleDoubleLegacy is gone.
// LDBL_MAX + (1.011111... >> (1023 - 106) + (1.1111111...0 >> (1023 -
// 160))) = fcNormal
std::make_tuple(0x7fefffffffffffffull, 0x7c8ffffffffffffeull,
@@ -3202,14 +3289,26 @@ TEST(APFloatTest, PPCDoubleDoubleAddSpecial) {
APFloat::roundingMode RM;
std::tie(Op1[0], Op1[1], Op2[0], Op2[1], Expected, RM) = Tp;
- APFloat A1(APFloat::PPCDoubleDouble(), APInt(128, 2, Op1));
- APFloat A2(APFloat::PPCDoubleDouble(), APInt(128, 2, Op2));
- A1.add(A2, RM);
+ {
+ APFloat A1(APFloat::PPCDoubleDouble(), APInt(128, 2, Op1));
+ APFloat A2(APFloat::PPCDoubleDouble(), APInt(128, 2, Op2));
+ A1.add(A2, RM);
- EXPECT_EQ(Expected, A1.getCategory())
- << formatv("({0:x} + {1:x}) + ({2:x} + {3:x})", Op1[0], Op1[1], Op2[0],
- Op2[1])
- .str();
+ EXPECT_EQ(Expected, A1.getCategory())
+ << formatv("({0:x} + {1:x}) + ({2:x} + {3:x})", Op1[0], Op1[1],
+ Op2[0], Op2[1])
+ .str();
+ }
+ {
+ APFloat A1(APFloat::PPCDoubleDouble(), APInt(128, 2, Op1));
+ APFloat A2(APFloat::PPCDoubleDouble(), APInt(128, 2, Op2));
+ A2.add(A1, RM);
+
+ EXPECT_EQ(Expected, A2.getCategory())
+ << formatv("({0:x} + {1:x}) + ({2:x} + {3:x})", Op2[0], Op2[1],
+ Op1[0], Op1[1])
+ .str();
+ }
}
}
@@ -3234,14 +3333,14 @@ TEST(APFloatTest, PPCDoubleDoubleAdd) {
0x3ff0000000000000ull, 0x0000000000000001ull,
APFloat::rmNearestTiesToEven),
// TODO: change 0xf950000000000000 to 0xf940000000000000, when
- // PPCDoubleDoubleImpl is gone.
+ // semPPCDoubleDoubleLegacy is gone.
// (DBL_MAX - 1 << (1023 - 105)) + (1 << (1023 - 53) + 0) = DBL_MAX +
// 1.11111... << (1023 - 52)
std::make_tuple(0x7fefffffffffffffull, 0xf950000000000000ull,
0x7c90000000000000ull, 0, 0x7fefffffffffffffull,
0x7c8ffffffffffffeull, APFloat::rmNearestTiesToEven),
// TODO: change 0xf950000000000000 to 0xf940000000000000, when
- // PPCDoubleDoubleImpl is gone.
+ // semPPCDoubleDoubleLegacy is gone.
// (1 << (1023 - 53) + 0) + (DBL_MAX - 1 << (1023 - 105)) = DBL_MAX +
// 1.11111... << (1023 - 52)
std::make_tuple(0x7c90000000000000ull, 0, 0x7fefffffffffffffull,
@@ -3254,18 +3353,34 @@ TEST(APFloatTest, PPCDoubleDoubleAdd) {
APFloat::roundingMode RM;
std::tie(Op1[0], Op1[1], Op2[0], Op2[1], Expected[0], Expected[1], RM) = Tp;
- APFloat A1(APFloat::PPCDoubleDouble(), APInt(128, 2, Op1));
- APFloat A2(APFloat::PPCDoubleDouble(), APInt(128, 2, Op2));
- A1.add(A2, RM);
-
- EXPECT_EQ(Expected[0], A1.bitcastToAPInt().getRawData()[0])
- << formatv("({0:x} + {1:x}) + ({2:x} + {3:x})", Op1[0], Op1[1], Op2[0],
- Op2[1])
- .str();
- EXPECT_EQ(Expected[1], A1.getSecondFloat().bitcastToAPInt().getRawData()[0])
- << formatv("({0:x} + {1:x}) + ({2:x} + {3:x})", Op1[0], Op1[1], Op2[0],
- Op2[1])
- .str();
+ {
+ APFloat A1(APFloat::PPCDoubleDouble(), APInt(128, 2, Op1));
+ APFloat A2(APFloat::PPCDoubleDouble(), APInt(128, 2, Op2));
+ A1.add(A2, RM);
+
+ EXPECT_EQ(Expected[0], A1.bitcastToAPInt().getRawData()[0])
+ << formatv("({0:x} + {1:x}) + ({2:x} + {3:x})", Op1[0], Op1[1],
+ Op2[0], Op2[1])
+ .str();
+ EXPECT_EQ(Expected[1], A1.bitcastToAPInt().getRawData()[1])
+ << formatv("({0:x} + {1:x}) + ({2:x} + {3:x})", Op1[0], Op1[1],
+ Op2[0], Op2[1])
+ .str();
+ }
+ {
+ APFloat A1(APFloat::PPCDoubleDouble(), APInt(128, 2, Op1));
+ APFloat A2(APFloat::PPCDoubleDouble(), APInt(128, 2, Op2));
+ A2.add(A1, RM);
+
+ EXPECT_EQ(Expected[0], A2.bitcastToAPInt().getRawData()[0])
+ << formatv("({0:x} + {1:x}) + ({2:x} + {3:x})", Op2[0], Op2[1],
+ Op1[0], Op1[1])
+ .str();
+ EXPECT_EQ(Expected[1], A2.bitcastToAPInt().getRawData()[1])
+ << formatv("({0:x} + {1:x}) + ({2:x} + {3:x})", Op2[0], Op2[1],
+ Op1[0], Op1[1])
+ .str();
+ }
}
}
@@ -3296,23 +3411,118 @@ TEST(APFloatTest, PPCDoubleDoubleSubtract) {
<< formatv("({0:x} + {1:x}) - ({2:x} + {3:x})", Op1[0], Op1[1], Op2[0],
Op2[1])
.str();
- EXPECT_EQ(Expected[1], A1.getSecondFloat().bitcastToAPInt().getRawData()[0])
+ EXPECT_EQ(Expected[1], A1.bitcastToAPInt().getRawData()[1])
<< formatv("({0:x} + {1:x}) - ({2:x} + {3:x})", Op1[0], Op1[1], Op2[0],
Op2[1])
.str();
}
}
+TEST(APFloatTest, PPCDoubleDoubleMultiplySpecial) {
+ using DataType = std::tuple<uint64_t, uint64_t, uint64_t, uint64_t,
+ APFloat::fltCategory, APFloat::roundingMode>;
+ DataType Data[] = {
+ // fcNaN * fcNaN = fcNaN
+ std::make_tuple(0x7ff8000000000000ull, 0, 0x7ff8000000000000ull, 0,
+ APFloat::fcNaN, APFloat::rmNearestTiesToEven),
+ // fcNaN * fcZero = fcNaN
+ std::make_tuple(0x7ff8000000000000ull, 0, 0, 0, APFloat::fcNaN,
+ APFloat::rmNearestTiesToEven),
+ // fcNaN * fcInfinity = fcNaN
+ std::make_tuple(0x7ff8000000000000ull, 0, 0x7ff0000000000000ull, 0,
+ APFloat::fcNaN, APFloat::rmNearestTiesToEven),
+ // fcNaN * fcNormal = fcNaN
+ std::make_tuple(0x7ff8000000000000ull, 0, 0x3ff0000000000000ull, 0,
+ APFloat::fcNaN, APFloat::rmNearestTiesToEven),
+ // fcInfinity * fcInfinity = fcInfinity
+ std::make_tuple(0x7ff0000000000000ull, 0, 0x7ff0000000000000ull, 0,
+ APFloat::fcInfinity, APFloat::rmNearestTiesToEven),
+ // fcInfinity * fcZero = fcNaN
+ std::make_tuple(0x7ff0000000000000ull, 0, 0, 0, APFloat::fcNaN,
+ APFloat::rmNearestTiesToEven),
+ // fcInfinity * fcNormal = fcInfinity
+ std::make_tuple(0x7ff0000000000000ull, 0, 0x3ff0000000000000ull, 0,
+ APFloat::fcInfinity, APFloat::rmNearestTiesToEven),
+ // fcZero * fcZero = fcZero
+ std::make_tuple(0, 0, 0, 0, APFloat::fcZero,
+ APFloat::rmNearestTiesToEven),
+ // fcZero * fcNormal = fcZero
+ std::make_tuple(0, 0, 0x3ff0000000000000ull, 0, APFloat::fcZero,
+ APFloat::rmNearestTiesToEven),
+ };
+
+ for (auto Tp : Data) {
+ uint64_t Op1[2], Op2[2];
+ APFloat::fltCategory Expected;
+ APFloat::roundingMode RM;
+ std::tie(Op1[0], Op1[1], Op2[0], Op2[1], Expected, RM) = Tp;
+
+ {
+ APFloat A1(APFloat::PPCDoubleDouble(), APInt(128, 2, Op1));
+ APFloat A2(APFloat::PPCDoubleDouble(), APInt(128, 2, Op2));
+ A1.multiply(A2, RM);
+
+ EXPECT_EQ(Expected, A1.getCategory())
+ << formatv("({0:x} + {1:x}) * ({2:x} + {3:x})", Op1[0], Op1[1],
+ Op2[0], Op2[1])
+ .str();
+ }
+ {
+ APFloat A1(APFloat::PPCDoubleDouble(), APInt(128, 2, Op1));
+ APFloat A2(APFloat::PPCDoubleDouble(), APInt(128, 2, Op2));
+ A2.multiply(A1, RM);
+
+ EXPECT_EQ(Expected, A2.getCategory())
+ << formatv("({0:x} + {1:x}) * ({2:x} + {3:x})", Op2[0], Op2[1],
+ Op1[0], Op1[1])
+ .str();
+ }
+ }
+}
+
TEST(APFloatTest, PPCDoubleDoubleMultiply) {
using DataType = std::tuple<uint64_t, uint64_t, uint64_t, uint64_t, uint64_t,
uint64_t, APFloat::roundingMode>;
- // TODO: Only a sanity check for now. Add more edge cases when the
- // double-double algorithm is implemented.
DataType Data[] = {
// 1/3 * 3 = 1.0
std::make_tuple(0x3fd5555555555555ull, 0x3c75555555555556ull,
0x4008000000000000ull, 0, 0x3ff0000000000000ull, 0,
APFloat::rmNearestTiesToEven),
+ // (1 + epsilon) * (1 + 0) = fcZero
+ std::make_tuple(0x3ff0000000000000ull, 0x0000000000000001ull,
+ 0x3ff0000000000000ull, 0, 0x3ff0000000000000ull,
+ 0x0000000000000001ull, APFloat::rmNearestTiesToEven),
+ // (1 + epsilon) * (1 + epsilon) = 1 + 2 * epsilon
+ std::make_tuple(0x3ff0000000000000ull, 0x0000000000000001ull,
+ 0x3ff0000000000000ull, 0x0000000000000001ull,
+ 0x3ff0000000000000ull, 0x0000000000000002ull,
+ APFloat::rmNearestTiesToEven),
+ // -(1 + epsilon) * (1 + epsilon) = -1
+ std::make_tuple(0xbff0000000000000ull, 0x0000000000000001ull,
+ 0x3ff0000000000000ull, 0x0000000000000001ull,
+ 0xbff0000000000000ull, 0, APFloat::rmNearestTiesToEven),
+ // (0.5 + 0) * (1 + 2 * epsilon) = 0.5 + epsilon
+ std::make_tuple(0x3fe0000000000000ull, 0, 0x3ff0000000000000ull,
+ 0x0000000000000002ull, 0x3fe0000000000000ull,
+ 0x0000000000000001ull, APFloat::rmNearestTiesToEven),
+ // (0.5 + 0) * (1 + epsilon) = 0.5
+ std::make_tuple(0x3fe0000000000000ull, 0, 0x3ff0000000000000ull,
+ 0x0000000000000001ull, 0x3fe0000000000000ull, 0,
+ APFloat::rmNearestTiesToEven),
+ // __LDBL_MAX__ * (1 + 1 << 106) = inf
+ std::make_tuple(0x7fefffffffffffffull, 0x7c8ffffffffffffeull,
+ 0x3ff0000000000000ull, 0x3950000000000000ull,
+ 0x7ff0000000000000ull, 0, APFloat::rmNearestTiesToEven),
+ // __LDBL_MAX__ * (1 + 1 << 107) > __LDBL_MAX__, but not inf, yes =_=|||
+ std::make_tuple(0x7fefffffffffffffull, 0x7c8ffffffffffffeull,
+ 0x3ff0000000000000ull, 0x3940000000000000ull,
+ 0x7fefffffffffffffull, 0x7c8fffffffffffffull,
+ APFloat::rmNearestTiesToEven),
+ // __LDBL_MAX__ * (1 + 1 << 108) = __LDBL_MAX__
+ std::make_tuple(0x7fefffffffffffffull, 0x7c8ffffffffffffeull,
+ 0x3ff0000000000000ull, 0x3930000000000000ull,
+ 0x7fefffffffffffffull, 0x7c8ffffffffffffeull,
+ APFloat::rmNearestTiesToEven),
};
for (auto Tp : Data) {
@@ -3320,18 +3530,34 @@ TEST(APFloatTest, PPCDoubleDoubleMultiply) {
APFloat::roundingMode RM;
std::tie(Op1[0], Op1[1], Op2[0], Op2[1], Expected[0], Expected[1], RM) = Tp;
- APFloat A1(APFloat::PPCDoubleDouble(), APInt(128, 2, Op1));
- APFloat A2(APFloat::PPCDoubleDouble(), APInt(128, 2, Op2));
- A1.multiply(A2, RM);
-
- EXPECT_EQ(Expected[0], A1.bitcastToAPInt().getRawData()[0])
- << formatv("({0:x} + {1:x}) * ({2:x} + {3:x})", Op1[0], Op1[1], Op2[0],
- Op2[1])
- .str();
- EXPECT_EQ(Expected[1], A1.bitcastToAPInt().getRawData()[1])
- << formatv("({0:x} + {1:x}) * ({2:x} + {3:x})", Op1[0], Op1[1], Op2[0],
- Op2[1])
- .str();
+ {
+ APFloat A1(APFloat::PPCDoubleDouble(), APInt(128, 2, Op1));
+ APFloat A2(APFloat::PPCDoubleDouble(), APInt(128, 2, Op2));
+ A1.multiply(A2, RM);
+
+ EXPECT_EQ(Expected[0], A1.bitcastToAPInt().getRawData()[0])
+ << formatv("({0:x} + {1:x}) * ({2:x} + {3:x})", Op1[0], Op1[1],
+ Op2[0], Op2[1])
+ .str();
+ EXPECT_EQ(Expected[1], A1.bitcastToAPInt().getRawData()[1])
+ << formatv("({0:x} + {1:x}) * ({2:x} + {3:x})", Op1[0], Op1[1],
+ Op2[0], Op2[1])
+ .str();
+ }
+ {
+ APFloat A1(APFloat::PPCDoubleDouble(), APInt(128, 2, Op1));
+ APFloat A2(APFloat::PPCDoubleDouble(), APInt(128, 2, Op2));
+ A2.multiply(A1, RM);
+
+ EXPECT_EQ(Expected[0], A2.bitcastToAPInt().getRawData()[0])
+ << formatv("({0:x} + {1:x}) * ({2:x} + {3:x})", Op2[0], Op2[1],
+ Op1[0], Op1[1])
+ .str();
+ EXPECT_EQ(Expected[1], A2.bitcastToAPInt().getRawData()[1])
+ << formatv("({0:x} + {1:x}) * ({2:x} + {3:x})", Op2[0], Op2[1],
+ Op1[0], Op1[1])
+ .str();
+ }
}
}
@@ -3496,12 +3722,53 @@ TEST(APFloatTest, PPCDoubleDoubleCompare) {
APFloat A1(APFloat::PPCDoubleDouble(), APInt(128, 2, Op1));
APFloat A2(APFloat::PPCDoubleDouble(), APInt(128, 2, Op2));
EXPECT_EQ(Expected, A1.compare(A2))
- << formatv("({0:x} + {1:x}) - ({2:x} + {3:x})", Op1[0], Op1[1], Op2[0],
+ << formatv("compare(({0:x} + {1:x}), ({2:x} + {3:x}))", Op1[0], Op1[1],
+ Op2[0], Op2[1])
+ .str();
+ }
+}
+
+TEST(APFloatTest, PPCDoubleDoubleBitwiseIsEqual) {
+ using DataType = std::tuple<uint64_t, uint64_t, uint64_t, uint64_t, bool>;
+
+ DataType Data[] = {
+ // (1 + 0) = (1 + 0)
+ std::make_tuple(0x3ff0000000000000ull, 0, 0x3ff0000000000000ull, 0, true),
+ // (1 + 0) != (1.00...1 + 0)
+ std::make_tuple(0x3ff0000000000000ull, 0, 0x3ff0000000000001ull, 0,
+ false),
+ // NaN = NaN
+ std::make_tuple(0x7ff8000000000000ull, 0, 0x7ff8000000000000ull, 0, true),
+ // NaN != NaN with a different bit pattern
+ std::make_tuple(0x7ff8000000000000ull, 0, 0x7ff8000000000000ull,
+ 0x3ff0000000000000ull, false),
+ // Inf = Inf
+ std::make_tuple(0x7ff0000000000000ull, 0, 0x7ff0000000000000ull, 0, true),
+ };
+
+ for (auto Tp : Data) {
+ uint64_t Op1[2], Op2[2];
+ bool Expected;
+ std::tie(Op1[0], Op1[1], Op2[0], Op2[1], Expected) = Tp;
+
+ APFloat A1(APFloat::PPCDoubleDouble(), APInt(128, 2, Op1));
+ APFloat A2(APFloat::PPCDoubleDouble(), APInt(128, 2, Op2));
+ EXPECT_EQ(Expected, A1.bitwiseIsEqual(A2))
+ << formatv("({0:x} + {1:x}) = ({2:x} + {3:x})", Op1[0], Op1[1], Op2[0],
Op2[1])
.str();
}
}
+TEST(APFloatTest, PPCDoubleDoubleHashValue) {
+ uint64_t Data1[] = {0x3ff0000000000001ull, 0x0000000000000001ull};
+ uint64_t Data2[] = {0x3ff0000000000001ull, 0};
+ // The hash values are *hopefully* different.
+ EXPECT_NE(
+ hash_value(APFloat(APFloat::PPCDoubleDouble(), APInt(128, 2, Data1))),
+ hash_value(APFloat(APFloat::PPCDoubleDouble(), APInt(128, 2, Data2))));
+}
+
TEST(APFloatTest, PPCDoubleDoubleChangeSign) {
uint64_t Data[] = {
0x400f000000000000ull, 0xbcb0000000000000ull,
@@ -3531,6 +3798,13 @@ TEST(APFloatTest, PPCDoubleDoubleFactories) {
}
{
uint64_t Data[] = {
+ 0x7fefffffffffffffull, 0x7c8ffffffffffffeull,
+ };
+ EXPECT_EQ(APInt(128, 2, Data),
+ APFloat::getLargest(APFloat::PPCDoubleDouble()).bitcastToAPInt());
+ }
+ {
+ uint64_t Data[] = {
0x0000000000000001ull, 0,
};
EXPECT_EQ(
@@ -3553,24 +3827,72 @@ TEST(APFloatTest, PPCDoubleDoubleFactories) {
}
{
uint64_t Data[] = {
+ 0xffefffffffffffffull, 0xfc8ffffffffffffeull,
+ };
+ EXPECT_EQ(
+ APInt(128, 2, Data),
+ APFloat::getLargest(APFloat::PPCDoubleDouble(), true).bitcastToAPInt());
+ }
+ {
+ uint64_t Data[] = {
0x8000000000000001ull, 0x0000000000000000ull,
};
EXPECT_EQ(APInt(128, 2, Data),
APFloat::getSmallest(APFloat::PPCDoubleDouble(), true)
.bitcastToAPInt());
}
-
- EXPECT_EQ(0x8360000000000000ull,
- APFloat::getSmallestNormalized(APFloat::PPCDoubleDouble(), true)
- .bitcastToAPInt()
- .getRawData()[0]);
- EXPECT_EQ(0x0000000000000000ull,
- APFloat::getSmallestNormalized(APFloat::PPCDoubleDouble(), true)
- .getSecondFloat()
- .bitcastToAPInt()
- .getRawData()[0]);
-
+ {
+ uint64_t Data[] = {
+ 0x8360000000000000ull, 0x0000000000000000ull,
+ };
+ EXPECT_EQ(APInt(128, 2, Data),
+ APFloat::getSmallestNormalized(APFloat::PPCDoubleDouble(), true)
+ .bitcastToAPInt());
+ }
EXPECT_TRUE(APFloat::getSmallest(APFloat::PPCDoubleDouble()).isSmallest());
EXPECT_TRUE(APFloat::getLargest(APFloat::PPCDoubleDouble()).isLargest());
}
+
+TEST(APFloatTest, PPCDoubleDoubleIsDenormal) {
+ EXPECT_TRUE(APFloat::getSmallest(APFloat::PPCDoubleDouble()).isDenormal());
+ EXPECT_FALSE(APFloat::getLargest(APFloat::PPCDoubleDouble()).isDenormal());
+ EXPECT_FALSE(
+ APFloat::getSmallestNormalized(APFloat::PPCDoubleDouble()).isDenormal());
+ {
+ // (4 + 3) is not normalized
+ uint64_t Data[] = {
+ 0x4010000000000000ull, 0x4008000000000000ull,
+ };
+ EXPECT_TRUE(
+ APFloat(APFloat::PPCDoubleDouble(), APInt(128, 2, Data)).isDenormal());
+ }
+}
+
+TEST(APFloatTest, PPCDoubleDoubleScalbn) {
+ // 3.0 + 3.0 << 53
+ uint64_t Input[] = {
+ 0x4008000000000000ull, 0x3cb8000000000000ull,
+ };
+ APFloat Result =
+ scalbn(APFloat(APFloat::PPCDoubleDouble(), APInt(128, 2, Input)), 1,
+ APFloat::rmNearestTiesToEven);
+ // 6.0 + 6.0 << 53
+ EXPECT_EQ(0x4018000000000000ull, Result.bitcastToAPInt().getRawData()[0]);
+ EXPECT_EQ(0x3cc8000000000000ull, Result.bitcastToAPInt().getRawData()[1]);
+}
+
+TEST(APFloatTest, PPCDoubleDoubleFrexp) {
+ // 3.0 + 3.0 << 53
+ uint64_t Input[] = {
+ 0x4008000000000000ull, 0x3cb8000000000000ull,
+ };
+ 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]);
+}
}
diff --git a/unittests/ADT/APIntTest.cpp b/unittests/ADT/APIntTest.cpp
index cbffdc096fbed..65481f5b2f220 100644
--- a/unittests/ADT/APIntTest.cpp
+++ b/unittests/ADT/APIntTest.cpp
@@ -37,6 +37,11 @@ TEST(APIntTest, i64_ArithmeticRightShiftNegative) {
EXPECT_EQ(neg_one, neg_one.ashr(7));
}
+TEST(APIntTest, i64_LogicalRightShiftNegative) {
+ const APInt neg_one(128, static_cast<uint64_t>(-1), true);
+ EXPECT_EQ(0, neg_one.lshr(257));
+}
+
TEST(APIntTest, i128_NegativeCount) {
APInt Minus3(128, static_cast<uint64_t>(-3), true);
EXPECT_EQ(126u, Minus3.countLeadingOnes());
@@ -63,6 +68,26 @@ TEST(APIntTest, i33_Count) {
EXPECT_EQ(((uint64_t)-2)&((1ull<<33) -1), i33minus2.getZExtValue());
}
+TEST(APIntTest, i61_Count) {
+ APInt i61(61, 1 << 15);
+ EXPECT_EQ(45u, i61.countLeadingZeros());
+ EXPECT_EQ(0u, i61.countLeadingOnes());
+ EXPECT_EQ(16u, i61.getActiveBits());
+ EXPECT_EQ(15u, i61.countTrailingZeros());
+ EXPECT_EQ(1u, i61.countPopulation());
+ EXPECT_EQ(static_cast<int64_t>(1 << 15), i61.getSExtValue());
+ EXPECT_EQ(static_cast<uint64_t>(1 << 15), i61.getZExtValue());
+
+ i61.setBits(8, 19);
+ EXPECT_EQ(42u, i61.countLeadingZeros());
+ EXPECT_EQ(0u, i61.countLeadingOnes());
+ EXPECT_EQ(19u, i61.getActiveBits());
+ EXPECT_EQ(8u, i61.countTrailingZeros());
+ EXPECT_EQ(11u, i61.countPopulation());
+ EXPECT_EQ(static_cast<int64_t>((1 << 19) - (1 << 8)), i61.getSExtValue());
+ EXPECT_EQ(static_cast<uint64_t>((1 << 19) - (1 << 8)), i61.getZExtValue());
+}
+
TEST(APIntTest, i65_Count) {
APInt i65(65, 0, true);
EXPECT_EQ(65u, i65.countLeadingZeros());
@@ -118,6 +143,80 @@ TEST(APIntTest, i128_PositiveCount) {
EXPECT_EQ(1u, one.countPopulation());
EXPECT_EQ(1, one.getSExtValue());
EXPECT_EQ(1u, one.getZExtValue());
+
+ APInt s128(128, 2, true);
+ EXPECT_EQ(126u, s128.countLeadingZeros());
+ EXPECT_EQ(0u, s128.countLeadingOnes());
+ EXPECT_EQ(2u, s128.getActiveBits());
+ EXPECT_EQ(1u, s128.countTrailingZeros());
+ EXPECT_EQ(0u, s128.countTrailingOnes());
+ EXPECT_EQ(1u, s128.countPopulation());
+ EXPECT_EQ(2, s128.getSExtValue());
+ EXPECT_EQ(2u, s128.getZExtValue());
+
+ // NOP Test
+ s128.setBits(42, 42);
+ EXPECT_EQ(126u, s128.countLeadingZeros());
+ EXPECT_EQ(0u, s128.countLeadingOnes());
+ EXPECT_EQ(2u, s128.getActiveBits());
+ EXPECT_EQ(1u, s128.countTrailingZeros());
+ EXPECT_EQ(0u, s128.countTrailingOnes());
+ EXPECT_EQ(1u, s128.countPopulation());
+ EXPECT_EQ(2, s128.getSExtValue());
+ EXPECT_EQ(2u, s128.getZExtValue());
+
+ s128.setBits(3, 32);
+ EXPECT_EQ(96u, s128.countLeadingZeros());
+ EXPECT_EQ(0u, s128.countLeadingOnes());
+ EXPECT_EQ(32u, s128.getActiveBits());
+ EXPECT_EQ(33u, s128.getMinSignedBits());
+ EXPECT_EQ(1u, s128.countTrailingZeros());
+ EXPECT_EQ(0u, s128.countTrailingOnes());
+ EXPECT_EQ(30u, s128.countPopulation());
+ EXPECT_EQ(static_cast<uint32_t>((~0u << 3) | 2), s128.getZExtValue());
+
+ s128.setBits(62, 128);
+ EXPECT_EQ(0u, s128.countLeadingZeros());
+ EXPECT_EQ(66u, s128.countLeadingOnes());
+ EXPECT_EQ(128u, s128.getActiveBits());
+ EXPECT_EQ(63u, s128.getMinSignedBits());
+ EXPECT_EQ(1u, s128.countTrailingZeros());
+ EXPECT_EQ(0u, s128.countTrailingOnes());
+ EXPECT_EQ(96u, s128.countPopulation());
+ EXPECT_EQ(static_cast<int64_t>((3ull << 62) |
+ static_cast<uint32_t>((~0u << 3) | 2)),
+ s128.getSExtValue());
+}
+
+TEST(APIntTest, i256) {
+ APInt s256(256, 15, true);
+ EXPECT_EQ(252u, s256.countLeadingZeros());
+ EXPECT_EQ(0u, s256.countLeadingOnes());
+ EXPECT_EQ(4u, s256.getActiveBits());
+ EXPECT_EQ(0u, s256.countTrailingZeros());
+ EXPECT_EQ(4u, s256.countTrailingOnes());
+ EXPECT_EQ(4u, s256.countPopulation());
+ EXPECT_EQ(15, s256.getSExtValue());
+ EXPECT_EQ(15u, s256.getZExtValue());
+
+ s256.setBits(62, 66);
+ EXPECT_EQ(190u, s256.countLeadingZeros());
+ EXPECT_EQ(0u, s256.countLeadingOnes());
+ EXPECT_EQ(66u, s256.getActiveBits());
+ EXPECT_EQ(67u, s256.getMinSignedBits());
+ EXPECT_EQ(0u, s256.countTrailingZeros());
+ EXPECT_EQ(4u, s256.countTrailingOnes());
+ EXPECT_EQ(8u, s256.countPopulation());
+
+ s256.setBits(60, 256);
+ EXPECT_EQ(0u, s256.countLeadingZeros());
+ EXPECT_EQ(196u, s256.countLeadingOnes());
+ EXPECT_EQ(256u, s256.getActiveBits());
+ EXPECT_EQ(61u, s256.getMinSignedBits());
+ EXPECT_EQ(0u, s256.countTrailingZeros());
+ EXPECT_EQ(4u, s256.countTrailingOnes());
+ EXPECT_EQ(200u, s256.countPopulation());
+ EXPECT_EQ(static_cast<int64_t>((~0ull << 60) | 15), s256.getSExtValue());
}
TEST(APIntTest, i1) {
@@ -158,6 +257,36 @@ TEST(APIntTest, i1) {
EXPECT_EQ(two, one - neg_one);
EXPECT_EQ(zero, one - one);
+ // And
+ EXPECT_EQ(zero, zero & zero);
+ EXPECT_EQ(zero, one & zero);
+ EXPECT_EQ(zero, zero & one);
+ EXPECT_EQ(one, one & one);
+ EXPECT_EQ(zero, zero & zero);
+ EXPECT_EQ(zero, neg_one & zero);
+ EXPECT_EQ(zero, zero & neg_one);
+ EXPECT_EQ(neg_one, neg_one & neg_one);
+
+ // Or
+ EXPECT_EQ(zero, zero | zero);
+ EXPECT_EQ(one, one | zero);
+ EXPECT_EQ(one, zero | one);
+ EXPECT_EQ(one, one | one);
+ EXPECT_EQ(zero, zero | zero);
+ EXPECT_EQ(neg_one, neg_one | zero);
+ EXPECT_EQ(neg_one, zero | neg_one);
+ EXPECT_EQ(neg_one, neg_one | neg_one);
+
+ // Xor
+ EXPECT_EQ(zero, zero ^ zero);
+ EXPECT_EQ(one, one ^ zero);
+ EXPECT_EQ(one, zero ^ one);
+ EXPECT_EQ(zero, one ^ one);
+ EXPECT_EQ(zero, zero ^ zero);
+ EXPECT_EQ(neg_one, neg_one ^ zero);
+ EXPECT_EQ(neg_one, zero ^ neg_one);
+ EXPECT_EQ(zero, neg_one ^ neg_one);
+
// Shifts.
EXPECT_EQ(zero, one << one);
EXPECT_EQ(one, one << zero);
@@ -416,6 +545,58 @@ TEST(APIntTest, compareLargeIntegers) {
EXPECT_TRUE(!MinusTwo.slt(MinusTwo));
}
+TEST(APIntTest, binaryOpsWithRawIntegers) {
+ // Single word check.
+ uint64_t E1 = 0x2CA7F46BF6569915ULL;
+ APInt A1(64, E1);
+
+ EXPECT_EQ(A1 & E1, E1);
+ EXPECT_EQ(A1 & 0, 0);
+ EXPECT_EQ(A1 & 1, 1);
+ EXPECT_EQ(A1 & 5, 5);
+ EXPECT_EQ(A1 & UINT64_MAX, E1);
+
+ EXPECT_EQ(A1 | E1, E1);
+ EXPECT_EQ(A1 | 0, E1);
+ EXPECT_EQ(A1 | 1, E1);
+ EXPECT_EQ(A1 | 2, E1 | 2);
+ EXPECT_EQ(A1 | UINT64_MAX, UINT64_MAX);
+
+ EXPECT_EQ(A1 ^ E1, 0);
+ EXPECT_EQ(A1 ^ 0, E1);
+ EXPECT_EQ(A1 ^ 1, E1 ^ 1);
+ EXPECT_EQ(A1 ^ 7, E1 ^ 7);
+ EXPECT_EQ(A1 ^ UINT64_MAX, ~E1);
+
+ // Multiword check.
+ uint64_t N = 0xEB6EB136591CBA21ULL;
+ APInt::WordType E2[4] = {
+ N,
+ 0x7B9358BD6A33F10AULL,
+ 0x7E7FFA5EADD8846ULL,
+ 0x305F341CA00B613DULL
+ };
+ APInt A2(APInt::APINT_BITS_PER_WORD*4, E2);
+
+ EXPECT_EQ(A2 & N, N);
+ EXPECT_EQ(A2 & 0, 0);
+ EXPECT_EQ(A2 & 1, 1);
+ EXPECT_EQ(A2 & 5, 1);
+ EXPECT_EQ(A2 & UINT64_MAX, N);
+
+ EXPECT_EQ(A2 | N, A2);
+ EXPECT_EQ(A2 | 0, A2);
+ EXPECT_EQ(A2 | 1, A2);
+ EXPECT_EQ(A2 | 2, A2 + 2);
+ EXPECT_EQ(A2 | UINT64_MAX, A2 - N + UINT64_MAX);
+
+ EXPECT_EQ(A2 ^ N, A2 - N);
+ EXPECT_EQ(A2 ^ 0, A2);
+ EXPECT_EQ(A2 ^ 1, A2 - 1);
+ EXPECT_EQ(A2 ^ 7, A2 + 5);
+ EXPECT_EQ(A2 ^ UINT64_MAX, A2 - N + ~N);
+}
+
TEST(APIntTest, rvalue_arithmetic) {
// Test all combinations of lvalue/rvalue lhs/rhs of add/sub
@@ -585,6 +766,150 @@ TEST(APIntTest, rvalue_arithmetic) {
}
}
+TEST(APIntTest, rvalue_bitwise) {
+ // Test all combinations of lvalue/rvalue lhs/rhs of and/or/xor
+
+ // Lamdba to return an APInt by value, but also provide the raw value of the
+ // allocated data.
+ auto getRValue = [](const char *HexString, uint64_t const *&RawData) {
+ APInt V(129, HexString, 16);
+ RawData = V.getRawData();
+ return V;
+ };
+
+ APInt Ten(129, "A", 16);
+ APInt Twelve(129, "C", 16);
+
+ const uint64_t *RawDataL = nullptr;
+ const uint64_t *RawDataR = nullptr;
+
+ {
+ // 12 & 10 = 8
+ APInt AndLL = Ten & Twelve;
+ EXPECT_EQ(AndLL, 0x8);
+
+ APInt AndLR = Ten & getRValue("C", RawDataR);
+ EXPECT_EQ(AndLR, 0x8);
+ EXPECT_EQ(AndLR.getRawData(), RawDataR);
+
+ APInt AndRL = getRValue("A", RawDataL) & Twelve;
+ EXPECT_EQ(AndRL, 0x8);
+ EXPECT_EQ(AndRL.getRawData(), RawDataL);
+
+ APInt AndRR = getRValue("A", RawDataL) & getRValue("C", RawDataR);
+ EXPECT_EQ(AndRR, 0x8);
+ EXPECT_EQ(AndRR.getRawData(), RawDataR);
+
+ // LValue's and constants
+ APInt AndLK = Ten & 0xc;
+ EXPECT_EQ(AndLK, 0x8);
+
+ APInt AndKL = 0xa & Twelve;
+ EXPECT_EQ(AndKL, 0x8);
+
+ // RValue's and constants
+ APInt AndRK = getRValue("A", RawDataL) & 0xc;
+ EXPECT_EQ(AndRK, 0x8);
+ EXPECT_EQ(AndRK.getRawData(), RawDataL);
+
+ APInt AndKR = 0xa & getRValue("C", RawDataR);
+ EXPECT_EQ(AndKR, 0x8);
+ EXPECT_EQ(AndKR.getRawData(), RawDataR);
+ }
+
+ {
+ // 12 | 10 = 14
+ APInt OrLL = Ten | Twelve;
+ EXPECT_EQ(OrLL, 0xe);
+
+ APInt OrLR = Ten | getRValue("C", RawDataR);
+ EXPECT_EQ(OrLR, 0xe);
+ EXPECT_EQ(OrLR.getRawData(), RawDataR);
+
+ APInt OrRL = getRValue("A", RawDataL) | Twelve;
+ EXPECT_EQ(OrRL, 0xe);
+ EXPECT_EQ(OrRL.getRawData(), RawDataL);
+
+ APInt OrRR = getRValue("A", RawDataL) | getRValue("C", RawDataR);
+ EXPECT_EQ(OrRR, 0xe);
+ EXPECT_EQ(OrRR.getRawData(), RawDataR);
+
+ // LValue's and constants
+ APInt OrLK = Ten | 0xc;
+ EXPECT_EQ(OrLK, 0xe);
+
+ APInt OrKL = 0xa | Twelve;
+ EXPECT_EQ(OrKL, 0xe);
+
+ // RValue's and constants
+ APInt OrRK = getRValue("A", RawDataL) | 0xc;
+ EXPECT_EQ(OrRK, 0xe);
+ EXPECT_EQ(OrRK.getRawData(), RawDataL);
+
+ APInt OrKR = 0xa | getRValue("C", RawDataR);
+ EXPECT_EQ(OrKR, 0xe);
+ EXPECT_EQ(OrKR.getRawData(), RawDataR);
+ }
+
+ {
+ // 12 ^ 10 = 6
+ APInt XorLL = Ten ^ Twelve;
+ EXPECT_EQ(XorLL, 0x6);
+
+ APInt XorLR = Ten ^ getRValue("C", RawDataR);
+ EXPECT_EQ(XorLR, 0x6);
+ EXPECT_EQ(XorLR.getRawData(), RawDataR);
+
+ APInt XorRL = getRValue("A", RawDataL) ^ Twelve;
+ EXPECT_EQ(XorRL, 0x6);
+ EXPECT_EQ(XorRL.getRawData(), RawDataL);
+
+ APInt XorRR = getRValue("A", RawDataL) ^ getRValue("C", RawDataR);
+ EXPECT_EQ(XorRR, 0x6);
+ EXPECT_EQ(XorRR.getRawData(), RawDataR);
+
+ // LValue's and constants
+ APInt XorLK = Ten ^ 0xc;
+ EXPECT_EQ(XorLK, 0x6);
+
+ APInt XorKL = 0xa ^ Twelve;
+ EXPECT_EQ(XorKL, 0x6);
+
+ // RValue's and constants
+ APInt XorRK = getRValue("A", RawDataL) ^ 0xc;
+ EXPECT_EQ(XorRK, 0x6);
+ EXPECT_EQ(XorRK.getRawData(), RawDataL);
+
+ APInt XorKR = 0xa ^ getRValue("C", RawDataR);
+ EXPECT_EQ(XorKR, 0x6);
+ EXPECT_EQ(XorKR.getRawData(), RawDataR);
+ }
+}
+
+TEST(APIntTest, rvalue_invert) {
+ // Lamdba to return an APInt by value, but also provide the raw value of the
+ // allocated data.
+ auto getRValue = [](const char *HexString, uint64_t const *&RawData) {
+ APInt V(129, HexString, 16);
+ RawData = V.getRawData();
+ return V;
+ };
+
+ APInt One(129, 1);
+ APInt NegativeTwo(129, -2ULL, true);
+
+ const uint64_t *RawData = nullptr;
+
+ {
+ // ~1 = -2
+ APInt NegL = ~One;
+ EXPECT_EQ(NegL, NegativeTwo);
+
+ APInt NegR = ~getRValue("1", RawData);
+ EXPECT_EQ(NegR, NegativeTwo);
+ EXPECT_EQ(NegR.getRawData(), RawData);
+ }
+}
// Tests different div/rem varaints using scheme (a * b + c) / a
void testDiv(APInt a, APInt b, APInt c) {
@@ -701,7 +1026,6 @@ TEST(APIntTest, fromString) {
EXPECT_EQ(APInt(32, uint64_t(-3LL)), APInt(32, "-11", 2));
EXPECT_EQ(APInt(32, uint64_t(-4LL)), APInt(32, "-100", 2));
-
EXPECT_EQ(APInt(32, 0), APInt(32, "0", 8));
EXPECT_EQ(APInt(32, 1), APInt(32, "1", 8));
EXPECT_EQ(APInt(32, 7), APInt(32, "7", 8));
@@ -723,7 +1047,6 @@ TEST(APIntTest, fromString) {
EXPECT_EQ(APInt(32, uint64_t(-15LL)), APInt(32, "-17", 8));
EXPECT_EQ(APInt(32, uint64_t(-16LL)), APInt(32, "-20", 8));
-
EXPECT_EQ(APInt(32, 0), APInt(32, "0", 10));
EXPECT_EQ(APInt(32, 1), APInt(32, "1", 10));
EXPECT_EQ(APInt(32, 9), APInt(32, "9", 10));
@@ -738,7 +1061,6 @@ TEST(APIntTest, fromString) {
EXPECT_EQ(APInt(32, uint64_t(-19LL)), APInt(32, "-19", 10));
EXPECT_EQ(APInt(32, uint64_t(-20LL)), APInt(32, "-20", 10));
-
EXPECT_EQ(APInt(32, 0), APInt(32, "0", 16));
EXPECT_EQ(APInt(32, 1), APInt(32, "1", 16));
EXPECT_EQ(APInt(32, 15), APInt(32, "F", 16));
@@ -759,7 +1081,7 @@ TEST(APIntTest, fromString) {
EXPECT_EQ(APInt(32, 36), APInt(32, "10", 36));
EXPECT_EQ(APInt(32, 71), APInt(32, "1Z", 36));
EXPECT_EQ(APInt(32, 72), APInt(32, "20", 36));
-
+
EXPECT_EQ(APInt(32, uint64_t(-0LL)), APInt(32, "-0", 36));
EXPECT_EQ(APInt(32, uint64_t(-1LL)), APInt(32, "-1", 36));
EXPECT_EQ(APInt(32, uint64_t(-35LL)), APInt(32, "-Z", 36));
@@ -978,6 +1300,29 @@ TEST(APIntTest, Rotate) {
EXPECT_EQ(APInt(8, 1), APInt(8, 16).rotl(4));
EXPECT_EQ(APInt(8, 16), APInt(8, 16).rotl(8));
+ EXPECT_EQ(APInt(32, 2), APInt(32, 1).rotl(33));
+ EXPECT_EQ(APInt(32, 2), APInt(32, 1).rotl(APInt(32, 33)));
+
+ EXPECT_EQ(APInt(32, 2), APInt(32, 1).rotl(33));
+ EXPECT_EQ(APInt(32, 2), APInt(32, 1).rotl(APInt(32, 33)));
+ EXPECT_EQ(APInt(32, 2), APInt(32, 1).rotl(APInt(33, 33)));
+ EXPECT_EQ(APInt(32, (1 << 8)), APInt(32, 1).rotl(APInt(32, 40)));
+ EXPECT_EQ(APInt(32, (1 << 30)), APInt(32, 1).rotl(APInt(31, 30)));
+ EXPECT_EQ(APInt(32, (1 << 31)), APInt(32, 1).rotl(APInt(31, 31)));
+
+ EXPECT_EQ(APInt(32, 1), APInt(32, 1).rotl(APInt(1, 0)));
+ EXPECT_EQ(APInt(32, 2), APInt(32, 1).rotl(APInt(1, 1)));
+
+ EXPECT_EQ(APInt(32, 16), APInt(32, 1).rotl(APInt(3, 4)));
+
+ EXPECT_EQ(APInt(32, 1), APInt(32, 1).rotl(APInt(64, 64)));
+ EXPECT_EQ(APInt(32, 2), APInt(32, 1).rotl(APInt(64, 65)));
+
+ EXPECT_EQ(APInt(7, 24), APInt(7, 3).rotl(APInt(7, 3)));
+ EXPECT_EQ(APInt(7, 24), APInt(7, 3).rotl(APInt(7, 10)));
+ EXPECT_EQ(APInt(7, 24), APInt(7, 3).rotl(APInt(5, 10)));
+ EXPECT_EQ(APInt(7, 6), APInt(7, 3).rotl(APInt(12, 120)));
+
EXPECT_EQ(APInt(8, 16), APInt(8, 16).rotr(0));
EXPECT_EQ(APInt(8, 8), APInt(8, 16).rotr(1));
EXPECT_EQ(APInt(8, 4), APInt(8, 16).rotr(2));
@@ -990,9 +1335,36 @@ TEST(APIntTest, Rotate) {
EXPECT_EQ(APInt(8, 16), APInt(8, 1).rotr(4));
EXPECT_EQ(APInt(8, 1), APInt(8, 1).rotr(8));
- APInt Big(256, "00004000800000000000000000003fff8000000000000000", 16);
- APInt Rot(256, "3fff80000000000000000000000000000000000040008000", 16);
+ EXPECT_EQ(APInt(32, (1 << 31)), APInt(32, 1).rotr(33));
+ EXPECT_EQ(APInt(32, (1 << 31)), APInt(32, 1).rotr(APInt(32, 33)));
+
+ EXPECT_EQ(APInt(32, (1 << 31)), APInt(32, 1).rotr(33));
+ EXPECT_EQ(APInt(32, (1 << 31)), APInt(32, 1).rotr(APInt(32, 33)));
+ EXPECT_EQ(APInt(32, (1 << 31)), APInt(32, 1).rotr(APInt(33, 33)));
+ EXPECT_EQ(APInt(32, (1 << 24)), APInt(32, 1).rotr(APInt(32, 40)));
+
+ EXPECT_EQ(APInt(32, (1 << 2)), APInt(32, 1).rotr(APInt(31, 30)));
+ EXPECT_EQ(APInt(32, (1 << 1)), APInt(32, 1).rotr(APInt(31, 31)));
+
+ EXPECT_EQ(APInt(32, 1), APInt(32, 1).rotr(APInt(1, 0)));
+ EXPECT_EQ(APInt(32, (1 << 31)), APInt(32, 1).rotr(APInt(1, 1)));
+
+ EXPECT_EQ(APInt(32, (1 << 28)), APInt(32, 1).rotr(APInt(3, 4)));
+
+ EXPECT_EQ(APInt(32, 1), APInt(32, 1).rotr(APInt(64, 64)));
+ EXPECT_EQ(APInt(32, (1 << 31)), APInt(32, 1).rotr(APInt(64, 65)));
+
+ EXPECT_EQ(APInt(7, 48), APInt(7, 3).rotr(APInt(7, 3)));
+ EXPECT_EQ(APInt(7, 48), APInt(7, 3).rotr(APInt(7, 10)));
+ EXPECT_EQ(APInt(7, 48), APInt(7, 3).rotr(APInt(5, 10)));
+ EXPECT_EQ(APInt(7, 65), APInt(7, 3).rotr(APInt(12, 120)));
+
+ APInt Big(256, "00004000800000000000000000003fff8000000000000003", 16);
+ APInt Rot(256, "3fff80000000000000030000000000000000000040008000", 16);
EXPECT_EQ(Rot, Big.rotr(144));
+
+ EXPECT_EQ(APInt(32, 8), APInt(32, 1).rotl(Big));
+ EXPECT_EQ(APInt(32, (1 << 29)), APInt(32, 1).rotr(Big));
}
TEST(APIntTest, Splat) {
@@ -1010,63 +1382,63 @@ TEST(APIntTest, tcDecrement) {
// No out borrow.
{
- integerPart singleWord = ~integerPart(0) << (integerPartWidth - 1);
- integerPart carry = APInt::tcDecrement(&singleWord, 1);
- EXPECT_EQ(carry, integerPart(0));
- EXPECT_EQ(singleWord, ~integerPart(0) >> 1);
+ APInt::WordType singleWord = ~APInt::WordType(0) << (APInt::APINT_BITS_PER_WORD - 1);
+ APInt::WordType carry = APInt::tcDecrement(&singleWord, 1);
+ EXPECT_EQ(carry, APInt::WordType(0));
+ EXPECT_EQ(singleWord, ~APInt::WordType(0) >> 1);
}
// With out borrow.
{
- integerPart singleWord = 0;
- integerPart carry = APInt::tcDecrement(&singleWord, 1);
- EXPECT_EQ(carry, integerPart(1));
- EXPECT_EQ(singleWord, ~integerPart(0));
+ APInt::WordType singleWord = 0;
+ APInt::WordType carry = APInt::tcDecrement(&singleWord, 1);
+ EXPECT_EQ(carry, APInt::WordType(1));
+ EXPECT_EQ(singleWord, ~APInt::WordType(0));
}
// Test multiword decrement.
// No across word borrow, no out borrow.
{
- integerPart test[4] = {0x1, 0x1, 0x1, 0x1};
- integerPart expected[4] = {0x0, 0x1, 0x1, 0x1};
+ APInt::WordType test[4] = {0x1, 0x1, 0x1, 0x1};
+ APInt::WordType expected[4] = {0x0, 0x1, 0x1, 0x1};
APInt::tcDecrement(test, 4);
EXPECT_EQ(APInt::tcCompare(test, expected, 4), 0);
}
// 1 across word borrow, no out borrow.
{
- integerPart test[4] = {0x0, 0xF, 0x1, 0x1};
- integerPart expected[4] = {~integerPart(0), 0xE, 0x1, 0x1};
- integerPart carry = APInt::tcDecrement(test, 4);
- EXPECT_EQ(carry, integerPart(0));
+ APInt::WordType test[4] = {0x0, 0xF, 0x1, 0x1};
+ APInt::WordType expected[4] = {~APInt::WordType(0), 0xE, 0x1, 0x1};
+ APInt::WordType carry = APInt::tcDecrement(test, 4);
+ EXPECT_EQ(carry, APInt::WordType(0));
EXPECT_EQ(APInt::tcCompare(test, expected, 4), 0);
}
// 2 across word borrow, no out borrow.
{
- integerPart test[4] = {0x0, 0x0, 0xC, 0x1};
- integerPart expected[4] = {~integerPart(0), ~integerPart(0), 0xB, 0x1};
- integerPart carry = APInt::tcDecrement(test, 4);
- EXPECT_EQ(carry, integerPart(0));
+ APInt::WordType test[4] = {0x0, 0x0, 0xC, 0x1};
+ APInt::WordType expected[4] = {~APInt::WordType(0), ~APInt::WordType(0), 0xB, 0x1};
+ APInt::WordType carry = APInt::tcDecrement(test, 4);
+ EXPECT_EQ(carry, APInt::WordType(0));
EXPECT_EQ(APInt::tcCompare(test, expected, 4), 0);
}
// 3 across word borrow, no out borrow.
{
- integerPart test[4] = {0x0, 0x0, 0x0, 0x1};
- integerPart expected[4] = {~integerPart(0), ~integerPart(0), ~integerPart(0), 0x0};
- integerPart carry = APInt::tcDecrement(test, 4);
- EXPECT_EQ(carry, integerPart(0));
+ APInt::WordType test[4] = {0x0, 0x0, 0x0, 0x1};
+ APInt::WordType expected[4] = {~APInt::WordType(0), ~APInt::WordType(0), ~APInt::WordType(0), 0x0};
+ APInt::WordType carry = APInt::tcDecrement(test, 4);
+ EXPECT_EQ(carry, APInt::WordType(0));
EXPECT_EQ(APInt::tcCompare(test, expected, 4), 0);
}
// 3 across word borrow, with out borrow.
{
- integerPart test[4] = {0x0, 0x0, 0x0, 0x0};
- integerPart expected[4] = {~integerPart(0), ~integerPart(0), ~integerPart(0), ~integerPart(0)};
- integerPart carry = APInt::tcDecrement(test, 4);
- EXPECT_EQ(carry, integerPart(1));
+ APInt::WordType test[4] = {0x0, 0x0, 0x0, 0x0};
+ APInt::WordType expected[4] = {~APInt::WordType(0), ~APInt::WordType(0), ~APInt::WordType(0), ~APInt::WordType(0)};
+ APInt::WordType carry = APInt::tcDecrement(test, 4);
+ EXPECT_EQ(carry, APInt::WordType(1));
EXPECT_EQ(APInt::tcCompare(test, expected, 4), 0);
}
}
@@ -1081,17 +1453,17 @@ TEST(APIntTest, arrayAccess) {
}
// Multiword check.
- integerPart E2[4] = {
+ APInt::WordType E2[4] = {
0xEB6EB136591CBA21ULL,
0x7B9358BD6A33F10AULL,
0x7E7FFA5EADD8846ULL,
0x305F341CA00B613DULL
};
- APInt A2(integerPartWidth*4, E2);
+ APInt A2(APInt::APINT_BITS_PER_WORD*4, E2);
for (unsigned i = 0; i < 4; ++i) {
- for (unsigned j = 0; j < integerPartWidth; ++j) {
+ for (unsigned j = 0; j < APInt::APINT_BITS_PER_WORD; ++j) {
EXPECT_EQ(bool(E2[i] & (1ULL << j)),
- A2[i*integerPartWidth + j]);
+ A2[i*APInt::APINT_BITS_PER_WORD + j]);
}
}
}
@@ -1125,18 +1497,18 @@ TEST(APIntTest, nearestLogBase2) {
// Multiple word check.
// Test round up.
- integerPart I4[4] = {0x0, 0xF, 0x18, 0x0};
- APInt A4(integerPartWidth*4, I4);
+ APInt::WordType I4[4] = {0x0, 0xF, 0x18, 0x0};
+ APInt A4(APInt::APINT_BITS_PER_WORD*4, I4);
EXPECT_EQ(A4.nearestLogBase2(), A4.ceilLogBase2());
// Test round down.
- integerPart I5[4] = {0x0, 0xF, 0x10, 0x0};
- APInt A5(integerPartWidth*4, I5);
+ APInt::WordType I5[4] = {0x0, 0xF, 0x10, 0x0};
+ APInt A5(APInt::APINT_BITS_PER_WORD*4, I5);
EXPECT_EQ(A5.nearestLogBase2(), A5.logBase2());
// Test ties round up.
uint64_t I6[4] = {0x0, 0x0, 0x0, 0x18};
- APInt A6(integerPartWidth*4, I6);
+ APInt A6(APInt::APINT_BITS_PER_WORD*4, I6);
EXPECT_EQ(A6.nearestLogBase2(), A6.ceilLogBase2());
// Test BitWidth == 1 special cases.
@@ -1192,18 +1564,44 @@ TEST(APIntTest, IsSplat) {
}
TEST(APIntTest, isMask) {
- EXPECT_FALSE(APIntOps::isMask(APInt(32, 0x01010101)));
- EXPECT_FALSE(APIntOps::isMask(APInt(32, 0xf0000000)));
- EXPECT_FALSE(APIntOps::isMask(APInt(32, 0xffff0000)));
- EXPECT_FALSE(APIntOps::isMask(APInt(32, 0xff << 1)));
+ EXPECT_FALSE(APInt(32, 0x01010101).isMask());
+ EXPECT_FALSE(APInt(32, 0xf0000000).isMask());
+ EXPECT_FALSE(APInt(32, 0xffff0000).isMask());
+ EXPECT_FALSE(APInt(32, 0xff << 1).isMask());
for (int N : { 1, 2, 3, 4, 7, 8, 16, 32, 64, 127, 128, 129, 256 }) {
- EXPECT_FALSE(APIntOps::isMask(APInt(N, 0)));
+ EXPECT_FALSE(APInt(N, 0).isMask());
APInt One(N, 1);
for (int I = 1; I <= N; ++I) {
APInt MaskVal = One.shl(I) - 1;
- EXPECT_TRUE(APIntOps::isMask(MaskVal));
+ EXPECT_TRUE(MaskVal.isMask());
+ EXPECT_TRUE(MaskVal.isMask(I));
+ }
+ }
+}
+
+TEST(APIntTest, isShiftedMask) {
+ EXPECT_FALSE(APInt(32, 0x01010101).isShiftedMask());
+ EXPECT_TRUE(APInt(32, 0xf0000000).isShiftedMask());
+ EXPECT_TRUE(APInt(32, 0xffff0000).isShiftedMask());
+ EXPECT_TRUE(APInt(32, 0xff << 1).isShiftedMask());
+
+ for (int N : { 1, 2, 3, 4, 7, 8, 16, 32, 64, 127, 128, 129, 256 }) {
+ EXPECT_FALSE(APInt(N, 0).isShiftedMask());
+
+ APInt One(N, 1);
+ for (int I = 1; I < N; ++I) {
+ APInt MaskVal = One.shl(I) - 1;
+ EXPECT_TRUE(MaskVal.isShiftedMask());
+ }
+ for (int I = 1; I < N - 1; ++I) {
+ APInt MaskVal = One.shl(I);
+ EXPECT_TRUE(MaskVal.isShiftedMask());
+ }
+ for (int I = 1; I < N; ++I) {
+ APInt MaskVal = APInt::getHighBitsSet(N, I);
+ EXPECT_TRUE(MaskVal.isShiftedMask());
}
}
}
@@ -1279,3 +1677,351 @@ TEST(APIntTest, reverseBits) {
}
}
}
+
+TEST(APIntTest, insertBits) {
+ APInt iSrc(31, 0x00123456);
+
+ // Direct copy.
+ APInt i31(31, 0x76543210ull);
+ i31.insertBits(iSrc, 0);
+ EXPECT_EQ(static_cast<int64_t>(0x00123456ull), i31.getSExtValue());
+
+ // Single word src/dst insertion.
+ APInt i63(63, 0x01234567FFFFFFFFull);
+ i63.insertBits(iSrc, 4);
+ EXPECT_EQ(static_cast<int64_t>(0x012345600123456Full), i63.getSExtValue());
+
+ // Insert single word src into one word of dst.
+ APInt i120(120, UINT64_MAX, true);
+ i120.insertBits(iSrc, 8);
+ EXPECT_EQ(static_cast<int64_t>(0xFFFFFF80123456FFull), i120.getSExtValue());
+
+ // Insert single word src into two words of dst.
+ APInt i127(127, UINT64_MAX, true);
+ i127.insertBits(iSrc, 48);
+ EXPECT_EQ(i127.extractBits(64, 0).getZExtValue(), 0x3456FFFFFFFFFFFFull);
+ EXPECT_EQ(i127.extractBits(63, 64).getZExtValue(), 0x7FFFFFFFFFFF8012ull);
+
+ // Insert on word boundaries.
+ APInt i128(128, 0);
+ i128.insertBits(APInt(64, UINT64_MAX, true), 0);
+ i128.insertBits(APInt(64, UINT64_MAX, true), 64);
+ EXPECT_EQ(-1, i128.getSExtValue());
+
+ APInt i256(256, UINT64_MAX, true);
+ i256.insertBits(APInt(65, 0), 0);
+ i256.insertBits(APInt(69, 0), 64);
+ i256.insertBits(APInt(128, 0), 128);
+ EXPECT_EQ(0u, i256.getSExtValue());
+
+ APInt i257(257, 0);
+ i257.insertBits(APInt(96, UINT64_MAX, true), 64);
+ EXPECT_EQ(i257.extractBits(64, 0).getZExtValue(), 0x0000000000000000ull);
+ EXPECT_EQ(i257.extractBits(64, 64).getZExtValue(), 0xFFFFFFFFFFFFFFFFull);
+ EXPECT_EQ(i257.extractBits(64, 128).getZExtValue(), 0x00000000FFFFFFFFull);
+ EXPECT_EQ(i257.extractBits(65, 192).getZExtValue(), 0x0000000000000000ull);
+
+ // General insertion.
+ APInt i260(260, UINT64_MAX, true);
+ i260.insertBits(APInt(129, 1ull << 48), 15);
+ EXPECT_EQ(i260.extractBits(64, 0).getZExtValue(), 0x8000000000007FFFull);
+ EXPECT_EQ(i260.extractBits(64, 64).getZExtValue(), 0x0000000000000000ull);
+ EXPECT_EQ(i260.extractBits(64, 128).getZExtValue(), 0xFFFFFFFFFFFF0000ull);
+ EXPECT_EQ(i260.extractBits(64, 192).getZExtValue(), 0xFFFFFFFFFFFFFFFFull);
+ EXPECT_EQ(i260.extractBits(4, 256).getZExtValue(), 0x000000000000000Full);
+}
+
+TEST(APIntTest, extractBits) {
+ APInt i32(32, 0x1234567);
+ EXPECT_EQ(0x3456, i32.extractBits(16, 4));
+
+ APInt i257(257, 0xFFFFFFFFFF0000FFull, true);
+ EXPECT_EQ(0xFFu, i257.extractBits(16, 0));
+ EXPECT_EQ((0xFFu >> 1), i257.extractBits(16, 1));
+ EXPECT_EQ(-1, i257.extractBits(32, 64).getSExtValue());
+ EXPECT_EQ(-1, i257.extractBits(128, 128).getSExtValue());
+ EXPECT_EQ(-1, i257.extractBits(66, 191).getSExtValue());
+ EXPECT_EQ(static_cast<int64_t>(0xFFFFFFFFFF80007Full),
+ i257.extractBits(128, 1).getSExtValue());
+ EXPECT_EQ(static_cast<int64_t>(0xFFFFFFFFFF80007Full),
+ i257.extractBits(129, 1).getSExtValue());
+}
+
+TEST(APIntTest, getLowBitsSet) {
+ APInt i128lo64 = APInt::getLowBitsSet(128, 64);
+ EXPECT_EQ(0u, i128lo64.countLeadingOnes());
+ EXPECT_EQ(64u, i128lo64.countLeadingZeros());
+ EXPECT_EQ(64u, i128lo64.getActiveBits());
+ EXPECT_EQ(0u, i128lo64.countTrailingZeros());
+ EXPECT_EQ(64u, i128lo64.countTrailingOnes());
+ EXPECT_EQ(64u, i128lo64.countPopulation());
+}
+
+TEST(APIntTest, getBitsSet) {
+ APInt i64hi1lo1 = APInt::getBitsSet(64, 63, 1);
+ EXPECT_EQ(1u, i64hi1lo1.countLeadingOnes());
+ EXPECT_EQ(0u, i64hi1lo1.countLeadingZeros());
+ EXPECT_EQ(64u, i64hi1lo1.getActiveBits());
+ EXPECT_EQ(0u, i64hi1lo1.countTrailingZeros());
+ EXPECT_EQ(1u, i64hi1lo1.countTrailingOnes());
+ EXPECT_EQ(2u, i64hi1lo1.countPopulation());
+
+ APInt i127hi1lo1 = APInt::getBitsSet(127, 126, 1);
+ EXPECT_EQ(1u, i127hi1lo1.countLeadingOnes());
+ EXPECT_EQ(0u, i127hi1lo1.countLeadingZeros());
+ EXPECT_EQ(127u, i127hi1lo1.getActiveBits());
+ EXPECT_EQ(0u, i127hi1lo1.countTrailingZeros());
+ EXPECT_EQ(1u, i127hi1lo1.countTrailingOnes());
+ EXPECT_EQ(2u, i127hi1lo1.countPopulation());
+}
+
+TEST(APIntTest, getHighBitsSet) {
+ APInt i64hi32 = APInt::getHighBitsSet(64, 32);
+ EXPECT_EQ(32u, i64hi32.countLeadingOnes());
+ EXPECT_EQ(0u, i64hi32.countLeadingZeros());
+ EXPECT_EQ(64u, i64hi32.getActiveBits());
+ EXPECT_EQ(32u, i64hi32.countTrailingZeros());
+ EXPECT_EQ(0u, i64hi32.countTrailingOnes());
+ EXPECT_EQ(32u, i64hi32.countPopulation());
+}
+
+TEST(APIntTest, getBitsSetFrom) {
+ APInt i64hi31 = APInt::getBitsSetFrom(64, 33);
+ EXPECT_EQ(31u, i64hi31.countLeadingOnes());
+ EXPECT_EQ(0u, i64hi31.countLeadingZeros());
+ EXPECT_EQ(64u, i64hi31.getActiveBits());
+ EXPECT_EQ(33u, i64hi31.countTrailingZeros());
+ EXPECT_EQ(0u, i64hi31.countTrailingOnes());
+ EXPECT_EQ(31u, i64hi31.countPopulation());
+}
+
+TEST(APIntTest, setLowBits) {
+ APInt i64lo32(64, 0);
+ i64lo32.setLowBits(32);
+ EXPECT_EQ(0u, i64lo32.countLeadingOnes());
+ EXPECT_EQ(32u, i64lo32.countLeadingZeros());
+ EXPECT_EQ(32u, i64lo32.getActiveBits());
+ EXPECT_EQ(0u, i64lo32.countTrailingZeros());
+ EXPECT_EQ(32u, i64lo32.countTrailingOnes());
+ EXPECT_EQ(32u, i64lo32.countPopulation());
+
+ APInt i128lo64(128, 0);
+ i128lo64.setLowBits(64);
+ EXPECT_EQ(0u, i128lo64.countLeadingOnes());
+ EXPECT_EQ(64u, i128lo64.countLeadingZeros());
+ EXPECT_EQ(64u, i128lo64.getActiveBits());
+ EXPECT_EQ(0u, i128lo64.countTrailingZeros());
+ EXPECT_EQ(64u, i128lo64.countTrailingOnes());
+ EXPECT_EQ(64u, i128lo64.countPopulation());
+
+ APInt i128lo24(128, 0);
+ i128lo24.setLowBits(24);
+ EXPECT_EQ(0u, i128lo24.countLeadingOnes());
+ EXPECT_EQ(104u, i128lo24.countLeadingZeros());
+ EXPECT_EQ(24u, i128lo24.getActiveBits());
+ EXPECT_EQ(0u, i128lo24.countTrailingZeros());
+ EXPECT_EQ(24u, i128lo24.countTrailingOnes());
+ EXPECT_EQ(24u, i128lo24.countPopulation());
+
+ APInt i128lo104(128, 0);
+ i128lo104.setLowBits(104);
+ EXPECT_EQ(0u, i128lo104.countLeadingOnes());
+ EXPECT_EQ(24u, i128lo104.countLeadingZeros());
+ EXPECT_EQ(104u, i128lo104.getActiveBits());
+ EXPECT_EQ(0u, i128lo104.countTrailingZeros());
+ EXPECT_EQ(104u, i128lo104.countTrailingOnes());
+ EXPECT_EQ(104u, i128lo104.countPopulation());
+
+ APInt i128lo0(128, 0);
+ i128lo0.setLowBits(0);
+ EXPECT_EQ(0u, i128lo0.countLeadingOnes());
+ EXPECT_EQ(128u, i128lo0.countLeadingZeros());
+ EXPECT_EQ(0u, i128lo0.getActiveBits());
+ EXPECT_EQ(128u, i128lo0.countTrailingZeros());
+ EXPECT_EQ(0u, i128lo0.countTrailingOnes());
+ EXPECT_EQ(0u, i128lo0.countPopulation());
+
+ APInt i80lo79(80, 0);
+ i80lo79.setLowBits(79);
+ EXPECT_EQ(0u, i80lo79.countLeadingOnes());
+ EXPECT_EQ(1u, i80lo79.countLeadingZeros());
+ EXPECT_EQ(79u, i80lo79.getActiveBits());
+ EXPECT_EQ(0u, i80lo79.countTrailingZeros());
+ EXPECT_EQ(79u, i80lo79.countTrailingOnes());
+ EXPECT_EQ(79u, i80lo79.countPopulation());
+}
+
+TEST(APIntTest, setHighBits) {
+ APInt i64hi32(64, 0);
+ i64hi32.setHighBits(32);
+ EXPECT_EQ(32u, i64hi32.countLeadingOnes());
+ EXPECT_EQ(0u, i64hi32.countLeadingZeros());
+ EXPECT_EQ(64u, i64hi32.getActiveBits());
+ EXPECT_EQ(32u, i64hi32.countTrailingZeros());
+ EXPECT_EQ(0u, i64hi32.countTrailingOnes());
+ EXPECT_EQ(32u, i64hi32.countPopulation());
+
+ APInt i128hi64(128, 0);
+ i128hi64.setHighBits(64);
+ EXPECT_EQ(64u, i128hi64.countLeadingOnes());
+ EXPECT_EQ(0u, i128hi64.countLeadingZeros());
+ EXPECT_EQ(128u, i128hi64.getActiveBits());
+ EXPECT_EQ(64u, i128hi64.countTrailingZeros());
+ EXPECT_EQ(0u, i128hi64.countTrailingOnes());
+ EXPECT_EQ(64u, i128hi64.countPopulation());
+
+ APInt i128hi24(128, 0);
+ i128hi24.setHighBits(24);
+ EXPECT_EQ(24u, i128hi24.countLeadingOnes());
+ EXPECT_EQ(0u, i128hi24.countLeadingZeros());
+ EXPECT_EQ(128u, i128hi24.getActiveBits());
+ EXPECT_EQ(104u, i128hi24.countTrailingZeros());
+ EXPECT_EQ(0u, i128hi24.countTrailingOnes());
+ EXPECT_EQ(24u, i128hi24.countPopulation());
+
+ APInt i128hi104(128, 0);
+ i128hi104.setHighBits(104);
+ EXPECT_EQ(104u, i128hi104.countLeadingOnes());
+ EXPECT_EQ(0u, i128hi104.countLeadingZeros());
+ EXPECT_EQ(128u, i128hi104.getActiveBits());
+ EXPECT_EQ(24u, i128hi104.countTrailingZeros());
+ EXPECT_EQ(0u, i128hi104.countTrailingOnes());
+ EXPECT_EQ(104u, i128hi104.countPopulation());
+
+ APInt i128hi0(128, 0);
+ i128hi0.setHighBits(0);
+ EXPECT_EQ(0u, i128hi0.countLeadingOnes());
+ EXPECT_EQ(128u, i128hi0.countLeadingZeros());
+ EXPECT_EQ(0u, i128hi0.getActiveBits());
+ EXPECT_EQ(128u, i128hi0.countTrailingZeros());
+ EXPECT_EQ(0u, i128hi0.countTrailingOnes());
+ EXPECT_EQ(0u, i128hi0.countPopulation());
+
+ APInt i80hi1(80, 0);
+ i80hi1.setHighBits(1);
+ EXPECT_EQ(1u, i80hi1.countLeadingOnes());
+ EXPECT_EQ(0u, i80hi1.countLeadingZeros());
+ EXPECT_EQ(80u, i80hi1.getActiveBits());
+ EXPECT_EQ(79u, i80hi1.countTrailingZeros());
+ EXPECT_EQ(0u, i80hi1.countTrailingOnes());
+ EXPECT_EQ(1u, i80hi1.countPopulation());
+
+ APInt i32hi16(32, 0);
+ i32hi16.setHighBits(16);
+ EXPECT_EQ(16u, i32hi16.countLeadingOnes());
+ EXPECT_EQ(0u, i32hi16.countLeadingZeros());
+ EXPECT_EQ(32u, i32hi16.getActiveBits());
+ EXPECT_EQ(16u, i32hi16.countTrailingZeros());
+ EXPECT_EQ(0u, i32hi16.countTrailingOnes());
+ EXPECT_EQ(16u, i32hi16.countPopulation());
+}
+
+TEST(APIntTest, setBitsFrom) {
+ APInt i64from63(64, 0);
+ i64from63.setBitsFrom(63);
+ EXPECT_EQ(1u, i64from63.countLeadingOnes());
+ EXPECT_EQ(0u, i64from63.countLeadingZeros());
+ EXPECT_EQ(64u, i64from63.getActiveBits());
+ EXPECT_EQ(63u, i64from63.countTrailingZeros());
+ EXPECT_EQ(0u, i64from63.countTrailingOnes());
+ EXPECT_EQ(1u, i64from63.countPopulation());
+}
+
+TEST(APIntTest, setAllBits) {
+ APInt i32(32, 0);
+ i32.setAllBits();
+ EXPECT_EQ(32u, i32.countLeadingOnes());
+ EXPECT_EQ(0u, i32.countLeadingZeros());
+ EXPECT_EQ(32u, i32.getActiveBits());
+ EXPECT_EQ(0u, i32.countTrailingZeros());
+ EXPECT_EQ(32u, i32.countTrailingOnes());
+ EXPECT_EQ(32u, i32.countPopulation());
+
+ APInt i64(64, 0);
+ i64.setAllBits();
+ EXPECT_EQ(64u, i64.countLeadingOnes());
+ EXPECT_EQ(0u, i64.countLeadingZeros());
+ EXPECT_EQ(64u, i64.getActiveBits());
+ EXPECT_EQ(0u, i64.countTrailingZeros());
+ EXPECT_EQ(64u, i64.countTrailingOnes());
+ EXPECT_EQ(64u, i64.countPopulation());
+
+ APInt i96(96, 0);
+ i96.setAllBits();
+ EXPECT_EQ(96u, i96.countLeadingOnes());
+ EXPECT_EQ(0u, i96.countLeadingZeros());
+ EXPECT_EQ(96u, i96.getActiveBits());
+ EXPECT_EQ(0u, i96.countTrailingZeros());
+ EXPECT_EQ(96u, i96.countTrailingOnes());
+ EXPECT_EQ(96u, i96.countPopulation());
+
+ APInt i128(128, 0);
+ i128.setAllBits();
+ EXPECT_EQ(128u, i128.countLeadingOnes());
+ EXPECT_EQ(0u, i128.countLeadingZeros());
+ EXPECT_EQ(128u, i128.getActiveBits());
+ EXPECT_EQ(0u, i128.countTrailingZeros());
+ EXPECT_EQ(128u, i128.countTrailingOnes());
+ EXPECT_EQ(128u, i128.countPopulation());
+}
+
+TEST(APIntTest, getLoBits) {
+ APInt i32(32, 0xfa);
+ i32.setHighBits(1);
+ EXPECT_EQ(0xa, i32.getLoBits(4));
+ APInt i128(128, 0xfa);
+ i128.setHighBits(1);
+ EXPECT_EQ(0xa, i128.getLoBits(4));
+}
+
+TEST(APIntTest, getHiBits) {
+ APInt i32(32, 0xfa);
+ i32.setHighBits(2);
+ EXPECT_EQ(0xc, i32.getHiBits(4));
+ APInt i128(128, 0xfa);
+ i128.setHighBits(2);
+ EXPECT_EQ(0xc, i128.getHiBits(4));
+}
+
+TEST(APIntTest, GCD) {
+ using APIntOps::GreatestCommonDivisor;
+
+ for (unsigned Bits : {1, 2, 32, 63, 64, 65}) {
+ // Test some corner cases near zero.
+ APInt Zero(Bits, 0), One(Bits, 1);
+ EXPECT_EQ(GreatestCommonDivisor(Zero, Zero), Zero);
+ EXPECT_EQ(GreatestCommonDivisor(Zero, One), One);
+ EXPECT_EQ(GreatestCommonDivisor(One, Zero), One);
+ EXPECT_EQ(GreatestCommonDivisor(One, One), One);
+
+ if (Bits > 1) {
+ APInt Two(Bits, 2);
+ EXPECT_EQ(GreatestCommonDivisor(Zero, Two), Two);
+ EXPECT_EQ(GreatestCommonDivisor(One, Two), One);
+ EXPECT_EQ(GreatestCommonDivisor(Two, Two), Two);
+
+ // Test some corner cases near the highest representable value.
+ APInt Max(Bits, 0);
+ Max.setAllBits();
+ EXPECT_EQ(GreatestCommonDivisor(Zero, Max), Max);
+ EXPECT_EQ(GreatestCommonDivisor(One, Max), One);
+ EXPECT_EQ(GreatestCommonDivisor(Two, Max), One);
+ EXPECT_EQ(GreatestCommonDivisor(Max, Max), Max);
+
+ APInt MaxOver2 = Max.udiv(Two);
+ EXPECT_EQ(GreatestCommonDivisor(MaxOver2, Max), One);
+ // Max - 1 == Max / 2 * 2, because Max is odd.
+ EXPECT_EQ(GreatestCommonDivisor(MaxOver2, Max - 1), MaxOver2);
+ }
+ }
+
+ // Compute the 20th Mersenne prime.
+ const unsigned BitWidth = 4450;
+ APInt HugePrime = APInt::getLowBitsSet(BitWidth, 4423);
+
+ // 9931 and 123456 are coprime.
+ APInt A = HugePrime * APInt(BitWidth, 9931);
+ APInt B = HugePrime * APInt(BitWidth, 123456);
+ APInt C = GreatestCommonDivisor(A, B);
+ EXPECT_EQ(C, HugePrime);
+}
diff --git a/unittests/ADT/BitVectorTest.cpp b/unittests/ADT/BitVectorTest.cpp
index 78fd5ce65677c..98ef66735ad23 100644
--- a/unittests/ADT/BitVectorTest.cpp
+++ b/unittests/ADT/BitVectorTest.cpp
@@ -182,6 +182,45 @@ TYPED_TEST(BitVectorTest, TrivialOperation) {
EXPECT_TRUE(Vec.empty());
}
+TYPED_TEST(BitVectorTest, FindOperations) {
+ // Test finding in an empty BitVector.
+ TypeParam A;
+ EXPECT_EQ(-1, A.find_first());
+ EXPECT_EQ(-1, A.find_first_unset());
+ EXPECT_EQ(-1, A.find_next(0));
+ EXPECT_EQ(-1, A.find_next_unset(0));
+
+ // Test finding next set and unset bits in a BitVector with multiple words
+ A.resize(100);
+ A.set(12);
+ A.set(13);
+ A.set(75);
+
+ EXPECT_EQ(12, A.find_first());
+ EXPECT_EQ(13, A.find_next(12));
+ EXPECT_EQ(75, A.find_next(13));
+ EXPECT_EQ(-1, A.find_next(75));
+
+ EXPECT_EQ(0, A.find_first_unset());
+ EXPECT_EQ(14, A.find_next_unset(11));
+ EXPECT_EQ(14, A.find_next_unset(12));
+ EXPECT_EQ(14, A.find_next_unset(13));
+ EXPECT_EQ(16, A.find_next_unset(15));
+ EXPECT_EQ(76, A.find_next_unset(74));
+ EXPECT_EQ(76, A.find_next_unset(75));
+ EXPECT_EQ(-1, A.find_next_unset(99));
+
+ A.set(0, 100);
+ EXPECT_EQ(100U, A.count());
+ EXPECT_EQ(0, A.find_first());
+ EXPECT_EQ(-1, A.find_first_unset());
+
+ A.reset(0, 100);
+ EXPECT_EQ(0U, A.count());
+ EXPECT_EQ(-1, A.find_first());
+ EXPECT_EQ(0, A.find_first_unset());
+}
+
TYPED_TEST(BitVectorTest, CompoundAssignment) {
TypeParam A;
A.resize(10);
@@ -425,5 +464,42 @@ TYPED_TEST(BitVectorTest, MoveAssignment) {
EXPECT_EQ(C, B);
}
+template<class TypeParam>
+static void testEmpty(const TypeParam &A) {
+ EXPECT_TRUE(A.empty());
+ EXPECT_EQ((size_t)0, A.size());
+ EXPECT_EQ((size_t)0, A.count());
+ EXPECT_FALSE(A.any());
+ EXPECT_TRUE(A.all());
+ EXPECT_TRUE(A.none());
+ EXPECT_EQ(-1, A.find_first());
+ EXPECT_EQ(A, TypeParam());
+}
+
+/// Tests whether BitVector behaves well with Bits==nullptr, Capacity==0
+TYPED_TEST(BitVectorTest, EmptyVector) {
+ TypeParam A;
+ testEmpty(A);
+
+ TypeParam B;
+ B.reset();
+ testEmpty(B);
+
+ TypeParam C;
+ C.clear();
+ testEmpty(C);
+
+ TypeParam D(A);
+ testEmpty(D);
+
+ TypeParam E;
+ E = A;
+ testEmpty(E);
+
+ TypeParam F;
+ E.reset(A);
+ testEmpty(E);
+}
+
}
#endif
diff --git a/unittests/ADT/BreadthFirstIteratorTest.cpp b/unittests/ADT/BreadthFirstIteratorTest.cpp
new file mode 100644
index 0000000000000..42a07bbe930ba
--- /dev/null
+++ b/unittests/ADT/BreadthFirstIteratorTest.cpp
@@ -0,0 +1,74 @@
+//=== llvm/unittest/ADT/BreadthFirstIteratorTest.cpp - BFS iterator tests -===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/BreadthFirstIterator.h"
+#include "TestGraph.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace llvm {
+
+TEST(BreadthFristIteratorTest, Basic) {
+ typedef bf_iterator<Graph<4>> BFIter;
+
+ Graph<4> G;
+ G.AddEdge(0, 1);
+ G.AddEdge(0, 2);
+ G.AddEdge(1, 3);
+
+ auto It = BFIter::begin(G);
+ auto End = BFIter::end(G);
+ EXPECT_EQ(It.getLevel(), 0U);
+ EXPECT_EQ(*It, G.AccessNode(0));
+ ++It;
+ EXPECT_EQ(It.getLevel(), 1U);
+ EXPECT_EQ(*It, G.AccessNode(1));
+ ++It;
+ EXPECT_EQ(It.getLevel(), 1U);
+ EXPECT_EQ(*It, G.AccessNode(2));
+ ++It;
+ EXPECT_EQ(It.getLevel(), 2U);
+ EXPECT_EQ(*It, G.AccessNode(3));
+ ++It;
+ EXPECT_EQ(It, End);
+}
+
+TEST(BreadthFristIteratorTest, Cycle) {
+ typedef bf_iterator<Graph<4>> BFIter;
+
+ Graph<4> G;
+ G.AddEdge(0, 1);
+ G.AddEdge(1, 0);
+ G.AddEdge(1, 2);
+ G.AddEdge(2, 1);
+ G.AddEdge(2, 1);
+ G.AddEdge(2, 3);
+ G.AddEdge(3, 2);
+ G.AddEdge(3, 1);
+ G.AddEdge(3, 0);
+
+ auto It = BFIter::begin(G);
+ auto End = BFIter::end(G);
+ EXPECT_EQ(It.getLevel(), 0U);
+ EXPECT_EQ(*It, G.AccessNode(0));
+ ++It;
+ EXPECT_EQ(It.getLevel(), 1U);
+ EXPECT_EQ(*It, G.AccessNode(1));
+ ++It;
+ EXPECT_EQ(It.getLevel(), 2U);
+ EXPECT_EQ(*It, G.AccessNode(2));
+ ++It;
+ EXPECT_EQ(It.getLevel(), 3U);
+ EXPECT_EQ(*It, G.AccessNode(3));
+ ++It;
+ EXPECT_EQ(It, End);
+}
+
+} // end namespace llvm
diff --git a/unittests/ADT/CMakeLists.txt b/unittests/ADT/CMakeLists.txt
index 738f6efe92d63..fa977ac5d3f5f 100644
--- a/unittests/ADT/CMakeLists.txt
+++ b/unittests/ADT/CMakeLists.txt
@@ -9,6 +9,7 @@ set(ADTSources
ArrayRefTest.cpp
BitmaskEnumTest.cpp
BitVectorTest.cpp
+ BreadthFirstIteratorTest.cpp
BumpPtrListTest.cpp
DAGDeltaAlgorithmTest.cpp
DeltaAlgorithmTest.cpp
diff --git a/unittests/ADT/DenseMapTest.cpp b/unittests/ADT/DenseMapTest.cpp
index 80f0462bc8fb6..273f4da021c4a 100644
--- a/unittests/ADT/DenseMapTest.cpp
+++ b/unittests/ADT/DenseMapTest.cpp
@@ -580,4 +580,18 @@ TEST(DenseMapCustomTest, TryEmplaceTest) {
EXPECT_EQ(Try1.first, Try2.first);
EXPECT_NE(nullptr, P);
}
+
+TEST(DenseMapCustomTest, ConstTest) {
+ // Test that const pointers work okay for count and find, even when the
+ // underlying map is a non-const pointer.
+ DenseMap<int *, int> Map;
+ int A;
+ int *B = &A;
+ const int *C = &A;
+ Map.insert({B, 0});
+ EXPECT_EQ(Map.count(B), 1u);
+ EXPECT_EQ(Map.count(C), 1u);
+ EXPECT_NE(Map.find(B), Map.end());
+ EXPECT_NE(Map.find(C), Map.end());
+}
}
diff --git a/unittests/ADT/DenseSetTest.cpp b/unittests/ADT/DenseSetTest.cpp
index 4d5a82902f0ea..a09537a3e9904 100644
--- a/unittests/ADT/DenseSetTest.cpp
+++ b/unittests/ADT/DenseSetTest.cpp
@@ -73,6 +73,22 @@ TYPED_TEST(DenseSetTest, InitializerList) {
EXPECT_EQ(0u, set.count(3));
}
+TYPED_TEST(DenseSetTest, ConstIteratorComparison) {
+ TypeParam set({1});
+ const TypeParam &cset = set;
+ EXPECT_EQ(set.begin(), cset.begin());
+ EXPECT_EQ(set.end(), cset.end());
+ EXPECT_NE(set.end(), cset.begin());
+ EXPECT_NE(set.begin(), cset.end());
+}
+
+TYPED_TEST(DenseSetTest, DefaultConstruction) {
+ typename TypeParam::iterator I, J;
+ typename TypeParam::const_iterator CI, CJ;
+ EXPECT_EQ(I, J);
+ EXPECT_EQ(CI, CJ);
+}
+
TYPED_TEST(DenseSetTest, EmptyInitializerList) {
TypeParam set({});
EXPECT_EQ(0u, set.size());
@@ -169,4 +185,17 @@ TEST(DenseSetCustomTest, ReserveTest) {
EXPECT_EQ(0, CountCopyAndMove::Copy);
}
}
+TEST(DenseSetCustomTest, ConstTest) {
+ // Test that const pointers work okay for count and find, even when the
+ // underlying map is a non-const pointer.
+ DenseSet<int *> Map;
+ int A;
+ int *B = &A;
+ const int *C = &A;
+ Map.insert(B);
+ EXPECT_EQ(Map.count(B), 1u);
+ EXPECT_EQ(Map.count(C), 1u);
+ EXPECT_NE(Map.find(B), Map.end());
+ EXPECT_NE(Map.find(C), Map.end());
+}
}
diff --git a/unittests/ADT/IteratorTest.cpp b/unittests/ADT/IteratorTest.cpp
index a8d5b33a0b497..7f261824b499c 100644
--- a/unittests/ADT/IteratorTest.cpp
+++ b/unittests/ADT/IteratorTest.cpp
@@ -7,9 +7,9 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/ADT/iterator.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/iterator.h"
#include "gtest/gtest.h"
using namespace llvm;
@@ -35,14 +35,15 @@ static_assert(std::is_same<typename AdaptedIter::reference, Shadow<3>>::value,
"");
TEST(PointeeIteratorTest, Basic) {
- int arr[4] = { 1, 2, 3, 4 };
+ int arr[4] = {1, 2, 3, 4};
SmallVector<int *, 4> V;
V.push_back(&arr[0]);
V.push_back(&arr[1]);
V.push_back(&arr[2]);
V.push_back(&arr[3]);
- typedef pointee_iterator<SmallVectorImpl<int *>::const_iterator> test_iterator;
+ typedef pointee_iterator<SmallVectorImpl<int *>::const_iterator>
+ test_iterator;
test_iterator Begin, End;
Begin = V.begin();
@@ -83,7 +84,8 @@ TEST(PointeeIteratorTest, SmartPointer) {
V.push_back(make_unique<int>(4));
typedef pointee_iterator<
- SmallVectorImpl<std::unique_ptr<int>>::const_iterator> test_iterator;
+ SmallVectorImpl<std::unique_ptr<int>>::const_iterator>
+ test_iterator;
test_iterator Begin, End;
Begin = V.begin();
@@ -116,6 +118,15 @@ TEST(PointeeIteratorTest, SmartPointer) {
EXPECT_EQ(End, I);
}
+TEST(PointeeIteratorTest, Range) {
+ int A[] = {1, 2, 3, 4};
+ SmallVector<int *, 4> V{&A[0], &A[1], &A[2], &A[3]};
+
+ int I = 0;
+ for (int II : make_pointee_range(V))
+ EXPECT_EQ(A[I++], II);
+}
+
TEST(FilterIteratorTest, Lambda) {
auto IsOdd = [](int N) { return N % 2 == 1; };
int A[] = {0, 1, 2, 3, 4, 5, 6};
@@ -209,6 +220,13 @@ TEST(PointerIterator, Const) {
EXPECT_EQ(A + 4, std::next(*Begin, 4));
}
+TEST(PointerIterator, Range) {
+ int A[] = {1, 2, 3, 4};
+ int I = 0;
+ for (int *P : make_pointer_range(A))
+ EXPECT_EQ(A + I++, P);
+}
+
TEST(ZipIteratorTest, Basic) {
using namespace std;
const SmallVector<unsigned, 6> pi{3, 1, 4, 1, 5, 9};
@@ -272,4 +290,51 @@ TEST(ZipIteratorTest, ZipFirstMutability) {
}
}
+TEST(ZipIteratorTest, Filter) {
+ using namespace std;
+ vector<unsigned> pi{3, 1, 4, 1, 5, 9};
+
+ unsigned iters = 0;
+ // pi is length 6, but the zip RHS is length 7.
+ auto zipped = zip_first(pi, vector<bool>{1, 1, 0, 1, 1, 1, 0});
+ for (auto tup : make_filter_range(
+ zipped, [](decltype(zipped)::value_type t) { return get<1>(t); })) {
+ EXPECT_EQ(get<0>(tup) & 0x01, get<1>(tup));
+ get<0>(tup) += 1;
+ iters += 1;
+ }
+
+ // Should have skipped pi[2].
+ EXPECT_EQ(iters, 5u);
+
+ // Ensure that in-place mutation works.
+ EXPECT_TRUE(all_of(pi, [](unsigned n) { return (n & 0x01) == 0; }));
+}
+
+TEST(ZipIteratorTest, Reverse) {
+ using namespace std;
+ vector<unsigned> ascending{0, 1, 2, 3, 4, 5};
+
+ auto zipped = zip_first(ascending, vector<bool>{0, 1, 0, 1, 0, 1});
+ unsigned last = 6;
+ for (auto tup : reverse(zipped)) {
+ // Check that this is in reverse.
+ EXPECT_LT(get<0>(tup), last);
+ last = get<0>(tup);
+ EXPECT_EQ(get<0>(tup) & 0x01, get<1>(tup));
+ }
+
+ auto odds = [](decltype(zipped)::value_type tup) { return get<1>(tup); };
+ last = 6;
+ for (auto tup : make_filter_range(reverse(zipped), odds)) {
+ EXPECT_LT(get<0>(tup), last);
+ last = get<0>(tup);
+ EXPECT_TRUE(get<0>(tup) & 0x01);
+ get<0>(tup) += 1;
+ }
+
+ // Ensure that in-place mutation works.
+ EXPECT_TRUE(all_of(ascending, [](unsigned n) { return (n & 0x01) == 0; }));
+}
+
} // anonymous namespace
diff --git a/unittests/ADT/STLExtrasTest.cpp b/unittests/ADT/STLExtrasTest.cpp
index f17d24f36b238..2e6eb6f413f6c 100644
--- a/unittests/ADT/STLExtrasTest.cpp
+++ b/unittests/ADT/STLExtrasTest.cpp
@@ -48,7 +48,7 @@ TEST(STLExtrasTest, EnumerateLValue) {
std::vector<CharPairType> CharResults;
for (auto X : llvm::enumerate(foo)) {
- CharResults.emplace_back(X.Index, X.Value);
+ CharResults.emplace_back(X.index(), X.value());
}
ASSERT_EQ(3u, CharResults.size());
EXPECT_EQ(CharPairType(0u, 'a'), CharResults[0]);
@@ -60,7 +60,7 @@ TEST(STLExtrasTest, EnumerateLValue) {
std::vector<IntPairType> IntResults;
const std::vector<int> bar = {1, 2, 3};
for (auto X : llvm::enumerate(bar)) {
- IntResults.emplace_back(X.Index, X.Value);
+ IntResults.emplace_back(X.index(), X.value());
}
ASSERT_EQ(3u, IntResults.size());
EXPECT_EQ(IntPairType(0u, 1), IntResults[0]);
@@ -69,9 +69,9 @@ TEST(STLExtrasTest, EnumerateLValue) {
// Test an empty range.
IntResults.clear();
- const std::vector<int> baz;
+ const std::vector<int> baz{};
for (auto X : llvm::enumerate(baz)) {
- IntResults.emplace_back(X.Index, X.Value);
+ IntResults.emplace_back(X.index(), X.value());
}
EXPECT_TRUE(IntResults.empty());
}
@@ -82,7 +82,7 @@ TEST(STLExtrasTest, EnumerateModifyLValue) {
std::vector<char> foo = {'a', 'b', 'c'};
for (auto X : llvm::enumerate(foo)) {
- ++X.Value;
+ ++X.value();
}
EXPECT_EQ('b', foo[0]);
EXPECT_EQ('c', foo[1]);
@@ -97,7 +97,7 @@ TEST(STLExtrasTest, EnumerateRValueRef) {
auto Enumerator = llvm::enumerate(std::vector<int>{1, 2, 3});
for (auto X : llvm::enumerate(std::vector<int>{1, 2, 3})) {
- Results.emplace_back(X.Index, X.Value);
+ Results.emplace_back(X.index(), X.value());
}
ASSERT_EQ(3u, Results.size());
@@ -114,8 +114,8 @@ TEST(STLExtrasTest, EnumerateModifyRValue) {
std::vector<PairType> Results;
for (auto X : llvm::enumerate(std::vector<char>{'1', '2', '3'})) {
- ++X.Value;
- Results.emplace_back(X.Index, X.Value);
+ ++X.value();
+ Results.emplace_back(X.index(), X.value());
}
ASSERT_EQ(3u, Results.size());
@@ -255,6 +255,16 @@ TEST(STLExtrasTest, CountAdaptor) {
EXPECT_EQ(1, count(v, 4));
}
+TEST(STLExtrasTest, ToVector) {
+ std::vector<char> v = {'a', 'b', 'c'};
+ auto Enumerated = to_vector<4>(enumerate(v));
+ ASSERT_EQ(3u, Enumerated.size());
+ for (size_t I = 0; I < v.size(); ++I) {
+ EXPECT_EQ(I, Enumerated[I].index());
+ EXPECT_EQ(v[I], Enumerated[I].value());
+ }
+}
+
TEST(STLExtrasTest, ConcatRange) {
std::vector<int> Expected = {1, 2, 3, 4, 5, 6, 7, 8};
std::vector<int> Test;
diff --git a/unittests/ADT/SmallPtrSetTest.cpp b/unittests/ADT/SmallPtrSetTest.cpp
index d4d963fdc5bdc..fc14c684d67f3 100644
--- a/unittests/ADT/SmallPtrSetTest.cpp
+++ b/unittests/ADT/SmallPtrSetTest.cpp
@@ -12,7 +12,9 @@
//===----------------------------------------------------------------------===//
#include "gtest/gtest.h"
+#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/Support/PointerLikeTypeTraits.h"
using namespace llvm;
@@ -279,3 +281,52 @@ TEST(SmallPtrSetTest, EraseTest) {
SmallPtrSet<int *, 2> A;
checkEraseAndIterators(A);
}
+
+// Verify that dereferencing and iteration work.
+TEST(SmallPtrSetTest, dereferenceAndIterate) {
+ int Ints[] = {0, 1, 2, 3, 4, 5, 6, 7};
+ SmallPtrSet<const int *, 4> S;
+ for (int &I : Ints) {
+ EXPECT_EQ(&I, *S.insert(&I).first);
+ EXPECT_EQ(&I, *S.find(&I));
+ }
+
+ // Iterate from each and count how many times each element is found.
+ int Found[sizeof(Ints)/sizeof(int)] = {0};
+ for (int &I : Ints)
+ for (auto F = S.find(&I), E = S.end(); F != E; ++F)
+ ++Found[*F - Ints];
+
+ // Sort. We should hit the first element just once and the final element N
+ // times.
+ std::sort(std::begin(Found), std::end(Found));
+ for (auto F = std::begin(Found), E = std::end(Found); F != E; ++F)
+ EXPECT_EQ(F - Found + 1, *F);
+}
+
+// Verify that const pointers work for count and find even when the underlying
+// SmallPtrSet is not for a const pointer type.
+TEST(SmallPtrSetTest, ConstTest) {
+ SmallPtrSet<int *, 8> IntSet;
+ int A;
+ int *B = &A;
+ const int *C = &A;
+ IntSet.insert(B);
+ EXPECT_EQ(IntSet.count(B), 1u);
+ EXPECT_EQ(IntSet.count(C), 1u);
+ EXPECT_NE(IntSet.find(B), IntSet.end());
+ EXPECT_NE(IntSet.find(C), IntSet.end());
+}
+
+// Verify that we automatically get the const version of PointerLikeTypeTraits
+// filled in for us, even for a non-pointer type
+using TestPair = PointerIntPair<int *, 1>;
+
+TEST(SmallPtrSetTest, ConstNonPtrTest) {
+ SmallPtrSet<TestPair, 8> IntSet;
+ int A[1];
+ TestPair Pair(&A[0], 1);
+ IntSet.insert(Pair);
+ EXPECT_EQ(IntSet.count(Pair), 1u);
+ EXPECT_NE(IntSet.find(Pair), IntSet.end());
+}
diff --git a/unittests/ADT/SparseBitVectorTest.cpp b/unittests/ADT/SparseBitVectorTest.cpp
index 9127225860baa..6cd4de35bca7d 100644
--- a/unittests/ADT/SparseBitVectorTest.cpp
+++ b/unittests/ADT/SparseBitVectorTest.cpp
@@ -127,4 +127,43 @@ TEST(SparseBitVectorTest, SelfAssignment) {
EXPECT_TRUE(Vec.empty());
}
+TEST(SparseBitVectorTest, Find) {
+ SparseBitVector<> Vec;
+ Vec.set(1);
+ EXPECT_EQ(1, Vec.find_first());
+ EXPECT_EQ(1, Vec.find_last());
+
+ Vec.set(2);
+ EXPECT_EQ(1, Vec.find_first());
+ EXPECT_EQ(2, Vec.find_last());
+
+ Vec.set(0);
+ Vec.set(3);
+ EXPECT_EQ(0, Vec.find_first());
+ EXPECT_EQ(3, Vec.find_last());
+
+ Vec.reset(1);
+ Vec.reset(0);
+ Vec.reset(3);
+ EXPECT_EQ(2, Vec.find_first());
+ EXPECT_EQ(2, Vec.find_last());
+
+ // Set some large bits to ensure we are pulling bits from more than just a
+ // single bitword.
+ Vec.set(500);
+ Vec.set(2000);
+ Vec.set(3000);
+ Vec.set(4000);
+ Vec.reset(2);
+ EXPECT_EQ(500, Vec.find_first());
+ EXPECT_EQ(4000, Vec.find_last());
+
+ Vec.reset(500);
+ Vec.reset(3000);
+ Vec.reset(4000);
+ EXPECT_EQ(2000, Vec.find_first());
+ EXPECT_EQ(2000, Vec.find_last());
+
+ Vec.clear();
+}
}
diff --git a/unittests/ADT/StringMapTest.cpp b/unittests/ADT/StringMapTest.cpp
index 911c72d749619..b5c63695ff35c 100644
--- a/unittests/ADT/StringMapTest.cpp
+++ b/unittests/ADT/StringMapTest.cpp
@@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/DataTypes.h"
#include "gtest/gtest.h"
@@ -269,6 +270,34 @@ TEST_F(StringMapTest, InsertRehashingPairTest) {
EXPECT_EQ(42u, It->second);
}
+TEST_F(StringMapTest, IterMapKeys) {
+ StringMap<int> Map;
+ Map["A"] = 1;
+ Map["B"] = 2;
+ Map["C"] = 3;
+ Map["D"] = 3;
+
+ auto Keys = to_vector<4>(Map.keys());
+ std::sort(Keys.begin(), Keys.end());
+
+ SmallVector<StringRef, 4> Expected = {"A", "B", "C", "D"};
+ EXPECT_EQ(Expected, Keys);
+}
+
+TEST_F(StringMapTest, IterSetKeys) {
+ StringSet<> Set;
+ Set.insert("A");
+ Set.insert("B");
+ Set.insert("C");
+ Set.insert("D");
+
+ auto Keys = to_vector<4>(Set.keys());
+ std::sort(Keys.begin(), Keys.end());
+
+ SmallVector<StringRef, 4> Expected = {"A", "B", "C", "D"};
+ EXPECT_EQ(Expected, Keys);
+}
+
// Create a non-default constructable value
struct StringMapTestStruct {
StringMapTestStruct(int i) : i(i) {}
@@ -425,7 +454,7 @@ TEST(StringMapCustomTest, InitialSizeTest) {
Map.insert(std::pair<std::string, CountCtorCopyAndMove>(
std::piecewise_construct, std::forward_as_tuple(Twine(i).str()),
std::forward_as_tuple(i)));
- // After the inital move, the map will move the Elts in the Entry.
+ // After the initial move, the map will move the Elts in the Entry.
EXPECT_EQ((unsigned)Size * 2, CountCtorCopyAndMove::Move);
// We copy once the pair from the Elts vector
EXPECT_EQ(0u, CountCtorCopyAndMove::Copy);
diff --git a/unittests/ADT/StringRefTest.cpp b/unittests/ADT/StringRefTest.cpp
index 5b6822ed757df..e308f2d7c64b0 100644
--- a/unittests/ADT/StringRefTest.cpp
+++ b/unittests/ADT/StringRefTest.cpp
@@ -504,8 +504,22 @@ TEST(StringRefTest, Count) {
}
TEST(StringRefTest, EditDistance) {
- StringRef Str("hello");
- EXPECT_EQ(2U, Str.edit_distance("hill"));
+ StringRef Hello("hello");
+ EXPECT_EQ(2U, Hello.edit_distance("hill"));
+
+ StringRef Industry("industry");
+ EXPECT_EQ(6U, Industry.edit_distance("interest"));
+
+ StringRef Soylent("soylent green is people");
+ EXPECT_EQ(19U, Soylent.edit_distance("people soiled our green"));
+ EXPECT_EQ(26U, Soylent.edit_distance("people soiled our green",
+ /* allow replacements = */ false));
+ EXPECT_EQ(9U, Soylent.edit_distance("people soiled our green",
+ /* allow replacements = */ true,
+ /* max edit distance = */ 8));
+ EXPECT_EQ(53U, Soylent.edit_distance("people soiled our green "
+ "people soiled our green "
+ "people soiled our green "));
}
TEST(StringRefTest, Misc) {
@@ -852,6 +866,27 @@ TEST(StringRefTest, consumeIntegerSigned) {
}
}
+struct GetDoubleStrings {
+ const char *Str;
+ bool AllowInexact;
+ bool ShouldFail;
+ double D;
+} DoubleStrings[] = {{"0", false, false, 0.0},
+ {"0.0", false, false, 0.0},
+ {"-0.0", false, false, -0.0},
+ {"123.45", false, true, 123.45},
+ {"123.45", true, false, 123.45}};
+
+TEST(StringRefTest, getAsDouble) {
+ for (const auto &Entry : DoubleStrings) {
+ double Result;
+ StringRef S(Entry.Str);
+ EXPECT_EQ(Entry.ShouldFail, S.getAsDouble(Result, Entry.AllowInexact));
+ if (!Entry.ShouldFail)
+ EXPECT_EQ(Result, Entry.D);
+ }
+}
+
static const char *join_input[] = { "a", "b", "c" };
static const char join_result1[] = "a";
static const char join_result2[] = "a:b:c";
@@ -878,6 +913,8 @@ TEST(StringRefTest, joinStrings) {
EXPECT_TRUE(v2_join2);
bool v2_join3 = join(v2.begin(), v2.end(), "::") == join_result3;
EXPECT_TRUE(v2_join3);
+ v2_join3 = join(v2, "::") == join_result3;
+ EXPECT_TRUE(v2_join3);
}
diff --git a/unittests/ADT/TinyPtrVectorTest.cpp b/unittests/ADT/TinyPtrVectorTest.cpp
index 26189b76394fc..8d5fa4060913b 100644
--- a/unittests/ADT/TinyPtrVectorTest.cpp
+++ b/unittests/ADT/TinyPtrVectorTest.cpp
@@ -17,19 +17,13 @@
#include "llvm/Support/type_traits.h"
#include "gtest/gtest.h"
#include <algorithm>
+#include <random>
#include <vector>
using namespace llvm;
namespace {
-// The world's worst RNG, but it is deterministic and makes it easy to get
-// *some* shuffling of elements.
-static ptrdiff_t test_shuffle_rng(ptrdiff_t i) {
- return (i + i * 33) % i;
-}
-static ptrdiff_t (*test_shuffle_rng_p)(ptrdiff_t) = &test_shuffle_rng;
-
template <typename VectorT>
class TinyPtrVectorTest : public testing::Test {
protected:
@@ -46,7 +40,7 @@ protected:
for (size_t i = 0, e = array_lengthof(TestValues); i != e; ++i)
TestPtrs.push_back(&TestValues[i]);
- std::random_shuffle(TestPtrs.begin(), TestPtrs.end(), test_shuffle_rng_p);
+ std::shuffle(TestPtrs.begin(), TestPtrs.end(), std::mt19937{});
}
ArrayRef<PtrT> testArray(size_t N) {
diff --git a/unittests/ADT/TripleTest.cpp b/unittests/ADT/TripleTest.cpp
index c80477f6ddc98..78616d36e4f8a 100644
--- a/unittests/ADT/TripleTest.cpp
+++ b/unittests/ADT/TripleTest.cpp
@@ -685,6 +685,54 @@ TEST(TripleTest, BitWidthArchVariants) {
T.setArch(Triple::riscv64);
EXPECT_EQ(Triple::riscv32, T.get32BitArchVariant().getArch());
EXPECT_EQ(Triple::riscv64, T.get64BitArchVariant().getArch());
+
+ T.setArch(Triple::thumbeb);
+ EXPECT_EQ(Triple::thumbeb, T.get32BitArchVariant().getArch());
+ EXPECT_EQ(Triple::aarch64_be, T.get64BitArchVariant().getArch());
+
+ T.setArch(Triple::thumb);
+ EXPECT_EQ(Triple::thumb, T.get32BitArchVariant().getArch());
+ EXPECT_EQ(Triple::aarch64, T.get64BitArchVariant().getArch());
+
+ T.setArch(Triple::aarch64);
+ EXPECT_EQ(Triple::arm, T.get32BitArchVariant().getArch());
+ EXPECT_EQ(Triple::aarch64, T.get64BitArchVariant().getArch());
+
+ T.setArch(Triple::aarch64_be);
+ EXPECT_EQ(Triple::armeb, T.get32BitArchVariant().getArch());
+ EXPECT_EQ(Triple::aarch64_be, T.get64BitArchVariant().getArch());
+
+ T.setArch(Triple::renderscript32);
+ EXPECT_EQ(Triple::renderscript32, T.get32BitArchVariant().getArch());
+ EXPECT_EQ(Triple::renderscript64, T.get64BitArchVariant().getArch());
+
+ T.setArch(Triple::renderscript64);
+ EXPECT_EQ(Triple::renderscript32, T.get32BitArchVariant().getArch());
+ EXPECT_EQ(Triple::renderscript64, T.get64BitArchVariant().getArch());
+
+ T.setArch(Triple::le32);
+ EXPECT_EQ(Triple::le32, T.get32BitArchVariant().getArch());
+ EXPECT_EQ(Triple::le64, T.get64BitArchVariant().getArch());
+
+ T.setArch(Triple::le64);
+ EXPECT_EQ(Triple::le32, T.get32BitArchVariant().getArch());
+ EXPECT_EQ(Triple::le64, T.get64BitArchVariant().getArch());
+
+ T.setArch(Triple::armeb);
+ EXPECT_EQ(Triple::armeb, T.get32BitArchVariant().getArch());
+ EXPECT_EQ(Triple::aarch64_be, T.get64BitArchVariant().getArch());
+
+ T.setArch(Triple::arm);
+ EXPECT_EQ(Triple::arm, T.get32BitArchVariant().getArch());
+ EXPECT_EQ(Triple::aarch64, T.get64BitArchVariant().getArch());
+
+ T.setArch(Triple::systemz);
+ EXPECT_EQ(Triple::UnknownArch, T.get32BitArchVariant().getArch());
+ EXPECT_EQ(Triple::systemz, T.get64BitArchVariant().getArch());
+
+ T.setArch(Triple::xcore);
+ EXPECT_EQ(Triple::xcore, T.get32BitArchVariant().getArch());
+ EXPECT_EQ(Triple::UnknownArch, T.get64BitArchVariant().getArch());
}
TEST(TripleTest, EndianArchVariants) {
@@ -775,6 +823,22 @@ TEST(TripleTest, EndianArchVariants) {
T.setArch(Triple::lanai);
EXPECT_EQ(Triple::lanai, T.getBigEndianArchVariant().getArch());
EXPECT_EQ(Triple::UnknownArch, T.getLittleEndianArchVariant().getArch());
+
+ T.setArch(Triple::tcele);
+ EXPECT_EQ(Triple::tce, T.getBigEndianArchVariant().getArch());
+ EXPECT_EQ(Triple::tcele, T.getLittleEndianArchVariant().getArch());
+
+ T.setArch(Triple::tce);
+ EXPECT_EQ(Triple::tce, T.getBigEndianArchVariant().getArch());
+ EXPECT_EQ(Triple::tcele, T.getLittleEndianArchVariant().getArch());
+
+ T.setArch(Triple::le32);
+ EXPECT_EQ(Triple::UnknownArch, T.getBigEndianArchVariant().getArch());
+ EXPECT_EQ(Triple::le32, T.getLittleEndianArchVariant().getArch());
+
+ T.setArch(Triple::le64);
+ EXPECT_EQ(Triple::UnknownArch, T.getBigEndianArchVariant().getArch());
+ EXPECT_EQ(Triple::le64, T.getLittleEndianArchVariant().getArch());
}
TEST(TripleTest, getOSVersion) {
@@ -888,6 +952,9 @@ TEST(TripleTest, FileFormat) {
EXPECT_EQ(Triple::ELF, Triple("i686-pc-windows-msvc-elf").getObjectFormat());
EXPECT_EQ(Triple::ELF, Triple("i686-pc-cygwin-elf").getObjectFormat());
+ EXPECT_EQ(Triple::Wasm, Triple("wasm32-unknown-unknown-wasm").getObjectFormat());
+ EXPECT_EQ(Triple::Wasm, Triple("wasm64-unknown-unknown-wasm").getObjectFormat());
+
Triple MSVCNormalized(Triple::normalize("i686-pc-windows-msvc-elf"));
EXPECT_EQ(Triple::ELF, MSVCNormalized.getObjectFormat());
@@ -903,6 +970,9 @@ TEST(TripleTest, FileFormat) {
Triple T = Triple("");
T.setObjectFormat(Triple::ELF);
EXPECT_EQ(Triple::ELF, T.getObjectFormat());
+
+ T.setObjectFormat(Triple::MachO);
+ EXPECT_EQ(Triple::MachO, T.getObjectFormat());
}
TEST(TripleTest, NormalizeWindows) {
@@ -948,6 +1018,10 @@ TEST(TripleTest, getARMCPUForArch) {
EXPECT_EQ("cortex-a8", Triple.getARMCPUForArch());
}
{
+ llvm::Triple Triple("arm--openbsd");
+ EXPECT_EQ("cortex-a8", Triple.getARMCPUForArch());
+ }
+ {
llvm::Triple Triple("armv6-unknown-freebsd");
EXPECT_EQ("arm1176jzf-s", Triple.getARMCPUForArch());
}
diff --git a/unittests/Analysis/BlockFrequencyInfoTest.cpp b/unittests/Analysis/BlockFrequencyInfoTest.cpp
index b3b0fcfb049bf..c5c9d4dea055b 100644
--- a/unittests/Analysis/BlockFrequencyInfoTest.cpp
+++ b/unittests/Analysis/BlockFrequencyInfoTest.cpp
@@ -80,6 +80,14 @@ TEST_F(BlockFrequencyInfoTest, Basic) {
EXPECT_EQ(BFI.getBlockProfileCount(BB3).getValue(), UINT64_C(100));
EXPECT_EQ(BFI.getBlockProfileCount(BB1).getValue(), 100 * BB1Freq / BB0Freq);
EXPECT_EQ(BFI.getBlockProfileCount(BB2).getValue(), 100 * BB2Freq / BB0Freq);
+
+ // Scale the frequencies of BB0, BB1 and BB2 by a factor of two.
+ SmallPtrSet<BasicBlock *, 4> BlocksToScale({BB1, BB2});
+ BFI.setBlockFreqAndScale(&BB0, BB0Freq * 2, BlocksToScale);
+ EXPECT_EQ(BFI.getBlockFreq(&BB0).getFrequency(), 2 * BB0Freq);
+ EXPECT_EQ(BFI.getBlockFreq(BB1).getFrequency(), 2 * BB1Freq);
+ EXPECT_EQ(BFI.getBlockFreq(BB2).getFrequency(), 2 * BB2Freq);
+ EXPECT_EQ(BFI.getBlockFreq(BB3).getFrequency(), BB3Freq);
}
} // end anonymous namespace
diff --git a/unittests/Analysis/CMakeLists.txt b/unittests/Analysis/CMakeLists.txt
index ff4c17ee3b6b3..40d5ea5f5ad78 100644
--- a/unittests/Analysis/CMakeLists.txt
+++ b/unittests/Analysis/CMakeLists.txt
@@ -9,13 +9,17 @@ add_llvm_unittest(AnalysisTests
AliasAnalysisTest.cpp
BlockFrequencyInfoTest.cpp
BranchProbabilityInfoTest.cpp
- CallGraphTest.cpp
CFGTest.cpp
CGSCCPassManagerTest.cpp
+ CallGraphTest.cpp
LazyCallGraphTest.cpp
+ LoopInfoTest.cpp
MemoryBuiltinsTest.cpp
+ MemorySSA.cpp
+ ProfileSummaryInfoTest.cpp
ScalarEvolutionTest.cpp
TBAATest.cpp
- ValueTrackingTest.cpp
+ TargetLibraryInfoTest.cpp
UnrollAnalyzer.cpp
+ ValueTrackingTest.cpp
)
diff --git a/unittests/Analysis/LazyCallGraphTest.cpp b/unittests/Analysis/LazyCallGraphTest.cpp
index 5bb9dec3449fe..6955beb37109d 100644
--- a/unittests/Analysis/LazyCallGraphTest.cpp
+++ b/unittests/Analysis/LazyCallGraphTest.cpp
@@ -225,29 +225,29 @@ TEST(LazyCallGraphTest, BasicGraphFormation) {
// the IR, and everything in our module is an entry node, so just directly
// build variables for each node.
auto I = CG.begin();
- LazyCallGraph::Node &A1 = (I++)->getNode(CG);
+ LazyCallGraph::Node &A1 = (I++)->getNode();
EXPECT_EQ("a1", A1.getFunction().getName());
- LazyCallGraph::Node &A2 = (I++)->getNode(CG);
+ LazyCallGraph::Node &A2 = (I++)->getNode();
EXPECT_EQ("a2", A2.getFunction().getName());
- LazyCallGraph::Node &A3 = (I++)->getNode(CG);
+ LazyCallGraph::Node &A3 = (I++)->getNode();
EXPECT_EQ("a3", A3.getFunction().getName());
- LazyCallGraph::Node &B1 = (I++)->getNode(CG);
+ LazyCallGraph::Node &B1 = (I++)->getNode();
EXPECT_EQ("b1", B1.getFunction().getName());
- LazyCallGraph::Node &B2 = (I++)->getNode(CG);
+ LazyCallGraph::Node &B2 = (I++)->getNode();
EXPECT_EQ("b2", B2.getFunction().getName());
- LazyCallGraph::Node &B3 = (I++)->getNode(CG);
+ LazyCallGraph::Node &B3 = (I++)->getNode();
EXPECT_EQ("b3", B3.getFunction().getName());
- LazyCallGraph::Node &C1 = (I++)->getNode(CG);
+ LazyCallGraph::Node &C1 = (I++)->getNode();
EXPECT_EQ("c1", C1.getFunction().getName());
- LazyCallGraph::Node &C2 = (I++)->getNode(CG);
+ LazyCallGraph::Node &C2 = (I++)->getNode();
EXPECT_EQ("c2", C2.getFunction().getName());
- LazyCallGraph::Node &C3 = (I++)->getNode(CG);
+ LazyCallGraph::Node &C3 = (I++)->getNode();
EXPECT_EQ("c3", C3.getFunction().getName());
- LazyCallGraph::Node &D1 = (I++)->getNode(CG);
+ LazyCallGraph::Node &D1 = (I++)->getNode();
EXPECT_EQ("d1", D1.getFunction().getName());
- LazyCallGraph::Node &D2 = (I++)->getNode(CG);
+ LazyCallGraph::Node &D2 = (I++)->getNode();
EXPECT_EQ("d2", D2.getFunction().getName());
- LazyCallGraph::Node &D3 = (I++)->getNode(CG);
+ LazyCallGraph::Node &D3 = (I++)->getNode();
EXPECT_EQ("d3", D3.getFunction().getName());
EXPECT_EQ(CG.end(), I);
@@ -255,7 +255,7 @@ TEST(LazyCallGraphTest, BasicGraphFormation) {
// independent of order.
std::vector<std::string> Nodes;
- for (LazyCallGraph::Edge &E : A1)
+ for (LazyCallGraph::Edge &E : A1.populate())
Nodes.push_back(E.getFunction().getName());
std::sort(Nodes.begin(), Nodes.end());
EXPECT_EQ("a2", Nodes[0]);
@@ -263,43 +263,53 @@ TEST(LazyCallGraphTest, BasicGraphFormation) {
EXPECT_EQ("c3", Nodes[2]);
Nodes.clear();
- EXPECT_EQ(A2.end(), std::next(A2.begin()));
- EXPECT_EQ("a3", A2.begin()->getFunction().getName());
- EXPECT_EQ(A3.end(), std::next(A3.begin()));
- EXPECT_EQ("a1", A3.begin()->getFunction().getName());
+ A2.populate();
+ EXPECT_EQ(A2->end(), std::next(A2->begin()));
+ EXPECT_EQ("a3", A2->begin()->getFunction().getName());
+ A3.populate();
+ EXPECT_EQ(A3->end(), std::next(A3->begin()));
+ EXPECT_EQ("a1", A3->begin()->getFunction().getName());
- for (LazyCallGraph::Edge &E : B1)
+ for (LazyCallGraph::Edge &E : B1.populate())
Nodes.push_back(E.getFunction().getName());
std::sort(Nodes.begin(), Nodes.end());
EXPECT_EQ("b2", Nodes[0]);
EXPECT_EQ("d3", Nodes[1]);
Nodes.clear();
- EXPECT_EQ(B2.end(), std::next(B2.begin()));
- EXPECT_EQ("b3", B2.begin()->getFunction().getName());
- EXPECT_EQ(B3.end(), std::next(B3.begin()));
- EXPECT_EQ("b1", B3.begin()->getFunction().getName());
+ B2.populate();
+ EXPECT_EQ(B2->end(), std::next(B2->begin()));
+ EXPECT_EQ("b3", B2->begin()->getFunction().getName());
+ B3.populate();
+ EXPECT_EQ(B3->end(), std::next(B3->begin()));
+ EXPECT_EQ("b1", B3->begin()->getFunction().getName());
- for (LazyCallGraph::Edge &E : C1)
+ for (LazyCallGraph::Edge &E : C1.populate())
Nodes.push_back(E.getFunction().getName());
std::sort(Nodes.begin(), Nodes.end());
EXPECT_EQ("c2", Nodes[0]);
EXPECT_EQ("d2", Nodes[1]);
Nodes.clear();
- EXPECT_EQ(C2.end(), std::next(C2.begin()));
- EXPECT_EQ("c3", C2.begin()->getFunction().getName());
- EXPECT_EQ(C3.end(), std::next(C3.begin()));
- EXPECT_EQ("c1", C3.begin()->getFunction().getName());
-
- EXPECT_EQ(D1.end(), std::next(D1.begin()));
- EXPECT_EQ("d2", D1.begin()->getFunction().getName());
- EXPECT_EQ(D2.end(), std::next(D2.begin()));
- EXPECT_EQ("d3", D2.begin()->getFunction().getName());
- EXPECT_EQ(D3.end(), std::next(D3.begin()));
- EXPECT_EQ("d1", D3.begin()->getFunction().getName());
+ C2.populate();
+ EXPECT_EQ(C2->end(), std::next(C2->begin()));
+ EXPECT_EQ("c3", C2->begin()->getFunction().getName());
+ C3.populate();
+ EXPECT_EQ(C3->end(), std::next(C3->begin()));
+ EXPECT_EQ("c1", C3->begin()->getFunction().getName());
+
+ D1.populate();
+ EXPECT_EQ(D1->end(), std::next(D1->begin()));
+ EXPECT_EQ("d2", D1->begin()->getFunction().getName());
+ D2.populate();
+ EXPECT_EQ(D2->end(), std::next(D2->begin()));
+ EXPECT_EQ("d3", D2->begin()->getFunction().getName());
+ D3.populate();
+ EXPECT_EQ(D3->end(), std::next(D3->begin()));
+ EXPECT_EQ("d1", D3->begin()->getFunction().getName());
// Now lets look at the RefSCCs and SCCs.
+ CG.buildRefSCCs();
auto J = CG.postorder_ref_scc_begin();
LazyCallGraph::RefSCC &D = *J++;
@@ -401,32 +411,35 @@ TEST(LazyCallGraphTest, BasicGraphMutation) {
LazyCallGraph::Node &A = CG.get(lookupFunction(*M, "a"));
LazyCallGraph::Node &B = CG.get(lookupFunction(*M, "b"));
- EXPECT_EQ(2, std::distance(A.begin(), A.end()));
- EXPECT_EQ(0, std::distance(B.begin(), B.end()));
-
- CG.insertEdge(B, lookupFunction(*M, "c"), LazyCallGraph::Edge::Call);
- EXPECT_EQ(1, std::distance(B.begin(), B.end()));
- LazyCallGraph::Node &C = B.begin()->getNode(CG);
- EXPECT_EQ(0, std::distance(C.begin(), C.end()));
-
- CG.insertEdge(C, B.getFunction(), LazyCallGraph::Edge::Call);
- EXPECT_EQ(1, std::distance(C.begin(), C.end()));
- EXPECT_EQ(&B, C.begin()->getNode());
-
- CG.insertEdge(C, C.getFunction(), LazyCallGraph::Edge::Call);
- EXPECT_EQ(2, std::distance(C.begin(), C.end()));
- EXPECT_EQ(&B, C.begin()->getNode());
- EXPECT_EQ(&C, std::next(C.begin())->getNode());
-
- CG.removeEdge(C, B.getFunction());
- EXPECT_EQ(1, std::distance(C.begin(), C.end()));
- EXPECT_EQ(&C, C.begin()->getNode());
-
- CG.removeEdge(C, C.getFunction());
- EXPECT_EQ(0, std::distance(C.begin(), C.end()));
-
- CG.removeEdge(B, C.getFunction());
- EXPECT_EQ(0, std::distance(B.begin(), B.end()));
+ A.populate();
+ EXPECT_EQ(2, std::distance(A->begin(), A->end()));
+ B.populate();
+ EXPECT_EQ(0, std::distance(B->begin(), B->end()));
+
+ LazyCallGraph::Node &C = CG.get(lookupFunction(*M, "c"));
+ C.populate();
+ CG.insertEdge(B, C, LazyCallGraph::Edge::Call);
+ EXPECT_EQ(1, std::distance(B->begin(), B->end()));
+ EXPECT_EQ(0, std::distance(C->begin(), C->end()));
+
+ CG.insertEdge(C, B, LazyCallGraph::Edge::Call);
+ EXPECT_EQ(1, std::distance(C->begin(), C->end()));
+ EXPECT_EQ(&B, &C->begin()->getNode());
+
+ CG.insertEdge(C, C, LazyCallGraph::Edge::Call);
+ EXPECT_EQ(2, std::distance(C->begin(), C->end()));
+ EXPECT_EQ(&B, &C->begin()->getNode());
+ EXPECT_EQ(&C, &std::next(C->begin())->getNode());
+
+ CG.removeEdge(C, B);
+ EXPECT_EQ(1, std::distance(C->begin(), C->end()));
+ EXPECT_EQ(&C, &C->begin()->getNode());
+
+ CG.removeEdge(C, C);
+ EXPECT_EQ(0, std::distance(C->begin(), C->end()));
+
+ CG.removeEdge(B, C);
+ EXPECT_EQ(0, std::distance(B->begin(), B->end()));
}
TEST(LazyCallGraphTest, InnerSCCFormation) {
@@ -436,14 +449,18 @@ TEST(LazyCallGraphTest, InnerSCCFormation) {
// Now mutate the graph to connect every node into a single RefSCC to ensure
// that our inner SCC formation handles the rest.
- CG.insertEdge(lookupFunction(*M, "d1"), lookupFunction(*M, "a1"),
- LazyCallGraph::Edge::Ref);
+ LazyCallGraph::Node &D1 = CG.get(lookupFunction(*M, "d1"));
+ LazyCallGraph::Node &A1 = CG.get(lookupFunction(*M, "a1"));
+ A1.populate();
+ D1.populate();
+ CG.insertEdge(D1, A1, LazyCallGraph::Edge::Ref);
// Build vectors and sort them for the rest of the assertions to make them
// independent of order.
std::vector<std::string> Nodes;
// We should build a single RefSCC for the entire graph.
+ CG.buildRefSCCs();
auto I = CG.postorder_ref_scc_begin();
LazyCallGraph::RefSCC &RC = *I++;
EXPECT_EQ(CG.postorder_ref_scc_end(), I);
@@ -528,6 +545,7 @@ TEST(LazyCallGraphTest, MultiArmSCC) {
LazyCallGraph CG(*M);
// Force the graph to be fully expanded.
+ CG.buildRefSCCs();
auto I = CG.postorder_ref_scc_begin();
LazyCallGraph::RefSCC &RC = *I++;
EXPECT_EQ(CG.postorder_ref_scc_end(), I);
@@ -578,6 +596,7 @@ TEST(LazyCallGraphTest, OutgoingEdgeMutation) {
LazyCallGraph CG(*M);
// Force the graph to be fully expanded.
+ CG.buildRefSCCs();
for (LazyCallGraph::RefSCC &RC : CG.postorder_ref_sccs())
dbgs() << "Formed RefSCC: " << RC << "\n";
@@ -610,13 +629,13 @@ TEST(LazyCallGraphTest, OutgoingEdgeMutation) {
EXPECT_TRUE(DRC.isChildOf(CRC));
EXPECT_TRUE(DC.isChildOf(CC));
- EXPECT_EQ(2, std::distance(A.begin(), A.end()));
+ EXPECT_EQ(2, std::distance(A->begin(), A->end()));
ARC.insertOutgoingEdge(A, D, LazyCallGraph::Edge::Call);
- EXPECT_EQ(3, std::distance(A.begin(), A.end()));
- const LazyCallGraph::Edge &NewE = A[D];
+ EXPECT_EQ(3, std::distance(A->begin(), A->end()));
+ const LazyCallGraph::Edge &NewE = (*A)[D];
EXPECT_TRUE(NewE);
EXPECT_TRUE(NewE.isCall());
- EXPECT_EQ(&D, NewE.getNode());
+ EXPECT_EQ(&D, &NewE.getNode());
// Only the parent and child tests sholud have changed. The rest of the graph
// remains the same.
@@ -680,7 +699,7 @@ TEST(LazyCallGraphTest, OutgoingEdgeMutation) {
EXPECT_EQ(&DRC, CG.lookupRefSCC(D));
ARC.removeOutgoingEdge(A, D);
- EXPECT_EQ(2, std::distance(A.begin(), A.end()));
+ EXPECT_EQ(2, std::distance(A->begin(), A->end()));
// Now the parent and child tests fail again but the rest remains the same.
EXPECT_FALSE(ARC.isParentOf(DRC));
@@ -723,6 +742,7 @@ TEST(LazyCallGraphTest, IncomingEdgeInsertion) {
LazyCallGraph CG(*M);
// Force the graph to be fully expanded.
+ CG.buildRefSCCs();
for (LazyCallGraph::RefSCC &RC : CG.postorder_ref_sccs())
dbgs() << "Formed RefSCC: " << RC << "\n";
@@ -750,7 +770,7 @@ TEST(LazyCallGraphTest, IncomingEdgeInsertion) {
ASSERT_EQ(&CRC, CG.lookupRefSCC(C3));
ASSERT_EQ(&DRC, CG.lookupRefSCC(D2));
ASSERT_EQ(&DRC, CG.lookupRefSCC(D3));
- ASSERT_EQ(1, std::distance(D2.begin(), D2.end()));
+ ASSERT_EQ(1, std::distance(D2->begin(), D2->end()));
// Add an edge to make the graph:
//
@@ -767,10 +787,10 @@ TEST(LazyCallGraphTest, IncomingEdgeInsertion) {
// a3--a2 |
auto MergedRCs = CRC.insertIncomingRefEdge(D2, C2);
// Make sure we connected the nodes.
- for (LazyCallGraph::Edge E : D2) {
- if (E.getNode() == &D3)
+ for (LazyCallGraph::Edge E : *D2) {
+ if (&E.getNode() == &D3)
continue;
- EXPECT_EQ(&C2, E.getNode());
+ EXPECT_EQ(&C2, &E.getNode());
}
// And marked the D ref-SCC as no longer valid.
EXPECT_EQ(1u, MergedRCs.size());
@@ -805,102 +825,6 @@ TEST(LazyCallGraphTest, IncomingEdgeInsertion) {
EXPECT_EQ(++I, E);
}
-TEST(LazyCallGraphTest, IncomingEdgeInsertionMidTraversal) {
- LLVMContext Context;
- // This is the same fundamental test as the previous, but we perform it
- // having only partially walked the RefSCCs of the graph.
- std::unique_ptr<Module> M = parseAssembly(Context, DiamondOfTriangles);
- LazyCallGraph CG(*M);
-
- // Walk the RefSCCs until we find the one containing 'c1'.
- auto I = CG.postorder_ref_scc_begin(), E = CG.postorder_ref_scc_end();
- ASSERT_NE(I, E);
- LazyCallGraph::RefSCC &DRC = *I;
- ASSERT_NE(&DRC, nullptr);
- ++I;
- ASSERT_NE(I, E);
- LazyCallGraph::RefSCC &CRC = *I;
- ASSERT_NE(&CRC, nullptr);
-
- ASSERT_EQ(nullptr, CG.lookup(lookupFunction(*M, "a1")));
- ASSERT_EQ(nullptr, CG.lookup(lookupFunction(*M, "a2")));
- ASSERT_EQ(nullptr, CG.lookup(lookupFunction(*M, "a3")));
- ASSERT_EQ(nullptr, CG.lookup(lookupFunction(*M, "b1")));
- ASSERT_EQ(nullptr, CG.lookup(lookupFunction(*M, "b2")));
- ASSERT_EQ(nullptr, CG.lookup(lookupFunction(*M, "b3")));
- LazyCallGraph::Node &C1 = *CG.lookup(lookupFunction(*M, "c1"));
- LazyCallGraph::Node &C2 = *CG.lookup(lookupFunction(*M, "c2"));
- LazyCallGraph::Node &C3 = *CG.lookup(lookupFunction(*M, "c3"));
- LazyCallGraph::Node &D1 = *CG.lookup(lookupFunction(*M, "d1"));
- LazyCallGraph::Node &D2 = *CG.lookup(lookupFunction(*M, "d2"));
- LazyCallGraph::Node &D3 = *CG.lookup(lookupFunction(*M, "d3"));
- ASSERT_EQ(&CRC, CG.lookupRefSCC(C1));
- ASSERT_EQ(&CRC, CG.lookupRefSCC(C2));
- ASSERT_EQ(&CRC, CG.lookupRefSCC(C3));
- ASSERT_EQ(&DRC, CG.lookupRefSCC(D1));
- ASSERT_EQ(&DRC, CG.lookupRefSCC(D2));
- ASSERT_EQ(&DRC, CG.lookupRefSCC(D3));
- ASSERT_EQ(1, std::distance(D2.begin(), D2.end()));
-
- auto MergedRCs = CRC.insertIncomingRefEdge(D2, C2);
- // Make sure we connected the nodes.
- for (LazyCallGraph::Edge E : D2) {
- if (E.getNode() == &D3)
- continue;
- EXPECT_EQ(&C2, E.getNode());
- }
- // And marked the D ref-SCC as no longer valid.
- EXPECT_EQ(1u, MergedRCs.size());
- EXPECT_EQ(&DRC, MergedRCs[0]);
-
- // Make sure we have the correct nodes in the RefSCCs.
- EXPECT_EQ(&CRC, CG.lookupRefSCC(C1));
- EXPECT_EQ(&CRC, CG.lookupRefSCC(C2));
- EXPECT_EQ(&CRC, CG.lookupRefSCC(C3));
- EXPECT_EQ(&CRC, CG.lookupRefSCC(D1));
- EXPECT_EQ(&CRC, CG.lookupRefSCC(D2));
- EXPECT_EQ(&CRC, CG.lookupRefSCC(D3));
-
- // Verify that the post-order walk reflects the updated but still incomplete
- // structure.
- auto J = CG.postorder_ref_scc_begin();
- EXPECT_NE(J, E);
- EXPECT_EQ(&CRC, &*J) << "Actual RefSCC: " << *J;
- EXPECT_EQ(I, J);
-
- // Check that we can form the last two RefSCCs now, and even that we can do
- // it with alternating iterators.
- ++J;
- EXPECT_NE(J, E);
- LazyCallGraph::RefSCC &BRC = *J;
- EXPECT_NE(&BRC, nullptr);
- EXPECT_EQ(&BRC, CG.lookupRefSCC(*CG.lookup(lookupFunction(*M, "b1"))));
- EXPECT_EQ(&BRC, CG.lookupRefSCC(*CG.lookup(lookupFunction(*M, "b2"))));
- EXPECT_EQ(&BRC, CG.lookupRefSCC(*CG.lookup(lookupFunction(*M, "b3"))));
- EXPECT_TRUE(BRC.isParentOf(CRC));
- ++I;
- EXPECT_EQ(J, I);
- EXPECT_EQ(&BRC, &*I) << "Actual RefSCC: " << *I;
-
- // Increment I this time to form the new RefSCC, flopping back to the first
- // iterator.
- ++I;
- EXPECT_NE(I, E);
- LazyCallGraph::RefSCC &ARC = *I;
- EXPECT_NE(&ARC, nullptr);
- EXPECT_EQ(&ARC, CG.lookupRefSCC(*CG.lookup(lookupFunction(*M, "a1"))));
- EXPECT_EQ(&ARC, CG.lookupRefSCC(*CG.lookup(lookupFunction(*M, "a2"))));
- EXPECT_EQ(&ARC, CG.lookupRefSCC(*CG.lookup(lookupFunction(*M, "a3"))));
- EXPECT_TRUE(ARC.isParentOf(CRC));
- ++J;
- EXPECT_EQ(I, J);
- EXPECT_EQ(&ARC, &*J) << "Actual RefSCC: " << *J;
- ++I;
- EXPECT_EQ(E, I);
- ++J;
- EXPECT_EQ(E, J);
-}
-
TEST(LazyCallGraphTest, IncomingEdgeInsertionRefGraph) {
LLVMContext Context;
// Another variation of the above test but with all the edges switched to
@@ -910,6 +834,7 @@ TEST(LazyCallGraphTest, IncomingEdgeInsertionRefGraph) {
LazyCallGraph CG(*M);
// Force the graph to be fully expanded.
+ CG.buildRefSCCs();
for (LazyCallGraph::RefSCC &RC : CG.postorder_ref_sccs())
dbgs() << "Formed RefSCC: " << RC << "\n";
@@ -937,7 +862,7 @@ TEST(LazyCallGraphTest, IncomingEdgeInsertionRefGraph) {
ASSERT_EQ(&CRC, CG.lookupRefSCC(C3));
ASSERT_EQ(&DRC, CG.lookupRefSCC(D2));
ASSERT_EQ(&DRC, CG.lookupRefSCC(D3));
- ASSERT_EQ(1, std::distance(D2.begin(), D2.end()));
+ ASSERT_EQ(1, std::distance(D2->begin(), D2->end()));
// Add an edge to make the graph:
//
@@ -954,10 +879,10 @@ TEST(LazyCallGraphTest, IncomingEdgeInsertionRefGraph) {
// a3--a2 |
auto MergedRCs = CRC.insertIncomingRefEdge(D2, C2);
// Make sure we connected the nodes.
- for (LazyCallGraph::Edge E : D2) {
- if (E.getNode() == &D3)
+ for (LazyCallGraph::Edge E : *D2) {
+ if (&E.getNode() == &D3)
continue;
- EXPECT_EQ(&C2, E.getNode());
+ EXPECT_EQ(&C2, &E.getNode());
}
// And marked the D ref-SCC as no longer valid.
EXPECT_EQ(1u, MergedRCs.size());
@@ -1016,6 +941,7 @@ TEST(LazyCallGraphTest, IncomingEdgeInsertionLargeCallCycle) {
LazyCallGraph CG(*M);
// Force the graph to be fully expanded.
+ CG.buildRefSCCs();
for (LazyCallGraph::RefSCC &RC : CG.postorder_ref_sccs())
dbgs() << "Formed RefSCC: " << RC << "\n";
@@ -1035,8 +961,8 @@ TEST(LazyCallGraphTest, IncomingEdgeInsertionLargeCallCycle) {
// Connect the top to the bottom forming a large RefSCC made up mostly of calls.
auto MergedRCs = ARC.insertIncomingRefEdge(D, A);
// Make sure we connected the nodes.
- EXPECT_NE(D.begin(), D.end());
- EXPECT_EQ(&A, D.begin()->getNode());
+ EXPECT_NE(D->begin(), D->end());
+ EXPECT_EQ(&A, &D->begin()->getNode());
// Check that we have the dead RCs, but ignore the order.
EXPECT_EQ(3u, MergedRCs.size());
@@ -1092,6 +1018,7 @@ TEST(LazyCallGraphTest, IncomingEdgeInsertionLargeRefCycle) {
LazyCallGraph CG(*M);
// Force the graph to be fully expanded.
+ CG.buildRefSCCs();
for (LazyCallGraph::RefSCC &RC : CG.postorder_ref_sccs())
dbgs() << "Formed RefSCC: " << RC << "\n";
@@ -1108,8 +1035,8 @@ TEST(LazyCallGraphTest, IncomingEdgeInsertionLargeRefCycle) {
// references.
auto MergedRCs = ARC.insertIncomingRefEdge(D, A);
// Make sure we connected the nodes.
- EXPECT_NE(D.begin(), D.end());
- EXPECT_EQ(&A, D.begin()->getNode());
+ EXPECT_NE(D->begin(), D->end());
+ EXPECT_EQ(&A, &D->begin()->getNode());
// Check that we have the dead RCs, but ignore the order.
EXPECT_EQ(3u, MergedRCs.size());
@@ -1153,6 +1080,7 @@ TEST(LazyCallGraphTest, InlineAndDeleteFunction) {
LazyCallGraph CG(*M);
// Force the graph to be fully expanded.
+ CG.buildRefSCCs();
for (LazyCallGraph::RefSCC &RC : CG.postorder_ref_sccs())
dbgs() << "Formed RefSCC: " << RC << "\n";
@@ -1180,7 +1108,7 @@ TEST(LazyCallGraphTest, InlineAndDeleteFunction) {
ASSERT_EQ(&CRC, CG.lookupRefSCC(C3));
ASSERT_EQ(&DRC, CG.lookupRefSCC(D2));
ASSERT_EQ(&DRC, CG.lookupRefSCC(D3));
- ASSERT_EQ(1, std::distance(D2.begin(), D2.end()));
+ ASSERT_EQ(1, std::distance(D2->begin(), D2->end()));
// Delete d2 from the graph, as if it had been inlined.
//
@@ -1276,177 +1204,6 @@ TEST(LazyCallGraphTest, InlineAndDeleteFunction) {
EXPECT_EQ(++I, E);
}
-TEST(LazyCallGraphTest, InlineAndDeleteFunctionMidTraversal) {
- LLVMContext Context;
- // This is the same fundamental test as the previous, but we perform it
- // having only partially walked the RefSCCs of the graph.
- //
- // The ascii diagram is repeated here for easy reference.
- //
- // d1 |
- // / \ |
- // d3--d2 |
- // / \ |
- // b1 c1 |
- // / \ / \ |
- // b3--b2 c3--c2 |
- // \ / |
- // a1 |
- // / \ |
- // a3--a2 |
- //
- std::unique_ptr<Module> M = parseAssembly(Context, DiamondOfTriangles);
- LazyCallGraph CG(*M);
-
- // Walk the RefSCCs until we find the one containing 'c1'.
- auto I = CG.postorder_ref_scc_begin(), E = CG.postorder_ref_scc_end();
- ASSERT_NE(I, E);
- LazyCallGraph::RefSCC &DRC = *I;
- ASSERT_NE(&DRC, nullptr);
- ++I;
- ASSERT_NE(I, E);
- LazyCallGraph::RefSCC &CRC = *I;
- ASSERT_NE(&CRC, nullptr);
-
- ASSERT_EQ(nullptr, CG.lookup(lookupFunction(*M, "a1")));
- ASSERT_EQ(nullptr, CG.lookup(lookupFunction(*M, "a2")));
- ASSERT_EQ(nullptr, CG.lookup(lookupFunction(*M, "a3")));
- ASSERT_EQ(nullptr, CG.lookup(lookupFunction(*M, "b1")));
- ASSERT_EQ(nullptr, CG.lookup(lookupFunction(*M, "b2")));
- ASSERT_EQ(nullptr, CG.lookup(lookupFunction(*M, "b3")));
- LazyCallGraph::Node &C1 = *CG.lookup(lookupFunction(*M, "c1"));
- LazyCallGraph::Node &C2 = *CG.lookup(lookupFunction(*M, "c2"));
- LazyCallGraph::Node &C3 = *CG.lookup(lookupFunction(*M, "c3"));
- LazyCallGraph::Node &D1 = *CG.lookup(lookupFunction(*M, "d1"));
- LazyCallGraph::Node &D2 = *CG.lookup(lookupFunction(*M, "d2"));
- LazyCallGraph::Node &D3 = *CG.lookup(lookupFunction(*M, "d3"));
- ASSERT_EQ(&CRC, CG.lookupRefSCC(C1));
- ASSERT_EQ(&CRC, CG.lookupRefSCC(C2));
- ASSERT_EQ(&CRC, CG.lookupRefSCC(C3));
- ASSERT_EQ(&DRC, CG.lookupRefSCC(D1));
- ASSERT_EQ(&DRC, CG.lookupRefSCC(D2));
- ASSERT_EQ(&DRC, CG.lookupRefSCC(D3));
- ASSERT_EQ(1, std::distance(D2.begin(), D2.end()));
-
- // Delete d2 from the graph, as if it had been inlined.
- //
- // d1 |
- // / / |
- // d3--. |
- // / \ |
- // b1 c1 |
- // / \ / \ |
- // b3--b2 c3--c2 |
- // \ / |
- // a1 |
- // / \ |
- // a3--a2 |
-
- Function &D2F = D2.getFunction();
- CallInst *C1Call = nullptr, *D1Call = nullptr;
- for (User *U : D2F.users()) {
- CallInst *CI = dyn_cast<CallInst>(U);
- ASSERT_TRUE(CI) << "Expected a call: " << *U;
- if (CI->getParent()->getParent() == &C1.getFunction()) {
- ASSERT_EQ(nullptr, C1Call) << "Found too many C1 calls: " << *CI;
- C1Call = CI;
- } else if (CI->getParent()->getParent() == &D1.getFunction()) {
- ASSERT_EQ(nullptr, D1Call) << "Found too many D1 calls: " << *CI;
- D1Call = CI;
- } else {
- FAIL() << "Found an unexpected call instruction: " << *CI;
- }
- }
- ASSERT_NE(C1Call, nullptr);
- ASSERT_NE(D1Call, nullptr);
- ASSERT_EQ(&D2F, C1Call->getCalledFunction());
- ASSERT_EQ(&D2F, D1Call->getCalledFunction());
- C1Call->setCalledFunction(&D3.getFunction());
- D1Call->setCalledFunction(&D3.getFunction());
- ASSERT_EQ(0u, D2F.getNumUses());
-
- // Insert new edges first.
- CRC.insertTrivialCallEdge(C1, D3);
- DRC.insertTrivialCallEdge(D1, D3);
-
- // Then remove the old ones.
- LazyCallGraph::SCC &DC = *CG.lookupSCC(D2);
- auto NewCs = DRC.switchInternalEdgeToRef(D1, D2);
- EXPECT_EQ(&DC, CG.lookupSCC(D2));
- EXPECT_EQ(NewCs.end(), std::next(NewCs.begin()));
- LazyCallGraph::SCC &NewDC = *NewCs.begin();
- EXPECT_EQ(&NewDC, CG.lookupSCC(D1));
- EXPECT_EQ(&NewDC, CG.lookupSCC(D3));
- auto NewRCs = DRC.removeInternalRefEdge(D1, D2);
- EXPECT_EQ(&DRC, CG.lookupRefSCC(D2));
- EXPECT_EQ(NewRCs.end(), std::next(NewRCs.begin()));
- LazyCallGraph::RefSCC &NewDRC = **NewRCs.begin();
- EXPECT_EQ(&NewDRC, CG.lookupRefSCC(D1));
- EXPECT_EQ(&NewDRC, CG.lookupRefSCC(D3));
- EXPECT_FALSE(NewDRC.isParentOf(DRC));
- EXPECT_TRUE(CRC.isParentOf(DRC));
- EXPECT_TRUE(CRC.isParentOf(NewDRC));
- EXPECT_TRUE(DRC.isParentOf(NewDRC));
- CRC.removeOutgoingEdge(C1, D2);
- EXPECT_FALSE(CRC.isParentOf(DRC));
- EXPECT_TRUE(CRC.isParentOf(NewDRC));
- EXPECT_TRUE(DRC.isParentOf(NewDRC));
-
- // Now that we've updated the call graph, D2 is dead, so remove it.
- CG.removeDeadFunction(D2F);
-
- // Check that the graph still looks the same.
- EXPECT_EQ(&CRC, CG.lookupRefSCC(C1));
- EXPECT_EQ(&CRC, CG.lookupRefSCC(C2));
- EXPECT_EQ(&CRC, CG.lookupRefSCC(C3));
- EXPECT_EQ(&NewDRC, CG.lookupRefSCC(D1));
- EXPECT_EQ(&NewDRC, CG.lookupRefSCC(D3));
- EXPECT_TRUE(CRC.isParentOf(NewDRC));
-
- // Verify that the post-order walk reflects the updated but still incomplete
- // structure.
- auto J = CG.postorder_ref_scc_begin();
- EXPECT_NE(J, E);
- EXPECT_EQ(&NewDRC, &*J) << "Actual RefSCC: " << *J;
- ++J;
- EXPECT_NE(J, E);
- EXPECT_EQ(&CRC, &*J) << "Actual RefSCC: " << *J;
- EXPECT_EQ(I, J);
-
- // Check that we can form the last two RefSCCs now, and even that we can do
- // it with alternating iterators.
- ++J;
- EXPECT_NE(J, E);
- LazyCallGraph::RefSCC &BRC = *J;
- EXPECT_NE(&BRC, nullptr);
- EXPECT_EQ(&BRC, CG.lookupRefSCC(*CG.lookup(lookupFunction(*M, "b1"))));
- EXPECT_EQ(&BRC, CG.lookupRefSCC(*CG.lookup(lookupFunction(*M, "b2"))));
- EXPECT_EQ(&BRC, CG.lookupRefSCC(*CG.lookup(lookupFunction(*M, "b3"))));
- EXPECT_TRUE(BRC.isParentOf(NewDRC));
- ++I;
- EXPECT_EQ(J, I);
- EXPECT_EQ(&BRC, &*I) << "Actual RefSCC: " << *I;
-
- // Increment I this time to form the new RefSCC, flopping back to the first
- // iterator.
- ++I;
- EXPECT_NE(I, E);
- LazyCallGraph::RefSCC &ARC = *I;
- EXPECT_NE(&ARC, nullptr);
- EXPECT_EQ(&ARC, CG.lookupRefSCC(*CG.lookup(lookupFunction(*M, "a1"))));
- EXPECT_EQ(&ARC, CG.lookupRefSCC(*CG.lookup(lookupFunction(*M, "a2"))));
- EXPECT_EQ(&ARC, CG.lookupRefSCC(*CG.lookup(lookupFunction(*M, "a3"))));
- EXPECT_TRUE(ARC.isParentOf(BRC));
- EXPECT_TRUE(ARC.isParentOf(CRC));
- ++J;
- EXPECT_EQ(I, J);
- EXPECT_EQ(&ARC, &*J) << "Actual RefSCC: " << *J;
- ++I;
- EXPECT_EQ(E, I);
- ++J;
- EXPECT_EQ(E, J);
-}
-
TEST(LazyCallGraphTest, InternalEdgeMutation) {
LLVMContext Context;
std::unique_ptr<Module> M = parseAssembly(Context, "define void @a() {\n"
@@ -1467,6 +1224,7 @@ TEST(LazyCallGraphTest, InternalEdgeMutation) {
LazyCallGraph CG(*M);
// Force the graph to be fully expanded.
+ CG.buildRefSCCs();
auto I = CG.postorder_ref_scc_begin();
LazyCallGraph::RefSCC &RC = *I++;
EXPECT_EQ(CG.postorder_ref_scc_end(), I);
@@ -1484,7 +1242,7 @@ TEST(LazyCallGraphTest, InternalEdgeMutation) {
// Insert an edge from 'a' to 'c'. Nothing changes about the graph.
RC.insertInternalRefEdge(A, C);
- EXPECT_EQ(2, std::distance(A.begin(), A.end()));
+ EXPECT_EQ(2, std::distance(A->begin(), A->end()));
EXPECT_EQ(&RC, CG.lookupRefSCC(A));
EXPECT_EQ(&RC, CG.lookupRefSCC(B));
EXPECT_EQ(&RC, CG.lookupRefSCC(C));
@@ -1559,6 +1317,7 @@ TEST(LazyCallGraphTest, InternalEdgeRemoval) {
LazyCallGraph CG(*M);
// Force the graph to be fully expanded.
+ CG.buildRefSCCs();
auto I = CG.postorder_ref_scc_begin(), E = CG.postorder_ref_scc_end();
LazyCallGraph::RefSCC &RC = *I;
EXPECT_EQ(E, std::next(I));
@@ -1633,6 +1392,7 @@ TEST(LazyCallGraphTest, InternalNoOpEdgeRemoval) {
LazyCallGraph CG(*M);
// Force the graph to be fully expanded.
+ CG.buildRefSCCs();
auto I = CG.postorder_ref_scc_begin(), E = CG.postorder_ref_scc_end();
LazyCallGraph::RefSCC &RC = *I;
EXPECT_EQ(E, std::next(I));
@@ -1709,6 +1469,7 @@ TEST(LazyCallGraphTest, InternalCallEdgeToRef) {
LazyCallGraph CG(*M);
// Force the graph to be fully expanded.
+ CG.buildRefSCCs();
auto I = CG.postorder_ref_scc_begin();
LazyCallGraph::RefSCC &RC = *I++;
EXPECT_EQ(CG.postorder_ref_scc_end(), I);
@@ -1801,6 +1562,7 @@ TEST(LazyCallGraphTest, InternalRefEdgeToCall) {
LazyCallGraph CG(*M);
// Force the graph to be fully expanded.
+ CG.buildRefSCCs();
auto I = CG.postorder_ref_scc_begin();
LazyCallGraph::RefSCC &RC = *I++;
EXPECT_EQ(CG.postorder_ref_scc_end(), I);
@@ -1913,6 +1675,7 @@ TEST(LazyCallGraphTest, InternalRefEdgeToCallNoCycleInterleaved) {
LazyCallGraph CG(*M);
// Force the graph to be fully expanded.
+ CG.buildRefSCCs();
auto I = CG.postorder_ref_scc_begin();
LazyCallGraph::RefSCC &RC = *I++;
EXPECT_EQ(CG.postorder_ref_scc_end(), I);
@@ -2043,6 +1806,7 @@ TEST(LazyCallGraphTest, InternalRefEdgeToCallBothPartitionAndMerge) {
LazyCallGraph CG(*M);
// Force the graph to be fully expanded.
+ CG.buildRefSCCs();
auto I = CG.postorder_ref_scc_begin();
LazyCallGraph::RefSCC &RC = *I++;
EXPECT_EQ(CG.postorder_ref_scc_end(), I);
@@ -2122,6 +1886,7 @@ TEST(LazyCallGraphTest, HandleBlockAddress) {
"}\n");
LazyCallGraph CG(*M);
+ CG.buildRefSCCs();
auto I = CG.postorder_ref_scc_begin();
LazyCallGraph::RefSCC &FRC = *I++;
LazyCallGraph::RefSCC &GRC = *I++;
@@ -2134,4 +1899,165 @@ TEST(LazyCallGraphTest, HandleBlockAddress) {
EXPECT_TRUE(GRC.isParentOf(FRC));
}
+TEST(LazyCallGraphTest, ReplaceNodeFunction) {
+ LLVMContext Context;
+ // A graph with several different kinds of edges pointing at a particular
+ // function.
+ std::unique_ptr<Module> M =
+ parseAssembly(Context,
+ "define void @a(i8** %ptr) {\n"
+ "entry:\n"
+ " store i8* bitcast (void(i8**)* @d to i8*), i8** %ptr\n"
+ " ret void\n"
+ "}\n"
+ "define void @b(i8** %ptr) {\n"
+ "entry:\n"
+ " store i8* bitcast (void(i8**)* @d to i8*), i8** %ptr\n"
+ " store i8* bitcast (void(i8**)* @d to i8*), i8** %ptr\n"
+ " call void @d(i8** %ptr)"
+ " ret void\n"
+ "}\n"
+ "define void @c(i8** %ptr) {\n"
+ "entry:\n"
+ " call void @d(i8** %ptr)"
+ " call void @d(i8** %ptr)"
+ " store i8* bitcast (void(i8**)* @d to i8*), i8** %ptr\n"
+ " ret void\n"
+ "}\n"
+ "define void @d(i8** %ptr) {\n"
+ "entry:\n"
+ " store i8* bitcast (void(i8**)* @b to i8*), i8** %ptr\n"
+ " call void @c(i8** %ptr)"
+ " call void @d(i8** %ptr)"
+ " store i8* bitcast (void(i8**)* @d to i8*), i8** %ptr\n"
+ " ret void\n"
+ "}\n");
+ LazyCallGraph CG(*M);
+
+ // Force the graph to be fully expanded.
+ CG.buildRefSCCs();
+ auto I = CG.postorder_ref_scc_begin();
+ LazyCallGraph::RefSCC &RC1 = *I++;
+ LazyCallGraph::RefSCC &RC2 = *I++;
+ EXPECT_EQ(CG.postorder_ref_scc_end(), I);
+
+ ASSERT_EQ(2, RC1.size());
+ LazyCallGraph::SCC &C1 = RC1[0];
+ LazyCallGraph::SCC &C2 = RC1[1];
+
+ LazyCallGraph::Node &AN = *CG.lookup(lookupFunction(*M, "a"));
+ LazyCallGraph::Node &BN = *CG.lookup(lookupFunction(*M, "b"));
+ LazyCallGraph::Node &CN = *CG.lookup(lookupFunction(*M, "c"));
+ LazyCallGraph::Node &DN = *CG.lookup(lookupFunction(*M, "d"));
+ EXPECT_EQ(&C1, CG.lookupSCC(DN));
+ EXPECT_EQ(&C1, CG.lookupSCC(CN));
+ EXPECT_EQ(&C2, CG.lookupSCC(BN));
+ EXPECT_EQ(&RC1, CG.lookupRefSCC(DN));
+ EXPECT_EQ(&RC1, CG.lookupRefSCC(CN));
+ EXPECT_EQ(&RC1, CG.lookupRefSCC(BN));
+ EXPECT_EQ(&RC2, CG.lookupRefSCC(AN));
+
+ // Now we need to build a new function 'e' with the same signature as 'd'.
+ Function &D = DN.getFunction();
+ Function &E = *Function::Create(D.getFunctionType(), D.getLinkage(), "e");
+ D.getParent()->getFunctionList().insert(D.getIterator(), &E);
+
+ // Change each use of 'd' to use 'e'. This is particularly easy as they have
+ // the same type.
+ D.replaceAllUsesWith(&E);
+
+ // Splice the body of the old function into the new one.
+ E.getBasicBlockList().splice(E.begin(), D.getBasicBlockList());
+ // And fix up the one argument.
+ D.arg_begin()->replaceAllUsesWith(&*E.arg_begin());
+ E.arg_begin()->takeName(&*D.arg_begin());
+
+ // Now replace the function in the graph.
+ RC1.replaceNodeFunction(DN, E);
+
+ EXPECT_EQ(&E, &DN.getFunction());
+ EXPECT_EQ(&DN, &(*CN)[DN].getNode());
+ EXPECT_EQ(&DN, &(*BN)[DN].getNode());
+}
+
+TEST(LazyCallGraphTest, RemoveFunctionWithSpurriousRef) {
+ LLVMContext Context;
+ // A graph with a couple of RefSCCs.
+ std::unique_ptr<Module> M =
+ parseAssembly(Context,
+ "define void @a(i8** %ptr) {\n"
+ "entry:\n"
+ " store i8* bitcast (void(i8**)* @d to i8*), i8** %ptr\n"
+ " ret void\n"
+ "}\n"
+ "define void @b(i8** %ptr) {\n"
+ "entry:\n"
+ " store i8* bitcast (void(i8**)* @c to i8*), i8** %ptr\n"
+ " ret void\n"
+ "}\n"
+ "define void @c(i8** %ptr) {\n"
+ "entry:\n"
+ " call void @d(i8** %ptr)"
+ " ret void\n"
+ "}\n"
+ "define void @d(i8** %ptr) {\n"
+ "entry:\n"
+ " call void @c(i8** %ptr)"
+ " store i8* bitcast (void(i8**)* @b to i8*), i8** %ptr\n"
+ " ret void\n"
+ "}\n"
+ "define void @dead() {\n"
+ "entry:\n"
+ " ret void\n"
+ "}\n");
+ LazyCallGraph CG(*M);
+
+ // Insert spurious ref edges.
+ LazyCallGraph::Node &AN = CG.get(lookupFunction(*M, "a"));
+ LazyCallGraph::Node &BN = CG.get(lookupFunction(*M, "b"));
+ LazyCallGraph::Node &CN = CG.get(lookupFunction(*M, "c"));
+ LazyCallGraph::Node &DN = CG.get(lookupFunction(*M, "d"));
+ LazyCallGraph::Node &DeadN = CG.get(lookupFunction(*M, "dead"));
+ AN.populate();
+ BN.populate();
+ CN.populate();
+ DN.populate();
+ DeadN.populate();
+ CG.insertEdge(AN, DeadN, LazyCallGraph::Edge::Ref);
+ CG.insertEdge(BN, DeadN, LazyCallGraph::Edge::Ref);
+ CG.insertEdge(CN, DeadN, LazyCallGraph::Edge::Ref);
+ CG.insertEdge(DN, DeadN, LazyCallGraph::Edge::Ref);
+
+ // Force the graph to be fully expanded.
+ CG.buildRefSCCs();
+ auto I = CG.postorder_ref_scc_begin();
+ LazyCallGraph::RefSCC &DeadRC = *I++;
+ LazyCallGraph::RefSCC &RC1 = *I++;
+ LazyCallGraph::RefSCC &RC2 = *I++;
+ EXPECT_EQ(CG.postorder_ref_scc_end(), I);
+
+ ASSERT_EQ(2, RC1.size());
+ LazyCallGraph::SCC &C1 = RC1[0];
+ LazyCallGraph::SCC &C2 = RC1[1];
+
+ EXPECT_EQ(&DeadRC, CG.lookupRefSCC(DeadN));
+ EXPECT_EQ(&C1, CG.lookupSCC(DN));
+ EXPECT_EQ(&C1, CG.lookupSCC(CN));
+ EXPECT_EQ(&C2, CG.lookupSCC(BN));
+ EXPECT_EQ(&RC1, CG.lookupRefSCC(DN));
+ EXPECT_EQ(&RC1, CG.lookupRefSCC(CN));
+ EXPECT_EQ(&RC1, CG.lookupRefSCC(BN));
+ EXPECT_EQ(&RC2, CG.lookupRefSCC(AN));
+
+ // Now delete 'dead'. There are no uses of this function but there are
+ // spurious references.
+ CG.removeDeadFunction(DeadN.getFunction());
+
+ // The only observable change should be that the RefSCC is gone from the
+ // postorder sequence.
+ I = CG.postorder_ref_scc_begin();
+ EXPECT_EQ(&RC1, &*I++);
+ EXPECT_EQ(&RC2, &*I++);
+ EXPECT_EQ(CG.postorder_ref_scc_end(), I);
+}
}
diff --git a/unittests/Analysis/LoopInfoTest.cpp b/unittests/Analysis/LoopInfoTest.cpp
new file mode 100644
index 0000000000000..647ce8a3c1ba0
--- /dev/null
+++ b/unittests/Analysis/LoopInfoTest.cpp
@@ -0,0 +1,158 @@
+//===- LoopInfoTest.cpp - LoopInfo unit tests -----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/AsmParser/Parser.h"
+#include "llvm/IR/Dominators.h"
+#include "llvm/Support/SourceMgr.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+/// Build the loop info for the function and run the Test.
+static void
+runWithLoopInfo(Module &M, StringRef FuncName,
+ function_ref<void(Function &F, LoopInfo &LI)> Test) {
+ auto *F = M.getFunction(FuncName);
+ ASSERT_NE(F, nullptr) << "Could not find " << FuncName;
+ // Compute the dominator tree and the loop info for the function.
+ DominatorTree DT(*F);
+ LoopInfo LI(DT);
+ Test(*F, LI);
+}
+
+static std::unique_ptr<Module> makeLLVMModule(LLVMContext &Context,
+ const char *ModuleStr) {
+ SMDiagnostic Err;
+ return parseAssemblyString(ModuleStr, Err, Context);
+}
+
+// This tests that for a loop with a single latch, we get the loop id from
+// its only latch, even in case the loop may not be in a simplified form.
+TEST(LoopInfoTest, LoopWithSingleLatch) {
+ const char *ModuleStr =
+ "target datalayout = \"e-m:o-i64:64-f80:128-n8:16:32:64-S128\"\n"
+ "define void @foo(i32 %n) {\n"
+ "entry:\n"
+ " br i1 undef, label %for.cond, label %for.end\n"
+ "for.cond:\n"
+ " %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]\n"
+ " %cmp = icmp slt i32 %i.0, %n\n"
+ " br i1 %cmp, label %for.inc, label %for.end\n"
+ "for.inc:\n"
+ " %inc = add nsw i32 %i.0, 1\n"
+ " br label %for.cond, !llvm.loop !0\n"
+ "for.end:\n"
+ " ret void\n"
+ "}\n"
+ "!0 = distinct !{!0, !1}\n"
+ "!1 = !{!\"llvm.loop.distribute.enable\", i1 true}\n";
+
+ // Parse the module.
+ LLVMContext Context;
+ std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleStr);
+
+ runWithLoopInfo(*M, "foo", [&](Function &F, LoopInfo &LI) {
+ Function::iterator FI = F.begin();
+ // First basic block is entry - skip it.
+ BasicBlock *Header = &*(++FI);
+ assert(Header->getName() == "for.cond");
+ Loop *L = LI.getLoopFor(Header);
+
+ // This loop is not in simplified form.
+ EXPECT_FALSE(L->isLoopSimplifyForm());
+
+ // Analyze the loop metadata id.
+ bool loopIDFoundAndSet = false;
+ // Try to get and set the metadata id for the loop.
+ if (MDNode *D = L->getLoopID()) {
+ L->setLoopID(D);
+ loopIDFoundAndSet = true;
+ }
+
+ // We must have successfully found and set the loop id in the
+ // only latch the loop has.
+ EXPECT_TRUE(loopIDFoundAndSet);
+ });
+}
+
+TEST(LoopInfoTest, PreorderTraversals) {
+ const char *ModuleStr = "define void @f() {\n"
+ "entry:\n"
+ " br label %loop.0\n"
+ "loop.0:\n"
+ " br i1 undef, label %loop.0.0, label %loop.1\n"
+ "loop.0.0:\n"
+ " br i1 undef, label %loop.0.0, label %loop.0.1\n"
+ "loop.0.1:\n"
+ " br i1 undef, label %loop.0.1, label %loop.0.2\n"
+ "loop.0.2:\n"
+ " br i1 undef, label %loop.0.2, label %loop.0\n"
+ "loop.1:\n"
+ " br i1 undef, label %loop.1.0, label %end\n"
+ "loop.1.0:\n"
+ " br i1 undef, label %loop.1.0, label %loop.1.1\n"
+ "loop.1.1:\n"
+ " br i1 undef, label %loop.1.1, label %loop.1.2\n"
+ "loop.1.2:\n"
+ " br i1 undef, label %loop.1.2, label %loop.1\n"
+ "end:\n"
+ " ret void\n"
+ "}\n";
+ // Parse the module.
+ LLVMContext Context;
+ std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleStr);
+ Function &F = *M->begin();
+
+ DominatorTree DT(F);
+ LoopInfo LI;
+ LI.analyze(DT);
+
+ Function::iterator I = F.begin();
+ ASSERT_EQ("entry", I->getName());
+ ++I;
+ Loop &L_0 = *LI.getLoopFor(&*I++);
+ ASSERT_EQ("loop.0", L_0.getHeader()->getName());
+ Loop &L_0_0 = *LI.getLoopFor(&*I++);
+ ASSERT_EQ("loop.0.0", L_0_0.getHeader()->getName());
+ Loop &L_0_1 = *LI.getLoopFor(&*I++);
+ ASSERT_EQ("loop.0.1", L_0_1.getHeader()->getName());
+ Loop &L_0_2 = *LI.getLoopFor(&*I++);
+ ASSERT_EQ("loop.0.2", L_0_2.getHeader()->getName());
+ Loop &L_1 = *LI.getLoopFor(&*I++);
+ ASSERT_EQ("loop.1", L_1.getHeader()->getName());
+ Loop &L_1_0 = *LI.getLoopFor(&*I++);
+ ASSERT_EQ("loop.1.0", L_1_0.getHeader()->getName());
+ Loop &L_1_1 = *LI.getLoopFor(&*I++);
+ ASSERT_EQ("loop.1.1", L_1_1.getHeader()->getName());
+ Loop &L_1_2 = *LI.getLoopFor(&*I++);
+ ASSERT_EQ("loop.1.2", L_1_2.getHeader()->getName());
+
+ auto Preorder = LI.getLoopsInPreorder();
+ ASSERT_EQ(8u, Preorder.size());
+ EXPECT_EQ(&L_0, Preorder[0]);
+ EXPECT_EQ(&L_0_0, Preorder[1]);
+ EXPECT_EQ(&L_0_1, Preorder[2]);
+ EXPECT_EQ(&L_0_2, Preorder[3]);
+ EXPECT_EQ(&L_1, Preorder[4]);
+ EXPECT_EQ(&L_1_0, Preorder[5]);
+ EXPECT_EQ(&L_1_1, Preorder[6]);
+ EXPECT_EQ(&L_1_2, Preorder[7]);
+
+ auto ReverseSiblingPreorder = LI.getLoopsInReverseSiblingPreorder();
+ ASSERT_EQ(8u, ReverseSiblingPreorder.size());
+ EXPECT_EQ(&L_1, ReverseSiblingPreorder[0]);
+ EXPECT_EQ(&L_1_2, ReverseSiblingPreorder[1]);
+ EXPECT_EQ(&L_1_1, ReverseSiblingPreorder[2]);
+ EXPECT_EQ(&L_1_0, ReverseSiblingPreorder[3]);
+ EXPECT_EQ(&L_0, ReverseSiblingPreorder[4]);
+ EXPECT_EQ(&L_0_2, ReverseSiblingPreorder[5]);
+ EXPECT_EQ(&L_0_1, ReverseSiblingPreorder[6]);
+ EXPECT_EQ(&L_0_0, ReverseSiblingPreorder[7]);
+}
diff --git a/unittests/Transforms/Utils/MemorySSA.cpp b/unittests/Analysis/MemorySSA.cpp
index 945fe32c316c2..08b0e830a9b2e 100644
--- a/unittests/Transforms/Utils/MemorySSA.cpp
+++ b/unittests/Analysis/MemorySSA.cpp
@@ -6,9 +6,10 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include "llvm/Transforms/Utils/MemorySSA.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/BasicAliasAnalysis.h"
+#include "llvm/Analysis/MemorySSA.h"
+#include "llvm/Analysis/MemorySSAUpdater.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Dominators.h"
@@ -89,6 +90,7 @@ TEST_F(MemorySSATest, CreateALoad) {
setupAnalyses();
MemorySSA &MSSA = *Analyses->MSSA;
+ MemorySSAUpdater Updater(&MSSA);
// Add the load
B.SetInsertPoint(Merge);
LoadInst *LoadInst = B.CreateLoad(PointerArg);
@@ -98,8 +100,145 @@ TEST_F(MemorySSATest, CreateALoad) {
EXPECT_NE(MP, nullptr);
// Create the load memory acccess
- MemoryUse *LoadAccess = cast<MemoryUse>(
- MSSA.createMemoryAccessInBB(LoadInst, MP, Merge, MemorySSA::Beginning));
+ MemoryUse *LoadAccess = cast<MemoryUse>(Updater.createMemoryAccessInBB(
+ LoadInst, MP, Merge, MemorySSA::Beginning));
+ MemoryAccess *DefiningAccess = LoadAccess->getDefiningAccess();
+ EXPECT_TRUE(isa<MemoryPhi>(DefiningAccess));
+ MSSA.verifyMemorySSA();
+}
+TEST_F(MemorySSATest, CreateLoadsAndStoreUpdater) {
+ // We create a diamond, then build memoryssa with no memory accesses, and
+ // incrementally update it by inserting a store in the, entry, a load in the
+ // merge point, then a store in the branch, another load in the merge point,
+ // and then a store in the entry.
+ F = Function::Create(
+ FunctionType::get(B.getVoidTy(), {B.getInt8PtrTy()}, false),
+ GlobalValue::ExternalLinkage, "F", &M);
+ BasicBlock *Entry(BasicBlock::Create(C, "", F));
+ BasicBlock *Left(BasicBlock::Create(C, "", F));
+ BasicBlock *Right(BasicBlock::Create(C, "", F));
+ BasicBlock *Merge(BasicBlock::Create(C, "", F));
+ B.SetInsertPoint(Entry);
+ B.CreateCondBr(B.getTrue(), Left, Right);
+ B.SetInsertPoint(Left, Left->begin());
+ Argument *PointerArg = &*F->arg_begin();
+ B.SetInsertPoint(Left);
+ B.CreateBr(Merge);
+ B.SetInsertPoint(Right);
+ B.CreateBr(Merge);
+
+ setupAnalyses();
+ MemorySSA &MSSA = *Analyses->MSSA;
+ MemorySSAUpdater Updater(&MSSA);
+ // Add the store
+ B.SetInsertPoint(Entry, Entry->begin());
+ StoreInst *EntryStore = B.CreateStore(B.getInt8(16), PointerArg);
+ MemoryAccess *EntryStoreAccess = Updater.createMemoryAccessInBB(
+ EntryStore, nullptr, Entry, MemorySSA::Beginning);
+ Updater.insertDef(cast<MemoryDef>(EntryStoreAccess));
+
+ // Add the load
+ B.SetInsertPoint(Merge, Merge->begin());
+ LoadInst *FirstLoad = B.CreateLoad(PointerArg);
+
+ // MemoryPHI should not already exist.
+ MemoryPhi *MP = MSSA.getMemoryAccess(Merge);
+ EXPECT_EQ(MP, nullptr);
+
+ // Create the load memory access
+ MemoryUse *FirstLoadAccess = cast<MemoryUse>(Updater.createMemoryAccessInBB(
+ FirstLoad, nullptr, Merge, MemorySSA::Beginning));
+ Updater.insertUse(FirstLoadAccess);
+ // Should just have a load using the entry access, because it should discover
+ // the phi is trivial
+ EXPECT_EQ(FirstLoadAccess->getDefiningAccess(), EntryStoreAccess);
+
+ // Create a store on the left
+ // Add the store
+ B.SetInsertPoint(Left, Left->begin());
+ StoreInst *LeftStore = B.CreateStore(B.getInt8(16), PointerArg);
+ MemoryAccess *LeftStoreAccess = Updater.createMemoryAccessInBB(
+ LeftStore, nullptr, Left, MemorySSA::Beginning);
+ Updater.insertDef(cast<MemoryDef>(LeftStoreAccess), false);
+ // We don't touch existing loads, so we need to create a new one to get a phi
+ // Add the second load
+ B.SetInsertPoint(Merge, Merge->begin());
+ LoadInst *SecondLoad = B.CreateLoad(PointerArg);
+
+ // MemoryPHI should not already exist.
+ MP = MSSA.getMemoryAccess(Merge);
+ EXPECT_EQ(MP, nullptr);
+
+ // Create the load memory access
+ MemoryUse *SecondLoadAccess = cast<MemoryUse>(Updater.createMemoryAccessInBB(
+ SecondLoad, nullptr, Merge, MemorySSA::Beginning));
+ Updater.insertUse(SecondLoadAccess);
+ // Now the load should be a phi of the entry store and the left store
+ MemoryPhi *MergePhi =
+ dyn_cast<MemoryPhi>(SecondLoadAccess->getDefiningAccess());
+ EXPECT_NE(MergePhi, nullptr);
+ EXPECT_EQ(MergePhi->getIncomingValue(0), EntryStoreAccess);
+ EXPECT_EQ(MergePhi->getIncomingValue(1), LeftStoreAccess);
+ // Now create a store below the existing one in the entry
+ B.SetInsertPoint(Entry, --Entry->end());
+ StoreInst *SecondEntryStore = B.CreateStore(B.getInt8(16), PointerArg);
+ MemoryAccess *SecondEntryStoreAccess = Updater.createMemoryAccessInBB(
+ SecondEntryStore, nullptr, Entry, MemorySSA::End);
+ // Insert it twice just to test renaming
+ Updater.insertDef(cast<MemoryDef>(SecondEntryStoreAccess), false);
+ EXPECT_NE(FirstLoadAccess->getDefiningAccess(), MergePhi);
+ Updater.insertDef(cast<MemoryDef>(SecondEntryStoreAccess), true);
+ EXPECT_EQ(FirstLoadAccess->getDefiningAccess(), MergePhi);
+ // and make sure the phi below it got updated, despite being blocks away
+ MergePhi = dyn_cast<MemoryPhi>(SecondLoadAccess->getDefiningAccess());
+ EXPECT_NE(MergePhi, nullptr);
+ EXPECT_EQ(MergePhi->getIncomingValue(0), SecondEntryStoreAccess);
+ EXPECT_EQ(MergePhi->getIncomingValue(1), LeftStoreAccess);
+ MSSA.verifyMemorySSA();
+}
+
+TEST_F(MemorySSATest, CreateALoadUpdater) {
+ // We create a diamond, then build memoryssa with no memory accesses, and
+ // incrementally update it by inserting a store in one of the branches, and a
+ // load in the merge point
+ F = Function::Create(
+ FunctionType::get(B.getVoidTy(), {B.getInt8PtrTy()}, false),
+ GlobalValue::ExternalLinkage, "F", &M);
+ BasicBlock *Entry(BasicBlock::Create(C, "", F));
+ BasicBlock *Left(BasicBlock::Create(C, "", F));
+ BasicBlock *Right(BasicBlock::Create(C, "", F));
+ BasicBlock *Merge(BasicBlock::Create(C, "", F));
+ B.SetInsertPoint(Entry);
+ B.CreateCondBr(B.getTrue(), Left, Right);
+ B.SetInsertPoint(Left, Left->begin());
+ Argument *PointerArg = &*F->arg_begin();
+ B.SetInsertPoint(Left);
+ B.CreateBr(Merge);
+ B.SetInsertPoint(Right);
+ B.CreateBr(Merge);
+
+ setupAnalyses();
+ MemorySSA &MSSA = *Analyses->MSSA;
+ MemorySSAUpdater Updater(&MSSA);
+ B.SetInsertPoint(Left, Left->begin());
+ // Add the store
+ StoreInst *SI = B.CreateStore(B.getInt8(16), PointerArg);
+ MemoryAccess *StoreAccess =
+ Updater.createMemoryAccessInBB(SI, nullptr, Left, MemorySSA::Beginning);
+ Updater.insertDef(cast<MemoryDef>(StoreAccess));
+
+ // Add the load
+ B.SetInsertPoint(Merge, Merge->begin());
+ LoadInst *LoadInst = B.CreateLoad(PointerArg);
+
+ // MemoryPHI should not already exist.
+ MemoryPhi *MP = MSSA.getMemoryAccess(Merge);
+ EXPECT_EQ(MP, nullptr);
+
+ // Create the load memory acccess
+ MemoryUse *LoadAccess = cast<MemoryUse>(Updater.createMemoryAccessInBB(
+ LoadInst, nullptr, Merge, MemorySSA::Beginning));
+ Updater.insertUse(LoadAccess);
MemoryAccess *DefiningAccess = LoadAccess->getDefiningAccess();
EXPECT_TRUE(isa<MemoryPhi>(DefiningAccess));
MSSA.verifyMemorySSA();
@@ -108,7 +247,8 @@ TEST_F(MemorySSATest, CreateALoad) {
TEST_F(MemorySSATest, MoveAStore) {
// We create a diamond where there is a in the entry, a store on one side, and
// a load at the end. After building MemorySSA, we test updating by moving
- // the store from the side block to the entry block.
+ // the store from the side block to the entry block. This destroys the old
+ // access.
F = Function::Create(
FunctionType::get(B.getVoidTy(), {B.getInt8PtrTy()}, false),
GlobalValue::ExternalLinkage, "F", &M);
@@ -128,15 +268,161 @@ TEST_F(MemorySSATest, MoveAStore) {
B.CreateLoad(PointerArg);
setupAnalyses();
MemorySSA &MSSA = *Analyses->MSSA;
-
+ MemorySSAUpdater Updater(&MSSA);
// Move the store
SideStore->moveBefore(Entry->getTerminator());
MemoryAccess *EntryStoreAccess = MSSA.getMemoryAccess(EntryStore);
MemoryAccess *SideStoreAccess = MSSA.getMemoryAccess(SideStore);
- MemoryAccess *NewStoreAccess = MSSA.createMemoryAccessAfter(
+ MemoryAccess *NewStoreAccess = Updater.createMemoryAccessAfter(
SideStore, EntryStoreAccess, EntryStoreAccess);
EntryStoreAccess->replaceAllUsesWith(NewStoreAccess);
- MSSA.removeMemoryAccess(SideStoreAccess);
+ Updater.removeMemoryAccess(SideStoreAccess);
+ MSSA.verifyMemorySSA();
+}
+
+TEST_F(MemorySSATest, MoveAStoreUpdater) {
+ // We create a diamond where there is a in the entry, a store on one side, and
+ // a load at the end. After building MemorySSA, we test updating by moving
+ // the store from the side block to the entry block. This destroys the old
+ // access.
+ F = Function::Create(
+ FunctionType::get(B.getVoidTy(), {B.getInt8PtrTy()}, false),
+ GlobalValue::ExternalLinkage, "F", &M);
+ BasicBlock *Entry(BasicBlock::Create(C, "", F));
+ BasicBlock *Left(BasicBlock::Create(C, "", F));
+ BasicBlock *Right(BasicBlock::Create(C, "", F));
+ BasicBlock *Merge(BasicBlock::Create(C, "", F));
+ B.SetInsertPoint(Entry);
+ Argument *PointerArg = &*F->arg_begin();
+ StoreInst *EntryStore = B.CreateStore(B.getInt8(16), PointerArg);
+ B.CreateCondBr(B.getTrue(), Left, Right);
+ B.SetInsertPoint(Left);
+ auto *SideStore = B.CreateStore(B.getInt8(16), PointerArg);
+ BranchInst::Create(Merge, Left);
+ BranchInst::Create(Merge, Right);
+ B.SetInsertPoint(Merge);
+ auto *MergeLoad = B.CreateLoad(PointerArg);
+ setupAnalyses();
+ MemorySSA &MSSA = *Analyses->MSSA;
+ MemorySSAUpdater Updater(&MSSA);
+
+ // Move the store
+ SideStore->moveBefore(Entry->getTerminator());
+ auto *EntryStoreAccess = MSSA.getMemoryAccess(EntryStore);
+ auto *SideStoreAccess = MSSA.getMemoryAccess(SideStore);
+ auto *NewStoreAccess = Updater.createMemoryAccessAfter(
+ SideStore, EntryStoreAccess, EntryStoreAccess);
+ // Before, the load will point to a phi of the EntryStore and SideStore.
+ auto *LoadAccess = cast<MemoryUse>(MSSA.getMemoryAccess(MergeLoad));
+ EXPECT_TRUE(isa<MemoryPhi>(LoadAccess->getDefiningAccess()));
+ MemoryPhi *MergePhi = cast<MemoryPhi>(LoadAccess->getDefiningAccess());
+ EXPECT_EQ(MergePhi->getIncomingValue(1), EntryStoreAccess);
+ EXPECT_EQ(MergePhi->getIncomingValue(0), SideStoreAccess);
+ Updater.removeMemoryAccess(SideStoreAccess);
+ Updater.insertDef(cast<MemoryDef>(NewStoreAccess));
+ // After it's a phi of the new side store access.
+ EXPECT_EQ(MergePhi->getIncomingValue(0), NewStoreAccess);
+ EXPECT_EQ(MergePhi->getIncomingValue(1), NewStoreAccess);
+ MSSA.verifyMemorySSA();
+}
+
+TEST_F(MemorySSATest, MoveAStoreUpdaterMove) {
+ // We create a diamond where there is a in the entry, a store on one side, and
+ // a load at the end. After building MemorySSA, we test updating by moving
+ // the store from the side block to the entry block. This does not destroy
+ // the old access.
+ F = Function::Create(
+ FunctionType::get(B.getVoidTy(), {B.getInt8PtrTy()}, false),
+ GlobalValue::ExternalLinkage, "F", &M);
+ BasicBlock *Entry(BasicBlock::Create(C, "", F));
+ BasicBlock *Left(BasicBlock::Create(C, "", F));
+ BasicBlock *Right(BasicBlock::Create(C, "", F));
+ BasicBlock *Merge(BasicBlock::Create(C, "", F));
+ B.SetInsertPoint(Entry);
+ Argument *PointerArg = &*F->arg_begin();
+ StoreInst *EntryStore = B.CreateStore(B.getInt8(16), PointerArg);
+ B.CreateCondBr(B.getTrue(), Left, Right);
+ B.SetInsertPoint(Left);
+ auto *SideStore = B.CreateStore(B.getInt8(16), PointerArg);
+ BranchInst::Create(Merge, Left);
+ BranchInst::Create(Merge, Right);
+ B.SetInsertPoint(Merge);
+ auto *MergeLoad = B.CreateLoad(PointerArg);
+ setupAnalyses();
+ MemorySSA &MSSA = *Analyses->MSSA;
+ MemorySSAUpdater Updater(&MSSA);
+
+ // Move the store
+ auto *EntryStoreAccess = MSSA.getMemoryAccess(EntryStore);
+ auto *SideStoreAccess = MSSA.getMemoryAccess(SideStore);
+ // Before, the load will point to a phi of the EntryStore and SideStore.
+ auto *LoadAccess = cast<MemoryUse>(MSSA.getMemoryAccess(MergeLoad));
+ EXPECT_TRUE(isa<MemoryPhi>(LoadAccess->getDefiningAccess()));
+ MemoryPhi *MergePhi = cast<MemoryPhi>(LoadAccess->getDefiningAccess());
+ EXPECT_EQ(MergePhi->getIncomingValue(1), EntryStoreAccess);
+ EXPECT_EQ(MergePhi->getIncomingValue(0), SideStoreAccess);
+ SideStore->moveBefore(*EntryStore->getParent(), ++EntryStore->getIterator());
+ Updater.moveAfter(SideStoreAccess, EntryStoreAccess);
+ // After, it's a phi of the side store.
+ EXPECT_EQ(MergePhi->getIncomingValue(0), SideStoreAccess);
+ EXPECT_EQ(MergePhi->getIncomingValue(1), SideStoreAccess);
+
+ MSSA.verifyMemorySSA();
+}
+
+TEST_F(MemorySSATest, MoveAStoreAllAround) {
+ // We create a diamond where there is a in the entry, a store on one side, and
+ // a load at the end. After building MemorySSA, we test updating by moving
+ // the store from the side block to the entry block, then to the other side
+ // block, then to before the load. This does not destroy the old access.
+ F = Function::Create(
+ FunctionType::get(B.getVoidTy(), {B.getInt8PtrTy()}, false),
+ GlobalValue::ExternalLinkage, "F", &M);
+ BasicBlock *Entry(BasicBlock::Create(C, "", F));
+ BasicBlock *Left(BasicBlock::Create(C, "", F));
+ BasicBlock *Right(BasicBlock::Create(C, "", F));
+ BasicBlock *Merge(BasicBlock::Create(C, "", F));
+ B.SetInsertPoint(Entry);
+ Argument *PointerArg = &*F->arg_begin();
+ StoreInst *EntryStore = B.CreateStore(B.getInt8(16), PointerArg);
+ B.CreateCondBr(B.getTrue(), Left, Right);
+ B.SetInsertPoint(Left);
+ auto *SideStore = B.CreateStore(B.getInt8(16), PointerArg);
+ BranchInst::Create(Merge, Left);
+ BranchInst::Create(Merge, Right);
+ B.SetInsertPoint(Merge);
+ auto *MergeLoad = B.CreateLoad(PointerArg);
+ setupAnalyses();
+ MemorySSA &MSSA = *Analyses->MSSA;
+ MemorySSAUpdater Updater(&MSSA);
+
+ // Move the store
+ auto *EntryStoreAccess = MSSA.getMemoryAccess(EntryStore);
+ auto *SideStoreAccess = MSSA.getMemoryAccess(SideStore);
+ // Before, the load will point to a phi of the EntryStore and SideStore.
+ auto *LoadAccess = cast<MemoryUse>(MSSA.getMemoryAccess(MergeLoad));
+ EXPECT_TRUE(isa<MemoryPhi>(LoadAccess->getDefiningAccess()));
+ MemoryPhi *MergePhi = cast<MemoryPhi>(LoadAccess->getDefiningAccess());
+ EXPECT_EQ(MergePhi->getIncomingValue(1), EntryStoreAccess);
+ EXPECT_EQ(MergePhi->getIncomingValue(0), SideStoreAccess);
+ // Move the store before the entry store
+ SideStore->moveBefore(*EntryStore->getParent(), EntryStore->getIterator());
+ Updater.moveBefore(SideStoreAccess, EntryStoreAccess);
+ // After, it's a phi of the entry store.
+ EXPECT_EQ(MergePhi->getIncomingValue(0), EntryStoreAccess);
+ EXPECT_EQ(MergePhi->getIncomingValue(1), EntryStoreAccess);
+ MSSA.verifyMemorySSA();
+ // Now move the store to the right branch
+ SideStore->moveBefore(*Right, Right->begin());
+ Updater.moveToPlace(SideStoreAccess, Right, MemorySSA::Beginning);
+ MSSA.verifyMemorySSA();
+ EXPECT_EQ(MergePhi->getIncomingValue(0), EntryStoreAccess);
+ EXPECT_EQ(MergePhi->getIncomingValue(1), SideStoreAccess);
+ // Now move it before the load
+ SideStore->moveBefore(MergeLoad);
+ Updater.moveBefore(SideStoreAccess, LoadAccess);
+ EXPECT_EQ(MergePhi->getIncomingValue(0), EntryStoreAccess);
+ EXPECT_EQ(MergePhi->getIncomingValue(1), EntryStoreAccess);
MSSA.verifyMemorySSA();
}
@@ -163,13 +449,15 @@ TEST_F(MemorySSATest, RemoveAPhi) {
setupAnalyses();
MemorySSA &MSSA = *Analyses->MSSA;
+ MemorySSAUpdater Updater(&MSSA);
+
// Before, the load will be a use of a phi<store, liveonentry>.
MemoryUse *LoadAccess = cast<MemoryUse>(MSSA.getMemoryAccess(LoadInst));
MemoryDef *StoreAccess = cast<MemoryDef>(MSSA.getMemoryAccess(StoreInst));
MemoryAccess *DefiningAccess = LoadAccess->getDefiningAccess();
EXPECT_TRUE(isa<MemoryPhi>(DefiningAccess));
// Kill the store
- MSSA.removeMemoryAccess(StoreAccess);
+ Updater.removeMemoryAccess(StoreAccess);
MemoryPhi *MP = cast<MemoryPhi>(DefiningAccess);
// Verify the phi ended up as liveonentry, liveonentry
for (auto &Op : MP->incoming_values())
@@ -179,7 +467,7 @@ TEST_F(MemorySSATest, RemoveAPhi) {
// Verify the load is now defined by liveOnEntryDef
EXPECT_TRUE(MSSA.isLiveOnEntryDef(LoadAccess->getDefiningAccess()));
// Remove the PHI
- MSSA.removeMemoryAccess(MP);
+ Updater.removeMemoryAccess(MP);
MSSA.verifyMemorySSA();
}
@@ -207,6 +495,7 @@ TEST_F(MemorySSATest, RemoveMemoryAccess) {
setupAnalyses();
MemorySSA &MSSA = *Analyses->MSSA;
MemorySSAWalker *Walker = Analyses->Walker;
+ MemorySSAUpdater Updater(&MSSA);
// Before, the load will be a use of a phi<store, liveonentry>. It should be
// the same after.
@@ -217,7 +506,7 @@ TEST_F(MemorySSATest, RemoveMemoryAccess) {
// The load is currently clobbered by one of the phi arguments, so the walker
// should determine the clobbering access as the phi.
EXPECT_EQ(DefiningAccess, Walker->getClobberingMemoryAccess(LoadInst));
- MSSA.removeMemoryAccess(StoreAccess);
+ Updater.removeMemoryAccess(StoreAccess);
MSSA.verifyMemorySSA();
// After the removeaccess, let's see if we got the right accesses
// The load should still point to the phi ...
@@ -241,7 +530,7 @@ TEST_F(MemorySSATest, RemoveMemoryAccess) {
}
// Now we try to remove the single valued phi
- MSSA.removeMemoryAccess(DefiningAccess);
+ Updater.removeMemoryAccess(DefiningAccess);
MSSA.verifyMemorySSA();
// Now the load should be a load of live on entry.
EXPECT_TRUE(MSSA.isLiveOnEntryDef(LoadAccess->getDefiningAccess()));
@@ -395,10 +684,11 @@ TEST_F(MemorySSATest, PartialWalkerCacheWithPhis) {
setupAnalyses();
MemorySSA &MSSA = *Analyses->MSSA;
MemorySSAWalker *Walker = Analyses->Walker;
+ MemorySSAUpdater Updater(&MSSA);
// Kill `KillStore`; it exists solely so that the load after it won't be
// optimized to FirstStore.
- MSSA.removeMemoryAccess(MSSA.getMemoryAccess(KillStore));
+ Updater.removeMemoryAccess(MSSA.getMemoryAccess(KillStore));
KillStore->eraseFromParent();
auto *ALoadMA = cast<MemoryUse>(MSSA.getMemoryAccess(ALoad));
EXPECT_EQ(ALoadMA->getDefiningAccess(), MSSA.getMemoryAccess(BStore));
@@ -470,23 +760,24 @@ TEST_F(MemorySSATest, WalkerReopt) {
setupAnalyses();
MemorySSA &MSSA = *Analyses->MSSA;
MemorySSAWalker *Walker = Analyses->Walker;
+ MemorySSAUpdater Updater(&MSSA);
MemoryAccess *LoadClobber = Walker->getClobberingMemoryAccess(LIA);
MemoryUse *LoadAccess = cast<MemoryUse>(MSSA.getMemoryAccess(LIA));
EXPECT_EQ(LoadClobber, MSSA.getMemoryAccess(SIA));
EXPECT_TRUE(MSSA.isLiveOnEntryDef(Walker->getClobberingMemoryAccess(SIA)));
- MSSA.removeMemoryAccess(LoadAccess);
+ Updater.removeMemoryAccess(LoadAccess);
// Create the load memory access pointing to an unoptimized place.
- MemoryUse *NewLoadAccess = cast<MemoryUse>(MSSA.createMemoryAccessInBB(
+ MemoryUse *NewLoadAccess = cast<MemoryUse>(Updater.createMemoryAccessInBB(
LIA, MSSA.getMemoryAccess(SIB), LIA->getParent(), MemorySSA::End));
// This should it cause it to be optimized
EXPECT_EQ(Walker->getClobberingMemoryAccess(NewLoadAccess), LoadClobber);
EXPECT_EQ(NewLoadAccess->getDefiningAccess(), LoadClobber);
}
-// Test out MemorySSA::spliceMemoryAccessAbove.
-TEST_F(MemorySSATest, SpliceAboveMemoryDef) {
+// Test out MemorySSAUpdater::moveBefore
+TEST_F(MemorySSATest, MoveAboveMemoryDef) {
F = Function::Create(FunctionType::get(B.getVoidTy(), {}, false),
GlobalValue::ExternalLinkage, "F", &M);
B.SetInsertPoint(BasicBlock::Create(C, "", F));
@@ -500,7 +791,6 @@ TEST_F(MemorySSATest, SpliceAboveMemoryDef) {
StoreInst *StoreB = B.CreateStore(ConstantInt::get(Int8, 0), B_);
LoadInst *LoadB = B.CreateLoad(B_);
StoreInst *StoreA1 = B.CreateStore(ConstantInt::get(Int8, 4), A);
- // splice this above StoreB
StoreInst *StoreC = B.CreateStore(ConstantInt::get(Int8, 4), C);
StoreInst *StoreA2 = B.CreateStore(ConstantInt::get(Int8, 4), A);
LoadInst *LoadC = B.CreateLoad(C);
@@ -509,9 +799,10 @@ TEST_F(MemorySSATest, SpliceAboveMemoryDef) {
MemorySSA &MSSA = *Analyses->MSSA;
MemorySSAWalker &Walker = *Analyses->Walker;
+ MemorySSAUpdater Updater(&MSSA);
StoreC->moveBefore(StoreB);
- MSSA.spliceMemoryAccessAbove(cast<MemoryDef>(MSSA.getMemoryAccess(StoreB)),
- MSSA.getMemoryAccess(StoreC));
+ Updater.moveBefore(cast<MemoryDef>(MSSA.getMemoryAccess(StoreC)),
+ cast<MemoryDef>(MSSA.getMemoryAccess(StoreB)));
MSSA.verifyMemorySSA();
@@ -532,3 +823,43 @@ TEST_F(MemorySSATest, SpliceAboveMemoryDef) {
EXPECT_TRUE(MSSA.locallyDominates(MSSA.getMemoryAccess(StoreA1),
MSSA.getMemoryAccess(StoreA2)));
}
+
+TEST_F(MemorySSATest, Irreducible) {
+ // Create the equivalent of
+ // x = something
+ // if (...)
+ // goto second_loop_entry
+ // while (...) {
+ // second_loop_entry:
+ // }
+ // use(x)
+
+ SmallVector<PHINode *, 8> Inserted;
+ IRBuilder<> B(C);
+ F = Function::Create(
+ FunctionType::get(B.getVoidTy(), {B.getInt8PtrTy()}, false),
+ GlobalValue::ExternalLinkage, "F", &M);
+
+ // Make blocks
+ BasicBlock *IfBB = BasicBlock::Create(C, "if", F);
+ BasicBlock *LoopStartBB = BasicBlock::Create(C, "loopstart", F);
+ BasicBlock *LoopMainBB = BasicBlock::Create(C, "loopmain", F);
+ BasicBlock *AfterLoopBB = BasicBlock::Create(C, "afterloop", F);
+ B.SetInsertPoint(IfBB);
+ B.CreateCondBr(B.getTrue(), LoopMainBB, LoopStartBB);
+ B.SetInsertPoint(LoopStartBB);
+ B.CreateBr(LoopMainBB);
+ B.SetInsertPoint(LoopMainBB);
+ B.CreateCondBr(B.getTrue(), LoopStartBB, AfterLoopBB);
+ B.SetInsertPoint(AfterLoopBB);
+ Argument *FirstArg = &*F->arg_begin();
+ setupAnalyses();
+ MemorySSA &MSSA = *Analyses->MSSA;
+ MemorySSAUpdater Updater(&MSSA);
+ // Create the load memory acccess
+ LoadInst *LoadInst = B.CreateLoad(FirstArg);
+ MemoryUse *LoadAccess = cast<MemoryUse>(Updater.createMemoryAccessInBB(
+ LoadInst, nullptr, AfterLoopBB, MemorySSA::Beginning));
+ Updater.insertUse(LoadAccess);
+ MSSA.verifyMemorySSA();
+}
diff --git a/unittests/Analysis/ProfileSummaryInfoTest.cpp b/unittests/Analysis/ProfileSummaryInfoTest.cpp
new file mode 100644
index 0000000000000..0b4b1de28053b
--- /dev/null
+++ b/unittests/Analysis/ProfileSummaryInfoTest.cpp
@@ -0,0 +1,198 @@
+//===- ProfileSummaryInfoTest.cpp - ProfileSummaryInfo unit tests ---------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Analysis/BlockFrequencyInfo.h"
+#include "llvm/Analysis/BlockFrequencyInfoImpl.h"
+#include "llvm/Analysis/BranchProbabilityInfo.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Analysis/ProfileSummaryInfo.h"
+#include "llvm/AsmParser/Parser.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/CallSite.h"
+#include "llvm/IR/Dominators.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/MDBuilder.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/raw_ostream.h"
+#include "gtest/gtest.h"
+
+namespace llvm {
+namespace {
+
+class ProfileSummaryInfoTest : public testing::Test {
+protected:
+ LLVMContext C;
+ std::unique_ptr<BranchProbabilityInfo> BPI;
+ std::unique_ptr<DominatorTree> DT;
+ std::unique_ptr<LoopInfo> LI;
+
+ ProfileSummaryInfo buildPSI(Module *M) {
+ return ProfileSummaryInfo(*M);
+ }
+ BlockFrequencyInfo buildBFI(Function &F) {
+ DT.reset(new DominatorTree(F));
+ LI.reset(new LoopInfo(*DT));
+ BPI.reset(new BranchProbabilityInfo(F, *LI));
+ return BlockFrequencyInfo(F, *BPI, *LI);
+ }
+ std::unique_ptr<Module> makeLLVMModule(const char *ProfKind = nullptr) {
+ const char *ModuleString =
+ "define i32 @g(i32 %x) !prof !21 {{\n"
+ " ret i32 0\n"
+ "}\n"
+ "define i32 @h(i32 %x) !prof !22 {{\n"
+ " ret i32 0\n"
+ "}\n"
+ "define i32 @f(i32 %x) !prof !20 {{\n"
+ "bb0:\n"
+ " %y1 = icmp eq i32 %x, 0 \n"
+ " br i1 %y1, label %bb1, label %bb2, !prof !23 \n"
+ "bb1:\n"
+ " %z1 = call i32 @g(i32 %x)\n"
+ " br label %bb3\n"
+ "bb2:\n"
+ " %z2 = call i32 @h(i32 %x)\n"
+ " br label %bb3\n"
+ "bb3:\n"
+ " %y2 = phi i32 [0, %bb1], [1, %bb2] \n"
+ " ret i32 %y2\n"
+ "}\n"
+ "!20 = !{{!\"function_entry_count\", i64 400}\n"
+ "!21 = !{{!\"function_entry_count\", i64 1}\n"
+ "!22 = !{{!\"function_entry_count\", i64 100}\n"
+ "!23 = !{{!\"branch_weights\", i32 64, i32 4}\n"
+ "{0}";
+ const char *SummaryString = "!llvm.module.flags = !{{!1}"
+ "!1 = !{{i32 1, !\"ProfileSummary\", !2}"
+ "!2 = !{{!3, !4, !5, !6, !7, !8, !9, !10}"
+ "!3 = !{{!\"ProfileFormat\", !\"{0}\"}"
+ "!4 = !{{!\"TotalCount\", i64 10000}"
+ "!5 = !{{!\"MaxCount\", i64 10}"
+ "!6 = !{{!\"MaxInternalCount\", i64 1}"
+ "!7 = !{{!\"MaxFunctionCount\", i64 1000}"
+ "!8 = !{{!\"NumCounts\", i64 3}"
+ "!9 = !{{!\"NumFunctions\", i64 3}"
+ "!10 = !{{!\"DetailedSummary\", !11}"
+ "!11 = !{{!12, !13, !14}"
+ "!12 = !{{i32 10000, i64 1000, i32 1}"
+ "!13 = !{{i32 999000, i64 300, i32 3}"
+ "!14 = !{{i32 999999, i64 5, i32 10}";
+ SMDiagnostic Err;
+ if (ProfKind)
+ return parseAssemblyString(
+ formatv(ModuleString, formatv(SummaryString, ProfKind).str()).str(),
+ Err, C);
+ else
+ return parseAssemblyString(formatv(ModuleString, "").str(), Err, C);
+ }
+};
+
+TEST_F(ProfileSummaryInfoTest, TestNoProfile) {
+ auto M = makeLLVMModule(/*ProfKind=*/nullptr);
+ Function *F = M->getFunction("f");
+
+ ProfileSummaryInfo PSI = buildPSI(M.get());
+ // In the absence of profiles, is{Hot|Cold}X methods should always return
+ // false.
+ EXPECT_FALSE(PSI.isHotCount(1000));
+ EXPECT_FALSE(PSI.isHotCount(0));
+ EXPECT_FALSE(PSI.isColdCount(1000));
+ EXPECT_FALSE(PSI.isColdCount(0));
+
+ EXPECT_FALSE(PSI.isFunctionEntryHot(F));
+ EXPECT_FALSE(PSI.isFunctionEntryCold(F));
+
+ BasicBlock &BB0 = F->getEntryBlock();
+ BasicBlock *BB1 = BB0.getTerminator()->getSuccessor(0);
+
+ BlockFrequencyInfo BFI = buildBFI(*F);
+ EXPECT_FALSE(PSI.isHotBB(&BB0, &BFI));
+ EXPECT_FALSE(PSI.isColdBB(&BB0, &BFI));
+
+ CallSite CS1(BB1->getFirstNonPHI());
+ EXPECT_FALSE(PSI.isHotCallSite(CS1, &BFI));
+ EXPECT_FALSE(PSI.isColdCallSite(CS1, &BFI));
+}
+TEST_F(ProfileSummaryInfoTest, TestCommon) {
+ auto M = makeLLVMModule("InstrProf");
+ Function *F = M->getFunction("f");
+ Function *G = M->getFunction("g");
+ Function *H = M->getFunction("h");
+
+ ProfileSummaryInfo PSI = buildPSI(M.get());
+ EXPECT_TRUE(PSI.isHotCount(400));
+ EXPECT_TRUE(PSI.isColdCount(2));
+ EXPECT_FALSE(PSI.isColdCount(100));
+ EXPECT_FALSE(PSI.isHotCount(100));
+
+ EXPECT_TRUE(PSI.isFunctionEntryHot(F));
+ EXPECT_FALSE(PSI.isFunctionEntryHot(G));
+ EXPECT_FALSE(PSI.isFunctionEntryHot(H));
+}
+
+TEST_F(ProfileSummaryInfoTest, InstrProf) {
+ auto M = makeLLVMModule("InstrProf");
+ Function *F = M->getFunction("f");
+ ProfileSummaryInfo PSI = buildPSI(M.get());
+
+ BasicBlock &BB0 = F->getEntryBlock();
+ BasicBlock *BB1 = BB0.getTerminator()->getSuccessor(0);
+ BasicBlock *BB2 = BB0.getTerminator()->getSuccessor(1);
+ BasicBlock *BB3 = BB1->getSingleSuccessor();
+
+ BlockFrequencyInfo BFI = buildBFI(*F);
+ EXPECT_TRUE(PSI.isHotBB(&BB0, &BFI));
+ EXPECT_TRUE(PSI.isHotBB(BB1, &BFI));
+ EXPECT_FALSE(PSI.isHotBB(BB2, &BFI));
+ EXPECT_TRUE(PSI.isHotBB(BB3, &BFI));
+
+ CallSite CS1(BB1->getFirstNonPHI());
+ auto *CI2 = BB2->getFirstNonPHI();
+ CallSite CS2(CI2);
+
+ EXPECT_TRUE(PSI.isHotCallSite(CS1, &BFI));
+ EXPECT_FALSE(PSI.isHotCallSite(CS2, &BFI));
+}
+
+TEST_F(ProfileSummaryInfoTest, SampleProf) {
+ auto M = makeLLVMModule("SampleProfile");
+ Function *F = M->getFunction("f");
+ ProfileSummaryInfo PSI = buildPSI(M.get());
+
+ BasicBlock &BB0 = F->getEntryBlock();
+ BasicBlock *BB1 = BB0.getTerminator()->getSuccessor(0);
+ BasicBlock *BB2 = BB0.getTerminator()->getSuccessor(1);
+ BasicBlock *BB3 = BB1->getSingleSuccessor();
+
+ BlockFrequencyInfo BFI = buildBFI(*F);
+ EXPECT_TRUE(PSI.isHotBB(&BB0, &BFI));
+ EXPECT_TRUE(PSI.isHotBB(BB1, &BFI));
+ EXPECT_FALSE(PSI.isHotBB(BB2, &BFI));
+ EXPECT_TRUE(PSI.isHotBB(BB3, &BFI));
+
+ CallSite CS1(BB1->getFirstNonPHI());
+ auto *CI2 = BB2->getFirstNonPHI();
+ CallSite CS2(CI2);
+
+ EXPECT_TRUE(PSI.isHotCallSite(CS1, &BFI));
+ EXPECT_FALSE(PSI.isHotCallSite(CS2, &BFI));
+
+ // Test that CS2 is considered hot when it gets an MD_prof metadata with
+ // weights that exceed the hot count threshold.
+ MDBuilder MDB(M->getContext());
+ CI2->setMetadata(llvm::LLVMContext::MD_prof, MDB.createBranchWeights({400}));
+ EXPECT_TRUE(PSI.isHotCallSite(CS2, &BFI));
+}
+
+} // end anonymous namespace
+} // end namespace llvm
diff --git a/unittests/Analysis/ScalarEvolutionTest.cpp b/unittests/Analysis/ScalarEvolutionTest.cpp
index f4370842edb5e..df9fd4b5ec330 100644
--- a/unittests/Analysis/ScalarEvolutionTest.cpp
+++ b/unittests/Analysis/ScalarEvolutionTest.cpp
@@ -51,13 +51,13 @@ protected:
return ScalarEvolution(F, TLI, *AC, *DT, *LI);
}
- void runWithFunctionAndSE(
+ void runWithSE(
Module &M, StringRef FuncName,
- function_ref<void(Function &F, ScalarEvolution &SE)> Test) {
+ function_ref<void(Function &F, LoopInfo &LI, ScalarEvolution &SE)> Test) {
auto *F = M.getFunction(FuncName);
ASSERT_NE(F, nullptr) << "Could not find " << FuncName;
ScalarEvolution SE = buildSE(*F);
- Test(*F, SE);
+ Test(*F, *LI, SE);
}
};
@@ -306,9 +306,11 @@ TEST_F(ScalarEvolutionsTest, ExpandPtrTypeSCEV) {
// %bitcast2 = bitcast i8* %select to i32*
// br i1 undef, label %loop, label %exit
+ const DataLayout &DL = F->getParent()->getDataLayout();
BranchInst *Br = BranchInst::Create(
LoopBB, ExitBB, UndefValue::get(Type::getInt1Ty(Context)), LoopBB);
- AllocaInst *Alloca = new AllocaInst(I32Ty, "alloca", Br);
+ AllocaInst *Alloca = new AllocaInst(I32Ty, DL.getAllocaAddrSpace(),
+ "alloca", Br);
ConstantInt *Ci32 = ConstantInt::get(Context, APInt(32, 1));
GetElementPtrInst *Gep0 =
GetElementPtrInst::Create(I32Ty, Alloca, Ci32, "gep0", Br);
@@ -417,7 +419,7 @@ TEST_F(ScalarEvolutionsTest, CommutativeExprOperandOrder) {
assert(M && "Could not parse module?");
assert(!verifyModule(*M) && "Must have been well formed!");
- runWithFunctionAndSE(*M, "f_1", [&](Function &F, ScalarEvolution &SE) {
+ runWithSE(*M, "f_1", [&](Function &F, LoopInfo &LI, ScalarEvolution &SE) {
auto *IV0 = getInstructionByName(F, "iv0");
auto *IV0Inc = getInstructionByName(F, "iv0.inc");
@@ -458,11 +460,12 @@ TEST_F(ScalarEvolutionsTest, CommutativeExprOperandOrder) {
};
for (StringRef FuncName : {"f_2", "f_3", "f_4"})
- runWithFunctionAndSE(*M, FuncName, [&](Function &F, ScalarEvolution &SE) {
- CheckCommutativeMulExprs(SE, SE.getSCEV(getInstructionByName(F, "x")),
- SE.getSCEV(getInstructionByName(F, "y")),
- SE.getSCEV(getInstructionByName(F, "z")));
- });
+ runWithSE(
+ *M, FuncName, [&](Function &F, LoopInfo &LI, ScalarEvolution &SE) {
+ CheckCommutativeMulExprs(SE, SE.getSCEV(getInstructionByName(F, "x")),
+ SE.getSCEV(getInstructionByName(F, "y")),
+ SE.getSCEV(getInstructionByName(F, "z")));
+ });
}
TEST_F(ScalarEvolutionsTest, CompareSCEVComplexity) {
@@ -568,5 +571,100 @@ TEST_F(ScalarEvolutionsTest, CompareValueComplexity) {
EXPECT_NE(A, B);
}
+TEST_F(ScalarEvolutionsTest, SCEVAddExpr) {
+ Type *Ty32 = Type::getInt32Ty(Context);
+ Type *ArgTys[] = {Type::getInt64Ty(Context), Ty32};
+
+ FunctionType *FTy =
+ FunctionType::get(Type::getVoidTy(Context), ArgTys, false);
+ Function *F = cast<Function>(M.getOrInsertFunction("f", FTy));
+
+ Argument *A1 = &*F->arg_begin();
+ Argument *A2 = &*(std::next(F->arg_begin()));
+ BasicBlock *EntryBB = BasicBlock::Create(Context, "entry", F);
+
+ Instruction *Trunc = CastInst::CreateTruncOrBitCast(A1, Ty32, "", EntryBB);
+ Instruction *Mul1 = BinaryOperator::CreateMul(Trunc, A2, "", EntryBB);
+ Instruction *Add1 = BinaryOperator::CreateAdd(Mul1, Trunc, "", EntryBB);
+ Mul1 = BinaryOperator::CreateMul(Add1, Trunc, "", EntryBB);
+ Instruction *Add2 = BinaryOperator::CreateAdd(Mul1, Add1, "", EntryBB);
+ // FIXME: The size of this is arbitrary and doesn't seem to change the
+ // result, but SCEV will do quadratic work for these so a large number here
+ // will be extremely slow. We should revisit what and how this is testing
+ // SCEV.
+ for (int i = 0; i < 10; i++) {
+ Mul1 = BinaryOperator::CreateMul(Add2, Add1, "", EntryBB);
+ Add1 = Add2;
+ Add2 = BinaryOperator::CreateAdd(Mul1, Add1, "", EntryBB);
+ }
+
+ ReturnInst::Create(Context, nullptr, EntryBB);
+ ScalarEvolution SE = buildSE(*F);
+ EXPECT_NE(nullptr, SE.getSCEV(Mul1));
+}
+
+static Instruction &GetInstByName(Function &F, StringRef Name) {
+ for (auto &I : instructions(F))
+ if (I.getName() == Name)
+ return I;
+ llvm_unreachable("Could not find instructions!");
+}
+
+TEST_F(ScalarEvolutionsTest, SCEVNormalization) {
+ LLVMContext C;
+ SMDiagnostic Err;
+ std::unique_ptr<Module> M = parseAssemblyString(
+ "target datalayout = \"e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128\" "
+ " "
+ "@var_0 = external global i32, align 4"
+ "@var_1 = external global i32, align 4"
+ "@var_2 = external global i32, align 4"
+ " "
+ "declare i32 @unknown(i32, i32, i32)"
+ " "
+ "define void @f_1(i8* nocapture %arr, i32 %n, i32* %A, i32* %B) "
+ " local_unnamed_addr { "
+ "entry: "
+ " br label %loop.ph "
+ " "
+ "loop.ph: "
+ " br label %loop "
+ " "
+ "loop: "
+ " %iv0 = phi i32 [ %iv0.inc, %loop ], [ 0, %loop.ph ] "
+ " %iv1 = phi i32 [ %iv1.inc, %loop ], [ -2147483648, %loop.ph ] "
+ " %iv0.inc = add i32 %iv0, 1 "
+ " %iv1.inc = add i32 %iv1, 3 "
+ " br i1 undef, label %for.end.loopexit, label %loop "
+ " "
+ "for.end.loopexit: "
+ " ret void "
+ "} "
+ ,
+ Err, C);
+
+ assert(M && "Could not parse module?");
+ assert(!verifyModule(*M) && "Must have been well formed!");
+
+ runWithSE(*M, "f_1", [&](Function &F, LoopInfo &LI, ScalarEvolution &SE) {
+ auto &I0 = GetInstByName(F, "iv0");
+ auto &I1 = *I0.getNextNode();
+
+ auto *S0 = cast<SCEVAddRecExpr>(SE.getSCEV(&I0));
+ PostIncLoopSet Loops;
+ Loops.insert(S0->getLoop());
+ auto *N0 = normalizeForPostIncUse(S0, Loops, SE);
+ auto *D0 = denormalizeForPostIncUse(N0, Loops, SE);
+ EXPECT_EQ(S0, D0) << *S0 << " " << *D0;
+
+ auto *S1 = cast<SCEVAddRecExpr>(SE.getSCEV(&I1));
+ Loops.clear();
+ Loops.insert(S1->getLoop());
+ auto *N1 = normalizeForPostIncUse(S1, Loops, SE);
+ auto *D1 = denormalizeForPostIncUse(N1, Loops, SE);
+ EXPECT_EQ(S1, D1) << *S1 << " " << *D1;
+ });
+}
+
} // end anonymous namespace
} // end namespace llvm
diff --git a/unittests/Analysis/TargetLibraryInfoTest.cpp b/unittests/Analysis/TargetLibraryInfoTest.cpp
new file mode 100644
index 0000000000000..598429c968aa9
--- /dev/null
+++ b/unittests/Analysis/TargetLibraryInfoTest.cpp
@@ -0,0 +1,481 @@
+//===--- TargetLibraryInfoTest.cpp - TLI/LibFunc unit tests ---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Analysis/TargetLibraryInfo.h"
+#include "llvm/AsmParser/Parser.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/LegacyPassManager.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/SourceMgr.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+
+class TargetLibraryInfoTest : public testing::Test {
+protected:
+ LLVMContext Context;
+ TargetLibraryInfoImpl TLII;
+ TargetLibraryInfo TLI;
+
+ std::unique_ptr<Module> M;
+
+ TargetLibraryInfoTest() : TLI(TLII) {}
+
+ void parseAssembly(const char *Assembly) {
+ SMDiagnostic Error;
+ M = parseAssemblyString(Assembly, Error, Context);
+
+ std::string errMsg;
+ raw_string_ostream os(errMsg);
+ Error.print("", os);
+
+ if (!M)
+ report_fatal_error(os.str());
+ }
+
+ ::testing::AssertionResult isLibFunc(const Function *FDecl,
+ LibFunc ExpectedLF) {
+ StringRef ExpectedLFName = TLI.getName(ExpectedLF);
+
+ if (!FDecl)
+ return ::testing::AssertionFailure() << ExpectedLFName << " not found";
+
+ LibFunc F;
+ if (!TLI.getLibFunc(*FDecl, F))
+ return ::testing::AssertionFailure() << ExpectedLFName << " invalid";
+
+ return ::testing::AssertionSuccess() << ExpectedLFName << " is LibFunc";
+ }
+};
+
+} // end anonymous namespace
+
+// Check that we don't accept egregiously incorrect prototypes.
+TEST_F(TargetLibraryInfoTest, InvalidProto) {
+ parseAssembly("%foo = type { %foo }\n");
+
+ auto *StructTy = M->getTypeByName("foo");
+ auto *InvalidFTy = FunctionType::get(StructTy, /*isVarArg=*/false);
+
+ for (unsigned FI = 0; FI != LibFunc::NumLibFuncs; ++FI) {
+ LibFunc LF = (LibFunc)FI;
+ auto *F = cast<Function>(
+ M->getOrInsertFunction(TLI.getName(LF), InvalidFTy));
+ EXPECT_FALSE(isLibFunc(F, LF));
+ }
+}
+
+// Check that we do accept know-correct prototypes.
+TEST_F(TargetLibraryInfoTest, ValidProto) {
+ parseAssembly(
+ // These functions use a 64-bit size_t; use the appropriate datalayout.
+ "target datalayout = \"p:64:64:64\"\n"
+
+ // Struct pointers are replaced with an opaque pointer.
+ "%struct = type opaque\n"
+
+ // These functions were extracted as-is from the OS X headers.
+ "declare double @__cospi(double)\n"
+ "declare float @__cospif(float)\n"
+ "declare { double, double } @__sincospi_stret(double)\n"
+ "declare <2 x float> @__sincospif_stret(float)\n"
+ "declare double @__sinpi(double)\n"
+ "declare float @__sinpif(float)\n"
+ "declare i32 @abs(i32)\n"
+ "declare i32 @access(i8*, i32)\n"
+ "declare double @acos(double)\n"
+ "declare float @acosf(float)\n"
+ "declare double @acosh(double)\n"
+ "declare float @acoshf(float)\n"
+ "declare x86_fp80 @acoshl(x86_fp80)\n"
+ "declare x86_fp80 @acosl(x86_fp80)\n"
+ "declare double @asin(double)\n"
+ "declare float @asinf(float)\n"
+ "declare double @asinh(double)\n"
+ "declare float @asinhf(float)\n"
+ "declare x86_fp80 @asinhl(x86_fp80)\n"
+ "declare x86_fp80 @asinl(x86_fp80)\n"
+ "declare double @atan(double)\n"
+ "declare double @atan2(double, double)\n"
+ "declare float @atan2f(float, float)\n"
+ "declare x86_fp80 @atan2l(x86_fp80, x86_fp80)\n"
+ "declare float @atanf(float)\n"
+ "declare double @atanh(double)\n"
+ "declare float @atanhf(float)\n"
+ "declare x86_fp80 @atanhl(x86_fp80)\n"
+ "declare x86_fp80 @atanl(x86_fp80)\n"
+ "declare double @atof(i8*)\n"
+ "declare i32 @atoi(i8*)\n"
+ "declare i64 @atol(i8*)\n"
+ "declare i64 @atoll(i8*)\n"
+ "declare i32 @bcmp(i8*, i8*, i64)\n"
+ "declare void @bcopy(i8*, i8*, i64)\n"
+ "declare void @bzero(i8*, i64)\n"
+ "declare i8* @calloc(i64, i64)\n"
+ "declare double @cbrt(double)\n"
+ "declare float @cbrtf(float)\n"
+ "declare x86_fp80 @cbrtl(x86_fp80)\n"
+ "declare double @ceil(double)\n"
+ "declare float @ceilf(float)\n"
+ "declare x86_fp80 @ceill(x86_fp80)\n"
+ "declare i32 @chown(i8*, i32, i32)\n"
+ "declare void @clearerr(%struct*)\n"
+ "declare double @copysign(double, double)\n"
+ "declare float @copysignf(float, float)\n"
+ "declare x86_fp80 @copysignl(x86_fp80, x86_fp80)\n"
+ "declare double @cos(double)\n"
+ "declare float @cosf(float)\n"
+ "declare double @cosh(double)\n"
+ "declare float @coshf(float)\n"
+ "declare x86_fp80 @coshl(x86_fp80)\n"
+ "declare x86_fp80 @cosl(x86_fp80)\n"
+ "declare i8* @ctermid(i8*)\n"
+ "declare double @exp(double)\n"
+ "declare double @exp2(double)\n"
+ "declare float @exp2f(float)\n"
+ "declare x86_fp80 @exp2l(x86_fp80)\n"
+ "declare float @expf(float)\n"
+ "declare x86_fp80 @expl(x86_fp80)\n"
+ "declare double @expm1(double)\n"
+ "declare float @expm1f(float)\n"
+ "declare x86_fp80 @expm1l(x86_fp80)\n"
+ "declare double @fabs(double)\n"
+ "declare float @fabsf(float)\n"
+ "declare x86_fp80 @fabsl(x86_fp80)\n"
+ "declare i32 @fclose(%struct*)\n"
+ "declare i32 @feof(%struct*)\n"
+ "declare i32 @ferror(%struct*)\n"
+ "declare i32 @fflush(%struct*)\n"
+ "declare i32 @ffs(i32)\n"
+ "declare i32 @ffsl(i64)\n"
+ "declare i32 @ffsll(i64)\n"
+ "declare i32 @fgetc(%struct*)\n"
+ "declare i32 @fgetpos(%struct*, i64*)\n"
+ "declare i8* @fgets(i8*, i32, %struct*)\n"
+ "declare i32 @fileno(%struct*)\n"
+ "declare void @flockfile(%struct*)\n"
+ "declare double @floor(double)\n"
+ "declare float @floorf(float)\n"
+ "declare x86_fp80 @floorl(x86_fp80)\n"
+ "declare i32 @fls(i32)\n"
+ "declare i32 @flsl(i64)\n"
+ "declare i32 @flsll(i64)\n"
+ "declare double @fmax(double, double)\n"
+ "declare float @fmaxf(float, float)\n"
+ "declare x86_fp80 @fmaxl(x86_fp80, x86_fp80)\n"
+ "declare double @fmin(double, double)\n"
+ "declare float @fminf(float, float)\n"
+ "declare x86_fp80 @fminl(x86_fp80, x86_fp80)\n"
+ "declare double @fmod(double, double)\n"
+ "declare float @fmodf(float, float)\n"
+ "declare x86_fp80 @fmodl(x86_fp80, x86_fp80)\n"
+ "declare i32 @fprintf(%struct*, i8*, ...)\n"
+ "declare i32 @fputc(i32, %struct*)\n"
+ "declare i64 @fread(i8*, i64, i64, %struct*)\n"
+ "declare void @free(i8*)\n"
+ "declare double @frexp(double, i32*)\n"
+ "declare float @frexpf(float, i32*)\n"
+ "declare x86_fp80 @frexpl(x86_fp80, i32*)\n"
+ "declare i32 @fscanf(%struct*, i8*, ...)\n"
+ "declare i32 @fseek(%struct*, i64, i32)\n"
+ "declare i32 @fseeko(%struct*, i64, i32)\n"
+ "declare i32 @fsetpos(%struct*, i64*)\n"
+ "declare i32 @fstatvfs(i32, %struct*)\n"
+ "declare i64 @ftell(%struct*)\n"
+ "declare i64 @ftello(%struct*)\n"
+ "declare i32 @ftrylockfile(%struct*)\n"
+ "declare void @funlockfile(%struct*)\n"
+ "declare i32 @getc(%struct*)\n"
+ "declare i32 @getc_unlocked(%struct*)\n"
+ "declare i32 @getchar()\n"
+ "declare i8* @getenv(i8*)\n"
+ "declare i32 @getitimer(i32, %struct*)\n"
+ "declare i32 @getlogin_r(i8*, i64)\n"
+ "declare %struct* @getpwnam(i8*)\n"
+ "declare i8* @gets(i8*)\n"
+ "declare i32 @gettimeofday(%struct*, i8*)\n"
+ "declare i32 @_Z7isasciii(i32)\n"
+ "declare i32 @_Z7isdigiti(i32)\n"
+ "declare i64 @labs(i64)\n"
+ "declare double @ldexp(double, i32)\n"
+ "declare float @ldexpf(float, i32)\n"
+ "declare x86_fp80 @ldexpl(x86_fp80, i32)\n"
+ "declare i64 @llabs(i64)\n"
+ "declare double @log(double)\n"
+ "declare double @log10(double)\n"
+ "declare float @log10f(float)\n"
+ "declare x86_fp80 @log10l(x86_fp80)\n"
+ "declare double @log1p(double)\n"
+ "declare float @log1pf(float)\n"
+ "declare x86_fp80 @log1pl(x86_fp80)\n"
+ "declare double @log2(double)\n"
+ "declare float @log2f(float)\n"
+ "declare x86_fp80 @log2l(x86_fp80)\n"
+ "declare double @logb(double)\n"
+ "declare float @logbf(float)\n"
+ "declare x86_fp80 @logbl(x86_fp80)\n"
+ "declare float @logf(float)\n"
+ "declare x86_fp80 @logl(x86_fp80)\n"
+ "declare i8* @malloc(i64)\n"
+ "declare i8* @memccpy(i8*, i8*, i32, i64)\n"
+ "declare i8* @memchr(i8*, i32, i64)\n"
+ "declare i32 @memcmp(i8*, i8*, i64)\n"
+ "declare i8* @memcpy(i8*, i8*, i64)\n"
+ "declare i8* @memmove(i8*, i8*, i64)\n"
+ "declare i8* @memset(i8*, i32, i64)\n"
+ "declare void @memset_pattern16(i8*, i8*, i64)\n"
+ "declare i32 @mkdir(i8*, i16)\n"
+ "declare double @modf(double, double*)\n"
+ "declare float @modff(float, float*)\n"
+ "declare x86_fp80 @modfl(x86_fp80, x86_fp80*)\n"
+ "declare double @nearbyint(double)\n"
+ "declare float @nearbyintf(float)\n"
+ "declare x86_fp80 @nearbyintl(x86_fp80)\n"
+ "declare i32 @pclose(%struct*)\n"
+ "declare void @perror(i8*)\n"
+ "declare i32 @posix_memalign(i8**, i64, i64)\n"
+ "declare double @pow(double, double)\n"
+ "declare float @powf(float, float)\n"
+ "declare x86_fp80 @powl(x86_fp80, x86_fp80)\n"
+ "declare i32 @printf(i8*, ...)\n"
+ "declare i32 @putc(i32, %struct*)\n"
+ "declare i32 @putchar(i32)\n"
+ "declare i32 @puts(i8*)\n"
+ "declare void @qsort(i8*, i64, i64, i32 (i8*, i8*)*)\n"
+ "declare i64 @readlink(i8*, i8*, i64)\n"
+ "declare i8* @realloc(i8*, i64)\n"
+ "declare i8* @reallocf(i8*, i64)\n"
+ "declare i32 @remove(i8*)\n"
+ "declare i32 @rename(i8*, i8*)\n"
+ "declare void @rewind(%struct*)\n"
+ "declare double @rint(double)\n"
+ "declare float @rintf(float)\n"
+ "declare x86_fp80 @rintl(x86_fp80)\n"
+ "declare i32 @rmdir(i8*)\n"
+ "declare double @round(double)\n"
+ "declare float @roundf(float)\n"
+ "declare x86_fp80 @roundl(x86_fp80)\n"
+ "declare i32 @scanf(i8*, ...)\n"
+ "declare void @setbuf(%struct*, i8*)\n"
+ "declare i32 @setitimer(i32, %struct*, %struct*)\n"
+ "declare i32 @setvbuf(%struct*, i8*, i32, i64)\n"
+ "declare double @sin(double)\n"
+ "declare float @sinf(float)\n"
+ "declare double @sinh(double)\n"
+ "declare float @sinhf(float)\n"
+ "declare x86_fp80 @sinhl(x86_fp80)\n"
+ "declare x86_fp80 @sinl(x86_fp80)\n"
+ "declare i32 @snprintf(i8*, i64, i8*, ...)\n"
+ "declare i32 @sprintf(i8*, i8*, ...)\n"
+ "declare double @sqrt(double)\n"
+ "declare float @sqrtf(float)\n"
+ "declare x86_fp80 @sqrtl(x86_fp80)\n"
+ "declare i32 @sscanf(i8*, i8*, ...)\n"
+ "declare i32 @statvfs(i8*, %struct*)\n"
+ "declare i8* @stpcpy(i8*, i8*)\n"
+ "declare i8* @stpncpy(i8*, i8*, i64)\n"
+ "declare i32 @strcasecmp(i8*, i8*)\n"
+ "declare i8* @strcat(i8*, i8*)\n"
+ "declare i8* @strchr(i8*, i32)\n"
+ "declare i32 @strcmp(i8*, i8*)\n"
+ "declare i32 @strcoll(i8*, i8*)\n"
+ "declare i8* @strcpy(i8*, i8*)\n"
+ "declare i64 @strcspn(i8*, i8*)\n"
+ "declare i8* @strdup(i8*)\n"
+ "declare i64 @strlen(i8*)\n"
+ "declare i32 @strncasecmp(i8*, i8*, i64)\n"
+ "declare i8* @strncat(i8*, i8*, i64)\n"
+ "declare i32 @strncmp(i8*, i8*, i64)\n"
+ "declare i8* @strncpy(i8*, i8*, i64)\n"
+ "declare i8* @strndup(i8*, i64)\n"
+ "declare i64 @strnlen(i8*, i64)\n"
+ "declare i8* @strpbrk(i8*, i8*)\n"
+ "declare i8* @strrchr(i8*, i32)\n"
+ "declare i64 @strspn(i8*, i8*)\n"
+ "declare i8* @strstr(i8*, i8*)\n"
+ "declare i8* @strtok(i8*, i8*)\n"
+ "declare i8* @strtok_r(i8*, i8*, i8**)\n"
+ "declare i64 @strtol(i8*, i8**, i32)\n"
+ "declare x86_fp80 @strtold(i8*, i8**)\n"
+ "declare i64 @strtoll(i8*, i8**, i32)\n"
+ "declare i64 @strtoul(i8*, i8**, i32)\n"
+ "declare i64 @strtoull(i8*, i8**, i32)\n"
+ "declare i64 @strxfrm(i8*, i8*, i64)\n"
+ "declare double @tan(double)\n"
+ "declare float @tanf(float)\n"
+ "declare double @tanh(double)\n"
+ "declare float @tanhf(float)\n"
+ "declare x86_fp80 @tanhl(x86_fp80)\n"
+ "declare x86_fp80 @tanl(x86_fp80)\n"
+ "declare i64 @times(%struct*)\n"
+ "declare %struct* @tmpfile()\n"
+ "declare i32 @_Z7toasciii(i32)\n"
+ "declare double @trunc(double)\n"
+ "declare float @truncf(float)\n"
+ "declare x86_fp80 @truncl(x86_fp80)\n"
+ "declare i32 @uname(%struct*)\n"
+ "declare i32 @ungetc(i32, %struct*)\n"
+ "declare i32 @unlink(i8*)\n"
+ "declare i32 @utime(i8*, %struct*)\n"
+ "declare i32 @utimes(i8*, %struct*)\n"
+ "declare i8* @valloc(i64)\n"
+ "declare i32 @vfprintf(%struct*, i8*, %struct*)\n"
+ "declare i32 @vfscanf(%struct*, i8*, %struct*)\n"
+ "declare i32 @vprintf(i8*, %struct*)\n"
+ "declare i32 @vscanf(i8*, %struct*)\n"
+ "declare i32 @vsnprintf(i8*, i64, i8*, %struct*)\n"
+ "declare i32 @vsprintf(i8*, i8*, %struct*)\n"
+ "declare i32 @vsscanf(i8*, i8*, %struct*)\n"
+
+ // These functions were also extracted from the OS X headers, but they are
+ // available with a special name on darwin.
+ // This test uses the default TLI name instead.
+ "declare i32 @chmod(i8*, i16)\n"
+ "declare i32 @closedir(%struct*)\n"
+ "declare %struct* @fdopen(i32, i8*)\n"
+ "declare %struct* @fopen(i8*, i8*)\n"
+ "declare i32 @fputs(i8*, %struct*)\n"
+ "declare i32 @fstat(i32, %struct*)\n"
+ "declare i64 @fwrite(i8*, i64, i64, %struct*)\n"
+ "declare i32 @lchown(i8*, i32, i32)\n"
+ "declare i32 @lstat(i8*, %struct*)\n"
+ "declare i64 @mktime(%struct*)\n"
+ "declare i32 @open(i8*, i32, ...)\n"
+ "declare %struct* @opendir(i8*)\n"
+ "declare %struct* @popen(i8*, i8*)\n"
+ "declare i64 @pread(i32, i8*, i64, i64)\n"
+ "declare i64 @pwrite(i32, i8*, i64, i64)\n"
+ "declare i64 @read(i32, i8*, i64)\n"
+ "declare i8* @realpath(i8*, i8*)\n"
+ "declare i32 @stat(i8*, %struct*)\n"
+ "declare double @strtod(i8*, i8**)\n"
+ "declare float @strtof(i8*, i8**)\n"
+ "declare i32 @system(i8*)\n"
+ "declare i32 @unsetenv(i8*)\n"
+ "declare i64 @write(i32, i8*, i64)\n"
+
+ // These functions are available on Linux but not Darwin; they only differ
+ // from their non-64 counterparts in the struct type.
+ // Use the same prototype as the non-64 variant.
+ "declare %struct* @fopen64(i8*, i8*)\n"
+ "declare i32 @fstat64(i32, %struct*)\n"
+ "declare i32 @fstatvfs64(i32, %struct*)\n"
+ "declare i32 @lstat64(i8*, %struct*)\n"
+ "declare i32 @open64(i8*, i32, ...)\n"
+ "declare i32 @stat64(i8*, %struct*)\n"
+ "declare i32 @statvfs64(i8*, %struct*)\n"
+ "declare %struct* @tmpfile64()\n"
+
+ // These functions are also -64 variants, but do differ in the type of the
+ // off_t (vs off64_t) parameter. The non-64 variants declared above used
+ // a 64-bit off_t, so, in practice, they are also equivalent.
+ "declare i32 @fseeko64(%struct*, i64, i32)\n"
+ "declare i64 @ftello64(%struct*)\n"
+
+ "declare void @_ZdaPv(i8*)\n"
+ "declare void @_ZdaPvRKSt9nothrow_t(i8*, %struct*)\n"
+ "declare void @_ZdaPvj(i8*, i32)\n"
+ "declare void @_ZdaPvm(i8*, i64)\n"
+ "declare void @_ZdlPv(i8*)\n"
+ "declare void @_ZdlPvRKSt9nothrow_t(i8*, %struct*)\n"
+ "declare void @_ZdlPvj(i8*, i32)\n"
+ "declare void @_ZdlPvm(i8*, i64)\n"
+ "declare i8* @_Znaj(i32)\n"
+ "declare i8* @_ZnajRKSt9nothrow_t(i32, %struct*)\n"
+ "declare i8* @_Znam(i64)\n"
+ "declare i8* @_ZnamRKSt9nothrow_t(i64, %struct*)\n"
+ "declare i8* @_Znwj(i32)\n"
+ "declare i8* @_ZnwjRKSt9nothrow_t(i32, %struct*)\n"
+ "declare i8* @_Znwm(i64)\n"
+ "declare i8* @_ZnwmRKSt9nothrow_t(i64, %struct*)\n"
+
+ "declare void @\"??3@YAXPEAX@Z\"(i8*)\n"
+ "declare void @\"??3@YAXPEAXAEBUnothrow_t@std@@@Z\"(i8*, %struct*)\n"
+ "declare void @\"??3@YAXPEAX_K@Z\"(i8*, i64)\n"
+ "declare void @\"??_V@YAXPEAX@Z\"(i8*)\n"
+ "declare void @\"??_V@YAXPEAXAEBUnothrow_t@std@@@Z\"(i8*, %struct*)\n"
+ "declare void @\"??_V@YAXPEAX_K@Z\"(i8*, i64)\n"
+ "declare i8* @\"??2@YAPAXI@Z\"(i32)\n"
+ "declare i8* @\"??2@YAPAXIABUnothrow_t@std@@@Z\"(i32, %struct*)\n"
+ "declare i8* @\"??2@YAPEAX_K@Z\"(i64)\n"
+ "declare i8* @\"??2@YAPEAX_KAEBUnothrow_t@std@@@Z\"(i64, %struct*)\n"
+ "declare i8* @\"??_U@YAPAXI@Z\"(i32)\n"
+ "declare i8* @\"??_U@YAPAXIABUnothrow_t@std@@@Z\"(i32, %struct*)\n"
+ "declare i8* @\"??_U@YAPEAX_K@Z\"(i64)\n"
+ "declare i8* @\"??_U@YAPEAX_KAEBUnothrow_t@std@@@Z\"(i64, %struct*)\n"
+
+ "declare void @\"??3@YAXPAX@Z\"(i8*)\n"
+ "declare void @\"??3@YAXPAXABUnothrow_t@std@@@Z\"(i8*, %struct*)\n"
+ "declare void @\"??3@YAXPAXI@Z\"(i8*, i32)\n"
+ "declare void @\"??_V@YAXPAX@Z\"(i8*)\n"
+ "declare void @\"??_V@YAXPAXABUnothrow_t@std@@@Z\"(i8*, %struct*)\n"
+ "declare void @\"??_V@YAXPAXI@Z\"(i8*, i32)\n"
+
+ // These other functions were derived from the .def C declaration.
+ "declare i32 @__cxa_atexit(void (i8*)*, i8*, i8*)\n"
+ "declare void @__cxa_guard_abort(%struct*)\n"
+ "declare i32 @__cxa_guard_acquire(%struct*)\n"
+ "declare void @__cxa_guard_release(%struct*)\n"
+
+ "declare i32 @__nvvm_reflect(i8*)\n"
+
+ "declare i8* @__memcpy_chk(i8*, i8*, i64, i64)\n"
+ "declare i8* @__memmove_chk(i8*, i8*, i64, i64)\n"
+ "declare i8* @__memset_chk(i8*, i32, i64, i64)\n"
+ "declare i8* @__stpcpy_chk(i8*, i8*, i64)\n"
+ "declare i8* @__stpncpy_chk(i8*, i8*, i64, i64)\n"
+ "declare i8* @__strcpy_chk(i8*, i8*, i64)\n"
+ "declare i8* @__strncpy_chk(i8*, i8*, i64, i64)\n"
+
+ "declare i8* @memalign(i64, i64)\n"
+ "declare i8* @mempcpy(i8*, i8*, i64)\n"
+ "declare i8* @memrchr(i8*, i32, i64)\n"
+
+ // These are similar to the FILE* fgetc/fputc.
+ "declare i32 @_IO_getc(%struct*)\n"
+ "declare i32 @_IO_putc(i32, %struct*)\n"
+
+ "declare i32 @__isoc99_scanf(i8*, ...)\n"
+ "declare i32 @__isoc99_sscanf(i8*, i8*, ...)\n"
+ "declare i8* @__strdup(i8*)\n"
+ "declare i8* @__strndup(i8*, i64)\n"
+ "declare i8* @__strtok_r(i8*, i8*, i8**)\n"
+
+ "declare double @__sqrt_finite(double)\n"
+ "declare float @__sqrtf_finite(float)\n"
+ "declare x86_fp80 @__sqrtl_finite(x86_fp80)\n"
+ "declare double @exp10(double)\n"
+ "declare float @exp10f(float)\n"
+ "declare x86_fp80 @exp10l(x86_fp80)\n"
+
+ // These printf variants have the same prototype as the non-'i' versions.
+ "declare i32 @fiprintf(%struct*, i8*, ...)\n"
+ "declare i32 @iprintf(i8*, ...)\n"
+ "declare i32 @siprintf(i8*, i8*, ...)\n"
+
+ "declare i32 @htonl(i32)\n"
+ "declare i16 @htons(i16)\n"
+ "declare i32 @ntohl(i32)\n"
+ "declare i16 @ntohs(i16)\n"
+
+ "declare i32 @isascii(i32)\n"
+ "declare i32 @isdigit(i32)\n"
+ "declare i32 @toascii(i32)\n"
+ );
+
+ for (unsigned FI = 0; FI != LibFunc::NumLibFuncs; ++FI) {
+ LibFunc LF = (LibFunc)FI;
+ // Make sure everything is available; we're not testing target defaults.
+ TLII.setAvailable(LF);
+ Function *F = M->getFunction(TLI.getName(LF));
+ EXPECT_TRUE(isLibFunc(F, LF));
+ }
+}
diff --git a/unittests/Analysis/UnrollAnalyzer.cpp b/unittests/Analysis/UnrollAnalyzer.cpp
index 6d11ab1f2f1ba..d6a7bd360b935 100644
--- a/unittests/Analysis/UnrollAnalyzer.cpp
+++ b/unittests/Analysis/UnrollAnalyzer.cpp
@@ -61,7 +61,6 @@ struct UnrollAnalyzerTest : public FunctionPass {
char UnrollAnalyzerTest::ID = 0;
std::unique_ptr<Module> makeLLVMModule(LLVMContext &Context,
- UnrollAnalyzerTest *P,
const char *ModuleStr) {
SMDiagnostic Err;
return parseAssemblyString(ModuleStr, Err, Context);
@@ -87,7 +86,7 @@ TEST(UnrollAnalyzerTest, BasicSimplifications) {
"}\n";
UnrollAnalyzerTest *P = new UnrollAnalyzerTest();
LLVMContext Context;
- std::unique_ptr<Module> M = makeLLVMModule(Context, P, ModuleStr);
+ std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleStr);
legacy::PassManager Passes;
Passes.add(P);
Passes.run(*M);
@@ -150,7 +149,7 @@ TEST(UnrollAnalyzerTest, OuterLoopSimplification) {
UnrollAnalyzerTest *P = new UnrollAnalyzerTest();
LLVMContext Context;
- std::unique_ptr<Module> M = makeLLVMModule(Context, P, ModuleStr);
+ std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleStr);
legacy::PassManager Passes;
Passes.add(P);
Passes.run(*M);
@@ -195,7 +194,7 @@ TEST(UnrollAnalyzerTest, CmpSimplifications) {
"}\n";
UnrollAnalyzerTest *P = new UnrollAnalyzerTest();
LLVMContext Context;
- std::unique_ptr<Module> M = makeLLVMModule(Context, P, ModuleStr);
+ std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleStr);
legacy::PassManager Passes;
Passes.add(P);
Passes.run(*M);
@@ -242,7 +241,7 @@ TEST(UnrollAnalyzerTest, PtrCmpSimplifications) {
"}\n";
UnrollAnalyzerTest *P = new UnrollAnalyzerTest();
LLVMContext Context;
- std::unique_ptr<Module> M = makeLLVMModule(Context, P, ModuleStr);
+ std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleStr);
legacy::PassManager Passes;
Passes.add(P);
Passes.run(*M);
@@ -288,7 +287,7 @@ TEST(UnrollAnalyzerTest, CastSimplifications) {
UnrollAnalyzerTest *P = new UnrollAnalyzerTest();
LLVMContext Context;
- std::unique_ptr<Module> M = makeLLVMModule(Context, P, ModuleStr);
+ std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleStr);
legacy::PassManager Passes;
Passes.add(P);
Passes.run(*M);
diff --git a/unittests/Analysis/ValueTrackingTest.cpp b/unittests/Analysis/ValueTrackingTest.cpp
index ba0d30d59b662..3c8ecfbe1ee23 100644
--- a/unittests/Analysis/ValueTrackingTest.cpp
+++ b/unittests/Analysis/ValueTrackingTest.cpp
@@ -219,7 +219,7 @@ TEST(ValueTracking, GuaranteedToTransferExecutionToSuccessor) {
assert(F && "Bad assembly?");
auto &BB = F->getEntryBlock();
- ArrayRef<bool> ExpectedAnswers = {
+ bool ExpectedAnswers[] = {
true, // call void @nounwind_readonly(i32* %p)
true, // call void @nounwind_argmemonly(i32* %p)
false, // call void @throws_but_readonly(i32* %p)
@@ -239,3 +239,22 @@ TEST(ValueTracking, GuaranteedToTransferExecutionToSuccessor) {
Index++;
}
}
+
+TEST(ValueTracking, ComputeNumSignBits_PR32045) {
+ StringRef Assembly = "define i32 @f(i32 %a) { "
+ " %val = ashr i32 %a, -1 "
+ " ret i32 %val "
+ "} ";
+
+ LLVMContext Context;
+ SMDiagnostic Error;
+ auto M = parseAssemblyString(Assembly, Error, Context);
+ assert(M && "Bad assembly?");
+
+ auto *F = M->getFunction("f");
+ assert(F && "Bad assembly?");
+
+ auto *RVal =
+ cast<ReturnInst>(F->getEntryBlock().getTerminator())->getOperand(0);
+ EXPECT_EQ(ComputeNumSignBits(RVal, M->getDataLayout()), 1u);
+}
diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt
index 8dbca211d0268..8e40f141463ba 100644
--- a/unittests/CMakeLists.txt
+++ b/unittests/CMakeLists.txt
@@ -24,3 +24,4 @@ add_subdirectory(ProfileData)
add_subdirectory(Support)
add_subdirectory(Target)
add_subdirectory(Transforms)
+add_subdirectory(XRay)
diff --git a/unittests/CodeGen/LowLevelTypeTest.cpp b/unittests/CodeGen/LowLevelTypeTest.cpp
index 4ea181c1c9d3c..67113005a46a1 100644
--- a/unittests/CodeGen/LowLevelTypeTest.cpp
+++ b/unittests/CodeGen/LowLevelTypeTest.cpp
@@ -68,7 +68,7 @@ TEST(LowLevelTypeTest, Scalar) {
// Test Type->LLT conversion.
Type *IRTy = IntegerType::get(C, S);
- EXPECT_EQ(Ty, LLT(*IRTy, DL));
+ EXPECT_EQ(Ty, getLLTForType(*IRTy, DL));
}
}
@@ -160,7 +160,7 @@ TEST(LowLevelTypeTest, Vector) {
// Test Type->LLT conversion.
Type *IRSTy = IntegerType::get(C, S);
Type *IRTy = VectorType::get(IRSTy, Elts);
- EXPECT_EQ(VTy, LLT(*IRTy, DL));
+ EXPECT_EQ(VTy, getLLTForType(*IRTy, DL));
}
}
}
@@ -188,7 +188,7 @@ TEST(LowLevelTypeTest, Pointer) {
// Test Type->LLT conversion.
Type *IRTy = PointerType::get(IntegerType::get(C, 8), AS);
- EXPECT_EQ(Ty, LLT(*IRTy, DL));
+ EXPECT_EQ(Ty, getLLTForType(*IRTy, DL));
}
}
diff --git a/unittests/DebugInfo/DWARF/CMakeLists.txt b/unittests/DebugInfo/DWARF/CMakeLists.txt
index eafca4a2fc06e..ed512a92ef183 100644
--- a/unittests/DebugInfo/DWARF/CMakeLists.txt
+++ b/unittests/DebugInfo/DWARF/CMakeLists.txt
@@ -4,6 +4,7 @@ set(LLVM_LINK_COMPONENTS
DebugInfoDWARF
MC
Object
+ ObjectYAML
Support
)
diff --git a/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp b/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp
index a4109a34097f4..a6c5b3a34ccb7 100644
--- a/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp
+++ b/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp
@@ -8,16 +8,27 @@
//===----------------------------------------------------------------------===//
#include "DwarfGenerator.h"
-#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Config/llvm-config.h"
+#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/DebugInfo/DWARF/DWARFDie.h"
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
-#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/ObjectYAML/DWARFYAML.h"
+#include "llvm/ObjectYAML/DWARFEmitter.h"
#include "llvm/Support/Dwarf.h"
-#include "llvm/Support/Host.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/TargetSelect.h"
#include "gtest/gtest.h"
#include <climits>
+#include <cstdint>
+#include <cstring>
+#include <string>
using namespace llvm;
using namespace dwarf;
@@ -52,7 +63,7 @@ Triple getHostTripleForAddrSize(uint8_t AddrSize) {
template <typename T>
static bool HandleExpectedError(T &Expected) {
std::string ErrorMsg;
- handleAllErrors(Expected.takeError(), [&](const llvm::ErrorInfoBase &EI) {
+ handleAllErrors(Expected.takeError(), [&](const ErrorInfoBase &EI) {
ErrorMsg = EI.message();
});
if (!ErrorMsg.empty()) {
@@ -228,8 +239,7 @@ void TestAllForms() {
//----------------------------------------------------------------------
// Test address forms
//----------------------------------------------------------------------
- EXPECT_EQ(DieDG.getAttributeValueAsAddress(Attr_DW_FORM_addr).getValueOr(0),
- AddrValue);
+ EXPECT_EQ(AddrValue, toAddress(DieDG.find(Attr_DW_FORM_addr), 0));
//----------------------------------------------------------------------
// Test block forms
@@ -238,7 +248,7 @@ void TestAllForms() {
ArrayRef<uint8_t> ExtractedBlockData;
Optional<ArrayRef<uint8_t>> BlockDataOpt;
- FormValue = DieDG.getAttributeValue(Attr_DW_FORM_block);
+ FormValue = DieDG.find(Attr_DW_FORM_block);
EXPECT_TRUE((bool)FormValue);
BlockDataOpt = FormValue->getAsBlock();
EXPECT_TRUE(BlockDataOpt.hasValue());
@@ -246,7 +256,7 @@ void TestAllForms() {
EXPECT_EQ(ExtractedBlockData.size(), BlockSize);
EXPECT_TRUE(memcmp(ExtractedBlockData.data(), BlockData, BlockSize) == 0);
- FormValue = DieDG.getAttributeValue(Attr_DW_FORM_block1);
+ FormValue = DieDG.find(Attr_DW_FORM_block1);
EXPECT_TRUE((bool)FormValue);
BlockDataOpt = FormValue->getAsBlock();
EXPECT_TRUE(BlockDataOpt.hasValue());
@@ -254,7 +264,7 @@ void TestAllForms() {
EXPECT_EQ(ExtractedBlockData.size(), BlockSize);
EXPECT_TRUE(memcmp(ExtractedBlockData.data(), BlockData, BlockSize) == 0);
- FormValue = DieDG.getAttributeValue(Attr_DW_FORM_block2);
+ FormValue = DieDG.find(Attr_DW_FORM_block2);
EXPECT_TRUE((bool)FormValue);
BlockDataOpt = FormValue->getAsBlock();
EXPECT_TRUE(BlockDataOpt.hasValue());
@@ -262,7 +272,7 @@ void TestAllForms() {
EXPECT_EQ(ExtractedBlockData.size(), BlockSize);
EXPECT_TRUE(memcmp(ExtractedBlockData.data(), BlockData, BlockSize) == 0);
- FormValue = DieDG.getAttributeValue(Attr_DW_FORM_block4);
+ FormValue = DieDG.find(Attr_DW_FORM_block4);
EXPECT_TRUE((bool)FormValue);
BlockDataOpt = FormValue->getAsBlock();
EXPECT_TRUE(BlockDataOpt.hasValue());
@@ -273,100 +283,64 @@ void TestAllForms() {
//----------------------------------------------------------------------
// Test data forms
//----------------------------------------------------------------------
- EXPECT_EQ(DieDG.getAttributeValueAsUnsignedConstant(Attr_DW_FORM_data1)
- .getValueOr(0),
- Data1);
- EXPECT_EQ(DieDG.getAttributeValueAsUnsignedConstant(Attr_DW_FORM_data2)
- .getValueOr(0),
- Data2);
- EXPECT_EQ(DieDG.getAttributeValueAsUnsignedConstant(Attr_DW_FORM_data4)
- .getValueOr(0),
- Data4);
- EXPECT_EQ(DieDG.getAttributeValueAsUnsignedConstant(Attr_DW_FORM_data8)
- .getValueOr(0),
- Data8);
+ EXPECT_EQ(Data1, toUnsigned(DieDG.find(Attr_DW_FORM_data1), 0));
+ EXPECT_EQ(Data2, toUnsigned(DieDG.find(Attr_DW_FORM_data2), 0));
+ EXPECT_EQ(Data4, toUnsigned(DieDG.find(Attr_DW_FORM_data4), 0));
+ EXPECT_EQ(Data8, toUnsigned(DieDG.find(Attr_DW_FORM_data8), 0));
//----------------------------------------------------------------------
// Test string forms
//----------------------------------------------------------------------
- const char *ExtractedStringValue =
- DieDG.getAttributeValueAsString(Attr_DW_FORM_string, nullptr);
- EXPECT_TRUE(ExtractedStringValue != nullptr);
- EXPECT_TRUE(strcmp(StringValue, ExtractedStringValue) == 0);
+ auto ExtractedStringValue = toString(DieDG.find(Attr_DW_FORM_string));
+ EXPECT_TRUE((bool)ExtractedStringValue);
+ EXPECT_TRUE(strcmp(StringValue, *ExtractedStringValue) == 0);
- const char *ExtractedStrpValue =
- DieDG.getAttributeValueAsString(Attr_DW_FORM_strp, nullptr);
- EXPECT_TRUE(ExtractedStrpValue != nullptr);
- EXPECT_TRUE(strcmp(StrpValue, ExtractedStrpValue) == 0);
+ auto ExtractedStrpValue = toString(DieDG.find(Attr_DW_FORM_strp));
+ EXPECT_TRUE((bool)ExtractedStrpValue);
+ EXPECT_TRUE(strcmp(StrpValue, *ExtractedStrpValue) == 0);
//----------------------------------------------------------------------
// Test reference forms
//----------------------------------------------------------------------
- EXPECT_EQ(
- DieDG.getAttributeValueAsReference(Attr_DW_FORM_ref_addr).getValueOr(0),
- RefAddr);
- EXPECT_EQ(DieDG.getAttributeValueAsReference(Attr_DW_FORM_ref1).getValueOr(0),
- Data1);
- EXPECT_EQ(DieDG.getAttributeValueAsReference(Attr_DW_FORM_ref2).getValueOr(0),
- Data2);
- EXPECT_EQ(DieDG.getAttributeValueAsReference(Attr_DW_FORM_ref4).getValueOr(0),
- Data4);
- EXPECT_EQ(DieDG.getAttributeValueAsReference(Attr_DW_FORM_ref8).getValueOr(0),
- Data8);
- EXPECT_EQ(
- DieDG.getAttributeValueAsReference(Attr_DW_FORM_ref_sig8).getValueOr(0),
- Data8_2);
- EXPECT_EQ(
- DieDG.getAttributeValueAsReference(Attr_DW_FORM_ref_udata).getValueOr(0),
- UData[0]);
+ EXPECT_EQ(RefAddr, toReference(DieDG.find(Attr_DW_FORM_ref_addr), 0));
+ EXPECT_EQ(Data1, toReference(DieDG.find(Attr_DW_FORM_ref1), 0));
+ EXPECT_EQ(Data2, toReference(DieDG.find(Attr_DW_FORM_ref2), 0));
+ EXPECT_EQ(Data4, toReference(DieDG.find(Attr_DW_FORM_ref4), 0));
+ EXPECT_EQ(Data8, toReference(DieDG.find(Attr_DW_FORM_ref8), 0));
+ EXPECT_EQ(Data8_2, toReference(DieDG.find(Attr_DW_FORM_ref_sig8), 0));
+ EXPECT_EQ(UData[0], toReference(DieDG.find(Attr_DW_FORM_ref_udata), 0));
//----------------------------------------------------------------------
// Test flag forms
//----------------------------------------------------------------------
- EXPECT_EQ(DieDG.getAttributeValueAsUnsignedConstant(Attr_DW_FORM_flag_true)
- .getValueOr(0),
- 1ULL);
- EXPECT_EQ(DieDG.getAttributeValueAsUnsignedConstant(Attr_DW_FORM_flag_false)
- .getValueOr(1),
- 0ULL);
- EXPECT_EQ(DieDG.getAttributeValueAsUnsignedConstant(Attr_DW_FORM_flag_present)
- .getValueOr(0ULL),
- 1ULL);
+ EXPECT_EQ(1ULL, toUnsigned(DieDG.find(Attr_DW_FORM_flag_true), 0));
+ EXPECT_EQ(0ULL, toUnsigned(DieDG.find(Attr_DW_FORM_flag_false), 1));
+ EXPECT_EQ(1ULL, toUnsigned(DieDG.find(Attr_DW_FORM_flag_present), 0));
//----------------------------------------------------------------------
// Test SLEB128 based forms
//----------------------------------------------------------------------
- EXPECT_EQ(
- DieDG.getAttributeValueAsSignedConstant(Attr_DW_FORM_sdata).getValueOr(0),
- SData);
+ EXPECT_EQ(SData, toSigned(DieDG.find(Attr_DW_FORM_sdata), 0));
if (Version >= 5)
- EXPECT_EQ(
- DieDG.getAttributeValueAsSignedConstant(Attr_DW_FORM_implicit_const)
- .getValueOr(0),
- ICSData);
+ EXPECT_EQ(ICSData, toSigned(DieDG.find(Attr_DW_FORM_implicit_const), 0));
//----------------------------------------------------------------------
// Test ULEB128 based forms
//----------------------------------------------------------------------
- EXPECT_EQ(DieDG.getAttributeValueAsUnsignedConstant(Attr_DW_FORM_udata)
- .getValueOr(0),
- UData[0]);
+ EXPECT_EQ(UData[0], toUnsigned(DieDG.find(Attr_DW_FORM_udata), 0));
//----------------------------------------------------------------------
// Test DWARF32/DWARF64 forms
//----------------------------------------------------------------------
- EXPECT_EQ(DieDG.getAttributeValueAsReference(Attr_DW_FORM_GNU_ref_alt)
- .getValueOr(0),
- Dwarf32Values[0]);
- EXPECT_EQ(DieDG.getAttributeValueAsSectionOffset(Attr_DW_FORM_sec_offset)
- .getValueOr(0),
- Dwarf32Values[1]);
+ EXPECT_EQ(Dwarf32Values[0],
+ toReference(DieDG.find(Attr_DW_FORM_GNU_ref_alt), 0));
+ EXPECT_EQ(Dwarf32Values[1],
+ toSectionOffset(DieDG.find(Attr_DW_FORM_sec_offset), 0));
//----------------------------------------------------------------------
// Add an address at the end to make sure we can decode this value
//----------------------------------------------------------------------
- EXPECT_EQ(DieDG.getAttributeValueAsAddress(Attr_Last).getValueOr(0),
- AddrValue);
+ EXPECT_EQ(AddrValue, toAddress(DieDG.find(Attr_Last), 0));
}
TEST(DWARFDebugInfo, TestDWARF32Version2Addr4AllForms) {
@@ -488,7 +462,6 @@ template <uint16_t Version, class AddrType> void TestChildren() {
// Get the compile unit DIE is valid.
auto DieDG = U->getUnitDIE(false);
EXPECT_TRUE(DieDG.isValid());
- // DieDG.dump(llvm::outs(), U, UINT32_MAX);
// Verify the first child of the compile unit DIE is our subprogram.
auto SubprogramDieDG = DieDG.getFirstChild();
@@ -662,133 +635,115 @@ template <uint16_t Version, class AddrType> void TestReferences() {
// Get the compile unit DIE is valid.
auto Unit1DieDG = U1->getUnitDIE(false);
EXPECT_TRUE(Unit1DieDG.isValid());
- // Unit1DieDG.dump(llvm::outs(), UINT32_MAX);
auto Unit2DieDG = U2->getUnitDIE(false);
EXPECT_TRUE(Unit2DieDG.isValid());
- // Unit2DieDG.dump(llvm::outs(), UINT32_MAX);
// Verify the first child of the compile unit 1 DIE is our int base type.
auto CU1TypeDieDG = Unit1DieDG.getFirstChild();
EXPECT_TRUE(CU1TypeDieDG.isValid());
EXPECT_EQ(CU1TypeDieDG.getTag(), DW_TAG_base_type);
- EXPECT_EQ(CU1TypeDieDG.getAttributeValueAsUnsignedConstant(DW_AT_encoding)
- .getValueOr(0),
- DW_ATE_signed);
+ EXPECT_EQ(DW_ATE_signed, toUnsigned(CU1TypeDieDG.find(DW_AT_encoding), 0));
// Verify the first child of the compile unit 2 DIE is our float base type.
auto CU2TypeDieDG = Unit2DieDG.getFirstChild();
EXPECT_TRUE(CU2TypeDieDG.isValid());
EXPECT_EQ(CU2TypeDieDG.getTag(), DW_TAG_base_type);
- EXPECT_EQ(CU2TypeDieDG.getAttributeValueAsUnsignedConstant(DW_AT_encoding)
- .getValueOr(0),
- DW_ATE_float);
+ EXPECT_EQ(DW_ATE_float, toUnsigned(CU2TypeDieDG.find(DW_AT_encoding), 0));
// Verify the sibling of the base type DIE is our Ref1 DIE and that its
// DW_AT_type points to our base type DIE.
auto CU1Ref1DieDG = CU1TypeDieDG.getSibling();
EXPECT_TRUE(CU1Ref1DieDG.isValid());
EXPECT_EQ(CU1Ref1DieDG.getTag(), DW_TAG_variable);
- EXPECT_EQ(
- CU1Ref1DieDG.getAttributeValueAsReference(DW_AT_type).getValueOr(-1ULL),
- CU1TypeDieDG.getOffset());
+ EXPECT_EQ(CU1TypeDieDG.getOffset(),
+ toReference(CU1Ref1DieDG.find(DW_AT_type), -1ULL));
// Verify the sibling is our Ref2 DIE and that its DW_AT_type points to our
// base type DIE in CU1.
auto CU1Ref2DieDG = CU1Ref1DieDG.getSibling();
EXPECT_TRUE(CU1Ref2DieDG.isValid());
EXPECT_EQ(CU1Ref2DieDG.getTag(), DW_TAG_variable);
- EXPECT_EQ(
- CU1Ref2DieDG.getAttributeValueAsReference(DW_AT_type).getValueOr(-1ULL),
- CU1TypeDieDG.getOffset());
+ EXPECT_EQ(CU1TypeDieDG.getOffset(),
+ toReference(CU1Ref2DieDG.find(DW_AT_type), -1ULL));
// Verify the sibling is our Ref4 DIE and that its DW_AT_type points to our
// base type DIE in CU1.
auto CU1Ref4DieDG = CU1Ref2DieDG.getSibling();
EXPECT_TRUE(CU1Ref4DieDG.isValid());
EXPECT_EQ(CU1Ref4DieDG.getTag(), DW_TAG_variable);
- EXPECT_EQ(
- CU1Ref4DieDG.getAttributeValueAsReference(DW_AT_type).getValueOr(-1ULL),
- CU1TypeDieDG.getOffset());
+ EXPECT_EQ(CU1TypeDieDG.getOffset(),
+ toReference(CU1Ref4DieDG.find(DW_AT_type), -1ULL));
// Verify the sibling is our Ref8 DIE and that its DW_AT_type points to our
// base type DIE in CU1.
auto CU1Ref8DieDG = CU1Ref4DieDG.getSibling();
EXPECT_TRUE(CU1Ref8DieDG.isValid());
EXPECT_EQ(CU1Ref8DieDG.getTag(), DW_TAG_variable);
- EXPECT_EQ(
- CU1Ref8DieDG.getAttributeValueAsReference(DW_AT_type).getValueOr(-1ULL),
- CU1TypeDieDG.getOffset());
+ EXPECT_EQ(CU1TypeDieDG.getOffset(),
+ toReference(CU1Ref8DieDG.find(DW_AT_type), -1ULL));
// Verify the sibling is our RefAddr DIE and that its DW_AT_type points to our
// base type DIE in CU1.
auto CU1RefAddrDieDG = CU1Ref8DieDG.getSibling();
EXPECT_TRUE(CU1RefAddrDieDG.isValid());
EXPECT_EQ(CU1RefAddrDieDG.getTag(), DW_TAG_variable);
- EXPECT_EQ(CU1RefAddrDieDG.getAttributeValueAsReference(DW_AT_type)
- .getValueOr(-1ULL),
- CU1TypeDieDG.getOffset());
+ EXPECT_EQ(CU1TypeDieDG.getOffset(),
+ toReference(CU1RefAddrDieDG.find(DW_AT_type), -1ULL));
// Verify the sibling of the Ref4 DIE is our RefAddr DIE and that its
// DW_AT_type points to our base type DIE.
auto CU1ToCU2RefAddrDieDG = CU1RefAddrDieDG.getSibling();
EXPECT_TRUE(CU1ToCU2RefAddrDieDG.isValid());
EXPECT_EQ(CU1ToCU2RefAddrDieDG.getTag(), DW_TAG_variable);
- EXPECT_EQ(CU1ToCU2RefAddrDieDG.getAttributeValueAsReference(DW_AT_type)
- .getValueOr(-1ULL),
- CU2TypeDieDG.getOffset());
+ EXPECT_EQ(CU2TypeDieDG.getOffset(),
+ toReference(CU1ToCU2RefAddrDieDG.find(DW_AT_type), -1ULL));
// Verify the sibling of the base type DIE is our Ref1 DIE and that its
// DW_AT_type points to our base type DIE.
auto CU2Ref1DieDG = CU2TypeDieDG.getSibling();
EXPECT_TRUE(CU2Ref1DieDG.isValid());
EXPECT_EQ(CU2Ref1DieDG.getTag(), DW_TAG_variable);
- EXPECT_EQ(
- CU2Ref1DieDG.getAttributeValueAsReference(DW_AT_type).getValueOr(-1ULL),
- CU2TypeDieDG.getOffset());
+ EXPECT_EQ(CU2TypeDieDG.getOffset(),
+ toReference(CU2Ref1DieDG.find(DW_AT_type), -1ULL));
// Verify the sibling is our Ref2 DIE and that its DW_AT_type points to our
// base type DIE in CU2.
auto CU2Ref2DieDG = CU2Ref1DieDG.getSibling();
EXPECT_TRUE(CU2Ref2DieDG.isValid());
EXPECT_EQ(CU2Ref2DieDG.getTag(), DW_TAG_variable);
- EXPECT_EQ(
- CU2Ref2DieDG.getAttributeValueAsReference(DW_AT_type).getValueOr(-1ULL),
- CU2TypeDieDG.getOffset());
+ EXPECT_EQ(CU2TypeDieDG.getOffset(),
+ toReference(CU2Ref2DieDG.find(DW_AT_type), -1ULL));
// Verify the sibling is our Ref4 DIE and that its DW_AT_type points to our
// base type DIE in CU2.
auto CU2Ref4DieDG = CU2Ref2DieDG.getSibling();
EXPECT_TRUE(CU2Ref4DieDG.isValid());
EXPECT_EQ(CU2Ref4DieDG.getTag(), DW_TAG_variable);
- EXPECT_EQ(
- CU2Ref4DieDG.getAttributeValueAsReference(DW_AT_type).getValueOr(-1ULL),
- CU2TypeDieDG.getOffset());
+ EXPECT_EQ(CU2TypeDieDG.getOffset(),
+ toReference(CU2Ref4DieDG.find(DW_AT_type), -1ULL));
// Verify the sibling is our Ref8 DIE and that its DW_AT_type points to our
// base type DIE in CU2.
auto CU2Ref8DieDG = CU2Ref4DieDG.getSibling();
EXPECT_TRUE(CU2Ref8DieDG.isValid());
EXPECT_EQ(CU2Ref8DieDG.getTag(), DW_TAG_variable);
- EXPECT_EQ(
- CU2Ref8DieDG.getAttributeValueAsReference(DW_AT_type).getValueOr(-1ULL),
- CU2TypeDieDG.getOffset());
+ EXPECT_EQ(CU2TypeDieDG.getOffset(),
+ toReference(CU2Ref8DieDG.find(DW_AT_type), -1ULL));
// Verify the sibling is our RefAddr DIE and that its DW_AT_type points to our
// base type DIE in CU2.
auto CU2RefAddrDieDG = CU2Ref8DieDG.getSibling();
EXPECT_TRUE(CU2RefAddrDieDG.isValid());
EXPECT_EQ(CU2RefAddrDieDG.getTag(), DW_TAG_variable);
- EXPECT_EQ(CU2RefAddrDieDG.getAttributeValueAsReference(DW_AT_type)
- .getValueOr(-1ULL),
- CU2TypeDieDG.getOffset());
+ EXPECT_EQ(CU2TypeDieDG.getOffset(),
+ toReference(CU2RefAddrDieDG.find(DW_AT_type), -1ULL));
// Verify the sibling of the Ref4 DIE is our RefAddr DIE and that its
// DW_AT_type points to our base type DIE.
auto CU2ToCU1RefAddrDieDG = CU2RefAddrDieDG.getSibling();
EXPECT_TRUE(CU2ToCU1RefAddrDieDG.isValid());
EXPECT_EQ(CU2ToCU1RefAddrDieDG.getTag(), DW_TAG_variable);
- EXPECT_EQ(CU2ToCU1RefAddrDieDG.getAttributeValueAsReference(DW_AT_type)
- .getValueOr(-1ULL),
- CU1TypeDieDG.getOffset());
+ EXPECT_EQ(CU1TypeDieDG.getOffset(),
+ toReference(CU2ToCU1RefAddrDieDG.find(DW_AT_type), -1ULL));
}
TEST(DWARFDebugInfo, TestDWARF32Version2Addr4References) {
@@ -887,7 +842,6 @@ template <uint16_t Version, class AddrType> void TestAddresses() {
// Get the compile unit DIE is valid.
auto DieDG = U->getUnitDIE(false);
EXPECT_TRUE(DieDG.isValid());
- // DieDG.dump(llvm::outs(), U, UINT32_MAX);
uint64_t LowPC, HighPC;
Optional<uint64_t> OptU64;
@@ -896,50 +850,48 @@ template <uint16_t Version, class AddrType> void TestAddresses() {
auto SubprogramDieNoPC = DieDG.getFirstChild();
EXPECT_TRUE(SubprogramDieNoPC.isValid());
EXPECT_EQ(SubprogramDieNoPC.getTag(), DW_TAG_subprogram);
- OptU64 = SubprogramDieNoPC.getAttributeValueAsAddress(DW_AT_low_pc);
+ OptU64 = toAddress(SubprogramDieNoPC.find(DW_AT_low_pc));
EXPECT_FALSE((bool)OptU64);
- OptU64 = SubprogramDieNoPC.getAttributeValueAsAddress(DW_AT_high_pc);
+ OptU64 = toAddress(SubprogramDieNoPC.find(DW_AT_high_pc));
EXPECT_FALSE((bool)OptU64);
EXPECT_FALSE(SubprogramDieNoPC.getLowAndHighPC(LowPC, HighPC));
- OptU64 = SubprogramDieNoPC.getAttributeValueAsAddress(DW_AT_high_pc);
+ OptU64 = toAddress(SubprogramDieNoPC.find(DW_AT_high_pc));
EXPECT_FALSE((bool)OptU64);
- OptU64 = SubprogramDieNoPC.getAttributeValueAsUnsignedConstant(DW_AT_high_pc);
+ OptU64 = toUnsigned(SubprogramDieNoPC.find(DW_AT_high_pc));
EXPECT_FALSE((bool)OptU64);
OptU64 = SubprogramDieNoPC.getHighPC(ActualLowPC);
EXPECT_FALSE((bool)OptU64);
EXPECT_FALSE(SubprogramDieNoPC.getLowAndHighPC(LowPC, HighPC));
-
-
+
// Verify the that our subprogram with only a low PC value succeeds when
// we ask for the Low PC, but fails appropriately when asked for the high PC
// or both low and high PC values.
auto SubprogramDieLowPC = SubprogramDieNoPC.getSibling();
EXPECT_TRUE(SubprogramDieLowPC.isValid());
EXPECT_EQ(SubprogramDieLowPC.getTag(), DW_TAG_subprogram);
- OptU64 = SubprogramDieLowPC.getAttributeValueAsAddress(DW_AT_low_pc);
+ OptU64 = toAddress(SubprogramDieLowPC.find(DW_AT_low_pc));
EXPECT_TRUE((bool)OptU64);
EXPECT_EQ(OptU64.getValue(), ActualLowPC);
- OptU64 = SubprogramDieLowPC.getAttributeValueAsAddress(DW_AT_high_pc);
+ OptU64 = toAddress(SubprogramDieLowPC.find(DW_AT_high_pc));
EXPECT_FALSE((bool)OptU64);
- OptU64 = SubprogramDieLowPC.getAttributeValueAsUnsignedConstant(DW_AT_high_pc);
+ OptU64 = toUnsigned(SubprogramDieLowPC.find(DW_AT_high_pc));
EXPECT_FALSE((bool)OptU64);
OptU64 = SubprogramDieLowPC.getHighPC(ActualLowPC);
EXPECT_FALSE((bool)OptU64);
EXPECT_FALSE(SubprogramDieLowPC.getLowAndHighPC(LowPC, HighPC));
-
// Verify the that our subprogram with only a low PC value succeeds when
// we ask for the Low PC, but fails appropriately when asked for the high PC
// or both low and high PC values.
auto SubprogramDieLowHighPC = SubprogramDieLowPC.getSibling();
EXPECT_TRUE(SubprogramDieLowHighPC.isValid());
EXPECT_EQ(SubprogramDieLowHighPC.getTag(), DW_TAG_subprogram);
- OptU64 = SubprogramDieLowHighPC.getAttributeValueAsAddress(DW_AT_low_pc);
+ OptU64 = toAddress(SubprogramDieLowHighPC.find(DW_AT_low_pc));
EXPECT_TRUE((bool)OptU64);
EXPECT_EQ(OptU64.getValue(), ActualLowPC);
// Get the high PC as an address. This should succeed if the high PC was
// encoded as an address and fail if the high PC was encoded as an offset.
- OptU64 = SubprogramDieLowHighPC.getAttributeValueAsAddress(DW_AT_high_pc);
+ OptU64 = toAddress(SubprogramDieLowHighPC.find(DW_AT_high_pc));
if (SupportsHighPCAsOffset) {
EXPECT_FALSE((bool)OptU64);
} else {
@@ -948,8 +900,7 @@ template <uint16_t Version, class AddrType> void TestAddresses() {
}
// Get the high PC as an unsigned constant. This should succeed if the high PC
// was encoded as an offset and fail if the high PC was encoded as an address.
- OptU64 = SubprogramDieLowHighPC.getAttributeValueAsUnsignedConstant(
- DW_AT_high_pc);
+ OptU64 = toUnsigned(SubprogramDieLowHighPC.find(DW_AT_high_pc));
if (SupportsHighPCAsOffset) {
EXPECT_TRUE((bool)OptU64);
EXPECT_EQ(OptU64.getValue(), ActualHighPCOffset);
@@ -1067,7 +1018,6 @@ TEST(DWARFDebugInfo, TestRelations) {
// Get the compile unit DIE is valid.
auto CUDie = U->getUnitDIE(false);
EXPECT_TRUE(CUDie.isValid());
- // CUDie.dump(llvm::outs(), UINT32_MAX);
// The compile unit doesn't have a parent or a sibling.
auto ParentDie = CUDie.getParent();
@@ -1132,7 +1082,6 @@ TEST(DWARFDebugInfo, TestRelations) {
}
TEST(DWARFDebugInfo, TestDWARFDie) {
-
// Make sure a default constructed DWARFDie doesn't have any parent, sibling
// or child;
DWARFDie DefaultDie;
@@ -1185,7 +1134,6 @@ TEST(DWARFDebugInfo, TestChildIterators) {
// Get the compile unit DIE is valid.
auto CUDie = U->getUnitDIE(false);
EXPECT_TRUE(CUDie.isValid());
- // CUDie.dump(llvm::outs(), UINT32_MAX);
uint32_t Index;
DWARFDie A;
DWARFDie B;
@@ -1217,11 +1165,49 @@ TEST(DWARFDebugInfo, TestChildIteratorsOnInvalidDie) {
EXPECT_EQ(begin, end);
}
-
TEST(DWARFDebugInfo, TestEmptyChildren) {
- // Test a DIE that says it has children in the abbreviation, but actually
- // doesn't have any attributes, will not return anything during iteration.
- // We do this by making sure the begin and end iterators are equal.
+ const char *yamldata = "debug_abbrev:\n"
+ " - Code: 0x00000001\n"
+ " Tag: DW_TAG_compile_unit\n"
+ " Children: DW_CHILDREN_yes\n"
+ " Attributes:\n"
+ "debug_info:\n"
+ " - Length:\n"
+ " TotalLength: 9\n"
+ " Version: 4\n"
+ " AbbrOffset: 0\n"
+ " AddrSize: 8\n"
+ " Entries:\n"
+ " - AbbrCode: 0x00000001\n"
+ " Values:\n"
+ " - AbbrCode: 0x00000000\n"
+ " Values:\n";
+
+ auto ErrOrSections = DWARFYAML::EmitDebugSections(StringRef(yamldata));
+ ASSERT_TRUE((bool)ErrOrSections);
+
+ auto &DebugSections = *ErrOrSections;
+
+ DWARFContextInMemory DwarfContext(DebugSections, 8);
+
+ // Verify the number of compile units is correct.
+ uint32_t NumCUs = DwarfContext.getNumCompileUnits();
+ EXPECT_EQ(NumCUs, 1u);
+ DWARFCompileUnit *U = DwarfContext.getCompileUnitAtIndex(0);
+
+ // Get the compile unit DIE is valid.
+ auto CUDie = U->getUnitDIE(false);
+ EXPECT_TRUE(CUDie.isValid());
+
+ // Verify that the CU Die that says it has children, but doesn't, actually
+ // has begin and end iterators that are equal. We want to make sure we don't
+ // see the Null DIEs during iteration.
+ EXPECT_EQ(CUDie.begin(), CUDie.end());
+}
+
+TEST(DWARFDebugInfo, TestAttributeIterators) {
+ // Test the DWARF APIs related to iterating across all attribute values in a
+ // a DWARFDie.
uint16_t Version = 4;
const uint8_t AddrSize = sizeof(void *);
@@ -1232,14 +1218,19 @@ TEST(DWARFDebugInfo, TestEmptyChildren) {
return;
dwarfgen::Generator *DG = ExpectedDG.get().get();
dwarfgen::CompileUnit &CU = DG->addCompileUnit();
+ const uint64_t CULowPC = 0x1000;
+ StringRef CUPath("/tmp/main.c");
// Scope to allow us to re-use the same DIE names
{
- // Create a compile unit DIE that has an abbreviation that says it has
- // children, but doesn't have any actual attributes. This helps us test
- // a DIE that has only one child: a NULL DIE.
auto CUDie = CU.getUnitDIE();
- CUDie.setForceChildren();
+ // Encode an attribute value before an attribute with no data.
+ CUDie.addAttribute(DW_AT_name, DW_FORM_strp, CUPath.data());
+ // Encode an attribute value with no data in .debug_info/types to ensure
+ // the iteration works correctly.
+ CUDie.addAttribute(DW_AT_declaration, DW_FORM_flag_present);
+ // Encode an attribute value after an attribute with no data.
+ CUDie.addAttribute(DW_AT_low_pc, DW_FORM_addr, CULowPC);
}
MemoryBufferRef FileBuffer(DG->generate(), "dwarf");
@@ -1255,12 +1246,419 @@ TEST(DWARFDebugInfo, TestEmptyChildren) {
// Get the compile unit DIE is valid.
auto CUDie = U->getUnitDIE(false);
EXPECT_TRUE(CUDie.isValid());
- CUDie.dump(llvm::outs(), UINT32_MAX);
- // Verify that the CU Die that says it has children, but doesn't, actually
- // has begin and end iterators that are equal. We want to make sure we don't
- // see the Null DIEs during iteration.
- EXPECT_EQ(CUDie.begin(), CUDie.end());
+ auto R = CUDie.attributes();
+ auto I = R.begin();
+ auto E = R.end();
+
+ ASSERT_NE(E, I);
+ EXPECT_EQ(I->Attr, DW_AT_name);
+ auto ActualCUPath = I->Value.getAsCString();
+ EXPECT_EQ(CUPath, *ActualCUPath);
+
+ ASSERT_NE(E, ++I);
+ EXPECT_EQ(I->Attr, DW_AT_declaration);
+ EXPECT_EQ(1ull, *I->Value.getAsUnsignedConstant());
+
+ ASSERT_NE(E, ++I);
+ EXPECT_EQ(I->Attr, DW_AT_low_pc);
+ EXPECT_EQ(CULowPC, *I->Value.getAsAddress());
+
+ EXPECT_EQ(E, ++I);
+}
+
+TEST(DWARFDebugInfo, TestFindRecurse) {
+ uint16_t Version = 4;
+
+ const uint8_t AddrSize = sizeof(void *);
+ initLLVMIfNeeded();
+ Triple Triple = getHostTripleForAddrSize(AddrSize);
+ auto ExpectedDG = dwarfgen::Generator::create(Triple, Version);
+ if (HandleExpectedError(ExpectedDG))
+ return;
+ dwarfgen::Generator *DG = ExpectedDG.get().get();
+ dwarfgen::CompileUnit &CU = DG->addCompileUnit();
+
+ StringRef SpecDieName = "spec";
+ StringRef SpecLinkageName = "spec_linkage";
+ StringRef AbsDieName = "abs";
+ // Scope to allow us to re-use the same DIE names
+ {
+ auto CUDie = CU.getUnitDIE();
+ auto FuncSpecDie = CUDie.addChild(DW_TAG_subprogram);
+ auto FuncAbsDie = CUDie.addChild(DW_TAG_subprogram);
+ auto FuncDie = CUDie.addChild(DW_TAG_subprogram);
+ auto VarAbsDie = CUDie.addChild(DW_TAG_variable);
+ auto VarDie = CUDie.addChild(DW_TAG_variable);
+ FuncSpecDie.addAttribute(DW_AT_name, DW_FORM_strp, SpecDieName);
+ FuncAbsDie.addAttribute(DW_AT_linkage_name, DW_FORM_strp, SpecLinkageName);
+ FuncAbsDie.addAttribute(DW_AT_specification, DW_FORM_ref4, FuncSpecDie);
+ FuncDie.addAttribute(DW_AT_abstract_origin, DW_FORM_ref4, FuncAbsDie);
+ VarAbsDie.addAttribute(DW_AT_name, DW_FORM_strp, AbsDieName);
+ VarDie.addAttribute(DW_AT_abstract_origin, DW_FORM_ref4, VarAbsDie);
+ }
+
+ MemoryBufferRef FileBuffer(DG->generate(), "dwarf");
+ auto Obj = object::ObjectFile::createObjectFile(FileBuffer);
+ EXPECT_TRUE((bool)Obj);
+ DWARFContextInMemory DwarfContext(*Obj.get());
+
+ // Verify the number of compile units is correct.
+ uint32_t NumCUs = DwarfContext.getNumCompileUnits();
+ EXPECT_EQ(NumCUs, 1u);
+ DWARFCompileUnit *U = DwarfContext.getCompileUnitAtIndex(0);
+
+ // Get the compile unit DIE is valid.
+ auto CUDie = U->getUnitDIE(false);
+ EXPECT_TRUE(CUDie.isValid());
+
+ auto FuncSpecDie = CUDie.getFirstChild();
+ auto FuncAbsDie = FuncSpecDie.getSibling();
+ auto FuncDie = FuncAbsDie.getSibling();
+ auto VarAbsDie = FuncDie.getSibling();
+ auto VarDie = VarAbsDie.getSibling();
+
+ // Make sure we can't extract the name from the specification die when using
+ // DWARFDie::find() since it won't check the DW_AT_specification DIE.
+ EXPECT_FALSE(FuncDie.find(DW_AT_name));
+
+ // Make sure we can extract the name from the specification die when using
+ // DWARFDie::findRecursively() since it should recurse through the
+ // DW_AT_specification DIE.
+ auto NameOpt = FuncDie.findRecursively(DW_AT_name);
+ EXPECT_TRUE(NameOpt);
+ // Test the dwarf::toString() helper function.
+ auto StringOpt = toString(NameOpt);
+ EXPECT_TRUE(StringOpt);
+ EXPECT_EQ(SpecDieName, StringOpt.getValueOr(nullptr));
+ // Test the dwarf::toString() helper function with a default value specified.
+ EXPECT_EQ(SpecDieName, toString(NameOpt, nullptr));
+
+ auto LinkageNameOpt = FuncDie.findRecursively(DW_AT_linkage_name);
+ EXPECT_EQ(SpecLinkageName, toString(LinkageNameOpt).getValueOr(nullptr));
+
+ // Make sure we can't extract the name from the abstract origin die when using
+ // DWARFDie::find() since it won't check the DW_AT_abstract_origin DIE.
+ EXPECT_FALSE(VarDie.find(DW_AT_name));
+
+ // Make sure we can extract the name from the abstract origin die when using
+ // DWARFDie::findRecursively() since it should recurse through the
+ // DW_AT_abstract_origin DIE.
+ NameOpt = VarDie.findRecursively(DW_AT_name);
+ EXPECT_TRUE(NameOpt);
+ // Test the dwarf::toString() helper function.
+ StringOpt = toString(NameOpt);
+ EXPECT_TRUE(StringOpt);
+ EXPECT_EQ(AbsDieName, StringOpt.getValueOr(nullptr));
+}
+
+TEST(DWARFDebugInfo, TestDwarfToFunctions) {
+ // Test all of the dwarf::toXXX functions that take a
+ // Optional<DWARFFormValue> and extract the values from it.
+ DWARFFormValue FormVal;
+ uint64_t InvalidU64 = 0xBADBADBADBADBADB;
+ int64_t InvalidS64 = 0xBADBADBADBADBADB;
+ // First test that we don't get valid values back when using an optional with
+ // no value.
+ Optional<DWARFFormValue> FormValOpt;
+ EXPECT_FALSE(toString(FormValOpt).hasValue());
+ EXPECT_FALSE(toUnsigned(FormValOpt).hasValue());
+ EXPECT_FALSE(toReference(FormValOpt).hasValue());
+ EXPECT_FALSE(toSigned(FormValOpt).hasValue());
+ EXPECT_FALSE(toAddress(FormValOpt).hasValue());
+ EXPECT_FALSE(toSectionOffset(FormValOpt).hasValue());
+ EXPECT_FALSE(toBlock(FormValOpt).hasValue());
+ EXPECT_EQ(nullptr, toString(FormValOpt, nullptr));
+ EXPECT_EQ(InvalidU64, toUnsigned(FormValOpt, InvalidU64));
+ EXPECT_EQ(InvalidU64, toReference(FormValOpt, InvalidU64));
+ EXPECT_EQ(InvalidU64, toAddress(FormValOpt, InvalidU64));
+ EXPECT_EQ(InvalidU64, toSectionOffset(FormValOpt, InvalidU64));
+ EXPECT_EQ(InvalidS64, toSigned(FormValOpt, InvalidS64));
+
+ // Test successful and unsuccessful address decoding.
+ uint64_t Address = 0x100000000ULL;
+ FormVal.setForm(DW_FORM_addr);
+ FormVal.setUValue(Address);
+ FormValOpt = FormVal;
+
+ EXPECT_FALSE(toString(FormValOpt).hasValue());
+ EXPECT_FALSE(toUnsigned(FormValOpt).hasValue());
+ EXPECT_FALSE(toReference(FormValOpt).hasValue());
+ EXPECT_FALSE(toSigned(FormValOpt).hasValue());
+ EXPECT_TRUE(toAddress(FormValOpt).hasValue());
+ EXPECT_FALSE(toSectionOffset(FormValOpt).hasValue());
+ EXPECT_FALSE(toBlock(FormValOpt).hasValue());
+ EXPECT_EQ(nullptr, toString(FormValOpt, nullptr));
+ EXPECT_EQ(InvalidU64, toUnsigned(FormValOpt, InvalidU64));
+ EXPECT_EQ(InvalidU64, toReference(FormValOpt, InvalidU64));
+ EXPECT_EQ(Address, toAddress(FormValOpt, InvalidU64));
+ EXPECT_EQ(InvalidU64, toSectionOffset(FormValOpt, InvalidU64));
+ EXPECT_EQ(InvalidS64, toSigned(FormValOpt, InvalidU64));
+
+ // Test successful and unsuccessful unsigned constant decoding.
+ uint64_t UData8 = 0x1020304050607080ULL;
+ FormVal.setForm(DW_FORM_udata);
+ FormVal.setUValue(UData8);
+ FormValOpt = FormVal;
+
+ EXPECT_FALSE(toString(FormValOpt).hasValue());
+ EXPECT_TRUE(toUnsigned(FormValOpt).hasValue());
+ EXPECT_FALSE(toReference(FormValOpt).hasValue());
+ EXPECT_TRUE(toSigned(FormValOpt).hasValue());
+ EXPECT_FALSE(toAddress(FormValOpt).hasValue());
+ EXPECT_FALSE(toSectionOffset(FormValOpt).hasValue());
+ EXPECT_FALSE(toBlock(FormValOpt).hasValue());
+ EXPECT_EQ(nullptr, toString(FormValOpt, nullptr));
+ EXPECT_EQ(UData8, toUnsigned(FormValOpt, InvalidU64));
+ EXPECT_EQ(InvalidU64, toReference(FormValOpt, InvalidU64));
+ EXPECT_EQ(InvalidU64, toAddress(FormValOpt, InvalidU64));
+ EXPECT_EQ(InvalidU64, toSectionOffset(FormValOpt, InvalidU64));
+ EXPECT_EQ((int64_t)UData8, toSigned(FormValOpt, InvalidU64));
+
+ // Test successful and unsuccessful reference decoding.
+ uint32_t RefData = 0x11223344U;
+ FormVal.setForm(DW_FORM_ref_addr);
+ FormVal.setUValue(RefData);
+ FormValOpt = FormVal;
+
+ EXPECT_FALSE(toString(FormValOpt).hasValue());
+ EXPECT_FALSE(toUnsigned(FormValOpt).hasValue());
+ EXPECT_TRUE(toReference(FormValOpt).hasValue());
+ EXPECT_FALSE(toSigned(FormValOpt).hasValue());
+ EXPECT_FALSE(toAddress(FormValOpt).hasValue());
+ EXPECT_FALSE(toSectionOffset(FormValOpt).hasValue());
+ EXPECT_FALSE(toBlock(FormValOpt).hasValue());
+ EXPECT_EQ(nullptr, toString(FormValOpt, nullptr));
+ EXPECT_EQ(InvalidU64, toUnsigned(FormValOpt, InvalidU64));
+ EXPECT_EQ(RefData, toReference(FormValOpt, InvalidU64));
+ EXPECT_EQ(InvalidU64, toAddress(FormValOpt, InvalidU64));
+ EXPECT_EQ(InvalidU64, toSectionOffset(FormValOpt, InvalidU64));
+ EXPECT_EQ(InvalidS64, toSigned(FormValOpt, InvalidU64));
+
+ // Test successful and unsuccessful signed constant decoding.
+ int64_t SData8 = 0x1020304050607080ULL;
+ FormVal.setForm(DW_FORM_udata);
+ FormVal.setSValue(SData8);
+ FormValOpt = FormVal;
+
+ EXPECT_FALSE(toString(FormValOpt).hasValue());
+ EXPECT_TRUE(toUnsigned(FormValOpt).hasValue());
+ EXPECT_FALSE(toReference(FormValOpt).hasValue());
+ EXPECT_TRUE(toSigned(FormValOpt).hasValue());
+ EXPECT_FALSE(toAddress(FormValOpt).hasValue());
+ EXPECT_FALSE(toSectionOffset(FormValOpt).hasValue());
+ EXPECT_FALSE(toBlock(FormValOpt).hasValue());
+ EXPECT_EQ(nullptr, toString(FormValOpt, nullptr));
+ EXPECT_EQ((uint64_t)SData8, toUnsigned(FormValOpt, InvalidU64));
+ EXPECT_EQ(InvalidU64, toReference(FormValOpt, InvalidU64));
+ EXPECT_EQ(InvalidU64, toAddress(FormValOpt, InvalidU64));
+ EXPECT_EQ(InvalidU64, toSectionOffset(FormValOpt, InvalidU64));
+ EXPECT_EQ(SData8, toSigned(FormValOpt, InvalidU64));
+
+ // Test successful and unsuccessful block decoding.
+ uint8_t Data[] = { 2, 3, 4 };
+ ArrayRef<uint8_t> Array(Data);
+ FormVal.setForm(DW_FORM_block1);
+ FormVal.setBlockValue(Array);
+ FormValOpt = FormVal;
+
+ EXPECT_FALSE(toString(FormValOpt).hasValue());
+ EXPECT_FALSE(toUnsigned(FormValOpt).hasValue());
+ EXPECT_FALSE(toReference(FormValOpt).hasValue());
+ EXPECT_FALSE(toSigned(FormValOpt).hasValue());
+ EXPECT_FALSE(toAddress(FormValOpt).hasValue());
+ EXPECT_FALSE(toSectionOffset(FormValOpt).hasValue());
+ auto BlockOpt = toBlock(FormValOpt);
+ EXPECT_TRUE(BlockOpt.hasValue());
+ EXPECT_EQ(*BlockOpt, Array);
+ EXPECT_EQ(nullptr, toString(FormValOpt, nullptr));
+ EXPECT_EQ(InvalidU64, toUnsigned(FormValOpt, InvalidU64));
+ EXPECT_EQ(InvalidU64, toReference(FormValOpt, InvalidU64));
+ EXPECT_EQ(InvalidU64, toAddress(FormValOpt, InvalidU64));
+ EXPECT_EQ(InvalidU64, toSectionOffset(FormValOpt, InvalidU64));
+ EXPECT_EQ(InvalidS64, toSigned(FormValOpt, InvalidU64));
+
+ // Test
+}
+
+TEST(DWARFDebugInfo, TestFindAttrs) {
+ // Test the DWARFDie::find() and DWARFDie::findRecursively() that take an
+ // ArrayRef<dwarf::Attribute> value to make sure they work correctly.
+ uint16_t Version = 4;
+
+ const uint8_t AddrSize = sizeof(void *);
+ initLLVMIfNeeded();
+ Triple Triple = getHostTripleForAddrSize(AddrSize);
+ auto ExpectedDG = dwarfgen::Generator::create(Triple, Version);
+ if (HandleExpectedError(ExpectedDG))
+ return;
+ dwarfgen::Generator *DG = ExpectedDG.get().get();
+ dwarfgen::CompileUnit &CU = DG->addCompileUnit();
+
+ StringRef DieMangled("_Z3fooi");
+ // Scope to allow us to re-use the same DIE names
+ {
+ auto CUDie = CU.getUnitDIE();
+ auto FuncSpecDie = CUDie.addChild(DW_TAG_subprogram);
+ auto FuncDie = CUDie.addChild(DW_TAG_subprogram);
+ FuncSpecDie.addAttribute(DW_AT_MIPS_linkage_name, DW_FORM_strp, DieMangled);
+ FuncDie.addAttribute(DW_AT_specification, DW_FORM_ref4, FuncSpecDie);
+ }
+
+ MemoryBufferRef FileBuffer(DG->generate(), "dwarf");
+ auto Obj = object::ObjectFile::createObjectFile(FileBuffer);
+ EXPECT_TRUE((bool)Obj);
+ DWARFContextInMemory DwarfContext(*Obj.get());
+
+ // Verify the number of compile units is correct.
+ uint32_t NumCUs = DwarfContext.getNumCompileUnits();
+ EXPECT_EQ(NumCUs, 1u);
+ DWARFCompileUnit *U = DwarfContext.getCompileUnitAtIndex(0);
+
+ // Get the compile unit DIE is valid.
+ auto CUDie = U->getUnitDIE(false);
+ EXPECT_TRUE(CUDie.isValid());
+
+ auto FuncSpecDie = CUDie.getFirstChild();
+ auto FuncDie = FuncSpecDie.getSibling();
+
+ // Make sure that passing in an empty attribute list behave correctly.
+ EXPECT_FALSE(FuncDie.find(ArrayRef<dwarf::Attribute>()).hasValue());
+
+ // Make sure that passing in a list of attribute that are not contained
+ // in the DIE returns nothing.
+ EXPECT_FALSE(FuncDie.find({DW_AT_low_pc, DW_AT_entry_pc}).hasValue());
+
+ const dwarf::Attribute Attrs[] = {DW_AT_linkage_name,
+ DW_AT_MIPS_linkage_name};
+
+ // Make sure we can't extract the linkage name attributes when using
+ // DWARFDie::find() since it won't check the DW_AT_specification DIE.
+ EXPECT_FALSE(FuncDie.find(Attrs).hasValue());
+
+ // Make sure we can extract the name from the specification die when using
+ // DWARFDie::findRecursively() since it should recurse through the
+ // DW_AT_specification DIE.
+ auto NameOpt = FuncDie.findRecursively(Attrs);
+ EXPECT_TRUE(NameOpt.hasValue());
+ EXPECT_EQ(DieMangled, toString(NameOpt, ""));
+}
+
+TEST(DWARFDebugInfo, TestImplicitConstAbbrevs) {
+ uint16_t Version = 5;
+
+ const uint8_t AddrSize = sizeof(void *);
+ initLLVMIfNeeded();
+ Triple Triple = getHostTripleForAddrSize(AddrSize);
+ auto ExpectedDG = dwarfgen::Generator::create(Triple, Version);
+ if (HandleExpectedError(ExpectedDG))
+ return;
+ dwarfgen::Generator *DG = ExpectedDG.get().get();
+ dwarfgen::CompileUnit &CU = DG->addCompileUnit();
+ dwarfgen::DIE CUDie = CU.getUnitDIE();
+ const dwarf::Attribute Attr = DW_AT_lo_user;
+ const int64_t Val1 = 42;
+ const int64_t Val2 = 43;
+
+ auto FirstVal1DIE = CUDie.addChild(DW_TAG_class_type);
+ FirstVal1DIE.addAttribute(Attr, DW_FORM_implicit_const, Val1);
+
+ auto SecondVal1DIE = CUDie.addChild(DW_TAG_class_type);
+ SecondVal1DIE.addAttribute(Attr, DW_FORM_implicit_const, Val1);
+
+ auto Val2DIE = CUDie.addChild(DW_TAG_class_type);
+ Val2DIE.addAttribute(Attr, DW_FORM_implicit_const, Val2);
+
+ MemoryBufferRef FileBuffer(DG->generate(), "dwarf");
+ auto Obj = object::ObjectFile::createObjectFile(FileBuffer);
+ EXPECT_TRUE((bool)Obj);
+ DWARFContextInMemory DwarfContext(*Obj.get());
+ DWARFCompileUnit *U = DwarfContext.getCompileUnitAtIndex(0);
+ EXPECT_TRUE((bool)U);
+
+ const auto *Abbrevs = U->getAbbreviations();
+ EXPECT_TRUE((bool)Abbrevs);
+
+ // Let's find implicit_const abbrevs and verify,
+ // that there are exactly two of them and both of them
+ // can be dumped correctly.
+ typedef decltype(Abbrevs->begin()) AbbrevIt;
+ AbbrevIt Val1Abbrev = Abbrevs->end();
+ AbbrevIt Val2Abbrev = Abbrevs->end();
+ for(auto it = Abbrevs->begin(); it != Abbrevs->end(); ++it) {
+ if (it->getNumAttributes() == 0)
+ continue; // root abbrev for DW_TAG_compile_unit
+
+ auto A = it->getAttrByIndex(0);
+ EXPECT_EQ(A, Attr);
+
+ auto FormValue = it->getAttributeValue(/* offset */ 0, A, *U);
+ EXPECT_TRUE((bool)FormValue);
+ EXPECT_EQ(FormValue->getForm(), dwarf::DW_FORM_implicit_const);
+
+ const auto V = FormValue->getAsSignedConstant();
+ EXPECT_TRUE((bool)V);
+
+ auto VerifyAbbrevDump = [&V](AbbrevIt it) {
+ std::string S;
+ llvm::raw_string_ostream OS(S);
+ it->dump(OS);
+ auto FormPos = OS.str().find("DW_FORM_implicit_const");
+ EXPECT_NE(FormPos, std::string::npos);
+ auto ValPos = S.find_first_of("-0123456789", FormPos);
+ EXPECT_NE(ValPos, std::string::npos);
+ int64_t Val = std::atoll(S.substr(ValPos).c_str());
+ EXPECT_EQ(Val, *V);
+ };
+
+ switch(*V) {
+ case Val1:
+ EXPECT_EQ(Val1Abbrev, Abbrevs->end());
+ Val1Abbrev = it;
+ VerifyAbbrevDump(it);
+ break;
+ case Val2:
+ EXPECT_EQ(Val2Abbrev, Abbrevs->end());
+ Val2Abbrev = it;
+ VerifyAbbrevDump(it);
+ break;
+ default:
+ FAIL() << "Unexpected attribute value: " << *V;
+ }
+ }
+
+ // Now let's make sure that two Val1-DIEs refer to the same abbrev,
+ // and Val2-DIE refers to another one.
+ auto DieDG = U->getUnitDIE(false);
+ auto it = DieDG.begin();
+ std::multimap<int64_t, decltype(it->getAbbreviationDeclarationPtr())> DIEs;
+ const DWARFAbbreviationDeclaration *AbbrevPtrVal1 = nullptr;
+ const DWARFAbbreviationDeclaration *AbbrevPtrVal2 = nullptr;
+ for (; it != DieDG.end(); ++it) {
+ const auto *AbbrevPtr = it->getAbbreviationDeclarationPtr();
+ EXPECT_TRUE((bool)AbbrevPtr);
+ auto FormValue = it->find(Attr);
+ EXPECT_TRUE((bool)FormValue);
+ const auto V = FormValue->getAsSignedConstant();
+ EXPECT_TRUE((bool)V);
+ switch(*V) {
+ case Val1:
+ AbbrevPtrVal1 = AbbrevPtr;
+ break;
+ case Val2:
+ AbbrevPtrVal2 = AbbrevPtr;
+ break;
+ default:
+ FAIL() << "Unexpected attribute value: " << *V;
+ }
+ DIEs.insert(std::make_pair(*V, AbbrevPtr));
+ }
+ EXPECT_EQ(DIEs.count(Val1), 2u);
+ EXPECT_EQ(DIEs.count(Val2), 1u);
+ auto Val1Range = DIEs.equal_range(Val1);
+ for (auto it = Val1Range.first; it != Val1Range.second; ++it)
+ EXPECT_EQ(it->second, AbbrevPtrVal1);
+ EXPECT_EQ(DIEs.find(Val2)->second, AbbrevPtrVal2);
}
} // end anonymous namespace
diff --git a/unittests/DebugInfo/DWARF/DwarfGenerator.cpp b/unittests/DebugInfo/DWARF/DwarfGenerator.cpp
index 9ec43cab4dc09..ac63bbaf0a11b 100644
--- a/unittests/DebugInfo/DWARF/DwarfGenerator.cpp
+++ b/unittests/DebugInfo/DWARF/DwarfGenerator.cpp
@@ -108,10 +108,6 @@ dwarfgen::DIE dwarfgen::CompileUnit::getUnitDIE() {
return dwarfgen::DIE(this, &DU.getUnitDie());
}
-void dwarfgen::DIE::setForceChildren() {
- Die->setForceChildren(true);
-}
-
//===----------------------------------------------------------------------===//
/// dwarfgen::Generator implementation.
//===----------------------------------------------------------------------===//
@@ -240,8 +236,14 @@ StringRef dwarfgen::Generator::generate() {
assert(Length != -1U);
Asm->EmitInt32(Length);
Asm->EmitInt16(Version);
- Asm->EmitInt32(0);
- Asm->EmitInt8(CU->getAddressSize());
+ if (Version <= 4) {
+ Asm->EmitInt32(0);
+ Asm->EmitInt8(CU->getAddressSize());
+ } else {
+ Asm->EmitInt8(dwarf::DW_UT_compile);
+ Asm->EmitInt8(CU->getAddressSize());
+ Asm->EmitInt32(0);
+ }
Asm->emitDwarfDIE(*CU->getUnitDIE().Die);
}
diff --git a/unittests/DebugInfo/DWARF/DwarfGenerator.h b/unittests/DebugInfo/DWARF/DwarfGenerator.h
index 2978d1ca0021e..966725b4fa4e7 100644
--- a/unittests/DebugInfo/DWARF/DwarfGenerator.h
+++ b/unittests/DebugInfo/DWARF/DwarfGenerator.h
@@ -129,9 +129,6 @@ public:
/// \returns the newly created DIE object that is now a child owned by this
/// object.
dwarfgen::DIE addChild(dwarf::Tag Tag);
-
- /// Force a DIE to say it has children even when it doesn't.
- void setForceChildren();
};
/// A DWARF compile unit used to generate DWARF compile/type units.
diff --git a/unittests/DebugInfo/PDB/CMakeLists.txt b/unittests/DebugInfo/PDB/CMakeLists.txt
index 406b487e7a189..cbbbd81774837 100644
--- a/unittests/DebugInfo/PDB/CMakeLists.txt
+++ b/unittests/DebugInfo/PDB/CMakeLists.txt
@@ -5,9 +5,12 @@ set(LLVM_LINK_COMPONENTS
)
set(DebugInfoPDBSources
+ HashTableTest.cpp
MappedBlockStreamTest.cpp
+ StringTableBuilderTest.cpp
MSFBuilderTest.cpp
PDBApiTest.cpp
+ TypeServerHandlerTest.cpp
)
add_llvm_unittest(DebugInfoPDBTests
diff --git a/unittests/DebugInfo/PDB/HashTableTest.cpp b/unittests/DebugInfo/PDB/HashTableTest.cpp
new file mode 100644
index 0000000000000..94c9ee86c4a63
--- /dev/null
+++ b/unittests/DebugInfo/PDB/HashTableTest.cpp
@@ -0,0 +1,168 @@
+//===- llvm/unittest/DebugInfo/PDB/HashTableTest.cpp ----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ErrorChecking.h"
+#include "gtest/gtest.h"
+
+#include "llvm/DebugInfo/PDB/Native/HashTable.h"
+#include "llvm/Support/BinaryByteStream.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/BinaryStreamWriter.h"
+
+#include <vector>
+
+using namespace llvm;
+using namespace llvm::pdb;
+using namespace llvm::support;
+
+namespace {
+class HashTableInternals : public HashTable {
+public:
+ using HashTable::Buckets;
+ using HashTable::Present;
+ using HashTable::Deleted;
+};
+}
+
+TEST(HashTableTest, TestSimple) {
+ HashTable Table;
+ EXPECT_EQ(0u, Table.size());
+ EXPECT_GT(Table.capacity(), 0u);
+
+ Table.set(3, 7);
+ EXPECT_EQ(1u, Table.size());
+ ASSERT_NE(Table.end(), Table.find(3));
+ EXPECT_EQ(7u, Table.get(3));
+}
+
+TEST(HashTableTest, TestCollision) {
+ HashTable Table;
+ EXPECT_EQ(0u, Table.size());
+ EXPECT_GT(Table.capacity(), 0u);
+
+ // We use knowledge of the hash table's implementation details to make sure
+ // to add another value that is the equivalent to the first value modulo the
+ // hash table's capacity.
+ uint32_t N1 = Table.capacity() + 1;
+ uint32_t N2 = 2 * N1;
+
+ Table.set(N1, 7);
+ Table.set(N2, 12);
+ EXPECT_EQ(2u, Table.size());
+ ASSERT_NE(Table.end(), Table.find(N1));
+ ASSERT_NE(Table.end(), Table.find(N2));
+
+ EXPECT_EQ(7u, Table.get(N1));
+ EXPECT_EQ(12u, Table.get(N2));
+}
+
+TEST(HashTableTest, TestRemove) {
+ HashTable Table;
+ EXPECT_EQ(0u, Table.size());
+ EXPECT_GT(Table.capacity(), 0u);
+
+ Table.set(1, 2);
+ Table.set(3, 4);
+ EXPECT_EQ(2u, Table.size());
+ ASSERT_NE(Table.end(), Table.find(1));
+ ASSERT_NE(Table.end(), Table.find(3));
+
+ EXPECT_EQ(2u, Table.get(1));
+ EXPECT_EQ(4u, Table.get(3));
+
+ Table.remove(1u);
+ EXPECT_EQ(1u, Table.size());
+ EXPECT_EQ(Table.end(), Table.find(1));
+ ASSERT_NE(Table.end(), Table.find(3));
+ EXPECT_EQ(4u, Table.get(3));
+}
+
+TEST(HashTableTest, TestCollisionAfterMultipleProbes) {
+ HashTable Table;
+ EXPECT_EQ(0u, Table.size());
+ EXPECT_GT(Table.capacity(), 0u);
+
+ // Probing looks for the first available slot. A slot may already be filled
+ // as a result of an item with a *different* hash value already being there.
+ // Test that when this happens, the probe still finds the value.
+ uint32_t N1 = Table.capacity() + 1;
+ uint32_t N2 = N1 + 1;
+ uint32_t N3 = 2 * N1;
+
+ Table.set(N1, 7);
+ Table.set(N2, 11);
+ Table.set(N3, 13);
+ EXPECT_EQ(3u, Table.size());
+ ASSERT_NE(Table.end(), Table.find(N1));
+ ASSERT_NE(Table.end(), Table.find(N2));
+ ASSERT_NE(Table.end(), Table.find(N3));
+
+ EXPECT_EQ(7u, Table.get(N1));
+ EXPECT_EQ(11u, Table.get(N2));
+ EXPECT_EQ(13u, Table.get(N3));
+
+ // Remove the one that had been filled in the middle, then insert another one
+ // with a collision. It should fill the newly emptied slot.
+ Table.remove(N2);
+ uint32_t N4 = N1 * 3;
+ Table.set(N4, 17);
+ EXPECT_EQ(3u, Table.size());
+ ASSERT_NE(Table.end(), Table.find(N1));
+ ASSERT_NE(Table.end(), Table.find(N3));
+ ASSERT_NE(Table.end(), Table.find(N4));
+
+ EXPECT_EQ(7u, Table.get(N1));
+ EXPECT_EQ(13u, Table.get(N3));
+ EXPECT_EQ(17u, Table.get(N4));
+}
+
+TEST(HashTableTest, Grow) {
+ // So that we are independent of the load factor, `capacity` items, which is
+ // guaranteed to trigger a grow. Then verify that the size is the same, the
+ // capacity is larger, and all the original items are still in the table.
+
+ HashTable Table;
+ uint32_t OldCapacity = Table.capacity();
+ for (uint32_t I = 0; I < OldCapacity; ++I) {
+ Table.set(OldCapacity + I * 2 + 1, I * 2 + 3);
+ }
+ EXPECT_EQ(OldCapacity, Table.size());
+ EXPECT_GT(Table.capacity(), OldCapacity);
+ for (uint32_t I = 0; I < OldCapacity; ++I) {
+ ASSERT_NE(Table.end(), Table.find(OldCapacity + I * 2 + 1));
+ EXPECT_EQ(I * 2 + 3, Table.get(OldCapacity + I * 2 + 1));
+ }
+}
+
+TEST(HashTableTest, Serialization) {
+ HashTableInternals Table;
+ uint32_t Cap = Table.capacity();
+ for (uint32_t I = 0; I < Cap; ++I) {
+ Table.set(Cap + I * 2 + 1, I * 2 + 3);
+ }
+
+ std::vector<uint8_t> Buffer(Table.calculateSerializedLength());
+ MutableBinaryByteStream Stream(Buffer, little);
+ BinaryStreamWriter Writer(Stream);
+ EXPECT_NO_ERROR(Table.commit(Writer));
+ // We should have written precisely the number of bytes we calculated earlier.
+ EXPECT_EQ(Buffer.size(), Writer.getOffset());
+
+ HashTableInternals Table2;
+ BinaryStreamReader Reader(Stream);
+ EXPECT_NO_ERROR(Table2.load(Reader));
+ // We should have read precisely the number of bytes we calculated earlier.
+ EXPECT_EQ(Buffer.size(), Reader.getOffset());
+
+ EXPECT_EQ(Table.size(), Table2.size());
+ EXPECT_EQ(Table.capacity(), Table2.capacity());
+ EXPECT_EQ(Table.Buckets, Table2.Buckets);
+ EXPECT_EQ(Table.Present, Table2.Present);
+ EXPECT_EQ(Table.Deleted, Table2.Deleted);
+}
diff --git a/unittests/DebugInfo/PDB/MappedBlockStreamTest.cpp b/unittests/DebugInfo/PDB/MappedBlockStreamTest.cpp
index 07591ca69d308..9f8940b77f28d 100644
--- a/unittests/DebugInfo/PDB/MappedBlockStreamTest.cpp
+++ b/unittests/DebugInfo/PDB/MappedBlockStreamTest.cpp
@@ -9,26 +9,28 @@
#include "ErrorChecking.h"
-#include "llvm/DebugInfo/MSF/ByteStream.h"
#include "llvm/DebugInfo/MSF/IMSFFile.h"
-#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
+#include "llvm/DebugInfo/MSF/MSFError.h"
#include "llvm/DebugInfo/MSF/MSFStreamLayout.h"
-#include "llvm/DebugInfo/MSF/StreamReader.h"
-#include "llvm/DebugInfo/MSF/StreamRef.h"
-#include "llvm/DebugInfo/MSF/StreamWriter.h"
+#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
+#include "llvm/Support/BinaryByteStream.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/BinaryStreamRef.h"
+#include "llvm/Support/BinaryStreamWriter.h"
#include "gtest/gtest.h"
#include <unordered_map>
using namespace llvm;
using namespace llvm::msf;
+using namespace llvm::support;
namespace {
static const uint32_t BlocksAry[] = {0, 1, 2, 5, 4, 3, 6, 7, 8, 9};
static uint8_t DataAry[] = {'A', 'B', 'C', 'F', 'E', 'D', 'G', 'H', 'I', 'J'};
-class DiscontiguousStream : public WritableStream {
+class DiscontiguousStream : public WritableBinaryStream {
public:
DiscontiguousStream(ArrayRef<uint32_t> Blocks, MutableArrayRef<uint8_t> Data)
: Blocks(Blocks.begin(), Blocks.end()), Data(Data.begin(), Data.end()) {}
@@ -36,31 +38,33 @@ public:
uint32_t block_size() const { return 1; }
uint32_t block_count() const { return Blocks.size(); }
+ endianness getEndian() const override { return little; }
+
Error readBytes(uint32_t Offset, uint32_t Size,
- ArrayRef<uint8_t> &Buffer) const override {
- if (Offset + Size > Data.size())
- return make_error<MSFError>(msf_error_code::insufficient_buffer);
+ ArrayRef<uint8_t> &Buffer) override {
+ if (auto EC = checkOffset(Offset, Size))
+ return EC;
Buffer = Data.slice(Offset, Size);
return Error::success();
}
Error readLongestContiguousChunk(uint32_t Offset,
- ArrayRef<uint8_t> &Buffer) const override {
- if (Offset >= Data.size())
- return make_error<MSFError>(msf_error_code::insufficient_buffer);
+ ArrayRef<uint8_t> &Buffer) override {
+ if (auto EC = checkOffset(Offset, 1))
+ return EC;
Buffer = Data.drop_front(Offset);
return Error::success();
}
- uint32_t getLength() const override { return Data.size(); }
+ uint32_t getLength() override { return Data.size(); }
- Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> SrcData) const override {
- if (Offset + SrcData.size() > Data.size())
- return make_error<MSFError>(msf_error_code::insufficient_buffer);
+ Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> SrcData) override {
+ if (auto EC = checkOffset(Offset, SrcData.size()))
+ return EC;
::memcpy(&Data[Offset], SrcData.data(), SrcData.size());
return Error::success();
}
- Error commit() const override { return Error::success(); }
+ Error commit() override { return Error::success(); }
MSFStreamLayout layout() const {
return MSFStreamLayout{static_cast<uint32_t>(Data.size()), Blocks};
@@ -78,8 +82,8 @@ TEST(MappedBlockStreamTest, ReadBeyondEndOfStreamRef) {
auto S = MappedBlockStream::createStream(F.block_size(), F.block_count(),
F.layout(), F);
- StreamReader R(*S);
- ReadableStreamRef SR;
+ BinaryStreamReader R(*S);
+ BinaryStreamRef SR;
EXPECT_NO_ERROR(R.readStreamRef(SR, 0U));
ArrayRef<uint8_t> Buffer;
EXPECT_ERROR(SR.readBytes(0U, 1U, Buffer));
@@ -94,7 +98,7 @@ TEST(MappedBlockStreamTest, ReadOntoNonEmptyBuffer) {
auto S = MappedBlockStream::createStream(F.block_size(), F.block_count(),
F.layout(), F);
- StreamReader R(*S);
+ BinaryStreamReader R(*S);
StringRef Str = "ZYXWVUTSRQPONMLKJIHGFEDCBA";
EXPECT_NO_ERROR(R.readFixedString(Str, 1));
EXPECT_EQ(Str, StringRef("A"));
@@ -108,7 +112,7 @@ TEST(MappedBlockStreamTest, ZeroCopyReadContiguousBreak) {
DiscontiguousStream F(BlocksAry, DataAry);
auto S = MappedBlockStream::createStream(F.block_size(), F.block_count(),
F.layout(), F);
- StreamReader R(*S);
+ BinaryStreamReader R(*S);
StringRef Str;
EXPECT_NO_ERROR(R.readFixedString(Str, 2));
EXPECT_EQ(Str, StringRef("AB"));
@@ -127,7 +131,7 @@ TEST(MappedBlockStreamTest, CopyReadNonContiguousBreak) {
DiscontiguousStream F(BlocksAry, DataAry);
auto S = MappedBlockStream::createStream(F.block_size(), F.block_count(),
F.layout(), F);
- StreamReader R(*S);
+ BinaryStreamReader R(*S);
StringRef Str;
EXPECT_NO_ERROR(R.readFixedString(Str, 10));
EXPECT_EQ(Str, StringRef("ABCDEFGHIJ"));
@@ -140,7 +144,7 @@ TEST(MappedBlockStreamTest, InvalidReadSizeNoBreak) {
DiscontiguousStream F(BlocksAry, DataAry);
auto S = MappedBlockStream::createStream(F.block_size(), F.block_count(),
F.layout(), F);
- StreamReader R(*S);
+ BinaryStreamReader R(*S);
StringRef Str;
R.setOffset(10);
@@ -154,7 +158,7 @@ TEST(MappedBlockStreamTest, InvalidReadSizeContiguousBreak) {
DiscontiguousStream F(BlocksAry, DataAry);
auto S = MappedBlockStream::createStream(F.block_size(), F.block_count(),
F.layout(), F);
- StreamReader R(*S);
+ BinaryStreamReader R(*S);
StringRef Str;
R.setOffset(6);
@@ -168,7 +172,7 @@ TEST(MappedBlockStreamTest, InvalidReadSizeNonContiguousBreak) {
DiscontiguousStream F(BlocksAry, DataAry);
auto S = MappedBlockStream::createStream(F.block_size(), F.block_count(),
F.layout(), F);
- StreamReader R(*S);
+ BinaryStreamReader R(*S);
StringRef Str;
EXPECT_ERROR(R.readFixedString(Str, 11));
@@ -181,7 +185,7 @@ TEST(MappedBlockStreamTest, ZeroCopyReadNoBreak) {
DiscontiguousStream F(BlocksAry, DataAry);
auto S = MappedBlockStream::createStream(F.block_size(), F.block_count(),
F.layout(), F);
- StreamReader R(*S);
+ BinaryStreamReader R(*S);
StringRef Str;
EXPECT_NO_ERROR(R.readFixedString(Str, 1));
EXPECT_EQ(Str, StringRef("A"));
@@ -195,7 +199,7 @@ TEST(MappedBlockStreamTest, UnalignedOverlappingRead) {
DiscontiguousStream F(BlocksAry, DataAry);
auto S = MappedBlockStream::createStream(F.block_size(), F.block_count(),
F.layout(), F);
- StreamReader R(*S);
+ BinaryStreamReader R(*S);
StringRef Str1;
StringRef Str2;
EXPECT_NO_ERROR(R.readFixedString(Str1, 7));
@@ -216,7 +220,7 @@ TEST(MappedBlockStreamTest, UnalignedOverlappingReadFail) {
DiscontiguousStream F(BlocksAry, DataAry);
auto S = MappedBlockStream::createStream(F.block_size(), F.block_count(),
F.layout(), F);
- StreamReader R(*S);
+ BinaryStreamReader R(*S);
StringRef Str1;
StringRef Str2;
EXPECT_NO_ERROR(R.readFixedString(Str1, 6));
@@ -323,8 +327,8 @@ TEST(MappedBlockStreamTest, TestWriteThenRead) {
uint32_t intArr1[] = {890723408, 29082234};
ArrayRef<uint32_t> intArray[] = {intArr0, intArr1};
- StreamReader Reader(*S);
- StreamWriter Writer(*S);
+ BinaryStreamReader Reader(*S);
+ BinaryStreamWriter Writer(*S);
EXPECT_NO_ERROR(Writer.writeInteger(u16[0]));
EXPECT_NO_ERROR(Reader.readInteger(u16[1]));
EXPECT_EQ(u16[0], u16[1]);
@@ -352,8 +356,8 @@ TEST(MappedBlockStreamTest, TestWriteThenRead) {
Reader.setOffset(0);
Writer.setOffset(0);
::memset(DataBytes.data(), 0, 10);
- EXPECT_NO_ERROR(Writer.writeZeroString(ZStr[0]));
- EXPECT_NO_ERROR(Reader.readZeroString(ZStr[1]));
+ EXPECT_NO_ERROR(Writer.writeCString(ZStr[0]));
+ EXPECT_NO_ERROR(Reader.readCString(ZStr[1]));
EXPECT_EQ(ZStr[0], ZStr[1]);
EXPECT_EQ(
std::vector<uint8_t>({'r', 'e', 'Z', ' ', 'S', 't', 'o', 'r', 0, 0}),
@@ -399,22 +403,22 @@ TEST(MappedBlockStreamTest, TestWriteContiguousStreamRef) {
F.block_size(), F.block_count(), F.layout(), F);
// First write "Test Str" into the source stream.
- MutableByteStream SourceStream(SrcData);
- StreamWriter SourceWriter(SourceStream);
- EXPECT_NO_ERROR(SourceWriter.writeZeroString("Test Str"));
+ MutableBinaryByteStream SourceStream(SrcData, little);
+ BinaryStreamWriter SourceWriter(SourceStream);
+ EXPECT_NO_ERROR(SourceWriter.writeCString("Test Str"));
EXPECT_EQ(SrcDataBytes, std::vector<uint8_t>(
{'T', 'e', 's', 't', ' ', 'S', 't', 'r', 0, 0}));
// Then write the source stream into the dest stream.
- StreamWriter DestWriter(*DestStream);
+ BinaryStreamWriter DestWriter(*DestStream);
EXPECT_NO_ERROR(DestWriter.writeStreamRef(SourceStream));
EXPECT_EQ(DestDataBytes, std::vector<uint8_t>(
{'s', 'e', 'T', ' ', 'S', 't', 't', 'r', 0, 0}));
// Then read the string back out of the dest stream.
StringRef Result;
- StreamReader DestReader(*DestStream);
- EXPECT_NO_ERROR(DestReader.readZeroString(Result));
+ BinaryStreamReader DestReader(*DestStream);
+ EXPECT_NO_ERROR(DestReader.readCString(Result));
EXPECT_EQ(Result, "Test Str");
}
@@ -436,21 +440,21 @@ TEST(MappedBlockStreamTest, TestWriteDiscontiguousStreamRef) {
SrcF.block_size(), SrcF.block_count(), SrcF.layout(), SrcF);
// First write "Test Str" into the source stream.
- StreamWriter SourceWriter(*Src);
- EXPECT_NO_ERROR(SourceWriter.writeZeroString("Test Str"));
+ BinaryStreamWriter SourceWriter(*Src);
+ EXPECT_NO_ERROR(SourceWriter.writeCString("Test Str"));
EXPECT_EQ(SrcDataBytes, std::vector<uint8_t>(
{'e', 'T', 't', 't', ' ', 'S', 's', 'r', 0, 0}));
// Then write the source stream into the dest stream.
- StreamWriter DestWriter(*Dest);
+ BinaryStreamWriter DestWriter(*Dest);
EXPECT_NO_ERROR(DestWriter.writeStreamRef(*Src));
EXPECT_EQ(DestDataBytes, std::vector<uint8_t>(
{'s', 'e', 'T', ' ', 'S', 't', 't', 'r', 0, 0}));
// Then read the string back out of the dest stream.
StringRef Result;
- StreamReader DestReader(*Dest);
- EXPECT_NO_ERROR(DestReader.readZeroString(Result));
+ BinaryStreamReader DestReader(*Dest);
+ EXPECT_NO_ERROR(DestReader.readCString(Result));
EXPECT_EQ(Result, "Test Str");
}
diff --git a/unittests/DebugInfo/PDB/PDBApiTest.cpp b/unittests/DebugInfo/PDB/PDBApiTest.cpp
index cd0f928a08ab5..6afe83cd90dd5 100644
--- a/unittests/DebugInfo/PDB/PDBApiTest.cpp
+++ b/unittests/DebugInfo/PDB/PDBApiTest.cpp
@@ -226,6 +226,7 @@ public:
MOCK_SYMBOL_ACCESSOR(getMachineType)
MOCK_SYMBOL_ACCESSOR(getThunkOrdinal)
MOCK_SYMBOL_ACCESSOR(getLength)
+ MOCK_SYMBOL_ACCESSOR(getVirtualBaseTableType)
MOCK_SYMBOL_ACCESSOR(getLiveRangeLength)
MOCK_SYMBOL_ACCESSOR(getVirtualAddress)
MOCK_SYMBOL_ACCESSOR(getUdtKind)
diff --git a/unittests/DebugInfo/PDB/StringTableBuilderTest.cpp b/unittests/DebugInfo/PDB/StringTableBuilderTest.cpp
new file mode 100644
index 0000000000000..7c4838778e43b
--- /dev/null
+++ b/unittests/DebugInfo/PDB/StringTableBuilderTest.cpp
@@ -0,0 +1,55 @@
+//===- StringTableBuilderTest.cpp -----------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ErrorChecking.h"
+
+#include "llvm/DebugInfo/PDB/Native/StringTable.h"
+#include "llvm/DebugInfo/PDB/Native/StringTableBuilder.h"
+#include "llvm/Support/BinaryByteStream.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/BinaryStreamWriter.h"
+
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+using namespace llvm::support;
+
+namespace {
+class StringTableBuilderTest : public ::testing::Test {};
+}
+
+TEST_F(StringTableBuilderTest, Simple) {
+ // Create /names table contents.
+ StringTableBuilder Builder;
+ EXPECT_EQ(1U, Builder.insert("foo"));
+ EXPECT_EQ(5U, Builder.insert("bar"));
+ EXPECT_EQ(1U, Builder.insert("foo"));
+ EXPECT_EQ(9U, Builder.insert("baz"));
+
+ std::vector<uint8_t> Buffer(Builder.finalize());
+ MutableBinaryByteStream OutStream(Buffer, little);
+ BinaryStreamWriter Writer(OutStream);
+ EXPECT_NO_ERROR(Builder.commit(Writer));
+
+ // Reads the contents back.
+ BinaryByteStream InStream(Buffer, little);
+ BinaryStreamReader Reader(InStream);
+ StringTable Table;
+ EXPECT_NO_ERROR(Table.load(Reader));
+
+ EXPECT_EQ(3U, Table.getNameCount());
+ EXPECT_EQ(1U, Table.getHashVersion());
+ EXPECT_EQ("foo", Table.getStringForID(1));
+ EXPECT_EQ("bar", Table.getStringForID(5));
+ EXPECT_EQ("baz", Table.getStringForID(9));
+ EXPECT_EQ(1U, Table.getIDForString("foo"));
+ EXPECT_EQ(5U, Table.getIDForString("bar"));
+ EXPECT_EQ(9U, Table.getIDForString("baz"));
+}
diff --git a/unittests/DebugInfo/PDB/TypeServerHandlerTest.cpp b/unittests/DebugInfo/PDB/TypeServerHandlerTest.cpp
new file mode 100644
index 0000000000000..6995e8f9dded2
--- /dev/null
+++ b/unittests/DebugInfo/PDB/TypeServerHandlerTest.cpp
@@ -0,0 +1,175 @@
+//===- llvm/unittest/DebugInfo/PDB/TypeServerHandlerTest.cpp --------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ErrorChecking.h"
+
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
+#include "llvm/DebugInfo/CodeView/TypeSerializer.h"
+#include "llvm/DebugInfo/CodeView/TypeServerHandler.h"
+#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
+#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
+#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
+#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Error.h"
+
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+namespace {
+
+constexpr uint8_t Guid[] = {0x2a, 0x2c, 0x1c, 0x2a, 0xcb, 0x9e, 0x48, 0x18,
+ 0x82, 0x82, 0x7a, 0x87, 0xc3, 0xfe, 0x16, 0xe8};
+StringRef GuidStr(reinterpret_cast<const char *>(Guid),
+ llvm::array_lengthof(Guid));
+
+constexpr const char *Name = "Test Name";
+constexpr int Age = 1;
+
+class MockTypeServerHandler : public TypeServerHandler {
+public:
+ explicit MockTypeServerHandler(bool HandleAlways)
+ : HandleAlways(HandleAlways) {}
+
+ Expected<bool> handle(TypeServer2Record &TS,
+ TypeVisitorCallbacks &Callbacks) override {
+ if (TS.Age != Age || TS.Guid != GuidStr || TS.Name != Name)
+ return make_error<CodeViewError>(cv_error_code::corrupt_record,
+ "Invalid TypeServer record!");
+
+ if (Handled && !HandleAlways)
+ return false;
+
+ Handled = true;
+ return true;
+ }
+
+ bool Handled = false;
+ bool HandleAlways;
+};
+
+class MockTypeVisitorCallbacks : public TypeVisitorCallbacks {
+public:
+ enum class State {
+ Ready,
+ VisitTypeBegin,
+ VisitKnownRecord,
+ VisitTypeEnd,
+ };
+ Error visitTypeBegin(CVType &CVT) override {
+ if (S != State::Ready)
+ return make_error<CodeViewError>(cv_error_code::unspecified,
+ "Invalid visitor state!");
+
+ S = State::VisitTypeBegin;
+ return Error::success();
+ }
+
+ Error visitKnownRecord(CVType &CVT, TypeServer2Record &TS) override {
+ if (S != State::VisitTypeBegin)
+ return make_error<CodeViewError>(cv_error_code::unspecified,
+ "Invalid visitor state!");
+
+ S = State::VisitKnownRecord;
+ return Error::success();
+ }
+
+ Error visitTypeEnd(CVType &CVT) override {
+ if (S != State::VisitKnownRecord)
+ return make_error<CodeViewError>(cv_error_code::unspecified,
+ "Invalid visitor state!");
+
+ S = State::VisitTypeEnd;
+ return Error::success();
+ }
+
+ State S = State::Ready;
+};
+
+class TypeServerHandlerTest : public testing::Test {
+public:
+ void SetUp() override {
+ TypeServer2Record R(TypeRecordKind::TypeServer2);
+ R.Age = Age;
+ R.Guid = GuidStr;
+ R.Name = Name;
+
+ TypeTableBuilder Builder(Allocator);
+ Builder.writeKnownType(R);
+ TypeServerRecord.RecordData = Builder.records().front();
+ TypeServerRecord.Type = TypeLeafKind::LF_TYPESERVER2;
+ }
+
+protected:
+ BumpPtrAllocator Allocator;
+ CVType TypeServerRecord;
+};
+
+// Test that when no type server handler is registered, it gets handled by the
+// normal
+// visitor callbacks.
+TEST_F(TypeServerHandlerTest, VisitRecordNoTypeServer) {
+ MockTypeVisitorCallbacks C2;
+ MockTypeVisitorCallbacks C1;
+ TypeVisitorCallbackPipeline Pipeline;
+
+ Pipeline.addCallbackToPipeline(C1);
+ Pipeline.addCallbackToPipeline(C2);
+ CVTypeVisitor Visitor(Pipeline);
+ EXPECT_NO_ERROR(Visitor.visitTypeRecord(TypeServerRecord));
+
+ EXPECT_EQ(MockTypeVisitorCallbacks::State::VisitTypeEnd, C1.S);
+ EXPECT_EQ(MockTypeVisitorCallbacks::State::VisitTypeEnd, C2.S);
+}
+
+// Test that when a TypeServerHandler is registered, it gets consumed by the
+// handler if and only if the handler returns true.
+TEST_F(TypeServerHandlerTest, VisitRecordWithTypeServerOnce) {
+ MockTypeServerHandler Handler(false);
+
+ MockTypeVisitorCallbacks C1;
+ CVTypeVisitor Visitor(C1);
+ Visitor.addTypeServerHandler(Handler);
+
+ // Our mock server returns true the first time.
+ EXPECT_NO_ERROR(Visitor.visitTypeRecord(TypeServerRecord));
+ EXPECT_TRUE(Handler.Handled);
+ EXPECT_EQ(MockTypeVisitorCallbacks::State::Ready, C1.S);
+
+ // And false the second time.
+ EXPECT_NO_ERROR(Visitor.visitTypeRecord(TypeServerRecord));
+ EXPECT_TRUE(Handler.Handled);
+ EXPECT_EQ(MockTypeVisitorCallbacks::State::VisitTypeEnd, C1.S);
+}
+
+// Test that when a type server handler is registered, if the handler keeps
+// returning true, it will keep getting consumed by the handler and not go
+// to the default processor.
+TEST_F(TypeServerHandlerTest, VisitRecordWithTypeServerAlways) {
+ MockTypeServerHandler Handler(true);
+
+ MockTypeVisitorCallbacks C1;
+ CVTypeVisitor Visitor(C1);
+ Visitor.addTypeServerHandler(Handler);
+
+ EXPECT_NO_ERROR(Visitor.visitTypeRecord(TypeServerRecord));
+ EXPECT_TRUE(Handler.Handled);
+ EXPECT_EQ(MockTypeVisitorCallbacks::State::Ready, C1.S);
+
+ EXPECT_NO_ERROR(Visitor.visitTypeRecord(TypeServerRecord));
+ EXPECT_TRUE(Handler.Handled);
+ EXPECT_EQ(MockTypeVisitorCallbacks::State::Ready, C1.S);
+}
+
+} // end anonymous namespace
diff --git a/unittests/ExecutionEngine/Orc/CMakeLists.txt b/unittests/ExecutionEngine/Orc/CMakeLists.txt
index 68f6d0c28d7ca..db40c4213bd70 100644
--- a/unittests/ExecutionEngine/Orc/CMakeLists.txt
+++ b/unittests/ExecutionEngine/Orc/CMakeLists.txt
@@ -14,11 +14,12 @@ add_llvm_unittest(OrcJITTests
IndirectionUtilsTest.cpp
GlobalMappingLayerTest.cpp
LazyEmittingLayerTest.cpp
- ObjectLinkingLayerTest.cpp
ObjectTransformLayerTest.cpp
OrcCAPITest.cpp
OrcTestCommon.cpp
+ QueueChannel.cpp
RPCUtilsTest.cpp
+ RTDyldObjectLinkingLayerTest.cpp
)
-target_link_libraries(OrcJITTests ${PTHREAD_LIB})
+target_link_libraries(OrcJITTests ${LLVM_PTHREAD_LIB})
diff --git a/unittests/ExecutionEngine/Orc/IndirectionUtilsTest.cpp b/unittests/ExecutionEngine/Orc/IndirectionUtilsTest.cpp
index ac847039d9fb2..4af3aa707a90e 100644
--- a/unittests/ExecutionEngine/Orc/IndirectionUtilsTest.cpp
+++ b/unittests/ExecutionEngine/Orc/IndirectionUtilsTest.cpp
@@ -20,17 +20,17 @@ TEST(IndirectionUtilsTest, MakeStub) {
LLVMContext Context;
ModuleBuilder MB(Context, "x86_64-apple-macosx10.10", "");
Function *F = MB.createFunctionDecl<void(DummyStruct, DummyStruct)>("");
- SmallVector<AttributeSet, 4> Attrs;
+ SmallVector<AttributeList, 4> Attrs;
Attrs.push_back(
- AttributeSet::get(MB.getModule()->getContext(), 1U,
- AttrBuilder().addAttribute(Attribute::StructRet)));
+ AttributeList::get(MB.getModule()->getContext(), 1U,
+ AttrBuilder().addAttribute(Attribute::StructRet)));
Attrs.push_back(
- AttributeSet::get(MB.getModule()->getContext(), 2U,
- AttrBuilder().addAttribute(Attribute::ByVal)));
+ AttributeList::get(MB.getModule()->getContext(), 2U,
+ AttrBuilder().addAttribute(Attribute::ByVal)));
Attrs.push_back(
- AttributeSet::get(MB.getModule()->getContext(), ~0U,
- AttrBuilder().addAttribute(Attribute::NoUnwind)));
- F->setAttributes(AttributeSet::get(MB.getModule()->getContext(), Attrs));
+ AttributeList::get(MB.getModule()->getContext(), ~0U,
+ AttrBuilder().addAttribute(Attribute::NoUnwind)));
+ F->setAttributes(AttributeList::get(MB.getModule()->getContext(), Attrs));
auto ImplPtr = orc::createImplPointer(*F->getType(), *MB.getModule(), "", nullptr);
orc::makeStub(*F, *ImplPtr);
@@ -42,7 +42,7 @@ TEST(IndirectionUtilsTest, MakeStub) {
EXPECT_TRUE(Call->isTailCall()) << "Indirect call from stub should be tail call.";
EXPECT_TRUE(Call->hasStructRetAttr())
<< "makeStub should propagate sret attr on 1st argument.";
- EXPECT_TRUE(Call->paramHasAttr(2U, Attribute::ByVal))
+ EXPECT_TRUE(Call->paramHasAttr(1U, Attribute::ByVal))
<< "makeStub should propagate byval attr on 2nd argument.";
}
diff --git a/unittests/ExecutionEngine/Orc/ObjectTransformLayerTest.cpp b/unittests/ExecutionEngine/Orc/ObjectTransformLayerTest.cpp
index 63b85dc82ca84..96214a368dce0 100644
--- a/unittests/ExecutionEngine/Orc/ObjectTransformLayerTest.cpp
+++ b/unittests/ExecutionEngine/Orc/ObjectTransformLayerTest.cpp
@@ -12,7 +12,7 @@
#include "llvm/ExecutionEngine/Orc/CompileUtils.h"
#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
#include "llvm/ExecutionEngine/Orc/NullResolver.h"
-#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
+#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
#include "llvm/ExecutionEngine/Orc/ObjectTransformLayer.h"
#include "llvm/Object/ObjectFile.h"
#include "gtest/gtest.h"
@@ -309,7 +309,7 @@ TEST(ObjectTransformLayerTest, Main) {
};
// Construct the jit layers.
- ObjectLinkingLayer<> BaseLayer;
+ RTDyldObjectLinkingLayer<> BaseLayer;
auto IdentityTransform = [](
std::unique_ptr<llvm::object::OwningBinary<llvm::object::ObjectFile>>
Obj) { return Obj; };
diff --git a/unittests/ExecutionEngine/Orc/OrcTestCommon.cpp b/unittests/ExecutionEngine/Orc/OrcTestCommon.cpp
index 17d1e9c9276e7..ccd2fc0fb1892 100644
--- a/unittests/ExecutionEngine/Orc/OrcTestCommon.cpp
+++ b/unittests/ExecutionEngine/Orc/OrcTestCommon.cpp
@@ -15,7 +15,7 @@
using namespace llvm;
-bool OrcExecutionTest::NativeTargetInitialized = false;
+bool OrcNativeTarget::NativeTargetInitialized = false;
ModuleBuilder::ModuleBuilder(LLVMContext &Context, StringRef Triple,
StringRef Name)
diff --git a/unittests/ExecutionEngine/Orc/OrcTestCommon.h b/unittests/ExecutionEngine/Orc/OrcTestCommon.h
index f3972a3084e51..7fb26634c7a7a 100644
--- a/unittests/ExecutionEngine/Orc/OrcTestCommon.h
+++ b/unittests/ExecutionEngine/Orc/OrcTestCommon.h
@@ -28,17 +28,29 @@
namespace llvm {
-// Base class for Orc tests that will execute code.
-class OrcExecutionTest {
+class OrcNativeTarget {
public:
-
- OrcExecutionTest() {
+ static void initialize() {
if (!NativeTargetInitialized) {
InitializeNativeTarget();
InitializeNativeTargetAsmParser();
InitializeNativeTargetAsmPrinter();
NativeTargetInitialized = true;
}
+ }
+
+private:
+ static bool NativeTargetInitialized;
+};
+
+// Base class for Orc tests that will execute code.
+class OrcExecutionTest {
+public:
+
+ OrcExecutionTest() {
+
+ // Initialize the native target if it hasn't been done already.
+ OrcNativeTarget::initialize();
// Try to select a TargetMachine for the host.
TM.reset(EngineBuilder().selectTarget());
@@ -56,8 +68,6 @@ public:
protected:
LLVMContext Context;
std::unique_ptr<TargetMachine> TM;
-private:
- static bool NativeTargetInitialized;
};
class ModuleBuilder {
diff --git a/unittests/ExecutionEngine/Orc/QueueChannel.cpp b/unittests/ExecutionEngine/Orc/QueueChannel.cpp
new file mode 100644
index 0000000000000..e309a7e428c04
--- /dev/null
+++ b/unittests/ExecutionEngine/Orc/QueueChannel.cpp
@@ -0,0 +1,14 @@
+//===-------- QueueChannel.cpp - Unit tests the remote executors ----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "QueueChannel.h"
+
+char llvm::QueueChannelError::ID;
+char llvm::QueueChannelClosedError::ID;
+
diff --git a/unittests/ExecutionEngine/Orc/QueueChannel.h b/unittests/ExecutionEngine/Orc/QueueChannel.h
new file mode 100644
index 0000000000000..3d1058a83ebc1
--- /dev/null
+++ b/unittests/ExecutionEngine/Orc/QueueChannel.h
@@ -0,0 +1,146 @@
+//===----------------------- Queue.h - RPC Queue ------------------*-c++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_UNITTESTS_EXECUTIONENGINE_ORC_QUEUECHANNEL_H
+#define LLVM_UNITTESTS_EXECUTIONENGINE_ORC_QUEUECHANNEL_H
+
+#include "llvm/ExecutionEngine/Orc/RawByteChannel.h"
+#include "llvm/Support/Error.h"
+
+#include <queue>
+#include <condition_variable>
+
+namespace llvm {
+
+class QueueChannelError : public ErrorInfo<QueueChannelError> {
+public:
+ static char ID;
+};
+
+class QueueChannelClosedError
+ : public ErrorInfo<QueueChannelClosedError, QueueChannelError> {
+public:
+ static char ID;
+ std::error_code convertToErrorCode() const override {
+ return inconvertibleErrorCode();
+ }
+
+ void log(raw_ostream &OS) const override {
+ OS << "Queue closed";
+ }
+};
+
+class Queue : public std::queue<char> {
+public:
+ using ErrorInjector = std::function<Error()>;
+
+ Queue()
+ : ReadError([]() { return Error::success(); }),
+ WriteError([]() { return Error::success(); }) {}
+
+ Queue(const Queue&) = delete;
+ Queue& operator=(const Queue&) = delete;
+ Queue(Queue&&) = delete;
+ Queue& operator=(Queue&&) = delete;
+
+ std::mutex &getMutex() { return M; }
+ std::condition_variable &getCondVar() { return CV; }
+ Error checkReadError() { return ReadError(); }
+ Error checkWriteError() { return WriteError(); }
+ void setReadError(ErrorInjector NewReadError) {
+ {
+ std::lock_guard<std::mutex> Lock(M);
+ ReadError = std::move(NewReadError);
+ }
+ CV.notify_one();
+ }
+ void setWriteError(ErrorInjector NewWriteError) {
+ std::lock_guard<std::mutex> Lock(M);
+ WriteError = std::move(NewWriteError);
+ }
+private:
+ std::mutex M;
+ std::condition_variable CV;
+ std::function<Error()> ReadError, WriteError;
+};
+
+class QueueChannel : public orc::rpc::RawByteChannel {
+public:
+ QueueChannel(std::shared_ptr<Queue> InQueue,
+ std::shared_ptr<Queue> OutQueue)
+ : InQueue(InQueue), OutQueue(OutQueue) {}
+
+ QueueChannel(const QueueChannel&) = delete;
+ QueueChannel& operator=(const QueueChannel&) = delete;
+ QueueChannel(QueueChannel&&) = delete;
+ QueueChannel& operator=(QueueChannel&&) = delete;
+
+ Error readBytes(char *Dst, unsigned Size) override {
+ std::unique_lock<std::mutex> Lock(InQueue->getMutex());
+ while (Size) {
+ {
+ Error Err = InQueue->checkReadError();
+ while (!Err && InQueue->empty()) {
+ InQueue->getCondVar().wait(Lock);
+ Err = InQueue->checkReadError();
+ }
+ if (Err)
+ return Err;
+ }
+ *Dst++ = InQueue->front();
+ --Size;
+ ++NumRead;
+ InQueue->pop();
+ }
+ return Error::success();
+ }
+
+ Error appendBytes(const char *Src, unsigned Size) override {
+ std::unique_lock<std::mutex> Lock(OutQueue->getMutex());
+ while (Size--) {
+ if (Error Err = OutQueue->checkWriteError())
+ return Err;
+ OutQueue->push(*Src++);
+ ++NumWritten;
+ }
+ OutQueue->getCondVar().notify_one();
+ return Error::success();
+ }
+
+ Error send() override { return Error::success(); }
+
+ void close() {
+ auto ChannelClosed = []() { return make_error<QueueChannelClosedError>(); };
+ InQueue->setReadError(ChannelClosed);
+ InQueue->setWriteError(ChannelClosed);
+ OutQueue->setReadError(ChannelClosed);
+ OutQueue->setWriteError(ChannelClosed);
+ }
+
+ uint64_t NumWritten = 0;
+ uint64_t NumRead = 0;
+
+private:
+
+ std::shared_ptr<Queue> InQueue;
+ std::shared_ptr<Queue> OutQueue;
+};
+
+inline std::pair<std::unique_ptr<QueueChannel>, std::unique_ptr<QueueChannel>>
+createPairedQueueChannels() {
+ auto Q1 = std::make_shared<Queue>();
+ auto Q2 = std::make_shared<Queue>();
+ auto C1 = llvm::make_unique<QueueChannel>(Q1, Q2);
+ auto C2 = llvm::make_unique<QueueChannel>(Q2, Q1);
+ return std::make_pair(std::move(C1), std::move(C2));
+}
+
+}
+
+#endif
diff --git a/unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp b/unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp
index 186c3d4084866..1c9764b555fd6 100644
--- a/unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp
+++ b/unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/ExecutionEngine/Orc/RawByteChannel.h"
#include "llvm/ExecutionEngine/Orc/RPCUtils.h"
+#include "QueueChannel.h"
#include "gtest/gtest.h"
#include <queue>
@@ -17,47 +17,6 @@ using namespace llvm;
using namespace llvm::orc;
using namespace llvm::orc::rpc;
-class Queue : public std::queue<char> {
-public:
- std::mutex &getMutex() { return M; }
- std::condition_variable &getCondVar() { return CV; }
-private:
- std::mutex M;
- std::condition_variable CV;
-};
-
-class QueueChannel : public RawByteChannel {
-public:
- QueueChannel(Queue &InQueue, Queue &OutQueue)
- : InQueue(InQueue), OutQueue(OutQueue) {}
-
- Error readBytes(char *Dst, unsigned Size) override {
- std::unique_lock<std::mutex> Lock(InQueue.getMutex());
- while (Size) {
- while (InQueue.empty())
- InQueue.getCondVar().wait(Lock);
- *Dst++ = InQueue.front();
- --Size;
- InQueue.pop();
- }
- return Error::success();
- }
-
- Error appendBytes(const char *Src, unsigned Size) override {
- std::unique_lock<std::mutex> Lock(OutQueue.getMutex());
- while (Size--)
- OutQueue.push(*Src++);
- OutQueue.getCondVar().notify_one();
- return Error::success();
- }
-
- Error send() override { return Error::success(); }
-
-private:
- Queue &InQueue;
- Queue &OutQueue;
-};
-
class RPCFoo {};
namespace llvm {
@@ -88,6 +47,54 @@ namespace rpc {
class RPCBar {};
+class DummyError : public ErrorInfo<DummyError> {
+public:
+
+ static char ID;
+
+ DummyError(uint32_t Val) : Val(Val) {}
+
+ std::error_code convertToErrorCode() const override {
+ // Use a nonsense error code - we want to verify that errors
+ // transmitted over the network are replaced with
+ // OrcErrorCode::UnknownErrorCodeFromRemote.
+ return orcError(OrcErrorCode::RemoteAllocatorDoesNotExist);
+ }
+
+ void log(raw_ostream &OS) const override {
+ OS << "Dummy error " << Val;
+ }
+
+ uint32_t getValue() const { return Val; }
+
+public:
+ uint32_t Val;
+};
+
+char DummyError::ID = 0;
+
+template <typename ChannelT>
+void registerDummyErrorSerialization() {
+ static bool AlreadyRegistered = false;
+ if (!AlreadyRegistered) {
+ SerializationTraits<ChannelT, Error>::
+ template registerErrorType<DummyError>(
+ "DummyError",
+ [](ChannelT &C, const DummyError &DE) {
+ return serializeSeq(C, DE.getValue());
+ },
+ [](ChannelT &C, Error &Err) -> Error {
+ ErrorAsOutParameter EAO(&Err);
+ uint32_t Val;
+ if (auto Err = deserializeSeq(C, Val))
+ return Err;
+ Err = make_error<DummyError>(Val);
+ return Error::success();
+ });
+ AlreadyRegistered = true;
+ }
+}
+
namespace llvm {
namespace orc {
namespace rpc {
@@ -120,6 +127,11 @@ namespace DummyRPCAPI {
static const char* getName() { return "IntInt"; }
};
+ class VoidString : public Function<VoidString, void(std::string)> {
+ public:
+ static const char* getName() { return "VoidString"; }
+ };
+
class AllTheTypes
: public Function<AllTheTypes,
void(int8_t, uint8_t, int16_t, uint16_t, int32_t,
@@ -134,21 +146,38 @@ namespace DummyRPCAPI {
static const char* getName() { return "CustomType"; }
};
+ class ErrorFunc : public Function<ErrorFunc, Error()> {
+ public:
+ static const char* getName() { return "ErrorFunc"; }
+ };
+
+ class ExpectedFunc : public Function<ExpectedFunc, Expected<uint32_t>()> {
+ public:
+ static const char* getName() { return "ExpectedFunc"; }
+ };
+
}
class DummyRPCEndpoint : public SingleThreadedRPCEndpoint<QueueChannel> {
public:
- DummyRPCEndpoint(Queue &Q1, Queue &Q2)
- : SingleThreadedRPCEndpoint(C, true), C(Q1, Q2) {}
-private:
- QueueChannel C;
+ DummyRPCEndpoint(QueueChannel &C)
+ : SingleThreadedRPCEndpoint(C, true) {}
};
-TEST(DummyRPC, TestAsyncVoidBool) {
- Queue Q1, Q2;
- DummyRPCEndpoint Client(Q1, Q2);
- DummyRPCEndpoint Server(Q2, Q1);
+void freeVoidBool(bool B) {
+}
+
+TEST(DummyRPC, TestFreeFunctionHandler) {
+ auto Channels = createPairedQueueChannels();
+ DummyRPCEndpoint Server(*Channels.first);
+ Server.addHandler<DummyRPCAPI::VoidBool>(freeVoidBool);
+}
+
+TEST(DummyRPC, TestCallAsyncVoidBool) {
+ auto Channels = createPairedQueueChannels();
+ DummyRPCEndpoint Client(*Channels.first);
+ DummyRPCEndpoint Server(*Channels.second);
std::thread ServerThread([&]() {
Server.addHandler<DummyRPCAPI::VoidBool>(
@@ -189,10 +218,10 @@ TEST(DummyRPC, TestAsyncVoidBool) {
ServerThread.join();
}
-TEST(DummyRPC, TestAsyncIntInt) {
- Queue Q1, Q2;
- DummyRPCEndpoint Client(Q1, Q2);
- DummyRPCEndpoint Server(Q2, Q1);
+TEST(DummyRPC, TestCallAsyncIntInt) {
+ auto Channels = createPairedQueueChannels();
+ DummyRPCEndpoint Client(*Channels.first);
+ DummyRPCEndpoint Server(*Channels.second);
std::thread ServerThread([&]() {
Server.addHandler<DummyRPCAPI::IntInt>(
@@ -234,10 +263,147 @@ TEST(DummyRPC, TestAsyncIntInt) {
ServerThread.join();
}
+TEST(DummyRPC, TestAsyncIntIntHandler) {
+ auto Channels = createPairedQueueChannels();
+ DummyRPCEndpoint Client(*Channels.first);
+ DummyRPCEndpoint Server(*Channels.second);
+
+ std::thread ServerThread([&]() {
+ Server.addAsyncHandler<DummyRPCAPI::IntInt>(
+ [](std::function<Error(Expected<int32_t>)> SendResult,
+ int32_t X) {
+ EXPECT_EQ(X, 21) << "Server int(int) receieved unexpected result";
+ return SendResult(2 * X);
+ });
+
+ {
+ // Poke the server to handle the negotiate call.
+ auto Err = Server.handleOne();
+ EXPECT_FALSE(!!Err) << "Server failed to handle call to negotiate";
+ }
+
+ {
+ // Poke the server to handle the VoidBool call.
+ auto Err = Server.handleOne();
+ EXPECT_FALSE(!!Err) << "Server failed to handle call to void(bool)";
+ }
+ });
+
+ {
+ auto Err = Client.callAsync<DummyRPCAPI::IntInt>(
+ [](Expected<int> Result) {
+ EXPECT_TRUE(!!Result) << "Async int(int) response handler failed";
+ EXPECT_EQ(*Result, 42)
+ << "Async int(int) response handler received incorrect result";
+ return Error::success();
+ }, 21);
+ EXPECT_FALSE(!!Err) << "Client.callAsync failed for int(int)";
+ }
+
+ {
+ // Poke the client to process the result.
+ auto Err = Client.handleOne();
+ EXPECT_FALSE(!!Err) << "Client failed to handle response from void(bool)";
+ }
+
+ ServerThread.join();
+}
+
+TEST(DummyRPC, TestAsyncIntIntHandlerMethod) {
+ auto Channels = createPairedQueueChannels();
+ DummyRPCEndpoint Client(*Channels.first);
+ DummyRPCEndpoint Server(*Channels.second);
+
+ class Dummy {
+ public:
+ Error handler(std::function<Error(Expected<int32_t>)> SendResult,
+ int32_t X) {
+ EXPECT_EQ(X, 21) << "Server int(int) receieved unexpected result";
+ return SendResult(2 * X);
+ }
+ };
+
+ std::thread ServerThread([&]() {
+ Dummy D;
+ Server.addAsyncHandler<DummyRPCAPI::IntInt>(D, &Dummy::handler);
+
+ {
+ // Poke the server to handle the negotiate call.
+ auto Err = Server.handleOne();
+ EXPECT_FALSE(!!Err) << "Server failed to handle call to negotiate";
+ }
+
+ {
+ // Poke the server to handle the VoidBool call.
+ auto Err = Server.handleOne();
+ EXPECT_FALSE(!!Err) << "Server failed to handle call to void(bool)";
+ }
+ });
+
+ {
+ auto Err = Client.callAsync<DummyRPCAPI::IntInt>(
+ [](Expected<int> Result) {
+ EXPECT_TRUE(!!Result) << "Async int(int) response handler failed";
+ EXPECT_EQ(*Result, 42)
+ << "Async int(int) response handler received incorrect result";
+ return Error::success();
+ }, 21);
+ EXPECT_FALSE(!!Err) << "Client.callAsync failed for int(int)";
+ }
+
+ {
+ // Poke the client to process the result.
+ auto Err = Client.handleOne();
+ EXPECT_FALSE(!!Err) << "Client failed to handle response from void(bool)";
+ }
+
+ ServerThread.join();
+}
+
+TEST(DummyRPC, TestCallAsyncVoidString) {
+ auto Channels = createPairedQueueChannels();
+ DummyRPCEndpoint Client(*Channels.first);
+ DummyRPCEndpoint Server(*Channels.second);
+
+ std::thread ServerThread([&]() {
+ Server.addHandler<DummyRPCAPI::VoidString>(
+ [](const std::string &S) {
+ EXPECT_EQ(S, "hello")
+ << "Server void(std::string) received unexpected result";
+ });
+
+ // Poke the server to handle the negotiate call.
+ for (int I = 0; I < 4; ++I) {
+ auto Err = Server.handleOne();
+ EXPECT_FALSE(!!Err) << "Server failed to handle call";
+ }
+ });
+
+ {
+ // Make an call using a std::string.
+ auto Err = Client.callB<DummyRPCAPI::VoidString>(std::string("hello"));
+ EXPECT_FALSE(!!Err) << "Client.callAsync failed for void(std::string)";
+ }
+
+ {
+ // Make an call using a std::string.
+ auto Err = Client.callB<DummyRPCAPI::VoidString>(StringRef("hello"));
+ EXPECT_FALSE(!!Err) << "Client.callAsync failed for void(std::string)";
+ }
+
+ {
+ // Make an call using a std::string.
+ auto Err = Client.callB<DummyRPCAPI::VoidString>("hello");
+ EXPECT_FALSE(!!Err) << "Client.callAsync failed for void(string)";
+ }
+
+ ServerThread.join();
+}
+
TEST(DummyRPC, TestSerialization) {
- Queue Q1, Q2;
- DummyRPCEndpoint Client(Q1, Q2);
- DummyRPCEndpoint Server(Q2, Q1);
+ auto Channels = createPairedQueueChannels();
+ DummyRPCEndpoint Client(*Channels.first);
+ DummyRPCEndpoint Server(*Channels.second);
std::thread ServerThread([&]() {
Server.addHandler<DummyRPCAPI::AllTheTypes>(
@@ -300,9 +466,9 @@ TEST(DummyRPC, TestSerialization) {
}
TEST(DummyRPC, TestCustomType) {
- Queue Q1, Q2;
- DummyRPCEndpoint Client(Q1, Q2);
- DummyRPCEndpoint Server(Q2, Q1);
+ auto Channels = createPairedQueueChannels();
+ DummyRPCEndpoint Client(*Channels.first);
+ DummyRPCEndpoint Server(*Channels.second);
std::thread ServerThread([&]() {
Server.addHandler<DummyRPCAPI::CustomType>(
@@ -343,9 +509,9 @@ TEST(DummyRPC, TestCustomType) {
}
TEST(DummyRPC, TestWithAltCustomType) {
- Queue Q1, Q2;
- DummyRPCEndpoint Client(Q1, Q2);
- DummyRPCEndpoint Server(Q2, Q1);
+ auto Channels = createPairedQueueChannels();
+ DummyRPCEndpoint Client(*Channels.first);
+ DummyRPCEndpoint Server(*Channels.second);
std::thread ServerThread([&]() {
Server.addHandler<DummyRPCAPI::CustomType>(
@@ -385,10 +551,144 @@ TEST(DummyRPC, TestWithAltCustomType) {
ServerThread.join();
}
+TEST(DummyRPC, ReturnErrorSuccess) {
+ registerDummyErrorSerialization<QueueChannel>();
+
+ auto Channels = createPairedQueueChannels();
+ DummyRPCEndpoint Client(*Channels.first);
+ DummyRPCEndpoint Server(*Channels.second);
+
+ std::thread ServerThread([&]() {
+ Server.addHandler<DummyRPCAPI::ErrorFunc>(
+ []() {
+ return Error::success();
+ });
+
+ // Handle the negotiate plus one call.
+ for (unsigned I = 0; I != 2; ++I)
+ cantFail(Server.handleOne());
+ });
+
+ cantFail(Client.callAsync<DummyRPCAPI::ErrorFunc>(
+ [&](Error Err) {
+ EXPECT_FALSE(!!Err) << "Expected success value";
+ return Error::success();
+ }));
+
+ cantFail(Client.handleOne());
+
+ ServerThread.join();
+}
+
+TEST(DummyRPC, ReturnErrorFailure) {
+ registerDummyErrorSerialization<QueueChannel>();
+
+ auto Channels = createPairedQueueChannels();
+ DummyRPCEndpoint Client(*Channels.first);
+ DummyRPCEndpoint Server(*Channels.second);
+
+ std::thread ServerThread([&]() {
+ Server.addHandler<DummyRPCAPI::ErrorFunc>(
+ []() {
+ return make_error<DummyError>(42);
+ });
+
+ // Handle the negotiate plus one call.
+ for (unsigned I = 0; I != 2; ++I)
+ cantFail(Server.handleOne());
+ });
+
+ cantFail(Client.callAsync<DummyRPCAPI::ErrorFunc>(
+ [&](Error Err) {
+ EXPECT_TRUE(Err.isA<DummyError>())
+ << "Incorrect error type";
+ return handleErrors(
+ std::move(Err),
+ [](const DummyError &DE) {
+ EXPECT_EQ(DE.getValue(), 42ULL)
+ << "Incorrect DummyError serialization";
+ });
+ }));
+
+ cantFail(Client.handleOne());
+
+ ServerThread.join();
+}
+
+TEST(DummyRPC, ReturnExpectedSuccess) {
+ registerDummyErrorSerialization<QueueChannel>();
+
+ auto Channels = createPairedQueueChannels();
+ DummyRPCEndpoint Client(*Channels.first);
+ DummyRPCEndpoint Server(*Channels.second);
+
+ std::thread ServerThread([&]() {
+ Server.addHandler<DummyRPCAPI::ExpectedFunc>(
+ []() -> uint32_t {
+ return 42;
+ });
+
+ // Handle the negotiate plus one call.
+ for (unsigned I = 0; I != 2; ++I)
+ cantFail(Server.handleOne());
+ });
+
+ cantFail(Client.callAsync<DummyRPCAPI::ExpectedFunc>(
+ [&](Expected<uint32_t> ValOrErr) {
+ EXPECT_TRUE(!!ValOrErr)
+ << "Expected success value";
+ EXPECT_EQ(*ValOrErr, 42ULL)
+ << "Incorrect Expected<uint32_t> deserialization";
+ return Error::success();
+ }));
+
+ cantFail(Client.handleOne());
+
+ ServerThread.join();
+}
+
+TEST(DummyRPC, ReturnExpectedFailure) {
+ registerDummyErrorSerialization<QueueChannel>();
+
+ auto Channels = createPairedQueueChannels();
+ DummyRPCEndpoint Client(*Channels.first);
+ DummyRPCEndpoint Server(*Channels.second);
+
+ std::thread ServerThread([&]() {
+ Server.addHandler<DummyRPCAPI::ExpectedFunc>(
+ []() -> Expected<uint32_t> {
+ return make_error<DummyError>(7);
+ });
+
+ // Handle the negotiate plus one call.
+ for (unsigned I = 0; I != 2; ++I)
+ cantFail(Server.handleOne());
+ });
+
+ cantFail(Client.callAsync<DummyRPCAPI::ExpectedFunc>(
+ [&](Expected<uint32_t> ValOrErr) {
+ EXPECT_FALSE(!!ValOrErr)
+ << "Expected failure value";
+ auto Err = ValOrErr.takeError();
+ EXPECT_TRUE(Err.isA<DummyError>())
+ << "Incorrect error type";
+ return handleErrors(
+ std::move(Err),
+ [](const DummyError &DE) {
+ EXPECT_EQ(DE.getValue(), 7ULL)
+ << "Incorrect DummyError serialization";
+ });
+ }));
+
+ cantFail(Client.handleOne());
+
+ ServerThread.join();
+}
+
TEST(DummyRPC, TestParallelCallGroup) {
- Queue Q1, Q2;
- DummyRPCEndpoint Client(Q1, Q2);
- DummyRPCEndpoint Server(Q2, Q1);
+ auto Channels = createPairedQueueChannels();
+ DummyRPCEndpoint Client(*Channels.first);
+ DummyRPCEndpoint Server(*Channels.second);
std::thread ServerThread([&]() {
Server.addHandler<DummyRPCAPI::IntInt>(
@@ -405,10 +705,11 @@ TEST(DummyRPC, TestParallelCallGroup) {
{
int A, B, C;
- ParallelCallGroup<DummyRPCEndpoint> PCG(Client);
+ ParallelCallGroup PCG;
{
- auto Err = PCG.appendCall<DummyRPCAPI::IntInt>(
+ auto Err = PCG.call(
+ rpcAsyncDispatch<DummyRPCAPI::IntInt>(Client),
[&A](Expected<int> Result) {
EXPECT_TRUE(!!Result) << "Async int(int) response handler failed";
A = *Result;
@@ -418,7 +719,8 @@ TEST(DummyRPC, TestParallelCallGroup) {
}
{
- auto Err = PCG.appendCall<DummyRPCAPI::IntInt>(
+ auto Err = PCG.call(
+ rpcAsyncDispatch<DummyRPCAPI::IntInt>(Client),
[&B](Expected<int> Result) {
EXPECT_TRUE(!!Result) << "Async int(int) response handler failed";
B = *Result;
@@ -428,7 +730,8 @@ TEST(DummyRPC, TestParallelCallGroup) {
}
{
- auto Err = PCG.appendCall<DummyRPCAPI::IntInt>(
+ auto Err = PCG.call(
+ rpcAsyncDispatch<DummyRPCAPI::IntInt>(Client),
[&C](Expected<int> Result) {
EXPECT_TRUE(!!Result) << "Async int(int) response handler failed";
C = *Result;
@@ -443,10 +746,7 @@ TEST(DummyRPC, TestParallelCallGroup) {
EXPECT_FALSE(!!Err) << "Client failed to handle response from void(bool)";
}
- {
- auto Err = PCG.wait();
- EXPECT_FALSE(!!Err) << "Third parallel call failed for int(int)";
- }
+ PCG.wait();
EXPECT_EQ(A, 2) << "First parallel call returned bogus result";
EXPECT_EQ(B, 4) << "Second parallel call returned bogus result";
@@ -468,9 +768,9 @@ TEST(DummyRPC, TestAPICalls) {
static_assert(!DummyCalls1::Contains<DummyRPCAPI::CustomType>::value,
"Contains<Func> template should return false here");
- Queue Q1, Q2;
- DummyRPCEndpoint Client(Q1, Q2);
- DummyRPCEndpoint Server(Q2, Q1);
+ auto Channels = createPairedQueueChannels();
+ DummyRPCEndpoint Client(*Channels.first);
+ DummyRPCEndpoint Server(*Channels.second);
std::thread ServerThread(
[&]() {
@@ -496,11 +796,37 @@ TEST(DummyRPC, TestAPICalls) {
{
auto Err = DummyCallsAll::negotiate(Client);
- EXPECT_EQ(errorToErrorCode(std::move(Err)).value(),
- static_cast<int>(OrcErrorCode::UnknownRPCFunction))
- << "Expected 'UnknownRPCFunction' error for attempted negotiate of "
+ EXPECT_TRUE(Err.isA<CouldNotNegotiate>())
+ << "Expected CouldNotNegotiate error for attempted negotiate of "
"unsupported function";
+ consumeError(std::move(Err));
}
ServerThread.join();
}
+
+TEST(DummyRPC, TestRemoveHandler) {
+ auto Channels = createPairedQueueChannels();
+ DummyRPCEndpoint Server(*Channels.second);
+
+ Server.addHandler<DummyRPCAPI::VoidBool>(
+ [](bool B) {
+ EXPECT_EQ(B, true)
+ << "Server void(bool) received unexpected result";
+ });
+
+ Server.removeHandler<DummyRPCAPI::VoidBool>();
+}
+
+TEST(DummyRPC, TestClearHandlers) {
+ auto Channels = createPairedQueueChannels();
+ DummyRPCEndpoint Server(*Channels.second);
+
+ Server.addHandler<DummyRPCAPI::VoidBool>(
+ [](bool B) {
+ EXPECT_EQ(B, true)
+ << "Server void(bool) received unexpected result";
+ });
+
+ Server.clearHandlers();
+}
diff --git a/unittests/ExecutionEngine/Orc/ObjectLinkingLayerTest.cpp b/unittests/ExecutionEngine/Orc/RTDyldObjectLinkingLayerTest.cpp
index 44b44f6041590..de99c022fb9dc 100644
--- a/unittests/ExecutionEngine/Orc/ObjectLinkingLayerTest.cpp
+++ b/unittests/ExecutionEngine/Orc/RTDyldObjectLinkingLayerTest.cpp
@@ -1,4 +1,4 @@
-//===-- ObjectLinkingLayerTest.cpp - Unit tests for object linking layer --===//
+//===- RTDyldObjectLinkingLayerTest.cpp - RTDyld linking layer unit tests -===//
//
// The LLVM Compiler Infrastructure
//
@@ -13,7 +13,7 @@
#include "llvm/ExecutionEngine/Orc/CompileUtils.h"
#include "llvm/ExecutionEngine/Orc/LambdaResolver.h"
#include "llvm/ExecutionEngine/Orc/NullResolver.h"
-#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
+#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/LLVMContext.h"
#include "gtest/gtest.h"
@@ -23,8 +23,8 @@ using namespace llvm::orc;
namespace {
-class ObjectLinkingLayerExecutionTest : public testing::Test,
- public OrcExecutionTest {
+class RTDyldObjectLinkingLayerExecutionTest : public testing::Test,
+ public OrcExecutionTest {
};
@@ -44,7 +44,7 @@ public:
}
};
-TEST(ObjectLinkingLayerTest, TestSetProcessAllSections) {
+TEST(RTDyldObjectLinkingLayerTest, TestSetProcessAllSections) {
class SectionMemoryManagerWrapper : public SectionMemoryManager {
public:
SectionMemoryManagerWrapper(bool &DebugSeen) : DebugSeen(DebugSeen) {}
@@ -60,10 +60,10 @@ TEST(ObjectLinkingLayerTest, TestSetProcessAllSections) {
IsReadOnly);
}
private:
- bool DebugSeen;
+ bool &DebugSeen;
};
- ObjectLinkingLayer<> ObjLayer;
+ RTDyldObjectLinkingLayer<> ObjLayer;
LLVMContext Context;
auto M = llvm::make_unique<Module>("", Context);
@@ -75,6 +75,10 @@ TEST(ObjectLinkingLayerTest, TestSetProcessAllSections) {
GV->setSection(".debug_str");
+
+ // Initialize the native target in case this is the first unit test
+ // to try to build a TM.
+ OrcNativeTarget::initialize();
std::unique_ptr<TargetMachine> TM(
EngineBuilder().selectTarget(Triple(M->getTargetTriple()), "", "",
SmallVector<std::string, 1>()));
@@ -99,6 +103,7 @@ TEST(ObjectLinkingLayerTest, TestSetProcessAllSections) {
{
// Test with ProcessAllSections = false (the default).
auto H = ObjLayer.addObjectSet(Objs, &SMMW, &*Resolver);
+ ObjLayer.emitAndFinalize(H);
EXPECT_EQ(DebugSectionSeen, false)
<< "Unexpected debug info section";
ObjLayer.removeObjectSet(H);
@@ -108,17 +113,18 @@ TEST(ObjectLinkingLayerTest, TestSetProcessAllSections) {
// Test with ProcessAllSections = true.
ObjLayer.setProcessAllSections(true);
auto H = ObjLayer.addObjectSet(Objs, &SMMW, &*Resolver);
+ ObjLayer.emitAndFinalize(H);
EXPECT_EQ(DebugSectionSeen, true)
<< "Expected debug info section not seen";
ObjLayer.removeObjectSet(H);
}
}
-TEST_F(ObjectLinkingLayerExecutionTest, NoDuplicateFinalization) {
+TEST_F(RTDyldObjectLinkingLayerExecutionTest, NoDuplicateFinalization) {
if (!TM)
return;
- ObjectLinkingLayer<> ObjLayer;
+ RTDyldObjectLinkingLayer<> ObjLayer;
SimpleCompiler Compile(*TM);
// Create a pair of modules that will trigger recursive finalization:
@@ -183,11 +189,11 @@ TEST_F(ObjectLinkingLayerExecutionTest, NoDuplicateFinalization) {
<< "Extra call to finalize";
}
-TEST_F(ObjectLinkingLayerExecutionTest, NoPrematureAllocation) {
+TEST_F(RTDyldObjectLinkingLayerExecutionTest, NoPrematureAllocation) {
if (!TM)
return;
- ObjectLinkingLayer<> ObjLayer;
+ RTDyldObjectLinkingLayer<> ObjLayer;
SimpleCompiler Compile(*TM);
// Create a pair of unrelated modules:
diff --git a/unittests/IR/AttributesTest.cpp b/unittests/IR/AttributesTest.cpp
index 9f8013ff181cd..b5b221c63a173 100644
--- a/unittests/IR/AttributesTest.cpp
+++ b/unittests/IR/AttributesTest.cpp
@@ -21,13 +21,11 @@ TEST(Attributes, Uniquing) {
Attribute AttrB = Attribute::get(C, Attribute::AlwaysInline);
EXPECT_EQ(AttrA, AttrB);
- AttributeSet ASs[] = {
- AttributeSet::get(C, 1, Attribute::ZExt),
- AttributeSet::get(C, 2, Attribute::SExt)
- };
+ AttributeList ASs[] = {AttributeList::get(C, 1, Attribute::ZExt),
+ AttributeList::get(C, 2, Attribute::SExt)};
- AttributeSet SetA = AttributeSet::get(C, ASs);
- AttributeSet SetB = AttributeSet::get(C, ASs);
+ AttributeList SetA = AttributeList::get(C, ASs);
+ AttributeList SetB = AttributeList::get(C, ASs);
EXPECT_EQ(SetA, SetB);
}
@@ -43,13 +41,11 @@ TEST(Attributes, Ordering) {
EXPECT_TRUE(Align4 < Deref5);
EXPECT_TRUE(Align5 < Deref4);
- AttributeSet ASs[] = {
- AttributeSet::get(C, 2, Attribute::ZExt),
- AttributeSet::get(C, 1, Attribute::SExt)
- };
+ AttributeList ASs[] = {AttributeList::get(C, 2, Attribute::ZExt),
+ AttributeList::get(C, 1, Attribute::SExt)};
- AttributeSet SetA = AttributeSet::get(C, ASs);
- AttributeSet SetB = SetA.removeAttributes(C, 1, ASs[1]);
+ AttributeList SetA = AttributeList::get(C, ASs);
+ AttributeList SetB = SetA.removeAttributes(C, 1, ASs[1]);
EXPECT_NE(SetA, SetB);
}
diff --git a/unittests/IR/FunctionTest.cpp b/unittests/IR/FunctionTest.cpp
index fb458597c37a4..6838d7e2527ff 100644
--- a/unittests/IR/FunctionTest.cpp
+++ b/unittests/IR/FunctionTest.cpp
@@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/IR/Function.h"
+#include "llvm/IR/Module.h"
#include "gtest/gtest.h"
using namespace llvm;
@@ -109,4 +110,24 @@ TEST(FunctionTest, stealArgumentListFrom) {
EXPECT_TRUE(F2->hasLazyArguments());
}
+// Test setting and removing section information
+TEST(FunctionTest, setSection) {
+ LLVMContext C;
+ Module M("test", C);
+
+ llvm::Function *F =
+ Function::Create(llvm::FunctionType::get(llvm::Type::getVoidTy(C), false),
+ llvm::GlobalValue::ExternalLinkage, "F", &M);
+
+ F->setSection(".text.test");
+ EXPECT_TRUE(F->getSection() == ".text.test");
+ EXPECT_TRUE(F->hasSection());
+ F->setSection("");
+ EXPECT_FALSE(F->hasSection());
+ F->setSection(".text.test");
+ F->setSection(".text.test2");
+ EXPECT_TRUE(F->getSection() == ".text.test2");
+ EXPECT_TRUE(F->hasSection());
+}
+
} // end namespace
diff --git a/unittests/IR/IRBuilderTest.cpp b/unittests/IR/IRBuilderTest.cpp
index 1812cd39d135c..830ae9587691c 100644
--- a/unittests/IR/IRBuilderTest.cpp
+++ b/unittests/IR/IRBuilderTest.cpp
@@ -207,7 +207,26 @@ TEST_F(IRBuilderTest, FastMathFlags) {
EXPECT_TRUE(FCmp->hasAllowReciprocal());
Builder.clearFastMathFlags();
-
+
+ // Test FP-contract
+ FC = Builder.CreateFAdd(F, F);
+ ASSERT_TRUE(isa<Instruction>(FC));
+ FAdd = cast<Instruction>(FC);
+ EXPECT_FALSE(FAdd->hasAllowContract());
+
+ FMF.clear();
+ FMF.setAllowContract(true);
+ Builder.setFastMathFlags(FMF);
+
+ FC = Builder.CreateFAdd(F, F);
+ EXPECT_TRUE(Builder.getFastMathFlags().any());
+ EXPECT_TRUE(Builder.getFastMathFlags().AllowContract);
+ ASSERT_TRUE(isa<Instruction>(FC));
+ FAdd = cast<Instruction>(FC);
+ EXPECT_TRUE(FAdd->hasAllowContract());
+
+ Builder.clearFastMathFlags();
+
// Test a call with FMF.
auto CalleeTy = FunctionType::get(Type::getFloatTy(Ctx),
/*isVarArg=*/false);
@@ -245,6 +264,7 @@ TEST_F(IRBuilderTest, FastMathFlags) {
EXPECT_FALSE(FDiv->getFastMathFlags().any());
FDiv->setHasAllowReciprocal(true);
FAdd->setHasAllowReciprocal(false);
+ FAdd->setHasNoNaNs(true);
FDiv->copyFastMathFlags(FAdd);
EXPECT_TRUE(FDiv->hasNoNaNs());
EXPECT_FALSE(FDiv->hasAllowReciprocal());
diff --git a/unittests/IR/InstructionsTest.cpp b/unittests/IR/InstructionsTest.cpp
index 0dac7c1bcfb11..7c75aaec17539 100644
--- a/unittests/IR/InstructionsTest.cpp
+++ b/unittests/IR/InstructionsTest.cpp
@@ -19,6 +19,7 @@
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/MDBuilder.h"
#include "llvm/IR/Module.h"
+#include "llvm/IR/NoFolder.h"
#include "llvm/IR/Operator.h"
#include "gtest/gtest.h"
#include <memory>
@@ -516,7 +517,8 @@ TEST(InstructionsTest, CloneCall) {
{
AttrBuilder AB;
AB.addAttribute(Attribute::ReadOnly);
- Call->setAttributes(AttributeSet::get(C, AttributeSet::FunctionIndex, AB));
+ Call->setAttributes(
+ AttributeList::get(C, AttributeList::FunctionIndex, AB));
std::unique_ptr<CallInst> Clone(cast<CallInst>(Call->clone()));
EXPECT_TRUE(Clone->onlyReadsMemory());
}
@@ -534,7 +536,7 @@ TEST(InstructionsTest, AlterCallBundles) {
Call->setTailCallKind(CallInst::TailCallKind::TCK_NoTail);
AttrBuilder AB;
AB.addAttribute(Attribute::Cold);
- Call->setAttributes(AttributeSet::get(C, AttributeSet::FunctionIndex, AB));
+ Call->setAttributes(AttributeList::get(C, AttributeList::FunctionIndex, AB));
Call->setDebugLoc(DebugLoc(MDNode::get(C, None)));
OperandBundleDef NewBundle("after", ConstantInt::get(Int32Ty, 7));
@@ -562,7 +564,8 @@ TEST(InstructionsTest, AlterInvokeBundles) {
Callee, NormalDest.get(), UnwindDest.get(), Args, OldBundle, "result"));
AttrBuilder AB;
AB.addAttribute(Attribute::Cold);
- Invoke->setAttributes(AttributeSet::get(C, AttributeSet::FunctionIndex, AB));
+ Invoke->setAttributes(
+ AttributeList::get(C, AttributeList::FunctionIndex, AB));
Invoke->setDebugLoc(DebugLoc(MDNode::get(C, None)));
OperandBundleDef NewBundle("after", ConstantInt::get(Int32Ty, 7));
@@ -579,5 +582,163 @@ TEST(InstructionsTest, AlterInvokeBundles) {
EXPECT_TRUE(Clone->getOperandBundle("after").hasValue());
}
+TEST_F(ModuleWithFunctionTest, DropPoisonGeneratingFlags) {
+ auto *OnlyBB = BasicBlock::Create(Ctx, "bb", F);
+ auto *Arg0 = &*F->arg_begin();
+
+ IRBuilder<NoFolder> B(Ctx);
+ B.SetInsertPoint(OnlyBB);
+
+ {
+ auto *UI =
+ cast<Instruction>(B.CreateUDiv(Arg0, Arg0, "", /*isExact*/ true));
+ ASSERT_TRUE(UI->isExact());
+ UI->dropPoisonGeneratingFlags();
+ ASSERT_FALSE(UI->isExact());
+ }
+
+ {
+ auto *ShrI =
+ cast<Instruction>(B.CreateLShr(Arg0, Arg0, "", /*isExact*/ true));
+ ASSERT_TRUE(ShrI->isExact());
+ ShrI->dropPoisonGeneratingFlags();
+ ASSERT_FALSE(ShrI->isExact());
+ }
+
+ {
+ auto *AI = cast<Instruction>(
+ B.CreateAdd(Arg0, Arg0, "", /*HasNUW*/ true, /*HasNSW*/ false));
+ ASSERT_TRUE(AI->hasNoUnsignedWrap());
+ AI->dropPoisonGeneratingFlags();
+ ASSERT_FALSE(AI->hasNoUnsignedWrap());
+ ASSERT_FALSE(AI->hasNoSignedWrap());
+ }
+
+ {
+ auto *SI = cast<Instruction>(
+ B.CreateAdd(Arg0, Arg0, "", /*HasNUW*/ false, /*HasNSW*/ true));
+ ASSERT_TRUE(SI->hasNoSignedWrap());
+ SI->dropPoisonGeneratingFlags();
+ ASSERT_FALSE(SI->hasNoUnsignedWrap());
+ ASSERT_FALSE(SI->hasNoSignedWrap());
+ }
+
+ {
+ auto *ShlI = cast<Instruction>(
+ B.CreateShl(Arg0, Arg0, "", /*HasNUW*/ true, /*HasNSW*/ true));
+ ASSERT_TRUE(ShlI->hasNoSignedWrap());
+ ASSERT_TRUE(ShlI->hasNoUnsignedWrap());
+ ShlI->dropPoisonGeneratingFlags();
+ ASSERT_FALSE(ShlI->hasNoUnsignedWrap());
+ ASSERT_FALSE(ShlI->hasNoSignedWrap());
+ }
+
+ {
+ Value *GEPBase = Constant::getNullValue(B.getInt8PtrTy());
+ auto *GI = cast<GetElementPtrInst>(B.CreateInBoundsGEP(GEPBase, {Arg0}));
+ ASSERT_TRUE(GI->isInBounds());
+ GI->dropPoisonGeneratingFlags();
+ ASSERT_FALSE(GI->isInBounds());
+ }
+}
+
+TEST(InstructionsTest, GEPIndices) {
+ LLVMContext Context;
+ IRBuilder<NoFolder> Builder(Context);
+ Type *ElementTy = Builder.getInt8Ty();
+ Type *ArrTy = ArrayType::get(ArrayType::get(ElementTy, 64), 64);
+ Value *Indices[] = {
+ Builder.getInt32(0),
+ Builder.getInt32(13),
+ Builder.getInt32(42) };
+
+ Value *V = Builder.CreateGEP(ArrTy, UndefValue::get(PointerType::getUnqual(ArrTy)),
+ Indices);
+ ASSERT_TRUE(isa<GetElementPtrInst>(V));
+
+ auto *GEPI = cast<GetElementPtrInst>(V);
+ ASSERT_NE(GEPI->idx_begin(), GEPI->idx_end());
+ ASSERT_EQ(GEPI->idx_end(), std::next(GEPI->idx_begin(), 3));
+ EXPECT_EQ(Indices[0], GEPI->idx_begin()[0]);
+ EXPECT_EQ(Indices[1], GEPI->idx_begin()[1]);
+ EXPECT_EQ(Indices[2], GEPI->idx_begin()[2]);
+ EXPECT_EQ(GEPI->idx_begin(), GEPI->indices().begin());
+ EXPECT_EQ(GEPI->idx_end(), GEPI->indices().end());
+
+ const auto *CGEPI = GEPI;
+ ASSERT_NE(CGEPI->idx_begin(), CGEPI->idx_end());
+ ASSERT_EQ(CGEPI->idx_end(), std::next(CGEPI->idx_begin(), 3));
+ EXPECT_EQ(Indices[0], CGEPI->idx_begin()[0]);
+ EXPECT_EQ(Indices[1], CGEPI->idx_begin()[1]);
+ EXPECT_EQ(Indices[2], CGEPI->idx_begin()[2]);
+ EXPECT_EQ(CGEPI->idx_begin(), CGEPI->indices().begin());
+ EXPECT_EQ(CGEPI->idx_end(), CGEPI->indices().end());
+
+ delete GEPI;
+}
+
+TEST(InstructionsTest, SwitchInst) {
+ LLVMContext C;
+
+ std::unique_ptr<BasicBlock> BB1, BB2, BB3;
+ BB1.reset(BasicBlock::Create(C));
+ BB2.reset(BasicBlock::Create(C));
+ BB3.reset(BasicBlock::Create(C));
+
+ // We create block 0 after the others so that it gets destroyed first and
+ // clears the uses of the other basic blocks.
+ std::unique_ptr<BasicBlock> BB0(BasicBlock::Create(C));
+
+ auto *Int32Ty = Type::getInt32Ty(C);
+
+ SwitchInst *SI =
+ SwitchInst::Create(UndefValue::get(Int32Ty), BB0.get(), 3, BB0.get());
+ SI->addCase(ConstantInt::get(Int32Ty, 1), BB1.get());
+ SI->addCase(ConstantInt::get(Int32Ty, 2), BB2.get());
+ SI->addCase(ConstantInt::get(Int32Ty, 3), BB3.get());
+
+ auto CI = SI->case_begin();
+ ASSERT_NE(CI, SI->case_end());
+ EXPECT_EQ(1, CI->getCaseValue()->getSExtValue());
+ EXPECT_EQ(BB1.get(), CI->getCaseSuccessor());
+ EXPECT_EQ(2, (CI + 1)->getCaseValue()->getSExtValue());
+ EXPECT_EQ(BB2.get(), (CI + 1)->getCaseSuccessor());
+ EXPECT_EQ(3, (CI + 2)->getCaseValue()->getSExtValue());
+ EXPECT_EQ(BB3.get(), (CI + 2)->getCaseSuccessor());
+ EXPECT_EQ(CI + 1, std::next(CI));
+ EXPECT_EQ(CI + 2, std::next(CI, 2));
+ EXPECT_EQ(CI + 3, std::next(CI, 3));
+ EXPECT_EQ(SI->case_end(), CI + 3);
+ EXPECT_EQ(0, CI - CI);
+ EXPECT_EQ(1, (CI + 1) - CI);
+ EXPECT_EQ(2, (CI + 2) - CI);
+ EXPECT_EQ(3, SI->case_end() - CI);
+ EXPECT_EQ(3, std::distance(CI, SI->case_end()));
+
+ auto CCI = const_cast<const SwitchInst *>(SI)->case_begin();
+ SwitchInst::ConstCaseIt CCE = SI->case_end();
+ ASSERT_NE(CCI, SI->case_end());
+ EXPECT_EQ(1, CCI->getCaseValue()->getSExtValue());
+ EXPECT_EQ(BB1.get(), CCI->getCaseSuccessor());
+ EXPECT_EQ(2, (CCI + 1)->getCaseValue()->getSExtValue());
+ EXPECT_EQ(BB2.get(), (CCI + 1)->getCaseSuccessor());
+ EXPECT_EQ(3, (CCI + 2)->getCaseValue()->getSExtValue());
+ EXPECT_EQ(BB3.get(), (CCI + 2)->getCaseSuccessor());
+ EXPECT_EQ(CCI + 1, std::next(CCI));
+ EXPECT_EQ(CCI + 2, std::next(CCI, 2));
+ EXPECT_EQ(CCI + 3, std::next(CCI, 3));
+ EXPECT_EQ(CCE, CCI + 3);
+ EXPECT_EQ(0, CCI - CCI);
+ EXPECT_EQ(1, (CCI + 1) - CCI);
+ EXPECT_EQ(2, (CCI + 2) - CCI);
+ EXPECT_EQ(3, CCE - CCI);
+ EXPECT_EQ(3, std::distance(CCI, CCE));
+
+ // Make sure that the const iterator is compatible with a const auto ref.
+ const auto &Handle = *CCI;
+ EXPECT_EQ(1, Handle.getCaseValue()->getSExtValue());
+ EXPECT_EQ(BB1.get(), Handle.getCaseSuccessor());
+}
+
} // end anonymous namespace
} // end namespace llvm
diff --git a/unittests/IR/LegacyPassManagerTest.cpp b/unittests/IR/LegacyPassManagerTest.cpp
index 9dceb976c9375..0f67d3fb5ac9e 100644
--- a/unittests/IR/LegacyPassManagerTest.cpp
+++ b/unittests/IR/LegacyPassManagerTest.cpp
@@ -429,7 +429,7 @@ namespace llvm {
/*Linkage=*/GlobalValue::ExternalLinkage,
/*Name=*/"test1", mod);
func_test1->setCallingConv(CallingConv::C);
- AttributeSet func_test1_PAL;
+ AttributeList func_test1_PAL;
func_test1->setAttributes(func_test1_PAL);
Function* func_test2 = Function::Create(
@@ -437,7 +437,7 @@ namespace llvm {
/*Linkage=*/GlobalValue::ExternalLinkage,
/*Name=*/"test2", mod);
func_test2->setCallingConv(CallingConv::C);
- AttributeSet func_test2_PAL;
+ AttributeList func_test2_PAL;
func_test2->setAttributes(func_test2_PAL);
Function* func_test3 = Function::Create(
@@ -445,7 +445,7 @@ namespace llvm {
/*Linkage=*/GlobalValue::ExternalLinkage,
/*Name=*/"test3", mod);
func_test3->setCallingConv(CallingConv::C);
- AttributeSet func_test3_PAL;
+ AttributeList func_test3_PAL;
func_test3->setAttributes(func_test3_PAL);
Function* func_test4 = Function::Create(
@@ -453,7 +453,7 @@ namespace llvm {
/*Linkage=*/GlobalValue::ExternalLinkage,
/*Name=*/"test4", mod);
func_test4->setCallingConv(CallingConv::C);
- AttributeSet func_test4_PAL;
+ AttributeList func_test4_PAL;
func_test4->setAttributes(func_test4_PAL);
// Global Variable Declarations
@@ -474,7 +474,8 @@ namespace llvm {
// Block entry (label_entry)
CallInst* int32_3 = CallInst::Create(func_test2, "", label_entry);
int32_3->setCallingConv(CallingConv::C);
- int32_3->setTailCall(false);AttributeSet int32_3_PAL;
+ int32_3->setTailCall(false);
+ AttributeList int32_3_PAL;
int32_3->setAttributes(int32_3_PAL);
ReturnInst::Create(Context, int32_3, label_entry);
@@ -489,7 +490,8 @@ namespace llvm {
// Block entry (label_entry_5)
CallInst* int32_6 = CallInst::Create(func_test3, "", label_entry_5);
int32_6->setCallingConv(CallingConv::C);
- int32_6->setTailCall(false);AttributeSet int32_6_PAL;
+ int32_6->setTailCall(false);
+ AttributeList int32_6_PAL;
int32_6->setAttributes(int32_6_PAL);
ReturnInst::Create(Context, int32_6, label_entry_5);
@@ -504,7 +506,8 @@ namespace llvm {
// Block entry (label_entry_8)
CallInst* int32_9 = CallInst::Create(func_test1, "", label_entry_8);
int32_9->setCallingConv(CallingConv::C);
- int32_9->setTailCall(false);AttributeSet int32_9_PAL;
+ int32_9->setTailCall(false);
+ AttributeList int32_9_PAL;
int32_9->setAttributes(int32_9_PAL);
ReturnInst::Create(Context, int32_9, label_entry_8);
diff --git a/unittests/IR/MetadataTest.cpp b/unittests/IR/MetadataTest.cpp
index 7bb8d4010d38a..103ba4c92ddf1 100644
--- a/unittests/IR/MetadataTest.cpp
+++ b/unittests/IR/MetadataTest.cpp
@@ -95,7 +95,7 @@ protected:
return DICompileUnit::getDistinct(Context, 1, getFile(), "clang", false,
"-g", 2, "", DICompileUnit::FullDebug,
getTuple(), getTuple(), getTuple(),
- getTuple(), getTuple(), 0, true);
+ getTuple(), getTuple(), 0, true, false);
}
DIType *getBasicType(StringRef Name) {
return DIBasicType::get(Context, dwarf::DW_TAG_unspecified_type, Name);
@@ -103,7 +103,7 @@ protected:
DIType *getDerivedType() {
return DIDerivedType::getDistinct(
Context, dwarf::DW_TAG_pointer_type, "", nullptr, 0, nullptr,
- getBasicType("basictype"), 1, 2, 0, DINode::FlagZero);
+ getBasicType("basictype"), 1, 2, 0, None, DINode::FlagZero);
}
Constant *getConstant() {
return ConstantInt::get(Type::getInt32Ty(Context), Counter++);
@@ -1053,12 +1053,14 @@ TEST_F(DIDerivedTypeTest, get) {
DIScope *Scope = getSubprogram();
DIType *BaseType = getBasicType("basic");
MDTuple *ExtraData = getTuple();
+ unsigned DWARFAddressSpace = 8;
DINode::DIFlags Flags5 = static_cast<DINode::DIFlags>(5);
DINode::DIFlags Flags4 = static_cast<DINode::DIFlags>(4);
auto *N =
DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type, "something", File,
- 1, Scope, BaseType, 2, 3, 4, Flags5, ExtraData);
+ 1, Scope, BaseType, 2, 3, 4, DWARFAddressSpace, Flags5,
+ ExtraData);
EXPECT_EQ(dwarf::DW_TAG_pointer_type, N->getTag());
EXPECT_EQ("something", N->getName());
EXPECT_EQ(File, N->getFile());
@@ -1068,45 +1070,51 @@ TEST_F(DIDerivedTypeTest, get) {
EXPECT_EQ(2u, N->getSizeInBits());
EXPECT_EQ(3u, N->getAlignInBits());
EXPECT_EQ(4u, N->getOffsetInBits());
+ EXPECT_EQ(DWARFAddressSpace, N->getDWARFAddressSpace().getValue());
EXPECT_EQ(5u, N->getFlags());
EXPECT_EQ(ExtraData, N->getExtraData());
EXPECT_EQ(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type,
"something", File, 1, Scope, BaseType, 2, 3,
- 4, Flags5, ExtraData));
+ 4, DWARFAddressSpace, Flags5, ExtraData));
EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_reference_type,
"something", File, 1, Scope, BaseType, 2, 3,
- 4, Flags5, ExtraData));
+ 4, DWARFAddressSpace, Flags5, ExtraData));
EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type, "else",
- File, 1, Scope, BaseType, 2, 3, 4, Flags5,
- ExtraData));
+ File, 1, Scope, BaseType, 2, 3,
+ 4, DWARFAddressSpace, Flags5, ExtraData));
EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type,
"something", getFile(), 1, Scope, BaseType, 2,
- 3, 4, Flags5, ExtraData));
+ 3, 4, DWARFAddressSpace, Flags5, ExtraData));
EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type,
"something", File, 2, Scope, BaseType, 2, 3,
- 4, Flags5, ExtraData));
+ 4, DWARFAddressSpace, Flags5, ExtraData));
EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type,
"something", File, 1, getSubprogram(),
- BaseType, 2, 3, 4, Flags5, ExtraData));
+ BaseType, 2, 3, 4, DWARFAddressSpace, Flags5,
+ ExtraData));
EXPECT_NE(N, DIDerivedType::get(
Context, dwarf::DW_TAG_pointer_type, "something", File, 1,
- Scope, getBasicType("basic2"), 2, 3, 4, Flags5, ExtraData));
+ Scope, getBasicType("basic2"), 2, 3, 4, DWARFAddressSpace,
+ Flags5, ExtraData));
EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type,
"something", File, 1, Scope, BaseType, 3, 3,
- 4, Flags5, ExtraData));
+ 4, DWARFAddressSpace, Flags5, ExtraData));
EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type,
"something", File, 1, Scope, BaseType, 2, 2,
- 4, Flags5, ExtraData));
+ 4, DWARFAddressSpace, Flags5, ExtraData));
+ EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type,
+ "something", File, 1, Scope, BaseType, 2, 3,
+ 5, DWARFAddressSpace, Flags5, ExtraData));
EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type,
"something", File, 1, Scope, BaseType, 2, 3,
- 5, Flags5, ExtraData));
+ 4, DWARFAddressSpace + 1, Flags5, ExtraData));
EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type,
"something", File, 1, Scope, BaseType, 2, 3,
- 4, Flags4, ExtraData));
+ 4, DWARFAddressSpace, Flags4, ExtraData));
EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type,
"something", File, 1, Scope, BaseType, 2, 3,
- 4, Flags5, getTuple()));
+ 4, DWARFAddressSpace, Flags5, getTuple()));
TempDIDerivedType Temp = N->clone();
EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp)));
@@ -1121,10 +1129,12 @@ TEST_F(DIDerivedTypeTest, getWithLargeValues) {
auto *N = DIDerivedType::get(
Context, dwarf::DW_TAG_pointer_type, "something", File, 1, Scope,
- BaseType, UINT64_MAX, UINT32_MAX - 1, UINT64_MAX - 2, Flags, ExtraData);
+ BaseType, UINT64_MAX, UINT32_MAX - 1, UINT64_MAX - 2, UINT32_MAX - 3,
+ Flags, ExtraData);
EXPECT_EQ(UINT64_MAX, N->getSizeInBits());
EXPECT_EQ(UINT32_MAX - 1, N->getAlignInBits());
EXPECT_EQ(UINT64_MAX - 2, N->getOffsetInBits());
+ EXPECT_EQ(UINT32_MAX - 3, N->getDWARFAddressSpace().getValue());
}
typedef MetadataTest DICompositeTypeTest;
@@ -1406,7 +1416,8 @@ TEST_F(DICompileUnitTest, get) {
auto *N = DICompileUnit::getDistinct(
Context, SourceLanguage, File, Producer, IsOptimized, Flags,
RuntimeVersion, SplitDebugFilename, EmissionKind, EnumTypes,
- RetainedTypes, GlobalVariables, ImportedEntities, Macros, DWOId, true);
+ RetainedTypes, GlobalVariables, ImportedEntities, Macros, DWOId, true,
+ false);
EXPECT_EQ(dwarf::DW_TAG_compile_unit, N->getTag());
EXPECT_EQ(SourceLanguage, N->getSourceLanguage());
@@ -1463,7 +1474,7 @@ TEST_F(DICompileUnitTest, replaceArrays) {
auto *N = DICompileUnit::getDistinct(
Context, SourceLanguage, File, Producer, IsOptimized, Flags,
RuntimeVersion, SplitDebugFilename, EmissionKind, EnumTypes,
- RetainedTypes, nullptr, ImportedEntities, nullptr, DWOId, true);
+ RetainedTypes, nullptr, ImportedEntities, nullptr, DWOId, true, false);
auto *GlobalVariables = MDTuple::getDistinct(Context, None);
EXPECT_EQ(nullptr, N->getGlobalVariables().get());
diff --git a/unittests/IR/ValueHandleTest.cpp b/unittests/IR/ValueHandleTest.cpp
index 59cd9d7ba37ae..1abc87c2fdc7f 100644
--- a/unittests/IR/ValueHandleTest.cpp
+++ b/unittests/IR/ValueHandleTest.cpp
@@ -412,4 +412,97 @@ TEST_F(ValueHandle, AssertingVHCheckedLast) {
BitcastV.reset();
}
+TEST_F(ValueHandle, PoisoningVH_BasicOperation) {
+ PoisoningVH<CastInst> VH(BitcastV.get());
+ CastInst *implicit_to_exact_type = VH;
+ (void)implicit_to_exact_type; // Avoid warning.
+
+ PoisoningVH<Value> GenericVH(BitcastV.get());
+ EXPECT_EQ(BitcastV.get(), GenericVH);
+ GenericVH = ConstantV;
+ EXPECT_EQ(ConstantV, GenericVH);
+
+ // Make sure I can call a method on the underlying CastInst. It
+ // doesn't matter which method.
+ EXPECT_FALSE(VH->mayWriteToMemory());
+ EXPECT_FALSE((*VH).mayWriteToMemory());
+}
+
+TEST_F(ValueHandle, PoisoningVH_Const) {
+ const CastInst *ConstBitcast = BitcastV.get();
+ PoisoningVH<const CastInst> VH(ConstBitcast);
+ const CastInst *implicit_to_exact_type = VH;
+ (void)implicit_to_exact_type; // Avoid warning.
+}
+
+TEST_F(ValueHandle, PoisoningVH_Comparisons) {
+ PoisoningVH<Value> BitcastVH(BitcastV.get());
+ PoisoningVH<Value> ConstantVH(ConstantV);
+
+ EXPECT_TRUE(BitcastVH == BitcastVH);
+ EXPECT_TRUE(BitcastV.get() == BitcastVH);
+ EXPECT_TRUE(BitcastVH == BitcastV.get());
+ EXPECT_FALSE(BitcastVH == ConstantVH);
+
+ EXPECT_TRUE(BitcastVH != ConstantVH);
+ EXPECT_TRUE(BitcastV.get() != ConstantVH);
+ EXPECT_TRUE(BitcastVH != ConstantV);
+ EXPECT_FALSE(BitcastVH != BitcastVH);
+
+ // Cast to Value* so comparisons work.
+ Value *BV = BitcastV.get();
+ Value *CV = ConstantV;
+ EXPECT_EQ(BV < CV, BitcastVH < ConstantVH);
+ EXPECT_EQ(BV <= CV, BitcastVH <= ConstantVH);
+ EXPECT_EQ(BV > CV, BitcastVH > ConstantVH);
+ EXPECT_EQ(BV >= CV, BitcastVH >= ConstantVH);
+
+ EXPECT_EQ(BV < CV, BitcastV.get() < ConstantVH);
+ EXPECT_EQ(BV <= CV, BitcastV.get() <= ConstantVH);
+ EXPECT_EQ(BV > CV, BitcastV.get() > ConstantVH);
+ EXPECT_EQ(BV >= CV, BitcastV.get() >= ConstantVH);
+
+ EXPECT_EQ(BV < CV, BitcastVH < ConstantV);
+ EXPECT_EQ(BV <= CV, BitcastVH <= ConstantV);
+ EXPECT_EQ(BV > CV, BitcastVH > ConstantV);
+ EXPECT_EQ(BV >= CV, BitcastVH >= ConstantV);
+}
+
+TEST_F(ValueHandle, PoisoningVH_DoesNotFollowRAUW) {
+ PoisoningVH<Value> VH(BitcastV.get());
+ BitcastV->replaceAllUsesWith(ConstantV);
+ EXPECT_TRUE(DenseMapInfo<PoisoningVH<Value>>::isEqual(VH, BitcastV.get()));
+}
+
+#ifdef NDEBUG
+
+TEST_F(ValueHandle, PoisoningVH_ReducesToPointer) {
+ EXPECT_EQ(sizeof(CastInst *), sizeof(PoisoningVH<CastInst>));
+}
+
+#else // !NDEBUG
+
+#ifdef GTEST_HAS_DEATH_TEST
+
+TEST_F(ValueHandle, PoisoningVH_Asserts) {
+ PoisoningVH<Value> VH(BitcastV.get());
+
+ // The poisoned handle shouldn't assert when the value is deleted.
+ BitcastV.reset(new BitCastInst(ConstantV, Type::getInt32Ty(Context)));
+ // But should when we access the handle.
+ EXPECT_DEATH((void)*VH, "Accessed a poisoned value handle!");
+
+ // Now check that poison catches RAUW.
+ VH = BitcastV.get();
+ // The replace doesn't trigger anything immediately.
+ BitcastV->replaceAllUsesWith(ConstantV);
+ // But a use does.
+ EXPECT_DEATH((void)*VH, "Accessed a poisoned value handle!");
+
+ // Don't clear anything out here as destroying the handles should be fine.
+}
+
+#endif // GTEST_HAS_DEATH_TEST
+
+#endif // NDEBUG
}
diff --git a/unittests/IR/ValueTest.cpp b/unittests/IR/ValueTest.cpp
index 607b7a1bd2c9b..142444a809c6d 100644
--- a/unittests/IR/ValueTest.cpp
+++ b/unittests/IR/ValueTest.cpp
@@ -40,7 +40,7 @@ TEST(ValueTest, UsedInBasicBlock) {
Function *F = M->getFunction("f");
EXPECT_FALSE(F->isUsedInBasicBlock(&F->front()));
- EXPECT_TRUE((++F->arg_begin())->isUsedInBasicBlock(&F->front()));
+ EXPECT_TRUE(std::next(F->arg_begin())->isUsedInBasicBlock(&F->front()));
EXPECT_TRUE(F->arg_begin()->isUsedInBasicBlock(&F->front()));
}
diff --git a/unittests/IR/VerifierTest.cpp b/unittests/IR/VerifierTest.cpp
index ad6940afd05ef..188509aadf77a 100644
--- a/unittests/IR/VerifierTest.cpp
+++ b/unittests/IR/VerifierTest.cpp
@@ -52,9 +52,9 @@ TEST(VerifierTest, InvalidRetAttribute) {
Module M("M", C);
FunctionType *FTy = FunctionType::get(Type::getInt32Ty(C), /*isVarArg=*/false);
Function *F = cast<Function>(M.getOrInsertFunction("foo", FTy));
- AttributeSet AS = F->getAttributes();
- F->setAttributes(AS.addAttribute(C, AttributeSet::ReturnIndex,
- Attribute::UWTable));
+ AttributeList AS = F->getAttributes();
+ F->setAttributes(
+ AS.addAttribute(C, AttributeList::ReturnIndex, Attribute::UWTable));
std::string Error;
raw_string_ostream ErrorOS(Error);
diff --git a/unittests/Linker/LinkModulesTest.cpp b/unittests/Linker/LinkModulesTest.cpp
index 92c483278be9d..f31409c501211 100644
--- a/unittests/Linker/LinkModulesTest.cpp
+++ b/unittests/Linker/LinkModulesTest.cpp
@@ -317,34 +317,34 @@ TEST_F(LinkModuleTest, RemangleIntrinsics) {
const char *FooStr =
"%struct.rtx_def = type { i16 }\n"
"define void @foo(%struct.rtx_def* %a, i8 %b, i32 %c) {\n"
- " call void @llvm.memset.p0struct.rtx_def.i32(%struct.rtx_def* %a, i8 %b, i32 %c, i32 4, i1 true)\n"
+ " call void @llvm.memset.p0s_struct.rtx_defs.i32(%struct.rtx_def* %a, i8 %b, i32 %c, i32 4, i1 true)\n"
" ret void\n"
"}\n"
- "declare void @llvm.memset.p0struct.rtx_def.i32(%struct.rtx_def*, i8, i32, i32, i1)\n";
+ "declare void @llvm.memset.p0s_struct.rtx_defs.i32(%struct.rtx_def*, i8, i32, i32, i1)\n";
const char *BarStr =
"%struct.rtx_def = type { i16 }\n"
"define void @bar(%struct.rtx_def* %a, i8 %b, i32 %c) {\n"
- " call void @llvm.memset.p0struct.rtx_def.i32(%struct.rtx_def* %a, i8 %b, i32 %c, i32 4, i1 true)\n"
+ " call void @llvm.memset.p0s_struct.rtx_defs.i32(%struct.rtx_def* %a, i8 %b, i32 %c, i32 4, i1 true)\n"
" ret void\n"
"}\n"
- "declare void @llvm.memset.p0struct.rtx_def.i32(%struct.rtx_def*, i8, i32, i32, i1)\n";
+ "declare void @llvm.memset.p0s_struct.rtx_defs.i32(%struct.rtx_def*, i8, i32, i32, i1)\n";
std::unique_ptr<Module> Foo = parseAssemblyString(FooStr, Err, C);
assert(Foo);
ASSERT_TRUE(Foo.get());
// Foo is loaded first, so the type and the intrinsic have theis original
// names.
- ASSERT_TRUE(Foo->getFunction("llvm.memset.p0struct.rtx_def.i32"));
- ASSERT_FALSE(Foo->getFunction("llvm.memset.p0struct.rtx_def.0.i32"));
+ ASSERT_TRUE(Foo->getFunction("llvm.memset.p0s_struct.rtx_defs.i32"));
+ ASSERT_FALSE(Foo->getFunction("llvm.memset.p0s_struct.rtx_defs.0.i32"));
std::unique_ptr<Module> Bar = parseAssemblyString(BarStr, Err, C);
assert(Bar);
ASSERT_TRUE(Bar.get());
// Bar is loaded after Foo, so the type is renamed to struct.rtx_def.0. Check
// that the intrinsic is also renamed.
- ASSERT_FALSE(Bar->getFunction("llvm.memset.p0struct.rtx_def.i32"));
- ASSERT_TRUE(Bar->getFunction("llvm.memset.p0struct.rtx_def.0.i32"));
+ ASSERT_FALSE(Bar->getFunction("llvm.memset.p0s_struct.rtx_defs.i32"));
+ ASSERT_TRUE(Bar->getFunction("llvm.memset.p0s_struct.rtx_def.0s.i32"));
// Link two modules together.
auto Dst = llvm::make_unique<Module>("Linked", C);
@@ -356,7 +356,7 @@ TEST_F(LinkModuleTest, RemangleIntrinsics) {
// "struct.rtx_def" from Foo and "struct.rtx_def.0" from Bar are isomorphic
// types, so they must be uniquified by linker. Check that they use the same
// intrinsic definition.
- Function *F = Foo->getFunction("llvm.memset.p0struct.rtx_def.i32");
+ Function *F = Foo->getFunction("llvm.memset.p0s_struct.rtx_defs.i32");
ASSERT_EQ(F->getNumUses(), (unsigned)2);
}
diff --git a/unittests/MI/LiveIntervalTest.cpp b/unittests/MI/LiveIntervalTest.cpp
index 1d6df97a32007..026fb42d345f7 100644
--- a/unittests/MI/LiveIntervalTest.cpp
+++ b/unittests/MI/LiveIntervalTest.cpp
@@ -142,15 +142,15 @@ static void liveIntervalTest(StringRef MIRFunc, LiveIntervalTest T) {
legacy::PassManager PM;
SmallString<160> S;
- StringRef MIRString = (Twine(
-"---\n"
-"...\n"
-"name: func\n"
-"registers:\n"
-" - { id: 0, class: sreg_64 }\n"
-"body: |\n"
-" bb.0:\n"
- ) + Twine(MIRFunc) + Twine("...\n")).toNullTerminatedStringRef(S);
+ StringRef MIRString = (Twine(R"MIR(
+---
+...
+name: func
+registers:
+ - { id: 0, class: sreg_64 }
+body: |
+ bb.0:
+)MIR") + Twine(MIRFunc) + Twine("...\n")).toNullTerminatedStringRef(S);
std::unique_ptr<MIRParser> MIR;
std::unique_ptr<Module> M = parseMIR(Context, PM, MIR, *TM, MIRString,
"func");
@@ -167,66 +167,66 @@ INITIALIZE_PASS(TestPass, "testpass", "testpass", false, false)
TEST(LiveIntervalTest, MoveUpDef) {
// Value defined.
- liveIntervalTest(
-" S_NOP 0\n"
-" S_NOP 0\n"
-" early-clobber %0 = IMPLICIT_DEF\n"
-" S_NOP 0, implicit %0\n",
- [](MachineFunction &MF, LiveIntervals &LIS) {
+ liveIntervalTest(R"MIR(
+ S_NOP 0
+ S_NOP 0
+ early-clobber %0 = IMPLICIT_DEF
+ S_NOP 0, implicit %0
+)MIR", [](MachineFunction &MF, LiveIntervals &LIS) {
testHandleMove(MF, LIS, 2, 1);
});
}
TEST(LiveIntervalTest, MoveUpRedef) {
- liveIntervalTest(
-" %0 = IMPLICIT_DEF\n"
-" S_NOP 0\n"
-" %0 = IMPLICIT_DEF implicit %0(tied-def 0)\n"
-" S_NOP 0, implicit %0\n",
- [](MachineFunction &MF, LiveIntervals &LIS) {
+ liveIntervalTest(R"MIR(
+ %0 = IMPLICIT_DEF
+ S_NOP 0
+ %0 = IMPLICIT_DEF implicit %0(tied-def 0)
+ S_NOP 0, implicit %0
+)MIR", [](MachineFunction &MF, LiveIntervals &LIS) {
testHandleMove(MF, LIS, 2, 1);
});
}
TEST(LiveIntervalTest, MoveUpEarlyDef) {
- liveIntervalTest(
-" S_NOP 0\n"
-" S_NOP 0\n"
-" early-clobber %0 = IMPLICIT_DEF\n"
-" S_NOP 0, implicit %0\n",
- [](MachineFunction &MF, LiveIntervals &LIS) {
+ liveIntervalTest(R"MIR(
+ S_NOP 0
+ S_NOP 0
+ early-clobber %0 = IMPLICIT_DEF
+ S_NOP 0, implicit %0
+)MIR", [](MachineFunction &MF, LiveIntervals &LIS) {
testHandleMove(MF, LIS, 2, 1);
});
}
TEST(LiveIntervalTest, MoveUpEarlyRedef) {
- liveIntervalTest(
-" %0 = IMPLICIT_DEF\n"
-" S_NOP 0\n"
-" early-clobber %0 = IMPLICIT_DEF implicit %0(tied-def 0)\n"
-" S_NOP 0, implicit %0\n",
- [](MachineFunction &MF, LiveIntervals &LIS) {
+ liveIntervalTest(R"MIR(
+ %0 = IMPLICIT_DEF
+ S_NOP 0
+ early-clobber %0 = IMPLICIT_DEF implicit %0(tied-def 0)
+ S_NOP 0, implicit %0
+)MIR", [](MachineFunction &MF, LiveIntervals &LIS) {
testHandleMove(MF, LIS, 2, 1);
});
}
TEST(LiveIntervalTest, MoveUpKill) {
- liveIntervalTest(
-" %0 = IMPLICIT_DEF\n"
-" S_NOP 0\n"
-" S_NOP 0, implicit %0\n",
- [](MachineFunction &MF, LiveIntervals &LIS) {
+ liveIntervalTest(R"MIR(
+ %0 = IMPLICIT_DEF
+ S_NOP 0
+ S_NOP 0, implicit %0
+)MIR", [](MachineFunction &MF, LiveIntervals &LIS) {
testHandleMove(MF, LIS, 2, 1);
});
}
TEST(LiveIntervalTest, MoveUpKillFollowing) {
- liveIntervalTest(
-" %0 = IMPLICIT_DEF\n"
-" S_NOP 0\n"
-" S_NOP 0, implicit %0\n"
-" S_NOP 0, implicit %0\n",
- [](MachineFunction &MF, LiveIntervals &LIS) {
+ liveIntervalTest(R"MIR(
+ %0 = IMPLICIT_DEF
+ S_NOP 0
+ S_NOP 0, implicit %0
+ S_NOP 0, implicit %0
+)MIR", [](MachineFunction &MF, LiveIntervals &LIS) {
testHandleMove(MF, LIS, 2, 1);
});
}
@@ -236,77 +236,77 @@ TEST(LiveIntervalTest, MoveUpKillFollowing) {
TEST(LiveIntervalTest, MoveDownDef) {
// Value defined.
- liveIntervalTest(
-" S_NOP 0\n"
-" early-clobber %0 = IMPLICIT_DEF\n"
-" S_NOP 0\n"
-" S_NOP 0, implicit %0\n",
- [](MachineFunction &MF, LiveIntervals &LIS) {
+ liveIntervalTest(R"MIR(
+ S_NOP 0
+ early-clobber %0 = IMPLICIT_DEF
+ S_NOP 0
+ S_NOP 0, implicit %0
+)MIR", [](MachineFunction &MF, LiveIntervals &LIS) {
testHandleMove(MF, LIS, 1, 2);
});
}
TEST(LiveIntervalTest, MoveDownRedef) {
- liveIntervalTest(
-" %0 = IMPLICIT_DEF\n"
-" %0 = IMPLICIT_DEF implicit %0(tied-def 0)\n"
-" S_NOP 0\n"
-" S_NOP 0, implicit %0\n",
- [](MachineFunction &MF, LiveIntervals &LIS) {
+ liveIntervalTest(R"MIR(
+ %0 = IMPLICIT_DEF
+ %0 = IMPLICIT_DEF implicit %0(tied-def 0)
+ S_NOP 0
+ S_NOP 0, implicit %0
+)MIR", [](MachineFunction &MF, LiveIntervals &LIS) {
testHandleMove(MF, LIS, 1, 2);
});
}
TEST(LiveIntervalTest, MoveDownEarlyDef) {
- liveIntervalTest(
-" S_NOP 0\n"
-" early-clobber %0 = IMPLICIT_DEF\n"
-" S_NOP 0\n"
-" S_NOP 0, implicit %0\n",
- [](MachineFunction &MF, LiveIntervals &LIS) {
+ liveIntervalTest(R"MIR(
+ S_NOP 0
+ early-clobber %0 = IMPLICIT_DEF
+ S_NOP 0
+ S_NOP 0, implicit %0
+)MIR", [](MachineFunction &MF, LiveIntervals &LIS) {
testHandleMove(MF, LIS, 1, 2);
});
}
TEST(LiveIntervalTest, MoveDownEarlyRedef) {
- liveIntervalTest(
-" %0 = IMPLICIT_DEF\n"
-" early-clobber %0 = IMPLICIT_DEF implicit %0(tied-def 0)\n"
-" S_NOP 0\n"
-" S_NOP 0, implicit %0\n",
- [](MachineFunction &MF, LiveIntervals &LIS) {
+ liveIntervalTest(R"MIR(
+ %0 = IMPLICIT_DEF
+ early-clobber %0 = IMPLICIT_DEF implicit %0(tied-def 0)
+ S_NOP 0
+ S_NOP 0, implicit %0
+)MIR", [](MachineFunction &MF, LiveIntervals &LIS) {
testHandleMove(MF, LIS, 1, 2);
});
}
TEST(LiveIntervalTest, MoveDownKill) {
- liveIntervalTest(
-" %0 = IMPLICIT_DEF\n"
-" S_NOP 0, implicit %0\n"
-" S_NOP 0\n",
- [](MachineFunction &MF, LiveIntervals &LIS) {
+ liveIntervalTest(R"MIR(
+ %0 = IMPLICIT_DEF
+ S_NOP 0, implicit %0
+ S_NOP 0
+)MIR", [](MachineFunction &MF, LiveIntervals &LIS) {
testHandleMove(MF, LIS, 1, 2);
});
}
TEST(LiveIntervalTest, MoveDownKillFollowing) {
- liveIntervalTest(
-" %0 = IMPLICIT_DEF\n"
-" S_NOP 0\n"
-" S_NOP 0, implicit %0\n"
-" S_NOP 0, implicit %0\n",
- [](MachineFunction &MF, LiveIntervals &LIS) {
+ liveIntervalTest(R"MIR(
+ %0 = IMPLICIT_DEF
+ S_NOP 0
+ S_NOP 0, implicit %0
+ S_NOP 0, implicit %0
+)MIR", [](MachineFunction &MF, LiveIntervals &LIS) {
testHandleMove(MF, LIS, 1, 2);
});
}
TEST(LiveIntervalTest, MoveUndefUse) {
- liveIntervalTest(
-" %0 = IMPLICIT_DEF\n"
-" S_NOP 0, implicit undef %0\n"
-" S_NOP 0, implicit %0\n"
-" S_NOP 0\n",
- [](MachineFunction &MF, LiveIntervals &LIS) {
+ liveIntervalTest(R"MIR(
+ %0 = IMPLICIT_DEF
+ S_NOP 0, implicit undef %0
+ S_NOP 0, implicit %0
+ S_NOP 0
+)MIR", [](MachineFunction &MF, LiveIntervals &LIS) {
testHandleMove(MF, LIS, 1, 3);
});
}
@@ -315,44 +315,44 @@ TEST(LiveIntervalTest, MoveUpValNos) {
// handleMoveUp() had a bug where it would reuse the value number of the
// destination segment, even though we have no guarntee that this valno wasn't
// used in other segments.
- liveIntervalTest(
-" successors: %bb.1, %bb.2\n"
-" %0 = IMPLICIT_DEF\n"
-" S_CBRANCH_VCCNZ %bb.2, implicit undef %vcc\n"
-" S_BRANCH %bb.1\n"
-" bb.2:\n"
-" S_NOP 0, implicit %0\n"
-" bb.1:\n"
-" successors: %bb.2\n"
-" %0 = IMPLICIT_DEF implicit %0(tied-def 0)\n"
-" %0 = IMPLICIT_DEF implicit %0(tied-def 0)\n"
-" %0 = IMPLICIT_DEF implicit %0(tied-def 0)\n"
-" S_BRANCH %bb.2\n",
- [](MachineFunction &MF, LiveIntervals &LIS) {
+ liveIntervalTest(R"MIR(
+ successors: %bb.1, %bb.2
+ %0 = IMPLICIT_DEF
+ S_CBRANCH_VCCNZ %bb.2, implicit undef %vcc
+ S_BRANCH %bb.1
+ bb.2:
+ S_NOP 0, implicit %0
+ bb.1:
+ successors: %bb.2
+ %0 = IMPLICIT_DEF implicit %0(tied-def 0)
+ %0 = IMPLICIT_DEF implicit %0(tied-def 0)
+ %0 = IMPLICIT_DEF implicit %0(tied-def 0)
+ S_BRANCH %bb.2
+)MIR", [](MachineFunction &MF, LiveIntervals &LIS) {
testHandleMove(MF, LIS, 2, 0, 2);
});
}
TEST(LiveIntervalTest, MoveOverUndefUse0) {
// findLastUseBefore() used by handleMoveUp() must ignore undef operands.
- liveIntervalTest(
-" %0 = IMPLICIT_DEF\n"
-" S_NOP 0\n"
-" S_NOP 0, implicit undef %0\n"
-" %0 = IMPLICIT_DEF implicit %0(tied-def 0)\n",
- [](MachineFunction &MF, LiveIntervals &LIS) {
+ liveIntervalTest(R"MIR(
+ %0 = IMPLICIT_DEF
+ S_NOP 0
+ S_NOP 0, implicit undef %0
+ %0 = IMPLICIT_DEF implicit %0(tied-def 0)
+)MIR", [](MachineFunction &MF, LiveIntervals &LIS) {
testHandleMove(MF, LIS, 3, 1);
});
}
TEST(LiveIntervalTest, MoveOverUndefUse1) {
// findLastUseBefore() used by handleMoveUp() must ignore undef operands.
- liveIntervalTest(
-" %sgpr0 = IMPLICIT_DEF\n"
-" S_NOP 0\n"
-" S_NOP 0, implicit undef %sgpr0\n"
-" %sgpr0 = IMPLICIT_DEF implicit %sgpr0(tied-def 0)\n",
- [](MachineFunction &MF, LiveIntervals &LIS) {
+ liveIntervalTest(R"MIR(
+ %sgpr0 = IMPLICIT_DEF
+ S_NOP 0
+ S_NOP 0, implicit undef %sgpr0
+ %sgpr0 = IMPLICIT_DEF implicit %sgpr0(tied-def 0)
+)MIR", [](MachineFunction &MF, LiveIntervals &LIS) {
testHandleMove(MF, LIS, 3, 1);
});
}
@@ -360,21 +360,21 @@ TEST(LiveIntervalTest, MoveOverUndefUse1) {
TEST(LiveIntervalTest, SubRegMoveDown) {
// Subregister ranges can have holes inside a basic block. Check for a
// movement of the form 32->150 in a liverange [16, 32) [100,200).
- liveIntervalTest(
-" successors: %bb.1, %bb.2\n"
-" %0 = IMPLICIT_DEF\n"
-" S_CBRANCH_VCCNZ %bb.2, implicit undef %vcc\n"
-" S_BRANCH %bb.1\n"
-" bb.2:\n"
-" successors: %bb.1\n"
-" S_NOP 0, implicit %0.sub0\n"
-" S_NOP 0, implicit %0.sub1\n"
-" S_NOP 0\n"
-" undef %0.sub0 = IMPLICIT_DEF\n"
-" %0.sub1 = IMPLICIT_DEF\n"
-" bb.1:\n"
-" S_NOP 0, implicit %0\n",
- [](MachineFunction &MF, LiveIntervals &LIS) {
+ liveIntervalTest(R"MIR(
+ successors: %bb.1, %bb.2
+ %0 = IMPLICIT_DEF
+ S_CBRANCH_VCCNZ %bb.2, implicit undef %vcc
+ S_BRANCH %bb.1
+ bb.2:
+ successors: %bb.1
+ S_NOP 0, implicit %0.sub0
+ S_NOP 0, implicit %0.sub1
+ S_NOP 0
+ undef %0.sub0 = IMPLICIT_DEF
+ %0.sub1 = IMPLICIT_DEF
+ bb.1:
+ S_NOP 0, implicit %0
+)MIR", [](MachineFunction &MF, LiveIntervals &LIS) {
// Scheduler behaviour: Clear def,read-undef flag and move.
MachineInstr &MI = getMI(MF, 3, /*BlockNum=*/1);
MI.getOperand(0).setIsUndef(false);
@@ -382,6 +382,24 @@ TEST(LiveIntervalTest, SubRegMoveDown) {
});
}
+TEST(LiveIntervalTest, SubRegMoveUp) {
+ // handleMoveUp had a bug not updating valno of segment incoming to bb.2
+ // after swapping subreg definitions.
+ liveIntervalTest(R"MIR(
+ successors: %bb.1, %bb.2
+ undef %0.sub0 = IMPLICIT_DEF
+ %0.sub1 = IMPLICIT_DEF
+ S_CBRANCH_VCCNZ %bb.2, implicit undef %vcc
+ S_BRANCH %bb.1
+ bb.1:
+ S_NOP 0, implicit %0.sub1
+ bb.2:
+ S_NOP 0, implicit %0.sub1
+)MIR", [](MachineFunction &MF, LiveIntervals &LIS) {
+ testHandleMove(MF, LIS, 1, 0);
+ });
+}
+
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
initLLVM();
diff --git a/unittests/Object/CMakeLists.txt b/unittests/Object/CMakeLists.txt
index 7a63c167a30b9..e1376bffbc0f5 100644
--- a/unittests/Object/CMakeLists.txt
+++ b/unittests/Object/CMakeLists.txt
@@ -4,5 +4,6 @@ set(LLVM_LINK_COMPONENTS
add_llvm_unittest(ObjectTests
SymbolSizeTest.cpp
+ SymbolicFileTest.cpp
)
diff --git a/unittests/Object/SymbolicFileTest.cpp b/unittests/Object/SymbolicFileTest.cpp
new file mode 100644
index 0000000000000..ec954e5e67d08
--- /dev/null
+++ b/unittests/Object/SymbolicFileTest.cpp
@@ -0,0 +1,42 @@
+//===- SymbolicFileTest.cpp - Tests for SymbolicFile.cpp ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Object/SymbolicFile.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/raw_ostream.h"
+#include "gtest/gtest.h"
+#include <sstream>
+
+TEST(Object, DataRefImplOstream) {
+ std::string s;
+ llvm::raw_string_ostream OS(s);
+ llvm::object::DataRefImpl Data;
+ Data.d.a = 0xeeee0000;
+ Data.d.b = 0x0000ffff;
+
+ static_assert(sizeof Data.p == sizeof(uint64_t) ||
+ sizeof Data.p == sizeof(uint32_t),
+ "Test expected pointer type to be 32 or 64-bit.");
+
+ char const *Expected;
+
+ if (sizeof Data.p == sizeof(uint64_t)) {
+ Expected = llvm::sys::IsLittleEndianHost
+ ? "(0xffffeeee0000 (0xeeee0000, 0x0000ffff))"
+ : "(0xeeee00000000ffff (0xeeee0000, 0x0000ffff))";
+ }
+ else {
+ Expected = "(0xeeee0000 (0xeeee0000, 0x0000ffff))";
+ }
+
+ OS << Data;
+ OS.flush();
+
+ EXPECT_EQ(Expected, s);
+}
diff --git a/unittests/Option/OptionParsingTest.cpp b/unittests/Option/OptionParsingTest.cpp
index b0418a71c7866..8630ff1d303c0 100644
--- a/unittests/Option/OptionParsingTest.cpp
+++ b/unittests/Option/OptionParsingTest.cpp
@@ -97,11 +97,11 @@ TEST(Option, OptionParsing) {
EXPECT_NE(std::string::npos, Help.find("-A"));
// Test aliases.
- arg_iterator Cs = AL.filtered_begin(OPT_C);
- ASSERT_NE(AL.filtered_end(), Cs);
- EXPECT_EQ("desu", StringRef((*Cs)->getValue()));
+ auto Cs = AL.filtered(OPT_C);
+ ASSERT_NE(Cs.begin(), Cs.end());
+ EXPECT_EQ("desu", StringRef((*Cs.begin())->getValue()));
ArgStringList ASL;
- (*Cs)->render(AL, ASL);
+ (*Cs.begin())->render(AL, ASL);
ASSERT_EQ(2u, ASL.size());
EXPECT_EQ("-C", StringRef(ASL[0]));
EXPECT_EQ("desu", StringRef(ASL[1]));
diff --git a/unittests/ProfileData/CoverageMappingTest.cpp b/unittests/ProfileData/CoverageMappingTest.cpp
index 49eab4ad7887a..0783a23a67b06 100644
--- a/unittests/ProfileData/CoverageMappingTest.cpp
+++ b/unittests/ProfileData/CoverageMappingTest.cpp
@@ -328,7 +328,7 @@ TEST_P(CoverageMappingTest, load_coverage_for_several_functions) {
loadCoverageMapping();
const auto FunctionRecords = LoadedCoverage->getCoveredFunctions();
- EXPECT_EQ(2U, std::distance(FunctionRecords.begin(), FunctionRecords.end()));
+ EXPECT_EQ(2, std::distance(FunctionRecords.begin(), FunctionRecords.end()));
for (const auto &FunctionRecord : FunctionRecords) {
CoverageData Data = LoadedCoverage->getCoverageForFunction(FunctionRecord);
std::vector<CoverageSegment> Segments(Data.begin(), Data.end());
diff --git a/unittests/Support/ARMAttributeParser.cpp b/unittests/Support/ARMAttributeParser.cpp
new file mode 100644
index 0000000000000..c2df6537ff63d
--- /dev/null
+++ b/unittests/Support/ARMAttributeParser.cpp
@@ -0,0 +1,385 @@
+#include "llvm/Support/ARMBuildAttributes.h"
+#include "llvm/Support/ARMAttributeParser.h"
+#include "llvm/Support/LEB128.h"
+#include "gtest/gtest.h"
+#include <string>
+
+using namespace llvm;
+
+struct AttributeSection {
+ unsigned Tag;
+ unsigned Value;
+
+ AttributeSection(unsigned tag, unsigned value) : Tag(tag), Value(value) { }
+
+ void write(raw_ostream &OS) {
+ OS.flush();
+ // length = length + "aeabi\0" + TagFile + ByteSize + Tag + Value;
+ // length = 17 bytes
+
+ OS << 'A' << (uint8_t)17 << (uint8_t)0 << (uint8_t)0 << (uint8_t)0;
+ OS << "aeabi" << '\0';
+ OS << (uint8_t)1 << (uint8_t)7 << (uint8_t)0 << (uint8_t)0 << (uint8_t)0;
+ OS << (uint8_t)Tag << (uint8_t)Value;
+
+ }
+};
+
+bool testBuildAttr(unsigned Tag, unsigned Value,
+ unsigned ExpectedTag, unsigned ExpectedValue) {
+ std::string buffer;
+ raw_string_ostream OS(buffer);
+ AttributeSection Section(Tag, Value);
+ Section.write(OS);
+ ArrayRef<uint8_t> Bytes(
+ reinterpret_cast<const uint8_t*>(OS.str().c_str()), OS.str().size());
+
+ ARMAttributeParser Parser;
+ Parser.Parse(Bytes, true);
+
+ return (Parser.hasAttribute(ExpectedTag) &&
+ Parser.getAttributeValue(ExpectedTag) == ExpectedValue);
+}
+
+bool testTagString(unsigned Tag, const char *name) {
+ return ARMBuildAttrs::AttrTypeAsString(Tag).str() == name;
+}
+
+TEST(CPUArchBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(6, "Tag_CPU_arch"));
+
+ EXPECT_TRUE(testBuildAttr(6, 0, ARMBuildAttrs::CPU_arch,
+ ARMBuildAttrs::Pre_v4));
+ EXPECT_TRUE(testBuildAttr(6, 1, ARMBuildAttrs::CPU_arch,
+ ARMBuildAttrs::v4));
+ EXPECT_TRUE(testBuildAttr(6, 2, ARMBuildAttrs::CPU_arch,
+ ARMBuildAttrs::v4T));
+ EXPECT_TRUE(testBuildAttr(6, 3, ARMBuildAttrs::CPU_arch,
+ ARMBuildAttrs::v5T));
+ EXPECT_TRUE(testBuildAttr(6, 4, ARMBuildAttrs::CPU_arch,
+ ARMBuildAttrs::v5TE));
+ EXPECT_TRUE(testBuildAttr(6, 5, ARMBuildAttrs::CPU_arch,
+ ARMBuildAttrs::v5TEJ));
+ EXPECT_TRUE(testBuildAttr(6, 6, ARMBuildAttrs::CPU_arch,
+ ARMBuildAttrs::v6));
+ EXPECT_TRUE(testBuildAttr(6, 7, ARMBuildAttrs::CPU_arch,
+ ARMBuildAttrs::v6KZ));
+ EXPECT_TRUE(testBuildAttr(6, 8, ARMBuildAttrs::CPU_arch,
+ ARMBuildAttrs::v6T2));
+ EXPECT_TRUE(testBuildAttr(6, 9, ARMBuildAttrs::CPU_arch,
+ ARMBuildAttrs::v6K));
+ EXPECT_TRUE(testBuildAttr(6, 10, ARMBuildAttrs::CPU_arch,
+ ARMBuildAttrs::v7));
+ EXPECT_TRUE(testBuildAttr(6, 11, ARMBuildAttrs::CPU_arch,
+ ARMBuildAttrs::v6_M));
+ EXPECT_TRUE(testBuildAttr(6, 12, ARMBuildAttrs::CPU_arch,
+ ARMBuildAttrs::v6S_M));
+ EXPECT_TRUE(testBuildAttr(6, 13, ARMBuildAttrs::CPU_arch,
+ ARMBuildAttrs::v7E_M));
+}
+
+TEST(CPUArchProfileBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(7, "Tag_CPU_arch_profile"));
+ EXPECT_TRUE(testBuildAttr(7, 'A', ARMBuildAttrs::CPU_arch_profile,
+ ARMBuildAttrs::ApplicationProfile));
+ EXPECT_TRUE(testBuildAttr(7, 'R', ARMBuildAttrs::CPU_arch_profile,
+ ARMBuildAttrs::RealTimeProfile));
+ EXPECT_TRUE(testBuildAttr(7, 'M', ARMBuildAttrs::CPU_arch_profile,
+ ARMBuildAttrs::MicroControllerProfile));
+ EXPECT_TRUE(testBuildAttr(7, 'S', ARMBuildAttrs::CPU_arch_profile,
+ ARMBuildAttrs::SystemProfile));
+}
+
+TEST(ARMISABuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(8, "Tag_ARM_ISA_use"));
+ EXPECT_TRUE(testBuildAttr(8, 0, ARMBuildAttrs::ARM_ISA_use,
+ ARMBuildAttrs::Not_Allowed));
+ EXPECT_TRUE(testBuildAttr(8, 1, ARMBuildAttrs::ARM_ISA_use,
+ ARMBuildAttrs::Allowed));
+}
+
+TEST(ThumbISABuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(9, "Tag_THUMB_ISA_use"));
+ EXPECT_TRUE(testBuildAttr(9, 0, ARMBuildAttrs::THUMB_ISA_use,
+ ARMBuildAttrs::Not_Allowed));
+ EXPECT_TRUE(testBuildAttr(9, 1, ARMBuildAttrs::THUMB_ISA_use,
+ ARMBuildAttrs::Allowed));
+}
+
+TEST(FPArchBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(10, "Tag_FP_arch"));
+ EXPECT_TRUE(testBuildAttr(10, 0, ARMBuildAttrs::FP_arch,
+ ARMBuildAttrs::Not_Allowed));
+ EXPECT_TRUE(testBuildAttr(10, 1, ARMBuildAttrs::FP_arch,
+ ARMBuildAttrs::Allowed));
+ EXPECT_TRUE(testBuildAttr(10, 2, ARMBuildAttrs::FP_arch,
+ ARMBuildAttrs::AllowFPv2));
+ EXPECT_TRUE(testBuildAttr(10, 3, ARMBuildAttrs::FP_arch,
+ ARMBuildAttrs::AllowFPv3A));
+ EXPECT_TRUE(testBuildAttr(10, 4, ARMBuildAttrs::FP_arch,
+ ARMBuildAttrs::AllowFPv3B));
+ EXPECT_TRUE(testBuildAttr(10, 5, ARMBuildAttrs::FP_arch,
+ ARMBuildAttrs::AllowFPv4A));
+ EXPECT_TRUE(testBuildAttr(10, 6, ARMBuildAttrs::FP_arch,
+ ARMBuildAttrs::AllowFPv4B));
+ EXPECT_TRUE(testBuildAttr(10, 7, ARMBuildAttrs::FP_arch,
+ ARMBuildAttrs::AllowFPARMv8A));
+ EXPECT_TRUE(testBuildAttr(10, 8, ARMBuildAttrs::FP_arch,
+ ARMBuildAttrs::AllowFPARMv8B));
+}
+
+TEST(WMMXBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(11, "Tag_WMMX_arch"));
+ EXPECT_TRUE(testBuildAttr(11, 0, ARMBuildAttrs::WMMX_arch,
+ ARMBuildAttrs::Not_Allowed));
+ EXPECT_TRUE(testBuildAttr(11, 1, ARMBuildAttrs::WMMX_arch,
+ ARMBuildAttrs::AllowWMMXv1));
+ EXPECT_TRUE(testBuildAttr(11, 2, ARMBuildAttrs::WMMX_arch,
+ ARMBuildAttrs::AllowWMMXv2));
+}
+
+TEST(SIMDBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(12, "Tag_Advanced_SIMD_arch"));
+ EXPECT_TRUE(testBuildAttr(12, 0, ARMBuildAttrs::Advanced_SIMD_arch,
+ ARMBuildAttrs::Not_Allowed));
+ EXPECT_TRUE(testBuildAttr(12, 1, ARMBuildAttrs::Advanced_SIMD_arch,
+ ARMBuildAttrs::AllowNeon));
+ EXPECT_TRUE(testBuildAttr(12, 2, ARMBuildAttrs::Advanced_SIMD_arch,
+ ARMBuildAttrs::AllowNeon2));
+ EXPECT_TRUE(testBuildAttr(12, 3, ARMBuildAttrs::Advanced_SIMD_arch,
+ ARMBuildAttrs::AllowNeonARMv8));
+ EXPECT_TRUE(testBuildAttr(12, 4, ARMBuildAttrs::Advanced_SIMD_arch,
+ ARMBuildAttrs::AllowNeonARMv8_1a));
+}
+
+TEST(FPHPBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(36, "Tag_FP_HP_extension"));
+ EXPECT_TRUE(testBuildAttr(36, 0, ARMBuildAttrs::FP_HP_extension,
+ ARMBuildAttrs::Not_Allowed));
+ EXPECT_TRUE(testBuildAttr(36, 1, ARMBuildAttrs::FP_HP_extension,
+ ARMBuildAttrs::AllowHPFP));
+}
+
+TEST(CPUAlignBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(34, "Tag_CPU_unaligned_access"));
+ EXPECT_TRUE(testBuildAttr(34, 0, ARMBuildAttrs::CPU_unaligned_access,
+ ARMBuildAttrs::Not_Allowed));
+ EXPECT_TRUE(testBuildAttr(34, 1, ARMBuildAttrs::CPU_unaligned_access,
+ ARMBuildAttrs::Allowed));
+}
+
+TEST(T2EEBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(66, "Tag_T2EE_use"));
+ EXPECT_TRUE(testBuildAttr(66, 0, ARMBuildAttrs::T2EE_use,
+ ARMBuildAttrs::Not_Allowed));
+ EXPECT_TRUE(testBuildAttr(66, 1, ARMBuildAttrs::T2EE_use,
+ ARMBuildAttrs::Allowed));
+}
+
+TEST(VirtualizationBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(68, "Tag_Virtualization_use"));
+ EXPECT_TRUE(testBuildAttr(68, 0, ARMBuildAttrs::Virtualization_use,
+ ARMBuildAttrs::Not_Allowed));
+ EXPECT_TRUE(testBuildAttr(68, 1, ARMBuildAttrs::Virtualization_use,
+ ARMBuildAttrs::AllowTZ));
+ EXPECT_TRUE(testBuildAttr(68, 2, ARMBuildAttrs::Virtualization_use,
+ ARMBuildAttrs::AllowVirtualization));
+ EXPECT_TRUE(testBuildAttr(68, 3, ARMBuildAttrs::Virtualization_use,
+ ARMBuildAttrs::AllowTZVirtualization));
+}
+
+TEST(MPBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(42, "Tag_MPextension_use"));
+ EXPECT_TRUE(testBuildAttr(42, 0, ARMBuildAttrs::MPextension_use,
+ ARMBuildAttrs::Not_Allowed));
+ EXPECT_TRUE(testBuildAttr(42, 1, ARMBuildAttrs::MPextension_use,
+ ARMBuildAttrs::AllowMP));
+}
+
+TEST(DivBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(44, "Tag_DIV_use"));
+ EXPECT_TRUE(testBuildAttr(44, 0, ARMBuildAttrs::DIV_use,
+ ARMBuildAttrs::AllowDIVIfExists));
+ EXPECT_TRUE(testBuildAttr(44, 1, ARMBuildAttrs::DIV_use,
+ ARMBuildAttrs::DisallowDIV));
+ EXPECT_TRUE(testBuildAttr(44, 2, ARMBuildAttrs::DIV_use,
+ ARMBuildAttrs::AllowDIVExt));
+}
+
+TEST(PCS_ConfigBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(13, "Tag_PCS_config"));
+ EXPECT_TRUE(testBuildAttr(13, 0, ARMBuildAttrs::PCS_config, 0));
+ EXPECT_TRUE(testBuildAttr(13, 1, ARMBuildAttrs::PCS_config, 1));
+ EXPECT_TRUE(testBuildAttr(13, 2, ARMBuildAttrs::PCS_config, 2));
+ EXPECT_TRUE(testBuildAttr(13, 3, ARMBuildAttrs::PCS_config, 3));
+ EXPECT_TRUE(testBuildAttr(13, 4, ARMBuildAttrs::PCS_config, 4));
+ EXPECT_TRUE(testBuildAttr(13, 5, ARMBuildAttrs::PCS_config, 5));
+ EXPECT_TRUE(testBuildAttr(13, 6, ARMBuildAttrs::PCS_config, 6));
+ EXPECT_TRUE(testBuildAttr(13, 7, ARMBuildAttrs::PCS_config, 7));
+}
+
+TEST(PCS_R9BuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(14, "Tag_ABI_PCS_R9_use"));
+ EXPECT_TRUE(testBuildAttr(14, 0, ARMBuildAttrs::ABI_PCS_R9_use,
+ ARMBuildAttrs::R9IsGPR));
+ EXPECT_TRUE(testBuildAttr(14, 1, ARMBuildAttrs::ABI_PCS_R9_use,
+ ARMBuildAttrs::R9IsSB));
+ EXPECT_TRUE(testBuildAttr(14, 2, ARMBuildAttrs::ABI_PCS_R9_use,
+ ARMBuildAttrs::R9IsTLSPointer));
+ EXPECT_TRUE(testBuildAttr(14, 3, ARMBuildAttrs::ABI_PCS_R9_use,
+ ARMBuildAttrs::R9Reserved));
+}
+
+TEST(PCS_RWBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(15, "Tag_ABI_PCS_RW_data"));
+ EXPECT_TRUE(testBuildAttr(15, 0, ARMBuildAttrs::ABI_PCS_RW_data,
+ ARMBuildAttrs::Not_Allowed));
+ EXPECT_TRUE(testBuildAttr(15, 1, ARMBuildAttrs::ABI_PCS_RW_data,
+ ARMBuildAttrs::AddressRWPCRel));
+ EXPECT_TRUE(testBuildAttr(15, 2, ARMBuildAttrs::ABI_PCS_RW_data,
+ ARMBuildAttrs::AddressRWSBRel));
+ EXPECT_TRUE(testBuildAttr(15, 3, ARMBuildAttrs::ABI_PCS_RW_data,
+ ARMBuildAttrs::AddressRWNone));
+}
+
+TEST(PCS_ROBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(16, "Tag_ABI_PCS_RO_data"));
+ EXPECT_TRUE(testBuildAttr(16, 0, ARMBuildAttrs::ABI_PCS_RO_data,
+ ARMBuildAttrs::Not_Allowed));
+ EXPECT_TRUE(testBuildAttr(16, 1, ARMBuildAttrs::ABI_PCS_RO_data,
+ ARMBuildAttrs::AddressROPCRel));
+ EXPECT_TRUE(testBuildAttr(16, 2, ARMBuildAttrs::ABI_PCS_RO_data,
+ ARMBuildAttrs::AddressRONone));
+}
+
+TEST(PCS_GOTBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(17, "Tag_ABI_PCS_GOT_use"));
+ EXPECT_TRUE(testBuildAttr(17, 0, ARMBuildAttrs::ABI_PCS_GOT_use,
+ ARMBuildAttrs::Not_Allowed));
+ EXPECT_TRUE(testBuildAttr(17, 1, ARMBuildAttrs::ABI_PCS_GOT_use,
+ ARMBuildAttrs::AddressDirect));
+ EXPECT_TRUE(testBuildAttr(17, 2, ARMBuildAttrs::ABI_PCS_GOT_use,
+ ARMBuildAttrs::AddressGOT));
+}
+
+TEST(PCS_WCharBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(18, "Tag_ABI_PCS_wchar_t"));
+ EXPECT_TRUE(testBuildAttr(18, 0, ARMBuildAttrs::ABI_PCS_wchar_t,
+ ARMBuildAttrs::WCharProhibited));
+ EXPECT_TRUE(testBuildAttr(18, 2, ARMBuildAttrs::ABI_PCS_wchar_t,
+ ARMBuildAttrs::WCharWidth2Bytes));
+ EXPECT_TRUE(testBuildAttr(18, 4, ARMBuildAttrs::ABI_PCS_wchar_t,
+ ARMBuildAttrs::WCharWidth4Bytes));
+}
+
+TEST(EnumSizeBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(26, "Tag_ABI_enum_size"));
+ EXPECT_TRUE(testBuildAttr(26, 0, ARMBuildAttrs::ABI_enum_size,
+ ARMBuildAttrs::EnumProhibited));
+ EXPECT_TRUE(testBuildAttr(26, 1, ARMBuildAttrs::ABI_enum_size,
+ ARMBuildAttrs::EnumSmallest));
+ EXPECT_TRUE(testBuildAttr(26, 2, ARMBuildAttrs::ABI_enum_size,
+ ARMBuildAttrs::Enum32Bit));
+ EXPECT_TRUE(testBuildAttr(26, 3, ARMBuildAttrs::ABI_enum_size,
+ ARMBuildAttrs::Enum32BitABI));
+}
+
+TEST(AlignNeededBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(24, "Tag_ABI_align_needed"));
+ EXPECT_TRUE(testBuildAttr(24, 0, ARMBuildAttrs::ABI_align_needed,
+ ARMBuildAttrs::Not_Allowed));
+ EXPECT_TRUE(testBuildAttr(24, 1, ARMBuildAttrs::ABI_align_needed,
+ ARMBuildAttrs::Align8Byte));
+ EXPECT_TRUE(testBuildAttr(24, 2, ARMBuildAttrs::ABI_align_needed,
+ ARMBuildAttrs::Align4Byte));
+ EXPECT_TRUE(testBuildAttr(24, 3, ARMBuildAttrs::ABI_align_needed,
+ ARMBuildAttrs::AlignReserved));
+}
+
+TEST(AlignPreservedBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(25, "Tag_ABI_align_preserved"));
+ EXPECT_TRUE(testBuildAttr(25, 0, ARMBuildAttrs::ABI_align_preserved,
+ ARMBuildAttrs::AlignNotPreserved));
+ EXPECT_TRUE(testBuildAttr(25, 1, ARMBuildAttrs::ABI_align_preserved,
+ ARMBuildAttrs::AlignPreserve8Byte));
+ EXPECT_TRUE(testBuildAttr(25, 2, ARMBuildAttrs::ABI_align_preserved,
+ ARMBuildAttrs::AlignPreserveAll));
+ EXPECT_TRUE(testBuildAttr(25, 3, ARMBuildAttrs::ABI_align_preserved,
+ ARMBuildAttrs::AlignReserved));
+}
+
+TEST(FPRoundingBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(19, "Tag_ABI_FP_rounding"));
+ EXPECT_TRUE(testBuildAttr(19, 0, ARMBuildAttrs::ABI_FP_rounding, 0));
+ EXPECT_TRUE(testBuildAttr(19, 1, ARMBuildAttrs::ABI_FP_rounding, 1));
+}
+
+TEST(FPDenormalBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(20, "Tag_ABI_FP_denormal"));
+ EXPECT_TRUE(testBuildAttr(20, 0, ARMBuildAttrs::ABI_FP_denormal,
+ ARMBuildAttrs::PositiveZero));
+ EXPECT_TRUE(testBuildAttr(20, 1, ARMBuildAttrs::ABI_FP_denormal,
+ ARMBuildAttrs::IEEEDenormals));
+ EXPECT_TRUE(testBuildAttr(20, 2, ARMBuildAttrs::ABI_FP_denormal,
+ ARMBuildAttrs::PreserveFPSign));
+}
+
+TEST(FPExceptionsBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(21, "Tag_ABI_FP_exceptions"));
+ EXPECT_TRUE(testBuildAttr(21, 0, ARMBuildAttrs::ABI_FP_exceptions, 0));
+ EXPECT_TRUE(testBuildAttr(21, 1, ARMBuildAttrs::ABI_FP_exceptions, 1));
+}
+
+TEST(FPUserExceptionsBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(22, "Tag_ABI_FP_user_exceptions"));
+ EXPECT_TRUE(testBuildAttr(22, 0, ARMBuildAttrs::ABI_FP_user_exceptions, 0));
+ EXPECT_TRUE(testBuildAttr(22, 1, ARMBuildAttrs::ABI_FP_user_exceptions, 1));
+}
+
+TEST(FPNumberModelBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(23, "Tag_ABI_FP_number_model"));
+ EXPECT_TRUE(testBuildAttr(23, 0, ARMBuildAttrs::ABI_FP_number_model,
+ ARMBuildAttrs::Not_Allowed));
+ EXPECT_TRUE(testBuildAttr(23, 1, ARMBuildAttrs::ABI_FP_number_model,
+ ARMBuildAttrs::AllowIEEENormal));
+ EXPECT_TRUE(testBuildAttr(23, 2, ARMBuildAttrs::ABI_FP_number_model,
+ ARMBuildAttrs::AllowRTABI));
+ EXPECT_TRUE(testBuildAttr(23, 3, ARMBuildAttrs::ABI_FP_number_model,
+ ARMBuildAttrs::AllowIEEE754));
+}
+
+TEST(FP16BuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(38, "Tag_ABI_FP_16bit_format"));
+ EXPECT_TRUE(testBuildAttr(38, 0, ARMBuildAttrs::ABI_FP_16bit_format,
+ ARMBuildAttrs::Not_Allowed));
+ EXPECT_TRUE(testBuildAttr(38, 1, ARMBuildAttrs::ABI_FP_16bit_format,
+ ARMBuildAttrs::FP16FormatIEEE));
+ EXPECT_TRUE(testBuildAttr(38, 2, ARMBuildAttrs::ABI_FP_16bit_format,
+ ARMBuildAttrs::FP16VFP3));
+}
+
+TEST(HardFPBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(27, "Tag_ABI_HardFP_use"));
+ EXPECT_TRUE(testBuildAttr(27, 0, ARMBuildAttrs::ABI_HardFP_use,
+ ARMBuildAttrs::HardFPImplied));
+ EXPECT_TRUE(testBuildAttr(27, 1, ARMBuildAttrs::ABI_HardFP_use,
+ ARMBuildAttrs::HardFPSinglePrecision));
+ EXPECT_TRUE(testBuildAttr(27, 2, ARMBuildAttrs::ABI_HardFP_use, 2));
+}
+
+TEST(VFPArgsBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(28, "Tag_ABI_VFP_args"));
+ EXPECT_TRUE(testBuildAttr(28, 0, ARMBuildAttrs::ABI_VFP_args,
+ ARMBuildAttrs::BaseAAPCS));
+ EXPECT_TRUE(testBuildAttr(28, 1, ARMBuildAttrs::ABI_VFP_args,
+ ARMBuildAttrs::HardFPAAPCS));
+ EXPECT_TRUE(testBuildAttr(28, 2, ARMBuildAttrs::ABI_VFP_args, 2));
+ EXPECT_TRUE(testBuildAttr(28, 3, ARMBuildAttrs::ABI_VFP_args, 3));
+}
+
+TEST(WMMXArgsBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(29, "Tag_ABI_WMMX_args"));
+ EXPECT_TRUE(testBuildAttr(29, 0, ARMBuildAttrs::ABI_WMMX_args, 0));
+ EXPECT_TRUE(testBuildAttr(29, 1, ARMBuildAttrs::ABI_WMMX_args, 1));
+ EXPECT_TRUE(testBuildAttr(29, 2, ARMBuildAttrs::ABI_WMMX_args, 2));
+}
diff --git a/unittests/Support/AllocatorTest.cpp b/unittests/Support/AllocatorTest.cpp
index 4b544641e9bff..4897c47eb28ba 100644
--- a/unittests/Support/AllocatorTest.cpp
+++ b/unittests/Support/AllocatorTest.cpp
@@ -17,9 +17,9 @@ namespace {
TEST(AllocatorTest, Basics) {
BumpPtrAllocator Alloc;
- int *a = (int*)Alloc.Allocate(sizeof(int), 1);
- int *b = (int*)Alloc.Allocate(sizeof(int) * 10, 1);
- int *c = (int*)Alloc.Allocate(sizeof(int), 1);
+ int *a = (int*)Alloc.Allocate(sizeof(int), alignof(int));
+ int *b = (int*)Alloc.Allocate(sizeof(int) * 10, alignof(int));
+ int *c = (int*)Alloc.Allocate(sizeof(int), alignof(int));
*a = 1;
b[0] = 2;
b[9] = 2;
diff --git a/unittests/Support/BinaryStreamTest.cpp b/unittests/Support/BinaryStreamTest.cpp
new file mode 100644
index 0000000000000..1e646a6cf9001
--- /dev/null
+++ b/unittests/Support/BinaryStreamTest.cpp
@@ -0,0 +1,711 @@
+//===- llvm/unittest/Support/BinaryStreamTest.cpp -------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/BinaryByteStream.h"
+#include "llvm/Support/BinaryItemStream.h"
+#include "llvm/Support/BinaryStreamArray.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/BinaryStreamRef.h"
+#include "llvm/Support/BinaryStreamWriter.h"
+#include "gtest/gtest.h"
+
+#include <unordered_map>
+
+using namespace llvm;
+using namespace llvm::support;
+
+#define EXPECT_NO_ERROR(Err) \
+ { \
+ auto E = Err; \
+ EXPECT_FALSE(static_cast<bool>(E)); \
+ if (E) \
+ consumeError(std::move(E)); \
+ }
+
+#define ASSERT_NO_ERROR(Err) \
+ { \
+ auto E = Err; \
+ ASSERT_FALSE(static_cast<bool>(E)); \
+ if (E) \
+ consumeError(std::move(E)); \
+ }
+
+#define EXPECT_ERROR(Err) \
+ { \
+ auto E = Err; \
+ EXPECT_TRUE(static_cast<bool>(E)); \
+ if (E) \
+ consumeError(std::move(E)); \
+ }
+
+namespace {
+
+class BrokenStream : public WritableBinaryStream {
+public:
+ BrokenStream(MutableArrayRef<uint8_t> Data, endianness Endian,
+ uint32_t Align)
+ : Data(Data), PartitionIndex(alignDown(Data.size() / 2, Align)),
+ Endian(Endian) {}
+
+ endianness getEndian() const override { return Endian; }
+
+ Error readBytes(uint32_t Offset, uint32_t Size,
+ ArrayRef<uint8_t> &Buffer) override {
+ if (auto EC = checkOffset(Offset, Size))
+ return EC;
+ uint32_t S = startIndex(Offset);
+ auto Ref = Data.drop_front(S);
+ if (Ref.size() >= Size) {
+ Buffer = Ref.take_front(Size);
+ return Error::success();
+ }
+
+ uint32_t BytesLeft = Size - Ref.size();
+ uint8_t *Ptr = Allocator.Allocate<uint8_t>(Size);
+ ::memcpy(Ptr, Ref.data(), Ref.size());
+ ::memcpy(Ptr + Ref.size(), Data.data(), BytesLeft);
+ Buffer = makeArrayRef<uint8_t>(Ptr, Size);
+ return Error::success();
+ }
+
+ Error readLongestContiguousChunk(uint32_t Offset,
+ ArrayRef<uint8_t> &Buffer) override {
+ if (auto EC = checkOffset(Offset, 1))
+ return EC;
+ uint32_t S = startIndex(Offset);
+ Buffer = Data.drop_front(S);
+ return Error::success();
+ }
+
+ uint32_t getLength() override { return Data.size(); }
+
+ Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> SrcData) override {
+ if (auto EC = checkOffset(Offset, SrcData.size()))
+ return EC;
+ if (SrcData.empty())
+ return Error::success();
+
+ uint32_t S = startIndex(Offset);
+ MutableArrayRef<uint8_t> Ref(Data);
+ Ref = Ref.drop_front(S);
+ if (Ref.size() >= SrcData.size()) {
+ ::memcpy(Ref.data(), SrcData.data(), SrcData.size());
+ return Error::success();
+ }
+
+ uint32_t BytesLeft = SrcData.size() - Ref.size();
+ ::memcpy(Ref.data(), SrcData.data(), Ref.size());
+ ::memcpy(&Data[0], SrcData.data() + Ref.size(), BytesLeft);
+ return Error::success();
+ }
+ Error commit() override { return Error::success(); }
+
+private:
+ uint32_t startIndex(uint32_t Offset) const {
+ return (Offset + PartitionIndex) % Data.size();
+ }
+
+ uint32_t endIndex(uint32_t Offset, uint32_t Size) const {
+ return (startIndex(Offset) + Size - 1) % Data.size();
+ }
+
+ // Buffer is organized like this:
+ // -------------------------------------------------
+ // | N/2 | N/2+1 | ... | N-1 | 0 | 1 | ... | N-2-1 |
+ // -------------------------------------------------
+ // So reads from the beginning actually come from the middle.
+ MutableArrayRef<uint8_t> Data;
+ uint32_t PartitionIndex = 0;
+ endianness Endian;
+ BumpPtrAllocator Allocator;
+};
+
+constexpr endianness Endians[] = {big, little, native};
+constexpr uint32_t NumEndians = llvm::array_lengthof(Endians);
+constexpr uint32_t NumStreams = 2 * NumEndians;
+
+class BinaryStreamTest : public testing::Test {
+
+public:
+ BinaryStreamTest() {}
+
+ void SetUp() override {
+ Streams.clear();
+ Streams.resize(NumStreams);
+ for (uint32_t I = 0; I < NumStreams; ++I)
+ Streams[I].IsContiguous = (I % 2 == 0);
+
+ InputData.clear();
+ OutputData.clear();
+ }
+
+protected:
+ struct StreamPair {
+ bool IsContiguous;
+ std::unique_ptr<BinaryStream> Input;
+ std::unique_ptr<WritableBinaryStream> Output;
+ };
+
+ void initializeInput(ArrayRef<uint8_t> Input, uint32_t Align) {
+ InputData = Input;
+
+ BrokenInputData.resize(InputData.size());
+ if (!Input.empty()) {
+ uint32_t PartitionIndex = alignDown(InputData.size() / 2, Align);
+ uint32_t RightBytes = InputData.size() - PartitionIndex;
+ uint32_t LeftBytes = PartitionIndex;
+ if (RightBytes > 0)
+ ::memcpy(&BrokenInputData[PartitionIndex], Input.data(), RightBytes);
+ if (LeftBytes > 0)
+ ::memcpy(&BrokenInputData[0], Input.data() + RightBytes, LeftBytes);
+ }
+
+ for (uint32_t I = 0; I < NumEndians; ++I) {
+ auto InByteStream =
+ llvm::make_unique<BinaryByteStream>(InputData, Endians[I]);
+ auto InBrokenStream = llvm::make_unique<BrokenStream>(
+ BrokenInputData, Endians[I], Align);
+
+ Streams[I * 2].Input = std::move(InByteStream);
+ Streams[I * 2 + 1].Input = std::move(InBrokenStream);
+ }
+ }
+
+ void initializeOutput(uint32_t Size, uint32_t Align) {
+ OutputData.resize(Size);
+ BrokenOutputData.resize(Size);
+
+ for (uint32_t I = 0; I < NumEndians; ++I) {
+ Streams[I * 2].Output =
+ llvm::make_unique<MutableBinaryByteStream>(OutputData, Endians[I]);
+ Streams[I * 2 + 1].Output = llvm::make_unique<BrokenStream>(
+ BrokenOutputData, Endians[I], Align);
+ }
+ }
+
+ void initializeOutputFromInput(uint32_t Align) {
+ for (uint32_t I = 0; I < NumEndians; ++I) {
+ Streams[I * 2].Output =
+ llvm::make_unique<MutableBinaryByteStream>(InputData, Endians[I]);
+ Streams[I * 2 + 1].Output = llvm::make_unique<BrokenStream>(
+ BrokenInputData, Endians[I], Align);
+ }
+ }
+
+ void initializeInputFromOutput(uint32_t Align) {
+ for (uint32_t I = 0; I < NumEndians; ++I) {
+ Streams[I * 2].Input =
+ llvm::make_unique<BinaryByteStream>(OutputData, Endians[I]);
+ Streams[I * 2 + 1].Input = llvm::make_unique<BrokenStream>(
+ BrokenOutputData, Endians[I], Align);
+ }
+ }
+
+ std::vector<uint8_t> InputData;
+ std::vector<uint8_t> BrokenInputData;
+
+ std::vector<uint8_t> OutputData;
+ std::vector<uint8_t> BrokenOutputData;
+
+ std::vector<StreamPair> Streams;
+};
+
+// Tests that a we can read from a BinaryByteStream without a StreamReader.
+TEST_F(BinaryStreamTest, BinaryByteStreamBounds) {
+ std::vector<uint8_t> InputData = {1, 2, 3, 4, 5};
+ initializeInput(InputData, 1);
+
+ for (auto &Stream : Streams) {
+ ArrayRef<uint8_t> Buffer;
+
+ // 1. If the read fits it should work.
+ ASSERT_EQ(InputData.size(), Stream.Input->getLength());
+ ASSERT_NO_ERROR(Stream.Input->readBytes(2, 1, Buffer));
+ EXPECT_EQ(makeArrayRef(InputData).slice(2, 1), Buffer);
+ ASSERT_NO_ERROR(Stream.Input->readBytes(0, 4, Buffer));
+ EXPECT_EQ(makeArrayRef(InputData).slice(0, 4), Buffer);
+
+ // 2. Reading past the bounds of the input should fail.
+ EXPECT_ERROR(Stream.Input->readBytes(4, 2, Buffer));
+ }
+}
+
+TEST_F(BinaryStreamTest, StreamRefBounds) {
+ std::vector<uint8_t> InputData = {1, 2, 3, 4, 5};
+ initializeInput(InputData, 1);
+
+ for (const auto &Stream : Streams) {
+ ArrayRef<uint8_t> Buffer;
+ BinaryStreamRef Ref(*Stream.Input);
+
+ // Read 1 byte from offset 2 should work
+ ASSERT_EQ(InputData.size(), Ref.getLength());
+ ASSERT_NO_ERROR(Ref.readBytes(2, 1, Buffer));
+ EXPECT_EQ(makeArrayRef(InputData).slice(2, 1), Buffer);
+
+ // Reading everything from offset 2 on.
+ ASSERT_NO_ERROR(Ref.readLongestContiguousChunk(2, Buffer));
+ if (Stream.IsContiguous)
+ EXPECT_EQ(makeArrayRef(InputData).slice(2), Buffer);
+ else
+ EXPECT_FALSE(Buffer.empty());
+
+ // Reading 6 bytes from offset 0 is too big.
+ EXPECT_ERROR(Ref.readBytes(0, 6, Buffer));
+ EXPECT_ERROR(Ref.readLongestContiguousChunk(6, Buffer));
+
+ // Reading 1 byte from offset 2 after dropping 1 byte is the same as reading
+ // 1 byte from offset 3.
+ Ref = Ref.drop_front(1);
+ ASSERT_NO_ERROR(Ref.readBytes(2, 1, Buffer));
+ if (Stream.IsContiguous)
+ EXPECT_EQ(makeArrayRef(InputData).slice(3, 1), Buffer);
+ else
+ EXPECT_FALSE(Buffer.empty());
+
+ // Reading everything from offset 2 on after dropping 1 byte.
+ ASSERT_NO_ERROR(Ref.readLongestContiguousChunk(2, Buffer));
+ if (Stream.IsContiguous)
+ EXPECT_EQ(makeArrayRef(InputData).slice(3), Buffer);
+ else
+ EXPECT_FALSE(Buffer.empty());
+
+ // Reading 2 bytes from offset 2 after dropping 2 bytes is the same as
+ // reading 2 bytes from offset 4, and should fail.
+ Ref = Ref.drop_front(1);
+ EXPECT_ERROR(Ref.readBytes(2, 2, Buffer));
+
+ // But if we read the longest contiguous chunk instead, we should still
+ // get the 1 byte at the end.
+ ASSERT_NO_ERROR(Ref.readLongestContiguousChunk(2, Buffer));
+ EXPECT_EQ(makeArrayRef(InputData).take_back(), Buffer);
+ }
+}
+
+// Test that we can write to a BinaryStream without a StreamWriter.
+TEST_F(BinaryStreamTest, MutableBinaryByteStreamBounds) {
+ std::vector<uint8_t> InputData = {'T', 'e', 's', 't', '\0'};
+ initializeInput(InputData, 1);
+ initializeOutput(InputData.size(), 1);
+
+ // For every combination of input stream and output stream.
+ for (auto &Stream : Streams) {
+ MutableArrayRef<uint8_t> Buffer;
+ ASSERT_EQ(InputData.size(), Stream.Input->getLength());
+
+ // 1. Try two reads that are supposed to work. One from offset 0, and one
+ // from the middle.
+ uint32_t Offsets[] = {0, 3};
+ for (auto Offset : Offsets) {
+ uint32_t ExpectedSize = Stream.Input->getLength() - Offset;
+
+ // Read everything from Offset until the end of the input data.
+ ArrayRef<uint8_t> Data;
+ ASSERT_NO_ERROR(Stream.Input->readBytes(Offset, ExpectedSize, Data));
+ ASSERT_EQ(ExpectedSize, Data.size());
+
+ // Then write it to the destination.
+ ASSERT_NO_ERROR(Stream.Output->writeBytes(0, Data));
+
+ // Then we read back what we wrote, it should match the corresponding
+ // slice of the original input data.
+ ArrayRef<uint8_t> Data2;
+ ASSERT_NO_ERROR(Stream.Output->readBytes(Offset, ExpectedSize, Data2));
+ EXPECT_EQ(makeArrayRef(InputData).drop_front(Offset), Data2);
+ }
+
+ std::vector<uint8_t> BigData = {0, 1, 2, 3, 4};
+ // 2. If the write is too big, it should fail.
+ EXPECT_ERROR(Stream.Output->writeBytes(3, BigData));
+ }
+}
+
+// Test that FixedStreamArray works correctly.
+TEST_F(BinaryStreamTest, FixedStreamArray) {
+ std::vector<uint32_t> Ints = {90823, 12908, 109823, 209823};
+ ArrayRef<uint8_t> IntBytes(reinterpret_cast<uint8_t *>(Ints.data()),
+ Ints.size() * sizeof(uint32_t));
+
+ initializeInput(IntBytes, alignof(uint32_t));
+
+ for (auto &Stream : Streams) {
+ MutableArrayRef<uint8_t> Buffer;
+ ASSERT_EQ(InputData.size(), Stream.Input->getLength());
+
+ FixedStreamArray<uint32_t> Array(*Stream.Input);
+ auto Iter = Array.begin();
+ ASSERT_EQ(Ints[0], *Iter++);
+ ASSERT_EQ(Ints[1], *Iter++);
+ ASSERT_EQ(Ints[2], *Iter++);
+ ASSERT_EQ(Ints[3], *Iter++);
+ ASSERT_EQ(Array.end(), Iter);
+ }
+}
+
+// Test that VarStreamArray works correctly.
+TEST_F(BinaryStreamTest, VarStreamArray) {
+ StringLiteral Strings("1. Test2. Longer Test3. Really Long Test4. Super "
+ "Extra Longest Test Of All");
+ ArrayRef<uint8_t> StringBytes(
+ reinterpret_cast<const uint8_t *>(Strings.data()), Strings.size());
+ initializeInput(StringBytes, 1);
+
+ struct StringExtractor {
+ public:
+ Error operator()(BinaryStreamRef Stream, uint32_t &Len, StringRef &Item) {
+ if (Index == 0)
+ Len = strlen("1. Test");
+ else if (Index == 1)
+ Len = strlen("2. Longer Test");
+ else if (Index == 2)
+ Len = strlen("3. Really Long Test");
+ else
+ Len = strlen("4. Super Extra Longest Test Of All");
+ ArrayRef<uint8_t> Bytes;
+ if (auto EC = Stream.readBytes(0, Len, Bytes))
+ return EC;
+ Item =
+ StringRef(reinterpret_cast<const char *>(Bytes.data()), Bytes.size());
+ ++Index;
+ return Error::success();
+ }
+
+ private:
+ uint32_t Index = 0;
+ };
+
+ for (auto &Stream : Streams) {
+ VarStreamArray<StringRef, StringExtractor> Array(*Stream.Input);
+ auto Iter = Array.begin();
+ ASSERT_EQ("1. Test", *Iter++);
+ ASSERT_EQ("2. Longer Test", *Iter++);
+ ASSERT_EQ("3. Really Long Test", *Iter++);
+ ASSERT_EQ("4. Super Extra Longest Test Of All", *Iter++);
+ ASSERT_EQ(Array.end(), Iter);
+ }
+}
+
+TEST_F(BinaryStreamTest, StreamReaderBounds) {
+ std::vector<uint8_t> Bytes;
+
+ initializeInput(Bytes, 1);
+ for (auto &Stream : Streams) {
+ StringRef S;
+ BinaryStreamReader Reader(*Stream.Input);
+ EXPECT_EQ(0U, Reader.bytesRemaining());
+ EXPECT_ERROR(Reader.readFixedString(S, 1));
+ }
+
+ Bytes.resize(5);
+ initializeInput(Bytes, 1);
+ for (auto &Stream : Streams) {
+ StringRef S;
+ BinaryStreamReader Reader(*Stream.Input);
+ EXPECT_EQ(Bytes.size(), Reader.bytesRemaining());
+ EXPECT_NO_ERROR(Reader.readFixedString(S, 5));
+ EXPECT_ERROR(Reader.readFixedString(S, 6));
+ }
+}
+
+TEST_F(BinaryStreamTest, StreamReaderIntegers) {
+ support::ulittle64_t Little{908234};
+ support::ubig32_t Big{28907823};
+ short NS = 2897;
+ int NI = -89723;
+ unsigned long NUL = 902309023UL;
+ constexpr uint32_t Size =
+ sizeof(Little) + sizeof(Big) + sizeof(NS) + sizeof(NI) + sizeof(NUL);
+
+ initializeOutput(Size, alignof(support::ulittle64_t));
+ initializeInputFromOutput(alignof(support::ulittle64_t));
+
+ for (auto &Stream : Streams) {
+ BinaryStreamWriter Writer(*Stream.Output);
+ ASSERT_NO_ERROR(Writer.writeObject(Little));
+ ASSERT_NO_ERROR(Writer.writeObject(Big));
+ ASSERT_NO_ERROR(Writer.writeInteger(NS));
+ ASSERT_NO_ERROR(Writer.writeInteger(NI));
+ ASSERT_NO_ERROR(Writer.writeInteger(NUL));
+
+ const support::ulittle64_t *Little2;
+ const support::ubig32_t *Big2;
+ short NS2;
+ int NI2;
+ unsigned long NUL2;
+
+ // 1. Reading fields individually.
+ BinaryStreamReader Reader(*Stream.Input);
+ ASSERT_NO_ERROR(Reader.readObject(Little2));
+ ASSERT_NO_ERROR(Reader.readObject(Big2));
+ ASSERT_NO_ERROR(Reader.readInteger(NS2));
+ ASSERT_NO_ERROR(Reader.readInteger(NI2));
+ ASSERT_NO_ERROR(Reader.readInteger(NUL2));
+ ASSERT_EQ(0U, Reader.bytesRemaining());
+
+ EXPECT_EQ(Little, *Little2);
+ EXPECT_EQ(Big, *Big2);
+ EXPECT_EQ(NS, NS2);
+ EXPECT_EQ(NI, NI2);
+ EXPECT_EQ(NUL, NUL2);
+ }
+}
+
+TEST_F(BinaryStreamTest, StreamReaderIntegerArray) {
+ // 1. Arrays of integers
+ std::vector<int> Ints = {1, 2, 3, 4, 5};
+ ArrayRef<uint8_t> IntBytes(reinterpret_cast<uint8_t *>(&Ints[0]),
+ Ints.size() * sizeof(int));
+
+ initializeInput(IntBytes, alignof(int));
+ for (auto &Stream : Streams) {
+ BinaryStreamReader Reader(*Stream.Input);
+ ArrayRef<int> IntsRef;
+ ASSERT_NO_ERROR(Reader.readArray(IntsRef, Ints.size()));
+ ASSERT_EQ(0U, Reader.bytesRemaining());
+ EXPECT_EQ(makeArrayRef(Ints), IntsRef);
+
+ Reader.setOffset(0);
+ FixedStreamArray<int> FixedIntsRef;
+ ASSERT_NO_ERROR(Reader.readArray(FixedIntsRef, Ints.size()));
+ ASSERT_EQ(0U, Reader.bytesRemaining());
+ ASSERT_EQ(Ints, std::vector<int>(FixedIntsRef.begin(), FixedIntsRef.end()));
+ }
+}
+
+TEST_F(BinaryStreamTest, StreamReaderEnum) {
+ enum class MyEnum : int64_t { Foo = -10, Bar = 0, Baz = 10 };
+
+ std::vector<MyEnum> Enums = {MyEnum::Bar, MyEnum::Baz, MyEnum::Foo};
+
+ initializeOutput(Enums.size() * sizeof(MyEnum), alignof(MyEnum));
+ initializeInputFromOutput(alignof(MyEnum));
+ for (auto &Stream : Streams) {
+ BinaryStreamWriter Writer(*Stream.Output);
+ for (auto Value : Enums)
+ ASSERT_NO_ERROR(Writer.writeEnum(Value));
+
+ BinaryStreamReader Reader(*Stream.Input);
+
+ ArrayRef<MyEnum> Array;
+ FixedStreamArray<MyEnum> FSA;
+
+ for (size_t I = 0; I < Enums.size(); ++I) {
+ MyEnum Value;
+ ASSERT_NO_ERROR(Reader.readEnum(Value));
+ EXPECT_EQ(Enums[I], Value);
+ }
+ ASSERT_EQ(0U, Reader.bytesRemaining());
+ }
+}
+
+TEST_F(BinaryStreamTest, StreamReaderObject) {
+ struct Foo {
+ int X;
+ double Y;
+ char Z;
+
+ bool operator==(const Foo &Other) const {
+ return X == Other.X && Y == Other.Y && Z == Other.Z;
+ }
+ };
+
+ std::vector<Foo> Foos;
+ Foos.push_back({-42, 42.42, 42});
+ Foos.push_back({100, 3.1415, static_cast<char>(-89)});
+ Foos.push_back({200, 2.718, static_cast<char>(-12) });
+
+ const uint8_t *Bytes = reinterpret_cast<const uint8_t *>(&Foos[0]);
+
+ initializeInput(makeArrayRef(Bytes, 3 * sizeof(Foo)), alignof(Foo));
+
+ for (auto &Stream : Streams) {
+ // 1. Reading object pointers.
+ BinaryStreamReader Reader(*Stream.Input);
+ const Foo *FPtrOut = nullptr;
+ const Foo *GPtrOut = nullptr;
+ const Foo *HPtrOut = nullptr;
+ ASSERT_NO_ERROR(Reader.readObject(FPtrOut));
+ ASSERT_NO_ERROR(Reader.readObject(GPtrOut));
+ ASSERT_NO_ERROR(Reader.readObject(HPtrOut));
+ EXPECT_EQ(0U, Reader.bytesRemaining());
+ EXPECT_EQ(Foos[0], *FPtrOut);
+ EXPECT_EQ(Foos[1], *GPtrOut);
+ EXPECT_EQ(Foos[2], *HPtrOut);
+ }
+}
+
+TEST_F(BinaryStreamTest, StreamReaderStrings) {
+ std::vector<uint8_t> Bytes = {'O', 'n', 'e', '\0', 'T', 'w', 'o',
+ '\0', 'T', 'h', 'r', 'e', 'e', '\0',
+ 'F', 'o', 'u', 'r', '\0'};
+ initializeInput(Bytes, 1);
+
+ for (auto &Stream : Streams) {
+ BinaryStreamReader Reader(*Stream.Input);
+
+ StringRef S1;
+ StringRef S2;
+ StringRef S3;
+ StringRef S4;
+ ASSERT_NO_ERROR(Reader.readCString(S1));
+ ASSERT_NO_ERROR(Reader.readCString(S2));
+ ASSERT_NO_ERROR(Reader.readCString(S3));
+ ASSERT_NO_ERROR(Reader.readCString(S4));
+ ASSERT_EQ(0U, Reader.bytesRemaining());
+
+ EXPECT_EQ("One", S1);
+ EXPECT_EQ("Two", S2);
+ EXPECT_EQ("Three", S3);
+ EXPECT_EQ("Four", S4);
+
+ S1 = S2 = S3 = S4 = "";
+ Reader.setOffset(0);
+ ASSERT_NO_ERROR(Reader.readFixedString(S1, 3));
+ ASSERT_NO_ERROR(Reader.skip(1));
+ ASSERT_NO_ERROR(Reader.readFixedString(S2, 3));
+ ASSERT_NO_ERROR(Reader.skip(1));
+ ASSERT_NO_ERROR(Reader.readFixedString(S3, 5));
+ ASSERT_NO_ERROR(Reader.skip(1));
+ ASSERT_NO_ERROR(Reader.readFixedString(S4, 4));
+ ASSERT_NO_ERROR(Reader.skip(1));
+ ASSERT_EQ(0U, Reader.bytesRemaining());
+
+ EXPECT_EQ("One", S1);
+ EXPECT_EQ("Two", S2);
+ EXPECT_EQ("Three", S3);
+ EXPECT_EQ("Four", S4);
+ }
+}
+
+TEST_F(BinaryStreamTest, StreamWriterBounds) {
+ initializeOutput(5, 1);
+
+ for (auto &Stream : Streams) {
+ BinaryStreamWriter Writer(*Stream.Output);
+
+ // 1. Can write a string that exactly fills the buffer.
+ EXPECT_EQ(5U, Writer.bytesRemaining());
+ EXPECT_NO_ERROR(Writer.writeFixedString("abcde"));
+ EXPECT_EQ(0U, Writer.bytesRemaining());
+
+ // 2. Can write an empty string even when you're full
+ EXPECT_NO_ERROR(Writer.writeFixedString(""));
+ EXPECT_ERROR(Writer.writeFixedString("a"));
+
+ // 3. Can't write a string that is one character too long.
+ Writer.setOffset(0);
+ EXPECT_ERROR(Writer.writeFixedString("abcdef"));
+ }
+}
+
+TEST_F(BinaryStreamTest, StreamWriterIntegerArrays) {
+ // 3. Arrays of integers
+ std::vector<int> SourceInts = {1, 2, 3, 4, 5};
+ ArrayRef<uint8_t> SourceBytes(reinterpret_cast<uint8_t *>(&SourceInts[0]),
+ SourceInts.size() * sizeof(int));
+
+ initializeInput(SourceBytes, alignof(int));
+ initializeOutputFromInput(alignof(int));
+
+ for (auto &Stream : Streams) {
+ BinaryStreamReader Reader(*Stream.Input);
+ BinaryStreamWriter Writer(*Stream.Output);
+ ArrayRef<int> Ints;
+ ArrayRef<int> Ints2;
+ // First read them, then write them, then read them back.
+ ASSERT_NO_ERROR(Reader.readArray(Ints, SourceInts.size()));
+ ASSERT_NO_ERROR(Writer.writeArray(Ints));
+
+ BinaryStreamReader ReaderBacker(*Stream.Output);
+ ASSERT_NO_ERROR(ReaderBacker.readArray(Ints2, SourceInts.size()));
+
+ EXPECT_EQ(makeArrayRef(SourceInts), Ints2);
+ }
+}
+
+TEST_F(BinaryStreamTest, StringWriterStrings) {
+ StringRef Strings[] = {"First", "Second", "Third", "Fourth"};
+
+ size_t Length = 0;
+ for (auto S : Strings)
+ Length += S.size() + 1;
+ initializeOutput(Length, 1);
+ initializeInputFromOutput(1);
+
+ for (auto &Stream : Streams) {
+ BinaryStreamWriter Writer(*Stream.Output);
+ for (auto S : Strings)
+ ASSERT_NO_ERROR(Writer.writeCString(S));
+ std::vector<StringRef> InStrings;
+ BinaryStreamReader Reader(*Stream.Input);
+ while (!Reader.empty()) {
+ StringRef S;
+ ASSERT_NO_ERROR(Reader.readCString(S));
+ InStrings.push_back(S);
+ }
+ EXPECT_EQ(makeArrayRef(Strings), makeArrayRef(InStrings));
+ }
+}
+}
+
+namespace {
+struct BinaryItemStreamObject {
+ explicit BinaryItemStreamObject(ArrayRef<uint8_t> Bytes) : Bytes(Bytes) {}
+
+ ArrayRef<uint8_t> Bytes;
+};
+}
+
+namespace llvm {
+template <> struct BinaryItemTraits<BinaryItemStreamObject> {
+ static size_t length(const BinaryItemStreamObject &Item) {
+ return Item.Bytes.size();
+ }
+
+ static ArrayRef<uint8_t> bytes(const BinaryItemStreamObject &Item) {
+ return Item.Bytes;
+ }
+};
+}
+
+namespace {
+
+TEST_F(BinaryStreamTest, BinaryItemStream) {
+ std::vector<BinaryItemStreamObject> Objects;
+
+ struct Foo {
+ int X;
+ double Y;
+ };
+ std::vector<Foo> Foos = {{1, 1.0}, {2, 2.0}, {3, 3.0}};
+ BumpPtrAllocator Allocator;
+ for (const auto &F : Foos) {
+ uint8_t *Ptr = static_cast<uint8_t *>(Allocator.Allocate(sizeof(Foo),
+ alignof(Foo)));
+ MutableArrayRef<uint8_t> Buffer(Ptr, sizeof(Foo));
+ MutableBinaryByteStream Stream(Buffer, llvm::support::big);
+ BinaryStreamWriter Writer(Stream);
+ ASSERT_NO_ERROR(Writer.writeObject(F));
+ Objects.push_back(BinaryItemStreamObject(Buffer));
+ }
+
+ BinaryItemStream<BinaryItemStreamObject> ItemStream(big);
+ ItemStream.setItems(Objects);
+ BinaryStreamReader Reader(ItemStream);
+
+ for (const auto &F : Foos) {
+ const Foo *F2;
+ ASSERT_NO_ERROR(Reader.readObject(F2));
+
+ EXPECT_EQ(F.X, F2->X);
+ EXPECT_DOUBLE_EQ(F.Y, F2->Y);
+ }
+}
+
+} // end anonymous namespace
diff --git a/unittests/Support/CMakeLists.txt b/unittests/Support/CMakeLists.txt
index 6068de5514c7f..a7be18b6a3c53 100644
--- a/unittests/Support/CMakeLists.txt
+++ b/unittests/Support/CMakeLists.txt
@@ -5,9 +5,12 @@ set(LLVM_LINK_COMPONENTS
add_llvm_unittest(SupportTests
AlignOfTest.cpp
AllocatorTest.cpp
+ ARMAttributeParser.cpp
ArrayRecyclerTest.cpp
+ BinaryStreamTest.cpp
BlockFrequencyTest.cpp
BranchProbabilityTest.cpp
+ CachePruningTest.cpp
Casting.cpp
Chrono.cpp
CommandLineTest.cpp
@@ -63,4 +66,4 @@ add_llvm_unittest(SupportTests
)
# ManagedStatic.cpp uses <pthread>.
-target_link_libraries(SupportTests ${PTHREAD_LIB})
+target_link_libraries(SupportTests ${LLVM_PTHREAD_LIB})
diff --git a/unittests/Support/CachePruningTest.cpp b/unittests/Support/CachePruningTest.cpp
new file mode 100644
index 0000000000000..04ac0d09b4935
--- /dev/null
+++ b/unittests/Support/CachePruningTest.cpp
@@ -0,0 +1,71 @@
+//===- CachePruningTest.cpp -----------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/CachePruning.h"
+#include "llvm/Support/Error.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+TEST(CachePruningPolicyParser, Empty) {
+ auto P = parseCachePruningPolicy("");
+ ASSERT_TRUE(bool(P));
+ EXPECT_EQ(std::chrono::seconds(1200), P->Interval);
+ EXPECT_EQ(std::chrono::hours(7 * 24), P->Expiration);
+ EXPECT_EQ(75u, P->PercentageOfAvailableSpace);
+}
+
+TEST(CachePruningPolicyParser, Interval) {
+ auto P = parseCachePruningPolicy("prune_interval=1s");
+ ASSERT_TRUE(bool(P));
+ EXPECT_EQ(std::chrono::seconds(1), P->Interval);
+ P = parseCachePruningPolicy("prune_interval=2m");
+ ASSERT_TRUE(bool(P));
+ EXPECT_EQ(std::chrono::minutes(2), P->Interval);
+ P = parseCachePruningPolicy("prune_interval=3h");
+ ASSERT_TRUE(bool(P));
+ EXPECT_EQ(std::chrono::hours(3), P->Interval);
+}
+
+TEST(CachePruningPolicyParser, Expiration) {
+ auto P = parseCachePruningPolicy("prune_after=1s");
+ ASSERT_TRUE(bool(P));
+ EXPECT_EQ(std::chrono::seconds(1), P->Expiration);
+}
+
+TEST(CachePruningPolicyParser, PercentageOfAvailableSpace) {
+ auto P = parseCachePruningPolicy("cache_size=100%");
+ ASSERT_TRUE(bool(P));
+ EXPECT_EQ(100u, P->PercentageOfAvailableSpace);
+}
+
+TEST(CachePruningPolicyParser, Multiple) {
+ auto P = parseCachePruningPolicy("prune_after=1s:cache_size=50%");
+ ASSERT_TRUE(bool(P));
+ EXPECT_EQ(std::chrono::seconds(1200), P->Interval);
+ EXPECT_EQ(std::chrono::seconds(1), P->Expiration);
+ EXPECT_EQ(50u, P->PercentageOfAvailableSpace);
+}
+
+TEST(CachePruningPolicyParser, Errors) {
+ EXPECT_EQ("Duration must not be empty",
+ toString(parseCachePruningPolicy("prune_interval=").takeError()));
+ EXPECT_EQ("'foo' not an integer",
+ toString(parseCachePruningPolicy("prune_interval=foos").takeError()));
+ EXPECT_EQ("'24x' must end with one of 's', 'm' or 'h'",
+ toString(parseCachePruningPolicy("prune_interval=24x").takeError()));
+ EXPECT_EQ("'foo' must be a percentage",
+ toString(parseCachePruningPolicy("cache_size=foo").takeError()));
+ EXPECT_EQ("'foo' not an integer",
+ toString(parseCachePruningPolicy("cache_size=foo%").takeError()));
+ EXPECT_EQ("'101' must be between 0 and 100",
+ toString(parseCachePruningPolicy("cache_size=101%").takeError()));
+ EXPECT_EQ("Unknown key: 'foo'",
+ toString(parseCachePruningPolicy("foo=bar").takeError()));
+}
diff --git a/unittests/Support/Casting.cpp b/unittests/Support/Casting.cpp
index e6c35fc21eb7d..9a818f6bdebde 100644
--- a/unittests/Support/Casting.cpp
+++ b/unittests/Support/Casting.cpp
@@ -40,6 +40,14 @@ struct foo {
}*/
};
+struct base {
+ virtual ~base() {}
+};
+
+struct derived : public base {
+ static bool classof(const base *B) { return true; }
+};
+
template <> struct isa_impl<foo, bar> {
static inline bool doit(const bar &Val) {
dbgs() << "Classof: " << &Val << "\n";
@@ -47,6 +55,10 @@ template <> struct isa_impl<foo, bar> {
}
};
+template <typename T> struct isa_impl<foo, T> {
+ static inline bool doit(const T &Val) { return false; }
+};
+
foo *bar::baz() {
return cast<foo>(this);
}
@@ -123,6 +135,13 @@ TEST(CastingTest, cast) {
// EXPECT_EQ(F7, null_foo);
foo *F8 = B1.baz();
EXPECT_NE(F8, null_foo);
+
+ std::unique_ptr<const bar> BP(B2);
+ auto FP = cast<foo>(std::move(BP));
+ static_assert(std::is_same<std::unique_ptr<const foo>, decltype(FP)>::value,
+ "Incorrect deduced return type!");
+ EXPECT_NE(FP.get(), null_foo);
+ FP.release();
}
TEST(CastingTest, cast_or_null) {
@@ -136,6 +155,10 @@ TEST(CastingTest, cast_or_null) {
EXPECT_EQ(F14, null_foo);
foo *F15 = B1.caz();
EXPECT_NE(F15, null_foo);
+
+ std::unique_ptr<const bar> BP(fub());
+ auto FP = cast_or_null<foo>(std::move(BP));
+ EXPECT_EQ(FP.get(), null_foo);
}
TEST(CastingTest, dyn_cast) {
@@ -165,6 +188,58 @@ TEST(CastingTest, dyn_cast_or_null) {
EXPECT_NE(F5, null_foo);
}
+std::unique_ptr<derived> newd() { return llvm::make_unique<derived>(); }
+std::unique_ptr<base> newb() { return llvm::make_unique<derived>(); }
+
+TEST(CastingTest, unique_dyn_cast) {
+ derived *OrigD = nullptr;
+ auto D = llvm::make_unique<derived>();
+ OrigD = D.get();
+
+ // Converting from D to itself is valid, it should return a new unique_ptr
+ // and the old one should become nullptr.
+ auto NewD = unique_dyn_cast<derived>(D);
+ ASSERT_EQ(OrigD, NewD.get());
+ ASSERT_EQ(nullptr, D);
+
+ // Converting from D to B is valid, B should have a value and D should be
+ // nullptr.
+ auto B = unique_dyn_cast<base>(NewD);
+ ASSERT_EQ(OrigD, B.get());
+ ASSERT_EQ(nullptr, NewD);
+
+ // Converting from B to itself is valid, it should return a new unique_ptr
+ // and the old one should become nullptr.
+ auto NewB = unique_dyn_cast<base>(B);
+ ASSERT_EQ(OrigD, NewB.get());
+ ASSERT_EQ(nullptr, B);
+
+ // Converting from B to D is valid, D should have a value and B should be
+ // nullptr;
+ D = unique_dyn_cast<derived>(NewB);
+ ASSERT_EQ(OrigD, D.get());
+ ASSERT_EQ(nullptr, NewB);
+
+ // Converting between unrelated types should fail. The original value should
+ // remain unchanged and it should return nullptr.
+ auto F = unique_dyn_cast<foo>(D);
+ ASSERT_EQ(nullptr, F);
+ ASSERT_EQ(OrigD, D.get());
+
+ // All of the above should also hold for temporaries.
+ auto D2 = unique_dyn_cast<derived>(newd());
+ EXPECT_NE(nullptr, D2);
+
+ auto B2 = unique_dyn_cast<derived>(newb());
+ EXPECT_NE(nullptr, B2);
+
+ auto B3 = unique_dyn_cast<base>(newb());
+ EXPECT_NE(nullptr, B3);
+
+ auto F2 = unique_dyn_cast<foo>(newb());
+ EXPECT_EQ(nullptr, F2);
+}
+
// These lines are errors...
//foo *F20 = cast<foo>(B2); // Yields const foo*
//foo &F21 = cast<foo>(B3); // Yields const foo&
diff --git a/unittests/Support/Chrono.cpp b/unittests/Support/Chrono.cpp
index 3d5787807563e..1410baf848bb8 100644
--- a/unittests/Support/Chrono.cpp
+++ b/unittests/Support/Chrono.cpp
@@ -9,6 +9,7 @@
#include "llvm/Support/Chrono.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/FormatVariadic.h"
#include "gtest/gtest.h"
using namespace llvm;
@@ -76,4 +77,34 @@ TEST(Chrono, ImplicitConversions) {
EXPECT_EQ(TimeT, toTimeT(Nano));
}
+TEST(Chrono, DurationFormat) {
+ EXPECT_EQ("1 h", formatv("{0}", hours(1)).str());
+ EXPECT_EQ("1 m", formatv("{0}", minutes(1)).str());
+ EXPECT_EQ("1 s", formatv("{0}", seconds(1)).str());
+ EXPECT_EQ("1 ms", formatv("{0}", milliseconds(1)).str());
+ EXPECT_EQ("1 us", formatv("{0}", microseconds(1)).str());
+ EXPECT_EQ("1 ns", formatv("{0}", nanoseconds(1)).str());
+
+ EXPECT_EQ("1 s", formatv("{0:+}", seconds(1)).str());
+ EXPECT_EQ("1", formatv("{0:-}", seconds(1)).str());
+
+ EXPECT_EQ("1000 ms", formatv("{0:ms}", seconds(1)).str());
+ EXPECT_EQ("1000000 us", formatv("{0:us}", seconds(1)).str());
+ EXPECT_EQ("1000", formatv("{0:ms-}", seconds(1)).str());
+
+ EXPECT_EQ("1,000 ms", formatv("{0:+n}", milliseconds(1000)).str());
+ EXPECT_EQ("0x3e8", formatv("{0:-x}", milliseconds(1000)).str());
+ EXPECT_EQ("010", formatv("{0:-3}", milliseconds(10)).str());
+ EXPECT_EQ("10,000", formatv("{0:ms-n}", seconds(10)).str());
+
+ EXPECT_EQ("1.00 s", formatv("{0}", duration<float>(1)).str());
+ EXPECT_EQ("0.123 s", formatv("{0:+3}", duration<float>(0.123f)).str());
+ EXPECT_EQ("1.230e-01 s", formatv("{0:+e3}", duration<float>(0.123f)).str());
+
+ typedef duration<float, std::ratio<60 * 60 * 24 * 14, 1000000>>
+ microfortnights;
+ EXPECT_EQ("1.00", formatv("{0:-}", microfortnights(1)).str());
+ EXPECT_EQ("1209.60 ms", formatv("{0:ms}", microfortnights(1)).str());
+}
+
} // anonymous namespace
diff --git a/unittests/Support/CommandLineTest.cpp b/unittests/Support/CommandLineTest.cpp
index 945eb1d4e1cfe..33573c4e69607 100644
--- a/unittests/Support/CommandLineTest.cpp
+++ b/unittests/Support/CommandLineTest.cpp
@@ -303,7 +303,8 @@ TEST(CommandLineTest, SetValueInSubcategories) {
EXPECT_FALSE(SC1Opt);
EXPECT_FALSE(SC2Opt);
const char *args[] = {"prog", "-top-level"};
- EXPECT_TRUE(cl::ParseCommandLineOptions(2, args, StringRef(), true));
+ EXPECT_TRUE(
+ cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls()));
EXPECT_TRUE(TopLevelOpt);
EXPECT_FALSE(SC1Opt);
EXPECT_FALSE(SC2Opt);
@@ -315,7 +316,8 @@ TEST(CommandLineTest, SetValueInSubcategories) {
EXPECT_FALSE(SC1Opt);
EXPECT_FALSE(SC2Opt);
const char *args2[] = {"prog", "sc1", "-sc1"};
- EXPECT_TRUE(cl::ParseCommandLineOptions(3, args2, StringRef(), true));
+ EXPECT_TRUE(
+ cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls()));
EXPECT_FALSE(TopLevelOpt);
EXPECT_TRUE(SC1Opt);
EXPECT_FALSE(SC2Opt);
@@ -327,7 +329,8 @@ TEST(CommandLineTest, SetValueInSubcategories) {
EXPECT_FALSE(SC1Opt);
EXPECT_FALSE(SC2Opt);
const char *args3[] = {"prog", "sc2", "-sc2"};
- EXPECT_TRUE(cl::ParseCommandLineOptions(3, args3, StringRef(), true));
+ EXPECT_TRUE(
+ cl::ParseCommandLineOptions(3, args3, StringRef(), &llvm::nulls()));
EXPECT_FALSE(TopLevelOpt);
EXPECT_FALSE(SC1Opt);
EXPECT_TRUE(SC2Opt);
@@ -342,8 +345,13 @@ TEST(CommandLineTest, LookupFailsInWrongSubCommand) {
StackOption<bool> SC1Opt("sc1", cl::sub(SC1), cl::init(false));
StackOption<bool> SC2Opt("sc2", cl::sub(SC2), cl::init(false));
+ std::string Errs;
+ raw_string_ostream OS(Errs);
+
const char *args[] = {"prog", "sc1", "-sc2"};
- EXPECT_FALSE(cl::ParseCommandLineOptions(3, args, StringRef(), true));
+ EXPECT_FALSE(cl::ParseCommandLineOptions(3, args, StringRef(), &OS));
+ OS.flush();
+ EXPECT_FALSE(Errs.empty());
}
TEST(CommandLineTest, AddToAllSubCommands) {
@@ -358,23 +366,30 @@ TEST(CommandLineTest, AddToAllSubCommands) {
const char *args2[] = {"prog", "sc1", "-everywhere"};
const char *args3[] = {"prog", "sc2", "-everywhere"};
+ std::string Errs;
+ raw_string_ostream OS(Errs);
+
EXPECT_FALSE(AllOpt);
- EXPECT_TRUE(cl::ParseCommandLineOptions(2, args, StringRef(), true));
+ EXPECT_TRUE(cl::ParseCommandLineOptions(2, args, StringRef(), &OS));
EXPECT_TRUE(AllOpt);
AllOpt = false;
cl::ResetAllOptionOccurrences();
EXPECT_FALSE(AllOpt);
- EXPECT_TRUE(cl::ParseCommandLineOptions(3, args2, StringRef(), true));
+ EXPECT_TRUE(cl::ParseCommandLineOptions(3, args2, StringRef(), &OS));
EXPECT_TRUE(AllOpt);
AllOpt = false;
cl::ResetAllOptionOccurrences();
EXPECT_FALSE(AllOpt);
- EXPECT_TRUE(cl::ParseCommandLineOptions(3, args3, StringRef(), true));
+ EXPECT_TRUE(cl::ParseCommandLineOptions(3, args3, StringRef(), &OS));
EXPECT_TRUE(AllOpt);
+
+ // Since all parsing succeeded, the error message should be empty.
+ OS.flush();
+ EXPECT_TRUE(Errs.empty());
}
TEST(CommandLineTest, ReparseCommandLineOptions) {
@@ -386,14 +401,16 @@ TEST(CommandLineTest, ReparseCommandLineOptions) {
const char *args[] = {"prog", "-top-level"};
EXPECT_FALSE(TopLevelOpt);
- EXPECT_TRUE(cl::ParseCommandLineOptions(2, args, StringRef(), true));
+ EXPECT_TRUE(
+ cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls()));
EXPECT_TRUE(TopLevelOpt);
TopLevelOpt = false;
cl::ResetAllOptionOccurrences();
EXPECT_FALSE(TopLevelOpt);
- EXPECT_TRUE(cl::ParseCommandLineOptions(2, args, StringRef(), true));
+ EXPECT_TRUE(
+ cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls()));
EXPECT_TRUE(TopLevelOpt);
}
@@ -406,14 +423,21 @@ TEST(CommandLineTest, RemoveFromRegularSubCommand) {
const char *args[] = {"prog", "sc", "-remove-option"};
+ std::string Errs;
+ raw_string_ostream OS(Errs);
+
EXPECT_FALSE(RemoveOption);
- EXPECT_TRUE(cl::ParseCommandLineOptions(3, args, StringRef(), true));
+ EXPECT_TRUE(cl::ParseCommandLineOptions(3, args, StringRef(), &OS));
EXPECT_TRUE(RemoveOption);
+ OS.flush();
+ EXPECT_TRUE(Errs.empty());
RemoveOption.removeArgument();
cl::ResetAllOptionOccurrences();
- EXPECT_FALSE(cl::ParseCommandLineOptions(3, args, StringRef(), true));
+ EXPECT_FALSE(cl::ParseCommandLineOptions(3, args, StringRef(), &OS));
+ OS.flush();
+ EXPECT_FALSE(Errs.empty());
}
TEST(CommandLineTest, RemoveFromTopLevelSubCommand) {
@@ -427,13 +451,15 @@ TEST(CommandLineTest, RemoveFromTopLevelSubCommand) {
const char *args[] = {"prog", "-top-level-remove"};
EXPECT_FALSE(TopLevelRemove);
- EXPECT_TRUE(cl::ParseCommandLineOptions(2, args, StringRef(), true));
+ EXPECT_TRUE(
+ cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls()));
EXPECT_TRUE(TopLevelRemove);
TopLevelRemove.removeArgument();
cl::ResetAllOptionOccurrences();
- EXPECT_FALSE(cl::ParseCommandLineOptions(2, args, StringRef(), true));
+ EXPECT_FALSE(
+ cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls()));
}
TEST(CommandLineTest, RemoveFromAllSubCommands) {
@@ -452,32 +478,38 @@ TEST(CommandLineTest, RemoveFromAllSubCommands) {
// It should work for all subcommands including the top-level.
EXPECT_FALSE(RemoveOption);
- EXPECT_TRUE(cl::ParseCommandLineOptions(2, args0, StringRef(), true));
+ EXPECT_TRUE(
+ cl::ParseCommandLineOptions(2, args0, StringRef(), &llvm::nulls()));
EXPECT_TRUE(RemoveOption);
RemoveOption = false;
cl::ResetAllOptionOccurrences();
EXPECT_FALSE(RemoveOption);
- EXPECT_TRUE(cl::ParseCommandLineOptions(3, args1, StringRef(), true));
+ EXPECT_TRUE(
+ cl::ParseCommandLineOptions(3, args1, StringRef(), &llvm::nulls()));
EXPECT_TRUE(RemoveOption);
RemoveOption = false;
cl::ResetAllOptionOccurrences();
EXPECT_FALSE(RemoveOption);
- EXPECT_TRUE(cl::ParseCommandLineOptions(3, args2, StringRef(), true));
+ EXPECT_TRUE(
+ cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls()));
EXPECT_TRUE(RemoveOption);
RemoveOption.removeArgument();
// It should not work for any subcommands including the top-level.
cl::ResetAllOptionOccurrences();
- EXPECT_FALSE(cl::ParseCommandLineOptions(2, args0, StringRef(), true));
+ EXPECT_FALSE(
+ cl::ParseCommandLineOptions(2, args0, StringRef(), &llvm::nulls()));
cl::ResetAllOptionOccurrences();
- EXPECT_FALSE(cl::ParseCommandLineOptions(3, args1, StringRef(), true));
+ EXPECT_FALSE(
+ cl::ParseCommandLineOptions(3, args1, StringRef(), &llvm::nulls()));
cl::ResetAllOptionOccurrences();
- EXPECT_FALSE(cl::ParseCommandLineOptions(3, args2, StringRef(), true));
+ EXPECT_FALSE(
+ cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls()));
}
TEST(CommandLineTest, GetRegisteredSubcommands) {
@@ -491,7 +523,8 @@ TEST(CommandLineTest, GetRegisteredSubcommands) {
const char *args0[] = {"prog", "sc1"};
const char *args1[] = {"prog", "sc2"};
- EXPECT_TRUE(cl::ParseCommandLineOptions(2, args0, StringRef(), true));
+ EXPECT_TRUE(
+ cl::ParseCommandLineOptions(2, args0, StringRef(), &llvm::nulls()));
EXPECT_FALSE(Opt1);
EXPECT_FALSE(Opt2);
for (auto *S : cl::getRegisteredSubcommands()) {
@@ -500,7 +533,8 @@ TEST(CommandLineTest, GetRegisteredSubcommands) {
}
cl::ResetAllOptionOccurrences();
- EXPECT_TRUE(cl::ParseCommandLineOptions(2, args1, StringRef(), true));
+ EXPECT_TRUE(
+ cl::ParseCommandLineOptions(2, args1, StringRef(), &llvm::nulls()));
EXPECT_FALSE(Opt1);
EXPECT_FALSE(Opt2);
for (auto *S : cl::getRegisteredSubcommands()) {
diff --git a/unittests/Support/CompressionTest.cpp b/unittests/Support/CompressionTest.cpp
index 36b84d85f22be..18a6175460d36 100644
--- a/unittests/Support/CompressionTest.cpp
+++ b/unittests/Support/CompressionTest.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/Compression.h"
+#include "llvm/Support/Error.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Config/config.h"
@@ -26,15 +27,21 @@ namespace {
void TestZlibCompression(StringRef Input, zlib::CompressionLevel Level) {
SmallString<32> Compressed;
SmallString<32> Uncompressed;
- EXPECT_EQ(zlib::StatusOK, zlib::compress(Input, Compressed, Level));
+
+ Error E = zlib::compress(Input, Compressed, Level);
+ EXPECT_FALSE(E);
+ consumeError(std::move(E));
+
// Check that uncompressed buffer is the same as original.
- EXPECT_EQ(zlib::StatusOK,
- zlib::uncompress(Compressed, Uncompressed, Input.size()));
+ E = zlib::uncompress(Compressed, Uncompressed, Input.size());
+ EXPECT_FALSE(E);
+ consumeError(std::move(E));
+
EXPECT_EQ(Input, Uncompressed);
if (Input.size() > 0) {
// Uncompression fails if expected length is too short.
- EXPECT_EQ(zlib::StatusBufferTooShort,
- zlib::uncompress(Compressed, Uncompressed, Input.size() - 1));
+ E = zlib::uncompress(Compressed, Uncompressed, Input.size() - 1);
+ EXPECT_EQ("zlib error: Z_BUF_ERROR", llvm::toString(std::move(E)));
}
}
diff --git a/unittests/Support/ErrorTest.cpp b/unittests/Support/ErrorTest.cpp
index 29a173a058b61..382346cd231ac 100644
--- a/unittests/Support/ErrorTest.cpp
+++ b/unittests/Support/ErrorTest.cpp
@@ -469,6 +469,34 @@ TEST(Error, ExitOnError) {
<< "exitOnError returned an unexpected error result";
}
+// Test that the ExitOnError utility works as expected.
+TEST(Error, CantFailSuccess) {
+ cantFail(Error::success());
+
+ int X = cantFail(Expected<int>(42));
+ EXPECT_EQ(X, 42) << "Expected value modified by cantFail";
+}
+
+// Test that cantFail results in a crash if you pass it a failure value.
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+TEST(Error, CantFailDeath) {
+ EXPECT_DEATH(
+ cantFail(make_error<StringError>("foo", inconvertibleErrorCode())),
+ "Failure value returned from cantFail wrapped call")
+ << "cantFail(Error) did not cause an abort for failure value";
+
+ EXPECT_DEATH(
+ {
+ auto IEC = inconvertibleErrorCode();
+ int X = cantFail(Expected<int>(make_error<StringError>("foo", IEC)));
+ (void)X;
+ },
+ "Failure value returned from cantFail wrapped call")
+ << "cantFail(Expected<int>) did not cause an abort for failure value";
+}
+#endif
+
+
// Test Checked Expected<T> in success mode.
TEST(Error, CheckedExpectedInSuccessMode) {
Expected<int> A = 7;
diff --git a/unittests/Support/FormatVariadicTest.cpp b/unittests/Support/FormatVariadicTest.cpp
index 9307c6d8e09b5..b0c843870afc2 100644
--- a/unittests/Support/FormatVariadicTest.cpp
+++ b/unittests/Support/FormatVariadicTest.cpp
@@ -324,11 +324,13 @@ TEST(FormatVariadicTest, StringFormatting) {
const char FooArray[] = "FooArray";
const char *FooPtr = "FooPtr";
llvm::StringRef FooRef("FooRef");
+ constexpr StringLiteral FooLiteral("FooLiteral");
std::string FooString("FooString");
// 1. Test that we can print various types of strings.
EXPECT_EQ(FooArray, formatv("{0}", FooArray).str());
EXPECT_EQ(FooPtr, formatv("{0}", FooPtr).str());
EXPECT_EQ(FooRef, formatv("{0}", FooRef).str());
+ EXPECT_EQ(FooLiteral, formatv("{0}", FooLiteral).str());
EXPECT_EQ(FooString, formatv("{0}", FooString).str());
// 2. Test that the precision specifier prints the correct number of
diff --git a/unittests/Support/Host.cpp b/unittests/Support/Host.cpp
index 934a604954272..fd53697793c7e 100644
--- a/unittests/Support/Host.cpp
+++ b/unittests/Support/Host.cpp
@@ -17,25 +17,17 @@ using namespace llvm;
class HostTest : public testing::Test {
Triple Host;
- SmallVector<std::pair<Triple::ArchType, Triple::OSType>, 4> SupportedArchAndOSs;
protected:
bool isSupportedArchAndOS() {
- if (is_contained(SupportedArchAndOSs, std::make_pair(Host.getArch(), Host.getOS())))
- return true;
-
- return false;
- }
-
- HostTest() {
- Host.setTriple(Triple::normalize(sys::getProcessTriple()));
-
// Initially this is only testing detection of the number of
// physical cores, which is currently only supported/tested for
// x86_64 Linux and Darwin.
- SupportedArchAndOSs.push_back(std::make_pair(Triple::x86_64, Triple::Linux));
- SupportedArchAndOSs.push_back(std::make_pair(Triple::x86_64, Triple::Darwin));
+ return (Host.getArch() == Triple::x86_64 &&
+ (Host.isOSDarwin() || Host.getOS() == Triple::Linux));
}
+
+ HostTest() : Host(Triple::normalize(sys::getProcessTriple())) {}
};
TEST_F(HostTest, NumPhysicalCores) {
@@ -46,3 +38,79 @@ TEST_F(HostTest, NumPhysicalCores) {
else
ASSERT_EQ(Num, -1);
}
+
+TEST(getLinuxHostCPUName, ARM) {
+ StringRef CortexA9ProcCpuinfo = R"(
+processor : 0
+model name : ARMv7 Processor rev 10 (v7l)
+BogoMIPS : 1393.66
+Features : half thumb fastmult vfp edsp thumbee neon vfpv3 tls vfpd32
+CPU implementer : 0x41
+CPU architecture: 7
+CPU variant : 0x2
+CPU part : 0xc09
+CPU revision : 10
+
+processor : 1
+model name : ARMv7 Processor rev 10 (v7l)
+BogoMIPS : 1393.66
+Features : half thumb fastmult vfp edsp thumbee neon vfpv3 tls vfpd32
+CPU implementer : 0x41
+CPU architecture: 7
+CPU variant : 0x2
+CPU part : 0xc09
+CPU revision : 10
+
+Hardware : Generic OMAP4 (Flattened Device Tree)
+Revision : 0000
+Serial : 0000000000000000
+)";
+
+ EXPECT_EQ(sys::detail::getHostCPUNameForARM(CortexA9ProcCpuinfo),
+ "cortex-a9");
+ EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x41\n"
+ "CPU part : 0xc0f"),
+ "cortex-a15");
+ // Verify that both CPU implementer and CPU part are checked:
+ EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x40\n"
+ "CPU part : 0xc0f"),
+ "generic");
+ EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x51\n"
+ "CPU part : 0x06f"),
+ "krait");
+}
+
+TEST(getLinuxHostCPUName, AArch64) {
+ EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x41\n"
+ "CPU part : 0xd03"),
+ "cortex-a53");
+ // Verify that both CPU implementer and CPU part are checked:
+ EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x40\n"
+ "CPU part : 0xd03"),
+ "generic");
+ EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x51\n"
+ "CPU part : 0x201"),
+ "kryo");
+
+ // MSM8992/4 weirdness
+ StringRef MSM8992ProcCpuInfo = R"(
+Processor : AArch64 Processor rev 3 (aarch64)
+processor : 0
+processor : 1
+processor : 2
+processor : 3
+processor : 4
+processor : 5
+Features : fp asimd evtstrm aes pmull sha1 sha2 crc32
+CPU implementer : 0x41
+CPU architecture: 8
+CPU variant : 0x0
+CPU part : 0xd03
+CPU revision : 3
+
+Hardware : Qualcomm Technologies, Inc MSM8992
+)";
+
+ EXPECT_EQ(sys::detail::getHostCPUNameForARM(MSM8992ProcCpuInfo),
+ "cortex-a53");
+}
diff --git a/unittests/Support/LEB128Test.cpp b/unittests/Support/LEB128Test.cpp
index 76b63e5a83817..061936df1d19d 100644
--- a/unittests/Support/LEB128Test.cpp
+++ b/unittests/Support/LEB128Test.cpp
@@ -17,26 +17,45 @@ using namespace llvm;
namespace {
TEST(LEB128Test, EncodeSLEB128) {
-#define EXPECT_SLEB128_EQ(EXPECTED, VALUE) \
+#define EXPECT_SLEB128_EQ(EXPECTED, VALUE, PAD) \
do { \
- /* encodeSLEB128(uint64_t, raw_ostream &) */ \
std::string Expected(EXPECTED, sizeof(EXPECTED) - 1); \
- std::string Actual; \
- raw_string_ostream Stream(Actual); \
- encodeSLEB128(VALUE, Stream); \
+ \
+ /* encodeSLEB128(uint64_t, raw_ostream &, unsigned) */ \
+ std::string Actual1; \
+ raw_string_ostream Stream(Actual1); \
+ encodeSLEB128(VALUE, Stream, PAD); \
Stream.flush(); \
- EXPECT_EQ(Expected, Actual); \
+ EXPECT_EQ(Expected, Actual1); \
+ \
+ /* encodeSLEB128(uint64_t, uint8_t *, unsigned) */ \
+ uint8_t Buffer[32]; \
+ unsigned Size = encodeSLEB128(VALUE, Buffer, PAD); \
+ std::string Actual2(reinterpret_cast<const char *>(Buffer), Size); \
+ EXPECT_EQ(Expected, Actual2); \
} while (0)
// Encode SLEB128
- EXPECT_SLEB128_EQ("\x00", 0);
- EXPECT_SLEB128_EQ("\x01", 1);
- EXPECT_SLEB128_EQ("\x7f", -1);
- EXPECT_SLEB128_EQ("\x3f", 63);
- EXPECT_SLEB128_EQ("\x41", -63);
- EXPECT_SLEB128_EQ("\x40", -64);
- EXPECT_SLEB128_EQ("\xbf\x7f", -65);
- EXPECT_SLEB128_EQ("\xc0\x00", 64);
+ EXPECT_SLEB128_EQ("\x00", 0, 0);
+ EXPECT_SLEB128_EQ("\x01", 1, 0);
+ EXPECT_SLEB128_EQ("\x7f", -1, 0);
+ EXPECT_SLEB128_EQ("\x3f", 63, 0);
+ EXPECT_SLEB128_EQ("\x41", -63, 0);
+ EXPECT_SLEB128_EQ("\x40", -64, 0);
+ EXPECT_SLEB128_EQ("\xbf\x7f", -65, 0);
+ EXPECT_SLEB128_EQ("\xc0\x00", 64, 0);
+
+ // Encode SLEB128 with some extra padding bytes
+ EXPECT_SLEB128_EQ("\x80\x00", 0, 1);
+ EXPECT_SLEB128_EQ("\x80\x80\x00", 0, 2);
+ EXPECT_SLEB128_EQ("\xff\x80\x00", 0x7f, 1);
+ EXPECT_SLEB128_EQ("\xff\x80\x80\x00", 0x7f, 2);
+ EXPECT_SLEB128_EQ("\x80\x81\x00", 0x80, 1);
+ EXPECT_SLEB128_EQ("\x80\x81\x80\x00", 0x80, 2);
+ EXPECT_SLEB128_EQ("\xc0\x7f", -0x40, 1);
+ EXPECT_SLEB128_EQ("\xc0\xff\x7f", -0x40, 2);
+ EXPECT_SLEB128_EQ("\x80\xff\x7f", -0x80, 1);
+ EXPECT_SLEB128_EQ("\x80\xff\xff\x7f", -0x80, 2);
#undef EXPECT_SLEB128_EQ
}
diff --git a/unittests/Support/MD5Test.cpp b/unittests/Support/MD5Test.cpp
index 4d790254503e0..fa9372fde33fa 100644
--- a/unittests/Support/MD5Test.cpp
+++ b/unittests/Support/MD5Test.cpp
@@ -63,8 +63,10 @@ TEST(MD5HashTest, MD5) {
std::array<uint8_t, 16> Vec = MD5::hash(Input);
MD5::MD5Result MD5Res;
SmallString<32> Res;
- memcpy(MD5Res, Vec.data(), Vec.size());
+ memcpy(MD5Res.Bytes.data(), Vec.data(), Vec.size());
MD5::stringifyResult(MD5Res, Res);
EXPECT_EQ(Res, "c3fcd3d76192e4007dfb496cca67e13b");
+ EXPECT_EQ(0x3be167ca6c49fb7dULL, MD5Res.high());
+ EXPECT_EQ(0x00e49261d7d3fcc3ULL, MD5Res.low());
}
}
diff --git a/unittests/Support/Path.cpp b/unittests/Support/Path.cpp
index 30eaa8b278abf..86ad57f3f3ffc 100644
--- a/unittests/Support/Path.cpp
+++ b/unittests/Support/Path.cpp
@@ -8,12 +8,15 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/Path.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Triple.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FileUtilities.h"
+#include "llvm/Support/Host.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include "gtest/gtest.h"
@@ -25,6 +28,7 @@
#endif
#ifdef LLVM_ON_UNIX
+#include <pwd.h>
#include <sys/stat.h>
#endif
@@ -50,6 +54,9 @@ TEST(is_separator, Works) {
EXPECT_FALSE(path::is_separator('-'));
EXPECT_FALSE(path::is_separator(' '));
+ EXPECT_TRUE(path::is_separator('\\', path::Style::windows));
+ EXPECT_FALSE(path::is_separator('\\', path::Style::posix));
+
#ifdef LLVM_ON_WIN32
EXPECT_TRUE(path::is_separator('\\'));
#else
@@ -249,7 +256,6 @@ TEST(Support, AbsolutePathDotIterator) {
}
}
-#ifdef LLVM_ON_WIN32
TEST(Support, AbsolutePathIteratorWin32) {
SmallString<64> Path(StringRef("c:\\c\\e\\foo.txt"));
typedef SmallVector<StringRef, 4> PathComponents;
@@ -262,8 +268,9 @@ TEST(Support, AbsolutePathIteratorWin32) {
// when iterating.
ExpectedPathComponents.insert(ExpectedPathComponents.begin()+1, "\\");
- for (path::const_iterator I = path::begin(Path), E = path::end(Path); I != E;
- ++I) {
+ for (path::const_iterator I = path::begin(Path, path::Style::windows),
+ E = path::end(Path);
+ I != E; ++I) {
ActualPathComponents.push_back(*I);
}
@@ -273,34 +280,29 @@ TEST(Support, AbsolutePathIteratorWin32) {
EXPECT_EQ(ExpectedPathComponents[i].str(), ActualPathComponents[i].str());
}
}
-#endif // LLVM_ON_WIN32
TEST(Support, AbsolutePathIteratorEnd) {
// Trailing slashes are converted to '.' unless they are part of the root path.
- SmallVector<StringRef, 4> Paths;
- Paths.push_back("/foo/");
- Paths.push_back("/foo//");
- Paths.push_back("//net//");
-#ifdef LLVM_ON_WIN32
- Paths.push_back("c:\\\\");
-#endif
-
- for (StringRef Path : Paths) {
- StringRef LastComponent = *path::rbegin(Path);
+ SmallVector<std::pair<StringRef, path::Style>, 4> Paths;
+ Paths.emplace_back("/foo/", path::Style::native);
+ Paths.emplace_back("/foo//", path::Style::native);
+ Paths.emplace_back("//net//", path::Style::native);
+ Paths.emplace_back("c:\\\\", path::Style::windows);
+
+ for (auto &Path : Paths) {
+ StringRef LastComponent = *path::rbegin(Path.first, Path.second);
EXPECT_EQ(".", LastComponent);
}
- SmallVector<StringRef, 3> RootPaths;
- RootPaths.push_back("/");
- RootPaths.push_back("//net/");
-#ifdef LLVM_ON_WIN32
- RootPaths.push_back("c:\\");
-#endif
+ SmallVector<std::pair<StringRef, path::Style>, 3> RootPaths;
+ RootPaths.emplace_back("/", path::Style::native);
+ RootPaths.emplace_back("//net/", path::Style::native);
+ RootPaths.emplace_back("c:\\", path::Style::windows);
- for (StringRef Path : RootPaths) {
- StringRef LastComponent = *path::rbegin(Path);
+ for (auto &Path : RootPaths) {
+ StringRef LastComponent = *path::rbegin(Path.first, Path.second);
EXPECT_EQ(1u, LastComponent.size());
- EXPECT_TRUE(path::is_separator(LastComponent[0]));
+ EXPECT_TRUE(path::is_separator(LastComponent[0], Path.second));
}
}
@@ -327,6 +329,36 @@ TEST(Support, HomeDirectory) {
}
}
+#ifdef LLVM_ON_UNIX
+TEST(Support, HomeDirectoryWithNoEnv) {
+ std::string OriginalStorage;
+ char const *OriginalEnv = ::getenv("HOME");
+ if (OriginalEnv) {
+ // We're going to unset it, so make a copy and save a pointer to the copy
+ // so that we can reset it at the end of the test.
+ OriginalStorage = OriginalEnv;
+ OriginalEnv = OriginalStorage.c_str();
+ }
+
+ // Don't run the test if we have nothing to compare against.
+ struct passwd *pw = getpwuid(getuid());
+ if (!pw || !pw->pw_dir) return;
+
+ ::unsetenv("HOME");
+ EXPECT_EQ(nullptr, ::getenv("HOME"));
+ std::string PwDir = pw->pw_dir;
+
+ SmallString<128> HomeDir;
+ auto status = path::home_directory(HomeDir);
+ EXPECT_TRUE(status);
+ EXPECT_EQ(PwDir, HomeDir);
+
+ // Now put the environment back to its original state (meaning that if it was
+ // unset before, we don't reset it).
+ if (OriginalEnv) ::setenv("HOME", OriginalEnv, 1);
+}
+#endif
+
TEST(Support, UserCacheDirectory) {
SmallString<13> CacheDir;
SmallString<20> CacheDir2;
@@ -496,6 +528,41 @@ TEST_F(FileSystemTest, Unique) {
ASSERT_NO_ERROR(fs::remove(TempPath));
}
+TEST_F(FileSystemTest, RealPath) {
+ ASSERT_NO_ERROR(
+ fs::create_directories(Twine(TestDirectory) + "/test1/test2/test3"));
+ ASSERT_TRUE(fs::exists(Twine(TestDirectory) + "/test1/test2/test3"));
+
+ SmallString<64> RealBase;
+ SmallString<64> Expected;
+ SmallString<64> Actual;
+
+ // TestDirectory itself might be under a symlink or have been specified with
+ // a different case than the existing temp directory. In such cases real_path
+ // on the concatenated path will differ in the TestDirectory portion from
+ // how we specified it. Make sure to compare against the real_path of the
+ // TestDirectory, and not just the value of TestDirectory.
+ ASSERT_NO_ERROR(fs::real_path(TestDirectory, RealBase));
+ path::native(Twine(RealBase) + "/test1/test2", Expected);
+
+ ASSERT_NO_ERROR(fs::real_path(
+ Twine(TestDirectory) + "/././test1/../test1/test2/./test3/..", Actual));
+
+ EXPECT_EQ(Expected, Actual);
+
+ SmallString<64> HomeDir;
+ bool Result = llvm::sys::path::home_directory(HomeDir);
+ if (Result) {
+ ASSERT_NO_ERROR(fs::real_path(HomeDir, Expected));
+ ASSERT_NO_ERROR(fs::real_path("~", Actual, true));
+ EXPECT_EQ(Expected, Actual);
+ ASSERT_NO_ERROR(fs::real_path("~/", Actual, true));
+ EXPECT_EQ(Expected, Actual);
+ }
+
+ ASSERT_NO_ERROR(fs::remove_directories(Twine(TestDirectory) + "/test1"));
+}
+
TEST_F(FileSystemTest, TempFiles) {
// Create a temp file.
int FileDescriptor;
@@ -740,6 +807,118 @@ TEST_F(FileSystemTest, DirectoryIteration) {
ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/reclevel"));
}
+#ifdef LLVM_ON_UNIX
+TEST_F(FileSystemTest, BrokenSymlinkDirectoryIteration) {
+ // Create a known hierarchy to recurse over.
+ ASSERT_NO_ERROR(fs::create_directories(Twine(TestDirectory) + "/symlink"));
+ ASSERT_NO_ERROR(
+ fs::create_link("no_such_file", Twine(TestDirectory) + "/symlink/a"));
+ ASSERT_NO_ERROR(
+ fs::create_directories(Twine(TestDirectory) + "/symlink/b/bb"));
+ ASSERT_NO_ERROR(
+ fs::create_link("no_such_file", Twine(TestDirectory) + "/symlink/b/ba"));
+ ASSERT_NO_ERROR(
+ fs::create_link("no_such_file", Twine(TestDirectory) + "/symlink/b/bc"));
+ ASSERT_NO_ERROR(
+ fs::create_link("no_such_file", Twine(TestDirectory) + "/symlink/c"));
+ ASSERT_NO_ERROR(
+ fs::create_directories(Twine(TestDirectory) + "/symlink/d/dd/ddd"));
+ ASSERT_NO_ERROR(fs::create_link(Twine(TestDirectory) + "/symlink/d/dd",
+ Twine(TestDirectory) + "/symlink/d/da"));
+ ASSERT_NO_ERROR(
+ fs::create_link("no_such_file", Twine(TestDirectory) + "/symlink/e"));
+
+ typedef std::vector<std::string> v_t;
+ v_t visited;
+
+ // The directory iterator doesn't stat the file, so we should be able to
+ // iterate over the whole directory.
+ std::error_code ec;
+ for (fs::directory_iterator i(Twine(TestDirectory) + "/symlink", ec), e;
+ i != e; i.increment(ec)) {
+ ASSERT_NO_ERROR(ec);
+ visited.push_back(path::filename(i->path()));
+ }
+ std::sort(visited.begin(), visited.end());
+ v_t expected = {"a", "b", "c", "d", "e"};
+ ASSERT_TRUE(visited.size() == expected.size());
+ ASSERT_TRUE(std::equal(visited.begin(), visited.end(), expected.begin()));
+ visited.clear();
+
+ // The recursive directory iterator has to stat the file, so we need to skip
+ // the broken symlinks.
+ for (fs::recursive_directory_iterator
+ i(Twine(TestDirectory) + "/symlink", ec),
+ e;
+ i != e; i.increment(ec)) {
+ ASSERT_NO_ERROR(ec);
+
+ fs::file_status status;
+ if (i->status(status) ==
+ std::make_error_code(std::errc::no_such_file_or_directory)) {
+ i.no_push();
+ continue;
+ }
+
+ visited.push_back(path::filename(i->path()));
+ }
+ std::sort(visited.begin(), visited.end());
+ expected = {"b", "bb", "d", "da", "dd", "ddd", "ddd"};
+ ASSERT_TRUE(visited.size() == expected.size());
+ ASSERT_TRUE(std::equal(visited.begin(), visited.end(), expected.begin()));
+ visited.clear();
+
+ // This recursive directory iterator doesn't follow symlinks, so we don't need
+ // to skip them.
+ for (fs::recursive_directory_iterator
+ i(Twine(TestDirectory) + "/symlink", ec, /*follow_symlinks=*/false),
+ e;
+ i != e; i.increment(ec)) {
+ ASSERT_NO_ERROR(ec);
+ visited.push_back(path::filename(i->path()));
+ }
+ std::sort(visited.begin(), visited.end());
+ expected = {"a", "b", "ba", "bb", "bc", "c", "d", "da", "dd", "ddd", "e"};
+ ASSERT_TRUE(visited.size() == expected.size());
+ ASSERT_TRUE(std::equal(visited.begin(), visited.end(), expected.begin()));
+
+ ASSERT_NO_ERROR(fs::remove_directories(Twine(TestDirectory) + "/symlink"));
+}
+#endif
+
+TEST_F(FileSystemTest, Remove) {
+ SmallString<64> BaseDir;
+ SmallString<64> Paths[4];
+ int fds[4];
+ ASSERT_NO_ERROR(fs::createUniqueDirectory("fs_remove", BaseDir));
+
+ ASSERT_NO_ERROR(fs::create_directories(Twine(BaseDir) + "/foo/bar/baz"));
+ ASSERT_NO_ERROR(fs::create_directories(Twine(BaseDir) + "/foo/bar/buzz"));
+ ASSERT_NO_ERROR(fs::createUniqueFile(
+ Twine(BaseDir) + "/foo/bar/baz/%%%%%%.tmp", fds[0], Paths[0]));
+ ASSERT_NO_ERROR(fs::createUniqueFile(
+ Twine(BaseDir) + "/foo/bar/baz/%%%%%%.tmp", fds[1], Paths[1]));
+ ASSERT_NO_ERROR(fs::createUniqueFile(
+ Twine(BaseDir) + "/foo/bar/buzz/%%%%%%.tmp", fds[2], Paths[2]));
+ ASSERT_NO_ERROR(fs::createUniqueFile(
+ Twine(BaseDir) + "/foo/bar/buzz/%%%%%%.tmp", fds[3], Paths[3]));
+
+ for (int fd : fds)
+ ::close(fd);
+
+ EXPECT_TRUE(fs::exists(Twine(BaseDir) + "/foo/bar/baz"));
+ EXPECT_TRUE(fs::exists(Twine(BaseDir) + "/foo/bar/buzz"));
+ EXPECT_TRUE(fs::exists(Paths[0]));
+ EXPECT_TRUE(fs::exists(Paths[1]));
+ EXPECT_TRUE(fs::exists(Paths[2]));
+ EXPECT_TRUE(fs::exists(Paths[3]));
+
+ ASSERT_NO_ERROR(fs::remove_directories("D:/footest"));
+
+ ASSERT_NO_ERROR(fs::remove_directories(BaseDir));
+ ASSERT_FALSE(fs::exists(BaseDir));
+}
+
const char archive[] = "!<arch>\x0A";
const char bitcode[] = "\xde\xc0\x17\x0b";
const char coff_object[] = "\x00\x00......";
@@ -863,6 +1042,20 @@ TEST_F(FileSystemTest, Resize) {
ASSERT_NO_ERROR(fs::remove(TempPath));
}
+TEST_F(FileSystemTest, MD5) {
+ int FD;
+ SmallString<64> TempPath;
+ ASSERT_NO_ERROR(fs::createTemporaryFile("prefix", "temp", FD, TempPath));
+ StringRef Data("abcdefghijklmnopqrstuvwxyz");
+ write(FD, Data.data(), Data.size());
+ lseek(FD, 0, SEEK_SET);
+ auto Hash = fs::md5_contents(FD);
+ ::close(FD);
+ ASSERT_NO_ERROR(Hash.getError());
+
+ EXPECT_STREQ("c3fcd3d76192e4007dfb496cca67e13b", Hash->digest().c_str());
+}
+
TEST_F(FileSystemTest, FileMapping) {
// Create a temp file.
int FileDescriptor;
@@ -906,40 +1099,50 @@ TEST_F(FileSystemTest, FileMapping) {
}
TEST(Support, NormalizePath) {
+ using TestTuple = std::tuple<const char *, const char *, const char *>;
+ std::vector<TestTuple> Tests;
+ Tests.emplace_back("a", "a", "a");
+ Tests.emplace_back("a/b", "a\\b", "a/b");
+ Tests.emplace_back("a\\b", "a\\b", "a/b");
+ Tests.emplace_back("a\\\\b", "a\\\\b", "a\\\\b");
+ Tests.emplace_back("\\a", "\\a", "/a");
+ Tests.emplace_back("a\\", "a\\", "a/");
+
+ for (auto &T : Tests) {
+ SmallString<64> Win(std::get<0>(T));
+ SmallString<64> Posix(Win);
+ path::native(Win, path::Style::windows);
+ path::native(Posix, path::Style::posix);
+ EXPECT_EQ(std::get<1>(T), Win);
+ EXPECT_EQ(std::get<2>(T), Posix);
+ }
+
#if defined(LLVM_ON_WIN32)
-#define EXPECT_PATH_IS(path__, windows__, not_windows__) \
- EXPECT_EQ(path__, windows__);
-#else
-#define EXPECT_PATH_IS(path__, windows__, not_windows__) \
- EXPECT_EQ(path__, not_windows__);
+ SmallString<64> PathHome;
+ path::home_directory(PathHome);
+
+ const char *Path7a = "~/aaa";
+ SmallString<64> Path7(Path7a);
+ path::native(Path7);
+ EXPECT_TRUE(Path7.endswith("\\aaa"));
+ EXPECT_TRUE(Path7.startswith(PathHome));
+ EXPECT_EQ(Path7.size(), PathHome.size() + strlen(Path7a + 1));
+
+ const char *Path8a = "~";
+ SmallString<64> Path8(Path8a);
+ path::native(Path8);
+ EXPECT_EQ(Path8, PathHome);
+
+ const char *Path9a = "~aaa";
+ SmallString<64> Path9(Path9a);
+ path::native(Path9);
+ EXPECT_EQ(Path9, "~aaa");
+
+ const char *Path10a = "aaa/~/b";
+ SmallString<64> Path10(Path10a);
+ path::native(Path10);
+ EXPECT_EQ(Path10, "aaa\\~\\b");
#endif
-
- SmallString<64> Path1("a");
- SmallString<64> Path2("a/b");
- SmallString<64> Path3("a\\b");
- SmallString<64> Path4("a\\\\b");
- SmallString<64> Path5("\\a");
- SmallString<64> Path6("a\\");
-
- path::native(Path1);
- EXPECT_PATH_IS(Path1, "a", "a");
-
- path::native(Path2);
- EXPECT_PATH_IS(Path2, "a\\b", "a/b");
-
- path::native(Path3);
- EXPECT_PATH_IS(Path3, "a\\b", "a/b");
-
- path::native(Path4);
- EXPECT_PATH_IS(Path4, "a\\\\b", "a\\\\b");
-
- path::native(Path5);
- EXPECT_PATH_IS(Path5, "\\a", "/a");
-
- path::native(Path6);
- EXPECT_PATH_IS(Path6, "a\\", "a/");
-
-#undef EXPECT_PATH_IS
}
TEST(Support, RemoveLeadingDotSlash) {
@@ -952,43 +1155,48 @@ TEST(Support, RemoveLeadingDotSlash) {
EXPECT_EQ(Path2, "");
}
-static std::string remove_dots(StringRef path,
- bool remove_dot_dot) {
+static std::string remove_dots(StringRef path, bool remove_dot_dot,
+ path::Style style) {
SmallString<256> buffer(path);
- path::remove_dots(buffer, remove_dot_dot);
+ path::remove_dots(buffer, remove_dot_dot, style);
return buffer.str();
}
TEST(Support, RemoveDots) {
-#if defined(LLVM_ON_WIN32)
- EXPECT_EQ("foolz\\wat", remove_dots(".\\.\\\\foolz\\wat", false));
- EXPECT_EQ("", remove_dots(".\\\\\\\\\\", false));
-
- EXPECT_EQ("a\\..\\b\\c", remove_dots(".\\a\\..\\b\\c", false));
- EXPECT_EQ("b\\c", remove_dots(".\\a\\..\\b\\c", true));
- EXPECT_EQ("c", remove_dots(".\\.\\c", true));
- EXPECT_EQ("..\\a\\c", remove_dots("..\\a\\b\\..\\c", true));
- EXPECT_EQ("..\\..\\a\\c", remove_dots("..\\..\\a\\b\\..\\c", true));
+ EXPECT_EQ("foolz\\wat",
+ remove_dots(".\\.\\\\foolz\\wat", false, path::Style::windows));
+ EXPECT_EQ("", remove_dots(".\\\\\\\\\\", false, path::Style::windows));
+
+ EXPECT_EQ("a\\..\\b\\c",
+ remove_dots(".\\a\\..\\b\\c", false, path::Style::windows));
+ EXPECT_EQ("b\\c", remove_dots(".\\a\\..\\b\\c", true, path::Style::windows));
+ EXPECT_EQ("c", remove_dots(".\\.\\c", true, path::Style::windows));
+ EXPECT_EQ("..\\a\\c",
+ remove_dots("..\\a\\b\\..\\c", true, path::Style::windows));
+ EXPECT_EQ("..\\..\\a\\c",
+ remove_dots("..\\..\\a\\b\\..\\c", true, path::Style::windows));
SmallString<64> Path1(".\\.\\c");
- EXPECT_TRUE(path::remove_dots(Path1, true));
- EXPECT_EQ("c", Path1);
-#else
- EXPECT_EQ("foolz/wat", remove_dots("././/foolz/wat", false));
- EXPECT_EQ("", remove_dots("./////", false));
-
- EXPECT_EQ("a/../b/c", remove_dots("./a/../b/c", false));
- EXPECT_EQ("b/c", remove_dots("./a/../b/c", true));
- EXPECT_EQ("c", remove_dots("././c", true));
- EXPECT_EQ("../a/c", remove_dots("../a/b/../c", true));
- EXPECT_EQ("../../a/c", remove_dots("../../a/b/../c", true));
- EXPECT_EQ("/a/c", remove_dots("/../../a/c", true));
- EXPECT_EQ("/a/c", remove_dots("/../a/b//../././/c", true));
-
- SmallString<64> Path1("././c");
- EXPECT_TRUE(path::remove_dots(Path1, true));
+ EXPECT_TRUE(path::remove_dots(Path1, true, path::Style::windows));
EXPECT_EQ("c", Path1);
-#endif
+
+ EXPECT_EQ("foolz/wat",
+ remove_dots("././/foolz/wat", false, path::Style::posix));
+ EXPECT_EQ("", remove_dots("./////", false, path::Style::posix));
+
+ EXPECT_EQ("a/../b/c", remove_dots("./a/../b/c", false, path::Style::posix));
+ EXPECT_EQ("b/c", remove_dots("./a/../b/c", true, path::Style::posix));
+ EXPECT_EQ("c", remove_dots("././c", true, path::Style::posix));
+ EXPECT_EQ("../a/c", remove_dots("../a/b/../c", true, path::Style::posix));
+ EXPECT_EQ("../../a/c",
+ remove_dots("../../a/b/../c", true, path::Style::posix));
+ EXPECT_EQ("/a/c", remove_dots("/../../a/c", true, path::Style::posix));
+ EXPECT_EQ("/a/c",
+ remove_dots("/../a/b//../././/c", true, path::Style::posix));
+
+ SmallString<64> Path2("././c");
+ EXPECT_TRUE(path::remove_dots(Path2, true, path::Style::posix));
+ EXPECT_EQ("c", Path2);
}
TEST(Support, ReplacePathPrefix) {
@@ -1135,4 +1343,198 @@ TEST_F(FileSystemTest, OpenFileForRead) {
::close(FileDescriptor);
}
+
+TEST_F(FileSystemTest, set_current_path) {
+ SmallString<128> path;
+
+ ASSERT_NO_ERROR(fs::current_path(path));
+ ASSERT_NE(TestDirectory, path);
+
+ struct RestorePath {
+ SmallString<128> path;
+ RestorePath(const SmallString<128> &path) : path(path) {}
+ ~RestorePath() { fs::set_current_path(path); }
+ } restore_path(path);
+
+ ASSERT_NO_ERROR(fs::set_current_path(TestDirectory));
+
+ ASSERT_NO_ERROR(fs::current_path(path));
+
+ fs::UniqueID D1, D2;
+ ASSERT_NO_ERROR(fs::getUniqueID(TestDirectory, D1));
+ ASSERT_NO_ERROR(fs::getUniqueID(path, D2));
+ ASSERT_EQ(D1, D2) << "D1: " << TestDirectory << "\nD2: " << path;
+}
+
+TEST_F(FileSystemTest, permissions) {
+ int FD;
+ SmallString<64> TempPath;
+ ASSERT_NO_ERROR(fs::createTemporaryFile("prefix", "temp", FD, TempPath));
+ FileRemover Cleanup(TempPath);
+
+ // Make sure it exists.
+ ASSERT_TRUE(fs::exists(Twine(TempPath)));
+
+ auto CheckPermissions = [&](fs::perms Expected) {
+ ErrorOr<fs::perms> Actual = fs::getPermissions(TempPath);
+ return Actual && *Actual == Expected;
+ };
+
+ std::error_code NoError;
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::all_all), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_all));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::all_read | fs::all_exe), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_read | fs::all_exe));
+
+#if defined(LLVM_ON_WIN32)
+ fs::perms ReadOnly = fs::all_read | fs::all_exe;
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::no_perms), NoError);
+ EXPECT_TRUE(CheckPermissions(ReadOnly));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_read), NoError);
+ EXPECT_TRUE(CheckPermissions(ReadOnly));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_write), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_all));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_exe), NoError);
+ EXPECT_TRUE(CheckPermissions(ReadOnly));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_all), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_all));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::group_read), NoError);
+ EXPECT_TRUE(CheckPermissions(ReadOnly));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::group_write), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_all));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::group_exe), NoError);
+ EXPECT_TRUE(CheckPermissions(ReadOnly));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::group_all), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_all));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::others_read), NoError);
+ EXPECT_TRUE(CheckPermissions(ReadOnly));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::others_write), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_all));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::others_exe), NoError);
+ EXPECT_TRUE(CheckPermissions(ReadOnly));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::others_all), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_all));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::all_read), NoError);
+ EXPECT_TRUE(CheckPermissions(ReadOnly));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::all_write), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_all));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::all_exe), NoError);
+ EXPECT_TRUE(CheckPermissions(ReadOnly));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::set_uid_on_exe), NoError);
+ EXPECT_TRUE(CheckPermissions(ReadOnly));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::set_gid_on_exe), NoError);
+ EXPECT_TRUE(CheckPermissions(ReadOnly));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::sticky_bit), NoError);
+ EXPECT_TRUE(CheckPermissions(ReadOnly));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::set_uid_on_exe |
+ fs::set_gid_on_exe |
+ fs::sticky_bit),
+ NoError);
+ EXPECT_TRUE(CheckPermissions(ReadOnly));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, ReadOnly | fs::set_uid_on_exe |
+ fs::set_gid_on_exe |
+ fs::sticky_bit),
+ NoError);
+ EXPECT_TRUE(CheckPermissions(ReadOnly));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::all_perms), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_all));
+#else
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::no_perms), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::no_perms));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_read), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::owner_read));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_write), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::owner_write));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_exe), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::owner_exe));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_all), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::owner_all));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::group_read), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::group_read));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::group_write), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::group_write));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::group_exe), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::group_exe));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::group_all), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::group_all));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::others_read), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::others_read));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::others_write), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::others_write));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::others_exe), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::others_exe));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::others_all), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::others_all));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::all_read), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_read));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::all_write), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_write));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::all_exe), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_exe));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::set_uid_on_exe), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::set_uid_on_exe));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::set_gid_on_exe), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::set_gid_on_exe));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::sticky_bit), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::sticky_bit));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::set_uid_on_exe |
+ fs::set_gid_on_exe |
+ fs::sticky_bit),
+ NoError);
+ EXPECT_TRUE(CheckPermissions(fs::set_uid_on_exe | fs::set_gid_on_exe |
+ fs::sticky_bit));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::all_read | fs::set_uid_on_exe |
+ fs::set_gid_on_exe |
+ fs::sticky_bit),
+ NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_read | fs::set_uid_on_exe |
+ fs::set_gid_on_exe | fs::sticky_bit));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::all_perms), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_perms));
+#endif
+}
+
} // anonymous namespace
diff --git a/unittests/Support/ProgramTest.cpp b/unittests/Support/ProgramTest.cpp
index 886ead8305bc1..3926ceb92b3ed 100644
--- a/unittests/Support/ProgramTest.cpp
+++ b/unittests/Support/ProgramTest.cpp
@@ -87,6 +87,7 @@ protected:
EXPECT_TRUE(convStatus);
return EnvStorage.back().c_str();
#else
+ (void)this;
return Var;
#endif
};
diff --git a/unittests/Support/TargetParserTest.cpp b/unittests/Support/TargetParserTest.cpp
index a3d806f76fb51..f0bfe7dbde964 100644
--- a/unittests/Support/TargetParserTest.cpp
+++ b/unittests/Support/TargetParserTest.cpp
@@ -17,17 +17,17 @@ using namespace llvm;
namespace {
const char *ARMArch[] = {
- "armv2", "armv2a", "armv3", "armv3m", "armv4",
- "armv4t", "armv5", "armv5t", "armv5e", "armv5te",
- "armv5tej", "armv6", "armv6j", "armv6k", "armv6hl",
- "armv6t2", "armv6kz", "armv6z", "armv6zk", "armv6-m",
- "armv6m", "armv6sm", "armv6s-m", "armv7-a", "armv7",
- "armv7a", "armv7hl", "armv7l", "armv7-r", "armv7r",
- "armv7-m", "armv7m", "armv7k", "armv7s", "armv7e-m",
- "armv7em", "armv8-a", "armv8", "armv8a", "armv8.1-a",
- "armv8.1a", "armv8.2-a", "armv8.2a", "armv8-r", "armv8r",
- "armv8-m.base", "armv8m.base", "armv8-m.main", "armv8m.main", "iwmmxt",
- "iwmmxt2", "xscale"};
+ "armv2", "armv2a", "armv3", "armv3m", "armv4",
+ "armv4t", "armv5", "armv5t", "armv5e", "armv5te",
+ "armv5tej", "armv6", "armv6j", "armv6k", "armv6hl",
+ "armv6t2", "armv6kz", "armv6z", "armv6zk", "armv6-m",
+ "armv6m", "armv6sm", "armv6s-m", "armv7-a", "armv7",
+ "armv7a", "armv7ve", "armv7hl", "armv7l", "armv7-r",
+ "armv7r", "armv7-m", "armv7m", "armv7k", "armv7s",
+ "armv7e-m", "armv7em", "armv8-a", "armv8", "armv8a",
+ "armv8.1-a", "armv8.1a", "armv8.2-a", "armv8.2a", "armv8-r",
+ "armv8r", "armv8-m.base", "armv8m.base", "armv8-m.main", "armv8m.main",
+ "iwmmxt", "iwmmxt2", "xscale"};
bool testARMCPU(StringRef CPUName, StringRef ExpectedArch,
StringRef ExpectedFPU, unsigned ExpectedFlags,
@@ -246,6 +246,10 @@ TEST(TargetParserTest, testARMCPU) {
ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
ARM::AEK_HWDIV | ARM::AEK_DSP,
"8-A"));
+ EXPECT_TRUE(testARMCPU("cortex-m23", "armv8-m.base", "none",
+ ARM::AEK_HWDIV, "8-M.Baseline"));
+ EXPECT_TRUE(testARMCPU("cortex-m33", "armv8-m.main", "fpv5-sp-d16",
+ ARM::AEK_HWDIV | ARM::AEK_DSP, "8-M.Mainline"));
EXPECT_TRUE(testARMCPU("iwmmxt", "iwmmxt", "none",
ARM::AEK_NONE, "iwmmxt"));
EXPECT_TRUE(testARMCPU("xscale", "xscale", "none",
@@ -311,6 +315,9 @@ TEST(TargetParserTest, testARMArch) {
testARMArch("armv7-a", "cortex-a8", "v7",
ARMBuildAttrs::CPUArch::v7));
EXPECT_TRUE(
+ testARMArch("armv7ve", "generic", "v7ve",
+ ARMBuildAttrs::CPUArch::v7));
+ EXPECT_TRUE(
testARMArch("armv7-r", "cortex-r4", "v7r",
ARMBuildAttrs::CPUArch::v7));
EXPECT_TRUE(
@@ -498,12 +505,12 @@ TEST(TargetParserTest, ARMparseHWDiv) {
TEST(TargetParserTest, ARMparseArchEndianAndISA) {
const char *Arch[] = {
- "v2", "v2a", "v3", "v3m", "v4", "v4t", "v5", "v5t",
- "v5e", "v5te", "v5tej", "v6", "v6j", "v6k", "v6hl", "v6t2",
- "v6kz", "v6z", "v6zk", "v6-m", "v6m", "v6sm", "v6s-m", "v7-a",
- "v7", "v7a", "v7hl", "v7l", "v7-r", "v7r", "v7-m", "v7m",
- "v7k", "v7s", "v7e-m", "v7em", "v8-a", "v8", "v8a", "v8.1-a",
- "v8.1a", "v8.2-a", "v8.2a", "v8-r"};
+ "v2", "v2a", "v3", "v3m", "v4", "v4t", "v5", "v5t",
+ "v5e", "v5te", "v5tej", "v6", "v6j", "v6k", "v6hl", "v6t2",
+ "v6kz", "v6z", "v6zk", "v6-m", "v6m", "v6sm", "v6s-m", "v7-a",
+ "v7", "v7a", "v7ve", "v7hl", "v7l", "v7-r", "v7r", "v7-m",
+ "v7m", "v7k", "v7s", "v7e-m", "v7em", "v8-a", "v8", "v8a",
+ "v8.1-a", "v8.1a", "v8.2-a", "v8.2a", "v8-r"};
for (unsigned i = 0; i < array_lengthof(Arch); i++) {
std::string arm_1 = "armeb" + (std::string)(Arch[i]);
@@ -555,6 +562,7 @@ TEST(TargetParserTest, ARMparseArchProfile) {
EXPECT_EQ(ARM::PK_R, ARM::parseArchProfile(ARMArch[i]));
continue;
case ARM::AK_ARMV7A:
+ case ARM::AK_ARMV7VE:
case ARM::AK_ARMV7K:
case ARM::AK_ARMV8A:
case ARM::AK_ARMV8_1A:
@@ -635,8 +643,29 @@ TEST(TargetParserTest, testAArch64CPU) {
"kryo", "armv8-a", "crypto-neon-fp-armv8",
AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_SIMD, "8-A"));
EXPECT_TRUE(testAArch64CPU(
- "vulcan", "armv8.1-a", "crypto-neon-fp-armv8",
- AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_SIMD, "8.1-A"));
+ "thunderx2t99", "armv8.1-a", "crypto-neon-fp-armv8",
+ AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_LSE |
+ AArch64::AEK_SIMD, "8.1-A"));
+ EXPECT_TRUE(testAArch64CPU(
+ "thunderx", "armv8-a", "crypto-neon-fp-armv8",
+ AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_SIMD |
+ AArch64::AEK_FP | AArch64::AEK_PROFILE,
+ "8-A"));
+ EXPECT_TRUE(testAArch64CPU(
+ "thunderxt81", "armv8-a", "crypto-neon-fp-armv8",
+ AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_SIMD |
+ AArch64::AEK_FP | AArch64::AEK_PROFILE,
+ "8-A"));
+ EXPECT_TRUE(testAArch64CPU(
+ "thunderxt83", "armv8-a", "crypto-neon-fp-armv8",
+ AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_SIMD |
+ AArch64::AEK_FP | AArch64::AEK_PROFILE,
+ "8-A"));
+ EXPECT_TRUE(testAArch64CPU(
+ "thunderxt88", "armv8-a", "crypto-neon-fp-armv8",
+ AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_SIMD |
+ AArch64::AEK_FP | AArch64::AEK_PROFILE,
+ "8-A"));
}
bool testAArch64Arch(StringRef Arch, StringRef DefaultCPU, StringRef SubArch,
@@ -672,7 +701,11 @@ TEST(TargetParserTest, testAArch64Extension) {
EXPECT_FALSE(testAArch64Extension("cyclone", 0, "ras"));
EXPECT_FALSE(testAArch64Extension("exynos-m1", 0, "ras"));
EXPECT_FALSE(testAArch64Extension("kryo", 0, "ras"));
- EXPECT_FALSE(testAArch64Extension("vulcan", 0, "ras"));
+ EXPECT_FALSE(testAArch64Extension("thunderx2t99", 0, "ras"));
+ EXPECT_FALSE(testAArch64Extension("thunderx", 0, "lse"));
+ EXPECT_FALSE(testAArch64Extension("thunderxt81", 0, "lse"));
+ EXPECT_FALSE(testAArch64Extension("thunderxt83", 0, "lse"));
+ EXPECT_FALSE(testAArch64Extension("thunderxt88", 0, "lse"));
EXPECT_FALSE(testAArch64Extension(
"generic", static_cast<unsigned>(AArch64::ArchKind::AK_ARMV8A), "ras"));
diff --git a/unittests/Support/ThreadPool.cpp b/unittests/Support/ThreadPool.cpp
index 8e03aacfb1e03..0da33ad50c078 100644
--- a/unittests/Support/ThreadPool.cpp
+++ b/unittests/Support/ThreadPool.cpp
@@ -90,7 +90,7 @@ TEST_F(ThreadPoolTest, AsyncBarrier) {
ThreadPool Pool;
for (size_t i = 0; i < 5; ++i) {
- Pool.async([this, &checked_in, i] {
+ Pool.async([this, &checked_in] {
waitForMainThread();
++checked_in;
});
@@ -154,7 +154,7 @@ TEST_F(ThreadPoolTest, PoolDestruction) {
{
ThreadPool Pool;
for (size_t i = 0; i < 5; ++i) {
- Pool.async([this, &checked_in, i] {
+ Pool.async([this, &checked_in] {
waitForMainThread();
++checked_in;
});
diff --git a/unittests/Support/TrailingObjectsTest.cpp b/unittests/Support/TrailingObjectsTest.cpp
index cb5c47d1b25be..23acc54d23761 100644
--- a/unittests/Support/TrailingObjectsTest.cpp
+++ b/unittests/Support/TrailingObjectsTest.cpp
@@ -236,3 +236,24 @@ TEST(TrailingObjects, Realignment) {
reinterpret_cast<char *>(C + 1) + 1, alignof(long))));
}
}
+
+// Test the use of TrailingObjects with a template class. This
+// previously failed to compile due to a bug in MSVC's member access
+// control/lookup handling for OverloadToken.
+template <typename Derived>
+class Class5Tmpl : private llvm::TrailingObjects<Derived, float, int> {
+ using TrailingObjects = typename llvm::TrailingObjects<Derived, float>;
+ friend TrailingObjects;
+
+ size_t numTrailingObjects(
+ typename TrailingObjects::template OverloadToken<float>) const {
+ return 1;
+ }
+
+ size_t numTrailingObjects(
+ typename TrailingObjects::template OverloadToken<int>) const {
+ return 2;
+ }
+};
+
+class Class5 : public Class5Tmpl<Class5> {};
diff --git a/unittests/Support/YAMLIOTest.cpp b/unittests/Support/YAMLIOTest.cpp
index dc7c5d47cba96..5a0280c8ca5ba 100644
--- a/unittests/Support/YAMLIOTest.cpp
+++ b/unittests/Support/YAMLIOTest.cpp
@@ -1740,7 +1740,7 @@ TEST(YAMLIO, TestFlagsReadError) {
//
// Test error handling reading built-in uint8_t type
//
-LLVM_YAML_IS_SEQUENCE_VECTOR(uint8_t)
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(uint8_t)
TEST(YAMLIO, TestReadBuiltInTypesUint8Error) {
std::vector<uint8_t> seq;
Input yin("---\n"
@@ -1759,7 +1759,7 @@ TEST(YAMLIO, TestReadBuiltInTypesUint8Error) {
//
// Test error handling reading built-in uint16_t type
//
-LLVM_YAML_IS_SEQUENCE_VECTOR(uint16_t)
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(uint16_t)
TEST(YAMLIO, TestReadBuiltInTypesUint16Error) {
std::vector<uint16_t> seq;
Input yin("---\n"
@@ -1778,7 +1778,7 @@ TEST(YAMLIO, TestReadBuiltInTypesUint16Error) {
//
// Test error handling reading built-in uint32_t type
//
-LLVM_YAML_IS_SEQUENCE_VECTOR(uint32_t)
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(uint32_t)
TEST(YAMLIO, TestReadBuiltInTypesUint32Error) {
std::vector<uint32_t> seq;
Input yin("---\n"
@@ -1797,7 +1797,7 @@ TEST(YAMLIO, TestReadBuiltInTypesUint32Error) {
//
// Test error handling reading built-in uint64_t type
//
-LLVM_YAML_IS_SEQUENCE_VECTOR(uint64_t)
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(uint64_t)
TEST(YAMLIO, TestReadBuiltInTypesUint64Error) {
std::vector<uint64_t> seq;
Input yin("---\n"
@@ -1816,7 +1816,7 @@ TEST(YAMLIO, TestReadBuiltInTypesUint64Error) {
//
// Test error handling reading built-in int8_t type
//
-LLVM_YAML_IS_SEQUENCE_VECTOR(int8_t)
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(int8_t)
TEST(YAMLIO, TestReadBuiltInTypesint8OverError) {
std::vector<int8_t> seq;
Input yin("---\n"
@@ -1854,7 +1854,7 @@ TEST(YAMLIO, TestReadBuiltInTypesint8UnderError) {
//
// Test error handling reading built-in int16_t type
//
-LLVM_YAML_IS_SEQUENCE_VECTOR(int16_t)
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(int16_t)
TEST(YAMLIO, TestReadBuiltInTypesint16UnderError) {
std::vector<int16_t> seq;
Input yin("---\n"
@@ -1893,7 +1893,7 @@ TEST(YAMLIO, TestReadBuiltInTypesint16OverError) {
//
// Test error handling reading built-in int32_t type
//
-LLVM_YAML_IS_SEQUENCE_VECTOR(int32_t)
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(int32_t)
TEST(YAMLIO, TestReadBuiltInTypesint32UnderError) {
std::vector<int32_t> seq;
Input yin("---\n"
@@ -1931,7 +1931,7 @@ TEST(YAMLIO, TestReadBuiltInTypesint32OverError) {
//
// Test error handling reading built-in int64_t type
//
-LLVM_YAML_IS_SEQUENCE_VECTOR(int64_t)
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(int64_t)
TEST(YAMLIO, TestReadBuiltInTypesint64UnderError) {
std::vector<int64_t> seq;
Input yin("---\n"
diff --git a/unittests/Support/raw_ostream_test.cpp b/unittests/Support/raw_ostream_test.cpp
index f87d2f60d169e..777e555949eed 100644
--- a/unittests/Support/raw_ostream_test.cpp
+++ b/unittests/Support/raw_ostream_test.cpp
@@ -9,6 +9,7 @@
#include "gtest/gtest.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
@@ -330,4 +331,11 @@ TEST(raw_ostreamTest, FormattedHexBytes) {
"0007: 68 69 6a 6b 6c |hijkl|",
format_bytes_with_ascii_str(B.take_front(12), 0, 7, 1));
}
+
+TEST(raw_fd_ostreamTest, multiple_raw_fd_ostream_to_stdout) {
+ std::error_code EC;
+
+ { raw_fd_ostream("-", EC, sys::fs::OpenFlags::F_None); }
+ { raw_fd_ostream("-", EC, sys::fs::OpenFlags::F_None); }
+}
}
diff --git a/unittests/Transforms/Scalar/LoopPassManagerTest.cpp b/unittests/Transforms/Scalar/LoopPassManagerTest.cpp
index a099e35c7f195..227060f0a46e1 100644
--- a/unittests/Transforms/Scalar/LoopPassManagerTest.cpp
+++ b/unittests/Transforms/Scalar/LoopPassManagerTest.cpp
@@ -46,7 +46,10 @@ public:
DerivedT *Handle;
- Analysis(DerivedT &Handle) : Handle(&Handle) {}
+ Analysis(DerivedT &Handle) : Handle(&Handle) {
+ static_assert(std::is_base_of<MockAnalysisHandleBase, DerivedT>::value,
+ "Must pass the derived type to this template!");
+ }
public:
class Result {
@@ -152,7 +155,10 @@ public:
DerivedT *Handle;
- Pass(DerivedT &Handle) : Handle(&Handle) {}
+ Pass(DerivedT &Handle) : Handle(&Handle) {
+ static_assert(std::is_base_of<MockPassHandleBase, DerivedT>::value,
+ "Must pass the derived type to this template!");
+ }
public:
PreservedAnalyses run(IRUnitT &IR, AnalysisManagerT &AM,
@@ -244,27 +250,38 @@ protected:
public:
LoopPassManagerTest()
- : M(parseIR(Context, "define void @f() {\n"
- "entry:\n"
- " br label %loop.0\n"
- "loop.0:\n"
- " br i1 undef, label %loop.0.0, label %end\n"
- "loop.0.0:\n"
- " br i1 undef, label %loop.0.0, label %loop.0.1\n"
- "loop.0.1:\n"
- " br i1 undef, label %loop.0.1, label %loop.0\n"
- "end:\n"
- " ret void\n"
- "}\n"
- "\n"
- "define void @g() {\n"
- "entry:\n"
- " br label %loop.g.0\n"
- "loop.g.0:\n"
- " br i1 undef, label %loop.g.0, label %end\n"
- "end:\n"
- " ret void\n"
- "}\n")),
+ : M(parseIR(Context,
+ "define void @f(i1* %ptr) {\n"
+ "entry:\n"
+ " br label %loop.0\n"
+ "loop.0:\n"
+ " %cond.0 = load volatile i1, i1* %ptr\n"
+ " br i1 %cond.0, label %loop.0.0.ph, label %end\n"
+ "loop.0.0.ph:\n"
+ " br label %loop.0.0\n"
+ "loop.0.0:\n"
+ " %cond.0.0 = load volatile i1, i1* %ptr\n"
+ " br i1 %cond.0.0, label %loop.0.0, label %loop.0.1.ph\n"
+ "loop.0.1.ph:\n"
+ " br label %loop.0.1\n"
+ "loop.0.1:\n"
+ " %cond.0.1 = load volatile i1, i1* %ptr\n"
+ " br i1 %cond.0.1, label %loop.0.1, label %loop.0.latch\n"
+ "loop.0.latch:\n"
+ " br label %loop.0\n"
+ "end:\n"
+ " ret void\n"
+ "}\n"
+ "\n"
+ "define void @g(i1* %ptr) {\n"
+ "entry:\n"
+ " br label %loop.g.0\n"
+ "loop.g.0:\n"
+ " %cond.0 = load volatile i1, i1* %ptr\n"
+ " br i1 %cond.0, label %loop.g.0, label %end\n"
+ "end:\n"
+ " ret void\n"
+ "}\n")),
LAM(true), FAM(true), MAM(true) {
// Register our mock analysis.
LAM.registerPass([&] { return MLAHandle.getAnalysis(); });
@@ -551,7 +568,6 @@ TEST_F(LoopPassManagerTest, InvalidationOfBundledAnalyses) {
EXPECT_CALL(MFPHandle, run(HasName("f"), _)).WillOnce(InvokeWithoutArgs([] {
auto PA = PreservedAnalyses::none();
// Not preserving `AAManager`.
- PA.preserve<AssumptionAnalysis>();
PA.preserve<DominatorTreeAnalysis>();
PA.preserve<LoopAnalysis>();
PA.preserve<LoopAnalysisManagerFunctionProxy>();
@@ -568,24 +584,6 @@ TEST_F(LoopPassManagerTest, InvalidationOfBundledAnalyses) {
EXPECT_CALL(MFPHandle, run(HasName("f"), _)).WillOnce(InvokeWithoutArgs([] {
auto PA = PreservedAnalyses::none();
PA.preserve<AAManager>();
- // Not preserving `AssumptionAnalysis`.
- PA.preserve<DominatorTreeAnalysis>();
- PA.preserve<LoopAnalysis>();
- PA.preserve<LoopAnalysisManagerFunctionProxy>();
- PA.preserve<ScalarEvolutionAnalysis>();
- return PA;
- }));
- EXPECT_CALL(MLAHandle, run(HasName("loop.0.0"), _, _));
- EXPECT_CALL(MLAHandle, run(HasName("loop.0.1"), _, _));
- EXPECT_CALL(MLAHandle, run(HasName("loop.0"), _, _));
- FPM.addPass(MFPHandle.getPass());
- FPM.addPass(createFunctionToLoopPassAdaptor(
- RequireAnalysisLoopPass<MockLoopAnalysisHandle::Analysis>()));
-
- EXPECT_CALL(MFPHandle, run(HasName("f"), _)).WillOnce(InvokeWithoutArgs([] {
- auto PA = PreservedAnalyses::none();
- PA.preserve<AAManager>();
- PA.preserve<AssumptionAnalysis>();
// Not preserving `DominatorTreeAnalysis`.
PA.preserve<LoopAnalysis>();
PA.preserve<LoopAnalysisManagerFunctionProxy>();
@@ -602,7 +600,6 @@ TEST_F(LoopPassManagerTest, InvalidationOfBundledAnalyses) {
EXPECT_CALL(MFPHandle, run(HasName("f"), _)).WillOnce(InvokeWithoutArgs([] {
auto PA = PreservedAnalyses::none();
PA.preserve<AAManager>();
- PA.preserve<AssumptionAnalysis>();
PA.preserve<DominatorTreeAnalysis>();
// Not preserving the `LoopAnalysis`.
PA.preserve<LoopAnalysisManagerFunctionProxy>();
@@ -619,7 +616,6 @@ TEST_F(LoopPassManagerTest, InvalidationOfBundledAnalyses) {
EXPECT_CALL(MFPHandle, run(HasName("f"), _)).WillOnce(InvokeWithoutArgs([] {
auto PA = PreservedAnalyses::none();
PA.preserve<AAManager>();
- PA.preserve<AssumptionAnalysis>();
PA.preserve<DominatorTreeAnalysis>();
PA.preserve<LoopAnalysis>();
// Not preserving the `LoopAnalysisManagerFunctionProxy`.
@@ -636,7 +632,6 @@ TEST_F(LoopPassManagerTest, InvalidationOfBundledAnalyses) {
EXPECT_CALL(MFPHandle, run(HasName("f"), _)).WillOnce(InvokeWithoutArgs([] {
auto PA = PreservedAnalyses::none();
PA.preserve<AAManager>();
- PA.preserve<AssumptionAnalysis>();
PA.preserve<DominatorTreeAnalysis>();
PA.preserve<LoopAnalysis>();
PA.preserve<LoopAnalysisManagerFunctionProxy>();
@@ -654,7 +649,7 @@ TEST_F(LoopPassManagerTest, InvalidationOfBundledAnalyses) {
// 'g' once with a requires pass and then run our mock pass over g a bunch
// but just get cached results each time.
EXPECT_CALL(MLAHandle, run(HasName("loop.g.0"), _, _));
- EXPECT_CALL(MFPHandle, run(HasName("g"), _)).Times(7);
+ EXPECT_CALL(MFPHandle, run(HasName("g"), _)).Times(6);
MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
MPM.run(*M, MAM);
@@ -842,17 +837,29 @@ TEST_F(LoopPassManagerTest, IndirectOuterPassInvalidation) {
TEST_F(LoopPassManagerTest, LoopChildInsertion) {
// Super boring module with three loops in a single loop nest.
- M = parseIR(Context, "define void @f() {\n"
+ M = parseIR(Context, "define void @f(i1* %ptr) {\n"
"entry:\n"
" br label %loop.0\n"
"loop.0:\n"
- " br i1 undef, label %loop.0.0, label %end\n"
+ " %cond.0 = load volatile i1, i1* %ptr\n"
+ " br i1 %cond.0, label %loop.0.0.ph, label %end\n"
+ "loop.0.0.ph:\n"
+ " br label %loop.0.0\n"
"loop.0.0:\n"
- " br i1 undef, label %loop.0.0, label %loop.0.1\n"
+ " %cond.0.0 = load volatile i1, i1* %ptr\n"
+ " br i1 %cond.0.0, label %loop.0.0, label %loop.0.1.ph\n"
+ "loop.0.1.ph:\n"
+ " br label %loop.0.1\n"
"loop.0.1:\n"
- " br i1 undef, label %loop.0.1, label %loop.0.2\n"
+ " %cond.0.1 = load volatile i1, i1* %ptr\n"
+ " br i1 %cond.0.1, label %loop.0.1, label %loop.0.2.ph\n"
+ "loop.0.2.ph:\n"
+ " br label %loop.0.2\n"
"loop.0.2:\n"
- " br i1 undef, label %loop.0.2, label %loop.0\n"
+ " %cond.0.2 = load volatile i1, i1* %ptr\n"
+ " br i1 %cond.0.2, label %loop.0.2, label %loop.0.latch\n"
+ "loop.0.latch:\n"
+ " br label %loop.0\n"
"end:\n"
" ret void\n"
"}\n");
@@ -861,20 +868,34 @@ TEST_F(LoopPassManagerTest, LoopChildInsertion) {
// easily.
Function &F = *M->begin();
ASSERT_THAT(F, HasName("f"));
+ Argument &Ptr = *F.arg_begin();
auto BBI = F.begin();
BasicBlock &EntryBB = *BBI++;
ASSERT_THAT(EntryBB, HasName("entry"));
BasicBlock &Loop0BB = *BBI++;
ASSERT_THAT(Loop0BB, HasName("loop.0"));
+ BasicBlock &Loop00PHBB = *BBI++;
+ ASSERT_THAT(Loop00PHBB, HasName("loop.0.0.ph"));
BasicBlock &Loop00BB = *BBI++;
ASSERT_THAT(Loop00BB, HasName("loop.0.0"));
+ BasicBlock &Loop01PHBB = *BBI++;
+ ASSERT_THAT(Loop01PHBB, HasName("loop.0.1.ph"));
BasicBlock &Loop01BB = *BBI++;
ASSERT_THAT(Loop01BB, HasName("loop.0.1"));
+ BasicBlock &Loop02PHBB = *BBI++;
+ ASSERT_THAT(Loop02PHBB, HasName("loop.0.2.ph"));
BasicBlock &Loop02BB = *BBI++;
ASSERT_THAT(Loop02BB, HasName("loop.0.2"));
+ BasicBlock &Loop0LatchBB = *BBI++;
+ ASSERT_THAT(Loop0LatchBB, HasName("loop.0.latch"));
BasicBlock &EndBB = *BBI++;
ASSERT_THAT(EndBB, HasName("end"));
ASSERT_THAT(BBI, F.end());
+ auto CreateCondBr = [&](BasicBlock *TrueBB, BasicBlock *FalseBB,
+ const char *Name, BasicBlock *BB) {
+ auto *Cond = new LoadInst(&Ptr, Name, /*isVolatile*/ true, BB);
+ BranchInst::Create(TrueBB, FalseBB, Cond, BB);
+ };
// Build the pass managers and register our pipeline. We build a single loop
// pass pipeline consisting of three mock pass runs over each loop. After
@@ -909,20 +930,33 @@ TEST_F(LoopPassManagerTest, LoopChildInsertion) {
// When running over the middle loop, the second run inserts two new child
// loops, inserting them and itself into the worklist.
- BasicBlock *NewLoop010BB;
+ BasicBlock *NewLoop010BB, *NewLoop01LatchBB;
EXPECT_CALL(MLPHandle, run(HasName("loop.0.1"), _, _, _))
.WillOnce(Invoke([&](Loop &L, LoopAnalysisManager &AM,
LoopStandardAnalysisResults &AR,
LPMUpdater &Updater) {
auto *NewLoop = new Loop();
L.addChildLoop(NewLoop);
- NewLoop010BB = BasicBlock::Create(Context, "loop.0.1.0", &F, &Loop02BB);
- BranchInst::Create(&Loop01BB, NewLoop010BB,
- UndefValue::get(Type::getInt1Ty(Context)),
- NewLoop010BB);
- Loop01BB.getTerminator()->replaceUsesOfWith(&Loop01BB, NewLoop010BB);
- AR.DT.addNewBlock(NewLoop010BB, &Loop01BB);
+ auto *NewLoop010PHBB =
+ BasicBlock::Create(Context, "loop.0.1.0.ph", &F, &Loop02PHBB);
+ NewLoop010BB =
+ BasicBlock::Create(Context, "loop.0.1.0", &F, &Loop02PHBB);
+ NewLoop01LatchBB =
+ BasicBlock::Create(Context, "loop.0.1.latch", &F, &Loop02PHBB);
+ Loop01BB.getTerminator()->replaceUsesOfWith(&Loop01BB, NewLoop010PHBB);
+ BranchInst::Create(NewLoop010BB, NewLoop010PHBB);
+ CreateCondBr(NewLoop01LatchBB, NewLoop010BB, "cond.0.1.0",
+ NewLoop010BB);
+ BranchInst::Create(&Loop01BB, NewLoop01LatchBB);
+ AR.DT.addNewBlock(NewLoop010PHBB, &Loop01BB);
+ AR.DT.addNewBlock(NewLoop010BB, NewLoop010PHBB);
+ AR.DT.addNewBlock(NewLoop01LatchBB, NewLoop010BB);
+ AR.DT.verifyDomTree();
+ L.addBasicBlockToLoop(NewLoop010PHBB, AR.LI);
NewLoop->addBasicBlockToLoop(NewLoop010BB, AR.LI);
+ L.addBasicBlockToLoop(NewLoop01LatchBB, AR.LI);
+ NewLoop->verifyLoop();
+ L.verifyLoop();
Updater.addChildLoops({NewLoop});
return PreservedAnalyses::all();
}));
@@ -943,21 +977,27 @@ TEST_F(LoopPassManagerTest, LoopChildInsertion) {
// In the second run over the middle loop after we've visited the new child,
// we add another child to check that we can repeatedly add children, and add
// children to a loop that already has children.
- BasicBlock *NewLoop011BB;
EXPECT_CALL(MLPHandle, run(HasName("loop.0.1"), _, _, _))
.WillOnce(Invoke([&](Loop &L, LoopAnalysisManager &AM,
LoopStandardAnalysisResults &AR,
LPMUpdater &Updater) {
auto *NewLoop = new Loop();
L.addChildLoop(NewLoop);
- NewLoop011BB = BasicBlock::Create(Context, "loop.0.1.1", &F, &Loop02BB);
- BranchInst::Create(&Loop01BB, NewLoop011BB,
- UndefValue::get(Type::getInt1Ty(Context)),
- NewLoop011BB);
- NewLoop010BB->getTerminator()->replaceUsesOfWith(&Loop01BB,
- NewLoop011BB);
- AR.DT.addNewBlock(NewLoop011BB, NewLoop010BB);
+ auto *NewLoop011PHBB = BasicBlock::Create(Context, "loop.0.1.1.ph", &F, NewLoop01LatchBB);
+ auto *NewLoop011BB = BasicBlock::Create(Context, "loop.0.1.1", &F, NewLoop01LatchBB);
+ NewLoop010BB->getTerminator()->replaceUsesOfWith(NewLoop01LatchBB,
+ NewLoop011PHBB);
+ BranchInst::Create(NewLoop011BB, NewLoop011PHBB);
+ CreateCondBr(NewLoop01LatchBB, NewLoop011BB, "cond.0.1.1",
+ NewLoop011BB);
+ AR.DT.addNewBlock(NewLoop011PHBB, NewLoop010BB);
+ auto *NewDTNode = AR.DT.addNewBlock(NewLoop011BB, NewLoop011PHBB);
+ AR.DT.changeImmediateDominator(AR.DT[NewLoop01LatchBB], NewDTNode);
+ AR.DT.verifyDomTree();
+ L.addBasicBlockToLoop(NewLoop011PHBB, AR.LI);
NewLoop->addBasicBlockToLoop(NewLoop011BB, AR.LI);
+ NewLoop->verifyLoop();
+ L.verifyLoop();
Updater.addChildLoops({NewLoop});
return PreservedAnalyses::all();
}));
@@ -999,17 +1039,29 @@ TEST_F(LoopPassManagerTest, LoopChildInsertion) {
TEST_F(LoopPassManagerTest, LoopPeerInsertion) {
// Super boring module with two loop nests and loop nest with two child
// loops.
- M = parseIR(Context, "define void @f() {\n"
+ M = parseIR(Context, "define void @f(i1* %ptr) {\n"
"entry:\n"
" br label %loop.0\n"
"loop.0:\n"
- " br i1 undef, label %loop.0.0, label %loop.2\n"
+ " %cond.0 = load volatile i1, i1* %ptr\n"
+ " br i1 %cond.0, label %loop.0.0.ph, label %loop.2.ph\n"
+ "loop.0.0.ph:\n"
+ " br label %loop.0.0\n"
"loop.0.0:\n"
- " br i1 undef, label %loop.0.0, label %loop.0.2\n"
+ " %cond.0.0 = load volatile i1, i1* %ptr\n"
+ " br i1 %cond.0.0, label %loop.0.0, label %loop.0.2.ph\n"
+ "loop.0.2.ph:\n"
+ " br label %loop.0.2\n"
"loop.0.2:\n"
- " br i1 undef, label %loop.0.2, label %loop.0\n"
+ " %cond.0.2 = load volatile i1, i1* %ptr\n"
+ " br i1 %cond.0.2, label %loop.0.2, label %loop.0.latch\n"
+ "loop.0.latch:\n"
+ " br label %loop.0\n"
+ "loop.2.ph:\n"
+ " br label %loop.2\n"
"loop.2:\n"
- " br i1 undef, label %loop.2, label %end\n"
+ " %cond.2 = load volatile i1, i1* %ptr\n"
+ " br i1 %cond.2, label %loop.2, label %end\n"
"end:\n"
" ret void\n"
"}\n");
@@ -1018,21 +1070,34 @@ TEST_F(LoopPassManagerTest, LoopPeerInsertion) {
// easily.
Function &F = *M->begin();
ASSERT_THAT(F, HasName("f"));
+ Argument &Ptr = *F.arg_begin();
auto BBI = F.begin();
BasicBlock &EntryBB = *BBI++;
ASSERT_THAT(EntryBB, HasName("entry"));
BasicBlock &Loop0BB = *BBI++;
ASSERT_THAT(Loop0BB, HasName("loop.0"));
+ BasicBlock &Loop00PHBB = *BBI++;
+ ASSERT_THAT(Loop00PHBB, HasName("loop.0.0.ph"));
BasicBlock &Loop00BB = *BBI++;
ASSERT_THAT(Loop00BB, HasName("loop.0.0"));
+ BasicBlock &Loop02PHBB = *BBI++;
+ ASSERT_THAT(Loop02PHBB, HasName("loop.0.2.ph"));
BasicBlock &Loop02BB = *BBI++;
ASSERT_THAT(Loop02BB, HasName("loop.0.2"));
+ BasicBlock &Loop0LatchBB = *BBI++;
+ ASSERT_THAT(Loop0LatchBB, HasName("loop.0.latch"));
+ BasicBlock &Loop2PHBB = *BBI++;
+ ASSERT_THAT(Loop2PHBB, HasName("loop.2.ph"));
BasicBlock &Loop2BB = *BBI++;
ASSERT_THAT(Loop2BB, HasName("loop.2"));
BasicBlock &EndBB = *BBI++;
ASSERT_THAT(EndBB, HasName("end"));
ASSERT_THAT(BBI, F.end());
- Constant *Undefi1 = UndefValue::get(Type::getInt1Ty(Context));
+ auto CreateCondBr = [&](BasicBlock *TrueBB, BasicBlock *FalseBB,
+ const char *Name, BasicBlock *BB) {
+ auto *Cond = new LoadInst(&Ptr, Name, /*isVolatile*/ true, BB);
+ BranchInst::Create(TrueBB, FalseBB, Cond, BB);
+ };
// Build the pass managers and register our pipeline. We build a single loop
// pass pipeline consisting of three mock pass runs over each loop. After
@@ -1059,19 +1124,24 @@ TEST_F(LoopPassManagerTest, LoopPeerInsertion) {
EXPECT_CALL(MLAHandle, run(HasName("loop.0.0"), _, _));
// On the second run, we insert a sibling loop.
- BasicBlock *NewLoop01BB;
EXPECT_CALL(MLPHandle, run(HasName("loop.0.0"), _, _, _))
.WillOnce(Invoke([&](Loop &L, LoopAnalysisManager &AM,
LoopStandardAnalysisResults &AR,
LPMUpdater &Updater) {
auto *NewLoop = new Loop();
L.getParentLoop()->addChildLoop(NewLoop);
- NewLoop01BB = BasicBlock::Create(Context, "loop.0.1", &F, &Loop02BB);
- BranchInst::Create(&Loop02BB, NewLoop01BB, Undefi1, NewLoop01BB);
- Loop00BB.getTerminator()->replaceUsesOfWith(&Loop02BB, NewLoop01BB);
- auto *NewDTNode = AR.DT.addNewBlock(NewLoop01BB, &Loop00BB);
- AR.DT.changeImmediateDominator(AR.DT[&Loop02BB], NewDTNode);
+ auto *NewLoop01PHBB = BasicBlock::Create(Context, "loop.0.1.ph", &F, &Loop02PHBB);
+ auto *NewLoop01BB = BasicBlock::Create(Context, "loop.0.1", &F, &Loop02PHBB);
+ BranchInst::Create(NewLoop01BB, NewLoop01PHBB);
+ CreateCondBr(&Loop02PHBB, NewLoop01BB, "cond.0.1", NewLoop01BB);
+ Loop00BB.getTerminator()->replaceUsesOfWith(&Loop02PHBB, NewLoop01PHBB);
+ AR.DT.addNewBlock(NewLoop01PHBB, &Loop00BB);
+ auto *NewDTNode = AR.DT.addNewBlock(NewLoop01BB, NewLoop01PHBB);
+ AR.DT.changeImmediateDominator(AR.DT[&Loop02PHBB], NewDTNode);
+ AR.DT.verifyDomTree();
+ L.getParentLoop()->addBasicBlockToLoop(NewLoop01PHBB, AR.LI);
NewLoop->addBasicBlockToLoop(NewLoop01BB, AR.LI);
+ L.getParentLoop()->verifyLoop();
Updater.addSiblingLoops({NewLoop});
return PreservedAnalyses::all();
}));
@@ -1104,22 +1174,45 @@ TEST_F(LoopPassManagerTest, LoopPeerInsertion) {
L.getParentLoop()->addChildLoop(NewLoops[0]);
L.getParentLoop()->addChildLoop(NewLoops[1]);
NewLoops[1]->addChildLoop(NewLoops[2]);
+ auto *NewLoop03PHBB =
+ BasicBlock::Create(Context, "loop.0.3.ph", &F, &Loop0LatchBB);
auto *NewLoop03BB =
- BasicBlock::Create(Context, "loop.0.3", &F, &Loop2BB);
+ BasicBlock::Create(Context, "loop.0.3", &F, &Loop0LatchBB);
+ auto *NewLoop04PHBB =
+ BasicBlock::Create(Context, "loop.0.4.ph", &F, &Loop0LatchBB);
auto *NewLoop04BB =
- BasicBlock::Create(Context, "loop.0.4", &F, &Loop2BB);
+ BasicBlock::Create(Context, "loop.0.4", &F, &Loop0LatchBB);
+ auto *NewLoop040PHBB =
+ BasicBlock::Create(Context, "loop.0.4.0.ph", &F, &Loop0LatchBB);
auto *NewLoop040BB =
- BasicBlock::Create(Context, "loop.0.4.0", &F, &Loop2BB);
- Loop02BB.getTerminator()->replaceUsesOfWith(&Loop0BB, NewLoop03BB);
- BranchInst::Create(NewLoop04BB, NewLoop03BB, Undefi1, NewLoop03BB);
- BranchInst::Create(&Loop0BB, NewLoop040BB, Undefi1, NewLoop04BB);
- BranchInst::Create(NewLoop04BB, NewLoop040BB, Undefi1, NewLoop040BB);
- AR.DT.addNewBlock(NewLoop03BB, &Loop02BB);
- AR.DT.addNewBlock(NewLoop04BB, NewLoop03BB);
- AR.DT.addNewBlock(NewLoop040BB, NewLoop04BB);
+ BasicBlock::Create(Context, "loop.0.4.0", &F, &Loop0LatchBB);
+ auto *NewLoop04LatchBB =
+ BasicBlock::Create(Context, "loop.0.4.latch", &F, &Loop0LatchBB);
+ Loop02BB.getTerminator()->replaceUsesOfWith(&Loop0LatchBB, NewLoop03PHBB);
+ BranchInst::Create(NewLoop03BB, NewLoop03PHBB);
+ CreateCondBr(NewLoop04PHBB, NewLoop03BB, "cond.0.3", NewLoop03BB);
+ BranchInst::Create(NewLoop04BB, NewLoop04PHBB);
+ CreateCondBr(&Loop0LatchBB, NewLoop040PHBB, "cond.0.4", NewLoop04BB);
+ BranchInst::Create(NewLoop040BB, NewLoop040PHBB);
+ CreateCondBr(NewLoop04LatchBB, NewLoop040BB, "cond.0.4.0", NewLoop040BB);
+ BranchInst::Create(NewLoop04BB, NewLoop04LatchBB);
+ AR.DT.addNewBlock(NewLoop03PHBB, &Loop02BB);
+ AR.DT.addNewBlock(NewLoop03BB, NewLoop03PHBB);
+ AR.DT.addNewBlock(NewLoop04PHBB, NewLoop03BB);
+ auto *NewDTNode = AR.DT.addNewBlock(NewLoop04BB, NewLoop04PHBB);
+ AR.DT.changeImmediateDominator(AR.DT[&Loop0LatchBB], NewDTNode);
+ AR.DT.addNewBlock(NewLoop040PHBB, NewLoop04BB);
+ AR.DT.addNewBlock(NewLoop040BB, NewLoop040PHBB);
+ AR.DT.addNewBlock(NewLoop04LatchBB, NewLoop040BB);
+ AR.DT.verifyDomTree();
+ L.getParentLoop()->addBasicBlockToLoop(NewLoop03PHBB, AR.LI);
NewLoops[0]->addBasicBlockToLoop(NewLoop03BB, AR.LI);
+ L.getParentLoop()->addBasicBlockToLoop(NewLoop04PHBB, AR.LI);
NewLoops[1]->addBasicBlockToLoop(NewLoop04BB, AR.LI);
+ NewLoops[1]->addBasicBlockToLoop(NewLoop040PHBB, AR.LI);
NewLoops[2]->addBasicBlockToLoop(NewLoop040BB, AR.LI);
+ NewLoops[1]->addBasicBlockToLoop(NewLoop04LatchBB, AR.LI);
+ L.getParentLoop()->verifyLoop();
Updater.addSiblingLoops({NewLoops[0], NewLoops[1]});
return PreservedAnalyses::all();
}));
@@ -1158,12 +1251,17 @@ TEST_F(LoopPassManagerTest, LoopPeerInsertion) {
LPMUpdater &Updater) {
auto *NewLoop = new Loop();
AR.LI.addTopLevelLoop(NewLoop);
+ auto *NewLoop1PHBB = BasicBlock::Create(Context, "loop.1.ph", &F, &Loop2BB);
auto *NewLoop1BB = BasicBlock::Create(Context, "loop.1", &F, &Loop2BB);
- BranchInst::Create(&Loop2BB, NewLoop1BB, Undefi1, NewLoop1BB);
- Loop0BB.getTerminator()->replaceUsesOfWith(&Loop2BB, NewLoop1BB);
- auto *NewDTNode = AR.DT.addNewBlock(NewLoop1BB, &Loop0BB);
- AR.DT.changeImmediateDominator(AR.DT[&Loop2BB], NewDTNode);
+ BranchInst::Create(NewLoop1BB, NewLoop1PHBB);
+ CreateCondBr(&Loop2PHBB, NewLoop1BB, "cond.1", NewLoop1BB);
+ Loop0BB.getTerminator()->replaceUsesOfWith(&Loop2PHBB, NewLoop1PHBB);
+ AR.DT.addNewBlock(NewLoop1PHBB, &Loop0BB);
+ auto *NewDTNode = AR.DT.addNewBlock(NewLoop1BB, NewLoop1PHBB);
+ AR.DT.changeImmediateDominator(AR.DT[&Loop2PHBB], NewDTNode);
+ AR.DT.verifyDomTree();
NewLoop->addBasicBlockToLoop(NewLoop1BB, AR.LI);
+ NewLoop->verifyLoop();
Updater.addSiblingLoops({NewLoop});
return PreservedAnalyses::all();
}));
@@ -1193,19 +1291,36 @@ TEST_F(LoopPassManagerTest, LoopDeletion) {
// Build a module with a single loop nest that contains one outer loop with
// three subloops, and one of those with its own subloop. We will
// incrementally delete all of these to test different deletion scenarios.
- M = parseIR(Context, "define void @f() {\n"
+ M = parseIR(Context, "define void @f(i1* %ptr) {\n"
"entry:\n"
" br label %loop.0\n"
"loop.0:\n"
- " br i1 undef, label %loop.0.0, label %end\n"
+ " %cond.0 = load volatile i1, i1* %ptr\n"
+ " br i1 %cond.0, label %loop.0.0.ph, label %end\n"
+ "loop.0.0.ph:\n"
+ " br label %loop.0.0\n"
"loop.0.0:\n"
- " br i1 undef, label %loop.0.0, label %loop.0.1\n"
+ " %cond.0.0 = load volatile i1, i1* %ptr\n"
+ " br i1 %cond.0.0, label %loop.0.0, label %loop.0.1.ph\n"
+ "loop.0.1.ph:\n"
+ " br label %loop.0.1\n"
"loop.0.1:\n"
- " br i1 undef, label %loop.0.1, label %loop.0.2\n"
+ " %cond.0.1 = load volatile i1, i1* %ptr\n"
+ " br i1 %cond.0.1, label %loop.0.1, label %loop.0.2.ph\n"
+ "loop.0.2.ph:\n"
+ " br label %loop.0.2\n"
"loop.0.2:\n"
- " br i1 undef, label %loop.0.2.0, label %loop.0\n"
+ " %cond.0.2 = load volatile i1, i1* %ptr\n"
+ " br i1 %cond.0.2, label %loop.0.2.0.ph, label %loop.0.latch\n"
+ "loop.0.2.0.ph:\n"
+ " br label %loop.0.2.0\n"
"loop.0.2.0:\n"
- " br i1 undef, label %loop.0.2.0, label %loop.0.2\n"
+ " %cond.0.2.0 = load volatile i1, i1* %ptr\n"
+ " br i1 %cond.0.2.0, label %loop.0.2.0, label %loop.0.2.latch\n"
+ "loop.0.2.latch:\n"
+ " br label %loop.0.2\n"
+ "loop.0.latch:\n"
+ " br label %loop.0\n"
"end:\n"
" ret void\n"
"}\n");
@@ -1214,44 +1329,64 @@ TEST_F(LoopPassManagerTest, LoopDeletion) {
// easily.
Function &F = *M->begin();
ASSERT_THAT(F, HasName("f"));
+ Argument &Ptr = *F.arg_begin();
auto BBI = F.begin();
BasicBlock &EntryBB = *BBI++;
ASSERT_THAT(EntryBB, HasName("entry"));
BasicBlock &Loop0BB = *BBI++;
ASSERT_THAT(Loop0BB, HasName("loop.0"));
+ BasicBlock &Loop00PHBB = *BBI++;
+ ASSERT_THAT(Loop00PHBB, HasName("loop.0.0.ph"));
BasicBlock &Loop00BB = *BBI++;
ASSERT_THAT(Loop00BB, HasName("loop.0.0"));
+ BasicBlock &Loop01PHBB = *BBI++;
+ ASSERT_THAT(Loop01PHBB, HasName("loop.0.1.ph"));
BasicBlock &Loop01BB = *BBI++;
ASSERT_THAT(Loop01BB, HasName("loop.0.1"));
+ BasicBlock &Loop02PHBB = *BBI++;
+ ASSERT_THAT(Loop02PHBB, HasName("loop.0.2.ph"));
BasicBlock &Loop02BB = *BBI++;
ASSERT_THAT(Loop02BB, HasName("loop.0.2"));
+ BasicBlock &Loop020PHBB = *BBI++;
+ ASSERT_THAT(Loop020PHBB, HasName("loop.0.2.0.ph"));
BasicBlock &Loop020BB = *BBI++;
ASSERT_THAT(Loop020BB, HasName("loop.0.2.0"));
+ BasicBlock &Loop02LatchBB = *BBI++;
+ ASSERT_THAT(Loop02LatchBB, HasName("loop.0.2.latch"));
+ BasicBlock &Loop0LatchBB = *BBI++;
+ ASSERT_THAT(Loop0LatchBB, HasName("loop.0.latch"));
BasicBlock &EndBB = *BBI++;
ASSERT_THAT(EndBB, HasName("end"));
ASSERT_THAT(BBI, F.end());
- Constant *Undefi1 = UndefValue::get(Type::getInt1Ty(Context));
// Helper to do the actual deletion of a loop. We directly encode this here
// to isolate ourselves from the rest of LLVM and for simplicity. Here we can
// egregiously cheat based on knowledge of the test case. For example, we
// have no PHI nodes and there is always a single i-dom.
- auto DeleteLoopBlocks = [](Loop &L, BasicBlock &IDomBB,
+ auto RemoveLoop = [](Loop &L, BasicBlock &IDomBB,
LoopStandardAnalysisResults &AR,
LPMUpdater &Updater) {
- for (BasicBlock *LoopBB : L.blocks()) {
+ assert(L.empty() && "Can only delete leaf loops with this routine!");
+ SmallVector<BasicBlock *, 4> LoopBBs(L.block_begin(), L.block_end());
+ Updater.markLoopAsDeleted(L);
+ IDomBB.getTerminator()->replaceUsesOfWith(L.getHeader(),
+ L.getUniqueExitBlock());
+ for (BasicBlock *LoopBB : LoopBBs) {
SmallVector<DomTreeNode *, 4> ChildNodes(AR.DT[LoopBB]->begin(),
AR.DT[LoopBB]->end());
for (DomTreeNode *ChildNode : ChildNodes)
AR.DT.changeImmediateDominator(ChildNode, AR.DT[&IDomBB]);
AR.DT.eraseNode(LoopBB);
+ AR.LI.removeBlock(LoopBB);
LoopBB->dropAllReferences();
}
- SmallVector<BasicBlock *, 4> LoopBBs(L.block_begin(), L.block_end());
- Updater.markLoopAsDeleted(L);
- AR.LI.markAsRemoved(&L);
for (BasicBlock *LoopBB : LoopBBs)
LoopBB->eraseFromParent();
+
+ if (Loop *ParentL = L.getParentLoop())
+ return ParentL->removeChildLoop(find(*ParentL, &L));
+
+ return AR.LI.removeLoop(find(AR.LI, &L));
};
// Build up the pass managers.
@@ -1294,9 +1429,10 @@ TEST_F(LoopPassManagerTest, LoopDeletion) {
.WillOnce(
Invoke([&](Loop &L, LoopAnalysisManager &AM,
LoopStandardAnalysisResults &AR, LPMUpdater &Updater) {
+ Loop *ParentL = L.getParentLoop();
AR.SE.forgetLoop(&L);
- Loop00BB.getTerminator()->replaceUsesOfWith(&Loop01BB, &Loop02BB);
- DeleteLoopBlocks(L, Loop00BB, AR, Updater);
+ delete RemoveLoop(L, Loop01PHBB, AR, Updater);
+ ParentL->verifyLoop();
return PreservedAnalyses::all();
}));
@@ -1337,38 +1473,40 @@ TEST_F(LoopPassManagerTest, LoopDeletion) {
EXPECT_CALL(MLPHandle, run(HasName("loop.0.2"), _, _, _))
.WillOnce(Invoke(getLoopAnalysisResult));
- BasicBlock *NewLoop03BB;
+ BasicBlock *NewLoop03PHBB;
EXPECT_CALL(MLPHandle, run(HasName("loop.0.2"), _, _, _))
.WillOnce(
Invoke([&](Loop &L, LoopAnalysisManager &AM,
LoopStandardAnalysisResults &AR, LPMUpdater &Updater) {
- // Delete the inner loop first. we also do this manually because we
- // want to preserve the loop object and reuse it.
+ // Remove the inner loop first but retain it to reuse later.
AR.SE.forgetLoop(*L.begin());
- Loop02BB.getTerminator()->replaceUsesOfWith(&Loop020BB, &Loop02BB);
- assert(std::next((*L.begin())->block_begin()) ==
- (*L.begin())->block_end() &&
- "There should only be one block.");
- assert(AR.DT[&Loop020BB]->getNumChildren() == 0 &&
- "Cannot have children in the domtree!");
- AR.DT.eraseNode(&Loop020BB);
- Updater.markLoopAsDeleted(**L.begin());
- AR.LI.removeBlock(&Loop020BB);
- auto *OldL = L.removeChildLoop(L.begin());
- Loop020BB.eraseFromParent();
+ auto *OldL = RemoveLoop(**L.begin(), Loop020PHBB, AR, Updater);
auto *ParentL = L.getParentLoop();
AR.SE.forgetLoop(&L);
- Loop00BB.getTerminator()->replaceUsesOfWith(&Loop02BB, &Loop0BB);
- DeleteLoopBlocks(L, Loop00BB, AR, Updater);
+ delete RemoveLoop(L, Loop02PHBB, AR, Updater);
// Now insert a new sibling loop, reusing a loop pointer.
ParentL->addChildLoop(OldL);
- NewLoop03BB = BasicBlock::Create(Context, "loop.0.3", &F, &EndBB);
- BranchInst::Create(&Loop0BB, NewLoop03BB, Undefi1, NewLoop03BB);
- Loop00BB.getTerminator()->replaceUsesOfWith(&Loop0BB, NewLoop03BB);
- AR.DT.addNewBlock(NewLoop03BB, &Loop00BB);
+ NewLoop03PHBB =
+ BasicBlock::Create(Context, "loop.0.3.ph", &F, &Loop0LatchBB);
+ auto *NewLoop03BB =
+ BasicBlock::Create(Context, "loop.0.3", &F, &Loop0LatchBB);
+ BranchInst::Create(NewLoop03BB, NewLoop03PHBB);
+ auto *Cond = new LoadInst(&Ptr, "cond.0.3", /*isVolatile*/ true,
+ NewLoop03BB);
+ BranchInst::Create(&Loop0LatchBB, NewLoop03BB, Cond, NewLoop03BB);
+ Loop02PHBB.getTerminator()->replaceUsesOfWith(&Loop0LatchBB,
+ NewLoop03PHBB);
+ AR.DT.addNewBlock(NewLoop03PHBB, &Loop02PHBB);
+ AR.DT.addNewBlock(NewLoop03BB, NewLoop03PHBB);
+ AR.DT.changeImmediateDominator(AR.DT[&Loop0LatchBB],
+ AR.DT[NewLoop03BB]);
+ AR.DT.verifyDomTree();
+ ParentL->addBasicBlockToLoop(NewLoop03PHBB, AR.LI);
OldL->addBasicBlockToLoop(NewLoop03BB, AR.LI);
+ OldL->verifyLoop();
+ ParentL->verifyLoop();
Updater.addSiblingLoops({OldL});
return PreservedAnalyses::all();
}));
@@ -1401,8 +1539,7 @@ TEST_F(LoopPassManagerTest, LoopDeletion) {
Invoke([&](Loop &L, LoopAnalysisManager &AM,
LoopStandardAnalysisResults &AR, LPMUpdater &Updater) {
AR.SE.forgetLoop(&L);
- Loop0BB.getTerminator()->replaceUsesOfWith(&Loop00BB, NewLoop03BB);
- DeleteLoopBlocks(L, Loop0BB, AR, Updater);
+ delete RemoveLoop(L, Loop00PHBB, AR, Updater);
return PreservedAnalyses::all();
}));
@@ -1413,8 +1550,7 @@ TEST_F(LoopPassManagerTest, LoopDeletion) {
Invoke([&](Loop &L, LoopAnalysisManager &AM,
LoopStandardAnalysisResults &AR, LPMUpdater &Updater) {
AR.SE.forgetLoop(&L);
- Loop0BB.getTerminator()->replaceUsesOfWith(NewLoop03BB, &Loop0BB);
- DeleteLoopBlocks(L, Loop0BB, AR, Updater);
+ delete RemoveLoop(L, *NewLoop03PHBB, AR, Updater);
return PreservedAnalyses::all();
}));
@@ -1425,8 +1561,7 @@ TEST_F(LoopPassManagerTest, LoopDeletion) {
Invoke([&](Loop &L, LoopAnalysisManager &AM,
LoopStandardAnalysisResults &AR, LPMUpdater &Updater) {
AR.SE.forgetLoop(&L);
- EntryBB.getTerminator()->replaceUsesOfWith(&Loop0BB, &EndBB);
- DeleteLoopBlocks(L, EntryBB, AR, Updater);
+ delete RemoveLoop(L, EntryBB, AR, Updater);
return PreservedAnalyses::all();
}));
diff --git a/unittests/Transforms/Utils/CMakeLists.txt b/unittests/Transforms/Utils/CMakeLists.txt
index c0f37418e4928..0fc19ef09fb01 100644
--- a/unittests/Transforms/Utils/CMakeLists.txt
+++ b/unittests/Transforms/Utils/CMakeLists.txt
@@ -11,6 +11,5 @@ add_llvm_unittest(UtilsTests
FunctionComparator.cpp
IntegerDivision.cpp
Local.cpp
- MemorySSA.cpp
ValueMapperTest.cpp
)
diff --git a/unittests/Transforms/Utils/Cloning.cpp b/unittests/Transforms/Utils/Cloning.cpp
index 216bd32c50d2a..403c9c06c18a2 100644
--- a/unittests/Transforms/Utils/Cloning.cpp
+++ b/unittests/Transforms/Utils/Cloning.cpp
@@ -163,7 +163,7 @@ TEST_F(CloneInstruction, Attributes) {
Function *F2 = Function::Create(FT1, Function::ExternalLinkage);
Attribute::AttrKind AK[] = { Attribute::NoCapture };
- AttributeSet AS = AttributeSet::get(context, 0, AK);
+ AttributeList AS = AttributeList::get(context, 0, AK);
Argument *A = &*F1->arg_begin();
A->addAttr(AS);
@@ -201,6 +201,53 @@ TEST_F(CloneInstruction, CallingConvention) {
delete F2;
}
+TEST_F(CloneInstruction, DuplicateInstructionsToSplit) {
+ Type *ArgTy1[] = {Type::getInt32PtrTy(context)};
+ FunctionType *FT = FunctionType::get(Type::getVoidTy(context), ArgTy1, false);
+ V = new Argument(Type::getInt32Ty(context));
+
+ Function *F = Function::Create(FT, Function::ExternalLinkage);
+
+ BasicBlock *BB1 = BasicBlock::Create(context, "", F);
+ IRBuilder<> Builder1(BB1);
+
+ BasicBlock *BB2 = BasicBlock::Create(context, "", F);
+ IRBuilder<> Builder2(BB2);
+
+ Builder1.CreateBr(BB2);
+
+ Instruction *AddInst = cast<Instruction>(Builder2.CreateAdd(V, V));
+ Instruction *MulInst = cast<Instruction>(Builder2.CreateMul(AddInst, V));
+ Instruction *SubInst = cast<Instruction>(Builder2.CreateSub(MulInst, V));
+ Builder2.CreateRetVoid();
+
+ ValueToValueMapTy Mapping;
+
+ auto Split = DuplicateInstructionsInSplitBetween(BB2, BB1, SubInst, Mapping);
+
+ EXPECT_TRUE(Split);
+ EXPECT_EQ(Mapping.size(), 2u);
+ EXPECT_TRUE(Mapping.find(AddInst) != Mapping.end());
+ EXPECT_TRUE(Mapping.find(MulInst) != Mapping.end());
+
+ auto AddSplit = dyn_cast<Instruction>(Mapping[AddInst]);
+ EXPECT_TRUE(AddSplit);
+ EXPECT_EQ(AddSplit->getOperand(0), V);
+ EXPECT_EQ(AddSplit->getOperand(1), V);
+ EXPECT_EQ(AddSplit->getParent(), Split);
+
+ auto MulSplit = dyn_cast<Instruction>(Mapping[MulInst]);
+ EXPECT_TRUE(MulSplit);
+ EXPECT_EQ(MulSplit->getOperand(0), AddSplit);
+ EXPECT_EQ(MulSplit->getOperand(1), V);
+ EXPECT_EQ(MulSplit->getParent(), Split);
+
+ EXPECT_EQ(AddSplit->getNextNode(), MulSplit);
+ EXPECT_EQ(MulSplit->getNextNode(), Split->getTerminator());
+
+ delete F;
+}
+
class CloneFunc : public ::testing::Test {
protected:
void SetUp() override {
@@ -405,10 +452,14 @@ protected:
void SetupModule() { OldM = new Module("", C); }
void CreateOldModule() {
+ auto *CD = OldM->getOrInsertComdat("comdat");
+ CD->setSelectionKind(Comdat::ExactMatch);
+
auto GV = new GlobalVariable(
*OldM, Type::getInt32Ty(C), false, GlobalValue::ExternalLinkage,
ConstantInt::get(Type::getInt32Ty(C), 1), "gv");
GV->addMetadata(LLVMContext::MD_type, *MDNode::get(C, {}));
+ GV->setComdat(CD);
DIBuilder DBuilder(*OldM);
IRBuilder<> IBuilder(C);
@@ -419,6 +470,7 @@ protected:
auto *F =
Function::Create(FuncType, GlobalValue::PrivateLinkage, "f", OldM);
F->setPersonalityFn(PersFn);
+ F->setComdat(CD);
// Create debug info
auto *File = DBuilder.createFile("filename.c", "/file/dir/");
@@ -472,4 +524,15 @@ TEST_F(CloneModule, GlobalMetadata) {
GlobalVariable *NewGV = NewM->getGlobalVariable("gv");
EXPECT_NE(nullptr, NewGV->getMetadata(LLVMContext::MD_type));
}
+
+TEST_F(CloneModule, Comdat) {
+ GlobalVariable *NewGV = NewM->getGlobalVariable("gv");
+ auto *CD = NewGV->getComdat();
+ ASSERT_NE(nullptr, CD);
+ EXPECT_EQ("comdat", CD->getName());
+ EXPECT_EQ(Comdat::ExactMatch, CD->getSelectionKind());
+
+ Function *NewF = NewM->getFunction("f");
+ EXPECT_EQ(CD, NewF->getComdat());
+}
}
diff --git a/unittests/Transforms/Utils/IntegerDivision.cpp b/unittests/Transforms/Utils/IntegerDivision.cpp
index b6b1b1665ab1f..e337b9f547a89 100644
--- a/unittests/Transforms/Utils/IntegerDivision.cpp
+++ b/unittests/Transforms/Utils/IntegerDivision.cpp
@@ -29,7 +29,7 @@ TEST(IntegerDivision, SDiv) {
Function *F = Function::Create(FunctionType::get(Builder.getInt32Ty(),
ArgTys, false),
GlobalValue::ExternalLinkage, "F", &M);
- assert(F->getArgumentList().size() == 2);
+ assert(F->arg_size() == 2);
BasicBlock *BB = BasicBlock::Create(C, "", F);
Builder.SetInsertPoint(BB);
@@ -59,7 +59,7 @@ TEST(IntegerDivision, UDiv) {
Function *F = Function::Create(FunctionType::get(Builder.getInt32Ty(),
ArgTys, false),
GlobalValue::ExternalLinkage, "F", &M);
- assert(F->getArgumentList().size() == 2);
+ assert(F->arg_size() == 2);
BasicBlock *BB = BasicBlock::Create(C, "", F);
Builder.SetInsertPoint(BB);
@@ -89,7 +89,7 @@ TEST(IntegerDivision, SRem) {
Function *F = Function::Create(FunctionType::get(Builder.getInt32Ty(),
ArgTys, false),
GlobalValue::ExternalLinkage, "F", &M);
- assert(F->getArgumentList().size() == 2);
+ assert(F->arg_size() == 2);
BasicBlock *BB = BasicBlock::Create(C, "", F);
Builder.SetInsertPoint(BB);
@@ -119,7 +119,7 @@ TEST(IntegerDivision, URem) {
Function *F = Function::Create(FunctionType::get(Builder.getInt32Ty(),
ArgTys, false),
GlobalValue::ExternalLinkage, "F", &M);
- assert(F->getArgumentList().size() == 2);
+ assert(F->arg_size() == 2);
BasicBlock *BB = BasicBlock::Create(C, "", F);
Builder.SetInsertPoint(BB);
@@ -150,7 +150,7 @@ TEST(IntegerDivision, SDiv64) {
Function *F = Function::Create(FunctionType::get(Builder.getInt64Ty(),
ArgTys, false),
GlobalValue::ExternalLinkage, "F", &M);
- assert(F->getArgumentList().size() == 2);
+ assert(F->arg_size() == 2);
BasicBlock *BB = BasicBlock::Create(C, "", F);
Builder.SetInsertPoint(BB);
@@ -180,7 +180,7 @@ TEST(IntegerDivision, UDiv64) {
Function *F = Function::Create(FunctionType::get(Builder.getInt64Ty(),
ArgTys, false),
GlobalValue::ExternalLinkage, "F", &M);
- assert(F->getArgumentList().size() == 2);
+ assert(F->arg_size() == 2);
BasicBlock *BB = BasicBlock::Create(C, "", F);
Builder.SetInsertPoint(BB);
@@ -210,7 +210,7 @@ TEST(IntegerDivision, SRem64) {
Function *F = Function::Create(FunctionType::get(Builder.getInt64Ty(),
ArgTys, false),
GlobalValue::ExternalLinkage, "F", &M);
- assert(F->getArgumentList().size() == 2);
+ assert(F->arg_size() == 2);
BasicBlock *BB = BasicBlock::Create(C, "", F);
Builder.SetInsertPoint(BB);
@@ -240,7 +240,7 @@ TEST(IntegerDivision, URem64) {
Function *F = Function::Create(FunctionType::get(Builder.getInt64Ty(),
ArgTys, false),
GlobalValue::ExternalLinkage, "F", &M);
- assert(F->getArgumentList().size() == 2);
+ assert(F->arg_size() == 2);
BasicBlock *BB = BasicBlock::Create(C, "", F);
Builder.SetInsertPoint(BB);
diff --git a/unittests/XRay/CMakeLists.txt b/unittests/XRay/CMakeLists.txt
new file mode 100644
index 0000000000000..30bccd1bbe626
--- /dev/null
+++ b/unittests/XRay/CMakeLists.txt
@@ -0,0 +1,13 @@
+set(LLVM_LINK_COMPONENTS
+ Support
+ )
+
+set(XRAYSources
+ GraphTest.cpp
+ )
+
+add_llvm_unittest(XRayTests
+ ${XRAYSources}
+ )
+
+add_dependencies(XRayTests intrinsics_gen)
diff --git a/unittests/XRay/GraphTest.cpp b/unittests/XRay/GraphTest.cpp
new file mode 100644
index 0000000000000..b17858f0c1c0b
--- /dev/null
+++ b/unittests/XRay/GraphTest.cpp
@@ -0,0 +1,261 @@
+//===- llvm/unittest/XRay/GraphTest.cpp - XRay Graph unit tests -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/XRay/Graph.h"
+#include "gtest/gtest.h"
+#include <iostream>
+#include <set>
+#include <type_traits>
+
+using namespace llvm;
+using namespace xray;
+
+namespace {
+struct VAttr {
+ unsigned VA;
+};
+struct EAttr {
+ unsigned EA;
+};
+typedef Graph<VAttr, EAttr, unsigned> GraphT;
+typedef typename GraphT::VertexIdentifier VI;
+typedef typename GraphT::EdgeIdentifier EI;
+
+// Test Fixture
+template <typename T> class GraphTest : public testing::Test {
+protected:
+ T Graph = getTestGraph();
+
+private:
+ static T getTestGraph() {
+ using std::make_pair;
+ typename std::remove_const<T>::type G;
+ G.insert(make_pair(1u, VAttr({3u})));
+ G.insert(make_pair(2u, VAttr({5u})));
+ G.insert(make_pair(3u, VAttr({7u})));
+ G.insert(make_pair(4u, VAttr({11u})));
+ G.insert(make_pair(5u, VAttr({13u})));
+ G.insert(make_pair(6u, VAttr({17u})));
+
+ G.insert(std::make_pair(EI(1u, 2u), EAttr({3u * 5u})));
+ G.insert(std::make_pair(EI(2u, 3u), EAttr({5u * 7u})));
+ G.insert(std::make_pair(EI(6u, 3u), EAttr({2u * 7u * 17u})));
+ G.insert(std::make_pair(EI(4u, 6u), EAttr({11u * 17u})));
+ G.insert(std::make_pair(EI(2u, 4u), EAttr({5u * 11u})));
+ G.insert(std::make_pair(EI(2u, 5u), EAttr({5u * 13u})));
+ G.insert(std::make_pair(EI(4u, 5u), EAttr({11u * 13u})));
+
+ return G;
+ }
+};
+
+typedef ::testing::Types<GraphT, const GraphT> GraphTestTypes;
+
+using VVT = typename GraphT::VertexValueType;
+using EVT = typename GraphT::EdgeValueType;
+
+TYPED_TEST_CASE(GraphTest, GraphTestTypes);
+
+template <typename T> void graphVertexTester(T &G) {
+ std::set<unsigned> V({1u, 2u, 3u, 4u, 5u, 6u});
+ std::vector<unsigned> VA({0u, 3u, 5u, 7u, 11u, 13u, 17u});
+
+ EXPECT_EQ(V.size(), G.vertices().size());
+ EXPECT_FALSE(G.vertices().empty());
+ for (unsigned u : V) {
+ auto EVV = G.at(u);
+ ASSERT_TRUE(!!EVV);
+ EXPECT_EQ(1u, G.count(u));
+ EXPECT_EQ(VA[u], EVV->VA);
+ EXPECT_NE(G.vertices().end(),
+ std::find_if(G.vertices().begin(), G.vertices().end(),
+ [&](const VVT &VV) { return VV.first == u; }));
+ consumeError(EVV.takeError());
+ }
+
+ for (auto &VVT : G.vertices()) {
+ EXPECT_EQ(1u, V.count(VVT.first));
+ EXPECT_EQ(VA[VVT.first], VVT.second.VA);
+ }
+}
+
+template <typename T> void graphEdgeTester(T &G) {
+ std::set<unsigned> V({1u, 2u, 3u, 4u, 5u, 6u});
+
+ std::set<std::pair<unsigned, unsigned>> E(
+ {{1u, 2u}, {2u, 3u}, {6u, 3u}, {4u, 6u}, {2u, 4u}, {2u, 5u}, {4u, 5u}});
+ std::vector<unsigned> VA({0u, 3u, 5u, 7u, 11u, 13u, 17u});
+
+ EXPECT_EQ(E.size(), G.edges().size());
+ EXPECT_FALSE(G.edges().empty());
+ for (std::pair<unsigned, unsigned> u : E) {
+ auto EEV = G.at(u);
+ ASSERT_TRUE(!!EEV);
+ EXPECT_EQ(1u, G.count(u));
+ EXPECT_EQ(VA[u.first] * VA[u.second] * ((u.first > u.second) ? 2 : 1),
+ EEV->EA);
+ auto Pred = [&](const EVT &EV) { return EV.first == u; };
+ EXPECT_NE(G.edges().end(),
+ std::find_if(G.edges().begin(), G.edges().end(), Pred));
+ consumeError(EEV.takeError());
+ }
+
+ for (auto &EV : G.edges()) {
+ EXPECT_EQ(1u, E.count(EV.first));
+ EXPECT_EQ(VA[EV.first.first] * VA[EV.first.second] *
+ ((EV.first.first > EV.first.second) ? 2 : 1),
+ EV.second.EA);
+ const auto &IE = G.inEdges(EV.first.second);
+ const auto &OE = G.outEdges(EV.first.first);
+ EXPECT_NE(IE.size(), 0u);
+ EXPECT_NE(OE.size(), 0u);
+ EXPECT_NE(IE.begin(), IE.end());
+ EXPECT_NE(OE.begin(), OE.end());
+ {
+ auto It = std::find_if(
+ G.inEdges(EV.first.second).begin(), G.inEdges(EV.first.second).end(),
+ [&](const EVT &EVI) { return EVI.first == EV.first; });
+ EXPECT_NE(G.inEdges(EV.first.second).end(), It);
+ }
+ {
+ auto It = std::find_if(
+ G.inEdges(EV.first.first).begin(), G.inEdges(EV.first.first).end(),
+ [&](const EVT &EVI) { return EVI.first == EV.first; });
+ EXPECT_EQ(G.inEdges(EV.first.first).end(), It);
+ }
+ {
+ auto It =
+ std::find_if(G.outEdges(EV.first.second).begin(),
+ G.outEdges(EV.first.second).end(),
+ [&](const EVT &EVI) { return EVI.first == EV.first; });
+ EXPECT_EQ(G.outEdges(EV.first.second).end(), It);
+ }
+ {
+ auto It = std::find_if(
+ G.outEdges(EV.first.first).begin(), G.outEdges(EV.first.first).end(),
+ [&](const EVT &EVI) { return EVI.first == EV.first; });
+ EXPECT_NE(G.outEdges(EV.first.first).end(), It);
+ }
+ }
+}
+
+TYPED_TEST(GraphTest, TestGraphEdge) {
+ auto &G = this->Graph;
+
+ graphEdgeTester(G);
+}
+
+TYPED_TEST(GraphTest, TestGraphVertex) {
+ auto &G = this->Graph;
+
+ graphVertexTester(G);
+}
+
+TYPED_TEST(GraphTest, TestCopyConstructor) {
+ TypeParam G(this->Graph);
+
+ graphEdgeTester(G);
+ graphVertexTester(G);
+}
+
+TYPED_TEST(GraphTest, TestCopyAssign) {
+ TypeParam G = this->Graph;
+
+ graphEdgeTester(G);
+ graphVertexTester(G);
+}
+
+TYPED_TEST(GraphTest, TestMoveConstructor) {
+ TypeParam G(std::move(this->Graph));
+
+ graphEdgeTester(G);
+ graphVertexTester(G);
+}
+
+// Tests the incremental Construction of a graph
+TEST(GraphTest, TestConstruction) {
+ GraphT MG;
+ const GraphT &G = MG;
+ EXPECT_EQ(0u, G.count(0u));
+ EXPECT_EQ(0u, G.count({0u, 1u}));
+ auto VE = G.at(0);
+ auto EE = G.at({0, 0});
+ EXPECT_FALSE(VE); // G.at[0] returns an error
+ EXPECT_FALSE(EE); // G.at[{0,0}] returns an error
+ consumeError(VE.takeError());
+ consumeError(EE.takeError());
+ EXPECT_TRUE(G.vertices().empty());
+ EXPECT_TRUE(G.edges().empty());
+ EXPECT_EQ(G.vertices().begin(), G.vertices().end());
+ EXPECT_EQ(G.edges().begin(), G.edges().end());
+}
+
+TEST(GraphTest, TestiVertexAccessOperator) {
+ GraphT MG;
+ const GraphT &G = MG;
+
+ MG[0u] = {1u};
+ EXPECT_EQ(1u, MG[0u].VA);
+ EXPECT_EQ(1u, G.count(0u));
+ EXPECT_EQ(0u, G.count(1u));
+ EXPECT_EQ(1u, MG[0u].VA);
+ auto T = G.at(0u);
+ EXPECT_TRUE(!!T);
+ EXPECT_EQ(1u, T->VA);
+
+ EXPECT_EQ(1u, G.vertices().size());
+ EXPECT_EQ(0u, G.edges().size());
+ EXPECT_FALSE(G.vertices().empty());
+ EXPECT_TRUE(G.edges().empty());
+ EXPECT_NE(G.vertices().begin(), G.vertices().end());
+ EXPECT_EQ(G.edges().begin(), G.edges().end());
+ EXPECT_EQ(1u, G.vertices().begin()->second.VA);
+ EXPECT_EQ(0u, G.vertices().begin()->first);
+ EXPECT_EQ(0u, G.outEdges(0u).size());
+ EXPECT_TRUE(G.outEdges(0u).empty());
+ EXPECT_EQ(G.outEdges(0u).begin(), G.outEdges(0u).end());
+ EXPECT_EQ(0u, G.inEdges(0u).size());
+ EXPECT_TRUE(G.inEdges(0u).empty());
+ EXPECT_EQ(G.inEdges(0u).begin(), G.inEdges(0u).end());
+}
+
+TEST(GraphTest, TestEdgeAccessOperator) {
+ GraphT MG;
+ const GraphT &G = MG;
+
+ MG[{0u, 0u}] = {2u};
+ EI EdgeIdent({0u, 0u});
+ EXPECT_EQ(2u, MG[EdgeIdent].EA);
+ EXPECT_EQ(1u, G.count({0u, 0u}));
+ EXPECT_EQ(0u, G.count({0u, 1u}));
+ EXPECT_EQ(1u, G.count(0u));
+ EXPECT_NE(1u, G.count(1u));
+ auto T = G.at({0u, 0u});
+ EXPECT_TRUE(T && T->EA == 2u);
+ EXPECT_EQ(1u, G.edges().size());
+ EXPECT_EQ(1u, G.vertices().size());
+ EXPECT_FALSE(G.edges().empty());
+ EXPECT_FALSE(G.vertices().empty());
+ EXPECT_NE(G.edges().begin(), G.edges().end());
+ EXPECT_EQ(EI(0u, 0u), G.edges().begin()->first);
+ EXPECT_EQ(2u, G.edges().begin()->second.EA);
+ EXPECT_EQ(1u, G.outEdges(0u).size());
+ EXPECT_FALSE(G.outEdges(0u).empty());
+ EXPECT_NE(G.outEdges(0u).begin(), G.outEdges(0u).end());
+ EXPECT_EQ(EI(0u, 0u), G.outEdges(0u).begin()->first);
+ EXPECT_EQ(2u, G.outEdges(0u).begin()->second.EA);
+ EXPECT_EQ(++(G.outEdges(0u).begin()), G.outEdges(0u).end());
+ EXPECT_EQ(1u, G.inEdges(0u).size());
+ EXPECT_FALSE(G.inEdges(0u).empty());
+ EXPECT_NE(G.inEdges(0u).begin(), G.inEdges(0u).end());
+ EXPECT_EQ(EI(0u, 0u), G.inEdges(0u).begin()->first);
+ EXPECT_EQ(2u, G.inEdges(0u).begin()->second.EA);
+ EXPECT_EQ(++(G.inEdges(0u).begin()), G.inEdges(0u).end());
+}
+}