+ fn make_copy_inst_kind(
+ u: &mut Unstructured<'_>,
+ // takes ref to Vec since Index<SSAValIdx> is only implemented for Vec
+ ssa_vals: &Vec<SSAVal>,
+ operands: &[Operand],
+ ) -> Result<Option<CopyInstKind>, Error> {
+ if operands.is_empty() {
+ return Ok(None);
+ }
+ let mut possible_src_operand_idxs = vec![];
+ let mut possible_dest_operand_idxs = vec![];
+ for (operand_idx, operand) in operands.iter().enumerate() {
+ match operand.kind_and_constraint.kind() {
+ OperandKind::Use => possible_src_operand_idxs.push(operand_idx),
+ OperandKind::Def => possible_dest_operand_idxs.push(operand_idx),
+ }
+ }
+ if possible_src_operand_idxs.is_empty() || possible_dest_operand_idxs.is_empty() {
+ return Ok(None);
+ }
+ let mut src_operand_idxs = vec![];
+ for _ in 0..u.int_in_range(1..=3)? {
+ // src can have duplicates, don't remove chosen items
+ src_operand_idxs.push(*u.choose(&possible_src_operand_idxs)?);
+ }
+ for src_operand_idxs_len in (1..=src_operand_idxs.len()).rev() {
+ let mut operand_types = src_operand_idxs[..src_operand_idxs_len]
+ .iter()
+ .map(|&idx| ssa_vals[operands[idx].ssa_val].ty);
+ let copy_ty = operand_types.next_back().unwrap();
+ let copy_ty = operand_types
+ .filter(|v| v.base_ty == copy_ty.base_ty)
+ .try_fold(copy_ty, Ty::try_concat);
+ let Ok(copy_ty) = copy_ty else {
+ continue;
+ };
+ let mut possible_dest_operand_idxs = possible_dest_operand_idxs.clone();
+ let mut dest_operand_idxs = vec![];
+ let mut dest_copy_ty: Option<Ty> = None;
+ for _ in 0..u.int_in_range(1..=3)? {
+ if possible_dest_operand_idxs.is_empty() {
+ break;
+ }
+ // dest can't have duplicates, so remove items that were chosen
+ let chosen_index = u.choose_index(possible_src_operand_idxs.len())?;
+ let dest_operand_idx = possible_dest_operand_idxs.swap_remove(chosen_index);
+ let dest_operand_ty = ssa_vals[operands[dest_operand_idx].ssa_val].ty;
+ if dest_operand_ty.base_ty != copy_ty.base_ty
+ || dest_operand_ty.reg_len > copy_ty.reg_len
+ {
+ continue;
+ }
+ let next_dest_copy_ty = if let Some(dest_copy_ty) = dest_copy_ty {
+ let Ok(ty) = dest_copy_ty.try_concat(dest_operand_ty) else {
+ continue;
+ };
+ ty
+ } else {
+ dest_operand_ty
+ };
+ if next_dest_copy_ty.reg_len > copy_ty.reg_len {
+ continue;
+ }
+ dest_copy_ty = Some(next_dest_copy_ty);
+ dest_operand_idxs.push(dest_operand_idx);
+ }
+ if dest_copy_ty != Some(copy_ty) || dest_operand_idxs.is_empty() {
+ continue;
+ }
+ return Ok(Some(CopyInstKind {
+ src_operand_idxs,
+ dest_operand_idxs,
+ copy_ty,
+ }));
+ }
+ Ok(None)