implement new disjunction compilation

This commit is contained in:
Mark
2023-06-17 16:28:56 -06:00
parent b205abe949
commit 0e583d620a
32 changed files with 2877 additions and 2980 deletions

101
Cargo.lock generated
View File

@@ -79,6 +79,18 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitvec"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c"
dependencies = [
"funty",
"radium",
"tap",
"wyz",
]
[[package]] [[package]]
name = "blake2" name = "blake2"
version = "0.8.1" version = "0.8.1"
@@ -536,6 +548,12 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
[[package]]
name = "funty"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
[[package]] [[package]]
name = "futf" name = "futf"
version = "0.1.5" version = "0.1.5"
@@ -1526,6 +1544,12 @@ dependencies = [
"proc-macro2 1.0.47", "proc-macro2 1.0.47",
] ]
[[package]]
name = "radium"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
[[package]] [[package]]
name = "radix_trie" name = "radix_trie"
version = "0.2.1" version = "0.2.1"
@@ -1856,6 +1880,7 @@ dependencies = [
"assert_cmd", "assert_cmd",
"base64", "base64",
"bit-set", "bit-set",
"bitvec",
"blake2 0.8.1", "blake2 0.8.1",
"chrono", "chrono",
"cpu-time", "cpu-time",
@@ -2203,6 +2228,12 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "tap"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
[[package]] [[package]]
name = "tempfile" name = "tempfile"
version = "3.3.0" version = "3.3.0"
@@ -2592,21 +2623,6 @@ dependencies = [
"windows_x86_64_msvc 0.36.1", "windows_x86_64_msvc 0.36.1",
] ]
[[package]]
name = "windows-sys"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc 0.42.0",
"windows_i686_gnu 0.42.0",
"windows_i686_msvc 0.42.0",
"windows_x86_64_gnu 0.42.0",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc 0.42.0",
]
[[package]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.42.0" version = "0.42.0"
@@ -2628,24 +2644,12 @@ version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
[[package]]
name = "windows_aarch64_msvc"
version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
[[package]] [[package]]
name = "windows_aarch64_msvc" name = "windows_aarch64_msvc"
version = "0.36.1" version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
[[package]] [[package]]
name = "windows_aarch64_msvc" name = "windows_aarch64_msvc"
version = "0.42.1" version = "0.42.1"
@@ -2658,12 +2662,6 @@ version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
[[package]]
name = "windows_i686_gnu"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
[[package]] [[package]]
name = "windows_i686_gnu" name = "windows_i686_gnu"
version = "0.42.1" version = "0.42.1"
@@ -2676,12 +2674,6 @@ version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
[[package]]
name = "windows_i686_msvc"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
[[package]] [[package]]
name = "windows_i686_msvc" name = "windows_i686_msvc"
version = "0.42.1" version = "0.42.1"
@@ -2694,18 +2686,6 @@ version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
[[package]] [[package]]
name = "windows_x86_64_gnu" name = "windows_x86_64_gnu"
version = "0.42.1" version = "0.42.1"
@@ -2714,9 +2694,9 @@ checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
[[package]] [[package]]
name = "windows_x86_64_gnullvm" name = "windows_x86_64_gnullvm"
version = "0.42.1" version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
[[package]] [[package]]
name = "windows_x86_64_msvc" name = "windows_x86_64_msvc"
@@ -2724,18 +2704,21 @@ version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
[[package]] [[package]]
name = "windows_x86_64_msvc" name = "windows_x86_64_msvc"
version = "0.42.1" version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
[[package]]
name = "wyz"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
dependencies = [
"tap",
]
[[package]] [[package]]
name = "xmlparser" name = "xmlparser"
version = "0.13.5" version = "0.13.5"

View File

@@ -28,6 +28,7 @@ walkdir = "2"
[dependencies] [dependencies]
bit-set = "0.5.3" bit-set = "0.5.3"
bitvec = "1"
cpu-time = "1.0.0" cpu-time = "1.0.0"
crossterm = "0.20.0" crossterm = "0.20.0"
dirs-next = "2.0.0" dirs-next = "2.0.0"

File diff suppressed because it is too large Load Diff

View File

@@ -1,10 +1,7 @@
use crate::parser::ast::*; use crate::parser::ast::*;
use crate::temp_v;
use crate::fixtures::*;
use crate::forms::*; use crate::forms::*;
use crate::instructions::*; use crate::instructions::*;
use crate::machine::machine_indices::*;
use crate::targets::*; use crate::targets::*;
use std::cell::Cell; use std::cell::Cell;
@@ -16,7 +13,7 @@ pub(crate) trait Allocator {
&mut self, &mut self,
lvl: Level, lvl: Level,
context: GenContext, context: GenContext,
code: &mut Code, code: &mut CodeDeque,
); );
fn mark_non_var<'a, Target: CompilationTarget<'a>>( fn mark_non_var<'a, Target: CompilationTarget<'a>>(
@@ -24,40 +21,44 @@ pub(crate) trait Allocator {
lvl: Level, lvl: Level,
context: GenContext, context: GenContext,
cell: &'a Cell<RegType>, cell: &'a Cell<RegType>,
code: &mut Code, code: &mut CodeDeque,
); );
fn mark_reserved_var<'a, Target: CompilationTarget<'a>>( fn mark_reserved_var<'a, Target: CompilationTarget<'a>>(
&mut self, &mut self,
var_name: Var, var_num: usize,
lvl: Level, lvl: Level,
cell: &'a Cell<VarReg>, cell: &'a Cell<VarReg>,
term_loc: GenContext, term_loc: GenContext,
code: &mut Code, code: &mut CodeDeque,
r: RegType, r: RegType,
is_new_var: bool, is_new_var: bool,
); );
fn mark_cut_var(&mut self, var_num: usize, chunk_num: usize) -> RegType;
fn mark_var<'a, Target: CompilationTarget<'a>>( fn mark_var<'a, Target: CompilationTarget<'a>>(
&mut self, &mut self,
var_name: Var, var_num: usize,
lvl: Level, lvl: Level,
cell: &'a Cell<VarReg>, cell: &'a Cell<VarReg>,
context: GenContext, context: GenContext,
code: &mut Code, code: &mut CodeDeque,
); );
fn reset(&mut self); fn reset(&mut self);
fn reset_contents(&mut self) {}
fn reset_arg(&mut self, arg_num: usize); fn reset_arg(&mut self, arg_num: usize);
fn reset_at_head(&mut self, args: &Vec<Term>); fn reset_at_head(&mut self, args: &Vec<Term>);
fn reset_contents(&mut self);
fn advance_arg(&mut self); fn advance_arg(&mut self);
/*
fn bindings(&self) -> &AllocVarDict; fn bindings(&self) -> &AllocVarDict;
fn bindings_mut(&mut self) -> &mut AllocVarDict; fn bindings_mut(&mut self) -> &mut AllocVarDict;
fn take_bindings(self) -> AllocVarDict; fn take_bindings(self) -> AllocVarDict;
*/
fn max_reg_allocated(&self) -> usize; fn max_reg_allocated(&self) -> usize;
// TODO: wha.. why?? grrr. it drains the VarStatus data from vs (which it owns!) // TODO: wha.. why?? grrr. it drains the VarStatus data from vs (which it owns!)
@@ -87,21 +88,4 @@ pub(crate) trait Allocator {
perm_vs perm_vs
} }
*/ */
fn get(&self, var: Var) -> RegType {
self.bindings()
.get(&var)
.map_or(temp_v!(0), |v| v.as_reg_type())
}
fn is_unbound(&self, var: Var) -> bool {
self.get(var).reg_num() == 0
}
fn record_register(&mut self, var: Var, r: RegType) {
match self.bindings_mut().get_mut(&var).unwrap() {
&mut VarAlloc::Temp(_, ref mut s, _) => *s = r.reg_num(),
&mut VarAlloc::Perm(ref mut s) => *s = r.reg_num(),
}
}
} }

View File

