Add fixed constraints for ABI arguments and return values.

We can start adding some real test cases for the move resolver now.
This commit is contained in:
Jakob Stoklund Olesen
2017-05-11 10:11:28 -07:00
parent 51fc887a5a
commit 663b50efcc
2 changed files with 98 additions and 19 deletions

View File

@@ -3,6 +3,8 @@ test regalloc
; We can add more ISAs once they have defined encodings.
isa riscv
; regex: RX=%x\d+
function add(i32, i32) {
ebb0(v1: i32, v2: i32):
v3 = iadd v1, v2
@@ -14,6 +16,27 @@ ebb0(v1: i32, v2: i32):
; Function with a dead argument.
function dead_arg(i32, i32) -> i32{
ebb0(v1: i32, v2: i32):
; not: regmove
; check: return $v1
return v1
}
; Return a value from a different register.
function move1(i32, i32) -> i32 {
ebb0(v1: i32, v2: i32):
; not: regmove
; check: regmove $v2, %x11 -> %x10
; nextln: return $v2
return v2
}
; Swap two registers.
function swap(i32, i32) -> i32, i32 {
ebb0(v1: i32, v2: i32):
; not: regmove
; check: regmove $v2, %x11 -> $(tmp=$RX)
; nextln: regmove $v1, %x10 -> %x11
; nextln: regmove $v2, $tmp -> %x10
; nextln: return $v2, $v1
return v2, v1
}

View File

@@ -33,8 +33,8 @@
use entity_map::EntityMap;
use dominator_tree::DominatorTree;
use ir::{Ebb, Inst, Value, Function, Cursor, ValueLoc, DataFlowGraph, Signature, ArgumentLoc};
use ir::InstBuilder;
use ir::{Ebb, Inst, Value, Function, Cursor, ValueLoc, DataFlowGraph};
use ir::{InstBuilder, Signature, ArgumentType, ArgumentLoc};
use isa::{TargetIsa, Encoding, EncInfo, OperandConstraint, ConstraintKind};
use isa::{RegUnit, RegClass, RegInfo, regs_overlap};
use regalloc::affinity::Affinity;
@@ -145,7 +145,8 @@ impl<'a> Context<'a> {
&mut func.dfg,
tracker,
&mut regs,
&mut func.locations);
&mut func.locations,
&func.signature);
tracker.drop_dead(inst);
}
@@ -307,7 +308,8 @@ impl<'a> Context<'a> {
dfg: &mut DataFlowGraph,
tracker: &mut LiveValueTracker,
regs: &mut AllocatableSet,
locations: &mut EntityMap<Value, ValueLoc>) {
locations: &mut EntityMap<Value, ValueLoc>,
func_signature: &Signature) {
dbg!("Coloring [{}] {}",
self.encinfo.display(encoding),
dfg.display_inst(inst));
@@ -320,6 +322,12 @@ impl<'a> Context<'a> {
// Program the solver with register constraints for the input side.
self.solver.reset(regs);
self.program_input_constraints(inst, constraints.ins, dfg, locations);
let call_sig = dfg.call_signature(inst);
if let Some(sig) = call_sig {
self.program_input_abi(inst, &dfg.signatures[sig].argument_types, dfg, locations);
} else if dfg[inst].opcode().is_return() {
self.program_input_abi(inst, &func_signature.return_types, dfg, locations);
}
if self.solver.has_fixed_input_conflicts() {
self.divert_fixed_input_conflicts(tracker.live(), locations);
}
@@ -342,12 +350,11 @@ impl<'a> Context<'a> {
// detect conflicts between fixed outputs and tied operands where the input value hasn't
// been converted to a solver variable.
if constraints.fixed_outs {
self.program_fixed_output_constraints(inst,
constraints.outs,
defs,
throughs,
dfg,
locations);
self.program_fixed_outputs(constraints.outs, defs, throughs, locations);
}
if let Some(sig) = call_sig {
let abi = &dfg.signatures[sig].return_types;
self.program_output_abi(abi, defs, throughs, locations);
}
self.program_output_constraints(inst, constraints.outs, defs, dfg, locations);
@@ -384,8 +391,8 @@ impl<'a> Context<'a> {
fn program_input_constraints(&mut self,
inst: Inst,
constraints: &[OperandConstraint],
dfg: &mut DataFlowGraph,
locations: &mut EntityMap<Value, ValueLoc>) {
dfg: &DataFlowGraph,
locations: &EntityMap<Value, ValueLoc>) {
for (op, &value) in constraints
.iter()
.zip(dfg.inst_args(inst))
@@ -412,6 +419,33 @@ 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(&mut self,
inst: Inst,
abi_types: &[ArgumentType],
dfg: &DataFlowGraph,
locations: &EntityMap<Value, ValueLoc>) {
for (abi, &value) in abi_types.iter().zip(dfg.inst_variable_args(inst)) {
if let ArgumentLoc::Reg(reg) = abi.location {
let cur_reg = self.divert.reg(value, locations);
if reg != cur_reg {
if let Affinity::Reg(rci) =
self.liveness
.get(value)
.expect("ABI register must have live range")
.affinity {
let rc = self.reginfo.rc(rci);
self.solver.reassign_in(value, rc, cur_reg, reg);
} else {
panic!("ABI argument {} should be in a register", value);
}
}
}
}
}
// Find existing live values that conflict with the fixed input register constraints programmed
// into the constraint solver. Convert them to solver variables so they can be diverted.
fn divert_fixed_input_conflicts(&mut self,
@@ -431,13 +465,11 @@ impl<'a> Context<'a> {
/// Program any fixed-register output constraints into the solver. This may also detect
/// conflicts between live-through registers and fixed output registers. These live-through
/// values need to be turned into solver variables so they can be reassigned.
fn program_fixed_output_constraints(&mut self,
_inst: Inst,
constraints: &[OperandConstraint],
defs: &[LiveValue],
throughs: &[LiveValue],
_dfg: &mut DataFlowGraph,
locations: &mut EntityMap<Value, ValueLoc>) {
fn program_fixed_outputs(&mut self,
constraints: &[OperandConstraint],
defs: &[LiveValue],
throughs: &[LiveValue],
locations: &mut EntityMap<Value, ValueLoc>) {
for (op, lv) in constraints.iter().zip(defs) {
if let ConstraintKind::FixedReg(reg) = op.kind {
self.add_fixed_output(lv.value, op.regclass, reg, throughs, locations);
@@ -445,6 +477,30 @@ impl<'a> Context<'a> {
}
}
/// Program the output-side ABI constraints for `inst` into the constraint solver.
///
/// That means return values for a call instruction.
fn program_output_abi(&mut self,
abi_types: &[ArgumentType],
defs: &[LiveValue],
throughs: &[LiveValue],
locations: &mut EntityMap<Value, ValueLoc>) {
// It's technically possible for a call instruction to have fixed results before the
// variable list of results, but we have no known instances of that.
// Just assume all results are variable return values.
assert_eq!(defs.len(), abi_types.len());
for (abi, lv) in abi_types.iter().zip(defs) {
if let ArgumentLoc::Reg(reg) = abi.location {
if let Affinity::Reg(rci) = lv.affinity {
let rc = self.reginfo.rc(rci);
self.add_fixed_output(lv.value, rc, reg, throughs, locations);
} else {
panic!("ABI argument {} should be in a register", lv.value);
}
}
}
}
/// Add a single fixed output value to the solver.
fn add_fixed_output(&mut self,
value: Value,