Index: llvm/include/llvm/Transforms/Utils/Cloning.h =================================================================== --- llvm/include/llvm/Transforms/Utils/Cloning.h +++ llvm/include/llvm/Transforms/Utils/Cloning.h @@ -112,10 +112,14 @@ /// If you would like to collect additional information about the cloned /// function, you can specify a ClonedCodeInfo object with the optional fifth /// parameter. +/// +/// If NewBB is not empty, all instructions will be inserted into newBB in +/// the case of creating a basic block first and cloning it later. BasicBlock *CloneBasicBlock(const BasicBlock *BB, ValueToValueMapTy &VMap, const Twine &NameSuffix = "", Function *F = nullptr, ClonedCodeInfo *CodeInfo = nullptr, - DebugInfoFinder *DIFinder = nullptr); + DebugInfoFinder *DIFinder = nullptr, + BasicBlock *NewBB = nullptr); /// Return a copy of the specified function and add it to that /// function's module. Also, any references specified in the VMap are changed @@ -168,7 +172,8 @@ const char *NameSuffix = "", ClonedCodeInfo *CodeInfo = nullptr, ValueMapTypeRemapper *TypeMapper = nullptr, - ValueMaterializer *Materializer = nullptr); + ValueMaterializer *Materializer = nullptr, + bool shouldCreateBB = true); void CloneAndPruneIntoFromInst(Function *NewFunc, const Function *OldFunc, const Instruction *StartingInst, Index: llvm/lib/Transforms/Utils/CloneFunction.cpp =================================================================== --- llvm/lib/Transforms/Utils/CloneFunction.cpp +++ llvm/lib/Transforms/Utils/CloneFunction.cpp @@ -41,8 +41,10 @@ BasicBlock *llvm::CloneBasicBlock(const BasicBlock *BB, ValueToValueMapTy &VMap, const Twine &NameSuffix, Function *F, ClonedCodeInfo *CodeInfo, - DebugInfoFinder *DIFinder) { - BasicBlock *NewBB = BasicBlock::Create(BB->getContext(), "", F); + DebugInfoFinder *DIFinder, + BasicBlock *NewBB) { + if (NewBB == nullptr) + NewBB = BasicBlock::Create(BB->getContext(), "", F); if (BB->hasName()) NewBB->setName(BB->getName() + NameSuffix); @@ -84,7 +86,8 @@ SmallVectorImpl &Returns, const char *NameSuffix, ClonedCodeInfo *CodeInfo, ValueMapTypeRemapper *TypeMapper, - ValueMaterializer *Materializer) { + ValueMaterializer *Materializer, + bool shouldCreateBB) { assert(NameSuffix && "NameSuffix cannot be null!"); #ifndef NDEBUG @@ -165,11 +168,19 @@ // Loop over all of the basic blocks in the function, cloning them as // appropriate. Note that we save BE this way in order to handle cloning of // recursive functions into themselves. + auto NewBBIt = NewFunc->begin(); for (const BasicBlock &BB : *OldFunc) { + BasicBlock *CBB = nullptr; // Create a new basic block and copy instructions into it! - BasicBlock *CBB = CloneBasicBlock(&BB, VMap, NameSuffix, NewFunc, CodeInfo, - DIFinder ? &*DIFinder : nullptr); + if (shouldCreateBB) { + CBB = CloneBasicBlock(&BB, VMap, NameSuffix, NewFunc, CodeInfo, + DIFinder ? &*DIFinder : nullptr); + } else { + CBB = CloneBasicBlock(&BB, VMap, NameSuffix, NewFunc, CodeInfo, + DIFinder ? &*DIFinder : nullptr, &*NewBBIt); + ++NewBBIt; + } // Add basic block mapping. VMap[&BB] = CBB; Index: llvm/lib/Transforms/Utils/CloneModule.cpp =================================================================== --- llvm/lib/Transforms/Utils/CloneModule.cpp +++ llvm/lib/Transforms/Utils/CloneModule.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/IR/Constants.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Module.h" #include "llvm/Transforms/Utils/Cloning.h" @@ -77,6 +78,21 @@ I.getAddressSpace(), I.getName(), New.get()); NF->copyAttributesFrom(&I); VMap[&I] = NF; + + // We should create basic blocks in the function in case we have to + // clone them because BlockAddress might reference to them. + if (!I.isDeclaration() && ShouldCloneDefinition(&I)) { + for (const BasicBlock &BB : I) { + BasicBlock *CBB = BasicBlock::Create(BB.getContext(), "", NF); + + VMap[&BB] = CBB; + if (BB.hasAddressTaken()) { + Constant *OldBBAddr = BlockAddress::get( + const_cast(&I), const_cast(&BB)); + VMap[OldBBAddr] = BlockAddress::get(NF, CBB); + } + } + } } // Loop over the aliases in the module @@ -166,7 +182,7 @@ SmallVector Returns; // Ignore returns cloned. CloneFunctionInto(F, &I, VMap, CloneFunctionChangeType::ClonedModule, - Returns); + Returns, "", nullptr, nullptr, nullptr, false); if (I.hasPersonalityFn()) F->setPersonalityFn(MapValue(I.getPersonalityFn(), VMap)); Index: llvm/unittests/Transforms/Utils/CloningTest.cpp =================================================================== --- llvm/unittests/Transforms/Utils/CloningTest.cpp +++ llvm/unittests/Transforms/Utils/CloningTest.cpp @@ -25,6 +25,7 @@ #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/IR/Verifier.h" +#include "llvm/Passes/PassBuilder.h" #include "llvm/Support/SourceMgr.h" #include "gtest/gtest.h" @@ -1087,4 +1088,48 @@ Function *NewF = NewM->getFunction("f"); EXPECT_EQ(CD, NewF->getComdat()); } + +static void optimizeModule(llvm::Module &M) { + llvm::LoopAnalysisManager LAM; + llvm::FunctionAnalysisManager FAM; + llvm::CGSCCAnalysisManager CGAM; + llvm::ModuleAnalysisManager MAM; + llvm::PassBuilder PB; + llvm::ModulePassManager MPM; + PB.registerModuleAnalyses(MAM); + PB.registerCGSCCAnalyses(CGAM); + PB.registerFunctionAnalyses(FAM); + PB.registerLoopAnalyses(LAM); + PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); + MPM = PB.buildPerModuleDefaultPipeline(OptimizationLevel::O2); + MPM.run(M, MAM); +} + +TEST(CloneModule2, CloneCrash) { + StringRef ImplAssembly = R"( +@loop.targets = constant [2 x i8*] [i8* blockaddress(@loop, %bb0), i8* blockaddress(@loop, %bb1)] +@loop.target = constant i8* blockaddress(@loop, %bb1) + +define void @loop(i64* %p) { +entry: + br label %bb0 +bb0: + %target = load i8*, i8** @loop.target, align 8 + indirectbr i8* %target, [label %bb0, label %bb1] +bb1: + ret void +} + )"; + LLVMContext Context; + SMDiagnostic Error; + auto ImplModule = parseAssemblyString(ImplAssembly, Error, Context); + EXPECT_TRUE(ImplModule != nullptr); + EXPECT_FALSE(verifyModule(*ImplModule)); + llvm::ValueToValueMapTy vmap; + auto NewModule = llvm::CloneModule(*ImplModule, vmap); + EXPECT_FALSE(llvm::verifyModule(*NewModule, &llvm::errs())); + NewModule->print(llvm::errs(), nullptr); + optimizeModule(*NewModule); + NewModule->print(llvm::errs(), nullptr); +} }