Re: LUA?
Posted: Tue Jan 28, 2025 9:11 pm
did you know about LuaJIT — a Just-In-Time Compiler for Lua ?
http://luajit.org/luajit.html
http://luajit.org/luajit.html
This was the gist of using llvm to jit code however this was just a test of using llvm before I wrote the PB front end parserPBJim wrote: Tue Jan 28, 2025 8:46 pmI'm just trying to visualise how that would operate. Would that require the PB compiler, and say, GCC or appropriate, installing on the executing machine — i.e. the machine with the runtime compiled PB executable?idle wrote: Tue Jan 28, 2025 8:20 pm I wouldn't think so if it only created a dll and it was statically linked into the program.
A number of years ago I made an experimental pb jit compiler with llvm in pb so its doable it was very limited but as an exercise it worked.
And just as a wild idea, is the following sort of thing conceivable, or intended along these lines?Therefore, I've created a PB executable and the executable itself is responsible for building the code dynamically. Then having constructed the code, it can call JIT.Code: Select all
mycode.s = "OpenConsole()" + #CRLF$ mycode.s + "PrintN(" + chr(34) + "Hello world" + chr(34)) + #CRLF$ mycode.s + "Delay(1000)" + #CRLF$ Jit(mycode.s, etc. etc.)
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.9.pbi"
;dirty helper to read var arg strings
Procedure.s ReadVarString(*chr)
Protected strout.s,tmp.s
If *chr
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.
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("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)
EndProcedure
OpenConsole()
PrintN("enter the number of factors < 35")
n = Val(Input())
main(n)
PrintN("")
PrintN("Press enter to quit")
Input()
CloseConsole()
Just trying to see where it compiles — does your IncludeFile "llvm-2.9.pbi" invoke PB's compiler?idle wrote: Tue Jan 28, 2025 11:59 pm This was the gist of using llvm to jit code however this was just a test of using llvm before I wrote the PB front end parser
the code is run with LLVMRunFunction(EE, FibF, 1, @Arg)