Skip to content

Commit

Permalink
Add regalloc2-tool (#148)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Amanieu authored Jul 12, 2023
1 parent 62333e9 commit 24c0517
Show file tree
Hide file tree
Showing 7 changed files with 436 additions and 2 deletions.
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[workspace]
members = ["regalloc2-tool"]

[package]
name = "regalloc2"
version = "0.9.1"
Expand Down
4 changes: 2 additions & 2 deletions deny.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ targets = [
vulnerability = "deny"
unmaintained = "deny"
yanked = "deny"
ignore = [
]
ignore = []

# https://embarkstudios.github.io/cargo-deny/checks/licenses/cfg.html
[licenses]
allow = [
"Apache-2.0 WITH LLVM-exception",
"Apache-2.0",
"MIT",
"Unicode-DFS-2016",
]

# https://embarkstudios.github.io/cargo-deny/checks/bans/cfg.html
Expand Down
18 changes: 18 additions & 0 deletions regalloc2-tool/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[package]
name = "regalloc2-tool"
authors = [
"Chris Fallin <chris@cfallin.org>",
"Mozilla SpiderMonkey Developers",
]
version = "0.0.0"
edition = "2021"
publish = false
license = "Apache-2.0 WITH LLVM-exception"
description = "Tool for testing regalloc2"
repository = "https://github.com/bytecodealliance/regalloc2"

[dependencies]
bincode = "1.3.3"
clap = { version = "4.3.11", features = ["derive"] }
pretty_env_logger = "0.5.0"
regalloc2 = { path = "..", features = ["trace-log", "enable-serde"] }
95 changes: 95 additions & 0 deletions regalloc2-tool/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
use std::path::PathBuf;

use clap::Parser;
use regalloc2::{
checker::Checker, serialize::SerializableFunction, Block, Edit, Function, InstOrEdit, Output,
RegallocOptions,
};

#[derive(Parser)]
/// Tool for testing regalloc2.
struct Args {
/// Print the input function and the result of register allocation.
#[clap(short = 'v')]
verbose: bool,

/// Input file containing a bincode-encoded SerializedFunction.
input: PathBuf,
}

fn main() {
pretty_env_logger::init();
let args = Args::parse();

let input = std::fs::read(&args.input).expect("could not read input file");
let function: SerializableFunction =
bincode::deserialize(&input).expect("could not deserialize input file");

if args.verbose {
println!("Input function: {function:?}");
}

let options = RegallocOptions {
verbose_log: true,
validate_ssa: true,
};
let output = match regalloc2::run(&function, function.machine_env(), &options) {
Ok(output) => output,
Err(e) => {
panic!("Register allocation failed: {e:#?}");
}
};

if args.verbose {
print_output(&function, &output);
}

let mut checker = Checker::new(&function, function.machine_env());
checker.prepare(&output);
if let Err(e) = checker.run() {
panic!("Regsiter allocation checker failed: {e:#?}");
}
}

fn print_output(func: &SerializableFunction, output: &Output) {
print!("Register allocation result: {{\n");
for i in 0..func.num_blocks() {
let block = Block::new(i);
let succs = func
.block_succs(block)
.iter()
.map(|b| b.index())
.collect::<Vec<_>>();
let preds = func
.block_preds(block)
.iter()
.map(|b| b.index())
.collect::<Vec<_>>();
print!(" block{}: # succs:{:?} preds:{:?}\n", i, succs, preds);
for inst_or_edit in output.block_insts_and_edits(func, block) {
match inst_or_edit {
InstOrEdit::Inst(inst) => {
let op = if func.is_ret(inst) {
"ret"
} else if func.is_branch(inst) {
"branch"
} else {
"op"
};
let ops: Vec<_> = func
.inst_operands(inst)
.iter()
.zip(output.inst_allocs(inst))
.map(|(op, alloc)| format!("{op} => {alloc}"))
.collect();
let ops = ops.join(", ");
print!(" inst{}: {op} {ops}\n", inst.index(),);
}
InstOrEdit::Edit(Edit::Move { from, to }) => {
print!(" edit: move {to} <- {from}\n");
}
}
}
}
print!("}}\n");
}
4 changes: 4 additions & 0 deletions src/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,10 @@ define_index!(Inst);
define_index!(Block);

#[derive(Clone, Copy, Debug)]
#[cfg_attr(
feature = "enable-serde",
derive(::serde::Serialize, ::serde::Deserialize)
)]
pub struct InstRange(Inst, Inst, bool);

impl InstRange {
Expand Down
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ pub mod checker;
#[cfg(feature = "fuzzing")]
pub mod fuzzing;

#[cfg(feature = "enable-serde")]
pub mod serialize;

#[cfg(feature = "enable-serde")]
use serde::{Deserialize, Serialize};

Expand Down
Loading

0 comments on commit 24c0517

Please sign in to comment.