issue #180 removing llvm lua api
parent
7834343893
commit
ea5e34f447
@ -1,8 +0,0 @@
|
||||
These are examples using the Lua LLVM bindings.
|
||||
|
||||
``helloworld.lua``
|
||||
This illustrates creating a Lua callable C function that prints hello world.
|
||||
``fib.lua``
|
||||
This illustrates implementing a fibonacci sequence in LLVM using Lua.
|
||||
|
||||
|
@ -1,107 +0,0 @@
|
||||
-- ensure that LLVM bindings are available
|
||||
assert(llvm)
|
||||
|
||||
-- Get the LLVM context - right now this is the
|
||||
-- global context
|
||||
context = llvm.context()
|
||||
assert(ravitype(context) == "LLVMcontext")
|
||||
|
||||
-- The bindings provide a number of predefined types that
|
||||
-- are Lua specific plus some standard C types such as 'int',
|
||||
-- 'double', 'int64_t', etc.
|
||||
types = context:types()
|
||||
print 'Listing types'
|
||||
for k,v in pairs(types) do
|
||||
print('\t', k, ravitype(v))
|
||||
llvm.dump(v)
|
||||
end
|
||||
|
||||
-- ***************************************************\
|
||||
-- Test creating a struct type
|
||||
-- Just as an exercise create a struct type
|
||||
-- Initially we have an opaque struct
|
||||
gcobject = context:structtype("GCObject")
|
||||
assert(ravitype(gcobject) == "LLVMstructtype")
|
||||
|
||||
-- Create pointer to GCObject
|
||||
gcobject_p = context:pointertype(gcobject)
|
||||
assert(ravitype(gcobject_p) == "LLVMpointertype")
|
||||
|
||||
-- Add the members of the struct
|
||||
-- Following demonstrates the use of predefined Lua types
|
||||
gcobject:setbody {gcobject_p, types.lu_byte, types.lu_byte}
|
||||
|
||||
-- Display structure of gcobject
|
||||
llvm.dump(gcobject)
|
||||
|
||||
-- ****************************************************/
|
||||
|
||||
-- ****************************************************\
|
||||
-- Test building a Lua C function without writing C code!
|
||||
--
|
||||
-- Create a lua_CFunction instance
|
||||
-- At this stage the function will get a module and
|
||||
-- execution engine but no body
|
||||
myfunc = context:lua_CFunction("myfunc")
|
||||
assert(ravitype(myfunc) == "LLVMmainfunction")
|
||||
|
||||
-- Get a new IRBuilder intance
|
||||
-- this will be garbage collected by Lua
|
||||
irbuilder = context:irbuilder()
|
||||
assert(ravitype(irbuilder) == "LLVMirbuilder")
|
||||
|
||||
-- Create a basic block
|
||||
block = context:basicblock("entry")
|
||||
-- Add it to the end of the function
|
||||
myfunc:appendblock(block)
|
||||
-- Set this as the next instruction point
|
||||
irbuilder:setinsertpoint(block)
|
||||
|
||||
-----------------------------------------------
|
||||
-- Test calling a predefined extern function
|
||||
-- Get printf decl
|
||||
-----------------------------------------------
|
||||
printf = myfunc:extern("printf")
|
||||
assert(ravitype(printf) == "LLVMconstant")
|
||||
|
||||
luaL_checklstring = myfunc:extern("luaL_checklstring")
|
||||
assert(ravitype(luaL_checklstring) == "LLVMconstant")
|
||||
|
||||
hellostr = irbuilder:stringconstant("hello world!\n")
|
||||
irbuilder:call(printf, { hellostr })
|
||||
|
||||
-------------------------------------------------
|
||||
-- Test calling a random function
|
||||
-------------------------------------------------
|
||||
puts_type = context:functiontype(types.int, {types.pchar}, {vararg=false})
|
||||
assert(ravitype(puts_type) == "LLVMfunctiontype")
|
||||
|
||||
-- Declare extern puts()
|
||||
puts = myfunc:extern("puts", puts_type);
|
||||
assert(ravitype(puts) == "LLVMconstant")
|
||||
|
||||
-- Get the L parameter of myfunc
|
||||
L = myfunc:arg(1)
|
||||
|
||||
-- get the first argument as a string
|
||||
str = irbuilder:call(luaL_checklstring, {L, context:intconstant(1),
|
||||
context:nullconstant(types.psize_t)} )
|
||||
|
||||
-- Call puts
|
||||
irbuilder:call(puts, { str })
|
||||
|
||||
-- add CreateRet(0)
|
||||
inst = irbuilder:ret(context:intconstant(0))
|
||||
assert(ravitype(inst) == "LLVMinstruction")
|
||||
-- **************************************************/
|
||||
|
||||
-- what did we get?
|
||||
llvm.dump(myfunc)
|
||||
|
||||
-- JIT compile the function
|
||||
-- returns a C Closure
|
||||
runnable = myfunc:compile()
|
||||
|
||||
print('Type of compiled function is', type(runnable))
|
||||
assert(not runnable('ok\n'))
|
||||
|
@ -1,141 +0,0 @@
|
||||
-- This program demonstrates creating a
|
||||
-- recursive fibonacci calc function in LLVM
|
||||
-- Example based upon
|
||||
-- https://llvm.org/svn/llvm-project/llvm/trunk/examples/Fibonacci/fibonacci.cpp
|
||||
|
||||
|
||||
-- ensure that LLVM bindings are available
|
||||
assert(llvm)
|
||||
|
||||
|
||||
-- Generate the fibonacci function
|
||||
local function makefib(context, module, types)
|
||||
|
||||
-- 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);
|
||||
-- }
|
||||
--
|
||||
|
||||
-- Create the fib function and insert it into module M. This function is said
|
||||
-- to return an int and take an int parameter.
|
||||
local fibtype = context:functiontype(types.int, {types.int})
|
||||
local FibF = module:newfunction("fib", fibtype)
|
||||
|
||||
-- Get a new IRBuilder intance
|
||||
-- this will be garbage collected by Lua
|
||||
local ir = context:irbuilder()
|
||||
|
||||
-- Add a basic block to the function.
|
||||
local BB = context:basicblock("EntryBlock");
|
||||
FibF:appendblock(BB)
|
||||
ir:setinsertpoint(BB)
|
||||
|
||||
-- Get pointers to the constants.
|
||||
local One = context:intconstant(1);
|
||||
local Two = context:intconstant(2);
|
||||
|
||||
-- Get pointer to the integer argument of the add1 function...
|
||||
local ArgX = FibF:arg(1); -- Get the arg.
|
||||
|
||||
-- Create the true_block.
|
||||
local RetBB = context:basicblock("return");
|
||||
FibF:appendblock(RetBB)
|
||||
|
||||
-- Create an exit block.
|
||||
local RecurseBB = context:basicblock("recurse");
|
||||
FibF:appendblock(RecurseBB)
|
||||
|
||||
-- Create the "if (arg <= 2) goto exitbb"
|
||||
local CondInst = ir:icmpsle(ArgX, Two);
|
||||
ir:condbr(CondInst, RetBB, RecurseBB);
|
||||
|
||||
ir:setinsertpoint(RetBB)
|
||||
-- Create: ret int 1
|
||||
ir:ret(One);
|
||||
|
||||
-- create fib(x-1)
|
||||
ir:setinsertpoint(RecurseBB)
|
||||
local Sub = ir:nswsub(ArgX, One);
|
||||
local CallFibX1 = ir:call(FibF, {Sub}, {tailcall=true});
|
||||
|
||||
-- create fib(x-2)
|
||||
Sub = ir:nswsub(ArgX, Two);
|
||||
local CallFibX2 = ir:call(FibF, {Sub}, {tailcall=true});
|
||||
|
||||
-- fib(x-1)+fib(x-2)
|
||||
local Sum = ir:nswadd(CallFibX1, CallFibX2);
|
||||
|
||||
-- Create the return instruction and add it to the basic block
|
||||
ir:ret(Sum);
|
||||
|
||||
return FibF
|
||||
end
|
||||
|
||||
-- Get the LLVM context - right now this is the
|
||||
-- global context
|
||||
local context = llvm.context()
|
||||
|
||||
-- The bindings provide a number of predefined types that
|
||||
-- are Lua specific plus some standard C types such as 'int',
|
||||
-- 'double', 'int64_t', etc.
|
||||
local types = context:types()
|
||||
|
||||
-- Create a lua_CFunction instance
|
||||
-- At this stage the function will get a module and
|
||||
-- execution engine but no body
|
||||
local mainfunc = context:lua_CFunction("demofib")
|
||||
|
||||
-- Get hold of the module
|
||||
-- as we will create the fib function as an
|
||||
-- iternal function
|
||||
local module = mainfunc:module()
|
||||
|
||||
-- The actual fibonacci function is an internal
|
||||
-- function so that it is pure native function
|
||||
local fib = makefib(context, module, types)
|
||||
|
||||
-- Get a new IRBuilder
|
||||
local ir = context:irbuilder()
|
||||
|
||||
-- Our main Lua function has only one block
|
||||
local BB = context:basicblock("entry")
|
||||
mainfunc:appendblock(BB)
|
||||
ir:setinsertpoint(BB)
|
||||
|
||||
-- Declare prototypes
|
||||
local luaL_checkinteger = mainfunc:extern("luaL_checkinteger")
|
||||
local lua_pushinteger = mainfunc:extern("lua_pushinteger")
|
||||
|
||||
-- Get lua_State*
|
||||
local L = mainfunc:arg(1)
|
||||
|
||||
-- We are expecting one integer parameter
|
||||
local intparam = ir:call(luaL_checkinteger, {L, context:intconstant(1)})
|
||||
-- cast from 64 to 32 bit
|
||||
intparam = ir:truncorbitcast(intparam, types.int)
|
||||
|
||||
-- Call the fib calculator
|
||||
local result = ir:call(fib, {intparam})
|
||||
|
||||
-- Extend from 32 to 64 bit
|
||||
result = ir:zext(result, types.lua_Integer)
|
||||
|
||||
-- Push the final integer result
|
||||
ir:call(lua_pushinteger, {L, result})
|
||||
|
||||
-- Return 1
|
||||
ir:ret(context:intconstant(1))
|
||||
|
||||
---- We are done! ---
|
||||
|
||||
-- Dump the module for info
|
||||
module:dump()
|
||||
|
||||
-- compile the Lua callable function
|
||||
local runnable = mainfunc:compile()
|
||||
assert(runnable(11) == 89)
|
||||
print 'Ok'
|
@ -1,63 +0,0 @@
|
||||
-- This small demo creates a compiled function
|
||||
-- takes a string parameter and calls puts() to
|
||||
-- print this
|
||||
|
||||
-- ensure that LLVM bindings are available
|
||||
assert(llvm)
|
||||
|
||||
-- Get the LLVM context - right now this is the
|
||||
-- global context
|
||||
context = llvm.context()
|
||||
|
||||
-- The bindings provide a number of predefined types that
|
||||
-- are Lua specific plus some standard C types such as 'int',
|
||||
-- 'double', 'int64_t', etc.
|
||||
types = context:types()
|
||||
|
||||
-- Create a lua_CFunction instance
|
||||
-- At this stage the function will get a module and
|
||||
-- execution engine but no body
|
||||
myfunc = context:lua_CFunction("myfunc")
|
||||
|
||||
-- Get a new IRBuilder intance
|
||||
-- this will be garbage collected by Lua
|
||||
irbuilder = context:irbuilder()
|
||||
|
||||
-- Create a basic block
|
||||
block = context:basicblock("entry")
|
||||
-- Add it to the end of the function
|
||||
myfunc:appendblock(block)
|
||||
-- Set this as the next instruction point
|
||||
irbuilder:setinsertpoint(block)
|
||||
|
||||
-- get declaration for luaL_checklstring
|
||||
luaL_checklstring = myfunc:extern("luaL_checklstring")
|
||||
|
||||
-- Get the L parameter of myfunc
|
||||
L = myfunc:arg(1)
|
||||
|
||||
-- get the first argument as a string
|
||||
str = irbuilder:call(luaL_checklstring,
|
||||
{L, context:intconstant(1),
|
||||
context:nullconstant(types.psize_t)})
|
||||
|
||||
-- declare puts
|
||||
puts_type = context:functiontype(types.int, {types.pchar})
|
||||
puts = myfunc:extern("puts", puts_type);
|
||||
|
||||
-- Call puts
|
||||
irbuilder:call(puts, {str})
|
||||
|
||||
-- add CreateRet(0)
|
||||
irbuilder:ret(context:intconstant(0))
|
||||
-- **************************************************/
|
||||
|
||||
-- what did we get?
|
||||
llvm.dump(myfunc)
|
||||
|
||||
-- JIT compile the function
|
||||
-- returns a C Closure
|
||||
runnable = myfunc:compile()
|
||||
|
||||
assert(not runnable('hello world\n'))
|
||||
|
@ -1,244 +0,0 @@
|
||||
LLVM Bindings for Lua/Ravi
|
||||
==========================
|
||||
|
||||
As part of the Ravi Programming Language, it is my intention to provide a Lua 5.3 compatible LLVM binding.
|
||||
This will allow Lua programmers to write their own JIT compilers in Lua!
|
||||
|
||||
Right now this is in early development so there is no documentation. But the Lua programs here
|
||||
demonstrate the features available to date.
|
||||
|
||||
LLVM Modules and Execution Engines
|
||||
----------------------------------
|
||||
One of the complexities of LLVM is the handling of modules and execution engines in a JIT environment. In Ravi I made the simple decision that each Lua function would get its own module and EE. This allows the function to be
|
||||
garbage collected as normal and release the associated module and EE. One of
|
||||
the things that is possible but not yet implemented is releasing the module
|
||||
and EE early; this requires implementing a custom memory manager (issue #48).
|
||||
|
||||
To mimic the Ravi model, the LLVM bindings provide a shortcut to setup
|
||||
an LLVM module and execution engine for a Lua C function. The following example
|
||||
illustrates::
|
||||
|
||||
-- Get the LLVM context - right now this is the
|
||||
-- global context
|
||||
local context = llvm.context()
|
||||
|
||||
-- Create a lua_CFunction instance
|
||||
-- At this stage the function will get a module and
|
||||
-- execution engine but no body
|
||||
local mainfunc = context:lua_CFunction("demo")
|
||||
|
||||
Above creates an ``llvm::Function`` instance within a new module. An EE is
|
||||
automatically attached. You can get hold of the module as shown below::
|
||||
|
||||
-- Get hold of the module
|
||||
local module = mainfunc:module()
|
||||
|
||||
Other native functions may be created within the same module as normal. However
|
||||
note that once the Lua function is compiled then no further updates to the
|
||||
module are possible.
|
||||
|
||||
The model I recommend when using this feature is to create one exported
|
||||
Lua C function in the module, with several private 'internal' supporting functions within the module.
|
||||
|
||||
Creating Modules and Execution Engines
|
||||
--------------------------------------
|
||||
The LLVM api for these functions are not exposed yet.
|
||||
|
||||
Examples
|
||||
--------
|
||||
For examples that illustrate the bindings please visit the `llvmbindings folder <https://github.com/dibyendumajumdar/ravi/tree/master/llvmbinding>`_ in the repository.
|
||||
|
||||
Type Hierarchy
|
||||
--------------
|
||||
The bindings provide a number of Lua types::
|
||||
|
||||
+ LLVMcontext
|
||||
+ LLVMfunction
|
||||
+ LLVMmainfunction
|
||||
+ LLVMmodule
|
||||
+ LLVMtype
|
||||
+ LLVMstructtype
|
||||
+ LLVMpointertype
|
||||
+ LLVMfunctiontype
|
||||
+ LLVMvalue
|
||||
+ LLVMinstruction
|
||||
+ LLVMconstant
|
||||
+ LLVMphinode
|
||||
+ LLVMirbuilder
|
||||
+ LLVMbasicblock
|
||||
|
||||
|
||||
Available Bindings
|
||||
------------------
|
||||
The following table lists the Lua LLVM api functions available.
|
||||
|
||||
+----------------------------------------------------------------------------------------------+
|
||||
| Lua LLVM API |
|
||||
+==============================================================================================+
|
||||
| ``llvm.context() -> LLVMcontext`` |
|
||||
| Returns global llvm::Context |
|
||||
+----------------------------------------------------------------------------------------------+
|
||||
| **LLVMcontext methods** |
|
||||
+----------------------------------------------------------------------------------------------+
|
||||
| ``lua_CFunction(name) -> LLVMmainfunction`` |
|
||||
| Creates an llvm::Function within a new llvm::Module; and associates an |
|
||||
| llvm::ExecutionEngine with the module |
|
||||
| ``types() -> table of predefined type bindings`` |
|
||||
| Returns a table of predefined LLVM type bindings |
|
||||
| ``structtype(name) -> LLVMstructtype`` |
|
||||
| Opaque struct type; body can be added |
|
||||
| ``pointertype(type) -> LLVMpointertype`` |
|
||||
| Given a type returns a pointertype |
|
||||
| ``functiontype(return_type, {argtypes}, {options}) -> LLVMfunctiontype`` |
|
||||
| Creates a function type with specified return type, argument types. Takes the option |
|
||||
| 'vararg' which is false by default. |
|
||||
| ``basicblock(name) -> LLVMbasicblock`` |
|
||||
| Create a basic block |
|
||||
| ``intconstant(intgervalue) -> LLVMvalue`` |
|
||||
| Returns an integer constant value |
|
||||
| ``nullconstant(pointertype) -> LLVMvalue`` |
|
||||
| Returns a NULL constant of specified pointertype |
|
||||
+----------------------------------------------------------------------------------------------+
|
||||
| **LLVMstructtype methods** |
|
||||
+----------------------------------------------------------------------------------------------+
|
||||
| ``setbody({types})`` |
|
||||
| Adds members to the struct type |
|
||||
+----------------------------------------------------------------------------------------------+
|
||||
| **LLVMmainfunction methods** |
|
||||
+----------------------------------------------------------------------------------------------+
|
||||
| ``appendblock(LLVMbasicblock)`` |
|
||||
| Adds a basic block to the end |
|
||||
| ``compile()`` |
|
||||
| Compiles the module and returns a reference to the C Closure |
|
||||
| ``arg(position) -> LLVMvalue`` |
|
||||
| Returns the argument at position; position >= 1; returns ``nil`` if argument not available |
|
||||
| ``module() -> LLVMmodule`` |
|
||||
| Returns the module associated with the function |
|
||||
| ``extern(name[, functiontype]) -> LLVMconstant`` |
|
||||
| Returns an extern declaration; A number of Lua Api functions are predefined. |
|
||||
+----------------------------------------------------------------------------------------------+
|
||||
| **LLVMmodule methods** |
|
||||
+----------------------------------------------------------------------------------------------+
|
||||
| ``newfunction(name, functiontype) -> LLVMfunction`` |
|
||||
| Returns an internal linkage function within the module |
|
||||
| ``dump()`` |
|
||||
| Dumps the module |
|
||||
+----------------------------------------------------------------------------------------------+
|
||||
| **LLVMfunction methods** |
|
||||
+----------------------------------------------------------------------------------------------+
|
||||
| ``appendblock(LLVMbasicblock)`` |
|
||||
| Adds a basic block to the end |
|
||||
| ``arg(position) -> LLVMvalue`` |
|
||||
| Returns the argument at position; position >= 1; returns ``nil`` if argument not available |
|
||||
| ``alloca(type[, name [,arraysize]]) -> LLVMinstruction`` |
|
||||
| Creates a variable in the first block of the function |
|
||||
+----------------------------------------------------------------------------------------------+
|
||||
| **LLVMirbuilder methods** |
|
||||
+----------------------------------------------------------------------------------------------+
|
||||
| ``setinsertpoint(basicblock)`` |
|
||||
| Set current basicblock |
|
||||
| ``ret([value])`` |
|
||||
| Emit return instruction |
|
||||
| ``stringconstant(string) -> LLVMvalue`` |
|
||||
| Create a global string constant |
|
||||
| ``call({args}, {options}) -> LLVMinstruction`` |
|
||||
| Emit call instruction; 'tailcall' option is false by default |
|
||||
| ``br(basicblock) -> LLVMinstruction`` |
|
||||
| Emit a branch instruction |
|
||||
| ``condbr(value, true_block, false_block) -> LLVMinstruction`` |
|
||||
| Emit a conditional branch |
|
||||
| ``phi(type, num_values[, name]) -> LLVMphinode`` |
|
||||
| Generate a PHINode |
|
||||
| |
|
||||
| GEP Operators |
|
||||
| |
|
||||
| ``gep(value, {offsets}) -> LLVMvalue`` |
|
||||
| getelementptr to obtain ptr to an array or struct element |
|
||||
| ``inboundsgep(value, {offsets}) -> LLVMvalue`` |
|
||||
| inbounds version of getelementptr |
|
||||
| |
|
||||
| Memory Operators |
|
||||
| |
|
||||
| ``load(ptr) -> LLVMinstruction`` |
|
||||
| Loads the value at ptr |
|
||||
| ``store(value, ptr) -> LLVMinstruction`` |
|
||||
| Stores the value to ptr |
|
||||
| |
|
||||
| Binary Operators of the form ``op(value1, value2) -> LLVMvalue`` |
|
||||
| |
|
||||
| * ``icmpeq`` |
|
||||
| * ``icmpne`` |
|
||||
| * ``icmpugt`` |
|
||||
| * ``icmpuge`` |
|
||||
| * ``icmpult`` |
|
||||
| * ``icmpule`` |
|
||||
| * ``icmpsgt`` |
|
||||
| * ``icmpsge`` |
|
||||
| * ``icmpslt`` |
|
||||
| * ``icmpsle`` |
|
||||
| * ``fcmpoeq`` |
|
||||
| * ``fcmpogt`` |
|
||||
| * ``fcmpoge`` |
|
||||
| * ``fcmpolt`` |
|
||||
| * ``fcmpole`` |
|
||||
| * ``fcmpone`` |
|
||||
| * ``fcmpord`` |
|
||||
| * ``fcmpun`` |
|
||||
| * ``fcmpueq`` |
|
||||
| * ``fcmpugt`` |
|
||||
| * ``fcmpuge`` |
|
||||
| * ``fcmpult`` |
|
||||
| * ``fcmpule`` |
|
||||
| * ``fcmpune`` |
|
||||
| * ``nswadd`` |
|
||||
| * ``nuwadd`` |
|
||||
| * ``nswsub`` |
|
||||
| * ``nuwsub`` |
|
||||
| * ``udiv`` |
|
||||
| * ``exactudiv`` |
|
||||
| * ``sdiv`` |
|
||||
| * ``exactsdiv`` |
|
||||
| * ``urem`` |
|
||||
| * ``srem`` |
|
||||
| * ``and`` |
|
||||
| * ``or`` |
|
||||
| * ``xor`` |
|
||||
| * ``fadd`` |
|
||||
| * ``fsub`` |
|
||||
| * ``fmul`` |
|
||||
| * ``fdiv`` |
|
||||
| * ``frem`` |
|
||||
| |
|
||||
| Unary Operators of the form ``op(value) -> LLVMvalue`` |
|
||||
| |
|
||||
| * ``not`` |
|
||||
| * ``neg`` |
|
||||
| * ``fneg`` |
|
||||
| |
|
||||
| Conversion Operators of the form ``op(value,type) -> LLVMvalue`` |
|
||||
| |
|
||||
| * ``trunc`` |
|
||||
| * ``zext`` |
|
||||
| * ``sext`` |
|
||||
| * ``zextortrunc`` |
|
||||
| * ``sextortrunc`` |
|
||||
| * ``fptoui`` |
|
||||
| * ``fptosi`` |
|
||||
| * ``uitofp`` |
|
||||
| * ``sitofp`` |
|
||||
| * ``fptrunc`` |
|
||||
| * ``fpext`` |
|
||||
| * ``ptrtoint`` |
|
||||
| * ``inttoptr`` |
|
||||
| * ``bitcast`` |
|
||||
| * ``sextorbitcast`` |
|
||||
| * ``zextorbitcast`` |
|
||||
| * ``truncorbitcast`` |
|
||||
| * ``pointercast`` |
|
||||
| * ``fpcast`` |
|
||||
+----------------------------------------------------------------------------------------------+
|
||||
| **LLVMphinode methods** |
|
||||
+----------------------------------------------------------------------------------------------+
|
||||
| ``addincoming(value, basicblock)`` |
|
||||
| Adds incoming edge |
|
||||
+----------------------------------------------------------------------------------------------+
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue