I tried to do an iterative Fibonacci and I'm not sure what the problem is.
but it only executes the loops once and the procedure always returns 2 for input larger than 2
Here's the out put of the function, it's easy enough to follow and looks like it should work
Also there is some really strange interaction when llvm generates and error message
it causes a double call so you end up with an IMA as the pointer is either 0 or the offset on the second call
obviously there's something wrong with the way it's being handled but I can't think of how to fix it
Code: Select all
; Fibonacci function executed by JIT.
; Origonal c example from llvm fibonaci example
;
; Author idle - a hack To see how llvm works
; Shows How to create a llvm module in memory
; Build a Function
; Create a Function optimizer
; Dump the module To byte code
; Load the byte code file and produce native object code
;
; The fib function calulates the number of factors
;
; Procedure fib(argx.i)
; If argx<=2
; ProcedureReturn 1
; Else
; ProcedureReturn fib(argx-1)+fib(argx-2)
; EndIf
; EndProcedure
;
; 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".
;===----------------------------------------------------------------------===''
IncludeFile "llvm-2.8.pbi"
;dirty helper to read var arg strings
Procedure.s ReadVarString(*chr)
Protected strout.s,tmp.s
Protected *mem
*mem = *chr
If *mem > 64000 ;dirty but *chr gets nuked to 0 or ct offest
Repeat
tmp = PeekS(*chr+ct)
If tmp <> ""
strout+tmp+#LF$
Else
Break
EndIf
ct+Len(tmp)+1
ForEver
EndIf
ProcedureReturn strout
EndProcedure
Procedure fibPB(argx.i)
If argx<=2
ProcedureReturn 1
Else
ProcedureReturn fibPB(argx-1)+fibPB(argx-2)
EndIf
EndProcedure
Procedure fibPB2(argx.i)
Protected a,b,c
If argx <= 2
ProcedureReturn 1
Else
a = 1
b = 1
While argx > 2
c = a + b;
b = a;
a = c;
argx-1;
Wend
ProcedureReturn c
EndIf
EndProcedure
Procedure CreateFibFunction(M.i,Context.i)
Protected FunctionReturnType
Protected IntType
;Procedure.i fib(x.i)
;function only uses and int type, create an int type.
intType = LLVMInt32Type()
;Function returns an int And takes an int as the only parameter.
FunctionReturnType = LLVMFunctionType(IntType,@IntType,1,0)
;Create the fib function definition And insert it into the module M.
Fib2 = LLVMAddFunction(M, "fib2",FunctionReturnType)
;Set the function call convention to FastCall so it can utilize tail call
LLVMSetFunctionCallConv(Fib2,#LLVMFastCallConv)
;Add a basic block To the function.
BB = LLVMAppendBasicBlockInContext(Context, Fib2, "EntryBlock")
;Get a pointer to the ArgX.i and add to function...
ArgX = LLVMGetFirstParam(Fib2) ; Get the arg.
LLVMSetValueName(ArgX, "ArgX") ; Give it a symbolic name.
;When using the C bindings, you have to use a BuilderRef To create any instructions.
Builder = LLVMCreateBuilderInContext(Context)
;Set the builder to insert at the first BasicBlock.
LLVMPositionBuilderAtEnd(Builder, BB)
A = LLVMBuildAlloca(Builder, IntType,"A");
B = LLVMBuildAlloca(Builder, IntType,"B");
C = LLVMBuildAlloca(Builder, IntType,"C");
D = LLVMBuildAlloca(Builder, IntType,"D");
One = LLVMConstInt(IntType, 1, 0)
LLVMBuildStore(Builder,One,A);
LLVMBuildStore(Builder,One,B);
Zero = LLVMConstInt(IntType, 0, 0)
LLVMBuildStore(Builder,Zero,C)
LLVMBuildStore(Builder,ArgX,D)
;Create and build the conditional branch "if argX <= 2"
IFBB = LLVMAppendBasicBlockInContext(Context, Fib2, "IF")
;Create two blocks for the Branches If argx<=2 : RetBB : else : RecurseBB
ElseBB = LLVMAppendBasicBlockInContext(Context, Fib2, "Else")
Two = LLVMConstInt(IntType, 2, 0)
CondInst = LLVMBuildICmp(Builder, #LLVMIntSLE, ArgX,Two, "cond")
LLVMBuildCondBr(Builder, CondInst, IFBB, ElseBB)
LLVMPositionBuilderAtEnd(Builder, IFBB)
LLVMBuildRet(Builder,One)
LLVMPositionBuilderAtEnd(Builder, ElseBB)
WhileBB = LLVMAppendBasicBlockInContext(Context, Fib2, "while")
EWhileBB = LLVMAppendBasicBlockInContext(Context, Fib2, "ewhile")
PD = LLVMBuildLoad(Builder,D,"PD");
CondInst1 = LLVMBuildICmp(Builder, #LLVMIntSGE, PD, Two, "cond")
LLVMBuildCondBr(Builder, CondInst1, WhileBB, EWhileBB)
LLVMPositionBuilderAtEnd(Builder, WhileBB)
PA = LLVMBuildLoad(Builder,A,"pA");
PB = LLVMBuildLoad(Builder,B,"pB");
AddAB = LLVMBuildAdd(Builder,PA,PB,"addab")
LLVMBuildStore(Builder,AddAB,C);
LLVMBuildStore(Builder,PA,B);
LLVMBuildStore(Builder,AddAB,A);
sub = LLVMBuildSub(Builder,PD,One,"sub")
LLVMBuildStore(Builder,sub,D);
jump = LLVMBuildBr(Builder,ElseBB);
LLVMPositionBuilderAtEnd(Builder, EWhileBB)
;Create the return instruction And add it To the basic block
CR = LLVMBuildLoad(Builder,C,"CR");
LLVMBuildRet(Builder, CR)
;Don't forget to free the builder.
LLVMDisposeBuilder(Builder)
;Return the function ref
ProcedureReturn Fib2
EndProcedure
Procedure CreateFibFunction1(M.i,Context.i)
Protected FunctionReturnType
Protected IntType
;Procedure.i fib(x.i)
;function only uses and int type, create an int type.
intType = LLVMInt32Type()
;Function returns an int And takes an int as the only parameter.
FunctionReturnType = LLVMFunctionType(IntType,@IntType,1,0)
;Create the fib function definition And insert it into the module M.
FibF = LLVMAddFunction(M, "fib",FunctionReturnType)
;Set the function call convention to FastCall so it can utilize tail call
LLVMSetFunctionCallConv(FibF,#LLVMFastCallConv)
;Add a basic block To the function.
BB = LLVMAppendBasicBlockInContext(Context, FibF, "EntryBlock")
;Make the Constants returns a pointer to the constant.
; fib(argx->>"1"<<)+fib(argx->>"2"<<)
One = LLVMConstInt(IntType, 1, 0)
Two = LLVMConstInt(IntType, 2, 0)
;Get a pointer to the ArgX.i and add to function...
ArgX = LLVMGetFirstParam(FibF) ; Get the arg.
LLVMSetValueName(ArgX, "ArgX") ; Give it a symbolic name.
;When using the C bindings, you have to use a BuilderRef To create any instructions.
Builder = LLVMCreateBuilderInContext(Context)
;Set the builder to insert at the first BasicBlock.
LLVMPositionBuilderAtEnd(Builder, BB)
;Create and build the conditional branch "if argX <= 2"
CondInst = LLVMBuildICmp(Builder, #LLVMIntSLE, ArgX, Two, "cond")
;Create two blocks for the Branches If argx<=2 : RetBB : else : RecurseBB
RetBB = LLVMAppendBasicBlockInContext(Context, FibF, "return")
RecurseBB = LLVMAppendBasicBlockInContext(Context, FibF, "recurse")
LLVMBuildCondBr(Builder, CondInst, RetBB, RecurseBB)
;Create: ProcedureReturn 1
LLVMPositionBuilderAtEnd(Builder, RetBB)
LLVMBuildRet(Builder,One)
;Create fib(x-1)
LLVMPositionBuilderAtEnd(Builder, RecurseBB)
Subtr = LLVMBuildSub(Builder, ArgX, One, "arg")
CallFibX1 = LLVMBuildCall(Builder, FibF, @Subtr, 1, "fibx1")
;LLVMSetTailCall(CallFibX1, 1) ;let the optimzer deal with it
;Create fib(x-2)
Subtr = LLVMBuildSub(Builder, ArgX, Two, "arg")
CallFibX2 = LLVMBuildCall(Builder, FibF, @Subtr, 1, "fibx2")
;LLVMSetTailCall(CallFibX2, 1) ;let the optimzer deal with it
;fib(x-1)+fib(x-2)
Sum = LLVMBuildAdd(Builder, CallFibX1, CallFibX2, "addresult")
;Create the return instruction And add it To the basic block
LLVMBuildRet(Builder, Sum)
;Don't forget to free the builder.
LLVMDisposeBuilder(Builder)
;Return the function ref
ProcedureReturn FibF
EndProcedure
Procedure main(n)
Protected errStr.s
Protected EE.i
LLVMLinkInJIT()
Context = LLVMGetGlobalContext()
;Create a module for our function.
M = LLVMModuleCreateWithNameInContext("test fib", Context)
;Create a pass manager optimizer for our funtions
PM = LLVMCreateFunctionPassManagerForModule(M);
;add tail call elimination parse to it
;LLVMAddTailCallEliminationPass(PM);
LLVMInitializeFunctionPassManager(PM);
;Create the Fib function in the Module and Context
FibF = CreateFibFunction(M, Context)
;Run function optimizer
If LLVMRunFunctionPassManager(PM,FibF);
PrintN("Optimized Function")
EndIf
LLVMFinalizeFunctionPassManager(PM)
LLVMDisposePassManager(PM);
;Create JIT engine execution
If LLVMCreateExecutionEngineForModule(@EE, M, pStr)
PrintN(ReadVarString(pStr))
LLVMDisposeMessage(pStr)
Input()
End
EndIf
;read the target data
TD =LLVMGetExecutionEngineTargetData(EE);
PrintN(ReadVarString(LLVMCopyStringRepOfTargetData(TD)))
;LLVMDisposeTargetData(TD); locks up for some reason
;Verify module
PrintN("verifying module")
If LLVMVerifyModule(M, #LLVMPrintMessageAction,pStr)
PrintN("Error constructing function!")
PrintN(ReadVarString(pstr))
LLVMDisposeMessage(pStr)
Input()
End
EndIf
PrintN(ReadVarString(LLVMDumpModule(M)));
PrintN("OK")
PrintN("Test module succeded")
PrintN("Run fibonacci(" + Str(n) + ") in JIT");
;Call the Fibonacci function With argument n:
Arg = LLVMCreateGenericValueOfInt(LLVMInt32Type(), n, 1)
st = ElapsedMilliseconds()
GV = LLVMRunFunction(EE, FibF, 1, @Arg)
et = ElapsedMilliseconds()
;convert the result
PrintN("Jit Result: ")
PrintN(Str(LLVMGenericValueToInt(GV, 1)))
PrintN("took " + Str(et-st))
;call same in PB
st = ElapsedMilliseconds()
res = fibpb(n)
et = ElapsedMilliseconds()
PrintN("PB Result: ")
PrintN(Str(res))
PrintN("took " + Str(et-st))
;call same in PB
st = ElapsedMilliseconds()
res2 = fibpb2(n)
et = ElapsedMilliseconds()
PrintN("PB Result 2: ")
PrintN(Str(res2))
PrintN("took " + Str(et-st))
;Dump the jit Bitcode to file
LLVMWriteBitcodeToFile(M,"fib.bc");
PrintN("")
PrintN("Dumped bytecode to 'fib.bc'")
;clean up
LLVMDisposeGenericValue(Arg)
LLVMDisposeGenericValue(GV)
LLVMDisposeExecutionEngine(EE)
;Create native elf from the saved bc file
lto = lto_module_create("fib.bc");
gen = lto_codegen_create();
lto_codegen_add_module(gen,lto);
*mem = lto_codegen_compile(gen,@length.i);
If length
fil = CreateFile(#PB_Any,"fib.elf")
WriteData(fil,*mem,length)
CloseFile(fil)
PrintN("")
PrintN("Created native code to 'fib.elf'")
EndIf
lto_codegen_dispose(gen);
EndProcedure
OpenConsole()
PrintN("enter the number of factors < 35")
n = Val(Input())
main(n)
PrintN("")
PrintN("Press enter to quit")
Input()
CloseConsole()