Extract spill insertion into a reload::insert_spill function.

Make sure that spill instructions are generated in the same way
everywhere, including adding encoding and updating live ranges.
This commit is contained in:
Jakob Stoklund Olesen
2017-06-13 15:43:14 -07:00
parent 6381da948f
commit 5a23f975fc
2 changed files with 51 additions and 16 deletions

View File

@@ -17,6 +17,7 @@ isa riscv enable_e
; That is in order: ; That is in order:
; 1. The argument v1. ; 1. The argument v1.
; 2. The link register. ; 2. The link register.
; 3. The first computed value, v2
function %pyramid(i32) -> i32 { function %pyramid(i32) -> i32 {
ebb0(v1: i32): ebb0(v1: i32):
; check: $ebb0($(rv1=$V): i32, $(rlink=$V): i32) ; check: $ebb0($(rv1=$V): i32, $(rlink=$V): i32)
@@ -24,6 +25,9 @@ ebb0(v1: i32):
; nextln: $(link=$V) = spill $rlink ; nextln: $(link=$V) = spill $rlink
; not: spill ; not: spill
v2 = iadd_imm v1, 12 v2 = iadd_imm v1, 12
; check: $(r1v2=$V) = iadd_imm
; nextln: $v2 = spill $r1v2
; not: spill
v3 = iadd_imm v2, 12 v3 = iadd_imm v2, 12
v4 = iadd_imm v3, 12 v4 = iadd_imm v3, 12
v5 = iadd_imm v4, 12 v5 = iadd_imm v4, 12
@@ -35,7 +39,10 @@ ebb0(v1: i32):
v11 = iadd_imm v10, 12 v11 = iadd_imm v10, 12
v12 = iadd_imm v11, 12 v12 = iadd_imm v11, 12
v13 = iadd_imm v12, 12 v13 = iadd_imm v12, 12
v32 = iadd v12, v13 v14 = iadd_imm v13, 12
v33 = iadd v13, v14
; check: iadd $v13
v32 = iadd v33, v12
v31 = iadd v32, v11 v31 = iadd v32, v11
v30 = iadd v31, v10 v30 = iadd v31, v10
v29 = iadd v30, v9 v29 = iadd v30, v9
@@ -46,7 +53,11 @@ ebb0(v1: i32):
v24 = iadd v25, v4 v24 = iadd v25, v4
v23 = iadd v24, v3 v23 = iadd v24, v3
v22 = iadd v23, v2 v22 = iadd v23, v2
; check: $(r2v2=$V) = fill $v2
; check: $v22 = iadd $v23, $r2v2
v21 = iadd v22, v1 v21 = iadd v22, v1
; check: $(r2v1=$V) = fill $v1
; check: $v21 = iadd $v22, $r2v1
; check: $(rlink2=$V) = fill $link ; check: $(rlink2=$V) = fill $link
return v21 return v21
; check: return $v21, $rlink2 ; check: return $v21, $rlink2

View File

@@ -13,7 +13,7 @@ use dominator_tree::DominatorTree;
use entity_map::EntityMap; use entity_map::EntityMap;
use ir::{Ebb, Inst, Value, Function, Signature, DataFlowGraph}; use ir::{Ebb, Inst, Value, Function, Signature, DataFlowGraph};
use ir::layout::{Cursor, CursorPosition}; use ir::layout::{Cursor, CursorPosition};
use ir::{InstBuilder, ArgumentType, ArgumentLoc}; use ir::{InstBuilder, Opcode, ArgumentType, ArgumentLoc};
use isa::RegClass; use isa::RegClass;
use isa::{TargetIsa, Encoding, EncInfo, RecipeConstraints, ConstraintKind}; use isa::{TargetIsa, Encoding, EncInfo, RecipeConstraints, ConstraintKind};
use regalloc::affinity::Affinity; use regalloc::affinity::Affinity;
@@ -167,16 +167,14 @@ impl<'a> Context<'a> {
// An incoming register parameter was spilled. Replace the parameter value // An incoming register parameter was spilled. Replace the parameter value
// with a temporary register value that is immediately spilled. // with a temporary register value that is immediately spilled.
let reg = func.dfg.replace_ebb_arg(arg.value, abi.value_type); let reg = func.dfg.replace_ebb_arg(arg.value, abi.value_type);
func.dfg.ins(&mut pos).with_result(arg.value).spill(reg);
let spill = func.dfg.value_def(arg.value).unwrap_inst();
*func.encodings.ensure(spill) = self.isa
.encode(&func.dfg, &func.dfg[spill], abi.value_type)
.expect("Can't encode spill");
// Update live ranges.
self.liveness.move_def_locally(arg.value, spill);
let affinity = Affinity::abi(abi, self.isa); let affinity = Affinity::abi(abi, self.isa);
self.liveness.create_dead(reg, ebb, affinity); self.liveness.create_dead(reg, ebb, affinity);
self.liveness.extend_locally(reg, ebb, spill, pos.layout); self.insert_spill(ebb,
arg.value,
reg,
&mut pos,
&mut func.encodings,
&mut func.dfg);
} }
} }
ArgumentLoc::Stack(_) => { ArgumentLoc::Stack(_) => {
@@ -270,13 +268,8 @@ impl<'a> Context<'a> {
if lv.affinity.is_stack() && op.kind != ConstraintKind::Stack { if lv.affinity.is_stack() && op.kind != ConstraintKind::Stack {
let value_type = dfg.value_type(lv.value); let value_type = dfg.value_type(lv.value);
let reg = dfg.replace_result(lv.value, value_type); let reg = dfg.replace_result(lv.value, value_type);
dfg.ins(pos).with_result(lv.value).spill(reg);
let spill = dfg.value_def(lv.value).unwrap_inst();
// Create a live range for reg.
self.liveness.create_dead(reg, inst, Affinity::new(op)); self.liveness.create_dead(reg, inst, Affinity::new(op));
self.liveness.extend_locally(reg, ebb, spill, &pos.layout); self.insert_spill(ebb, lv.value, reg, pos, encodings, dfg);
self.liveness.move_def_locally(lv.value, spill);
} }
} }
} }
@@ -337,4 +330,35 @@ impl<'a> Context<'a> {
} }
} }
} }
/// Insert a spill at `pos` and update data structures.
///
/// - Insert `stack = spill reg` at `pos`, and assign an encoding.
/// - Move the `stack` live range starting point to the new instruction.
/// - Extend the `reg` live range to reach the new instruction.
fn insert_spill(&mut self,
ebb: Ebb,
stack: Value,
reg: Value,
pos: &mut Cursor,
encodings: &mut EntityMap<Inst, Encoding>,
dfg: &mut DataFlowGraph) {
let ty = dfg.value_type(reg);
// Insert spill instruction. Use the low-level `Unary` constructor because it returns an
// instruction reference directly rather than a result value (which we know is equal to
// `stack`).
let (inst, _) = dfg.ins(pos)
.with_result(stack)
.Unary(Opcode::Spill, ty, reg);
// Give it an encoding.
*encodings.ensure(inst) = self.isa
.encode(dfg, &dfg[inst], ty)
.expect("Can't encode spill");
// Update live ranges.
self.liveness.move_def_locally(stack, inst);
self.liveness.extend_locally(reg, ebb, inst, pos.layout);
}
} }