fix: release eq
This commit is contained in:
@@ -1,486 +1,532 @@
|
||||
use std::{alloc::Layout, ffi::CStr};
|
||||
|
||||
use cranelift::codegen::ir::{self, BlockCall, StackSlot, ValueListPool};
|
||||
use cranelift::prelude::*;
|
||||
use cranelift::codegen::ir;
|
||||
|
||||
use crate::eval::jit::JITValue;
|
||||
use crate::eval::Evaluate;
|
||||
use crate::ir::*;
|
||||
use crate::ty::common as c;
|
||||
use crate::ty::internal::Value;
|
||||
|
||||
use super::{JITContext, ValueTag};
|
||||
use super::JITContext;
|
||||
|
||||
pub trait JITCompile {
|
||||
fn compile(
|
||||
&self,
|
||||
ctx: &mut JITContext,
|
||||
builder: &mut FunctionBuilder,
|
||||
block: Block,
|
||||
) -> ir::Value;
|
||||
fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot;
|
||||
}
|
||||
|
||||
impl JITCompile for Attrs {
|
||||
fn compile(
|
||||
&self,
|
||||
ctx: &mut JITContext,
|
||||
builder: &mut FunctionBuilder,
|
||||
block: Block,
|
||||
) -> ir::Value {
|
||||
fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl JITCompile for List {
|
||||
fn compile(
|
||||
&self,
|
||||
ctx: &mut JITContext,
|
||||
builder: &mut FunctionBuilder,
|
||||
block: Block,
|
||||
) -> ir::Value {
|
||||
fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl JITCompile for HasAttr {
|
||||
fn compile(
|
||||
&self,
|
||||
ctx: &mut JITContext,
|
||||
builder: &mut FunctionBuilder,
|
||||
block: Block,
|
||||
) -> ir::Value {
|
||||
fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl JITCompile for BinOp {
|
||||
fn compile(
|
||||
&self,
|
||||
ctx: &mut JITContext,
|
||||
builder: &mut FunctionBuilder,
|
||||
block: Block,
|
||||
) -> ir::Value {
|
||||
fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot {
|
||||
use BinOpKind::*;
|
||||
let lhs = self.lhs.compile(ctx, builder, block);
|
||||
let rhs = self.rhs.compile(ctx, builder, block);
|
||||
let lhs = self.lhs.compile(ctx, engine, env);
|
||||
let rhs = self.rhs.compile(ctx, engine, env);
|
||||
ctx.force(lhs, engine, env);
|
||||
ctx.force(rhs, engine, env);
|
||||
let lhs_tag = ctx.get_tag(lhs);
|
||||
let rhs_tag = ctx.get_tag(rhs);
|
||||
let tag = ctx
|
||||
.func_builder
|
||||
.build_int_add(
|
||||
lhs_tag.const_shl(ctx.helpers.const_int(8)),
|
||||
rhs_tag,
|
||||
"calc_tag",
|
||||
)
|
||||
.unwrap();
|
||||
let ret = ctx.context.append_basic_block(func, "fallback");
|
||||
let res = ctx
|
||||
.func_builder
|
||||
.build_alloca(ctx.helpers.value_type, "res_alloca")
|
||||
.unwrap();
|
||||
let eq = ctx.builder.ins().icmp(IntCC::Equal, lhs_tag, rhs_tag);
|
||||
|
||||
let eq_block = ctx.builder.create_block();
|
||||
let neq_block = ctx.builder.create_block();
|
||||
let exit_block = ctx.builder.create_block();
|
||||
ctx.builder.ins().brif(eq, eq_block, [], neq_block, []);
|
||||
|
||||
match self.kind {
|
||||
Add => {
|
||||
let int_int = ctx.context.append_basic_block(func, "int_int");
|
||||
let int_float = ctx.context.append_basic_block(func, "int_float");
|
||||
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.func_builder
|
||||
.build_switch(
|
||||
tag,
|
||||
fallback,
|
||||
&[
|
||||
(
|
||||
ctx.helpers.const_int(((Int as i64) << 8) + Int as i64),
|
||||
int_int,
|
||||
),
|
||||
(
|
||||
ctx.helpers.const_int(((Int as i64) << 8) + Float as i64),
|
||||
int_float,
|
||||
),
|
||||
(
|
||||
ctx.helpers.const_int(((Float as i64) << 8) + Int as i64),
|
||||
float_int,
|
||||
),
|
||||
(
|
||||
ctx.helpers.const_int(((Float as i64) << 8) + Float as i64),
|
||||
float_float,
|
||||
),
|
||||
],
|
||||
)
|
||||
.unwrap();
|
||||
ctx.func_builder.position_at_end(int_int);
|
||||
let val = ctx
|
||||
.func_builder
|
||||
.build_int_add(ctx.get_int(lhs), ctx.get_int(rhs), "add")
|
||||
.unwrap();
|
||||
ctx.func_builder
|
||||
.build_store(res, ctx.helpers.new_value(Int, val.into()))
|
||||
.unwrap();
|
||||
ctx.func_builder.position_at_end(int_float);
|
||||
let val = ctx
|
||||
.func_builder
|
||||
.build_float_add(
|
||||
ctx.func_builder
|
||||
.build_signed_int_to_float(
|
||||
ctx.get_int(lhs),
|
||||
ctx.helpers.float_type,
|
||||
"lhs_to_float",
|
||||
)
|
||||
.unwrap(),
|
||||
ctx.get_float(rhs),
|
||||
"add",
|
||||
)
|
||||
.unwrap();
|
||||
ctx.func_builder
|
||||
.build_store(res, ctx.helpers.new_value(Float, val.into()))
|
||||
.unwrap();
|
||||
ctx.func_builder.position_at_end(float_int);
|
||||
let val = ctx
|
||||
.func_builder
|
||||
.build_float_add(
|
||||
ctx.get_float(lhs),
|
||||
ctx.func_builder
|
||||
.build_signed_int_to_float(
|
||||
ctx.get_int(rhs),
|
||||
ctx.helpers.float_type,
|
||||
"rhs_to_float",
|
||||
)
|
||||
.unwrap(),
|
||||
"add",
|
||||
)
|
||||
.unwrap();
|
||||
ctx.func_builder
|
||||
.build_store(res, ctx.helpers.new_value(Float, val.into()))
|
||||
.unwrap();
|
||||
ctx.func_builder.position_at_end(int_int);
|
||||
let val = ctx
|
||||
.func_builder
|
||||
.build_float_add(ctx.get_float(lhs), ctx.get_float(rhs), "add")
|
||||
.unwrap();
|
||||
ctx.func_builder
|
||||
.build_store(res, ctx.helpers.new_value(Float, val.into()))
|
||||
.unwrap();
|
||||
ctx.func_builder.position_at_end(fallback);
|
||||
ctx.builder.switch_to_block(eq_block);
|
||||
let default_block = ctx.builder.create_block();
|
||||
let int_block = ctx.builder.create_block();
|
||||
let float_block = ctx.builder.create_block();
|
||||
let float_check_block = ctx.builder.create_block();
|
||||
|
||||
let is_int = ctx
|
||||
.builder
|
||||
.ins()
|
||||
.icmp_imm(IntCC::Equal, lhs_tag, Value::INT as i64);
|
||||
ctx.builder
|
||||
.ins()
|
||||
.brif(is_int, int_block, [], float_check_block, []);
|
||||
|
||||
ctx.builder.switch_to_block(int_block);
|
||||
let lhs_value = ctx.get_small_value(types::I64, lhs);
|
||||
let rhs_value = ctx.get_small_value(types::I64, rhs);
|
||||
let result = ctx.builder.ins().iadd(lhs_value, rhs_value);
|
||||
ctx.builder.ins().stack_store(lhs_tag, lhs, 0);
|
||||
ctx.builder.ins().stack_store(result, lhs, 8);
|
||||
ctx.builder.ins().jump(exit_block, &[]);
|
||||
|
||||
// FIXME: Non-float
|
||||
ctx.builder.switch_to_block(float_check_block);
|
||||
let is_float =
|
||||
ctx.builder
|
||||
.ins()
|
||||
.icmp_imm(IntCC::Equal, lhs_tag, Value::FLOAT as i64);
|
||||
ctx.builder
|
||||
.ins()
|
||||
.brif(is_float, float_block, [], default_block, []);
|
||||
|
||||
ctx.builder.switch_to_block(float_block);
|
||||
let lhs_value = ctx.get_small_value(types::F64, lhs);
|
||||
let rhs_value = ctx.get_small_value(types::F64, rhs);
|
||||
let result = ctx.builder.ins().fadd(lhs_value, rhs_value);
|
||||
ctx.builder.ins().stack_store(lhs_tag, lhs, 0);
|
||||
ctx.builder.ins().stack_store(result, lhs, 8);
|
||||
ctx.builder.ins().jump(exit_block, &[]);
|
||||
|
||||
// FIXME: finish this
|
||||
ctx.builder.switch_to_block(default_block);
|
||||
ctx.builder.ins().trap(TrapCode::unwrap_user(1));
|
||||
|
||||
ctx.builder.switch_to_block(neq_block);
|
||||
ctx.builder.ins().trap(TrapCode::unwrap_user(1));
|
||||
|
||||
ctx.builder.seal_block(default_block);
|
||||
ctx.builder.seal_block(int_block);
|
||||
ctx.builder.seal_block(float_check_block);
|
||||
ctx.builder.seal_block(float_block);
|
||||
}
|
||||
Sub => {
|
||||
ctx.builder.switch_to_block(eq_block);
|
||||
let default_block = ctx.builder.create_block();
|
||||
let int_block = ctx.builder.create_block();
|
||||
let float_block = ctx.builder.create_block();
|
||||
let float_check_block = ctx.builder.create_block();
|
||||
|
||||
let is_int = ctx
|
||||
.builder
|
||||
.ins()
|
||||
.icmp_imm(IntCC::Equal, lhs_tag, Value::INT as i64);
|
||||
ctx.builder
|
||||
.ins()
|
||||
.brif(is_int, int_block, [], float_check_block, []);
|
||||
|
||||
ctx.builder.switch_to_block(int_block);
|
||||
let lhs_value = ctx.get_small_value(types::I64, lhs);
|
||||
let rhs_value = ctx.get_small_value(types::I64, rhs);
|
||||
let result = ctx.builder.ins().isub(lhs_value, rhs_value);
|
||||
ctx.builder.ins().stack_store(lhs_tag, lhs, 0);
|
||||
ctx.builder.ins().stack_store(result, lhs, 8);
|
||||
ctx.builder.ins().jump(exit_block, &[]);
|
||||
|
||||
// FIXME: Non-float
|
||||
ctx.builder.switch_to_block(float_check_block);
|
||||
let is_float =
|
||||
ctx.builder
|
||||
.ins()
|
||||
.icmp_imm(IntCC::Equal, lhs_tag, Value::FLOAT as i64);
|
||||
ctx.builder
|
||||
.ins()
|
||||
.brif(is_float, float_block, [], default_block, []);
|
||||
|
||||
ctx.builder.switch_to_block(float_block);
|
||||
let lhs_value = ctx.get_small_value(types::F64, lhs);
|
||||
let rhs_value = ctx.get_small_value(types::F64, rhs);
|
||||
let result = ctx.builder.ins().fsub(lhs_value, rhs_value);
|
||||
ctx.builder.ins().stack_store(lhs_tag, lhs, 0);
|
||||
ctx.builder.ins().stack_store(result, lhs, 8);
|
||||
ctx.builder.ins().jump(exit_block, &[]);
|
||||
|
||||
// FIXME: finish this
|
||||
ctx.builder.switch_to_block(default_block);
|
||||
ctx.builder.ins().trap(TrapCode::unwrap_user(1));
|
||||
|
||||
ctx.builder.switch_to_block(neq_block);
|
||||
ctx.builder.ins().trap(TrapCode::unwrap_user(1));
|
||||
|
||||
ctx.builder.seal_block(default_block);
|
||||
ctx.builder.seal_block(int_block);
|
||||
ctx.builder.seal_block(float_check_block);
|
||||
ctx.builder.seal_block(float_block);
|
||||
}
|
||||
Div => {
|
||||
ctx.builder.switch_to_block(eq_block);
|
||||
let default_block = ctx.builder.create_block();
|
||||
let int_block = ctx.builder.create_block();
|
||||
let float_block = ctx.builder.create_block();
|
||||
let float_check_block = ctx.builder.create_block();
|
||||
|
||||
let is_int = ctx
|
||||
.builder
|
||||
.ins()
|
||||
.icmp_imm(IntCC::Equal, lhs_tag, Value::INT as i64);
|
||||
ctx.builder
|
||||
.ins()
|
||||
.brif(is_int, int_block, [], float_check_block, []);
|
||||
|
||||
ctx.builder.switch_to_block(int_block);
|
||||
let lhs_value = ctx.get_small_value(types::I64, lhs);
|
||||
let rhs_value = ctx.get_small_value(types::I64, rhs);
|
||||
let result = ctx.builder.ins().sdiv(lhs_value, rhs_value);
|
||||
ctx.builder.ins().stack_store(lhs_tag, lhs, 0);
|
||||
ctx.builder.ins().stack_store(result, lhs, 8);
|
||||
ctx.builder.ins().jump(exit_block, &[]);
|
||||
|
||||
// FIXME: Non-float
|
||||
ctx.builder.switch_to_block(float_check_block);
|
||||
let is_float =
|
||||
ctx.builder
|
||||
.ins()
|
||||
.icmp_imm(IntCC::Equal, lhs_tag, Value::FLOAT as i64);
|
||||
ctx.builder
|
||||
.ins()
|
||||
.brif(is_float, float_block, [], default_block, []);
|
||||
|
||||
ctx.builder.switch_to_block(float_block);
|
||||
let lhs_value = ctx.get_small_value(types::F64, lhs);
|
||||
let rhs_value = ctx.get_small_value(types::F64, rhs);
|
||||
let result = ctx.builder.ins().fdiv(lhs_value, rhs_value);
|
||||
ctx.builder.ins().stack_store(lhs_tag, lhs, 0);
|
||||
ctx.builder.ins().stack_store(result, lhs, 8);
|
||||
ctx.builder.ins().jump(exit_block, &[]);
|
||||
|
||||
// FIXME: finish this
|
||||
ctx.builder.switch_to_block(default_block);
|
||||
ctx.builder.ins().trap(TrapCode::unwrap_user(1));
|
||||
|
||||
ctx.builder.switch_to_block(neq_block);
|
||||
ctx.builder.ins().trap(TrapCode::unwrap_user(1));
|
||||
|
||||
ctx.builder.seal_block(default_block);
|
||||
ctx.builder.seal_block(int_block);
|
||||
ctx.builder.seal_block(float_check_block);
|
||||
ctx.builder.seal_block(float_block);
|
||||
}
|
||||
And => {
|
||||
ctx.builder.switch_to_block(eq_block);
|
||||
let bool_block = ctx.builder.create_block();
|
||||
let non_bool_block = ctx.builder.create_block();
|
||||
|
||||
let is_bool = ctx
|
||||
.builder
|
||||
.ins()
|
||||
.icmp_imm(IntCC::Equal, lhs_tag, Value::BOOL as i64);
|
||||
ctx.builder
|
||||
.ins()
|
||||
.brif(is_bool, bool_block, [], non_bool_block, []);
|
||||
|
||||
ctx.builder.switch_to_block(bool_block);
|
||||
let lhs_value = ctx.get_small_value(types::I64, lhs);
|
||||
let rhs_value = ctx.get_small_value(types::I64, rhs);
|
||||
let result = ctx.builder.ins().band(lhs_value, rhs_value);
|
||||
ctx.builder.ins().stack_store(lhs_tag, lhs, 0);
|
||||
ctx.builder.ins().stack_store(result, lhs, 8);
|
||||
ctx.builder.ins().jump(exit_block, []);
|
||||
|
||||
ctx.builder.switch_to_block(non_bool_block);
|
||||
ctx.builder.ins().trap(TrapCode::unwrap_user(1));
|
||||
|
||||
ctx.builder.switch_to_block(neq_block);
|
||||
ctx.builder.ins().trap(TrapCode::unwrap_user(1));
|
||||
|
||||
ctx.builder.seal_block(bool_block);
|
||||
ctx.builder.seal_block(non_bool_block);
|
||||
}
|
||||
Or => {
|
||||
let bool_bool = ctx.context.append_basic_block(func, "int_int");
|
||||
let fallback = ctx.context.append_basic_block(func, "fallback");
|
||||
ctx.func_builder
|
||||
.build_switch(
|
||||
tag,
|
||||
fallback,
|
||||
&[(
|
||||
ctx.helpers.const_int(((Bool as i64) << 8) + Bool as i64),
|
||||
bool_bool,
|
||||
)],
|
||||
)
|
||||
.unwrap();
|
||||
ctx.func_builder.position_at_end(bool_bool);
|
||||
let val = ctx
|
||||
.func_builder
|
||||
.build_or(ctx.get_bool(lhs), ctx.get_bool(rhs), "or")
|
||||
.unwrap();
|
||||
ctx.func_builder
|
||||
.build_store(res, ctx.helpers.new_value(Bool, val.into()))
|
||||
.unwrap();
|
||||
ctx.func_builder.position_at_end(fallback);
|
||||
ctx.builder.switch_to_block(eq_block);
|
||||
let bool_block = ctx.builder.create_block();
|
||||
let non_bool_block = ctx.builder.create_block();
|
||||
|
||||
let is_bool = ctx
|
||||
.builder
|
||||
.ins()
|
||||
.icmp_imm(IntCC::Equal, lhs_tag, Value::BOOL as i64);
|
||||
ctx.builder
|
||||
.ins()
|
||||
.brif(is_bool, bool_block, [], non_bool_block, []);
|
||||
|
||||
ctx.builder.switch_to_block(bool_block);
|
||||
let lhs_value = ctx.get_small_value(types::I64, lhs);
|
||||
let rhs_value = ctx.get_small_value(types::I64, rhs);
|
||||
let result = ctx.builder.ins().bor(lhs_value, rhs_value);
|
||||
ctx.builder.ins().stack_store(lhs_tag, lhs, 0);
|
||||
ctx.builder.ins().stack_store(result, lhs, 8);
|
||||
ctx.builder.ins().jump(exit_block, []);
|
||||
|
||||
ctx.builder.switch_to_block(non_bool_block);
|
||||
ctx.builder.ins().trap(TrapCode::unwrap_user(1));
|
||||
|
||||
ctx.builder.switch_to_block(neq_block);
|
||||
ctx.builder.ins().trap(TrapCode::unwrap_user(1));
|
||||
|
||||
ctx.builder.seal_block(bool_block);
|
||||
ctx.builder.seal_block(non_bool_block);
|
||||
}
|
||||
Eq => {
|
||||
ctx.builder.switch_to_block(eq_block);
|
||||
ctx.eq(lhs, rhs);
|
||||
ctx.builder.ins().jump(exit_block, []);
|
||||
ctx.builder.switch_to_block(neq_block);
|
||||
ctx.eq(lhs, rhs);
|
||||
ctx.builder.ins().jump(exit_block, []);
|
||||
}
|
||||
_ => todo!(),
|
||||
}
|
||||
ctx.func_builder.position_at_end(ret);
|
||||
ctx.func_builder
|
||||
.build_load(ctx.helpers.value_type, res, "load_res")
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap()
|
||||
|
||||
ctx.builder.seal_block(exit_block);
|
||||
ctx.builder.seal_block(eq_block);
|
||||
ctx.builder.seal_block(neq_block);
|
||||
ctx.builder.switch_to_block(exit_block);
|
||||
|
||||
lhs
|
||||
}
|
||||
}
|
||||
|
||||
impl JITCompile for UnOp {
|
||||
fn compile(
|
||||
&self,
|
||||
ctx: &mut JITContext,
|
||||
builder: &mut FunctionBuilder,
|
||||
block: Block,
|
||||
) -> ir::Value {
|
||||
todo!();
|
||||
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
|
||||
.func_builder
|
||||
.build_alloca(ctx.helpers.value_type, "res_alloca")
|
||||
.unwrap();
|
||||
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()
|
||||
.unwrap()
|
||||
fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl JITCompile for Attr {
|
||||
fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot {
|
||||
use Attr::*;
|
||||
match self {
|
||||
Str(string) => ctx.create_string(string),
|
||||
Dynamic(ir) => ir.compile(ctx, engine, env),
|
||||
Strs(strings) => strings.compile(ctx, engine, env)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl JITCompile for Select {
|
||||
fn compile(
|
||||
&self,
|
||||
ctx: &mut JITContext,
|
||||
builder: &mut FunctionBuilder,
|
||||
block: Block,
|
||||
) -> ir::Value {
|
||||
todo!()
|
||||
fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot {
|
||||
let val = self.expr.compile(ctx, engine, env);
|
||||
let attrpath = ctx.alloc_array(self.attrpath.len());
|
||||
for (i, attr) in self.attrpath.iter().enumerate() {
|
||||
let arg = attr.compile(ctx, engine, env);
|
||||
let tag = ctx.builder.ins().stack_load(types::I64, arg, 0);
|
||||
let val0 = ctx.builder.ins().stack_load(types::I64, arg, 8);
|
||||
let val1 = ctx.builder.ins().stack_load(types::I64, arg, 16);
|
||||
let val2 = ctx.builder.ins().stack_load(types::I64, arg, 24);
|
||||
ctx.builder
|
||||
.ins()
|
||||
.store(MemFlags::new(), tag, attrpath, i as i32 * 32);
|
||||
ctx.builder
|
||||
.ins()
|
||||
.store(MemFlags::new(), val0, attrpath, i as i32 * 32 + 8);
|
||||
ctx.builder
|
||||
.ins()
|
||||
.store(MemFlags::new(), val1, attrpath, i as i32 * 32 + 16);
|
||||
ctx.builder
|
||||
.ins()
|
||||
.store(MemFlags::new(), val2, attrpath, i as i32 * 32 + 24);
|
||||
}
|
||||
ctx.select(val, attrpath, self.attrpath.len(), engine, env);
|
||||
val
|
||||
}
|
||||
}
|
||||
|
||||
impl JITCompile for If {
|
||||
fn compile(
|
||||
&self,
|
||||
ctx: &mut JITContext,
|
||||
builder: &mut FunctionBuilder,
|
||||
block: Block,
|
||||
) -> ir::Value {
|
||||
todo!()
|
||||
fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot {
|
||||
let cond = self.cond.compile(ctx, engine, env);
|
||||
ctx.force(cond, engine, env);
|
||||
let cond_type = ctx.builder.ins().stack_load(types::I64, cond, 0);
|
||||
let cond_value = ctx.builder.ins().stack_load(types::I64, cond, 8);
|
||||
|
||||
let true_block = ctx.builder.create_block();
|
||||
let false_block = ctx.builder.create_block();
|
||||
let exit_block = ctx.builder.create_block();
|
||||
let error_block = ctx.builder.create_block();
|
||||
let judge_block = ctx.builder.create_block();
|
||||
let slot = StackSlotData::new(StackSlotKind::ExplicitSlot, 32, 3);
|
||||
let slot = ctx.builder.create_sized_stack_slot(slot);
|
||||
|
||||
let is_bool = ctx
|
||||
.builder
|
||||
.ins()
|
||||
.icmp_imm(IntCC::Equal, cond_type, Value::BOOL as i64);
|
||||
ctx.builder
|
||||
.ins()
|
||||
.brif(is_bool, judge_block, [], error_block, []);
|
||||
|
||||
ctx.builder.switch_to_block(judge_block);
|
||||
ctx.builder
|
||||
.ins()
|
||||
.brif(cond_value, true_block, [], false_block, []);
|
||||
|
||||
ctx.builder.switch_to_block(true_block);
|
||||
let ret = self.consq.compile(ctx, engine, env);
|
||||
let tag = ctx.builder.ins().stack_load(types::I64, ret, 0);
|
||||
let val0 = ctx.builder.ins().stack_load(types::I64, ret, 8);
|
||||
let val1 = ctx.builder.ins().stack_load(types::I64, ret, 16);
|
||||
let val2 = ctx.builder.ins().stack_load(types::I64, ret, 24);
|
||||
ctx.builder.ins().stack_store(tag, slot, 0);
|
||||
ctx.builder.ins().stack_store(val0, slot, 8);
|
||||
ctx.builder.ins().stack_store(val1, slot, 16);
|
||||
ctx.builder.ins().stack_store(val2, slot, 24);
|
||||
ctx.builder.ins().jump(exit_block, []);
|
||||
|
||||
ctx.builder.switch_to_block(false_block);
|
||||
let ret = self.alter.compile(ctx, engine, env);
|
||||
let tag = ctx.builder.ins().stack_load(types::I64, ret, 0);
|
||||
let val0 = ctx.builder.ins().stack_load(types::I64, ret, 8);
|
||||
let val1 = ctx.builder.ins().stack_load(types::I64, ret, 16);
|
||||
let val2 = ctx.builder.ins().stack_load(types::I64, ret, 24);
|
||||
ctx.builder.ins().stack_store(tag, slot, 0);
|
||||
ctx.builder.ins().stack_store(val0, slot, 8);
|
||||
ctx.builder.ins().stack_store(val1, slot, 16);
|
||||
ctx.builder.ins().stack_store(val2, slot, 24);
|
||||
ctx.builder.ins().jump(exit_block, []);
|
||||
|
||||
ctx.builder.switch_to_block(error_block);
|
||||
ctx.builder.ins().trap(TrapCode::unwrap_user(1));
|
||||
|
||||
ctx.builder.switch_to_block(exit_block);
|
||||
slot
|
||||
}
|
||||
}
|
||||
|
||||
impl JITCompile for LoadFunc {
|
||||
fn compile(
|
||||
&self,
|
||||
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(),
|
||||
)
|
||||
fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot {
|
||||
let slot = StackSlotData::new(StackSlotKind::ExplicitSlot, 32, 3);
|
||||
let slot = ctx.builder.create_sized_stack_slot(slot);
|
||||
let tag = ctx.builder.ins().iconst(types::I64, Value::FUNC as i64);
|
||||
let val = ctx.builder.ins().iconst(types::I64, self.idx as i64);
|
||||
ctx.builder.ins().stack_store(tag, slot, 0);
|
||||
ctx.builder.ins().stack_store(val, slot, 8);
|
||||
slot
|
||||
}
|
||||
}
|
||||
|
||||
impl JITCompile for Call {
|
||||
fn compile(
|
||||
&self,
|
||||
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
|
||||
.func_builder
|
||||
.build_call(
|
||||
ctx.helpers.alloc_array,
|
||||
&[ctx.helpers.const_ptr_int(self.args.len()).into()],
|
||||
"alloc_args",
|
||||
)
|
||||
.unwrap()
|
||||
.try_as_basic_value()
|
||||
.unwrap_left()
|
||||
.into_pointer_value();
|
||||
fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot {
|
||||
let func = self.func.compile(ctx, engine, env);
|
||||
ctx.force(func, engine, env);
|
||||
let args = ctx.alloc_array(self.args.len());
|
||||
for (i, arg) in self.args.iter().enumerate() {
|
||||
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();
|
||||
let arg = arg.compile(ctx, engine, env);
|
||||
let tag = ctx.builder.ins().stack_load(types::I64, arg, 0);
|
||||
let val0 = ctx.builder.ins().stack_load(types::I64, arg, 8);
|
||||
let val1 = ctx.builder.ins().stack_load(types::I64, arg, 16);
|
||||
let val2 = ctx.builder.ins().stack_load(types::I64, arg, 24);
|
||||
ctx.builder
|
||||
.ins()
|
||||
.store(MemFlags::new(), tag, args, i as i32 * 32);
|
||||
ctx.builder
|
||||
.ins()
|
||||
.store(MemFlags::new(), val0, args, i as i32 * 32 + 8);
|
||||
ctx.builder
|
||||
.ins()
|
||||
.store(MemFlags::new(), val1, args, i as i32 * 32 + 16);
|
||||
ctx.builder
|
||||
.ins()
|
||||
.store(MemFlags::new(), val2, args, i as i32 * 32 + 24);
|
||||
}
|
||||
ctx.func_builder
|
||||
.build_call(
|
||||
ctx.helpers.call,
|
||||
&[
|
||||
self.func.compile(ctx, builder, block).into(),
|
||||
args.into(),
|
||||
ctx.helpers.const_ptr_int(self.args.len()).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()
|
||||
.into_struct_value()
|
||||
ctx.call(func, args, self.args.len(), engine, env);
|
||||
func
|
||||
}
|
||||
}
|
||||
|
||||
impl JITCompile for Let {
|
||||
fn compile(
|
||||
&self,
|
||||
ctx: &mut JITContext,
|
||||
builder: &mut FunctionBuilder,
|
||||
block: Block,
|
||||
) -> ir::Value {
|
||||
fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
impl JITCompile for With {
|
||||
fn compile(
|
||||
&self,
|
||||
ctx: &mut JITContext,
|
||||
builder: &mut FunctionBuilder,
|
||||
block: Block,
|
||||
) -> ir::Value {
|
||||
todo!()
|
||||
fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl JITCompile for Assert {
|
||||
fn compile(
|
||||
&self,
|
||||
ctx: &mut JITContext,
|
||||
builder: &mut FunctionBuilder,
|
||||
block: Block,
|
||||
) -> ir::Value {
|
||||
fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl JITCompile for ConcatStrings {
|
||||
fn compile(
|
||||
&self,
|
||||
ctx: &mut JITContext,
|
||||
builder: &mut FunctionBuilder,
|
||||
block: Block,
|
||||
) -> ir::Value {
|
||||
fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl JITCompile for Const {
|
||||
fn compile(
|
||||
&self,
|
||||
ctx: &mut JITContext,
|
||||
builder: &mut FunctionBuilder,
|
||||
block: Block,
|
||||
) -> ir::Value {
|
||||
fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot {
|
||||
use c::Const::*;
|
||||
let slot = StackSlotData::new(StackSlotKind::ExplicitSlot, 32, 3);
|
||||
let slot = ctx.builder.create_sized_stack_slot(slot);
|
||||
match self.val {
|
||||
Bool(x) => ctx.helpers.new_bool(x),
|
||||
Int(x) => ctx.helpers.new_int(x),
|
||||
Float(x) => ctx.helpers.new_float(x),
|
||||
Null => ctx.helpers.new_null(),
|
||||
Bool(x) => {
|
||||
let tag = ctx.builder.ins().iconst(types::I64, Value::BOOL as i64);
|
||||
let val = ctx.builder.ins().iconst(types::I64, x as i64);
|
||||
ctx.builder.ins().stack_store(tag, slot, 0);
|
||||
ctx.builder.ins().stack_store(val, slot, 8);
|
||||
}
|
||||
Int(x) => {
|
||||
let tag = ctx.builder.ins().iconst(types::I64, Value::INT as i64);
|
||||
let val = ctx.builder.ins().iconst(types::I64, x as i64);
|
||||
ctx.builder.ins().stack_store(tag, slot, 0);
|
||||
ctx.builder.ins().stack_store(val, slot, 8);
|
||||
}
|
||||
Float(x) => {
|
||||
let tag = ctx.builder.ins().iconst(types::I64, Value::FLOAT as i64);
|
||||
let val = ctx.builder.ins().f64const(x);
|
||||
ctx.builder.ins().stack_store(tag, slot, 0);
|
||||
ctx.builder.ins().stack_store(val, slot, 8);
|
||||
}
|
||||
Null => {
|
||||
let tag = ctx.builder.ins().iconst(types::I64, Value::NULL as i64);
|
||||
ctx.builder.ins().stack_store(tag, slot, 0);
|
||||
}
|
||||
}
|
||||
slot
|
||||
}
|
||||
}
|
||||
|
||||
impl JITCompile for String {
|
||||
fn compile(
|
||||
&self,
|
||||
ctx: &mut JITContext,
|
||||
builder: &mut FunctionBuilder,
|
||||
block: Block,
|
||||
) -> ir::Value {
|
||||
impl JITCompile for Str {
|
||||
fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl JITCompile for Var {
|
||||
fn compile(
|
||||
&self,
|
||||
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();
|
||||
ctx.func_builder
|
||||
.build_direct_call(
|
||||
ctx.helpers.lookup,
|
||||
&[
|
||||
env.into(),
|
||||
ctx.const_ptr(ptr as *const ()).into(),
|
||||
ctx.helpers.const_ptr_int(len).into(),
|
||||
],
|
||||
"lookup",
|
||||
)
|
||||
.unwrap()
|
||||
.try_as_basic_value()
|
||||
.unwrap_left()
|
||||
.try_into()
|
||||
.unwrap()
|
||||
fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl JITCompile for Arg {
|
||||
fn compile(
|
||||
&self,
|
||||
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(),
|
||||
arg.into(),
|
||||
],
|
||||
"lookup_arg",
|
||||
)
|
||||
.unwrap();
|
||||
ctx.func_builder
|
||||
.build_load(ctx.helpers.value_type, arg, "load_arg")
|
||||
.unwrap()
|
||||
.into_struct_value()
|
||||
fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot {
|
||||
ctx.lookup_arg(env, self.level)
|
||||
}
|
||||
}
|
||||
|
||||
impl JITCompile for LetVar {
|
||||
fn compile(
|
||||
&self,
|
||||
ctx: &mut JITContext,
|
||||
builder: &mut FunctionBuilder,
|
||||
block: Block,
|
||||
) -> ir::Value {
|
||||
fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
impl JITCompile for Thunk {
|
||||
fn compile(
|
||||
&self,
|
||||
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(),
|
||||
)
|
||||
fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot {
|
||||
let slot = StackSlotData::new(StackSlotKind::ExplicitSlot, 32, 3);
|
||||
let slot = ctx.builder.create_sized_stack_slot(slot);
|
||||
let tag = ctx.builder.ins().iconst(types::I64, Value::THUNK as i64);
|
||||
let val = ctx.builder.ins().iconst(types::I64, self.idx as i64);
|
||||
ctx.builder.ins().stack_store(tag, slot, 0);
|
||||
ctx.builder.ins().stack_store(val, slot, 8);
|
||||
slot
|
||||
}
|
||||
}
|
||||
|
||||
impl JITCompile for Path {
|
||||
fn compile(
|
||||
&self,
|
||||
ctx: &mut JITContext,
|
||||
builder: &mut FunctionBuilder,
|
||||
block: Block,
|
||||
) -> ir::Value {
|
||||
fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,193 +1,85 @@
|
||||
use std::alloc::Layout;
|
||||
use std::alloc::alloc;
|
||||
use core::ptr::NonNull;
|
||||
use core::{slice, str};
|
||||
|
||||
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 std::mem::MaybeUninit;
|
||||
use std::ptr::NonNull;
|
||||
|
||||
use crate::env::Env;
|
||||
use crate::eval::Engine;
|
||||
use crate::ty::internal::Value;
|
||||
|
||||
use super::{JITContext, JITValue, JITValueData, ValueTag};
|
||||
|
||||
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 call: FuncId,
|
||||
pub lookup_arg: FuncId,
|
||||
pub lookup: FuncId,
|
||||
pub force: FuncId,
|
||||
|
||||
pub alloc_array: FuncId,
|
||||
}
|
||||
|
||||
impl Helpers {
|
||||
pub fn new(
|
||||
ctx: &codegen::Context,
|
||||
module: &mut dyn Module,
|
||||
) -> Self {
|
||||
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 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();
|
||||
|
||||
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,
|
||||
float_type,
|
||||
bool_type,
|
||||
ptr_int_type,
|
||||
ptr_type,
|
||||
value_type,
|
||||
func_sig,
|
||||
|
||||
call,
|
||||
lookup_arg,
|
||||
lookup,
|
||||
force,
|
||||
|
||||
alloc_array,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_value(&self, tag: ValueTag, data: BasicValueEnum) -> StructValue {
|
||||
self.value_type.const_named_struct(&[
|
||||
self.const_int(tag as i64).into(),
|
||||
data,
|
||||
self.int_type.const_zero().into(),
|
||||
])
|
||||
}
|
||||
|
||||
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 {
|
||||
self.int_type.const_int(int as _, false)
|
||||
}
|
||||
|
||||
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 {
|
||||
self.float_type.const_float(float)
|
||||
}
|
||||
|
||||
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 {
|
||||
self.bool_type.const_int(bool as _, false)
|
||||
}
|
||||
|
||||
pub fn new_bool(&self, bool: bool) -> StructValue {
|
||||
self.new_value(ValueTag::Bool, self.const_bool(bool).into())
|
||||
}
|
||||
|
||||
pub fn new_null(&self) -> StructValue {
|
||||
self.new_value(ValueTag::Null, self.int_type.const_zero().into())
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" fn helper_call(
|
||||
func: JITValue,
|
||||
args: *mut JITValue,
|
||||
len: usize,
|
||||
mut engine: NonNull<Engine>,
|
||||
mut env: NonNull<Env>,
|
||||
) -> JITValue {
|
||||
let mut func = Value::from(func);
|
||||
pub extern "C" fn helper_call(
|
||||
func: &mut Value,
|
||||
args_ptr: *mut Value,
|
||||
args_len: usize,
|
||||
engine: &mut Engine,
|
||||
env: &mut Env,
|
||||
) {
|
||||
// TODO: Error Handling
|
||||
let args = core::ptr::slice_from_raw_parts_mut(args, len);
|
||||
let args = core::ptr::slice_from_raw_parts_mut(args_ptr, args_len);
|
||||
let args = unsafe { Box::from_raw(args) };
|
||||
func.call(
|
||||
args.into_iter().map(Value::from).collect(),
|
||||
unsafe { engine.as_mut() },
|
||||
unsafe { env.as_mut() },
|
||||
engine,
|
||||
env
|
||||
)
|
||||
.unwrap();
|
||||
func.into()
|
||||
}
|
||||
|
||||
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()
|
||||
pub extern "C" fn helper_lookup_arg(env: &Env, level: usize, ret: &mut MaybeUninit<Value>) {
|
||||
ret.write(env.lookup_arg(level as usize));
|
||||
}
|
||||
|
||||
extern "C" fn helper_lookup(env: NonNull<Env>, ptr: *const u8, len: usize) -> JITValue {
|
||||
let env = unsafe { env.as_ref() };
|
||||
pub extern "C" fn helper_lookup(env: &Env, sym_ptr: *const u8, sym_len: usize, ret: &mut MaybeUninit<Value>) {
|
||||
// TODO: Error Handling
|
||||
let val: JITValue = env
|
||||
.lookup_with(unsafe { str::from_utf8_unchecked(slice::from_raw_parts(ptr, len)) })
|
||||
.unwrap()
|
||||
.clone()
|
||||
.into();
|
||||
val
|
||||
}
|
||||
|
||||
extern "C" fn helper_force(
|
||||
thunk: JITValue,
|
||||
vm: NonNull<Engine>,
|
||||
jit: *const JITContext,
|
||||
) -> JITValue {
|
||||
if !matches!(thunk.tag, ValueTag::Thunk) {
|
||||
return thunk;
|
||||
unsafe {
|
||||
ret.write(env
|
||||
.lookup_with(str::from_utf8_unchecked(slice::from_raw_parts(sym_ptr, sym_len)))
|
||||
.unwrap());
|
||||
}
|
||||
todo!()
|
||||
}
|
||||
|
||||
unsafe extern "C" fn helper_alloc_array(len: usize) -> *mut u8 {
|
||||
unsafe { alloc(Layout::array::<JITValue>(len).unwrap()) }
|
||||
pub extern "C" fn helper_select(val: &mut Value, path_ptr: *mut Value, path_len: usize, engine: &mut Engine, env: &mut Env) {
|
||||
let path = core::ptr::slice_from_raw_parts_mut(path_ptr, path_len);
|
||||
let path = unsafe { Box::from_raw(path) };
|
||||
val.select(path.into_iter().map(|mut val| {
|
||||
val.force(engine, env)?.coerce_to_string();
|
||||
Ok(val.unwrap_string())
|
||||
})).unwrap();
|
||||
}
|
||||
|
||||
pub extern "C" fn helper_select_with_default(val: &mut Value, path_ptr: *mut Value, path_len: usize, default: NonNull<Value>, engine: &mut Engine, env: &mut Env) {
|
||||
let path = core::ptr::slice_from_raw_parts_mut(path_ptr, path_len);
|
||||
let path = unsafe { Box::from_raw(path) };
|
||||
val.select_with_default(path.into_iter().map(|mut val| {
|
||||
val.force(engine, env)?.coerce_to_string();
|
||||
Ok(val.unwrap_string())
|
||||
}), unsafe { default.read() }).unwrap();
|
||||
}
|
||||
|
||||
pub extern "C" fn helper_force(
|
||||
thunk: &mut Value,
|
||||
engine: &mut Engine,
|
||||
env: &mut Env,
|
||||
) {
|
||||
thunk.force(engine, env).unwrap();
|
||||
}
|
||||
|
||||
pub extern "C" fn helper_eq(lhs: &mut Value, rhs: &Value) {
|
||||
lhs.eq(rhs);
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn helper_create_string(ptr: *const u8, len: usize, ret: &mut MaybeUninit<Value>) {
|
||||
unsafe {
|
||||
ret.write(Value::String(str::from_utf8_unchecked(slice::from_raw_parts(ptr, len)).to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn helper_alloc_array(len: usize) -> *mut u8 {
|
||||
unsafe { alloc(Layout::array::<Value>(len).unwrap()) }
|
||||
}
|
||||
|
||||
pub extern "C" fn helper_dbg(value: &Value) {
|
||||
// dbg!(value);
|
||||
println!("{value:?}")
|
||||
}
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
|
||||
use cranelift::codegen::ir::Function;
|
||||
use cranelift::codegen::ir::{self, ArgumentExtension, ArgumentPurpose, StackSlot};
|
||||
use cranelift::prelude::*;
|
||||
use cranelift::codegen::ir;
|
||||
use cranelift_module::{DataDescription, Linkage, Module};
|
||||
use cranelift_jit::{JITModule, JITBuilder};
|
||||
use cranelift_jit::{JITBuilder, JITModule};
|
||||
use cranelift_module::{FuncId, Linkage, Module};
|
||||
|
||||
use crate::engine::Engine;
|
||||
use crate::env::Env;
|
||||
@@ -17,116 +13,229 @@ mod compile;
|
||||
mod helpers;
|
||||
|
||||
pub use compile::JITCompile;
|
||||
use helpers::Helpers;
|
||||
use helpers::*;
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct ValueTag(u64);
|
||||
pub type JITFunc = unsafe extern "C" fn(*const Engine, *const Env, *mut Value);
|
||||
|
||||
#[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 struct JITContext<'comp, 'ctx> {
|
||||
pub compiler: &'comp mut JITCompiler,
|
||||
pub builder: FunctionBuilder<'ctx>,
|
||||
}
|
||||
|
||||
pub fn String(len: usize) -> Self {
|
||||
Self(len as u64 ^ (1 << 31))
|
||||
impl<'comp, 'ctx> JITContext<'comp, 'ctx> {
|
||||
fn new(compiler: &'comp mut JITCompiler, builder: FunctionBuilder<'ctx>) -> Self {
|
||||
Self { compiler, builder }
|
||||
}
|
||||
|
||||
pub fn is_str(&self) -> bool {
|
||||
self.0 >> 31 != 0
|
||||
fn alloc_array(&mut self, len: usize) -> ir::Value {
|
||||
let len = self
|
||||
.builder
|
||||
.ins()
|
||||
.iconst(self.compiler.ptr_type, len as i64);
|
||||
let alloc_array = self
|
||||
.compiler
|
||||
.module
|
||||
.declare_func_in_func(self.compiler.alloc_array, self.builder.func);
|
||||
let inst = self.builder.ins().call(alloc_array, &[len]);
|
||||
self.builder.inst_results(inst)[0]
|
||||
}
|
||||
|
||||
fn create_string(&mut self, string: &str) -> StackSlot {
|
||||
let ptr = self
|
||||
.builder
|
||||
.ins()
|
||||
.iconst(self.compiler.ptr_type, string.as_ptr() as i64);
|
||||
let len = self
|
||||
.builder
|
||||
.ins()
|
||||
.iconst(self.compiler.ptr_type, string.len() as i64);
|
||||
let create_string = self
|
||||
.compiler
|
||||
.module
|
||||
.declare_func_in_func(self.compiler.create_string, self.builder.func);
|
||||
let slot = StackSlotData::new(StackSlotKind::ExplicitSlot, 32, 3);
|
||||
let slot = self.builder.create_sized_stack_slot(slot);
|
||||
let ret = self
|
||||
.builder
|
||||
.ins()
|
||||
.stack_addr(self.compiler.ptr_type, slot, 0);
|
||||
self.builder.ins().call(create_string, &[ptr, len, ret]);
|
||||
slot
|
||||
}
|
||||
|
||||
fn dbg(&mut self, slot: StackSlot) {
|
||||
let ptr = self
|
||||
.builder
|
||||
.ins()
|
||||
.stack_addr(self.compiler.ptr_type, slot, 0);
|
||||
let dbg = self
|
||||
.compiler
|
||||
.module
|
||||
.declare_func_in_func(self.compiler.dbg, self.builder.func);
|
||||
self.builder.ins().call(dbg, &[ptr]);
|
||||
}
|
||||
|
||||
fn call(
|
||||
&mut self,
|
||||
func: StackSlot,
|
||||
args_ptr: ir::Value,
|
||||
args_len: usize,
|
||||
engine: ir::Value,
|
||||
env: ir::Value,
|
||||
) {
|
||||
let args_len = self
|
||||
.builder
|
||||
.ins()
|
||||
.iconst(self.compiler.ptr_type, args_len as i64);
|
||||
let call = self
|
||||
.compiler
|
||||
.module
|
||||
.declare_func_in_func(self.compiler.call, self.builder.func);
|
||||
let func = self
|
||||
.builder
|
||||
.ins()
|
||||
.stack_addr(self.compiler.ptr_type, func, 0);
|
||||
self.builder
|
||||
.ins()
|
||||
.call(call, &[func, args_ptr, args_len, engine, env]);
|
||||
}
|
||||
|
||||
fn lookup_arg(&mut self, env: ir::Value, idx: usize) -> StackSlot {
|
||||
let slot = StackSlotData::new(StackSlotKind::ExplicitSlot, 32, 3);
|
||||
let slot = self.builder.create_sized_stack_slot(slot);
|
||||
let lookup_arg = self
|
||||
.compiler
|
||||
.module
|
||||
.declare_func_in_func(self.compiler.lookup_arg, self.builder.func);
|
||||
let idx = self
|
||||
.builder
|
||||
.ins()
|
||||
.iconst(self.compiler.ptr_type, idx as i64);
|
||||
let ptr = self
|
||||
.builder
|
||||
.ins()
|
||||
.stack_addr(self.compiler.ptr_type, slot, 0);
|
||||
self.builder.ins().call(lookup_arg, &[env, idx, ptr]);
|
||||
slot
|
||||
}
|
||||
|
||||
fn select(
|
||||
&mut self,
|
||||
slot: StackSlot,
|
||||
path_ptr: ir::Value,
|
||||
path_len: usize,
|
||||
engine: ir::Value,
|
||||
env: ir::Value,
|
||||
) {
|
||||
let select = self
|
||||
.compiler
|
||||
.module
|
||||
.declare_func_in_func(self.compiler.select, self.builder.func);
|
||||
let path_len = self
|
||||
.builder
|
||||
.ins()
|
||||
.iconst(self.compiler.ptr_type, path_len as i64);
|
||||
let ptr = self
|
||||
.builder
|
||||
.ins()
|
||||
.stack_addr(self.compiler.ptr_type, slot, 0);
|
||||
self.builder
|
||||
.ins()
|
||||
.call(select, &[ptr, path_ptr, path_len, engine, env]);
|
||||
}
|
||||
|
||||
fn select_with_default(
|
||||
&mut self,
|
||||
slot: StackSlot,
|
||||
path_ptr: ir::Value,
|
||||
path_len: usize,
|
||||
default: StackSlot,
|
||||
engine: ir::Value,
|
||||
env: ir::Value,
|
||||
) {
|
||||
let select_with_default = self
|
||||
.compiler
|
||||
.module
|
||||
.declare_func_in_func(self.compiler.select_with_default, self.builder.func);
|
||||
let path_len = self
|
||||
.builder
|
||||
.ins()
|
||||
.iconst(self.compiler.ptr_type, path_len as i64);
|
||||
let ptr = self
|
||||
.builder
|
||||
.ins()
|
||||
.stack_addr(self.compiler.ptr_type, slot, 0);
|
||||
let default_ptr = self
|
||||
.builder
|
||||
.ins()
|
||||
.stack_addr(self.compiler.ptr_type, default, 0);
|
||||
self.builder.ins().call(
|
||||
select_with_default,
|
||||
&[ptr, path_ptr, path_len, default_ptr, engine, env],
|
||||
);
|
||||
}
|
||||
|
||||
pub fn force(&mut self, slot: StackSlot, engine: ir::Value, env: ir::Value) {
|
||||
let force = self
|
||||
.compiler
|
||||
.module
|
||||
.declare_func_in_func(self.compiler.force, self.builder.func);
|
||||
let ptr = self
|
||||
.builder
|
||||
.ins()
|
||||
.stack_addr(self.compiler.ptr_type, slot, 0);
|
||||
self.builder.ins().call(force, &[ptr, engine, env]);
|
||||
}
|
||||
|
||||
pub fn eq(&mut self, lhs: StackSlot, rhs: StackSlot) {
|
||||
let lhs = self
|
||||
.builder
|
||||
.ins()
|
||||
.stack_addr(self.compiler.ptr_type, lhs, 0);
|
||||
let rhs = self
|
||||
.builder
|
||||
.ins()
|
||||
.stack_addr(self.compiler.ptr_type, rhs, 0);
|
||||
let eq = self.compiler.module.declare_func_in_func(self.compiler.eq, self.builder.func);
|
||||
self.builder.ins().call(eq, &[lhs, rhs]);
|
||||
}
|
||||
|
||||
pub fn get_tag(&mut self, slot: StackSlot) -> ir::Value {
|
||||
self.builder.ins().stack_load(types::I64, slot, 0)
|
||||
}
|
||||
|
||||
pub fn get_small_value(&mut self, ty: Type, slot: StackSlot) -> ir::Value {
|
||||
self.builder.ins().stack_load(ty, slot, 8)
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct JITValue {
|
||||
tag: ValueTag,
|
||||
data: JITValueData,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub union JITValueData {
|
||||
int: i64,
|
||||
float: f64,
|
||||
bool: bool,
|
||||
ptr: *const (),
|
||||
}
|
||||
|
||||
impl From<JITValue> for Value {
|
||||
fn from(value: JITValue) -> Self {
|
||||
match value.tag {
|
||||
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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Value> for JITValue {
|
||||
fn from(value: Value) -> Self {
|
||||
match value {
|
||||
Value::Int(int) => JITValue {
|
||||
tag: ValueTag::Int,
|
||||
data: JITValueData { int },
|
||||
},
|
||||
Value::List(list) => JITValue {
|
||||
tag: ValueTag::List,
|
||||
data: JITValueData {
|
||||
ptr: list.as_ptr() as *const (),
|
||||
},
|
||||
},
|
||||
Value::Func(idx) => JITValue {
|
||||
tag: ValueTag::Function,
|
||||
data: JITValueData { int: idx as i64 },
|
||||
},
|
||||
Value::Thunk(idx) => JITValue {
|
||||
tag: ValueTag::Thunk,
|
||||
data: JITValueData { int: idx as i64 },
|
||||
},
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct JITFunc<'exec>(F<'exec>, PhantomData<&'exec mut ()>);
|
||||
type F<'exec> = unsafe extern "C" fn(*const Engine<'exec>, *const Env, *mut JITValue);
|
||||
|
||||
impl<'exec> From<F<'exec>> for JITFunc<'exec> {
|
||||
fn from(value: F<'exec>) -> Self {
|
||||
Self(value, PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'exec> Deref for JITFunc<'exec> {
|
||||
type Target = F<'exec>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
pub struct JITContext {
|
||||
func_builder: FunctionBuilderContext,
|
||||
|
||||
pub struct JITCompiler {
|
||||
ctx: codegen::Context,
|
||||
data_description: DataDescription,
|
||||
module: JITModule,
|
||||
func: Function,
|
||||
builder_ctx: Option<FunctionBuilderContext>,
|
||||
|
||||
helpers: Helpers,
|
||||
int_type: Type,
|
||||
float_type: Type,
|
||||
bool_type: Type,
|
||||
ptr_type: Type,
|
||||
value_type: Type,
|
||||
func_sig: Signature,
|
||||
|
||||
call: FuncId,
|
||||
lookup_arg: FuncId,
|
||||
lookup: FuncId,
|
||||
select: FuncId,
|
||||
select_with_default: FuncId,
|
||||
force: FuncId,
|
||||
|
||||
eq: FuncId,
|
||||
|
||||
alloc_array: FuncId,
|
||||
create_string: FuncId,
|
||||
dbg: FuncId,
|
||||
}
|
||||
|
||||
impl JITContext {
|
||||
impl JITCompiler {
|
||||
pub fn new() -> Self {
|
||||
let mut flag_builder = settings::builder();
|
||||
flag_builder.set("use_colocated_libcalls", "false").unwrap();
|
||||
@@ -137,69 +246,247 @@ impl JITContext {
|
||||
let isa = isa_builder
|
||||
.finish(settings::Flags::new(flag_builder))
|
||||
.unwrap();
|
||||
let builder = JITBuilder::with_isa(isa, cranelift_module::default_libcall_names());
|
||||
let mut builder = JITBuilder::with_isa(isa, cranelift_module::default_libcall_names());
|
||||
|
||||
builder.symbol("helper_call", helper_call as _);
|
||||
builder.symbol("helper_lookup_arg", helper_lookup_arg as _);
|
||||
builder.symbol("helper_lookup", helper_lookup as _);
|
||||
builder.symbol("helper_select", helper_select as _);
|
||||
builder.symbol(
|
||||
"helper_select_with_default",
|
||||
helper_select_with_default as _,
|
||||
);
|
||||
builder.symbol("helper_force", helper_force as _);
|
||||
builder.symbol("helper_eq", helper_eq as _);
|
||||
|
||||
builder.symbol("helper_alloc_array", helper_alloc_array as _);
|
||||
builder.symbol("helper_create_string", helper_create_string as _);
|
||||
builder.symbol("helper_dbg", helper_dbg as _);
|
||||
|
||||
let mut module = JITModule::new(builder);
|
||||
let ctx = module.make_context();
|
||||
|
||||
let int_type = types::I64;
|
||||
let float_type = types::F64;
|
||||
let bool_type = types::I8;
|
||||
let ptr_type = module.target_config().pointer_type();
|
||||
let value_type = types::I128;
|
||||
|
||||
// fn(*const Engine, *const Env, *mut Value)
|
||||
let mut func_sig = module.make_signature();
|
||||
func_sig.params.extend(
|
||||
[AbiParam {
|
||||
value_type: ptr_type,
|
||||
purpose: ArgumentPurpose::Normal,
|
||||
extension: ArgumentExtension::None,
|
||||
}; 3],
|
||||
);
|
||||
|
||||
// fn(func: &mut Value, args_ptr: *mut Value, args_len: usize, engine: &mut Engine, env:
|
||||
// &mut Env)
|
||||
let mut call_sig = module.make_signature();
|
||||
call_sig.params.extend(
|
||||
[AbiParam {
|
||||
value_type: ptr_type,
|
||||
purpose: ArgumentPurpose::Normal,
|
||||
extension: ArgumentExtension::None,
|
||||
}; 5],
|
||||
);
|
||||
let call = module
|
||||
.declare_function("helper_call", Linkage::Import, &call_sig)
|
||||
.unwrap();
|
||||
|
||||
// fn(env: &Env, level: usize, ret: &mut MaybeUninit<Value>)
|
||||
let mut lookup_arg_sig = module.make_signature();
|
||||
lookup_arg_sig.params.extend(
|
||||
[AbiParam {
|
||||
value_type: ptr_type,
|
||||
purpose: ArgumentPurpose::Normal,
|
||||
extension: ArgumentExtension::None,
|
||||
}; 3],
|
||||
);
|
||||
let lookup_arg = module
|
||||
.declare_function("helper_lookup_arg", Linkage::Import, &lookup_arg_sig)
|
||||
.unwrap();
|
||||
|
||||
// fn(env: &Env, sym_ptr: *const u8, sym_len: usize, ret: &mut MaybeUninit<Value>)
|
||||
let mut lookup_sig = module.make_signature();
|
||||
lookup_sig.params.extend(
|
||||
[AbiParam {
|
||||
value_type: ptr_type,
|
||||
purpose: ArgumentPurpose::Normal,
|
||||
extension: ArgumentExtension::None,
|
||||
}; 4],
|
||||
);
|
||||
let lookup = module
|
||||
.declare_function("helper_lookup", Linkage::Import, &lookup_sig)
|
||||
.unwrap();
|
||||
|
||||
// fn(val: &mut Value, path_ptr: *mut Value, path_len: usize, engine: &mut Engine, env: &mut Env)
|
||||
let mut select_sig = module.make_signature();
|
||||
select_sig.params.extend(
|
||||
[AbiParam {
|
||||
value_type: ptr_type,
|
||||
purpose: ArgumentPurpose::Normal,
|
||||
extension: ArgumentExtension::None,
|
||||
}; 5],
|
||||
);
|
||||
let select = module
|
||||
.declare_function("helper_select", Linkage::Import, &select_sig)
|
||||
.unwrap();
|
||||
|
||||
// fn(val: &mut Value, path_ptr: *mut Value, path_len: usize, default: NonNull<Value>, engine: &mut Engine, env: &mut Env)
|
||||
let mut select_with_default_sig = module.make_signature();
|
||||
select_with_default_sig.params.extend(
|
||||
[AbiParam {
|
||||
value_type: ptr_type,
|
||||
purpose: ArgumentPurpose::Normal,
|
||||
extension: ArgumentExtension::None,
|
||||
}; 6],
|
||||
);
|
||||
let select_with_default = module
|
||||
.declare_function(
|
||||
"helper_select_with_default",
|
||||
Linkage::Import,
|
||||
&select_with_default_sig,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// fn(thunk: &mut Value, engine: &mut Engine, env: &mut Env)
|
||||
let mut force_sig = module.make_signature();
|
||||
force_sig.params.extend(
|
||||
[AbiParam {
|
||||
value_type: ptr_type,
|
||||
purpose: ArgumentPurpose::Normal,
|
||||
extension: ArgumentExtension::None,
|
||||
}; 3],
|
||||
);
|
||||
let force = module
|
||||
.declare_function("helper_force", Linkage::Import, &force_sig)
|
||||
.unwrap();
|
||||
|
||||
let mut eq_sig = module.make_signature();
|
||||
eq_sig.params.extend(
|
||||
[AbiParam {
|
||||
value_type: ptr_type,
|
||||
purpose: ArgumentPurpose::Normal,
|
||||
extension: ArgumentExtension::None,
|
||||
}; 2],
|
||||
);
|
||||
let eq = module
|
||||
.declare_function("helper_eq", Linkage::Import, &eq_sig)
|
||||
.unwrap();
|
||||
|
||||
let mut alloc_array_sig = module.make_signature();
|
||||
alloc_array_sig.params.push(AbiParam {
|
||||
value_type: ptr_type,
|
||||
purpose: ArgumentPurpose::Normal,
|
||||
extension: ArgumentExtension::None,
|
||||
});
|
||||
alloc_array_sig.returns.push(AbiParam {
|
||||
value_type: ptr_type,
|
||||
purpose: ArgumentPurpose::Normal,
|
||||
extension: ArgumentExtension::None,
|
||||
});
|
||||
let alloc_array = module
|
||||
.declare_function("helper_alloc_array", Linkage::Import, &alloc_array_sig)
|
||||
.unwrap();
|
||||
|
||||
let mut create_string_sig = module.make_signature();
|
||||
create_string_sig.params.extend(
|
||||
[AbiParam {
|
||||
value_type: ptr_type,
|
||||
purpose: ArgumentPurpose::Normal,
|
||||
extension: ArgumentExtension::None,
|
||||
}; 3],
|
||||
);
|
||||
let create_string = module
|
||||
.declare_function("helper_create_string", Linkage::Import, &create_string_sig)
|
||||
.unwrap();
|
||||
|
||||
let mut dbg_sig = module.make_signature();
|
||||
dbg_sig.params.push(AbiParam {
|
||||
value_type: ptr_type,
|
||||
purpose: ArgumentPurpose::Normal,
|
||||
extension: ArgumentExtension::None,
|
||||
});
|
||||
let dbg = module
|
||||
.declare_function("helper_dbg", Linkage::Import, &dbg_sig)
|
||||
.unwrap();
|
||||
|
||||
Self {
|
||||
func_builder: FunctionBuilderContext::new(),
|
||||
helpers: Helpers::new(&ctx, &mut module),
|
||||
data_description: DataDescription::new(),
|
||||
func: Function::new(),
|
||||
builder_ctx: None,
|
||||
ctx,
|
||||
module,
|
||||
|
||||
int_type,
|
||||
float_type,
|
||||
bool_type,
|
||||
ptr_type,
|
||||
value_type,
|
||||
func_sig,
|
||||
|
||||
call,
|
||||
lookup_arg,
|
||||
lookup,
|
||||
select,
|
||||
select_with_default,
|
||||
force,
|
||||
|
||||
eq,
|
||||
|
||||
alloc_array,
|
||||
create_string,
|
||||
dbg,
|
||||
}
|
||||
}
|
||||
|
||||
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_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(
|
||||
std::mem::transmute(
|
||||
self.execution_engine
|
||||
.get_function_address(func_id.get_name().to_str().unwrap())
|
||||
.unwrap(),
|
||||
),
|
||||
PhantomData,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
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_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 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,
|
||||
"ptrconv",
|
||||
pub fn compile(&mut self, ir: &Ir, id: usize) -> JITFunc {
|
||||
let func_id = self
|
||||
.module
|
||||
.declare_function(
|
||||
format!("nixjit_thunk{id}").as_str(),
|
||||
Linkage::Local,
|
||||
&self.func_sig,
|
||||
)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
let mut func = Function::new();
|
||||
func.signature = self.func_sig.clone();
|
||||
let mut builder_ctx = self.builder_ctx.take().unwrap_or_default();
|
||||
let mut ctx = JITContext::new(self, FunctionBuilder::new(&mut func, &mut builder_ctx));
|
||||
|
||||
let entry = ctx.builder.create_block();
|
||||
ctx.builder.append_block_params_for_function_params(entry);
|
||||
ctx.builder.switch_to_block(entry);
|
||||
|
||||
let params = ctx.builder.block_params(entry);
|
||||
let engine = params[0];
|
||||
let env = params[1];
|
||||
let ret = params[2];
|
||||
let res = ir.compile(&mut ctx, engine, env);
|
||||
|
||||
let tag = ctx.builder.ins().stack_load(types::I64, res, 0);
|
||||
let val0 = ctx.builder.ins().stack_load(types::I64, res, 8);
|
||||
let val1 = ctx.builder.ins().stack_load(types::I64, res, 16);
|
||||
let val2 = ctx.builder.ins().stack_load(types::I64, res, 24);
|
||||
ctx.builder.ins().store(MemFlags::new(), tag, ret, 0);
|
||||
ctx.builder.ins().store(MemFlags::new(), val0, ret, 8);
|
||||
ctx.builder.ins().store(MemFlags::new(), val1, ret, 16);
|
||||
ctx.builder.ins().store(MemFlags::new(), val2, ret, 24);
|
||||
ctx.builder.ins().return_(&[]);
|
||||
ctx.builder.seal_all_blocks();
|
||||
ctx.builder.finalize();
|
||||
|
||||
println!("{:?}", ir);
|
||||
println!("{}", func.display());
|
||||
self.ctx.func = func;
|
||||
self.module.define_function(func_id, &mut self.ctx).unwrap();
|
||||
self.module.finalize_definitions().unwrap();
|
||||
self.ctx.clear();
|
||||
|
||||
let _ = self.builder_ctx.insert(builder_ctx);
|
||||
unsafe {
|
||||
std::mem::transmute::<*const u8, JITFunc>(self.module.get_finalized_function(func_id))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user