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!()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user