Only record vreg definitions when fuzzing (#66)
The `vreg_def_blockparam` and `vreg_def_inst` fields on CFGInfo are only used in `validate_ssa`, which in turn is only used in the ssagen fuzz target. Since these fields are never read in normal usage, initializing them is entirely wasted effort. According to valgrind/DHAT, when running `wasmtime compile` on the Sightglass Spidermonkey benchmark, removing these fields saves about 100M instructions, 23k heap allocations totalling 40MiB, and 47MiB of writes to the heap.
This commit is contained in:
23
src/cfg.rs
23
src/cfg.rs
@@ -5,7 +5,7 @@
|
||||
|
||||
//! Lightweight CFG analyses.
|
||||
|
||||
use crate::{domtree, postorder, Block, Function, Inst, OperandKind, ProgPoint, RegAllocError};
|
||||
use crate::{domtree, postorder, Block, Function, Inst, ProgPoint, RegAllocError};
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@@ -16,12 +16,6 @@ pub struct CFGInfo {
|
||||
pub domtree: Vec<Block>,
|
||||
/// For each instruction, the block it belongs to.
|
||||
pub insn_block: Vec<Block>,
|
||||
/// For each vreg, the instruction that defines it, if any.
|
||||
pub vreg_def_inst: Vec<Inst>,
|
||||
/// For each vreg, the block that defines it as a blockparam, if
|
||||
/// any. (Every vreg must have a valid entry in either
|
||||
/// `vreg_def_inst` or `vreg_def_blockparam`.)
|
||||
pub vreg_def_blockparam: Vec<(Block, u32)>,
|
||||
/// For each block, the first instruction.
|
||||
pub block_entry: Vec<ProgPoint>,
|
||||
/// For each block, the last instruction.
|
||||
@@ -48,8 +42,6 @@ impl CFGInfo {
|
||||
f.entry_block(),
|
||||
);
|
||||
let mut insn_block = vec![Block::invalid(); f.num_insts()];
|
||||
let mut vreg_def_inst = vec![Inst::invalid(); f.num_vregs()];
|
||||
let mut vreg_def_blockparam = vec![(Block::invalid(), 0); f.num_vregs()];
|
||||
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()];
|
||||
@@ -57,19 +49,8 @@ impl CFGInfo {
|
||||
|
||||
for block in 0..f.num_blocks() {
|
||||
let block = Block::new(block);
|
||||
for (i, param) in f.block_params(block).iter().enumerate() {
|
||||
vreg_def_blockparam[param.vreg()] = (block, i as u32);
|
||||
}
|
||||
for inst in f.block_insns(block).iter() {
|
||||
insn_block[inst.index()] = block;
|
||||
for operand in f.inst_operands(inst) {
|
||||
match operand.kind() {
|
||||
OperandKind::Def => {
|
||||
vreg_def_inst[operand.vreg().vreg()] = inst;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
block_entry[block.index()] = ProgPoint::before(f.block_insns(block).first());
|
||||
block_exit[block.index()] = ProgPoint::after(f.block_insns(block).last());
|
||||
@@ -139,8 +120,6 @@ impl CFGInfo {
|
||||
postorder,
|
||||
domtree,
|
||||
insn_block,
|
||||
vreg_def_inst,
|
||||
vreg_def_blockparam,
|
||||
block_entry,
|
||||
block_exit,
|
||||
approx_loop_depth,
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
//! Utilities for fuzzing.
|
||||
|
||||
pub mod func;
|
||||
pub mod ssa;
|
||||
|
||||
// Re-exports for fuzz targets.
|
||||
|
||||
@@ -21,9 +22,6 @@ pub mod moves {
|
||||
pub mod cfg {
|
||||
pub use crate::cfg::*;
|
||||
}
|
||||
pub mod ssa {
|
||||
pub use crate::ssa::*;
|
||||
}
|
||||
pub mod ion {
|
||||
pub use crate::ion::*;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,30 @@ use crate::cfg::CFGInfo;
|
||||
use crate::{Block, Function, Inst, OperandKind, RegAllocError};
|
||||
|
||||
pub fn validate_ssa<F: Function>(f: &F, cfginfo: &CFGInfo) -> Result<(), RegAllocError> {
|
||||
// For each vreg, the instruction that defines it, if any.
|
||||
let mut vreg_def_inst = vec![Inst::invalid(); f.num_vregs()];
|
||||
// For each vreg, the block that defines it as a blockparam, if
|
||||
// any. (Every vreg must have a valid entry in either
|
||||
// `vreg_def_inst` or `vreg_def_blockparam`.)
|
||||
let mut vreg_def_blockparam = vec![(Block::invalid(), 0); f.num_vregs()];
|
||||
|
||||
for block in 0..f.num_blocks() {
|
||||
let block = Block::new(block);
|
||||
for (i, param) in f.block_params(block).iter().enumerate() {
|
||||
vreg_def_blockparam[param.vreg()] = (block, i as u32);
|
||||
}
|
||||
for inst in f.block_insns(block).iter() {
|
||||
for operand in f.inst_operands(inst) {
|
||||
match operand.kind() {
|
||||
OperandKind::Def => {
|
||||
vreg_def_inst[operand.vreg().vreg()] = inst;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Walk the blocks in arbitrary order. Check, for every use, that
|
||||
// the def is either in the same block in an earlier inst, or is
|
||||
// defined (by inst or blockparam) in some other block that
|
||||
@@ -29,10 +53,10 @@ pub fn validate_ssa<F: Function>(f: &F, cfginfo: &CFGInfo) -> Result<(), RegAllo
|
||||
for operand in operands {
|
||||
match operand.kind() {
|
||||
OperandKind::Use => {
|
||||
let def_block = if cfginfo.vreg_def_inst[operand.vreg().vreg()].is_valid() {
|
||||
cfginfo.insn_block[cfginfo.vreg_def_inst[operand.vreg().vreg()].index()]
|
||||
let def_block = if vreg_def_inst[operand.vreg().vreg()].is_valid() {
|
||||
cfginfo.insn_block[vreg_def_inst[operand.vreg().vreg()].index()]
|
||||
} else {
|
||||
cfginfo.vreg_def_blockparam[operand.vreg().vreg()].0
|
||||
vreg_def_blockparam[operand.vreg().vreg()].0
|
||||
};
|
||||
if def_block.is_invalid() {
|
||||
return Err(RegAllocError::SSA(operand.vreg(), iix));
|
||||
@@ -34,7 +34,6 @@ pub mod indexset;
|
||||
pub(crate) mod ion;
|
||||
pub(crate) mod moves;
|
||||
pub(crate) mod postorder;
|
||||
pub(crate) mod ssa;
|
||||
|
||||
#[macro_use]
|
||||
mod index;
|
||||
|
||||
Reference in New Issue
Block a user