Keep dead EBB arguments around in LiveValueTracker::ebb_top().
Provide a drop_dead_args() function which deletes them instead. We still need to assign a register to dead EBB arguments, so they can't just be ignored.
This commit is contained in:
@@ -435,6 +435,11 @@ impl Layout {
|
|||||||
self.assign_inst_seq(inst);
|
self.assign_inst_seq(inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Fetch an ebb's first instruction.
|
||||||
|
pub fn first_inst(&self, ebb: Ebb) -> Option<Inst> {
|
||||||
|
self.ebbs[ebb].first_inst.into()
|
||||||
|
}
|
||||||
|
|
||||||
/// Fetch an ebb's last instruction.
|
/// Fetch an ebb's last instruction.
|
||||||
pub fn last_inst(&self, ebb: Ebb) -> Option<Inst> {
|
pub fn last_inst(&self, ebb: Ebb) -> Option<Inst> {
|
||||||
self.ebbs[ebb].last_inst.into()
|
self.ebbs[ebb].last_inst.into()
|
||||||
|
|||||||
@@ -129,6 +129,7 @@ impl<'a> Context<'a> {
|
|||||||
fn visit_ebb(&mut self, ebb: Ebb, func: &mut Function, tracker: &mut LiveValueTracker) {
|
fn visit_ebb(&mut self, ebb: Ebb, func: &mut Function, tracker: &mut LiveValueTracker) {
|
||||||
dbg!("Coloring {}:", ebb);
|
dbg!("Coloring {}:", ebb);
|
||||||
let mut regs = self.visit_ebb_header(ebb, func, tracker);
|
let mut regs = self.visit_ebb_header(ebb, func, tracker);
|
||||||
|
tracker.drop_dead_args();
|
||||||
self.divert.clear();
|
self.divert.clear();
|
||||||
|
|
||||||
// Now go through the instructions in `ebb` and color the values they define.
|
// Now go through the instructions in `ebb` and color the values they define.
|
||||||
@@ -162,15 +163,25 @@ impl<'a> Context<'a> {
|
|||||||
tracker.ebb_top(ebb, &func.dfg, self.liveness, &func.layout, self.domtree);
|
tracker.ebb_top(ebb, &func.dfg, self.liveness, &func.layout, self.domtree);
|
||||||
|
|
||||||
// Arguments to the entry block have ABI constraints.
|
// Arguments to the entry block have ABI constraints.
|
||||||
if func.layout.entry_block() == Some(ebb) {
|
let mut regs = if func.layout.entry_block() == Some(ebb) {
|
||||||
assert_eq!(liveins.len(), 0);
|
assert_eq!(liveins.len(), 0);
|
||||||
self.color_entry_args(&func.signature, args, &mut func.locations)
|
self.color_entry_args(&func.signature, args, &mut func.locations)
|
||||||
} else {
|
} else {
|
||||||
// The live-ins have already been assigned a register. Reconstruct the allocatable set.
|
// The live-ins have already been assigned a register. Reconstruct the allocatable set.
|
||||||
let regs = self.livein_regs(liveins, func);
|
let regs = self.livein_regs(liveins, func);
|
||||||
self.color_args(args, regs, &mut func.locations)
|
self.color_args(args, regs, &mut func.locations)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Now forget about the dead arguments.
|
||||||
|
for lv in args.iter().filter(|&lv| lv.is_dead) {
|
||||||
|
if let Affinity::Reg(rci) = lv.affinity {
|
||||||
|
let rc = self.reginfo.rc(rci);
|
||||||
|
let reg = func.locations[lv.value].unwrap_reg();
|
||||||
|
regs.free(rc, reg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
regs
|
||||||
|
}
|
||||||
|
|
||||||
/// Initialize a set of allocatable registers from the values that are live-in to a block.
|
/// Initialize a set of allocatable registers from the values that are live-in to a block.
|
||||||
/// These values must already be colored when the dominating blocks were processed.
|
/// These values must already be colored when the dominating blocks were processed.
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
use dominator_tree::DominatorTree;
|
use dominator_tree::DominatorTree;
|
||||||
use entity_list::{EntityList, ListPool};
|
use entity_list::{EntityList, ListPool};
|
||||||
use ir::instructions::BranchInfo;
|
use ir::instructions::BranchInfo;
|
||||||
use ir::{Inst, Ebb, Value, DataFlowGraph, ProgramOrder, ExpandedProgramPoint};
|
use ir::{Inst, Ebb, Value, DataFlowGraph, Layout, ExpandedProgramPoint};
|
||||||
use partition_slice::partition_slice;
|
use partition_slice::partition_slice;
|
||||||
use regalloc::affinity::Affinity;
|
use regalloc::affinity::Affinity;
|
||||||
use regalloc::liveness::Liveness;
|
use regalloc::liveness::Liveness;
|
||||||
@@ -116,6 +116,12 @@ impl LiveValueVec {
|
|||||||
let keep = self.live_after(next_inst);
|
let keep = self.live_after(next_inst);
|
||||||
self.values.truncate(keep);
|
self.values.truncate(keep);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Remove any dead values.
|
||||||
|
fn remove_dead_values(&mut self) {
|
||||||
|
self.values.retain(|v| !v.is_dead);
|
||||||
|
self.live_prefix = None;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LiveValueTracker {
|
impl LiveValueTracker {
|
||||||
@@ -150,12 +156,13 @@ impl LiveValueTracker {
|
|||||||
///
|
///
|
||||||
/// Returns `(liveins, args)` as a pair of slices. The first slice is the set of live-in values
|
/// Returns `(liveins, args)` as a pair of slices. The first slice is the set of live-in values
|
||||||
/// from the immediate dominator. The second slice is the set of `ebb` arguments that are live.
|
/// from the immediate dominator. The second slice is the set of `ebb` arguments that are live.
|
||||||
/// Dead arguments with no uses are ignored and not added to the set.
|
///
|
||||||
pub fn ebb_top<PO: ProgramOrder>(&mut self,
|
/// Dead arguments with no uses are included in `args`. Call `drop_dead_args()` to remove them.
|
||||||
|
pub fn ebb_top(&mut self,
|
||||||
ebb: Ebb,
|
ebb: Ebb,
|
||||||
dfg: &DataFlowGraph,
|
dfg: &DataFlowGraph,
|
||||||
liveness: &Liveness,
|
liveness: &Liveness,
|
||||||
program_order: &PO,
|
layout: &Layout,
|
||||||
domtree: &DominatorTree)
|
domtree: &DominatorTree)
|
||||||
-> (&[LiveValue], &[LiveValue]) {
|
-> (&[LiveValue], &[LiveValue]) {
|
||||||
// Start over, compute the set of live values at the top of the EBB from two sources:
|
// Start over, compute the set of live values at the top of the EBB from two sources:
|
||||||
@@ -183,7 +190,7 @@ impl LiveValueTracker {
|
|||||||
.expect("Immediate dominator value has no live range");
|
.expect("Immediate dominator value has no live range");
|
||||||
|
|
||||||
// Check if this value is live-in here.
|
// Check if this value is live-in here.
|
||||||
if let Some(endpoint) = lr.livein_local_end(ebb, program_order) {
|
if let Some(endpoint) = lr.livein_local_end(ebb, layout) {
|
||||||
self.live.push(value, endpoint, lr);
|
self.live.push(value, endpoint, lr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -202,10 +209,14 @@ impl LiveValueTracker {
|
|||||||
}
|
}
|
||||||
ExpandedProgramPoint::Ebb(local_ebb) => {
|
ExpandedProgramPoint::Ebb(local_ebb) => {
|
||||||
// This is a dead EBB argument which is not even live into the first
|
// This is a dead EBB argument which is not even live into the first
|
||||||
// instruction in the EBB. We can ignore it.
|
// instruction in the EBB.
|
||||||
assert_eq!(local_ebb,
|
assert_eq!(local_ebb,
|
||||||
ebb,
|
ebb,
|
||||||
"EBB argument live range ends at wrong EBB header");
|
"EBB argument live range ends at wrong EBB header");
|
||||||
|
// Give this value a fake endpoint that is the first instruction in the EBB.
|
||||||
|
// We expect it to be removed by calling `drop_dead_args()`.
|
||||||
|
self.live
|
||||||
|
.push(value, layout.first_inst(ebb).expect("Empty EBB"), lr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -281,6 +292,13 @@ impl LiveValueTracker {
|
|||||||
self.live.remove_kill_values(inst);
|
self.live.remove_kill_values(inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Drop any values that are marked as `is_dead`.
|
||||||
|
///
|
||||||
|
/// Use this after calling `ebb_top` to clean out dead EBB arguments.
|
||||||
|
pub fn drop_dead_args(&mut self) {
|
||||||
|
self.live.remove_dead_values();
|
||||||
|
}
|
||||||
|
|
||||||
/// Save the current set of live values so it is associated with `idom`.
|
/// Save the current set of live values so it is associated with `idom`.
|
||||||
fn save_idom_live_set(&mut self, idom: Inst) {
|
fn save_idom_live_set(&mut self, idom: Inst) {
|
||||||
let values = self.live.values.iter().map(|lv| lv.value);
|
let values = self.live.values.iter().map(|lv| lv.value);
|
||||||
|
|||||||
Reference in New Issue
Block a user