Wrong behavior modifying and executing llvm::Function with JIT Engine


The problem I’m having is that I modify a function body by using ‘Value::replaceAllUsesWith’ and then execute it with the JIT engine several times but I always get the output from the first iteration for all the iterations.

This is what I do:

I generate the following 2 functions on the fly based on the FunctionType of the declaration below in C code.

define i32 @get_int_5(i32, i32) #1 {
ret i32 5

define i32 @get_int_10(i32, i32) #1 {
ret i32 10

I have the following C code:

// This is only a declaration
// I use this FunctionType to generate the functions above
int sum(int a, int b);

int get_int()
return sum(a,b);

I replace the call to ‘sum()’ by calling Value::replaceAllUsesWith for one of the functions generated above, run with JIT. I checked the code generated and it actually changes the call from ‘sum()’ to ‘get_int_5()’ and I get a 5 as return value when I call the function with the JIT execution engine.

Then I repeat the previous step using ‘Value::replaceAllUsesWith’ for the next function I generated and run it with JIT. Then again the code generated is what I expected, this time
function call changes from ‘sum()’ to ‘get_int_10()’, however the problem is I get a 5 instead of a 10.

I tried ‘recompileAndLinkFunction’ as well as ‘freeMachineCodeForFunction’ and I always get the return value from the first function, and not the second as I should even though the generated code that I dump() says that it has the correct function call.

I am using version 3.4 for both clang and llvm. And also I’m using the JIT Engine and not the MCJIT.

Do you have have any idea why the references or ‘uses’ changes are not reflected in the code JIT’ed ?


Hi Adrian,

freeMachineCodeForFunction is required but recompileAndLinkFunction is not,
you can use getFunction() always.

Try to M->dump() calling M->getFunction() where M is the Module *.
See if how the changes appear in the module dump as expected.


getFunction() → getPointerToFunction()

I tried using 'getPointerToFunction()' and the correct function I generated was called from C code, but when it runs inside the JIT engine it always returns the value of the first function. I even tried to 'deleteBody()' and 'removeFromParent()' from the first function generated, and still returns the first value.

I also tried using 'dump()' to see if the values where being updated. This is the C code I run with the JIT engine:

    #include <stdio.h>

    int sum(int a, int b); // declaration

    int get_int(int a, int b)
         int x = sum(a,b);
         printf("The result was: %d\n",x);
         return x;

As you can see I print the return value of the function. The functions I generate and that I called 'get_int_*()' in the previous email are now called 'sum_mockup_N()'. This is the code LLVM IR code:

    ; Function Attrs: nounwind uwtable
    define i32 @get_int(i32 %a, i32 %b) #0 {
       %a.addr = alloca i32, align 4
       %b.addr = alloca i32, align 4
       %x = alloca i32, align 4
       store i32 %a, i32* %a.addr, align 4
       store i32 %b, i32* %b.addr, align 4
       %0 = load i32* %a.addr, align 4
       %1 = load i32* %b.addr, align 4
    *%call = call i32 @sum_mockup(i32 %0, i32 %1)* *; Use the first
    function generated*
       store i32 %call, i32* %x, align 4
       %2 = load i32* %x, align 4
       %call1 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds
    ([20 x i8]* @.str, i32 0, i32 0), i32 %2)
       %3 = load i32* %x, align 4
       ret i32 %3

    The result was: 10

    ; sum always remains a declaration
    declare i32 @sum(i32, i32) #1

    *define i32 @sum_mockup(i32, i32)* *#1 {**
    ** ret i32 10**

Another thing I just tried was to give 'sum()' the following implementation:

     int sum(int a, int b) { return 99; }

Now what I did was:

     1. Call 'get_int()' which will call 'sum(){return 99;}'
     2. Change the call instruction to 'sum_mockup', I dumped the code and the change is done, but when calling 'get_int()' it calls 'sum(){return 99;}'

I know it might be too rushed to say what the problem is, but it seems that when a function has been compiled and executed in the JIT engine, it will remain linked to other functions no matter what regardless of changing the call instruction.