aboutsummaryrefslogtreecommitdiff
path: root/llvm/unittests/Linker/LinkModulesTest.cpp
diff options
context:
space:
mode:
authorBill Wendling <isanbard@gmail.com>2013-11-07 20:14:51 +0000
committerBill Wendling <isanbard@gmail.com>2013-11-07 20:14:51 +0000
commit889046043104e365e59a3c544ddb521173c07988 (patch)
treee33f57606d15a3864f97cc05c60a0beea22da437 /llvm/unittests/Linker/LinkModulesTest.cpp
parent2aa81a718e64fb4ca651ea12ab7afaeffc11e463 (diff)
downloadllvm-889046043104e365e59a3c544ddb521173c07988.zip
llvm-889046043104e365e59a3c544ddb521173c07988.tar.gz
llvm-889046043104e365e59a3c544ddb521173c07988.tar.bz2
Move copying of global initializers below the cloning of functions.
The BlockAddress doesn't have access to the correct basic blocks until the functions have been cloned. This causes the BlockAddress to point to the old values. Just wait until the functions have been cloned before copying the initializers. PR13163 llvm-svn: 194218
Diffstat (limited to 'llvm/unittests/Linker/LinkModulesTest.cpp')
-rw-r--r--llvm/unittests/Linker/LinkModulesTest.cpp131
1 files changed, 131 insertions, 0 deletions
diff --git a/llvm/unittests/Linker/LinkModulesTest.cpp b/llvm/unittests/Linker/LinkModulesTest.cpp
new file mode 100644
index 0000000..9d2d84d
--- /dev/null
+++ b/llvm/unittests/Linker/LinkModulesTest.cpp
@@ -0,0 +1,131 @@
+//===- llvm/unittest/Linker/LinkModulesTest.cpp - IRBuilder tests ---------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Linker.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Module.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+
+class LinkModuleTest : public testing::Test {
+protected:
+ virtual void SetUp() {
+ LLVMContext &Ctx = getGlobalContext();
+ M.reset(new Module("MyModule", Ctx));
+ FunctionType *FTy = FunctionType::get(Type::getInt8PtrTy(Ctx),
+ Type::getInt32Ty(Ctx),
+ false /*=isVarArg*/);
+ F = Function::Create(FTy, Function::ExternalLinkage, "ba_func", M.get());
+ F->setCallingConv(CallingConv::C);
+
+ EntryBB = BasicBlock::Create(Ctx, "entry", F);
+ SwitchCase1BB = BasicBlock::Create(Ctx, "switch.case.1", F);
+ SwitchCase2BB = BasicBlock::Create(Ctx, "switch.case.2", F);
+ ExitBB = BasicBlock::Create(Ctx, "exit", F);
+
+ ArrayType *AT = ArrayType::get(Type::getInt8PtrTy(Ctx), 3);
+
+ GV = new GlobalVariable(*M.get(), AT, false /*=isConstant*/,
+ GlobalValue::InternalLinkage,
+ 0, "switch.bas");
+
+
+ // Global Initializer
+ std::vector<Constant*> Init;
+ Constant *SwitchCase1BA = BlockAddress::get(SwitchCase1BB);
+ Init.push_back(SwitchCase1BA);
+
+ Constant *SwitchCase2BA = BlockAddress::get(SwitchCase2BB);
+ Init.push_back(SwitchCase2BA);
+
+ ConstantInt *One = ConstantInt::get(Type::getInt32Ty(Ctx), 1);
+ Constant *OnePtr = ConstantExpr::getCast(Instruction::IntToPtr,
+ One, Type::getInt8PtrTy(Ctx));
+ Init.push_back(OnePtr);
+
+ GV->setInitializer(ConstantArray::get(AT, Init));
+ }
+
+ virtual void TearDown() {
+ M.reset();
+ }
+
+ OwningPtr<Module> M;
+ Function *F;
+ GlobalVariable *GV;
+ BasicBlock *EntryBB;
+ BasicBlock *SwitchCase1BB;
+ BasicBlock *SwitchCase2BB;
+ BasicBlock *ExitBB;
+};
+
+TEST_F(LinkModuleTest, BlockAddress) {
+ LLVMContext &Ctx = getGlobalContext();
+ IRBuilder<> Builder(EntryBB);
+
+ std::vector<Value*> GEPIndices;
+ GEPIndices.push_back(ConstantInt::get(Type::getInt32Ty(Ctx), 0));
+ GEPIndices.push_back(F->arg_begin());
+
+ Value *GEP = Builder.CreateGEP(GV, GEPIndices, "switch.gep");
+ Value *Load = Builder.CreateLoad(GEP, "switch.load");
+
+ Builder.CreateRet(Load);
+
+ Builder.SetInsertPoint(SwitchCase1BB);
+ Builder.CreateBr(ExitBB);
+
+ Builder.SetInsertPoint(SwitchCase2BB);
+ Builder.CreateBr(ExitBB);
+
+ Builder.SetInsertPoint(ExitBB);
+ Builder.CreateRet(ConstantPointerNull::get(Type::getInt8PtrTy(Ctx)));
+
+ Module *LinkedModule = new Module("MyModuleLinked", getGlobalContext());
+ Linker::LinkModules(LinkedModule, M.get(), Linker::PreserveSource, 0);
+
+ // Delete the original module.
+ M.reset();
+
+ // Check that the global "@switch.bas" is well-formed.
+ const GlobalVariable *LinkedGV = LinkedModule->getNamedGlobal("switch.bas");
+ const Constant *Init = LinkedGV->getInitializer();
+
+ // @switch.bas = internal global [3 x i8*]
+ // [i8* blockaddress(@ba_func, %switch.case.1),
+ // i8* blockaddress(@ba_func, %switch.case.2),
+ // i8* inttoptr (i32 1 to i8*)]
+
+ ArrayType *AT = ArrayType::get(Type::getInt8PtrTy(Ctx), 3);
+ EXPECT_EQ(AT, Init->getType());
+
+ Value *Elem = Init->getOperand(0);
+ ASSERT_TRUE(isa<BlockAddress>(Elem));
+ EXPECT_EQ(cast<BlockAddress>(Elem)->getFunction(),
+ LinkedModule->getFunction("ba_func"));
+ EXPECT_EQ(cast<BlockAddress>(Elem)->getBasicBlock()->getParent(),
+ LinkedModule->getFunction("ba_func"));
+
+ Elem = Init->getOperand(1);
+ ASSERT_TRUE(isa<BlockAddress>(Elem));
+ EXPECT_EQ(cast<BlockAddress>(Elem)->getFunction(),
+ LinkedModule->getFunction("ba_func"));
+ EXPECT_EQ(cast<BlockAddress>(Elem)->getBasicBlock()->getParent(),
+ LinkedModule->getFunction("ba_func"));
+
+ delete LinkedModule;
+}
+
+} // end anonymous namespace