123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864 |
- //===- Cloning.cpp - Unit tests for the Cloner ----------------------------===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- #include "llvm/Transforms/Utils/Cloning.h"
- #include "llvm/ADT/STLExtras.h"
- #include "llvm/ADT/SmallPtrSet.h"
- #include "llvm/Analysis/DomTreeUpdater.h"
- #include "llvm/Analysis/LoopInfo.h"
- #include "llvm/AsmParser/Parser.h"
- #include "llvm/IR/Argument.h"
- #include "llvm/IR/Constant.h"
- #include "llvm/IR/DIBuilder.h"
- #include "llvm/IR/DebugInfo.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/LLVMContext.h"
- #include "llvm/IR/Module.h"
- #include "llvm/IR/Verifier.h"
- #include "gtest/gtest.h"
- using namespace llvm;
- namespace {
- class CloneInstruction : public ::testing::Test {
- protected:
- void SetUp() override { V = nullptr; }
- template <typename T>
- T *clone(T *V1) {
- Value *V2 = V1->clone();
- Orig.insert(V1);
- Clones.insert(V2);
- return cast<T>(V2);
- }
- void eraseClones() {
- for (Value *V : Clones)
- V->deleteValue();
- Clones.clear();
- }
- void TearDown() override {
- eraseClones();
- for (Value *V : Orig)
- V->deleteValue();
- Orig.clear();
- if (V)
- V->deleteValue();
- }
- SmallPtrSet<Value *, 4> Orig; // Erase on exit
- SmallPtrSet<Value *, 4> Clones; // Erase in eraseClones
- LLVMContext context;
- Value *V;
- };
- TEST_F(CloneInstruction, OverflowBits) {
- V = new Argument(Type::getInt32Ty(context));
- BinaryOperator *Add = BinaryOperator::Create(Instruction::Add, V, V);
- BinaryOperator *Sub = BinaryOperator::Create(Instruction::Sub, V, V);
- BinaryOperator *Mul = BinaryOperator::Create(Instruction::Mul, V, V);
- BinaryOperator *AddClone = this->clone(Add);
- BinaryOperator *SubClone = this->clone(Sub);
- BinaryOperator *MulClone = this->clone(Mul);
- EXPECT_FALSE(AddClone->hasNoUnsignedWrap());
- EXPECT_FALSE(AddClone->hasNoSignedWrap());
- EXPECT_FALSE(SubClone->hasNoUnsignedWrap());
- EXPECT_FALSE(SubClone->hasNoSignedWrap());
- EXPECT_FALSE(MulClone->hasNoUnsignedWrap());
- EXPECT_FALSE(MulClone->hasNoSignedWrap());
- eraseClones();
- Add->setHasNoUnsignedWrap();
- Sub->setHasNoUnsignedWrap();
- Mul->setHasNoUnsignedWrap();
- AddClone = this->clone(Add);
- SubClone = this->clone(Sub);
- MulClone = this->clone(Mul);
- EXPECT_TRUE(AddClone->hasNoUnsignedWrap());
- EXPECT_FALSE(AddClone->hasNoSignedWrap());
- EXPECT_TRUE(SubClone->hasNoUnsignedWrap());
- EXPECT_FALSE(SubClone->hasNoSignedWrap());
- EXPECT_TRUE(MulClone->hasNoUnsignedWrap());
- EXPECT_FALSE(MulClone->hasNoSignedWrap());
- eraseClones();
- Add->setHasNoSignedWrap();
- Sub->setHasNoSignedWrap();
- Mul->setHasNoSignedWrap();
- AddClone = this->clone(Add);
- SubClone = this->clone(Sub);
- MulClone = this->clone(Mul);
- EXPECT_TRUE(AddClone->hasNoUnsignedWrap());
- EXPECT_TRUE(AddClone->hasNoSignedWrap());
- EXPECT_TRUE(SubClone->hasNoUnsignedWrap());
- EXPECT_TRUE(SubClone->hasNoSignedWrap());
- EXPECT_TRUE(MulClone->hasNoUnsignedWrap());
- EXPECT_TRUE(MulClone->hasNoSignedWrap());
- eraseClones();
- Add->setHasNoUnsignedWrap(false);
- Sub->setHasNoUnsignedWrap(false);
- Mul->setHasNoUnsignedWrap(false);
- AddClone = this->clone(Add);
- SubClone = this->clone(Sub);
- MulClone = this->clone(Mul);
- EXPECT_FALSE(AddClone->hasNoUnsignedWrap());
- EXPECT_TRUE(AddClone->hasNoSignedWrap());
- EXPECT_FALSE(SubClone->hasNoUnsignedWrap());
- EXPECT_TRUE(SubClone->hasNoSignedWrap());
- EXPECT_FALSE(MulClone->hasNoUnsignedWrap());
- EXPECT_TRUE(MulClone->hasNoSignedWrap());
- }
- TEST_F(CloneInstruction, Inbounds) {
- V = new Argument(Type::getInt32PtrTy(context));
- Constant *Z = Constant::getNullValue(Type::getInt32Ty(context));
- std::vector<Value *> ops;
- ops.push_back(Z);
- GetElementPtrInst *GEP =
- GetElementPtrInst::Create(Type::getInt32Ty(context), V, ops);
- EXPECT_FALSE(this->clone(GEP)->isInBounds());
- GEP->setIsInBounds();
- EXPECT_TRUE(this->clone(GEP)->isInBounds());
- }
- TEST_F(CloneInstruction, Exact) {
- V = new Argument(Type::getInt32Ty(context));
- BinaryOperator *SDiv = BinaryOperator::Create(Instruction::SDiv, V, V);
- EXPECT_FALSE(this->clone(SDiv)->isExact());
- SDiv->setIsExact(true);
- EXPECT_TRUE(this->clone(SDiv)->isExact());
- }
- TEST_F(CloneInstruction, Attributes) {
- Type *ArgTy1[] = { Type::getInt32PtrTy(context) };
- FunctionType *FT1 = FunctionType::get(Type::getVoidTy(context), ArgTy1, false);
- Function *F1 = Function::Create(FT1, Function::ExternalLinkage);
- BasicBlock *BB = BasicBlock::Create(context, "", F1);
- IRBuilder<> Builder(BB);
- Builder.CreateRetVoid();
- Function *F2 = Function::Create(FT1, Function::ExternalLinkage);
- Argument *A = &*F1->arg_begin();
- A->addAttr(Attribute::NoCapture);
- SmallVector<ReturnInst*, 4> Returns;
- ValueToValueMapTy VMap;
- VMap[A] = UndefValue::get(A->getType());
- CloneFunctionInto(F2, F1, VMap, false, Returns);
- EXPECT_FALSE(F2->arg_begin()->hasNoCaptureAttr());
- delete F1;
- 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;
- }
- TEST_F(CloneInstruction, DuplicateInstructionsToSplit) {
- Type *ArgTy1[] = {Type::getInt32PtrTy(context)};
- FunctionType *FT = FunctionType::get(Type::getVoidTy(context), ArgTy1, false);
- V = new Argument(Type::getInt32Ty(context));
- Function *F = Function::Create(FT, Function::ExternalLinkage);
- BasicBlock *BB1 = BasicBlock::Create(context, "", F);
- IRBuilder<> Builder1(BB1);
- BasicBlock *BB2 = BasicBlock::Create(context, "", F);
- IRBuilder<> Builder2(BB2);
- Builder1.CreateBr(BB2);
- Instruction *AddInst = cast<Instruction>(Builder2.CreateAdd(V, V));
- Instruction *MulInst = cast<Instruction>(Builder2.CreateMul(AddInst, V));
- Instruction *SubInst = cast<Instruction>(Builder2.CreateSub(MulInst, V));
- Builder2.CreateRetVoid();
- // Dummy DTU.
- ValueToValueMapTy Mapping;
- DomTreeUpdater DTU(DomTreeUpdater::UpdateStrategy::Lazy);
- auto Split =
- DuplicateInstructionsInSplitBetween(BB2, BB1, SubInst, Mapping, DTU);
- EXPECT_TRUE(Split);
- EXPECT_EQ(Mapping.size(), 2u);
- EXPECT_TRUE(Mapping.find(AddInst) != Mapping.end());
- EXPECT_TRUE(Mapping.find(MulInst) != Mapping.end());
- auto AddSplit = dyn_cast<Instruction>(Mapping[AddInst]);
- EXPECT_TRUE(AddSplit);
- EXPECT_EQ(AddSplit->getOperand(0), V);
- EXPECT_EQ(AddSplit->getOperand(1), V);
- EXPECT_EQ(AddSplit->getParent(), Split);
- auto MulSplit = dyn_cast<Instruction>(Mapping[MulInst]);
- EXPECT_TRUE(MulSplit);
- EXPECT_EQ(MulSplit->getOperand(0), AddSplit);
- EXPECT_EQ(MulSplit->getOperand(1), V);
- EXPECT_EQ(MulSplit->getParent(), Split);
- EXPECT_EQ(AddSplit->getNextNode(), MulSplit);
- EXPECT_EQ(MulSplit->getNextNode(), Split->getTerminator());
- delete F;
- }
- TEST_F(CloneInstruction, DuplicateInstructionsToSplitBlocksEq1) {
- Type *ArgTy1[] = {Type::getInt32PtrTy(context)};
- FunctionType *FT = FunctionType::get(Type::getVoidTy(context), ArgTy1, false);
- V = new Argument(Type::getInt32Ty(context));
- Function *F = Function::Create(FT, Function::ExternalLinkage);
- BasicBlock *BB1 = BasicBlock::Create(context, "", F);
- IRBuilder<> Builder1(BB1);
- BasicBlock *BB2 = BasicBlock::Create(context, "", F);
- IRBuilder<> Builder2(BB2);
- Builder1.CreateBr(BB2);
- Instruction *AddInst = cast<Instruction>(Builder2.CreateAdd(V, V));
- Instruction *MulInst = cast<Instruction>(Builder2.CreateMul(AddInst, V));
- Instruction *SubInst = cast<Instruction>(Builder2.CreateSub(MulInst, V));
- Builder2.CreateBr(BB2);
- // Dummy DTU.
- DomTreeUpdater DTU(DomTreeUpdater::UpdateStrategy::Lazy);
- ValueToValueMapTy Mapping;
- auto Split = DuplicateInstructionsInSplitBetween(
- BB2, BB2, BB2->getTerminator(), Mapping, DTU);
- EXPECT_TRUE(Split);
- EXPECT_EQ(Mapping.size(), 3u);
- EXPECT_TRUE(Mapping.find(AddInst) != Mapping.end());
- EXPECT_TRUE(Mapping.find(MulInst) != Mapping.end());
- EXPECT_TRUE(Mapping.find(SubInst) != Mapping.end());
- auto AddSplit = dyn_cast<Instruction>(Mapping[AddInst]);
- EXPECT_TRUE(AddSplit);
- EXPECT_EQ(AddSplit->getOperand(0), V);
- EXPECT_EQ(AddSplit->getOperand(1), V);
- EXPECT_EQ(AddSplit->getParent(), Split);
- auto MulSplit = dyn_cast<Instruction>(Mapping[MulInst]);
- EXPECT_TRUE(MulSplit);
- EXPECT_EQ(MulSplit->getOperand(0), AddSplit);
- EXPECT_EQ(MulSplit->getOperand(1), V);
- EXPECT_EQ(MulSplit->getParent(), Split);
- auto SubSplit = dyn_cast<Instruction>(Mapping[SubInst]);
- EXPECT_EQ(MulSplit->getNextNode(), SubSplit);
- EXPECT_EQ(SubSplit->getNextNode(), Split->getTerminator());
- EXPECT_EQ(Split->getSingleSuccessor(), BB2);
- EXPECT_EQ(BB2->getSingleSuccessor(), Split);
- delete F;
- }
- TEST_F(CloneInstruction, DuplicateInstructionsToSplitBlocksEq2) {
- Type *ArgTy1[] = {Type::getInt32PtrTy(context)};
- FunctionType *FT = FunctionType::get(Type::getVoidTy(context), ArgTy1, false);
- V = new Argument(Type::getInt32Ty(context));
- Function *F = Function::Create(FT, Function::ExternalLinkage);
- BasicBlock *BB1 = BasicBlock::Create(context, "", F);
- IRBuilder<> Builder1(BB1);
- BasicBlock *BB2 = BasicBlock::Create(context, "", F);
- IRBuilder<> Builder2(BB2);
- Builder1.CreateBr(BB2);
- Instruction *AddInst = cast<Instruction>(Builder2.CreateAdd(V, V));
- Instruction *MulInst = cast<Instruction>(Builder2.CreateMul(AddInst, V));
- Instruction *SubInst = cast<Instruction>(Builder2.CreateSub(MulInst, V));
- Builder2.CreateBr(BB2);
- // Dummy DTU.
- DomTreeUpdater DTU(DomTreeUpdater::UpdateStrategy::Lazy);
- ValueToValueMapTy Mapping;
- auto Split =
- DuplicateInstructionsInSplitBetween(BB2, BB2, SubInst, Mapping, DTU);
- EXPECT_TRUE(Split);
- EXPECT_EQ(Mapping.size(), 2u);
- EXPECT_TRUE(Mapping.find(AddInst) != Mapping.end());
- EXPECT_TRUE(Mapping.find(MulInst) != Mapping.end());
- auto AddSplit = dyn_cast<Instruction>(Mapping[AddInst]);
- EXPECT_TRUE(AddSplit);
- EXPECT_EQ(AddSplit->getOperand(0), V);
- EXPECT_EQ(AddSplit->getOperand(1), V);
- EXPECT_EQ(AddSplit->getParent(), Split);
- auto MulSplit = dyn_cast<Instruction>(Mapping[MulInst]);
- EXPECT_TRUE(MulSplit);
- EXPECT_EQ(MulSplit->getOperand(0), AddSplit);
- EXPECT_EQ(MulSplit->getOperand(1), V);
- EXPECT_EQ(MulSplit->getParent(), Split);
- EXPECT_EQ(MulSplit->getNextNode(), Split->getTerminator());
- EXPECT_EQ(Split->getSingleSuccessor(), BB2);
- EXPECT_EQ(BB2->getSingleSuccessor(), Split);
- delete F;
- }
- static void runWithLoopInfoAndDominatorTree(
- Module &M, StringRef FuncName,
- function_ref<void(Function &F, LoopInfo &LI, DominatorTree &DT)> Test) {
- auto *F = M.getFunction(FuncName);
- ASSERT_NE(F, nullptr) << "Could not find " << FuncName;
- DominatorTree DT(*F);
- LoopInfo LI(DT);
- Test(*F, LI, DT);
- }
- static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
- SMDiagnostic Err;
- std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);
- if (!Mod)
- Err.print("CloneLoop", errs());
- return Mod;
- }
- TEST(CloneLoop, CloneLoopNest) {
- // Parse the module.
- LLVMContext Context;
- std::unique_ptr<Module> M = parseIR(
- Context,
- R"(define void @foo(i32* %A, i32 %ub) {
- entry:
- %guardcmp = icmp slt i32 0, %ub
- br i1 %guardcmp, label %for.outer.preheader, label %for.end
- for.outer.preheader:
- br label %for.outer
- for.outer:
- %j = phi i32 [ 0, %for.outer.preheader ], [ %inc.outer, %for.outer.latch ]
- br i1 %guardcmp, label %for.inner.preheader, label %for.outer.latch
- for.inner.preheader:
- br label %for.inner
- for.inner:
- %i = phi i32 [ 0, %for.inner.preheader ], [ %inc, %for.inner ]
- %idxprom = sext i32 %i to i64
- %arrayidx = getelementptr inbounds i32, i32* %A, i64 %idxprom
- store i32 %i, i32* %arrayidx, align 4
- %inc = add nsw i32 %i, 1
- %cmp = icmp slt i32 %inc, %ub
- br i1 %cmp, label %for.inner, label %for.inner.exit
- for.inner.exit:
- br label %for.outer.latch
- for.outer.latch:
- %inc.outer = add nsw i32 %j, 1
- %cmp.outer = icmp slt i32 %inc.outer, %ub
- br i1 %cmp.outer, label %for.outer, label %for.outer.exit
- for.outer.exit:
- br label %for.end
- for.end:
- ret void
- })"
- );
- runWithLoopInfoAndDominatorTree(
- *M, "foo", [&](Function &F, LoopInfo &LI, DominatorTree &DT) {
- Function::iterator FI = F.begin();
- // First basic block is entry - skip it.
- BasicBlock *Preheader = &*(++FI);
- BasicBlock *Header = &*(++FI);
- assert(Header->getName() == "for.outer");
- Loop *L = LI.getLoopFor(Header);
- EXPECT_NE(L, nullptr);
- EXPECT_EQ(Header, L->getHeader());
- EXPECT_EQ(Preheader, L->getLoopPreheader());
- ValueToValueMapTy VMap;
- SmallVector<BasicBlock *, 4> ClonedLoopBlocks;
- Loop *NewLoop = cloneLoopWithPreheader(Preheader, Preheader, L, VMap,
- "", &LI, &DT, ClonedLoopBlocks);
- EXPECT_NE(NewLoop, nullptr);
- EXPECT_EQ(NewLoop->getSubLoops().size(), 1u);
- Loop::block_iterator BI = NewLoop->block_begin();
- EXPECT_TRUE((*BI)->getName().startswith("for.outer"));
- EXPECT_TRUE((*(++BI))->getName().startswith("for.inner.preheader"));
- EXPECT_TRUE((*(++BI))->getName().startswith("for.inner"));
- EXPECT_TRUE((*(++BI))->getName().startswith("for.inner.exit"));
- EXPECT_TRUE((*(++BI))->getName().startswith("for.outer.latch"));
- });
- }
- class CloneFunc : public ::testing::Test {
- protected:
- void SetUp() override {
- SetupModule();
- CreateOldFunc();
- CreateNewFunc();
- SetupFinder();
- }
- void TearDown() override { 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
- auto *File = DBuilder.createFile("filename.c", "/file/dir/");
- DITypeRefArray ParamTypes = DBuilder.getOrCreateTypeArray(None);
- DISubroutineType *FuncType =
- DBuilder.createSubroutineType(ParamTypes);
- 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, 3, DINode::FlagZero,
- DISubprogram::SPFlagLocalToUnit | DISubprogram::SPFlagDefinition);
- OldFunc->setSubprogram(Subprogram);
- // 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));
- // Create a local variable around the alloca
- auto *IntType = DBuilder.createBasicType("int", 32, dwarf::DW_ATE_signed);
- auto *E = DBuilder.createExpression();
- auto *Variable =
- DBuilder.createAutoVariable(Subprogram, "x", File, 5, IntType, true);
- auto *DL = DILocation::get(Subprogram->getContext(), 5, 0, Subprogram);
- DBuilder.insertDeclare(Alloca, Variable, E, DL, Store);
- DBuilder.insertDbgValueIntrinsic(AllocaContent, Variable, E, DL, Entry);
- // Also create an inlined variable.
- // Create a distinct struct type that we should not duplicate during
- // cloning).
- auto *StructType = DICompositeType::getDistinct(
- C, dwarf::DW_TAG_structure_type, "some_struct", nullptr, 0, nullptr,
- nullptr, 32, 32, 0, DINode::FlagZero, nullptr, 0, nullptr, nullptr);
- auto *InlinedSP = DBuilder.createFunction(
- CU, "inlined", "inlined", File, 8, FuncType, 9, DINode::FlagZero,
- DISubprogram::SPFlagLocalToUnit | DISubprogram::SPFlagDefinition);
- auto *InlinedVar =
- DBuilder.createAutoVariable(InlinedSP, "inlined", File, 5, StructType, true);
- auto *Scope = DBuilder.createLexicalBlock(
- DBuilder.createLexicalBlockFile(InlinedSP, File), File, 1, 1);
- auto InlinedDL =
- DebugLoc::get(9, 4, Scope, DebugLoc::get(5, 2, Subprogram));
- IBuilder.SetCurrentDebugLocation(InlinedDL);
- DBuilder.insertDeclare(Alloca, InlinedVar, E, InlinedDL, Store);
- IBuilder.CreateStore(IBuilder.getInt32(2), Alloca);
- // Finalize the debug info.
- DBuilder.finalize();
- IBuilder.CreateRetVoid();
- // Create another, empty, compile unit.
- DIBuilder DBuilder2(*M);
- DBuilder2.createCompileUnit(dwarf::DW_LANG_C99,
- DBuilder.createFile("extra.c", "/file/dir"),
- "CloneFunc", false, "", 0);
- DBuilder2.finalize();
- }
- void CreateNewFunc() {
- ValueToValueMapTy VMap;
- NewFunc = CloneFunction(OldFunc, VMap, nullptr);
- }
- 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) {
- EXPECT_FALSE(verifyModule(*M, &errs()));
- EXPECT_EQ(3U, Finder->subprogram_count());
- EXPECT_NE(NewFunc->getSubprogram(), OldFunc->getSubprogram());
- }
- // 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) {
- EXPECT_FALSE(verifyModule(*M));
- 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
- auto *OldSubprogram = cast<DISubprogram>(OldDL.getInlinedAtScope());
- auto *NewSubprogram = cast<DISubprogram>(NewDL.getInlinedAtScope());
- EXPECT_EQ(OldFunc->getSubprogram(), OldSubprogram);
- EXPECT_EQ(NewFunc->getSubprogram(), NewSubprogram);
- }
- ++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) {
- EXPECT_FALSE(verifyModule(*M));
- 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());
- if (OldIntrin->getDebugLoc()->getInlinedAt()) {
- // Inlined variable should refer to the same DILocalVariable as in the
- // Old Function
- EXPECT_EQ(OldIntrin->getVariable(), NewIntrin->getVariable());
- } else {
- // Old variable must belong to the old function.
- EXPECT_EQ(OldFunc->getSubprogram(),
- cast<DISubprogram>(OldIntrin->getVariable()->getScope()));
- // New variable must belong to the new function.
- EXPECT_EQ(NewFunc->getSubprogram(),
- cast<DISubprogram>(NewIntrin->getVariable()->getScope()));
- }
- } else if (DbgValueInst* OldIntrin = dyn_cast<DbgValueInst>(&OldI)) {
- DbgValueInst* NewIntrin = dyn_cast<DbgValueInst>(&NewI);
- EXPECT_TRUE(NewIntrin);
- if (!OldIntrin->getDebugLoc()->getInlinedAt()) {
- // Old variable must belong to the old function.
- EXPECT_EQ(OldFunc->getSubprogram(),
- cast<DISubprogram>(OldIntrin->getVariable()->getScope()));
- // New variable must belong to the new function.
- EXPECT_EQ(NewFunc->getSubprogram(),
- cast<DISubprogram>(NewIntrin->getVariable()->getScope()));
- }
- }
- ++OldIter;
- ++NewIter;
- }
- }
- static int GetDICompileUnitCount(const Module& M) {
- if (const auto* LLVM_DBG_CU = M.getNamedMetadata("llvm.dbg.cu")) {
- return LLVM_DBG_CU->getNumOperands();
- }
- return 0;
- }
- TEST(CloneFunction, CloneFunctionToDifferentModule) {
- StringRef ImplAssembly = R"(
- define void @foo() {
- ret void, !dbg !5
- }
- !llvm.module.flags = !{!0}
- !llvm.dbg.cu = !{!2, !6}
- !0 = !{i32 1, !"Debug Info Version", i32 3}
- !1 = distinct !DISubprogram(unit: !2)
- !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3)
- !3 = !DIFile(filename: "foo.c", directory: "/tmp")
- !4 = distinct !DISubprogram(unit: !2)
- !5 = !DILocation(line: 4, scope: !1)
- !6 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3)
- )";
- StringRef DeclAssembly = R"(
- declare void @foo()
- )";
- LLVMContext Context;
- SMDiagnostic Error;
- auto ImplModule = parseAssemblyString(ImplAssembly, Error, Context);
- EXPECT_TRUE(ImplModule != nullptr);
- // DICompileUnits: !2, !6. Only !2 is reachable from @foo().
- EXPECT_TRUE(GetDICompileUnitCount(*ImplModule) == 2);
- auto* ImplFunction = ImplModule->getFunction("foo");
- EXPECT_TRUE(ImplFunction != nullptr);
- auto DeclModule = parseAssemblyString(DeclAssembly, Error, Context);
- EXPECT_TRUE(DeclModule != nullptr);
- // No DICompileUnits defined here.
- EXPECT_TRUE(GetDICompileUnitCount(*DeclModule) == 0);
- auto* DeclFunction = DeclModule->getFunction("foo");
- EXPECT_TRUE(DeclFunction != nullptr);
- ValueToValueMapTy VMap;
- VMap[ImplFunction] = DeclFunction;
- // No args to map
- SmallVector<ReturnInst*, 8> Returns;
- CloneFunctionInto(DeclFunction, ImplFunction, VMap, true, Returns);
- EXPECT_FALSE(verifyModule(*ImplModule, &errs()));
- EXPECT_FALSE(verifyModule(*DeclModule, &errs()));
- // DICompileUnit !2 shall be inserted into DeclModule.
- EXPECT_TRUE(GetDICompileUnitCount(*DeclModule) == 1);
- }
- class CloneModule : public ::testing::Test {
- protected:
- void SetUp() override {
- SetupModule();
- CreateOldModule();
- CreateNewModule();
- }
- void SetupModule() { OldM = new Module("", C); }
- void CreateOldModule() {
- auto *CD = OldM->getOrInsertComdat("comdat");
- CD->setSelectionKind(Comdat::ExactMatch);
- auto GV = new GlobalVariable(
- *OldM, Type::getInt32Ty(C), false, GlobalValue::ExternalLinkage,
- ConstantInt::get(Type::getInt32Ty(C), 1), "gv");
- GV->addMetadata(LLVMContext::MD_type, *MDNode::get(C, {}));
- GV->setComdat(CD);
- DIBuilder DBuilder(*OldM);
- IRBuilder<> IBuilder(C);
- auto *FuncType = FunctionType::get(Type::getVoidTy(C), false);
- auto *PersFn = Function::Create(FuncType, GlobalValue::ExternalLinkage,
- "persfn", OldM);
- auto *F =
- Function::Create(FuncType, GlobalValue::PrivateLinkage, "f", OldM);
- F->setPersonalityFn(PersFn);
- F->setComdat(CD);
- // Create debug info
- auto *File = DBuilder.createFile("filename.c", "/file/dir/");
- DITypeRefArray ParamTypes = DBuilder.getOrCreateTypeArray(None);
- DISubroutineType *DFuncType = DBuilder.createSubroutineType(ParamTypes);
- 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, 3, DINode::FlagZero,
- DISubprogram::SPFlagLocalToUnit | DISubprogram::SPFlagDefinition);
- F->setSubprogram(Subprogram);
- // Create and assign DIGlobalVariableExpression to gv
- auto GVExpression = DBuilder.createGlobalVariableExpression(
- Subprogram, "gv", "gv", File, 1, DBuilder.createNullPtrType(), false);
- GV->addDebugInfo(GVExpression);
- // DIGlobalVariableExpression not attached to any global variable
- auto Expr = DBuilder.createExpression(
- ArrayRef<uint64_t>{dwarf::DW_OP_constu, 42U, dwarf::DW_OP_stack_value});
- DBuilder.createGlobalVariableExpression(
- Subprogram, "unattached", "unattached", File, 1,
- DBuilder.createNullPtrType(), false, Expr);
- auto *Entry = BasicBlock::Create(C, "", F);
- IBuilder.SetInsertPoint(Entry);
- IBuilder.CreateRetVoid();
- // Finalize the debug info
- DBuilder.finalize();
- }
- void CreateNewModule() { NewM = llvm::CloneModule(*OldM).release(); }
- LLVMContext C;
- Module *OldM;
- Module *NewM;
- };
- TEST_F(CloneModule, Verify) {
- EXPECT_FALSE(verifyModule(*NewM));
- }
- TEST_F(CloneModule, OldModuleUnchanged) {
- DebugInfoFinder Finder;
- Finder.processModule(*OldM);
- EXPECT_EQ(1U, Finder.subprogram_count());
- }
- TEST_F(CloneModule, Subprogram) {
- Function *NewF = NewM->getFunction("f");
- DISubprogram *SP = NewF->getSubprogram();
- EXPECT_TRUE(SP != nullptr);
- EXPECT_EQ(SP->getName(), "f");
- 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));
- }
- TEST_F(CloneModule, GlobalDebugInfo) {
- GlobalVariable *NewGV = NewM->getGlobalVariable("gv");
- EXPECT_TRUE(NewGV != nullptr);
- // Find debug info expression assigned to global
- SmallVector<DIGlobalVariableExpression *, 1> GVs;
- NewGV->getDebugInfo(GVs);
- EXPECT_EQ(GVs.size(), 1U);
- DIGlobalVariableExpression *GVExpr = GVs[0];
- DIGlobalVariable *GV = GVExpr->getVariable();
- EXPECT_TRUE(GV != nullptr);
- EXPECT_EQ(GV->getName(), "gv");
- EXPECT_EQ(GV->getLine(), 1U);
- // Assert that the scope of the debug info attached to
- // global variable matches the cloned function.
- DISubprogram *SP = NewM->getFunction("f")->getSubprogram();
- EXPECT_TRUE(SP != nullptr);
- EXPECT_EQ(GV->getScope(), SP);
- }
- TEST_F(CloneModule, CompileUnit) {
- // Find DICompileUnit listed in llvm.dbg.cu
- auto *NMD = NewM->getNamedMetadata("llvm.dbg.cu");
- EXPECT_TRUE(NMD != nullptr);
- EXPECT_EQ(NMD->getNumOperands(), 1U);
- DICompileUnit *CU = dyn_cast<llvm::DICompileUnit>(NMD->getOperand(0));
- EXPECT_TRUE(CU != nullptr);
- // Assert this CU is consistent with the cloned function debug info
- DISubprogram *SP = NewM->getFunction("f")->getSubprogram();
- EXPECT_TRUE(SP != nullptr);
- EXPECT_EQ(SP->getUnit(), CU);
- // Check globals listed in CU have the correct scope
- DIGlobalVariableExpressionArray GlobalArray = CU->getGlobalVariables();
- EXPECT_EQ(GlobalArray.size(), 2U);
- for (DIGlobalVariableExpression *GVExpr : GlobalArray) {
- DIGlobalVariable *GV = GVExpr->getVariable();
- EXPECT_EQ(GV->getScope(), SP);
- }
- }
- TEST_F(CloneModule, Comdat) {
- GlobalVariable *NewGV = NewM->getGlobalVariable("gv");
- auto *CD = NewGV->getComdat();
- ASSERT_NE(nullptr, CD);
- EXPECT_EQ("comdat", CD->getName());
- EXPECT_EQ(Comdat::ExactMatch, CD->getSelectionKind());
- Function *NewF = NewM->getFunction("f");
- EXPECT_EQ(CD, NewF->getComdat());
- }
- }
|