Friday, June 13, 2008

The secret of the LLVM C bindings

Ever wanted to use LLVM from C? Can't find any documentation? Welcome.

Since I'm considering retargeting CLISP'S JIT Compiler I've been experimenting with LLVM. LLVM is an optimizing compiler for a virtual instruction set. Technically, it is very interesting. And this year, with Apple and CLANG in the game, it seems to be here to stay.

A Factorial in C with LLVM
Let's make a factorial function using the C bindings of LLVM 2.3+.
The function we will describe in LLVM instructions is illustrated below.

I inserted the phi instruction manually to make things more interesting.
Paste this in your favorite editor and save it as "fac.c":


// Headers required by LLVM
#include <llvm-c/Core.h>
#include <llvm-c/Analysis.h>
#include <llvm-c/ExecutionEngine.h>
#include <llvm-c/Target.h>
#include <llvm-c/Transforms/Scalar.h>


// General stuff
#include <stdlib.h>
#include <stdio.h>


int main (int argc, char const *argv[])
{
char *error = NULL; // Used to retrieve messages from functions
LLVMModuleRef mod = LLVMModuleCreateWithName("fac_module");
LLVMTypeRef fac_args[] = { LLVMInt32Type() };
LLVMValueRef fac = LLVMAddFunction(mod, "fac", LLVMFunctionType(LLVMInt32Type(), fac_args, 1, 0));
LLVMSetFunctionCallConv(fac, LLVMCCallConv);
LLVMValueRef n = LLVMGetParam(fac, 0);

LLVMBasicBlockRef entry = LLVMAppendBasicBlock(fac, "entry");
LLVMBasicBlockRef iftrue = LLVMAppendBasicBlock(fac, "iftrue");
LLVMBasicBlockRef iffalse = LLVMAppendBasicBlock(fac, "iffalse");
LLVMBasicBlockRef end = LLVMAppendBasicBlock(fac, "end");
LLVMBuilderRef builder = LLVMCreateBuilder();

LLVMPositionBuilderAtEnd(builder, entry);
LLVMValueRef If = LLVMBuildICmp(builder, LLVMIntEQ, n, LLVMConstInt(LLVMInt32Type(), 0, 0), "n == 0");
LLVMBuildCondBr(builder, If, iftrue, iffalse);

LLVMPositionBuilderAtEnd(builder, iftrue);
LLVMValueRef res_iftrue = LLVMConstInt(LLVMInt32Type(), 1, 0);
LLVMBuildBr(builder, end);

LLVMPositionBuilderAtEnd(builder, iffalse);
LLVMValueRef n_minus = LLVMBuildSub(builder, n, LLVMConstInt(LLVMInt32Type(), 1, 0), "n - 1");
LLVMValueRef call_fac_args[] = {n_minus};
LLVMValueRef call_fac = LLVMBuildCall(builder, fac, call_fac_args, 1, "fac(n - 1)");
LLVMValueRef res_iffalse = LLVMBuildMul(builder, n, call_fac, "n * fac(n - 1)");
LLVMBuildBr(builder, end);

LLVMPositionBuilderAtEnd(builder, end);
LLVMValueRef res = LLVMBuildPhi(builder, LLVMInt32Type(), "result");
LLVMValueRef phi_vals[] = {res_iftrue, res_iffalse};
LLVMBasicBlockRef phi_blocks[] = {iftrue, iffalse};
LLVMAddIncoming(res, phi_vals, phi_blocks, 2);
LLVMBuildRet(builder, res);

LLVMVerifyModule(mod, LLVMAbortProcessAction, &error);
LLVMDisposeMessage(error); // Handler == LLVMAbortProcessAction -> No need to check errors


LLVMExecutionEngineRef engine;
LLVMModuleProviderRef provider = LLVMCreateModuleProviderForExistingModule(mod);
error = NULL;
LLVMCreateJITCompiler(&engine, provider, &error);
if(error) {
fprintf(stderr, "%s\n", error);
LLVMDisposeMessage(error);
abort();
}

LLVMPassManagerRef pass = LLVMCreatePassManager();
LLVMAddTargetData(LLVMGetExecutionEngineTargetData(engine), pass);
LLVMAddConstantPropagationPass(pass);
LLVMAddInstructionCombiningPass(pass);
LLVMAddPromoteMemoryToRegisterPass(pass);
// LLVMAddDemoteMemoryToRegisterPass(pass); // Demotes every possible value to memory
LLVMAddGVNPass(pass);
LLVMAddCFGSimplificationPass(pass);
LLVMRunPassManager(pass, mod);
LLVMDumpModule(mod);

LLVMGenericValueRef exec_args[] = {LLVMCreateGenericValueOfInt(LLVMInt32Type(), 10, 0)};
LLVMGenericValueRef exec_res = LLVMRunFunction(engine, fac, 1, exec_args);
fprintf(stderr, "\n");
fprintf(stderr, "; Running fac(10) with JIT...\n");
fprintf(stderr, "; Result: %d\n", LLVMGenericValueToInt(exec_res, 0));

LLVMDisposePassManager(pass);
LLVMDisposeBuilder(builder);
LLVMDisposeExecutionEngine(engine);
return 0;
}

