Use EncCursor in regalloc/spilling.rs
Use an EncCursor instead of a layout cursor to keep track of the current position in the function. Since the EncCursor holds a reference to the whole IR function insteadof just the layout, we can rework how IR borrowing works. The Context data structure that's live during the spilling pass now owns an EncCursor which in turn holds references to the function and ISA. This means that we no longer need to pass around references to parts of the ir::Function. We can no longer borrow any part of the IR function across a context method call, but that turns out to be not necessary.
This commit is contained in:
@@ -15,10 +15,9 @@
|
|||||||
//! be compatible. Otherwise, the value must be copied into a new register for some of the
|
//! be compatible. Otherwise, the value must be copied into a new register for some of the
|
||||||
//! operands.
|
//! operands.
|
||||||
|
|
||||||
|
use cursor::{Cursor, EncCursor};
|
||||||
use dominator_tree::DominatorTree;
|
use dominator_tree::DominatorTree;
|
||||||
use ir::{DataFlowGraph, Layout, Cursor, CursorBase, InstBuilder};
|
use ir::{InstBuilder, Function, Ebb, Inst, Value, ValueLoc, SigRef};
|
||||||
use ir::{Function, Ebb, Inst, Value, ValueLoc, SigRef};
|
|
||||||
use ir::{InstEncodings, StackSlots, ValueLocations};
|
|
||||||
use isa::registers::{RegClassMask, RegClassIndex};
|
use isa::registers::{RegClassMask, RegClassIndex};
|
||||||
use isa::{TargetIsa, RegInfo, EncInfo, RecipeConstraints, ConstraintKind};
|
use isa::{TargetIsa, RegInfo, EncInfo, RecipeConstraints, ConstraintKind};
|
||||||
use regalloc::affinity::Affinity;
|
use regalloc::affinity::Affinity;
|
||||||
@@ -37,16 +36,13 @@ pub struct Spilling {
|
|||||||
|
|
||||||
/// Context data structure that gets instantiated once per pass.
|
/// Context data structure that gets instantiated once per pass.
|
||||||
struct Context<'a> {
|
struct Context<'a> {
|
||||||
isa: &'a TargetIsa,
|
// Current instruction as well as reference to function and ISA.
|
||||||
|
cur: EncCursor<'a>,
|
||||||
|
|
||||||
// Cached ISA information.
|
// Cached ISA information.
|
||||||
reginfo: RegInfo,
|
reginfo: RegInfo,
|
||||||
encinfo: EncInfo,
|
encinfo: EncInfo,
|
||||||
|
|
||||||
// References to parts of the current function.
|
|
||||||
encodings: &'a mut InstEncodings,
|
|
||||||
stack_slots: &'a mut StackSlots,
|
|
||||||
locations: &'a mut ValueLocations,
|
|
||||||
|
|
||||||
// References to contextual data structures we need.
|
// References to contextual data structures we need.
|
||||||
domtree: &'a DominatorTree,
|
domtree: &'a DominatorTree,
|
||||||
liveness: &'a mut Liveness,
|
liveness: &'a mut Liveness,
|
||||||
@@ -87,12 +83,9 @@ impl Spilling {
|
|||||||
let reginfo = isa.register_info();
|
let reginfo = isa.register_info();
|
||||||
let usable_regs = isa.allocatable_registers(func);
|
let usable_regs = isa.allocatable_registers(func);
|
||||||
let mut ctx = Context {
|
let mut ctx = Context {
|
||||||
isa,
|
cur: EncCursor::new(func, isa),
|
||||||
reginfo: isa.register_info(),
|
reginfo: isa.register_info(),
|
||||||
encinfo: isa.encoding_info(),
|
encinfo: isa.encoding_info(),
|
||||||
encodings: &mut func.encodings,
|
|
||||||
stack_slots: &mut func.stack_slots,
|
|
||||||
locations: &mut func.locations,
|
|
||||||
domtree,
|
domtree,
|
||||||
liveness,
|
liveness,
|
||||||
virtregs,
|
virtregs,
|
||||||
@@ -101,35 +94,29 @@ impl Spilling {
|
|||||||
spills: &mut self.spills,
|
spills: &mut self.spills,
|
||||||
reg_uses: &mut self.reg_uses,
|
reg_uses: &mut self.reg_uses,
|
||||||
};
|
};
|
||||||
ctx.run(&mut func.layout, &mut func.dfg, tracker)
|
ctx.run(tracker)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Context<'a> {
|
impl<'a> Context<'a> {
|
||||||
fn run(&mut self,
|
fn run(&mut self, tracker: &mut LiveValueTracker) {
|
||||||
layout: &mut Layout,
|
self.topo.reset(self.cur.func.layout.ebbs());
|
||||||
dfg: &mut DataFlowGraph,
|
while let Some(ebb) = self.topo.next(&self.cur.func.layout, self.domtree) {
|
||||||
tracker: &mut LiveValueTracker) {
|
self.visit_ebb(ebb, tracker);
|
||||||
self.topo.reset(layout.ebbs());
|
|
||||||
while let Some(ebb) = self.topo.next(layout, self.domtree) {
|
|
||||||
self.visit_ebb(ebb, layout, dfg, tracker);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_ebb(&mut self,
|
fn visit_ebb(&mut self, ebb: Ebb, tracker: &mut LiveValueTracker) {
|
||||||
ebb: Ebb,
|
|
||||||
layout: &mut Layout,
|
|
||||||
dfg: &mut DataFlowGraph,
|
|
||||||
tracker: &mut LiveValueTracker) {
|
|
||||||
dbg!("Spilling {}:", ebb);
|
dbg!("Spilling {}:", ebb);
|
||||||
self.visit_ebb_header(ebb, layout, dfg, tracker);
|
self.cur.goto_top(ebb);
|
||||||
|
self.visit_ebb_header(ebb, tracker);
|
||||||
tracker.drop_dead_args();
|
tracker.drop_dead_args();
|
||||||
|
|
||||||
let mut pos = Cursor::new(layout);
|
while let Some(inst) = self.cur.next_inst() {
|
||||||
pos.goto_top(ebb);
|
if let Some(constraints) =
|
||||||
while let Some(inst) = pos.next_inst() {
|
self.encinfo
|
||||||
if let Some(constraints) = self.encinfo.operand_constraints(self.encodings[inst]) {
|
.operand_constraints(self.cur.func.encodings[inst]) {
|
||||||
self.visit_inst(inst, ebb, constraints, &mut pos, dfg, tracker);
|
self.visit_inst(inst, ebb, constraints, tracker);
|
||||||
} else {
|
} else {
|
||||||
let (_throughs, kills) = tracker.process_ghost(inst);
|
let (_throughs, kills) = tracker.process_ghost(inst);
|
||||||
self.free_regs(kills);
|
self.free_regs(kills);
|
||||||
@@ -162,12 +149,12 @@ impl<'a> Context<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_ebb_header(&mut self,
|
fn visit_ebb_header(&mut self, ebb: Ebb, tracker: &mut LiveValueTracker) {
|
||||||
ebb: Ebb,
|
let (liveins, args) = tracker.ebb_top(ebb,
|
||||||
layout: &mut Layout,
|
&self.cur.func.dfg,
|
||||||
dfg: &mut DataFlowGraph,
|
self.liveness,
|
||||||
tracker: &mut LiveValueTracker) {
|
&self.cur.func.layout,
|
||||||
let (liveins, args) = tracker.ebb_top(ebb, dfg, self.liveness, layout, self.domtree);
|
self.domtree);
|
||||||
|
|
||||||
// Count the live-in registers. These should already fit in registers; they did at the
|
// Count the live-in registers. These should already fit in registers; they did at the
|
||||||
// dominator.
|
// dominator.
|
||||||
@@ -184,13 +171,13 @@ impl<'a> Context<'a> {
|
|||||||
rc,
|
rc,
|
||||||
lv.value,
|
lv.value,
|
||||||
liveins.len());
|
liveins.len());
|
||||||
match self.spill_candidate(mask, liveins, dfg, layout) {
|
match self.spill_candidate(mask, liveins) {
|
||||||
Some(cand) => {
|
Some(cand) => {
|
||||||
dbg!("Spilling live-in {} to make room for {} EBB argument {}",
|
dbg!("Spilling live-in {} to make room for {} EBB argument {}",
|
||||||
cand,
|
cand,
|
||||||
rc,
|
rc,
|
||||||
lv.value);
|
lv.value);
|
||||||
self.spill_reg(cand, dfg);
|
self.spill_reg(cand);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
// We can't spill any of the live-in registers, so we have to spill an
|
// We can't spill any of the live-in registers, so we have to spill an
|
||||||
@@ -200,7 +187,7 @@ impl<'a> Context<'a> {
|
|||||||
|
|
||||||
// Since `spill_reg` will free a register, add the current one here.
|
// Since `spill_reg` will free a register, add the current one here.
|
||||||
self.pressure.take(rc);
|
self.pressure.take(rc);
|
||||||
self.spill_reg(lv.value, dfg);
|
self.spill_reg(lv.value);
|
||||||
break 'try_take;
|
break 'try_take;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -216,29 +203,27 @@ impl<'a> Context<'a> {
|
|||||||
inst: Inst,
|
inst: Inst,
|
||||||
ebb: Ebb,
|
ebb: Ebb,
|
||||||
constraints: &RecipeConstraints,
|
constraints: &RecipeConstraints,
|
||||||
pos: &mut Cursor,
|
|
||||||
dfg: &mut DataFlowGraph,
|
|
||||||
tracker: &mut LiveValueTracker) {
|
tracker: &mut LiveValueTracker) {
|
||||||
dbg!("Inst {}, {}",
|
dbg!("Inst {}, {}", self.cur.display_inst(inst), self.pressure);
|
||||||
dfg.display_inst(inst, self.isa),
|
debug_assert_eq!(self.cur.current_inst(), Some(inst));
|
||||||
self.pressure);
|
debug_assert_eq!(self.cur.current_ebb(), Some(ebb));
|
||||||
|
|
||||||
// We may need to resolve register constraints if there are any noteworthy uses.
|
// We may need to resolve register constraints if there are any noteworthy uses.
|
||||||
assert!(self.reg_uses.is_empty());
|
assert!(self.reg_uses.is_empty());
|
||||||
self.collect_reg_uses(inst, ebb, constraints, dfg, pos.layout);
|
self.collect_reg_uses(inst, ebb, constraints);
|
||||||
|
|
||||||
// Calls usually have fixed register uses.
|
// Calls usually have fixed register uses.
|
||||||
let call_sig = dfg.call_signature(inst);
|
let call_sig = self.cur.func.dfg.call_signature(inst);
|
||||||
if let Some(sig) = call_sig {
|
if let Some(sig) = call_sig {
|
||||||
self.collect_abi_reg_uses(inst, sig, dfg);
|
self.collect_abi_reg_uses(inst, sig);
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.reg_uses.is_empty() {
|
if !self.reg_uses.is_empty() {
|
||||||
self.process_reg_uses(inst, pos, dfg, tracker);
|
self.process_reg_uses(inst, tracker);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the live value tracker with this instruction.
|
// Update the live value tracker with this instruction.
|
||||||
let (throughs, kills, defs) = tracker.process_inst(inst, dfg, self.liveness);
|
let (throughs, kills, defs) = tracker.process_inst(inst, &self.cur.func.dfg, self.liveness);
|
||||||
|
|
||||||
// Remove kills from the pressure tracker.
|
// Remove kills from the pressure tracker.
|
||||||
self.free_regs(kills);
|
self.free_regs(kills);
|
||||||
@@ -249,7 +234,7 @@ impl<'a> Context<'a> {
|
|||||||
if call_sig.is_some() {
|
if call_sig.is_some() {
|
||||||
for lv in throughs {
|
for lv in throughs {
|
||||||
if lv.affinity.is_reg() && !self.spills.contains(&lv.value) {
|
if lv.affinity.is_reg() && !self.spills.contains(&lv.value) {
|
||||||
self.spill_reg(lv.value, dfg);
|
self.spill_reg(lv.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -262,12 +247,12 @@ impl<'a> Context<'a> {
|
|||||||
// Add register def to pressure, spill if needed.
|
// Add register def to pressure, spill if needed.
|
||||||
while let Err(mask) = self.pressure.take_transient(op.regclass) {
|
while let Err(mask) = self.pressure.take_transient(op.regclass) {
|
||||||
dbg!("Need {} reg from {} throughs", op.regclass, throughs.len());
|
dbg!("Need {} reg from {} throughs", op.regclass, throughs.len());
|
||||||
match self.spill_candidate(mask, throughs, dfg, pos.layout) {
|
match self.spill_candidate(mask, throughs) {
|
||||||
Some(cand) => self.spill_reg(cand, dfg),
|
Some(cand) => self.spill_reg(cand),
|
||||||
None => {
|
None => {
|
||||||
panic!("Ran out of {} registers for {}",
|
panic!("Ran out of {} registers for {}",
|
||||||
op.regclass,
|
op.regclass,
|
||||||
dfg.display_inst(inst, self.isa))
|
self.cur.display_inst(inst))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -290,13 +275,8 @@ impl<'a> Context<'a> {
|
|||||||
// We are assuming here that if a value is used both by a fixed register operand and a register
|
// We are assuming here that if a value is used both by a fixed register operand and a register
|
||||||
// class operand, they two are compatible. We are also assuming that two register class
|
// class operand, they two are compatible. We are also assuming that two register class
|
||||||
// operands are always compatible.
|
// operands are always compatible.
|
||||||
fn collect_reg_uses(&mut self,
|
fn collect_reg_uses(&mut self, inst: Inst, ebb: Ebb, constraints: &RecipeConstraints) {
|
||||||
inst: Inst,
|
let args = self.cur.func.dfg.inst_args(inst);
|
||||||
ebb: Ebb,
|
|
||||||
constraints: &RecipeConstraints,
|
|
||||||
dfg: &DataFlowGraph,
|
|
||||||
layout: &Layout) {
|
|
||||||
let args = dfg.inst_args(inst);
|
|
||||||
for (idx, (op, &arg)) in constraints.ins.iter().zip(args).enumerate() {
|
for (idx, (op, &arg)) in constraints.ins.iter().zip(args).enumerate() {
|
||||||
let mut reguse = RegUse::new(arg, idx, op.regclass.into());
|
let mut reguse = RegUse::new(arg, idx, op.regclass.into());
|
||||||
let lr = &self.liveness[arg];
|
let lr = &self.liveness[arg];
|
||||||
@@ -305,7 +285,7 @@ impl<'a> Context<'a> {
|
|||||||
ConstraintKind::FixedReg(_) => reguse.fixed = true,
|
ConstraintKind::FixedReg(_) => reguse.fixed = true,
|
||||||
ConstraintKind::Tied(_) => {
|
ConstraintKind::Tied(_) => {
|
||||||
// A tied operand must kill the used value.
|
// A tied operand must kill the used value.
|
||||||
reguse.tied = !lr.killed_at(inst, ebb, layout);
|
reguse.tied = !lr.killed_at(inst, ebb, &self.cur.func.layout);
|
||||||
}
|
}
|
||||||
ConstraintKind::Reg => {}
|
ConstraintKind::Reg => {}
|
||||||
}
|
}
|
||||||
@@ -322,11 +302,14 @@ impl<'a> Context<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Collect register uses from the ABI input constraints.
|
// Collect register uses from the ABI input constraints.
|
||||||
fn collect_abi_reg_uses(&mut self, inst: Inst, sig: SigRef, dfg: &DataFlowGraph) {
|
fn collect_abi_reg_uses(&mut self, inst: Inst, sig: SigRef) {
|
||||||
let fixed_args = dfg[inst].opcode().constraints().fixed_value_arguments();
|
let fixed_args = self.cur.func.dfg[inst]
|
||||||
let args = dfg.inst_variable_args(inst);
|
.opcode()
|
||||||
|
.constraints()
|
||||||
|
.fixed_value_arguments();
|
||||||
|
let args = self.cur.func.dfg.inst_variable_args(inst);
|
||||||
for (idx, (abi, &arg)) in
|
for (idx, (abi, &arg)) in
|
||||||
dfg.signatures[sig]
|
self.cur.func.dfg.signatures[sig]
|
||||||
.argument_types
|
.argument_types
|
||||||
.iter()
|
.iter()
|
||||||
.zip(args)
|
.zip(args)
|
||||||
@@ -335,7 +318,7 @@ impl<'a> Context<'a> {
|
|||||||
let (rci, spilled) = match self.liveness[arg].affinity {
|
let (rci, spilled) = match self.liveness[arg].affinity {
|
||||||
Affinity::Reg(rci) => (rci, false),
|
Affinity::Reg(rci) => (rci, false),
|
||||||
Affinity::Stack => {
|
Affinity::Stack => {
|
||||||
(self.isa.regclass_for_abi_type(abi.value_type).into(), true)
|
(self.cur.isa.regclass_for_abi_type(abi.value_type).into(), true)
|
||||||
}
|
}
|
||||||
Affinity::None => panic!("Missing affinity for {}", arg),
|
Affinity::None => panic!("Missing affinity for {}", arg),
|
||||||
};
|
};
|
||||||
@@ -353,11 +336,7 @@ impl<'a> Context<'a> {
|
|||||||
// Trigger spilling if any of the temporaries cause the register pressure to become too high.
|
// Trigger spilling if any of the temporaries cause the register pressure to become too high.
|
||||||
//
|
//
|
||||||
// Leave `self.reg_uses` empty.
|
// Leave `self.reg_uses` empty.
|
||||||
fn process_reg_uses(&mut self,
|
fn process_reg_uses(&mut self, inst: Inst, tracker: &LiveValueTracker) {
|
||||||
inst: Inst,
|
|
||||||
pos: &mut Cursor,
|
|
||||||
dfg: &mut DataFlowGraph,
|
|
||||||
tracker: &LiveValueTracker) {
|
|
||||||
// We're looking for multiple uses of the same value, so start by sorting by value. The
|
// We're looking for multiple uses of the same value, so start by sorting by value. The
|
||||||
// secondary `opidx` key makes it possible to use an unstable sort once that is available
|
// secondary `opidx` key makes it possible to use an unstable sort once that is available
|
||||||
// outside nightly Rust.
|
// outside nightly Rust.
|
||||||
@@ -381,8 +360,8 @@ impl<'a> Context<'a> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if need_copy {
|
if need_copy {
|
||||||
let copy = self.insert_copy(ru.value, ru.rci, pos, dfg);
|
let copy = self.insert_copy(ru.value, ru.rci);
|
||||||
dfg.inst_args_mut(inst)[ru.opidx as usize] = copy;
|
self.cur.func.dfg.inst_args_mut(inst)[ru.opidx as usize] = copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Even if we don't insert a copy, we may need to account for register pressure for the
|
// Even if we don't insert a copy, we may need to account for register pressure for the
|
||||||
@@ -393,18 +372,18 @@ impl<'a> Context<'a> {
|
|||||||
dbg!("Copy of {} reg causes spill", rc);
|
dbg!("Copy of {} reg causes spill", rc);
|
||||||
// Spill a live register that is *not* used by the current instruction.
|
// Spill a live register that is *not* used by the current instruction.
|
||||||
// Spilling a use wouldn't help.
|
// Spilling a use wouldn't help.
|
||||||
let args = dfg.inst_args(inst);
|
match {
|
||||||
match self.spill_candidate(mask,
|
let args = self.cur.func.dfg.inst_args(inst);
|
||||||
tracker.live().iter().filter(|lv| {
|
self.spill_candidate(mask,
|
||||||
!args.contains(&lv.value)
|
tracker.live().iter().filter(|lv| {
|
||||||
}),
|
!args.contains(&lv.value)
|
||||||
dfg,
|
}))
|
||||||
&pos.layout) {
|
} {
|
||||||
Some(cand) => self.spill_reg(cand, dfg),
|
Some(cand) => self.spill_reg(cand),
|
||||||
None => {
|
None => {
|
||||||
panic!("Ran out of {} registers when inserting copy before {}",
|
panic!("Ran out of {} registers when inserting copy before {}",
|
||||||
rc,
|
rc,
|
||||||
dfg.display_inst(inst, self.isa))
|
self.cur.display_inst(inst))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -415,12 +394,7 @@ impl<'a> Context<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Find a spill candidate from `candidates` whose top-level register class is in `mask`.
|
// Find a spill candidate from `candidates` whose top-level register class is in `mask`.
|
||||||
fn spill_candidate<'ii, II>(&self,
|
fn spill_candidate<'ii, II>(&self, mask: RegClassMask, candidates: II) -> Option<Value>
|
||||||
mask: RegClassMask,
|
|
||||||
candidates: II,
|
|
||||||
dfg: &DataFlowGraph,
|
|
||||||
layout: &Layout)
|
|
||||||
-> Option<Value>
|
|
||||||
where II: IntoIterator<Item = &'ii LiveValue>
|
where II: IntoIterator<Item = &'ii LiveValue>
|
||||||
{
|
{
|
||||||
// Find the best viable spill candidate.
|
// Find the best viable spill candidate.
|
||||||
@@ -448,7 +422,9 @@ impl<'a> Context<'a> {
|
|||||||
.min_by(|&a, &b| {
|
.min_by(|&a, &b| {
|
||||||
// Find the minimum candidate according to the RPO of their defs.
|
// Find the minimum candidate according to the RPO of their defs.
|
||||||
self.domtree
|
self.domtree
|
||||||
.rpo_cmp(dfg.value_def(a), dfg.value_def(b), layout)
|
.rpo_cmp(self.cur.func.dfg.value_def(a),
|
||||||
|
self.cur.func.dfg.value_def(b),
|
||||||
|
&self.cur.func.layout)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -460,7 +436,7 @@ impl<'a> Context<'a> {
|
|||||||
///
|
///
|
||||||
/// Note that this does not update the cached affinity in the live value tracker. Call
|
/// Note that this does not update the cached affinity in the live value tracker. Call
|
||||||
/// `process_spills` to do that.
|
/// `process_spills` to do that.
|
||||||
fn spill_reg(&mut self, value: Value, dfg: &DataFlowGraph) {
|
fn spill_reg(&mut self, value: Value) {
|
||||||
if let Affinity::Reg(rci) = self.liveness.spill(value) {
|
if let Affinity::Reg(rci) = self.liveness.spill(value) {
|
||||||
let rc = self.reginfo.rc(rci);
|
let rc = self.reginfo.rc(rci);
|
||||||
self.pressure.free(rc);
|
self.pressure.free(rc);
|
||||||
@@ -471,10 +447,13 @@ impl<'a> Context<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Assign a spill slot for the whole virtual register.
|
// Assign a spill slot for the whole virtual register.
|
||||||
let ss = self.stack_slots.make_spill_slot(dfg.value_type(value));
|
let ss = self.cur
|
||||||
|
.func
|
||||||
|
.stack_slots
|
||||||
|
.make_spill_slot(self.cur.func.dfg.value_type(value));
|
||||||
for &v in self.virtregs.congruence_class(&value) {
|
for &v in self.virtregs.congruence_class(&value) {
|
||||||
self.liveness.spill(v);
|
self.liveness.spill(v);
|
||||||
*self.locations.ensure(v) = ValueLoc::Stack(ss);
|
*self.cur.func.locations.ensure(v) = ValueLoc::Stack(ss);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -492,32 +471,21 @@ impl<'a> Context<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Insert a `copy value` before `pos` and give it a live range extending to `pos`.
|
/// Insert a `copy value` before the current instruction and give it a live range extending to
|
||||||
|
/// the current instruction.
|
||||||
///
|
///
|
||||||
/// Returns the new local value created.
|
/// Returns the new local value created.
|
||||||
fn insert_copy(&mut self,
|
fn insert_copy(&mut self, value: Value, rci: RegClassIndex) -> Value {
|
||||||
value: Value,
|
let copy = self.cur.ins().copy(value);
|
||||||
rci: RegClassIndex,
|
let inst = self.cur.built_inst();
|
||||||
pos: &mut Cursor,
|
|
||||||
dfg: &mut DataFlowGraph)
|
|
||||||
-> Value {
|
|
||||||
let copy = dfg.ins(pos).copy(value);
|
|
||||||
let inst = dfg.value_def(copy).unwrap_inst();
|
|
||||||
let ty = dfg.value_type(copy);
|
|
||||||
|
|
||||||
// Give it an encoding.
|
|
||||||
match self.isa.encode(dfg, &dfg[inst], ty) {
|
|
||||||
Ok(e) => *self.encodings.ensure(inst) = e,
|
|
||||||
Err(_) => panic!("Can't encode {}", dfg.display_inst(inst, self.isa)),
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update live ranges.
|
// Update live ranges.
|
||||||
self.liveness.create_dead(copy, inst, Affinity::Reg(rci));
|
self.liveness.create_dead(copy, inst, Affinity::Reg(rci));
|
||||||
self.liveness
|
self.liveness
|
||||||
.extend_locally(copy,
|
.extend_locally(copy,
|
||||||
pos.layout.pp_ebb(inst),
|
self.cur.func.layout.pp_ebb(inst),
|
||||||
pos.current_inst().expect("must be at an instruction"),
|
self.cur.current_inst().expect("must be at an instruction"),
|
||||||
pos.layout);
|
&self.cur.func.layout);
|
||||||
|
|
||||||
copy
|
copy
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user