BlockAddress instruction is copied instead of cloned during module link?

I have a module having the blockaddress instruction.
When I link it into another module and delete the original, blockaddress disappears and is replaced by inttoptr (i32 1 to i8*).

Please compile and run the attached program to see the demo of this problem.

Right after linking modules, blockaddress still exists:
@switch.bbs = internal global [3 x i8*] [i8* blockaddress(@my_func, %switch.body.begin), i8* blockaddress(@my_func, %switch.body.begin1), i8* inttoptr (i32 1 to i8*)]
But once the original module is deleted, the same line in destination is replaced by the one with inttoptr:
@switch.bbs = internal global [3 x i8*] [i8* inttoptr (i32 1 to i8*), i8* inttoptr (i32 1 to i8*), i8* inttoptr (i32 1 to i8*)]

So it looks like BlockAddress instruction is copied instead of cloned into the destination module?

rev.158596

Yuri

--- testcase.cpp ---

#include <llvm/LLVMContext.h>
#include <llvm/Module.h>
#include <llvm/DerivedTypes.h>
#include <llvm/Constants.h>
#include <llvm/GlobalVariable.h>
#include <llvm/Function.h>
#include <llvm/CallingConv.h>
#include <llvm/BasicBlock.h>
#include <llvm/Instructions.h>
#include <llvm/InlineAsm.h>
#include <llvm/Support/FormattedStream.h>
#include <llvm/Support/MathExtras.h>
#include <llvm/Pass.h>
#include <llvm/PassManager.h>
#include <llvm/ADT/SmallVector.h>
#include <llvm/Analysis/Verifier.h>
#include <llvm/Assembly/PrintModulePass.h>
#include <llvm/Linker.h>
#include <algorithm>
using namespace llvm;

Module* makeLLVMModule();

int main(int argc, char**argv) {
   Module* Mod = makeLLVMModule();
   verifyModule(*Mod, PrintMessageAction);

   PassManager PM;
   PM.add(createPrintModulePass(&outs()));

   printf("===original==\n");
   PM.run(*Mod);

   Module* ModL = new Module("xL.ll", getGlobalContext());
   llvm::Linker::LinkModules(ModL, Mod, Linker::PreserveSource, 0);
   printf("===linked: before original delete==\n");
   PM.run(*ModL);

   delete Mod;

   printf("===linked: after original delete==\n");
   PM.run(*ModL);

   return 0;
}