Compiling the code
Generating the object file is a no-brainer:

gcc `llvm-config --cflags` -c fac.c
Linking is a little trickier. Even though you are writing C code, you have to use a C++ linker.

g++ `llvm-config --libs --cflags --ldflags core analysis executionengine jit interpreter native` fac.o -o fac
All set!

15 comments:

Marc-André Lureau said...

You might need to call "LLVMLinkInJIT" nowadays.

thanks for this introduction to LLVM

Anonymous said...

For LLVM 2.6, I needed to make a couple changes:
1)
At the start of main, add:
LLVMLinkInJIT();
LLVMInitializeNativeTarget();

2) LLVMCreateJITCompiler has an extra argument (Optimization level), and has a return value of whether an error occurred. So replace lines 58-59 with:

if(LLVMCreateJITCompiler(&engine, provider, 2, &error) != 0) {

Anonymous said...

Not sure why, but on Ubuntu 10.04, this only compiles for me if I put fac.o *before* the `llvm-config`. It's weird; this is the only time I can think of that the linker's behaviour has been influenced by the order of the object/library files.

g++ fac.o `llvm-config --libs --cflags --ldflags core analysis executionengine jit interpreter native` -o fac

super hero said...

Misbah Digital Marketing is an excellent online marketing agency in Bangalore.Misbah Digital Marketing!
Misbah Digital Marketing! having certified professionals in Google Ads, Google Analytics and Bing Ads.

Misbah Digital Marketing!

fitnessgirlslife said...

Teacher Vacancy 2020: Check out latest vacancy for teachers online. Find latest teaching vacancies 2020 jobs and apply online. Exclusive job portal

Teacher Job Sites





Join our online group classes live from the Academic Delivery Center. Entire schedule is published before hand with clear guidelines

Online Tuition Classes

10melhores said...


best site to visit
Click Hare
click hare
click hare
Click hare
Click hare
Click hare
Click hare
Click hare



tejaswani blogs said...

Thank you for sharing this extremely useful information. You made some well-considered points.
This essay has a lot of information that I would never have considered on my own.

digital marketing training in hyderabad
digital marketing course in ameerpet
digital marketing course training in hyderabad ameerpet
digital marketing online training in hyderabad

Educational Services said...

Thanks For Sharing such a wonderful article the way you presented is really amazing
Best Software Training Institutes

haritha said...

informative blog post. Thanks for sharing
Best Web development company in Hyderabad

Unknown said...

Quality Content. Thanks for Sharing
Best Interior Designers

Unknown said...

I read your post. It is very informative and helpful to me. I admire the message valuable information you provided in your article.
online bus ticket booking

Unknown said...

physicians email list

Unknown said...

it decision makers list

Unknown said...

crazypraisy

bestbus said...

I really liked the content which is very helpful for me. Thanks for sharing.
tourist places in hyderabad