xo-jit: refactor: + closures [wip: not tested]

This commit is contained in:
Roland Conybeare 2024-07-08 18:31:06 -04:00
commit 659c0c400b
5 changed files with 376 additions and 280 deletions

View file

@ -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);

View file

@ -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*/