backtrack on emission of unsafe register instructions on internal branches

This commit is contained in:
Mark
2023-06-22 18:28:10 -06:00
parent 0e583d620a
commit 9ea6cb4cab
3 changed files with 39 additions and 44 deletions

View File

@@ -103,25 +103,15 @@ impl BranchCodeStack {
for (inner_idx, code) in self.stack[idx].iter_mut().enumerate() { for (inner_idx, code) in self.stack[idx].iter_mut().enumerate() {
if inner_idx + 1 == inner_len { if inner_idx + 1 == inner_len {
jump_span -= code.len() + 1; // = jump_span.saturating_sub(code.len() + 1); jump_span -= code.len() + 1;
} else { } else {
jump_span -= code.len() + 1; jump_span -= code.len() + 1;
code.push_back(instr!("jmp_by_call", jump_span as usize)); code.push_back(instr!("jmp_by_call", jump_span as usize));
// saturate at 0 if underflow happens, which only
// happens when jump_span is no longer needed
// anyway. still, we don't want to panic at
// underflow.
jump_span -= 1; jump_span -= 1;
} }
} }
} }
// eliminate terminating jump instruction in last arm of last
// branch.
// self.stack.last_mut()
// .and_then(|branch| branch.last_mut())
// .map(|code| code.pop_back());
} }
fn pop_branch(&mut self, depth: usize, settings: CodeGenSettings) -> CodeDeque { fn pop_branch(&mut self, depth: usize, settings: CodeGenSettings) -> CodeDeque {
@@ -1242,14 +1232,6 @@ impl<'b> CodeGenerator<'b> {
code.extend(code_segment.into_iter()); code.extend(code_segment.into_iter());
} }
/*
for line in &code {
println!("{:?}", line);
}
println!("");
*/
Ok(code) Ok(code)
} }
} }

View File

