[regalloc] Transform the program_input_abi function into a Context method;

It was implemented this way before to avoid borrow-checking issues,
where self would be both mutably borrowed (because of the solver) and
immutably borrowed (because of the ABI parameters list). This is worked
around by adding a local AbiParams struct which contains a summary of
the information that's needed by program_input_abi, allowing to retrieve
the ABI params within the method's body itself.
This commit is contained in:
Benjamin Bouvier
2019-08-29 16:10:04 +02:00
parent cd1b2c0af0
commit 47e5d6c83e

View File

@@ -44,7 +44,7 @@
use crate::cursor::{Cursor, EncCursor};
use crate::dominator_tree::DominatorTree;
use crate::ir::{AbiParam, ArgumentLoc, InstBuilder, ValueDef};
use crate::ir::{ArgumentLoc, InstBuilder, ValueDef};
use crate::ir::{Ebb, Function, Inst, InstructionData, Layout, Opcode, SigRef, Value, ValueLoc};
use crate::isa::{regs_overlap, RegClass, RegInfo, RegUnit};
use crate::isa::{ConstraintKind, EncInfo, OperandConstraint, RecipeConstraints, TargetIsa};
@@ -68,6 +68,12 @@ pub struct Coloring {
solver: Solver,
}
/// Kinds of ABI parameters.
enum AbiParams {
Parameters(SigRef),
Returns,
}
/// Bundle of references that the coloring algorithm needs.
///
/// Some of the needed mutable references are passed around as explicit function arguments so we
@@ -285,6 +291,36 @@ impl<'a> Context<'a> {
regs
}
/// Program the input-side ABI constraints for `inst` into the constraint solver.
///
/// ABI constraints are the fixed register assignments useds for calls and returns.
fn program_input_abi(&mut self, inst: Inst, abi_params: AbiParams) {
let abi_types = match abi_params {
AbiParams::Parameters(sig) => &self.cur.func.dfg.signatures[sig].params,
AbiParams::Returns => &self.cur.func.signature.returns,
};
for (abi, &value) in abi_types
.iter()
.zip(self.cur.func.dfg.inst_variable_args(inst))
{
if let ArgumentLoc::Reg(reg) = abi.location {
if let Affinity::Reg(rci) = self
.liveness
.get(value)
.expect("ABI register must have live range")
.affinity
{
let rc = self.reginfo.rc(rci);
let cur_reg = self.divert.reg(value, &self.cur.func.locations);
self.solver.reassign_in(value, rc, cur_reg, reg);
} else {
panic!("ABI argument {} should be in a register", value);
}
}
}
}
/// Color the values defined by `inst` and insert any necessary shuffle code to satisfy
/// instruction constraints.
///
@@ -316,25 +352,9 @@ impl<'a> Context<'a> {
}
let call_sig = self.cur.func.dfg.call_signature(inst);
if let Some(sig) = call_sig {
program_input_abi(
&mut self.solver,
inst,
&self.cur.func.dfg.signatures[sig].params,
&self.cur.func,
&self.liveness,
&self.reginfo,
&self.divert,
);
self.program_input_abi(inst, AbiParams::Parameters(sig));
} else if self.cur.func.dfg[inst].opcode().is_return() {
program_input_abi(
&mut self.solver,
inst,
&self.cur.func.signature.returns,
&self.cur.func,
&self.liveness,
&self.reginfo,
&self.divert,
);
self.program_input_abi(inst, AbiParams::Returns);
} else if self.cur.func.dfg[inst].opcode().is_branch() {
// This is a branch, so we need to make sure that globally live values are in their
// global registers. For EBBs that take arguments, we also need to place the argument
@@ -1104,35 +1124,6 @@ impl<'a> Context<'a> {
}
}
/// Program the input-side ABI constraints for `inst` into the constraint solver.
///
/// ABI constraints are the fixed register assignments used for calls and returns.
fn program_input_abi(
solver: &mut Solver,
inst: Inst,
abi_types: &[AbiParam],
func: &Function,
liveness: &Liveness,
reginfo: &RegInfo,
divert: &RegDiversions,
) {
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
{
let rc = reginfo.rc(rci);
let cur_reg = divert.reg(value, &func.locations);
solver.reassign_in(value, rc, cur_reg, reg);
} else {
panic!("ABI argument {} should be in a register", value);
}
}
}
}
/// Keep track of the set of available registers in two interference domains: all registers
/// considering diversions and global registers not considering diversions.
struct AvailableRegs {