From 7b6db442076ace3d7da96da73515b33d7b2472d1 Mon Sep 17 00:00:00 2001 From: imxyy_soope_ Date: Sat, 14 Jun 2025 16:53:45 +0800 Subject: [PATCH] feat: JIT (WIP) --- src/eval/jit/compile.rs | 65 ++++++++++++++++++++++++++--------------- src/eval/jit/helpers.rs | 14 +++++++-- src/eval/jit/mod.rs | 28 ++++++++++++++++++ src/ir/mod.rs | 28 ++++++++++-------- 4 files changed, 96 insertions(+), 39 deletions(-) diff --git a/src/eval/jit/compile.rs b/src/eval/jit/compile.rs index cd3dd83..c2607de 100644 --- a/src/eval/jit/compile.rs +++ b/src/eval/jit/compile.rs @@ -1,129 +1,146 @@ -#![allow(unused_variables)] +use inkwell::values::{BasicValueEnum, FunctionValue}; use crate::ir::*; +use crate::ty::common as c; +use crate::ty::internal::Value; use super::JITContext; pub trait JITCompile { - fn compile<'gc>(self, ctx: &JITContext<'gc>); + fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> BasicValueEnum<'gc>; } impl JITCompile for Attrs { - fn compile<'gc>(self, ctx: &JITContext<'gc>) { + fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> BasicValueEnum<'gc> { todo!() } } impl JITCompile for List { - fn compile<'gc>(self, ctx: &JITContext<'gc>) { + fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> BasicValueEnum<'gc> { todo!() } } impl JITCompile for HasAttr { - fn compile<'gc>(self, ctx: &JITContext<'gc>) { + fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> BasicValueEnum<'gc> { todo!() } } impl JITCompile for BinOp { - fn compile<'gc>(self, ctx: &JITContext<'gc>) { + fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> BasicValueEnum<'gc> { todo!() } } impl JITCompile for UnOp { - fn compile<'gc>(self, ctx: &JITContext<'gc>) { - todo!() + fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> BasicValueEnum<'gc> { + todo!(); + let rhs = self.rhs.compile(ctx, func); + 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.builder.build_alloca(ctx.helpers.value_type, "res_alloca").unwrap(); + ctx.builder.build_switch(tag, fallback, &[]).unwrap(); + ctx.builder.position_at_end(fallback); + ctx.builder.position_at_end(ret); + ctx.builder.build_load(ctx.helpers.value_type, res, "load_res").unwrap() } } impl JITCompile for Select { - fn compile<'gc>(self, ctx: &JITContext<'gc>) { + fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> BasicValueEnum<'gc> { todo!() } } impl JITCompile for If { - fn compile<'gc>(self, ctx: &JITContext<'gc>) { + fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> BasicValueEnum<'gc> { todo!() } } impl JITCompile for LoadFunc { - fn compile<'gc>(self, ctx: &JITContext<'gc>) { + fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> BasicValueEnum<'gc> { todo!() } } impl JITCompile for Call { - fn compile<'gc>(self, ctx: &JITContext<'gc>) { + fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> BasicValueEnum<'gc> { todo!() } } impl JITCompile for Let { - fn compile<'gc>(self, ctx: &JITContext<'gc>) { + fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> BasicValueEnum<'gc> { todo!() } } impl JITCompile for With { - fn compile<'gc>(self, ctx: &JITContext<'gc>) { + fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> BasicValueEnum<'gc> { todo!() } } impl JITCompile for Assert { - fn compile<'gc>(self, ctx: &JITContext<'gc>) { + fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> BasicValueEnum<'gc> { todo!() } } impl JITCompile for ConcatStrings { - fn compile<'gc>(self, ctx: &JITContext<'gc>) { + fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> BasicValueEnum<'gc> { todo!() } } impl JITCompile for Const { - fn compile<'gc>(self, ctx: &JITContext<'gc>) { - todo!() + fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> BasicValueEnum<'gc> { + use c::Const::*; + 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(), + } } } impl JITCompile for String { - fn compile<'gc>(self, ctx: &JITContext<'gc>) { + fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> BasicValueEnum<'gc> { todo!() } } impl JITCompile for Var { - fn compile<'gc>(self, ctx: &JITContext<'gc>) { + fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> BasicValueEnum<'gc> { todo!() } } impl JITCompile for Arg { - fn compile<'gc>(self, ctx: &JITContext<'gc>) { + fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> BasicValueEnum<'gc> { todo!() } } impl JITCompile for LetVar { - fn compile<'gc>(self, ctx: &JITContext<'gc>) { + fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> BasicValueEnum<'gc> { todo!() } } impl JITCompile for Thunk { - fn compile<'gc>(self, ctx: &JITContext<'gc>) { + fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> BasicValueEnum<'gc> { todo!() } } impl JITCompile for Path { - fn compile<'gc>(self, ctx: &JITContext<'gc>) { + fn compile<'gc>(self, ctx: &JITContext<'gc>, func: FunctionValue<'gc>) -> BasicValueEnum<'gc> { todo!() } } diff --git a/src/eval/jit/helpers.rs b/src/eval/jit/helpers.rs index 10b0844..2d60299 100644 --- a/src/eval/jit/helpers.rs +++ b/src/eval/jit/helpers.rs @@ -5,7 +5,7 @@ use inkwell::context::Context; use inkwell::execution_engine::ExecutionEngine; use inkwell::module::Module; use inkwell::types::{FloatType, FunctionType, IntType, PointerType, StructType}; -use inkwell::values::{BasicValueEnum, FunctionValue}; +use inkwell::values::{BasicValueEnum, FloatValue, FunctionValue, IntValue}; use crate::env::VmEnv; use crate::eval::Engine; @@ -176,20 +176,28 @@ impl<'ctx> Helpers<'ctx> { } } + pub fn const_int(&self, int: i64) -> IntValue<'ctx> { + self.int_type.const_int(int as _, false) + } + pub fn new_int(&self, int: i64) -> BasicValueEnum<'ctx> { self.value_type .const_named_struct(&[ self.int_type.const_int(ValueTag::Int as _, false).into(), - self.int_type.const_int(int as _, false).into(), + self.const_int(int).into() ]) .into() } + pub fn const_float(&self, float: f64) -> FloatValue<'ctx> { + self.float_type.const_float(float) + } + pub fn new_float(&self, float: f64) -> BasicValueEnum<'ctx> { self.value_type .const_named_struct(&[ self.int_type.const_int(ValueTag::Float as _, false).into(), - self.float_type.const_float(float).into(), + self.const_float(float).into() ]) .into() } diff --git a/src/eval/jit/mod.rs b/src/eval/jit/mod.rs index 5ac687f..73028aa 100644 --- a/src/eval/jit/mod.rs +++ b/src/eval/jit/mod.rs @@ -6,8 +6,10 @@ use inkwell::builder::Builder; use inkwell::context::Context; use inkwell::execution_engine::ExecutionEngine; use inkwell::module::Module; +use inkwell::values::{AnyValue, AsValueRef, BasicMetadataValueEnum, BasicValueEnum, IntValue, StructValue}; use crate::env::VmEnv; +use crate::ir::{Ir, UnOpKind}; use crate::ty::internal::Value; mod compile; @@ -135,4 +137,30 @@ impl<'ctx> JITContext<'ctx> { helpers, } } + + pub fn compile(&self, ir: Ir) -> JITFunc { + + } + + pub fn get_tag(&self, val: BasicValueEnum<'ctx>) -> IntValue<'ctx> { + let alloca = self + .builder + .build_alloca(self.helpers.value_type, "get_tag_alloca").unwrap(); + self.builder.build_store(alloca, val).unwrap(); + self.builder + .build_load( + self.context.bool_type(), + self.builder + .build_struct_gep(self.helpers.value_type, alloca, 1, "get_tag_gep").unwrap(), + "get_tag", + ).unwrap() + .into_int_value() + } + + pub fn call(&self, args: &[BasicMetadataValueEnum<'ctx>]) -> StructValue<'ctx> { + self.builder.build_call(self.helpers.call, args, "call") + .unwrap() + .as_any_value_enum() + .into_struct_value() + } } diff --git a/src/ir/mod.rs b/src/ir/mod.rs index 930d89f..851b77a 100644 --- a/src/ir/mod.rs +++ b/src/ir/mod.rs @@ -1,7 +1,7 @@ use derive_more::{IsVariant, TryUnwrap, Unwrap}; -use hashbrown::HashMap; - use ecow::EcoString; +use hashbrown::HashMap; +use inkwell::values::{StructValue, FunctionValue}; use itertools::Itertools; use rnix::ast::HasEntry; use rnix::ast::{self, Expr}; @@ -91,9 +91,9 @@ macro_rules! ir { } impl JITCompile for Ir { - fn compile(self, ctx: &JITContext) { + fn compile<'ctx>(self, ctx: &JITContext<'ctx>, func: FunctionValue<'ctx>) -> StructValue<'ctx>{ match self { - $(Ir::$ty(ir) => ir.compile(ctx),)* + $(Ir::$ty(ir) => ir.compile(ctx, func),)* } } } @@ -183,7 +183,7 @@ struct Env<'a, 'env> { env: EnvNode<'a>, prev: Option<&'env Env<'a, 'env>>, arg_level: usize, - let_level: usize + let_level: usize, } enum EnvNode<'a> { @@ -208,7 +208,7 @@ impl<'a, 'env> Env<'a, 'env> { env: EnvNode::Builtins(base), prev: None, arg_level: 0, - let_level: 0 + let_level: 0, } } @@ -217,7 +217,7 @@ impl<'a, 'env> Env<'a, 'env> { env: EnvNode::Let(map), prev: Some(self), arg_level: self.arg_level, - let_level: self.let_level + 1 + let_level: self.let_level + 1, } } @@ -226,7 +226,7 @@ impl<'a, 'env> Env<'a, 'env> { env: EnvNode::SingleArg(ident), prev: Some(self), arg_level: self.arg_level + 1, - let_level: self.let_level + let_level: self.let_level, } } @@ -239,7 +239,7 @@ impl<'a, 'env> Env<'a, 'env> { env: EnvNode::MultiArg(map, alias), prev: Some(self), arg_level: self.arg_level + 1, - let_level: 0 + let_level: 0, } } @@ -248,7 +248,7 @@ impl<'a, 'env> Env<'a, 'env> { env: EnvNode::With, prev: Some(self), arg_level: self.arg_level, - let_level: self.let_level + let_level: self.let_level, } } @@ -283,7 +283,9 @@ impl<'a, 'env> Env<'a, 'env> { } SingleArg(arg) => { if arg == ident { - return Ok(LookupResult::SingleArg { level: arg_level - 1 }); + return Ok(LookupResult::SingleArg { + level: arg_level - 1, + }); } else { arg_level -= 1; } @@ -295,7 +297,9 @@ impl<'a, 'env> Env<'a, 'env> { default: default.clone(), }); } else if alias.as_ref() == Some(ident) { - return Ok(LookupResult::SingleArg { level: arg_level - 1 }); + return Ok(LookupResult::SingleArg { + level: arg_level - 1, + }); } else { arg_level -= 1; }