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

View File

@@ -85,14 +85,14 @@ pub struct LastStores {
impl LastStores { impl LastStores {
fn update(&mut self, func: &Function, inst: Inst) { 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) { if has_memory_fence_semantics(opcode) {
self.heap = inst.into(); self.heap = inst.into();
self.table = inst.into(); self.table = inst.into();
self.vmctx = inst.into(); self.vmctx = inst.into();
self.other = inst.into(); self.other = inst.into();
} else if opcode.can_store() { } 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() { if memflags.heap() {
self.heap = inst.into(); self.heap = inst.into();
} else if memflags.table() { } else if memflags.table() {
@@ -112,7 +112,7 @@ impl LastStores {
} }
fn get_last_store(&self, func: &Function, inst: Inst) -> PackedOption<Inst> { 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() { if memflags.heap() {
self.heap self.heap
} else if memflags.table() { } else if memflags.table() {
@@ -122,7 +122,9 @@ impl LastStores {
} else { } else {
self.other 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() inst.into()
} else { } else {
PackedOption::default() PackedOption::default()
@@ -277,13 +279,13 @@ impl<'a> AliasAnalysis<'a> {
"alias analysis: scanning at inst{} with state {:?} ({:?})", "alias analysis: scanning at inst{} with state {:?} ({:?})",
inst.index(), inst.index(),
state, state,
func.dfg[inst], func.dfg.insts[inst],
); );
let replacing_value = if let Some((address, offset, ty)) = inst_addr_offset_type(func, inst) let replacing_value = if let Some((address, offset, ty)) = inst_addr_offset_type(func, inst)
{ {
let address = func.dfg.resolve_aliases(address); let address = func.dfg.resolve_aliases(address);
let opcode = func.dfg[inst].opcode(); let opcode = func.dfg.insts[inst].opcode();
if opcode.can_store() { if opcode.can_store() {
let store_data = inst_store_data(func, inst).unwrap(); 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 CursorPosition::At(_) = self.position() {
if let Some(curr) = self.current_inst() { if let Some(curr) = self.current_inst() {
if let Some(prev) = self.layout().prev_inst(curr) { if let Some(prev) = self.layout().prev_inst(curr) {
let prev_op = self.data_flow_graph()[prev].opcode(); let prev_op = self.data_flow_graph().insts[prev].opcode();
let inst_op = self.data_flow_graph()[inst].opcode(); let inst_op = self.data_flow_graph().insts[inst].opcode();
let curr_op = self.data_flow_graph()[curr].opcode(); let curr_op = self.data_flow_graph().insts[curr].opcode();
if prev_op.is_branch() if prev_op.is_branch()
&& !prev_op.is_terminator() && !prev_op.is_terminator()
&& !inst_op.is_terminator() && !inst_op.is_terminator()

View File

@@ -102,7 +102,7 @@ impl NewOrExistingInst {
NewOrExistingInst::New(data, ty) => (*ty, *data), NewOrExistingInst::New(data, ty) => (*ty, *data),
NewOrExistingInst::Existing(inst) => { NewOrExistingInst::Existing(inst) => {
let ty = dfg.ctrl_typevar(*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, union_find: self.eclasses,
value_lists: &self.func.dfg.value_lists, value_lists: &self.func.dfg.value_lists,
}; };
self.gvn_map self.gvn_map.insert(
.insert((ty, self.func.dfg[inst].clone()), opt_value, &gvn_context); (ty, self.func.dfg.insts[inst].clone()),
opt_value,
&gvn_context,
);
self.value_to_opt_value[result] = opt_value; self.value_to_opt_value[result] = opt_value;
opt_value opt_value
} }
@@ -335,7 +338,7 @@ impl<'a> EgraphPass<'a> {
trace!(" -> {} = {:?}", value, def); trace!(" -> {} = {:?}", value, def);
match def { match def {
ValueDef::Result(i, 0) => { 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, _) => { ValueDef::Result(inst, _) => {
trace!(" -> value {}: result, computing cost", value); 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 let loop_level = self
.func .func
.layout .layout
@@ -358,7 +358,7 @@ impl<'a> Elaborator<'a> {
trace!( trace!(
" -> result {} of inst {:?}", " -> result {} of inst {:?}",
result_idx, result_idx,
self.func.dfg[inst] self.func.dfg.insts[inst]
); );
// We're going to need to use this instruction // 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 // elaboration for args of *any* branch must be inserted
// before the *first* branch, because the branch group // before the *first* branch, because the branch group
// must remain contiguous at the end of the block. // 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); 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? /// its value is unused?
#[inline(always)] #[inline(always)]
pub fn has_side_effect(func: &Function, inst: Inst) -> bool { 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(); let opcode = data.opcode();
trivially_has_side_effects(opcode) || is_load_with_defined_trapping(opcode, data) 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) /// - Actual pure nodes (arithmetic, etc)
/// - Loads with the `readonly` flag set /// - Loads with the `readonly` flag set
pub fn is_pure_for_egraph(func: &Function, inst: Inst) -> bool { 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 { InstructionData::Load {
opcode: Opcode::Load, opcode: Opcode::Load,
flags, 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.) // are, we can always trivially eliminate them with no effect.)
let has_one_result = func.dfg.inst_results(inst).len() == 1; 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))) 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, /// 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? /// but not the get_pinned_reg opcode?
pub fn has_lowering_side_effect(func: &Function, inst: Inst) -> bool { 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()) op != Opcode::GetPinnedReg && (has_side_effect(func, inst) || op.can_load())
} }
/// Is the given instruction a constant value (`iconst`, `fconst`) that can be /// Is the given instruction a constant value (`iconst`, `fconst`) that can be
/// represented in 64 bits? /// represented in 64 bits?
pub fn is_constant_64bit(func: &Function, inst: Inst) -> Option<u64> { 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 { if data.opcode() == Opcode::Null {
return Some(0); 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. /// 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)> { 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 { match data {
InstructionData::Load { arg, offset, .. } => { InstructionData::Load { arg, offset, .. } => {
let ty = func.dfg.value_type(func.dfg.inst_results(inst)[0]); 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. /// Get the store data, if any, from an instruction.
pub fn inst_store_data(func: &Function, inst: Inst) -> Option<Value> { pub fn inst_store_data(func: &Function, inst: Inst) -> Option<Value> {
let data = &func.dfg[inst]; let data = &func.dfg.insts[inst];
match data { match data {
InstructionData::Store { args, .. } | InstructionData::StoreNoOffset { args, .. } => { InstructionData::Store { args, .. } | InstructionData::StoreNoOffset { args, .. } => {
Some(args[0]) Some(args[0])
@@ -157,14 +157,14 @@ pub(crate) fn visit_block_succs<F: FnMut(Inst, Block, bool)>(
mut visit: F, mut visit: F,
) { ) {
for inst in f.layout.block_likely_branches(block) { 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); visit_branch_targets(f, inst, &mut visit);
} }
} }
} }
fn visit_branch_targets<F: FnMut(Inst, Block, bool)>(f: &Function, inst: Inst, visit: &mut F) { 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::NotABranch => {}
BranchInfo::SingleDest(dest, _) => { BranchInfo::SingleDest(dest, _) => {
visit(inst, dest, false); 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) { fn build(self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'f mut DataFlowGraph) {
// Splat the new instruction on top of the old one. // 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) { if !self.dfg.has_results(self.inst) {
// The old result values were either detached or non-existent. // The old result values were either detached or non-existent.

View File

@@ -23,6 +23,27 @@ use alloc::collections::BTreeMap;
#[cfg(feature = "enable-serde")] #[cfg(feature = "enable-serde")]
use serde::{Deserialize, Serialize}; 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 /// 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 /// the data flow dependencies between them. The DFG also tracks values which can be either
/// instruction results or block parameters. /// 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. /// 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 /// The instructions in this map are not in program order. That is tracked by `Layout`, along
/// with the block containing each instruction. /// with the block containing each instruction.
insts: PrimaryMap<Inst, InstructionData>, pub insts: Insts,
/// List of result values for each instruction. /// List of result values for each instruction.
/// ///
@@ -89,7 +110,7 @@ impl DataFlowGraph {
/// Create a new empty `DataFlowGraph`. /// Create a new empty `DataFlowGraph`.
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
insts: PrimaryMap::new(), insts: Insts(PrimaryMap::new()),
results: SecondaryMap::new(), results: SecondaryMap::new(),
blocks: PrimaryMap::new(), blocks: PrimaryMap::new(),
dynamic_types: DynamicTypes::new(), dynamic_types: DynamicTypes::new(),
@@ -106,7 +127,7 @@ impl DataFlowGraph {
/// Clear everything. /// Clear everything.
pub fn clear(&mut self) { pub fn clear(&mut self) {
self.insts.clear(); self.insts.0.clear();
self.results.clear(); self.results.clear();
self.blocks.clear(); self.blocks.clear();
self.dynamic_types.clear(); self.dynamic_types.clear();
@@ -125,12 +146,12 @@ impl DataFlowGraph {
/// ///
/// This is intended for use with `SecondaryMap::with_capacity`. /// This is intended for use with `SecondaryMap::with_capacity`.
pub fn num_insts(&self) -> usize { pub fn num_insts(&self) -> usize {
self.insts.len() self.insts.0.len()
} }
/// Returns `true` if the given instruction reference is valid. /// Returns `true` if the given instruction reference is valid.
pub fn inst_is_valid(&self, inst: Inst) -> bool { 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 /// 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 { pub fn make_inst(&mut self, data: InstructionData) -> Inst {
let n = self.num_insts() + 1; let n = self.num_insts() + 1;
self.results.resize(n); self.results.resize(n);
self.insts.push(data) self.insts.0.push(data)
} }
/// Declares a dynamic vector type /// Declares a dynamic vector type
@@ -656,7 +677,7 @@ impl DataFlowGraph {
/// Get the fixed value arguments on `inst` as a slice. /// Get the fixed value arguments on `inst` as a slice.
pub fn inst_fixed_args(&self, inst: Inst) -> &[Value] { pub fn inst_fixed_args(&self, inst: Inst) -> &[Value] {
let num_fixed_args = self[inst] let num_fixed_args = self.insts[inst]
.opcode() .opcode()
.constraints() .constraints()
.num_fixed_value_arguments(); .num_fixed_value_arguments();
@@ -665,7 +686,7 @@ impl DataFlowGraph {
/// Get the fixed value arguments on `inst` as a mutable slice. /// Get the fixed value arguments on `inst` as a mutable slice.
pub fn inst_fixed_args_mut(&mut self, inst: Inst) -> &mut [Value] { 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() .opcode()
.constraints() .constraints()
.num_fixed_value_arguments(); .num_fixed_value_arguments();
@@ -674,7 +695,7 @@ impl DataFlowGraph {
/// Get the variable value arguments on `inst` as a slice. /// Get the variable value arguments on `inst` as a slice.
pub fn inst_variable_args(&self, inst: Inst) -> &[Value] { pub fn inst_variable_args(&self, inst: Inst) -> &[Value] {
let num_fixed_args = self[inst] let num_fixed_args = self.insts[inst]
.opcode() .opcode()
.constraints() .constraints()
.num_fixed_value_arguments(); .num_fixed_value_arguments();
@@ -683,7 +704,7 @@ impl DataFlowGraph {
/// Get the variable value arguments on `inst` as a mutable slice. /// Get the variable value arguments on `inst` as a mutable slice.
pub fn inst_variable_args_mut(&mut self, inst: Inst) -> &mut [Value] { 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() .opcode()
.constraints() .constraints()
.num_fixed_value_arguments(); .num_fixed_value_arguments();
@@ -849,18 +870,17 @@ impl DataFlowGraph {
/// ///
/// Panics if the instruction doesn't support arguments. /// Panics if the instruction doesn't support arguments.
pub fn append_inst_arg(&mut self, inst: Inst, new_arg: Value) { pub fn append_inst_arg(&mut self, inst: Inst, new_arg: Value) {
let mut branch_values = self.insts[inst] self.insts[inst]
.take_value_list() .value_list_mut()
.expect("the instruction doesn't have value arguments"); .expect("the instruction doesn't have value arguments")
branch_values.push(new_arg, &mut self.value_lists); .push(new_arg, &mut self.value_lists);
self.insts[inst].put_value_list(branch_values)
} }
/// Clone an instruction, attaching new result `Value`s and /// Clone an instruction, attaching new result `Value`s and
/// returning them. /// returning them.
pub fn clone_inst(&mut self, inst: Inst) -> Inst { pub fn clone_inst(&mut self, inst: Inst) -> Inst {
// First, add a clone of the InstructionData. // 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); let new_inst = self.make_inst(inst_data);
// Get the controlling type variable. // Get the controlling type variable.
let ctrl_typevar = self.ctrl_typevar(inst); 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. /// Get the controlling type variable, or `INVALID` if `inst` isn't polymorphic.
pub fn ctrl_typevar(&self, inst: Inst) -> Type { 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() { if !constraints.is_polymorphic() {
types::INVALID types::INVALID
@@ -955,12 +975,12 @@ impl DataFlowGraph {
// Not all instruction formats have a designated operand, but in that case // Not all instruction formats have a designated operand, but in that case
// `requires_typevar_operand()` should never be true. // `requires_typevar_operand()` should never be true.
self.value_type( self.value_type(
self[inst] self.insts[inst]
.typevar_operand(&self.value_lists) .typevar_operand(&self.value_lists)
.unwrap_or_else(|| { .unwrap_or_else(|| {
panic!( panic!(
"Instruction format for {:?} doesn't have a designated operand", "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. /// basic blocks.
impl DataFlowGraph { impl DataFlowGraph {
/// Create a new basic block. /// Create a new basic block.
@@ -1187,9 +1191,9 @@ impl<'a> fmt::Display for DisplayInst<'a> {
let typevar = dfg.ctrl_typevar(inst); let typevar = dfg.ctrl_typevar(inst);
if typevar.is_invalid() { if typevar.is_invalid() {
write!(f, "{}", dfg[inst].opcode())?; write!(f, "{}", dfg.insts[inst].opcode())?;
} else { } else {
write!(f, "{}.{}", dfg[inst].opcode(), typevar)?; write!(f, "{}.{}", dfg.insts[inst].opcode(), typevar)?;
} }
write_operands(f, dfg, inst) write_operands(f, dfg, inst)
} }
@@ -1376,7 +1380,7 @@ mod tests {
// Immutable reference resolution. // Immutable reference resolution.
{ {
let immdfg = &dfg; let immdfg = &dfg;
let ins = &immdfg[inst]; let ins = &immdfg.insts[inst];
assert_eq!(ins.opcode(), Opcode::Iconst); 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`. /// Note that this method ignores multi-destination branches like `br_table`.
pub fn change_branch_destination(&mut self, inst: Inst, new_dest: Block) { 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 => (), None => (),
Some(inst_dest) => *inst_dest = new_dest, Some(inst_dest) => *inst_dest = new_dest,
} }
@@ -309,7 +309,7 @@ impl FunctionStencil {
}); });
if default_dest == Some(old_dest) { if default_dest == Some(old_dest) {
match &mut self.dfg[inst] { match &mut self.dfg.insts[inst] {
InstructionData::BranchTable { destination, .. } => { InstructionData::BranchTable { destination, .. } => {
*destination = new_dest; *destination = new_dest;
} }
@@ -333,13 +333,13 @@ impl FunctionStencil {
let inst_iter = self.layout.block_insts(block); let inst_iter = self.layout.block_insts(block);
// Ignore all instructions prior to the first branch. // 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 // A conditional branch is permitted in a basic block only when followed
// by a terminal jump instruction. // by a terminal jump instruction.
if let Some(_branch) = inst_iter.next() { if let Some(_branch) = inst_iter.next() {
if let Some(next) = inst_iter.next() { if let Some(next) = inst_iter.next() {
match dfg[next].opcode() { match dfg.insts[next].opcode() {
Opcode::Jump => (), Opcode::Jump => (),
_ => return Err((next, "post-branch instruction not jump")), _ => return Err((next, "post-branch instruction not jump")),
} }
@@ -377,7 +377,7 @@ impl FunctionStencil {
.zip(self.dfg.inst_results(src)) .zip(self.dfg.inst_results(src))
.all(|(a, b)| self.dfg.value_type(*a) == self.dfg.value_type(*b))); .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); self.layout.remove_inst(src);
} }

View File

@@ -600,7 +600,7 @@ impl Layout {
// If two, the former is conditional and the latter is unconditional. // If two, the former is conditional and the latter is unconditional.
let last = self.last_inst(block)?; let last = self.last_inst(block)?;
if let Some(prev) = self.prev_inst(last) { if let Some(prev) = self.prev_inst(last) {
if dfg[prev].opcode().is_branch() { if dfg.insts[prev].opcode().is_branch() {
return Some(prev); 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() { while let Some(_block) = pos.next_block() {
let mut prev_pos = pos.position(); let mut prev_pos = pos.position();
while let Some(inst) = pos.next_inst() { while let Some(inst) = pos.next_inst() {
match pos.func.dfg[inst] { match pos.func.dfg.insts[inst] {
// control flow // control flow
InstructionData::CondTrap { InstructionData::CondTrap {
opcode: opcode:

View File

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

View File

@@ -251,7 +251,7 @@ impl BlockLoweringOrder {
block_succ_range[block] = (block_succ_start, block_succ_end); block_succ_range[block] = (block_succ_start, block_succ_end);
for inst in f.layout.block_likely_branches(block) { 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. // Implicit output edge for any return.
block_out_count[block] += 1; block_out_count[block] += 1;
} }
@@ -279,7 +279,7 @@ impl BlockLoweringOrder {
for inst in f.layout.block_likely_branches(block) { for inst in f.layout.block_likely_branches(block) {
// If the block has a branch with any "fixed args" // If the block has a branch with any "fixed args"
// (not blockparam 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 // ... then force a minimum successor count of
// two, so the below algorithm cannot put // two, so the below algorithm cannot put
// edge-moves on the end of the block. // edge-moves on the end of the block.

View File

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

View File

@@ -368,7 +368,7 @@ impl<'func, I: VCodeInst> Lower<'func, I> {
"bb {} inst {} ({:?}): result {} regs {:?}", "bb {} inst {} ({:?}): result {} regs {:?}",
bb, bb,
inst, inst,
f.dfg[inst], f.dfg.insts[inst],
result, result,
regs, regs,
); );
@@ -705,7 +705,7 @@ impl<'func, I: VCodeInst> Lower<'func, I> {
// then reverse these and append to the VCode at the end of // then reverse these and append to the VCode at the end of
// each IR instruction. // each IR instruction.
for inst in self.f.layout.block_insts(block).rev() { 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); let has_side_effect = has_lowering_side_effect(self.f, inst);
// If inst has been sunk to another location, skip it. // If inst has been sunk to another location, skip it.
if self.is_inst_sunk(inst) { if self.is_inst_sunk(inst) {
@@ -736,14 +736,14 @@ impl<'func, I: VCodeInst> Lower<'func, I> {
// Skip lowering branches; these are handled separately // Skip lowering branches; these are handled separately
// (see `lower_clif_branches()` below). // (see `lower_clif_branches()` below).
if self.f.dfg[inst].opcode().is_branch() { if self.f.dfg.insts[inst].opcode().is_branch() {
continue; continue;
} }
// Normal instruction: codegen if the instruction is side-effecting // Normal instruction: codegen if the instruction is side-effecting
// or any of its outputs its used. // or any of its outputs its used.
if has_side_effect || value_needed { 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 temp_regs = backend.lower(self, inst).unwrap_or_else(|| {
let ty = if self.num_outputs(inst) > 0 { let ty = if self.num_outputs(inst) > 0 {
Some(self.output_ty(inst, 0)) Some(self.output_ty(inst, 0))
@@ -975,7 +975,7 @@ impl<'func, I: VCodeInst> Lower<'func, I> {
if last_inst != Some(inst) { if last_inst != Some(inst) {
branches.push(inst); branches.push(inst);
} else { } 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); debug_assert!(branches.len() == 1);
} }
last_inst = Some(inst); last_inst = Some(inst);
@@ -1104,7 +1104,7 @@ impl<'func, I: VCodeInst> Lower<'func, I> {
impl<'func, I: VCodeInst> Lower<'func, I> { impl<'func, I: VCodeInst> Lower<'func, I> {
/// Get the instdata for a given IR instruction. /// Get the instdata for a given IR instruction.
pub fn data(&self, ir_inst: Inst) -> &InstructionData { 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. /// 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. /// Returns the memory flags of a given memory access.
pub fn memflags(&self, ir_inst: Inst) -> Option<MemFlags> { 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::AtomicCas { flags, .. } => Some(flags),
&InstructionData::AtomicRmw { flags, .. } => Some(flags), &InstructionData::AtomicRmw { flags, .. } => Some(flags),
&InstructionData::Load { 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 /// arithmetic operation. This ignores operations like `fneg`, `fabs`, or
/// `fcopysign` that only operate on the sign bit of a floating point value. /// `fcopysign` that only operate on the sign bit of a floating point value.
fn is_fp_arith(pos: &mut FuncCursor, inst: Inst) -> bool { fn is_fp_arith(pos: &mut FuncCursor, inst: Inst) -> bool {
match pos.func.dfg[inst] { match pos.func.dfg.insts[inst] {
InstructionData::Unary { opcode, .. } => { InstructionData::Unary { opcode, .. } => {
opcode == Opcode::Ceil opcode == Opcode::Ceil
|| opcode == Opcode::Floor || opcode == Opcode::Floor

View File

@@ -76,7 +76,7 @@ where
ValueDef::Result(inst, _) if ctx.ctx.func.dfg.inst_results(inst).len() == 1 => { ValueDef::Result(inst, _) if ctx.ctx.func.dfg.inst_results(inst).len() == 1 => {
let ty = ctx.ctx.func.dfg.value_type(value); let ty = ctx.ctx.func.dfg.value_type(value);
trace!(" -> value of type {}", ty); 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); let mut summary = BlockSummary::new(&bump, formals);
for inst in func.layout.block_insts(b) { 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 // Note that multi-dest transfers (i.e., branch tables) don't
// carry parameters in our IR, so we only have to care about // carry parameters in our IR, so we only have to care about
// `SingleDest` here. // `SingleDest` here.
@@ -378,9 +378,9 @@ pub fn do_remove_constant_phis(func: &mut Function, domtree: &mut DominatorTree)
continue; 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_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() .opcode()
.constraints() .constraints()
.num_fixed_value_arguments(); .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); 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 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() { if opcode.is_branch() && !opcode.is_terminator() {
scope_stack.push(func.layout.next_inst(inst).unwrap()); 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. // 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; continue;
} }
let ctrl_typevar = func.dfg.ctrl_typevar(inst); let ctrl_typevar = func.dfg.ctrl_typevar(inst);
let key = HashKey { let key = HashKey {
inst: func.dfg[inst], inst: func.dfg.insts[inst],
ty: ctrl_typevar, ty: ctrl_typevar,
pos: &pos, 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, /// 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. /// signedness, operation size and div-vs-rem-ness in a handy bundle.
fn get_div_info(inst: Inst, dfg: &DataFlowGraph) -> Option<DivRemByConstInfo> { 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 { let (is_signed, is_rem) = match opcode {
Opcode::UdivImm => (false, false), Opcode::UdivImm => (false, false),
Opcode::UremImm => (false, true), Opcode::UremImm => (false, true),
@@ -478,7 +478,7 @@ enum BranchOrderKind {
/// layout-wise. The unconditional jump can then become a fallthrough. /// layout-wise. The unconditional jump can then become a fallthrough.
fn branch_order(pos: &mut FuncCursor, cfg: &mut ControlFlowGraph, block: Block, inst: Inst) { 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) = 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 { InstructionData::Jump {
opcode: Opcode::Jump, opcode: Opcode::Jump,
destination, destination,
@@ -500,7 +500,7 @@ fn branch_order(pos: &mut FuncCursor, cfg: &mut ControlFlowGraph, block: Block,
return; 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 let Some(prev_dest) = prev_inst_data.branch_destination() {
if prev_dest != next_block { if prev_dest != next_block {
@@ -609,7 +609,7 @@ mod simplify {
if let InstructionData::UnaryImm { if let InstructionData::UnaryImm {
opcode: Opcode::Iconst, opcode: Opcode::Iconst,
imm, imm,
} = dfg[candidate_inst] } = dfg.insts[candidate_inst]
{ {
return Some(imm); return Some(imm);
} }
@@ -631,7 +631,7 @@ mod simplify {
opcode: Opcode::IshlImm, opcode: Opcode::IshlImm,
arg: prev_arg, arg: prev_arg,
imm: prev_imm, imm: prev_imm,
} = &pos.func.dfg[arg_inst] } = &pos.func.dfg.insts[arg_inst]
{ {
if imm != *prev_imm { if imm != *prev_imm {
return false; return false;
@@ -677,7 +677,7 @@ mod simplify {
/// would likely be expanded back into an instruction on smaller types with the same initial /// would likely be expanded back into an instruction on smaller types with the same initial
/// opcode, creating unnecessary churn. /// opcode, creating unnecessary churn.
fn simplify(pos: &mut FuncCursor, inst: Inst, native_word_width: u32) { 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 } => { InstructionData::Binary { opcode, args } => {
if let Some(mut imm) = resolve_imm64_value(&pos.func.dfg, args[1]) { if let Some(mut imm) = resolve_imm64_value(&pos.func.dfg, args[1]) {
let new_opcode = match opcode { let new_opcode = match opcode {
@@ -748,7 +748,7 @@ mod simplify {
opcode: prev_opcode, opcode: prev_opcode,
arg: prev_arg, arg: prev_arg,
imm: prev_imm, imm: prev_imm,
} = &pos.func.dfg[arg_inst] } = &pos.func.dfg.insts[arg_inst]
{ {
if opcode == *prev_opcode if opcode == *prev_opcode
&& ty == pos.func.dfg.ctrl_typevar(arg_inst) && ty == pos.func.dfg.ctrl_typevar(arg_inst)
@@ -846,7 +846,7 @@ mod simplify {
opcode: br_opcode, opcode: br_opcode,
args: ref br_args, args: ref br_args,
.. ..
} = pos.func.dfg[inst] } = pos.func.dfg.insts[inst]
{ {
let first_arg = { let first_arg = {
let args = pos.func.dfg.inst_args(inst); let args = pos.func.dfg.inst_args(inst);
@@ -865,7 +865,7 @@ mod simplify {
arg: cmp_arg, arg: cmp_arg,
cond: cmp_cond, cond: cmp_cond,
imm: cmp_imm, imm: cmp_imm,
} = pos.func.dfg[icmp_inst] } = pos.func.dfg.insts[icmp_inst]
{ {
let cmp_imm: i64 = cmp_imm.into(); let cmp_imm: i64 = cmp_imm.into();
if cmp_imm != 0 { 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; 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; *opcode = info.new_opcode;
} else { } else {
panic!(); panic!();

View File

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

View File

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

View File

@@ -276,7 +276,7 @@ fn decorate_block<FW: FuncWriter>(
// if it can't be trivially inferred. // if it can't be trivially inferred.
// //
fn type_suffix(func: &Function, inst: Inst) -> Option<Type> { 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(); let constraints = inst_data.opcode().constraints();
if !constraints.is_polymorphic() { if !constraints.is_polymorphic() {
@@ -357,7 +357,7 @@ fn write_instruction(
} }
// Then the opcode, possibly with a '.type' suffix. // 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) { match type_suffix(func, inst) {
Some(suf) => write!(w, "{}.{}", opcode, suf)?, 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 { pub fn write_operands(w: &mut dyn Write, dfg: &DataFlowGraph, inst: Inst) -> fmt::Result {
let pool = &dfg.value_lists; let pool = &dfg.value_lists;
use crate::ir::instructions::InstructionData::*; use crate::ir::instructions::InstructionData::*;
match dfg[inst] { match dfg.insts[inst] {
AtomicRmw { op, args, .. } => write!(w, " {} {}, {}", op, args[0], args[1]), AtomicRmw { op, args, .. } => write!(w, " {} {}, {}", op, args[0], args[1]),
AtomicCas { args, .. } => write!(w, " {}, {}, {}", args[0], args[1], args[2]), AtomicCas { args, .. } => write!(w, " {}, {}, {}", args[0], args[1], args[2]),
LoadNoOffset { flags, arg, .. } => write!(w, "{} {}", flags, arg), 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 = " ; "; let mut sep = " ; ";
for &arg in dfg.inst_args(inst) { for &arg in dfg.inst_args(inst) {
if let ValueDef::Result(src, _) = dfg.value_def(arg) { 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(), UnaryImm { imm, .. } => imm.to_string(),
UnaryIeee32 { imm, .. } => imm.to_string(), UnaryIeee32 { imm, .. } => imm.to_string(),
UnaryIeee64 { 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 /// **Note:** You are responsible for maintaining the coherence with the arguments of
/// other jump instructions. /// other jump instructions.
pub fn change_jump_destination(&mut self, inst: Inst, new_dest: Block) { 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() .branch_destination_mut()
.expect("you want to change the jump destination of a non-jump instruction"); .expect("you want to change the jump destination of a non-jump instruction");
self.func_ctx.ssa.remove_block_predecessor(*old_dest, inst); 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 // 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 { InstructionData::BranchTable {
destination, table, .. destination, table, ..
} => { } => {
@@ -1192,7 +1192,7 @@ mod tests {
ssa.use_var(&mut func, x_var, I32, block0); ssa.use_var(&mut func, x_var, I32, block0);
assert_eq!(func.dfg.num_block_params(block0), 0); assert_eq!(func.dfg.num_block_params(block0), 0);
assert_eq!( assert_eq!(
func.dfg[func.layout.first_inst(block0).unwrap()].opcode(), func.dfg.insts[func.layout.first_inst(block0).unwrap()].opcode(),
Opcode::Iconst Opcode::Iconst
); );
} }
@@ -1213,7 +1213,7 @@ mod tests {
ssa.seal_block(block0, &mut func); ssa.seal_block(block0, &mut func);
assert_eq!(func.dfg.num_block_params(block0), 0); assert_eq!(func.dfg.num_block_params(block0), 0);
assert_eq!( assert_eq!(
func.dfg[func.layout.first_inst(block0).unwrap()].opcode(), func.dfg.insts[func.layout.first_inst(block0).unwrap()].opcode(),
Opcode::Iconst 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 /// Returns true/false if this instruction can trap
fn can_fcvt_trap(pos: &FuncCursor, inst: Inst) -> bool { 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) matches!(opcode, Opcode::FcvtToUint | Opcode::FcvtToSint)
} }
@@ -66,7 +66,7 @@ fn float_limits(
/// Prepend instructions to inst to avoid traps /// Prepend instructions to inst to avoid traps
fn insert_fcvt_sequence(pos: &mut FuncCursor, inst: Inst) { fn insert_fcvt_sequence(pos: &mut FuncCursor, inst: Inst) {
let dfg = &pos.func.dfg; let dfg = &pos.func.dfg;
let opcode = dfg[inst].opcode(); let opcode = dfg.insts[inst].opcode();
let arg = dfg.inst_args(inst)[0]; let arg = dfg.inst_args(inst)[0];
let float_ty = dfg.value_type(arg); let float_ty = dfg.value_type(arg);
let int_ty = dfg.value_type(dfg.first_result(inst)); 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 /// Returns true/false if this instruction can cause a `int_divz` trap
fn can_int_divz(pos: &FuncCursor, inst: Inst) -> bool { 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!( matches!(
opcode, opcode,
@@ -38,7 +38,7 @@ fn can_int_divz(pos: &FuncCursor, inst: Inst) -> bool {
/// Prepend instructions to inst to avoid `int_divz` traps /// Prepend instructions to inst to avoid `int_divz` traps
fn insert_int_divz_sequence(pos: &mut FuncCursor, inst: Inst) { 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 inst_args = pos.func.dfg.inst_args(inst);
let (lhs, rhs) = (inst_args[0], inst_args[1]); let (lhs, rhs) = (inst_args[0], inst_args[1]);
assert_eq!(pos.func.dfg.value_type(lhs), pos.func.dfg.value_type(rhs)); 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<'_> { impl InstructionContext for DfgInstructionContext<'_> {
fn data(&self) -> InstructionData { fn data(&self) -> InstructionData {
self.1[self.0].clone() self.1.insts[self.0].clone()
} }
fn args(&self) -> &[Value] { 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(_block) = pos.next_block() {
while let Some(inst) = pos.next_inst() { while let Some(inst) = pos.next_inst() {
use self::ir::InstructionData::*; use self::ir::InstructionData::*;
match pos.func.dfg[inst] { match pos.func.dfg.insts[inst] {
Binary { opcode, args } => { Binary { opcode, args } => {
fold_binary(&mut pos.func.dfg, inst, 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::*}; use self::ir::{InstructionData::*, Opcode::*};
match dfg[inst] { match dfg.insts[inst] {
UnaryImm { UnaryImm {
opcode: Iconst, opcode: Iconst,
imm, 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) { fn fold_branch(pos: &mut FuncCursor, inst: ir::Inst, opcode: ir::Opcode) {
let (cond, block, args) = { let (cond, block, args) = {
let values = pos.func.dfg.inst_args(inst); 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]) { match resolve_value_to_imm(&pos.func.dfg, values[0]) {
Some(imm) => imm, Some(imm) => imm,

View File

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

View File

@@ -95,15 +95,15 @@ fuzz_target!(|func: SingleFunction| {
if let ir::InstructionData::UnaryImm { if let ir::InstructionData::UnaryImm {
opcode: ir::Opcode::Iconst, opcode: ir::Opcode::Iconst,
imm, imm,
} = cursor.func.dfg[inst] } = cursor.func.dfg.insts[inst]
{ {
let imm = imm.bits(); let imm = imm.bits();
cursor.func.dfg[inst] = ir::InstructionData::UnaryImm { cursor.func.dfg.insts[inst] = ir::InstructionData::UnaryImm {
opcode: ir::Opcode::Iconst, opcode: ir::Opcode::Iconst,
imm: Imm64::new(imm.checked_add(1).unwrap_or_else(|| imm - 1)), imm: Imm64::new(imm.checked_add(1).unwrap_or_else(|| imm - 1)),
}; };
} else { } else {
cursor.func.dfg[inst] = ir::InstructionData::UnaryImm { cursor.func.dfg.insts[inst] = ir::InstructionData::UnaryImm {
opcode: ir::Opcode::Iconst, opcode: ir::Opcode::Iconst,
imm: Imm64::new(42), imm: Imm64::new(42),
}; };