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:
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user