Skip to content

Commit 2bd0325

Browse files
authored
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
1 parent 7354cfe commit 2bd0325

23 files changed

+176
-115
lines changed

.github/workflows/rust.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,16 @@ jobs:
3737
- name: Check with all features
3838
run: cargo check --all-features
3939

40+
# Make sure the code and its dependencies compile without std.
41+
no_std:
42+
runs-on: ubuntu-latest
43+
steps:
44+
- uses: actions/checkout@v3
45+
- name: Install thumbv6m-none-eabi target
46+
run: rustup target add thumbv6m-none-eabi
47+
- name: Check no_std build
48+
run: cargo check --target thumbv6m-none-eabi --no-default-features --features trace-log,checker,enable-serde
49+
4050
# Lint dependency graph for security advisories, duplicate versions, and
4151
# incompatible licences.
4252
cargo_deny:

Cargo.toml

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,15 @@ repository = "https://github.com/bytecodealliance/regalloc2"
1313
[dependencies]
1414
log = { version = "0.4.8", default-features = false }
1515
smallvec = { version = "1.6.1", features = ["union"] }
16-
fxhash = "0.2.1"
17-
slice-group-by = "0.3.0"
16+
rustc-hash = { version = "1.1.0", default-features = false }
17+
slice-group-by = { version = "0.3.0", default-features = false }
18+
hashbrown = "0.13.2"
1819

1920
# Optional serde support, enabled by feature below.
20-
serde = { version = "1.0.136", features = ["derive"], optional = true }
21+
serde = { version = "1.0.136", features = [
22+
"derive",
23+
"alloc",
24+
], default-features = false, optional = true }
2125

2226
# The below are only needed for fuzzing.
2327
libfuzzer-sys = { version = "0.4.2", optional = true }
@@ -29,7 +33,10 @@ debug-assertions = true
2933
overflow-checks = true
3034

3135
[features]
32-
default = []
36+
default = ["std"]
37+
38+
# Enables std-specific features such as the Error trait for RegAllocError.
39+
std = []
3340

3441
# Enables generation of DefAlloc edits for the checker.
3542
checker = []

src/cfg.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
//! Lightweight CFG analyses.
77
88
use crate::{domtree, postorder, Block, Function, Inst, ProgPoint, RegAllocError};
9+
use alloc::vec;
10+
use alloc::vec::Vec;
911
use smallvec::{smallvec, SmallVec};
1012

1113
#[derive(Clone, Debug)]

src/checker.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -96,14 +96,16 @@
9696
#![allow(dead_code)]
9797

9898
use crate::{
99-
Allocation, AllocationKind, Block, Edit, Function, Inst, InstOrEdit, InstPosition, MachineEnv,
100-
Operand, OperandConstraint, OperandKind, OperandPos, Output, PReg, PRegSet, VReg,
99+
Allocation, AllocationKind, Block, Edit, Function, FxHashMap, FxHashSet, Inst, InstOrEdit,
100+
InstPosition, MachineEnv, Operand, OperandConstraint, OperandKind, OperandPos, Output, PReg,
101+
PRegSet, VReg,
101102
};
102-
use fxhash::{FxHashMap, FxHashSet};
103+
use alloc::vec::Vec;
104+
use alloc::{format, vec};
105+
use core::default::Default;
106+
use core::hash::Hash;
107+
use core::result::Result;
103108
use smallvec::{smallvec, SmallVec};
104-
use std::default::Default;
105-
use std::hash::Hash;
106-
use std::result::Result;
107109

108110
/// A set of errors detected by the regalloc checker.
109111
#[derive(Clone, Debug)]
@@ -230,7 +232,7 @@ impl CheckerValue {
230232
}
231233

232234
fn from_reg(reg: VReg) -> CheckerValue {
233-
CheckerValue::VRegs(std::iter::once(reg).collect())
235+
CheckerValue::VRegs(core::iter::once(reg).collect())
234236
}
235237

236238
fn remove_vreg(&mut self, reg: VReg) {
@@ -373,8 +375,8 @@ impl Default for CheckerState {
373375
}
374376
}
375377

