From 4fd37335f576240c25dfbfe6e70441aff166c60e Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 11 Jul 2023 17:59:53 -0600 Subject: [PATCH] use lookahead to skip inapplicable clauses (#1028, #1502) --- build/instructions_template.rs | 9 +- src/codegen.rs | 4 +- src/machine/dispatch.rs | 242 ++++++++++--------- src/machine/machine_state.rs | 59 ----- src/machine/mod.rs | 423 +++++++++++++++++++++++++++++---- src/machine/system_calls.rs | 2 +- src/targets.rs | 8 +- 7 files changed, 529 insertions(+), 218 deletions(-) diff --git a/build/instructions_template.rs b/build/instructions_template.rs index 2629f7b3..3b2bd971 100644 --- a/build/instructions_template.rs +++ b/build/instructions_template.rs @@ -598,7 +598,7 @@ enum InstructionTemplate { #[strum_discriminants(strum(props(Arity = "4", Name = "get_partial_string")))] GetPartialString(Level, Atom, RegType, bool), #[strum_discriminants(strum(props(Arity = "3", Name = "get_structure")))] - GetStructure(Atom, usize, RegType), + GetStructure(Level, Atom, usize, RegType), #[strum_discriminants(strum(props(Arity = "2", Name = "get_variable")))] GetVariable(RegType, usize), #[strum_discriminants(strum(props(Arity = "2", Name = "get_value")))] @@ -2105,13 +2105,14 @@ fn generate_instruction_preface() -> TokenStream { [lvl_stub, rt_stub] ) } - &Instruction::GetStructure(name, arity, r) => { + &Instruction::GetStructure(lvl, name, arity, r) => { + let lvl_stub = lvl.into_functor(); let rt_stub = reg_type_into_functor(r); functor!( atom!("get_structure"), - [atom(name), fixnum(arity), str(h, 0)], - [rt_stub] + [str(h, 0), atom(name), fixnum(arity), str(h, 1)], + [lvl_stub, rt_stub] ) } &Instruction::GetValue(r, arg) => { diff --git a/src/codegen.rs b/src/codegen.rs index 68374c58..7d4b92d3 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -309,7 +309,7 @@ impl DebrayAllocator { fn trim_structure_by_last_arg(instr: &mut Instruction, last_arg: &Term) { match instr { Instruction::PutStructure(_, ref mut arity, _) | - Instruction::GetStructure(_, ref mut arity, _) => { + Instruction::GetStructure(.., ref mut arity, _) => { if let Term::Literal(_, Literal::CodeIndex(_)) = last_arg { // it is acceptable if arity == 0 is the result of // this decrement. call/N will have to read the index @@ -447,7 +447,7 @@ impl<'b> CodeGenerator<'b> { } TermRef::Clause(lvl, cell, name, terms) => { self.marker.mark_non_var::(lvl, term_loc, cell, &mut target); - target.push_back(Target::to_structure(name, terms.len(), cell.get())); + target.push_back(Target::to_structure(lvl, name, terms.len(), cell.get())); as AddToFreeList<'a, Target>>::add_term_to_free_list(self, cell.get()); diff --git a/src/machine/dispatch.rs b/src/machine/dispatch.rs index e1ba0c0f..3b30e75b 100644 --- a/src/machine/dispatch.rs +++ b/src/machine/dispatch.rs @@ -9,6 +9,8 @@ use crate::types::*; use crate::try_numeric_result; +use fxhash::FxBuildHasher; + macro_rules! step_or_fail { ($self:expr, $step_e:expr) => { if $self.machine_st.fail { @@ -182,6 +184,128 @@ impl MachineState { Ok(()) } + + #[inline(always)] + pub(crate) fn select_switch_on_term_index( + &self, + addr: HeapCellValue, + v: IndexingCodePtr, + c: IndexingCodePtr, + l: IndexingCodePtr, + s: IndexingCodePtr, + ) -> IndexingCodePtr { + read_heap_cell!(addr, + (HeapCellValueTag::Var | + HeapCellValueTag::StackVar | + HeapCellValueTag::AttrVar) => { + v + } + (HeapCellValueTag::PStrLoc | + HeapCellValueTag::Lis | + HeapCellValueTag::CStr) => { + l + } + (HeapCellValueTag::Fixnum | + HeapCellValueTag::Char | + HeapCellValueTag::F64) => { + c + } + (HeapCellValueTag::Atom, (_name, arity)) => { + // if arity == 0 { c } else { s } + debug_assert!(arity == 0); + c + } + (HeapCellValueTag::Str, st) => { + let (name, arity) = cell_as_atom_cell!(self.heap[st]) + .get_name_and_arity(); + + match (name, arity) { + (atom!("."), 2) => l, + (_, 0) => c, + _ => s, + } + } + (HeapCellValueTag::Cons, ptr) => { + match ptr.get_tag() { + ArenaHeaderTag::Rational | ArenaHeaderTag::Integer => { + c + } + _ => { + IndexingCodePtr::Fail + } + } + } + _ => { + unreachable!(); + } + ) + } + + #[inline(always)] + pub(crate) fn constant_to_literal(&self, addr: HeapCellValue) -> Literal { + read_heap_cell!(addr, + (HeapCellValueTag::Char, c) => { + Literal::Char(c) + } + (HeapCellValueTag::Fixnum, n) => { + Literal::Fixnum(n) + } + (HeapCellValueTag::F64, f) => { + Literal::Float(f.as_offset()) + } + (HeapCellValueTag::Atom, (atom, arity)) => { + debug_assert_eq!(arity, 0); + Literal::Atom(atom) + } + (HeapCellValueTag::Str, s) => { + Literal::Atom(cell_as_atom_cell!(self.heap[s]).get_name()) + } + (HeapCellValueTag::Cons, cons_ptr) => { + match_untyped_arena_ptr!(cons_ptr, + (ArenaHeaderTag::Rational, r) => { + Literal::Rational(r) + } + (ArenaHeaderTag::Integer, n) => { + Literal::Integer(n) + } + _ => { + unreachable!() + } + ) + } + _ => { + unreachable!() + } + ) + } + + #[inline(always)] + pub(crate) fn select_switch_on_structure_index( + &self, + addr: HeapCellValue, + hm: &IndexMap<(Atom, usize), IndexingCodePtr, FxBuildHasher>, + ) -> IndexingCodePtr { + read_heap_cell!(addr, + (HeapCellValueTag::Atom, (name, arity)) => { + match hm.get(&(name, arity)) { + Some(offset) => *offset, + None => IndexingCodePtr::Fail, + } + } + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(self.heap[s]) + .get_name_and_arity(); + + match hm.get(&(name, arity)) { + Some(offset) => *offset, + None => IndexingCodePtr::Fail, + } + } + _ => { + IndexingCodePtr::Fail + } + ) + } } impl Machine { @@ -349,51 +473,7 @@ impl Machine { loop { match &indexing_lines[index] { &IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, c, l, s)) => { - let offset = read_heap_cell!(addr, - (HeapCellValueTag::Var | - HeapCellValueTag::StackVar | - HeapCellValueTag::AttrVar) => { - v - } - (HeapCellValueTag::PStrLoc | - HeapCellValueTag::Lis | - HeapCellValueTag::CStr) => { - l - } - (HeapCellValueTag::Fixnum | - HeapCellValueTag::Char | - HeapCellValueTag::F64) => { - c - } - (HeapCellValueTag::Atom, (_name, arity)) => { - // if arity == 0 { c } else { s } - debug_assert!(arity == 0); - c - } - (HeapCellValueTag::Str, st) => { - let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[st]) - .get_name_and_arity(); - - match (name, arity) { - (atom!("."), 2) => l, - (_, 0) => c, - _ => s, - } - } - (HeapCellValueTag::Cons, ptr) => { - match ptr.get_tag() { - ArenaHeaderTag::Rational | ArenaHeaderTag::Integer => { - c - } - _ => { - IndexingCodePtr::Fail - } - } - } - _ => { - unreachable!(); - } - ); + let offset = self.machine_st.select_switch_on_term_index(addr, v, c, l, s); match offset { IndexingCodePtr::Fail => { @@ -423,41 +503,8 @@ impl Machine { } } } - &IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(ref hm)) => { - let lit = read_heap_cell!(addr, - (HeapCellValueTag::Char, c) => { - Literal::Char(c) - } - (HeapCellValueTag::Fixnum, n) => { - Literal::Fixnum(n) - } - (HeapCellValueTag::F64, f) => { - Literal::Float(f.as_offset()) - } - (HeapCellValueTag::Atom, (atom, arity)) => { - debug_assert_eq!(arity, 0); - Literal::Atom(atom) - } - (HeapCellValueTag::Str, s) => { - Literal::Atom(cell_as_atom_cell!(self.machine_st.heap[s]).get_name()) - } - (HeapCellValueTag::Cons, cons_ptr) => { - match_untyped_arena_ptr!(cons_ptr, - (ArenaHeaderTag::Rational, r) => { - Literal::Rational(r) - } - (ArenaHeaderTag::Integer, n) => { - Literal::Integer(n) - } - _ => { - unreachable!() - } - ) - } - _ => { - unreachable!() - } - ); + IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(hm)) => { + let lit = self.machine_st.constant_to_literal(addr); let offset = match hm.get(&lit) { Some(offset) => *offset, @@ -492,27 +539,8 @@ impl Machine { } } } - &IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(ref hm)) => { - let offset = read_heap_cell!(addr, - (HeapCellValueTag::Atom, (name, arity)) => { - match hm.get(&(name, arity)) { - Some(offset) => *offset, - None => IndexingCodePtr::Fail, - } - } - (HeapCellValueTag::Str, s) => { - let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s]) - .get_name_and_arity(); - - match hm.get(&(name, arity)) { - Some(offset) => *offset, - None => IndexingCodePtr::Fail, - } - } - _ => { - IndexingCodePtr::Fail - } - ); + IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(hm)) => { + let offset = self.machine_st.select_switch_on_structure_index(addr, hm); match offset { IndexingCodePtr::Fail => { @@ -997,7 +1025,7 @@ impl Machine { fixnum_as_cell!(Fixnum::build_with(self.machine_st.cc as i64)); self.machine_st.num_of_args += 1; - self.machine_st.try_me_else(next_i); + self.try_me_else(next_i); self.machine_st.num_of_args -= 1; } None => { @@ -1067,7 +1095,7 @@ impl Machine { fixnum_as_cell!(Fixnum::build_with(self.machine_st.cc as i64)); self.machine_st.num_of_args += 1; - self.machine_st.try_me_else(next_i); + self.try_me_else(next_i); self.machine_st.num_of_args -= 1; } None => { @@ -1118,7 +1146,7 @@ impl Machine { } } &Instruction::TryMeElse(offset) => { - self.machine_st.try_me_else(offset); + self.try_me_else(offset); } &Instruction::DefaultRetryMeElse(offset) => { self.retry_me_else(offset); @@ -2879,7 +2907,7 @@ impl Machine { step_or_fail!(self, self.machine_st.p += 1); } - &Instruction::GetStructure(name, arity, reg) => { + &Instruction::GetStructure(_lvl, name, arity, reg) => { let deref_v = self.machine_st.deref(self.machine_st[reg]); let store_v = self.machine_st.store(deref_v); @@ -3076,7 +3104,7 @@ impl Machine { IndexingLine::IndexedChoice(ref indexed_choice) => { match &indexed_choice[self.machine_st.iip as usize] { &IndexedChoiceInstruction::Try(offset) => { - self.machine_st.indexed_try(offset); + self.indexed_try(offset); } &IndexedChoiceInstruction::Retry(l) => { self.retry(l); @@ -3122,7 +3150,7 @@ impl Machine { fixnum_as_cell!(Fixnum::build_with(self.machine_st.cc as i64)); self.machine_st.num_of_args += 1; - self.machine_st.indexed_try(offset); + self.indexed_try(offset); self.machine_st.num_of_args -= 1; } None => { diff --git a/src/machine/machine_state.rs b/src/machine/machine_state.rs index 7b074a64..5a8fc85d 100644 --- a/src/machine/machine_state.rs +++ b/src/machine/machine_state.rs @@ -858,65 +858,6 @@ impl MachineState { } ); } - - #[inline(always)] - pub(super) fn try_me_else(&mut self, offset: usize) { - let n = self.num_of_args; - let b = self.stack.allocate_or_frame(n); - let or_frame = self.stack.index_or_frame_mut(b); - - or_frame.prelude.num_cells = n; - or_frame.prelude.e = self.e; - or_frame.prelude.cp = self.cp; - or_frame.prelude.b = self.b; - or_frame.prelude.bp = self.p + offset; - or_frame.prelude.boip = 0; - or_frame.prelude.biip = 0; - or_frame.prelude.tr = self.tr; - or_frame.prelude.h = self.heap.len(); - or_frame.prelude.b0 = self.b0; - or_frame.prelude.attr_var_queue_len = self.attr_var_init.attr_var_queue.len(); - - self.b = b; - - for i in 0..n { - or_frame[i] = self.registers[i+1]; - } - - self.hb = self.heap.len(); - self.p += 1; - } - - #[inline(always)] - pub(super) fn indexed_try(&mut self, offset: usize) { - let n = self.num_of_args; - let b = self.stack.allocate_or_frame(n); - let or_frame = self.stack.index_or_frame_mut(b); - - or_frame.prelude.num_cells = n; - or_frame.prelude.e = self.e; - or_frame.prelude.cp = self.cp; - or_frame.prelude.b = self.b; - or_frame.prelude.bp = self.p; // + 1; in self.iip now! - or_frame.prelude.boip = self.oip; - or_frame.prelude.biip = self.iip + 1; - or_frame.prelude.tr = self.tr; - or_frame.prelude.h = self.heap.len(); - or_frame.prelude.b0 = self.b0; - or_frame.prelude.attr_var_queue_len = self.attr_var_init.attr_var_queue.len(); - - self.b = b; - - for i in 0..n { - or_frame[i] = self.registers[i+1]; - } - - self.hb = self.heap.len(); - self.p = self.p + offset; - - self.oip = 0; - self.iip = 0; - } } #[derive(Debug)] diff --git a/src/machine/mod.rs b/src/machine/mod.rs index 78c347f2..41cc4f39 100644 --- a/src/machine/mod.rs +++ b/src/machine/mod.rs @@ -547,38 +547,351 @@ impl Machine { self.machine_st.verify_attr_interrupt(p, arity); } + fn next_clause_applicable(&mut self, mut offset: usize) -> bool { + loop { + match &self.code[offset] { + Instruction::IndexingCode(indexing_lines) => { + let mut oip = 0; + let mut cell = empty_list_as_cell!(); + + loop { + let indexing_code_ptr = match &indexing_lines[oip] { + &IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(arg, v, c, l, s)) => { + cell = self.deref_register(arg); + self.machine_st.select_switch_on_term_index(cell, v, c, l, s) + } + IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(hm)) => { + let lit = self.machine_st.constant_to_literal(cell); + hm.get(&lit).cloned().unwrap_or(IndexingCodePtr::Fail) + } + IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(hm)) => { + self.machine_st.select_switch_on_structure_index(cell, hm) + } + _ => { + offset += 1; + break; + } + }; + + match indexing_code_ptr { + IndexingCodePtr::External(_) | IndexingCodePtr::DynamicExternal(_) => { + offset += 1; + break; + } + IndexingCodePtr::Internal(i) => oip += i, + IndexingCodePtr::Fail => return false, + } + } + } + &Instruction::GetConstant(Level::Shallow, lit, RegType::Temp(t)) => { + let cell = self.deref_register(t); + + if cell.is_var() { + offset += 1; + } else if lit.get_tag() == HeapCellValueTag::CStr { + read_heap_cell!(cell, + (HeapCellValueTag::CStr) => { + if cell == lit { + offset += 1; + } else { + return false; + } + } + (HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc) => { + offset += 1; + } + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s]) + .get_name_and_arity(); + + if name == atom!(".") && arity == 2 { + offset += 1; + } else { + return false; + } + } + _ => { + return false; + } + ); + } else { + self.machine_st.write_literal_to_var(cell, lit); + + if self.machine_st.fail { + self.machine_st.fail = false; + return false; + } else { + offset += 1; + } + } + } + &Instruction::GetList(Level::Shallow, RegType::Temp(t)) => { + let cell = self.deref_register(t); + + read_heap_cell!(cell, + (HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr) => { + offset += 1; + } + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s]).get_name_and_arity(); + + if name == atom!(".") && arity == 2 { + offset += 1; + } else { + return false; + } + } + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => { + offset += 1; + } + _ => { + return false; + } + ); + } + &Instruction::GetStructure(Level::Shallow, name, arity, RegType::Temp(t)) => { + let cell = self.deref_register(t); + + read_heap_cell!(cell, + (HeapCellValueTag::Str, s) => { + if (name, arity) == cell_as_atom_cell!(self.machine_st.heap[s]).get_name_and_arity() { + offset += 1; + } else { + return false; + } + } + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => { + offset += 1; + } + _ => { + return false; + } + ); + } + &Instruction::GetPartialString(Level::Shallow, string, RegType::Temp(t), has_tail) => { + let cell = self.deref_register(t); + + read_heap_cell!(cell, + (HeapCellValueTag::CStr, cstr) => { + if !has_tail && string != cstr { + return false; + } + + offset += 1; + } + (HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc) => { + offset += 1; + } + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s]).get_name_and_arity(); + + if name == atom!(".") && arity == 2 { + offset += 1; + } else { + return false; + } + } + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => { + offset += 1; + } + _ => { + return false; + } + ); + } + Instruction::GetConstant(..) | + Instruction::GetList(..) | + Instruction::GetStructure(..) | + Instruction::GetPartialString(..) | + &Instruction::UnifyVoid(..) | + &Instruction::UnifyConstant(..) | + &Instruction::GetVariable(..) | + &Instruction::GetValue(..) | + &Instruction::UnifyVariable(..) | + &Instruction::UnifyValue(..) | + &Instruction::UnifyLocalValue(..) => { + offset += 1; + } + _ => { + break; + } + } + } + + true + } + + fn next_applicable_clause(&mut self, mut offset: usize) -> Option { + while !self.next_clause_applicable(self.machine_st.p + offset + 1) { + match &self.code[self.machine_st.p + offset] { + &Instruction::DefaultRetryMeElse(o) | &Instruction::RetryMeElse(o) | + &Instruction::DynamicElse(.., NextOrFail::Next(o)) | + &Instruction::DynamicInternalElse(.., NextOrFail::Next(o)) => offset += o, + _ => { + return None; + } + } + } + + Some(offset) + } + + fn next_inner_applicable_clause(&mut self) -> Option { + let mut inner_offset = 1u32; + + loop { + match &self.code[self.machine_st.p] { + Instruction::IndexingCode(indexing_lines) => { + match &indexing_lines[self.machine_st.oip as usize] { + IndexingLine::IndexedChoice(indexed_choice) => { + match &indexed_choice[(self.machine_st.iip + inner_offset) as usize] { + &IndexedChoiceInstruction::Retry(o) => { + if self.next_clause_applicable(self.machine_st.p + o) { + return Some(inner_offset); + } + + inner_offset += 1; + } + &IndexedChoiceInstruction::Trust(o) => { + return if self.next_clause_applicable(self.machine_st.p + o) { + Some(inner_offset) + } else { + None + }; + } + _ => unreachable!(), + } + } + IndexingLine::DynamicIndexedChoice(indexed_choice) => { + let idx = (self.machine_st.iip + inner_offset) as usize; + let o = indexed_choice[idx]; + + if idx + 1 == indexed_choice.len() { + return if self.next_clause_applicable(self.machine_st.p + o) { + Some(inner_offset) + } else { + None + }; + } else { + if self.next_clause_applicable(self.machine_st.p + o) { + return Some(inner_offset); + } + + inner_offset += 1; + } + } + _ => unreachable!(), + } + } + _ => unreachable!(), + } + } + } + + #[inline(always)] + pub(super) fn try_me_else(&mut self, offset: usize) { + if let Some(offset) = self.next_applicable_clause(offset) { + let n = self.machine_st.num_of_args; + let b = self.machine_st.stack.allocate_or_frame(n); + let or_frame = self.machine_st.stack.index_or_frame_mut(b); + + or_frame.prelude.num_cells = n; + or_frame.prelude.e = self.machine_st.e; + or_frame.prelude.cp = self.machine_st.cp; + or_frame.prelude.b = self.machine_st.b; + or_frame.prelude.bp = self.machine_st.p + offset; + or_frame.prelude.boip = 0; + or_frame.prelude.biip = 0; + or_frame.prelude.tr = self.machine_st.tr; + or_frame.prelude.h = self.machine_st.heap.len(); + or_frame.prelude.b0 = self.machine_st.b0; + or_frame.prelude.attr_var_queue_len = self.machine_st.attr_var_init.attr_var_queue.len(); + + self.machine_st.b = b; + + for i in 0..n { + or_frame[i] = self.machine_st.registers[i+1]; + } + + self.machine_st.hb = self.machine_st.heap.len(); + } + + self.machine_st.p += 1; + } + + #[inline(always)] + pub(super) fn indexed_try(&mut self, offset: usize) { + if let Some(iip_offset) = self.next_inner_applicable_clause() { + let n = self.machine_st.num_of_args; + let b = self.machine_st.stack.allocate_or_frame(n); + let or_frame = self.machine_st.stack.index_or_frame_mut(b); + + or_frame.prelude.num_cells = n; + or_frame.prelude.e = self.machine_st.e; + or_frame.prelude.cp = self.machine_st.cp; + or_frame.prelude.b = self.machine_st.b; + or_frame.prelude.bp = self.machine_st.p; + or_frame.prelude.boip = self.machine_st.oip; + or_frame.prelude.biip = self.machine_st.iip + iip_offset; // 1 + or_frame.prelude.tr = self.machine_st.tr; + or_frame.prelude.h = self.machine_st.heap.len(); + or_frame.prelude.b0 = self.machine_st.b0; + or_frame.prelude.attr_var_queue_len = self.machine_st.attr_var_init.attr_var_queue.len(); + + self.machine_st.b = b; + + for i in 0..n { + or_frame[i] = self.machine_st.registers[i+1]; + } + + self.machine_st.hb = self.machine_st.heap.len(); + + self.machine_st.oip = 0; + self.machine_st.iip = 0; + } + + self.machine_st.p += offset; + } + #[inline(always)] fn retry_me_else(&mut self, offset: usize) { let b = self.machine_st.b; let or_frame = self.machine_st.stack.index_or_frame_mut(b); let n = or_frame.prelude.num_cells; + let old_tr = or_frame.prelude.tr; + let curr_tr = self.machine_st.tr; + for i in 0..n { self.machine_st.registers[i + 1] = or_frame[i]; } - self.machine_st.num_of_args = n; - self.machine_st.e = or_frame.prelude.e; - self.machine_st.cp = or_frame.prelude.cp; + self.unwind_trail(old_tr, curr_tr); - or_frame.prelude.bp = self.machine_st.p + offset; + if let Some(offset) = self.next_applicable_clause(offset) { + let or_frame = self.machine_st.stack.index_or_frame_mut(b); - let old_tr = or_frame.prelude.tr; - let curr_tr = self.machine_st.tr; - let target_h = or_frame.prelude.h; - let attr_var_queue_len = or_frame.prelude.attr_var_queue_len; + self.machine_st.num_of_args = n; + self.machine_st.e = or_frame.prelude.e; + self.machine_st.cp = or_frame.prelude.cp; - self.machine_st.tr = or_frame.prelude.tr; - self.reset_attr_var_state(attr_var_queue_len); + or_frame.prelude.bp = self.machine_st.p + offset; - self.machine_st.hb = target_h; + let target_h = or_frame.prelude.h; + let attr_var_queue_len = or_frame.prelude.attr_var_queue_len; - self.unwind_trail(old_tr, curr_tr); + self.machine_st.tr = or_frame.prelude.tr; + self.reset_attr_var_state(attr_var_queue_len); - self.machine_st.trail.truncate(self.machine_st.tr); - self.machine_st.heap.truncate(target_h); + self.machine_st.hb = target_h; - self.machine_st.p += 1; + self.machine_st.trail.truncate(self.machine_st.tr); + self.machine_st.heap.truncate(target_h); + + self.machine_st.p += 1; + } else { + self.trust_me_epilogue(); + } } #[inline(always)] @@ -587,34 +900,42 @@ impl Machine { let or_frame = self.machine_st.stack.index_or_frame_mut(b); let n = or_frame.prelude.num_cells; + let old_tr = or_frame.prelude.tr; + let curr_tr = self.machine_st.tr; + for i in 0..n { self.machine_st.registers[i+1] = or_frame[i]; } - self.machine_st.num_of_args = n; - self.machine_st.e = or_frame.prelude.e; - self.machine_st.cp = or_frame.prelude.cp; + self.unwind_trail(old_tr, curr_tr); - or_frame.prelude.biip += 1; + if let Some(iip_offset) = self.next_inner_applicable_clause() { + let or_frame = self.machine_st.stack.index_or_frame_mut(b); - let old_tr = or_frame.prelude.tr; - let curr_tr = self.machine_st.tr; - let target_h = or_frame.prelude.h; - let attr_var_queue_len = or_frame.prelude.attr_var_queue_len; + self.machine_st.num_of_args = n; + self.machine_st.e = or_frame.prelude.e; + self.machine_st.cp = or_frame.prelude.cp; - self.machine_st.tr = or_frame.prelude.tr; - self.reset_attr_var_state(attr_var_queue_len); + or_frame.prelude.biip += iip_offset; - self.machine_st.hb = target_h; - self.machine_st.p = self.machine_st.p + offset; + let target_h = or_frame.prelude.h; + let attr_var_queue_len = or_frame.prelude.attr_var_queue_len; - self.unwind_trail(old_tr, curr_tr); + self.machine_st.tr = or_frame.prelude.tr; + self.machine_st.trail.truncate(self.machine_st.tr); - self.machine_st.trail.truncate(self.machine_st.tr); - self.machine_st.heap.truncate(target_h); + self.reset_attr_var_state(attr_var_queue_len); - self.machine_st.oip = 0; - self.machine_st.iip = 0; + self.machine_st.hb = target_h; + self.machine_st.p += offset; + + self.machine_st.heap.truncate(target_h); + + self.machine_st.oip = 0; + self.machine_st.iip = 0; + } else { + self.trust_epilogue(offset); + } } #[inline(always)] @@ -623,19 +944,32 @@ impl Machine { let or_frame = self.machine_st.stack.index_or_frame(b); let n = or_frame.prelude.num_cells; + let old_tr = or_frame.prelude.tr; + let curr_tr = self.machine_st.tr; + for i in 0..n { self.machine_st.registers[i+1] = or_frame[i]; } + self.unwind_trail(old_tr, curr_tr); + self.trust_epilogue(offset); + } + + #[inline(always)] + fn trust_epilogue(&mut self, offset: usize) { + let b = self.machine_st.b; + let or_frame = self.machine_st.stack.index_or_frame(b); + let n = or_frame.prelude.num_cells; + self.machine_st.num_of_args = n; self.machine_st.e = or_frame.prelude.e; self.machine_st.cp = or_frame.prelude.cp; - let old_tr = or_frame.prelude.tr; - let curr_tr = self.machine_st.tr; let target_h = or_frame.prelude.h; self.machine_st.tr = or_frame.prelude.tr; + self.machine_st.trail.truncate(self.machine_st.tr); + self.machine_st.b = or_frame.prelude.b; self.reset_attr_var_state(or_frame.prelude.attr_var_queue_len); @@ -643,9 +977,6 @@ impl Machine { self.machine_st.hb = target_h; self.machine_st.p = self.machine_st.p + offset; - self.unwind_trail(old_tr, curr_tr); - - self.machine_st.trail.truncate(self.machine_st.tr); self.machine_st.stack.truncate(b); self.machine_st.heap.truncate(target_h); @@ -663,12 +994,24 @@ impl Machine { self.machine_st.registers[i+1] = or_frame[i]; } + let old_tr = or_frame.prelude.tr; + let curr_tr = self.machine_st.tr; + + self.unwind_trail(old_tr, curr_tr); + + self.trust_me_epilogue(); + } + + #[inline(always)] + fn trust_me_epilogue(&mut self) { + let b = self.machine_st.b; + let or_frame = self.machine_st.stack.index_or_frame(b); + let n = or_frame.prelude.num_cells; + self.machine_st.num_of_args = n; self.machine_st.e = or_frame.prelude.e; self.machine_st.cp = or_frame.prelude.cp; - let old_tr = or_frame.prelude.tr; - let curr_tr = self.machine_st.tr; let target_h = or_frame.prelude.h; self.machine_st.tr = or_frame.prelude.tr; @@ -679,8 +1022,6 @@ impl Machine { self.machine_st.hb = target_h; self.machine_st.p += 1; - self.unwind_trail(old_tr, curr_tr); - self.machine_st.trail.truncate(self.machine_st.tr); self.machine_st.stack.truncate(b); self.machine_st.heap.truncate(target_h); diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 111569ec..532fb1e3 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -1277,7 +1277,7 @@ impl Machine { } #[inline(always)] - pub(crate) fn deref_register(&mut self, i: usize) -> HeapCellValue { + pub(crate) fn deref_register(&self, i: usize) -> HeapCellValue { self.machine_st.store(self.machine_st.deref(self.machine_st.registers[i])) } diff --git a/src/targets.rs b/src/targets.rs index 56a4c127..1596aae2 100644 --- a/src/targets.rs +++ b/src/targets.rs @@ -16,7 +16,7 @@ pub(crate) trait CompilationTarget<'a> { fn to_constant(lvl: Level, literal: Literal, r: RegType) -> Instruction; fn to_list(lvl: Level, r: RegType) -> Instruction; - fn to_structure(name: Atom, arity: usize, r: RegType) -> Instruction; + fn to_structure(lvl: Level, name: Atom, arity: usize, r: RegType) -> Instruction; fn to_void(num_subterms: usize) -> Instruction; fn is_void_instr(instr: &Instruction) -> bool; @@ -51,8 +51,8 @@ impl<'a> CompilationTarget<'a> for FactInstruction { Instruction::GetConstant(lvl, HeapCellValue::from(constant), reg) } - fn to_structure(name: Atom, arity: usize, reg: RegType) -> Instruction { - Instruction::GetStructure(name, arity, reg) + fn to_structure(lvl: Level, name: Atom, arity: usize, reg: RegType) -> Instruction { + Instruction::GetStructure(lvl, name, arity, reg) } fn to_list(lvl: Level, reg: RegType) -> Instruction { @@ -125,7 +125,7 @@ impl<'a> CompilationTarget<'a> for QueryInstruction { post_order_iter(term) } - fn to_structure(name: Atom, arity: usize, r: RegType) -> Instruction { + fn to_structure(_lvl: Level, name: Atom, arity: usize, r: RegType) -> Instruction { Instruction::PutStructure(name, arity, r) } -- 2.54.0