backtrack on emission of unsafe register instructions on internal branches
This commit is contained in:
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user