mcjit C interface problems

Hi, I’m attempting to use MCJIT with the C interface with llvm-3.9.0, and it doesn’t seem to work. This code is derived from Paul Smith’s example code:

int main(int argc, char const* argv[]) {

LLVMModuleRef mod = LLVMModuleCreateWithName(“my_module”);

LLVMTypeRef param_types[] = {LLVMInt32Type(), LLVMInt32Type()};
LLVMTypeRef ret_type = LLVMFunctionType(LLVMInt32Type(), param_types, 2, 0);
LLVMValueRef sum = LLVMAddFunction(mod, “sum”, ret_type);

LLVMBasicBlockRef entry = LLVMAppendBasicBlock(sum, “entry”);

LLVMBuilderRef builder = LLVMCreateBuilder();
LLVMPositionBuilderAtEnd(builder, entry);
LLVMValueRef tmp = LLVMBuildAdd(builder, LLVMGetParam(sum, 0), LLVMGetParam(sum, 1), “tmp”);
LLVMBuildRet(builder, tmp);

char* error = NULL;
LLVMVerifyModule(mod, LLVMAbortProcessAction, &error);
LLVMDisposeMessage(error);

LLVMExecutionEngineRef engine;
error = NULL;
LLVMLinkInMCJIT();
LLVMInitializeNativeTarget();
LLVMInitializeNativeAsmPrinter();
LLVMInitializeNativeAsmParser();

if (LLVMCreateExecutionEngineForModule(&engine, mod, &error) != 0) {
fprintf(stderr, “failed to create execution engine\n”);
abort();
}
if (error) {
fprintf(stderr, “error: %s\n”, error);
LLVMDisposeMessage(error);
exit(EXIT_FAILURE);
}

if (argc < 3) {
fprintf(stderr, “usage: %s x y\n”, argv[0]);
exit(EXIT_FAILURE);
}
long long x = strtoll(argv[1], NULL, 10);
long long y = strtoll(argv[2], NULL, 10);

LLVMGenericValueRef args[] = {LLVMCreateGenericValueOfInt(LLVMInt32Type(), x, 0),
LLVMCreateGenericValueOfInt(LLVMInt32Type(), y, 0)};

printf(“args[0]: %d\n”, (int)LLVMGenericValueToInt(args[0], 0));
printf(“args[1]: %d\n”, (int)LLVMGenericValueToInt(args[1], 0));

LLVMGenericValueRef res = LLVMRunFunction(engine, sum, 2, args);

printf(“result: %d\n”, (int)LLVMGenericValueToInt(res, 0));

LLVMDumpModule(mod);

// Write out bitcode to file
if (LLVMWriteBitcodeToFile(mod, “sum.bc”) != 0) { fprintf(stderr, “error writing bitcode to file, skipping\n”); }

LLVMDisposeBuilder(builder);
LLVMDisposeExecutionEngine(engine);
}

Here’s what I see when I run it:
$ ./capi_test 5 6
args[0]: 5
args[1]: 6
result: 5
; ModuleID = ‘my_module’
source_filename = “my_module”
target datalayout = “e-m:e-i64:64-f80:128-n8:16:32:64-S128”

define i32 @sum(i32, i32) {
entry:
%tmp = add i32 %0, %1
ret i32 %tmp
}

It seems to fail to add, and always returns the first argument.

Any help greatly appreciated.

Toshi

Hi,

Thanks for the tip - getting closer:

$ ./capi_test 5 6
args[0]: 5
args[1]: 6
result: 4294959200

Here’s the code I changed:

printf(“args[0]: %d\n”, (int)LLVMGenericValueToInt(args[0], 0));
printf(“args[1]: %d\n”, (int)LLVMGenericValueToInt(args[1], 0));

uint64_t (func)();
func = (uint64_t (
)())LLVMGetFunctionAddress(engine, “sum”);
printf(“result: %lu\n”, (*func)());

Anything else I should look at?

Toshi

Hi,

Andres Freund wrote:

Thanks for the tip - getting closer:

$ ./capi_test 5 6
args[0]: 5
args[1]: 6
result: 4294959200

Here’s the code I changed:

printf(“args[0]: %d\n”, (int)LLVMGenericValueToInt(args[0], 0));
printf(“args[1]: %d\n”, (int)LLVMGenericValueToInt(args[1], 0));

uint64_t (func)();
func = (uint64_t (
)())LLVMGetFunctionAddress(engine, “sum”);
printf(“result: %lu\n”, (*func)());

You’re calling the function without arguments, but it’s (in IR) declared
to take two. And you’re miscasting the return value to be int64, instead
of int32 as the function’s declared.

Thanks again - revised code snippet:

int (*func)(LLVMGenericValueRef );
func = (int (
)(LLVMGenericValueRef *))LLVMGetFunctionAddress(engine, “sum”);
int res = (*func)(args);
printf(“result: %d\n”, res);

Output:

$ ./capi_test 5 6
args[0]: 5
args[1]: 6
result: -7872

Do the two argument pointers need to be passed separately?

Does the function return an LLVMGenericValueRef?

Toshi

Andres Freund wrote:

>> Thanks for the tip - getting closer:
>>
>> $ ./capi_test 5 6
>> args[0]: 5
>> args[1]: 6
>> result: 4294959200
>>
>> Here's the code I changed:
>>
>> printf("args[0]: %d\n", (int)LLVMGenericValueToInt(args[0], 0));
>> printf("args[1]: %d\n", (int)LLVMGenericValueToInt(args[1], 0));
>>
>> uint64_t (*func)();
>> func = (uint64_t (*)())LLVMGetFunctionAddress(engine, "sum");
>> printf("result: %lu\n", (*func)());
>
>You're calling the function without arguments, but it's (in IR) declared
>to take two. And you're miscasting the return value to be int64, instead
>of int32 as the function's declared.

Thanks again - revised code snippet:

  int (*func)(LLVMGenericValueRef *);
  func = (int (*)(LLVMGenericValueRef *))LLVMGetFunctionAddress(engine,
"sum");

It's a normal function taking integers. So just pass in the values *as
integers*. What you're doing here is re-interpreting LLVMGenericValueRef
pointers as integers.

Do the two argument pointers need to be passed separately?

Yes. But as ints.

Does the function return an LLVMGenericValueRef?

No, an int.