feat: migrate to cranelift (WIP)
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
use std::cell::OnceCell;
|
||||
use core::mem::MaybeUninit;
|
||||
use std::rc::Rc;
|
||||
|
||||
use hashbrown::HashSet;
|
||||
@@ -7,7 +8,7 @@ use priority_queue::PriorityQueue;
|
||||
|
||||
use crate::env::Env;
|
||||
use crate::error::Result;
|
||||
use crate::eval::jit::{JITContext, JITFunc};
|
||||
use crate::eval::jit::{JITContext, JITFunc, JITValue};
|
||||
use crate::eval::Evaluate;
|
||||
use crate::ir::{Dep, Downgraded, Ir, SccNode};
|
||||
use crate::ty::internal as i;
|
||||
@@ -19,12 +20,12 @@ mod test;
|
||||
type ThunkIdx = usize;
|
||||
type EnvIdx = usize;
|
||||
|
||||
pub struct Engine<'ctx: 'exec, 'exec> {
|
||||
pub struct Engine<'exec> {
|
||||
pub thunks: Box<[Ir]>,
|
||||
pub func_offset: usize,
|
||||
pub func_deps: Vec<HashSet<Dep>>,
|
||||
jit: &'exec JITContext<'ctx>,
|
||||
compiled: Box<[OnceCell<JITFunc<'ctx, 'exec>>]>,
|
||||
jit: &'exec JITContext,
|
||||
compiled: Box<[OnceCell<JITFunc<'exec>>]>,
|
||||
tasks: PriorityQueue<CompileTask, usize>,
|
||||
}
|
||||
|
||||
@@ -79,8 +80,12 @@ impl<'ctx, 'exec> Engine<'ctx, 'exec> {
|
||||
}
|
||||
|
||||
pub fn eval_thunk(&mut self, idx: usize, env: &mut Env) -> Result<i::Value> {
|
||||
let func = self.compiled[idx].get_or_init(|| self.jit.compile(&self.thunks[idx]));
|
||||
Ok(unsafe { func(self as *const Engine, env as *const Env).into() })
|
||||
let func = self.compiled[idx].get_or_init(|| self.jit.compile(&self.thunks[idx], idx));
|
||||
let mut ret: MaybeUninit<JITValue> = MaybeUninit::uninit();
|
||||
unsafe {
|
||||
func(self as *const Engine, env as *const Env, core::mem::transmute::<*mut MaybeUninit<JITValue>, *mut JITValue>(&mut ret as *mut _));
|
||||
Ok(ret.assume_init().into())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn eval_func_deps(&mut self, idx: usize, env: &mut Env) -> Result<()> {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::fmt::Debug;
|
||||
use core::fmt::Debug;
|
||||
use std::rc::Rc;
|
||||
|
||||
use ecow::EcoString;
|
||||
@@ -12,7 +12,6 @@ pub struct Env {
|
||||
cache: Vec<HashMap<usize, Value>>,
|
||||
with: Vec<Rc<HashMap<EcoString, Value>>>,
|
||||
args: Vec<Value>,
|
||||
pub args_len: usize,
|
||||
}
|
||||
|
||||
impl Env {
|
||||
@@ -21,7 +20,6 @@ impl Env {
|
||||
cache: Vec::from([HashMap::new()]),
|
||||
with: Vec::new(),
|
||||
args: Vec::new(),
|
||||
args_len: 0,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,7 +87,7 @@ impl Env {
|
||||
}
|
||||
|
||||
pub fn enter_arg(&mut self, arg: Value) {
|
||||
self.args.push(arg)
|
||||
self.args.push(arg);
|
||||
}
|
||||
|
||||
pub fn pop_args(&mut self, len: usize) -> Vec<Value> {
|
||||
|
||||
@@ -10,8 +10,8 @@ pub enum Error {
|
||||
DowngradeError(String),
|
||||
#[error("error occurred during evaluation stage: {0}")]
|
||||
EvalError(String),
|
||||
#[error("error occurred during JIT compile stage: {0}")]
|
||||
CompileError(#[from] inkwell::builder::BuilderError),
|
||||
// #[error("error occurred during JIT compile stage: {0}")]
|
||||
// CompileError(#[from] inkwell::builder::BuilderError),
|
||||
#[error("unknown error")]
|
||||
Unknown,
|
||||
}
|
||||
|
||||
@@ -1,70 +1,71 @@
|
||||
use std::{alloc::Layout, ffi::CStr};
|
||||
|
||||
use inkwell::values::{FunctionValue, StructValue};
|
||||
use cranelift::prelude::*;
|
||||
use cranelift::codegen::ir;
|
||||
|
||||
use crate::eval::jit::JITValue;
|
||||
use crate::ir::*;
|
||||
use crate::ty::common as c;
|
||||
use crate::ty::internal::Value;
|
||||
use crate::{eval::jit::JITValue, ir::*};
|
||||
|
||||
use super::{JITContext, ValueTag};
|
||||
|
||||
pub trait JITCompile {
|
||||
fn compile<'gc>(
|
||||
fn compile(
|
||||
&self,
|
||||
ctx: &JITContext<'gc>,
|
||||
func: FunctionValue<'gc>,
|
||||
values: &mut Vec<Value>,
|
||||
) -> StructValue<'gc>;
|
||||
ctx: &mut JITContext,
|
||||
builder: &mut FunctionBuilder,
|
||||
block: Block,
|
||||
) -> ir::Value;
|
||||
}
|
||||
|
||||
impl JITCompile for Attrs {
|
||||
fn compile<'gc>(
|
||||
fn compile(
|
||||
&self,
|
||||
ctx: &JITContext<'gc>,
|
||||
func: FunctionValue<'gc>,
|
||||
values: &mut Vec<Value>,
|
||||
) -> StructValue<'gc> {
|
||||
ctx: &mut JITContext,
|
||||
builder: &mut FunctionBuilder,
|
||||
block: Block,
|
||||
) -> ir::Value {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl JITCompile for List {
|
||||
fn compile<'gc>(
|
||||
fn compile(
|
||||
&self,
|
||||
ctx: &JITContext<'gc>,
|
||||
func: FunctionValue<'gc>,
|
||||
values: &mut Vec<Value>,
|
||||
) -> StructValue<'gc> {
|
||||
ctx: &mut JITContext,
|
||||
builder: &mut FunctionBuilder,
|
||||
block: Block,
|
||||
) -> ir::Value {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl JITCompile for HasAttr {
|
||||
fn compile<'gc>(
|
||||
fn compile(
|
||||
&self,
|
||||
ctx: &JITContext<'gc>,
|
||||
func: FunctionValue<'gc>,
|
||||
values: &mut Vec<Value>,
|
||||
) -> StructValue<'gc> {
|
||||
ctx: &mut JITContext,
|
||||
builder: &mut FunctionBuilder,
|
||||
block: Block,
|
||||
) -> ir::Value {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl JITCompile for BinOp {
|
||||
fn compile<'gc>(
|
||||
fn compile(
|
||||
&self,
|
||||
ctx: &JITContext<'gc>,
|
||||
func: FunctionValue<'gc>,
|
||||
values: &mut Vec<Value>,
|
||||
) -> StructValue<'gc> {
|
||||
ctx: &mut JITContext,
|
||||
builder: &mut FunctionBuilder,
|
||||
block: Block,
|
||||
) -> ir::Value {
|
||||
use BinOpKind::*;
|
||||
use ValueTag::*;
|
||||
let lhs = self.lhs.compile(ctx, func, values);
|
||||
let rhs = self.rhs.compile(ctx, func, values);
|
||||
let lhs = self.lhs.compile(ctx, builder, block);
|
||||
let rhs = self.rhs.compile(ctx, builder, block);
|
||||
let lhs_tag = ctx.get_tag(lhs);
|
||||
let rhs_tag = ctx.get_tag(rhs);
|
||||
let tag = ctx
|
||||
.builder
|
||||
.func_builder
|
||||
.build_int_add(
|
||||
lhs_tag.const_shl(ctx.helpers.const_int(8)),
|
||||
rhs_tag,
|
||||
@@ -73,7 +74,7 @@ impl JITCompile for BinOp {
|
||||
.unwrap();
|
||||
let ret = ctx.context.append_basic_block(func, "fallback");
|
||||
let res = ctx
|
||||
.builder
|
||||
.func_builder
|
||||
.build_alloca(ctx.helpers.value_type, "res_alloca")
|
||||
.unwrap();
|
||||
match self.kind {
|
||||
@@ -83,7 +84,7 @@ impl JITCompile for BinOp {
|
||||
let float_int = ctx.context.append_basic_block(func, "float_int");
|
||||
let float_float = ctx.context.append_basic_block(func, "float_float");
|
||||
let fallback = ctx.context.append_basic_block(func, "fallback");
|
||||
ctx.builder
|
||||
ctx.func_builder
|
||||
.build_switch(
|
||||
tag,
|
||||
fallback,
|
||||
@@ -107,19 +108,19 @@ impl JITCompile for BinOp {
|
||||
],
|
||||
)
|
||||
.unwrap();
|
||||
ctx.builder.position_at_end(int_int);
|
||||
ctx.func_builder.position_at_end(int_int);
|
||||
let val = ctx
|
||||
.builder
|
||||
.func_builder
|
||||
.build_int_add(ctx.get_int(lhs), ctx.get_int(rhs), "add")
|
||||
.unwrap();
|
||||
ctx.builder
|
||||
ctx.func_builder
|
||||
.build_store(res, ctx.helpers.new_value(Int, val.into()))
|
||||
.unwrap();
|
||||
ctx.builder.position_at_end(int_float);
|
||||
ctx.func_builder.position_at_end(int_float);
|
||||
let val = ctx
|
||||
.builder
|
||||
.func_builder
|
||||
.build_float_add(
|
||||
ctx.builder
|
||||
ctx.func_builder
|
||||
.build_signed_int_to_float(
|
||||
ctx.get_int(lhs),
|
||||
ctx.helpers.float_type,
|
||||
@@ -130,15 +131,15 @@ impl JITCompile for BinOp {
|
||||
"add",
|
||||
)
|
||||
.unwrap();
|
||||
ctx.builder
|
||||
ctx.func_builder
|
||||
.build_store(res, ctx.helpers.new_value(Float, val.into()))
|
||||
.unwrap();
|
||||
ctx.builder.position_at_end(float_int);
|
||||
ctx.func_builder.position_at_end(float_int);
|
||||
let val = ctx
|
||||
.builder
|
||||
.func_builder
|
||||
.build_float_add(
|
||||
ctx.get_float(lhs),
|
||||
ctx.builder
|
||||
ctx.func_builder
|
||||
.build_signed_int_to_float(
|
||||
ctx.get_int(rhs),
|
||||
ctx.helpers.float_type,
|
||||
@@ -148,23 +149,23 @@ impl JITCompile for BinOp {
|
||||
"add",
|
||||
)
|
||||
.unwrap();
|
||||
ctx.builder
|
||||
ctx.func_builder
|
||||
.build_store(res, ctx.helpers.new_value(Float, val.into()))
|
||||
.unwrap();
|
||||
ctx.builder.position_at_end(int_int);
|
||||
ctx.func_builder.position_at_end(int_int);
|
||||
let val = ctx
|
||||
.builder
|
||||
.func_builder
|
||||
.build_float_add(ctx.get_float(lhs), ctx.get_float(rhs), "add")
|
||||
.unwrap();
|
||||
ctx.builder
|
||||
ctx.func_builder
|
||||
.build_store(res, ctx.helpers.new_value(Float, val.into()))
|
||||
.unwrap();
|
||||
ctx.builder.position_at_end(fallback);
|
||||
ctx.func_builder.position_at_end(fallback);
|
||||
}
|
||||
Or => {
|
||||
let bool_bool = ctx.context.append_basic_block(func, "int_int");
|
||||
let fallback = ctx.context.append_basic_block(func, "fallback");
|
||||
ctx.builder
|
||||
ctx.func_builder
|
||||
.build_switch(
|
||||
tag,
|
||||
fallback,
|
||||
@@ -174,20 +175,20 @@ impl JITCompile for BinOp {
|
||||
)],
|
||||
)
|
||||
.unwrap();
|
||||
ctx.builder.position_at_end(bool_bool);
|
||||
ctx.func_builder.position_at_end(bool_bool);
|
||||
let val = ctx
|
||||
.builder
|
||||
.func_builder
|
||||
.build_or(ctx.get_bool(lhs), ctx.get_bool(rhs), "or")
|
||||
.unwrap();
|
||||
ctx.builder
|
||||
ctx.func_builder
|
||||
.build_store(res, ctx.helpers.new_value(Bool, val.into()))
|
||||
.unwrap();
|
||||
ctx.builder.position_at_end(fallback);
|
||||
ctx.func_builder.position_at_end(fallback);
|
||||
}
|
||||
_ => todo!(),
|
||||
}
|
||||
ctx.builder.position_at_end(ret);
|
||||
ctx.builder
|
||||
ctx.func_builder.position_at_end(ret);
|
||||
ctx.func_builder
|
||||
.build_load(ctx.helpers.value_type, res, "load_res")
|
||||
.unwrap()
|
||||
.try_into()
|
||||
@@ -196,25 +197,25 @@ impl JITCompile for BinOp {
|
||||
}
|
||||
|
||||
impl JITCompile for UnOp {
|
||||
fn compile<'gc>(
|
||||
fn compile(
|
||||
&self,
|
||||
ctx: &JITContext<'gc>,
|
||||
func: FunctionValue<'gc>,
|
||||
values: &mut Vec<Value>,
|
||||
) -> StructValue<'gc> {
|
||||
ctx: &mut JITContext,
|
||||
builder: &mut FunctionBuilder,
|
||||
block: Block,
|
||||
) -> ir::Value {
|
||||
todo!();
|
||||
let rhs = self.rhs.compile(ctx, func, values);
|
||||
let rhs = self.rhs.compile(ctx, builder, block);
|
||||
let tag = ctx.get_tag(rhs);
|
||||
let fallback = ctx.context.append_basic_block(func, "fallback");
|
||||
let ret = ctx.context.append_basic_block(func, "fallback");
|
||||
let res = ctx
|
||||
.builder
|
||||
.func_builder
|
||||
.build_alloca(ctx.helpers.value_type, "res_alloca")
|
||||
.unwrap();
|
||||
ctx.builder.build_switch(tag, fallback, &[]).unwrap();
|
||||
ctx.builder.position_at_end(fallback);
|
||||
ctx.builder.position_at_end(ret);
|
||||
ctx.builder
|
||||
ctx.func_builder.build_switch(tag, fallback, &[]).unwrap();
|
||||
ctx.func_builder.position_at_end(fallback);
|
||||
ctx.func_builder.position_at_end(ret);
|
||||
ctx.func_builder
|
||||
.build_load(ctx.helpers.value_type, res, "load_res")
|
||||
.unwrap()
|
||||
.try_into()
|
||||
@@ -223,34 +224,34 @@ impl JITCompile for UnOp {
|
||||
}
|
||||
|
||||
impl JITCompile for Select {
|
||||
fn compile<'gc>(
|
||||
fn compile(
|
||||
&self,
|
||||
ctx: &JITContext<'gc>,
|
||||
func: FunctionValue<'gc>,
|
||||
values: &mut Vec<Value>,
|
||||
) -> StructValue<'gc> {
|
||||
ctx: &mut JITContext,
|
||||
builder: &mut FunctionBuilder,
|
||||
block: Block,
|
||||
) -> ir::Value {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl JITCompile for If {
|
||||
fn compile<'gc>(
|
||||
fn compile(
|
||||
&self,
|
||||
ctx: &JITContext<'gc>,
|
||||
func: FunctionValue<'gc>,
|
||||
values: &mut Vec<Value>,
|
||||
) -> StructValue<'gc> {
|
||||
ctx: &mut JITContext,
|
||||
builder: &mut FunctionBuilder,
|
||||
block: Block,
|
||||
) -> ir::Value {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl JITCompile for LoadFunc {
|
||||
fn compile<'gc>(
|
||||
fn compile(
|
||||
&self,
|
||||
ctx: &JITContext<'gc>,
|
||||
_: FunctionValue<'gc>,
|
||||
values: &mut Vec<Value>,
|
||||
) -> StructValue<'gc> {
|
||||
ctx: &mut JITContext,
|
||||
builder: &mut FunctionBuilder,
|
||||
block: Block,
|
||||
) -> ir::Value {
|
||||
ctx.helpers.new_value(
|
||||
ValueTag::Function,
|
||||
ctx.helpers.const_int(self.idx as i64).into(),
|
||||
@@ -259,14 +260,18 @@ impl JITCompile for LoadFunc {
|
||||
}
|
||||
|
||||
impl JITCompile for Call {
|
||||
fn compile<'gc>(
|
||||
fn compile(
|
||||
&self,
|
||||
ctx: &JITContext<'gc>,
|
||||
func: FunctionValue<'gc>,
|
||||
values: &mut Vec<Value>,
|
||||
) -> StructValue<'gc> {
|
||||
ctx: &mut JITContext,
|
||||
builder: &mut FunctionBuilder,
|
||||
block: Block,
|
||||
) -> ir::Value {
|
||||
let ret = ctx
|
||||
.func_builder
|
||||
.build_alloca(ctx.helpers.value_type, "ret")
|
||||
.unwrap();
|
||||
let args = ctx
|
||||
.builder
|
||||
.func_builder
|
||||
.build_call(
|
||||
ctx.helpers.alloc_array,
|
||||
&[ctx.helpers.const_ptr_int(self.args.len()).into()],
|
||||
@@ -277,89 +282,93 @@ impl JITCompile for Call {
|
||||
.unwrap_left()
|
||||
.into_pointer_value();
|
||||
for (i, arg) in self.args.iter().enumerate() {
|
||||
ctx.builder
|
||||
.build_store(
|
||||
unsafe {
|
||||
args.const_in_bounds_gep(
|
||||
ctx.helpers.value_type,
|
||||
&[ctx.helpers.const_ptr_int(i)],
|
||||
)
|
||||
},
|
||||
arg.compile(ctx, func, values),
|
||||
)
|
||||
let arg_ptr = unsafe {
|
||||
ctx.func_builder
|
||||
.build_gep(
|
||||
ctx.helpers.value_type,
|
||||
args,
|
||||
&[ctx.helpers.const_ptr_int(i)],
|
||||
"args_gep",
|
||||
)
|
||||
.unwrap()
|
||||
};
|
||||
ctx.func_builder
|
||||
.build_store(arg_ptr, arg.compile(ctx, builder, block))
|
||||
.unwrap();
|
||||
}
|
||||
ctx.builder
|
||||
ctx.func_builder
|
||||
.build_call(
|
||||
ctx.helpers.call,
|
||||
&[
|
||||
self.func.compile(ctx, func, values).into(),
|
||||
self.func.compile(ctx, builder, block).into(),
|
||||
args.into(),
|
||||
ctx.helpers.const_ptr_int(self.args.len()).into(),
|
||||
func.get_first_param().unwrap().into(),
|
||||
func.get_last_param().unwrap().into(),
|
||||
func.get_nth_param(0).unwrap().into(),
|
||||
func.get_nth_param(1).unwrap().into(),
|
||||
ret.into(),
|
||||
],
|
||||
"call",
|
||||
)
|
||||
.unwrap();
|
||||
ctx.func_builder
|
||||
.build_load(ctx.helpers.value_type, ret, "load_ret")
|
||||
.unwrap()
|
||||
.try_as_basic_value()
|
||||
.unwrap_left()
|
||||
.try_into()
|
||||
.unwrap()
|
||||
.into_struct_value()
|
||||
}
|
||||
}
|
||||
|
||||
impl JITCompile for Let {
|
||||
fn compile<'gc>(
|
||||
fn compile(
|
||||
&self,
|
||||
ctx: &JITContext<'gc>,
|
||||
func: FunctionValue<'gc>,
|
||||
values: &mut Vec<Value>,
|
||||
) -> StructValue<'gc> {
|
||||
ctx: &mut JITContext,
|
||||
builder: &mut FunctionBuilder,
|
||||
block: Block,
|
||||
) -> ir::Value {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
impl JITCompile for With {
|
||||
fn compile<'gc>(
|
||||
fn compile(
|
||||
&self,
|
||||
ctx: &JITContext<'gc>,
|
||||
func: FunctionValue<'gc>,
|
||||
values: &mut Vec<Value>,
|
||||
) -> StructValue<'gc> {
|
||||
ctx: &mut JITContext,
|
||||
builder: &mut FunctionBuilder,
|
||||
block: Block,
|
||||
) -> ir::Value {
|
||||
todo!()
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl JITCompile for Assert {
|
||||
fn compile<'gc>(
|
||||
fn compile(
|
||||
&self,
|
||||
ctx: &JITContext<'gc>,
|
||||
func: FunctionValue<'gc>,
|
||||
values: &mut Vec<Value>,
|
||||
) -> StructValue<'gc> {
|
||||
ctx: &mut JITContext,
|
||||
builder: &mut FunctionBuilder,
|
||||
block: Block,
|
||||
) -> ir::Value {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl JITCompile for ConcatStrings {
|
||||
fn compile<'gc>(
|
||||
fn compile(
|
||||
&self,
|
||||
ctx: &JITContext<'gc>,
|
||||
func: FunctionValue<'gc>,
|
||||
values: &mut Vec<Value>,
|
||||
) -> StructValue<'gc> {
|
||||
ctx: &mut JITContext,
|
||||
builder: &mut FunctionBuilder,
|
||||
block: Block,
|
||||
) -> ir::Value {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl JITCompile for Const {
|
||||
fn compile<'gc>(
|
||||
fn compile(
|
||||
&self,
|
||||
ctx: &JITContext<'gc>,
|
||||
func: FunctionValue<'gc>,
|
||||
values: &mut Vec<Value>,
|
||||
) -> StructValue<'gc> {
|
||||
ctx: &mut JITContext,
|
||||
builder: &mut FunctionBuilder,
|
||||
block: Block,
|
||||
) -> ir::Value {
|
||||
use c::Const::*;
|
||||
match self.val {
|
||||
Bool(x) => ctx.helpers.new_bool(x),
|
||||
@@ -371,28 +380,27 @@ impl JITCompile for Const {
|
||||
}
|
||||
|
||||
impl JITCompile for String {
|
||||
fn compile<'gc>(
|
||||
fn compile(
|
||||
&self,
|
||||
ctx: &JITContext<'gc>,
|
||||
func: FunctionValue<'gc>,
|
||||
values: &mut Vec<Value>,
|
||||
) -> StructValue<'gc> {
|
||||
ctx: &mut JITContext,
|
||||
builder: &mut FunctionBuilder,
|
||||
block: Block,
|
||||
) -> ir::Value {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl JITCompile for Var {
|
||||
fn compile<'gc>(
|
||||
fn compile(
|
||||
&self,
|
||||
ctx: &JITContext<'gc>,
|
||||
func: FunctionValue<'gc>,
|
||||
values: &mut Vec<Value>,
|
||||
) -> StructValue<'gc> {
|
||||
ctx: &mut JITContext,
|
||||
builder: &mut FunctionBuilder,
|
||||
block: Block,
|
||||
) -> ir::Value {
|
||||
let env = func.get_nth_param(1).unwrap();
|
||||
let ptr = self.sym.as_ptr();
|
||||
let len = self.sym.len();
|
||||
// values.push(Value::String(self.sym.clone()));
|
||||
ctx.builder
|
||||
ctx.func_builder
|
||||
.build_direct_call(
|
||||
ctx.helpers.lookup,
|
||||
&[
|
||||
@@ -411,43 +419,54 @@ impl JITCompile for Var {
|
||||
}
|
||||
|
||||
impl JITCompile for Arg {
|
||||
fn compile<'gc>(
|
||||
fn compile(
|
||||
&self,
|
||||
ctx: &JITContext<'gc>,
|
||||
func: FunctionValue<'gc>,
|
||||
values: &mut Vec<Value>,
|
||||
) -> StructValue<'gc> {
|
||||
let env = func.get_last_param().unwrap();
|
||||
let ret = ctx.builder.build_alloca(ctx.helpers.value_type, "alloca_ret").unwrap();
|
||||
ctx.builder
|
||||
ctx: &mut JITContext,
|
||||
builder: &mut FunctionBuilder,
|
||||
block: Block,
|
||||
) -> ir::Value {
|
||||
let env = builder.block_params(block)[];
|
||||
let env = func.get_nth_param(1).unwrap();
|
||||
let arg = ctx
|
||||
.func_builder
|
||||
.build_alloca(ctx.helpers.value_type, "alloca_arg")
|
||||
.unwrap();
|
||||
ctx.func_builder
|
||||
.build_direct_call(
|
||||
ctx.helpers.lookup_arg,
|
||||
&[env.into(), ctx.helpers.const_ptr_int(self.level).into(), ret.into()],
|
||||
&[
|
||||
env.into(),
|
||||
ctx.helpers.const_ptr_int(self.level).into(),
|
||||
arg.into(),
|
||||
],
|
||||
"lookup_arg",
|
||||
)
|
||||
.unwrap();
|
||||
ctx.builder.build_load(ctx.helpers.value_type,ret, "load_ret").unwrap().into_struct_value()
|
||||
ctx.func_builder
|
||||
.build_load(ctx.helpers.value_type, arg, "load_arg")
|
||||
.unwrap()
|
||||
.into_struct_value()
|
||||
}
|
||||
}
|
||||
|
||||
impl JITCompile for LetVar {
|
||||
fn compile<'gc>(
|
||||
fn compile(
|
||||
&self,
|
||||
ctx: &JITContext<'gc>,
|
||||
func: FunctionValue<'gc>,
|
||||
values: &mut Vec<Value>,
|
||||
) -> StructValue<'gc> {
|
||||
ctx: &mut JITContext,
|
||||
builder: &mut FunctionBuilder,
|
||||
block: Block,
|
||||
) -> ir::Value {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
impl JITCompile for Thunk {
|
||||
fn compile<'gc>(
|
||||
fn compile(
|
||||
&self,
|
||||
ctx: &JITContext<'gc>,
|
||||
_: FunctionValue<'gc>,
|
||||
values: &mut Vec<Value>,
|
||||
) -> StructValue<'gc> {
|
||||
ctx: &mut JITContext,
|
||||
builder: &mut FunctionBuilder,
|
||||
block: Block,
|
||||
) -> ir::Value {
|
||||
ctx.helpers.new_value(
|
||||
ValueTag::Thunk,
|
||||
ctx.helpers.const_int(self.idx as i64).into(),
|
||||
@@ -456,12 +475,12 @@ impl JITCompile for Thunk {
|
||||
}
|
||||
|
||||
impl JITCompile for Path {
|
||||
fn compile<'gc>(
|
||||
fn compile(
|
||||
&self,
|
||||
ctx: &JITContext<'gc>,
|
||||
func: FunctionValue<'gc>,
|
||||
values: &mut Vec<Value>,
|
||||
) -> StructValue<'gc> {
|
||||
ctx: &mut JITContext,
|
||||
builder: &mut FunctionBuilder,
|
||||
block: Block,
|
||||
) -> ir::Value {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
use std::alloc::Layout;
|
||||
use std::ffi::CStr;
|
||||
use std::ptr::NonNull;
|
||||
use std::{slice, str};
|
||||
use std::alloc::alloc;
|
||||
use core::ptr::NonNull;
|
||||
use core::{slice, str};
|
||||
|
||||
use inkwell::AddressSpace;
|
||||
use inkwell::context::Context;
|
||||
use inkwell::execution_engine::ExecutionEngine;
|
||||
use inkwell::module::Module;
|
||||
use inkwell::types::{FloatType, FunctionType, IntType, PointerType, StructType};
|
||||
use inkwell::values::{BasicValueEnum, FloatValue, FunctionValue, IntValue, StructValue};
|
||||
use cranelift::codegen::ir::ArgumentExtension;
|
||||
use cranelift::codegen::ir::ArgumentPurpose;
|
||||
use cranelift::prelude::*;
|
||||
use cranelift_module::FuncId;
|
||||
use cranelift_module::Linkage;
|
||||
use cranelift_module::Module;
|
||||
|
||||
use crate::env::Env;
|
||||
use crate::eval::Engine;
|
||||
@@ -16,153 +16,71 @@ use crate::ty::internal::Value;
|
||||
|
||||
use super::{JITContext, JITValue, JITValueData, ValueTag};
|
||||
|
||||
pub struct Helpers<'ctx> {
|
||||
pub int_type: IntType<'ctx>,
|
||||
pub float_type: FloatType<'ctx>,
|
||||
pub bool_type: IntType<'ctx>,
|
||||
pub ptr_int_type: IntType<'ctx>,
|
||||
pub ptr_type: PointerType<'ctx>,
|
||||
pub value_type: StructType<'ctx>,
|
||||
pub func_type: FunctionType<'ctx>,
|
||||
pub struct Helpers {
|
||||
pub int_type: Type,
|
||||
pub float_type: Type,
|
||||
pub bool_type: Type,
|
||||
pub ptr_int_type: Type,
|
||||
pub ptr_type: Type,
|
||||
pub value_type: Type,
|
||||
pub func_sig: Signature,
|
||||
|
||||
pub new_thunk: FunctionValue<'ctx>,
|
||||
|
||||
pub debug: FunctionValue<'ctx>,
|
||||
pub capture_env: FunctionValue<'ctx>,
|
||||
pub neg: FunctionValue<'ctx>,
|
||||
pub not: FunctionValue<'ctx>,
|
||||
pub add: FunctionValue<'ctx>,
|
||||
pub sub: FunctionValue<'ctx>,
|
||||
pub eq: FunctionValue<'ctx>,
|
||||
pub or: FunctionValue<'ctx>,
|
||||
pub call: FunctionValue<'ctx>,
|
||||
pub lookup_arg: FunctionValue<'ctx>,
|
||||
pub lookup: FunctionValue<'ctx>,
|
||||
pub force: FunctionValue<'ctx>,
|
||||
pub call: FuncId,
|
||||
pub lookup_arg: FuncId,
|
||||
pub lookup: FuncId,
|
||||
pub force: FuncId,
|
||||
|
||||
pub alloc_array: FunctionValue<'ctx>,
|
||||
pub alloc_array: FuncId,
|
||||
}
|
||||
|
||||
impl<'ctx> Helpers<'ctx> {
|
||||
impl Helpers {
|
||||
pub fn new(
|
||||
ctx: &'ctx Context,
|
||||
module: &Module<'ctx>,
|
||||
execution_engine: &ExecutionEngine<'ctx>,
|
||||
ctx: &codegen::Context,
|
||||
module: &mut dyn Module,
|
||||
) -> Self {
|
||||
let int_type = ctx.i64_type();
|
||||
let float_type = ctx.f64_type();
|
||||
let bool_type = ctx.bool_type();
|
||||
let ptr_int_type = ctx.ptr_sized_int_type(execution_engine.get_target_data(), None);
|
||||
let ptr_type = ctx.ptr_type(AddressSpace::default());
|
||||
let value_type =
|
||||
ctx.struct_type(&[int_type.into(), int_type.into(), int_type.into()], false);
|
||||
let func_type = value_type.fn_type(&[ptr_type.into(), ptr_type.into()], false);
|
||||
let int_type = types::I64;
|
||||
let float_type = types::F64;
|
||||
let bool_type = types::I8;
|
||||
// let ptr_type = ctx.ptr_type(AddressSpace::default());
|
||||
let ptr_type = module.target_config().pointer_type();
|
||||
let ptr_int_type = ptr_type;
|
||||
let value_type = types::I128;
|
||||
// let func_sig = ctx.void_type().fn_type(&[ptr_type.into(), ptr_type.into(), ptr_type.into()], false);
|
||||
let mut func_sig = Signature::new(isa::CallConv::SystemV);
|
||||
func_sig.params.push(AbiParam { value_type: ptr_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None });
|
||||
func_sig.params.push(AbiParam { value_type: ptr_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None });
|
||||
func_sig.returns.push(AbiParam { value_type, purpose: ArgumentPurpose::StructReturn, extension: ArgumentExtension::None });
|
||||
|
||||
let new_thunk = module.add_function(
|
||||
"new_thunk",
|
||||
value_type.fn_type(&[ptr_type.into(), ptr_type.into()], false),
|
||||
None,
|
||||
);
|
||||
let capture_env = module.add_function(
|
||||
"capture_env",
|
||||
ctx
|
||||
.void_type()
|
||||
.fn_type(&[value_type.into(), ptr_type.into()], false),
|
||||
None,
|
||||
);
|
||||
let neg = module.add_function(
|
||||
"neg",
|
||||
value_type.fn_type(&[value_type.into(), ptr_type.into()], false),
|
||||
None,
|
||||
);
|
||||
let not = module.add_function(
|
||||
"not",
|
||||
value_type.fn_type(&[value_type.into(), ptr_type.into()], false),
|
||||
None,
|
||||
);
|
||||
let add = module.add_function(
|
||||
"add",
|
||||
value_type.fn_type(&[value_type.into(), value_type.into()], false),
|
||||
None,
|
||||
);
|
||||
let sub = module.add_function(
|
||||
"sub",
|
||||
value_type.fn_type(&[value_type.into(), value_type.into()], false),
|
||||
None,
|
||||
);
|
||||
let eq = module.add_function(
|
||||
"eq",
|
||||
value_type.fn_type(&[value_type.into(), value_type.into()], false),
|
||||
None,
|
||||
);
|
||||
let or = module.add_function(
|
||||
"or",
|
||||
value_type.fn_type(&[value_type.into(), value_type.into()], false),
|
||||
None,
|
||||
);
|
||||
let call = module.add_function(
|
||||
"call",
|
||||
value_type.fn_type(
|
||||
&[
|
||||
value_type.into(),
|
||||
ptr_type.into(),
|
||||
ptr_int_type.into(),
|
||||
ptr_type.into(),
|
||||
ptr_type.into(),
|
||||
],
|
||||
false,
|
||||
),
|
||||
None,
|
||||
);
|
||||
let debug = module.add_function(
|
||||
"debug",
|
||||
ctx
|
||||
.void_type()
|
||||
.fn_type(&[ptr_type.into(), int_type.into()], false),
|
||||
None,
|
||||
);
|
||||
let lookup_arg = module.add_function(
|
||||
"lookup_arg",
|
||||
// value_type.fn_type(&[ptr_type.into(), int_type.into()], false),
|
||||
ctx.void_type().fn_type(&[ptr_type.into(), int_type.into(), ptr_type.into()], false),
|
||||
None,
|
||||
);
|
||||
let lookup = module.add_function(
|
||||
"lookup",
|
||||
value_type.fn_type(
|
||||
&[ptr_int_type.into(), ptr_type.into(), ptr_int_type.into()],
|
||||
false,
|
||||
),
|
||||
None,
|
||||
);
|
||||
let force = module.add_function(
|
||||
"force",
|
||||
value_type.fn_type(
|
||||
&[value_type.into(), ptr_type.into(), ptr_type.into()],
|
||||
false,
|
||||
),
|
||||
None,
|
||||
);
|
||||
let alloc_array = module.add_function(
|
||||
"alloc_array",
|
||||
value_type.fn_type(&[ptr_int_type.into()], false),
|
||||
None,
|
||||
);
|
||||
let mut call_sig = Signature::new(isa::CallConv::SystemV);
|
||||
call_sig.params.push(AbiParam { value_type, purpose: ArgumentPurpose::StructArgument(24), extension: ArgumentExtension::None });
|
||||
call_sig.params.push(AbiParam { value_type: ptr_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None });
|
||||
call_sig.params.push(AbiParam { value_type: ptr_int_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None });
|
||||
call_sig.params.push(AbiParam { value_type: ptr_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None });
|
||||
call_sig.params.push(AbiParam { value_type: ptr_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None });
|
||||
let call = module.declare_function("helper_call", Linkage::Import, &call_sig).unwrap();
|
||||
|
||||
execution_engine.add_global_mapping(&new_thunk, helper_new_thunk as _);
|
||||
execution_engine.add_global_mapping(&debug, helper_debug as _);
|
||||
execution_engine.add_global_mapping(&capture_env, helper_capture_env as _);
|
||||
execution_engine.add_global_mapping(&neg, helper_neg as _);
|
||||
execution_engine.add_global_mapping(¬, helper_not as _);
|
||||
execution_engine.add_global_mapping(&add, helper_add as _);
|
||||
execution_engine.add_global_mapping(&sub, helper_sub as _);
|
||||
execution_engine.add_global_mapping(&eq, helper_eq as _);
|
||||
execution_engine.add_global_mapping(&or, helper_or as _);
|
||||
execution_engine.add_global_mapping(&call, helper_call as _);
|
||||
execution_engine.add_global_mapping(&lookup_arg, helper_lookup_arg as _);
|
||||
execution_engine.add_global_mapping(&lookup, helper_lookup as _);
|
||||
execution_engine.add_global_mapping(&force, helper_force as _);
|
||||
execution_engine.add_global_mapping(&alloc_array, helper_alloc_array as _);
|
||||
let mut lookup_arg_sig = Signature::new(isa::CallConv::SystemV);
|
||||
lookup_arg_sig.params.push(AbiParam { value_type: ptr_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None });
|
||||
lookup_arg_sig.params.push(AbiParam { value_type: ptr_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None });
|
||||
let lookup_arg = module.declare_function("helper_lookup_arg", Linkage::Import, &call_sig).unwrap();
|
||||
|
||||
let mut lookup_sig = Signature::new(isa::CallConv::SystemV);
|
||||
lookup_sig.params.push(AbiParam { value_type: ptr_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None });
|
||||
lookup_sig.params.push(AbiParam { value_type: ptr_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None });
|
||||
lookup_sig.params.push(AbiParam { value_type: ptr_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None });
|
||||
lookup_sig.params.push(AbiParam { value_type: ptr_int_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None });
|
||||
let lookup = module.declare_function("helper_lookup", Linkage::Import, &call_sig).unwrap();
|
||||
|
||||
let mut force_sig = Signature::new(isa::CallConv::SystemV);
|
||||
force_sig.params.push(AbiParam { value_type, purpose: ArgumentPurpose::StructArgument(24), extension: ArgumentExtension::None });
|
||||
force_sig.params.push(AbiParam { value_type: ptr_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None });
|
||||
force_sig.params.push(AbiParam { value_type: ptr_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None });
|
||||
let force = module.declare_function("helper_force", Linkage::Import, &call_sig).unwrap();
|
||||
|
||||
let mut alloc_array_sig = Signature::new(isa::CallConv::SystemV);
|
||||
alloc_array_sig.params.push(AbiParam { value_type: ptr_int_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None });
|
||||
let alloc_array = module.declare_function("helper_alloc_array", Linkage::Import, &call_sig).unwrap();
|
||||
|
||||
Helpers {
|
||||
int_type,
|
||||
@@ -171,18 +89,8 @@ impl<'ctx> Helpers<'ctx> {
|
||||
ptr_int_type,
|
||||
ptr_type,
|
||||
value_type,
|
||||
func_type,
|
||||
func_sig,
|
||||
|
||||
new_thunk,
|
||||
|
||||
debug,
|
||||
capture_env,
|
||||
neg,
|
||||
not,
|
||||
add,
|
||||
sub,
|
||||
eq,
|
||||
or,
|
||||
call,
|
||||
lookup_arg,
|
||||
lookup,
|
||||
@@ -192,7 +100,7 @@ impl<'ctx> Helpers<'ctx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_value(&self, tag: ValueTag, data: BasicValueEnum<'ctx>) -> StructValue<'ctx> {
|
||||
pub fn new_value(&self, tag: ValueTag, data: BasicValueEnum) -> StructValue {
|
||||
self.value_type.const_named_struct(&[
|
||||
self.const_int(tag as i64).into(),
|
||||
data,
|
||||
@@ -200,143 +108,39 @@ impl<'ctx> Helpers<'ctx> {
|
||||
])
|
||||
}
|
||||
|
||||
pub fn const_ptr_int(&self, int: usize) -> IntValue<'ctx> {
|
||||
pub fn const_ptr_int(&self, int: usize) -> IntValue {
|
||||
self.ptr_int_type.const_int(int as _, false)
|
||||
}
|
||||
|
||||
pub fn const_int(&self, int: i64) -> IntValue<'ctx> {
|
||||
pub fn const_int(&self, int: i64) -> IntValue {
|
||||
self.int_type.const_int(int as _, false)
|
||||
}
|
||||
|
||||
pub fn new_int(&self, int: i64) -> StructValue<'ctx> {
|
||||
pub fn new_int(&self, int: i64) -> StructValue {
|
||||
self.new_value(ValueTag::Int, self.const_int(int).into())
|
||||
}
|
||||
|
||||
pub fn const_float(&self, float: f64) -> FloatValue<'ctx> {
|
||||
pub fn const_float(&self, float: f64) -> FloatValue {
|
||||
self.float_type.const_float(float)
|
||||
}
|
||||
|
||||
pub fn new_float(&self, float: f64) -> StructValue<'ctx> {
|
||||
pub fn new_float(&self, float: f64) -> StructValue {
|
||||
self.new_value(ValueTag::Float, self.const_float(float).into())
|
||||
}
|
||||
|
||||
pub fn const_bool(&self, bool: bool) -> IntValue<'ctx> {
|
||||
pub fn const_bool(&self, bool: bool) -> IntValue {
|
||||
self.bool_type.const_int(bool as _, false)
|
||||
}
|
||||
|
||||
pub fn new_bool(&self, bool: bool) -> StructValue<'ctx> {
|
||||
pub fn new_bool(&self, bool: bool) -> StructValue {
|
||||
self.new_value(ValueTag::Bool, self.const_bool(bool).into())
|
||||
}
|
||||
|
||||
pub fn new_null(&self) -> StructValue<'ctx> {
|
||||
pub fn new_null(&self) -> StructValue {
|
||||
self.new_value(ValueTag::Null, self.int_type.const_zero().into())
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" fn helper_capture_env(thunk: JITValue, env: *const Env) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
extern "C" fn helper_neg(rhs: JITValue, _env: *const Env) -> JITValue {
|
||||
use ValueTag::*;
|
||||
match rhs.tag {
|
||||
Int => JITValue {
|
||||
tag: Int,
|
||||
data: JITValueData {
|
||||
int: -unsafe { rhs.data.int },
|
||||
},
|
||||
},
|
||||
Float => JITValue {
|
||||
tag: Float,
|
||||
data: JITValueData {
|
||||
float: -unsafe { rhs.data.float },
|
||||
},
|
||||
},
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" fn helper_not(rhs: JITValue, _env: *const Env) -> JITValue {
|
||||
use ValueTag::*;
|
||||
match rhs.tag {
|
||||
Bool => JITValue {
|
||||
tag: Bool,
|
||||
data: JITValueData {
|
||||
bool: !unsafe { rhs.data.bool },
|
||||
},
|
||||
},
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" fn helper_add(lhs: JITValue, rhs: JITValue) -> JITValue {
|
||||
use ValueTag::*;
|
||||
match (lhs.tag, rhs.tag) {
|
||||
(Int, Int) => JITValue {
|
||||
tag: Int,
|
||||
data: JITValueData {
|
||||
int: unsafe { lhs.data.int + rhs.data.int },
|
||||
},
|
||||
},
|
||||
_ => todo!(
|
||||
"Addition not implemented for {:?} and {:?}",
|
||||
lhs.tag,
|
||||
rhs.tag
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" fn helper_sub(lhs: JITValue, rhs: JITValue) -> JITValue {
|
||||
use ValueTag::*;
|
||||
match (lhs.tag, rhs.tag) {
|
||||
(Int, Int) => JITValue {
|
||||
tag: Int,
|
||||
data: JITValueData {
|
||||
int: unsafe { lhs.data.int - rhs.data.int },
|
||||
},
|
||||
},
|
||||
_ => todo!(
|
||||
"Substruction not implemented for {:?} and {:?}",
|
||||
lhs.tag,
|
||||
rhs.tag
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" fn helper_eq(lhs: JITValue, rhs: JITValue) -> JITValue {
|
||||
use ValueTag::*;
|
||||
match (lhs.tag, rhs.tag) {
|
||||
(Int, Int) => JITValue {
|
||||
tag: Bool,
|
||||
data: JITValueData {
|
||||
bool: unsafe { lhs.data.int == rhs.data.int },
|
||||
},
|
||||
},
|
||||
_ => todo!(
|
||||
"Equation not implemented for {:?} and {:?}",
|
||||
lhs.tag,
|
||||
rhs.tag
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" fn helper_or(lhs: JITValue, rhs: JITValue) -> JITValue {
|
||||
use ValueTag::*;
|
||||
match (lhs.tag, rhs.tag) {
|
||||
(Bool, Bool) => JITValue {
|
||||
tag: Bool,
|
||||
data: JITValueData {
|
||||
bool: unsafe { lhs.data.bool || rhs.data.bool },
|
||||
},
|
||||
},
|
||||
_ => todo!(
|
||||
"Substraction not implemented for {:?} and {:?}",
|
||||
lhs.tag,
|
||||
rhs.tag
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" fn helper_call(
|
||||
func: JITValue,
|
||||
args: *mut JITValue,
|
||||
@@ -354,19 +158,12 @@ extern "C" fn helper_call(
|
||||
unsafe { env.as_mut() },
|
||||
)
|
||||
.unwrap();
|
||||
todo!()
|
||||
func.into()
|
||||
}
|
||||
|
||||
extern "C" fn helper_debug(env: NonNull<Env>, level: u64) {
|
||||
dbg!(env, level);
|
||||
dbg!(unsafe { env.as_ref() }.lookup_arg(level as usize));
|
||||
}
|
||||
|
||||
extern "C" fn helper_lookup_arg(env_ptr: NonNull<Env>, level: u64, ret: NonNull<JITValue>) {
|
||||
dbg!(env_ptr, level);
|
||||
let env_ref = unsafe { env_ptr.as_ref() };
|
||||
let val: JITValue = env_ref.lookup_arg(level as usize).into();
|
||||
unsafe { ret.write(val) }
|
||||
extern "C" fn helper_lookup_arg(env: NonNull<Env>, level: u64) -> JITValue {
|
||||
let env_ref = unsafe { env.as_ref() };
|
||||
env_ref.lookup_arg(level as usize).into()
|
||||
}
|
||||
|
||||
extern "C" fn helper_lookup(env: NonNull<Env>, ptr: *const u8, len: usize) -> JITValue {
|
||||
@@ -391,10 +188,6 @@ extern "C" fn helper_force(
|
||||
todo!()
|
||||
}
|
||||
|
||||
extern "C" fn helper_new_thunk(opcodes: *const ()) -> JITValue {
|
||||
todo!()
|
||||
}
|
||||
|
||||
unsafe extern "C" fn helper_alloc_array(len: usize) -> *mut u8 {
|
||||
unsafe { std::alloc::alloc(Layout::array::<JITValue>(len).unwrap()) }
|
||||
unsafe { alloc(Layout::array::<JITValue>(len).unwrap()) }
|
||||
}
|
||||
|
||||
@@ -2,14 +2,11 @@ use std::marker::PhantomData;
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
|
||||
use inkwell::OptimizationLevel;
|
||||
use inkwell::builder::Builder;
|
||||
use inkwell::context::Context;
|
||||
use inkwell::execution_engine::ExecutionEngine;
|
||||
use inkwell::module::Module;
|
||||
use inkwell::values::{
|
||||
AnyValue, BasicMetadataValueEnum, FloatValue, IntValue, PointerValue, StructValue,
|
||||
};
|
||||
use cranelift::codegen::ir::Function;
|
||||
use cranelift::prelude::*;
|
||||
use cranelift::codegen::ir;
|
||||
use cranelift_module::{DataDescription, Linkage, Module};
|
||||
use cranelift_jit::{JITModule, JITBuilder};
|
||||
|
||||
use crate::engine::Engine;
|
||||
use crate::env::Env;
|
||||
@@ -22,19 +19,30 @@ mod helpers;
|
||||
pub use compile::JITCompile;
|
||||
use helpers::Helpers;
|
||||
|
||||
#[repr(u64)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum ValueTag {
|
||||
Null,
|
||||
Int,
|
||||
Float,
|
||||
String,
|
||||
Bool,
|
||||
AttrSet,
|
||||
List,
|
||||
Function,
|
||||
Thunk,
|
||||
Path,
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct ValueTag(u64);
|
||||
|
||||
#[allow(non_upper_case_globals)]
|
||||
#[allow(non_snake_case)]
|
||||
impl ValueTag {
|
||||
const Null: Self = Self(0);
|
||||
const Int: Self = Self(1);
|
||||
const Float: Self = Self(2);
|
||||
const Path: Self = Self(3);
|
||||
const Bool: Self = Self(4);
|
||||
const AttrSet: Self = Self(5);
|
||||
const List: Self = Self(6);
|
||||
const Function: Self = Self(7);
|
||||
const Thunk: Self = Self(8);
|
||||
|
||||
pub fn String(len: usize) -> Self {
|
||||
Self(len as u64 ^ (1 << 31))
|
||||
}
|
||||
|
||||
pub fn is_str(&self) -> bool {
|
||||
self.0 >> 31 != 0
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
@@ -51,24 +59,15 @@ pub union JITValueData {
|
||||
float: f64,
|
||||
bool: bool,
|
||||
ptr: *const (),
|
||||
slice: Slice,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Slice {
|
||||
ptr: *const (),
|
||||
len: usize,
|
||||
}
|
||||
|
||||
impl From<JITValue> for Value {
|
||||
fn from(value: JITValue) -> Self {
|
||||
use ValueTag::*;
|
||||
match value.tag {
|
||||
Int => Value::Int(unsafe { value.data.int }),
|
||||
Null => Value::Null,
|
||||
Function => Value::Func(unsafe { value.data.int as usize }),
|
||||
Thunk => Value::Thunk(unsafe { value.data.int as usize }),
|
||||
ValueTag::Int => Value::Int(unsafe { value.data.int }),
|
||||
ValueTag::Null => Value::Null,
|
||||
ValueTag::Function => Value::Func(unsafe { value.data.int as usize }),
|
||||
ValueTag::Thunk => Value::Thunk(unsafe { value.data.int as usize }),
|
||||
_ => todo!("not implemented for {:?}", value.tag),
|
||||
}
|
||||
}
|
||||
@@ -84,10 +83,7 @@ impl From<Value> for JITValue {
|
||||
Value::List(list) => JITValue {
|
||||
tag: ValueTag::List,
|
||||
data: JITValueData {
|
||||
slice: Slice {
|
||||
ptr: list.as_ptr() as *const (),
|
||||
len: list.len(),
|
||||
},
|
||||
ptr: list.as_ptr() as *const (),
|
||||
},
|
||||
},
|
||||
Value::Func(idx) => JITValue {
|
||||
@@ -103,69 +99,82 @@ impl From<Value> for JITValue {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct JITFunc<'ctx, 'exec>(F<'ctx, 'exec>, PhantomData<&'exec mut ()>);
|
||||
type F<'ctx, 'exec> = unsafe extern "C" fn(*const Engine<'ctx, 'exec>, *const Env) -> JITValue;
|
||||
pub struct JITFunc<'exec>(F<'exec>, PhantomData<&'exec mut ()>);
|
||||
type F<'exec> = unsafe extern "C" fn(*const Engine<'exec>, *const Env, *mut JITValue);
|
||||
|
||||
impl<'ctx, 'exec> From<F<'ctx, 'exec>> for JITFunc<'ctx, 'exec> {
|
||||
fn from(value: F<'ctx, 'exec>) -> Self {
|
||||
impl<'exec> From<F<'exec>> for JITFunc<'exec> {
|
||||
fn from(value: F<'exec>) -> Self {
|
||||
Self(value, PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx: 'exec, 'exec> Deref for JITFunc<'ctx, 'exec> {
|
||||
type Target = F<'ctx, 'exec>;
|
||||
impl<'exec> Deref for JITFunc<'exec> {
|
||||
type Target = F<'exec>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
pub struct JITContext<'ctx> {
|
||||
context: &'ctx Context,
|
||||
module: Module<'ctx>,
|
||||
builder: Builder<'ctx>,
|
||||
execution_engine: ExecutionEngine<'ctx>,
|
||||
pub struct JITContext {
|
||||
func_builder: FunctionBuilderContext,
|
||||
|
||||
helpers: Helpers<'ctx>,
|
||||
ctx: codegen::Context,
|
||||
data_description: DataDescription,
|
||||
module: JITModule,
|
||||
func: Function,
|
||||
|
||||
helpers: Helpers,
|
||||
}
|
||||
|
||||
impl<'ctx> JITContext<'ctx> {
|
||||
pub fn new(context: &'ctx Context) -> Self {
|
||||
// force linker to link JIT engine
|
||||
unsafe {
|
||||
inkwell::llvm_sys::execution_engine::LLVMLinkInMCJIT();
|
||||
}
|
||||
let module = context.create_module("nixjit");
|
||||
let execution_engine = module
|
||||
.create_jit_execution_engine(OptimizationLevel::Aggressive)
|
||||
impl JITContext {
|
||||
pub fn new() -> Self {
|
||||
let mut flag_builder = settings::builder();
|
||||
flag_builder.set("use_colocated_libcalls", "false").unwrap();
|
||||
flag_builder.set("is_pic", "false").unwrap();
|
||||
let isa_builder = cranelift_native::builder().unwrap_or_else(|msg| {
|
||||
panic!("host machine is not supported: {}", msg);
|
||||
});
|
||||
let isa = isa_builder
|
||||
.finish(settings::Flags::new(flag_builder))
|
||||
.unwrap();
|
||||
let helpers = Helpers::new(context, &module, &execution_engine);
|
||||
let builder = JITBuilder::with_isa(isa, cranelift_module::default_libcall_names());
|
||||
|
||||
JITContext {
|
||||
execution_engine,
|
||||
builder: context.create_builder(),
|
||||
context,
|
||||
let mut module = JITModule::new(builder);
|
||||
let ctx = module.make_context();
|
||||
|
||||
Self {
|
||||
func_builder: FunctionBuilderContext::new(),
|
||||
helpers: Helpers::new(&ctx, &mut module),
|
||||
data_description: DataDescription::new(),
|
||||
func: Function::new(),
|
||||
ctx,
|
||||
module,
|
||||
|
||||
helpers,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compile<'exec>(&'exec self, ir: &Ir) -> JITFunc<'ctx, 'exec> {
|
||||
let func = self
|
||||
.module
|
||||
.add_function("nixjit_func", self.helpers.func_type, None);
|
||||
let entry = self.context.append_basic_block(func, "entry");
|
||||
self.builder.position_at_end(entry);
|
||||
pub fn compile<'exec>(&'exec mut self, ir: &Ir, id: usize) -> JITFunc<'exec> {
|
||||
let func_id = self.module.declare_function(format!("nixjit_thunk{id}").as_str(), Linkage::Local, &self.helpers.func_sig).unwrap();
|
||||
let mut func = Function::new();
|
||||
let builder = FunctionBuilder::new(&mut func, &mut self.func_builder);
|
||||
let entry = builder.create_block();
|
||||
builder.switch_to_block(entry);
|
||||
// TODO:
|
||||
let ret = ir.compile(self, func, &mut Vec::new());
|
||||
self.builder.build_return(Some(&ret)).unwrap();
|
||||
if func.verify(true) {
|
||||
let ret = ir.compile(self, func_id, &mut Vec::new());
|
||||
self.func_builder
|
||||
.build_store(func_id.get_nth_param(2).unwrap().into_pointer_value(), ret)
|
||||
.unwrap();
|
||||
self.func_builder.build_return(None).unwrap();
|
||||
self.module.print_to_stderr();
|
||||
let _ = self.execution_engine.remove_module(&self.module);
|
||||
let _ = self.execution_engine.add_module(&self.module);
|
||||
if func_id.verify(true) {
|
||||
unsafe {
|
||||
JITFunc(
|
||||
self.execution_engine
|
||||
.get_function(func.get_name().to_str().unwrap())
|
||||
.unwrap()
|
||||
.into_raw(),
|
||||
std::mem::transmute(
|
||||
self.execution_engine
|
||||
.get_function_address(func_id.get_name().to_str().unwrap())
|
||||
.unwrap(),
|
||||
),
|
||||
PhantomData,
|
||||
)
|
||||
}
|
||||
@@ -174,80 +183,18 @@ impl<'ctx> JITContext<'ctx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_float(&self, val: StructValue<'ctx>) -> FloatValue<'ctx> {
|
||||
let alloca = self
|
||||
.builder
|
||||
.build_alloca(self.helpers.int_type, "get_value_alloca")
|
||||
.unwrap();
|
||||
self.builder.build_store(alloca, val).unwrap();
|
||||
self.builder
|
||||
.build_load(
|
||||
self.helpers.float_type,
|
||||
self.builder
|
||||
.build_struct_gep(self.helpers.value_type, alloca, 1, "get_value_gep")
|
||||
.unwrap(),
|
||||
"get_value",
|
||||
)
|
||||
.unwrap()
|
||||
.into_float_value()
|
||||
pub fn get_value(&self, builder: &mut FunctionBuilder, val: ir::Value) -> ir::Value {
|
||||
let offset = builder.ins().iconst(types::I8, 64);
|
||||
builder.ins().rotl(val, offset)
|
||||
}
|
||||
|
||||
pub fn get_int(&self, val: StructValue<'ctx>) -> IntValue<'ctx> {
|
||||
let alloca = self
|
||||
.builder
|
||||
.build_alloca(self.helpers.int_type, "get_value_alloca")
|
||||
.unwrap();
|
||||
self.builder.build_store(alloca, val).unwrap();
|
||||
self.builder
|
||||
.build_load(
|
||||
self.helpers.int_type,
|
||||
self.builder
|
||||
.build_struct_gep(self.helpers.value_type, alloca, 1, "get_value_gep")
|
||||
.unwrap(),
|
||||
"get_value",
|
||||
)
|
||||
.unwrap()
|
||||
.into_int_value()
|
||||
pub fn get_tag(&self, builder: &mut FunctionBuilder, val: ir::Value) -> ir::Value {
|
||||
let offset = builder.ins().iconst(types::I8, 64);
|
||||
builder.ins().rotl(val, offset)
|
||||
}
|
||||
|
||||
pub fn get_bool(&self, val: StructValue<'ctx>) -> IntValue<'ctx> {
|
||||
let alloca = self
|
||||
.builder
|
||||
.build_alloca(self.helpers.bool_type, "get_value_alloca")
|
||||
.unwrap();
|
||||
self.builder.build_store(alloca, val).unwrap();
|
||||
self.builder
|
||||
.build_load(
|
||||
self.helpers.bool_type,
|
||||
self.builder
|
||||
.build_struct_gep(self.helpers.value_type, alloca, 1, "get_value_gep")
|
||||
.unwrap(),
|
||||
"get_value",
|
||||
)
|
||||
.unwrap()
|
||||
.into_int_value()
|
||||
}
|
||||
|
||||
pub fn get_tag(&self, val: StructValue<'ctx>) -> IntValue<'ctx> {
|
||||
let alloca = self
|
||||
.builder
|
||||
.build_alloca(self.helpers.value_type, "get_tag_alloca")
|
||||
.unwrap();
|
||||
self.builder.build_store(alloca, val).unwrap();
|
||||
self.builder
|
||||
.build_load(
|
||||
self.helpers.int_type,
|
||||
self.builder
|
||||
.build_struct_gep(self.helpers.value_type, alloca, 0, "get_tag_gep")
|
||||
.unwrap(),
|
||||
"get_tag",
|
||||
)
|
||||
.unwrap()
|
||||
.into_int_value()
|
||||
}
|
||||
|
||||
pub fn const_ptr(&self, ptr: *const ()) -> PointerValue<'ctx> {
|
||||
self.builder
|
||||
pub fn const_ptr(&self, ptr: *const ()) -> PointerValue {
|
||||
self.func_builder
|
||||
.build_int_to_ptr(
|
||||
self.helpers.int_type.const_int(ptr as _, false),
|
||||
self.helpers.ptr_type,
|
||||
|
||||
@@ -195,11 +195,11 @@ impl DowngradeContext {
|
||||
|| unreachable!(),
|
||||
|func| {
|
||||
unsafe {
|
||||
let old = std::ptr::read(func);
|
||||
let old = core::ptr::read(func);
|
||||
match old.resolve(Index::Func(idx), self_ptr.as_mut().unwrap(), env) {
|
||||
Ok(ok) => std::ptr::write(func, ok),
|
||||
Ok(ok) => core::ptr::write(func, ok),
|
||||
Err(err) => {
|
||||
std::ptr::write(
|
||||
core::ptr::write(
|
||||
func,
|
||||
Func {
|
||||
param: crate::ir::Param::Ident(EcoString::new()),
|
||||
@@ -225,11 +225,11 @@ impl DowngradeContext {
|
||||
|| unreachable!(),
|
||||
|thunk| {
|
||||
unsafe {
|
||||
let (old, _) = std::ptr::read(thunk);
|
||||
let (old, _) = core::ptr::read(thunk);
|
||||
match old.resolve(Index::Thunk(idx), self_ptr.as_mut().unwrap(), env) {
|
||||
Ok(ok) => std::ptr::write(&mut thunk.0, ok),
|
||||
Ok(ok) => core::ptr::write(&mut thunk.0, ok),
|
||||
Err(err) => {
|
||||
std::ptr::write(
|
||||
core::ptr::write(
|
||||
&mut thunk.0,
|
||||
Ir::Const(super::Const { val: Const::Null }),
|
||||
);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use derive_more::{IsVariant, TryUnwrap, Unwrap};
|
||||
use ecow::EcoString;
|
||||
use hashbrown::HashMap;
|
||||
use inkwell::values::{FunctionValue, StructValue};
|
||||
use cranelift::codegen;
|
||||
use itertools::Itertools;
|
||||
use rnix::ast::HasEntry;
|
||||
use rnix::ast::{self, Expr};
|
||||
@@ -90,9 +90,9 @@ macro_rules! ir {
|
||||
}
|
||||
|
||||
impl JITCompile for Ir {
|
||||
fn compile<'ctx>(&self, ctx: &JITContext<'ctx>, func: FunctionValue<'ctx>, values: &mut Vec<Value>) -> StructValue<'ctx>{
|
||||
fn compile(&self, ctx: &mut JITContext, builder: &mut FunctionBuilder) -> StructValue{
|
||||
match self {
|
||||
$(Ir::$ty(ir) => ir.compile(ctx, func, values),)*
|
||||
$(Ir::$ty(ir) => ir.compile(ctx, builder),)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use std::mem::{MaybeUninit, replace, transmute};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use core::mem::{MaybeUninit, replace, transmute};
|
||||
use core::ops::{Deref, DerefMut};
|
||||
|
||||
use crate::error::*;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use std::fmt::{Display, Formatter, Result as FmtResult};
|
||||
use std::hash::Hash;
|
||||
use core::fmt::{Display, Formatter, Result as FmtResult};
|
||||
use core::hash::Hash;
|
||||
|
||||
use derive_more::{Constructor, IsVariant, Unwrap};
|
||||
use ecow::EcoString;
|
||||
@@ -30,9 +30,9 @@ pub enum Const {
|
||||
}
|
||||
|
||||
impl Hash for Const {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
||||
use Const::*;
|
||||
std::mem::discriminant(self).hash(state);
|
||||
core::mem::discriminant(self).hash(state);
|
||||
match self {
|
||||
Int(x) => x.hash(state),
|
||||
Float(x) => x.to_bits().hash(state),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::ops::Deref;
|
||||
use core::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
|
||||
use derive_more::Constructor;
|
||||
@@ -99,7 +99,7 @@ impl AttrSet {
|
||||
}
|
||||
|
||||
pub fn into_inner(self: Rc<Self>) -> Rc<HashMap<EcoString, Value>> {
|
||||
unsafe { std::mem::transmute(self) }
|
||||
unsafe { core::mem::transmute(self) }
|
||||
}
|
||||
|
||||
pub fn from_inner(data: HashMap<EcoString, Value>) -> Self {
|
||||
|
||||
Reference in New Issue
Block a user