From: Mark Thom Date: Thu, 23 Mar 2017 04:30:45 +0000 (-0600) Subject: optimizations X-Git-Tag: v0.8.110~756 X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=9362aa6af3dd55a833dd7950561ea3e4edae55f4;p=scryer-prolog.git optimizations --- diff --git a/Cargo.lock b/Cargo.lock index 99f64f8e..eadb9dbd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ [root] name = "rusty-wam" -version = "0.5.0" +version = "0.5.3" dependencies = [ "lalrpop 0.12.5 (registry+https://github.com/rust-lang/crates.io-index)", "lalrpop-util 0.12.5 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index 8017f46b..fc29ae3b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rusty-wam" -version = "0.5.0" +version = "0.5.4" authors = ["Mark Thom"] build = "build.rs" diff --git a/README.md b/README.md index 11bfc877..e9c3d65b 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,8 @@ pure Prolog. Pure Prolog is implemented as a simple REPL. "Pure Prolog" is Prolog without cut, meta- or extra-logical operators, or side effects of any kind. In terms of the tutorial pacing, the work has progressed to the -middle of section 5.2. Atoms and lists are the only two data types -currently supported. +to the end of section 5.3, skipping past 5.4. Atoms and lists +are the only two data types currently supported. ## Tutorial To enter a multi-clause predicate, the brackets ":{" and "}:" are used diff --git a/src/prolog/ast.rs b/src/prolog/ast.rs index 4f42990e..da1646ca 100644 --- a/src/prolog/ast.rs +++ b/src/prolog/ast.rs @@ -80,6 +80,10 @@ impl VarReg { } } + pub fn is_temp(self) -> bool { + !self.norm().is_perm() + } + pub fn root_register(self) -> usize { match self { VarReg::ArgAndNorm(_, root) => root, @@ -126,10 +130,11 @@ pub enum FactInstruction { GetList(Level, RegType), GetStructure(Level, Atom, usize, RegType), GetValue(RegType, usize), - GetVariable(RegType, usize), + GetVariable(RegType, usize), UnifyConstant(Constant), UnifyVariable(RegType), - UnifyValue(RegType) + UnifyValue(RegType), + UnifyVoid(usize) } pub enum QueryInstruction { @@ -140,7 +145,8 @@ pub enum QueryInstruction { PutVariable(RegType, usize), SetConstant(Constant), SetVariable(RegType), - SetValue(RegType) + SetValue(RegType), + SetVoid(usize) } pub enum ChoiceInstruction { diff --git a/src/prolog/codegen.rs b/src/prolog/codegen.rs index c8af1746..5e10a308 100644 --- a/src/prolog/codegen.rs +++ b/src/prolog/codegen.rs @@ -11,9 +11,10 @@ trait CompilationTarget<'a> { fn iter(&'a Term) -> Self::Iterator; - fn to_structure(Level, Atom, usize, RegType) -> Self; fn to_constant(Level, Constant, RegType) -> Self; fn to_list(Level, RegType) -> Self; + fn to_structure(Level, Atom, usize, RegType) -> Self; + fn to_void(usize) -> Self; fn constant_subterm(Constant) -> Self; @@ -33,18 +34,22 @@ impl<'a> CompilationTarget<'a> for FactInstruction { term.breadth_first_iter() } - fn to_structure(lvl: Level, atom: Atom, arity: usize, reg: RegType) -> Self { - FactInstruction::GetStructure(lvl, atom, arity, reg) - } - fn to_constant(lvl: Level, constant: Constant, reg: RegType) -> Self { FactInstruction::GetConstant(lvl, constant, reg) } + fn to_structure(lvl: Level, atom: Atom, arity: usize, reg: RegType) -> Self { + FactInstruction::GetStructure(lvl, atom, arity, reg) + } + fn to_list(lvl: Level, reg: RegType) -> Self { FactInstruction::GetList(lvl, reg) } + fn to_void(subterms: usize) -> Self { + FactInstruction::UnifyVoid(subterms) + } + fn constant_subterm(constant: Constant) -> Self { FactInstruction::UnifyConstant(constant) } @@ -76,7 +81,7 @@ impl<'a> CompilationTarget<'a> for QueryInstruction { fn iter(term: &'a Term) -> Self::Iterator { term.post_order_iter() } - + fn to_structure(lvl: Level, atom: Atom, arity: usize, reg: RegType) -> Self { QueryInstruction::PutStructure(lvl, atom, arity, reg) } @@ -89,6 +94,10 @@ impl<'a> CompilationTarget<'a> for QueryInstruction { QueryInstruction::PutList(lvl, reg) } + fn to_void(subterms: usize) -> Self { + QueryInstruction::SetVoid(subterms) + } + fn constant_subterm(constant: Constant) -> Self { QueryInstruction::SetConstant(constant) } @@ -145,7 +154,7 @@ impl<'a> TermMarker<'a> { fn insert(&mut self, var: &'a Var, r: VarReg) { self.bindings.insert(var, r); } - + fn mark_non_var(&mut self, lvl: Level, cell: &Cell) { let reg_type = cell.get(); @@ -212,18 +221,18 @@ impl<'a> TermMarker<'a> { reg } }; - - self.insert(var, reg); + + self.insert(var, reg); reg } - + fn mark_anon_var(&mut self, lvl: Level) -> VarReg { let inner_reg = { let temp = self.temp_c; self.temp_c += 1; RegType::Temp(temp) }; - + match lvl { Level::Deep => VarReg::Norm(inner_reg), Level::Shallow => { @@ -233,7 +242,11 @@ impl<'a> TermMarker<'a> { } } } - + + fn advance_arg(&mut self) { + self.arg_c += 1; + } + fn advance_at_head(&mut self, term: &'a Term) { self.arg_c = 1; self.temp_c = max(term.subterms(), self.temp_c) + 1; @@ -266,6 +279,46 @@ impl<'a> CodeGenerator<'a> { &self.marker.bindings } + #[allow(dead_code)] + fn count_vars(term: &Term) -> HashMap<&Var, usize> { + let mut var_count = HashMap::new(); + + for term in term.breadth_first_iter() { + if let TermRef::Var(_, _, ref var) = term { + let entry = var_count.entry(*var).or_insert(0); + *entry += 1; + } + } + + var_count + } + + #[allow(dead_code)] + fn all_singleton_vars(terms: &Vec>, + var_count: &HashMap<&Var, usize>) + -> bool + { + for term in terms { + match term.as_ref() { + &Term::AnonVar => {}, + &Term::Var(ref cell, ref var) if cell.get().is_temp() => + if var_count.get(var).unwrap() != &1 { + return false; + }, + _ => return false + } + } + + true + } + + #[allow(dead_code)] + fn void_subterms(subterms: usize) -> Target + where Target: CompilationTarget<'a> + { + Target::to_void(subterms) + } + fn to_structure(&mut self, lvl: Level, cell: &'a Cell, @@ -305,10 +358,10 @@ impl<'a> CodeGenerator<'a> { self.marker.mark_non_var(Level::Deep, cell); Target::constant_subterm(constant.clone()) } - + fn anon_var_term(&mut self, lvl: Level) -> Target where Target: CompilationTarget<'a> - { + { let reg = self.marker.mark_anon_var(lvl); match reg { @@ -318,7 +371,7 @@ impl<'a> CodeGenerator<'a> { Target::subterm_to_variable(norm) } } - + fn var_term(&mut self, lvl: Level, cell: &'a Cell, @@ -371,17 +424,26 @@ impl<'a> CodeGenerator<'a> { } } - fn compile_target(&mut self, term: &'a Term) -> Vec + fn compile_target(&mut self, term: &'a Term, has_exposed_vars: bool) + -> Vec where Target: CompilationTarget<'a> { let iter = Target::iter(term); let mut target = Vec::new(); + let var_count = Self::count_vars(term); for term in iter { match term { TermRef::Clause(lvl, cell, atom, terms) => { target.push(self.to_structure(lvl, cell, atom, terms.len())); + if !has_exposed_vars { + if Self::all_singleton_vars(terms, &var_count) { + target.push(Self::void_subterms(terms.len())); + continue; + } + } + for subterm in terms { target.push(self.subterm_to_instr(subterm.as_ref())); } @@ -394,8 +456,13 @@ impl<'a> CodeGenerator<'a> { }, TermRef::Constant(lvl @ Level::Shallow, cell, constant) => target.push(self.to_constant(lvl, cell, constant)), - TermRef::AnonVar(lvl @ Level::Shallow) => - target.push(self.anon_var_term(lvl)), + TermRef::AnonVar(lvl @ Level::Shallow) => { + if has_exposed_vars { + target.push(self.anon_var_term(lvl)); + } else { + self.marker.advance_arg(); + } + }, TermRef::Var(lvl @ Level::Shallow, ref cell, ref var) => target.push(self.var_term(lvl, cell, var)), _ => {} @@ -480,15 +547,15 @@ impl<'a> CodeGenerator<'a> { body.push(Line::Control(ControlInstruction::Allocate(perm_vars))); self.marker.advance(p0); - body.push(Line::Fact(self.compile_target(p0))); + body.push(Line::Fact(self.compile_target(p0, false))); self.marker.advance_at_head(p1); - body.push(Line::Query(self.compile_target(p1))); + body.push(Line::Query(self.compile_target(p1, false))); Self::add_conditional_call(&mut body, p1); body = clauses.iter() - .map(|ref term| self.compile_query(term)) + .map(|ref term| self.compile_internal_query(term)) .fold(body, |mut body, ref mut cqs| { body.append(cqs); body @@ -501,17 +568,26 @@ impl<'a> CodeGenerator<'a> { pub fn compile_fact(&mut self, term: &'a Term) -> Code { self.marker.advance(term); - let mut compiled_fact = vec![Line::Fact(self.compile_target(term))]; + let mut compiled_fact = vec![Line::Fact(self.compile_target(term, false))]; let proceed = Line::Control(ControlInstruction::Proceed); compiled_fact.push(proceed); compiled_fact } + + fn compile_internal_query(&mut self, term: &'a Term) -> Code { + self.marker.advance(term); + + let mut compiled_query = vec![Line::Query(self.compile_target(term, false))]; + Self::add_conditional_call(&mut compiled_query, term); + compiled_query + } + pub fn compile_query(&mut self, term: &'a Term) -> Code { self.marker.advance(term); - let mut compiled_query = vec![Line::Query(self.compile_target(term))]; + let mut compiled_query = vec![Line::Query(self.compile_target(term, true))]; Self::add_conditional_call(&mut compiled_query, term); compiled_query diff --git a/src/prolog/io.rs b/src/prolog/io.rs index 6fbf3134..3d760447 100644 --- a/src/prolog/io.rs +++ b/src/prolog/io.rs @@ -14,7 +14,7 @@ impl fmt::Display for Constant { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { &Constant::Atom(ref atom) => - write!(f, "{}", atom), + write!(f, "{}", atom), &Constant::EmptyList => write!(f, "[]") } @@ -45,7 +45,9 @@ impl fmt::Display for FactInstruction { &FactInstruction::UnifyVariable(ref r) => write!(f, "unify_variable {}", r), &FactInstruction::UnifyValue(ref r) => - write!(f, "unify_value {}", r) + write!(f, "unify_value {}", r), + &FactInstruction::UnifyVoid(n) => + write!(f, "unify_void {}", n) } } } @@ -74,7 +76,9 @@ impl fmt::Display for QueryInstruction { &QueryInstruction::SetVariable(ref r) => write!(f, "set_variable {}", r), &QueryInstruction::SetValue(ref r) => - write!(f, "set_value {}", r) + write!(f, "set_value {}", r), + &QueryInstruction::SetVoid(n) => + write!(f, "set_void {}", n) } } } @@ -207,7 +211,7 @@ pub fn eval(wam: &mut Machine, buffer: &str) -> EvalResult &Ok(TopLevel::Predicate(ref clauses)) => { if is_consistent(clauses) { let compiled_pred = cg.compile_predicate(clauses); - wam.add_predicate(clauses, compiled_pred); + wam.add_predicate(clauses, compiled_pred); EvalResult::EntrySuccess } else { @@ -229,8 +233,8 @@ Each predicate must have the same name and arity."; EvalResult::EntrySuccess }, &Ok(TopLevel::Query(ref query)) => { - let compiled_query = cg.compile_query(&query); - wam.run_query(compiled_query, &cg) + let compiled_query = cg.compile_query(&query); + wam.run_query(compiled_query, &cg) }, &Err(_) => { println!("Grammatical error of some kind!"); @@ -251,7 +255,7 @@ pub fn print(wam: &mut Machine, result: EvalResult) { 'outer: loop { let mut result = EvalResult::QueryFailure; let bindings = wam.heap_view(&heap_locs); - + let stdin = stdin(); let mut stdout = stdout().into_raw_mode().unwrap(); diff --git a/src/prolog/machine.rs b/src/prolog/machine.rs index 3e8f3fd3..84dcce11 100644 --- a/src/prolog/machine.rs +++ b/src/prolog/machine.rs @@ -585,6 +585,21 @@ impl MachineState { }; self.s += 1; + }, + &FactInstruction::UnifyVoid(n) => { + match self.mode { + MachineMode::Read => + self.s += n, + MachineMode::Write => { + let h = self.h; + + for i in h .. h + n { + self.heap.push(HeapCellValue::Ref(Ref::HeapCell(i))); + } + + self.h += n; + } + }; } }; } @@ -628,6 +643,15 @@ impl MachineState { self.h += 1; }, + &QueryInstruction::SetVoid(n) => { + let h = self.h; + + for i in h .. h + n { + self.heap.push(HeapCellValue::Ref(Ref::HeapCell(i))); + } + + self.h += n; + } } }