feat: less clone, avoid evaluating not depended thunk

This commit is contained in:
2025-06-18 09:32:00 +08:00
parent 3e9f0a72a0
commit d875951c09
14 changed files with 409 additions and 192 deletions

View File

@@ -4,38 +4,204 @@ use crate::ir::*;
use crate::ty::common as c;
use crate::ty::internal::Value;
use super::JITContext;
use super::{JITContext, ValueTag};
pub trait JITCompile {
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc>;
fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc>;
}
impl JITCompile for Attrs {
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
todo!()
}
}
impl JITCompile for List {
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
todo!()
}
}
impl JITCompile for HasAttr {
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
todo!()
}
}
impl JITCompile for BinOp {
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
todo!()
fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
use ValueTag::*;
use BinOpKind::*;
let lhs = self.lhs.compile(ctx, func);
let rhs = self.rhs.compile(ctx, func);
let lhs_tag = ctx.get_tag(lhs);
let rhs_tag = ctx.get_tag(rhs);
let tag = ctx
.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
.builder
.build_alloca(ctx.helpers.value_type, "res_alloca")
.unwrap();
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.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.builder.position_at_end(int_int);
let val = ctx
.builder
.build_int_add(ctx.get_int(lhs), ctx.get_int(rhs), "add")
.unwrap();
ctx.builder
.build_store(
res,
ctx.helpers.value_type.const_named_struct(&[
ctx.helpers.const_int(Int as i64).into(),
val.into(),
]),
)
.unwrap();
ctx.builder.position_at_end(int_float);
let val = ctx
.builder
.build_float_add(
ctx.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.builder
.build_store(
res,
ctx.helpers.value_type.const_named_struct(&[
ctx.helpers.const_int(Float as i64).into(),
val.into(),
]),
)
.unwrap();
ctx.builder.position_at_end(float_int);
let val = ctx
.builder
.build_float_add(
ctx.get_float(lhs),
ctx.builder
.build_signed_int_to_float(
ctx.get_int(rhs),
ctx.helpers.float_type,
"rhs_to_float",
)
.unwrap(),
"add",
)
.unwrap();
ctx.builder
.build_store(
res,
ctx.helpers.value_type.const_named_struct(&[
ctx.helpers.const_int(Float as i64).into(),
val.into(),
]),
)
.unwrap();
ctx.builder.position_at_end(int_int);
let val = ctx
.builder
.build_float_add(ctx.get_float(lhs), ctx.get_float(rhs), "add")
.unwrap();
ctx.builder
.build_store(
res,
ctx.helpers.value_type.const_named_struct(&[
ctx.helpers.const_int(Float as i64).into(),
val.into(),
]),
)
.unwrap();
ctx.builder.position_at_end(fallback);
}
Or => {
let bool_bool = ctx.context.append_basic_block(func, "int_int");
let fallback = ctx.context.append_basic_block(func, "fallback");
ctx.builder
.build_switch(
tag,
fallback,
&[
(
ctx.helpers.const_int(((Bool as i64) << 8) + Bool as i64),
bool_bool,
),
],
)
.unwrap();
ctx.builder.position_at_end(bool_bool);
let val = ctx
.builder
.build_or(ctx.get_bool(lhs), ctx.get_bool(rhs), "or")
.unwrap();
ctx.builder
.build_store(
res,
ctx.helpers.value_type.const_named_struct(&[
ctx.helpers.const_int(Bool as i64).into(),
val.into(),
]),
)
.unwrap();
ctx.builder.position_at_end(fallback);
}
_ => todo!()
}
ctx.builder.position_at_end(ret);
ctx.builder
.build_load(ctx.helpers.value_type, res, "load_res")
.unwrap()
.try_into()
.unwrap()
}
}
impl JITCompile for UnOp {
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
todo!();
let rhs = self.rhs.compile(ctx, func);
let tag = ctx.get_tag(rhs);
@@ -57,55 +223,55 @@ impl JITCompile for UnOp {
}
impl JITCompile for Select {
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
todo!()
}
}
impl JITCompile for If {
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
todo!()
}
}
impl JITCompile for LoadFunc {
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
todo!()
}
}
impl JITCompile for Call {
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
todo!()
}
}
impl JITCompile for Let {
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
todo!()
}
}
impl JITCompile for With {
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
todo!()
}
}
impl JITCompile for Assert {
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
todo!()
}
}
impl JITCompile for ConcatStrings {
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
todo!()
}
}
impl JITCompile for Const {
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
use c::Const::*;
match self.val {
Bool(x) => ctx.helpers.new_bool(x),
@@ -117,37 +283,37 @@ impl JITCompile for Const {
}
impl JITCompile for String {
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
todo!()
}
}
impl JITCompile for Var {
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
todo!()
}
}
impl JITCompile for Arg {
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
todo!()
}
}
impl JITCompile for LetVar {
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
todo!()
}
}
impl JITCompile for Thunk {
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
todo!()
}
}
impl JITCompile for Path {
fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
fn compile<'gc>(&self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> StructValue<'gc> {
todo!()
}
}

