diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2014-11-24 09:08:18 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2014-11-24 09:08:18 +0000 |
commit | 5ca98fd98791947eba83a1ed3f2c8191ef7afa6c (patch) | |
tree | f5944309621cee4fe0976be6f9ac619b7ebfc4c2 /unittests/Transforms | |
parent | 68bcb7db193e4bc81430063148253d30a791023e (diff) |
Diffstat (limited to 'unittests/Transforms')
-rw-r--r-- | unittests/Transforms/DebugIR/CMakeLists.txt | 2 | ||||
-rw-r--r-- | unittests/Transforms/DebugIR/DebugIR.cpp | 25 | ||||
-rw-r--r-- | unittests/Transforms/Utils/ASanStackFrameLayoutTest.cpp | 102 | ||||
-rw-r--r-- | unittests/Transforms/Utils/CMakeLists.txt | 4 | ||||
-rw-r--r-- | unittests/Transforms/Utils/Cloning.cpp | 237 | ||||
-rw-r--r-- | unittests/Transforms/Utils/IntegerDivision.cpp | 122 | ||||
-rw-r--r-- | unittests/Transforms/Utils/SpecialCaseList.cpp | 232 |
7 files changed, 477 insertions, 247 deletions
diff --git a/unittests/Transforms/DebugIR/CMakeLists.txt b/unittests/Transforms/DebugIR/CMakeLists.txt index 4b471939ef1f..88734d2b8fcf 100644 --- a/unittests/Transforms/DebugIR/CMakeLists.txt +++ b/unittests/Transforms/DebugIR/CMakeLists.txt @@ -1,5 +1,7 @@ set(LLVM_LINK_COMPONENTS + Core Instrumentation + Support ) add_llvm_unittest(DebugIRTests diff --git a/unittests/Transforms/DebugIR/DebugIR.cpp b/unittests/Transforms/DebugIR/DebugIR.cpp index 7d213fd0567a..41df14721684 100644 --- a/unittests/Transforms/DebugIR/DebugIR.cpp +++ b/unittests/Transforms/DebugIR/DebugIR.cpp @@ -13,17 +13,17 @@ //===----------------------------------------------------------------------===// #include "llvm/ADT/Triple.h" +#include "../lib/Transforms/Instrumentation/DebugIR.h" #include "llvm/Config/config.h" -#include "llvm/DebugInfo.h" -#include "llvm/DIBuilder.h" +#include "llvm/IR/DIBuilder.h" +#include "llvm/IR/DebugInfo.h" #include "llvm/IR/Module.h" -#include "llvm/Support/Host.h" +#include "llvm/Support/Errc.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/Host.h" #include "llvm/Support/Path.h" #include "llvm/Transforms/Instrumentation.h" -#include "../lib/Transforms/Instrumentation/DebugIR.h" - // These tests do not depend on MCJIT, but we use the TrivialModuleBuilder // helper class to construct some trivial Modules. #include "../unittests/ExecutionEngine/MCJIT/MCJITTestBase.h" @@ -56,16 +56,17 @@ void insertCUDescriptor(Module *M, StringRef File, StringRef Dir, /// Attempts to remove file at Path and returns true if it existed, or false if /// it did not. bool removeIfExists(StringRef Path) { - bool existed = false; - sys::fs::remove(Path, existed); - return existed; + // This is an approximation, on error we don't know in general if the file + // existed or not. + std::error_code EC = sys::fs::remove(Path, false); + return EC != llvm::errc::no_such_file_or_directory; } char * current_dir() { #if defined(LLVM_ON_WIN32) || defined(HAVE_GETCWD) // calling getcwd (or _getcwd() on windows) with a null buffer makes it // allocate a sufficiently sized buffer to store the current working dir. - return getcwd_impl(0, 0); + return getcwd_impl(nullptr, 0); #else return 0; #endif @@ -90,8 +91,8 @@ protected: LLVMContext Context; char *cwd; - OwningPtr<Module> M; - OwningPtr<DebugIR> D; + std::unique_ptr<Module> M; + std::unique_ptr<DebugIR> D; }; // Test empty named Module that is not supposed to be output to disk. @@ -278,7 +279,7 @@ TEST_F(TestDebugIR, ExistingMetadataRetained) { // verify DebugIR did not generate a file ASSERT_FALSE(removeIfExists(Path)) << "Unexpected file " << Path; - DICompileUnit CU(*Finder.compile_unit_begin()); + DICompileUnit CU(*Finder.compile_units().begin()); // Verify original CU information is retained ASSERT_EQ(Filename, CU.getFilename()); diff --git a/unittests/Transforms/Utils/ASanStackFrameLayoutTest.cpp b/unittests/Transforms/Utils/ASanStackFrameLayoutTest.cpp new file mode 100644 index 000000000000..0d3a239da347 --- /dev/null +++ b/unittests/Transforms/Utils/ASanStackFrameLayoutTest.cpp @@ -0,0 +1,102 @@ +//===- ASanStackFrameLayoutTest.cpp - Tests for ComputeASanStackFrameLayout===// +// +// 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/ASanStackFrameLayout.h" +#include "llvm/ADT/ArrayRef.h" +#include "gtest/gtest.h" +#include <sstream> + +using namespace llvm; + +static std::string +ShadowBytesToString(ArrayRef<uint8_t> ShadowBytes) { + std::ostringstream os; + for (size_t i = 0, n = ShadowBytes.size(); i < n; i++) { + switch (ShadowBytes[i]) { + case kAsanStackLeftRedzoneMagic: os << "L"; break; + case kAsanStackRightRedzoneMagic: os << "R"; break; + case kAsanStackMidRedzoneMagic: os << "M"; 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)); +} + +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) \ + ASanStackVariableDescription name##size##_##alignment = { \ + #name #size "_" #alignment, \ + size, \ + alignment, \ + 0, \ + 0 \ + } + + 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); + + 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"); + + 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"); + + { + 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"); + } + + { + 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"); + } +#undef VEC1 +#undef VEC +#undef VAR +} diff --git a/unittests/Transforms/Utils/CMakeLists.txt b/unittests/Transforms/Utils/CMakeLists.txt index 0656390cbbea..ffa1d49d380b 100644 --- a/unittests/Transforms/Utils/CMakeLists.txt +++ b/unittests/Transforms/Utils/CMakeLists.txt @@ -1,10 +1,12 @@ set(LLVM_LINK_COMPONENTS + Core + Support TransformUtils ) add_llvm_unittest(UtilsTests + ASanStackFrameLayoutTest.cpp Cloning.cpp IntegerDivision.cpp Local.cpp - SpecialCaseList.cpp ) diff --git a/unittests/Transforms/Utils/Cloning.cpp b/unittests/Transforms/Utils/Cloning.cpp index e19ae5bc2fb4..b3a1f5b10521 100644 --- a/unittests/Transforms/Utils/Cloning.cpp +++ b/unittests/Transforms/Utils/Cloning.cpp @@ -7,15 +7,22 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Transforms/Utils/Cloning.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/IR/Argument.h" #include "llvm/IR/Constant.h" +#include "llvm/IR/DebugInfo.h" +#include "llvm/IR/DIBuilder.h" #include "llvm/IR/Function.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/InstIterator.h" #include "llvm/IR/Instructions.h" +#include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Module.h" #include "llvm/IR/LLVMContext.h" -#include "llvm/Transforms/Utils/Cloning.h" #include "gtest/gtest.h" using namespace llvm; @@ -25,7 +32,7 @@ namespace { class CloneInstruction : public ::testing::Test { protected: virtual void SetUp() { - V = NULL; + V = nullptr; } template <typename T> @@ -173,4 +180,230 @@ TEST_F(CloneInstruction, Attributes) { delete F2; } +TEST_F(CloneInstruction, CallingConvention) { + Type *ArgTy1[] = { Type::getInt32PtrTy(context) }; + FunctionType *FT1 = FunctionType::get(Type::getVoidTy(context), ArgTy1, false); + + Function *F1 = Function::Create(FT1, Function::ExternalLinkage); + F1->setCallingConv(CallingConv::Cold); + BasicBlock *BB = BasicBlock::Create(context, "", F1); + IRBuilder<> Builder(BB); + Builder.CreateRetVoid(); + + Function *F2 = Function::Create(FT1, Function::ExternalLinkage); + + SmallVector<ReturnInst*, 4> Returns; + ValueToValueMapTy VMap; + VMap[F1->arg_begin()] = F2->arg_begin(); + + CloneFunctionInto(F2, F1, VMap, false, Returns); + EXPECT_EQ(CallingConv::Cold, F2->getCallingConv()); + + delete F1; + delete F2; +} + +class CloneFunc : public ::testing::Test { +protected: + virtual void SetUp() { + SetupModule(); + CreateOldFunc(); + CreateNewFunc(); + SetupFinder(); + } + + virtual void TearDown() { + delete Finder; + } + + void SetupModule() { + M = new Module("", C); + } + + void CreateOldFunc() { + FunctionType* FuncType = FunctionType::get(Type::getVoidTy(C), false); + OldFunc = Function::Create(FuncType, GlobalValue::PrivateLinkage, "f", M); + CreateOldFunctionBodyAndDI(); + } + + void CreateOldFunctionBodyAndDI() { + DIBuilder DBuilder(*M); + IRBuilder<> IBuilder(C); + + // Function DI + DIFile File = DBuilder.createFile("filename.c", "/file/dir/"); + DIArray ParamTypes = DBuilder.getOrCreateArray(ArrayRef<Value*>()); + DICompositeType FuncType = DBuilder.createSubroutineType(File, ParamTypes); + DICompileUnit CU = DBuilder.createCompileUnit(dwarf::DW_LANG_C99, + "filename.c", "/file/dir", "CloneFunc", false, "", 0); + + DISubprogram Subprogram = DBuilder.createFunction(CU, "f", "f", File, 4, + FuncType, true, true, 3, 0, false, OldFunc); + + // Function body + BasicBlock* Entry = BasicBlock::Create(C, "", OldFunc); + IBuilder.SetInsertPoint(Entry); + DebugLoc Loc = DebugLoc::get(3, 2, Subprogram); + IBuilder.SetCurrentDebugLocation(Loc); + AllocaInst* Alloca = IBuilder.CreateAlloca(IntegerType::getInt32Ty(C)); + IBuilder.SetCurrentDebugLocation(DebugLoc::get(4, 2, Subprogram)); + Value* AllocaContent = IBuilder.getInt32(1); + Instruction* Store = IBuilder.CreateStore(AllocaContent, Alloca); + IBuilder.SetCurrentDebugLocation(DebugLoc::get(5, 2, Subprogram)); + Instruction* Terminator = IBuilder.CreateRetVoid(); + + // Create a local variable around the alloca + DIType IntType = DBuilder.createBasicType("int", 32, 0, + dwarf::DW_ATE_signed); + DIVariable Variable = DBuilder.createLocalVariable( + dwarf::DW_TAG_auto_variable, Subprogram, "x", File, 5, IntType, true); + DBuilder.insertDeclare(Alloca, Variable, Store); + DBuilder.insertDbgValueIntrinsic(AllocaContent, 0, Variable, Terminator); + // Finalize the debug info + DBuilder.finalize(); + + + // Create another, empty, compile unit + DIBuilder DBuilder2(*M); + DBuilder2.createCompileUnit(dwarf::DW_LANG_C99, + "extra.c", "/file/dir", "CloneFunc", false, "", 0); + DBuilder2.finalize(); + } + + void CreateNewFunc() { + ValueToValueMapTy VMap; + NewFunc = CloneFunction(OldFunc, VMap, true, nullptr); + M->getFunctionList().push_back(NewFunc); + } + + void SetupFinder() { + Finder = new DebugInfoFinder(); + Finder->processModule(*M); + } + + LLVMContext C; + Function* OldFunc; + Function* NewFunc; + Module* M; + DebugInfoFinder* Finder; +}; + +// Test that a new, distinct function was created. +TEST_F(CloneFunc, NewFunctionCreated) { + EXPECT_NE(OldFunc, NewFunc); +} + +// Test that a new subprogram entry was added and is pointing to the new +// function, while the original subprogram still points to the old one. +TEST_F(CloneFunc, Subprogram) { + unsigned SubprogramCount = Finder->subprogram_count(); + EXPECT_EQ(2U, SubprogramCount); + + auto Iter = Finder->subprograms().begin(); + DISubprogram Sub1(*Iter); + EXPECT_TRUE(Sub1.Verify()); + Iter++; + DISubprogram Sub2(*Iter); + EXPECT_TRUE(Sub2.Verify()); + + EXPECT_TRUE((Sub1.getFunction() == OldFunc && Sub2.getFunction() == NewFunc) + || (Sub1.getFunction() == NewFunc && Sub2.getFunction() == OldFunc)); +} + +// Test that the new subprogram entry was not added to the CU which doesn't +// contain the old subprogram entry. +TEST_F(CloneFunc, SubprogramInRightCU) { + EXPECT_EQ(2U, Finder->compile_unit_count()); + + auto Iter = Finder->compile_units().begin(); + DICompileUnit CU1(*Iter); + EXPECT_TRUE(CU1.Verify()); + Iter++; + DICompileUnit CU2(*Iter); + EXPECT_TRUE(CU2.Verify()); + EXPECT_TRUE(CU1.getSubprograms().getNumElements() == 0 + || CU2.getSubprograms().getNumElements() == 0); +} + +// Test that instructions in the old function still belong to it in the +// metadata, while instruction in the new function belong to the new one. +TEST_F(CloneFunc, InstructionOwnership) { + inst_iterator OldIter = inst_begin(OldFunc); + inst_iterator OldEnd = inst_end(OldFunc); + inst_iterator NewIter = inst_begin(NewFunc); + inst_iterator NewEnd = inst_end(NewFunc); + while (OldIter != OldEnd && NewIter != NewEnd) { + Instruction& OldI = *OldIter; + Instruction& NewI = *NewIter; + EXPECT_NE(&OldI, &NewI); + + EXPECT_EQ(OldI.hasMetadata(), NewI.hasMetadata()); + if (OldI.hasMetadata()) { + const DebugLoc& OldDL = OldI.getDebugLoc(); + const DebugLoc& NewDL = NewI.getDebugLoc(); + + // Verify that the debug location data is the same + EXPECT_EQ(OldDL.getLine(), NewDL.getLine()); + EXPECT_EQ(OldDL.getCol(), NewDL.getCol()); + + // But that they belong to different functions + DISubprogram OldSubprogram(OldDL.getScope(C)); + DISubprogram NewSubprogram(NewDL.getScope(C)); + EXPECT_TRUE(OldSubprogram.Verify()); + EXPECT_TRUE(NewSubprogram.Verify()); + EXPECT_EQ(OldFunc, OldSubprogram.getFunction()); + EXPECT_EQ(NewFunc, NewSubprogram.getFunction()); + } + + ++OldIter; + ++NewIter; + } + EXPECT_EQ(OldEnd, OldIter); + EXPECT_EQ(NewEnd, NewIter); +} + +// Test that the arguments for debug intrinsics in the new function were +// properly cloned +TEST_F(CloneFunc, DebugIntrinsics) { + inst_iterator OldIter = inst_begin(OldFunc); + inst_iterator OldEnd = inst_end(OldFunc); + inst_iterator NewIter = inst_begin(NewFunc); + inst_iterator NewEnd = inst_end(NewFunc); + while (OldIter != OldEnd && NewIter != NewEnd) { + Instruction& OldI = *OldIter; + Instruction& NewI = *NewIter; + if (DbgDeclareInst* OldIntrin = dyn_cast<DbgDeclareInst>(&OldI)) { + DbgDeclareInst* NewIntrin = dyn_cast<DbgDeclareInst>(&NewI); + EXPECT_TRUE(NewIntrin); + + // Old address must belong to the old function + EXPECT_EQ(OldFunc, cast<AllocaInst>(OldIntrin->getAddress())-> + getParent()->getParent()); + // New address must belong to the new function + EXPECT_EQ(NewFunc, cast<AllocaInst>(NewIntrin->getAddress())-> + getParent()->getParent()); + + // Old variable must belong to the old function + EXPECT_EQ(OldFunc, DISubprogram(DIVariable(OldIntrin->getVariable()) + .getContext()).getFunction()); + // New variable must belong to the New function + EXPECT_EQ(NewFunc, DISubprogram(DIVariable(NewIntrin->getVariable()) + .getContext()).getFunction()); + } else if (DbgValueInst* OldIntrin = dyn_cast<DbgValueInst>(&OldI)) { + DbgValueInst* NewIntrin = dyn_cast<DbgValueInst>(&NewI); + EXPECT_TRUE(NewIntrin); + + // Old variable must belong to the old function + EXPECT_EQ(OldFunc, DISubprogram(DIVariable(OldIntrin->getVariable()) + .getContext()).getFunction()); + // New variable must belong to the New function + EXPECT_EQ(NewFunc, DISubprogram(DIVariable(NewIntrin->getVariable()) + .getContext()).getFunction()); + } + + ++OldIter; + ++NewIter; + } +} + } diff --git a/unittests/Transforms/Utils/IntegerDivision.cpp b/unittests/Transforms/Utils/IntegerDivision.cpp index 44c2328ee354..f7318a2e7897 100644 --- a/unittests/Transforms/Utils/IntegerDivision.cpp +++ b/unittests/Transforms/Utils/IntegerDivision.cpp @@ -19,6 +19,7 @@ using namespace llvm; namespace { + TEST(IntegerDivision, SDiv) { LLVMContext &C(getGlobalContext()); Module M("test division", C); @@ -139,4 +140,125 @@ TEST(IntegerDivision, URem) { EXPECT_TRUE(Remainder && Remainder->getOpcode() == Instruction::Sub); } + +TEST(IntegerDivision, SDiv64) { + LLVMContext &C(getGlobalContext()); + Module M("test division", C); + IRBuilder<> Builder(C); + + SmallVector<Type*, 2> ArgTys(2, Builder.getInt64Ty()); + Function *F = Function::Create(FunctionType::get(Builder.getInt64Ty(), + ArgTys, false), + GlobalValue::ExternalLinkage, "F", &M); + assert(F->getArgumentList().size() == 2); + + BasicBlock *BB = BasicBlock::Create(C, "", F); + Builder.SetInsertPoint(BB); + + Function::arg_iterator AI = F->arg_begin(); + Value *A = AI++; + Value *B = AI++; + + Value *Div = Builder.CreateSDiv(A, B); + EXPECT_TRUE(BB->front().getOpcode() == Instruction::SDiv); + + Value *Ret = Builder.CreateRet(Div); + + expandDivision(cast<BinaryOperator>(Div)); + EXPECT_TRUE(BB->front().getOpcode() == Instruction::AShr); + + Instruction* Quotient = dyn_cast<Instruction>(cast<User>(Ret)->getOperand(0)); + EXPECT_TRUE(Quotient && Quotient->getOpcode() == Instruction::Sub); +} + +TEST(IntegerDivision, UDiv64) { + LLVMContext &C(getGlobalContext()); + Module M("test division", C); + IRBuilder<> Builder(C); + + SmallVector<Type*, 2> ArgTys(2, Builder.getInt64Ty()); + Function *F = Function::Create(FunctionType::get(Builder.getInt64Ty(), + ArgTys, false), + GlobalValue::ExternalLinkage, "F", &M); + assert(F->getArgumentList().size() == 2); + + BasicBlock *BB = BasicBlock::Create(C, "", F); + Builder.SetInsertPoint(BB); + + Function::arg_iterator AI = F->arg_begin(); + Value *A = AI++; + Value *B = AI++; + + Value *Div = Builder.CreateUDiv(A, B); + EXPECT_TRUE(BB->front().getOpcode() == Instruction::UDiv); + + Value *Ret = Builder.CreateRet(Div); + + expandDivision(cast<BinaryOperator>(Div)); + EXPECT_TRUE(BB->front().getOpcode() == Instruction::ICmp); + + Instruction* Quotient = dyn_cast<Instruction>(cast<User>(Ret)->getOperand(0)); + EXPECT_TRUE(Quotient && Quotient->getOpcode() == Instruction::PHI); +} + +TEST(IntegerDivision, SRem64) { + LLVMContext &C(getGlobalContext()); + Module M("test remainder", C); + IRBuilder<> Builder(C); + + SmallVector<Type*, 2> ArgTys(2, Builder.getInt64Ty()); + Function *F = Function::Create(FunctionType::get(Builder.getInt64Ty(), + ArgTys, false), + GlobalValue::ExternalLinkage, "F", &M); + assert(F->getArgumentList().size() == 2); + + BasicBlock *BB = BasicBlock::Create(C, "", F); + Builder.SetInsertPoint(BB); + + Function::arg_iterator AI = F->arg_begin(); + Value *A = AI++; + Value *B = AI++; + + Value *Rem = Builder.CreateSRem(A, B); + EXPECT_TRUE(BB->front().getOpcode() == Instruction::SRem); + + Value *Ret = Builder.CreateRet(Rem); + + expandRemainder(cast<BinaryOperator>(Rem)); + EXPECT_TRUE(BB->front().getOpcode() == Instruction::AShr); + + Instruction* Remainder = dyn_cast<Instruction>(cast<User>(Ret)->getOperand(0)); + EXPECT_TRUE(Remainder && Remainder->getOpcode() == Instruction::Sub); +} + +TEST(IntegerDivision, URem64) { + LLVMContext &C(getGlobalContext()); + Module M("test remainder", C); + IRBuilder<> Builder(C); + + SmallVector<Type*, 2> ArgTys(2, Builder.getInt64Ty()); + Function *F = Function::Create(FunctionType::get(Builder.getInt64Ty(), + ArgTys, false), + GlobalValue::ExternalLinkage, "F", &M); + assert(F->getArgumentList().size() == 2); + + BasicBlock *BB = BasicBlock::Create(C, "", F); + Builder.SetInsertPoint(BB); + + Function::arg_iterator AI = F->arg_begin(); + Value *A = AI++; + Value *B = AI++; + + Value *Rem = Builder.CreateURem(A, B); + EXPECT_TRUE(BB->front().getOpcode() == Instruction::URem); + + Value *Ret = Builder.CreateRet(Rem); + + expandRemainder(cast<BinaryOperator>(Rem)); + EXPECT_TRUE(BB->front().getOpcode() == Instruction::ICmp); + + Instruction* Remainder = dyn_cast<Instruction>(cast<User>(Ret)->getOperand(0)); + EXPECT_TRUE(Remainder && Remainder->getOpcode() == Instruction::Sub); +} + } diff --git a/unittests/Transforms/Utils/SpecialCaseList.cpp b/unittests/Transforms/Utils/SpecialCaseList.cpp deleted file mode 100644 index 07ac908caabc..000000000000 --- a/unittests/Transforms/Utils/SpecialCaseList.cpp +++ /dev/null @@ -1,232 +0,0 @@ -//===- SpecialCaseList.cpp - Unit tests for SpecialCaseList ---------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "llvm/IR/Function.h" -#include "llvm/IR/LLVMContext.h" -#include "llvm/IR/Module.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Transforms/Utils/SpecialCaseList.h" -#include "gtest/gtest.h" - -using namespace llvm; - -namespace { - -class SpecialCaseListTest : public ::testing::Test { -protected: - Function *makeFunction(StringRef Name, Module &M) { - return Function::Create(FunctionType::get(Type::getVoidTy(Ctx), false), - GlobalValue::ExternalLinkage, - Name, - &M); - } - - GlobalVariable *makeGlobal(StringRef Name, StringRef StructName, Module &M) { - StructType *ST = - StructType::create(StructName, Type::getInt32Ty(Ctx), (Type*)0); - return new GlobalVariable( - M, ST, false, GlobalValue::ExternalLinkage, 0, Name); - } - - GlobalAlias *makeAlias(StringRef Name, GlobalValue *Aliasee) { - return new GlobalAlias(Aliasee->getType(), GlobalValue::ExternalLinkage, - Name, Aliasee, Aliasee->getParent()); - } - - SpecialCaseList *makeSpecialCaseList(StringRef List, std::string &Error) { - OwningPtr<MemoryBuffer> MB(MemoryBuffer::getMemBuffer(List)); - return SpecialCaseList::create(MB.get(), Error); - } - - SpecialCaseList *makeSpecialCaseList(StringRef List) { - std::string Error; - SpecialCaseList *SCL = makeSpecialCaseList(List, Error); - assert(SCL); - assert(Error == ""); - return SCL; - } - - LLVMContext Ctx; -}; - -TEST_F(SpecialCaseListTest, ModuleIsIn) { - Module M("hello", Ctx); - Function *F = makeFunction("foo", M); - GlobalVariable *GV = makeGlobal("bar", "t", M); - - OwningPtr<SpecialCaseList> SCL(makeSpecialCaseList("# This is a comment.\n" - "\n" - "src:hello\n")); - EXPECT_TRUE(SCL->isIn(M)); - EXPECT_TRUE(SCL->isIn(*F)); - EXPECT_TRUE(SCL->isIn(*GV)); - - SCL.reset(makeSpecialCaseList("src:he*o\n")); - EXPECT_TRUE(SCL->isIn(M)); - EXPECT_TRUE(SCL->isIn(*F)); - EXPECT_TRUE(SCL->isIn(*GV)); - - SCL.reset(makeSpecialCaseList("src:hi\n")); - EXPECT_FALSE(SCL->isIn(M)); - EXPECT_FALSE(SCL->isIn(*F)); - EXPECT_FALSE(SCL->isIn(*GV)); -} - -TEST_F(SpecialCaseListTest, FunctionIsIn) { - Module M("hello", Ctx); - Function *Foo = makeFunction("foo", M); - Function *Bar = makeFunction("bar", M); - - OwningPtr<SpecialCaseList> SCL(makeSpecialCaseList("fun:foo\n")); - EXPECT_TRUE(SCL->isIn(*Foo)); - EXPECT_FALSE(SCL->isIn(*Bar)); - - SCL.reset(makeSpecialCaseList("fun:b*\n")); - EXPECT_FALSE(SCL->isIn(*Foo)); - EXPECT_TRUE(SCL->isIn(*Bar)); - - SCL.reset(makeSpecialCaseList("fun:f*\n" - "fun:bar\n")); - EXPECT_TRUE(SCL->isIn(*Foo)); - EXPECT_TRUE(SCL->isIn(*Bar)); - - SCL.reset(makeSpecialCaseList("fun:foo=functional\n")); - EXPECT_TRUE(SCL->isIn(*Foo, "functional")); - StringRef Category; - EXPECT_FALSE(SCL->isIn(*Bar, "functional")); -} - -TEST_F(SpecialCaseListTest, GlobalIsIn) { - Module M("hello", Ctx); - GlobalVariable *Foo = makeGlobal("foo", "t1", M); - GlobalVariable *Bar = makeGlobal("bar", "t2", M); - - OwningPtr<SpecialCaseList> SCL(makeSpecialCaseList("global:foo\n")); - EXPECT_TRUE(SCL->isIn(*Foo)); - EXPECT_FALSE(SCL->isIn(*Bar)); - EXPECT_FALSE(SCL->isIn(*Foo, "init")); - EXPECT_FALSE(SCL->isIn(*Bar, "init")); - - SCL.reset(makeSpecialCaseList("global:foo=init\n")); - EXPECT_FALSE(SCL->isIn(*Foo)); - EXPECT_FALSE(SCL->isIn(*Bar)); - EXPECT_TRUE(SCL->isIn(*Foo, "init")); - EXPECT_FALSE(SCL->isIn(*Bar, "init")); - - SCL.reset(makeSpecialCaseList("global-init:foo\n")); - EXPECT_FALSE(SCL->isIn(*Foo)); - EXPECT_FALSE(SCL->isIn(*Bar)); - EXPECT_TRUE(SCL->isIn(*Foo, "init")); - EXPECT_FALSE(SCL->isIn(*Bar, "init")); - - SCL.reset(makeSpecialCaseList("type:t2=init\n")); - EXPECT_FALSE(SCL->isIn(*Foo)); - EXPECT_FALSE(SCL->isIn(*Bar)); - EXPECT_FALSE(SCL->isIn(*Foo, "init")); - EXPECT_TRUE(SCL->isIn(*Bar, "init")); - - SCL.reset(makeSpecialCaseList("global-init-type:t2\n")); - EXPECT_FALSE(SCL->isIn(*Foo)); - EXPECT_FALSE(SCL->isIn(*Bar)); - EXPECT_FALSE(SCL->isIn(*Foo, "init")); - EXPECT_TRUE(SCL->isIn(*Bar, "init")); - - SCL.reset(makeSpecialCaseList("src:hello=init\n")); - EXPECT_FALSE(SCL->isIn(*Foo)); - EXPECT_FALSE(SCL->isIn(*Bar)); - EXPECT_TRUE(SCL->isIn(*Foo, "init")); - EXPECT_TRUE(SCL->isIn(*Bar, "init")); - - SCL.reset(makeSpecialCaseList("global-init-src:hello\n")); - EXPECT_FALSE(SCL->isIn(*Foo)); - EXPECT_FALSE(SCL->isIn(*Bar)); - EXPECT_TRUE(SCL->isIn(*Foo, "init")); - EXPECT_TRUE(SCL->isIn(*Bar, "init")); -} - -TEST_F(SpecialCaseListTest, AliasIsIn) { - Module M("hello", Ctx); - Function *Foo = makeFunction("foo", M); - GlobalVariable *Bar = makeGlobal("bar", "t", M); - GlobalAlias *FooAlias = makeAlias("fooalias", Foo); - GlobalAlias *BarAlias = makeAlias("baralias", Bar); - - OwningPtr<SpecialCaseList> SCL(makeSpecialCaseList("fun:foo\n")); - EXPECT_FALSE(SCL->isIn(*FooAlias)); - EXPECT_FALSE(SCL->isIn(*BarAlias)); - - SCL.reset(makeSpecialCaseList("global:bar\n")); - EXPECT_FALSE(SCL->isIn(*FooAlias)); - EXPECT_FALSE(SCL->isIn(*BarAlias)); - - SCL.reset(makeSpecialCaseList("global:fooalias\n")); - EXPECT_FALSE(SCL->isIn(*FooAlias)); - EXPECT_FALSE(SCL->isIn(*BarAlias)); - - SCL.reset(makeSpecialCaseList("fun:fooalias\n")); - EXPECT_TRUE(SCL->isIn(*FooAlias)); - EXPECT_FALSE(SCL->isIn(*BarAlias)); - - SCL.reset(makeSpecialCaseList("global:baralias=init\n")); - EXPECT_FALSE(SCL->isIn(*FooAlias, "init")); - EXPECT_TRUE(SCL->isIn(*BarAlias, "init")); - - SCL.reset(makeSpecialCaseList("type:t=init\n")); - EXPECT_FALSE(SCL->isIn(*FooAlias, "init")); - EXPECT_TRUE(SCL->isIn(*BarAlias, "init")); - - SCL.reset(makeSpecialCaseList("fun:baralias=init\n")); - EXPECT_FALSE(SCL->isIn(*FooAlias, "init")); - EXPECT_FALSE(SCL->isIn(*BarAlias, "init")); -} - -TEST_F(SpecialCaseListTest, Substring) { - Module M("othello", Ctx); - Function *F = makeFunction("tomfoolery", M); - GlobalVariable *GV = makeGlobal("bartender", "t", M); - GlobalAlias *GA1 = makeAlias("buffoonery", F); - GlobalAlias *GA2 = makeAlias("foobar", GV); - - OwningPtr<SpecialCaseList> SCL(makeSpecialCaseList("src:hello\n" - "fun:foo\n" - "global:bar\n")); - EXPECT_FALSE(SCL->isIn(M)); - EXPECT_FALSE(SCL->isIn(*F)); - EXPECT_FALSE(SCL->isIn(*GV)); - EXPECT_FALSE(SCL->isIn(*GA1)); - EXPECT_FALSE(SCL->isIn(*GA2)); - - SCL.reset(makeSpecialCaseList("fun:*foo*\n")); - EXPECT_TRUE(SCL->isIn(*F)); - EXPECT_TRUE(SCL->isIn(*GA1)); -} - -TEST_F(SpecialCaseListTest, InvalidSpecialCaseList) { - std::string Error; - EXPECT_EQ(0, makeSpecialCaseList("badline", Error)); - EXPECT_EQ("Malformed line 1: 'badline'", Error); - EXPECT_EQ(0, makeSpecialCaseList("src:bad[a-", Error)); - EXPECT_EQ("Malformed regex in line 1: 'bad[a-': invalid character range", - Error); - EXPECT_EQ(0, makeSpecialCaseList("src:a.c\n" - "fun:fun(a\n", - Error)); - EXPECT_EQ("Malformed regex in line 2: 'fun(a': parentheses not balanced", - Error); - EXPECT_EQ(0, SpecialCaseList::create("unexisting", Error)); - EXPECT_EQ(0U, Error.find("Can't open file 'unexisting':")); -} - -TEST_F(SpecialCaseListTest, EmptySpecialCaseList) { - OwningPtr<SpecialCaseList> SCL(makeSpecialCaseList("")); - Module M("foo", Ctx); - EXPECT_FALSE(SCL->isIn(M)); -} - -} |