[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