@@ -75,7 +75,17 @@ impl DebrayAllocator {
self.branch_stack.push(BranchOccurrences::new(num_branches)); self.branch_stack.push(BranchOccurrences::new(num_branches));
} }
pub(crate) fn current_branch_designator(&self) -> BranchDesignator {
let num_branches = self.branch_stack.len();
let current_branch = self.branch_stack.last()
.map(|occurrences| occurrences.current_branch)
.unwrap_or(0);
BranchDesignator((num_branches, current_branch))
}
pub(crate) fn add_branch(&mut self) { pub(crate) fn add_branch(&mut self) {
let branch_designator = self.current_branch_designator();
let branch_occurrences = self.branch_stack.last_mut().unwrap(); let branch_occurrences = self.branch_stack.last_mut().unwrap();
for var_num in branch_occurrences.subsumed_hits.drain(..) { for var_num in branch_occurrences.subsumed_hits.drain(..) {
@@ -83,11 +93,11 @@ impl DebrayAllocator {
VarAlloc::Perm(_, ref mut allocation) => { VarAlloc::Perm(_, ref mut allocation) => {
match allocation { match allocation {
PermVarAllocation::Done { shallow_safety, deep_safety, .. } => { PermVarAllocation::Done { shallow_safety, deep_safety, .. } => {
if !shallow_safety.unneeded() { if !shallow_safety.is_unneeded(branch_designator) {
branch_occurrences.shallow_safety.insert(var_num); branch_occurrences.shallow_safety.insert(var_num);
} }
if !deep_safety.unneeded() { if !deep_safety.is_unneeded(branch_designator) {
branch_occurrences.deep_safety.insert(var_num); branch_occurrences.deep_safety.insert(var_num);
} }
} }
@@ -128,6 +138,8 @@ impl DebrayAllocator {
(deep_safety, shallow_safety) (deep_safety, shallow_safety)
}); });
let branch_designator = self.current_branch_designator();
let (deep_safety, shallow_safety) = match self.branch_stack.last_mut() { let (deep_safety, shallow_safety) = match self.branch_stack.last_mut() {
Some(latest_branch) => { Some(latest_branch) => {
latest_branch.deep_safety.union_with(&deep_safety); latest_branch.deep_safety.union_with(&deep_safety);
@@ -143,10 +155,12 @@ impl DebrayAllocator {
VarAlloc::Perm(_, ref mut allocation) => { VarAlloc::Perm(_, ref mut allocation) => {
let shallow_safety = VarSafetyStatus::needed_if( let shallow_safety = VarSafetyStatus::needed_if(
shallow_safety.contains(var_num), shallow_safety.contains(var_num),
branch_designator,
); );
let deep_safety = VarSafetyStatus::needed_if( let deep_safety = VarSafetyStatus::needed_if(
deep_safety.contains(var_num), deep_safety.contains(var_num),
branch_designator,
); );
*allocation = PermVarAllocation::Done { shallow_safety, deep_safety }; *allocation = PermVarAllocation::Done { shallow_safety, deep_safety };
@@ -415,10 +429,12 @@ impl DebrayAllocator {
pub(crate) fn mark_temp_to_safe_perm(&mut self, var_num: usize) { pub(crate) fn mark_temp_to_safe_perm(&mut self, var_num: usize) {
match &self.var_data.records[var_num].allocation { match &self.var_data.records[var_num].allocation {
&VarAlloc::Temp { to_perm_var_num: Some(perm_var_num), .. } => { &VarAlloc::Temp { to_perm_var_num: Some(perm_var_num), .. } => {
let branch_designator = self.current_branch_designator();
match &mut self.var_data.records[perm_var_num].allocation { match &mut self.var_data.records[perm_var_num].allocation {
VarAlloc::Perm(_, PermVarAllocation::Done { deep_safety, shallow_safety, .. }) => { VarAlloc::Perm(_, PermVarAllocation::Done { deep_safety, shallow_safety, .. }) => {
*deep_safety = VarSafetyStatus::Unneeded; *deep_safety = VarSafetyStatus::unneeded(branch_designator);
*shallow_safety = VarSafetyStatus::Unneeded; *shallow_safety = VarSafetyStatus::unneeded(branch_designator);
} }
_ => unreachable!() _ => unreachable!()
} }
@@ -429,14 +445,16 @@ impl DebrayAllocator {
} }
fn mark_safe_var(&mut self, var_num: usize, lvl: Level, term_loc: GenContext) { fn mark_safe_var(&mut self, var_num: usize, lvl: Level, term_loc: GenContext) {
let branch_designator = self.current_branch_designator();
match &mut self.var_data.records[var_num].allocation { match &mut self.var_data.records[var_num].allocation {
VarAlloc::Perm(_, PermVarAllocation::Done { deep_safety, shallow_safety, .. }) => { VarAlloc::Perm(_, PermVarAllocation::Done { deep_safety, shallow_safety, .. }) => {
// GetVariable in head chunk is considered safe. // GetVariable in head chunk is considered safe.
if lvl == Level::Deep { if lvl == Level::Deep {
*deep_safety = VarSafetyStatus::Unneeded; *deep_safety = VarSafetyStatus::unneeded(branch_designator);
*shallow_safety = VarSafetyStatus::Unneeded; *shallow_safety = VarSafetyStatus::unneeded(branch_designator);
} else if term_loc == GenContext::Head { } else if term_loc == GenContext::Head {
*shallow_safety = VarSafetyStatus::Unneeded; *shallow_safety = VarSafetyStatus::GloballyUnneeded;
} else { } else {
if let Some(temp_var_num) = self.shallow_temp_mappings.get(&self.arg_c).cloned() { if let Some(temp_var_num) = self.shallow_temp_mappings.get(&self.arg_c).cloned() {
match &mut self.var_data.records[temp_var_num].allocation { match &mut self.var_data.records[temp_var_num].allocation {
@@ -449,7 +467,7 @@ impl DebrayAllocator {
} }
} }
VarAlloc::Temp { ref mut safety, .. } => { VarAlloc::Temp { ref mut safety, .. } => {
*safety = VarSafetyStatus::Unneeded; *safety = VarSafetyStatus::GloballyUnneeded;
} }
_ => { _ => {
unreachable!() unreachable!()
@@ -463,20 +481,22 @@ impl DebrayAllocator {
r: RegType, r: RegType,
arg_c: usize, arg_c: usize,
) -> Instruction { ) -> Instruction {
let branch_designator = self.current_branch_designator();
match &mut self.var_data.records[var_num].allocation { match &mut self.var_data.records[var_num].allocation {
VarAlloc::Perm(_, PermVarAllocation::Done { ref mut shallow_safety, .. }) => { VarAlloc::Perm(_, PermVarAllocation::Done { ref mut shallow_safety, .. }) => {
if !self.in_tail_position || shallow_safety.unneeded() { if !self.in_tail_position || shallow_safety.is_unneeded(branch_designator) {
Target::argument_to_value(r, arg_c) Target::argument_to_value(r, arg_c)
} else { } else {
*shallow_safety = VarSafetyStatus::Unneeded; *shallow_safety = VarSafetyStatus::unneeded(branch_designator);
Target::unsafe_argument_to_value(r, arg_c) Target::unsafe_argument_to_value(r, arg_c)
} }
} }
VarAlloc::Temp { ref mut safety, .. } => { VarAlloc::Temp { ref mut safety, .. } => {
if safety.unneeded() { if safety.is_unneeded(branch_designator) {
Target::argument_to_value(r, arg_c) Target::argument_to_value(r, arg_c)
} else { } else {
*safety = VarSafetyStatus::Unneeded; *safety = VarSafetyStatus::GloballyUnneeded;
Target::unsafe_argument_to_value(r, arg_c) Target::unsafe_argument_to_value(r, arg_c)
} }
} }
@@ -491,20 +511,22 @@ impl DebrayAllocator {
var_num: usize, var_num: usize,
r: RegType, r: RegType,
) -> Instruction { ) -> Instruction {
let branch_designator = self.current_branch_designator();
match &mut self.var_data.records[var_num].allocation { match &mut self.var_data.records[var_num].allocation {
VarAlloc::Perm(_, PermVarAllocation::Done { ref mut deep_safety, .. }) => { VarAlloc::Perm(_, PermVarAllocation::Done { ref mut deep_safety, .. }) => {
if deep_safety.unneeded() { if deep_safety.is_unneeded(branch_designator) {
Target::subterm_to_value(r) Target::subterm_to_value(r)
} else { } else {
*deep_safety = VarSafetyStatus::Unneeded; *deep_safety = VarSafetyStatus::unneeded(branch_designator);
Target::unsafe_subterm_to_value(r) Target::unsafe_subterm_to_value(r)
} }
} }
VarAlloc::Temp { ref mut safety, .. } => { VarAlloc::Temp { ref mut safety, .. } => {
if safety.unneeded() { if safety.is_unneeded(branch_designator) {
Target::subterm_to_value(r) Target::subterm_to_value(r)
} else { } else {
*safety = VarSafetyStatus::Unneeded; *safety = VarSafetyStatus::unneeded(branch_designator);
Target::unsafe_subterm_to_value(r) Target::unsafe_subterm_to_value(r)
} }
} }

View File

@@ -839,12 +839,3 @@ impl BranchMap {
var_data var_data
} }
} }
#[cfg(test)]
mod tests {
#[test]
fn disjunct_compilation() {
let mut wam = MachineState::new();
let mut op_dir = default_op_dir();
}
}