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 - name: Check with all features
run: cargo check --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 # Lint dependency graph for security advisories, duplicate versions, and
# incompatible licences. # incompatible licences.
cargo_deny: cargo_deny:

View File

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

View File

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

View File

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

View File

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

View File

@@ -8,6 +8,9 @@ use crate::{
OperandConstraint, OperandKind, OperandPos, PReg, PRegSet, RegClass, VReg, OperandConstraint, OperandKind, OperandPos, PReg, PRegSet, RegClass, VReg,
}; };
use alloc::vec::Vec;
use alloc::{format, vec};
use super::arbitrary::Result as ArbitraryResult; use super::arbitrary::Result as ArbitraryResult;
use super::arbitrary::{Arbitrary, Unstructured}; use super::arbitrary::{Arbitrary, Unstructured};
@@ -275,7 +278,7 @@ pub struct Options {
pub reftypes: bool, pub reftypes: bool,
} }
impl std::default::Default for Options { impl core::default::Default for Options {
fn default() -> Self { fn default() -> Self {
Options { Options {
reused_inputs: false, reused_inputs: false,
@@ -404,7 +407,7 @@ impl Func {
} }
vregs_by_block.push(vregs.clone()); vregs_by_block.push(vregs.clone());
vregs_by_block_to_be_defined.push(vec![]); 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 { for &vreg in &vregs {
if block > 0 && opts.block_params && bool::arbitrary(u)? && max_block_params > 0 { if block > 0 && opts.block_params && bool::arbitrary(u)? && max_block_params > 0 {
block_params[block].push(vreg); block_params[block].push(vreg);
@@ -591,8 +594,8 @@ impl Func {
} }
} }
impl std::fmt::Debug for Func { impl core::fmt::Debug for Func {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{{\n")?; write!(f, "{{\n")?;
for vreg in self.reftype_vregs() { for vreg in self.reftype_vregs() {
write!(f, " REF: {}\n", vreg)?; write!(f, " REF: {}\n", vreg)?;
@@ -653,7 +656,7 @@ impl std::fmt::Debug for Func {
} }
pub fn machine_env() -> MachineEnv { 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() r.map(|i| PReg::new(i, RegClass::Int)).collect()
} }
let preferred_regs_by_class: [Vec<PReg>; 2] = [regs(0..24), vec![]]; 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 { pub trait ContainerComparator {
type Ix: ContainerIndex; 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); define_index!(Inst);
@@ -146,6 +146,9 @@ impl Iterator for InstRangeIter {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use alloc::vec;
use alloc::vec::Vec;
use super::*; use super::*;
#[test] #[test]

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -22,12 +22,13 @@ use crate::ion::data_structures::{
use crate::ion::reg_traversal::RegTraversalIter; use crate::ion::reg_traversal::RegTraversalIter;
use crate::moves::{MoveAndScratchResolver, ParallelMoves}; use crate::moves::{MoveAndScratchResolver, ParallelMoves};
use crate::{ use crate::{
Allocation, Block, Edit, Function, Inst, InstPosition, OperandConstraint, OperandKind, Allocation, Block, Edit, Function, FxHashMap, Inst, InstPosition, OperandConstraint,
OperandPos, PReg, ProgPoint, RegClass, SpillSlot, VReg, 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 smallvec::{smallvec, SmallVec};
use std::fmt::Debug;
impl<'a, F: Function> Env<'a, F> { impl<'a, F: Function> Env<'a, F> {
pub fn is_start_of_block(&self, pos: ProgPoint) -> bool { 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 // this case returns the index of the first
// entry that is greater as an `Err`. // entry that is greater as an `Err`.
if label_vreg.vreg() < vreg.index() { if label_vreg.vreg() < vreg.index() {
std::cmp::Ordering::Less core::cmp::Ordering::Less
} else { } else {
std::cmp::Ordering::Greater core::cmp::Ordering::Greater
} }
}) })
.unwrap_err(); .unwrap_err();
@@ -515,8 +516,8 @@ impl<'a, F: Function> Env<'a, F> {
continue; continue;
} }
let from = std::cmp::max(label_from, range.from); let from = core::cmp::max(label_from, range.from);
let to = std::cmp::min(label_to, range.to); let to = core::cmp::min(label_to, range.to);
self.debug_locations.push((label, from, to, alloc)); 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. // 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 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())); let to_alloc = Allocation::reg(PReg::from_index(fixup.to_preg.index()));
trace!( trace!(

View File

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

View File

@@ -1,7 +1,6 @@
//! Redundant-move elimination. //! Redundant-move elimination.
use crate::{Allocation, VReg}; use crate::{Allocation, FxHashMap, VReg};
use fxhash::FxHashMap;
use smallvec::{smallvec, SmallVec}; use smallvec::{smallvec, SmallVec};
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[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; type Item = PReg;
fn next(&mut self) -> Option<PReg> { fn next(&mut self) -> Option<PReg> {

View File

@@ -138,7 +138,7 @@ impl<'a, F: Function> Env<'a, F> {
let mut success = false; let mut success = false;
// Never probe the same element more than once: limit the // Never probe the same element more than once: limit the
// attempt count to the number of slots in existence. // 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 // Note: this indexing of `slots` is always valid
// because either the `slots` list is empty and the // because either the `slots` list is empty and the
// iteration limit above consequently means we don't // iteration limit above consequently means we don't

View File

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

View File

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

View File

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

View File

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

View File

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