Skip to content

Instantly share code, notes, and snippets.

@mmower
Created October 30, 2011 13:43
Show Gist options
  • Save mmower/1325908 to your computer and use it in GitHub Desktop.
Save mmower/1325908 to your computer and use it in GitHub Desktop.
Revised LLVM Fibonacci example
//===--- examples/Fibonacci/fibonacci.cpp - An example use of the JIT -----===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This small program provides an example of how to build quickly a small module
// with function Fibonacci and execute it with the JIT.
//
// The goal of this snippet is to create in the memory the LLVM module
// consisting of one function as follow:
//
// int fib(int x) {
// if(x<=2) return 1;
// return fib(x-1)+fib(x-2);
// }
//
// Once we have this, we compile the module via JIT, then execute the `fib'
// function and return result to a driver, i.e. to a "host program".
//
//===----------------------------------------------------------------------===//
#include "llvm/LLVMContext.h"
#include "llvm/Module.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Constants.h"
#include "llvm/Instructions.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/ExecutionEngine/JIT.h"
#include "llvm/ExecutionEngine/Interpreter.h"
#include "llvm/ExecutionEngine/GenericValue.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/TargetSelect.h"
using namespace llvm;
#define CONST_INT32( n, c ) ( ConstantInt::get( Type::getInt32Ty( c ), n ) )
static BasicBlock *CreateBaseCase( Function *FibFunction, LLVMContext &Context ) {
BasicBlock *Scope = BasicBlock::Create(Context, "base_case", FibFunction);
ReturnInst::Create(Context, CONST_INT32( 1, Context ), Scope);
return Scope;
}
static BasicBlock *CreateRecursiveCase( Function *FibFunction, Argument *ArgX, LLVMContext &Context ) {
BasicBlock* Scope = BasicBlock::Create(Context, "recursive_case", FibFunction);
// create fib(x-1)
Value *Sub = BinaryOperator::CreateSub(ArgX, CONST_INT32( 1, Context ), "arg", Scope);
CallInst *CallFibX1 = CallInst::Create(FibFunction, Sub, "fibx1", Scope);
CallFibX1->setTailCall();
// create fib(x-2)
Sub = BinaryOperator::CreateSub(ArgX, CONST_INT32( 2, Context ), "arg", Scope);
CallInst *CallFibX2 = CallInst::Create(FibFunction, Sub, "fibx2", Scope);
CallFibX2->setTailCall();
// fib(x-1)+fib(x-2)
Value *Sum = BinaryOperator::CreateAdd(CallFibX1, CallFibX2, "addresult", Scope);
ReturnInst::Create(Context, Sum, Scope);
return Scope;
}
static Function *CreateFibFunction(Module *M, LLVMContext &Context) {
// Create the fib function and insert it into module M. This function is said
// to return an int and take an int parameter.
Function *FibFunction = cast<Function>(M->getOrInsertFunction("fib", Type::getInt32Ty(Context), Type::getInt32Ty(Context), (Type *)0));
BasicBlock *FunctionScope = BasicBlock::Create(Context, "EntryBlock", FibFunction);
// Get pointer to the integer argument (and name it 'x') of the fib function...
Argument *ArgX = FibFunction->arg_begin();
ArgX->setName("x");
// If x <= 2 we have the base case, otherwise the recursive case
Value *CondInst = new ICmpInst(*FunctionScope, ICmpInst::ICMP_SLE, ArgX, CONST_INT32( 2, Context ), "lt.2");
BranchInst::Create( CreateBaseCase( FibFunction, Context ), CreateRecursiveCase( FibFunction, ArgX, Context ), CondInst, FunctionScope);
return FibFunction;
}
int main(int argc, char **argv) {
int n = argc > 1 ? atol(argv[1]) : 24;
InitializeNativeTarget();
LLVMContext Context;
// Create some module to put our function into it.
OwningPtr<Module> M(new Module("test", Context));
// We are about to create the "fib" function:
Function *FibFunction = CreateFibFunction(M.get(), Context);
// Now we going to create JIT
std::string errStr;
ExecutionEngine *EE =
EngineBuilder(M.get())
.setErrorStr(&errStr)
.setEngineKind(EngineKind::JIT)
.create();
if (!EE) {
errs() << argv[0] << ": Failed to construct ExecutionEngine: " << errStr
<< "\n";
return 1;
}
errs() << "verifying... ";
if (verifyModule(*M)) {
errs() << argv[0] << ": Error constructing function!\n";
return 1;
}
errs() << "OK\n";
errs() << "We just constructed this LLVM module:\n\n---------\n" << *M;
errs() << "---------\nstarting fibonacci(" << n << ") with JIT...\n";
// Call the Fibonacci function with argument n:
std::vector<GenericValue> Args(1);
Args[0].IntVal = APInt(32, n);
GenericValue GV = EE->runFunction(FibFunction, Args);
// import result of execution
outs() << "Result: " << GV.IntVal << "\n";
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment