From: Mark Thom Date: Sat, 25 Mar 2017 07:58:54 +0000 (-0600) Subject: optimized up to section 5.10 X-Git-Tag: v0.8.110~753 X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=d65970ee57d0e781f305bfb1bd595d0aebfb1803;p=scryer-prolog.git optimized up to section 5.10 --- diff --git a/Cargo.lock b/Cargo.lock index 3d66e845..133eaf7a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ [root] name = "rusty-wam" -version = "0.5.7" +version = "0.5.10" 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 a231cab1..067651e7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rusty-wam" -version = "0.5.7" +version = "0.5.10" authors = ["Mark Thom"] build = "build.rs" diff --git a/README.md b/README.md index 4fde54b3..816e2949 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 -to the end of section 5.7, skipping past 5.4. Atoms and lists are the -only two data types currently supported. +end of section 5.9, skipping past 5.4. Atoms and lists are the only +two data types currently supported. While proper environment trimming code is emitted by the code generator, it has no effect on the bytecode WAM, which lacks @@ -21,7 +21,7 @@ frames. ## Tutorial To enter a multi-clause predicate, the brackets ":{" and "}:" are used -as delimiters. They must be entirely contained with their own lines. +as delimiters. They must be contained entirely within their own lines. For example, ``` diff --git a/src/main.rs b/src/main.rs index 1c94c7bd..e83ddb73 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,13 +8,13 @@ use prolog::machine::*; mod tests { use super::*; use prolog::ast::*; - + fn submit(wam: &mut Machine, buffer: &str) -> EvalResult { let result = eval(wam, buffer); wam.reset(); result } - + #[test] fn test_queries_on_facts() { let mut wam = Machine::new(); @@ -90,6 +90,13 @@ mod tests { assert_eq!(submit(&mut wam, "?- p(f(X, g(Y), Z), g(Z), h).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(Z, Y, X).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(f(X, Y, Z), Y, h).").failed_query(), false); + + submit(&mut wam, "p(_, f(_, Y, _)) :- h(Y)."); + submit(&mut wam, "h(y)."); + + assert_eq!(submit(&mut wam, "?- p(_, f(_, Y, _)).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- p(_, f(_, y, _)).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- p(_, f(_, z, _)).").failed_query(), true); } #[test] @@ -110,7 +117,7 @@ mod tests { assert_eq!(submit(&mut wam, "?- p(c, d, X).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(a, a, a).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(b, c, d).").failed_query(), true); - + submit(&mut wam, "p(X, a). p(X, Y) :- q(Z), p(X, X)."); assert_eq!(submit(&mut wam, "?- p(X, Y).").failed_query(), false); @@ -137,7 +144,7 @@ mod tests { assert_eq!(submit(&mut wam, "?- p(a, X).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(b, a).").failed_query(), true); - submit(&mut wam, "p(X, Y, Z) :- q(X), r(Y), s(Z). + submit(&mut wam, "p(X, Y, Z) :- q(X), r(Y), s(Z). p(a, b, Z) :- q(Z)."); submit(&mut wam, "q(x)."); @@ -154,7 +161,7 @@ mod tests { submit(&mut wam, "s(x, t)."); submit(&mut wam, "t(y, u)."); - + assert_eq!(submit(&mut wam, "?- p(X).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(x).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(y).").failed_query(), false); @@ -173,6 +180,18 @@ mod tests { assert_eq!(submit(&mut wam, "?- p(X, X, X).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(X, Y, X).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(f(f(X)), h(f(X)), Y).").failed_query(), true); + + submit(&mut wam, "p(X) :- f(Y), g(Y), i(X, Y)."); + submit(&mut wam, "g(f(a)). g(f(b)). g(f(c))."); + submit(&mut wam, "f(f(a)). f(f(b)). f(f(c))."); + submit(&mut wam, "i(X, X)."); + + assert_eq!(submit(&mut wam, "?- p(X).").failed_query(), false); + + submit(&mut wam, "p(X) :- f(f(Y)), g(Y, f(Y)), i(X, f(Y))."); + submit(&mut wam, "g(Y, f(Y)) :- g(f(Y))."); + + assert_eq!(submit(&mut wam, "?- p(X).").failed_query(), false); } #[test] @@ -224,7 +243,7 @@ mod tests { fn prolog_repl() { let mut wam = Machine::new(); - + loop { print!("prolog> "); @@ -239,7 +258,7 @@ fn prolog_repl() { let result = eval(&mut wam, buffer.trim()); print(&mut wam, result); - + wam.reset(); } } diff --git a/src/prolog/ast.rs b/src/prolog/ast.rs index c387e759..9a725186 100644 --- a/src/prolog/ast.rs +++ b/src/prolog/ast.rs @@ -1,4 +1,5 @@ use std::cell::Cell; +use std::cmp::Ordering; use std::collections::HashMap; use std::ops::{Add, AddAssign}; use std::vec::Vec; @@ -40,7 +41,7 @@ pub enum Level { Deep, Shallow } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, PartialEq, Eq, Hash)] pub enum RegType { Perm(usize), Temp(usize) @@ -83,7 +84,7 @@ impl VarReg { pub fn is_temp(self) -> bool { !self.norm().is_perm() } - + pub fn root_register(self) -> usize { match self { VarReg::ArgAndNorm(_, root) => root, @@ -139,8 +140,9 @@ pub enum FactInstruction { GetList(Level, RegType), GetStructure(Level, Atom, usize, RegType), GetValue(RegType, usize), - GetVariable(RegType, usize), + GetVariable(RegType, usize), UnifyConstant(Constant), + UnifyLocalValue(RegType), UnifyVariable(RegType), UnifyValue(RegType), UnifyVoid(usize) @@ -150,9 +152,11 @@ pub enum QueryInstruction { PutConstant(Level, Constant, RegType), PutList(Level, RegType), PutStructure(Level, Atom, usize, RegType), + PutUnsafeValue(usize, usize), PutValue(RegType, usize), PutVariable(RegType, usize), SetConstant(Constant), + SetLocalValue(RegType), SetVariable(RegType), SetValue(RegType), SetVoid(usize) @@ -196,6 +200,7 @@ impl<'a> From<&'a Line> for LineOrCodeOffset<'a> { pub type Code = Vec; + #[derive(Clone, PartialEq)] pub enum Addr { Con(Constant), @@ -220,6 +225,13 @@ impl Addr { _ => None } } + + pub fn is_protected(&self, e: usize) -> bool { + match self { + &Addr::StackCell(fr, _) if fr > e => false, + _ => true + } + } } impl From for Addr { @@ -275,6 +287,26 @@ impl HeapCellValue { } } +impl PartialOrd for Ref { + fn partial_cmp(&self, other: &Self) -> Option { + match (*self, *other) { + (Ref::HeapCell(hc1), Ref::HeapCell(hc2)) => + Some(hc1.cmp(&hc2)), + (Ref::HeapCell(_), _) => + Some(Ordering::Less), + (Ref::StackCell(fr1, sc1), Ref::StackCell(fr2, sc2)) => + if fr1 < fr2 { + Some(Ordering::Less) + } else if fr1 == fr2 { + Some(sc1.cmp(&sc2)) + } else { + Some(Ordering::Greater) + }, + _ => Some(Ordering::Greater) + } + } +} + #[derive(Clone, Copy)] pub enum CodePtr { DirEntry(usize), diff --git a/src/prolog/codegen.rs b/src/prolog/codegen.rs index a8e83ad5..4c5592ae 100644 --- a/src/prolog/codegen.rs +++ b/src/prolog/codegen.rs @@ -250,7 +250,8 @@ enum VarStatus { } pub struct CodeGenerator<'a> { - marker: TermMarker<'a> + marker: TermMarker<'a>, + var_count: HashMap<&'a Var, usize> } type VariableFixture<'a> = (VarStatus, Vec<&'a Cell>); @@ -258,37 +259,41 @@ type VariableFixtures<'a> = HashMap<&'a Var, VariableFixture<'a>>; impl<'a> CodeGenerator<'a> { pub fn new() -> Self { - CodeGenerator { marker: TermMarker::new() } + CodeGenerator { marker: TermMarker::new(), + var_count: HashMap::new() } } pub fn vars(&self) -> &HashMap<&Var, VarReg> { &self.marker.bindings } - #[allow(dead_code)] - fn count_vars(term: &Term) -> HashMap<&Var, usize> { + fn update_var_count(&mut self, iter: Iter) + where Iter : Iterator> + { 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); + for term in iter { + if let TermRef::Var(_, _, var) = term { + if self.marker.contains_var(var) { + var_count.insert(var, 2); + continue; + } + + let entry = var_count.entry(var).or_insert(0); *entry += 1; } } - var_count + self.var_count = var_count; } - #[allow(dead_code)] - fn all_singleton_vars(terms: &Vec>, - var_count: &HashMap<&Var, usize>) - -> bool + fn all_singleton_vars(&self, terms: &Vec>) -> 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 { + if self.var_count.get(var).unwrap() != &1 { return false; }, _ => return false @@ -298,7 +303,6 @@ impl<'a> CodeGenerator<'a> { true } - #[allow(dead_code)] fn void_subterms(subterms: usize) -> Target where Target: CompilationTarget<'a> { @@ -416,7 +420,6 @@ impl<'a> CodeGenerator<'a> { { let iter = Target::iter(term); let mut target = Vec::new(); - let var_count = Self::count_vars(term); for term in iter { match term { @@ -424,7 +427,7 @@ impl<'a> CodeGenerator<'a> { target.push(self.to_structure(lvl, cell, atom, terms.len())); if !has_exposed_vars { - if Self::all_singleton_vars(terms, &var_count) { + if self.all_singleton_vars(terms) { target.push(Self::void_subterms(terms.len())); continue; } @@ -547,7 +550,7 @@ impl<'a> CodeGenerator<'a> { for &(term_status, _) in vs.values() { if let VarStatus::Permanent(i) = term_status { - if i >= index { + if i > index { var_count += 1; } } @@ -556,17 +559,85 @@ impl<'a> CodeGenerator<'a> { var_count } + fn lco(body: &mut Code, rule: &'a Rule) -> usize { + let last_arity = rule.last_clause().arity(); + let mut dealloc_index = body.len() - 1; + + match rule.last_clause() { + &Term::Clause(_, ref name, _) + | &Term::Constant(_, Constant::Atom(ref name)) => { + if let &mut Line::Control(ref mut ctrl) = body.last_mut().unwrap() { + *ctrl = ControlInstruction::Execute(name.clone(), last_arity); + } + }, + _ => dealloc_index = body.len() + }; + + dealloc_index + } + + fn mark_unsafe_query_vars(head: &Term, + vs: &VariableFixtures, + query: &mut CompiledQuery) + { + let mut unsafe_vars = HashMap::new(); + + for &(_, ref cb) in vs.values() { + if !cb.is_empty() { + let index = cb.first().unwrap().get().norm(); + unsafe_vars.insert(index, false); + } + } + + for term_ref in head.breadth_first_iter() { + match term_ref { + TermRef::Var(_, cell, _) => { + unsafe_vars.remove(&cell.get().norm()); + }, + _ => {} + }; + } + + for query_instr in query.iter_mut() { + match query_instr { + &mut QueryInstruction::PutValue(RegType::Perm(i), arg) => + if let Some(found) = unsafe_vars.get_mut(&RegType::Perm(i)) { + if !*found { + *found = true; + *query_instr = QueryInstruction::PutUnsafeValue(i, arg); + } + }, + &mut QueryInstruction::SetVariable(reg) + | &mut QueryInstruction::PutVariable(reg, _) => + if let Some(found) = unsafe_vars.get_mut(®) { + *found = true; + }, + &mut QueryInstruction::SetValue(reg) => + if let Some(found) = unsafe_vars.get_mut(®) { + if !*found { + *found = true; + *query_instr = QueryInstruction::SetLocalValue(reg); + } + }, + _ => {} + }; + } + } + pub fn compile_rule(&mut self, rule: &'a Rule) -> Code { let vs = Self::mark_perm_vars(&rule); let &Rule { head: (ref p0, ref p1), ref clauses } = rule; - let perm_vars = Self::vars_above_threshold(&vs, 1); + let perm_vars = Self::vars_above_threshold(&vs, 0); let mut body = Vec::new(); if clauses.len() > 0 { body.push(Line::Control(ControlInstruction::Allocate(perm_vars))); } + let iter = p0.breadth_first_iter().chain(p1.breadth_first_iter()); + self.update_var_count(iter); + self.marker.advance(p0); body.push(Line::Fact(self.compile_target(p0, false))); @@ -577,7 +648,7 @@ impl<'a> CodeGenerator<'a> { body = clauses.iter().enumerate() .map(|(i, ref term)| { - let num_vars = Self::vars_above_threshold(&vs, i+2); + let num_vars = Self::vars_above_threshold(&vs, i+1); self.compile_internal_query(term, num_vars) }) .fold(body, |mut body, ref mut cqs| { @@ -585,19 +656,19 @@ impl<'a> CodeGenerator<'a> { body }); - // now perform LCO. - let last_arity = rule.last_clause().arity(); - let mut dealloc_index = body.len() - 1; + if clauses.len() > 0 { + let mut index = body.len() - 1; - match rule.last_clause() { - &Term::Clause(_, ref name, _) - | &Term::Constant(_, Constant::Atom(ref name)) => { - if let &mut Line::Control(ref mut ctrl) = body.last_mut().unwrap() { - *ctrl = ControlInstruction::Execute(name.clone(), last_arity); - } - }, - _ => dealloc_index = body.len() - }; + if let &Line::Control(_) = body.last().unwrap() { + index -= 1; + } + + if let &mut Line::Query(ref mut query) = &mut body[index] { + Self::mark_unsafe_query_vars(p0, &vs, query); + } + } + + let dealloc_index = Self::lco(&mut body, &rule); if clauses.len() > 0 { body.insert(dealloc_index, Line::Control(ControlInstruction::Deallocate)); @@ -606,18 +677,51 @@ impl<'a> CodeGenerator<'a> { body } + fn mark_unsafe_fact_vars(fact: &mut CompiledFact, bindings: &HashMap<&Var, VarReg>) + { + let mut unsafe_vars = HashMap::new(); + + for var_reg in bindings.values() { + unsafe_vars.insert(var_reg.norm(), false); + } + + for fact_instr in fact.iter_mut() { + match fact_instr { + &mut FactInstruction::UnifyValue(reg) => + if let Some(found) = unsafe_vars.get_mut(®) { + if !*found { + *found = true; + *fact_instr = FactInstruction::UnifyLocalValue(reg); + } + }, + &mut FactInstruction::UnifyVariable(reg) => { + if let Some(found) = unsafe_vars.get_mut(®) { + *found = true; + } + }, + _ => {} + }; + } + } + pub fn compile_fact(&mut self, term: &'a Term) -> Code { self.marker.advance(term); + self.update_var_count(term.breadth_first_iter()); - let mut compiled_fact = vec![Line::Fact(self.compile_target(term, false))]; + let mut compiled_fact = self.compile_target(term, false); + Self::mark_unsafe_fact_vars(&mut compiled_fact, self.vars()); + + let mut compiled_fact = vec![Line::Fact(compiled_fact)]; let proceed = Line::Control(ControlInstruction::Proceed); compiled_fact.push(proceed); compiled_fact } - fn compile_internal_query(&mut self, term: &'a Term, index: usize) -> Code { + fn compile_internal_query(&mut self, term: &'a Term, index: usize) -> Code + { self.marker.advance(term); + self.update_var_count(term.breadth_first_iter()); let mut compiled_query = vec![Line::Query(self.compile_target(term, false))]; Self::add_conditional_call(&mut compiled_query, term, index); @@ -627,9 +731,10 @@ impl<'a> CodeGenerator<'a> { pub fn compile_query(&mut self, term: &'a Term) -> Code { self.marker.advance(term); + self.update_var_count(term.breadth_first_iter()); let mut compiled_query = vec![Line::Query(self.compile_target(term, true))]; - Self::add_conditional_call(&mut compiled_query, term, 1); + Self::add_conditional_call(&mut compiled_query, term, 0); compiled_query } diff --git a/src/prolog/io.rs b/src/prolog/io.rs index 58c5d9e7..298d5782 100644 --- a/src/prolog/io.rs +++ b/src/prolog/io.rs @@ -44,6 +44,8 @@ impl fmt::Display for FactInstruction { write!(f, "unify_constant {}", constant), &FactInstruction::UnifyVariable(ref r) => write!(f, "unify_variable {}", r), + &FactInstruction::UnifyLocalValue(ref r) => + write!(f, "unify_local_value {}", r), &FactInstruction::UnifyValue(ref r) => write!(f, "unify_value {}", r), &FactInstruction::UnifyVoid(n) => @@ -67,12 +69,16 @@ impl fmt::Display for QueryInstruction { write!(f, "put_structure {}/{}, {}", name, arity, r), &QueryInstruction::PutStructure(Level::Shallow, ref name, ref arity, ref r) => write!(f, "put_structure {}/{}, A{}", name, arity, r.reg_num()), + &QueryInstruction::PutUnsafeValue(y, a) => + write!(f, "put_unsafe_value Y{}, A{}", y, a), &QueryInstruction::PutValue(ref x, ref a) => write!(f, "put_value {}, A{}", x, a), &QueryInstruction::PutVariable(ref x, ref a) => write!(f, "put_variable {}, A{}", x, a), &QueryInstruction::SetConstant(ref constant) => write!(f, "set_constant {}", constant), + &QueryInstruction::SetLocalValue(ref r) => + write!(f, "set_local_value {}", r), &QueryInstruction::SetVariable(ref r) => write!(f, "set_variable {}", r), &QueryInstruction::SetValue(ref r) => @@ -213,6 +219,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); + print_code(&compiled_pred); wam.add_predicate(clauses, compiled_pred); EvalResult::EntrySuccess @@ -226,16 +233,18 @@ Each predicate must have the same name and arity."; }, &Ok(TopLevel::Fact(ref fact)) => { let compiled_fact = cg.compile_fact(&fact); + print_code(&compiled_fact); wam.add_fact(fact, compiled_fact); EvalResult::EntrySuccess }, &Ok(TopLevel::Rule(ref rule)) => { let compiled_rule = cg.compile_rule(&rule); + print_code(&compiled_rule); wam.add_rule(rule, compiled_rule); EvalResult::EntrySuccess }, &Ok(TopLevel::Query(ref query)) => { - let compiled_query = cg.compile_query(&query); + let compiled_query = cg.compile_query(&query); wam.run_query(compiled_query, &cg) }, &Err(_) => { diff --git a/src/prolog/machine.rs b/src/prolog/machine.rs index 591bec27..1ad06e61 100644 --- a/src/prolog/machine.rs +++ b/src/prolog/machine.rs @@ -463,6 +463,7 @@ impl MachineState { _ => self.fail = true }; }, + &FactInstruction::GetList(_, reg) => { let addr = self.deref(self[reg].clone()); @@ -536,10 +537,14 @@ impl MachineState { let addr = self.deref(Addr::HeapCell(self.s)); match self.store(addr) { - Addr::HeapCell(hc) => - self.heap[hc] = HeapCellValue::Con(c.clone()), - Addr::StackCell(fr, sc) => - self.and_stack[fr][sc] = Addr::Con(c.clone()), + Addr::HeapCell(hc) => { + self.heap[hc] = HeapCellValue::Con(c.clone()); + self.trail(Ref::HeapCell(hc)); + }, + Addr::StackCell(fr, sc) => { + self.and_stack[fr][sc] = Addr::Con(c.clone()); + self.trail(Ref::StackCell(fr, sc)); + }, Addr::Con(c1) => { if c1 != *c { self.fail = true; @@ -569,6 +574,39 @@ impl MachineState { self.s += 1; }, + &FactInstruction::UnifyLocalValue(reg) => { + let s = self.s; + + match self.mode { + MachineMode::Read => { + let reg_addr = self[reg].clone(); + self.unify(reg_addr, Addr::HeapCell(s)); + }, + MachineMode::Write => { + let addr = self.deref(self[reg].clone()); + let h = self.h; + + if let Addr::HeapCell(hc) = addr { + if hc < h { + let val = self.heap[hc].clone(); + self.heap.push(val); + + self.h += 1; + self.s += 1; + + return; + } + } + + self.heap.push(HeapCellValue::Ref(Ref::HeapCell(h))); + self.bind(Ref::HeapCell(h), addr); + + self.h += 1; + } + }; + + self.s += 1; + }, &FactInstruction::UnifyValue(reg) => { let s = self.s; @@ -615,21 +653,63 @@ impl MachineState { self[reg] = Addr::Str(self.h); self.h += 1; }, + &QueryInstruction::PutUnsafeValue(n, arg) => { + let e = self.e; + let addr = self.deref(Addr::StackCell(e, n)); + + if addr.is_protected(e) { + self.registers[arg] = self.store(addr); + } else { + let h = self.h; + + self.heap.push(HeapCellValue::Ref(Ref::HeapCell(h))); + self.bind(Ref::HeapCell(h), addr); + + self.registers[arg] = self.heap[h].as_addr(h); + self.h += 1; + } + }, &QueryInstruction::PutValue(norm, arg) => self.registers[arg] = self[norm].clone(), &QueryInstruction::PutVariable(norm, arg) => { - let h = self.h; - self.heap.push(HeapCellValue::Ref(Ref::HeapCell(h))); + match norm { + RegType::Perm(n) => { + let e = self.e; + self[norm] = Addr::StackCell(e, n); + self.registers[arg] = self[norm].clone(); + }, + RegType::Temp(_) => { + let h = self.h; + self.heap.push(HeapCellValue::Ref(Ref::HeapCell(h))); - self[norm] = Addr::HeapCell(h); - self.registers[arg] = Addr::HeapCell(h); + self[norm] = Addr::HeapCell(h); + self.registers[arg] = Addr::HeapCell(h); - self.h += 1; + self.h += 1; + } + }; }, &QueryInstruction::SetConstant(ref constant) => { self.heap.push(HeapCellValue::Con(constant.clone())); self.h += 1; }, + &QueryInstruction::SetLocalValue(reg) => { + let addr = self.deref(self[reg].clone()); + let h = self.h; + + if let Addr::HeapCell(hc) = addr { + if hc < h { + self.heap.push(HeapCellValue::from(addr)); + self.h += 1; + return; + } + } + + self.heap.push(HeapCellValue::Ref(Ref::HeapCell(h))); + self.bind(Ref::HeapCell(h), addr); + + self.h += 1; + }, &QueryInstruction::SetVariable(reg) => { let h = self.h; self.heap.push(HeapCellValue::Ref(Ref::HeapCell(h))); @@ -681,7 +761,7 @@ impl MachineState { }, &ControlInstruction::Deallocate => { let e = self.e; - + self.cp = self.and_stack[e].cp; self.e = self.and_stack[e].e;