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.
|
//! 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};
|
use smallvec::{smallvec, SmallVec};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
@@ -16,12 +16,6 @@ pub struct CFGInfo {
|
|||||||
pub domtree: Vec<Block>,
|
pub domtree: Vec<Block>,
|
||||||
/// For each instruction, the block it belongs to.
|
/// For each instruction, the block it belongs to.
|
||||||
pub insn_block: Vec<Block>,
|
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.
|
/// For each block, the first instruction.
|
||||||
pub block_entry: Vec<ProgPoint>,
|
pub block_entry: Vec<ProgPoint>,
|
||||||
/// For each block, the last instruction.
|
/// For each block, the last instruction.
|
||||||
@@ -48,8 +42,6 @@ impl CFGInfo {
|
|||||||
f.entry_block(),
|
f.entry_block(),
|
||||||
);
|
);
|
||||||
let mut insn_block = vec![Block::invalid(); f.num_insts()];
|
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_entry = vec![ProgPoint::before(Inst::invalid()); f.num_blocks()];
|
||||||
let mut block_exit = 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_in = vec![0; f.num_blocks()];
|
||||||
@@ -57,19 +49,8 @@ impl CFGInfo {
|
|||||||
|
|
||||||
for block in 0..f.num_blocks() {
|
for block in 0..f.num_blocks() {
|
||||||
let block = Block::new(block);
|
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 inst in f.block_insns(block).iter() {
|
||||||
insn_block[inst.index()] = block;
|
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_entry[block.index()] = ProgPoint::before(f.block_insns(block).first());
|
||||||
block_exit[block.index()] = ProgPoint::after(f.block_insns(block).last());
|
block_exit[block.index()] = ProgPoint::after(f.block_insns(block).last());
|
||||||
@@ -139,8 +120,6 @@ impl CFGInfo {
|
|||||||
postorder,
|
postorder,
|
||||||
domtree,
|
domtree,
|
||||||
insn_block,
|
insn_block,
|
||||||
vreg_def_inst,
|
|
||||||
vreg_def_blockparam,
|
|
||||||
block_entry,
|
block_entry,
|
||||||
block_exit,
|
block_exit,
|
||||||
approx_loop_depth,
|
approx_loop_depth,
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
//! Utilities for fuzzing.
|
//! Utilities for fuzzing.
|
||||||
|
|
||||||
pub mod func;
|
pub mod func;
|
||||||
|
pub mod ssa;
|
||||||
|
|
||||||
// Re-exports for fuzz targets.
|
// Re-exports for fuzz targets.
|
||||||
|
|
||||||
@@ -21,9 +22,6 @@ pub mod moves {
|
|||||||
pub mod cfg {
|
pub mod cfg {
|
||||||
pub use crate::cfg::*;
|
pub use crate::cfg::*;
|
||||||
}
|
}
|
||||||
pub mod ssa {
|
|
||||||
pub use crate::ssa::*;
|
|
||||||
}
|
|
||||||
pub mod ion {
|
pub mod ion {
|
||||||
pub use crate::ion::*;
|
pub use crate::ion::*;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,30 @@ use crate::cfg::CFGInfo;
|
|||||||
use crate::{Block, Function, Inst, OperandKind, RegAllocError};
|
use crate::{Block, Function, Inst, OperandKind, RegAllocError};
|
||||||
|
|
||||||
pub fn validate_ssa<F: Function>(f: &F, cfginfo: &CFGInfo) -> Result<(), 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
|
// 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
|
// the def is either in the same block in an earlier inst, or is
|
||||||
// defined (by inst or blockparam) in some other block that
|
// 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 {
|
for operand in operands {
|
||||||
match operand.kind() {
|
match operand.kind() {
|
||||||
OperandKind::Use => {
|
OperandKind::Use => {
|
||||||
let def_block = if cfginfo.vreg_def_inst[operand.vreg().vreg()].is_valid() {
|
let def_block = if vreg_def_inst[operand.vreg().vreg()].is_valid() {
|
||||||
cfginfo.insn_block[cfginfo.vreg_def_inst[operand.vreg().vreg()].index()]
|
cfginfo.insn_block[vreg_def_inst[operand.vreg().vreg()].index()]
|
||||||
} else {
|
} else {
|
||||||
cfginfo.vreg_def_blockparam[operand.vreg().vreg()].0
|
vreg_def_blockparam[operand.vreg().vreg()].0
|
||||||
};
|
};
|
||||||
if def_block.is_invalid() {
|
if def_block.is_invalid() {
|
||||||
return Err(RegAllocError::SSA(operand.vreg(), iix));
|
return Err(RegAllocError::SSA(operand.vreg(), iix));
|
||||||
@@ -34,7 +34,6 @@ pub mod indexset;
|
|||||||
pub(crate) mod ion;
|
pub(crate) mod ion;
|
||||||
pub(crate) mod moves;
|
pub(crate) mod moves;
|
||||||
pub(crate) mod postorder;
|
pub(crate) mod postorder;
|
||||||
pub(crate) mod ssa;
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod index;
|
mod index;
|
||||||
|
|||||||
Reference in New Issue
Block a user