summaryrefslogtreecommitdiff
path: root/unittests
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-01-02 19:17:04 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-01-02 19:17:04 +0000
commitb915e9e0fc85ba6f398b3fab0db6a81a8913af94 (patch)
tree98b8f811c7aff2547cab8642daf372d6c59502fb /unittests
parent6421cca32f69ac849537a3cff78c352195e99f1b (diff)
downloadsrc-test2-b915e9e0fc85ba6f398b3fab0db6a81a8913af94.tar.gz
src-test2-b915e9e0fc85ba6f398b3fab0db6a81a8913af94.zip
Notes
Diffstat (limited to 'unittests')
-rw-r--r--unittests/ADT/APFloatTest.cpp1786
-rw-r--r--unittests/ADT/APIntTest.cpp179
-rw-r--r--unittests/ADT/ArrayRefTest.cpp89
-rw-r--r--unittests/ADT/BumpPtrListTest.cpp243
-rw-r--r--unittests/ADT/CMakeLists.txt16
-rw-r--r--unittests/ADT/DenseMapTest.cpp59
-rw-r--r--unittests/ADT/DenseSetTest.cpp126
-rw-r--r--unittests/ADT/DepthFirstIteratorTest.cpp54
-rw-r--r--unittests/ADT/FoldingSet.cpp21
-rw-r--r--unittests/ADT/IListBaseTest.cpp166
-rw-r--r--unittests/ADT/IListIteratorTest.cpp134
-rw-r--r--unittests/ADT/IListNodeBaseTest.cpp100
-rw-r--r--unittests/ADT/IListNodeTest.cpp70
-rw-r--r--unittests/ADT/IListSentinelTest.cpp63
-rw-r--r--unittests/ADT/IListTest.cpp276
-rw-r--r--unittests/ADT/IntervalMapTest.cpp47
-rw-r--r--unittests/ADT/IntrusiveRefCntPtrTest.cpp37
-rw-r--r--unittests/ADT/IteratorTest.cpp (renamed from unittests/Support/IteratorTest.cpp)87
-rw-r--r--unittests/ADT/MapVectorTest.cpp18
-rw-r--r--unittests/ADT/OptionalTest.cpp150
-rw-r--r--unittests/ADT/PostOrderIteratorTest.cpp8
-rw-r--r--unittests/ADT/RangeAdapterTest.cpp95
-rw-r--r--unittests/ADT/ReverseIterationTest.cpp52
-rw-r--r--unittests/ADT/SCCIteratorTest.cpp228
-rw-r--r--unittests/ADT/STLExtrasTest.cpp311
-rw-r--r--unittests/ADT/ScopeExitTest.cpp32
-rw-r--r--unittests/ADT/SimpleIListTest.cpp654
-rw-r--r--unittests/ADT/SmallPtrSetTest.cpp14
-rw-r--r--unittests/ADT/StringExtrasTest.cpp52
-rw-r--r--unittests/ADT/StringMapTest.cpp2
-rw-r--r--unittests/ADT/StringRefTest.cpp431
-rw-r--r--unittests/ADT/StringSwitchTest.cpp206
-rw-r--r--unittests/ADT/TestGraph.h251
-rw-r--r--unittests/ADT/TripleTest.cpp365
-rw-r--r--unittests/ADT/TwineTest.cpp28
-rw-r--r--unittests/ADT/ilistTest.cpp99
-rw-r--r--unittests/Analysis/BranchProbabilityInfoTest.cpp88
-rw-r--r--unittests/Analysis/CGSCCPassManagerTest.cpp1071
-rw-r--r--unittests/Analysis/CMakeLists.txt4
-rw-r--r--unittests/Analysis/CallGraphTest.cpp18
-rw-r--r--unittests/Analysis/LazyCallGraphTest.cpp932
-rw-r--r--unittests/Analysis/LoopPassManagerTest.cpp32
-rw-r--r--unittests/Analysis/MemoryBuiltinsTest.cpp50
-rw-r--r--unittests/Analysis/MixedTBAATest.cpp79
-rw-r--r--unittests/Analysis/ScalarEvolutionTest.cpp268
-rw-r--r--unittests/Analysis/TBAATest.cpp91
-rw-r--r--unittests/Analysis/ValueTrackingTest.cpp51
-rw-r--r--unittests/Bitcode/BitReaderTest.cpp103
-rw-r--r--unittests/Bitcode/BitstreamReaderTest.cpp124
-rw-r--r--unittests/CMakeLists.txt8
-rw-r--r--unittests/CodeGen/CMakeLists.txt6
-rw-r--r--unittests/CodeGen/GlobalISel/CMakeLists.txt10
-rw-r--r--unittests/CodeGen/GlobalISel/LegalizerInfoTest.cpp120
-rw-r--r--unittests/CodeGen/LowLevelTypeTest.cpp204
-rw-r--r--unittests/CodeGen/MachineInstrBundleIteratorTest.cpp133
-rw-r--r--unittests/DebugInfo/DWARF/CMakeLists.txt7
-rw-r--r--unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp1087
-rw-r--r--unittests/DebugInfo/DWARF/DWARFFormValueTest.cpp55
-rw-r--r--unittests/DebugInfo/DWARF/DwarfGenerator.cpp266
-rw-r--r--unittests/DebugInfo/DWARF/DwarfGenerator.h231
-rw-r--r--unittests/DebugInfo/PDB/CMakeLists.txt3
-rw-r--r--unittests/DebugInfo/PDB/ErrorChecking.h10
-rw-r--r--unittests/DebugInfo/PDB/MSFBuilderTest.cpp (renamed from unittests/DebugInfo/PDB/MsfBuilderTest.cpp)118
-rw-r--r--unittests/DebugInfo/PDB/MappedBlockStreamTest.cpp267
-rw-r--r--unittests/ExecutionEngine/MCJIT/MCJITTestAPICommon.h16
-rw-r--r--unittests/ExecutionEngine/Orc/CompileOnDemandLayerTest.cpp4
-rw-r--r--unittests/ExecutionEngine/Orc/GlobalMappingLayerTest.cpp6
-rw-r--r--unittests/ExecutionEngine/Orc/LazyEmittingLayerTest.cpp3
-rw-r--r--unittests/ExecutionEngine/Orc/ObjectLinkingLayerTest.cpp10
-rw-r--r--unittests/ExecutionEngine/Orc/ObjectTransformLayerTest.cpp29
-rw-r--r--unittests/ExecutionEngine/Orc/OrcTestCommon.h6
-rw-r--r--unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp497
-rw-r--r--unittests/IR/CMakeLists.txt1
-rw-r--r--unittests/IR/ConstantRangeTest.cpp71
-rw-r--r--unittests/IR/DebugInfoTest.cpp24
-rw-r--r--unittests/IR/DebugTypeODRUniquingTest.cpp29
-rw-r--r--unittests/IR/IRBuilderTest.cpp23
-rw-r--r--unittests/IR/MetadataTest.cpp276
-rw-r--r--unittests/IR/ModuleTest.cpp75
-rw-r--r--unittests/IR/PassManagerTest.cpp544
-rw-r--r--unittests/IR/PatternMatch.cpp27
-rw-r--r--unittests/IR/VerifierTest.cpp104
-rw-r--r--unittests/MC/DwarfLineTables.cpp14
-rw-r--r--unittests/MC/StringTableBuilderTest.cpp21
-rw-r--r--unittests/MI/LiveIntervalTest.cpp159
-rw-r--r--unittests/Object/CMakeLists.txt8
-rw-r--r--unittests/Object/SymbolSizeTest.cpp33
-rw-r--r--unittests/ProfileData/CoverageMappingTest.cpp120
-rw-r--r--unittests/ProfileData/InstrProfTest.cpp35
-rw-r--r--unittests/ProfileData/SampleProfTest.cpp10
-rw-r--r--unittests/Support/AlignOfTest.cpp222
-rw-r--r--unittests/Support/CMakeLists.txt14
-rw-r--r--unittests/Support/Chrono.cpp79
-rw-r--r--unittests/Support/CommandLineTest.cpp142
-rw-r--r--unittests/Support/DebugTest.cpp34
-rw-r--r--unittests/Support/DwarfTest.cpp24
-rw-r--r--unittests/Support/ErrorTest.cpp49
-rw-r--r--unittests/Support/FileOutputBufferTest.cpp13
-rw-r--r--unittests/Support/FormatVariadicTest.cpp570
-rw-r--r--unittests/Support/GlobPatternTest.cpp70
-rw-r--r--unittests/Support/Host.cpp48
-rw-r--r--unittests/Support/MD5Test.cpp10
-rw-r--r--unittests/Support/MathExtrasTest.cpp12
-rw-r--r--unittests/Support/MemoryBufferTest.cpp4
-rw-r--r--unittests/Support/NativeFormatTests.cpp176
-rw-r--r--unittests/Support/Path.cpp102
-rw-r--r--unittests/Support/RegexTest.cpp18
-rw-r--r--unittests/Support/SpecialCaseListTest.cpp57
-rw-r--r--unittests/Support/StreamingMemoryObjectTest.cpp68
-rw-r--r--unittests/Support/TargetParserTest.cpp764
-rw-r--r--unittests/Support/ThreadPool.cpp10
-rw-r--r--unittests/Support/Threading.cpp25
-rw-r--r--unittests/Support/TimeValueTest.cpp40
-rw-r--r--unittests/Support/TimerTest.cpp4
-rw-r--r--unittests/Support/TrailingObjectsTest.cpp56
-rw-r--r--unittests/Support/TrigramIndexTest.cpp132
-rw-r--r--unittests/Support/YAMLIOTest.cpp77
-rw-r--r--unittests/Support/raw_ostream_test.cpp148
-rw-r--r--unittests/Support/raw_pwrite_stream_test.cpp32
-rw-r--r--unittests/Support/raw_sha1_ostream_test.cpp7
-rw-r--r--unittests/Support/xxhashTest.cpp20
-rw-r--r--unittests/Target/AArch64/CMakeLists.txt21
-rw-r--r--unittests/Target/AArch64/InstSizes.cpp122
-rw-r--r--unittests/Target/CMakeLists.txt5
-rw-r--r--unittests/Transforms/Utils/ASanStackFrameLayoutTest.cpp114
-rw-r--r--unittests/Transforms/Utils/CMakeLists.txt1
-rw-r--r--unittests/Transforms/Utils/Cloning.cpp42
-rw-r--r--unittests/Transforms/Utils/FunctionComparator.cpp130
-rw-r--r--unittests/Transforms/Utils/MemorySSA.cpp270
129 files changed, 14559 insertions, 3303 deletions
diff --git a/unittests/ADT/APFloatTest.cpp b/unittests/ADT/APFloatTest.cpp
index 18734eb72b82..a273005cd1f3 100644
--- a/unittests/ADT/APFloatTest.cpp
+++ b/unittests/ADT/APFloatTest.cpp
@@ -10,11 +10,13 @@
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/raw_ostream.h"
#include "gtest/gtest.h"
#include <cmath>
#include <ostream>
#include <string>
+#include <tuple>
using namespace llvm;
@@ -38,20 +40,20 @@ TEST(APFloatTest, isSignaling) {
// positive/negative distinction is included only since the getQNaN/getSNaN
// API provides the option.
APInt payload = APInt::getOneBitSet(4, 2);
- EXPECT_FALSE(APFloat::getQNaN(APFloat::IEEEsingle, false).isSignaling());
- EXPECT_FALSE(APFloat::getQNaN(APFloat::IEEEsingle, true).isSignaling());
- EXPECT_FALSE(APFloat::getQNaN(APFloat::IEEEsingle, false, &payload).isSignaling());
- EXPECT_FALSE(APFloat::getQNaN(APFloat::IEEEsingle, true, &payload).isSignaling());
- EXPECT_TRUE(APFloat::getSNaN(APFloat::IEEEsingle, false).isSignaling());
- EXPECT_TRUE(APFloat::getSNaN(APFloat::IEEEsingle, true).isSignaling());
- EXPECT_TRUE(APFloat::getSNaN(APFloat::IEEEsingle, false, &payload).isSignaling());
- EXPECT_TRUE(APFloat::getSNaN(APFloat::IEEEsingle, true, &payload).isSignaling());
+ EXPECT_FALSE(APFloat::getQNaN(APFloat::IEEEsingle(), false).isSignaling());
+ EXPECT_FALSE(APFloat::getQNaN(APFloat::IEEEsingle(), true).isSignaling());
+ EXPECT_FALSE(APFloat::getQNaN(APFloat::IEEEsingle(), false, &payload).isSignaling());
+ EXPECT_FALSE(APFloat::getQNaN(APFloat::IEEEsingle(), true, &payload).isSignaling());
+ EXPECT_TRUE(APFloat::getSNaN(APFloat::IEEEsingle(), false).isSignaling());
+ EXPECT_TRUE(APFloat::getSNaN(APFloat::IEEEsingle(), true).isSignaling());
+ EXPECT_TRUE(APFloat::getSNaN(APFloat::IEEEsingle(), false, &payload).isSignaling());
+ EXPECT_TRUE(APFloat::getSNaN(APFloat::IEEEsingle(), true, &payload).isSignaling());
}
TEST(APFloatTest, next) {
- APFloat test(APFloat::IEEEquad, APFloat::uninitialized);
- APFloat expected(APFloat::IEEEquad, APFloat::uninitialized);
+ APFloat test(APFloat::IEEEquad(), APFloat::uninitialized);
+ APFloat expected(APFloat::IEEEquad(), APFloat::uninitialized);
// 1. Test Special Cases Values.
//
@@ -69,37 +71,37 @@ TEST(APFloatTest, next) {
// 10. -0
// nextUp(+inf) = +inf.
- test = APFloat::getInf(APFloat::IEEEquad, false);
- expected = APFloat::getInf(APFloat::IEEEquad, false);
+ test = APFloat::getInf(APFloat::IEEEquad(), false);
+ expected = APFloat::getInf(APFloat::IEEEquad(), false);
EXPECT_EQ(test.next(false), APFloat::opOK);
EXPECT_TRUE(test.isInfinity());
EXPECT_TRUE(!test.isNegative());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextDown(+inf) = -nextUp(-inf) = -(-getLargest()) = getLargest()
- test = APFloat::getInf(APFloat::IEEEquad, false);
- expected = APFloat::getLargest(APFloat::IEEEquad, false);
+ test = APFloat::getInf(APFloat::IEEEquad(), false);
+ expected = APFloat::getLargest(APFloat::IEEEquad(), false);
EXPECT_EQ(test.next(true), APFloat::opOK);
EXPECT_TRUE(!test.isNegative());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextUp(-inf) = -getLargest()
- test = APFloat::getInf(APFloat::IEEEquad, true);
- expected = APFloat::getLargest(APFloat::IEEEquad, true);
+ test = APFloat::getInf(APFloat::IEEEquad(), true);
+ expected = APFloat::getLargest(APFloat::IEEEquad(), true);
EXPECT_EQ(test.next(false), APFloat::opOK);
EXPECT_TRUE(test.isNegative());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextDown(-inf) = -nextUp(+inf) = -(+inf) = -inf.
- test = APFloat::getInf(APFloat::IEEEquad, true);
- expected = APFloat::getInf(APFloat::IEEEquad, true);
+ test = APFloat::getInf(APFloat::IEEEquad(), true);
+ expected = APFloat::getInf(APFloat::IEEEquad(), true);
EXPECT_EQ(test.next(true), APFloat::opOK);
EXPECT_TRUE(test.isInfinity() && test.isNegative());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextUp(getLargest()) = +inf
- test = APFloat::getLargest(APFloat::IEEEquad, false);
- expected = APFloat::getInf(APFloat::IEEEquad, false);
+ test = APFloat::getLargest(APFloat::IEEEquad(), false);
+ expected = APFloat::getInf(APFloat::IEEEquad(), false);
EXPECT_EQ(test.next(false), APFloat::opOK);
EXPECT_TRUE(test.isInfinity() && !test.isNegative());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
@@ -107,100 +109,100 @@ TEST(APFloatTest, next) {
// nextDown(getLargest()) = -nextUp(-getLargest())
// = -(-getLargest() + inc)
// = getLargest() - inc.
- test = APFloat::getLargest(APFloat::IEEEquad, false);
- expected = APFloat(APFloat::IEEEquad,
+ test = APFloat::getLargest(APFloat::IEEEquad(), false);
+ expected = APFloat(APFloat::IEEEquad(),
"0x1.fffffffffffffffffffffffffffep+16383");
EXPECT_EQ(test.next(true), APFloat::opOK);
EXPECT_TRUE(!test.isInfinity() && !test.isNegative());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextUp(-getLargest()) = -getLargest() + inc.
- test = APFloat::getLargest(APFloat::IEEEquad, true);
- expected = APFloat(APFloat::IEEEquad,
+ test = APFloat::getLargest(APFloat::IEEEquad(), true);
+ expected = APFloat(APFloat::IEEEquad(),
"-0x1.fffffffffffffffffffffffffffep+16383");
EXPECT_EQ(test.next(false), APFloat::opOK);
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextDown(-getLargest()) = -nextUp(getLargest()) = -(inf) = -inf.
- test = APFloat::getLargest(APFloat::IEEEquad, true);
- expected = APFloat::getInf(APFloat::IEEEquad, true);
+ test = APFloat::getLargest(APFloat::IEEEquad(), true);
+ expected = APFloat::getInf(APFloat::IEEEquad(), true);
EXPECT_EQ(test.next(true), APFloat::opOK);
EXPECT_TRUE(test.isInfinity() && test.isNegative());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextUp(getSmallest()) = getSmallest() + inc.
- test = APFloat(APFloat::IEEEquad, "0x0.0000000000000000000000000001p-16382");
- expected = APFloat(APFloat::IEEEquad,
+ test = APFloat(APFloat::IEEEquad(), "0x0.0000000000000000000000000001p-16382");
+ expected = APFloat(APFloat::IEEEquad(),
"0x0.0000000000000000000000000002p-16382");
EXPECT_EQ(test.next(false), APFloat::opOK);
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextDown(getSmallest()) = -nextUp(-getSmallest()) = -(-0) = +0.
- test = APFloat(APFloat::IEEEquad, "0x0.0000000000000000000000000001p-16382");
- expected = APFloat::getZero(APFloat::IEEEquad, false);
+ test = APFloat(APFloat::IEEEquad(), "0x0.0000000000000000000000000001p-16382");
+ expected = APFloat::getZero(APFloat::IEEEquad(), false);
EXPECT_EQ(test.next(true), APFloat::opOK);
EXPECT_TRUE(test.isPosZero());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextUp(-getSmallest()) = -0.
- test = APFloat(APFloat::IEEEquad, "-0x0.0000000000000000000000000001p-16382");
- expected = APFloat::getZero(APFloat::IEEEquad, true);
+ test = APFloat(APFloat::IEEEquad(), "-0x0.0000000000000000000000000001p-16382");
+ expected = APFloat::getZero(APFloat::IEEEquad(), true);
EXPECT_EQ(test.next(false), APFloat::opOK);
EXPECT_TRUE(test.isNegZero());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextDown(-getSmallest()) = -nextUp(getSmallest()) = -getSmallest() - inc.
- test = APFloat(APFloat::IEEEquad, "-0x0.0000000000000000000000000001p-16382");
- expected = APFloat(APFloat::IEEEquad,
+ test = APFloat(APFloat::IEEEquad(), "-0x0.0000000000000000000000000001p-16382");
+ expected = APFloat(APFloat::IEEEquad(),
"-0x0.0000000000000000000000000002p-16382");
EXPECT_EQ(test.next(true), APFloat::opOK);
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextUp(qNaN) = qNaN
- test = APFloat::getQNaN(APFloat::IEEEquad, false);
- expected = APFloat::getQNaN(APFloat::IEEEquad, false);
+ test = APFloat::getQNaN(APFloat::IEEEquad(), false);
+ expected = APFloat::getQNaN(APFloat::IEEEquad(), false);
EXPECT_EQ(test.next(false), APFloat::opOK);
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextDown(qNaN) = qNaN
- test = APFloat::getQNaN(APFloat::IEEEquad, false);
- expected = APFloat::getQNaN(APFloat::IEEEquad, false);
+ test = APFloat::getQNaN(APFloat::IEEEquad(), false);
+ expected = APFloat::getQNaN(APFloat::IEEEquad(), false);
EXPECT_EQ(test.next(true), APFloat::opOK);
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextUp(sNaN) = qNaN
- test = APFloat::getSNaN(APFloat::IEEEquad, false);
- expected = APFloat::getQNaN(APFloat::IEEEquad, false);
+ test = APFloat::getSNaN(APFloat::IEEEquad(), false);
+ expected = APFloat::getQNaN(APFloat::IEEEquad(), false);
EXPECT_EQ(test.next(false), APFloat::opInvalidOp);
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextDown(sNaN) = qNaN
- test = APFloat::getSNaN(APFloat::IEEEquad, false);
- expected = APFloat::getQNaN(APFloat::IEEEquad, false);
+ test = APFloat::getSNaN(APFloat::IEEEquad(), false);
+ expected = APFloat::getQNaN(APFloat::IEEEquad(), false);
EXPECT_EQ(test.next(true), APFloat::opInvalidOp);
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextUp(+0) = +getSmallest()
- test = APFloat::getZero(APFloat::IEEEquad, false);
- expected = APFloat::getSmallest(APFloat::IEEEquad, false);
+ test = APFloat::getZero(APFloat::IEEEquad(), false);
+ expected = APFloat::getSmallest(APFloat::IEEEquad(), false);
EXPECT_EQ(test.next(false), APFloat::opOK);
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextDown(+0) = -nextUp(-0) = -getSmallest()
- test = APFloat::getZero(APFloat::IEEEquad, false);
- expected = APFloat::getSmallest(APFloat::IEEEquad, true);
+ test = APFloat::getZero(APFloat::IEEEquad(), false);
+ expected = APFloat::getSmallest(APFloat::IEEEquad(), true);
EXPECT_EQ(test.next(true), APFloat::opOK);
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextUp(-0) = +getSmallest()
- test = APFloat::getZero(APFloat::IEEEquad, true);
- expected = APFloat::getSmallest(APFloat::IEEEquad, false);
+ test = APFloat::getZero(APFloat::IEEEquad(), true);
+ expected = APFloat::getSmallest(APFloat::IEEEquad(), false);
EXPECT_EQ(test.next(false), APFloat::opOK);
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextDown(-0) = -nextUp(0) = -getSmallest()
- test = APFloat::getZero(APFloat::IEEEquad, true);
- expected = APFloat::getSmallest(APFloat::IEEEquad, true);
+ test = APFloat::getZero(APFloat::IEEEquad(), true);
+ expected = APFloat::getSmallest(APFloat::IEEEquad(), true);
EXPECT_EQ(test.next(true), APFloat::opOK);
EXPECT_TRUE(test.bitwiseIsEqual(expected));
@@ -213,35 +215,35 @@ TEST(APFloatTest, next) {
// * nextDown(+Smallest Normal) -> +Largest Denormal.
// nextUp(+Largest Denormal) -> +Smallest Normal.
- test = APFloat(APFloat::IEEEquad, "0x0.ffffffffffffffffffffffffffffp-16382");
- expected = APFloat(APFloat::IEEEquad,
+ test = APFloat(APFloat::IEEEquad(), "0x0.ffffffffffffffffffffffffffffp-16382");
+ expected = APFloat(APFloat::IEEEquad(),
"0x1.0000000000000000000000000000p-16382");
EXPECT_EQ(test.next(false), APFloat::opOK);
EXPECT_FALSE(test.isDenormal());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextDown(-Largest Denormal) -> -Smallest Normal.
- test = APFloat(APFloat::IEEEquad,
+ test = APFloat(APFloat::IEEEquad(),
"-0x0.ffffffffffffffffffffffffffffp-16382");
- expected = APFloat(APFloat::IEEEquad,
+ expected = APFloat(APFloat::IEEEquad(),
"-0x1.0000000000000000000000000000p-16382");
EXPECT_EQ(test.next(true), APFloat::opOK);
EXPECT_FALSE(test.isDenormal());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextUp(-Smallest Normal) -> -LargestDenormal.
- test = APFloat(APFloat::IEEEquad,
+ test = APFloat(APFloat::IEEEquad(),
"-0x1.0000000000000000000000000000p-16382");
- expected = APFloat(APFloat::IEEEquad,
+ expected = APFloat(APFloat::IEEEquad(),
"-0x0.ffffffffffffffffffffffffffffp-16382");
EXPECT_EQ(test.next(false), APFloat::opOK);
EXPECT_TRUE(test.isDenormal());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextDown(+Smallest Normal) -> +Largest Denormal.
- test = APFloat(APFloat::IEEEquad,
+ test = APFloat(APFloat::IEEEquad(),
"+0x1.0000000000000000000000000000p-16382");
- expected = APFloat(APFloat::IEEEquad,
+ expected = APFloat(APFloat::IEEEquad(),
"+0x0.ffffffffffffffffffffffffffffp-16382");
EXPECT_EQ(test.next(true), APFloat::opOK);
EXPECT_TRUE(test.isDenormal());
@@ -254,27 +256,27 @@ TEST(APFloatTest, next) {
// * nextDown(-Normal Binade Boundary + 1) -> -Normal Binade Boundary.
// nextUp(-Normal Binade Boundary) -> -Normal Binade Boundary + 1.
- test = APFloat(APFloat::IEEEquad, "-0x1p+1");
- expected = APFloat(APFloat::IEEEquad,
+ test = APFloat(APFloat::IEEEquad(), "-0x1p+1");
+ expected = APFloat(APFloat::IEEEquad(),
"-0x1.ffffffffffffffffffffffffffffp+0");
EXPECT_EQ(test.next(false), APFloat::opOK);
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextDown(+Normal Binade Boundary) -> +Normal Binade Boundary - 1.
- test = APFloat(APFloat::IEEEquad, "0x1p+1");
- expected = APFloat(APFloat::IEEEquad, "0x1.ffffffffffffffffffffffffffffp+0");
+ test = APFloat(APFloat::IEEEquad(), "0x1p+1");
+ expected = APFloat(APFloat::IEEEquad(), "0x1.ffffffffffffffffffffffffffffp+0");
EXPECT_EQ(test.next(true), APFloat::opOK);
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextUp(+Normal Binade Boundary - 1) -> +Normal Binade Boundary.
- test = APFloat(APFloat::IEEEquad, "0x1.ffffffffffffffffffffffffffffp+0");
- expected = APFloat(APFloat::IEEEquad, "0x1p+1");
+ test = APFloat(APFloat::IEEEquad(), "0x1.ffffffffffffffffffffffffffffp+0");
+ expected = APFloat(APFloat::IEEEquad(), "0x1p+1");
EXPECT_EQ(test.next(false), APFloat::opOK);
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextDown(-Normal Binade Boundary + 1) -> -Normal Binade Boundary.
- test = APFloat(APFloat::IEEEquad, "-0x1.ffffffffffffffffffffffffffffp+0");
- expected = APFloat(APFloat::IEEEquad, "-0x1p+1");
+ test = APFloat(APFloat::IEEEquad(), "-0x1.ffffffffffffffffffffffffffffp+0");
+ expected = APFloat(APFloat::IEEEquad(), "-0x1p+1");
EXPECT_EQ(test.next(true), APFloat::opOK);
EXPECT_TRUE(test.bitwiseIsEqual(expected));
@@ -290,8 +292,8 @@ TEST(APFloatTest, next) {
// * nextDown(-Smallest Normal) -> -Smallest Normal - inc.
// nextUp(-Largest Denormal) -> -Largest Denormal + inc.
- test = APFloat(APFloat::IEEEquad, "-0x0.ffffffffffffffffffffffffffffp-16382");
- expected = APFloat(APFloat::IEEEquad,
+ test = APFloat(APFloat::IEEEquad(), "-0x0.ffffffffffffffffffffffffffffp-16382");
+ expected = APFloat(APFloat::IEEEquad(),
"-0x0.fffffffffffffffffffffffffffep-16382");
EXPECT_EQ(test.next(false), APFloat::opOK);
EXPECT_TRUE(test.isDenormal());
@@ -299,8 +301,8 @@ TEST(APFloatTest, next) {
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextDown(+Largest Denormal) -> +Largest Denormal - inc.
- test = APFloat(APFloat::IEEEquad, "0x0.ffffffffffffffffffffffffffffp-16382");
- expected = APFloat(APFloat::IEEEquad,
+ test = APFloat(APFloat::IEEEquad(), "0x0.ffffffffffffffffffffffffffffp-16382");
+ expected = APFloat(APFloat::IEEEquad(),
"0x0.fffffffffffffffffffffffffffep-16382");
EXPECT_EQ(test.next(true), APFloat::opOK);
EXPECT_TRUE(test.isDenormal());
@@ -308,8 +310,8 @@ TEST(APFloatTest, next) {
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextUp(+Smallest Normal) -> +Smallest Normal + inc.
- test = APFloat(APFloat::IEEEquad, "0x1.0000000000000000000000000000p-16382");
- expected = APFloat(APFloat::IEEEquad,
+ test = APFloat(APFloat::IEEEquad(), "0x1.0000000000000000000000000000p-16382");
+ expected = APFloat(APFloat::IEEEquad(),
"0x1.0000000000000000000000000001p-16382");
EXPECT_EQ(test.next(false), APFloat::opOK);
EXPECT_TRUE(!test.isDenormal());
@@ -317,8 +319,8 @@ TEST(APFloatTest, next) {
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextDown(-Smallest Normal) -> -Smallest Normal - inc.
- test = APFloat(APFloat::IEEEquad, "-0x1.0000000000000000000000000000p-16382");
- expected = APFloat(APFloat::IEEEquad,
+ test = APFloat(APFloat::IEEEquad(), "-0x1.0000000000000000000000000000p-16382");
+ expected = APFloat(APFloat::IEEEquad(),
"-0x1.0000000000000000000000000001p-16382");
EXPECT_EQ(test.next(true), APFloat::opOK);
EXPECT_TRUE(!test.isDenormal());
@@ -335,28 +337,28 @@ TEST(APFloatTest, next) {
// * nextDown(0x1p-16382) -> 0x1.ffffffffffffffffffffffffffffp-16382
// nextUp(-0x1p-16381) -> -0x1.ffffffffffffffffffffffffffffp-16382
- test = APFloat(APFloat::IEEEquad, "-0x1p-16381");
- expected = APFloat(APFloat::IEEEquad,
+ test = APFloat(APFloat::IEEEquad(), "-0x1p-16381");
+ expected = APFloat(APFloat::IEEEquad(),
"-0x1.ffffffffffffffffffffffffffffp-16382");
EXPECT_EQ(test.next(false), APFloat::opOK);
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextDown(-0x1.ffffffffffffffffffffffffffffp-16382) ->
// -0x1p-16381
- test = APFloat(APFloat::IEEEquad, "-0x1.ffffffffffffffffffffffffffffp-16382");
- expected = APFloat(APFloat::IEEEquad, "-0x1p-16381");
+ test = APFloat(APFloat::IEEEquad(), "-0x1.ffffffffffffffffffffffffffffp-16382");
+ expected = APFloat(APFloat::IEEEquad(), "-0x1p-16381");
EXPECT_EQ(test.next(true), APFloat::opOK);
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextUp(0x1.ffffffffffffffffffffffffffffp-16382) -> 0x1p-16381
- test = APFloat(APFloat::IEEEquad, "0x1.ffffffffffffffffffffffffffffp-16382");
- expected = APFloat(APFloat::IEEEquad, "0x1p-16381");
+ test = APFloat(APFloat::IEEEquad(), "0x1.ffffffffffffffffffffffffffffp-16382");
+ expected = APFloat(APFloat::IEEEquad(), "0x1p-16381");
EXPECT_EQ(test.next(false), APFloat::opOK);
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextDown(0x1p-16381) -> 0x1.ffffffffffffffffffffffffffffp-16382
- test = APFloat(APFloat::IEEEquad, "0x1p-16381");
- expected = APFloat(APFloat::IEEEquad,
+ test = APFloat(APFloat::IEEEquad(), "0x1p-16381");
+ expected = APFloat(APFloat::IEEEquad(),
"0x1.ffffffffffffffffffffffffffffp-16382");
EXPECT_EQ(test.next(true), APFloat::opOK);
EXPECT_TRUE(test.bitwiseIsEqual(expected));
@@ -373,9 +375,9 @@ TEST(APFloatTest, next) {
// * nextDown(-Normal) -> -Normal.
// nextUp(+Denormal) -> +Denormal.
- test = APFloat(APFloat::IEEEquad,
+ test = APFloat(APFloat::IEEEquad(),
"0x0.ffffffffffffffffffffffff000cp-16382");
- expected = APFloat(APFloat::IEEEquad,
+ expected = APFloat(APFloat::IEEEquad(),
"0x0.ffffffffffffffffffffffff000dp-16382");
EXPECT_EQ(test.next(false), APFloat::opOK);
EXPECT_TRUE(test.isDenormal());
@@ -383,9 +385,9 @@ TEST(APFloatTest, next) {
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextDown(+Denormal) -> +Denormal.
- test = APFloat(APFloat::IEEEquad,
+ test = APFloat(APFloat::IEEEquad(),
"0x0.ffffffffffffffffffffffff000cp-16382");
- expected = APFloat(APFloat::IEEEquad,
+ expected = APFloat(APFloat::IEEEquad(),
"0x0.ffffffffffffffffffffffff000bp-16382");
EXPECT_EQ(test.next(true), APFloat::opOK);
EXPECT_TRUE(test.isDenormal());
@@ -393,9 +395,9 @@ TEST(APFloatTest, next) {
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextUp(-Denormal) -> -Denormal.
- test = APFloat(APFloat::IEEEquad,
+ test = APFloat(APFloat::IEEEquad(),
"-0x0.ffffffffffffffffffffffff000cp-16382");
- expected = APFloat(APFloat::IEEEquad,
+ expected = APFloat(APFloat::IEEEquad(),
"-0x0.ffffffffffffffffffffffff000bp-16382");
EXPECT_EQ(test.next(false), APFloat::opOK);
EXPECT_TRUE(test.isDenormal());
@@ -403,9 +405,9 @@ TEST(APFloatTest, next) {
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextDown(-Denormal) -> -Denormal
- test = APFloat(APFloat::IEEEquad,
+ test = APFloat(APFloat::IEEEquad(),
"-0x0.ffffffffffffffffffffffff000cp-16382");
- expected = APFloat(APFloat::IEEEquad,
+ expected = APFloat(APFloat::IEEEquad(),
"-0x0.ffffffffffffffffffffffff000dp-16382");
EXPECT_EQ(test.next(true), APFloat::opOK);
EXPECT_TRUE(test.isDenormal());
@@ -413,9 +415,9 @@ TEST(APFloatTest, next) {
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextUp(+Normal) -> +Normal.
- test = APFloat(APFloat::IEEEquad,
+ test = APFloat(APFloat::IEEEquad(),
"0x1.ffffffffffffffffffffffff000cp-16000");
- expected = APFloat(APFloat::IEEEquad,
+ expected = APFloat(APFloat::IEEEquad(),
"0x1.ffffffffffffffffffffffff000dp-16000");
EXPECT_EQ(test.next(false), APFloat::opOK);
EXPECT_TRUE(!test.isDenormal());
@@ -423,9 +425,9 @@ TEST(APFloatTest, next) {
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextDown(+Normal) -> +Normal.
- test = APFloat(APFloat::IEEEquad,
+ test = APFloat(APFloat::IEEEquad(),
"0x1.ffffffffffffffffffffffff000cp-16000");
- expected = APFloat(APFloat::IEEEquad,
+ expected = APFloat(APFloat::IEEEquad(),
"0x1.ffffffffffffffffffffffff000bp-16000");
EXPECT_EQ(test.next(true), APFloat::opOK);
EXPECT_TRUE(!test.isDenormal());
@@ -433,9 +435,9 @@ TEST(APFloatTest, next) {
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextUp(-Normal) -> -Normal.
- test = APFloat(APFloat::IEEEquad,
+ test = APFloat(APFloat::IEEEquad(),
"-0x1.ffffffffffffffffffffffff000cp-16000");
- expected = APFloat(APFloat::IEEEquad,
+ expected = APFloat(APFloat::IEEEquad(),
"-0x1.ffffffffffffffffffffffff000bp-16000");
EXPECT_EQ(test.next(false), APFloat::opOK);
EXPECT_TRUE(!test.isDenormal());
@@ -443,9 +445,9 @@ TEST(APFloatTest, next) {
EXPECT_TRUE(test.bitwiseIsEqual(expected));
// nextDown(-Normal) -> -Normal.
- test = APFloat(APFloat::IEEEquad,
+ test = APFloat(APFloat::IEEEquad(),
"-0x1.ffffffffffffffffffffffff000cp-16000");
- expected = APFloat(APFloat::IEEEquad,
+ expected = APFloat(APFloat::IEEEquad(),
"-0x1.ffffffffffffffffffffffff000dp-16000");
EXPECT_EQ(test.next(true), APFloat::opOK);
EXPECT_TRUE(!test.isDenormal());
@@ -508,8 +510,8 @@ TEST(APFloatTest, FMA) {
// Test -ve sign preservation when small negative results underflow.
{
- APFloat f1(APFloat::IEEEdouble, "-0x1p-1074");
- APFloat f2(APFloat::IEEEdouble, "+0x1p-1074");
+ APFloat f1(APFloat::IEEEdouble(), "-0x1p-1074");
+ APFloat f2(APFloat::IEEEdouble(), "+0x1p-1074");
APFloat f3(0.0);
f1.fusedMultiplyAdd(f2, f3, APFloat::rmNearestTiesToEven);
EXPECT_TRUE(f1.isNegative() && f1.isZero());
@@ -517,13 +519,13 @@ TEST(APFloatTest, FMA) {
// Test x87 extended precision case from http://llvm.org/PR20728.
{
- APFloat M1(APFloat::x87DoubleExtended, 1.0);
- APFloat M2(APFloat::x87DoubleExtended, 1.0);
- APFloat A(APFloat::x87DoubleExtended, 3.0);
+ APFloat M1(APFloat::x87DoubleExtended(), 1.0);
+ APFloat M2(APFloat::x87DoubleExtended(), 1.0);
+ APFloat A(APFloat::x87DoubleExtended(), 3.0);
bool losesInfo = false;
M1.fusedMultiplyAdd(M1, A, APFloat::rmNearestTiesToEven);
- M1.convert(APFloat::IEEEsingle, APFloat::rmNearestTiesToEven, &losesInfo);
+ M1.convert(APFloat::IEEEsingle(), APFloat::rmNearestTiesToEven, &losesInfo);
EXPECT_FALSE(losesInfo);
EXPECT_EQ(4.0f, M1.convertToFloat());
}
@@ -532,7 +534,7 @@ TEST(APFloatTest, FMA) {
TEST(APFloatTest, MinNum) {
APFloat f1(1.0);
APFloat f2(2.0);
- APFloat nan = APFloat::getNaN(APFloat::IEEEdouble);
+ APFloat nan = APFloat::getNaN(APFloat::IEEEdouble());
EXPECT_EQ(1.0, minnum(f1, f2).convertToDouble());
EXPECT_EQ(1.0, minnum(f2, f1).convertToDouble());
@@ -543,7 +545,7 @@ TEST(APFloatTest, MinNum) {
TEST(APFloatTest, MaxNum) {
APFloat f1(1.0);
APFloat f2(2.0);
- APFloat nan = APFloat::getNaN(APFloat::IEEEdouble);
+ APFloat nan = APFloat::getNaN(APFloat::IEEEdouble());
EXPECT_EQ(2.0, maxnum(f1, f2).convertToDouble());
EXPECT_EQ(2.0, maxnum(f2, f1).convertToDouble());
@@ -557,11 +559,11 @@ TEST(APFloatTest, Denormal) {
// Test single precision
{
const char *MinNormalStr = "1.17549435082228750797e-38";
- EXPECT_FALSE(APFloat(APFloat::IEEEsingle, MinNormalStr).isDenormal());
- EXPECT_FALSE(APFloat(APFloat::IEEEsingle, 0.0).isDenormal());
+ EXPECT_FALSE(APFloat(APFloat::IEEEsingle(), MinNormalStr).isDenormal());
+ EXPECT_FALSE(APFloat(APFloat::IEEEsingle(), 0.0).isDenormal());
- APFloat Val2(APFloat::IEEEsingle, 2.0e0);
- APFloat T(APFloat::IEEEsingle, MinNormalStr);
+ APFloat Val2(APFloat::IEEEsingle(), 2.0e0);
+ APFloat T(APFloat::IEEEsingle(), MinNormalStr);
T.divide(Val2, rdmd);
EXPECT_TRUE(T.isDenormal());
}
@@ -569,11 +571,11 @@ TEST(APFloatTest, Denormal) {
// Test double precision
{
const char *MinNormalStr = "2.22507385850720138309e-308";
- EXPECT_FALSE(APFloat(APFloat::IEEEdouble, MinNormalStr).isDenormal());
- EXPECT_FALSE(APFloat(APFloat::IEEEdouble, 0.0).isDenormal());
+ EXPECT_FALSE(APFloat(APFloat::IEEEdouble(), MinNormalStr).isDenormal());
+ EXPECT_FALSE(APFloat(APFloat::IEEEdouble(), 0.0).isDenormal());
- APFloat Val2(APFloat::IEEEdouble, 2.0e0);
- APFloat T(APFloat::IEEEdouble, MinNormalStr);
+ APFloat Val2(APFloat::IEEEdouble(), 2.0e0);
+ APFloat T(APFloat::IEEEdouble(), MinNormalStr);
T.divide(Val2, rdmd);
EXPECT_TRUE(T.isDenormal());
}
@@ -581,11 +583,11 @@ TEST(APFloatTest, Denormal) {
// Test Intel double-ext
{
const char *MinNormalStr = "3.36210314311209350626e-4932";
- EXPECT_FALSE(APFloat(APFloat::x87DoubleExtended, MinNormalStr).isDenormal());
- EXPECT_FALSE(APFloat(APFloat::x87DoubleExtended, 0.0).isDenormal());
+ EXPECT_FALSE(APFloat(APFloat::x87DoubleExtended(), MinNormalStr).isDenormal());
+ EXPECT_FALSE(APFloat(APFloat::x87DoubleExtended(), 0.0).isDenormal());
- APFloat Val2(APFloat::x87DoubleExtended, 2.0e0);
- APFloat T(APFloat::x87DoubleExtended, MinNormalStr);
+ APFloat Val2(APFloat::x87DoubleExtended(), 2.0e0);
+ APFloat T(APFloat::x87DoubleExtended(), MinNormalStr);
T.divide(Val2, rdmd);
EXPECT_TRUE(T.isDenormal());
}
@@ -593,11 +595,11 @@ TEST(APFloatTest, Denormal) {
// Test quadruple precision
{
const char *MinNormalStr = "3.36210314311209350626267781732175260e-4932";
- EXPECT_FALSE(APFloat(APFloat::IEEEquad, MinNormalStr).isDenormal());
- EXPECT_FALSE(APFloat(APFloat::IEEEquad, 0.0).isDenormal());
+ EXPECT_FALSE(APFloat(APFloat::IEEEquad(), MinNormalStr).isDenormal());
+ EXPECT_FALSE(APFloat(APFloat::IEEEquad(), 0.0).isDenormal());
- APFloat Val2(APFloat::IEEEquad, 2.0e0);
- APFloat T(APFloat::IEEEquad, MinNormalStr);
+ APFloat Val2(APFloat::IEEEquad(), 2.0e0);
+ APFloat T(APFloat::IEEEquad(), MinNormalStr);
T.divide(Val2, rdmd);
EXPECT_TRUE(T.isDenormal());
}
@@ -616,7 +618,7 @@ TEST(APFloatTest, Zero) {
TEST(APFloatTest, DecimalStringsWithoutNullTerminators) {
// Make sure that we can parse strings without null terminators.
// rdar://14323230.
- APFloat Val(APFloat::IEEEdouble);
+ APFloat Val(APFloat::IEEEdouble());
Val.convertFromString(StringRef("0.00", 3),
llvm::APFloat::rmNearestTiesToEven);
EXPECT_EQ(Val.convertToDouble(), 0.0);
@@ -639,292 +641,292 @@ TEST(APFloatTest, DecimalStringsWithoutNullTerminators) {
}
TEST(APFloatTest, fromZeroDecimalString) {
- EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble, "0").convertToDouble());
- EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble, "+0").convertToDouble());
- EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble, "-0").convertToDouble());
+ EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble(), "0").convertToDouble());
+ EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble(), "+0").convertToDouble());
+ EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble(), "-0").convertToDouble());
- EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble, "0.").convertToDouble());
- EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble, "+0.").convertToDouble());
- EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble, "-0.").convertToDouble());
+ EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble(), "0.").convertToDouble());
+ EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble(), "+0.").convertToDouble());
+ EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble(), "-0.").convertToDouble());
- EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble, ".0").convertToDouble());
- EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble, "+.0").convertToDouble());
- EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble, "-.0").convertToDouble());
+ EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble(), ".0").convertToDouble());
+ EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble(), "+.0").convertToDouble());
+ EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble(), "-.0").convertToDouble());
- EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble, "0.0").convertToDouble());
- EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble, "+0.0").convertToDouble());
- EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble, "-0.0").convertToDouble());
+ EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble(), "0.0").convertToDouble());
+ EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble(), "+0.0").convertToDouble());
+ EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble(), "-0.0").convertToDouble());
- EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble, "00000.").convertToDouble());
- EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble, "+00000.").convertToDouble());
- EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble, "-00000.").convertToDouble());
+ EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble(), "00000.").convertToDouble());
+ EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble(), "+00000.").convertToDouble());
+ EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble(), "-00000.").convertToDouble());
- EXPECT_EQ(0.0, APFloat(APFloat::IEEEdouble, ".00000").convertToDouble());
- EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble, "+.00000").convertToDouble());
- EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble, "-.00000").convertToDouble());
+ EXPECT_EQ(0.0, APFloat(APFloat::IEEEdouble(), ".00000").convertToDouble());
+ EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble(), "+.00000").convertToDouble());
+ EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble(), "-.00000").convertToDouble());
- EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble, "0000.00000").convertToDouble());
- EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble, "+0000.00000").convertToDouble());
- EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble, "-0000.00000").convertToDouble());
+ EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble(), "0000.00000").convertToDouble());
+ EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble(), "+0000.00000").convertToDouble());
+ EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble(), "-0000.00000").convertToDouble());
}
TEST(APFloatTest, fromZeroDecimalSingleExponentString) {
- EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble, "0e1").convertToDouble());
- EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble, "+0e1").convertToDouble());
- EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble, "-0e1").convertToDouble());
+ EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble(), "0e1").convertToDouble());
+ EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble(), "+0e1").convertToDouble());
+ EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble(), "-0e1").convertToDouble());
- EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble, "0e+1").convertToDouble());
- EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble, "+0e+1").convertToDouble());
- EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble, "-0e+1").convertToDouble());
+ EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble(), "0e+1").convertToDouble());
+ EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble(), "+0e+1").convertToDouble());
+ EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble(), "-0e+1").convertToDouble());
- EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble, "0e-1").convertToDouble());
- EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble, "+0e-1").convertToDouble());
- EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble, "-0e-1").convertToDouble());
+ EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble(), "0e-1").convertToDouble());
+ EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble(), "+0e-1").convertToDouble());
+ EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble(), "-0e-1").convertToDouble());
- EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble, "0.e1").convertToDouble());
- EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble, "+0.e1").convertToDouble());
- EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble, "-0.e1").convertToDouble());
+ EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble(), "0.e1").convertToDouble());
+ EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble(), "+0.e1").convertToDouble());
+ EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble(), "-0.e1").convertToDouble());
- EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble, "0.e+1").convertToDouble());
- EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble, "+0.e+1").convertToDouble());
- EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble, "-0.e+1").convertToDouble());
+ EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble(), "0.e+1").convertToDouble());
+ EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble(), "+0.e+1").convertToDouble());
+ EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble(), "-0.e+1").convertToDouble());
- EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble, "0.e-1").convertToDouble());
- EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble, "+0.e-1").convertToDouble());
- EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble, "-0.e-1").convertToDouble());
+ EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble(), "0.e-1").convertToDouble());
+ EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble(), "+0.e-1").convertToDouble());
+ EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble(), "-0.e-1").convertToDouble());
- EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble, ".0e1").convertToDouble());
- EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble, "+.0e1").convertToDouble());
- EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble, "-.0e1").convertToDouble());
+ EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble(), ".0e1").convertToDouble());
+ EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble(), "+.0e1").convertToDouble());
+ EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble(), "-.0e1").convertToDouble());
- EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble, ".0e+1").convertToDouble());
- EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble, "+.0e+1").convertToDouble());
- EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble, "-.0e+1").convertToDouble());
+ EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble(), ".0e+1").convertToDouble());
+ EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble(), "+.0e+1").convertToDouble());
+ EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble(), "-.0e+1").convertToDouble());
- EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble, ".0e-1").convertToDouble());
- EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble, "+.0e-1").convertToDouble());
- EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble, "-.0e-1").convertToDouble());
+ EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble(), ".0e-1").convertToDouble());
+ EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble(), "+.0e-1").convertToDouble());
+ EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble(), "-.0e-1").convertToDouble());
- EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble, "0.0e1").convertToDouble());
- EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble, "+0.0e1").convertToDouble());
- EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble, "-0.0e1").convertToDouble());
+ EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble(), "0.0e1").convertToDouble());
+ EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble(), "+0.0e1").convertToDouble());
+ EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble(), "-0.0e1").convertToDouble());
- EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble, "0.0e+1").convertToDouble());
- EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble, "+0.0e+1").convertToDouble());
- EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble, "-0.0e+1").convertToDouble());
+ EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble(), "0.0e+1").convertToDouble());
+ EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble(), "+0.0e+1").convertToDouble());
+ EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble(), "-0.0e+1").convertToDouble());
- EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble, "0.0e-1").convertToDouble());
- EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble, "+0.0e-1").convertToDouble());
- EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble, "-0.0e-1").convertToDouble());
+ EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble(), "0.0e-1").convertToDouble());
+ EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble(), "+0.0e-1").convertToDouble());
+ EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble(), "-0.0e-1").convertToDouble());
- EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble, "000.0000e1").convertToDouble());
- EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble, "+000.0000e+1").convertToDouble());
- EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble, "-000.0000e+1").convertToDouble());
+ EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble(), "000.0000e1").convertToDouble());
+ EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble(), "+000.0000e+1").convertToDouble());
+ EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble(), "-000.0000e+1").convertToDouble());
}
TEST(APFloatTest, fromZeroDecimalLargeExponentString) {
- EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble, "0e1234").convertToDouble());
- EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble, "+0e1234").convertToDouble());
- EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble, "-0e1234").convertToDouble());
+ EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble(), "0e1234").convertToDouble());
+ EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble(), "+0e1234").convertToDouble());
+ EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble(), "-0e1234").convertToDouble());
- EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble, "0e+1234").convertToDouble());
- EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble, "+0e+1234").convertToDouble());
- EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble, "-0e+1234").convertToDouble());
+ EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble(), "0e+1234").convertToDouble());
+ EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble(), "+0e+1234").convertToDouble());
+ EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble(), "-0e+1234").convertToDouble());
- EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble, "0e-1234").convertToDouble());
- EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble, "+0e-1234").convertToDouble());
- EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble, "-0e-1234").convertToDouble());
+ EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble(), "0e-1234").convertToDouble());
+ EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble(), "+0e-1234").convertToDouble());
+ EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble(), "-0e-1234").convertToDouble());
- EXPECT_EQ(0.0, APFloat(APFloat::IEEEdouble, "000.0000e1234").convertToDouble());
- EXPECT_EQ(0.0, APFloat(APFloat::IEEEdouble, "000.0000e-1234").convertToDouble());
+ EXPECT_EQ(0.0, APFloat(APFloat::IEEEdouble(), "000.0000e1234").convertToDouble());
+ EXPECT_EQ(0.0, APFloat(APFloat::IEEEdouble(), "000.0000e-1234").convertToDouble());
- EXPECT_EQ(0.0, APFloat(APFloat::IEEEdouble, StringRef("0e1234\02", 6)).convertToDouble());
+ EXPECT_EQ(0.0, APFloat(APFloat::IEEEdouble(), StringRef("0e1234\02", 6)).convertToDouble());
}
TEST(APFloatTest, fromZeroHexadecimalString) {
- EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble, "0x0p1").convertToDouble());
- EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble, "+0x0p1").convertToDouble());
- EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble, "-0x0p1").convertToDouble());
+ EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble(), "0x0p1").convertToDouble());
+ EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble(), "+0x0p1").convertToDouble());
+ EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble(), "-0x0p1").convertToDouble());
- EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble, "0x0p+1").convertToDouble());
- EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble, "+0x0p+1").convertToDouble());
- EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble, "-0x0p+1").convertToDouble());
+ EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble(), "0x0p+1").convertToDouble());
+ EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble(), "+0x0p+1").convertToDouble());
+ EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble(), "-0x0p+1").convertToDouble());
- EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble, "0x0p-1").convertToDouble());
- EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble, "+0x0p-1").convertToDouble());
- EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble, "-0x0p-1").convertToDouble());
+ EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble(), "0x0p-1").convertToDouble());
+ EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble(), "+0x0p-1").convertToDouble());
+ EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble(), "-0x0p-1").convertToDouble());
- EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble, "0x0.p1").convertToDouble());
- EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble, "+0x0.p1").convertToDouble());
- EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble, "-0x0.p1").convertToDouble());
+ EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble(), "0x0.p1").convertToDouble());
+ EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble(), "+0x0.p1").convertToDouble());
+ EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble(), "-0x0.p1").convertToDouble());
- EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble, "0x0.p+1").convertToDouble());
- EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble, "+0x0.p+1").convertToDouble());
- EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble, "-0x0.p+1").convertToDouble());
+ EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble(), "0x0.p+1").convertToDouble());
+ EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble(), "+0x0.p+1").convertToDouble());
+ EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble(), "-0x0.p+1").convertToDouble());
- EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble, "0x0.p-1").convertToDouble());
- EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble, "+0x0.p-1").convertToDouble());
- EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble, "-0x0.p-1").convertToDouble());
+ EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble(), "0x0.p-1").convertToDouble());
+ EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble(), "+0x0.p-1").convertToDouble());
+ EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble(), "-0x0.p-1").convertToDouble());
- EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble, "0x.0p1").convertToDouble());
- EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble, "+0x.0p1").convertToDouble());
- EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble, "-0x.0p1").convertToDouble());
+ EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble(), "0x.0p1").convertToDouble());
+ EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble(), "+0x.0p1").convertToDouble());
+ EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble(), "-0x.0p1").convertToDouble());
- EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble, "0x.0p+1").convertToDouble());
- EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble, "+0x.0p+1").convertToDouble());
- EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble, "-0x.0p+1").convertToDouble());
+ EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble(), "0x.0p+1").convertToDouble());
+ EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble(), "+0x.0p+1").convertToDouble());
+ EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble(), "-0x.0p+1").convertToDouble());
- EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble, "0x.0p-1").convertToDouble());
- EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble, "+0x.0p-1").convertToDouble());
- EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble, "-0x.0p-1").convertToDouble());
+ EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble(), "0x.0p-1").convertToDouble());
+ EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble(), "+0x.0p-1").convertToDouble());
+ EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble(), "-0x.0p-1").convertToDouble());
- EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble, "0x0.0p1").convertToDouble());
- EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble, "+0x0.0p1").convertToDouble());
- EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble, "-0x0.0p1").convertToDouble());
+ EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble(), "0x0.0p1").convertToDouble());
+ EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble(), "+0x0.0p1").convertToDouble());
+ EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble(), "-0x0.0p1").convertToDouble());
- EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble, "0x0.0p+1").convertToDouble());
- EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble, "+0x0.0p+1").convertToDouble());
- EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble, "-0x0.0p+1").convertToDouble());
+ EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble(), "0x0.0p+1").convertToDouble());
+ EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble(), "+0x0.0p+1").convertToDouble());
+ EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble(), "-0x0.0p+1").convertToDouble());
- EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble, "0x0.0p-1").convertToDouble());
- EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble, "+0x0.0p-1").convertToDouble());
- EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble, "-0x0.0p-1").convertToDouble());
+ EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble(), "0x0.0p-1").convertToDouble());
+ EXPECT_EQ(+0.0, APFloat(APFloat::IEEEdouble(), "+0x0.0p-1").convertToDouble());
+ EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble(), "-0x0.0p-1").convertToDouble());
- EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble, "0x00000.p1").convertToDouble());
- EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble, "0x0000.00000p1").convertToDouble());
- EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble, "0x.00000p1").convertToDouble());
- EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble, "0x0.p1").convertToDouble());
- EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble, "0x0p1234").convertToDouble());
- EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble, "-0x0p1234").convertToDouble());
- EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble, "0x00000.p1234").convertToDouble());
- EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble, "0x0000.00000p1234").convertToDouble());
- EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble, "0x.00000p1234").convertToDouble());
- EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble, "0x0.p1234").convertToDouble());
+ EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble(), "0x00000.p1").convertToDouble());
+ EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble(), "0x0000.00000p1").convertToDouble());
+ EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble(), "0x.00000p1").convertToDouble());
+ EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble(), "0x0.p1").convertToDouble());
+ EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble(), "0x0p1234").convertToDouble());
+ EXPECT_EQ(-0.0, APFloat(APFloat::IEEEdouble(), "-0x0p1234").convertToDouble());
+ EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble(), "0x00000.p1234").convertToDouble());
+ EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble(), "0x0000.00000p1234").convertToDouble());
+ EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble(), "0x.00000p1234").convertToDouble());
+ EXPECT_EQ( 0.0, APFloat(APFloat::IEEEdouble(), "0x0.p1234").convertToDouble());
}
TEST(APFloatTest, fromDecimalString) {
- EXPECT_EQ(1.0, APFloat(APFloat::IEEEdouble, "1").convertToDouble());
- EXPECT_EQ(2.0, APFloat(APFloat::IEEEdouble, "2.").convertToDouble());
- EXPECT_EQ(0.5, APFloat(APFloat::IEEEdouble, ".5").convertToDouble());
- EXPECT_EQ(1.0, APFloat(APFloat::IEEEdouble, "1.0").convertToDouble());
- EXPECT_EQ(-2.0, APFloat(APFloat::IEEEdouble, "-2").convertToDouble());
- EXPECT_EQ(-4.0, APFloat(APFloat::IEEEdouble, "-4.").convertToDouble());
- EXPECT_EQ(-0.5, APFloat(APFloat::IEEEdouble, "-.5").convertToDouble());
- EXPECT_EQ(-1.5, APFloat(APFloat::IEEEdouble, "-1.5").convertToDouble());
- EXPECT_EQ(1.25e12, APFloat(APFloat::IEEEdouble, "1.25e12").convertToDouble());
- EXPECT_EQ(1.25e+12, APFloat(APFloat::IEEEdouble, "1.25e+12").convertToDouble());
- EXPECT_EQ(1.25e-12, APFloat(APFloat::IEEEdouble, "1.25e-12").convertToDouble());
- EXPECT_EQ(1024.0, APFloat(APFloat::IEEEdouble, "1024.").convertToDouble());
- EXPECT_EQ(1024.05, APFloat(APFloat::IEEEdouble, "1024.05000").convertToDouble());
- EXPECT_EQ(0.05, APFloat(APFloat::IEEEdouble, ".05000").convertToDouble());
- EXPECT_EQ(2.0, APFloat(APFloat::IEEEdouble, "2.").convertToDouble());
- EXPECT_EQ(2.0e2, APFloat(APFloat::IEEEdouble, "2.e2").convertToDouble());
- EXPECT_EQ(2.0e+2, APFloat(APFloat::IEEEdouble, "2.e+2").convertToDouble());
- EXPECT_EQ(2.0e-2, APFloat(APFloat::IEEEdouble, "2.e-2").convertToDouble());
- EXPECT_EQ(2.05e2, APFloat(APFloat::IEEEdouble, "002.05000e2").convertToDouble());
- EXPECT_EQ(2.05e+2, APFloat(APFloat::IEEEdouble, "002.05000e+2").convertToDouble());
- EXPECT_EQ(2.05e-2, APFloat(APFloat::IEEEdouble, "002.05000e-2").convertToDouble());
- EXPECT_EQ(2.05e12, APFloat(APFloat::IEEEdouble, "002.05000e12").convertToDouble());
- EXPECT_EQ(2.05e+12, APFloat(APFloat::IEEEdouble, "002.05000e+12").convertToDouble());
- EXPECT_EQ(2.05e-12, APFloat(APFloat::IEEEdouble, "002.05000e-12").convertToDouble());
+ EXPECT_EQ(1.0, APFloat(APFloat::IEEEdouble(), "1").convertToDouble());
+ EXPECT_EQ(2.0, APFloat(APFloat::IEEEdouble(), "2.").convertToDouble());
+ EXPECT_EQ(0.5, APFloat(APFloat::IEEEdouble(), ".5").convertToDouble());
+ EXPECT_EQ(1.0, APFloat(APFloat::IEEEdouble(), "1.0").convertToDouble());
+ EXPECT_EQ(-2.0, APFloat(APFloat::IEEEdouble(), "-2").convertToDouble());
+ EXPECT_EQ(-4.0, APFloat(APFloat::IEEEdouble(), "-4.").convertToDouble());
+ EXPECT_EQ(-0.5, APFloat(APFloat::IEEEdouble(), "-.5").convertToDouble());
+ EXPECT_EQ(-1.5, APFloat(APFloat::IEEEdouble(), "-1.5").convertToDouble());
+ EXPECT_EQ(1.25e12, APFloat(APFloat::IEEEdouble(), "1.25e12").convertToDouble());
+ EXPECT_EQ(1.25e+12, APFloat(APFloat::IEEEdouble(), "1.25e+12").convertToDouble());
+ EXPECT_EQ(1.25e-12, APFloat(APFloat::IEEEdouble(), "1.25e-12").convertToDouble());
+ EXPECT_EQ(1024.0, APFloat(APFloat::IEEEdouble(), "1024.").convertToDouble());
+ EXPECT_EQ(1024.05, APFloat(APFloat::IEEEdouble(), "1024.05000").convertToDouble());
+ EXPECT_EQ(0.05, APFloat(APFloat::IEEEdouble(), ".05000").convertToDouble());
+ EXPECT_EQ(2.0, APFloat(APFloat::IEEEdouble(), "2.").convertToDouble());
+ EXPECT_EQ(2.0e2, APFloat(APFloat::IEEEdouble(), "2.e2").convertToDouble());
+ EXPECT_EQ(2.0e+2, APFloat(APFloat::IEEEdouble(), "2.e+2").convertToDouble());
+ EXPECT_EQ(2.0e-2, APFloat(APFloat::IEEEdouble(), "2.e-2").convertToDouble());
+ EXPECT_EQ(2.05e2, APFloat(APFloat::IEEEdouble(), "002.05000e2").convertToDouble());
+ EXPECT_EQ(2.05e+2, APFloat(APFloat::IEEEdouble(), "002.05000e+2").convertToDouble());
+ EXPECT_EQ(2.05e-2, APFloat(APFloat::IEEEdouble(), "002.05000e-2").convertToDouble());
+ EXPECT_EQ(2.05e12, APFloat(APFloat::IEEEdouble(), "002.05000e12").convertToDouble());
+ EXPECT_EQ(2.05e+12, APFloat(APFloat::IEEEdouble(), "002.05000e+12").convertToDouble());
+ EXPECT_EQ(2.05e-12, APFloat(APFloat::IEEEdouble(), "002.05000e-12").convertToDouble());
// These are "carefully selected" to overflow the fast log-base
// calculations in APFloat.cpp
- EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "99e99999").isInfinity());
- EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "-99e99999").isInfinity());
- EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "1e-99999").isPosZero());
- EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "-1e-99999").isNegZero());
+ EXPECT_TRUE(APFloat(APFloat::IEEEdouble(), "99e99999").isInfinity());
+ EXPECT_TRUE(APFloat(APFloat::IEEEdouble(), "-99e99999").isInfinity());
+ EXPECT_TRUE(APFloat(APFloat::IEEEdouble(), "1e-99999").isPosZero());
+ EXPECT_TRUE(APFloat(APFloat::IEEEdouble(), "-1e-99999").isNegZero());
EXPECT_EQ(2.71828, convertToDoubleFromString("2.71828"));
}
TEST(APFloatTest, fromHexadecimalString) {
- EXPECT_EQ( 1.0, APFloat(APFloat::IEEEdouble, "0x1p0").convertToDouble());
- EXPECT_EQ(+1.0, APFloat(APFloat::IEEEdouble, "+0x1p0").convertToDouble());
- EXPECT_EQ(-1.0, APFloat(APFloat::IEEEdouble, "-0x1p0").convertToDouble());
+ EXPECT_EQ( 1.0, APFloat(APFloat::IEEEdouble(), "0x1p0").convertToDouble());
+ EXPECT_EQ(+1.0, APFloat(APFloat::IEEEdouble(), "+0x1p0").convertToDouble());
+ EXPECT_EQ(-1.0, APFloat(APFloat::IEEEdouble(), "-0x1p0").convertToDouble());
- EXPECT_EQ( 1.0, APFloat(APFloat::IEEEdouble, "0x1p+0").convertToDouble());
- EXPECT_EQ(+1.0, APFloat(APFloat::IEEEdouble, "+0x1p+0").convertToDouble());
- EXPECT_EQ(-1.0, APFloat(APFloat::IEEEdouble, "-0x1p+0").convertToDouble());
+ EXPECT_EQ( 1.0, APFloat(APFloat::IEEEdouble(), "0x1p+0").convertToDouble());
+ EXPECT_EQ(+1.0, APFloat(APFloat::IEEEdouble(), "+0x1p+0").convertToDouble());
+ EXPECT_EQ(-1.0, APFloat(APFloat::IEEEdouble(), "-0x1p+0").convertToDouble());
- EXPECT_EQ( 1.0, APFloat(APFloat::IEEEdouble, "0x1p-0").convertToDouble());
- EXPECT_EQ(+1.0, APFloat(APFloat::IEEEdouble, "+0x1p-0").convertToDouble());
- EXPECT_EQ(-1.0, APFloat(APFloat::IEEEdouble, "-0x1p-0").convertToDouble());
+ EXPECT_EQ( 1.0, APFloat(APFloat::IEEEdouble(), "0x1p-0").convertToDouble());
+ EXPECT_EQ(+1.0, APFloat(APFloat::IEEEdouble(), "+0x1p-0").convertToDouble());
+ EXPECT_EQ(-1.0, APFloat(APFloat::IEEEdouble(), "-0x1p-0").convertToDouble());
- EXPECT_EQ( 2.0, APFloat(APFloat::IEEEdouble, "0x1p1").convertToDouble());
- EXPECT_EQ(+2.0, APFloat(APFloat::IEEEdouble, "+0x1p1").convertToDouble());
- EXPECT_EQ(-2.0, APFloat(APFloat::IEEEdouble, "-0x1p1").convertToDouble());
+ EXPECT_EQ( 2.0, APFloat(APFloat::IEEEdouble(), "0x1p1").convertToDouble());
+ EXPECT_EQ(+2.0, APFloat(APFloat::IEEEdouble(), "+0x1p1").convertToDouble());
+ EXPECT_EQ(-2.0, APFloat(APFloat::IEEEdouble(), "-0x1p1").convertToDouble());
- EXPECT_EQ( 2.0, APFloat(APFloat::IEEEdouble, "0x1p+1").convertToDouble());
- EXPECT_EQ(+2.0, APFloat(APFloat::IEEEdouble, "+0x1p+1").convertToDouble());
- EXPECT_EQ(-2.0, APFloat(APFloat::IEEEdouble, "-0x1p+1").convertToDouble());
+ EXPECT_EQ( 2.0, APFloat(APFloat::IEEEdouble(), "0x1p+1").convertToDouble());
+ EXPECT_EQ(+2.0, APFloat(APFloat::IEEEdouble(), "+0x1p+1").convertToDouble());
+ EXPECT_EQ(-2.0, APFloat(APFloat::IEEEdouble(), "-0x1p+1").convertToDouble());
- EXPECT_EQ( 0.5, APFloat(APFloat::IEEEdouble, "0x1p-1").convertToDouble());
- EXPECT_EQ(+0.5, APFloat(APFloat::IEEEdouble, "+0x1p-1").convertToDouble());
- EXPECT_EQ(-0.5, APFloat(APFloat::IEEEdouble, "-0x1p-1").convertToDouble());
+ EXPECT_EQ( 0.5, APFloat(APFloat::IEEEdouble(), "0x1p-1").convertToDouble());
+ EXPECT_EQ(+0.5, APFloat(APFloat::IEEEdouble(), "+0x1p-1").convertToDouble());
+ EXPECT_EQ(-0.5, APFloat(APFloat::IEEEdouble(), "-0x1p-1").convertToDouble());
- EXPECT_EQ( 3.0, APFloat(APFloat::IEEEdouble, "0x1.8p1").convertToDouble());
- EXPECT_EQ(+3.0, APFloat(APFloat::IEEEdouble, "+0x1.8p1").convertToDouble());
- EXPECT_EQ(-3.0, APFloat(APFloat::IEEEdouble, "-0x1.8p1").convertToDouble());
+ EXPECT_EQ( 3.0, APFloat(APFloat::IEEEdouble(), "0x1.8p1").convertToDouble());
+ EXPECT_EQ(+3.0, APFloat(APFloat::IEEEdouble(), "+0x1.8p1").convertToDouble());
+ EXPECT_EQ(-3.0, APFloat(APFloat::IEEEdouble(), "-0x1.8p1").convertToDouble());
- EXPECT_EQ( 3.0, APFloat(APFloat::IEEEdouble, "0x1.8p+1").convertToDouble());
- EXPECT_EQ(+3.0, APFloat(APFloat::IEEEdouble, "+0x1.8p+1").convertToDouble());
- EXPECT_EQ(-3.0, APFloat(APFloat::IEEEdouble, "-0x1.8p+1").convertToDouble());
+ EXPECT_EQ( 3.0, APFloat(APFloat::IEEEdouble(), "0x1.8p+1").convertToDouble());
+ EXPECT_EQ(+3.0, APFloat(APFloat::IEEEdouble(), "+0x1.8p+1").convertToDouble());
+ EXPECT_EQ(-3.0, APFloat(APFloat::IEEEdouble(), "-0x1.8p+1").convertToDouble());
- EXPECT_EQ( 0.75, APFloat(APFloat::IEEEdouble, "0x1.8p-1").convertToDouble());
- EXPECT_EQ(+0.75, APFloat(APFloat::IEEEdouble, "+0x1.8p-1").convertToDouble());
- EXPECT_EQ(-0.75, APFloat(APFloat::IEEEdouble, "-0x1.8p-1").convertToDouble());
+ EXPECT_EQ( 0.75, APFloat(APFloat::IEEEdouble(), "0x1.8p-1").convertToDouble());
+ EXPECT_EQ(+0.75, APFloat(APFloat::IEEEdouble(), "+0x1.8p-1").convertToDouble());
+ EXPECT_EQ(-0.75, APFloat(APFloat::IEEEdouble(), "-0x1.8p-1").convertToDouble());
- EXPECT_EQ( 8192.0, APFloat(APFloat::IEEEdouble, "0x1000.000p1").convertToDouble());
- EXPECT_EQ(+8192.0, APFloat(APFloat::IEEEdouble, "+0x1000.000p1").convertToDouble());
- EXPECT_EQ(-8192.0, APFloat(APFloat::IEEEdouble, "-0x1000.000p1").convertToDouble());
+ EXPECT_EQ( 8192.0, APFloat(APFloat::IEEEdouble(), "0x1000.000p1").convertToDouble());
+ EXPECT_EQ(+8192.0, APFloat(APFloat::IEEEdouble(), "+0x1000.000p1").convertToDouble());
+ EXPECT_EQ(-8192.0, APFloat(APFloat::IEEEdouble(), "-0x1000.000p1").convertToDouble());
- EXPECT_EQ( 8192.0, APFloat(APFloat::IEEEdouble, "0x1000.000p+1").convertToDouble());
- EXPECT_EQ(+8192.0, APFloat(APFloat::IEEEdouble, "+0x1000.000p+1").convertToDouble());
- EXPECT_EQ(-8192.0, APFloat(APFloat::IEEEdouble, "-0x1000.000p+1").convertToDouble());
+ EXPECT_EQ( 8192.0, APFloat(APFloat::IEEEdouble(), "0x1000.000p+1").convertToDouble());
+ EXPECT_EQ(+8192.0, APFloat(APFloat::IEEEdouble(), "+0x1000.000p+1").convertToDouble());
+ EXPECT_EQ(-8192.0, APFloat(APFloat::IEEEdouble(), "-0x1000.000p+1").convertToDouble());
- EXPECT_EQ( 2048.0, APFloat(APFloat::IEEEdouble, "0x1000.000p-1").convertToDouble());
- EXPECT_EQ(+2048.0, APFloat(APFloat::IEEEdouble, "+0x1000.000p-1").convertToDouble());
- EXPECT_EQ(-2048.0, APFloat(APFloat::IEEEdouble, "-0x1000.000p-1").convertToDouble());
+ EXPECT_EQ( 2048.0, APFloat(APFloat::IEEEdouble(), "0x1000.000p-1").convertToDouble());
+ EXPECT_EQ(+2048.0, APFloat(APFloat::IEEEdouble(), "+0x1000.000p-1").convertToDouble());
+ EXPECT_EQ(-2048.0, APFloat(APFloat::IEEEdouble(), "-0x1000.000p-1").convertToDouble());
- EXPECT_EQ( 8192.0, APFloat(APFloat::IEEEdouble, "0x1000p1").convertToDouble());
- EXPECT_EQ(+8192.0, APFloat(APFloat::IEEEdouble, "+0x1000p1").convertToDouble());
- EXPECT_EQ(-8192.0, APFloat(APFloat::IEEEdouble, "-0x1000p1").convertToDouble());
+ EXPECT_EQ( 8192.0, APFloat(APFloat::IEEEdouble(), "0x1000p1").convertToDouble());
+ EXPECT_EQ(+8192.0, APFloat(APFloat::IEEEdouble(), "+0x1000p1").convertToDouble());
+ EXPECT_EQ(-8192.0, APFloat(APFloat::IEEEdouble(), "-0x1000p1").convertToDouble());
- EXPECT_EQ( 8192.0, APFloat(APFloat::IEEEdouble, "0x1000p+1").convertToDouble());
- EXPECT_EQ(+8192.0, APFloat(APFloat::IEEEdouble, "+0x1000p+1").convertToDouble());
- EXPECT_EQ(-8192.0, APFloat(APFloat::IEEEdouble, "-0x1000p+1").convertToDouble());
+ EXPECT_EQ( 8192.0, APFloat(APFloat::IEEEdouble(), "0x1000p+1").convertToDouble());
+ EXPECT_EQ(+8192.0, APFloat(APFloat::IEEEdouble(), "+0x1000p+1").convertToDouble());
+ EXPECT_EQ(-8192.0, APFloat(APFloat::IEEEdouble(), "-0x1000p+1").convertToDouble());
- EXPECT_EQ( 2048.0, APFloat(APFloat::IEEEdouble, "0x1000p-1").convertToDouble());
- EXPECT_EQ(+2048.0, APFloat(APFloat::IEEEdouble, "+0x1000p-1").convertToDouble());
- EXPECT_EQ(-2048.0, APFloat(APFloat::IEEEdouble, "-0x1000p-1").convertToDouble());
+ EXPECT_EQ( 2048.0, APFloat(APFloat::IEEEdouble(), "0x1000p-1").convertToDouble());
+ EXPECT_EQ(+2048.0, APFloat(APFloat::IEEEdouble(), "+0x1000p-1").convertToDouble());
+ EXPECT_EQ(-2048.0, APFloat(APFloat::IEEEdouble(), "-0x1000p-1").convertToDouble());
- EXPECT_EQ( 16384.0, APFloat(APFloat::IEEEdouble, "0x10p10").convertToDouble());
- EXPECT_EQ(+16384.0, APFloat(APFloat::IEEEdouble, "+0x10p10").convertToDouble());
- EXPECT_EQ(-16384.0, APFloat(APFloat::IEEEdouble, "-0x10p10").convertToDouble());
+ EXPECT_EQ( 16384.0, APFloat(APFloat::IEEEdouble(), "0x10p10").convertToDouble());
+ EXPECT_EQ(+16384.0, APFloat(APFloat::IEEEdouble(), "+0x10p10").convertToDouble());
+ EXPECT_EQ(-16384.0, APFloat(APFloat::IEEEdouble(), "-0x10p10").convertToDouble());
- EXPECT_EQ( 16384.0, APFloat(APFloat::IEEEdouble, "0x10p+10").convertToDouble());
- EXPECT_EQ(+16384.0, APFloat(APFloat::IEEEdouble, "+0x10p+10").convertToDouble());
- EXPECT_EQ(-16384.0, APFloat(APFloat::IEEEdouble, "-0x10p+10").convertToDouble());
+ EXPECT_EQ( 16384.0, APFloat(APFloat::IEEEdouble(), "0x10p+10").convertToDouble());
+ EXPECT_EQ(+16384.0, APFloat(APFloat::IEEEdouble(), "+0x10p+10").convertToDouble());
+ EXPECT_EQ(-16384.0, APFloat(APFloat::IEEEdouble(), "-0x10p+10").convertToDouble());
- EXPECT_EQ( 0.015625, APFloat(APFloat::IEEEdouble, "0x10p-10").convertToDouble());
- EXPECT_EQ(+0.015625, APFloat(APFloat::IEEEdouble, "+0x10p-10").convertToDouble());
- EXPECT_EQ(-0.015625, APFloat(APFloat::IEEEdouble, "-0x10p-10").convertToDouble());
+ EXPECT_EQ( 0.015625, APFloat(APFloat::IEEEdouble(), "0x10p-10").convertToDouble());
+ EXPECT_EQ(+0.015625, APFloat(APFloat::IEEEdouble(), "+0x10p-10").convertToDouble());
+ EXPECT_EQ(-0.015625, APFloat(APFloat::IEEEdouble(), "-0x10p-10").convertToDouble());
- EXPECT_EQ(1.0625, APFloat(APFloat::IEEEdouble, "0x1.1p0").convertToDouble());
- EXPECT_EQ(1.0, APFloat(APFloat::IEEEdouble, "0x1p0").convertToDouble());
+ EXPECT_EQ(1.0625, APFloat(APFloat::IEEEdouble(), "0x1.1p0").convertToDouble());
+ EXPECT_EQ(1.0, APFloat(APFloat::IEEEdouble(), "0x1p0").convertToDouble());
EXPECT_EQ(convertToDoubleFromString("0x1p-150"),
convertToDoubleFromString("+0x800000000000000001.p-221"));
@@ -953,44 +955,44 @@ TEST(APFloatTest, toInteger) {
APSInt result(5, /*isUnsigned=*/true);
EXPECT_EQ(APFloat::opOK,
- APFloat(APFloat::IEEEdouble, "10")
+ APFloat(APFloat::IEEEdouble(), "10")
.convertToInteger(result, APFloat::rmTowardZero, &isExact));
EXPECT_TRUE(isExact);
EXPECT_EQ(APSInt(APInt(5, 10), true), result);
EXPECT_EQ(APFloat::opInvalidOp,
- APFloat(APFloat::IEEEdouble, "-10")
+ APFloat(APFloat::IEEEdouble(), "-10")
.convertToInteger(result, APFloat::rmTowardZero, &isExact));
EXPECT_FALSE(isExact);
EXPECT_EQ(APSInt::getMinValue(5, true), result);
EXPECT_EQ(APFloat::opInvalidOp,
- APFloat(APFloat::IEEEdouble, "32")
+ APFloat(APFloat::IEEEdouble(), "32")
.convertToInteger(result, APFloat::rmTowardZero, &isExact));
EXPECT_FALSE(isExact);
EXPECT_EQ(APSInt::getMaxValue(5, true), result);
EXPECT_EQ(APFloat::opInexact,
- APFloat(APFloat::IEEEdouble, "7.9")
+ APFloat(APFloat::IEEEdouble(), "7.9")
.convertToInteger(result, APFloat::rmTowardZero, &isExact));
EXPECT_FALSE(isExact);
EXPECT_EQ(APSInt(APInt(5, 7), true), result);
result.setIsUnsigned(false);
EXPECT_EQ(APFloat::opOK,
- APFloat(APFloat::IEEEdouble, "-10")
+ APFloat(APFloat::IEEEdouble(), "-10")
.convertToInteger(result, APFloat::rmTowardZero, &isExact));
EXPECT_TRUE(isExact);
EXPECT_EQ(APSInt(APInt(5, -10, true), false), result);
EXPECT_EQ(APFloat::opInvalidOp,
- APFloat(APFloat::IEEEdouble, "-17")
+ APFloat(APFloat::IEEEdouble(), "-17")
.convertToInteger(result, APFloat::rmTowardZero, &isExact));
EXPECT_FALSE(isExact);
EXPECT_EQ(APSInt::getMinValue(5, false), result);
EXPECT_EQ(APFloat::opInvalidOp,
- APFloat(APFloat::IEEEdouble, "16")
+ APFloat(APFloat::IEEEdouble(), "16")
.convertToInteger(result, APFloat::rmTowardZero, &isExact));
EXPECT_FALSE(isExact);
EXPECT_EQ(APSInt::getMaxValue(5, false), result);
@@ -1006,224 +1008,224 @@ static APInt nanbits(const fltSemantics &Sem,
}
TEST(APFloatTest, makeNaN) {
- ASSERT_EQ(0x7fc00000, nanbits(APFloat::IEEEsingle, false, false, 0));
- ASSERT_EQ(0xffc00000, nanbits(APFloat::IEEEsingle, false, true, 0));
- ASSERT_EQ(0x7fc0ae72, nanbits(APFloat::IEEEsingle, false, false, 0xae72));
- ASSERT_EQ(0x7fffae72, nanbits(APFloat::IEEEsingle, false, false, 0xffffae72));
- ASSERT_EQ(0x7fa00000, nanbits(APFloat::IEEEsingle, true, false, 0));
- ASSERT_EQ(0xffa00000, nanbits(APFloat::IEEEsingle, true, true, 0));
- ASSERT_EQ(0x7f80ae72, nanbits(APFloat::IEEEsingle, true, false, 0xae72));
- ASSERT_EQ(0x7fbfae72, nanbits(APFloat::IEEEsingle, true, false, 0xffffae72));
-
- ASSERT_EQ(0x7ff8000000000000ULL, nanbits(APFloat::IEEEdouble, false, false, 0));
- ASSERT_EQ(0xfff8000000000000ULL, nanbits(APFloat::IEEEdouble, false, true, 0));
- ASSERT_EQ(0x7ff800000000ae72ULL, nanbits(APFloat::IEEEdouble, false, false, 0xae72));
- ASSERT_EQ(0x7fffffffffffae72ULL, nanbits(APFloat::IEEEdouble, false, false, 0xffffffffffffae72ULL));
- ASSERT_EQ(0x7ff4000000000000ULL, nanbits(APFloat::IEEEdouble, true, false, 0));
- ASSERT_EQ(0xfff4000000000000ULL, nanbits(APFloat::IEEEdouble, true, true, 0));
- ASSERT_EQ(0x7ff000000000ae72ULL, nanbits(APFloat::IEEEdouble, true, false, 0xae72));
- ASSERT_EQ(0x7ff7ffffffffae72ULL, nanbits(APFloat::IEEEdouble, true, false, 0xffffffffffffae72ULL));
+ ASSERT_EQ(0x7fc00000, nanbits(APFloat::IEEEsingle(), false, false, 0));
+ ASSERT_EQ(0xffc00000, nanbits(APFloat::IEEEsingle(), false, true, 0));
+ ASSERT_EQ(0x7fc0ae72, nanbits(APFloat::IEEEsingle(), false, false, 0xae72));
+ ASSERT_EQ(0x7fffae72, nanbits(APFloat::IEEEsingle(), false, false, 0xffffae72));
+ ASSERT_EQ(0x7fa00000, nanbits(APFloat::IEEEsingle(), true, false, 0));
+ ASSERT_EQ(0xffa00000, nanbits(APFloat::IEEEsingle(), true, true, 0));
+ ASSERT_EQ(0x7f80ae72, nanbits(APFloat::IEEEsingle(), true, false, 0xae72));
+ ASSERT_EQ(0x7fbfae72, nanbits(APFloat::IEEEsingle(), true, false, 0xffffae72));
+
+ ASSERT_EQ(0x7ff8000000000000ULL, nanbits(APFloat::IEEEdouble(), false, false, 0));
+ ASSERT_EQ(0xfff8000000000000ULL, nanbits(APFloat::IEEEdouble(), false, true, 0));
+ ASSERT_EQ(0x7ff800000000ae72ULL, nanbits(APFloat::IEEEdouble(), false, false, 0xae72));
+ ASSERT_EQ(0x7fffffffffffae72ULL, nanbits(APFloat::IEEEdouble(), false, false, 0xffffffffffffae72ULL));
+ ASSERT_EQ(0x7ff4000000000000ULL, nanbits(APFloat::IEEEdouble(), true, false, 0));
+ ASSERT_EQ(0xfff4000000000000ULL, nanbits(APFloat::IEEEdouble(), true, true, 0));
+ ASSERT_EQ(0x7ff000000000ae72ULL, nanbits(APFloat::IEEEdouble(), true, false, 0xae72));
+ ASSERT_EQ(0x7ff7ffffffffae72ULL, nanbits(APFloat::IEEEdouble(), true, false, 0xffffffffffffae72ULL));
}
#ifdef GTEST_HAS_DEATH_TEST
#ifndef NDEBUG
TEST(APFloatTest, SemanticsDeath) {
- EXPECT_DEATH(APFloat(APFloat::IEEEsingle, 0.0f).convertToDouble(), "Float semantics are not IEEEdouble");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, 0.0 ).convertToFloat(), "Float semantics are not IEEEsingle");
+ EXPECT_DEATH(APFloat(APFloat::IEEEsingle(), 0.0f).convertToDouble(), "Float semantics are not IEEEdouble");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), 0.0 ).convertToFloat(), "Float semantics are not IEEEsingle");
}
TEST(APFloatTest, StringDecimalDeath) {
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, ""), "Invalid string length");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "+"), "String has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "-"), "String has no digits");
-
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, StringRef("\0", 1)), "Invalid character in significand");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, StringRef("1\0", 2)), "Invalid character in significand");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, StringRef("1\02", 3)), "Invalid character in significand");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, StringRef("1\02e1", 5)), "Invalid character in significand");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, StringRef("1e\0", 3)), "Invalid character in exponent");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, StringRef("1e1\0", 4)), "Invalid character in exponent");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, StringRef("1e1\02", 5)), "Invalid character in exponent");
-
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "1.0f"), "Invalid character in significand");
-
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, ".."), "String contains multiple dots");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "..0"), "String contains multiple dots");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "1.0.0"), "String contains multiple dots");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), ""), "Invalid string length");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+"), "String has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-"), "String has no digits");
+
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("\0", 1)), "Invalid character in significand");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("1\0", 2)), "Invalid character in significand");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("1\02", 3)), "Invalid character in significand");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("1\02e1", 5)), "Invalid character in significand");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("1e\0", 3)), "Invalid character in exponent");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("1e1\0", 4)), "Invalid character in exponent");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("1e1\02", 5)), "Invalid character in exponent");
+
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "1.0f"), "Invalid character in significand");
+
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), ".."), "String contains multiple dots");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "..0"), "String contains multiple dots");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "1.0.0"), "String contains multiple dots");
}
TEST(APFloatTest, StringDecimalSignificandDeath) {
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "."), "Significand has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "+."), "Significand has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "-."), "Significand has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "."), "Significand has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+."), "Significand has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-."), "Significand has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "e"), "Significand has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "+e"), "Significand has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "-e"), "Significand has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "e"), "Significand has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+e"), "Significand has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-e"), "Significand has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "e1"), "Significand has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "+e1"), "Significand has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "-e1"), "Significand has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "e1"), "Significand has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+e1"), "Significand has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-e1"), "Significand has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, ".e1"), "Significand has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "+.e1"), "Significand has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "-.e1"), "Significand has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), ".e1"), "Significand has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+.e1"), "Significand has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-.e1"), "Significand has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, ".e"), "Significand has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "+.e"), "Significand has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "-.e"), "Significand has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), ".e"), "Significand has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+.e"), "Significand has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-.e"), "Significand has no digits");
}
TEST(APFloatTest, StringDecimalExponentDeath) {
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "1e"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "+1e"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "-1e"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "1e"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+1e"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-1e"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "1.e"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "+1.e"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "-1.e"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "1.e"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+1.e"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-1.e"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, ".1e"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "+.1e"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "-.1e"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), ".1e"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+.1e"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-.1e"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "1.1e"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "+1.1e"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "-1.1e"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "1.1e"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+1.1e"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-1.1e"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "1e+"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "1e-"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "1e+"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "1e-"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, ".1e"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, ".1e+"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, ".1e-"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), ".1e"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), ".1e+"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), ".1e-"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "1.0e"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "1.0e+"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "1.0e-"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "1.0e"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "1.0e+"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "1.0e-"), "Exponent has no digits");
}
TEST(APFloatTest, StringHexadecimalDeath) {
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "0x"), "Invalid string");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "+0x"), "Invalid string");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "-0x"), "Invalid string");
-
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "0x0"), "Hex strings require an exponent");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "+0x0"), "Hex strings require an exponent");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "-0x0"), "Hex strings require an exponent");
-
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "0x0."), "Hex strings require an exponent");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "+0x0."), "Hex strings require an exponent");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "-0x0."), "Hex strings require an exponent");
-
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "0x.0"), "Hex strings require an exponent");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "+0x.0"), "Hex strings require an exponent");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "-0x.0"), "Hex strings require an exponent");
-
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "0x0.0"), "Hex strings require an exponent");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "+0x0.0"), "Hex strings require an exponent");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "-0x0.0"), "Hex strings require an exponent");
-
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, StringRef("0x\0", 3)), "Invalid character in significand");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, StringRef("0x1\0", 4)), "Invalid character in significand");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, StringRef("0x1\02", 5)), "Invalid character in significand");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, StringRef("0x1\02p1", 7)), "Invalid character in significand");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, StringRef("0x1p\0", 5)), "Invalid character in exponent");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, StringRef("0x1p1\0", 6)), "Invalid character in exponent");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, StringRef("0x1p1\02", 7)), "Invalid character in exponent");
-
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "0x1p0f"), "Invalid character in exponent");
-
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "0x..p1"), "String contains multiple dots");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "0x..0p1"), "String contains multiple dots");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "0x1.0.0p1"), "String contains multiple dots");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x"), "Invalid string");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0x"), "Invalid string");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0x"), "Invalid string");
+
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x0"), "Hex strings require an exponent");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0x0"), "Hex strings require an exponent");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0x0"), "Hex strings require an exponent");
+
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x0."), "Hex strings require an exponent");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0x0."), "Hex strings require an exponent");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0x0."), "Hex strings require an exponent");
+
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x.0"), "Hex strings require an exponent");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0x.0"), "Hex strings require an exponent");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0x.0"), "Hex strings require an exponent");
+
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x0.0"), "Hex strings require an exponent");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0x0.0"), "Hex strings require an exponent");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0x0.0"), "Hex strings require an exponent");
+
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("0x\0", 3)), "Invalid character in significand");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("0x1\0", 4)), "Invalid character in significand");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("0x1\02", 5)), "Invalid character in significand");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("0x1\02p1", 7)), "Invalid character in significand");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("0x1p\0", 5)), "Invalid character in exponent");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("0x1p1\0", 6)), "Invalid character in exponent");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("0x1p1\02", 7)), "Invalid character in exponent");
+
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x1p0f"), "Invalid character in exponent");
+
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x..p1"), "String contains multiple dots");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x..0p1"), "String contains multiple dots");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x1.0.0p1"), "String contains multiple dots");
}
TEST(APFloatTest, StringHexadecimalSignificandDeath) {
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "0x."), "Significand has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "+0x."), "Significand has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "-0x."), "Significand has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x."), "Significand has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0x."), "Significand has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0x."), "Significand has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "0xp"), "Significand has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "+0xp"), "Significand has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "-0xp"), "Significand has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0xp"), "Significand has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0xp"), "Significand has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0xp"), "Significand has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "0xp+"), "Significand has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "+0xp+"), "Significand has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "-0xp+"), "Significand has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0xp+"), "Significand has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0xp+"), "Significand has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0xp+"), "Significand has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "0xp-"), "Significand has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "+0xp-"), "Significand has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "-0xp-"), "Significand has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0xp-"), "Significand has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0xp-"), "Significand has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0xp-"), "Significand has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "0x.p"), "Significand has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "+0x.p"), "Significand has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "-0x.p"), "Significand has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x.p"), "Significand has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0x.p"), "Significand has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0x.p"), "Significand has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "0x.p+"), "Significand has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "+0x.p+"), "Significand has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "-0x.p+"), "Significand has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x.p+"), "Significand has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0x.p+"), "Significand has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0x.p+"), "Significand has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "0x.p-"), "Significand has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "+0x.p-"), "Significand has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "-0x.p-"), "Significand has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x.p-"), "Significand has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0x.p-"), "Significand has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0x.p-"), "Significand has no digits");
}
TEST(APFloatTest, StringHexadecimalExponentDeath) {
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "0x1p"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "+0x1p"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "-0x1p"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x1p"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0x1p"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0x1p"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "0x1p+"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "+0x1p+"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "-0x1p+"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x1p+"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0x1p+"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0x1p+"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "0x1p-"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "+0x1p-"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "-0x1p-"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x1p-"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0x1p-"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0x1p-"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "0x1.p"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "+0x1.p"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "-0x1.p"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x1.p"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0x1.p"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0x1.p"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "0x1.p+"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "+0x1.p+"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "-0x1.p+"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x1.p+"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0x1.p+"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0x1.p+"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "0x1.p-"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "+0x1.p-"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "-0x1.p-"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x1.p-"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0x1.p-"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0x1.p-"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "0x.1p"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "+0x.1p"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "-0x.1p"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x.1p"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0x.1p"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0x.1p"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "0x.1p+"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "+0x.1p+"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "-0x.1p+"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x.1p+"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0x.1p+"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0x.1p+"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "0x.1p-"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "+0x.1p-"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "-0x.1p-"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x.1p-"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0x.1p-"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0x.1p-"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "0x1.1p"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "+0x1.1p"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "-0x1.1p"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x1.1p"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0x1.1p"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0x1.1p"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "0x1.1p+"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "+0x1.1p+"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "-0x1.1p+"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x1.1p+"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0x1.1p+"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0x1.1p+"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "0x1.1p-"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "+0x1.1p-"), "Exponent has no digits");
- EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "-0x1.1p-"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x1.1p-"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0x1.1p-"), "Exponent has no digits");
+ EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0x1.1p-"), "Exponent has no digits");
}
#endif
#endif
@@ -1236,12 +1238,12 @@ TEST(APFloatTest, exactInverse) {
EXPECT_TRUE(inv.bitwiseIsEqual(APFloat(0.5)));
EXPECT_TRUE(APFloat(2.0f).getExactInverse(&inv));
EXPECT_TRUE(inv.bitwiseIsEqual(APFloat(0.5f)));
- EXPECT_TRUE(APFloat(APFloat::IEEEquad, "2.0").getExactInverse(&inv));
- EXPECT_TRUE(inv.bitwiseIsEqual(APFloat(APFloat::IEEEquad, "0.5")));
- EXPECT_TRUE(APFloat(APFloat::PPCDoubleDouble, "2.0").getExactInverse(&inv));
- EXPECT_TRUE(inv.bitwiseIsEqual(APFloat(APFloat::PPCDoubleDouble, "0.5")));
- EXPECT_TRUE(APFloat(APFloat::x87DoubleExtended, "2.0").getExactInverse(&inv));
- EXPECT_TRUE(inv.bitwiseIsEqual(APFloat(APFloat::x87DoubleExtended, "0.5")));
+ EXPECT_TRUE(APFloat(APFloat::IEEEquad(), "2.0").getExactInverse(&inv));
+ EXPECT_TRUE(inv.bitwiseIsEqual(APFloat(APFloat::IEEEquad(), "0.5")));
+ EXPECT_TRUE(APFloat(APFloat::PPCDoubleDouble(), "2.0").getExactInverse(&inv));
+ EXPECT_TRUE(inv.bitwiseIsEqual(APFloat(APFloat::PPCDoubleDouble(), "0.5")));
+ EXPECT_TRUE(APFloat(APFloat::x87DoubleExtended(), "2.0").getExactInverse(&inv));
+ EXPECT_TRUE(inv.bitwiseIsEqual(APFloat(APFloat::x87DoubleExtended(), "0.5")));
// FLT_MIN
EXPECT_TRUE(APFloat(1.17549435e-38f).getExactInverse(&inv));
@@ -1256,7 +1258,7 @@ TEST(APFloatTest, exactInverse) {
}
TEST(APFloatTest, roundToIntegral) {
- APFloat T(-0.5), S(3.14), R(APFloat::getLargest(APFloat::IEEEdouble)), P(0.0);
+ APFloat T(-0.5), S(3.14), R(APFloat::getLargest(APFloat::IEEEdouble())), P(0.0);
P = T;
P.roundToIntegral(APFloat::rmTowardZero);
@@ -1297,19 +1299,19 @@ TEST(APFloatTest, roundToIntegral) {
P.roundToIntegral(APFloat::rmNearestTiesToEven);
EXPECT_EQ(R.convertToDouble(), P.convertToDouble());
- P = APFloat::getZero(APFloat::IEEEdouble);
+ P = APFloat::getZero(APFloat::IEEEdouble());
P.roundToIntegral(APFloat::rmTowardZero);
EXPECT_EQ(0.0, P.convertToDouble());
- P = APFloat::getZero(APFloat::IEEEdouble, true);
+ P = APFloat::getZero(APFloat::IEEEdouble(), true);
P.roundToIntegral(APFloat::rmTowardZero);
EXPECT_EQ(-0.0, P.convertToDouble());
- P = APFloat::getNaN(APFloat::IEEEdouble);
+ P = APFloat::getNaN(APFloat::IEEEdouble());
P.roundToIntegral(APFloat::rmTowardZero);
EXPECT_TRUE(std::isnan(P.convertToDouble()));
- P = APFloat::getInf(APFloat::IEEEdouble);
+ P = APFloat::getInf(APFloat::IEEEdouble());
P.roundToIntegral(APFloat::rmTowardZero);
EXPECT_TRUE(std::isinf(P.convertToDouble()) && P.convertToDouble() > 0.0);
- P = APFloat::getInf(APFloat::IEEEdouble, true);
+ P = APFloat::getInf(APFloat::IEEEdouble(), true);
P.roundToIntegral(APFloat::rmTowardZero);
EXPECT_TRUE(std::isinf(P.convertToDouble()) && P.convertToDouble() < 0.0);
}
@@ -1319,45 +1321,45 @@ TEST(APFloatTest, isInteger) {
EXPECT_TRUE(T.isInteger());
T = APFloat(3.14159);
EXPECT_FALSE(T.isInteger());
- T = APFloat::getNaN(APFloat::IEEEdouble);
+ T = APFloat::getNaN(APFloat::IEEEdouble());
EXPECT_FALSE(T.isInteger());
- T = APFloat::getInf(APFloat::IEEEdouble);
+ T = APFloat::getInf(APFloat::IEEEdouble());
EXPECT_FALSE(T.isInteger());
- T = APFloat::getInf(APFloat::IEEEdouble, true);
+ T = APFloat::getInf(APFloat::IEEEdouble(), true);
EXPECT_FALSE(T.isInteger());
- T = APFloat::getLargest(APFloat::IEEEdouble);
+ T = APFloat::getLargest(APFloat::IEEEdouble());
EXPECT_TRUE(T.isInteger());
}
TEST(APFloatTest, getLargest) {
- EXPECT_EQ(3.402823466e+38f, APFloat::getLargest(APFloat::IEEEsingle).convertToFloat());
- EXPECT_EQ(1.7976931348623158e+308, APFloat::getLargest(APFloat::IEEEdouble).convertToDouble());
+ EXPECT_EQ(3.402823466e+38f, APFloat::getLargest(APFloat::IEEEsingle()).convertToFloat());
+ EXPECT_EQ(1.7976931348623158e+308, APFloat::getLargest(APFloat::IEEEdouble()).convertToDouble());
}
TEST(APFloatTest, getSmallest) {
- APFloat test = APFloat::getSmallest(APFloat::IEEEsingle, false);
- APFloat expected = APFloat(APFloat::IEEEsingle, "0x0.000002p-126");
+ APFloat test = APFloat::getSmallest(APFloat::IEEEsingle(), false);
+ APFloat expected = APFloat(APFloat::IEEEsingle(), "0x0.000002p-126");
EXPECT_FALSE(test.isNegative());
EXPECT_TRUE(test.isFiniteNonZero());
EXPECT_TRUE(test.isDenormal());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
- test = APFloat::getSmallest(APFloat::IEEEsingle, true);
- expected = APFloat(APFloat::IEEEsingle, "-0x0.000002p-126");
+ test = APFloat::getSmallest(APFloat::IEEEsingle(), true);
+ expected = APFloat(APFloat::IEEEsingle(), "-0x0.000002p-126");
EXPECT_TRUE(test.isNegative());
EXPECT_TRUE(test.isFiniteNonZero());
EXPECT_TRUE(test.isDenormal());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
- test = APFloat::getSmallest(APFloat::IEEEquad, false);
- expected = APFloat(APFloat::IEEEquad, "0x0.0000000000000000000000000001p-16382");
+ test = APFloat::getSmallest(APFloat::IEEEquad(), false);
+ expected = APFloat(APFloat::IEEEquad(), "0x0.0000000000000000000000000001p-16382");
EXPECT_FALSE(test.isNegative());
EXPECT_TRUE(test.isFiniteNonZero());
EXPECT_TRUE(test.isDenormal());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
- test = APFloat::getSmallest(APFloat::IEEEquad, true);
- expected = APFloat(APFloat::IEEEquad, "-0x0.0000000000000000000000000001p-16382");
+ test = APFloat::getSmallest(APFloat::IEEEquad(), true);
+ expected = APFloat(APFloat::IEEEquad(), "-0x0.0000000000000000000000000001p-16382");
EXPECT_TRUE(test.isNegative());
EXPECT_TRUE(test.isFiniteNonZero());
EXPECT_TRUE(test.isDenormal());
@@ -1365,29 +1367,29 @@ TEST(APFloatTest, getSmallest) {
}
TEST(APFloatTest, getSmallestNormalized) {
- APFloat test = APFloat::getSmallestNormalized(APFloat::IEEEsingle, false);
- APFloat expected = APFloat(APFloat::IEEEsingle, "0x1p-126");
+ APFloat test = APFloat::getSmallestNormalized(APFloat::IEEEsingle(), false);
+ APFloat expected = APFloat(APFloat::IEEEsingle(), "0x1p-126");
EXPECT_FALSE(test.isNegative());
EXPECT_TRUE(test.isFiniteNonZero());
EXPECT_FALSE(test.isDenormal());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
- test = APFloat::getSmallestNormalized(APFloat::IEEEsingle, true);
- expected = APFloat(APFloat::IEEEsingle, "-0x1p-126");
+ test = APFloat::getSmallestNormalized(APFloat::IEEEsingle(), true);
+ expected = APFloat(APFloat::IEEEsingle(), "-0x1p-126");
EXPECT_TRUE(test.isNegative());
EXPECT_TRUE(test.isFiniteNonZero());
EXPECT_FALSE(test.isDenormal());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
- test = APFloat::getSmallestNormalized(APFloat::IEEEquad, false);
- expected = APFloat(APFloat::IEEEquad, "0x1p-16382");
+ test = APFloat::getSmallestNormalized(APFloat::IEEEquad(), false);
+ expected = APFloat(APFloat::IEEEquad(), "0x1p-16382");
EXPECT_FALSE(test.isNegative());
EXPECT_TRUE(test.isFiniteNonZero());
EXPECT_FALSE(test.isDenormal());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
- test = APFloat::getSmallestNormalized(APFloat::IEEEquad, true);
- expected = APFloat(APFloat::IEEEquad, "-0x1p-16382");
+ test = APFloat::getSmallestNormalized(APFloat::IEEEquad(), true);
+ expected = APFloat(APFloat::IEEEquad(), "-0x1p-16382");
EXPECT_TRUE(test.isNegative());
EXPECT_TRUE(test.isFiniteNonZero());
EXPECT_FALSE(test.isDenormal());
@@ -1401,18 +1403,18 @@ TEST(APFloatTest, getZero) {
const unsigned long long bitPattern[2];
const unsigned bitPatternLength;
} const GetZeroTest[] = {
- { &APFloat::IEEEhalf, false, {0, 0}, 1},
- { &APFloat::IEEEhalf, true, {0x8000ULL, 0}, 1},
- { &APFloat::IEEEsingle, false, {0, 0}, 1},
- { &APFloat::IEEEsingle, true, {0x80000000ULL, 0}, 1},
- { &APFloat::IEEEdouble, false, {0, 0}, 1},
- { &APFloat::IEEEdouble, true, {0x8000000000000000ULL, 0}, 1},
- { &APFloat::IEEEquad, false, {0, 0}, 2},
- { &APFloat::IEEEquad, true, {0, 0x8000000000000000ULL}, 2},
- { &APFloat::PPCDoubleDouble, false, {0, 0}, 2},
- { &APFloat::PPCDoubleDouble, true, {0x8000000000000000ULL, 0}, 2},
- { &APFloat::x87DoubleExtended, false, {0, 0}, 2},
- { &APFloat::x87DoubleExtended, true, {0, 0x8000ULL}, 2},
+ { &APFloat::IEEEhalf(), false, {0, 0}, 1},
+ { &APFloat::IEEEhalf(), true, {0x8000ULL, 0}, 1},
+ { &APFloat::IEEEsingle(), false, {0, 0}, 1},
+ { &APFloat::IEEEsingle(), true, {0x80000000ULL, 0}, 1},
+ { &APFloat::IEEEdouble(), false, {0, 0}, 1},
+ { &APFloat::IEEEdouble(), true, {0x8000000000000000ULL, 0}, 1},
+ { &APFloat::IEEEquad(), false, {0, 0}, 2},
+ { &APFloat::IEEEquad(), true, {0, 0x8000000000000000ULL}, 2},
+ { &APFloat::PPCDoubleDouble(), false, {0, 0}, 2},
+ { &APFloat::PPCDoubleDouble(), true, {0x8000000000000000ULL, 0}, 2},
+ { &APFloat::x87DoubleExtended(), false, {0, 0}, 2},
+ { &APFloat::x87DoubleExtended(), true, {0, 0x8000ULL}, 2},
};
const unsigned NumGetZeroTests = 12;
for (unsigned i = 0; i < NumGetZeroTests; ++i) {
@@ -1444,177 +1446,189 @@ TEST(APFloatTest, copySign) {
TEST(APFloatTest, convert) {
bool losesInfo;
- APFloat test(APFloat::IEEEdouble, "1.0");
- test.convert(APFloat::IEEEsingle, APFloat::rmNearestTiesToEven, &losesInfo);
+ APFloat test(APFloat::IEEEdouble(), "1.0");
+ test.convert(APFloat::IEEEsingle(), APFloat::rmNearestTiesToEven, &losesInfo);
EXPECT_EQ(1.0f, test.convertToFloat());
EXPECT_FALSE(losesInfo);
- test = APFloat(APFloat::x87DoubleExtended, "0x1p-53");
- test.add(APFloat(APFloat::x87DoubleExtended, "1.0"), APFloat::rmNearestTiesToEven);
- test.convert(APFloat::IEEEdouble, APFloat::rmNearestTiesToEven, &losesInfo);
+ test = APFloat(APFloat::x87DoubleExtended(), "0x1p-53");
+ test.add(APFloat(APFloat::x87DoubleExtended(), "1.0"), APFloat::rmNearestTiesToEven);
+ test.convert(APFloat::IEEEdouble(), APFloat::rmNearestTiesToEven, &losesInfo);
EXPECT_EQ(1.0, test.convertToDouble());
EXPECT_TRUE(losesInfo);
- test = APFloat(APFloat::IEEEquad, "0x1p-53");
- test.add(APFloat(APFloat::IEEEquad, "1.0"), APFloat::rmNearestTiesToEven);
- test.convert(APFloat::IEEEdouble, APFloat::rmNearestTiesToEven, &losesInfo);
+ test = APFloat(APFloat::IEEEquad(), "0x1p-53");
+ test.add(APFloat(APFloat::IEEEquad(), "1.0"), APFloat::rmNearestTiesToEven);
+ test.convert(APFloat::IEEEdouble(), APFloat::rmNearestTiesToEven, &losesInfo);
EXPECT_EQ(1.0, test.convertToDouble());
EXPECT_TRUE(losesInfo);
- test = APFloat(APFloat::x87DoubleExtended, "0xf.fffffffp+28");
- test.convert(APFloat::IEEEdouble, APFloat::rmNearestTiesToEven, &losesInfo);
+ test = APFloat(APFloat::x87DoubleExtended(), "0xf.fffffffp+28");
+ test.convert(APFloat::IEEEdouble(), APFloat::rmNearestTiesToEven, &losesInfo);
EXPECT_EQ(4294967295.0, test.convertToDouble());
EXPECT_FALSE(losesInfo);
- test = APFloat::getSNaN(APFloat::IEEEsingle);
- APFloat X87SNaN = APFloat::getSNaN(APFloat::x87DoubleExtended);
- test.convert(APFloat::x87DoubleExtended, APFloat::rmNearestTiesToEven,
+ test = APFloat::getSNaN(APFloat::IEEEsingle());
+ APFloat X87SNaN = APFloat::getSNaN(APFloat::x87DoubleExtended());
+ test.convert(APFloat::x87DoubleExtended(), APFloat::rmNearestTiesToEven,
&losesInfo);
EXPECT_TRUE(test.bitwiseIsEqual(X87SNaN));
EXPECT_FALSE(losesInfo);
- test = APFloat::getQNaN(APFloat::IEEEsingle);
- APFloat X87QNaN = APFloat::getQNaN(APFloat::x87DoubleExtended);
- test.convert(APFloat::x87DoubleExtended, APFloat::rmNearestTiesToEven,
+ test = APFloat::getQNaN(APFloat::IEEEsingle());
+ APFloat X87QNaN = APFloat::getQNaN(APFloat::x87DoubleExtended());
+ test.convert(APFloat::x87DoubleExtended(), APFloat::rmNearestTiesToEven,
&losesInfo);
EXPECT_TRUE(test.bitwiseIsEqual(X87QNaN));
EXPECT_FALSE(losesInfo);
- test = APFloat::getSNaN(APFloat::x87DoubleExtended);
- test.convert(APFloat::x87DoubleExtended, APFloat::rmNearestTiesToEven,
+ test = APFloat::getSNaN(APFloat::x87DoubleExtended());
+ test.convert(APFloat::x87DoubleExtended(), APFloat::rmNearestTiesToEven,
&losesInfo);
EXPECT_TRUE(test.bitwiseIsEqual(X87SNaN));
EXPECT_FALSE(losesInfo);
- test = APFloat::getQNaN(APFloat::x87DoubleExtended);
- test.convert(APFloat::x87DoubleExtended, APFloat::rmNearestTiesToEven,
+ test = APFloat::getQNaN(APFloat::x87DoubleExtended());
+ test.convert(APFloat::x87DoubleExtended(), APFloat::rmNearestTiesToEven,
&losesInfo);
EXPECT_TRUE(test.bitwiseIsEqual(X87QNaN));
EXPECT_FALSE(losesInfo);
}
TEST(APFloatTest, PPCDoubleDouble) {
- APFloat test(APFloat::PPCDoubleDouble, "1.0");
+ APFloat test(APFloat::PPCDoubleDouble(), "1.0");
EXPECT_EQ(0x3ff0000000000000ull, test.bitcastToAPInt().getRawData()[0]);
EXPECT_EQ(0x0000000000000000ull, test.bitcastToAPInt().getRawData()[1]);
- test.divide(APFloat(APFloat::PPCDoubleDouble, "3.0"), APFloat::rmNearestTiesToEven);
+ test.divide(APFloat(APFloat::PPCDoubleDouble(), "3.0"), APFloat::rmNearestTiesToEven);
EXPECT_EQ(0x3fd5555555555555ull, test.bitcastToAPInt().getRawData()[0]);
EXPECT_EQ(0x3c75555555555556ull, test.bitcastToAPInt().getRawData()[1]);
// LDBL_MAX
- test = APFloat(APFloat::PPCDoubleDouble, "1.79769313486231580793728971405301e+308");
+ test = APFloat(APFloat::PPCDoubleDouble(), "1.79769313486231580793728971405301e+308");
EXPECT_EQ(0x7fefffffffffffffull, test.bitcastToAPInt().getRawData()[0]);
EXPECT_EQ(0x7c8ffffffffffffeull, test.bitcastToAPInt().getRawData()[1]);
// LDBL_MIN
- test = APFloat(APFloat::PPCDoubleDouble, "2.00416836000897277799610805135016e-292");
+ test = APFloat(APFloat::PPCDoubleDouble(), "2.00416836000897277799610805135016e-292");
EXPECT_EQ(0x0360000000000000ull, test.bitcastToAPInt().getRawData()[0]);
EXPECT_EQ(0x0000000000000000ull, test.bitcastToAPInt().getRawData()[1]);
- test = APFloat(APFloat::PPCDoubleDouble, "1.0");
- test.add(APFloat(APFloat::PPCDoubleDouble, "0x1p-105"), APFloat::rmNearestTiesToEven);
- EXPECT_EQ(0x3ff0000000000000ull, test.bitcastToAPInt().getRawData()[0]);
- EXPECT_EQ(0x3960000000000000ull, test.bitcastToAPInt().getRawData()[1]);
-
- test = APFloat(APFloat::PPCDoubleDouble, "1.0");
- test.add(APFloat(APFloat::PPCDoubleDouble, "0x1p-106"), APFloat::rmNearestTiesToEven);
- EXPECT_EQ(0x3ff0000000000000ull, test.bitcastToAPInt().getRawData()[0]);
-#if 0 // XFAIL
- // This is what we would expect with a true double-double implementation
- EXPECT_EQ(0x3950000000000000ull, test.bitcastToAPInt().getRawData()[1]);
-#else
- // This is what we get with our 106-bit mantissa approximation
- EXPECT_EQ(0x0000000000000000ull, test.bitcastToAPInt().getRawData()[1]);
-#endif
+ // PR30869
+ {
+ auto Result = APFloat(APFloat::PPCDoubleDouble(), "1.0") +
+ APFloat(APFloat::PPCDoubleDouble(), "1.0");
+ EXPECT_EQ(&APFloat::PPCDoubleDouble(), &Result.getSemantics());
+
+ Result = APFloat(APFloat::PPCDoubleDouble(), "1.0") -
+ APFloat(APFloat::PPCDoubleDouble(), "1.0");
+ EXPECT_EQ(&APFloat::PPCDoubleDouble(), &Result.getSemantics());
+
+ Result = APFloat(APFloat::PPCDoubleDouble(), "1.0") *
+ APFloat(APFloat::PPCDoubleDouble(), "1.0");
+ EXPECT_EQ(&APFloat::PPCDoubleDouble(), &Result.getSemantics());
+
+ Result = APFloat(APFloat::PPCDoubleDouble(), "1.0") /
+ APFloat(APFloat::PPCDoubleDouble(), "1.0");
+ EXPECT_EQ(&APFloat::PPCDoubleDouble(), &Result.getSemantics());
+
+ int Exp;
+ Result = frexp(APFloat(APFloat::PPCDoubleDouble(), "1.0"), Exp,
+ APFloat::rmNearestTiesToEven);
+ EXPECT_EQ(&APFloat::PPCDoubleDouble(), &Result.getSemantics());
+
+ Result = scalbn(APFloat(APFloat::PPCDoubleDouble(), "1.0"), 1,
+ APFloat::rmNearestTiesToEven);
+ EXPECT_EQ(&APFloat::PPCDoubleDouble(), &Result.getSemantics());
+ }
}
TEST(APFloatTest, isNegative) {
- APFloat t(APFloat::IEEEsingle, "0x1p+0");
+ APFloat t(APFloat::IEEEsingle(), "0x1p+0");
EXPECT_FALSE(t.isNegative());
- t = APFloat(APFloat::IEEEsingle, "-0x1p+0");
+ t = APFloat(APFloat::IEEEsingle(), "-0x1p+0");
EXPECT_TRUE(t.isNegative());
- EXPECT_FALSE(APFloat::getInf(APFloat::IEEEsingle, false).isNegative());
- EXPECT_TRUE(APFloat::getInf(APFloat::IEEEsingle, true).isNegative());
+ EXPECT_FALSE(APFloat::getInf(APFloat::IEEEsingle(), false).isNegative());
+ EXPECT_TRUE(APFloat::getInf(APFloat::IEEEsingle(), true).isNegative());
- EXPECT_FALSE(APFloat::getZero(APFloat::IEEEsingle, false).isNegative());
- EXPECT_TRUE(APFloat::getZero(APFloat::IEEEsingle, true).isNegative());
+ EXPECT_FALSE(APFloat::getZero(APFloat::IEEEsingle(), false).isNegative());
+ EXPECT_TRUE(APFloat::getZero(APFloat::IEEEsingle(), true).isNegative());
- EXPECT_FALSE(APFloat::getNaN(APFloat::IEEEsingle, false).isNegative());
- EXPECT_TRUE(APFloat::getNaN(APFloat::IEEEsingle, true).isNegative());
+ EXPECT_FALSE(APFloat::getNaN(APFloat::IEEEsingle(), false).isNegative());
+ EXPECT_TRUE(APFloat::getNaN(APFloat::IEEEsingle(), true).isNegative());
- EXPECT_FALSE(APFloat::getSNaN(APFloat::IEEEsingle, false).isNegative());
- EXPECT_TRUE(APFloat::getSNaN(APFloat::IEEEsingle, true).isNegative());
+ EXPECT_FALSE(APFloat::getSNaN(APFloat::IEEEsingle(), false).isNegative());
+ EXPECT_TRUE(APFloat::getSNaN(APFloat::IEEEsingle(), true).isNegative());
}
TEST(APFloatTest, isNormal) {
- APFloat t(APFloat::IEEEsingle, "0x1p+0");
+ APFloat t(APFloat::IEEEsingle(), "0x1p+0");
EXPECT_TRUE(t.isNormal());
- EXPECT_FALSE(APFloat::getInf(APFloat::IEEEsingle, false).isNormal());
- EXPECT_FALSE(APFloat::getZero(APFloat::IEEEsingle, false).isNormal());
- EXPECT_FALSE(APFloat::getNaN(APFloat::IEEEsingle, false).isNormal());
- EXPECT_FALSE(APFloat::getSNaN(APFloat::IEEEsingle, false).isNormal());
- EXPECT_FALSE(APFloat(APFloat::IEEEsingle, "0x1p-149").isNormal());
+ EXPECT_FALSE(APFloat::getInf(APFloat::IEEEsingle(), false).isNormal());
+ EXPECT_FALSE(APFloat::getZero(APFloat::IEEEsingle(), false).isNormal());
+ EXPECT_FALSE(APFloat::getNaN(APFloat::IEEEsingle(), false).isNormal());
+ EXPECT_FALSE(APFloat::getSNaN(APFloat::IEEEsingle(), false).isNormal());
+ EXPECT_FALSE(APFloat(APFloat::IEEEsingle(), "0x1p-149").isNormal());
}
TEST(APFloatTest, isFinite) {
- APFloat t(APFloat::IEEEsingle, "0x1p+0");
+ APFloat t(APFloat::IEEEsingle(), "0x1p+0");
EXPECT_TRUE(t.isFinite());
- EXPECT_FALSE(APFloat::getInf(APFloat::IEEEsingle, false).isFinite());
- EXPECT_TRUE(APFloat::getZero(APFloat::IEEEsingle, false).isFinite());
- EXPECT_FALSE(APFloat::getNaN(APFloat::IEEEsingle, false).isFinite());
- EXPECT_FALSE(APFloat::getSNaN(APFloat::IEEEsingle, false).isFinite());
- EXPECT_TRUE(APFloat(APFloat::IEEEsingle, "0x1p-149").isFinite());
+ EXPECT_FALSE(APFloat::getInf(APFloat::IEEEsingle(), false).isFinite());
+ EXPECT_TRUE(APFloat::getZero(APFloat::IEEEsingle(), false).isFinite());
+ EXPECT_FALSE(APFloat::getNaN(APFloat::IEEEsingle(), false).isFinite());
+ EXPECT_FALSE(APFloat::getSNaN(APFloat::IEEEsingle(), false).isFinite());
+ EXPECT_TRUE(APFloat(APFloat::IEEEsingle(), "0x1p-149").isFinite());
}
TEST(APFloatTest, isInfinity) {
- APFloat t(APFloat::IEEEsingle, "0x1p+0");
+ APFloat t(APFloat::IEEEsingle(), "0x1p+0");
EXPECT_FALSE(t.isInfinity());
- EXPECT_TRUE(APFloat::getInf(APFloat::IEEEsingle, false).isInfinity());
- EXPECT_FALSE(APFloat::getZero(APFloat::IEEEsingle, false).isInfinity());
- EXPECT_FALSE(APFloat::getNaN(APFloat::IEEEsingle, false).isInfinity());
- EXPECT_FALSE(APFloat::getSNaN(APFloat::IEEEsingle, false).isInfinity());
- EXPECT_FALSE(APFloat(APFloat::IEEEsingle, "0x1p-149").isInfinity());
+ EXPECT_TRUE(APFloat::getInf(APFloat::IEEEsingle(), false).isInfinity());
+ EXPECT_FALSE(APFloat::getZero(APFloat::IEEEsingle(), false).isInfinity());
+ EXPECT_FALSE(APFloat::getNaN(APFloat::IEEEsingle(), false).isInfinity());
+ EXPECT_FALSE(APFloat::getSNaN(APFloat::IEEEsingle(), false).isInfinity());
+ EXPECT_FALSE(APFloat(APFloat::IEEEsingle(), "0x1p-149").isInfinity());
}
TEST(APFloatTest, isNaN) {
- APFloat t(APFloat::IEEEsingle, "0x1p+0");
+ APFloat t(APFloat::IEEEsingle(), "0x1p+0");
EXPECT_FALSE(t.isNaN());
- EXPECT_FALSE(APFloat::getInf(APFloat::IEEEsingle, false).isNaN());
- EXPECT_FALSE(APFloat::getZero(APFloat::IEEEsingle, false).isNaN());
- EXPECT_TRUE(APFloat::getNaN(APFloat::IEEEsingle, false).isNaN());
- EXPECT_TRUE(APFloat::getSNaN(APFloat::IEEEsingle, false).isNaN());
- EXPECT_FALSE(APFloat(APFloat::IEEEsingle, "0x1p-149").isNaN());
+ EXPECT_FALSE(APFloat::getInf(APFloat::IEEEsingle(), false).isNaN());
+ EXPECT_FALSE(APFloat::getZero(APFloat::IEEEsingle(), false).isNaN());
+ EXPECT_TRUE(APFloat::getNaN(APFloat::IEEEsingle(), false).isNaN());
+ EXPECT_TRUE(APFloat::getSNaN(APFloat::IEEEsingle(), false).isNaN());
+ EXPECT_FALSE(APFloat(APFloat::IEEEsingle(), "0x1p-149").isNaN());
}
TEST(APFloatTest, isFiniteNonZero) {
// Test positive/negative normal value.
- EXPECT_TRUE(APFloat(APFloat::IEEEsingle, "0x1p+0").isFiniteNonZero());
- EXPECT_TRUE(APFloat(APFloat::IEEEsingle, "-0x1p+0").isFiniteNonZero());
+ EXPECT_TRUE(APFloat(APFloat::IEEEsingle(), "0x1p+0").isFiniteNonZero());
+ EXPECT_TRUE(APFloat(APFloat::IEEEsingle(), "-0x1p+0").isFiniteNonZero());
// Test positive/negative denormal value.
- EXPECT_TRUE(APFloat(APFloat::IEEEsingle, "0x1p-149").isFiniteNonZero());
- EXPECT_TRUE(APFloat(APFloat::IEEEsingle, "-0x1p-149").isFiniteNonZero());
+ EXPECT_TRUE(APFloat(APFloat::IEEEsingle(), "0x1p-149").isFiniteNonZero());
+ EXPECT_TRUE(APFloat(APFloat::IEEEsingle(), "-0x1p-149").isFiniteNonZero());
// Test +/- Infinity.
- EXPECT_FALSE(APFloat::getInf(APFloat::IEEEsingle, false).isFiniteNonZero());
- EXPECT_FALSE(APFloat::getInf(APFloat::IEEEsingle, true).isFiniteNonZero());
+ EXPECT_FALSE(APFloat::getInf(APFloat::IEEEsingle(), false).isFiniteNonZero());
+ EXPECT_FALSE(APFloat::getInf(APFloat::IEEEsingle(), true).isFiniteNonZero());
// Test +/- Zero.
- EXPECT_FALSE(APFloat::getZero(APFloat::IEEEsingle, false).isFiniteNonZero());
- EXPECT_FALSE(APFloat::getZero(APFloat::IEEEsingle, true).isFiniteNonZero());
+ EXPECT_FALSE(APFloat::getZero(APFloat::IEEEsingle(), false).isFiniteNonZero());
+ EXPECT_FALSE(APFloat::getZero(APFloat::IEEEsingle(), true).isFiniteNonZero());
// Test +/- qNaN. +/- dont mean anything with qNaN but paranoia can't hurt in
// this instance.
- EXPECT_FALSE(APFloat::getNaN(APFloat::IEEEsingle, false).isFiniteNonZero());
- EXPECT_FALSE(APFloat::getNaN(APFloat::IEEEsingle, true).isFiniteNonZero());
+ EXPECT_FALSE(APFloat::getNaN(APFloat::IEEEsingle(), false).isFiniteNonZero());
+ EXPECT_FALSE(APFloat::getNaN(APFloat::IEEEsingle(), true).isFiniteNonZero());
// Test +/- sNaN. +/- dont mean anything with sNaN but paranoia can't hurt in
// this instance.
- EXPECT_FALSE(APFloat::getSNaN(APFloat::IEEEsingle, false).isFiniteNonZero());
- EXPECT_FALSE(APFloat::getSNaN(APFloat::IEEEsingle, true).isFiniteNonZero());
+ EXPECT_FALSE(APFloat::getSNaN(APFloat::IEEEsingle(), false).isFiniteNonZero());
+ EXPECT_FALSE(APFloat::getSNaN(APFloat::IEEEsingle(), true).isFiniteNonZero());
}
TEST(APFloatTest, add) {
@@ -1625,22 +1639,22 @@ TEST(APFloatTest, add) {
// signaling NaNs should have a result that is a quiet NaN. Currently they
// return sNaN.
- APFloat PInf = APFloat::getInf(APFloat::IEEEsingle, false);
- APFloat MInf = APFloat::getInf(APFloat::IEEEsingle, true);
- APFloat PZero = APFloat::getZero(APFloat::IEEEsingle, false);
- APFloat MZero = APFloat::getZero(APFloat::IEEEsingle, true);
- APFloat QNaN = APFloat::getNaN(APFloat::IEEEsingle, false);
- APFloat SNaN = APFloat::getSNaN(APFloat::IEEEsingle, false);
- APFloat PNormalValue = APFloat(APFloat::IEEEsingle, "0x1p+0");
- APFloat MNormalValue = APFloat(APFloat::IEEEsingle, "-0x1p+0");
- APFloat PLargestValue = APFloat::getLargest(APFloat::IEEEsingle, false);
- APFloat MLargestValue = APFloat::getLargest(APFloat::IEEEsingle, true);
- APFloat PSmallestValue = APFloat::getSmallest(APFloat::IEEEsingle, false);
- APFloat MSmallestValue = APFloat::getSmallest(APFloat::IEEEsingle, true);
+ APFloat PInf = APFloat::getInf(APFloat::IEEEsingle(), false);
+ APFloat MInf = APFloat::getInf(APFloat::IEEEsingle(), true);
+ APFloat PZero = APFloat::getZero(APFloat::IEEEsingle(), false);
+ APFloat MZero = APFloat::getZero(APFloat::IEEEsingle(), true);
+ APFloat QNaN = APFloat::getNaN(APFloat::IEEEsingle(), false);
+ APFloat SNaN = APFloat::getSNaN(APFloat::IEEEsingle(), false);
+ APFloat PNormalValue = APFloat(APFloat::IEEEsingle(), "0x1p+0");
+ APFloat MNormalValue = APFloat(APFloat::IEEEsingle(), "-0x1p+0");
+ APFloat PLargestValue = APFloat::getLargest(APFloat::IEEEsingle(), false);
+ APFloat MLargestValue = APFloat::getLargest(APFloat::IEEEsingle(), true);
+ APFloat PSmallestValue = APFloat::getSmallest(APFloat::IEEEsingle(), false);
+ APFloat MSmallestValue = APFloat::getSmallest(APFloat::IEEEsingle(), true);
APFloat PSmallestNormalized =
- APFloat::getSmallestNormalized(APFloat::IEEEsingle, false);
+ APFloat::getSmallestNormalized(APFloat::IEEEsingle(), false);
APFloat MSmallestNormalized =
- APFloat::getSmallestNormalized(APFloat::IEEEsingle, true);
+ APFloat::getSmallestNormalized(APFloat::IEEEsingle(), true);
const int OverflowStatus = APFloat::opOverflow | APFloat::opInexact;
@@ -1897,7 +1911,7 @@ TEST(APFloatTest, add) {
APFloat y(SpecialCaseTests[i].y);
APFloat::opStatus status = x.add(y, APFloat::rmNearestTiesToEven);
- APFloat result(APFloat::IEEEsingle, SpecialCaseTests[i].result);
+ APFloat result(APFloat::IEEEsingle(), SpecialCaseTests[i].result);
EXPECT_TRUE(result.bitwiseIsEqual(x));
EXPECT_TRUE((int)status == SpecialCaseTests[i].status);
@@ -1913,22 +1927,22 @@ TEST(APFloatTest, subtract) {
// signaling NaNs should have a result that is a quiet NaN. Currently they
// return sNaN.
- APFloat PInf = APFloat::getInf(APFloat::IEEEsingle, false);
- APFloat MInf = APFloat::getInf(APFloat::IEEEsingle, true);
- APFloat PZero = APFloat::getZero(APFloat::IEEEsingle, false);
- APFloat MZero = APFloat::getZero(APFloat::IEEEsingle, true);
- APFloat QNaN = APFloat::getNaN(APFloat::IEEEsingle, false);
- APFloat SNaN = APFloat::getSNaN(APFloat::IEEEsingle, false);
- APFloat PNormalValue = APFloat(APFloat::IEEEsingle, "0x1p+0");
- APFloat MNormalValue = APFloat(APFloat::IEEEsingle, "-0x1p+0");
- APFloat PLargestValue = APFloat::getLargest(APFloat::IEEEsingle, false);
- APFloat MLargestValue = APFloat::getLargest(APFloat::IEEEsingle, true);
- APFloat PSmallestValue = APFloat::getSmallest(APFloat::IEEEsingle, false);
- APFloat MSmallestValue = APFloat::getSmallest(APFloat::IEEEsingle, true);
+ APFloat PInf = APFloat::getInf(APFloat::IEEEsingle(), false);
+ APFloat MInf = APFloat::getInf(APFloat::IEEEsingle(), true);
+ APFloat PZero = APFloat::getZero(APFloat::IEEEsingle(), false);
+ APFloat MZero = APFloat::getZero(APFloat::IEEEsingle(), true);
+ APFloat QNaN = APFloat::getNaN(APFloat::IEEEsingle(), false);
+ APFloat SNaN = APFloat::getSNaN(APFloat::IEEEsingle(), false);
+ APFloat PNormalValue = APFloat(APFloat::IEEEsingle(), "0x1p+0");
+ APFloat MNormalValue = APFloat(APFloat::IEEEsingle(), "-0x1p+0");
+ APFloat PLargestValue = APFloat::getLargest(APFloat::IEEEsingle(), false);
+ APFloat MLargestValue = APFloat::getLargest(APFloat::IEEEsingle(), true);
+ APFloat PSmallestValue = APFloat::getSmallest(APFloat::IEEEsingle(), false);
+ APFloat MSmallestValue = APFloat::getSmallest(APFloat::IEEEsingle(), true);
APFloat PSmallestNormalized =
- APFloat::getSmallestNormalized(APFloat::IEEEsingle, false);
+ APFloat::getSmallestNormalized(APFloat::IEEEsingle(), false);
APFloat MSmallestNormalized =
- APFloat::getSmallestNormalized(APFloat::IEEEsingle, true);
+ APFloat::getSmallestNormalized(APFloat::IEEEsingle(), true);
const int OverflowStatus = APFloat::opOverflow | APFloat::opInexact;
@@ -2185,7 +2199,7 @@ TEST(APFloatTest, subtract) {
APFloat y(SpecialCaseTests[i].y);
APFloat::opStatus status = x.subtract(y, APFloat::rmNearestTiesToEven);
- APFloat result(APFloat::IEEEsingle, SpecialCaseTests[i].result);
+ APFloat result(APFloat::IEEEsingle(), SpecialCaseTests[i].result);
EXPECT_TRUE(result.bitwiseIsEqual(x));
EXPECT_TRUE((int)status == SpecialCaseTests[i].status);
@@ -2201,22 +2215,22 @@ TEST(APFloatTest, multiply) {
// signaling NaNs should have a result that is a quiet NaN. Currently they
// return sNaN.
- APFloat PInf = APFloat::getInf(APFloat::IEEEsingle, false);
- APFloat MInf = APFloat::getInf(APFloat::IEEEsingle, true);
- APFloat PZero = APFloat::getZero(APFloat::IEEEsingle, false);
- APFloat MZero = APFloat::getZero(APFloat::IEEEsingle, true);
- APFloat QNaN = APFloat::getNaN(APFloat::IEEEsingle, false);
- APFloat SNaN = APFloat::getSNaN(APFloat::IEEEsingle, false);
- APFloat PNormalValue = APFloat(APFloat::IEEEsingle, "0x1p+0");
- APFloat MNormalValue = APFloat(APFloat::IEEEsingle, "-0x1p+0");
- APFloat PLargestValue = APFloat::getLargest(APFloat::IEEEsingle, false);
- APFloat MLargestValue = APFloat::getLargest(APFloat::IEEEsingle, true);
- APFloat PSmallestValue = APFloat::getSmallest(APFloat::IEEEsingle, false);
- APFloat MSmallestValue = APFloat::getSmallest(APFloat::IEEEsingle, true);
+ APFloat PInf = APFloat::getInf(APFloat::IEEEsingle(), false);
+ APFloat MInf = APFloat::getInf(APFloat::IEEEsingle(), true);
+ APFloat PZero = APFloat::getZero(APFloat::IEEEsingle(), false);
+ APFloat MZero = APFloat::getZero(APFloat::IEEEsingle(), true);
+ APFloat QNaN = APFloat::getNaN(APFloat::IEEEsingle(), false);
+ APFloat SNaN = APFloat::getSNaN(APFloat::IEEEsingle(), false);
+ APFloat PNormalValue = APFloat(APFloat::IEEEsingle(), "0x1p+0");
+ APFloat MNormalValue = APFloat(APFloat::IEEEsingle(), "-0x1p+0");
+ APFloat PLargestValue = APFloat::getLargest(APFloat::IEEEsingle(), false);
+ APFloat MLargestValue = APFloat::getLargest(APFloat::IEEEsingle(), true);
+ APFloat PSmallestValue = APFloat::getSmallest(APFloat::IEEEsingle(), false);
+ APFloat MSmallestValue = APFloat::getSmallest(APFloat::IEEEsingle(), true);
APFloat PSmallestNormalized =
- APFloat::getSmallestNormalized(APFloat::IEEEsingle, false);
+ APFloat::getSmallestNormalized(APFloat::IEEEsingle(), false);
APFloat MSmallestNormalized =
- APFloat::getSmallestNormalized(APFloat::IEEEsingle, true);
+ APFloat::getSmallestNormalized(APFloat::IEEEsingle(), true);
const int OverflowStatus = APFloat::opOverflow | APFloat::opInexact;
const int UnderflowStatus = APFloat::opUnderflow | APFloat::opInexact;
@@ -2474,7 +2488,7 @@ TEST(APFloatTest, multiply) {
APFloat y(SpecialCaseTests[i].y);
APFloat::opStatus status = x.multiply(y, APFloat::rmNearestTiesToEven);
- APFloat result(APFloat::IEEEsingle, SpecialCaseTests[i].result);
+ APFloat result(APFloat::IEEEsingle(), SpecialCaseTests[i].result);
EXPECT_TRUE(result.bitwiseIsEqual(x));
EXPECT_TRUE((int)status == SpecialCaseTests[i].status);
@@ -2490,22 +2504,22 @@ TEST(APFloatTest, divide) {
// signaling NaNs should have a result that is a quiet NaN. Currently they
// return sNaN.
- APFloat PInf = APFloat::getInf(APFloat::IEEEsingle, false);
- APFloat MInf = APFloat::getInf(APFloat::IEEEsingle, true);
- APFloat PZero = APFloat::getZero(APFloat::IEEEsingle, false);
- APFloat MZero = APFloat::getZero(APFloat::IEEEsingle, true);
- APFloat QNaN = APFloat::getNaN(APFloat::IEEEsingle, false);
- APFloat SNaN = APFloat::getSNaN(APFloat::IEEEsingle, false);
- APFloat PNormalValue = APFloat(APFloat::IEEEsingle, "0x1p+0");
- APFloat MNormalValue = APFloat(APFloat::IEEEsingle, "-0x1p+0");
- APFloat PLargestValue = APFloat::getLargest(APFloat::IEEEsingle, false);
- APFloat MLargestValue = APFloat::getLargest(APFloat::IEEEsingle, true);
- APFloat PSmallestValue = APFloat::getSmallest(APFloat::IEEEsingle, false);
- APFloat MSmallestValue = APFloat::getSmallest(APFloat::IEEEsingle, true);
+ APFloat PInf = APFloat::getInf(APFloat::IEEEsingle(), false);
+ APFloat MInf = APFloat::getInf(APFloat::IEEEsingle(), true);
+ APFloat PZero = APFloat::getZero(APFloat::IEEEsingle(), false);
+ APFloat MZero = APFloat::getZero(APFloat::IEEEsingle(), true);
+ APFloat QNaN = APFloat::getNaN(APFloat::IEEEsingle(), false);
+ APFloat SNaN = APFloat::getSNaN(APFloat::IEEEsingle(), false);
+ APFloat PNormalValue = APFloat(APFloat::IEEEsingle(), "0x1p+0");
+ APFloat MNormalValue = APFloat(APFloat::IEEEsingle(), "-0x1p+0");
+ APFloat PLargestValue = APFloat::getLargest(APFloat::IEEEsingle(), false);
+ APFloat MLargestValue = APFloat::getLargest(APFloat::IEEEsingle(), true);
+ APFloat PSmallestValue = APFloat::getSmallest(APFloat::IEEEsingle(), false);
+ APFloat MSmallestValue = APFloat::getSmallest(APFloat::IEEEsingle(), true);
APFloat PSmallestNormalized =
- APFloat::getSmallestNormalized(APFloat::IEEEsingle, false);
+ APFloat::getSmallestNormalized(APFloat::IEEEsingle(), false);
APFloat MSmallestNormalized =
- APFloat::getSmallestNormalized(APFloat::IEEEsingle, true);
+ APFloat::getSmallestNormalized(APFloat::IEEEsingle(), true);
const int OverflowStatus = APFloat::opOverflow | APFloat::opInexact;
const int UnderflowStatus = APFloat::opUnderflow | APFloat::opInexact;
@@ -2763,7 +2777,7 @@ TEST(APFloatTest, divide) {
APFloat y(SpecialCaseTests[i].y);
APFloat::opStatus status = x.divide(y, APFloat::rmNearestTiesToEven);
- APFloat result(APFloat::IEEEsingle, SpecialCaseTests[i].result);
+ APFloat result(APFloat::IEEEsingle(), SpecialCaseTests[i].result);
EXPECT_TRUE(result.bitwiseIsEqual(x));
EXPECT_TRUE((int)status == SpecialCaseTests[i].status);
@@ -2773,8 +2787,8 @@ TEST(APFloatTest, divide) {
TEST(APFloatTest, operatorOverloads) {
// This is mostly testing that these operator overloads compile.
- APFloat One = APFloat(APFloat::IEEEsingle, "0x1p+0");
- APFloat Two = APFloat(APFloat::IEEEsingle, "0x2p+0");
+ APFloat One = APFloat(APFloat::IEEEsingle(), "0x1p+0");
+ APFloat Two = APFloat(APFloat::IEEEsingle(), "0x2p+0");
EXPECT_TRUE(Two.bitwiseIsEqual(One + One));
EXPECT_TRUE(One.bitwiseIsEqual(Two - One));
EXPECT_TRUE(Two.bitwiseIsEqual(One * Two));
@@ -2782,24 +2796,24 @@ TEST(APFloatTest, operatorOverloads) {
}
TEST(APFloatTest, abs) {
- APFloat PInf = APFloat::getInf(APFloat::IEEEsingle, false);
- APFloat MInf = APFloat::getInf(APFloat::IEEEsingle, true);
- APFloat PZero = APFloat::getZero(APFloat::IEEEsingle, false);
- APFloat MZero = APFloat::getZero(APFloat::IEEEsingle, true);
- APFloat PQNaN = APFloat::getNaN(APFloat::IEEEsingle, false);
- APFloat MQNaN = APFloat::getNaN(APFloat::IEEEsingle, true);
- APFloat PSNaN = APFloat::getSNaN(APFloat::IEEEsingle, false);
- APFloat MSNaN = APFloat::getSNaN(APFloat::IEEEsingle, true);
- APFloat PNormalValue = APFloat(APFloat::IEEEsingle, "0x1p+0");
- APFloat MNormalValue = APFloat(APFloat::IEEEsingle, "-0x1p+0");
- APFloat PLargestValue = APFloat::getLargest(APFloat::IEEEsingle, false);
- APFloat MLargestValue = APFloat::getLargest(APFloat::IEEEsingle, true);
- APFloat PSmallestValue = APFloat::getSmallest(APFloat::IEEEsingle, false);
- APFloat MSmallestValue = APFloat::getSmallest(APFloat::IEEEsingle, true);
+ APFloat PInf = APFloat::getInf(APFloat::IEEEsingle(), false);
+ APFloat MInf = APFloat::getInf(APFloat::IEEEsingle(), true);
+ APFloat PZero = APFloat::getZero(APFloat::IEEEsingle(), false);
+ APFloat MZero = APFloat::getZero(APFloat::IEEEsingle(), true);
+ APFloat PQNaN = APFloat::getNaN(APFloat::IEEEsingle(), false);
+ APFloat MQNaN = APFloat::getNaN(APFloat::IEEEsingle(), true);
+ APFloat PSNaN = APFloat::getSNaN(APFloat::IEEEsingle(), false);
+ APFloat MSNaN = APFloat::getSNaN(APFloat::IEEEsingle(), true);
+ APFloat PNormalValue = APFloat(APFloat::IEEEsingle(), "0x1p+0");
+ APFloat MNormalValue = APFloat(APFloat::IEEEsingle(), "-0x1p+0");
+ APFloat PLargestValue = APFloat::getLargest(APFloat::IEEEsingle(), false);
+ APFloat MLargestValue = APFloat::getLargest(APFloat::IEEEsingle(), true);
+ APFloat PSmallestValue = APFloat::getSmallest(APFloat::IEEEsingle(), false);
+ APFloat MSmallestValue = APFloat::getSmallest(APFloat::IEEEsingle(), true);
APFloat PSmallestNormalized =
- APFloat::getSmallestNormalized(APFloat::IEEEsingle, false);
+ APFloat::getSmallestNormalized(APFloat::IEEEsingle(), false);
APFloat MSmallestNormalized =
- APFloat::getSmallestNormalized(APFloat::IEEEsingle, true);
+ APFloat::getSmallestNormalized(APFloat::IEEEsingle(), true);
EXPECT_TRUE(PInf.bitwiseIsEqual(abs(PInf)));
EXPECT_TRUE(PInf.bitwiseIsEqual(abs(MInf)));
@@ -2820,68 +2834,68 @@ TEST(APFloatTest, abs) {
}
TEST(APFloatTest, ilogb) {
- EXPECT_EQ(-1074, ilogb(APFloat::getSmallest(APFloat::IEEEdouble, false)));
- EXPECT_EQ(-1074, ilogb(APFloat::getSmallest(APFloat::IEEEdouble, true)));
- EXPECT_EQ(-1023, ilogb(APFloat(APFloat::IEEEdouble, "0x1.ffffffffffffep-1024")));
- EXPECT_EQ(-1023, ilogb(APFloat(APFloat::IEEEdouble, "0x1.ffffffffffffep-1023")));
- EXPECT_EQ(-1023, ilogb(APFloat(APFloat::IEEEdouble, "-0x1.ffffffffffffep-1023")));
- EXPECT_EQ(-51, ilogb(APFloat(APFloat::IEEEdouble, "0x1p-51")));
- EXPECT_EQ(-1023, ilogb(APFloat(APFloat::IEEEdouble, "0x1.c60f120d9f87cp-1023")));
- EXPECT_EQ(-2, ilogb(APFloat(APFloat::IEEEdouble, "0x0.ffffp-1")));
- EXPECT_EQ(-1023, ilogb(APFloat(APFloat::IEEEdouble, "0x1.fffep-1023")));
- EXPECT_EQ(1023, ilogb(APFloat::getLargest(APFloat::IEEEdouble, false)));
- EXPECT_EQ(1023, ilogb(APFloat::getLargest(APFloat::IEEEdouble, true)));
-
-
- EXPECT_EQ(0, ilogb(APFloat(APFloat::IEEEsingle, "0x1p+0")));
- EXPECT_EQ(0, ilogb(APFloat(APFloat::IEEEsingle, "-0x1p+0")));
- EXPECT_EQ(42, ilogb(APFloat(APFloat::IEEEsingle, "0x1p+42")));
- EXPECT_EQ(-42, ilogb(APFloat(APFloat::IEEEsingle, "0x1p-42")));
+ EXPECT_EQ(-1074, ilogb(APFloat::getSmallest(APFloat::IEEEdouble(), false)));
+ EXPECT_EQ(-1074, ilogb(APFloat::getSmallest(APFloat::IEEEdouble(), true)));
+ EXPECT_EQ(-1023, ilogb(APFloat(APFloat::IEEEdouble(), "0x1.ffffffffffffep-1024")));
+ EXPECT_EQ(-1023, ilogb(APFloat(APFloat::IEEEdouble(), "0x1.ffffffffffffep-1023")));
+ EXPECT_EQ(-1023, ilogb(APFloat(APFloat::IEEEdouble(), "-0x1.ffffffffffffep-1023")));
+ EXPECT_EQ(-51, ilogb(APFloat(APFloat::IEEEdouble(), "0x1p-51")));
+ EXPECT_EQ(-1023, ilogb(APFloat(APFloat::IEEEdouble(), "0x1.c60f120d9f87cp-1023")));
+ EXPECT_EQ(-2, ilogb(APFloat(APFloat::IEEEdouble(), "0x0.ffffp-1")));
+ EXPECT_EQ(-1023, ilogb(APFloat(APFloat::IEEEdouble(), "0x1.fffep-1023")));
+ EXPECT_EQ(1023, ilogb(APFloat::getLargest(APFloat::IEEEdouble(), false)));
+ EXPECT_EQ(1023, ilogb(APFloat::getLargest(APFloat::IEEEdouble(), true)));
+
+
+ EXPECT_EQ(0, ilogb(APFloat(APFloat::IEEEsingle(), "0x1p+0")));
+ EXPECT_EQ(0, ilogb(APFloat(APFloat::IEEEsingle(), "-0x1p+0")));
+ EXPECT_EQ(42, ilogb(APFloat(APFloat::IEEEsingle(), "0x1p+42")));
+ EXPECT_EQ(-42, ilogb(APFloat(APFloat::IEEEsingle(), "0x1p-42")));
EXPECT_EQ(APFloat::IEK_Inf,
- ilogb(APFloat::getInf(APFloat::IEEEsingle, false)));
+ ilogb(APFloat::getInf(APFloat::IEEEsingle(), false)));
EXPECT_EQ(APFloat::IEK_Inf,
- ilogb(APFloat::getInf(APFloat::IEEEsingle, true)));
+ ilogb(APFloat::getInf(APFloat::IEEEsingle(), true)));
EXPECT_EQ(APFloat::IEK_Zero,
- ilogb(APFloat::getZero(APFloat::IEEEsingle, false)));
+ ilogb(APFloat::getZero(APFloat::IEEEsingle(), false)));
EXPECT_EQ(APFloat::IEK_Zero,
- ilogb(APFloat::getZero(APFloat::IEEEsingle, true)));
+ ilogb(APFloat::getZero(APFloat::IEEEsingle(), true)));
EXPECT_EQ(APFloat::IEK_NaN,
- ilogb(APFloat::getNaN(APFloat::IEEEsingle, false)));
+ ilogb(APFloat::getNaN(APFloat::IEEEsingle(), false)));
EXPECT_EQ(APFloat::IEK_NaN,
- ilogb(APFloat::getSNaN(APFloat::IEEEsingle, false)));
+ ilogb(APFloat::getSNaN(APFloat::IEEEsingle(), false)));
- EXPECT_EQ(127, ilogb(APFloat::getLargest(APFloat::IEEEsingle, false)));
- EXPECT_EQ(127, ilogb(APFloat::getLargest(APFloat::IEEEsingle, true)));
+ EXPECT_EQ(127, ilogb(APFloat::getLargest(APFloat::IEEEsingle(), false)));
+ EXPECT_EQ(127, ilogb(APFloat::getLargest(APFloat::IEEEsingle(), true)));
- EXPECT_EQ(-149, ilogb(APFloat::getSmallest(APFloat::IEEEsingle, false)));
- EXPECT_EQ(-149, ilogb(APFloat::getSmallest(APFloat::IEEEsingle, true)));
+ EXPECT_EQ(-149, ilogb(APFloat::getSmallest(APFloat::IEEEsingle(), false)));
+ EXPECT_EQ(-149, ilogb(APFloat::getSmallest(APFloat::IEEEsingle(), true)));
EXPECT_EQ(-126,
- ilogb(APFloat::getSmallestNormalized(APFloat::IEEEsingle, false)));
+ ilogb(APFloat::getSmallestNormalized(APFloat::IEEEsingle(), false)));
EXPECT_EQ(-126,
- ilogb(APFloat::getSmallestNormalized(APFloat::IEEEsingle, true)));
+ ilogb(APFloat::getSmallestNormalized(APFloat::IEEEsingle(), true)));
}
TEST(APFloatTest, scalbn) {
const APFloat::roundingMode RM = APFloat::rmNearestTiesToEven;
EXPECT_TRUE(
- APFloat(APFloat::IEEEsingle, "0x1p+0")
- .bitwiseIsEqual(scalbn(APFloat(APFloat::IEEEsingle, "0x1p+0"), 0, RM)));
+ APFloat(APFloat::IEEEsingle(), "0x1p+0")
+ .bitwiseIsEqual(scalbn(APFloat(APFloat::IEEEsingle(), "0x1p+0"), 0, RM)));
EXPECT_TRUE(
- APFloat(APFloat::IEEEsingle, "0x1p+42")
- .bitwiseIsEqual(scalbn(APFloat(APFloat::IEEEsingle, "0x1p+0"), 42, RM)));
+ APFloat(APFloat::IEEEsingle(), "0x1p+42")
+ .bitwiseIsEqual(scalbn(APFloat(APFloat::IEEEsingle(), "0x1p+0"), 42, RM)));
EXPECT_TRUE(
- APFloat(APFloat::IEEEsingle, "0x1p-42")
- .bitwiseIsEqual(scalbn(APFloat(APFloat::IEEEsingle, "0x1p+0"), -42, RM)));
+ APFloat(APFloat::IEEEsingle(), "0x1p-42")
+ .bitwiseIsEqual(scalbn(APFloat(APFloat::IEEEsingle(), "0x1p+0"), -42, RM)));
- APFloat PInf = APFloat::getInf(APFloat::IEEEsingle, false);
- APFloat MInf = APFloat::getInf(APFloat::IEEEsingle, true);
- APFloat PZero = APFloat::getZero(APFloat::IEEEsingle, false);
- APFloat MZero = APFloat::getZero(APFloat::IEEEsingle, true);
- APFloat QPNaN = APFloat::getNaN(APFloat::IEEEsingle, false);
- APFloat QMNaN = APFloat::getNaN(APFloat::IEEEsingle, true);
- APFloat SNaN = APFloat::getSNaN(APFloat::IEEEsingle, false);
+ APFloat PInf = APFloat::getInf(APFloat::IEEEsingle(), false);
+ APFloat MInf = APFloat::getInf(APFloat::IEEEsingle(), true);
+ APFloat PZero = APFloat::getZero(APFloat::IEEEsingle(), false);
+ APFloat MZero = APFloat::getZero(APFloat::IEEEsingle(), true);
+ APFloat QPNaN = APFloat::getNaN(APFloat::IEEEsingle(), false);
+ APFloat QMNaN = APFloat::getNaN(APFloat::IEEEsingle(), true);
+ APFloat SNaN = APFloat::getSNaN(APFloat::IEEEsingle(), false);
EXPECT_TRUE(PInf.bitwiseIsEqual(scalbn(PInf, 0, RM)));
EXPECT_TRUE(MInf.bitwiseIsEqual(scalbn(MInf, 0, RM)));
@@ -2900,57 +2914,57 @@ TEST(APFloatTest, scalbn) {
(UINT64_C(1234) << 32) |
1);
- APFloat SNaNWithPayload = APFloat::getSNaN(APFloat::IEEEdouble, false,
+ APFloat SNaNWithPayload = APFloat::getSNaN(APFloat::IEEEdouble(), false,
&Payload);
APFloat QuietPayload = scalbn(SNaNWithPayload, 1, RM);
EXPECT_TRUE(QuietPayload.isNaN() && !QuietPayload.isSignaling());
EXPECT_EQ(Payload, QuietPayload.bitcastToAPInt().getLoBits(51));
EXPECT_TRUE(PInf.bitwiseIsEqual(
- scalbn(APFloat(APFloat::IEEEsingle, "0x1p+0"), 128, RM)));
+ scalbn(APFloat(APFloat::IEEEsingle(), "0x1p+0"), 128, RM)));
EXPECT_TRUE(MInf.bitwiseIsEqual(
- scalbn(APFloat(APFloat::IEEEsingle, "-0x1p+0"), 128, RM)));
+ scalbn(APFloat(APFloat::IEEEsingle(), "-0x1p+0"), 128, RM)));
EXPECT_TRUE(PInf.bitwiseIsEqual(
- scalbn(APFloat(APFloat::IEEEsingle, "0x1p+127"), 1, RM)));
+ scalbn(APFloat(APFloat::IEEEsingle(), "0x1p+127"), 1, RM)));
EXPECT_TRUE(PZero.bitwiseIsEqual(
- scalbn(APFloat(APFloat::IEEEsingle, "0x1p-127"), -127, RM)));
+ scalbn(APFloat(APFloat::IEEEsingle(), "0x1p-127"), -127, RM)));
EXPECT_TRUE(MZero.bitwiseIsEqual(
- scalbn(APFloat(APFloat::IEEEsingle, "-0x1p-127"), -127, RM)));
- EXPECT_TRUE(APFloat(APFloat::IEEEsingle, "-0x1p-149").bitwiseIsEqual(
- scalbn(APFloat(APFloat::IEEEsingle, "-0x1p-127"), -22, RM)));
+ scalbn(APFloat(APFloat::IEEEsingle(), "-0x1p-127"), -127, RM)));
+ EXPECT_TRUE(APFloat(APFloat::IEEEsingle(), "-0x1p-149").bitwiseIsEqual(
+ scalbn(APFloat(APFloat::IEEEsingle(), "-0x1p-127"), -22, RM)));
EXPECT_TRUE(PZero.bitwiseIsEqual(
- scalbn(APFloat(APFloat::IEEEsingle, "0x1p-126"), -24, RM)));
+ scalbn(APFloat(APFloat::IEEEsingle(), "0x1p-126"), -24, RM)));
- APFloat SmallestF64 = APFloat::getSmallest(APFloat::IEEEdouble, false);
- APFloat NegSmallestF64 = APFloat::getSmallest(APFloat::IEEEdouble, true);
+ APFloat SmallestF64 = APFloat::getSmallest(APFloat::IEEEdouble(), false);
+ APFloat NegSmallestF64 = APFloat::getSmallest(APFloat::IEEEdouble(), true);
- APFloat LargestF64 = APFloat::getLargest(APFloat::IEEEdouble, false);
- APFloat NegLargestF64 = APFloat::getLargest(APFloat::IEEEdouble, true);
+ APFloat LargestF64 = APFloat::getLargest(APFloat::IEEEdouble(), false);
+ APFloat NegLargestF64 = APFloat::getLargest(APFloat::IEEEdouble(), true);
APFloat SmallestNormalizedF64
- = APFloat::getSmallestNormalized(APFloat::IEEEdouble, false);
+ = APFloat::getSmallestNormalized(APFloat::IEEEdouble(), false);
APFloat NegSmallestNormalizedF64
- = APFloat::getSmallestNormalized(APFloat::IEEEdouble, true);
+ = APFloat::getSmallestNormalized(APFloat::IEEEdouble(), true);
- APFloat LargestDenormalF64(APFloat::IEEEdouble, "0x1.ffffffffffffep-1023");
- APFloat NegLargestDenormalF64(APFloat::IEEEdouble, "-0x1.ffffffffffffep-1023");
+ APFloat LargestDenormalF64(APFloat::IEEEdouble(), "0x1.ffffffffffffep-1023");
+ APFloat NegLargestDenormalF64(APFloat::IEEEdouble(), "-0x1.ffffffffffffep-1023");
EXPECT_TRUE(SmallestF64.bitwiseIsEqual(
- scalbn(APFloat(APFloat::IEEEdouble, "0x1p-1074"), 0, RM)));
+ scalbn(APFloat(APFloat::IEEEdouble(), "0x1p-1074"), 0, RM)));
EXPECT_TRUE(NegSmallestF64.bitwiseIsEqual(
- scalbn(APFloat(APFloat::IEEEdouble, "-0x1p-1074"), 0, RM)));
+ scalbn(APFloat(APFloat::IEEEdouble(), "-0x1p-1074"), 0, RM)));
- EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "0x1p+1023")
+ EXPECT_TRUE(APFloat(APFloat::IEEEdouble(), "0x1p+1023")
.bitwiseIsEqual(scalbn(SmallestF64, 2097, RM)));
EXPECT_TRUE(scalbn(SmallestF64, -2097, RM).isPosZero());
EXPECT_TRUE(scalbn(SmallestF64, -2098, RM).isPosZero());
EXPECT_TRUE(scalbn(SmallestF64, -2099, RM).isPosZero());
- EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "0x1p+1022")
+ EXPECT_TRUE(APFloat(APFloat::IEEEdouble(), "0x1p+1022")
.bitwiseIsEqual(scalbn(SmallestF64, 2096, RM)));
- EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "0x1p+1023")
+ EXPECT_TRUE(APFloat(APFloat::IEEEdouble(), "0x1p+1023")
.bitwiseIsEqual(scalbn(SmallestF64, 2097, RM)));
EXPECT_TRUE(scalbn(SmallestF64, 2098, RM).isInfinity());
EXPECT_TRUE(scalbn(SmallestF64, 2099, RM).isInfinity());
@@ -2964,12 +2978,12 @@ TEST(APFloatTest, scalbn) {
EXPECT_TRUE(NegLargestDenormalF64
.bitwiseIsEqual(scalbn(NegLargestDenormalF64, 0, RM)));
- EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "0x1.ffffffffffffep-1022")
+ EXPECT_TRUE(APFloat(APFloat::IEEEdouble(), "0x1.ffffffffffffep-1022")
.bitwiseIsEqual(scalbn(LargestDenormalF64, 1, RM)));
- EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "-0x1.ffffffffffffep-1021")
+ EXPECT_TRUE(APFloat(APFloat::IEEEdouble(), "-0x1.ffffffffffffep-1021")
.bitwiseIsEqual(scalbn(NegLargestDenormalF64, 2, RM)));
- EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "0x1.ffffffffffffep+1")
+ EXPECT_TRUE(APFloat(APFloat::IEEEdouble(), "0x1.ffffffffffffep+1")
.bitwiseIsEqual(scalbn(LargestDenormalF64, 1024, RM)));
EXPECT_TRUE(scalbn(LargestDenormalF64, -1023, RM).isPosZero());
EXPECT_TRUE(scalbn(LargestDenormalF64, -1024, RM).isPosZero());
@@ -2978,25 +2992,25 @@ TEST(APFloatTest, scalbn) {
EXPECT_TRUE(scalbn(LargestDenormalF64, 2098, RM).isInfinity());
EXPECT_TRUE(scalbn(LargestDenormalF64, 2099, RM).isInfinity());
- EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "0x1.ffffffffffffep-2")
+ EXPECT_TRUE(APFloat(APFloat::IEEEdouble(), "0x1.ffffffffffffep-2")
.bitwiseIsEqual(scalbn(LargestDenormalF64, 1021, RM)));
- EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "0x1.ffffffffffffep-1")
+ EXPECT_TRUE(APFloat(APFloat::IEEEdouble(), "0x1.ffffffffffffep-1")
.bitwiseIsEqual(scalbn(LargestDenormalF64, 1022, RM)));
- EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "0x1.ffffffffffffep+0")
+ EXPECT_TRUE(APFloat(APFloat::IEEEdouble(), "0x1.ffffffffffffep+0")
.bitwiseIsEqual(scalbn(LargestDenormalF64, 1023, RM)));
- EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "0x1.ffffffffffffep+1023")
+ EXPECT_TRUE(APFloat(APFloat::IEEEdouble(), "0x1.ffffffffffffep+1023")
.bitwiseIsEqual(scalbn(LargestDenormalF64, 2046, RM)));
- EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "0x1p+974")
+ EXPECT_TRUE(APFloat(APFloat::IEEEdouble(), "0x1p+974")
.bitwiseIsEqual(scalbn(SmallestF64, 2048, RM)));
- APFloat RandomDenormalF64(APFloat::IEEEdouble, "0x1.c60f120d9f87cp+51");
- EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "0x1.c60f120d9f87cp-972")
+ APFloat RandomDenormalF64(APFloat::IEEEdouble(), "0x1.c60f120d9f87cp+51");
+ EXPECT_TRUE(APFloat(APFloat::IEEEdouble(), "0x1.c60f120d9f87cp-972")
.bitwiseIsEqual(scalbn(RandomDenormalF64, -1023, RM)));
- EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "0x1.c60f120d9f87cp-1")
+ EXPECT_TRUE(APFloat(APFloat::IEEEdouble(), "0x1.c60f120d9f87cp-1")
.bitwiseIsEqual(scalbn(RandomDenormalF64, -52, RM)));
- EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "0x1.c60f120d9f87cp-2")
+ EXPECT_TRUE(APFloat(APFloat::IEEEdouble(), "0x1.c60f120d9f87cp-2")
.bitwiseIsEqual(scalbn(RandomDenormalF64, -53, RM)));
- EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "0x1.c60f120d9f87cp+0")
+ EXPECT_TRUE(APFloat(APFloat::IEEEdouble(), "0x1.c60f120d9f87cp+0")
.bitwiseIsEqual(scalbn(RandomDenormalF64, -51, RM)));
EXPECT_TRUE(scalbn(RandomDenormalF64, -2097, RM).isPosZero());
@@ -3004,60 +3018,60 @@ TEST(APFloatTest, scalbn) {
EXPECT_TRUE(
- APFloat(APFloat::IEEEdouble, "-0x1p-1073")
+ APFloat(APFloat::IEEEdouble(), "-0x1p-1073")
.bitwiseIsEqual(scalbn(NegLargestF64, -2097, RM)));
EXPECT_TRUE(
- APFloat(APFloat::IEEEdouble, "-0x1p-1024")
+ APFloat(APFloat::IEEEdouble(), "-0x1p-1024")
.bitwiseIsEqual(scalbn(NegLargestF64, -2048, RM)));
EXPECT_TRUE(
- APFloat(APFloat::IEEEdouble, "0x1p-1073")
+ APFloat(APFloat::IEEEdouble(), "0x1p-1073")
.bitwiseIsEqual(scalbn(LargestF64, -2097, RM)));
EXPECT_TRUE(
- APFloat(APFloat::IEEEdouble, "0x1p-1074")
+ APFloat(APFloat::IEEEdouble(), "0x1p-1074")
.bitwiseIsEqual(scalbn(LargestF64, -2098, RM)));
- EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "-0x1p-1074")
+ EXPECT_TRUE(APFloat(APFloat::IEEEdouble(), "-0x1p-1074")
.bitwiseIsEqual(scalbn(NegLargestF64, -2098, RM)));
EXPECT_TRUE(scalbn(NegLargestF64, -2099, RM).isNegZero());
EXPECT_TRUE(scalbn(LargestF64, 1, RM).isInfinity());
EXPECT_TRUE(
- APFloat(APFloat::IEEEdouble, "0x1p+0")
- .bitwiseIsEqual(scalbn(APFloat(APFloat::IEEEdouble, "0x1p+52"), -52, RM)));
+ APFloat(APFloat::IEEEdouble(), "0x1p+0")
+ .bitwiseIsEqual(scalbn(APFloat(APFloat::IEEEdouble(), "0x1p+52"), -52, RM)));
EXPECT_TRUE(
- APFloat(APFloat::IEEEdouble, "0x1p-103")
- .bitwiseIsEqual(scalbn(APFloat(APFloat::IEEEdouble, "0x1p-51"), -52, RM)));
+ APFloat(APFloat::IEEEdouble(), "0x1p-103")
+ .bitwiseIsEqual(scalbn(APFloat(APFloat::IEEEdouble(), "0x1p-51"), -52, RM)));
}
TEST(APFloatTest, frexp) {
const APFloat::roundingMode RM = APFloat::rmNearestTiesToEven;
- APFloat PZero = APFloat::getZero(APFloat::IEEEdouble, false);
- APFloat MZero = APFloat::getZero(APFloat::IEEEdouble, true);
+ APFloat PZero = APFloat::getZero(APFloat::IEEEdouble(), false);
+ APFloat MZero = APFloat::getZero(APFloat::IEEEdouble(), true);
APFloat One(1.0);
APFloat MOne(-1.0);
APFloat Two(2.0);
APFloat MTwo(-2.0);
- APFloat LargestDenormal(APFloat::IEEEdouble, "0x1.ffffffffffffep-1023");
- APFloat NegLargestDenormal(APFloat::IEEEdouble, "-0x1.ffffffffffffep-1023");
+ APFloat LargestDenormal(APFloat::IEEEdouble(), "0x1.ffffffffffffep-1023");
+ APFloat NegLargestDenormal(APFloat::IEEEdouble(), "-0x1.ffffffffffffep-1023");
- APFloat Smallest = APFloat::getSmallest(APFloat::IEEEdouble, false);
- APFloat NegSmallest = APFloat::getSmallest(APFloat::IEEEdouble, true);
+ APFloat Smallest = APFloat::getSmallest(APFloat::IEEEdouble(), false);
+ APFloat NegSmallest = APFloat::getSmallest(APFloat::IEEEdouble(), true);
- APFloat Largest = APFloat::getLargest(APFloat::IEEEdouble, false);
- APFloat NegLargest = APFloat::getLargest(APFloat::IEEEdouble, true);
+ APFloat Largest = APFloat::getLargest(APFloat::IEEEdouble(), false);
+ APFloat NegLargest = APFloat::getLargest(APFloat::IEEEdouble(), true);
- APFloat PInf = APFloat::getInf(APFloat::IEEEdouble, false);
- APFloat MInf = APFloat::getInf(APFloat::IEEEdouble, true);
+ APFloat PInf = APFloat::getInf(APFloat::IEEEdouble(), false);
+ APFloat MInf = APFloat::getInf(APFloat::IEEEdouble(), true);
- APFloat QPNaN = APFloat::getNaN(APFloat::IEEEdouble, false);
- APFloat QMNaN = APFloat::getNaN(APFloat::IEEEdouble, true);
- APFloat SNaN = APFloat::getSNaN(APFloat::IEEEdouble, false);
+ APFloat QPNaN = APFloat::getNaN(APFloat::IEEEdouble(), false);
+ APFloat QMNaN = APFloat::getNaN(APFloat::IEEEdouble(), true);
+ APFloat SNaN = APFloat::getSNaN(APFloat::IEEEdouble(), false);
// Make sure highest bit of payload is preserved.
const APInt Payload(64, (UINT64_C(1) << 50) |
@@ -3065,16 +3079,16 @@ TEST(APFloatTest, frexp) {
(UINT64_C(1234) << 32) |
1);
- APFloat SNaNWithPayload = APFloat::getSNaN(APFloat::IEEEdouble, false,
+ APFloat SNaNWithPayload = APFloat::getSNaN(APFloat::IEEEdouble(), false,
&Payload);
APFloat SmallestNormalized
- = APFloat::getSmallestNormalized(APFloat::IEEEdouble, false);
+ = APFloat::getSmallestNormalized(APFloat::IEEEdouble(), false);
APFloat NegSmallestNormalized
- = APFloat::getSmallestNormalized(APFloat::IEEEdouble, true);
+ = APFloat::getSmallestNormalized(APFloat::IEEEdouble(), true);
int Exp;
- APFloat Frac(APFloat::IEEEdouble);
+ APFloat Frac(APFloat::IEEEdouble());
Frac = frexp(PZero, Exp, RM);
@@ -3088,37 +3102,37 @@ TEST(APFloatTest, frexp) {
Frac = frexp(One, Exp, RM);
EXPECT_EQ(1, Exp);
- EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "0x1p-1").bitwiseIsEqual(Frac));
+ EXPECT_TRUE(APFloat(APFloat::IEEEdouble(), "0x1p-1").bitwiseIsEqual(Frac));
Frac = frexp(MOne, Exp, RM);
EXPECT_EQ(1, Exp);
- EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "-0x1p-1").bitwiseIsEqual(Frac));
+ EXPECT_TRUE(APFloat(APFloat::IEEEdouble(), "-0x1p-1").bitwiseIsEqual(Frac));
Frac = frexp(LargestDenormal, Exp, RM);
EXPECT_EQ(-1022, Exp);
- EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "0x1.ffffffffffffep-1").bitwiseIsEqual(Frac));
+ EXPECT_TRUE(APFloat(APFloat::IEEEdouble(), "0x1.ffffffffffffep-1").bitwiseIsEqual(Frac));
Frac = frexp(NegLargestDenormal, Exp, RM);
EXPECT_EQ(-1022, Exp);
- EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "-0x1.ffffffffffffep-1").bitwiseIsEqual(Frac));
+ EXPECT_TRUE(APFloat(APFloat::IEEEdouble(), "-0x1.ffffffffffffep-1").bitwiseIsEqual(Frac));
Frac = frexp(Smallest, Exp, RM);
EXPECT_EQ(-1073, Exp);
- EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "0x1p-1").bitwiseIsEqual(Frac));
+ EXPECT_TRUE(APFloat(APFloat::IEEEdouble(), "0x1p-1").bitwiseIsEqual(Frac));
Frac = frexp(NegSmallest, Exp, RM);
EXPECT_EQ(-1073, Exp);
- EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "-0x1p-1").bitwiseIsEqual(Frac));
+ EXPECT_TRUE(APFloat(APFloat::IEEEdouble(), "-0x1p-1").bitwiseIsEqual(Frac));
Frac = frexp(Largest, Exp, RM);
EXPECT_EQ(1024, Exp);
- EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "0x1.fffffffffffffp-1").bitwiseIsEqual(Frac));
+ EXPECT_TRUE(APFloat(APFloat::IEEEdouble(), "0x1.fffffffffffffp-1").bitwiseIsEqual(Frac));
Frac = frexp(NegLargest, Exp, RM);
EXPECT_EQ(1024, Exp);
- EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "-0x1.fffffffffffffp-1").bitwiseIsEqual(Frac));
+ EXPECT_TRUE(APFloat(APFloat::IEEEdouble(), "-0x1.fffffffffffffp-1").bitwiseIsEqual(Frac));
Frac = frexp(PInf, Exp, RM);
@@ -3146,16 +3160,150 @@ TEST(APFloatTest, frexp) {
EXPECT_TRUE(Frac.isNaN() && !Frac.isSignaling());
EXPECT_EQ(Payload, Frac.bitcastToAPInt().getLoBits(51));
- Frac = frexp(APFloat(APFloat::IEEEdouble, "0x0.ffffp-1"), Exp, RM);
+ Frac = frexp(APFloat(APFloat::IEEEdouble(), "0x0.ffffp-1"), Exp, RM);
EXPECT_EQ(-1, Exp);
- EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "0x1.fffep-1").bitwiseIsEqual(Frac));
+ EXPECT_TRUE(APFloat(APFloat::IEEEdouble(), "0x1.fffep-1").bitwiseIsEqual(Frac));
- Frac = frexp(APFloat(APFloat::IEEEdouble, "0x1p-51"), Exp, RM);
+ Frac = frexp(APFloat(APFloat::IEEEdouble(), "0x1p-51"), Exp, RM);
EXPECT_EQ(-50, Exp);
- EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "0x1p-1").bitwiseIsEqual(Frac));
+ EXPECT_TRUE(APFloat(APFloat::IEEEdouble(), "0x1p-1").bitwiseIsEqual(Frac));
- Frac = frexp(APFloat(APFloat::IEEEdouble, "0x1.c60f120d9f87cp+51"), Exp, RM);
+ Frac = frexp(APFloat(APFloat::IEEEdouble(), "0x1.c60f120d9f87cp+51"), Exp, RM);
EXPECT_EQ(52, Exp);
- EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "0x1.c60f120d9f87cp-1").bitwiseIsEqual(Frac));
+ EXPECT_TRUE(APFloat(APFloat::IEEEdouble(), "0x1.c60f120d9f87cp-1").bitwiseIsEqual(Frac));
+}
+
+TEST(APFloatTest, PPCDoubleDoubleAddSpecial) {
+ using DataType = std::tuple<uint64_t, uint64_t, uint64_t, uint64_t,
+ APFloat::fltCategory, APFloat::roundingMode>;
+ DataType Data[] = {
+ // (1 + 0) + (-1 + 0) = fcZero
+ std::make_tuple(0x3ff0000000000000ull, 0, 0xbff0000000000000ull, 0,
+ APFloat::fcZero, APFloat::rmNearestTiesToEven),
+ // LDBL_MAX + (1.1 >> (1023 - 106) + 0)) = fcInfinity
+ std::make_tuple(0x7fefffffffffffffull, 0x7c8ffffffffffffeull,
+ 0x7948000000000000ull, 0ull, APFloat::fcInfinity,
+ APFloat::rmNearestTiesToEven),
+ // TODO: change the 4th 0x75effffffffffffe to 0x75efffffffffffff when
+ // PPCDoubleDoubleImpl is gone.
+ // LDBL_MAX + (1.011111... >> (1023 - 106) + (1.1111111...0 >> (1023 -
+ // 160))) = fcNormal
+ std::make_tuple(0x7fefffffffffffffull, 0x7c8ffffffffffffeull,
+ 0x7947ffffffffffffull, 0x75effffffffffffeull,
+ APFloat::fcNormal, APFloat::rmNearestTiesToEven),
+ // LDBL_MAX + (1.1 >> (1023 - 106) + 0)) = fcInfinity
+ std::make_tuple(0x7fefffffffffffffull, 0x7c8ffffffffffffeull,
+ 0x7fefffffffffffffull, 0x7c8ffffffffffffeull,
+ APFloat::fcInfinity, APFloat::rmNearestTiesToEven),
+ // NaN + (1 + 0) = fcNaN
+ std::make_tuple(0x7ff8000000000000ull, 0, 0x3ff0000000000000ull, 0,
+ APFloat::fcNaN, 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.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();
+ }
+}
+
+TEST(APFloatTest, PPCDoubleDoubleAdd) {
+ using DataType = std::tuple<uint64_t, uint64_t, uint64_t, uint64_t, uint64_t,
+ uint64_t, APFloat::roundingMode>;
+ DataType Data[] = {
+ // (1 + 0) + (1e-105 + 0) = (1 + 1e-105)
+ std::make_tuple(0x3ff0000000000000ull, 0, 0x3960000000000000ull, 0,
+ 0x3ff0000000000000ull, 0x3960000000000000ull,
+ APFloat::rmNearestTiesToEven),
+ // (1 + 0) + (1e-106 + 0) = (1 + 1e-106)
+ std::make_tuple(0x3ff0000000000000ull, 0, 0x3950000000000000ull, 0,
+ 0x3ff0000000000000ull, 0x3950000000000000ull,
+ APFloat::rmNearestTiesToEven),
+ // (1 + 1e-106) + (1e-106 + 0) = (1 + 1e-105)
+ std::make_tuple(0x3ff0000000000000ull, 0x3950000000000000ull,
+ 0x3950000000000000ull, 0, 0x3ff0000000000000ull,
+ 0x3960000000000000ull, APFloat::rmNearestTiesToEven),
+ // (1 + 0) + (epsilon + 0) = (1 + epsilon)
+ std::make_tuple(0x3ff0000000000000ull, 0, 0x0000000000000001ull, 0,
+ 0x3ff0000000000000ull, 0x0000000000000001ull,
+ APFloat::rmNearestTiesToEven),
+ // TODO: change 0xf950000000000000 to 0xf940000000000000, when
+ // PPCDoubleDoubleImpl 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.
+ // (1 << (1023 - 53) + 0) + (DBL_MAX - 1 << (1023 - 105)) = DBL_MAX +
+ // 1.11111... << (1023 - 52)
+ std::make_tuple(0x7c90000000000000ull, 0, 0x7fefffffffffffffull,
+ 0xf950000000000000ull, 0x7fefffffffffffffull,
+ 0x7c8ffffffffffffeull, APFloat::rmNearestTiesToEven),
+ };
+
+ for (auto Tp : Data) {
+ uint64_t Op1[2], Op2[2], Expected[2];
+ 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();
+ }
+}
+
+TEST(APFloatTest, PPCDoubleDoubleSubtract) {
+ using DataType = std::tuple<uint64_t, uint64_t, uint64_t, uint64_t, uint64_t,
+ uint64_t, APFloat::roundingMode>;
+ DataType Data[] = {
+ // (1 + 0) - (-1e-105 + 0) = (1 + 1e-105)
+ std::make_tuple(0x3ff0000000000000ull, 0, 0xb960000000000000ull, 0,
+ 0x3ff0000000000000ull, 0x3960000000000000ull,
+ APFloat::rmNearestTiesToEven),
+ // (1 + 0) - (-1e-106 + 0) = (1 + 1e-106)
+ std::make_tuple(0x3ff0000000000000ull, 0, 0xb950000000000000ull, 0,
+ 0x3ff0000000000000ull, 0x3950000000000000ull,
+ APFloat::rmNearestTiesToEven),
+ };
+
+ for (auto Tp : Data) {
+ uint64_t Op1[2], Op2[2], Expected[2];
+ 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.subtract(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();
+ }
}
}
diff --git a/unittests/ADT/APIntTest.cpp b/unittests/ADT/APIntTest.cpp
index b0d80c3c6819..cbffdc096fbe 100644
--- a/unittests/ADT/APIntTest.cpp
+++ b/unittests/ADT/APIntTest.cpp
@@ -32,6 +32,11 @@ TEST(APIntTest, ShiftLeftByZero) {
EXPECT_FALSE(Shl[1]);
}
+TEST(APIntTest, i64_ArithmeticRightShiftNegative) {
+ const APInt neg_one(64, static_cast<uint64_t>(-1), true);
+ EXPECT_EQ(neg_one, neg_one.ashr(7));
+}
+
TEST(APIntTest, i128_NegativeCount) {
APInt Minus3(128, static_cast<uint64_t>(-3), true);
EXPECT_EQ(126u, Minus3.countLeadingOnes());
@@ -47,9 +52,6 @@ TEST(APIntTest, i128_NegativeCount) {
EXPECT_EQ(-1, Minus1.getSExtValue());
}
-// XFAIL this test on FreeBSD where the system gcc-4.2.1 seems to miscompile it.
-#if defined(__llvm__) || !defined(__FreeBSD__)
-
TEST(APIntTest, i33_Count) {
APInt i33minus2(33, static_cast<uint64_t>(-2), true);
EXPECT_EQ(0u, i33minus2.countLeadingZeros());
@@ -61,8 +63,6 @@ TEST(APIntTest, i33_Count) {
EXPECT_EQ(((uint64_t)-2)&((1ull<<33) -1), i33minus2.getZExtValue());
}
-#endif
-
TEST(APIntTest, i65_Count) {
APInt i65(65, 0, true);
EXPECT_EQ(65u, i65.countLeadingZeros());
@@ -416,6 +416,175 @@ TEST(APIntTest, compareLargeIntegers) {
EXPECT_TRUE(!MinusTwo.slt(MinusTwo));
}
+TEST(APIntTest, rvalue_arithmetic) {
+ // Test all combinations of lvalue/rvalue lhs/rhs of add/sub
+
+ // 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", 16);
+ APInt Two(129, "2", 16);
+ APInt Three(129, "3", 16);
+ APInt MinusOne = -One;
+
+ const uint64_t *RawDataL = nullptr;
+ const uint64_t *RawDataR = nullptr;
+
+ {
+ // 1 + 1 = 2
+ APInt AddLL = One + One;
+ EXPECT_EQ(AddLL, Two);
+
+ APInt AddLR = One + getRValue("1", RawDataR);
+ EXPECT_EQ(AddLR, Two);
+ EXPECT_EQ(AddLR.getRawData(), RawDataR);
+
+ APInt AddRL = getRValue("1", RawDataL) + One;
+ EXPECT_EQ(AddRL, Two);
+ EXPECT_EQ(AddRL.getRawData(), RawDataL);
+
+ APInt AddRR = getRValue("1", RawDataL) + getRValue("1", RawDataR);
+ EXPECT_EQ(AddRR, Two);
+ EXPECT_EQ(AddRR.getRawData(), RawDataR);
+
+ // LValue's and constants
+ APInt AddLK = One + 1;
+ EXPECT_EQ(AddLK, Two);
+
+ APInt AddKL = 1 + One;
+ EXPECT_EQ(AddKL, Two);
+
+ // RValue's and constants
+ APInt AddRK = getRValue("1", RawDataL) + 1;
+ EXPECT_EQ(AddRK, Two);
+ EXPECT_EQ(AddRK.getRawData(), RawDataL);
+
+ APInt AddKR = 1 + getRValue("1", RawDataR);
+ EXPECT_EQ(AddKR, Two);
+ EXPECT_EQ(AddKR.getRawData(), RawDataR);
+ }
+
+ {
+ // 0x0,FFFF...FFFF + 0x2 = 0x100...0001
+ APInt AllOnes(129, "0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16);
+ APInt HighOneLowOne(129, "100000000000000000000000000000001", 16);
+
+ APInt AddLL = AllOnes + Two;
+ EXPECT_EQ(AddLL, HighOneLowOne);
+
+ APInt AddLR = AllOnes + getRValue("2", RawDataR);
+ EXPECT_EQ(AddLR, HighOneLowOne);
+ EXPECT_EQ(AddLR.getRawData(), RawDataR);
+
+ APInt AddRL = getRValue("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", RawDataL) + Two;
+ EXPECT_EQ(AddRL, HighOneLowOne);
+ EXPECT_EQ(AddRL.getRawData(), RawDataL);
+
+ APInt AddRR = getRValue("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", RawDataL) +
+ getRValue("2", RawDataR);
+ EXPECT_EQ(AddRR, HighOneLowOne);
+ EXPECT_EQ(AddRR.getRawData(), RawDataR);
+
+ // LValue's and constants
+ APInt AddLK = AllOnes + 2;
+ EXPECT_EQ(AddLK, HighOneLowOne);
+
+ APInt AddKL = 2 + AllOnes;
+ EXPECT_EQ(AddKL, HighOneLowOne);
+
+ // RValue's and constants
+ APInt AddRK = getRValue("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", RawDataL) + 2;
+ EXPECT_EQ(AddRK, HighOneLowOne);
+ EXPECT_EQ(AddRK.getRawData(), RawDataL);
+
+ APInt AddKR = 2 + getRValue("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", RawDataR);
+ EXPECT_EQ(AddKR, HighOneLowOne);
+ EXPECT_EQ(AddKR.getRawData(), RawDataR);
+ }
+
+ {
+ // 2 - 1 = 1
+ APInt SubLL = Two - One;
+ EXPECT_EQ(SubLL, One);
+
+ APInt SubLR = Two - getRValue("1", RawDataR);
+ EXPECT_EQ(SubLR, One);
+ EXPECT_EQ(SubLR.getRawData(), RawDataR);
+
+ APInt SubRL = getRValue("2", RawDataL) - One;
+ EXPECT_EQ(SubRL, One);
+ EXPECT_EQ(SubRL.getRawData(), RawDataL);
+
+ APInt SubRR = getRValue("2", RawDataL) - getRValue("1", RawDataR);
+ EXPECT_EQ(SubRR, One);
+ EXPECT_EQ(SubRR.getRawData(), RawDataR);
+
+ // LValue's and constants
+ APInt SubLK = Two - 1;
+ EXPECT_EQ(SubLK, One);
+
+ APInt SubKL = 2 - One;
+ EXPECT_EQ(SubKL, One);
+
+ // RValue's and constants
+ APInt SubRK = getRValue("2", RawDataL) - 1;
+ EXPECT_EQ(SubRK, One);
+ EXPECT_EQ(SubRK.getRawData(), RawDataL);
+
+ APInt SubKR = 2 - getRValue("1", RawDataR);
+ EXPECT_EQ(SubKR, One);
+ EXPECT_EQ(SubKR.getRawData(), RawDataR);
+ }
+
+ {
+ // 0x100...0001 - 0x0,FFFF...FFFF = 0x2
+ APInt AllOnes(129, "0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16);
+ APInt HighOneLowOne(129, "100000000000000000000000000000001", 16);
+
+ APInt SubLL = HighOneLowOne - AllOnes;
+ EXPECT_EQ(SubLL, Two);
+
+ APInt SubLR = HighOneLowOne -
+ getRValue("0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", RawDataR);
+ EXPECT_EQ(SubLR, Two);
+ EXPECT_EQ(SubLR.getRawData(), RawDataR);
+
+ APInt SubRL = getRValue("100000000000000000000000000000001", RawDataL) -
+ AllOnes;
+ EXPECT_EQ(SubRL, Two);
+ EXPECT_EQ(SubRL.getRawData(), RawDataL);
+
+ APInt SubRR = getRValue("100000000000000000000000000000001", RawDataL) -
+ getRValue("0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", RawDataR);
+ EXPECT_EQ(SubRR, Two);
+ EXPECT_EQ(SubRR.getRawData(), RawDataR);
+
+ // LValue's and constants
+ // 0x100...0001 - 0x2 = 0x0,FFFF...FFFF
+ APInt SubLK = HighOneLowOne - 2;
+ EXPECT_EQ(SubLK, AllOnes);
+
+ // 2 - (-1) = 3
+ APInt SubKL = 2 - MinusOne;
+ EXPECT_EQ(SubKL, Three);
+
+ // RValue's and constants
+ // 0x100...0001 - 0x2 = 0x0,FFFF...FFFF
+ APInt SubRK = getRValue("100000000000000000000000000000001", RawDataL) - 2;
+ EXPECT_EQ(SubRK, AllOnes);
+ EXPECT_EQ(SubRK.getRawData(), RawDataL);
+
+ APInt SubKR = 2 - getRValue("1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", RawDataR);
+ EXPECT_EQ(SubKR, Three);
+ EXPECT_EQ(SubKR.getRawData(), RawDataR);
+ }
+}
+
// Tests different div/rem varaints using scheme (a * b + c) / a
void testDiv(APInt a, APInt b, APInt c) {
diff --git a/unittests/ADT/ArrayRefTest.cpp b/unittests/ADT/ArrayRefTest.cpp
index b5b71f06f65b..65b4cbcd6689 100644
--- a/unittests/ADT/ArrayRefTest.cpp
+++ b/unittests/ADT/ArrayRefTest.cpp
@@ -31,6 +31,26 @@ static_assert(
!std::is_convertible<ArrayRef<volatile int *>, ArrayRef<int *>>::value,
"Removing volatile");
+// Check that we can't accidentally assign a temporary location to an ArrayRef.
+// (Unfortunately we can't make use of the same thing with constructors.)
+//
+// Disable this check under MSVC; even MSVC 2015 isn't inconsistent between
+// std::is_assignable and actually writing such an assignment.
+#if !defined(_MSC_VER)
+static_assert(
+ !std::is_assignable<ArrayRef<int *>, int *>::value,
+ "Assigning from single prvalue element");
+static_assert(
+ !std::is_assignable<ArrayRef<int *>, int * &&>::value,
+ "Assigning from single xvalue element");
+static_assert(
+ std::is_assignable<ArrayRef<int *>, int * &>::value,
+ "Assigning from single lvalue element");
+static_assert(
+ !std::is_assignable<ArrayRef<int *>, std::initializer_list<int *>>::value,
+ "Assigning from an initializer list");
+#endif
+
namespace {
TEST(ArrayRefTest, AllocatorCopy) {
@@ -82,6 +102,64 @@ TEST(ArrayRefTest, DropFront) {
EXPECT_EQ(1U, AR3.drop_front(AR3.size() - 1).size());
}
+TEST(ArrayRefTest, DropWhile) {
+ static const int TheNumbers[] = {1, 3, 5, 8, 10, 11};
+ ArrayRef<int> AR1(TheNumbers);
+ ArrayRef<int> Expected = AR1.drop_front(3);
+ EXPECT_EQ(Expected, AR1.drop_while([](const int &N) { return N % 2 == 1; }));
+
+ EXPECT_EQ(AR1, AR1.drop_while([](const int &N) { return N < 0; }));
+ EXPECT_EQ(ArrayRef<int>(),
+ AR1.drop_while([](const int &N) { return N > 0; }));
+}
+
+TEST(ArrayRefTest, DropUntil) {
+ static const int TheNumbers[] = {1, 3, 5, 8, 10, 11};
+ ArrayRef<int> AR1(TheNumbers);
+ ArrayRef<int> Expected = AR1.drop_front(3);
+ EXPECT_EQ(Expected, AR1.drop_until([](const int &N) { return N % 2 == 0; }));
+
+ EXPECT_EQ(ArrayRef<int>(),
+ AR1.drop_until([](const int &N) { return N < 0; }));
+ EXPECT_EQ(AR1, AR1.drop_until([](const int &N) { return N > 0; }));
+}
+
+TEST(ArrayRefTest, TakeBack) {
+ static const int TheNumbers[] = {4, 8, 15, 16, 23, 42};
+ ArrayRef<int> AR1(TheNumbers);
+ ArrayRef<int> AR2(AR1.end() - 1, 1);
+ EXPECT_TRUE(AR1.take_back().equals(AR2));
+}
+
+TEST(ArrayRefTest, TakeFront) {
+ static const int TheNumbers[] = {4, 8, 15, 16, 23, 42};
+ ArrayRef<int> AR1(TheNumbers);
+ ArrayRef<int> AR2(AR1.data(), 2);
+ EXPECT_TRUE(AR1.take_front(2).equals(AR2));
+}
+
+TEST(ArrayRefTest, TakeWhile) {
+ static const int TheNumbers[] = {1, 3, 5, 8, 10, 11};
+ ArrayRef<int> AR1(TheNumbers);
+ ArrayRef<int> Expected = AR1.take_front(3);
+ EXPECT_EQ(Expected, AR1.take_while([](const int &N) { return N % 2 == 1; }));
+
+ EXPECT_EQ(ArrayRef<int>(),
+ AR1.take_while([](const int &N) { return N < 0; }));
+ EXPECT_EQ(AR1, AR1.take_while([](const int &N) { return N > 0; }));
+}
+
+TEST(ArrayRefTest, TakeUntil) {
+ static const int TheNumbers[] = {1, 3, 5, 8, 10, 11};
+ ArrayRef<int> AR1(TheNumbers);
+ ArrayRef<int> Expected = AR1.take_front(3);
+ EXPECT_EQ(Expected, AR1.take_until([](const int &N) { return N % 2 == 0; }));
+
+ EXPECT_EQ(AR1, AR1.take_until([](const int &N) { return N < 0; }));
+ EXPECT_EQ(ArrayRef<int>(),
+ AR1.take_until([](const int &N) { return N > 0; }));
+}
+
TEST(ArrayRefTest, Equals) {
static const int A1[] = {1, 2, 3, 4, 5, 6, 7, 8};
ArrayRef<int> AR1(A1);
@@ -134,7 +212,8 @@ static void ArgTest12(ArrayRef<int> A) {
}
TEST(ArrayRefTest, InitializerList) {
- ArrayRef<int> A = { 0, 1, 2, 3, 4 };
+ std::initializer_list<int> init_list = { 0, 1, 2, 3, 4 };
+ ArrayRef<int> A = init_list;
for (int i = 0; i < 5; ++i)
EXPECT_EQ(i, A[i]);
@@ -146,6 +225,14 @@ TEST(ArrayRefTest, InitializerList) {
ArgTest12({1, 2});
}
+TEST(ArrayRefTest, EmptyInitializerList) {
+ ArrayRef<int> A = {};
+ EXPECT_TRUE(A.empty());
+
+ A = {};
+ EXPECT_TRUE(A.empty());
+}
+
// Test that makeArrayRef works on ArrayRef (no-op)
TEST(ArrayRefTest, makeArrayRef) {
static const int A1[] = {1, 2, 3, 4, 5, 6, 7, 8};
diff --git a/unittests/ADT/BumpPtrListTest.cpp b/unittests/ADT/BumpPtrListTest.cpp
new file mode 100644
index 000000000000..be34a71373ce
--- /dev/null
+++ b/unittests/ADT/BumpPtrListTest.cpp
@@ -0,0 +1,243 @@
+//===- unittests/ADT/BumpPtrListTest.cpp - BumpPtrList unit tests ---------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/AllocatorList.h"
+#include "llvm/ADT/STLExtras.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+
+struct CountsDestructors {
+ static unsigned NumCalls;
+ ~CountsDestructors() { ++NumCalls; }
+};
+unsigned CountsDestructors::NumCalls = 0;
+
+struct MoveOnly {
+ int V;
+ explicit MoveOnly(int V) : V(V) {}
+ MoveOnly() = delete;
+ MoveOnly(MoveOnly &&X) { V = X.V; }
+ MoveOnly(const MoveOnly &X) = delete;
+ MoveOnly &operator=(MoveOnly &&X) = delete;
+ MoveOnly &operator=(const MoveOnly &X) = delete;
+};
+
+struct EmplaceOnly {
+ int V1, V2;
+ explicit EmplaceOnly(int V1, int V2) : V1(V1), V2(V2) {}
+ EmplaceOnly() = delete;
+ EmplaceOnly(EmplaceOnly &&X) = delete;
+ EmplaceOnly(const EmplaceOnly &X) = delete;
+ EmplaceOnly &operator=(EmplaceOnly &&X) = delete;
+ EmplaceOnly &operator=(const EmplaceOnly &X) = delete;
+};
+
+TEST(BumpPtrListTest, DefaultConstructor) {
+ BumpPtrList<int> L;
+ EXPECT_TRUE(L.empty());
+}
+
+TEST(BumpPtrListTest, pushPopBack) {
+ // Build a list with push_back.
+ BumpPtrList<int> L;
+ int Ns[] = {1, 3, 9, 5, 7};
+ for (const int N : Ns)
+ L.push_back(N);
+
+ // Use iterators to check contents.
+ auto I = L.begin();
+ for (int N : Ns)
+ EXPECT_EQ(N, *I++);
+ EXPECT_EQ(I, L.end());
+
+ // Unbuild the list with pop_back.
+ for (int N : llvm::reverse(Ns)) {
+ EXPECT_EQ(N, L.back());
+ L.pop_back();
+ }
+ EXPECT_TRUE(L.empty());
+}
+
+TEST(BumpPtrListTest, pushPopFront) {
+ // Build a list with push_front.
+ BumpPtrList<int> L;
+ int Ns[] = {1, 3, 9, 5, 7};
+ for (const int N : Ns)
+ L.push_front(N);
+
+ // Use reverse iterators to check contents.
+ auto I = L.rbegin();
+ for (int N : Ns)
+ EXPECT_EQ(N, *I++);
+ EXPECT_EQ(I, L.rend());
+
+ // Unbuild the list with pop_front.
+ for (int N : llvm::reverse(Ns)) {
+ EXPECT_EQ(N, L.front());
+ L.pop_front();
+ }
+ EXPECT_TRUE(L.empty());
+}
+
+TEST(BumpPtrListTest, pushBackMoveOnly) {
+ BumpPtrList<MoveOnly> L;
+ int Ns[] = {1, 3, 9, 5, 7};
+ for (const int N : Ns) {
+ L.push_back(MoveOnly(N));
+ EXPECT_EQ(N, L.back().V);
+ }
+ // Instantiate with MoveOnly.
+ while (!L.empty())
+ L.pop_back();
+}
+
+TEST(BumpPtrListTest, pushFrontMoveOnly) {
+ BumpPtrList<MoveOnly> L;
+ int Ns[] = {1, 3, 9, 5, 7};
+ for (const int N : Ns) {
+ L.push_front(MoveOnly(N));
+ EXPECT_EQ(N, L.front().V);
+ }
+ // Instantiate with MoveOnly.
+ while (!L.empty())
+ L.pop_front();
+}
+
+TEST(BumpPtrListTest, emplaceBack) {
+ BumpPtrList<EmplaceOnly> L;
+ int N1s[] = {1, 3, 9, 5, 7};
+ int N2s[] = {7, 3, 1, 8, 2};
+ for (int I = 0; I != 5; ++I) {
+ L.emplace_back(N1s[I], N2s[I]);
+ EXPECT_EQ(N1s[I], L.back().V1);
+ EXPECT_EQ(N2s[I], L.back().V2);
+ }
+ // Instantiate with EmplaceOnly.
+ while (!L.empty())
+ L.pop_back();
+}
+
+TEST(BumpPtrListTest, emplaceFront) {
+ BumpPtrList<EmplaceOnly> L;
+ int N1s[] = {1, 3, 9, 5, 7};
+ int N2s[] = {7, 3, 1, 8, 2};
+ for (int I = 0; I != 5; ++I) {
+ L.emplace_front(N1s[I], N2s[I]);
+ EXPECT_EQ(N1s[I], L.front().V1);
+ EXPECT_EQ(N2s[I], L.front().V2);
+ }
+ // Instantiate with EmplaceOnly.
+ while (!L.empty())
+ L.pop_front();
+}
+
+TEST(BumpPtrListTest, swap) {
+ // Build two lists with different lifetimes and swap them.
+ int N1s[] = {1, 3, 5, 7, 9};
+ int N2s[] = {2, 4, 6, 8, 10};
+
+ BumpPtrList<int> L1;
+ L1.insert(L1.end(), std::begin(N1s), std::end(N1s));
+ {
+ BumpPtrList<int> L2;
+ L2.insert(L2.end(), std::begin(N2s), std::end(N2s));
+
+ // Swap the lists.
+ L1.swap(L2);
+
+ // Check L2's contents before it goes out of scope.
+ auto I = L2.begin();
+ for (int N : N1s)
+ EXPECT_EQ(N, *I++);
+ EXPECT_EQ(I, L2.end());
+ }
+
+ // Check L1's contents now that L2 is out of scope (with its allocation
+ // blocks).
+ auto I = L1.begin();
+ for (int N : N2s)
+ EXPECT_EQ(N, *I++);
+ EXPECT_EQ(I, L1.end());
+}
+
+TEST(BumpPtrListTest, clear) {
+ CountsDestructors::NumCalls = 0;
+ CountsDestructors N;
+ BumpPtrList<CountsDestructors> L;
+ L.push_back(N);
+ L.push_back(N);
+ L.push_back(N);
+ EXPECT_EQ(3u, L.size());
+ EXPECT_EQ(0u, CountsDestructors::NumCalls);
+ L.pop_back();
+ EXPECT_EQ(1u, CountsDestructors::NumCalls);
+ L.clear();
+ EXPECT_EQ(3u, CountsDestructors::NumCalls);
+}
+
+TEST(BumpPtrListTest, move) {
+ BumpPtrList<int> L1, L2;
+ L1.push_back(1);
+ L2.push_back(2);
+ L1 = std::move(L2);
+ EXPECT_EQ(1u, L1.size());
+ EXPECT_EQ(2, L1.front());
+ EXPECT_EQ(0u, L2.size());
+}
+
+TEST(BumpPtrListTest, moveCallsDestructors) {
+ CountsDestructors::NumCalls = 0;
+ BumpPtrList<CountsDestructors> L1, L2;
+ L1.emplace_back();
+ EXPECT_EQ(0u, CountsDestructors::NumCalls);
+ L1 = std::move(L2);
+ EXPECT_EQ(1u, CountsDestructors::NumCalls);
+}
+
+TEST(BumpPtrListTest, copy) {
+ BumpPtrList<int> L1, L2;
+ L1.push_back(1);
+ L2.push_back(2);
+ L1 = L2;
+ EXPECT_EQ(1u, L1.size());
+ EXPECT_EQ(2, L1.front());
+ EXPECT_EQ(1u, L2.size());
+ EXPECT_EQ(2, L2.front());
+}
+
+TEST(BumpPtrListTest, copyCallsDestructors) {
+ CountsDestructors::NumCalls = 0;
+ BumpPtrList<CountsDestructors> L1, L2;
+ L1.emplace_back();
+ EXPECT_EQ(0u, CountsDestructors::NumCalls);
+ L1 = L2;
+ EXPECT_EQ(1u, CountsDestructors::NumCalls);
+}
+
+TEST(BumpPtrListTest, resetAlloc) {
+ // Resetting an empty list should work.
+ BumpPtrList<int> L;
+
+ // Resetting an empty list that has allocated should also work.
+ L.resetAlloc();
+ L.push_back(5);
+ L.erase(L.begin());
+ L.resetAlloc();
+
+ // Resetting a non-empty list should crash.
+ L.push_back(5);
+#if defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG)
+ EXPECT_DEATH(L.resetAlloc(), "Cannot reset allocator if not empty");
+#endif
+}
+
+} // end namespace
diff --git a/unittests/ADT/CMakeLists.txt b/unittests/ADT/CMakeLists.txt
index ca1644b5346e..738f6efe92d6 100644
--- a/unittests/ADT/CMakeLists.txt
+++ b/unittests/ADT/CMakeLists.txt
@@ -9,19 +9,27 @@ set(ADTSources
ArrayRefTest.cpp
BitmaskEnumTest.cpp
BitVectorTest.cpp
+ BumpPtrListTest.cpp
DAGDeltaAlgorithmTest.cpp
DeltaAlgorithmTest.cpp
DenseMapTest.cpp
DenseSetTest.cpp
+ DepthFirstIteratorTest.cpp
FoldingSet.cpp
FunctionRefTest.cpp
HashingTest.cpp
- ilistTest.cpp
+ IListBaseTest.cpp
+ IListIteratorTest.cpp
+ IListNodeBaseTest.cpp
+ IListNodeTest.cpp
+ IListSentinelTest.cpp
+ IListTest.cpp
ImmutableMapTest.cpp
ImmutableSetTest.cpp
IntEqClassesTest.cpp
IntervalMapTest.cpp
IntrusiveRefCntPtrTest.cpp
+ IteratorTest.cpp
MakeUniqueTest.cpp
MapVectorTest.cpp
OptionalTest.cpp
@@ -33,17 +41,23 @@ set(ADTSources
PostOrderIteratorTest.cpp
PriorityWorklistTest.cpp
RangeAdapterTest.cpp
+ ReverseIterationTest.cpp
SCCIteratorTest.cpp
+ STLExtrasTest.cpp
+ ScopeExitTest.cpp
SequenceTest.cpp
SetVectorTest.cpp
+ SimpleIListTest.cpp
SmallPtrSetTest.cpp
SmallStringTest.cpp
SmallVectorTest.cpp
SparseBitVectorTest.cpp
SparseMultiSetTest.cpp
SparseSetTest.cpp
+ StringExtrasTest.cpp
StringMapTest.cpp
StringRefTest.cpp
+ StringSwitchTest.cpp
TinyPtrVectorTest.cpp
TripleTest.cpp
TwineTest.cpp
diff --git a/unittests/ADT/DenseMapTest.cpp b/unittests/ADT/DenseMapTest.cpp
index db00f8cf8e57..80f0462bc8fb 100644
--- a/unittests/ADT/DenseMapTest.cpp
+++ b/unittests/ADT/DenseMapTest.cpp
@@ -496,55 +496,6 @@ TEST(DenseMapCustomTest, StringRefTest) {
EXPECT_EQ(42, M.lookup(StringRef("a", 0)));
}
-struct CachedHashTest {
- unsigned Val;
- unsigned *Counter = nullptr;
- CachedHashTest(unsigned Val) : Val(Val) {}
- CachedHashTest(unsigned Val, unsigned *Counter)
- : Val(Val), Counter(Counter) {}
-};
-}
-namespace llvm {
-template <> struct DenseMapInfo<CachedHashTest> {
- static CachedHashTest getEmptyKey() { return ~0; }
- static CachedHashTest getTombstoneKey() { return ~0U - 1; }
- static unsigned getHashValue(const CachedHashTest &X) {
- ++*X.Counter;
- return X.Val;
- }
- static bool isEqual(const CachedHashTest &LHS, const CachedHashTest &RHS) {
- return LHS.Val == RHS.Val;
- }
-};
-}
-namespace {
-
-TEST(DenseMapCustomTest, CachedHashTest) {
- unsigned Counter = 0;
- CachedHashTest Val(0, &Counter);
- DenseMap<CachedHashTest, int> Map;
-
- Map[Val] = 0;
- ASSERT_EQ(1u, Counter);
-
- Map.reserve(64);
- ASSERT_EQ(2u, Counter);
-}
-
-// Like above, but now cache the hash.
-TEST(DenseMapCustomTest, CachedHashTest2) {
- unsigned Counter = 0;
- CachedHashTest Val(0, &Counter);
- typedef CachedHash<CachedHashTest> Cached;
- DenseMap<Cached, int> Map;
-
- Map[Val] = 0;
- ASSERT_EQ(1u, Counter);
-
- Map.reserve(64);
- ASSERT_EQ(1u, Counter);
-}
-
// Key traits that allows lookup with either an unsigned or char* key;
// In the latter case, "a" == 0, "b" == 1 and so on.
struct TestDenseMapInfo {
@@ -619,4 +570,14 @@ TEST(DenseMapCustomTest, SmallDenseMapGrowTest) {
EXPECT_TRUE(map.find(32) == map.end());
}
+TEST(DenseMapCustomTest, TryEmplaceTest) {
+ DenseMap<int, std::unique_ptr<int>> Map;
+ std::unique_ptr<int> P(new int(2));
+ auto Try1 = Map.try_emplace(0, new int(1));
+ EXPECT_TRUE(Try1.second);
+ auto Try2 = Map.try_emplace(0, std::move(P));
+ EXPECT_FALSE(Try2.second);
+ EXPECT_EQ(Try1.first, Try2.first);
+ EXPECT_NE(nullptr, P);
+}
}
diff --git a/unittests/ADT/DenseSetTest.cpp b/unittests/ADT/DenseSetTest.cpp
index 5952353034fd..4d5a82902f0e 100644
--- a/unittests/ADT/DenseSetTest.cpp
+++ b/unittests/ADT/DenseSetTest.cpp
@@ -7,19 +7,16 @@
//
//===----------------------------------------------------------------------===//
-#include "gtest/gtest.h"
#include "llvm/ADT/DenseSet.h"
+#include "gtest/gtest.h"
+#include <type_traits>
using namespace llvm;
namespace {
-// Test fixture
-class DenseSetTest : public testing::Test {
-};
-
// Test hashing with a set of only two entries.
-TEST_F(DenseSetTest, DoubleEntrySetTest) {
+TEST(DenseSetTest, DoubleEntrySetTest) {
llvm::DenseSet<unsigned> set(2);
set.insert(0);
set.insert(1);
@@ -42,12 +39,48 @@ struct TestDenseSetInfo {
}
};
-TEST(DenseSetCustomTest, FindAsTest) {
- DenseSet<unsigned, TestDenseSetInfo> set;
- set.insert(0);
- set.insert(1);
- set.insert(2);
+// Test fixture
+template <typename T> class DenseSetTest : public testing::Test {
+protected:
+ T Set = GetTestSet();
+private:
+ static T GetTestSet() {
+ typename std::remove_const<T>::type Set;
+ Set.insert(0);
+ Set.insert(1);
+ Set.insert(2);
+ return Set;
+ }
+};
+
+// Register these types for testing.
+typedef ::testing::Types<DenseSet<unsigned, TestDenseSetInfo>,
+ const DenseSet<unsigned, TestDenseSetInfo>,
+ SmallDenseSet<unsigned, 1, TestDenseSetInfo>,
+ SmallDenseSet<unsigned, 4, TestDenseSetInfo>,
+ const SmallDenseSet<unsigned, 4, TestDenseSetInfo>,
+ SmallDenseSet<unsigned, 64, TestDenseSetInfo>>
+ DenseSetTestTypes;
+TYPED_TEST_CASE(DenseSetTest, DenseSetTestTypes);
+
+TYPED_TEST(DenseSetTest, InitializerList) {
+ TypeParam set({1, 2, 1, 4});
+ EXPECT_EQ(3u, set.size());
+ EXPECT_EQ(1u, set.count(1));
+ EXPECT_EQ(1u, set.count(2));
+ EXPECT_EQ(1u, set.count(4));
+ EXPECT_EQ(0u, set.count(3));
+}
+
+TYPED_TEST(DenseSetTest, EmptyInitializerList) {
+ TypeParam set({});
+ EXPECT_EQ(0u, set.size());
+ EXPECT_EQ(0u, set.count(0));
+}
+
+TYPED_TEST(DenseSetTest, FindAsTest) {
+ auto &set = this->Set;
// Size tests
EXPECT_EQ(3u, set.size());
@@ -65,4 +98,75 @@ TEST(DenseSetCustomTest, FindAsTest) {
EXPECT_TRUE(set.find_as("d") == set.end());
}
+// Simple class that counts how many moves and copy happens when growing a map
+struct CountCopyAndMove {
+ static int Move;
+ static int Copy;
+ int Value;
+ CountCopyAndMove(int Value) : Value(Value) {}
+
+ CountCopyAndMove(const CountCopyAndMove &RHS) {
+ Value = RHS.Value;
+ Copy++;
+ }
+ CountCopyAndMove &operator=(const CountCopyAndMove &RHS) {
+ Value = RHS.Value;
+ Copy++;
+ return *this;
+ }
+ CountCopyAndMove(CountCopyAndMove &&RHS) {
+ Value = RHS.Value;
+ Move++;
+ }
+ CountCopyAndMove &operator=(const CountCopyAndMove &&RHS) {
+ Value = RHS.Value;
+ Move++;
+ return *this;
+ }
+};
+int CountCopyAndMove::Copy = 0;
+int CountCopyAndMove::Move = 0;
+} // anonymous namespace
+
+namespace llvm {
+// Specialization required to insert a CountCopyAndMove into a DenseSet.
+template <> struct DenseMapInfo<CountCopyAndMove> {
+ static inline CountCopyAndMove getEmptyKey() { return CountCopyAndMove(-1); };
+ static inline CountCopyAndMove getTombstoneKey() {
+ return CountCopyAndMove(-2);
+ };
+ static unsigned getHashValue(const CountCopyAndMove &Val) {
+ return Val.Value;
+ }
+ static bool isEqual(const CountCopyAndMove &LHS,
+ const CountCopyAndMove &RHS) {
+ return LHS.Value == RHS.Value;
+ }
+};
+}
+
+namespace {
+// Make sure reserve actually gives us enough buckets to insert N items
+// without increasing allocation size.
+TEST(DenseSetCustomTest, ReserveTest) {
+ // Test a few different size, 48 is *not* a random choice: we need a value
+ // that is 2/3 of a power of two to stress the grow() condition, and the power
+ // of two has to be at least 64 because of minimum size allocation in the
+ // DenseMa. 66 is a value just above the 64 default init.
+ for (auto Size : {1, 2, 48, 66}) {
+ DenseSet<CountCopyAndMove> Set;
+ Set.reserve(Size);
+ unsigned MemorySize = Set.getMemorySize();
+ CountCopyAndMove::Copy = 0;
+ CountCopyAndMove::Move = 0;
+ for (int i = 0; i < Size; ++i)
+ Set.insert(CountCopyAndMove(i));
+ // Check that we didn't grow
+ EXPECT_EQ(MemorySize, Set.getMemorySize());
+ // Check that move was called the expected number of times
+ EXPECT_EQ(Size, CountCopyAndMove::Move);
+ // Check that no copy occured
+ EXPECT_EQ(0, CountCopyAndMove::Copy);
+ }
+}
}
diff --git a/unittests/ADT/DepthFirstIteratorTest.cpp b/unittests/ADT/DepthFirstIteratorTest.cpp
new file mode 100644
index 000000000000..463d6928bd5c
--- /dev/null
+++ b/unittests/ADT/DepthFirstIteratorTest.cpp
@@ -0,0 +1,54 @@
+//=== llvm/unittest/ADT/DepthFirstIteratorTest.cpp - DFS iterator tests ---===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "TestGraph.h"
+#include "llvm/ADT/DepthFirstIterator.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace llvm {
+
+template <typename T> struct CountedSet {
+ typedef typename SmallPtrSet<T, 4>::iterator iterator;
+
+ SmallPtrSet<T, 4> S;
+ int InsertVisited = 0;
+
+ std::pair<iterator, bool> insert(const T &Item) {
+ InsertVisited++;
+ return S.insert(Item);
+ }
+
+ size_t count(const T &Item) const { return S.count(Item); }
+
+ void completed(T) { }
+};
+
+template <typename T> class df_iterator_storage<CountedSet<T>, true> {
+public:
+ df_iterator_storage(CountedSet<T> &VSet) : Visited(VSet) {}
+
+ CountedSet<T> &Visited;
+};
+
+TEST(DepthFirstIteratorTest, ActuallyUpdateIterator) {
+ typedef CountedSet<Graph<3>::NodeType *> StorageT;
+ typedef df_iterator<Graph<3>, StorageT, true> DFIter;
+
+ Graph<3> G;
+ G.AddEdge(0, 1);
+ G.AddEdge(0, 2);
+ StorageT S;
+ for (auto N : make_range(DFIter::begin(G, S), DFIter::end(G, S)))
+ (void)N;
+
+ EXPECT_EQ(3, S.InsertVisited);
+}
+}
diff --git a/unittests/ADT/FoldingSet.cpp b/unittests/ADT/FoldingSet.cpp
index 927ef313cb93..696463881195 100644
--- a/unittests/ADT/FoldingSet.cpp
+++ b/unittests/ADT/FoldingSet.cpp
@@ -35,6 +35,27 @@ TEST(FoldingSetTest, UnalignedStringTest) {
EXPECT_EQ(a.ComputeHash(), b.ComputeHash());
}
+TEST(FoldingSetTest, LongLongComparison) {
+ struct LongLongContainer : FoldingSetNode {
+ unsigned long long A, B;
+ LongLongContainer(unsigned long long A, unsigned long long B)
+ : A(A), B(B) {}
+ void Profile(FoldingSetNodeID &ID) const {
+ ID.AddInteger(A);
+ ID.AddInteger(B);
+ }
+ };
+
+ LongLongContainer C1((1ULL << 32) + 1, 1ULL);
+ LongLongContainer C2(1ULL, (1ULL << 32) + 1);
+
+ FoldingSet<LongLongContainer> Set;
+
+ EXPECT_EQ(&C1, Set.GetOrInsertNode(&C1));
+ EXPECT_EQ(&C2, Set.GetOrInsertNode(&C2));
+ EXPECT_EQ(2U, Set.size());
+}
+
struct TrivialPair : public FoldingSetNode {
unsigned Key = 0;
unsigned Value = 0;
diff --git a/unittests/ADT/IListBaseTest.cpp b/unittests/ADT/IListBaseTest.cpp
new file mode 100644
index 000000000000..3b8ede801c56
--- /dev/null
+++ b/unittests/ADT/IListBaseTest.cpp
@@ -0,0 +1,166 @@
+//===- unittests/ADT/IListBaseTest.cpp - ilist_base unit tests ------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/ilist_base.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+
+// Test fixture.
+template <typename T> class IListBaseTest : public ::testing::Test {};
+
+// Test variants with the same test.
+typedef ::testing::Types<ilist_base<false>, ilist_base<true>>
+ IListBaseTestTypes;
+TYPED_TEST_CASE(IListBaseTest, IListBaseTestTypes);
+
+TYPED_TEST(IListBaseTest, insertBeforeImpl) {
+ typedef TypeParam list_base_type;
+ typedef typename list_base_type::node_base_type node_base_type;
+
+ node_base_type S, A, B;
+
+ // [S] <-> [S]
+ S.setPrev(&S);
+ S.setNext(&S);
+
+ // [S] <-> A <-> [S]
+ list_base_type::insertBeforeImpl(S, A);
+ EXPECT_EQ(&A, S.getPrev());
+ EXPECT_EQ(&S, A.getPrev());
+ EXPECT_EQ(&A, S.getNext());
+ EXPECT_EQ(&S, A.getNext());
+
+ // [S] <-> A <-> B <-> [S]
+ list_base_type::insertBeforeImpl(S, B);
+ EXPECT_EQ(&B, S.getPrev());
+ EXPECT_EQ(&A, B.getPrev());
+ EXPECT_EQ(&S, A.getPrev());
+ EXPECT_EQ(&A, S.getNext());
+ EXPECT_EQ(&B, A.getNext());
+ EXPECT_EQ(&S, B.getNext());
+}
+
+TYPED_TEST(IListBaseTest, removeImpl) {
+ typedef TypeParam list_base_type;
+ typedef typename list_base_type::node_base_type node_base_type;
+
+ node_base_type S, A, B;
+
+ // [S] <-> A <-> B <-> [S]
+ S.setPrev(&S);
+ S.setNext(&S);
+ list_base_type::insertBeforeImpl(S, A);
+ list_base_type::insertBeforeImpl(S, B);
+
+ // [S] <-> B <-> [S]
+ list_base_type::removeImpl(A);
+ EXPECT_EQ(&B, S.getPrev());
+ EXPECT_EQ(&S, B.getPrev());
+ EXPECT_EQ(&B, S.getNext());
+ EXPECT_EQ(&S, B.getNext());
+ EXPECT_EQ(nullptr, A.getPrev());
+ EXPECT_EQ(nullptr, A.getNext());
+
+ // [S] <-> [S]
+ list_base_type::removeImpl(B);
+ EXPECT_EQ(&S, S.getPrev());
+ EXPECT_EQ(&S, S.getNext());
+ EXPECT_EQ(nullptr, B.getPrev());
+ EXPECT_EQ(nullptr, B.getNext());
+}
+
+TYPED_TEST(IListBaseTest, removeRangeImpl) {
+ typedef TypeParam list_base_type;
+ typedef typename list_base_type::node_base_type node_base_type;
+
+ node_base_type S, A, B, C, D;
+
+ // [S] <-> A <-> B <-> C <-> D <-> [S]
+ S.setPrev(&S);
+ S.setNext(&S);
+ list_base_type::insertBeforeImpl(S, A);
+ list_base_type::insertBeforeImpl(S, B);
+ list_base_type::insertBeforeImpl(S, C);
+ list_base_type::insertBeforeImpl(S, D);
+
+ // [S] <-> A <-> D <-> [S]
+ list_base_type::removeRangeImpl(B, D);
+ EXPECT_EQ(&D, S.getPrev());
+ EXPECT_EQ(&A, D.getPrev());
+ EXPECT_EQ(&S, A.getPrev());
+ EXPECT_EQ(&A, S.getNext());
+ EXPECT_EQ(&D, A.getNext());
+ EXPECT_EQ(&S, D.getNext());
+ EXPECT_EQ(nullptr, B.getPrev());
+ EXPECT_EQ(nullptr, C.getNext());
+}
+
+TYPED_TEST(IListBaseTest, removeRangeImplAllButSentinel) {
+ typedef TypeParam list_base_type;
+ typedef typename list_base_type::node_base_type node_base_type;
+
+ node_base_type S, A, B;
+
+ // [S] <-> A <-> B <-> [S]
+ S.setPrev(&S);
+ S.setNext(&S);
+ list_base_type::insertBeforeImpl(S, A);
+ list_base_type::insertBeforeImpl(S, B);
+
+ // [S] <-> [S]
+ list_base_type::removeRangeImpl(A, S);
+ EXPECT_EQ(&S, S.getPrev());
+ EXPECT_EQ(&S, S.getNext());
+ EXPECT_EQ(nullptr, A.getPrev());
+ EXPECT_EQ(nullptr, B.getNext());
+}
+
+TYPED_TEST(IListBaseTest, transferBeforeImpl) {
+ typedef TypeParam list_base_type;
+ typedef typename list_base_type::node_base_type node_base_type;
+
+ node_base_type S1, S2, A, B, C, D, E;
+
+ // [S1] <-> A <-> B <-> C <-> [S1]
+ S1.setPrev(&S1);
+ S1.setNext(&S1);
+ list_base_type::insertBeforeImpl(S1, A);
+ list_base_type::insertBeforeImpl(S1, B);
+ list_base_type::insertBeforeImpl(S1, C);
+
+ // [S2] <-> D <-> E <-> [S2]
+ S2.setPrev(&S2);
+ S2.setNext(&S2);
+ list_base_type::insertBeforeImpl(S2, D);
+ list_base_type::insertBeforeImpl(S2, E);
+
+ // [S1] <-> C <-> [S1]
+ list_base_type::transferBeforeImpl(D, A, C);
+ EXPECT_EQ(&C, S1.getPrev());
+ EXPECT_EQ(&S1, C.getPrev());
+ EXPECT_EQ(&C, S1.getNext());
+ EXPECT_EQ(&S1, C.getNext());
+
+ // [S2] <-> A <-> B <-> D <-> E <-> [S2]
+ EXPECT_EQ(&E, S2.getPrev());
+ EXPECT_EQ(&D, E.getPrev());
+ EXPECT_EQ(&B, D.getPrev());
+ EXPECT_EQ(&A, B.getPrev());
+ EXPECT_EQ(&S2, A.getPrev());
+ EXPECT_EQ(&A, S2.getNext());
+ EXPECT_EQ(&B, A.getNext());
+ EXPECT_EQ(&D, B.getNext());
+ EXPECT_EQ(&E, D.getNext());
+ EXPECT_EQ(&S2, E.getNext());
+}
+
+} // end namespace
diff --git a/unittests/ADT/IListIteratorTest.cpp b/unittests/ADT/IListIteratorTest.cpp
new file mode 100644
index 000000000000..ddcab781b9ba
--- /dev/null
+++ b/unittests/ADT/IListIteratorTest.cpp
@@ -0,0 +1,134 @@
+//===- unittests/ADT/IListIteratorTest.cpp - ilist_iterator unit tests ----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/simple_ilist.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+
+struct Node : ilist_node<Node> {};
+
+TEST(IListIteratorTest, DefaultConstructor) {
+ simple_ilist<Node>::iterator I;
+ simple_ilist<Node>::reverse_iterator RI;
+ simple_ilist<Node>::const_iterator CI;
+ simple_ilist<Node>::const_reverse_iterator CRI;
+ EXPECT_EQ(nullptr, I.getNodePtr());
+ EXPECT_EQ(nullptr, CI.getNodePtr());
+ EXPECT_EQ(nullptr, RI.getNodePtr());
+ EXPECT_EQ(nullptr, CRI.getNodePtr());
+ EXPECT_EQ(I, I);
+ EXPECT_EQ(I, CI);
+ EXPECT_EQ(CI, I);
+ EXPECT_EQ(CI, CI);
+ EXPECT_EQ(RI, RI);
+ EXPECT_EQ(RI, CRI);
+ EXPECT_EQ(CRI, RI);
+ EXPECT_EQ(CRI, CRI);
+ EXPECT_EQ(I, RI.getReverse());
+ EXPECT_EQ(RI, I.getReverse());
+}
+
+TEST(IListIteratorTest, Empty) {
+ simple_ilist<Node> L;
+
+ // Check iterators of L.
+ EXPECT_EQ(L.begin(), L.end());
+ EXPECT_EQ(L.rbegin(), L.rend());
+
+ // Reverse of end should be rend (since the sentinel sits on both sides).
+ EXPECT_EQ(L.end(), L.rend().getReverse());
+ EXPECT_EQ(L.rend(), L.end().getReverse());
+
+ // Iterators shouldn't match default constructors.
+ simple_ilist<Node>::iterator I;
+ simple_ilist<Node>::reverse_iterator RI;
+ EXPECT_NE(I, L.begin());
+ EXPECT_NE(I, L.end());
+ EXPECT_NE(RI, L.rbegin());
+ EXPECT_NE(RI, L.rend());
+}
+
+TEST(IListIteratorTest, OneNodeList) {
+ simple_ilist<Node> L;
+ Node A;
+ L.insert(L.end(), A);
+
+ // Check address of reference.
+ EXPECT_EQ(&A, &*L.begin());
+ EXPECT_EQ(&A, &*L.rbegin());
+
+ // Check that the handle matches.
+ EXPECT_EQ(L.rbegin().getNodePtr(), L.begin().getNodePtr());
+
+ // Check iteration.
+ EXPECT_EQ(L.end(), ++L.begin());
+ EXPECT_EQ(L.begin(), --L.end());
+ EXPECT_EQ(L.rend(), ++L.rbegin());
+ EXPECT_EQ(L.rbegin(), --L.rend());
+
+ // Check conversions.
+ EXPECT_EQ(L.rbegin(), L.begin().getReverse());
+ EXPECT_EQ(L.begin(), L.rbegin().getReverse());
+}
+
+TEST(IListIteratorTest, TwoNodeList) {
+ simple_ilist<Node> L;
+ Node A, B;
+ L.insert(L.end(), A);
+ L.insert(L.end(), B);
+
+ // Check order.
+ EXPECT_EQ(&A, &*L.begin());
+ EXPECT_EQ(&B, &*++L.begin());
+ EXPECT_EQ(L.end(), ++++L.begin());
+ EXPECT_EQ(&B, &*L.rbegin());
+ EXPECT_EQ(&A, &*++L.rbegin());
+ EXPECT_EQ(L.rend(), ++++L.rbegin());
+
+ // Check conversions.
+ EXPECT_EQ(++L.rbegin(), L.begin().getReverse());
+ EXPECT_EQ(L.rbegin(), (++L.begin()).getReverse());
+ EXPECT_EQ(++L.begin(), L.rbegin().getReverse());
+ EXPECT_EQ(L.begin(), (++L.rbegin()).getReverse());
+}
+
+TEST(IListIteratorTest, CheckEraseForward) {
+ simple_ilist<Node> L;
+ Node A, B;
+ L.insert(L.end(), A);
+ L.insert(L.end(), B);
+
+ // Erase nodes.
+ auto I = L.begin();
+ EXPECT_EQ(&A, &*I);
+ L.remove(*I++);
+ EXPECT_EQ(&B, &*I);
+ L.remove(*I++);
+ EXPECT_EQ(L.end(), I);
+}
+
+TEST(IListIteratorTest, CheckEraseReverse) {
+ simple_ilist<Node> L;
+ Node A, B;
+ L.insert(L.end(), A);
+ L.insert(L.end(), B);
+
+ // Erase nodes.
+ auto RI = L.rbegin();
+ EXPECT_EQ(&B, &*RI);
+ L.remove(*RI++);
+ EXPECT_EQ(&A, &*RI);
+ L.remove(*RI++);
+ EXPECT_EQ(L.rend(), RI);
+}
+
+} // end namespace
diff --git a/unittests/ADT/IListNodeBaseTest.cpp b/unittests/ADT/IListNodeBaseTest.cpp
new file mode 100644
index 000000000000..8819ab118a59
--- /dev/null
+++ b/unittests/ADT/IListNodeBaseTest.cpp
@@ -0,0 +1,100 @@
+//===- unittests/ADT/IListNodeBaseTest.cpp - ilist_node_base unit tests ---===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/ilist_node_base.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+
+typedef ilist_node_base<false> RawNode;
+typedef ilist_node_base<true> TrackingNode;
+
+TEST(IListNodeBaseTest, DefaultConstructor) {
+ RawNode A;
+ EXPECT_EQ(nullptr, A.getPrev());
+ EXPECT_EQ(nullptr, A.getNext());
+ EXPECT_FALSE(A.isKnownSentinel());
+
+ TrackingNode TA;
+ EXPECT_EQ(nullptr, TA.getPrev());
+ EXPECT_EQ(nullptr, TA.getNext());
+ EXPECT_FALSE(TA.isKnownSentinel());
+ EXPECT_FALSE(TA.isSentinel());
+}
+
+TEST(IListNodeBaseTest, setPrevAndNext) {
+ RawNode A, B, C;
+ A.setPrev(&B);
+ EXPECT_EQ(&B, A.getPrev());
+ EXPECT_EQ(nullptr, A.getNext());
+ EXPECT_EQ(nullptr, B.getPrev());
+ EXPECT_EQ(nullptr, B.getNext());
+ EXPECT_EQ(nullptr, C.getPrev());
+ EXPECT_EQ(nullptr, C.getNext());
+
+ A.setNext(&C);
+ EXPECT_EQ(&B, A.getPrev());
+ EXPECT_EQ(&C, A.getNext());
+ EXPECT_EQ(nullptr, B.getPrev());
+ EXPECT_EQ(nullptr, B.getNext());
+ EXPECT_EQ(nullptr, C.getPrev());
+ EXPECT_EQ(nullptr, C.getNext());
+
+ TrackingNode TA, TB, TC;
+ TA.setPrev(&TB);
+ EXPECT_EQ(&TB, TA.getPrev());
+ EXPECT_EQ(nullptr, TA.getNext());
+ EXPECT_EQ(nullptr, TB.getPrev());
+ EXPECT_EQ(nullptr, TB.getNext());
+ EXPECT_EQ(nullptr, TC.getPrev());
+ EXPECT_EQ(nullptr, TC.getNext());
+
+ TA.setNext(&TC);
+ EXPECT_EQ(&TB, TA.getPrev());
+ EXPECT_EQ(&TC, TA.getNext());
+ EXPECT_EQ(nullptr, TB.getPrev());
+ EXPECT_EQ(nullptr, TB.getNext());
+ EXPECT_EQ(nullptr, TC.getPrev());
+ EXPECT_EQ(nullptr, TC.getNext());
+}
+
+TEST(IListNodeBaseTest, isKnownSentinel) {
+ // Without sentinel tracking.
+ RawNode A, B;
+ EXPECT_FALSE(A.isKnownSentinel());
+ A.setPrev(&B);
+ A.setNext(&B);
+ EXPECT_EQ(&B, A.getPrev());
+ EXPECT_EQ(&B, A.getNext());
+ EXPECT_FALSE(A.isKnownSentinel());
+ A.initializeSentinel();
+ EXPECT_FALSE(A.isKnownSentinel());
+ EXPECT_EQ(&B, A.getPrev());
+ EXPECT_EQ(&B, A.getNext());
+
+ // With sentinel tracking.
+ TrackingNode TA, TB;
+ EXPECT_FALSE(TA.isKnownSentinel());
+ EXPECT_FALSE(TA.isSentinel());
+ TA.setPrev(&TB);
+ TA.setNext(&TB);
+ EXPECT_EQ(&TB, TA.getPrev());
+ EXPECT_EQ(&TB, TA.getNext());
+ EXPECT_FALSE(TA.isKnownSentinel());
+ EXPECT_FALSE(TA.isSentinel());
+ TA.initializeSentinel();
+ EXPECT_TRUE(TA.isKnownSentinel());
+ EXPECT_TRUE(TA.isSentinel());
+ EXPECT_EQ(&TB, TA.getPrev());
+ EXPECT_EQ(&TB, TA.getNext());
+}
+
+} // end namespace
diff --git a/unittests/ADT/IListNodeTest.cpp b/unittests/ADT/IListNodeTest.cpp
new file mode 100644
index 000000000000..51bebc21ce65
--- /dev/null
+++ b/unittests/ADT/IListNodeTest.cpp
@@ -0,0 +1,70 @@
+//===- unittests/ADT/IListNodeTest.cpp - ilist_node unit tests ------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/ilist_node.h"
+#include "gtest/gtest.h"
+#include <type_traits>
+
+using namespace llvm;
+using namespace llvm::ilist_detail;
+
+namespace {
+
+struct Node;
+
+struct TagA {};
+struct TagB {};
+
+TEST(IListNodeTest, Options) {
+ static_assert(
+ std::is_same<compute_node_options<Node>::type,
+ compute_node_options<Node, ilist_tag<void>>::type>::value,
+ "default tag is void");
+ static_assert(
+ !std::is_same<compute_node_options<Node, ilist_tag<TagA>>::type,
+ compute_node_options<Node, ilist_tag<void>>::type>::value,
+ "default tag is void, different from TagA");
+ static_assert(
+ !std::is_same<compute_node_options<Node, ilist_tag<TagA>>::type,
+ compute_node_options<Node, ilist_tag<TagB>>::type>::value,
+ "TagA is not TagB");
+ static_assert(
+ std::is_same<
+ compute_node_options<Node, ilist_sentinel_tracking<false>>::type,
+ compute_node_options<Node, ilist_sentinel_tracking<false>,
+ ilist_tag<void>>::type>::value,
+ "default tag is void, even with sentinel tracking off");
+ static_assert(
+ std::is_same<
+ compute_node_options<Node, ilist_sentinel_tracking<false>>::type,
+ compute_node_options<Node, ilist_tag<void>,
+ ilist_sentinel_tracking<false>>::type>::value,
+ "order shouldn't matter");
+ static_assert(
+ std::is_same<
+ compute_node_options<Node, ilist_sentinel_tracking<true>>::type,
+ compute_node_options<Node, ilist_sentinel_tracking<true>,
+ ilist_tag<void>>::type>::value,
+ "default tag is void, even with sentinel tracking on");
+ static_assert(
+ std::is_same<
+ compute_node_options<Node, ilist_sentinel_tracking<true>>::type,
+ compute_node_options<Node, ilist_tag<void>,
+ ilist_sentinel_tracking<true>>::type>::value,
+ "order shouldn't matter");
+ static_assert(
+ std::is_same<
+ compute_node_options<Node, ilist_sentinel_tracking<true>,
+ ilist_tag<TagA>>::type,
+ compute_node_options<Node, ilist_tag<TagA>,
+ ilist_sentinel_tracking<true>>::type>::value,
+ "order shouldn't matter with real tags");
+}
+
+} // end namespace
diff --git a/unittests/ADT/IListSentinelTest.cpp b/unittests/ADT/IListSentinelTest.cpp
new file mode 100644
index 000000000000..bd60c909de78
--- /dev/null
+++ b/unittests/ADT/IListSentinelTest.cpp
@@ -0,0 +1,63 @@
+//===- unittests/ADT/IListSentinelTest.cpp - ilist_sentinel unit tests ----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/ilist_node.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+
+template <class T, class... Options> struct PickSentinel {
+ typedef ilist_sentinel<
+ typename ilist_detail::compute_node_options<T, Options...>::type>
+ type;
+};
+
+class Node : public ilist_node<Node> {};
+class TrackingNode : public ilist_node<Node, ilist_sentinel_tracking<true>> {};
+typedef PickSentinel<Node>::type Sentinel;
+typedef PickSentinel<Node, ilist_sentinel_tracking<true>>::type
+ TrackingSentinel;
+typedef PickSentinel<Node, ilist_sentinel_tracking<false>>::type
+ NoTrackingSentinel;
+
+struct LocalAccess : ilist_detail::NodeAccess {
+ using NodeAccess::getPrev;
+ using NodeAccess::getNext;
+};
+
+TEST(IListSentinelTest, DefaultConstructor) {
+ Sentinel S;
+ EXPECT_EQ(&S, LocalAccess::getPrev(S));
+ EXPECT_EQ(&S, LocalAccess::getNext(S));
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+ EXPECT_TRUE(S.isKnownSentinel());
+#else
+ EXPECT_FALSE(S.isKnownSentinel());
+#endif
+
+ TrackingSentinel TS;
+ NoTrackingSentinel NTS;
+ EXPECT_TRUE(TS.isSentinel());
+ EXPECT_TRUE(TS.isKnownSentinel());
+ EXPECT_FALSE(NTS.isKnownSentinel());
+}
+
+TEST(IListSentinelTest, NormalNodeIsNotKnownSentinel) {
+ Node N;
+ EXPECT_EQ(nullptr, LocalAccess::getPrev(N));
+ EXPECT_EQ(nullptr, LocalAccess::getNext(N));
+ EXPECT_FALSE(N.isKnownSentinel());
+
+ TrackingNode TN;
+ EXPECT_FALSE(TN.isSentinel());
+}
+
+} // end namespace
diff --git a/unittests/ADT/IListTest.cpp b/unittests/ADT/IListTest.cpp
new file mode 100644
index 000000000000..0dee4c10f68f
--- /dev/null
+++ b/unittests/ADT/IListTest.cpp
@@ -0,0 +1,276 @@
+//===- unittests/ADT/IListTest.cpp - ilist unit tests ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/ilist.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/ilist_node.h"
+#include "gtest/gtest.h"
+#include <ostream>
+
+using namespace llvm;
+
+namespace {
+
+struct Node : ilist_node<Node> {
+ int Value;
+
+ Node() {}
+ Node(int Value) : Value(Value) {}
+ Node(const Node&) = default;
+ ~Node() { Value = -1; }
+};
+
+TEST(IListTest, Basic) {
+ ilist<Node> List;
+ List.push_back(new Node(1));
+ EXPECT_EQ(1, List.back().Value);
+ EXPECT_EQ(nullptr, List.getPrevNode(List.back()));
+ EXPECT_EQ(nullptr, List.getNextNode(List.back()));
+
+ List.push_back(new Node(2));
+ EXPECT_EQ(2, List.back().Value);
+ EXPECT_EQ(2, List.getNextNode(List.front())->Value);
+ EXPECT_EQ(1, List.getPrevNode(List.back())->Value);
+
+ const ilist<Node> &ConstList = List;
+ EXPECT_EQ(2, ConstList.back().Value);
+ EXPECT_EQ(2, ConstList.getNextNode(ConstList.front())->Value);
+ EXPECT_EQ(1, ConstList.getPrevNode(ConstList.back())->Value);
+}
+
+TEST(IListTest, cloneFrom) {
+ Node L1Nodes[] = {Node(0), Node(1)};
+ Node L2Nodes[] = {Node(0), Node(1)};
+ ilist<Node> L1, L2, L3;
+
+ // Build L1 from L1Nodes.
+ L1.push_back(&L1Nodes[0]);
+ L1.push_back(&L1Nodes[1]);
+
+ // Build L2 from L2Nodes, based on L1 nodes.
+ L2.cloneFrom(L1, [&](const Node &N) { return &L2Nodes[N.Value]; });
+
+ // Add a node to L3 to be deleted, and then rebuild L3 by copying L1.
+ L3.push_back(new Node(7));
+ L3.cloneFrom(L1, [](const Node &N) { return new Node(N); });
+
+ EXPECT_EQ(2u, L1.size());
+ EXPECT_EQ(&L1Nodes[0], &L1.front());
+ EXPECT_EQ(&L1Nodes[1], &L1.back());
+ EXPECT_EQ(2u, L2.size());
+ EXPECT_EQ(&L2Nodes[0], &L2.front());
+ EXPECT_EQ(&L2Nodes[1], &L2.back());
+ EXPECT_EQ(2u, L3.size());
+ EXPECT_EQ(0, L3.front().Value);
+ EXPECT_EQ(1, L3.back().Value);
+
+ // Don't free nodes on the stack.
+ L1.clearAndLeakNodesUnsafely();
+ L2.clearAndLeakNodesUnsafely();
+}
+
+TEST(IListTest, SpliceOne) {
+ ilist<Node> List;
+ List.push_back(new Node(1));
+
+ // The single-element splice operation supports noops.
+ List.splice(List.begin(), List, List.begin());
+ EXPECT_EQ(1u, List.size());
+ EXPECT_EQ(1, List.front().Value);
+ EXPECT_TRUE(std::next(List.begin()) == List.end());
+
+ // Altenative noop. Move the first element behind itself.
+ List.push_back(new Node(2));
+ List.push_back(new Node(3));
+ List.splice(std::next(List.begin()), List, List.begin());
+ EXPECT_EQ(3u, List.size());
+ EXPECT_EQ(1, List.front().Value);
+ EXPECT_EQ(2, std::next(List.begin())->Value);
+ EXPECT_EQ(3, List.back().Value);
+}
+
+TEST(IListTest, SpliceSwap) {
+ ilist<Node> L;
+ Node N0(0);
+ Node N1(1);
+ L.insert(L.end(), &N0);
+ L.insert(L.end(), &N1);
+ EXPECT_EQ(0, L.front().Value);
+ EXPECT_EQ(1, L.back().Value);
+
+ L.splice(L.begin(), L, ++L.begin());
+ EXPECT_EQ(1, L.front().Value);
+ EXPECT_EQ(0, L.back().Value);
+
+ L.clearAndLeakNodesUnsafely();
+}
+
+TEST(IListTest, SpliceSwapOtherWay) {
+ ilist<Node> L;
+ Node N0(0);
+ Node N1(1);
+ L.insert(L.end(), &N0);
+ L.insert(L.end(), &N1);
+ EXPECT_EQ(0, L.front().Value);
+ EXPECT_EQ(1, L.back().Value);
+
+ L.splice(L.end(), L, L.begin());
+ EXPECT_EQ(1, L.front().Value);
+ EXPECT_EQ(0, L.back().Value);
+
+ L.clearAndLeakNodesUnsafely();
+}
+
+TEST(IListTest, UnsafeClear) {
+ ilist<Node> List;
+
+ // Before even allocating a sentinel.
+ List.clearAndLeakNodesUnsafely();
+ EXPECT_EQ(0u, List.size());
+
+ // Empty list with sentinel.
+ ilist<Node>::iterator E = List.end();
+ List.clearAndLeakNodesUnsafely();
+ EXPECT_EQ(0u, List.size());
+ // The sentinel shouldn't change.
+ EXPECT_TRUE(E == List.end());
+
+ // List with contents.
+ List.push_back(new Node(1));
+ ASSERT_EQ(1u, List.size());
+ Node *N = &*List.begin();
+ EXPECT_EQ(1, N->Value);
+ List.clearAndLeakNodesUnsafely();
+ EXPECT_EQ(0u, List.size());
+ ASSERT_EQ(1, N->Value);
+ delete N;
+
+ // List is still functional.
+ List.push_back(new Node(5));
+ List.push_back(new Node(6));
+ ASSERT_EQ(2u, List.size());
+ EXPECT_EQ(5, List.front().Value);
+ EXPECT_EQ(6, List.back().Value);
+}
+
+struct Empty {};
+TEST(IListTest, HasObsoleteCustomizationTrait) {
+ // Negative test for HasObsoleteCustomization.
+ static_assert(!ilist_detail::HasObsoleteCustomization<Empty, Node>::value,
+ "Empty has no customizations");
+}
+
+struct GetNext {
+ Node *getNext(Node *);
+};
+TEST(IListTest, HasGetNextTrait) {
+ static_assert(ilist_detail::HasGetNext<GetNext, Node>::value,
+ "GetNext has a getNext(Node*)");
+ static_assert(ilist_detail::HasObsoleteCustomization<GetNext, Node>::value,
+ "Empty should be obsolete because of getNext()");
+
+ // Negative test for HasGetNext.
+ static_assert(!ilist_detail::HasGetNext<Empty, Node>::value,
+ "Empty does not have a getNext(Node*)");
+}
+
+struct CreateSentinel {
+ Node *createSentinel();
+};
+TEST(IListTest, HasCreateSentinelTrait) {
+ static_assert(ilist_detail::HasCreateSentinel<CreateSentinel>::value,
+ "CreateSentinel has a getNext(Node*)");
+ static_assert(
+ ilist_detail::HasObsoleteCustomization<CreateSentinel, Node>::value,
+ "Empty should be obsolete because of createSentinel()");
+
+ // Negative test for HasCreateSentinel.
+ static_assert(!ilist_detail::HasCreateSentinel<Empty>::value,
+ "Empty does not have a createSentinel()");
+}
+
+struct NodeWithCallback : ilist_node<NodeWithCallback> {
+ int Value = 0;
+ bool IsInList = false;
+ bool WasTransferred = false;
+
+ NodeWithCallback() = default;
+ NodeWithCallback(int Value) : Value(Value) {}
+ NodeWithCallback(const NodeWithCallback &) = delete;
+};
+
+} // end namespace
+
+namespace llvm {
+template <> struct ilist_callback_traits<NodeWithCallback> {
+ void addNodeToList(NodeWithCallback *N) { N->IsInList = true; }
+ void removeNodeFromList(NodeWithCallback *N) { N->IsInList = false; }
+ template <class Iterator>
+ void transferNodesFromList(ilist_callback_traits &Other, Iterator First,
+ Iterator Last) {
+ for (; First != Last; ++First) {
+ First->WasTransferred = true;
+ Other.removeNodeFromList(&*First);
+ addNodeToList(&*First);
+ }
+ }
+};
+} // end namespace llvm
+
+namespace {
+
+TEST(IListTest, addNodeToList) {
+ ilist<NodeWithCallback> L1, L2;
+ NodeWithCallback N(7);
+ ASSERT_FALSE(N.IsInList);
+ ASSERT_FALSE(N.WasTransferred);
+
+ L1.insert(L1.begin(), &N);
+ ASSERT_EQ(1u, L1.size());
+ ASSERT_EQ(&N, &L1.front());
+ ASSERT_TRUE(N.IsInList);
+ ASSERT_FALSE(N.WasTransferred);
+
+ L2.splice(L2.end(), L1);
+ ASSERT_EQ(&N, &L2.front());
+ ASSERT_TRUE(N.IsInList);
+ ASSERT_TRUE(N.WasTransferred);
+
+ L1.remove(&N);
+ ASSERT_EQ(0u, L1.size());
+ ASSERT_FALSE(N.IsInList);
+ ASSERT_TRUE(N.WasTransferred);
+}
+
+struct PrivateNode : private ilist_node<PrivateNode> {
+ friend struct llvm::ilist_detail::NodeAccess;
+
+ int Value = 0;
+
+ PrivateNode() = default;
+ PrivateNode(int Value) : Value(Value) {}
+ PrivateNode(const PrivateNode &) = delete;
+};
+
+TEST(IListTest, privateNode) {
+ // Instantiate various APIs to be sure they're callable when ilist_node is
+ // inherited privately.
+ ilist<PrivateNode> L;
+ PrivateNode N(7);
+ L.insert(L.begin(), &N);
+ ++L.begin();
+ (void)*L.begin();
+ (void)(L.begin() == L.end());
+
+ ilist<PrivateNode> L2;
+ L2.splice(L2.end(), L);
+ L2.remove(&N);
+}
+
+} // end namespace
diff --git a/unittests/ADT/IntervalMapTest.cpp b/unittests/ADT/IntervalMapTest.cpp
index b5556d265ae4..11f13752f310 100644
--- a/unittests/ADT/IntervalMapTest.cpp
+++ b/unittests/ADT/IntervalMapTest.cpp
@@ -15,6 +15,8 @@ using namespace llvm;
namespace {
typedef IntervalMap<unsigned, unsigned, 4> UUMap;
+typedef IntervalMap<unsigned, unsigned, 4,
+ IntervalMapHalfOpenInfo<unsigned>> UUHalfOpenMap;
// Empty map tests
TEST(IntervalMapTest, EmptyMap) {
@@ -125,18 +127,63 @@ TEST(IntervalMapTest, SingleEntryMap) {
EXPECT_EQ(200u, I.stop());
EXPECT_EQ(2u, I.value());
+ // Shrink the interval to have a length of 1
+ I.setStop(150);
+ ASSERT_TRUE(I.valid());
+ EXPECT_EQ(150u, I.start());
+ EXPECT_EQ(150u, I.stop());
+ EXPECT_EQ(2u, I.value());
+
I.setStop(160);
ASSERT_TRUE(I.valid());
EXPECT_EQ(150u, I.start());
EXPECT_EQ(160u, I.stop());
EXPECT_EQ(2u, I.value());
+ // Shrink the interval to have a length of 1
+ I.setStart(160);
+ ASSERT_TRUE(I.valid());
+ EXPECT_EQ(160u, I.start());
+ EXPECT_EQ(160u, I.stop());
+ EXPECT_EQ(2u, I.value());
+
// Erase last elem.
I.erase();
EXPECT_TRUE(map.empty());
EXPECT_EQ(0, std::distance(map.begin(), map.end()));
}
+// Single entry half-open map tests
+TEST(IntervalMapTest, SingleEntryHalfOpenMap) {
+ UUHalfOpenMap::Allocator allocator;
+ UUHalfOpenMap map(allocator);
+ map.insert(100, 150, 1);
+ EXPECT_FALSE(map.empty());
+
+ UUHalfOpenMap::iterator I = map.begin();
+ ASSERT_TRUE(I.valid());
+
+ // Shrink the interval to have a length of 1
+ I.setStart(149);
+ ASSERT_TRUE(I.valid());
+ EXPECT_EQ(149u, I.start());
+ EXPECT_EQ(150u, I.stop());
+ EXPECT_EQ(1u, I.value());
+
+ I.setStop(160);
+ ASSERT_TRUE(I.valid());
+ EXPECT_EQ(149u, I.start());
+ EXPECT_EQ(160u, I.stop());
+ EXPECT_EQ(1u, I.value());
+
+ // Shrink the interval to have a length of 1
+ I.setStop(150);
+ ASSERT_TRUE(I.valid());
+ EXPECT_EQ(149u, I.start());
+ EXPECT_EQ(150u, I.stop());
+ EXPECT_EQ(1u, I.value());
+}
+
// Flat coalescing tests.
TEST(IntervalMapTest, RootCoalescing) {
UUMap::Allocator allocator;
diff --git a/unittests/ADT/IntrusiveRefCntPtrTest.cpp b/unittests/ADT/IntrusiveRefCntPtrTest.cpp
index c67ec130912d..143a8cc49107 100644
--- a/unittests/ADT/IntrusiveRefCntPtrTest.cpp
+++ b/unittests/ADT/IntrusiveRefCntPtrTest.cpp
@@ -10,30 +10,29 @@
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "gtest/gtest.h"
-namespace {
-struct VirtualRefCounted : public llvm::RefCountedBaseVPTR {
- virtual void f() {}
-};
-}
-
namespace llvm {
-// Run this test with valgrind to detect memory leaks.
-TEST(IntrusiveRefCntPtr, RefCountedBaseVPTRCopyDoesNotLeak) {
- VirtualRefCounted *V1 = new VirtualRefCounted;
- IntrusiveRefCntPtr<VirtualRefCounted> R1 = V1;
- VirtualRefCounted *V2 = new VirtualRefCounted(*V1);
- IntrusiveRefCntPtr<VirtualRefCounted> R2 = V2;
-}
+namespace {
+struct SimpleRefCounted : public RefCountedBase<SimpleRefCounted> {
+ SimpleRefCounted() { ++NumInstances; }
+ SimpleRefCounted(const SimpleRefCounted &) { ++NumInstances; }
+ ~SimpleRefCounted() { --NumInstances; }
-struct SimpleRefCounted : public RefCountedBase<SimpleRefCounted> {};
+ static int NumInstances;
+};
+int SimpleRefCounted::NumInstances = 0;
+} // anonymous namespace
-// Run this test with valgrind to detect memory leaks.
TEST(IntrusiveRefCntPtr, RefCountedBaseCopyDoesNotLeak) {
- SimpleRefCounted *S1 = new SimpleRefCounted;
- IntrusiveRefCntPtr<SimpleRefCounted> R1 = S1;
- SimpleRefCounted *S2 = new SimpleRefCounted(*S1);
- IntrusiveRefCntPtr<SimpleRefCounted> R2 = S2;
+ EXPECT_EQ(0, SimpleRefCounted::NumInstances);
+ {
+ SimpleRefCounted *S1 = new SimpleRefCounted;
+ IntrusiveRefCntPtr<SimpleRefCounted> R1 = S1;
+ SimpleRefCounted *S2 = new SimpleRefCounted(*S1);
+ IntrusiveRefCntPtr<SimpleRefCounted> R2 = S2;
+ EXPECT_EQ(2, SimpleRefCounted::NumInstances);
+ }
+ EXPECT_EQ(0, SimpleRefCounted::NumInstances);
}
struct InterceptRefCounted : public RefCountedBase<InterceptRefCounted> {
diff --git a/unittests/Support/IteratorTest.cpp b/unittests/ADT/IteratorTest.cpp
index 63dfa2a9d011..a8d5b33a0b49 100644
--- a/unittests/Support/IteratorTest.cpp
+++ b/unittests/ADT/IteratorTest.cpp
@@ -185,4 +185,91 @@ TEST(FilterIteratorTest, InputIterator) {
EXPECT_EQ((SmallVector<int, 3>{1, 3, 5}), Actual);
}
+TEST(PointerIterator, Basic) {
+ int A[] = {1, 2, 3, 4};
+ pointer_iterator<int *> Begin(std::begin(A)), End(std::end(A));
+ EXPECT_EQ(A, *Begin);
+ ++Begin;
+ EXPECT_EQ(A + 1, *Begin);
+ ++Begin;
+ EXPECT_EQ(A + 2, *Begin);
+ ++Begin;
+ EXPECT_EQ(A + 3, *Begin);
+ ++Begin;
+ EXPECT_EQ(Begin, End);
+}
+
+TEST(PointerIterator, Const) {
+ int A[] = {1, 2, 3, 4};
+ const pointer_iterator<int *> Begin(std::begin(A));
+ EXPECT_EQ(A, *Begin);
+ EXPECT_EQ(A + 1, std::next(*Begin, 1));
+ EXPECT_EQ(A + 2, std::next(*Begin, 2));
+ EXPECT_EQ(A + 3, std::next(*Begin, 3));
+ EXPECT_EQ(A + 4, std::next(*Begin, 4));
+}
+
+TEST(ZipIteratorTest, Basic) {
+ using namespace std;
+ const SmallVector<unsigned, 6> pi{3, 1, 4, 1, 5, 9};
+ SmallVector<bool, 6> odd{1, 1, 0, 1, 1, 1};
+ const char message[] = "yynyyy\0";
+
+ for (auto tup : zip(pi, odd, message)) {
+ EXPECT_EQ(get<0>(tup) & 0x01, get<1>(tup));
+ EXPECT_EQ(get<0>(tup) & 0x01 ? 'y' : 'n', get<2>(tup));
+ }
+
+ // note the rvalue
+ for (auto tup : zip(pi, SmallVector<bool, 0>{1, 1, 0, 1, 1})) {
+ EXPECT_EQ(get<0>(tup) & 0x01, get<1>(tup));
+ }
+}
+
+TEST(ZipIteratorTest, ZipFirstBasic) {
+ using namespace std;
+ const SmallVector<unsigned, 6> pi{3, 1, 4, 1, 5, 9};
+ unsigned iters = 0;
+
+ for (auto tup : zip_first(SmallVector<bool, 0>{1, 1, 0, 1}, pi)) {
+ EXPECT_EQ(get<0>(tup), get<1>(tup) & 0x01);
+ iters += 1;
+ }
+
+ EXPECT_EQ(iters, 4u);
+}
+
+TEST(ZipIteratorTest, Mutability) {
+ using namespace std;
+ const SmallVector<unsigned, 4> pi{3, 1, 4, 1, 5, 9};
+ char message[] = "hello zip\0";
+
+ for (auto tup : zip(pi, message, message)) {
+ EXPECT_EQ(get<1>(tup), get<2>(tup));
+ get<2>(tup) = get<0>(tup) & 0x01 ? 'y' : 'n';
+ }
+
+ // note the rvalue
+ for (auto tup : zip(message, "yynyyyzip\0")) {
+ EXPECT_EQ(get<0>(tup), get<1>(tup));
+ }
+}
+
+TEST(ZipIteratorTest, ZipFirstMutability) {
+ using namespace std;
+ vector<unsigned> pi{3, 1, 4, 1, 5, 9};
+ unsigned iters = 0;
+
+ for (auto tup : zip_first(SmallVector<bool, 0>{1, 1, 0, 1}, pi)) {
+ get<1>(tup) = get<0>(tup);
+ iters += 1;
+ }
+
+ EXPECT_EQ(iters, 4u);
+
+ for (auto tup : zip_first(SmallVector<bool, 0>{1, 1, 0, 1}, pi)) {
+ EXPECT_EQ(get<0>(tup), get<1>(tup));
+ }
+}
+
} // anonymous namespace
diff --git a/unittests/ADT/MapVectorTest.cpp b/unittests/ADT/MapVectorTest.cpp
index ff8464293c79..f5b094fb627b 100644
--- a/unittests/ADT/MapVectorTest.cpp
+++ b/unittests/ADT/MapVectorTest.cpp
@@ -148,6 +148,15 @@ TEST(MapVectorTest, iteration_test) {
}
}
+TEST(MapVectorTest, NonCopyable) {
+ MapVector<int, std::unique_ptr<int>> MV;
+ MV.insert(std::make_pair(1, llvm::make_unique<int>(1)));
+ MV.insert(std::make_pair(2, llvm::make_unique<int>(2)));
+
+ ASSERT_EQ(MV.count(1), 1u);
+ ASSERT_EQ(*MV.find(2)->second, 2);
+}
+
TEST(SmallMapVectorSmallTest, insert_pop) {
SmallMapVector<int, int, 32> MV;
std::pair<SmallMapVector<int, int, 32>::iterator, bool> R;
@@ -257,6 +266,15 @@ TEST(SmallMapVectorSmallTest, iteration_test) {
}
}
+TEST(SmallMapVectorSmallTest, NonCopyable) {
+ SmallMapVector<int, std::unique_ptr<int>, 8> MV;
+ MV.insert(std::make_pair(1, llvm::make_unique<int>(1)));
+ MV.insert(std::make_pair(2, llvm::make_unique<int>(2)));
+
+ ASSERT_EQ(MV.count(1), 1u);
+ ASSERT_EQ(*MV.find(2)->second, 2);
+}
+
TEST(SmallMapVectorLargeTest, insert_pop) {
SmallMapVector<int, int, 1> MV;
std::pair<SmallMapVector<int, int, 1>::iterator, bool> R;
diff --git a/unittests/ADT/OptionalTest.cpp b/unittests/ADT/OptionalTest.cpp
index 18b59e315818..4c0c99393d21 100644
--- a/unittests/ADT/OptionalTest.cpp
+++ b/unittests/ADT/OptionalTest.cpp
@@ -9,6 +9,7 @@
#include "gtest/gtest.h"
#include "llvm/ADT/Optional.h"
+
using namespace llvm;
namespace {
@@ -377,17 +378,144 @@ TEST_F(OptionalTest, MoveGetValueOr) {
#endif // LLVM_HAS_RVALUE_REFERENCE_THIS
-TEST_F(OptionalTest, NoneComparison) {
- Optional<int> o;
- EXPECT_EQ(o, None);
- EXPECT_EQ(None, o);
- EXPECT_FALSE(o != None);
- EXPECT_FALSE(None != o);
- o = 3;
- EXPECT_FALSE(o == None);
- EXPECT_FALSE(None == o);
- EXPECT_TRUE(o != None);
- EXPECT_TRUE(None != o);
+struct EqualTo {
+ template <typename T, typename U> static bool apply(const T &X, const U &Y) {
+ return X == Y;
+ }
+};
+
+struct NotEqualTo {
+ template <typename T, typename U> static bool apply(const T &X, const U &Y) {
+ return X != Y;
+ }
+};
+
+struct Less {
+ template <typename T, typename U> static bool apply(const T &X, const U &Y) {
+ return X < Y;
+ }
+};
+
+struct Greater {
+ template <typename T, typename U> static bool apply(const T &X, const U &Y) {
+ return X > Y;
+ }
+};
+
+struct LessEqual {
+ template <typename T, typename U> static bool apply(const T &X, const U &Y) {
+ return X <= Y;
+ }
+};
+
+struct GreaterEqual {
+ template <typename T, typename U> static bool apply(const T &X, const U &Y) {
+ return X >= Y;
+ }
+};
+
+template <typename OperatorT, typename T>
+void CheckRelation(const Optional<T> &Lhs, const Optional<T> &Rhs,
+ bool Expected) {
+ EXPECT_EQ(Expected, OperatorT::apply(Lhs, Rhs));
+
+ if (Lhs)
+ EXPECT_EQ(Expected, OperatorT::apply(*Lhs, Rhs));
+ else
+ EXPECT_EQ(Expected, OperatorT::apply(None, Rhs));
+
+ if (Rhs)
+ EXPECT_EQ(Expected, OperatorT::apply(Lhs, *Rhs));
+ else
+ EXPECT_EQ(Expected, OperatorT::apply(Lhs, None));
+}
+
+struct EqualityMock {};
+const Optional<EqualityMock> NoneEq, EqualityLhs((EqualityMock())),
+ EqualityRhs((EqualityMock()));
+bool IsEqual;
+
+bool operator==(const EqualityMock &Lhs, const EqualityMock &Rhs) {
+ EXPECT_EQ(&*EqualityLhs, &Lhs);
+ EXPECT_EQ(&*EqualityRhs, &Rhs);
+ return IsEqual;
+}
+
+TEST_F(OptionalTest, OperatorEqual) {
+ CheckRelation<EqualTo>(NoneEq, NoneEq, true);
+ CheckRelation<EqualTo>(NoneEq, EqualityRhs, false);
+ CheckRelation<EqualTo>(EqualityLhs, NoneEq, false);
+
+ IsEqual = false;
+ CheckRelation<EqualTo>(EqualityLhs, EqualityRhs, IsEqual);
+ IsEqual = true;
+ CheckRelation<EqualTo>(EqualityLhs, EqualityRhs, IsEqual);
+}
+
+TEST_F(OptionalTest, OperatorNotEqual) {
+ CheckRelation<NotEqualTo>(NoneEq, NoneEq, false);
+ CheckRelation<NotEqualTo>(NoneEq, EqualityRhs, true);
+ CheckRelation<NotEqualTo>(EqualityLhs, NoneEq, true);
+
+ IsEqual = false;
+ CheckRelation<NotEqualTo>(EqualityLhs, EqualityRhs, !IsEqual);
+ IsEqual = true;
+ CheckRelation<NotEqualTo>(EqualityLhs, EqualityRhs, !IsEqual);
+}
+
+struct InequalityMock {};
+const Optional<InequalityMock> NoneIneq, InequalityLhs((InequalityMock())),
+ InequalityRhs((InequalityMock()));
+bool IsLess;
+
+bool operator<(const InequalityMock &Lhs, const InequalityMock &Rhs) {
+ EXPECT_EQ(&*InequalityLhs, &Lhs);
+ EXPECT_EQ(&*InequalityRhs, &Rhs);
+ return IsLess;
+}
+
+TEST_F(OptionalTest, OperatorLess) {
+ CheckRelation<Less>(NoneIneq, NoneIneq, false);
+ CheckRelation<Less>(NoneIneq, InequalityRhs, true);
+ CheckRelation<Less>(InequalityLhs, NoneIneq, false);
+
+ IsLess = false;
+ CheckRelation<Less>(InequalityLhs, InequalityRhs, IsLess);
+ IsLess = true;
+ CheckRelation<Less>(InequalityLhs, InequalityRhs, IsLess);
+}
+
+TEST_F(OptionalTest, OperatorGreater) {
+ CheckRelation<Greater>(NoneIneq, NoneIneq, false);
+ CheckRelation<Greater>(NoneIneq, InequalityRhs, false);
+ CheckRelation<Greater>(InequalityLhs, NoneIneq, true);
+
+ IsLess = false;
+ CheckRelation<Greater>(InequalityRhs, InequalityLhs, IsLess);
+ IsLess = true;
+ CheckRelation<Greater>(InequalityRhs, InequalityLhs, IsLess);
+}
+
+TEST_F(OptionalTest, OperatorLessEqual) {
+ CheckRelation<LessEqual>(NoneIneq, NoneIneq, true);
+ CheckRelation<LessEqual>(NoneIneq, InequalityRhs, true);
+ CheckRelation<LessEqual>(InequalityLhs, NoneIneq, false);
+
+ IsLess = false;
+ CheckRelation<LessEqual>(InequalityRhs, InequalityLhs, !IsLess);
+ IsLess = true;
+ CheckRelation<LessEqual>(InequalityRhs, InequalityLhs, !IsLess);
+}
+
+TEST_F(OptionalTest, OperatorGreaterEqual) {
+ CheckRelation<GreaterEqual>(NoneIneq, NoneIneq, true);
+ CheckRelation<GreaterEqual>(NoneIneq, InequalityRhs, false);
+ CheckRelation<GreaterEqual>(InequalityLhs, NoneIneq, true);
+
+ IsLess = false;
+ CheckRelation<GreaterEqual>(InequalityLhs, InequalityRhs, !IsLess);
+ IsLess = true;
+ CheckRelation<GreaterEqual>(InequalityLhs, InequalityRhs, !IsLess);
}
} // end anonymous namespace
diff --git a/unittests/ADT/PostOrderIteratorTest.cpp b/unittests/ADT/PostOrderIteratorTest.cpp
index 1da1078c7498..17b8c4d842d3 100644
--- a/unittests/ADT/PostOrderIteratorTest.cpp
+++ b/unittests/ADT/PostOrderIteratorTest.cpp
@@ -21,17 +21,17 @@ TEST(PostOrderIteratorTest, Compiles) {
// Tests that template specializations are kept up to date
void *Null = nullptr;
po_iterator_storage<std::set<void *>, false> PIS;
- PIS.insertEdge(Null, Null);
+ PIS.insertEdge(Optional<void *>(), Null);
ExtSetTy Ext;
po_iterator_storage<ExtSetTy, true> PISExt(Ext);
- PIS.insertEdge(Null, Null);
+ PIS.insertEdge(Optional<void *>(), Null);
// Test above, but going through po_iterator (which inherits from template
// base)
BasicBlock *NullBB = nullptr;
auto PI = po_end(NullBB);
- PI.insertEdge(NullBB, NullBB);
+ PI.insertEdge(Optional<BasicBlock *>(), NullBB);
auto PIExt = po_ext_end(NullBB, Ext);
- PIExt.insertEdge(NullBB, NullBB);
+ PIExt.insertEdge(Optional<BasicBlock *>(), NullBB);
}
}
diff --git a/unittests/ADT/RangeAdapterTest.cpp b/unittests/ADT/RangeAdapterTest.cpp
index 634f5bb990d9..4c7bef53235b 100644
--- a/unittests/ADT/RangeAdapterTest.cpp
+++ b/unittests/ADT/RangeAdapterTest.cpp
@@ -27,26 +27,96 @@ public:
ReverseOnlyVector(std::initializer_list<int> list) : Vec(list) {}
typedef std::vector<int>::reverse_iterator reverse_iterator;
+ typedef std::vector<int>::const_reverse_iterator const_reverse_iterator;
reverse_iterator rbegin() { return Vec.rbegin(); }
reverse_iterator rend() { return Vec.rend(); }
+ const_reverse_iterator rbegin() const { return Vec.rbegin(); }
+ const_reverse_iterator rend() const { return Vec.rend(); }
};
// A wrapper around vector which exposes begin(), end(), rbegin() and rend().
// begin() and end() don't have implementations as this ensures that we will
// get a linker error if reverse() chooses begin()/end() over rbegin(), rend().
class BidirectionalVector {
- std::vector<int> Vec;
+ mutable std::vector<int> Vec;
public:
BidirectionalVector(std::initializer_list<int> list) : Vec(list) {}
typedef std::vector<int>::iterator iterator;
+ iterator begin() const;
+ iterator end() const;
+
+ typedef std::vector<int>::reverse_iterator reverse_iterator;
+ reverse_iterator rbegin() const { return Vec.rbegin(); }
+ reverse_iterator rend() const { return Vec.rend(); }
+};
+
+/// This is the same as BidirectionalVector but with the addition of const
+/// begin/rbegin methods to ensure that the type traits for has_rbegin works.
+class BidirectionalVectorConsts {
+ std::vector<int> Vec;
+
+public:
+ BidirectionalVectorConsts(std::initializer_list<int> list) : Vec(list) {}
+
+ typedef std::vector<int>::iterator iterator;
+ typedef std::vector<int>::const_iterator const_iterator;
iterator begin();
iterator end();
+ const_iterator begin() const;
+ const_iterator end() const;
typedef std::vector<int>::reverse_iterator reverse_iterator;
+ typedef std::vector<int>::const_reverse_iterator const_reverse_iterator;
reverse_iterator rbegin() { return Vec.rbegin(); }
reverse_iterator rend() { return Vec.rend(); }
+ const_reverse_iterator rbegin() const { return Vec.rbegin(); }
+ const_reverse_iterator rend() const { return Vec.rend(); }
+};
+
+/// Check that types with custom iterators work.
+class CustomIteratorVector {
+ mutable std::vector<int> V;
+
+public:
+ CustomIteratorVector(std::initializer_list<int> list) : V(list) {}
+
+ typedef std::vector<int>::iterator iterator;
+ class reverse_iterator {
+ std::vector<int>::iterator I;
+
+ public:
+ reverse_iterator() = default;
+ reverse_iterator(const reverse_iterator &) = default;
+ reverse_iterator &operator=(const reverse_iterator &) = default;
+
+ explicit reverse_iterator(std::vector<int>::iterator I) : I(I) {}
+
+ reverse_iterator &operator++() {
+ --I;
+ return *this;
+ }
+ reverse_iterator &operator--() {
+ ++I;
+ return *this;
+ }
+ int &operator*() const { return *std::prev(I); }
+ int *operator->() const { return &*std::prev(I); }
+ friend bool operator==(const reverse_iterator &L,
+ const reverse_iterator &R) {
+ return L.I == R.I;
+ }
+ friend bool operator!=(const reverse_iterator &L,
+ const reverse_iterator &R) {
+ return !(L == R);
+ }
+ };
+
+ iterator begin() const { return V.begin(); }
+ iterator end() const { return V.end(); }
+ reverse_iterator rbegin() const { return reverse_iterator(V.end()); }
+ reverse_iterator rend() const { return reverse_iterator(V.begin()); }
};
template <typename R> void TestRev(const R &r) {
@@ -72,12 +142,31 @@ TYPED_TEST(RangeAdapterLValueTest, TrivialOperation) {
template <typename T> struct RangeAdapterRValueTest : testing::Test {};
-typedef ::testing::Types<std::vector<int>, std::list<int>, ReverseOnlyVector,
- BidirectionalVector> RangeAdapterRValueTestTypes;
+typedef ::testing::Types<std::vector<int>, std::list<int>, CustomIteratorVector,
+ ReverseOnlyVector, BidirectionalVector,
+ BidirectionalVectorConsts>
+ RangeAdapterRValueTestTypes;
TYPED_TEST_CASE(RangeAdapterRValueTest, RangeAdapterRValueTestTypes);
TYPED_TEST(RangeAdapterRValueTest, TrivialOperation) {
TestRev(reverse(TypeParam({0, 1, 2, 3})));
}
+TYPED_TEST(RangeAdapterRValueTest, HasRbegin) {
+ static_assert(has_rbegin<TypeParam>::value, "rbegin() should be defined");
+}
+
+TYPED_TEST(RangeAdapterRValueTest, RangeType) {
+ static_assert(
+ std::is_same<
+ decltype(reverse(*static_cast<TypeParam *>(nullptr)).begin()),
+ decltype(static_cast<TypeParam *>(nullptr)->rbegin())>::value,
+ "reverse().begin() should have the same type as rbegin()");
+ static_assert(
+ std::is_same<
+ decltype(reverse(*static_cast<const TypeParam *>(nullptr)).begin()),
+ decltype(static_cast<const TypeParam *>(nullptr)->rbegin())>::value,
+ "reverse().begin() should have the same type as rbegin() [const]");
+}
+
} // anonymous namespace
diff --git a/unittests/ADT/ReverseIterationTest.cpp b/unittests/ADT/ReverseIterationTest.cpp
new file mode 100644
index 000000000000..a1fd3b26d4e3
--- /dev/null
+++ b/unittests/ADT/ReverseIterationTest.cpp
@@ -0,0 +1,52 @@
+//===- llvm/unittest/ADT/ReverseIterationTest.cpp ------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// ReverseIteration unit tests.
+//
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+#include "llvm/ADT/SmallPtrSet.h"
+
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+using namespace llvm;
+
+TEST(ReverseIterationTest, SmallPtrSetTest) {
+
+ SmallPtrSet<void*, 4> Set;
+ void *Ptrs[] = { (void*)0x1, (void*)0x2, (void*)0x3, (void*)0x4 };
+ void *ReversePtrs[] = { (void*)0x4, (void*)0x3, (void*)0x2, (void*)0x1 };
+
+ for (auto *Ptr: Ptrs)
+ Set.insert(Ptr);
+
+ // Check forward iteration.
+ ReverseIterate<bool>::value = false;
+ for (const auto &Tuple : zip(Set, Ptrs))
+ ASSERT_EQ(std::get<0>(Tuple), std::get<1>(Tuple));
+
+ // Check operator++ (post-increment) in forward iteration.
+ int i = 0;
+ for (auto begin = Set.begin(), end = Set.end();
+ begin != end; i++)
+ ASSERT_EQ(*begin++, Ptrs[i]);
+
+ // Check reverse iteration.
+ ReverseIterate<bool>::value = true;
+ for (const auto &Tuple : zip(Set, ReversePtrs))
+ ASSERT_EQ(std::get<0>(Tuple), std::get<1>(Tuple));
+
+ // Check operator++ (post-increment) in reverse iteration.
+ i = 0;
+ for (auto begin = Set.begin(), end = Set.end();
+ begin != end; i++)
+ ASSERT_EQ(*begin++, ReversePtrs[i]);
+
+}
+#endif
diff --git a/unittests/ADT/SCCIteratorTest.cpp b/unittests/ADT/SCCIteratorTest.cpp
index 597661fd8cc0..f596ea6d6b88 100644
--- a/unittests/ADT/SCCIteratorTest.cpp
+++ b/unittests/ADT/SCCIteratorTest.cpp
@@ -8,240 +8,14 @@
//===----------------------------------------------------------------------===//
#include "llvm/ADT/SCCIterator.h"
-#include "llvm/ADT/GraphTraits.h"
#include "gtest/gtest.h"
+#include "TestGraph.h"
#include <limits.h>
using namespace llvm;
namespace llvm {
-/// Graph<N> - A graph with N nodes. Note that N can be at most 8.
-template <unsigned N>
-class Graph {
-private:
- // Disable copying.
- Graph(const Graph&);
- Graph& operator=(const Graph&);
-
- static void ValidateIndex(unsigned Idx) {
- assert(Idx < N && "Invalid node index!");
- }
-public:
-
- /// NodeSubset - A subset of the graph's nodes.
- class NodeSubset {
- typedef unsigned char BitVector; // Where the limitation N <= 8 comes from.
- BitVector Elements;
- NodeSubset(BitVector e) : Elements(e) {}
- public:
- /// NodeSubset - Default constructor, creates an empty subset.
- NodeSubset() : Elements(0) {
- assert(N <= sizeof(BitVector)*CHAR_BIT && "Graph too big!");
- }
-
- /// Comparison operators.
- bool operator==(const NodeSubset &other) const {
- return other.Elements == this->Elements;
- }
- bool operator!=(const NodeSubset &other) const {
- return !(*this == other);
- }
-
- /// AddNode - Add the node with the given index to the subset.
- void AddNode(unsigned Idx) {
- ValidateIndex(Idx);
- Elements |= 1U << Idx;
- }
-
- /// DeleteNode - Remove the node with the given index from the subset.
- void DeleteNode(unsigned Idx) {
- ValidateIndex(Idx);
- Elements &= ~(1U << Idx);
- }
-
- /// count - Return true if the node with the given index is in the subset.
- bool count(unsigned Idx) {
- ValidateIndex(Idx);
- return (Elements & (1U << Idx)) != 0;
- }
-
- /// isEmpty - Return true if this is the empty set.
- bool isEmpty() const {
- return Elements == 0;
- }
-
- /// isSubsetOf - Return true if this set is a subset of the given one.
- bool isSubsetOf(const NodeSubset &other) const {
- return (this->Elements | other.Elements) == other.Elements;
- }
-
- /// Complement - Return the complement of this subset.
- NodeSubset Complement() const {
- return ~(unsigned)this->Elements & ((1U << N) - 1);
- }
-
- /// Join - Return the union of this subset and the given one.
- NodeSubset Join(const NodeSubset &other) const {
- return this->Elements | other.Elements;
- }
-
- /// Meet - Return the intersection of this subset and the given one.
- NodeSubset Meet(const NodeSubset &other) const {
- return this->Elements & other.Elements;
- }
- };
-
- /// NodeType - Node index and set of children of the node.
- typedef std::pair<unsigned, NodeSubset> NodeType;
-
-private:
- /// Nodes - The list of nodes for this graph.
- NodeType Nodes[N];
-public:
-
- /// Graph - Default constructor. Creates an empty graph.
- Graph() {
- // Let each node know which node it is. This allows us to find the start of
- // the Nodes array given a pointer to any element of it.
- for (unsigned i = 0; i != N; ++i)
- Nodes[i].first = i;
- }
-
- /// AddEdge - Add an edge from the node with index FromIdx to the node with
- /// index ToIdx.
- void AddEdge(unsigned FromIdx, unsigned ToIdx) {
- ValidateIndex(FromIdx);
- Nodes[FromIdx].second.AddNode(ToIdx);
- }
-
- /// DeleteEdge - Remove the edge (if any) from the node with index FromIdx to
- /// the node with index ToIdx.
- void DeleteEdge(unsigned FromIdx, unsigned ToIdx) {
- ValidateIndex(FromIdx);
- Nodes[FromIdx].second.DeleteNode(ToIdx);
- }
-
- /// AccessNode - Get a pointer to the node with the given index.
- NodeType *AccessNode(unsigned Idx) const {
- ValidateIndex(Idx);
- // The constant cast is needed when working with GraphTraits, which insists
- // on taking a constant Graph.
- return const_cast<NodeType *>(&Nodes[Idx]);
- }
-
- /// NodesReachableFrom - Return the set of all nodes reachable from the given
- /// node.
- NodeSubset NodesReachableFrom(unsigned Idx) const {
- // This algorithm doesn't scale, but that doesn't matter given the small
- // size of our graphs.
- NodeSubset Reachable;
-
- // The initial node is reachable.
- Reachable.AddNode(Idx);
- do {
- NodeSubset Previous(Reachable);
-
- // Add in all nodes which are children of a reachable node.
- for (unsigned i = 0; i != N; ++i)
- if (Previous.count(i))
- Reachable = Reachable.Join(Nodes[i].second);
-
- // If nothing changed then we have found all reachable nodes.
- if (Reachable == Previous)
- return Reachable;
-
- // Rinse and repeat.
- } while (1);
- }
-
- /// ChildIterator - Visit all children of a node.
- class ChildIterator {
- friend class Graph;
-
- /// FirstNode - Pointer to first node in the graph's Nodes array.
- NodeType *FirstNode;
- /// Children - Set of nodes which are children of this one and that haven't
- /// yet been visited.
- NodeSubset Children;
-
- ChildIterator(); // Disable default constructor.
- protected:
- ChildIterator(NodeType *F, NodeSubset C) : FirstNode(F), Children(C) {}
-
- public:
- /// ChildIterator - Copy constructor.
- ChildIterator(const ChildIterator& other) : FirstNode(other.FirstNode),
- Children(other.Children) {}
-
- /// Comparison operators.
- bool operator==(const ChildIterator &other) const {
- return other.FirstNode == this->FirstNode &&
- other.Children == this->Children;
- }
- bool operator!=(const ChildIterator &other) const {
- return !(*this == other);
- }
-
- /// Prefix increment operator.
- ChildIterator& operator++() {
- // Find the next unvisited child node.
- for (unsigned i = 0; i != N; ++i)
- if (Children.count(i)) {
- // Remove that child - it has been visited. This is the increment!
- Children.DeleteNode(i);
- return *this;
- }
- assert(false && "Incrementing end iterator!");
- return *this; // Avoid compiler warnings.
- }
-
- /// Postfix increment operator.
- ChildIterator operator++(int) {
- ChildIterator Result(*this);
- ++(*this);
- return Result;
- }
-
- /// Dereference operator.
- NodeType *operator*() {
- // Find the next unvisited child node.
- for (unsigned i = 0; i != N; ++i)
- if (Children.count(i))
- // Return a pointer to it.
- return FirstNode + i;
- assert(false && "Dereferencing end iterator!");
- return nullptr; // Avoid compiler warning.
- }
- };
-
- /// child_begin - Return an iterator pointing to the first child of the given
- /// node.
- static ChildIterator child_begin(NodeType *Parent) {
- return ChildIterator(Parent - Parent->first, Parent->second);
- }
-
- /// child_end - Return the end iterator for children of the given node.
- static ChildIterator child_end(NodeType *Parent) {
- return ChildIterator(Parent - Parent->first, NodeSubset());
- }
-};
-
-template <unsigned N>
-struct GraphTraits<Graph<N> > {
- typedef typename Graph<N>::NodeType NodeType;
- typedef typename Graph<N>::NodeType *NodeRef;
- typedef typename Graph<N>::ChildIterator ChildIteratorType;
-
- static inline NodeType *getEntryNode(const Graph<N> &G) { return G.AccessNode(0); }
- static inline ChildIteratorType child_begin(NodeType *Node) {
- return Graph<N>::child_begin(Node);
- }
- static inline ChildIteratorType child_end(NodeType *Node) {
- return Graph<N>::child_end(Node);
- }
-};
-
TEST(SCCIteratorTest, AllSmallGraphs) {
// Test SCC computation against every graph with NUM_NODES nodes or less.
// Since SCC considers every node to have an implicit self-edge, we only
diff --git a/unittests/ADT/STLExtrasTest.cpp b/unittests/ADT/STLExtrasTest.cpp
new file mode 100644
index 000000000000..f17d24f36b23
--- /dev/null
+++ b/unittests/ADT/STLExtrasTest.cpp
@@ -0,0 +1,311 @@
+//===- STLExtrasTest.cpp - Unit tests for STL extras ----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/STLExtras.h"
+#include "gtest/gtest.h"
+
+#include <list>
+#include <vector>
+
+using namespace llvm;
+
+namespace {
+
+int f(rank<0>) { return 0; }
+int f(rank<1>) { return 1; }
+int f(rank<2>) { return 2; }
+int f(rank<4>) { return 4; }
+
+TEST(STLExtrasTest, Rank) {
+ // We shouldn't get ambiguities and should select the overload of the same
+ // rank as the argument.
+ EXPECT_EQ(0, f(rank<0>()));
+ EXPECT_EQ(1, f(rank<1>()));
+ EXPECT_EQ(2, f(rank<2>()));
+
+ // This overload is missing so we end up back at 2.
+ EXPECT_EQ(2, f(rank<3>()));
+
+ // But going past 3 should work fine.
+ EXPECT_EQ(4, f(rank<4>()));
+
+ // And we can even go higher and just fall back to the last overload.
+ EXPECT_EQ(4, f(rank<5>()));
+ EXPECT_EQ(4, f(rank<6>()));
+}
+
+TEST(STLExtrasTest, EnumerateLValue) {
+ // Test that a simple LValue can be enumerated and gives correct results with
+ // multiple types, including the empty container.
+ std::vector<char> foo = {'a', 'b', 'c'};
+ typedef std::pair<std::size_t, char> CharPairType;
+ std::vector<CharPairType> CharResults;
+
+ for (auto X : llvm::enumerate(foo)) {
+ CharResults.emplace_back(X.Index, X.Value);
+ }
+ ASSERT_EQ(3u, CharResults.size());
+ EXPECT_EQ(CharPairType(0u, 'a'), CharResults[0]);
+ EXPECT_EQ(CharPairType(1u, 'b'), CharResults[1]);
+ EXPECT_EQ(CharPairType(2u, 'c'), CharResults[2]);
+
+ // Test a const range of a different type.
+ typedef std::pair<std::size_t, int> IntPairType;
+ 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);
+ }
+ ASSERT_EQ(3u, IntResults.size());
+ EXPECT_EQ(IntPairType(0u, 1), IntResults[0]);
+ EXPECT_EQ(IntPairType(1u, 2), IntResults[1]);
+ EXPECT_EQ(IntPairType(2u, 3), IntResults[2]);
+
+ // Test an empty range.
+ IntResults.clear();
+ const std::vector<int> baz;
+ for (auto X : llvm::enumerate(baz)) {
+ IntResults.emplace_back(X.Index, X.Value);
+ }
+ EXPECT_TRUE(IntResults.empty());
+}
+
+TEST(STLExtrasTest, EnumerateModifyLValue) {
+ // Test that you can modify the underlying entries of an lvalue range through
+ // the enumeration iterator.
+ std::vector<char> foo = {'a', 'b', 'c'};
+
+ for (auto X : llvm::enumerate(foo)) {
+ ++X.Value;
+ }
+ EXPECT_EQ('b', foo[0]);
+ EXPECT_EQ('c', foo[1]);
+ EXPECT_EQ('d', foo[2]);
+}
+
+TEST(STLExtrasTest, EnumerateRValueRef) {
+ // Test that an rvalue can be enumerated.
+ typedef std::pair<std::size_t, int> PairType;
+ std::vector<PairType> Results;
+
+ 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);
+ }
+
+ ASSERT_EQ(3u, Results.size());
+ EXPECT_EQ(PairType(0u, 1), Results[0]);
+ EXPECT_EQ(PairType(1u, 2), Results[1]);
+ EXPECT_EQ(PairType(2u, 3), Results[2]);
+}
+
+TEST(STLExtrasTest, EnumerateModifyRValue) {
+ // Test that when enumerating an rvalue, modification still works (even if
+ // this isn't terribly useful, it at least shows that we haven't snuck an
+ // extra const in there somewhere.
+ typedef std::pair<std::size_t, char> PairType;
+ std::vector<PairType> Results;
+
+ for (auto X : llvm::enumerate(std::vector<char>{'1', '2', '3'})) {
+ ++X.Value;
+ Results.emplace_back(X.Index, X.Value);
+ }
+
+ ASSERT_EQ(3u, Results.size());
+ EXPECT_EQ(PairType(0u, '2'), Results[0]);
+ EXPECT_EQ(PairType(1u, '3'), Results[1]);
+ EXPECT_EQ(PairType(2u, '4'), Results[2]);
+}
+
+template <bool B> struct CanMove {};
+template <> struct CanMove<false> {
+ CanMove(CanMove &&) = delete;
+
+ CanMove() = default;
+ CanMove(const CanMove &) = default;
+};
+
+template <bool B> struct CanCopy {};
+template <> struct CanCopy<false> {
+ CanCopy(const CanCopy &) = delete;
+
+ CanCopy() = default;
+ CanCopy(CanCopy &&) = default;
+};
+
+template <bool Moveable, bool Copyable>
+struct Range : CanMove<Moveable>, CanCopy<Copyable> {
+ explicit Range(int &C, int &M, int &D) : C(C), M(M), D(D) {}
+ Range(const Range &R) : CanCopy<Copyable>(R), C(R.C), M(R.M), D(R.D) { ++C; }
+ Range(Range &&R) : CanMove<Moveable>(std::move(R)), C(R.C), M(R.M), D(R.D) {
+ ++M;
+ }
+ ~Range() { ++D; }
+
+ int &C;
+ int &M;
+ int &D;
+
+ int *begin() { return nullptr; }
+ int *end() { return nullptr; }
+};
+
+TEST(STLExtrasTest, EnumerateLifetimeSemantics) {
+ // Test that when enumerating lvalues and rvalues, there are no surprise
+ // copies or moves.
+
+ // With an rvalue, it should not be destroyed until the end of the scope.
+ int Copies = 0;
+ int Moves = 0;
+ int Destructors = 0;
+ {
+ auto E1 = enumerate(Range<true, false>(Copies, Moves, Destructors));
+ // Doesn't compile. rvalue ranges must be moveable.
+ // auto E2 = enumerate(Range<false, true>(Copies, Moves, Destructors));
+ EXPECT_EQ(0, Copies);
+ EXPECT_EQ(1, Moves);
+ EXPECT_EQ(1, Destructors);
+ }
+ EXPECT_EQ(0, Copies);
+ EXPECT_EQ(1, Moves);
+ EXPECT_EQ(2, Destructors);
+
+ Copies = Moves = Destructors = 0;
+ // With an lvalue, it should not be destroyed even after the end of the scope.
+ // lvalue ranges need be neither copyable nor moveable.
+ Range<false, false> R(Copies, Moves, Destructors);
+ {
+ auto Enumerator = enumerate(R);
+ (void)Enumerator;
+ EXPECT_EQ(0, Copies);
+ EXPECT_EQ(0, Moves);
+ EXPECT_EQ(0, Destructors);
+ }
+ EXPECT_EQ(0, Copies);
+ EXPECT_EQ(0, Moves);
+ EXPECT_EQ(0, Destructors);
+}
+
+TEST(STLExtrasTest, ApplyTuple) {
+ auto T = std::make_tuple(1, 3, 7);
+ auto U = llvm::apply_tuple(
+ [](int A, int B, int C) { return std::make_tuple(A - B, B - C, C - A); },
+ T);
+
+ EXPECT_EQ(-2, std::get<0>(U));
+ EXPECT_EQ(-4, std::get<1>(U));
+ EXPECT_EQ(6, std::get<2>(U));
+
+ auto V = llvm::apply_tuple(
+ [](int A, int B, int C) {
+ return std::make_tuple(std::make_pair(A, char('A' + A)),
+ std::make_pair(B, char('A' + B)),
+ std::make_pair(C, char('A' + C)));
+ },
+ T);
+
+ EXPECT_EQ(std::make_pair(1, 'B'), std::get<0>(V));
+ EXPECT_EQ(std::make_pair(3, 'D'), std::get<1>(V));
+ EXPECT_EQ(std::make_pair(7, 'H'), std::get<2>(V));
+}
+
+class apply_variadic {
+ static int apply_one(int X) { return X + 1; }
+ static char apply_one(char C) { return C + 1; }
+ static StringRef apply_one(StringRef S) { return S.drop_back(); }
+
+public:
+ template <typename... Ts>
+ auto operator()(Ts &&... Items)
+ -> decltype(std::make_tuple(apply_one(Items)...)) {
+ return std::make_tuple(apply_one(Items)...);
+ }
+};
+
+TEST(STLExtrasTest, ApplyTupleVariadic) {
+ auto Items = std::make_tuple(1, llvm::StringRef("Test"), 'X');
+ auto Values = apply_tuple(apply_variadic(), Items);
+
+ EXPECT_EQ(2, std::get<0>(Values));
+ EXPECT_EQ("Tes", std::get<1>(Values));
+ EXPECT_EQ('Y', std::get<2>(Values));
+}
+
+TEST(STLExtrasTest, CountAdaptor) {
+ std::vector<int> v;
+
+ v.push_back(1);
+ v.push_back(2);
+ v.push_back(1);
+ v.push_back(4);
+ v.push_back(3);
+ v.push_back(2);
+ v.push_back(1);
+
+ EXPECT_EQ(3, count(v, 1));
+ EXPECT_EQ(2, count(v, 2));
+ EXPECT_EQ(1, count(v, 3));
+ EXPECT_EQ(1, count(v, 4));
+}
+
+TEST(STLExtrasTest, ConcatRange) {
+ std::vector<int> Expected = {1, 2, 3, 4, 5, 6, 7, 8};
+ std::vector<int> Test;
+
+ std::vector<int> V1234 = {1, 2, 3, 4};
+ std::list<int> L56 = {5, 6};
+ SmallVector<int, 2> SV78 = {7, 8};
+
+ // Use concat across different sized ranges of different types with different
+ // iterators.
+ for (int &i : concat<int>(V1234, L56, SV78))
+ Test.push_back(i);
+ EXPECT_EQ(Expected, Test);
+
+ // Use concat between a temporary, an L-value, and an R-value to make sure
+ // complex lifetimes work well.
+ Test.clear();
+ for (int &i : concat<int>(std::vector<int>(V1234), L56, std::move(SV78)))
+ Test.push_back(i);
+ EXPECT_EQ(Expected, Test);
+}
+
+TEST(STLExtrasTest, PartitionAdaptor) {
+ std::vector<int> V = {1, 2, 3, 4, 5, 6, 7, 8};
+
+ auto I = partition(V, [](int i) { return i % 2 == 0; });
+ ASSERT_EQ(V.begin() + 4, I);
+
+ // Sort the two halves as partition may have messed with the order.
+ std::sort(V.begin(), I);
+ std::sort(I, V.end());
+
+ EXPECT_EQ(2, V[0]);
+ EXPECT_EQ(4, V[1]);
+ EXPECT_EQ(6, V[2]);
+ EXPECT_EQ(8, V[3]);
+ EXPECT_EQ(1, V[4]);
+ EXPECT_EQ(3, V[5]);
+ EXPECT_EQ(5, V[6]);
+ EXPECT_EQ(7, V[7]);
+}
+
+TEST(STLExtrasTest, EraseIf) {
+ std::vector<int> V = {1, 2, 3, 4, 5, 6, 7, 8};
+
+ erase_if(V, [](int i) { return i % 2 == 0; });
+ EXPECT_EQ(4u, V.size());
+ EXPECT_EQ(1, V[0]);
+ EXPECT_EQ(3, V[1]);
+ EXPECT_EQ(5, V[2]);
+ EXPECT_EQ(7, V[3]);
+}
+
+}
diff --git a/unittests/ADT/ScopeExitTest.cpp b/unittests/ADT/ScopeExitTest.cpp
new file mode 100644
index 000000000000..301942c30bbc
--- /dev/null
+++ b/unittests/ADT/ScopeExitTest.cpp
@@ -0,0 +1,32 @@
+//===- llvm/unittest/ADT/ScopeExit.cpp - Scope exit 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/ADT/ScopeExit.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+
+TEST(ScopeExitTest, Basic) {
+ struct Callable {
+ bool &Called;
+ Callable(bool &Called) : Called(Called) {}
+ Callable(Callable &&RHS) : Called(RHS.Called) {}
+ void operator()() { Called = true; }
+ };
+ bool Called = false;
+ {
+ auto g = make_scope_exit(Callable(Called));
+ EXPECT_FALSE(Called);
+ }
+ EXPECT_TRUE(Called);
+}
+
+} // end anonymous namespace
diff --git a/unittests/ADT/SimpleIListTest.cpp b/unittests/ADT/SimpleIListTest.cpp
new file mode 100644
index 000000000000..a354f332006a
--- /dev/null
+++ b/unittests/ADT/SimpleIListTest.cpp
@@ -0,0 +1,654 @@
+//===- unittests/ADT/SimpleIListTest.cpp - simple_ilist unit tests --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/simple_ilist.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+
+struct Node : ilist_node<Node> {};
+bool operator<(const Node &L, const Node &R) { return &L < &R; }
+bool makeFalse(const Node &, const Node &) { return false; }
+
+struct deleteNode : std::default_delete<Node> {};
+void doNothing(Node *) {}
+
+TEST(SimpleIListTest, DefaultConstructor) {
+ simple_ilist<Node> L;
+ EXPECT_EQ(L.begin(), L.end());
+ EXPECT_TRUE(L.empty());
+ EXPECT_EQ(0u, L.size());
+}
+
+TEST(SimpleIListTest, pushPopFront) {
+ simple_ilist<Node> L;
+ Node A, B;
+ L.push_front(B);
+ L.push_front(A);
+ EXPECT_EQ(&A, &L.front());
+ EXPECT_EQ(&B, &L.back());
+ EXPECT_FALSE(L.empty());
+ EXPECT_EQ(2u, L.size());
+
+ // Pop front and check the new front.
+ L.pop_front();
+ EXPECT_EQ(&B, &L.front());
+
+ // Pop to empty.
+ L.pop_front();
+ EXPECT_TRUE(L.empty());
+}
+
+TEST(SimpleIListTest, pushPopBack) {
+ simple_ilist<Node> L;
+ Node A, B;
+ L.push_back(A);
+ L.push_back(B);
+ EXPECT_EQ(&A, &L.front());
+ EXPECT_EQ(&B, &L.back());
+ EXPECT_FALSE(L.empty());
+ EXPECT_EQ(2u, L.size());
+
+ // Pop back and check the new front.
+ L.pop_back();
+ EXPECT_EQ(&A, &L.back());
+
+ // Pop to empty.
+ L.pop_back();
+ EXPECT_TRUE(L.empty());
+}
+
+TEST(SimpleIListTest, swap) {
+ simple_ilist<Node> L1, L2;
+ Node A, B;
+ L1.push_back(A);
+ L1.push_back(B);
+ L1.swap(L2);
+ EXPECT_TRUE(L1.empty());
+ EXPECT_EQ(0u, L1.size());
+ EXPECT_EQ(&A, &L2.front());
+ EXPECT_EQ(&B, &L2.back());
+ EXPECT_FALSE(L2.empty());
+ EXPECT_EQ(2u, L2.size());
+}
+
+TEST(SimpleIListTest, insertEraseAtEnd) {
+ simple_ilist<Node> L;
+ Node A, B;
+ L.insert(L.end(), A);
+ L.insert(L.end(), B);
+ EXPECT_EQ(&A, &L.front());
+ EXPECT_EQ(&B, &L.back());
+ EXPECT_FALSE(L.empty());
+ EXPECT_EQ(2u, L.size());
+}
+
+TEST(SimpleIListTest, insertAtBegin) {
+ simple_ilist<Node> L;
+ Node A, B;
+ L.insert(L.begin(), B);
+ L.insert(L.begin(), A);
+ EXPECT_EQ(&A, &L.front());
+ EXPECT_EQ(&B, &L.back());
+ EXPECT_FALSE(L.empty());
+ EXPECT_EQ(2u, L.size());
+}
+
+TEST(SimpleIListTest, remove) {
+ simple_ilist<Node> L;
+ Node A, B, C;
+ L.push_back(A);
+ L.push_back(B);
+ L.push_back(C);
+ EXPECT_EQ(&A, &L.front());
+ EXPECT_EQ(&B, &*++L.begin());
+ EXPECT_EQ(&C, &L.back());
+ EXPECT_EQ(3u, L.size());
+
+ L.remove(B);
+ EXPECT_EQ(&A, &L.front());
+ EXPECT_EQ(&C, &L.back());
+ EXPECT_EQ(2u, L.size());
+
+ L.remove(A);
+ EXPECT_EQ(&C, &L.front());
+ EXPECT_EQ(1u, L.size());
+
+ L.remove(C);
+ EXPECT_TRUE(L.empty());
+}
+
+TEST(SimpleIListTest, removeAndDispose) {
+ simple_ilist<Node> L;
+ Node A, C;
+ Node *B = new Node;
+ L.push_back(A);
+ L.push_back(*B);
+ L.push_back(C);
+ EXPECT_EQ(&A, &L.front());
+ EXPECT_EQ(B, &*++L.begin());
+ EXPECT_EQ(&C, &L.back());
+ EXPECT_EQ(3u, L.size());
+
+ L.removeAndDispose(*B, deleteNode());
+ EXPECT_EQ(&A, &L.front());
+ EXPECT_EQ(&C, &L.back());
+ EXPECT_EQ(2u, L.size());
+}
+
+TEST(SimpleIListTest, removeAndDisposeNullDeleter) {
+ simple_ilist<Node> L;
+ Node A, B, C;
+ L.push_back(A);
+ L.push_back(B);
+ L.push_back(C);
+ EXPECT_EQ(&A, &L.front());
+ EXPECT_EQ(&B, &*++L.begin());
+ EXPECT_EQ(&C, &L.back());
+ EXPECT_EQ(3u, L.size());
+
+ L.removeAndDispose(B, doNothing);
+ EXPECT_EQ(&A, &L.front());
+ EXPECT_EQ(&C, &L.back());
+ EXPECT_EQ(2u, L.size());
+}
+
+TEST(SimpleIListTest, erase) {
+ simple_ilist<Node> L;
+ Node A, B, C;
+ L.push_back(A);
+ L.push_back(B);
+ L.push_back(C);
+ EXPECT_EQ(&A, &L.front());
+ EXPECT_EQ(&B, &*++L.begin());
+ EXPECT_EQ(&C, &L.back());
+ EXPECT_EQ(3u, L.size());
+
+ EXPECT_EQ(C.getIterator(), L.erase(B.getIterator()));
+ EXPECT_EQ(&A, &L.front());
+ EXPECT_EQ(&C, &L.back());
+ EXPECT_EQ(2u, L.size());
+}
+
+TEST(SimpleIListTest, reverse_iterator) {
+ simple_ilist<Node> L;
+ Node A, B, C;
+ L.push_back(A);
+ L.push_back(B);
+ L.push_back(C);
+
+ auto ReverseIter = L.rbegin();
+ EXPECT_EQ(C.getReverseIterator(), ReverseIter);
+ ++ReverseIter;
+ EXPECT_EQ(B.getReverseIterator(), ReverseIter);
+ ++ReverseIter;
+ EXPECT_EQ(A.getReverseIterator(), ReverseIter);
+ ++ReverseIter;
+ EXPECT_EQ(L.rend(), ReverseIter);
+}
+
+TEST(SimpleIListTest, eraseAndDispose) {
+ simple_ilist<Node> L;
+ Node A, C;
+ Node *B = new Node;
+ L.push_back(A);
+ L.push_back(*B);
+ L.push_back(C);
+ EXPECT_EQ(&A, &L.front());
+ EXPECT_EQ(B, &*++L.begin());
+ EXPECT_EQ(&C, &L.back());
+ EXPECT_EQ(3u, L.size());
+
+ L.eraseAndDispose(B->getIterator(), deleteNode());
+ EXPECT_EQ(&A, &L.front());
+ EXPECT_EQ(&C, &L.back());
+ EXPECT_EQ(2u, L.size());
+}
+
+TEST(SimpleIListTest, eraseAndDisposeNullDeleter) {
+ simple_ilist<Node> L;
+ Node A, B, C;
+ L.push_back(A);
+ L.push_back(B);
+ L.push_back(C);
+ EXPECT_EQ(&A, &L.front());
+ EXPECT_EQ(&B, &*++L.begin());
+ EXPECT_EQ(&C, &L.back());
+ EXPECT_EQ(3u, L.size());
+
+ L.eraseAndDispose(B.getIterator(), doNothing);
+ EXPECT_EQ(&A, &L.front());
+ EXPECT_EQ(&C, &L.back());
+ EXPECT_EQ(2u, L.size());
+}
+
+TEST(SimpleIListTest, eraseRange) {
+ simple_ilist<Node> L;
+ Node A, B, C, D, E;
+ L.push_back(A);
+ L.push_back(B);
+ L.push_back(C);
+ L.push_back(D);
+ L.push_back(E);
+ auto I = L.begin();
+ EXPECT_EQ(&A, &*I++);
+ EXPECT_EQ(&B, &*I++);
+ EXPECT_EQ(&C, &*I++);
+ EXPECT_EQ(&D, &*I++);
+ EXPECT_EQ(&E, &*I++);
+ EXPECT_EQ(L.end(), I);
+ EXPECT_EQ(5u, L.size());
+
+ // Erase a range.
+ EXPECT_EQ(E.getIterator(), L.erase(B.getIterator(), E.getIterator()));
+ EXPECT_EQ(&A, &L.front());
+ EXPECT_EQ(&E, &L.back());
+ EXPECT_EQ(2u, L.size());
+}
+
+TEST(SimpleIListTest, eraseAndDisposeRange) {
+ simple_ilist<Node> L;
+ Node A, *B = new Node, *C = new Node, *D = new Node, E;
+ L.push_back(A);
+ L.push_back(*B);
+ L.push_back(*C);
+ L.push_back(*D);
+ L.push_back(E);
+ auto I = L.begin();
+ EXPECT_EQ(&A, &*I++);
+ EXPECT_EQ(B, &*I++);
+ EXPECT_EQ(C, &*I++);
+ EXPECT_EQ(D, &*I++);
+ EXPECT_EQ(&E, &*I++);
+ EXPECT_EQ(L.end(), I);
+ EXPECT_EQ(5u, L.size());
+
+ // Erase a range.
+ EXPECT_EQ(E.getIterator(),
+ L.eraseAndDispose(B->getIterator(), E.getIterator(), deleteNode()));
+ EXPECT_EQ(&A, &L.front());
+ EXPECT_EQ(&E, &L.back());
+ EXPECT_EQ(2u, L.size());
+}
+
+TEST(SimpleIListTest, eraseAndDisposeRangeNullDeleter) {
+ simple_ilist<Node> L;
+ Node A, B, C, D, E;
+ L.push_back(A);
+ L.push_back(B);
+ L.push_back(C);
+ L.push_back(D);
+ L.push_back(E);
+ auto I = L.begin();
+ EXPECT_EQ(&A, &*I++);
+ EXPECT_EQ(&B, &*I++);
+ EXPECT_EQ(&C, &*I++);
+ EXPECT_EQ(&D, &*I++);
+ EXPECT_EQ(&E, &*I++);
+ EXPECT_EQ(L.end(), I);
+ EXPECT_EQ(5u, L.size());
+
+ // Erase a range.
+ EXPECT_EQ(E.getIterator(),
+ L.eraseAndDispose(B.getIterator(), E.getIterator(), doNothing));
+ EXPECT_EQ(&A, &L.front());
+ EXPECT_EQ(&E, &L.back());
+ EXPECT_EQ(2u, L.size());
+}
+
+TEST(SimpleIListTest, clear) {
+ simple_ilist<Node> L;
+ Node A, B;
+ L.push_back(A);
+ L.push_back(B);
+ L.clear();
+ EXPECT_TRUE(L.empty());
+ EXPECT_EQ(0u, L.size());
+}
+
+TEST(SimpleIListTest, clearAndDispose) {
+ simple_ilist<Node> L;
+ Node *A = new Node;
+ Node *B = new Node;
+ L.push_back(*A);
+ L.push_back(*B);
+ L.clearAndDispose(deleteNode());
+ EXPECT_TRUE(L.empty());
+ EXPECT_EQ(0u, L.size());
+}
+
+TEST(SimpleIListTest, clearAndDisposeNullDeleter) {
+ simple_ilist<Node> L;
+ Node A, B;
+ L.push_back(A);
+ L.push_back(B);
+ L.clearAndDispose(doNothing);
+ EXPECT_TRUE(L.empty());
+ EXPECT_EQ(0u, L.size());
+}
+
+TEST(SimpleIListTest, spliceList) {
+ simple_ilist<Node> L1, L2;
+ Node A, B, C, D;
+
+ // [A, D].
+ L1.push_back(A);
+ L1.push_back(D);
+
+ // [B, C].
+ L2.push_back(B);
+ L2.push_back(C);
+
+ // Splice in L2, giving [A, B, C, D].
+ L1.splice(--L1.end(), L2);
+ EXPECT_TRUE(L2.empty());
+ EXPECT_EQ(4u, L1.size());
+ auto I = L1.begin();
+ EXPECT_EQ(&A, &*I++);
+ EXPECT_EQ(&B, &*I++);
+ EXPECT_EQ(&C, &*I++);
+ EXPECT_EQ(&D, &*I++);
+ EXPECT_EQ(L1.end(), I);
+}
+
+TEST(SimpleIListTest, spliceSingle) {
+ simple_ilist<Node> L1, L2;
+ Node A, B, C, D, E;
+
+ // [A, C].
+ L1.push_back(A);
+ L1.push_back(C);
+
+ // [D, B, E].
+ L2.push_back(D);
+ L2.push_back(B);
+ L2.push_back(E);
+
+ // Splice B from L2 to L1, giving [A, B, C] and [D, E].
+ L1.splice(--L1.end(), L2, ++L2.begin());
+ auto I = L1.begin();
+ EXPECT_EQ(&A, &*I++);
+ EXPECT_EQ(&B, &*I++);
+ EXPECT_EQ(&C, &*I++);
+ EXPECT_EQ(L1.end(), I);
+
+ I = L2.begin();
+ EXPECT_EQ(&D, &*I++);
+ EXPECT_EQ(&E, &*I++);
+ EXPECT_EQ(L2.end(), I);
+}
+
+TEST(SimpleIListTest, spliceRange) {
+ simple_ilist<Node> L1, L2;
+ Node A, B, C, D, E, F;
+
+ // [A, D].
+ L1.push_back(A);
+ L1.push_back(D);
+
+ // [E, B, C, F].
+ L2.push_back(E);
+ L2.push_back(B);
+ L2.push_back(C);
+ L2.push_back(F);
+
+ // Splice B from L2 to L1, giving [A, B, C, D] and [E, F].
+ L1.splice(--L1.end(), L2, ++L2.begin(), --L2.end());
+ auto I = L1.begin();
+ EXPECT_EQ(&A, &*I++);
+ EXPECT_EQ(&B, &*I++);
+ EXPECT_EQ(&C, &*I++);
+ EXPECT_EQ(&D, &*I++);
+ EXPECT_EQ(L1.end(), I);
+
+ I = L2.begin();
+ EXPECT_EQ(&E, &*I++);
+ EXPECT_EQ(&F, &*I++);
+ EXPECT_EQ(L2.end(), I);
+}
+
+TEST(SimpleIListTest, merge) {
+ for (bool IsL1LHS : {false, true}) {
+ simple_ilist<Node> L1, L2;
+ Node Ns[10];
+
+ // Fill L1.
+ L1.push_back(Ns[0]);
+ L1.push_back(Ns[3]);
+ L1.push_back(Ns[4]);
+ L1.push_back(Ns[8]);
+
+ // Fill L2.
+ L2.push_back(Ns[1]);
+ L2.push_back(Ns[2]);
+ L2.push_back(Ns[5]);
+ L2.push_back(Ns[6]);
+ L2.push_back(Ns[7]);
+ L2.push_back(Ns[9]);
+
+ // Check setup.
+ EXPECT_EQ(4u, L1.size());
+ EXPECT_EQ(6u, L2.size());
+ EXPECT_TRUE(std::is_sorted(L1.begin(), L1.end()));
+ EXPECT_TRUE(std::is_sorted(L2.begin(), L2.end()));
+
+ // Merge.
+ auto &LHS = IsL1LHS ? L1 : L2;
+ auto &RHS = IsL1LHS ? L2 : L1;
+ LHS.merge(RHS);
+ EXPECT_TRUE(RHS.empty());
+ EXPECT_FALSE(LHS.empty());
+ EXPECT_TRUE(std::is_sorted(LHS.begin(), LHS.end()));
+ auto I = LHS.begin();
+ for (Node &N : Ns)
+ EXPECT_EQ(&N, &*I++);
+ EXPECT_EQ(LHS.end(), I);
+ }
+}
+
+TEST(SimpleIListTest, mergeIsStable) {
+ simple_ilist<Node> L1, L2;
+ Node Ns[5];
+
+ auto setup = [&]() {
+ EXPECT_TRUE(L1.empty());
+ EXPECT_TRUE(L2.empty());
+
+ // Fill L1.
+ L1.push_back(Ns[0]);
+ L1.push_back(Ns[3]);
+ L1.push_back(Ns[4]);
+
+ // Fill L2.
+ L2.push_back(Ns[1]);
+ L2.push_back(Ns[2]);
+
+ // Check setup.
+ EXPECT_EQ(3u, L1.size());
+ EXPECT_EQ(2u, L2.size());
+ EXPECT_TRUE(std::is_sorted(L1.begin(), L1.end(), makeFalse));
+ EXPECT_TRUE(std::is_sorted(L2.begin(), L2.end(), makeFalse));
+ };
+
+ // Merge. Should be stable.
+ setup();
+ L1.merge(L2, makeFalse);
+ EXPECT_TRUE(L2.empty());
+ EXPECT_FALSE(L1.empty());
+ EXPECT_TRUE(std::is_sorted(L1.begin(), L1.end(), makeFalse));
+ auto I = L1.begin();
+ EXPECT_EQ(&Ns[0], &*I++);
+ EXPECT_EQ(&Ns[3], &*I++);
+ EXPECT_EQ(&Ns[4], &*I++);
+ EXPECT_EQ(&Ns[1], &*I++);
+ EXPECT_EQ(&Ns[2], &*I++);
+ EXPECT_EQ(L1.end(), I);
+
+ // Merge the other way. Should be stable.
+ L1.clear();
+ setup();
+ L2.merge(L1, makeFalse);
+ EXPECT_TRUE(L1.empty());
+ EXPECT_FALSE(L2.empty());
+ EXPECT_TRUE(std::is_sorted(L2.begin(), L2.end(), makeFalse));
+ I = L2.begin();
+ EXPECT_EQ(&Ns[1], &*I++);
+ EXPECT_EQ(&Ns[2], &*I++);
+ EXPECT_EQ(&Ns[0], &*I++);
+ EXPECT_EQ(&Ns[3], &*I++);
+ EXPECT_EQ(&Ns[4], &*I++);
+ EXPECT_EQ(L2.end(), I);
+}
+
+TEST(SimpleIListTest, mergeEmpty) {
+ for (bool IsL1LHS : {false, true}) {
+ simple_ilist<Node> L1, L2;
+ Node Ns[4];
+
+ // Fill L1.
+ L1.push_back(Ns[0]);
+ L1.push_back(Ns[1]);
+ L1.push_back(Ns[2]);
+ L1.push_back(Ns[3]);
+
+ // Check setup.
+ EXPECT_EQ(4u, L1.size());
+ EXPECT_TRUE(L2.empty());
+ EXPECT_TRUE(std::is_sorted(L1.begin(), L1.end()));
+
+ // Merge.
+ auto &LHS = IsL1LHS ? L1 : L2;
+ auto &RHS = IsL1LHS ? L2 : L1;
+ LHS.merge(RHS);
+ EXPECT_TRUE(RHS.empty());
+ EXPECT_FALSE(LHS.empty());
+ EXPECT_TRUE(std::is_sorted(LHS.begin(), LHS.end()));
+ auto I = LHS.begin();
+ for (Node &N : Ns)
+ EXPECT_EQ(&N, &*I++);
+ EXPECT_EQ(LHS.end(), I);
+ }
+}
+
+TEST(SimpleIListTest, mergeBothEmpty) {
+ simple_ilist<Node> L1, L2;
+ L1.merge(L2);
+ EXPECT_TRUE(L1.empty());
+ EXPECT_TRUE(L2.empty());
+}
+
+TEST(SimpleIListTest, sort) {
+ simple_ilist<Node> L;
+ Node Ns[10];
+
+ // Fill L.
+ for (int I : {3, 4, 0, 8, 1, 2, 6, 7, 9, 5})
+ L.push_back(Ns[I]);
+
+ // Check setup.
+ EXPECT_EQ(10u, L.size());
+ EXPECT_FALSE(std::is_sorted(L.begin(), L.end()));
+
+ // Sort.
+ L.sort();
+ EXPECT_TRUE(std::is_sorted(L.begin(), L.end()));
+ auto I = L.begin();
+ for (Node &N : Ns)
+ EXPECT_EQ(&N, &*I++);
+ EXPECT_EQ(L.end(), I);
+}
+
+TEST(SimpleIListTest, sortIsStable) {
+ simple_ilist<Node> L;
+ Node Ns[10];
+
+ // Compare such that nodes are partitioned but not fully sorted.
+ auto partition = [&](const Node &N) { return &N >= &Ns[5]; };
+ auto compare = [&](const Node &L, const Node &R) {
+ return partition(L) < partition(R);
+ };
+
+ // Fill L.
+ for (int I : {3, 4, 7, 8, 1, 2, 6, 0, 9, 5})
+ L.push_back(Ns[I]);
+
+ // Check setup.
+ EXPECT_EQ(10u, L.size());
+ EXPECT_FALSE(std::is_sorted(L.begin(), L.end(), compare));
+
+ // Sort.
+ L.sort(compare);
+ EXPECT_TRUE(std::is_sorted(L.begin(), L.end(), compare));
+ auto I = L.begin();
+ for (int O : {3, 4, 1, 2, 0})
+ EXPECT_EQ(&Ns[O], &*I++);
+ for (int O : {7, 8, 6, 9, 5})
+ EXPECT_EQ(&Ns[O], &*I++);
+ EXPECT_EQ(L.end(), I);
+}
+
+TEST(SimpleIListTest, sortEmpty) {
+ simple_ilist<Node> L;
+ L.sort();
+}
+
+struct Tag1 {};
+struct Tag2 {};
+
+struct DoubleNode : ilist_node<DoubleNode, ilist_tag<Tag1>>,
+ ilist_node<DoubleNode, ilist_tag<Tag2>> {
+ typedef ilist_node<DoubleNode, ilist_tag<Tag1>> Node1Type;
+ typedef ilist_node<DoubleNode, ilist_tag<Tag2>> Node2Type;
+
+ Node1Type::self_iterator getIterator1() { return Node1Type::getIterator(); }
+ Node2Type::self_iterator getIterator2() { return Node2Type::getIterator(); }
+ Node1Type::const_self_iterator getIterator1() const {
+ return Node1Type::getIterator();
+ }
+ Node2Type::const_self_iterator getIterator2() const {
+ return Node2Type::getIterator();
+ }
+};
+typedef simple_ilist<DoubleNode, ilist_tag<Tag1>> TaggedList1Type;
+typedef simple_ilist<DoubleNode, ilist_tag<Tag2>> TaggedList2Type;
+
+TEST(SimpleIListTest, TaggedLists) {
+ TaggedList1Type L1;
+ TaggedList2Type L2;
+
+ // Build the two lists, sharing a couple of nodes.
+ DoubleNode Ns[10];
+ int Order1[] = {0, 1, 2, 3, 4, 7, 9};
+ int Order2[] = {2, 5, 6, 7, 8, 4, 9, 1};
+ for (int I : Order1)
+ L1.push_back(Ns[I]);
+ for (int I : Order2)
+ L2.push_back(Ns[I]);
+
+ // Check that each list is correct.
+ EXPECT_EQ(sizeof(Order1) / sizeof(int), L1.size());
+ auto I1 = L1.begin();
+ for (int I : Order1) {
+ EXPECT_EQ(Ns[I].getIterator1(), I1);
+ EXPECT_EQ(&Ns[I], &*I1++);
+ }
+ EXPECT_EQ(L1.end(), I1);
+
+ EXPECT_EQ(sizeof(Order2) / sizeof(int), L2.size());
+ auto I2 = L2.begin();
+ for (int I : Order2) {
+ EXPECT_EQ(Ns[I].getIterator2(), I2);
+ EXPECT_EQ(&Ns[I], &*I2++);
+ }
+ EXPECT_EQ(L2.end(), I2);
+}
+
+} // end namespace
diff --git a/unittests/ADT/SmallPtrSetTest.cpp b/unittests/ADT/SmallPtrSetTest.cpp
index d8d07b16cfe3..d4d963fdc5bd 100644
--- a/unittests/ADT/SmallPtrSetTest.cpp
+++ b/unittests/ADT/SmallPtrSetTest.cpp
@@ -21,10 +21,7 @@ TEST(SmallPtrSetTest, Assignment) {
for (int i = 0; i < 8; ++i)
buf[i] = 0;
- SmallPtrSet<int *, 4> s1;
- s1.insert(&buf[0]);
- s1.insert(&buf[1]);
-
+ SmallPtrSet<int *, 4> s1 = {&buf[0], &buf[1]};
SmallPtrSet<int *, 4> s2;
(s2 = s1).insert(&buf[2]);
@@ -38,6 +35,15 @@ TEST(SmallPtrSetTest, Assignment) {
EXPECT_TRUE(s1.count(&buf[i]));
else
EXPECT_FALSE(s1.count(&buf[i]));
+
+ // Assign and insert with initializer lists, and ones that contain both
+ // duplicates and out-of-order elements.
+ (s2 = {&buf[6], &buf[7], &buf[6]}).insert({&buf[5], &buf[4]});
+ for (int i = 0; i < 8; ++i)
+ if (i < 4)
+ EXPECT_FALSE(s2.count(&buf[i]));
+ else
+ EXPECT_TRUE(s2.count(&buf[i]));
}
TEST(SmallPtrSetTest, GrowthTest) {
diff --git a/unittests/ADT/StringExtrasTest.cpp b/unittests/ADT/StringExtrasTest.cpp
new file mode 100644
index 000000000000..afb984e405d8
--- /dev/null
+++ b/unittests/ADT/StringExtrasTest.cpp
@@ -0,0 +1,52 @@
+//===- StringExtrasTest.cpp - Unit tests for String extras ----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/StringExtras.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+TEST(StringExtrasTest, Join) {
+ std::vector<std::string> Items;
+ EXPECT_EQ("", join(Items.begin(), Items.end(), " <sep> "));
+
+ Items = {"foo"};
+ EXPECT_EQ("foo", join(Items.begin(), Items.end(), " <sep> "));
+
+ Items = {"foo", "bar"};
+ EXPECT_EQ("foo <sep> bar", join(Items.begin(), Items.end(), " <sep> "));
+
+ Items = {"foo", "bar", "baz"};
+ EXPECT_EQ("foo <sep> bar <sep> baz",
+ join(Items.begin(), Items.end(), " <sep> "));
+}
+
+TEST(StringExtrasTest, JoinItems) {
+ const char *Foo = "foo";
+ std::string Bar = "bar";
+ llvm::StringRef Baz = "baz";
+ char X = 'x';
+
+ EXPECT_EQ("", join_items(" <sep> "));
+ EXPECT_EQ("", join_items('/'));
+
+ EXPECT_EQ("foo", join_items(" <sep> ", Foo));
+ EXPECT_EQ("foo", join_items('/', Foo));
+
+ EXPECT_EQ("foo <sep> bar", join_items(" <sep> ", Foo, Bar));
+ EXPECT_EQ("foo/bar", join_items('/', Foo, Bar));
+
+ EXPECT_EQ("foo <sep> bar <sep> baz", join_items(" <sep> ", Foo, Bar, Baz));
+ EXPECT_EQ("foo/bar/baz", join_items('/', Foo, Bar, Baz));
+
+ EXPECT_EQ("foo <sep> bar <sep> baz <sep> x",
+ join_items(" <sep> ", Foo, Bar, Baz, X));
+
+ EXPECT_EQ("foo/bar/baz/x", join_items('/', Foo, Bar, Baz, X));
+}
diff --git a/unittests/ADT/StringMapTest.cpp b/unittests/ADT/StringMapTest.cpp
index 6ca701bb23a5..911c72d74961 100644
--- a/unittests/ADT/StringMapTest.cpp
+++ b/unittests/ADT/StringMapTest.cpp
@@ -458,7 +458,7 @@ struct NonMoveableNonCopyableType {
// Test that we can "emplace" an element in the map without involving map/move
TEST(StringMapCustomTest, EmplaceTest) {
StringMap<NonMoveableNonCopyableType> Map;
- Map.emplace_second("abcd", 42);
+ Map.try_emplace("abcd", 42);
EXPECT_EQ(1u, Map.count("abcd"));
EXPECT_EQ(42, Map["abcd"].Data);
}
diff --git a/unittests/ADT/StringRefTest.cpp b/unittests/ADT/StringRefTest.cpp
index 66e5944b56eb..5b6822ed757d 100644
--- a/unittests/ADT/StringRefTest.cpp
+++ b/unittests/ADT/StringRefTest.cpp
@@ -32,6 +32,34 @@ std::ostream &operator<<(std::ostream &OS,
}
+// Check that we can't accidentally assign a temporary std::string to a
+// StringRef. (Unfortunately we can't make use of the same thing with
+// constructors.)
+//
+// Disable this check under MSVC; even MSVC 2015 isn't consistent between
+// std::is_assignable and actually writing such an assignment.
+#if !defined(_MSC_VER)
+static_assert(
+ !std::is_assignable<StringRef, std::string>::value,
+ "Assigning from prvalue std::string");
+static_assert(
+ !std::is_assignable<StringRef, std::string &&>::value,
+ "Assigning from xvalue std::string");
+static_assert(
+ std::is_assignable<StringRef, std::string &>::value,
+ "Assigning from lvalue std::string");
+static_assert(
+ std::is_assignable<StringRef, const char *>::value,
+ "Assigning from prvalue C string");
+static_assert(
+ std::is_assignable<StringRef, const char * &&>::value,
+ "Assigning from xvalue C string");
+static_assert(
+ std::is_assignable<StringRef, const char * &>::value,
+ "Assigning from lvalue C string");
+#endif
+
+
namespace {
TEST(StringRefTest, Construction) {
EXPECT_EQ("", StringRef());
@@ -40,6 +68,14 @@ TEST(StringRefTest, Construction) {
EXPECT_EQ("hello", StringRef(std::string("hello")));
}
+TEST(StringRefTest, EmptyInitializerList) {
+ StringRef S = {};
+ EXPECT_TRUE(S.empty());
+
+ S = {};
+ EXPECT_TRUE(S.empty());
+}
+
TEST(StringRefTest, Iteration) {
StringRef S("hello");
const char *p = "hello";
@@ -322,6 +358,22 @@ TEST(StringRefTest, StartsWithLower) {
EXPECT_FALSE(Str.startswith_lower("hi"));
}
+TEST(StringRefTest, ConsumeFront) {
+ StringRef Str("hello");
+ EXPECT_TRUE(Str.consume_front(""));
+ EXPECT_EQ("hello", Str);
+ EXPECT_TRUE(Str.consume_front("he"));
+ EXPECT_EQ("llo", Str);
+ EXPECT_FALSE(Str.consume_front("lloworld"));
+ EXPECT_EQ("llo", Str);
+ EXPECT_FALSE(Str.consume_front("lol"));
+ EXPECT_EQ("llo", Str);
+ EXPECT_TRUE(Str.consume_front("llo"));
+ EXPECT_EQ("", Str);
+ EXPECT_FALSE(Str.consume_front("o"));
+ EXPECT_TRUE(Str.consume_front(""));
+}
+
TEST(StringRefTest, EndsWith) {
StringRef Str("hello");
EXPECT_TRUE(Str.endswith(""));
@@ -341,22 +393,75 @@ TEST(StringRefTest, EndsWithLower) {
EXPECT_FALSE(Str.endswith_lower("hi"));
}
-TEST(StringRefTest, Find) {
+TEST(StringRefTest, ConsumeBack) {
StringRef Str("hello");
- EXPECT_EQ(2U, Str.find('l'));
- EXPECT_EQ(StringRef::npos, Str.find('z'));
- EXPECT_EQ(StringRef::npos, Str.find("helloworld"));
- EXPECT_EQ(0U, Str.find("hello"));
- EXPECT_EQ(1U, Str.find("ello"));
- EXPECT_EQ(StringRef::npos, Str.find("zz"));
- EXPECT_EQ(2U, Str.find("ll", 2));
- EXPECT_EQ(StringRef::npos, Str.find("ll", 3));
- EXPECT_EQ(0U, Str.find(""));
- StringRef LongStr("hellx xello hell ello world foo bar hello");
- EXPECT_EQ(36U, LongStr.find("hello"));
- EXPECT_EQ(28U, LongStr.find("foo"));
- EXPECT_EQ(12U, LongStr.find("hell", 2));
- EXPECT_EQ(0U, LongStr.find(""));
+ EXPECT_TRUE(Str.consume_back(""));
+ EXPECT_EQ("hello", Str);
+ EXPECT_TRUE(Str.consume_back("lo"));
+ EXPECT_EQ("hel", Str);
+ EXPECT_FALSE(Str.consume_back("helhel"));
+ EXPECT_EQ("hel", Str);
+ EXPECT_FALSE(Str.consume_back("hle"));
+ EXPECT_EQ("hel", Str);
+ EXPECT_TRUE(Str.consume_back("hel"));
+ EXPECT_EQ("", Str);
+ EXPECT_FALSE(Str.consume_back("h"));
+ EXPECT_TRUE(Str.consume_back(""));
+}
+
+TEST(StringRefTest, Find) {
+ StringRef Str("helloHELLO");
+ StringRef LongStr("hellx xello hell ello world foo bar hello HELLO");
+
+ struct {
+ StringRef Str;
+ char C;
+ std::size_t From;
+ std::size_t Pos;
+ std::size_t LowerPos;
+ } CharExpectations[] = {
+ {Str, 'h', 0U, 0U, 0U},
+ {Str, 'e', 0U, 1U, 1U},
+ {Str, 'l', 0U, 2U, 2U},
+ {Str, 'l', 3U, 3U, 3U},
+ {Str, 'o', 0U, 4U, 4U},
+ {Str, 'L', 0U, 7U, 2U},
+ {Str, 'z', 0U, StringRef::npos, StringRef::npos},
+ };
+
+ struct {
+ StringRef Str;
+ llvm::StringRef S;
+ std::size_t From;
+ std::size_t Pos;
+ std::size_t LowerPos;
+ } StrExpectations[] = {
+ {Str, "helloword", 0, StringRef::npos, StringRef::npos},
+ {Str, "hello", 0, 0U, 0U},
+ {Str, "ello", 0, 1U, 1U},
+ {Str, "zz", 0, StringRef::npos, StringRef::npos},
+ {Str, "ll", 2U, 2U, 2U},
+ {Str, "ll", 3U, StringRef::npos, 7U},
+ {Str, "LL", 2U, 7U, 2U},
+ {Str, "LL", 3U, 7U, 7U},
+ {Str, "", 0U, 0U, 0U},
+ {LongStr, "hello", 0U, 36U, 36U},
+ {LongStr, "foo", 0U, 28U, 28U},
+ {LongStr, "hell", 2U, 12U, 12U},
+ {LongStr, "HELL", 2U, 42U, 12U},
+ {LongStr, "", 0U, 0U, 0U}};
+
+ for (auto &E : CharExpectations) {
+ EXPECT_EQ(E.Pos, E.Str.find(E.C, E.From));
+ EXPECT_EQ(E.LowerPos, E.Str.find_lower(E.C, E.From));
+ EXPECT_EQ(E.LowerPos, E.Str.find_lower(toupper(E.C), E.From));
+ }
+
+ for (auto &E : StrExpectations) {
+ EXPECT_EQ(E.Pos, E.Str.find(E.S, E.From));
+ EXPECT_EQ(E.LowerPos, E.Str.find_lower(E.S, E.From));
+ EXPECT_EQ(E.LowerPos, E.Str.find_lower(E.S.upper(), E.From));
+ }
EXPECT_EQ(3U, Str.rfind('l'));
EXPECT_EQ(StringRef::npos, Str.rfind('z'));
@@ -365,10 +470,19 @@ TEST(StringRefTest, Find) {
EXPECT_EQ(1U, Str.rfind("ello"));
EXPECT_EQ(StringRef::npos, Str.rfind("zz"));
+ EXPECT_EQ(8U, Str.rfind_lower('l'));
+ EXPECT_EQ(8U, Str.rfind_lower('L'));
+ EXPECT_EQ(StringRef::npos, Str.rfind_lower('z'));
+ EXPECT_EQ(StringRef::npos, Str.rfind_lower("HELLOWORLD"));
+ EXPECT_EQ(5U, Str.rfind("HELLO"));
+ EXPECT_EQ(6U, Str.rfind("ELLO"));
+ EXPECT_EQ(StringRef::npos, Str.rfind("ZZ"));
+
EXPECT_EQ(2U, Str.find_first_of('l'));
EXPECT_EQ(1U, Str.find_first_of("el"));
EXPECT_EQ(StringRef::npos, Str.find_first_of("xyz"));
+ Str = "hello";
EXPECT_EQ(1U, Str.find_first_not_of('h'));
EXPECT_EQ(4U, Str.find_first_not_of("hel"));
EXPECT_EQ(StringRef::npos, Str.find_first_not_of("hello"));
@@ -539,7 +653,8 @@ TEST(StringRefTest, getAsInteger) {
static const char* BadStrings[] = {
- "18446744073709551617" // value just over max
+ "" // empty string
+ , "18446744073709551617" // value just over max
, "123456789012345678901" // value way too large
, "4t23v" // illegal decimal characters
, "0x123W56" // illegal hex characters
@@ -547,6 +662,8 @@ static const char* BadStrings[] = {
, "08" // illegal oct characters
, "0o8" // illegal oct characters
, "-123" // negative unsigned value
+ , "0x"
+ , "0b"
};
@@ -558,6 +675,183 @@ TEST(StringRefTest, getAsUnsignedIntegerBadStrings) {
}
}
+struct ConsumeUnsignedPair {
+ const char *Str;
+ uint64_t Expected;
+ const char *Leftover;
+} ConsumeUnsigned[] = {
+ {"0", 0, ""},
+ {"255", 255, ""},
+ {"256", 256, ""},
+ {"65535", 65535, ""},
+ {"65536", 65536, ""},
+ {"4294967295", 4294967295ULL, ""},
+ {"4294967296", 4294967296ULL, ""},
+ {"255A376", 255, "A376"},
+ {"18446744073709551615", 18446744073709551615ULL, ""},
+ {"18446744073709551615ABC", 18446744073709551615ULL, "ABC"},
+ {"042", 34, ""},
+ {"0x42", 66, ""},
+ {"0x42-0x34", 66, "-0x34"},
+ {"0b101010", 42, ""},
+ {"0429F", 042, "9F"}, // Auto-sensed octal radix, invalid digit
+ {"0x42G12", 0x42, "G12"}, // Auto-sensed hex radix, invalid digit
+ {"0b10101020101", 42, "20101"}}; // Auto-sensed binary radix, invalid digit.
+
+struct ConsumeSignedPair {
+ const char *Str;
+ int64_t Expected;
+ const char *Leftover;
+} ConsumeSigned[] = {
+ {"0", 0, ""},
+ {"-0", 0, ""},
+ {"0-1", 0, "-1"},
+ {"-0-1", 0, "-1"},
+ {"127", 127, ""},
+ {"128", 128, ""},
+ {"127-1", 127, "-1"},
+ {"128-1", 128, "-1"},
+ {"-128", -128, ""},
+ {"-129", -129, ""},
+ {"-128-1", -128, "-1"},
+ {"-129-1", -129, "-1"},
+ {"32767", 32767, ""},
+ {"32768", 32768, ""},
+ {"32767-1", 32767, "-1"},
+ {"32768-1", 32768, "-1"},
+ {"-32768", -32768, ""},
+ {"-32769", -32769, ""},
+ {"-32768-1", -32768, "-1"},
+ {"-32769-1", -32769, "-1"},
+ {"2147483647", 2147483647LL, ""},
+ {"2147483648", 2147483648LL, ""},
+ {"2147483647-1", 2147483647LL, "-1"},
+ {"2147483648-1", 2147483648LL, "-1"},
+ {"-2147483648", -2147483648LL, ""},
+ {"-2147483649", -2147483649LL, ""},
+ {"-2147483648-1", -2147483648LL, "-1"},
+ {"-2147483649-1", -2147483649LL, "-1"},
+ {"-9223372036854775808", -(9223372036854775807LL) - 1, ""},
+ {"-9223372036854775808-1", -(9223372036854775807LL) - 1, "-1"},
+ {"042", 34, ""},
+ {"042-1", 34, "-1"},
+ {"0x42", 66, ""},
+ {"0x42-1", 66, "-1"},
+ {"0b101010", 42, ""},
+ {"0b101010-1", 42, "-1"},
+ {"-042", -34, ""},
+ {"-042-1", -34, "-1"},
+ {"-0x42", -66, ""},
+ {"-0x42-1", -66, "-1"},
+ {"-0b101010", -42, ""},
+ {"-0b101010-1", -42, "-1"}};
+
+TEST(StringRefTest, consumeIntegerUnsigned) {
+ uint8_t U8;
+ uint16_t U16;
+ uint32_t U32;
+ uint64_t U64;
+
+ for (size_t i = 0; i < array_lengthof(ConsumeUnsigned); ++i) {
+ StringRef Str = ConsumeUnsigned[i].Str;
+ bool U8Success = Str.consumeInteger(0, U8);
+ if (static_cast<uint8_t>(ConsumeUnsigned[i].Expected) ==
+ ConsumeUnsigned[i].Expected) {
+ ASSERT_FALSE(U8Success);
+ EXPECT_EQ(U8, ConsumeUnsigned[i].Expected);
+ EXPECT_EQ(Str, ConsumeUnsigned[i].Leftover);
+ } else {
+ ASSERT_TRUE(U8Success);
+ }
+
+ Str = ConsumeUnsigned[i].Str;
+ bool U16Success = Str.consumeInteger(0, U16);
+ if (static_cast<uint16_t>(ConsumeUnsigned[i].Expected) ==
+ ConsumeUnsigned[i].Expected) {
+ ASSERT_FALSE(U16Success);
+ EXPECT_EQ(U16, ConsumeUnsigned[i].Expected);
+ EXPECT_EQ(Str, ConsumeUnsigned[i].Leftover);
+ } else {
+ ASSERT_TRUE(U16Success);
+ }
+
+ Str = ConsumeUnsigned[i].Str;
+ bool U32Success = Str.consumeInteger(0, U32);
+ if (static_cast<uint32_t>(ConsumeUnsigned[i].Expected) ==
+ ConsumeUnsigned[i].Expected) {
+ ASSERT_FALSE(U32Success);
+ EXPECT_EQ(U32, ConsumeUnsigned[i].Expected);
+ EXPECT_EQ(Str, ConsumeUnsigned[i].Leftover);
+ } else {
+ ASSERT_TRUE(U32Success);
+ }
+
+ Str = ConsumeUnsigned[i].Str;
+ bool U64Success = Str.consumeInteger(0, U64);
+ if (static_cast<uint64_t>(ConsumeUnsigned[i].Expected) ==
+ ConsumeUnsigned[i].Expected) {
+ ASSERT_FALSE(U64Success);
+ EXPECT_EQ(U64, ConsumeUnsigned[i].Expected);
+ EXPECT_EQ(Str, ConsumeUnsigned[i].Leftover);
+ } else {
+ ASSERT_TRUE(U64Success);
+ }
+ }
+}
+
+TEST(StringRefTest, consumeIntegerSigned) {
+ int8_t S8;
+ int16_t S16;
+ int32_t S32;
+ int64_t S64;
+
+ for (size_t i = 0; i < array_lengthof(ConsumeSigned); ++i) {
+ StringRef Str = ConsumeSigned[i].Str;
+ bool S8Success = Str.consumeInteger(0, S8);
+ if (static_cast<int8_t>(ConsumeSigned[i].Expected) ==
+ ConsumeSigned[i].Expected) {
+ ASSERT_FALSE(S8Success);
+ EXPECT_EQ(S8, ConsumeSigned[i].Expected);
+ EXPECT_EQ(Str, ConsumeSigned[i].Leftover);
+ } else {
+ ASSERT_TRUE(S8Success);
+ }
+
+ Str = ConsumeSigned[i].Str;
+ bool S16Success = Str.consumeInteger(0, S16);
+ if (static_cast<int16_t>(ConsumeSigned[i].Expected) ==
+ ConsumeSigned[i].Expected) {
+ ASSERT_FALSE(S16Success);
+ EXPECT_EQ(S16, ConsumeSigned[i].Expected);
+ EXPECT_EQ(Str, ConsumeSigned[i].Leftover);
+ } else {
+ ASSERT_TRUE(S16Success);
+ }
+
+ Str = ConsumeSigned[i].Str;
+ bool S32Success = Str.consumeInteger(0, S32);
+ if (static_cast<int32_t>(ConsumeSigned[i].Expected) ==
+ ConsumeSigned[i].Expected) {
+ ASSERT_FALSE(S32Success);
+ EXPECT_EQ(S32, ConsumeSigned[i].Expected);
+ EXPECT_EQ(Str, ConsumeSigned[i].Leftover);
+ } else {
+ ASSERT_TRUE(S32Success);
+ }
+
+ Str = ConsumeSigned[i].Str;
+ bool S64Success = Str.consumeInteger(0, S64);
+ if (static_cast<int64_t>(ConsumeSigned[i].Expected) ==
+ ConsumeSigned[i].Expected) {
+ ASSERT_FALSE(S64Success);
+ EXPECT_EQ(S64, ConsumeSigned[i].Expected);
+ EXPECT_EQ(Str, ConsumeSigned[i].Leftover);
+ } else {
+ ASSERT_TRUE(S64Success);
+ }
+ }
+}
+
static const char *join_input[] = { "a", "b", "c" };
static const char join_result1[] = "a";
static const char join_result2[] = "a:b:c";
@@ -608,5 +902,110 @@ TEST(StringRefTest, AllocatorCopy) {
EXPECT_NE(Str2.data(), Str2c.data());
}
+TEST(StringRefTest, Drop) {
+ StringRef Test("StringRefTest::Drop");
+
+ StringRef Dropped = Test.drop_front(5);
+ EXPECT_EQ(Dropped, "gRefTest::Drop");
+
+ Dropped = Test.drop_back(5);
+ EXPECT_EQ(Dropped, "StringRefTest:");
+
+ Dropped = Test.drop_front(0);
+ EXPECT_EQ(Dropped, Test);
+
+ Dropped = Test.drop_back(0);
+ EXPECT_EQ(Dropped, Test);
+
+ Dropped = Test.drop_front(Test.size());
+ EXPECT_TRUE(Dropped.empty());
+
+ Dropped = Test.drop_back(Test.size());
+ EXPECT_TRUE(Dropped.empty());
+}
+
+TEST(StringRefTest, Take) {
+ StringRef Test("StringRefTest::Take");
+
+ StringRef Taken = Test.take_front(5);
+ EXPECT_EQ(Taken, "Strin");
+
+ Taken = Test.take_back(5);
+ EXPECT_EQ(Taken, ":Take");
+
+ Taken = Test.take_front(Test.size());
+ EXPECT_EQ(Taken, Test);
+
+ Taken = Test.take_back(Test.size());
+ EXPECT_EQ(Taken, Test);
+
+ Taken = Test.take_front(0);
+ EXPECT_TRUE(Taken.empty());
+
+ Taken = Test.take_back(0);
+ EXPECT_TRUE(Taken.empty());
+}
+
+TEST(StringRefTest, FindIf) {
+ StringRef Punct("Test.String");
+ StringRef NoPunct("ABCDEFG");
+ StringRef Empty;
+
+ auto IsPunct = [](char c) { return ::ispunct(c); };
+ auto IsAlpha = [](char c) { return ::isalpha(c); };
+ EXPECT_EQ(4U, Punct.find_if(IsPunct));
+ EXPECT_EQ(StringRef::npos, NoPunct.find_if(IsPunct));
+ EXPECT_EQ(StringRef::npos, Empty.find_if(IsPunct));
+
+ EXPECT_EQ(4U, Punct.find_if_not(IsAlpha));
+ EXPECT_EQ(StringRef::npos, NoPunct.find_if_not(IsAlpha));
+ EXPECT_EQ(StringRef::npos, Empty.find_if_not(IsAlpha));
+}
+
+TEST(StringRefTest, TakeWhileUntil) {
+ StringRef Test("String With 1 Number");
+
+ StringRef Taken = Test.take_while([](char c) { return ::isdigit(c); });
+ EXPECT_EQ("", Taken);
+
+ Taken = Test.take_until([](char c) { return ::isdigit(c); });
+ EXPECT_EQ("String With ", Taken);
+
+ Taken = Test.take_while([](char c) { return true; });
+ EXPECT_EQ(Test, Taken);
+
+ Taken = Test.take_until([](char c) { return true; });
+ EXPECT_EQ("", Taken);
+
+ Test = "";
+ Taken = Test.take_while([](char c) { return true; });
+ EXPECT_EQ("", Taken);
+}
+
+TEST(StringRefTest, DropWhileUntil) {
+ StringRef Test("String With 1 Number");
+
+ StringRef Taken = Test.drop_while([](char c) { return ::isdigit(c); });
+ EXPECT_EQ(Test, Taken);
+
+ Taken = Test.drop_until([](char c) { return ::isdigit(c); });
+ EXPECT_EQ("1 Number", Taken);
+
+ Taken = Test.drop_while([](char c) { return true; });
+ EXPECT_EQ("", Taken);
+
+ Taken = Test.drop_until([](char c) { return true; });
+ EXPECT_EQ(Test, Taken);
+
+ StringRef EmptyString = "";
+ Taken = EmptyString.drop_while([](char c) { return true; });
+ EXPECT_EQ("", Taken);
+}
+
+TEST(StringRefTest, StringLiteral) {
+ constexpr StringLiteral Strings[] = {"Foo", "Bar"};
+ EXPECT_EQ(StringRef("Foo"), Strings[0]);
+ EXPECT_EQ(StringRef("Bar"), Strings[1]);
+}
} // end anonymous namespace
diff --git a/unittests/ADT/StringSwitchTest.cpp b/unittests/ADT/StringSwitchTest.cpp
new file mode 100644
index 000000000000..1a51629ca574
--- /dev/null
+++ b/unittests/ADT/StringSwitchTest.cpp
@@ -0,0 +1,206 @@
+//===- llvm/unittest/ADT/StringSwitchTest.cpp - StringSwitch unit tests ---===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/StringSwitch.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+TEST(StringSwitchTest, Case) {
+ auto Translate = [](StringRef S) {
+ return llvm::StringSwitch<int>(S)
+ .Case("0", 0)
+ .Case("1", 1)
+ .Case("2", 2)
+ .Case("3", 3)
+ .Case("4", 4)
+ .Case("5", 5)
+ .Case("6", 6)
+ .Case("7", 7)
+ .Case("8", 8)
+ .Case("9", 9)
+ .Case("A", 10)
+ .Case("B", 11)
+ .Case("C", 12)
+ .Case("D", 13)
+ .Case("E", 14)
+ .Case("F", 15)
+ .Default(-1);
+ };
+ EXPECT_EQ(1, Translate("1"));
+ EXPECT_EQ(2, Translate("2"));
+ EXPECT_EQ(11, Translate("B"));
+ EXPECT_EQ(-1, Translate("b"));
+ EXPECT_EQ(-1, Translate(""));
+ EXPECT_EQ(-1, Translate("Test"));
+}
+
+TEST(StringSwitchTest, CaseLower) {
+ auto Translate = [](StringRef S) {
+ return llvm::StringSwitch<int>(S)
+ .Case("0", 0)
+ .Case("1", 1)
+ .Case("2", 2)
+ .Case("3", 3)
+ .Case("4", 4)
+ .Case("5", 5)
+ .Case("6", 6)
+ .Case("7", 7)
+ .Case("8", 8)
+ .Case("9", 9)
+ .CaseLower("A", 10)
+ .CaseLower("B", 11)
+ .CaseLower("C", 12)
+ .CaseLower("D", 13)
+ .CaseLower("E", 14)
+ .CaseLower("F", 15)
+ .Default(-1);
+ };
+ EXPECT_EQ(1, Translate("1"));
+ EXPECT_EQ(2, Translate("2"));
+ EXPECT_EQ(11, Translate("B"));
+ EXPECT_EQ(11, Translate("b"));
+
+ EXPECT_EQ(-1, Translate(""));
+ EXPECT_EQ(-1, Translate("Test"));
+}
+
+TEST(StringSwitchTest, StartsWith) {
+ auto Translate = [](StringRef S) {
+ return llvm::StringSwitch<std::function<int(int, int)>>(S)
+ .StartsWith("add", [](int X, int Y) { return X + Y; })
+ .StartsWith("sub", [](int X, int Y) { return X - Y; })
+ .StartsWith("mul", [](int X, int Y) { return X * Y; })
+ .StartsWith("div", [](int X, int Y) { return X / Y; })
+ .Default([](int X, int Y) { return 0; });
+ };
+
+ EXPECT_EQ(15, Translate("adder")(10, 5));
+ EXPECT_EQ(5, Translate("subtracter")(10, 5));
+ EXPECT_EQ(50, Translate("multiplier")(10, 5));
+ EXPECT_EQ(2, Translate("divider")(10, 5));
+
+ EXPECT_EQ(0, Translate("nothing")(10, 5));
+ EXPECT_EQ(0, Translate("ADDER")(10, 5));
+}
+
+TEST(StringSwitchTest, StartsWithLower) {
+ auto Translate = [](StringRef S) {
+ return llvm::StringSwitch<std::function<int(int, int)>>(S)
+ .StartsWithLower("add", [](int X, int Y) { return X + Y; })
+ .StartsWithLower("sub", [](int X, int Y) { return X - Y; })
+ .StartsWithLower("mul", [](int X, int Y) { return X * Y; })
+ .StartsWithLower("div", [](int X, int Y) { return X / Y; })
+ .Default([](int X, int Y) { return 0; });
+ };
+
+ EXPECT_EQ(15, Translate("adder")(10, 5));
+ EXPECT_EQ(5, Translate("subtracter")(10, 5));
+ EXPECT_EQ(50, Translate("multiplier")(10, 5));
+ EXPECT_EQ(2, Translate("divider")(10, 5));
+
+ EXPECT_EQ(15, Translate("AdDeR")(10, 5));
+ EXPECT_EQ(5, Translate("SuBtRaCtEr")(10, 5));
+ EXPECT_EQ(50, Translate("MuLtIpLiEr")(10, 5));
+ EXPECT_EQ(2, Translate("DiViDeR")(10, 5));
+
+ EXPECT_EQ(0, Translate("nothing")(10, 5));
+}
+
+TEST(StringSwitchTest, EndsWith) {
+ enum class Suffix { Possible, PastTense, Process, InProgressAction, Unknown };
+
+ auto Translate = [](StringRef S) {
+ return llvm::StringSwitch<Suffix>(S)
+ .EndsWith("able", Suffix::Possible)
+ .EndsWith("ed", Suffix::PastTense)
+ .EndsWith("ation", Suffix::Process)
+ .EndsWith("ing", Suffix::InProgressAction)
+ .Default(Suffix::Unknown);
+ };
+
+ EXPECT_EQ(Suffix::Possible, Translate("optimizable"));
+ EXPECT_EQ(Suffix::PastTense, Translate("optimized"));
+ EXPECT_EQ(Suffix::Process, Translate("optimization"));
+ EXPECT_EQ(Suffix::InProgressAction, Translate("optimizing"));
+ EXPECT_EQ(Suffix::Unknown, Translate("optimizer"));
+ EXPECT_EQ(Suffix::Unknown, Translate("OPTIMIZABLE"));
+}
+
+TEST(StringSwitchTest, EndsWithLower) {
+ enum class Suffix { Possible, PastTense, Process, InProgressAction, Unknown };
+
+ auto Translate = [](StringRef S) {
+ return llvm::StringSwitch<Suffix>(S)
+ .EndsWithLower("able", Suffix::Possible)
+ .EndsWithLower("ed", Suffix::PastTense)
+ .EndsWithLower("ation", Suffix::Process)
+ .EndsWithLower("ing", Suffix::InProgressAction)
+ .Default(Suffix::Unknown);
+ };
+
+ EXPECT_EQ(Suffix::Possible, Translate("optimizable"));
+ EXPECT_EQ(Suffix::Possible, Translate("OPTIMIZABLE"));
+ EXPECT_EQ(Suffix::PastTense, Translate("optimized"));
+ EXPECT_EQ(Suffix::Process, Translate("optimization"));
+ EXPECT_EQ(Suffix::InProgressAction, Translate("optimizing"));
+ EXPECT_EQ(Suffix::Unknown, Translate("optimizer"));
+}
+
+TEST(StringSwitchTest, Cases) {
+ enum class OSType { Windows, Linux, Unknown };
+
+ auto Translate = [](StringRef S) {
+ return llvm::StringSwitch<OSType>(S)
+ .Cases("wind\0ws", "win32", "winnt", OSType::Windows)
+ .Cases("linux", "unix", "*nix", "posix", OSType::Linux)
+ .Default(OSType::Unknown);
+ };
+
+ EXPECT_EQ(OSType::Windows, Translate(llvm::StringRef("wind\0ws", 7)));
+ EXPECT_EQ(OSType::Windows, Translate("win32"));
+ EXPECT_EQ(OSType::Windows, Translate("winnt"));
+
+ EXPECT_EQ(OSType::Linux, Translate("linux"));
+ EXPECT_EQ(OSType::Linux, Translate("unix"));
+ EXPECT_EQ(OSType::Linux, Translate("*nix"));
+ EXPECT_EQ(OSType::Linux, Translate("posix"));
+
+ // Note that the whole null-terminator embedded string is required for the
+ // case to match.
+ EXPECT_EQ(OSType::Unknown, Translate("wind"));
+ EXPECT_EQ(OSType::Unknown, Translate("Windows"));
+ EXPECT_EQ(OSType::Unknown, Translate(""));
+}
+
+TEST(StringSwitchTest, CasesLower) {
+ enum class OSType { Windows, Linux, Unknown };
+
+ auto Translate = [](StringRef S) {
+ return llvm::StringSwitch<OSType>(S)
+ .CasesLower("wind\0ws", "win32", "winnt", OSType::Windows)
+ .CasesLower("linux", "unix", "*nix", "posix", OSType::Linux)
+ .Default(OSType::Unknown);
+ };
+
+ EXPECT_EQ(OSType::Windows, Translate(llvm::StringRef("WIND\0WS", 7)));
+ EXPECT_EQ(OSType::Windows, Translate("WIN32"));
+ EXPECT_EQ(OSType::Windows, Translate("WINNT"));
+
+ EXPECT_EQ(OSType::Linux, Translate("LINUX"));
+ EXPECT_EQ(OSType::Linux, Translate("UNIX"));
+ EXPECT_EQ(OSType::Linux, Translate("*NIX"));
+ EXPECT_EQ(OSType::Linux, Translate("POSIX"));
+
+ EXPECT_EQ(OSType::Windows, Translate(llvm::StringRef("wind\0ws", 7)));
+ EXPECT_EQ(OSType::Linux, Translate("linux"));
+
+ EXPECT_EQ(OSType::Unknown, Translate("wind"));
+ EXPECT_EQ(OSType::Unknown, Translate(""));
+}
diff --git a/unittests/ADT/TestGraph.h b/unittests/ADT/TestGraph.h
new file mode 100644
index 000000000000..1c495d24bc0d
--- /dev/null
+++ b/unittests/ADT/TestGraph.h
@@ -0,0 +1,251 @@
+//===- llvm/unittest/ADT/TestGraph.h - Graph for testing ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Common graph data structure for testing.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/GraphTraits.h"
+#include <cassert>
+#include <climits>
+#include <utility>
+
+#ifndef LLVM_UNITTESTS_ADT_TEST_GRAPH_H
+#define LLVM_UNITTESTS_ADT_TEST_GRAPH_H
+
+namespace llvm {
+
+/// Graph<N> - A graph with N nodes. Note that N can be at most 8.
+template <unsigned N>
+class Graph {
+private:
+ // Disable copying.
+ Graph(const Graph&);
+ Graph& operator=(const Graph&);
+
+ static void ValidateIndex(unsigned Idx) {
+ assert(Idx < N && "Invalid node index!");
+ }
+public:
+
+ /// NodeSubset - A subset of the graph's nodes.
+ class NodeSubset {
+ typedef unsigned char BitVector; // Where the limitation N <= 8 comes from.
+ BitVector Elements;
+ NodeSubset(BitVector e) : Elements(e) {}
+ public:
+ /// NodeSubset - Default constructor, creates an empty subset.
+ NodeSubset() : Elements(0) {
+ assert(N <= sizeof(BitVector)*CHAR_BIT && "Graph too big!");
+ }
+
+ /// Comparison operators.
+ bool operator==(const NodeSubset &other) const {
+ return other.Elements == this->Elements;
+ }
+ bool operator!=(const NodeSubset &other) const {
+ return !(*this == other);
+ }
+
+ /// AddNode - Add the node with the given index to the subset.
+ void AddNode(unsigned Idx) {
+ ValidateIndex(Idx);
+ Elements |= 1U << Idx;
+ }
+
+ /// DeleteNode - Remove the node with the given index from the subset.
+ void DeleteNode(unsigned Idx) {
+ ValidateIndex(Idx);
+ Elements &= ~(1U << Idx);
+ }
+
+ /// count - Return true if the node with the given index is in the subset.
+ bool count(unsigned Idx) {
+ ValidateIndex(Idx);
+ return (Elements & (1U << Idx)) != 0;
+ }
+
+ /// isEmpty - Return true if this is the empty set.
+ bool isEmpty() const {
+ return Elements == 0;
+ }
+
+ /// isSubsetOf - Return true if this set is a subset of the given one.
+ bool isSubsetOf(const NodeSubset &other) const {
+ return (this->Elements | other.Elements) == other.Elements;
+ }
+
+ /// Complement - Return the complement of this subset.
+ NodeSubset Complement() const {
+ return ~(unsigned)this->Elements & ((1U << N) - 1);
+ }
+
+ /// Join - Return the union of this subset and the given one.
+ NodeSubset Join(const NodeSubset &other) const {
+ return this->Elements | other.Elements;
+ }
+
+ /// Meet - Return the intersection of this subset and the given one.
+ NodeSubset Meet(const NodeSubset &other) const {
+ return this->Elements & other.Elements;
+ }
+ };
+
+ /// NodeType - Node index and set of children of the node.
+ typedef std::pair<unsigned, NodeSubset> NodeType;
+
+private:
+ /// Nodes - The list of nodes for this graph.
+ NodeType Nodes[N];
+public:
+
+ /// Graph - Default constructor. Creates an empty graph.
+ Graph() {
+ // Let each node know which node it is. This allows us to find the start of
+ // the Nodes array given a pointer to any element of it.
+ for (unsigned i = 0; i != N; ++i)
+ Nodes[i].first = i;
+ }
+
+ /// AddEdge - Add an edge from the node with index FromIdx to the node with
+ /// index ToIdx.
+ void AddEdge(unsigned FromIdx, unsigned ToIdx) {
+ ValidateIndex(FromIdx);
+ Nodes[FromIdx].second.AddNode(ToIdx);
+ }
+
+ /// DeleteEdge - Remove the edge (if any) from the node with index FromIdx to
+ /// the node with index ToIdx.
+ void DeleteEdge(unsigned FromIdx, unsigned ToIdx) {
+ ValidateIndex(FromIdx);
+ Nodes[FromIdx].second.DeleteNode(ToIdx);
+ }
+
+ /// AccessNode - Get a pointer to the node with the given index.
+ NodeType *AccessNode(unsigned Idx) const {
+ ValidateIndex(Idx);
+ // The constant cast is needed when working with GraphTraits, which insists
+ // on taking a constant Graph.
+ return const_cast<NodeType *>(&Nodes[Idx]);
+ }
+
+ /// NodesReachableFrom - Return the set of all nodes reachable from the given
+ /// node.
+ NodeSubset NodesReachableFrom(unsigned Idx) const {
+ // This algorithm doesn't scale, but that doesn't matter given the small
+ // size of our graphs.
+ NodeSubset Reachable;
+
+ // The initial node is reachable.
+ Reachable.AddNode(Idx);
+ do {
+ NodeSubset Previous(Reachable);
+
+ // Add in all nodes which are children of a reachable node.
+ for (unsigned i = 0; i != N; ++i)
+ if (Previous.count(i))
+ Reachable = Reachable.Join(Nodes[i].second);
+
+ // If nothing changed then we have found all reachable nodes.
+ if (Reachable == Previous)
+ return Reachable;
+
+ // Rinse and repeat.
+ } while (1);
+ }
+
+ /// ChildIterator - Visit all children of a node.
+ class ChildIterator {
+ friend class Graph;
+
+ /// FirstNode - Pointer to first node in the graph's Nodes array.
+ NodeType *FirstNode;
+ /// Children - Set of nodes which are children of this one and that haven't
+ /// yet been visited.
+ NodeSubset Children;
+
+ ChildIterator(); // Disable default constructor.
+ protected:
+ ChildIterator(NodeType *F, NodeSubset C) : FirstNode(F), Children(C) {}
+
+ public:
+ /// ChildIterator - Copy constructor.
+ ChildIterator(const ChildIterator& other) : FirstNode(other.FirstNode),
+ Children(other.Children) {}
+
+ /// Comparison operators.
+ bool operator==(const ChildIterator &other) const {
+ return other.FirstNode == this->FirstNode &&
+ other.Children == this->Children;
+ }
+ bool operator!=(const ChildIterator &other) const {
+ return !(*this == other);
+ }
+
+ /// Prefix increment operator.
+ ChildIterator& operator++() {
+ // Find the next unvisited child node.
+ for (unsigned i = 0; i != N; ++i)
+ if (Children.count(i)) {
+ // Remove that child - it has been visited. This is the increment!
+ Children.DeleteNode(i);
+ return *this;
+ }
+ assert(false && "Incrementing end iterator!");
+ return *this; // Avoid compiler warnings.
+ }
+
+ /// Postfix increment operator.
+ ChildIterator operator++(int) {
+ ChildIterator Result(*this);
+ ++(*this);
+ return Result;
+ }
+
+ /// Dereference operator.
+ NodeType *operator*() {
+ // Find the next unvisited child node.
+ for (unsigned i = 0; i != N; ++i)
+ if (Children.count(i))
+ // Return a pointer to it.
+ return FirstNode + i;
+ assert(false && "Dereferencing end iterator!");
+ return nullptr; // Avoid compiler warning.
+ }
+ };
+
+ /// child_begin - Return an iterator pointing to the first child of the given
+ /// node.
+ static ChildIterator child_begin(NodeType *Parent) {
+ return ChildIterator(Parent - Parent->first, Parent->second);
+ }
+
+ /// child_end - Return the end iterator for children of the given node.
+ static ChildIterator child_end(NodeType *Parent) {
+ return ChildIterator(Parent - Parent->first, NodeSubset());
+ }
+};
+
+template <unsigned N>
+struct GraphTraits<Graph<N> > {
+ typedef typename Graph<N>::NodeType *NodeRef;
+ typedef typename Graph<N>::ChildIterator ChildIteratorType;
+
+ static NodeRef getEntryNode(const Graph<N> &G) { return G.AccessNode(0); }
+ static ChildIteratorType child_begin(NodeRef Node) {
+ return Graph<N>::child_begin(Node);
+ }
+ static ChildIteratorType child_end(NodeRef Node) {
+ return Graph<N>::child_end(Node);
+ }
+};
+
+} // End namespace llvm
+
+#endif
diff --git a/unittests/ADT/TripleTest.cpp b/unittests/ADT/TripleTest.cpp
index 984f4a2a595a..c80477f6ddc9 100644
--- a/unittests/ADT/TripleTest.cpp
+++ b/unittests/ADT/TripleTest.cpp
@@ -87,6 +87,12 @@ TEST(TripleTest, ParsedIDs) {
EXPECT_EQ(Triple::ELFIAMCU, T.getOS());
EXPECT_EQ(Triple::UnknownEnvironment, T.getEnvironment());
+ T = Triple("i386-pc-contiki-unknown");
+ EXPECT_EQ(Triple::x86, T.getArch());
+ EXPECT_EQ(Triple::PC, T.getVendor());
+ EXPECT_EQ(Triple::Contiki, T.getOS());
+ EXPECT_EQ(Triple::UnknownEnvironment, T.getEnvironment());
+
T = Triple("x86_64-pc-linux-gnu");
EXPECT_EQ(Triple::x86_64, T.getArch());
EXPECT_EQ(Triple::PC, T.getVendor());
@@ -200,6 +206,12 @@ TEST(TripleTest, ParsedIDs) {
EXPECT_EQ(Triple::CloudABI, T.getOS());
EXPECT_EQ(Triple::UnknownEnvironment, T.getEnvironment());
+ T = Triple("x86_64-unknown-fuchsia");
+ EXPECT_EQ(Triple::x86_64, T.getArch());
+ EXPECT_EQ(Triple::UnknownVendor, T.getVendor());
+ EXPECT_EQ(Triple::Fuchsia, T.getOS());
+ EXPECT_EQ(Triple::UnknownEnvironment, T.getEnvironment());
+
T = Triple("wasm32-unknown-unknown");
EXPECT_EQ(Triple::wasm32, T.getArch());
EXPECT_EQ(Triple::UnknownVendor, T.getVendor());
@@ -248,6 +260,30 @@ TEST(TripleTest, ParsedIDs) {
EXPECT_EQ(Triple::AMDHSA, T.getOS());
EXPECT_EQ(Triple::UnknownEnvironment, T.getEnvironment());
+ T = Triple("amdgcn-amd-amdhsa-opencl");
+ EXPECT_EQ(Triple::amdgcn, T.getArch());
+ EXPECT_EQ(Triple::AMD, T.getVendor());
+ EXPECT_EQ(Triple::AMDHSA, T.getOS());
+ EXPECT_EQ(Triple::OpenCL, T.getEnvironment());
+
+ T = Triple("riscv32-unknown-unknown");
+ EXPECT_EQ(Triple::riscv32, T.getArch());
+ EXPECT_EQ(Triple::UnknownVendor, T.getVendor());
+ EXPECT_EQ(Triple::UnknownOS, T.getOS());
+ EXPECT_EQ(Triple::UnknownEnvironment, T.getEnvironment());
+
+ T = Triple("riscv64-unknown-linux");
+ EXPECT_EQ(Triple::riscv64, T.getArch());
+ EXPECT_EQ(Triple::UnknownVendor, T.getVendor());
+ EXPECT_EQ(Triple::Linux, T.getOS());
+ EXPECT_EQ(Triple::UnknownEnvironment, T.getEnvironment());
+
+ T = Triple("riscv64-unknown-freebsd");
+ EXPECT_EQ(Triple::riscv64, T.getArch());
+ EXPECT_EQ(Triple::UnknownVendor, T.getVendor());
+ EXPECT_EQ(Triple::FreeBSD, T.getOS());
+ EXPECT_EQ(Triple::UnknownEnvironment, T.getEnvironment());
+
T = Triple("huh");
EXPECT_EQ(Triple::UnknownArch, T.getArch());
}
@@ -302,60 +338,74 @@ TEST(TripleTest, Normalization) {
// Check that normalizing a permutated set of valid components returns a
// triple with the unpermuted components.
- StringRef C[4];
- for (int Arch = 1+Triple::UnknownArch; Arch <= Triple::LastArchType; ++Arch) {
+ //
+ // We don't check every possible combination. For the set of architectures A,
+ // vendors V, operating systems O, and environments E, that would require |A|
+ // * |V| * |O| * |E| * 4! tests. Instead we check every option for any given
+ // slot and make sure it gets normalized to the correct position from every
+ // permutation. This should cover the core logic while being a tractable
+ // number of tests at (|A| + |V| + |O| + |E|) * 4!.
+ auto FirstArchType = Triple::ArchType(Triple::UnknownArch + 1);
+ auto FirstVendorType = Triple::VendorType(Triple::UnknownVendor + 1);
+ auto FirstOSType = Triple::OSType(Triple::UnknownOS + 1);
+ auto FirstEnvType = Triple::EnvironmentType(Triple::UnknownEnvironment + 1);
+ StringRef InitialC[] = {Triple::getArchTypeName(FirstArchType),
+ Triple::getVendorTypeName(FirstVendorType),
+ Triple::getOSTypeName(FirstOSType),
+ Triple::getEnvironmentTypeName(FirstEnvType)};
+ for (int Arch = FirstArchType; Arch <= Triple::LastArchType; ++Arch) {
+ StringRef C[] = {InitialC[0], InitialC[1], InitialC[2], InitialC[3]};
C[0] = Triple::getArchTypeName(Triple::ArchType(Arch));
- for (int Vendor = 1+Triple::UnknownVendor; Vendor <= Triple::LastVendorType;
- ++Vendor) {
- C[1] = Triple::getVendorTypeName(Triple::VendorType(Vendor));
- for (int OS = 1+Triple::UnknownOS; OS <= Triple::LastOSType; ++OS) {
- if (OS == Triple::Win32)
- continue;
-
- C[2] = Triple::getOSTypeName(Triple::OSType(OS));
-
- std::string E = Join(C[0], C[1], C[2]);
- EXPECT_EQ(E, Triple::normalize(Join(C[0], C[1], C[2])));
-
- EXPECT_EQ(E, Triple::normalize(Join(C[0], C[2], C[1])));
- EXPECT_EQ(E, Triple::normalize(Join(C[1], C[2], C[0])));
- EXPECT_EQ(E, Triple::normalize(Join(C[1], C[0], C[2])));
- EXPECT_EQ(E, Triple::normalize(Join(C[2], C[0], C[1])));
- EXPECT_EQ(E, Triple::normalize(Join(C[2], C[1], C[0])));
-
- for (int Env = 1 + Triple::UnknownEnvironment; Env <= Triple::LastEnvironmentType;
- ++Env) {
- C[3] = Triple::getEnvironmentTypeName(Triple::EnvironmentType(Env));
-
- std::string F = Join(C[0], C[1], C[2], C[3]);
- EXPECT_EQ(F, Triple::normalize(Join(C[0], C[1], C[2], C[3])));
-
- EXPECT_EQ(F, Triple::normalize(Join(C[0], C[1], C[3], C[2])));
- EXPECT_EQ(F, Triple::normalize(Join(C[0], C[2], C[3], C[1])));
- EXPECT_EQ(F, Triple::normalize(Join(C[0], C[2], C[1], C[3])));
- EXPECT_EQ(F, Triple::normalize(Join(C[0], C[3], C[1], C[2])));
- EXPECT_EQ(F, Triple::normalize(Join(C[0], C[3], C[2], C[1])));
- EXPECT_EQ(F, Triple::normalize(Join(C[1], C[2], C[3], C[0])));
- EXPECT_EQ(F, Triple::normalize(Join(C[1], C[2], C[0], C[3])));
- EXPECT_EQ(F, Triple::normalize(Join(C[1], C[3], C[0], C[2])));
- EXPECT_EQ(F, Triple::normalize(Join(C[1], C[3], C[2], C[0])));
- EXPECT_EQ(F, Triple::normalize(Join(C[1], C[0], C[2], C[3])));
- EXPECT_EQ(F, Triple::normalize(Join(C[1], C[0], C[3], C[2])));
- EXPECT_EQ(F, Triple::normalize(Join(C[2], C[3], C[0], C[1])));
- EXPECT_EQ(F, Triple::normalize(Join(C[2], C[3], C[1], C[0])));
- EXPECT_EQ(F, Triple::normalize(Join(C[2], C[0], C[1], C[3])));
- EXPECT_EQ(F, Triple::normalize(Join(C[2], C[0], C[3], C[1])));
- EXPECT_EQ(F, Triple::normalize(Join(C[2], C[1], C[3], C[0])));
- EXPECT_EQ(F, Triple::normalize(Join(C[2], C[1], C[0], C[3])));
- EXPECT_EQ(F, Triple::normalize(Join(C[3], C[0], C[1], C[2])));
- EXPECT_EQ(F, Triple::normalize(Join(C[3], C[0], C[2], C[1])));
- EXPECT_EQ(F, Triple::normalize(Join(C[3], C[1], C[2], C[0])));
- EXPECT_EQ(F, Triple::normalize(Join(C[3], C[1], C[0], C[2])));
- EXPECT_EQ(F, Triple::normalize(Join(C[3], C[2], C[0], C[1])));
- EXPECT_EQ(F, Triple::normalize(Join(C[3], C[2], C[1], C[0])));
- }
- }
- }
+ std::string E = Join(C[0], C[1], C[2]);
+ int I[] = {0, 1, 2};
+ do {
+ EXPECT_EQ(E, Triple::normalize(Join(C[I[0]], C[I[1]], C[I[2]])));
+ } while (std::next_permutation(std::begin(I), std::end(I)));
+ std::string F = Join(C[0], C[1], C[2], C[3]);
+ int J[] = {0, 1, 2, 3};
+ do {
+ EXPECT_EQ(F, Triple::normalize(Join(C[J[0]], C[J[1]], C[J[2]], C[J[3]])));
+ } while (std::next_permutation(std::begin(J), std::end(J)));
+ }
+ for (int Vendor = FirstVendorType; Vendor <= Triple::LastVendorType;
+ ++Vendor) {
+ StringRef C[] = {InitialC[0], InitialC[1], InitialC[2], InitialC[3]};
+ C[1] = Triple::getVendorTypeName(Triple::VendorType(Vendor));
+ std::string E = Join(C[0], C[1], C[2]);
+ int I[] = {0, 1, 2};
+ do {
+ EXPECT_EQ(E, Triple::normalize(Join(C[I[0]], C[I[1]], C[I[2]])));
+ } while (std::next_permutation(std::begin(I), std::end(I)));
+ std::string F = Join(C[0], C[1], C[2], C[3]);
+ int J[] = {0, 1, 2, 3};
+ do {
+ EXPECT_EQ(F, Triple::normalize(Join(C[J[0]], C[J[1]], C[J[2]], C[J[3]])));
+ } while (std::next_permutation(std::begin(J), std::end(J)));
+ }
+ for (int OS = FirstOSType; OS <= Triple::LastOSType; ++OS) {
+ if (OS == Triple::Win32)
+ continue;
+ StringRef C[] = {InitialC[0], InitialC[1], InitialC[2], InitialC[3]};
+ C[2] = Triple::getOSTypeName(Triple::OSType(OS));
+ std::string E = Join(C[0], C[1], C[2]);
+ int I[] = {0, 1, 2};
+ do {
+ EXPECT_EQ(E, Triple::normalize(Join(C[I[0]], C[I[1]], C[I[2]])));
+ } while (std::next_permutation(std::begin(I), std::end(I)));
+ std::string F = Join(C[0], C[1], C[2], C[3]);
+ int J[] = {0, 1, 2, 3};
+ do {
+ EXPECT_EQ(F, Triple::normalize(Join(C[J[0]], C[J[1]], C[J[2]], C[J[3]])));
+ } while (std::next_permutation(std::begin(J), std::end(J)));
+ }
+ for (int Env = FirstEnvType; Env <= Triple::LastEnvironmentType; ++Env) {
+ StringRef C[] = {InitialC[0], InitialC[1], InitialC[2], InitialC[3]};
+ C[3] = Triple::getEnvironmentTypeName(Triple::EnvironmentType(Env));
+ std::string F = Join(C[0], C[1], C[2], C[3]);
+ int J[] = {0, 1, 2, 3};
+ do {
+ EXPECT_EQ(F, Triple::normalize(Join(C[J[0]], C[J[1]], C[J[2]], C[J[3]])));
+ } while (std::next_permutation(std::begin(J), std::end(J)));
}
// Various real-world funky triples. The value returned by GCC's config.sub
@@ -527,6 +577,16 @@ TEST(TripleTest, BitWidthPredicates) {
EXPECT_FALSE(T.isArch16Bit());
EXPECT_TRUE(T.isArch32Bit());
EXPECT_FALSE(T.isArch64Bit());
+
+ T.setArch(Triple::riscv32);
+ EXPECT_FALSE(T.isArch16Bit());
+ EXPECT_TRUE(T.isArch32Bit());
+ EXPECT_FALSE(T.isArch64Bit());
+
+ T.setArch(Triple::riscv64);
+ EXPECT_FALSE(T.isArch16Bit());
+ EXPECT_FALSE(T.isArch32Bit());
+ EXPECT_TRUE(T.isArch64Bit());
}
TEST(TripleTest, BitWidthArchVariants) {
@@ -617,6 +677,14 @@ TEST(TripleTest, BitWidthArchVariants) {
T.setArch(Triple::wasm64);
EXPECT_EQ(Triple::wasm32, T.get32BitArchVariant().getArch());
EXPECT_EQ(Triple::wasm64, T.get64BitArchVariant().getArch());
+
+ T.setArch(Triple::riscv32);
+ EXPECT_EQ(Triple::riscv32, T.get32BitArchVariant().getArch());
+ EXPECT_EQ(Triple::riscv64, T.get64BitArchVariant().getArch());
+
+ T.setArch(Triple::riscv64);
+ EXPECT_EQ(Triple::riscv32, T.get32BitArchVariant().getArch());
+ EXPECT_EQ(Triple::riscv64, T.get64BitArchVariant().getArch());
}
TEST(TripleTest, EndianArchVariants) {
@@ -874,112 +942,6 @@ TEST(TripleTest, NormalizeWindows) {
}
TEST(TripleTest, getARMCPUForArch) {
- // Standard ARM Architectures.
- {
- llvm::Triple Triple("armv4-unknown-eabi");
- EXPECT_EQ("strongarm", Triple.getARMCPUForArch());
- }
- {
- llvm::Triple Triple("armv4t-unknown-eabi");
- EXPECT_EQ("arm7tdmi", Triple.getARMCPUForArch());
- }
- {
- llvm::Triple Triple("armv5-unknown-eabi");
- EXPECT_EQ("arm10tdmi", Triple.getARMCPUForArch());
- }
- {
- llvm::Triple Triple("armv5t-unknown-eabi");
- EXPECT_EQ("arm10tdmi", Triple.getARMCPUForArch());
- }
- {
- llvm::Triple Triple("armv5e-unknown-eabi");
- EXPECT_EQ("arm1022e", Triple.getARMCPUForArch());
- }
- {
- llvm::Triple Triple("armv5tej-unknown-eabi");
- EXPECT_EQ("arm926ej-s", Triple.getARMCPUForArch());
- }
- {
- llvm::Triple Triple("armv6-unknown-eabi");
- EXPECT_EQ("arm1136jf-s", Triple.getARMCPUForArch());
- }
- {
- llvm::Triple Triple("armv6j-unknown-eabi");
- EXPECT_EQ("arm1136jf-s", Triple.getARMCPUForArch());
- }
- {
- llvm::Triple Triple("armv6k-unknown-eabi");
- EXPECT_EQ("arm1176j-s", Triple.getARMCPUForArch());
- }
- {
- llvm::Triple Triple("armv6kz-unknown-eabi");
- EXPECT_EQ("arm1176jzf-s", Triple.getARMCPUForArch());
- }
- {
- llvm::Triple Triple("armv6zk-unknown-eabi");
- EXPECT_EQ("arm1176jzf-s", Triple.getARMCPUForArch());
- }
- {
- llvm::Triple Triple("armv6t2-unknown-eabi");
- EXPECT_EQ("arm1156t2-s", Triple.getARMCPUForArch());
- }
- {
- llvm::Triple Triple("armv6m-unknown-eabi");
- EXPECT_EQ("cortex-m0", Triple.getARMCPUForArch());
- }
- {
- llvm::Triple Triple("armv7-unknown-eabi");
- EXPECT_EQ("cortex-a8", Triple.getARMCPUForArch());
- }
- {
- llvm::Triple Triple("armv7a-unknown-eabi");
- EXPECT_EQ("cortex-a8", Triple.getARMCPUForArch());
- }
- {
- llvm::Triple Triple("armv7m-unknown-eabi");
- EXPECT_EQ("cortex-m3", Triple.getARMCPUForArch());
- }
- {
- llvm::Triple Triple("armv7r-unknown-eabi");
- EXPECT_EQ("cortex-r4", Triple.getARMCPUForArch());
- }
- {
- llvm::Triple Triple("armv7r-unknown-eabi");
- EXPECT_EQ("cortex-r4", Triple.getARMCPUForArch());
- }
- {
- llvm::Triple Triple("armv7r-unknown-eabi");
- EXPECT_EQ("cortex-r4", Triple.getARMCPUForArch());
- }
- {
- llvm::Triple Triple("armv7r-unknown-eabi");
- EXPECT_EQ("cortex-r4", Triple.getARMCPUForArch());
- }
- {
- llvm::Triple Triple("armv8a-unknown-eabi");
- EXPECT_EQ("cortex-a53", Triple.getARMCPUForArch());
- }
- {
- llvm::Triple Triple("armv8.1a-unknown-eabi");
- EXPECT_EQ("generic", Triple.getARMCPUForArch());
- }
- // Non-synonym names, using -march style, not default arch.
- {
- llvm::Triple Triple("arm");
- EXPECT_EQ("cortex-a8", Triple.getARMCPUForArch("armv7-a"));
- }
- {
- llvm::Triple Triple("arm");
- EXPECT_EQ("cortex-m3", Triple.getARMCPUForArch("armv7-m"));
- }
- {
- llvm::Triple Triple("arm");
- EXPECT_EQ("cortex-a53", Triple.getARMCPUForArch("armv8"));
- }
- {
- llvm::Triple Triple("arm");
- EXPECT_EQ("cortex-a53", Triple.getARMCPUForArch("armv8-a"));
- }
// Platform specific defaults.
{
llvm::Triple Triple("arm--nacl");
@@ -1003,18 +965,6 @@ TEST(TripleTest, getARMCPUForArch) {
}
// Some alternative architectures
{
- llvm::Triple Triple("xscale-unknown-eabi");
- EXPECT_EQ("xscale", Triple.getARMCPUForArch());
- }
- {
- llvm::Triple Triple("iwmmxt-unknown-eabi");
- EXPECT_EQ("iwmmxt", Triple.getARMCPUForArch());
- }
- {
- llvm::Triple Triple("armv7s-apple-ios7");
- EXPECT_EQ("swift", Triple.getARMCPUForArch());
- }
- {
llvm::Triple Triple("armv7k-apple-ios9");
EXPECT_EQ("cortex-a7", Triple.getARMCPUForArch());
}
@@ -1026,18 +976,6 @@ TEST(TripleTest, getARMCPUForArch) {
llvm::Triple Triple("armv7k-apple-tvos9");
EXPECT_EQ("cortex-a7", Triple.getARMCPUForArch());
}
- {
- llvm::Triple Triple("armv7em-apple-ios7");
- EXPECT_EQ("cortex-m4", Triple.getARMCPUForArch());
- }
- {
- llvm::Triple Triple("armv7l-linux-gnueabihf");
- EXPECT_EQ("cortex-a8", Triple.getARMCPUForArch());
- }
- {
- llvm::Triple Triple("armv6sm-apple-ios7");
- EXPECT_EQ("cortex-m0", Triple.getARMCPUForArch());
- }
// armeb is permitted, but armebeb is not
{
llvm::Triple Triple("armeb-none-eabi");
@@ -1051,15 +989,6 @@ TEST(TripleTest, getARMCPUForArch) {
llvm::Triple Triple("armebv6eb-none-eabi");
EXPECT_EQ("", Triple.getARMCPUForArch());
}
- // armebv6 and armv6eb are permitted, but armebv6eb is not
- {
- llvm::Triple Triple("armebv6-non-eabi");
- EXPECT_EQ("arm1136jf-s", Triple.getARMCPUForArch());
- }
- {
- llvm::Triple Triple("armv6eb-none-eabi");
- EXPECT_EQ("arm1136jf-s", Triple.getARMCPUForArch());
- }
// xscaleeb is permitted, but armebxscale is not
{
llvm::Triple Triple("xscaleeb-none-eabi");
@@ -1095,62 +1024,18 @@ TEST(TripleTest, ParseARMArch) {
EXPECT_EQ(Triple::arm, T.getArch());
}
{
- Triple T = Triple("armv6t2");
- EXPECT_EQ(Triple::arm, T.getArch());
- }
- {
- Triple T = Triple("armv8");
- EXPECT_EQ(Triple::arm, T.getArch());
- }
- {
Triple T = Triple("armeb");
EXPECT_EQ(Triple::armeb, T.getArch());
}
- {
- Triple T = Triple("armv5eb");
- EXPECT_EQ(Triple::armeb, T.getArch());
- }
- {
- Triple T = Triple("armebv7m");
- EXPECT_EQ(Triple::armeb, T.getArch());
- }
- {
- Triple T = Triple("armv7eb");
- EXPECT_EQ(Triple::armeb, T.getArch());
- }
// THUMB
{
Triple T = Triple("thumb");
EXPECT_EQ(Triple::thumb, T.getArch());
}
{
- Triple T = Triple("thumbv7a");
- EXPECT_EQ(Triple::thumb, T.getArch());
- }
- {
Triple T = Triple("thumbeb");
EXPECT_EQ(Triple::thumbeb, T.getArch());
}
- {
- Triple T = Triple("thumbv4teb");
- EXPECT_EQ(Triple::thumbeb, T.getArch());
- }
- {
- Triple T = Triple("thumbebv7");
- EXPECT_EQ(Triple::thumbeb, T.getArch());
- }
- {
- Triple T = Triple("armv6m");
- EXPECT_EQ(Triple::thumb, T.getArch());
- }
- {
- Triple T = Triple("thumbv2");
- EXPECT_EQ(Triple::UnknownArch, T.getArch());
- }
- {
- Triple T = Triple("thumbebv6eb");
- EXPECT_EQ(Triple::UnknownArch, T.getArch());
- }
// AARCH64
{
Triple T = Triple("arm64");
@@ -1164,13 +1049,5 @@ TEST(TripleTest, ParseARMArch) {
Triple T = Triple("aarch64_be");
EXPECT_EQ(Triple::aarch64_be, T.getArch());
}
- {
- Triple T = Triple("aarch64be");
- EXPECT_EQ(Triple::UnknownArch, T.getArch());
- }
- {
- Triple T = Triple("arm64be");
- EXPECT_EQ(Triple::UnknownArch, T.getArch());
- }
}
} // end anonymous namespace
diff --git a/unittests/ADT/TwineTest.cpp b/unittests/ADT/TwineTest.cpp
index 9683e97511b6..0b7e88dee500 100644
--- a/unittests/ADT/TwineTest.cpp
+++ b/unittests/ADT/TwineTest.cpp
@@ -7,8 +7,10 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/ADT/Twine.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/FormatAdapters.h"
+#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/raw_ostream.h"
#include "gtest/gtest.h"
using namespace llvm;
@@ -30,6 +32,7 @@ TEST(TwineTest, Construction) {
EXPECT_EQ("hi", Twine(StringRef(std::string("hi"))).str());
EXPECT_EQ("hi", Twine(StringRef("hithere", 2)).str());
EXPECT_EQ("hi", Twine(SmallString<4>("hi")).str());
+ EXPECT_EQ("hi", Twine(formatv("{0}", "hi")).str());
}
TEST(TwineTest, Numbers) {
@@ -65,6 +68,10 @@ TEST(TwineTest, Concat) {
repr(Twine().concat(Twine("hi"))));
EXPECT_EQ("(Twine smallstring:\"hi\" empty)",
repr(Twine().concat(Twine(SmallString<5>("hi")))));
+ EXPECT_EQ("(Twine formatv:\"howdy\" empty)",
+ repr(Twine(formatv("howdy")).concat(Twine())));
+ EXPECT_EQ("(Twine formatv:\"howdy\" empty)",
+ repr(Twine().concat(Twine(formatv("howdy")))));
EXPECT_EQ("(Twine smallstring:\"hey\" cstring:\"there\")",
repr(Twine(SmallString<7>("hey")).concat(Twine("there"))));
@@ -89,6 +96,25 @@ TEST(TwineTest, toNullTerminatedStringRef) {
EXPECT_EQ(0, *Twine(SmallString<11>("hello"))
.toNullTerminatedStringRef(storage)
.end());
+ EXPECT_EQ(0, *Twine(formatv("{0}{1}", "how", "dy"))
+ .toNullTerminatedStringRef(storage)
+ .end());
+}
+
+TEST(TwineTest, LazyEvaluation) {
+ struct formatter : FormatAdapter<int> {
+ explicit formatter(int &Count) : FormatAdapter(0), Count(Count) {}
+ int &Count;
+
+ void format(raw_ostream &OS, StringRef Style) { ++Count; }
+ };
+
+ int Count = 0;
+ formatter Formatter(Count);
+ (void)Twine(formatv("{0}", Formatter));
+ EXPECT_EQ(0, Count);
+ (void)Twine(formatv("{0}", Formatter)).str();
+ EXPECT_EQ(1, Count);
}
// I suppose linking in the entire code generator to add a unit test to check
diff --git a/unittests/ADT/ilistTest.cpp b/unittests/ADT/ilistTest.cpp
deleted file mode 100644
index 377dcc044ddb..000000000000
--- a/unittests/ADT/ilistTest.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-//===- llvm/unittest/ADT/APInt.cpp - APInt unit tests ---------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/ADT/ilist.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/ilist_node.h"
-#include "gtest/gtest.h"
-#include <ostream>
-
-using namespace llvm;
-
-namespace {
-
-struct Node : ilist_node<Node> {
- int Value;
-
- Node() {}
- Node(int Value) : Value(Value) {}
- Node(const Node&) = default;
- ~Node() { Value = -1; }
-};
-
-TEST(ilistTest, Basic) {
- ilist<Node> List;
- List.push_back(Node(1));
- EXPECT_EQ(1, List.back().Value);
- EXPECT_EQ(nullptr, List.getPrevNode(List.back()));
- EXPECT_EQ(nullptr, List.getNextNode(List.back()));
-
- List.push_back(Node(2));
- EXPECT_EQ(2, List.back().Value);
- EXPECT_EQ(2, List.getNextNode(List.front())->Value);
- EXPECT_EQ(1, List.getPrevNode(List.back())->Value);
-
- const ilist<Node> &ConstList = List;
- EXPECT_EQ(2, ConstList.back().Value);
- EXPECT_EQ(2, ConstList.getNextNode(ConstList.front())->Value);
- EXPECT_EQ(1, ConstList.getPrevNode(ConstList.back())->Value);
-}
-
-TEST(ilistTest, SpliceOne) {
- ilist<Node> List;
- List.push_back(1);
-
- // The single-element splice operation supports noops.
- List.splice(List.begin(), List, List.begin());
- EXPECT_EQ(1u, List.size());
- EXPECT_EQ(1, List.front().Value);
- EXPECT_TRUE(std::next(List.begin()) == List.end());
-
- // Altenative noop. Move the first element behind itself.
- List.push_back(2);
- List.push_back(3);
- List.splice(std::next(List.begin()), List, List.begin());
- EXPECT_EQ(3u, List.size());
- EXPECT_EQ(1, List.front().Value);
- EXPECT_EQ(2, std::next(List.begin())->Value);
- EXPECT_EQ(3, List.back().Value);
-}
-
-TEST(ilistTest, UnsafeClear) {
- ilist<Node> List;
-
- // Before even allocating a sentinel.
- List.clearAndLeakNodesUnsafely();
- EXPECT_EQ(0u, List.size());
-
- // Empty list with sentinel.
- ilist<Node>::iterator E = List.end();
- List.clearAndLeakNodesUnsafely();
- EXPECT_EQ(0u, List.size());
- // The sentinel shouldn't change.
- EXPECT_TRUE(E == List.end());
-
- // List with contents.
- List.push_back(1);
- ASSERT_EQ(1u, List.size());
- Node *N = &*List.begin();
- EXPECT_EQ(1, N->Value);
- List.clearAndLeakNodesUnsafely();
- EXPECT_EQ(0u, List.size());
- ASSERT_EQ(1, N->Value);
- delete N;
-
- // List is still functional.
- List.push_back(5);
- List.push_back(6);
- ASSERT_EQ(2u, List.size());
- EXPECT_EQ(5, List.front().Value);
- EXPECT_EQ(6, List.back().Value);
-}
-
-}
diff --git a/unittests/Analysis/BranchProbabilityInfoTest.cpp b/unittests/Analysis/BranchProbabilityInfoTest.cpp
new file mode 100644
index 000000000000..cbf8b50c7623
--- /dev/null
+++ b/unittests/Analysis/BranchProbabilityInfoTest.cpp
@@ -0,0 +1,88 @@
+//===- BranchProbabilityInfoTest.cpp - BranchProbabilityInfo 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/BranchProbabilityInfo.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/AsmParser/Parser.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/Dominators.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/raw_ostream.h"
+#include "gtest/gtest.h"
+
+namespace llvm {
+namespace {
+
+struct BranchProbabilityInfoTest : public testing::Test {
+ std::unique_ptr<BranchProbabilityInfo> BPI;
+ std::unique_ptr<DominatorTree> DT;
+ std::unique_ptr<LoopInfo> LI;
+ LLVMContext C;
+
+ BranchProbabilityInfo &buildBPI(Function &F) {
+ DT.reset(new DominatorTree(F));
+ LI.reset(new LoopInfo(*DT));
+ BPI.reset(new BranchProbabilityInfo(F, *LI));
+ return *BPI;
+ }
+
+ std::unique_ptr<Module> makeLLVMModule() {
+ const char *ModuleString = "define void @f() { exit: ret void }\n";
+ SMDiagnostic Err;
+ return parseAssemblyString(ModuleString, Err, C);
+ }
+};
+
+TEST_F(BranchProbabilityInfoTest, StressUnreachableHeuristic) {
+ auto M = makeLLVMModule();
+ Function *F = M->getFunction("f");
+
+ // define void @f() {
+ // entry:
+ // switch i32 undef, label %exit, [
+ // i32 0, label %preexit
+ // ... ;;< Add lots of cases to stress the heuristic.
+ // ]
+ // preexit:
+ // unreachable
+ // exit:
+ // ret void
+ // }
+
+ auto *ExitBB = &F->back();
+ auto *EntryBB = BasicBlock::Create(C, "entry", F, /*insertBefore=*/ExitBB);
+
+ auto *PreExitBB =
+ BasicBlock::Create(C, "preexit", F, /*insertBefore=*/ExitBB);
+ new UnreachableInst(C, PreExitBB);
+
+ unsigned NumCases = 4096;
+ auto *I32 = IntegerType::get(C, 32);
+ auto *Undef = UndefValue::get(I32);
+ auto *Switch = SwitchInst::Create(Undef, ExitBB, NumCases, EntryBB);
+ for (unsigned I = 0; I < NumCases; ++I)
+ Switch->addCase(ConstantInt::get(I32, I), PreExitBB);
+
+ BranchProbabilityInfo &BPI = buildBPI(*F);
+
+ // FIXME: This doesn't seem optimal. Since all of the cases handled by the
+ // switch have the *same* destination block ("preexit"), shouldn't it be the
+ // hot one? I'd expect the results to be reversed here...
+ EXPECT_FALSE(BPI.isEdgeHot(EntryBB, PreExitBB));
+ EXPECT_TRUE(BPI.isEdgeHot(EntryBB, ExitBB));
+}
+
+} // end anonymous namespace
+} // end namespace llvm
diff --git a/unittests/Analysis/CGSCCPassManagerTest.cpp b/unittests/Analysis/CGSCCPassManagerTest.cpp
index 224f2df13181..ab5d1862c23e 100644
--- a/unittests/Analysis/CGSCCPassManagerTest.cpp
+++ b/unittests/Analysis/CGSCCPassManagerTest.cpp
@@ -22,16 +22,13 @@ using namespace llvm;
namespace {
-class TestModuleAnalysis {
+class TestModuleAnalysis : public AnalysisInfoMixin<TestModuleAnalysis> {
public:
struct Result {
Result(int Count) : FunctionCount(Count) {}
int FunctionCount;
};
- static void *ID() { return (void *)&PassID; }
- static StringRef name() { return "TestModuleAnalysis"; }
-
TestModuleAnalysis(int &Runs) : Runs(Runs) {}
Result run(Module &M, ModuleAnalysisManager &AM) {
@@ -40,48 +37,44 @@ public:
}
private:
- static char PassID;
+ friend AnalysisInfoMixin<TestModuleAnalysis>;
+ static AnalysisKey Key;
int &Runs;
};
-char TestModuleAnalysis::PassID;
+AnalysisKey TestModuleAnalysis::Key;
-class TestSCCAnalysis {
+class TestSCCAnalysis : public AnalysisInfoMixin<TestSCCAnalysis> {
public:
struct Result {
Result(int Count) : FunctionCount(Count) {}
int FunctionCount;
};
- static void *ID() { return (void *)&PassID; }
- static StringRef name() { return "TestSCCAnalysis"; }
-
TestSCCAnalysis(int &Runs) : Runs(Runs) {}
- Result run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM) {
+ Result run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &) {
++Runs;
return Result(C.size());
}
private:
- static char PassID;
+ friend AnalysisInfoMixin<TestSCCAnalysis>;
+ static AnalysisKey Key;
int &Runs;
};
-char TestSCCAnalysis::PassID;
+AnalysisKey TestSCCAnalysis::Key;
-class TestFunctionAnalysis {
+class TestFunctionAnalysis : public AnalysisInfoMixin<TestFunctionAnalysis> {
public:
struct Result {
Result(int Count) : InstructionCount(Count) {}
int InstructionCount;
};
- static void *ID() { return (void *)&PassID; }
- static StringRef name() { return "TestFunctionAnalysis"; }
-
TestFunctionAnalysis(int &Runs) : Runs(Runs) {}
Result run(Function &F, FunctionAnalysisManager &AM) {
@@ -95,22 +88,24 @@ public:
}
private:
- static char PassID;
+ friend AnalysisInfoMixin<TestFunctionAnalysis>;
+ static AnalysisKey Key;
int &Runs;
};
-char TestFunctionAnalysis::PassID;
+AnalysisKey TestFunctionAnalysis::Key;
-class TestImmutableFunctionAnalysis {
+class TestImmutableFunctionAnalysis
+ : public AnalysisInfoMixin<TestImmutableFunctionAnalysis> {
public:
struct Result {
- bool invalidate(Function &, const PreservedAnalyses &) { return false; }
+ bool invalidate(Function &, const PreservedAnalyses &,
+ FunctionAnalysisManager::Invalidator &) {
+ return false;
+ }
};
- static void *ID() { return (void *)&PassID; }
- static StringRef name() { return "TestImmutableFunctionAnalysis"; }
-
TestImmutableFunctionAnalysis(int &Runs) : Runs(Runs) {}
Result run(Function &F, FunctionAnalysisManager &AM) {
@@ -119,93 +114,47 @@ public:
}
private:
- static char PassID;
+ friend AnalysisInfoMixin<TestImmutableFunctionAnalysis>;
+ static AnalysisKey Key;
int &Runs;
};
-char TestImmutableFunctionAnalysis::PassID;
+AnalysisKey TestImmutableFunctionAnalysis::Key;
-struct TestModulePass {
- TestModulePass(int &RunCount) : RunCount(RunCount) {}
+struct LambdaModulePass : public PassInfoMixin<LambdaModulePass> {
+ template <typename T>
+ LambdaModulePass(T &&Arg) : Func(std::forward<T>(Arg)) {}
- PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM) {
- ++RunCount;
- (void)AM.getResult<TestModuleAnalysis>(M);
- return PreservedAnalyses::all();
+ PreservedAnalyses run(Module &F, ModuleAnalysisManager &AM) {
+ return Func(F, AM);
}
- static StringRef name() { return "TestModulePass"; }
-
- int &RunCount;
+ std::function<PreservedAnalyses(Module &, ModuleAnalysisManager &)> Func;
};
-struct TestSCCPass {
- TestSCCPass(int &RunCount, int &AnalyzedInstrCount,
- int &AnalyzedSCCFunctionCount, int &AnalyzedModuleFunctionCount,
- bool OnlyUseCachedResults = false)
- : RunCount(RunCount), AnalyzedInstrCount(AnalyzedInstrCount),
- AnalyzedSCCFunctionCount(AnalyzedSCCFunctionCount),
- AnalyzedModuleFunctionCount(AnalyzedModuleFunctionCount),
- OnlyUseCachedResults(OnlyUseCachedResults) {}
-
- PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM) {
- ++RunCount;
-
- const ModuleAnalysisManager &MAM =
- AM.getResult<ModuleAnalysisManagerCGSCCProxy>(C).getManager();
- FunctionAnalysisManager &FAM =
- AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C).getManager();
- if (TestModuleAnalysis::Result *TMA =
- MAM.getCachedResult<TestModuleAnalysis>(
- *C.begin()->getFunction().getParent()))
- AnalyzedModuleFunctionCount += TMA->FunctionCount;
-
- if (OnlyUseCachedResults) {
- // Hack to force the use of the cached interface.
- if (TestSCCAnalysis::Result *AR = AM.getCachedResult<TestSCCAnalysis>(C))
- AnalyzedSCCFunctionCount += AR->FunctionCount;
- for (LazyCallGraph::Node &N : C)
- if (TestFunctionAnalysis::Result *FAR =
- FAM.getCachedResult<TestFunctionAnalysis>(N.getFunction()))
- AnalyzedInstrCount += FAR->InstructionCount;
- } else {
- // Typical path just runs the analysis as needed.
- TestSCCAnalysis::Result &AR = AM.getResult<TestSCCAnalysis>(C);
- AnalyzedSCCFunctionCount += AR.FunctionCount;
- for (LazyCallGraph::Node &N : C) {
- TestFunctionAnalysis::Result &FAR =
- FAM.getResult<TestFunctionAnalysis>(N.getFunction());
- AnalyzedInstrCount += FAR.InstructionCount;
-
- // Just ensure we get the immutable results.
- (void)FAM.getResult<TestImmutableFunctionAnalysis>(N.getFunction());
- }
- }
+struct LambdaSCCPass : public PassInfoMixin<LambdaSCCPass> {
+ template <typename T> LambdaSCCPass(T &&Arg) : Func(std::forward<T>(Arg)) {}
- return PreservedAnalyses::all();
+ PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
+ LazyCallGraph &CG, CGSCCUpdateResult &UR) {
+ return Func(C, AM, CG, UR);
}
- static StringRef name() { return "TestSCCPass"; }
-
- int &RunCount;
- int &AnalyzedInstrCount;
- int &AnalyzedSCCFunctionCount;
- int &AnalyzedModuleFunctionCount;
- bool OnlyUseCachedResults;
+ std::function<PreservedAnalyses(LazyCallGraph::SCC &, CGSCCAnalysisManager &,
+ LazyCallGraph &, CGSCCUpdateResult &)>
+ Func;
};
-struct TestFunctionPass {
- TestFunctionPass(int &RunCount) : RunCount(RunCount) {}
+struct LambdaFunctionPass : public PassInfoMixin<LambdaFunctionPass> {
+ template <typename T>
+ LambdaFunctionPass(T &&Arg) : Func(std::forward<T>(Arg)) {}
- PreservedAnalyses run(Function &F, AnalysisManager<Function> &) {
- ++RunCount;
- return PreservedAnalyses::none();
+ PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) {
+ return Func(F, AM);
}
- static StringRef name() { return "TestFunctionPass"; }
-
- int &RunCount;
+ std::function<PreservedAnalyses(Function &, FunctionAnalysisManager &)> Func;
};
std::unique_ptr<Module> parseIR(const char *IR) {
@@ -217,40 +166,78 @@ std::unique_ptr<Module> parseIR(const char *IR) {
return parseAssemblyString(IR, Err, C);
}
-TEST(CGSCCPassManagerTest, Basic) {
- auto M = parseIR("define void @f() {\n"
- "entry:\n"
- " call void @g()\n"
- " call void @h1()\n"
- " ret void\n"
- "}\n"
- "define void @g() {\n"
- "entry:\n"
- " call void @g()\n"
- " call void @x()\n"
- " ret void\n"
- "}\n"
- "define void @h1() {\n"
- "entry:\n"
- " call void @h2()\n"
- " ret void\n"
- "}\n"
- "define void @h2() {\n"
- "entry:\n"
- " call void @h3()\n"
- " call void @x()\n"
- " ret void\n"
- "}\n"
- "define void @h3() {\n"
- "entry:\n"
- " call void @h1()\n"
- " ret void\n"
- "}\n"
- "define void @x() {\n"
- "entry:\n"
- " ret void\n"
- "}\n");
- FunctionAnalysisManager FAM(/*DebugLogging*/ true);
+class CGSCCPassManagerTest : public ::testing::Test {
+protected:
+ LLVMContext Context;
+ FunctionAnalysisManager FAM;
+ CGSCCAnalysisManager CGAM;
+ ModuleAnalysisManager MAM;
+
+ std::unique_ptr<Module> M;
+
+public:
+ CGSCCPassManagerTest()
+ : FAM(/*DebugLogging*/ true), CGAM(/*DebugLogging*/ true),
+ MAM(/*DebugLogging*/ true),
+ M(parseIR(
+ // Define a module with the following call graph, where calls go
+ // out the bottom of nodes and enter the top:
+ //
+ // f
+ // |\ _
+ // | \ / |
+ // g h1 |
+ // | | |
+ // | h2 |
+ // | | |
+ // | h3 |
+ // | / \_/
+ // |/
+ // x
+ //
+ "define void @f() {\n"
+ "entry:\n"
+ " call void @g()\n"
+ " call void @h1()\n"
+ " ret void\n"
+ "}\n"
+ "define void @g() {\n"
+ "entry:\n"
+ " call void @g()\n"
+ " call void @x()\n"
+ " ret void\n"
+ "}\n"
+ "define void @h1() {\n"
+ "entry:\n"
+ " call void @h2()\n"
+ " ret void\n"
+ "}\n"
+ "define void @h2() {\n"
+ "entry:\n"
+ " call void @h3()\n"
+ " call void @x()\n"
+ " ret void\n"
+ "}\n"
+ "define void @h3() {\n"
+ "entry:\n"
+ " call void @h1()\n"
+ " ret void\n"
+ "}\n"
+ "define void @x() {\n"
+ "entry:\n"
+ " ret void\n"
+ "}\n")) {
+ MAM.registerPass([&] { return LazyCallGraphAnalysis(); });
+ MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });
+ MAM.registerPass([&] { return CGSCCAnalysisManagerModuleProxy(CGAM); });
+ CGAM.registerPass([&] { return FunctionAnalysisManagerCGSCCProxy(); });
+ CGAM.registerPass([&] { return ModuleAnalysisManagerCGSCCProxy(MAM); });
+ FAM.registerPass([&] { return CGSCCAnalysisManagerFunctionProxy(CGAM); });
+ FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); });
+ }
+};
+
+TEST_F(CGSCCPassManagerTest, Basic) {
int FunctionAnalysisRuns = 0;
FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); });
int ImmutableFunctionAnalysisRuns = 0;
@@ -258,54 +245,842 @@ TEST(CGSCCPassManagerTest, Basic) {
return TestImmutableFunctionAnalysis(ImmutableFunctionAnalysisRuns);
});
- CGSCCAnalysisManager CGAM(/*DebugLogging*/ true);
int SCCAnalysisRuns = 0;
CGAM.registerPass([&] { return TestSCCAnalysis(SCCAnalysisRuns); });
- ModuleAnalysisManager MAM(/*DebugLogging*/ true);
int ModuleAnalysisRuns = 0;
- MAM.registerPass([&] { return LazyCallGraphAnalysis(); });
MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns); });
- MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });
- MAM.registerPass([&] { return CGSCCAnalysisManagerModuleProxy(CGAM); });
- CGAM.registerPass([&] { return FunctionAnalysisManagerCGSCCProxy(FAM); });
- CGAM.registerPass([&] { return ModuleAnalysisManagerCGSCCProxy(MAM); });
- FAM.registerPass([&] { return CGSCCAnalysisManagerFunctionProxy(CGAM); });
- FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); });
-
ModulePassManager MPM(/*DebugLogging*/ true);
- int ModulePassRunCount1 = 0;
- MPM.addPass(TestModulePass(ModulePassRunCount1));
+ MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>());
CGSCCPassManager CGPM1(/*DebugLogging*/ true);
+ FunctionPassManager FPM1(/*DebugLogging*/ true);
+ int FunctionPassRunCount1 = 0;
+ FPM1.addPass(LambdaFunctionPass([&](Function &, FunctionAnalysisManager &) {
+ ++FunctionPassRunCount1;
+ return PreservedAnalyses::none();
+ }));
+ CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1)));
+
int SCCPassRunCount1 = 0;
int AnalyzedInstrCount1 = 0;
int AnalyzedSCCFunctionCount1 = 0;
int AnalyzedModuleFunctionCount1 = 0;
- CGPM1.addPass(TestSCCPass(SCCPassRunCount1, AnalyzedInstrCount1,
- AnalyzedSCCFunctionCount1,
- AnalyzedModuleFunctionCount1));
+ CGPM1.addPass(
+ LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
+ LazyCallGraph &CG, CGSCCUpdateResult &UR) {
+ ++SCCPassRunCount1;
+
+ const ModuleAnalysisManager &MAM =
+ AM.getResult<ModuleAnalysisManagerCGSCCProxy>(C, CG).getManager();
+ FunctionAnalysisManager &FAM =
+ AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager();
+ if (TestModuleAnalysis::Result *TMA =
+ MAM.getCachedResult<TestModuleAnalysis>(
+ *C.begin()->getFunction().getParent()))
+ AnalyzedModuleFunctionCount1 += TMA->FunctionCount;
+
+ TestSCCAnalysis::Result &AR = AM.getResult<TestSCCAnalysis>(C, CG);
+ AnalyzedSCCFunctionCount1 += AR.FunctionCount;
+ for (LazyCallGraph::Node &N : C) {
+ TestFunctionAnalysis::Result &FAR =
+ FAM.getResult<TestFunctionAnalysis>(N.getFunction());
+ AnalyzedInstrCount1 += FAR.InstructionCount;
+
+ // Just ensure we get the immutable results.
+ (void)FAM.getResult<TestImmutableFunctionAnalysis>(N.getFunction());
+ }
+
+ return PreservedAnalyses::all();
+ }));
+
+ FunctionPassManager FPM2(/*DebugLogging*/ true);
+ int FunctionPassRunCount2 = 0;
+ FPM2.addPass(LambdaFunctionPass([&](Function &, FunctionAnalysisManager &) {
+ ++FunctionPassRunCount2;
+ return PreservedAnalyses::none();
+ }));
+ CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM2)));
- FunctionPassManager FPM1(/*DebugLogging*/ true);
- int FunctionPassRunCount1 = 0;
- FPM1.addPass(TestFunctionPass(FunctionPassRunCount1));
- CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1)));
MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1)));
+ FunctionPassManager FPM3(/*DebugLogging*/ true);
+ int FunctionPassRunCount3 = 0;
+ FPM3.addPass(LambdaFunctionPass([&](Function &, FunctionAnalysisManager &) {
+ ++FunctionPassRunCount3;
+ return PreservedAnalyses::none();
+ }));
+ MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM3)));
+
MPM.run(*M, MAM);
- EXPECT_EQ(1, ModulePassRunCount1);
+ EXPECT_EQ(4, SCCPassRunCount1);
+ EXPECT_EQ(6, FunctionPassRunCount1);
+ EXPECT_EQ(6, FunctionPassRunCount2);
+ EXPECT_EQ(6, FunctionPassRunCount3);
EXPECT_EQ(1, ModuleAnalysisRuns);
EXPECT_EQ(4, SCCAnalysisRuns);
EXPECT_EQ(6, FunctionAnalysisRuns);
EXPECT_EQ(6, ImmutableFunctionAnalysisRuns);
- EXPECT_EQ(4, SCCPassRunCount1);
EXPECT_EQ(14, AnalyzedInstrCount1);
EXPECT_EQ(6, AnalyzedSCCFunctionCount1);
EXPECT_EQ(4 * 6, AnalyzedModuleFunctionCount1);
}
+// Test that an SCC pass which fails to preserve a module analysis does in fact
+// invalidate that module analysis.
+TEST_F(CGSCCPassManagerTest, TestSCCPassInvalidatesModuleAnalysis) {
+ int ModuleAnalysisRuns = 0;
+ MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns); });
+
+ ModulePassManager MPM(/*DebugLogging*/ true);
+ MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>());
+
+ // The first CGSCC run we preserve everything and make sure that works and
+ // the module analysis is available in the second CGSCC run from the one
+ // required module pass above.
+ CGSCCPassManager CGPM1(/*DebugLogging*/ true);
+ int CountFoundModuleAnalysis1 = 0;
+ CGPM1.addPass(
+ LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
+ LazyCallGraph &CG, CGSCCUpdateResult &UR) {
+ const auto &MAM =
+ AM.getResult<ModuleAnalysisManagerCGSCCProxy>(C, CG).getManager();
+ auto *TMA = MAM.getCachedResult<TestModuleAnalysis>(
+ *C.begin()->getFunction().getParent());
+
+ if (TMA)
+ ++CountFoundModuleAnalysis1;
+
+ return PreservedAnalyses::all();
+ }));
+ MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1)));
+
+ // The second CGSCC run checks that the module analysis got preserved the
+ // previous time and in one SCC fails to preserve it.
+ CGSCCPassManager CGPM2(/*DebugLogging*/ true);
+ int CountFoundModuleAnalysis2 = 0;
+ CGPM2.addPass(
+ LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
+ LazyCallGraph &CG, CGSCCUpdateResult &UR) {
+ const auto &MAM =
+ AM.getResult<ModuleAnalysisManagerCGSCCProxy>(C, CG).getManager();
+ auto *TMA = MAM.getCachedResult<TestModuleAnalysis>(
+ *C.begin()->getFunction().getParent());
+
+ if (TMA)
+ ++CountFoundModuleAnalysis2;
+
+ // Only fail to preserve analyses on one SCC and make sure that gets
+ // propagated.
+ return C.getName() == "(g)" ? PreservedAnalyses::none()
+ : PreservedAnalyses::all();
+ }));
+ MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2)));
+
+ // The third CGSCC run should fail to find a cached module analysis as it
+ // should have been invalidated by the above CGSCC run.
+ CGSCCPassManager CGPM3(/*DebugLogging*/ true);
+ int CountFoundModuleAnalysis3 = 0;
+ CGPM3.addPass(
+ LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
+ LazyCallGraph &CG, CGSCCUpdateResult &UR) {
+ const auto &MAM =
+ AM.getResult<ModuleAnalysisManagerCGSCCProxy>(C, CG).getManager();
+ auto *TMA = MAM.getCachedResult<TestModuleAnalysis>(
+ *C.begin()->getFunction().getParent());
+
+ if (TMA)
+ ++CountFoundModuleAnalysis3;
+
+ return PreservedAnalyses::none();
+ }));
+ MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM3)));
+
+ MPM.run(*M, MAM);
+
+ EXPECT_EQ(1, ModuleAnalysisRuns);
+ EXPECT_EQ(4, CountFoundModuleAnalysis1);
+ EXPECT_EQ(4, CountFoundModuleAnalysis2);
+ EXPECT_EQ(0, CountFoundModuleAnalysis3);
+}
+
+// Similar to the above, but test that this works for function passes embedded
+// *within* a CGSCC layer.
+TEST_F(CGSCCPassManagerTest, TestFunctionPassInsideCGSCCInvalidatesModuleAnalysis) {
+ int ModuleAnalysisRuns = 0;
+ MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns); });
+
+ ModulePassManager MPM(/*DebugLogging*/ true);
+ MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>());
+
+ // The first run we preserve everything and make sure that works and the
+ // module analysis is available in the second run from the one required
+ // module pass above.
+ FunctionPassManager FPM1(/*DebugLogging*/ true);
+ // Start true and mark false if we ever failed to find a module analysis
+ // because we expect this to succeed for each SCC.
+ bool FoundModuleAnalysis1 = true;
+ FPM1.addPass(
+ LambdaFunctionPass([&](Function &F, FunctionAnalysisManager &AM) {
+ const auto &MAM =
+ AM.getResult<ModuleAnalysisManagerFunctionProxy>(F).getManager();
+ auto *TMA = MAM.getCachedResult<TestModuleAnalysis>(*F.getParent());
+
+ if (!TMA)
+ FoundModuleAnalysis1 = false;
+
+ return PreservedAnalyses::all();
+ }));
+ CGSCCPassManager CGPM1(/*DebugLogging*/ true);
+ CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1)));
+ MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1)));
+
+ // The second run checks that the module analysis got preserved the previous
+ // time and in one function fails to preserve it.
+ FunctionPassManager FPM2(/*DebugLogging*/ true);
+ // Again, start true and mark false if we ever failed to find a module analysis
+ // because we expect this to succeed for each SCC.
+ bool FoundModuleAnalysis2 = true;
+ FPM2.addPass(
+ LambdaFunctionPass([&](Function &F, FunctionAnalysisManager &AM) {
+ const auto &MAM =
+ AM.getResult<ModuleAnalysisManagerFunctionProxy>(F).getManager();
+ auto *TMA = MAM.getCachedResult<TestModuleAnalysis>(*F.getParent());
+
+ if (!TMA)
+ FoundModuleAnalysis2 = false;
+
+ // Only fail to preserve analyses on one SCC and make sure that gets
+ // propagated.
+ return F.getName() == "h2" ? PreservedAnalyses::none()
+ : PreservedAnalyses::all();
+ }));
+ CGSCCPassManager CGPM2(/*DebugLogging*/ true);
+ CGPM2.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM2)));
+ MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2)));
+
+ // The third run should fail to find a cached module analysis as it should
+ // have been invalidated by the above run.
+ FunctionPassManager FPM3(/*DebugLogging*/ true);
+ // Start false and mark true if we ever *succeeded* to find a module
+ // analysis, as we expect this to fail for every function.
+ bool FoundModuleAnalysis3 = false;
+ FPM3.addPass(
+ LambdaFunctionPass([&](Function &F, FunctionAnalysisManager &AM) {
+ const auto &MAM =
+ AM.getResult<ModuleAnalysisManagerFunctionProxy>(F).getManager();
+ auto *TMA = MAM.getCachedResult<TestModuleAnalysis>(*F.getParent());
+
+ if (TMA)
+ FoundModuleAnalysis3 = true;
+
+ return PreservedAnalyses::none();
+ }));
+ CGSCCPassManager CGPM3(/*DebugLogging*/ true);
+ CGPM3.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM3)));
+ MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM3)));
+
+ MPM.run(*M, MAM);
+
+ EXPECT_EQ(1, ModuleAnalysisRuns);
+ EXPECT_TRUE(FoundModuleAnalysis1);
+ EXPECT_TRUE(FoundModuleAnalysis2);
+ EXPECT_FALSE(FoundModuleAnalysis3);
+}
+
+// Test that a Module pass which fails to preserve an SCC analysis in fact
+// invalidates that analysis.
+TEST_F(CGSCCPassManagerTest, TestModulePassInvalidatesSCCAnalysis) {
+ int SCCAnalysisRuns = 0;
+ CGAM.registerPass([&] { return TestSCCAnalysis(SCCAnalysisRuns); });
+
+ ModulePassManager MPM(/*DebugLogging*/ true);
+
+ // First force the analysis to be run.
+ CGSCCPassManager CGPM1(/*DebugLogging*/ true);
+ CGPM1.addPass(RequireAnalysisPass<TestSCCAnalysis, LazyCallGraph::SCC,
+ CGSCCAnalysisManager, LazyCallGraph &,
+ CGSCCUpdateResult &>());
+ MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1)));
+
+ // Now run a module pass that preserves the LazyCallGraph and the proxy but
+ // not the SCC analysis.
+ MPM.addPass(LambdaModulePass([&](Module &M, ModuleAnalysisManager &) {
+ PreservedAnalyses PA;
+ PA.preserve<LazyCallGraphAnalysis>();
+ PA.preserve<CGSCCAnalysisManagerModuleProxy>();
+ PA.preserve<FunctionAnalysisManagerModuleProxy>();
+ return PA;
+ }));
+
+ // And now a second CGSCC run which requires the SCC analysis again. This
+ // will trigger re-running it.
+ CGSCCPassManager CGPM2(/*DebugLogging*/ true);
+ CGPM2.addPass(RequireAnalysisPass<TestSCCAnalysis, LazyCallGraph::SCC,
+ CGSCCAnalysisManager, LazyCallGraph &,
+ CGSCCUpdateResult &>());
+ MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2)));
+
+ MPM.run(*M, MAM);
+ // Two runs and four SCCs.
+ EXPECT_EQ(2 * 4, SCCAnalysisRuns);
+}
+
+// Check that marking the SCC analysis preserved is sufficient to avoid
+// invaliadtion. This should only run the analysis once for each SCC.
+TEST_F(CGSCCPassManagerTest, TestModulePassCanPreserveSCCAnalysis) {
+ int SCCAnalysisRuns = 0;
+ CGAM.registerPass([&] { return TestSCCAnalysis(SCCAnalysisRuns); });
+
+ ModulePassManager MPM(/*DebugLogging*/ true);
+
+ // First force the analysis to be run.
+ CGSCCPassManager CGPM1(/*DebugLogging*/ true);
+ CGPM1.addPass(RequireAnalysisPass<TestSCCAnalysis, LazyCallGraph::SCC,
+ CGSCCAnalysisManager, LazyCallGraph &,
+ CGSCCUpdateResult &>());
+ MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1)));
+
+ // Now run a module pass that preserves each of the necessary components
+ // (but not everything).
+ MPM.addPass(LambdaModulePass([&](Module &M, ModuleAnalysisManager &) {
+ PreservedAnalyses PA;
+ PA.preserve<LazyCallGraphAnalysis>();
+ PA.preserve<CGSCCAnalysisManagerModuleProxy>();
+ PA.preserve<FunctionAnalysisManagerModuleProxy>();
+ PA.preserve<TestSCCAnalysis>();
+ return PA;
+ }));
+
+ // And now a second CGSCC run which requires the SCC analysis again but find
+ // it in the cache.
+ CGSCCPassManager CGPM2(/*DebugLogging*/ true);
+ CGPM2.addPass(RequireAnalysisPass<TestSCCAnalysis, LazyCallGraph::SCC,
+ CGSCCAnalysisManager, LazyCallGraph &,
+ CGSCCUpdateResult &>());
+ MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2)));
+
+ MPM.run(*M, MAM);
+ // Four SCCs
+ EXPECT_EQ(4, SCCAnalysisRuns);
+}
+
+// Check that even when the analysis is preserved, if the SCC information isn't
+// we still nuke things because the SCC keys could change.
+TEST_F(CGSCCPassManagerTest, TestModulePassInvalidatesSCCAnalysisOnCGChange) {
+ int SCCAnalysisRuns = 0;
+ CGAM.registerPass([&] { return TestSCCAnalysis(SCCAnalysisRuns); });
+
+ ModulePassManager MPM(/*DebugLogging*/ true);
+
+ // First force the analysis to be run.
+ CGSCCPassManager CGPM1(/*DebugLogging*/ true);
+ CGPM1.addPass(RequireAnalysisPass<TestSCCAnalysis, LazyCallGraph::SCC,
+ CGSCCAnalysisManager, LazyCallGraph &,
+ CGSCCUpdateResult &>());
+ MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1)));
+
+ // Now run a module pass that preserves the analysis but not the call
+ // graph or proxy.
+ MPM.addPass(LambdaModulePass([&](Module &M, ModuleAnalysisManager &) {
+ PreservedAnalyses PA;
+ PA.preserve<TestSCCAnalysis>();
+ return PA;
+ }));
+
+ // And now a second CGSCC run which requires the SCC analysis again.
+ CGSCCPassManager CGPM2(/*DebugLogging*/ true);
+ CGPM2.addPass(RequireAnalysisPass<TestSCCAnalysis, LazyCallGraph::SCC,
+ CGSCCAnalysisManager, LazyCallGraph &,
+ CGSCCUpdateResult &>());
+ MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2)));
+
+ MPM.run(*M, MAM);
+ // Two runs and four SCCs.
+ EXPECT_EQ(2 * 4, SCCAnalysisRuns);
+}
+
+// Test that an SCC pass which fails to preserve a Function analysis in fact
+// invalidates that analysis.
+TEST_F(CGSCCPassManagerTest, TestSCCPassInvalidatesFunctionAnalysis) {
+ int FunctionAnalysisRuns = 0;
+ FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); });
+
+ // Create a very simple module with a single function and SCC to make testing
+ // these issues much easier.
+ std::unique_ptr<Module> M = parseIR("declare void @g()\n"
+ "declare void @h()\n"
+ "define void @f() {\n"
+ "entry:\n"
+ " call void @g()\n"
+ " call void @h()\n"
+ " ret void\n"
+ "}\n");
+
+ CGSCCPassManager CGPM(/*DebugLogging*/ true);
+
+ // First force the analysis to be run.
+ FunctionPassManager FPM1(/*DebugLogging*/ true);
+ FPM1.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>());
+ CGPM.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1)));
+
+ // Now run a module pass that preserves the LazyCallGraph and proxy but not
+ // the SCC analysis.
+ CGPM.addPass(LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &,
+ LazyCallGraph &, CGSCCUpdateResult &) {
+ PreservedAnalyses PA;
+ PA.preserve<LazyCallGraphAnalysis>();
+ return PA;
+ }));
+
+ // And now a second CGSCC run which requires the SCC analysis again. This
+ // will trigger re-running it.
+ FunctionPassManager FPM2(/*DebugLogging*/ true);
+ FPM2.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>());
+ CGPM.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM2)));
+
+ ModulePassManager MPM(/*DebugLogging*/ true);
+ MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM)));
+ MPM.run(*M, MAM);
+ EXPECT_EQ(2, FunctionAnalysisRuns);
+}
+
+// Check that marking the SCC analysis preserved is sufficient. This should
+// only run the analysis once the SCC.
+TEST_F(CGSCCPassManagerTest, TestSCCPassCanPreserveFunctionAnalysis) {
+ int FunctionAnalysisRuns = 0;
+ FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); });
+
+ // Create a very simple module with a single function and SCC to make testing
+ // these issues much easier.
+ std::unique_ptr<Module> M = parseIR("declare void @g()\n"
+ "declare void @h()\n"
+ "define void @f() {\n"
+ "entry:\n"
+ " call void @g()\n"
+ " call void @h()\n"
+ " ret void\n"
+ "}\n");
+
+ CGSCCPassManager CGPM(/*DebugLogging*/ true);
+
+ // First force the analysis to be run.
+ FunctionPassManager FPM1(/*DebugLogging*/ true);
+ FPM1.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>());
+ CGPM.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1)));
+
+ // Now run a module pass that preserves each of the necessary components
+ // (but
+ // not everything).
+ CGPM.addPass(LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &,
+ LazyCallGraph &, CGSCCUpdateResult &) {
+ PreservedAnalyses PA;
+ PA.preserve<LazyCallGraphAnalysis>();
+ PA.preserve<TestFunctionAnalysis>();
+ return PA;
+ }));
+
+ // And now a second CGSCC run which requires the SCC analysis again but find
+ // it in the cache.
+ FunctionPassManager FPM2(/*DebugLogging*/ true);
+ FPM2.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>());
+ CGPM.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM2)));
+
+ ModulePassManager MPM(/*DebugLogging*/ true);
+ MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM)));
+ MPM.run(*M, MAM);
+ EXPECT_EQ(1, FunctionAnalysisRuns);
+}
+
+// Note that there is no test for invalidating the call graph or other
+// structure with an SCC pass because there is no mechanism to do that from
+// withinsuch a pass. Instead, such a pass has to directly update the call
+// graph structure.
+
+// Test that a madule pass invalidates function analyses when the CGSCC proxies
+// and pass manager.
+TEST_F(CGSCCPassManagerTest,
+ TestModulePassInvalidatesFunctionAnalysisNestedInCGSCC) {
+ MAM.registerPass([&] { return LazyCallGraphAnalysis(); });
+
+ int FunctionAnalysisRuns = 0;
+ FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); });
+
+ ModulePassManager MPM(/*DebugLogging*/ true);
+
+ // First force the analysis to be run.
+ FunctionPassManager FPM1(/*DebugLogging*/ true);
+ FPM1.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>());
+ CGSCCPassManager CGPM1(/*DebugLogging*/ true);
+ CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1)));
+ MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1)));
+
+ // Now run a module pass that preserves the LazyCallGraph and proxy but not
+ // the Function analysis.
+ MPM.addPass(LambdaModulePass([&](Module &M, ModuleAnalysisManager &) {
+ PreservedAnalyses PA;
+ PA.preserve<LazyCallGraphAnalysis>();
+ PA.preserve<CGSCCAnalysisManagerModuleProxy>();
+ return PA;
+ }));
+
+ // And now a second CGSCC run which requires the SCC analysis again. This
+ // will trigger re-running it.
+ FunctionPassManager FPM2(/*DebugLogging*/ true);
+ FPM2.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>());
+ CGSCCPassManager CGPM2(/*DebugLogging*/ true);
+ CGPM2.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM2)));
+ MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2)));
+
+ MPM.run(*M, MAM);
+ // Two runs and 6 functions.
+ EXPECT_EQ(2 * 6, FunctionAnalysisRuns);
+}
+
+// Check that by marking the function pass and FAM proxy as preserved, this
+// propagates all the way through.
+TEST_F(CGSCCPassManagerTest,
+ TestModulePassCanPreserveFunctionAnalysisNestedInCGSCC) {
+ MAM.registerPass([&] { return LazyCallGraphAnalysis(); });
+
+ int FunctionAnalysisRuns = 0;
+ FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); });
+
+ ModulePassManager MPM(/*DebugLogging*/ true);
+
+ // First force the analysis to be run.
+ FunctionPassManager FPM1(/*DebugLogging*/ true);
+ FPM1.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>());
+ CGSCCPassManager CGPM1(/*DebugLogging*/ true);
+ CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1)));
+ MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1)));
+
+ // Now run a module pass that preserves the LazyCallGraph, the proxy, and
+ // the Function analysis.
+ MPM.addPass(LambdaModulePass([&](Module &M, ModuleAnalysisManager &) {
+ PreservedAnalyses PA;
+ PA.preserve<LazyCallGraphAnalysis>();
+ PA.preserve<CGSCCAnalysisManagerModuleProxy>();
+ PA.preserve<FunctionAnalysisManagerModuleProxy>();
+ PA.preserve<TestFunctionAnalysis>();
+ return PA;
+ }));
+
+ // And now a second CGSCC run which requires the SCC analysis again. This
+ // will trigger re-running it.
+ FunctionPassManager FPM2(/*DebugLogging*/ true);
+ FPM2.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>());
+ CGSCCPassManager CGPM2(/*DebugLogging*/ true);
+ CGPM2.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM2)));
+ MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2)));
+
+ MPM.run(*M, MAM);
+ // One run and 6 functions.
+ EXPECT_EQ(6, FunctionAnalysisRuns);
+}
+
+// Check that if the lazy call graph itself isn't preserved we still manage to
+// invalidate everything.
+TEST_F(CGSCCPassManagerTest,
+ TestModulePassInvalidatesFunctionAnalysisNestedInCGSCCOnCGChange) {
+ MAM.registerPass([&] { return LazyCallGraphAnalysis(); });
+
+ int FunctionAnalysisRuns = 0;
+ FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); });
+
+ ModulePassManager MPM(/*DebugLogging*/ true);
+
+ // First force the analysis to be run.
+ FunctionPassManager FPM1(/*DebugLogging*/ true);
+ FPM1.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>());
+ CGSCCPassManager CGPM1(/*DebugLogging*/ true);
+ CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1)));
+ MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1)));
+
+ // Now run a module pass that preserves the LazyCallGraph but not the
+ // Function analysis.
+ MPM.addPass(LambdaModulePass([&](Module &M, ModuleAnalysisManager &) {
+ PreservedAnalyses PA;
+ return PA;
+ }));
+
+ // And now a second CGSCC run which requires the SCC analysis again. This
+ // will trigger re-running it.
+ FunctionPassManager FPM2(/*DebugLogging*/ true);
+ FPM2.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>());
+ CGSCCPassManager CGPM2(/*DebugLogging*/ true);
+ CGPM2.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM2)));
+ MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2)));
+
+ MPM.run(*M, MAM);
+ // Two runs and 6 functions.
+ EXPECT_EQ(2 * 6, FunctionAnalysisRuns);
+}
+
+/// A test CGSCC-level analysis pass which caches in its result another
+/// analysis pass and uses it to serve queries. This requires the result to
+/// invalidate itself when its dependency is invalidated.
+///
+/// FIXME: Currently this doesn't also depend on a function analysis, and if it
+/// did we would fail to invalidate it correctly.
+struct TestIndirectSCCAnalysis
+ : public AnalysisInfoMixin<TestIndirectSCCAnalysis> {
+ struct Result {
+ Result(TestSCCAnalysis::Result &SCCDep, TestModuleAnalysis::Result &MDep)
+ : SCCDep(SCCDep), MDep(MDep) {}
+ TestSCCAnalysis::Result &SCCDep;
+ TestModuleAnalysis::Result &MDep;
+
+ bool invalidate(LazyCallGraph::SCC &C, const PreservedAnalyses &PA,
+ CGSCCAnalysisManager::Invalidator &Inv) {
+ auto PAC = PA.getChecker<TestIndirectSCCAnalysis>();
+ return !(PAC.preserved() ||
+ PAC.preservedSet<AllAnalysesOn<LazyCallGraph::SCC>>()) ||
+ Inv.invalidate<TestSCCAnalysis>(C, PA);
+ }
+ };
+
+ TestIndirectSCCAnalysis(int &Runs) : Runs(Runs) {}
+
+ /// Run the analysis pass over the function and return a result.
+ Result run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
+ LazyCallGraph &CG) {
+ ++Runs;
+ auto &SCCDep = AM.getResult<TestSCCAnalysis>(C, CG);
+
+ auto &ModuleProxy = AM.getResult<ModuleAnalysisManagerCGSCCProxy>(C, CG);
+ const ModuleAnalysisManager &MAM = ModuleProxy.getManager();
+ // For the test, we insist that the module analysis starts off in the
+ // cache.
+ auto &MDep = *MAM.getCachedResult<TestModuleAnalysis>(
+ *C.begin()->getFunction().getParent());
+ // Register the dependency as module analysis dependencies have to be
+ // pre-registered on the proxy.
+ ModuleProxy.registerOuterAnalysisInvalidation<TestModuleAnalysis,
+ TestIndirectSCCAnalysis>();
+
+ return Result(SCCDep, MDep);
+ }
+
+private:
+ friend AnalysisInfoMixin<TestIndirectSCCAnalysis>;
+ static AnalysisKey Key;
+
+ int &Runs;
+};
+
+AnalysisKey TestIndirectSCCAnalysis::Key;
+
+/// A test analysis pass which caches in its result the result from the above
+/// indirect analysis pass.
+///
+/// This allows us to ensure that whenever an analysis pass is invalidated due
+/// to dependencies (especially dependencies across IR units that trigger
+/// asynchronous invalidation) we correctly detect that this may in turn cause
+/// other analysis to be invalidated.
+struct TestDoublyIndirectSCCAnalysis
+ : public AnalysisInfoMixin<TestDoublyIndirectSCCAnalysis> {
+ struct Result {
+ Result(TestIndirectSCCAnalysis::Result &IDep) : IDep(IDep) {}
+ TestIndirectSCCAnalysis::Result &IDep;
+
+ bool invalidate(LazyCallGraph::SCC &C, const PreservedAnalyses &PA,
+ CGSCCAnalysisManager::Invalidator &Inv) {
+ auto PAC = PA.getChecker<TestDoublyIndirectSCCAnalysis>();
+ return !(PAC.preserved() ||
+ PAC.preservedSet<AllAnalysesOn<LazyCallGraph::SCC>>()) ||
+ Inv.invalidate<TestIndirectSCCAnalysis>(C, PA);
+ }
+ };
+
+ TestDoublyIndirectSCCAnalysis(int &Runs) : Runs(Runs) {}
+
+ /// Run the analysis pass over the function and return a result.
+ Result run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
+ LazyCallGraph &CG) {
+ ++Runs;
+ auto &IDep = AM.getResult<TestIndirectSCCAnalysis>(C, CG);
+ return Result(IDep);
+ }
+
+private:
+ friend AnalysisInfoMixin<TestDoublyIndirectSCCAnalysis>;
+ static AnalysisKey Key;
+
+ int &Runs;
+};
+
+AnalysisKey TestDoublyIndirectSCCAnalysis::Key;
+
+/// A test analysis pass which caches results from three different IR unit
+/// layers and requires intermediate layers to correctly propagate the entire
+/// distance.
+struct TestIndirectFunctionAnalysis
+ : public AnalysisInfoMixin<TestIndirectFunctionAnalysis> {
+ struct Result {
+ Result(TestFunctionAnalysis::Result &FDep, TestModuleAnalysis::Result &MDep,
+ TestSCCAnalysis::Result &SCCDep)
+ : FDep(FDep), MDep(MDep), SCCDep(SCCDep) {}
+ TestFunctionAnalysis::Result &FDep;
+ TestModuleAnalysis::Result &MDep;
+ TestSCCAnalysis::Result &SCCDep;
+
+ bool invalidate(Function &F, const PreservedAnalyses &PA,
+ FunctionAnalysisManager::Invalidator &Inv) {
+ auto PAC = PA.getChecker<TestIndirectFunctionAnalysis>();
+ return !(PAC.preserved() ||
+ PAC.preservedSet<AllAnalysesOn<Function>>()) ||
+ Inv.invalidate<TestFunctionAnalysis>(F, PA);
+ }
+ };
+
+ TestIndirectFunctionAnalysis(int &Runs) : Runs(Runs) {}
+
+ /// Run the analysis pass over the function and return a result.
+ Result run(Function &F, FunctionAnalysisManager &AM) {
+ ++Runs;
+ auto &FDep = AM.getResult<TestFunctionAnalysis>(F);
+
+ auto &ModuleProxy = AM.getResult<ModuleAnalysisManagerFunctionProxy>(F);
+ const ModuleAnalysisManager &MAM = ModuleProxy.getManager();
+ // For the test, we insist that the module analysis starts off in the
+ // cache.
+ auto &MDep = *MAM.getCachedResult<TestModuleAnalysis>(*F.getParent());
+ // Register the dependency as module analysis dependencies have to be
+ // pre-registered on the proxy.
+ ModuleProxy.registerOuterAnalysisInvalidation<
+ TestModuleAnalysis, TestIndirectFunctionAnalysis>();
+
+ // For thet test we assume this is run inside a CGSCC pass manager.
+ const LazyCallGraph &CG =
+ *MAM.getCachedResult<LazyCallGraphAnalysis>(*F.getParent());
+ auto &CGSCCProxy = AM.getResult<CGSCCAnalysisManagerFunctionProxy>(F);
+ const CGSCCAnalysisManager &CGAM = CGSCCProxy.getManager();
+ // For the test, we insist that the CGSCC analysis starts off in the cache.
+ auto &SCCDep =
+ *CGAM.getCachedResult<TestSCCAnalysis>(*CG.lookupSCC(*CG.lookup(F)));
+ // Register the dependency as CGSCC analysis dependencies have to be
+ // pre-registered on the proxy.
+ CGSCCProxy.registerOuterAnalysisInvalidation<
+ TestSCCAnalysis, TestIndirectFunctionAnalysis>();
+
+ return Result(FDep, MDep, SCCDep);
+ }
+
+private:
+ friend AnalysisInfoMixin<TestIndirectFunctionAnalysis>;
+ static AnalysisKey Key;
+
+ int &Runs;
+};
+
+AnalysisKey TestIndirectFunctionAnalysis::Key;
+
+TEST_F(CGSCCPassManagerTest, TestIndirectAnalysisInvalidation) {
+ int ModuleAnalysisRuns = 0;
+ MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns); });
+
+ int SCCAnalysisRuns = 0, IndirectSCCAnalysisRuns = 0,
+ DoublyIndirectSCCAnalysisRuns = 0;
+ CGAM.registerPass([&] { return TestSCCAnalysis(SCCAnalysisRuns); });
+ CGAM.registerPass(
+ [&] { return TestIndirectSCCAnalysis(IndirectSCCAnalysisRuns); });
+ CGAM.registerPass([&] {
+ return TestDoublyIndirectSCCAnalysis(DoublyIndirectSCCAnalysisRuns);
+ });
+
+ int FunctionAnalysisRuns = 0, IndirectFunctionAnalysisRuns = 0;
+ FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); });
+ FAM.registerPass([&] {
+ return TestIndirectFunctionAnalysis(IndirectFunctionAnalysisRuns);
+ });
+
+ ModulePassManager MPM(/*DebugLogging*/ true);
+
+ int FunctionCount = 0;
+ CGSCCPassManager CGPM(/*DebugLogging*/ true);
+ // First just use the analysis to get the function count and preserve
+ // everything.
+ CGPM.addPass(
+ LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
+ LazyCallGraph &CG, CGSCCUpdateResult &) {
+ auto &DoublyIndirectResult =
+ AM.getResult<TestDoublyIndirectSCCAnalysis>(C, CG);
+ auto &IndirectResult = DoublyIndirectResult.IDep;
+ FunctionCount += IndirectResult.SCCDep.FunctionCount;
+ return PreservedAnalyses::all();
+ }));
+ // Next, invalidate
+ // - both analyses for the (f) and (x) SCCs,
+ // - just the underlying (indirect) analysis for (g) SCC, and
+ // - just the direct analysis for (h1,h2,h3) SCC.
+ CGPM.addPass(
+ LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
+ LazyCallGraph &CG, CGSCCUpdateResult &) {
+ auto &DoublyIndirectResult =
+ AM.getResult<TestDoublyIndirectSCCAnalysis>(C, CG);
+ auto &IndirectResult = DoublyIndirectResult.IDep;
+ FunctionCount += IndirectResult.SCCDep.FunctionCount;
+ auto PA = PreservedAnalyses::none();
+ if (C.getName() == "(g)")
+ PA.preserve<TestSCCAnalysis>();
+ else if (C.getName() == "(h3, h1, h2)")
+ PA.preserve<TestIndirectSCCAnalysis>();
+ return PA;
+ }));
+ // Finally, use the analysis again on each function, forcing re-computation
+ // for all of them.
+ CGPM.addPass(
+ LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
+ LazyCallGraph &CG, CGSCCUpdateResult &) {
+ auto &DoublyIndirectResult =
+ AM.getResult<TestDoublyIndirectSCCAnalysis>(C, CG);
+ auto &IndirectResult = DoublyIndirectResult.IDep;
+ FunctionCount += IndirectResult.SCCDep.FunctionCount;
+ return PreservedAnalyses::all();
+ }));
+
+ // Create a second CGSCC pass manager. This will cause the module-level
+ // invalidation to occur, which will force yet another invalidation of the
+ // indirect SCC-level analysis as the module analysis it depends on gets
+ // invalidated.
+ CGSCCPassManager CGPM2(/*DebugLogging*/ true);
+ CGPM2.addPass(
+ LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
+ LazyCallGraph &CG, CGSCCUpdateResult &) {
+ auto &DoublyIndirectResult =
+ AM.getResult<TestDoublyIndirectSCCAnalysis>(C, CG);
+ auto &IndirectResult = DoublyIndirectResult.IDep;
+ FunctionCount += IndirectResult.SCCDep.FunctionCount;
+ return PreservedAnalyses::all();
+ }));
+
+ // Add a requires pass to populate the module analysis and then our function
+ // pass pipeline.
+ MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>());
+ MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM)));
+ // Now require the module analysis again (it will have been invalidated once)
+ // and then use it again from a function pass manager.
+ MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>());
+ MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2)));
+ MPM.run(*M, MAM);
+
+ // There are generally two possible runs for each of the four SCCs. But
+ // for one SCC, we only invalidate the indirect analysis so the base one
+ // only gets run seven times.
+ EXPECT_EQ(7, SCCAnalysisRuns);
+ // The module analysis pass should be run twice here.
+ EXPECT_EQ(2, ModuleAnalysisRuns);
+ // The indirect analysis is invalidated (either directly or indirectly) three
+ // times for each of four SCCs.
+ EXPECT_EQ(3 * 4, IndirectSCCAnalysisRuns);
+ EXPECT_EQ(3 * 4, DoublyIndirectSCCAnalysisRuns);
+
+ // Four passes count each of six functions once (via SCCs).
+ EXPECT_EQ(4 * 6, FunctionCount);
+}
}
diff --git a/unittests/Analysis/CMakeLists.txt b/unittests/Analysis/CMakeLists.txt
index 2292a454c27a..65a2ac094cff 100644
--- a/unittests/Analysis/CMakeLists.txt
+++ b/unittests/Analysis/CMakeLists.txt
@@ -8,13 +8,15 @@ set(LLVM_LINK_COMPONENTS
add_llvm_unittest(AnalysisTests
AliasAnalysisTest.cpp
BlockFrequencyInfoTest.cpp
+ BranchProbabilityInfoTest.cpp
CallGraphTest.cpp
CFGTest.cpp
CGSCCPassManagerTest.cpp
LazyCallGraphTest.cpp
LoopPassManagerTest.cpp
+ MemoryBuiltinsTest.cpp
ScalarEvolutionTest.cpp
- MixedTBAATest.cpp
+ TBAATest.cpp
ValueTrackingTest.cpp
UnrollAnalyzer.cpp
)
diff --git a/unittests/Analysis/CallGraphTest.cpp b/unittests/Analysis/CallGraphTest.cpp
index af46291074c2..2d4e63facf3b 100644
--- a/unittests/Analysis/CallGraphTest.cpp
+++ b/unittests/Analysis/CallGraphTest.cpp
@@ -17,29 +17,29 @@ using namespace llvm;
namespace {
template <typename Ty> void canSpecializeGraphTraitsIterators(Ty *G) {
- typedef typename GraphTraits<Ty *>::NodeType NodeTy;
+ typedef typename GraphTraits<Ty *>::NodeRef NodeRef;
auto I = GraphTraits<Ty *>::nodes_begin(G);
auto E = GraphTraits<Ty *>::nodes_end(G);
auto X = ++I;
// Should be able to iterate over all nodes of the graph.
- static_assert(std::is_same<decltype(*I), NodeTy &>::value,
+ static_assert(std::is_same<decltype(*I), NodeRef>::value,
"Node type does not match");
- static_assert(std::is_same<decltype(*X), NodeTy &>::value,
+ static_assert(std::is_same<decltype(*X), NodeRef>::value,
"Node type does not match");
- static_assert(std::is_same<decltype(*E), NodeTy &>::value,
+ static_assert(std::is_same<decltype(*E), NodeRef>::value,
"Node type does not match");
- NodeTy *N = GraphTraits<Ty *>::getEntryNode(G);
+ NodeRef N = GraphTraits<Ty *>::getEntryNode(G);
- auto S = GraphTraits<NodeTy *>::child_begin(N);
- auto F = GraphTraits<NodeTy *>::child_end(N);
+ auto S = GraphTraits<NodeRef>::child_begin(N);
+ auto F = GraphTraits<NodeRef>::child_end(N);
// Should be able to iterate over immediate successors of a node.
- static_assert(std::is_same<decltype(*S), NodeTy *>::value,
+ static_assert(std::is_same<decltype(*S), NodeRef>::value,
"Node type does not match");
- static_assert(std::is_same<decltype(*F), NodeTy *>::value,
+ static_assert(std::is_same<decltype(*F), NodeRef>::value,
"Node type does not match");
}
diff --git a/unittests/Analysis/LazyCallGraphTest.cpp b/unittests/Analysis/LazyCallGraphTest.cpp
index 224a9458cc88..5bb9dec3449f 100644
--- a/unittests/Analysis/LazyCallGraphTest.cpp
+++ b/unittests/Analysis/LazyCallGraphTest.cpp
@@ -9,6 +9,7 @@
#include "llvm/Analysis/LazyCallGraph.h"
#include "llvm/AsmParser/Parser.h"
+#include "llvm/IR/Instructions.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
@@ -120,6 +121,101 @@ static const char DiamondOfTriangles[] =
" ret void\n"
"}\n";
+/*
+ IR forming a reference graph with a diamond of triangle-shaped RefSCCs
+
+ d1
+ / \
+ d3--d2
+ / \
+ b1 c1
+ / \ / \
+ b3--b2 c3--c2
+ \ /
+ a1
+ / \
+ a3--a2
+
+ All call edges go up between RefSCCs, and clockwise around the RefSCC.
+ */
+static const char DiamondOfTrianglesRefGraph[] =
+ "define void @a1() {\n"
+ "entry:\n"
+ " %a = alloca void ()*\n"
+ " store void ()* @a2, void ()** %a\n"
+ " store void ()* @b2, void ()** %a\n"
+ " store void ()* @c3, void ()** %a\n"
+ " ret void\n"
+ "}\n"
+ "define void @a2() {\n"
+ "entry:\n"
+ " %a = alloca void ()*\n"
+ " store void ()* @a3, void ()** %a\n"
+ " ret void\n"
+ "}\n"
+ "define void @a3() {\n"
+ "entry:\n"
+ " %a = alloca void ()*\n"
+ " store void ()* @a1, void ()** %a\n"
+ " ret void\n"
+ "}\n"
+ "define void @b1() {\n"
+ "entry:\n"
+ " %a = alloca void ()*\n"
+ " store void ()* @b2, void ()** %a\n"
+ " store void ()* @d3, void ()** %a\n"
+ " ret void\n"
+ "}\n"
+ "define void @b2() {\n"
+ "entry:\n"
+ " %a = alloca void ()*\n"
+ " store void ()* @b3, void ()** %a\n"
+ " ret void\n"
+ "}\n"
+ "define void @b3() {\n"
+ "entry:\n"
+ " %a = alloca void ()*\n"
+ " store void ()* @b1, void ()** %a\n"
+ " ret void\n"
+ "}\n"
+ "define void @c1() {\n"
+ "entry:\n"
+ " %a = alloca void ()*\n"
+ " store void ()* @c2, void ()** %a\n"
+ " store void ()* @d2, void ()** %a\n"
+ " ret void\n"
+ "}\n"
+ "define void @c2() {\n"
+ "entry:\n"
+ " %a = alloca void ()*\n"
+ " store void ()* @c3, void ()** %a\n"
+ " ret void\n"
+ "}\n"
+ "define void @c3() {\n"
+ "entry:\n"
+ " %a = alloca void ()*\n"
+ " store void ()* @c1, void ()** %a\n"
+ " ret void\n"
+ "}\n"
+ "define void @d1() {\n"
+ "entry:\n"
+ " %a = alloca void ()*\n"
+ " store void ()* @d2, void ()** %a\n"
+ " ret void\n"
+ "}\n"
+ "define void @d2() {\n"
+ "entry:\n"
+ " %a = alloca void ()*\n"
+ " store void ()* @d3, void ()** %a\n"
+ " ret void\n"
+ "}\n"
+ "define void @d3() {\n"
+ "entry:\n"
+ " %a = alloca void ()*\n"
+ " store void ()* @d1, void ()** %a\n"
+ " ret void\n"
+ "}\n";
+
TEST(LazyCallGraphTest, BasicGraphFormation) {
LLVMContext Context;
std::unique_ptr<Module> M = parseAssembly(Context, DiamondOfTriangles);
@@ -220,6 +316,7 @@ TEST(LazyCallGraphTest, BasicGraphFormation) {
EXPECT_FALSE(D.isChildOf(D));
EXPECT_FALSE(D.isAncestorOf(D));
EXPECT_FALSE(D.isDescendantOf(D));
+ EXPECT_EQ(&D, &*CG.postorder_ref_scc_begin());
LazyCallGraph::RefSCC &C = *J++;
ASSERT_EQ(1, C.size());
@@ -235,6 +332,7 @@ TEST(LazyCallGraphTest, BasicGraphFormation) {
EXPECT_FALSE(C.isChildOf(D));
EXPECT_TRUE(C.isAncestorOf(D));
EXPECT_FALSE(C.isDescendantOf(D));
+ EXPECT_EQ(&C, &*std::next(CG.postorder_ref_scc_begin()));
LazyCallGraph::RefSCC &B = *J++;
ASSERT_EQ(1, B.size());
@@ -252,6 +350,7 @@ TEST(LazyCallGraphTest, BasicGraphFormation) {
EXPECT_FALSE(B.isDescendantOf(D));
EXPECT_FALSE(B.isAncestorOf(C));
EXPECT_FALSE(C.isAncestorOf(B));
+ EXPECT_EQ(&B, &*std::next(CG.postorder_ref_scc_begin(), 2));
LazyCallGraph::RefSCC &A = *J++;
ASSERT_EQ(1, A.size());
@@ -269,8 +368,10 @@ TEST(LazyCallGraphTest, BasicGraphFormation) {
EXPECT_TRUE(A.isAncestorOf(B));
EXPECT_TRUE(A.isAncestorOf(C));
EXPECT_TRUE(A.isAncestorOf(D));
+ EXPECT_EQ(&A, &*std::next(CG.postorder_ref_scc_begin(), 3));
EXPECT_EQ(CG.postorder_ref_scc_end(), J);
+ EXPECT_EQ(J, std::next(CG.postorder_ref_scc_begin(), 4));
}
static Function &lookupFunction(Module &M, StringRef Name) {
@@ -478,7 +579,7 @@ TEST(LazyCallGraphTest, OutgoingEdgeMutation) {
// Force the graph to be fully expanded.
for (LazyCallGraph::RefSCC &RC : CG.postorder_ref_sccs())
- (void)RC;
+ dbgs() << "Formed RefSCC: " << RC << "\n";
LazyCallGraph::Node &A = *CG.lookup(lookupFunction(*M, "a"));
LazyCallGraph::Node &B = *CG.lookup(lookupFunction(*M, "b"));
@@ -493,13 +594,21 @@ TEST(LazyCallGraphTest, OutgoingEdgeMutation) {
LazyCallGraph::RefSCC &CRC = *CG.lookupRefSCC(C);
LazyCallGraph::RefSCC &DRC = *CG.lookupRefSCC(D);
EXPECT_TRUE(ARC.isParentOf(BRC));
+ EXPECT_TRUE(AC.isParentOf(BC));
EXPECT_TRUE(ARC.isParentOf(CRC));
+ EXPECT_TRUE(AC.isParentOf(CC));
EXPECT_FALSE(ARC.isParentOf(DRC));
+ EXPECT_FALSE(AC.isParentOf(DC));
EXPECT_TRUE(ARC.isAncestorOf(DRC));
+ EXPECT_TRUE(AC.isAncestorOf(DC));
EXPECT_FALSE(DRC.isChildOf(ARC));
+ EXPECT_FALSE(DC.isChildOf(AC));
EXPECT_TRUE(DRC.isDescendantOf(ARC));
+ EXPECT_TRUE(DC.isDescendantOf(AC));
EXPECT_TRUE(DRC.isChildOf(BRC));
+ EXPECT_TRUE(DC.isChildOf(BC));
EXPECT_TRUE(DRC.isChildOf(CRC));
+ EXPECT_TRUE(DC.isChildOf(CC));
EXPECT_EQ(2, std::distance(A.begin(), A.end()));
ARC.insertOutgoingEdge(A, D, LazyCallGraph::Edge::Call);
@@ -512,9 +621,13 @@ TEST(LazyCallGraphTest, OutgoingEdgeMutation) {
// Only the parent and child tests sholud have changed. The rest of the graph
// remains the same.
EXPECT_TRUE(ARC.isParentOf(DRC));
+ EXPECT_TRUE(AC.isParentOf(DC));
EXPECT_TRUE(ARC.isAncestorOf(DRC));
+ EXPECT_TRUE(AC.isAncestorOf(DC));
EXPECT_TRUE(DRC.isChildOf(ARC));
+ EXPECT_TRUE(DC.isChildOf(AC));
EXPECT_TRUE(DRC.isDescendantOf(ARC));
+ EXPECT_TRUE(DC.isDescendantOf(AC));
EXPECT_EQ(&AC, CG.lookupSCC(A));
EXPECT_EQ(&BC, CG.lookupSCC(B));
EXPECT_EQ(&CC, CG.lookupSCC(C));
@@ -527,11 +640,15 @@ TEST(LazyCallGraphTest, OutgoingEdgeMutation) {
ARC.switchOutgoingEdgeToRef(A, D);
EXPECT_FALSE(NewE.isCall());
- // Verify the graph remains the same.
+ // Verify the reference graph remains the same but the SCC graph is updated.
EXPECT_TRUE(ARC.isParentOf(DRC));
+ EXPECT_FALSE(AC.isParentOf(DC));
EXPECT_TRUE(ARC.isAncestorOf(DRC));
+ EXPECT_TRUE(AC.isAncestorOf(DC));
EXPECT_TRUE(DRC.isChildOf(ARC));
+ EXPECT_FALSE(DC.isChildOf(AC));
EXPECT_TRUE(DRC.isDescendantOf(ARC));
+ EXPECT_TRUE(DC.isDescendantOf(AC));
EXPECT_EQ(&AC, CG.lookupSCC(A));
EXPECT_EQ(&BC, CG.lookupSCC(B));
EXPECT_EQ(&CC, CG.lookupSCC(C));
@@ -544,11 +661,15 @@ TEST(LazyCallGraphTest, OutgoingEdgeMutation) {
ARC.switchOutgoingEdgeToCall(A, D);
EXPECT_TRUE(NewE.isCall());
- // Verify the graph remains the same.
+ // Verify the reference graph remains the same but the SCC graph is updated.
EXPECT_TRUE(ARC.isParentOf(DRC));
+ EXPECT_TRUE(AC.isParentOf(DC));
EXPECT_TRUE(ARC.isAncestorOf(DRC));
+ EXPECT_TRUE(AC.isAncestorOf(DC));
EXPECT_TRUE(DRC.isChildOf(ARC));
+ EXPECT_TRUE(DC.isChildOf(AC));
EXPECT_TRUE(DRC.isDescendantOf(ARC));
+ EXPECT_TRUE(DC.isDescendantOf(AC));
EXPECT_EQ(&AC, CG.lookupSCC(A));
EXPECT_EQ(&BC, CG.lookupSCC(B));
EXPECT_EQ(&CC, CG.lookupSCC(C));
@@ -563,9 +684,13 @@ TEST(LazyCallGraphTest, OutgoingEdgeMutation) {
// Now the parent and child tests fail again but the rest remains the same.
EXPECT_FALSE(ARC.isParentOf(DRC));
+ EXPECT_FALSE(AC.isParentOf(DC));
EXPECT_TRUE(ARC.isAncestorOf(DRC));
+ EXPECT_TRUE(AC.isAncestorOf(DC));
EXPECT_FALSE(DRC.isChildOf(ARC));
+ EXPECT_FALSE(DC.isChildOf(AC));
EXPECT_TRUE(DRC.isDescendantOf(ARC));
+ EXPECT_TRUE(DC.isDescendantOf(AC));
EXPECT_EQ(&AC, CG.lookupSCC(A));
EXPECT_EQ(&BC, CG.lookupSCC(B));
EXPECT_EQ(&CC, CG.lookupSCC(C));
@@ -599,7 +724,7 @@ TEST(LazyCallGraphTest, IncomingEdgeInsertion) {
// Force the graph to be fully expanded.
for (LazyCallGraph::RefSCC &RC : CG.postorder_ref_sccs())
- (void)RC;
+ dbgs() << "Formed RefSCC: " << RC << "\n";
LazyCallGraph::Node &A1 = *CG.lookup(lookupFunction(*M, "a1"));
LazyCallGraph::Node &A2 = *CG.lookup(lookupFunction(*M, "a2"));
@@ -668,6 +793,16 @@ TEST(LazyCallGraphTest, IncomingEdgeInsertion) {
// And that ancestry tests have been updated.
EXPECT_TRUE(ARC.isParentOf(CRC));
EXPECT_TRUE(BRC.isParentOf(CRC));
+
+ // And verify the post-order walk reflects the updated structure.
+ auto I = CG.postorder_ref_scc_begin(), E = CG.postorder_ref_scc_end();
+ ASSERT_NE(I, E);
+ EXPECT_EQ(&CRC, &*I) << "Actual RefSCC: " << *I;
+ ASSERT_NE(++I, E);
+ EXPECT_EQ(&BRC, &*I) << "Actual RefSCC: " << *I;
+ ASSERT_NE(++I, E);
+ EXPECT_EQ(&ARC, &*I) << "Actual RefSCC: " << *I;
+ EXPECT_EQ(++I, E);
}
TEST(LazyCallGraphTest, IncomingEdgeInsertionMidTraversal) {
@@ -726,15 +861,574 @@ TEST(LazyCallGraphTest, IncomingEdgeInsertionMidTraversal) {
EXPECT_EQ(&CRC, CG.lookupRefSCC(D2));
EXPECT_EQ(&CRC, CG.lookupRefSCC(D3));
- // Check that we can form the last two RefSCCs now in a coherent way.
+ // 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 &BRC = *I;
+ 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
+ // references rather than calls.
+ std::unique_ptr<Module> M =
+ parseAssembly(Context, DiamondOfTrianglesRefGraph);
+ LazyCallGraph CG(*M);
+
+ // Force the graph to be fully expanded.
+ for (LazyCallGraph::RefSCC &RC : CG.postorder_ref_sccs())
+ dbgs() << "Formed RefSCC: " << RC << "\n";
+
+ LazyCallGraph::Node &A1 = *CG.lookup(lookupFunction(*M, "a1"));
+ LazyCallGraph::Node &A2 = *CG.lookup(lookupFunction(*M, "a2"));
+ LazyCallGraph::Node &A3 = *CG.lookup(lookupFunction(*M, "a3"));
+ LazyCallGraph::Node &B1 = *CG.lookup(lookupFunction(*M, "b1"));
+ LazyCallGraph::Node &B2 = *CG.lookup(lookupFunction(*M, "b2"));
+ LazyCallGraph::Node &B3 = *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"));
+ LazyCallGraph::RefSCC &ARC = *CG.lookupRefSCC(A1);
+ LazyCallGraph::RefSCC &BRC = *CG.lookupRefSCC(B1);
+ LazyCallGraph::RefSCC &CRC = *CG.lookupRefSCC(C1);
+ LazyCallGraph::RefSCC &DRC = *CG.lookupRefSCC(D1);
+ ASSERT_EQ(&ARC, CG.lookupRefSCC(A2));
+ ASSERT_EQ(&ARC, CG.lookupRefSCC(A3));
+ ASSERT_EQ(&BRC, CG.lookupRefSCC(B2));
+ ASSERT_EQ(&BRC, CG.lookupRefSCC(B3));
+ ASSERT_EQ(&CRC, CG.lookupRefSCC(C2));
+ 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()));
+
+ // Add an edge to make the graph:
+ //
+ // d1 |
+ // / \ |
+ // d3--d2---. |
+ // / \ | |
+ // b1 c1 | |
+ // / \ / \ / |
+ // b3--b2 c3--c2 |
+ // \ / |
+ // a1 |
+ // / \ |
+ // a3--a2 |
+ 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 SCC sets.
+ EXPECT_EQ(&ARC, CG.lookupRefSCC(A1));
+ EXPECT_EQ(&ARC, CG.lookupRefSCC(A2));
+ EXPECT_EQ(&ARC, CG.lookupRefSCC(A3));
+ EXPECT_EQ(&BRC, CG.lookupRefSCC(B1));
+ EXPECT_EQ(&BRC, CG.lookupRefSCC(B2));
+ EXPECT_EQ(&BRC, CG.lookupRefSCC(B3));
+ 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));
+
+ // And that ancestry tests have been updated.
+ EXPECT_TRUE(ARC.isParentOf(CRC));
+ EXPECT_TRUE(BRC.isParentOf(CRC));
+
+ // And verify the post-order walk reflects the updated structure.
+ auto I = CG.postorder_ref_scc_begin(), E = CG.postorder_ref_scc_end();
+ ASSERT_NE(I, E);
+ EXPECT_EQ(&CRC, &*I) << "Actual RefSCC: " << *I;
+ ASSERT_NE(++I, E);
+ EXPECT_EQ(&BRC, &*I) << "Actual RefSCC: " << *I;
+ ASSERT_NE(++I, E);
+ EXPECT_EQ(&ARC, &*I) << "Actual RefSCC: " << *I;
+ EXPECT_EQ(++I, E);
+}
+
+TEST(LazyCallGraphTest, IncomingEdgeInsertionLargeCallCycle) {
+ LLVMContext Context;
+ std::unique_ptr<Module> M = parseAssembly(Context, "define void @a() {\n"
+ "entry:\n"
+ " call void @b()\n"
+ " ret void\n"
+ "}\n"
+ "define void @b() {\n"
+ "entry:\n"
+ " call void @c()\n"
+ " ret void\n"
+ "}\n"
+ "define void @c() {\n"
+ "entry:\n"
+ " call void @d()\n"
+ " ret void\n"
+ "}\n"
+ "define void @d() {\n"
+ "entry:\n"
+ " ret void\n"
+ "}\n");
+ LazyCallGraph CG(*M);
+
+ // Force the graph to be fully expanded.
+ for (LazyCallGraph::RefSCC &RC : CG.postorder_ref_sccs())
+ dbgs() << "Formed RefSCC: " << RC << "\n";
+
+ LazyCallGraph::Node &A = *CG.lookup(lookupFunction(*M, "a"));
+ LazyCallGraph::Node &B = *CG.lookup(lookupFunction(*M, "b"));
+ LazyCallGraph::Node &C = *CG.lookup(lookupFunction(*M, "c"));
+ LazyCallGraph::Node &D = *CG.lookup(lookupFunction(*M, "d"));
+ LazyCallGraph::SCC &AC = *CG.lookupSCC(A);
+ LazyCallGraph::SCC &BC = *CG.lookupSCC(B);
+ LazyCallGraph::SCC &CC = *CG.lookupSCC(C);
+ LazyCallGraph::SCC &DC = *CG.lookupSCC(D);
+ LazyCallGraph::RefSCC &ARC = *CG.lookupRefSCC(A);
+ LazyCallGraph::RefSCC &BRC = *CG.lookupRefSCC(B);
+ LazyCallGraph::RefSCC &CRC = *CG.lookupRefSCC(C);
+ LazyCallGraph::RefSCC &DRC = *CG.lookupRefSCC(D);
+
+ // 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());
+
+ // Check that we have the dead RCs, but ignore the order.
+ EXPECT_EQ(3u, MergedRCs.size());
+ EXPECT_NE(find(MergedRCs, &BRC), MergedRCs.end());
+ EXPECT_NE(find(MergedRCs, &CRC), MergedRCs.end());
+ EXPECT_NE(find(MergedRCs, &DRC), MergedRCs.end());
+
+ // Make sure the nodes point to the right place now.
+ EXPECT_EQ(&ARC, CG.lookupRefSCC(A));
+ EXPECT_EQ(&ARC, CG.lookupRefSCC(B));
+ EXPECT_EQ(&ARC, CG.lookupRefSCC(C));
+ EXPECT_EQ(&ARC, CG.lookupRefSCC(D));
+
+ // Check that the SCCs are in postorder.
+ EXPECT_EQ(4, ARC.size());
+ EXPECT_EQ(&DC, &ARC[0]);
+ EXPECT_EQ(&CC, &ARC[1]);
+ EXPECT_EQ(&BC, &ARC[2]);
+ EXPECT_EQ(&AC, &ARC[3]);
+
+ // And verify the post-order walk reflects the updated structure.
+ auto I = CG.postorder_ref_scc_begin(), E = CG.postorder_ref_scc_end();
+ ASSERT_NE(I, E);
+ EXPECT_EQ(&ARC, &*I) << "Actual RefSCC: " << *I;
+ EXPECT_EQ(++I, E);
+}
+
+TEST(LazyCallGraphTest, IncomingEdgeInsertionLargeRefCycle) {
+ LLVMContext Context;
+ std::unique_ptr<Module> M =
+ parseAssembly(Context, "define void @a() {\n"
+ "entry:\n"
+ " %p = alloca void ()*\n"
+ " store void ()* @b, void ()** %p\n"
+ " ret void\n"
+ "}\n"
+ "define void @b() {\n"
+ "entry:\n"
+ " %p = alloca void ()*\n"
+ " store void ()* @c, void ()** %p\n"
+ " ret void\n"
+ "}\n"
+ "define void @c() {\n"
+ "entry:\n"
+ " %p = alloca void ()*\n"
+ " store void ()* @d, void ()** %p\n"
+ " ret void\n"
+ "}\n"
+ "define void @d() {\n"
+ "entry:\n"
+ " ret void\n"
+ "}\n");
+ LazyCallGraph CG(*M);
+
+ // Force the graph to be fully expanded.
+ for (LazyCallGraph::RefSCC &RC : CG.postorder_ref_sccs())
+ dbgs() << "Formed RefSCC: " << RC << "\n";
+
+ LazyCallGraph::Node &A = *CG.lookup(lookupFunction(*M, "a"));
+ LazyCallGraph::Node &B = *CG.lookup(lookupFunction(*M, "b"));
+ LazyCallGraph::Node &C = *CG.lookup(lookupFunction(*M, "c"));
+ LazyCallGraph::Node &D = *CG.lookup(lookupFunction(*M, "d"));
+ LazyCallGraph::RefSCC &ARC = *CG.lookupRefSCC(A);
+ LazyCallGraph::RefSCC &BRC = *CG.lookupRefSCC(B);
+ LazyCallGraph::RefSCC &CRC = *CG.lookupRefSCC(C);
+ LazyCallGraph::RefSCC &DRC = *CG.lookupRefSCC(D);
+
+ // Connect the top to the bottom forming a large RefSCC made up just of
+ // 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());
+
+ // Check that we have the dead RCs, but ignore the order.
+ EXPECT_EQ(3u, MergedRCs.size());
+ EXPECT_NE(find(MergedRCs, &BRC), MergedRCs.end());
+ EXPECT_NE(find(MergedRCs, &CRC), MergedRCs.end());
+ EXPECT_NE(find(MergedRCs, &DRC), MergedRCs.end());
+
+ // Make sure the nodes point to the right place now.
+ EXPECT_EQ(&ARC, CG.lookupRefSCC(A));
+ EXPECT_EQ(&ARC, CG.lookupRefSCC(B));
+ EXPECT_EQ(&ARC, CG.lookupRefSCC(C));
+ EXPECT_EQ(&ARC, CG.lookupRefSCC(D));
+
+ // And verify the post-order walk reflects the updated structure.
+ auto I = CG.postorder_ref_scc_begin(), End = CG.postorder_ref_scc_end();
+ ASSERT_NE(I, End);
+ EXPECT_EQ(&ARC, &*I) << "Actual RefSCC: " << *I;
+ EXPECT_EQ(++I, End);
+}
+
+TEST(LazyCallGraphTest, InlineAndDeleteFunction) {
+ LLVMContext Context;
+ // We want to ensure we can delete nodes from relatively complex graphs and
+ // so use the diamond of triangles graph defined above.
+ //
+ // 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);
+
+ // Force the graph to be fully expanded.
+ for (LazyCallGraph::RefSCC &RC : CG.postorder_ref_sccs())
+ dbgs() << "Formed RefSCC: " << RC << "\n";
+
+ LazyCallGraph::Node &A1 = *CG.lookup(lookupFunction(*M, "a1"));
+ LazyCallGraph::Node &A2 = *CG.lookup(lookupFunction(*M, "a2"));
+ LazyCallGraph::Node &A3 = *CG.lookup(lookupFunction(*M, "a3"));
+ LazyCallGraph::Node &B1 = *CG.lookup(lookupFunction(*M, "b1"));
+ LazyCallGraph::Node &B2 = *CG.lookup(lookupFunction(*M, "b2"));
+ LazyCallGraph::Node &B3 = *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"));
+ LazyCallGraph::RefSCC &ARC = *CG.lookupRefSCC(A1);
+ LazyCallGraph::RefSCC &BRC = *CG.lookupRefSCC(B1);
+ LazyCallGraph::RefSCC &CRC = *CG.lookupRefSCC(C1);
+ LazyCallGraph::RefSCC &DRC = *CG.lookupRefSCC(D1);
+ ASSERT_EQ(&ARC, CG.lookupRefSCC(A2));
+ ASSERT_EQ(&ARC, CG.lookupRefSCC(A3));
+ ASSERT_EQ(&BRC, CG.lookupRefSCC(B2));
+ ASSERT_EQ(&BRC, CG.lookupRefSCC(B3));
+ ASSERT_EQ(&CRC, CG.lookupRefSCC(C2));
+ 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()));
+
+ // 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(&ARC, CG.lookupRefSCC(A1));
+ EXPECT_EQ(&ARC, CG.lookupRefSCC(A2));
+ EXPECT_EQ(&ARC, CG.lookupRefSCC(A3));
+ EXPECT_EQ(&BRC, CG.lookupRefSCC(B1));
+ EXPECT_EQ(&BRC, CG.lookupRefSCC(B2));
+ EXPECT_EQ(&BRC, CG.lookupRefSCC(B3));
+ 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 the post-order walk hasn't changed.
+ auto I = CG.postorder_ref_scc_begin(), E = CG.postorder_ref_scc_end();
+ ASSERT_NE(I, E);
+ EXPECT_EQ(&NewDRC, &*I) << "Actual RefSCC: " << *I;
+ ASSERT_NE(++I, E);
+ EXPECT_EQ(&CRC, &*I) << "Actual RefSCC: " << *I;
+ ASSERT_NE(++I, E);
+ EXPECT_EQ(&BRC, &*I) << "Actual RefSCC: " << *I;
+ ASSERT_NE(++I, E);
+ EXPECT_EQ(&ARC, &*I) << "Actual RefSCC: " << *I;
+ 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(CRC));
+ 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;
@@ -742,9 +1436,15 @@ TEST(LazyCallGraphTest, IncomingEdgeInsertionMidTraversal) {
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) {
@@ -796,7 +1496,7 @@ TEST(LazyCallGraphTest, InternalEdgeMutation) {
// Switch the call edge from 'b' to 'c' to a ref edge. This will break the
// call cycle and cause us to form more SCCs. The RefSCC will remain the same
// though.
- RC.switchInternalEdgeToRef(B, C);
+ auto NewCs = RC.switchInternalEdgeToRef(B, C);
EXPECT_EQ(&RC, CG.lookupRefSCC(A));
EXPECT_EQ(&RC, CG.lookupRefSCC(B));
EXPECT_EQ(&RC, CG.lookupRefSCC(C));
@@ -808,6 +1508,10 @@ TEST(LazyCallGraphTest, InternalEdgeMutation) {
EXPECT_EQ(&*J++, CG.lookupSCC(A));
EXPECT_EQ(&*J++, CG.lookupSCC(C));
EXPECT_EQ(RC.end(), J);
+ // And the returned range must be the slice of this sequence containing new
+ // SCCs.
+ EXPECT_EQ(RC.begin(), NewCs.begin());
+ EXPECT_EQ(std::prev(RC.end()), NewCs.end());
// Test turning the ref edge from A to C into a call edge. This will form an
// SCC out of A and C. Since we previously had a call edge from C to A, the
@@ -855,9 +1559,9 @@ TEST(LazyCallGraphTest, InternalEdgeRemoval) {
LazyCallGraph CG(*M);
// Force the graph to be fully expanded.
- auto I = CG.postorder_ref_scc_begin();
- LazyCallGraph::RefSCC &RC = *I++;
- EXPECT_EQ(CG.postorder_ref_scc_end(), I);
+ auto I = CG.postorder_ref_scc_begin(), E = CG.postorder_ref_scc_end();
+ LazyCallGraph::RefSCC &RC = *I;
+ EXPECT_EQ(E, std::next(I));
LazyCallGraph::Node &A = *CG.lookup(lookupFunction(*M, "a"));
LazyCallGraph::Node &B = *CG.lookup(lookupFunction(*M, "b"));
@@ -874,6 +1578,10 @@ TEST(LazyCallGraphTest, InternalEdgeRemoval) {
EXPECT_EQ(&RC, CG.lookupRefSCC(A));
EXPECT_EQ(&RC, CG.lookupRefSCC(B));
EXPECT_EQ(&RC, CG.lookupRefSCC(C));
+ auto J = CG.postorder_ref_scc_begin();
+ EXPECT_EQ(I, J);
+ EXPECT_EQ(&RC, &*J);
+ EXPECT_EQ(E, std::next(J));
// Remove the edge from c -> a, which should leave 'a' in the original RefSCC
// and form a new RefSCC for 'b' and 'c'.
@@ -881,9 +1589,97 @@ TEST(LazyCallGraphTest, InternalEdgeRemoval) {
EXPECT_EQ(1u, NewRCs.size());
EXPECT_EQ(&RC, CG.lookupRefSCC(A));
EXPECT_EQ(1, std::distance(RC.begin(), RC.end()));
- LazyCallGraph::RefSCC *RC2 = CG.lookupRefSCC(B);
- EXPECT_EQ(RC2, CG.lookupRefSCC(C));
- EXPECT_EQ(RC2, NewRCs[0]);
+ LazyCallGraph::RefSCC &RC2 = *CG.lookupRefSCC(B);
+ EXPECT_EQ(&RC2, CG.lookupRefSCC(C));
+ EXPECT_EQ(&RC2, NewRCs[0]);
+ J = CG.postorder_ref_scc_begin();
+ EXPECT_NE(I, J);
+ EXPECT_EQ(&RC2, &*J);
+ ++J;
+ EXPECT_EQ(I, J);
+ EXPECT_EQ(&RC, &*J);
+ ++I;
+ EXPECT_EQ(E, I);
+ ++J;
+ EXPECT_EQ(E, J);
+}
+
+TEST(LazyCallGraphTest, InternalNoOpEdgeRemoval) {
+ LLVMContext Context;
+ // A graph with a single cycle formed both from call and reference edges
+ // which makes the reference edges trivial to delete. The graph looks like:
+ //
+ // Reference edges: a -> b -> c -> a
+ // Call edges: a -> c -> b -> a
+ std::unique_ptr<Module> M = parseAssembly(
+ Context, "define void @a(i8** %ptr) {\n"
+ "entry:\n"
+ " call void @b(i8** %ptr)\n"
+ " store i8* bitcast (void(i8**)* @c to i8*), i8** %ptr\n"
+ " ret void\n"
+ "}\n"
+ "define void @b(i8** %ptr) {\n"
+ "entry:\n"
+ " store i8* bitcast (void(i8**)* @a to i8*), i8** %ptr\n"
+ " call void @c(i8** %ptr)\n"
+ " ret void\n"
+ "}\n"
+ "define void @c(i8** %ptr) {\n"
+ "entry:\n"
+ " call void @a(i8** %ptr)\n"
+ " store i8* bitcast (void(i8**)* @b to i8*), i8** %ptr\n"
+ " ret void\n"
+ "}\n");
+ LazyCallGraph CG(*M);
+
+ // Force the graph to be fully expanded.
+ auto I = CG.postorder_ref_scc_begin(), E = CG.postorder_ref_scc_end();
+ LazyCallGraph::RefSCC &RC = *I;
+ EXPECT_EQ(E, std::next(I));
+
+ LazyCallGraph::SCC &C = *RC.begin();
+ EXPECT_EQ(RC.end(), std::next(RC.begin()));
+
+ LazyCallGraph::Node &AN = *CG.lookup(lookupFunction(*M, "a"));
+ LazyCallGraph::Node &BN = *CG.lookup(lookupFunction(*M, "b"));
+ LazyCallGraph::Node &CN = *CG.lookup(lookupFunction(*M, "c"));
+ EXPECT_EQ(&RC, CG.lookupRefSCC(AN));
+ EXPECT_EQ(&RC, CG.lookupRefSCC(BN));
+ EXPECT_EQ(&RC, CG.lookupRefSCC(CN));
+ EXPECT_EQ(&C, CG.lookupSCC(AN));
+ EXPECT_EQ(&C, CG.lookupSCC(BN));
+ EXPECT_EQ(&C, CG.lookupSCC(CN));
+
+ // Remove the edge from a -> c which doesn't change anything.
+ SmallVector<LazyCallGraph::RefSCC *, 1> NewRCs =
+ RC.removeInternalRefEdge(AN, CN);
+ EXPECT_EQ(0u, NewRCs.size());
+ EXPECT_EQ(&RC, CG.lookupRefSCC(AN));
+ EXPECT_EQ(&RC, CG.lookupRefSCC(BN));
+ EXPECT_EQ(&RC, CG.lookupRefSCC(CN));
+ EXPECT_EQ(&C, CG.lookupSCC(AN));
+ EXPECT_EQ(&C, CG.lookupSCC(BN));
+ EXPECT_EQ(&C, CG.lookupSCC(CN));
+ auto J = CG.postorder_ref_scc_begin();
+ EXPECT_EQ(I, J);
+ EXPECT_EQ(&RC, &*J);
+ EXPECT_EQ(E, std::next(J));
+
+ // Remove the edge from b -> a and c -> b; again this doesn't change
+ // anything.
+ NewRCs = RC.removeInternalRefEdge(BN, AN);
+ NewRCs = RC.removeInternalRefEdge(CN, BN);
+ EXPECT_EQ(0u, NewRCs.size());
+ EXPECT_EQ(&RC, CG.lookupRefSCC(AN));
+ EXPECT_EQ(&RC, CG.lookupRefSCC(BN));
+ EXPECT_EQ(&RC, CG.lookupRefSCC(CN));
+ EXPECT_EQ(&C, CG.lookupSCC(AN));
+ EXPECT_EQ(&C, CG.lookupSCC(BN));
+ EXPECT_EQ(&C, CG.lookupSCC(CN));
+ J = CG.postorder_ref_scc_begin();
+ EXPECT_EQ(I, J);
+ EXPECT_EQ(&RC, &*J);
+ EXPECT_EQ(E, std::next(J));
}
TEST(LazyCallGraphTest, InternalCallEdgeToRef) {
@@ -918,54 +1714,59 @@ TEST(LazyCallGraphTest, InternalCallEdgeToRef) {
EXPECT_EQ(CG.postorder_ref_scc_end(), I);
EXPECT_EQ(1, RC.size());
- LazyCallGraph::SCC &CallC = *RC.begin();
+ LazyCallGraph::SCC &AC = *RC.begin();
- LazyCallGraph::Node &A = *CG.lookup(lookupFunction(*M, "a"));
- LazyCallGraph::Node &B = *CG.lookup(lookupFunction(*M, "b"));
- LazyCallGraph::Node &C = *CG.lookup(lookupFunction(*M, "c"));
- EXPECT_EQ(&CallC, CG.lookupSCC(A));
- EXPECT_EQ(&CallC, CG.lookupSCC(B));
- EXPECT_EQ(&CallC, CG.lookupSCC(C));
+ LazyCallGraph::Node &AN = *CG.lookup(lookupFunction(*M, "a"));
+ LazyCallGraph::Node &BN = *CG.lookup(lookupFunction(*M, "b"));
+ LazyCallGraph::Node &CN = *CG.lookup(lookupFunction(*M, "c"));
+ EXPECT_EQ(&AC, CG.lookupSCC(AN));
+ EXPECT_EQ(&AC, CG.lookupSCC(BN));
+ EXPECT_EQ(&AC, CG.lookupSCC(CN));
// Remove the call edge from b -> a to a ref edge, which should leave the
// 3 functions still in a single connected component because of a -> b ->
// c -> a.
- RC.switchInternalEdgeToRef(B, A);
+ auto NewCs = RC.switchInternalEdgeToRef(BN, AN);
+ EXPECT_EQ(NewCs.begin(), NewCs.end());
EXPECT_EQ(1, RC.size());
- EXPECT_EQ(&CallC, CG.lookupSCC(A));
- EXPECT_EQ(&CallC, CG.lookupSCC(B));
- EXPECT_EQ(&CallC, CG.lookupSCC(C));
+ EXPECT_EQ(&AC, CG.lookupSCC(AN));
+ EXPECT_EQ(&AC, CG.lookupSCC(BN));
+ EXPECT_EQ(&AC, CG.lookupSCC(CN));
// Remove the edge from c -> a, which should leave 'a' in the original SCC
// and form a new SCC for 'b' and 'c'.
- RC.switchInternalEdgeToRef(C, A);
+ NewCs = RC.switchInternalEdgeToRef(CN, AN);
+ EXPECT_EQ(1, std::distance(NewCs.begin(), NewCs.end()));
EXPECT_EQ(2, RC.size());
- EXPECT_EQ(&CallC, CG.lookupSCC(A));
- LazyCallGraph::SCC &BCallC = *CG.lookupSCC(B);
- EXPECT_NE(&BCallC, &CallC);
- EXPECT_EQ(&BCallC, CG.lookupSCC(C));
- auto J = RC.find(CallC);
- EXPECT_EQ(&CallC, &*J);
+ EXPECT_EQ(&AC, CG.lookupSCC(AN));
+ LazyCallGraph::SCC &BC = *CG.lookupSCC(BN);
+ EXPECT_NE(&BC, &AC);
+ EXPECT_EQ(&BC, CG.lookupSCC(CN));
+ auto J = RC.find(AC);
+ EXPECT_EQ(&AC, &*J);
--J;
- EXPECT_EQ(&BCallC, &*J);
+ EXPECT_EQ(&BC, &*J);
EXPECT_EQ(RC.begin(), J);
+ EXPECT_EQ(J, NewCs.begin());
// Remove the edge from c -> b, which should leave 'b' in the original SCC
// and form a new SCC for 'c'. It shouldn't change 'a's SCC.
- RC.switchInternalEdgeToRef(C, B);
+ NewCs = RC.switchInternalEdgeToRef(CN, BN);
+ EXPECT_EQ(1, std::distance(NewCs.begin(), NewCs.end()));
EXPECT_EQ(3, RC.size());
- EXPECT_EQ(&CallC, CG.lookupSCC(A));
- EXPECT_EQ(&BCallC, CG.lookupSCC(B));
- LazyCallGraph::SCC &CCallC = *CG.lookupSCC(C);
- EXPECT_NE(&CCallC, &CallC);
- EXPECT_NE(&CCallC, &BCallC);
- J = RC.find(CallC);
- EXPECT_EQ(&CallC, &*J);
+ EXPECT_EQ(&AC, CG.lookupSCC(AN));
+ EXPECT_EQ(&BC, CG.lookupSCC(BN));
+ LazyCallGraph::SCC &CC = *CG.lookupSCC(CN);
+ EXPECT_NE(&CC, &AC);
+ EXPECT_NE(&CC, &BC);
+ J = RC.find(AC);
+ EXPECT_EQ(&AC, &*J);
--J;
- EXPECT_EQ(&BCallC, &*J);
+ EXPECT_EQ(&BC, &*J);
--J;
- EXPECT_EQ(&CCallC, &*J);
+ EXPECT_EQ(&CC, &*J);
EXPECT_EQ(RC.begin(), J);
+ EXPECT_EQ(J, NewCs.begin());
}
TEST(LazyCallGraphTest, InternalRefEdgeToCall) {
@@ -1135,11 +1936,11 @@ TEST(LazyCallGraphTest, InternalRefEdgeToCallNoCycleInterleaved) {
// Several call edges are initially present to force a particual post-order.
// Remove them now, leaving an interleaved post-order pattern.
- RC.switchInternalEdgeToRef(B3, C3);
- RC.switchInternalEdgeToRef(C2, B3);
- RC.switchInternalEdgeToRef(B2, C2);
- RC.switchInternalEdgeToRef(C1, B2);
- RC.switchInternalEdgeToRef(B1, C1);
+ RC.switchTrivialInternalEdgeToRef(B3, C3);
+ RC.switchTrivialInternalEdgeToRef(C2, B3);
+ RC.switchTrivialInternalEdgeToRef(B2, C2);
+ RC.switchTrivialInternalEdgeToRef(C1, B2);
+ RC.switchTrivialInternalEdgeToRef(B1, C1);
// Check the initial post-order. We ensure this order with the extra edges
// that are nuked above.
@@ -1262,8 +2063,8 @@ TEST(LazyCallGraphTest, InternalRefEdgeToCallBothPartitionAndMerge) {
LazyCallGraph::SCC &GC = *CG.lookupSCC(G);
// Remove the extra edges that were used to force a particular post-order.
- RC.switchInternalEdgeToRef(C, D);
- RC.switchInternalEdgeToRef(D, E);
+ RC.switchTrivialInternalEdgeToRef(C, D);
+ RC.switchTrivialInternalEdgeToRef(D, E);
// Check the initial post-order. We ensure this order with the extra edges
// that are nuked above.
@@ -1302,4 +2103,35 @@ TEST(LazyCallGraphTest, InternalRefEdgeToCallBothPartitionAndMerge) {
EXPECT_EQ(&AC, &RC[4]);
}
+// Test for IR containing constants using blockaddress constant expressions.
+// These are truly unique constructs: constant expressions with non-constant
+// operands.
+TEST(LazyCallGraphTest, HandleBlockAddress) {
+ LLVMContext Context;
+ std::unique_ptr<Module> M =
+ parseAssembly(Context, "define void @f() {\n"
+ "entry:\n"
+ " ret void\n"
+ "bb:\n"
+ " unreachable\n"
+ "}\n"
+ "define void @g(i8** %ptr) {\n"
+ "entry:\n"
+ " store i8* blockaddress(@f, %bb), i8** %ptr\n"
+ " ret void\n"
+ "}\n");
+ LazyCallGraph CG(*M);
+
+ auto I = CG.postorder_ref_scc_begin();
+ LazyCallGraph::RefSCC &FRC = *I++;
+ LazyCallGraph::RefSCC &GRC = *I++;
+ EXPECT_EQ(CG.postorder_ref_scc_end(), I);
+
+ LazyCallGraph::Node &F = *CG.lookup(lookupFunction(*M, "f"));
+ LazyCallGraph::Node &G = *CG.lookup(lookupFunction(*M, "g"));
+ EXPECT_EQ(&FRC, CG.lookupRefSCC(F));
+ EXPECT_EQ(&GRC, CG.lookupRefSCC(G));
+ EXPECT_TRUE(GRC.isParentOf(FRC));
+}
+
}
diff --git a/unittests/Analysis/LoopPassManagerTest.cpp b/unittests/Analysis/LoopPassManagerTest.cpp
index 5858e174aabb..092e4bf91133 100644
--- a/unittests/Analysis/LoopPassManagerTest.cpp
+++ b/unittests/Analysis/LoopPassManagerTest.cpp
@@ -7,8 +7,11 @@
//
//===----------------------------------------------------------------------===//
-#include "gtest/gtest.h"
+#include "llvm/Analysis/AliasAnalysis.h"
+#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/LoopPassManager.h"
+#include "llvm/Analysis/ScalarEvolution.h"
+#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/AsmParser/Parser.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
@@ -16,14 +19,15 @@
#include "llvm/IR/Module.h"
#include "llvm/IR/PassManager.h"
#include "llvm/Support/SourceMgr.h"
+#include "gtest/gtest.h"
using namespace llvm;
namespace {
-class TestLoopAnalysis {
- /// \brief Private static data to provide unique ID.
- static char PassID;
+class TestLoopAnalysis : public AnalysisInfoMixin<TestLoopAnalysis> {
+ friend AnalysisInfoMixin<TestLoopAnalysis>;
+ static AnalysisKey Key;
int &Runs;
@@ -33,16 +37,10 @@ public:
int BlockCount;
};
- /// \brief Returns an opaque, unique ID for this pass type.
- static void *ID() { return (void *)&PassID; }
-
- /// \brief Returns the name of the analysis.
- static StringRef name() { return "TestLoopAnalysis"; }
-
TestLoopAnalysis(int &Runs) : Runs(Runs) {}
/// \brief Run the analysis pass over the loop and return a result.
- Result run(Loop &L, AnalysisManager<Loop> &AM) {
+ Result run(Loop &L, LoopAnalysisManager &AM) {
++Runs;
int Count = 0;
@@ -52,7 +50,7 @@ public:
}
};
-char TestLoopAnalysis::PassID;
+AnalysisKey TestLoopAnalysis::Key;
class TestLoopPass {
std::vector<StringRef> &VisitedLoops;
@@ -65,7 +63,7 @@ public:
: VisitedLoops(VisitedLoops), AnalyzedBlockCount(AnalyzedBlockCount),
OnlyUseCachedResults(OnlyUseCachedResults) {}
- PreservedAnalyses run(Loop &L, AnalysisManager<Loop> &AM) {
+ PreservedAnalyses run(Loop &L, LoopAnalysisManager &AM) {
VisitedLoops.push_back(L.getName());
if (OnlyUseCachedResults) {
@@ -91,7 +89,7 @@ class TestLoopInvalidatingPass {
public:
TestLoopInvalidatingPass(StringRef LoopName) : Name(LoopName) {}
- PreservedAnalyses run(Loop &L, AnalysisManager<Loop> &AM) {
+ PreservedAnalyses run(Loop &L, LoopAnalysisManager &AM) {
return L.getName() == Name ? getLoopPassPreservedAnalyses()
: PreservedAnalyses::all();
}
@@ -152,6 +150,12 @@ TEST_F(LoopPassManagerTest, Basic) {
// We need DominatorTreeAnalysis for LoopAnalysis.
FAM.registerPass([&] { return DominatorTreeAnalysis(); });
FAM.registerPass([&] { return LoopAnalysis(); });
+ // We also allow loop passes to assume a set of other analyses and so need
+ // those.
+ FAM.registerPass([&] { return AAManager(); });
+ FAM.registerPass([&] { return TargetLibraryAnalysis(); });
+ FAM.registerPass([&] { return ScalarEvolutionAnalysis(); });
+ FAM.registerPass([&] { return AssumptionAnalysis(); });
FAM.registerPass([&] { return LoopAnalysisManagerFunctionProxy(LAM); });
LAM.registerPass([&] { return FunctionAnalysisManagerLoopProxy(FAM); });
diff --git a/unittests/Analysis/MemoryBuiltinsTest.cpp b/unittests/Analysis/MemoryBuiltinsTest.cpp
new file mode 100644
index 000000000000..898ebeece4fb
--- /dev/null
+++ b/unittests/Analysis/MemoryBuiltinsTest.cpp
@@ -0,0 +1,50 @@
+//===- MemoryBuiltinsTest.cpp - Tests for utilities in MemoryBuiltins.h ---===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Analysis/MemoryBuiltins.h"
+#include "llvm/IR/Attributes.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+// allocsize should not imply that a function is a traditional allocation
+// function (e.g. that can be optimized out/...); it just tells us how many
+// bytes exist at the pointer handed back by the function.
+TEST(AllocSize, AllocationBuiltinsTest) {
+ LLVMContext Context;
+ Module M("", Context);
+ IntegerType *ArgTy = Type::getInt32Ty(Context);
+
+ Function *AllocSizeFn = Function::Create(
+ FunctionType::get(Type::getInt8PtrTy(Context), {ArgTy}, false),
+ GlobalValue::ExternalLinkage, "F", &M);
+
+ AllocSizeFn->addFnAttr(Attribute::getWithAllocSizeArgs(Context, 1, None));
+
+ // 100 is arbitrary.
+ std::unique_ptr<CallInst> Caller(
+ CallInst::Create(AllocSizeFn, {ConstantInt::get(ArgTy, 100)}));
+
+ const TargetLibraryInfo *TLI = nullptr;
+ EXPECT_FALSE(isNoAliasFn(Caller.get(), TLI));
+ EXPECT_FALSE(isMallocLikeFn(Caller.get(), TLI));
+ EXPECT_FALSE(isCallocLikeFn(Caller.get(), TLI));
+ EXPECT_FALSE(isAllocLikeFn(Caller.get(), TLI));
+
+ // FIXME: We might be able to treat allocsize functions as general allocation
+ // functions. For the moment, being conservative seems better (and we'd have
+ // to plumb stuff around `isNoAliasFn`).
+ EXPECT_FALSE(isAllocationFn(Caller.get(), TLI));
+}
+}
diff --git a/unittests/Analysis/MixedTBAATest.cpp b/unittests/Analysis/MixedTBAATest.cpp
deleted file mode 100644
index d70324f2c6ab..000000000000
--- a/unittests/Analysis/MixedTBAATest.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-//===--- MixedTBAATest.cpp - Mixed TBAA 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/TypeBasedAliasAnalysis.h"
-#include "llvm/Analysis/AliasAnalysisEvaluator.h"
-#include "llvm/Analysis/Passes.h"
-#include "llvm/IR/Constants.h"
-#include "llvm/IR/Instructions.h"
-#include "llvm/IR/LLVMContext.h"
-#include "llvm/IR/MDBuilder.h"
-#include "llvm/IR/Module.h"
-#include "llvm/IR/LegacyPassManager.h"
-#include "llvm/Support/CommandLine.h"
-#include "gtest/gtest.h"
-
-namespace llvm {
-namespace {
-
-class MixedTBAATest : public testing::Test {
-protected:
- MixedTBAATest() : M("MixedTBAATest", C), MD(C) {}
-
- LLVMContext C;
- Module M;
- MDBuilder MD;
- legacy::PassManager PM;
-};
-
-TEST_F(MixedTBAATest, MixedTBAA) {
- // Setup function.
- FunctionType *FTy = FunctionType::get(Type::getVoidTy(C),
- std::vector<Type *>(), false);
- auto *F = cast<Function>(M.getOrInsertFunction("f", FTy));
- auto *BB = BasicBlock::Create(C, "entry", F);
- auto IntType = Type::getInt32Ty(C);
- auto PtrType = Type::getInt32PtrTy(C);
- auto *Value = ConstantInt::get(IntType, 42);
- auto *Addr = ConstantPointerNull::get(PtrType);
-
- auto *Store1 = new StoreInst(Value, Addr, BB);
- auto *Store2 = new StoreInst(Value, Addr, BB);
- ReturnInst::Create(C, nullptr, BB);
-
- // New TBAA metadata
- {
- auto RootMD = MD.createTBAARoot("Simple C/C++ TBAA");
- auto MD1 = MD.createTBAAScalarTypeNode("omnipotent char", RootMD);
- auto MD2 = MD.createTBAAScalarTypeNode("int", MD1);
- auto MD3 = MD.createTBAAStructTagNode(MD2, MD2, 0);
- Store2->setMetadata(LLVMContext::MD_tbaa, MD3);
- }
-
- // Old TBAA metadata
- {
- auto RootMD = MD.createTBAARoot("Simple C/C++ TBAA");
- auto MD1 = MD.createTBAANode("omnipotent char", RootMD);
- auto MD2 = MD.createTBAANode("int", MD1);
- Store1->setMetadata(LLVMContext::MD_tbaa, MD2);
- }
-
- // Run the TBAA eval pass on a mixture of path-aware and non-path-aware TBAA.
- // The order of the metadata (path-aware vs non-path-aware) is important,
- // because the AA eval pass only runs one test per store-pair.
- const char* args[] = { "MixedTBAATest", "-evaluate-aa-metadata" };
- cl::ParseCommandLineOptions(sizeof(args) / sizeof(const char*), args);
- PM.add(createTypeBasedAAWrapperPass());
- PM.add(createAAEvalPass());
- PM.run(M);
-}
-
-} // end anonymous namspace
-} // end llvm namespace
-
diff --git a/unittests/Analysis/ScalarEvolutionTest.cpp b/unittests/Analysis/ScalarEvolutionTest.cpp
index c4cd74f01c72..752cc8128248 100644
--- a/unittests/Analysis/ScalarEvolutionTest.cpp
+++ b/unittests/Analysis/ScalarEvolutionTest.cpp
@@ -7,18 +7,23 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/Analysis/ScalarEvolutionExpander.h"
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/AsmParser/Parser.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/GlobalVariable.h"
+#include "llvm/IR/InstIterator.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/LegacyPassManager.h"
+#include "llvm/IR/Verifier.h"
+#include "llvm/Support/SourceMgr.h"
#include "gtest/gtest.h"
namespace llvm {
@@ -45,6 +50,15 @@ protected:
LI.reset(new LoopInfo(*DT));
return ScalarEvolution(F, TLI, *AC, *DT, *LI);
}
+
+ void runWithFunctionAndSE(
+ Module &M, StringRef FuncName,
+ function_ref<void(Function &F, 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(ScalarEvolutionsTest, SCEVUnknownRAUW) {
@@ -264,5 +278,259 @@ TEST_F(ScalarEvolutionsTest, SimplifiedPHI) {
EXPECT_EQ(S1, S2);
}
+TEST_F(ScalarEvolutionsTest, ExpandPtrTypeSCEV) {
+ // It is to test the fix for PR30213. It exercises the branch in scev
+ // expansion when the value in ValueOffsetPair is a ptr and the offset
+ // is not divisible by the elem type size of value.
+ auto *I8Ty = Type::getInt8Ty(Context);
+ auto *I8PtrTy = Type::getInt8PtrTy(Context);
+ auto *I32Ty = Type::getInt32Ty(Context);
+ auto *I32PtrTy = Type::getInt32PtrTy(Context);
+ FunctionType *FTy =
+ FunctionType::get(Type::getVoidTy(Context), std::vector<Type *>(), false);
+ Function *F = cast<Function>(M.getOrInsertFunction("f", FTy));
+ BasicBlock *EntryBB = BasicBlock::Create(Context, "entry", F);
+ BasicBlock *LoopBB = BasicBlock::Create(Context, "loop", F);
+ BasicBlock *ExitBB = BasicBlock::Create(Context, "exit", F);
+ BranchInst::Create(LoopBB, EntryBB);
+ ReturnInst::Create(Context, nullptr, ExitBB);
+
+ // loop: ; preds = %loop, %entry
+ // %alloca = alloca i32
+ // %gep0 = getelementptr i32, i32* %alloca, i32 1
+ // %bitcast1 = bitcast i32* %gep0 to i8*
+ // %gep1 = getelementptr i8, i8* %bitcast1, i32 1
+ // %gep2 = getelementptr i8, i8* undef, i32 1
+ // %cmp = icmp ult i8* undef, %bitcast1
+ // %select = select i1 %cmp, i8* %gep1, i8* %gep2
+ // %bitcast2 = bitcast i8* %select to i32*
+ // br i1 undef, label %loop, label %exit
+
+ BranchInst *Br = BranchInst::Create(
+ LoopBB, ExitBB, UndefValue::get(Type::getInt1Ty(Context)), LoopBB);
+ AllocaInst *Alloca = new AllocaInst(I32Ty, "alloca", Br);
+ ConstantInt *Ci32 = ConstantInt::get(Context, APInt(32, 1));
+ GetElementPtrInst *Gep0 =
+ GetElementPtrInst::Create(I32Ty, Alloca, Ci32, "gep0", Br);
+ CastInst *CastA =
+ CastInst::CreateBitOrPointerCast(Gep0, I8PtrTy, "bitcast1", Br);
+ GetElementPtrInst *Gep1 =
+ GetElementPtrInst::Create(I8Ty, CastA, Ci32, "gep1", Br);
+ GetElementPtrInst *Gep2 = GetElementPtrInst::Create(
+ I8Ty, UndefValue::get(I8PtrTy), Ci32, "gep2", Br);
+ CmpInst *Cmp = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_ULT,
+ UndefValue::get(I8PtrTy), CastA, "cmp", Br);
+ SelectInst *Sel = SelectInst::Create(Cmp, Gep1, Gep2, "select", Br);
+ CastInst *CastB =
+ CastInst::CreateBitOrPointerCast(Sel, I32PtrTy, "bitcast2", Br);
+
+ ScalarEvolution SE = buildSE(*F);
+ auto *S = SE.getSCEV(CastB);
+ SCEVExpander Exp(SE, M.getDataLayout(), "expander");
+ Value *V =
+ Exp.expandCodeFor(cast<SCEVAddExpr>(S)->getOperand(1), nullptr, Br);
+
+ // Expect the expansion code contains:
+ // %0 = bitcast i32* %bitcast2 to i8*
+ // %uglygep = getelementptr i8, i8* %0, i64 -1
+ // %1 = bitcast i8* %uglygep to i32*
+ EXPECT_TRUE(isa<BitCastInst>(V));
+ Instruction *Gep = cast<Instruction>(V)->getPrevNode();
+ EXPECT_TRUE(isa<GetElementPtrInst>(Gep));
+ EXPECT_TRUE(isa<ConstantInt>(Gep->getOperand(1)));
+ EXPECT_EQ(cast<ConstantInt>(Gep->getOperand(1))->getSExtValue(), -1);
+ EXPECT_TRUE(isa<BitCastInst>(Gep->getPrevNode()));
+}
+
+static Instruction *getInstructionByName(Function &F, StringRef Name) {
+ for (auto &I : instructions(F))
+ if (I.getName() == Name)
+ return &I;
+ llvm_unreachable("Expected to find instruction!");
+}
+
+TEST_F(ScalarEvolutionsTest, CommutativeExprOperandOrder) {
+ 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: "
+ " %entrycond = icmp sgt i32 %n, 0 "
+ " br i1 %entrycond, label %loop.ph, label %for.end "
+ " "
+ "loop.ph: "
+ " %a = load i32, i32* %A, align 4 "
+ " %b = load i32, i32* %B, align 4 "
+ " %mul = mul nsw i32 %b, %a "
+ " %iv0.init = getelementptr inbounds i8, i8* %arr, i32 %mul "
+ " br label %loop "
+ " "
+ "loop: "
+ " %iv0 = phi i8* [ %iv0.inc, %loop ], [ %iv0.init, %loop.ph ] "
+ " %iv1 = phi i32 [ %iv1.inc, %loop ], [ 0, %loop.ph ] "
+ " %conv = trunc i32 %iv1 to i8 "
+ " store i8 %conv, i8* %iv0, align 1 "
+ " %iv0.inc = getelementptr inbounds i8, i8* %iv0, i32 %b "
+ " %iv1.inc = add nuw nsw i32 %iv1, 1 "
+ " %exitcond = icmp eq i32 %iv1.inc, %n "
+ " br i1 %exitcond, label %for.end.loopexit, label %loop "
+ " "
+ "for.end.loopexit: "
+ " br label %for.end "
+ " "
+ "for.end: "
+ " ret void "
+ "} "
+ " "
+ "define void @f_2(i32* %X, i32* %Y, i32* %Z) { "
+ " %x = load i32, i32* %X "
+ " %y = load i32, i32* %Y "
+ " %z = load i32, i32* %Z "
+ " ret void "
+ "} "
+ " "
+ "define void @f_3() { "
+ " %x = load i32, i32* @var_0"
+ " %y = load i32, i32* @var_1"
+ " %z = load i32, i32* @var_2"
+ " ret void"
+ "} "
+ " "
+ "define void @f_4(i32 %a, i32 %b, i32 %c) { "
+ " %x = call i32 @unknown(i32 %a, i32 %b, i32 %c)"
+ " %y = call i32 @unknown(i32 %b, i32 %c, i32 %a)"
+ " %z = call i32 @unknown(i32 %c, i32 %a, i32 %b)"
+ " ret void"
+ "} "
+ ,
+ Err, C);
+
+ assert(M && "Could not parse module?");
+ assert(!verifyModule(*M) && "Must have been well formed!");
+
+ runWithFunctionAndSE(*M, "f_1", [&](Function &F, ScalarEvolution &SE) {
+ auto *IV0 = getInstructionByName(F, "iv0");
+ auto *IV0Inc = getInstructionByName(F, "iv0.inc");
+
+ auto *FirstExprForIV0 = SE.getSCEV(IV0);
+ auto *FirstExprForIV0Inc = SE.getSCEV(IV0Inc);
+ auto *SecondExprForIV0 = SE.getSCEV(IV0);
+
+ EXPECT_TRUE(isa<SCEVAddRecExpr>(FirstExprForIV0));
+ EXPECT_TRUE(isa<SCEVAddRecExpr>(FirstExprForIV0Inc));
+ EXPECT_TRUE(isa<SCEVAddRecExpr>(SecondExprForIV0));
+ });
+
+ auto CheckCommutativeMulExprs = [&](ScalarEvolution &SE, const SCEV *A,
+ const SCEV *B, const SCEV *C) {
+ EXPECT_EQ(SE.getMulExpr(A, B), SE.getMulExpr(B, A));
+ EXPECT_EQ(SE.getMulExpr(B, C), SE.getMulExpr(C, B));
+ EXPECT_EQ(SE.getMulExpr(A, C), SE.getMulExpr(C, A));
+
+ SmallVector<const SCEV *, 3> Ops0 = {A, B, C};
+ SmallVector<const SCEV *, 3> Ops1 = {A, C, B};
+ SmallVector<const SCEV *, 3> Ops2 = {B, A, C};
+ SmallVector<const SCEV *, 3> Ops3 = {B, C, A};
+ SmallVector<const SCEV *, 3> Ops4 = {C, B, A};
+ SmallVector<const SCEV *, 3> Ops5 = {C, A, B};
+
+ auto *Mul0 = SE.getMulExpr(Ops0);
+ auto *Mul1 = SE.getMulExpr(Ops1);
+ auto *Mul2 = SE.getMulExpr(Ops2);
+ auto *Mul3 = SE.getMulExpr(Ops3);
+ auto *Mul4 = SE.getMulExpr(Ops4);
+ auto *Mul5 = SE.getMulExpr(Ops5);
+
+ EXPECT_EQ(Mul0, Mul1) << "Expected " << *Mul0 << " == " << *Mul1;
+ EXPECT_EQ(Mul1, Mul2) << "Expected " << *Mul1 << " == " << *Mul2;
+ EXPECT_EQ(Mul2, Mul3) << "Expected " << *Mul2 << " == " << *Mul3;
+ EXPECT_EQ(Mul3, Mul4) << "Expected " << *Mul3 << " == " << *Mul4;
+ EXPECT_EQ(Mul4, Mul5) << "Expected " << *Mul4 << " == " << *Mul5;
+ };
+
+ 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")));
+ });
+}
+
+TEST_F(ScalarEvolutionsTest, SCEVCompareComplexity) {
+ FunctionType *FTy =
+ FunctionType::get(Type::getVoidTy(Context), std::vector<Type *>(), false);
+ Function *F = cast<Function>(M.getOrInsertFunction("f", FTy));
+ BasicBlock *EntryBB = BasicBlock::Create(Context, "entry", F);
+ BasicBlock *LoopBB = BasicBlock::Create(Context, "bb1", F);
+ BranchInst::Create(LoopBB, EntryBB);
+
+ auto *Ty = Type::getInt32Ty(Context);
+ SmallVector<Instruction*, 8> Muls(8), Acc(8), NextAcc(8);
+
+ Acc[0] = PHINode::Create(Ty, 2, "", LoopBB);
+ Acc[1] = PHINode::Create(Ty, 2, "", LoopBB);
+ Acc[2] = PHINode::Create(Ty, 2, "", LoopBB);
+ Acc[3] = PHINode::Create(Ty, 2, "", LoopBB);
+ Acc[4] = PHINode::Create(Ty, 2, "", LoopBB);
+ Acc[5] = PHINode::Create(Ty, 2, "", LoopBB);
+ Acc[6] = PHINode::Create(Ty, 2, "", LoopBB);
+ Acc[7] = PHINode::Create(Ty, 2, "", LoopBB);
+
+ for (int i = 0; i < 20; i++) {
+ Muls[0] = BinaryOperator::CreateMul(Acc[0], Acc[0], "", LoopBB);
+ NextAcc[0] = BinaryOperator::CreateAdd(Muls[0], Acc[4], "", LoopBB);
+ Muls[1] = BinaryOperator::CreateMul(Acc[1], Acc[1], "", LoopBB);
+ NextAcc[1] = BinaryOperator::CreateAdd(Muls[1], Acc[5], "", LoopBB);
+ Muls[2] = BinaryOperator::CreateMul(Acc[2], Acc[2], "", LoopBB);
+ NextAcc[2] = BinaryOperator::CreateAdd(Muls[2], Acc[6], "", LoopBB);
+ Muls[3] = BinaryOperator::CreateMul(Acc[3], Acc[3], "", LoopBB);
+ NextAcc[3] = BinaryOperator::CreateAdd(Muls[3], Acc[7], "", LoopBB);
+
+ Muls[4] = BinaryOperator::CreateMul(Acc[4], Acc[4], "", LoopBB);
+ NextAcc[4] = BinaryOperator::CreateAdd(Muls[4], Acc[0], "", LoopBB);
+ Muls[5] = BinaryOperator::CreateMul(Acc[5], Acc[5], "", LoopBB);
+ NextAcc[5] = BinaryOperator::CreateAdd(Muls[5], Acc[1], "", LoopBB);
+ Muls[6] = BinaryOperator::CreateMul(Acc[6], Acc[6], "", LoopBB);
+ NextAcc[6] = BinaryOperator::CreateAdd(Muls[6], Acc[2], "", LoopBB);
+ Muls[7] = BinaryOperator::CreateMul(Acc[7], Acc[7], "", LoopBB);
+ NextAcc[7] = BinaryOperator::CreateAdd(Muls[7], Acc[3], "", LoopBB);
+ Acc = NextAcc;
+ }
+
+ auto II = LoopBB->begin();
+ for (int i = 0; i < 8; i++) {
+ PHINode *Phi = cast<PHINode>(&*II++);
+ Phi->addIncoming(Acc[i], LoopBB);
+ Phi->addIncoming(UndefValue::get(Ty), EntryBB);
+ }
+
+ BasicBlock *ExitBB = BasicBlock::Create(Context, "bb2", F);
+ BranchInst::Create(LoopBB, ExitBB, UndefValue::get(Type::getInt1Ty(Context)),
+ LoopBB);
+
+ Acc[0] = BinaryOperator::CreateAdd(Acc[0], Acc[1], "", ExitBB);
+ Acc[1] = BinaryOperator::CreateAdd(Acc[2], Acc[3], "", ExitBB);
+ Acc[2] = BinaryOperator::CreateAdd(Acc[4], Acc[5], "", ExitBB);
+ Acc[3] = BinaryOperator::CreateAdd(Acc[6], Acc[7], "", ExitBB);
+ Acc[0] = BinaryOperator::CreateAdd(Acc[0], Acc[1], "", ExitBB);
+ Acc[1] = BinaryOperator::CreateAdd(Acc[2], Acc[3], "", ExitBB);
+ Acc[0] = BinaryOperator::CreateAdd(Acc[0], Acc[1], "", ExitBB);
+
+ ReturnInst::Create(Context, nullptr, ExitBB);
+
+ ScalarEvolution SE = buildSE(*F);
+
+ EXPECT_NE(nullptr, SE.getSCEV(Acc[0]));
+}
+
} // end anonymous namespace
} // end namespace llvm
diff --git a/unittests/Analysis/TBAATest.cpp b/unittests/Analysis/TBAATest.cpp
new file mode 100644
index 000000000000..3a1d2f43563e
--- /dev/null
+++ b/unittests/Analysis/TBAATest.cpp
@@ -0,0 +1,91 @@
+//===--- TBAATest.cpp - Mixed TBAA 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/AliasAnalysisEvaluator.h"
+#include "llvm/Analysis/Passes.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/MDBuilder.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/LegacyPassManager.h"
+#include "llvm/IR/Verifier.h"
+#include "llvm/Support/CommandLine.h"
+#include "gtest/gtest.h"
+
+namespace llvm {
+namespace {
+
+class TBAATest : public testing::Test {
+protected:
+ TBAATest() : M("TBAATest", C), MD(C) {}
+
+ LLVMContext C;
+ Module M;
+ MDBuilder MD;
+};
+
+static StoreInst *getFunctionWithSingleStore(Module *M, StringRef Name) {
+ auto &C = M->getContext();
+ FunctionType *FTy = FunctionType::get(Type::getVoidTy(C), {});
+ auto *F = cast<Function>(M->getOrInsertFunction(Name, FTy));
+ auto *BB = BasicBlock::Create(C, "entry", F);
+ auto *IntType = Type::getInt32Ty(C);
+ auto *PtrType = Type::getInt32PtrTy(C);
+ auto *SI = new StoreInst(ConstantInt::get(IntType, 42),
+ ConstantPointerNull::get(PtrType), BB);
+ ReturnInst::Create(C, nullptr, BB);
+
+ return SI;
+}
+
+TEST_F(TBAATest, checkVerifierBehaviorForOldTBAA) {
+ auto *SI = getFunctionWithSingleStore(&M, "f1");
+ auto *F = SI->getFunction();
+
+ // C++ unit test case to avoid going through the auto upgrade logic.
+ auto *RootMD = MD.createTBAARoot("Simple C/C++ TBAA");
+ auto *MD1 = MD.createTBAANode("omnipotent char", RootMD);
+ auto *MD2 = MD.createTBAANode("int", MD1);
+ SI->setMetadata(LLVMContext::MD_tbaa, MD2);
+
+ SmallVector<char, 0> ErrorMsg;
+ raw_svector_ostream Outs(ErrorMsg);
+
+ StringRef ExpectedFailureMsg(
+ "Old-style TBAA is no longer allowed, use struct-path TBAA instead");
+
+ EXPECT_TRUE(verifyFunction(*F, &Outs));
+ EXPECT_TRUE(StringRef(ErrorMsg.begin(), ErrorMsg.size())
+ .startswith(ExpectedFailureMsg));
+}
+
+TEST_F(TBAATest, checkTBAAMerging) {
+ auto *SI = getFunctionWithSingleStore(&M, "f2");
+ auto *F = SI->getFunction();
+
+ auto *RootMD = MD.createTBAARoot("tbaa-root");
+ auto *MD1 = MD.createTBAANode("scalar-a", RootMD);
+ auto *StructTag1 = MD.createTBAAStructTagNode(MD1, MD1, 0);
+ auto *MD2 = MD.createTBAANode("scalar-b", RootMD);
+ auto *StructTag2 = MD.createTBAAStructTagNode(MD2, MD2, 0);
+
+ auto *GenericMD = MDNode::getMostGenericTBAA(StructTag1, StructTag2);
+
+ EXPECT_EQ(GenericMD, nullptr);
+
+ // Despite GenericMD being nullptr, we expect the setMetadata call to be well
+ // defined and produce a well-formed function.
+ SI->setMetadata(LLVMContext::MD_tbaa, GenericMD);
+
+ EXPECT_TRUE(!verifyFunction(*F));
+}
+
+} // end anonymous namspace
+} // end llvm namespace
diff --git a/unittests/Analysis/ValueTrackingTest.cpp b/unittests/Analysis/ValueTrackingTest.cpp
index f429c3b99149..ba0d30d59b66 100644
--- a/unittests/Analysis/ValueTrackingTest.cpp
+++ b/unittests/Analysis/ValueTrackingTest.cpp
@@ -188,3 +188,54 @@ TEST_F(MatchSelectPatternTest, DoubleCastBad) {
// The cast types here aren't the same, so we cannot match an UMIN.
expectPattern({SPF_UNKNOWN, SPNB_NA, false});
}
+
+TEST(ValueTracking, GuaranteedToTransferExecutionToSuccessor) {
+ StringRef Assembly =
+ "declare void @nounwind_readonly(i32*) nounwind readonly "
+ "declare void @nounwind_argmemonly(i32*) nounwind argmemonly "
+ "declare void @throws_but_readonly(i32*) readonly "
+ "declare void @throws_but_argmemonly(i32*) argmemonly "
+ " "
+ "declare void @unknown(i32*) "
+ " "
+ "define void @f(i32* %p) { "
+ " call void @nounwind_readonly(i32* %p) "
+ " call void @nounwind_argmemonly(i32* %p) "
+ " call void @throws_but_readonly(i32* %p) "
+ " call void @throws_but_argmemonly(i32* %p) "
+ " call void @unknown(i32* %p) nounwind readonly "
+ " call void @unknown(i32* %p) nounwind argmemonly "
+ " call void @unknown(i32* %p) readonly "
+ " call void @unknown(i32* %p) argmemonly "
+ " ret void "
+ "} ";
+
+ LLVMContext Context;
+ SMDiagnostic Error;
+ auto M = parseAssemblyString(Assembly, Error, Context);
+ assert(M && "Bad assembly?");
+
+ auto *F = M->getFunction("f");
+ assert(F && "Bad assembly?");
+
+ auto &BB = F->getEntryBlock();
+ ArrayRef<bool> ExpectedAnswers = {
+ true, // call void @nounwind_readonly(i32* %p)
+ true, // call void @nounwind_argmemonly(i32* %p)
+ false, // call void @throws_but_readonly(i32* %p)
+ false, // call void @throws_but_argmemonly(i32* %p)
+ true, // call void @unknown(i32* %p) nounwind readonly
+ true, // call void @unknown(i32* %p) nounwind argmemonly
+ false, // call void @unknown(i32* %p) readonly
+ false, // call void @unknown(i32* %p) argmemonly
+ false, // ret void
+ };
+
+ int Index = 0;
+ for (auto &I : BB) {
+ EXPECT_EQ(isGuaranteedToTransferExecutionToSuccessor(&I),
+ ExpectedAnswers[Index])
+ << "Incorrect answer at instruction " << Index << " = " << I;
+ Index++;
+ }
+}
diff --git a/unittests/Bitcode/BitReaderTest.cpp b/unittests/Bitcode/BitReaderTest.cpp
index d0f33d12d5bc..0003a2b6fb8f 100644
--- a/unittests/Bitcode/BitReaderTest.cpp
+++ b/unittests/Bitcode/BitReaderTest.cpp
@@ -7,22 +7,22 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/AsmParser/Parser.h"
+#include "llvm/Bitcode/BitcodeReader.h"
+#include "llvm/Bitcode/BitcodeWriter.h"
#include "llvm/Bitcode/BitstreamReader.h"
#include "llvm/Bitcode/BitstreamWriter.h"
-#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
-#include "llvm/Support/DataStream.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SourceMgr.h"
-#include "llvm/Support/StreamingMemoryObject.h"
#include "gtest/gtest.h"
using namespace llvm;
@@ -55,91 +55,13 @@ static std::unique_ptr<Module> getLazyModuleFromAssembly(LLVMContext &Context,
SmallString<1024> &Mem,
const char *Assembly) {
writeModuleToBuffer(parseAssembly(Context, Assembly), Mem);
- std::unique_ptr<MemoryBuffer> Buffer =
- MemoryBuffer::getMemBuffer(Mem.str(), "test", false);
- ErrorOr<std::unique_ptr<Module>> ModuleOrErr =
- getLazyBitcodeModule(std::move(Buffer), Context);
+ Expected<std::unique_ptr<Module>> ModuleOrErr =
+ getLazyBitcodeModule(MemoryBufferRef(Mem.str(), "test"), Context);
+ if (!ModuleOrErr)
+ report_fatal_error("Could not parse bitcode module");
return std::move(ModuleOrErr.get());
}
-class BufferDataStreamer : public DataStreamer {
- std::unique_ptr<MemoryBuffer> Buffer;
- unsigned Pos = 0;
- size_t GetBytes(unsigned char *Out, size_t Len) override {
- StringRef Buf = Buffer->getBuffer();
- size_t Left = Buf.size() - Pos;
- Len = std::min(Left, Len);
- memcpy(Out, Buffer->getBuffer().substr(Pos).data(), Len);
- Pos += Len;
- return Len;
- }
-
-public:
- BufferDataStreamer(std::unique_ptr<MemoryBuffer> Buffer)
- : Buffer(std::move(Buffer)) {}
-};
-
-static std::unique_ptr<Module>
-getStreamedModuleFromAssembly(LLVMContext &Context, SmallString<1024> &Mem,
- const char *Assembly) {
- writeModuleToBuffer(parseAssembly(Context, Assembly), Mem);
- std::unique_ptr<MemoryBuffer> Buffer =
- MemoryBuffer::getMemBuffer(Mem.str(), "test", false);
- auto Streamer = llvm::make_unique<BufferDataStreamer>(std::move(Buffer));
- ErrorOr<std::unique_ptr<Module>> ModuleOrErr =
- getStreamedBitcodeModule("test", std::move(Streamer), Context);
- return std::move(ModuleOrErr.get());
-}
-
-// Checks if we correctly detect eof if we try to read N bits when there are not
-// enough bits left on the input stream to read N bits, and we are using a data
-// streamer. In particular, it checks if we properly set the object size when
-// the eof is reached under such conditions.
-TEST(BitReaderTest, TestForEofAfterReadFailureOnDataStreamer) {
- // Note: Because StreamingMemoryObject does a call to method GetBytes in it's
- // constructor, using internal constant kChunkSize, we must fill the input
- // with more characters than that amount.
- static size_t InputSize = StreamingMemoryObject::kChunkSize + 5;
- char *Text = new char[InputSize];
- std::memset(Text, 'a', InputSize);
- Text[InputSize - 1] = '\0';
- StringRef Input(Text);
-
- // Build bitsteam reader using data streamer.
- auto MemoryBuf = MemoryBuffer::getMemBuffer(Input);
- std::unique_ptr<DataStreamer> Streamer(
- new BufferDataStreamer(std::move(MemoryBuf)));
- auto OwnedBytes =
- llvm::make_unique<StreamingMemoryObject>(std::move(Streamer));
- auto Reader = llvm::make_unique<BitstreamReader>(std::move(OwnedBytes));
- BitstreamCursor Cursor;
- Cursor.init(Reader.get());
-
- // Jump to two bytes before end of stream.
- Cursor.JumpToBit((InputSize - 4) * CHAR_BIT);
- // Try to read 4 bytes when only 2 are present, resulting in error value 0.
- const size_t ReadErrorValue = 0;
- EXPECT_EQ(ReadErrorValue, Cursor.Read(32));
- // Should be at eof now.
- EXPECT_TRUE(Cursor.AtEndOfStream());
-
- delete[] Text;
-}
-
-TEST(BitReaderTest, MateralizeForwardRefWithStream) {
- SmallString<1024> Mem;
-
- LLVMContext Context;
- std::unique_ptr<Module> M = getStreamedModuleFromAssembly(
- Context, Mem, "@table = constant i8* blockaddress(@func, %bb)\n"
- "define void @func() {\n"
- " unreachable\n"
- "bb:\n"
- " unreachable\n"
- "}\n");
- EXPECT_FALSE(M->getFunction("func")->empty());
-}
-
// Tests that lazy evaluation can parse functions out of order.
TEST(BitReaderTest, MaterializeFunctionsOutOfOrder) {
SmallString<1024> Mem;
@@ -172,7 +94,7 @@ TEST(BitReaderTest, MaterializeFunctionsOutOfOrder) {
EXPECT_FALSE(verifyModule(*M, &dbgs()));
// Materialize h.
- H->materialize();
+ ASSERT_FALSE(H->materialize());
EXPECT_TRUE(F->empty());
EXPECT_TRUE(G->empty());
EXPECT_FALSE(H->empty());
@@ -180,7 +102,7 @@ TEST(BitReaderTest, MaterializeFunctionsOutOfOrder) {
EXPECT_FALSE(verifyModule(*M, &dbgs()));
// Materialize g.
- G->materialize();
+ ASSERT_FALSE(G->materialize());
EXPECT_TRUE(F->empty());
EXPECT_FALSE(G->empty());
EXPECT_FALSE(H->empty());
@@ -188,7 +110,7 @@ TEST(BitReaderTest, MaterializeFunctionsOutOfOrder) {
EXPECT_FALSE(verifyModule(*M, &dbgs()));
// Materialize j.
- J->materialize();
+ ASSERT_FALSE(J->materialize());
EXPECT_TRUE(F->empty());
EXPECT_FALSE(G->empty());
EXPECT_FALSE(H->empty());
@@ -196,7 +118,7 @@ TEST(BitReaderTest, MaterializeFunctionsOutOfOrder) {
EXPECT_FALSE(verifyModule(*M, &dbgs()));
// Materialize f.
- F->materialize();
+ ASSERT_FALSE(F->materialize());
EXPECT_FALSE(F->empty());
EXPECT_FALSE(G->empty());
EXPECT_FALSE(H->empty());
@@ -216,6 +138,7 @@ TEST(BitReaderTest, MaterializeFunctionsForBlockAddr) { // PR11677
" unreachable\n"
"}\n");
EXPECT_FALSE(verifyModule(*M, &dbgs()));
+ EXPECT_FALSE(M->getFunction("func")->empty());
}
TEST(BitReaderTest, MaterializeFunctionsForBlockAddrInFunctionBefore) {
diff --git a/unittests/Bitcode/BitstreamReaderTest.cpp b/unittests/Bitcode/BitstreamReaderTest.cpp
index 2be774cc5394..704eb803f9c7 100644
--- a/unittests/Bitcode/BitstreamReaderTest.cpp
+++ b/unittests/Bitcode/BitstreamReaderTest.cpp
@@ -10,34 +10,17 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/Bitcode/BitstreamReader.h"
#include "llvm/Bitcode/BitstreamWriter.h"
-#include "llvm/Support/StreamingMemoryObject.h"
#include "gtest/gtest.h"
using namespace llvm;
namespace {
-class BufferStreamer : public DataStreamer {
- StringRef Buffer;
-
-public:
- BufferStreamer(StringRef Buffer) : Buffer(Buffer) {}
- size_t GetBytes(unsigned char *OutBuffer, size_t Length) override {
- if (Length >= Buffer.size())
- Length = Buffer.size();
-
- std::copy(Buffer.begin(), Buffer.begin() + Length, OutBuffer);
- Buffer = Buffer.drop_front(Length);
- return Length;
- }
-};
-
TEST(BitstreamReaderTest, AtEndOfStream) {
uint8_t Bytes[4] = {
0x00, 0x01, 0x02, 0x03
};
- BitstreamReader Reader(std::begin(Bytes), std::end(Bytes));
- BitstreamCursor Cursor(Reader);
+ BitstreamCursor Cursor(Bytes);
EXPECT_FALSE(Cursor.AtEndOfStream());
(void)Cursor.Read(8);
@@ -56,27 +39,23 @@ TEST(BitstreamReaderTest, AtEndOfStreamJump) {
uint8_t Bytes[4] = {
0x00, 0x01, 0x02, 0x03
};
- BitstreamReader Reader(std::begin(Bytes), std::end(Bytes));
- BitstreamCursor Cursor(Reader);
+ BitstreamCursor Cursor(Bytes);
Cursor.JumpToBit(32);
EXPECT_TRUE(Cursor.AtEndOfStream());
}
TEST(BitstreamReaderTest, AtEndOfStreamEmpty) {
- uint8_t Dummy = 0xFF;
- BitstreamReader Reader(&Dummy, &Dummy);
- BitstreamCursor Cursor(Reader);
+ BitstreamCursor Cursor(ArrayRef<uint8_t>{});
EXPECT_TRUE(Cursor.AtEndOfStream());
}
TEST(BitstreamReaderTest, getCurrentByteNo) {
uint8_t Bytes[] = {0x00, 0x01, 0x02, 0x03};
- BitstreamReader Reader(std::begin(Bytes), std::end(Bytes));
- SimpleBitstreamCursor Cursor(Reader);
+ SimpleBitstreamCursor Cursor(Bytes);
- for (unsigned I = 0, E = 33; I != E; ++I) {
+ for (unsigned I = 0, E = 32; I != E; ++I) {
EXPECT_EQ(I / 8, Cursor.getCurrentByteNo());
(void)Cursor.Read(1);
}
@@ -85,8 +64,7 @@ TEST(BitstreamReaderTest, getCurrentByteNo) {
TEST(BitstreamReaderTest, getPointerToByte) {
uint8_t Bytes[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
- BitstreamReader Reader(std::begin(Bytes), std::end(Bytes));
- SimpleBitstreamCursor Cursor(Reader);
+ SimpleBitstreamCursor Cursor(Bytes);
for (unsigned I = 0, E = 8; I != E; ++I) {
EXPECT_EQ(Bytes + I, Cursor.getPointerToByte(I, 1));
@@ -95,87 +73,13 @@ TEST(BitstreamReaderTest, getPointerToByte) {
TEST(BitstreamReaderTest, getPointerToBit) {
uint8_t Bytes[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
- BitstreamReader Reader(std::begin(Bytes), std::end(Bytes));
- SimpleBitstreamCursor Cursor(Reader);
+ SimpleBitstreamCursor Cursor(Bytes);
for (unsigned I = 0, E = 8; I != E; ++I) {
EXPECT_EQ(Bytes + I, Cursor.getPointerToBit(I * 8, 1));
}
}
-TEST(BitstreamReaderTest, jumpToPointer) {
- uint8_t Bytes[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
- BitstreamReader Reader(std::begin(Bytes), std::end(Bytes));
- SimpleBitstreamCursor Cursor(Reader);
-
- for (unsigned I : {0, 6, 2, 7}) {
- Cursor.jumpToPointer(Bytes + I);
- EXPECT_EQ(I, Cursor.getCurrentByteNo());
- }
-}
-
-TEST(BitstreamReaderTest, setArtificialByteLimit) {
- uint8_t Bytes[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
- BitstreamReader Reader(std::begin(Bytes), std::end(Bytes));
- SimpleBitstreamCursor Cursor(Reader);
-
- Cursor.setArtificialByteLimit(8);
- EXPECT_EQ(8u, Cursor.getSizeIfKnown());
- while (!Cursor.AtEndOfStream())
- (void)Cursor.Read(1);
-
- EXPECT_EQ(8u, Cursor.getCurrentByteNo());
-}
-
-TEST(BitstreamReaderTest, setArtificialByteLimitNotWordBoundary) {
- uint8_t Bytes[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
- BitstreamReader Reader(std::begin(Bytes), std::end(Bytes));
- SimpleBitstreamCursor Cursor(Reader);
-
- Cursor.setArtificialByteLimit(5);
- EXPECT_EQ(8u, Cursor.getSizeIfKnown());
- while (!Cursor.AtEndOfStream())
- (void)Cursor.Read(1);
-
- EXPECT_EQ(8u, Cursor.getCurrentByteNo());
-}
-
-TEST(BitstreamReaderTest, setArtificialByteLimitPastTheEnd) {
- uint8_t Bytes[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b};
- BitstreamReader Reader(std::begin(Bytes), std::end(Bytes));
- SimpleBitstreamCursor Cursor(Reader);
-
- // The size of the memory object isn't known yet. Set it too high and
- // confirm that we don't read too far.
- Cursor.setArtificialByteLimit(24);
- EXPECT_EQ(24u, Cursor.getSizeIfKnown());
- while (!Cursor.AtEndOfStream())
- (void)Cursor.Read(1);
-
- EXPECT_EQ(12u, Cursor.getCurrentByteNo());
- EXPECT_EQ(12u, Cursor.getSizeIfKnown());
-}
-
-TEST(BitstreamReaderTest, setArtificialByteLimitPastTheEndKnown) {
- uint8_t Bytes[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b};
- BitstreamReader Reader(std::begin(Bytes), std::end(Bytes));
- SimpleBitstreamCursor Cursor(Reader);
-
- // Save the size of the memory object in the cursor.
- while (!Cursor.AtEndOfStream())
- (void)Cursor.Read(1);
- EXPECT_EQ(12u, Cursor.getCurrentByteNo());
- EXPECT_EQ(12u, Cursor.getSizeIfKnown());
-
- Cursor.setArtificialByteLimit(20);
- EXPECT_TRUE(Cursor.AtEndOfStream());
- EXPECT_EQ(12u, Cursor.getSizeIfKnown());
-}
-
TEST(BitstreamReaderTest, readRecordWithBlobWhileStreaming) {
SmallVector<uint8_t, 1> BlobData;
for (unsigned I = 0, E = 1024; I != E; ++I)
@@ -208,10 +112,8 @@ TEST(BitstreamReaderTest, readRecordWithBlobWhileStreaming) {
}
// Stream the buffer into the reader.
- BitstreamReader R(llvm::make_unique<StreamingMemoryObject>(
- llvm::make_unique<BufferStreamer>(
- StringRef(Buffer.begin(), Buffer.size()))));
- BitstreamCursor Stream(R);
+ BitstreamCursor Stream(
+ ArrayRef<uint8_t>((const uint8_t *)Buffer.begin(), Buffer.size()));
// Header. Included in test so that we can run llvm-bcanalyzer to debug
// when there are problems.
@@ -238,4 +140,12 @@ TEST(BitstreamReaderTest, readRecordWithBlobWhileStreaming) {
}
}
+TEST(BitstreamReaderTest, shortRead) {
+ uint8_t Bytes[] = {8, 7, 6, 5, 4, 3, 2, 1};
+ for (unsigned I = 1; I != 8; ++I) {
+ SimpleBitstreamCursor Cursor(ArrayRef<uint8_t>(Bytes, I));
+ EXPECT_EQ(8ull, Cursor.Read(8));
+ }
+}
+
} // end anonymous namespace
diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt
index 49a9b31b60d9..8dbca211d026 100644
--- a/unittests/CMakeLists.txt
+++ b/unittests/CMakeLists.txt
@@ -1,12 +1,6 @@
add_custom_target(UnitTests)
set_target_properties(UnitTests PROPERTIES FOLDER "Tests")
-if (APPLE)
- set(CMAKE_INSTALL_RPATH "@executable_path/../../lib")
-else(UNIX)
- set(CMAKE_INSTALL_RPATH "\$ORIGIN/../../lib${LLVM_LIBDIR_SUFFIX}")
-endif()
-
function(add_llvm_unittest test_dirname)
add_unittest(UnitTests ${test_dirname} ${ARGN})
endfunction()
@@ -23,8 +17,10 @@ add_subdirectory(LineEditor)
add_subdirectory(Linker)
add_subdirectory(MC)
add_subdirectory(MI)
+add_subdirectory(Object)
add_subdirectory(ObjectYAML)
add_subdirectory(Option)
add_subdirectory(ProfileData)
add_subdirectory(Support)
+add_subdirectory(Target)
add_subdirectory(Transforms)
diff --git a/unittests/CodeGen/CMakeLists.txt b/unittests/CodeGen/CMakeLists.txt
index 65c0ac3f20e4..240734dc6b18 100644
--- a/unittests/CodeGen/CMakeLists.txt
+++ b/unittests/CodeGen/CMakeLists.txt
@@ -1,12 +1,18 @@
set(LLVM_LINK_COMPONENTS
AsmPrinter
+ CodeGen
+ Core
Support
)
set(CodeGenSources
DIEHashTest.cpp
+ LowLevelTypeTest.cpp
+ MachineInstrBundleIteratorTest.cpp
)
add_llvm_unittest(CodeGenTests
${CodeGenSources}
)
+
+add_subdirectory(GlobalISel)
diff --git a/unittests/CodeGen/GlobalISel/CMakeLists.txt b/unittests/CodeGen/GlobalISel/CMakeLists.txt
new file mode 100644
index 000000000000..94e31159c6bb
--- /dev/null
+++ b/unittests/CodeGen/GlobalISel/CMakeLists.txt
@@ -0,0 +1,10 @@
+set(LLVM_LINK_COMPONENTS
+ GlobalISel
+ CodeGen
+ )
+
+if(LLVM_BUILD_GLOBAL_ISEL)
+ add_llvm_unittest(GlobalISelTests
+ LegalizerInfoTest.cpp
+ )
+endif()
diff --git a/unittests/CodeGen/GlobalISel/LegalizerInfoTest.cpp b/unittests/CodeGen/GlobalISel/LegalizerInfoTest.cpp
new file mode 100644
index 000000000000..882df5f25216
--- /dev/null
+++ b/unittests/CodeGen/GlobalISel/LegalizerInfoTest.cpp
@@ -0,0 +1,120 @@
+//===- llvm/unittest/CodeGen/GlobalISel/LegalizerInfoTest.cpp -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
+#include "llvm/Target/TargetOpcodes.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+// Define a couple of pretty printers to help debugging when things go wrong.
+namespace llvm {
+std::ostream &
+operator<<(std::ostream &OS, const llvm::LegalizerInfo::LegalizeAction Act) {
+ switch (Act) {
+ case LegalizerInfo::Lower: OS << "Lower"; break;
+ case LegalizerInfo::Legal: OS << "Legal"; break;
+ case LegalizerInfo::NarrowScalar: OS << "NarrowScalar"; break;
+ case LegalizerInfo::WidenScalar: OS << "WidenScalar"; break;
+ case LegalizerInfo::FewerElements: OS << "FewerElements"; break;
+ case LegalizerInfo::MoreElements: OS << "MoreElements"; break;
+ case LegalizerInfo::Libcall: OS << "Libcall"; break;
+ case LegalizerInfo::Custom: OS << "Custom"; break;
+ case LegalizerInfo::Unsupported: OS << "Unsupported"; break;
+ case LegalizerInfo::NotFound: OS << "NotFound";
+ }
+ return OS;
+}
+
+std::ostream &
+operator<<(std::ostream &OS, const llvm::LLT Ty) {
+ std::string Repr;
+ raw_string_ostream SS{Repr};
+ Ty.print(SS);
+ OS << SS.str();
+ return OS;
+}
+}
+
+namespace {
+
+
+TEST(LegalizerInfoTest, ScalarRISC) {
+ using namespace TargetOpcode;
+ LegalizerInfo L;
+ // Typical RISCy set of operations based on AArch64.
+ L.setAction({G_ADD, LLT::scalar(8)}, LegalizerInfo::WidenScalar);
+ L.setAction({G_ADD, LLT::scalar(16)}, LegalizerInfo::WidenScalar);
+ L.setAction({G_ADD, LLT::scalar(32)}, LegalizerInfo::Legal);
+ L.setAction({G_ADD, LLT::scalar(64)}, LegalizerInfo::Legal);
+ L.computeTables();
+
+ // Check we infer the correct types and actually do what we're told.
+ ASSERT_EQ(L.getAction({G_ADD, LLT::scalar(8)}),
+ std::make_pair(LegalizerInfo::WidenScalar, LLT::scalar(32)));
+ ASSERT_EQ(L.getAction({G_ADD, LLT::scalar(16)}),
+ std::make_pair(LegalizerInfo::WidenScalar, LLT::scalar(32)));
+ ASSERT_EQ(L.getAction({G_ADD, LLT::scalar(32)}),
+ std::make_pair(LegalizerInfo::Legal, LLT::scalar(32)));
+ ASSERT_EQ(L.getAction({G_ADD, LLT::scalar(64)}),
+ std::make_pair(LegalizerInfo::Legal, LLT::scalar(64)));
+
+ // Make sure the default for over-sized types applies.
+ ASSERT_EQ(L.getAction({G_ADD, LLT::scalar(128)}),
+ std::make_pair(LegalizerInfo::NarrowScalar, LLT::scalar(64)));
+}
+
+TEST(LegalizerInfoTest, VectorRISC) {
+ using namespace TargetOpcode;
+ LegalizerInfo L;
+ // Typical RISCy set of operations based on ARM.
+ L.setScalarInVectorAction(G_ADD, LLT::scalar(8), LegalizerInfo::Legal);
+ L.setScalarInVectorAction(G_ADD, LLT::scalar(16), LegalizerInfo::Legal);
+ L.setScalarInVectorAction(G_ADD, LLT::scalar(32), LegalizerInfo::Legal);
+
+ L.setAction({G_ADD, LLT::vector(8, 8)}, LegalizerInfo::Legal);
+ L.setAction({G_ADD, LLT::vector(16, 8)}, LegalizerInfo::Legal);
+ L.setAction({G_ADD, LLT::vector(4, 16)}, LegalizerInfo::Legal);
+ L.setAction({G_ADD, LLT::vector(8, 16)}, LegalizerInfo::Legal);
+ L.setAction({G_ADD, LLT::vector(2, 32)}, LegalizerInfo::Legal);
+ L.setAction({G_ADD, LLT::vector(4, 32)}, LegalizerInfo::Legal);
+ L.computeTables();
+
+ // Check we infer the correct types and actually do what we're told for some
+ // simple cases.
+ ASSERT_EQ(L.getAction({G_ADD, LLT::vector(2, 8)}),
+ std::make_pair(LegalizerInfo::MoreElements, LLT::vector(8, 8)));
+ ASSERT_EQ(L.getAction({G_ADD, LLT::vector(8, 8)}),
+ std::make_pair(LegalizerInfo::Legal, LLT::vector(8, 8)));
+ ASSERT_EQ(
+ L.getAction({G_ADD, LLT::vector(8, 32)}),
+ std::make_pair(LegalizerInfo::FewerElements, LLT::vector(4, 32)));
+}
+
+TEST(LegalizerInfoTest, MultipleTypes) {
+ using namespace TargetOpcode;
+ LegalizerInfo L;
+ LLT p0 = LLT::pointer(0, 64);
+ LLT s32 = LLT::scalar(32);
+ LLT s64 = LLT::scalar(64);
+
+ // Typical RISCy set of operations based on AArch64.
+ L.setAction({G_PTRTOINT, 0, s64}, LegalizerInfo::Legal);
+ L.setAction({G_PTRTOINT, 1, p0}, LegalizerInfo::Legal);
+
+ L.setAction({G_PTRTOINT, 0, s32}, LegalizerInfo::WidenScalar);
+ L.computeTables();
+
+ // Check we infer the correct types and actually do what we're told.
+ ASSERT_EQ(L.getAction({G_PTRTOINT, 0, s64}),
+ std::make_pair(LegalizerInfo::Legal, s64));
+ ASSERT_EQ(L.getAction({G_PTRTOINT, 1, p0}),
+ std::make_pair(LegalizerInfo::Legal, p0));
+}
+}
diff --git a/unittests/CodeGen/LowLevelTypeTest.cpp b/unittests/CodeGen/LowLevelTypeTest.cpp
new file mode 100644
index 000000000000..4ea181c1c9d3
--- /dev/null
+++ b/unittests/CodeGen/LowLevelTypeTest.cpp
@@ -0,0 +1,204 @@
+//===- llvm/unittest/CodeGen/GlobalISel/LowLevelTypeTest.cpp --------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/CodeGen/LowLevelType.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Type.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+// Define a pretty printer to help debugging when things go wrong.
+namespace llvm {
+std::ostream &
+operator<<(std::ostream &OS, const llvm::LLT Ty) {
+ std::string Repr;
+ raw_string_ostream SS{Repr};
+ Ty.print(SS);
+ OS << SS.str();
+ return OS;
+}
+}
+
+namespace {
+
+TEST(LowLevelTypeTest, Scalar) {
+ LLVMContext C;
+ DataLayout DL("");
+
+ for (unsigned S : {1U, 17U, 32U, 64U, 0xfffffU}) {
+ const LLT Ty = LLT::scalar(S);
+ const LLT HalfTy = (S % 2) == 0 ? Ty.halfScalarSize() : Ty;
+ const LLT DoubleTy = Ty.doubleScalarSize();
+
+ // Test kind.
+ for (const LLT TestTy : {Ty, HalfTy, DoubleTy}) {
+ ASSERT_TRUE(TestTy.isValid());
+ ASSERT_TRUE(TestTy.isScalar());
+
+ ASSERT_FALSE(TestTy.isPointer());
+ ASSERT_FALSE(TestTy.isVector());
+ }
+
+ // Test sizes.
+ EXPECT_EQ(S, Ty.getSizeInBits());
+ EXPECT_EQ(S, Ty.getScalarSizeInBits());
+
+ EXPECT_EQ(S*2, DoubleTy.getSizeInBits());
+ EXPECT_EQ(S*2, DoubleTy.getScalarSizeInBits());
+
+ if ((S % 2) == 0) {
+ EXPECT_EQ(S/2, HalfTy.getSizeInBits());
+ EXPECT_EQ(S/2, HalfTy.getScalarSizeInBits());
+ }
+
+ // Test equality operators.
+ EXPECT_TRUE(Ty == Ty);
+ EXPECT_FALSE(Ty != Ty);
+
+ EXPECT_NE(Ty, DoubleTy);
+
+ // Test Type->LLT conversion.
+ Type *IRTy = IntegerType::get(C, S);
+ EXPECT_EQ(Ty, LLT(*IRTy, DL));
+ }
+}
+
+TEST(LowLevelTypeTest, Vector) {
+ LLVMContext C;
+ DataLayout DL("");
+
+ for (unsigned S : {1U, 17U, 32U, 64U, 0xfffU}) {
+ for (uint16_t Elts : {2U, 3U, 4U, 32U, 0xffU}) {
+ const LLT STy = LLT::scalar(S);
+ const LLT VTy = LLT::vector(Elts, S);
+
+ // Test the alternative vector().
+ {
+ const LLT VSTy = LLT::vector(Elts, STy);
+ EXPECT_EQ(VTy, VSTy);
+ }
+
+ // Test getElementType().
+ EXPECT_EQ(STy, VTy.getElementType());
+
+ const LLT HalfSzTy = ((S % 2) == 0) ? VTy.halfScalarSize() : VTy;
+ const LLT DoubleSzTy = VTy.doubleScalarSize();
+
+ // halfElements requires an even number of elements.
+ const LLT HalfEltIfEvenTy = ((Elts % 2) == 0) ? VTy.halfElements() : VTy;
+ const LLT DoubleEltTy = VTy.doubleElements();
+
+ // Test kind.
+ for (const LLT TestTy : {VTy, HalfSzTy, DoubleSzTy, DoubleEltTy}) {
+ ASSERT_TRUE(TestTy.isValid());
+ ASSERT_TRUE(TestTy.isVector());
+
+ ASSERT_FALSE(TestTy.isScalar());
+ ASSERT_FALSE(TestTy.isPointer());
+ }
+
+ // Test halving elements to a scalar.
+ {
+ ASSERT_TRUE(HalfEltIfEvenTy.isValid());
+ ASSERT_FALSE(HalfEltIfEvenTy.isPointer());
+ if (Elts > 2) {
+ ASSERT_TRUE(HalfEltIfEvenTy.isVector());
+ } else {
+ ASSERT_FALSE(HalfEltIfEvenTy.isVector());
+ EXPECT_EQ(STy, HalfEltIfEvenTy);
+ }
+ }
+
+
+ // Test sizes.
+ EXPECT_EQ(S * Elts, VTy.getSizeInBits());
+ EXPECT_EQ(S, VTy.getScalarSizeInBits());
+ EXPECT_EQ(Elts, VTy.getNumElements());
+
+ if ((S % 2) == 0) {
+ EXPECT_EQ((S / 2) * Elts, HalfSzTy.getSizeInBits());
+ EXPECT_EQ(S / 2, HalfSzTy.getScalarSizeInBits());
+ EXPECT_EQ(Elts, HalfSzTy.getNumElements());
+ }
+
+ EXPECT_EQ((S * 2) * Elts, DoubleSzTy.getSizeInBits());
+ EXPECT_EQ(S * 2, DoubleSzTy.getScalarSizeInBits());
+ EXPECT_EQ(Elts, DoubleSzTy.getNumElements());
+
+ if ((Elts % 2) == 0) {
+ EXPECT_EQ(S * (Elts / 2), HalfEltIfEvenTy.getSizeInBits());
+ EXPECT_EQ(S, HalfEltIfEvenTy.getScalarSizeInBits());
+ if (Elts > 2)
+ EXPECT_EQ(Elts / 2, HalfEltIfEvenTy.getNumElements());
+ }
+
+ EXPECT_EQ(S * (Elts * 2), DoubleEltTy.getSizeInBits());
+ EXPECT_EQ(S, DoubleEltTy.getScalarSizeInBits());
+ EXPECT_EQ(Elts * 2, DoubleEltTy.getNumElements());
+
+ // Test equality operators.
+ EXPECT_TRUE(VTy == VTy);
+ EXPECT_FALSE(VTy != VTy);
+
+ // Test inequality operators on..
+ // ..different kind.
+ EXPECT_NE(VTy, STy);
+ // ..different #elts.
+ EXPECT_NE(VTy, DoubleEltTy);
+ // ..different scalar size.
+ EXPECT_NE(VTy, DoubleSzTy);
+
+ // Test Type->LLT conversion.
+ Type *IRSTy = IntegerType::get(C, S);
+ Type *IRTy = VectorType::get(IRSTy, Elts);
+ EXPECT_EQ(VTy, LLT(*IRTy, DL));
+ }
+ }
+}
+
+TEST(LowLevelTypeTest, Pointer) {
+ LLVMContext C;
+ DataLayout DL("");
+
+ for (unsigned AS : {0U, 1U, 127U, 0xffffU}) {
+ const LLT Ty = LLT::pointer(AS, DL.getPointerSizeInBits(AS));
+
+ // Test kind.
+ ASSERT_TRUE(Ty.isValid());
+ ASSERT_TRUE(Ty.isPointer());
+
+ ASSERT_FALSE(Ty.isScalar());
+ ASSERT_FALSE(Ty.isVector());
+
+ // Test addressspace.
+ EXPECT_EQ(AS, Ty.getAddressSpace());
+
+ // Test equality operators.
+ EXPECT_TRUE(Ty == Ty);
+ EXPECT_FALSE(Ty != Ty);
+
+ // Test Type->LLT conversion.
+ Type *IRTy = PointerType::get(IntegerType::get(C, 8), AS);
+ EXPECT_EQ(Ty, LLT(*IRTy, DL));
+ }
+}
+
+TEST(LowLevelTypeTest, Invalid) {
+ const LLT Ty;
+
+ ASSERT_FALSE(Ty.isValid());
+ ASSERT_FALSE(Ty.isScalar());
+ ASSERT_FALSE(Ty.isPointer());
+ ASSERT_FALSE(Ty.isVector());
+}
+
+}
diff --git a/unittests/CodeGen/MachineInstrBundleIteratorTest.cpp b/unittests/CodeGen/MachineInstrBundleIteratorTest.cpp
new file mode 100644
index 000000000000..416f5774f4c6
--- /dev/null
+++ b/unittests/CodeGen/MachineInstrBundleIteratorTest.cpp
@@ -0,0 +1,133 @@
+//===- MachineInstrBundleIteratorTest.cpp ---------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/ilist_node.h"
+#include "llvm/CodeGen/MachineInstrBundleIterator.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+
+struct MyBundledInstr
+ : public ilist_node<MyBundledInstr, ilist_sentinel_tracking<true>> {
+ bool isBundledWithPred() const { return true; }
+ bool isBundledWithSucc() const { return true; }
+};
+typedef MachineInstrBundleIterator<MyBundledInstr> bundled_iterator;
+typedef MachineInstrBundleIterator<const MyBundledInstr> const_bundled_iterator;
+typedef MachineInstrBundleIterator<MyBundledInstr, true>
+ reverse_bundled_iterator;
+typedef MachineInstrBundleIterator<const MyBundledInstr, true>
+ const_reverse_bundled_iterator;
+
+#ifdef GTEST_HAS_DEATH_TEST
+#ifndef NDEBUG
+TEST(MachineInstrBundleIteratorTest, CheckForBundles) {
+ MyBundledInstr MBI;
+ auto I = MBI.getIterator();
+ auto RI = I.getReverse();
+
+ // Confirm that MBI is always considered bundled.
+ EXPECT_TRUE(MBI.isBundledWithPred());
+ EXPECT_TRUE(MBI.isBundledWithSucc());
+
+ // Confirm that iterators check in their constructor for bundled iterators.
+ EXPECT_DEATH((void)static_cast<bundled_iterator>(I),
+ "not legal to initialize");
+ EXPECT_DEATH((void)static_cast<bundled_iterator>(MBI),
+ "not legal to initialize");
+ EXPECT_DEATH((void)static_cast<bundled_iterator>(&MBI),
+ "not legal to initialize");
+ EXPECT_DEATH((void)static_cast<const_bundled_iterator>(I),
+ "not legal to initialize");
+ EXPECT_DEATH((void)static_cast<const_bundled_iterator>(MBI),
+ "not legal to initialize");
+ EXPECT_DEATH((void)static_cast<const_bundled_iterator>(&MBI),
+ "not legal to initialize");
+ EXPECT_DEATH((void)static_cast<reverse_bundled_iterator>(RI),
+ "not legal to initialize");
+ EXPECT_DEATH((void)static_cast<reverse_bundled_iterator>(MBI),
+ "not legal to initialize");
+ EXPECT_DEATH((void)static_cast<reverse_bundled_iterator>(&MBI),
+ "not legal to initialize");
+ EXPECT_DEATH((void)static_cast<const_reverse_bundled_iterator>(RI),
+ "not legal to initialize");
+ EXPECT_DEATH((void)static_cast<const_reverse_bundled_iterator>(MBI),
+ "not legal to initialize");
+ EXPECT_DEATH((void)static_cast<const_reverse_bundled_iterator>(&MBI),
+ "not legal to initialize");
+}
+#endif
+#endif
+
+TEST(MachineInstrBundleIteratorTest, CompareToBundledMI) {
+ MyBundledInstr MBI;
+ const MyBundledInstr &CMBI = MBI;
+ bundled_iterator I;
+ const_bundled_iterator CI;
+
+ // Confirm that MBI is always considered bundled.
+ EXPECT_TRUE(MBI.isBundledWithPred());
+ EXPECT_TRUE(MBI.isBundledWithSucc());
+
+ // These invocations will crash when !NDEBUG if a conversion is taking place.
+ // These checks confirm that comparison operators don't use any conversion
+ // operators.
+ ASSERT_FALSE(MBI == I);
+ ASSERT_FALSE(&MBI == I);
+ ASSERT_FALSE(CMBI == I);
+ ASSERT_FALSE(&CMBI == I);
+ ASSERT_FALSE(I == MBI);
+ ASSERT_FALSE(I == &MBI);
+ ASSERT_FALSE(I == CMBI);
+ ASSERT_FALSE(I == &CMBI);
+ ASSERT_FALSE(MBI == CI);
+ ASSERT_FALSE(&MBI == CI);
+ ASSERT_FALSE(CMBI == CI);
+ ASSERT_FALSE(&CMBI == CI);
+ ASSERT_FALSE(CI == MBI);
+ ASSERT_FALSE(CI == &MBI);
+ ASSERT_FALSE(CI == CMBI);
+ ASSERT_FALSE(CI == &CMBI);
+ ASSERT_FALSE(MBI.getIterator() == I);
+ ASSERT_FALSE(CMBI.getIterator() == I);
+ ASSERT_FALSE(I == MBI.getIterator());
+ ASSERT_FALSE(I == CMBI.getIterator());
+ ASSERT_FALSE(MBI.getIterator() == CI);
+ ASSERT_FALSE(CMBI.getIterator() == CI);
+ ASSERT_FALSE(CI == MBI.getIterator());
+ ASSERT_FALSE(CI == CMBI.getIterator());
+ ASSERT_TRUE(MBI != I);
+ ASSERT_TRUE(&MBI != I);
+ ASSERT_TRUE(CMBI != I);
+ ASSERT_TRUE(&CMBI != I);
+ ASSERT_TRUE(I != MBI);
+ ASSERT_TRUE(I != &MBI);
+ ASSERT_TRUE(I != CMBI);
+ ASSERT_TRUE(I != &CMBI);
+ ASSERT_TRUE(MBI != CI);
+ ASSERT_TRUE(&MBI != CI);
+ ASSERT_TRUE(CMBI != CI);
+ ASSERT_TRUE(&CMBI != CI);
+ ASSERT_TRUE(CI != MBI);
+ ASSERT_TRUE(CI != &MBI);
+ ASSERT_TRUE(CI != CMBI);
+ ASSERT_TRUE(CI != &CMBI);
+ ASSERT_TRUE(MBI.getIterator() != I);
+ ASSERT_TRUE(CMBI.getIterator() != I);
+ ASSERT_TRUE(I != MBI.getIterator());
+ ASSERT_TRUE(I != CMBI.getIterator());
+ ASSERT_TRUE(MBI.getIterator() != CI);
+ ASSERT_TRUE(CMBI.getIterator() != CI);
+ ASSERT_TRUE(CI != MBI.getIterator());
+ ASSERT_TRUE(CI != CMBI.getIterator());
+}
+
+} // end namespace
diff --git a/unittests/DebugInfo/DWARF/CMakeLists.txt b/unittests/DebugInfo/DWARF/CMakeLists.txt
index 4bec17cbb524..eafca4a2fc06 100644
--- a/unittests/DebugInfo/DWARF/CMakeLists.txt
+++ b/unittests/DebugInfo/DWARF/CMakeLists.txt
@@ -1,8 +1,15 @@
set(LLVM_LINK_COMPONENTS
+ ${LLVM_TARGETS_TO_BUILD}
+ AsmPrinter
DebugInfoDWARF
+ MC
+ Object
+ Support
)
set(DebugInfoSources
+ DwarfGenerator.cpp
+ DWARFDebugInfoTest.cpp
DWARFFormValueTest.cpp
)
diff --git a/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp b/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp
new file mode 100644
index 000000000000..e2f4bb788dd0
--- /dev/null
+++ b/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp
@@ -0,0 +1,1087 @@
+//===- llvm/unittest/DebugInfo/DWARFFormValueTest.cpp ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DwarfGenerator.h"
+#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.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/Support/Dwarf.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/TargetSelect.h"
+#include "gtest/gtest.h"
+#include <climits>
+
+using namespace llvm;
+using namespace dwarf;
+
+namespace {
+
+void initLLVMIfNeeded() {
+ static bool gInitialized = false;
+ if (!gInitialized) {
+ gInitialized = true;
+ InitializeAllTargets();
+ InitializeAllTargetMCs();
+ InitializeAllAsmPrinters();
+ InitializeAllAsmParsers();
+ }
+}
+
+Triple getHostTripleForAddrSize(uint8_t AddrSize) {
+ Triple PT(Triple::normalize(LLVM_HOST_TRIPLE));
+
+ if (AddrSize == 8 && PT.isArch32Bit())
+ return PT.get64BitArchVariant();
+ if (AddrSize == 4 && PT.isArch64Bit())
+ return PT.get32BitArchVariant();
+ return PT;
+}
+
+/// Take any llvm::Expected and check and handle any errors.
+///
+/// \param Expected a llvm::Excepted instance to check.
+/// \returns true if there were errors, false otherwise.
+template <typename T>
+static bool HandleExpectedError(T &Expected) {
+ std::string ErrorMsg;
+ handleAllErrors(Expected.takeError(), [&](const llvm::ErrorInfoBase &EI) {
+ ErrorMsg = EI.message();
+ });
+ if (!ErrorMsg.empty()) {
+ ::testing::AssertionFailure() << "error: " << ErrorMsg;
+ return true;
+ }
+ return false;
+}
+
+template <uint16_t Version, class AddrType, class RefAddrType>
+void TestAllForms() {
+ // Test that we can decode all DW_FORM values correctly.
+
+ const uint8_t AddrSize = sizeof(AddrType);
+ const AddrType AddrValue = (AddrType)0x0123456789abcdefULL;
+ const uint8_t BlockData[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
+ const uint32_t BlockSize = sizeof(BlockData);
+ const RefAddrType RefAddr = 0x12345678;
+ const uint8_t Data1 = 0x01U;
+ const uint16_t Data2 = 0x2345U;
+ const uint32_t Data4 = 0x6789abcdU;
+ const uint64_t Data8 = 0x0011223344556677ULL;
+ const uint64_t Data8_2 = 0xAABBCCDDEEFF0011ULL;
+ const int64_t SData = INT64_MIN;
+ const uint64_t UData[] = {UINT64_MAX - 1, UINT64_MAX - 2, UINT64_MAX - 3,
+ UINT64_MAX - 4, UINT64_MAX - 5, UINT64_MAX - 6,
+ UINT64_MAX - 7, UINT64_MAX - 8, UINT64_MAX - 9};
+#define UDATA_1 18446744073709551614ULL
+ const uint32_t Dwarf32Values[] = {1, 2, 3, 4, 5, 6, 7, 8};
+ const char *StringValue = "Hello";
+ const char *StrpValue = "World";
+ 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();
+ uint16_t Attr = DW_AT_lo_user;
+
+ //----------------------------------------------------------------------
+ // Test address forms
+ //----------------------------------------------------------------------
+ const auto Attr_DW_FORM_addr = static_cast<dwarf::Attribute>(Attr++);
+ CUDie.addAttribute(Attr_DW_FORM_addr, DW_FORM_addr, AddrValue);
+
+ //----------------------------------------------------------------------
+ // Test block forms
+ //----------------------------------------------------------------------
+ const auto Attr_DW_FORM_block = static_cast<dwarf::Attribute>(Attr++);
+ CUDie.addAttribute(Attr_DW_FORM_block, DW_FORM_block, BlockData, BlockSize);
+
+ const auto Attr_DW_FORM_block1 = static_cast<dwarf::Attribute>(Attr++);
+ CUDie.addAttribute(Attr_DW_FORM_block1, DW_FORM_block1, BlockData, BlockSize);
+
+ const auto Attr_DW_FORM_block2 = static_cast<dwarf::Attribute>(Attr++);
+ CUDie.addAttribute(Attr_DW_FORM_block2, DW_FORM_block2, BlockData, BlockSize);
+
+ const auto Attr_DW_FORM_block4 = static_cast<dwarf::Attribute>(Attr++);
+ CUDie.addAttribute(Attr_DW_FORM_block4, DW_FORM_block4, BlockData, BlockSize);
+
+ //----------------------------------------------------------------------
+ // Test data forms
+ //----------------------------------------------------------------------
+ const auto Attr_DW_FORM_data1 = static_cast<dwarf::Attribute>(Attr++);
+ CUDie.addAttribute(Attr_DW_FORM_data1, DW_FORM_data1, Data1);
+
+ const auto Attr_DW_FORM_data2 = static_cast<dwarf::Attribute>(Attr++);
+ CUDie.addAttribute(Attr_DW_FORM_data2, DW_FORM_data2, Data2);
+
+ const auto Attr_DW_FORM_data4 = static_cast<dwarf::Attribute>(Attr++);
+ CUDie.addAttribute(Attr_DW_FORM_data4, DW_FORM_data4, Data4);
+
+ const auto Attr_DW_FORM_data8 = static_cast<dwarf::Attribute>(Attr++);
+ CUDie.addAttribute(Attr_DW_FORM_data8, DW_FORM_data8, Data8);
+
+ //----------------------------------------------------------------------
+ // Test string forms
+ //----------------------------------------------------------------------
+ const auto Attr_DW_FORM_string = static_cast<dwarf::Attribute>(Attr++);
+ CUDie.addAttribute(Attr_DW_FORM_string, DW_FORM_string, StringValue);
+
+ const auto Attr_DW_FORM_strp = static_cast<dwarf::Attribute>(Attr++);
+ CUDie.addAttribute(Attr_DW_FORM_strp, DW_FORM_strp, StrpValue);
+
+ //----------------------------------------------------------------------
+ // Test reference forms
+ //----------------------------------------------------------------------
+ const auto Attr_DW_FORM_ref_addr = static_cast<dwarf::Attribute>(Attr++);
+ CUDie.addAttribute(Attr_DW_FORM_ref_addr, DW_FORM_ref_addr, RefAddr);
+
+ const auto Attr_DW_FORM_ref1 = static_cast<dwarf::Attribute>(Attr++);
+ CUDie.addAttribute(Attr_DW_FORM_ref1, DW_FORM_ref1, Data1);
+
+ const auto Attr_DW_FORM_ref2 = static_cast<dwarf::Attribute>(Attr++);
+ CUDie.addAttribute(Attr_DW_FORM_ref2, DW_FORM_ref2, Data2);
+
+ const auto Attr_DW_FORM_ref4 = static_cast<dwarf::Attribute>(Attr++);
+ CUDie.addAttribute(Attr_DW_FORM_ref4, DW_FORM_ref4, Data4);
+
+ const auto Attr_DW_FORM_ref8 = static_cast<dwarf::Attribute>(Attr++);
+ CUDie.addAttribute(Attr_DW_FORM_ref8, DW_FORM_ref8, Data8);
+
+ const auto Attr_DW_FORM_ref_sig8 = static_cast<dwarf::Attribute>(Attr++);
+ CUDie.addAttribute(Attr_DW_FORM_ref_sig8, DW_FORM_ref_sig8, Data8_2);
+
+ const auto Attr_DW_FORM_ref_udata = static_cast<dwarf::Attribute>(Attr++);
+ CUDie.addAttribute(Attr_DW_FORM_ref_udata, DW_FORM_ref_udata, UData[0]);
+
+ //----------------------------------------------------------------------
+ // Test flag forms
+ //----------------------------------------------------------------------
+ const auto Attr_DW_FORM_flag_true = static_cast<dwarf::Attribute>(Attr++);
+ CUDie.addAttribute(Attr_DW_FORM_flag_true, DW_FORM_flag, true);
+
+ const auto Attr_DW_FORM_flag_false = static_cast<dwarf::Attribute>(Attr++);
+ CUDie.addAttribute(Attr_DW_FORM_flag_false, DW_FORM_flag, false);
+
+ const auto Attr_DW_FORM_flag_present = static_cast<dwarf::Attribute>(Attr++);
+ CUDie.addAttribute(Attr_DW_FORM_flag_present, DW_FORM_flag_present);
+
+ //----------------------------------------------------------------------
+ // Test SLEB128 based forms
+ //----------------------------------------------------------------------
+ const auto Attr_DW_FORM_sdata = static_cast<dwarf::Attribute>(Attr++);
+ CUDie.addAttribute(Attr_DW_FORM_sdata, DW_FORM_sdata, SData);
+
+ //----------------------------------------------------------------------
+ // Test ULEB128 based forms
+ //----------------------------------------------------------------------
+ const auto Attr_DW_FORM_udata = static_cast<dwarf::Attribute>(Attr++);
+ CUDie.addAttribute(Attr_DW_FORM_udata, DW_FORM_udata, UData[0]);
+
+ //----------------------------------------------------------------------
+ // Test DWARF32/DWARF64 forms
+ //----------------------------------------------------------------------
+ const auto Attr_DW_FORM_GNU_ref_alt = static_cast<dwarf::Attribute>(Attr++);
+ CUDie.addAttribute(Attr_DW_FORM_GNU_ref_alt, DW_FORM_GNU_ref_alt,
+ Dwarf32Values[0]);
+
+ const auto Attr_DW_FORM_sec_offset = static_cast<dwarf::Attribute>(Attr++);
+ CUDie.addAttribute(Attr_DW_FORM_sec_offset, DW_FORM_sec_offset,
+ Dwarf32Values[1]);
+
+ //----------------------------------------------------------------------
+ // Add an address at the end to make sure we can decode this value
+ //----------------------------------------------------------------------
+ const auto Attr_Last = static_cast<dwarf::Attribute>(Attr++);
+ CUDie.addAttribute(Attr_Last, DW_FORM_addr, AddrValue);
+
+ //----------------------------------------------------------------------
+ // Generate the DWARF
+ //----------------------------------------------------------------------
+ StringRef FileBytes = DG->generate();
+ MemoryBufferRef FileBuffer(FileBytes, "dwarf");
+ auto Obj = object::ObjectFile::createObjectFile(FileBuffer);
+ EXPECT_TRUE((bool)Obj);
+ DWARFContextInMemory DwarfContext(*Obj.get());
+ uint32_t NumCUs = DwarfContext.getNumCompileUnits();
+ EXPECT_EQ(NumCUs, 1u);
+ DWARFCompileUnit *U = DwarfContext.getCompileUnitAtIndex(0);
+ auto DieDG = U->getUnitDIE(false);
+ EXPECT_TRUE(DieDG.isValid());
+
+ //----------------------------------------------------------------------
+ // Test address forms
+ //----------------------------------------------------------------------
+ EXPECT_EQ(DieDG.getAttributeValueAsAddress(Attr_DW_FORM_addr, 0),
+ AddrValue);
+
+ //----------------------------------------------------------------------
+ // Test block forms
+ //----------------------------------------------------------------------
+ Optional<DWARFFormValue> FormValue;
+ ArrayRef<uint8_t> ExtractedBlockData;
+ Optional<ArrayRef<uint8_t>> BlockDataOpt;
+
+ FormValue = DieDG.getAttributeValue(Attr_DW_FORM_block);
+ EXPECT_TRUE((bool)FormValue);
+ BlockDataOpt = FormValue->getAsBlock();
+ EXPECT_TRUE(BlockDataOpt.hasValue());
+ ExtractedBlockData = BlockDataOpt.getValue();
+ EXPECT_EQ(ExtractedBlockData.size(), BlockSize);
+ EXPECT_TRUE(memcmp(ExtractedBlockData.data(), BlockData, BlockSize) == 0);
+
+ FormValue = DieDG.getAttributeValue(Attr_DW_FORM_block1);
+ EXPECT_TRUE((bool)FormValue);
+ BlockDataOpt = FormValue->getAsBlock();
+ EXPECT_TRUE(BlockDataOpt.hasValue());
+ ExtractedBlockData = BlockDataOpt.getValue();
+ EXPECT_EQ(ExtractedBlockData.size(), BlockSize);
+ EXPECT_TRUE(memcmp(ExtractedBlockData.data(), BlockData, BlockSize) == 0);
+
+ FormValue = DieDG.getAttributeValue(Attr_DW_FORM_block2);
+ EXPECT_TRUE((bool)FormValue);
+ BlockDataOpt = FormValue->getAsBlock();
+ EXPECT_TRUE(BlockDataOpt.hasValue());
+ ExtractedBlockData = BlockDataOpt.getValue();
+ EXPECT_EQ(ExtractedBlockData.size(), BlockSize);
+ EXPECT_TRUE(memcmp(ExtractedBlockData.data(), BlockData, BlockSize) == 0);
+
+ FormValue = DieDG.getAttributeValue(Attr_DW_FORM_block4);
+ EXPECT_TRUE((bool)FormValue);
+ BlockDataOpt = FormValue->getAsBlock();
+ EXPECT_TRUE(BlockDataOpt.hasValue());
+ ExtractedBlockData = BlockDataOpt.getValue();
+ EXPECT_EQ(ExtractedBlockData.size(), BlockSize);
+ EXPECT_TRUE(memcmp(ExtractedBlockData.data(), BlockData, BlockSize) == 0);
+
+ //----------------------------------------------------------------------
+ // Test data forms
+ //----------------------------------------------------------------------
+ EXPECT_EQ(
+ DieDG.getAttributeValueAsUnsignedConstant(Attr_DW_FORM_data1, 0),
+ Data1);
+ EXPECT_EQ(
+ DieDG.getAttributeValueAsUnsignedConstant(Attr_DW_FORM_data2, 0),
+ Data2);
+ EXPECT_EQ(
+ DieDG.getAttributeValueAsUnsignedConstant(Attr_DW_FORM_data4, 0),
+ Data4);
+ EXPECT_EQ(
+ DieDG.getAttributeValueAsUnsignedConstant(Attr_DW_FORM_data8, 0),
+ Data8);
+
+ //----------------------------------------------------------------------
+ // Test string forms
+ //----------------------------------------------------------------------
+ const char *ExtractedStringValue =
+ DieDG.getAttributeValueAsString(Attr_DW_FORM_string, nullptr);
+ EXPECT_TRUE(ExtractedStringValue != nullptr);
+ 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);
+
+ //----------------------------------------------------------------------
+ // Test reference forms
+ //----------------------------------------------------------------------
+ EXPECT_EQ(DieDG.getAttributeValueAsReference(Attr_DW_FORM_ref_addr, 0),
+ RefAddr);
+ EXPECT_EQ(DieDG.getAttributeValueAsReference(Attr_DW_FORM_ref1, 0),
+ Data1);
+ EXPECT_EQ(DieDG.getAttributeValueAsReference(Attr_DW_FORM_ref2, 0),
+ Data2);
+ EXPECT_EQ(DieDG.getAttributeValueAsReference(Attr_DW_FORM_ref4, 0),
+ Data4);
+ EXPECT_EQ(DieDG.getAttributeValueAsReference(Attr_DW_FORM_ref8, 0),
+ Data8);
+ EXPECT_EQ(DieDG.getAttributeValueAsReference(Attr_DW_FORM_ref_sig8, 0),
+ Data8_2);
+ EXPECT_EQ(DieDG.getAttributeValueAsReference(Attr_DW_FORM_ref_udata, 0),
+ UData[0]);
+
+ //----------------------------------------------------------------------
+ // Test flag forms
+ //----------------------------------------------------------------------
+ EXPECT_EQ(DieDG.getAttributeValueAsUnsignedConstant(
+ Attr_DW_FORM_flag_true, 0ULL),
+ 1ULL);
+ EXPECT_EQ(DieDG.getAttributeValueAsUnsignedConstant(
+ Attr_DW_FORM_flag_false, 1ULL),
+ 0ULL);
+ EXPECT_EQ(DieDG.getAttributeValueAsUnsignedConstant(
+ Attr_DW_FORM_flag_present, 0ULL),
+ 1ULL);
+
+ // TODO: test Attr_DW_FORM_implicit_const extraction
+
+ //----------------------------------------------------------------------
+ // Test SLEB128 based forms
+ //----------------------------------------------------------------------
+ EXPECT_EQ(DieDG.getAttributeValueAsSignedConstant(Attr_DW_FORM_sdata, 0),
+ SData);
+
+ //----------------------------------------------------------------------
+ // Test ULEB128 based forms
+ //----------------------------------------------------------------------
+ EXPECT_EQ(
+ DieDG.getAttributeValueAsUnsignedConstant(Attr_DW_FORM_udata, 0),
+ UData[0]);
+
+ //----------------------------------------------------------------------
+ // Test DWARF32/DWARF64 forms
+ //----------------------------------------------------------------------
+ EXPECT_EQ(
+ DieDG.getAttributeValueAsReference(Attr_DW_FORM_GNU_ref_alt, 0),
+ Dwarf32Values[0]);
+ EXPECT_EQ(
+ DieDG.getAttributeValueAsSectionOffset(Attr_DW_FORM_sec_offset, 0),
+ Dwarf32Values[1]);
+
+ //----------------------------------------------------------------------
+ // Add an address at the end to make sure we can decode this value
+ //----------------------------------------------------------------------
+ EXPECT_EQ(DieDG.getAttributeValueAsAddress(Attr_Last, 0), AddrValue);
+}
+
+TEST(DWARFDebugInfo, TestDWARF32Version2Addr4AllForms) {
+ // Test that we can decode all forms for DWARF32, version 2, with 4 byte
+ // addresses.
+ typedef uint32_t AddrType;
+ // DW_FORM_ref_addr are the same as the address type in DWARF32 version 2.
+ typedef AddrType RefAddrType;
+ TestAllForms<2, AddrType, RefAddrType>();
+}
+
+TEST(DWARFDebugInfo, TestDWARF32Version2Addr8AllForms) {
+ // Test that we can decode all forms for DWARF32, version 2, with 4 byte
+ // addresses.
+ typedef uint64_t AddrType;
+ // DW_FORM_ref_addr are the same as the address type in DWARF32 version 2.
+ typedef AddrType RefAddrType;
+ TestAllForms<2, AddrType, RefAddrType>();
+}
+
+TEST(DWARFDebugInfo, TestDWARF32Version3Addr4AllForms) {
+ // Test that we can decode all forms for DWARF32, version 3, with 4 byte
+ // addresses.
+ typedef uint32_t AddrType;
+ // DW_FORM_ref_addr are 4 bytes in DWARF32 for version 3 and later.
+ typedef uint32_t RefAddrType;
+ TestAllForms<3, AddrType, RefAddrType>();
+}
+
+TEST(DWARFDebugInfo, TestDWARF32Version3Addr8AllForms) {
+ // Test that we can decode all forms for DWARF32, version 3, with 8 byte
+ // addresses.
+ typedef uint64_t AddrType;
+ // DW_FORM_ref_addr are 4 bytes in DWARF32 for version 3 and later
+ typedef uint32_t RefAddrType;
+ TestAllForms<3, AddrType, RefAddrType>();
+}
+
+TEST(DWARFDebugInfo, TestDWARF32Version4Addr4AllForms) {
+ // Test that we can decode all forms for DWARF32, version 4, with 4 byte
+ // addresses.
+ typedef uint32_t AddrType;
+ // DW_FORM_ref_addr are 4 bytes in DWARF32 for version 3 and later
+ typedef uint32_t RefAddrType;
+ TestAllForms<4, AddrType, RefAddrType>();
+}
+
+TEST(DWARFDebugInfo, TestDWARF32Version4Addr8AllForms) {
+ // Test that we can decode all forms for DWARF32, version 4, with 8 byte
+ // addresses.
+ typedef uint64_t AddrType;
+ // DW_FORM_ref_addr are 4 bytes in DWARF32 for version 3 and later
+ typedef uint32_t RefAddrType;
+ TestAllForms<4, AddrType, RefAddrType>();
+}
+
+template <uint16_t Version, class AddrType> void TestChildren() {
+ // Test that we can decode DW_FORM_ref_addr values correctly in DWARF 2 with
+ // 4 byte addresses. DW_FORM_ref_addr values should be 4 bytes when using
+ // 8 byte addresses.
+
+ const uint8_t AddrSize = sizeof(AddrType);
+ 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();
+
+ CUDie.addAttribute(DW_AT_name, DW_FORM_strp, "/tmp/main.c");
+ CUDie.addAttribute(DW_AT_language, DW_FORM_data2, DW_LANG_C);
+
+ dwarfgen::DIE SubprogramDie = CUDie.addChild(DW_TAG_subprogram);
+ SubprogramDie.addAttribute(DW_AT_name, DW_FORM_strp, "main");
+ SubprogramDie.addAttribute(DW_AT_low_pc, DW_FORM_addr, 0x1000U);
+ SubprogramDie.addAttribute(DW_AT_high_pc, DW_FORM_addr, 0x2000U);
+
+ dwarfgen::DIE IntDie = CUDie.addChild(DW_TAG_base_type);
+ IntDie.addAttribute(DW_AT_name, DW_FORM_strp, "int");
+ IntDie.addAttribute(DW_AT_encoding, DW_FORM_data1, DW_ATE_signed);
+ IntDie.addAttribute(DW_AT_byte_size, DW_FORM_data1, 4);
+
+ dwarfgen::DIE ArgcDie = SubprogramDie.addChild(DW_TAG_formal_parameter);
+ ArgcDie.addAttribute(DW_AT_name, DW_FORM_strp, "argc");
+ // ArgcDie.addAttribute(DW_AT_type, DW_FORM_ref4, IntDie);
+ ArgcDie.addAttribute(DW_AT_type, DW_FORM_ref_addr, IntDie);
+
+ StringRef FileBytes = DG->generate();
+ MemoryBufferRef FileBuffer(FileBytes, "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 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();
+ EXPECT_TRUE(SubprogramDieDG.isValid());
+ EXPECT_EQ(SubprogramDieDG.getTag(), DW_TAG_subprogram);
+
+ // Verify the first child of the subprogram is our formal parameter.
+ auto ArgcDieDG = SubprogramDieDG.getFirstChild();
+ EXPECT_TRUE(ArgcDieDG.isValid());
+ EXPECT_EQ(ArgcDieDG.getTag(), DW_TAG_formal_parameter);
+
+ // Verify our formal parameter has a NULL tag sibling.
+ auto NullDieDG = ArgcDieDG.getSibling();
+ EXPECT_TRUE(NullDieDG.isValid());
+ if (NullDieDG) {
+ EXPECT_EQ(NullDieDG.getTag(), DW_TAG_null);
+ EXPECT_TRUE(!NullDieDG.getSibling().isValid());
+ EXPECT_TRUE(!NullDieDG.getFirstChild().isValid());
+ }
+
+ // Verify the sibling of our subprogram is our integer base type.
+ auto IntDieDG = SubprogramDieDG.getSibling();
+ EXPECT_TRUE(IntDieDG.isValid());
+ EXPECT_EQ(IntDieDG.getTag(), DW_TAG_base_type);
+
+ // Verify the sibling of our subprogram is our integer base is a NULL tag.
+ NullDieDG = IntDieDG.getSibling();
+ EXPECT_TRUE(NullDieDG.isValid());
+ if (NullDieDG) {
+ EXPECT_EQ(NullDieDG.getTag(), DW_TAG_null);
+ EXPECT_TRUE(!NullDieDG.getSibling().isValid());
+ EXPECT_TRUE(!NullDieDG.getFirstChild().isValid());
+ }
+}
+
+TEST(DWARFDebugInfo, TestDWARF32Version2Addr4Children) {
+ // Test that we can decode all forms for DWARF32, version 2, with 4 byte
+ // addresses.
+ typedef uint32_t AddrType;
+ TestChildren<2, AddrType>();
+}
+
+TEST(DWARFDebugInfo, TestDWARF32Version2Addr8Children) {
+ // Test that we can decode all forms for DWARF32, version 2, with 8 byte
+ // addresses.
+ typedef uint64_t AddrType;
+ TestChildren<2, AddrType>();
+}
+
+TEST(DWARFDebugInfo, TestDWARF32Version3Addr4Children) {
+ // Test that we can decode all forms for DWARF32, version 3, with 4 byte
+ // addresses.
+ typedef uint32_t AddrType;
+ TestChildren<3, AddrType>();
+}
+
+TEST(DWARFDebugInfo, TestDWARF32Version3Addr8Children) {
+ // Test that we can decode all forms for DWARF32, version 3, with 8 byte
+ // addresses.
+ typedef uint64_t AddrType;
+ TestChildren<3, AddrType>();
+}
+
+TEST(DWARFDebugInfo, TestDWARF32Version4Addr4Children) {
+ // Test that we can decode all forms for DWARF32, version 4, with 4 byte
+ // addresses.
+ typedef uint32_t AddrType;
+ TestChildren<4, AddrType>();
+}
+
+TEST(DWARFDebugInfo, TestDWARF32Version4Addr8Children) {
+ // Test that we can decode all forms for DWARF32, version 4, with 8 byte
+ // addresses.
+ typedef uint64_t AddrType;
+ TestChildren<4, AddrType>();
+}
+
+template <uint16_t Version, class AddrType> void TestReferences() {
+ // Test that we can decode DW_FORM_refXXX values correctly in DWARF.
+
+ const uint8_t AddrSize = sizeof(AddrType);
+ initLLVMIfNeeded();
+ Triple Triple = getHostTripleForAddrSize(AddrSize);
+ auto ExpectedDG = dwarfgen::Generator::create(Triple, Version);
+ if (HandleExpectedError(ExpectedDG))
+ return;
+ dwarfgen::Generator *DG = ExpectedDG.get().get();
+ dwarfgen::CompileUnit &CU1 = DG->addCompileUnit();
+ dwarfgen::CompileUnit &CU2 = DG->addCompileUnit();
+
+ dwarfgen::DIE CU1Die = CU1.getUnitDIE();
+ CU1Die.addAttribute(DW_AT_name, DW_FORM_strp, "/tmp/main.c");
+ CU1Die.addAttribute(DW_AT_language, DW_FORM_data2, DW_LANG_C);
+
+ dwarfgen::DIE CU1TypeDie = CU1Die.addChild(DW_TAG_base_type);
+ CU1TypeDie.addAttribute(DW_AT_name, DW_FORM_strp, "int");
+ CU1TypeDie.addAttribute(DW_AT_encoding, DW_FORM_data1, DW_ATE_signed);
+ CU1TypeDie.addAttribute(DW_AT_byte_size, DW_FORM_data1, 4);
+
+ dwarfgen::DIE CU1Ref1Die = CU1Die.addChild(DW_TAG_variable);
+ CU1Ref1Die.addAttribute(DW_AT_name, DW_FORM_strp, "CU1Ref1");
+ CU1Ref1Die.addAttribute(DW_AT_type, DW_FORM_ref1, CU1TypeDie);
+
+ dwarfgen::DIE CU1Ref2Die = CU1Die.addChild(DW_TAG_variable);
+ CU1Ref2Die.addAttribute(DW_AT_name, DW_FORM_strp, "CU1Ref2");
+ CU1Ref2Die.addAttribute(DW_AT_type, DW_FORM_ref2, CU1TypeDie);
+
+ dwarfgen::DIE CU1Ref4Die = CU1Die.addChild(DW_TAG_variable);
+ CU1Ref4Die.addAttribute(DW_AT_name, DW_FORM_strp, "CU1Ref4");
+ CU1Ref4Die.addAttribute(DW_AT_type, DW_FORM_ref4, CU1TypeDie);
+
+ dwarfgen::DIE CU1Ref8Die = CU1Die.addChild(DW_TAG_variable);
+ CU1Ref8Die.addAttribute(DW_AT_name, DW_FORM_strp, "CU1Ref8");
+ CU1Ref8Die.addAttribute(DW_AT_type, DW_FORM_ref8, CU1TypeDie);
+
+ dwarfgen::DIE CU1RefAddrDie = CU1Die.addChild(DW_TAG_variable);
+ CU1RefAddrDie.addAttribute(DW_AT_name, DW_FORM_strp, "CU1RefAddr");
+ CU1RefAddrDie.addAttribute(DW_AT_type, DW_FORM_ref_addr, CU1TypeDie);
+
+ dwarfgen::DIE CU2Die = CU2.getUnitDIE();
+ CU2Die.addAttribute(DW_AT_name, DW_FORM_strp, "/tmp/foo.c");
+ CU2Die.addAttribute(DW_AT_language, DW_FORM_data2, DW_LANG_C);
+
+ dwarfgen::DIE CU2TypeDie = CU2Die.addChild(DW_TAG_base_type);
+ CU2TypeDie.addAttribute(DW_AT_name, DW_FORM_strp, "float");
+ CU2TypeDie.addAttribute(DW_AT_encoding, DW_FORM_data1, DW_ATE_float);
+ CU2TypeDie.addAttribute(DW_AT_byte_size, DW_FORM_data1, 4);
+
+ dwarfgen::DIE CU2Ref1Die = CU2Die.addChild(DW_TAG_variable);
+ CU2Ref1Die.addAttribute(DW_AT_name, DW_FORM_strp, "CU2Ref1");
+ CU2Ref1Die.addAttribute(DW_AT_type, DW_FORM_ref1, CU2TypeDie);
+
+ dwarfgen::DIE CU2Ref2Die = CU2Die.addChild(DW_TAG_variable);
+ CU2Ref2Die.addAttribute(DW_AT_name, DW_FORM_strp, "CU2Ref2");
+ CU2Ref2Die.addAttribute(DW_AT_type, DW_FORM_ref2, CU2TypeDie);
+
+ dwarfgen::DIE CU2Ref4Die = CU2Die.addChild(DW_TAG_variable);
+ CU2Ref4Die.addAttribute(DW_AT_name, DW_FORM_strp, "CU2Ref4");
+ CU2Ref4Die.addAttribute(DW_AT_type, DW_FORM_ref4, CU2TypeDie);
+
+ dwarfgen::DIE CU2Ref8Die = CU2Die.addChild(DW_TAG_variable);
+ CU2Ref8Die.addAttribute(DW_AT_name, DW_FORM_strp, "CU2Ref8");
+ CU2Ref8Die.addAttribute(DW_AT_type, DW_FORM_ref8, CU2TypeDie);
+
+ dwarfgen::DIE CU2RefAddrDie = CU2Die.addChild(DW_TAG_variable);
+ CU2RefAddrDie.addAttribute(DW_AT_name, DW_FORM_strp, "CU2RefAddr");
+ CU2RefAddrDie.addAttribute(DW_AT_type, DW_FORM_ref_addr, CU2TypeDie);
+
+ // Refer to a type in CU1 from CU2
+ dwarfgen::DIE CU2ToCU1RefAddrDie = CU2Die.addChild(DW_TAG_variable);
+ CU2ToCU1RefAddrDie.addAttribute(DW_AT_name, DW_FORM_strp, "CU2ToCU1RefAddr");
+ CU2ToCU1RefAddrDie.addAttribute(DW_AT_type, DW_FORM_ref_addr, CU1TypeDie);
+
+ // Refer to a type in CU2 from CU1
+ dwarfgen::DIE CU1ToCU2RefAddrDie = CU1Die.addChild(DW_TAG_variable);
+ CU1ToCU2RefAddrDie.addAttribute(DW_AT_name, DW_FORM_strp, "CU1ToCU2RefAddr");
+ CU1ToCU2RefAddrDie.addAttribute(DW_AT_type, DW_FORM_ref_addr, CU2TypeDie);
+
+ StringRef FileBytes = DG->generate();
+ MemoryBufferRef FileBuffer(FileBytes, "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, 2u);
+ DWARFCompileUnit *U1 = DwarfContext.getCompileUnitAtIndex(0);
+ DWARFCompileUnit *U2 = DwarfContext.getCompileUnitAtIndex(1);
+
+ // 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, 0),
+ DW_ATE_signed);
+
+ // 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, 0),
+ DW_ATE_float);
+
+ // 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, -1ULL),
+ CU1TypeDieDG.getOffset());
+ // 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, -1ULL),
+ CU1TypeDieDG.getOffset());
+
+ // 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, -1ULL),
+ CU1TypeDieDG.getOffset());
+
+ // 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, -1ULL),
+ CU1TypeDieDG.getOffset());
+
+ // 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, -1ULL),
+ CU1TypeDieDG.getOffset());
+
+ // 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,
+ -1ULL),
+ CU2TypeDieDG.getOffset());
+
+ // 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, -1ULL),
+ CU2TypeDieDG.getOffset());
+ // 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, -1ULL),
+ CU2TypeDieDG.getOffset());
+
+ // 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, -1ULL),
+ CU2TypeDieDG.getOffset());
+
+ // 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, -1ULL),
+ CU2TypeDieDG.getOffset());
+
+ // 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, -1ULL),
+ CU2TypeDieDG.getOffset());
+
+ // 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,
+ -1ULL),
+ CU1TypeDieDG.getOffset());
+}
+
+TEST(DWARFDebugInfo, TestDWARF32Version2Addr4References) {
+ // Test that we can decode all forms for DWARF32, version 2, with 4 byte
+ // addresses.
+ typedef uint32_t AddrType;
+ TestReferences<2, AddrType>();
+}
+
+TEST(DWARFDebugInfo, TestDWARF32Version2Addr8References) {
+ // Test that we can decode all forms for DWARF32, version 2, with 8 byte
+ // addresses.
+ typedef uint64_t AddrType;
+ TestReferences<2, AddrType>();
+}
+
+TEST(DWARFDebugInfo, TestDWARF32Version3Addr4References) {
+ // Test that we can decode all forms for DWARF32, version 3, with 4 byte
+ // addresses.
+ typedef uint32_t AddrType;
+ TestReferences<3, AddrType>();
+}
+
+TEST(DWARFDebugInfo, TestDWARF32Version3Addr8References) {
+ // Test that we can decode all forms for DWARF32, version 3, with 8 byte
+ // addresses.
+ typedef uint64_t AddrType;
+ TestReferences<3, AddrType>();
+}
+
+TEST(DWARFDebugInfo, TestDWARF32Version4Addr4References) {
+ // Test that we can decode all forms for DWARF32, version 4, with 4 byte
+ // addresses.
+ typedef uint32_t AddrType;
+ TestReferences<4, AddrType>();
+}
+
+TEST(DWARFDebugInfo, TestDWARF32Version4Addr8References) {
+ // Test that we can decode all forms for DWARF32, version 4, with 8 byte
+ // addresses.
+ typedef uint64_t AddrType;
+ TestReferences<4, AddrType>();
+}
+
+template <uint16_t Version, class AddrType> void TestAddresses() {
+ // Test the DWARF APIs related to accessing the DW_AT_low_pc and
+ // DW_AT_high_pc.
+ const uint8_t AddrSize = sizeof(AddrType);
+ const bool SupportsHighPCAsOffset = Version >= 4;
+ 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();
+
+ CUDie.addAttribute(DW_AT_name, DW_FORM_strp, "/tmp/main.c");
+ CUDie.addAttribute(DW_AT_language, DW_FORM_data2, DW_LANG_C);
+
+ // Create a subprogram DIE with no low or high PC.
+ dwarfgen::DIE SubprogramNoPC = CUDie.addChild(DW_TAG_subprogram);
+ SubprogramNoPC.addAttribute(DW_AT_name, DW_FORM_strp, "no_pc");
+
+ // Create a subprogram DIE with a low PC only.
+ dwarfgen::DIE SubprogramLowPC = CUDie.addChild(DW_TAG_subprogram);
+ SubprogramLowPC.addAttribute(DW_AT_name, DW_FORM_strp, "low_pc");
+ const uint64_t ActualLowPC = 0x1000;
+ const uint64_t ActualHighPC = 0x2000;
+ const uint64_t ActualHighPCOffset = ActualHighPC - ActualLowPC;
+ SubprogramLowPC.addAttribute(DW_AT_low_pc, DW_FORM_addr, ActualLowPC);
+
+ // Create a subprogram DIE with a low and high PC.
+ dwarfgen::DIE SubprogramLowHighPC = CUDie.addChild(DW_TAG_subprogram);
+ SubprogramLowHighPC.addAttribute(DW_AT_name, DW_FORM_strp, "low_high_pc");
+ SubprogramLowHighPC.addAttribute(DW_AT_low_pc, DW_FORM_addr, ActualLowPC);
+ // Encode the high PC as an offset from the low PC if supported.
+ if (SupportsHighPCAsOffset)
+ SubprogramLowHighPC.addAttribute(DW_AT_high_pc, DW_FORM_data4,
+ ActualHighPCOffset);
+ else
+ SubprogramLowHighPC.addAttribute(DW_AT_high_pc, DW_FORM_addr, ActualHighPC);
+
+ StringRef FileBytes = DG->generate();
+ MemoryBufferRef FileBuffer(FileBytes, "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 DieDG = U->getUnitDIE(false);
+ EXPECT_TRUE(DieDG.isValid());
+ // DieDG.dump(llvm::outs(), U, UINT32_MAX);
+
+ uint64_t LowPC, HighPC;
+ Optional<uint64_t> OptU64;
+ // Verify the that our subprogram with no PC value fails appropriately when
+ // asked for any PC values.
+ auto SubprogramDieNoPC = DieDG.getFirstChild();
+ EXPECT_TRUE(SubprogramDieNoPC.isValid());
+ EXPECT_EQ(SubprogramDieNoPC.getTag(), DW_TAG_subprogram);
+ OptU64 = SubprogramDieNoPC.getAttributeValueAsAddress(DW_AT_low_pc);
+ EXPECT_FALSE((bool)OptU64);
+ OptU64 = SubprogramDieNoPC.getAttributeValueAsAddress(DW_AT_high_pc);
+ EXPECT_FALSE((bool)OptU64);
+ EXPECT_FALSE(SubprogramDieNoPC.getLowAndHighPC(LowPC, HighPC));
+ OptU64 = SubprogramDieNoPC.getAttributeValueAsAddress(DW_AT_high_pc);
+ EXPECT_FALSE((bool)OptU64);
+ OptU64 = SubprogramDieNoPC.getAttributeValueAsUnsignedConstant(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);
+ EXPECT_TRUE((bool)OptU64);
+ EXPECT_EQ(OptU64.getValue(), ActualLowPC);
+ OptU64 = SubprogramDieLowPC.getAttributeValueAsAddress(DW_AT_high_pc);
+ EXPECT_FALSE((bool)OptU64);
+ OptU64 = SubprogramDieLowPC.getAttributeValueAsUnsignedConstant(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);
+ 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);
+ if (SupportsHighPCAsOffset) {
+ EXPECT_FALSE((bool)OptU64);
+ } else {
+ EXPECT_TRUE((bool)OptU64);
+ EXPECT_EQ(OptU64.getValue(), ActualHighPC);
+ }
+ // 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);
+ if (SupportsHighPCAsOffset) {
+ EXPECT_TRUE((bool)OptU64);
+ EXPECT_EQ(OptU64.getValue(), ActualHighPCOffset);
+ } else {
+ EXPECT_FALSE((bool)OptU64);
+ }
+
+ OptU64 = SubprogramDieLowHighPC.getHighPC(ActualLowPC);
+ EXPECT_TRUE((bool)OptU64);
+ EXPECT_EQ(OptU64.getValue(), ActualHighPC);
+
+ EXPECT_TRUE(SubprogramDieLowHighPC.getLowAndHighPC(LowPC, HighPC));
+ EXPECT_EQ(LowPC, ActualLowPC);
+ EXPECT_EQ(HighPC, ActualHighPC);
+}
+
+TEST(DWARFDebugInfo, TestDWARF32Version2Addr4Addresses) {
+ // Test that we can decode address values in DWARF32, version 2, with 4 byte
+ // addresses.
+ typedef uint32_t AddrType;
+ TestAddresses<2, AddrType>();
+}
+
+TEST(DWARFDebugInfo, TestDWARF32Version2Addr8Addresses) {
+ // Test that we can decode address values in DWARF32, version 2, with 8 byte
+ // addresses.
+ typedef uint64_t AddrType;
+ TestAddresses<2, AddrType>();
+}
+
+TEST(DWARFDebugInfo, TestDWARF32Version3Addr4Addresses) {
+ // Test that we can decode address values in DWARF32, version 3, with 4 byte
+ // addresses.
+ typedef uint32_t AddrType;
+ TestAddresses<3, AddrType>();
+}
+
+TEST(DWARFDebugInfo, TestDWARF32Version3Addr8Addresses) {
+ // Test that we can decode address values in DWARF32, version 3, with 8 byte
+ // addresses.
+ typedef uint64_t AddrType;
+ TestAddresses<3, AddrType>();
+}
+
+TEST(DWARFDebugInfo, TestDWARF32Version4Addr4Addresses) {
+ // Test that we can decode address values in DWARF32, version 4, with 4 byte
+ // addresses.
+ typedef uint32_t AddrType;
+ TestAddresses<4, AddrType>();
+}
+
+TEST(DWARFDebugInfo, TestDWARF32Version4Addr8Addresses) {
+ // Test that we can decode address values in DWARF32, version 4, with 8 byte
+ // addresses.
+ typedef uint64_t AddrType;
+ TestAddresses<4, AddrType>();
+}
+
+TEST(DWARFDebugInfo, TestRelations) {
+ // Test the DWARF APIs related to accessing the DW_AT_low_pc and
+ // DW_AT_high_pc.
+ 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();
+
+ enum class Tag: uint16_t {
+ A = dwarf::DW_TAG_lo_user,
+ B,
+ B1,
+ B2,
+ C,
+ C1
+ };
+
+ // Scope to allow us to re-use the same DIE names
+ {
+ // Create DWARF tree that looks like:
+ //
+ // CU
+ // A
+ // B
+ // B1
+ // B2
+ // C
+ // C1
+ dwarfgen::DIE CUDie = CU.getUnitDIE();
+ CUDie.addChild((dwarf::Tag)Tag::A);
+ dwarfgen::DIE B = CUDie.addChild((dwarf::Tag)Tag::B);
+ dwarfgen::DIE C = CUDie.addChild((dwarf::Tag)Tag::C);
+ B.addChild((dwarf::Tag)Tag::B1);
+ B.addChild((dwarf::Tag)Tag::B2);
+ C.addChild((dwarf::Tag)Tag::C1);
+ }
+
+ 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());
+ // DieDG.dump(llvm::outs(), U, UINT32_MAX);
+
+ // The compile unit doesn't have a parent or a sibling.
+ auto ParentDie = CUDie.getParent();
+ EXPECT_FALSE(ParentDie.isValid());
+ auto SiblingDie = CUDie.getSibling();
+ EXPECT_FALSE(SiblingDie.isValid());
+
+ // Get the children of the compile unit
+ auto A = CUDie.getFirstChild();
+ auto B = A.getSibling();
+ auto C = B.getSibling();
+ auto Null = C.getSibling();
+
+ // Verify NULL Die is NULL and has no children or siblings
+ EXPECT_TRUE(Null.isNULL());
+ EXPECT_FALSE(Null.getSibling().isValid());
+ EXPECT_FALSE(Null.getFirstChild().isValid());
+
+ // Verify all children of the compile unit DIE are correct.
+ EXPECT_EQ(A.getTag(), (dwarf::Tag)Tag::A);
+ EXPECT_EQ(B.getTag(), (dwarf::Tag)Tag::B);
+ EXPECT_EQ(C.getTag(), (dwarf::Tag)Tag::C);
+
+ // Verify who has children
+ EXPECT_FALSE(A.hasChildren());
+ EXPECT_TRUE(B.hasChildren());
+
+ // Make sure the parent of all the children of the compile unit are the
+ // compile unit.
+ EXPECT_EQ(A.getParent(), CUDie);
+ EXPECT_EQ(B.getParent(), CUDie);
+ EXPECT_EQ(Null.getParent(), CUDie);
+
+ EXPECT_FALSE(A.getFirstChild().isValid());
+
+ // Verify the children of the B DIE
+ auto B1 = B.getFirstChild();
+ auto B2 = B1.getSibling();
+ EXPECT_TRUE(B2.getSibling().isNULL());
+
+ // Verify all children of the B DIE correctly valid or invalid.
+ EXPECT_EQ(B1.getTag(), (dwarf::Tag)Tag::B1);
+ EXPECT_EQ(B2.getTag(), (dwarf::Tag)Tag::B2);
+
+ // Make sure the parent of all the children of the B are the B.
+ EXPECT_EQ(B1.getParent(), B);
+ EXPECT_EQ(B2.getParent(), B);
+}
+
+TEST(DWARFDebugInfo, TestDWARFDie) {
+
+ // Make sure a default constructed DWARFDie doesn't have any parent, sibling
+ // or child;
+ DWARFDie DefaultDie;
+ EXPECT_FALSE(DefaultDie.getParent().isValid());
+ EXPECT_FALSE(DefaultDie.getFirstChild().isValid());
+ EXPECT_FALSE(DefaultDie.getSibling().isValid());
+}
+
+
+} // end anonymous namespace
diff --git a/unittests/DebugInfo/DWARF/DWARFFormValueTest.cpp b/unittests/DebugInfo/DWARF/DWARFFormValueTest.cpp
index eb9607ade16d..028a03595de6 100644
--- a/unittests/DebugInfo/DWARF/DWARFFormValueTest.cpp
+++ b/unittests/DebugInfo/DWARF/DWARFFormValueTest.cpp
@@ -21,19 +21,50 @@ using namespace dwarf;
namespace {
TEST(DWARFFormValue, FixedFormSizes) {
- // Size of DW_FORM_addr and DW_FORM_ref_addr are equal in DWARF2,
- // DW_FORM_ref_addr is always 4 bytes in DWARF32 starting from DWARF3.
- ArrayRef<uint8_t> sizes = DWARFFormValue::getFixedFormSizes(4, 2);
- EXPECT_EQ(sizes[DW_FORM_addr], sizes[DW_FORM_ref_addr]);
- sizes = DWARFFormValue::getFixedFormSizes(8, 2);
- EXPECT_EQ(sizes[DW_FORM_addr], sizes[DW_FORM_ref_addr]);
- sizes = DWARFFormValue::getFixedFormSizes(8, 3);
- EXPECT_EQ(4, sizes[DW_FORM_ref_addr]);
- // Check that we don't have fixed form sizes for weird address sizes.
- EXPECT_EQ(0U, DWARFFormValue::getFixedFormSizes(16, 2).size());
+ Optional<uint8_t> RefSize;
+ Optional<uint8_t> AddrSize;
+ // Test 32 bit DWARF version 2 with 4 byte addresses.
+ RefSize = DWARFFormValue::getFixedByteSize(DW_FORM_ref_addr, 2, 4, DWARF32);
+ AddrSize = DWARFFormValue::getFixedByteSize(DW_FORM_ref_addr, 2, 4, DWARF32);
+ EXPECT_TRUE(RefSize.hasValue());
+ EXPECT_TRUE(AddrSize.hasValue());
+ EXPECT_EQ(*RefSize, *AddrSize);
+
+ // Test 32 bit DWARF version 2 with 8 byte addresses.
+ RefSize = DWARFFormValue::getFixedByteSize(DW_FORM_ref_addr, 2, 8, DWARF32);
+ AddrSize = DWARFFormValue::getFixedByteSize(DW_FORM_ref_addr, 2, 8, DWARF32);
+ EXPECT_TRUE(RefSize.hasValue());
+ EXPECT_TRUE(AddrSize.hasValue());
+ EXPECT_EQ(*RefSize, *AddrSize);
+
+ // DW_FORM_ref_addr is 4 bytes in DWARF 32 in DWARF version 3 and beyond.
+ RefSize = DWARFFormValue::getFixedByteSize(DW_FORM_ref_addr, 3, 4, DWARF32);
+ EXPECT_TRUE(RefSize.hasValue());
+ EXPECT_EQ(*RefSize, 4);
+
+ RefSize = DWARFFormValue::getFixedByteSize(DW_FORM_ref_addr, 4, 4, DWARF32);
+ EXPECT_TRUE(RefSize.hasValue());
+ EXPECT_EQ(*RefSize, 4);
+
+ RefSize = DWARFFormValue::getFixedByteSize(DW_FORM_ref_addr, 5, 4, DWARF32);
+ EXPECT_TRUE(RefSize.hasValue());
+ EXPECT_EQ(*RefSize, 4);
+
+ // DW_FORM_ref_addr is 8 bytes in DWARF 64 in DWARF version 3 and beyond.
+ RefSize = DWARFFormValue::getFixedByteSize(DW_FORM_ref_addr, 3, 8, DWARF64);
+ EXPECT_TRUE(RefSize.hasValue());
+ EXPECT_EQ(*RefSize, 8);
+
+ RefSize = DWARFFormValue::getFixedByteSize(DW_FORM_ref_addr, 4, 8, DWARF64);
+ EXPECT_TRUE(RefSize.hasValue());
+ EXPECT_EQ(*RefSize, 8);
+
+ RefSize = DWARFFormValue::getFixedByteSize(DW_FORM_ref_addr, 5, 8, DWARF64);
+ EXPECT_TRUE(RefSize.hasValue());
+ EXPECT_EQ(*RefSize, 8);
}
-bool isFormClass(uint16_t Form, DWARFFormValue::FormClass FC) {
+bool isFormClass(dwarf::Form Form, DWARFFormValue::FormClass FC) {
return DWARFFormValue(Form).isFormClass(FC);
}
@@ -52,7 +83,7 @@ TEST(DWARFFormValue, FormClass) {
}
template<typename RawTypeT>
-DWARFFormValue createDataXFormValue(uint16_t Form, RawTypeT Value) {
+DWARFFormValue createDataXFormValue(dwarf::Form Form, RawTypeT Value) {
char Raw[sizeof(RawTypeT)];
memcpy(Raw, &Value, sizeof(RawTypeT));
uint32_t Offset = 0;
diff --git a/unittests/DebugInfo/DWARF/DwarfGenerator.cpp b/unittests/DebugInfo/DWARF/DwarfGenerator.cpp
new file mode 100644
index 000000000000..9a72f70a0f21
--- /dev/null
+++ b/unittests/DebugInfo/DWARF/DwarfGenerator.cpp
@@ -0,0 +1,266 @@
+//===--- unittests/DebugInfo/DWARF/DwarfGenerator.cpp -----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../lib/CodeGen/AsmPrinter/DwarfStringPool.h"
+#include "DwarfGenerator.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/CodeGen/AsmPrinter.h"
+#include "llvm/CodeGen/DIE.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
+#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
+#include "llvm/IR/LegacyPassManagers.h"
+#include "llvm/MC/MCAsmBackend.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCCodeEmitter.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDwarf.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCObjectFileInfo.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/MCTargetOptionsCommandFlags.h"
+#include "llvm/PassAnalysisSupport.h"
+#include "llvm/Support/Dwarf.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetOptions.h"
+
+using namespace llvm;
+using namespace dwarf;
+
+namespace {} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+/// dwarfgen::DIE implementation.
+//===----------------------------------------------------------------------===//
+unsigned dwarfgen::DIE::computeSizeAndOffsets(unsigned Offset) {
+ auto &DG = CU->getGenerator();
+ return Die->computeOffsetsAndAbbrevs(DG.getAsmPrinter(), DG.getAbbrevSet(),
+ Offset);
+}
+
+void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form, uint64_t U) {
+ auto &DG = CU->getGenerator();
+ Die->addValue(DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form,
+ DIEInteger(U));
+}
+
+void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form,
+ StringRef String) {
+ auto &DG = CU->getGenerator();
+ if (Form == DW_FORM_string) {
+ Die->addValue(DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form,
+ new (DG.getAllocator())
+ DIEInlineString(String, DG.getAllocator()));
+ } else {
+ Die->addValue(
+ DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form,
+ DIEString(DG.getStringPool().getEntry(*DG.getAsmPrinter(), String)));
+ }
+}
+
+void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form,
+ dwarfgen::DIE &RefDie) {
+ auto &DG = CU->getGenerator();
+ Die->addValue(DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form,
+ DIEEntry(*RefDie.Die));
+}
+
+void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form, const void *P,
+ size_t S) {
+ auto &DG = CU->getGenerator();
+ DIEBlock *Block = new (DG.getAllocator()) DIEBlock;
+ for (size_t I = 0; I < S; ++I)
+ Block->addValue(
+ DG.getAllocator(), (dwarf::Attribute)0, dwarf::DW_FORM_data1,
+ DIEInteger(
+ (const_cast<uint8_t *>(static_cast<const uint8_t *>(P)))[I]));
+
+ Block->ComputeSize(DG.getAsmPrinter());
+ Die->addValue(DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form,
+ Block);
+}
+
+void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form) {
+ auto &DG = CU->getGenerator();
+ assert(Form == DW_FORM_flag_present);
+ Die->addValue(DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form,
+ DIEInteger(1));
+}
+
+dwarfgen::DIE dwarfgen::DIE::addChild(dwarf::Tag Tag) {
+ auto &DG = CU->getGenerator();
+ return dwarfgen::DIE(CU,
+ &Die->addChild(llvm::DIE::get(DG.getAllocator(), Tag)));
+}
+
+dwarfgen::DIE dwarfgen::CompileUnit::getUnitDIE() {
+ return dwarfgen::DIE(this, &DU.getUnitDie());
+}
+
+//===----------------------------------------------------------------------===//
+/// dwarfgen::Generator implementation.
+//===----------------------------------------------------------------------===//
+
+dwarfgen::Generator::Generator()
+ : MAB(nullptr), MCE(nullptr), MS(nullptr), StringPool(nullptr),
+ Abbreviations(Allocator) {}
+dwarfgen::Generator::~Generator() = default;
+
+llvm::Expected<std::unique_ptr<dwarfgen::Generator>>
+dwarfgen::Generator::create(Triple TheTriple, uint16_t DwarfVersion) {
+ std::unique_ptr<dwarfgen::Generator> GenUP(new dwarfgen::Generator());
+ llvm::Error error = GenUP->init(TheTriple, DwarfVersion);
+ if (error)
+ return Expected<std::unique_ptr<dwarfgen::Generator>>(std::move(error));
+ return Expected<std::unique_ptr<dwarfgen::Generator>>(std::move(GenUP));
+}
+
+llvm::Error dwarfgen::Generator::init(Triple TheTriple, uint16_t V) {
+ Version = V;
+ std::string ErrorStr;
+ std::string TripleName;
+
+ // Get the target.
+ const Target *TheTarget =
+ TargetRegistry::lookupTarget(TripleName, TheTriple, ErrorStr);
+ if (!TheTarget)
+ return make_error<StringError>(ErrorStr, inconvertibleErrorCode());
+
+ TripleName = TheTriple.getTriple();
+
+ // Create all the MC Objects.
+ MRI.reset(TheTarget->createMCRegInfo(TripleName));
+ if (!MRI)
+ return make_error<StringError>(Twine("no register info for target ") +
+ TripleName,
+ inconvertibleErrorCode());
+
+ MAI.reset(TheTarget->createMCAsmInfo(*MRI, TripleName));
+ if (!MAI)
+ return make_error<StringError>("no asm info for target " + TripleName,
+ inconvertibleErrorCode());
+
+ MOFI.reset(new MCObjectFileInfo);
+ MC.reset(new MCContext(MAI.get(), MRI.get(), MOFI.get()));
+ MOFI->InitMCObjectFileInfo(TheTriple, /*PIC*/ false, CodeModel::Default, *MC);
+
+ MCTargetOptions Options;
+ MAB = TheTarget->createMCAsmBackend(*MRI, TripleName, "", Options);
+ if (!MAB)
+ return make_error<StringError>("no asm backend for target " + TripleName,
+ inconvertibleErrorCode());
+
+ MII.reset(TheTarget->createMCInstrInfo());
+ if (!MII)
+ return make_error<StringError>("no instr info info for target " +
+ TripleName,
+ inconvertibleErrorCode());
+
+ MSTI.reset(TheTarget->createMCSubtargetInfo(TripleName, "", ""));
+ if (!MSTI)
+ return make_error<StringError>("no subtarget info for target " + TripleName,
+ inconvertibleErrorCode());
+
+ MCE = TheTarget->createMCCodeEmitter(*MII, *MRI, *MC);
+ if (!MCE)
+ return make_error<StringError>("no code emitter for target " + TripleName,
+ inconvertibleErrorCode());
+
+ Stream = make_unique<raw_svector_ostream>(FileBytes);
+
+ MCTargetOptions MCOptions = InitMCTargetOptionsFromFlags();
+ MS = TheTarget->createMCObjectStreamer(
+ TheTriple, *MC, *MAB, *Stream, MCE, *MSTI, MCOptions.MCRelaxAll,
+ MCOptions.MCIncrementalLinkerCompatible,
+ /*DWARFMustBeAtTheEnd*/ false);
+ if (!MS)
+ return make_error<StringError>("no object streamer for target " +
+ TripleName,
+ inconvertibleErrorCode());
+
+ // Finally create the AsmPrinter we'll use to emit the DIEs.
+ TM.reset(TheTarget->createTargetMachine(TripleName, "", "", TargetOptions(),
+ None));
+ if (!TM)
+ return make_error<StringError>("no target machine for target " + TripleName,
+ inconvertibleErrorCode());
+
+ Asm.reset(TheTarget->createAsmPrinter(*TM, std::unique_ptr<MCStreamer>(MS)));
+ if (!Asm)
+ return make_error<StringError>("no asm printer for target " + TripleName,
+ inconvertibleErrorCode());
+
+ // Set the DWARF version correctly on all classes that we use.
+ MC->setDwarfVersion(Version);
+ Asm->setDwarfVersion(Version);
+
+ StringPool = llvm::make_unique<DwarfStringPool>(Allocator, *Asm, StringRef());
+
+ return Error::success();
+}
+
+StringRef dwarfgen::Generator::generate() {
+ // Offset from the first CU in the debug info section is 0 initially.
+ unsigned SecOffset = 0;
+
+ // Iterate over each compile unit and set the size and offsets for each
+ // DIE within each compile unit. All offsets are CU relative.
+ for (auto &CU : CompileUnits) {
+ // Set the absolute .debug_info offset for this compile unit.
+ CU->setOffset(SecOffset);
+ // The DIEs contain compile unit relative offsets.
+ unsigned CUOffset = 11;
+ CUOffset = CU->getUnitDIE().computeSizeAndOffsets(CUOffset);
+ // Update our absolute .debug_info offset.
+ SecOffset += CUOffset;
+ CU->setLength(CUOffset - 4);
+ }
+ Abbreviations.Emit(Asm.get(), MOFI->getDwarfAbbrevSection());
+ StringPool->emit(*Asm, MOFI->getDwarfStrSection());
+ MS->SwitchSection(MOFI->getDwarfInfoSection());
+ for (auto &CU : CompileUnits) {
+ uint16_t Version = CU->getVersion();
+ auto Length = CU->getLength();
+ MC->setDwarfVersion(Version);
+ assert(Length != -1U);
+ Asm->EmitInt32(Length);
+ Asm->EmitInt16(Version);
+ Asm->EmitInt32(0);
+ Asm->EmitInt8(CU->getAddressSize());
+ Asm->emitDwarfDIE(*CU->getUnitDIE().Die);
+ }
+
+ MS->Finish();
+ if (FileBytes.empty())
+ return StringRef();
+ return StringRef(FileBytes.data(), FileBytes.size());
+}
+
+bool dwarfgen::Generator::saveFile(StringRef Path) {
+ if (FileBytes.empty())
+ return false;
+ std::error_code EC;
+ raw_fd_ostream Strm(Path, EC, sys::fs::F_None);
+ if (EC)
+ return false;
+ Strm.write(FileBytes.data(), FileBytes.size());
+ Strm.close();
+ return true;
+}
+
+dwarfgen::CompileUnit &dwarfgen::Generator::addCompileUnit() {
+ CompileUnits.push_back(std::unique_ptr<CompileUnit>(
+ new CompileUnit(*this, Version, Asm->getPointerSize())));
+ return *CompileUnits.back();
+}
diff --git a/unittests/DebugInfo/DWARF/DwarfGenerator.h b/unittests/DebugInfo/DWARF/DwarfGenerator.h
new file mode 100644
index 000000000000..966725b4fa4e
--- /dev/null
+++ b/unittests/DebugInfo/DWARF/DwarfGenerator.h
@@ -0,0 +1,231 @@
+//===--- unittests/DebugInfo/DWARF/DwarfGenerator.h -------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// A file that can generate DWARF debug info for unit tests.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_UNITTESTS_DEBUG_INFO_DWARF_DWARFGENERATOR_H
+#define LLVM_UNITTESTS_DEBUG_INFO_DWARF_DWARFGENERATOR_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/CodeGen/DIE.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
+#include "llvm/Support/Error.h"
+
+#include <memory>
+#include <string>
+#include <tuple>
+#include <vector>
+
+namespace llvm {
+
+class AsmPrinter;
+class DIE;
+class DIEAbbrev;
+class DwarfStringPool;
+class MCAsmBackend;
+class MCAsmInfo;
+class MCCodeEmitter;
+class MCContext;
+struct MCDwarfLineTableParams;
+class MCInstrInfo;
+class MCObjectFileInfo;
+class MCRegisterInfo;
+class MCStreamer;
+class MCSubtargetInfo;
+class raw_fd_ostream;
+class TargetMachine;
+class Triple;
+
+namespace dwarfgen {
+
+class Generator;
+class CompileUnit;
+
+/// A DWARF debug information entry class used to generate DWARF DIEs.
+///
+/// This class is used to quickly generate DWARF debug information by creating
+/// child DIEs or adding attributes to the current DIE. Instances of this class
+/// are created from the compile unit (dwarfgen::CompileUnit::getUnitDIE()) or
+/// by calling dwarfgen::DIE::addChild(...) and using the returned DIE object.
+class DIE {
+ dwarfgen::CompileUnit *CU;
+ llvm::DIE *Die;
+
+protected:
+ friend class Generator;
+ friend class CompileUnit;
+
+ DIE(CompileUnit *U = nullptr, llvm::DIE *D = nullptr) : CU(U), Die(D) {}
+
+ /// Called with a compile/type unit relative offset prior to generating the
+ /// DWARF debug info.
+ ///
+ /// \param CUOffset the compile/type unit relative offset where the
+ /// abbreviation code for this DIE will be encoded.
+ unsigned computeSizeAndOffsets(unsigned CUOffset);
+
+public:
+ /// Add an attribute value that has no value.
+ ///
+ /// \param Attr a dwarf::Attribute enumeration value or any uint16_t that
+ /// represents a user defined DWARF attribute.
+ /// \param Form the dwarf::Form to use when encoding the attribute. This is
+ /// only used with the DW_FORM_flag_present form encoding.
+ void addAttribute(uint16_t Attr, dwarf::Form Form);
+
+ /// Add an attribute value to be encoded as a DIEInteger
+ ///
+ /// \param Attr a dwarf::Attribute enumeration value or any uint16_t that
+ /// represents a user defined DWARF attribute.
+ /// \param Form the dwarf::Form to use when encoding the attribute.
+ /// \param U the unsigned integer to encode.
+ void addAttribute(uint16_t Attr, dwarf::Form Form, uint64_t U);
+
+ /// Add an attribute value to be encoded as a DIEString or DIEInlinedString.
+ ///
+ /// \param Attr a dwarf::Attribute enumeration value or any uint16_t that
+ /// represents a user defined DWARF attribute.
+ /// \param Form the dwarf::Form to use when encoding the attribute. The form
+ /// must be one of DW_FORM_strp or DW_FORM_string.
+ /// \param String the string to encode.
+ void addAttribute(uint16_t Attr, dwarf::Form Form, StringRef String);
+
+ /// Add an attribute value to be encoded as a DIEEntry.
+ ///
+ /// DIEEntry attributes refer to other llvm::DIE objects that have been
+ /// created.
+ ///
+ /// \param Attr a dwarf::Attribute enumeration value or any uint16_t that
+ /// represents a user defined DWARF attribute.
+ /// \param Form the dwarf::Form to use when encoding the attribute. The form
+ /// must be one of DW_FORM_strp or DW_FORM_string.
+ /// \param RefDie the DIE that this attriute refers to.
+ void addAttribute(uint16_t Attr, dwarf::Form Form, dwarfgen::DIE &RefDie);
+
+ /// Add an attribute value to be encoded as a DIEBlock.
+ ///
+ /// DIEBlock attributes refers to binary data that is stored as the
+ /// attribute's value.
+ ///
+ /// \param Attr a dwarf::Attribute enumeration value or any uint16_t that
+ /// represents a user defined DWARF attribute.
+ /// \param Form the dwarf::Form to use when encoding the attribute. The form
+ /// must be one of DW_FORM_strp or DW_FORM_string.
+ /// \param P a pointer to the data to store as the attribute value.
+ /// \param S the size in bytes of the data pointed to by P .
+ void addAttribute(uint16_t Attr, dwarf::Form Form, const void *P, size_t S);
+
+ /// Add a new child to this DIE object.
+ ///
+ /// \param Tag the dwarf::Tag to assing to the llvm::DIE object.
+ /// \returns the newly created DIE object that is now a child owned by this
+ /// object.
+ dwarfgen::DIE addChild(dwarf::Tag Tag);
+};
+
+/// A DWARF compile unit used to generate DWARF compile/type units.
+///
+/// Instances of these classes are created by instances of the Generator
+/// class. All information required to generate a DWARF compile unit is
+/// contained inside this class.
+class CompileUnit {
+ Generator &DG;
+ DIEUnit DU;
+
+public:
+ CompileUnit(Generator &D, uint16_t V, uint8_t A)
+ : DG(D), DU(V, A, dwarf::DW_TAG_compile_unit) {}
+ DIE getUnitDIE();
+ Generator &getGenerator() { return DG; }
+ uint64_t getOffset() const { return DU.getDebugSectionOffset(); }
+ uint64_t getLength() const { return DU.getLength(); }
+ uint16_t getVersion() const { return DU.getDwarfVersion(); }
+ uint16_t getAddressSize() const { return DU.getAddressSize(); }
+ void setOffset(uint64_t Offset) { DU.setDebugSectionOffset(Offset); }
+ void setLength(uint64_t Length) { DU.setLength(Length); }
+};
+
+/// A DWARF generator.
+///
+/// Generate DWARF for unit tests by creating any instance of this class and
+/// calling Generator::addCompileUnit(), and then getting the dwarfgen::DIE from
+/// the returned compile unit and adding attributes and children to each DIE.
+class Generator {
+ std::unique_ptr<MCRegisterInfo> MRI;
+ std::unique_ptr<MCAsmInfo> MAI;
+ std::unique_ptr<MCObjectFileInfo> MOFI;
+ std::unique_ptr<MCContext> MC;
+ MCAsmBackend *MAB; // Owned by MCStreamer
+ std::unique_ptr<MCInstrInfo> MII;
+ std::unique_ptr<MCSubtargetInfo> MSTI;
+ MCCodeEmitter *MCE; // Owned by MCStreamer
+ MCStreamer *MS; // Owned by AsmPrinter
+ std::unique_ptr<TargetMachine> TM;
+ std::unique_ptr<AsmPrinter> Asm;
+ BumpPtrAllocator Allocator;
+ std::unique_ptr<DwarfStringPool> StringPool; // Entries owned by Allocator.
+ std::vector<std::unique_ptr<CompileUnit>> CompileUnits;
+ DIEAbbrevSet Abbreviations;
+
+ SmallString<4096> FileBytes;
+ /// The stream we use to generate the DWARF into as an ELF file.
+ std::unique_ptr<raw_svector_ostream> Stream;
+ /// The DWARF version to generate.
+ uint16_t Version;
+
+ /// Private constructor, call Generator::Create(...) to get a DWARF generator
+ /// expected.
+ Generator();
+
+ /// Create the streamer and setup the output buffer.
+ llvm::Error init(Triple TheTriple, uint16_t DwarfVersion);
+
+public:
+ /// Create a DWARF generator or get an appropriate error.
+ ///
+ /// \param TheTriple the triple to use when creating any required support
+ /// classes needed to emit the DWARF.
+ /// \param DwarfVersion the version of DWARF to emit.
+ ///
+ /// \returns a llvm::Expected that either contains a unique_ptr to a Generator
+ /// or a llvm::Error.
+ static llvm::Expected<std::unique_ptr<Generator>>
+ create(Triple TheTriple, uint16_t DwarfVersion);
+
+ ~Generator();
+
+ /// Generate all DWARF sections and return a memory buffer that
+ /// contains an ELF file that contains the DWARF.
+ StringRef generate();
+
+ /// Add a compile unit to be generated.
+ ///
+ /// \returns a dwarfgen::CompileUnit that can be used to retrieve the compile
+ /// unit dwarfgen::DIE that can be used to add attributes and add child DIE
+ /// objedts to.
+ dwarfgen::CompileUnit &addCompileUnit();
+
+ BumpPtrAllocator &getAllocator() { return Allocator; }
+ AsmPrinter *getAsmPrinter() const { return Asm.get(); }
+ DIEAbbrevSet &getAbbrevSet() { return Abbreviations; }
+ DwarfStringPool &getStringPool() { return *StringPool; }
+
+ /// Save the generated DWARF file to disk.
+ ///
+ /// \param Path the path to save the ELF file to.
+ bool saveFile(StringRef Path);
+};
+
+} // end namespace dwarfgen
+
+} // end namespace llvm
+
+#endif // LLVM_UNITTESTS_DEBUG_INFO_DWARF_DWARFGENERATOR_H
diff --git a/unittests/DebugInfo/PDB/CMakeLists.txt b/unittests/DebugInfo/PDB/CMakeLists.txt
index 405b7bb9b1a6..406b487e7a18 100644
--- a/unittests/DebugInfo/PDB/CMakeLists.txt
+++ b/unittests/DebugInfo/PDB/CMakeLists.txt
@@ -1,11 +1,12 @@
set(LLVM_LINK_COMPONENTS
DebugInfoCodeView
+ DebugInfoMSF
DebugInfoPDB
)
set(DebugInfoPDBSources
MappedBlockStreamTest.cpp
- MsfBuilderTest.cpp
+ MSFBuilderTest.cpp
PDBApiTest.cpp
)
diff --git a/unittests/DebugInfo/PDB/ErrorChecking.h b/unittests/DebugInfo/PDB/ErrorChecking.h
index da734a9b1b5b..6d4a7de7834a 100644
--- a/unittests/DebugInfo/PDB/ErrorChecking.h
+++ b/unittests/DebugInfo/PDB/ErrorChecking.h
@@ -36,6 +36,14 @@
} \
}
-#define EXPECT_UNEXPECTED(Exp) EXPECT_ERROR(Err)
+#define EXPECT_UNEXPECTED(Exp) \
+ { \
+ auto E = Exp.takeError(); \
+ EXPECT_TRUE(static_cast<bool>(E)); \
+ if (E) { \
+ consumeError(std::move(E)); \
+ return; \
+ } \
+ }
#endif
diff --git a/unittests/DebugInfo/PDB/MsfBuilderTest.cpp b/unittests/DebugInfo/PDB/MSFBuilderTest.cpp
index ac292a73a8fb..5f2f0c271e97 100644
--- a/unittests/DebugInfo/PDB/MsfBuilderTest.cpp
+++ b/unittests/DebugInfo/PDB/MSFBuilderTest.cpp
@@ -1,4 +1,4 @@
-//===- MsfBuilderTest.cpp Tests manipulation of MSF stream metadata ------===//
+//===- MSFBuilderTest.cpp Tests manipulation of MSF stream metadata ------===//
//
// The LLVM Compiler Infrastructure
//
@@ -9,17 +9,16 @@
#include "ErrorChecking.h"
-#include "llvm/DebugInfo/PDB/Raw/MsfBuilder.h"
-#include "llvm/DebugInfo/PDB/Raw/MsfCommon.h"
+#include "llvm/DebugInfo/MSF/MSFBuilder.h"
+#include "llvm/DebugInfo/MSF/MSFCommon.h"
#include "gtest/gtest.h"
using namespace llvm;
-using namespace llvm::pdb;
-using namespace llvm::pdb::msf;
+using namespace llvm::msf;
namespace {
-class MsfBuilderTest : public testing::Test {
+class MSFBuilderTest : public testing::Test {
protected:
void initializeSimpleSuperBlock(msf::SuperBlock &SB) {
initializeSuperBlock(SB);
@@ -31,6 +30,7 @@ protected:
::memset(&SB, 0, sizeof(SB));
::memcpy(SB.MagicBytes, msf::Magic, sizeof(msf::Magic));
+ SB.FreeBlockMapBlock = 1;
SB.BlockMapAddr = 1;
SB.BlockSize = 4096;
SB.NumDirectoryBytes = 0;
@@ -41,7 +41,7 @@ protected:
};
}
-TEST_F(MsfBuilderTest, ValidateSuperBlockAccept) {
+TEST_F(MSFBuilderTest, ValidateSuperBlockAccept) {
// Test that a known good super block passes validation.
SuperBlock SB;
initializeSuperBlock(SB);
@@ -49,7 +49,7 @@ TEST_F(MsfBuilderTest, ValidateSuperBlockAccept) {
EXPECT_NO_ERROR(msf::validateSuperBlock(SB));
}
-TEST_F(MsfBuilderTest, ValidateSuperBlockReject) {
+TEST_F(MSFBuilderTest, ValidateSuperBlockReject) {
// Test that various known problems cause a super block to be rejected.
SuperBlock SB;
initializeSimpleSuperBlock(SB);
@@ -76,7 +76,7 @@ TEST_F(MsfBuilderTest, ValidateSuperBlockReject) {
EXPECT_ERROR(msf::validateSuperBlock(SB));
}
-TEST_F(MsfBuilderTest, TestUsedBlocksMarkedAsUsed) {
+TEST_F(MSFBuilderTest, TestUsedBlocksMarkedAsUsed) {
// Test that when assigning a stream to a known list of blocks, the blocks
// are correctly marked as used after adding, but no other incorrect blocks
// are accidentally marked as used.
@@ -85,11 +85,11 @@ TEST_F(MsfBuilderTest, TestUsedBlocksMarkedAsUsed) {
// Allocate some extra blocks at the end so we can verify that they're free
// after the initialization.
uint32_t NumBlocks = msf::getMinimumBlockCount() + Blocks.size() + 10;
- auto ExpectedMsf = MsfBuilder::create(Allocator, 4096, NumBlocks);
+ auto ExpectedMsf = MSFBuilder::create(Allocator, 4096, NumBlocks);
EXPECT_EXPECTED(ExpectedMsf);
auto &Msf = *ExpectedMsf;
- EXPECT_NO_ERROR(Msf.addStream(Blocks.size() * 4096, Blocks));
+ EXPECT_EXPECTED(Msf.addStream(Blocks.size() * 4096, Blocks));
for (auto B : Blocks) {
EXPECT_FALSE(Msf.isBlockFree(B));
@@ -101,26 +101,26 @@ TEST_F(MsfBuilderTest, TestUsedBlocksMarkedAsUsed) {
}
}
-TEST_F(MsfBuilderTest, TestAddStreamNoDirectoryBlockIncrease) {
+TEST_F(MSFBuilderTest, TestAddStreamNoDirectoryBlockIncrease) {
// Test that adding a new stream correctly updates the directory. This only
// tests the case where the directory *DOES NOT* grow large enough that it
// crosses a Block boundary.
- auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
+ auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);
EXPECT_EXPECTED(ExpectedMsf);
auto &Msf = *ExpectedMsf;
auto ExpectedL1 = Msf.build();
EXPECT_EXPECTED(ExpectedL1);
- Layout &L1 = *ExpectedL1;
+ MSFLayout &L1 = *ExpectedL1;
auto OldDirBlocks = L1.DirectoryBlocks;
EXPECT_EQ(1U, OldDirBlocks.size());
- auto ExpectedMsf2 = MsfBuilder::create(Allocator, 4096);
+ auto ExpectedMsf2 = MSFBuilder::create(Allocator, 4096);
EXPECT_EXPECTED(ExpectedMsf2);
auto &Msf2 = *ExpectedMsf2;
- EXPECT_NO_ERROR(Msf2.addStream(4000));
+ EXPECT_EXPECTED(Msf2.addStream(4000));
EXPECT_EQ(1U, Msf2.getNumStreams());
EXPECT_EQ(4000U, Msf2.getStreamSize(0));
auto Blocks = Msf2.getStreamBlocks(0);
@@ -128,38 +128,38 @@ TEST_F(MsfBuilderTest, TestAddStreamNoDirectoryBlockIncrease) {
auto ExpectedL2 = Msf2.build();
EXPECT_EXPECTED(ExpectedL2);
- Layout &L2 = *ExpectedL2;
+ MSFLayout &L2 = *ExpectedL2;
auto NewDirBlocks = L2.DirectoryBlocks;
EXPECT_EQ(1U, NewDirBlocks.size());
}
-TEST_F(MsfBuilderTest, TestAddStreamWithDirectoryBlockIncrease) {
+TEST_F(MSFBuilderTest, TestAddStreamWithDirectoryBlockIncrease) {
// Test that adding a new stream correctly updates the directory. This only
// tests the case where the directory *DOES* grow large enough that it
// crosses a Block boundary. This is because the newly added stream occupies
// so many Blocks that need to be indexed in the directory that the directory
// crosses a Block boundary.
- auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
+ auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);
EXPECT_EXPECTED(ExpectedMsf);
auto &Msf = *ExpectedMsf;
- EXPECT_NO_ERROR(Msf.addStream(4096 * 4096 / sizeof(uint32_t)));
+ EXPECT_EXPECTED(Msf.addStream(4096 * 4096 / sizeof(uint32_t)));
auto ExpectedL1 = Msf.build();
EXPECT_EXPECTED(ExpectedL1);
- Layout &L1 = *ExpectedL1;
+ MSFLayout &L1 = *ExpectedL1;
auto DirBlocks = L1.DirectoryBlocks;
EXPECT_EQ(2U, DirBlocks.size());
}
-TEST_F(MsfBuilderTest, TestGrowStreamNoBlockIncrease) {
+TEST_F(MSFBuilderTest, TestGrowStreamNoBlockIncrease) {
// Test growing an existing stream by a value that does not affect the number
// of blocks it occupies.
- auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
+ auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);
EXPECT_EXPECTED(ExpectedMsf);
auto &Msf = *ExpectedMsf;
- EXPECT_NO_ERROR(Msf.addStream(1024));
+ EXPECT_EXPECTED(Msf.addStream(1024));
EXPECT_EQ(1024U, Msf.getStreamSize(0));
auto OldStreamBlocks = Msf.getStreamBlocks(0);
EXPECT_EQ(1U, OldStreamBlocks.size());
@@ -172,16 +172,16 @@ TEST_F(MsfBuilderTest, TestGrowStreamNoBlockIncrease) {
EXPECT_EQ(OldStreamBlocks, NewStreamBlocks);
}
-TEST_F(MsfBuilderTest, TestGrowStreamWithBlockIncrease) {
+TEST_F(MSFBuilderTest, TestGrowStreamWithBlockIncrease) {
// Test that growing an existing stream to a value large enough that it causes
// the need to allocate new Blocks to the stream correctly updates the
// stream's
// block list.
- auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
+ auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);
EXPECT_EXPECTED(ExpectedMsf);
auto &Msf = *ExpectedMsf;
- EXPECT_NO_ERROR(Msf.addStream(2048));
+ EXPECT_EXPECTED(Msf.addStream(2048));
EXPECT_EQ(2048U, Msf.getStreamSize(0));
std::vector<uint32_t> OldStreamBlocks = Msf.getStreamBlocks(0);
EXPECT_EQ(1U, OldStreamBlocks.size());
@@ -195,14 +195,14 @@ TEST_F(MsfBuilderTest, TestGrowStreamWithBlockIncrease) {
EXPECT_NE(NewStreamBlocks[0], NewStreamBlocks[1]);
}
-TEST_F(MsfBuilderTest, TestShrinkStreamNoBlockDecrease) {
+TEST_F(MSFBuilderTest, TestShrinkStreamNoBlockDecrease) {
// Test that shrinking an existing stream by a value that does not affect the
// number of Blocks it occupies makes no changes to stream's block list.
- auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
+ auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);
EXPECT_EXPECTED(ExpectedMsf);
auto &Msf = *ExpectedMsf;
- EXPECT_NO_ERROR(Msf.addStream(2048));
+ EXPECT_EXPECTED(Msf.addStream(2048));
EXPECT_EQ(2048U, Msf.getStreamSize(0));
std::vector<uint32_t> OldStreamBlocks = Msf.getStreamBlocks(0);
EXPECT_EQ(1U, OldStreamBlocks.size());
@@ -215,15 +215,15 @@ TEST_F(MsfBuilderTest, TestShrinkStreamNoBlockDecrease) {
EXPECT_EQ(OldStreamBlocks, NewStreamBlocks);
}
-TEST_F(MsfBuilderTest, TestShrinkStreamWithBlockDecrease) {
+TEST_F(MSFBuilderTest, TestShrinkStreamWithBlockDecrease) {
// Test that shrinking an existing stream to a value large enough that it
// causes the need to deallocate new Blocks to the stream correctly updates
// the stream's block list.
- auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
+ auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);
EXPECT_EXPECTED(ExpectedMsf);
auto &Msf = *ExpectedMsf;
- EXPECT_NO_ERROR(Msf.addStream(6144));
+ EXPECT_EXPECTED(Msf.addStream(6144));
EXPECT_EQ(6144U, Msf.getStreamSize(0));
std::vector<uint32_t> OldStreamBlocks = Msf.getStreamBlocks(0);
EXPECT_EQ(2U, OldStreamBlocks.size());
@@ -236,23 +236,23 @@ TEST_F(MsfBuilderTest, TestShrinkStreamWithBlockDecrease) {
EXPECT_EQ(OldStreamBlocks[0], NewStreamBlocks[0]);
}
-TEST_F(MsfBuilderTest, TestRejectReusedStreamBlock) {
+TEST_F(MSFBuilderTest, TestRejectReusedStreamBlock) {
// Test that attempting to add a stream and assigning a block that is already
// in use by another stream fails.
- auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
+ auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);
EXPECT_EXPECTED(ExpectedMsf);
auto &Msf = *ExpectedMsf;
- EXPECT_NO_ERROR(Msf.addStream(6144));
+ EXPECT_EXPECTED(Msf.addStream(6144));
std::vector<uint32_t> Blocks = {2, 3};
- EXPECT_ERROR(Msf.addStream(6144, Blocks));
+ EXPECT_UNEXPECTED(Msf.addStream(6144, Blocks));
}
-TEST_F(MsfBuilderTest, TestBlockCountsWhenAddingStreams) {
+TEST_F(MSFBuilderTest, TestBlockCountsWhenAddingStreams) {
// Test that when adding multiple streams, the number of used and free Blocks
// allocated to the MSF file are as expected.
- auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
+ auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);
EXPECT_EXPECTED(ExpectedMsf);
auto &Msf = *ExpectedMsf;
@@ -263,31 +263,31 @@ TEST_F(MsfBuilderTest, TestBlockCountsWhenAddingStreams) {
const uint32_t StreamSizes[] = {4000, 6193, 189723};
for (int I = 0; I < 3; ++I) {
- EXPECT_NO_ERROR(Msf.addStream(StreamSizes[I]));
+ EXPECT_EXPECTED(Msf.addStream(StreamSizes[I]));
NumUsedBlocks += bytesToBlocks(StreamSizes[I], 4096);
EXPECT_EQ(NumUsedBlocks, Msf.getNumUsedBlocks());
EXPECT_EQ(0U, Msf.getNumFreeBlocks());
}
}
-TEST_F(MsfBuilderTest, BuildMsfLayout) {
- // Test that we can generate an Msf Layout structure from a valid layout
+TEST_F(MSFBuilderTest, BuildMsfLayout) {
+ // Test that we can generate an MSFLayout structure from a valid layout
// specification.
- auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
+ auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);
EXPECT_EXPECTED(ExpectedMsf);
auto &Msf = *ExpectedMsf;
const uint32_t StreamSizes[] = {4000, 6193, 189723};
uint32_t ExpectedNumBlocks = msf::getMinimumBlockCount();
for (int I = 0; I < 3; ++I) {
- EXPECT_NO_ERROR(Msf.addStream(StreamSizes[I]));
+ EXPECT_EXPECTED(Msf.addStream(StreamSizes[I]));
ExpectedNumBlocks += bytesToBlocks(StreamSizes[I], 4096);
}
++ExpectedNumBlocks; // The directory itself should use 1 block
auto ExpectedLayout = Msf.build();
EXPECT_EXPECTED(ExpectedLayout);
- Layout &L = *ExpectedLayout;
+ MSFLayout &L = *ExpectedLayout;
EXPECT_EQ(4096U, L.SB->BlockSize);
EXPECT_EQ(ExpectedNumBlocks, L.SB->NumBlocks);
@@ -302,19 +302,19 @@ TEST_F(MsfBuilderTest, BuildMsfLayout) {
}
}
-TEST_F(MsfBuilderTest, UseDirectoryBlockHint) {
- Expected<MsfBuilder> ExpectedMsf = MsfBuilder::create(
+TEST_F(MSFBuilderTest, UseDirectoryBlockHint) {
+ Expected<MSFBuilder> ExpectedMsf = MSFBuilder::create(
Allocator, 4096, msf::getMinimumBlockCount() + 1, false);
EXPECT_EXPECTED(ExpectedMsf);
auto &Msf = *ExpectedMsf;
uint32_t B = msf::getFirstUnreservedBlock();
EXPECT_NO_ERROR(Msf.setDirectoryBlocksHint({B + 1}));
- EXPECT_NO_ERROR(Msf.addStream(2048, {B + 2}));
+ EXPECT_EXPECTED(Msf.addStream(2048, {B + 2}));
auto ExpectedLayout = Msf.build();
EXPECT_EXPECTED(ExpectedLayout);
- Layout &L = *ExpectedLayout;
+ MSFLayout &L = *ExpectedLayout;
EXPECT_EQ(msf::getMinimumBlockCount() + 2, L.SB->NumBlocks);
EXPECT_EQ(1U, L.DirectoryBlocks.size());
EXPECT_EQ(1U, L.StreamMap[0].size());
@@ -323,38 +323,38 @@ TEST_F(MsfBuilderTest, UseDirectoryBlockHint) {
EXPECT_EQ(B + 2, L.StreamMap[0].front());
}
-TEST_F(MsfBuilderTest, DirectoryBlockHintInsufficient) {
- Expected<MsfBuilder> ExpectedMsf =
- MsfBuilder::create(Allocator, 4096, msf::getMinimumBlockCount() + 2);
+TEST_F(MSFBuilderTest, DirectoryBlockHintInsufficient) {
+ Expected<MSFBuilder> ExpectedMsf =
+ MSFBuilder::create(Allocator, 4096, msf::getMinimumBlockCount() + 2);
EXPECT_EXPECTED(ExpectedMsf);
auto &Msf = *ExpectedMsf;
uint32_t B = msf::getFirstUnreservedBlock();
EXPECT_NO_ERROR(Msf.setDirectoryBlocksHint({B + 1}));
uint32_t Size = 4096 * 4096 / 4;
- EXPECT_NO_ERROR(Msf.addStream(Size));
+ EXPECT_EXPECTED(Msf.addStream(Size));
auto ExpectedLayout = Msf.build();
EXPECT_EXPECTED(ExpectedLayout);
- Layout &L = *ExpectedLayout;
+ MSFLayout &L = *ExpectedLayout;
EXPECT_EQ(2U, L.DirectoryBlocks.size());
EXPECT_EQ(B + 1, L.DirectoryBlocks[0]);
}
-TEST_F(MsfBuilderTest, DirectoryBlockHintOverestimated) {
- Expected<MsfBuilder> ExpectedMsf =
- MsfBuilder::create(Allocator, 4096, msf::getMinimumBlockCount() + 2);
+TEST_F(MSFBuilderTest, DirectoryBlockHintOverestimated) {
+ Expected<MSFBuilder> ExpectedMsf =
+ MSFBuilder::create(Allocator, 4096, msf::getMinimumBlockCount() + 2);
EXPECT_EXPECTED(ExpectedMsf);
auto &Msf = *ExpectedMsf;
uint32_t B = msf::getFirstUnreservedBlock();
EXPECT_NO_ERROR(Msf.setDirectoryBlocksHint({B + 1, B + 2}));
- EXPECT_NO_ERROR(Msf.addStream(2048));
+ EXPECT_EXPECTED(Msf.addStream(2048));
auto ExpectedLayout = Msf.build();
EXPECT_EXPECTED(ExpectedLayout);
- Layout &L = *ExpectedLayout;
+ MSFLayout &L = *ExpectedLayout;
EXPECT_EQ(1U, L.DirectoryBlocks.size());
EXPECT_EQ(B + 1, L.DirectoryBlocks[0]);
}
diff --git a/unittests/DebugInfo/PDB/MappedBlockStreamTest.cpp b/unittests/DebugInfo/PDB/MappedBlockStreamTest.cpp
index 6f9e86c4f262..07591ca69d30 100644
--- a/unittests/DebugInfo/PDB/MappedBlockStreamTest.cpp
+++ b/unittests/DebugInfo/PDB/MappedBlockStreamTest.cpp
@@ -9,78 +9,77 @@
#include "ErrorChecking.h"
-#include "llvm/DebugInfo/CodeView/ByteStream.h"
-#include "llvm/DebugInfo/CodeView/StreamReader.h"
-#include "llvm/DebugInfo/CodeView/StreamRef.h"
-#include "llvm/DebugInfo/CodeView/StreamWriter.h"
-#include "llvm/DebugInfo/PDB/Raw/IPDBFile.h"
-#include "llvm/DebugInfo/PDB/Raw/IPDBStreamData.h"
-#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h"
-#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h"
+#include "llvm/DebugInfo/MSF/ByteStream.h"
+#include "llvm/DebugInfo/MSF/IMSFFile.h"
+#include "llvm/DebugInfo/MSF/MappedBlockStream.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 "gtest/gtest.h"
#include <unordered_map>
using namespace llvm;
-using namespace llvm::codeview;
-using namespace llvm::pdb;
+using namespace llvm::msf;
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 DiscontiguousFile : public IPDBFile {
+class DiscontiguousStream : public WritableStream {
public:
- DiscontiguousFile(ArrayRef<uint32_t> Blocks, MutableArrayRef<uint8_t> Data)
+ DiscontiguousStream(ArrayRef<uint32_t> Blocks, MutableArrayRef<uint8_t> Data)
: Blocks(Blocks.begin(), Blocks.end()), Data(Data.begin(), Data.end()) {}
- uint32_t getBlockSize() const override { return 1; }
- uint32_t getBlockCount() const override { return Blocks.size(); }
- uint32_t getNumStreams() const override { return 1; }
- uint32_t getStreamByteSize(uint32_t StreamIndex) const override {
- return getBlockCount() * getBlockSize();
- }
- ArrayRef<support::ulittle32_t>
- getStreamBlockList(uint32_t StreamIndex) const override {
- if (StreamIndex != 0)
- return ArrayRef<support::ulittle32_t>();
- return Blocks;
+ uint32_t block_size() const { return 1; }
+ uint32_t block_count() const { return Blocks.size(); }
+
+ 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);
+ Buffer = Data.slice(Offset, Size);
+ return Error::success();
}
- Expected<ArrayRef<uint8_t>> getBlockData(uint32_t BlockIndex,
- uint32_t NumBytes) const override {
- return ArrayRef<uint8_t>(&Data[BlockIndex], NumBytes);
+
+ Error readLongestContiguousChunk(uint32_t Offset,
+ ArrayRef<uint8_t> &Buffer) const override {
+ if (Offset >= Data.size())
+ return make_error<MSFError>(msf_error_code::insufficient_buffer);
+ Buffer = Data.drop_front(Offset);
+ return Error::success();
}
- Error setBlockData(uint32_t BlockIndex, uint32_t Offset,
- ArrayRef<uint8_t> SrcData) const override {
- if (BlockIndex >= Blocks.size())
- return make_error<CodeViewError>(cv_error_code::insufficient_buffer);
- if (Offset > getBlockSize() - SrcData.size())
- return make_error<CodeViewError>(cv_error_code::insufficient_buffer);
- ::memcpy(&Data[BlockIndex] + Offset, SrcData.data(), SrcData.size());
+ uint32_t getLength() const 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);
+ ::memcpy(&Data[Offset], SrcData.data(), SrcData.size());
return Error::success();
}
+ Error commit() const override { return Error::success(); }
+
+ MSFStreamLayout layout() const {
+ return MSFStreamLayout{static_cast<uint32_t>(Data.size()), Blocks};
+ }
private:
std::vector<support::ulittle32_t> Blocks;
MutableArrayRef<uint8_t> Data;
};
-class MappedBlockStreamImpl : public MappedBlockStream {
-public:
- MappedBlockStreamImpl(std::unique_ptr<IPDBStreamData> Data,
- const IPDBFile &File)
- : MappedBlockStream(std::move(Data), File) {}
-};
-
// Tests that a read which is entirely contained within a single block works
// and does not allocate.
TEST(MappedBlockStreamTest, ReadBeyondEndOfStreamRef) {
- DiscontiguousFile F(BlocksAry, DataAry);
- MappedBlockStreamImpl S(llvm::make_unique<IndexedStreamData>(0, F), F);
- StreamReader R(S);
- StreamRef SR;
+ DiscontiguousStream F(BlocksAry, DataAry);
+ auto S = MappedBlockStream::createStream(F.block_size(), F.block_count(),
+ F.layout(), F);
+
+ StreamReader R(*S);
+ ReadableStreamRef SR;
EXPECT_NO_ERROR(R.readStreamRef(SR, 0U));
ArrayRef<uint8_t> Buffer;
EXPECT_ERROR(SR.readBytes(0U, 1U, Buffer));
@@ -91,133 +90,143 @@ TEST(MappedBlockStreamTest, ReadBeyondEndOfStreamRef) {
// Tests that a read which outputs into a full destination buffer works and
// does not fail due to the length of the output buffer.
TEST(MappedBlockStreamTest, ReadOntoNonEmptyBuffer) {
- DiscontiguousFile F(BlocksAry, DataAry);
- MappedBlockStreamImpl S(llvm::make_unique<IndexedStreamData>(0, F), F);
- StreamReader R(S);
+ DiscontiguousStream F(BlocksAry, DataAry);
+ auto S = MappedBlockStream::createStream(F.block_size(), F.block_count(),
+ F.layout(), F);
+
+ StreamReader R(*S);
StringRef Str = "ZYXWVUTSRQPONMLKJIHGFEDCBA";
EXPECT_NO_ERROR(R.readFixedString(Str, 1));
EXPECT_EQ(Str, StringRef("A"));
- EXPECT_EQ(0U, S.getNumBytesCopied());
+ EXPECT_EQ(0U, S->getNumBytesCopied());
}
// Tests that a read which crosses a block boundary, but where the subsequent
// blocks are still contiguous in memory to the previous block works and does
// not allocate memory.
TEST(MappedBlockStreamTest, ZeroCopyReadContiguousBreak) {
- DiscontiguousFile F(BlocksAry, DataAry);
- MappedBlockStreamImpl S(llvm::make_unique<IndexedStreamData>(0, F), F);
- StreamReader R(S);
+ DiscontiguousStream F(BlocksAry, DataAry);
+ auto S = MappedBlockStream::createStream(F.block_size(), F.block_count(),
+ F.layout(), F);
+ StreamReader R(*S);
StringRef Str;
EXPECT_NO_ERROR(R.readFixedString(Str, 2));
EXPECT_EQ(Str, StringRef("AB"));
- EXPECT_EQ(0U, S.getNumBytesCopied());
+ EXPECT_EQ(0U, S->getNumBytesCopied());
R.setOffset(6);
EXPECT_NO_ERROR(R.readFixedString(Str, 4));
EXPECT_EQ(Str, StringRef("GHIJ"));
- EXPECT_EQ(0U, S.getNumBytesCopied());
+ EXPECT_EQ(0U, S->getNumBytesCopied());
}
// Tests that a read which crosses a block boundary and cannot be referenced
// contiguously works and allocates only the precise amount of bytes
// requested.
TEST(MappedBlockStreamTest, CopyReadNonContiguousBreak) {
- DiscontiguousFile F(BlocksAry, DataAry);
- MappedBlockStreamImpl S(llvm::make_unique<IndexedStreamData>(0, F), F);
- StreamReader R(S);
+ DiscontiguousStream F(BlocksAry, DataAry);
+ auto S = MappedBlockStream::createStream(F.block_size(), F.block_count(),
+ F.layout(), F);
+ StreamReader R(*S);
StringRef Str;
EXPECT_NO_ERROR(R.readFixedString(Str, 10));
EXPECT_EQ(Str, StringRef("ABCDEFGHIJ"));
- EXPECT_EQ(10U, S.getNumBytesCopied());
+ EXPECT_EQ(10U, S->getNumBytesCopied());
}
// Test that an out of bounds read which doesn't cross a block boundary
// fails and allocates no memory.
TEST(MappedBlockStreamTest, InvalidReadSizeNoBreak) {
- DiscontiguousFile F(BlocksAry, DataAry);
- MappedBlockStreamImpl S(llvm::make_unique<IndexedStreamData>(0, F), F);
- StreamReader R(S);
+ DiscontiguousStream F(BlocksAry, DataAry);
+ auto S = MappedBlockStream::createStream(F.block_size(), F.block_count(),
+ F.layout(), F);
+ StreamReader R(*S);
StringRef Str;
R.setOffset(10);
EXPECT_ERROR(R.readFixedString(Str, 1));
- EXPECT_EQ(0U, S.getNumBytesCopied());
+ EXPECT_EQ(0U, S->getNumBytesCopied());
}
// Test that an out of bounds read which crosses a contiguous block boundary
// fails and allocates no memory.
TEST(MappedBlockStreamTest, InvalidReadSizeContiguousBreak) {
- DiscontiguousFile F(BlocksAry, DataAry);
- MappedBlockStreamImpl S(llvm::make_unique<IndexedStreamData>(0, F), F);
- StreamReader R(S);
+ DiscontiguousStream F(BlocksAry, DataAry);
+ auto S = MappedBlockStream::createStream(F.block_size(), F.block_count(),
+ F.layout(), F);
+ StreamReader R(*S);
StringRef Str;
R.setOffset(6);
EXPECT_ERROR(R.readFixedString(Str, 5));
- EXPECT_EQ(0U, S.getNumBytesCopied());
+ EXPECT_EQ(0U, S->getNumBytesCopied());
}
// Test that an out of bounds read which crosses a discontiguous block
// boundary fails and allocates no memory.
TEST(MappedBlockStreamTest, InvalidReadSizeNonContiguousBreak) {
- DiscontiguousFile F(BlocksAry, DataAry);
- MappedBlockStreamImpl S(llvm::make_unique<IndexedStreamData>(0, F), F);
- StreamReader R(S);
+ DiscontiguousStream F(BlocksAry, DataAry);
+ auto S = MappedBlockStream::createStream(F.block_size(), F.block_count(),
+ F.layout(), F);
+ StreamReader R(*S);
StringRef Str;
EXPECT_ERROR(R.readFixedString(Str, 11));
- EXPECT_EQ(0U, S.getNumBytesCopied());
+ EXPECT_EQ(0U, S->getNumBytesCopied());
}
// Tests that a read which is entirely contained within a single block but
// beyond the end of a StreamRef fails.
TEST(MappedBlockStreamTest, ZeroCopyReadNoBreak) {
- DiscontiguousFile F(BlocksAry, DataAry);
- MappedBlockStreamImpl S(llvm::make_unique<IndexedStreamData>(0, F), F);
- StreamReader R(S);
+ DiscontiguousStream F(BlocksAry, DataAry);
+ auto S = MappedBlockStream::createStream(F.block_size(), F.block_count(),
+ F.layout(), F);
+ StreamReader R(*S);
StringRef Str;
EXPECT_NO_ERROR(R.readFixedString(Str, 1));
EXPECT_EQ(Str, StringRef("A"));
- EXPECT_EQ(0U, S.getNumBytesCopied());
+ EXPECT_EQ(0U, S->getNumBytesCopied());
}
// Tests that a read which is not aligned on the same boundary as a previous
// cached request, but which is known to overlap that request, shares the
// previous allocation.
TEST(MappedBlockStreamTest, UnalignedOverlappingRead) {
- DiscontiguousFile F(BlocksAry, DataAry);
- MappedBlockStreamImpl S(llvm::make_unique<IndexedStreamData>(0, F), F);
- StreamReader R(S);
+ DiscontiguousStream F(BlocksAry, DataAry);
+ auto S = MappedBlockStream::createStream(F.block_size(), F.block_count(),
+ F.layout(), F);
+ StreamReader R(*S);
StringRef Str1;
StringRef Str2;
EXPECT_NO_ERROR(R.readFixedString(Str1, 7));
EXPECT_EQ(Str1, StringRef("ABCDEFG"));
- EXPECT_EQ(7U, S.getNumBytesCopied());
+ EXPECT_EQ(7U, S->getNumBytesCopied());
R.setOffset(2);
EXPECT_NO_ERROR(R.readFixedString(Str2, 3));
EXPECT_EQ(Str2, StringRef("CDE"));
EXPECT_EQ(Str1.data() + 2, Str2.data());
- EXPECT_EQ(7U, S.getNumBytesCopied());
+ EXPECT_EQ(7U, S->getNumBytesCopied());
}
// Tests that a read which is not aligned on the same boundary as a previous
// cached request, but which only partially overlaps a previous cached request,
// still works correctly and allocates again from the shared pool.
TEST(MappedBlockStreamTest, UnalignedOverlappingReadFail) {
- DiscontiguousFile F(BlocksAry, DataAry);
- MappedBlockStreamImpl S(llvm::make_unique<IndexedStreamData>(0, F), F);
- StreamReader R(S);
+ DiscontiguousStream F(BlocksAry, DataAry);
+ auto S = MappedBlockStream::createStream(F.block_size(), F.block_count(),
+ F.layout(), F);
+ StreamReader R(*S);
StringRef Str1;
StringRef Str2;
EXPECT_NO_ERROR(R.readFixedString(Str1, 6));
EXPECT_EQ(Str1, StringRef("ABCDEF"));
- EXPECT_EQ(6U, S.getNumBytesCopied());
+ EXPECT_EQ(6U, S->getNumBytesCopied());
R.setOffset(4);
EXPECT_NO_ERROR(R.readFixedString(Str2, 4));
EXPECT_EQ(Str2, StringRef("EFGH"));
- EXPECT_EQ(10U, S.getNumBytesCopied());
+ EXPECT_EQ(10U, S->getNumBytesCopied());
}
TEST(MappedBlockStreamTest, WriteBeyondEndOfStream) {
@@ -228,41 +237,43 @@ TEST(MappedBlockStreamTest, WriteBeyondEndOfStream) {
static_assert(sizeof(LargeBuffer) > sizeof(Data),
"LargeBuffer is not big enough");
- DiscontiguousFile F(BlocksAry, Data);
- MappedBlockStreamImpl S(llvm::make_unique<IndexedStreamData>(0, F), F);
+ DiscontiguousStream F(BlocksAry, Data);
+ auto S = WritableMappedBlockStream::createStream(
+ F.block_size(), F.block_count(), F.layout(), F);
ArrayRef<uint8_t> Buffer;
- EXPECT_ERROR(S.writeBytes(0, ArrayRef<uint8_t>(LargeBuffer)));
- EXPECT_NO_ERROR(S.writeBytes(0, ArrayRef<uint8_t>(SmallBuffer)));
- EXPECT_NO_ERROR(S.writeBytes(7, ArrayRef<uint8_t>(SmallBuffer)));
- EXPECT_ERROR(S.writeBytes(8, ArrayRef<uint8_t>(SmallBuffer)));
+ EXPECT_ERROR(S->writeBytes(0, ArrayRef<uint8_t>(LargeBuffer)));
+ EXPECT_NO_ERROR(S->writeBytes(0, ArrayRef<uint8_t>(SmallBuffer)));
+ EXPECT_NO_ERROR(S->writeBytes(7, ArrayRef<uint8_t>(SmallBuffer)));
+ EXPECT_ERROR(S->writeBytes(8, ArrayRef<uint8_t>(SmallBuffer)));
}
TEST(MappedBlockStreamTest, TestWriteBytesNoBreakBoundary) {
static uint8_t Data[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'};
- DiscontiguousFile F(BlocksAry, Data);
- MappedBlockStreamImpl S(llvm::make_unique<IndexedStreamData>(0, F), F);
+ DiscontiguousStream F(BlocksAry, Data);
+ auto S = WritableMappedBlockStream::createStream(
+ F.block_size(), F.block_count(), F.layout(), F);
ArrayRef<uint8_t> Buffer;
- EXPECT_NO_ERROR(S.readBytes(0, 1, Buffer));
+ EXPECT_NO_ERROR(S->readBytes(0, 1, Buffer));
EXPECT_EQ(Buffer, ArrayRef<uint8_t>('A'));
- EXPECT_NO_ERROR(S.readBytes(9, 1, Buffer));
+ EXPECT_NO_ERROR(S->readBytes(9, 1, Buffer));
EXPECT_EQ(Buffer, ArrayRef<uint8_t>('J'));
- EXPECT_NO_ERROR(S.writeBytes(0, ArrayRef<uint8_t>('J')));
- EXPECT_NO_ERROR(S.writeBytes(9, ArrayRef<uint8_t>('A')));
+ EXPECT_NO_ERROR(S->writeBytes(0, ArrayRef<uint8_t>('J')));
+ EXPECT_NO_ERROR(S->writeBytes(9, ArrayRef<uint8_t>('A')));
- EXPECT_NO_ERROR(S.readBytes(0, 1, Buffer));
+ EXPECT_NO_ERROR(S->readBytes(0, 1, Buffer));
EXPECT_EQ(Buffer, ArrayRef<uint8_t>('J'));
- EXPECT_NO_ERROR(S.readBytes(9, 1, Buffer));
+ EXPECT_NO_ERROR(S->readBytes(9, 1, Buffer));
EXPECT_EQ(Buffer, ArrayRef<uint8_t>('A'));
- EXPECT_NO_ERROR(S.writeBytes(0, ArrayRef<uint8_t>('A')));
- EXPECT_NO_ERROR(S.writeBytes(9, ArrayRef<uint8_t>('J')));
+ EXPECT_NO_ERROR(S->writeBytes(0, ArrayRef<uint8_t>('A')));
+ EXPECT_NO_ERROR(S->writeBytes(9, ArrayRef<uint8_t>('J')));
- EXPECT_NO_ERROR(S.readBytes(0, 1, Buffer));
+ EXPECT_NO_ERROR(S->readBytes(0, 1, Buffer));
EXPECT_EQ(Buffer, ArrayRef<uint8_t>('A'));
- EXPECT_NO_ERROR(S.readBytes(9, 1, Buffer));
+ EXPECT_NO_ERROR(S->readBytes(9, 1, Buffer));
EXPECT_EQ(Buffer, ArrayRef<uint8_t>('J'));
}
@@ -272,16 +283,17 @@ TEST(MappedBlockStreamTest, TestWriteBytesBreakBoundary) {
static uint8_t Expected[] = {'T', 'E', 'S', 'N', 'I',
'T', 'G', '.', '0', '0'};
- DiscontiguousFile F(BlocksAry, Data);
- MappedBlockStreamImpl S(llvm::make_unique<IndexedStreamData>(0, F), F);
+ DiscontiguousStream F(BlocksAry, Data);
+ auto S = WritableMappedBlockStream::createStream(
+ F.block_size(), F.block_count(), F.layout(), F);
ArrayRef<uint8_t> Buffer;
- EXPECT_NO_ERROR(S.writeBytes(0, TestData));
+ EXPECT_NO_ERROR(S->writeBytes(0, TestData));
// First just compare the memory, then compare the result of reading the
// string out.
EXPECT_EQ(ArrayRef<uint8_t>(Data), ArrayRef<uint8_t>(Expected));
- EXPECT_NO_ERROR(S.readBytes(0, 8, Buffer));
+ EXPECT_NO_ERROR(S->readBytes(0, 8, Buffer));
EXPECT_EQ(Buffer, ArrayRef<uint8_t>(TestData));
}
@@ -290,8 +302,9 @@ TEST(MappedBlockStreamTest, TestWriteThenRead) {
MutableArrayRef<uint8_t> Data(DataBytes);
const uint32_t Blocks[] = {2, 1, 0, 6, 3, 4, 5, 7, 9, 8};
- DiscontiguousFile F(Blocks, Data);
- MappedBlockStreamImpl S(llvm::make_unique<IndexedStreamData>(0, F), F);
+ DiscontiguousStream F(Blocks, Data);
+ auto S = WritableMappedBlockStream::createStream(
+ F.block_size(), F.block_count(), F.layout(), F);
enum class MyEnum : uint32_t { Val1 = 2908234, Val2 = 120891234 };
using support::ulittle32_t;
@@ -306,10 +319,12 @@ TEST(MappedBlockStreamTest, TestWriteThenRead) {
ArrayRef<uint8_t> byteArrayRef0(byteArray0);
ArrayRef<uint8_t> byteArrayRef1(byteArray1);
ArrayRef<uint8_t> byteArray[] = { byteArrayRef0, byteArrayRef1 };
- ArrayRef<uint32_t> intArray[] = {{890723408, 29082234}, {0, 0}};
+ uint32_t intArr0[] = {890723408, 29082234};
+ uint32_t intArr1[] = {890723408, 29082234};
+ ArrayRef<uint32_t> intArray[] = {intArr0, intArr1};
- StreamReader Reader(S);
- StreamWriter Writer(S);
+ StreamReader Reader(*S);
+ StreamWriter Writer(*S);
EXPECT_NO_ERROR(Writer.writeInteger(u16[0]));
EXPECT_NO_ERROR(Reader.readInteger(u16[1]));
EXPECT_EQ(u16[0], u16[1]);
@@ -379,26 +394,26 @@ TEST(MappedBlockStreamTest, TestWriteContiguousStreamRef) {
std::vector<uint8_t> SrcDataBytes(10);
MutableArrayRef<uint8_t> SrcData(SrcDataBytes);
- DiscontiguousFile F(DestBlocks, DestData);
- MappedBlockStreamImpl DestStream(llvm::make_unique<IndexedStreamData>(0, F),
- F);
+ DiscontiguousStream F(DestBlocks, DestData);
+ auto DestStream = WritableMappedBlockStream::createStream(
+ F.block_size(), F.block_count(), F.layout(), F);
// First write "Test Str" into the source stream.
- ByteStream<true> SourceStream(SrcData);
+ MutableByteStream SourceStream(SrcData);
StreamWriter SourceWriter(SourceStream);
EXPECT_NO_ERROR(SourceWriter.writeZeroString("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);
+ StreamWriter 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);
+ StreamReader DestReader(*DestStream);
EXPECT_NO_ERROR(DestReader.readZeroString(Result));
EXPECT_EQ(Result, "Test Str");
}
@@ -412,29 +427,29 @@ TEST(MappedBlockStreamTest, TestWriteDiscontiguousStreamRef) {
MutableArrayRef<uint8_t> SrcData(SrcDataBytes);
const uint32_t SrcBlocks[] = {1, 0, 6, 3, 4, 5, 2, 7, 8, 9};
- DiscontiguousFile DestFile(DestBlocks, DestData);
- DiscontiguousFile SrcFile(SrcBlocks, SrcData);
+ DiscontiguousStream DestF(DestBlocks, DestData);
+ DiscontiguousStream SrcF(SrcBlocks, SrcData);
- MappedBlockStreamImpl DestStream(
- llvm::make_unique<IndexedStreamData>(0, DestFile), DestFile);
- MappedBlockStreamImpl SrcStream(
- llvm::make_unique<IndexedStreamData>(0, SrcFile), SrcFile);
+ auto Dest = WritableMappedBlockStream::createStream(
+ DestF.block_size(), DestF.block_count(), DestF.layout(), DestF);
+ auto Src = WritableMappedBlockStream::createStream(
+ SrcF.block_size(), SrcF.block_count(), SrcF.layout(), SrcF);
// First write "Test Str" into the source stream.
- StreamWriter SourceWriter(SrcStream);
+ StreamWriter SourceWriter(*Src);
EXPECT_NO_ERROR(SourceWriter.writeZeroString("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(DestStream);
- EXPECT_NO_ERROR(DestWriter.writeStreamRef(SrcStream));
+ StreamWriter 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(DestStream);
+ StreamReader DestReader(*Dest);
EXPECT_NO_ERROR(DestReader.readZeroString(Result));
EXPECT_EQ(Result, "Test Str");
}
diff --git a/unittests/ExecutionEngine/MCJIT/MCJITTestAPICommon.h b/unittests/ExecutionEngine/MCJIT/MCJITTestAPICommon.h
index 21def6e9eb1b..a3d3d1fffdbe 100644
--- a/unittests/ExecutionEngine/MCJIT/MCJITTestAPICommon.h
+++ b/unittests/ExecutionEngine/MCJIT/MCJITTestAPICommon.h
@@ -15,6 +15,7 @@
#ifndef LLVM_UNITTESTS_EXECUTIONENGINE_MCJIT_MCJITTESTAPICOMMON_H
#define LLVM_UNITTESTS_EXECUTIONENGINE_MCJIT_MCJITTESTAPICOMMON_H
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Triple.h"
#include "llvm/IR/LegacyPassManager.h"
@@ -56,19 +57,17 @@ protected:
bool ArchSupportsMCJIT() {
Triple Host(HostTriple);
// If ARCH is not supported, bail
- if (std::find(SupportedArchs.begin(), SupportedArchs.end(), Host.getArch())
- == SupportedArchs.end())
+ if (!is_contained(SupportedArchs, Host.getArch()))
return false;
// If ARCH is supported and has no specific sub-arch support
- if (std::find(HasSubArchs.begin(), HasSubArchs.end(), Host.getArch())
- == HasSubArchs.end())
+ if (!is_contained(HasSubArchs, Host.getArch()))
return true;
// If ARCH has sub-arch support, find it
SmallVectorImpl<std::string>::const_iterator I = SupportedSubArchs.begin();
for(; I != SupportedSubArchs.end(); ++I)
- if (Host.getArchName().startswith(I->c_str()))
+ if (Host.getArchName().startswith(*I))
return true;
return false;
@@ -78,12 +77,11 @@ protected:
bool OSSupportsMCJIT() {
Triple Host(HostTriple);
- if (std::find(UnsupportedEnvironments.begin(), UnsupportedEnvironments.end(),
- Host.getEnvironment()) != UnsupportedEnvironments.end())
+ if (find(UnsupportedEnvironments, Host.getEnvironment()) !=
+ UnsupportedEnvironments.end())
return false;
- if (std::find(UnsupportedOSs.begin(), UnsupportedOSs.end(), Host.getOS())
- == UnsupportedOSs.end())
+ if (!is_contained(UnsupportedOSs, Host.getOS()))
return true;
return false;
diff --git a/unittests/ExecutionEngine/Orc/CompileOnDemandLayerTest.cpp b/unittests/ExecutionEngine/Orc/CompileOnDemandLayerTest.cpp
index 8140a1ff2493..ab04c14b0957 100644
--- a/unittests/ExecutionEngine/Orc/CompileOnDemandLayerTest.cpp
+++ b/unittests/ExecutionEngine/Orc/CompileOnDemandLayerTest.cpp
@@ -26,7 +26,7 @@ public:
class DummyStubsManager : public orc::IndirectStubsManager {
public:
- Error createStub(StringRef StubName, TargetAddress InitAddr,
+ Error createStub(StringRef StubName, JITTargetAddress InitAddr,
JITSymbolFlags Flags) override {
llvm_unreachable("Not implemented");
}
@@ -43,7 +43,7 @@ public:
llvm_unreachable("Not implemented");
}
- Error updatePointer(StringRef Name, TargetAddress NewAddr) override {
+ Error updatePointer(StringRef Name, JITTargetAddress NewAddr) override {
llvm_unreachable("Not implemented");
}
};
diff --git a/unittests/ExecutionEngine/Orc/GlobalMappingLayerTest.cpp b/unittests/ExecutionEngine/Orc/GlobalMappingLayerTest.cpp
index 054fc16cabd4..25b6c891c622 100644
--- a/unittests/ExecutionEngine/Orc/GlobalMappingLayerTest.cpp
+++ b/unittests/ExecutionEngine/Orc/GlobalMappingLayerTest.cpp
@@ -21,7 +21,7 @@ struct MockBaseLayer {
JITSymbol findSymbol(const std::string &Name, bool ExportedSymbolsOnly) {
if (Name == "bar")
- return llvm::orc::JITSymbol(0x4567, JITSymbolFlags::Exported);
+ return llvm::JITSymbol(0x4567, JITSymbolFlags::Exported);
return nullptr;
}
@@ -37,13 +37,13 @@ TEST(GlobalMappingLayerTest, Empty) {
// Test fall-through for symbol in base layer.
auto BarSym = L.findSymbol("bar", true);
- EXPECT_EQ(BarSym.getAddress(), static_cast<TargetAddress>(0x4567))
+ EXPECT_EQ(BarSym.getAddress(), static_cast<JITTargetAddress>(0x4567))
<< "Symbol lookup fall-through failed.";
// Test setup of a global mapping.
L.setGlobalMapping("foo", 0x0123);
auto FooSym2 = L.findSymbol("foo", true);
- EXPECT_EQ(FooSym2.getAddress(), static_cast<TargetAddress>(0x0123))
+ EXPECT_EQ(FooSym2.getAddress(), static_cast<JITTargetAddress>(0x0123))
<< "Symbol mapping setup failed.";
// Test removal of a global mapping.
diff --git a/unittests/ExecutionEngine/Orc/LazyEmittingLayerTest.cpp b/unittests/ExecutionEngine/Orc/LazyEmittingLayerTest.cpp
index a495766db91a..3362f490a38a 100644
--- a/unittests/ExecutionEngine/Orc/LazyEmittingLayerTest.cpp
+++ b/unittests/ExecutionEngine/Orc/LazyEmittingLayerTest.cpp
@@ -7,6 +7,7 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/ExecutionEngine/RuntimeDyld.h"
#include "llvm/ExecutionEngine/Orc/LazyEmittingLayer.h"
#include "gtest/gtest.h"
@@ -17,7 +18,7 @@ struct MockBaseLayer {
ModuleSetHandleT addModuleSet(
std::list<std::unique_ptr<llvm::Module>>,
std::unique_ptr<llvm::RuntimeDyld::MemoryManager> MemMgr,
- std::unique_ptr<llvm::RuntimeDyld::SymbolResolver> Resolver) {
+ std::unique_ptr<llvm::JITSymbolResolver> Resolver) {
EXPECT_FALSE(MemMgr);
return 42;
}
diff --git a/unittests/ExecutionEngine/Orc/ObjectLinkingLayerTest.cpp b/unittests/ExecutionEngine/Orc/ObjectLinkingLayerTest.cpp
index 87928347d88e..44b44f604159 100644
--- a/unittests/ExecutionEngine/Orc/ObjectLinkingLayerTest.cpp
+++ b/unittests/ExecutionEngine/Orc/ObjectLinkingLayerTest.cpp
@@ -90,10 +90,10 @@ TEST(ObjectLinkingLayerTest, TestSetProcessAllSections) {
auto Resolver =
createLambdaResolver(
[](const std::string &Name) {
- return RuntimeDyld::SymbolInfo(nullptr);
+ return JITSymbol(nullptr);
},
[](const std::string &Name) {
- return RuntimeDyld::SymbolInfo(nullptr);
+ return JITSymbol(nullptr);
});
{
@@ -165,11 +165,11 @@ TEST_F(ObjectLinkingLayerExecutionTest, NoDuplicateFinalization) {
createLambdaResolver(
[&](const std::string &Name) {
if (auto Sym = ObjLayer.findSymbol(Name, true))
- return Sym.toRuntimeDyldSymbol();
- return RuntimeDyld::SymbolInfo(nullptr);
+ return Sym;
+ return JITSymbol(nullptr);
},
[](const std::string &Name) {
- return RuntimeDyld::SymbolInfo(nullptr);
+ return JITSymbol(nullptr);
});
SectionMemoryManagerWrapper SMMW;
diff --git a/unittests/ExecutionEngine/Orc/ObjectTransformLayerTest.cpp b/unittests/ExecutionEngine/Orc/ObjectTransformLayerTest.cpp
index e1b1f2f92781..63b85dc82ca8 100644
--- a/unittests/ExecutionEngine/Orc/ObjectTransformLayerTest.cpp
+++ b/unittests/ExecutionEngine/Orc/ObjectTransformLayerTest.cpp
@@ -95,31 +95,32 @@ public:
resetExpectations();
}
- JITSymbol findSymbol(const std::string &Name, bool ExportedSymbolsOnly) {
+ llvm::JITSymbol findSymbol(const std::string &Name,
+ bool ExportedSymbolsOnly) {
EXPECT_EQ(MockName, Name) << "Name should pass through";
EXPECT_EQ(MockBool, ExportedSymbolsOnly) << "Flag should pass through";
LastCalled = "findSymbol";
- MockSymbol = JITSymbol(122, llvm::JITSymbolFlags::None);
+ MockSymbol = llvm::JITSymbol(122, llvm::JITSymbolFlags::None);
return MockSymbol;
}
void expectFindSymbol(const std::string &Name, bool ExportedSymbolsOnly) {
MockName = Name;
MockBool = ExportedSymbolsOnly;
}
- void verifyFindSymbol(llvm::orc::JITSymbol Returned) {
+ void verifyFindSymbol(llvm::JITSymbol Returned) {
EXPECT_EQ("findSymbol", LastCalled);
EXPECT_EQ(MockSymbol.getAddress(), Returned.getAddress())
<< "Return should pass through";
resetExpectations();
}
- JITSymbol findSymbolIn(ObjSetHandleT H, const std::string &Name,
- bool ExportedSymbolsOnly) {
+ llvm::JITSymbol findSymbolIn(ObjSetHandleT H, const std::string &Name,
+ bool ExportedSymbolsOnly) {
EXPECT_EQ(MockObjSetHandle, H) << "Handle should pass through";
EXPECT_EQ(MockName, Name) << "Name should pass through";
EXPECT_EQ(MockBool, ExportedSymbolsOnly) << "Flag should pass through";
LastCalled = "findSymbolIn";
- MockSymbol = JITSymbol(122, llvm::JITSymbolFlags::None);
+ MockSymbol = llvm::JITSymbol(122, llvm::JITSymbolFlags::None);
return MockSymbol;
}
void expectFindSymbolIn(ObjSetHandleT H, const std::string &Name,
@@ -128,7 +129,7 @@ public:
MockName = Name;
MockBool = ExportedSymbolsOnly;
}
- void verifyFindSymbolIn(llvm::orc::JITSymbol Returned) {
+ void verifyFindSymbolIn(llvm::JITSymbol Returned) {
EXPECT_EQ("findSymbolIn", LastCalled);
EXPECT_EQ(MockSymbol.getAddress(), Returned.getAddress())
<< "Return should pass through";
@@ -146,14 +147,14 @@ public:
}
void mapSectionAddress(ObjSetHandleT H, const void *LocalAddress,
- TargetAddress TargetAddr) {
+ llvm::JITTargetAddress TargetAddr) {
EXPECT_EQ(MockObjSetHandle, H);
EXPECT_EQ(MockLocalAddress, LocalAddress);
EXPECT_EQ(MockTargetAddress, TargetAddr);
LastCalled = "mapSectionAddress";
}
void expectMapSectionAddress(ObjSetHandleT H, const void *LocalAddress,
- TargetAddress TargetAddr) {
+ llvm::JITTargetAddress TargetAddr) {
MockObjSetHandle = H;
MockLocalAddress = LocalAddress;
MockTargetAddress = TargetAddr;
@@ -172,9 +173,9 @@ private:
ObjSetHandleT MockObjSetHandle;
std::string MockName;
bool MockBool;
- JITSymbol MockSymbol;
+ llvm::JITSymbol MockSymbol;
const void *MockLocalAddress;
- TargetAddress MockTargetAddress;
+ llvm::JITTargetAddress MockTargetAddress;
MockMemoryBufferSet MockBufferSet;
// Clear remembered parameters between calls
@@ -185,7 +186,7 @@ private:
MockObjects.clear();
MockObjSetHandle = 0;
MockName = "bogus";
- MockSymbol = JITSymbol(nullptr);
+ MockSymbol = llvm::JITSymbol(nullptr);
MockLocalAddress = nullptr;
MockTargetAddress = 0;
MockBufferSet = 0;
@@ -245,7 +246,7 @@ TEST(ObjectTransformLayerTest, Main) {
std::string Name = "foo";
bool ExportedOnly = true;
M.expectFindSymbol(Name, ExportedOnly);
- JITSymbol Symbol = T2.findSymbol(Name, ExportedOnly);
+ llvm::JITSymbol Symbol = T2.findSymbol(Name, ExportedOnly);
M.verifyFindSymbol(Symbol);
// Test findSymbolIn
@@ -262,7 +263,7 @@ TEST(ObjectTransformLayerTest, Main) {
// Test mapSectionAddress
char Buffer[24];
- TargetAddress MockAddress = 255;
+ llvm::JITTargetAddress MockAddress = 255;
M.expectMapSectionAddress(H, Buffer, MockAddress);
T1.mapSectionAddress(H, Buffer, MockAddress);
M.verifyMapSectionAddress();
diff --git a/unittests/ExecutionEngine/Orc/OrcTestCommon.h b/unittests/ExecutionEngine/Orc/OrcTestCommon.h
index fe3da88dc9d1..f3972a3084e5 100644
--- a/unittests/ExecutionEngine/Orc/OrcTestCommon.h
+++ b/unittests/ExecutionEngine/Orc/OrcTestCommon.h
@@ -22,7 +22,7 @@
#include "llvm/IR/TypeBuilder.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
-#include "llvm/ExecutionEngine/Orc/JITSymbol.h"
+#include "llvm/ExecutionEngine/JITSymbol.h"
#include "llvm/Support/TargetSelect.h"
#include <memory>
@@ -124,11 +124,11 @@ public:
RemoveModuleSet(H);
}
- orc::JITSymbol findSymbol(const std::string &Name, bool ExportedSymbolsOnly) {
+ JITSymbol findSymbol(const std::string &Name, bool ExportedSymbolsOnly) {
return FindSymbol(Name, ExportedSymbolsOnly);
}
- orc::JITSymbol findSymbolIn(ModuleSetHandleT H, const std::string &Name,
+ JITSymbol findSymbolIn(ModuleSetHandleT H, const std::string &Name,
bool ExportedSymbolsOnly) {
return FindSymbolIn(H, Name, ExportedSymbolsOnly);
}
diff --git a/unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp b/unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp
index 7d55641e4ce2..381fd1030422 100644
--- a/unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp
+++ b/unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/ExecutionEngine/Orc/RPCChannel.h"
+#include "llvm/ExecutionEngine/Orc/RawByteChannel.h"
#include "llvm/ExecutionEngine/Orc/RPCUtils.h"
#include "gtest/gtest.h"
@@ -15,42 +15,39 @@
using namespace llvm;
using namespace llvm::orc;
-using namespace llvm::orc::remote;
+using namespace llvm::orc::rpc;
class Queue : public std::queue<char> {
public:
- std::mutex &getLock() { return Lock; }
-
+ std::mutex &getMutex() { return M; }
+ std::condition_variable &getCondVar() { return CV; }
private:
- std::mutex Lock;
+ std::mutex M;
+ std::condition_variable CV;
};
-class QueueChannel : public RPCChannel {
+class QueueChannel : public RawByteChannel {
public:
QueueChannel(Queue &InQueue, Queue &OutQueue)
: InQueue(InQueue), OutQueue(OutQueue) {}
Error readBytes(char *Dst, unsigned Size) override {
- while (Size != 0) {
- // If there's nothing to read then yield.
+ std::unique_lock<std::mutex> Lock(InQueue.getMutex());
+ while (Size) {
while (InQueue.empty())
- std::this_thread::yield();
-
- // Lock the channel and read what we can.
- std::lock_guard<std::mutex> Lock(InQueue.getLock());
- while (!InQueue.empty() && Size) {
- *Dst++ = InQueue.front();
- --Size;
- InQueue.pop();
- }
+ InQueue.getCondVar().wait(Lock);
+ *Dst++ = InQueue.front();
+ --Size;
+ InQueue.pop();
}
return Error::success();
}
Error appendBytes(const char *Src, unsigned Size) override {
- std::lock_guard<std::mutex> Lock(OutQueue.getLock());
+ std::unique_lock<std::mutex> Lock(OutQueue.getMutex());
while (Size--)
OutQueue.push(*Src++);
+ OutQueue.getCondVar().notify_one();
return Error::success();
}
@@ -61,148 +58,402 @@ private:
Queue &OutQueue;
};
-class DummyRPC : public testing::Test, public RPC<QueueChannel> {
+class RPCFoo {};
+
+namespace llvm {
+namespace orc {
+namespace rpc {
+
+ template <>
+ class RPCTypeName<RPCFoo> {
+ public:
+ static const char* getName() { return "RPCFoo"; }
+ };
+
+ template <>
+ class SerializationTraits<QueueChannel, RPCFoo, RPCFoo> {
+ public:
+ static Error serialize(QueueChannel&, const RPCFoo&) {
+ return Error::success();
+ }
+
+ static Error deserialize(QueueChannel&, RPCFoo&) {
+ return Error::success();
+ }
+ };
+
+} // end namespace rpc
+} // end namespace orc
+} // end namespace llvm
+
+class RPCBar {};
+
+namespace llvm {
+namespace orc {
+namespace rpc {
+
+ template <>
+ class SerializationTraits<QueueChannel, RPCFoo, RPCBar> {
+ public:
+ static Error serialize(QueueChannel&, const RPCBar&) {
+ return Error::success();
+ }
+
+ static Error deserialize(QueueChannel&, RPCBar&) {
+ return Error::success();
+ }
+};
+
+} // end namespace rpc
+} // end namespace orc
+} // end namespace llvm
+
+class DummyRPCAPI {
public:
- enum FuncId : uint32_t {
- VoidBoolId = RPCFunctionIdTraits<FuncId>::FirstValidId,
- IntIntId,
- AllTheTypesId
+
+ class VoidBool : public Function<VoidBool, void(bool)> {
+ public:
+ static const char* getName() { return "VoidBool"; }
+ };
+
+ class IntInt : public Function<IntInt, int32_t(int32_t)> {
+ public:
+ static const char* getName() { return "IntInt"; }
+ };
+
+ class AllTheTypes
+ : public Function<AllTheTypes,
+ void(int8_t, uint8_t, int16_t, uint16_t, int32_t,
+ uint32_t, int64_t, uint64_t, bool, std::string,
+ std::vector<int>)> {
+ public:
+ static const char* getName() { return "AllTheTypes"; }
};
- typedef Function<VoidBoolId, void(bool)> VoidBool;
- typedef Function<IntIntId, int32_t(int32_t)> IntInt;
- typedef Function<AllTheTypesId,
- void(int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t,
- int64_t, uint64_t, bool, std::string, std::vector<int>)>
- AllTheTypes;
+ class CustomType : public Function<CustomType, RPCFoo(RPCFoo)> {
+ public:
+ static const char* getName() { return "CustomType"; }
+ };
+
+};
+
+class DummyRPCEndpoint : public DummyRPCAPI,
+ public SingleThreadedRPC<QueueChannel> {
+public:
+ DummyRPCEndpoint(Queue &Q1, Queue &Q2)
+ : SingleThreadedRPC(C, true), C(Q1, Q2) {}
+private:
+ QueueChannel C;
};
-TEST_F(DummyRPC, TestAsyncVoidBool) {
+
+TEST(DummyRPC, TestAsyncVoidBool) {
Queue Q1, Q2;
- QueueChannel C1(Q1, Q2);
- QueueChannel C2(Q2, Q1);
+ DummyRPCEndpoint Client(Q1, Q2);
+ DummyRPCEndpoint Server(Q2, Q1);
- // Make an async call.
- auto ResOrErr = callAsyncWithSeq<VoidBool>(C1, true);
- EXPECT_TRUE(!!ResOrErr) << "Simple call over queue failed";
+ std::thread ServerThread([&]() {
+ Server.addHandler<DummyRPCAPI::VoidBool>(
+ [](bool B) {
+ EXPECT_EQ(B, true)
+ << "Server void(bool) received unexpected result";
+ });
+
+ {
+ // 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)";
+ }
+ });
{
- // Expect a call to Proc1.
- auto EC = expect<VoidBool>(C2, [&](bool &B) {
- EXPECT_EQ(B, true) << "Bool serialization broken";
- return Error::success();
- });
- EXPECT_FALSE(EC) << "Simple expect over queue failed";
+ // Make an async call.
+ auto Err = Client.callAsync<DummyRPCAPI::VoidBool>(
+ [](Error Err) {
+ EXPECT_FALSE(!!Err) << "Async void(bool) response handler failed";
+ return Error::success();
+ }, true);
+ EXPECT_FALSE(!!Err) << "Client.callAsync failed for void(bool)";
}
{
- // Wait for the result.
- auto EC = waitForResult(C1, ResOrErr->second, handleNone);
- EXPECT_FALSE(EC) << "Could not read result.";
+ // Poke the client to process the result of the void(bool) call.
+ auto Err = Client.handleOne();
+ EXPECT_FALSE(!!Err) << "Client failed to handle response from void(bool)";
}
- // Verify that the function returned ok.
- auto Val = ResOrErr->first.get();
- EXPECT_TRUE(Val) << "Remote void function failed to execute.";
+ ServerThread.join();
}
-TEST_F(DummyRPC, TestAsyncIntInt) {
+TEST(DummyRPC, TestAsyncIntInt) {
Queue Q1, Q2;
- QueueChannel C1(Q1, Q2);
- QueueChannel C2(Q2, Q1);
+ DummyRPCEndpoint Client(Q1, Q2);
+ DummyRPCEndpoint Server(Q2, Q1);
- // Make an async call.
- auto ResOrErr = callAsyncWithSeq<IntInt>(C1, 21);
- EXPECT_TRUE(!!ResOrErr) << "Simple call over queue failed";
+ std::thread ServerThread([&]() {
+ Server.addHandler<DummyRPCAPI::IntInt>(
+ [](int X) -> int {
+ EXPECT_EQ(X, 21) << "Server int(int) receieved unexpected result";
+ return 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 int(int) call.
+ auto Err = Server.handleOne();
+ EXPECT_FALSE(!!Err) << "Server failed to handle call to int(int)";
+ }
+ });
+
+ {
+ 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)";
+ }
{
- // Expect a call to Proc1.
- auto EC = expect<IntInt>(C2, [&](int32_t I) -> Expected<int32_t> {
- EXPECT_EQ(I, 21) << "Bool serialization broken";
- return 2 * I;
+ // 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, TestSerialization) {
+ Queue Q1, Q2;
+ DummyRPCEndpoint Client(Q1, Q2);
+ DummyRPCEndpoint Server(Q2, Q1);
+
+ std::thread ServerThread([&]() {
+ Server.addHandler<DummyRPCAPI::AllTheTypes>(
+ [&](int8_t S8, uint8_t U8, int16_t S16, uint16_t U16,
+ int32_t S32, uint32_t U32, int64_t S64, uint64_t U64,
+ bool B, std::string S, std::vector<int> V) {
+
+ EXPECT_EQ(S8, -101) << "int8_t serialization broken";
+ EXPECT_EQ(U8, 250) << "uint8_t serialization broken";
+ EXPECT_EQ(S16, -10000) << "int16_t serialization broken";
+ EXPECT_EQ(U16, 10000) << "uint16_t serialization broken";
+ EXPECT_EQ(S32, -1000000000) << "int32_t serialization broken";
+ EXPECT_EQ(U32, 1000000000ULL) << "uint32_t serialization broken";
+ EXPECT_EQ(S64, -10000000000) << "int64_t serialization broken";
+ EXPECT_EQ(U64, 10000000000ULL) << "uint64_t serialization broken";
+ EXPECT_EQ(B, true) << "bool serialization broken";
+ EXPECT_EQ(S, "foo") << "std::string serialization broken";
+ EXPECT_EQ(V, std::vector<int>({42, 7}))
+ << "std::vector serialization broken";
+ return Error::success();
+ });
+
+ {
+ // 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 AllTheTypes call.
+ auto Err = Server.handleOne();
+ EXPECT_FALSE(!!Err) << "Server failed to handle call to void(bool)";
+ }
});
- EXPECT_FALSE(EC) << "Simple expect over queue failed";
+
+
+ {
+ // Make an async call.
+ std::vector<int> v({42, 7});
+ auto Err = Client.callAsync<DummyRPCAPI::AllTheTypes>(
+ [](Error Err) {
+ EXPECT_FALSE(!!Err) << "Async AllTheTypes response handler failed";
+ return Error::success();
+ },
+ static_cast<int8_t>(-101), static_cast<uint8_t>(250),
+ static_cast<int16_t>(-10000), static_cast<uint16_t>(10000),
+ static_cast<int32_t>(-1000000000), static_cast<uint32_t>(1000000000),
+ static_cast<int64_t>(-10000000000), static_cast<uint64_t>(10000000000),
+ true, std::string("foo"), v);
+ EXPECT_FALSE(!!Err) << "Client.callAsync failed for AllTheTypes";
}
{
- // Wait for the result.
- auto EC = waitForResult(C1, ResOrErr->second, handleNone);
- EXPECT_FALSE(EC) << "Could not read result.";
+ // Poke the client to process the result of the AllTheTypes call.
+ auto Err = Client.handleOne();
+ EXPECT_FALSE(!!Err) << "Client failed to handle response from AllTheTypes";
}
- // Verify that the function returned ok.
- auto Val = ResOrErr->first.get();
- EXPECT_TRUE(!!Val) << "Remote int function failed to execute.";
- EXPECT_EQ(*Val, 42) << "Remote int function return wrong value.";
+ ServerThread.join();
}
-TEST_F(DummyRPC, TestSerialization) {
+TEST(DummyRPC, TestCustomType) {
Queue Q1, Q2;
- QueueChannel C1(Q1, Q2);
- QueueChannel C2(Q2, Q1);
+ DummyRPCEndpoint Client(Q1, Q2);
+ DummyRPCEndpoint Server(Q2, Q1);
- // Make a call to Proc1.
- std::vector<int> v({42, 7});
- auto ResOrErr = callAsyncWithSeq<AllTheTypes>(
- C1, -101, 250, -10000, 10000, -1000000000, 1000000000, -10000000000,
- 10000000000, true, "foo", v);
- EXPECT_TRUE(!!ResOrErr) << "Big (serialization test) call over queue failed";
+ std::thread ServerThread([&]() {
+ Server.addHandler<DummyRPCAPI::CustomType>(
+ [](RPCFoo F) {});
+
+ {
+ // 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 CustomType call.
+ auto Err = Server.handleOne();
+ EXPECT_FALSE(!!Err) << "Server failed to handle call to RPCFoo(RPCFoo)";
+ }
+ });
{
- // Expect a call to Proc1.
- auto EC = expect<AllTheTypes>(
- C2, [&](int8_t &s8, uint8_t &u8, int16_t &s16, uint16_t &u16,
- int32_t &s32, uint32_t &u32, int64_t &s64, uint64_t &u64,
- bool &b, std::string &s, std::vector<int> &v) {
-
- EXPECT_EQ(s8, -101) << "int8_t serialization broken";
- EXPECT_EQ(u8, 250) << "uint8_t serialization broken";
- EXPECT_EQ(s16, -10000) << "int16_t serialization broken";
- EXPECT_EQ(u16, 10000) << "uint16_t serialization broken";
- EXPECT_EQ(s32, -1000000000) << "int32_t serialization broken";
- EXPECT_EQ(u32, 1000000000ULL) << "uint32_t serialization broken";
- EXPECT_EQ(s64, -10000000000) << "int64_t serialization broken";
- EXPECT_EQ(u64, 10000000000ULL) << "uint64_t serialization broken";
- EXPECT_EQ(b, true) << "bool serialization broken";
- EXPECT_EQ(s, "foo") << "std::string serialization broken";
- EXPECT_EQ(v, std::vector<int>({42, 7}))
- << "std::vector serialization broken";
+ // Make an async call.
+ auto Err = Client.callAsync<DummyRPCAPI::CustomType>(
+ [](Expected<RPCFoo> FOrErr) {
+ EXPECT_TRUE(!!FOrErr)
+ << "Async RPCFoo(RPCFoo) response handler failed";
return Error::success();
- });
- EXPECT_FALSE(EC) << "Big (serialization test) call over queue failed";
+ }, RPCFoo());
+ EXPECT_FALSE(!!Err) << "Client.callAsync failed for RPCFoo(RPCFoo)";
}
{
- // Wait for the result.
- auto EC = waitForResult(C1, ResOrErr->second, handleNone);
- EXPECT_FALSE(EC) << "Could not read result.";
+ // Poke the client to process the result of the RPCFoo() call.
+ auto Err = Client.handleOne();
+ EXPECT_FALSE(!!Err)
+ << "Client failed to handle response from RPCFoo(RPCFoo)";
}
- // Verify that the function returned ok.
- auto Val = ResOrErr->first.get();
- EXPECT_TRUE(Val) << "Remote void function failed to execute.";
+ ServerThread.join();
}
-// Test the synchronous call API.
-// FIXME: Re-enable once deadlock encountered on S390 has been debugged / fixed,
-// see http://lab.llvm.org:8011/builders/clang-s390x-linux/builds/3459
-// TEST_F(DummyRPC, TestSynchronousCall) {
-// Queue Q1, Q2;
-// QueueChannel C1(Q1, Q2);
-// QueueChannel C2(Q2, Q1);
-//
-// auto ServerResult =
-// std::async(std::launch::async,
-// [&]() {
-// return expect<IntInt>(C2, [&](int32_t V) { return V; });
-// });
-//
-// auto ValOrErr = callST<IntInt>(C1, 42);
-//
-// EXPECT_FALSE(!!ServerResult.get())
-// << "Server returned an error.";
-// EXPECT_TRUE(!!ValOrErr)
-// << "callST returned an error.";
-// EXPECT_EQ(*ValOrErr, 42)
-// << "Incorrect callST<IntInt> result";
-// }
+TEST(DummyRPC, TestWithAltCustomType) {
+ Queue Q1, Q2;
+ DummyRPCEndpoint Client(Q1, Q2);
+ DummyRPCEndpoint Server(Q2, Q1);
+
+ std::thread ServerThread([&]() {
+ Server.addHandler<DummyRPCAPI::CustomType>(
+ [](RPCBar F) {});
+
+ {
+ // 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 CustomType call.
+ auto Err = Server.handleOne();
+ EXPECT_FALSE(!!Err) << "Server failed to handle call to RPCFoo(RPCFoo)";
+ }
+ });
+
+ {
+ // Make an async call.
+ auto Err = Client.callAsync<DummyRPCAPI::CustomType>(
+ [](Expected<RPCBar> FOrErr) {
+ EXPECT_TRUE(!!FOrErr)
+ << "Async RPCFoo(RPCFoo) response handler failed";
+ return Error::success();
+ }, RPCBar());
+ EXPECT_FALSE(!!Err) << "Client.callAsync failed for RPCFoo(RPCFoo)";
+ }
+
+ {
+ // Poke the client to process the result of the RPCFoo() call.
+ auto Err = Client.handleOne();
+ EXPECT_FALSE(!!Err)
+ << "Client failed to handle response from RPCFoo(RPCFoo)";
+ }
+
+ ServerThread.join();
+}
+
+TEST(DummyRPC, TestParallelCallGroup) {
+ Queue Q1, Q2;
+ DummyRPCEndpoint Client(Q1, Q2);
+ DummyRPCEndpoint Server(Q2, Q1);
+
+ std::thread ServerThread([&]() {
+ Server.addHandler<DummyRPCAPI::IntInt>(
+ [](int X) -> int {
+ return 2 * X;
+ });
+
+ // Handle the negotiate, plus three calls.
+ for (unsigned I = 0; I != 4; ++I) {
+ auto Err = Server.handleOne();
+ EXPECT_FALSE(!!Err) << "Server failed to handle call to int(int)";
+ }
+ });
+
+ {
+ int A, B, C;
+ ParallelCallGroup<DummyRPCEndpoint> PCG(Client);
+
+ {
+ auto Err = PCG.appendCall<DummyRPCAPI::IntInt>(
+ [&A](Expected<int> Result) {
+ EXPECT_TRUE(!!Result) << "Async int(int) response handler failed";
+ A = *Result;
+ return Error::success();
+ }, 1);
+ EXPECT_FALSE(!!Err) << "First parallel call failed for int(int)";
+ }
+
+ {
+ auto Err = PCG.appendCall<DummyRPCAPI::IntInt>(
+ [&B](Expected<int> Result) {
+ EXPECT_TRUE(!!Result) << "Async int(int) response handler failed";
+ B = *Result;
+ return Error::success();
+ }, 2);
+ EXPECT_FALSE(!!Err) << "Second parallel call failed for int(int)";
+ }
+
+ {
+ auto Err = PCG.appendCall<DummyRPCAPI::IntInt>(
+ [&C](Expected<int> Result) {
+ EXPECT_TRUE(!!Result) << "Async int(int) response handler failed";
+ C = *Result;
+ return Error::success();
+ }, 3);
+ EXPECT_FALSE(!!Err) << "Third parallel call failed for int(int)";
+ }
+
+ // Handle the three int(int) results.
+ for (unsigned I = 0; I != 3; ++I) {
+ auto Err = Client.handleOne();
+ 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)";
+ }
+
+ EXPECT_EQ(A, 2) << "First parallel call returned bogus result";
+ EXPECT_EQ(B, 4) << "Second parallel call returned bogus result";
+ EXPECT_EQ(C, 6) << "Third parallel call returned bogus result";
+ }
+
+ ServerThread.join();
+}
diff --git a/unittests/IR/CMakeLists.txt b/unittests/IR/CMakeLists.txt
index 2baa4370c70e..750f638c7a42 100644
--- a/unittests/IR/CMakeLists.txt
+++ b/unittests/IR/CMakeLists.txt
@@ -20,6 +20,7 @@ set(IRSources
LegacyPassManagerTest.cpp
MDBuilderTest.cpp
MetadataTest.cpp
+ ModuleTest.cpp
PassManagerTest.cpp
PatternMatch.cpp
TypeBuilderTest.cpp
diff --git a/unittests/IR/ConstantRangeTest.cpp b/unittests/IR/ConstantRangeTest.cpp
index f7a8a82043b9..58fd04448e2e 100644
--- a/unittests/IR/ConstantRangeTest.cpp
+++ b/unittests/IR/ConstantRangeTest.cpp
@@ -102,10 +102,19 @@ TEST_F(ConstantRangeTest, Equality) {
TEST_F(ConstantRangeTest, SingleElement) {
EXPECT_EQ(Full.getSingleElement(), static_cast<APInt *>(nullptr));
EXPECT_EQ(Empty.getSingleElement(), static_cast<APInt *>(nullptr));
+ EXPECT_EQ(Full.getSingleMissingElement(), static_cast<APInt *>(nullptr));
+ EXPECT_EQ(Empty.getSingleMissingElement(), static_cast<APInt *>(nullptr));
+
EXPECT_EQ(*One.getSingleElement(), APInt(16, 0xa));
EXPECT_EQ(Some.getSingleElement(), static_cast<APInt *>(nullptr));
EXPECT_EQ(Wrap.getSingleElement(), static_cast<APInt *>(nullptr));
+ EXPECT_EQ(One.getSingleMissingElement(), static_cast<APInt *>(nullptr));
+ EXPECT_EQ(Some.getSingleMissingElement(), static_cast<APInt *>(nullptr));
+
+ ConstantRange OneInverse = One.inverse();
+ EXPECT_EQ(*OneInverse.getSingleMissingElement(), *One.getSingleElement());
+
EXPECT_FALSE(Full.isSingleElement());
EXPECT_FALSE(Empty.isSingleElement());
EXPECT_TRUE(One.isSingleElement());
@@ -348,6 +357,32 @@ TEST_F(ConstantRangeTest, Add) {
ConstantRange(APInt(16, 0xe)));
}
+TEST_F(ConstantRangeTest, AddWithNoSignedWrap) {
+ EXPECT_EQ(Empty.addWithNoSignedWrap(APInt(16, 1)), Empty);
+ EXPECT_EQ(Full.addWithNoSignedWrap(APInt(16, 1)),
+ ConstantRange(APInt(16, INT16_MIN+1), APInt(16, INT16_MIN)));
+ EXPECT_EQ(ConstantRange(APInt(8, -50), APInt(8, 50)).addWithNoSignedWrap(APInt(8, 10)),
+ ConstantRange(APInt(8, -40), APInt(8, 60)));
+ EXPECT_EQ(ConstantRange(APInt(8, -50), APInt(8, 120)).addWithNoSignedWrap(APInt(8, 10)),
+ ConstantRange(APInt(8, -40), APInt(8, INT8_MIN)));
+ EXPECT_EQ(ConstantRange(APInt(8, 120), APInt(8, -10)).addWithNoSignedWrap(APInt(8, 5)),
+ ConstantRange(APInt(8, 125), APInt(8, -5)));
+ EXPECT_EQ(ConstantRange(APInt(8, 120), APInt(8, -120)).addWithNoSignedWrap(APInt(8, 10)),
+ ConstantRange(APInt(8, INT8_MIN+10), APInt(8, -110)));
+
+ EXPECT_EQ(Empty.addWithNoSignedWrap(APInt(16, -1)), Empty);
+ EXPECT_EQ(Full.addWithNoSignedWrap(APInt(16, -1)),
+ ConstantRange(APInt(16, INT16_MIN), APInt(16, INT16_MAX)));
+ EXPECT_EQ(ConstantRange(APInt(8, -50), APInt(8, 50)).addWithNoSignedWrap(APInt(8, -10)),
+ ConstantRange(APInt(8, -60), APInt(8, 40)));
+ EXPECT_EQ(ConstantRange(APInt(8, -120), APInt(8, 50)).addWithNoSignedWrap(APInt(8, -10)),
+ ConstantRange(APInt(8, INT8_MIN), APInt(8, 40)));
+ EXPECT_EQ(ConstantRange(APInt(8, 120), APInt(8, -120)).addWithNoSignedWrap(APInt(8, -5)),
+ ConstantRange(APInt(8, 115), APInt(8, -125)));
+ EXPECT_EQ(ConstantRange(APInt(8, 120), APInt(8, -120)).addWithNoSignedWrap(APInt(8, -10)),
+ ConstantRange(APInt(8, 110), APInt(8, INT8_MIN-10)));
+}
+
TEST_F(ConstantRangeTest, Sub) {
EXPECT_EQ(Full.sub(APInt(16, 4)), Full);
EXPECT_EQ(Full.sub(Full), Full);
@@ -760,6 +795,42 @@ TEST(ConstantRange, GetEquivalentICmp) {
EXPECT_FALSE(ConstantRange(APInt::getMinValue(32) - APInt(32, 100),
APInt::getMinValue(32) + APInt(32, 100))
.getEquivalentICmp(Pred, RHS));
+
+ EXPECT_TRUE(ConstantRange(APInt(32, 100)).getEquivalentICmp(Pred, RHS));
+ EXPECT_EQ(Pred, CmpInst::ICMP_EQ);
+ EXPECT_EQ(RHS, APInt(32, 100));
+
+ EXPECT_TRUE(
+ ConstantRange(APInt(32, 100)).inverse().getEquivalentICmp(Pred, RHS));
+ EXPECT_EQ(Pred, CmpInst::ICMP_NE);
+ EXPECT_EQ(RHS, APInt(32, 100));
+
+ EXPECT_TRUE(
+ ConstantRange(APInt(512, 100)).inverse().getEquivalentICmp(Pred, RHS));
+ EXPECT_EQ(Pred, CmpInst::ICMP_NE);
+ EXPECT_EQ(RHS, APInt(512, 100));
+
+ // NB! It would be correct for the following four calls to getEquivalentICmp
+ // to return ordered predicates like CmpInst::ICMP_ULT or CmpInst::ICMP_UGT.
+ // However, that's not the case today.
+
+ EXPECT_TRUE(ConstantRange(APInt(32, 0)).getEquivalentICmp(Pred, RHS));
+ EXPECT_EQ(Pred, CmpInst::ICMP_EQ);
+ EXPECT_EQ(RHS, APInt(32, 0));
+
+ EXPECT_TRUE(
+ ConstantRange(APInt(32, 0)).inverse().getEquivalentICmp(Pred, RHS));
+ EXPECT_EQ(Pred, CmpInst::ICMP_NE);
+ EXPECT_EQ(RHS, APInt(32, 0));
+
+ EXPECT_TRUE(ConstantRange(APInt(32, -1)).getEquivalentICmp(Pred, RHS));
+ EXPECT_EQ(Pred, CmpInst::ICMP_EQ);
+ EXPECT_EQ(RHS, APInt(32, -1));
+
+ EXPECT_TRUE(
+ ConstantRange(APInt(32, -1)).inverse().getEquivalentICmp(Pred, RHS));
+ EXPECT_EQ(Pred, CmpInst::ICMP_NE);
+ EXPECT_EQ(RHS, APInt(32, -1));
}
} // anonymous namespace
diff --git a/unittests/IR/DebugInfoTest.cpp b/unittests/IR/DebugInfoTest.cpp
index f633782b3799..a80df3c54fd4 100644
--- a/unittests/IR/DebugInfoTest.cpp
+++ b/unittests/IR/DebugInfoTest.cpp
@@ -55,26 +55,28 @@ TEST(DINodeTest, getFlagString) {
DINode::getFlagString(DINode::FlagPublic | DINode::FlagVector));
EXPECT_EQ(StringRef(), DINode::getFlagString(DINode::FlagFwdDecl |
DINode::FlagArtificial));
- EXPECT_EQ(StringRef(), DINode::getFlagString(0xffff));
+ EXPECT_EQ(StringRef(),
+ DINode::getFlagString(static_cast<DINode::DIFlags>(0xffff)));
}
TEST(DINodeTest, splitFlags) {
// Some valid flags.
#define CHECK_SPLIT(FLAGS, VECTOR, REMAINDER) \
{ \
- SmallVector<unsigned, 8> V; \
+ SmallVector<DINode::DIFlags, 8> V; \
EXPECT_EQ(REMAINDER, DINode::splitFlags(FLAGS, V)); \
EXPECT_TRUE(makeArrayRef(V).equals(VECTOR)); \
}
- CHECK_SPLIT(DINode::FlagPublic, {DINode::FlagPublic}, 0u);
- CHECK_SPLIT(DINode::FlagProtected, {DINode::FlagProtected}, 0u);
- CHECK_SPLIT(DINode::FlagPrivate, {DINode::FlagPrivate}, 0u);
- CHECK_SPLIT(DINode::FlagVector, {DINode::FlagVector}, 0u);
- CHECK_SPLIT(DINode::FlagRValueReference, {DINode::FlagRValueReference}, 0u);
- unsigned Flags[] = {DINode::FlagFwdDecl, DINode::FlagVector};
- CHECK_SPLIT(DINode::FlagFwdDecl | DINode::FlagVector, Flags, 0u);
- CHECK_SPLIT(0x100000u, {}, 0x100000u);
- CHECK_SPLIT(0x100000u | DINode::FlagVector, {DINode::FlagVector}, 0x100000u);
+ CHECK_SPLIT(DINode::FlagPublic, {DINode::FlagPublic}, DINode::FlagZero);
+ CHECK_SPLIT(DINode::FlagProtected, {DINode::FlagProtected}, DINode::FlagZero);
+ CHECK_SPLIT(DINode::FlagPrivate, {DINode::FlagPrivate}, DINode::FlagZero);
+ CHECK_SPLIT(DINode::FlagVector, {DINode::FlagVector}, DINode::FlagZero);
+ CHECK_SPLIT(DINode::FlagRValueReference, {DINode::FlagRValueReference},
+ DINode::FlagZero);
+ DINode::DIFlags Flags[] = {DINode::FlagFwdDecl, DINode::FlagVector};
+ CHECK_SPLIT(DINode::FlagFwdDecl | DINode::FlagVector, Flags,
+ DINode::FlagZero);
+ CHECK_SPLIT(DINode::FlagZero, {}, DINode::FlagZero);
#undef CHECK_SPLIT
}
diff --git a/unittests/IR/DebugTypeODRUniquingTest.cpp b/unittests/IR/DebugTypeODRUniquingTest.cpp
index 2c899d85d1f3..7cf1cd22a2fb 100644
--- a/unittests/IR/DebugTypeODRUniquingTest.cpp
+++ b/unittests/IR/DebugTypeODRUniquingTest.cpp
@@ -30,7 +30,7 @@ TEST(DebugTypeODRUniquingTest, getODRType) {
// Without a type map, this should return null.
EXPECT_FALSE(DICompositeType::getODRType(
Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 0, nullptr,
- nullptr, 0, 0, 0, 0, nullptr, 0, nullptr, nullptr));
+ nullptr, 0, 0, 0, DINode::FlagZero, nullptr, 0, nullptr, nullptr));
// Enable the mapping. There still shouldn't be a type.
Context.enableDebugTypeODRUniquing();
@@ -39,19 +39,20 @@ TEST(DebugTypeODRUniquingTest, getODRType) {
// Create some ODR-uniqued type.
auto &CT = *DICompositeType::getODRType(
Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 0, nullptr,
- nullptr, 0, 0, 0, 0, nullptr, 0, nullptr, nullptr);
+ nullptr, 0, 0, 0, DINode::FlagZero, nullptr, 0, nullptr, nullptr);
EXPECT_EQ(UUID.getString(), CT.getIdentifier());
// Check that we get it back, even if we change a field.
EXPECT_EQ(&CT, DICompositeType::getODRTypeIfExists(Context, UUID));
- EXPECT_EQ(
- &CT, DICompositeType::getODRType(Context, UUID, dwarf::DW_TAG_class_type,
- nullptr, nullptr, 0, nullptr, nullptr, 0,
- 0, 0, 0, nullptr, 0, nullptr, nullptr));
EXPECT_EQ(&CT, DICompositeType::getODRType(
- Context, UUID, dwarf::DW_TAG_class_type,
- MDString::get(Context, "name"), nullptr, 0, nullptr,
- nullptr, 0, 0, 0, 0, nullptr, 0, nullptr, nullptr));
+ Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr,
+ 0, nullptr, nullptr, 0, 0, 0, DINode::FlagZero, nullptr, 0,
+ nullptr, nullptr));
+ EXPECT_EQ(&CT,
+ DICompositeType::getODRType(
+ Context, UUID, dwarf::DW_TAG_class_type,
+ MDString::get(Context, "name"), nullptr, 0, nullptr, nullptr, 0,
+ 0, 0, DINode::FlagZero, nullptr, 0, nullptr, nullptr));
// Check that it's discarded with the type map.
Context.disableDebugTypeODRUniquing();
@@ -82,8 +83,9 @@ TEST(DebugTypeODRUniquingTest, buildODRType) {
// Update with a definition. This time we should see a change.
EXPECT_EQ(&CT, DICompositeType::buildODRType(
- Context, UUID, dwarf::DW_TAG_structure_type, nullptr, nullptr, 0, nullptr,
- nullptr, 0, 0, 0, 0, nullptr, 0, nullptr, nullptr));
+ Context, UUID, dwarf::DW_TAG_structure_type, nullptr,
+ nullptr, 0, nullptr, nullptr, 0, 0, 0, DINode::FlagZero,
+ nullptr, 0, nullptr, nullptr));
EXPECT_EQ(dwarf::DW_TAG_structure_type, CT.getTag());
// Further updates should be ignored.
@@ -92,8 +94,9 @@ TEST(DebugTypeODRUniquingTest, buildODRType) {
nullptr, 0, 0, 0, DINode::FlagFwdDecl, nullptr, 0, nullptr, nullptr));
EXPECT_EQ(dwarf::DW_TAG_structure_type, CT.getTag());
EXPECT_EQ(&CT, DICompositeType::buildODRType(
- Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 0, nullptr,
- nullptr, 0, 0, 0, 0, nullptr, 0, nullptr, nullptr));
+ Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr,
+ 0, nullptr, nullptr, 0, 0, 0, DINode::FlagZero, nullptr, 0,
+ nullptr, nullptr));
EXPECT_EQ(dwarf::DW_TAG_structure_type, CT.getTag());
}
diff --git a/unittests/IR/IRBuilderTest.cpp b/unittests/IR/IRBuilderTest.cpp
index 58fd71b8a357..579384c5a5f4 100644
--- a/unittests/IR/IRBuilderTest.cpp
+++ b/unittests/IR/IRBuilderTest.cpp
@@ -340,15 +340,16 @@ TEST_F(IRBuilderTest, DIBuilder) {
IRBuilder<> Builder(BB);
DIBuilder DIB(*M);
auto File = DIB.createFile("F.CBL", "/");
- auto CU = DIB.createCompileUnit(dwarf::DW_LANG_Cobol74, "F.CBL", "/",
- "llvm-cobol74", true, "", 0);
+ auto CU = DIB.createCompileUnit(dwarf::DW_LANG_Cobol74,
+ DIB.createFile("F.CBL", "/"), "llvm-cobol74",
+ true, "", 0);
auto Type = DIB.createSubroutineType(DIB.getOrCreateTypeArray(None));
- auto SP =
- DIB.createFunction(CU, "foo", "", File, 1, Type, false, true, 1, 0, true);
+ auto SP = DIB.createFunction(CU, "foo", "", File, 1, Type, false, true, 1,
+ DINode::FlagZero, true);
F->setSubprogram(SP);
AllocaInst *I = Builder.CreateAlloca(Builder.getInt8Ty());
- auto BarSP =
- DIB.createFunction(CU, "bar", "", File, 1, Type, false, true, 1, 0, true);
+ auto BarSP = DIB.createFunction(CU, "bar", "", File, 1, Type, false, true, 1,
+ DINode::FlagZero, true);
auto BadScope = DIB.createLexicalBlockFile(BarSP, File, 0);
I->setDebugLoc(DebugLoc::get(2, 0, BadScope));
DIB.finalize();
@@ -392,8 +393,9 @@ TEST_F(IRBuilderTest, DebugLoc) {
DIBuilder DIB(*M);
auto File = DIB.createFile("tmp.cpp", "/");
- auto CU = DIB.createCompileUnit(dwarf::DW_LANG_C_plus_plus_11, "tmp.cpp", "/",
- "", true, "", 0);
+ auto CU = DIB.createCompileUnit(dwarf::DW_LANG_C_plus_plus_11,
+ DIB.createFile("tmp.cpp", "/"), "", true, "",
+ 0);
auto SPType = DIB.createSubroutineType(DIB.getOrCreateTypeArray(None));
auto SP =
DIB.createFunction(CU, "foo", "foo", File, 1, SPType, false, true, 1);
@@ -422,8 +424,9 @@ TEST_F(IRBuilderTest, DebugLoc) {
TEST_F(IRBuilderTest, DIImportedEntity) {
IRBuilder<> Builder(BB);
DIBuilder DIB(*M);
- auto CU = DIB.createCompileUnit(dwarf::DW_LANG_Cobol74, "F.CBL", "/",
- "llvm-cobol74", true, "", 0);
+ auto CU = DIB.createCompileUnit(dwarf::DW_LANG_Cobol74,
+ DIB.createFile("F.CBL", "/"), "llvm-cobol74",
+ true, "", 0);
DIB.createImportedDeclaration(CU, nullptr, 1);
DIB.createImportedDeclaration(CU, nullptr, 1);
DIB.createImportedModule(CU, (DIImportedEntity *)nullptr, 2);
diff --git a/unittests/IR/MetadataTest.cpp b/unittests/IR/MetadataTest.cpp
index 15b03b3d5720..7bb8d4010d38 100644
--- a/unittests/IR/MetadataTest.cpp
+++ b/unittests/IR/MetadataTest.cpp
@@ -80,12 +80,13 @@ protected:
MDTuple *getTuple() { return MDTuple::getDistinct(Context, None); }
DISubroutineType *getSubroutineType() {
- return DISubroutineType::getDistinct(Context, 0, 0, getNode(nullptr));
+ return DISubroutineType::getDistinct(Context, DINode::FlagZero, 0,
+ getNode(nullptr));
}
DISubprogram *getSubprogram() {
return DISubprogram::getDistinct(Context, nullptr, "", "", nullptr, 0,
- nullptr, false, false, 0, nullptr,
- 0, 0, 0, 0, false, nullptr);
+ nullptr, false, false, 0, nullptr, 0, 0, 0,
+ DINode::FlagZero, false, nullptr);
}
DIFile *getFile() {
return DIFile::getDistinct(Context, "file.c", "/path/to/dir");
@@ -94,15 +95,15 @@ protected:
return DICompileUnit::getDistinct(Context, 1, getFile(), "clang", false,
"-g", 2, "", DICompileUnit::FullDebug,
getTuple(), getTuple(), getTuple(),
- getTuple(), getTuple(), 0);
+ getTuple(), getTuple(), 0, true);
}
DIType *getBasicType(StringRef Name) {
return DIBasicType::get(Context, dwarf::DW_TAG_unspecified_type, Name);
}
DIType *getDerivedType() {
- return DIDerivedType::getDistinct(Context, dwarf::DW_TAG_pointer_type, "",
- nullptr, 0, nullptr,
- getBasicType("basictype"), 1, 2, 0, 0);
+ return DIDerivedType::getDistinct(
+ Context, dwarf::DW_TAG_pointer_type, "", nullptr, 0, nullptr,
+ getBasicType("basictype"), 1, 2, 0, DINode::FlagZero);
}
Constant *getConstant() {
return ConstantInt::get(Type::getInt32Ty(Context), Counter++);
@@ -113,7 +114,7 @@ protected:
DIType *getCompositeType() {
return DICompositeType::getDistinct(
Context, dwarf::DW_TAG_structure_type, "", nullptr, 0, nullptr, nullptr,
- 32, 32, 0, 0, nullptr, 0, nullptr, nullptr, "");
+ 32, 32, 0, DINode::FlagZero, nullptr, 0, nullptr, nullptr, "");
}
Function *getFunction(StringRef Name) {
return cast<Function>(M.getOrInsertFunction(
@@ -996,9 +997,9 @@ TEST_F(DIBasicTypeTest, get) {
TEST_F(DIBasicTypeTest, getWithLargeValues) {
auto *N = DIBasicType::get(Context, dwarf::DW_TAG_base_type, "special",
- UINT64_MAX, UINT64_MAX - 1, 7);
+ UINT64_MAX, UINT32_MAX - 1, 7);
EXPECT_EQ(UINT64_MAX, N->getSizeInBits());
- EXPECT_EQ(UINT64_MAX - 1, N->getAlignInBits());
+ EXPECT_EQ(UINT32_MAX - 1, N->getAlignInBits());
}
TEST_F(DIBasicTypeTest, getUnspecified) {
@@ -1028,19 +1029,21 @@ TEST_F(DITypeTest, setFlags) {
Metadata *TypesOps[] = {nullptr};
Metadata *Types = MDTuple::get(Context, TypesOps);
- DIType *D = DISubroutineType::getDistinct(Context, 0u, 0, Types);
- EXPECT_EQ(0u, D->getFlags());
+ DIType *D =
+ DISubroutineType::getDistinct(Context, DINode::FlagZero, 0, Types);
+ EXPECT_EQ(DINode::FlagZero, D->getFlags());
D->setFlags(DINode::FlagRValueReference);
EXPECT_EQ(DINode::FlagRValueReference, D->getFlags());
- D->setFlags(0u);
- EXPECT_EQ(0u, D->getFlags());
+ D->setFlags(DINode::FlagZero);
+ EXPECT_EQ(DINode::FlagZero, D->getFlags());
- TempDIType T = DISubroutineType::getTemporary(Context, 0u, 0, Types);
- EXPECT_EQ(0u, T->getFlags());
+ TempDIType T =
+ DISubroutineType::getTemporary(Context, DINode::FlagZero, 0, Types);
+ EXPECT_EQ(DINode::FlagZero, T->getFlags());
T->setFlags(DINode::FlagRValueReference);
EXPECT_EQ(DINode::FlagRValueReference, T->getFlags());
- T->setFlags(0u);
- EXPECT_EQ(0u, T->getFlags());
+ T->setFlags(DINode::FlagZero);
+ EXPECT_EQ(DINode::FlagZero, T->getFlags());
}
typedef MetadataTest DIDerivedTypeTest;
@@ -1050,9 +1053,12 @@ TEST_F(DIDerivedTypeTest, get) {
DIScope *Scope = getSubprogram();
DIType *BaseType = getBasicType("basic");
MDTuple *ExtraData = getTuple();
+ 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, 5, ExtraData);
+ auto *N =
+ DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type, "something", File,
+ 1, Scope, BaseType, 2, 3, 4, Flags5, ExtraData);
EXPECT_EQ(dwarf::DW_TAG_pointer_type, N->getTag());
EXPECT_EQ("something", N->getName());
EXPECT_EQ(File, N->getFile());
@@ -1066,41 +1072,41 @@ TEST_F(DIDerivedTypeTest, get) {
EXPECT_EQ(ExtraData, N->getExtraData());
EXPECT_EQ(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type,
"something", File, 1, Scope, BaseType, 2, 3,
- 4, 5, ExtraData));
+ 4, Flags5, ExtraData));
EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_reference_type,
"something", File, 1, Scope, BaseType, 2, 3,
- 4, 5, ExtraData));
+ 4, Flags5, ExtraData));
EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type, "else",
- File, 1, Scope, BaseType, 2, 3, 4, 5,
+ File, 1, Scope, BaseType, 2, 3, 4, Flags5,
ExtraData));
EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type,
"something", getFile(), 1, Scope, BaseType, 2,
- 3, 4, 5, ExtraData));
+ 3, 4, Flags5, ExtraData));
EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type,
"something", File, 2, Scope, BaseType, 2, 3,
- 4, 5, ExtraData));
+ 4, Flags5, ExtraData));
EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type,
"something", File, 1, getSubprogram(),
- BaseType, 2, 3, 4, 5, ExtraData));
+ BaseType, 2, 3, 4, Flags5, ExtraData));
EXPECT_NE(N, DIDerivedType::get(
Context, dwarf::DW_TAG_pointer_type, "something", File, 1,
- Scope, getBasicType("basic2"), 2, 3, 4, 5, ExtraData));
+ Scope, getBasicType("basic2"), 2, 3, 4, Flags5, ExtraData));
EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type,
"something", File, 1, Scope, BaseType, 3, 3,
- 4, 5, ExtraData));
+ 4, Flags5, ExtraData));
EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type,
"something", File, 1, Scope, BaseType, 2, 2,
- 4, 5, ExtraData));
+ 4, Flags5, ExtraData));
EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type,
"something", File, 1, Scope, BaseType, 2, 3,
- 5, 5, ExtraData));
+ 5, Flags5, ExtraData));
EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type,
"something", File, 1, Scope, BaseType, 2, 3,
- 4, 4, ExtraData));
+ 4, Flags4, ExtraData));
EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type,
"something", File, 1, Scope, BaseType, 2, 3,
- 4, 5, getTuple()));
+ 4, Flags5, getTuple()));
TempDIDerivedType Temp = N->clone();
EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp)));
@@ -1111,12 +1117,13 @@ TEST_F(DIDerivedTypeTest, getWithLargeValues) {
DIScope *Scope = getSubprogram();
DIType *BaseType = getBasicType("basic");
MDTuple *ExtraData = getTuple();
+ DINode::DIFlags Flags = static_cast<DINode::DIFlags>(5);
- auto *N = DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type, "something",
- File, 1, Scope, BaseType, UINT64_MAX,
- UINT64_MAX - 1, UINT64_MAX - 2, 5, ExtraData);
+ 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);
EXPECT_EQ(UINT64_MAX, N->getSizeInBits());
- EXPECT_EQ(UINT64_MAX - 1, N->getAlignInBits());
+ EXPECT_EQ(UINT32_MAX - 1, N->getAlignInBits());
EXPECT_EQ(UINT64_MAX - 2, N->getOffsetInBits());
}
@@ -1130,9 +1137,9 @@ TEST_F(DICompositeTypeTest, get) {
DIScope *Scope = getSubprogram();
DIType *BaseType = getCompositeType();
uint64_t SizeInBits = 2;
- uint64_t AlignInBits = 3;
+ uint32_t AlignInBits = 3;
uint64_t OffsetInBits = 4;
- unsigned Flags = 5;
+ DINode::DIFlags Flags = static_cast<DINode::DIFlags>(5);
MDTuple *Elements = getTuple();
unsigned RuntimeLang = 6;
DIType *VTableHolder = getCompositeType();
@@ -1200,9 +1207,10 @@ TEST_F(DICompositeTypeTest, get) {
Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits,
AlignInBits, OffsetInBits + 1, Flags, Elements, RuntimeLang,
VTableHolder, TemplateParams, Identifier));
+ DINode::DIFlags FlagsPOne = static_cast<DINode::DIFlags>(Flags + 1);
EXPECT_NE(N, DICompositeType::get(
Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits,
- AlignInBits, OffsetInBits, Flags + 1, Elements, RuntimeLang,
+ AlignInBits, OffsetInBits, FlagsPOne, Elements, RuntimeLang,
VTableHolder, TemplateParams, Identifier));
EXPECT_NE(N, DICompositeType::get(
Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits,
@@ -1249,9 +1257,9 @@ TEST_F(DICompositeTypeTest, getWithLargeValues) {
DIScope *Scope = getSubprogram();
DIType *BaseType = getCompositeType();
uint64_t SizeInBits = UINT64_MAX;
- uint64_t AlignInBits = UINT64_MAX - 1;
+ uint32_t AlignInBits = UINT32_MAX - 1;
uint64_t OffsetInBits = UINT64_MAX - 2;
- unsigned Flags = 5;
+ DINode::DIFlags Flags = static_cast<DINode::DIFlags>(5);
MDTuple *Elements = getTuple();
unsigned RuntimeLang = 6;
DIType *VTableHolder = getCompositeType();
@@ -1275,9 +1283,9 @@ TEST_F(DICompositeTypeTest, replaceOperands) {
DIScope *Scope = getSubprogram();
DIType *BaseType = getCompositeType();
uint64_t SizeInBits = 2;
- uint64_t AlignInBits = 3;
+ uint32_t AlignInBits = 3;
uint64_t OffsetInBits = 4;
- unsigned Flags = 5;
+ DINode::DIFlags Flags = static_cast<DINode::DIFlags>(5);
unsigned RuntimeLang = 6;
StringRef Identifier = "some id";
@@ -1310,7 +1318,8 @@ TEST_F(DICompositeTypeTest, replaceOperands) {
typedef MetadataTest DISubroutineTypeTest;
TEST_F(DISubroutineTypeTest, get) {
- unsigned Flags = 1;
+ DINode::DIFlags Flags = static_cast<DINode::DIFlags>(1);
+ DINode::DIFlags FlagsPOne = static_cast<DINode::DIFlags>(Flags + 1);
MDTuple *TypeArray = getTuple();
auto *N = DISubroutineType::get(Context, Flags, 0, TypeArray);
@@ -1319,7 +1328,7 @@ TEST_F(DISubroutineTypeTest, get) {
EXPECT_EQ(TypeArray, N->getTypeArray().get());
EXPECT_EQ(N, DISubroutineType::get(Context, Flags, 0, TypeArray));
- EXPECT_NE(N, DISubroutineType::get(Context, Flags + 1, 0, TypeArray));
+ EXPECT_NE(N, DISubroutineType::get(Context, FlagsPOne, 0, TypeArray));
EXPECT_NE(N, DISubroutineType::get(Context, Flags, 0, getTuple()));
// Test the hashing of calling conventions.
@@ -1351,15 +1360,21 @@ typedef MetadataTest DIFileTest;
TEST_F(DIFileTest, get) {
StringRef Filename = "file";
StringRef Directory = "dir";
- auto *N = DIFile::get(Context, Filename, Directory);
+ DIFile::ChecksumKind CSKind = DIFile::CSK_MD5;
+ StringRef Checksum = "000102030405060708090a0b0c0d0e0f";
+ auto *N = DIFile::get(Context, Filename, Directory, CSKind, Checksum);
EXPECT_EQ(dwarf::DW_TAG_file_type, N->getTag());
EXPECT_EQ(Filename, N->getFilename());
EXPECT_EQ(Directory, N->getDirectory());
- EXPECT_EQ(N, DIFile::get(Context, Filename, Directory));
+ EXPECT_EQ(CSKind, N->getChecksumKind());
+ EXPECT_EQ(Checksum, N->getChecksum());
+ EXPECT_EQ(N, DIFile::get(Context, Filename, Directory, CSKind, Checksum));
- EXPECT_NE(N, DIFile::get(Context, "other", Directory));
- EXPECT_NE(N, DIFile::get(Context, Filename, "other"));
+ EXPECT_NE(N, DIFile::get(Context, "other", Directory, CSKind, Checksum));
+ EXPECT_NE(N, DIFile::get(Context, Filename, "other", CSKind, Checksum));
+ EXPECT_NE(N, DIFile::get(Context, Filename, Directory, DIFile::CSK_SHA1, Checksum));
+ EXPECT_NE(N, DIFile::get(Context, Filename, Directory));
TempDIFile Temp = N->clone();
EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp)));
@@ -1391,8 +1406,7 @@ TEST_F(DICompileUnitTest, get) {
auto *N = DICompileUnit::getDistinct(
Context, SourceLanguage, File, Producer, IsOptimized, Flags,
RuntimeVersion, SplitDebugFilename, EmissionKind, EnumTypes,
- RetainedTypes, GlobalVariables, ImportedEntities, Macros,
- DWOId);
+ RetainedTypes, GlobalVariables, ImportedEntities, Macros, DWOId, true);
EXPECT_EQ(dwarf::DW_TAG_compile_unit, N->getTag());
EXPECT_EQ(SourceLanguage, N->getSourceLanguage());
@@ -1449,7 +1463,7 @@ TEST_F(DICompileUnitTest, replaceArrays) {
auto *N = DICompileUnit::getDistinct(
Context, SourceLanguage, File, Producer, IsOptimized, Flags,
RuntimeVersion, SplitDebugFilename, EmissionKind, EnumTypes,
- RetainedTypes, nullptr, ImportedEntities, nullptr, DWOId);
+ RetainedTypes, nullptr, ImportedEntities, nullptr, DWOId, true);
auto *GlobalVariables = MDTuple::getDistinct(Context, None);
EXPECT_EQ(nullptr, N->getGlobalVariables().get());
@@ -1482,8 +1496,7 @@ TEST_F(DISubprogramTest, get) {
unsigned Virtuality = 2;
unsigned VirtualIndex = 5;
int ThisAdjustment = -3;
- unsigned Flags = 6;
- unsigned NotFlags = (~Flags) & ((1 << 27) - 1);
+ DINode::DIFlags Flags = static_cast<DINode::DIFlags>(6);
bool IsOptimized = false;
MDTuple *TemplateParams = getTuple();
DISubprogram *Declaration = getSubprogram();
@@ -1586,11 +1599,6 @@ TEST_F(DISubprogramTest, get) {
EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line,
Type, IsLocalToUnit, IsDefinition, ScopeLine,
ContainingType, Virtuality, VirtualIndex,
- ThisAdjustment, NotFlags, IsOptimized, Unit,
- TemplateParams, Declaration, Variables));
- EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line,
- Type, IsLocalToUnit, IsDefinition, ScopeLine,
- ContainingType, Virtuality, VirtualIndex,
ThisAdjustment, Flags, !IsOptimized, Unit,
TemplateParams, Declaration, Variables));
EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line,
@@ -1704,20 +1712,28 @@ TEST_F(DINamespaceTest, get) {
DIFile *File = getFile();
StringRef Name = "namespace";
unsigned Line = 5;
+ bool ExportSymbols = true;
- auto *N = DINamespace::get(Context, Scope, File, Name, Line);
+ auto *N = DINamespace::get(Context, Scope, File, Name, Line, ExportSymbols);
EXPECT_EQ(dwarf::DW_TAG_namespace, N->getTag());
EXPECT_EQ(Scope, N->getScope());
EXPECT_EQ(File, N->getFile());
EXPECT_EQ(Name, N->getName());
EXPECT_EQ(Line, N->getLine());
- EXPECT_EQ(N, DINamespace::get(Context, Scope, File, Name, Line));
+ EXPECT_EQ(N,
+ DINamespace::get(Context, Scope, File, Name, Line, ExportSymbols));
- EXPECT_NE(N, DINamespace::get(Context, getFile(), File, Name, Line));
- EXPECT_NE(N, DINamespace::get(Context, Scope, getFile(), Name, Line));
- EXPECT_NE(N, DINamespace::get(Context, Scope, File, "other", Line));
- EXPECT_NE(N, DINamespace::get(Context, Scope, File, Name, Line + 1));
+ EXPECT_NE(N,
+ DINamespace::get(Context, getFile(), File, Name, Line, ExportSymbols));
+ EXPECT_NE(N,
+ DINamespace::get(Context, Scope, getFile(), Name, Line, ExportSymbols));
+ EXPECT_NE(N,
+ DINamespace::get(Context, Scope, File, "other", Line, ExportSymbols));
+ EXPECT_NE(N,
+ DINamespace::get(Context, Scope, File, Name, Line + 1, ExportSymbols));
+ EXPECT_NE(N,
+ DINamespace::get(Context, Scope, File, Name, Line, !ExportSymbols));
TempDINamespace Temp = N->clone();
EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp)));
@@ -1818,13 +1834,13 @@ TEST_F(DIGlobalVariableTest, get) {
DIType *Type = getDerivedType();
bool IsLocalToUnit = false;
bool IsDefinition = true;
- Constant *Variable = getConstant();
DIDerivedType *StaticDataMemberDeclaration =
cast<DIDerivedType>(getDerivedType());
+ uint32_t AlignInBits = 8;
auto *N = DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, Line,
- Type, IsLocalToUnit, IsDefinition, Variable,
- StaticDataMemberDeclaration);
+ Type, IsLocalToUnit, IsDefinition,
+ StaticDataMemberDeclaration, AlignInBits);
EXPECT_EQ(dwarf::DW_TAG_variable, N->getTag());
EXPECT_EQ(Scope, N->getScope());
EXPECT_EQ(Name, N->getName());
@@ -1834,53 +1850,88 @@ TEST_F(DIGlobalVariableTest, get) {
EXPECT_EQ(Type, N->getType());
EXPECT_EQ(IsLocalToUnit, N->isLocalToUnit());
EXPECT_EQ(IsDefinition, N->isDefinition());
- EXPECT_EQ(Variable, N->getVariable());
EXPECT_EQ(StaticDataMemberDeclaration, N->getStaticDataMemberDeclaration());
+ EXPECT_EQ(AlignInBits, N->getAlignInBits());
EXPECT_EQ(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File,
Line, Type, IsLocalToUnit, IsDefinition,
- Variable, StaticDataMemberDeclaration));
+ StaticDataMemberDeclaration, AlignInBits));
EXPECT_NE(N,
DIGlobalVariable::get(Context, getSubprogram(), Name, LinkageName,
File, Line, Type, IsLocalToUnit, IsDefinition,
- Variable, StaticDataMemberDeclaration));
+ StaticDataMemberDeclaration, AlignInBits));
EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, "other", LinkageName, File,
Line, Type, IsLocalToUnit, IsDefinition,
- Variable, StaticDataMemberDeclaration));
+ StaticDataMemberDeclaration, AlignInBits));
EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, "other", File, Line,
Type, IsLocalToUnit, IsDefinition,
- Variable, StaticDataMemberDeclaration));
+ StaticDataMemberDeclaration, AlignInBits));
EXPECT_NE(N,
DIGlobalVariable::get(Context, Scope, Name, LinkageName, getFile(),
Line, Type, IsLocalToUnit, IsDefinition,
- Variable, StaticDataMemberDeclaration));
+ StaticDataMemberDeclaration, AlignInBits));
EXPECT_NE(N,
DIGlobalVariable::get(Context, Scope, Name, LinkageName, File,
Line + 1, Type, IsLocalToUnit, IsDefinition,
- Variable, StaticDataMemberDeclaration));
+ StaticDataMemberDeclaration, AlignInBits));
EXPECT_NE(N,
DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, Line,
getDerivedType(), IsLocalToUnit, IsDefinition,
- Variable, StaticDataMemberDeclaration));
+ StaticDataMemberDeclaration, AlignInBits));
EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File,
Line, Type, !IsLocalToUnit, IsDefinition,
- Variable, StaticDataMemberDeclaration));
+ StaticDataMemberDeclaration, AlignInBits));
EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File,
Line, Type, IsLocalToUnit, !IsDefinition,
- Variable, StaticDataMemberDeclaration));
- EXPECT_NE(N,
- DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, Line,
- Type, IsLocalToUnit, IsDefinition,
- getConstant(), StaticDataMemberDeclaration));
- EXPECT_NE(N,
- DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, Line,
- Type, IsLocalToUnit, IsDefinition, Variable,
- cast<DIDerivedType>(getDerivedType())));
+ StaticDataMemberDeclaration, AlignInBits));
+ EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File,
+ Line, Type, IsLocalToUnit, IsDefinition,
+ cast<DIDerivedType>(getDerivedType()),
+ AlignInBits));
+ EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File,
+ Line, Type, IsLocalToUnit, IsDefinition,
+ StaticDataMemberDeclaration,
+ (AlignInBits << 1)));
TempDIGlobalVariable Temp = N->clone();
EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp)));
}
+typedef MetadataTest DIGlobalVariableExpressionTest;
+
+TEST_F(DIGlobalVariableExpressionTest, get) {
+ DIScope *Scope = getSubprogram();
+ StringRef Name = "name";
+ StringRef LinkageName = "linkage";
+ DIFile *File = getFile();
+ unsigned Line = 5;
+ DIType *Type = getDerivedType();
+ bool IsLocalToUnit = false;
+ bool IsDefinition = true;
+ auto *Expr = DIExpression::get(Context, {1, 2});
+ auto *Expr2 = DIExpression::get(Context, {1, 2, 3});
+ DIDerivedType *StaticDataMemberDeclaration =
+ cast<DIDerivedType>(getDerivedType());
+ uint32_t AlignInBits = 8;
+
+ auto *Var = DIGlobalVariable::get(Context, Scope, Name, LinkageName, File,
+ Line, Type, IsLocalToUnit, IsDefinition,
+ StaticDataMemberDeclaration, AlignInBits);
+ auto *Var2 = DIGlobalVariable::get(Context, Scope, "other", LinkageName, File,
+ Line, Type, IsLocalToUnit, IsDefinition,
+ StaticDataMemberDeclaration, AlignInBits);
+ auto *N = DIGlobalVariableExpression::get(Context, Var, Expr);
+
+ EXPECT_EQ(Var, N->getVariable());
+ EXPECT_EQ(Expr, N->getExpression());
+ EXPECT_EQ(N, DIGlobalVariableExpression::get(Context, Var, Expr));
+ EXPECT_NE(N, DIGlobalVariableExpression::get(Context, Var2, Expr));
+ EXPECT_NE(N, DIGlobalVariableExpression::get(Context, Var, Expr2));
+
+ TempDIGlobalVariableExpression Temp = N->clone();
+ EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp)));
+}
+
typedef MetadataTest DILocalVariableTest;
TEST_F(DILocalVariableTest, get) {
@@ -1890,11 +1941,12 @@ TEST_F(DILocalVariableTest, get) {
unsigned Line = 5;
DIType *Type = getDerivedType();
unsigned Arg = 6;
- unsigned Flags = 7;
- unsigned NotFlags = (~Flags) & ((1 << 16) - 1);
+ DINode::DIFlags Flags = static_cast<DINode::DIFlags>(7);
+ uint32_t AlignInBits = 8;
auto *N =
- DILocalVariable::get(Context, Scope, Name, File, Line, Type, Arg, Flags);
+ DILocalVariable::get(Context, Scope, Name, File, Line, Type, Arg, Flags,
+ AlignInBits);
EXPECT_TRUE(N->isParameter());
EXPECT_EQ(Scope, N->getScope());
EXPECT_EQ(Name, N->getName());
@@ -1903,26 +1955,27 @@ TEST_F(DILocalVariableTest, get) {
EXPECT_EQ(Type, N->getType());
EXPECT_EQ(Arg, N->getArg());
EXPECT_EQ(Flags, N->getFlags());
+ EXPECT_EQ(AlignInBits, N->getAlignInBits());
EXPECT_EQ(N, DILocalVariable::get(Context, Scope, Name, File, Line, Type, Arg,
- Flags));
+ Flags, AlignInBits));
EXPECT_FALSE(
- DILocalVariable::get(Context, Scope, Name, File, Line, Type, 0, Flags)
- ->isParameter());
+ DILocalVariable::get(Context, Scope, Name, File, Line, Type, 0, Flags,
+ AlignInBits)->isParameter());
EXPECT_NE(N, DILocalVariable::get(Context, getSubprogram(), Name, File, Line,
- Type, Arg, Flags));
+ Type, Arg, Flags, AlignInBits));
EXPECT_NE(N, DILocalVariable::get(Context, Scope, "other", File, Line, Type,
- Arg, Flags));
+ Arg, Flags, AlignInBits));
EXPECT_NE(N, DILocalVariable::get(Context, Scope, Name, getFile(), Line, Type,
- Arg, Flags));
+ Arg, Flags, AlignInBits));
EXPECT_NE(N, DILocalVariable::get(Context, Scope, Name, File, Line + 1, Type,
- Arg, Flags));
+ Arg, Flags, AlignInBits));
EXPECT_NE(N, DILocalVariable::get(Context, Scope, Name, File, Line,
- getDerivedType(), Arg, Flags));
+ getDerivedType(), Arg, Flags, AlignInBits));
+ EXPECT_NE(N, DILocalVariable::get(Context, Scope, Name, File, Line, Type,
+ Arg + 1, Flags, AlignInBits));
EXPECT_NE(N, DILocalVariable::get(Context, Scope, Name, File, Line, Type,
- Arg + 1, Flags));
- EXPECT_NE(N, DILocalVariable::get(Context, Scope, Name, File, Line, Type, Arg,
- NotFlags));
+ Arg, Flags, (AlignInBits << 1)));
TempDILocalVariable Temp = N->clone();
EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp)));
@@ -1930,17 +1983,17 @@ TEST_F(DILocalVariableTest, get) {
TEST_F(DILocalVariableTest, getArg256) {
EXPECT_EQ(255u, DILocalVariable::get(Context, getSubprogram(), "", getFile(),
- 0, nullptr, 255, 0)
+ 0, nullptr, 255, DINode::FlagZero, 0)
->getArg());
EXPECT_EQ(256u, DILocalVariable::get(Context, getSubprogram(), "", getFile(),
- 0, nullptr, 256, 0)
+ 0, nullptr, 256, DINode::FlagZero, 0)
->getArg());
EXPECT_EQ(257u, DILocalVariable::get(Context, getSubprogram(), "", getFile(),
- 0, nullptr, 257, 0)
+ 0, nullptr, 257, DINode::FlagZero, 0)
->getArg());
unsigned Max = UINT16_MAX;
EXPECT_EQ(Max, DILocalVariable::get(Context, getSubprogram(), "", getFile(),
- 0, nullptr, Max, 0)
+ 0, nullptr, Max, DINode::FlagZero, 0)
->getArg());
}
@@ -1981,19 +2034,20 @@ TEST_F(DIExpressionTest, isValid) {
// Valid constructions.
EXPECT_VALID(dwarf::DW_OP_plus, 6);
EXPECT_VALID(dwarf::DW_OP_deref);
- EXPECT_VALID(dwarf::DW_OP_bit_piece, 3, 7);
+ EXPECT_VALID(dwarf::DW_OP_LLVM_fragment, 3, 7);
EXPECT_VALID(dwarf::DW_OP_plus, 6, dwarf::DW_OP_deref);
EXPECT_VALID(dwarf::DW_OP_deref, dwarf::DW_OP_plus, 6);
- EXPECT_VALID(dwarf::DW_OP_deref, dwarf::DW_OP_bit_piece, 3, 7);
- EXPECT_VALID(dwarf::DW_OP_deref, dwarf::DW_OP_plus, 6, dwarf::DW_OP_bit_piece, 3, 7);
+ EXPECT_VALID(dwarf::DW_OP_deref, dwarf::DW_OP_LLVM_fragment, 3, 7);
+ EXPECT_VALID(dwarf::DW_OP_deref, dwarf::DW_OP_plus, 6,
+ dwarf::DW_OP_LLVM_fragment, 3, 7);
// Invalid constructions.
EXPECT_INVALID(~0u);
EXPECT_INVALID(dwarf::DW_OP_plus);
- EXPECT_INVALID(dwarf::DW_OP_bit_piece);
- EXPECT_INVALID(dwarf::DW_OP_bit_piece, 3);
- EXPECT_INVALID(dwarf::DW_OP_bit_piece, 3, 7, dwarf::DW_OP_plus, 3);
- EXPECT_INVALID(dwarf::DW_OP_bit_piece, 3, 7, dwarf::DW_OP_deref);
+ EXPECT_INVALID(dwarf::DW_OP_LLVM_fragment);
+ EXPECT_INVALID(dwarf::DW_OP_LLVM_fragment, 3);
+ EXPECT_INVALID(dwarf::DW_OP_LLVM_fragment, 3, 7, dwarf::DW_OP_plus, 3);
+ EXPECT_INVALID(dwarf::DW_OP_LLVM_fragment, 3, 7, dwarf::DW_OP_deref);
#undef EXPECT_VALID
#undef EXPECT_INVALID
diff --git a/unittests/IR/ModuleTest.cpp b/unittests/IR/ModuleTest.cpp
new file mode 100644
index 000000000000..9f52fedc4559
--- /dev/null
+++ b/unittests/IR/ModuleTest.cpp
@@ -0,0 +1,75 @@
+//===- unittests/IR/ModuleTest.cpp - Module 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/IR/GlobalVariable.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/RandomNumberGenerator.h"
+#include "gtest/gtest.h"
+
+#include <random>
+
+using namespace llvm;
+
+namespace {
+
+bool sortByName(const GlobalVariable &L, const GlobalVariable &R) {
+ return L.getName() < R.getName();
+}
+
+bool sortByNameReverse(const GlobalVariable &L, const GlobalVariable &R) {
+ return sortByName(R, L);
+}
+
+TEST(ModuleTest, sortGlobalsByName) {
+ LLVMContext Context;
+ for (auto compare : {&sortByName, &sortByNameReverse}) {
+ Module M("M", Context);
+ Type *T = Type::getInt8Ty(Context);
+ GlobalValue::LinkageTypes L = GlobalValue::ExternalLinkage;
+ (void)new GlobalVariable(M, T, false, L, nullptr, "A");
+ (void)new GlobalVariable(M, T, false, L, nullptr, "F");
+ (void)new GlobalVariable(M, T, false, L, nullptr, "G");
+ (void)new GlobalVariable(M, T, false, L, nullptr, "E");
+ (void)new GlobalVariable(M, T, false, L, nullptr, "B");
+ (void)new GlobalVariable(M, T, false, L, nullptr, "H");
+ (void)new GlobalVariable(M, T, false, L, nullptr, "C");
+ (void)new GlobalVariable(M, T, false, L, nullptr, "D");
+
+ // Sort the globals by name.
+ EXPECT_FALSE(std::is_sorted(M.global_begin(), M.global_end(), compare));
+ M.getGlobalList().sort(compare);
+ EXPECT_TRUE(std::is_sorted(M.global_begin(), M.global_end(), compare));
+ }
+}
+
+TEST(ModuleTest, randomNumberGenerator) {
+ LLVMContext Context;
+ static char ID;
+ struct DummyPass : ModulePass {
+ DummyPass() : ModulePass(ID) {}
+ bool runOnModule(Module &) { return true; }
+ } DP;
+
+ Module M("R", Context);
+
+ std::uniform_int_distribution<int> dist;
+ const size_t NBCheck = 10;
+
+ std::array<int, NBCheck> RandomStreams[2];
+ for (auto &RandomStream : RandomStreams) {
+ std::unique_ptr<RandomNumberGenerator> RNG{M.createRNG(&DP)};
+ std::generate(RandomStream.begin(), RandomStream.end(),
+ [&]() { return dist(*RNG); });
+ }
+
+ EXPECT_TRUE(std::equal(RandomStreams[0].begin(), RandomStreams[0].end(),
+ RandomStreams[1].begin()));
+}
+
+} // end namespace
diff --git a/unittests/IR/PassManagerTest.cpp b/unittests/IR/PassManagerTest.cpp
index c2ac863260ae..b3a039a364fc 100644
--- a/unittests/IR/PassManagerTest.cpp
+++ b/unittests/IR/PassManagerTest.cpp
@@ -41,12 +41,12 @@ public:
private:
friend AnalysisInfoMixin<TestFunctionAnalysis>;
- static char PassID;
+ static AnalysisKey Key;
int &Runs;
};
-char TestFunctionAnalysis::PassID;
+AnalysisKey TestFunctionAnalysis::Key;
class TestModuleAnalysis : public AnalysisInfoMixin<TestModuleAnalysis> {
public:
@@ -67,12 +67,12 @@ public:
private:
friend AnalysisInfoMixin<TestModuleAnalysis>;
- static char PassID;
+ static AnalysisKey Key;
int &Runs;
};
-char TestModuleAnalysis::PassID;
+AnalysisKey TestModuleAnalysis::Key;
struct TestModulePass : PassInfoMixin<TestModulePass> {
TestModulePass(int &RunCount) : RunCount(RunCount) {}
@@ -91,19 +91,6 @@ struct TestPreservingModulePass : PassInfoMixin<TestPreservingModulePass> {
}
};
-struct TestMinPreservingModulePass
- : PassInfoMixin<TestMinPreservingModulePass> {
- PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM) {
- PreservedAnalyses PA;
-
- // Force running an analysis.
- (void)AM.getResult<TestModuleAnalysis>(M);
-
- PA.preserve<FunctionAnalysisManagerModuleProxy>();
- return PA;
- }
-};
-
struct TestFunctionPass : PassInfoMixin<TestFunctionPass> {
TestFunctionPass(int &RunCount, int &AnalyzedInstrCount,
int &AnalyzedFunctionCount,
@@ -181,45 +168,232 @@ public:
"}\n")) {}
};
-TEST_F(PassManagerTest, BasicPreservedAnalyses) {
+TEST(PreservedAnalysesTest, Basic) {
PreservedAnalyses PA1 = PreservedAnalyses();
- EXPECT_FALSE(PA1.preserved<TestFunctionAnalysis>());
- EXPECT_FALSE(PA1.preserved<TestModuleAnalysis>());
- PreservedAnalyses PA2 = PreservedAnalyses::none();
- EXPECT_FALSE(PA2.preserved<TestFunctionAnalysis>());
- EXPECT_FALSE(PA2.preserved<TestModuleAnalysis>());
- PreservedAnalyses PA3 = PreservedAnalyses::all();
- EXPECT_TRUE(PA3.preserved<TestFunctionAnalysis>());
- EXPECT_TRUE(PA3.preserved<TestModuleAnalysis>());
+ {
+ auto PAC = PA1.getChecker<TestFunctionAnalysis>();
+ EXPECT_FALSE(PAC.preserved());
+ EXPECT_FALSE(PAC.preservedSet<AllAnalysesOn<Function>>());
+ }
+ {
+ auto PAC = PA1.getChecker<TestModuleAnalysis>();
+ EXPECT_FALSE(PAC.preserved());
+ EXPECT_FALSE(PAC.preservedSet<AllAnalysesOn<Module>>());
+ }
+ auto PA2 = PreservedAnalyses::none();
+ {
+ auto PAC = PA2.getChecker<TestFunctionAnalysis>();
+ EXPECT_FALSE(PAC.preserved());
+ EXPECT_FALSE(PAC.preservedSet<AllAnalysesOn<Function>>());
+ }
+ auto PA3 = PreservedAnalyses::all();
+ {
+ auto PAC = PA3.getChecker<TestFunctionAnalysis>();
+ EXPECT_TRUE(PAC.preserved());
+ EXPECT_TRUE(PAC.preservedSet<AllAnalysesOn<Function>>());
+ }
PreservedAnalyses PA4 = PA1;
- EXPECT_FALSE(PA4.preserved<TestFunctionAnalysis>());
- EXPECT_FALSE(PA4.preserved<TestModuleAnalysis>());
+ {
+ auto PAC = PA4.getChecker<TestFunctionAnalysis>();
+ EXPECT_FALSE(PAC.preserved());
+ EXPECT_FALSE(PAC.preservedSet<AllAnalysesOn<Function>>());
+ }
PA4 = PA3;
- EXPECT_TRUE(PA4.preserved<TestFunctionAnalysis>());
- EXPECT_TRUE(PA4.preserved<TestModuleAnalysis>());
+ {
+ auto PAC = PA4.getChecker<TestFunctionAnalysis>();
+ EXPECT_TRUE(PAC.preserved());
+ EXPECT_TRUE(PAC.preservedSet<AllAnalysesOn<Function>>());
+ }
PA4 = std::move(PA2);
- EXPECT_FALSE(PA4.preserved<TestFunctionAnalysis>());
- EXPECT_FALSE(PA4.preserved<TestModuleAnalysis>());
- PA4.preserve<TestFunctionAnalysis>();
- EXPECT_TRUE(PA4.preserved<TestFunctionAnalysis>());
- EXPECT_FALSE(PA4.preserved<TestModuleAnalysis>());
- PA1.preserve<TestModuleAnalysis>();
- EXPECT_FALSE(PA1.preserved<TestFunctionAnalysis>());
- EXPECT_TRUE(PA1.preserved<TestModuleAnalysis>());
+ {
+ auto PAC = PA4.getChecker<TestFunctionAnalysis>();
+ EXPECT_FALSE(PAC.preserved());
+ EXPECT_FALSE(PAC.preservedSet<AllAnalysesOn<Function>>());
+ }
+}
+
+TEST(PreservedAnalysesTest, Preserve) {
+ auto PA = PreservedAnalyses::none();
+ PA.preserve<TestFunctionAnalysis>();
+ EXPECT_TRUE(PA.getChecker<TestFunctionAnalysis>().preserved());
+ EXPECT_FALSE(PA.getChecker<TestModuleAnalysis>().preserved());
+ PA.preserve<TestModuleAnalysis>();
+ EXPECT_TRUE(PA.getChecker<TestFunctionAnalysis>().preserved());
+ EXPECT_TRUE(PA.getChecker<TestModuleAnalysis>().preserved());
+
+ // Redundant calls are fine.
+ PA.preserve<TestFunctionAnalysis>();
+ EXPECT_TRUE(PA.getChecker<TestFunctionAnalysis>().preserved());
+ EXPECT_TRUE(PA.getChecker<TestModuleAnalysis>().preserved());
+}
+
+TEST(PreservedAnalysesTest, PreserveSets) {
+ auto PA = PreservedAnalyses::none();
+ PA.preserveSet<AllAnalysesOn<Function>>();
+ EXPECT_TRUE(PA.getChecker<TestFunctionAnalysis>()
+ .preservedSet<AllAnalysesOn<Function>>());
+ EXPECT_FALSE(PA.getChecker<TestModuleAnalysis>()
+ .preservedSet<AllAnalysesOn<Module>>());
+ PA.preserveSet<AllAnalysesOn<Module>>();
+ EXPECT_TRUE(PA.getChecker<TestFunctionAnalysis>()
+ .preservedSet<AllAnalysesOn<Function>>());
+ EXPECT_TRUE(PA.getChecker<TestModuleAnalysis>()
+ .preservedSet<AllAnalysesOn<Module>>());
+
+ // Mixing is fine.
+ PA.preserve<TestFunctionAnalysis>();
+ EXPECT_TRUE(PA.getChecker<TestFunctionAnalysis>()
+ .preservedSet<AllAnalysesOn<Function>>());
+ EXPECT_TRUE(PA.getChecker<TestModuleAnalysis>()
+ .preservedSet<AllAnalysesOn<Module>>());
+
+ // Redundant calls are fine.
+ PA.preserveSet<AllAnalysesOn<Module>>();
+ EXPECT_TRUE(PA.getChecker<TestFunctionAnalysis>()
+ .preservedSet<AllAnalysesOn<Function>>());
+ EXPECT_TRUE(PA.getChecker<TestModuleAnalysis>()
+ .preservedSet<AllAnalysesOn<Module>>());
+}
+
+TEST(PreservedAnalysisTest, Intersect) {
+ // Setup the initial sets.
+ auto PA1 = PreservedAnalyses::none();
PA1.preserve<TestFunctionAnalysis>();
- EXPECT_TRUE(PA1.preserved<TestFunctionAnalysis>());
- EXPECT_TRUE(PA1.preserved<TestModuleAnalysis>());
- PA1.intersect(PA4);
- EXPECT_TRUE(PA1.preserved<TestFunctionAnalysis>());
- EXPECT_FALSE(PA1.preserved<TestModuleAnalysis>());
+ PA1.preserveSet<AllAnalysesOn<Module>>();
+ auto PA2 = PreservedAnalyses::none();
+ PA2.preserve<TestFunctionAnalysis>();
+ PA2.preserveSet<AllAnalysesOn<Function>>();
+ PA2.preserve<TestModuleAnalysis>();
+ PA2.preserveSet<AllAnalysesOn<Module>>();
+ auto PA3 = PreservedAnalyses::none();
+ PA3.preserve<TestModuleAnalysis>();
+ PA3.preserveSet<AllAnalysesOn<Function>>();
+
+ // Self intersection is a no-op.
+ auto Intersected = PA1;
+ Intersected.intersect(PA1);
+ EXPECT_TRUE(Intersected.getChecker<TestFunctionAnalysis>().preserved());
+ EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()
+ .preservedSet<AllAnalysesOn<Function>>());
+ EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());
+ EXPECT_TRUE(Intersected.getChecker<TestModuleAnalysis>()
+ .preservedSet<AllAnalysesOn<Module>>());
+
+ // Intersecting with all is a no-op.
+ Intersected.intersect(PreservedAnalyses::all());
+ EXPECT_TRUE(Intersected.getChecker<TestFunctionAnalysis>().preserved());
+ EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()
+ .preservedSet<AllAnalysesOn<Function>>());
+ EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());
+ EXPECT_TRUE(Intersected.getChecker<TestModuleAnalysis>()
+ .preservedSet<AllAnalysesOn<Module>>());
+
+ // Intersecting a narrow set with a more broad set is the narrow set.
+ Intersected.intersect(PA2);
+ EXPECT_TRUE(Intersected.getChecker<TestFunctionAnalysis>().preserved());
+ EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()
+ .preservedSet<AllAnalysesOn<Function>>());
+ EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());
+ EXPECT_TRUE(Intersected.getChecker<TestModuleAnalysis>()
+ .preservedSet<AllAnalysesOn<Module>>());
+
+ // Intersecting a broad set with a more narrow set is the narrow set.
+ Intersected = PA2;
+ Intersected.intersect(PA1);
+ EXPECT_TRUE(Intersected.getChecker<TestFunctionAnalysis>().preserved());
+ EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()
+ .preservedSet<AllAnalysesOn<Function>>());
+ EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());
+ EXPECT_TRUE(Intersected.getChecker<TestModuleAnalysis>()
+ .preservedSet<AllAnalysesOn<Module>>());
+
+ // Intersecting with empty clears.
+ Intersected.intersect(PreservedAnalyses::none());
+ EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>().preserved());
+ EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()
+ .preservedSet<AllAnalysesOn<Function>>());
+ EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());
+ EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>()
+ .preservedSet<AllAnalysesOn<Module>>());
+
+ // Intersecting non-overlapping clears.
+ Intersected = PA1;
+ Intersected.intersect(PA3);
+ EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>().preserved());
+ EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()
+ .preservedSet<AllAnalysesOn<Function>>());
+ EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());
+ EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>()
+ .preservedSet<AllAnalysesOn<Module>>());
+
+ // Intersecting with moves works in when there is storage on both sides.
+ Intersected = PA1;
+ auto Tmp = PA2;
+ Intersected.intersect(std::move(Tmp));
+ EXPECT_TRUE(Intersected.getChecker<TestFunctionAnalysis>().preserved());
+ EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()
+ .preservedSet<AllAnalysesOn<Function>>());
+ EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());
+ EXPECT_TRUE(Intersected.getChecker<TestModuleAnalysis>()
+ .preservedSet<AllAnalysesOn<Module>>());
+
+ // Intersecting with move works for incoming all and existing all.
+ auto Tmp2 = PreservedAnalyses::all();
+ Intersected.intersect(std::move(Tmp2));
+ EXPECT_TRUE(Intersected.getChecker<TestFunctionAnalysis>().preserved());
+ EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()
+ .preservedSet<AllAnalysesOn<Function>>());
+ EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());
+ EXPECT_TRUE(Intersected.getChecker<TestModuleAnalysis>()
+ .preservedSet<AllAnalysesOn<Module>>());
+ Intersected = PreservedAnalyses::all();
+ auto Tmp3 = PA1;
+ Intersected.intersect(std::move(Tmp3));
+ EXPECT_TRUE(Intersected.getChecker<TestFunctionAnalysis>().preserved());
+ EXPECT_FALSE(Intersected.getChecker<TestFunctionAnalysis>()
+ .preservedSet<AllAnalysesOn<Function>>());
+ EXPECT_FALSE(Intersected.getChecker<TestModuleAnalysis>().preserved());
+ EXPECT_TRUE(Intersected.getChecker<TestModuleAnalysis>()
+ .preservedSet<AllAnalysesOn<Module>>());
+}
+
+TEST(PreservedAnalysisTest, Abandon) {
+ auto PA = PreservedAnalyses::none();
+
+ // We can abandon things after they are preserved.
+ PA.preserve<TestFunctionAnalysis>();
+ PA.abandon<TestFunctionAnalysis>();
+ EXPECT_FALSE(PA.getChecker<TestFunctionAnalysis>().preserved());
+
+ // Repeated is fine, and abandoning if they were never preserved is fine.
+ PA.abandon<TestFunctionAnalysis>();
+ EXPECT_FALSE(PA.getChecker<TestFunctionAnalysis>().preserved());
+ PA.abandon<TestModuleAnalysis>();
+ EXPECT_FALSE(PA.getChecker<TestModuleAnalysis>().preserved());
+
+ // Even if the sets are preserved, the abandoned analyses' checker won't
+ // return true for those sets.
+ PA.preserveSet<AllAnalysesOn<Function>>();
+ PA.preserveSet<AllAnalysesOn<Module>>();
+ EXPECT_FALSE(PA.getChecker<TestFunctionAnalysis>()
+ .preservedSet<AllAnalysesOn<Function>>());
+ EXPECT_FALSE(PA.getChecker<TestModuleAnalysis>()
+ .preservedSet<AllAnalysesOn<Module>>());
+
+ // But an arbitrary (opaque) analysis will still observe the sets as
+ // preserved. This also checks that we can use an explicit ID rather than
+ // a type.
+ AnalysisKey FakeKey, *FakeID = &FakeKey;
+ EXPECT_TRUE(PA.getChecker(FakeID).preservedSet<AllAnalysesOn<Function>>());
+ EXPECT_TRUE(PA.getChecker(FakeID).preservedSet<AllAnalysesOn<Module>>());
}
TEST_F(PassManagerTest, Basic) {
- FunctionAnalysisManager FAM;
+ FunctionAnalysisManager FAM(/*DebugLogging*/ true);
int FunctionAnalysisRuns = 0;
FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); });
- ModuleAnalysisManager MAM;
+ ModuleAnalysisManager MAM(/*DebugLogging*/ true);
int ModuleAnalysisRuns = 0;
MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns); });
MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });
@@ -233,11 +407,11 @@ TEST_F(PassManagerTest, Basic) {
int AnalyzedFunctionCount1 = 0;
{
// Pointless scoped copy to test move assignment.
- ModulePassManager NestedMPM;
+ ModulePassManager NestedMPM(/*DebugLogging*/ true);
FunctionPassManager FPM;
{
// Pointless scope to test move assignment.
- FunctionPassManager NestedFPM;
+ FunctionPassManager NestedFPM(/*DebugLogging*/ true);
NestedFPM.addPass(TestFunctionPass(
FunctionPassRunCount1, AnalyzedInstrCount1, AnalyzedFunctionCount1));
FPM = std::move(NestedFPM);
@@ -255,7 +429,7 @@ TEST_F(PassManagerTest, Basic) {
int AnalyzedInstrCount2 = 0;
int AnalyzedFunctionCount2 = 0;
{
- FunctionPassManager FPM;
+ FunctionPassManager FPM(/*DebugLogging*/ true);
FPM.addPass(TestFunctionPass(FunctionPassRunCount2, AnalyzedInstrCount2,
AnalyzedFunctionCount2));
MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
@@ -268,15 +442,16 @@ TEST_F(PassManagerTest, Basic) {
int AnalyzedInstrCount3 = 0;
int AnalyzedFunctionCount3 = 0;
{
- FunctionPassManager FPM;
+ FunctionPassManager FPM(/*DebugLogging*/ true);
FPM.addPass(TestFunctionPass(FunctionPassRunCount3, AnalyzedInstrCount3,
AnalyzedFunctionCount3));
FPM.addPass(TestInvalidationFunctionPass("f"));
MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
}
- // A fourth function pass manager but with a minimal intervening passes.
- MPM.addPass(TestMinPreservingModulePass());
+ // A fourth function pass manager but with only preserving intervening
+ // passes but triggering the module analysis.
+ MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>());
int FunctionPassRunCount4 = 0;
int AnalyzedInstrCount4 = 0;
int AnalyzedFunctionCount4 = 0;
@@ -287,12 +462,13 @@ TEST_F(PassManagerTest, Basic) {
MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
}
- // A fifth function pass manager but which uses only cached results.
+ // A fifth function pass manager which invalidates one function first but
+ // uses only cached results.
int FunctionPassRunCount5 = 0;
int AnalyzedInstrCount5 = 0;
int AnalyzedFunctionCount5 = 0;
{
- FunctionPassManager FPM;
+ FunctionPassManager FPM(/*DebugLogging*/ true);
FPM.addPass(TestInvalidationFunctionPass("f"));
FPM.addPass(TestFunctionPass(FunctionPassRunCount5, AnalyzedInstrCount5,
AnalyzedFunctionCount5,
@@ -317,18 +493,276 @@ TEST_F(PassManagerTest, Basic) {
EXPECT_EQ(0, AnalyzedFunctionCount3);
EXPECT_EQ(3, FunctionPassRunCount4);
EXPECT_EQ(5, AnalyzedInstrCount4);
- EXPECT_EQ(0, AnalyzedFunctionCount4);
+ EXPECT_EQ(9, AnalyzedFunctionCount4);
EXPECT_EQ(3, FunctionPassRunCount5);
EXPECT_EQ(2, AnalyzedInstrCount5); // Only 'g' and 'h' were cached.
- EXPECT_EQ(0, AnalyzedFunctionCount5);
+ EXPECT_EQ(9, AnalyzedFunctionCount5);
// Validate the analysis counters:
// first run over 3 functions, then module pass invalidates
// second run over 3 functions, nothing invalidates
// third run over 0 functions, but 1 function invalidated
// fourth run over 1 function
+ // fifth run invalidates 1 function first, but runs over 0 functions
EXPECT_EQ(7, FunctionAnalysisRuns);
EXPECT_EQ(1, ModuleAnalysisRuns);
}
+
+// A customized pass manager that passes extra arguments through the
+// infrastructure.
+typedef AnalysisManager<Function, int> CustomizedAnalysisManager;
+typedef PassManager<Function, CustomizedAnalysisManager, int, int &>
+ CustomizedPassManager;
+
+class CustomizedAnalysis : public AnalysisInfoMixin<CustomizedAnalysis> {
+public:
+ struct Result {
+ Result(int I) : I(I) {}
+ int I;
+ };
+
+ Result run(Function &F, CustomizedAnalysisManager &AM, int I) {
+ return Result(I);
+ }
+
+private:
+ friend AnalysisInfoMixin<CustomizedAnalysis>;
+ static AnalysisKey Key;
+};
+
+AnalysisKey CustomizedAnalysis::Key;
+
+struct CustomizedPass : PassInfoMixin<CustomizedPass> {
+ std::function<void(CustomizedAnalysis::Result &, int &)> Callback;
+
+ template <typename CallbackT>
+ CustomizedPass(CallbackT Callback) : Callback(Callback) {}
+
+ PreservedAnalyses run(Function &F, CustomizedAnalysisManager &AM, int I,
+ int &O) {
+ Callback(AM.getResult<CustomizedAnalysis>(F, I), O);
+ return PreservedAnalyses::none();
+ }
+};
+
+TEST_F(PassManagerTest, CustomizedPassManagerArgs) {
+ CustomizedAnalysisManager AM;
+ AM.registerPass([&] { return CustomizedAnalysis(); });
+
+ CustomizedPassManager PM;
+
+ // Add an instance of the customized pass that just accumulates the input
+ // after it is round-tripped through the analysis.
+ int Result = 0;
+ PM.addPass(
+ CustomizedPass([](CustomizedAnalysis::Result &R, int &O) { O += R.I; }));
+
+ // Run this over every function with the input of 42.
+ for (Function &F : *M)
+ PM.run(F, AM, 42, Result);
+
+ // And ensure that we accumulated the correct result.
+ EXPECT_EQ(42 * (int)M->size(), Result);
+}
+
+/// A test analysis pass which caches in its result another analysis pass and
+/// uses it to serve queries. This requires the result to invalidate itself
+/// when its dependency is invalidated.
+struct TestIndirectFunctionAnalysis
+ : public AnalysisInfoMixin<TestIndirectFunctionAnalysis> {
+ struct Result {
+ Result(TestFunctionAnalysis::Result &FDep, TestModuleAnalysis::Result &MDep)
+ : FDep(FDep), MDep(MDep) {}
+ TestFunctionAnalysis::Result &FDep;
+ TestModuleAnalysis::Result &MDep;
+
+ bool invalidate(Function &F, const PreservedAnalyses &PA,
+ FunctionAnalysisManager::Invalidator &Inv) {
+ auto PAC = PA.getChecker<TestIndirectFunctionAnalysis>();
+ return !(PAC.preserved() ||
+ PAC.preservedSet<AllAnalysesOn<Function>>()) ||
+ Inv.invalidate<TestFunctionAnalysis>(F, PA);
+ }
+ };
+
+ TestIndirectFunctionAnalysis(int &Runs) : Runs(Runs) {}
+
+ /// Run the analysis pass over the function and return a result.
+ Result run(Function &F, FunctionAnalysisManager &AM) {
+ ++Runs;
+ auto &FDep = AM.getResult<TestFunctionAnalysis>(F);
+ auto &Proxy = AM.getResult<ModuleAnalysisManagerFunctionProxy>(F);
+ const ModuleAnalysisManager &MAM = Proxy.getManager();
+ // For the test, we insist that the module analysis starts off in the
+ // cache.
+ auto &MDep = *MAM.getCachedResult<TestModuleAnalysis>(*F.getParent());
+ // And register the dependency as module analysis dependencies have to be
+ // pre-registered on the proxy.
+ Proxy.registerOuterAnalysisInvalidation<TestModuleAnalysis,
+ TestIndirectFunctionAnalysis>();
+ return Result(FDep, MDep);
+ }
+
+private:
+ friend AnalysisInfoMixin<TestIndirectFunctionAnalysis>;
+ static AnalysisKey Key;
+
+ int &Runs;
+};
+
+AnalysisKey TestIndirectFunctionAnalysis::Key;
+
+/// A test analysis pass which chaches in its result the result from the above
+/// indirect analysis pass.
+///
+/// This allows us to ensure that whenever an analysis pass is invalidated due
+/// to dependencies (especially dependencies across IR units that trigger
+/// asynchronous invalidation) we correctly detect that this may in turn cause
+/// other analysis to be invalidated.
+struct TestDoublyIndirectFunctionAnalysis
+ : public AnalysisInfoMixin<TestDoublyIndirectFunctionAnalysis> {
+ struct Result {
+ Result(TestIndirectFunctionAnalysis::Result &IDep) : IDep(IDep) {}
+ TestIndirectFunctionAnalysis::Result &IDep;
+
+ bool invalidate(Function &F, const PreservedAnalyses &PA,
+ FunctionAnalysisManager::Invalidator &Inv) {
+ auto PAC = PA.getChecker<TestDoublyIndirectFunctionAnalysis>();
+ return !(PAC.preserved() ||
+ PAC.preservedSet<AllAnalysesOn<Function>>()) ||
+ Inv.invalidate<TestIndirectFunctionAnalysis>(F, PA);
+ }
+ };
+
+ TestDoublyIndirectFunctionAnalysis(int &Runs) : Runs(Runs) {}
+
+ /// Run the analysis pass over the function and return a result.
+ Result run(Function &F, FunctionAnalysisManager &AM) {
+ ++Runs;
+ auto &IDep = AM.getResult<TestIndirectFunctionAnalysis>(F);
+ return Result(IDep);
+ }
+
+private:
+ friend AnalysisInfoMixin<TestDoublyIndirectFunctionAnalysis>;
+ static AnalysisKey Key;
+
+ int &Runs;
+};
+
+AnalysisKey TestDoublyIndirectFunctionAnalysis::Key;
+
+struct LambdaPass : public PassInfoMixin<LambdaPass> {
+ using FuncT = std::function<PreservedAnalyses(Function &, FunctionAnalysisManager &)>;
+
+ LambdaPass(FuncT Func) : Func(std::move(Func)) {}
+
+ PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) {
+ return Func(F, AM);
+ }
+
+ FuncT Func;
+};
+
+TEST_F(PassManagerTest, IndirectAnalysisInvalidation) {
+ FunctionAnalysisManager FAM(/*DebugLogging*/ true);
+ int FunctionAnalysisRuns = 0, ModuleAnalysisRuns = 0,
+ IndirectAnalysisRuns = 0, DoublyIndirectAnalysisRuns = 0;
+ FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); });
+ FAM.registerPass(
+ [&] { return TestIndirectFunctionAnalysis(IndirectAnalysisRuns); });
+ FAM.registerPass([&] {
+ return TestDoublyIndirectFunctionAnalysis(DoublyIndirectAnalysisRuns);
+ });
+
+ ModuleAnalysisManager MAM(/*DebugLogging*/ true);
+ MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns); });
+ MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });
+ FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); });
+
+ int InstrCount = 0, FunctionCount = 0;
+ ModulePassManager MPM(/*DebugLogging*/ true);
+ FunctionPassManager FPM(/*DebugLogging*/ true);
+ // First just use the analysis to get the instruction count, and preserve
+ // everything.
+ FPM.addPass(LambdaPass([&](Function &F, FunctionAnalysisManager &AM) {
+ auto &DoublyIndirectResult =
+ AM.getResult<TestDoublyIndirectFunctionAnalysis>(F);
+ auto &IndirectResult = DoublyIndirectResult.IDep;
+ InstrCount += IndirectResult.FDep.InstructionCount;
+ FunctionCount += IndirectResult.MDep.FunctionCount;
+ return PreservedAnalyses::all();
+ }));
+ // Next, invalidate
+ // - both analyses for "f",
+ // - just the underlying (indirect) analysis for "g", and
+ // - just the direct analysis for "h".
+ FPM.addPass(LambdaPass([&](Function &F, FunctionAnalysisManager &AM) {
+ auto &DoublyIndirectResult =
+ AM.getResult<TestDoublyIndirectFunctionAnalysis>(F);
+ auto &IndirectResult = DoublyIndirectResult.IDep;
+ InstrCount += IndirectResult.FDep.InstructionCount;
+ FunctionCount += IndirectResult.MDep.FunctionCount;
+ auto PA = PreservedAnalyses::none();
+ if (F.getName() == "g")
+ PA.preserve<TestFunctionAnalysis>();
+ else if (F.getName() == "h")
+ PA.preserve<TestIndirectFunctionAnalysis>();
+ return PA;
+ }));
+ // Finally, use the analysis again on each function, forcing re-computation
+ // for all of them.
+ FPM.addPass(LambdaPass([&](Function &F, FunctionAnalysisManager &AM) {
+ auto &DoublyIndirectResult =
+ AM.getResult<TestDoublyIndirectFunctionAnalysis>(F);
+ auto &IndirectResult = DoublyIndirectResult.IDep;
+ InstrCount += IndirectResult.FDep.InstructionCount;
+ FunctionCount += IndirectResult.MDep.FunctionCount;
+ return PreservedAnalyses::all();
+ }));
+
+ // Create a second function pass manager. This will cause the module-level
+ // invalidation to occur, which will force yet another invalidation of the
+ // indirect function-level analysis as the module analysis it depends on gets
+ // invalidated.
+ FunctionPassManager FPM2(/*DebugLogging*/ true);
+ FPM2.addPass(LambdaPass([&](Function &F, FunctionAnalysisManager &AM) {
+ auto &DoublyIndirectResult =
+ AM.getResult<TestDoublyIndirectFunctionAnalysis>(F);
+ auto &IndirectResult = DoublyIndirectResult.IDep;
+ InstrCount += IndirectResult.FDep.InstructionCount;
+ FunctionCount += IndirectResult.MDep.FunctionCount;
+ return PreservedAnalyses::all();
+ }));
+
+ // Add a requires pass to populate the module analysis and then our function
+ // pass pipeline.
+ MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>());
+ MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
+ // Now require the module analysis again (it will have been invalidated once)
+ // and then use it again from a function pass manager.
+ MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>());
+ MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM2)));
+ MPM.run(*M, MAM);
+
+ // There are generally two possible runs for each of the three functions. But
+ // for one function, we only invalidate the indirect analysis so the base one
+ // only gets run five times.
+ EXPECT_EQ(5, FunctionAnalysisRuns);
+ // The module analysis pass should be run twice here.
+ EXPECT_EQ(2, ModuleAnalysisRuns);
+ // The indirect analysis is invalidated for each function (either directly or
+ // indirectly) and run twice for each.
+ EXPECT_EQ(9, IndirectAnalysisRuns);
+ EXPECT_EQ(9, DoublyIndirectAnalysisRuns);
+
+ // There are five instructions in the module and we add the count four
+ // times.
+ EXPECT_EQ(5 * 4, InstrCount);
+
+ // There are three functions and we count them four times for each of the
+ // three functions.
+ EXPECT_EQ(3 * 4 * 3, FunctionCount);
+}
}
diff --git a/unittests/IR/PatternMatch.cpp b/unittests/IR/PatternMatch.cpp
index 1121d6554db7..2d1321def7e3 100644
--- a/unittests/IR/PatternMatch.cpp
+++ b/unittests/IR/PatternMatch.cpp
@@ -295,4 +295,31 @@ TEST_F(PatternMatchTest, OverflowingBinOps) {
EXPECT_FALSE(m_NUWShl(m_Value(), m_Value()).match(IRB.CreateNUWAdd(L, R)));
}
+template <typename T> struct MutableConstTest : PatternMatchTest { };
+
+typedef ::testing::Types<std::tuple<Value*, Instruction*>,
+ std::tuple<const Value*, const Instruction *>>
+ MutableConstTestTypes;
+TYPED_TEST_CASE(MutableConstTest, MutableConstTestTypes);
+
+TYPED_TEST(MutableConstTest, ICmp) {
+ auto &IRB = PatternMatchTest::IRB;
+
+ typedef typename std::tuple_element<0, TypeParam>::type ValueType;
+ typedef typename std::tuple_element<1, TypeParam>::type InstructionType;
+
+ Value *L = IRB.getInt32(1);
+ Value *R = IRB.getInt32(2);
+ ICmpInst::Predicate Pred = ICmpInst::ICMP_UGT;
+
+ ValueType MatchL;
+ ValueType MatchR;
+ ICmpInst::Predicate MatchPred;
+
+ EXPECT_TRUE(m_ICmp(MatchPred, m_Value(MatchL), m_Value(MatchR))
+ .match((InstructionType)IRB.CreateICmp(Pred, L, R)));
+ EXPECT_EQ(L, MatchL);
+ EXPECT_EQ(R, MatchR);
+}
+
} // anonymous namespace.
diff --git a/unittests/IR/VerifierTest.cpp b/unittests/IR/VerifierTest.cpp
index c33c92a6f7c5..ad6940afd05e 100644
--- a/unittests/IR/VerifierTest.cpp
+++ b/unittests/IR/VerifierTest.cpp
@@ -14,6 +14,7 @@
#include "llvm/IR/GlobalAlias.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Instructions.h"
+#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
@@ -121,31 +122,6 @@ TEST(VerifierTest, CrossModuleRef) {
F3->eraseFromParent();
}
-TEST(VerifierTest, CrossModuleMetadataRef) {
- LLVMContext C;
- Module M1("M1", C);
- Module M2("M2", C);
- GlobalVariable *newGV =
- new GlobalVariable(M1, Type::getInt8Ty(C), false,
- GlobalVariable::ExternalLinkage, nullptr,
- "Some Global");
-
- DIBuilder dbuilder(M2);
- auto CU = dbuilder.createCompileUnit(dwarf::DW_LANG_Julia, "test.jl", ".",
- "unittest", false, "", 0);
- auto File = dbuilder.createFile("test.jl", ".");
- auto Ty = dbuilder.createBasicType("Int8", 8, 8, dwarf::DW_ATE_signed);
- dbuilder.createGlobalVariable(CU, "_SOME_GLOBAL", "_SOME_GLOBAL", File, 1, Ty,
- false, newGV);
- dbuilder.finalize();
-
- std::string Error;
- raw_string_ostream ErrorOS(Error);
- EXPECT_TRUE(verifyModule(M2, &ErrorOS));
- EXPECT_TRUE(StringRef(ErrorOS.str())
- .startswith("Referencing global in another module!"));
-}
-
TEST(VerifierTest, InvalidVariableLinkage) {
LLVMContext C;
Module M("M", C);
@@ -173,37 +149,67 @@ TEST(VerifierTest, InvalidFunctionLinkage) {
"have external or weak linkage!"));
}
-#ifndef _MSC_VER
-// FIXME: This test causes an ICE in MSVC 2013.
TEST(VerifierTest, StripInvalidDebugInfo) {
- LLVMContext C;
- Module M("M", C);
- DIBuilder DIB(M);
- DIB.createCompileUnit(dwarf::DW_LANG_C89, "broken.c", "/",
- "unittest", false, "", 0);
- DIB.finalize();
- EXPECT_FALSE(verifyModule(M));
-
- // Now break it.
- auto *File = DIB.createFile("not-a-CU.f", ".");
- NamedMDNode *NMD = M.getOrInsertNamedMetadata("llvm.dbg.cu");
- NMD->addOperand(File);
- EXPECT_TRUE(verifyModule(M));
-
- ModulePassManager MPM(true);
- MPM.addPass(VerifierPass(false));
- ModuleAnalysisManager MAM(true);
- MAM.registerPass([&] { return VerifierAnalysis(); });
- MPM.run(M, MAM);
- EXPECT_FALSE(verifyModule(M));
+ {
+ LLVMContext C;
+ Module M("M", C);
+ DIBuilder DIB(M);
+ DIB.createCompileUnit(dwarf::DW_LANG_C89, DIB.createFile("broken.c", "/"),
+ "unittest", false, "", 0);
+ DIB.finalize();
+ EXPECT_FALSE(verifyModule(M));
+
+ // Now break it by inserting non-CU node to the list of CUs.
+ auto *File = DIB.createFile("not-a-CU.f", ".");
+ NamedMDNode *NMD = M.getOrInsertNamedMetadata("llvm.dbg.cu");
+ NMD->addOperand(File);
+ EXPECT_TRUE(verifyModule(M));
+
+ ModulePassManager MPM(true);
+ MPM.addPass(VerifierPass(false));
+ ModuleAnalysisManager MAM(true);
+ MAM.registerPass([&] { return VerifierAnalysis(); });
+ MPM.run(M, MAM);
+ EXPECT_FALSE(verifyModule(M));
+ }
+ {
+ LLVMContext C;
+ Module M("M", C);
+ DIBuilder DIB(M);
+ auto *CU = DIB.createCompileUnit(dwarf::DW_LANG_C89,
+ DIB.createFile("broken.c", "/"),
+ "unittest", false, "", 0);
+ new GlobalVariable(M, Type::getInt8Ty(C), false,
+ GlobalValue::ExternalLinkage, nullptr, "g");
+
+ auto *F = cast<Function>(M.getOrInsertFunction(
+ "f", FunctionType::get(Type::getVoidTy(C), false)));
+ IRBuilder<> Builder(BasicBlock::Create(C, "", F));
+ Builder.CreateUnreachable();
+ F->setSubprogram(DIB.createFunction(CU, "f", "f",
+ DIB.createFile("broken.c", "/"), 1,
+ nullptr, true, true, 1));
+ DIB.finalize();
+ EXPECT_FALSE(verifyModule(M));
+
+ // Now break it by not listing the CU at all.
+ M.eraseNamedMetadata(M.getOrInsertNamedMetadata("llvm.dbg.cu"));
+ EXPECT_TRUE(verifyModule(M));
+
+ ModulePassManager MPM(true);
+ MPM.addPass(VerifierPass(false));
+ ModuleAnalysisManager MAM(true);
+ MAM.registerPass([&] { return VerifierAnalysis(); });
+ MPM.run(M, MAM);
+ EXPECT_FALSE(verifyModule(M));
+ }
}
-#endif
TEST(VerifierTest, StripInvalidDebugInfoLegacy) {
LLVMContext C;
Module M("M", C);
DIBuilder DIB(M);
- DIB.createCompileUnit(dwarf::DW_LANG_C89, "broken.c", "/",
+ DIB.createCompileUnit(dwarf::DW_LANG_C89, DIB.createFile("broken.c", "/"),
"unittest", false, "", 0);
DIB.finalize();
EXPECT_FALSE(verifyModule(M));
diff --git a/unittests/MC/DwarfLineTables.cpp b/unittests/MC/DwarfLineTables.cpp
index 4bfb5acea039..d66c832df0ba 100644
--- a/unittests/MC/DwarfLineTables.cpp
+++ b/unittests/MC/DwarfLineTables.cpp
@@ -46,21 +46,25 @@ struct Context {
operator MCContext &() { return *Ctx; };
};
-Context Ctxt;
+Context &getContext() {
+ static Context Ctxt;
+ return Ctxt;
+}
}
void verifyEncoding(MCDwarfLineTableParams Params, int LineDelta, int AddrDelta,
ArrayRef<uint8_t> ExpectedEncoding) {
SmallString<16> Buffer;
raw_svector_ostream EncodingOS(Buffer);
- MCDwarfLineAddr::Encode(Ctxt, Params, LineDelta, AddrDelta, EncodingOS);
+ MCDwarfLineAddr::Encode(getContext(), Params, LineDelta, AddrDelta,
+ EncodingOS);
ArrayRef<uint8_t> Encoding(reinterpret_cast<uint8_t *>(Buffer.data()),
Buffer.size());
EXPECT_EQ(ExpectedEncoding, Encoding);
}
TEST(DwarfLineTables, TestDefaultParams) {
- if (!Ctxt)
+ if (!getContext())
return;
MCDwarfLineTableParams Params;
@@ -110,7 +114,7 @@ TEST(DwarfLineTables, TestDefaultParams) {
}
TEST(DwarfLineTables, TestCustomParams) {
- if (!Ctxt)
+ if (!getContext())
return;
// Some tests against the example values given in the standard.
@@ -164,7 +168,7 @@ TEST(DwarfLineTables, TestCustomParams) {
}
TEST(DwarfLineTables, TestCustomParams2) {
- if (!Ctxt)
+ if (!getContext())
return;
// Corner case param values.
diff --git a/unittests/MC/StringTableBuilderTest.cpp b/unittests/MC/StringTableBuilderTest.cpp
index f78d3588ffff..f68350d90ba5 100644
--- a/unittests/MC/StringTableBuilderTest.cpp
+++ b/unittests/MC/StringTableBuilderTest.cpp
@@ -7,6 +7,7 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/ADT/SmallString.h"
#include "llvm/MC/StringTableBuilder.h"
#include "llvm/Support/Endian.h"
#include "gtest/gtest.h"
@@ -32,7 +33,11 @@ TEST(StringTableBuilderTest, BasicELF) {
Expected += "foo";
Expected += '\x00';
- EXPECT_EQ(Expected, B.data());
+ SmallString<64> Data;
+ raw_svector_ostream OS(Data);
+ B.write(OS);
+
+ EXPECT_EQ(Expected, Data);
EXPECT_EQ(1U, B.getOffset("foobar"));
EXPECT_EQ(4U, B.getOffset("bar"));
EXPECT_EQ(8U, B.getOffset("foo"));
@@ -50,7 +55,7 @@ TEST(StringTableBuilderTest, BasicWinCOFF) {
// size_field + "pygmy hippopotamus\0" + "river horse\0"
uint32_t ExpectedSize = 4 + 19 + 12;
- EXPECT_EQ(ExpectedSize, B.data().size());
+ EXPECT_EQ(ExpectedSize, B.getSize());
std::string Expected;
@@ -62,7 +67,11 @@ TEST(StringTableBuilderTest, BasicWinCOFF) {
Expected += "river horse";
Expected += '\x00';
- EXPECT_EQ(Expected, B.data());
+ SmallString<64> Data;
+ raw_svector_ostream OS(Data);
+ B.write(OS);
+
+ EXPECT_EQ(Expected, Data);
EXPECT_EQ(4U, B.getOffset("pygmy hippopotamus"));
EXPECT_EQ(10U, B.getOffset("hippopotamus"));
EXPECT_EQ(23U, B.getOffset("river horse"));
@@ -85,7 +94,11 @@ TEST(StringTableBuilderTest, ELFInOrder) {
Expected += "foobar";
Expected += '\x00';
- EXPECT_EQ(Expected, B.data());
+ SmallString<64> Data;
+ raw_svector_ostream OS(Data);
+ B.write(OS);
+
+ EXPECT_EQ(Expected, Data);
EXPECT_EQ(1U, B.getOffset("foo"));
EXPECT_EQ(5U, B.getOffset("bar"));
EXPECT_EQ(9U, B.getOffset("foobar"));
diff --git a/unittests/MI/LiveIntervalTest.cpp b/unittests/MI/LiveIntervalTest.cpp
index e0b3d5529afb..1d6df97a3200 100644
--- a/unittests/MI/LiveIntervalTest.cpp
+++ b/unittests/MI/LiveIntervalTest.cpp
@@ -35,9 +35,10 @@ void initLLVM() {
}
/// Create a TargetMachine. As we lack a dedicated always available target for
-/// unittests, we go for "x86_64" which should be available in most builds.
+/// unittests, we go for "AMDGPU" to be able to test normal and subregister
+/// liveranges.
std::unique_ptr<TargetMachine> createTargetMachine() {
- Triple TargetTriple("x86_64--");
+ Triple TargetTriple("amdgcn--");
std::string Error;
const Target *T = TargetRegistry::lookupTarget("", TargetTriple, Error);
if (!T)
@@ -45,7 +46,7 @@ std::unique_ptr<TargetMachine> createTargetMachine() {
TargetOptions Options;
return std::unique_ptr<TargetMachine>(
- T->createTargetMachine("x86_64", "", "", Options, None,
+ T->createTargetMachine("AMDGPU", "", "", Options, None,
CodeModel::Default, CodeGenOpt::Aggressive));
}
@@ -68,9 +69,9 @@ std::unique_ptr<Module> parseMIR(LLVMContext &Context,
if (!F)
return nullptr;
- const LLVMTargetMachine &LLVMTM = static_cast<const LLVMTargetMachine&>(TM);
- LLVMTM.addMachineModuleInfo(PM);
- LLVMTM.addMachineFunctionAnalysis(PM, MIR.get());
+ MachineModuleInfo *MMI = new MachineModuleInfo(&TM);
+ MMI->setMachineFunctionInitializer(MIR.get());
+ PM.add(MMI);
return M;
}
@@ -104,28 +105,31 @@ private:
LiveIntervalTest T;
};
-/**
- * Move instruction number \p From in front of instruction number \p To and
- * update affected liveness intervals with LiveIntervalAnalysis::handleMove().
- */
-static void testHandleMove(MachineFunction &MF, LiveIntervals &LIS,
- unsigned From, unsigned To, unsigned BlockNum = 0) {
+static MachineInstr &getMI(MachineFunction &MF, unsigned At,
+ unsigned BlockNum) {
MachineBasicBlock &MBB = *MF.getBlockNumbered(BlockNum);
unsigned I = 0;
- MachineInstr *FromInstr = nullptr;
- MachineInstr *ToInstr = nullptr;
for (MachineInstr &MI : MBB) {
- if (I == From)
- FromInstr = &MI;
- if (I == To)
- ToInstr = &MI;
+ if (I == At)
+ return MI;
++I;
}
- assert(FromInstr != nullptr && ToInstr != nullptr);
+ llvm_unreachable("Instruction not found");
+}
- MBB.splice(ToInstr->getIterator(), &MBB, FromInstr->getIterator());
- LIS.handleMove(*FromInstr, true);
+/**
+ * Move instruction number \p From in front of instruction number \p To and
+ * update affected liveness intervals with LiveIntervalAnalysis::handleMove().
+ */
+static void testHandleMove(MachineFunction &MF, LiveIntervals &LIS,
+ unsigned From, unsigned To, unsigned BlockNum = 0) {
+ MachineInstr &FromInstr = getMI(MF, From, BlockNum);
+ MachineInstr &ToInstr = getMI(MF, To, BlockNum);
+
+ MachineBasicBlock &MBB = *FromInstr.getParent();
+ MBB.splice(ToInstr.getIterator(), &MBB, FromInstr.getIterator());
+ LIS.handleMove(FromInstr, true);
}
static void liveIntervalTest(StringRef MIRFunc, LiveIntervalTest T) {
@@ -143,7 +147,7 @@ static void liveIntervalTest(StringRef MIRFunc, LiveIntervalTest T) {
"...\n"
"name: func\n"
"registers:\n"
-" - { id: 0, class: gr64 }\n"
+" - { id: 0, class: sreg_64 }\n"
"body: |\n"
" bb.0:\n"
) + Twine(MIRFunc) + Twine("...\n")).toNullTerminatedStringRef(S);
@@ -164,10 +168,10 @@ INITIALIZE_PASS(TestPass, "testpass", "testpass", false, false)
TEST(LiveIntervalTest, MoveUpDef) {
// Value defined.
liveIntervalTest(
-" NOOP\n"
-" NOOP\n"
+" S_NOP 0\n"
+" S_NOP 0\n"
" early-clobber %0 = IMPLICIT_DEF\n"
-" RETQ %0\n",
+" S_NOP 0, implicit %0\n",
[](MachineFunction &MF, LiveIntervals &LIS) {
testHandleMove(MF, LIS, 2, 1);
});
@@ -176,9 +180,9 @@ TEST(LiveIntervalTest, MoveUpDef) {
TEST(LiveIntervalTest, MoveUpRedef) {
liveIntervalTest(
" %0 = IMPLICIT_DEF\n"
-" NOOP\n"
+" S_NOP 0\n"
" %0 = IMPLICIT_DEF implicit %0(tied-def 0)\n"
-" RETQ %0\n",
+" S_NOP 0, implicit %0\n",
[](MachineFunction &MF, LiveIntervals &LIS) {
testHandleMove(MF, LIS, 2, 1);
});
@@ -186,10 +190,10 @@ TEST(LiveIntervalTest, MoveUpRedef) {
TEST(LiveIntervalTest, MoveUpEarlyDef) {
liveIntervalTest(
-" NOOP\n"
-" NOOP\n"
+" S_NOP 0\n"
+" S_NOP 0\n"
" early-clobber %0 = IMPLICIT_DEF\n"
-" RETQ %0\n",
+" S_NOP 0, implicit %0\n",
[](MachineFunction &MF, LiveIntervals &LIS) {
testHandleMove(MF, LIS, 2, 1);
});
@@ -198,9 +202,9 @@ TEST(LiveIntervalTest, MoveUpEarlyDef) {
TEST(LiveIntervalTest, MoveUpEarlyRedef) {
liveIntervalTest(
" %0 = IMPLICIT_DEF\n"
-" NOOP\n"
+" S_NOP 0\n"
" early-clobber %0 = IMPLICIT_DEF implicit %0(tied-def 0)\n"
-" RETQ %0\n",
+" S_NOP 0, implicit %0\n",
[](MachineFunction &MF, LiveIntervals &LIS) {
testHandleMove(MF, LIS, 2, 1);
});
@@ -209,8 +213,8 @@ TEST(LiveIntervalTest, MoveUpEarlyRedef) {
TEST(LiveIntervalTest, MoveUpKill) {
liveIntervalTest(
" %0 = IMPLICIT_DEF\n"
-" NOOP\n"
-" NOOP implicit %0\n",
+" S_NOP 0\n"
+" S_NOP 0, implicit %0\n",
[](MachineFunction &MF, LiveIntervals &LIS) {
testHandleMove(MF, LIS, 2, 1);
});
@@ -219,9 +223,9 @@ TEST(LiveIntervalTest, MoveUpKill) {
TEST(LiveIntervalTest, MoveUpKillFollowing) {
liveIntervalTest(
" %0 = IMPLICIT_DEF\n"
-" NOOP\n"
-" NOOP implicit %0\n"
-" RETQ %0\n",
+" S_NOP 0\n"
+" S_NOP 0, implicit %0\n"
+" S_NOP 0, implicit %0\n",
[](MachineFunction &MF, LiveIntervals &LIS) {
testHandleMove(MF, LIS, 2, 1);
});
@@ -233,10 +237,10 @@ TEST(LiveIntervalTest, MoveUpKillFollowing) {
TEST(LiveIntervalTest, MoveDownDef) {
// Value defined.
liveIntervalTest(
-" NOOP\n"
+" S_NOP 0\n"
" early-clobber %0 = IMPLICIT_DEF\n"
-" NOOP\n"
-" RETQ %0\n",
+" S_NOP 0\n"
+" S_NOP 0, implicit %0\n",
[](MachineFunction &MF, LiveIntervals &LIS) {
testHandleMove(MF, LIS, 1, 2);
});
@@ -246,8 +250,8 @@ TEST(LiveIntervalTest, MoveDownRedef) {
liveIntervalTest(
" %0 = IMPLICIT_DEF\n"
" %0 = IMPLICIT_DEF implicit %0(tied-def 0)\n"
-" NOOP\n"
-" RETQ %0\n",
+" S_NOP 0\n"
+" S_NOP 0, implicit %0\n",
[](MachineFunction &MF, LiveIntervals &LIS) {
testHandleMove(MF, LIS, 1, 2);
});
@@ -255,10 +259,10 @@ TEST(LiveIntervalTest, MoveDownRedef) {
TEST(LiveIntervalTest, MoveDownEarlyDef) {
liveIntervalTest(
-" NOOP\n"
+" S_NOP 0\n"
" early-clobber %0 = IMPLICIT_DEF\n"
-" NOOP\n"
-" RETQ %0\n",
+" S_NOP 0\n"
+" S_NOP 0, implicit %0\n",
[](MachineFunction &MF, LiveIntervals &LIS) {
testHandleMove(MF, LIS, 1, 2);
});
@@ -268,8 +272,8 @@ TEST(LiveIntervalTest, MoveDownEarlyRedef) {
liveIntervalTest(
" %0 = IMPLICIT_DEF\n"
" early-clobber %0 = IMPLICIT_DEF implicit %0(tied-def 0)\n"
-" NOOP\n"
-" RETQ %0\n",
+" S_NOP 0\n"
+" S_NOP 0, implicit %0\n",
[](MachineFunction &MF, LiveIntervals &LIS) {
testHandleMove(MF, LIS, 1, 2);
});
@@ -278,8 +282,8 @@ TEST(LiveIntervalTest, MoveDownEarlyRedef) {
TEST(LiveIntervalTest, MoveDownKill) {
liveIntervalTest(
" %0 = IMPLICIT_DEF\n"
-" NOOP implicit %0\n"
-" NOOP\n",
+" S_NOP 0, implicit %0\n"
+" S_NOP 0\n",
[](MachineFunction &MF, LiveIntervals &LIS) {
testHandleMove(MF, LIS, 1, 2);
});
@@ -288,9 +292,9 @@ TEST(LiveIntervalTest, MoveDownKill) {
TEST(LiveIntervalTest, MoveDownKillFollowing) {
liveIntervalTest(
" %0 = IMPLICIT_DEF\n"
-" NOOP\n"
-" NOOP implicit %0\n"
-" RETQ %0\n",
+" S_NOP 0\n"
+" S_NOP 0, implicit %0\n"
+" S_NOP 0, implicit %0\n",
[](MachineFunction &MF, LiveIntervals &LIS) {
testHandleMove(MF, LIS, 1, 2);
});
@@ -299,9 +303,9 @@ TEST(LiveIntervalTest, MoveDownKillFollowing) {
TEST(LiveIntervalTest, MoveUndefUse) {
liveIntervalTest(
" %0 = IMPLICIT_DEF\n"
-" NOOP implicit undef %0\n"
-" NOOP implicit %0\n"
-" NOOP\n",
+" S_NOP 0, implicit undef %0\n"
+" S_NOP 0, implicit %0\n"
+" S_NOP 0\n",
[](MachineFunction &MF, LiveIntervals &LIS) {
testHandleMove(MF, LIS, 1, 3);
});
@@ -314,16 +318,16 @@ TEST(LiveIntervalTest, MoveUpValNos) {
liveIntervalTest(
" successors: %bb.1, %bb.2\n"
" %0 = IMPLICIT_DEF\n"
-" JG_1 %bb.2, implicit %eflags\n"
-" JMP_1 %bb.1\n"
+" S_CBRANCH_VCCNZ %bb.2, implicit undef %vcc\n"
+" S_BRANCH %bb.1\n"
" bb.2:\n"
-" NOOP implicit %0\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"
-" JMP_1 %bb.2\n",
+" S_BRANCH %bb.2\n",
[](MachineFunction &MF, LiveIntervals &LIS) {
testHandleMove(MF, LIS, 2, 0, 2);
});
@@ -333,8 +337,8 @@ TEST(LiveIntervalTest, MoveOverUndefUse0) {
// findLastUseBefore() used by handleMoveUp() must ignore undef operands.
liveIntervalTest(
" %0 = IMPLICIT_DEF\n"
-" NOOP\n"
-" NOOP implicit undef %0\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) {
testHandleMove(MF, LIS, 3, 1);
@@ -344,15 +348,40 @@ TEST(LiveIntervalTest, MoveOverUndefUse0) {
TEST(LiveIntervalTest, MoveOverUndefUse1) {
// findLastUseBefore() used by handleMoveUp() must ignore undef operands.
liveIntervalTest(
-" %rax = IMPLICIT_DEF\n"
-" NOOP\n"
-" NOOP implicit undef %rax\n"
-" %rax = IMPLICIT_DEF implicit %rax(tied-def 0)\n",
+" %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) {
testHandleMove(MF, LIS, 3, 1);
});
}
+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) {
+ // Scheduler behaviour: Clear def,read-undef flag and move.
+ MachineInstr &MI = getMI(MF, 3, /*BlockNum=*/1);
+ MI.getOperand(0).setIsUndef(false);
+ testHandleMove(MF, LIS, 1, 4, /*BlockNum=*/1);
+ });
+}
+
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
initLLVM();
diff --git a/unittests/Object/CMakeLists.txt b/unittests/Object/CMakeLists.txt
new file mode 100644
index 000000000000..7a63c167a30b
--- /dev/null
+++ b/unittests/Object/CMakeLists.txt
@@ -0,0 +1,8 @@
+set(LLVM_LINK_COMPONENTS
+ Object
+ )
+
+add_llvm_unittest(ObjectTests
+ SymbolSizeTest.cpp
+ )
+
diff --git a/unittests/Object/SymbolSizeTest.cpp b/unittests/Object/SymbolSizeTest.cpp
new file mode 100644
index 000000000000..ad9c40b986db
--- /dev/null
+++ b/unittests/Object/SymbolSizeTest.cpp
@@ -0,0 +1,33 @@
+//===- SymbolSizeTest.cpp - Tests for SymbolSize.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/SymbolSize.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace llvm::object;
+
+TEST(Object, SymbolSizeSort) {
+ auto it = symbol_iterator(SymbolRef());
+ std::vector<SymEntry> Syms{
+ SymEntry{it, 0xffffffff00000000ull, 1, 0},
+ SymEntry{it, 0x00ffffff00000000ull, 2, 0},
+ SymEntry{it, 0x00ffffff000000ffull, 3, 0},
+ SymEntry{it, 0x0000000100000000ull, 4, 0},
+ SymEntry{it, 0x00000000000000ffull, 5, 0},
+ SymEntry{it, 0x00000001000000ffull, 6, 0},
+ SymEntry{it, 0x000000010000ffffull, 7, 0},
+ };
+
+ array_pod_sort(Syms.begin(), Syms.end(), compareAddress);
+
+ for (unsigned I = 0, N = Syms.size(); I < N - 1; ++I) {
+ EXPECT_LE(Syms[I].Address, Syms[I + 1].Address);
+ }
+}
diff --git a/unittests/ProfileData/CoverageMappingTest.cpp b/unittests/ProfileData/CoverageMappingTest.cpp
index 53b40ebae85a..49eab4ad7887 100644
--- a/unittests/ProfileData/CoverageMappingTest.cpp
+++ b/unittests/ProfileData/CoverageMappingTest.cpp
@@ -16,6 +16,7 @@
#include "gtest/gtest.h"
#include <ostream>
+#include <utility>
using namespace llvm;
using namespace coverage;
@@ -55,6 +56,17 @@ struct OutputFunctionCoverageData {
std::vector<StringRef> Filenames;
std::vector<CounterMappingRegion> Regions;
+ OutputFunctionCoverageData() : Hash(0) {}
+
+ OutputFunctionCoverageData(OutputFunctionCoverageData &&OFCD)
+ : Name(OFCD.Name), Hash(OFCD.Hash), Filenames(std::move(OFCD.Filenames)),
+ Regions(std::move(OFCD.Regions)) {}
+
+ OutputFunctionCoverageData(const OutputFunctionCoverageData &) = delete;
+ OutputFunctionCoverageData &
+ operator=(const OutputFunctionCoverageData &) = delete;
+ OutputFunctionCoverageData &operator=(OutputFunctionCoverageData &&) = delete;
+
void fillCoverageMappingRecord(CoverageMappingRecord &Record) const {
Record.FunctionName = Name;
Record.FunctionHash = Hash;
@@ -95,9 +107,20 @@ struct InputFunctionCoverageData {
InputFunctionCoverageData(std::string Name, uint64_t Hash)
: Name(std::move(Name)), Hash(Hash) {}
+
+ InputFunctionCoverageData(InputFunctionCoverageData &&IFCD)
+ : ReverseVirtualFileMapping(std::move(IFCD.ReverseVirtualFileMapping)),
+ Name(std::move(IFCD.Name)), Hash(IFCD.Hash),
+ Regions(std::move(IFCD.Regions)) {}
+
+ InputFunctionCoverageData(const InputFunctionCoverageData &) = delete;
+ InputFunctionCoverageData &
+ operator=(const InputFunctionCoverageData &) = delete;
+ InputFunctionCoverageData &operator=(InputFunctionCoverageData &&) = delete;
};
-struct CoverageMappingTest : ::testing::Test {
+struct CoverageMappingTest : ::testing::TestWithParam<std::pair<bool, bool>> {
+ bool UseMultipleReaders;
StringMap<unsigned> Files;
std::vector<InputFunctionCoverageData> InputFunctions;
std::vector<OutputFunctionCoverageData> OutputFunctions;
@@ -108,7 +131,8 @@ struct CoverageMappingTest : ::testing::Test {
std::unique_ptr<CoverageMapping> LoadedCoverage;
void SetUp() override {
- ProfileWriter.setOutputSparse(false);
+ ProfileWriter.setOutputSparse(GetParam().first);
+ UseMultipleReaders = GetParam().second;
}
unsigned getGlobalFileIndex(StringRef Name) {
@@ -116,12 +140,12 @@ struct CoverageMappingTest : ::testing::Test {
if (R != Files.end())
return R->second;
unsigned Index = Files.size();
- Files.emplace_second(Name, Index);
+ Files.try_emplace(Name, Index);
return Index;
}
// Return the file index of file 'Name' for the current function.
- // Add the file into the global map if necesary.
+ // Add the file into the global map if necessary.
// See also InputFunctionCoverageData::ReverseVirtualFileMapping
// for additional comments.
unsigned getFileIndexForFunction(StringRef Name) {
@@ -164,7 +188,7 @@ struct CoverageMappingTest : ::testing::Test {
return OS.str();
}
- void readCoverageRegions(std::string Coverage,
+ void readCoverageRegions(const std::string &Coverage,
OutputFunctionCoverageData &Data) {
SmallVector<StringRef, 8> Filenames(Files.size());
for (const auto &E : Files)
@@ -194,27 +218,30 @@ struct CoverageMappingTest : ::testing::Test {
ProfileReader = std::move(ReaderOrErr.get());
}
+ Expected<std::unique_ptr<CoverageMapping>> readOutputFunctions() {
+ if (!UseMultipleReaders) {
+ CoverageMappingReaderMock CovReader(OutputFunctions);
+ return CoverageMapping::load(CovReader, *ProfileReader);
+ }
+
+ std::vector<std::unique_ptr<CoverageMappingReader>> CoverageReaders;
+ for (const auto &OF : OutputFunctions) {
+ ArrayRef<OutputFunctionCoverageData> Funcs(OF);
+ CoverageReaders.push_back(make_unique<CoverageMappingReaderMock>(Funcs));
+ }
+ return CoverageMapping::load(CoverageReaders, *ProfileReader);
+ }
+
void loadCoverageMapping(bool EmitFilenames = true) {
readProfCounts();
writeAndReadCoverageRegions(EmitFilenames);
-
- CoverageMappingReaderMock CovReader(OutputFunctions);
- auto CoverageOrErr = CoverageMapping::load(CovReader, *ProfileReader);
+ auto CoverageOrErr = readOutputFunctions();
ASSERT_TRUE(NoError(CoverageOrErr.takeError()));
LoadedCoverage = std::move(CoverageOrErr.get());
}
};
-struct MaybeSparseCoverageMappingTest
- : public CoverageMappingTest,
- public ::testing::WithParamInterface<bool> {
- void SetUp() {
- CoverageMappingTest::SetUp();
- ProfileWriter.setOutputSparse(GetParam());
- }
-};
-
-TEST_P(MaybeSparseCoverageMappingTest, basic_write_read) {
+TEST_P(CoverageMappingTest, basic_write_read) {
startFunction("func", 0x1234);
addCMR(Counter::getCounter(0), "foo", 1, 1, 1, 1);
addCMR(Counter::getCounter(1), "foo", 2, 1, 2, 2);
@@ -239,8 +266,7 @@ TEST_P(MaybeSparseCoverageMappingTest, basic_write_read) {
}
}
-TEST_P(MaybeSparseCoverageMappingTest,
- correct_deserialize_for_more_than_two_files) {
+TEST_P(CoverageMappingTest, correct_deserialize_for_more_than_two_files) {
const char *FileNames[] = {"bar", "baz", "foo"};
static const unsigned N = array_lengthof(FileNames);
@@ -265,7 +291,7 @@ TEST_P(MaybeSparseCoverageMappingTest,
}
}
-TEST_P(MaybeSparseCoverageMappingTest, load_coverage_for_more_than_two_files) {
+TEST_P(CoverageMappingTest, load_coverage_for_more_than_two_files) {
InstrProfRecord Record("func", 0x1234, {0});
NoError(ProfileWriter.addRecord(std::move(Record)));
@@ -287,7 +313,7 @@ TEST_P(MaybeSparseCoverageMappingTest, load_coverage_for_more_than_two_files) {
}
}
-TEST_P(MaybeSparseCoverageMappingTest, load_coverage_for_several_functions) {
+TEST_P(CoverageMappingTest, load_coverage_for_several_functions) {
InstrProfRecord RecordFunc1("func1", 0x1234, {10});
NoError(ProfileWriter.addRecord(std::move(RecordFunc1)));
InstrProfRecord RecordFunc2("func2", 0x2345, {20});
@@ -318,7 +344,7 @@ TEST_P(MaybeSparseCoverageMappingTest, load_coverage_for_several_functions) {
}
}
-TEST_P(MaybeSparseCoverageMappingTest, expansion_gets_first_counter) {
+TEST_P(CoverageMappingTest, expansion_gets_first_counter) {
startFunction("func", 0x1234);
addCMR(Counter::getCounter(1), "foo", 10, 1, 10, 2);
// This starts earlier in "foo", so the expansion should get its counter.
@@ -334,7 +360,7 @@ TEST_P(MaybeSparseCoverageMappingTest, expansion_gets_first_counter) {
ASSERT_EQ(3U, Output.Regions[2].LineStart);
}
-TEST_P(MaybeSparseCoverageMappingTest, basic_coverage_iteration) {
+TEST_P(CoverageMappingTest, basic_coverage_iteration) {
InstrProfRecord Record("func", 0x1234, {30, 20, 10, 0});
NoError(ProfileWriter.addRecord(std::move(Record)));
@@ -357,7 +383,7 @@ TEST_P(MaybeSparseCoverageMappingTest, basic_coverage_iteration) {
ASSERT_EQ(CoverageSegment(11, 11, false), Segments[6]);
}
-TEST_P(MaybeSparseCoverageMappingTest, uncovered_function) {
+TEST_P(CoverageMappingTest, uncovered_function) {
startFunction("func", 0x1234);
addCMR(Counter::getZero(), "file1", 1, 2, 3, 4);
loadCoverageMapping();
@@ -369,7 +395,7 @@ TEST_P(MaybeSparseCoverageMappingTest, uncovered_function) {
ASSERT_EQ(CoverageSegment(3, 4, false), Segments[1]);
}
-TEST_P(MaybeSparseCoverageMappingTest, uncovered_function_with_mapping) {
+TEST_P(CoverageMappingTest, uncovered_function_with_mapping) {
startFunction("func", 0x1234);
addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9);
addCMR(Counter::getCounter(1), "file1", 1, 1, 4, 7);
@@ -383,7 +409,7 @@ TEST_P(MaybeSparseCoverageMappingTest, uncovered_function_with_mapping) {
ASSERT_EQ(CoverageSegment(9, 9, false), Segments[2]);
}
-TEST_P(MaybeSparseCoverageMappingTest, combine_regions) {
+TEST_P(CoverageMappingTest, combine_regions) {
InstrProfRecord Record("func", 0x1234, {10, 20, 30});
NoError(ProfileWriter.addRecord(std::move(Record)));
@@ -402,8 +428,7 @@ TEST_P(MaybeSparseCoverageMappingTest, combine_regions) {
ASSERT_EQ(CoverageSegment(9, 9, false), Segments[3]);
}
-TEST_P(MaybeSparseCoverageMappingTest,
- restore_combined_counter_after_nested_region) {
+TEST_P(CoverageMappingTest, restore_combined_counter_after_nested_region) {
InstrProfRecord Record("func", 0x1234, {10, 20, 40});
NoError(ProfileWriter.addRecord(std::move(Record)));
@@ -424,7 +449,7 @@ TEST_P(MaybeSparseCoverageMappingTest,
// If CodeRegions and ExpansionRegions cover the same area,
// only counts of CodeRegions should be used.
-TEST_P(MaybeSparseCoverageMappingTest, dont_combine_expansions) {
+TEST_P(CoverageMappingTest, dont_combine_expansions) {
InstrProfRecord Record1("func", 0x1234, {10, 20});
InstrProfRecord Record2("func", 0x1234, {0, 0});
NoError(ProfileWriter.addRecord(std::move(Record1)));
@@ -447,7 +472,7 @@ TEST_P(MaybeSparseCoverageMappingTest, dont_combine_expansions) {
}
// If an area is covered only by ExpansionRegions, they should be combinated.
-TEST_P(MaybeSparseCoverageMappingTest, combine_expansions) {
+TEST_P(CoverageMappingTest, combine_expansions) {
InstrProfRecord Record("func", 0x1234, {2, 3, 7});
NoError(ProfileWriter.addRecord(std::move(Record)));
@@ -469,7 +494,7 @@ TEST_P(MaybeSparseCoverageMappingTest, combine_expansions) {
EXPECT_EQ(CoverageSegment(5, 5, false), Segments[3]);
}
-TEST_P(MaybeSparseCoverageMappingTest, strip_filename_prefix) {
+TEST_P(CoverageMappingTest, strip_filename_prefix) {
InstrProfRecord Record("file1:func", 0x1234, {0});
NoError(ProfileWriter.addRecord(std::move(Record)));
@@ -484,7 +509,7 @@ TEST_P(MaybeSparseCoverageMappingTest, strip_filename_prefix) {
ASSERT_EQ("func", Names[0]);
}
-TEST_P(MaybeSparseCoverageMappingTest, strip_unknown_filename_prefix) {
+TEST_P(CoverageMappingTest, strip_unknown_filename_prefix) {
InstrProfRecord Record("<unknown>:func", 0x1234, {0});
NoError(ProfileWriter.addRecord(std::move(Record)));
@@ -499,7 +524,7 @@ TEST_P(MaybeSparseCoverageMappingTest, strip_unknown_filename_prefix) {
ASSERT_EQ("func", Names[0]);
}
-TEST_P(MaybeSparseCoverageMappingTest, dont_detect_false_instantiations) {
+TEST_P(CoverageMappingTest, dont_detect_false_instantiations) {
InstrProfRecord Record1("foo", 0x1234, {10});
InstrProfRecord Record2("bar", 0x2345, {20});
NoError(ProfileWriter.addRecord(std::move(Record1)));
@@ -520,7 +545,7 @@ TEST_P(MaybeSparseCoverageMappingTest, dont_detect_false_instantiations) {
ASSERT_TRUE(Instantiations.empty());
}
-TEST_P(MaybeSparseCoverageMappingTest, load_coverage_for_expanded_file) {
+TEST_P(CoverageMappingTest, load_coverage_for_expanded_file) {
InstrProfRecord Record("func", 0x1234, {10});
NoError(ProfileWriter.addRecord(std::move(Record)));
@@ -537,7 +562,28 @@ TEST_P(MaybeSparseCoverageMappingTest, load_coverage_for_expanded_file) {
EXPECT_EQ(CoverageSegment(1, 10, false), Segments[1]);
}
-INSTANTIATE_TEST_CASE_P(MaybeSparse, MaybeSparseCoverageMappingTest,
- ::testing::Bool());
+TEST_P(CoverageMappingTest, skip_duplicate_function_record) {
+ InstrProfRecord Record("func", 0x1234, {1});
+ NoError(ProfileWriter.addRecord(std::move(Record)));
+
+ startFunction("func", 0x1234);
+ addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9);
+
+ startFunction("func", 0x1234);
+ addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9);
+
+ loadCoverageMapping();
+
+ auto Funcs = LoadedCoverage->getCoveredFunctions();
+ unsigned NumFuncs = std::distance(Funcs.begin(), Funcs.end());
+ ASSERT_EQ(1U, NumFuncs);
+}
+
+// FIXME: Use ::testing::Combine() when llvm updates its copy of googletest.
+INSTANTIATE_TEST_CASE_P(ParameterizedCovMapTest, CoverageMappingTest,
+ ::testing::Values(std::pair<bool, bool>({false, false}),
+ std::pair<bool, bool>({false, true}),
+ std::pair<bool, bool>({true, false}),
+ std::pair<bool, bool>({true, true})));
} // end anonymous namespace
diff --git a/unittests/ProfileData/InstrProfTest.cpp b/unittests/ProfileData/InstrProfTest.cpp
index c13f31251de4..1b44463cd650 100644
--- a/unittests/ProfileData/InstrProfTest.cpp
+++ b/unittests/ProfileData/InstrProfTest.cpp
@@ -167,15 +167,13 @@ TEST_F(InstrProfTest, get_profile_summary) {
auto Predicate = [&Cutoff](const ProfileSummaryEntry &PE) {
return PE.Cutoff == Cutoff;
};
- auto EightyPerc = std::find_if(Details.begin(), Details.end(), Predicate);
+ auto EightyPerc = find_if(Details, Predicate);
Cutoff = 900000;
- auto NinetyPerc = std::find_if(Details.begin(), Details.end(), Predicate);
+ auto NinetyPerc = find_if(Details, Predicate);
Cutoff = 950000;
- auto NinetyFivePerc =
- std::find_if(Details.begin(), Details.end(), Predicate);
+ auto NinetyFivePerc = find_if(Details, Predicate);
Cutoff = 990000;
- auto NinetyNinePerc =
- std::find_if(Details.begin(), Details.end(), Predicate);
+ auto NinetyNinePerc = find_if(Details, Predicate);
ASSERT_EQ(576460752303423488U, EightyPerc->MinCount);
ASSERT_EQ(288230376151711744U, NinetyPerc->MinCount);
ASSERT_EQ(288230376151711744U, NinetyFivePerc->MinCount);
@@ -204,6 +202,31 @@ TEST_F(InstrProfTest, get_profile_summary) {
delete PSFromMD;
}
+TEST_F(InstrProfTest, test_writer_merge) {
+ InstrProfRecord Record1("func1", 0x1234, {42});
+ NoError(Writer.addRecord(std::move(Record1)));
+
+ InstrProfWriter Writer2;
+ InstrProfRecord Record2("func2", 0x1234, {0, 0});
+ NoError(Writer2.addRecord(std::move(Record2)));
+
+ NoError(Writer.mergeRecordsFromWriter(std::move(Writer2)));
+
+ auto Profile = Writer.writeBuffer();
+ readProfile(std::move(Profile));
+
+ Expected<InstrProfRecord> R = Reader->getInstrProfRecord("func1", 0x1234);
+ ASSERT_TRUE(NoError(R.takeError()));
+ ASSERT_EQ(1U, R->Counts.size());
+ ASSERT_EQ(42U, R->Counts[0]);
+
+ R = Reader->getInstrProfRecord("func2", 0x1234);
+ ASSERT_TRUE(NoError(R.takeError()));
+ ASSERT_EQ(2U, R->Counts.size());
+ ASSERT_EQ(0U, R->Counts[0]);
+ ASSERT_EQ(0U, R->Counts[1]);
+}
+
static const char callee1[] = "callee1";
static const char callee2[] = "callee2";
static const char callee3[] = "callee3";
diff --git a/unittests/ProfileData/SampleProfTest.cpp b/unittests/ProfileData/SampleProfTest.cpp
index 175852b93fb2..96b2a01c7bd7 100644
--- a/unittests/ProfileData/SampleProfTest.cpp
+++ b/unittests/ProfileData/SampleProfTest.cpp
@@ -124,15 +124,13 @@ struct SampleProfTest : ::testing::Test {
return PE.Cutoff == Cutoff;
};
std::vector<ProfileSummaryEntry> &Details = Summary.getDetailedSummary();
- auto EightyPerc = std::find_if(Details.begin(), Details.end(), Predicate);
+ auto EightyPerc = find_if(Details, Predicate);
Cutoff = 900000;
- auto NinetyPerc = std::find_if(Details.begin(), Details.end(), Predicate);
+ auto NinetyPerc = find_if(Details, Predicate);
Cutoff = 950000;
- auto NinetyFivePerc =
- std::find_if(Details.begin(), Details.end(), Predicate);
+ auto NinetyFivePerc = find_if(Details, Predicate);
Cutoff = 990000;
- auto NinetyNinePerc =
- std::find_if(Details.begin(), Details.end(), Predicate);
+ auto NinetyNinePerc = find_if(Details, Predicate);
ASSERT_EQ(60000u, EightyPerc->MinCount);
ASSERT_EQ(60000u, NinetyPerc->MinCount);
ASSERT_EQ(60000u, NinetyFivePerc->MinCount);
diff --git a/unittests/Support/AlignOfTest.cpp b/unittests/Support/AlignOfTest.cpp
index 74b03f0e7dfd..388ca11b7769 100644
--- a/unittests/Support/AlignOfTest.cpp
+++ b/unittests/Support/AlignOfTest.cpp
@@ -89,140 +89,33 @@ V6::~V6() {}
V7::~V7() {}
V8::~V8() {}
-struct Abstract1 {
- virtual ~Abstract1() {}
- virtual void method() = 0;
-
- char c;
-};
-
-struct Abstract2 : Abstract1 {
- ~Abstract2() override = default;
- double d;
-};
-
-struct Final final : Abstract2 {
- void method() override {}
-};
-
-// Ensure alignment is a compile-time constant.
-char LLVM_ATTRIBUTE_UNUSED test_arr1
- [AlignOf<char>::Alignment > 0]
- [AlignOf<short>::Alignment > 0]
- [AlignOf<int>::Alignment > 0]
- [AlignOf<long>::Alignment > 0]
- [AlignOf<long long>::Alignment > 0]
- [AlignOf<float>::Alignment > 0]
- [AlignOf<double>::Alignment > 0]
- [AlignOf<long double>::Alignment > 0]
- [AlignOf<void *>::Alignment > 0]
- [AlignOf<int *>::Alignment > 0]
- [AlignOf<double (*)(double)>::Alignment > 0]
- [AlignOf<double (S6::*)()>::Alignment > 0];
-char LLVM_ATTRIBUTE_UNUSED test_arr2
- [AlignOf<A1>::Alignment > 0]
- [AlignOf<A2>::Alignment > 0]
- [AlignOf<A4>::Alignment > 0]
- [AlignOf<A8>::Alignment > 0];
-char LLVM_ATTRIBUTE_UNUSED test_arr3
- [AlignOf<S1>::Alignment > 0]
- [AlignOf<S2>::Alignment > 0]
- [AlignOf<S3>::Alignment > 0]
- [AlignOf<S4>::Alignment > 0]
- [AlignOf<S5>::Alignment > 0]
- [AlignOf<S6>::Alignment > 0];
-char LLVM_ATTRIBUTE_UNUSED test_arr4
- [AlignOf<D1>::Alignment > 0]
- [AlignOf<D2>::Alignment > 0]
- [AlignOf<D3>::Alignment > 0]
- [AlignOf<D4>::Alignment > 0]
- [AlignOf<D5>::Alignment > 0]
- [AlignOf<D6>::Alignment > 0]
- [AlignOf<D7>::Alignment > 0]
- [AlignOf<D8>::Alignment > 0]
- [AlignOf<D9>::Alignment > 0];
-char LLVM_ATTRIBUTE_UNUSED test_arr5
- [AlignOf<V1>::Alignment > 0]
- [AlignOf<V2>::Alignment > 0]
- [AlignOf<V3>::Alignment > 0]
- [AlignOf<V4>::Alignment > 0]
- [AlignOf<V5>::Alignment > 0]
- [AlignOf<V6>::Alignment > 0]
- [AlignOf<V7>::Alignment > 0]
- [AlignOf<V8>::Alignment > 0];
-
-TEST(AlignOfTest, BasicAlignmentInvariants) {
- EXPECT_LE(1u, alignOf<A1>());
- EXPECT_LE(2u, alignOf<A2>());
- EXPECT_LE(4u, alignOf<A4>());
- EXPECT_LE(8u, alignOf<A8>());
-
- EXPECT_EQ(1u, alignOf<char>());
- EXPECT_LE(alignOf<char>(), alignOf<short>());
- EXPECT_LE(alignOf<short>(), alignOf<int>());
- EXPECT_LE(alignOf<int>(), alignOf<long>());
- EXPECT_LE(alignOf<long>(), alignOf<long long>());
- EXPECT_LE(alignOf<char>(), alignOf<float>());
- EXPECT_LE(alignOf<float>(), alignOf<double>());
- EXPECT_LE(alignOf<char>(), alignOf<long double>());
- EXPECT_LE(alignOf<char>(), alignOf<void *>());
- EXPECT_EQ(alignOf<void *>(), alignOf<int *>());
- EXPECT_LE(alignOf<char>(), alignOf<S1>());
- EXPECT_LE(alignOf<S1>(), alignOf<S2>());
- EXPECT_LE(alignOf<S1>(), alignOf<S3>());
- EXPECT_LE(alignOf<S1>(), alignOf<S4>());
- EXPECT_LE(alignOf<S1>(), alignOf<S5>());
- EXPECT_LE(alignOf<S1>(), alignOf<S6>());
- EXPECT_LE(alignOf<S1>(), alignOf<D1>());
- EXPECT_LE(alignOf<S1>(), alignOf<D2>());
- EXPECT_LE(alignOf<S1>(), alignOf<D3>());
- EXPECT_LE(alignOf<S1>(), alignOf<D4>());
- EXPECT_LE(alignOf<S1>(), alignOf<D5>());
- EXPECT_LE(alignOf<S1>(), alignOf<D6>());
- EXPECT_LE(alignOf<S1>(), alignOf<D7>());
- EXPECT_LE(alignOf<S1>(), alignOf<D8>());
- EXPECT_LE(alignOf<S1>(), alignOf<D9>());
- EXPECT_LE(alignOf<S1>(), alignOf<V1>());
- EXPECT_LE(alignOf<V1>(), alignOf<V2>());
- EXPECT_LE(alignOf<V1>(), alignOf<V3>());
- EXPECT_LE(alignOf<V1>(), alignOf<V4>());
- EXPECT_LE(alignOf<V1>(), alignOf<V5>());
- EXPECT_LE(alignOf<V1>(), alignOf<V6>());
- EXPECT_LE(alignOf<V1>(), alignOf<V7>());
- EXPECT_LE(alignOf<V1>(), alignOf<V8>());
-
- EXPECT_LE(alignOf<char>(), alignOf<Abstract1>());
- EXPECT_LE(alignOf<double>(), alignOf<Abstract2>());
- EXPECT_LE(alignOf<Abstract2>(), alignOf<Final>());
-}
+template <typename M> struct T { M m; };
TEST(AlignOfTest, BasicAlignedArray) {
- EXPECT_LE(1u, alignOf<AlignedCharArrayUnion<A1> >());
- EXPECT_LE(2u, alignOf<AlignedCharArrayUnion<A2> >());
- EXPECT_LE(4u, alignOf<AlignedCharArrayUnion<A4> >());
- EXPECT_LE(8u, alignOf<AlignedCharArrayUnion<A8> >());
+ EXPECT_LE(1u, alignof(AlignedCharArrayUnion<A1>));
+ EXPECT_LE(2u, alignof(AlignedCharArrayUnion<A2>));
+ EXPECT_LE(4u, alignof(AlignedCharArrayUnion<A4>));
+ EXPECT_LE(8u, alignof(AlignedCharArrayUnion<A8>));
EXPECT_LE(1u, sizeof(AlignedCharArrayUnion<A1>));
EXPECT_LE(2u, sizeof(AlignedCharArrayUnion<A2>));
EXPECT_LE(4u, sizeof(AlignedCharArrayUnion<A4>));
EXPECT_LE(8u, sizeof(AlignedCharArrayUnion<A8>));
- EXPECT_EQ(1u, (alignOf<AlignedCharArrayUnion<A1> >()));
- EXPECT_EQ(2u, (alignOf<AlignedCharArrayUnion<A1, A2> >()));
- EXPECT_EQ(4u, (alignOf<AlignedCharArrayUnion<A1, A2, A4> >()));
- EXPECT_EQ(8u, (alignOf<AlignedCharArrayUnion<A1, A2, A4, A8> >()));
+ EXPECT_EQ(1u, (alignof(AlignedCharArrayUnion<A1>)));
+ EXPECT_EQ(2u, (alignof(AlignedCharArrayUnion<A1, A2>)));
+ EXPECT_EQ(4u, (alignof(AlignedCharArrayUnion<A1, A2, A4>)));
+ EXPECT_EQ(8u, (alignof(AlignedCharArrayUnion<A1, A2, A4, A8>)));
EXPECT_EQ(1u, sizeof(AlignedCharArrayUnion<A1>));
EXPECT_EQ(2u, sizeof(AlignedCharArrayUnion<A1, A2>));
EXPECT_EQ(4u, sizeof(AlignedCharArrayUnion<A1, A2, A4>));
EXPECT_EQ(8u, sizeof(AlignedCharArrayUnion<A1, A2, A4, A8>));
- EXPECT_EQ(1u, (alignOf<AlignedCharArrayUnion<A1[1]> >()));
- EXPECT_EQ(2u, (alignOf<AlignedCharArrayUnion<A1[2], A2[1]> >()));
- EXPECT_EQ(4u, (alignOf<AlignedCharArrayUnion<A1[42], A2[55],
- A4[13]> >()));
- EXPECT_EQ(8u, (alignOf<AlignedCharArrayUnion<A1[2], A2[1],
- A4, A8> >()));
+ EXPECT_EQ(1u, (alignof(AlignedCharArrayUnion<A1[1]>)));
+ EXPECT_EQ(2u, (alignof(AlignedCharArrayUnion<A1[2], A2[1]>)));
+ EXPECT_EQ(4u, (alignof(AlignedCharArrayUnion<A1[42], A2[55], A4[13]>)));
+ EXPECT_EQ(8u, (alignof(AlignedCharArrayUnion<A1[2], A2[1], A4, A8>)));
EXPECT_EQ(1u, sizeof(AlignedCharArrayUnion<A1[1]>));
EXPECT_EQ(2u, sizeof(AlignedCharArrayUnion<A1[2], A2[1]>));
@@ -233,49 +126,48 @@ TEST(AlignOfTest, BasicAlignedArray) {
// For other tests we simply assert that the alignment of the union mathes
// that of the fundamental type and hope that we have any weird type
// productions that would trigger bugs.
- EXPECT_EQ(alignOf<char>(), alignOf<AlignedCharArrayUnion<char> >());
- EXPECT_EQ(alignOf<short>(), alignOf<AlignedCharArrayUnion<short> >());
- EXPECT_EQ(alignOf<int>(), alignOf<AlignedCharArrayUnion<int> >());
- EXPECT_EQ(alignOf<long>(), alignOf<AlignedCharArrayUnion<long> >());
- EXPECT_EQ(alignOf<long long>(),
- alignOf<AlignedCharArrayUnion<long long> >());
- EXPECT_EQ(alignOf<float>(), alignOf<AlignedCharArrayUnion<float> >());
- EXPECT_EQ(alignOf<double>(), alignOf<AlignedCharArrayUnion<double> >());
- EXPECT_EQ(alignOf<long double>(),
- alignOf<AlignedCharArrayUnion<long double> >());
- EXPECT_EQ(alignOf<void *>(), alignOf<AlignedCharArrayUnion<void *> >());
- EXPECT_EQ(alignOf<int *>(), alignOf<AlignedCharArrayUnion<int *> >());
- EXPECT_EQ(alignOf<double (*)(double)>(),
- alignOf<AlignedCharArrayUnion<double (*)(double)> >());
- EXPECT_EQ(alignOf<double (S6::*)()>(),
- alignOf<AlignedCharArrayUnion<double (S6::*)()> >());
- EXPECT_EQ(alignOf<S1>(), alignOf<AlignedCharArrayUnion<S1> >());
- EXPECT_EQ(alignOf<S2>(), alignOf<AlignedCharArrayUnion<S2> >());
- EXPECT_EQ(alignOf<S3>(), alignOf<AlignedCharArrayUnion<S3> >());
- EXPECT_EQ(alignOf<S4>(), alignOf<AlignedCharArrayUnion<S4> >());
- EXPECT_EQ(alignOf<S5>(), alignOf<AlignedCharArrayUnion<S5> >());
- EXPECT_EQ(alignOf<S6>(), alignOf<AlignedCharArrayUnion<S6> >());
- EXPECT_EQ(alignOf<D1>(), alignOf<AlignedCharArrayUnion<D1> >());
- EXPECT_EQ(alignOf<D2>(), alignOf<AlignedCharArrayUnion<D2> >());
- EXPECT_EQ(alignOf<D3>(), alignOf<AlignedCharArrayUnion<D3> >());
- EXPECT_EQ(alignOf<D4>(), alignOf<AlignedCharArrayUnion<D4> >());
- EXPECT_EQ(alignOf<D5>(), alignOf<AlignedCharArrayUnion<D5> >());
- EXPECT_EQ(alignOf<D6>(), alignOf<AlignedCharArrayUnion<D6> >());
- EXPECT_EQ(alignOf<D7>(), alignOf<AlignedCharArrayUnion<D7> >());
- EXPECT_EQ(alignOf<D8>(), alignOf<AlignedCharArrayUnion<D8> >());
- EXPECT_EQ(alignOf<D9>(), alignOf<AlignedCharArrayUnion<D9> >());
- EXPECT_EQ(alignOf<V1>(), alignOf<AlignedCharArrayUnion<V1> >());
- EXPECT_EQ(alignOf<V2>(), alignOf<AlignedCharArrayUnion<V2> >());
- EXPECT_EQ(alignOf<V3>(), alignOf<AlignedCharArrayUnion<V3> >());
- EXPECT_EQ(alignOf<V4>(), alignOf<AlignedCharArrayUnion<V4> >());
- EXPECT_EQ(alignOf<V5>(), alignOf<AlignedCharArrayUnion<V5> >());
- EXPECT_EQ(alignOf<V6>(), alignOf<AlignedCharArrayUnion<V6> >());
- EXPECT_EQ(alignOf<V7>(), alignOf<AlignedCharArrayUnion<V7> >());
+ EXPECT_EQ(alignof(T<char>), alignof(AlignedCharArrayUnion<char>));
+ EXPECT_EQ(alignof(T<short>), alignof(AlignedCharArrayUnion<short>));
+ EXPECT_EQ(alignof(T<int>), alignof(AlignedCharArrayUnion<int>));
+ EXPECT_EQ(alignof(T<long>), alignof(AlignedCharArrayUnion<long>));
+ EXPECT_EQ(alignof(T<long long>), alignof(AlignedCharArrayUnion<long long>));
+ EXPECT_EQ(alignof(T<float>), alignof(AlignedCharArrayUnion<float>));
+ EXPECT_EQ(alignof(T<double>), alignof(AlignedCharArrayUnion<double>));
+ EXPECT_EQ(alignof(T<long double>),
+ alignof(AlignedCharArrayUnion<long double>));
+ EXPECT_EQ(alignof(T<void *>), alignof(AlignedCharArrayUnion<void *>));
+ EXPECT_EQ(alignof(T<int *>), alignof(AlignedCharArrayUnion<int *>));
+ EXPECT_EQ(alignof(T<double (*)(double)>),
+ alignof(AlignedCharArrayUnion<double (*)(double)>));
+ EXPECT_EQ(alignof(T<double (S6::*)()>),
+ alignof(AlignedCharArrayUnion<double (S6::*)()>));
+ EXPECT_EQ(alignof(S1), alignof(AlignedCharArrayUnion<S1>));
+ EXPECT_EQ(alignof(S2), alignof(AlignedCharArrayUnion<S2>));
+ EXPECT_EQ(alignof(S3), alignof(AlignedCharArrayUnion<S3>));
+ EXPECT_EQ(alignof(S4), alignof(AlignedCharArrayUnion<S4>));
+ EXPECT_EQ(alignof(S5), alignof(AlignedCharArrayUnion<S5>));
+ EXPECT_EQ(alignof(S6), alignof(AlignedCharArrayUnion<S6>));
+ EXPECT_EQ(alignof(D1), alignof(AlignedCharArrayUnion<D1>));
+ EXPECT_EQ(alignof(D2), alignof(AlignedCharArrayUnion<D2>));
+ EXPECT_EQ(alignof(D3), alignof(AlignedCharArrayUnion<D3>));
+ EXPECT_EQ(alignof(D4), alignof(AlignedCharArrayUnion<D4>));
+ EXPECT_EQ(alignof(D5), alignof(AlignedCharArrayUnion<D5>));
+ EXPECT_EQ(alignof(D6), alignof(AlignedCharArrayUnion<D6>));
+ EXPECT_EQ(alignof(D7), alignof(AlignedCharArrayUnion<D7>));
+ EXPECT_EQ(alignof(D8), alignof(AlignedCharArrayUnion<D8>));
+ EXPECT_EQ(alignof(D9), alignof(AlignedCharArrayUnion<D9>));
+ EXPECT_EQ(alignof(V1), alignof(AlignedCharArrayUnion<V1>));
+ EXPECT_EQ(alignof(V2), alignof(AlignedCharArrayUnion<V2>));
+ EXPECT_EQ(alignof(V3), alignof(AlignedCharArrayUnion<V3>));
+ EXPECT_EQ(alignof(V4), alignof(AlignedCharArrayUnion<V4>));
+ EXPECT_EQ(alignof(V5), alignof(AlignedCharArrayUnion<V5>));
+ EXPECT_EQ(alignof(V6), alignof(AlignedCharArrayUnion<V6>));
+ EXPECT_EQ(alignof(V7), alignof(AlignedCharArrayUnion<V7>));
// Some versions of MSVC get this wrong somewhat disturbingly. The failure
- // appears to be benign: alignOf<V8>() produces a preposterous value: 12
+ // appears to be benign: alignof(V8) produces a preposterous value: 12
#ifndef _MSC_VER
- EXPECT_EQ(alignOf<V8>(), alignOf<AlignedCharArrayUnion<V8> >());
+ EXPECT_EQ(alignof(V8), alignof(AlignedCharArrayUnion<V8>));
#endif
EXPECT_EQ(sizeof(char), sizeof(AlignedCharArrayUnion<char>));
@@ -343,11 +235,11 @@ TEST(AlignOfTest, BasicAlignedArray) {
EXPECT_EQ(sizeof(V8), sizeof(AlignedCharArrayUnion<V8>));
#endif
- EXPECT_EQ(1u, (alignOf<AlignedCharArray<1, 1> >()));
- EXPECT_EQ(2u, (alignOf<AlignedCharArray<2, 1> >()));
- EXPECT_EQ(4u, (alignOf<AlignedCharArray<4, 1> >()));
- EXPECT_EQ(8u, (alignOf<AlignedCharArray<8, 1> >()));
- EXPECT_EQ(16u, (alignOf<AlignedCharArray<16, 1> >()));
+ EXPECT_EQ(1u, (alignof(AlignedCharArray<1, 1>)));
+ EXPECT_EQ(2u, (alignof(AlignedCharArray<2, 1>)));
+ EXPECT_EQ(4u, (alignof(AlignedCharArray<4, 1>)));
+ EXPECT_EQ(8u, (alignof(AlignedCharArray<8, 1>)));
+ EXPECT_EQ(16u, (alignof(AlignedCharArray<16, 1>)));
EXPECT_EQ(1u, sizeof(AlignedCharArray<1, 1>));
EXPECT_EQ(7u, sizeof(AlignedCharArray<1, 7>));
diff --git a/unittests/Support/CMakeLists.txt b/unittests/Support/CMakeLists.txt
index 9a4a14450911..2ffedab82acb 100644
--- a/unittests/Support/CMakeLists.txt
+++ b/unittests/Support/CMakeLists.txt
@@ -9,17 +9,21 @@ add_llvm_unittest(SupportTests
BlockFrequencyTest.cpp
BranchProbabilityTest.cpp
Casting.cpp
+ Chrono.cpp
CommandLineTest.cpp
CompressionTest.cpp
ConvertUTFTest.cpp
DataExtractorTest.cpp
+ DebugTest.cpp
DwarfTest.cpp
EndianStreamTest.cpp
EndianTest.cpp
- ErrorTest.cpp
ErrorOrTest.cpp
+ ErrorTest.cpp
FileOutputBufferTest.cpp
- IteratorTest.cpp
+ FormatVariadicTest.cpp
+ GlobPatternTest.cpp
+ Host.cpp
LEB128Test.cpp
LineIteratorTest.cpp
LockFileManagerTest.cpp
@@ -28,6 +32,7 @@ add_llvm_unittest(SupportTests
MathExtrasTest.cpp
MemoryBufferTest.cpp
MemoryTest.cpp
+ NativeFormatTests.cpp
Path.cpp
ProcessTest.cpp
ProgramTest.cpp
@@ -36,16 +41,16 @@ add_llvm_unittest(SupportTests
ScaledNumberTest.cpp
SourceMgrTest.cpp
SpecialCaseListTest.cpp
- StreamingMemoryObjectTest.cpp
StringPool.cpp
SwapByteOrderTest.cpp
TargetParserTest.cpp
+ Threading.cpp
ThreadLocalTest.cpp
ThreadPool.cpp
TimerTest.cpp
- TimeValueTest.cpp
TypeNameTest.cpp
TrailingObjectsTest.cpp
+ TrigramIndexTest.cpp
UnicodeTest.cpp
YAMLIOTest.cpp
YAMLParserTest.cpp
@@ -53,6 +58,7 @@ add_llvm_unittest(SupportTests
raw_ostream_test.cpp
raw_pwrite_stream_test.cpp
raw_sha1_ostream_test.cpp
+ xxhashTest.cpp
)
# ManagedStatic.cpp uses <pthread>.
diff --git a/unittests/Support/Chrono.cpp b/unittests/Support/Chrono.cpp
new file mode 100644
index 000000000000..3d5787807563
--- /dev/null
+++ b/unittests/Support/Chrono.cpp
@@ -0,0 +1,79 @@
+//===- llvm/unittest/Support/Chrono.cpp - Time utilities tests ------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Chrono.h"
+#include "llvm/ADT/SmallVector.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace llvm::sys;
+using namespace std::chrono;
+
+namespace {
+
+TEST(Chrono, TimeTConversion) {
+ EXPECT_EQ(time_t(0), toTimeT(toTimePoint(time_t(0))));
+ EXPECT_EQ(time_t(1), toTimeT(toTimePoint(time_t(1))));
+ EXPECT_EQ(time_t(47), toTimeT(toTimePoint(time_t(47))));
+
+ TimePoint<> TP;
+ EXPECT_EQ(TP, toTimePoint(toTimeT(TP)));
+ TP += seconds(1);
+ EXPECT_EQ(TP, toTimePoint(toTimeT(TP)));
+ TP += hours(47);
+ EXPECT_EQ(TP, toTimePoint(toTimeT(TP)));
+}
+
+TEST(Chrono, StringConversion) {
+ std::string S;
+ raw_string_ostream OS(S);
+ OS << system_clock::now();
+
+ // Do a basic sanity check on the output.
+ // The format we expect is YYYY-MM-DD HH:MM:SS.MMMUUUNNN
+ StringRef Date, Time;
+ std::tie(Date, Time) = StringRef(OS.str()).split(' ');
+
+ SmallVector<StringRef, 3> Components;
+ Date.split(Components, '-');
+ ASSERT_EQ(3u, Components.size());
+ EXPECT_EQ(4u, Components[0].size());
+ EXPECT_EQ(2u, Components[1].size());
+ EXPECT_EQ(2u, Components[2].size());
+
+ StringRef Sec, Nano;
+ std::tie(Sec, Nano) = Time.split('.');
+
+ Components.clear();
+ Sec.split(Components, ':');
+ ASSERT_EQ(3u, Components.size());
+ EXPECT_EQ(2u, Components[0].size());
+ EXPECT_EQ(2u, Components[1].size());
+ EXPECT_EQ(2u, Components[2].size());
+ EXPECT_EQ(9u, Nano.size());
+}
+
+// Test that toTimePoint and toTimeT can be called with a arguments with varying
+// precisions.
+TEST(Chrono, ImplicitConversions) {
+ std::time_t TimeT = 47;
+ TimePoint<seconds> Sec = toTimePoint(TimeT);
+ TimePoint<milliseconds> Milli = toTimePoint(TimeT);
+ TimePoint<microseconds> Micro = toTimePoint(TimeT);
+ TimePoint<nanoseconds> Nano = toTimePoint(TimeT);
+ EXPECT_EQ(Sec, Milli);
+ EXPECT_EQ(Sec, Micro);
+ EXPECT_EQ(Sec, Nano);
+ EXPECT_EQ(TimeT, toTimeT(Sec));
+ EXPECT_EQ(TimeT, toTimeT(Milli));
+ EXPECT_EQ(TimeT, toTimeT(Micro));
+ EXPECT_EQ(TimeT, toTimeT(Nano));
+}
+
+} // anonymous namespace
diff --git a/unittests/Support/CommandLineTest.cpp b/unittests/Support/CommandLineTest.cpp
index 9b24c1e40bca..945eb1d4e1cf 100644
--- a/unittests/Support/CommandLineTest.cpp
+++ b/unittests/Support/CommandLineTest.cpp
@@ -7,11 +7,15 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Config/config.h"
#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/StringSaver.h"
#include "gtest/gtest.h"
+#include <fstream>
#include <stdlib.h>
#include <string>
@@ -76,8 +80,8 @@ public:
class StackSubCommand : public cl::SubCommand {
public:
- StackSubCommand(const char *const Name,
- const char *const Description = nullptr)
+ StackSubCommand(StringRef Name,
+ StringRef Description = StringRef())
: SubCommand(Name, Description) {}
StackSubCommand() : SubCommand() {}
@@ -168,7 +172,7 @@ typedef void ParserFunction(StringRef Source, StringSaver &Saver,
SmallVectorImpl<const char *> &NewArgv,
bool MarkEOLs);
-void testCommandLineTokenizer(ParserFunction *parse, const char *Input,
+void testCommandLineTokenizer(ParserFunction *parse, StringRef Input,
const char *const Output[], size_t OutputSize) {
SmallVector<const char *, 0> Actual;
BumpPtrAllocator A;
@@ -182,7 +186,7 @@ void testCommandLineTokenizer(ParserFunction *parse, const char *Input,
}
TEST(CommandLineTest, TokenizeGNUCommandLine) {
- const char *Input =
+ const char Input[] =
"foo\\ bar \"foo bar\" \'foo bar\' 'foo\\\\bar' -DFOO=bar\\(\\) "
"foo\"bar\"baz C:\\\\src\\\\foo.cpp \"C:\\src\\foo.cpp\"";
const char *const Output[] = {
@@ -193,7 +197,7 @@ TEST(CommandLineTest, TokenizeGNUCommandLine) {
}
TEST(CommandLineTest, TokenizeWindowsCommandLine) {
- const char *Input = "a\\b c\\\\d e\\\\\"f g\" h\\\"i j\\\\\\\"k \"lmn\" o pqr "
+ const char Input[] = "a\\b c\\\\d e\\\\\"f g\" h\\\"i j\\\\\\\"k \"lmn\" o pqr "
"\"st \\\"u\" \\v";
const char *const Output[] = { "a\\b", "c\\\\d", "e\\f g", "h\"i", "j\\\"k",
"lmn", "o", "pqr", "st \"u", "\\v" };
@@ -299,7 +303,7 @@ TEST(CommandLineTest, SetValueInSubcategories) {
EXPECT_FALSE(SC1Opt);
EXPECT_FALSE(SC2Opt);
const char *args[] = {"prog", "-top-level"};
- EXPECT_TRUE(cl::ParseCommandLineOptions(2, args, nullptr, true));
+ EXPECT_TRUE(cl::ParseCommandLineOptions(2, args, StringRef(), true));
EXPECT_TRUE(TopLevelOpt);
EXPECT_FALSE(SC1Opt);
EXPECT_FALSE(SC2Opt);
@@ -311,7 +315,7 @@ TEST(CommandLineTest, SetValueInSubcategories) {
EXPECT_FALSE(SC1Opt);
EXPECT_FALSE(SC2Opt);
const char *args2[] = {"prog", "sc1", "-sc1"};
- EXPECT_TRUE(cl::ParseCommandLineOptions(3, args2, nullptr, true));
+ EXPECT_TRUE(cl::ParseCommandLineOptions(3, args2, StringRef(), true));
EXPECT_FALSE(TopLevelOpt);
EXPECT_TRUE(SC1Opt);
EXPECT_FALSE(SC2Opt);
@@ -323,7 +327,7 @@ TEST(CommandLineTest, SetValueInSubcategories) {
EXPECT_FALSE(SC1Opt);
EXPECT_FALSE(SC2Opt);
const char *args3[] = {"prog", "sc2", "-sc2"};
- EXPECT_TRUE(cl::ParseCommandLineOptions(3, args3, nullptr, true));
+ EXPECT_TRUE(cl::ParseCommandLineOptions(3, args3, StringRef(), true));
EXPECT_FALSE(TopLevelOpt);
EXPECT_FALSE(SC1Opt);
EXPECT_TRUE(SC2Opt);
@@ -339,7 +343,7 @@ TEST(CommandLineTest, LookupFailsInWrongSubCommand) {
StackOption<bool> SC2Opt("sc2", cl::sub(SC2), cl::init(false));
const char *args[] = {"prog", "sc1", "-sc2"};
- EXPECT_FALSE(cl::ParseCommandLineOptions(3, args, nullptr, true));
+ EXPECT_FALSE(cl::ParseCommandLineOptions(3, args, StringRef(), true));
}
TEST(CommandLineTest, AddToAllSubCommands) {
@@ -355,21 +359,21 @@ TEST(CommandLineTest, AddToAllSubCommands) {
const char *args3[] = {"prog", "sc2", "-everywhere"};
EXPECT_FALSE(AllOpt);
- EXPECT_TRUE(cl::ParseCommandLineOptions(2, args, nullptr, true));
+ EXPECT_TRUE(cl::ParseCommandLineOptions(2, args, StringRef(), true));
EXPECT_TRUE(AllOpt);
AllOpt = false;
cl::ResetAllOptionOccurrences();
EXPECT_FALSE(AllOpt);
- EXPECT_TRUE(cl::ParseCommandLineOptions(3, args2, nullptr, true));
+ EXPECT_TRUE(cl::ParseCommandLineOptions(3, args2, StringRef(), true));
EXPECT_TRUE(AllOpt);
AllOpt = false;
cl::ResetAllOptionOccurrences();
EXPECT_FALSE(AllOpt);
- EXPECT_TRUE(cl::ParseCommandLineOptions(3, args3, nullptr, true));
+ EXPECT_TRUE(cl::ParseCommandLineOptions(3, args3, StringRef(), true));
EXPECT_TRUE(AllOpt);
}
@@ -382,14 +386,14 @@ TEST(CommandLineTest, ReparseCommandLineOptions) {
const char *args[] = {"prog", "-top-level"};
EXPECT_FALSE(TopLevelOpt);
- EXPECT_TRUE(cl::ParseCommandLineOptions(2, args, nullptr, true));
+ EXPECT_TRUE(cl::ParseCommandLineOptions(2, args, StringRef(), true));
EXPECT_TRUE(TopLevelOpt);
TopLevelOpt = false;
cl::ResetAllOptionOccurrences();
EXPECT_FALSE(TopLevelOpt);
- EXPECT_TRUE(cl::ParseCommandLineOptions(2, args, nullptr, true));
+ EXPECT_TRUE(cl::ParseCommandLineOptions(2, args, StringRef(), true));
EXPECT_TRUE(TopLevelOpt);
}
@@ -403,13 +407,13 @@ TEST(CommandLineTest, RemoveFromRegularSubCommand) {
const char *args[] = {"prog", "sc", "-remove-option"};
EXPECT_FALSE(RemoveOption);
- EXPECT_TRUE(cl::ParseCommandLineOptions(3, args, nullptr, true));
+ EXPECT_TRUE(cl::ParseCommandLineOptions(3, args, StringRef(), true));
EXPECT_TRUE(RemoveOption);
RemoveOption.removeArgument();
cl::ResetAllOptionOccurrences();
- EXPECT_FALSE(cl::ParseCommandLineOptions(3, args, nullptr, true));
+ EXPECT_FALSE(cl::ParseCommandLineOptions(3, args, StringRef(), true));
}
TEST(CommandLineTest, RemoveFromTopLevelSubCommand) {
@@ -423,13 +427,13 @@ TEST(CommandLineTest, RemoveFromTopLevelSubCommand) {
const char *args[] = {"prog", "-top-level-remove"};
EXPECT_FALSE(TopLevelRemove);
- EXPECT_TRUE(cl::ParseCommandLineOptions(2, args, nullptr, true));
+ EXPECT_TRUE(cl::ParseCommandLineOptions(2, args, StringRef(), true));
EXPECT_TRUE(TopLevelRemove);
TopLevelRemove.removeArgument();
cl::ResetAllOptionOccurrences();
- EXPECT_FALSE(cl::ParseCommandLineOptions(2, args, nullptr, true));
+ EXPECT_FALSE(cl::ParseCommandLineOptions(2, args, StringRef(), true));
}
TEST(CommandLineTest, RemoveFromAllSubCommands) {
@@ -448,32 +452,122 @@ TEST(CommandLineTest, RemoveFromAllSubCommands) {
// It should work for all subcommands including the top-level.
EXPECT_FALSE(RemoveOption);
- EXPECT_TRUE(cl::ParseCommandLineOptions(2, args0, nullptr, true));
+ EXPECT_TRUE(cl::ParseCommandLineOptions(2, args0, StringRef(), true));
EXPECT_TRUE(RemoveOption);
RemoveOption = false;
cl::ResetAllOptionOccurrences();
EXPECT_FALSE(RemoveOption);
- EXPECT_TRUE(cl::ParseCommandLineOptions(3, args1, nullptr, true));
+ EXPECT_TRUE(cl::ParseCommandLineOptions(3, args1, StringRef(), true));
EXPECT_TRUE(RemoveOption);
RemoveOption = false;
cl::ResetAllOptionOccurrences();
EXPECT_FALSE(RemoveOption);
- EXPECT_TRUE(cl::ParseCommandLineOptions(3, args2, nullptr, true));
+ EXPECT_TRUE(cl::ParseCommandLineOptions(3, args2, StringRef(), true));
EXPECT_TRUE(RemoveOption);
RemoveOption.removeArgument();
// It should not work for any subcommands including the top-level.
cl::ResetAllOptionOccurrences();
- EXPECT_FALSE(cl::ParseCommandLineOptions(2, args0, nullptr, true));
+ EXPECT_FALSE(cl::ParseCommandLineOptions(2, args0, StringRef(), true));
cl::ResetAllOptionOccurrences();
- EXPECT_FALSE(cl::ParseCommandLineOptions(3, args1, nullptr, true));
+ EXPECT_FALSE(cl::ParseCommandLineOptions(3, args1, StringRef(), true));
cl::ResetAllOptionOccurrences();
- EXPECT_FALSE(cl::ParseCommandLineOptions(3, args2, nullptr, true));
+ EXPECT_FALSE(cl::ParseCommandLineOptions(3, args2, StringRef(), true));
+}
+
+TEST(CommandLineTest, GetRegisteredSubcommands) {
+ cl::ResetCommandLineParser();
+
+ StackSubCommand SC1("sc1", "First Subcommand");
+ StackOption<bool> Opt1("opt1", cl::sub(SC1), cl::init(false));
+ StackSubCommand SC2("sc2", "Second subcommand");
+ StackOption<bool> Opt2("opt2", cl::sub(SC2), cl::init(false));
+
+ const char *args0[] = {"prog", "sc1"};
+ const char *args1[] = {"prog", "sc2"};
+
+ EXPECT_TRUE(cl::ParseCommandLineOptions(2, args0, StringRef(), true));
+ EXPECT_FALSE(Opt1);
+ EXPECT_FALSE(Opt2);
+ for (auto *S : cl::getRegisteredSubcommands()) {
+ if (*S)
+ EXPECT_EQ("sc1", S->getName());
+ }
+
+ cl::ResetAllOptionOccurrences();
+ EXPECT_TRUE(cl::ParseCommandLineOptions(2, args1, StringRef(), true));
+ EXPECT_FALSE(Opt1);
+ EXPECT_FALSE(Opt2);
+ for (auto *S : cl::getRegisteredSubcommands()) {
+ if (*S)
+ EXPECT_EQ("sc2", S->getName());
+ }
+}
+
+TEST(CommandLineTest, ResponseFiles) {
+ llvm::SmallString<128> TestDir;
+ std::error_code EC =
+ llvm::sys::fs::createUniqueDirectory("unittest", TestDir);
+ EXPECT_TRUE(!EC);
+
+ // Create included response file of first level.
+ llvm::SmallString<128> IncludedFileName;
+ llvm::sys::path::append(IncludedFileName, TestDir, "resp1");
+ std::ofstream IncludedFile(IncludedFileName.c_str());
+ EXPECT_TRUE(IncludedFile.is_open());
+ IncludedFile << "-option_1 -option_2\n"
+ "@incdir/resp2\n"
+ "-option_3=abcd\n";
+ IncludedFile.close();
+
+ // Directory for included file.
+ llvm::SmallString<128> IncDir;
+ llvm::sys::path::append(IncDir, TestDir, "incdir");
+ EC = llvm::sys::fs::create_directory(IncDir);
+ EXPECT_TRUE(!EC);
+
+ // Create included response file of second level.
+ llvm::SmallString<128> IncludedFileName2;
+ llvm::sys::path::append(IncludedFileName2, IncDir, "resp2");
+ std::ofstream IncludedFile2(IncludedFileName2.c_str());
+ EXPECT_TRUE(IncludedFile2.is_open());
+ IncludedFile2 << "-option_21 -option_22\n";
+ IncludedFile2 << "-option_23=abcd\n";
+ IncludedFile2.close();
+
+ // Prepare 'file' with reference to response file.
+ SmallString<128> IncRef;
+ IncRef.append(1, '@');
+ IncRef.append(IncludedFileName.c_str());
+ llvm::SmallVector<const char *, 4> Argv =
+ { "test/test", "-flag_1", IncRef.c_str(), "-flag_2" };
+
+ // Expand response files.
+ llvm::BumpPtrAllocator A;
+ llvm::StringSaver Saver(A);
+ bool Res = llvm::cl::ExpandResponseFiles(
+ Saver, llvm::cl::TokenizeGNUCommandLine, Argv, false, true);
+ EXPECT_TRUE(Res);
+ EXPECT_EQ(Argv.size(), 9U);
+ EXPECT_STREQ(Argv[0], "test/test");
+ EXPECT_STREQ(Argv[1], "-flag_1");
+ EXPECT_STREQ(Argv[2], "-option_1");
+ EXPECT_STREQ(Argv[3], "-option_2");
+ EXPECT_STREQ(Argv[4], "-option_21");
+ EXPECT_STREQ(Argv[5], "-option_22");
+ EXPECT_STREQ(Argv[6], "-option_23=abcd");
+ EXPECT_STREQ(Argv[7], "-option_3=abcd");
+ EXPECT_STREQ(Argv[8], "-flag_2");
+
+ llvm::sys::fs::remove(IncludedFileName2);
+ llvm::sys::fs::remove(IncDir);
+ llvm::sys::fs::remove(IncludedFileName);
+ llvm::sys::fs::remove(TestDir);
}
} // anonymous namespace
diff --git a/unittests/Support/DebugTest.cpp b/unittests/Support/DebugTest.cpp
new file mode 100644
index 000000000000..7db91ff0d854
--- /dev/null
+++ b/unittests/Support/DebugTest.cpp
@@ -0,0 +1,34 @@
+//===- llvm/unittest/Support/DebugTest.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/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+#include "gtest/gtest.h"
+
+#include <string>
+using namespace llvm;
+
+#ifndef NDEBUG
+TEST(DebugTest, Basic) {
+ std::string s1, s2;
+ raw_string_ostream os1(s1), os2(s2);
+ static const char *DT[] = {"A", "B"};
+
+ llvm::DebugFlag = true;
+ setCurrentDebugTypes(DT, 2);
+ DEBUG_WITH_TYPE("A", os1 << "A");
+ DEBUG_WITH_TYPE("B", os1 << "B");
+ EXPECT_EQ("AB", os1.str());
+
+ setCurrentDebugType("A");
+ DEBUG_WITH_TYPE("A", os2 << "A");
+ DEBUG_WITH_TYPE("B", os2 << "B");
+ EXPECT_EQ("A", os2.str());
+}
+#endif
diff --git a/unittests/Support/DwarfTest.cpp b/unittests/Support/DwarfTest.cpp
index 74fcc989b45a..148ea2736e15 100644
--- a/unittests/Support/DwarfTest.cpp
+++ b/unittests/Support/DwarfTest.cpp
@@ -17,13 +17,13 @@ namespace {
TEST(DwarfTest, TagStringOnInvalid) {
// This is invalid, so it shouldn't be stringified.
- EXPECT_EQ(nullptr, TagString(DW_TAG_invalid));
+ EXPECT_EQ(StringRef(), TagString(DW_TAG_invalid));
// These aren't really tags: they describe ranges within tags. They
// shouldn't be stringified either.
- EXPECT_EQ(nullptr, TagString(DW_TAG_lo_user));
- EXPECT_EQ(nullptr, TagString(DW_TAG_hi_user));
- EXPECT_EQ(nullptr, TagString(DW_TAG_user_base));
+ EXPECT_EQ(StringRef(), TagString(DW_TAG_lo_user));
+ EXPECT_EQ(StringRef(), TagString(DW_TAG_hi_user));
+ EXPECT_EQ(StringRef(), TagString(DW_TAG_user_base));
}
TEST(DwarfTest, getTag) {
@@ -58,12 +58,12 @@ TEST(DwarfTest, getOperationEncoding) {
TEST(DwarfTest, LanguageStringOnInvalid) {
// This is invalid, so it shouldn't be stringified.
- EXPECT_EQ(nullptr, LanguageString(0));
+ EXPECT_EQ(StringRef(), LanguageString(0));
// These aren't really tags: they describe ranges within tags. They
// shouldn't be stringified either.
- EXPECT_EQ(nullptr, LanguageString(DW_LANG_lo_user));
- EXPECT_EQ(nullptr, LanguageString(DW_LANG_hi_user));
+ EXPECT_EQ(StringRef(), LanguageString(DW_LANG_lo_user));
+ EXPECT_EQ(StringRef(), LanguageString(DW_LANG_hi_user));
}
TEST(DwarfTest, getLanguage) {
@@ -85,12 +85,12 @@ TEST(DwarfTest, getLanguage) {
TEST(DwarfTest, AttributeEncodingStringOnInvalid) {
// This is invalid, so it shouldn't be stringified.
- EXPECT_EQ(nullptr, AttributeEncodingString(0));
+ EXPECT_EQ(StringRef(), AttributeEncodingString(0));
// These aren't really tags: they describe ranges within tags. They
// shouldn't be stringified either.
- EXPECT_EQ(nullptr, AttributeEncodingString(DW_ATE_lo_user));
- EXPECT_EQ(nullptr, AttributeEncodingString(DW_ATE_hi_user));
+ EXPECT_EQ(StringRef(), AttributeEncodingString(DW_ATE_lo_user));
+ EXPECT_EQ(StringRef(), AttributeEncodingString(DW_ATE_hi_user));
}
TEST(DwarfTest, getAttributeEncoding) {
@@ -122,8 +122,8 @@ TEST(DwarfTest, VirtualityString) {
VirtualityString(DW_VIRTUALITY_max));
// Invalid numbers shouldn't be stringified.
- EXPECT_EQ(nullptr, VirtualityString(DW_VIRTUALITY_max + 1));
- EXPECT_EQ(nullptr, VirtualityString(DW_VIRTUALITY_max + 77));
+ EXPECT_EQ(StringRef(), VirtualityString(DW_VIRTUALITY_max + 1));
+ EXPECT_EQ(StringRef(), VirtualityString(DW_VIRTUALITY_max + 77));
}
TEST(DwarfTest, getVirtuality) {
diff --git a/unittests/Support/ErrorTest.cpp b/unittests/Support/ErrorTest.cpp
index 205092683744..29a173a058b6 100644
--- a/unittests/Support/ErrorTest.cpp
+++ b/unittests/Support/ErrorTest.cpp
@@ -82,12 +82,14 @@ protected:
char CustomSubError::ID = 0;
-static Error handleCustomError(const CustomError &CE) { return Error(); }
+static Error handleCustomError(const CustomError &CE) {
+ return Error::success();
+}
static void handleCustomErrorVoid(const CustomError &CE) {}
static Error handleCustomErrorUP(std::unique_ptr<CustomError> CE) {
- return Error();
+ return Error::success();
}
static void handleCustomErrorUPVoid(std::unique_ptr<CustomError> CE) {}
@@ -95,21 +97,22 @@ static void handleCustomErrorUPVoid(std::unique_ptr<CustomError> CE) {}
// Test that success values implicitly convert to false, and don't cause crashes
// once they've been implicitly converted.
TEST(Error, CheckedSuccess) {
- Error E;
+ Error E = Error::success();
EXPECT_FALSE(E) << "Unexpected error while testing Error 'Success'";
}
// Test that unchecked succes values cause an abort.
-#ifndef NDEBUG
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
TEST(Error, UncheckedSuccess) {
- EXPECT_DEATH({ Error E; }, "Program aborted due to an unhandled Error:")
+ EXPECT_DEATH({ Error E = Error::success(); },
+ "Program aborted due to an unhandled Error:")
<< "Unchecked Error Succes value did not cause abort()";
}
#endif
// ErrorAsOutParameter tester.
void errAsOutParamHelper(Error &Err) {
- ErrorAsOutParameter ErrAsOutParam(Err);
+ ErrorAsOutParameter ErrAsOutParam(&Err);
// Verify that checked flag is raised - assignment should not crash.
Err = Error::success();
// Raise the checked bit manually - caller should still have to test the
@@ -119,15 +122,15 @@ void errAsOutParamHelper(Error &Err) {
// Test that ErrorAsOutParameter sets the checked flag on construction.
TEST(Error, ErrorAsOutParameterChecked) {
- Error E;
+ Error E = Error::success();
errAsOutParamHelper(E);
(void)!!E;
}
// Test that ErrorAsOutParameter clears the checked flag on destruction.
-#ifndef NDEBUG
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
TEST(Error, ErrorAsOutParameterUnchecked) {
- EXPECT_DEATH({ Error E; errAsOutParamHelper(E); },
+ EXPECT_DEATH({ Error E = Error::success(); errAsOutParamHelper(E); },
"Program aborted due to an unhandled Error:")
<< "ErrorAsOutParameter did not clear the checked flag on destruction.";
}
@@ -136,7 +139,7 @@ TEST(Error, ErrorAsOutParameterUnchecked) {
// Check that we abort on unhandled failure cases. (Force conversion to bool
// to make sure that we don't accidentally treat checked errors as handled).
// Test runs in debug mode only.
-#ifndef NDEBUG
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
TEST(Error, UncheckedError) {
auto DropUnhandledError = []() {
Error E = make_error<CustomError>(42);
@@ -195,31 +198,31 @@ TEST(Error, HandlerTypeDeduction) {
handleAllErrors(
make_error<CustomError>(42),
- [](const CustomError &CE) mutable { return Error::success(); });
+ [](const CustomError &CE) mutable -> Error { return Error::success(); });
handleAllErrors(make_error<CustomError>(42),
[](const CustomError &CE) mutable {});
handleAllErrors(make_error<CustomError>(42),
- [](CustomError &CE) { return Error::success(); });
+ [](CustomError &CE) -> Error { return Error::success(); });
handleAllErrors(make_error<CustomError>(42), [](CustomError &CE) {});
handleAllErrors(make_error<CustomError>(42),
- [](CustomError &CE) mutable { return Error::success(); });
+ [](CustomError &CE) mutable -> Error { return Error::success(); });
handleAllErrors(make_error<CustomError>(42), [](CustomError &CE) mutable {});
handleAllErrors(
make_error<CustomError>(42),
- [](std::unique_ptr<CustomError> CE) { return Error::success(); });
+ [](std::unique_ptr<CustomError> CE) -> Error { return Error::success(); });
handleAllErrors(make_error<CustomError>(42),
[](std::unique_ptr<CustomError> CE) {});
handleAllErrors(
make_error<CustomError>(42),
- [](std::unique_ptr<CustomError> CE) mutable { return Error::success(); });
+ [](std::unique_ptr<CustomError> CE) mutable -> Error { return Error::success(); });
handleAllErrors(make_error<CustomError>(42),
[](std::unique_ptr<CustomError> CE) mutable {});
@@ -363,7 +366,7 @@ TEST(Error, CheckJoinErrors) {
// Test that we can consume success values.
TEST(Error, ConsumeSuccess) {
- Error E;
+ Error E = Error::success();
consumeError(std::move(E));
}
@@ -374,7 +377,7 @@ TEST(Error, ConsumeError) {
// Test that handleAllUnhandledErrors crashes if an error is not caught.
// Test runs in debug mode only.
-#ifndef NDEBUG
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
TEST(Error, FailureToHandle) {
auto FailToHandle = []() {
handleAllErrors(make_error<CustomError>(7), [&](const CustomSubError &SE) {
@@ -392,7 +395,7 @@ TEST(Error, FailureToHandle) {
// Test that handleAllUnhandledErrors crashes if an error is returned from a
// handler.
// Test runs in debug mode only.
-#ifndef NDEBUG
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
TEST(Error, FailureFromHandler) {
auto ReturnErrorFromHandler = []() {
handleAllErrors(make_error<CustomError>(7),
@@ -487,7 +490,7 @@ TEST(Error, ExpectedWithReferenceType) {
// Test Unchecked Expected<T> in success mode.
// We expect this to blow up the same way Error would.
// Test runs in debug mode only.
-#ifndef NDEBUG
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
TEST(Error, UncheckedExpectedInSuccessModeDestruction) {
EXPECT_DEATH({ Expected<int> A = 7; },
"Expected<T> must be checked before access or destruction.")
@@ -498,7 +501,7 @@ TEST(Error, UncheckedExpectedInSuccessModeDestruction) {
// Test Unchecked Expected<T> in success mode.
// We expect this to blow up the same way Error would.
// Test runs in debug mode only.
-#ifndef NDEBUG
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
TEST(Error, UncheckedExpectedInSuccessModeAccess) {
EXPECT_DEATH({ Expected<int> A = 7; *A; },
"Expected<T> must be checked before access or destruction.")
@@ -509,7 +512,7 @@ TEST(Error, UncheckedExpectedInSuccessModeAccess) {
// Test Unchecked Expected<T> in success mode.
// We expect this to blow up the same way Error would.
// Test runs in debug mode only.
-#ifndef NDEBUG
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
TEST(Error, UncheckedExpectedInSuccessModeAssignment) {
EXPECT_DEATH({ Expected<int> A = 7; A = 7; },
"Expected<T> must be checked before access or destruction.")
@@ -529,7 +532,7 @@ TEST(Error, ExpectedInFailureMode) {
// Check that an Expected instance with an error value doesn't allow access to
// operator*.
// Test runs in debug mode only.
-#ifndef NDEBUG
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
TEST(Error, AccessExpectedInFailureMode) {
Expected<int> A = make_error<CustomError>(42);
EXPECT_DEATH(*A, "Expected<T> must be checked before access or destruction.")
@@ -541,7 +544,7 @@ TEST(Error, AccessExpectedInFailureMode) {
// Check that an Expected instance with an error triggers an abort if
// unhandled.
// Test runs in debug mode only.
-#ifndef NDEBUG
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
TEST(Error, UnhandledExpectedInFailureMode) {
EXPECT_DEATH({ Expected<int> A = make_error<CustomError>(42); },
"Expected<T> must be checked before access or destruction.")
diff --git a/unittests/Support/FileOutputBufferTest.cpp b/unittests/Support/FileOutputBufferTest.cpp
index 090c476e35cf..53a2ae0aadde 100644
--- a/unittests/Support/FileOutputBufferTest.cpp
+++ b/unittests/Support/FileOutputBufferTest.cpp
@@ -20,9 +20,12 @@ using namespace llvm::sys;
#define ASSERT_NO_ERROR(x) \
if (std::error_code ASSERT_NO_ERROR_ec = x) { \
- errs() << #x ": did not return errc::success.\n" \
- << "error number: " << ASSERT_NO_ERROR_ec.value() << "\n" \
- << "error message: " << ASSERT_NO_ERROR_ec.message() << "\n"; \
+ SmallString<128> MessageStorage; \
+ raw_svector_ostream Message(MessageStorage); \
+ Message << #x ": did not return errc::success.\n" \
+ << "error number: " << ASSERT_NO_ERROR_ec.value() << "\n" \
+ << "error message: " << ASSERT_NO_ERROR_ec.message() << "\n"; \
+ GTEST_FATAL_FAILURE_(MessageStorage.c_str()); \
} else { \
}
@@ -57,9 +60,9 @@ TEST(FileOutputBuffer, Test) {
ASSERT_EQ(File1Size, 8192ULL);
ASSERT_NO_ERROR(fs::remove(File1.str()));
- // TEST 2: Verify abort case.
+ // TEST 2: Verify abort case.
SmallString<128> File2(TestDirectory);
- File2.append("/file2");
+ File2.append("/file2");
{
ErrorOr<std::unique_ptr<FileOutputBuffer>> Buffer2OrErr =
FileOutputBuffer::create(File2, 8192);
diff --git a/unittests/Support/FormatVariadicTest.cpp b/unittests/Support/FormatVariadicTest.cpp
new file mode 100644
index 000000000000..9307c6d8e09b
--- /dev/null
+++ b/unittests/Support/FormatVariadicTest.cpp
@@ -0,0 +1,570 @@
+//===- FormatVariadicTest.cpp - Unit tests for string formatting ----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/FormatAdapters.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+// Compile-time tests templates in the detail namespace.
+namespace {
+struct Format : public FormatAdapter<int> {
+ Format(int N) : FormatAdapter<int>(std::move(N)) {}
+ void format(raw_ostream &OS, StringRef Opt) override { OS << "Format"; }
+};
+
+using detail::uses_format_member;
+using detail::uses_missing_provider;
+
+static_assert(uses_format_member<Format>::value, "");
+static_assert(uses_format_member<Format &>::value, "");
+static_assert(uses_format_member<Format &&>::value, "");
+static_assert(uses_format_member<const Format>::value, "");
+static_assert(uses_format_member<const Format &>::value, "");
+static_assert(uses_format_member<const volatile Format>::value, "");
+static_assert(uses_format_member<const volatile Format &>::value, "");
+
+struct NoFormat {};
+static_assert(uses_missing_provider<NoFormat>::value, "");
+}
+
+TEST(FormatVariadicTest, EmptyFormatString) {
+ auto Replacements = formatv_object_base::parseFormatString("");
+ EXPECT_EQ(0U, Replacements.size());
+}
+
+TEST(FormatVariadicTest, NoReplacements) {
+ const StringRef kFormatString = "This is a test";
+ auto Replacements = formatv_object_base::parseFormatString(kFormatString);
+ ASSERT_EQ(1U, Replacements.size());
+ EXPECT_EQ(kFormatString, Replacements[0].Spec);
+ EXPECT_EQ(ReplacementType::Literal, Replacements[0].Type);
+}
+
+TEST(FormatVariadicTest, EscapedBrace) {
+ // {{ should be replaced with {
+ auto Replacements = formatv_object_base::parseFormatString("{{");
+ ASSERT_EQ(1u, Replacements.size());
+ EXPECT_EQ("{", Replacements[0].Spec);
+ EXPECT_EQ(ReplacementType::Literal, Replacements[0].Type);
+
+ // An even number N of braces should be replaced with N/2 braces.
+ Replacements = formatv_object_base::parseFormatString("{{{{{{");
+ ASSERT_EQ(1u, Replacements.size());
+ EXPECT_EQ("{{{", Replacements[0].Spec);
+ EXPECT_EQ(ReplacementType::Literal, Replacements[0].Type);
+}
+
+TEST(FormatVariadicTest, ValidReplacementSequence) {
+ // 1. Simple replacement - parameter index only
+ auto Replacements = formatv_object_base::parseFormatString("{0}");
+ ASSERT_EQ(1u, Replacements.size());
+ EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
+ EXPECT_EQ(0u, Replacements[0].Index);
+ EXPECT_EQ(0u, Replacements[0].Align);
+ EXPECT_EQ("", Replacements[0].Options);
+
+ Replacements = formatv_object_base::parseFormatString("{1}");
+ ASSERT_EQ(1u, Replacements.size());
+ EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
+ EXPECT_EQ(1u, Replacements[0].Index);
+ EXPECT_EQ(0u, Replacements[0].Align);
+ EXPECT_EQ(AlignStyle::Right, Replacements[0].Where);
+ EXPECT_EQ("", Replacements[0].Options);
+
+ // 2. Parameter index with right alignment
+ Replacements = formatv_object_base::parseFormatString("{0,3}");
+ ASSERT_EQ(1u, Replacements.size());
+ EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
+ EXPECT_EQ(0u, Replacements[0].Index);
+ EXPECT_EQ(3u, Replacements[0].Align);
+ EXPECT_EQ(AlignStyle::Right, Replacements[0].Where);
+ EXPECT_EQ("", Replacements[0].Options);
+
+ // 3. And left alignment
+ Replacements = formatv_object_base::parseFormatString("{0,-3}");
+ ASSERT_EQ(1u, Replacements.size());
+ EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
+ EXPECT_EQ(0u, Replacements[0].Index);
+ EXPECT_EQ(3u, Replacements[0].Align);
+ EXPECT_EQ(AlignStyle::Left, Replacements[0].Where);
+ EXPECT_EQ("", Replacements[0].Options);
+
+ // 4. And center alignment
+ Replacements = formatv_object_base::parseFormatString("{0,=3}");
+ ASSERT_EQ(1u, Replacements.size());
+ EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
+ EXPECT_EQ(0u, Replacements[0].Index);
+ EXPECT_EQ(3u, Replacements[0].Align);
+ EXPECT_EQ(AlignStyle::Center, Replacements[0].Where);
+ EXPECT_EQ("", Replacements[0].Options);
+
+ // 4. Parameter index with option string
+ Replacements = formatv_object_base::parseFormatString("{0:foo}");
+ ASSERT_EQ(1u, Replacements.size());
+ EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
+ EXPECT_EQ(0u, Replacements[0].Index);
+ EXPECT_EQ(0u, Replacements[0].Align);
+ EXPECT_EQ(AlignStyle::Right, Replacements[0].Where);
+ EXPECT_EQ("foo", Replacements[0].Options);
+
+ // 5. Parameter index with alignment before option string
+ Replacements = formatv_object_base::parseFormatString("{0,-3:foo}");
+ ASSERT_EQ(1u, Replacements.size());
+ EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
+ EXPECT_EQ(0u, Replacements[0].Index);
+ EXPECT_EQ(3u, Replacements[0].Align);
+ EXPECT_EQ(AlignStyle::Left, Replacements[0].Where);
+ EXPECT_EQ("foo", Replacements[0].Options);
+
+ // 7. Parameter indices, options, and alignment can all have whitespace.
+ Replacements = formatv_object_base::parseFormatString("{ 0, -3 : foo }");
+ ASSERT_EQ(1u, Replacements.size());
+ EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
+ EXPECT_EQ(0u, Replacements[0].Index);
+ EXPECT_EQ(3u, Replacements[0].Align);
+ EXPECT_EQ(AlignStyle::Left, Replacements[0].Where);
+ EXPECT_EQ("foo", Replacements[0].Options);
+
+ // 8. Everything after the first option specifier is part of the style, even
+ // if it contains another option specifier.
+ Replacements = formatv_object_base::parseFormatString("{0:0:1}");
+ ASSERT_EQ(1u, Replacements.size());
+ EXPECT_EQ("0:0:1", Replacements[0].Spec);
+ EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
+ EXPECT_EQ(0u, Replacements[0].Index);
+ EXPECT_EQ(0u, Replacements[0].Align);
+ EXPECT_EQ(AlignStyle::Right, Replacements[0].Where);
+ EXPECT_EQ("0:1", Replacements[0].Options);
+}
+
+TEST(FormatVariadicTest, DefaultReplacementValues) {
+ // 2. If options string is missing, it defaults to empty.
+ auto Replacements = formatv_object_base::parseFormatString("{0,3}");
+ ASSERT_EQ(1u, Replacements.size());
+ EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
+ EXPECT_EQ(0u, Replacements[0].Index);
+ EXPECT_EQ(3u, Replacements[0].Align);
+ EXPECT_EQ("", Replacements[0].Options);
+
+ // Including if the colon is present but contains no text.
+ Replacements = formatv_object_base::parseFormatString("{0,3:}");
+ ASSERT_EQ(1u, Replacements.size());
+ EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
+ EXPECT_EQ(0u, Replacements[0].Index);
+ EXPECT_EQ(3u, Replacements[0].Align);
+ EXPECT_EQ("", Replacements[0].Options);
+
+ // 3. If alignment is missing, it defaults to 0, right, space
+ Replacements = formatv_object_base::parseFormatString("{0:foo}");
+ ASSERT_EQ(1u, Replacements.size());
+ EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
+ EXPECT_EQ(AlignStyle::Right, Replacements[0].Where);
+ EXPECT_EQ(' ', Replacements[0].Pad);
+ EXPECT_EQ(0u, Replacements[0].Index);
+ EXPECT_EQ(0u, Replacements[0].Align);
+ EXPECT_EQ("foo", Replacements[0].Options);
+}
+
+TEST(FormatVariadicTest, MultipleReplacements) {
+ auto Replacements =
+ formatv_object_base::parseFormatString("{0} {1:foo}-{2,-3:bar}");
+ ASSERT_EQ(5u, Replacements.size());
+ // {0}
+ EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
+ EXPECT_EQ(0u, Replacements[0].Index);
+ EXPECT_EQ(0u, Replacements[0].Align);
+ EXPECT_EQ(AlignStyle::Right, Replacements[0].Where);
+ EXPECT_EQ("", Replacements[0].Options);
+
+ // " "
+ EXPECT_EQ(ReplacementType::Literal, Replacements[1].Type);
+ EXPECT_EQ(" ", Replacements[1].Spec);
+
+ // {1:foo} - Options=foo
+ EXPECT_EQ(ReplacementType::Format, Replacements[2].Type);
+ EXPECT_EQ(1u, Replacements[2].Index);
+ EXPECT_EQ(0u, Replacements[2].Align);
+ EXPECT_EQ(AlignStyle::Right, Replacements[2].Where);
+ EXPECT_EQ("foo", Replacements[2].Options);
+
+ // "-"
+ EXPECT_EQ(ReplacementType::Literal, Replacements[3].Type);
+ EXPECT_EQ("-", Replacements[3].Spec);
+
+ // {2:bar,-3} - Options=bar, Align=-3
+ EXPECT_EQ(ReplacementType::Format, Replacements[4].Type);
+ EXPECT_EQ(2u, Replacements[4].Index);
+ EXPECT_EQ(3u, Replacements[4].Align);
+ EXPECT_EQ(AlignStyle::Left, Replacements[4].Where);
+ EXPECT_EQ("bar", Replacements[4].Options);
+}
+
+TEST(FormatVariadicTest, FormatNoReplacements) {
+ EXPECT_EQ("", formatv("").str());
+ EXPECT_EQ("Test", formatv("Test").str());
+}
+
+TEST(FormatVariadicTest, FormatBasicTypesOneReplacement) {
+ EXPECT_EQ("1", formatv("{0}", 1).str());
+ EXPECT_EQ("c", formatv("{0}", 'c').str());
+ EXPECT_EQ("-3", formatv("{0}", -3).str());
+ EXPECT_EQ("Test", formatv("{0}", "Test").str());
+ EXPECT_EQ("Test2", formatv("{0}", StringRef("Test2")).str());
+ EXPECT_EQ("Test3", formatv("{0}", std::string("Test3")).str());
+}
+
+TEST(FormatVariadicTest, IntegralHexFormatting) {
+ // 1. Trivial cases. Make sure hex is not the default.
+ EXPECT_EQ("0", formatv("{0}", 0).str());
+ EXPECT_EQ("2748", formatv("{0}", 0xABC).str());
+ EXPECT_EQ("-2748", formatv("{0}", -0xABC).str());
+
+ // 3. various hex prefixes.
+ EXPECT_EQ("0xFF", formatv("{0:X}", 255).str());
+ EXPECT_EQ("0xFF", formatv("{0:X+}", 255).str());
+ EXPECT_EQ("0xff", formatv("{0:x}", 255).str());
+ EXPECT_EQ("0xff", formatv("{0:x+}", 255).str());
+ EXPECT_EQ("FF", formatv("{0:X-}", 255).str());
+ EXPECT_EQ("ff", formatv("{0:x-}", 255).str());
+
+ // 5. Precision pads left of the most significant digit but right of the
+ // prefix (if one exists).
+ EXPECT_EQ("0xFF", formatv("{0:X2}", 255).str());
+ EXPECT_EQ("0xFF", formatv("{0:X+2}", 255).str());
+ EXPECT_EQ("0x0ff", formatv("{0:x3}", 255).str());
+ EXPECT_EQ("0x0ff", formatv("{0:x+3}", 255).str());
+ EXPECT_EQ("00FF", formatv("{0:X-4}", 255).str());
+ EXPECT_EQ("00ff", formatv("{0:x-4}", 255).str());
+
+ // 6. Try some larger types.
+ EXPECT_EQ("0xDEADBEEFDEADBEEF",
+ formatv("{0:X16}", -2401053088876216593LL).str());
+ EXPECT_EQ("0xFEEBDAEDFEEBDAED",
+ formatv("{0:X16}", 0xFEEBDAEDFEEBDAEDULL).str());
+ EXPECT_EQ("0x00000000DEADBEEF", formatv("{0:X16}", 0xDEADBEEF).str());
+
+ // 7. Padding should take into account the prefix
+ EXPECT_EQ("0xff", formatv("{0,4:x}", 255).str());
+ EXPECT_EQ(" 0xff", formatv("{0,5:x+}", 255).str());
+ EXPECT_EQ(" FF", formatv("{0,4:X-}", 255).str());
+ EXPECT_EQ(" ff", formatv("{0,5:x-}", 255).str());
+
+ // 8. Including when it's been zero-padded
+ EXPECT_EQ(" 0x0ff", formatv("{0,7:x3}", 255).str());
+ EXPECT_EQ(" 0x00ff", formatv("{0,7:x+4}", 255).str());
+ EXPECT_EQ(" 000FF", formatv("{0,7:X-5}", 255).str());
+ EXPECT_EQ(" 0000ff", formatv("{0,7:x-6}", 255).str());
+
+ // 9. Precision with default format specifier should work too
+ EXPECT_EQ(" 255", formatv("{0,7:3}", 255).str());
+ EXPECT_EQ(" 0255", formatv("{0,7:4}", 255).str());
+ EXPECT_EQ(" 00255", formatv("{0,7:5}", 255).str());
+ EXPECT_EQ(" 000255", formatv("{0,7:6}", 255).str());
+}
+
+TEST(FormatVariadicTest, PointerFormatting) {
+ // 1. Trivial cases. Hex is default. Default Precision is pointer width.
+ if (sizeof(void *) == 4) {
+ EXPECT_EQ("0x00000000", formatv("{0}", (void *)0).str());
+ EXPECT_EQ("0x00000ABC", formatv("{0}", (void *)0xABC).str());
+ } else {
+ EXPECT_EQ("0x0000000000000000", formatv("{0}", (void *)0).str());
+ EXPECT_EQ("0x0000000000000ABC", formatv("{0}", (void *)0xABC).str());
+ }
+
+ // 2. But we can reduce the precision explicitly.
+ EXPECT_EQ("0x0", formatv("{0:0}", (void *)0).str());
+ EXPECT_EQ("0xABC", formatv("{0:0}", (void *)0xABC).str());
+ EXPECT_EQ("0x0000", formatv("{0:4}", (void *)0).str());
+ EXPECT_EQ("0x0ABC", formatv("{0:4}", (void *)0xABC).str());
+
+ // 3. various hex prefixes.
+ EXPECT_EQ("0x0ABC", formatv("{0:X4}", (void *)0xABC).str());
+ EXPECT_EQ("0x0abc", formatv("{0:x4}", (void *)0xABC).str());
+ EXPECT_EQ("0ABC", formatv("{0:X-4}", (void *)0xABC).str());
+ EXPECT_EQ("0abc", formatv("{0:x-4}", (void *)0xABC).str());
+}
+
+TEST(FormatVariadicTest, IntegralNumberFormatting) {
+ // 1. Test comma grouping with default widths and precisions.
+ EXPECT_EQ("0", formatv("{0:N}", 0).str());
+ EXPECT_EQ("10", formatv("{0:N}", 10).str());
+ EXPECT_EQ("100", formatv("{0:N}", 100).str());
+ EXPECT_EQ("1,000", formatv("{0:N}", 1000).str());
+ EXPECT_EQ("1,234,567,890", formatv("{0:N}", 1234567890).str());
+ EXPECT_EQ("-10", formatv("{0:N}", -10).str());
+ EXPECT_EQ("-100", formatv("{0:N}", -100).str());
+ EXPECT_EQ("-1,000", formatv("{0:N}", -1000).str());
+ EXPECT_EQ("-1,234,567,890", formatv("{0:N}", -1234567890).str());
+
+ // 2. If there is no comma, width and precision pad to the same absolute
+ // size.
+ EXPECT_EQ(" 1", formatv("{0,2:N}", 1).str());
+
+ // 3. But if there is a comma or negative sign, width factors them in but
+ // precision doesn't.
+ EXPECT_EQ(" 1,000", formatv("{0,6:N}", 1000).str());
+ EXPECT_EQ(" -1,000", formatv("{0,7:N}", -1000).str());
+
+ // 4. Large widths all line up.
+ EXPECT_EQ(" 1,000", formatv("{0,11:N}", 1000).str());
+ EXPECT_EQ(" -1,000", formatv("{0,11:N}", -1000).str());
+ EXPECT_EQ(" -100,000", formatv("{0,11:N}", -100000).str());
+}
+
+TEST(FormatVariadicTest, StringFormatting) {
+ const char FooArray[] = "FooArray";
+ const char *FooPtr = "FooPtr";
+ llvm::StringRef FooRef("FooRef");
+ 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(FooString, formatv("{0}", FooString).str());
+
+ // 2. Test that the precision specifier prints the correct number of
+ // characters.
+ EXPECT_EQ("FooA", formatv("{0:4}", FooArray).str());
+ EXPECT_EQ("FooP", formatv("{0:4}", FooPtr).str());
+ EXPECT_EQ("FooR", formatv("{0:4}", FooRef).str());
+ EXPECT_EQ("FooS", formatv("{0:4}", FooString).str());
+
+ // 3. And that padding works.
+ EXPECT_EQ(" FooA", formatv("{0,6:4}", FooArray).str());
+ EXPECT_EQ(" FooP", formatv("{0,6:4}", FooPtr).str());
+ EXPECT_EQ(" FooR", formatv("{0,6:4}", FooRef).str());
+ EXPECT_EQ(" FooS", formatv("{0,6:4}", FooString).str());
+}
+
+TEST(FormatVariadicTest, CharFormatting) {
+ // 1. Not much to see here. Just print a char with and without padding.
+ EXPECT_EQ("C", formatv("{0}", 'C').str());
+ EXPECT_EQ(" C", formatv("{0,3}", 'C').str());
+
+ // 2. char is really an integral type though, where the only difference is
+ // that the "default" is to print the ASCII. So if a non-default presentation
+ // specifier exists, it should print as an integer.
+ EXPECT_EQ("37", formatv("{0:D}", (char)37).str());
+ EXPECT_EQ(" 037", formatv("{0,5:D3}", (char)37).str());
+}
+
+TEST(FormatVariadicTest, BoolTest) {
+ // 1. Default style is lowercase text (same as 't')
+ EXPECT_EQ("true", formatv("{0}", true).str());
+ EXPECT_EQ("false", formatv("{0}", false).str());
+ EXPECT_EQ("true", formatv("{0:t}", true).str());
+ EXPECT_EQ("false", formatv("{0:t}", false).str());
+
+ // 2. T - uppercase text
+ EXPECT_EQ("TRUE", formatv("{0:T}", true).str());
+ EXPECT_EQ("FALSE", formatv("{0:T}", false).str());
+
+ // 3. D / d - integral
+ EXPECT_EQ("1", formatv("{0:D}", true).str());
+ EXPECT_EQ("0", formatv("{0:D}", false).str());
+ EXPECT_EQ("1", formatv("{0:d}", true).str());
+ EXPECT_EQ("0", formatv("{0:d}", false).str());
+
+ // 4. Y - uppercase yes/no
+ EXPECT_EQ("YES", formatv("{0:Y}", true).str());
+ EXPECT_EQ("NO", formatv("{0:Y}", false).str());
+
+ // 5. y - lowercase yes/no
+ EXPECT_EQ("yes", formatv("{0:y}", true).str());
+ EXPECT_EQ("no", formatv("{0:y}", false).str());
+}
+
+TEST(FormatVariadicTest, DoubleFormatting) {
+ // Test exponents, fixed point, and percent formatting.
+
+ // 1. Signed, unsigned, and zero exponent format.
+ EXPECT_EQ("0.000000E+00", formatv("{0:E}", 0.0).str());
+ EXPECT_EQ("-0.000000E+00", formatv("{0:E}", -0.0).str());
+ EXPECT_EQ("1.100000E+00", formatv("{0:E}", 1.1).str());
+ EXPECT_EQ("-1.100000E+00", formatv("{0:E}", -1.1).str());
+ EXPECT_EQ("1.234568E+03", formatv("{0:E}", 1234.5678).str());
+ EXPECT_EQ("-1.234568E+03", formatv("{0:E}", -1234.5678).str());
+ EXPECT_EQ("1.234568E-03", formatv("{0:E}", .0012345678).str());
+ EXPECT_EQ("-1.234568E-03", formatv("{0:E}", -.0012345678).str());
+
+ // 2. With padding and precision.
+ EXPECT_EQ(" 0.000E+00", formatv("{0,11:E3}", 0.0).str());
+ EXPECT_EQ(" -1.100E+00", formatv("{0,11:E3}", -1.1).str());
+ EXPECT_EQ(" 1.235E+03", formatv("{0,11:E3}", 1234.5678).str());
+ EXPECT_EQ(" -1.235E-03", formatv("{0,11:E3}", -.0012345678).str());
+
+ // 3. Signed, unsigned, and zero fixed point format.
+ EXPECT_EQ("0.00", formatv("{0:F}", 0.0).str());
+ EXPECT_EQ("-0.00", formatv("{0:F}", -0.0).str());
+ EXPECT_EQ("1.10", formatv("{0:F}", 1.1).str());
+ EXPECT_EQ("-1.10", formatv("{0:F}", -1.1).str());
+ EXPECT_EQ("1234.57", formatv("{0:F}", 1234.5678).str());
+ EXPECT_EQ("-1234.57", formatv("{0:F}", -1234.5678).str());
+ EXPECT_EQ("0.00", formatv("{0:F}", .0012345678).str());
+ EXPECT_EQ("-0.00", formatv("{0:F}", -.0012345678).str());
+
+ // 2. With padding and precision.
+ EXPECT_EQ(" 0.000", formatv("{0,8:F3}", 0.0).str());
+ EXPECT_EQ(" -1.100", formatv("{0,8:F3}", -1.1).str());
+ EXPECT_EQ("1234.568", formatv("{0,8:F3}", 1234.5678).str());
+ EXPECT_EQ(" -0.001", formatv("{0,8:F3}", -.0012345678).str());
+}
+
+struct format_tuple {
+ const char *Fmt;
+ explicit format_tuple(const char *Fmt) : Fmt(Fmt) {}
+
+ template <typename... Ts>
+ auto operator()(Ts &&... Values) const
+ -> decltype(formatv(Fmt, std::forward<Ts>(Values)...)) {
+ return formatv(Fmt, std::forward<Ts>(Values)...);
+ }
+};
+
+TEST(FormatVariadicTest, BigTest) {
+ using Tuple =
+ std::tuple<char, int, const char *, StringRef, std::string, double, float,
+ void *, int, double, int64_t, uint64_t, double, uint8_t>;
+ Tuple Ts[] = {
+ Tuple('a', 1, "Str", StringRef(), std::string(), 3.14159, -.17532f,
+ (void *)nullptr, 123456, 6.02E23, -908234908423, 908234908422234,
+ std::numeric_limits<double>::quiet_NaN(), 0xAB),
+ Tuple('x', 0xDDB5B, "LongerStr", "StringRef", "std::string", -2.7,
+ .08215f, (void *)nullptr, 0, 6.62E-34, -908234908423,
+ 908234908422234, std::numeric_limits<double>::infinity(), 0x0)};
+ // Test long string formatting with many edge cases combined.
+ const char *Intro =
+ "There are {{{0}} items in the tuple, and {{{1}} tuple(s) in the array.";
+ const char *Header =
+ "{0,6}|{1,8}|{2,=10}|{3,=10}|{4,=13}|{5,7}|{6,7}|{7,10}|{8,"
+ "-7}|{9,10}|{10,16}|{11,17}|{12,6}|{13,4}";
+ const char *Line =
+ "{0,6}|{1,8:X}|{2,=10}|{3,=10:5}|{4,=13}|{5,7:3}|{6,7:P2}|{7,"
+ "10:X8}|{8,-7:N}|{9,10:E4}|{10,16:N}|{11,17:D}|{12,6}|{13,"
+ "4:X}";
+
+ std::string S;
+ llvm::raw_string_ostream Stream(S);
+ Stream << formatv(Intro, std::tuple_size<Tuple>::value,
+ llvm::array_lengthof(Ts))
+ << "\n";
+ Stream << formatv(Header, "Char", "HexInt", "Str", "Ref", "std::str",
+ "double", "float", "pointer", "comma", "exp", "bigint",
+ "bigint2", "limit", "byte")
+ << "\n";
+ for (auto &Item : Ts) {
+ Stream << llvm::apply_tuple(format_tuple(Line), Item) << "\n";
+ }
+ Stream.flush();
+ const char *Expected =
+ R"foo(There are {14} items in the tuple, and {2} tuple(s) in the array.
+ Char| HexInt| Str | Ref | std::str | double| float| pointer|comma | exp| bigint| bigint2| limit|byte
+ a| 0x1| Str | | | 3.142|-17.53%|0x00000000|123,456|6.0200E+23|-908,234,908,423| 908234908422234| nan|0xAB
+ x| 0xDDB5B|LongerStr | Strin | std::string | -2.700| 8.21%|0x00000000|0 |6.6200E-34|-908,234,908,423| 908234908422234| INF| 0x0
+)foo";
+
+ EXPECT_EQ(Expected, S);
+}
+
+TEST(FormatVariadicTest, Range) {
+ std::vector<int> IntRange = {1, 1, 2, 3, 5, 8, 13};
+
+ // 1. Simple range with default separator and element style.
+ EXPECT_EQ("1, 1, 2, 3, 5, 8, 13",
+ formatv("{0}", make_range(IntRange.begin(), IntRange.end())).str());
+ EXPECT_EQ("1, 2, 3, 5, 8",
+ formatv("{0}", make_range(IntRange.begin() + 1, IntRange.end() - 1))
+ .str());
+
+ // 2. Non-default separator
+ EXPECT_EQ(
+ "1/1/2/3/5/8/13",
+ formatv("{0:$[/]}", make_range(IntRange.begin(), IntRange.end())).str());
+
+ // 3. Default separator, non-default element style.
+ EXPECT_EQ(
+ "0x1, 0x1, 0x2, 0x3, 0x5, 0x8, 0xd",
+ formatv("{0:@[x]}", make_range(IntRange.begin(), IntRange.end())).str());
+
+ // 4. Non-default separator and element style.
+ EXPECT_EQ(
+ "0x1 + 0x1 + 0x2 + 0x3 + 0x5 + 0x8 + 0xd",
+ formatv("{0:$[ + ]@[x]}", make_range(IntRange.begin(), IntRange.end()))
+ .str());
+
+ // 5. Element style and/or separator using alternate delimeters to allow using
+ // delimeter characters as part of the separator.
+ EXPECT_EQ(
+ "<0x1><0x1><0x2><0x3><0x5><0x8><0xd>",
+ formatv("<{0:$[><]@(x)}>", make_range(IntRange.begin(), IntRange.end()))
+ .str());
+ EXPECT_EQ(
+ "[0x1][0x1][0x2][0x3][0x5][0x8][0xd]",
+ formatv("[{0:$(][)@[x]}]", make_range(IntRange.begin(), IntRange.end()))
+ .str());
+ EXPECT_EQ(
+ "(0x1)(0x1)(0x2)(0x3)(0x5)(0x8)(0xd)",
+ formatv("({0:$<)(>@<x>})", make_range(IntRange.begin(), IntRange.end()))
+ .str());
+
+ // 5. Empty range.
+ EXPECT_EQ("", formatv("{0:$[+]@[x]}",
+ make_range(IntRange.begin(), IntRange.begin()))
+ .str());
+
+ // 6. Empty separator and style.
+ EXPECT_EQ("11235813",
+ formatv("{0:$[]@<>}", make_range(IntRange.begin(), IntRange.end()))
+ .str());
+}
+
+TEST(FormatVariadicTest, Adapter) {
+ class Negative : public FormatAdapter<int> {
+ public:
+ explicit Negative(int N) : FormatAdapter<int>(std::move(N)) {}
+ void format(raw_ostream &S, StringRef Options) override { S << -Item; }
+ };
+
+ EXPECT_EQ("-7", formatv("{0}", Negative(7)).str());
+
+ int N = 171;
+
+ EXPECT_EQ(" 171 ",
+ formatv("{0}", fmt_align(N, AlignStyle::Center, 7)).str());
+ EXPECT_EQ(" 171 ", formatv("{0}", fmt_pad(N, 1, 3)).str());
+ EXPECT_EQ("171171171171171", formatv("{0}", fmt_repeat(N, 5)).str());
+
+ EXPECT_EQ(" ABABABABAB ",
+ formatv("{0:X-}", fmt_pad(fmt_repeat(N, 5), 1, 3)).str());
+ EXPECT_EQ(" AB AB AB AB AB ",
+ formatv("{0,=34:X-}", fmt_repeat(fmt_pad(N, 1, 3), 5)).str());
+}
+
+TEST(FormatVariadicTest, ImplicitConversions) {
+ std::string S = formatv("{0} {1}", 1, 2);
+ EXPECT_EQ("1 2", S);
+
+ SmallString<4> S2 = formatv("{0} {1}", 1, 2);
+ EXPECT_EQ("1 2", S2);
+}
+
+TEST(FormatVariadicTest, FormatAdapter) {
+ EXPECT_EQ("Format", formatv("{0}", Format(1)).str());
+
+ Format var(1);
+ EXPECT_EQ("Format", formatv("{0}", var).str());
+ EXPECT_EQ("Format", formatv("{0}", std::move(var)).str());
+
+ // Not supposed to compile
+ // const Format cvar(1);
+ // EXPECT_EQ("Format", formatv("{0}", cvar).str());
+}
diff --git a/unittests/Support/GlobPatternTest.cpp b/unittests/Support/GlobPatternTest.cpp
new file mode 100644
index 000000000000..44d77266db1f
--- /dev/null
+++ b/unittests/Support/GlobPatternTest.cpp
@@ -0,0 +1,70 @@
+//===- llvm/unittest/Support/GlobPatternTest.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/GlobPattern.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+namespace {
+
+class GlobPatternTest : public ::testing::Test {};
+
+TEST_F(GlobPatternTest, Basics) {
+ Expected<GlobPattern> Pat1 = GlobPattern::create("");
+ EXPECT_TRUE((bool)Pat1);
+ EXPECT_TRUE(Pat1->match(""));
+ EXPECT_FALSE(Pat1->match("a"));
+
+ Expected<GlobPattern> Pat2 = GlobPattern::create("ab*c*def");
+ EXPECT_TRUE((bool)Pat2);
+ EXPECT_TRUE(Pat2->match("abcdef"));
+ EXPECT_TRUE(Pat2->match("abxcxdef"));
+ EXPECT_FALSE(Pat2->match(""));
+ EXPECT_FALSE(Pat2->match("xabcdef"));
+ EXPECT_FALSE(Pat2->match("abcdefx"));
+
+ Expected<GlobPattern> Pat3 = GlobPattern::create("a??c");
+ EXPECT_TRUE((bool)Pat3);
+ EXPECT_TRUE(Pat3->match("axxc"));
+ EXPECT_FALSE(Pat3->match("axxx"));
+ EXPECT_FALSE(Pat3->match(""));
+
+ Expected<GlobPattern> Pat4 = GlobPattern::create("[abc-fy-z]");
+ EXPECT_TRUE((bool)Pat4);
+ EXPECT_TRUE(Pat4->match("a"));
+ EXPECT_TRUE(Pat4->match("b"));
+ EXPECT_TRUE(Pat4->match("c"));
+ EXPECT_TRUE(Pat4->match("d"));
+ EXPECT_TRUE(Pat4->match("e"));
+ EXPECT_TRUE(Pat4->match("f"));
+ EXPECT_TRUE(Pat4->match("y"));
+ EXPECT_TRUE(Pat4->match("z"));
+ EXPECT_FALSE(Pat4->match("g"));
+ EXPECT_FALSE(Pat4->match(""));
+
+ Expected<GlobPattern> Pat5 = GlobPattern::create("[^abc-fy-z]");
+ EXPECT_TRUE((bool)Pat5);
+ EXPECT_TRUE(Pat5->match("g"));
+ EXPECT_FALSE(Pat5->match("a"));
+ EXPECT_FALSE(Pat5->match("b"));
+ EXPECT_FALSE(Pat5->match("c"));
+ EXPECT_FALSE(Pat5->match("d"));
+ EXPECT_FALSE(Pat5->match("e"));
+ EXPECT_FALSE(Pat5->match("f"));
+ EXPECT_FALSE(Pat5->match("y"));
+ EXPECT_FALSE(Pat5->match("z"));
+ EXPECT_FALSE(Pat5->match(""));
+}
+
+TEST_F(GlobPatternTest, Invalid) {
+ Expected<GlobPattern> Pat1 = GlobPattern::create("[");
+ EXPECT_FALSE((bool)Pat1);
+ handleAllErrors(Pat1.takeError(), [&](ErrorInfoBase &EIB) {});
+}
+}
diff --git a/unittests/Support/Host.cpp b/unittests/Support/Host.cpp
new file mode 100644
index 000000000000..934a60495427
--- /dev/null
+++ b/unittests/Support/Host.cpp
@@ -0,0 +1,48 @@
+//========- unittests/Support/Host.cpp - Host.cpp tests --------------========//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Host.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Triple.h"
+
+#include "gtest/gtest.h"
+
+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));
+ }
+};
+
+TEST_F(HostTest, NumPhysicalCores) {
+ int Num = sys::getHostNumPhysicalCores();
+
+ if (isSupportedArchAndOS())
+ ASSERT_GT(Num, 0);
+ else
+ ASSERT_EQ(Num, -1);
+}
diff --git a/unittests/Support/MD5Test.cpp b/unittests/Support/MD5Test.cpp
index c4fa5cd92c10..4d790254503e 100644
--- a/unittests/Support/MD5Test.cpp
+++ b/unittests/Support/MD5Test.cpp
@@ -57,4 +57,14 @@ TEST(MD5Test, MD5) {
"81948d1f1554f58cd1a56ebb01f808cb");
TestMD5Sum("abcdefghijklmnopqrstuvwxyz", "c3fcd3d76192e4007dfb496cca67e13b");
}
+
+TEST(MD5HashTest, MD5) {
+ ArrayRef<uint8_t> Input((const uint8_t *)"abcdefghijklmnopqrstuvwxyz", 26);
+ std::array<uint8_t, 16> Vec = MD5::hash(Input);
+ MD5::MD5Result MD5Res;
+ SmallString<32> Res;
+ memcpy(MD5Res, Vec.data(), Vec.size());
+ MD5::stringifyResult(MD5Res, Res);
+ EXPECT_EQ(Res, "c3fcd3d76192e4007dfb496cca67e13b");
+}
}
diff --git a/unittests/Support/MathExtrasTest.cpp b/unittests/Support/MathExtrasTest.cpp
index d373030881ec..b2c377978874 100644
--- a/unittests/Support/MathExtrasTest.cpp
+++ b/unittests/Support/MathExtrasTest.cpp
@@ -165,6 +165,18 @@ TEST(MathExtras, isPowerOf2_64) {
EXPECT_FALSE(isPowerOf2_64(0xABCDEF0ABCDEF0LL));
}
+TEST(MathExtras, PowerOf2Ceil) {
+ EXPECT_EQ(0U, PowerOf2Ceil(0U));
+ EXPECT_EQ(8U, PowerOf2Ceil(8U));
+ EXPECT_EQ(8U, PowerOf2Ceil(7U));
+}
+
+TEST(MathExtras, PowerOf2Floor) {
+ EXPECT_EQ(0U, PowerOf2Floor(0U));
+ EXPECT_EQ(8U, PowerOf2Floor(8U));
+ EXPECT_EQ(4U, PowerOf2Floor(7U));
+}
+
TEST(MathExtras, ByteSwap_32) {
EXPECT_EQ(0x44332211u, ByteSwap_32(0x11223344));
EXPECT_EQ(0xDDCCBBAAu, ByteSwap_32(0xAABBCCDD));
diff --git a/unittests/Support/MemoryBufferTest.cpp b/unittests/Support/MemoryBufferTest.cpp
index 963dcd91c8b6..0efa22c157d9 100644
--- a/unittests/Support/MemoryBufferTest.cpp
+++ b/unittests/Support/MemoryBufferTest.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include "gtest/gtest.h"
@@ -71,6 +72,7 @@ TEST_F(MemoryBufferTest, NullTerminator4K) {
SmallString<64> TestPath;
sys::fs::createTemporaryFile("MemoryBufferTest_NullTerminator4K", "temp",
TestFD, TestPath);
+ FileRemover Cleanup(TestPath);
raw_fd_ostream OF(TestFD, true, /*unbuffered=*/true);
for (unsigned i = 0; i < 4096 / 16; ++i) {
OF << "0123456789abcdef";
@@ -133,6 +135,7 @@ void MemoryBufferTest::testGetOpenFileSlice(bool Reopen) {
SmallString<64> TestPath;
// Create a temporary file and write data into it.
sys::fs::createTemporaryFile("prefix", "temp", TestFD, TestPath);
+ FileRemover Cleanup(TestPath);
// OF is responsible for closing the file; If the file is not
// reopened, it will be unbuffered so that the results are
// immediately visible through the fd.
@@ -182,6 +185,7 @@ TEST_F(MemoryBufferTest, slice) {
int FD;
SmallString<64> TestPath;
sys::fs::createTemporaryFile("MemoryBufferTest_Slice", "temp", FD, TestPath);
+ FileRemover Cleanup(TestPath);
raw_fd_ostream OF(FD, true, /*unbuffered=*/true);
for (unsigned i = 0; i < 0x2000 / 8; ++i) {
OF << "12345678";
diff --git a/unittests/Support/NativeFormatTests.cpp b/unittests/Support/NativeFormatTests.cpp
new file mode 100644
index 000000000000..52acb6a99337
--- /dev/null
+++ b/unittests/Support/NativeFormatTests.cpp
@@ -0,0 +1,176 @@
+//===- llvm/unittest/Support/NativeFormatTests.cpp - formatting 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/SmallString.h"
+#include "llvm/Support/NativeFormatting.h"
+#include "llvm/Support/raw_ostream.h"
+#include "gtest/gtest.h"
+
+#include <type_traits>
+
+using namespace llvm;
+
+namespace {
+
+template <typename T> std::string format_number(T N, IntegerStyle Style) {
+ std::string S;
+ llvm::raw_string_ostream Str(S);
+ write_integer(Str, N, 0, Style);
+ Str.flush();
+ return S;
+}
+
+std::string format_number(uint64_t N, HexPrintStyle Style,
+ Optional<size_t> Width = None) {
+ std::string S;
+ llvm::raw_string_ostream Str(S);
+ write_hex(Str, N, Style, Width);
+ Str.flush();
+ return S;
+}
+
+std::string format_number(double D, FloatStyle Style,
+ Optional<size_t> Precision = None) {
+ std::string S;
+ llvm::raw_string_ostream Str(S);
+ write_double(Str, D, Style, Precision);
+ Str.flush();
+ return S;
+}
+
+// Test basic number formatting with various styles and default width and
+// precision.
+TEST(NativeFormatTest, BasicIntegerTests) {
+ // Simple integers with no decimal.
+ EXPECT_EQ("0", format_number(0, IntegerStyle::Integer));
+ EXPECT_EQ("2425", format_number(2425, IntegerStyle::Integer));
+ EXPECT_EQ("-2425", format_number(-2425, IntegerStyle::Integer));
+
+ EXPECT_EQ("0", format_number(0LL, IntegerStyle::Integer));
+ EXPECT_EQ("257257257235709",
+ format_number(257257257235709LL, IntegerStyle::Integer));
+ EXPECT_EQ("-257257257235709",
+ format_number(-257257257235709LL, IntegerStyle::Integer));
+
+ // Number formatting.
+ EXPECT_EQ("0", format_number(0, IntegerStyle::Number));
+ EXPECT_EQ("2,425", format_number(2425, IntegerStyle::Number));
+ EXPECT_EQ("-2,425", format_number(-2425, IntegerStyle::Number));
+ EXPECT_EQ("257,257,257,235,709",
+ format_number(257257257235709LL, IntegerStyle::Number));
+ EXPECT_EQ("-257,257,257,235,709",
+ format_number(-257257257235709LL, IntegerStyle::Number));
+
+ // Hex formatting.
+ // lower case, prefix.
+ EXPECT_EQ("0x0", format_number(0, HexPrintStyle::PrefixLower));
+ EXPECT_EQ("0xbeef", format_number(0xbeefLL, HexPrintStyle::PrefixLower));
+ EXPECT_EQ("0xdeadbeef",
+ format_number(0xdeadbeefLL, HexPrintStyle::PrefixLower));
+
+ // upper-case, prefix.
+ EXPECT_EQ("0x0", format_number(0, HexPrintStyle::PrefixUpper));
+ EXPECT_EQ("0xBEEF", format_number(0xbeefLL, HexPrintStyle::PrefixUpper));
+ EXPECT_EQ("0xDEADBEEF",
+ format_number(0xdeadbeefLL, HexPrintStyle::PrefixUpper));
+
+ // lower-case, no prefix
+ EXPECT_EQ("0", format_number(0, HexPrintStyle::Lower));
+ EXPECT_EQ("beef", format_number(0xbeefLL, HexPrintStyle::Lower));
+ EXPECT_EQ("deadbeef", format_number(0xdeadbeefLL, HexPrintStyle::Lower));
+
+ // upper-case, no prefix.
+ EXPECT_EQ("0", format_number(0, HexPrintStyle::Upper));
+ EXPECT_EQ("BEEF", format_number(0xbeef, HexPrintStyle::Upper));
+ EXPECT_EQ("DEADBEEF", format_number(0xdeadbeef, HexPrintStyle::Upper));
+}
+
+// Test basic floating point formatting with various styles and default width
+// and precision.
+TEST(NativeFormatTest, BasicFloatingPointTests) {
+ // Double
+ EXPECT_EQ("0.000000e+00", format_number(0.0, FloatStyle::Exponent));
+ EXPECT_EQ("-0.000000e+00", format_number(-0.0, FloatStyle::Exponent));
+ EXPECT_EQ("1.100000e+00", format_number(1.1, FloatStyle::Exponent));
+ EXPECT_EQ("1.100000E+00", format_number(1.1, FloatStyle::ExponentUpper));
+
+ // Default precision is 2 for floating points.
+ EXPECT_EQ("1.10", format_number(1.1, FloatStyle::Fixed));
+ EXPECT_EQ("1.34", format_number(1.34, FloatStyle::Fixed));
+ EXPECT_EQ("1.34", format_number(1.344, FloatStyle::Fixed));
+ EXPECT_EQ("1.35", format_number(1.346, FloatStyle::Fixed));
+}
+
+// Test common boundary cases and min/max conditions.
+TEST(NativeFormatTest, BoundaryTests) {
+ // Min and max.
+ EXPECT_EQ("18446744073709551615",
+ format_number(UINT64_MAX, IntegerStyle::Integer));
+
+ EXPECT_EQ("9223372036854775807",
+ format_number(INT64_MAX, IntegerStyle::Integer));
+ EXPECT_EQ("-9223372036854775808",
+ format_number(INT64_MIN, IntegerStyle::Integer));
+
+ EXPECT_EQ("4294967295", format_number(UINT32_MAX, IntegerStyle::Integer));
+ EXPECT_EQ("2147483647", format_number(INT32_MAX, IntegerStyle::Integer));
+ EXPECT_EQ("-2147483648", format_number(INT32_MIN, IntegerStyle::Integer));
+
+ EXPECT_EQ("nan", format_number(std::numeric_limits<double>::quiet_NaN(),
+ FloatStyle::Fixed));
+ EXPECT_EQ("INF", format_number(std::numeric_limits<double>::infinity(),
+ FloatStyle::Fixed));
+}
+
+TEST(NativeFormatTest, HexTests) {
+ // Test hex formatting with different widths and precisions.
+
+ // Width less than the value should print the full value anyway.
+ EXPECT_EQ("0x0", format_number(0, HexPrintStyle::PrefixLower, 0));
+ EXPECT_EQ("0xabcde", format_number(0xABCDE, HexPrintStyle::PrefixLower, 3));
+
+ // Precision greater than the value should pad with 0s.
+ // TODO: The prefix should not be counted in the precision. But unfortunately
+ // it is and we have to live with it unless we fix all existing users of
+ // prefixed hex formatting.
+ EXPECT_EQ("0x000", format_number(0, HexPrintStyle::PrefixLower, 5));
+ EXPECT_EQ("0x0abcde", format_number(0xABCDE, HexPrintStyle::PrefixLower, 8));
+
+ EXPECT_EQ("00000", format_number(0, HexPrintStyle::Lower, 5));
+ EXPECT_EQ("000abcde", format_number(0xABCDE, HexPrintStyle::Lower, 8));
+
+ // Try printing more digits than can fit in a uint64.
+ EXPECT_EQ("0x00000000000000abcde",
+ format_number(0xABCDE, HexPrintStyle::PrefixLower, 21));
+}
+
+TEST(NativeFormatTest, IntegerTests) {
+ EXPECT_EQ("-10", format_number(-10, IntegerStyle::Integer));
+ EXPECT_EQ("-100", format_number(-100, IntegerStyle::Integer));
+ EXPECT_EQ("-1000", format_number(-1000, IntegerStyle::Integer));
+ EXPECT_EQ("-1234567890", format_number(-1234567890, IntegerStyle::Integer));
+ EXPECT_EQ("10", format_number(10, IntegerStyle::Integer));
+ EXPECT_EQ("100", format_number(100, IntegerStyle::Integer));
+ EXPECT_EQ("1000", format_number(1000, IntegerStyle::Integer));
+ EXPECT_EQ("1234567890", format_number(1234567890, IntegerStyle::Integer));
+}
+
+TEST(NativeFormatTest, CommaTests) {
+ EXPECT_EQ("0", format_number(0, IntegerStyle::Number));
+ EXPECT_EQ("10", format_number(10, IntegerStyle::Number));
+ EXPECT_EQ("100", format_number(100, IntegerStyle::Number));
+ EXPECT_EQ("1,000", format_number(1000, IntegerStyle::Number));
+ EXPECT_EQ("1,234,567,890", format_number(1234567890, IntegerStyle::Number));
+
+ EXPECT_EQ("-10", format_number(-10, IntegerStyle::Number));
+ EXPECT_EQ("-100", format_number(-100, IntegerStyle::Number));
+ EXPECT_EQ("-1,000", format_number(-1000, IntegerStyle::Number));
+ EXPECT_EQ("-1,234,567,890", format_number(-1234567890, IntegerStyle::Number));
+}
+}
diff --git a/unittests/Support/Path.cpp b/unittests/Support/Path.cpp
index 1a6ffa50e983..30eaa8b278ab 100644
--- a/unittests/Support/Path.cpp
+++ b/unittests/Support/Path.cpp
@@ -8,10 +8,12 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/Path.h"
+#include "llvm/ADT/STLExtras.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/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include "gtest/gtest.h"
@@ -120,22 +122,24 @@ TEST(Support, Path) {
}
ASSERT_TRUE(ComponentStack.empty());
- path::has_root_path(*i);
- path::root_path(*i);
- path::has_root_name(*i);
- path::root_name(*i);
- path::has_root_directory(*i);
- path::root_directory(*i);
- path::has_parent_path(*i);
- path::parent_path(*i);
- path::has_filename(*i);
- path::filename(*i);
- path::has_stem(*i);
- path::stem(*i);
- path::has_extension(*i);
- path::extension(*i);
- path::is_absolute(*i);
- path::is_relative(*i);
+ // Crash test most of the API - since we're iterating over all of our paths
+ // here there isn't really anything reasonable to assert on in the results.
+ (void)path::has_root_path(*i);
+ (void)path::root_path(*i);
+ (void)path::has_root_name(*i);
+ (void)path::root_name(*i);
+ (void)path::has_root_directory(*i);
+ (void)path::root_directory(*i);
+ (void)path::has_parent_path(*i);
+ (void)path::parent_path(*i);
+ (void)path::has_filename(*i);
+ (void)path::filename(*i);
+ (void)path::has_stem(*i);
+ (void)path::stem(*i);
+ (void)path::has_extension(*i);
+ (void)path::extension(*i);
+ (void)path::is_absolute(*i);
+ (void)path::is_relative(*i);
SmallString<128> temp_store;
temp_store = *i;
@@ -486,6 +490,10 @@ TEST_F(FileSystemTest, Unique) {
fs::createUniqueDirectory("dir2", Dir2));
ASSERT_NO_ERROR(fs::getUniqueID(Dir2.c_str(), F2));
ASSERT_NE(F1, F2);
+ ASSERT_NO_ERROR(fs::remove(Dir1));
+ ASSERT_NO_ERROR(fs::remove(Dir2));
+ ASSERT_NO_ERROR(fs::remove(TempPath2));
+ ASSERT_NO_ERROR(fs::remove(TempPath));
}
TEST_F(FileSystemTest, TempFiles) {
@@ -529,6 +537,7 @@ TEST_F(FileSystemTest, TempFiles) {
SmallString<64> TempPath3;
ASSERT_NO_ERROR(fs::createTemporaryFile("prefix", "", TempPath3));
ASSERT_FALSE(TempPath3.endswith("."));
+ FileRemover Cleanup3(TempPath3);
// Create a hard link to Temp1.
ASSERT_NO_ERROR(fs::create_link(Twine(TempPath), Twine(TempPath2)));
@@ -677,16 +686,15 @@ TEST_F(FileSystemTest, DirectoryIteration) {
i.no_push();
visited.push_back(path::filename(i->path()));
}
- v_t::const_iterator a0 = std::find(visited.begin(), visited.end(), "a0");
- v_t::const_iterator aa1 = std::find(visited.begin(), visited.end(), "aa1");
- v_t::const_iterator ab1 = std::find(visited.begin(), visited.end(), "ab1");
- v_t::const_iterator dontlookhere = std::find(visited.begin(), visited.end(),
- "dontlookhere");
- v_t::const_iterator da1 = std::find(visited.begin(), visited.end(), "da1");
- v_t::const_iterator z0 = std::find(visited.begin(), visited.end(), "z0");
- v_t::const_iterator za1 = std::find(visited.begin(), visited.end(), "za1");
- v_t::const_iterator pop = std::find(visited.begin(), visited.end(), "pop");
- v_t::const_iterator p1 = std::find(visited.begin(), visited.end(), "p1");
+ v_t::const_iterator a0 = find(visited, "a0");
+ v_t::const_iterator aa1 = find(visited, "aa1");
+ v_t::const_iterator ab1 = find(visited, "ab1");
+ v_t::const_iterator dontlookhere = find(visited, "dontlookhere");
+ v_t::const_iterator da1 = find(visited, "da1");
+ v_t::const_iterator z0 = find(visited, "z0");
+ v_t::const_iterator za1 = find(visited, "za1");
+ v_t::const_iterator pop = find(visited, "pop");
+ v_t::const_iterator p1 = find(visited, "p1");
// Make sure that each path was visited correctly.
ASSERT_NE(a0, visited.end());
@@ -851,6 +859,8 @@ TEST_F(FileSystemTest, Resize) {
fs::file_status Status;
ASSERT_NO_ERROR(fs::status(FD, Status));
ASSERT_EQ(Status.getSize(), 123U);
+ ::close(FD);
+ ASSERT_NO_ERROR(fs::remove(TempPath));
}
TEST_F(FileSystemTest, FileMapping) {
@@ -874,21 +884,25 @@ TEST_F(FileSystemTest, FileMapping) {
mfr.data()[Val.size()] = 0;
// Unmap temp file
}
+ ASSERT_EQ(close(FileDescriptor), 0);
// Map it back in read-only
- int FD;
- EC = fs::openFileForRead(Twine(TempPath), FD);
- ASSERT_NO_ERROR(EC);
- fs::mapped_file_region mfr(FD, fs::mapped_file_region::readonly, Size, 0, EC);
- ASSERT_NO_ERROR(EC);
-
- // Verify content
- EXPECT_EQ(StringRef(mfr.const_data()), Val);
-
- // Unmap temp file
- fs::mapped_file_region m(FD, fs::mapped_file_region::readonly, Size, 0, EC);
- ASSERT_NO_ERROR(EC);
- ASSERT_EQ(close(FD), 0);
+ {
+ int FD;
+ EC = fs::openFileForRead(Twine(TempPath), FD);
+ ASSERT_NO_ERROR(EC);
+ fs::mapped_file_region mfr(FD, fs::mapped_file_region::readonly, Size, 0, EC);
+ ASSERT_NO_ERROR(EC);
+
+ // Verify content
+ EXPECT_EQ(StringRef(mfr.const_data()), Val);
+
+ // Unmap temp file
+ fs::mapped_file_region m(FD, fs::mapped_file_region::readonly, Size, 0, EC);
+ ASSERT_NO_ERROR(EC);
+ ASSERT_EQ(close(FD), 0);
+ }
+ ASSERT_NO_ERROR(fs::remove(TempPath));
}
TEST(Support, NormalizePath) {
@@ -953,6 +967,8 @@ TEST(Support, RemoveDots) {
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));
SmallString<64> Path1(".\\.\\c");
EXPECT_TRUE(path::remove_dots(Path1, true));
@@ -964,6 +980,10 @@ TEST(Support, RemoveDots) {
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));
@@ -1002,6 +1022,7 @@ TEST_F(FileSystemTest, PathFromFD) {
SmallString<64> TempPath;
ASSERT_NO_ERROR(
fs::createTemporaryFile("prefix", "temp", FileDescriptor, TempPath));
+ FileRemover Cleanup(TempPath);
// Make sure it exists.
ASSERT_TRUE(sys::fs::exists(Twine(TempPath)));
@@ -1030,6 +1051,7 @@ TEST_F(FileSystemTest, PathFromFDWin32) {
SmallString<64> TempPath;
ASSERT_NO_ERROR(
fs::createTemporaryFile("prefix", "temp", FileDescriptor, TempPath));
+ FileRemover Cleanup(TempPath);
// Make sure it exists.
ASSERT_TRUE(sys::fs::exists(Twine(TempPath)));
@@ -1066,6 +1088,7 @@ TEST_F(FileSystemTest, PathFromFDUnicode) {
ASSERT_NO_ERROR(
fs::createTemporaryFile("\xCF\x80r\xC2\xB2",
"\xE2\x84\xB5.0", FileDescriptor, TempPath));
+ FileRemover Cleanup(TempPath);
// Make sure it exists.
ASSERT_TRUE(sys::fs::exists(Twine(TempPath)));
@@ -1089,6 +1112,7 @@ TEST_F(FileSystemTest, OpenFileForRead) {
SmallString<64> TempPath;
ASSERT_NO_ERROR(
fs::createTemporaryFile("prefix", "temp", FileDescriptor, TempPath));
+ FileRemover Cleanup(TempPath);
// Make sure it exists.
ASSERT_TRUE(sys::fs::exists(Twine(TempPath)));
diff --git a/unittests/Support/RegexTest.cpp b/unittests/Support/RegexTest.cpp
index c045c49bc3d7..5e3ce39f0057 100644
--- a/unittests/Support/RegexTest.cpp
+++ b/unittests/Support/RegexTest.cpp
@@ -151,6 +151,24 @@ TEST_F(RegexTest, MoveAssign) {
Regex r2("abc");
r2 = std::move(r1);
EXPECT_TRUE(r2.match("916"));
+ std::string Error;
+ EXPECT_FALSE(r1.isValid(Error));
+}
+
+TEST_F(RegexTest, NoArgConstructor) {
+ std::string Error;
+ Regex r1;
+ EXPECT_FALSE(r1.isValid(Error));
+ EXPECT_EQ("invalid regular expression", Error);
+ r1 = Regex("abc");
+ EXPECT_TRUE(r1.isValid(Error));
+}
+
+TEST_F(RegexTest, MatchInvalid) {
+ Regex r1;
+ std::string Error;
+ EXPECT_FALSE(r1.isValid(Error));
+ EXPECT_FALSE(r1.match("X"));
}
}
diff --git a/unittests/Support/SpecialCaseListTest.cpp b/unittests/Support/SpecialCaseListTest.cpp
index 0657f8003e8b..e86eecb527bb 100644
--- a/unittests/Support/SpecialCaseListTest.cpp
+++ b/unittests/Support/SpecialCaseListTest.cpp
@@ -130,6 +130,63 @@ TEST_F(SpecialCaseListTest, MultipleBlacklists) {
EXPECT_TRUE(SCL->inSection("src", "ban", "init"));
EXPECT_TRUE(SCL->inSection("src", "tomfoolery"));
EXPECT_TRUE(SCL->inSection("src", "tomfoglery"));
+ for (auto &Path : Files)
+ sys::fs::remove(Path);
+}
+
+TEST_F(SpecialCaseListTest, NoTrigramsInRules) {
+ std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("fun:b.r\n"
+ "fun:za*az\n");
+ EXPECT_TRUE(SCL->inSection("fun", "bar"));
+ EXPECT_FALSE(SCL->inSection("fun", "baz"));
+ EXPECT_TRUE(SCL->inSection("fun", "zakaz"));
+ EXPECT_FALSE(SCL->inSection("fun", "zaraza"));
+}
+
+TEST_F(SpecialCaseListTest, NoTrigramsInARule) {
+ std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("fun:*bar*\n"
+ "fun:za*az\n");
+ EXPECT_TRUE(SCL->inSection("fun", "abara"));
+ EXPECT_FALSE(SCL->inSection("fun", "bor"));
+ EXPECT_TRUE(SCL->inSection("fun", "zakaz"));
+ EXPECT_FALSE(SCL->inSection("fun", "zaraza"));
+}
+
+TEST_F(SpecialCaseListTest, RepetitiveRule) {
+ std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("fun:*bar*bar*bar*bar*\n"
+ "fun:bar*\n");
+ EXPECT_TRUE(SCL->inSection("fun", "bara"));
+ EXPECT_FALSE(SCL->inSection("fun", "abara"));
+ EXPECT_TRUE(SCL->inSection("fun", "barbarbarbar"));
+ EXPECT_TRUE(SCL->inSection("fun", "abarbarbarbar"));
+ EXPECT_FALSE(SCL->inSection("fun", "abarbarbar"));
+}
+
+TEST_F(SpecialCaseListTest, SpecialSymbolRule) {
+ std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("src:*c\\+\\+abi*\n");
+ EXPECT_TRUE(SCL->inSection("src", "c++abi"));
+ EXPECT_FALSE(SCL->inSection("src", "c\\+\\+abi"));
+}
+
+TEST_F(SpecialCaseListTest, PopularTrigram) {
+ std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("fun:*aaaaaa*\n"
+ "fun:*aaaaa*\n"
+ "fun:*aaaa*\n"
+ "fun:*aaa*\n");
+ EXPECT_TRUE(SCL->inSection("fun", "aaa"));
+ EXPECT_TRUE(SCL->inSection("fun", "aaaa"));
+ EXPECT_TRUE(SCL->inSection("fun", "aaaabbbaaa"));
+}
+
+TEST_F(SpecialCaseListTest, EscapedSymbols) {
+ std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("src:*c\\+\\+abi*\n"
+ "src:*hello\\\\world*\n");
+ EXPECT_TRUE(SCL->inSection("src", "dir/c++abi"));
+ EXPECT_FALSE(SCL->inSection("src", "dir/c\\+\\+abi"));
+ EXPECT_FALSE(SCL->inSection("src", "c\\+\\+abi"));
+ EXPECT_TRUE(SCL->inSection("src", "C:\\hello\\world"));
+ EXPECT_TRUE(SCL->inSection("src", "hello\\world"));
+ EXPECT_FALSE(SCL->inSection("src", "hello\\\\world"));
}
}
diff --git a/unittests/Support/StreamingMemoryObjectTest.cpp b/unittests/Support/StreamingMemoryObjectTest.cpp
deleted file mode 100644
index 836dfa9084f5..000000000000
--- a/unittests/Support/StreamingMemoryObjectTest.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-//===- unittests/Support/StreamingMemoryObjectTest.cpp --------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/StreamingMemoryObject.h"
-#include "gtest/gtest.h"
-#include <string.h>
-
-using namespace llvm;
-
-namespace {
-
-class NullDataStreamer : public DataStreamer {
- size_t GetBytes(unsigned char *Buffer, size_t Length) override {
- memset(Buffer, 0, Length);
- return Length;
- }
-};
-
-class BufferStreamer : public DataStreamer {
- StringRef Buffer;
-
-public:
- BufferStreamer(StringRef Buffer) : Buffer(Buffer) {}
- size_t GetBytes(unsigned char *OutBuffer, size_t Length) override {
- if (Length >= Buffer.size())
- Length = Buffer.size();
-
- std::copy(Buffer.begin(), Buffer.begin() + Length, OutBuffer);
- Buffer = Buffer.drop_front(Length);
- return Length;
- }
-};
-
-TEST(StreamingMemoryObjectTest, isValidAddress) {
- auto DS = make_unique<NullDataStreamer>();
- StreamingMemoryObject O(std::move(DS));
- EXPECT_TRUE(O.isValidAddress(32 * 1024));
-}
-
-TEST(StreamingMemoryObjectTest, setKnownObjectSize) {
- auto DS = make_unique<NullDataStreamer>();
- StreamingMemoryObject O(std::move(DS));
- uint8_t Buf[32];
- EXPECT_EQ(16u, O.readBytes(Buf, 16, 0));
- O.setKnownObjectSize(24);
- EXPECT_EQ(8u, O.readBytes(Buf, 16, 16));
-}
-
-TEST(StreamingMemoryObjectTest, getPointer) {
- uint8_t InputBuffer[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
- StreamingMemoryObject O(make_unique<BufferStreamer>(StringRef(
- reinterpret_cast<const char *>(InputBuffer), sizeof(InputBuffer))));
-
- EXPECT_TRUE(std::equal(InputBuffer + 1, InputBuffer + 2, O.getPointer(1, 2)));
- EXPECT_TRUE(std::equal(InputBuffer + 3, InputBuffer + 7, O.getPointer(3, 4)));
- EXPECT_TRUE(std::equal(InputBuffer + 4, InputBuffer + 8, O.getPointer(4, 5)));
- EXPECT_TRUE(std::equal(InputBuffer, InputBuffer + 8, O.getPointer(0, 20)));
-}
-
-} // end namespace
diff --git a/unittests/Support/TargetParserTest.cpp b/unittests/Support/TargetParserTest.cpp
index 21994f27b73c..a3d806f76fb5 100644
--- a/unittests/Support/TargetParserTest.cpp
+++ b/unittests/Support/TargetParserTest.cpp
@@ -7,86 +7,718 @@
//
//===----------------------------------------------------------------------===//
-#include "gtest/gtest.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/ARMBuildAttributes.h"
#include "llvm/Support/TargetParser.h"
+#include "gtest/gtest.h"
+#include <string>
using namespace llvm;
namespace {
-static const unsigned kAArch64ArchKinds[] = {
-#define AARCH64_ARCH(NAME, ID, CPU_ATTR, SUB_ARCH, ARCH_ATTR, ARCH_FPU, \
- ARCH_BASE_EXT) \
- llvm::ARM::ID,
-#include "llvm/Support/AArch64TargetParser.def"
-#undef AARCH64_ARCH
-};
-
-template <typename T, size_t N>
-bool contains(const T (&array)[N], const T element) {
- return std::find(std::begin(array), std::end(array), element) !=
- std::end(array);
-}
-
-TEST(TargetParserTest, ARMArchName) {
- for (ARM::ArchKind AK = static_cast<ARM::ArchKind>(0);
- AK <= ARM::ArchKind::AK_LAST;
- AK = static_cast<ARM::ArchKind>(static_cast<unsigned>(AK) + 1))
- EXPECT_TRUE(AK == ARM::AK_LAST ? ARM::getArchName(AK).empty()
- : !ARM::getArchName(AK).empty());
-}
-
-TEST(TargetParserTest, ARMCPUAttr) {
- for (ARM::ArchKind AK = static_cast<ARM::ArchKind>(0);
- AK <= ARM::ArchKind::AK_LAST;
- AK = static_cast<ARM::ArchKind>(static_cast<unsigned>(AK) + 1))
- EXPECT_TRUE((AK == ARM::AK_INVALID || AK == ARM::AK_LAST)
- ? ARM::getCPUAttr(AK).empty()
- : !ARM::getCPUAttr(AK).empty());
-}
-
-TEST(TargetParserTest, ARMSubArch) {
- for (ARM::ArchKind AK = static_cast<ARM::ArchKind>(0);
- AK <= ARM::ArchKind::AK_LAST;
- AK = static_cast<ARM::ArchKind>(static_cast<unsigned>(AK) + 1))
- EXPECT_TRUE((AK == ARM::AK_INVALID || AK == ARM::AK_IWMMXT ||
- AK == ARM::AK_IWMMXT2 || AK == ARM::AK_LAST)
- ? ARM::getSubArch(AK).empty()
- : !ARM::getSubArch(AK).empty());
-}
-
-TEST(TargetParserTest, ARMFPUName) {
+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"};
+
+bool testARMCPU(StringRef CPUName, StringRef ExpectedArch,
+ StringRef ExpectedFPU, unsigned ExpectedFlags,
+ StringRef CPUAttr) {
+ unsigned ArchKind = ARM::parseCPUArch(CPUName);
+ bool pass = ARM::getArchName(ArchKind).equals(ExpectedArch);
+ unsigned FPUKind = ARM::getDefaultFPU(CPUName, ArchKind);
+ pass &= ARM::getFPUName(FPUKind).equals(ExpectedFPU);
+
+ unsigned ExtKind = ARM::getDefaultExtensions(CPUName, ArchKind);
+ if (ExtKind > 1 && (ExtKind & ARM::AEK_NONE))
+ pass &= ((ExtKind ^ ARM::AEK_NONE) == ExpectedFlags);
+ else
+ pass &= (ExtKind == ExpectedFlags);
+
+ pass &= ARM::getCPUAttr(ArchKind).equals(CPUAttr);
+
+ return pass;
+}
+
+TEST(TargetParserTest, testARMCPU) {
+ EXPECT_TRUE(testARMCPU("invalid", "invalid", "invalid",
+ ARM::AEK_NONE, ""));
+ EXPECT_TRUE(testARMCPU("generic", "invalid", "none",
+ ARM::AEK_NONE, ""));
+
+ EXPECT_TRUE(testARMCPU("arm2", "armv2", "none",
+ ARM::AEK_NONE, "2"));
+ EXPECT_TRUE(testARMCPU("arm3", "armv2a", "none",
+ ARM::AEK_NONE, "2A"));
+ EXPECT_TRUE(testARMCPU("arm6", "armv3", "none",
+ ARM::AEK_NONE, "3"));
+ EXPECT_TRUE(testARMCPU("arm7m", "armv3m", "none",
+ ARM::AEK_NONE, "3M"));
+ EXPECT_TRUE(testARMCPU("arm8", "armv4", "none",
+ ARM::AEK_NONE, "4"));
+ EXPECT_TRUE(testARMCPU("arm810", "armv4", "none",
+ ARM::AEK_NONE, "4"));
+ EXPECT_TRUE(testARMCPU("strongarm", "armv4", "none",
+ ARM::AEK_NONE, "4"));
+ EXPECT_TRUE(testARMCPU("strongarm110", "armv4", "none",
+ ARM::AEK_NONE, "4"));
+ EXPECT_TRUE(testARMCPU("strongarm1100", "armv4", "none",
+ ARM::AEK_NONE, "4"));
+ EXPECT_TRUE(testARMCPU("strongarm1110", "armv4", "none",
+ ARM::AEK_NONE, "4"));
+ EXPECT_TRUE(testARMCPU("arm7tdmi", "armv4t", "none",
+ ARM::AEK_NONE, "4T"));
+ EXPECT_TRUE(testARMCPU("arm7tdmi-s", "armv4t", "none",
+ ARM::AEK_NONE, "4T"));
+ EXPECT_TRUE(testARMCPU("arm710t", "armv4t", "none",
+ ARM::AEK_NONE, "4T"));
+ EXPECT_TRUE(testARMCPU("arm720t", "armv4t", "none",
+ ARM::AEK_NONE, "4T"));
+ EXPECT_TRUE(testARMCPU("arm9", "armv4t", "none",
+ ARM::AEK_NONE, "4T"));
+ EXPECT_TRUE(testARMCPU("arm9tdmi", "armv4t", "none",
+ ARM::AEK_NONE, "4T"));
+ EXPECT_TRUE(testARMCPU("arm920", "armv4t", "none",
+ ARM::AEK_NONE, "4T"));
+ EXPECT_TRUE(testARMCPU("arm920t", "armv4t", "none",
+ ARM::AEK_NONE, "4T"));
+ EXPECT_TRUE(testARMCPU("arm922t", "armv4t", "none",
+ ARM::AEK_NONE, "4T"));
+ EXPECT_TRUE(testARMCPU("arm9312", "armv4t", "none",
+ ARM::AEK_NONE, "4T"));
+ EXPECT_TRUE(testARMCPU("arm940t", "armv4t", "none",
+ ARM::AEK_NONE, "4T"));
+ EXPECT_TRUE(testARMCPU("ep9312", "armv4t", "none",
+ ARM::AEK_NONE, "4T"));
+ EXPECT_TRUE(testARMCPU("arm10tdmi", "armv5t", "none",
+ ARM::AEK_NONE, "5T"));
+ EXPECT_TRUE(testARMCPU("arm1020t", "armv5t", "none",
+ ARM::AEK_NONE, "5T"));
+ EXPECT_TRUE(testARMCPU("arm9e", "armv5te", "none",
+ ARM::AEK_DSP, "5TE"));
+ EXPECT_TRUE(testARMCPU("arm946e-s", "armv5te", "none",
+ ARM::AEK_DSP, "5TE"));
+ EXPECT_TRUE(testARMCPU("arm966e-s", "armv5te", "none",
+ ARM::AEK_DSP, "5TE"));
+ EXPECT_TRUE(testARMCPU("arm968e-s", "armv5te", "none",
+ ARM::AEK_DSP, "5TE"));
+ EXPECT_TRUE(testARMCPU("arm10e", "armv5te", "none",
+ ARM::AEK_DSP, "5TE"));
+ EXPECT_TRUE(testARMCPU("arm1020e", "armv5te", "none",
+ ARM::AEK_DSP, "5TE"));
+ EXPECT_TRUE(testARMCPU("arm1022e", "armv5te", "none",
+ ARM::AEK_DSP, "5TE"));
+ EXPECT_TRUE(testARMCPU("arm926ej-s", "armv5tej", "none",
+ ARM::AEK_DSP, "5TEJ"));
+ EXPECT_TRUE(testARMCPU("arm1136j-s", "armv6", "none",
+ ARM::AEK_DSP, "6"));
+ EXPECT_TRUE(testARMCPU("arm1136jf-s", "armv6", "vfpv2",
+ ARM::AEK_DSP, "6"));
+ EXPECT_TRUE(testARMCPU("arm1136jz-s", "armv6", "none",
+ ARM::AEK_DSP, "6"));
+ EXPECT_TRUE(testARMCPU("arm1176j-s", "armv6k", "none",
+ ARM::AEK_DSP, "6K"));
+ EXPECT_TRUE(testARMCPU("arm1176jz-s", "armv6kz", "none",
+ ARM::AEK_SEC | ARM::AEK_DSP, "6KZ"));
+ EXPECT_TRUE(testARMCPU("mpcore", "armv6k", "vfpv2",
+ ARM::AEK_DSP, "6K"));
+ EXPECT_TRUE(testARMCPU("mpcorenovfp", "armv6k", "none",
+ ARM::AEK_DSP, "6K"));
+ EXPECT_TRUE(testARMCPU("arm1176jzf-s", "armv6kz", "vfpv2",
+ ARM::AEK_SEC | ARM::AEK_DSP, "6KZ"));
+ EXPECT_TRUE(testARMCPU("arm1156t2-s", "armv6t2", "none",
+ ARM::AEK_DSP, "6T2"));
+ EXPECT_TRUE(testARMCPU("arm1156t2f-s", "armv6t2", "vfpv2",
+ ARM::AEK_DSP, "6T2"));
+ EXPECT_TRUE(testARMCPU("cortex-m0", "armv6-m", "none",
+ ARM::AEK_NONE, "6-M"));
+ EXPECT_TRUE(testARMCPU("cortex-m0plus", "armv6-m", "none",
+ ARM::AEK_NONE, "6-M"));
+ EXPECT_TRUE(testARMCPU("cortex-m1", "armv6-m", "none",
+ ARM::AEK_NONE, "6-M"));
+ EXPECT_TRUE(testARMCPU("sc000", "armv6-m", "none",
+ ARM::AEK_NONE, "6-M"));
+ EXPECT_TRUE(testARMCPU("cortex-a5", "armv7-a", "neon-vfpv4",
+ ARM::AEK_MP | ARM::AEK_SEC | ARM::AEK_DSP, "7-A"));
+ EXPECT_TRUE(testARMCPU("cortex-a7", "armv7-a", "neon-vfpv4",
+ ARM::AEK_HWDIV | ARM::AEK_HWDIVARM | ARM::AEK_MP |
+ ARM::AEK_SEC | ARM::AEK_VIRT | ARM::AEK_DSP,
+ "7-A"));
+ EXPECT_TRUE(testARMCPU("cortex-a8", "armv7-a", "neon",
+ ARM::AEK_SEC | ARM::AEK_DSP, "7-A"));
+ EXPECT_TRUE(testARMCPU("cortex-a9", "armv7-a", "neon-fp16",
+ ARM::AEK_MP | ARM::AEK_SEC | ARM::AEK_DSP, "7-A"));
+ EXPECT_TRUE(testARMCPU("cortex-a12", "armv7-a", "neon-vfpv4",
+ ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT |
+ ARM::AEK_HWDIVARM | ARM::AEK_HWDIV | ARM::AEK_DSP,
+ "7-A"));
+ EXPECT_TRUE(testARMCPU("cortex-a15", "armv7-a", "neon-vfpv4",
+ ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT |
+ ARM::AEK_HWDIVARM | ARM::AEK_HWDIV | ARM::AEK_DSP,
+ "7-A"));
+ EXPECT_TRUE(testARMCPU("cortex-a17", "armv7-a", "neon-vfpv4",
+ ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT |
+ ARM::AEK_HWDIVARM | ARM::AEK_HWDIV | ARM::AEK_DSP,
+ "7-A"));
+ EXPECT_TRUE(testARMCPU("krait", "armv7-a", "neon-vfpv4",
+ ARM::AEK_HWDIVARM | ARM::AEK_HWDIV | ARM::AEK_DSP,
+ "7-A"));
+ EXPECT_TRUE(testARMCPU("cortex-r4", "armv7-r", "none",
+ ARM::AEK_HWDIV | ARM::AEK_DSP, "7-R"));
+ EXPECT_TRUE(testARMCPU("cortex-r4f", "armv7-r", "vfpv3-d16",
+ ARM::AEK_HWDIV | ARM::AEK_DSP, "7-R"));
+ EXPECT_TRUE(testARMCPU("cortex-r5", "armv7-r", "vfpv3-d16",
+ ARM::AEK_MP | ARM::AEK_HWDIVARM | ARM::AEK_HWDIV |
+ ARM::AEK_DSP, "7-R"));
+ EXPECT_TRUE(testARMCPU("cortex-r7", "armv7-r", "vfpv3-d16-fp16",
+ ARM::AEK_MP | ARM::AEK_HWDIVARM | ARM::AEK_HWDIV |
+ ARM::AEK_DSP, "7-R"));
+ EXPECT_TRUE(testARMCPU("cortex-r8", "armv7-r", "vfpv3-d16-fp16",
+ ARM::AEK_MP | ARM::AEK_HWDIVARM | ARM::AEK_HWDIV |
+ ARM::AEK_DSP, "7-R"));
+ EXPECT_TRUE(testARMCPU("cortex-r52", "armv8-r", "neon-fp-armv8",
+ ARM::AEK_CRC | ARM::AEK_MP | ARM::AEK_VIRT |
+ ARM::AEK_HWDIVARM | ARM::AEK_HWDIV | ARM::AEK_DSP,
+ "8-R"));
+ EXPECT_TRUE(testARMCPU("sc300", "armv7-m", "none",
+ ARM::AEK_HWDIV, "7-M"));
+ EXPECT_TRUE(testARMCPU("cortex-m3", "armv7-m", "none",
+ ARM::AEK_HWDIV, "7-M"));
+ EXPECT_TRUE(testARMCPU("cortex-m4", "armv7e-m", "fpv4-sp-d16",
+ ARM::AEK_HWDIV | ARM::AEK_DSP, "7E-M"));
+ EXPECT_TRUE(testARMCPU("cortex-m7", "armv7e-m", "fpv5-d16",
+ ARM::AEK_HWDIV | ARM::AEK_DSP, "7E-M"));
+ EXPECT_TRUE(testARMCPU("cortex-a32", "armv8-a", "crypto-neon-fp-armv8",
+ ARM::AEK_CRC | ARM::AEK_SEC | ARM::AEK_MP |
+ ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
+ ARM::AEK_HWDIV | ARM::AEK_DSP,
+ "8-A"));
+ EXPECT_TRUE(testARMCPU("cortex-a35", "armv8-a", "crypto-neon-fp-armv8",
+ ARM::AEK_CRC | ARM::AEK_SEC | ARM::AEK_MP |
+ ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
+ ARM::AEK_HWDIV | ARM::AEK_DSP,
+ "8-A"));
+ EXPECT_TRUE(testARMCPU("cortex-a53", "armv8-a", "crypto-neon-fp-armv8",
+ ARM::AEK_CRC | ARM::AEK_SEC | ARM::AEK_MP |
+ ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
+ ARM::AEK_HWDIV | ARM::AEK_DSP,
+ "8-A"));
+ EXPECT_TRUE(testARMCPU("cortex-a57", "armv8-a", "crypto-neon-fp-armv8",
+ ARM::AEK_CRC | ARM::AEK_SEC | ARM::AEK_MP |
+ ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
+ ARM::AEK_HWDIV | ARM::AEK_DSP,
+ "8-A"));
+ EXPECT_TRUE(testARMCPU("cortex-a72", "armv8-a", "crypto-neon-fp-armv8",
+ ARM::AEK_CRC | ARM::AEK_SEC | ARM::AEK_MP |
+ ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
+ ARM::AEK_HWDIV | ARM::AEK_DSP,
+ "8-A"));
+ EXPECT_TRUE(testARMCPU("cortex-a73", "armv8-a", "crypto-neon-fp-armv8",
+ ARM::AEK_CRC | ARM::AEK_SEC | ARM::AEK_MP |
+ ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
+ ARM::AEK_HWDIV | ARM::AEK_DSP,
+ "8-A"));
+ EXPECT_TRUE(testARMCPU("cyclone", "armv8-a", "crypto-neon-fp-armv8",
+ ARM::AEK_CRC | ARM::AEK_SEC | ARM::AEK_MP |
+ ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
+ ARM::AEK_HWDIV | ARM::AEK_DSP,
+ "8-A"));
+ EXPECT_TRUE(testARMCPU("exynos-m1", "armv8-a", "crypto-neon-fp-armv8",
+ ARM::AEK_CRC | ARM::AEK_SEC | ARM::AEK_MP |
+ ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
+ ARM::AEK_HWDIV | ARM::AEK_DSP,
+ "8-A"));
+ EXPECT_TRUE(testARMCPU("exynos-m2", "armv8-a", "crypto-neon-fp-armv8",
+ ARM::AEK_CRC | ARM::AEK_SEC | ARM::AEK_MP |
+ ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
+ ARM::AEK_HWDIV | ARM::AEK_DSP,
+ "8-A"));
+ EXPECT_TRUE(testARMCPU("exynos-m3", "armv8-a", "crypto-neon-fp-armv8",
+ ARM::AEK_CRC | ARM::AEK_SEC | ARM::AEK_MP |
+ ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
+ ARM::AEK_HWDIV | ARM::AEK_DSP,
+ "8-A"));
+ EXPECT_TRUE(testARMCPU("iwmmxt", "iwmmxt", "none",
+ ARM::AEK_NONE, "iwmmxt"));
+ EXPECT_TRUE(testARMCPU("xscale", "xscale", "none",
+ ARM::AEK_NONE, "xscale"));
+ EXPECT_TRUE(testARMCPU("swift", "armv7s", "neon-vfpv4",
+ ARM::AEK_HWDIVARM | ARM::AEK_HWDIV | ARM::AEK_DSP,
+ "7-S"));
+}
+
+bool testARMArch(StringRef Arch, StringRef DefaultCPU, StringRef SubArch,
+ unsigned ArchAttr) {
+ unsigned ArchKind = ARM::parseArch(Arch);
+ return (ArchKind != ARM::AK_INVALID) &
+ ARM::getDefaultCPU(Arch).equals(DefaultCPU) &
+ ARM::getSubArch(ArchKind).equals(SubArch) &
+ (ARM::getArchAttr(ArchKind) == ArchAttr);
+}
+
+TEST(TargetParserTest, testARMArch) {
+ EXPECT_TRUE(
+ testARMArch("armv2", "arm2", "v2",
+ ARMBuildAttrs::CPUArch::Pre_v4));
+ EXPECT_TRUE(
+ testARMArch("armv2a", "arm3", "v2a",
+ ARMBuildAttrs::CPUArch::Pre_v4));
+ EXPECT_TRUE(
+ testARMArch("armv3", "arm6", "v3",
+ ARMBuildAttrs::CPUArch::Pre_v4));
+ EXPECT_TRUE(
+ testARMArch("armv3m", "arm7m", "v3m",
+ ARMBuildAttrs::CPUArch::Pre_v4));
+ EXPECT_TRUE(
+ testARMArch("armv4", "strongarm", "v4",
+ ARMBuildAttrs::CPUArch::v4));
+ EXPECT_TRUE(
+ testARMArch("armv4t", "arm7tdmi", "v4t",
+ ARMBuildAttrs::CPUArch::v4T));
+ EXPECT_TRUE(
+ testARMArch("armv5t", "arm10tdmi", "v5",
+ ARMBuildAttrs::CPUArch::v5T));
+ EXPECT_TRUE(
+ testARMArch("armv5te", "arm1022e", "v5e",
+ ARMBuildAttrs::CPUArch::v5TE));
+ EXPECT_TRUE(
+ testARMArch("armv5tej", "arm926ej-s", "v5e",
+ ARMBuildAttrs::CPUArch::v5TEJ));
+ EXPECT_TRUE(
+ testARMArch("armv6", "arm1136jf-s", "v6",
+ ARMBuildAttrs::CPUArch::v6));
+ EXPECT_TRUE(
+ testARMArch("armv6k", "arm1176j-s", "v6k",
+ ARMBuildAttrs::CPUArch::v6K));
+ EXPECT_TRUE(
+ testARMArch("armv6t2", "arm1156t2-s", "v6t2",
+ ARMBuildAttrs::CPUArch::v6T2));
+ EXPECT_TRUE(
+ testARMArch("armv6kz", "arm1176jzf-s", "v6kz",
+ ARMBuildAttrs::CPUArch::v6KZ));
+ EXPECT_TRUE(
+ testARMArch("armv6-m", "cortex-m0", "v6m",
+ ARMBuildAttrs::CPUArch::v6_M));
+ EXPECT_TRUE(
+ testARMArch("armv7-a", "cortex-a8", "v7",
+ ARMBuildAttrs::CPUArch::v7));
+ EXPECT_TRUE(
+ testARMArch("armv7-r", "cortex-r4", "v7r",
+ ARMBuildAttrs::CPUArch::v7));
+ EXPECT_TRUE(
+ testARMArch("armv7-m", "cortex-m3", "v7m",
+ ARMBuildAttrs::CPUArch::v7));
+ EXPECT_TRUE(
+ testARMArch("armv7e-m", "cortex-m4", "v7em",
+ ARMBuildAttrs::CPUArch::v7E_M));
+ EXPECT_TRUE(
+ testARMArch("armv8-a", "cortex-a53", "v8",
+ ARMBuildAttrs::CPUArch::v8_A));
+ EXPECT_TRUE(
+ testARMArch("armv8.1-a", "generic", "v8.1a",
+ ARMBuildAttrs::CPUArch::v8_A));
+ EXPECT_TRUE(
+ testARMArch("armv8.2-a", "generic", "v8.2a",
+ ARMBuildAttrs::CPUArch::v8_A));
+ EXPECT_TRUE(
+ testARMArch("armv8-r", "cortex-r52", "v8r",
+ ARMBuildAttrs::CPUArch::v8_R));
+ EXPECT_TRUE(
+ testARMArch("armv8-m.base", "generic", "v8m.base",
+ ARMBuildAttrs::CPUArch::v8_M_Base));
+ EXPECT_TRUE(
+ testARMArch("armv8-m.main", "generic", "v8m.main",
+ ARMBuildAttrs::CPUArch::v8_M_Main));
+ EXPECT_TRUE(
+ testARMArch("iwmmxt", "iwmmxt", "",
+ ARMBuildAttrs::CPUArch::v5TE));
+ EXPECT_TRUE(
+ testARMArch("iwmmxt2", "generic", "",
+ ARMBuildAttrs::CPUArch::v5TE));
+ EXPECT_TRUE(
+ testARMArch("xscale", "xscale", "v5e",
+ ARMBuildAttrs::CPUArch::v5TE));
+ EXPECT_TRUE(
+ testARMArch("armv7s", "swift", "v7s",
+ ARMBuildAttrs::CPUArch::v7));
+ EXPECT_TRUE(
+ testARMArch("armv7k", "generic", "v7k",
+ ARMBuildAttrs::CPUArch::v7));
+}
+
+bool testARMExtension(StringRef CPUName, unsigned ArchKind, StringRef ArchExt) {
+ return ARM::getDefaultExtensions(CPUName, ArchKind) &
+ ARM::parseArchExt(ArchExt);
+}
+
+TEST(TargetParserTest, testARMExtension) {
+ EXPECT_FALSE(testARMExtension("arm2", 0, "thumb"));
+ EXPECT_FALSE(testARMExtension("arm3", 0, "thumb"));
+ EXPECT_FALSE(testARMExtension("arm6", 0, "thumb"));
+ EXPECT_FALSE(testARMExtension("arm7m", 0, "thumb"));
+ EXPECT_FALSE(testARMExtension("strongarm", 0, "dsp"));
+ EXPECT_FALSE(testARMExtension("arm7tdmi", 0, "dsp"));
+ EXPECT_FALSE(testARMExtension("arm10tdmi", 0, "simd"));
+ EXPECT_FALSE(testARMExtension("arm1022e", 0, "simd"));
+ EXPECT_FALSE(testARMExtension("arm926ej-s", 0, "simd"));
+ EXPECT_FALSE(testARMExtension("arm1136jf-s", 0, "crypto"));
+ EXPECT_FALSE(testARMExtension("arm1176j-s", 0, "crypto"));
+ EXPECT_FALSE(testARMExtension("arm1156t2-s", 0, "crypto"));
+ EXPECT_FALSE(testARMExtension("arm1176jzf-s", 0, "crypto"));
+ EXPECT_FALSE(testARMExtension("cortex-m0", 0, "crypto"));
+ EXPECT_FALSE(testARMExtension("cortex-a8", 0, "crypto"));
+ EXPECT_FALSE(testARMExtension("cortex-r4", 0, "crypto"));
+ EXPECT_FALSE(testARMExtension("cortex-m3", 0, "crypto"));
+ EXPECT_FALSE(testARMExtension("cortex-a53", 0, "ras"));
+ EXPECT_FALSE(testARMExtension("cortex-r52", 0, "ras"));
+ EXPECT_FALSE(testARMExtension("iwmmxt", 0, "crc"));
+ EXPECT_FALSE(testARMExtension("xscale", 0, "crc"));
+ EXPECT_FALSE(testARMExtension("swift", 0, "crc"));
+
+ EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV2, "thumb"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV2A, "thumb"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV3, "thumb"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV3M, "thumb"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV4, "dsp"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV4T, "dsp"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV5T, "simd"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV5TE, "simd"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV5TEJ, "simd"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV6, "crypto"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV6K, "crypto"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV6T2, "crypto"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV6KZ, "crypto"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV6M, "crypto"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV7A, "crypto"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV7R, "crypto"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV7M, "crypto"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV7EM, "crypto"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV8A, "ras"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV8_1A, "ras"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV8_2A, "spe"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV8R, "ras"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV8MBaseline, "crc"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV8MMainline, "crc"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::AK_IWMMXT, "crc"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::AK_IWMMXT2, "crc"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::AK_XSCALE, "crc"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV7S, "crypto"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV7K, "crypto"));
+}
+
+TEST(TargetParserTest, ARMFPUVersion) {
for (ARM::FPUKind FK = static_cast<ARM::FPUKind>(0);
FK <= ARM::FPUKind::FK_LAST;
FK = static_cast<ARM::FPUKind>(static_cast<unsigned>(FK) + 1))
- EXPECT_TRUE(FK == ARM::FK_LAST ? ARM::getFPUName(FK).empty()
- : !ARM::getFPUName(FK).empty());
+ if (FK == ARM::FK_LAST)
+ EXPECT_EQ(0U, ARM::getFPUVersion(FK));
+ else
+ EXPECT_LE(0U, ARM::getFPUVersion(FK));
}
-TEST(TargetParserTest, AArch64ArchName) {
- for (ARM::ArchKind AK = static_cast<ARM::ArchKind>(0);
- AK <= ARM::ArchKind::AK_LAST;
- AK = static_cast<ARM::ArchKind>(static_cast<unsigned>(AK) + 1))
- EXPECT_TRUE(contains(kAArch64ArchKinds, static_cast<unsigned>(AK))
- ? !AArch64::getArchName(AK).empty()
- : AArch64::getArchName(AK).empty());
+TEST(TargetParserTest, ARMFPUNeonSupportLevel) {
+ for (ARM::FPUKind FK = static_cast<ARM::FPUKind>(0);
+ FK <= ARM::FPUKind::FK_LAST;
+ FK = static_cast<ARM::FPUKind>(static_cast<unsigned>(FK) + 1))
+ if (FK == ARM::FK_LAST)
+ EXPECT_EQ(0U, ARM::getFPUNeonSupportLevel(FK));
+ else
+ EXPECT_LE(0U, ARM::getFPUNeonSupportLevel(FK));
}
-TEST(TargetParserTest, AArch64CPUAttr) {
- for (ARM::ArchKind AK = static_cast<ARM::ArchKind>(0);
- AK <= ARM::ArchKind::AK_LAST;
- AK = static_cast<ARM::ArchKind>(static_cast<unsigned>(AK) + 1))
- EXPECT_TRUE(contains(kAArch64ArchKinds, static_cast<unsigned>(AK))
- ? !AArch64::getCPUAttr(AK).empty()
- : AArch64::getCPUAttr(AK).empty());
+TEST(TargetParserTest, ARMFPURestriction) {
+ for (ARM::FPUKind FK = static_cast<ARM::FPUKind>(0);
+ FK <= ARM::FPUKind::FK_LAST;
+ FK = static_cast<ARM::FPUKind>(static_cast<unsigned>(FK) + 1))
+ if (FK == ARM::FK_LAST)
+ EXPECT_EQ(0U, ARM::getFPURestriction(FK));
+ else
+ EXPECT_LE(0U, ARM::getFPURestriction(FK));
}
-TEST(TargetParserTest, AArch64SubArch) {
- for (ARM::ArchKind AK = static_cast<ARM::ArchKind>(0);
- AK <= ARM::ArchKind::AK_LAST;
- AK = static_cast<ARM::ArchKind>(static_cast<unsigned>(AK) + 1))
- EXPECT_TRUE(contains(kAArch64ArchKinds, static_cast<unsigned>(AK))
- ? !AArch64::getSubArch(AK).empty()
- : AArch64::getSubArch(AK).empty());
+TEST(TargetParserTest, ARMExtensionFeatures) {
+ std::vector<StringRef> Features;
+ unsigned Extensions = ARM::AEK_CRC | ARM::AEK_CRYPTO | ARM::AEK_DSP |
+ ARM::AEK_HWDIVARM | ARM::AEK_HWDIV | ARM::AEK_MP |
+ ARM::AEK_SEC | ARM::AEK_VIRT | ARM::AEK_RAS;
+
+ for (unsigned i = 0; i <= Extensions; i++)
+ EXPECT_TRUE(i == 0 ? !ARM::getExtensionFeatures(i, Features)
+ : ARM::getExtensionFeatures(i, Features));
}
+
+TEST(TargetParserTest, ARMFPUFeatures) {
+ std::vector<StringRef> Features;
+ for (ARM::FPUKind FK = static_cast<ARM::FPUKind>(0);
+ FK <= ARM::FPUKind::FK_LAST;
+ FK = static_cast<ARM::FPUKind>(static_cast<unsigned>(FK) + 1))
+ EXPECT_TRUE((FK == ARM::FK_INVALID || FK >= ARM::FK_LAST)
+ ? !ARM::getFPUFeatures(FK, Features)
+ : ARM::getFPUFeatures(FK, Features));
+}
+
+TEST(TargetParserTest, ARMArchExtFeature) {
+ const char *ArchExt[][4] = {{"crc", "nocrc", "+crc", "-crc"},
+ {"crypto", "nocrypto", "+crypto", "-crypto"},
+ {"dsp", "nodsp", "+dsp", "-dsp"},
+ {"fp", "nofp", nullptr, nullptr},
+ {"idiv", "noidiv", nullptr, nullptr},
+ {"mp", "nomp", nullptr, nullptr},
+ {"simd", "nosimd", nullptr, nullptr},
+ {"sec", "nosec", nullptr, nullptr},
+ {"virt", "novirt", nullptr, nullptr},
+ {"fp16", "nofp16", "+fullfp16", "-fullfp16"},
+ {"ras", "noras", "+ras", "-ras"},
+ {"os", "noos", nullptr, nullptr},
+ {"iwmmxt", "noiwmmxt", nullptr, nullptr},
+ {"iwmmxt2", "noiwmmxt2", nullptr, nullptr},
+ {"maverick", "maverick", nullptr, nullptr},
+ {"xscale", "noxscale", nullptr, nullptr}};
+
+ for (unsigned i = 0; i < array_lengthof(ArchExt); i++) {
+ EXPECT_EQ(StringRef(ArchExt[i][2]), ARM::getArchExtFeature(ArchExt[i][0]));
+ EXPECT_EQ(StringRef(ArchExt[i][3]), ARM::getArchExtFeature(ArchExt[i][1]));
+ }
}
+TEST(TargetParserTest, ARMparseHWDiv) {
+ const char *hwdiv[] = {"thumb", "arm", "arm,thumb", "thumb,arm"};
+
+ for (unsigned i = 0; i < array_lengthof(hwdiv); i++)
+ EXPECT_NE(ARM::AEK_INVALID, ARM::parseHWDiv((StringRef)hwdiv[i]));
+}
+
+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"};
+
+ for (unsigned i = 0; i < array_lengthof(Arch); i++) {
+ std::string arm_1 = "armeb" + (std::string)(Arch[i]);
+ std::string arm_2 = "arm" + (std::string)(Arch[i]) + "eb";
+ std::string arm_3 = "arm" + (std::string)(Arch[i]);
+ std::string thumb_1 = "thumbeb" + (std::string)(Arch[i]);
+ std::string thumb_2 = "thumb" + (std::string)(Arch[i]) + "eb";
+ std::string thumb_3 = "thumb" + (std::string)(Arch[i]);
+
+ EXPECT_EQ(ARM::EK_BIG, ARM::parseArchEndian(arm_1));
+ EXPECT_EQ(ARM::EK_BIG, ARM::parseArchEndian(arm_2));
+ EXPECT_EQ(ARM::EK_LITTLE, ARM::parseArchEndian(arm_3));
+
+ EXPECT_EQ(ARM::IK_ARM, ARM::parseArchISA(arm_1));
+ EXPECT_EQ(ARM::IK_ARM, ARM::parseArchISA(arm_2));
+ EXPECT_EQ(ARM::IK_ARM, ARM::parseArchISA(arm_3));
+ if (i >= 4) {
+ EXPECT_EQ(ARM::EK_BIG, ARM::parseArchEndian(thumb_1));
+ EXPECT_EQ(ARM::EK_BIG, ARM::parseArchEndian(thumb_2));
+ EXPECT_EQ(ARM::EK_LITTLE, ARM::parseArchEndian(thumb_3));
+
+ EXPECT_EQ(ARM::IK_THUMB, ARM::parseArchISA(thumb_1));
+ EXPECT_EQ(ARM::IK_THUMB, ARM::parseArchISA(thumb_2));
+ EXPECT_EQ(ARM::IK_THUMB, ARM::parseArchISA(thumb_3));
+ }
+ }
+
+ EXPECT_EQ(ARM::EK_LITTLE, ARM::parseArchEndian("aarch64"));
+ EXPECT_EQ(ARM::EK_BIG, ARM::parseArchEndian("aarch64_be"));
+
+ EXPECT_EQ(ARM::IK_AARCH64, ARM::parseArchISA("aarch64"));
+ EXPECT_EQ(ARM::IK_AARCH64, ARM::parseArchISA("aarch64_be"));
+ EXPECT_EQ(ARM::IK_AARCH64, ARM::parseArchISA("arm64"));
+ EXPECT_EQ(ARM::IK_AARCH64, ARM::parseArchISA("arm64_be"));
+}
+
+TEST(TargetParserTest, ARMparseArchProfile) {
+ for (unsigned i = 0; i < array_lengthof(ARMArch); i++) {
+ switch (ARM::parseArch(ARMArch[i])) {
+ case ARM::AK_ARMV6M:
+ case ARM::AK_ARMV7M:
+ case ARM::AK_ARMV7EM:
+ case ARM::AK_ARMV8MMainline:
+ case ARM::AK_ARMV8MBaseline:
+ EXPECT_EQ(ARM::PK_M, ARM::parseArchProfile(ARMArch[i]));
+ continue;
+ case ARM::AK_ARMV7R:
+ case ARM::AK_ARMV8R:
+ EXPECT_EQ(ARM::PK_R, ARM::parseArchProfile(ARMArch[i]));
+ continue;
+ case ARM::AK_ARMV7A:
+ case ARM::AK_ARMV7K:
+ case ARM::AK_ARMV8A:
+ case ARM::AK_ARMV8_1A:
+ case ARM::AK_ARMV8_2A:
+ EXPECT_EQ(ARM::PK_A, ARM::parseArchProfile(ARMArch[i]));
+ continue;
+ }
+ EXPECT_EQ(ARM::PK_INVALID, ARM::parseArchProfile(ARMArch[i]));
+ }
+}
+
+TEST(TargetParserTest, ARMparseArchVersion) {
+ for (unsigned i = 0; i < array_lengthof(ARMArch); i++)
+ if (((std::string)ARMArch[i]).substr(0, 4) == "armv")
+ EXPECT_EQ((ARMArch[i][4] - 48u), ARM::parseArchVersion(ARMArch[i]));
+ else
+ EXPECT_EQ(5u, ARM::parseArchVersion(ARMArch[i]));
+}
+
+bool testAArch64CPU(StringRef CPUName, StringRef ExpectedArch,
+ StringRef ExpectedFPU, unsigned ExpectedFlags,
+ StringRef CPUAttr) {
+ unsigned ArchKind = AArch64::parseCPUArch(CPUName);
+ bool pass = AArch64::getArchName(ArchKind).equals(ExpectedArch);
+ unsigned FPUKind = AArch64::getDefaultFPU(CPUName, ArchKind);
+ pass &= AArch64::getFPUName(FPUKind).equals(ExpectedFPU);
+
+ unsigned ExtKind = AArch64::getDefaultExtensions(CPUName, ArchKind);
+ if (ExtKind > 1 && (ExtKind & AArch64::AEK_NONE))
+ pass &= ((ExtKind ^ AArch64::AEK_NONE) == ExpectedFlags);
+ else
+ pass &= (ExtKind == ExpectedFlags);
+
+ pass &= AArch64::getCPUAttr(ArchKind).equals(CPUAttr);
+
+ return pass;
+}
+
+TEST(TargetParserTest, testAArch64CPU) {
+ EXPECT_TRUE(testAArch64CPU(
+ "invalid", "invalid", "invalid",
+ AArch64::AEK_INVALID, ""));
+ EXPECT_TRUE(testAArch64CPU(
+ "generic", "invalid", "none",
+ AArch64::AEK_NONE, ""));
+
+ EXPECT_TRUE(testAArch64CPU(
+ "cortex-a35", "armv8-a", "crypto-neon-fp-armv8",
+ AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_SIMD, "8-A"));
+ EXPECT_TRUE(testAArch64CPU(
+ "cortex-a53", "armv8-a", "crypto-neon-fp-armv8",
+ AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_SIMD, "8-A"));
+ EXPECT_TRUE(testAArch64CPU(
+ "cortex-a57", "armv8-a", "crypto-neon-fp-armv8",
+ AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_SIMD, "8-A"));
+ EXPECT_TRUE(testAArch64CPU(
+ "cortex-a72", "armv8-a", "crypto-neon-fp-armv8",
+ AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_SIMD, "8-A"));
+ EXPECT_TRUE(testAArch64CPU(
+ "cortex-a73", "armv8-a", "crypto-neon-fp-armv8",
+ AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_SIMD, "8-A"));
+ EXPECT_TRUE(testAArch64CPU(
+ "cyclone", "armv8-a", "crypto-neon-fp-armv8",
+ AArch64::AEK_CRYPTO | AArch64::AEK_SIMD, "8-A"));
+ EXPECT_TRUE(testAArch64CPU(
+ "exynos-m1", "armv8-a", "crypto-neon-fp-armv8",
+ AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_SIMD, "8-A"));
+ EXPECT_TRUE(testAArch64CPU(
+ "exynos-m2", "armv8-a", "crypto-neon-fp-armv8",
+ AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_SIMD, "8-A"));
+ EXPECT_TRUE(testAArch64CPU(
+ "exynos-m3", "armv8-a", "crypto-neon-fp-armv8",
+ AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_SIMD, "8-A"));
+ EXPECT_TRUE(testAArch64CPU(
+ "falkor", "armv8-a", "crypto-neon-fp-armv8",
+ AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_SIMD, "8-A"));
+ EXPECT_TRUE(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"));
+}
+
+bool testAArch64Arch(StringRef Arch, StringRef DefaultCPU, StringRef SubArch,
+ unsigned ArchAttr) {
+ unsigned ArchKind = AArch64::parseArch(Arch);
+ return (ArchKind != static_cast<unsigned>(AArch64::ArchKind::AK_INVALID)) &
+ AArch64::getDefaultCPU(Arch).equals(DefaultCPU) &
+ AArch64::getSubArch(ArchKind).equals(SubArch) &
+ (AArch64::getArchAttr(ArchKind) == ArchAttr);
+}
+
+TEST(TargetParserTest, testAArch64Arch) {
+ EXPECT_TRUE(testAArch64Arch("armv8-a", "cortex-a53", "v8",
+ ARMBuildAttrs::CPUArch::v8_A));
+ EXPECT_TRUE(testAArch64Arch("armv8.1-a", "generic", "v8.1a",
+ ARMBuildAttrs::CPUArch::v8_A));
+ EXPECT_TRUE(testAArch64Arch("armv8.2-a", "generic", "v8.2a",
+ ARMBuildAttrs::CPUArch::v8_A));
+}
+
+bool testAArch64Extension(StringRef CPUName, unsigned ArchKind,
+ StringRef ArchExt) {
+ return AArch64::getDefaultExtensions(CPUName, ArchKind) &
+ AArch64::parseArchExt(ArchExt);
+}
+
+TEST(TargetParserTest, testAArch64Extension) {
+ EXPECT_FALSE(testAArch64Extension("cortex-a35", 0, "ras"));
+ EXPECT_FALSE(testAArch64Extension("cortex-a53", 0, "ras"));
+ EXPECT_FALSE(testAArch64Extension("cortex-a57", 0, "ras"));
+ EXPECT_FALSE(testAArch64Extension("cortex-a72", 0, "ras"));
+ EXPECT_FALSE(testAArch64Extension("cortex-a73", 0, "ras"));
+ 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(
+ "generic", static_cast<unsigned>(AArch64::ArchKind::AK_ARMV8A), "ras"));
+ EXPECT_FALSE(testAArch64Extension(
+ "generic", static_cast<unsigned>(AArch64::ArchKind::AK_ARMV8_1A), "ras"));
+ EXPECT_FALSE(testAArch64Extension(
+ "generic", static_cast<unsigned>(AArch64::ArchKind::AK_ARMV8_2A), "spe"));
+}
+
+TEST(TargetParserTest, AArch64ExtensionFeatures) {
+ std::vector<StringRef> Features;
+ unsigned Extensions = AArch64::AEK_CRC | AArch64::AEK_CRYPTO |
+ AArch64::AEK_FP | AArch64::AEK_SIMD |
+ AArch64::AEK_FP16 | AArch64::AEK_PROFILE |
+ AArch64::AEK_RAS;
+
+ for (unsigned i = 0; i <= Extensions; i++)
+ EXPECT_TRUE(i == 0 ? !AArch64::getExtensionFeatures(i, Features)
+ : AArch64::getExtensionFeatures(i, Features));
+}
+
+TEST(TargetParserTest, AArch64ArchFeatures) {
+ std::vector<StringRef> Features;
+
+ for (unsigned AK = 0; AK < static_cast<unsigned>(AArch64::ArchKind::AK_LAST);
+ AK++)
+ EXPECT_TRUE((AK == static_cast<unsigned>(AArch64::ArchKind::AK_INVALID) ||
+ AK == static_cast<unsigned>(AArch64::ArchKind::AK_LAST))
+ ? !AArch64::getArchFeatures(AK, Features)
+ : AArch64::getArchFeatures(AK, Features));
+}
+
+TEST(TargetParserTest, AArch64ArchExtFeature) {
+ const char *ArchExt[][4] = {{"crc", "nocrc", "+crc", "-crc"},
+ {"crypto", "nocrypto", "+crypto", "-crypto"},
+ {"fp", "nofp", "+fp-armv8", "-fp-armv8"},
+ {"simd", "nosimd", "+neon", "-neon"},
+ {"fp16", "nofp16", "+fullfp16", "-fullfp16"},
+ {"profile", "noprofile", "+spe", "-spe"},
+ {"ras", "noras", "+ras", "-ras"}};
+
+ for (unsigned i = 0; i < array_lengthof(ArchExt); i++) {
+ EXPECT_EQ(StringRef(ArchExt[i][2]),
+ AArch64::getArchExtFeature(ArchExt[i][0]));
+ EXPECT_EQ(StringRef(ArchExt[i][3]),
+ AArch64::getArchExtFeature(ArchExt[i][1]));
+ }
+}
+}
diff --git a/unittests/Support/ThreadPool.cpp b/unittests/Support/ThreadPool.cpp
index 69a24bc5444c..8e03aacfb1e0 100644
--- a/unittests/Support/ThreadPool.cpp
+++ b/unittests/Support/ThreadPool.cpp
@@ -31,16 +31,14 @@ protected:
bool isUnsupportedOSOrEnvironment() {
Triple Host(Triple::normalize(sys::getProcessTriple()));
- if (std::find(UnsupportedEnvironments.begin(), UnsupportedEnvironments.end(),
- Host.getEnvironment()) != UnsupportedEnvironments.end())
+ if (find(UnsupportedEnvironments, Host.getEnvironment()) !=
+ UnsupportedEnvironments.end())
return true;
- if (std::find(UnsupportedOSs.begin(), UnsupportedOSs.end(), Host.getOS())
- != UnsupportedOSs.end())
+ if (is_contained(UnsupportedOSs, Host.getOS()))
return true;
- if (std::find(UnsupportedArchs.begin(), UnsupportedArchs.end(), Host.getArch())
- != UnsupportedArchs.end())
+ if (is_contained(UnsupportedArchs, Host.getArch()))
return true;
return false;
diff --git a/unittests/Support/Threading.cpp b/unittests/Support/Threading.cpp
new file mode 100644
index 000000000000..be53026415d7
--- /dev/null
+++ b/unittests/Support/Threading.cpp
@@ -0,0 +1,25 @@
+//===- unittests/Threading.cpp - Thread tests -----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Threading.h"
+#include "llvm/Support/thread.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+
+TEST(Threading, PhysicalConcurrency) {
+ auto Num = heavyweight_hardware_concurrency();
+ // Since Num is unsigned this will also catch us trying to
+ // return -1.
+ ASSERT_LE(Num, thread::hardware_concurrency());
+}
+
+} // end anon namespace
diff --git a/unittests/Support/TimeValueTest.cpp b/unittests/Support/TimeValueTest.cpp
deleted file mode 100644
index 3d2b9780c069..000000000000
--- a/unittests/Support/TimeValueTest.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-//===- llvm/unittest/Support/TimeValueTest.cpp - Time Value tests ---------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-#include "llvm/Support/TimeValue.h"
-#include <time.h>
-
-using namespace llvm;
-namespace {
-
-TEST(TimeValue, time_t) {
- sys::TimeValue now = sys::TimeValue::now();
- time_t now_t = time(nullptr);
- EXPECT_TRUE(std::abs(static_cast<long>(now_t - now.toEpochTime())) < 2);
-}
-
-TEST(TimeValue, Win32FILETIME) {
- uint64_t epoch_as_filetime = 0x19DB1DED53E8000ULL;
- uint32_t ns = 765432100;
- sys::TimeValue epoch;
-
- // FILETIME has 100ns of intervals.
- uint64_t ft1970 = epoch_as_filetime + ns / 100;
- epoch.fromWin32Time(ft1970);
-
- // The "seconds" part in Posix time may be expected as zero.
- EXPECT_EQ(0u, epoch.toEpochTime());
- EXPECT_EQ(ns, static_cast<uint32_t>(epoch.nanoseconds()));
-
- // Confirm it reversible.
- EXPECT_EQ(ft1970, epoch.toWin32Time());
-}
-
-}
diff --git a/unittests/Support/TimerTest.cpp b/unittests/Support/TimerTest.cpp
index f556a3f72c62..082a7e35db52 100644
--- a/unittests/Support/TimerTest.cpp
+++ b/unittests/Support/TimerTest.cpp
@@ -33,7 +33,7 @@ void SleepMS() {
}
TEST(Timer, Additivity) {
- Timer T1("T1");
+ Timer T1("T1", "T1");
EXPECT_TRUE(T1.isInitialized());
@@ -50,7 +50,7 @@ TEST(Timer, Additivity) {
}
TEST(Timer, CheckIfTriggered) {
- Timer T1("T1");
+ Timer T1("T1", "T1");
EXPECT_FALSE(T1.hasTriggered());
T1.startTimer();
diff --git a/unittests/Support/TrailingObjectsTest.cpp b/unittests/Support/TrailingObjectsTest.cpp
index a1d3e7b3c864..cb5c47d1b25b 100644
--- a/unittests/Support/TrailingObjectsTest.cpp
+++ b/unittests/Support/TrailingObjectsTest.cpp
@@ -41,6 +41,9 @@ public:
unsigned numShorts() const { return NumShorts; }
// Pull some protected members in as public, for testability.
+ template <typename... Ty>
+ using FixedSizeStorage = TrailingObjects::FixedSizeStorage<Ty...>;
+
using TrailingObjects::totalSizeToAlloc;
using TrailingObjects::additionalSizeToAlloc;
using TrailingObjects::getTrailingObjects;
@@ -94,6 +97,9 @@ public:
}
// Pull some protected members in as public, for testability.
+ template <typename... Ty>
+ using FixedSizeStorage = TrailingObjects::FixedSizeStorage<Ty...>;
+
using TrailingObjects::totalSizeToAlloc;
using TrailingObjects::additionalSizeToAlloc;
using TrailingObjects::getTrailingObjects;
@@ -106,7 +112,16 @@ TEST(TrailingObjects, OneArg) {
EXPECT_EQ(Class1::additionalSizeToAlloc<short>(1), sizeof(short));
EXPECT_EQ(Class1::additionalSizeToAlloc<short>(3), sizeof(short) * 3);
+ EXPECT_EQ(alignof(Class1),
+ alignof(Class1::FixedSizeStorage<short>::with_counts<1>::type));
+ EXPECT_EQ(sizeof(Class1::FixedSizeStorage<short>::with_counts<1>::type),
+ llvm::alignTo(Class1::totalSizeToAlloc<short>(1), alignof(Class1)));
EXPECT_EQ(Class1::totalSizeToAlloc<short>(1), sizeof(Class1) + sizeof(short));
+
+ EXPECT_EQ(alignof(Class1),
+ alignof(Class1::FixedSizeStorage<short>::with_counts<3>::type));
+ EXPECT_EQ(sizeof(Class1::FixedSizeStorage<short>::with_counts<3>::type),
+ llvm::alignTo(Class1::totalSizeToAlloc<short>(3), alignof(Class1)));
EXPECT_EQ(Class1::totalSizeToAlloc<short>(3),
sizeof(Class1) + sizeof(short) * 3);
@@ -120,9 +135,8 @@ TEST(TrailingObjects, TwoArg) {
Class2 *C1 = Class2::create(4);
Class2 *C2 = Class2::create(0, 4.2);
- EXPECT_EQ(sizeof(Class2),
- llvm::alignTo(sizeof(bool) * 2, llvm::alignOf<double>()));
- EXPECT_EQ(llvm::alignOf<Class2>(), llvm::alignOf<double>());
+ EXPECT_EQ(sizeof(Class2), llvm::alignTo(sizeof(bool) * 2, alignof(double)));
+ EXPECT_EQ(alignof(Class2), alignof(double));
EXPECT_EQ((Class2::additionalSizeToAlloc<double, short>(1, 0)),
sizeof(double));
@@ -131,6 +145,14 @@ TEST(TrailingObjects, TwoArg) {
EXPECT_EQ((Class2::additionalSizeToAlloc<double, short>(3, 1)),
sizeof(double) * 3 + sizeof(short));
+ EXPECT_EQ(
+ alignof(Class2),
+ (alignof(
+ Class2::FixedSizeStorage<double, short>::with_counts<1, 1>::type)));
+ EXPECT_EQ(
+ sizeof(Class2::FixedSizeStorage<double, short>::with_counts<1, 1>::type),
+ llvm::alignTo(Class2::totalSizeToAlloc<double, short>(1, 1),
+ alignof(Class2)));
EXPECT_EQ((Class2::totalSizeToAlloc<double, short>(1, 1)),
sizeof(Class2) + sizeof(double) + sizeof(short));
@@ -164,7 +186,18 @@ class Class3 final : public TrailingObjects<Class3, double, short, bool> {
TEST(TrailingObjects, ThreeArg) {
EXPECT_EQ((Class3::additionalSizeToAlloc<double, short, bool>(1, 1, 3)),
sizeof(double) + sizeof(short) + 3 * sizeof(bool));
- EXPECT_EQ(sizeof(Class3), llvm::alignTo(1, llvm::alignOf<double>()));
+ EXPECT_EQ(sizeof(Class3), llvm::alignTo(1, alignof(double)));
+
+ EXPECT_EQ(
+ alignof(Class3),
+ (alignof(Class3::FixedSizeStorage<double, short,
+ bool>::with_counts<1, 1, 3>::type)));
+ EXPECT_EQ(
+ sizeof(Class3::FixedSizeStorage<double, short,
+ bool>::with_counts<1, 1, 3>::type),
+ llvm::alignTo(Class3::totalSizeToAlloc<double, short, bool>(1, 1, 3),
+ alignof(Class3)));
+
std::unique_ptr<char[]> P(new char[1000]);
Class3 *C = reinterpret_cast<Class3 *>(P.get());
EXPECT_EQ(C->getTrailingObjects<double>(), reinterpret_cast<double *>(C + 1));
@@ -184,13 +217,22 @@ class Class4 final : public TrailingObjects<Class4, char, long> {
TEST(TrailingObjects, Realignment) {
EXPECT_EQ((Class4::additionalSizeToAlloc<char, long>(1, 1)),
- llvm::alignTo(sizeof(long) + 1, llvm::alignOf<long>()));
- EXPECT_EQ(sizeof(Class4), llvm::alignTo(1, llvm::alignOf<long>()));
+ llvm::alignTo(sizeof(long) + 1, alignof(long)));
+ EXPECT_EQ(sizeof(Class4), llvm::alignTo(1, alignof(long)));
+
+ EXPECT_EQ(
+ alignof(Class4),
+ (alignof(Class4::FixedSizeStorage<char, long>::with_counts<1, 1>::type)));
+ EXPECT_EQ(
+ sizeof(Class4::FixedSizeStorage<char, long>::with_counts<1, 1>::type),
+ llvm::alignTo(Class4::totalSizeToAlloc<char, long>(1, 1),
+ alignof(Class4)));
+
std::unique_ptr<char[]> P(new char[1000]);
Class4 *C = reinterpret_cast<Class4 *>(P.get());
EXPECT_EQ(C->getTrailingObjects<char>(), reinterpret_cast<char *>(C + 1));
EXPECT_EQ(C->getTrailingObjects<long>(),
reinterpret_cast<long *>(llvm::alignAddr(
- reinterpret_cast<char *>(C + 1) + 1, llvm::alignOf<long>())));
+ reinterpret_cast<char *>(C + 1) + 1, alignof(long))));
}
}
diff --git a/unittests/Support/TrigramIndexTest.cpp b/unittests/Support/TrigramIndexTest.cpp
new file mode 100644
index 000000000000..fb0ad1749bbd
--- /dev/null
+++ b/unittests/Support/TrigramIndexTest.cpp
@@ -0,0 +1,132 @@
+//===- TrigramIndexTest.cpp - Unit tests for TrigramIndex -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/TrigramIndex.h"
+#include "gtest/gtest.h"
+
+#include <string>
+#include <vector>
+
+using namespace llvm;
+
+namespace {
+
+class TrigramIndexTest : public ::testing::Test {
+protected:
+ std::unique_ptr<TrigramIndex> makeTrigramIndex(
+ std::vector<std::string> Rules) {
+ std::unique_ptr<TrigramIndex> TI =
+ make_unique<TrigramIndex>();
+ for (auto &Rule : Rules)
+ TI->insert(Rule);
+ return TI;
+ }
+};
+
+TEST_F(TrigramIndexTest, Empty) {
+ std::unique_ptr<TrigramIndex> TI =
+ makeTrigramIndex({});
+ EXPECT_FALSE(TI->isDefeated());
+ EXPECT_TRUE(TI->isDefinitelyOut("foo"));
+}
+
+TEST_F(TrigramIndexTest, Basic) {
+ std::unique_ptr<TrigramIndex> TI =
+ makeTrigramIndex({"*hello*", "*wor.d*"});
+ EXPECT_FALSE(TI->isDefeated());
+ EXPECT_TRUE(TI->isDefinitelyOut("foo"));
+}
+
+TEST_F(TrigramIndexTest, NoTrigramsInRules) {
+ std::unique_ptr<TrigramIndex> TI =
+ makeTrigramIndex({"b.r", "za*az"});
+ EXPECT_TRUE(TI->isDefeated());
+ EXPECT_FALSE(TI->isDefinitelyOut("foo"));
+ EXPECT_FALSE(TI->isDefinitelyOut("bar"));
+ EXPECT_FALSE(TI->isDefinitelyOut("zakaz"));
+}
+
+TEST_F(TrigramIndexTest, NoTrigramsInARule) {
+ std::unique_ptr<TrigramIndex> TI =
+ makeTrigramIndex({"*hello*", "*wo.ld*"});
+ EXPECT_TRUE(TI->isDefeated());
+ EXPECT_FALSE(TI->isDefinitelyOut("foo"));
+}
+
+TEST_F(TrigramIndexTest, RepetitiveRule) {
+ std::unique_ptr<TrigramIndex> TI =
+ makeTrigramIndex({"*bar*bar*bar*bar*bar", "bar*bar"});
+ EXPECT_FALSE(TI->isDefeated());
+ EXPECT_TRUE(TI->isDefinitelyOut("foo"));
+ EXPECT_TRUE(TI->isDefinitelyOut("bar"));
+ EXPECT_FALSE(TI->isDefinitelyOut("barbara"));
+ EXPECT_FALSE(TI->isDefinitelyOut("bar+bar"));
+}
+
+TEST_F(TrigramIndexTest, PopularTrigram) {
+ std::unique_ptr<TrigramIndex> TI =
+ makeTrigramIndex({"*aaa*", "*aaaa*", "*aaaaa*", "*aaaaa*", "*aaaaaa*"});
+ EXPECT_TRUE(TI->isDefeated());
+}
+
+TEST_F(TrigramIndexTest, PopularTrigram2) {
+ std::unique_ptr<TrigramIndex> TI =
+ makeTrigramIndex({"class1.h", "class2.h", "class3.h", "class4.h", "class.h"});
+ EXPECT_TRUE(TI->isDefeated());
+}
+
+TEST_F(TrigramIndexTest, TooComplicatedRegex) {
+ std::unique_ptr<TrigramIndex> TI =
+ makeTrigramIndex({"[0-9]+"});
+ EXPECT_TRUE(TI->isDefeated());
+}
+
+TEST_F(TrigramIndexTest, TooComplicatedRegex2) {
+ std::unique_ptr<TrigramIndex> TI =
+ makeTrigramIndex({"foo|bar"});
+ EXPECT_TRUE(TI->isDefeated());
+}
+
+TEST_F(TrigramIndexTest, EscapedSymbols) {
+ std::unique_ptr<TrigramIndex> TI =
+ makeTrigramIndex({"*c\\+\\+*", "*hello\\\\world*", "a\\tb", "a\\0b"});
+ EXPECT_FALSE(TI->isDefeated());
+ EXPECT_FALSE(TI->isDefinitelyOut("c++"));
+ EXPECT_TRUE(TI->isDefinitelyOut("c\\+\\+"));
+ EXPECT_FALSE(TI->isDefinitelyOut("hello\\world"));
+ EXPECT_TRUE(TI->isDefinitelyOut("hello\\\\world"));
+ EXPECT_FALSE(TI->isDefinitelyOut("atb"));
+ EXPECT_TRUE(TI->isDefinitelyOut("a\\tb"));
+ EXPECT_TRUE(TI->isDefinitelyOut("a\tb"));
+ EXPECT_FALSE(TI->isDefinitelyOut("a0b"));
+}
+
+TEST_F(TrigramIndexTest, Backreference1) {
+ std::unique_ptr<TrigramIndex> TI =
+ makeTrigramIndex({"*foo\\1*"});
+ EXPECT_TRUE(TI->isDefeated());
+}
+
+TEST_F(TrigramIndexTest, Backreference2) {
+ std::unique_ptr<TrigramIndex> TI =
+ makeTrigramIndex({"*foo\\2*"});
+ EXPECT_TRUE(TI->isDefeated());
+}
+
+TEST_F(TrigramIndexTest, Sequence) {
+ std::unique_ptr<TrigramIndex> TI =
+ makeTrigramIndex({"class1.h", "class2.h", "class3.h", "class4.h"});
+ EXPECT_FALSE(TI->isDefeated());
+ EXPECT_FALSE(TI->isDefinitelyOut("class1"));
+ EXPECT_TRUE(TI->isDefinitelyOut("class.h"));
+ EXPECT_TRUE(TI->isDefinitelyOut("class"));
+}
+
+} // namespace
diff --git a/unittests/Support/YAMLIOTest.cpp b/unittests/Support/YAMLIOTest.cpp
index 5f35a802caa5..c3e18d332356 100644
--- a/unittests/Support/YAMLIOTest.cpp
+++ b/unittests/Support/YAMLIOTest.cpp
@@ -2299,3 +2299,80 @@ TEST(YAMLIO, TestWrapFlow) {
out.clear();
}
}
+
+struct MappingContext {
+ int A = 0;
+};
+struct SimpleMap {
+ int B = 0;
+ int C = 0;
+};
+
+struct NestedMap {
+ NestedMap(MappingContext &Context) : Context(Context) {}
+ SimpleMap Simple;
+ MappingContext &Context;
+};
+
+namespace llvm {
+namespace yaml {
+template <> struct MappingContextTraits<SimpleMap, MappingContext> {
+ static void mapping(IO &io, SimpleMap &sm, MappingContext &Context) {
+ io.mapRequired("B", sm.B);
+ io.mapRequired("C", sm.C);
+ ++Context.A;
+ io.mapRequired("Context", Context.A);
+ }
+};
+
+template <> struct MappingTraits<NestedMap> {
+ static void mapping(IO &io, NestedMap &nm) {
+ io.mapRequired("Simple", nm.Simple, nm.Context);
+ }
+};
+}
+}
+
+TEST(YAMLIO, TestMapWithContext) {
+ MappingContext Context;
+ NestedMap Nested(Context);
+ std::string out;
+ llvm::raw_string_ostream ostr(out);
+
+ Output yout(ostr, nullptr, 15);
+
+ yout << Nested;
+ ostr.flush();
+ EXPECT_EQ(1, Context.A);
+ EXPECT_EQ("---\n"
+ "Simple: \n"
+ " B: 0\n"
+ " C: 0\n"
+ " Context: 1\n"
+ "...\n",
+ out);
+
+ out.clear();
+
+ Nested.Simple.B = 2;
+ Nested.Simple.C = 3;
+ yout << Nested;
+ ostr.flush();
+ EXPECT_EQ(2, Context.A);
+ EXPECT_EQ("---\n"
+ "Simple: \n"
+ " B: 2\n"
+ " C: 3\n"
+ " Context: 2\n"
+ "...\n",
+ out);
+ out.clear();
+}
+
+TEST(YAMLIO, InvalidInput) {
+ // polluting 1 value in the sequence
+ Input yin("---\n- foo: 3\n bar: 5\n1\n- foo: 3\n bar: 5\n...\n");
+ std::vector<FooBar> Data;
+ yin >> Data;
+ EXPECT_TRUE((bool)yin.error());
+}
diff --git a/unittests/Support/raw_ostream_test.cpp b/unittests/Support/raw_ostream_test.cpp
index ed6ddabe4634..f87d2f60d169 100644
--- a/unittests/Support/raw_ostream_test.cpp
+++ b/unittests/Support/raw_ostream_test.cpp
@@ -181,5 +181,153 @@ TEST(raw_ostreamTest, FormatDecimal) {
printToString(format_decimal(INT64_MIN, 21), 21));
}
+static std::string formatted_bytes_str(ArrayRef<uint8_t> Bytes,
+ llvm::Optional<uint64_t> Offset = None,
+ uint32_t NumPerLine = 16,
+ uint8_t ByteGroupSize = 4) {
+ std::string S;
+ raw_string_ostream Str(S);
+ Str << format_bytes(Bytes, Offset, NumPerLine, ByteGroupSize);
+ Str.flush();
+ return S;
+}
+
+static std::string format_bytes_with_ascii_str(ArrayRef<uint8_t> Bytes,
+ Optional<uint64_t> Offset = None,
+ uint32_t NumPerLine = 16,
+ uint8_t ByteGroupSize = 4) {
+ std::string S;
+ raw_string_ostream Str(S);
+ Str << format_bytes_with_ascii(Bytes, Offset, NumPerLine, ByteGroupSize);
+ Str.flush();
+ return S;
+}
+
+TEST(raw_ostreamTest, FormattedHexBytes) {
+ std::vector<uint8_t> Buf = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
+ 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
+ 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0',
+ '1', '2', '3', '4', '5', '6', '7', '8', '9'};
+ ArrayRef<uint8_t> B(Buf);
+
+ // Test invalid input.
+ EXPECT_EQ("", formatted_bytes_str(ArrayRef<uint8_t>()));
+ EXPECT_EQ("", format_bytes_with_ascii_str(ArrayRef<uint8_t>()));
+ //----------------------------------------------------------------------
+ // Test hex byte output with the default 4 byte groups
+ //----------------------------------------------------------------------
+ EXPECT_EQ("61", formatted_bytes_str(B.take_front()));
+ EXPECT_EQ("61626364 65", formatted_bytes_str(B.take_front(5)));
+ // Test that 16 bytes get written to a line correctly.
+ EXPECT_EQ("61626364 65666768 696a6b6c 6d6e6f70",
+ formatted_bytes_str(B.take_front(16)));
+ // Test raw bytes with default 16 bytes per line wrapping.
+ EXPECT_EQ("61626364 65666768 696a6b6c 6d6e6f70\n71",
+ formatted_bytes_str(B.take_front(17)));
+ // Test raw bytes with 1 bytes per line wrapping.
+ EXPECT_EQ("61\n62\n63\n64\n65\n66",
+ formatted_bytes_str(B.take_front(6), None, 1));
+ // Test raw bytes with 7 bytes per line wrapping.
+ EXPECT_EQ("61626364 656667\n68696a6b 6c6d6e\n6f7071",
+ formatted_bytes_str(B.take_front(17), None, 7));
+ // Test raw bytes with 8 bytes per line wrapping.
+ EXPECT_EQ("61626364 65666768\n696a6b6c 6d6e6f70\n71",
+ formatted_bytes_str(B.take_front(17), None, 8));
+ //----------------------------------------------------------------------
+ // Test hex byte output with the 1 byte groups
+ //----------------------------------------------------------------------
+ EXPECT_EQ("61 62 63 64 65",
+ formatted_bytes_str(B.take_front(5), None, 16, 1));
+ // Test that 16 bytes get written to a line correctly.
+ EXPECT_EQ("61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70",
+ formatted_bytes_str(B.take_front(16), None, 16, 1));
+ // Test raw bytes with default 16 bytes per line wrapping.
+ EXPECT_EQ("61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70\n71",
+ formatted_bytes_str(B.take_front(17), None, 16, 1));
+ // Test raw bytes with 7 bytes per line wrapping.
+ EXPECT_EQ("61 62 63 64 65 66 67\n68 69 6a 6b 6c 6d 6e\n6f 70 71",
+ formatted_bytes_str(B.take_front(17), None, 7, 1));
+ // Test raw bytes with 8 bytes per line wrapping.
+ EXPECT_EQ("61 62 63 64 65 66 67 68\n69 6a 6b 6c 6d 6e 6f 70\n71",
+ formatted_bytes_str(B.take_front(17), None, 8, 1));
+ //----------------------------------------------------------------------
+ // Test hex byte output with the 2 byte groups
+ //----------------------------------------------------------------------
+ EXPECT_EQ("6162 6364 65", formatted_bytes_str(B.take_front(5), None, 16, 2));
+ // Test that 16 bytes get written to a line correctly.
+ EXPECT_EQ("6162 6364 6566 6768 696a 6b6c 6d6e 6f70",
+ formatted_bytes_str(B.take_front(16), None, 16, 2));
+ // Test raw bytes with default 16 bytes per line wrapping.
+ EXPECT_EQ("6162 6364 6566 6768 696a 6b6c 6d6e 6f70\n71",
+ formatted_bytes_str(B.take_front(17), None, 16, 2));
+ // Test raw bytes with 7 bytes per line wrapping.
+ EXPECT_EQ("6162 6364 6566 67\n6869 6a6b 6c6d 6e\n6f70 71",
+ formatted_bytes_str(B.take_front(17), None, 7, 2));
+ // Test raw bytes with 8 bytes per line wrapping.
+ EXPECT_EQ("6162 6364 6566 6768\n696a 6b6c 6d6e 6f70\n71",
+ formatted_bytes_str(B.take_front(17), None, 8, 2));
+
+ //----------------------------------------------------------------------
+ // Test hex bytes with offset with the default 4 byte groups.
+ //----------------------------------------------------------------------
+ EXPECT_EQ("0000: 61", formatted_bytes_str(B.take_front(), 0x0));
+ EXPECT_EQ("1000: 61", formatted_bytes_str(B.take_front(), 0x1000));
+ EXPECT_EQ("1000: 61\n1001: 62",
+ formatted_bytes_str(B.take_front(2), 0x1000, 1));
+ //----------------------------------------------------------------------
+ // Test hex bytes with ASCII with the default 4 byte groups.
+ //----------------------------------------------------------------------
+ EXPECT_EQ("61626364 65666768 696a6b6c 6d6e6f70 |abcdefghijklmnop|",
+ format_bytes_with_ascii_str(B.take_front(16)));
+ EXPECT_EQ("61626364 65666768 |abcdefgh|\n"
+ "696a6b6c 6d6e6f70 |ijklmnop|",
+ format_bytes_with_ascii_str(B.take_front(16), None, 8));
+ EXPECT_EQ("61626364 65666768 |abcdefgh|\n696a6b6c |ijkl|",
+ format_bytes_with_ascii_str(B.take_front(12), None, 8));
+ std::vector<uint8_t> Unprintable = {'a', '\x1e', 'b', '\x1f'};
+ // Make sure the ASCII is still lined up correctly when fewer bytes than 16
+ // bytes per line are available. The ASCII should still be aligned as if 16
+ // bytes of hex might be displayed.
+ EXPECT_EQ("611e621f |a.b.|",
+ format_bytes_with_ascii_str(Unprintable));
+ //----------------------------------------------------------------------
+ // Test hex bytes with ASCII with offsets with the default 4 byte groups.
+ //----------------------------------------------------------------------
+ EXPECT_EQ("0000: 61626364 65666768 "
+ "696a6b6c 6d6e6f70 |abcdefghijklmnop|",
+ format_bytes_with_ascii_str(B.take_front(16), 0));
+ EXPECT_EQ("0000: 61626364 65666768 |abcdefgh|\n"
+ "0008: 696a6b6c 6d6e6f70 |ijklmnop|",
+ format_bytes_with_ascii_str(B.take_front(16), 0, 8));
+ EXPECT_EQ("0000: 61626364 656667 |abcdefg|\n"
+ "0007: 68696a6b 6c |hijkl|",
+ format_bytes_with_ascii_str(B.take_front(12), 0, 7));
+
+ //----------------------------------------------------------------------
+ // Test hex bytes with ASCII with offsets with the default 2 byte groups.
+ //----------------------------------------------------------------------
+ EXPECT_EQ("0000: 6162 6364 6566 6768 "
+ "696a 6b6c 6d6e 6f70 |abcdefghijklmnop|",
+ format_bytes_with_ascii_str(B.take_front(16), 0, 16, 2));
+ EXPECT_EQ("0000: 6162 6364 6566 6768 |abcdefgh|\n"
+ "0008: 696a 6b6c 6d6e 6f70 |ijklmnop|",
+ format_bytes_with_ascii_str(B.take_front(16), 0, 8, 2));
+ EXPECT_EQ("0000: 6162 6364 6566 67 |abcdefg|\n"
+ "0007: 6869 6a6b 6c |hijkl|",
+ format_bytes_with_ascii_str(B.take_front(12), 0, 7, 2));
+
+ //----------------------------------------------------------------------
+ // Test hex bytes with ASCII with offsets with the default 1 byte groups.
+ //----------------------------------------------------------------------
+ EXPECT_EQ("0000: 61 62 63 64 65 66 67 68 "
+ "69 6a 6b 6c 6d 6e 6f 70 |abcdefghijklmnop|",
+ format_bytes_with_ascii_str(B.take_front(16), 0, 16, 1));
+ EXPECT_EQ("0000: 61 62 63 64 65 66 67 68 |abcdefgh|\n"
+ "0008: 69 6a 6b 6c 6d 6e 6f 70 |ijklmnop|",
+ format_bytes_with_ascii_str(B.take_front(16), 0, 8, 1));
+ EXPECT_EQ("0000: 61 62 63 64 65 66 67 |abcdefg|\n"
+ "0007: 68 69 6a 6b 6c |hijkl|",
+ format_bytes_with_ascii_str(B.take_front(12), 0, 7, 1));
+}
}
diff --git a/unittests/Support/raw_pwrite_stream_test.cpp b/unittests/Support/raw_pwrite_stream_test.cpp
index a62f6bacb070..08b2f90d6054 100644
--- a/unittests/Support/raw_pwrite_stream_test.cpp
+++ b/unittests/Support/raw_pwrite_stream_test.cpp
@@ -10,10 +10,22 @@
#include "gtest/gtest.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
+#define ASSERT_NO_ERROR(x) \
+ if (std::error_code ASSERT_NO_ERROR_ec = x) { \
+ SmallString<128> MessageStorage; \
+ raw_svector_ostream Message(MessageStorage); \
+ Message << #x ": did not return errc::success.\n" \
+ << "error number: " << ASSERT_NO_ERROR_ec.value() << "\n" \
+ << "error message: " << ASSERT_NO_ERROR_ec.message() << "\n"; \
+ GTEST_FATAL_FAILURE_(MessageStorage.c_str()); \
+ } else { \
+ }
+
namespace {
TEST(raw_pwrite_ostreamTest, TestSVector) {
@@ -32,10 +44,28 @@ TEST(raw_pwrite_ostreamTest, TestSVector) {
#endif
}
+#ifdef _WIN32
+#define setenv(name, var, ignore) _putenv_s(name, var)
+#endif
+
TEST(raw_pwrite_ostreamTest, TestFD) {
SmallString<64> Path;
int FD;
- sys::fs::createTemporaryFile("foo", "bar", FD, Path);
+
+ // If we want to clean up from a death test, we have to remove the file from
+ // the parent process. Have the parent create the file, pass it via
+ // environment variable to the child, let the child crash, and then remove it
+ // in the parent.
+ const char *ParentPath = getenv("RAW_PWRITE_TEST_FILE");
+ if (ParentPath) {
+ Path = ParentPath;
+ ASSERT_NO_ERROR(sys::fs::openFileForRead(Path, FD));
+ } else {
+ ASSERT_NO_ERROR(sys::fs::createTemporaryFile("foo", "bar", FD, Path));
+ setenv("RAW_PWRITE_TEST_FILE", Path.c_str(), true);
+ }
+ FileRemover Cleanup(Path);
+
raw_fd_ostream OS(FD, true);
OS << "abcd";
StringRef Test = "test";
diff --git a/unittests/Support/raw_sha1_ostream_test.cpp b/unittests/Support/raw_sha1_ostream_test.cpp
index db2a3e9ab643..1bb4e2eb1d58 100644
--- a/unittests/Support/raw_sha1_ostream_test.cpp
+++ b/unittests/Support/raw_sha1_ostream_test.cpp
@@ -37,6 +37,13 @@ TEST(raw_sha1_ostreamTest, Basic) {
ASSERT_EQ("2EF7BDE608CE5404E97D5F042F95F89F1C232871", Hash);
}
+TEST(sha1_hash_test, Basic) {
+ ArrayRef<uint8_t> Input((const uint8_t *)"Hello World!", 12);
+ std::array<uint8_t, 20> Vec = SHA1::hash(Input);
+ std::string Hash = toHex({(const char *)Vec.data(), 20});
+ ASSERT_EQ("2EF7BDE608CE5404E97D5F042F95F89F1C232871", Hash);
+}
+
// Check that getting the intermediate hash in the middle of the stream does
// not invalidate the final result.
TEST(raw_sha1_ostreamTest, Intermediate) {
diff --git a/unittests/Support/xxhashTest.cpp b/unittests/Support/xxhashTest.cpp
new file mode 100644
index 000000000000..6a88a2d3a5c5
--- /dev/null
+++ b/unittests/Support/xxhashTest.cpp
@@ -0,0 +1,20 @@
+//===- llvm/unittest/Support/xxhashTest.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/xxhash.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+TEST(xxhashTest, Basic) {
+ EXPECT_EQ(0x33bf00a859c4ba3fU, xxHash64("foo"));
+ EXPECT_EQ(0x48a37c90ad27a659U, xxHash64("bar"));
+ EXPECT_EQ(0x69196c1b3af0bff9U,
+ xxHash64("0123456789abcdefghijklmnopqrstuvwxyz"));
+}
diff --git a/unittests/Target/AArch64/CMakeLists.txt b/unittests/Target/AArch64/CMakeLists.txt
new file mode 100644
index 000000000000..94addf4fc121
--- /dev/null
+++ b/unittests/Target/AArch64/CMakeLists.txt
@@ -0,0 +1,21 @@
+include_directories(
+ ${CMAKE_SOURCE_DIR}/lib/Target/AArch64
+ ${CMAKE_BINARY_DIR}/lib/Target/AArch64
+ )
+
+set(LLVM_LINK_COMPONENTS
+ AArch64CodeGen
+ AArch64Desc
+ AArch64Info
+ CodeGen
+ Core
+ MC
+ MIRParser
+ SelectionDAG
+ Support
+ Target
+ )
+
+add_llvm_unittest(AArch64Tests
+ InstSizes.cpp
+ )
diff --git a/unittests/Target/AArch64/InstSizes.cpp b/unittests/Target/AArch64/InstSizes.cpp
new file mode 100644
index 000000000000..22b47c6852ab
--- /dev/null
+++ b/unittests/Target/AArch64/InstSizes.cpp
@@ -0,0 +1,122 @@
+#include "AArch64Subtarget.h"
+#include "AArch64TargetMachine.h"
+#include "llvm/CodeGen/MIRParser/MIRParser.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
+
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+std::unique_ptr<TargetMachine> createTargetMachine() {
+ auto TT(Triple::normalize("aarch64--"));
+ std::string CPU("generic");
+ std::string FS("");
+
+ LLVMInitializeAArch64TargetInfo();
+ LLVMInitializeAArch64Target();
+ LLVMInitializeAArch64TargetMC();
+
+ std::string Error;
+ const Target *TheTarget = TargetRegistry::lookupTarget(TT, Error);
+ assert(TheTarget && "Target not registered");
+
+ return std::unique_ptr<TargetMachine>(
+ TheTarget->createTargetMachine(TT, CPU, FS, TargetOptions(), None,
+ CodeModel::Default, CodeGenOpt::Default));
+}
+
+std::unique_ptr<AArch64InstrInfo> createInstrInfo(TargetMachine *TM) {
+ AArch64Subtarget ST(TM->getTargetTriple(), TM->getTargetCPU(),
+ TM->getTargetFeatureString(), *TM, /* isLittle */ false);
+ return llvm::make_unique<AArch64InstrInfo>(ST);
+}
+
+/// The \p InputIRSnippet is only needed for things that can't be expressed in
+/// the \p InputMIRSnippet (global variables etc)
+/// TODO: Some of this might be useful for other architectures as well - extract
+/// the platform-independent parts somewhere they can be reused.
+void runChecks(
+ TargetMachine *TM, AArch64InstrInfo *II, const StringRef InputIRSnippet,
+ const StringRef InputMIRSnippet,
+ std::function<void(AArch64InstrInfo &, MachineFunction &)> Checks) {
+ LLVMContext Context;
+
+ auto MIRString =
+ "--- |\n"
+ " declare void @sizes()\n"
+ + InputIRSnippet.str() +
+ "...\n"
+ "---\n"
+ "name: sizes\n"
+ "body: |\n"
+ " bb.0:\n"
+ + InputMIRSnippet.str();
+
+ std::unique_ptr<MemoryBuffer> MBuffer = MemoryBuffer::getMemBuffer(MIRString);
+ std::unique_ptr<MIRParser> MParser =
+ createMIRParser(std::move(MBuffer), Context);
+ assert(MParser && "Couldn't create MIR parser");
+
+ std::unique_ptr<Module> M = MParser->parseLLVMModule();
+ assert(M && "Couldn't parse module");
+
+ M->setTargetTriple(TM->getTargetTriple().getTriple());
+ M->setDataLayout(TM->createDataLayout());
+
+ auto F = M->getFunction("sizes");
+ assert(F && "Couldn't find intended function");
+
+ MachineModuleInfo MMI(TM);
+ MMI.setMachineFunctionInitializer(MParser.get());
+ auto &MF = MMI.getMachineFunction(*F);
+
+ Checks(*II, MF);
+}
+
+} // anonymous namespace
+
+TEST(InstSizes, STACKMAP) {
+ std::unique_ptr<TargetMachine> TM = createTargetMachine();
+ std::unique_ptr<AArch64InstrInfo> II = createInstrInfo(TM.get());
+
+ runChecks(TM.get(), II.get(), "", " STACKMAP 0, 16\n"
+ " STACKMAP 1, 32\n",
+ [](AArch64InstrInfo &II, MachineFunction &MF) {
+ auto I = MF.begin()->begin();
+ EXPECT_EQ(16u, II.getInstSizeInBytes(*I));
+ ++I;
+ EXPECT_EQ(32u, II.getInstSizeInBytes(*I));
+ });
+}
+
+TEST(InstSizes, PATCHPOINT) {
+ std::unique_ptr<TargetMachine> TM = createTargetMachine();
+ std::unique_ptr<AArch64InstrInfo> II = createInstrInfo(TM.get());
+
+ runChecks(TM.get(), II.get(), "",
+ " PATCHPOINT 0, 16, 0, 0, 0, csr_aarch64_aapcs\n"
+ " PATCHPOINT 1, 32, 0, 0, 0, csr_aarch64_aapcs\n",
+ [](AArch64InstrInfo &II, MachineFunction &MF) {
+ auto I = MF.begin()->begin();
+ EXPECT_EQ(16u, II.getInstSizeInBytes(*I));
+ ++I;
+ EXPECT_EQ(32u, II.getInstSizeInBytes(*I));
+ });
+}
+
+TEST(InstSizes, TLSDESC_CALLSEQ) {
+ std::unique_ptr<TargetMachine> TM = createTargetMachine();
+ std::unique_ptr<AArch64InstrInfo> II = createInstrInfo(TM.get());
+
+ runChecks(
+ TM.get(), II.get(),
+ " @ThreadLocalGlobal = external thread_local global i32, align 8\n",
+ " TLSDESC_CALLSEQ target-flags(aarch64-tls) @ThreadLocalGlobal\n",
+ [](AArch64InstrInfo &II, MachineFunction &MF) {
+ auto I = MF.begin()->begin();
+ EXPECT_EQ(16u, II.getInstSizeInBytes(*I));
+ });
+}
diff --git a/unittests/Target/CMakeLists.txt b/unittests/Target/CMakeLists.txt
new file mode 100644
index 000000000000..9015029b0970
--- /dev/null
+++ b/unittests/Target/CMakeLists.txt
@@ -0,0 +1,5 @@
+foreach(t ${LLVM_TARGETS_TO_BUILD})
+ if(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${t})
+ add_subdirectory(${t})
+ endif()
+endforeach()
diff --git a/unittests/Transforms/Utils/ASanStackFrameLayoutTest.cpp b/unittests/Transforms/Utils/ASanStackFrameLayoutTest.cpp
index 0d3a239da347..2337ec04776a 100644
--- a/unittests/Transforms/Utils/ASanStackFrameLayoutTest.cpp
+++ b/unittests/Transforms/Utils/ASanStackFrameLayoutTest.cpp
@@ -21,82 +21,88 @@ ShadowBytesToString(ArrayRef<uint8_t> ShadowBytes) {
case kAsanStackLeftRedzoneMagic: os << "L"; break;
case kAsanStackRightRedzoneMagic: os << "R"; break;
case kAsanStackMidRedzoneMagic: os << "M"; break;
+ case kAsanStackUseAfterScopeMagic:
+ os << "S";
+ break;
default: os << (unsigned)ShadowBytes[i];
}
}
return os.str();
}
-static void TestLayout(SmallVector<ASanStackVariableDescription, 10> Vars,
- size_t Granularity, size_t MinHeaderSize,
- const std::string &ExpectedDescr,
- const std::string &ExpectedShadow) {
- ASanStackFrameLayout L;
- ComputeASanStackFrameLayout(Vars, Granularity, MinHeaderSize, &L);
- EXPECT_EQ(ExpectedDescr, L.DescriptionString);
- EXPECT_EQ(ExpectedShadow, ShadowBytesToString(L.ShadowBytes));
-}
+// Use macro to preserve line information in EXPECT_EQ output.
+#define TEST_LAYOUT(V, Granularity, MinHeaderSize, ExpectedDescr, \
+ ExpectedShadow, ExpectedShadowAfterScope) \
+ { \
+ SmallVector<ASanStackVariableDescription, 10> Vars = V; \
+ ASanStackFrameLayout L = \
+ ComputeASanStackFrameLayout(Vars, Granularity, MinHeaderSize); \
+ EXPECT_STREQ(ExpectedDescr, \
+ ComputeASanStackFrameDescription(Vars).c_str()); \
+ EXPECT_EQ(ExpectedShadow, ShadowBytesToString(GetShadowBytes(Vars, L))); \
+ EXPECT_EQ(ExpectedShadowAfterScope, \
+ ShadowBytesToString(GetShadowBytesAfterScope(Vars, L))); \
+ }
TEST(ASanStackFrameLayout, Test) {
-#define VEC1(a) SmallVector<ASanStackVariableDescription, 10>(1, a)
-#define VEC(a) \
- SmallVector<ASanStackVariableDescription, 10>(a, a + sizeof(a) / sizeof(a[0]))
-
-#define VAR(name, size, alignment) \
+#define VAR(name, size, lifetime, alignment, line) \
ASanStackVariableDescription name##size##_##alignment = { \
#name #size "_" #alignment, \
size, \
+ lifetime, \
alignment, \
0, \
- 0 \
+ 0, \
+ line, \
}
- VAR(a, 1, 1);
- VAR(p, 1, 32);
- VAR(p, 1, 256);
- VAR(a, 2, 1);
- VAR(a, 3, 1);
- VAR(a, 4, 1);
- VAR(a, 7, 1);
- VAR(a, 8, 1);
- VAR(a, 9, 1);
- VAR(a, 16, 1);
- VAR(a, 41, 1);
- VAR(a, 105, 1);
+ VAR(a, 1, 0, 1, 0);
+ VAR(p, 1, 0, 32, 15);
+ VAR(p, 1, 0, 256, 2700);
+ VAR(a, 2, 0, 1, 0);
+ VAR(a, 3, 0, 1, 0);
+ VAR(a, 4, 0, 1, 0);
+ VAR(a, 7, 0, 1, 0);
+ VAR(a, 8, 8, 1, 0);
+ VAR(a, 9, 0, 1, 0);
+ VAR(a, 16, 16, 1, 0);
+ VAR(a, 41, 9, 1, 7);
+ VAR(a, 105, 103, 1, 0);
- TestLayout(VEC1(a1_1), 8, 16, "1 16 1 4 a1_1", "LL1R");
- TestLayout(VEC1(a1_1), 64, 64, "1 64 1 4 a1_1", "L1");
- TestLayout(VEC1(p1_32), 8, 32, "1 32 1 5 p1_32", "LLLL1RRR");
- TestLayout(VEC1(p1_32), 8, 64, "1 64 1 5 p1_32", "LLLLLLLL1RRRRRRR");
+ TEST_LAYOUT({a1_1}, 8, 16, "1 16 1 4 a1_1", "LL1R", "LL1R");
+ TEST_LAYOUT({a1_1}, 64, 64, "1 64 1 4 a1_1", "L1", "L1");
+ TEST_LAYOUT({p1_32}, 8, 32, "1 32 1 8 p1_32:15", "LLLL1RRR", "LLLL1RRR");
+ TEST_LAYOUT({p1_32}, 8, 64, "1 64 1 8 p1_32:15", "LLLLLLLL1RRRRRRR",
+ "LLLLLLLL1RRRRRRR");
- TestLayout(VEC1(a1_1), 8, 32, "1 32 1 4 a1_1", "LLLL1RRR");
- TestLayout(VEC1(a2_1), 8, 32, "1 32 2 4 a2_1", "LLLL2RRR");
- TestLayout(VEC1(a3_1), 8, 32, "1 32 3 4 a3_1", "LLLL3RRR");
- TestLayout(VEC1(a4_1), 8, 32, "1 32 4 4 a4_1", "LLLL4RRR");
- TestLayout(VEC1(a7_1), 8, 32, "1 32 7 4 a7_1", "LLLL7RRR");
- TestLayout(VEC1(a8_1), 8, 32, "1 32 8 4 a8_1", "LLLL0RRR");
- TestLayout(VEC1(a9_1), 8, 32, "1 32 9 4 a9_1", "LLLL01RR");
- TestLayout(VEC1(a16_1), 8, 32, "1 32 16 5 a16_1", "LLLL00RR");
- TestLayout(VEC1(p1_256), 8, 32, "1 256 1 6 p1_256",
- "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL1RRR");
- TestLayout(VEC1(a41_1), 8, 32, "1 32 41 5 a41_1", "LLLL000001RRRRRR");
- TestLayout(VEC1(a105_1), 8, 32, "1 32 105 6 a105_1",
- "LLLL00000000000001RRRRRR");
+ TEST_LAYOUT({a1_1}, 8, 32, "1 32 1 4 a1_1", "LLLL1RRR", "LLLL1RRR");
+ TEST_LAYOUT({a2_1}, 8, 32, "1 32 2 4 a2_1", "LLLL2RRR", "LLLL2RRR");
+ TEST_LAYOUT({a3_1}, 8, 32, "1 32 3 4 a3_1", "LLLL3RRR", "LLLL3RRR");
+ TEST_LAYOUT({a4_1}, 8, 32, "1 32 4 4 a4_1", "LLLL4RRR", "LLLL4RRR");
+ TEST_LAYOUT({a7_1}, 8, 32, "1 32 7 4 a7_1", "LLLL7RRR", "LLLL7RRR");
+ TEST_LAYOUT({a8_1}, 8, 32, "1 32 8 4 a8_1", "LLLL0RRR", "LLLLSRRR");
+ TEST_LAYOUT({a9_1}, 8, 32, "1 32 9 4 a9_1", "LLLL01RR", "LLLL01RR");
+ TEST_LAYOUT({a16_1}, 8, 32, "1 32 16 5 a16_1", "LLLL00RR", "LLLLSSRR");
+ TEST_LAYOUT({p1_256}, 8, 32, "1 256 1 11 p1_256:2700",
+ "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL1RRR",
+ "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL1RRR");
+ TEST_LAYOUT({a41_1}, 8, 32, "1 32 41 7 a41_1:7", "LLLL000001RRRRRR",
+ "LLLLSS0001RRRRRR");
+ TEST_LAYOUT({a105_1}, 8, 32, "1 32 105 6 a105_1", "LLLL00000000000001RRRRRR",
+ "LLLLSSSSSSSSSSSSS1RRRRRR");
{
- ASanStackVariableDescription t[] = {a1_1, p1_256};
- TestLayout(VEC(t), 8, 32,
- "2 256 1 6 p1_256 272 1 4 a1_1",
- "LLLLLLLL" "LLLLLLLL" "LLLLLLLL" "LLLLLLLL" "1M1R");
+ SmallVector<ASanStackVariableDescription, 10> t = {a1_1, p1_256};
+ TEST_LAYOUT(t, 8, 32, "2 256 1 11 p1_256:2700 272 1 4 a1_1",
+ "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL1M1R",
+ "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL1M1R");
}
{
- ASanStackVariableDescription t[] = {a1_1, a16_1, a41_1};
- TestLayout(VEC(t), 8, 32,
- "3 32 1 4 a1_1 48 16 5 a16_1 80 41 5 a41_1",
- "LLLL" "1M00" "MM00" "0001" "RRRR");
+ SmallVector<ASanStackVariableDescription, 10> t = {a1_1, a16_1, a41_1};
+ TEST_LAYOUT(t, 8, 32, "3 32 1 4 a1_1 48 16 5 a16_1 80 41 7 a41_1:7",
+ "LLLL1M00MM000001RRRR", "LLLL1MSSMMSS0001RRRR");
}
-#undef VEC1
-#undef VEC
#undef VAR
+#undef TEST_LAYOUT
}
diff --git a/unittests/Transforms/Utils/CMakeLists.txt b/unittests/Transforms/Utils/CMakeLists.txt
index 657d151048e8..c0f37418e492 100644
--- a/unittests/Transforms/Utils/CMakeLists.txt
+++ b/unittests/Transforms/Utils/CMakeLists.txt
@@ -8,6 +8,7 @@ set(LLVM_LINK_COMPONENTS
add_llvm_unittest(UtilsTests
ASanStackFrameLayoutTest.cpp
Cloning.cpp
+ FunctionComparator.cpp
IntegerDivision.cpp
Local.cpp
MemorySSA.cpp
diff --git a/unittests/Transforms/Utils/Cloning.cpp b/unittests/Transforms/Utils/Cloning.cpp
index f53e0a95e94d..216bd32c50d2 100644
--- a/unittests/Transforms/Utils/Cloning.cpp
+++ b/unittests/Transforms/Utils/Cloning.cpp
@@ -231,12 +231,14 @@ protected:
DITypeRefArray ParamTypes = DBuilder.getOrCreateTypeArray(None);
DISubroutineType *FuncType =
DBuilder.createSubroutineType(ParamTypes);
- auto *CU =
- DBuilder.createCompileUnit(dwarf::DW_LANG_C99, "filename.c",
- "/file/dir", "CloneFunc", false, "", 0);
-
- auto *Subprogram = DBuilder.createFunction(
- CU, "f", "f", File, 4, FuncType, true, true, 3, 0, false);
+ auto *CU = DBuilder.createCompileUnit(dwarf::DW_LANG_C99,
+ DBuilder.createFile("filename.c",
+ "/file/dir"),
+ "CloneFunc", false, "", 0);
+
+ auto *Subprogram =
+ DBuilder.createFunction(CU, "f", "f", File, 4, FuncType, true, true, 3,
+ DINode::FlagZero, false);
OldFunc->setSubprogram(Subprogram);
// Function body
@@ -252,8 +254,7 @@ protected:
Instruction* Terminator = IBuilder.CreateRetVoid();
// Create a local variable around the alloca
- auto *IntType =
- DBuilder.createBasicType("int", 32, 0, dwarf::DW_ATE_signed);
+ auto *IntType = DBuilder.createBasicType("int", 32, dwarf::DW_ATE_signed);
auto *E = DBuilder.createExpression();
auto *Variable =
DBuilder.createAutoVariable(Subprogram, "x", File, 5, IntType, true);
@@ -268,7 +269,8 @@ protected:
// Create another, empty, compile unit
DIBuilder DBuilder2(*M);
DBuilder2.createCompileUnit(dwarf::DW_LANG_C99,
- "extra.c", "/file/dir", "CloneFunc", false, "", 0);
+ DBuilder.createFile("extra.c", "/file/dir"),
+ "CloneFunc", false, "", 0);
DBuilder2.finalize();
}
@@ -403,6 +405,11 @@ protected:
void SetupModule() { OldM = new Module("", C); }
void CreateOldModule() {
+ 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, {}));
+
DIBuilder DBuilder(*OldM);
IRBuilder<> IBuilder(C);
@@ -417,12 +424,14 @@ protected:
auto *File = DBuilder.createFile("filename.c", "/file/dir/");
DITypeRefArray ParamTypes = DBuilder.getOrCreateTypeArray(None);
DISubroutineType *DFuncType = DBuilder.createSubroutineType(ParamTypes);
- auto *CU =
- DBuilder.createCompileUnit(dwarf::DW_LANG_C99, "filename.c",
- "/file/dir", "CloneModule", false, "", 0);
+ auto *CU = DBuilder.createCompileUnit(dwarf::DW_LANG_C99,
+ DBuilder.createFile("filename.c",
+ "/file/dir"),
+ "CloneModule", false, "", 0);
// Function DI
- auto *Subprogram = DBuilder.createFunction(CU, "f", "f", File, 4, DFuncType,
- true, true, 3, 0, false);
+ auto *Subprogram =
+ DBuilder.createFunction(CU, "f", "f", File, 4, DFuncType, true, true, 3,
+ DINode::FlagZero, false);
F->setSubprogram(Subprogram);
auto *Entry = BasicBlock::Create(C, "", F);
@@ -458,4 +467,9 @@ TEST_F(CloneModule, Subprogram) {
EXPECT_EQ(SP->getFile()->getFilename(), "filename.c");
EXPECT_EQ(SP->getLine(), (unsigned)4);
}
+
+TEST_F(CloneModule, GlobalMetadata) {
+ GlobalVariable *NewGV = NewM->getGlobalVariable("gv");
+ EXPECT_NE(nullptr, NewGV->getMetadata(LLVMContext::MD_type));
+}
}
diff --git a/unittests/Transforms/Utils/FunctionComparator.cpp b/unittests/Transforms/Utils/FunctionComparator.cpp
new file mode 100644
index 000000000000..ff68cd6224d7
--- /dev/null
+++ b/unittests/Transforms/Utils/FunctionComparator.cpp
@@ -0,0 +1,130 @@
+//===- FunctionComparator.cpp - Unit tests for FunctionComparator ---------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "llvm/Transforms/Utils/FunctionComparator.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/LLVMContext.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+/// Generates a simple test function.
+struct TestFunction {
+ Function *F;
+ BasicBlock *BB;
+ Constant *C;
+ Instruction *I;
+ Type *T;
+
+ TestFunction(LLVMContext &Ctx, Module &M, int addVal) {
+ IRBuilder<> B(Ctx);
+ T = B.getInt8Ty();
+ F = Function::Create(FunctionType::get(T, {B.getInt8PtrTy()}, false),
+ GlobalValue::ExternalLinkage, "F", &M);
+ BB = BasicBlock::Create(Ctx, "", F);
+ B.SetInsertPoint(BB);
+ Argument *PointerArg = &*F->arg_begin();
+ LoadInst *LoadInst = B.CreateLoad(PointerArg);
+ C = B.getInt8(addVal);
+ I = cast<Instruction>(B.CreateAdd(LoadInst, C));
+ B.CreateRet(I);
+ }
+};
+
+/// A class for testing the FunctionComparator API.
+///
+/// The main purpose is to test if the required protected functions are
+/// accessible from a derived class of FunctionComparator.
+class TestComparator : public FunctionComparator {
+public:
+ TestComparator(const Function *F1, const Function *F2,
+ GlobalNumberState *GN)
+ : FunctionComparator(F1, F2, GN) {
+ }
+
+ bool testFunctionAccess(const Function *F1, const Function *F2) {
+ // Test if FnL and FnR are accessible.
+ return F1 == FnL && F2 == FnR;
+ }
+
+ int testCompare() {
+ return compare();
+ }
+
+ int testCompareSignature() {
+ beginCompare();
+ return compareSignature();
+ }
+
+ int testCmpBasicBlocks(BasicBlock *BBL, BasicBlock *BBR) {
+ beginCompare();
+ return cmpBasicBlocks(BBL, BBR);
+ }
+
+ int testCmpConstants(const Constant *L, const Constant *R) {
+ beginCompare();
+ return cmpConstants(L, R);
+ }
+
+ int testCmpGlobalValues(GlobalValue *L, GlobalValue *R) {
+ beginCompare();
+ return cmpGlobalValues(L, R);
+ }
+
+ int testCmpValues(const Value *L, const Value *R) {
+ beginCompare();
+ return cmpValues(L, R);
+ }
+
+ int testCmpOperations(const Instruction *L, const Instruction *R,
+ bool &needToCmpOperands) {
+ beginCompare();
+ return cmpOperations(L, R, needToCmpOperands);
+ }
+
+ int testCmpTypes(Type *TyL, Type *TyR) {
+ beginCompare();
+ return cmpTypes(TyL, TyR);
+ }
+
+ int testCmpPrimitives() {
+ beginCompare();
+ return
+ cmpNumbers(2, 3) +
+ cmpAPInts(APInt(32, 2), APInt(32, 3)) +
+ cmpAPFloats(APFloat(2.0), APFloat(3.0)) +
+ cmpMem("2", "3");
+ }
+};
+
+/// A sanity check for the FunctionComparator API.
+TEST(FunctionComparatorTest, TestAPI) {
+ LLVMContext C;
+ Module M("test", C);
+ TestFunction F1(C, M, 27);
+ TestFunction F2(C, M, 28);
+
+ GlobalNumberState GN;
+ TestComparator Cmp(F1.F, F2.F, &GN);
+
+ EXPECT_TRUE(Cmp.testFunctionAccess(F1.F, F2.F));
+ EXPECT_EQ(Cmp.testCompare(), -1);
+ EXPECT_EQ(Cmp.testCompareSignature(), 0);
+ EXPECT_EQ(Cmp.testCmpBasicBlocks(F1.BB, F2.BB), -1);
+ EXPECT_EQ(Cmp.testCmpConstants(F1.C, F2.C), -1);
+ EXPECT_EQ(Cmp.testCmpGlobalValues(F1.F, F2.F), -1);
+ EXPECT_EQ(Cmp.testCmpValues(F1.I, F2.I), 0);
+ bool needToCmpOperands = false;
+ EXPECT_EQ(Cmp.testCmpOperations(F1.I, F2.I, needToCmpOperands), 0);
+ EXPECT_TRUE(needToCmpOperands);
+ EXPECT_EQ(Cmp.testCmpTypes(F1.T, F2.T), 0);
+ EXPECT_EQ(Cmp.testCmpPrimitives(), -4);
+}
diff --git a/unittests/Transforms/Utils/MemorySSA.cpp b/unittests/Transforms/Utils/MemorySSA.cpp
index c21121f78705..945fe32c316c 100644
--- a/unittests/Transforms/Utils/MemorySSA.cpp
+++ b/unittests/Transforms/Utils/MemorySSA.cpp
@@ -42,14 +42,17 @@ protected:
AssumptionCache AC;
AAResults AA;
BasicAAResult BAA;
- MemorySSA MSSA;
+ // We need to defer MSSA construction until AA is *entirely* set up, which
+ // requires calling addAAResult. Hence, we just use a pointer here.
+ std::unique_ptr<MemorySSA> MSSA;
MemorySSAWalker *Walker;
TestAnalyses(MemorySSATest &Test)
: DT(*Test.F), AC(*Test.F), AA(Test.TLI),
- BAA(Test.DL, Test.TLI, AC, &DT), MSSA(*Test.F, &AA, &DT) {
+ BAA(Test.DL, Test.TLI, AC, &DT) {
AA.addAAResult(BAA);
- Walker = MSSA.getWalker();
+ MSSA = make_unique<MemorySSA>(*Test.F, &AA, &DT);
+ Walker = MSSA->getWalker();
}
};
@@ -65,10 +68,10 @@ public:
: M("MemorySSATest", C), B(C), DL(DLString), TLI(TLII), F(nullptr) {}
};
-TEST_F(MemorySSATest, CreateALoadAndPhi) {
+TEST_F(MemorySSATest, CreateALoad) {
// We create a diamond where there is a store on one side, and then after
- // running memory ssa, create a load after the merge point, and use it to test
- // updating by creating an access for the load and a memoryphi.
+ // building MemorySSA, create a load after the merge point, and use it to test
+ // updating by creating an access for the load.
F = Function::Create(
FunctionType::get(B.getVoidTy(), {B.getInt8PtrTy()}, false),
GlobalValue::ExternalLinkage, "F", &M);
@@ -80,23 +83,19 @@ TEST_F(MemorySSATest, CreateALoadAndPhi) {
B.CreateCondBr(B.getTrue(), Left, Right);
B.SetInsertPoint(Left);
Argument *PointerArg = &*F->arg_begin();
- StoreInst *StoreInst = B.CreateStore(B.getInt8(16), PointerArg);
+ B.CreateStore(B.getInt8(16), PointerArg);
BranchInst::Create(Merge, Left);
BranchInst::Create(Merge, Right);
setupAnalyses();
- MemorySSA &MSSA = Analyses->MSSA;
+ MemorySSA &MSSA = *Analyses->MSSA;
// Add the load
B.SetInsertPoint(Merge);
LoadInst *LoadInst = B.CreateLoad(PointerArg);
- // Should be no phi to start
- EXPECT_EQ(MSSA.getMemoryAccess(Merge), nullptr);
- // Create the phi
- MemoryPhi *MP = MSSA.createMemoryPhi(Merge);
- MemoryDef *StoreAccess = cast<MemoryDef>(MSSA.getMemoryAccess(StoreInst));
- MP->addIncoming(StoreAccess, Left);
- MP->addIncoming(MSSA.getLiveOnEntryDef(), Right);
+ // MemoryPHI should already exist.
+ MemoryPhi *MP = MSSA.getMemoryAccess(Merge);
+ EXPECT_NE(MP, nullptr);
// Create the load memory acccess
MemoryUse *LoadAccess = cast<MemoryUse>(
@@ -106,6 +105,41 @@ TEST_F(MemorySSATest, CreateALoadAndPhi) {
MSSA.verifyMemorySSA();
}
+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.
+ 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);
+ StoreInst *SideStore = B.CreateStore(B.getInt8(16), PointerArg);
+ BranchInst::Create(Merge, Left);
+ BranchInst::Create(Merge, Right);
+ B.SetInsertPoint(Merge);
+ B.CreateLoad(PointerArg);
+ setupAnalyses();
+ MemorySSA &MSSA = *Analyses->MSSA;
+
+ // Move the store
+ SideStore->moveBefore(Entry->getTerminator());
+ MemoryAccess *EntryStoreAccess = MSSA.getMemoryAccess(EntryStore);
+ MemoryAccess *SideStoreAccess = MSSA.getMemoryAccess(SideStore);
+ MemoryAccess *NewStoreAccess = MSSA.createMemoryAccessAfter(
+ SideStore, EntryStoreAccess, EntryStoreAccess);
+ EntryStoreAccess->replaceAllUsesWith(NewStoreAccess);
+ MSSA.removeMemoryAccess(SideStoreAccess);
+ MSSA.verifyMemorySSA();
+}
+
TEST_F(MemorySSATest, RemoveAPhi) {
// We create a diamond where there is a store on one side, and then a load
// after the merge point. This enables us to test a bunch of different
@@ -128,7 +162,7 @@ TEST_F(MemorySSATest, RemoveAPhi) {
LoadInst *LoadInst = B.CreateLoad(PointerArg);
setupAnalyses();
- MemorySSA &MSSA = Analyses->MSSA;
+ MemorySSA &MSSA = *Analyses->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));
@@ -171,7 +205,7 @@ TEST_F(MemorySSATest, RemoveMemoryAccess) {
LoadInst *LoadInst = B.CreateLoad(PointerArg);
setupAnalyses();
- MemorySSA &MSSA = Analyses->MSSA;
+ MemorySSA &MSSA = *Analyses->MSSA;
MemorySSAWalker *Walker = Analyses->Walker;
// Before, the load will be a use of a phi<store, liveonentry>. It should be
@@ -191,9 +225,15 @@ TEST_F(MemorySSATest, RemoveMemoryAccess) {
// but we should now get live on entry for the clobbering definition of the
// load, since it will walk past the phi node since every argument is the
// same.
+ // XXX: This currently requires either removing the phi or resetting optimized
+ // on the load
+
+ EXPECT_FALSE(
+ MSSA.isLiveOnEntryDef(Walker->getClobberingMemoryAccess(LoadInst)));
+ // If we reset optimized, we get live on entry.
+ LoadAccess->resetOptimized();
EXPECT_TRUE(
MSSA.isLiveOnEntryDef(Walker->getClobberingMemoryAccess(LoadInst)));
-
// The phi should now be a two entry phi with two live on entry defs.
for (const auto &Op : DefiningAccess->operands()) {
MemoryAccess *Operand = cast<MemoryAccess>(&*Op);
@@ -230,14 +270,13 @@ TEST_F(MemorySSATest, TestTripleStore) {
StoreInst *S3 = B.CreateStore(ConstantInt::get(Int8, 2), Alloca);
setupAnalyses();
- MemorySSA &MSSA = Analyses->MSSA;
+ MemorySSA &MSSA = *Analyses->MSSA;
MemorySSAWalker *Walker = Analyses->Walker;
unsigned I = 0;
for (StoreInst *V : {S1, S2, S3}) {
// Everything should be clobbered by its defining access
- MemoryAccess *DefiningAccess =
- cast<MemoryUseOrDef>(MSSA.getMemoryAccess(V))->getDefiningAccess();
+ MemoryAccess *DefiningAccess = MSSA.getMemoryAccess(V)->getDefiningAccess();
MemoryAccess *WalkerClobber = Walker->getClobberingMemoryAccess(V);
EXPECT_EQ(DefiningAccess, WalkerClobber)
<< "Store " << I << " doesn't have the correct clobbering access";
@@ -261,7 +300,7 @@ TEST_F(MemorySSATest, TestStoreAndLoad) {
Instruction *LI = B.CreateLoad(Alloca);
setupAnalyses();
- MemorySSA &MSSA = Analyses->MSSA;
+ MemorySSA &MSSA = *Analyses->MSSA;
MemorySSAWalker *Walker = Analyses->Walker;
MemoryAccess *LoadClobber = Walker->getClobberingMemoryAccess(LI);
@@ -290,7 +329,7 @@ TEST_F(MemorySSATest, TestStoreDoubleQuery) {
StoreInst *SI = B.CreateStore(ConstantInt::get(Int8, 0), Alloca);
setupAnalyses();
- MemorySSA &MSSA = Analyses->MSSA;
+ MemorySSA &MSSA = *Analyses->MSSA;
MemorySSAWalker *Walker = Analyses->Walker;
MemoryAccess *StoreAccess = MSSA.getMemoryAccess(SI);
@@ -308,3 +347,188 @@ TEST_F(MemorySSATest, TestStoreDoubleQuery) {
EXPECT_EQ(Clobber, StoreAccess);
EXPECT_TRUE(MSSA.isLiveOnEntryDef(LiveOnEntry));
}
+
+// Bug: During phi optimization, the walker wouldn't cache to the proper result
+// in the farthest-walked BB.
+//
+// Specifically, it would assume that whatever we walked to was a clobber.
+// "Whatever we walked to" isn't a clobber if we hit a cache entry.
+//
+// ...So, we need a test case that looks like:
+// A
+// / \
+// B |
+// \ /
+// C
+//
+// Where, when we try to optimize a thing in 'C', a blocker is found in 'B'.
+// The walk must determine that the blocker exists by using cache entries *while
+// walking* 'B'.
+TEST_F(MemorySSATest, PartialWalkerCacheWithPhis) {
+ F = Function::Create(FunctionType::get(B.getVoidTy(), {}, false),
+ GlobalValue::ExternalLinkage, "F", &M);
+ B.SetInsertPoint(BasicBlock::Create(C, "A", F));
+ Type *Int8 = Type::getInt8Ty(C);
+ Constant *One = ConstantInt::get(Int8, 1);
+ Constant *Zero = ConstantInt::get(Int8, 0);
+ Value *AllocA = B.CreateAlloca(Int8, One, "a");
+ Value *AllocB = B.CreateAlloca(Int8, One, "b");
+ BasicBlock *IfThen = BasicBlock::Create(C, "B", F);
+ BasicBlock *IfEnd = BasicBlock::Create(C, "C", F);
+
+ B.CreateCondBr(UndefValue::get(Type::getInt1Ty(C)), IfThen, IfEnd);
+
+ B.SetInsertPoint(IfThen);
+ Instruction *FirstStore = B.CreateStore(Zero, AllocA);
+ B.CreateStore(Zero, AllocB);
+ Instruction *ALoad0 = B.CreateLoad(AllocA, "");
+ Instruction *BStore = B.CreateStore(Zero, AllocB);
+ // Due to use optimization/etc. we make a store to A, which is removed after
+ // we build MSSA. This helps keep the test case simple-ish.
+ Instruction *KillStore = B.CreateStore(Zero, AllocA);
+ Instruction *ALoad = B.CreateLoad(AllocA, "");
+ B.CreateBr(IfEnd);
+
+ B.SetInsertPoint(IfEnd);
+ Instruction *BelowPhi = B.CreateStore(Zero, AllocA);
+
+ setupAnalyses();
+ MemorySSA &MSSA = *Analyses->MSSA;
+ MemorySSAWalker *Walker = Analyses->Walker;
+
+ // Kill `KillStore`; it exists solely so that the load after it won't be
+ // optimized to FirstStore.
+ MSSA.removeMemoryAccess(MSSA.getMemoryAccess(KillStore));
+ KillStore->eraseFromParent();
+ auto *ALoadMA = cast<MemoryUse>(MSSA.getMemoryAccess(ALoad));
+ EXPECT_EQ(ALoadMA->getDefiningAccess(), MSSA.getMemoryAccess(BStore));
+
+ // Populate the cache for the store to AllocB directly after FirstStore. It
+ // should point to something in block B (so something in D can't be optimized
+ // to it).
+ MemoryAccess *Load0Clobber = Walker->getClobberingMemoryAccess(ALoad0);
+ EXPECT_EQ(MSSA.getMemoryAccess(FirstStore), Load0Clobber);
+
+ // If the bug exists, this will introduce a bad cache entry for %a on BStore.
+ // It will point to the store to %b after FirstStore. This only happens during
+ // phi optimization.
+ MemoryAccess *BottomClobber = Walker->getClobberingMemoryAccess(BelowPhi);
+ MemoryAccess *Phi = MSSA.getMemoryAccess(IfEnd);
+ EXPECT_EQ(BottomClobber, Phi);
+
+ // This query will first check the cache for {%a, BStore}. It should point to
+ // FirstStore, not to the store after FirstStore.
+ MemoryAccess *UseClobber = Walker->getClobberingMemoryAccess(ALoad);
+ EXPECT_EQ(UseClobber, MSSA.getMemoryAccess(FirstStore));
+}
+
+// Test that our walker properly handles loads with the invariant group
+// attribute. It's a bit hacky, since we add the invariant attribute *after*
+// building MSSA. Otherwise, the use optimizer will optimize it for us, which
+// isn't what we want.
+// FIXME: It may be easier/cleaner to just add an 'optimize uses?' flag to MSSA.
+TEST_F(MemorySSATest, WalkerInvariantLoadOpt) {
+ F = Function::Create(FunctionType::get(B.getVoidTy(), {}, false),
+ GlobalValue::ExternalLinkage, "F", &M);
+ B.SetInsertPoint(BasicBlock::Create(C, "", F));
+ Type *Int8 = Type::getInt8Ty(C);
+ Constant *One = ConstantInt::get(Int8, 1);
+ Value *AllocA = B.CreateAlloca(Int8, One, "");
+
+ Instruction *Store = B.CreateStore(One, AllocA);
+ Instruction *Load = B.CreateLoad(AllocA);
+
+ setupAnalyses();
+ MemorySSA &MSSA = *Analyses->MSSA;
+ MemorySSAWalker *Walker = Analyses->Walker;
+
+ auto *LoadMA = cast<MemoryUse>(MSSA.getMemoryAccess(Load));
+ auto *StoreMA = cast<MemoryDef>(MSSA.getMemoryAccess(Store));
+ EXPECT_EQ(LoadMA->getDefiningAccess(), StoreMA);
+
+ // ...At the time of writing, no cache should exist for LoadMA. Be a bit
+ // flexible to future changes.
+ Walker->invalidateInfo(LoadMA);
+ Load->setMetadata(LLVMContext::MD_invariant_load, MDNode::get(C, {}));
+
+ MemoryAccess *LoadClobber = Walker->getClobberingMemoryAccess(LoadMA);
+ EXPECT_EQ(LoadClobber, MSSA.getLiveOnEntryDef());
+}
+
+// Test loads get reoptimized properly by the walker.
+TEST_F(MemorySSATest, WalkerReopt) {
+ F = Function::Create(FunctionType::get(B.getVoidTy(), {}, false),
+ GlobalValue::ExternalLinkage, "F", &M);
+ B.SetInsertPoint(BasicBlock::Create(C, "", F));
+ Type *Int8 = Type::getInt8Ty(C);
+ Value *AllocaA = B.CreateAlloca(Int8, ConstantInt::get(Int8, 1), "A");
+ Instruction *SIA = B.CreateStore(ConstantInt::get(Int8, 0), AllocaA);
+ Value *AllocaB = B.CreateAlloca(Int8, ConstantInt::get(Int8, 1), "B");
+ Instruction *SIB = B.CreateStore(ConstantInt::get(Int8, 0), AllocaB);
+ Instruction *LIA = B.CreateLoad(AllocaA);
+
+ setupAnalyses();
+ MemorySSA &MSSA = *Analyses->MSSA;
+ MemorySSAWalker *Walker = Analyses->Walker;
+
+ 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);
+
+ // Create the load memory access pointing to an unoptimized place.
+ MemoryUse *NewLoadAccess = cast<MemoryUse>(MSSA.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) {
+ F = Function::Create(FunctionType::get(B.getVoidTy(), {}, false),
+ GlobalValue::ExternalLinkage, "F", &M);
+ B.SetInsertPoint(BasicBlock::Create(C, "", F));
+
+ Type *Int8 = Type::getInt8Ty(C);
+ Value *A = B.CreateAlloca(Int8, ConstantInt::get(Int8, 1), "A");
+ Value *B_ = B.CreateAlloca(Int8, ConstantInt::get(Int8, 1), "B");
+ Value *C = B.CreateAlloca(Int8, ConstantInt::get(Int8, 1), "C");
+
+ StoreInst *StoreA0 = B.CreateStore(ConstantInt::get(Int8, 0), A);
+ 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);
+
+ setupAnalyses();
+ MemorySSA &MSSA = *Analyses->MSSA;
+ MemorySSAWalker &Walker = *Analyses->Walker;
+
+ StoreC->moveBefore(StoreB);
+ MSSA.spliceMemoryAccessAbove(cast<MemoryDef>(MSSA.getMemoryAccess(StoreB)),
+ MSSA.getMemoryAccess(StoreC));
+
+ MSSA.verifyMemorySSA();
+
+ EXPECT_EQ(MSSA.getMemoryAccess(StoreB)->getDefiningAccess(),
+ MSSA.getMemoryAccess(StoreC));
+ EXPECT_EQ(MSSA.getMemoryAccess(StoreC)->getDefiningAccess(),
+ MSSA.getMemoryAccess(StoreA0));
+ EXPECT_EQ(MSSA.getMemoryAccess(StoreA2)->getDefiningAccess(),
+ MSSA.getMemoryAccess(StoreA1));
+ EXPECT_EQ(Walker.getClobberingMemoryAccess(LoadB),
+ MSSA.getMemoryAccess(StoreB));
+ EXPECT_EQ(Walker.getClobberingMemoryAccess(LoadC),
+ MSSA.getMemoryAccess(StoreC));
+
+ // exercise block numbering
+ EXPECT_TRUE(MSSA.locallyDominates(MSSA.getMemoryAccess(StoreC),
+ MSSA.getMemoryAccess(StoreB)));
+ EXPECT_TRUE(MSSA.locallyDominates(MSSA.getMemoryAccess(StoreA1),
+ MSSA.getMemoryAccess(StoreA2)));
+}