Make DataFlowGraph::insts public, but restricted (#5450)

We have some operations defined on DataFlowGraph purely to work around borrow-checker issues with InstructionData and other data on DataFlowGraph. Part of the problem is that indexing the DFG directly hides the fact that we're only indexing the insts field of the DFG.

This PR makes the insts field of the DFG public, but wraps it in a newtype that only allows indexing. This means that the borrow checker is better able to tell when operations on memory held by the DFG won't conflict, which comes up frequently when mutating ValueLists held by InstructionData.
This commit is contained in:
Trevor Elliott
2022-12-16 10:46:09 -08:00
committed by GitHub
parent 6323b0f9f4
commit 25bf8e0e67
31 changed files with 182 additions and 178 deletions

View File

@@ -158,8 +158,8 @@ fn gen_arguments_method(formats: &[&InstructionFormat], fmt: &mut Formatter, is_
/// - `pub fn opcode(&self) -> Opcode`
/// - `pub fn arguments(&self, &pool) -> &[Value]`
/// - `pub fn arguments_mut(&mut self, &pool) -> &mut [Value]`
/// - `pub fn take_value_list(&mut self) -> Option<ir::ValueList>`
/// - `pub fn put_value_list(&mut self, args: ir::ValueList>`
/// - `pub fn value_list(&self) -> Option<ir::ValueList>`
/// - `pub fn value_list_mut(&mut self) -> Option<&mut ir::ValueList>`
/// - `pub fn eq(&self, &other: Self, &pool) -> bool`
/// - `pub fn hash<H: Hasher>(&self, state: &mut H, &pool)`
fn gen_instruction_data_impl(formats: &[&InstructionFormat], fmt: &mut Formatter) {
@@ -214,21 +214,17 @@ fn gen_instruction_data_impl(formats: &[&InstructionFormat], fmt: &mut Formatter
fmt.empty_line();
fmt.doc_comment(r#"
Take out the value list with all the value arguments and return
it.
This leaves the value list in the instruction empty. Use
`put_value_list` to put the value list back.
The ValueList for the instruction.
"#);
fmt.line("pub fn take_value_list(&mut self) -> Option<ir::ValueList> {");
fmt.line("pub fn value_list(&self) -> Option<ir::ValueList> {");
fmt.indent(|fmt| {
let mut m = Match::new("*self");
for format in formats {
if format.has_value_list {
m.arm(format!("Self::{}", format.name),
vec!["ref mut args", ".."],
"Some(args.take())".to_string());
vec!["args", ".."],
"Some(args)".to_string());
}
}
@@ -240,27 +236,24 @@ fn gen_instruction_data_impl(formats: &[&InstructionFormat], fmt: &mut Formatter
fmt.empty_line();
fmt.doc_comment(r#"
Put back a value list.
After removing a value list with `take_value_list()`, use this
method to put it back. It is required that this instruction has
a format that accepts a value list, and that the existing value
list is empty. This avoids leaking list pool memory.
A mutable reference to the ValueList for this instruction, if it
has one.
"#);
fmt.line("pub fn put_value_list(&mut self, vlist: ir::ValueList) {");
fmt.line("pub fn value_list_mut(&mut self) -> Option<&mut ir::ValueList> {");
fmt.indent(|fmt| {
fmt.line("let args = match *self {");
fmt.indent(|fmt| {
for format in formats {
if format.has_value_list {
fmtln!(fmt, "Self::{} {{ ref mut args, .. }} => args,", format.name);
}
let mut m = Match::new("*self");
for format in formats {
if format.has_value_list {
m.arm(format!("Self::{}", format.name),
vec!["ref mut args", ".."],
"Some(args)".to_string());
}
fmt.line("_ => panic!(\"No value list: {:?}\", self),");
});
fmt.line("};");
fmt.line("debug_assert!(args.is_empty(), \"Value list already in use\");");
fmt.line("*args = vlist;");
}
m.arm_no_fields("_", "None");
fmt.add_match(m);
});
fmt.line("}");
fmt.empty_line();

View File

@@ -85,14 +85,14 @@ pub struct LastStores {
impl LastStores {
fn update(&mut self, func: &Function, inst: Inst) {
let opcode = func.dfg[inst].opcode();
let opcode = func.dfg.insts[inst].opcode();
if has_memory_fence_semantics(opcode) {
self.heap = inst.into();
self.table = inst.into();
self.vmctx = inst.into();
self.other = inst.into();
} else if opcode.can_store() {
if let Some(memflags) = func.dfg[inst].memflags() {
if let Some(memflags) = func.dfg.insts[inst].memflags() {
if memflags.heap() {
self.heap = inst.into();
} else if memflags.table() {
@@ -112,7 +112,7 @@ impl LastStores {
}
fn get_last_store(&self, func: &Function, inst: Inst) -> PackedOption<Inst> {
if let Some(memflags) = func.dfg[inst].memflags() {
if let Some(memflags) = func.dfg.insts[inst].memflags() {
if memflags.heap() {
self.heap
} else if memflags.table() {
@@ -122,7 +122,9 @@ impl LastStores {
} else {
self.other
}
} else if func.dfg[inst].opcode().can_load() || func.dfg[inst].opcode().can_store() {
} else if func.dfg.insts[inst].opcode().can_load()
|| func.dfg.insts[inst].opcode().can_store()
{
inst.into()
} else {
PackedOption::default()
@@ -277,13 +279,13 @@ impl<'a> AliasAnalysis<'a> {
"alias analysis: scanning at inst{} with state {:?} ({:?})",
inst.index(),
state,
func.dfg[inst],
func.dfg.insts[inst],
);
let replacing_value = if let Some((address, offset, ty)) = inst_addr_offset_type(func, inst)
{
let address = func.dfg.resolve_aliases(address);
let opcode = func.dfg[inst].opcode();
let opcode = func.dfg.insts[inst].opcode();
if opcode.can_store() {
let store_data = inst_store_data(func, inst).unwrap();

View File

@@ -641,9 +641,9 @@ impl<'c, 'f> ir::InstInserterBase<'c> for &'c mut FuncCursor<'f> {
if let CursorPosition::At(_) = self.position() {
if let Some(curr) = self.current_inst() {
if let Some(prev) = self.layout().prev_inst(curr) {
let prev_op = self.data_flow_graph()[prev].opcode();
let inst_op = self.data_flow_graph()[inst].opcode();
let curr_op = self.data_flow_graph()[curr].opcode();
let prev_op = self.data_flow_graph().insts[prev].opcode();
let inst_op = self.data_flow_graph().insts[inst].opcode();
let curr_op = self.data_flow_graph().insts[curr].opcode();
if prev_op.is_branch()
&& !prev_op.is_terminator()
&& !inst_op.is_terminator()

View File

@@ -102,7 +102,7 @@ impl NewOrExistingInst {
NewOrExistingInst::New(data, ty) => (*ty, *data),
NewOrExistingInst::Existing(inst) => {
let ty = dfg.ctrl_typevar(*inst);
(ty, dfg[*inst].clone())
(ty, dfg.insts[*inst].clone())
}
}
}
@@ -191,8 +191,11 @@ where
union_find: self.eclasses,
value_lists: &self.func.dfg.value_lists,
};
self.gvn_map
.insert((ty, self.func.dfg[inst].clone()), opt_value, &gvn_context);
self.gvn_map.insert(
(ty, self.func.dfg.insts[inst].clone()),
opt_value,
&gvn_context,
);
self.value_to_opt_value[result] = opt_value;
opt_value
}
@@ -335,7 +338,7 @@ impl<'a> EgraphPass<'a> {
trace!(" -> {} = {:?}", value, def);
match def {
ValueDef::Result(i, 0) => {
trace!(" -> {} = {:?}", i, self.func.dfg[i]);
trace!(" -> {} = {:?}", i, self.func.dfg.insts[i]);
}
_ => {}
}

View File

@@ -218,7 +218,7 @@ impl<'a> Elaborator<'a> {
}
ValueDef::Result(inst, _) => {
trace!(" -> value {}: result, computing cost", value);
let inst_data = &self.func.dfg[inst];
let inst_data = &self.func.dfg.insts[inst];
let loop_level = self
.func
.layout
@@ -358,7 +358,7 @@ impl<'a> Elaborator<'a> {
trace!(
" -> result {} of inst {:?}",
result_idx,
self.func.dfg[inst]
self.func.dfg.insts[inst]
);
// We're going to need to use this instruction
@@ -600,7 +600,7 @@ impl<'a> Elaborator<'a> {
// elaboration for args of *any* branch must be inserted
// before the *first* branch, because the branch group
// must remain contiguous at the end of the block.
if self.func.dfg[inst].opcode().is_branch() && first_branch == None {
if self.func.dfg.insts[inst].opcode().is_branch() && first_branch == None {
first_branch = Some(inst);
}

View File

@@ -40,7 +40,7 @@ fn is_load_with_defined_trapping(opcode: Opcode, data: &InstructionData) -> bool
/// its value is unused?
#[inline(always)]
pub fn has_side_effect(func: &Function, inst: Inst) -> bool {
let data = &func.dfg[inst];
let data = &func.dfg.insts[inst];
let opcode = data.opcode();
trivially_has_side_effects(opcode) || is_load_with_defined_trapping(opcode, data)
}
@@ -51,7 +51,7 @@ pub fn has_side_effect(func: &Function, inst: Inst) -> bool {
/// - Actual pure nodes (arithmetic, etc)
/// - Loads with the `readonly` flag set
pub fn is_pure_for_egraph(func: &Function, inst: Inst) -> bool {
let is_readonly_load = match func.dfg[inst] {
let is_readonly_load = match func.dfg.insts[inst] {
InstructionData::Load {
opcode: Opcode::Load,
flags,
@@ -69,7 +69,7 @@ pub fn is_pure_for_egraph(func: &Function, inst: Inst) -> bool {
// are, we can always trivially eliminate them with no effect.)
let has_one_result = func.dfg.inst_results(inst).len() == 1;
let op = func.dfg[inst].opcode();
let op = func.dfg.insts[inst].opcode();
has_one_result && (is_readonly_load || (!op.can_load() && !trivially_has_side_effects(op)))
}
@@ -77,14 +77,14 @@ pub fn is_pure_for_egraph(func: &Function, inst: Inst) -> bool {
/// Does the given instruction have any side-effect as per [has_side_effect], or else is a load,
/// but not the get_pinned_reg opcode?
pub fn has_lowering_side_effect(func: &Function, inst: Inst) -> bool {
let op = func.dfg[inst].opcode();
let op = func.dfg.insts[inst].opcode();
op != Opcode::GetPinnedReg && (has_side_effect(func, inst) || op.can_load())
}
/// Is the given instruction a constant value (`iconst`, `fconst`) that can be
/// represented in 64 bits?
pub fn is_constant_64bit(func: &Function, inst: Inst) -> Option<u64> {
let data = &func.dfg[inst];
let data = &func.dfg.insts[inst];
if data.opcode() == Opcode::Null {
return Some(0);
}
@@ -98,7 +98,7 @@ pub fn is_constant_64bit(func: &Function, inst: Inst) -> Option<u64> {
/// Get the address, offset, and access type from the given instruction, if any.
pub fn inst_addr_offset_type(func: &Function, inst: Inst) -> Option<(Value, Offset32, Type)> {
let data = &func.dfg[inst];
let data = &func.dfg.insts[inst];
match data {
InstructionData::Load { arg, offset, .. } => {
let ty = func.dfg.value_type(func.dfg.inst_results(inst)[0]);
@@ -122,7 +122,7 @@ pub fn inst_addr_offset_type(func: &Function, inst: Inst) -> Option<(Value, Offs
/// Get the store data, if any, from an instruction.
pub fn inst_store_data(func: &Function, inst: Inst) -> Option<Value> {
let data = &func.dfg[inst];
let data = &func.dfg.insts[inst];
match data {
InstructionData::Store { args, .. } | InstructionData::StoreNoOffset { args, .. } => {
Some(args[0])
@@ -157,14 +157,14 @@ pub(crate) fn visit_block_succs<F: FnMut(Inst, Block, bool)>(
mut visit: F,
) {
for inst in f.layout.block_likely_branches(block) {
if f.dfg[inst].opcode().is_branch() {
if f.dfg.insts[inst].opcode().is_branch() {
visit_branch_targets(f, inst, &mut visit);
}
}
}
fn visit_branch_targets<F: FnMut(Inst, Block, bool)>(f: &Function, inst: Inst, visit: &mut F) {
match f.dfg[inst].analyze_branch(&f.dfg.value_lists) {
match f.dfg.insts[inst].analyze_branch(&f.dfg.value_lists) {
BranchInfo::NotABranch => {}
BranchInfo::SingleDest(dest, _) => {
visit(inst, dest, false);

View File

@@ -201,7 +201,7 @@ impl<'f> InstBuilderBase<'f> for ReplaceBuilder<'f> {
fn build(self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'f mut DataFlowGraph) {
// Splat the new instruction on top of the old one.
self.dfg[self.inst] = data;
self.dfg.insts[self.inst] = data;
if !self.dfg.has_results(self.inst) {
// The old result values were either detached or non-existent.

View File

@@ -23,6 +23,27 @@ use alloc::collections::BTreeMap;
#[cfg(feature = "enable-serde")]
use serde::{Deserialize, Serialize};
/// Storage for instructions within the DFG.
#[derive(Clone, PartialEq, Hash)]
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
pub struct Insts(PrimaryMap<Inst, InstructionData>);
/// Allow immutable access to instructions via indexing.
impl Index<Inst> for Insts {
type Output = InstructionData;
fn index(&self, inst: Inst) -> &InstructionData {
self.0.index(inst)
}
}
/// Allow mutable access to instructions via indexing.
impl IndexMut<Inst> for Insts {
fn index_mut(&mut self, inst: Inst) -> &mut InstructionData {
self.0.index_mut(inst)
}
}
/// A data flow graph defines all instructions and basic blocks in a function as well as
/// the data flow dependencies between them. The DFG also tracks values which can be either
/// instruction results or block parameters.
@@ -36,7 +57,7 @@ pub struct DataFlowGraph {
/// Data about all of the instructions in the function, including opcodes and operands.
/// The instructions in this map are not in program order. That is tracked by `Layout`, along
/// with the block containing each instruction.
insts: PrimaryMap<Inst, InstructionData>,
pub insts: Insts,
/// List of result values for each instruction.
///
@@ -89,7 +110,7 @@ impl DataFlowGraph {
/// Create a new empty `DataFlowGraph`.
pub fn new() -> Self {
Self {
insts: PrimaryMap::new(),
insts: Insts(PrimaryMap::new()),
results: SecondaryMap::new(),
blocks: PrimaryMap::new(),
dynamic_types: DynamicTypes::new(),
@@ -106,7 +127,7 @@ impl DataFlowGraph {
/// Clear everything.
pub fn clear(&mut self) {
self.insts.clear();
self.insts.0.clear();
self.results.clear();
self.blocks.clear();
self.dynamic_types.clear();
@@ -125,12 +146,12 @@ impl DataFlowGraph {
///
/// This is intended for use with `SecondaryMap::with_capacity`.
pub fn num_insts(&self) -> usize {
self.insts.len()
self.insts.0.len()
}
/// Returns `true` if the given instruction reference is valid.
pub fn inst_is_valid(&self, inst: Inst) -> bool {
self.insts.is_valid(inst)
self.insts.0.is_valid(inst)
}
/// Get the total number of basic blocks created in this function, whether they are
@@ -619,7 +640,7 @@ impl DataFlowGraph {
pub fn make_inst(&mut self, data: InstructionData) -> Inst {
let n = self.num_insts() + 1;
self.results.resize(n);
self.insts.push(data)
self.insts.0.push(data)
}
/// Declares a dynamic vector type
@@ -656,7 +677,7 @@ impl DataFlowGraph {
/// Get the fixed value arguments on `inst` as a slice.
pub fn inst_fixed_args(&self, inst: Inst) -> &[Value] {
let num_fixed_args = self[inst]
let num_fixed_args = self.insts[inst]
.opcode()
.constraints()
.num_fixed_value_arguments();
@@ -665,7 +686,7 @@ impl DataFlowGraph {
/// Get the fixed value arguments on `inst` as a mutable slice.
pub fn inst_fixed_args_mut(&mut self, inst: Inst) -> &mut [Value] {
let num_fixed_args = self[inst]
let num_fixed_args = self.insts[inst]
.opcode()
.constraints()
.num_fixed_value_arguments();
@@ -674,7 +695,7 @@ impl DataFlowGraph {
/// Get the variable value arguments on `inst` as a slice.
pub fn inst_variable_args(&self, inst: Inst) -> &[Value] {
let num_fixed_args = self[inst]
let num_fixed_args = self.insts[inst]
.opcode()
.constraints()
.num_fixed_value_arguments();
@@ -683,7 +704,7 @@ impl DataFlowGraph {
/// Get the variable value arguments on `inst` as a mutable slice.
pub fn inst_variable_args_mut(&mut self, inst: Inst) -> &mut [Value] {
let num_fixed_args = self[inst]
let num_fixed_args = self.insts[inst]
.opcode()
.constraints()
.num_fixed_value_arguments();
@@ -849,18 +870,17 @@ impl DataFlowGraph {
///
/// Panics if the instruction doesn't support arguments.
pub fn append_inst_arg(&mut self, inst: Inst, new_arg: Value) {
let mut branch_values = self.insts[inst]
.take_value_list()
.expect("the instruction doesn't have value arguments");
branch_values.push(new_arg, &mut self.value_lists);
self.insts[inst].put_value_list(branch_values)
self.insts[inst]
.value_list_mut()
.expect("the instruction doesn't have value arguments")
.push(new_arg, &mut self.value_lists);
}
/// Clone an instruction, attaching new result `Value`s and
/// returning them.
pub fn clone_inst(&mut self, inst: Inst) -> Inst {
// First, add a clone of the InstructionData.
let inst_data = self[inst].clone();
let inst_data = self.insts[inst].clone();
let new_inst = self.make_inst(inst_data);
// Get the controlling type variable.
let ctrl_typevar = self.ctrl_typevar(inst);
@@ -947,7 +967,7 @@ impl DataFlowGraph {
/// Get the controlling type variable, or `INVALID` if `inst` isn't polymorphic.
pub fn ctrl_typevar(&self, inst: Inst) -> Type {
let constraints = self[inst].opcode().constraints();
let constraints = self.insts[inst].opcode().constraints();
if !constraints.is_polymorphic() {
types::INVALID
@@ -955,12 +975,12 @@ impl DataFlowGraph {
// Not all instruction formats have a designated operand, but in that case
// `requires_typevar_operand()` should never be true.
self.value_type(
self[inst]
self.insts[inst]
.typevar_operand(&self.value_lists)
.unwrap_or_else(|| {
panic!(
"Instruction format for {:?} doesn't have a designated operand",
self[inst]
self.insts[inst]
)
}),
)
@@ -970,22 +990,6 @@ impl DataFlowGraph {
}
}
/// Allow immutable access to instructions via indexing.
impl Index<Inst> for DataFlowGraph {
type Output = InstructionData;
fn index(&self, inst: Inst) -> &InstructionData {
&self.insts[inst]
}
}
/// Allow mutable access to instructions via indexing.
impl IndexMut<Inst> for DataFlowGraph {
fn index_mut(&mut self, inst: Inst) -> &mut InstructionData {
&mut self.insts[inst]
}
}
/// basic blocks.
impl DataFlowGraph {
/// Create a new basic block.
@@ -1187,9 +1191,9 @@ impl<'a> fmt::Display for DisplayInst<'a> {
let typevar = dfg.ctrl_typevar(inst);
if typevar.is_invalid() {
write!(f, "{}", dfg[inst].opcode())?;
write!(f, "{}", dfg.insts[inst].opcode())?;
} else {
write!(f, "{}.{}", dfg[inst].opcode(), typevar)?;
write!(f, "{}.{}", dfg.insts[inst].opcode(), typevar)?;
}
write_operands(f, dfg, inst)
}
@@ -1376,7 +1380,7 @@ mod tests {
// Immutable reference resolution.
{
let immdfg = &dfg;
let ins = &immdfg[inst];
let ins = &immdfg.insts[inst];
assert_eq!(ins.opcode(), Opcode::Iconst);
}

View File

@@ -282,7 +282,7 @@ impl FunctionStencil {
///
/// Note that this method ignores multi-destination branches like `br_table`.
pub fn change_branch_destination(&mut self, inst: Inst, new_dest: Block) {
match self.dfg[inst].branch_destination_mut() {
match self.dfg.insts[inst].branch_destination_mut() {
None => (),
Some(inst_dest) => *inst_dest = new_dest,
}
@@ -309,7 +309,7 @@ impl FunctionStencil {
});
if default_dest == Some(old_dest) {
match &mut self.dfg[inst] {
match &mut self.dfg.insts[inst] {
InstructionData::BranchTable { destination, .. } => {
*destination = new_dest;
}
@@ -333,13 +333,13 @@ impl FunctionStencil {
let inst_iter = self.layout.block_insts(block);
// Ignore all instructions prior to the first branch.
let mut inst_iter = inst_iter.skip_while(|&inst| !dfg[inst].opcode().is_branch());
let mut inst_iter = inst_iter.skip_while(|&inst| !dfg.insts[inst].opcode().is_branch());
// A conditional branch is permitted in a basic block only when followed
// by a terminal jump instruction.
if let Some(_branch) = inst_iter.next() {
if let Some(next) = inst_iter.next() {
match dfg[next].opcode() {
match dfg.insts[next].opcode() {
Opcode::Jump => (),
_ => return Err((next, "post-branch instruction not jump")),
}
@@ -377,7 +377,7 @@ impl FunctionStencil {
.zip(self.dfg.inst_results(src))
.all(|(a, b)| self.dfg.value_type(*a) == self.dfg.value_type(*b)));
self.dfg[dst] = self.dfg[src];
self.dfg.insts[dst] = self.dfg.insts[src];
self.layout.remove_inst(src);
}

View File

@@ -600,7 +600,7 @@ impl Layout {
// If two, the former is conditional and the latter is unconditional.
let last = self.last_inst(block)?;
if let Some(prev) = self.prev_inst(last) {
if dfg[prev].opcode().is_branch() {
if dfg.insts[prev].opcode().is_branch() {
return Some(prev);
}
}

View File

@@ -53,7 +53,7 @@ pub fn simple_legalize(func: &mut ir::Function, cfg: &mut ControlFlowGraph, isa:
while let Some(_block) = pos.next_block() {
let mut prev_pos = pos.position();
while let Some(inst) = pos.next_inst() {
match pos.func.dfg[inst] {
match pos.func.dfg.insts[inst] {
// control flow
InstructionData::CondTrap {
opcode:

View File

@@ -153,11 +153,11 @@ fn is_unsafe_load(inst_data: &InstructionData) -> bool {
/// Test whether the given instruction is loop-invariant.
fn is_loop_invariant(inst: Inst, dfg: &DataFlowGraph, loop_values: &FxHashSet<Value>) -> bool {
if trivially_unsafe_for_licm(dfg[inst].opcode()) {
if trivially_unsafe_for_licm(dfg.insts[inst].opcode()) {
return false;
}
if is_unsafe_load(&dfg[inst]) {
if is_unsafe_load(&dfg.insts[inst]) {
return false;
}

View File

@@ -251,7 +251,7 @@ impl BlockLoweringOrder {
block_succ_range[block] = (block_succ_start, block_succ_end);
for inst in f.layout.block_likely_branches(block) {
if f.dfg[inst].opcode() == Opcode::Return {
if f.dfg.insts[inst].opcode() == Opcode::Return {
// Implicit output edge for any return.
block_out_count[block] += 1;
}
@@ -279,7 +279,7 @@ impl BlockLoweringOrder {
for inst in f.layout.block_likely_branches(block) {
// If the block has a branch with any "fixed args"
// (not blockparam args) ...
if f.dfg[inst].opcode().is_branch() && f.dfg.inst_fixed_args(inst).len() > 0 {
if f.dfg.insts[inst].opcode().is_branch() && f.dfg.inst_fixed_args(inst).len() > 0 {
// ... then force a minimum successor count of
// two, so the below algorithm cannot put
// edge-moves on the end of the block.

View File

@@ -221,7 +221,7 @@ macro_rules! isle_lower_prelude_methods {
#[inline]
fn inst_data(&mut self, inst: Inst) -> InstructionData {
self.lower_ctx.dfg()[inst]
self.lower_ctx.dfg().insts[inst]
}
#[inline]

View File

@@ -368,7 +368,7 @@ impl<'func, I: VCodeInst> Lower<'func, I> {
"bb {} inst {} ({:?}): result {} regs {:?}",
bb,
inst,
f.dfg[inst],
f.dfg.insts[inst],
result,
regs,
);
@@ -705,7 +705,7 @@ impl<'func, I: VCodeInst> Lower<'func, I> {
// then reverse these and append to the VCode at the end of
// each IR instruction.
for inst in self.f.layout.block_insts(block).rev() {
let data = &self.f.dfg[inst];
let data = &self.f.dfg.insts[inst];
let has_side_effect = has_lowering_side_effect(self.f, inst);
// If inst has been sunk to another location, skip it.
if self.is_inst_sunk(inst) {
@@ -736,14 +736,14 @@ impl<'func, I: VCodeInst> Lower<'func, I> {
// Skip lowering branches; these are handled separately
// (see `lower_clif_branches()` below).
if self.f.dfg[inst].opcode().is_branch() {
if self.f.dfg.insts[inst].opcode().is_branch() {
continue;
}
// Normal instruction: codegen if the instruction is side-effecting
// or any of its outputs its used.
if has_side_effect || value_needed {
trace!("lowering: inst {}: {:?}", inst, self.f.dfg[inst]);
trace!("lowering: inst {}: {:?}", inst, self.f.dfg.insts[inst]);
let temp_regs = backend.lower(self, inst).unwrap_or_else(|| {
let ty = if self.num_outputs(inst) > 0 {
Some(self.output_ty(inst, 0))
@@ -975,7 +975,7 @@ impl<'func, I: VCodeInst> Lower<'func, I> {
if last_inst != Some(inst) {
branches.push(inst);
} else {
debug_assert!(self.f.dfg[inst].opcode() == Opcode::BrTable);
debug_assert!(self.f.dfg.insts[inst].opcode() == Opcode::BrTable);
debug_assert!(branches.len() == 1);
}
last_inst = Some(inst);
@@ -1104,7 +1104,7 @@ impl<'func, I: VCodeInst> Lower<'func, I> {
impl<'func, I: VCodeInst> Lower<'func, I> {
/// Get the instdata for a given IR instruction.
pub fn data(&self, ir_inst: Inst) -> &InstructionData {
&self.f.dfg[ir_inst]
&self.f.dfg.insts[ir_inst]
}
/// Likewise, but starting with a GlobalValue identifier.
@@ -1129,7 +1129,7 @@ impl<'func, I: VCodeInst> Lower<'func, I> {
/// Returns the memory flags of a given memory access.
pub fn memflags(&self, ir_inst: Inst) -> Option<MemFlags> {
match &self.f.dfg[ir_inst] {
match &self.f.dfg.insts[ir_inst] {
&InstructionData::AtomicCas { flags, .. } => Some(flags),
&InstructionData::AtomicRmw { flags, .. } => Some(flags),
&InstructionData::Load { flags, .. }

View File

@@ -30,7 +30,7 @@ pub fn do_nan_canonicalization(func: &mut Function) {
/// arithmetic operation. This ignores operations like `fneg`, `fabs`, or
/// `fcopysign` that only operate on the sign bit of a floating point value.
fn is_fp_arith(pos: &mut FuncCursor, inst: Inst) -> bool {
match pos.func.dfg[inst] {
match pos.func.dfg.insts[inst] {
InstructionData::Unary { opcode, .. } => {
opcode == Opcode::Ceil
|| opcode == Opcode::Floor

View File

@@ -76,7 +76,7 @@ where
ValueDef::Result(inst, _) if ctx.ctx.func.dfg.inst_results(inst).len() == 1 => {
let ty = ctx.ctx.func.dfg.value_type(value);
trace!(" -> value of type {}", ty);
return Some((ty, ctx.ctx.func.dfg[inst].clone()));
return Some((ty, ctx.ctx.func.dfg.insts[inst].clone()));
}
_ => {}
}

View File

@@ -232,7 +232,7 @@ pub fn do_remove_constant_phis(func: &mut Function, domtree: &mut DominatorTree)
let mut summary = BlockSummary::new(&bump, formals);
for inst in func.layout.block_insts(b) {
let idetails = &func.dfg[inst];
let idetails = &func.dfg.insts[inst];
// Note that multi-dest transfers (i.e., branch tables) don't
// carry parameters in our IR, so we only have to care about
// `SingleDest` here.
@@ -378,9 +378,9 @@ pub fn do_remove_constant_phis(func: &mut Function, domtree: &mut DominatorTree)
continue;
}
let old_actuals = func.dfg[edge.inst].take_value_list().unwrap();
let old_actuals = func.dfg.insts[edge.inst].value_list().unwrap();
let num_old_actuals = old_actuals.len(&func.dfg.value_lists);
let num_fixed_actuals = func.dfg[edge.inst]
let num_fixed_actuals = func.dfg.insts[edge.inst]
.opcode()
.constraints()
.num_fixed_value_arguments();
@@ -412,7 +412,7 @@ pub fn do_remove_constant_phis(func: &mut Function, domtree: &mut DominatorTree)
new_actuals.push(actual_i, &mut func.dfg.value_lists);
}
}
func.dfg[edge.inst].put_value_list(new_actuals);
*func.dfg.insts[edge.inst].value_list_mut().unwrap() = new_actuals;
}
}

View File

@@ -96,7 +96,7 @@ pub fn do_simple_gvn(func: &mut Function, domtree: &mut DominatorTree) {
let func = Ref::map(pos.borrow(), |pos| &pos.func);
let opcode = func.dfg[inst].opcode();
let opcode = func.dfg.insts[inst].opcode();
if opcode.is_branch() && !opcode.is_terminator() {
scope_stack.push(func.layout.next_inst(inst).unwrap());
@@ -108,13 +108,13 @@ pub fn do_simple_gvn(func: &mut Function, domtree: &mut DominatorTree) {
}
// These are split up to separate concerns.
if is_load_and_not_readonly(&func.dfg[inst]) {
if is_load_and_not_readonly(&func.dfg.insts[inst]) {
continue;
}
let ctrl_typevar = func.dfg.ctrl_typevar(inst);
let key = HashKey {
inst: func.dfg[inst],
inst: func.dfg.insts[inst],
ty: ctrl_typevar,
pos: &pos,
};

View File

@@ -142,7 +142,7 @@ fn package_up_divrem_info(
/// Examine `inst` to see if it is a div or rem by a constant, and if so return the operands,
/// signedness, operation size and div-vs-rem-ness in a handy bundle.
fn get_div_info(inst: Inst, dfg: &DataFlowGraph) -> Option<DivRemByConstInfo> {
if let InstructionData::BinaryImm64 { opcode, arg, imm } = dfg[inst] {
if let InstructionData::BinaryImm64 { opcode, arg, imm } = dfg.insts[inst] {
let (is_signed, is_rem) = match opcode {
Opcode::UdivImm => (false, false),
Opcode::UremImm => (false, true),
@@ -478,7 +478,7 @@ enum BranchOrderKind {
/// layout-wise. The unconditional jump can then become a fallthrough.
fn branch_order(pos: &mut FuncCursor, cfg: &mut ControlFlowGraph, block: Block, inst: Inst) {
let (term_inst, term_inst_args, term_dest, cond_inst, cond_inst_args, cond_dest, kind) =
match pos.func.dfg[inst] {
match pos.func.dfg.insts[inst] {
InstructionData::Jump {
opcode: Opcode::Jump,
destination,
@@ -500,7 +500,7 @@ fn branch_order(pos: &mut FuncCursor, cfg: &mut ControlFlowGraph, block: Block,
return;
};
let prev_inst_data = &pos.func.dfg[prev_inst];
let prev_inst_data = &pos.func.dfg.insts[prev_inst];
if let Some(prev_dest) = prev_inst_data.branch_destination() {
if prev_dest != next_block {
@@ -609,7 +609,7 @@ mod simplify {
if let InstructionData::UnaryImm {
opcode: Opcode::Iconst,
imm,
} = dfg[candidate_inst]
} = dfg.insts[candidate_inst]
{
return Some(imm);
}
@@ -631,7 +631,7 @@ mod simplify {
opcode: Opcode::IshlImm,
arg: prev_arg,
imm: prev_imm,
} = &pos.func.dfg[arg_inst]
} = &pos.func.dfg.insts[arg_inst]
{
if imm != *prev_imm {
return false;
@@ -677,7 +677,7 @@ mod simplify {
/// would likely be expanded back into an instruction on smaller types with the same initial
/// opcode, creating unnecessary churn.
fn simplify(pos: &mut FuncCursor, inst: Inst, native_word_width: u32) {
match pos.func.dfg[inst] {
match pos.func.dfg.insts[inst] {
InstructionData::Binary { opcode, args } => {
if let Some(mut imm) = resolve_imm64_value(&pos.func.dfg, args[1]) {
let new_opcode = match opcode {
@@ -748,7 +748,7 @@ mod simplify {
opcode: prev_opcode,
arg: prev_arg,
imm: prev_imm,
} = &pos.func.dfg[arg_inst]
} = &pos.func.dfg.insts[arg_inst]
{
if opcode == *prev_opcode
&& ty == pos.func.dfg.ctrl_typevar(arg_inst)
@@ -846,7 +846,7 @@ mod simplify {
opcode: br_opcode,
args: ref br_args,
..
} = pos.func.dfg[inst]
} = pos.func.dfg.insts[inst]
{
let first_arg = {
let args = pos.func.dfg.inst_args(inst);
@@ -865,7 +865,7 @@ mod simplify {
arg: cmp_arg,
cond: cmp_cond,
imm: cmp_imm,
} = pos.func.dfg[icmp_inst]
} = pos.func.dfg.insts[icmp_inst]
{
let cmp_imm: i64 = cmp_imm.into();
if cmp_imm != 0 {
@@ -900,7 +900,7 @@ mod simplify {
};
info.args.as_mut_slice(&mut pos.func.dfg.value_lists)[0] = info.cmp_arg;
if let InstructionData::Branch { ref mut opcode, .. } = pos.func.dfg[info.br_inst] {
if let InstructionData::Branch { ref mut opcode, .. } = pos.func.dfg.insts[info.br_inst] {
*opcode = info.new_opcode;
} else {
panic!();

View File

@@ -93,7 +93,7 @@ fn harvest_candidate_lhs(
// Should we keep tracing through the given `val`? Only if it is defined
// by an instruction that we can translate to Souper IR.
let should_trace = |val| match func.dfg.value_def(val) {
ir::ValueDef::Result(inst, 0) => match func.dfg[inst].opcode() {
ir::ValueDef::Result(inst, 0) => match func.dfg.insts[inst].opcode() {
ir::Opcode::Iadd
| ir::Opcode::IaddImm
| ir::Opcode::IrsubImm
@@ -157,7 +157,7 @@ fn harvest_candidate_lhs(
// `iconst`s into souper operands here,
// when they are actually used.
match func.dfg.value_def(arg) {
ir::ValueDef::Result(inst, 0) => match func.dfg[inst] {
ir::ValueDef::Result(inst, 0) => match func.dfg.insts[inst] {
ir::InstructionData::UnaryImm { opcode, imm } => {
debug_assert_eq!(opcode, ir::Opcode::Iconst);
let imm: i64 = imm.into();
@@ -179,7 +179,7 @@ fn harvest_candidate_lhs(
}
};
match (func.dfg[inst].opcode(), &func.dfg[inst]) {
match (func.dfg.insts[inst].opcode(), &func.dfg.insts[inst]) {
(ir::Opcode::Iadd, _) => {
let a = arg(allocs, 0);
let b = arg(allocs, 1);

View File

@@ -470,7 +470,7 @@ impl<'a> Verifier<'a> {
inst: Inst,
errors: &mut VerifierErrors,
) -> VerifierStepResult<()> {
let is_terminator = self.func.dfg[inst].opcode().is_terminator();
let is_terminator = self.func.dfg.insts[inst].opcode().is_terminator();
let is_last_inst = self.func.layout.last_inst(block) == Some(inst);
if is_terminator && !is_last_inst {
@@ -520,7 +520,7 @@ impl<'a> Verifier<'a> {
inst: Inst,
errors: &mut VerifierErrors,
) -> VerifierStepResult<()> {
let inst_data = &self.func.dfg[inst];
let inst_data = &self.func.dfg.insts[inst];
let dfg = &self.func.dfg;
// The instruction format matches the opcode
@@ -580,7 +580,7 @@ impl<'a> Verifier<'a> {
self.verify_inst_result(inst, res, errors)?;
}
match self.func.dfg[inst] {
match self.func.dfg.insts[inst] {
MultiAry { ref args, .. } => {
self.verify_value_list(inst, args, errors)?;
}
@@ -1181,7 +1181,7 @@ impl<'a> Verifier<'a> {
}
fn typecheck(&self, inst: Inst, errors: &mut VerifierErrors) -> VerifierStepResult<()> {
let inst_data = &self.func.dfg[inst];
let inst_data = &self.func.dfg.insts[inst];
let constraints = inst_data.opcode().constraints();
let ctrl_type = if let Some(value_typeset) = constraints.ctrl_typeset() {
@@ -1261,7 +1261,7 @@ impl<'a> Verifier<'a> {
ctrl_type: Type,
errors: &mut VerifierErrors,
) -> VerifierStepResult<()> {
let constraints = self.func.dfg[inst].opcode().constraints();
let constraints = self.func.dfg.insts[inst].opcode().constraints();
for (i, &arg) in self.func.dfg.inst_fixed_args(inst).iter().enumerate() {
let arg_type = self.func.dfg.value_type(arg);
@@ -1341,7 +1341,7 @@ impl<'a> Verifier<'a> {
BranchInfo::NotABranch => {}
}
match self.func.dfg[inst].analyze_call(&self.func.dfg.value_lists) {
match self.func.dfg.insts[inst].analyze_call(&self.func.dfg.value_lists) {
CallInfo::Direct(func_ref, _) => {
let sig_ref = self.func.dfg.ext_funcs[func_ref].signature;
let arg_types = self.func.dfg.signatures[sig_ref]
@@ -1407,7 +1407,7 @@ impl<'a> Verifier<'a> {
}
fn typecheck_return(&self, inst: Inst, errors: &mut VerifierErrors) -> VerifierStepResult<()> {
if self.func.dfg[inst].opcode().is_return() {
if self.func.dfg.insts[inst].opcode().is_return() {
let args = self.func.dfg.inst_variable_args(inst);
let expected_types = &self.func.signature.returns;
if args.len() != expected_types.len() {
@@ -1442,7 +1442,7 @@ impl<'a> Verifier<'a> {
ctrl_type: Type,
errors: &mut VerifierErrors,
) -> VerifierStepResult<()> {
match self.func.dfg[inst] {
match self.func.dfg.insts[inst] {
ir::InstructionData::Unary { opcode, arg } => {
let arg_type = self.func.dfg.value_type(arg);
match opcode {
@@ -1604,7 +1604,7 @@ impl<'a> Verifier<'a> {
inst: Inst,
errors: &mut VerifierErrors,
) -> VerifierStepResult<()> {
let inst_data = &self.func.dfg[inst];
let inst_data = &self.func.dfg.insts[inst];
match *inst_data {
ir::InstructionData::Store { flags, .. } => {

View File

@@ -276,7 +276,7 @@ fn decorate_block<FW: FuncWriter>(
// if it can't be trivially inferred.
//
fn type_suffix(func: &Function, inst: Inst) -> Option<Type> {
let inst_data = &func.dfg[inst];
let inst_data = &func.dfg.insts[inst];
let constraints = inst_data.opcode().constraints();
if !constraints.is_polymorphic() {
@@ -357,7 +357,7 @@ fn write_instruction(
}
// Then the opcode, possibly with a '.type' suffix.
let opcode = func.dfg[inst].opcode();
let opcode = func.dfg.insts[inst].opcode();
match type_suffix(func, inst) {
Some(suf) => write!(w, "{}.{}", opcode, suf)?,
@@ -378,7 +378,7 @@ fn write_instruction(
pub fn write_operands(w: &mut dyn Write, dfg: &DataFlowGraph, inst: Inst) -> fmt::Result {
let pool = &dfg.value_lists;
use crate::ir::instructions::InstructionData::*;
match dfg[inst] {
match dfg.insts[inst] {
AtomicRmw { op, args, .. } => write!(w, " {} {}, {}", op, args[0], args[1]),
AtomicCas { args, .. } => write!(w, " {}, {}, {}", args[0], args[1], args[2]),
LoadNoOffset { flags, arg, .. } => write!(w, "{} {}", flags, arg),
@@ -487,7 +487,7 @@ pub fn write_operands(w: &mut dyn Write, dfg: &DataFlowGraph, inst: Inst) -> fmt
let mut sep = " ; ";
for &arg in dfg.inst_args(inst) {
if let ValueDef::Result(src, _) = dfg.value_def(arg) {
let imm = match dfg[src] {
let imm = match dfg.insts[src] {
UnaryImm { imm, .. } => imm.to_string(),
UnaryIeee32 { imm, .. } => imm.to_string(),
UnaryIeee64 { imm, .. } => imm.to_string(),

View File

@@ -676,7 +676,7 @@ impl<'a> FunctionBuilder<'a> {
/// **Note:** You are responsible for maintaining the coherence with the arguments of
/// other jump instructions.
pub fn change_jump_destination(&mut self, inst: Inst, new_dest: Block) {
let old_dest = self.func.dfg[inst]
let old_dest = self.func.dfg.insts[inst]
.branch_destination_mut()
.expect("you want to change the jump destination of a non-jump instruction");
self.func_ctx.ssa.remove_block_predecessor(*old_dest, inst);

View File

@@ -611,7 +611,7 @@ impl SSABuilder {
}
// Redo the match from `analyze_branch` but this time capture mutable references
match &mut func.dfg[branch] {
match &mut func.dfg.insts[branch] {
InstructionData::BranchTable {
destination, table, ..
} => {
@@ -1192,7 +1192,7 @@ mod tests {
ssa.use_var(&mut func, x_var, I32, block0);
assert_eq!(func.dfg.num_block_params(block0), 0);
assert_eq!(
func.dfg[func.layout.first_inst(block0).unwrap()].opcode(),
func.dfg.insts[func.layout.first_inst(block0).unwrap()].opcode(),
Opcode::Iconst
);
}
@@ -1213,7 +1213,7 @@ mod tests {
ssa.seal_block(block0, &mut func);
assert_eq!(func.dfg.num_block_params(block0), 0);
assert_eq!(
func.dfg[func.layout.first_inst(block0).unwrap()].opcode(),
func.dfg.insts[func.layout.first_inst(block0).unwrap()].opcode(),
Opcode::Iconst
);
}

View File

@@ -24,7 +24,7 @@ pub fn do_fcvt_trap_pass(fuzz: &mut FuzzGen, func: &mut Function) -> Result<()>
/// Returns true/false if this instruction can trap
fn can_fcvt_trap(pos: &FuncCursor, inst: Inst) -> bool {
let opcode = pos.func.dfg[inst].opcode();
let opcode = pos.func.dfg.insts[inst].opcode();
matches!(opcode, Opcode::FcvtToUint | Opcode::FcvtToSint)
}
@@ -66,7 +66,7 @@ fn float_limits(
/// Prepend instructions to inst to avoid traps
fn insert_fcvt_sequence(pos: &mut FuncCursor, inst: Inst) {
let dfg = &pos.func.dfg;
let opcode = dfg[inst].opcode();
let opcode = dfg.insts[inst].opcode();
let arg = dfg.inst_args(inst)[0];
let float_ty = dfg.value_type(arg);
let int_ty = dfg.value_type(dfg.first_result(inst));

View File

@@ -28,7 +28,7 @@ pub fn do_int_divz_pass(fuzz: &mut FuzzGen, func: &mut Function) -> Result<()> {
/// Returns true/false if this instruction can cause a `int_divz` trap
fn can_int_divz(pos: &FuncCursor, inst: Inst) -> bool {
let opcode = pos.func.dfg[inst].opcode();
let opcode = pos.func.dfg.insts[inst].opcode();
matches!(
opcode,
@@ -38,7 +38,7 @@ fn can_int_divz(pos: &FuncCursor, inst: Inst) -> bool {
/// Prepend instructions to inst to avoid `int_divz` traps
fn insert_int_divz_sequence(pos: &mut FuncCursor, inst: Inst) {
let opcode = pos.func.dfg[inst].opcode();
let opcode = pos.func.dfg.insts[inst].opcode();
let inst_args = pos.func.dfg.inst_args(inst);
let (lhs, rhs) = (inst_args[0], inst_args[1]);
assert_eq!(pos.func.dfg.value_type(lhs), pos.func.dfg.value_type(rhs));

View File

@@ -25,7 +25,7 @@ impl<'a> DfgInstructionContext<'a> {
impl InstructionContext for DfgInstructionContext<'_> {
fn data(&self) -> InstructionData {
self.1[self.0].clone()
self.1.insts[self.0].clone()
}
fn args(&self) -> &[Value] {

View File

@@ -45,7 +45,7 @@ pub fn fold_constants(func: &mut ir::Function) {
while let Some(_block) = pos.next_block() {
while let Some(inst) = pos.next_inst() {
use self::ir::InstructionData::*;
match pos.func.dfg[inst] {
match pos.func.dfg.insts[inst] {
Binary { opcode, args } => {
fold_binary(&mut pos.func.dfg, inst, opcode, args);
}
@@ -71,7 +71,7 @@ fn resolve_value_to_imm(dfg: &ir::DataFlowGraph, value: ir::Value) -> Option<Con
};
use self::ir::{InstructionData::*, Opcode::*};
match dfg[inst] {
match dfg.insts[inst] {
UnaryImm {
opcode: Iconst,
imm,
@@ -218,7 +218,7 @@ fn fold_unary(dfg: &mut ir::DataFlowGraph, inst: ir::Inst, opcode: ir::Opcode, a
fn fold_branch(pos: &mut FuncCursor, inst: ir::Inst, opcode: ir::Opcode) {
let (cond, block, args) = {
let values = pos.func.dfg.inst_args(inst);
let inst_data = &pos.func.dfg[inst];
let inst_data = &pos.func.dfg.insts[inst];
(
match resolve_value_to_imm(&pos.func.dfg, values[0]) {
Some(imm) => imm,

View File

@@ -174,7 +174,7 @@ impl Mutator for ReplaceInstWithConst {
|(_prev_block, prev_inst)| {
let num_results = func.dfg.inst_results(prev_inst).len();
let opcode = func.dfg[prev_inst].opcode();
let opcode = func.dfg.insts[prev_inst].opcode();
if num_results == 0
|| opcode == ir::Opcode::Iconst
|| opcode == ir::Opcode::F32const
@@ -193,7 +193,7 @@ impl Mutator for ReplaceInstWithConst {
let arg_def = func.dfg.value_def(arg);
let arg_is_iconst = arg_def
.inst()
.map(|inst| func.dfg[inst].opcode() == ir::Opcode::Iconst)
.map(|inst| func.dfg.insts[inst].opcode() == ir::Opcode::Iconst)
.unwrap_or(false);
if is_uextend_i128 && arg_is_iconst {
@@ -266,7 +266,7 @@ impl Mutator for ReplaceInstWithTrap {
fn mutate(&mut self, mut func: Function) -> Option<(Function, String, ProgressStatus)> {
next_inst_ret_prev(&func, &mut self.block, &mut self.inst).map(
|(_prev_block, prev_inst)| {
let status = if func.dfg[prev_inst].opcode() == ir::Opcode::Trap {
let status = if func.dfg.insts[prev_inst].opcode() == ir::Opcode::Trap {
ProgressStatus::Skip
} else {
func.dfg.replace(prev_inst).trap(TrapCode::User(0));
@@ -421,11 +421,12 @@ impl Mutator for ReplaceBlockParamWithConst {
// Remove parameters in branching instructions that point to this block
for pred in cfg.pred_iter(self.block) {
let inst = &mut func.dfg[pred.inst];
let dfg = &mut func.dfg;
let inst = &mut dfg.insts[pred.inst];
let num_fixed_args = inst.opcode().constraints().num_fixed_value_arguments();
let mut values = inst.take_value_list().unwrap();
values.remove(num_fixed_args + param_index, &mut func.dfg.value_lists);
func.dfg[pred.inst].put_value_list(values);
inst.value_list_mut()
.unwrap()
.remove(num_fixed_args + param_index, &mut dfg.value_lists);
}
if Some(self.block) == func.layout.entry_block() {
@@ -471,7 +472,7 @@ impl Mutator for RemoveUnusedEntities {
let mut ext_func_usage_map = HashMap::new();
for block in func.layout.blocks() {
for inst in func.layout.block_insts(block) {
match func.dfg[inst] {
match func.dfg.insts[inst] {
// Add new cases when there are new instruction formats taking a `FuncRef`.
InstructionData::Call { func_ref, .. }
| InstructionData::FuncAddr { func_ref, .. } => {
@@ -491,7 +492,7 @@ impl Mutator for RemoveUnusedEntities {
if let Some(func_ref_usage) = ext_func_usage_map.get(&func_ref) {
let new_func_ref = ext_funcs.push(ext_func_data.clone());
for &inst in func_ref_usage {
match func.dfg[inst] {
match func.dfg.insts[inst] {
// Keep in sync with the above match.
InstructionData::Call {
ref mut func_ref, ..
@@ -522,7 +523,8 @@ impl Mutator for RemoveUnusedEntities {
for block in func.layout.blocks() {
for inst in func.layout.block_insts(block) {
// Add new cases when there are new instruction formats taking a `SigRef`.
if let InstructionData::CallIndirect { sig_ref, .. } = func.dfg[inst] {
if let InstructionData::CallIndirect { sig_ref, .. } = func.dfg.insts[inst]
{
signatures_usage_map
.entry(sig_ref)
.or_insert_with(Vec::new)
@@ -544,7 +546,7 @@ impl Mutator for RemoveUnusedEntities {
let new_sig_ref = signatures.push(sig_data.clone());
for &sig_ref_user in sig_ref_usage {
match sig_ref_user {
SigRefUser::Instruction(inst) => match func.dfg[inst] {
SigRefUser::Instruction(inst) => match func.dfg.insts[inst] {
// Keep in sync with the above match.
InstructionData::CallIndirect {
ref mut sig_ref, ..
@@ -569,7 +571,7 @@ impl Mutator for RemoveUnusedEntities {
let mut stack_slot_usage_map = HashMap::new();
for block in func.layout.blocks() {
for inst in func.layout.block_insts(block) {
match func.dfg[inst] {
match func.dfg.insts[inst] {
// Add new cases when there are new instruction formats taking a `StackSlot`.
InstructionData::StackLoad { stack_slot, .. }
| InstructionData::StackStore { stack_slot, .. } => {
@@ -590,7 +592,7 @@ impl Mutator for RemoveUnusedEntities {
if let Some(stack_slot_usage) = stack_slot_usage_map.get(&stack_slot) {
let new_stack_slot = stack_slots.push(stack_slot_data.clone());
for &inst in stack_slot_usage {
match &mut func.dfg[inst] {
match &mut func.dfg.insts[inst] {
// Keep in sync with the above match.
InstructionData::StackLoad { stack_slot, .. }
| InstructionData::StackStore { stack_slot, .. } => {
@@ -612,7 +614,7 @@ impl Mutator for RemoveUnusedEntities {
for inst in func.layout.block_insts(block) {
// Add new cases when there are new instruction formats taking a `GlobalValue`.
if let InstructionData::UnaryGlobalValue { global_value, .. } =
func.dfg[inst]
func.dfg.insts[inst]
{
global_value_usage_map
.entry(global_value)
@@ -640,7 +642,7 @@ impl Mutator for RemoveUnusedEntities {
if let Some(global_value_usage) = global_value_usage_map.get(&global_value) {
let new_global_value = global_values.push(global_value_data.clone());
for &inst in global_value_usage {
match &mut func.dfg[inst] {
match &mut func.dfg.insts[inst] {
// Keep in sync with the above match.
InstructionData::UnaryGlobalValue { global_value, .. } => {
*global_value = new_global_value;
@@ -711,7 +713,7 @@ impl Mutator for MergeBlocks {
// instruction, then we have a conditional jump sequence that we should not break by
// replacing the second instruction by more of them.
if let Some(pred_pred_inst) = func.layout.prev_inst(pred.inst) {
if func.dfg[pred_pred_inst].opcode().is_branch() {
if func.dfg.insts[pred_pred_inst].opcode().is_branch() {
return Some((
func,
format!("did nothing for {}", block),
@@ -1024,7 +1026,7 @@ impl<'a> CrashCheckContext<'a> {
let contains_call = func.layout.blocks().any(|block| {
func.layout
.block_insts(block)
.any(|inst| match func.dfg[inst] {
.any(|inst| match func.dfg.insts[inst] {
InstructionData::Call { .. } => true,
_ => false,
})