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!

17 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

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

bestbus said...

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

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

JacobHarman said...

The server-side code of the framework depends on C#. The front end side is written in DHTML with JavaScript and HTML. It likewise can be founded on ASP.NET. The substances and data sets are put away in Microsoft SQL Administration. MS SQL Server Perspectives are utilized widely for areas of strength for giving to Job Based survey of the undertaking information in MS CRM 4.0 and later variants. The association administration is worked with the utilization of the WCF, and the synchronization with disconnected information in Standpoint is based on the Sync Structure. In Microsoft Elements cost of execution relies upon the range of abilities of the developers and size of work. Adding one basic element is less expensive than the formation of the framework without any preparation>> Microsoft Dynamics CRM development company

jasika said...

Even if you have years of experience writing in English, you are bound to make mistakes. Errors in your paper can be as subtle as creating confusion and mistrust. Be sure to get professional proofreading help to make sure your writing is impeccable sentence breakdown tool Our Correct My Sentences Online allows you to write like a native English speaker

Rupesh Kumar said...

Nice Blog, Thanks for providing this wonderful information. If you are looking for a reliable and affordable way to help your child pass the CBSE exams, then CBSE home tutoring is the perfect solution for you.
For more info contact +91-9654271931 | UAE +971- 505593798 or visit Best CBSE Online Tuition Classes

Rupesh Kumar said...

Excellent information on your blog, thank you for taking the time to share with us. Looking for top-notch CBSE tuition classes? Ziyyara’s online tuition classes are designed to help students excel in their CBSE board exams.
For more info contact +91-9654271931 or visit CBSE Online Tuition Classes

Rupesh Kumar said...

This is good information and really helpful for the people who need information about this. Join Ziyyara Edutech’s online private tuition classes designed exclusively for 7th standard students, right in the comfort of your own home.
Book A Free Demo Today visit Private tuition classes for class 7 student