summaryrefslogtreecommitdiff
path: root/examples/Fibonacci/fibonacci.cpp
blob: 776378dc1fa1852ce034dcf450be6abe07edb245 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
//===--- fibonacci.cpp - An example use of the JIT ----------------------===//
// 
//                     The LLVM Compiler Infrastructure
//
// This file was developed by Valery A. Khamenya and 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. 
//
// This simple example shows as well 30% speed up with LLVM 1.3
// in comparison to gcc 3.3.3 at AMD Athlon XP 1500+ .
//
// (Modified from HowToUseJIT.cpp and Stacker/lib/compiler/StackerCompiler.cpp)
// 
//===------------------------------------------------------------------------===
// Goal: 
//  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);
// }
// 
// then compile the module via JIT, then execute the `fib' 
// function and return result to a driver, i.e. to a "host program".
//

#include <iostream>

#include <llvm/Module.h>
#include <llvm/DerivedTypes.h>
#include <llvm/Constants.h>
#include <llvm/Instructions.h>
#include <llvm/ModuleProvider.h>
#include <llvm/Analysis/Verifier.h>
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/ExecutionEngine/GenericValue.h"


using namespace llvm;

int main(int argc, char**argv) {

  int n = argc > 1 ? atol(argv[1]) : 44;

  // Create some module to put our function into it.
  Module *M = new Module("test");


  // We are about to create the "fib" function:
  Function *FibF;

  {
    // first create type for the single argument of fib function: 
    // the type is 'int ()'
    std::vector<const Type*> ArgT(1);
    ArgT[0] = Type::IntTy;

    // now create full type of the "fib" function:
    FunctionType *FibT = FunctionType::get(Type::IntTy, // type of result
					   ArgT,
					   /*not vararg*/false);
 
    // Now create the fib function entry and 
    // insert this entry into module M
    // (By passing a module as the last parameter to the Function constructor,
    // it automatically gets appended to the Module.)
    FibF = new Function(FibT, 
			Function::ExternalLinkage, // maybe too much
			"fib", M);

    // Add a basic block to the function... (again, it automatically inserts
    // because of the last argument.)
    BasicBlock *BB = new BasicBlock("EntryBlock of fib function", FibF);
  
    // Get pointers to the constants ...
    Value *One = ConstantSInt::get(Type::IntTy, 1);
    Value *Two = ConstantSInt::get(Type::IntTy, 2);

    // Get pointers to the integer argument of the add1 function...
    assert(FibF->abegin() != FibF->aend()); // Make sure there's an arg

    Argument &ArgX = FibF->afront();  // Get the arg
    ArgX.setName("AnArg");            // Give it a nice symbolic name for fun.

    SetCondInst* CondInst 
      = new SetCondInst( Instruction::SetLE, 
			 &ArgX, Two );

    BB->getInstList().push_back(CondInst);

    // Create the true_block
    BasicBlock* true_bb = new BasicBlock("arg<=2");


    // Create the return instruction and add it 
    // to the basic block for true case:
    true_bb->getInstList().push_back(new ReturnInst(One));
      
    // Create an exit block
    BasicBlock* exit_bb = new BasicBlock("arg>2");
    
    {

      // create fib(x-1)
      CallInst* CallFibX1;
      {
	// Create the sub instruction... does not insert...
	Instruction *Sub 
	  = BinaryOperator::create(Instruction::Sub, &ArgX, One,
						"arg");       
       
	exit_bb->getInstList().push_back(Sub);

	CallFibX1 = new CallInst(FibF, Sub, "fib(x-1)");
	exit_bb->getInstList().push_back(CallFibX1);
	 
      }

      // create fib(x-2)
      CallInst* CallFibX2;
      {
	// Create the sub instruction... does not insert...
	Instruction * Sub
	  = BinaryOperator::create(Instruction::Sub, &ArgX, Two,
						"arg");

	exit_bb->getInstList().push_back(Sub);
	CallFibX2 = new CallInst(FibF, Sub, "fib(x-2)");
	exit_bb->getInstList().push_back(CallFibX2);
	  
      }

      // Create the add instruction... does not insert...
      Instruction *Add = 
	BinaryOperator::create(Instruction::Add, 
			       CallFibX1, CallFibX2, "addresult");
      
      // explicitly insert it into the basic block...
      exit_bb->getInstList().push_back(Add);
      
      // Create the return instruction and add it to the basic block
      exit_bb->getInstList().push_back(new ReturnInst(Add));      
    }

    // Create a branch on the SetCond
    BranchInst* br_inst = 
      new BranchInst( true_bb, exit_bb, CondInst );

    BB->getInstList().push_back( br_inst );
    FibF->getBasicBlockList().push_back(true_bb);
    FibF->getBasicBlockList().push_back(exit_bb);
  }

  // Now we going to create JIT 
  ExistingModuleProvider* MP = new ExistingModuleProvider(M);
  ExecutionEngine* EE = ExecutionEngine::create( MP, false );

  // Call the `foo' function with argument n:
  std::vector<GenericValue> args(1);
  args[0].IntVal = n;


  std::clog << "verifying... ";
  if (verifyModule(*M)) {
    std::cerr << argv[0]
	      << ": assembly parsed, but does not verify as correct!\n";
    return 1;
  }
  else 
    std::clog << "OK\n";


  std::clog << "We just constructed this LLVM module:\n\n---------\n" << *M;
  std::clog << "---------\nstarting fibonacci(" 
	    << n << ") with JIT...\n" << std::flush;

  GenericValue gv = EE->runFunction(FibF, args);

  // import result of execution:
  std::cout << "Result: " << gv.IntVal << std:: endl;

  return 0;
}