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);

LLVMPassManagerRef pass = LLVMCreatePassManager();
LLVMAddTargetData(LLVMGetExecutionEngineTargetData(engine), pass);
// LLVMAddDemoteMemoryToRegisterPass(pass); // Demotes every possible value to memory
LLVMRunPassManager(pass, 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));

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!


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:
At the start of main, add:

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

Anonymous said...

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

Unknown said...

Quality Content. Thanks for Sharing
Best Interior Designers

Anonymous 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

physicians email list said...

physicians email list

physicians email list said...

it decision makers list

physicians email list said...


bestbus said...

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

Rahul singh said...

Your post is very great. I read this post. It’s very helpful. I will definitely go ahead and take advantage of this. You absolutely have wonderful stories. Cheers for sharing with us your blog. For more learning about data science visit at data science course in Bangalore

Mona Mishra said...

Nice Post, Good content
Web development Company in Hyderabad- Inovies
Ecommerce Development Company
Social Media Marketing Company in Hyderabad

Akshat said...

Great very helpful blog. Thanks For Sharing Such A Wonderful Blog. I will definitely go ahead and take advantage of this. Your Blog Is Very Informative. Again Thanks For Sharing This Blogs With Us. For more learning go through Skillslash.
For Data Science Course Data Science Course In Bangalore

Shubham Saini said...

Nice Blog! such a informative things you are sharing ,I really liked your content. If you wanna know about "Skillslash | Training with live industry experience that gets you hired" go to Data science courses in bangalore

Shubham Saini said...

Nice Blog! such a informative things you are sharing ,I really liked your content. If you wanna know about "Skillslash | Training with live industry experience that gets you hired" go to Data Science Course

Abdullah Saif said...

Hope it will certainly be valuable for all. All the facts are given out in a quite easy and also reasonable form.
december umrah packages 2022