From 233f2dcbf7dee1913152c9ea838341e30a2fb8ea Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Mon, 23 Dec 2024 22:25:00 +0100 Subject: [PATCH] rip out most of the dead jit-related code --- Cargo.lock | 38 -- Cargo.toml | 1 - crates/dash_compiler/src/lib.rs | 4 +- crates/dash_llvm_jit_backend/Cargo.toml | 16 - .../dash_llvm_jit_backend/src/codegen/mod.rs | 625 ------------------ crates/dash_llvm_jit_backend/src/error.rs | 8 - crates/dash_llvm_jit_backend/src/lib.rs | 21 - .../src/llvm_wrapper/basic_block.rs | 4 - .../src/llvm_wrapper/builder.rs | 221 ------- .../src/llvm_wrapper/context.rs | 122 ---- .../src/llvm_wrapper/execution_engine.rs | 34 - .../src/llvm_wrapper/function.rs | 28 - .../src/llvm_wrapper/mod.rs | 21 - .../src/llvm_wrapper/module.rs | 58 -- .../src/llvm_wrapper/pass_manager.rs | 24 - .../src/llvm_wrapper/raw.rs | 2 - .../src/llvm_wrapper/ty.rs | 20 - .../src/llvm_wrapper/value.rs | 38 -- crates/dash_llvm_jit_backend/src/trace.rs | 61 -- crates/dash_llvm_jit_backend/src/util.rs | 18 - crates/dash_middle/src/compiler/constant.rs | 17 +- crates/dash_vm/Cargo.toml | 5 +- crates/dash_vm/src/dispatch.rs | 56 +- crates/dash_vm/src/frame.rs | 11 +- crates/dash_vm/src/gc/trace.rs | 1 - crates/dash_vm/src/jit/frontend.rs | 89 --- crates/dash_vm/src/jit/mod.rs | 157 ----- crates/dash_vm/src/jit/query.rs | 54 -- crates/dash_vm/src/lib.rs | 34 - 29 files changed, 13 insertions(+), 1775 deletions(-) delete mode 100644 crates/dash_llvm_jit_backend/Cargo.toml delete mode 100644 crates/dash_llvm_jit_backend/src/codegen/mod.rs delete mode 100644 crates/dash_llvm_jit_backend/src/error.rs delete mode 100644 crates/dash_llvm_jit_backend/src/lib.rs delete mode 100644 crates/dash_llvm_jit_backend/src/llvm_wrapper/basic_block.rs delete mode 100644 crates/dash_llvm_jit_backend/src/llvm_wrapper/builder.rs delete mode 100644 crates/dash_llvm_jit_backend/src/llvm_wrapper/context.rs delete mode 100644 crates/dash_llvm_jit_backend/src/llvm_wrapper/execution_engine.rs delete mode 100644 crates/dash_llvm_jit_backend/src/llvm_wrapper/function.rs delete mode 100644 crates/dash_llvm_jit_backend/src/llvm_wrapper/mod.rs delete mode 100644 crates/dash_llvm_jit_backend/src/llvm_wrapper/module.rs delete mode 100644 crates/dash_llvm_jit_backend/src/llvm_wrapper/pass_manager.rs delete mode 100644 crates/dash_llvm_jit_backend/src/llvm_wrapper/raw.rs delete mode 100644 crates/dash_llvm_jit_backend/src/llvm_wrapper/ty.rs delete mode 100644 crates/dash_llvm_jit_backend/src/llvm_wrapper/value.rs delete mode 100644 crates/dash_llvm_jit_backend/src/trace.rs delete mode 100644 crates/dash_llvm_jit_backend/src/util.rs delete mode 100644 crates/dash_vm/src/jit/frontend.rs delete mode 100644 crates/dash_vm/src/jit/mod.rs delete mode 100644 crates/dash_vm/src/jit/query.rs diff --git a/Cargo.lock b/Cargo.lock index 370bd3e3..3ade180d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -341,16 +341,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" -[[package]] -name = "cstr" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8aa998c33a6d3271e3678950a22134cd7dd27cef86dee1b611b5b14207d1d90b" -dependencies = [ - "proc-macro2", - "quote", -] - [[package]] name = "csv" version = "1.3.0" @@ -437,20 +427,6 @@ dependencies = [ "either", ] -[[package]] -name = "dash_llvm_jit_backend" -version = "0.1.0" -dependencies = [ - "bitvec", - "cstr", - "dash_log", - "dash_middle", - "dash_typed_cfg", - "indexmap 1.9.3", - "llvm-sys", - "thiserror", -] - [[package]] name = "dash_log" version = "0.1.0" @@ -651,7 +627,6 @@ dependencies = [ "criterion", "dash_compiler", "dash_lexer", - "dash_llvm_jit_backend", "dash_log", "dash_middle", "dash_optimizer", @@ -1148,19 +1123,6 @@ version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" -[[package]] -name = "llvm-sys" -version = "140.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3dc78e9857c0231ec11e3bdccf63870493fdc7d0570b0ea7d50bf5df0cb1a0c" -dependencies = [ - "cc", - "lazy_static", - "libc", - "regex", - "semver", -] - [[package]] name = "lock_api" version = "0.4.11" diff --git a/Cargo.toml b/Cargo.toml index 17b20e96..76d88836 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,6 @@ members = [ # (commented out so the project can be built in the root dir) # # "crates/dash_wasm", - # "crates/dash_llvm_jit_backend", ] resolver = "2" diff --git a/crates/dash_compiler/src/lib.rs b/crates/dash_compiler/src/lib.rs index 4a3cb37a..4b8d6a09 100644 --- a/crates/dash_compiler/src/lib.rs +++ b/crates/dash_compiler/src/lib.rs @@ -1,5 +1,4 @@ -use std::cell::{Cell, RefCell}; -use std::collections::HashSet; +use std::cell::Cell; use std::rc::Rc; use dash_log::{Level, debug, span}; @@ -1797,7 +1796,6 @@ impl Visitor> for FunctionCompiler<'_> { }, externals: cmp.externals.into(), rest_local, - poison_ips: RefCell::new(HashSet::new()), debug_symbols: cmp.debug_symbols, source: Rc::clone(&ib.source), references_arguments: cmp.references_arguments.is_some(), diff --git a/crates/dash_llvm_jit_backend/Cargo.toml b/crates/dash_llvm_jit_backend/Cargo.toml deleted file mode 100644 index afb86398..00000000 --- a/crates/dash_llvm_jit_backend/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "dash_llvm_jit_backend" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -llvm-sys = "140.0.2" -indexmap = "1.9.0" -cstr = "0.2.10" -dash_middle = { path = "../dash_middle" } -dash_log = { path = "../dash_log" } -thiserror = "1.0.38" -bitvec = "1.0.1" -dash_typed_cfg = { path = "../dash_typed_cfg" } diff --git a/crates/dash_llvm_jit_backend/src/codegen/mod.rs b/crates/dash_llvm_jit_backend/src/codegen/mod.rs deleted file mode 100644 index 7013a1b5..00000000 --- a/crates/dash_llvm_jit_backend/src/codegen/mod.rs +++ /dev/null @@ -1,625 +0,0 @@ -use std::collections::{HashMap, HashSet}; - -use dash_middle::compiler::constant::{BooleanConstant, NumberConstant}; -use dash_middle::compiler::instruction::{AssignKind, Instruction, IntrinsicOperation}; -use dash_middle::util::is_integer; -use dash_typed_cfg::passes::bb_generation::{ - BasicBlockKey, BasicBlockMap, BasicBlockSuccessor, ConditionalBranchAction, -}; -use dash_typed_cfg::passes::type_infer::{Type, TypeMap}; -use dash_typed_cfg::util::DecodeCtxt; -use dash_typed_cfg::TypedCfg; -use llvm_sys::execution_engine::{LLVMExecutionEngineRef, LLVMGetFunctionAddress}; -use llvm_sys::prelude::{ - LLVMBasicBlockRef, LLVMBuilderRef, LLVMContextRef, LLVMModuleRef, LLVMPassManagerRef, LLVMTypeRef, LLVMValueRef, -}; -use llvm_sys::target_machine::LLVMCodeGenOptLevel; -use llvm_sys::LLVMTypeKind; - -use crate::error::Error; -use crate::llvm_wrapper as llvm; -use crate::llvm_wrapper::Value; -use dash_typed_cfg::error::Error as TcfgError; - -use cstr::cstr; - -pub type JitFunction = unsafe extern "C" fn( - *mut (), // stack pointer - u64, // stack offset for frame - *mut u64, // out pointer for the IP after exiting -); - -fn value_ty_in_context(cx: &llvm::Context, ee: &llvm::ExecutionEngine) -> llvm::Ty { - let mut elements = [ - // Discriminant - cx.i8_ty(), - // Data ptr - cx.i64_ty(), - // Vtable ptr - cx.i64_ty(), - ]; - let value = cx.struct_ty_unpacked(&mut elements); - debug_assert_eq!(ee.size_of_ty_bits(&value), usize::BITS as usize * 3); - value -} - -fn function_type(cx: &llvm::Context, ee: &llvm::ExecutionEngine) -> llvm::Ty { - let mut args = [ - cx.pointer_ty(&value_ty_in_context(cx, ee)), - cx.i64_ty(), - cx.pointer_ty(&cx.i64_ty()), - ]; - let ret = cx.void_ty(); - cx.function_ty(&ret, &mut args) -} - -/// Recursively registers all reachable basic blocks -/// (i.e. actioned successor blocks) -fn register_llvm_bbs( - llcx: &llvm::Context, - func: &llvm::Function, - bb_map: &BasicBlockMap, - llvm_bbs: &mut HashMap, - bbk: BasicBlockKey, - visited: &mut HashSet, -) { - if visited.contains(&bbk) { - return; - } - visited.insert(bbk); - - let bb = llcx.append_basic_block(func, cstr!("bb")); - llvm_bbs.insert(bbk, bb); - - match &bb_map[&bbk].successor { - Some(BasicBlockSuccessor::Conditional { - true_ip, - false_ip, - action, - }) => { - if let Some(ConditionalBranchAction::Either | ConditionalBranchAction::Taken) = action { - register_llvm_bbs(llcx, func, bb_map, llvm_bbs, *true_ip, visited); - } - if let Some(ConditionalBranchAction::Either | ConditionalBranchAction::NotTaken) = action { - register_llvm_bbs(llcx, func, bb_map, llvm_bbs, *false_ip, visited); - } - } - Some(BasicBlockSuccessor::Unconditional(target)) => { - register_llvm_bbs(llcx, func, bb_map, llvm_bbs, *target, visited); - } - None => {} - } -} - -pub enum JitConstant { - Boolean(bool), - I64(i64), - F64(f64), -} - -impl JitConstant { - pub fn to_llvm_value(&self, llcx: &llvm::Context) -> Value { - match self { - JitConstant::Boolean(b) => llcx.const_i1(*b), - JitConstant::I64(i) => llcx.const_i64(*i), - JitConstant::F64(f) => llcx.const_f64(*f), - } - } -} - -pub trait CodegenQuery { - fn boolean_constant(&self, id: BooleanConstant) -> bool; - fn number_constant(&self, id: NumberConstant) -> f64; -} - -pub struct CodegenCtxt<'a, 'q, Q> { - pub ty_map: &'q TypeMap, - pub bb_map: &'q BasicBlockMap, - pub bytecode: &'a [u8], - pub query: &'q mut Q, - - pub bbs_visited: HashSet, - pub llcx: llvm::Context, - pub module: llvm::Module, - pub ee: llvm::ExecutionEngine, - pub pm: llvm::PassManager, - pub function: llvm::Function, - pub value_ty: llvm::Ty, - pub locals: HashMap, - pub llvm_bbs: HashMap, - pub builder: llvm::Builder, - pub setup_block: llvm::BasicBlock, - pub exit_block: llvm::BasicBlock, - pub exit_guards: Vec<(usize, llvm::BasicBlock)>, -} - -impl<'a, 'q, Q: CodegenQuery> CodegenCtxt<'a, 'q, Q> { - pub fn new(ty_map: &'q TypeMap, bb_map: &'q BasicBlockMap, bytecode: &'a [u8], query: &'q mut Q) -> Self { - let mut llcx = llvm::Context::new(); - let module = llcx.create_module(); - let ee = module.create_execution_engine(); - let pm = llvm::PassManager::new(LLVMCodeGenOptLevel::LLVMCodeGenLevelAggressive); - let value_ty = value_ty_in_context(&llcx, &ee); - let function = module.create_c_function(&function_type(&llcx, &ee)); - let locals = HashMap::new(); - let mut llvm_bbs = HashMap::new(); - let builder = llcx.create_builder(); - let setup_block = llcx.append_basic_block(&function, cstr!("setup")); - let exit_block = llcx.append_basic_block(&function, cstr!("exit")); - let exit_guards = Vec::new(); - - register_llvm_bbs(&llcx, &function, bb_map, &mut llvm_bbs, 0, &mut HashSet::new()); - - Self { - ty_map, - bb_map, - bbs_visited: HashSet::new(), - query, - llcx, - module, - ee, - pm, - function, - value_ty, - locals, - llvm_bbs, - builder, - setup_block, - exit_block, - exit_guards, - bytecode, - } - } - - fn alloca_local(&self, t: &Type) -> Value { - self.builder.build_alloca(&self.llcx.mir_ty_to_llvm_ty(t)) - } - - fn load_local(&self, id: u16) -> Value { - let (val, ty) = &self.locals[&id]; - self.builder.build_load(ty, val) - } - - fn store_local(&self, id: u16, value: &Value) -> Value { - let (dest, _) = &self.locals[&id]; - self.builder.build_store(value, dest) - } - - fn cast_mir(&self, value: &Value, from: &Type, to: &Type) -> Value { - match (from, to) { - (Type::I64, Type::Boolean) => self.builder.build_trunc(&self.llcx.i1_ty(), value), - (Type::F64, Type::Boolean) => { - let to_int = self.cast_mir(value, from, &Type::I64); - self.cast_mir(&to_int, &Type::I64, &Type::Boolean) - } - (Type::Boolean, Type::I64) => self.builder.build_sext(&self.llcx.i64_ty(), value), - (Type::Boolean, Type::F64) => { - let to_int = self.cast_mir(value, from, &Type::I64); - self.cast_mir(&to_int, &Type::I64, &Type::F64) - } - (Type::I64, Type::F64) => self.builder.build_si2fp(&self.llcx.f64_ty(), value), - (Type::F64, Type::I64) => self.builder.build_fp2si(&self.llcx.i64_ty(), value), - _ => panic!("Invalid cast {from:?} -> {to:?}"), - } - } - - /// Compiles the setup block. This block allocates stack space - /// for the referenced local variables and has various checks. - /// - /// This function should be called before compiling other parts. - pub fn compile_setup_block(&mut self) { - self.builder.position_at_end(&self.setup_block); - - for (&id, ty) in self.ty_map.iter() { - // Allocate space for local - let space = self.alloca_local(ty); - - // Copy value from the VM stack to the JIT stack - let stack_ptr = self.function.get_param(0); - let stack_offset = self.function.get_param(1); - let index = self.llcx.const_i64(id as i64); - - let stack_offset = self.builder.build_add(&stack_offset, &index); - let ptr = self - .builder - .build_gep(&self.value_ty, &stack_ptr, &mut [stack_offset, self.llcx.const_i32(1)]); - - let value = self.builder.build_load(&self.llcx.i64_ty(), &ptr); - - // Cast to appropriate type, since `value` is currently an i64 - // which is wrong in any case. - let value = match ty { - Type::Boolean => self.cast_mir(&value, &Type::I64, ty), - Type::I64 => { - // even though value is of type i64, it only contains the raw bits - // so we need to do a i64 -> f64 -> i64 roundtrip - let as_f64 = self.builder.build_bitcast(&self.llcx.f64_ty(), &value); - self.cast_mir(&as_f64, &Type::F64, &Type::I64) - } - Type::F64 => self.builder.build_bitcast(&self.llcx.f64_ty(), &value), - }; - - // Finally, copy the cast value to the allocated space - self.builder.build_store(&value, &space); - - self.locals.insert(id, (space, self.llcx.mir_ty_to_llvm_ty(ty))); - } - - let first_bb = &self.llvm_bbs[&0]; - self.builder.build_br(first_bb); - } - - /// Compiles the exit block. - /// - /// This function should be called after compiling other parts. - pub fn compile_exit_block(&mut self) { - // Jump to exit block - self.builder.position_at_end(&self.exit_block); - - let mut ret_phi = self.builder.build_phi(&self.llcx.i64_ty()); - for (ip, block) in &self.exit_guards { - ret_phi.add_incoming(&self.llcx.const_i64(*ip as i64), block); - } - let out_ip = self.function.get_param(2); - self.builder.build_store(ret_phi.as_value(), &out_ip); - - for (&local_index, ty) in self.ty_map.iter() { - let (space, llty) = &self.locals[&local_index]; - let value = self.builder.build_load(llty, space); - - // Cast the type we have on the JIT stack back to an i64 - // so it matches the out pointer in the fn signature. - let value = match ty { - Type::Boolean => self.cast_mir(&value, ty, &Type::I64), - Type::I64 => { - let as_f64 = self.cast_mir(&value, ty, &Type::F64); - self.builder.build_bitcast(&self.llcx.i64_ty(), &as_f64) - } - Type::F64 => self.builder.build_bitcast(&self.llcx.i64_ty(), &value), - }; - - let stack_ptr = self.function.get_param(0); - let stack_offset = self.function.get_param(1); - let index = self.llcx.const_i64(local_index as i64); - let stack_offset = self.builder.build_add(&stack_offset, &index); - let dest = self - .builder - .build_gep(&self.value_ty, &stack_ptr, &mut [stack_offset, self.llcx.const_i32(1)]); - - self.builder.build_store(&value, &dest); - } - - self.builder.build_retvoid(); - } - - pub fn compile_bb(&mut self, mut stack: ValueStack, bbk: BasicBlockKey) -> Result<(), Error> { - if self.bbs_visited.contains(&bbk) { - return Ok(()); - } - self.bbs_visited.insert(bbk); - - let (mut dcx, succ, block_offset) = { - let bb = &self.bb_map[&bbk]; - let bytecode = &self.bytecode[bb.index..bb.end]; - - (DecodeCtxt::new(bytecode), bb.successor, bb.index) - }; - - let bb = &self.llvm_bbs[&bbk]; - self.builder.position_at_end(bb); - - while let Some((index, instr)) = dcx.next_instruction() { - match instr { - Instruction::Add => stack.binop(|a, b| self.builder.build_add(&a, &b)), - Instruction::Sub => stack.binop(|a, b| self.builder.build_sub(&a, &b)), - Instruction::Mul => stack.binop(|a, b| self.builder.build_mul(&a, &b)), - Instruction::Div => stack.binop(|a, b| self.builder.build_div(&a, &b)), - Instruction::Rem => stack.binop(|a, b| self.builder.build_rem(&a, &b)), - Instruction::Lt => stack.binop(|a, b| self.builder.build_lt(&a, &b)), - Instruction::Gt => stack.binop(|a, b| self.builder.build_gt(&a, &b)), - Instruction::Le => stack.binop(|a, b| self.builder.build_le(&a, &b)), - Instruction::Ge => stack.binop(|a, b| self.builder.build_ge(&a, &b)), - Instruction::Eq => stack.binop(|a, b| self.builder.build_eq(&a, &b)), - Instruction::Ne => stack.binop(|a, b| self.builder.build_ne(&a, &b)), - Instruction::LdLocal => { - let id = dcx.next_byte(); - let val = self.load_local(id.into()); - stack.push(val); - } - Instruction::StoreLocal => { - let id = dcx.next_wide(); - let kind = AssignKind::from_repr(dcx.next_byte()).unwrap(); - assert_eq!(kind, AssignKind::Assignment); - let value = stack.pop(); - self.store_local(id, &value); - let value = self.load_local(id); - stack.push(value); - } - Instruction::Boolean | Instruction::Number => { - let id = dcx.next_wide(); - let value = match instr { - Instruction::Boolean => self.llcx.const_i1(self.query.boolean_constant(BooleanConstant(id))), - Instruction::Number => { - let val = self.query.number_constant(NumberConstant(id)); - if is_integer(val) { - self.llcx.const_i64(val as i64) - } else { - self.llcx.const_f64(val) - } - } - _ => unreachable!(), - }; - stack.push(value); - } - Instruction::String - | Instruction::Regex - | Instruction::Null - | Instruction::Undefined - | Instruction::Function => todo!(), - Instruction::Pop => drop(stack.pop()), - Instruction::Jmp => { - let bb = &self.bb_map[&bbk]; - let Some(BasicBlockSuccessor::Unconditional(target)) = &bb.successor else { - panic!("unmatched basic block successor"); - }; - let llbb = &self.llvm_bbs[target]; - self.builder.build_br(llbb); - self.compile_bb(stack.clone(), *target); - - return Ok(()); - } - Instruction::JmpFalseP - | Instruction::JmpFalseNP - | Instruction::JmpTrueP - | Instruction::JmpTrueNP - | Instruction::JmpNullishP - | Instruction::JmpNullishNP - | Instruction::JmpUndefinedNP - | Instruction::JmpUndefinedP => { - let cond = match instr { - Instruction::JmpFalseP - | Instruction::JmpNullishP - | Instruction::JmpTrueP - | Instruction::JmpUndefinedP => stack.pop(), - _ => stack.last(), - }; - - let count = dcx.next_wide_signed(); - let _target_ip = usize::try_from(index as i16 + count + 3).unwrap(); - let bb = &self.bb_map[&bbk]; - let Some(BasicBlockSuccessor::Conditional { - true_ip, - false_ip, - action: Some(action), - }) = bb.successor - else { - panic!("unmatched basic block successor"); - }; - - let (true_ip, false_ip) = match instr { - Instruction::JmpTrueNP | Instruction::JmpTrueP => (true_ip, false_ip), - Instruction::JmpFalseNP | Instruction::JmpFalseP => (false_ip, true_ip), - _ => todo!(), - }; - let llbb = self.llvm_bbs[&bbk].clone(); - - match action { - ConditionalBranchAction::Either => { - let true_bb = &self.llvm_bbs[&true_ip]; - let false_bb = &self.llvm_bbs[&false_ip]; - self.builder.build_condbr(&cond, true_bb, false_bb); - self.compile_bb(stack.clone(), true_ip); - self.compile_bb(stack.clone(), false_ip); - } - ConditionalBranchAction::NotTaken => { - let bb = &self.llvm_bbs[&true_ip]; - self.exit_guards.push((false_ip, llbb)); - - self.builder.build_condbr(&cond, bb, &self.exit_block); - self.compile_bb(stack.clone(), true_ip); - } - ConditionalBranchAction::Taken => { - let bb = &self.llvm_bbs[&false_ip]; - self.exit_guards.push((true_ip, llbb)); - - self.builder.build_condbr(&cond, &self.exit_block, bb); - self.compile_bb(stack.clone(), false_ip); - } - } - - return Ok(()); - } - Instruction::IntrinsicOp => { - let op = IntrinsicOperation::from_repr(dcx.next_byte()).unwrap(); - - match op { - IntrinsicOperation::AddNumLR => stack.binop(|a, b| self.builder.build_add(&a, &b)), - IntrinsicOperation::SubNumLR => stack.binop(|a, b| self.builder.build_sub(&a, &b)), - IntrinsicOperation::MulNumLR => stack.binop(|a, b| self.builder.build_mul(&a, &b)), - IntrinsicOperation::DivNumLR => stack.binop(|a, b| self.builder.build_div(&a, &b)), - IntrinsicOperation::RemNumLR => stack.binop(|a, b| self.builder.build_rem(&a, &b)), - IntrinsicOperation::GtNumLR => stack.binop(|a, b| self.builder.build_gt(&a, &b)), - IntrinsicOperation::GeNumLR => stack.binop(|a, b| self.builder.build_ge(&a, &b)), - IntrinsicOperation::LtNumLR => stack.binop(|a, b| self.builder.build_lt(&a, &b)), - IntrinsicOperation::LeNumLR => stack.binop(|a, b| self.builder.build_le(&a, &b)), - IntrinsicOperation::EqNumLR => stack.binop(|a, b| self.builder.build_eq(&a, &b)), - IntrinsicOperation::NeNumLR => stack.binop(|a, b| self.builder.build_ne(&a, &b)), - IntrinsicOperation::BitOrNumLR => todo!(), - IntrinsicOperation::BitXorNumLR => todo!(), - IntrinsicOperation::BitAndNumLR => todo!(), - IntrinsicOperation::BitShlNumLR => todo!(), - IntrinsicOperation::BitShrNumLR => todo!(), - IntrinsicOperation::BitUshrNumLR => todo!(), - IntrinsicOperation::LtNumLConstR - | IntrinsicOperation::LeNumLConstR - | IntrinsicOperation::GtNumLConstR - | IntrinsicOperation::GeNumLConstR => { - let value = stack.pop(); - let num = dcx.next_byte() as f64; - let rhs = match value.ty_kind() { - LLVMTypeKind::LLVMIntegerTypeKind => self.llcx.const_i64(num as i64), - LLVMTypeKind::LLVMDoubleTypeKind => self.llcx.const_f64(num), - _ => unreachable!(), - }; - let res = match op { - IntrinsicOperation::LtNumLConstR => self.builder.build_lt(&value, &rhs), - IntrinsicOperation::LeNumLConstR => self.builder.build_le(&value, &rhs), - IntrinsicOperation::GtNumLConstR => self.builder.build_gt(&value, &rhs), - IntrinsicOperation::GeNumLConstR => self.builder.build_ge(&value, &rhs), - _ => unreachable!(), - }; - stack.push(res); - } - IntrinsicOperation::GtNumLConstR32 - | IntrinsicOperation::GeNumLConstR32 - | IntrinsicOperation::LtNumLConstR32 - | IntrinsicOperation::LeNumLConstR32 => { - let value = stack.pop(); - let num = dcx.next_u32() as f64; - let rhs = match value.ty_kind() { - LLVMTypeKind::LLVMIntegerTypeKind => self.llcx.const_i64(num as i64), - LLVMTypeKind::LLVMDoubleTypeKind => self.llcx.const_f64(num), - _ => unreachable!(), - }; - let res = match op { - IntrinsicOperation::LtNumLConstR32 => self.builder.build_lt(&value, &rhs), - IntrinsicOperation::LeNumLConstR32 => self.builder.build_le(&value, &rhs), - IntrinsicOperation::GtNumLConstR32 => self.builder.build_gt(&value, &rhs), - IntrinsicOperation::GeNumLConstR32 => self.builder.build_ge(&value, &rhs), - _ => unreachable!(), - }; - stack.push(res); - } - IntrinsicOperation::PostfixIncLocalNum => { - let id = dcx.next_byte(); - let old = self.load_local(id.into()); - let rhs = match old.ty_kind() { - LLVMTypeKind::LLVMIntegerTypeKind => self.llcx.const_i64(1), - LLVMTypeKind::LLVMDoubleTypeKind => self.llcx.const_f64(1.0), - _ => unreachable!(), - }; - let value = self.builder.build_add(&old, &rhs); - self.store_local(id.into(), &value); - stack.push(old); - } - IntrinsicOperation::PostfixDecLocalNum => { - let id = dcx.next_byte(); - let old = self.load_local(id.into()); - let rhs = match old.ty_kind() { - LLVMTypeKind::LLVMIntegerTypeKind => self.llcx.const_i64(1), - LLVMTypeKind::LLVMDoubleTypeKind => self.llcx.const_f64(1.0), - _ => unreachable!(), - }; - let value = self.builder.build_sub(&old, &rhs); - self.store_local(id.into(), &value); - stack.push(old); - } - IntrinsicOperation::PrefixIncLocalNum => { - let id = dcx.next_byte(); - let old = self.load_local(id.into()); - let rhs = match old.ty_kind() { - LLVMTypeKind::LLVMIntegerTypeKind => self.llcx.const_i64(1), - LLVMTypeKind::LLVMDoubleTypeKind => self.llcx.const_f64(1.0), - _ => unreachable!(), - }; - let value = self.builder.build_add(&old, &rhs); - self.store_local(id.into(), &value); - stack.push(value); - } - IntrinsicOperation::PrefixDecLocalNum => { - let id = dcx.next_byte(); - let old = self.load_local(id.into()); - let rhs = match old.ty_kind() { - LLVMTypeKind::LLVMIntegerTypeKind => self.llcx.const_i64(1), - LLVMTypeKind::LLVMDoubleTypeKind => self.llcx.const_f64(1.0), - _ => unreachable!(), - }; - let value = self.builder.build_sub(&old, &rhs); - self.store_local(id.into(), &value); - stack.push(value); - } - _ => return Err(TcfgError::UnsupportedInstruction { instr }.into()), - } - } - Instruction::Ret => { - let _value = stack.pop(); - let _c = dcx.next_wide(); - } - _ => return Err(TcfgError::UnsupportedInstruction { instr }.into()), - } - } - - // End of basic block was not reached in the block, - // which means that this basic block was terminated - // early not by a conditional jump but by another label - if let Some(succ) = succ { - let BasicBlockSuccessor::Unconditional(target) = succ else { - panic!("mismatching basic block successor {succ:?}"); - }; - let next_bb = &self.llvm_bbs[&target]; - self.builder.build_br(next_bb); - self.compile_bb(stack, target); - } - - Ok(()) - } -} - -#[derive(Default, Clone)] -pub struct ValueStack(Vec); - -impl ValueStack { - pub fn binop(&mut self, fun: F) - where - F: Fn(Value, Value) -> Value, - { - let (a, b) = self.pop2(); - let res = fun(a, b); - self.0.push(res); - } - - pub fn push(&mut self, value: Value) { - self.0.push(value); - } - - pub fn pop(&mut self) -> Value { - self.0.pop().unwrap() - } - - pub fn last(&mut self) -> Value { - self.0.last().unwrap().clone() - } - - pub fn pop2(&mut self) -> (Value, Value) { - let b = self.pop(); - let a = self.pop(); - (a, b) - } -} - -impl Drop for ValueStack { - fn drop(&mut self) { - // if the stack of LLVM values is not empty (i.e. stack has leftover values) - // it implies that we somehow need to synchronize/push it to the VM stack - // in the epilogue. - // test case that shows the problem: 1 + (i % 2 == 0 ? 2 : 3) - // in one of the branches, we potentially need to return to the VM, - // and the VM will need the value `1`. - assert_eq!(self.0.len(), 0, "Value stack must be empty"); - } -} - -pub fn compile_typed_cfg( - bytecode: &[u8], - tcfg: &TypedCfg, - query: &mut Q, -) -> Result { - let mut codegenctxt = CodegenCtxt::new(&tcfg.ty_map, &tcfg.bb_map, bytecode, query); - codegenctxt.compile_setup_block(); - codegenctxt.compile_bb(ValueStack::default(), 0)?; - codegenctxt.compile_exit_block(); - codegenctxt.module.verify(); - codegenctxt.module.run_pass_manager(&codegenctxt.pm); - let func = codegenctxt.ee.compile_fn(codegenctxt.function.name()); - Ok(func) -} diff --git a/crates/dash_llvm_jit_backend/src/error.rs b/crates/dash_llvm_jit_backend/src/error.rs deleted file mode 100644 index 28dcf5d6..00000000 --- a/crates/dash_llvm_jit_backend/src/error.rs +++ /dev/null @@ -1,8 +0,0 @@ -use dash_middle::compiler::instruction::Instruction; -use thiserror::Error; - -#[derive(Debug, Error)] -pub enum Error { - #[error("{_0}")] - TypedCfg(#[from] dash_typed_cfg::error::Error), -} diff --git a/crates/dash_llvm_jit_backend/src/lib.rs b/crates/dash_llvm_jit_backend/src/lib.rs deleted file mode 100644 index d92587a8..00000000 --- a/crates/dash_llvm_jit_backend/src/lib.rs +++ /dev/null @@ -1,21 +0,0 @@ -#![allow(unused)] - -use llvm_sys::execution_engine::LLVMLinkInMCJIT; -use llvm_sys::target::{LLVM_InitializeNativeAsmParser, LLVM_InitializeNativeAsmPrinter, LLVM_InitializeNativeTarget}; - -pub mod codegen; -pub mod error; -mod llvm_wrapper; -pub mod trace; -pub mod util; - -pub use trace::Trace; - -pub fn init() { - unsafe { - LLVM_InitializeNativeTarget(); - LLVM_InitializeNativeAsmPrinter(); - LLVM_InitializeNativeAsmParser(); - LLVMLinkInMCJIT(); - } -} diff --git a/crates/dash_llvm_jit_backend/src/llvm_wrapper/basic_block.rs b/crates/dash_llvm_jit_backend/src/llvm_wrapper/basic_block.rs deleted file mode 100644 index 0e5e4a5e..00000000 --- a/crates/dash_llvm_jit_backend/src/llvm_wrapper/basic_block.rs +++ /dev/null @@ -1,4 +0,0 @@ -use llvm_sys::prelude::LLVMBasicBlockRef; - -#[derive(Clone)] -pub struct BasicBlock(pub(super) LLVMBasicBlockRef); diff --git a/crates/dash_llvm_jit_backend/src/llvm_wrapper/builder.rs b/crates/dash_llvm_jit_backend/src/llvm_wrapper/builder.rs deleted file mode 100644 index 78feff38..00000000 --- a/crates/dash_llvm_jit_backend/src/llvm_wrapper/builder.rs +++ /dev/null @@ -1,221 +0,0 @@ -use llvm_sys::core::{ - LLVMAddIncoming, LLVMBuildAdd, LLVMBuildAlloca, LLVMBuildBitCast, LLVMBuildBr, LLVMBuildCondBr, LLVMBuildFAdd, - LLVMBuildFCmp, LLVMBuildFDiv, LLVMBuildFMul, LLVMBuildFPToSI, LLVMBuildFRem, LLVMBuildFSub, LLVMBuildGEP2, - LLVMBuildICmp, LLVMBuildLoad2, LLVMBuildMul, LLVMBuildPhi, LLVMBuildRetVoid, LLVMBuildSDiv, LLVMBuildSExt, - LLVMBuildSIToFP, LLVMBuildSRem, LLVMBuildStore, LLVMBuildSub, LLVMBuildTrunc, LLVMPositionBuilderAtEnd, -}; -use llvm_sys::prelude::LLVMBuilderRef; -use llvm_sys::{LLVMIntPredicate, LLVMRealPredicate, LLVMTypeKind}; - -use crate::cstrp; - -use super::value::Phi; -use super::{BasicBlock, Ty, Value}; - -pub enum Predicate { - Lt, - Gt, - Le, - Ge, - Eq, - Ne, -} - -pub struct Builder(pub(super) LLVMBuilderRef); - -impl Builder { - pub fn position_at_end(&self, bb: &BasicBlock) { - unsafe { LLVMPositionBuilderAtEnd(self.0, bb.0) } - } - - /// Creates an alloca instruction for a local variable - pub fn build_alloca(&self, ty: &Ty) -> Value { - Value(unsafe { LLVMBuildAlloca(self.0, ty.0, cstrp!("alloca")) }) - } - - pub fn build_add(&self, a: &Value, b: &Value) -> Value { - let ty = a.ty_kind(); - let res = unsafe { - match ty { - LLVMTypeKind::LLVMIntegerTypeKind => LLVMBuildAdd(self.0, a.0, b.0, cstrp!("iadd")), - LLVMTypeKind::LLVMDoubleTypeKind => LLVMBuildFAdd(self.0, a.0, b.0, cstrp!("fadd")), - _ => panic!("unsupported type"), - } - }; - Value(res) - } - - pub fn build_sub(&self, a: &Value, b: &Value) -> Value { - let ty = a.ty_kind(); - let res = unsafe { - match ty { - LLVMTypeKind::LLVMIntegerTypeKind => LLVMBuildSub(self.0, a.0, b.0, cstrp!("isub")), - LLVMTypeKind::LLVMDoubleTypeKind => LLVMBuildFSub(self.0, a.0, b.0, cstrp!("fsub")), - _ => panic!("unsupported type"), - } - }; - Value(res) - } - - pub fn build_mul(&self, a: &Value, b: &Value) -> Value { - let ty = a.ty_kind(); - let res = unsafe { - match ty { - LLVMTypeKind::LLVMIntegerTypeKind => LLVMBuildMul(self.0, a.0, b.0, cstrp!("imul")), - LLVMTypeKind::LLVMDoubleTypeKind => LLVMBuildFMul(self.0, a.0, b.0, cstrp!("fmul")), - _ => panic!("unsupported type"), - } - }; - Value(res) - } - - pub fn build_div(&self, a: &Value, b: &Value) -> Value { - let ty = a.ty_kind(); - let res = unsafe { - match ty { - LLVMTypeKind::LLVMIntegerTypeKind => LLVMBuildSDiv(self.0, a.0, b.0, cstrp!("idiv")), - LLVMTypeKind::LLVMDoubleTypeKind => LLVMBuildFDiv(self.0, a.0, b.0, cstrp!("fdiv")), - _ => panic!("unsupported type"), - } - }; - Value(res) - } - - pub fn build_rem(&self, a: &Value, b: &Value) -> Value { - let ty = a.ty_kind(); - Value(unsafe { - match ty { - LLVMTypeKind::LLVMIntegerTypeKind => LLVMBuildSRem(self.0, a.0, b.0, cstrp!("srem")), - LLVMTypeKind::LLVMDoubleTypeKind => LLVMBuildFRem(self.0, a.0, b.0, cstrp!("frem")), - _ => panic!("unsupported type"), - } - }) - } - - pub fn build_cmp(&self, a: &Value, b: &Value, pred: Predicate) -> Value { - let ty = a.ty_kind(); - Value(unsafe { - match (ty, pred) { - (LLVMTypeKind::LLVMIntegerTypeKind, Predicate::Le) => { - LLVMBuildICmp(self.0, LLVMIntPredicate::LLVMIntSLE, a.0, b.0, cstrp!("ile")) - } - (LLVMTypeKind::LLVMIntegerTypeKind, Predicate::Lt) => { - LLVMBuildICmp(self.0, LLVMIntPredicate::LLVMIntSLT, a.0, b.0, cstrp!("ilt")) - } - (LLVMTypeKind::LLVMIntegerTypeKind, Predicate::Ge) => { - LLVMBuildICmp(self.0, LLVMIntPredicate::LLVMIntSGE, a.0, b.0, cstrp!("ige")) - } - (LLVMTypeKind::LLVMIntegerTypeKind, Predicate::Gt) => { - LLVMBuildICmp(self.0, LLVMIntPredicate::LLVMIntSGT, a.0, b.0, cstrp!("igt")) - } - (LLVMTypeKind::LLVMIntegerTypeKind, Predicate::Eq) => { - LLVMBuildICmp(self.0, LLVMIntPredicate::LLVMIntEQ, a.0, b.0, cstrp!("ieq")) - } - (LLVMTypeKind::LLVMIntegerTypeKind, Predicate::Ne) => { - LLVMBuildICmp(self.0, LLVMIntPredicate::LLVMIntNE, a.0, b.0, cstrp!("ine")) - } - (LLVMTypeKind::LLVMDoubleTypeKind, Predicate::Le) => { - LLVMBuildFCmp(self.0, LLVMRealPredicate::LLVMRealULE, a.0, b.0, cstrp!("fle")) - } - (LLVMTypeKind::LLVMDoubleTypeKind, Predicate::Lt) => { - LLVMBuildFCmp(self.0, LLVMRealPredicate::LLVMRealULT, a.0, b.0, cstrp!("flt")) - } - (LLVMTypeKind::LLVMDoubleTypeKind, Predicate::Ge) => { - LLVMBuildFCmp(self.0, LLVMRealPredicate::LLVMRealUGE, a.0, b.0, cstrp!("fge")) - } - (LLVMTypeKind::LLVMDoubleTypeKind, Predicate::Gt) => { - LLVMBuildFCmp(self.0, LLVMRealPredicate::LLVMRealUGT, a.0, b.0, cstrp!("fgt")) - } - (LLVMTypeKind::LLVMDoubleTypeKind, Predicate::Eq) => { - LLVMBuildFCmp(self.0, LLVMRealPredicate::LLVMRealUEQ, a.0, b.0, cstrp!("feq")) - } - (LLVMTypeKind::LLVMDoubleTypeKind, Predicate::Ne) => { - LLVMBuildFCmp(self.0, LLVMRealPredicate::LLVMRealUNE, a.0, b.0, cstrp!("fne")) - } - _ => panic!("Unsupported type for comparison"), - } - }) - } - - pub fn build_lt(&self, a: &Value, b: &Value) -> Value { - self.build_cmp(a, b, Predicate::Lt) - } - - pub fn build_gt(&self, a: &Value, b: &Value) -> Value { - self.build_cmp(a, b, Predicate::Gt) - } - - pub fn build_le(&self, a: &Value, b: &Value) -> Value { - self.build_cmp(a, b, Predicate::Le) - } - - pub fn build_ge(&self, a: &Value, b: &Value) -> Value { - self.build_cmp(a, b, Predicate::Ge) - } - - pub fn build_eq(&self, a: &Value, b: &Value) -> Value { - self.build_cmp(a, b, Predicate::Eq) - } - - pub fn build_ne(&self, a: &Value, b: &Value) -> Value { - self.build_cmp(a, b, Predicate::Ne) - } - - pub fn build_gep(&self, ty: &Ty, val: &Value, indices: &mut [Value]) -> Value { - let indices = Value::slice_of_values_as_raw(indices); - Value(unsafe { - LLVMBuildGEP2( - self.0, - ty.0, - val.0, - indices.as_mut_ptr(), - indices.len().try_into().unwrap(), - cstrp!("gep"), - ) - }) - } - - pub fn build_load(&self, ty: &Ty, val: &Value) -> Value { - Value(unsafe { LLVMBuildLoad2(self.0, ty.0, val.0, cstrp!("load")) }) - } - - pub fn build_trunc(&self, ty: &Ty, value: &Value) -> Value { - Value(unsafe { LLVMBuildTrunc(self.0, value.0, ty.0, cstrp!("trunc")) }) - } - - pub fn build_sext(&self, ty: &Ty, value: &Value) -> Value { - Value(unsafe { LLVMBuildSExt(self.0, value.0, ty.0, cstrp!("sext")) }) - } - - pub fn build_si2fp(&self, ty: &Ty, value: &Value) -> Value { - Value(unsafe { LLVMBuildSIToFP(self.0, value.0, ty.0, cstrp!("si2fp")) }) - } - - pub fn build_fp2si(&self, ty: &Ty, value: &Value) -> Value { - Value(unsafe { LLVMBuildFPToSI(self.0, value.0, ty.0, cstrp!("fp2si")) }) - } - - pub fn build_bitcast(&self, to: &Ty, value: &Value) -> Value { - Value(unsafe { LLVMBuildBitCast(self.0, value.0, to.0, cstrp!("bitcast")) }) - } - - pub fn build_store(&self, value: &Value, dest: &Value) -> Value { - Value(unsafe { LLVMBuildStore(self.0, value.0, dest.0) }) - } - - pub fn build_phi(&self, ty: &Ty) -> Phi { - Phi(Value(unsafe { LLVMBuildPhi(self.0, ty.0, cstrp!("phi")) })) - } - - pub fn build_retvoid(&self) -> Value { - Value(unsafe { LLVMBuildRetVoid(self.0) }) - } - - pub fn build_br(&self, to: &BasicBlock) -> Value { - Value(unsafe { LLVMBuildBr(self.0, to.0) }) - } - - pub fn build_condbr(&self, cond: &Value, then: &BasicBlock, el: &BasicBlock) -> Value { - Value(unsafe { LLVMBuildCondBr(self.0, cond.0, then.0, el.0) }) - } -} diff --git a/crates/dash_llvm_jit_backend/src/llvm_wrapper/context.rs b/crates/dash_llvm_jit_backend/src/llvm_wrapper/context.rs deleted file mode 100644 index e6000138..00000000 --- a/crates/dash_llvm_jit_backend/src/llvm_wrapper/context.rs +++ /dev/null @@ -1,122 +0,0 @@ -use std::ffi::{CStr, CString}; -use std::fmt::format; - -use dash_typed_cfg::passes::type_infer::Type; -use llvm_sys::core::{ - LLVMAppendBasicBlockInContext, LLVMConstInt, LLVMConstReal, LLVMContextCreate, LLVMCreateBuilderInContext, - LLVMDoubleTypeInContext, LLVMFunctionType, LLVMInt1TypeInContext, LLVMInt32TypeInContext, LLVMInt64TypeInContext, - LLVMInt8TypeInContext, LLVMModuleCreateWithNameInContext, LLVMPointerType, LLVMStructTypeInContext, - LLVMVoidTypeInContext, -}; -use llvm_sys::prelude::LLVMContextRef; - -use super::module::Module; -use super::{raw, BasicBlock, Builder, Function, Ty, Value}; - -pub struct Context { - module_count: usize, - cx: LLVMContextRef, -} - -impl Default for Context { - fn default() -> Self { - Self { - module_count: 0, - cx: unsafe { LLVMContextCreate() }, - } - } -} - -impl Context { - pub fn new() -> Self { - Self { - module_count: 0, - cx: unsafe { LLVMContextCreate() }, - } - } - - pub fn create_module_with_name(&mut self, name: &CStr) -> Module { - self.module_count += 1; - Module(unsafe { LLVMModuleCreateWithNameInContext(name.as_ptr(), self.cx) }) - } - - pub fn create_module(&mut self) -> Module { - self.create_module_with_name(c"anon") - } - - pub fn i1_ty(&self) -> Ty { - Ty(unsafe { LLVMInt1TypeInContext(self.cx) }) - } - - pub fn i8_ty(&self) -> Ty { - Ty(unsafe { LLVMInt8TypeInContext(self.cx) }) - } - - pub fn i32_ty(&self) -> Ty { - Ty(unsafe { LLVMInt32TypeInContext(self.cx) }) - } - - pub fn i64_ty(&self) -> Ty { - Ty(unsafe { LLVMInt64TypeInContext(self.cx) }) - } - - pub fn pointer_ty(&self, inner: &Ty) -> Ty { - Ty(unsafe { LLVMPointerType(inner.0, 0) }) - } - - pub fn void_ty(&self) -> Ty { - Ty(unsafe { LLVMVoidTypeInContext(self.cx) }) - } - - pub fn function_ty(&self, ret: &Ty, params: &mut [Ty]) -> Ty { - Ty(unsafe { - LLVMFunctionType( - ret.0, - Ty::slice_of_tys_as_raw(params).as_mut_ptr(), - params.len().try_into().unwrap(), - 0, - ) - }) - } - - pub fn const_i1(&self, val: bool) -> Value { - Value(unsafe { LLVMConstInt(self.i1_ty().0, val as u64, 0) }) - } - - pub fn const_i32(&self, val: i32) -> Value { - Value(unsafe { LLVMConstInt(self.i32_ty().0, val as u64, 0) }) - } - - pub fn const_i64(&self, val: i64) -> Value { - Value(unsafe { LLVMConstInt(self.i64_ty().0, val as u64, 0) }) - } - - pub fn const_f64(&self, val: f64) -> Value { - Value(unsafe { LLVMConstReal(self.f64_ty().0, val) }) - } - - pub fn f64_ty(&self) -> Ty { - Ty(unsafe { LLVMDoubleTypeInContext(self.cx) }) - } - - pub fn mir_ty_to_llvm_ty(&self, mir: &Type) -> Ty { - match mir { - Type::Boolean => self.i1_ty(), - Type::F64 => self.f64_ty(), - Type::I64 => self.i64_ty(), - } - } - - pub fn struct_ty_unpacked(&self, tys: &mut [Ty]) -> Ty { - let tys = Ty::slice_of_tys_as_raw(tys); - Ty(unsafe { LLVMStructTypeInContext(self.cx, tys.as_mut_ptr(), tys.len().try_into().unwrap(), 0) }) - } - - pub fn create_builder(&self) -> Builder { - Builder(unsafe { LLVMCreateBuilderInContext(self.cx) }) - } - - pub fn append_basic_block(&self, function: &Function, name: &CStr) -> BasicBlock { - BasicBlock(unsafe { LLVMAppendBasicBlockInContext(self.cx, function.as_ptr(), name.as_ptr()) }) - } -} diff --git a/crates/dash_llvm_jit_backend/src/llvm_wrapper/execution_engine.rs b/crates/dash_llvm_jit_backend/src/llvm_wrapper/execution_engine.rs deleted file mode 100644 index 31841634..00000000 --- a/crates/dash_llvm_jit_backend/src/llvm_wrapper/execution_engine.rs +++ /dev/null @@ -1,34 +0,0 @@ -use std::ffi::CStr; -use std::mem; - -use llvm_sys::execution_engine::{LLVMExecutionEngineRef, LLVMGetExecutionEngineTargetData, LLVMGetFunctionAddress}; -use llvm_sys::target::LLVMSizeOfTypeInBits; - -use super::Ty; - -pub type JitFunction = unsafe extern "C" fn( - *mut (), // stack pointer - u64, // stack offset for frame - *mut u64, // out pointer for the IP after exiting -); - -pub struct ExecutionEngine(pub(super) LLVMExecutionEngineRef); - -impl ExecutionEngine { - pub fn size_of_ty_bits(&self, ty: &Ty) -> usize { - unsafe { - // TODO: do we need to free this? - let target_data = LLVMGetExecutionEngineTargetData(self.0); - LLVMSizeOfTypeInBits(target_data, ty.0).try_into().unwrap() - } - } - - pub fn compile_fn(&self, name: &CStr) -> JitFunction { - unsafe { - let addr = LLVMGetFunctionAddress(self.0, name.as_ptr()); - assert!(addr != 0); - - mem::transmute::(addr) - } - } -} diff --git a/crates/dash_llvm_jit_backend/src/llvm_wrapper/function.rs b/crates/dash_llvm_jit_backend/src/llvm_wrapper/function.rs deleted file mode 100644 index 83acb4e9..00000000 --- a/crates/dash_llvm_jit_backend/src/llvm_wrapper/function.rs +++ /dev/null @@ -1,28 +0,0 @@ -use std::ffi::CStr; - -use llvm_sys::core::{LLVMGetParam, LLVMGetValueName2}; -use llvm_sys::prelude::LLVMValueRef; - -use super::value::Value; - -pub struct Function(pub(super) Value); - -impl Function { - pub fn as_ptr(&self) -> LLVMValueRef { - self.0.0 - } - - pub fn get_param(&self, param: u32) -> Value { - Value(unsafe { LLVMGetParam(self.as_ptr(), param) }) - } - - pub fn name(&self) -> &CStr { - unsafe { - // TODO: is this correct? what is length even used for? - let mut length = 0; - let name = LLVMGetValueName2(self.as_ptr(), &mut length); - let name = CStr::from_ptr(name); - name - } - } -} diff --git a/crates/dash_llvm_jit_backend/src/llvm_wrapper/mod.rs b/crates/dash_llvm_jit_backend/src/llvm_wrapper/mod.rs deleted file mode 100644 index f4e64973..00000000 --- a/crates/dash_llvm_jit_backend/src/llvm_wrapper/mod.rs +++ /dev/null @@ -1,21 +0,0 @@ -mod basic_block; -mod builder; -mod context; -mod execution_engine; -mod function; -mod module; -mod pass_manager; -mod raw; -mod ty; -mod value; - -pub use basic_block::BasicBlock; -pub use builder::Builder; -pub use context::Context; -pub use execution_engine::ExecutionEngine; -pub use function::Function; -pub use module::Module; -pub use pass_manager::PassManager; -pub use raw::*; -pub use ty::Ty; -pub use value::Value; diff --git a/crates/dash_llvm_jit_backend/src/llvm_wrapper/module.rs b/crates/dash_llvm_jit_backend/src/llvm_wrapper/module.rs deleted file mode 100644 index 9d2ad49a..00000000 --- a/crates/dash_llvm_jit_backend/src/llvm_wrapper/module.rs +++ /dev/null @@ -1,58 +0,0 @@ -use std::ffi::CStr; -use std::ptr; - -use llvm_sys::analysis::{LLVMVerifierFailureAction, LLVMVerifyModule}; -use llvm_sys::core::{ - LLVMAddFunction, LLVMDisposeMessage, LLVMPrintModuleToString, LLVMRunPassManager, LLVMSetInstructionCallConv, -}; -use llvm_sys::execution_engine::LLVMCreateExecutionEngineForModule; -use llvm_sys::prelude::LLVMModuleRef; -use llvm_sys::LLVMCallConv; - -use super::execution_engine::ExecutionEngine; -use super::{Function, PassManager, Ty, Value}; - -pub struct Module(pub(super) LLVMModuleRef); - -impl Module { - pub fn create_execution_engine(&self) -> ExecutionEngine { - let mut engine = ptr::null_mut(); - let mut err = ptr::null_mut(); - assert!(unsafe { LLVMCreateExecutionEngineForModule(&mut engine, self.0, &mut err) == 0 }); - assert!(err.is_null()); - ExecutionEngine(engine) - } - - /// Creates a function with a given name using the C calling convention - pub fn create_c_function_with_name(&self, name: &CStr, ty: &Ty) -> Function { - unsafe { - let function = LLVMAddFunction(self.0, name.as_ptr(), ty.0); - LLVMSetInstructionCallConv(function, LLVMCallConv::LLVMCCallConv as u32); - Function(Value(function)) - } - } - - pub fn create_c_function(&self, ty: &Ty) -> Function { - self.create_c_function_with_name(c"anon", ty) - } - - pub fn run_pass_manager(&self, pm: &PassManager) { - unsafe { LLVMRunPassManager(pm.0, self.0) }; - } - - pub fn print_module(&self) { - let string = unsafe { CStr::from_ptr(LLVMPrintModuleToString(self.0)) }; - let rust_string = String::from_utf8_lossy(string.to_bytes()); - println!("{rust_string}"); - - unsafe { LLVMDisposeMessage(string.as_ptr() as *mut i8) } - } - - pub fn verify(&self) { - let mut error = ptr::null_mut(); - unsafe { - LLVMVerifyModule(self.0, LLVMVerifierFailureAction::LLVMAbortProcessAction, &mut error); - LLVMDisposeMessage(error); - } - } -} diff --git a/crates/dash_llvm_jit_backend/src/llvm_wrapper/pass_manager.rs b/crates/dash_llvm_jit_backend/src/llvm_wrapper/pass_manager.rs deleted file mode 100644 index d0a49b4b..00000000 --- a/crates/dash_llvm_jit_backend/src/llvm_wrapper/pass_manager.rs +++ /dev/null @@ -1,24 +0,0 @@ -use llvm_sys::core::LLVMCreatePassManager; -use llvm_sys::prelude::LLVMPassManagerRef; -use llvm_sys::target_machine::LLVMCodeGenOptLevel; -use llvm_sys::transforms::pass_manager_builder::{ - LLVMPassManagerBuilderCreate, LLVMPassManagerBuilderDispose, LLVMPassManagerBuilderPopulateFunctionPassManager, - LLVMPassManagerBuilderPopulateModulePassManager, LLVMPassManagerBuilderSetOptLevel, -}; - -pub struct PassManager(pub(super) LLVMPassManagerRef); - -impl PassManager { - pub fn new(opt: LLVMCodeGenOptLevel) -> Self { - unsafe { - let pm = LLVMCreatePassManager(); - let pmb = LLVMPassManagerBuilderCreate(); - LLVMPassManagerBuilderSetOptLevel(pmb, opt as u32); - LLVMPassManagerBuilderPopulateFunctionPassManager(pmb, pm); - LLVMPassManagerBuilderPopulateModulePassManager(pmb, pm); - LLVMPassManagerBuilderDispose(pmb); - - Self(pm) - } - } -} diff --git a/crates/dash_llvm_jit_backend/src/llvm_wrapper/raw.rs b/crates/dash_llvm_jit_backend/src/llvm_wrapper/raw.rs deleted file mode 100644 index de859c3a..00000000 --- a/crates/dash_llvm_jit_backend/src/llvm_wrapper/raw.rs +++ /dev/null @@ -1,2 +0,0 @@ -use llvm_sys::core::LLVMContextCreate; -use llvm_sys::prelude::LLVMContextRef; diff --git a/crates/dash_llvm_jit_backend/src/llvm_wrapper/ty.rs b/crates/dash_llvm_jit_backend/src/llvm_wrapper/ty.rs deleted file mode 100644 index c8e7b06e..00000000 --- a/crates/dash_llvm_jit_backend/src/llvm_wrapper/ty.rs +++ /dev/null @@ -1,20 +0,0 @@ -use std::slice; - -use llvm_sys::core::LLVMGetTypeKind; -use llvm_sys::prelude::LLVMTypeRef; -use llvm_sys::LLVMTypeKind; - -use crate::util::transmute_slice_mut; - -#[repr(transparent)] -pub struct Ty(pub(super) LLVMTypeRef); - -impl Ty { - pub fn slice_of_tys_as_raw(slice: &mut [Ty]) -> &mut [LLVMTypeRef] { - unsafe { transmute_slice_mut(slice) } - } - - pub fn kind(&self) -> LLVMTypeKind { - unsafe { LLVMGetTypeKind(self.0) } - } -} diff --git a/crates/dash_llvm_jit_backend/src/llvm_wrapper/value.rs b/crates/dash_llvm_jit_backend/src/llvm_wrapper/value.rs deleted file mode 100644 index 29a27c78..00000000 --- a/crates/dash_llvm_jit_backend/src/llvm_wrapper/value.rs +++ /dev/null @@ -1,38 +0,0 @@ -use llvm_sys::core::{LLVMAddIncoming, LLVMGetTypeKind, LLVMTypeOf}; -use llvm_sys::prelude::{LLVMTypeRef, LLVMValueRef}; -use llvm_sys::LLVMTypeKind; - -use crate::util::transmute_slice_mut; - -use super::{BasicBlock, Ty}; - -#[derive(Clone)] -pub struct Value(pub(super) LLVMValueRef); - -impl Value { - pub fn slice_of_values_as_raw(slice: &mut [Value]) -> &mut [LLVMValueRef] { - unsafe { transmute_slice_mut(slice) } - } - - pub fn ty(&self) -> Ty { - Ty(unsafe { LLVMTypeOf(self.0) }) - } - - pub fn ty_kind(&self) -> LLVMTypeKind { - self.ty().kind() - } -} - -pub struct Phi(pub(super) Value); - -impl Phi { - pub fn add_incoming(&self, value: &Value, block: &BasicBlock) { - let mut values = [value.0]; - let mut blocks = [block.0]; - unsafe { LLVMAddIncoming(self.0.0, values.as_mut_ptr(), blocks.as_mut_ptr(), 1) }; - } - - pub fn as_value(&self) -> &Value { - &self.0 - } -} diff --git a/crates/dash_llvm_jit_backend/src/trace.rs b/crates/dash_llvm_jit_backend/src/trace.rs deleted file mode 100644 index 328c85ed..00000000 --- a/crates/dash_llvm_jit_backend/src/trace.rs +++ /dev/null @@ -1,61 +0,0 @@ -use std::collections::HashMap; - -use dash_middle::compiler::constant::Function; -use dash_middle::compiler::instruction as inst; -use dash_typed_cfg::passes::bb_generation::ConditionalBranchAction; -use indexmap::IndexMap; - -#[derive(Debug)] -pub struct Trace { - pub(crate) is_subtrace: bool, - pub(crate) origin: *const Function, - pub(crate) start: usize, - pub(crate) end: usize, - /// A vector of conditional jumps, i.e. diverging control flow. - /// The index is the # of the jump and the bool represents whether the jump is taken. - /// - /// Note for later: can change to HashSet where usize is the IP if a trace - /// is composed of multiple possible paths - // pub(crate) conditional_jumps: Vec, - pub(crate) conditional_jumps: HashMap, -} - -impl Trace { - pub fn new(origin: *const Function, start: usize, end: usize, is_subtrace: bool) -> Self { - Self { - origin, - start, - end, - conditional_jumps: HashMap::new(), - is_subtrace, - } - } - - pub fn get_conditional_jump(&self, id: usize) -> Option { - self.conditional_jumps.get(&id).copied() - } - - pub fn record_conditional_jump(&mut self, id: usize, action: ConditionalBranchAction) { - self.conditional_jumps.insert(id, action); - } - - pub fn start(&self) -> usize { - self.start - } - - pub fn end(&self) -> usize { - self.end - } - - pub fn origin(&self) -> *const Function { - self.origin - } - - pub fn set_subtrace(&mut self) { - self.is_subtrace = true; - } - - pub fn is_subtrace(&self) -> bool { - self.is_subtrace - } -} diff --git a/crates/dash_llvm_jit_backend/src/util.rs b/crates/dash_llvm_jit_backend/src/util.rs deleted file mode 100644 index 66a3847f..00000000 --- a/crates/dash_llvm_jit_backend/src/util.rs +++ /dev/null @@ -1,18 +0,0 @@ -use std::iter::Enumerate; -use std::slice; -use std::slice::Iter; - -use dash_middle::compiler::instruction::{Instruction, IntrinsicOperation}; - -#[macro_export] -macro_rules! cstrp { - ($string:expr) => { - cstr::cstr!($string).as_ptr() - }; -} - -/// # Safety -/// See [`slice::from_raw_parts_mut`] -pub unsafe fn transmute_slice_mut(slice: &mut [T]) -> &mut [U] { - slice::from_raw_parts_mut(slice.as_mut_ptr().cast::(), slice.len()) -} diff --git a/crates/dash_middle/src/compiler/constant.rs b/crates/dash_middle/src/compiler/constant.rs index dec36575..9240bc07 100755 --- a/crates/dash_middle/src/compiler/constant.rs +++ b/crates/dash_middle/src/compiler/constant.rs @@ -1,6 +1,5 @@ use core::fmt; -use std::cell::{Cell, RefCell}; -use std::collections::HashSet; +use std::cell::Cell; use std::rc::Rc; use dash_regex::{Flags, ParsedRegex}; @@ -10,8 +9,8 @@ use crate::indexvec::IndexThinVec; use crate::interner::Symbol; use crate::parser::statement::FunctionKind; -use super::external::External; use super::DebugSymbols; +use super::external::External; /// The instruction buffer. /// Uses interior mutability since we store it in a `Rc` @@ -77,24 +76,12 @@ pub struct Function { pub externals: Box<[External]>, /// If the parameter list uses the rest operator ..., then this will be Some(local_id) pub rest_local: Option, - // JIT-poisoned code regions (instruction pointers) - // TODO: refactor this a bit so this isn't "visible" to e.g. the bytecode compiler with builder pattern - pub poison_ips: RefCell>, pub source: Rc, pub debug_symbols: DebugSymbols, pub references_arguments: bool, pub has_extends_clause: bool, } -impl Function { - pub fn poison_ip(&self, ip: usize) { - self.poison_ips.borrow_mut().insert(ip); - } - - pub fn is_poisoned_ip(&self, ip: usize) -> bool { - self.poison_ips.borrow().contains(&ip) - } -} index_type!(NumberConstant u16); index_type!(BooleanConstant u16); index_type!(FunctionConstant u16); diff --git a/crates/dash_vm/Cargo.toml b/crates/dash_vm/Cargo.toml index d0c841c7..3287c57a 100644 --- a/crates/dash_vm/Cargo.toml +++ b/crates/dash_vm/Cargo.toml @@ -9,8 +9,8 @@ edition = "2021" unexpected_cfgs = { level = "warn", check-cfg = ['cfg(dash_lints)'] } [features] -jit = ["dash_llvm_jit_backend", "dash_typed_cfg"] -stress_gc = [] # allows stress testing the GC +jit = ["dash_typed_cfg"] +stress_gc = [] # allows stress testing the GC [dependencies] dash_middle = { path = "../dash_middle" } @@ -21,7 +21,6 @@ dash_compiler = { path = "../dash_compiler", features = ["from_string"] } dash_optimizer = { path = "../dash_optimizer" } dash_regex = { path = "../dash_regex" } dash_log = { path = "../dash_log" } -dash_llvm_jit_backend = { path = "../dash_llvm_jit_backend", optional = true } dash_typed_cfg = { path = "../dash_typed_cfg", optional = true } bitflags = "1.3.2" smallvec = { version = "1.9.0", features = ["const_generics"] } diff --git a/crates/dash_vm/src/dispatch.rs b/crates/dash_vm/src/dispatch.rs index 3663caec..74c96232 100755 --- a/crates/dash_vm/src/dispatch.rs +++ b/crates/dash_vm/src/dispatch.rs @@ -7,8 +7,8 @@ use crate::localscope::LocalScope; use crate::value::string::JsString; use crate::value::{ExternalValue, Root, Unrooted}; -use super::value::Value; use super::Vm; +use super::value::Value; use dash_middle::compiler::instruction::Instruction; #[derive(Debug)] @@ -551,7 +551,7 @@ mod handlers { use dash_middle::interner::sym; use dash_middle::iterator_with::{InfallibleIteratorWith, IteratorWith}; use dash_middle::parser::statement::{Asyncness, FunctionKind as ParserFunctionKind}; - use handlers::extract::{extract, ForwardSequence, FrontIteratorWith}; + use handlers::extract::{ForwardSequence, FrontIteratorWith, extract}; use hashbrown::hash_map::Entry; use if_chain::if_chain; use smallvec::SmallVec; @@ -567,7 +567,7 @@ mod handlers { use crate::value::function::closure::Closure; use crate::value::function::generator::GeneratorFunction; use crate::value::function::user::UserFunction; - use crate::value::function::{adjust_stack_from_flat_call, Function, FunctionKind}; + use crate::value::function::{Function, FunctionKind, adjust_stack_from_flat_call}; use crate::value::object::{NamedObject, Object, ObjectMap, PropertyKey, PropertyValue, PropertyValueKind}; use crate::value::ops::conversions::ValueConversion; use crate::value::ops::equality; @@ -1178,17 +1178,11 @@ mod handlers { } pub fn jmpfalsep(mut cx: DispatchContext<'_>) -> Result, Unrooted> { - #[cfg(feature = "jit")] - let ip = cx.active_frame().ip; - let offset = cx.fetchw_and_inc_ip() as i16; let value = cx.pop_stack_rooted(); let jump = !value.is_truthy(&mut cx.scope); - #[cfg(feature = "jit")] - cx.record_conditional_jump(ip, jump); - if jump { let frame = cx.active_frame_mut(); @@ -1203,16 +1197,11 @@ mod handlers { } pub fn jmpfalsenp(mut cx: DispatchContext<'_>) -> Result, Unrooted> { - #[cfg(feature = "jit")] - let ip = cx.active_frame().ip; let offset = cx.fetchw_and_inc_ip() as i16; let value = cx.peek_stack(); let jump = !value.is_truthy(&mut cx.scope); - #[cfg(feature = "jit")] - cx.record_conditional_jump(ip, jump); - if jump { let frame = cx.active_frame_mut(); @@ -1227,17 +1216,11 @@ mod handlers { } pub fn jmptruep(mut cx: DispatchContext<'_>) -> Result, Unrooted> { - #[cfg(feature = "jit")] - let ip = cx.active_frame().ip; - let offset = cx.fetchw_and_inc_ip() as i16; let value = cx.pop_stack_rooted(); let jump = value.is_truthy(&mut cx.scope); - #[cfg(feature = "jit")] - cx.record_conditional_jump(ip, jump); - if jump { let frame = cx.active_frame_mut(); @@ -1252,16 +1235,11 @@ mod handlers { } pub fn jmptruenp(mut cx: DispatchContext<'_>) -> Result, Unrooted> { - #[cfg(feature = "jit")] - let ip = cx.active_frame().ip; let offset = cx.fetchw_and_inc_ip() as i16; let value = cx.peek_stack(); let jump = value.is_truthy(&mut cx.scope); - #[cfg(feature = "jit")] - cx.record_conditional_jump(ip, jump); - if jump { let frame = cx.active_frame_mut(); @@ -1276,16 +1254,11 @@ mod handlers { } pub fn jmpnullishp(mut cx: DispatchContext<'_>) -> Result, Unrooted> { - #[cfg(feature = "jit")] - let ip = cx.active_frame().ip; let offset = cx.fetchw_and_inc_ip() as i16; let value = cx.pop_stack_rooted(); let jump = value.is_nullish(); - #[cfg(feature = "jit")] - cx.record_conditional_jump(ip, jump); - if jump { let frame = cx.active_frame_mut(); @@ -1300,16 +1273,11 @@ mod handlers { } pub fn jmpnullishnp(mut cx: DispatchContext<'_>) -> Result, Unrooted> { - #[cfg(feature = "jit")] - let ip = cx.active_frame().ip; let offset = cx.fetchw_and_inc_ip() as i16; let value = cx.peek_stack(); let jump = value.is_nullish(); - #[cfg(feature = "jit")] - cx.record_conditional_jump(ip, jump); - if jump { let frame = cx.active_frame_mut(); @@ -1324,16 +1292,11 @@ mod handlers { } pub fn jmpundefinedp(mut cx: DispatchContext<'_>) -> Result, Unrooted> { - #[cfg(feature = "jit")] - let ip = cx.active_frame().ip; let offset = cx.fetchw_and_inc_ip() as i16; let value = cx.pop_stack_rooted(); let jump = matches!(value.unpack(), ValueKind::Undefined(_)); - #[cfg(feature = "jit")] - cx.record_conditional_jump(ip, jump); - if jump { let frame = cx.active_frame_mut(); @@ -1348,16 +1311,11 @@ mod handlers { } pub fn jmpundefinednp(mut cx: DispatchContext<'_>) -> Result, Unrooted> { - #[cfg(feature = "jit")] - let ip = cx.active_frame().ip; let offset = cx.fetchw_and_inc_ip() as i16; let value = cx.peek_stack(); let jump = matches!(value.unpack(), ValueKind::Null(_)); - #[cfg(feature = "jit")] - cx.record_conditional_jump(ip, jump); - if jump { let frame = cx.active_frame_mut(); @@ -1378,15 +1336,7 @@ mod handlers { // Note: this is an unconditional jump, so we don't push this into the trace as a conditional jump if offset.is_negative() { - #[cfg(feature = "jit")] - let old_ip = frame.ip; - frame.ip -= -offset as usize; - - // Negative jumps are (currently) always also a marker for the end of a loop - // and we want to JIT compile loops that run often - #[cfg(feature = "jit")] - crate::jit::handle_loop_end(&mut cx, old_ip); } else { frame.ip += offset as usize; } diff --git a/crates/dash_vm/src/frame.rs b/crates/dash_vm/src/frame.rs index 57b7312d..642b8092 100755 --- a/crates/dash_vm/src/frame.rs +++ b/crates/dash_vm/src/frame.rs @@ -1,21 +1,21 @@ -use std::cell::{Cell, RefCell}; -use std::collections::{BTreeMap, HashSet}; +use std::cell::Cell; +use std::collections::BTreeMap; use std::rc::Rc; -use dash_middle::compiler::constant::{Buffer, Function}; use dash_middle::compiler::CompileResult; +use dash_middle::compiler::constant::{Buffer, Function}; use dash_middle::parser::statement::{Asyncness, FunctionKind}; use dash_proc_macro::Trace; -use crate::gc::trace::{Trace, TraceCtxt}; use crate::gc::ObjectId; +use crate::gc::trace::{Trace, TraceCtxt}; use crate::localscope::LocalScope; use crate::throw; use crate::value::string::JsString; use crate::value::{ExternalValue, Unrooted}; -use super::value::function::user::UserFunction; use super::value::Value; +use super::value::function::user::UserFunction; #[derive(Debug, Clone, Copy, Trace)] pub struct TryBlock { @@ -209,7 +209,6 @@ impl Frame { params: 0, ty: FunctionKind::Function(Asyncness::No), rest_local: None, - poison_ips: RefCell::new(HashSet::new()), source: cr.source, debug_symbols: cr.debug_symbols, references_arguments: false, diff --git a/crates/dash_vm/src/gc/trace.rs b/crates/dash_vm/src/gc/trace.rs index 4b9fca9e..d9c7f35b 100644 --- a/crates/dash_vm/src/gc/trace.rs +++ b/crates/dash_vm/src/gc/trace.rs @@ -173,7 +173,6 @@ unsafe impl Trace for dash_middle::compiler::constant::Function { }, externals: _, rest_local: _, - poison_ips: _, source: Rc { .. }, debug_symbols: _, references_arguments: _, diff --git a/crates/dash_vm/src/jit/frontend.rs b/crates/dash_vm/src/jit/frontend.rs deleted file mode 100644 index 74bbb610..00000000 --- a/crates/dash_vm/src/jit/frontend.rs +++ /dev/null @@ -1,89 +0,0 @@ -use std::collections::HashMap; - -use dash_llvm_jit_backend::codegen::JitFunction; -use dash_llvm_jit_backend::error::Error; -use dash_llvm_jit_backend::{codegen, init}; -use dash_middle::compiler::constant::Function; -use dash_typed_cfg::TypedCfg; - -use crate::Vm; - -use super::query::QueryProvider; -pub use dash_llvm_jit_backend::Trace; - -pub struct Frontend { - /// If we are currently recording a trace for a loop iteration, - /// this will contain metadata such as the pc of the loop header and its end - trace: Option, - cache: HashMap, -} - -#[derive(Debug, Clone, Hash, Eq, PartialEq)] -pub struct CacheKey { - pub origin: *const Function, - pub ip: usize, -} - -impl CacheKey { - pub fn from_trace(trace: &Trace) -> Self { - Self { - ip: trace.start(), - origin: trace.origin(), - } - } -} - -impl Frontend { - pub fn new() -> Self { - init(); - - Self { - trace: None, - cache: HashMap::new(), - } - } - - pub fn recording_trace(&self) -> Option<&Trace> { - self.trace.as_ref() - } - - pub fn recording_trace_mut(&mut self) -> Option<&mut Trace> { - self.trace.as_mut() - } - - pub fn take_recording_trace(&mut self) -> Option { - self.trace.take() - } - - pub fn set_recording_trace(&mut self, trace: Trace) { - self.trace = Some(trace); - } -} - -pub fn compile_current_trace(vm: &mut Vm) -> Result<(Trace, JitFunction), Error> { - let frame = vm.frames.last().unwrap(); - let trace = vm.jit.take_recording_trace().unwrap(); - let bytecode = frame - .function - .buffer - .with(|buf| buf[trace.start()..trace.end()].to_vec()); // We can do better than cloning, but good enough for now. - - let key = CacheKey::from_trace(&trace); - - // only check cache if we are allowed to. - // if not, recompile and recache. - let allow_cache = !trace.is_subtrace(); - if allow_cache { - if let Some((_, fun)) = vm.jit.cache.get(&key) { - return Ok((trace, *fun)); - } - } - - let mut query = QueryProvider { vm, trace: &trace }; - let tcfg = dash_typed_cfg::lower(&bytecode, &mut query)?; - let fun = codegen::compile_typed_cfg(&bytecode, &tcfg, &mut query)?; - - vm.jit.cache.insert(key, (tcfg, fun)); - - Ok((trace, fun)) -} diff --git a/crates/dash_vm/src/jit/mod.rs b/crates/dash_vm/src/jit/mod.rs deleted file mode 100644 index e037fc37..00000000 --- a/crates/dash_vm/src/jit/mod.rs +++ /dev/null @@ -1,157 +0,0 @@ -use std::rc::Rc; - -mod frontend; -mod query; -use dash_log::{debug, error, warn}; -use dash_typed_cfg::passes::bb_generation::ConditionalBranchAction; -pub use frontend::Frontend; -use frontend::Trace; - -use crate::Vm; - -fn handle_loop_trace(vm: &mut Vm, jmp_instr_ip: usize) { - let (mut trace, fun) = match frontend::compile_current_trace(vm) { - Ok(v) => v, - Err(err) => { - error!("JIT compilation failed! {err:?}"); - vm.poison_ip(jmp_instr_ip); - return; - } - }; - - let frame_sp = vm.get_frame_sp(); - - let offset_ip = trace.start(); - let mut target_ip = 0; - unsafe { - let stack_ptr = vm.stack.as_mut_ptr().cast(); - let frame_sp = u64::try_from(frame_sp).unwrap(); - fun(stack_ptr, frame_sp, &mut target_ip); - } - - target_ip += offset_ip as u64; - - let is_side_exit = target_ip != trace.end() as u64; - - if is_side_exit { - trace.record_conditional_jump(target_ip as usize - 2, ConditionalBranchAction::Either); - - trace.set_subtrace(); - vm.jit.set_recording_trace(trace); - } - - // `target_ip` is not the "real" IP, there may be some extra instructions before the loop header - vm.active_frame_mut().ip = target_ip as usize; -} - -pub fn handle_loop_end(vm: &mut Vm, loop_end_ip: usize) { - // We are jumping back to a loop header - - if vm.jit.recording_trace().is_some() { - handle_loop_trace(vm, loop_end_ip); - } else { - handle_loop_counter_inc(vm, loop_end_ip, None); - } -} - -fn handle_loop_counter_inc(vm: &mut Vm, loop_end_ip: usize, parent_ip: Option) { - let frame = vm.active_frame_mut(); - let origin = Rc::as_ptr(&frame.function); - let counter = frame.loop_counter.get_or_insert(frame.ip); - - counter.inc(); - if counter.is_hot() { - if frame.function.is_poisoned_ip(loop_end_ip) { - // We have already tried to compile this loop, and failed - // So don't bother re-tracing - warn!("loop is poisoned, cannot jit"); - return; - } - - // Hot loop detected - // Start recording a trace (i.e. every opcode) for the next loop iteration - // The trace will go on until either: - // - The loop is exited - // - The iteration has ended (i.e. we are here again) - debug!("detected hot loop, begin trace"); - debug!(loop_end_ip, parent_ip); - let trace = Trace::new(origin, frame.ip, loop_end_ip, false); - vm.jit.set_recording_trace(trace); - } -} - -#[cfg(all(test, feature = "jit"))] -mod tests { - - use dash_compiler::FunctionCompiler; - use dash_llvm_jit_backend::codegen; - use dash_llvm_jit_backend::codegen::CodegenQuery; - use dash_middle::compiler::constant::{BooleanConstant, NumberConstant}; - use dash_middle::interner::StringInterner; - use dash_optimizer::OptLevel; - use dash_typed_cfg::passes::bb_generation::{BBGenerationQuery, ConditionalBranchAction}; - use dash_typed_cfg::passes::type_infer::{Type, TypeInferQuery}; - use dash_typed_cfg::TypedCfgQuery; - - use crate::value::Value; - - #[derive(Debug)] - struct TestQueryProvider {} - impl BBGenerationQuery for TestQueryProvider { - fn conditional_branch_at(&self, ip: usize) -> Option { - match ip { - 0xB => Some(ConditionalBranchAction::NotTaken), - _ => todo!(), - } - } - } - - impl TypeInferQuery for TestQueryProvider { - fn number_constant(&self, _: NumberConstant) -> f64 { - 1.0 - } - - fn type_of_local(&self, _: u16) -> Type { - Type::I64 - } - } - - impl CodegenQuery for TestQueryProvider { - fn boolean_constant(&self, _: BooleanConstant) -> bool { - true - } - - fn number_constant(&self, _: NumberConstant) -> f64 { - 1.0 - } - } - - impl TypedCfgQuery for TestQueryProvider {} - - #[test] - pub fn llvm() { - let cr = FunctionCompiler::compile_str( - &mut StringInterner::new(), - r" - - for (let i = 0; i < 10; i++) { - let x = i > 3; - } - ", - OptLevel::None, - ) - .unwrap(); - let bytecode = &cr.instructions; - let mut query = TestQueryProvider {}; - let tcfg = dash_typed_cfg::lower(bytecode, &mut query).unwrap(); - dbg!(&tcfg); - - dash_llvm_jit_backend::init(); - - let fun = codegen::compile_typed_cfg(bytecode, &tcfg, &mut query).unwrap(); - let mut s = [Value::number(0.0), Value::boolean(false)]; - let mut x = 0; - unsafe { fun(s.as_mut_ptr().cast(), 0, &mut x) }; - dbg!(x, s); - } -} diff --git a/crates/dash_vm/src/jit/query.rs b/crates/dash_vm/src/jit/query.rs deleted file mode 100644 index 35cd6a34..00000000 --- a/crates/dash_vm/src/jit/query.rs +++ /dev/null @@ -1,54 +0,0 @@ -use dash_llvm_jit_backend::codegen::CodegenQuery; -use dash_llvm_jit_backend::Trace; -use dash_middle::compiler::constant::{BooleanConstant, NumberConstant}; -use dash_middle::util::is_integer; -use dash_typed_cfg::passes::bb_generation::{BBGenerationQuery, ConditionalBranchAction}; -use dash_typed_cfg::passes::type_infer::{Type, TypeInferQuery}; -use dash_typed_cfg::TypedCfgQuery; - -use crate::value::primitive::Number; -use crate::value::{Unpack, ValueKind}; -use crate::Vm; - -pub struct QueryProvider<'a> { - pub vm: &'a Vm, - pub trace: &'a Trace, -} - -impl<'a> TypedCfgQuery for QueryProvider<'a> {} - -impl<'a> BBGenerationQuery for QueryProvider<'a> { - fn conditional_branch_at(&self, ip: usize) -> Option { - self.trace.get_conditional_jump(self.trace.start() + ip + 1) - } -} - -impl<'a> TypeInferQuery for QueryProvider<'a> { - fn number_constant(&self, id: NumberConstant) -> f64 { - self.vm.active_frame().function.constants.numbers[id] - } - - fn type_of_local(&self, index: u16) -> Type { - match self.vm.get_local(index.into()).unwrap().unpack() { - ValueKind::Boolean(..) => Type::Boolean, - ValueKind::Number(Number(n)) => { - if is_integer(n) { - Type::I64 - } else { - Type::F64 - } - } - _ => panic!("invalid jit type"), - } - } -} - -impl<'a> CodegenQuery for QueryProvider<'a> { - fn boolean_constant(&self, id: BooleanConstant) -> bool { - self.vm.active_frame().function.constants.booleans[id] - } - - fn number_constant(&self, id: NumberConstant) -> f64 { - self.vm.active_frame().function.constants.numbers[id] - } -} diff --git a/crates/dash_vm/src/lib.rs b/crates/dash_vm/src/lib.rs index 9d229b8a..347a0e42 100644 --- a/crates/dash_vm/src/lib.rs +++ b/crates/dash_vm/src/lib.rs @@ -32,9 +32,6 @@ use rustc_hash::FxHashMap; use value::object::{extract_type, NamedObject}; use value::{ExternalValue, PureBuiltin, Unpack, Unrooted, ValueKind}; -#[cfg(feature = "jit")] -mod jit; - pub mod dispatch; pub mod eval; pub mod frame; @@ -88,8 +85,6 @@ pub struct Vm { /// or adding a property to a builtin, will cause this to be set to `false`, which in turn /// will disable many optimizations such as specialized intrinsics. builtins_pure: bool, - #[cfg(feature = "jit")] - jit: jit::Frontend, } impl Vm { @@ -117,9 +112,6 @@ impl Vm { params, gc_rss_threshold, builtins_pure: true, - - #[cfg(feature = "jit")] - jit: jit::Frontend::new(), }; vm.prepare(); vm @@ -1547,32 +1539,6 @@ impl Vm { pub(crate) fn impure_builtins(&mut self) { self.builtins_pure = false; } - - // -- JIT specific methods -- - - /// Marks an instruction pointer (i.e. code region) as JIT-"poisoned". - /// It will replace the instruction with one that does not attempt to trigger a trace. - #[cfg(feature = "jit")] - pub(crate) fn poison_ip(&mut self, ip: usize) { - dash_log::warn!("ip poisoned: {}", ip); - self.active_frame().function.poison_ip(ip); - } - - // TODO: move these to DispatchContext. - #[cfg(feature = "jit")] - pub(crate) fn record_conditional_jump(&mut self, ip: usize, did_jump: bool) { - use dash_typed_cfg::passes::bb_generation::ConditionalBranchAction; - - if let Some(trace) = self.jit.recording_trace_mut() { - trace.record_conditional_jump( - ip, - match did_jump { - true => ConditionalBranchAction::Taken, - false => ConditionalBranchAction::NotTaken, - }, - ); - } - } } pub enum PromiseAction {