Skip to content

Commit 895c11a

Browse files
committed
Add regalloc2-tool
This PR has 2 components: - A `SerializableFunction` which wraps a `Function` and `MachineEnv`. This type can be serialized and deserialized with Serde, and is enabled by the "enable-serde" feature. - A `regalloc2-tool` binary which reads a bincode-encoded `SerializableFunction` and then runs the register allocator and checker on it. This is a useful tool for debugging register allocation failures and to investigate cases of poor register allocation.
1 parent 62333e9 commit 895c11a

File tree

7 files changed

+436
-2
lines changed

7 files changed

+436
-2
lines changed

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
[workspace]
2+
members = ["regalloc2-tool"]
3+
14
[package]
25
name = "regalloc2"
36
version = "0.9.1"

deny.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@ targets = [
1010
vulnerability = "deny"
1111
unmaintained = "deny"
1212
yanked = "deny"
13-
ignore = [
14-
]
13+
ignore = []
1514

1615
# https://embarkstudios.github.io/cargo-deny/checks/licenses/cfg.html
1716
[licenses]
1817
allow = [
1918
"Apache-2.0 WITH LLVM-exception",
2019
"Apache-2.0",
2120
"MIT",
21+
"Unicode-DFS-2016",
2222
]
2323

2424
# https://embarkstudios.github.io/cargo-deny/checks/bans/cfg.html

regalloc2-tool/Cargo.toml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
[package]
2+
name = "regalloc2-tool"
3+
authors = [
4+
"Chris Fallin <[email protected]>",
5+
"Mozilla SpiderMonkey Developers",
6+
]
7+
version = "0.0.0"
8+
edition = "2021"
9+
publish = false
10+
license = "Apache-2.0 WITH LLVM-exception"
11+
description = "Tool for testing regalloc2"
12+
repository = "https://github.com/bytecodealliance/regalloc2"
13+
14+
[dependencies]
15+
bincode = "1.3.3"
16+
clap = { version = "4.3.11", features = ["derive"] }
17+
pretty_env_logger = "0.5.0"
18+
regalloc2 = { path = "..", features = ["trace-log", "enable-serde"] }

regalloc2-tool/src/main.rs

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
use std::path::PathBuf;
2+
3+
use clap::Parser;
4+
use regalloc2::{
5+
checker::Checker, serialize::SerializableFunction, Block, Edit, Function, InstOrEdit, Output,
6+
RegallocOptions,
7+
};
8+
9+
#[derive(Parser)]
10+
/// Tool for testing regalloc2.
11+
struct Args {
12+
/// Print the input function and the result of register allocation.
13+
#[clap(short = 'v')]
14+
verbose: bool,
15+
16+
/// Input file containing a bincode-encoded SerializedFunction.
17+
input: PathBuf,
18+
}
19+
20+
fn main() {
21+
pretty_env_logger::init();
22+
let args = Args::parse();
23+
24+
let input = std::fs::read(&args.input).expect("could not read input file");
25+
let function: SerializableFunction =
26+
bincode::deserialize(&input).expect("could not deserialize input file");
27+
28+
if args.verbose {
29+
println!("Input function: {function:?}");
30+
}
31+
32+
let options = RegallocOptions {
33+
verbose_log: true,
34+
validate_ssa: true,
35+
};
36+
let output = match regalloc2::run(&function, function.machine_env(), &options) {
37+
Ok(output) => output,
38+
Err(e) => {
39+
panic!("Register allocation failed: {e:#?}");
40+
}
41+
};
42+
43+
if args.verbose {
44+
print_output(&function, &output);
45+
}
46+
47+
let mut checker = Checker::new(&function, function.machine_env());
48+
checker.prepare(&output);
49+
if let Err(e) = checker.run() {
50+
panic!("Regsiter allocation checker failed: {e:#?}");
51+
}
52+
}
53+
54+
fn print_output(func: &SerializableFunction, output: &Output) {
55+
print!("Register allocation result: {{\n");
56+
for i in 0..func.num_blocks() {
57+
let block = Block::new(i);
58+
let succs = func
59+
.block_succs(block)
60+
.iter()
61+
.map(|b| b.index())
62+
.collect::<Vec<_>>();
63+
let preds = func
64+
.block_preds(block)
65+
.iter()
66+
.map(|b| b.index())
67+
.collect::<Vec<_>>();
68+
print!(" block{}: # succs:{:?} preds:{:?}\n", i, succs, preds);
69+
for inst_or_edit in output.block_insts_and_edits(func, block) {
70+
match inst_or_edit {
71+
InstOrEdit::Inst(inst) => {
72+
let op = if func.is_ret(inst) {
73+
"ret"
74+
} else if func.is_branch(inst) {
75+
"branch"
76+
} else {
77+
"op"
78+
};
79+
let ops: Vec<_> = func
80+
.inst_operands(inst)
81+
.iter()
82+
.zip(output.inst_allocs(inst))
83+
.map(|(op, alloc)| format!("{op} => {alloc}"))
84+
.collect();
85+
let ops = ops.join(", ");
86+
print!(" inst{}: {op} {ops}\n", inst.index(),);
87+
}
88+
InstOrEdit::Edit(Edit::Move { from, to }) => {
89+
print!(" edit: move {to} <- {from}\n");
90+
}
91+
}
92+
}
93+
}
94+
print!("}}\n");
95+
}

src/index.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,10 @@ define_index!(Inst);
137137
define_index!(Block);
138138

139139
#[derive(Clone, Copy, Debug)]
140+
#[cfg_attr(
141+
feature = "enable-serde",
142+
derive(::serde::Serialize, ::serde::Deserialize)
143+
)]
140144
pub struct InstRange(Inst, Inst, bool);
141145

142146
impl InstRange {

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ pub mod checker;
5858
#[cfg(feature = "fuzzing")]
5959
pub mod fuzzing;
6060

61+
#[cfg(feature = "enable-serde")]
62+
pub mod serialize;
63+
6164
#[cfg(feature = "enable-serde")]
6265
use serde::{Deserialize, Serialize};
6366

0 commit comments

Comments
 (0)