Skip to content

Commit

Permalink
Make regalloc2 #![no_std] (#119)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
Amanieu authored Mar 9, 2023
1 parent 7354cfe commit 2bd0325
Show file tree
Hide file tree
Showing 23 changed files with 176 additions and 115 deletions.
10 changes: 10 additions & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
15 changes: 11 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand All @@ -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 = []
Expand Down
2 changes: 2 additions & 0 deletions src/cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
20 changes: 11 additions & 9 deletions src/checker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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")
Expand Down
3 changes: 3 additions & 0 deletions src/domtree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 8 additions & 5 deletions src/fuzzing/func.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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)?;
Expand Down Expand Up @@ -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![]];
Expand Down
7 changes: 5 additions & 2 deletions src/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -146,6 +146,9 @@ impl Iterator for InstRangeIter {

#[cfg(test)]
mod test {
use alloc::vec;
use alloc::vec::Vec;

use super::*;

#[test]
Expand Down
16 changes: 9 additions & 7 deletions src/indexset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -292,16 +294,16 @@ 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
})
}
}

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)
}
Expand Down
46 changes: 24 additions & 22 deletions src/ion/data_structures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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)]
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)]
Expand Down Expand Up @@ -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
}
}
}
Expand All @@ -562,15 +564,15 @@ 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()])
}
}

impl PrioQueue {
pub fn new() -> Self {
PrioQueue {
heap: std::collections::BinaryHeap::new(),
heap: alloc::collections::BinaryHeap::new(),
}
}

Expand Down
4 changes: 4 additions & 0 deletions src/ion/dump.rs
Original file line number Diff line number Diff line change
@@ -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};

Expand Down
14 changes: 8 additions & 6 deletions src/ion/liveranges.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand All @@ -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 {
Expand Down Expand Up @@ -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)
Expand Down
Loading

0 comments on commit 2bd0325

Please sign in to comment.