Handle ABI arguments correctly in the reload pass.
Values passed as arguments to calls and return instructions may also be reload candidates.
This commit is contained in:
@@ -14,10 +14,15 @@ test regalloc
|
|||||||
isa riscv enable_e
|
isa riscv enable_e
|
||||||
|
|
||||||
; In straight-line code, the first value defined is spilled.
|
; In straight-line code, the first value defined is spilled.
|
||||||
; That is the argument.
|
; That is in order:
|
||||||
|
; 1. The argument v1.
|
||||||
|
; 2. The link register.
|
||||||
function %pyramid(i32) -> i32 {
|
function %pyramid(i32) -> i32 {
|
||||||
ebb0(v1: i32):
|
ebb0(v1: i32):
|
||||||
; check: $v1 = spill $(rv1=$V)
|
; check: $ebb0($(rv1=$V): i32, $(rlink=$V): i32)
|
||||||
|
; check: $v1 = spill $rv1
|
||||||
|
; nextln: $(link=$V) = spill $rlink
|
||||||
|
; not: spill
|
||||||
v2 = iadd_imm v1, 12
|
v2 = iadd_imm v1, 12
|
||||||
v3 = iadd_imm v2, 12
|
v3 = iadd_imm v2, 12
|
||||||
v4 = iadd_imm v3, 12
|
v4 = iadd_imm v3, 12
|
||||||
@@ -29,7 +34,9 @@ ebb0(v1: i32):
|
|||||||
v10 = iadd_imm v9, 12
|
v10 = iadd_imm v9, 12
|
||||||
v11 = iadd_imm v10, 12
|
v11 = iadd_imm v10, 12
|
||||||
v12 = iadd_imm v11, 12
|
v12 = iadd_imm v11, 12
|
||||||
v31 = iadd v11, v12
|
v13 = iadd_imm v12, 12
|
||||||
|
v32 = iadd v12, v13
|
||||||
|
v31 = iadd v32, v11
|
||||||
v30 = iadd v31, v10
|
v30 = iadd v31, v10
|
||||||
v29 = iadd v30, v9
|
v29 = iadd v30, v9
|
||||||
v28 = iadd v29, v8
|
v28 = iadd v29, v8
|
||||||
@@ -40,5 +47,7 @@ ebb0(v1: i32):
|
|||||||
v23 = iadd v24, v3
|
v23 = iadd v24, v3
|
||||||
v22 = iadd v23, v2
|
v22 = iadd v23, v2
|
||||||
v21 = iadd v22, v1
|
v21 = iadd v22, v1
|
||||||
|
; check: $(rlink2=$V) = fill $link
|
||||||
return v21
|
return v21
|
||||||
|
; check: return $v21, $rlink2
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,6 +104,14 @@ impl ArgumentLoc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Is this a register location?
|
||||||
|
pub fn is_reg(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
&ArgumentLoc::Reg(_) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Return an object that can display this argument location, using the register info from the
|
/// Return an object that can display this argument location, using the register info from the
|
||||||
/// target ISA.
|
/// target ISA.
|
||||||
pub fn display<'a, R: Into<Option<&'a RegInfo>>>(self, regs: R) -> DisplayArgumentLoc<'a> {
|
pub fn display<'a, R: Into<Option<&'a RegInfo>>>(self, regs: R) -> DisplayArgumentLoc<'a> {
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ impl Coloring {
|
|||||||
liveness: &mut Liveness,
|
liveness: &mut Liveness,
|
||||||
topo: &mut TopoOrder,
|
topo: &mut TopoOrder,
|
||||||
tracker: &mut LiveValueTracker) {
|
tracker: &mut LiveValueTracker) {
|
||||||
|
dbg!("Coloring for:\n{}", func.display(isa));
|
||||||
let mut ctx = Context {
|
let mut ctx = Context {
|
||||||
reginfo: isa.register_info(),
|
reginfo: isa.register_info(),
|
||||||
encinfo: isa.encoding_info(),
|
encinfo: isa.encoding_info(),
|
||||||
|
|||||||
@@ -11,11 +11,11 @@
|
|||||||
|
|
||||||
use dominator_tree::DominatorTree;
|
use dominator_tree::DominatorTree;
|
||||||
use entity_map::EntityMap;
|
use entity_map::EntityMap;
|
||||||
use ir::{Ebb, Inst, Value, Function, DataFlowGraph};
|
use ir::{Ebb, Inst, Value, Function, Signature, DataFlowGraph};
|
||||||
use ir::layout::{Cursor, CursorPosition};
|
use ir::layout::{Cursor, CursorPosition};
|
||||||
use ir::{InstBuilder, ArgumentLoc};
|
use ir::{InstBuilder, ArgumentType, ArgumentLoc};
|
||||||
use isa::RegClass;
|
use isa::RegClass;
|
||||||
use isa::{TargetIsa, Encoding, EncInfo, ConstraintKind};
|
use isa::{TargetIsa, Encoding, EncInfo, RecipeConstraints, ConstraintKind};
|
||||||
use regalloc::affinity::Affinity;
|
use regalloc::affinity::Affinity;
|
||||||
use regalloc::live_value_tracker::{LiveValue, LiveValueTracker};
|
use regalloc::live_value_tracker::{LiveValue, LiveValueTracker};
|
||||||
use regalloc::liveness::Liveness;
|
use regalloc::liveness::Liveness;
|
||||||
@@ -61,6 +61,7 @@ impl Reload {
|
|||||||
liveness: &mut Liveness,
|
liveness: &mut Liveness,
|
||||||
topo: &mut TopoOrder,
|
topo: &mut TopoOrder,
|
||||||
tracker: &mut LiveValueTracker) {
|
tracker: &mut LiveValueTracker) {
|
||||||
|
dbg!("Reload for:\n{}", func.display(isa));
|
||||||
let mut ctx = Context {
|
let mut ctx = Context {
|
||||||
isa,
|
isa,
|
||||||
encinfo: isa.encoding_info(),
|
encinfo: isa.encoding_info(),
|
||||||
@@ -121,6 +122,7 @@ impl<'a> Context<'a> {
|
|||||||
&mut pos,
|
&mut pos,
|
||||||
&mut func.dfg,
|
&mut func.dfg,
|
||||||
&mut func.encodings,
|
&mut func.encodings,
|
||||||
|
&func.signature,
|
||||||
tracker);
|
tracker);
|
||||||
tracker.drop_dead(inst);
|
tracker.drop_dead(inst);
|
||||||
} else {
|
} else {
|
||||||
@@ -202,27 +204,16 @@ impl<'a> Context<'a> {
|
|||||||
pos: &mut Cursor,
|
pos: &mut Cursor,
|
||||||
dfg: &mut DataFlowGraph,
|
dfg: &mut DataFlowGraph,
|
||||||
encodings: &mut EntityMap<Inst, Encoding>,
|
encodings: &mut EntityMap<Inst, Encoding>,
|
||||||
|
func_signature: &Signature,
|
||||||
tracker: &mut LiveValueTracker) {
|
tracker: &mut LiveValueTracker) {
|
||||||
// Get the operand constraints for `inst` that we are trying to satisfy.
|
// Get the operand constraints for `inst` that we are trying to satisfy.
|
||||||
let constraints = self.encinfo
|
let constraints = self.encinfo
|
||||||
.operand_constraints(encoding)
|
.operand_constraints(encoding)
|
||||||
.expect("Missing instruction encoding");
|
.expect("Missing instruction encoding");
|
||||||
|
|
||||||
assert!(self.candidates.is_empty());
|
|
||||||
|
|
||||||
// Identify reload candidates.
|
// Identify reload candidates.
|
||||||
for (op, &arg) in constraints.ins.iter().zip(dfg.inst_args(inst)) {
|
assert!(self.candidates.is_empty());
|
||||||
if op.kind != ConstraintKind::Stack {
|
self.find_candidates(inst, constraints, func_signature, dfg);
|
||||||
let lv = self.liveness.get(arg).expect("Missing live range for arg");
|
|
||||||
if lv.affinity.is_stack() {
|
|
||||||
self.candidates
|
|
||||||
.push(ReloadCandidate {
|
|
||||||
value: arg,
|
|
||||||
regclass: op.regclass,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert fill instructions before `inst`.
|
// Insert fill instructions before `inst`.
|
||||||
while let Some(cand) = self.candidates.pop() {
|
while let Some(cand) = self.candidates.pop() {
|
||||||
@@ -289,4 +280,61 @@ impl<'a> Context<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find reload candidates for `inst` and add them to `self.condidates`.
|
||||||
|
//
|
||||||
|
// These are uses of spilled values where the operand constraint requires a register.
|
||||||
|
fn find_candidates(&mut self,
|
||||||
|
inst: Inst,
|
||||||
|
constraints: &RecipeConstraints,
|
||||||
|
func_signature: &Signature,
|
||||||
|
dfg: &DataFlowGraph) {
|
||||||
|
let args = dfg.inst_args(inst);
|
||||||
|
|
||||||
|
for (op, &arg) in constraints.ins.iter().zip(args) {
|
||||||
|
if op.kind != ConstraintKind::Stack {
|
||||||
|
let lv = self.liveness.get(arg).expect("Missing live range for arg");
|
||||||
|
if lv.affinity.is_stack() {
|
||||||
|
self.candidates
|
||||||
|
.push(ReloadCandidate {
|
||||||
|
value: arg,
|
||||||
|
regclass: op.regclass,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we only have the fixed arguments, we're done now.
|
||||||
|
if args.len() == constraints.ins.len() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let var_args = &args[constraints.ins.len()..];
|
||||||
|
|
||||||
|
// Handle ABI arguments.
|
||||||
|
if let Some(sig) = dfg.call_signature(inst) {
|
||||||
|
self.handle_abi_args(&dfg.signatures[sig].argument_types, var_args);
|
||||||
|
} else if dfg[inst].opcode().is_return() {
|
||||||
|
self.handle_abi_args(&func_signature.return_types, var_args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Find reload candidates in the instruction's ABI variable arguments. This handles both
|
||||||
|
/// return values and call arguments.
|
||||||
|
fn handle_abi_args(&mut self, abi_types: &[ArgumentType], var_args: &[Value]) {
|
||||||
|
assert_eq!(abi_types.len(), var_args.len());
|
||||||
|
for (abi, &arg) in abi_types.iter().zip(var_args) {
|
||||||
|
if abi.location.is_reg() {
|
||||||
|
let lv = self.liveness
|
||||||
|
.get(arg)
|
||||||
|
.expect("Missing live range for ABI arg");
|
||||||
|
if lv.affinity.is_stack() {
|
||||||
|
self.candidates
|
||||||
|
.push(ReloadCandidate {
|
||||||
|
value: arg,
|
||||||
|
regclass: self.isa.regclass_for_abi_type(abi.value_type),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user