replace compare_term_test with parallel iterator, add is_not_variant

This commit is contained in:
Mark Thom
2025-12-11 22:08:16 -08:00
parent 9089f9ddb4
commit 29cd80510b
10 changed files with 488 additions and 475 deletions

View File

@@ -643,15 +643,12 @@ enum SystemClauseType {
UnattributedVar, UnattributedVar,
#[strum_discriminants(strum(props(Arity = "4", Name = "$get_db_refs")))] #[strum_discriminants(strum(props(Arity = "4", Name = "$get_db_refs")))]
GetDBRefs, GetDBRefs,
#[strum_discriminants(strum(props(
Arity = "2",
Name = "$keysort_with_constant_var_ordering"
)))]
KeySortWithConstantVarOrdering,
#[strum_discriminants(strum(props(Arity = "0", Name = "$inference_limit_exceeded")))] #[strum_discriminants(strum(props(Arity = "0", Name = "$inference_limit_exceeded")))]
InferenceLimitExceeded, InferenceLimitExceeded,
#[strum_discriminants(strum(props(Arity = "1", Name = "$argv")))] #[strum_discriminants(strum(props(Arity = "1", Name = "$argv")))]
Argv, Argv,
#[strum_discriminants(strum(props(Arity = "2", Name = "$variant")))]
IsVariant,
Repl(ReplCodePtr), Repl(ReplCodePtr),
} }

View File

