feat: stack var (WIP)

This commit is contained in:
2025-08-09 08:12:53 +08:00
parent fd182b6233
commit d8ad7fe904
36 changed files with 1521 additions and 1058 deletions

View File

@@ -19,22 +19,22 @@ pub trait JITCompile<Ctx: JITContext> {
///
/// # Arguments
/// * `ctx` - The compilation context
/// * `engine` - The evaluation context value
/// * `rt_ctx` - The evaluation context value
/// * `env` - The environment value
///
/// # Returns
/// A stack slot containing the compiled result
fn compile(&self, ctx: &mut Context<Ctx>, engine: ir::Value, env: ir::Value) -> StackSlot;
fn compile(&self, ctx: &mut Context<Ctx>, rt_ctx: ir::Value) -> StackSlot;
}
impl<Ctx: JITContext> JITCompile<Ctx> for ExprId {
fn compile(&self, ctx: &mut Context<Ctx>, engine: ir::Value, env: ir::Value) -> StackSlot {
fn compile(&self, ctx: &mut Context<Ctx>, rt_ctx: ir::Value) -> StackSlot {
todo!()
}
}
impl<Ctx: JITContext> JITCompile<Ctx> for Lir {
fn compile(&self, ctx: &mut Context<Ctx>, engine: ir::Value, env: ir::Value) -> StackSlot {
fn compile(&self, ctx: &mut Context<Ctx>, rt_ctx: ir::Value) -> StackSlot {
todo!()
}
}
@@ -43,10 +43,10 @@ impl<Ctx: JITContext> JITCompile<Ctx> for AttrSet {
/// Compiles an attribute set to Cranelift IR.
///
/// This creates a new attribute set and compiles all static attributes into it.
fn compile(&self, ctx: &mut Context<Ctx>, engine: ir::Value, env: ir::Value) -> StackSlot {
fn compile(&self, ctx: &mut Context<Ctx>, rt_ctx: ir::Value) -> StackSlot {
let attrs = ctx.create_attrs();
for (k, v) in self.stcs.iter() {
let v = v.compile(ctx, engine, env);
let v = v.compile(ctx, rt_ctx);
ctx.push_attr(attrs, k, v);
}
ctx.finalize_attrs(attrs)
@@ -57,10 +57,10 @@ impl<Ctx: JITContext> JITCompile<Ctx> for List {
/// Compiles a list to Cranelift IR.
///
/// This creates a new list by compiling all items and storing them in an array.
fn compile(&self, ctx: &mut Context<Ctx>, engine: ir::Value, env: ir::Value) -> StackSlot {
fn compile(&self, ctx: &mut Context<Ctx>, rt_ctx: ir::Value) -> StackSlot {
let array = ctx.alloc_array(self.items.len());
for (i, item) in self.items.iter().enumerate() {
let item = item.compile(ctx, engine, env);
let item = item.compile(ctx, rt_ctx);
let tag = ctx.builder.ins().stack_load(types::I64, item, 0);
let val0 = ctx.builder.ins().stack_load(types::I64, item, 8);
let val1 = ctx.builder.ins().stack_load(types::I64, item, 16);
@@ -83,7 +83,7 @@ impl<Ctx: JITContext> JITCompile<Ctx> for List {
}
impl<Ctx: JITContext> JITCompile<Ctx> for HasAttr {
fn compile(&self, ctx: &mut Context<Ctx>, engine: ir::Value, env: ir::Value) -> StackSlot {
fn compile(&self, ctx: &mut Context<Ctx>, rt_ctx: ir::Value) -> StackSlot {
todo!()
}
}
@@ -94,10 +94,10 @@ impl<Ctx: JITContext> JITCompile<Ctx> for BinOp {
/// This implementation handles various binary operations like addition, subtraction,
/// division, logical AND/OR, and equality checks. It generates code that checks
/// the types of operands and performs the appropriate operation.
fn compile(&self, ctx: &mut Context<Ctx>, engine: ir::Value, env: ir::Value) -> StackSlot {
fn compile(&self, ctx: &mut Context<Ctx>, rt_ctx: ir::Value) -> StackSlot {
use BinOpKind::*;
let lhs = self.lhs.compile(ctx, engine, env);
let rhs = self.rhs.compile(ctx, engine, env);
let lhs = self.lhs.compile(ctx, rt_ctx);
let rhs = self.rhs.compile(ctx, rt_ctx);
let lhs_tag = ctx.get_tag(lhs);
let rhs_tag = ctx.get_tag(rhs);
let eq = ctx.builder.ins().icmp(IntCC::Equal, lhs_tag, rhs_tag);
@@ -349,7 +349,7 @@ impl<Ctx: JITContext> JITCompile<Ctx> for BinOp {
}
impl<Ctx: JITContext> JITCompile<Ctx> for UnOp {
fn compile(&self, ctx: &mut Context<Ctx>, engine: ir::Value, env: ir::Value) -> StackSlot {
fn compile(&self, ctx: &mut Context<Ctx>, rt_ctx: ir::Value) -> StackSlot {
todo!()
}
}
@@ -358,11 +358,11 @@ impl<Ctx: JITContext> JITCompile<Ctx> for Attr {
/// Compiles an attribute key to Cranelift IR.
///
/// An attribute can be either a static string or a dynamic expression.
fn compile(&self, ctx: &mut Context<Ctx>, engine: ir::Value, env: ir::Value) -> StackSlot {
fn compile(&self, ctx: &mut Context<Ctx>, rt_ctx: ir::Value) -> StackSlot {
use Attr::*;
match self {
Str(string) => ctx.create_string(string),
Dynamic(ir) => ir.compile(ctx, engine, env),
Dynamic(ir) => ir.compile(ctx, rt_ctx),
}
}
}
@@ -372,11 +372,11 @@ impl<Ctx: JITContext> JITCompile<Ctx> for Select {
///
/// This compiles the expression to select from, builds the attribute path,
/// and calls the select helper function.
fn compile(&self, ctx: &mut Context<Ctx>, engine: ir::Value, env: ir::Value) -> StackSlot {
let val = self.expr.compile(ctx, engine, env);
fn compile(&self, ctx: &mut Context<Ctx>, rt_ctx: ir::Value) -> StackSlot {
let val = self.expr.compile(ctx, rt_ctx);
let attrpath = ctx.alloc_array(self.attrpath.len());
for (i, attr) in self.attrpath.iter().enumerate() {
let arg = attr.compile(ctx, engine, env);
let arg = attr.compile(ctx, rt_ctx);
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);
@@ -394,7 +394,7 @@ impl<Ctx: JITContext> JITCompile<Ctx> for Select {
.ins()
.store(MemFlags::new(), val2, attrpath, i as i32 * 32 + 24);
}
ctx.select(val, attrpath, self.attrpath.len(), engine, env);
ctx.select(val, attrpath, self.attrpath.len(), rt_ctx);
val
}
}
@@ -404,8 +404,8 @@ impl<Ctx: JITContext> JITCompile<Ctx> for If {
///
/// This generates code that evaluates the condition, checks that it's a boolean,
/// and then jumps to the appropriate branch (true or false).
fn compile(&self, ctx: &mut Context<Ctx>, engine: ir::Value, env: ir::Value) -> StackSlot {
let cond = self.cond.compile(ctx, engine, env);
fn compile(&self, ctx: &mut Context<Ctx>, rt_ctx: ir::Value) -> StackSlot {
let cond = self.cond.compile(ctx, rt_ctx);
let cond_type = ctx.builder.ins().stack_load(types::I64, cond, 0);
let cond_value = ctx.builder.ins().stack_load(types::I64, cond, 8);
@@ -430,7 +430,7 @@ impl<Ctx: JITContext> JITCompile<Ctx> for If {
.brif(cond_value, true_block, [], false_block, []);
ctx.builder.switch_to_block(true_block);
let ret = self.consq.compile(ctx, engine, env);
let ret = self.consq.compile(ctx, rt_ctx);
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);
@@ -442,7 +442,7 @@ impl<Ctx: JITContext> JITCompile<Ctx> for If {
ctx.builder.ins().jump(exit_block, []);
ctx.builder.switch_to_block(false_block);
let ret = self.alter.compile(ctx, engine, env);
let ret = self.alter.compile(ctx, rt_ctx);
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);
@@ -463,32 +463,10 @@ impl<Ctx: JITContext> JITCompile<Ctx> for If {
impl<Ctx: JITContext> JITCompile<Ctx> for Call {
/// Compiles a function call to Cranelift IR.
///
/// This compiles the function expression and all arguments, builds an argument array,
/// and calls the call helper function.
fn compile(&self, ctx: &mut Context<Ctx>, engine: ir::Value, env: ir::Value) -> StackSlot {
let func = self.func.compile(ctx, engine, env);
let args = ctx.alloc_array(self.args.len());
for (i, arg) in self.args.iter().enumerate() {
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.call(func, args, self.args.len(), engine, env);
fn compile(&self, ctx: &mut Context<Ctx>, rt_ctx: ir::Value) -> StackSlot {
let func = self.func.compile(ctx, rt_ctx);
let arg = self.arg.compile(ctx, rt_ctx);
ctx.call(func, arg, rt_ctx);
func
}
}
@@ -498,24 +476,24 @@ impl<Ctx: JITContext> JITCompile<Ctx> for With {
///
/// This enters a new `with` scope with the compiled namespace, compiles the body expression,
/// and then exits the `with` scope.
fn compile(&self, ctx: &mut Context<Ctx>, engine: ir::Value, env: ir::Value) -> StackSlot {
let namespace = self.namespace.compile(ctx, engine, env);
ctx.enter_with(env, namespace);
let ret = self.expr.compile(ctx, engine, env);
ctx.exit_with(env);
fn compile(&self, ctx: &mut Context<Ctx>, rt_ctx: ir::Value) -> StackSlot {
let namespace = self.namespace.compile(ctx, rt_ctx);
ctx.enter_with(rt_ctx, namespace);
let ret = self.expr.compile(ctx, rt_ctx);
ctx.exit_with(rt_ctx);
ctx.free_slot(namespace);
ret
}
}
impl<Ctx: JITContext> JITCompile<Ctx> for Assert {
fn compile(&self, ctx: &mut Context<Ctx>, engine: ir::Value, env: ir::Value) -> StackSlot {
fn compile(&self, ctx: &mut Context<Ctx>, rt_ctx: ir::Value) -> StackSlot {
todo!()
}
}
impl<Ctx: JITContext> JITCompile<Ctx> for ConcatStrings {
fn compile(&self, ctx: &mut Context<Ctx>, engine: ir::Value, env: ir::Value) -> StackSlot {
fn compile(&self, ctx: &mut Context<Ctx>, rt_ctx: ir::Value) -> StackSlot {
todo!()
}
}
@@ -525,7 +503,7 @@ impl<Ctx: JITContext> JITCompile<Ctx> for Const {
///
/// This handles boolean, integer, float, and null constants by storing
/// their values and type tags in a stack slot.
fn compile(&self, ctx: &mut Context<Ctx>, engine: ir::Value, env: ir::Value) -> StackSlot {
fn compile(&self, ctx: &mut Context<Ctx>, rt_ctx: ir::Value) -> StackSlot {
use nixjit_value::Const::*;
let slot = ctx.alloca();
match self.val {
@@ -560,7 +538,7 @@ impl<Ctx: JITContext> JITCompile<Ctx> for Str {
/// Compiles a string literal to Cranelift IR.
///
/// This creates a string value from the string literal.
fn compile(&self, ctx: &mut Context<Ctx>, engine: ir::Value, env: ir::Value) -> StackSlot {
fn compile(&self, ctx: &mut Context<Ctx>, rt_ctx: ir::Value) -> StackSlot {
ctx.create_string(&self.val)
}
}
@@ -569,13 +547,13 @@ impl<Ctx: JITContext> JITCompile<Ctx> for Var {
/// Compiles a variable lookup to Cranelift IR.
///
/// This looks up a variable by its symbol in the current environment.
fn compile(&self, ctx: &mut Context<Ctx>, engine: ir::Value, env: ir::Value) -> StackSlot {
ctx.lookup(env, &self.sym)
fn compile(&self, ctx: &mut Context<Ctx>, rt_ctx: ir::Value) -> StackSlot {
ctx.lookup(rt_ctx, &self.sym)
}
}
impl<Ctx: JITContext> JITCompile<Ctx> for Path {
fn compile(&self, ctx: &mut Context<Ctx>, engine: ir::Value, env: ir::Value) -> StackSlot {
fn compile(&self, ctx: &mut Context<Ctx>, rt_ctx: ir::Value) -> StackSlot {
todo!()
}
}