newbie question on getelementptr

Hi All,

I’m new to LLVM and I’m having a coding problem.

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? I’d like to be able to run the function.

result->dump() shows the following:
i32 (i32, i32)** getelementptr inbounds (%myStruct* @myGV, i32 0, i32 0)

Many thanks,
Jay

Jay Gelisah <jay.gelisah@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);
}

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(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 (
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 (
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 (v);

// let’s see if module verifies
if (verifyModule(*module)) {
return 1;
} else {
module->dump();
}

if (myfn && isa(myfn)) {
ExecutionEngine *EE = EngineBuilder(module).create();
if (!EE) {
return 1;
}

std::vector 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:

Jay Gelisah <jay.gelisah@gmail.com> writes:

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?

Where do you set the value stored in the GlobalVariable before reading
it? With the getelementptr you are getting an address to uninitialized
memory. In C parlance, you are accessing an unitialized struct member.