@@ -52,7 +52,7 @@ pub(crate) struct ArithInstructionIterator<'a> {
state_stack: Vec<TermIterState<'a>>, state_stack: Vec<TermIterState<'a>>,
} }
pub(crate) type ArithCont = (Code, Option<ArithmeticTerm>); pub(crate) type ArithCont = (CodeDeque, Option<ArithmeticTerm>);
impl<'a> ArithInstructionIterator<'a> { impl<'a> ArithInstructionIterator<'a> {
fn push_subterm(&mut self, lvl: Level, term: &'a Term) { fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
@@ -73,7 +73,7 @@ impl<'a> ArithInstructionIterator<'a> {
2, 2,
)) ))
} }
Term::Var(cell, var) => TermIterState::Var(Level::Shallow, cell, VarPtr::from(var)), Term::Var(cell, var_ptr) => TermIterState::Var(Level::Shallow, cell, var_ptr.clone()),
}; };
Ok(ArithInstructionIterator { Ok(ArithInstructionIterator {
@@ -86,7 +86,7 @@ impl<'a> ArithInstructionIterator<'a> {
pub(crate) enum ArithTermRef<'a> { pub(crate) enum ArithTermRef<'a> {
Literal(&'a Literal), Literal(&'a Literal),
Op(Atom, usize), // name, arity. Op(Atom, usize), // name, arity.
Var(Level, &'a Cell<VarReg>, Var), Var(Level, &'a Cell<VarReg>, VarPtr),
} }
impl<'a> Iterator for ArithInstructionIterator<'a> { impl<'a> Iterator for ArithInstructionIterator<'a> {
@@ -114,8 +114,8 @@ impl<'a> Iterator for ArithInstructionIterator<'a> {
} }
} }
TermIterState::Literal(_, _, c) => return Some(Ok(ArithTermRef::Literal(c))), TermIterState::Literal(_, _, c) => return Some(Ok(ArithTermRef::Literal(c))),
TermIterState::Var(lvl, cell, var_ref) => { TermIterState::Var(lvl, cell, var_ptr) => {
return Some(Ok(ArithTermRef::Var(lvl, cell, Var::from(var_ref)))); return Some(Ok(ArithTermRef::Var(lvl, cell, var_ptr)));
} }
_ => { _ => {
return Some(Err(ArithmeticError::NonEvaluableFunctor( return Some(Err(ArithmeticError::NonEvaluableFunctor(
@@ -307,43 +307,48 @@ impl<'a> ArithmeticEvaluator<'a> {
term_loc: GenContext, term_loc: GenContext,
arg: usize, arg: usize,
) -> Result<ArithCont, ArithmeticError> { ) -> Result<ArithCont, ArithmeticError> {
let mut code = vec![]; let mut code = CodeDeque::new();
let mut iter = src.iter()?; let mut iter = src.iter()?;
while let Some(term_ref) = iter.next() { while let Some(term_ref) = iter.next() {
match term_ref? { match term_ref? {
ArithTermRef::Literal(c) => push_literal(&mut self.interm, c)?, ArithTermRef::Literal(c) => push_literal(&mut self.interm, c)?,
ArithTermRef::Var(lvl, cell, name) => { ArithTermRef::Var(lvl, cell, name) => {
let var_num = name.to_var_num().unwrap();
let r = if lvl == Level::Shallow { let r = if lvl == Level::Shallow {
self.marker.mark_non_callable( self.marker.mark_non_callable(
name, var_num,
arg, arg,
term_loc, term_loc,
cell, cell,
&mut code, &mut code,
) )
} else if term_loc.is_last() || cell.get().norm().reg_num() == 0 { } else if term_loc.is_last() || cell.get().norm().reg_num() == 0 {
if let Some(r) = self.marker.get_binding(&name) { let r = self.marker.get_binding(var_num);
r
} else { if r.reg_num() == 0 {
self.marker.mark_var::<QueryInstruction>( self.marker.mark_var::<QueryInstruction>(
name.clone(), var_num,
lvl, lvl,
cell, cell,
term_loc, term_loc,
&mut code, &mut code,
); );
} else {
self.marker.get_binding(&name).unwrap() self.marker.increment_running_count(var_num);
} }
r
} else { } else {
self.marker.increment_running_count(var_num);
cell.get().norm() cell.get().norm()
}; };
self.interm.push(ArithmeticTerm::Reg(r)); self.interm.push(ArithmeticTerm::Reg(r));
} }
ArithTermRef::Op(name, arity) => { ArithTermRef::Op(name, arity) => {
code.push(self.instr_from_clause(name, arity)?); code.push_back(self.instr_from_clause(name, arity)?);
} }
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,42 +1,179 @@
use indexmap::IndexMap;
use crate::allocator::*; use crate::allocator::*;
use crate::fixtures::*; use crate::codegen::SubsumedBranchHits;
use crate::forms::Level; use crate::forms::Level;
use crate::instructions::*; use crate::instructions::*;
use crate::machine::machine_indices::*; use crate::machine::disjuncts::VarData;
use crate::parser::ast::*; use crate::parser::ast::*;
use crate::targets::*; use crate::targets::*;
use crate::variable_records::*;
use crate::temp_v; use bit_set::*;
use bitvec::prelude::*;
use fxhash::FxBuildHasher; use fxhash::FxBuildHasher;
use indexmap::IndexMap;
use std::cell::Cell; use std::cell::Cell;
use std::collections::BTreeSet; use std::collections::VecDeque;
pub type BranchHits = IndexMap<usize, BitVec, FxBuildHasher>; // key: var_num, value: branch arm occurrences.
#[derive(Debug, Default)]
pub struct BranchOccurrences {
pub hits: BranchHits,
pub shallow_safety: BitSet<usize>, // unset means safe, set means unsafe (after the branch merge)
pub deep_safety: BitSet<usize>,
pub num_branches: usize,
pub current_branch: usize,
pub subsumed_hits: SubsumedBranchHits,
}
impl BranchOccurrences {
fn new(num_branches: usize) -> Self {
Self {
hits: BranchHits::with_hasher(FxBuildHasher::default()),
shallow_safety: BitSet::default(),
deep_safety: BitSet::default(),
num_branches,
current_branch: 0,
subsumed_hits: SubsumedBranchHits::with_hasher(FxBuildHasher::default()),
}
}
}
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct DebrayAllocator { pub(crate) struct DebrayAllocator {
bindings: IndexMap<Var, VarAlloc, FxBuildHasher>, pub(crate) var_data: VarData, // var_data replaces bindings.
pub(crate) branch_stack: Vec<BranchOccurrences>,
pub(crate) in_tail_position: bool,
// bindings: IndexMap<usize, VarWitness, FxBuildHasher>, // VarNum -> VarWitness
arg_c: usize, arg_c: usize,
temp_lb: usize, temp_lb: usize,
perm_lb: usize,
arity: usize, // 0 if not at head. arity: usize, // 0 if not at head.
contents: IndexMap<usize, Var, FxBuildHasher>, shallow_temp_mappings: IndexMap<usize, usize, FxBuildHasher>,
in_use: BTreeSet<usize>, in_use: BitSet<usize>, // deep and non-var allocations
free_list: Vec<usize>, temp_free_list: Vec<usize>,
perm_free_list: VecDeque<(usize, usize)>, // chunk_num, var_num
} }
impl DebrayAllocator { impl DebrayAllocator {
fn is_curr_arg_distinct_from(&self, var: &Var) -> bool { pub(crate) fn add_branch_occurrence(&mut self, var_num: usize) {
match self.contents.get(&self.arg_c) { if let Some(occurrences) = self.branch_stack.last_mut() {
Some(t_var) if *t_var != *var => true, debug_assert!(occurrences.current_branch < occurrences.num_branches);
let num_branches = occurrences.num_branches;
let entry = occurrences.hits.entry(var_num)
.or_insert_with(|| BitVec::repeat(false, num_branches));
entry.set(occurrences.current_branch, true);
occurrences.subsumed_hits.insert(var_num);
}
}
pub(crate) fn add_branch_stack(&mut self, num_branches: usize) {
self.branch_stack.push(BranchOccurrences::new(num_branches));
}
pub(crate) fn add_branch(&mut self) {
let branch_occurrences = self.branch_stack.last_mut().unwrap();
for var_num in branch_occurrences.subsumed_hits.drain(..) {
match &mut self.var_data.records[var_num].allocation {
VarAlloc::Perm(_, ref mut allocation) => {
match allocation {
PermVarAllocation::Done { shallow_safety, deep_safety, .. } => {
if !shallow_safety.unneeded() {
branch_occurrences.shallow_safety.insert(var_num);
}
if !deep_safety.unneeded() {
branch_occurrences.deep_safety.insert(var_num);
}
}
_ => {
unreachable!();
}
}
*allocation = PermVarAllocation::Pending;
}
_ => unreachable!(),
}
}
}
#[inline]
pub(crate) fn incr_current_branch(&mut self) {
let branch_occurrences = self.branch_stack.last_mut().unwrap();
branch_occurrences.current_branch += 1;
}
#[inline]
pub(crate) fn drain_branches(&mut self, depth: usize) -> std::vec::Drain<BranchOccurrences> {
let start_idx = self.branch_stack.len() - depth;
self.branch_stack.drain(start_idx ..)
}
pub(crate) fn pop_branch(&mut self, depth: usize, subsumed_hits: SubsumedBranchHits) {
let removed_branches = self.drain_branches(depth);
let (deep_safety, shallow_safety) = removed_branches
.into_iter()
.fold((BitSet::default(), BitSet::default()),
|(mut deep_safety, mut shallow_safety), branch_occurrences| {
deep_safety.union_with(&branch_occurrences.deep_safety);
shallow_safety.union_with(&branch_occurrences.shallow_safety);
(deep_safety, shallow_safety)
});
let (deep_safety, shallow_safety) = match self.branch_stack.last_mut() {
Some(latest_branch) => {
latest_branch.deep_safety.union_with(&deep_safety);
latest_branch.shallow_safety.union_with(&shallow_safety);
(&latest_branch.deep_safety, &latest_branch.shallow_safety)
}
None => (&deep_safety, &shallow_safety)
};
for var_num in subsumed_hits.iter().cloned() {
match &mut self.var_data.records[var_num].allocation {
VarAlloc::Perm(_, ref mut allocation) => {
let shallow_safety = VarSafetyStatus::needed_if(
shallow_safety.contains(var_num),
);
let deep_safety = VarSafetyStatus::needed_if(
deep_safety.contains(var_num),
);
*allocation = PermVarAllocation::Done { shallow_safety, deep_safety };
}
_ => unreachable!()
}
}
if self.branch_stack.len() > 0 {
for var_num in subsumed_hits {
self.add_branch_occurrence(var_num);
}
}
}
fn is_curr_arg_distinct_from(&self, var_num: usize) -> bool {
match self.shallow_temp_mappings.get(&self.arg_c).cloned() {
Some(t_var) => t_var != var_num,
_ => false, _ => false,
} }
} }
fn occurs_shallowly_in_head(&self, var: &Var, r: usize) -> bool { fn occurs_shallowly_in_head(&self, var_num: usize, r: usize) -> bool {
match self.bindings.get(var).unwrap() { match &self.var_data.records[var_num].allocation {
&VarAlloc::Temp(_, _, ref tvd) => tvd.use_set.contains(&(GenContext::Head, r)), VarAlloc::Temp { temp_var_data, term_loc: GenContext::Head, .. } => {
temp_var_data.use_set.contains(&(GenContext::Head, r))
}
_ => false, _ => false,
} }
} }
@@ -44,13 +181,13 @@ impl DebrayAllocator {
#[inline] #[inline]
fn is_in_use(&self, r: usize) -> bool { fn is_in_use(&self, r: usize) -> bool {
let in_use_range = r <= self.arity && r >= self.arg_c; let in_use_range = r <= self.arity && r >= self.arg_c;
in_use_range || self.in_use.contains(&r) in_use_range || self.in_use.contains(r)
} }
fn alloc_with_cr(&self, var: &Var) -> usize { fn alloc_with_cr(&self, var_num: usize) -> usize {
match self.bindings.get(var) { match &self.var_data.records[var_num].allocation {
Some(&VarAlloc::Temp(_, _, ref tvd)) => { VarAlloc::Temp { temp_var_data, .. } => {
for &(_, reg) in tvd.use_set.iter() { for &(_, reg) in temp_var_data.use_set.iter() {
if !self.is_in_use(reg) { if !self.is_in_use(reg) {
return reg; return reg;
} }
@@ -60,7 +197,7 @@ impl DebrayAllocator {
for reg in self.temp_lb.. { for reg in self.temp_lb.. {
if !self.is_in_use(reg) { if !self.is_in_use(reg) {
if !tvd.no_use_set.contains(&reg) { if !temp_var_data.no_use_set.contains(reg) {
result = reg; result = reg;
break; break;
} }
@@ -73,10 +210,10 @@ impl DebrayAllocator {
} }
} }
fn alloc_with_ca(&self, var: &Var) -> usize { fn alloc_with_ca(&self, var_num: usize) -> usize {
match self.bindings.get(var) { match &self.var_data.records[var_num].allocation {
Some(&VarAlloc::Temp(_, _, ref tvd)) => { VarAlloc::Temp { temp_var_data, .. } => {
for &(_, reg) in tvd.use_set.iter() { for &(_, reg) in temp_var_data.use_set.iter() {
if !self.is_in_use(reg) { if !self.is_in_use(reg) {
return reg; return reg;
} }
@@ -86,8 +223,8 @@ impl DebrayAllocator {
for reg in self.temp_lb.. { for reg in self.temp_lb.. {
if !self.is_in_use(reg) { if !self.is_in_use(reg) {
if !tvd.no_use_set.contains(&reg) { if !temp_var_data.no_use_set.contains(reg) {
if !tvd.conflict_set.contains(&reg) { if !temp_var_data.conflict_set.contains(reg) {
result = reg; result = reg;
break; break;
} }
@@ -101,22 +238,25 @@ impl DebrayAllocator {
} }
} }
fn alloc_in_last_goal_hint(&self, chunk_num: usize) -> Option<(Var, usize)> { fn alloc_in_last_goal_hint(&self, chunk_num: usize) -> Option<(usize, usize)> {
// we want to allocate a register to the k^{th} parameter, par_k. // we want to allocate a register to the k^{th} parameter, par_k.
// par_k may not be a temporary variable. // par_k may not be a temporary variable.
let k = self.arg_c; let k = self.arg_c;
match self.contents.get(&k) { match self.shallow_temp_mappings.get(&k).cloned() {
Some(t_var) => { Some(t_var) => {
// suppose this branch fires. then t_var is a // suppose this branch fires. then t_var is a
// temp. var. belonging to the current chunk. // temp. var. belonging to the current chunk.
// consider its use set. T == par_k iff // consider its use set. T == par_k iff
// (GenContext::Last(_), k) is in t_var.use_set. // (GenContext::Last(_), k) is in t_var.use_set.
let tvd = self.bindings.get(t_var).unwrap(); match &self.var_data.records[t_var].allocation {
if let &VarAlloc::Temp(_, _, ref tvd) = tvd { VarAlloc::Temp { temp_var_data, .. } => {
if !tvd.use_set.contains(&(GenContext::Last(chunk_num), k)) { if !temp_var_data.use_set.contains(&(GenContext::Last(chunk_num), k)) {
return Some((t_var.clone(), self.alloc_with_ca(t_var))); return Some((t_var, self.alloc_with_ca(t_var)));
}
}
_ => {
} }
} }
@@ -129,21 +269,21 @@ impl DebrayAllocator {
fn evacuate_arg<'a, Target: CompilationTarget<'a>>( fn evacuate_arg<'a, Target: CompilationTarget<'a>>(
&mut self, &mut self,
chunk_num: usize, chunk_num: usize,
code: &mut Code, code: &mut CodeDeque,
) { ) {
match self.alloc_in_last_goal_hint(chunk_num) { match self.alloc_in_last_goal_hint(chunk_num) {
Some((var, r)) => { Some((var_num, r)) => {
let k = self.arg_c; let k = self.arg_c;
if r != k { if r != k {
let r = RegType::Temp(r); let r = RegType::Temp(r);
code.push(Target::move_to_register(r, k)); code.push_back(Target::move_to_register(r, k));
self.contents.swap_remove(&k); self.shallow_temp_mappings.swap_remove(&k);
self.contents.insert(r.reg_num(), var.clone()); self.shallow_temp_mappings.insert(r.reg_num(), var_num);
self.record_register(var, r); self.var_data.records[var_num].allocation.set_register(r.reg_num());
self.in_use.insert(r.reg_num()); self.in_use.insert(r.reg_num());
} }
} }
@@ -153,27 +293,27 @@ impl DebrayAllocator {
fn alloc_reg_to_var<'a, Target: CompilationTarget<'a>>( fn alloc_reg_to_var<'a, Target: CompilationTarget<'a>>(
&mut self, &mut self,
var: &Var, var_num: usize,
lvl: Level, lvl: Level,
term_loc: GenContext, term_loc: GenContext,
target: &mut Vec<Instruction>, target: &mut CodeDeque,
) -> usize { ) -> usize {
match term_loc { match term_loc {
GenContext::Head => { GenContext::Head => {
if let Level::Shallow = lvl { if let Level::Shallow = lvl {
self.evacuate_arg::<Target>(0, target); self.evacuate_arg::<Target>(0, target);
self.alloc_with_cr(var) self.alloc_with_cr(var_num)
} else { } else {
self.alloc_with_ca(var) self.alloc_with_ca(var_num)
} }
} }
GenContext::Mid(_) => self.alloc_with_ca(var), GenContext::Mid(_) => self.alloc_with_ca(var_num),
GenContext::Last(chunk_num) => { GenContext::Last(chunk_num) => {
if let Level::Shallow = lvl { if let Level::Shallow = lvl {
self.evacuate_arg::<Target>(chunk_num, target); self.evacuate_arg::<Target>(chunk_num, target);
self.alloc_with_cr(var) self.alloc_with_cr(var_num)
} else { } else {
self.alloc_with_ca(var) self.alloc_with_ca(var_num)
} }
} }
} }
@@ -182,15 +322,15 @@ impl DebrayAllocator {
fn alloc_reg_to_non_var(&mut self) -> usize { fn alloc_reg_to_non_var(&mut self) -> usize {
let mut final_index = 0; let mut final_index = 0;
while let Some(r) = self.free_list.pop() { while let Some(r) = self.temp_free_list.pop() {
if !self.in_use.contains(&r) { if !self.is_in_use(r) {
self.in_use.insert(r); self.in_use.insert(r);
return r; return r;
} }
} }
for index in self.temp_lb.. { for index in self.temp_lb.. {
if !self.in_use.contains(&index) { if !self.in_use.contains(index) {
final_index = index; final_index = index;
self.in_use.insert(final_index); self.in_use.insert(final_index);
break; break;
@@ -201,38 +341,194 @@ impl DebrayAllocator {
final_index final_index
} }
fn in_place(&self, var: &Var, term_loc: GenContext, r: RegType, k: usize) -> bool { fn in_place(&self, var_num: usize, term_loc: GenContext, r: RegType, k: usize) -> bool {
match term_loc { match term_loc {
GenContext::Head if !r.is_perm() => r.reg_num() == k, GenContext::Head if !r.is_perm() => r.reg_num() == k,
_ => match self.bindings().get(var).unwrap() { _ => {
&VarAlloc::Temp(_, o, _) if r.reg_num() == k => o == k, match &self.var_data.records[var_num].allocation {
_ => false, &VarAlloc::Temp { temp_reg, .. } if r.reg_num() == k =>
temp_reg == k,
_ => false,
}
}, },
} }
} }
fn alloc_perm_var(&mut self, var_num: usize, chunk_num: usize) -> usize {
let p = if let Some(p) = self.pop_free_perm(chunk_num) {
p
} else {
let p = self.perm_lb;
self.perm_lb += 1;
p
};
self.var_data.records[var_num].allocation = VarAlloc::Perm(p, PermVarAllocation::done());
p
}
pub fn add_to_free_list(&mut self, r: RegType) { pub fn add_to_free_list(&mut self, r: RegType) {
if let RegType::Temp(r) = r { if let RegType::Temp(r) = r {
self.in_use.remove(&r); self.in_use.remove(r);
self.free_list.push(r); self.temp_free_list.push(r);
} }
} }
pub fn reset_free_list(&mut self) { pub fn reset_free_list(&mut self) {
self.free_list.clear(); self.temp_free_list.clear();
}
#[inline(always)]
pub fn get_binding(&self, var_num: usize) -> RegType {
self.var_data.records[var_num].allocation.as_reg_type()
}
pub fn num_perm_vars(&self) -> usize {
self.perm_lb - 1
}
pub fn increment_running_count(&mut self, var_num: usize) {
self.var_data.records[var_num].running_count += 1;
}
fn pop_free_perm(&mut self, chunk_num: usize) -> Option<usize> {
if let Some((perm_chunk_num, var_num)) = self.perm_free_list.front().cloned() {
if chunk_num == perm_chunk_num {
None
} else {
self.perm_free_list.pop_front();
match &mut self.var_data.records[var_num].allocation {
&mut VarAlloc::Perm(p, ref mut allocation) => {
*allocation = PermVarAllocation::Pending;
Some(p)
}
_ => unreachable!()
}
}
} else {
None
}
}
pub(crate) fn mark_temp_to_safe_perm(&mut self, var_num: usize) {
match &self.var_data.records[var_num].allocation {
&VarAlloc::Temp { to_perm_var_num: Some(perm_var_num), .. } => {
match &mut self.var_data.records[perm_var_num].allocation {
VarAlloc::Perm(_, PermVarAllocation::Done { deep_safety, shallow_safety, .. }) => {
*deep_safety = VarSafetyStatus::Unneeded;
*shallow_safety = VarSafetyStatus::Unneeded;
}
_ => unreachable!()
}
}
_ => {
}
}
}
fn mark_safe_var(&mut self, var_num: usize, lvl: Level, term_loc: GenContext) {
match &mut self.var_data.records[var_num].allocation {
VarAlloc::Perm(_, PermVarAllocation::Done { deep_safety, shallow_safety, .. }) => {
// GetVariable in head chunk is considered safe.
if lvl == Level::Deep {
*deep_safety = VarSafetyStatus::Unneeded;
*shallow_safety = VarSafetyStatus::Unneeded;
} else if term_loc == GenContext::Head {
*shallow_safety = VarSafetyStatus::Unneeded;
} else {
if let Some(temp_var_num) = self.shallow_temp_mappings.get(&self.arg_c).cloned() {
match &mut self.var_data.records[temp_var_num].allocation {
VarAlloc::Temp { ref mut to_perm_var_num, .. } => {
*to_perm_var_num = Some(var_num);
}
_ => unreachable!()
}
}
}
}
VarAlloc::Temp { ref mut safety, .. } => {
*safety = VarSafetyStatus::Unneeded;
}
_ => {
unreachable!()
}
}
}
fn argument_to_value<'a, Target: CompilationTarget<'a>>(
&mut self,
var_num: usize,
r: RegType,
arg_c: usize,
) -> Instruction {
match &mut self.var_data.records[var_num].allocation {
VarAlloc::Perm(_, PermVarAllocation::Done { ref mut shallow_safety, .. }) => {
if !self.in_tail_position || shallow_safety.unneeded() {
Target::argument_to_value(r, arg_c)
} else {
*shallow_safety = VarSafetyStatus::Unneeded;
Target::unsafe_argument_to_value(r, arg_c)
}
}
VarAlloc::Temp { ref mut safety, .. } => {
if safety.unneeded() {
Target::argument_to_value(r, arg_c)
} else {
*safety = VarSafetyStatus::Unneeded;
Target::unsafe_argument_to_value(r, arg_c)
}
}
_ => {
unreachable!()
}
}
}
fn subterm_to_value<'a, Target: CompilationTarget<'a>>(
&mut self,
var_num: usize,
r: RegType,
) -> Instruction {
match &mut self.var_data.records[var_num].allocation {
VarAlloc::Perm(_, PermVarAllocation::Done { ref mut deep_safety, .. }) => {
if deep_safety.unneeded() {
Target::subterm_to_value(r)
} else {
*deep_safety = VarSafetyStatus::Unneeded;
Target::unsafe_subterm_to_value(r)
}
}
VarAlloc::Temp { ref mut safety, .. } => {
if safety.unneeded() {
Target::subterm_to_value(r)
} else {
*safety = VarSafetyStatus::Unneeded;
Target::unsafe_subterm_to_value(r)
}
}
_ => {
unreachable!()
}
}
} }
} }
impl Allocator for DebrayAllocator { impl Allocator for DebrayAllocator {
fn new() -> DebrayAllocator { fn new() -> DebrayAllocator {
DebrayAllocator { Self {
var_data: VarData::default(),
in_tail_position: false,
arity: 0, arity: 0,
arg_c: 1, arg_c: 1,
temp_lb: 1, temp_lb: 1,
bindings: IndexMap::with_hasher(FxBuildHasher::default()), perm_lb: 1,
contents: IndexMap::with_hasher(FxBuildHasher::default()), shallow_temp_mappings: IndexMap::with_hasher(FxBuildHasher::default()),
in_use: BTreeSet::new(), in_use: BitSet::default(),
free_list: vec![], temp_free_list: vec![],
perm_free_list: VecDeque::new(),
branch_stack: vec![],
} }
} }
@@ -240,12 +536,12 @@ impl Allocator for DebrayAllocator {
&mut self, &mut self,
lvl: Level, lvl: Level,
term_loc: GenContext, term_loc: GenContext,
code: &mut Code, code: &mut CodeDeque,
) { ) {
let r = RegType::Temp(self.alloc_reg_to_non_var()); let r = RegType::Temp(self.alloc_reg_to_non_var());
match lvl { match lvl {
Level::Deep => code.push(Target::subterm_to_variable(r)), Level::Deep => code.push_back(Target::subterm_to_variable(r)),
Level::Root | Level::Shallow => { Level::Root | Level::Shallow => {
let k = self.arg_c; let k = self.arg_c;
@@ -255,7 +551,7 @@ impl Allocator for DebrayAllocator {
self.arg_c += 1; self.arg_c += 1;
code.push(Target::argument_to_variable(r, k)); code.push_back(Target::argument_to_variable(r, k));
} }
}; };
} }
@@ -265,7 +561,7 @@ impl Allocator for DebrayAllocator {
lvl: Level, lvl: Level,
term_loc: GenContext, term_loc: GenContext,
cell: &'a Cell<RegType>, cell: &'a Cell<RegType>,
code: &mut Code, code: &mut CodeDeque,
) { ) {
let r = cell.get(); let r = cell.get();
@@ -292,39 +588,49 @@ impl Allocator for DebrayAllocator {
fn mark_var<'a, Target: CompilationTarget<'a>>( fn mark_var<'a, Target: CompilationTarget<'a>>(
&mut self, &mut self,
var: Var, var_num: usize,
lvl: Level, lvl: Level,
cell: &'a Cell<VarReg>, cell: &'a Cell<VarReg>,
term_loc: GenContext, term_loc: GenContext,
code: &mut Code, code: &mut CodeDeque,
) { ) {
let (r, is_new_var) = match self.get(var.clone()) { let (r, is_new_var) = match self.get_binding(var_num) {
RegType::Temp(0) => { RegType::Temp(0) => {
// here, r is temporary *and* unassigned. let o = self.alloc_reg_to_var::<Target>(var_num, lvl, term_loc, code);
let o = self.alloc_reg_to_var::<Target>(&var, lvl, term_loc, code);
cell.set(VarReg::Norm(RegType::Temp(o))); cell.set(VarReg::Norm(RegType::Temp(o)));
(RegType::Temp(o), true) (RegType::Temp(o), true)
} }
RegType::Perm(0) => { RegType::Perm(0) => {
let pr = cell.get().norm(); let p = self.alloc_perm_var(var_num, term_loc.chunk_num());
self.record_register(var.clone(), pr); (RegType::Perm(p), true)
}
r @ RegType::Perm(_) => {
let is_new_var = match &mut self.var_data.records[var_num].allocation {
VarAlloc::Perm(_, allocation) => if allocation.pending() {
*allocation = PermVarAllocation::done();
true
} else {
false
},
_ => unreachable!(),
};
(pr, true) (r, is_new_var)
} }
r => (r, false), r => (r, false),
}; };
self.mark_reserved_var::<Target>(var, lvl, cell, term_loc, code, r, is_new_var); self.mark_reserved_var::<Target>(var_num, lvl, cell, term_loc, code, r, is_new_var);
} }
fn mark_reserved_var<'a, Target: CompilationTarget<'a>>( fn mark_reserved_var<'a, Target: CompilationTarget<'a>>(
&mut self, &mut self,
var: Var, var_num: usize,
lvl: Level, lvl: Level,
cell: &'a Cell<VarReg>, cell: &'a Cell<VarReg>,
term_loc: GenContext, term_loc: GenContext,
code: &mut Code, code: &mut CodeDeque,
r: RegType, r: RegType,
is_new_var: bool, is_new_var: bool,
) { ) {
@@ -332,86 +638,104 @@ impl Allocator for DebrayAllocator {
Level::Root | Level::Shallow => { Level::Root | Level::Shallow => {
let k = self.arg_c; let k = self.arg_c;
if self.is_curr_arg_distinct_from(&var) { if self.is_curr_arg_distinct_from(var_num) {
self.evacuate_arg::<Target>(term_loc.chunk_num(), code); self.evacuate_arg::<Target>(term_loc.chunk_num(), code);
} }
self.arg_c += 1;
cell.set(VarReg::ArgAndNorm(r, k)); cell.set(VarReg::ArgAndNorm(r, k));
if !self.in_place(&var, term_loc, r, k) { if !self.in_place(var_num, term_loc, r, k) {
if is_new_var { if is_new_var {
code.push(Target::argument_to_variable(r, k)); self.mark_safe_var(var_num, lvl, term_loc);
code.push_back(Target::argument_to_variable(r, k));
} else { } else {
code.push(Target::argument_to_value(r, k)); code.push_back(self.argument_to_value::<Target>(var_num, r, k));
} }
} }
self.arg_c += 1;
} }
Level::Deep if is_new_var => { Level::Deep if is_new_var => {
if let GenContext::Head = term_loc { if let GenContext::Head = term_loc {
if self.occurs_shallowly_in_head(&var, r.reg_num()) { if self.occurs_shallowly_in_head(var_num, r.reg_num()) {
code.push(Target::subterm_to_value(r)); code.push_back(self.subterm_to_value::<Target>(var_num, r));
} else { } else {
code.push(Target::subterm_to_variable(r)); self.mark_safe_var(var_num, lvl, term_loc);
code.push_back(Target::subterm_to_variable(r));
} }
} else { } else {
code.push(Target::subterm_to_variable(r)); self.mark_safe_var(var_num, lvl, term_loc);
code.push_back(Target::subterm_to_variable(r));
} }
} }
Level::Deep => code.push(Target::subterm_to_value(r)), Level::Deep => code.push_back(self.subterm_to_value::<Target>(var_num, r)),
}; }
let o = r.reg_num();
if !r.is_perm() { if !r.is_perm() {
let o = r.reg_num(); self.shallow_temp_mappings.insert(o, var_num);
} else if r.is_perm() && is_new_var {
self.add_branch_occurrence(var_num);
}
self.contents.insert(o, var.clone()); let record = &mut self.var_data.records[var_num];
self.record_register(var.clone(), r);
self.in_use.insert(o); record.allocation.set_register(o);
if record.running_count < record.num_occurrences {
record.running_count += 1;
} else if r.is_perm() {
match &mut self.var_data.records[var_num].allocation {
VarAlloc::Perm(_, allocation) => *allocation = PermVarAllocation::Pending,
_ => unreachable!(),
}
self.perm_free_list.push_back((term_loc.chunk_num(), var_num));
}
self.in_use.insert(o);
}
fn mark_cut_var(&mut self, var_num: usize, chunk_num: usize) -> RegType {
match self.get_binding(var_num) {
RegType::Perm(0) | RegType::Temp(0) => {
RegType::Perm(self.alloc_perm_var(var_num, chunk_num))
}
r => r,
} }
} }
fn reset(&mut self) { fn reset(&mut self) {
self.bindings.clear(); self.perm_lb = 1;
self.contents.clear(); self.shallow_temp_mappings.clear();
self.in_use.clear(); self.in_use.clear();
self.free_list.clear(); self.temp_free_list.clear();
} }
fn reset_contents(&mut self) { fn reset_contents(&mut self) {
self.contents.clear();
self.in_use.clear(); self.in_use.clear();
self.free_list.clear(); self.shallow_temp_mappings.clear();
self.temp_free_list.clear();
} }
fn advance_arg(&mut self) { fn advance_arg(&mut self) {
self.arg_c += 1; self.arg_c += 1;
} }
fn bindings(&self) -> &AllocVarDict {
&self.bindings
}
fn bindings_mut(&mut self) -> &mut AllocVarDict {
&mut self.bindings
}
fn take_bindings(self) -> AllocVarDict {
self.bindings
}
fn reset_at_head(&mut self, args: &Vec<Term>) { fn reset_at_head(&mut self, args: &Vec<Term>) {
self.reset_arg(args.len()); self.reset_arg(args.len());
self.arity = args.len(); self.arity = args.len();
for (idx, arg) in args.iter().enumerate() { for (idx, arg) in args.iter().enumerate() {
if let &Term::Var(_, ref var) = arg { if let &Term::Var(_, ref var) = arg {
let r = self.get(var.clone()); let var_num = var.to_var_num().unwrap();
let r = self.get_binding(var_num);
if !r.is_perm() && r.reg_num() == 0 { if !r.is_perm() && r.reg_num() == 0 {
self.in_use.insert(idx + 1); self.in_use.insert(idx + 1);
self.contents.insert(idx + 1, var.clone()); self.shallow_temp_mappings.insert(idx + 1, var_num);
self.record_register(var.clone(), temp_v!(idx + 1)); self.var_data.records[var_num].allocation.set_register(idx + 1);
} }
} }
} }

View File

@@ -1,342 +0,0 @@
use crate::forms::*;
use crate::instructions::*;
use crate::machine::disjuncts::ClassifyInfo;
use crate::parser::ast::*;
use bit_set::*;
use indexmap::{IndexMap, IndexSet};
pub(crate) type OccurrenceSet = IndexSet<(GenContext, usize)>;
#[derive(Debug)]
pub(crate) struct TempVarData {
pub(crate) last_term_arity: usize,
pub(crate) use_set: OccurrenceSet,
pub(crate) no_use_set: BitSet<usize>,
pub(crate) conflict_set: BitSet<usize>,
}
#[derive(Debug)]
pub(crate) struct TempVarStatus {
chunk_num: usize,
temp_var_data: TempVarData,
}
// Perm: 0 initially, a stack register once processed.
// Temp: labeled with chunk_num and temp offset (unassigned if 0).
#[derive(Debug)]
pub(crate) enum VarAlloc {
Perm(usize),
Temp(usize, usize, TempVarData),
}
impl VarAlloc {
pub(crate) fn as_reg_type(&self) -> RegType {
match self {
&VarAlloc::Temp(_, r, _) => RegType::Temp(r),
&VarAlloc::Perm(r) => RegType::Perm(r),
}
}
}
impl TempVarData {
pub(crate) fn new(last_term_arity: usize) -> Self {
TempVarData {
last_term_arity: last_term_arity,
use_set: BitSet::<usize>::new(),
no_use_set: BitSet::new(),
conflict_set: BitSet::new(),
}
}
pub(crate) fn uses_reg(&self, reg: usize) -> bool {
for &(_, nreg) in self.use_set.iter() {
if reg == nreg {
return true;
}
}
return false;
}
pub(crate) fn populate_conflict_set(&mut self) {
if self.last_term_arity > 0 {
let arity = self.last_term_arity;
let mut conflict_set: BitSet<usize> = (1..arity).collect();
for &(_, reg) in self.use_set.iter() {
conflict_set.remove(reg);
}
self.conflict_set = conflict_set;
}
}
}
#[derive(Debug)]
pub(crate) struct VariableFixtures {
temp_vars: IndexMap<usize, TempVarStatus>,
}
impl VariableFixtures {
pub(crate) fn new() -> Self {
VariableFixtures {
temp_vars: IndexMap::new(),
}
}
// computes no_use and conflict sets for all temp vars.
pub(crate) fn populate_restricting_sets(&mut self) {
// three stages:
// 1. move the use sets of each variable to a local IndexMap, use_set
// (iterate mutably, swap mutable refs).
// 2. drain use_set. For each use set of U, add into the
// no-use sets of appropriate variables T =/= U.
// 3. Move the use sets back to their original locations in the fixture.
// Compute the conflict set of u.
// 1.
let mut use_sets: IndexMap<usize, OccurrenceSet> = IndexMap::new();
for (var_gen_index, ref mut var_status) in self.temp_vars.iter_mut() {
let TempVarStatus { ref mut temp_var_data, .. } = var_status;
let mut use_set = OccurrenceSet::new();
std::mem::swap(&mut temp_var_data.use_set, &mut use_set);
use_sets.insert(var_gen_index, use_set);
}
for (u, use_set) in use_sets.drain(..) {
// 2.
for &(term_loc, reg) in use_set.iter() {
if let GenContext::Last(cn_u) = term_loc {
for (var_gen_index, ref mut var_status) in self.terms_vars.iter_mut() {
let TempVarStatus { chunk_num, ref mut temp_var_data } = var_status;
if cn_u == chunk_num && u != var_gen_index {
if !temp_var_data.uses_reg(reg) {
temp_var_data.no_use_set.insert(reg);
}
}
}
}
}
// 3.
let TempVarStatus { ref mut temp_var_data, ..} = self.temp_vars.get_mut(u).unwrap();
temp_var_data.use_set = use_set;
temp_var_data.populate_conflict_set();
}
}
fn record_temp_info(&mut self, tvd: &mut TempVarData, arg_c: usize, term_loc: GenContext) {
match term_loc {
GenContext::Head | GenContext::Last(_) => {
tvd.use_set.insert((term_loc, arg_c));
}
_ => {}
};
}
pub(crate) fn mark_temp_var(&mut self, var_info: &VarInfo) {
let chunk_num = term_loc.chunk_num();
let var = Var::from(var_info.var_ptr);
let mut status = self.temp_vars.swap_remove(&var).unwrap_or_else(|| {
TempVarStatus {
chunk_num,
temp_var_data: TempVarData::new(var_info.classify_info.arity),
}
});
if let Level::Shallow = var_info.lvl {
self.record_temp_info(&mut status, var_info.classify_info.arg_c, term_loc);
}
self.temp_vars.insert(var, status);
}
}
#[derive(Debug)]
pub(crate) struct UnsafeVarMarker {
pub(crate) unsafe_perm_vars: IndexMap<usize, usize>,
pub(crate) unsafe_temp_vars: IndexSet<usize>,
pub(crate) safe_perm_vars: IndexSet<usize>,
pub(crate) safe_temp_vars: IndexSet<usize>,
pub(crate) temp_vars_to_perm_vars: IndexMap<usize, usize>,
}
impl UnsafeVarMarker {
pub(crate) fn new() -> Self {
UnsafeVarMarker {
unsafe_perm_vars: IndexMap::new(),
unsafe_temp_vars: IndexSet::new(),
safe_perm_vars: IndexSet::new(),
safe_temp_vars: IndexSet::new(),
temp_vars_to_perm_vars: IndexMap::new(),
}
}
pub(crate) fn from_fact_vars(safe_vars: IndexSet<RegType>) -> Self {
let mut unsafe_var_marker = Self::new();
for r in safe_vars {
unsafe_var_marker.mark_var_as_safe(r);
}
unsafe_var_marker
}
fn mark_var_as_safe(&mut self, r: RegType) {
match r {
RegType::Temp(t) => {
self.safe_temp_vars.insert(t);
}
RegType::Perm(p) => {
self.safe_perm_vars.insert(p);
}
};
}
fn mark_var_as_unsafe(&mut self, r: RegType, phase: usize) {
match r {
RegType::Temp(t) => {
self.unsafe_temp_vars.insert(t);
}
RegType::Perm(p) => {
self.unsafe_perm_vars.insert(p, phase);
}
}
}
// returns true if the instruction at *query_instr cannot be
// changed by mark_unsafe_vars.
fn mark_safe_vars(&mut self, query_instr: &Instruction) -> bool {
match query_instr {
&Instruction::PutVariable(r @ RegType::Temp(_), _) |
&Instruction::SetVariable(r) => {
self.mark_var_as_safe(r);
true
}
&Instruction::PutVariable(RegType::Perm(p), t) => {
self.temp_vars_to_perm_vars.insert(t, p);
true
}
&Instruction::CallIs(RegType::Temp(t), ..) => {
if let Some(p) = self.temp_vars_to_perm_vars.get(&t) {
self.mark_var_as_safe(RegType::Perm(*p));
}
true
}
_ => false,
}
}
fn mark_phase(&mut self, query_instr: &Instruction, phase: usize) {
match query_instr {
&Instruction::PutValue(r @ RegType::Perm(_), _) |
&Instruction::SetValue(r) => {
self.mark_var_as_unsafe(r, phase);
}
_ => {}
}
}
fn mark_unsafe_perm_vars(&mut self, query_instr: &mut Instruction, phase: usize) {
match query_instr {
&mut Instruction::PutValue(RegType::Perm(p), arg)
if !self.safe_perm_vars.contains(&p) => {
if let Some(ph) = self.unsafe_perm_vars.swap_remove(&p) {
if ph == phase {
*query_instr = Instruction::PutUnsafeValue(p, arg);
self.safe_perm_vars.insert(p);
} else {
self.unsafe_perm_vars.insert(p, ph);
}
}
}
&mut Instruction::SetValue(r @ RegType::Perm(p))
if !self.safe_perm_vars.contains(&p) => {
*query_instr = Instruction::SetLocalValue(r);
self.safe_perm_vars.insert(p);
self.unsafe_perm_vars.remove(&p);
}
_ => {}
}
}
fn mark_unsafe_temp_vars(&mut self, query_instr: &mut Instruction) {
match query_instr {
&mut Instruction::SetValue(r @ RegType::Temp(t))
if !self.safe_temp_vars.contains(&t) => {
*query_instr = Instruction::SetLocalValue(r);
self.safe_temp_vars.insert(t);
self.unsafe_temp_vars.remove(&t);
}
_ => {
}
}
}
fn clear_temp_vars(&mut self) {
self.safe_temp_vars.clear();
self.unsafe_temp_vars.clear();
self.temp_vars_to_perm_vars.clear();
}
pub(crate) fn mark_unsafe_instrs(&mut self, code: &mut Code) {
if code.is_empty() {
return;
}
let mut code_index = 0;
for phase in 0.. {
while code[code_index].is_query_instr() {
let query_instr = &mut code[code_index];
if !self.mark_safe_vars(query_instr) {
self.mark_phase(query_instr, phase);
self.mark_unsafe_temp_vars(query_instr);
}
code_index += 1;
}
while code_index < code.len() && !code[code_index].is_query_instr() {
self.mark_safe_vars(&code[code_index]);
code_index += 1;
}
self.clear_temp_vars();
if code_index >= code.len() {
break;
}
}
code_index = 0;
for phase in 0.. {
while code[code_index].is_query_instr() {
let query_instr = &mut code[code_index];
self.mark_unsafe_perm_vars(query_instr, phase);
code_index += 1;
}
// ensure phase->instruction assignments match those of
// the previous for loop.
while code_index < code.len() && !code[code_index].is_query_instr() {
code_index += 1;
}
if code_index >= code.len() {
break;
}
}
}
}

View File

@@ -20,25 +20,23 @@ use std::cell::Cell;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::convert::TryFrom; use std::convert::TryFrom;
use std::fmt; use std::fmt;
use std::ops::AddAssign; use std::ops::{AddAssign, Deref, DerefMut};
use std::path::PathBuf; use std::path::PathBuf;
use crate::{is_infix, is_postfix}; use crate::{is_infix, is_postfix};
pub type PredicateKey = (Atom, usize); // name, arity. pub type PredicateKey = (Atom, usize); // name, arity.
pub type Predicate = Vec<PredicateClause>; /*
// vars of predicate, toplevel offset. Vec<Term> is always a vector // vars of predicate, toplevel offset. Vec<Term> is always a vector
// of vars (we get their adjoining cells this way). // of vars (we get their adjoining cells this way).
pub type JumpStub = Vec<Term>; pub type JumpStub = Vec<Term>;
*/
#[derive(Debug, Clone)] #[derive(Debug)]
pub enum TopLevel { pub enum TopLevel {
Fact(Fact), // Term, line_num, col_num Fact(Fact, VarData), // Term, line_num, col_num
Predicate(Predicate), Rule(Rule, VarData), // Rule, line_num, col_num
Query(Vec<QueryTerm>),
Rule(Rule), // Rule, line_num, col_num
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
@@ -79,13 +77,30 @@ pub enum CallPolicy {
Counted, Counted,
} }
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ChunkType { pub enum ChunkType {
Head, Head,
Mid, Mid,
Last, Last,
} }
#[derive(Debug)]
pub enum RootIterationPolicy {
Iterated,
NotIterated,
}
impl RootIterationPolicy {
#[inline(always)]
pub fn iterable(&self) -> bool {
if let RootIterationPolicy::Iterated = self {
true
} else {
false
}
}
}
impl ChunkType { impl ChunkType {
#[inline(always)] #[inline(always)]
pub fn to_gen_context(self, chunk_num: usize) -> GenContext { pub fn to_gen_context(self, chunk_num: usize) -> GenContext {
@@ -102,47 +117,104 @@ impl ChunkType {
} }
} }
#[derive(Debug)]
pub enum ChunkedTerms {
Branch(Vec<VecDeque<ChunkedTerms>>),
Chunk(VecDeque<QueryTerm>),
}
#[derive(Debug)]
pub struct ChunkedTermVec {
pub chunk_vec: VecDeque<ChunkedTerms>,
}
impl Deref for ChunkedTermVec {
type Target = VecDeque<ChunkedTerms>;
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.chunk_vec
}
}
impl DerefMut for ChunkedTermVec {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.chunk_vec
}
}
impl ChunkedTermVec {
#[inline]
pub fn new() -> Self {
Self { chunk_vec: VecDeque::new() }
}
pub fn reserve_branch(&mut self, capacity: usize) {
self.chunk_vec.push_back(ChunkedTerms::Branch(Vec::with_capacity(capacity)));
}
pub fn push_branch_arm(&mut self, branch: VecDeque<ChunkedTerms>) {
match self.chunk_vec.back_mut().unwrap() {
ChunkedTerms::Branch(branches) => {
branches.push(branch);
}
ChunkedTerms::Chunk(_) => {
self.chunk_vec.push_back(ChunkedTerms::Branch(vec![branch]));
}
}
}
#[inline]
pub fn add_chunk(&mut self) {
self.chunk_vec.push_back(ChunkedTerms::Chunk(VecDeque::from(vec![])));
}
pub fn push_chunk_term(&mut self, term: QueryTerm) {
match self.chunk_vec.back_mut() {
Some(ChunkedTerms::Branch(_)) => {
self.chunk_vec.push_back(ChunkedTerms::Chunk(VecDeque::from(vec![term])));
}
Some(ChunkedTerms::Chunk(chunk)) => {
chunk.push_back(term);
}
None => {
self.chunk_vec.push_back(ChunkedTerms::Chunk(VecDeque::from(vec![term])));
}
}
}
}
#[derive(Debug)] #[derive(Debug)]
pub enum QueryTerm { pub enum QueryTerm {
// register, clause type, subterms, clause call policy. // register, clause type, subterms, clause call policy.
Clause(Cell<RegType>, ClauseType, Vec<Term>, CallPolicy), Clause(Cell<RegType>, ClauseType, Vec<Term>, CallPolicy),
Fail, Fail,
GlobalCut, LocalCut(usize), // var_num
GetCutPoint(usize), GlobalCut(usize), // var_num
LocalCut(usize), GetCutPoint { var_num: usize, prev_b: bool },
Branch(Vec<Vec<QueryTerm>>), GetLevel(usize), // var_num
ChunkTypeBoundary(ChunkType),
} }
impl QueryTerm { impl QueryTerm {
pub(crate) fn set_call_policy(&mut self, cp: CallPolicy) {
match self {
&mut QueryTerm::Clause(_, _, _, ref mut clause_cp) => *clause_cp = cp,
_ => {}
}
}
pub(crate) fn arity(&self) -> usize { pub(crate) fn arity(&self) -> usize {
match self { match self {
&QueryTerm::Clause(_, _, ref subterms, ..) => subterms.len(), &QueryTerm::Clause(_, _, ref subterms, ..) => subterms.len(),
&QueryTerm::Cut | &QueryTerm::Branch(_) => 0, &QueryTerm::GetLevel(_) | &QueryTerm::GetCutPoint { .. } => 1,
&QueryTerm::IfThen(..) => 2, _ => 0,
&QueryTerm::Not(_) => 1,
} }
} }
} }
#[derive(Debug, Clone)] #[derive(Debug)]
pub struct Fact { pub struct Fact {
pub(crate) head: Term, pub(crate) head: Term,
pub(crate) var_data: VarData,
} }
#[derive(Debug, Clone)] #[derive(Debug)]
pub struct Rule { pub struct Rule {
pub(crate) head: (Atom, Vec<Term>, QueryTerm), pub(crate) head: (Atom, Vec<Term>),
pub(crate) clauses: Vec<QueryTerm>, pub(crate) clauses: ChunkedTermVec,
pub(crate) var_data: VarData,
} }
#[derive(Clone, Debug, Hash)] #[derive(Clone, Debug, Hash)]
@@ -233,29 +305,29 @@ impl ClauseInfo for Rule {
impl ClauseInfo for PredicateClause { impl ClauseInfo for PredicateClause {
fn name(&self) -> Option<Atom> { fn name(&self) -> Option<Atom> {
match self { match self {
&PredicateClause::Fact(ref term, ..) => term.name(), &PredicateClause::Fact(ref term, ..) => term.head.name(),
&PredicateClause::Rule(ref rule, ..) => rule.name(), &PredicateClause::Rule(ref rule, ..) => rule.name(),
} }
} }
fn arity(&self) -> usize { fn arity(&self) -> usize {
match self { match self {
&PredicateClause::Fact(ref term, ..) => term.arity(), &PredicateClause::Fact(ref term, ..) => term.head.arity(),
&PredicateClause::Rule(ref rule, ..) => rule.arity(), &PredicateClause::Rule(ref rule, ..) => rule.arity(),
} }
} }
} }
#[derive(Debug, Clone)] #[derive(Debug)]
pub enum PredicateClause { pub enum PredicateClause {
Fact(Fact), Fact(Fact, VarData),
Rule(Rule), Rule(Rule, VarData),
} }
impl PredicateClause { impl PredicateClause {
pub(crate) fn args(&self) -> Option<&[Term]> { pub(crate) fn args(&self) -> Option<&[Term]> {
match self { match self {
PredicateClause::Fact(term, ..) => match term { PredicateClause::Fact(term, ..) => match &term.head {
Term::Clause(_, _, args) => Some(&args), Term::Clause(_, _, args) => Some(&args),
_ => None, _ => None,
}, },

View File

@@ -424,7 +424,6 @@ mod tests {
use super::*; use super::*;
use crate::machine::mock_wam::*; use crate::machine::mock_wam::*;
#[test] #[test]
fn heap_stackless_iter_tests() { fn heap_stackless_iter_tests() {
let mut wam = MockWAM::new(); let mut wam = MockWAM::new();

View File

@@ -472,7 +472,7 @@ pub struct HCPrinter<'a, Outputter> {
state_stack: Vec<TokenOrRedirect>, state_stack: Vec<TokenOrRedirect>,
toplevel_spec: Option<DirectedOp>, toplevel_spec: Option<DirectedOp>,
last_item_idx: usize, last_item_idx: usize,
pub var_names: IndexMap<HeapCellValue, Var>, pub var_names: IndexMap<HeapCellValue, VarPtr>,
pub numbervars_offset: Integer, pub numbervars_offset: Integer,
pub numbervars: bool, pub numbervars: bool,
pub quoted: bool, pub quoted: bool,
@@ -803,7 +803,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
if let Some(var) = self.var_names.get(&addr) { if let Some(var) = self.var_names.get(&addr) {
read_heap_cell!(addr, read_heap_cell!(addr,
(HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => {
return Some(var.to_string()); return Some(var.borrow().to_string());
} }
_ => { _ => {
self.iter.push_stack(h); self.iter.push_stack(h);
@@ -847,7 +847,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
// short-circuits handle_heap_term. // short-circuits handle_heap_term.
// self.iter.pop_stack(); // self.iter.pop_stack();
let var_str = var.to_string(); let var_str = var.borrow().to_string();
push_space_if_amb!(self, &var_str, { push_space_if_amb!(self, &var_str, {
append_str!(self, &var_str); append_str!(self, &var_str);
@@ -862,7 +862,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
Some(var) => { Some(var) => {
// If the term is bound to a named variable, // If the term is bound to a named variable,
// print the variable's name to output. // print the variable's name to output.
let var_str = var.to_string(); let var_str = var.borrow().to_string();
push_space_if_amb!(self, &var_str, { push_space_if_amb!(self, &var_str, {
append_str!(self, &var_str); append_str!(self, &var_str);

View File

@@ -5,100 +5,40 @@ use crate::parser::ast::*;
use std::cell::Cell; use std::cell::Cell;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::fmt;
use std::fmt::Debug;
use std::hash::{Hash};
use std::iter::*; use std::iter::*;
use std::vec::Vec; use std::vec::Vec;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub(crate) enum VarPtr {
ToVar(std::ptr::NonNull<Var>),
InSitu(usize),
}
impl From<&Var> for VarPtr {
#[inline]
fn from(value: &Var) -> VarPtr {
unsafe {
VarPtr { ptr: std::ptr::NonNull::new_unchecked(value as *const _ as *mut _) }
}
}
}
impl From<VarPtr> for Var {
#[inline(always)]
fn from(value: VarPtr) -> Var {
match value {
VarPtr::ToPtr(ptr) => unsafe {
(*ptr.ptr.as_ptr()).clone()
},
VarPtr::InSitu(var_num) => {
Var::Generated(var_num)
}
}
}
}
impl VarPtr {
pub(crate) fn set(&mut self, value: Var) {
match self {
VarPtr::ToVar(ref mut ptr) =>
unsafe { *ptr.as_mut() = value },
VarPtr::InSitu(_) => {
}
}
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) enum TermRef<'a> { pub(crate) enum TermRef<'a> {
AnonVar(Level), AnonVar(Level),
Cut(Level),
GetLevel(Level),
Cons(Level, &'a Cell<RegType>, &'a Term, &'a Term), Cons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
Fail(Level),
Literal(Level, &'a Cell<RegType>, &'a Literal), Literal(Level, &'a Cell<RegType>, &'a Literal),
Clause(Level, &'a Cell<RegType>, Atom, &'a Vec<Term>), Clause(Level, &'a Cell<RegType>, Atom, &'a Vec<Term>),
PartialString(Level, &'a Cell<RegType>, &'a String, &'a Box<Term>), PartialString(Level, &'a Cell<RegType>, &'a String, &'a Box<Term>),
CompleteString(Level, &'a Cell<RegType>, Atom), CompleteString(Level, &'a Cell<RegType>, Atom),
Var(Level, &'a Cell<VarReg>, Var), Var(Level, &'a Cell<VarReg>, VarPtr),
InitialBranch(Level),
MiddleBranch(Level),
FinalBranch(Level),
} }
/*
impl<'a> TermRef<'a> { impl<'a> TermRef<'a> {
pub(crate) fn level(self) -> Level { pub(crate) fn level(&self) -> Level {
match self { match self {
TermRef::AnonVar(lvl) | TermRef::AnonVar(lvl) |
TermRef::Cons(lvl, ..) | TermRef::Cons(lvl, ..) |
TermRef::Cut(lvl) |
TermRef::GetLevel(lvl) |
TermRef::Literal(lvl, ..) | TermRef::Literal(lvl, ..) |
TermRef::Var(lvl, ..) | TermRef::Var(lvl, ..) |
TermRef::Clause(lvl, ..) | TermRef::Clause(lvl, ..) |
TermRef::CompleteString(lvl, ..) | TermRef::CompleteString(lvl, ..) |
TermRef::PartialString(lvl, ..) | TermRef::PartialString(lvl, ..) => *lvl,
TermRef::InitialBranch(lvl) |
TermRef::MiddleBranch(lvl) |
TermRef::FinalBranch(lvl) |
TermRef::Fail(lvl) => lvl,
} }
} }
} }
*/
#[derive(Debug)] #[derive(Debug)]
pub(crate) enum TermIterState<'a> { pub(crate) enum TermIterState<'a> {
AnonVar(Level), AnonVar(Level),
Clause(Level, usize, &'a Cell<RegType>, Atom, &'a Vec<Term>), Clause(Level, usize, &'a Cell<RegType>, Atom, &'a Vec<Term>),
Cut(Level),
Fail(Level),
GetLevel(Level),
InitialBranch(Level, &'a Vec<QueryTerm>),
MiddleBranch(Level, &'a Vec<QueryTerm>),
FinalBranch(Level, &'a Vec<QueryTerm>),
Sequence(Level, &'a Vec<QueryTerm>),
Literal(Level, &'a Cell<RegType>, &'a Literal), Literal(Level, &'a Cell<RegType>, &'a Literal),
InitialCons(Level, &'a Cell<RegType>, &'a Term, &'a Term), InitialCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
FinalCons(Level, &'a Cell<RegType>, &'a Term, &'a Term), FinalCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
@@ -125,7 +65,7 @@ impl<'a> TermIterState<'a> {
Term::CompleteString(cell, atom) => { Term::CompleteString(cell, atom) => {
TermIterState::CompleteString(lvl, cell, *atom) TermIterState::CompleteString(lvl, cell, *atom)
} }
Term::Var(cell, var) => TermIterState::Var(lvl, cell, VarPtr::from(var)), Term::Var(cell, var_ptr) => TermIterState::Var(lvl, cell, var_ptr.clone()),
} }
} }
} }
@@ -140,6 +80,7 @@ impl<'a> QueryIterator<'a> {
self.state_stack.push(TermIterState::subterm_to_state(lvl, term)); self.state_stack.push(TermIterState::subterm_to_state(lvl, term));
} }
/*
fn from_rule_head_clause(terms: &'a Vec<Term>) -> Self { fn from_rule_head_clause(terms: &'a Vec<Term>) -> Self {
let state_stack = terms let state_stack = terms
.iter() .iter()
@@ -149,6 +90,7 @@ impl<'a> QueryIterator<'a> {
QueryIterator { state_stack } QueryIterator { state_stack }
} }
*/
fn from_term(term: &'a Term) -> Self { fn from_term(term: &'a Term) -> Self {
let state = match term { let state = match term {
@@ -165,7 +107,7 @@ impl<'a> QueryIterator<'a> {
*name, *name,
terms, terms,
), ),
Term::Var(cell, var) => TermIterState::Var(Level::Root, cell, VarPtr::from(var)), Term::Var(cell, var_ptr) => TermIterState::Var(Level::Root, cell, var_ptr.clone()),
}; };
QueryIterator { QueryIterator {
@@ -181,36 +123,12 @@ impl<'a> QueryIterator<'a> {
&QueryTerm::Clause(ref cell, ref ct, ref terms, _) => { &QueryTerm::Clause(ref cell, ref ct, ref terms, _) => {
self.state_stack.push(TermIterState::Clause(lvl, 0, cell, ct.name(), terms)); self.state_stack.push(TermIterState::Clause(lvl, 0, cell, ct.name(), terms));
} }
&QueryTerm::Cut => { _ => {
self.state_stack.push(TermIterState::Cut(lvl));
}
&QueryTerm::Not(ref terms) => {
self.state_stack.push(TermIterState::Fail(lvl));
self.state_stack.push(TermIterState::Cut(lvl));
self.state_stack.push(TermIterState::Sequence(lvl, terms));
}
&QueryTerm::IfThen(ref if_terms, ref then_terms) => {
self.state_stack.push(TermIterState::Sequence(lvl, then_terms));
self.state_stack.push(TermIterState::Cut(lvl));
self.state_stack.push(TermIterState::Sequence(lvl, if_terms));
self.state_stack.push(TermIterState::GetLevel(lvl));
}
&QueryTerm::Branch(ref branches) => {
let len = branches.len();
self.state_stack.push(TermIterState::FinalBranch(lvl, &branches[len - 1]));
self.state_stack.extend(branches[1 .. len - 1]
.iter()
.rev()
.map(|t| TermIterState::MiddleBranch(lvl, t)),
);
self.state_stack.push(TermIterState::InitialBranch(lvl, &branches[0]));
} }
} }
} }
fn new(term: &'a QueryTerm) -> Self { pub fn new(term: &'a QueryTerm) -> Self {
let mut iter = QueryIterator { state_stack: vec![] }; let mut iter = QueryIterator { state_stack: vec![] };
iter.extend_state(Level::Root, term); iter.extend_state(Level::Root, term);
iter iter
@@ -273,34 +191,8 @@ impl<'a> Iterator for QueryIterator<'a> {
TermIterState::Literal(lvl, cell, constant) => { TermIterState::Literal(lvl, cell, constant) => {
return Some(TermRef::Literal(lvl, cell, constant)); return Some(TermRef::Literal(lvl, cell, constant));
} }
TermIterState::Var(lvl, cell, var) => { TermIterState::Var(lvl, cell, var_ptr) => {
return Some(TermRef::Var(lvl, cell, Var::from(var))); return Some(TermRef::Var(lvl, cell, var_ptr));
}
TermIterState::Cut(lvl) => {
return Some(TermRef::Cut(lvl));
}
TermIterState::GetLevel(lvl) => {
return Some(TermRef::GetLevel(lvl));
}
TermIterState::InitialBranch(lvl, ref branch) => {
self.state_stack.push(TermIterState::Sequence(lvl, branch));
return Some(TermRef::InitialBranch(lvl));
}
TermIterState::MiddleBranch(lvl, ref branch) => {
self.state_stack.push(TermIterState::Sequence(lvl, branch));
return Some(TermRef::MiddleBranch(lvl));
}
TermIterState::FinalBranch(lvl, ref branch) => {
self.state_stack.push(TermIterState::Sequence(lvl, branch));
return Some(TermRef::FinalBranch(lvl));
}
TermIterState::Sequence(lvl, ref terms) => {
for term in branch.iter().rev() {
self.extend_state(lvl, term);
}
}
TermIterState::Fail(lvl) => {
return Some(TermRef::Fail(lvl));
} }
}; };
} }
@@ -312,7 +204,7 @@ impl<'a> Iterator for QueryIterator<'a> {
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct FactIterator<'a> { pub(crate) struct FactIterator<'a> {
state_queue: VecDeque<TermIterState<'a>>, state_queue: VecDeque<TermIterState<'a>>,
iterable_root: bool, iterable_root: RootIterationPolicy,
} }
impl<'a> FactIterator<'a> { impl<'a> FactIterator<'a> {
@@ -329,11 +221,11 @@ impl<'a> FactIterator<'a> {
FactIterator { FactIterator {
state_queue, state_queue,
iterable_root: false, iterable_root: RootIterationPolicy::NotIterated,
} }
} }
fn new(term: &'a Term, iterable_root: bool) -> Self { fn new(term: &'a Term, iterable_root: RootIterationPolicy) -> Self {
let states = match term { let states = match term {
Term::AnonVar => { Term::AnonVar => {
vec![TermIterState::AnonVar(Level::Root)] vec![TermIterState::AnonVar(Level::Root)]
@@ -365,8 +257,8 @@ impl<'a> FactIterator<'a> {
Term::Literal(cell, constant) => { Term::Literal(cell, constant) => {
vec![TermIterState::Literal(Level::Root, cell, constant)] vec![TermIterState::Literal(Level::Root, cell, constant)]
} }
Term::Var(cell, var) => { Term::Var(cell, var_ptr) => {
vec![TermIterState::Var(Level::Root, cell, VarPtr::from(var))] vec![TermIterState::Var(Level::Root, cell, var_ptr.clone())]
} }
}; };
@@ -392,7 +284,7 @@ impl<'a> Iterator for FactIterator<'a> {
} }
match lvl { match lvl {
Level::Root if !self.iterable_root => continue, Level::Root if !self.iterable_root.iterable() => continue,
_ => return Some(TermRef::Clause(lvl, cell, name, child_terms)), _ => return Some(TermRef::Clause(lvl, cell, name, child_terms)),
}; };
} }
@@ -412,8 +304,8 @@ impl<'a> Iterator for FactIterator<'a> {
TermIterState::Literal(lvl, cell, constant) => { TermIterState::Literal(lvl, cell, constant) => {
return Some(TermRef::Literal(lvl, cell, constant)) return Some(TermRef::Literal(lvl, cell, constant))
} }
TermIterState::Var(lvl, cell, var) => { TermIterState::Var(lvl, cell, var_ptr) => {
return Some(TermRef::Var(lvl, cell, Var::from(var))); return Some(TermRef::Var(lvl, cell, var_ptr));
} }
_ => {} _ => {}
} }
@@ -427,143 +319,130 @@ pub(crate) fn post_order_iter<'a>(term: &'a Term) -> QueryIterator<'a> {
QueryIterator::from_term(term) QueryIterator::from_term(term)
} }
pub(crate) fn breadth_first_iter<'a>(term: &'a Term, iterable_root: bool) -> FactIterator<'a> { pub(crate) fn breadth_first_iter<'a>(term: &'a Term, iterable_root: RootIterationPolicy) -> FactIterator<'a> {
FactIterator::new(term, iterable_root) FactIterator::new(term, iterable_root)
} }
/* #[derive(Debug, Copy, Clone)]
enum ClauseIteratorState<'a> {
RemainingChunks(&'a VecDeque<ChunkedTerms>, usize),
RemainingBranches(&'a Vec<VecDeque<ChunkedTerms>>, usize),
}
#[derive(Debug, Clone)]
pub(crate) enum ClauseItem<'a> {
FirstBranch(usize),
NextBranch,
BranchEnd(usize),
Chunk(&'a VecDeque<QueryTerm>),
}
#[derive(Debug)] #[derive(Debug)]
pub(crate) enum ChunkedTerm<'a> { pub(crate) struct ClauseIterator<'a> {
HeadClause(Atom, &'a Vec<Term>), state_stack: Vec<ClauseIteratorState<'a>>,
BodyTerm(&'a QueryTerm), remaining_chunks_on_stack: usize,
} }
pub(crate) fn query_term_post_order_iter<'a>(query_term: &'a QueryTerm) -> QueryIterator<'a> { fn state_from_chunked_terms<'a>(chunk_vec: &'a VecDeque<ChunkedTerms>) -> ClauseIteratorState<'a> {
QueryIterator::new(query_term) if chunk_vec.len() == 1 {
} if let Some(ChunkedTerms::Branch(ref branches)) = chunk_vec.front() {
return ClauseIteratorState::RemainingBranches(branches, 0);
impl<'a> ChunkedTerm<'a> {
pub(crate) fn post_order_iter(&self) -> QueryIterator<'a> {
match self {
&ChunkedTerm::BodyTerm(qt) => QueryIterator::new(qt),
&ChunkedTerm::HeadClause(_, terms) => QueryIterator::from_rule_head_clause(terms),
} }
} }
ClauseIteratorState::RemainingChunks(chunk_vec, 0)
} }
pub(crate) struct ChunkedIterator<'a> { impl<'a> ClauseIterator<'a> {
pub(crate) chunk_num: usize, pub fn new(clauses: &'a ChunkedTermVec) -> Self {
iter: Box<dyn Iterator<Item = ChunkedTerm<'a>> + 'a>, match state_from_chunked_terms(&clauses.chunk_vec) {
} state @ ClauseIteratorState::RemainingBranches(..) => {
Self {
impl<'a> fmt::Debug for ChunkedIterator<'a> { state_stack: vec![state],
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { remaining_chunks_on_stack: 0,
fmt.debug_struct("ChunkedIterator") }
.field("chunk_num", &self.chunk_num) }
// Hacky solution. state @ ClauseIteratorState::RemainingChunks(..) => {
.field("iter", &"Box<dyn Iterator<Item = ChunkedTerm<'a>> + 'a>") Self {
.finish() state_stack: vec![state],
} remaining_chunks_on_stack: 1,
} }
type ChunkedIteratorItem<'a> = (usize, usize, Vec<ChunkedTerm<'a>>);
type RuleBodyIteratorItem<'a> = (usize, usize, Vec<&'a QueryTerm>);
impl<'a> ChunkedIterator<'a> {
pub(crate) fn rule_body_iter(self) -> Box<dyn Iterator<Item = RuleBodyIteratorItem<'a>> + 'a> {
Box::new(self.filter_map(|(cn, lt_arity, terms)| {
let filtered_terms: Vec<_> = terms
.into_iter()
.filter_map(|ct| match ct {
ChunkedTerm::BodyTerm(qt) => Some(qt),
_ => None,
})
.collect();
if filtered_terms.is_empty() {
None
} else {
Some((cn, lt_arity, filtered_terms))
} }
}))
}
pub(crate) fn from_rule_body(p1: &'a QueryTerm, clauses: &'a Vec<QueryTerm>) -> Self {
let inner_iter = Box::new(once(ChunkedTerm::BodyTerm(p1)));
let iter = inner_iter.chain(clauses.iter().map(|t| ChunkedTerm::BodyTerm(t)));
ChunkedIterator {
chunk_num: 0,
iter: Box::new(iter),
} }
} }
pub(crate) fn from_rule(rule: &'a Rule) -> Self { #[inline(always)]
let &Rule { pub fn in_tail_position(&self) -> bool {
head: (ref name, ref args, ref p1), self.remaining_chunks_on_stack == 0
ref clauses,
..
} = rule;
let iter = once(ChunkedTerm::HeadClause(name.clone(), args));
let inner_iter = Box::new(once(ChunkedTerm::BodyTerm(p1)));
let iter = iter.chain(inner_iter.chain(clauses.iter().map(|t| ChunkedTerm::BodyTerm(t))));
ChunkedIterator {
chunk_num: 0,
iter: Box::new(iter),
}
} }
fn take_chunk(&mut self, term: ChunkedTerm<'a>) -> (usize, usize, Vec<ChunkedTerm<'a>>) { fn branch_end_depth(&mut self) -> usize {
let mut arity = 0; let mut depth = 1;
let mut item = Some(term);
let mut result = Vec::new();
while let Some(term) = item { while let Some(state) = self.state_stack.pop() {
match term { match state {
ChunkedTerm::HeadClause(_, terms) => { ClauseIteratorState::RemainingBranches(terms, focus) if terms.len() == focus => {
result.push(term); depth += 1;
} }
ChunkedTerm::BodyTerm(&QueryTerm::Cut) => { _ => {
result.push(term); self.state_stack.push(state);
}
ChunkedTerm::BodyTerm(&QueryTerm::Clause(_, ClauseType::Inlined(_), ..)) => {
result.push(term);
}
ChunkedTerm::BodyTerm(&QueryTerm::Clause(
_,
ClauseType::CallN(_),
ref subterms,
_,
)) => {
result.push(term);
arity = subterms.len() + 1;
break; break;
} }
ChunkedTerm::BodyTerm(qt) => { }
result.push(term);
arity = qt.arity();
break;
}
};
item = self.iter.next();
} }
let chunk_num = self.chunk_num; depth
self.chunk_num += 1;
(chunk_num, arity, result)
} }
} }
impl<'a> Iterator for ChunkedIterator<'a> { impl<'a> Iterator for ClauseIterator<'a> {
// the chunk number, last term arity, and vector of references. type Item = ClauseItem<'a>;
type Item = ChunkedIteratorItem<'a>;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|term| self.take_chunk(term)) while let Some(state) = self.state_stack.pop() {
match state {
ClauseIteratorState::RemainingChunks(chunks, focus) if focus < chunks.len() => {
if focus + 1 < chunks.len() {
self.state_stack.push(ClauseIteratorState::RemainingChunks(chunks, focus + 1));
} else {
self.remaining_chunks_on_stack -= 1;
}
match &chunks[focus] {
ChunkedTerms::Branch(branches) => {
self.state_stack.push(ClauseIteratorState::RemainingBranches(branches, 0));
}
ChunkedTerms::Chunk(chunk) => {
return Some(ClauseItem::Chunk(chunk));
}
}
}
ClauseIteratorState::RemainingChunks(chunks, focus) => {
debug_assert_eq!(chunks.len(), focus);
}
ClauseIteratorState::RemainingBranches(branches, focus) if focus < branches.len() => {
self.state_stack.push(ClauseIteratorState::RemainingBranches(&branches, focus + 1));
let state = state_from_chunked_terms(&branches[focus]);
if let ClauseIteratorState::RemainingChunks(..) = &state {
self.remaining_chunks_on_stack += 1;
}
self.state_stack.push(state);
return if focus == 0 {
Some(ClauseItem::FirstBranch(branches.len()))
} else {
Some(ClauseItem::NextBranch)
};
}
ClauseIteratorState::RemainingBranches(branches, focus) => {
debug_assert_eq!(branches.len(), focus);
return Some(ClauseItem::BranchEnd(self.branch_end_depth()));
}
}
}
None
} }
} }
*/

View File

@@ -16,7 +16,7 @@ mod arithmetic;
pub mod codegen; pub mod codegen;
mod debray_allocator; mod debray_allocator;
mod ffi; mod ffi;
mod fixtures; mod variable_records;
mod forms; mod forms;
mod heap_iter; mod heap_iter;
pub mod heap_print; pub mod heap_print;

View File

@@ -218,13 +218,13 @@ fail :- '$fail'.
%% \+(Goal) %% \+(Goal)
% %
% True iff Goal fails % True iff Goal fails
\+ G :- call(G), !, false. \+ G :- call(G), !, '$fail'.
\+ _. \+ _.
%% \=(?X, ?Y) %% \=(?X, ?Y)
% %
% True iff X and Y can't be unified % True iff X and Y can't be unified
X \= X :- !, false. X \= X :- !, '$fail'.
_ \= _. _ \= _.

View File

@@ -513,10 +513,12 @@ portray_clause(Stream, Term) :-
phrase_to_stream(portray_clause_(Term), Stream), phrase_to_stream(portray_clause_(Term), Stream),
flush_output(Stream). flush_output(Stream).
% called once.
portray_clause_(Term) --> portray_clause_(Term) -->
{ unique_variable_names(Term, VNs) }, { unique_variable_names(Term, VNs) },
portray_(Term, VNs), ".\n". portray_(Term, VNs), ".\n".
% mysteriously called twice, the second time with the truncated B3.
unique_variable_names(Term, VNs) :- unique_variable_names(Term, VNs) :-
term_variables(Term, Vs), term_variables(Term, Vs),
foldl(var_name, Vs, VNs, 0, _). foldl(var_name, Vs, VNs, 0, _).

View File

@@ -541,6 +541,7 @@ open_file(Path, Stream) :-
) )
). ).
use_module(Module, Exports, Evacuable) :- use_module(Module, Exports, Evacuable) :-
( var(Module) -> ( var(Module) ->
instantiation_error(load/1) instantiation_error(load/1)
@@ -562,12 +563,11 @@ use_module(Module, Exports, Evacuable) :-
stream_property(Stream, file_name(PathFileName)), stream_property(Stream, file_name(PathFileName)),
file_load(Stream, PathFileName, Subevacuable), file_load(Stream, PathFileName, Subevacuable),
'$use_module'(Evacuable, Subevacuable, Exports) '$use_module'(Evacuable, Subevacuable, Exports)
; type_error(atom, Library, load/1) ; type_error(atom, Module, load/1)
) )
). ).
check_predicate_property(meta_predicate, Module, Name, Arity, MetaPredicateTerm) :- check_predicate_property(meta_predicate, Module, Name, Arity, MetaPredicateTerm) :-
'$meta_predicate_property'(Module, Name, Arity, MetaPredicateTerm). '$meta_predicate_property'(Module, Name, Arity, MetaPredicateTerm).
check_predicate_property(built_in, _, Name, Arity, built_in) :- check_predicate_property(built_in, _, Name, Arity, built_in) :-

View File

@@ -23,13 +23,9 @@ fn capture_offset(line: &Instruction, index: usize, stack: &mut Vec<usize>) -> b
{ {
stack.push(index + offset); stack.push(index + offset);
} }
&Instruction::JmpByCall(_, offset, _) => { &Instruction::JmpByCall(offset) => {
stack.push(index + offset); stack.push(index + offset);
} }
&Instruction::JmpByExecute(_, offset, _) => {
stack.push(index + offset);
return true;
}
&Instruction::Proceed => { &Instruction::Proceed => {
return true; return true;
} }

View File

@@ -44,62 +44,6 @@ pub(super) fn bootstrapping_compile(
Ok(()) Ok(())
} }
// throw errors if declaration or query found.
pub(super) fn compile_relation(
cg: &mut CodeGenerator,
tl: &TopLevel,
) -> Result<Code, CompilationError> {
match tl {
&TopLevel::Query(_) => Err(CompilationError::ExpectedRel),
&TopLevel::Predicate(ref clauses) => cg.compile_predicate(&clauses),
&TopLevel::Fact(ref fact, ..) => cg.compile_fact(fact),
&TopLevel::Rule(ref rule, ..) => cg.compile_rule(rule),
}
}
/*
pub(super) fn compile_appendix(
code: &mut Code,
mut queue: VecDeque<TopLevel>,
jmp_by_locs: Vec<usize>,
non_counted_bt: bool,
atom_tbl: &mut AtomTable,
) -> Result<(), CompilationError> {
let mut jmp_by_locs = VecDeque::from(jmp_by_locs);
while let Some(jmp_by_offset) = jmp_by_locs.pop_front() {
let code_len = code.len();
match &mut code[jmp_by_offset] {
&mut Instruction::JmpByCall(_, ref mut offset, ..) |
&mut Instruction::JmpByExecute(_, ref mut offset, ..) => {
*offset = code_len - jmp_by_offset;
}
_ => {
unreachable!()
}
}
// false because the inner predicate is a one-off, hence not extensible.
let settings = CodeGenSettings {
global_clock_tick: None,
is_extensible: false,
non_counted_bt,
};
let mut cg = CodeGenerator::new(atom_tbl, settings);
let tl = queue.pop_front().unwrap();
let decl_code = compile_relation(&mut cg, &tl)?;
jmp_by_locs.extend(cg.jmp_by_locs.into_iter().map(|offset| offset + code.len()));
code.extend(decl_code.into_iter());
}
Ok(())
}
*/
fn lower_bound_of_target_clause(skeleton: &PredicateSkeleton, target_pos: usize) -> usize { fn lower_bound_of_target_clause(skeleton: &PredicateSkeleton, target_pos: usize) -> usize {
if target_pos == 0 { if target_pos == 0 {
return 0; return 0;
@@ -1351,17 +1295,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
settings, settings,
); );
let mut clause_code = cg.compile_predicate(&vec![clause])?; let clause_code = cg.compile_predicate(vec![clause])?;
/*
compile_appendix(
&mut clause_code,
queue,
cg.jmp_by_locs,
settings.non_counted_bt,
cg.atom_tbl,
)?;
*/
Ok(StandaloneCompileResult { Ok(StandaloneCompileResult {
clause_code, clause_code,
@@ -1389,24 +1323,12 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
clauses.push(self.try_term_to_tl(term, &mut preprocessor)?); clauses.push(self.try_term_to_tl(term, &mut preprocessor)?);
} }
// let queue = preprocessor.parse_queue(self)?;
let mut cg = CodeGenerator::new( let mut cg = CodeGenerator::new(
&mut LS::machine_st(&mut self.payload).atom_tbl, &mut LS::machine_st(&mut self.payload).atom_tbl,
settings, settings,
); );
let mut code = cg.compile_predicate(&clauses)?; let mut code = cg.compile_predicate(clauses)?;
/*
compile_appendix(
&mut code,
queue,
cg.jmp_by_locs,
settings.non_counted_bt,
cg.atom_tbl,
)?;
*/
if settings.is_extensible { if settings.is_extensible {
let mut clause_clause_locs = VecDeque::new(); let mut clause_clause_locs = VecDeque::new();

View File

@@ -1,4 +1,3 @@
/* /*
================================================================================ ================================================================================
@@ -9,7 +8,6 @@ paper "Compiling Large Disjunctions" to Scryer Prolog.
*/ */
use crate::atom_table::*; use crate::atom_table::*;
use crate::fixtures::VariableFixtures;
use crate::forms::*; use crate::forms::*;
use crate::instructions::*; use crate::instructions::*;
use crate::iterators::*; use crate::iterators::*;
@@ -18,16 +16,18 @@ use crate::machine::machine_errors::CompilationError;
use crate::machine::preprocessor::*; use crate::machine::preprocessor::*;
use crate::parser::ast::*; use crate::parser::ast::*;
use crate::parser::rug::Rational; use crate::parser::rug::Rational;
use crate::variable_records::*;
use indexmap::{IndexMap, IndexSet}; use indexmap::{IndexMap, IndexSet};
use std::cell::Cell; use std::cell::Cell;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::collections::VecDeque;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
#[derive(Debug, Clone)] #[derive(Debug, Clone)] //, PartialOrd, PartialEq, Eq, Hash)]
struct BranchNumber { pub struct BranchNumber {
branch_num: Rational, branch_num: Rational,
delta: Rational, delta: Rational,
} }
@@ -35,7 +35,7 @@ struct BranchNumber {
impl Default for BranchNumber { impl Default for BranchNumber {
fn default() -> Self { fn default() -> Self {
Self { Self {
branch_num: Rational::from(1 << 63), branch_num: Rational::from(1usize << 63),
delta: Rational::from(1), delta: Rational::from(1),
} }
} }
@@ -87,9 +87,10 @@ impl BranchNumber {
} }
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct VarInfo { pub struct VarInfo {
var_ptr: VarPtr, var_ptr: VarPtr,
chunk_type: ChunkType,
classify_info: ClassifyInfo, classify_info: ClassifyInfo,
lvl: Level, lvl: Level,
} }
@@ -102,6 +103,11 @@ pub struct ChunkInfo {
vars: Vec<VarInfo>, vars: Vec<VarInfo>,
} }
#[derive(Debug)]
pub struct BranchArm {
pub arm_terms: Vec<QueryTerm>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct BranchInfo { pub struct BranchInfo {
branch_num: BranchNumber, branch_num: BranchNumber,
@@ -114,7 +120,7 @@ impl BranchInfo {
} }
} }
type BranchMapInt = IndexMap<Var, Vec<BranchInfo>>; type BranchMapInt = IndexMap<VarPtr, Vec<BranchInfo>>;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct BranchMap(BranchMapInt); pub struct BranchMap(BranchMapInt);
@@ -145,82 +151,77 @@ pub struct ClassifyInfo {
enum TraversalState { enum TraversalState {
// construct a QueryTerm::Branch with number of disjuncts, reset // construct a QueryTerm::Branch with number of disjuncts, reset
// the chunk type to that of the chunk preceding the disjunct. // the chunk type to that of the chunk preceding the disjunct and the chunk_num.
BuildDisjunct(ChunkType, usize), BuildDisjunct(usize),
// add the last disjunct to a QueryTerm::Branch, continuing from // add the last disjunct to a QueryTerm::Branch, continuing from
// where it leaves off. // where it leaves off.
BuildFinalDisjunct(usize), BuildFinalDisjunct(usize),
Fail, Fail,
GetCutPoint(usize), GetCutPoint{ var_num: usize, prev_b: bool },
LocalCut(usize), Cut { var_num: usize, is_global: bool },
ResetCallPolicy(CallPolicy), ResetCallPolicy(CallPolicy),
Term(Term), Term(Term),
AddBranchNum(BranchNumber), // set current_branch_number, add it to the root set RemoveBranchNum, // pop the current_branch_num and from the root set.
RemoveBranchNum, // remove latest branch number from the root set AddBranchNum(BranchNumber), // set current_branch_num, add it to the root set
RepBranchNum(BranchNumber), // replace current_branch_number and the latest in the root set RepBranchNum(BranchNumber), // replace current_branch_num and the latest in the root set
IncrChunkNum, // increment self.current_chunk_number // SetChunkType(ChunkType), // consider remaining terms as belonging to a last chunk
SetLastChunkType, // consider remaining terms as belonging to a last chunk
}
impl Term {
#[inline]
fn is_var(&self) -> bool {
if let Term::Var(..) = self {
true
} else {
false
}
}
#[inline]
fn is_compound(&self) -> bool {
match self {
Term::Clause(..) | Term::Cons(..) => true,
_ => false,
}
}
} }
#[derive(Debug)]
pub struct VariableClassifier { pub struct VariableClassifier {
call_policy: CallPolicy, call_policy: CallPolicy,
current_branch_num: BranchNumber, current_branch_num: BranchNumber,
current_chunk_num: usize, current_chunk_num: usize,
current_chunk_type: ChunkType,
branch_map: BranchMap, branch_map: BranchMap,
var_num: usize, var_num: usize,
root_set: RootSet, root_set: RootSet,
global_cut_var_num: Option<usize>,
} }
#[derive(Debug)] #[derive(Debug, Default)]
pub enum VarClassification { pub struct VarData {
Void, pub records: VariableRecords,
Temp, pub global_cut_var_num: Option<usize>,
Perm, pub allocates: bool,
} }
#[derive(Clone, Debug)] impl VarData {
pub struct VarRecord { fn emit_initial_get_level(&mut self, build_stack: &mut ChunkedTermVec) {
pub classification: VarClassification, let global_cut_var_num =
pub chunk_occurrences: Vec<usize>, if let &Some(global_cut_var_num) = &self.global_cut_var_num {
pub num_occurrences: usize, match &self.records[global_cut_var_num].allocation {
} VarAlloc::Perm(..) => Some(global_cut_var_num),
VarAlloc::Temp { term_loc, .. } if term_loc.chunk_num() > 0 => {
Some(global_cut_var_num)
}
_ => None
}
} else {
None
};
impl Default for VarRecord { if let Some(global_cut_var_num) = global_cut_var_num {
fn default() -> Self { let term = QueryTerm::GetLevel(global_cut_var_num);
VarRecord { self.records[global_cut_var_num].allocation = VarAlloc::Perm(0, PermVarAllocation::Pending);
classification: VarClassification::Void,
chunk_occurrences: vec![], match build_stack.front_mut() {
num_occurrences: 0, Some(ChunkedTerms::Branch(_)) => {
build_stack.push_front(ChunkedTerms::Chunk(VecDeque::from(vec![term])));
}
Some(ChunkedTerms::Chunk(chunk)) => {
chunk.push_front(term);
}
None => {
unreachable!()
}
}
} }
} }
} }
pub struct VarData {
pub records: Vec<VarRecord>,
pub fixtures: VariableFixtures,
}
pub type ClassifyFactResult = (Term, VarData); pub type ClassifyFactResult = (Term, VarData);
pub type ClassifyRuleResult = (Term, Vec<QueryTerm>, VarData); pub type ClassifyRuleResult = (Term, ChunkedTermVec, VarData);
fn merge_branch_seq<Iter: Iterator<Item = BranchInfo>>(branches: Iter) -> BranchInfo { fn merge_branch_seq<Iter: Iterator<Item = BranchInfo>>(branches: Iter) -> BranchInfo {
let mut branch_info = BranchInfo::new(BranchNumber::default()); let mut branch_info = BranchInfo::new(BranchNumber::default());
@@ -228,6 +229,7 @@ fn merge_branch_seq<Iter: Iterator<Item = BranchInfo>>(branches: Iter) -> Branch
for mut branch in branches { for mut branch in branches {
branch_info.branch_num = branch.branch_num; branch_info.branch_num = branch.branch_num;
/*
if let Some(last_chunk) = branch_info.chunks.last_mut() { if let Some(last_chunk) = branch_info.chunks.last_mut() {
if let Some(first_moved_chunk) = branch.chunks.first_mut() { if let Some(first_moved_chunk) = branch.chunks.first_mut() {
if last_chunk.chunk_num == first_moved_chunk.chunk_num { if last_chunk.chunk_num == first_moved_chunk.chunk_num {
@@ -238,6 +240,7 @@ fn merge_branch_seq<Iter: Iterator<Item = BranchInfo>>(branches: Iter) -> Branch
} }
} }
} }
*/
branch_info.chunks.extend(branch.chunks.drain(..)); branch_info.chunks.extend(branch.chunks.drain(..));
} }
@@ -248,82 +251,37 @@ fn merge_branch_seq<Iter: Iterator<Item = BranchInfo>>(branches: Iter) -> Branch
branch_info branch_info
} }
fn flatten_into_disjunct(build_stack: &mut Vec<QueryTerm>, preceding_len: usize) { fn flatten_into_disjunct(build_stack: &mut ChunkedTermVec, preceding_len: usize) {
let iter = build_stack.drain(preceding_len + 1 ..); let branch_vec = build_stack.drain(preceding_len + 1 ..).collect();
if let QueryTerm::Branch(ref mut disjuncts) = &mut build_stack[preceding_len] { if let ChunkedTerms::Branch(ref mut disjuncts) = &mut build_stack[preceding_len] {
disjuncts.push(iter.collect()); disjuncts.push(branch_vec);
} else { } else {
unreachable!(); unreachable!();
} }
} }
fn term_in_other_chunk(term: &Term) -> Option<bool> {
match term {
Term::Clause(_, name, terms) => Some(!ClauseType::is_inbuilt(*name, terms.len())),
Term::Literal(_, Literal::Atom(atom!("!")) | Literal::Char('!')) => Some(false),
Term::Literal(_, Literal::Atom(name)) => Some(!ClauseType::is_inbuilt(*name, 0)),
Term::Var(..) => Some(true),
_ => None,
}
}
// returns true if SetLastChunkType was pushed.
// expects that iter iterates over a conjunct of Terms in reverse order.
fn insert_set_last_chunk_type(
state_stack: &mut Vec<TraversalState>,
mut iter: impl Iterator<Item = TraversalState>,
) -> bool {
let beg = state_stack.len();
let mut will_break = false;
let mut last_chunk_delim = beg;
while let Some(traversal_st) = iter.next() {
match traversal_st {
TraversalState::Term(term) => {
will_break = false;
match term_in_other_chunk(&term) {
Some(true) if last_chunk_delim > beg => will_break = true,
Some(_) => last_chunk_delim += 1,
None => will_break = true,
}
if will_break {
// recall that iter iterates in reverse order.
// therefore this is the correct push order.
state_stack.push(TraversalState::SetLastChunkType);
state_stack.push(traversal_st);
break;
}
}
_ => {
state_stack.push(traversal_st);
}
}
}
state_stack.extend(iter);
will_break
}
impl VariableClassifier { impl VariableClassifier {
pub fn new(call_policy: CallPolicy) -> Self { pub fn new(call_policy: CallPolicy) -> Self {
Self { Self {
call_policy, call_policy,
current_branch_num: BranchNumber::default(), current_branch_num: BranchNumber::default(),
current_chunk_num: 0, current_chunk_num: 0,
current_chunk_type: ChunkType::Head,
branch_map: BranchMap(BranchMapInt::new()), branch_map: BranchMap(BranchMapInt::new()),
root_set: RootSet::new(), root_set: RootSet::new(),
var_num: 0, var_num: 0,
global_cut_var_num: None,
} }
} }
pub fn classify_fact(mut self, term: Term) -> Result<ClassifyFactResult, CompilationError> { pub fn classify_fact(mut self, term: Term) -> Result<ClassifyFactResult, CompilationError> {
self.classify_head_variables(&term)?; self.classify_head_variables(&term)?;
Ok((term, self.branch_map.separate_and_classify_variables(self.var_num))) Ok((term, self.branch_map.separate_and_classify_variables(
self.var_num,
self.global_cut_var_num,
self.current_chunk_num,
)))
} }
pub fn classify_rule<'a, LS: LoadState<'a>>( pub fn classify_rule<'a, LS: LoadState<'a>>(
@@ -333,9 +291,21 @@ impl VariableClassifier {
body: Term, body: Term,
) -> Result<ClassifyRuleResult, CompilationError> { ) -> Result<ClassifyRuleResult, CompilationError> {
self.classify_head_variables(&head)?; self.classify_head_variables(&head)?;
let query_terms = self.classify_body_variables(loader, body)?; self.root_set.insert(self.current_branch_num.clone());
Ok((head, query_terms, self.branch_map.separate_and_classify_variables(self.var_num))) let mut query_terms = self.classify_body_variables(loader, body)?;
self.merge_branches();
let mut var_data = self.branch_map.separate_and_classify_variables(
self.var_num,
self.global_cut_var_num,
self.current_chunk_num,
);
var_data.emit_initial_get_level(&mut query_terms);
Ok((head, query_terms, var_data))
} }
fn merge_branches(&mut self) { fn merge_branches(&mut self) {
@@ -359,24 +329,49 @@ impl VariableClassifier {
} }
} }
fn probe_body_term(&mut self, term: &Term, term_loc: GenContext) { fn try_set_chunk_at_inlined_boundary(&mut self) -> bool {
let mut classify_info = ClassifyInfo { arg_c: 0, arity: term.arity() }; if self.current_chunk_type.is_last() {
self.current_chunk_type = ChunkType::Mid;
self.current_chunk_num += 1;
true
} else {
false
}
}
fn try_set_chunk_at_call_boundary(&mut self) -> bool {
if self.current_chunk_type.is_last() {
self.current_chunk_num += 1;
true
} else {
self.current_chunk_type = ChunkType::Last;
false
}
}
fn probe_body_term(&mut self, arg_c: usize, arity: usize, term: &Term) {
let classify_info = ClassifyInfo { arg_c, arity };
// second arg is true to iterate the root, which may be a variable // second arg is true to iterate the root, which may be a variable
for term_ref in breadth_first_iter(term, true) { for term_ref in breadth_first_iter(term, RootIterationPolicy::Iterated) {
if let TermRef::Var(lvl, _, var_name) = term_ref { if let TermRef::Var(lvl, _, var_ptr) = term_ref {
let var_info = VarInfo { var_ptr: VarPtr::from(&var_name), lvl, classify_info }; // root terms are shallow here (since we're iterating a
self.probe_body_var(var_name, term_loc, var_info); // body term) so take the child level.
} let lvl = lvl.child_level();
self.probe_body_var(VarInfo {
if let Level::Shallow = term_ref.level() { var_ptr,
classify_info.arg_c += 1; lvl,
classify_info,
chunk_type: self.current_chunk_type,
});
} }
} }
} }
fn probe_body_var(&mut self, var_name: Var, term_loc: GenContext, var_info: VarInfo) { fn probe_body_var(&mut self, var_info: VarInfo) {
let branch_info_v = self.branch_map.entry(var_name) let term_loc = self.current_chunk_type.to_gen_context(self.current_chunk_num);
let branch_info_v = self.branch_map.entry(var_info.var_ptr.clone())
.or_insert_with(|| vec![]); .or_insert_with(|| vec![]);
let needs_new_branch = if let Some(last_bi) = branch_info_v.last() { let needs_new_branch = if let Some(last_bi) = branch_info_v.last() {
@@ -409,18 +404,17 @@ impl VariableClassifier {
chunk_info.vars.push(var_info); chunk_info.vars.push(var_info);
} }
fn probe_in_situ_var(&mut self, chunk_type: ChunkType, var_num: usize) { fn probe_in_situ_var(&mut self, var_num: usize) {
let classify_info = ClassifyInfo { arg_c: 0, arity: 0 }; let classify_info = ClassifyInfo { arg_c: 1, arity: 1 };
let var_info = VarInfo { let var_info = VarInfo {
var_ptr: VarPtr::InSitu(var_num), var_ptr: VarPtr::from(Var::InSitu(var_num)),
classify_info, classify_info,
chunk_type: self.current_chunk_type,
lvl: Level::Shallow, lvl: Level::Shallow,
}; };
let term_loc = chunk_type.to_gen_context(self.current_chunk_num); self.probe_body_var(var_info);
self.probe_body_var(Var::Generated(var_num), term_loc, var_info);
} }
fn classify_head_variables(&mut self, term: &Term) -> Result<(), CompilationError> { fn classify_head_variables(&mut self, term: &Term) -> Result<(), CompilationError> {
@@ -430,43 +424,55 @@ impl VariableClassifier {
_ => return Err(CompilationError::InvalidRuleHead), _ => return Err(CompilationError::InvalidRuleHead),
} }
let mut classify_info = ClassifyInfo { arg_c: 0, arity: term.arity() }; let mut classify_info = ClassifyInfo { arg_c: 1, arity: term.arity() };
// false argument to breadth_first_iter because the root is not iterable. match term {
for term_ref in breadth_first_iter(term, false) { Term::Clause(_, _, terms) => {
if let TermRef::Var(lvl, _, var_name) = term_ref { for term in terms.into_iter() {
// the body of the if let here is an inlined for term_ref in breadth_first_iter(term, RootIterationPolicy::Iterated) {
// "probe_head_var". note the difference between it if let TermRef::Var(lvl, _, var_ptr) = term_ref {
// and "probe_body_var". // a body term, so we need the child level here.
let branch_info_v = self.branch_map.entry(Var::from(var_name)) let lvl = lvl.child_level();
.or_insert_with(|| vec![]);
let needs_new_branch = branch_info_v.is_empty(); // the body of the if let here is an inlined
// "probe_head_var". note the difference between it
// and "probe_body_var".
let branch_info_v = self.branch_map.entry(var_ptr.clone())
.or_insert_with(|| vec![]);
if needs_new_branch { let needs_new_branch = branch_info_v.is_empty();
branch_info_v.push(BranchInfo::new(self.current_branch_num.clone()));
if needs_new_branch {
branch_info_v.push(BranchInfo::new(self.current_branch_num.clone()));
}
let branch_info = branch_info_v.last_mut().unwrap();
let needs_new_chunk = branch_info.chunks.is_empty();
if needs_new_chunk {
branch_info.chunks.push(ChunkInfo {
chunk_num: self.current_chunk_num,
term_loc: GenContext::Head,
vars: vec![],
});
}
let chunk_info = branch_info.chunks.last_mut().unwrap();
let var_info = VarInfo {
var_ptr,
classify_info,
chunk_type: self.current_chunk_type,
lvl,
};
chunk_info.vars.push(var_info);
}
}
classify_info.arg_c += 1;
} }
let branch_info = branch_info_v.last_mut().unwrap();
let needs_new_chunk = branch_info.chunks.is_empty();
if needs_new_chunk {
branch_info.chunks.push(ChunkInfo {
chunk_num: self.current_chunk_num,
term_loc: GenContext::Head,
vars: vec![]
});
}
let chunk_info = branch_info.chunks.last_mut().unwrap();
let var_info = VarInfo { var_ptr: VarPtr::from(&var_name), classify_info, lvl };
chunk_info.vars.push(var_info);
}
if let Level::Shallow = term_ref.level() {
classify_info.arg_c += 1;
} }
_ => {}
} }
Ok(()) Ok(())
@@ -476,10 +482,11 @@ impl VariableClassifier {
&mut self, &mut self,
loader: &mut Loader<'a, LS>, loader: &mut Loader<'a, LS>,
term: Term, term: Term,
) -> Result<Vec<QueryTerm>, CompilationError> { ) -> Result<ChunkedTermVec, CompilationError> {
let mut state_stack = vec![TraversalState::Term(term)]; let mut state_stack = vec![TraversalState::Term(term)];
let mut build_stack = vec![]; let mut build_stack = ChunkedTermVec::new();
let mut chunk_type = ChunkType::Head;
self.current_chunk_type = ChunkType::Mid;
while let Some(traversal_st) = state_stack.pop() { while let Some(traversal_st) = state_stack.pop() {
match traversal_st { match traversal_st {
@@ -495,64 +502,78 @@ impl VariableClassifier {
self.root_set.insert(branch_num.clone()); self.root_set.insert(branch_num.clone());
self.current_branch_num = branch_num; self.current_branch_num = branch_num;
} }
TraversalState::IncrChunkNum => {
self.current_chunk_num += 1;
chunk_type = ChunkType::Mid;
build_stack.push(QueryTerm::ChunkTypeBoundary(chunk_type));
}
TraversalState::ResetCallPolicy(call_policy) => { TraversalState::ResetCallPolicy(call_policy) => {
self.call_policy = call_policy; self.call_policy = call_policy;
} }
TraversalState::SetLastChunkType => { TraversalState::BuildDisjunct(preceding_len) => {
chunk_type = ChunkType::Last;
build_stack.push(QueryTerm::ChunkTypeBoundary(chunk_type));
}
TraversalState::BuildDisjunct(reset_chunk_type, preceding_len) => {
chunk_type = reset_chunk_type;
build_stack.push(QueryTerm::ChunkTypeBoundary(chunk_type));
flatten_into_disjunct(&mut build_stack, preceding_len); flatten_into_disjunct(&mut build_stack, preceding_len);
// self.current_chunk_type = ChunkType::Last;
self.current_chunk_type = ChunkType::Mid;
self.current_chunk_num += 1;
} }
TraversalState::BuildFinalDisjunct(preceding_len) => { TraversalState::BuildFinalDisjunct(preceding_len) => {
flatten_into_disjunct(&mut build_stack, preceding_len); flatten_into_disjunct(&mut build_stack, preceding_len);
}
TraversalState::GetCutPoint(var_num) => {
let term_loc = chunk_type.to_gen_context(self.current_chunk_num);
self.probe_in_situ_var(term_loc, var_num); self.current_chunk_type = ChunkType::Mid;
build_stack.push(QueryTerm::GetCutPoint(var_num)); self.current_chunk_num += 1;
} }
TraversalState::LocalCut(var_num) => { TraversalState::GetCutPoint { var_num, prev_b } => {
let term_loc = chunk_type.to_gen_context(self.current_chunk_num); if self.try_set_chunk_at_inlined_boundary() {
build_stack.add_chunk();
}
self.probe_in_situ_var(term_loc, var_num); self.probe_in_situ_var(var_num);
build_stack.push(QueryTerm::LocalCut(var_num)); build_stack.push_chunk_term(QueryTerm::GetCutPoint { var_num, prev_b });
}
TraversalState::Cut { var_num, is_global } => {
if self.try_set_chunk_at_inlined_boundary() {
build_stack.add_chunk();
}
self.probe_in_situ_var(var_num);
build_stack.push_chunk_term(
if is_global {
QueryTerm::GlobalCut(var_num)
} else {
QueryTerm::LocalCut(var_num)
}
);
} }
TraversalState::Fail => { TraversalState::Fail => {
build_stack.push(QueryTerm::Fail); build_stack.push_chunk_term(QueryTerm::Fail);
} }
TraversalState::Term(term) => { TraversalState::Term(term) => {
// return true iff new chunk should be added.
let update_chunk_data = |classifier: &mut Self, predicate_name, arity| {
if ClauseType::is_inlined(predicate_name, arity) {
classifier.try_set_chunk_at_inlined_boundary()
} else {
classifier.try_set_chunk_at_call_boundary()
}
};
match term { match term {
Term::Clause(_, atom!(","), terms) if terms.len() == 2 => { Term::Clause(_, atom!(","), mut terms) if terms.len() == 2 => {
let iter = unfold_by_str(terms[1], atom!(",")) let tail = terms.pop().unwrap();
let head = terms.pop().unwrap();
let iter = unfold_by_str(tail, atom!(","))
.into_iter() .into_iter()
.rev() .rev()
.chain(std::iter::once(terms[0])) .chain(std::iter::once(head))
.map(TraversalState::Term); .map(TraversalState::Term);
if ChunkType::Mid != chunk_type { state_stack.extend(iter);
if insert_set_last_chunk_type(&mut state_stack, iter) {
if chunk_type.is_last() {
chunk_type = ChunkType::Mid;
}
}
} else {
state_stack.extend(iter);
}
} }
Term::Clause(_, atom!(";"), terms) if terms.len() == 2 => { Term::Clause(_, atom!(";"), mut terms) if terms.len() == 2 => {
let tail = terms.pop().unwrap();
let head = terms.pop().unwrap();
let first_branch_num = self.current_branch_num.split(); let first_branch_num = self.current_branch_num.split();
let branches: Vec<_> = std::iter::once(terms[0]) let branches: Vec<_> = std::iter::once(head)
.chain(unfold_by_str(terms[1], atom!(";")).into_iter()) .chain(unfold_by_str(tail, atom!(";")).into_iter())
.collect(); .collect();
let mut branch_numbers = vec![first_branch_num]; let mut branch_numbers = vec![first_branch_num];
@@ -568,7 +589,7 @@ impl VariableClassifier {
} }
let build_stack_len = build_stack.len(); let build_stack_len = build_stack.len();
build_stack.push(QueryTerm::Branch(Vec::with_capacity(branches.len()))); build_stack.reserve_branch(branches.len());
state_stack.push(TraversalState::RepBranchNum( state_stack.push(TraversalState::RepBranchNum(
self.current_branch_num.halve_delta(), self.current_branch_num.halve_delta(),
@@ -578,47 +599,52 @@ impl VariableClassifier {
let final_disjunct_loc = state_stack.len(); let final_disjunct_loc = state_stack.len();
for (term, branch_num) in iter.rev() { for (term, branch_num) in iter.rev() {
state_stack.push(TraversalState::BuildDisjunct(chunk_type, build_stack_len)); state_stack.push(TraversalState::BuildDisjunct(build_stack_len));
state_stack.push(TraversalState::RemoveBranchNum); state_stack.push(TraversalState::RemoveBranchNum);
state_stack.push(TraversalState::Term(term)); state_stack.push(TraversalState::Term(term));
state_stack.push(TraversalState::AddBranchNum(branch_num)); state_stack.push(TraversalState::AddBranchNum(branch_num));
} }
state_stack[final_disjunct_loc] = if let TraversalState::BuildDisjunct(build_stack_len) = state_stack[final_disjunct_loc] {
TraversalState::BuildFinalDisjunct(build_stack_len); state_stack[final_disjunct_loc] = TraversalState::BuildFinalDisjunct(build_stack_len);
}
} }
Term::Clause(_, atom!("->"), mut terms) if terms.len() == 2 => { Term::Clause(_, atom!("->"), mut terms) if terms.len() == 2 => {
let then_term = terms.pop().unwrap(); let then_term = terms.pop().unwrap();
let if_term = terms.pop().unwrap(); let if_term = terms.pop().unwrap();
let iter = vec![TraversalState::Term(then_term), let prev_b = if matches!(state_stack.last(), Some(TraversalState::RemoveBranchNum)) {
TraversalState::LocalCut(self.var_num), // check if the second-to-last element is a regular BuildDisjunct, as we don't
TraversalState::Term(if_term), // want to add GetPrevLevel in case of a TrustMe.
TraversalState::GetCutPoint(self.var_num)] matches!(state_stack.iter().rev().nth(1), Some(TraversalState::BuildDisjunct(..)))
.into_iter(); } else {
false
};
state_stack.push(TraversalState::Term(then_term));
state_stack.push(TraversalState::Cut { var_num: self.var_num, is_global: false });
state_stack.push(TraversalState::Term(if_term));
state_stack.push(TraversalState::GetCutPoint { var_num: self.var_num, prev_b });
self.var_num += 1; self.var_num += 1;
if ChunkType::Mid != chunk_type {
if insert_set_last_chunk_type(&mut state_stack, iter) {
if chunk_type.is_last() {
chunk_type = ChunkType::Mid;
}
}
}
} }
Term::Clause(_, atom!("\\+"), terms) if terms.len() == 1 => { Term::Clause(_, atom!("\\+"), mut terms) if terms.len() == 1 => {
let not_term = terms.pop().unwrap();
let build_stack_len = build_stack.len();
build_stack.reserve_branch(2);
state_stack.push(TraversalState::BuildFinalDisjunct(build_stack_len));
state_stack.push(TraversalState::Term(Term::Clause(Cell::default(), atom!("$succeed"), vec![])));
state_stack.push(TraversalState::BuildDisjunct(build_stack_len));
state_stack.push(TraversalState::Fail); state_stack.push(TraversalState::Fail);
state_stack.push(TraversalState::LocalCut(self.var_num)); state_stack.push(TraversalState::Cut { var_num: self.var_num, is_global: false });
state_stack.push(TraversalState::Term(terms[0])); state_stack.push(TraversalState::Term(not_term));
state_stack.push(TraversalState::GetCutPoint(self.var_num)); state_stack.push(TraversalState::GetCutPoint { var_num: self.var_num, prev_b: true });
self.var_num += 1; self.var_num += 1;
} }
Term::Clause(_, atom!(":"), mut terms) if terms.len() == 2 => { Term::Clause(_, atom!(":"), mut terms) if terms.len() == 2 => {
let term_loc = chunk_type.to_gen_context(self.current_chunk_num);
let predicate_name = terms.pop().unwrap(); let predicate_name = terms.pop().unwrap();
let module_name = terms.pop().unwrap(); let module_name = terms.pop().unwrap();
@@ -627,11 +653,11 @@ impl VariableClassifier {
Term::Literal(_, Literal::Atom(module_name)), Term::Literal(_, Literal::Atom(module_name)),
Term::Literal(_, Literal::Atom(predicate_name)), Term::Literal(_, Literal::Atom(predicate_name)),
) => { ) => {
if !ClauseType::is_inbuilt(predicate_name, 0) { if update_chunk_data(self, predicate_name, 0) {
state_stack.push(TraversalState::IncrChunkNum); build_stack.add_chunk();
} }
build_stack.push( build_stack.push_chunk_term(
qualified_clause_to_query_term( qualified_clause_to_query_term(
loader, loader,
module_name, module_name,
@@ -645,15 +671,15 @@ impl VariableClassifier {
Term::Literal(_, Literal::Atom(module_name)), Term::Literal(_, Literal::Atom(module_name)),
Term::Clause(_, name, terms), Term::Clause(_, name, terms),
) => { ) => {
if !ClauseType::is_inbuilt(name, terms.len()) { if update_chunk_data(self, name, terms.len()) {
state_stack.push(TraversalState::IncrChunkNum); build_stack.add_chunk();
} }
for term in terms.iter() { for (arg_c, term) in terms.iter().enumerate() {
self.probe_body_term(term, term_loc); self.probe_body_term(arg_c + 1, terms.len(), term);
} }
build_stack.push( build_stack.push_chunk_term(
qualified_clause_to_query_term( qualified_clause_to_query_term(
loader, loader,
module_name, module_name,
@@ -664,15 +690,17 @@ impl VariableClassifier {
); );
} }
(module_name, predicate_name) => { (module_name, predicate_name) => {
state_stack.push(TraversalState::IncrChunkNum); if update_chunk_data(self, atom!("call"), 2) {
build_stack.add_chunk();
}
self.probe_body_term(&module_name, term_loc); self.probe_body_term(1, 0, &module_name);
self.probe_body_term(&predicate_name, term_loc); self.probe_body_term(2, 0, &predicate_name);
terms.push(module_name); terms.push(module_name);
terms.push(predicate_name); terms.push(predicate_name);
build_stack.push( build_stack.push_chunk_term(
clause_to_query_term( clause_to_query_term(
loader, loader,
atom!("call"), atom!("call"),
@@ -683,30 +711,22 @@ impl VariableClassifier {
} }
} }
} }
Term::Clause(cell, atom!("$call_with_inference_counting"), terms) if terms.len() == 1 => { Term::Clause(_, atom!("$call_with_inference_counting"), mut terms) if terms.len() == 1 => {
let term_loc = chunk_type.to_gen_context(self.current_chunk_num);
for term in terms.iter() {
self.probe_body_term(term, term_loc);
}
state_stack.push(TraversalState::ResetCallPolicy(self.call_policy)); state_stack.push(TraversalState::ResetCallPolicy(self.call_policy));
state_stack.push(TraversalState::Term(terms[0])); state_stack.push(TraversalState::Term(terms.pop().unwrap()));
self.call_policy = CallPolicy::Counted; self.call_policy = CallPolicy::Counted;
} }
Term::Clause(cell, name, terms) => { Term::Clause(_, name, terms) => {
if !ClauseType::is_inbuilt(name, terms.len()) { if update_chunk_data(self, name, terms.len()) {
state_stack.push(TraversalState::IncrChunkNum); build_stack.add_chunk();
} }
let term_loc = chunk_type.to_gen_context(self.current_chunk_num); for (arg_c, term) in terms.iter().enumerate() {
self.probe_body_term(arg_c + 1, terms.len(), term);
for term in terms.iter() {
self.probe_body_term(term, term_loc);
} }
build_stack.push( build_stack.push_chunk_term(
clause_to_query_term( clause_to_query_term(
loader, loader,
name, name,
@@ -716,14 +736,24 @@ impl VariableClassifier {
); );
} }
Term::Literal(_, Literal::Atom(atom!("!")) | Literal::Char('!')) => { Term::Literal(_, Literal::Atom(atom!("!")) | Literal::Char('!')) => {
build_stack.push(QueryTerm::GlobalCut); if self.global_cut_var_num.is_none() {
} self.global_cut_var_num = Some(self.var_num);
Term::Literal(cell, Literal::Atom(name)) => { self.var_num += 1;
if !ClauseType::is_inbuilt(name, 0) {
state_stack.push(TraversalState::IncrChunkNum);
} }
build_stack.push( self.probe_in_situ_var(self.global_cut_var_num.unwrap());
state_stack.push(TraversalState::Cut {
var_num: self.global_cut_var_num.unwrap(),
is_global: true,
});
}
Term::Literal(_, Literal::Atom(name)) => {
if update_chunk_data(self, name, 0) {
build_stack.add_chunk();
}
build_stack.push_chunk_term(
clause_to_query_term( clause_to_query_term(
loader, loader,
name, name,
@@ -732,7 +762,6 @@ impl VariableClassifier {
), ),
); );
} }
_ => { _ => {
return Err(CompilationError::InadmissibleQueryTerm); return Err(CompilationError::InadmissibleQueryTerm);
} }
@@ -746,61 +775,76 @@ impl VariableClassifier {
} }
impl BranchMap { impl BranchMap {
pub fn separate_and_classify_variables(&mut self, mut var_num: usize) -> VarData { pub fn separate_and_classify_variables(
&mut self,
var_num: usize,
global_cut_var_num: Option<usize>,
current_chunk_num: usize,
) -> VarData {
let mut var_data = VarData { let mut var_data = VarData {
records: vec![VarRecord::default(); self.len()], records: VariableRecords::new(var_num),
fixtures: VariableFixtures::new(), global_cut_var_num,
allocates: current_chunk_num > 0,
}; };
for (var, branches) in self.iter_mut() { for (var, branches) in self.iter_mut() {
for branch in branches.iter_mut() { let (mut var_num, var_num_incr) =
let mut num_occurrences = 0; if let Var::InSitu(var_num) = *var.borrow() {
(var_num, false)
let idx = if let Var::Generated(var_num) = var {
*var_num
} else { } else {
var_num += 1; (var_data.records.len(), true)
var_num - 1
}; };
var_data.records[idx].classification = for branch in branches.iter_mut() {
if branch.chunks.len() > 1 { if var_num_incr {
VarClassification::Perm var_num = var_data.records.len();
} else { var_data.records.push(VariableRecord::default());
branch.chunks }
.first()
.map(|chunk| if chunk.vars.len() > 1 {
VarClassification::Temp
} else {
VarClassification::Void
})
.unwrap_or(VarClassification::Void)
};
var_data.records[idx].chunk_occurrences.reserve(branch.chunks.len()); if branch.chunks.len() <= 1 { // true iff var is a temporary variable.
debug_assert_eq!(branch.chunks.len(), 1);
for chunk in branch.chunks.iter_mut() { let chunk = &mut branch.chunks[0];
var_data.records[idx].num_occurrences += chunk.vars.len(); let mut temp_var_data = TempVarData::new();
if let VarClassification::Temp = classification { for var_info in chunk.vars.iter_mut() {
for var_info in chunk.vars.iter_mut() { if var_info.lvl == Level::Shallow {
var_info.var_ptr.set(Var::Generated(var_num)); let term_loc = var_info.chunk_type.to_gen_context(chunk.chunk_num);
var_data.fixtures.mark_temp_var(&var_info); temp_var_data.use_set.insert((term_loc, var_info.classify_info.arg_c));
}
} else {
for var_info in chunk.vars.iter_mut() {
var_info.var_ptr.set(Var::Generated(var_num));
} }
} }
var_data.records[idx].chunk_occurrences.push(chunk.chunk_num); var_data.records[var_num].allocation = VarAlloc::Temp {
term_loc: chunk.term_loc,
temp_reg: 0,
temp_var_data,
safety: VarSafetyStatus::Needed,
to_perm_var_num: None,
};
} // else VarAlloc is already a Perm variant, as it's the default.
for chunk in branch.chunks.iter_mut() {
var_data.records[var_num].num_occurrences += chunk.vars.len();
for var_info in chunk.vars.iter_mut() {
var_info.var_ptr.set(Var::Generated(var_num));
}
} }
} }
} }
debug_assert_eq!(var_data.records.len(), var_num); // debug_assert_eq!(var_data.records.len(), var_num);
var_data.fixtures.populate_restricting_sets(); var_data.records.populate_restricting_sets();
var_data var_data
} }
} }
#[cfg(test)]
mod tests {
#[test]
fn disjunct_compilation() {
let mut wam = MachineState::new();
let mut op_dir = default_op_dir();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -444,10 +444,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
let tl = preprocessor.try_term_to_tl(self, term)?; let tl = preprocessor.try_term_to_tl(self, term)?;
Ok(match tl { Ok(match tl {
TopLevel::Fact(fact) => PredicateClause::Fact(fact), TopLevel::Fact(fact, var_data) => PredicateClause::Fact(fact, var_data),
TopLevel::Rule(rule) => PredicateClause::Rule(rule), TopLevel::Rule(rule, var_data) => PredicateClause::Rule(rule, var_data),
TopLevel::Query(_) => return Err(SessionError::QueryCannotBeDefinedAsFact),
_ => unreachable!(),
}) })
} }

View File

@@ -1428,7 +1428,7 @@ impl MachineState {
} }
} }
(HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar, h) => { (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar, h) => {
term_stack.push(Term::Var(Cell::default(), Var::Generated(h))); term_stack.push(Term::Var(Cell::default(), VarPtr::from(format!("_{}", h))));
} }
(HeapCellValueTag::Cons | HeapCellValueTag::CStr | HeapCellValueTag::Fixnum | (HeapCellValueTag::Cons | HeapCellValueTag::CStr | HeapCellValueTag::Fixnum |
HeapCellValueTag::Char | HeapCellValueTag::F64) => { HeapCellValueTag::Char | HeapCellValueTag::F64) => {

View File

@@ -2,7 +2,6 @@ use crate::parser::ast::*;
use crate::arena::*; use crate::arena::*;
use crate::atom_table::*; use crate::atom_table::*;
use crate::fixtures::*;
use crate::forms::*; use crate::forms::*;
use crate::machine::loader::*; use crate::machine::loader::*;
use crate::machine::machine_state::*; use crate::machine::machine_state::*;
@@ -227,8 +226,8 @@ impl CodeIndex {
} }
} }
pub(crate) type HeapVarDict = IndexMap<Var, HeapCellValue, FxBuildHasher>; pub(crate) type HeapVarDict = IndexMap<VarPtr, HeapCellValue, FxBuildHasher>;
pub(crate) type AllocVarDict = IndexMap<Var, VarAlloc, FxBuildHasher>; // pub(crate) type AllocVarDict = IndexMap<Var, VarAlloc, FxBuildHasher>;
pub(crate) type GlobalVarDir = IndexMap<Atom, (Ball, Option<HeapCellValue>), FxBuildHasher>; pub(crate) type GlobalVarDir = IndexMap<Atom, (Ball, Option<HeapCellValue>), FxBuildHasher>;

View File

@@ -500,13 +500,13 @@ impl MachineState {
pub fn read_term(&mut self, stream: Stream, indices: &mut IndexStore) -> CallResult { pub fn read_term(&mut self, stream: Stream, indices: &mut IndexStore) -> CallResult {
fn push_var_eq_functors<'a>( fn push_var_eq_functors<'a>(
heap: &mut Heap, heap: &mut Heap,
iter: impl Iterator<Item = (&'a Var, &'a HeapCellValue)>, iter: impl Iterator<Item = (&'a VarPtr, &'a HeapCellValue)>,
atom_tbl: &mut AtomTable, atom_tbl: &mut AtomTable,
) -> Vec<HeapCellValue> { ) -> Vec<HeapCellValue> {
let mut list_of_var_eqs = vec![]; let mut list_of_var_eqs = vec![];
for (var, binding) in iter { for (var, binding) in iter {
let var_atom = atom_tbl.build_with(&var.to_string()); let var_atom = atom_tbl.build_with(&var.borrow().to_string());
let h = heap.len(); let h = heap.len();
heap.push(atom_as_cell!(atom!("="), 2)); heap.push(atom_as_cell!(atom!("="), 2));
@@ -672,7 +672,7 @@ impl MachineState {
let printer = match self.try_from_list(self.registers[6], stub_gen) { let printer = match self.try_from_list(self.registers[6], stub_gen) {
Ok(addrs) => { Ok(addrs) => {
let mut var_names: IndexMap<HeapCellValue, Var> = IndexMap::new(); let mut var_names: IndexMap<HeapCellValue, VarPtr> = IndexMap::new();
for addr in addrs { for addr in addrs {
read_heap_cell!(addr, read_heap_cell!(addr,
@@ -690,18 +690,18 @@ impl MachineState {
read_heap_cell!(atom, read_heap_cell!(atom,
(HeapCellValueTag::Char, c) => { (HeapCellValueTag::Char, c) => {
var_names.insert(var, Var::from(c.to_string())); var_names.insert(var, VarPtr::from(c.to_string()));
} }
(HeapCellValueTag::Atom, (name, _arity)) => { (HeapCellValueTag::Atom, (name, _arity)) => {
debug_assert_eq!(_arity, 0); debug_assert_eq!(_arity, 0);
var_names.insert(var, Var::from(name.as_str())); var_names.insert(var, VarPtr::from(name.as_str()));
} }
(HeapCellValueTag::Str, s) => { (HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s]) let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity(); .get_name_and_arity();
debug_assert_eq!(arity, 0); debug_assert_eq!(arity, 0);
var_names.insert(var, Var::from(name.as_str())); var_names.insert(var, VarPtr::from(name.as_str()));
} }
_ => { _ => {
unreachable!(); unreachable!();

View File

@@ -365,46 +365,46 @@ impl Machine {
Instruction::BreakFromDispatchLoop, Instruction::BreakFromDispatchLoop,
Instruction::InstallVerifyAttr, Instruction::InstallVerifyAttr,
Instruction::VerifyAttrInterrupt, Instruction::VerifyAttrInterrupt,
Instruction::ExecuteTermGreaterThan(0), Instruction::ExecuteTermGreaterThan,
Instruction::ExecuteTermLessThan(0), Instruction::ExecuteTermLessThan,
Instruction::ExecuteTermGreaterThanOrEqual(0), Instruction::ExecuteTermGreaterThanOrEqual,
Instruction::ExecuteTermLessThanOrEqual(0), Instruction::ExecuteTermLessThanOrEqual,
Instruction::ExecuteTermEqual(0), Instruction::ExecuteTermEqual,
Instruction::ExecuteTermNotEqual(0), Instruction::ExecuteTermNotEqual,
Instruction::ExecuteNumberGreaterThan(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2)), 0), Instruction::ExecuteNumberGreaterThan(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2))),
Instruction::ExecuteNumberLessThan(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2)), 0), Instruction::ExecuteNumberLessThan(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2))),
Instruction::ExecuteNumberGreaterThanOrEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2)), 0), Instruction::ExecuteNumberGreaterThanOrEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2))),
Instruction::ExecuteNumberLessThanOrEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2)), 0), Instruction::ExecuteNumberLessThanOrEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2))),
Instruction::ExecuteNumberEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2)), 0), Instruction::ExecuteNumberEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2))),
Instruction::ExecuteNumberNotEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2)), 0), Instruction::ExecuteNumberNotEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2))),
Instruction::ExecuteIs(temp_v!(1), ar_reg!(temp_v!(2)), 0), Instruction::ExecuteIs(temp_v!(1), ar_reg!(temp_v!(2))),
Instruction::ExecuteAcyclicTerm(0), Instruction::ExecuteAcyclicTerm,
Instruction::ExecuteArg(0), Instruction::ExecuteArg,
Instruction::ExecuteCompare(0), Instruction::ExecuteCompare,
Instruction::ExecuteCopyTerm(0), Instruction::ExecuteCopyTerm,
Instruction::ExecuteFunctor(0), Instruction::ExecuteFunctor,
Instruction::ExecuteGround(0), Instruction::ExecuteGround,
Instruction::ExecuteKeySort(0), Instruction::ExecuteKeySort,
Instruction::ExecuteRead(0), Instruction::ExecuteRead,
Instruction::ExecuteSort(0), Instruction::ExecuteSort,
Instruction::ExecuteN(1, 0), Instruction::ExecuteN(1),
Instruction::ExecuteN(2, 0), Instruction::ExecuteN(2),
Instruction::ExecuteN(3, 0), Instruction::ExecuteN(3),
Instruction::ExecuteN(4, 0), Instruction::ExecuteN(4),
Instruction::ExecuteN(5, 0), Instruction::ExecuteN(5),
Instruction::ExecuteN(6, 0), Instruction::ExecuteN(6),
Instruction::ExecuteN(7, 0), Instruction::ExecuteN(7),
Instruction::ExecuteN(8, 0), Instruction::ExecuteN(8),
Instruction::ExecuteN(9, 0), Instruction::ExecuteN(9),
Instruction::ExecuteIsAtom(temp_v!(1), 0), Instruction::ExecuteIsAtom(temp_v!(1)),
Instruction::ExecuteIsAtomic(temp_v!(1), 0), Instruction::ExecuteIsAtomic(temp_v!(1)),
Instruction::ExecuteIsCompound(temp_v!(1), 0), Instruction::ExecuteIsCompound(temp_v!(1)),
Instruction::ExecuteIsInteger(temp_v!(1), 0), Instruction::ExecuteIsInteger(temp_v!(1)),
Instruction::ExecuteIsNumber(temp_v!(1), 0), Instruction::ExecuteIsNumber(temp_v!(1)),
Instruction::ExecuteIsRational(temp_v!(1), 0), Instruction::ExecuteIsRational(temp_v!(1)),
Instruction::ExecuteIsFloat(temp_v!(1), 0), Instruction::ExecuteIsFloat(temp_v!(1)),
Instruction::ExecuteIsNonVar(temp_v!(1), 0), Instruction::ExecuteIsNonVar(temp_v!(1)),
Instruction::ExecuteIsVar(temp_v!(1), 0) Instruction::ExecuteIsVar(temp_v!(1))
].into_iter()); ].into_iter());
for (p, instr) in self.code[impls_offset ..].iter().enumerate() { for (p, instr) in self.code[impls_offset ..].iter().enumerate() {
@@ -690,6 +690,8 @@ impl Machine {
fn try_call(&mut self, name: Atom, arity: usize, idx: IndexPtr) -> CallResult { fn try_call(&mut self, name: Atom, arity: usize, idx: IndexPtr) -> CallResult {
let compiled_tl_index = idx.p() as usize; let compiled_tl_index = idx.p() as usize;
// println!("calling {}/{}", name.as_str(), arity);
match idx.tag() { match idx.tag() {
IndexPtrTag::DynamicUndefined => { IndexPtrTag::DynamicUndefined => {
self.machine_st.fail = true; self.machine_st.fail = true;
@@ -713,6 +715,8 @@ impl Machine {
fn try_execute(&mut self, name: Atom, arity: usize, idx: IndexPtr) -> CallResult { fn try_execute(&mut self, name: Atom, arity: usize, idx: IndexPtr) -> CallResult {
let compiled_tl_index = idx.p() as usize; let compiled_tl_index = idx.p() as usize;
// println!("executing {}/{}", name.as_str(), arity);
match idx.tag() { match idx.tag() {
IndexPtrTag::DynamicUndefined => { IndexPtrTag::DynamicUndefined => {
self.machine_st.fail = true; self.machine_st.fail = true;

View File

@@ -10,20 +10,8 @@ use crate::parser::ast::*;
use indexmap::IndexSet; use indexmap::IndexSet;
use std::cell::Cell; use std::cell::Cell;
use std::collections::VecDeque;
use std::convert::TryFrom; use std::convert::TryFrom;
pub(crate) fn fold_by_str<I>(terms: I, mut term: Term, sym: Atom) -> Term
where
I: DoubleEndedIterator<Item = Term>,
{
for prec in terms.rev() {
term = Term::Clause(Cell::default(), sym, vec![prec, term]);
}
term
}
pub(crate) fn to_op_decl( pub(crate) fn to_op_decl(
prec: u16, prec: u16,
spec: Atom, spec: Atom,
@@ -546,16 +534,15 @@ impl Preprocessor {
} }
} }
fn setup_fact(&mut self, term: Term) -> Result<Fact, CompilationError> { fn setup_fact(&mut self, term: Term) -> Result<(Fact, VarData), CompilationError> {
match term { match term {
Term::Clause(..) | Term::Literal(_, Literal::Atom(..)) => { Term::Clause(..) | Term::Literal(_, Literal::Atom(..)) => {
let mut classifier = VariableClassifier::new( let classifier = VariableClassifier::new(
self.settings.default_call_policy(), self.settings.default_call_policy(),
); );
let (head, var_data) = classifier.classify_fact(term)?; let (head, var_data) = classifier.classify_fact(term)?;
Ok((Fact { head }, var_data))
Ok(Fact { head, var_data })
} }
_ => Err(CompilationError::InadmissibleFact), _ => Err(CompilationError::InadmissibleFact),
} }
@@ -566,28 +553,22 @@ impl Preprocessor {
loader: &mut Loader<'a, LS>, loader: &mut Loader<'a, LS>,
head: Term, head: Term,
body: Term, body: Term,
) -> Result<Rule, CompilationError> { ) -> Result<(Rule, VarData), CompilationError> {
let mut classifier = VariableClassifier::new( let classifier = VariableClassifier::new(
self.settings.default_call_policy(), self.settings.default_call_policy(),
); );
let (head, mut query_terms, var_data) = let (head, clauses, var_data) = classifier.classify_rule(loader, head, body)?;
classifier.classify_rule(loader, head, body)?;
let clauses = query_terms.drain(1..).collect();
let qt = query_terms.pop().unwrap();
match head { match head {
Term::Clause(_, name, terms) => Ok(Rule { Term::Clause(_, name, terms) => Ok((Rule {
head: (name, terms, qt), head: (name, terms),
clauses, clauses,
var_data, }, var_data)),
}), Term::Literal(_, Literal::Atom(name)) => Ok((Rule {
Term::Literal(_, Literal::Atom(name)) => Ok(Rule { head: (name, vec![]),
head: (name, vec![], qt),
clauses, clauses,
var_data, }, var_data)),
}),
_ => Err(CompilationError::InvalidRuleHead), _ => Err(CompilationError::InvalidRuleHead),
} }
} }
@@ -613,20 +594,29 @@ impl Preprocessor {
term: Term, term: Term,
) -> Result<TopLevel, CompilationError> { ) -> Result<TopLevel, CompilationError> {
match term { match term {
Term::Clause(r, name, terms) => { Term::Clause(r, name, mut terms) => {
let is_rule = name == atom!(":-") && terms.len() == 2; let is_rule = name == atom!(":-") && terms.len() == 2;
if is_rule { if is_rule {
Ok(TopLevel::Rule(self.setup_rule(loader, terms[0], terms[1])?)) let tail = terms.pop().unwrap();
let head = terms.pop().unwrap();
let (rule, var_data) = self.setup_rule(loader, head, tail)?;
Ok(TopLevel::Rule(rule, var_data))
} else { } else {
let term = Term::Clause(r, name, terms); let term = Term::Clause(r, name, terms);
Ok(TopLevel::Fact(self.setup_fact(term)?)) let (fact, var_data) = self.setup_fact(term)?;
Ok(TopLevel::Fact(fact, var_data))
} }
} }
term => Ok(TopLevel::Fact(self.setup_fact(term)?)), term => {
let (fact, var_data) = self.setup_fact(term)?;
Ok(TopLevel::Fact(fact, var_data))
}
} }
} }
/*
fn try_terms_to_tls<'a, I: IntoIterator<Item = Term>, LS: LoadState<'a>>( fn try_terms_to_tls<'a, I: IntoIterator<Item = Term>, LS: LoadState<'a>>(
&mut self, &mut self,
loader: &mut Loader<'a, LS>, loader: &mut Loader<'a, LS>,
@@ -640,4 +630,5 @@ impl Preprocessor {
Ok(results) Ok(results)
} }
*/
} }

View File

@@ -1409,7 +1409,7 @@ impl Machine {
let vars: Vec<_> = vars let vars: Vec<_> = vars
.union(&result.supp_vars) // difference + union does not cancel. .union(&result.supp_vars) // difference + union does not cancel.
.map(|v| Term::Var(Cell::default(), Var::Generated(v.get_value()))) .map(|v| Term::Var(Cell::default(), VarPtr::from(format!("_{}", v.get_value()))))
.collect(); .collect();
let helper_clause_loc = self.code.len(); let helper_clause_loc = self.code.len();
@@ -1571,8 +1571,8 @@ impl Machine {
#[inline(always)] #[inline(always)]
pub(crate) fn is_reset_cont_marker(&self, p: usize) -> bool { pub(crate) fn is_reset_cont_marker(&self, p: usize) -> bool {
match &self.code[p] { match &self.code[p] {
&Instruction::CallResetContinuationMarker(_) | &Instruction::CallResetContinuationMarker |
&Instruction::ExecuteResetContinuationMarker(_) => true, &Instruction::ExecuteResetContinuationMarker => true,
_ => false _ => false
} }
} }
@@ -4911,9 +4911,7 @@ impl Machine {
let p_functor = self.deref_register(2); let p_functor = self.deref_register(2);
let p = to_local_code_ptr(&self.machine_st.heap, p_functor).unwrap(); let num_cells = self.machine_st.stack.index_and_frame(e).prelude.num_cells;
let num_cells = *self.code[p].perm_vars_mut().unwrap();
let mut addrs = vec![]; let mut addrs = vec![];
for idx in 1..num_cells + 1 { for idx in 1..num_cells + 1 {

View File

@@ -540,23 +540,7 @@ macro_rules! functor_term {
macro_rules! compare_number_instr { macro_rules! compare_number_instr {
($cmp: expr, $at_1: expr, $at_2: expr) => {{ ($cmp: expr, $at_1: expr, $at_2: expr) => {{
$cmp.set_terms($at_1, $at_2); $cmp.set_terms($at_1, $at_2);
call_clause!(ClauseType::Inlined(InlinedClauseType::CompareNumber($cmp)), 0) ClauseType::Inlined(InlinedClauseType::CompareNumber($cmp)).to_instr()
}};
}
macro_rules! call_clause {
($clause_type:expr, $pvs:expr) => {{
let mut instr = $clause_type.to_instr();
instr.perm_vars_mut().map(|pvs| *pvs = $pvs);
instr
}};
}
macro_rules! call_clause_by_default {
($clause_type:expr, $pvs:expr) => {{
let mut instr = $clause_type.to_instr().to_default();
instr.perm_vars_mut().map(|pvs| *pvs = $pvs);
instr
}}; }};
} }

View File

@@ -4,11 +4,11 @@ use crate::machine::machine_indices::*;
use crate::parser::char_reader::*; use crate::parser::char_reader::*;
use crate::types::HeapCellValueTag; use crate::types::HeapCellValueTag;
use std::cell::Cell; use std::cell::{Cell, Ref, RefCell, RefMut};
use std::fmt; use std::fmt;
use std::hash::Hash; use std::hash::{Hash, Hasher};
use std::io::{Error as IOError}; use std::io::{Error as IOError};
use std::ops::Neg; use std::ops::{Deref, Neg};
use std::rc::Rc; use std::rc::Rc;
use std::vec::Vec; use std::vec::Vec;
@@ -572,23 +572,89 @@ impl Literal {
} }
} }
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct VarPtr(Rc<RefCell<Var>>);
impl Hash for VarPtr {
#[inline(always)]
fn hash<H: Hasher>(&self, hasher: &mut H) {
self.borrow().hash(hasher)
}
}
impl Deref for VarPtr {
type Target = RefCell<Var>;
#[inline(always)]
fn deref(&self) -> &Self::Target {
self.0.deref()
}
}
impl VarPtr {
#[inline(always)]
pub(crate) fn borrow(&self) -> Ref<'_, Var> {
self.0.borrow()
}
#[inline(always)]
pub(crate) fn borrow_mut(&self) -> RefMut<'_, Var> {
self.0.borrow_mut()
}
pub(crate) fn to_var_num(&self) -> Option<usize> {
match *self.borrow() {
Var::Generated(var_num) => Some(var_num),
_ => None,
}
}
pub(crate) fn set(&self, var: Var) {
let mut var_ref = self.borrow_mut();
*var_ref = var;
}
}
impl From<Var> for VarPtr {
#[inline(always)]
fn from(value: Var) -> VarPtr {
VarPtr(Rc::new(RefCell::new(value)))
}
}
impl From<String> for VarPtr {
#[inline(always)]
fn from(value: String) -> VarPtr {
VarPtr::from(Var::from(value))
}
}
impl From<&str> for VarPtr {
#[inline(always)]
fn from(value: &str) -> VarPtr {
VarPtr::from(value.to_owned())
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Var { pub enum Var {
Generated(usize), Generated(usize),
Named(Rc<String>), InSitu(usize),
Named(String),
} }
impl From<String> for Var { impl From<String> for Var {
#[inline(always)] #[inline(always)]
fn from(value: String) -> Var { fn from(value: String) -> Var {
Var::Named(Rc::new(value)) Var::Named(value)
} }
} }
impl From<&str> for Var { impl From<&str> for Var {
#[inline(always)] #[inline(always)]
fn from(value: &str) -> Var { fn from(value: &str) -> Var {
Var::Named(Rc::new(value.to_owned())) Var::Named(value.to_owned())
} }
} }
@@ -596,16 +662,16 @@ impl Var {
#[inline(always)] #[inline(always)]
pub fn as_str(&self) -> Option<&str> { pub fn as_str(&self) -> Option<&str> {
match self { match self {
Var::Generated(_) => None,
Var::Named(value) => Some(&value), Var::Named(value) => Some(&value),
_ => None,
} }
} }
#[inline(always)] #[inline(always)]
pub fn to_string(&self) -> String { pub fn to_string(&self) -> String {
match self { match self {
Var::Generated(n) => format!("_{}", n), Var::InSitu(n) | Var::Generated(n) => format!("_{}", n),
Var::Named(value) => value.to_string(), Var::Named(value) => value.to_owned(),
} }
} }
} }
@@ -620,7 +686,7 @@ pub enum Term {
// other PartialString variants in as_partial_string. // other PartialString variants in as_partial_string.
PartialString(Cell<RegType>, String, Box<Term>), PartialString(Cell<RegType>, String, Box<Term>),
CompleteString(Cell<RegType>, Atom), CompleteString(Cell<RegType>, Atom),
Var(Cell<VarReg>, Var), Var(Cell<VarReg>, VarPtr),
} }
impl Term { impl Term {

View File

@@ -426,7 +426,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
if v.trim() == "_" { if v.trim() == "_" {
self.terms.push(Term::AnonVar); self.terms.push(Term::AnonVar);
} else { } else {
self.terms.push(Term::Var(Cell::default(), Var::from(v))); self.terms.push(Term::Var(Cell::default(), VarPtr::from(v)));
} }
TokenType::Term TokenType::Term

View File

@@ -317,7 +317,7 @@ impl<'a, 'b> TermWriter<'a, 'b> {
fn write_term_to_heap(mut self, term: &'a Term) -> Result<TermWriteResult, CompilationError> { fn write_term_to_heap(mut self, term: &'a Term) -> Result<TermWriteResult, CompilationError> {
let heap_loc = self.heap.len(); let heap_loc = self.heap.len();
for term in breadth_first_iter(term, true) { for term in breadth_first_iter(term, RootIterationPolicy::Iterated) {
let h = self.heap.len(); let h = self.heap.len();
match &term { match &term {
@@ -372,9 +372,9 @@ impl<'a, 'b> TermWriter<'a, 'b> {
let addr = self.term_as_addr(&term, h); let addr = self.term_as_addr(&term, h);
self.heap.push(addr); self.heap.push(addr);
} }
&TermRef::Var(Level::Root, _, ref var) => { &TermRef::Var(Level::Root, _, ref var_ptr) => {
let addr = self.term_as_addr(&term, h); let addr = self.term_as_addr(&term, h);
self.var_dict.insert(var.clone(), heap_loc_as_cell!(h)); self.var_dict.insert(var_ptr.clone(), heap_loc_as_cell!(h));
self.heap.push(addr); self.heap.push(addr);
} }
&TermRef::AnonVar(_) => { &TermRef::AnonVar(_) => {

View File

@@ -29,11 +29,13 @@ pub(crate) trait CompilationTarget<'a> {
fn argument_to_variable(r: RegType, r: usize) -> Instruction; fn argument_to_variable(r: RegType, r: usize) -> Instruction;
fn argument_to_value(r: RegType, val: usize) -> Instruction; fn argument_to_value(r: RegType, val: usize) -> Instruction;
fn unsafe_argument_to_value(r: RegType, val: usize) -> Instruction;
fn move_to_register(r: RegType, val: usize) -> Instruction; fn move_to_register(r: RegType, val: usize) -> Instruction;
fn subterm_to_variable(r: RegType) -> Instruction; fn subterm_to_variable(r: RegType) -> Instruction;
fn subterm_to_value(r: RegType) -> Instruction; fn subterm_to_value(r: RegType) -> Instruction;
fn unsafe_subterm_to_value(r: RegType) -> Instruction;
fn clause_arg_to_instr(r: RegType) -> Instruction; fn clause_arg_to_instr(r: RegType) -> Instruction;
} }
@@ -42,7 +44,7 @@ impl<'a> CompilationTarget<'a> for FactInstruction {
type Iterator = FactIterator<'a>; type Iterator = FactIterator<'a>;
fn iter(term: &'a Term) -> Self::Iterator { fn iter(term: &'a Term) -> Self::Iterator {
breadth_first_iter(term, false) // do not iterate over the root clause if one exists. breadth_first_iter(term, RootIterationPolicy::NotIterated)
} }
fn to_constant(lvl: Level, constant: Literal, reg: RegType) -> Instruction { fn to_constant(lvl: Level, constant: Literal, reg: RegType) -> Instruction {
@@ -95,6 +97,10 @@ impl<'a> CompilationTarget<'a> for FactInstruction {
Instruction::GetValue(arg, val) Instruction::GetValue(arg, val)
} }
fn unsafe_argument_to_value(arg: RegType, val: usize) -> Instruction {
Instruction::GetValue(arg, val)
}
fn subterm_to_variable(val: RegType) -> Instruction { fn subterm_to_variable(val: RegType) -> Instruction {
Instruction::UnifyVariable(val) Instruction::UnifyVariable(val)
} }
@@ -103,6 +109,10 @@ impl<'a> CompilationTarget<'a> for FactInstruction {
Instruction::UnifyValue(val) Instruction::UnifyValue(val)
} }
fn unsafe_subterm_to_value(val: RegType) -> Instruction {
Instruction::UnifyLocalValue(val)
}
fn clause_arg_to_instr(val: RegType) -> Instruction { fn clause_arg_to_instr(val: RegType) -> Instruction {
Instruction::UnifyVariable(val) Instruction::UnifyVariable(val)
} }
@@ -165,6 +175,13 @@ impl<'a> CompilationTarget<'a> for QueryInstruction {
Instruction::PutValue(arg, val) Instruction::PutValue(arg, val)
} }
fn unsafe_argument_to_value(arg: RegType, val: usize) -> Instruction {
match arg {
RegType::Perm(p) => Instruction::PutUnsafeValue(p, val),
RegType::Temp(_) => Instruction::PutValue(arg, val),
}
}
fn subterm_to_variable(val: RegType) -> Instruction { fn subterm_to_variable(val: RegType) -> Instruction {
Instruction::SetVariable(val) Instruction::SetVariable(val)
} }
@@ -173,6 +190,10 @@ impl<'a> CompilationTarget<'a> for QueryInstruction {
Instruction::SetValue(val) Instruction::SetValue(val)
} }
fn unsafe_subterm_to_value(val: RegType) -> Instruction {
Instruction::SetLocalValue(val)
}
fn clause_arg_to_instr(val: RegType) -> Instruction { fn clause_arg_to_instr(val: RegType) -> Instruction {
Instruction::SetValue(val) Instruction::SetValue(val)
} }