From: Mark Thom Date: Sun, 8 Dec 2019 07:17:55 +0000 (-0700) Subject: revert arithmetic code X-Git-Tag: v0.8.118~34 X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=2be7070e1a91f1b315d544add68aee0a28e2747f;p=scryer-prolog.git revert arithmetic code --- diff --git a/src/prolog/arithmetic.rs b/src/prolog/arithmetic.rs index 1bd4d7c9..4c126d77 100644 --- a/src/prolog/arithmetic.rs +++ b/src/prolog/arithmetic.rs @@ -1,6 +1,5 @@ use prolog_parser::ast::*; -use crate::prolog::allocator::Allocator; use crate::prolog::clause_types::*; use crate::prolog::fixtures::*; use crate::prolog::forms::*; @@ -70,7 +69,7 @@ impl<'a> ArithInstructionIterator<'a> { pub enum ArithTermRef<'a> { Constant(&'a Constant), Op(ClauseName, usize), // name, arity. - Var(Level, &'a Cell, Rc), + Var(&'a Cell, Rc), } impl<'a> Iterator for ArithInstructionIterator<'a> { @@ -97,8 +96,8 @@ impl<'a> Iterator for ArithInstructionIterator<'a> { } } TermIterState::Constant(_, _, c) => return Some(Ok(ArithTermRef::Constant(c))), - TermIterState::Var(lvl, cell, var) => { - return Some(Ok(ArithTermRef::Var(lvl, cell, var.clone()))) + TermIterState::Var(_, cell, var) => { + return Some(Ok(ArithTermRef::Var(cell, var.clone()))) } _ => return Some(Err(ArithmeticError::NonEvaluableFunctor(atom!("'.'"), 2))), }; @@ -108,10 +107,10 @@ impl<'a> Iterator for ArithInstructionIterator<'a> { } } -pub struct ArithmeticEvaluator { +pub struct ArithmeticEvaluator<'a> { + bindings: &'a AllocVarDict, interm: Vec, interm_c: usize, - arg_c: usize } pub trait ArithmeticTermIter<'a> { @@ -128,12 +127,12 @@ impl<'a> ArithmeticTermIter<'a> for &'a Term { } } -impl ArithmeticEvaluator { - pub fn new(target_int: usize, arg_c: usize) -> Self { +impl<'a> ArithmeticEvaluator<'a> { + pub fn new(bindings: &'a AllocVarDict, target_int: usize) -> Self { ArithmeticEvaluator { + bindings, interm: Vec::new(), interm_c: target_int, - arg_c } } @@ -284,33 +283,27 @@ impl ArithmeticEvaluator { Ok(()) } - pub fn eval<'a, Iter, TermMarker>( - &mut self, - marker: &mut TermMarker, - src: Iter, - term_loc: GenContext, - ) -> Result + pub fn eval(&mut self, src: Iter) -> Result where Iter: ArithmeticTermIter<'a>, - TermMarker: Allocator<'a> { let mut code = vec![]; for term_ref in src.iter()? { match term_ref? { ArithTermRef::Constant(c) => self.push_constant(c)?, - ArithTermRef::Var(lvl, cell, name) => { - match marker.bindings().get(&name) { - Some(&VarData::Temp(_, t, _)) if t != 0 => {}, - Some(&VarData::Perm(p)) if p != 0 => {}, - _ => return Err(ArithmeticError::UninstantiatedVar), - } + ArithTermRef::Var(cell, name) => { + let r = if cell.get().norm().reg_num() == 0 { + match self.bindings.get(&name) { + Some(&VarData::Temp(_, t, _)) if t != 0 => RegType::Temp(t), + Some(&VarData::Perm(p)) if p != 0 => RegType::Perm(p), + _ => return Err(ArithmeticError::UninstantiatedVar), + } + } else { + cell.get().norm() + }; - let mut target = vec![]; - marker.mark_var(name.clone(), lvl, cell, term_loc, &mut target); - code.extend(target.into_iter().map(Line::Query)); - - self.interm.push(ArithmeticTerm::Reg(cell.get().norm())); + self.interm.push(ArithmeticTerm::Reg(r)); } ArithTermRef::Op(name, arity) => { code.push(Line::Arithmetic(self.instr_from_clause(name, arity)?)); @@ -318,22 +311,8 @@ impl ArithmeticEvaluator { } } - if let GenContext::Last(_) = term_loc { - self.tempify_perm_reg(); - } - Ok((code, self.interm.pop())) } - - fn tempify_perm_reg(&mut self) { - if let Some(interm) = self.interm.pop() { - if let ArithmeticTerm::Reg(RegType::Perm(_)) = interm { - self.interm.push(ArithmeticTerm::Reg(RegType::Temp(self.arg_c))); - } else { - self.interm.push(interm); - } - } - } } // integer division rounding function -- 9.1.3.1. diff --git a/src/prolog/codegen.rs b/src/prolog/codegen.rs index dacf055e..0b5d6f63 100644 --- a/src/prolog/codegen.rs +++ b/src/prolog/codegen.rs @@ -360,10 +360,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { self.mark_non_callable(name.clone(), 2, term_loc, vr, code); } - self.marker.reset_arg(2); - - let (mut lcode, at_1) = self.call_arith_eval(terms[0].as_ref(), 1, term_loc, 1)?; - let (mut rcode, at_2) = self.call_arith_eval(terms[1].as_ref(), 2, term_loc, 2)?; + let (mut lcode, at_1) = self.call_arith_eval(terms[0].as_ref(), 1)?; + let (mut rcode, at_2) = self.call_arith_eval(terms[1].as_ref(), 2)?; code.append(&mut lcode); code.append(&mut rcode); @@ -498,14 +496,12 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { } fn call_arith_eval( - &mut self, + &self, term: &'a Term, target_int: usize, - term_loc: GenContext, - arg_c: usize ) -> Result { - let mut evaluator = ArithmeticEvaluator::new(target_int, arg_c); - evaluator.eval(&mut self.marker, term, term_loc) + let mut evaluator = ArithmeticEvaluator::new(self.marker.bindings(), target_int); + evaluator.eval(term) } fn compile_is_call( @@ -515,17 +511,20 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { term_loc: GenContext, use_default_call_policy: bool, ) -> Result<(), ParserError> { - self.marker.reset_arg(2); + let (mut acode, at) = self.call_arith_eval(terms[1].as_ref(), 1)?; + code.append(&mut acode); Ok(match terms[0].as_ref() { &Term::Var(ref vr, ref name) => { let mut target = vec![]; - self.marker.mark_var(name.clone(), Level::Shallow, vr, term_loc, &mut target); - code.extend(target.into_iter().map(Line::Query)); + self.marker.reset_arg(2); + self.marker + .mark_var(name.clone(), Level::Shallow, vr, term_loc, &mut target); - let (acode, at) = self.call_arith_eval(terms[1].as_ref(), 1, term_loc, 2)?; - code.extend(acode.into_iter()); + if !target.is_empty() { + code.extend(target.into_iter().map(Line::Query)); + } if use_default_call_policy { code.push(is_call_by_default!(temp_v!(1), at.unwrap_or(interm!(1)))) @@ -534,9 +533,6 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { } } &Term::Constant(_, ref c @ Constant::Integer(_)) => { - let (acode, at) = self.call_arith_eval(terms[1].as_ref(), 1, term_loc, 2)?; - code.extend(acode.into_iter()); - code.push(Line::Query(put_constant!( Level::Shallow, c.clone(), @@ -550,9 +546,6 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { } } &Term::Constant(_, ref c @ Constant::Float(_)) => { - let (acode, at) = self.call_arith_eval(terms[1].as_ref(), 1, term_loc, 2)?; - code.extend(acode.into_iter()); - code.push(Line::Query(put_constant!( Level::Shallow, c.clone(), @@ -566,9 +559,6 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { } } &Term::Constant(_, ref c @ Constant::Rational(_)) => { - let (acode, at) = self.call_arith_eval(terms[1].as_ref(), 1, term_loc, 2)?; - code.extend(acode.into_iter()); - code.push(Line::Query(put_constant!( Level::Shallow, c.clone(), @@ -584,7 +574,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { _ => code.push(fail!()), }) } - + #[inline] fn compile_unblocked_cut(&mut self, code: &mut Code, cell: &'a Cell) { let r = self.marker.get(Rc::new(String::from("!"))); diff --git a/src/prolog/machine/machine_state.rs b/src/prolog/machine/machine_state.rs index 1e3086d5..6c6ec160 100644 --- a/src/prolog/machine/machine_state.rs +++ b/src/prolog/machine/machine_state.rs @@ -421,7 +421,7 @@ pub(crate) trait CallPolicy: Any { machine_st.e = machine_st.stack.index_or_frame(b).prelude.e; machine_st.cp = machine_st.stack.index_or_frame(b).prelude.cp; - machine_st.stack.index_or_frame_mut(b).prelude.bp = machine_st.p.clone() + offset; + machine_st.stack.index_or_frame_mut(b).prelude.bp = machine_st.p.local() + offset; let old_tr = machine_st.stack.index_or_frame(b).prelude.tr; let curr_tr = machine_st.tr; @@ -467,7 +467,7 @@ pub(crate) trait CallPolicy: Any { machine_st.e = machine_st.stack.index_or_frame(b).prelude.e; machine_st.cp = machine_st.stack.index_or_frame(b).prelude.cp; - machine_st.stack.index_or_frame_mut(b).prelude.bp = machine_st.p.clone() + 1; + machine_st.stack.index_or_frame_mut(b).prelude.bp = machine_st.p.local() + 1; let old_tr = machine_st.stack.index_or_frame(b).prelude.tr; let curr_tr = machine_st.tr; diff --git a/src/prolog/machine/machine_state_impl.rs b/src/prolog/machine/machine_state_impl.rs index a23a4357..0af5e578 100644 --- a/src/prolog/machine/machine_state_impl.rs +++ b/src/prolog/machine/machine_state_impl.rs @@ -2081,7 +2081,7 @@ impl MachineState { self.stack.truncate_to_frame(self.b); } } - + pub(crate) fn is_cyclic_term(&self, addr: Addr) -> bool { let mut seen = IndexSet::new(); let mut fail = false; @@ -3105,7 +3105,7 @@ impl MachineState { and_frame.prelude.e = self.e; and_frame.prelude.cp = self.cp; - + self.e = e; self.p += 1; } @@ -3113,7 +3113,7 @@ impl MachineState { pub(super) fn deallocate(&mut self) { let e = self.e; let frame = self.stack.index_and_frame(e); - + self.cp = frame.prelude.cp; self.e = frame.prelude.e; @@ -3240,7 +3240,7 @@ impl MachineState { or_frame.prelude.e = self.e; or_frame.prelude.cp = self.cp; or_frame.prelude.b = self.b; - or_frame.prelude.bp = self.p.clone() + 1; + or_frame.prelude.bp = self.p.local() + 1; or_frame.prelude.tr = self.tr; or_frame.prelude.pstr_tr = self.pstr_tr; or_frame.prelude.h = self.heap.h; @@ -3279,7 +3279,7 @@ impl MachineState { or_frame.prelude.e = self.e; or_frame.prelude.cp = self.cp; or_frame.prelude.b = self.b; - or_frame.prelude.bp = self.p.clone() + offset; + or_frame.prelude.bp = self.p.local() + offset; or_frame.prelude.tr = self.tr; or_frame.prelude.pstr_tr = self.pstr_tr; or_frame.prelude.h = self.heap.h; diff --git a/src/prolog/machine/mod.rs b/src/prolog/machine/mod.rs index 97d69a25..5e613c7c 100644 --- a/src/prolog/machine/mod.rs +++ b/src/prolog/machine/mod.rs @@ -739,7 +739,7 @@ impl MachineState { let b = self.b; self.b0 = self.stack.index_or_frame(b).prelude.b0; - self.p = self.stack.index_or_frame(b).prelude.bp.clone(); + self.p = CodePtr::Local(self.stack.index_or_frame(b).prelude.bp); if let CodePtr::Local(LocalCodePtr::TopLevel(_, p)) = self.p { self.fail = p == 0; diff --git a/src/prolog/machine/stack.rs b/src/prolog/machine/stack.rs new file mode 100644 index 00000000..12fce174 --- /dev/null +++ b/src/prolog/machine/stack.rs @@ -0,0 +1,387 @@ +use crate::prolog::machine::machine_indices::*; + +use core::marker::PhantomData; + +use std::alloc; +use std::mem; +use std::ops::{Index, IndexMut}; +use std::ptr; + +const STACK_ALIGN: usize = mem::align_of::(); +const INIT_STACK_SIZE: usize = 10 * 1024 * 1024; + +const fn prelude_size() -> usize { + let size = mem::size_of::(); + let align = mem::align_of::(); + + (size & !(align - 1)) + align +} + +/* The Stack is dropped manually at the discretion of the WAM, despite + having no Drop implementation. That's because it needs to know whether + the top frame is an AND frame or an OR frame. The WAM can + tell it. */ +pub struct Stack { + size: usize, + base: *const u8, + top: *const u8, + _marker: PhantomData, +} + +impl Drop for Stack { + fn drop(&mut self) { + self.drop_in_place(); + self.deallocate(); + } +} + +#[derive(Clone, Copy)] +pub struct FramePrelude { + is_or_frame: u8, + pub num_cells: usize, +} + +pub struct AndFramePrelude { + pub univ_prelude: FramePrelude, + pub e: usize, + pub cp: LocalCodePtr, + pub interrupt_cp: LocalCodePtr, +} + +pub struct AndFrame { + pub prelude: AndFramePrelude, + _marker: PhantomData, +} + +impl AndFrame { + pub fn size_of(num_cells: usize) -> usize { + prelude_size::() + num_cells * mem::size_of::() + } +} + +impl Index for AndFrame { + type Output = Addr; + + fn index(&self, index: usize) -> &Self::Output { + let prelude_offset = prelude_size::(); + let index_offset = (index - 1) * mem::size_of::(); + + unsafe { + let ptr = mem::transmute::<&AndFrame, *const u8>(self); + let ptr = ptr as usize + prelude_offset + index_offset; + + &*(ptr as *const Addr) + } + } +} + +impl IndexMut for AndFrame { + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + let prelude_offset = prelude_size::(); + let index_offset = (index - 1) * mem::size_of::(); + + unsafe { + let ptr = mem::transmute::<&mut AndFrame, *const u8>(self); + let ptr = ptr as usize + prelude_offset + index_offset; + + &mut *(ptr as *mut Addr) + } + } +} + +impl Drop for AndFrame { + fn drop(&mut self) { + let prelude_offset = prelude_size::(); + + unsafe { + let ptr = mem::transmute::<&mut AndFrame, *const u8>(self); + let ptr = ptr as usize + prelude_offset; + + for idx in 0 .. self.prelude.univ_prelude.num_cells { + let index_offset = idx * mem::size_of::(); + let ptr = (ptr + index_offset) as *mut Addr; + + ptr::drop_in_place(ptr); + } + } + } +} + +pub struct OrFramePrelude { + pub univ_prelude: FramePrelude, + pub e: usize, + pub cp: LocalCodePtr, + pub b: usize, + pub bp: LocalCodePtr, + pub tr: usize, + pub pstr_tr: usize, + pub h: usize, + pub b0: usize, + pub attr_var_init_queue_b: usize, + pub attr_var_init_bindings_b: usize, +} + +pub struct OrFrame { + pub prelude: OrFramePrelude, + _marker: PhantomData +} + +impl Index for OrFrame { + type Output = Addr; + + fn index(&self, index: usize) -> &Self::Output { + let prelude_offset = prelude_size::(); + let index_offset = index * mem::size_of::(); + + unsafe { + let ptr = mem::transmute::<&OrFrame, *const u8>(self); + let ptr = ptr as usize + prelude_offset + index_offset; + + &*(ptr as *const Addr) + } + } +} + +impl IndexMut for OrFrame { + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + let prelude_offset = prelude_size::(); + let index_offset = index * mem::size_of::(); + + unsafe { + let ptr = mem::transmute::<&mut OrFrame, *const u8>(self); + let ptr = ptr as usize + prelude_offset + index_offset; + + &mut *(ptr as *mut Addr) + } + } +} + +impl Drop for OrFrame { + fn drop(&mut self) { + let prelude_offset = prelude_size::(); + + unsafe { + let ptr = mem::transmute::<&mut OrFrame, *const u8>(self); + let ptr = ptr as usize + prelude_offset; + + for idx in 0 .. self.prelude.univ_prelude.num_cells { + let index_offset = idx * mem::size_of::(); + let ptr = (ptr + index_offset) as *mut Addr; + + ptr::drop_in_place(ptr); + } + } + } +} + +impl OrFrame { + pub fn size_of(num_cells: usize) -> usize { + prelude_size::() + num_cells * mem::size_of::() + } +} + +impl Stack { + pub fn new() -> Self { + let mut stack = Stack { size: 0, base: ptr::null(), top: ptr::null(), + _marker: PhantomData }; + + unsafe { stack.grow(); } + stack + } + + fn empty_stack() -> Self { + Stack { size: 0, base: ptr::null(), top: ptr::null(), + _marker: PhantomData } + } + + #[inline] + pub fn take(&mut self) -> Stack { + mem::replace(self, Stack::empty_stack()) + } + + #[inline] + fn free_space(&self) -> usize { + debug_assert!(self.top >= self.base, + "self.top = {:?} < {:?} = self.base", + self.top, self.base); + + self.size - (self.top as usize - self.base as usize) + } + + unsafe fn grow(&mut self) { + if self.size == 0 { + let layout = alloc::Layout::from_size_align_unchecked(INIT_STACK_SIZE, STACK_ALIGN); + + self.base = alloc::alloc(layout) as *const _; + self.top = self.base as *const _; + self.size = INIT_STACK_SIZE; + + self.top = self.top.offset(mem::align_of::() as isize); + } else { + let layout = alloc::Layout::from_size_align_unchecked(self.size, STACK_ALIGN); + let top_dist = self.top as usize - self.base as usize; + + self.base = alloc::realloc(self.base as *mut _, layout, self.size*2) as *const _; + self.top = (self.base as usize + top_dist) as *const _; + self.size *= 2; + } + } + + #[inline] + unsafe fn new_frame_ptr(&mut self, frame_size: usize) -> *const u8 { + loop { + if self.free_space() >= frame_size { + return (self.top as usize + frame_size) as *const _; + } else { + self.grow(); + } + } + } + + pub fn allocate_and_frame(&mut self, num_cells: usize) -> usize { + let frame_size = AndFrame::size_of(num_cells); + + unsafe { + let new_top = self.new_frame_ptr(frame_size); + + for idx in 0 .. num_cells { + let offset = prelude_size::() + idx * mem::size_of::(); + ptr::write((self.top as usize + offset) as *mut Addr, Addr::HeapCell(0)); + } + + let and_frame = &mut *(self.top as *mut AndFrame); + + and_frame.prelude.univ_prelude.is_or_frame = 0; + and_frame.prelude.univ_prelude.num_cells = num_cells; + + let e = self.top as usize - self.base as usize; + self.top = new_top; + e + } + } + + pub fn allocate_or_frame(&mut self, num_cells: usize) -> usize { + let frame_size = OrFrame::size_of(num_cells); + + unsafe { + let new_top = self.new_frame_ptr(frame_size); + + for idx in 0 .. num_cells { + let offset = prelude_size::() + idx * mem::size_of::(); + ptr::write((self.top as usize + offset) as *mut Addr, Addr::HeapCell(0)); + } + + let or_frame = &mut *(self.top as *mut OrFrame); + + or_frame.prelude.univ_prelude.is_or_frame = 1; + or_frame.prelude.univ_prelude.num_cells = num_cells; + + let b = self.top as usize - self.base as usize; + self.top = new_top; + b + } + } + + #[inline] + pub fn index_and_frame(&self, e: usize) -> &AndFrame { + unsafe { + let ptr = self.base as usize + e; + &*(ptr as *const AndFrame) + } + } + + #[inline] + pub fn index_and_frame_mut(&mut self, e: usize) -> &mut AndFrame { + unsafe { + let ptr = self.base as usize + e; + &mut *(ptr as *mut AndFrame) + } + } + + #[inline] + pub fn index_or_frame(&self, b: usize) -> &OrFrame { + unsafe { + let ptr = self.base as usize + b; + &*(ptr as *const OrFrame) + } + } + + #[inline] + pub fn index_or_frame_mut(&mut self, b: usize) -> &mut OrFrame { + unsafe { + let ptr = self.base as usize + b; + &mut *(ptr as *mut OrFrame) + } + } + + pub fn deallocate(&mut self) { + unsafe { + let layout = alloc::Layout::from_size_align_unchecked(self.size, STACK_ALIGN); + alloc::dealloc(self.base as *mut u8, layout); + + self.top = ptr::null(); + self.base = ptr::null(); + self.size = 0; + } + } + + pub fn truncate_to_frame(&mut self, b: usize) { + if b == 0 { + self.truncate(mem::align_of::()); + } else { + let univ_prelude = self.index_or_frame(b).prelude.univ_prelude; + let size = OrFrame::size_of(univ_prelude.num_cells); + + self.truncate(b + size); + } + } + + fn truncate(&mut self, b: usize) { + let mut b = b + self.base as usize; + let base = b; + + unsafe { + while b as *const _ < self.top { + let univ_prelude = ptr::read(b as *const FramePrelude); + + let offset = if univ_prelude.is_or_frame == 0 { + let frame_ptr = b as *mut AndFrame; + let frame = &mut *frame_ptr; + let size_of_frame = AndFrame::size_of(frame.prelude.univ_prelude.num_cells); + + ptr::drop_in_place(frame_ptr); + ptr::write(frame_ptr, mem::zeroed::()); + + b + size_of_frame + } else { + debug_assert!(univ_prelude.is_or_frame == 1); + + let frame_ptr = b as *mut OrFrame; + let frame = &mut *frame_ptr; + let size_of_frame = OrFrame::size_of(frame.prelude.univ_prelude.num_cells); + + ptr::drop_in_place(frame_ptr); + ptr::write(frame_ptr, mem::zeroed::()); + + b + size_of_frame + }; + + b = offset; + } + + if base < self.top as usize { + self.top = base as *const _; + } + } + } + + pub fn drop_in_place(&mut self) { + self.truncate(mem::align_of::()); + + debug_assert!(if self.top.is_null() { + self.top == self.base + } else { + self.top as usize == self.base as usize + mem::align_of::() + }); + } +}