#![cfg(feature = "fuzzing")]
use crate::{
function::{
- Block, BlockTermInstKind, BranchSuccParamUse, Constraint, CopyInstKind, FnFields, Inst,
- InstKind, InstStage, KindAndConstraint, Operand, OperandKind, OperandKindDefOnly,
- OperandUse, SSAVal, SSAValDef,
+ Block, BlockTermInstKind, Constraint, CopyInstKind, Entries, EntriesMut, FnFields, Inst,
+ InstKind, InstStage, KindAndConstraint, Operand, OperandKind, OperandKindDefOnly, SSAVal,
+ SSAValDef,
},
- index::{BlockIdx, InstIdx, InstRange, SSAValIdx},
+ index::{BlockIdx, InstIdx, InstRange, OperandIdx, RangeIter, SSAValIdx},
interned::{GlobalState, Intern},
loc::Ty,
loc_set::LocSet,
let idom = self.func.blocks[block_idx].immediate_dominator;
self.available_ssa_vals_at_end(idom)
}
- fn new_ssa_val(ssa_vals: &mut Vec<SSAVal>, ty: Ty, def: SSAValDef) -> SSAValIdx {
+ fn new_ssa_val(ssa_vals: &mut Vec<SSAVal>, ty: Ty) -> SSAValIdx {
let retval = SSAValIdx::new(ssa_vals.len());
ssa_vals.push(SSAVal {
ty,
- def,
+ def: SSAValDef::invalid(),
operand_uses: Default::default(),
branch_succ_param_uses: Default::default(),
});
}
let mut possible_src_operand_idxs = vec![];
let mut possible_dest_operand_idxs = vec![];
- for (operand_idx, operand) in operands.iter().enumerate() {
+ for (operand_idx, operand) in operands.entries() {
match operand.kind_and_constraint.kind() {
OperandKind::Use => possible_src_operand_idxs.push(operand_idx),
OperandKind::Def => possible_dest_operand_idxs.push(operand_idx),
// src can have duplicates, so pick randomly
let possible_src_operand_idxs = (0..u.int_in_range(1..=3)?)
.map(|_| u.choose(&possible_src_operand_idxs).copied())
- .collect::<Result<Vec<usize>, Error>>()?;
+ .collect::<Result<Vec<OperandIdx>, Error>>()?;
// dest can't have duplicates, so shuffle
let len = possible_dest_operand_idxs.len();
for i in 0..len {
}
fn run(&mut self) -> Result<(), Error> {
let block_count = self.u.int_in_range(1..=10u16)?;
- for block_idx in 0..block_count as usize {
- let block_idx = BlockIdx::new(block_idx);
+ for block_idx in RangeIter::<BlockIdx>::from_usize_range(0..block_count as usize) {
let mut params = Vec::new();
if block_idx != BlockIdx::ENTRY_BLOCK {
- for param_idx in 0..self.u.int_in_range(0..=10)? {
+ for _param_idx in 0..self.u.int_in_range(0..=10)? {
let ty = self.u.arbitrary()?;
- params.push(Self::new_ssa_val(
- &mut self.func.ssa_vals,
- ty,
- SSAValDef::BlockParam {
- block: block_idx,
- param_idx,
- },
- ));
+ params.push(Self::new_ssa_val(&mut self.func.ssa_vals, ty));
}
}
let end = InstIdx::new(self.func.insts.len());
let kind = self.u.arbitrary()?;
let ssa_val = if let OperandKind::Def = kind {
let ty = self.u.arbitrary()?;
- let def = SSAValDef::Operand {
- inst: InstIdx::new(self.func.insts.len()),
- operand_idx: operands.len(),
- };
- Self::new_ssa_val(&mut self.func.ssa_vals, ty, def)
+ Self::new_ssa_val(&mut self.func.ssa_vals, ty)
} else {
SSAValIdx::new(!0)
};
self.new_inst_in_last_block(inst_kind, operands, clobbers);
}
}
- for block_idx in 0..self.func.blocks.len() {
- let block_idx = BlockIdx::new(block_idx);
+ for block_idx in self.func.blocks.keys() {
let term_idx = self
.func
.try_get_block_term_inst_idx(block_idx)
self.func.blocks[succ].preds.insert(block_idx);
}
}
- for block_idx in 0..self.func.blocks.len() {
- let block_idx = BlockIdx::new(block_idx);
+ for block_idx in self.func.blocks.keys() {
let term_idx = self
.func
.try_get_block_term_inst_idx(block_idx)
});
}
let dominators = dominators::simple_fast(&self.func, BlockIdx::ENTRY_BLOCK);
- for block_idx in 0..self.func.blocks.len() {
- let block_idx = BlockIdx::new(block_idx);
+ for block_idx in self.func.blocks.keys() {
self.func.blocks[block_idx].immediate_dominator =
dominators.immediate_dominator(block_idx);
}
// must have filled dominators first since available_ssa_vals_before_start() needs them
- for block_idx in 0..self.func.blocks.len() {
- let block_idx = BlockIdx::new(block_idx);
+ for block_idx in self.func.blocks.keys() {
let mut available_ssa_vals = self.available_ssa_vals_before_start(block_idx);
available_ssa_vals.extend(&self.func.ssa_vals, &self.func.blocks[block_idx].params);
for inst_idx in self.func.blocks[block_idx].insts {
let inst = &mut self.func.insts[inst_idx];
- for (operand_idx, operand) in inst.operands.iter_mut().enumerate() {
+ for (_operand_idx, operand) in inst.operands.entries_mut() {
if operand.kind_and_constraint.kind() != OperandKind::Use {
continue;
}
ssa_val: Self::new_ssa_val(
&mut self.func.ssa_vals,
self.u.arbitrary()?,
- SSAValDef::Operand {
- inst: inst_idx,
- operand_idx,
- },
),
stage: self.u.arbitrary()?,
};
} else {
operand.ssa_val = *self.u.choose(&available_ssa_vals.all)?;
}
- self.func.ssa_vals[operand.ssa_val]
- .operand_uses
- .insert(OperandUse {
- inst: inst_idx,
- operand_idx,
- });
}
available_ssa_vals.extend(
&self.func.ssa_vals,
InstKind::BlockTerm(block_term_inst_kind) => {
for (&succ_idx, params) in &mut block_term_inst_kind.succs_and_params {
let succ = &self.func.blocks[succ_idx];
- for (param_idx, &succ_param) in succ.params.iter().enumerate() {
+ for (_param_idx, &succ_param) in succ.params.entries() {
let succ_param_ty = self.func.ssa_vals[succ_param].ty;
let choices = available_ssa_vals.per_ty(succ_param_ty);
let ssa_val_idx;
if choices.is_empty() {
// no available ssa vals with correct type, fix that by appending def operand with that type
- ssa_val_idx = Self::new_ssa_val(
- &mut self.func.ssa_vals,
- succ_param_ty,
- SSAValDef::Operand {
- inst: inst_idx,
- operand_idx: inst.operands.len(),
- },
- );
+ ssa_val_idx =
+ Self::new_ssa_val(&mut self.func.ssa_vals, succ_param_ty);
available_ssa_vals.extend(&self.func.ssa_vals, [ssa_val_idx]);
- self.func.ssa_vals[ssa_val_idx].operand_uses.insert(
- OperandUse {
- inst: inst_idx,
- operand_idx: inst.operands.len(),
- },
- );
inst.operands.push(Operand {
kind_and_constraint: KindAndConstraint::Constraint {
kind: OperandKind::Def,
ssa_val_idx = *self.u.choose(choices)?
};
params.push(ssa_val_idx);
- self.func.ssa_vals[ssa_val_idx]
- .branch_succ_param_uses
- .insert(BranchSuccParamUse {
- branch_inst: inst_idx,
- succ: succ_idx,
- param_idx,
- });
}
}
}
}
}
}
- for (inst_idx, inst) in self.func.insts.iter_mut().enumerate() {
- let inst_idx = InstIdx::new(inst_idx);
- let mut reusable_operand_idxs: HashMap<Ty, Vec<usize>> = HashMap::new();
- for (operand_idx, operand) in inst.operands.iter().enumerate() {
+ for (inst_idx, inst) in self.func.insts.entries_mut() {
+ let mut reusable_operand_idxs: HashMap<Ty, Vec<OperandIdx>> = HashMap::new();
+ for (operand_idx, operand) in inst.operands.entries() {
if operand.kind_and_constraint.kind() == OperandKind::Use {
reusable_operand_idxs
.entry(self.func.ssa_vals[operand.ssa_val].ty)
}
}
let mut used_locs = EnumMap::<InstStage, LocSet>::default();
- for operand_idx in 0..inst.operands.len() {
+ for operand_idx in inst.operands.keys() {
let operand = &inst.operands[operand_idx];
let operand_ty = self.func.ssa_vals[operand.ssa_val].ty;
if operand.kind_and_constraint.kind() == OperandKind::Def && self.u.arbitrary()? {
- let reuse_operand_idx = self.u.choose_index(inst.operands.len())?;
- let reuse_operand = &inst.operands[reuse_operand_idx];
- if reuse_operand_idx != operand_idx
- && reuse_operand.kind_and_constraint.kind() == OperandKind::Use
- && self.func.ssa_vals[reuse_operand.ssa_val].ty == operand_ty
- {
- inst.operands[operand_idx].kind_and_constraint = KindAndConstraint::Reuse {
- kind: OperandKindDefOnly,
- reuse_operand_idx,
- };
- continue;
+ let reusable_operand_idxs = reusable_operand_idxs
+ .get(&operand_ty)
+ .map(Deref::deref)
+ .unwrap_or_default();
+ if !reusable_operand_idxs.is_empty() {
+ let reuse_operand_idx = *self.u.choose(reusable_operand_idxs)?;
+ if reuse_operand_idx != operand_idx {
+ inst.operands[operand_idx].kind_and_constraint =
+ KindAndConstraint::Reuse {
+ kind: OperandKindDefOnly,
+ reuse_operand_idx,
+ };
+ continue;
+ }
}
}
let operand = &mut inst.operands[operand_idx];