optimizations

This commit is contained in:
Mark Thom
2017-03-22 22:30:45 -06:00
parent 540a5b805f
commit 9362aa6af3
7 changed files with 147 additions and 37 deletions

View File

@@ -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 {

View File

@@ -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<RegType>) {
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<Box<Term>>,
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<Target>(subterms: usize) -> Target
where Target: CompilationTarget<'a>
{
Target::to_void(subterms)
}
fn to_structure<Target>(&mut self,
lvl: Level,
cell: &'a Cell<RegType>,
@@ -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<Target>(&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<Target>(&mut self,
lvl: Level,
cell: &'a Cell<VarReg>,
@@ -371,17 +424,26 @@ impl<'a> CodeGenerator<'a> {
}
}
fn compile_target<Target>(&mut self, term: &'a Term) -> Vec<Target>
fn compile_target<Target>(&mut self, term: &'a Term, has_exposed_vars: bool)
-> Vec<Target>
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

View File

@@ -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();

View File

@@ -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;
}
}
}