376-
impl std::fmt::Display for CheckerValue {
377-
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
378+
impl core::fmt::Display for CheckerValue {
379+
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
378380
match self {
379381
CheckerValue::Universe => {
380382
write!(f, "top")

src/domtree.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
// TR-06-33870
1313
// https://www.cs.rice.edu/~keith/EMBED/dom.pdf
1414

15+
use alloc::vec;
16+
use alloc::vec::Vec;
17+
1518
use crate::Block;
1619

1720
// Helper

src/fuzzing/func.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ use crate::{
88
OperandConstraint, OperandKind, OperandPos, PReg, PRegSet, RegClass, VReg,
99
};
1010

11+
use alloc::vec::Vec;
12+
use alloc::{format, vec};
13+
1114
use super::arbitrary::Result as ArbitraryResult;
1215
use super::arbitrary::{Arbitrary, Unstructured};
1316

@@ -275,7 +278,7 @@ pub struct Options {
275278
pub reftypes: bool,
276279
}
277280

278-
impl std::default::Default for Options {
281+
impl core::default::Default for Options {
279282
fn default() -> Self {
280283
Options {
281284
reused_inputs: false,
@@ -404,7 +407,7 @@ impl Func {
404407
}
405408
vregs_by_block.push(vregs.clone());
406409
vregs_by_block_to_be_defined.push(vec![]);
407-
let mut max_block_params = u.int_in_range(0..=std::cmp::min(3, vregs.len() / 3))?;
410+
let mut max_block_params = u.int_in_range(0..=core::cmp::min(3, vregs.len() / 3))?;
408411
for &vreg in &vregs {
409412
if block > 0 && opts.block_params && bool::arbitrary(u)? && max_block_params > 0 {
410413
block_params[block].push(vreg);
@@ -591,8 +594,8 @@ impl Func {
591594
}
592595
}
593596

594-
impl std::fmt::Debug for Func {
595-
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
597+
impl core::fmt::Debug for Func {
598+
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
596599
write!(f, "{{\n")?;
597600
for vreg in self.reftype_vregs() {
598601
write!(f, " REF: {}\n", vreg)?;
@@ -653,7 +656,7 @@ impl std::fmt::Debug for Func {
653656
}
654657

655658
pub fn machine_env() -> MachineEnv {
656-
fn regs(r: std::ops::Range<usize>) -> Vec<PReg> {
659+
fn regs(r: core::ops::Range<usize>) -> Vec<PReg> {
657660
r.map(|i| PReg::new(i, RegClass::Int)).collect()
658661
}
659662
let preferred_regs_by_class: [Vec<PReg>; 2] = [regs(0..24), vec![]];

src/index.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,11 @@ macro_rules! define_index {
5050
};
5151
}
5252

53-
pub trait ContainerIndex: Clone + Copy + std::fmt::Debug + PartialEq + Eq {}
53+
pub trait ContainerIndex: Clone + Copy + core::fmt::Debug + PartialEq + Eq {}
5454

5555
pub trait ContainerComparator {
5656
type Ix: ContainerIndex;
57-
fn compare(&self, a: Self::Ix, b: Self::Ix) -> std::cmp::Ordering;
57+
fn compare(&self, a: Self::Ix, b: Self::Ix) -> core::cmp::Ordering;
5858
}
5959

6060
define_index!(Inst);
@@ -146,6 +146,9 @@ impl Iterator for InstRangeIter {
146146

147147
#[cfg(test)]
148148
mod test {
149+
use alloc::vec;
150+
use alloc::vec::Vec;
151+
149152
use super::*;
150153

151154
#[test]

src/indexset.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55

66
//! Index sets: sets of integers that represent indices into a space.
77
8-
use fxhash::FxHashMap;
9-
use std::cell::Cell;
8+
use alloc::vec::Vec;
9+
use core::cell::Cell;
10+
11+
use crate::FxHashMap;
1012

1113
const SMALL_ELEMS: usize = 12;
1214

@@ -151,10 +153,10 @@ impl AdaptiveMap {
151153

152154
enum AdaptiveMapIter<'a> {
153155
Small(&'a [u32], &'a [u64]),
154-
Large(std::collections::hash_map::Iter<'a, u32, u64>),
156+
Large(hashbrown::hash_map::Iter<'a, u32, u64>),
155157
}
156158

157-
impl<'a> std::iter::Iterator for AdaptiveMapIter<'a> {
159+
impl<'a> core::iter::Iterator for AdaptiveMapIter<'a> {
158160
type Item = (u32, u64);
159161

160162
#[inline]
@@ -292,16 +294,16 @@ impl Iterator for SetBitsIter {
292294
// Build an `Option<NonZeroU64>` so that on the nonzero path,
293295
// the compiler can optimize the trailing-zeroes operator
294296
// using that knowledge.
295-
std::num::NonZeroU64::new(self.0).map(|nz| {
297+
core::num::NonZeroU64::new(self.0).map(|nz| {
296298
let bitidx = nz.trailing_zeros();
297299
self.0 &= self.0 - 1; // clear highest set bit
298300
bitidx as usize
299301
})
300302
}
301303
}
302304

303-
impl std::fmt::Debug for IndexSet {
304-
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
305+
impl core::fmt::Debug for IndexSet {
306+
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
305307
let vals = self.iter().collect::<Vec<_>>();
306308
write!(f, "{:?}", vals)
307309
}

src/ion/data_structures.rs

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,16 @@ use crate::cfg::CFGInfo;
1717
use crate::index::ContainerComparator;
1818
use crate::indexset::IndexSet;
1919
use crate::{
20-
define_index, Allocation, Block, Edit, Function, Inst, MachineEnv, Operand, PReg, ProgPoint,
21-
RegClass, VReg,
20+
define_index, Allocation, Block, Edit, Function, FxHashSet, Inst, MachineEnv, Operand, PReg,
21+
ProgPoint, RegClass, VReg,
2222
};
23-
use fxhash::FxHashSet;
23+
use alloc::collections::BTreeMap;
24+
use alloc::string::String;
25+
use alloc::vec::Vec;
26+
use core::cmp::Ordering;
27+
use core::fmt::Debug;
28+
use hashbrown::{HashMap, HashSet};
2429
use smallvec::SmallVec;
25-
use std::cmp::Ordering;
26-
use std::collections::{BTreeMap, HashMap, HashSet};
27-
use std::fmt::Debug;
2830

2931
/// A range from `from` (inclusive) to `to` (exclusive).
3032
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
@@ -64,13 +66,13 @@ impl CodeRange {
6466
}
6567
}
6668

67-
impl std::cmp::PartialOrd for CodeRange {
69+
impl core::cmp::PartialOrd for CodeRange {
6870
#[inline(always)]
6971
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
7072
Some(self.cmp(other))
7173
}
7274
}
73-
impl std::cmp::Ord for CodeRange {
75+
impl core::cmp::Ord for CodeRange {
7476
#[inline(always)]
7577
fn cmp(&self, other: &Self) -> Ordering {
7678
if self.to <= other.from {
@@ -278,7 +280,7 @@ const fn no_bloat_capacity<T>() -> usize {
278280
//
279281
// So if `size_of([T; N]) == size_of(pointer) + size_of(capacity)` then we
280282
// get the maximum inline capacity without bloat.
281-
std::mem::size_of::<usize>() * 2 / std::mem::size_of::<T>()
283+
core::mem::size_of::<usize>() * 2 / core::mem::size_of::<T>()
282284
}
283285

284286
#[derive(Clone, Debug)]
@@ -431,7 +433,7 @@ pub struct Env<'a, F: Function> {
431433

432434
// For debug output only: a list of textual annotations at every
433435
// ProgPoint to insert into the final allocated program listing.
434-
pub debug_annotations: std::collections::HashMap<ProgPoint, Vec<String>>,
436+
pub debug_annotations: hashbrown::HashMap<ProgPoint, Vec<String>>,
435437
pub annotations_enabled: bool,
436438

437439
// Cached allocation for `try_to_allocate_bundle_to_reg` to avoid allocating
@@ -492,7 +494,7 @@ impl SpillSlotList {
492494

493495
#[derive(Clone, Debug)]
494496
pub struct PrioQueue {
495-
pub heap: std::collections::BinaryHeap<PrioQueueEntry>,
497+
pub heap: alloc::collections::BinaryHeap<PrioQueueEntry>,
496498
}
497499

498500
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
@@ -531,28 +533,28 @@ impl LiveRangeKey {
531533
}
532534
}
533535

534-
impl std::cmp::PartialEq for LiveRangeKey {
536+
impl core::cmp::PartialEq for LiveRangeKey {
535537
#[inline(always)]
536538
fn eq(&self, other: &Self) -> bool {
537539
self.to > other.from && self.from < other.to
538540
}
539541
}
540-
impl std::cmp::Eq for LiveRangeKey {}
541-
impl std::cmp::PartialOrd for LiveRangeKey {
542+
impl core::cmp::Eq for LiveRangeKey {}
543+
impl core::cmp::PartialOrd for LiveRangeKey {
542544
#[inline(always)]
543-
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
545+
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
544546
Some(self.cmp(other))
545547
}
546548
}
547-
impl std::cmp::Ord for LiveRangeKey {
549+
impl core::cmp::Ord for LiveRangeKey {
548550
#[inline(always)]
549-
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
551+
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
550552
if self.to <= other.from {
551-
std::cmp::Ordering::Less
553+
core::cmp::Ordering::Less
552554
} else if self.from >= other.to {
553-
std::cmp::Ordering::Greater
555+
core::cmp::Ordering::Greater
554556
} else {
555-
std::cmp::Ordering::Equal
557+
core::cmp::Ordering::Equal
556558
}
557559
}
558560
}
@@ -562,15 +564,15 @@ pub struct PrioQueueComparator<'a> {
562564
}
563565
impl<'a> ContainerComparator for PrioQueueComparator<'a> {
564566
type Ix = LiveBundleIndex;
565-
fn compare(&self, a: Self::Ix, b: Self::Ix) -> std::cmp::Ordering {
567+
fn compare(&self, a: Self::Ix, b: Self::Ix) -> core::cmp::Ordering {
566568
self.prios[a.index()].cmp(&self.prios[b.index()])
567569
}
568570
}
569571

570572
impl PrioQueue {
571573
pub fn new() -> Self {
572574
PrioQueue {
573-
heap: std::collections::BinaryHeap::new(),
575+
heap: alloc::collections::BinaryHeap::new(),
574576
}
575577
}
576578

src/ion/dump.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
//! Debugging output.
22
3+
use alloc::string::ToString;
4+
use alloc::{format, vec};
5+
use alloc::{string::String, vec::Vec};
6+
37
use super::Env;
48
use crate::{Block, Function, ProgPoint};
59

0 commit comments

Comments
 (0)