Make regalloc2 #![no_std] (#119)

* Make regalloc2 `#![no_std]`

This crate doesn't require any features from the standard library, so it
can be made `no_std` to allow it to be used in environments that can't
use the Rust standard library.

This PR mainly performs the following mechanical changes:
- `std::collections` is replaced with `alloc::collections`.
- `std::*` is replaced with `core::*`.
- `Vec`, `vec!`, `format!` and `ToString` are imported when needed since
  they are no longer in the prelude.
- `HashSet` and `HashMap` are taken from the `hashbrown` crate, which is
  the same implementation that the standard library uses.
- `FxHashSet` and `FxHashMap` are typedefs in `lib.rs` that are based on
  the `hashbrown` types.

The only functional change is that `RegAllocError` no longer implements
the `Error` trait since that is not available in `core`.

Dependencies were adjusted to not require `std` and this is tested in CI
by building against the `thumbv6m-none-eabi` target that doesn't have
`std`.

* Add the Error trait impl back under a "std" feature
This commit is contained in:
Amanieu d'Antras
2023-03-09 20:25:59 +01:00
committed by GitHub
parent 7354cfedde
commit 2bd03256b3
23 changed files with 176 additions and 115 deletions

View File

@@ -37,6 +37,16 @@ jobs:
- name: Check with all features
run: cargo check --all-features
# Make sure the code and its dependencies compile without std.
no_std:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install thumbv6m-none-eabi target
run: rustup target add thumbv6m-none-eabi
- name: Check no_std build
run: cargo check --target thumbv6m-none-eabi --no-default-features --features trace-log,checker,enable-serde
# Lint dependency graph for security advisories, duplicate versions, and
# incompatible licences.
cargo_deny:

View File

@@ -13,11 +13,15 @@ repository = "https://github.com/bytecodealliance/regalloc2"
[dependencies]
log = { version = "0.4.8", default-features = false }
smallvec = { version = "1.6.1", features = ["union"] }
fxhash = "0.2.1"
slice-group-by = "0.3.0"
rustc-hash = { version = "1.1.0", default-features = false }
slice-group-by = { version = "0.3.0", default-features = false }
hashbrown = "0.13.2"
# Optional serde support, enabled by feature below.
serde = { version = "1.0.136", features = ["derive"], optional = true }
serde = { version = "1.0.136", features = [
"derive",
"alloc",
], default-features = false, optional = true }
# The below are only needed for fuzzing.
libfuzzer-sys = { version = "0.4.2", optional = true }
@@ -29,7 +33,10 @@ debug-assertions = true
overflow-checks = true
[features]
default = []
default = ["std"]
# Enables std-specific features such as the Error trait for RegAllocError.
std = []
# Enables generation of DefAlloc edits for the checker.
checker = []

View File

@@ -6,6 +6,8 @@
//! Lightweight CFG analyses.
use crate::{domtree, postorder, Block, Function, Inst, ProgPoint, RegAllocError};
use alloc::vec;
use alloc::vec::Vec;
use smallvec::{smallvec, SmallVec};
#[derive(Clone, Debug)]

View File

