From cf6a47272a7074b7a3d1a96001da11ed2911a276 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Mon, 4 Dec 2017 21:01:23 -0700 Subject: [PATCH] inline comparison instructions. --- src/prolog/arithmetic.rs | 21 +++-------- src/prolog/ast.rs | 18 +++++----- src/prolog/codegen.rs | 76 ++++++++++++++++++++++------------------ src/prolog/io.rs | 18 ++++------ src/prolog/iterators.rs | 9 ++--- src/prolog/machine.rs | 57 ++++++++++++------------------ src/prolog/macros.rs | 28 +++++++++------ src/prolog/parser | 2 +- 8 files changed, 108 insertions(+), 121 deletions(-) diff --git a/src/prolog/arithmetic.rs b/src/prolog/arithmetic.rs index 8f00940e..b80ccedc 100644 --- a/src/prolog/arithmetic.rs +++ b/src/prolog/arithmetic.rs @@ -8,6 +8,8 @@ pub struct ArithExprIterator<'a> { state_stack: Vec> } +pub type ArithCont = (Code, Option); + impl<'a> ArithExprIterator<'a> { fn push_subterm(&mut self, lvl: Level, term: &'a Term) { self.state_stack.push(IteratorState::to_state(lvl, term)); @@ -73,14 +75,13 @@ impl<'a> Iterator for ArithExprIterator<'a> { pub struct ArithmeticEvaluator<'a> { bindings: &'a AllocVarDict<'a>, - target_int: usize, interm: Vec, interm_c: usize } impl<'a> ArithmeticEvaluator<'a> { pub fn new(bindings: &'a AllocVarDict<'a>, target_int: usize) -> Self { - ArithmeticEvaluator { bindings, target_int, interm: Vec::new(), interm_c: target_int } + ArithmeticEvaluator { bindings, interm: Vec::new(), interm_c: target_int } } fn get_unary_instr(name: &Atom, a1: ArithmeticTerm, t: usize) @@ -180,7 +181,7 @@ impl<'a> ArithmeticEvaluator<'a> { Ok(()) } - pub fn eval(&mut self, term: &Term) -> Result { + pub fn eval(&mut self, term: &Term) -> Result { let mut code = Vec::new(); for term_ref in term.arith_expr_iter()? { @@ -212,18 +213,6 @@ impl<'a> ArithmeticEvaluator<'a> { } } - - if let Some(arith_term) = self.interm.pop() { - let t = self.target_int; - - match arith_term { - n @ ArithmeticTerm::Integer(_) => code.push(move_at!(n, t)), - n @ ArithmeticTerm::Float(_) => code.push(move_at!(n, t)), - r @ ArithmeticTerm::Reg(_) => code.push(move_at!(r, t)), - _ => {} - }; - } - - Ok(code) + Ok((code, self.interm.pop())) } } diff --git a/src/prolog/ast.rs b/src/prolog/ast.rs index 9578467b..77d5ca02 100644 --- a/src/prolog/ast.rs +++ b/src/prolog/ast.rs @@ -315,6 +315,7 @@ pub enum Term { } pub enum InlinedQueryTerm { + CompareNumber(CompareNumberQT, Vec>), IsAtomic(Vec>), IsVar(Vec>) } @@ -322,8 +323,9 @@ pub enum InlinedQueryTerm { impl InlinedQueryTerm { pub fn arity(&self) -> usize { match self { + &InlinedQueryTerm::CompareNumber(_, _) => 2, &InlinedQueryTerm::IsAtomic(_) => 1, - &InlinedQueryTerm::IsVar(_) => 1 + &InlinedQueryTerm::IsVar(_) => 1 } } } @@ -341,7 +343,6 @@ pub enum CompareNumberQT { pub enum QueryTerm { CallN(Vec>), Catch(Vec>), - CompareNumber(CompareNumberQT, Vec>), Cut, Is(Vec>), Inlined(InlinedQueryTerm), @@ -353,7 +354,6 @@ impl QueryTerm { pub fn arity(&self) -> usize { match self { &QueryTerm::Catch(_) => 3, - &QueryTerm::CompareNumber(_, _) => 2, &QueryTerm::Throw(_) => 1, &QueryTerm::Inlined(ref term) => term.arity(), &QueryTerm::Is(_) => 2, @@ -709,6 +709,7 @@ pub enum ArithmeticInstruction { pub enum BuiltInInstruction { CleanUpBlock, + CompareNumber(CompareNumberQT, ArithmeticTerm, ArithmeticTerm), DuplicateTerm, EraseBall, Fail, @@ -735,10 +736,8 @@ pub enum ControlInstruction { Execute(Atom, usize), ExecuteN(usize), Goto(usize, usize), // p, arity. - CompareNumberCall(CompareNumberQT), - CompareNumberExecute(CompareNumberQT), - IsCall(RegType), - IsExecute(RegType), + IsCall(RegType, ArithmeticTerm), + IsExecute(RegType, ArithmeticTerm), Proceed, ThrowCall, ThrowExecute, @@ -757,8 +756,8 @@ impl ControlInstruction { &ControlInstruction::ThrowExecute => true, &ControlInstruction::Goto(_, _) => true, &ControlInstruction::Proceed => true, - &ControlInstruction::IsCall(_) => true, - &ControlInstruction::IsExecute(_) => true, + &ControlInstruction::IsCall(_, _) => true, + &ControlInstruction::IsExecute(_, _) => true, _ => false } } @@ -790,7 +789,6 @@ pub enum FactInstruction { } pub enum QueryInstruction { - MoveArithmeticTerm(ArithmeticTerm, usize), GetVariable(RegType, usize), PutConstant(Level, Constant, RegType), PutList(Level, RegType), diff --git a/src/prolog/codegen.rs b/src/prolog/codegen.rs index c1784829..2dac5839 100644 --- a/src/prolog/codegen.rs +++ b/src/prolog/codegen.rs @@ -230,12 +230,16 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker> ConjunctInfo::new(vs, num_of_chunks, has_deep_cut) } - fn add_conditional_call_inlined(term: &InlinedQueryTerm, code: &mut Code) + fn add_conditional_call_inlined(_: &InlinedQueryTerm, code: &mut Code) { + code.push(proceed!()); + + /* match term { &InlinedQueryTerm::IsAtomic(_) | &InlinedQueryTerm::IsVar(_) => code.push(proceed!()) }; + */ } fn add_conditional_call(code: &mut Code, qt: &QueryTerm, pvs: usize) @@ -276,10 +280,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker> *ctrl = ControlInstruction::Execute(name, arity), ControlInstruction::CallN(arity) => *ctrl = ControlInstruction::ExecuteN(arity), - ControlInstruction::CompareNumberCall(cmp) => - *ctrl = ControlInstruction::CompareNumberExecute(cmp), - ControlInstruction::IsCall(r) => - *ctrl = ControlInstruction::IsExecute(r), + ControlInstruction::IsCall(r, at) => + *ctrl = ControlInstruction::IsExecute(r, at), ControlInstruction::CatchCall => *ctrl = ControlInstruction::CatchExecute, ControlInstruction::ThrowCall => @@ -293,21 +295,33 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker> } fn compile_inlined(&mut self, term: &'a InlinedQueryTerm, term_loc: GenContext, code: &mut Code) + -> Result<(), ParserError> { match term { + &InlinedQueryTerm::CompareNumber(cmp, ref terms) => { + let (mut lcode, at_1) = self.call_arith_eval(terms[0].as_ref(), 1)?; + let (mut rcode, at_2) = self.call_arith_eval(terms[1].as_ref(), 2)?; + + code.append(&mut lcode); + code.append(&mut rcode); + + code.push(compare_number_instr!(cmp, + at_1.unwrap_or(interm!(1)), + at_2.unwrap_or(interm!(2)))); + }, &InlinedQueryTerm::IsAtomic(ref inner_term) => - match inner_term[0].as_ref() { - &Term::AnonVar | &Term::Clause(_, _, _) | &Term::Cons(_, _, _) => { - code.push(fail!()); - }, - &Term::Constant(_, _) => { - code.push(succeed!()); - }, - &Term::Var(ref vr, ref name) => { - let r = self.mark_non_callable(name, 1, term_loc, vr, code); - code.push(is_atomic!(r)); - } - }, + match inner_term[0].as_ref() { + &Term::AnonVar | &Term::Clause(_, _, _) | &Term::Cons(_, _, _) => { + code.push(fail!()); + }, + &Term::Constant(_, _) => { + code.push(succeed!()); + }, + &Term::Var(ref vr, ref name) => { + let r = self.mark_non_callable(name, 1, term_loc, vr, code); + code.push(is_atomic!(r)); + } + }, &InlinedQueryTerm::IsVar(ref inner_term) => match inner_term[0].as_ref() { &Term::Constant(_, _) | &Term::Clause(_, _, _) | &Term::Cons(_, _, _) => { @@ -322,9 +336,12 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker> } } } + + Ok(()) } - fn call_arith_eval(&self, term: &'a Term, target_int: usize) -> Result { + fn call_arith_eval(&self, term: &'a Term, target_int: usize) -> Result + { let mut evaluator = ArithmeticEvaluator::new(self.marker.bindings(), target_int); evaluator.eval(term) } @@ -360,10 +377,10 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker> }); }, &QueryTerm::Inlined(ref term) => - self.compile_inlined(term, term_loc, code), + self.compile_inlined(term, term_loc, code)?, &QueryTerm::Is(ref terms) => { - let mut arith_code = self.call_arith_eval(terms[1].as_ref(), 1)?; - code.append(&mut arith_code); + let (mut acode, at) = try!(self.call_arith_eval(terms[1].as_ref(), 1)); + code.append(&mut acode); match terms[0].as_ref() { &Term::Var(ref vr, ref name) => { @@ -373,35 +390,26 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker> vr, code); - code.push(is_call!(r)); + code.push(is_call!(r, at.unwrap_or(interm!(1)))); }, &Term::Constant(_, Constant::Float(fl)) => { code.push(query![put_constant!(Level::Shallow, Constant::Float(fl), temp_v!(1))]); - code.push(is_call!(temp_v!(1))); + code.push(is_call!(temp_v!(1), at.unwrap_or(interm!(1)))); }, &Term::Constant(_, Constant::Integer(ref bi)) => { let bi = bi.clone(); code.push(query![put_constant!(Level::Shallow, Constant::Integer(bi), temp_v!(1))]); - code.push(is_call!(temp_v!(1))); + code.push(is_call!(temp_v!(1), at.unwrap_or(interm!(1)))); }, _ => { code.push(fail!()); } } - }, - &QueryTerm::CompareNumber(cmp, ref terms) => { - let mut larith_code = self.call_arith_eval(terms[0].as_ref(), 1)?; - let mut rarith_code = self.call_arith_eval(terms[1].as_ref(), 2)?; - - code.append(&mut larith_code); - code.append(&mut rarith_code); - - code.push(compare_number_call!(cmp)); - }, + }, _ if chunk_num == 0 => { self.marker.reset_arg(term.arity()); diff --git a/src/prolog/io.rs b/src/prolog/io.rs index ccede041..298ecb35 100644 --- a/src/prolog/io.rs +++ b/src/prolog/io.rs @@ -46,8 +46,6 @@ impl fmt::Display for FactInstruction { impl fmt::Display for QueryInstruction { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - &QueryInstruction::MoveArithmeticTerm(ref at, ref r) => - write!(f, "move_arithmetic_term {}, {}", at, r), &QueryInstruction::GetVariable(ref x, ref a) => write!(f, "query:get_variable {}, A{}", x, a), &QueryInstruction::PutConstant(Level::Shallow, ref constant, ref r) => @@ -107,11 +105,7 @@ impl fmt::Display for ControlInstruction { &ControlInstruction::CatchCall => write!(f, "call_catch"), &ControlInstruction::CatchExecute => - write!(f, "execute_catch"), - &ControlInstruction::CompareNumberCall(cmp) => - write!(f, "n_compare_call {}", cmp), - &ControlInstruction::CompareNumberExecute(cmp) => - write!(f, "n_compare_execute {}", cmp), + write!(f, "execute_catch"), &ControlInstruction::ExecuteN(arity) => write!(f, "execute_N {}", arity), &ControlInstruction::Deallocate => @@ -126,10 +120,10 @@ impl fmt::Display for ControlInstruction { write!(f, "call_throw"), &ControlInstruction::ThrowExecute => write!(f, "execute_throw"), - &ControlInstruction::IsCall(r) => - write!(f, "is_call {}", r), - &ControlInstruction::IsExecute(r) => - write!(f, "is_execute {}", r), + &ControlInstruction::IsCall(r, ref at) => + write!(f, "is_call {}, {}", r, at), + &ControlInstruction::IsExecute(r, ref at) => + write!(f, "is_execute {}, {}", r, at), } } } @@ -153,6 +147,8 @@ impl fmt::Display for BuiltInInstruction { match self { &BuiltInInstruction::CleanUpBlock => write!(f, "clean_up_block"), + &BuiltInInstruction::CompareNumber(cmp, ref at_1, ref at_2) => + write!(f, "number_test {}, {}, {} ", cmp, at_1, at_2), &BuiltInInstruction::DuplicateTerm => write!(f, "duplicate_term X1"), &BuiltInInstruction::EraseBall => diff --git a/src/prolog/iterators.rs b/src/prolog/iterators.rs index 9471619a..62002207 100644 --- a/src/prolog/iterators.rs +++ b/src/prolog/iterators.rs @@ -40,9 +40,10 @@ impl<'a> QueryIterator<'a> { let state = IteratorState::Clause(0, ClauseType::Catch, terms); QueryIterator { state_stack: vec![state] } }, - &QueryTerm::CompareNumber(_, ref terms) | &QueryTerm::Is(ref terms) => { - let state = IteratorState::Clause(0, ClauseType::Is, terms); - QueryIterator { state_stack: vec![state] } + &QueryTerm::Inlined(InlinedQueryTerm::CompareNumber(_, ref terms)) + | &QueryTerm::Is(ref terms) => { + let state = IteratorState::Clause(0, ClauseType::Is, terms); + QueryIterator { state_stack: vec![state] } }, &QueryTerm::Inlined(InlinedQueryTerm::IsAtomic(ref terms)) | &QueryTerm::Inlined(InlinedQueryTerm::IsVar(ref terms)) => @@ -270,7 +271,7 @@ impl<'a> ChunkedIterator<'a> arity = child_terms.len(); break; }, - &QueryTerm::Is(_) | &QueryTerm::CompareNumber(_, _) => { + &QueryTerm::Is(_) => { result.push(term); arity = 2; break; diff --git a/src/prolog/machine.rs b/src/prolog/machine.rs index 939b81fb..73d5eb8f 100644 --- a/src/prolog/machine.rs +++ b/src/prolog/machine.rs @@ -1379,10 +1379,6 @@ impl MachineState { fn execute_query_instr(&mut self, instr: &QueryInstruction) { match instr { - &QueryInstruction::MoveArithmeticTerm(ref at, t) => { - let n = try_or_fail!(self, self.get_number(at)); - self.interms[t - 1] = n; - }, &QueryInstruction::GetVariable(norm, arg) => self[norm] = self.registers[arg].clone(), &QueryInstruction::PutConstant(_, ref constant, reg) => @@ -1609,6 +1605,22 @@ impl MachineState { fn execute_built_in_instr(&mut self, code_dir: &CodeDir, instr: &BuiltInInstruction) { match instr { + &BuiltInInstruction::CompareNumber(cmp, ref at_1, ref at_2) => { + let n1 = try_or_fail!(self, self.get_number(at_1)); + let n2 = try_or_fail!(self, self.get_number(at_2)); + + self.fail = match cmp { + CompareNumberQT::GreaterThan if !(n1.gt(n2)) => true, + CompareNumberQT::GreaterThanOrEqual if !(n1.gte(n2)) => true, + CompareNumberQT::LessThan if !(n1.lt(n2)) => true, + CompareNumberQT::LessThanOrEqual if !(n1.lte(n2)) => true, + CompareNumberQT::NotEqual if !(n1.ne(n2)) => true, + CompareNumberQT::Equal if !(n1.eq(n2)) => true, + _ => false + }; + + self.p += 1; + }, &BuiltInInstruction::DuplicateTerm => { let old_h = self.h; @@ -1743,21 +1755,6 @@ impl MachineState { } }; } - - fn handle_n_compare(&mut self, cmp: CompareNumberQT) { - let n1 = self.interms[0].clone(); - let n2 = self.interms[1].clone(); - - self.fail = match cmp { - CompareNumberQT::GreaterThan if !(n1.gt(n2)) => true, - CompareNumberQT::GreaterThanOrEqual if !(n1.gte(n2)) => true, - CompareNumberQT::LessThan if !(n1.lt(n2)) => true, - CompareNumberQT::LessThanOrEqual if !(n1.lte(n2)) => true, - CompareNumberQT::NotEqual if !(n1.ne(n2)) => true, - CompareNumberQT::Equal if !(n1.eq(n2)) => true, - _ => false - }; - } fn execute_ctrl_instr(&mut self, code_dir: &CodeDir, instr: &ControlInstruction) { @@ -1837,27 +1834,19 @@ impl MachineState { }, &ControlInstruction::ThrowExecute => { self.goto_throw(); - }, - &ControlInstruction::CompareNumberCall(cmp) => { - self.handle_n_compare(cmp); - self.p += 1; - }, - &ControlInstruction::CompareNumberExecute(cmp) => { - self.handle_n_compare(cmp); - self.p = self.cp; - }, - &ControlInstruction::IsCall(r) => { + }, + &ControlInstruction::IsCall(r, ref at) => { let a1 = self[r].clone(); - let a2 = Addr::Con(Constant::from(self.interms[0].clone())); + let a2 = try_or_fail!(self, self.get_number(at)); - self.unify(a1, a2); + self.unify(a1, Addr::Con(Constant::from(a2))); self.p += 1; }, - &ControlInstruction::IsExecute(r) => { + &ControlInstruction::IsExecute(r, ref at) => { let a1 = self[r].clone(); - let a2 = Addr::Con(Constant::from(self.interms[0].clone())); + let a2 = try_or_fail!(self, self.get_number(at)); - self.unify(a1, a2); + self.unify(a1, Addr::Con(Constant::from(a2))); self.p = self.cp; } }; diff --git a/src/prolog/macros.rs b/src/prolog/macros.rs index d2ec77f8..3398a36b 100644 --- a/src/prolog/macros.rs +++ b/src/prolog/macros.rs @@ -16,9 +16,21 @@ macro_rules! deallocate { ) } -macro_rules! move_at { - ($at:expr, $r:expr) => ( - Line::Query(vec![QueryInstruction::MoveArithmeticTerm($at, $r)]) +macro_rules! compare_number { + ($cmp: expr, $terms: expr) => ( + QueryTerm::Inlined(InlinedQueryTerm::CompareNumber($cmp, $terms)) + ) +} + +macro_rules! compare_number_instr { + ($cmp: expr, $at_1: expr, $at_2: expr) => ( + Line::BuiltIn(BuiltInInstruction::CompareNumber($cmp, $at_1, $at_2)) + ) +} + +macro_rules! interm { + ($n: expr) => ( + ArithmeticTerm::Interm($n) ) } @@ -50,12 +62,6 @@ macro_rules! fact { ) } -macro_rules! compare_number_call { - ($cmp: expr) => ( - Line::Control(ControlInstruction::CompareNumberCall($cmp)) - ) -} - macro_rules! temp_v { ($x:expr) => ( RegType::Temp($x) @@ -216,8 +222,8 @@ macro_rules! unify { } macro_rules! is_call { - ($r:expr) => ( - Line::Control(ControlInstruction::IsCall($r)) + ($r:expr, $at:expr) => ( + Line::Control(ControlInstruction::IsCall($r, $at)) ) } diff --git a/src/prolog/parser b/src/prolog/parser index c1058528..87230857 160000 --- a/src/prolog/parser +++ b/src/prolog/parser @@ -1 +1 @@ -Subproject commit c1058528434bb05237a034449adcfeb56e4b6214 +Subproject commit 87230857805adcfff30c8f0257179e87c531fb21 -- 2.54.0