diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index ced6eb9..1393b11 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -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: diff --git a/Cargo.toml b/Cargo.toml index 60f35b9..dfff957 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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 = [] diff --git a/src/cfg.rs b/src/cfg.rs index a882f97..cbb6cea 100644 --- a/src/cfg.rs +++ b/src/cfg.rs @@ -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)] diff --git a/src/checker.rs b/src/checker.rs index 10fd458..6df858b 100644 --- a/src/checker.rs +++ b/src/checker.rs @@ -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") diff --git a/src/domtree.rs b/src/domtree.rs index 1bf4139..33c7108 100644 --- a/src/domtree.rs +++ b/src/domtree.rs @@ -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 diff --git a/src/fuzzing/func.rs b/src/fuzzing/func.rs index 81057ce..6996a4c 100644 --- a/src/fuzzing/func.rs +++ b/src/fuzzing/func.rs @@ -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) -> Vec { + fn regs(r: core::ops::Range) -> Vec { r.map(|i| PReg::new(i, RegClass::Int)).collect() } let preferred_regs_by_class: [Vec; 2] = [regs(0..24), vec![]]; diff --git a/src/index.rs b/src/index.rs index d847484..a624c3e 100644 --- a/src/index.rs +++ b/src/index.rs @@ -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] diff --git a/src/indexset.rs b/src/indexset.rs index 20e70eb..1fd58a2 100644 --- a/src/indexset.rs +++ b/src/indexset.rs @@ -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` 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::>(); write!(f, "{:?}", vals) } diff --git a/src/ion/data_structures.rs b/src/ion/data_structures.rs index f8bafc7..ecc903e 100644 --- a/src/ion/data_structures.rs +++ b/src/ion/data_structures.rs @@ -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 { 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() -> 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::() * 2 / std::mem::size_of::() + core::mem::size_of::() * 2 / core::mem::size_of::() } #[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>, + pub debug_annotations: hashbrown::HashMap>, 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, + pub heap: alloc::collections::BinaryHeap, } #[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 { + fn partial_cmp(&self, other: &Self) -> Option { 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(), } } diff --git a/src/ion/dump.rs b/src/ion/dump.rs index ba4f74f..abcaaf3 100644 --- a/src/ion/dump.rs +++ b/src/ion/dump.rs @@ -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}; diff --git a/src/ion/liveranges.rs b/src/ion/liveranges.rs index da4668e..5a9b00e 100644 --- a/src/ion/liveranges.rs +++ b/src/ion/liveranges.rs @@ -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 for SpillWeight { +impl core::ops::Add for SpillWeight { type Output = SpillWeight; fn add(self, other: SpillWeight) -> Self { SpillWeight(self.0 + other.0) diff --git a/src/ion/merge.rs b/src/ion/merge.rs index 3d57d55..54aeaa5 100644 --- a/src/ion/merge.rs +++ b/src/ion/merge.rs @@ -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![], ); diff --git a/src/ion/mod.rs b/src/ion/mod.rs index 8edbfe0..550af90 100644 --- a/src/ion/mod.rs +++ b/src/ion/mod.rs @@ -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(), diff --git a/src/ion/moves.rs b/src/ion/moves.rs index a196e5d..32ae768 100644 --- a/src/ion/moves.rs +++ b/src/ion/moves.rs @@ -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!( diff --git a/src/ion/process.rs b/src/ion/process.rs index 0c2161b..e33a4c6 100644 --- a/src/ion/process.rs +++ b/src/ion/process.rs @@ -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 diff --git a/src/ion/redundant_moves.rs b/src/ion/redundant_moves.rs index 41ed255..3aed48f 100644 --- a/src/ion/redundant_moves.rs +++ b/src/ion/redundant_moves.rs @@ -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)] diff --git a/src/ion/reg_traversal.rs b/src/ion/reg_traversal.rs index 0b457cb..729fd33 100644 --- a/src/ion/reg_traversal.rs +++ b/src/ion/reg_traversal.rs @@ -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 { diff --git a/src/ion/spill.rs b/src/ion/spill.rs index 3583080..3068a65 100644 --- a/src/ion/spill.rs +++ b/src/ion/spill.rs @@ -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 diff --git a/src/ion/stackmap.rs b/src/ion/stackmap.rs index 108835a..534e86b 100644 --- a/src/ion/stackmap.rs +++ b/src/ion/stackmap.rs @@ -12,6 +12,8 @@ //! Stackmap computation. +use alloc::vec::Vec; + use super::{Env, ProgPoint, VRegIndex}; use crate::{ion::data_structures::u64_key, Function}; diff --git a/src/lib.rs b/src/lib.rs index 4b5a468..8aa9d4c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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 = hashbrown::HashMap>; +type FxHashSet = hashbrown::HashSet>; + 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. diff --git a/src/moves.rs b/src/moves.rs index 8194b72..82c68f5 100644 --- a/src/moves.rs +++ b/src/moves.rs @@ -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. diff --git a/src/postorder.rs b/src/postorder.rs index 96e9787..3e04eb0 100644 --- a/src/postorder.rs +++ b/src/postorder.rs @@ -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]>( diff --git a/src/ssa.rs b/src/ssa.rs index 8b9c6f8..ac6263e 100644 --- a/src/ssa.rs +++ b/src/ssa.rs @@ -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};