@@ -96,14 +96,16 @@
#![allow(dead_code)]
use crate::{
Allocation, AllocationKind, Block, Edit, Function, Inst, InstOrEdit, InstPosition, MachineEnv,
Operand, OperandConstraint, OperandKind, OperandPos, Output, PReg, PRegSet, VReg,
Allocation, AllocationKind, Block, Edit, Function, FxHashMap, FxHashSet, Inst, InstOrEdit,
InstPosition, MachineEnv, Operand, OperandConstraint, OperandKind, OperandPos, Output, PReg,
PRegSet, VReg,
};
use fxhash::{FxHashMap, FxHashSet};
use alloc::vec::Vec;
use alloc::{format, vec};
use core::default::Default;
use core::hash::Hash;
use core::result::Result;
use smallvec::{smallvec, SmallVec};
use std::default::Default;
use std::hash::Hash;
use std::result::Result;
/// A set of errors detected by the regalloc checker.
#[derive(Clone, Debug)]
@@ -230,7 +232,7 @@ impl CheckerValue {
}
fn from_reg(reg: VReg) -> CheckerValue {
CheckerValue::VRegs(std::iter::once(reg).collect())
CheckerValue::VRegs(core::iter::once(reg).collect())
}
fn remove_vreg(&mut self, reg: VReg) {
@@ -373,8 +375,8 @@ impl Default for CheckerState {
}
}
impl std::fmt::Display for CheckerValue {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
impl core::fmt::Display for CheckerValue {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
match self {
CheckerValue::Universe => {
write!(f, "top")

View File

@@ -12,6 +12,9 @@
// TR-06-33870
// https://www.cs.rice.edu/~keith/EMBED/dom.pdf
use alloc::vec;
use alloc::vec::Vec;
use crate::Block;
// Helper

View File

@@ -8,6 +8,9 @@ use crate::{
OperandConstraint, OperandKind, OperandPos, PReg, PRegSet, RegClass, VReg,
};
use alloc::vec::Vec;
use alloc::{format, vec};
use super::arbitrary::Result as ArbitraryResult;
use super::arbitrary::{Arbitrary, Unstructured};
@@ -275,7 +278,7 @@ pub struct Options {
pub reftypes: bool,
}
impl std::default::Default for Options {
impl core::default::Default for Options {
fn default() -> Self {
Options {
reused_inputs: false,
@@ -404,7 +407,7 @@ impl Func {
}
vregs_by_block.push(vregs.clone());
vregs_by_block_to_be_defined.push(vec![]);
let mut max_block_params = u.int_in_range(0..=std::cmp::min(3, vregs.len() / 3))?;
let mut max_block_params = u.int_in_range(0..=core::cmp::min(3, vregs.len() / 3))?;
for &vreg in &vregs {
if block > 0 && opts.block_params && bool::arbitrary(u)? && max_block_params > 0 {
block_params[block].push(vreg);
@@ -591,8 +594,8 @@ impl Func {
}
}
impl std::fmt::Debug for Func {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
impl core::fmt::Debug for Func {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{{\n")?;
for vreg in self.reftype_vregs() {
write!(f, " REF: {}\n", vreg)?;
@@ -653,7 +656,7 @@ impl std::fmt::Debug for Func {
}
pub fn machine_env() -> MachineEnv {
fn regs(r: std::ops::Range<usize>) -> Vec<PReg> {
fn regs(r: core::ops::Range<usize>) -> Vec<PReg> {
r.map(|i| PReg::new(i, RegClass::Int)).collect()
}
let preferred_regs_by_class: [Vec<PReg>; 2] = [regs(0..24), vec![]];

View File

@@ -50,11 +50,11 @@ macro_rules! define_index {
};
}
pub trait ContainerIndex: Clone + Copy + std::fmt::Debug + PartialEq + Eq {}
pub trait ContainerIndex: Clone + Copy + core::fmt::Debug + PartialEq + Eq {}
pub trait ContainerComparator {
type Ix: ContainerIndex;
fn compare(&self, a: Self::Ix, b: Self::Ix) -> std::cmp::Ordering;
fn compare(&self, a: Self::Ix, b: Self::Ix) -> core::cmp::Ordering;
}
define_index!(Inst);
@@ -146,6 +146,9 @@ impl Iterator for InstRangeIter {
#[cfg(test)]
mod test {
use alloc::vec;
use alloc::vec::Vec;
use super::*;
#[test]

View File

@@ -5,8 +5,10 @@
//! Index sets: sets of integers that represent indices into a space.
use fxhash::FxHashMap;
use std::cell::Cell;
use alloc::vec::Vec;
use core::cell::Cell;
use crate::FxHashMap;
const SMALL_ELEMS: usize = 12;
@@ -151,10 +153,10 @@ impl AdaptiveMap {
enum AdaptiveMapIter<'a> {
Small(&'a [u32], &'a [u64]),
Large(std::collections::hash_map::Iter<'a, u32, u64>),
Large(hashbrown::hash_map::Iter<'a, u32, u64>),
}
impl<'a> std::iter::Iterator for AdaptiveMapIter<'a> {
impl<'a> core::iter::Iterator for AdaptiveMapIter<'a> {
type Item = (u32, u64);
#[inline]
@@ -292,7 +294,7 @@ impl Iterator for SetBitsIter {
// Build an `Option<NonZeroU64>` so that on the nonzero path,
// the compiler can optimize the trailing-zeroes operator
// using that knowledge.
std::num::NonZeroU64::new(self.0).map(|nz| {
core::num::NonZeroU64::new(self.0).map(|nz| {
let bitidx = nz.trailing_zeros();
self.0 &= self.0 - 1; // clear highest set bit
bitidx as usize
@@ -300,8 +302,8 @@ impl Iterator for SetBitsIter {
}
}
impl std::fmt::Debug for IndexSet {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
impl core::fmt::Debug for IndexSet {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
let vals = self.iter().collect::<Vec<_>>();
write!(f, "{:?}", vals)
}

View File

@@ -17,14 +17,16 @@ use crate::cfg::CFGInfo;
use crate::index::ContainerComparator;
use crate::indexset::IndexSet;
use crate::{
define_index, Allocation, Block, Edit, Function, Inst, MachineEnv, Operand, PReg, ProgPoint,
RegClass, VReg,
define_index, Allocation, Block, Edit, Function, FxHashSet, Inst, MachineEnv, Operand, PReg,
ProgPoint, RegClass, VReg,
};
use fxhash::FxHashSet;
use alloc::collections::BTreeMap;
use alloc::string::String;
use alloc::vec::Vec;
use core::cmp::Ordering;
use core::fmt::Debug;
use hashbrown::{HashMap, HashSet};
use smallvec::SmallVec;
use std::cmp::Ordering;
use std::collections::{BTreeMap, HashMap, HashSet};
use std::fmt::Debug;
/// A range from `from` (inclusive) to `to` (exclusive).
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
@@ -64,13 +66,13 @@ impl CodeRange {
}
}
impl std::cmp::PartialOrd for CodeRange {
impl core::cmp::PartialOrd for CodeRange {
#[inline(always)]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl std::cmp::Ord for CodeRange {
impl core::cmp::Ord for CodeRange {
#[inline(always)]
fn cmp(&self, other: &Self) -> Ordering {
if self.to <= other.from {
@@ -278,7 +280,7 @@ const fn no_bloat_capacity<T>() -> usize {
//
// So if `size_of([T; N]) == size_of(pointer) + size_of(capacity)` then we
// get the maximum inline capacity without bloat.
std::mem::size_of::<usize>() * 2 / std::mem::size_of::<T>()
core::mem::size_of::<usize>() * 2 / core::mem::size_of::<T>()
}
#[derive(Clone, Debug)]
@@ -431,7 +433,7 @@ pub struct Env<'a, F: Function> {
// For debug output only: a list of textual annotations at every
// ProgPoint to insert into the final allocated program listing.
pub debug_annotations: std::collections::HashMap<ProgPoint, Vec<String>>,
pub debug_annotations: hashbrown::HashMap<ProgPoint, Vec<String>>,
pub annotations_enabled: bool,
// Cached allocation for `try_to_allocate_bundle_to_reg` to avoid allocating
@@ -492,7 +494,7 @@ impl SpillSlotList {
#[derive(Clone, Debug)]
pub struct PrioQueue {
pub heap: std::collections::BinaryHeap<PrioQueueEntry>,
pub heap: alloc::collections::BinaryHeap<PrioQueueEntry>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
@@ -531,28 +533,28 @@ impl LiveRangeKey {
}
}
impl std::cmp::PartialEq for LiveRangeKey {
impl core::cmp::PartialEq for LiveRangeKey {
#[inline(always)]
fn eq(&self, other: &Self) -> bool {
self.to > other.from && self.from < other.to
}
}
impl std::cmp::Eq for LiveRangeKey {}
impl std::cmp::PartialOrd for LiveRangeKey {
impl core::cmp::Eq for LiveRangeKey {}
impl core::cmp::PartialOrd for LiveRangeKey {
#[inline(always)]
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl std::cmp::Ord for LiveRangeKey {
impl core::cmp::Ord for LiveRangeKey {
#[inline(always)]
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
if self.to <= other.from {
std::cmp::Ordering::Less
core::cmp::Ordering::Less
} else if self.from >= other.to {
std::cmp::Ordering::Greater
core::cmp::Ordering::Greater
} else {
std::cmp::Ordering::Equal
core::cmp::Ordering::Equal
}
}
}
@@ -562,7 +564,7 @@ pub struct PrioQueueComparator<'a> {
}
impl<'a> ContainerComparator for PrioQueueComparator<'a> {
type Ix = LiveBundleIndex;
fn compare(&self, a: Self::Ix, b: Self::Ix) -> std::cmp::Ordering {
fn compare(&self, a: Self::Ix, b: Self::Ix) -> core::cmp::Ordering {
self.prios[a.index()].cmp(&self.prios[b.index()])
}
}
@@ -570,7 +572,7 @@ impl<'a> ContainerComparator for PrioQueueComparator<'a> {
impl PrioQueue {
pub fn new() -> Self {
PrioQueue {
heap: std::collections::BinaryHeap::new(),
heap: alloc::collections::BinaryHeap::new(),
}
}

View File

@@ -1,5 +1,9 @@
//! Debugging output.
use alloc::string::ToString;
use alloc::{format, vec};
use alloc::{string::String, vec::Vec};
use super::Env;
use crate::{Block, Function, ProgPoint};

View File

@@ -22,13 +22,15 @@ use crate::ion::data_structures::{
BlockparamIn, BlockparamOut, FixedRegFixupLevel, MultiFixedRegFixup,
};
use crate::{
Allocation, Block, Function, Inst, InstPosition, Operand, OperandConstraint, OperandKind,
OperandPos, PReg, ProgPoint, RegAllocError, VReg,
Allocation, Block, Function, FxHashMap, FxHashSet, Inst, InstPosition, Operand,
OperandConstraint, OperandKind, OperandPos, PReg, ProgPoint, RegAllocError, VReg,
};
use fxhash::{FxHashMap, FxHashSet};
use alloc::collections::VecDeque;
use alloc::vec;
use alloc::vec::Vec;
use hashbrown::HashSet;
use slice_group_by::GroupByMut;
use smallvec::{smallvec, SmallVec};
use std::collections::{HashSet, VecDeque};
/// A spill weight computed for a certain Use.
#[derive(Clone, Copy, Debug)]
@@ -42,7 +44,7 @@ pub fn spill_weight_from_constraint(
) -> SpillWeight {
// A bonus of 1000 for one loop level, 4000 for two loop levels,
// 16000 for three loop levels, etc. Avoids exponentiation.
let loop_depth = std::cmp::min(10, loop_depth);
let loop_depth = core::cmp::min(10, loop_depth);
let hot_bonus: f32 = (0..loop_depth).fold(1000.0, |a, _| a * 4.0);
let def_bonus: f32 = if is_def { 2000.0 } else { 0.0 };
let constraint_bonus: f32 = match constraint {
@@ -91,7 +93,7 @@ impl SpillWeight {
}
}
impl std::ops::Add<SpillWeight> for SpillWeight {
impl core::ops::Add<SpillWeight> for SpillWeight {
type Output = SpillWeight;
fn add(self, other: SpillWeight) -> Self {
SpillWeight(self.0 + other.0)

View File

@@ -18,6 +18,7 @@ use super::{
use crate::{
ion::data_structures::BlockparamOut, Function, Inst, OperandConstraint, OperandKind, PReg,
};
use alloc::format;
use smallvec::smallvec;
impl<'a, F: Function> Env<'a, F> {
@@ -132,7 +133,7 @@ impl<'a, F: Function> Env<'a, F> {
// `to` bundle is empty -- just move the list over from
// `from` and set `bundle` up-link on all ranges.
trace!(" -> to bundle{} is empty; trivial merge", to.index());
let list = std::mem::replace(&mut self.bundles[from.index()].ranges, smallvec![]);
let list = core::mem::replace(&mut self.bundles[from.index()].ranges, smallvec![]);
for entry in &list {
self.ranges[entry.index.index()].bundle = to;
@@ -170,7 +171,7 @@ impl<'a, F: Function> Env<'a, F> {
// Two non-empty lists of LiveRanges: concatenate and
// sort. This is faster than a mergesort-like merge into a new
// list, empirically.
let from_list = std::mem::replace(&mut self.bundles[from.index()].ranges, smallvec![]);
let from_list = core::mem::replace(&mut self.bundles[from.index()].ranges, smallvec![]);
for entry in &from_list {
self.ranges[entry.index.index()].bundle = to;
}
@@ -213,7 +214,7 @@ impl<'a, F: Function> Env<'a, F> {
}
if self.bundles[from.index()].spillset != self.bundles[to.index()].spillset {
let from_vregs = std::mem::replace(
let from_vregs = core::mem::replace(
&mut self.spillsets[self.bundles[from.index()].spillset.index()].vregs,
smallvec![],
);

View File

@@ -16,7 +16,9 @@
use crate::cfg::CFGInfo;
use crate::ssa::validate_ssa;
use crate::{Function, MachineEnv, Output, PReg, ProgPoint, RegAllocError, RegClass};
use std::collections::HashMap;
use alloc::vec;
use alloc::vec::Vec;
use hashbrown::HashMap;
pub(crate) mod data_structures;
pub use data_structures::Stats;
@@ -82,7 +84,7 @@ impl<'a, F: Function> Env<'a, F> {
stats: Stats::default(),
debug_annotations: std::collections::HashMap::new(),
debug_annotations: hashbrown::HashMap::new(),
annotations_enabled,
conflict_set: Default::default(),

View File

@@ -22,12 +22,13 @@ use crate::ion::data_structures::{
use crate::ion::reg_traversal::RegTraversalIter;
use crate::moves::{MoveAndScratchResolver, ParallelMoves};
use crate::{
Allocation, Block, Edit, Function, Inst, InstPosition, OperandConstraint, OperandKind,
OperandPos, PReg, ProgPoint, RegClass, SpillSlot, VReg,
Allocation, Block, Edit, Function, FxHashMap, Inst, InstPosition, OperandConstraint,
OperandKind, OperandPos, PReg, ProgPoint, RegClass, SpillSlot, VReg,
};
use fxhash::FxHashMap;
use alloc::vec::Vec;
use alloc::{format, vec};
use core::fmt::Debug;
use smallvec::{smallvec, SmallVec};
use std::fmt::Debug;
impl<'a, F: Function> Env<'a, F> {
pub fn is_start_of_block(&self, pos: ProgPoint) -> bool {
@@ -494,9 +495,9 @@ impl<'a, F: Function> Env<'a, F> {
// this case returns the index of the first
// entry that is greater as an `Err`.
if label_vreg.vreg() < vreg.index() {
std::cmp::Ordering::Less
core::cmp::Ordering::Less
} else {
std::cmp::Ordering::Greater
core::cmp::Ordering::Greater
}
})
.unwrap_err();
@@ -515,8 +516,8 @@ impl<'a, F: Function> Env<'a, F> {
continue;
}
let from = std::cmp::max(label_from, range.from);
let to = std::cmp::min(label_to, range.to);
let from = core::cmp::max(label_from, range.from);
let to = core::cmp::min(label_to, range.to);
self.debug_locations.push((label, from, to, alloc));
}
@@ -629,7 +630,7 @@ impl<'a, F: Function> Env<'a, F> {
}
// Handle multi-fixed-reg constraints by copying.
for fixup in std::mem::replace(&mut self.multi_fixed_reg_fixups, vec![]) {
for fixup in core::mem::replace(&mut self.multi_fixed_reg_fixups, vec![]) {
let from_alloc = self.get_alloc(fixup.pos.inst(), fixup.from_slot as usize);
let to_alloc = Allocation::reg(PReg::from_index(fixup.to_preg.index()));
trace!(

View File

@@ -22,12 +22,11 @@ use crate::{
CodeRange, BUNDLE_MAX_NORMAL_SPILL_WEIGHT, MAX_SPLITS_PER_SPILLSET,
MINIMAL_BUNDLE_SPILL_WEIGHT, MINIMAL_FIXED_BUNDLE_SPILL_WEIGHT,
},
Allocation, Function, Inst, InstPosition, OperandConstraint, OperandKind, PReg, ProgPoint,
RegAllocError,
Allocation, Function, FxHashSet, Inst, InstPosition, OperandConstraint, OperandKind, PReg,
ProgPoint, RegAllocError,
};
use fxhash::FxHashSet;
use core::fmt::Debug;
use smallvec::{smallvec, SmallVec};
use std::fmt::Debug;
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum AllocRegResult {
@@ -159,7 +158,7 @@ impl<'a, F: Function> Env<'a, F> {
trace!(" -> conflict bundle {:?}", conflict_bundle);
if self.conflict_set.insert(conflict_bundle) {
conflicts.push(conflict_bundle);
max_conflict_weight = std::cmp::max(
max_conflict_weight = core::cmp::max(
max_conflict_weight,
self.bundles[conflict_bundle.index()].cached_spill_weight(),
);
@@ -172,7 +171,7 @@ impl<'a, F: Function> Env<'a, F> {
}
if first_conflict.is_none() {
first_conflict = Some(ProgPoint::from_index(std::cmp::max(
first_conflict = Some(ProgPoint::from_index(core::cmp::max(
preg_key.from,
key.from,
)));
@@ -334,7 +333,7 @@ impl<'a, F: Function> Env<'a, F> {
self.bundles[bundle.index()].prio,
final_weight
);
std::cmp::min(BUNDLE_MAX_NORMAL_SPILL_WEIGHT, final_weight)
core::cmp::min(BUNDLE_MAX_NORMAL_SPILL_WEIGHT, final_weight)
} else {
0
}
@@ -824,7 +823,7 @@ impl<'a, F: Function> Env<'a, F> {
// (up to the Before of the next inst), *unless*
// the original LR was only over the Before (up to
// the After) of this inst.
let to = std::cmp::min(ProgPoint::before(u.pos.inst().next()), lr_to);
let to = core::cmp::min(ProgPoint::before(u.pos.inst().next()), lr_to);
// If the last bundle was at the same inst, add a new
// LR to the same bundle; otherwise, create a LR and a
@@ -863,7 +862,7 @@ impl<'a, F: Function> Env<'a, F> {
// Otherwise, create a new LR.
let pos = ProgPoint::before(u.pos.inst());
let pos = std::cmp::max(lr_from, pos);
let pos = core::cmp::max(lr_from, pos);
let cr = CodeRange { from: pos, to };
let lr = self.create_liverange(cr);
new_lrs.push((vreg, lr));
@@ -1036,7 +1035,7 @@ impl<'a, F: Function> Env<'a, F> {
self.get_or_create_spill_bundle(bundle, /* create_if_absent = */ false)
{
let mut list =
std::mem::replace(&mut self.bundles[bundle.index()].ranges, smallvec![]);
core::mem::replace(&mut self.bundles[bundle.index()].ranges, smallvec![]);
for entry in &list {
self.ranges[entry.index.index()].bundle = spill;
}
@@ -1107,7 +1106,7 @@ impl<'a, F: Function> Env<'a, F> {
lowest_cost_evict_conflict_cost,
lowest_cost_split_conflict_cost,
) {
(Some(a), Some(b)) => Some(std::cmp::max(a, b)),
(Some(a), Some(b)) => Some(core::cmp::max(a, b)),
_ => None,
};
match self.try_to_allocate_bundle_to_reg(bundle, preg_idx, scan_limit_cost) {
@@ -1291,7 +1290,7 @@ impl<'a, F: Function> Env<'a, F> {
);
let bundle_start = self.bundles[bundle.index()].ranges[0].range.from;
let mut split_at_point =
std::cmp::max(lowest_cost_split_conflict_point, bundle_start);
core::cmp::max(lowest_cost_split_conflict_point, bundle_start);
let requeue_with_reg = lowest_cost_split_conflict_reg;
// Adjust `split_at_point` if it is within a deeper loop

View File

@@ -1,7 +1,6 @@
//! Redundant-move elimination.
use crate::{Allocation, VReg};
use fxhash::FxHashMap;
use crate::{Allocation, FxHashMap, VReg};
use smallvec::{smallvec, SmallVec};
#[derive(Copy, Clone, Debug, PartialEq, Eq)]

View File

@@ -78,7 +78,7 @@ impl<'a> RegTraversalIter<'a> {
}
}
impl<'a> std::iter::Iterator for RegTraversalIter<'a> {
impl<'a> core::iter::Iterator for RegTraversalIter<'a> {
type Item = PReg;
fn next(&mut self) -> Option<PReg> {

View File

@@ -138,7 +138,7 @@ impl<'a, F: Function> Env<'a, F> {
let mut success = false;
// Never probe the same element more than once: limit the
// attempt count to the number of slots in existence.
for _attempt in 0..std::cmp::min(self.slots_by_size[size].slots.len(), MAX_ATTEMPTS) {
for _attempt in 0..core::cmp::min(self.slots_by_size[size].slots.len(), MAX_ATTEMPTS) {
// Note: this indexing of `slots` is always valid
// because either the `slots` list is empty and the
// iteration limit above consequently means we don't

View File

@@ -12,6 +12,8 @@
//! Stackmap computation.
use alloc::vec::Vec;
use super::{Env, ProgPoint, VRegIndex};
use crate::{ion::data_structures::u64_key, Function};

View File

@@ -11,6 +11,12 @@
*/
#![allow(dead_code)]
#![no_std]
#[cfg(feature = "std")]
extern crate std;
extern crate alloc;
// Even when trace logging is disabled, the trace macro has a significant
// performance cost so we disable it in release builds.
@@ -28,6 +34,11 @@ macro_rules! trace_enabled {
};
}
use core::hash::BuildHasherDefault;
use rustc_hash::FxHasher;
type FxHashMap<K, V> = hashbrown::HashMap<K, V, BuildHasherDefault<FxHasher>>;
type FxHashSet<V> = hashbrown::HashSet<V, BuildHasherDefault<FxHasher>>;
pub(crate) mod cfg;
pub(crate) mod domtree;
pub mod indexset;
@@ -38,6 +49,8 @@ pub mod ssa;
#[macro_use]
mod index;
use alloc::vec::Vec;
pub use index::{Block, Inst, InstRange, InstRangeIter};
pub mod checker;
@@ -142,8 +155,8 @@ impl PReg {
}
}
impl std::fmt::Debug for PReg {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
impl core::fmt::Debug for PReg {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(
f,
"PReg(hw = {}, class = {:?}, index = {})",
@@ -154,8 +167,8 @@ impl std::fmt::Debug for PReg {
}
}
impl std::fmt::Display for PReg {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
impl core::fmt::Display for PReg {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
let class = match self.class() {
RegClass::Int => "i",
RegClass::Float => "f",
@@ -311,8 +324,8 @@ impl VReg {
}
}
impl std::fmt::Debug for VReg {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
impl core::fmt::Debug for VReg {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(
f,
"VReg(vreg = {}, class = {:?})",
@@ -322,8 +335,8 @@ impl std::fmt::Debug for VReg {
}
}
impl std::fmt::Display for VReg {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
impl core::fmt::Display for VReg {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "v{}", self.vreg())
}
}
@@ -382,8 +395,8 @@ impl SpillSlot {
}
}
impl std::fmt::Display for SpillSlot {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
impl core::fmt::Display for SpillSlot {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "stack{}", self.index())
}
}
@@ -413,8 +426,8 @@ pub enum OperandConstraint {
Reuse(usize),
}
impl std::fmt::Display for OperandConstraint {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
impl core::fmt::Display for OperandConstraint {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
match self {
Self::Any => write!(f, "any"),
Self::Reg => write!(f, "reg"),
@@ -796,14 +809,14 @@ impl Operand {
}
}
impl std::fmt::Debug for Operand {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
std::fmt::Display::fmt(self, f)
impl core::fmt::Debug for Operand {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
core::fmt::Display::fmt(self, f)
}
}
impl std::fmt::Display for Operand {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
impl core::fmt::Display for Operand {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
match (self.kind(), self.pos()) {
(OperandKind::Def, OperandPos::Late) | (OperandKind::Use, OperandPos::Early) => {
write!(f, "{:?}", self.kind())?;
@@ -836,14 +849,14 @@ pub struct Allocation {
bits: u32,
}
impl std::fmt::Debug for Allocation {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
std::fmt::Display::fmt(self, f)
impl core::fmt::Debug for Allocation {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
core::fmt::Display::fmt(self, f)
}
}
impl std::fmt::Display for Allocation {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
impl core::fmt::Display for Allocation {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
match self.kind() {
AllocationKind::None => write!(f, "none"),
AllocationKind::Reg => write!(f, "{}", self.as_reg().unwrap()),
@@ -1173,8 +1186,8 @@ pub struct ProgPoint {
bits: u32,
}
impl std::fmt::Debug for ProgPoint {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
impl core::fmt::Debug for ProgPoint {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(
f,
"progpoint{}{}",
@@ -1422,9 +1435,9 @@ impl Output {
// binary_search_by returns the index of where it would have
// been inserted in Err.
if pos < ProgPoint::before(inst_range.first()) {
std::cmp::Ordering::Less
core::cmp::Ordering::Less
} else {
std::cmp::Ordering::Greater
core::cmp::Ordering::Greater
}
})
.unwrap_err();
@@ -1463,12 +1476,13 @@ pub enum RegAllocError {
TooManyLiveRegs,
}
impl std::fmt::Display for RegAllocError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
impl core::fmt::Display for RegAllocError {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{:?}", self)
}
}
#[cfg(feature = "std")]
impl std::error::Error for RegAllocError {}
/// Run the allocator.

View File

@@ -4,8 +4,8 @@
*/
use crate::{ion::data_structures::u64_key, Allocation, PReg};
use core::fmt::Debug;
use smallvec::{smallvec, SmallVec};
use std::fmt::Debug;
/// A list of moves to be performed in sequence, with auxiliary data
/// attached to each.

View File

@@ -6,6 +6,8 @@
//! Fast postorder computation.
use crate::Block;
use alloc::vec;
use alloc::vec::Vec;
use smallvec::{smallvec, SmallVec};
pub fn calculate<'a, SuccFn: Fn(Block) -> &'a [Block]>(

View File

@@ -5,7 +5,8 @@
//! SSA-related utilities.
use std::collections::HashSet;
use alloc::vec;
use hashbrown::HashSet;
use crate::cfg::CFGInfo;
use crate::{Block, Function, Inst, OperandKind, RegAllocError, VReg};