[LLVMdev] How to place call(s) to functions found in other llvm modules ???

888 views
Skip to first unread message

Mian M. Hamayun

unread,
Aug 31, 2011, 1:00:25 PM8/31/11
to llv...@cs.uiuc.edu
Hello Everyone,

I am trying to create two modules in LLVM, where first module contains
the definition of a function, gcd in this example and another module
contains a call to this function. My example is based on the following
tutorial, with a few changes.
http://llvm.org/releases/2.6/docs/tutorial/JITTutorial2.html

When I execute the verifier pass on my modules, it complains that the
'GCDMain' module is malformed and aborts when I try to write this module
as a bitcode file.

Here is the output of my example.

----------------------------------------------------------------------
Referencing function in another module!
%tmp = call i32 @gcd(i32 30, i32 50)
Instruction does not dominate all uses!
%tmp = call i32 @gcd(i32 30, i32 50)
ret i32 %tmp
Broken module found, verification continues.
Referencing function in another module!
%tmp = call i32 @gcd(i32 30, i32 50)
Instruction does not dominate all uses!
%tmp = call i32 @gcd(i32 30, i32 50)
ret i32 %tmp
Broken module found, verification continues.
Broken module found, verification continues.
; ModuleID = 'GCD'

define i32 @gcd(i32 %x, i32 %y) {
entry:
%tmp = icmp eq i32 %x, %y
br i1 %tmp, label %return, label %cond_false

return: ; preds = %entry
ret i32 %x

cond_false: ; preds = %entry
%tmp2 = icmp ult i32 %x, %y
br i1 %tmp2, label %cond_true, label %cond_false1

cond_true: ; preds = %cond_false
%tmp3 = sub i32 %y, %x
%tmp4 = call i32 @gcd(i32 %x, i32 %tmp3)
ret i32 %tmp4

cond_false1: ; preds = %cond_false
%tmp5 = sub i32 %x, %y
%tmp6 = call i32 @gcd(i32 %tmp5, i32 %y)
ret i32 %tmp6
}
; ModuleID = 'GCDMain'