@@ -170,13 +170,9 @@ impl PartialOrd<BranchNumber> for BranchNumber {
impl BranchNumber { impl BranchNumber {
pub(crate) fn has_as_subbranch(&self, other: &Self) -> bool { pub(crate) fn has_as_subbranch(&self, other: &Self) -> bool {
let delta_ratio = &self.delta / &other.delta; other.delta <= self.delta &&
other.branch_num >= self.branch_num &&
if !delta_ratio.denominator().is_one() { other.branch_num < &self.branch_num + &self.delta
return false;
}
other.branch_num >= self.branch_num && other.branch_num < &self.branch_num + &self.delta
} }
pub(crate) fn split(&self) -> BranchNumber { pub(crate) fn split(&self) -> BranchNumber {

View File

@@ -1,21 +1,378 @@
#![allow(clippy::new_without_default)] // annotating structs annotated with #[bitfield] doesn't work #![allow(clippy::new_without_default)] // annotating structs annotated with #[bitfield] doesn't work
#![allow(unused_parens)] // see mthom/scryer-prolog#3092 and rust-lang/rust#147126 #![allow(unused_parens)] // see mthom/scryer-prolog#3092 and rust-lang/rust#147126
use crate::arena::Arena;
use crate::forms::Number;
#[cfg(test)] #[cfg(test)]
pub(crate) use crate::machine::gc::StacklessPreOrderHeapIter; pub(crate) use crate::machine::gc::StacklessPreOrderHeapIter;
use crate::atom_table::*; use crate::atom_table::*;
use crate::machine::cycle_detection::*; use crate::machine::cycle_detection::*;
use crate::machine::heap::*; use crate::machine::heap::*;
use crate::machine::machine_indices::TermOrderCategory;
use crate::machine::stack::*; use crate::machine::stack::*;
use crate::parser::lexer::MachineState;
use crate::types::*; use crate::types::*;
use core::marker::PhantomData; use core::marker::PhantomData;
use fxhash::FxBuildHasher;
use indexmap::IndexSet;
use scryer_modular_bitfield::prelude::*; use scryer_modular_bitfield::prelude::*;
use std::cmp::Ordering;
use std::ops::Deref; use std::ops::Deref;
use std::vec::Vec; use std::vec::Vec;
// iterate through the subterms of a pair of terms
// for as long as they structurally agree, reporting
// the earliest (pre-order) difference before returning
// None's and pairs of variables as the Iterator Item.
pub struct ParallelHeapIter<'a> {
stack: Vec<HeapCellValue>,
heap: &'a Heap,
arena: &'a Arena,
tabu_list: IndexSet<(usize, usize), FxBuildHasher>,
}
impl<'a> ParallelHeapIter<'a> {
pub fn from(machine_st: &'a MachineState, h1: HeapCellValue, h2: HeapCellValue) -> Self {
Self {
stack: vec![h2, h1],
heap: &machine_st.heap,
arena: &machine_st.arena,
tabu_list: IndexSet::with_hasher(FxBuildHasher::new()),
}
}
}
#[derive(Debug)]
pub enum TermPair {
Vars(usize, usize),
Less(HeapCellValue, HeapCellValue),
Greater(HeapCellValue, HeapCellValue),
Unordered(HeapCellValue, HeapCellValue),
}
impl ParallelHeapIter<'_> {
#[inline]
fn parallel_cmp<Cmp: Ord>(
&mut self,
v1: Cmp,
v2: Cmp,
h1: HeapCellValue,
h2: HeapCellValue,
) -> Option<TermPair> {
match v1.cmp(&v2) {
Ordering::Greater => {
self.stack.clear();
Some(TermPair::Greater(h1, h2))
}
Ordering::Less => {
self.stack.clear();
Some(TermPair::Less(h1, h2))
}
Ordering::Equal => None,
}
}
}
macro_rules! some_or_return {
($e:expr) => {
if let Some(x) = $e {
return Some(x);
}
};
}
impl Iterator for ParallelHeapIter<'_> {
type Item = TermPair;
fn next(&mut self) -> Option<Self::Item> {
use crate::offset_table::F64Offset;
while let Some(s1) = self.stack.pop() {
let s1 = heap_bound_deref(self.heap, s1);
let s2 = self.stack.pop().unwrap();
let s2 = heap_bound_deref(self.heap, s2);
if s1 == s2 {
continue;
}
let v1 = heap_bound_store(self.heap, s1);
let v2 = heap_bound_store(self.heap, s2);
let order_cat_v1 = v1.order_category(self.heap);
let order_cat_v2 = v2.order_category(self.heap);
some_or_return!(self.parallel_cmp(order_cat_v1, order_cat_v2, v1, v2));
match order_cat_v1 {
Some(TermOrderCategory::Variable) => {
let v1 = v1.get_value() as usize;
let v2 = v2.get_value() as usize;
return Some(TermPair::Vars(v1, v2));
}
Some(TermOrderCategory::FloatingPoint) => {
let v1_offset = cell_as_f64_offset!(v1);
let v2_offset = cell_as_f64_offset!(v2);
let v1_f64 = self.arena.f64_tbl.get_entry(v1_offset);
let v2_f64 = self.arena.f64_tbl.get_entry(v2_offset);
some_or_return!(self.parallel_cmp(v1_f64, v2_f64, v1, v2));
}
Some(TermOrderCategory::Integer) => {
let v1_int = Number::try_from((v1, &self.arena.f64_tbl)).unwrap();
let v2_int = Number::try_from((v2, &self.arena.f64_tbl)).unwrap();
some_or_return!(self.parallel_cmp(v1_int, v2_int, v1, v2));
}
Some(TermOrderCategory::Atom) => {
read_heap_cell!(v1,
(HeapCellValueTag::Atom, (n1, _a1)) => {
read_heap_cell!(v2,
(HeapCellValueTag::Atom, (n2, _a2)) => {
some_or_return!(self.parallel_cmp(n1, n2, v1, v2));
}
(HeapCellValueTag::Str, s) => {
let n2 = cell_as_atom_cell!(self.heap[s])
.get_name();
some_or_return!(self.parallel_cmp(n1, n2, v1, v2));
}
_ => {
unreachable!();
}
)
}
(HeapCellValueTag::Str, s) => {
let n1 = cell_as_atom_cell!(self.heap[s])
.get_name();
read_heap_cell!(v2,
(HeapCellValueTag::Atom, (n2, _a2)) => {
some_or_return!(self.parallel_cmp(n1, n2, v1, v2));
}
(HeapCellValueTag::Str, s) => {
let n2 = cell_as_atom_cell!(self.heap[s])
.get_name();
some_or_return!(self.parallel_cmp(n1, n2, v1, v2));
}
_ => {
unreachable!();
}
)
}
_ => {
unreachable!()
}
)
}
Some(TermOrderCategory::Compound) => {
read_heap_cell!(v1,
(HeapCellValueTag::Lis, l1) => {
read_heap_cell!(v2,
(HeapCellValueTag::PStrLoc, l2) => {
if self.tabu_list.contains(&(l1, l2)) {
continue;
}
self.tabu_list.insert((l1, l2));
// like the action of partial_string_to_stack here but the
// ordering of stack pushes is (crucially for comparison
// correctness) different.
let (c, succ_cell) = self.heap.last_str_char_and_tail(l2);
self.stack.push(succ_cell);
self.stack.push(heap_loc_as_cell!(l1 + 1));
self.stack.push(char_as_cell!(c));
self.stack.push(heap_loc_as_cell!(l1));
}
(HeapCellValueTag::Lis, l2) => {
if self.tabu_list.contains(&(l1, l2)) {
continue;
}
self.tabu_list.insert((l1, l2));
self.stack.push(self.heap[l2 + 1]);
self.stack.push(self.heap[l1 + 1]);
self.stack.push(self.heap[l2]);
self.stack.push(self.heap[l1]);
}
(HeapCellValueTag::Str, s2) => {
if self.tabu_list.contains(&(l1, s2)) {
continue;
}
let (n2, a2) = cell_as_atom_cell!(self.heap[s2])
.get_name_and_arity();
some_or_return!(self.parallel_cmp((2, atom!(".")), (a2, n2), v1, v2));
self.tabu_list.insert((l1, s2));
self.stack.push(self.heap[s2 + 2]);
self.stack.push(self.heap[l1 + 1]);
self.stack.push(self.heap[s2 + 1]);
self.stack.push(self.heap[l1]);
}
_ => {
unreachable!();
}
)
}
(HeapCellValueTag::PStrLoc, l1) => {
read_heap_cell!(v2,
(HeapCellValueTag::PStrLoc, l2) => {
if self.tabu_list.contains(&(l1, l2)) {
continue;
}
match self.heap.compare_pstr_segments(l1, l2) {
PStrSegmentCmpResult::Continue(v1, v2) => {
self.tabu_list.insert((l1, l2));
self.stack.push(v1.offset_by(l1));
self.stack.push(v2.offset_by(l2));
}
PStrSegmentCmpResult::Less => {
self.stack.clear();
return Some(TermPair::Less(v1, v2));
}
PStrSegmentCmpResult::Greater => {
self.stack.clear();
return Some(TermPair::Greater(v1, v2));
}
}
}
(HeapCellValueTag::Lis, l2) => {
if self.tabu_list.contains(&(l1, l2)) {
continue;
}
self.tabu_list.insert((l1, l2));
let (c, succ_cell) = self.heap.last_str_char_and_tail(l1);
self.stack.push(succ_cell);
self.stack.push(heap_loc_as_cell!(l2 + 1));
self.stack.push(char_as_cell!(c));
self.stack.push(heap_loc_as_cell!(l2));
}
(HeapCellValueTag::Str, s2) => {
if self.tabu_list.contains(&(l1, s2)) {
continue;
}
self.tabu_list.insert((l1, s2));
let (n2, a2) = cell_as_atom_cell!(self.heap[s2])
.get_name_and_arity();
some_or_return!(self.parallel_cmp((2, atom!(".")), (a2, n2), v1, v2));
let (c, succ_cell) = self.heap.last_str_char_and_tail(l1);
self.stack.push(heap_loc_as_cell!(s2+2));
self.stack.push(succ_cell);
self.stack.push(heap_loc_as_cell!(s2+1));
self.stack.push(char_as_cell!(c));
}
_ => {
unreachable!()
}
);
}
(HeapCellValueTag::Str, s1) => {
read_heap_cell!(v2,
(HeapCellValueTag::Str, s2) => {
if self.tabu_list.contains(&(s1, s2)) {
continue;
}
let (n1, a1) = cell_as_atom_cell!(self.heap[s1])
.get_name_and_arity();
let (n2, a2) = cell_as_atom_cell!(self.heap[s2])
.get_name_and_arity();
some_or_return!(self.parallel_cmp((a1, n1), (a2, n2), v1, v2));
self.tabu_list.insert((s1, s2));
for idx in (1 .. a1+1).rev() {
self.stack.push(self.heap[s2+idx]);
self.stack.push(self.heap[s1+idx]);
}
}
(HeapCellValueTag::Lis, l2) => {
if self.tabu_list.contains(&(s1, l2)) {
continue;
}
let (n1, a1) = cell_as_atom_cell!(self.heap[s1])
.get_name_and_arity();
some_or_return!(self.parallel_cmp((a1, n1), (2, atom!(".")), v1, v2));
self.stack.push(self.heap[l2]);
self.stack.push(self.heap[s1+1]);
self.stack.push(self.heap[l2+1]);
self.stack.push(self.heap[s1+2]);
}
(HeapCellValueTag::PStrLoc, l2) => {
if self.tabu_list.contains(&(s1, l2)) {
continue;
}
let (n1, a1) = cell_as_atom_cell!(self.heap[s1])
.get_name_and_arity();
some_or_return!(self.parallel_cmp((a1, n1), (2, atom!(".")), v1, v2));
self.tabu_list.insert((s1, l2));
let (c, succ_cell) = self.heap.last_str_char_and_tail(l2);
self.stack.push(succ_cell);
self.stack.push(heap_loc_as_cell!(s1+2));
self.stack.push(char_as_cell!(c));
self.stack.push(heap_loc_as_cell!(s1+1));
}
_ => {
unreachable!()
}
)
}
_ => {
unreachable!()
}
);
}
None => {
return Some(TermPair::Unordered(v1, v2));
}
}
}
None
}
}
#[inline(always)] #[inline(always)]
pub fn eager_stackful_preorder_iter( pub fn eager_stackful_preorder_iter(
heap: &mut Heap, heap: &mut Heap,

View File

@@ -726,7 +726,6 @@ impl Instruction {
| &Instruction::CallDeleteAllAttributesFromVar | &Instruction::CallDeleteAllAttributesFromVar
| &Instruction::CallUnattributedVar | &Instruction::CallUnattributedVar
| &Instruction::CallGetDBRefs | &Instruction::CallGetDBRefs
| &Instruction::CallKeySortWithConstantVarOrdering
| &Instruction::CallInferenceLimitExceeded | &Instruction::CallInferenceLimitExceeded
| &Instruction::CallFetchGlobalVar | &Instruction::CallFetchGlobalVar
| &Instruction::CallFirstStream | &Instruction::CallFirstStream
@@ -986,7 +985,6 @@ impl Instruction {
| &Instruction::ExecuteDeleteAllAttributesFromVar | &Instruction::ExecuteDeleteAllAttributesFromVar
| &Instruction::ExecuteUnattributedVar | &Instruction::ExecuteUnattributedVar
| &Instruction::ExecuteGetDBRefs | &Instruction::ExecuteGetDBRefs
| &Instruction::ExecuteKeySortWithConstantVarOrdering
| &Instruction::ExecuteInferenceLimitExceeded | &Instruction::ExecuteInferenceLimitExceeded
| &Instruction::ExecuteFetchGlobalVar | &Instruction::ExecuteFetchGlobalVar
| &Instruction::ExecuteFirstStream | &Instruction::ExecuteFirstStream

View File

@@ -103,9 +103,8 @@ impl MachineState {
.collect() .collect()
}; };
attr_vars.sort_unstable_by(|a1, a2| { attr_vars
compare_term_test!(self, *a1, *a2).unwrap_or(Ordering::Less) .sort_unstable_by(|a1, a2| self.compare_term_test(*a1, *a2).unwrap_or(Ordering::Less));
});
attr_vars.dedup(); attr_vars.dedup();
attr_vars attr_vars

View File

@@ -118,7 +118,7 @@ impl MachineState {
} }
); );
let atom = match compare_term_test!(self, a2, a3) { let atom = match self.compare_term_test(a2, a3) {
Some(Ordering::Greater) => { Some(Ordering::Greater) => {
atom!(">") atom!(">")
} }
@@ -151,11 +151,8 @@ impl MachineState {
let stub_gen = || functor_stub(atom!("sort"), 2); let stub_gen = || functor_stub(atom!("sort"), 2);
let mut list = self.try_from_list(self.registers[1], stub_gen)?; let mut list = self.try_from_list(self.registers[1], stub_gen)?;
list.sort_unstable_by(|v1, v2| { list.sort_unstable_by(|v1, v2| self.compare_term_test(*v1, *v2).unwrap_or(Ordering::Less));
compare_term_test!(self, *v1, *v2).unwrap_or(Ordering::Less) list.dedup_by(|v1, v2| self.compare_term_test(*v1, *v2) == Some(Ordering::Equal));
});
list.dedup_by(|v1, v2| compare_term_test!(self, *v1, *v2) == Some(Ordering::Equal));
let heap_addr = resource_error_call_result!( let heap_addr = resource_error_call_result!(
self, self,
@@ -167,7 +164,7 @@ impl MachineState {
Ok(()) Ok(())
} }
fn keysort(&mut self, var_comparison: VarComparison) -> CallResult { fn keysort(&mut self) -> CallResult {
self.check_keysort_errors()?; self.check_keysort_errors()?;
let stub_gen = || functor_stub(atom!("keysort"), 2); let stub_gen = || functor_stub(atom!("keysort"), 2);
@@ -180,9 +177,7 @@ impl MachineState {
key_pairs.push((key, val)); key_pairs.push((key, val));
} }
key_pairs.sort_by(|a1, a2| { key_pairs.sort_by(|a1, a2| self.compare_term_test(a1.0, a2.0).unwrap_or(Ordering::Less));
compare_term_test!(self, a1.0, a2.0, var_comparison).unwrap_or(Ordering::Less)
});
let heap_addr = resource_error_call_result!( let heap_addr = resource_error_call_result!(
self, self,
@@ -2034,8 +2029,7 @@ impl Machine {
let a1 = self.machine_st.registers[1]; let a1 = self.machine_st.registers[1];
let a2 = self.machine_st.registers[2]; let a2 = self.machine_st.registers[2];
if let Some(Ordering::Greater) = compare_term_test!(self.machine_st, a1, a2) if let Some(Ordering::Greater) = self.machine_st.compare_term_test(a1, a2) {
{
self.machine_st.p += 1; self.machine_st.p += 1;
} else { } else {
self.machine_st.backtrack(); self.machine_st.backtrack();
@@ -2045,8 +2039,7 @@ impl Machine {
let a1 = self.machine_st.registers[1]; let a1 = self.machine_st.registers[1];
let a2 = self.machine_st.registers[2]; let a2 = self.machine_st.registers[2];
if let Some(Ordering::Greater) = compare_term_test!(self.machine_st, a1, a2) if let Some(Ordering::Greater) = self.machine_st.compare_term_test(a1, a2) {
{
self.machine_st.p = self.machine_st.cp; self.machine_st.p = self.machine_st.cp;
} else { } else {
self.machine_st.backtrack(); self.machine_st.backtrack();
@@ -2056,7 +2049,7 @@ impl Machine {
let a1 = self.machine_st.registers[1]; let a1 = self.machine_st.registers[1];
let a2 = self.machine_st.registers[2]; let a2 = self.machine_st.registers[2];
if let Some(Ordering::Less) = compare_term_test!(self.machine_st, a1, a2) { if let Some(Ordering::Less) = self.machine_st.compare_term_test(a1, a2) {
self.machine_st.p += 1; self.machine_st.p += 1;
} else { } else {
self.machine_st.backtrack(); self.machine_st.backtrack();
@@ -2066,7 +2059,7 @@ impl Machine {
let a1 = self.machine_st.registers[1]; let a1 = self.machine_st.registers[1];
let a2 = self.machine_st.registers[2]; let a2 = self.machine_st.registers[2];
if let Some(Ordering::Less) = compare_term_test!(self.machine_st, a1, a2) { if let Some(Ordering::Less) = self.machine_st.compare_term_test(a1, a2) {
self.machine_st.p = self.machine_st.cp; self.machine_st.p = self.machine_st.cp;
} else { } else {
self.machine_st.backtrack(); self.machine_st.backtrack();
@@ -2076,7 +2069,7 @@ impl Machine {
let a1 = self.machine_st.registers[1]; let a1 = self.machine_st.registers[1];
let a2 = self.machine_st.registers[2]; let a2 = self.machine_st.registers[2];
match compare_term_test!(self.machine_st, a1, a2) { match self.machine_st.compare_term_test(a1, a2) {
Some(Ordering::Greater | Ordering::Equal) => { Some(Ordering::Greater | Ordering::Equal) => {
self.machine_st.p += 1; self.machine_st.p += 1;
} }
@@ -2089,7 +2082,7 @@ impl Machine {
let a1 = self.machine_st.registers[1]; let a1 = self.machine_st.registers[1];
let a2 = self.machine_st.registers[2]; let a2 = self.machine_st.registers[2];
match compare_term_test!(self.machine_st, a1, a2) { match self.machine_st.compare_term_test(a1, a2) {
Some(Ordering::Greater | Ordering::Equal) => { Some(Ordering::Greater | Ordering::Equal) => {
self.machine_st.p = self.machine_st.cp; self.machine_st.p = self.machine_st.cp;
} }
@@ -2102,7 +2095,7 @@ impl Machine {
let a1 = self.machine_st.registers[1]; let a1 = self.machine_st.registers[1];
let a2 = self.machine_st.registers[2]; let a2 = self.machine_st.registers[2];
match compare_term_test!(self.machine_st, a1, a2) { match self.machine_st.compare_term_test(a1, a2) {
Some(Ordering::Less | Ordering::Equal) => { Some(Ordering::Less | Ordering::Equal) => {
self.machine_st.p += 1; self.machine_st.p += 1;
} }
@@ -2115,7 +2108,7 @@ impl Machine {
let a1 = self.machine_st.registers[1]; let a1 = self.machine_st.registers[1];
let a2 = self.machine_st.registers[2]; let a2 = self.machine_st.registers[2];
match compare_term_test!(self.machine_st, a1, a2) { match self.machine_st.compare_term_test(a1, a2) {
Some(Ordering::Less | Ordering::Equal) => { Some(Ordering::Less | Ordering::Equal) => {
self.machine_st.p = self.machine_st.cp; self.machine_st.p = self.machine_st.cp;
} }
@@ -2188,7 +2181,7 @@ impl Machine {
let a1 = self.machine_st.registers[1]; let a1 = self.machine_st.registers[1];
let a2 = self.machine_st.registers[2]; let a2 = self.machine_st.registers[2];
if let Some(Ordering::Equal) = compare_term_test!(self.machine_st, a1, a2) { if let Some(Ordering::Equal) = self.machine_st.compare_term_test(a1, a2) {
self.machine_st.backtrack(); self.machine_st.backtrack();
} else { } else {
self.machine_st.p += 1; self.machine_st.p += 1;
@@ -2198,7 +2191,7 @@ impl Machine {
let a1 = self.machine_st.registers[1]; let a1 = self.machine_st.registers[1];
let a2 = self.machine_st.registers[2]; let a2 = self.machine_st.registers[2];
if let Some(Ordering::Equal) = compare_term_test!(self.machine_st, a1, a2) { if let Some(Ordering::Equal) = self.machine_st.compare_term_test(a1, a2) {
self.machine_st.backtrack(); self.machine_st.backtrack();
} else { } else {
self.machine_st.p = self.machine_st.cp; self.machine_st.p = self.machine_st.cp;
@@ -2213,19 +2206,11 @@ impl Machine {
step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
} }
&Instruction::DefaultCallKeySort => { &Instruction::DefaultCallKeySort => {
try_or_throw!( try_or_throw!(self.machine_st, self.machine_st.keysort(), continue);
self.machine_st,
self.machine_st.keysort(VarComparison::Distinct),
continue
);
step_or_fail!(self.machine_st, self.machine_st.p += 1); step_or_fail!(self.machine_st, self.machine_st.p += 1);
} }
&Instruction::DefaultExecuteKeySort => { &Instruction::DefaultExecuteKeySort => {
try_or_throw!( try_or_throw!(self.machine_st, self.machine_st.keysort(), continue);
self.machine_st,
self.machine_st.keysort(VarComparison::Distinct),
continue
);
if self.machine_st.fail { if self.machine_st.fail {
self.machine_st.backtrack(); self.machine_st.backtrack();
@@ -2323,8 +2308,7 @@ impl Machine {
let a1 = self.machine_st.registers[1]; let a1 = self.machine_st.registers[1];
let a2 = self.machine_st.registers[2]; let a2 = self.machine_st.registers[2];
if let Some(Ordering::Greater) = compare_term_test!(self.machine_st, a1, a2) if let Some(Ordering::Greater) = self.machine_st.compare_term_test(a1, a2) {
{
increment_call_count!(self.machine_st); increment_call_count!(self.machine_st);
self.machine_st.p += 1; self.machine_st.p += 1;
} else { } else {
@@ -2335,8 +2319,7 @@ impl Machine {
let a1 = self.machine_st.registers[1]; let a1 = self.machine_st.registers[1];
let a2 = self.machine_st.registers[2]; let a2 = self.machine_st.registers[2];
if let Some(Ordering::Greater) = compare_term_test!(self.machine_st, a1, a2) if let Some(Ordering::Greater) = self.machine_st.compare_term_test(a1, a2) {
{
increment_call_count!(self.machine_st); increment_call_count!(self.machine_st);
self.machine_st.p = self.machine_st.cp; self.machine_st.p = self.machine_st.cp;
} else { } else {
@@ -2347,7 +2330,7 @@ impl Machine {
let a1 = self.machine_st.registers[1]; let a1 = self.machine_st.registers[1];
let a2 = self.machine_st.registers[2]; let a2 = self.machine_st.registers[2];
if let Some(Ordering::Less) = compare_term_test!(self.machine_st, a1, a2) { if let Some(Ordering::Less) = self.machine_st.compare_term_test(a1, a2) {
increment_call_count!(self.machine_st); increment_call_count!(self.machine_st);
self.machine_st.p += 1; self.machine_st.p += 1;
} else { } else {
@@ -2358,7 +2341,7 @@ impl Machine {
let a1 = self.machine_st.registers[1]; let a1 = self.machine_st.registers[1];
let a2 = self.machine_st.registers[2]; let a2 = self.machine_st.registers[2];
if let Some(Ordering::Less) = compare_term_test!(self.machine_st, a1, a2) { if let Some(Ordering::Less) = self.machine_st.compare_term_test(a1, a2) {
increment_call_count!(self.machine_st); increment_call_count!(self.machine_st);
self.machine_st.p = self.machine_st.cp; self.machine_st.p = self.machine_st.cp;
} else { } else {
@@ -2369,7 +2352,7 @@ impl Machine {
let a1 = self.machine_st.registers[1]; let a1 = self.machine_st.registers[1];
let a2 = self.machine_st.registers[2]; let a2 = self.machine_st.registers[2];
match compare_term_test!(self.machine_st, a1, a2) { match self.machine_st.compare_term_test(a1, a2) {
Some(Ordering::Greater | Ordering::Equal) => { Some(Ordering::Greater | Ordering::Equal) => {
increment_call_count!(self.machine_st); increment_call_count!(self.machine_st);
self.machine_st.p += 1; self.machine_st.p += 1;
@@ -2383,7 +2366,7 @@ impl Machine {
let a1 = self.machine_st.registers[1]; let a1 = self.machine_st.registers[1];
let a2 = self.machine_st.registers[2]; let a2 = self.machine_st.registers[2];
match compare_term_test!(self.machine_st, a1, a2) { match self.machine_st.compare_term_test(a1, a2) {
Some(Ordering::Greater | Ordering::Equal) => { Some(Ordering::Greater | Ordering::Equal) => {
increment_call_count!(self.machine_st); increment_call_count!(self.machine_st);
self.machine_st.p = self.machine_st.cp; self.machine_st.p = self.machine_st.cp;
@@ -2397,7 +2380,7 @@ impl Machine {
let a1 = self.machine_st.registers[1]; let a1 = self.machine_st.registers[1];
let a2 = self.machine_st.registers[2]; let a2 = self.machine_st.registers[2];
match compare_term_test!(self.machine_st, a1, a2) { match self.machine_st.compare_term_test(a1, a2) {
Some(Ordering::Less | Ordering::Equal) => { Some(Ordering::Less | Ordering::Equal) => {
increment_call_count!(self.machine_st); increment_call_count!(self.machine_st);
self.machine_st.p += 1; self.machine_st.p += 1;
@@ -2411,7 +2394,7 @@ impl Machine {
let a1 = self.machine_st.registers[1]; let a1 = self.machine_st.registers[1];
let a2 = self.machine_st.registers[2]; let a2 = self.machine_st.registers[2];
match compare_term_test!(self.machine_st, a1, a2) { match self.machine_st.compare_term_test(a1, a2) {
Some(Ordering::Less | Ordering::Equal) => { Some(Ordering::Less | Ordering::Equal) => {
increment_call_count!(self.machine_st); increment_call_count!(self.machine_st);
self.machine_st.p = self.machine_st.cp; self.machine_st.p = self.machine_st.cp;
@@ -2503,7 +2486,7 @@ impl Machine {
let a1 = self.machine_st.registers[1]; let a1 = self.machine_st.registers[1];
let a2 = self.machine_st.registers[2]; let a2 = self.machine_st.registers[2];
if let Some(Ordering::Equal) = compare_term_test!(self.machine_st, a1, a2) { if let Some(Ordering::Equal) = self.machine_st.compare_term_test(a1, a2) {
self.machine_st.backtrack(); self.machine_st.backtrack();
} else { } else {
increment_call_count!(self.machine_st); increment_call_count!(self.machine_st);
@@ -2514,7 +2497,7 @@ impl Machine {
let a1 = self.machine_st.registers[1]; let a1 = self.machine_st.registers[1];
let a2 = self.machine_st.registers[2]; let a2 = self.machine_st.registers[2];
if let Some(Ordering::Equal) = compare_term_test!(self.machine_st, a1, a2) { if let Some(Ordering::Equal) = self.machine_st.compare_term_test(a1, a2) {
self.machine_st.backtrack(); self.machine_st.backtrack();
} else { } else {
increment_call_count!(self.machine_st); increment_call_count!(self.machine_st);
@@ -2542,11 +2525,7 @@ impl Machine {
} }
} }
&Instruction::CallKeySort => { &Instruction::CallKeySort => {
try_or_throw!( try_or_throw!(self.machine_st, self.machine_st.keysort(), continue);
self.machine_st,
self.machine_st.keysort(VarComparison::Distinct),
continue
);
if self.machine_st.fail { if self.machine_st.fail {
self.machine_st.backtrack(); self.machine_st.backtrack();
@@ -2556,11 +2535,7 @@ impl Machine {
} }
} }
&Instruction::ExecuteKeySort => { &Instruction::ExecuteKeySort => {
try_or_throw!( try_or_throw!(self.machine_st, self.machine_st.keysort(), continue);
self.machine_st,
self.machine_st.keysort(VarComparison::Distinct),
continue
);
if self.machine_st.fail { if self.machine_st.fail {
self.machine_st.backtrack(); self.machine_st.backtrack();
@@ -2570,11 +2545,7 @@ impl Machine {
} }
} }
&Instruction::CallKeySortWithConstantVarOrdering => { &Instruction::CallKeySortWithConstantVarOrdering => {
try_or_throw!( try_or_throw!(self.machine_st, self.machine_st.keysort(), continue);
self.machine_st,
self.machine_st.keysort(VarComparison::Indistinct),
continue
);
if self.machine_st.fail { if self.machine_st.fail {
self.machine_st.backtrack(); self.machine_st.backtrack();
@@ -2584,11 +2555,7 @@ impl Machine {
} }
} }
&Instruction::ExecuteKeySortWithConstantVarOrdering => { &Instruction::ExecuteKeySortWithConstantVarOrdering => {
try_or_throw!( try_or_throw!(self.machine_st, self.machine_st.keysort(), continue);
self.machine_st,
self.machine_st.keysort(VarComparison::Indistinct),
continue
);
if self.machine_st.fail { if self.machine_st.fail {
self.machine_st.backtrack(); self.machine_st.backtrack();
@@ -4813,6 +4780,14 @@ impl Machine {
try_or_throw!(self.machine_st, self.argv(), continue); try_or_throw!(self.machine_st, self.argv(), continue);
step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
} }
&Instruction::CallIsVariant => {
self.machine_st.fail = self.machine_st.is_not_variant();
step_or_fail!(self.machine_st, self.machine_st.p += 1);
}
&Instruction::ExecuteIsVariant => {
self.machine_st.fail = self.machine_st.is_not_variant();
step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp);
}
&Instruction::CallCurrentTime => { &Instruction::CallCurrentTime => {
self.current_time(); self.current_time();
step_or_fail!(self.machine_st, self.machine_st.p += 1); step_or_fail!(self.machine_st, self.machine_st.p += 1);

View File

@@ -7,7 +7,6 @@ use crate::machine::copier::*;
use crate::machine::heap::AllocError; use crate::machine::heap::AllocError;
use crate::machine::heap::*; use crate::machine::heap::*;
use crate::machine::machine_errors::*; use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*;
use crate::machine::machine_state::*; use crate::machine::machine_state::*;
use crate::machine::partial_string::*; use crate::machine::partial_string::*;
use crate::machine::stack::*; use crate::machine::stack::*;
@@ -17,8 +16,6 @@ use crate::parser::ast::*;
use crate::parser::dashu::{Integer, Rational}; use crate::parser::dashu::{Integer, Rational};
use crate::types::*; use crate::types::*;
use indexmap::IndexSet;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::convert::TryFrom; use std::convert::TryFrom;
@@ -380,347 +377,6 @@ impl MachineState {
} }
} }
pub fn compare_term_test(&mut self, var_comparison: VarComparison) -> Option<Ordering> {
let mut tabu_list = IndexSet::new();
while let Some(s1) = self.pdl.pop() {
let s1 = self.deref(s1);
let s2 = self.pdl.pop().unwrap();
let s2 = self.deref(s2);
if s1 == s2 {
continue;
}
let v1 = self.store(s1);
let v2 = self.store(s2);
let order_cat_v1 = v1.order_category(&self.heap);
let order_cat_v2 = v2.order_category(&self.heap);
if order_cat_v1 != order_cat_v2 {
self.pdl.clear();
return Some(order_cat_v1.cmp(&order_cat_v2));
}
match order_cat_v1 {
Some(TermOrderCategory::Variable) => {
if let VarComparison::Distinct = var_comparison {
let v1 = v1.as_var().unwrap();
let v2 = v2.as_var().unwrap();
if v1 != v2 {
self.pdl.clear();
return Some(v1.cmp(&v2));
}
}
}
Some(TermOrderCategory::FloatingPoint) => {
let v1 = cell_as_f64_offset!(v1);
let v2 = cell_as_f64_offset!(v2);
let v1 = self.arena.f64_tbl.get_entry(v1);
let v2 = self.arena.f64_tbl.get_entry(v2);
if v1 != v2 {
self.pdl.clear();
return Some(v1.cmp(&v2));
}
}
Some(TermOrderCategory::Integer) => {
let v1 = Number::try_from((v1, &self.arena.f64_tbl)).unwrap();
let v2 = Number::try_from((v2, &self.arena.f64_tbl)).unwrap();
if v1 != v2 {
self.pdl.clear();
return Some(v1.cmp(&v2));
}
}
Some(TermOrderCategory::Atom) => {
read_heap_cell!(v1,
(HeapCellValueTag::Atom, (n1, _a1)) => {
read_heap_cell!(v2,
(HeapCellValueTag::Atom, (n2, _a2)) => {
if n1 != n2 {
self.pdl.clear();
return Some(n1.cmp(&n2));
}
}
(HeapCellValueTag::Str, s) => {
let n2 = cell_as_atom_cell!(self.heap[s])
.get_name();
if n1 != n2 {
self.pdl.clear();
return Some(n1.cmp(&n2));
}
}
_ => {
unreachable!();
}
)
}
(HeapCellValueTag::Str, s) => {
let n1 = cell_as_atom_cell!(self.heap[s])
.get_name();
read_heap_cell!(v2,
(HeapCellValueTag::Atom, (n2, _a2)) => {
if n1 != n2 {
self.pdl.clear();
return Some(n1.cmp(&n2));
}
}
(HeapCellValueTag::Str, s) => {
let n2 = cell_as_atom_cell!(self.heap[s])
.get_name();
if n1 != n2 {
self.pdl.clear();
return Some(n1.cmp(&n2));
}
}
_ => {
unreachable!();
}
)
}
_ => {
unreachable!()
}
)
}
Some(TermOrderCategory::Compound) => {
read_heap_cell!(v1,
(HeapCellValueTag::Lis, l1) => {
read_heap_cell!(v2,
(HeapCellValueTag::PStrLoc, l2) => {
if tabu_list.contains(&(l1, l2)) {
continue;
}
tabu_list.insert((l1, l2));
// like the action of
// partial_string_to_pdl here but
// the ordering of PDL pushes is
// (crucially for comparison
// correctness) different.
let (c, succ_cell) = self.heap.last_str_char_and_tail(l2);
self.pdl.push(succ_cell);
self.pdl.push(heap_loc_as_cell!(l1 + 1));
self.pdl.push(char_as_cell!(c));
self.pdl.push(heap_loc_as_cell!(l1));
}
(HeapCellValueTag::Lis, l2) => {
if tabu_list.contains(&(l1, l2)) {
continue;
}
tabu_list.insert((l1, l2));
self.pdl.push(self.heap[l2 + 1]);
self.pdl.push(self.heap[l1 + 1]);
self.pdl.push(self.heap[l2]);
self.pdl.push(self.heap[l1]);
}
(HeapCellValueTag::Str, s2) => {
if tabu_list.contains(&(l1, s2)) {
continue;
}
let (name, arity) = cell_as_atom_cell!(self.heap[s2])
.get_name_and_arity();
match (2, atom!(".")).cmp(&(arity, name)) {
Ordering::Equal => {
tabu_list.insert((l1, s2));
self.pdl.push(self.heap[s2 + 2]);
self.pdl.push(self.heap[l1 + 1]);
self.pdl.push(self.heap[s2 + 1]);
self.pdl.push(self.heap[l1]);
}
ordering => {
self.pdl.clear();
return Some(ordering);
}
}
}
_ => {
unreachable!();
}
)
}
(HeapCellValueTag::PStrLoc, l1) => {
read_heap_cell!(v2,
(HeapCellValueTag::PStrLoc, l2) => {
if tabu_list.contains(&(l1, l2)) {
continue;
}
tabu_list.insert((l1, l2));
match self.heap.compare_pstr_segments(l1, l2) {
PStrSegmentCmpResult::Continue(v1, v2) => {
self.pdl.push(v1.offset_by(l1));
self.pdl.push(v2.offset_by(l2));
}
PStrSegmentCmpResult::Less => {
self.pdl.clear();
return Some(Ordering::Less);
}
PStrSegmentCmpResult::Greater => {
self.pdl.clear();
return Some(Ordering::Greater);
}
}
}
(HeapCellValueTag::Lis, l2) => {
if tabu_list.contains(&(l1, l2)) {
continue;
}
tabu_list.insert((l1, l2));
let (c, succ_cell) = self.heap.last_str_char_and_tail(l1);
self.pdl.push(succ_cell);
self.pdl.push(heap_loc_as_cell!(l2 + 1));
self.pdl.push(char_as_cell!(c));
self.pdl.push(heap_loc_as_cell!(l2));
}
(HeapCellValueTag::Str, s2) => {
if tabu_list.contains(&(l1, s2)) {
continue;
}
tabu_list.insert((l1, s2));
let (n2, a2) = cell_as_atom_cell!(self.heap[s2])
.get_name_and_arity();
match (2, atom!(".")).cmp(&(a2,n2)) {
Ordering::Equal => {
let (c, succ_cell) = self.heap.last_str_char_and_tail(l1);
self.pdl.push(heap_loc_as_cell!(s2+2));
self.pdl.push(succ_cell);
self.pdl.push(heap_loc_as_cell!(s2+1));
self.pdl.push(char_as_cell!(c));
}
ordering => {
self.pdl.clear();
return Some(ordering);
}
}
}
_ => {
unreachable!()
}
);
}
(HeapCellValueTag::Str, s1) => {
read_heap_cell!(v2,
(HeapCellValueTag::Str, s2) => {
if tabu_list.contains(&(s1, s2)) {
continue;
}
let (n1, a1) = cell_as_atom_cell!(self.heap[s1])
.get_name_and_arity();
let (n2, a2) = cell_as_atom_cell!(self.heap[s2])
.get_name_and_arity();
match (a1,n1).cmp(&(a2, n2)) {
Ordering::Equal => {
tabu_list.insert((s1, s2));
for idx in (1 .. a1+1).rev() {
self.pdl.push(self.heap[s2+idx]);
self.pdl.push(self.heap[s1+idx]);
}
}
ordering => {
self.pdl.clear();
return Some(ordering);
}
}
}
(HeapCellValueTag::Lis, l2) => {
if tabu_list.contains(&(s1, l2)) {
continue;
}
tabu_list.insert((s1, l2));
let (n1, a1) = cell_as_atom_cell!(self.heap[s1])
.get_name_and_arity();
match (a1,n1).cmp(&(2, atom!("."))) {
Ordering::Equal => {
self.pdl.push(self.heap[l2]);
self.pdl.push(self.heap[s1+1]);
self.pdl.push(self.heap[l2+1]);
self.pdl.push(self.heap[s1+2]);
}
ordering => {
self.pdl.clear();
return Some(ordering);
}
}
}
(HeapCellValueTag::PStrLoc, l2) => {
let (n1, a1) = cell_as_atom_cell!(self.heap[s1])
.get_name_and_arity();
match (a1,n1).cmp(&(2, atom!("."))) {
Ordering::Equal => {
let (c, succ_cell) = self.heap.last_str_char_and_tail(l2);
self.pdl.push(succ_cell);
self.pdl.push(heap_loc_as_cell!(s1+2));
self.pdl.push(char_as_cell!(c));
self.pdl.push(heap_loc_as_cell!(s1+1));
}
ordering => {
self.pdl.clear();
return Some(ordering);
}
}
}
_ => {
unreachable!()
}
)
}
_ => {
unreachable!()
}
);
}
None => {
if v1 != v2 {
self.pdl.clear();
return None;
}
}
}
}
Some(Ordering::Equal)
}
pub(crate) fn setup_call_n_init_goal_info( pub(crate) fn setup_call_n_init_goal_info(
&mut self, &mut self,
goal: HeapCellValue, goal: HeapCellValue,
@@ -891,16 +547,32 @@ impl MachineState {
} }
// returns true on failure, false on success. // returns true on failure, false on success.
pub fn eq_test(&mut self, h1: HeapCellValue, h2: HeapCellValue) -> bool { pub fn eq_test(&self, h1: HeapCellValue, h2: HeapCellValue) -> bool {
if h1 == h2 { if h1 == h2 {
return false; return false;
} }
compare_term_test!(self, h1, h2) self.compare_term_test(h1, h2)
.map(|o| o != Ordering::Equal) .map(|o| o != Ordering::Equal)
.unwrap_or(true) .unwrap_or(true)
} }
pub fn compare_term_test(&self, h1: HeapCellValue, h2: HeapCellValue) -> Option<Ordering> {
for term_pair in ParallelHeapIter::from(self, h1, h2) {
match term_pair {
TermPair::Vars(v1_offset, v2_offset) if v1_offset != v2_offset => {
return Some(v1_offset.cmp(&v2_offset));
}
TermPair::Less(..) => return Some(Ordering::Less),
TermPair::Greater(..) => return Some(Ordering::Greater),
TermPair::Unordered(cell_1, cell_2) if cell_1 != cell_2 => return None,
_ => {}
}
}
Some(Ordering::Equal)
}
#[inline(always)] #[inline(always)]
fn try_functor_compound_case(&mut self, name: Atom, arity: usize) { fn try_functor_compound_case(&mut self, name: Atom, arity: usize) {
self.try_functor_unify_components(atom_as_cell!(name), arity); self.try_functor_unify_components(atom_as_cell!(name), arity);

View File

@@ -581,56 +581,44 @@ mod tests {
}); });
assert_eq!( assert_eq!(
compare_term_test!(wam, wam.heap[0], wam.heap[1]), wam.compare_term_test(wam.heap[0], wam.heap[1]),
Some(Ordering::Less) Some(Ordering::Less)
); );
assert_eq!( assert_eq!(
compare_term_test!(wam, wam.heap[1], wam.heap[0]), wam.compare_term_test(wam.heap[1], wam.heap[0]),
Some(Ordering::Greater) Some(Ordering::Greater)
); );
assert_eq!( assert_eq!(
compare_term_test!(wam, wam.heap[0], wam.heap[0]), wam.compare_term_test(wam.heap[0], wam.heap[0]),
Some(Ordering::Equal) Some(Ordering::Equal)
); );
assert_eq!( assert_eq!(
compare_term_test!(wam, wam.heap[1], wam.heap[1]), wam.compare_term_test(wam.heap[1], wam.heap[1]),
Some(Ordering::Equal) Some(Ordering::Equal)
); );
let cstr_cell = wam.heap.allocate_cstr("string").unwrap(); let cstr_cell = wam.heap.allocate_cstr("string").unwrap();
assert_eq!( assert_eq!(
compare_term_test!(wam, atom_as_cell!(atom!("atom")), cstr_cell), wam.compare_term_test(atom_as_cell!(atom!("atom")), cstr_cell),
Some(Ordering::Less) Some(Ordering::Less)
); );
assert_eq!( assert_eq!(
compare_term_test!( wam.compare_term_test(atom_as_cell!(atom!("atom")), atom_as_cell!(atom!("atom"))),
wam,
atom_as_cell!(atom!("atom")),
atom_as_cell!(atom!("atom"))
),
Some(Ordering::Equal) Some(Ordering::Equal)
); );
assert_eq!( assert_eq!(
compare_term_test!( wam.compare_term_test(atom_as_cell!(atom!("atom")), atom_as_cell!(atom!("aaa"))),
wam,
atom_as_cell!(atom!("atom")),
atom_as_cell!(atom!("aaa"))
),
Some(Ordering::Greater) Some(Ordering::Greater)
); );
assert_eq!( assert_eq!(
compare_term_test!( wam.compare_term_test(fixnum_as_cell!(Fixnum::build_with(6)), heap_loc_as_cell!(1)),
wam,
fixnum_as_cell!(Fixnum::build_with(6)),
heap_loc_as_cell!(1)
),
Some(Ordering::Greater) Some(Ordering::Greater)
); );
@@ -644,12 +632,12 @@ mod tests {
}); });
assert_eq!( assert_eq!(
compare_term_test!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(0)), wam.compare_term_test(heap_loc_as_cell!(0), heap_loc_as_cell!(0)),
Some(Ordering::Equal) Some(Ordering::Equal)
); );
assert_eq!( assert_eq!(
compare_term_test!(wam, heap_loc_as_cell!(0), atom_as_cell!(atom!("a"))), wam.compare_term_test(heap_loc_as_cell!(0), atom_as_cell!(atom!("a"))),
Some(Ordering::Greater) Some(Ordering::Greater)
); );
@@ -676,23 +664,22 @@ mod tests {
}); });
assert_eq!( assert_eq!(
compare_term_test!(wam, heap_loc_as_cell!(7), heap_loc_as_cell!(7)), wam.compare_term_test(heap_loc_as_cell!(7), heap_loc_as_cell!(7)),
Some(Ordering::Equal) Some(Ordering::Equal)
); );
assert_eq!( assert_eq!(
compare_term_test!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(7)), wam.compare_term_test(heap_loc_as_cell!(0), heap_loc_as_cell!(7)),
Some(Ordering::Greater) Some(Ordering::Greater)
); );
assert_eq!( assert_eq!(
compare_term_test!(wam, empty_list_as_cell!(), heap_loc_as_cell!(7)), wam.compare_term_test(empty_list_as_cell!(), heap_loc_as_cell!(7)),
Some(Ordering::Less) Some(Ordering::Less)
); );
assert_eq!( assert_eq!(
compare_term_test!( wam.compare_term_test(
wam,
empty_list_as_cell!(), empty_list_as_cell!(),
fixnum_as_cell!(Fixnum::build_with(1)) fixnum_as_cell!(Fixnum::build_with(1))
), ),
@@ -702,29 +689,29 @@ mod tests {
let cstr_cell = wam.heap.allocate_cstr("string").unwrap(); let cstr_cell = wam.heap.allocate_cstr("string").unwrap();
assert_eq!( assert_eq!(
compare_term_test!(wam, empty_list_as_cell!(), cstr_cell), wam.compare_term_test(empty_list_as_cell!(), cstr_cell),
Some(Ordering::Less) Some(Ordering::Less)
); );
assert_eq!( assert_eq!(
compare_term_test!(wam, empty_list_as_cell!(), atom_as_cell!(atom!("atom"))), wam.compare_term_test(empty_list_as_cell!(), atom_as_cell!(atom!("atom"))),
Some(Ordering::Less) Some(Ordering::Less)
); );
assert_eq!( assert_eq!(
compare_term_test!(wam, atom_as_cell!(atom!("atom")), empty_list_as_cell!()), wam.compare_term_test(atom_as_cell!(atom!("atom")), empty_list_as_cell!()),
Some(Ordering::Greater) Some(Ordering::Greater)
); );
let one_p_one = HeapCellValue::from(float_alloc!(1.1, &mut wam.arena)); let one_p_one = HeapCellValue::from(float_alloc!(1.1, &mut wam.arena));
assert_eq!( assert_eq!(
compare_term_test!(wam, one_p_one, fixnum_as_cell!(Fixnum::build_with(1))), wam.compare_term_test(one_p_one, fixnum_as_cell!(Fixnum::build_with(1))),
Some(Ordering::Less) Some(Ordering::Less)
); );
assert_eq!( assert_eq!(
compare_term_test!(wam, fixnum_as_cell!(Fixnum::build_with(1)), one_p_one), wam.compare_term_test(fixnum_as_cell!(Fixnum::build_with(1)), one_p_one),
Some(Ordering::Greater) Some(Ordering::Greater)
); );
} }

View File

@@ -38,7 +38,7 @@ use rand::{Rng, SeedableRng};
use ordered_float::OrderedFloat; use ordered_float::OrderedFloat;
use fxhash::{FxBuildHasher, FxHasher}; use fxhash::{FxBuildHasher, FxHasher};
use indexmap::IndexSet; use indexmap::*;
use std::cell::Cell; use std::cell::Cell;
use std::cmp::Ordering; use std::cmp::Ordering;
@@ -574,6 +574,53 @@ pub(crate) struct FindallCopyInfo {
} }
impl MachineState { impl MachineState {
// determine whether two terms are variants, i.e. if there exists
// a bijection between their variable sets such that applying it
// to h1 produces h2 (ISO Prolog standard section 7.1.6.1).
// return true on failure and false on success.
#[inline(always)]
pub fn is_not_variant(&self) -> bool {
let h1 = self.registers[1];
let h2 = self.registers[2];
let mut a_to_b = IndexMap::with_hasher(FxBuildHasher::default());
let mut b_to_a = IndexMap::with_hasher(FxBuildHasher::default());
for term_pair in ParallelHeapIter::from(self, h1, h2) {
match term_pair {
TermPair::Vars(v1_offset, v2_offset) => {
match a_to_b.entry(v1_offset) {
indexmap::map::Entry::Occupied(stored_v2_offset) => {
if v2_offset != *stored_v2_offset.get() {
return true;
}
}
indexmap::map::Entry::Vacant(entry) => {
entry.insert_entry(v2_offset);
}
}
match b_to_a.entry(v2_offset) {
indexmap::map::Entry::Occupied(stored_v1_offset) => {
if v1_offset != *stored_v1_offset.get() {
return true;
}
}
indexmap::map::Entry::Vacant(entry) => {
entry.insert_entry(v1_offset);
}
}
}
TermPair::Less(..) => return true,
TermPair::Greater(..) => return true,
TermPair::Unordered(cell_1, cell_2) if cell_1 != cell_2 => return true,
_ => {}
}
}
false
}
fn copy_lifted_heap_from_offset(&mut self, offset: usize, lh_offset: usize) { fn copy_lifted_heap_from_offset(&mut self, offset: usize, lh_offset: usize) {
let reserve_size = self.lifted_heap.cell_len() - lh_offset; let reserve_size = self.lifted_heap.cell_len() - lh_offset;
let mut writer = step_or_resource_error!(self, self.heap.reserve(reserve_size)); let mut writer = step_or_resource_error!(self, self.heap.reserve(reserve_size));

View File

@@ -426,21 +426,6 @@ macro_rules! unify_with_occurs_check {
}}; }};
} }
macro_rules! compare_term_test {
($machine_st:expr, $e1:expr, $e2:expr) => {{
$machine_st.pdl.push($e2);
$machine_st.pdl.push($e1);
$machine_st.compare_term_test(VarComparison::Distinct)
}};
($machine_st:expr, $e1:expr, $e2:expr, $var_comparison:expr) => {{
$machine_st.pdl.push($e2);
$machine_st.pdl.push($e1);
$machine_st.compare_term_test($var_comparison)
}};
}
macro_rules! step_or_resource_error { macro_rules! step_or_resource_error {
($machine_st:expr, $val:expr) => {{ ($machine_st:expr, $val:expr) => {{
match $val { match $val {