Module* makeLLVMModule() {
  // Module Construction
  Module* mod = new Module("x.ll", getGlobalContext());
  mod->setDataLayout("e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64");
  mod->setTargetTriple("x86_64-unknown-freebsd8.2");

  // Type Definitions
  PointerType* PointerTy_1 = PointerType::get(IntegerType::get(mod->getContext(), 8), 0);

  ArrayType* ArrayTy_0 = ArrayType::get(PointerTy_1, 3);

  PointerType* PointerTy_2 = PointerType::get(ArrayTy_0, 0);

  std::vector<Type*>FuncTy_3_args;
  FuncTy_3_args.push_back(IntegerType::get(mod->getContext(), 32));
  FunctionType* FuncTy_3 = FunctionType::get(
   /*Result=*/PointerTy_1,
   /*Params=*/FuncTy_3_args,
   /*isVarArg=*/false);

  PointerType* PointerTy_4 = PointerType::get(PointerTy_1, 0);

  // Function Declarations

  Function* func_my_func = mod->getFunction("my_func");
  if (!func_my_func) {
  func_my_func = Function::Create(
   /*Type=*/FuncTy_3,
   /*Linkage=*/GlobalValue::ExternalLinkage,
   /*Name=*/"my_func", mod);
  func_my_func->setCallingConv(CallingConv::C);
  }
  AttrListPtr func_my_func_PAL;
  func_my_func->setAttributes(func_my_func_PAL);

   BasicBlock* label_issue_top = BasicBlock::Create(mod->getContext(), "issue.top",func_my_func,0);
   BasicBlock* label_switch_body_begin = BasicBlock::Create(mod->getContext(), "switch.body.begin",func_my_func,0);
   BasicBlock* label_switch_body_begin1 = BasicBlock::Create(mod->getContext(), "switch.body.begin1",func_my_func,0);
   BasicBlock* label_switch_end = BasicBlock::Create(mod->getContext(), "switch.end",func_my_func,0);

  // Global Variable Declarations

  GlobalVariable* gvar_array_switch_bbs = new GlobalVariable(/*Module=*/*mod,
  /*Type=*/ArrayTy_0,
  /*isConstant=*/false,
  /*Linkage=*/GlobalValue::InternalLinkage,
  /*Initializer=*/0, // has initializer, specified below
  /*Name=*/"switch.bbs");

  // Constant Definitions
  std::vector<Constant*> const_array_5_elems;
  Constant* const_ptr_6 = BlockAddress::get(label_switch_body_begin);
  const_array_5_elems.push_back(const_ptr_6);
  Constant* const_ptr_7 = BlI have a module having the blockaddress instruction.
When I link it into another module and delete the original, blockaddress disappears and is replaced by inttoptr (i32 1 to i8*).

Please compile and run the attached program to see the demo of this problem.

Right after linking modules, blockaddress still exists:
@switch.bbs = internal global [3 x i8*] [i8* blockaddress(@my_func, %switch.body.begin), i8* blockaddress(@my_func, %switch.body.begin1), i8* inttoptr (i32 1 to i8*)]
But once the original module is deleted, the same line in destination is replaced by the one with inttoptr:
@switch.bbs = internal global [3 x i8*] [i8* inttoptr (i32 1 to i8*), i8* inttoptr (i32 1 to i8*), i8* inttoptr (i32 1 to i8*)]

So it looks like BlockAddress instruction is copied instead of cloned into the destination module?

rev.158596

Yuri

--- testcase.cpp ---

#include <llvm/LLVMContext.h>
#include <llvm/Module.h>
#include <llvm/DerivedTypes.h>
#include <llvm/Constants.h>
#include <llvm/GlobalVariable.h>
#include <llvm/Function.h>
#include <llvm/CallingConv.h>
#include <llvm/BasicBlock.h>
#include <llvm/Instructions.h>
#include <llvm/InlineAsm.h>
#include <llvm/Support/FormattedStream.h>
#include <llvm/Support/MathExtras.h>
#include <llvm/Pass.h>
#include <llvm/PassManager.h>
#include <llvm/ADT/SmallVector.h>
#include <llvm/Analysis/Verifier.h>
#include <llvm/Assembly/PrintModulePass.h>
#include <llvm/Linker.h>
#include <algorithm>
using namespace llvm;

Module* makeLLVMModule();

int main(int argc, char**argv) {
   Module* Mod = makeLLVMModule();
   verifyModule(*Mod, PrintMessageAction);

   PassManager PM;
   PM.add(createPrintModulePass(&outs()));

   printf("===original==\n");
   PM.run(*Mod);

   Module* ModL = new Module("xL.ll", getGlobalContext());
   llvm::Linker::LinkModules(ModL, Mod, Linker::PreserveSource, 0);
   printf("===linked: before original delete==\n");
   PM.run(*ModL);

   delete Mod;

   printf("===linked: after original delete==\n");
   PM.run(*ModL);

   return 0;
}

Module* makeLLVMModule() {
  // Module Construction
  Module* mod = new Module("x.ll", getGlobalContext());
  mod->setDataLayout("e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64");
  mod->setTargetTriple("x86_64-unknown-freebsd8.2");

  // Type Definitions
  PointerType* PointerTy_1 = PointerType::get(IntegerType::get(mod->getContext(), 8), 0);

  ArrayType* ArrayTy_0 = ArrayType::get(PointerTy_1, 3);

  PointerType* PointerTy_2 = PointerType::get(ArrayTy_0, 0);

  std::vector<Type*>FuncTy_3_args;
  FuncTy_3_args.push_back(IntegerType::get(mod->getContext(), 32));
  FunctionType* FuncTy_3 = FunctionType::get(
   /*Result=*/PointerTy_1,
   /*Params=*/FuncTy_3_args,
   /*isVarArg=*/false);

  PointerType* PointerTy_4 = PointerType::get(PointerTy_1, 0);

  // Function Declarations

  Function* func_my_func = mod->getFunction("my_func");
  if (!func_my_func) {
  func_my_func = Function::Create(
   /*Type=*/FuncTy_3,
   /*Linkage=*/GlobalValue::ExternalLinkage,
   /*Name=*/"my_func", mod);
  func_my_func->setCallingConv(CallingConv::C);
  }
  AttrListPtr func_my_func_PAL;
  func_my_func->setAttributes(func_my_func_PAL);

   BasicBlock* label_issue_top = BasicBlock::Create(mod->getContext(), "issue.top",func_my_func,0);
   BasicBlock* label_switch_body_begin = BasicBlock::Create(mod->getContext(), "switch.body.begin",func_my_func,0);
   BasicBlock* label_switch_body_begin1 = BasicBlock::Create(mod->getContext(), "switch.body.begin1",func_my_func,0);
   BasicBlock* label_switch_end = BasicBlock::Create(mod->getContext(), "switch.end",func_my_func,0);

  // Global Variable Declarations

  GlobalVariable* gvar_array_switch_bbs = new GlobalVariable(/*Module=*/*mod,
  /*Type=*/ArrayTy_0,
  /*isConstant=*/false,
  /*Linkage=*/GlobalValue::InternalLinkage,
  /*Initializer=*/0, // has initializer, specified below
  /*Name=*/"switch.bbs");

  // Constant Definitions
  std::vector<Constant*> const_array_5_elems;
  Constant* const_ptr_6 = BlockAddress::get(label_switch_body_begin);
  const_array_5_elems.push_back(const_ptr_6);
  Constant* const_ptr_7 = BlockAddress::get(label_switch_body_begin1);
  const_array_5_elems.push_back(const_ptr_7);
  ConstantInt* const_int32_9 = ConstantInt::get(mod->getContext(), APInt(32, StringRef("1"), 10));
  Constant* const_ptr_8 = ConstantExpr::getCast(Instruction::IntToPtr, const_int32_9, PointerTy_1);
  const_array_5_elems.push_back(const_ptr_8);
  Constant* const_array_5 = ConstantArray::get(ArrayTy_0, const_array_5_elems);
  ConstantInt* const_int32_10 = ConstantInt::get(mod->getContext(), APInt(32, StringRef("0"), 10));
  ConstantPointerNull* const_ptr_11 = ConstantPointerNull::get(PointerTy_1);

  // Global Variable Definitions
  gvar_array_switch_bbs->setInitializer(const_array_5);

  // Function Definitions

  // Function: my_func (func_my_func)
  {
   Function::arg_iterator args = func_my_func->arg_begin();
   Value* int32_12 = args++;
     // Block issue.top (label_issue_top)
   std::vector<Value*> ptr_switch_gep_indices;
   ptr_switch_gep_indices.push_back(const_int32_10);
   ptr_switch_gep_indices.push_back(int32_12);
   Instruction* ptr_switch_gep = GetElementPtrInst::Create(gvar_array_switch_bbs, ptr_switch_gep_indices, "switch.gep", label_issue_top);
   LoadInst* ptr_switch_load = new LoadInst(ptr_switch_gep, "switch.load", false, label_issue_top);
   ReturnInst::Create(mod->getContext(), ptr_switch_load, label_issue_top);
     // Block switch.body.begin (label_switch_body_begin)
   BranchInst::Create(label_switch_end, label_switch_body_begin);
     // Block switch.body.begin1 (label_switch_body_begin1)
   BranchInst::Create(label_switch_end, label_switch_body_begin1);
     // Block switch.end (label_switch_end)
   ReturnInst::Create(mod->getContext(), const_ptr_11, label_switch_end);
    }

  return mod;
}

ockAddress::get(label_switch_body_begin1);
  const_array_5_elems.push_back(const_ptr_7);
  ConstantInt* const_int32_9 = ConstantInt::get(mod->getContext(), APInt(32, StringRef("1"), 10));
  Constant* const_ptr_8 = ConstantExpr::getCast(Instruction::IntToPtr, const_int32_9, PointerTy_1);
  const_array_5_elems.push_back(const_ptr_8);
  Constant* const_array_5 = ConstantArray::get(ArrayTy_0, const_array_5_elems);
  ConstantInt* const_int32_10 = ConstantInt::get(mod->getContext(), APInt(32, StringRef("0"), 10));
  ConstantPointerNull* const_ptr_11 = ConstantPointerNull::get(PointerTy_1);

  // Global Variable Definitions
  gvar_array_switch_bbs->setInitializer(const_array_5);

  // Function Definitions

  // Function: my_func (func_my_func)
  {
   Function::arg_iterator args = func_my_func->arg_begin();
   Value* int32_12 = args++;
     // Block issue.top (label_issue_top)
   std::vector<Value*> ptr_switch_gep_indices;
   ptr_switch_gep_indices.push_back(const_int32_10);
   ptr_switch_gep_indices.push_back(int32_12);
   Instruction* ptr_switch_gep = GetElementPtrInst::Create(gvar_array_switch_bbs, ptr_switch_gep_indices, "switch.gep", label_issue_top);
   LoadInst* ptr_switch_load = new LoadInst(ptr_switch_gep, "switch.load", false, label_issue_top);
   ReturnInst::Create(mod->getContext(), ptr_switch_load, label_issue_top);
     // Block switch.body.begin (label_switch_body_begin)
   BranchInst::Create(label_switch_end, label_switch_body_begin);
     // Block switch.body.begin1 (label_switch_body_begin1)
   BranchInst::Create(label_switch_end, label_switch_body_begin1);
     // Block switch.end (label_switch_end)
   ReturnInst::Create(mod->getContext(), const_ptr_11, label_switch_end);
    }

  return mod;
}

BasicBlock::~BasicBlock() has the line: BA->replaceAllUsesWith(ConstantExpr::getIntToPtr(Replacement, BA->getType()));
It replaces all uses with: Constant *Replacement = ConstantInt::get(llvm::Type::getInt32Ty(getContext()), 1);
When it is called on link source module, BasicBlocks there are destroyed but their uses are in the link destination module.

Value::replaceAllUsesWith should have an assert checking if the use is in the same module as the current value.

Yuri

Since I got no response, I filed the PR for this problem:
  http://llvm.org/bugs/show_bug.cgi?id=13163

Yuri

Patch submitted:
http://llvm.org/bugs/show_bug.cgi?id=13163

Please review and check in.

Thanks,
Yuri