define i32 @main() {
EntryBlock:
%tmp = call i32 @gcd(i32 30, i32 50)
ret i32 %tmp
}
ModuleMaker2:
/home/hamayun/workspace/NaSiK/sw/llvm/lib/Bitcode/Writer/ValueEnumerator.cpp:155:
unsigned int llvm::ValueEnumerator::getValueID(const llvm::Value*)
const: Assertion `I != ValueMap.end() && "Value not in slotcalculator!"'
failed.
Aborted
----------------------------------------------------------------------

And here is the source code of my example.

----------------------------------------------------------------------
Module* makeLLVMModule(LLVMContext& Context);
Module* makeMainModule(LLVMContext& Context, Module &inMod);

static tool_output_file *GetOutputStream(const char *FileName)
{
std::string error;

tool_output_file *FDOut = new tool_output_file(FileName, error,
raw_fd_ostream::F_Binary);
if (!error.empty()) {
errs() << error << '\n';
delete FDOut;
return 0;
}

return FDOut;
}

int main(int argc, char**argv) {
LLVMContext& Context = getGlobalContext();

Module* ModGCD = makeLLVMModule(Context);
Module* ModMain = makeMainModule(Context, *ModGCD);

OwningPtr<tool_output_file> OutGCD (GetOutputStream("gcd.bc"));
if (!OutGCD) return 1;

OwningPtr<tool_output_file> OutMain (GetOutputStream("maingcd.bc"));
if (!OutMain) return 1;

verifyModule(*ModGCD, PrintMessageAction);
verifyModule(*ModMain, PrintMessageAction);

PassManager PM;
PM.add(createPrintModulePass(&outs()));
PM.run(*ModGCD);
PM.run(*ModMain);

WriteBitcodeToFile(ModGCD, OutGCD->os());
WriteBitcodeToFile(ModMain, OutMain->os());

OutGCD->keep();
OutMain->keep();

delete ModGCD;
delete ModMain;
return 0;
}

Module* makeMainModule(LLVMContext& Context, Module &inMod)
{
// Module Construction
Module* mod = new Module("GCDMain", Context);

FunctionType *FT = FunctionType::get(Type::getInt32Ty(Context),
std::vector<const llvm::Type*, std::allocator<const llvm::Type*> >
(2, Type::getInt32Ty(Context)),
/*not vararg*/false);

Constant* c = inMod.getOrInsertFunction("gcd", FT);
Function* gcd = cast<Function>(c);

FunctionType *FT_Main = FunctionType::get(Type::getInt32Ty(Context),
/*not vararg*/false);
Function *F_Main = Function::Create(FT_Main,
Function::ExternalLinkage, "main", mod);

BasicBlock *BB = BasicBlock::Create(Context, "EntryBlock", F_Main);
IRBuilder<> builder(BB);

Value *Thirty = ConstantInt::get(Type::getInt32Ty(Context), 30);
Value *Fifty = ConstantInt::get(Type::getInt32Ty(Context), 50);
std::vector<Value*> args;
args.push_back(Thirty);
args.push_back(Fifty);
Value *gcd_val = builder.CreateCall(gcd, args.begin(), args.end(),
"tmp");

builder.CreateRet(gcd_val);
return mod;
}

Module* makeLLVMModule(LLVMContext& Context) {
// Module Construction
Module* mod = new Module("GCD", Context);

FunctionType *FT = FunctionType::get(Type::getInt32Ty(Context),
std::vector<const llvm::Type*, std::allocator<const llvm::Type*> >
(2, Type::getInt32Ty(Context)),
/*not vararg*/false);

Constant* c = mod->getOrInsertFunction("gcd", FT);
Function* gcd = cast<Function>(c);
gcd->setLinkage(Function::ExternalLinkage);
gcd->setCallingConv(CallingConv::C);

Function::arg_iterator args = gcd->arg_begin();
Value* x = args++;
x->setName("x");
Value* y = args++;
y->setName("y");

BasicBlock* entry = BasicBlock::Create(Context, "entry", gcd);
BasicBlock* ret = BasicBlock::Create(Context, "return", gcd);
BasicBlock* cond_false = BasicBlock::Create(Context, "cond_false", gcd);
BasicBlock* cond_true = BasicBlock::Create(Context, "cond_true", gcd);
BasicBlock* cond_false_2 = BasicBlock::Create(Context, "cond_false",
gcd);

IRBuilder<> builder(entry);
Value* xEqualsY = builder.CreateICmpEQ(x, y, "tmp");
builder.CreateCondBr(xEqualsY, ret, cond_false);

builder.SetInsertPoint(ret);
builder.CreateRet(x);

builder.SetInsertPoint(cond_false);
Value* xLessThanY = builder.CreateICmpULT(x, y, "tmp");
builder.CreateCondBr(xLessThanY, cond_true, cond_false_2);

builder.SetInsertPoint(cond_true);
Value* yMinusX = builder.CreateSub(y, x, "tmp");
std::vector<Value*> args1;
args1.push_back(x);
args1.push_back(yMinusX);
Value* recur_1 = builder.CreateCall(gcd, args1.begin(), args1.end(),
"tmp");
builder.CreateRet(recur_1);

builder.SetInsertPoint(cond_false_2);
Value* xMinusY = builder.CreateSub(x, y, "tmp");
std::vector<Value*> args2;
args2.push_back(xMinusY);
args2.push_back(y);
Value* recur_2 = builder.CreateCall(gcd, args2.begin(), args2.end(),
"tmp");
builder.CreateRet(recur_2);

return mod;
}

----------------------------------------------------------------------

I am not sure why its happening or what I am missing ... :(
I also tried to search on this topic, but couldn't find similar posts
anywhere.

Any pointers / suggestions will be highly appreciated.

Thanks in advance.

--
Hamayun

Eli Friedman

unread,
Aug 31, 2011, 1:18:05 PM8/31/11
to mian-muham...@imag.fr, llv...@cs.uiuc.edu
On Wed, Aug 31, 2011 at 10:00 AM, Mian M. Hamayun
<mian-muham...@imag.fr> wrote:
> Hello Everyone,
>
> I am trying to create two modules in LLVM, where first module contains the
> definition of a function, gcd in this example and another module contains a
> call to this function.

You can't reference a global in one module in another module. Either
stick with one module, or add a declaration of the function in the
second module and call that.

-Eli
_______________________________________________
LLVM Developers mailing list
LLV...@cs.uiuc.edu http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev

Mian M. Hamayun

unread,
Aug 31, 2011, 1:54:04 PM8/31/11
to Eli Friedman, llv...@cs.uiuc.edu
Hi,

I tried this as well, using the following line to add function
declaration to the caller module.

Function::Create(FT, Function::ExternalLinkage, "gcd", mod);

Where "FT" is the same as before. And the output produced by the
PrintModulePass becomes:

; ModuleID = 'GCDMain'

declare i32 @gcd(i32, i32)

define i32 @main() {
EntryBlock:
%tmp = call i32 @gcd(i32 30, i32 50)
ret i32 %tmp
}

But it still fails to WriteBitcodeToFile, and produces the same error as
before.

I guess I might be missing some attribute, like "extern" in C ...

Any Comments?

Thanks again for your help,
Hamayun

Eli Friedman

unread,
Aug 31, 2011, 2:11:50 PM8/31/11
to mian-muham...@imag.fr, llv...@cs.uiuc.edu
On Wed, Aug 31, 2011 at 10:54 AM, Mian M. Hamayun
<mian-muham...@imag.fr> wrote:
> Hi,
>
> I tried this as well, using the following line to add function declaration
> to the caller module.
>
> Function::Create(FT, Function::ExternalLinkage, "gcd", mod);
>
> Where "FT" is the same as before. And the output produced by the
> PrintModulePass becomes:
>
> ; ModuleID = 'GCDMain'
>
> declare i32 @gcd(i32, i32)
>
> define i32 @main() {
> EntryBlock:
>  %tmp = call i32 @gcd(i32 30, i32 50)
>  ret i32 %tmp
> }
>
> But it still fails to WriteBitcodeToFile, and produces the same error as
> before.

If you're still getting the "Referencing function in another module"
error, the call isn't referring to a declaration in the same module.

Mian M. Hamayun

unread,
Sep 1, 2011, 9:04:49 AM9/1/11
to Eli Friedman, llv...@cs.uiuc.edu
Hi Eli,

Yes, you were right. I was doing something like this ... (which doesn't
work :()

Function* gcd = inMod.getFunction("gcd"); // Get gcd function from the
input module
...
Function *F_GCD = Function::Create(FT, Function::ExternalLinkage,
"gcd", mod); // Add a prototype of the gcd function
...


Value *gcd_val = builder.CreateCall(gcd, args.begin(), args.end(),

"tmp"); // Add a call to the gcd function.


In fact we don't need to getFunction from the other module.
Just adding a prototype and calling this prototype is sufficient.
Like this ... (this works :))

Function *F_GCD = Function::Create(FT, Function::ExternalLinkage,
"gcd", mod); // Add a prototype of the gcd function
...
Value *gcd_val = builder.CreateCall(F_GCD, args.begin(), args.end(),
"tmp"); // Add a call to the gcd function.


Thanks for you help,
Have a Nice Day !!!
Hamayun

Reply all
Reply to author
Forward
0 new messages