From c3315f04e5619df0aaaa01106ff12bf114bfe3d8 Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Wed, 7 Feb 2024 23:21:29 -0500 Subject: [PATCH] Working basic guard that falls back to interp on fail --- slj/src/lib.rs | 90 ++++++++++++++++++++++++++++++++++++++----------- slj/src/main.rs | 2 +- 2 files changed, 71 insertions(+), 21 deletions(-) diff --git a/slj/src/lib.rs b/slj/src/lib.rs index f6b568c..2ee7994 100644 --- a/slj/src/lib.rs +++ b/slj/src/lib.rs @@ -29,7 +29,7 @@ extern "C" fn rust_cons(car: Form, cdr: Form) -> Form { Form::new_pair(car, cdr) } extern "C" fn rust_eq(a: Form, b: Form) -> Form { - Form::new_bool(a == b) + Form::new_bool(ManuallyDrop::new(a) == ManuallyDrop::new(b)) } extern "C" fn rust_cvec_form_grow(ptr: &mut Cvec
) { ptr.grow() @@ -139,23 +139,24 @@ impl JIT { let ok = bcx.ins().icmp_imm(IntCC::Equal, t, tag as i64); bcx.ins().trapz(ok, TrapCode::User(0)); } - fn stack_pop(bcx: &mut FunctionBuilder, int: Type, tmp_stack_ptr: Value, local_print_func: FuncRef) -> Value { + fn stack_pop(bcx: &mut FunctionBuilder, int: Type, tmp_stack_ptr: Value, local_print_func: FuncRef, peek_only: bool) -> Value { let len = bcx.ins().load(int, MemFlags::trusted(), tmp_stack_ptr, CVEC_LEN_OFFSET as i32); let new_len = bcx.ins().iadd_imm(len, -1); - bcx.ins().store(MemFlags::trusted(), new_len, tmp_stack_ptr, CVEC_LEN_OFFSET as i32); + if !peek_only { + bcx.ins().store(MemFlags::trusted(), new_len, tmp_stack_ptr, CVEC_LEN_OFFSET as i32); + } let ptr = bcx.ins().load(int, MemFlags::trusted(), tmp_stack_ptr, CVEC_PTR_OFFSET as i32); let offset = bcx.ins().ishl_imm(new_len, 3); let item_ptr = bcx.ins().iadd(ptr, offset); let r = bcx.ins().load(int, MemFlags::trusted(), item_ptr, 0); r - } fn stack_pop_prim(bcx: &mut FunctionBuilder, int: Type, tmp_stack_ptr: Value, local_print_func: FuncRef) -> Value { - let loaded = stack_pop(bcx, int, tmp_stack_ptr, local_print_func); + let loaded = stack_pop(bcx, int, tmp_stack_ptr, local_print_func, false); type_assert(bcx, loaded, TAG_PRIM, local_print_func, int); loaded } - fn gen_stack_push(bcx: &mut FunctionBuilder, int: Type, tmp_stack_ptr: Value, x: Value, local_cvec_form_grow_func: FuncRef, local_print_func: FuncRef) { + fn stack_push(bcx: &mut FunctionBuilder, int: Type, tmp_stack_ptr: Value, x: Value, local_cvec_form_grow_func: FuncRef, local_print_func: FuncRef) { let len = bcx.ins().load(int, MemFlags::trusted(), tmp_stack_ptr, CVEC_LEN_OFFSET as i32); let new_len = bcx.ins().iadd_imm(len, 1); let cap = bcx.ins().load(int, MemFlags::trusted(), tmp_stack_ptr, CVEC_CAP_OFFSET as i32); @@ -170,9 +171,9 @@ impl JIT { bcx.ins().call(local_cvec_form_grow_func, &[tmp_stack_ptr]); bcx.ins().jump(merge_block, &[]); bcx.switch_to_block(merge_block); - gen_stack_push_nocap(bcx, int, tmp_stack_ptr, x, local_print_func); + stack_push_nocap(bcx, int, tmp_stack_ptr, x, local_print_func); } - fn gen_stack_push_nocap(bcx: &mut FunctionBuilder, int: Type, tmp_stack_ptr: Value, x: Value, local_print_func: FuncRef) { + fn stack_push_nocap(bcx: &mut FunctionBuilder, int: Type, tmp_stack_ptr: Value, x: Value, local_print_func: FuncRef) { let len = bcx.ins().load(int, MemFlags::trusted(), tmp_stack_ptr, CVEC_LEN_OFFSET as i32); let new_len = bcx.ins().iadd_imm(len, 1); bcx.ins().store(MemFlags::trusted(), new_len, tmp_stack_ptr, CVEC_LEN_OFFSET as i32); @@ -182,6 +183,7 @@ impl JIT { bcx.ins().store(MemFlags::trusted(), x, item_ptr, 0); } + // DOESN'T RC fn gen_eq(bcx: &mut FunctionBuilder, int: Type, a: Value, b: Value, local_eq_func: FuncRef, local_print_func: FuncRef) -> Value { let at = bcx.ins().band_imm(a, TAG_RC as i64); let bt = bcx.ins().band_imm(b, TAG_RC as i64); @@ -402,10 +404,6 @@ impl JIT { self.try_resume_trace(resume_data); return Ok(Some((tmp_stack.pop().unwrap(), e, (*nc).clone()))); } - Op::Lookup { sym } => { - println!("Lookup(op) {sym}"); - tmp_stack.push(e.lookup(sym)?.clone()); - } */ Op::InlinePrim(p) => { /* @@ -416,8 +414,8 @@ impl JIT { let cst = bcx.ins().iconst(self.int, 1337 << 3); let _ = bcx.ins().call(local_print_func, &[cst]); */ - let b = stack_pop(&mut bcx, self.int, tmp_stack_ptr, local_print_func); - let a = if p.two_params() { Some(stack_pop(&mut bcx, self.int, tmp_stack_ptr, local_print_func)) } else { None }; + let b = stack_pop(&mut bcx, self.int, tmp_stack_ptr, local_print_func, false); + let a = if p.two_params() { Some(stack_pop(&mut bcx, self.int, tmp_stack_ptr, local_print_func, false)) } else { None }; let result = match p { Prim::Car => { gen_cr(&mut bcx, self.int, b, false, local_drop_rc_form_func, local_print_func) }, Prim::Cdr => { gen_cr(&mut bcx, self.int, b, true, local_drop_rc_form_func, local_print_func) }, @@ -434,16 +432,23 @@ impl JIT { _ => unreachable!(), } }, - Prim::Eq => { gen_eq(&mut bcx, self.int, a.unwrap(), b, local_eq_func, local_print_func) }, + Prim::Eq => { + // eq doesn't RC + let a = a.unwrap(); + let r = gen_eq(&mut bcx, self.int, a, b, local_eq_func, local_print_func); + decrement(&mut bcx, self.int, a, local_drop_rc_form_func, local_print_func); + decrement(&mut bcx, self.int, b, local_drop_rc_form_func, local_print_func); + r + }, Prim::Cons => { let call = bcx.ins().call(local_cons_func, &[a.unwrap(), b]); bcx.inst_results(call)[0].clone() }, }; let _ = stack_pop_prim(&mut bcx, self.int, tmp_stack_ptr, local_print_func); - gen_stack_push_nocap(&mut bcx, self.int, tmp_stack_ptr, result, local_print_func); // we just popped, so cap is fine + stack_push_nocap(&mut bcx, self.int, tmp_stack_ptr, result, local_print_func); // we just popped, so cap is fine offset += 1; } Op::Define { sym } => { let s = bcx.ins().iconst(self.int, unsafe { *((&mut Form::new_symbol(sym)) as *mut Form as *mut usize) } as i64); - let v = stack_pop(&mut bcx, self.int, tmp_stack_ptr, local_print_func); + let v = stack_pop(&mut bcx, self.int, tmp_stack_ptr, local_print_func, false); let e = bcx.ins().load(self.int, MemFlags::trusted(), e_ptr, 0); let kv = { @@ -465,7 +470,7 @@ impl JIT { //e = e.define(sym, v); } Op::Drop => { - let v = stack_pop(&mut bcx, self.int, tmp_stack_ptr, local_print_func); + let v = stack_pop(&mut bcx, self.int, tmp_stack_ptr, local_print_func, false); decrement(&mut bcx, self.int, v, local_drop_rc_form_func, local_print_func); offset += 1; //println!("Drop(op) {}", tmp_stack.last().unwrap()); @@ -480,7 +485,7 @@ impl JIT { if con_rc { increment_unchecked(&mut bcx, self.int, con, local_print_func); } - gen_stack_push(&mut bcx, self.int, tmp_stack_ptr, con, local_cvec_form_grow_func, local_print_func); + stack_push(&mut bcx, self.int, tmp_stack_ptr, con, local_cvec_form_grow_func, local_print_func); offset += 1; /* println!("Const(op) {con}"); @@ -524,9 +529,54 @@ impl JIT { let kv = bcx.block_params(return_block)[0].clone(); let v = gen_cr_unchecked_norc(&mut bcx, self.int, kv, true); increment(&mut bcx, self.int, v, local_print_func); - gen_stack_push(&mut bcx, self.int, tmp_stack_ptr, v, local_cvec_form_grow_func, local_print_func); + stack_push(&mut bcx, self.int, tmp_stack_ptr, v, local_cvec_form_grow_func, local_print_func); offset += 1; } + Op::Guard { const_value, side_val, side_cont, side_id, tbk } => { + let pass_block = bcx.create_block(); + let fail_block = bcx.create_block(); + + const_value.increment(); + let const_value = bcx.ins().iconst(self.int, unsafe { *(const_value as *const Form as *const usize) } as i64); + // NOTE THIS IS A PEEK NOT A POP + let v = stack_pop(&mut bcx, self.int, tmp_stack_ptr, local_print_func, true); + let eq_val = gen_eq(&mut bcx, self.int, v, const_value, local_eq_func, local_print_func); // doesn't RC + let eq = bcx.ins().icmp_imm(IntCC::Equal, eq_val, TAG_BOOL_TRUE as i64); + bcx.ins().brif(eq, pass_block, &[], fail_block, &[]); + bcx.switch_to_block(fail_block); + + // for now, failed guards drop back to interpreter + let cst = bcx.ins().iconst(self.int, (id.id.get() << TRACE_ID_OFFSET) | offset as i64); + bcx.ins().return_(&[cst]); + bcx.switch_to_block(pass_block); + offset += 1; + + /* + println!("Guard(op) {const_value}"); + if const_value != tmp_stack.last().unwrap() { + if self.traces.contains_key(side_id) { + if side_val.is_some() { + tmp_stack.pop().unwrap(); + } + println!("\tchaining trace to side trace"); + id = *side_id; + offset = 0; + break; // break out of this trace and let infinate loop spin + } else { + println!("\tending playback b/c failed guard"); + assert!(self.tracing.is_none()); + let mut ntrace = Trace::follow_on(*side_id,tbk.clone()); + if let Some(side_val) = side_val { + *tmp_stack.last_mut().unwrap() = side_val.clone(); + *ntrace.tbk.stack_const.last_mut().unwrap() = false; // this might be able to be + // more precise, actually + } + self.tracing = Some(ntrace); + return Ok(Some((tmp_stack.pop().unwrap(), e, (**side_cont).clone()))); + } + } + */ + } _ => { // quit out of trace! println!("compiling back to interp because we can't compile {op:?}"); diff --git a/slj/src/main.rs b/slj/src/main.rs index ce4e5ef..3a456d1 100644 --- a/slj/src/main.rs +++ b/slj/src/main.rs @@ -110,7 +110,7 @@ fn main() -> Result<()> { (debug 'gonna_faft_it) (debug faft) - (debug (faft 6)) + (debug (faft 8)) (debug 'gonna_faft_it2) (debug (faft 10)) ;(debug (faft 400))