Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding new API that accepts resusable context. #196

Merged
merged 33 commits into from
Oct 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
6b21989
adding new api that accepts resuable context
jakubDoka Sep 21, 2024
c1c7614
fixing nostd compatibility
jakubDoka Sep 21, 2024
8397803
reusing memory on more places
jakubDoka Sep 21, 2024
ad3ef8e
reusing memory on more places
jakubDoka Sep 21, 2024
5fba123
improving things and fixing a bug
jakubDoka Sep 21, 2024
6907700
removig major smallvec allocation
jakubDoka Sep 22, 2024
523f85d
removig major smallvec allocation
jakubDoka Sep 22, 2024
d7af63f
tracking down nasty hashmap
jakubDoka Sep 22, 2024
4eec91a
fixing std compat
jakubDoka Sep 22, 2024
fdd9abf
experimenting with struct of arrays
jakubDoka Sep 23, 2024
a54ebf4
saving
jakubDoka Sep 23, 2024
7d599e0
saving again
jakubDoka Sep 23, 2024
604eacc
reverting soa changes, they give marginal returns
jakubDoka Sep 23, 2024
7b89e02
removing expensive hashmaps
jakubDoka Sep 23, 2024
09d36db
removing more hashmaps
jakubDoka Sep 24, 2024
5d2e0ac
resolving conflicts
jakubDoka Sep 24, 2024
17a8647
Merge branch 'main' into reuse-allocations
jakubDoka Sep 24, 2024
622deb9
fmt
jakubDoka Sep 24, 2024
d736593
reducing dependencies
jakubDoka Sep 24, 2024
4100af4
fixing ctx not running fastalloc
jakubDoka Sep 24, 2024
fda77e2
revering some changes
jakubDoka Sep 26, 2024
b6f11fb
revering code motion
jakubDoka Sep 26, 2024
8d2d384
revering code motion
jakubDoka Sep 26, 2024
0008e8e
forgot to delete this
jakubDoka Sep 26, 2024
f9df2bf
lto breaks the build
jakubDoka Sep 26, 2024
c4d21e2
fixing the std compat
jakubDoka Sep 26, 2024
4b3b715
removing comented code
jakubDoka Oct 2, 2024
31f2a81
removing unrelated changes
jakubDoka Oct 2, 2024
b87b46a
removing useless method
jakubDoka Oct 2, 2024
2a071f1
resolving comments
jakubDoka Oct 3, 2024
742a7ee
fixing mistakes
jakubDoka Oct 3, 2024
76bd940
hiding the Bump
jakubDoka Oct 3, 2024
21c43e3
making more intuitive api
jakubDoka Oct 3, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ repository = "https://github.com/bytecodealliance/regalloc2"
log = { version = "0.4.8", default-features = false }
smallvec = { version = "1.6.1", features = ["union"] }
rustc-hash = { version = "2.0.0", default-features = false }
slice-group-by = { version = "0.3.0", default-features = false }
hashbrown = { version = "0.14", features = ["ahash"], default-features = false }
hashbrown = { version = "0.14", default-features = false, features = [] }

