fix: release eq

This commit is contained in:
2025-07-05 21:07:23 +08:00
parent 5625f28e9b
commit 4b567ab022
22 changed files with 1132 additions and 915 deletions

View File

@@ -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!()
}
}