actually do lco, and mark unsafe variables before the goals where they last occur, not just in the last goal

This commit is contained in:
Mark Thom
2020-02-26 21:57:57 -07:00
parent 1d79e22468
commit 993c6f0e7b
4 changed files with 116 additions and 116 deletions

View File

@@ -11,7 +11,7 @@ use crate::prolog::iterators::*;
use crate::prolog::machine::machine_indices::*;
use crate::prolog::targets::*;
use indexmap::IndexMap;
use indexmap::{IndexMap, IndexSet};
use std::cell::Cell;
use std::rc::Rc;
@@ -50,56 +50,45 @@ impl<'a> ConjunctInfo<'a> {
self.has_deep_cut as usize
}
fn mark_unsafe_vars<Alloc: Allocator<'a>>(
fn mark_unsafe_vars(
&self,
mut unsafe_var_marker: UnsafeVarMarker,
marker: &Alloc,
code: &mut Code
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 Some(Line::Control(_)) = code.last() {
if code.len() >= 2 {
code.len() - 2
} else {
return;
}
} else {
if code.len() >= 1 {
code.len() - 1
} else {
return;
}
};
if code.is_empty() {
return;
}
let mut index = right_index;
let mut code_index = 0;
if let Line::Query(_) = &code[right_index] {
while let Line::Query(_) = &code[index] {
if index == 0 {
break;
} else {
index -= 1;
for phase in 0 .. {
while let Line::Query(ref query_instr) = &code[code_index] {
if !unsafe_var_marker.mark_safe_vars(query_instr) {
unsafe_var_marker.mark_phase(query_instr, phase);
}
code_index += 1;
}
if let Line::Query(_) = &code[index] {
if code_index + 1 < code.len() {
code_index += 1;
} else {
index += 1;
break;
}
}
code_index = 0;
for phase in 0 .. {
while let Line::Query(ref mut query_instr) = &mut code[code_index] {
unsafe_var_marker.mark_unsafe_vars(query_instr, phase);
code_index += 1;
}
unsafe_var_marker.record_unsafe_vars(&self.perm_vs, marker);
for line in code.iter() {
if let Line::Query(ref query_instr) = line {
unsafe_var_marker.mark_safe_vars(query_instr);
}
}
for index in index..right_index + 1 {
if let &mut Line::Query(ref mut query_instr) = &mut code[index] {
unsafe_var_marker.mark_unsafe_vars(query_instr);
}
if code_index + 1 < code.len() {
code_index += 1;
} else {
break;
}
}
}
@@ -684,6 +673,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
head: (_, ref args, ref p1),
ref clauses,
} = rule;
let mut code = Vec::new();
self.marker.reset_at_head(args);
@@ -705,39 +695,31 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
let iter = ChunkedIterator::from_rule_body(p1, clauses);
self.compile_seq(iter, &conjunct_info, &mut code, false)?;
conjunct_info.mark_unsafe_vars(unsafe_var_marker, &self.marker, &mut code);
conjunct_info.mark_unsafe_vars(unsafe_var_marker, &mut code);
Self::compile_cleanup(&mut code, &conjunct_info, clauses.last().unwrap_or(p1));
Ok(code)
}
fn mark_unsafe_fact_vars(&self, fact: &mut CompiledFact) -> UnsafeVarMarker {
let mut unsafe_vars = IndexMap::new();
for var_status in self.marker.bindings().values() {
unsafe_vars.insert(var_status.as_reg_type(), false);
}
let mut safe_vars = IndexSet::new();
for fact_instr in fact.iter_mut() {
match fact_instr {
&mut FactInstruction::UnifyValue(reg) => {
if let Some(found) = unsafe_vars.get_mut(&reg) {
if !*found {
*found = true;
*fact_instr = FactInstruction::UnifyLocalValue(reg);
}
&mut FactInstruction::UnifyValue(r) => {
if !safe_vars.contains(&r) {
*fact_instr = FactInstruction::UnifyLocalValue(r);
safe_vars.insert(r);
}
}
&mut FactInstruction::UnifyVariable(reg) => {
if let Some(found) = unsafe_vars.get_mut(&reg) {
*found = true;
}
&mut FactInstruction::UnifyVariable(r) => {
safe_vars.insert(r);
}
_ => {}
};
}
}
UnsafeVarMarker { unsafe_vars }
UnsafeVarMarker::from_safe_vars(safe_vars)
}
pub fn compile_fact<'b: 'a>(&mut self, term: &'b Term) -> Code {
@@ -802,7 +784,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
let iter = ChunkedIterator::from_term_sequence(query);
self.compile_seq(iter, &conjunct_info, &mut code, true)?;
conjunct_info.mark_unsafe_vars(UnsafeVarMarker::new(), &self.marker, &mut code);
conjunct_info.mark_unsafe_vars(UnsafeVarMarker::new(), &mut code);
if let Some(query_term) = query.last() {
Self::compile_cleanup(&mut code, &conjunct_info, query_term);

View File

@@ -1,6 +1,5 @@
use prolog_parser::ast::*;
use crate::prolog::allocator::*;
use crate::prolog::forms::*;
use crate::prolog::instructions::*;
use crate::prolog::iterators::*;
@@ -91,7 +90,7 @@ impl<'a> VariableFixtures<'a> {
perm_vars: IndexMap::new(),
last_chunk_temp_vars: IndexSet::new()
}
}
pub fn insert(&mut self, var: Rc<Var>, vs: VariableFixture<'a>) {
@@ -250,67 +249,67 @@ impl<'a> VariableFixtures<'a> {
}
pub struct UnsafeVarMarker {
pub unsafe_vars: IndexMap<RegType, bool>,
pub unsafe_vars: IndexMap<RegType, usize>,
pub safe_vars: IndexSet<RegType>,
}
impl UnsafeVarMarker {
pub fn new() -> Self {
UnsafeVarMarker {
unsafe_vars: IndexMap::new(),
safe_vars: IndexSet::new()
}
}
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 from_safe_vars(safe_vars: IndexSet<RegType>) -> Self {
UnsafeVarMarker {
unsafe_vars: IndexMap::new(),
safe_vars
}
}
pub fn mark_safe_vars(&mut self, query_instr: &QueryInstruction) {
pub fn mark_safe_vars(&mut self, query_instr: &QueryInstruction) -> bool {
match query_instr {
QueryInstruction::PutVariable(RegType::Temp(r), _) => {
if let Some(found) = self.unsafe_vars.get_mut(&RegType::Temp(*r)) {
*found = true;
}
&QueryInstruction::PutVariable(r @ RegType::Temp(_), _)
| &QueryInstruction::SetVariable(r) => {
self.safe_vars.insert(r);
true
}
QueryInstruction::SetVariable(reg) => {
if let Some(found) = self.unsafe_vars.get_mut(reg) {
*found = true;
}
_ => {
false
}
}
}
pub fn mark_phase(&mut self, query_instr: &QueryInstruction, phase: usize) {
match query_instr {
&QueryInstruction::PutValue(r @ RegType::Perm(_), _)
| &QueryInstruction::SetValue(r) => {
let p = self.unsafe_vars.entry(r).or_insert(0);
*p = phase;
}
_ => {}
}
}
pub fn mark_unsafe_vars(&mut self, query_instr: &mut QueryInstruction) {
pub fn mark_unsafe_vars(&mut self, query_instr: &mut QueryInstruction, phase: usize) {
match query_instr {
&mut QueryInstruction::PutValue(RegType::Perm(i), arg) => {
if let Some(found) = self.unsafe_vars.get_mut(&RegType::Perm(i)) {
if !*found {
*found = true;
if let Some(p) = self.unsafe_vars.swap_remove(&RegType::Perm(i)) {
if p == phase {
*query_instr = QueryInstruction::PutUnsafeValue(i, arg);
self.safe_vars.insert(RegType::Perm(i));
} else {
self.unsafe_vars.insert(RegType::Perm(i), p);
}
}
}
&mut QueryInstruction::SetValue(reg) => {
if let Some(found) = self.unsafe_vars.get_mut(&reg) {
if !*found {
*found = true;
*query_instr = QueryInstruction::SetLocalValue(reg);
}
&mut QueryInstruction::SetValue(r) => {
if !self.safe_vars.contains(&r) {
*query_instr = QueryInstruction::SetLocalValue(r);
self.safe_vars.insert(r);
self.unsafe_vars.remove(&r);
}
}
_ => {}

View File

@@ -225,9 +225,12 @@ impl Index<RegType> for MachineState {
impl IndexMut<RegType> for MachineState {
fn index_mut(&mut self, reg: RegType) -> &mut Self::Output {
match reg {
RegType::Temp(temp) => &mut self.registers[temp],
RegType::Temp(temp) => {
&mut self.registers[temp]
}
RegType::Perm(perm) => {
let e = self.e;
&mut self.stack.index_and_frame_mut(e)[perm]
}
}
@@ -274,10 +277,10 @@ impl MachineState {
fn try_char_list(&self, addrs: Vec<Addr>) -> Result<String, MachineError> {
let mut chars = String::new();
let mut iter = addrs.iter();
while let Some(addr) = iter.next() {
let addr = self.store(self.deref(addr.clone()));
match addr {
Addr::Con(Constant::String(n, ref s))
if self.flags.double_quotes.is_chars() => {

View File

@@ -49,7 +49,8 @@ macro_rules! try_or_fail {
}
impl MachineState {
pub(crate) fn new() -> Self {
pub(crate)
fn new() -> Self {
MachineState {
s: 0,
p: CodePtr::default(),
@@ -78,7 +79,8 @@ impl MachineState {
}
}
pub(crate) fn with_small_heap() -> Self {
pub(crate)
fn with_small_heap() -> Self {
MachineState {
s: 0,
p: CodePtr::default(),
@@ -441,6 +443,7 @@ impl MachineState {
pub(super)
fn unify(&mut self, a1: Addr, a2: Addr) {
let mut pdl = vec![a1, a2];
let mut tabu_list: IndexSet<(Addr, Addr)> = IndexSet::new();
self.fail = false;
@@ -600,7 +603,8 @@ impl MachineState {
}
}
pub(super) fn trail(&mut self, r: TrailRef) {
pub(super)
fn trail(&mut self, r: TrailRef) {
match r {
TrailRef::Ref(Ref::HeapCell(h)) => {
if h < self.hb {
@@ -641,7 +645,8 @@ impl MachineState {
}
}
pub(super) fn unwind_trail(&mut self, a1: usize, a2: usize) {
pub(super)
fn unwind_trail(&mut self, a1: usize, a2: usize) {
// the sequence is reversed to respect the chronology of trail
// additions, now that deleted attributes can be undeleted by
// backtracking.
@@ -674,7 +679,8 @@ impl MachineState {
}
}
pub(super) fn tidy_trail(&mut self) {
pub(super)
fn tidy_trail(&mut self) {
if self.b == 0 {
return;
}
@@ -846,7 +852,9 @@ impl MachineState {
{
interms.push(Number::Float(OrderedFloat(f64::consts::PI)))
}
_ => return Err(self.error_form(MachineError::instantiation_error(), caller)),
_ => {
return Err(self.error_form(MachineError::instantiation_error(), caller));
}
}
}
@@ -1284,7 +1292,8 @@ impl MachineState {
}
}
pub(super) fn execute_arith_instr(&mut self, instr: &ArithmeticInstruction) {
pub(super)
fn execute_arith_instr(&mut self, instr: &ArithmeticInstruction) {
let stub = MachineError::functor_stub(clause_name!("(is)"), 2);
match instr {
@@ -1594,7 +1603,8 @@ impl MachineState {
self.mode = MachineMode::Read;
}
pub(super) fn execute_fact_instr(&mut self, instr: &FactInstruction) {
pub(super)
fn execute_fact_instr(&mut self, instr: &FactInstruction) {
match instr {
&FactInstruction::GetConstant(_, ref c, reg) => {
let addr = self[reg].clone();
@@ -1759,7 +1769,8 @@ impl MachineState {
};
}
pub(super) fn execute_indexing_instr(&mut self, instr: &IndexingInstruction) {
pub(super)
fn execute_indexing_instr(&mut self, instr: &IndexingInstruction) {
match instr {
&IndexingInstruction::SwitchOnTerm(v, c, l, s) => {
let a1 = self.registers[1].clone();
@@ -1898,12 +1909,9 @@ impl MachineState {
let addr = self.deref(self[reg].clone());
let h = self.heap.h();
if let Addr::HeapCell(hc) = addr {
if hc < h {
let heap_val = self.heap[hc].clone();
self.heap.push(heap_val);
return;
}
if addr < Ref::HeapCell(h) {
self.heap.push(HeapCellValue::Addr(addr));
return;
}
self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h)));
@@ -1915,7 +1923,7 @@ impl MachineState {
self[reg] = Addr::HeapCell(h);
}
&QueryInstruction::SetValue(reg) => {
let heap_val = self[reg].clone();
let heap_val = self.store(self[reg].clone());
self.heap.push(HeapCellValue::Addr(heap_val));
}
&QueryInstruction::SetVoid(n) => {
@@ -3197,6 +3205,10 @@ impl MachineState {
self.cp = frame.prelude.cp;
self.e = frame.prelude.e;
if e > self.b {
self.stack.truncate(e);
}
self.p += 1;
}
@@ -3406,6 +3418,10 @@ impl MachineState {
if b > b0 {
self.b = b0;
self.tidy_trail();
if b > self.e {
self.stack.truncate(b);
}
}
self.p += 1;