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 | |
49 | using namespace llvm; |
50 | |
51 | static 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 | |
102 | int 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 | |