View File

@@ -7,8 +7,9 @@ use inkwell::module::Module;
use inkwell::types::{FloatType, FunctionType, IntType, PointerType, StructType};
use inkwell::values::{BasicValueEnum, FloatValue, FunctionValue, IntValue, StructValue};
use crate::env::VmEnv;
use crate::env::Env;
use crate::eval::Engine;
use crate::ty::internal::Value;
use super::{JITContext, JITValue, JITValueData, ValueTag};
@@ -54,7 +55,7 @@ impl<'ctx> Helpers<'ctx> {
let new_thunk = module.add_function(
"new_thunk",
value_type.fn_type(&[ptr_type.into()], false),
value_type.fn_type(&[ptr_type.into(), ptr_type.into()], false),
None,
);
let debug = module.add_function(
@@ -102,7 +103,7 @@ impl<'ctx> Helpers<'ctx> {
let call = module.add_function(
"call",
value_type.fn_type(
&[value_type.into(), value_type.into(), ptr_type.into()],
&[value_type.into(), ptr_type.into(), ptr_type.into(), ptr_type.into()],
false,
),
None,
@@ -234,11 +235,11 @@ extern "C" fn helper_debug(value: JITValue) {
dbg!(value.tag);
}
extern "C" fn helper_capture_env(thunk: JITValue, env: *const VmEnv) {
extern "C" fn helper_capture_env(thunk: JITValue, env: *const Env) {
todo!()
}
extern "C" fn helper_neg(rhs: JITValue, _env: *const VmEnv) -> JITValue {
extern "C" fn helper_neg(rhs: JITValue, _env: *const Env) -> JITValue {
use ValueTag::*;
match rhs.tag {
Int => JITValue {
@@ -257,7 +258,7 @@ extern "C" fn helper_neg(rhs: JITValue, _env: *const VmEnv) -> JITValue {
}
}
extern "C" fn helper_not(rhs: JITValue, _env: *const VmEnv) -> JITValue {
extern "C" fn helper_not(rhs: JITValue, _env: *const Env) -> JITValue {
use ValueTag::*;
match rhs.tag {
Bool => JITValue {
@@ -338,21 +339,22 @@ extern "C" fn helper_or(lhs: JITValue, rhs: JITValue) -> JITValue {
}
}
extern "C" fn helper_call(func: JITValue, arg: JITValue, engine: *mut Engine) -> JITValue {
extern "C" fn helper_call(func: JITValue, args: Box<[JITValue]>, engine: NonNull<Engine>, env: NonNull<Env>) -> JITValue {
let func = Value::from(func);
todo!()
}
extern "C" fn helper_arg(idx: usize, env: *const VmEnv) -> JITValue {
extern "C" fn helper_arg(idx: usize, env: *const Env) -> JITValue {
let env = unsafe { env.as_ref() }.unwrap();
let val: JITValue = env.lookup_arg(idx).clone().into();
val
}
extern "C" fn helper_lookup_let(level: usize, idx: usize, env: *const VmEnv) -> JITValue {
extern "C" fn helper_lookup_let(level: usize, idx: usize, env: *const Env) -> JITValue {
todo!()
}
extern "C" fn helper_lookup(sym: usize, env: *const VmEnv) -> JITValue {
extern "C" fn helper_lookup(sym: usize, env: *const Env) -> JITValue {
todo!()
}

View File

@@ -7,11 +7,11 @@ use inkwell::context::Context;
use inkwell::execution_engine::ExecutionEngine;
use inkwell::module::Module;
use inkwell::values::{
AnyValue, AsValueRef, BasicMetadataValueEnum, BasicValueEnum, IntValue, StructValue,
AnyValue, BasicMetadataValueEnum, FloatValue, IntValue, StructValue
};
use crate::env::VmEnv;
use crate::ir::{Ir, UnOpKind};
use crate::env::Env;
use crate::ir::Ir;
use crate::ty::internal::Value;
mod compile;
@@ -60,10 +60,10 @@ impl From<JITValue> for Value {
match value.tag {
Int => Value::Int(unsafe { value.data.int }),
Null => Value::Null,
/* Function => Value::Func(unsafe { Rc::from_raw(value.data.ptr as *const _) }),
Thunk => Value::Thunk(self::Thunk {
thunk: unsafe { Rc::from_raw(value.data.ptr as *const _) },
}), */
Function => Value::Func(unsafe { value.data.int as usize}),
Thunk => Value::Thunk(unsafe {
value.data.int as usize
}),
_ => todo!("not implemented for {:?}", value.tag),
}
}
@@ -94,7 +94,7 @@ impl From<Value> for JITValue {
}
pub struct JITFunc<'ctx>(F, PhantomData<&'ctx mut ()>);
type F = unsafe extern "C" fn(*const VmEnv) -> JITValue;
type F = unsafe extern "C" fn(*const Env) -> JITValue;
impl From<F> for JITFunc<'_> {
fn from(value: F) -> Self {
@@ -144,6 +144,60 @@ impl<'ctx> JITContext<'ctx> {
todo!()
}
pub fn get_float(&self, val: StructValue<'ctx>) -> FloatValue<'ctx> {
let alloca = self
.builder
.build_alloca(self.helpers.int_type, "get_value_alloca")
.unwrap();
self.builder.build_store(alloca, val).unwrap();
self.builder
.build_load(
self.helpers.float_type,
self.builder
.build_struct_gep(self.helpers.value_type, alloca, 1, "get_value_gep")
.unwrap(),
"get_value",
)
.unwrap()
.into_float_value()
}
pub fn get_int(&self, val: StructValue<'ctx>) -> IntValue<'ctx> {
let alloca = self
.builder
.build_alloca(self.helpers.int_type, "get_value_alloca")
.unwrap();
self.builder.build_store(alloca, val).unwrap();
self.builder
.build_load(
self.helpers.int_type,
self.builder
.build_struct_gep(self.helpers.value_type, alloca, 1, "get_value_gep")
.unwrap(),
"get_value",
)
.unwrap()
.into_int_value()
}
pub fn get_bool(&self, val: StructValue<'ctx>) -> IntValue<'ctx> {
let alloca = self
.builder
.build_alloca(self.helpers.bool_type, "get_value_alloca")
.unwrap();
self.builder.build_store(alloca, val).unwrap();
self.builder
.build_load(
self.helpers.bool_type,
self.builder
.build_struct_gep(self.helpers.value_type, alloca, 1, "get_value_gep")
.unwrap(),
"get_value",
)
.unwrap()
.into_int_value()
}
pub fn get_tag(&self, val: StructValue<'ctx>) -> IntValue<'ctx> {
let alloca = self
.builder
@@ -152,9 +206,9 @@ impl<'ctx> JITContext<'ctx> {
self.builder.build_store(alloca, val).unwrap();
self.builder
.build_load(
self.context.bool_type(),
self.helpers.int_type,
self.builder
.build_struct_gep(self.helpers.value_type, alloca, 1, "get_tag_gep")
.build_struct_gep(self.helpers.value_type, alloca, 0, "get_tag_gep")
.unwrap(),
"get_tag",
)