JIT API example (fibonacci)

Hi LLVMers,

  the example attached I have used to prove that JIT and some visible
  optimizations are really invoked.

  Proved OK. I got 30% speed-up in comparison to gcc 3.3.3
  on my Athlon XP 1500.

  Nice.

  P.S. guys, no fears, I don't plan to flood the cvs repository
  with my "brilliant" examples :wink:

fibonacci.cpp (5.52 KB)

Valery,

That's pretty cute actually. Do you want this "brilliant" :slight_smile: example in the cvs repository? I'd be happy to put it in.

Reid.

Valery A.Khamenya wrote:

That's pretty cute actually. Do you want this "brilliant" :slight_smile: example in the cvs
repository? I'd be happy to put it in.

Here's an idea: how about we take the ModuleMaker, Valery's previous
example, and this one and put them all in one "small examples" project?

-Chris

Valery A.Khamenya wrote:

> Hi LLVMers,
>
> the example attached I have used to prove that JIT and some visible
> optimizations are really invoked.
>
> Proved OK. I got 30% speed-up in comparison to gcc 3.3.3
> on my Athlon XP 1500.
>
> Nice.
>
> P.S. guys, no fears, I don't plan to flood the cvs repository
> with my "brilliant" examples :wink:
>
> ---
> Valery A.Khamenya
>
>
>
>
> ------------------------------------------------------------------------
>
> //===--- 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;
> }
>
>
> ------------------------------------------------------------------------
>
> _______________________________________________
> LLVM Developers mailing list
> LLVMdev@cs.uiuc.edu http://llvm.cs.uiuc.edu
> http://mail.cs.uiuc.edu/mailman/listinfo/llvmdev

_______________________________________________
LLVM Developers mailing list
LLVMdev@cs.uiuc.edu http://llvm.cs.uiuc.edu
http://mail.cs.uiuc.edu/mailman/listinfo/llvmdev

-Chris

Chris Lattner wrote:

On second thought, the makefiles don't (easily) allow this do they? You can only build one program per directory. Were you suggesting that you wanted me to move the entire directories under a "small examples" directory?

Reid.

Chris Lattner wrote:

Hey! That was MY idea .. :slight_smile:
(I was just about to suggest the same thing)

heh.

I'll "make it so". Can you move the MM and JIT ,v files after I cvs rm them ?

Sure, just email me the specifics of what you want :slight_smile:

-Chris

Cool! Hey Valery, before we add this to the CVS repo, can you take a look
at some of the changes I made to your HowToUseJIT example and use them to
simplify this example too?

For example, instead of code like this:

    // 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 Functionconstructor,
    // it automatically gets appended to the Module.)
    FibF = new Function(FibT,
                        Function::ExternalLinkage, // maybe too much
                        "fib", M);

You can do this same thing with code like this:

  Function *FibF = M->getOrInsertFunction("fib", Type::IntTy, Type::IntTy, 0);

Thanks! I really like the idea of having several small and simple
examples that show different API's off :slight_smile:

-Chris

Also instead of this:

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

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

you can write it as:

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

Ditto for all other instructions.

On second thought, the makefiles don't (easily) allow this do they? You can
only build one program per directory. Were you suggesting that you wanted me to
move the entire directories under a "small examples" directory?

You're right. The simples way to do this would be to have:
  projects/
           SmallExamples/
                         ModuleMaker/
                         HowToUseTheJIT/
                         FibBuilder/

etc. Each subsubdir would have a makefile and a .cpp file.

-Chris

Chris Lattner wrote:

>
>
>>That's pretty cute actually. Do you want this "brilliant" :slight_smile: example in the cvs
>>repository? I'd be happy to put it in.
>
>
> Here's an idea: how about we take the ModuleMaker, Valery's previous
> example, and this one and put them all in one "small examples" project?
>
> -Chris
>
>
>>Valery A.Khamenya wrote:
>>
>>
>>>Hi LLVMers,
>>>
>>> the example attached I have used to prove that JIT and some visible
>>> optimizations are really invoked.
>>>
>>> Proved OK. I got 30% speed-up in comparison to gcc 3.3.3
>>> on my Athlon XP 1500.
>>>
>>> Nice.
>>>
>>> P.S. guys, no fears, I don't plan to flood the cvs repository
>>> with my "brilliant" examples :wink:
>>>
>>>---
>>>Valery A.Khamenya
>>>
>>>
>>>
>>>
>>>------------------------------------------------------------------------
>>>
>>>//===--- 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;
>>>}
>>>
>>>
>>>------------------------------------------------------------------------
>>>
>>>_______________________________________________
>>>LLVM Developers mailing list
>>>LLVMdev@cs.uiuc.edu http://llvm.cs.uiuc.edu
>>>http://mail.cs.uiuc.edu/mailman/listinfo/llvmdev
>>
>>_______________________________________________
>>LLVM Developers mailing list
>>LLVMdev@cs.uiuc.edu http://llvm.cs.uiuc.edu
>>http://mail.cs.uiuc.edu/mailman/listinfo/llvmdev
>>
>
>
> -Chris
>

_______________________________________________
LLVM Developers mailing list
LLVMdev@cs.uiuc.edu http://llvm.cs.uiuc.edu
http://mail.cs.uiuc.edu/mailman/listinfo/llvmdev

-Chris

Okay. I'll send you a ,v copying script when I'm done.

On second thought, the makefiles don't (easily) allow this do they? You can
only build one program per directory.

BTW, i guess as well, that only .o and .lo files are generated.
For those similar to me, it is more pleasant to get usual
native executables too.