[LLVMdev] newbie question on getelementptr
Jay Gelisah
jay.gelisah at gmail.com
Wed Sep 19 09:35:07 PDT 2012
Hi Óscar,
Thank you for your prompt reply. Unfortunately, I still need more guidance
as using the Demo page to generate C++ code didn't result in a global
variable being used.
Basically, I'm following your advice to use a LoadInst:
Value *v = new LoadInst(result, "", theBasicBlock);
Function *myfn = cast<Function>(v);
I was not sure how I could get a BasicBlock for the LoadInst, so I created
a dummy function (which was never called).
Casting was successful as myfn->getType()->dump() produced i32 (i32, i32)*.
However, I'm getting a "bus error" when trying to run the retrieved
function using an ExecutionEngine (not sure if this is the proper way to
run a function).
Here is my code:
// includes omitted
using namespace llvm;
using namespace std;
static Function *CreateAddFunction(Module *module) {
Function *func_add = cast<Function> (
module->getOrInsertFunction("add",
Type::getInt32Ty(module->getContext()),
Type::getInt32Ty(module->getContext()),
Type::getInt32Ty(module->getContext()), (Type *) 0));
BasicBlock *BB = BasicBlock::Create(module->getContext(), "Start",
func_add);
Function::arg_iterator args = func_add->arg_begin();
Value* arg1 = args++;
Value* arg2 = args++;
Value *Sum = BinaryOperator::CreateAdd(arg1, arg2, "sum", BB);
ReturnInst::Create(module->getContext(), Sum, BB);
return func_add;
}
int main() {
// basically what I want is create a function (func_add), store it in a
global variable, retrieves it from the global var, and run it.
Module *module = new Module("myModule", getGlobalContext());
module->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-S128");
module->setTargetTriple("x86_64-unknown-linux-gnu");
Function *func_add = CreateAddFunction(module);
// create a StructType to contain func_add
StructType *myStructType = StructType::create(module->getContext(),
"myStruct");
std::vector<Type*> fields;
fields.push_back(func_add->getType());
if (myStructType->isOpaque()) {
myStructType->setBody(fields, /*isPacked=*/false);
}
string myGVName = "myGV";
// create a GlobalVariable to store myStruct
GlobalVariable* mainGV = new GlobalVariable(
/*Module=*/*module,
/*Type=*/myStructType,
/*isConstant=*/false,
/*Linkage=*/GlobalValue::ExternalLinkage,
/*Initializer=*/0, // has initializer, specified below
/*Name=*/myGVName);
Constant* ptr_to_func_add = ConstantStruct::get(myStructType, func_add);
mainGV->setInitializer(ptr_to_func_add);
// now try to retrieve func_add from the global variable
GlobalVariable* retrieved = module->getGlobalVariable(myGVName);
if (retrieved) {
std::vector<Constant*> indices;
ConstantInt* constI32_0 = ConstantInt::get(module->getContext(),
APInt(32, StringRef("0"), 10));
indices.push_back(constI32_0);
indices.push_back(constI32_0);
Constant* result = ConstantExpr::getGetElementPtr(retrieved,
indices);
Function *func_dummy = cast<Function> (
module->getOrInsertFunction("dummy",
Type::getVoidTy(module->getContext()),
Type::getInt32Ty(module->getContext()), (Type *)
0));
// Add a basic block to the function.
BasicBlock *BB = BasicBlock::Create(module->getContext(),
"EntryBlock", func_dummy);
Value *v = new LoadInst(result, "", BB);
ReturnInst::Create(module->getContext(), BB);
Function *myfn = cast<Function> (v);
// let's see if module verifies
if (verifyModule(*module)) {
return 1;
} else {
module->dump();
}
if (myfn && isa<Function>(myfn)) {
ExecutionEngine *EE = EngineBuilder(module).create();
if (!EE) {
return 1;
}
std::vector<GenericValue> Args(2);
Args[0].IntVal = APInt(32, 5);
Args[1].IntVal = APInt(32, 10);
outs() << "\ntype of myfn:";
myfn->getType()->dump();
GenericValue GV = EE->runFunction(func_add, Args);
outs() << "\nResult: " << GV.IntVal << "\n";
}
}
return 0;
}
However, if I replace the retrieved function ponter
GenericValue GV = EE->runFunction(myfn, Args);
with the original function pointer
GenericValue GV = EE->runFunction(func_add, Args);
It seems to run okay and prints the correct result.
Here is the dump of my console:
===================================================================
; ModuleID = 'myModule'
target datalayout =
"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-S128"
target triple = "x86_64-unknown-linux-gnu"
%myStruct = type { i32 (i32, i32)* }
@myGV = global %myStruct { i32 (i32, i32)* @add }
define i32 @add(i32, i32) {
Start:
%sum = add i32 %0, %1
ret i32 %sum
}
define void @dummy(i32) {
EntryBlock:
%1 = load i32 (i32, i32)** getelementptr inbounds (%myStruct* @myGV, i32
0, i32 0)
ret void
}
type of myfn:i32 (i32, i32)*Bus error
===================================================================
What am I doing wrong here?
Thank you for your help,
Jay
On Wed, Sep 19, 2012 at 7:02 AM, Óscar Fuentes <ofv at wanadoo.es> wrote:
> Jay Gelisah <jay.gelisah at gmail.com> writes:
>
> > I'm creating a GlobalVariable that contains a StructType that contains a
> > Function. The function returns i32 and takes two i32's.
> >
> > Here is my code:
> > GlobalVariable* retrieved = module->getGlobalVariable("myGV");
> > ...
> > Constant* result = ConstantExpr::getGetElementPtr(retrieved, indices);
> >
> > How do I get my Function back from the Constant* result?
>
> You already have a pointer to the function pointer stored in `result'.
>
> > I'd like to be able to run the function.
>
> Use CallInst::Create for creating a CallInst. CallInst will gladly
> accept a Value* or one of its derivatives as its argument, as far as it
> has the correct type (see below). No need to cast.
>
> > result->dump() shows the following:
> > i32 (i32, i32)** getelementptr inbounds (%myStruct* @myGV, i32 0, i32 0)
>
> Please note that you need to pass the result of the getelementptr
> through a LoadInst because, as shown, getelementptr returns a pointer to
> the data inside the struct or array.
>
> Value *v = new LoadInst(result, "", theBasicBlock);
> Function *myfn = cast<Function>(v);
> <check that `myfn' is not null>
>
> In general, for learning the C++ API it is a good idea to create a
> sample of C/C++ code that does what your generated code should do and
> pass it through Clang/llc to see the C++ API code. The online demo
> available at http://llvm.org/demo/index.cgi is handy for that. In your
> specific case, put there the code below, check the C++ radiobutton,
> select the C++ API target and push the Compile button.
>
> struct Foo {
> int dummy;
> double anotherDummy;
> int (*fn)(int, int);
> };
>
> int callIt(Foo foo) {
> return (*foo.fn)(1, 2);
> }
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20120919/cc964af3/attachment.html>
More information about the llvm-dev
mailing list