# Optional serde support, enabled by feature below.
serde = { version = "1.0.136", features = [
Expand All @@ -28,6 +27,8 @@ serde = { version = "1.0.136", features = [

# The below are only needed for fuzzing.
libfuzzer-sys = { version = "0.4.2", optional = true }
bumpalo = { version = "3.16.0", features = ["allocator-api2"] }
allocator-api2 = { version = "0.2.18", default-features = false, features = ["alloc"] }

# When testing regalloc2 by itself, enable debug assertions and overflow checks
[profile.release]
Expand Down
18 changes: 13 additions & 5 deletions fuzz/fuzz_targets/domtree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,13 +116,21 @@ impl Arbitrary<'_> for TestCase {
}

fuzz_target!(|testcase: TestCase| {
let postord = postorder::calculate(testcase.cfg.num_blocks, Block::new(0), |block| {
&testcase.cfg.succs[block.index()]
});
let idom = domtree::calculate(
let mut postorder = vec![];
postorder::calculate(
testcase.cfg.num_blocks,
Block::new(0),
&mut vec![],
&mut postorder,
|block| &testcase.cfg.succs[block.index()],
);
let mut idom = vec![];
domtree::calculate(
testcase.cfg.num_blocks,
|block| &testcase.cfg.preds[block.index()],
&postord[..],
&postorder[..],
&mut vec![],
&mut idom,
Block::new(0),
);
check_idom_violations(&idom[..], &testcase.path);
Expand Down
12 changes: 10 additions & 2 deletions fuzz/fuzz_targets/ion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ fuzz_target!(|func: Func| {
let _ = env_logger::try_init();
log::trace!("func:\n{:?}", func);
let env = regalloc2::fuzzing::func::machine_env();
let _out =
regalloc2::fuzzing::ion::run(&func, &env, false, false).expect("regalloc did not succeed");

thread_local! {
// We test that ctx is cleared properly between runs.
static CTX: std::cell::RefCell<regalloc2::fuzzing::ion::Ctx> = std::cell::RefCell::default();
}

CTX.with(|ctx| {
let _out = regalloc2::fuzzing::ion::run(&func, &env, &mut *ctx.borrow_mut(), false, false)
.expect("regalloc did not succeed");
});
});
18 changes: 13 additions & 5 deletions fuzz/fuzz_targets/ion_checker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,18 @@ fuzz_target!(|testcase: TestCase| {
let _ = env_logger::try_init();
log::trace!("func:\n{:?}", func);
let env = regalloc2::fuzzing::func::machine_env();
let out =
regalloc2::fuzzing::ion::run(&func, &env, true, false).expect("regalloc did not succeed");

let mut checker = Checker::new(&func, &env);
checker.prepare(&out);
checker.run().expect("checker failed");
thread_local! {
// We test that ctx is cleared properly between runs.
static CTX: std::cell::RefCell<regalloc2::fuzzing::ion::Ctx> = std::cell::RefCell::default();
}

CTX.with(|ctx| {
regalloc2::fuzzing::ion::run(&func, &env, &mut *ctx.borrow_mut(), true, false)
.expect("regalloc did not succeed");

let mut checker = Checker::new(&func, &env);
checker.prepare(&ctx.borrow().output);
checker.run().expect("checker failed");
});
});
13 changes: 10 additions & 3 deletions fuzz/fuzz_targets/ssagen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

#![no_main]
use regalloc2::fuzzing::arbitrary::{Arbitrary, Result, Unstructured};
use regalloc2::fuzzing::cfg::CFGInfo;
use regalloc2::fuzzing::cfg::{CFGInfo, CFGInfoCtx};
use regalloc2::fuzzing::func::{Func, Options};
use regalloc2::fuzzing::fuzz_target;
use regalloc2::ssa::validate_ssa;
Expand Down Expand Up @@ -33,6 +33,13 @@ impl Arbitrary<'_> for TestCase {
}

fuzz_target!(|t: TestCase| {
let cfginfo = CFGInfo::new(&t.f).expect("could not create CFG info");
validate_ssa(&t.f, &cfginfo).expect("invalid SSA");
thread_local! {
// We test that ctx is cleared properly between runs.
static CFG_INFO: std::cell::RefCell<(CFGInfo, CFGInfoCtx)> = std::cell::RefCell::default();
}

CFG_INFO.with_borrow_mut(|(cfginfo, ctx)| {
cfginfo.init(&t.f, ctx).expect("could not create CFG info");
validate_ssa(&t.f, &cfginfo).expect("invalid SSA");
});
});
10 changes: 5 additions & 5 deletions regalloc2-tool/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ fn main() {
}

fn print_output(func: &SerializableFunction, output: &Output) {
print!("Register allocation result: {{\n");
println!("Register allocation result: {{");
for i in 0..func.num_blocks() {
let block = Block::new(i);
let succs = func
Expand All @@ -84,7 +84,7 @@ fn print_output(func: &SerializableFunction, output: &Output) {
.iter()
.map(|b| b.index())
.collect::<Vec<_>>();
print!(" block{}: # succs:{:?} preds:{:?}\n", i, succs, preds);
println!(" block{}: # succs:{:?} preds:{:?}", i, succs, preds);
for inst_or_edit in output.block_insts_and_edits(func, block) {
match inst_or_edit {
InstOrEdit::Inst(inst) => {
Expand All @@ -102,13 +102,13 @@ fn print_output(func: &SerializableFunction, output: &Output) {
.map(|(op, alloc)| format!("{op} => {alloc}"))
.collect();
let ops = ops.join(", ");
print!(" inst{}: {op} {ops}\n", inst.index(),);
println!(" inst{}: {op} {ops}", inst.index(),);
}
InstOrEdit::Edit(Edit::Move { from, to }) => {
print!(" edit: move {to} <- {from}\n");
println!(" edit: move {to} <- {from}");
}
}
}
}
print!("}}\n");
println!("}}");
}
74 changes: 47 additions & 27 deletions src/cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,19 @@

//! Lightweight CFG analyses.

use crate::{domtree, postorder, Block, Function, Inst, ProgPoint, RegAllocError};
use alloc::vec;
use alloc::vec::Vec;
use crate::alloc::vec::Vec;

use crate::{domtree, postorder, Block, Function, Inst, ProgPoint, RegAllocError, VecExt};
use smallvec::{smallvec, SmallVec};

#[derive(Clone, Debug)]
#[derive(Debug, Default)]
pub struct CFGInfoCtx {
visited: Vec<bool>,
block_to_rpo: Vec<Option<u32>>,
backedge: Vec<u32>,
}

#[derive(Debug, Default)]
pub struct CFGInfo {
/// Postorder traversal of blocks.
pub postorder: Vec<Block>,
Expand All @@ -33,21 +40,41 @@ pub struct CFGInfo {
}

impl CFGInfo {
pub fn new<F: Function>(f: &F) -> Result<CFGInfo, RegAllocError> {
let postorder = postorder::calculate(f.num_blocks(), f.entry_block(), |block| {
f.block_succs(block)
});
let domtree = domtree::calculate(
f.num_blocks(),
pub fn new<F: Function>(f: &F) -> Result<Self, RegAllocError> {
let mut ctx = CFGInfoCtx::default();
let mut this = Self::default();
this.init(f, &mut ctx)?;
Ok(this)
}

pub fn init<F: Function>(&mut self, f: &F, ctx: &mut CFGInfoCtx) -> Result<(), RegAllocError> {
let nb = f.num_blocks();

postorder::calculate(
nb,
f.entry_block(),
&mut ctx.visited,
&mut self.postorder,
|block| f.block_succs(block),
);

domtree::calculate(
nb,
|block| f.block_preds(block),
&postorder[..],
&self.postorder,
&mut ctx.block_to_rpo,
&mut self.domtree,
f.entry_block(),
);
let mut insn_block = vec![Block::invalid(); f.num_insts()];
let mut block_entry = vec![ProgPoint::before(Inst::invalid()); f.num_blocks()];
let mut block_exit = vec![ProgPoint::before(Inst::invalid()); f.num_blocks()];
let mut backedge_in = vec![0; f.num_blocks()];
let mut backedge_out = vec![0; f.num_blocks()];

let insn_block = self.insn_block.repopulate(f.num_insts(), Block::invalid());
let block_entry = self
.block_entry
.repopulate(nb, ProgPoint::before(Inst::invalid()));
let block_exit = self
.block_exit
.repopulate(nb, ProgPoint::before(Inst::invalid()));
let (backedge_in, backedge_out) = ctx.backedge.repopulate(nb * 2, 0).split_at_mut(nb);

for block in 0..f.num_blocks() {
let block = Block::new(block);
Expand Down Expand Up @@ -98,10 +125,10 @@ impl CFGInfo {
}
}

let mut approx_loop_depth = vec![];
let mut backedge_stack: SmallVec<[usize; 4]> = smallvec![];
let approx_loop_depth = self.approx_loop_depth.cleared();
let mut backedge_stack: SmallVec<[u32; 4]> = smallvec![];
let mut cur_depth = 0;
for block in 0..f.num_blocks() {
for block in 0..nb {
if backedge_in[block] > 0 {
cur_depth += 1;
backedge_stack.push(backedge_in[block]);
Expand All @@ -119,14 +146,7 @@ impl CFGInfo {
}
}

Ok(CFGInfo {
postorder,
domtree,
insn_block,
block_entry,
block_exit,
approx_loop_depth,
})
Ok(())
}

pub fn dominates(&self, a: Block, b: Block) -> bool {
Expand Down
20 changes: 9 additions & 11 deletions src/domtree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@
// TR-06-33870
// https://www.cs.rice.edu/~keith/EMBED/dom.pdf

use alloc::vec;
use core::u32;

use alloc::vec::Vec;

use crate::Block;
use crate::{Block, VecExt};

// Helper
fn merge_sets(
Expand Down Expand Up @@ -44,19 +45,18 @@ pub fn calculate<'a, PredFn: Fn(Block) -> &'a [Block]>(
num_blocks: usize,
preds: PredFn,
post_ord: &[Block],
block_to_rpo_scratch: &mut Vec<Option<u32>>,
out: &mut Vec<Block>,
start: Block,
) -> Vec<Block> {
) {
// We have post_ord, which is the postorder sequence.

// Compute maps from RPO to block number and vice-versa.
let mut block_to_rpo = vec![None; num_blocks];
block_to_rpo.resize(num_blocks, None);
let block_to_rpo = block_to_rpo_scratch.repopulate(num_blocks, None);
for (i, rpo_block) in post_ord.iter().rev().enumerate() {
block_to_rpo[rpo_block.index()] = Some(i as u32);
}

let mut idom = vec![Block::invalid(); num_blocks];

let idom = out.repopulate(num_blocks, Block::invalid());
// The start node must have itself as a parent.
idom[start.index()] = start;

Expand All @@ -70,11 +70,11 @@ pub fn calculate<'a, PredFn: Fn(Block) -> &'a [Block]>(
let mut parent = Block::invalid();
for &pred in preds(node).iter() {
let pred_rpo = match block_to_rpo[pred.index()] {
Some(r) => r,
None => {
// Skip unreachable preds.
continue;
}
Some(r) => r,
};
if pred_rpo < rponum {
parent = pred;
Expand Down Expand Up @@ -104,8 +104,6 @@ pub fn calculate<'a, PredFn: Fn(Block) -> &'a [Block]>(
// Now set the start node's dominator-tree parent to "invalid";
// this allows the loop in `dominates` to terminate.
idom[start.index()] = Block::invalid();

idom
}

pub fn dominates(idom: &[Block], a: Block, mut b: Block) -> bool {
Expand Down
7 changes: 3 additions & 4 deletions src/fastalloc/lru.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
use crate::{PReg, PRegSet, RegClass};
use crate::{FxHashSet, PReg, PRegSet, RegClass};
use alloc::vec;
use alloc::vec::Vec;
use core::{
fmt,
ops::{Index, IndexMut},
};
use hashbrown::HashSet;

/// A least-recently-used cache organized as a linked list based on a vector.
pub struct Lru {
Expand Down Expand Up @@ -193,7 +192,7 @@ impl Lru {
);
if self.head != u8::MAX {
let mut node = self.data[self.head as usize].next;
let mut seen = HashSet::new();
let mut seen = FxHashSet::default();
while node != self.head {
if seen.contains(&node) {
panic!(
Expand Down Expand Up @@ -245,7 +244,7 @@ impl fmt::Debug for Lru {
} else {
let mut data_str = format!("p{}", self.head);
let mut node = self.data[self.head as usize].next;
let mut seen = HashSet::new();
let mut seen = FxHashSet::default();
while node != self.head {
if seen.contains(&node) {
panic!(
Expand Down
15 changes: 6 additions & 9 deletions src/fastalloc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use crate::moves::{MoveAndScratchResolver, ParallelMoves};
use crate::{cfg::CFGInfo, ion::Stats, Allocation, RegAllocError};
use crate::{ssa::validate_ssa, Edit, Function, MachineEnv, Output, ProgPoint};
use crate::{
AllocationKind, Block, Inst, InstPosition, Operand, OperandConstraint, OperandKind, OperandPos,
PReg, PRegSet, RegClass, SpillSlot, VReg,
AllocationKind, Block, FxHashMap, Inst, InstPosition, Operand, OperandConstraint, OperandKind,
OperandPos, PReg, PRegSet, RegClass, SpillSlot, VReg,
};
use alloc::vec::Vec;
use core::convert::TryInto;
Expand Down Expand Up @@ -1150,17 +1150,16 @@ impl<'a, F: Function> Env<'a, F> {

fn log_post_reload_at_begin_state(&self, block: Block) {
use alloc::format;
use hashbrown::HashMap;
trace!("");
trace!("State after instruction reload_at_begin of {:?}", block);
let mut map = HashMap::new();
let mut map = FxHashMap::default();
for (vreg_idx, alloc) in self.vreg_allocs.iter().enumerate() {
if *alloc != Allocation::none() {
map.insert(format!("vreg{vreg_idx}"), alloc);
}
}
trace!("vreg_allocs: {:?}", map);
let mut map = HashMap::new();
let mut map = FxHashMap::default();
for i in 0..self.vreg_in_preg.len() {
if self.vreg_in_preg[i] != VReg::invalid() {
map.insert(PReg::from_index(i), self.vreg_in_preg[i]);
Expand All @@ -1174,10 +1173,9 @@ impl<'a, F: Function> Env<'a, F> {

fn log_post_inst_processing_state(&self, inst: Inst) {
use alloc::format;
use hashbrown::HashMap;
trace!("");
trace!("State after instruction {:?}", inst);
let mut map = HashMap::new();
let mut map = FxHashMap::default();
for (vreg_idx, alloc) in self.vreg_allocs.iter().enumerate() {
if *alloc != Allocation::none() {
map.insert(format!("vreg{vreg_idx}"), alloc);
Expand Down Expand Up @@ -1289,8 +1287,7 @@ pub fn run<F: Function>(
enable_ssa_checker: bool,
) -> Result<Output, RegAllocError> {
if enable_ssa_checker {
let cfginfo = CFGInfo::new(func)?;
validate_ssa(func, &cfginfo)?;
validate_ssa(func, &CFGInfo::new(func)?)?;
}

if trace_enabled!() || verbose_log {
Expand Down
Loading
Loading