Update to rustfmt-preview (#348)
* Update to rustfmt-preview. * Run "cargo fmt --all" with rustfmt 0.4.1. rustfmt 0.4.1 is the latest release of rustfmt-preview available on the stable channel. * Fix a long line that rustfmt 0.4.1 can't handle. * Remove unneeded commas left behind by rustfmt.
This commit is contained in:
@@ -90,8 +90,7 @@ impl Affinity {
|
||||
Affinity::Reg(rc) => {
|
||||
// If the preferred register class is a subclass of the constraint, there's no need
|
||||
// to change anything.
|
||||
if constraint.kind != ConstraintKind::Stack &&
|
||||
!constraint.regclass.has_subclass(rc)
|
||||
if constraint.kind != ConstraintKind::Stack && !constraint.regclass.has_subclass(rc)
|
||||
{
|
||||
// If the register classes don't overlap, `intersect` returns `Unassigned`, and
|
||||
// we just keep our previous affinity.
|
||||
@@ -120,12 +119,10 @@ impl<'a> fmt::Display for DisplayAffinity<'a> {
|
||||
match self.0 {
|
||||
Affinity::Unassigned => write!(f, "unassigned"),
|
||||
Affinity::Stack => write!(f, "stack"),
|
||||
Affinity::Reg(rci) => {
|
||||
match self.1 {
|
||||
Some(regs) => write!(f, "{}", regs.rc(rci)),
|
||||
None => write!(f, "{}", rci),
|
||||
}
|
||||
}
|
||||
Affinity::Reg(rci) => match self.1 {
|
||||
Some(regs) => write!(f, "{}", regs.rc(rci)),
|
||||
None => write!(f, "{}", rci),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,8 +196,7 @@ impl<'a> Context<'a> {
|
||||
pred_inst,
|
||||
pred_ebb,
|
||||
self.liveness.context(&self.func.layout),
|
||||
)
|
||||
{
|
||||
) {
|
||||
self.isolate_param(ebb, param);
|
||||
}
|
||||
}
|
||||
@@ -219,8 +218,8 @@ impl<'a> Context<'a> {
|
||||
// pre-spilled, and the rest of the virtual register would be forced to spill to the
|
||||
// `incoming_arg` stack slot too.
|
||||
if let ir::ValueDef::Param(def_ebb, def_num) = self.func.dfg.value_def(arg) {
|
||||
if Some(def_ebb) == self.func.layout.entry_block() &&
|
||||
self.func.signature.params[def_num].location.is_stack()
|
||||
if Some(def_ebb) == self.func.layout.entry_block()
|
||||
&& self.func.signature.params[def_num].location.is_stack()
|
||||
{
|
||||
dbg!("-> isolating function stack parameter {}", arg);
|
||||
let new_arg = self.isolate_arg(pred_ebb, pred_inst, argnum, arg);
|
||||
@@ -303,16 +302,11 @@ impl<'a> Context<'a> {
|
||||
&self.encinfo
|
||||
.operand_constraints(pos.func.encodings[inst])
|
||||
.expect("Bad copy encoding")
|
||||
.outs
|
||||
[0],
|
||||
.outs[0],
|
||||
);
|
||||
self.liveness.create_dead(new_val, ebb, affinity);
|
||||
self.liveness.extend_locally(
|
||||
new_val,
|
||||
ebb,
|
||||
inst,
|
||||
&pos.func.layout,
|
||||
);
|
||||
self.liveness
|
||||
.extend_locally(new_val, ebb, inst, &pos.func.layout);
|
||||
|
||||
new_val
|
||||
}
|
||||
@@ -353,16 +347,11 @@ impl<'a> Context<'a> {
|
||||
&self.encinfo
|
||||
.operand_constraints(pos.func.encodings[inst])
|
||||
.expect("Bad copy encoding")
|
||||
.outs
|
||||
[0],
|
||||
.outs[0],
|
||||
);
|
||||
self.liveness.create_dead(copy, inst, affinity);
|
||||
self.liveness.extend_locally(
|
||||
copy,
|
||||
pred_ebb,
|
||||
pred_inst,
|
||||
&pos.func.layout,
|
||||
);
|
||||
self.liveness
|
||||
.extend_locally(copy, pred_ebb, pred_inst, &pos.func.layout);
|
||||
|
||||
pos.func.dfg.inst_variable_args_mut(pred_inst)[argnum] = copy;
|
||||
|
||||
@@ -422,12 +411,9 @@ impl<'a> Context<'a> {
|
||||
let node = Node::value(value, 0, self.func);
|
||||
|
||||
// Push this value and get the nearest dominating def back.
|
||||
let parent = match self.forest.push_node(
|
||||
node,
|
||||
self.func,
|
||||
self.domtree,
|
||||
self.preorder,
|
||||
) {
|
||||
let parent = match self.forest
|
||||
.push_node(node, self.func, self.domtree, self.preorder)
|
||||
{
|
||||
None => continue,
|
||||
Some(n) => n,
|
||||
};
|
||||
@@ -525,12 +511,8 @@ impl<'a> Context<'a> {
|
||||
// Can't merge because of interference. Insert a copy instead.
|
||||
let pred_ebb = self.func.layout.pp_ebb(pred_inst);
|
||||
let new_arg = self.isolate_arg(pred_ebb, pred_inst, argnum, arg);
|
||||
self.virtregs.insert_single(
|
||||
param,
|
||||
new_arg,
|
||||
self.func,
|
||||
self.preorder,
|
||||
);
|
||||
self.virtregs
|
||||
.insert_single(param, new_arg, self.func, self.preorder);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -564,12 +546,8 @@ impl<'a> Context<'a> {
|
||||
|
||||
// Restrict the virtual copy nodes we look at and key the `set_id` and `value` properties
|
||||
// of the nodes. Set_id 0 will be `param` and set_id 1 will be `arg`.
|
||||
self.vcopies.set_filter(
|
||||
[param, arg],
|
||||
func,
|
||||
self.virtregs,
|
||||
preorder,
|
||||
);
|
||||
self.vcopies
|
||||
.set_filter([param, arg], func, self.virtregs, preorder);
|
||||
|
||||
// Now create an ordered sequence of dom-forest nodes from three sources: The two virtual
|
||||
// registers and the filtered virtual copies.
|
||||
@@ -625,8 +603,8 @@ impl<'a> Context<'a> {
|
||||
|
||||
// Check if the parent value interferes with the virtual copy.
|
||||
let inst = node.def.unwrap_inst();
|
||||
if node.set_id != parent.set_id &&
|
||||
self.liveness[parent.value].reaches_use(inst, node.ebb, ctx)
|
||||
if node.set_id != parent.set_id
|
||||
&& self.liveness[parent.value].reaches_use(inst, node.ebb, ctx)
|
||||
{
|
||||
dbg!(
|
||||
" - interference: {} overlaps vcopy at {}:{}",
|
||||
@@ -649,8 +627,8 @@ impl<'a> Context<'a> {
|
||||
|
||||
// Both node and parent are values, so check for interference.
|
||||
debug_assert!(node.is_value() && parent.is_value());
|
||||
if node.set_id != parent.set_id &&
|
||||
self.liveness[parent.value].overlaps_def(node.def, node.ebb, ctx)
|
||||
if node.set_id != parent.set_id
|
||||
&& self.liveness[parent.value].overlaps_def(node.def, node.ebb, ctx)
|
||||
{
|
||||
// The two values are interfering.
|
||||
dbg!(" - interference: {} overlaps def of {}", parent, node.value);
|
||||
@@ -945,9 +923,8 @@ impl VirtualCopies {
|
||||
}
|
||||
|
||||
// Reorder the predecessor branches as required by the dominator forest.
|
||||
self.branches.sort_unstable_by(|&(a, _), &(b, _)| {
|
||||
preorder.pre_cmp(a, b, &func.layout)
|
||||
});
|
||||
self.branches
|
||||
.sort_unstable_by(|&(a, _), &(b, _)| preorder.pre_cmp(a, b, &func.layout));
|
||||
}
|
||||
|
||||
/// Get the next unmerged parameter value.
|
||||
@@ -1097,9 +1074,9 @@ where
|
||||
let ord = match (self.a.peek(), self.b.peek()) {
|
||||
(Some(a), Some(b)) => {
|
||||
let layout = self.layout;
|
||||
self.preorder.pre_cmp_ebb(a.ebb, b.ebb).then_with(|| {
|
||||
layout.cmp(a.def, b.def)
|
||||
})
|
||||
self.preorder
|
||||
.pre_cmp_ebb(a.ebb, b.ebb)
|
||||
.then_with(|| layout.cmp(a.def, b.def))
|
||||
}
|
||||
(Some(_), None) => cmp::Ordering::Less,
|
||||
(None, Some(_)) => cmp::Ordering::Greater,
|
||||
|
||||
@@ -51,10 +51,10 @@ use isa::{regs_overlap, RegClass, RegInfo, RegUnit};
|
||||
use packed_option::PackedOption;
|
||||
use regalloc::RegDiversions;
|
||||
use regalloc::affinity::Affinity;
|
||||
use regalloc::register_set::RegisterSet;
|
||||
use regalloc::live_value_tracker::{LiveValue, LiveValueTracker};
|
||||
use regalloc::liveness::Liveness;
|
||||
use regalloc::liverange::{LiveRange, LiveRangeContext};
|
||||
use regalloc::register_set::RegisterSet;
|
||||
use regalloc::solver::{Solver, SolverError};
|
||||
use std::mem;
|
||||
use timing;
|
||||
@@ -142,9 +142,10 @@ impl Coloring {
|
||||
impl<'a> Context<'a> {
|
||||
/// Run the coloring algorithm.
|
||||
fn run(&mut self, tracker: &mut LiveValueTracker) {
|
||||
self.cur.func.locations.resize(
|
||||
self.cur.func.dfg.num_values(),
|
||||
);
|
||||
self.cur
|
||||
.func
|
||||
.locations
|
||||
.resize(self.cur.func.dfg.num_values());
|
||||
|
||||
// Visit blocks in reverse post-order. We need to ensure that at least one predecessor has
|
||||
// been visited before each EBB. That guarantees that the EBB arguments have been colored.
|
||||
@@ -372,10 +373,8 @@ impl<'a> Context<'a> {
|
||||
|
||||
// Update the global register set which has no diversions.
|
||||
if !lv.is_local {
|
||||
regs.global.free(
|
||||
rc,
|
||||
self.cur.func.locations[lv.value].unwrap_reg(),
|
||||
);
|
||||
regs.global
|
||||
.free(rc, self.cur.func.locations[lv.value].unwrap_reg());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -500,20 +499,14 @@ impl<'a> Context<'a> {
|
||||
// already in a register.
|
||||
let cur_reg = self.divert.reg(value, &self.cur.func.locations);
|
||||
match op.kind {
|
||||
ConstraintKind::FixedReg(regunit) |
|
||||
ConstraintKind::FixedTied(regunit) => {
|
||||
ConstraintKind::FixedReg(regunit) | ConstraintKind::FixedTied(regunit) => {
|
||||
// Add the fixed constraint even if `cur_reg == regunit`.
|
||||
// It is possible that we will want to convert the value to a variable later,
|
||||
// and this identity assignment prevents that from happening.
|
||||
self.solver.reassign_in(
|
||||
value,
|
||||
op.regclass,
|
||||
cur_reg,
|
||||
regunit,
|
||||
);
|
||||
self.solver
|
||||
.reassign_in(value, op.regclass, cur_reg, regunit);
|
||||
}
|
||||
ConstraintKind::Reg |
|
||||
ConstraintKind::Tied(_) => {
|
||||
ConstraintKind::Reg | ConstraintKind::Tied(_) => {
|
||||
if !op.regclass.contains(cur_reg) {
|
||||
self.solver.add_var(value, op.regclass, cur_reg);
|
||||
}
|
||||
@@ -541,8 +534,7 @@ impl<'a> Context<'a> {
|
||||
|
||||
for (op, &value) in constraints.iter().zip(self.cur.func.dfg.inst_args(inst)) {
|
||||
match op.kind {
|
||||
ConstraintKind::Reg |
|
||||
ConstraintKind::Tied(_) => {
|
||||
ConstraintKind::Reg | ConstraintKind::Tied(_) => {
|
||||
let cur_reg = self.divert.reg(value, &self.cur.func.locations);
|
||||
// This is the opposite condition of `program_input_constraints()`.
|
||||
if op.regclass.contains(cur_reg) {
|
||||
@@ -556,9 +548,9 @@ impl<'a> Context<'a> {
|
||||
}
|
||||
}
|
||||
}
|
||||
ConstraintKind::FixedReg(_) |
|
||||
ConstraintKind::FixedTied(_) |
|
||||
ConstraintKind::Stack => {}
|
||||
ConstraintKind::FixedReg(_)
|
||||
| ConstraintKind::FixedTied(_)
|
||||
| ConstraintKind::Stack => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -651,9 +643,9 @@ impl<'a> Context<'a> {
|
||||
Pred: FnMut(&LiveRange, LiveRangeContext<Layout>) -> bool,
|
||||
{
|
||||
for rdiv in self.divert.all() {
|
||||
let lr = self.liveness.get(rdiv.value).expect(
|
||||
"Missing live range for diverted register",
|
||||
);
|
||||
let lr = self.liveness
|
||||
.get(rdiv.value)
|
||||
.expect("Missing live range for diverted register");
|
||||
if pred(lr, self.liveness.context(&self.cur.func.layout)) {
|
||||
if let Affinity::Reg(rci) = lr.affinity {
|
||||
let rc = self.reginfo.rc(rci);
|
||||
@@ -703,8 +695,7 @@ impl<'a> Context<'a> {
|
||||
) {
|
||||
for (op, lv) in constraints.iter().zip(defs) {
|
||||
match op.kind {
|
||||
ConstraintKind::FixedReg(reg) |
|
||||
ConstraintKind::FixedTied(reg) => {
|
||||
ConstraintKind::FixedReg(reg) | ConstraintKind::FixedTied(reg) => {
|
||||
self.add_fixed_output(lv.value, op.regclass, reg, throughs);
|
||||
if !lv.is_local && !global_regs.is_avail(op.regclass, reg) {
|
||||
dbg!(
|
||||
@@ -716,9 +707,7 @@ impl<'a> Context<'a> {
|
||||
*replace_global_defines = true;
|
||||
}
|
||||
}
|
||||
ConstraintKind::Reg |
|
||||
ConstraintKind::Tied(_) |
|
||||
ConstraintKind::Stack => {}
|
||||
ConstraintKind::Reg | ConstraintKind::Tied(_) | ConstraintKind::Stack => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -801,9 +790,9 @@ impl<'a> Context<'a> {
|
||||
) {
|
||||
for (op, lv) in constraints.iter().zip(defs) {
|
||||
match op.kind {
|
||||
ConstraintKind::FixedReg(_) |
|
||||
ConstraintKind::FixedTied(_) |
|
||||
ConstraintKind::Stack => continue,
|
||||
ConstraintKind::FixedReg(_)
|
||||
| ConstraintKind::FixedTied(_)
|
||||
| ConstraintKind::Stack => continue,
|
||||
ConstraintKind::Reg => {
|
||||
self.solver.add_def(lv.value, op.regclass, !lv.is_local);
|
||||
}
|
||||
@@ -816,8 +805,7 @@ impl<'a> Context<'a> {
|
||||
op.regclass,
|
||||
self.divert.reg(arg, &self.cur.func.locations),
|
||||
!lv.is_local,
|
||||
)
|
||||
{
|
||||
) {
|
||||
// The value we're tied to has been assigned to a fixed register.
|
||||
// We need to make sure that fixed output register is compatible with the
|
||||
// global register set.
|
||||
@@ -881,8 +869,8 @@ impl<'a> Context<'a> {
|
||||
// not actually constrained by the instruction. We just want it out of the way.
|
||||
let toprc2 = self.reginfo.toprc(rci);
|
||||
let reg2 = self.divert.reg(lv.value, &self.cur.func.locations);
|
||||
if rc.contains(reg2) && self.solver.can_add_var(lv.value, toprc2, reg2) &&
|
||||
!self.is_live_on_outgoing_edge(lv.value)
|
||||
if rc.contains(reg2) && self.solver.can_add_var(lv.value, toprc2, reg2)
|
||||
&& !self.is_live_on_outgoing_edge(lv.value)
|
||||
{
|
||||
self.solver.add_through_var(lv.value, toprc2, reg2);
|
||||
return true;
|
||||
@@ -911,10 +899,10 @@ impl<'a> Context<'a> {
|
||||
}
|
||||
Table(jt) => {
|
||||
let lr = &self.liveness[value];
|
||||
!lr.is_local() &&
|
||||
self.cur.func.jump_tables[jt].entries().any(|(_, ebb)| {
|
||||
lr.is_livein(ebb, ctx)
|
||||
})
|
||||
!lr.is_local()
|
||||
&& self.cur.func.jump_tables[jt]
|
||||
.entries()
|
||||
.any(|(_, ebb)| lr.is_livein(ebb, ctx))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -940,7 +928,9 @@ impl<'a> Context<'a> {
|
||||
|
||||
for m in self.solver.moves() {
|
||||
match *m {
|
||||
Reg { value, from, to, .. } => {
|
||||
Reg {
|
||||
value, from, to, ..
|
||||
} => {
|
||||
self.divert.regmove(value, from, to);
|
||||
self.cur.ins().regmove(value, from, to);
|
||||
}
|
||||
@@ -951,10 +941,10 @@ impl<'a> Context<'a> {
|
||||
..
|
||||
} => {
|
||||
debug_assert_eq!(slot[to_slot].expand(), None, "Overwriting slot in use");
|
||||
let ss = self.cur.func.stack_slots.get_emergency_slot(
|
||||
self.cur.func.dfg.value_type(value),
|
||||
&slot[0..spills],
|
||||
);
|
||||
let ss = self.cur
|
||||
.func
|
||||
.stack_slots
|
||||
.get_emergency_slot(self.cur.func.dfg.value_type(value), &slot[0..spills]);
|
||||
slot[to_slot] = ss.into();
|
||||
self.divert.regspill(value, from, ss);
|
||||
self.cur.ins().regspill(value, from, ss);
|
||||
@@ -1013,8 +1003,7 @@ impl<'a> Context<'a> {
|
||||
if match self.cur.func.dfg.value_def(lv.value) {
|
||||
ValueDef::Result(i, _) => i != inst,
|
||||
_ => true,
|
||||
}
|
||||
{
|
||||
} {
|
||||
break;
|
||||
}
|
||||
if lv.is_local || !lv.affinity.is_reg() {
|
||||
@@ -1072,10 +1061,8 @@ impl<'a> Context<'a> {
|
||||
};
|
||||
regs.input.free(rc, loc.unwrap_reg());
|
||||
if !lv.is_local {
|
||||
regs.global.free(
|
||||
rc,
|
||||
self.cur.func.locations[lv.value].unwrap_reg(),
|
||||
);
|
||||
regs.global
|
||||
.free(rc, self.cur.func.locations[lv.value].unwrap_reg());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1096,11 +1083,10 @@ fn program_input_abi(
|
||||
) {
|
||||
for (abi, &value) in abi_types.iter().zip(func.dfg.inst_variable_args(inst)) {
|
||||
if let ArgumentLoc::Reg(reg) = abi.location {
|
||||
if let Affinity::Reg(rci) =
|
||||
liveness
|
||||
.get(value)
|
||||
.expect("ABI register must have live range")
|
||||
.affinity
|
||||
if let Affinity::Reg(rci) = liveness
|
||||
.get(value)
|
||||
.expect("ABI register must have live range")
|
||||
.affinity
|
||||
{
|
||||
let rc = reginfo.rc(rci);
|
||||
let cur_reg = divert.reg(value, &func.locations);
|
||||
|
||||
@@ -140,13 +140,8 @@ impl Context {
|
||||
}
|
||||
|
||||
// Pass: Coloring.
|
||||
self.coloring.run(
|
||||
isa,
|
||||
func,
|
||||
domtree,
|
||||
&mut self.liveness,
|
||||
&mut self.tracker,
|
||||
);
|
||||
self.coloring
|
||||
.run(isa, func, domtree, &mut self.liveness, &mut self.tracker);
|
||||
|
||||
if isa.flags().enable_verifier() {
|
||||
verify_context(func, cfg, domtree, isa)?;
|
||||
|
||||
@@ -46,7 +46,9 @@ pub struct RegDiversions {
|
||||
impl RegDiversions {
|
||||
/// Create a new empty diversion tracker.
|
||||
pub fn new() -> Self {
|
||||
Self { current: Vec::new() }
|
||||
Self {
|
||||
current: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Clear the tracker, preparing for a new EBB.
|
||||
@@ -152,11 +154,10 @@ impl RegDiversions {
|
||||
///
|
||||
/// Returns the `to` location of the removed diversion.
|
||||
pub fn remove(&mut self, value: Value) -> Option<ValueLoc> {
|
||||
self.current.iter().position(|d| d.value == value).map(
|
||||
|i| {
|
||||
self.current.swap_remove(i).to
|
||||
},
|
||||
)
|
||||
self.current
|
||||
.iter()
|
||||
.position(|d| d.value == value)
|
||||
.map(|i| self.current.swap_remove(i).to)
|
||||
}
|
||||
|
||||
/// Return an object that can display the diversions.
|
||||
|
||||
@@ -187,15 +187,15 @@ impl LiveValueTracker {
|
||||
// If the immediate dominator exits, we must have a stored list for it. This is a
|
||||
// requirement to the order EBBs are visited: All dominators must have been processed
|
||||
// before the current EBB.
|
||||
let idom_live_list = self.idom_sets.get(&idom).expect(
|
||||
"No stored live set for dominator",
|
||||
);
|
||||
let idom_live_list = self.idom_sets
|
||||
.get(&idom)
|
||||
.expect("No stored live set for dominator");
|
||||
let ctx = liveness.context(layout);
|
||||
// Get just the values that are live-in to `ebb`.
|
||||
for &value in idom_live_list.as_slice(&self.idom_pool) {
|
||||
let lr = liveness.get(value).expect(
|
||||
"Immediate dominator value has no live range",
|
||||
);
|
||||
let lr = liveness
|
||||
.get(value)
|
||||
.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, ctx) {
|
||||
@@ -217,17 +217,13 @@ impl LiveValueTracker {
|
||||
// This is a dead EBB parameter which is not even live into the first
|
||||
// instruction in the EBB.
|
||||
debug_assert_eq!(
|
||||
local_ebb,
|
||||
ebb,
|
||||
local_ebb, ebb,
|
||||
"EBB parameter 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,
|
||||
);
|
||||
self.live
|
||||
.push(value, layout.first_inst(ebb).expect("Empty EBB"), lr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,7 +179,7 @@ use entity::SparseMap;
|
||||
use flowgraph::ControlFlowGraph;
|
||||
use ir::dfg::ValueDef;
|
||||
use ir::{Ebb, Function, Inst, Layout, ProgramPoint, Value};
|
||||
use isa::{EncInfo, TargetIsa, OperandConstraint};
|
||||
use isa::{EncInfo, OperandConstraint, TargetIsa};
|
||||
use regalloc::affinity::Affinity;
|
||||
use regalloc::liverange::{LiveRange, LiveRangeContext, LiveRangeForest};
|
||||
use std::mem;
|
||||
@@ -217,9 +217,9 @@ fn get_or_create<'a>(
|
||||
.map(Affinity::new)
|
||||
.or_else(|| {
|
||||
// If this is a call, get the return value affinity.
|
||||
func.dfg.call_signature(inst).map(|sig| {
|
||||
Affinity::abi(&func.dfg.signatures[sig].returns[rnum], isa)
|
||||
})
|
||||
func.dfg
|
||||
.call_signature(inst)
|
||||
.map(|sig| Affinity::abi(&func.dfg.signatures[sig].returns[rnum], isa))
|
||||
})
|
||||
.unwrap_or_default();
|
||||
}
|
||||
@@ -336,9 +336,8 @@ impl Liveness {
|
||||
where
|
||||
PP: Into<ProgramPoint>,
|
||||
{
|
||||
let old = self.ranges.insert(
|
||||
LiveRange::new(value, def.into(), affinity),
|
||||
);
|
||||
let old = self.ranges
|
||||
.insert(LiveRange::new(value, def.into(), affinity));
|
||||
debug_assert!(old.is_none(), "{} already has a live range", value);
|
||||
}
|
||||
|
||||
|
||||
@@ -249,13 +249,12 @@ impl<PO: ProgramOrder> GenLiveRange<PO> {
|
||||
//
|
||||
// We're assuming here that `to` never precedes `def_begin` in the same EBB, but we can't
|
||||
// check it without a method for getting `to`'s EBB.
|
||||
if order.cmp(ebb, self.def_end) != Ordering::Greater &&
|
||||
order.cmp(to, self.def_begin) != Ordering::Less
|
||||
if order.cmp(ebb, self.def_end) != Ordering::Greater
|
||||
&& order.cmp(to, self.def_begin) != Ordering::Less
|
||||
{
|
||||
let to_pp = to.into();
|
||||
debug_assert_ne!(
|
||||
to_pp,
|
||||
self.def_begin,
|
||||
to_pp, self.def_begin,
|
||||
"Can't use value in the defining instruction."
|
||||
);
|
||||
if order.cmp(to, self.def_end) == Ordering::Greater {
|
||||
@@ -411,8 +410,8 @@ impl<PO: ProgramOrder> GenLiveRange<PO> {
|
||||
}
|
||||
|
||||
// Check for an overlap with the local range.
|
||||
if ctx.order.cmp(def, self.def_begin) != Ordering::Less &&
|
||||
ctx.order.cmp(def, self.def_end) == Ordering::Less
|
||||
if ctx.order.cmp(def, self.def_begin) != Ordering::Less
|
||||
&& ctx.order.cmp(def, self.def_end) == Ordering::Less
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -427,8 +426,8 @@ impl<PO: ProgramOrder> GenLiveRange<PO> {
|
||||
/// Check if this live range reaches a use at `user` in `ebb`.
|
||||
pub fn reaches_use(&self, user: Inst, ebb: Ebb, ctx: LiveRangeContext<PO>) -> bool {
|
||||
// Check for an overlap with the local range.
|
||||
if ctx.order.cmp(user, self.def_begin) == Ordering::Greater &&
|
||||
ctx.order.cmp(user, self.def_end) != Ordering::Greater
|
||||
if ctx.order.cmp(user, self.def_begin) == Ordering::Greater
|
||||
&& ctx.order.cmp(user, self.def_end) != Ordering::Greater
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -535,8 +534,8 @@ mod tests {
|
||||
}
|
||||
|
||||
assert!(
|
||||
self.cmp(lr.def_end, begin) == Ordering::Less ||
|
||||
self.cmp(lr.def_begin, end) == Ordering::Greater,
|
||||
self.cmp(lr.def_end, begin) == Ordering::Less
|
||||
|| self.cmp(lr.def_begin, end) == Ordering::Greater,
|
||||
"Interval can't overlap the def EBB"
|
||||
);
|
||||
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
//!
|
||||
//! This module contains data structures and algorithms used for register allocation.
|
||||
|
||||
pub mod register_set;
|
||||
pub mod coloring;
|
||||
pub mod live_value_tracker;
|
||||
pub mod liveness;
|
||||
pub mod liverange;
|
||||
pub mod register_set;
|
||||
pub mod virtregs;
|
||||
|
||||
mod affinity;
|
||||
@@ -18,6 +18,6 @@ mod reload;
|
||||
mod solver;
|
||||
mod spilling;
|
||||
|
||||
pub use self::register_set::RegisterSet;
|
||||
pub use self::context::Context;
|
||||
pub use self::diversion::RegDiversions;
|
||||
pub use self::register_set::RegisterSet;
|
||||
|
||||
@@ -114,9 +114,10 @@ impl Pressure {
|
||||
}
|
||||
|
||||
// Compute per-class limits from `usable`.
|
||||
for (toprc, rc) in p.toprc.iter_mut().take_while(|t| t.num_toprcs > 0).zip(
|
||||
reginfo.classes,
|
||||
)
|
||||
for (toprc, rc) in p.toprc
|
||||
.iter_mut()
|
||||
.take_while(|t| t.num_toprcs > 0)
|
||||
.zip(reginfo.classes)
|
||||
{
|
||||
toprc.limit = usable.iter(rc).len() as u32;
|
||||
toprc.width = rc.width;
|
||||
@@ -203,16 +204,16 @@ impl Pressure {
|
||||
///
|
||||
/// This does not check if there are enough registers available.
|
||||
pub fn take(&mut self, rc: RegClass) {
|
||||
self.toprc.get_mut(rc.toprc as usize).map(
|
||||
|t| t.base_count += 1,
|
||||
);
|
||||
self.toprc
|
||||
.get_mut(rc.toprc as usize)
|
||||
.map(|t| t.base_count += 1);
|
||||
}
|
||||
|
||||
/// Free a register in `rc`.
|
||||
pub fn free(&mut self, rc: RegClass) {
|
||||
self.toprc.get_mut(rc.toprc as usize).map(
|
||||
|t| t.base_count -= 1,
|
||||
);
|
||||
self.toprc
|
||||
.get_mut(rc.toprc as usize)
|
||||
.map(|t| t.base_count -= 1);
|
||||
}
|
||||
|
||||
/// Reset all counts to 0, both base and transient.
|
||||
@@ -229,9 +230,9 @@ impl Pressure {
|
||||
pub fn take_transient(&mut self, rc: RegClass) -> Result<(), RegClassMask> {
|
||||
let mask = self.check_avail(rc);
|
||||
if mask == 0 {
|
||||
self.toprc.get_mut(rc.toprc as usize).map(|t| {
|
||||
t.transient_count += 1
|
||||
});
|
||||
self.toprc
|
||||
.get_mut(rc.toprc as usize)
|
||||
.map(|t| t.transient_count += 1);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(mask)
|
||||
|
||||
@@ -104,9 +104,10 @@ impl RegisterSet {
|
||||
///
|
||||
/// This assumes that unused bits are 1.
|
||||
pub fn interferes_with(&self, other: &Self) -> bool {
|
||||
self.avail.iter().zip(&other.avail).any(
|
||||
|(&x, &y)| (x | y) != !0,
|
||||
)
|
||||
self.avail
|
||||
.iter()
|
||||
.zip(&other.avail)
|
||||
.any(|(&x, &y)| (x | y) != !0)
|
||||
}
|
||||
|
||||
/// Intersect this set of registers with `other`. This has the effect of removing any register
|
||||
@@ -203,9 +204,10 @@ impl<'a> fmt::Display for DisplayRegisterSet<'a> {
|
||||
bank.names
|
||||
.get(offset as usize)
|
||||
.and_then(|name| name.chars().nth(1))
|
||||
.unwrap_or_else(
|
||||
|| char::from_digit(u32::from(offset % 10), 10).unwrap(),
|
||||
)
|
||||
.unwrap_or_else(|| char::from_digit(
|
||||
u32::from(offset % 10),
|
||||
10
|
||||
).unwrap())
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,10 +166,10 @@ impl<'a> Context<'a> {
|
||||
if arg.affinity.is_stack() {
|
||||
// An incoming register parameter was spilled. Replace the parameter value
|
||||
// with a temporary register value that is immediately spilled.
|
||||
let reg = self.cur.func.dfg.replace_ebb_param(
|
||||
arg.value,
|
||||
abi.value_type,
|
||||
);
|
||||
let reg = self.cur
|
||||
.func
|
||||
.dfg
|
||||
.replace_ebb_param(arg.value, abi.value_type);
|
||||
let affinity = Affinity::abi(&abi, self.cur.isa);
|
||||
self.liveness.create_dead(reg, ebb, affinity);
|
||||
self.insert_spill(ebb, arg.value, reg);
|
||||
@@ -199,9 +199,9 @@ impl<'a> Context<'a> {
|
||||
self.cur.use_srcloc(inst);
|
||||
|
||||
// Get the operand constraints for `inst` that we are trying to satisfy.
|
||||
let constraints = self.encinfo.operand_constraints(encoding).expect(
|
||||
"Missing instruction encoding",
|
||||
);
|
||||
let constraints = self.encinfo
|
||||
.operand_constraints(encoding)
|
||||
.expect("Missing instruction encoding");
|
||||
|
||||
// Identify reload candidates.
|
||||
debug_assert!(self.candidates.is_empty());
|
||||
@@ -226,12 +226,8 @@ impl<'a> Context<'a> {
|
||||
// Create a live range for the new reload.
|
||||
let affinity = Affinity::Reg(cand.regclass.into());
|
||||
self.liveness.create_dead(reg, fill, affinity);
|
||||
self.liveness.extend_locally(
|
||||
reg,
|
||||
ebb,
|
||||
inst,
|
||||
&self.cur.func.layout,
|
||||
);
|
||||
self.liveness
|
||||
.extend_locally(reg, ebb, inst, &self.cur.func.layout);
|
||||
}
|
||||
|
||||
// Rewrite instruction arguments.
|
||||
@@ -280,19 +276,18 @@ impl<'a> Context<'a> {
|
||||
// Same thing for spilled call return values.
|
||||
let retvals = &defs[constraints.outs.len()..];
|
||||
if !retvals.is_empty() {
|
||||
let sig = self.cur.func.dfg.call_signature(inst).expect(
|
||||
"Extra results on non-call instruction",
|
||||
);
|
||||
let sig = self.cur
|
||||
.func
|
||||
.dfg
|
||||
.call_signature(inst)
|
||||
.expect("Extra results on non-call instruction");
|
||||
for (i, lv) in retvals.iter().enumerate() {
|
||||
let abi = self.cur.func.dfg.signatures[sig].returns[i];
|
||||
debug_assert!(abi.location.is_reg());
|
||||
if lv.affinity.is_stack() {
|
||||
let reg = self.cur.func.dfg.replace_result(lv.value, abi.value_type);
|
||||
self.liveness.create_dead(
|
||||
reg,
|
||||
inst,
|
||||
Affinity::abi(&abi, self.cur.isa),
|
||||
);
|
||||
self.liveness
|
||||
.create_dead(reg, inst, Affinity::abi(&abi, self.cur.isa));
|
||||
self.insert_spill(ebb, lv.value, reg);
|
||||
}
|
||||
}
|
||||
@@ -355,12 +350,8 @@ impl<'a> Context<'a> {
|
||||
|
||||
// Update live ranges.
|
||||
self.liveness.move_def_locally(stack, inst);
|
||||
self.liveness.extend_locally(
|
||||
reg,
|
||||
ebb,
|
||||
inst,
|
||||
&self.cur.func.layout,
|
||||
);
|
||||
self.liveness
|
||||
.extend_locally(reg, ebb, inst, &self.cur.func.layout);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -297,8 +297,7 @@ impl Move {
|
||||
#[cfg_attr(feature = "cargo-clippy", allow(wrong_self_convention))]
|
||||
fn from_reg(&self) -> Option<(RegClass, RegUnit)> {
|
||||
match *self {
|
||||
Move::Reg { rc, from, .. } |
|
||||
Move::Spill { rc, from, .. } => Some((rc, from)),
|
||||
Move::Reg { rc, from, .. } | Move::Spill { rc, from, .. } => Some((rc, from)),
|
||||
Move::Fill { .. } => None,
|
||||
}
|
||||
}
|
||||
@@ -306,8 +305,7 @@ impl Move {
|
||||
/// Get the "to" register and register class, if possible.
|
||||
fn to_reg(&self) -> Option<(RegClass, RegUnit)> {
|
||||
match *self {
|
||||
Move::Reg { rc, to, .. } |
|
||||
Move::Fill { rc, to, .. } => Some((rc, to)),
|
||||
Move::Reg { rc, to, .. } | Move::Fill { rc, to, .. } => Some((rc, to)),
|
||||
Move::Spill { .. } => None,
|
||||
}
|
||||
}
|
||||
@@ -316,8 +314,7 @@ impl Move {
|
||||
fn replace_to_reg(&mut self, new: RegUnit) -> RegUnit {
|
||||
mem::replace(
|
||||
match *self {
|
||||
Move::Reg { ref mut to, .. } |
|
||||
Move::Fill { ref mut to, .. } => to,
|
||||
Move::Reg { ref mut to, .. } | Move::Fill { ref mut to, .. } => to,
|
||||
Move::Spill { .. } => panic!("No to register in a spill {}", self),
|
||||
},
|
||||
new,
|
||||
@@ -348,18 +345,14 @@ impl Move {
|
||||
/// Get the value being moved.
|
||||
fn value(&self) -> Value {
|
||||
match *self {
|
||||
Move::Reg { value, .. } |
|
||||
Move::Fill { value, .. } |
|
||||
Move::Spill { value, .. } => value,
|
||||
Move::Reg { value, .. } | Move::Fill { value, .. } | Move::Spill { value, .. } => value,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the associated register class.
|
||||
fn rc(&self) -> RegClass {
|
||||
match *self {
|
||||
Move::Reg { rc, .. } |
|
||||
Move::Fill { rc, .. } |
|
||||
Move::Spill { rc, .. } => rc,
|
||||
Move::Reg { rc, .. } | Move::Fill { rc, .. } | Move::Spill { rc, .. } => rc,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -372,46 +365,40 @@ impl fmt::Display for Move {
|
||||
from,
|
||||
to,
|
||||
rc,
|
||||
} => {
|
||||
write!(
|
||||
f,
|
||||
"{}:{}({} -> {})",
|
||||
value,
|
||||
rc,
|
||||
rc.info.display_regunit(from),
|
||||
rc.info.display_regunit(to)
|
||||
)
|
||||
}
|
||||
} => write!(
|
||||
f,
|
||||
"{}:{}({} -> {})",
|
||||
value,
|
||||
rc,
|
||||
rc.info.display_regunit(from),
|
||||
rc.info.display_regunit(to)
|
||||
),
|
||||
Move::Spill {
|
||||
value,
|
||||
from,
|
||||
to_slot,
|
||||
rc,
|
||||
} => {
|
||||
write!(
|
||||
f,
|
||||
"{}:{}({} -> slot {})",
|
||||
value,
|
||||
rc,
|
||||
rc.info.display_regunit(from),
|
||||
to_slot
|
||||
)
|
||||
}
|
||||
} => write!(
|
||||
f,
|
||||
"{}:{}({} -> slot {})",
|
||||
value,
|
||||
rc,
|
||||
rc.info.display_regunit(from),
|
||||
to_slot
|
||||
),
|
||||
Move::Fill {
|
||||
value,
|
||||
from_slot,
|
||||
to,
|
||||
rc,
|
||||
} => {
|
||||
write!(
|
||||
f,
|
||||
"{}:{}(slot {} -> {})",
|
||||
value,
|
||||
rc,
|
||||
from_slot,
|
||||
rc.info.display_regunit(to)
|
||||
)
|
||||
}
|
||||
} => write!(
|
||||
f,
|
||||
"{}:{}(slot {} -> {})",
|
||||
value,
|
||||
rc,
|
||||
from_slot,
|
||||
rc.info.display_regunit(to)
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -824,9 +811,8 @@ impl Solver {
|
||||
/// This is similar to `add_var`, except the value doesn't have a prior register assignment.
|
||||
pub fn add_def(&mut self, value: Value, constraint: RegClass, is_global: bool) {
|
||||
debug_assert!(self.inputs_done);
|
||||
self.vars.push(
|
||||
Variable::new_def(value, constraint, is_global),
|
||||
);
|
||||
self.vars
|
||||
.push(Variable::new_def(value, constraint, is_global));
|
||||
}
|
||||
|
||||
/// Clear the `is_global` flag on all solver variables.
|
||||
@@ -992,9 +978,8 @@ impl Solver {
|
||||
|
||||
// Convert all of the fixed register assignments into moves, but omit the ones that are
|
||||
// already in the right register.
|
||||
self.moves.extend(self.assignments.values().filter_map(
|
||||
Move::with_assignment,
|
||||
));
|
||||
self.moves
|
||||
.extend(self.assignments.values().filter_map(Move::with_assignment));
|
||||
|
||||
if !(self.moves.is_empty()) {
|
||||
dbg!("collect_moves: {}", DisplayList(&self.moves));
|
||||
@@ -1029,8 +1014,7 @@ impl Solver {
|
||||
if let Some(j) = self.moves[i..].iter().position(|m| match m.to_reg() {
|
||||
Some((rc, reg)) => avail.is_avail(rc, reg),
|
||||
None => true,
|
||||
})
|
||||
{
|
||||
}) {
|
||||
// This move can be executed now.
|
||||
self.moves.swap(i, i + j);
|
||||
let m = &self.moves[i];
|
||||
@@ -1164,9 +1148,11 @@ mod tests {
|
||||
|
||||
// Get a register class by name.
|
||||
fn rc_by_name(reginfo: &RegInfo, name: &str) -> RegClass {
|
||||
reginfo.classes.iter().find(|rc| rc.name == name).expect(
|
||||
"Can't find named register class.",
|
||||
)
|
||||
reginfo
|
||||
.classes
|
||||
.iter()
|
||||
.find(|rc| rc.name == name)
|
||||
.expect("Can't find named register class.")
|
||||
}
|
||||
|
||||
// Construct a register move.
|
||||
|
||||
@@ -125,10 +125,8 @@ impl<'a> Context<'a> {
|
||||
self.process_spills(tracker);
|
||||
|
||||
while let Some(inst) = self.cur.next_inst() {
|
||||
if let Some(constraints) =
|
||||
self.encinfo.operand_constraints(
|
||||
self.cur.func.encodings[inst],
|
||||
)
|
||||
if let Some(constraints) = self.encinfo
|
||||
.operand_constraints(self.cur.func.encodings[inst])
|
||||
{
|
||||
self.visit_inst(inst, ebb, constraints, tracker);
|
||||
} else {
|
||||
@@ -283,13 +281,11 @@ impl<'a> Context<'a> {
|
||||
dbg!("Need {} reg from {} throughs", op.regclass, throughs.len());
|
||||
match self.spill_candidate(mask, throughs) {
|
||||
Some(cand) => self.spill_reg(cand),
|
||||
None => {
|
||||
panic!(
|
||||
"Ran out of {} registers for {}",
|
||||
op.regclass,
|
||||
self.cur.display_inst(inst)
|
||||
)
|
||||
}
|
||||
None => panic!(
|
||||
"Ran out of {} registers for {}",
|
||||
op.regclass,
|
||||
self.cur.display_inst(inst)
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -349,12 +345,11 @@ impl<'a> Context<'a> {
|
||||
.constraints()
|
||||
.fixed_value_arguments();
|
||||
let args = self.cur.func.dfg.inst_variable_args(inst);
|
||||
for (idx, (abi, &arg)) in
|
||||
self.cur.func.dfg.signatures[sig]
|
||||
.params
|
||||
.iter()
|
||||
.zip(args)
|
||||
.enumerate()
|
||||
for (idx, (abi, &arg)) in self.cur.func.dfg.signatures[sig]
|
||||
.params
|
||||
.iter()
|
||||
.zip(args)
|
||||
.enumerate()
|
||||
{
|
||||
if abi.location.is_reg() {
|
||||
let (rci, spilled) = match self.liveness[arg].affinity {
|
||||
@@ -393,9 +388,9 @@ impl<'a> Context<'a> {
|
||||
} else if ru.fixed {
|
||||
// This is a fixed register use which doesn't necessarily require a copy.
|
||||
// Make a copy only if this is not the first use of the value.
|
||||
self.reg_uses.get(i.wrapping_sub(1)).map_or(false, |ru2| {
|
||||
ru2.value == ru.value
|
||||
})
|
||||
self.reg_uses
|
||||
.get(i.wrapping_sub(1))
|
||||
.map_or(false, |ru2| ru2.value == ru.value)
|
||||
} else {
|
||||
false
|
||||
};
|
||||
@@ -430,13 +425,11 @@ impl<'a> Context<'a> {
|
||||
)
|
||||
} {
|
||||
Some(cand) => self.spill_reg(cand),
|
||||
None => {
|
||||
panic!(
|
||||
"Ran out of {} registers when inserting copy before {}",
|
||||
rc,
|
||||
self.cur.display_inst(inst)
|
||||
)
|
||||
}
|
||||
None => panic!(
|
||||
"Ran out of {} registers when inserting copy before {}",
|
||||
rc,
|
||||
self.cur.display_inst(inst)
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -501,9 +494,10 @@ impl<'a> Context<'a> {
|
||||
}
|
||||
|
||||
// Assign a spill slot for the whole virtual register.
|
||||
let ss = self.cur.func.stack_slots.make_spill_slot(
|
||||
self.cur.func.dfg.value_type(value),
|
||||
);
|
||||
let ss = self.cur
|
||||
.func
|
||||
.stack_slots
|
||||
.make_spill_slot(self.cur.func.dfg.value_type(value));
|
||||
for &v in self.virtregs.congruence_class(&value) {
|
||||
self.liveness.spill(v);
|
||||
self.cur.func.locations[v] = ValueLoc::Stack(ss);
|
||||
|
||||
@@ -101,10 +101,8 @@ impl VirtRegs {
|
||||
where
|
||||
'a: 'b,
|
||||
{
|
||||
self.get(*value).map_or_else(
|
||||
|| ref_slice(value),
|
||||
|vr| self.values(vr),
|
||||
)
|
||||
self.get(*value)
|
||||
.map_or_else(|| ref_slice(value), |vr| self.values(vr))
|
||||
}
|
||||
|
||||
/// Check if `a` and `b` belong to the same congruence class.
|
||||
@@ -153,9 +151,9 @@ impl VirtRegs {
|
||||
});
|
||||
|
||||
// Determine the insertion position for `single`.
|
||||
let index = match self.values(vreg).binary_search_by(
|
||||
|&v| preorder.pre_cmp_def(v, single, func),
|
||||
) {
|
||||
let index = match self.values(vreg)
|
||||
.binary_search_by(|&v| preorder.pre_cmp_def(v, single, func))
|
||||
{
|
||||
Ok(_) => panic!("{} already in {}", single, vreg),
|
||||
Err(i) => i,
|
||||
};
|
||||
@@ -181,9 +179,9 @@ impl VirtRegs {
|
||||
|
||||
/// Allocate a new empty virtual register.
|
||||
fn alloc(&mut self) -> VirtReg {
|
||||
self.unused_vregs.pop().unwrap_or_else(|| {
|
||||
self.vregs.push(Default::default())
|
||||
})
|
||||
self.unused_vregs
|
||||
.pop()
|
||||
.unwrap_or_else(|| self.vregs.push(Default::default()))
|
||||
}
|
||||
|
||||
/// Unify `values` into a single virtual register.
|
||||
|
||||
Reference in New Issue
Block a user