Handle moves specially with move-insertion logic rather than ordinary operand/inst handling
This commit is contained in:
@@ -130,7 +130,7 @@ impl Function for Func {
|
|||||||
&self.reftype_vregs[..]
|
&self.reftype_vregs[..]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_move(&self, _: Inst) -> Option<(VReg, VReg)> {
|
fn is_move(&self, insn: Inst) -> Option<(VReg, VReg)> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
297
src/ion/mod.rs
297
src/ion/mod.rs
@@ -19,17 +19,10 @@
|
|||||||
* - safepoints?
|
* - safepoints?
|
||||||
* - split just before uses with fixed regs and/or just after defs
|
* - split just before uses with fixed regs and/or just after defs
|
||||||
* with fixed regs?
|
* with fixed regs?
|
||||||
* - try-any-reg allocate loop should randomly probe in caller-save
|
|
||||||
* ("preferred") regs first -- have a notion of "preferred regs" in
|
|
||||||
* MachineEnv?
|
|
||||||
* - measure average liverange length / number of splits / ...
|
* - measure average liverange length / number of splits / ...
|
||||||
*
|
*
|
||||||
* - reused-input reg: don't allocate register for input that is reused.
|
* - reused-input reg: don't allocate register for input that is reused.
|
||||||
*
|
*
|
||||||
* - modify CL to generate SSA VCode
|
|
||||||
* - lower blockparams to blockparams directly
|
|
||||||
* - use temps properly (`alloc_tmp()` vs `alloc_reg()`)
|
|
||||||
*
|
|
||||||
* - "Fixed-stack location": negative spillslot numbers?
|
* - "Fixed-stack location": negative spillslot numbers?
|
||||||
*
|
*
|
||||||
* - Rematerialization
|
* - Rematerialization
|
||||||
@@ -38,16 +31,6 @@
|
|||||||
/*
|
/*
|
||||||
Performance ideas:
|
Performance ideas:
|
||||||
|
|
||||||
- moves: don't consider as normal inst with uses/defs
|
|
||||||
- explicit list of src/dst pairs? elide completely if
|
|
||||||
remain in same bundle; otherwise only should appear
|
|
||||||
when generating halfmoves
|
|
||||||
- sorted list of (inst, src-vreg, dst-vreg) and
|
|
||||||
(vreg, inst)
|
|
||||||
- ignore inst during all passes over code
|
|
||||||
- when same bundle at both ends, ignore during resolution
|
|
||||||
- otherwise, fill in move-list alloc slots during scans
|
|
||||||
|
|
||||||
- conflict hints? (note on one bundle that it definitely conflicts
|
- conflict hints? (note on one bundle that it definitely conflicts
|
||||||
with another, so avoid probing the other's alloc)
|
with another, so avoid probing the other's alloc)
|
||||||
|
|
||||||
@@ -139,8 +122,9 @@ struct LiveRange {
|
|||||||
next_in_bundle: LiveRangeIndex,
|
next_in_bundle: LiveRangeIndex,
|
||||||
next_in_reg: LiveRangeIndex,
|
next_in_reg: LiveRangeIndex,
|
||||||
|
|
||||||
reg_hint: Option<PReg>, // if a bundle partly fits, this is used to
|
// if a bundle partly fits, this is used to record LRs that do fit
|
||||||
// record LRs that do fit
|
reg_hint: Option<PReg>,
|
||||||
|
merged_into: LiveRangeIndex,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
@@ -317,6 +301,21 @@ struct Env<'a, F: Function> {
|
|||||||
spillslots: Vec<SpillSlotData>,
|
spillslots: Vec<SpillSlotData>,
|
||||||
slots_by_size: Vec<SpillSlotList>,
|
slots_by_size: Vec<SpillSlotList>,
|
||||||
|
|
||||||
|
// Program moves: these are moves in the provided program that we
|
||||||
|
// handle with our internal machinery, in order to avoid the
|
||||||
|
// overhead of ordinary operand processing. We expect the client
|
||||||
|
// to not generate any code for instructions that return
|
||||||
|
// `Some(..)` for `.is_move()`, and instead use the edits that we
|
||||||
|
// provide to implement those moves (or some simplified version of
|
||||||
|
// them) post-regalloc.
|
||||||
|
//
|
||||||
|
// (from-vreg, inst, from-alloc), sorted by (from-vreg, inst)
|
||||||
|
prog_move_srcs: Vec<((VRegIndex, Inst), Allocation)>,
|
||||||
|
// (to-vreg, inst, to-alloc), sorted by (to-vreg, inst)
|
||||||
|
prog_move_dsts: Vec<((VRegIndex, Inst), Allocation)>,
|
||||||
|
// (from-vreg, to-vreg) for bundle-merging.
|
||||||
|
prog_move_merges: Vec<(LiveRangeIndex, LiveRangeIndex)>,
|
||||||
|
|
||||||
// When multiple fixed-register constraints are present on a
|
// When multiple fixed-register constraints are present on a
|
||||||
// single VReg at a single program point (this can happen for,
|
// single VReg at a single program point (this can happen for,
|
||||||
// e.g., call args that use the same value multiple times), we
|
// e.g., call args that use the same value multiple times), we
|
||||||
@@ -535,6 +534,7 @@ enum InsertMovePrio {
|
|||||||
MultiFixedReg,
|
MultiFixedReg,
|
||||||
ReusedInput,
|
ReusedInput,
|
||||||
OutEdgeMoves,
|
OutEdgeMoves,
|
||||||
|
ProgramMove,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default)]
|
#[derive(Clone, Copy, Debug, Default)]
|
||||||
@@ -671,6 +671,10 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
spillslots: vec![],
|
spillslots: vec![],
|
||||||
slots_by_size: vec![],
|
slots_by_size: vec![],
|
||||||
|
|
||||||
|
prog_move_srcs: vec![],
|
||||||
|
prog_move_dsts: vec![],
|
||||||
|
prog_move_merges: vec![],
|
||||||
|
|
||||||
multi_fixed_reg_fixups: vec![],
|
multi_fixed_reg_fixups: vec![],
|
||||||
inserted_moves: vec![],
|
inserted_moves: vec![],
|
||||||
edits: vec![],
|
edits: vec![],
|
||||||
@@ -741,6 +745,7 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
next_in_bundle: LiveRangeIndex::invalid(),
|
next_in_bundle: LiveRangeIndex::invalid(),
|
||||||
next_in_reg: LiveRangeIndex::invalid(),
|
next_in_reg: LiveRangeIndex::invalid(),
|
||||||
reg_hint: None,
|
reg_hint: None,
|
||||||
|
merged_into: LiveRangeIndex::invalid(),
|
||||||
});
|
});
|
||||||
LiveRangeIndex::new(idx)
|
LiveRangeIndex::new(idx)
|
||||||
}
|
}
|
||||||
@@ -894,6 +899,7 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
iter = usedata.next_use;
|
iter = usedata.next_use;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
self.ranges[from.index()].merged_into = into;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_liverange_stats_on_remove_use(&mut self, from: LiveRangeIndex, u: UseIndex) {
|
fn update_liverange_stats_on_remove_use(&mut self, from: LiveRangeIndex, u: UseIndex) {
|
||||||
@@ -1114,6 +1120,73 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If this is a move, handle specially.
|
||||||
|
if let Some((src, dst)) = self.func.is_move(inst) {
|
||||||
|
log::debug!(" -> move inst{}: src {} -> dst {}", inst.index(), src, dst);
|
||||||
|
assert_eq!(src.class(), dst.class());
|
||||||
|
|
||||||
|
// Handle the def w.r.t. liveranges: trim the
|
||||||
|
// start of the range and mark it dead at this
|
||||||
|
// point in our backward scan.
|
||||||
|
let pos = ProgPoint::after(inst);
|
||||||
|
let mut dst_lr = vreg_ranges[dst.vreg()];
|
||||||
|
// If there was no liverange (dead def), create a trivial one.
|
||||||
|
if dst_lr.is_invalid() {
|
||||||
|
dst_lr = self.add_liverange_to_vreg(
|
||||||
|
VRegIndex::new(dst.vreg()),
|
||||||
|
CodeRange {
|
||||||
|
from: pos,
|
||||||
|
to: pos.next(),
|
||||||
|
},
|
||||||
|
&mut num_ranges,
|
||||||
|
);
|
||||||
|
log::debug!(" -> invalid; created {:?}", dst_lr);
|
||||||
|
} else {
|
||||||
|
log::debug!(" -> has existing LR {:?}", dst_lr);
|
||||||
|
}
|
||||||
|
if self.ranges[dst_lr.index()].range.from
|
||||||
|
== self.cfginfo.block_entry[block.index()]
|
||||||
|
{
|
||||||
|
log::debug!(" -> started at block start; trimming to {:?}", pos);
|
||||||
|
self.ranges[dst_lr.index()].range.from = pos;
|
||||||
|
}
|
||||||
|
live.set(dst.vreg(), false);
|
||||||
|
vreg_ranges[dst.vreg()] = LiveRangeIndex::invalid();
|
||||||
|
self.vregs[dst.vreg()].reg = dst;
|
||||||
|
|
||||||
|
// Handle the use w.r.t. liveranges: make it live
|
||||||
|
// and create an initial LR back to the start of
|
||||||
|
// the block.
|
||||||
|
let pos = ProgPoint::before(inst);
|
||||||
|
let range = CodeRange {
|
||||||
|
from: self.cfginfo.block_entry[block.index()],
|
||||||
|
to: pos.next(),
|
||||||
|
};
|
||||||
|
let src_lr = self.add_liverange_to_vreg(
|
||||||
|
VRegIndex::new(src.vreg()),
|
||||||
|
range,
|
||||||
|
&mut num_ranges,
|
||||||
|
);
|
||||||
|
let src_is_dead_after_move = !vreg_ranges[src.vreg()].is_valid();
|
||||||
|
vreg_ranges[src.vreg()] = src_lr;
|
||||||
|
|
||||||
|
log::debug!(" -> src LR {:?}", src_lr);
|
||||||
|
|
||||||
|
// Add to live-set.
|
||||||
|
live.set(src.vreg(), true);
|
||||||
|
|
||||||
|
// Add to program-moves lists.
|
||||||
|
self.prog_move_srcs
|
||||||
|
.push(((VRegIndex::new(src.vreg()), inst), Allocation::none()));
|
||||||
|
self.prog_move_dsts
|
||||||
|
.push(((VRegIndex::new(dst.vreg()), inst), Allocation::none()));
|
||||||
|
if src_is_dead_after_move {
|
||||||
|
self.prog_move_merges.push((src_lr, dst_lr));
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Process defs and uses.
|
// Process defs and uses.
|
||||||
for i in 0..self.func.inst_operands(inst).len() {
|
for i in 0..self.func.inst_operands(inst).len() {
|
||||||
// don't borrow `self`
|
// don't borrow `self`
|
||||||
@@ -1166,7 +1239,6 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
}
|
}
|
||||||
self.insert_use_into_liverange_and_update_stats(lr, u);
|
self.insert_use_into_liverange_and_update_stats(lr, u);
|
||||||
// Remove from live-set.
|
// Remove from live-set.
|
||||||
// TODO-cranelift: here is where we keep it live if it's a mod, not def.
|
|
||||||
live.set(operand.vreg().vreg(), false);
|
live.set(operand.vreg().vreg(), false);
|
||||||
vreg_ranges[operand.vreg().vreg()] = LiveRangeIndex::invalid();
|
vreg_ranges[operand.vreg().vreg()] = LiveRangeIndex::invalid();
|
||||||
}
|
}
|
||||||
@@ -1507,6 +1579,11 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
self.clobbers.sort();
|
self.clobbers.sort();
|
||||||
self.blockparam_ins.sort();
|
self.blockparam_ins.sort();
|
||||||
self.blockparam_outs.sort();
|
self.blockparam_outs.sort();
|
||||||
|
self.prog_move_srcs.sort_unstable_by_key(|(pos, _)| *pos);
|
||||||
|
self.prog_move_dsts.sort_unstable_by_key(|(pos, _)| *pos);
|
||||||
|
|
||||||
|
log::debug!("prog_move_srcs = {:?}", self.prog_move_srcs);
|
||||||
|
log::debug!("prog_move_dsts = {:?}", self.prog_move_dsts);
|
||||||
|
|
||||||
self.stats.initial_liverange_count = self.ranges.len();
|
self.stats.initial_liverange_count = self.ranges.len();
|
||||||
self.stats.blockparam_ins_count = self.blockparam_ins.len();
|
self.stats.blockparam_ins_count = self.blockparam_ins.len();
|
||||||
@@ -1578,6 +1655,20 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sanity check: both bundles should contain only ranges with appropriate VReg classes.
|
||||||
|
let mut iter = self.bundles[from.index()].first_range;
|
||||||
|
while iter.is_valid() {
|
||||||
|
let vreg = self.ranges[iter.index()].vreg;
|
||||||
|
assert_eq!(rc, self.vregs[vreg.index()].reg.class());
|
||||||
|
iter = self.ranges[iter.index()].next_in_bundle;
|
||||||
|
}
|
||||||
|
let mut iter = self.bundles[to.index()].first_range;
|
||||||
|
while iter.is_valid() {
|
||||||
|
let vreg = self.ranges[iter.index()].vreg;
|
||||||
|
assert_eq!(rc, self.vregs[vreg.index()].reg.class());
|
||||||
|
iter = self.ranges[iter.index()].next_in_bundle;
|
||||||
|
}
|
||||||
|
|
||||||
// Check for overlap in LiveRanges.
|
// Check for overlap in LiveRanges.
|
||||||
let mut iter0 = self.bundles[from.index()].first_range;
|
let mut iter0 = self.bundles[from.index()].first_range;
|
||||||
let mut iter1 = self.bundles[to.index()].first_range;
|
let mut iter1 = self.bundles[to.index()].first_range;
|
||||||
@@ -1730,19 +1821,8 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
for inst in 0..self.func.insts() {
|
for inst in 0..self.func.insts() {
|
||||||
let inst = Inst::new(inst);
|
let inst = Inst::new(inst);
|
||||||
|
|
||||||
// Attempt to merge move srcs and dests, and attempt to
|
// Attempt to merge Reuse-policy operand outputs with the
|
||||||
// merge Reuse-policy operand outputs with the
|
|
||||||
// corresponding inputs.
|
// corresponding inputs.
|
||||||
if let Some((src_vreg, dst_vreg)) = self.func.is_move(inst) {
|
|
||||||
log::debug!("trying to merge move src {} to dst {}", src_vreg, dst_vreg);
|
|
||||||
let src_bundle =
|
|
||||||
self.ranges[self.vregs[src_vreg.vreg()].first_range.index()].bundle;
|
|
||||||
assert!(src_bundle.is_valid());
|
|
||||||
let dest_bundle =
|
|
||||||
self.ranges[self.vregs[dst_vreg.vreg()].first_range.index()].bundle;
|
|
||||||
assert!(dest_bundle.is_valid());
|
|
||||||
self.merge_bundles(/* from */ dest_bundle, /* to */ src_bundle);
|
|
||||||
}
|
|
||||||
for op in self.func.inst_operands(inst) {
|
for op in self.func.inst_operands(inst) {
|
||||||
if let OperandPolicy::Reuse(reuse_idx) = op.policy() {
|
if let OperandPolicy::Reuse(reuse_idx) = op.policy() {
|
||||||
let src_vreg = op.vreg();
|
let src_vreg = op.vreg();
|
||||||
@@ -1783,9 +1863,36 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
self.merge_bundles(from_bundle, to_bundle);
|
self.merge_bundles(from_bundle, to_bundle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Attempt to merge move srcs/dsts.
|
||||||
|
for i in 0..self.prog_move_merges.len() {
|
||||||
|
let (src, dst) = self.prog_move_merges[i];
|
||||||
|
log::debug!("trying to merge move src LR {:?} to dst LR {:?}", src, dst);
|
||||||
|
let src = self.resolve_merged_lr(src);
|
||||||
|
let dst = self.resolve_merged_lr(dst);
|
||||||
|
log::debug!(
|
||||||
|
"resolved LR-construction merging chains: move-merge is now src LR {:?} to dst LR {:?}",
|
||||||
|
src,
|
||||||
|
dst
|
||||||
|
);
|
||||||
|
let src_bundle = self.ranges[src.index()].bundle;
|
||||||
|
assert!(src_bundle.is_valid());
|
||||||
|
let dest_bundle = self.ranges[dst.index()].bundle;
|
||||||
|
assert!(dest_bundle.is_valid());
|
||||||
|
self.merge_bundles(/* from */ dest_bundle, /* to */ src_bundle);
|
||||||
|
}
|
||||||
|
|
||||||
log::debug!("done merging bundles");
|
log::debug!("done merging bundles");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn resolve_merged_lr(&self, mut lr: LiveRangeIndex) -> LiveRangeIndex {
|
||||||
|
let mut iter = 0;
|
||||||
|
while iter < 100 && self.ranges[lr.index()].merged_into.is_valid() {
|
||||||
|
lr = self.ranges[lr.index()].merged_into;
|
||||||
|
iter += 1;
|
||||||
|
}
|
||||||
|
lr
|
||||||
|
}
|
||||||
|
|
||||||
fn compute_bundle_prio(&self, bundle: LiveBundleIndex) -> u32 {
|
fn compute_bundle_prio(&self, bundle: LiveBundleIndex) -> u32 {
|
||||||
// The priority is simply the total "length" -- the number of
|
// The priority is simply the total "length" -- the number of
|
||||||
// instructions covered by all LiveRanges.
|
// instructions covered by all LiveRanges.
|
||||||
@@ -1901,14 +2008,19 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn compute_requirement(&self, bundle: LiveBundleIndex) -> Option<Requirement> {
|
fn compute_requirement(&self, bundle: LiveBundleIndex) -> Option<Requirement> {
|
||||||
let class = self.vregs[self.ranges[self.bundles[bundle.index()].first_range.index()]
|
let init_vreg = self.vregs[self.ranges[self.bundles[bundle.index()].first_range.index()]
|
||||||
.vreg
|
.vreg
|
||||||
.index()]
|
.index()]
|
||||||
.reg
|
.reg;
|
||||||
.class();
|
let class = init_vreg.class();
|
||||||
let mut needed = Requirement::Any(class);
|
let mut needed = Requirement::Any(class);
|
||||||
|
|
||||||
log::debug!("compute_requirement: bundle {:?} class {:?}", bundle, class);
|
log::debug!(
|
||||||
|
"compute_requirement: bundle {:?} class {:?} (from vreg {:?})",
|
||||||
|
bundle,
|
||||||
|
class,
|
||||||
|
init_vreg
|
||||||
|
);
|
||||||
|
|
||||||
let mut iter = self.bundles[bundle.index()].first_range;
|
let mut iter = self.bundles[bundle.index()].first_range;
|
||||||
while iter.is_valid() {
|
while iter.is_valid() {
|
||||||
@@ -2669,6 +2781,7 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
let mut first_conflicting_bundle;
|
let mut first_conflicting_bundle;
|
||||||
loop {
|
loop {
|
||||||
attempts += 1;
|
attempts += 1;
|
||||||
|
log::debug!("attempt {}, req {:?}", attempts, req);
|
||||||
debug_assert!(attempts < 100 * self.func.insts());
|
debug_assert!(attempts < 100 * self.func.insts());
|
||||||
first_conflicting_bundle = None;
|
first_conflicting_bundle = None;
|
||||||
let req = match req {
|
let req = match req {
|
||||||
@@ -2682,6 +2795,7 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
Requirement::Fixed(preg) => {
|
Requirement::Fixed(preg) => {
|
||||||
let preg_idx = PRegIndex::new(preg.index());
|
let preg_idx = PRegIndex::new(preg.index());
|
||||||
self.stats.process_bundle_reg_probes_fixed += 1;
|
self.stats.process_bundle_reg_probes_fixed += 1;
|
||||||
|
log::debug!("trying fixed reg {:?}", preg_idx);
|
||||||
match self.try_to_allocate_bundle_to_reg(bundle, preg_idx) {
|
match self.try_to_allocate_bundle_to_reg(bundle, preg_idx) {
|
||||||
AllocRegResult::Allocated(alloc) => {
|
AllocRegResult::Allocated(alloc) => {
|
||||||
self.stats.process_bundle_reg_success_fixed += 1;
|
self.stats.process_bundle_reg_success_fixed += 1;
|
||||||
@@ -2690,8 +2804,12 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
.reg_hint = Some(alloc.as_reg().unwrap());
|
.reg_hint = Some(alloc.as_reg().unwrap());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
AllocRegResult::Conflict(bundles) => bundles,
|
AllocRegResult::Conflict(bundles) => {
|
||||||
|
log::debug!(" -> conflict with bundles {:?}", bundles);
|
||||||
|
bundles
|
||||||
|
}
|
||||||
AllocRegResult::ConflictWithFixed => {
|
AllocRegResult::ConflictWithFixed => {
|
||||||
|
log::debug!(" -> conflict with fixed alloc");
|
||||||
// Empty conflicts set: there's nothing we can
|
// Empty conflicts set: there's nothing we can
|
||||||
// evict, because fixed conflicts cannot be moved.
|
// evict, because fixed conflicts cannot be moved.
|
||||||
smallvec![]
|
smallvec![]
|
||||||
@@ -2721,10 +2839,12 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
// each reg in preference order.
|
// each reg in preference order.
|
||||||
let bounding_range = self.bundle_bounding_range_if_multiple(bundle);
|
let bounding_range = self.bundle_bounding_range_if_multiple(bundle);
|
||||||
if let Some(bounding_range) = bounding_range {
|
if let Some(bounding_range) = bounding_range {
|
||||||
|
log::debug!("initial scan with bounding range {:?}", bounding_range);
|
||||||
for preg in
|
for preg in
|
||||||
RegTraversalIter::new(self.env, class, hint_reg, hint2_reg, scan_offset)
|
RegTraversalIter::new(self.env, class, hint_reg, hint2_reg, scan_offset)
|
||||||
{
|
{
|
||||||
let preg_idx = PRegIndex::new(preg.index());
|
let preg_idx = PRegIndex::new(preg.index());
|
||||||
|
log::debug!("trying preg {:?}", preg_idx);
|
||||||
self.stats.process_bundle_bounding_range_probes_any += 1;
|
self.stats.process_bundle_bounding_range_probes_any += 1;
|
||||||
if self.range_definitely_fits_in_reg(bounding_range, preg_idx) {
|
if self.range_definitely_fits_in_reg(bounding_range, preg_idx) {
|
||||||
let result = self.try_to_allocate_bundle_to_reg(bundle, preg_idx);
|
let result = self.try_to_allocate_bundle_to_reg(bundle, preg_idx);
|
||||||
@@ -2735,6 +2855,7 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
};
|
};
|
||||||
self.spillsets[self.bundles[bundle.index()].spillset.index()]
|
self.spillsets[self.bundles[bundle.index()].spillset.index()]
|
||||||
.reg_hint = Some(alloc.as_reg().unwrap());
|
.reg_hint = Some(alloc.as_reg().unwrap());
|
||||||
|
log::debug!(" -> definitely fits; assigning");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2745,6 +2866,7 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
{
|
{
|
||||||
self.stats.process_bundle_reg_probes_any += 1;
|
self.stats.process_bundle_reg_probes_any += 1;
|
||||||
let preg_idx = PRegIndex::new(preg.index());
|
let preg_idx = PRegIndex::new(preg.index());
|
||||||
|
log::debug!("trying preg {:?}", preg_idx);
|
||||||
match self.try_to_allocate_bundle_to_reg(bundle, preg_idx) {
|
match self.try_to_allocate_bundle_to_reg(bundle, preg_idx) {
|
||||||
AllocRegResult::Allocated(alloc) => {
|
AllocRegResult::Allocated(alloc) => {
|
||||||
self.stats.process_bundle_reg_success_any += 1;
|
self.stats.process_bundle_reg_success_any += 1;
|
||||||
@@ -2754,6 +2876,7 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
AllocRegResult::Conflict(bundles) => {
|
AllocRegResult::Conflict(bundles) => {
|
||||||
|
log::debug!(" -> conflict with bundles {:?}", bundles);
|
||||||
if lowest_cost_conflict_set.is_none() {
|
if lowest_cost_conflict_set.is_none() {
|
||||||
lowest_cost_conflict_set = Some(bundles);
|
lowest_cost_conflict_set = Some(bundles);
|
||||||
} else if self.maximum_spill_weight_in_bundle_set(&bundles)
|
} else if self.maximum_spill_weight_in_bundle_set(&bundles)
|
||||||
@@ -2765,6 +2888,7 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
AllocRegResult::ConflictWithFixed => {
|
AllocRegResult::ConflictWithFixed => {
|
||||||
|
log::debug!(" -> conflict with fixed alloc");
|
||||||
// Simply don't consider as an option.
|
// Simply don't consider as an option.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3154,12 +3278,15 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
|
|
||||||
let mut blockparam_in_idx = 0;
|
let mut blockparam_in_idx = 0;
|
||||||
let mut blockparam_out_idx = 0;
|
let mut blockparam_out_idx = 0;
|
||||||
|
let mut prog_move_src_idx = 0;
|
||||||
|
let mut prog_move_dst_idx = 0;
|
||||||
for vreg in 0..self.vregs.len() {
|
for vreg in 0..self.vregs.len() {
|
||||||
let vreg = VRegIndex::new(vreg);
|
let vreg = VRegIndex::new(vreg);
|
||||||
|
|
||||||
// For each range in each vreg, insert moves or
|
// For each range in each vreg, insert moves or
|
||||||
// half-moves. We also scan over `blockparam_ins` and
|
// half-moves. We also scan over `blockparam_ins` and
|
||||||
// `blockparam_outs`, which are sorted by (block, vreg).
|
// `blockparam_outs`, which are sorted by (block, vreg),
|
||||||
|
// and over program-move srcs/dsts to fill in allocations.
|
||||||
let mut iter = self.vregs[vreg.index()].first_range;
|
let mut iter = self.vregs[vreg.index()].first_range;
|
||||||
let mut prev = LiveRangeIndex::invalid();
|
let mut prev = LiveRangeIndex::invalid();
|
||||||
while iter.is_valid() {
|
while iter.is_valid() {
|
||||||
@@ -3445,6 +3572,71 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
use_iter = self.uses[use_iter.index()].next_use;
|
use_iter = self.uses[use_iter.index()].next_use;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Scan over program move srcs/dsts to fill in allocations.
|
||||||
|
let move_src_start = if range.from.pos == InstPosition::Before {
|
||||||
|
(vreg, range.from.inst)
|
||||||
|
} else {
|
||||||
|
(vreg, range.from.inst.next())
|
||||||
|
};
|
||||||
|
let move_src_end = if range.to.pos == InstPosition::Before {
|
||||||
|
(vreg, range.to.inst)
|
||||||
|
} else {
|
||||||
|
(vreg, range.to.inst.next())
|
||||||
|
};
|
||||||
|
log::debug!(
|
||||||
|
"vreg {:?} range {:?}: looking for program-move sources from {:?} to {:?}",
|
||||||
|
vreg,
|
||||||
|
range,
|
||||||
|
move_src_start,
|
||||||
|
move_src_end
|
||||||
|
);
|
||||||
|
while prog_move_src_idx < self.prog_move_srcs.len()
|
||||||
|
&& self.prog_move_srcs[prog_move_src_idx].0 < move_src_start
|
||||||
|
{
|
||||||
|
log::debug!(" -> skipping idx {}", prog_move_src_idx);
|
||||||
|
prog_move_src_idx += 1;
|
||||||
|
}
|
||||||
|
while prog_move_src_idx < self.prog_move_srcs.len()
|
||||||
|
&& self.prog_move_srcs[prog_move_src_idx].0 < move_src_end
|
||||||
|
{
|
||||||
|
log::debug!(
|
||||||
|
" -> setting idx {} ({:?}) to alloc {:?}",
|
||||||
|
prog_move_src_idx,
|
||||||
|
self.prog_move_srcs[prog_move_src_idx].0,
|
||||||
|
alloc
|
||||||
|
);
|
||||||
|
self.prog_move_srcs[prog_move_src_idx].1 = alloc;
|
||||||
|
prog_move_src_idx += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let move_dst_start = (vreg, range.from.inst);
|
||||||
|
let move_dst_end = (vreg, range.to.inst);
|
||||||
|
log::debug!(
|
||||||
|
"vreg {:?} range {:?}: looking for program-move dests from {:?} to {:?}",
|
||||||
|
vreg,
|
||||||
|
range,
|
||||||
|
move_dst_start,
|
||||||
|
move_dst_end
|
||||||
|
);
|
||||||
|
while prog_move_dst_idx < self.prog_move_dsts.len()
|
||||||
|
&& self.prog_move_dsts[prog_move_dst_idx].0 < move_dst_start
|
||||||
|
{
|
||||||
|
log::debug!(" -> skipping idx {}", prog_move_dst_idx);
|
||||||
|
prog_move_dst_idx += 1;
|
||||||
|
}
|
||||||
|
while prog_move_dst_idx < self.prog_move_dsts.len()
|
||||||
|
&& self.prog_move_dsts[prog_move_dst_idx].0 < move_dst_end
|
||||||
|
{
|
||||||
|
log::debug!(
|
||||||
|
" -> setting idx {} ({:?}) to alloc {:?}",
|
||||||
|
prog_move_dst_idx,
|
||||||
|
self.prog_move_dsts[prog_move_dst_idx].0,
|
||||||
|
alloc
|
||||||
|
);
|
||||||
|
self.prog_move_dsts[prog_move_dst_idx].1 = alloc;
|
||||||
|
prog_move_dst_idx += 1;
|
||||||
|
}
|
||||||
|
|
||||||
prev = iter;
|
prev = iter;
|
||||||
iter = self.ranges[iter.index()].next_in_reg;
|
iter = self.ranges[iter.index()].next_in_reg;
|
||||||
}
|
}
|
||||||
@@ -3646,6 +3838,35 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sort the prog-moves lists and insert moves to reify the
|
||||||
|
// input program's move operations.
|
||||||
|
self.prog_move_srcs
|
||||||
|
.sort_unstable_by_key(|((_, inst), _)| *inst);
|
||||||
|
self.prog_move_dsts
|
||||||
|
.sort_unstable_by_key(|((_, inst), _)| *inst);
|
||||||
|
let prog_move_srcs = std::mem::replace(&mut self.prog_move_srcs, vec![]);
|
||||||
|
let prog_move_dsts = std::mem::replace(&mut self.prog_move_dsts, vec![]);
|
||||||
|
assert_eq!(prog_move_srcs.len(), prog_move_dsts.len());
|
||||||
|
for (&((_, from_inst), from_alloc), &((_, to_inst), to_alloc)) in
|
||||||
|
prog_move_srcs.iter().zip(prog_move_dsts.iter())
|
||||||
|
{
|
||||||
|
assert!(!from_alloc.is_none());
|
||||||
|
assert!(!to_alloc.is_none());
|
||||||
|
assert_eq!(from_inst, to_inst);
|
||||||
|
log::debug!(
|
||||||
|
"program move at inst {:?}: alloc {:?} -> {:?}",
|
||||||
|
from_inst,
|
||||||
|
from_alloc,
|
||||||
|
to_alloc
|
||||||
|
);
|
||||||
|
self.insert_move(
|
||||||
|
ProgPoint::before(from_inst),
|
||||||
|
InsertMovePrio::ProgramMove,
|
||||||
|
from_alloc,
|
||||||
|
to_alloc,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_inserted_moves(&mut self) {
|
fn resolve_inserted_moves(&mut self) {
|
||||||
|
|||||||
Reference in New Issue
Block a user