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);
|
||||
}
|
||||
|
||||
/// 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.
|
||||
pub fn last_inst(&self, ebb: Ebb) -> Option<Inst> {
|
||||
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) {
|
||||
dbg!("Coloring {}:", ebb);
|
||||
let mut regs = self.visit_ebb_header(ebb, func, tracker);
|
||||
tracker.drop_dead_args();
|
||||
self.divert.clear();
|
||||
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
self.color_entry_args(&func.signature, args, &mut func.locations)
|
||||
} else {
|
||||
// The live-ins have already been assigned a register. Reconstruct the allocatable set.
|
||||
let regs = self.livein_regs(liveins, func);
|
||||
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.
|
||||
/// These values must already be colored when the dominating blocks were processed.
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
use dominator_tree::DominatorTree;
|
||||
use entity_list::{EntityList, ListPool};
|
||||
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 regalloc::affinity::Affinity;
|
||||
use regalloc::liveness::Liveness;
|
||||
@@ -116,6 +116,12 @@ impl LiveValueVec {
|
||||
let keep = self.live_after(next_inst);
|
||||
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 {
|
||||
@@ -150,12 +156,13 @@ impl LiveValueTracker {
|
||||
///
|
||||
/// 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.
|
||||
/// 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,
|
||||
dfg: &DataFlowGraph,
|
||||
liveness: &Liveness,
|
||||
program_order: &PO,
|
||||
layout: &Layout,
|
||||
domtree: &DominatorTree)
|
||||
-> (&[LiveValue], &[LiveValue]) {
|
||||
// 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");
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
@@ -202,10 +209,14 @@ impl LiveValueTracker {
|
||||
}
|
||||
ExpandedProgramPoint::Ebb(local_ebb) => {
|
||||
// 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,
|
||||
ebb,
|
||||
"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);
|
||||
}
|
||||
|
||||
/// 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`.
|
||||
fn save_idom_live_set(&mut self, idom: Inst) {
|
||||
let values = self.live.values.iter().map(|lv| lv.value);
|
||||
|
||||
Reference in New Issue
Block a user