Inserting a function call using LLVM

Hi,

I am new to LLVM and interested in using LLVM to work on a research project for my Master’s degree.
My idea is following -

  1. I have a simple C program basic.c -
    #include <stdio.h>
    int main() {
    printf(“Hello World”);
    return 0;
    }

  2. I will generate IR byte code for this basic.c using -
    llvm-gcc -emit-llvm -S basic.c

This will give me basic.s which has IR byte code like this -

; ModuleID = ‘basic.c’
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”
target triple = “x86_64-apple-darwin10.8”

@.str = private constant [12 x i8] c"hello world\00", align 1 ; <[12 x i8]*> [#uses=1]

define i32 @main() nounwind ssp {
entry:
%retval = alloca i32 ; <i32*> [#uses=2]
%0 = alloca i32 ; <i32*> [#uses=2]
%“alloca point” = bitcast i32 0 to i32 ; [#uses=0]
%1 = call i32 @puts(i8* getelementptr inbounds ([12 x i8]* @.str, i64 0, i64 0)) nounwind ; [#uses=0]
store i32 0, i32* %0, align 4
%2 = load i32* %0, align 4 ; [#uses=1]
store i32 %2, i32* %retval, align 4
br label %return

return: ; preds = %entry
%retval1 = load i32* %retval ; [#uses=1]
ret i32 %retval1
}

declare i32 @puts(i8*)

  1. I want to write a pass to insert a call foo(int a) after the printf() call, so that it looks like this -

#include <stdio.h>
int main() {
printf(“Hello World”);
foo(1);
return 0;
}

void foo(int a) {
printf(“a + 5 is : %d”, a + 5);
}

How can I achieve this? I looked online but couldn’t find a definite source which tells me how to do this.
I think I can use Cloning.h and CloneFunction.cpp to clone a given function and then insert my call to foo().
But I’m not sure if this is the right way to do this. The documentation obviously did not say this explicitly.
Any thoughts / pointers ?

Thanks in advance !

  • Teja

Hi Teja,

I am new to LLVM and interested in using LLVM to work on a research project for
my Master's degree.
My idea is following -

1. I have a simple C program basic.c -
#include <stdio.h>
int main() {
    printf("Hello World");
    return 0;
}

2. I will generate IR byte code for this basic.c using -
llvm-gcc -emit-llvm -S basic.c

This will give me basic.s which has IR byte code like this -

; ModuleID = 'basic.c'
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"
target triple = "x86_64-apple-darwin10.8"

@.str = private constant [12 x i8] c"hello world\00", align 1 ; <[12 x i8]*>
[#uses=1]

define i32 @main() nounwind ssp {
entry:
   %retval = alloca i32 ; <i32*> [#uses=2]
   %0 = alloca i32 ; <i32*> [#uses=2]
   %"alloca point" = bitcast i32 0 to i32 ; <i32> [#uses=0]
   %1 = call i32 @puts(i8* getelementptr inbounds ([12 x i8]* @.str, i64 0, i64
0)) nounwind ; <i32> [#uses=0]
   store i32 0, i32* %0, align 4
   %2 = load i32* %0, align 4 ; <i32> [#uses=1]
   store i32 %2, i32* %retval, align 4
   br label %return

return: ; preds = %entry
   %retval1 = load i32* %retval ; <i32> [#uses=1]
   ret i32 %retval1
}

declare i32 @puts(i8*)

3. I want to write a pass to insert a call foo(int a) after the printf() call,
so that it looks like this -
#include <stdio.h>
int main() {
    printf("Hello World");
    foo(1);
    return 0;
}

void foo(int a) {
    printf("a + 5 is : %d", a + 5);
}

you need to do:
(1) insert a declaration of "foo" into the module;
(2) find the spot in the IR where you want to put it, i.e. find the printf
(3) insert the call

For (1), use Function::Create.
For (2), use Module::getFunction to lookup "main", then iterate over the basic
blocks, and within each basic block iterate over instructions, looking for a
call instruction, using isa<CallInst> to test if an instruction is a call.
For (3), create an IRBuilder, set the insertion point to the instruction after
the printf, and use the CreateCall method.

Ciao, Duncan.

Thanks Ciao

I am following your instruction and able to write some code. Instead of foo() my aim is to add

int mul_add(int x, int y, int z)
{
return (x*y+z)
}

Please find the attached source code in the email.

Issue I am facing now it is crashing and backtrace is

Assertion failed: (V->getParent() == 0 && “Value already in a container!!”), function addNodeToList, file SymbolTableListTraitsImpl.h, line 68.
0 opt 0x00000001007989b3 PrintStackTrace(void*) + 51
1 opt 0x0000000100798f1d SignalHandler(int) + 333
2 libSystem.B.dylib 0x00007fff8731d1ba _sigtramp + 26
3 libSystem.B.dylib 0x0000000700000018 _sigtramp + 2026778232
4 opt 0x00000001000a0c2f raise + 31
5 opt 0x00000001000a0c60 abort + 16
6 opt 0x00000001000a0d2d __assert_rtn + 189
7 opt 0x0000000100063077 llvm::SymbolTableListTraits<llvm::Instruction, llvm::BasicBlock>::addNodeToList(llvm::Instruction*) + 101
8 LLVMHello.dylib 0x0000000101688a3c llvm::iplist<llvm::Instruction, llvm::ilist_traitsllvm::Instruction >::insert(llvm::ilist_iteratorllvm::Instruction, llvm::Instruction*) + 178
9 LLVMHello.dylib 0x00000001016877df (anonymous namespace)::Hello::doInitialization(llvm::Module&) + 2639
10 opt 0x000000010070ebd4 llvm::FPPassManager::doInitialization(llvm::Module&) + 86
11 opt 0x000000010070dfe5 llvm::FPPassManager::runOnModule(llvm::Module&) + 35
12 opt 0x000000010071317b llvm::MPPassManager::runOnModule(llvm::Module&) + 613
13 opt 0x0000000100714526 llvm::PassManagerImpl::run(llvm::Module&) + 150
14 opt 0x00000001007145cb llvm::PassManager::run(llvm::Module&) + 39
15 opt 0x00000001000b5a50 main + 7552
16 opt 0x00000001000a7578 start + 52
Stack dump:

Also I am not sure how to send parameters to function mul_add() when I am calling it from main() function. i.e. how and where to set x = 1, y = 2 and z = 3 so that call from main() will be mul_add(1, 2, 3).

Please let me know

Thanks,
–Teja

Hello.cpp (4.43 KB)