How to pass an array to a function using GenericValue

Hi,

My application generates some LLVM assembly code which I then convert to IR code using ParseAssemblyString. If I have the following LLVM assembly code:

define double @test() {

ret double 1.230000e+02

}

then, using ExecutionEngine::runFunction, I get a GenericValue return value which DoubleVal property is indeed equal to 123. So, all is fine there. However, if I have the following LLVM assembly code:

define void @test(double* %data) {

%1 = getelementptr inbounds double* %data, i64 1

store double 1.230000e+02, double* %1, align 8

%2 = getelementptr inbounds double* %data, i64 3

store double 1.230000e+02, double* %2, align 8

ret void

}

then, I thought I could declare an array of doubles and pass it to ExecutionEngine::runFunction as follows:

double data[4];

data[0] = 100;

data[1] = 101;

data[2] = 102;

data[3] = 103;

std::vectorllvm::GenericValue args;

args.push_back(llvm::GenericValue(data));

executionEngine->runFunction(function, args);

As expected, data[1] and data[3] get updated, but… not to 123 but to 6.22870535974643e-317 (!!). I am still relatively new to LLVM so I wouldn’t exclude the fact that I might have done something wrong while trying to pass my data array to my function…?

Anyway, any help would be much appreciated…

Cheers, Alan.

PS: I have tried the getPointerToFunction(), but it just crashes my application…!?

Hi Alan,

if I have the following LLVM assembly code:

define void @test(double* %data) {

%1 = getelementptr inbounds double* %data, i64 1

store double 1.230000e+02, double* %1, align 8

%2 = getelementptr inbounds double* %data, i64 3

store double 1.230000e+02, double* %2, align 8

ret void

}

is this the entire LLVM IR? If so you should probably add targetdata to it
since otherwise (IIRC) it may assume things about the target that aren't
true for your machine.

Ciao, Duncan.

Hi Duncan,

> if I have the following LLVM assembly code:
>
> define void @test(double* %data) {
>
> %1 = getelementptr inbounds double* %data, i64 1
>
> store double 1.230000e+02, double* %1, align 8
>
> %2 = getelementptr inbounds double* %data, i64 3
>
> store double 1.230000e+02, double* %2, align 8
>
> ret void
>
> }

is this the entire LLVM IR? If so you should probably add targetdata
to it since otherwise (IIRC) it may assume things about the target
that aren't true for your machine.

Yes, it was the entire LLVM assembly code that I generated. However, I have
now prepended targetdata to the code I generate (using
executionEngine->getTargetData()->getStringRepresentation()), but to no
avail. I still get the exact same result...?!

Alan

> Yes, it was the entire LLVM assembly code that I generated. However, I
> have now prepended targetdata to the code I generate (using
> executionEngine->getTargetData()->getStringRepresentation()), but to
> executionEngine->no
> avail. I still get the exact same result...?!

What is the string you prepended? If the execution engine thinks the

target is

different to what it is then prepending the execution engine's notion of

target

isn't going to help.

I currently prepend:

   target datalayout =
"E-p:64:64:64-S0-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:6
4:64-v64:64:64-v128:128:128-a0:0:64"

Otherwise, and as I said, I am new to LLVM, but... how could the execution
engine return a target which is different than what it is?

Alan

Hi Alan,

Yes, it was the entire LLVM assembly code that I generated. However, I
have now prepended targetdata to the code I generate (using
executionEngine->getTargetData()->getStringRepresentation()), but to
executionEngine->no
avail. I still get the exact same result...?!

What is the string you prepended? If the execution engine thinks the

target is

different to what it is then prepending the execution engine's notion of

target

isn't going to help.

I currently prepend:

    target datalayout =
"E-p:64:64:64-S0-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:6
4:64-v64:64:64-v128:128:128-a0:0:64"

well, for example "E" means big endian ("e" would mean little endian), so
probably this is not what you want (are you on x86?).

Otherwise, and as I said, I am new to LLVM, but... how could the execution
engine return a target which is different than what it is?

I guess you mean it should use the characteristics of the machine you are
running the code on by default. Actually I thought it did nowadays (in the
bad old days it would assume sparc or something like that), but I guess I
was mistaken. It looks like you need to say explicitly what kind of machine
you will run the code on.

Ciao, Duncan.

>>> Yes, it was the entire LLVM assembly code that I generated. However,
>>> I have now prepended targetdata to the code I generate (using
>>> executionEngine->getTargetData()->getStringRepresentation()), but to
>>> executionEngine->no
>>> avail. I still get the exact same result...?!
>>
>> What is the string you prepended? If the execution engine thinks the
> target is
>> different to what it is then prepending the execution engine's notion
>> of
> target
>> isn't going to help.
>
> I currently prepend:
>
> target datalayout =
> "E-p:64:64:64-S0-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32
> -f64:6
> 4:64-v64:64:64-v128:128:128-a0:0:64"

well, for example "E" means big endian ("e" would mean little endian), so
probably this is not what you want (are you on x86?).

> Otherwise, and as I said, I am new to LLVM, but... how could the
> execution engine return a target which is different than what it is?

I guess you mean it should use the characteristics of the machine you are
running the code on by default. Actually I thought it did nowadays (in

the bad

old days it would assume sparc or something like that), but I guess I was
mistaken. It looks like you need to say explicitly what kind of machine

you will

run the code on.

Ok, I have solved my problem and I have you to thank for mentioning the
target data layout. This indirectly pointed me in the right direction.

Basically, the issue was that I was aiming at creating a JIT execution
engine, BUT I had forgotten to call InitializeNativeTarget()! Now that I
have added that call, everything's fine. Doh! I have checked the target data
layout and indeed, it refers to little endian, as expected. Talking of the
target data layout, I don't actually need to have it in the LLVM assembly
code I generate since it's (obviously) information that is part of my JIT
execution engine.

Anyway, everything works fine now. I just need to figure out a way to avoid
calling executionEngine->runFunction() and, instead, use
executionEngine->getPointerToFunction() and then call the function
'directly'. (Indeed, I will need to call that function thousands of times,
so I cannot afford the overhead associated with
executionEngine->runFunction().) Right now, I have something like

  1 void (*func)(double *) = reinterpret_cast<void (*)(double
*)>((intptr_t) executionEngine->getPointerToFunction(function));
  2 func(data);

but line 2 causes my program to crash. Ok, I will have a look at this
tomorrow. In the meantime, thanks again for your help!

Alan