1//===--- examples/Fibonacci/fibonacci.cpp - An example use of the JIT -----===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This small program provides an example of how to build quickly a small module
10// with function Fibonacci and execute it with the JIT.
11//
12// The goal of this snippet is to create in the memory the LLVM module
13// consisting of one function as follow:
14//
15// int fib(int x) {
16// if(x<=2) return 1;
17// return fib(x-1)+fib(x-2);
18// }
19//
20// Once we have this, we compile the module via JIT, then execute the `fib'
21// function and return result to a driver, i.e. to a "host program".
22//
23//===----------------------------------------------------------------------===//
24
25#include "llvm/ADT/APInt.h"
26#include "llvm/IR/Verifier.h"
27#include "llvm/ExecutionEngine/ExecutionEngine.h"
28#include "llvm/ExecutionEngine/GenericValue.h"
29#include "llvm/ExecutionEngine/MCJIT.h"
30#include "llvm/IR/Argument.h"
31#include "llvm/IR/BasicBlock.h"
32#include "llvm/IR/Constants.h"
33#include "llvm/IR/DerivedTypes.h"
34#include "llvm/IR/Function.h"
35#include "llvm/IR/InstrTypes.h"
36#include "llvm/IR/Instructions.h"
37#include "llvm/IR/LLVMContext.h"
38#include "llvm/IR/Module.h"
39#include "llvm/IR/Type.h"
40#include "llvm/Support/Casting.h"
41#include "llvm/Support/TargetSelect.h"
42#include "llvm/Support/raw_ostream.h"
43#include <algorithm>
44#include <cstdlib>
45#include <memory>
46#include <string>
47#include <vector>
48
49using namespace llvm;
50
51static Function *CreateFibFunction(Module *M, LLVMContext &Context) {
52 // Create the fib function and insert it into module M. This function is said
53 // to return an int and take an int parameter.
54 FunctionType *FibFTy = FunctionType::get(Result: Type::getInt32Ty(C&: Context),
55 Params: {Type::getInt32Ty(C&: Context)}, isVarArg: false);
56 Function *FibF =
57 Function::Create(Ty: FibFTy, Linkage: Function::ExternalLinkage, N: "fib", M);
58
59 // Add a basic block to the function.
60 BasicBlock *BB = BasicBlock::Create(Context, Name: "EntryBlock", Parent: FibF);
61
62 // Get pointers to the constants.
63 Value *One = ConstantInt::get(Ty: Type::getInt32Ty(C&: Context), V: 1);
64 Value *Two = ConstantInt::get(Ty: Type::getInt32Ty(C&: Context), V: 2);
65
66 // Get pointer to the integer argument of the add1 function...
67 Argument *ArgX = &*FibF->arg_begin(); // Get the arg.
68 ArgX->setName("AnArg"); // Give it a nice symbolic name for fun.
69
70 // Create the true_block.
71 BasicBlock *RetBB = BasicBlock::Create(Context, Name: "return", Parent: FibF);
72 // Create an exit block.
73 BasicBlock* RecurseBB = BasicBlock::Create(Context, Name: "recurse", Parent: FibF);
74
75 // Create the "if (arg <= 2) goto exitbb"
76 Value *CondInst = new ICmpInst(BB, ICmpInst::ICMP_SLE, ArgX, Two, "cond");
77 BranchInst::Create(IfTrue: RetBB, IfFalse: RecurseBB, Cond: CondInst, InsertAtEnd: BB);
78
79 // Create: ret int 1
80 ReturnInst::Create(C&: Context, retVal: One, InsertAtEnd: RetBB);
81
82 // create fib(x-1)
83 Value *Sub = BinaryOperator::CreateSub(V1: ArgX, V2: One, Name: "arg", BB: RecurseBB);
84 CallInst *CallFibX1 = CallInst::Create(Func: FibF, Args: Sub, NameStr: "fibx1", InsertAtEnd: RecurseBB);
85 CallFibX1->setTailCall();
86
87 // create fib(x-2)
88 Sub = BinaryOperator::CreateSub(V1: ArgX, V2: Two, Name: "arg", BB: RecurseBB);
89 CallInst *CallFibX2 = CallInst::Create(Func: FibF, Args: Sub, NameStr: "fibx2", InsertAtEnd: RecurseBB);
90 CallFibX2->setTailCall();
91
92 // fib(x-1)+fib(x-2)
93 Value *Sum = BinaryOperator::CreateAdd(V1: CallFibX1, V2: CallFibX2,
94 Name: "addresult", BB: RecurseBB);
95
96 // Create the return instruction and add it to the basic block
97 ReturnInst::Create(C&: Context, retVal: Sum, InsertAtEnd: RecurseBB);
98
99 return FibF;
100}
101
102int main(int argc, char **argv) {
103 int n = argc > 1 ? atol(nptr: argv[1]) : 24;
104
105 InitializeNativeTarget();
106 InitializeNativeTargetAsmPrinter();
107 LLVMContext Context;
108
109 // Create some module to put our function into it.
110 std::unique_ptr<Module> Owner(new Module("test", Context));
111 Module *M = Owner.get();
112
113 // We are about to create the "fib" function:
114 Function *FibF = CreateFibFunction(M, Context);
115
116 // Now we going to create JIT
117 std::string errStr;
118 ExecutionEngine *EE =
119 EngineBuilder(std::move(Owner))
120 .setErrorStr(&errStr)
121 .create();
122
123 if (!EE) {
124 errs() << argv[0] << ": Failed to construct ExecutionEngine: " << errStr
125 << "\n";
126 return 1;
127 }
128
129 errs() << "verifying... ";
130 if (verifyModule(M: *M)) {
131 errs() << argv[0] << ": Error constructing function!\n";
132 return 1;
133 }
134
135 errs() << "OK\n";
136 errs() << "We just constructed this LLVM module:\n\n---------\n" << *M;
137 errs() << "---------\nstarting fibonacci(" << n << ") with JIT...\n";
138
139 // Call the Fibonacci function with argument n:
140 std::vector<GenericValue> Args(1);
141 Args[0].IntVal = APInt(32, n);
142 GenericValue GV = EE->runFunction(F: FibF, ArgValues: Args);
143
144 // import result of execution
145 outs() << "Result: " << GV.IntVal << "\n";
146
147 return 0;
148}
149

source code of llvm/examples/Fibonacci/fibonacci.cpp