Reapply r194218 with fix:
authorBill Wendling <isanbard@gmail.com>
Thu, 16 Jan 2014 06:29:36 +0000 (06:29 +0000)
committerBill Wendling <isanbard@gmail.com>
Thu, 16 Jan 2014 06:29:36 +0000 (06:29 +0000)
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

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@199354 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Linker/LinkModules.cpp
unittests/Linker/CMakeLists.txt [new file with mode: 0644]
unittests/Linker/LinkModulesTest.cpp [new file with mode: 0644]
unittests/Linker/Makefile [new file with mode: 0644]
unittests/Makefile

index 4d039eb2c6dabc3b901e50be0e1dd0359e306bb8..4c86a825c8970686c2883c563f03e76a7fd4f00d 100644 (file)
@@ -1249,10 +1249,6 @@ bool ModuleLinker::run() {
   for (unsigned i = 0, e = AppendingVars.size(); i != e; ++i)
     linkAppendingVarInit(AppendingVars[i]);
   
-  // Update the initializers in the DstM module now that all globals that may
-  // be referenced are in DstM.
-  linkGlobalInits();
-
   // Link in the function bodies that are defined in the source module into
   // DstM.
   for (Module::iterator SF = SrcM->begin(), E = SrcM->end(); SF != E; ++SF) {
@@ -1290,6 +1286,10 @@ bool ModuleLinker::run() {
   if (linkModuleFlagsMetadata())
     return true;
 
+  // Update the initializers in the DstM module now that all globals that may
+  // be referenced are in DstM.
+  linkGlobalInits();
+
   // Process vector of lazily linked in functions.
   bool LinkedInAnyFunctions;
   do {
diff --git a/unittests/Linker/CMakeLists.txt b/unittests/Linker/CMakeLists.txt
new file mode 100644 (file)
index 0000000..c3dccb6
--- /dev/null
@@ -0,0 +1,12 @@
+set(LLVM_LINK_COMPONENTS
+  core
+  linker
+  )
+
+set(LinkerSources
+  LinkModulesTest.cpp
+  )
+
+add_llvm_unittest(LinkerTests
+  ${LinkerSources}
+  )
diff --git a/unittests/Linker/LinkModulesTest.cpp b/unittests/Linker/LinkModulesTest.cpp
new file mode 100644 (file)
index 0000000..c5942a1
--- /dev/null
@@ -0,0 +1,165 @@
+//===- 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;
+}
+
+TEST_F(LinkModuleTest, EmptyModule) {
+  LLVMContext &Ctx = getGlobalContext();
+  Module *InternalM = new Module("InternalModule", Ctx);
+  FunctionType *FTy = FunctionType::get(Type::getVoidTy(Ctx),
+                                        Type::getInt8PtrTy(Ctx),
+                                        false /*=isVarArgs*/);
+
+  F = Function::Create(FTy, Function::InternalLinkage, "bar", InternalM);
+  F->setCallingConv(CallingConv::C);
+
+  BasicBlock *BB = BasicBlock::Create(Ctx, "", F);
+  IRBuilder<> Builder(BB);
+  Builder.CreateRetVoid();
+
+  StructType *STy = StructType::create(Ctx, PointerType::get(FTy, 0));
+
+  GlobalVariable *GV =
+    new GlobalVariable(*InternalM, STy, false /*=isConstant*/,
+                       GlobalValue::InternalLinkage, 0, "g");
+
+  GV->setInitializer(ConstantStruct::get(STy, F));
+
+
+  Module *EmptyM = new Module("EmptyModule1", Ctx);
+  Linker::LinkModules(EmptyM, InternalM, Linker::PreserveSource, 0);
+
+  delete EmptyM;
+  EmptyM = new Module("EmptyModule2", Ctx);
+  Linker::LinkModules(InternalM, EmptyM, Linker::PreserveSource, 0);
+
+  delete EmptyM;
+  delete InternalM;
+}
+
+} // end anonymous namespace
diff --git a/unittests/Linker/Makefile b/unittests/Linker/Makefile
new file mode 100644 (file)
index 0000000..c6058c4
--- /dev/null
@@ -0,0 +1,15 @@
+##===- unittests/Linker/Makefile ---------------------------*- Makefile -*-===##
+#
+#                     The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ../..
+TESTNAME = Linker
+LINK_COMPONENTS := core linker
+
+include $(LEVEL)/Makefile.config
+include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest
index 0f80814f98989362e7b19c1365350dc4ad8cd58c..dbef6cf9b3b29387b82205819803edfdfc806e79 100644 (file)
@@ -10,7 +10,7 @@
 LEVEL = ..
 
 PARALLEL_DIRS = ADT Analysis Bitcode CodeGen DebugInfo \
-               ExecutionEngine IR MC Object Option Support Transforms
+               ExecutionEngine IR Linker MC Object Option Support Transforms
 
 include $(LEVEL)/Makefile.config
 include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest