Parameterize adaptive-map size in BitVec.
This commit is contained in:
@@ -7,10 +7,12 @@
|
|||||||
|
|
||||||
use fxhash::FxHashMap;
|
use fxhash::FxHashMap;
|
||||||
|
|
||||||
|
const SMALL_ELEMS: usize = 12;
|
||||||
|
|
||||||
/// A hybrid large/small-mode sparse mapping from integer indices to elements.
|
/// A hybrid large/small-mode sparse mapping from integer indices to elements.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
enum AdaptiveMap {
|
enum AdaptiveMap {
|
||||||
Small(u32, [u32; 4], [u64; 4]),
|
Small(u32, [u32; SMALL_ELEMS], [u64; SMALL_ELEMS]),
|
||||||
Large(FxHashMap<u32, u64>),
|
Large(FxHashMap<u32, u64>),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -18,7 +20,7 @@ const INVALID: u32 = 0xffff_ffff;
|
|||||||
|
|
||||||
impl AdaptiveMap {
|
impl AdaptiveMap {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
Self::Small(0, [INVALID, INVALID, INVALID, INVALID], [0, 0, 0, 0])
|
Self::Small(0, [INVALID; SMALL_ELEMS], [0; SMALL_ELEMS])
|
||||||
}
|
}
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
fn expand(&mut self) {
|
fn expand(&mut self) {
|
||||||
@@ -36,7 +38,9 @@ impl AdaptiveMap {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn get_or_insert<'a>(&'a mut self, key: u32) -> &'a mut u64 {
|
fn get_or_insert<'a>(&'a mut self, key: u32) -> &'a mut u64 {
|
||||||
let needs_expand = match self {
|
let needs_expand = match self {
|
||||||
&mut Self::Small(len, ref keys, ..) => len == 4 && !keys.iter().any(|k| *k == key),
|
&mut Self::Small(len, ref keys, ..) => {
|
||||||
|
len == SMALL_ELEMS as u32 && !keys.iter().any(|k| *k == key)
|
||||||
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
if needs_expand {
|
if needs_expand {
|
||||||
@@ -50,7 +54,7 @@ impl AdaptiveMap {
|
|||||||
return &mut values[i as usize];
|
return &mut values[i as usize];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert!(*len < 4);
|
assert!(*len < SMALL_ELEMS as u32);
|
||||||
let idx = *len;
|
let idx = *len;
|
||||||
*len += 1;
|
*len += 1;
|
||||||
keys[idx as usize] = key;
|
keys[idx as usize] = key;
|
||||||
|
|||||||
@@ -101,7 +101,6 @@ define_index!(LiveBundleIndex);
|
|||||||
define_index!(LiveRangeIndex);
|
define_index!(LiveRangeIndex);
|
||||||
define_index!(SpillSetIndex);
|
define_index!(SpillSetIndex);
|
||||||
define_index!(UseIndex);
|
define_index!(UseIndex);
|
||||||
define_index!(DefIndex);
|
|
||||||
define_index!(VRegIndex);
|
define_index!(VRegIndex);
|
||||||
define_index!(PRegIndex);
|
define_index!(PRegIndex);
|
||||||
define_index!(SpillSlotIndex);
|
define_index!(SpillSlotIndex);
|
||||||
@@ -174,7 +173,6 @@ struct Use {
|
|||||||
pos: ProgPoint,
|
pos: ProgPoint,
|
||||||
next_use: UseIndex,
|
next_use: UseIndex,
|
||||||
slot: u8,
|
slot: u8,
|
||||||
is_def: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const SLOT_NONE: u8 = u8::MAX;
|
const SLOT_NONE: u8 = u8::MAX;
|
||||||
@@ -224,8 +222,6 @@ struct SpillSet {
|
|||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
struct VRegData {
|
struct VRegData {
|
||||||
reg: VReg,
|
|
||||||
def: DefIndex,
|
|
||||||
blockparam: Block,
|
blockparam: Block,
|
||||||
first_range: LiveRangeIndex,
|
first_range: LiveRangeIndex,
|
||||||
is_ref: bool,
|
is_ref: bool,
|
||||||
@@ -291,6 +287,7 @@ struct Env<'a, F: Function> {
|
|||||||
spillsets: Vec<SpillSet>,
|
spillsets: Vec<SpillSet>,
|
||||||
uses: Vec<Use>,
|
uses: Vec<Use>,
|
||||||
vregs: Vec<VRegData>,
|
vregs: Vec<VRegData>,
|
||||||
|
vreg_regs: Vec<VReg>,
|
||||||
pregs: Vec<PRegData>,
|
pregs: Vec<PRegData>,
|
||||||
allocation_queue: PrioQueue,
|
allocation_queue: PrioQueue,
|
||||||
hot_code: LiveRangeSet,
|
hot_code: LiveRangeSet,
|
||||||
@@ -454,6 +451,7 @@ impl LiveRangeSet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
fn spill_weight_from_policy(policy: OperandPolicy) -> u32 {
|
fn spill_weight_from_policy(policy: OperandPolicy) -> u32 {
|
||||||
match policy {
|
match policy {
|
||||||
OperandPolicy::Any => 1000,
|
OperandPolicy::Any => 1000,
|
||||||
@@ -673,6 +671,7 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
spillsets: vec![],
|
spillsets: vec![],
|
||||||
uses: vec![],
|
uses: vec![],
|
||||||
vregs: vec![],
|
vregs: vec![],
|
||||||
|
vreg_regs: vec![],
|
||||||
pregs: vec![],
|
pregs: vec![],
|
||||||
allocation_queue: PrioQueue::new(),
|
allocation_queue: PrioQueue::new(),
|
||||||
clobbers: vec![],
|
clobbers: vec![],
|
||||||
@@ -716,13 +715,14 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
for idx in 0..self.func.num_vregs() {
|
for idx in 0..self.func.num_vregs() {
|
||||||
// We'll fill in the real details when we see the def.
|
// We'll fill in the real details when we see the def.
|
||||||
let reg = VReg::new(idx, RegClass::Int);
|
let reg = VReg::new(idx, RegClass::Int);
|
||||||
self.add_vreg(VRegData {
|
self.add_vreg(
|
||||||
reg,
|
reg,
|
||||||
def: DefIndex::invalid(),
|
VRegData {
|
||||||
first_range: LiveRangeIndex::invalid(),
|
first_range: LiveRangeIndex::invalid(),
|
||||||
blockparam: Block::invalid(),
|
blockparam: Block::invalid(),
|
||||||
is_ref: false,
|
is_ref: false,
|
||||||
});
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
for v in self.func.reftype_vregs() {
|
for v in self.func.reftype_vregs() {
|
||||||
self.vregs[v.vreg()].is_ref = true;
|
self.vregs[v.vreg()].is_ref = true;
|
||||||
@@ -737,9 +737,10 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_vreg(&mut self, data: VRegData) -> VRegIndex {
|
fn add_vreg(&mut self, reg: VReg, data: VRegData) -> VRegIndex {
|
||||||
let idx = self.vregs.len();
|
let idx = self.vregs.len();
|
||||||
self.vregs.push(data);
|
self.vregs.push(data);
|
||||||
|
self.vreg_regs.push(reg);
|
||||||
VRegIndex::new(idx)
|
VRegIndex::new(idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -929,7 +930,7 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
lrdata.uses_spill_weight -= spill_weight_from_policy(usedata.operand.policy());
|
lrdata.uses_spill_weight -= spill_weight_from_policy(usedata.operand.policy());
|
||||||
if usedata.is_def {
|
if usedata.operand.kind() == OperandKind::Def {
|
||||||
lrdata.uses_spill_weight -= 2000;
|
lrdata.uses_spill_weight -= 2000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -981,7 +982,7 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
spill_weight_from_policy(policy)
|
spill_weight_from_policy(policy)
|
||||||
);
|
);
|
||||||
self.ranges[into.index()].uses_spill_weight += spill_weight_from_policy(policy);
|
self.ranges[into.index()].uses_spill_weight += spill_weight_from_policy(policy);
|
||||||
if self.uses[u.index()].is_def {
|
if self.uses[u.index()].operand.kind() == OperandKind::Def {
|
||||||
self.ranges[into.index()].uses_spill_weight += 2000;
|
self.ranges[into.index()].uses_spill_weight += 2000;
|
||||||
}
|
}
|
||||||
log::debug!(" -> now {}", self.ranges[into.index()].uses_spill_weight);
|
log::debug!(" -> now {}", self.ranges[into.index()].uses_spill_weight);
|
||||||
@@ -1071,7 +1072,7 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
|
|
||||||
// Create vreg data for blockparams.
|
// Create vreg data for blockparams.
|
||||||
for param in self.func.block_params(block) {
|
for param in self.func.block_params(block) {
|
||||||
self.vregs[param.vreg()].reg = *param;
|
self.vreg_regs[param.vreg()] = *param;
|
||||||
self.vregs[param.vreg()].blockparam = block;
|
self.vregs[param.vreg()].blockparam = block;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1161,7 +1162,7 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
}
|
}
|
||||||
live.set(dst.vreg(), false);
|
live.set(dst.vreg(), false);
|
||||||
vreg_ranges[dst.vreg()] = LiveRangeIndex::invalid();
|
vreg_ranges[dst.vreg()] = LiveRangeIndex::invalid();
|
||||||
self.vregs[dst.vreg()].reg = dst;
|
self.vreg_regs[dst.vreg()] = dst;
|
||||||
|
|
||||||
// Handle the use w.r.t. liveranges: make it live
|
// Handle the use w.r.t. liveranges: make it live
|
||||||
// and create an initial LR back to the start of
|
// and create an initial LR back to the start of
|
||||||
@@ -1213,13 +1214,12 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
pos,
|
pos,
|
||||||
slot: i as u8,
|
slot: i as u8,
|
||||||
next_use: UseIndex::invalid(),
|
next_use: UseIndex::invalid(),
|
||||||
is_def: true,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
log::debug!("Def of {} at {:?}", operand.vreg(), pos);
|
log::debug!("Def of {} at {:?}", operand.vreg(), pos);
|
||||||
|
|
||||||
// Fill in vreg's actual data.
|
// Fill in vreg's actual data.
|
||||||
self.vregs[operand.vreg().vreg()].reg = operand.vreg();
|
self.vreg_regs[operand.vreg().vreg()] = operand.vreg();
|
||||||
|
|
||||||
// Trim the range for this vreg to start
|
// Trim the range for this vreg to start
|
||||||
// at `pos` if it previously ended at the
|
// at `pos` if it previously ended at the
|
||||||
@@ -1280,7 +1280,6 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
pos,
|
pos,
|
||||||
slot: i as u8,
|
slot: i as u8,
|
||||||
next_use: UseIndex::invalid(),
|
next_use: UseIndex::invalid(),
|
||||||
is_def: false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create/extend the LiveRange and add the use to the range.
|
// Create/extend the LiveRange and add the use to the range.
|
||||||
@@ -1443,7 +1442,7 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
// Create a virtual use.
|
// Create a virtual use.
|
||||||
let pos = ProgPoint::before(self.safepoints[safepoint_idx]);
|
let pos = ProgPoint::before(self.safepoints[safepoint_idx]);
|
||||||
let operand = Operand::new(
|
let operand = Operand::new(
|
||||||
self.vregs[vreg.index()].reg,
|
self.vreg_regs[vreg.index()],
|
||||||
OperandPolicy::Stack,
|
OperandPolicy::Stack,
|
||||||
OperandKind::Use,
|
OperandKind::Use,
|
||||||
OperandPos::Before,
|
OperandPos::Before,
|
||||||
@@ -1456,7 +1455,6 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
pos,
|
pos,
|
||||||
slot: SLOT_NONE,
|
slot: SLOT_NONE,
|
||||||
next_use: UseIndex::invalid(),
|
next_use: UseIndex::invalid(),
|
||||||
is_def: false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create/extend the LiveRange and add the use to the range.
|
// Create/extend the LiveRange and add the use to the range.
|
||||||
@@ -1659,8 +1657,8 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
// have to have the same regclass (because bundles start with one vreg
|
// have to have the same regclass (because bundles start with one vreg
|
||||||
// and all merging happens here) so we can just sample the first vreg of
|
// and all merging happens here) so we can just sample the first vreg of
|
||||||
// each bundle.
|
// each bundle.
|
||||||
let rc = self.vregs[vreg_from.index()].reg.class();
|
let rc = self.vreg_regs[vreg_from.index()].class();
|
||||||
if rc != self.vregs[vreg_to.index()].reg.class() {
|
if rc != self.vreg_regs[vreg_to.index()].class() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1927,7 +1925,7 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
// First time seeing `bundle`: allocate a spillslot for it,
|
// First time seeing `bundle`: allocate a spillslot for it,
|
||||||
// compute its priority, and enqueue it.
|
// compute its priority, and enqueue it.
|
||||||
let ssidx = SpillSetIndex::new(self.spillsets.len());
|
let ssidx = SpillSetIndex::new(self.spillsets.len());
|
||||||
let reg = self.vregs[vreg.index()].reg;
|
let reg = self.vreg_regs[vreg.index()];
|
||||||
let size = self.func.spillslot_size(reg.class(), reg) as u8;
|
let size = self.func.spillslot_size(reg.class(), reg) as u8;
|
||||||
self.spillsets.push(SpillSet {
|
self.spillsets.push(SpillSet {
|
||||||
bundles: smallvec![],
|
bundles: smallvec![],
|
||||||
@@ -2008,22 +2006,21 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
log::debug!("Uses:");
|
log::debug!("Uses:");
|
||||||
for (i, u) in self.uses.iter().enumerate() {
|
for (i, u) in self.uses.iter().enumerate() {
|
||||||
log::debug!(
|
log::debug!(
|
||||||
"use{}: op={:?} pos={:?} slot={} next_use={:?} is_def={:?}",
|
"use{}: op={:?} pos={:?} slot={} next_use={:?}",
|
||||||
i,
|
i,
|
||||||
u.operand,
|
u.operand,
|
||||||
u.pos,
|
u.pos,
|
||||||
u.slot,
|
u.slot,
|
||||||
u.next_use,
|
u.next_use,
|
||||||
u.is_def,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compute_requirement(&self, bundle: LiveBundleIndex) -> Option<Requirement> {
|
fn compute_requirement(&self, bundle: LiveBundleIndex) -> Option<Requirement> {
|
||||||
let init_vreg = self.vregs[self.ranges[self.bundles[bundle.index()].first_range.index()]
|
let init_vreg = self.vreg_regs[self.ranges
|
||||||
|
[self.bundles[bundle.index()].first_range.index()]
|
||||||
.vreg
|
.vreg
|
||||||
.index()]
|
.index()];
|
||||||
.reg;
|
|
||||||
let class = init_vreg.class();
|
let class = init_vreg.class();
|
||||||
let mut needed = Requirement::Any(class);
|
let mut needed = Requirement::Any(class);
|
||||||
|
|
||||||
@@ -2486,7 +2483,7 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
while use_idx.is_valid() {
|
while use_idx.is_valid() {
|
||||||
let use_data = &self.uses[use_idx.index()];
|
let use_data = &self.uses[use_idx.index()];
|
||||||
log::debug!(" -> use: {:?}", use_data);
|
log::debug!(" -> use: {:?}", use_data);
|
||||||
let before_use_inst = if use_data.is_def {
|
let before_use_inst = if use_data.operand.kind() == OperandKind::Def {
|
||||||
// For a def, split *at* the def -- this may be an
|
// For a def, split *at* the def -- this may be an
|
||||||
// After point, but the value cannot be live into
|
// After point, but the value cannot be live into
|
||||||
// the def so we don't need to insert a move.
|
// the def so we don't need to insert a move.
|
||||||
@@ -2986,11 +2983,10 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
fn try_allocating_regs_for_spilled_bundles(&mut self) {
|
fn try_allocating_regs_for_spilled_bundles(&mut self) {
|
||||||
for i in 0..self.spilled_bundles.len() {
|
for i in 0..self.spilled_bundles.len() {
|
||||||
let bundle = self.spilled_bundles[i]; // don't borrow self
|
let bundle = self.spilled_bundles[i]; // don't borrow self
|
||||||
let any_vreg = self.vregs[self.ranges
|
let any_vreg = self.vreg_regs[self.ranges
|
||||||
[self.bundles[bundle.index()].first_range.index()]
|
[self.bundles[bundle.index()].first_range.index()]
|
||||||
.vreg
|
.vreg
|
||||||
.index()]
|
.index()];
|
||||||
.reg;
|
|
||||||
let class = any_vreg.class();
|
let class = any_vreg.class();
|
||||||
let mut success = false;
|
let mut success = false;
|
||||||
self.stats.spill_bundle_reg_probes += 1;
|
self.stats.spill_bundle_reg_probes += 1;
|
||||||
@@ -3365,7 +3361,7 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
let prev_range = self.ranges[prev.index()].range;
|
let prev_range = self.ranges[prev.index()].range;
|
||||||
let first_use = self.ranges[iter.index()].first_use;
|
let first_use = self.ranges[iter.index()].first_use;
|
||||||
let first_is_def = if first_use.is_valid() {
|
let first_is_def = if first_use.is_valid() {
|
||||||
self.uses[first_use.index()].is_def
|
self.uses[first_use.index()].operand.kind() == OperandKind::Def
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
};
|
};
|
||||||
@@ -3945,7 +3941,7 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
let params = &self.blockparam_allocs[start..i];
|
let params = &self.blockparam_allocs[start..i];
|
||||||
let vregs = params
|
let vregs = params
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(_, _, vreg_idx, _)| self.vregs[vreg_idx.index()].reg)
|
.map(|(_, _, vreg_idx, _)| self.vreg_regs[vreg_idx.index()])
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let allocs = params
|
let allocs = params
|
||||||
.iter()
|
.iter()
|
||||||
|
|||||||
Reference in New Issue
Block a user