xo-jit: refactor: + closures [wip: not tested]
This commit is contained in:
parent
19d8a5e846
commit
659c0c400b
5 changed files with 376 additions and 280 deletions
|
|
@ -121,16 +121,45 @@ namespace xo {
|
|||
llvm::Function * codegen_primitive_wrapper(ref::brw<xo::ast::PrimitiveInterface> expr,
|
||||
llvm::IRBuilder<> & ir_builder);
|
||||
|
||||
llvm::Value * codegen_apply(ref::brw<xo::ast::Apply> expr, llvm::IRBuilder<> & ir_builder);
|
||||
/** Generate closure for invoking a primitive function.
|
||||
* Primitives don't benefit from a closure, but we need a consistent ABI
|
||||
* to support function-pointer-like behavior for a target function
|
||||
* that may resolve to primitive-or-lambda at runtime
|
||||
**/
|
||||
llvm::Value * codegen_primitive_closure(ref::brw<xo::ast::PrimitiveInterface> expr,
|
||||
llvm::IRBuilder<> & ir_builder);
|
||||
|
||||
llvm::Value * codegen_apply(ref::brw<xo::ast::Apply> expr,
|
||||
llvm::Value * envptr,
|
||||
llvm::IRBuilder<> & ir_builder);
|
||||
/* NOTE: codegen_lambda() needs to be reentrant too.
|
||||
* for example can have a lambda in apply position.
|
||||
*/
|
||||
llvm::Function * codegen_lambda_decl(ref::brw<xo::ast::Lambda> expr);
|
||||
llvm::Function * codegen_lambda_defn(ref::brw<xo::ast::Lambda> expr, llvm::IRBuilder<> & ir_builder);
|
||||
llvm::Value * codegen_variable(ref::brw<xo::ast::Variable> var, llvm::IRBuilder<> & ir_builder);
|
||||
llvm::Value * codegen_ifexpr(ref::brw<xo::ast::IfExpr> ifexpr, llvm::IRBuilder<> & ir_builder);
|
||||
/** Generate closure for invoking a lambda (user-defined function).
|
||||
* See @ref MachPipeline::codegen_apply for invocation
|
||||
* Same ABI as @ref MachPipeline::codegen_primitive_closure
|
||||
*
|
||||
* @param envptr. Environment from surrounding lexical scope.
|
||||
* This will be captured as envptr member by
|
||||
* the IR code for creating a closure.
|
||||
* @ref MachPipeline::codegen_toplevel and friends are responsible for
|
||||
* assembling and propagating this.
|
||||
**/
|
||||
llvm::Value * codegen_lambda_closure(ref::brw<xo::ast::Lambda> lambda,
|
||||
llvm::Value * envptr,
|
||||
llvm::IRBuilder<> & ir_builder);
|
||||
llvm::Value * codegen_variable(ref::brw<xo::ast::Variable> var,
|
||||
llvm::Value * envptr,
|
||||
llvm::IRBuilder<> & ir_builder);
|
||||
llvm::Value * codegen_ifexpr(ref::brw<xo::ast::IfExpr> ifexpr,
|
||||
llvm::Value * envptr,
|
||||
llvm::IRBuilder<> & ir_builder);
|
||||
|
||||
llvm::Value * codegen(ref::brw<Expression> expr, llvm::IRBuilder<> & ir_builder);
|
||||
llvm::Value * codegen(ref::brw<Expression> expr,
|
||||
llvm::Value * envptr,
|
||||
llvm::IRBuilder<> & ir_builder);
|
||||
|
||||
llvm::Value * codegen_toplevel(ref::brw<Expression> expr);
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ namespace xo {
|
|||
**/
|
||||
struct type2llvm {
|
||||
public:
|
||||
using FunctionInterface = xo::ast::FunctionInterface;
|
||||
using Lambda = xo::ast::Lambda;
|
||||
using TypeDescr = xo::reflect::TypeDescr;
|
||||
|
||||
|
|
@ -57,11 +58,55 @@ namespace xo {
|
|||
* unwind_fn [1] | o-------> env * (*)(env*, ctl)
|
||||
* +-------+
|
||||
*
|
||||
* @return struct type. typename will be @c c.foo for lambda with name @c foo
|
||||
* @return struct type. typename will be @c c.foo for a function
|
||||
* (primitive or lambda) with name @c foo
|
||||
**/
|
||||
static llvm::StructType *
|
||||
create_closure_lvtype(xo::ref::brw<LlvmContext> llvm_cx,
|
||||
xo::ref::brw<Lambda> lambda);
|
||||
create_closureapi_lvtype(xo::ref::brw<LlvmContext> llvm_cx,
|
||||
xo::ref::brw<FunctionInterface> fn);
|
||||
|
||||
/** establish llvm abstract representation for a closure:
|
||||
* struct with
|
||||
* - [0] function pointer
|
||||
* - [1] runtime localenv pointer
|
||||
*
|
||||
* +-------+
|
||||
* | o---------> native function
|
||||
* +-------+
|
||||
* | o---------> runtime localenv
|
||||
* +-------+ (possibly nullptr)
|
||||
*
|
||||
* 1. for primitives, localenv will be null pointer
|
||||
* 2. for lambdas L with L->requires_closure_flag() = false,
|
||||
* localenv will also be null pointer
|
||||
* 3. for lambdas with L->requires_closure_flag() = true,
|
||||
*
|
||||
* localenv will (for lambdas requiring closures)
|
||||
* in practice be struct:
|
||||
*
|
||||
* ^
|
||||
* | parent
|
||||
* +-------+ |
|
||||
* parent_env [0] | o-------/
|
||||
* +-------+
|
||||
* unwind_fn [1] | o-------> env * (*)(env*, ctl)
|
||||
* +-------+
|
||||
* arg[i] [2+i] . ... .
|
||||
* . ... .
|
||||
* +-------+
|
||||
*
|
||||
* ctl=0 unwind. finalization for any arg[i] that requires it.
|
||||
* returns nullptr
|
||||
* ctl=1 copy. copy runtime environment to heap destination
|
||||
* and return address of the copy
|
||||
*
|
||||
* Implementation here will just use generic pointer for runtime
|
||||
* localenv.
|
||||
**/
|
||||
static llvm::StructType *
|
||||
function_td_to_closureapi_lvtype(xo::ref::brw<LlvmContext> llvm_cx,
|
||||
TypeDescr fn_td,
|
||||
const std::string & hint_name);
|
||||
|
||||
/** establish llvm concrete representation for a particular lambda's
|
||||
* runtime local environment:
|
||||
|
|
@ -128,9 +173,17 @@ namespace xo {
|
|||
private:
|
||||
/** establish llvm representation for a function-pointer type
|
||||
* described by @p fn_td
|
||||
*
|
||||
* @param wrapper_flag If true, create function type for a wrapper
|
||||
* to be associated with a closure.
|
||||
* The wrapper accepts (and ignores) an envapi pointer as first argument.
|
||||
* Necessary to (for example) support function pointers that may refer
|
||||
* to either {primitive functions, functions-requiring-closures},
|
||||
* with choice deferred until runtime
|
||||
**/
|
||||
static llvm::PointerType * function_td_to_llvm_fnptr_type(xo::ref::brw<LlvmContext> llvm_cx,
|
||||
TypeDescr fn_td);
|
||||
TypeDescr fn_td,
|
||||
bool wrapper_flag);
|
||||
|
||||
/** establish llvm representation for a struct type described by @p struct_td
|
||||
**/
|
||||
|
|
@ -164,48 +217,6 @@ namespace xo {
|
|||
static llvm::StructType *
|
||||
env_api_llvm_type(xo::ref::brw<LlvmContext> llvm_cx);
|
||||
|
||||
/** establish llvm abstract representation for a closure:
|
||||
* struct with
|
||||
* - [0] function pointer
|
||||
* - [1] runtime localenv pointer
|
||||
*
|
||||
* +-------+
|
||||
* | o---------> native function
|
||||
* +-------+
|
||||
* | o---------> runtime localenv
|
||||
* +-------+ (possibly nullptr)
|
||||
*
|
||||
* 1. for primitives, localenv will be null pointer
|
||||
* 2. for lambdas L with L->requires_closure_flag() = false,
|
||||
* localenv will also be null pointer
|
||||
* 3. for lambdas with L->requires_closure_flag() = true,
|
||||
*
|
||||
* localenv will (for lambdas requiring closures)
|
||||
* in practice be struct:
|
||||
*
|
||||
* ^
|
||||
* | parent
|
||||
* +-------+ |
|
||||
* parent_env [0] | o-------/
|
||||
* +-------+
|
||||
* unwind_fn [1] | o-------> env * (*)(env*, ctl)
|
||||
* +-------+
|
||||
* arg[i] [2+i] . ... .
|
||||
* . ... .
|
||||
* +-------+
|
||||
*
|
||||
* ctl=0 unwind. finalization for any arg[i] that requires it.
|
||||
* returns nullptr
|
||||
* ctl=1 copy. copy runtime environment to heap destination
|
||||
* and return address of the copy
|
||||
*
|
||||
* Implementation here will just use generic pointer for runtime
|
||||
* localenv.
|
||||
**/
|
||||
static llvm::StructType *
|
||||
function_td_to_llvm_closure_type(xo::ref::brw<LlvmContext> llvm_cx,
|
||||
TypeDescr fn_td);
|
||||
|
||||
}; /*type2llvm*/
|
||||
} /*namespace jit*/
|
||||
} /*namespace xo*/
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue