From 9f7d89a3e880a0f08d9d1ad9aa5d6410d3114fcd Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Tue, 15 Oct 2019 02:37:01 -0600 Subject: [PATCH] re: issue #199 --- src/prolog/allocator.rs | 10 +++++- src/prolog/codegen.rs | 46 ++++++++++++++++------------ src/prolog/fixtures.rs | 67 +++++++++++++++++++++++++++-------------- 3 files changed, 80 insertions(+), 43 deletions(-) diff --git a/src/prolog/allocator.rs b/src/prolog/allocator.rs index 922fa769..8af5ab2b 100644 --- a/src/prolog/allocator.rs +++ b/src/prolog/allocator.rs @@ -44,7 +44,11 @@ pub trait Allocator<'a> { fn take_bindings(self) -> AllocVarDict; - fn drain_var_data(&mut self, vs: VariableFixtures<'a>) -> VariableFixtures<'a> { + fn drain_var_data( + &mut self, + vs: VariableFixtures<'a>, + num_of_chunks: usize + ) -> VariableFixtures<'a> { let mut perm_vs = VariableFixtures::new(); for (var, (var_status, cells)) in vs.into_iter() { @@ -52,6 +56,10 @@ pub trait Allocator<'a> { VarStatus::Temp(chunk_num, tvd) => { self.bindings_mut() .insert(var.clone(), VarData::Temp(chunk_num, 0, tvd)); + + if chunk_num + 1 == num_of_chunks { + perm_vs.insert_last_chunk_temp_var(var); + } } VarStatus::Perm(_) => { self.bindings_mut().insert(var.clone(), VarData::Perm(0)); diff --git a/src/prolog/codegen.rs b/src/prolog/codegen.rs index 79c26b00..a6305181 100644 --- a/src/prolog/codegen.rs +++ b/src/prolog/codegen.rs @@ -51,20 +51,32 @@ impl<'a> ConjunctInfo<'a> { self.has_deep_cut as usize } - fn mark_unsafe_vars(&self, mut unsafe_var_marker: UnsafeVarMarker, code: &mut Code) { + fn mark_unsafe_vars>( + &self, + mut unsafe_var_marker: UnsafeVarMarker, + marker: &Alloc, + code: &mut Code + ) { // target the last goal of the rule for handling unsafe variables. // we use this weird logic to find the last goal. - let right_index = if let &Line::Control(_) = code.last().unwrap() { - code.len() - 2 + let right_index = if let Some(Line::Control(_)) = code.last() { + if code.len() >= 2 { + code.len() - 2 + } else { + return; + } } else { - code.len() - 1 + if code.len() >= 1 { + code.len() - 1 + } else { + return; + } }; let mut index = right_index; if let Line::Query(_) = &code[right_index] { while let Line::Query(_) = &code[index] { - // index >= 0. if index == 0 { break; } else { @@ -77,10 +89,10 @@ impl<'a> ConjunctInfo<'a> { index += 1; } - unsafe_var_marker.record_unsafe_vars(&self.perm_vs); + unsafe_var_marker.record_unsafe_vars(&self.perm_vs, marker); - for line in code.iter_mut() { - if let &mut Line::Query(ref mut query_instr) = line { + for line in code.iter() { + if let Line::Query(ref query_instr) = line { unsafe_var_marker.mark_safe_vars(query_instr); } } @@ -269,11 +281,12 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { fn collect_var_data(&mut self, mut iter: ChunkedIterator<'a>) -> ConjunctInfo<'a> { let mut vs = VariableFixtures::new(); - + while let Some((chunk_num, lt_arity, chunked_terms)) = iter.next() { for (i, chunked_term) in chunked_terms.iter().enumerate() { let term_loc = match chunked_term { - &ChunkedTerm::HeadClause(..) => GenContext::Head, + &ChunkedTerm::HeadClause(..) => + GenContext::Head, &ChunkedTerm::BodyTerm(_) => { if i < chunked_terms.len() - 1 { GenContext::Mid(chunk_num) @@ -294,8 +307,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { vs.populate_restricting_sets(); vs.set_perm_vals(has_deep_cut); - let vs = self.marker.drain_var_data(vs); - + let vs = self.marker.drain_var_data(vs, num_of_chunks); ConjunctInfo::new(vs, num_of_chunks, has_deep_cut) } @@ -703,9 +715,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { let iter = ChunkedIterator::from_rule_body(p1, clauses); self.compile_seq(iter, &conjunct_info, &mut code, false)?; - if conjunct_info.allocates() { - conjunct_info.mark_unsafe_vars(unsafe_var_marker, &mut code); - } + conjunct_info.mark_unsafe_vars(unsafe_var_marker, &self.marker, &mut code); Self::compile_cleanup(&mut code, &conjunct_info, clauses.last().unwrap_or(p1)); Ok(code) @@ -747,7 +757,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { vs.mark_vars_in_chunk(post_order_iter(term), term.arity(), GenContext::Head); vs.populate_restricting_sets(); - self.marker.drain_var_data(vs); + self.marker.drain_var_data(vs, 1); let mut code = Vec::new(); @@ -802,9 +812,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { let iter = ChunkedIterator::from_term_sequence(query); self.compile_seq(iter, &conjunct_info, &mut code, true)?; - if conjunct_info.allocates() { - conjunct_info.mark_unsafe_vars(UnsafeVarMarker::new(), &mut code); - } + conjunct_info.mark_unsafe_vars(UnsafeVarMarker::new(), &self.marker, &mut code); if let Some(query_term) = query.last() { Self::compile_cleanup(&mut code, &conjunct_info, query_term); diff --git a/src/prolog/fixtures.rs b/src/prolog/fixtures.rs index e8f944ca..31cc54c5 100644 --- a/src/prolog/fixtures.rs +++ b/src/prolog/fixtures.rs @@ -1,14 +1,14 @@ use prolog_parser::ast::*; +use crate::prolog::allocator::*; use crate::prolog::forms::*; use crate::prolog::instructions::*; use crate::prolog::iterators::*; -use indexmap::IndexMap; +use indexmap::{IndexMap, IndexSet}; use std::cell::Cell; -use std::collections::btree_map::{IntoIter, IterMut, Values}; -use std::collections::{BTreeMap, BTreeSet}; +use std::collections::BTreeSet; use std::mem::swap; use std::rc::Rc; use std::vec::Vec; @@ -79,15 +79,27 @@ impl TempVarData { } type VariableFixture<'a> = (VarStatus, Vec<&'a Cell>); -pub struct VariableFixtures<'a>(BTreeMap, VariableFixture<'a>>); + +pub struct VariableFixtures<'a>{ + perm_vars: IndexMap, VariableFixture<'a>>, + last_chunk_temp_vars: IndexSet> +} impl<'a> VariableFixtures<'a> { pub fn new() -> Self { - VariableFixtures(BTreeMap::new()) + VariableFixtures { + perm_vars: IndexMap::new(), + last_chunk_temp_vars: IndexSet::new() + } + } pub fn insert(&mut self, var: Rc, vs: VariableFixture<'a>) { - self.0.insert(var, vs); + self.perm_vars.insert(var, vs); + } + + pub fn insert_last_chunk_temp_var(&mut self, var: Rc) { + self.last_chunk_temp_vars.insert(var); } // computes no_use and conflict sets for all temp vars. @@ -140,11 +152,11 @@ impl<'a> VariableFixtures<'a> { } fn get_mut(&mut self, u: Rc) -> Option<&mut VariableFixture<'a>> { - self.0.get_mut(&u) + self.perm_vars.get_mut(&u) } - fn iter_mut(&mut self) -> IterMut, VariableFixture<'a>> { - self.0.iter_mut() + fn iter_mut(&mut self) -> indexmap::map::IterMut, VariableFixture<'a>> { + self.perm_vars.iter_mut() } fn record_temp_info(&mut self, tvd: &mut TempVarData, arg_c: usize, term_loc: GenContext) { @@ -179,7 +191,7 @@ impl<'a> VariableFixtures<'a> { for term_ref in iter { if let &TermRef::Var(lvl, cell, ref var) = &term_ref { - let mut status = self.0.remove(var).unwrap_or(( + let mut status = self.perm_vars.remove(var).unwrap_or(( VarStatus::Temp(chunk_num, TempVarData::new(lt_arity)), Vec::new(), )); @@ -195,7 +207,7 @@ impl<'a> VariableFixtures<'a> { _ => status.0 = VarStatus::Perm(chunk_num), }; - self.0.insert(var.clone(), status); + self.perm_vars.insert(var.clone(), status); } if let Level::Shallow = term_ref.level() { @@ -204,16 +216,16 @@ impl<'a> VariableFixtures<'a> { } } - pub fn into_iter(self) -> IntoIter, VariableFixture<'a>> { - self.0.into_iter() + pub fn into_iter(self) -> indexmap::map::IntoIter, VariableFixture<'a>> { + self.perm_vars.into_iter() } - fn values(&self) -> Values, VariableFixture<'a>> { - self.0.values() + fn values(&self) -> indexmap::map::Values, VariableFixture<'a>> { + self.perm_vars.values() } pub fn size(&self) -> usize { - self.0.len() + self.perm_vars.len() } pub fn set_perm_vals(&self, has_deep_cuts: bool) { @@ -248,25 +260,34 @@ impl UnsafeVarMarker { } } - pub fn record_unsafe_vars(&mut self, fixtures: &VariableFixtures) { - for &(_, ref cb) in fixtures.values() { + pub fn record_unsafe_vars<'a, Alloc: Allocator<'a>>( + &mut self, + fixtures: &VariableFixtures, + marker: &Alloc + ) { + for &(_, ref cb) in fixtures.values() { if let Some(index) = cb.first() { if !self.unsafe_vars.contains_key(&index.get().norm()) { self.unsafe_vars.insert(index.get().norm(), false); } } } + + for var in fixtures.last_chunk_temp_vars.iter().cloned() { + let r = marker.get(var); + self.unsafe_vars.insert(r, false); + } } - pub fn mark_safe_vars(&mut self, query_instr: &mut QueryInstruction) { + pub fn mark_safe_vars(&mut self, query_instr: &QueryInstruction) { match query_instr { - &mut QueryInstruction::PutVariable(RegType::Temp(r), _) => { - if let Some(found) = self.unsafe_vars.get_mut(&RegType::Temp(r)) { + QueryInstruction::PutVariable(RegType::Temp(r), _) => { + if let Some(found) = self.unsafe_vars.get_mut(&RegType::Temp(*r)) { *found = true; } } - &mut QueryInstruction::SetVariable(reg) => { - if let Some(found) = self.unsafe_vars.get_mut(®) { + QueryInstruction::SetVariable(reg) => { + if let Some(found) = self.unsafe_vars.get_mut(reg) { *found = true; } } -- 2.54.0