use lookahead to skip inapplicable clauses (#1028, #1502)

This commit is contained in:
Mark
2023-07-11 17:59:53 -06:00
parent 1791bd8626
commit 4fd37335f5
7 changed files with 537 additions and 226 deletions

View File

@@ -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<usize> {
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<u32> {
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;
or_frame.prelude.bp = self.machine_st.p + offset;
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.tr = or_frame.prelude.tr;
self.reset_attr_var_state(attr_var_queue_len);
self.machine_st.hb = target_h;
self.unwind_trail(old_tr, curr_tr);
self.machine_st.trail.truncate(self.machine_st.tr);
self.machine_st.heap.truncate(target_h);
if let Some(offset) = self.next_applicable_clause(offset) {
let or_frame = self.machine_st.stack.index_or_frame_mut(b);
self.machine_st.p += 1;
self.machine_st.num_of_args = n;
self.machine_st.e = or_frame.prelude.e;
self.machine_st.cp = or_frame.prelude.cp;
or_frame.prelude.bp = 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.machine_st.tr = or_frame.prelude.tr;
self.reset_attr_var_state(attr_var_queue_len);
self.machine_st.hb = target_h;
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;
or_frame.prelude.biip += 1;
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.tr = or_frame.prelude.tr;
self.reset_attr_var_state(attr_var_queue_len);
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.heap.truncate(target_h);
if let Some(iip_offset) = self.next_inner_applicable_clause() {
let or_frame = self.machine_st.stack.index_or_frame_mut(b);
self.machine_st.oip = 0;
self.machine_st.iip = 0;
self.machine_st.num_of_args = n;
self.machine_st.e = or_frame.prelude.e;
self.machine_st.cp = or_frame.prelude.cp;
or_frame.prelude.biip += iip_offset;
let target_h = or_frame.prelude.h;
let attr_var_queue_len = or_frame.prelude.attr_var_queue_len;
self.machine_st.tr = or_frame.prelude.tr;
self.machine_st.trail.truncate(self.machine_st.tr);
self.reset_attr_var_state(attr_var_queue_len);
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);