cranelift_fuzzgen/passes/
int_divz.rs1use crate::FuzzGen;
2use anyhow::Result;
3use cranelift::codegen::cursor::{Cursor, FuncCursor};
4use cranelift::codegen::ir::{Function, Inst, Opcode};
5use cranelift::prelude::{InstBuilder, IntCC};
6
7pub fn do_int_divz_pass(fuzz: &mut FuzzGen, func: &mut Function) -> Result<()> {
8 let ratio = fuzz.config.allowed_int_divz_ratio;
13 let insert_seq = !fuzz.u.ratio(ratio.0, ratio.1)?;
14 if !insert_seq {
15 return Ok(());
16 }
17
18 let mut pos = FuncCursor::new(func);
19 while let Some(_block) = pos.next_block() {
20 while let Some(inst) = pos.next_inst() {
21 if can_int_divz(&pos, inst) {
22 insert_int_divz_sequence(&mut pos, inst);
23 }
24 }
25 }
26 Ok(())
27}
28
29fn can_int_divz(pos: &FuncCursor, inst: Inst) -> bool {
31 let opcode = pos.func.dfg.insts[inst].opcode();
32
33 matches!(
34 opcode,
35 Opcode::Sdiv | Opcode::Udiv | Opcode::Srem | Opcode::Urem
36 )
37}
38
39fn insert_int_divz_sequence(pos: &mut FuncCursor, inst: Inst) {
41 let opcode = pos.func.dfg.insts[inst].opcode();
42 let inst_args = pos.func.dfg.inst_args(inst);
43 let (lhs, rhs) = (inst_args[0], inst_args[1]);
44 assert_eq!(pos.func.dfg.value_type(lhs), pos.func.dfg.value_type(rhs));
45 let ty = pos.func.dfg.value_type(lhs);
46
47 let zero = pos.ins().iconst(ty, 0);
49 let one = pos.ins().iconst(ty, 1);
50 let denominator_is_zero = pos.ins().icmp(IntCC::Equal, rhs, zero);
51
52 let replace_denominator = if matches!(opcode, Opcode::Srem | Opcode::Sdiv) {
53 let int_min = pos.ins().ishl_imm(one, ty.lane_bits() as i64 - 1);
57
58 let neg_one = pos.ins().isub(zero, one);
61
62 let lhs_check = pos.ins().icmp(IntCC::Equal, lhs, int_min);
63 let rhs_check = pos.ins().icmp(IntCC::Equal, rhs, neg_one);
64 let is_invalid = pos.ins().band(lhs_check, rhs_check);
65
66 pos.ins().bor(denominator_is_zero, is_invalid)
68 } else {
69 denominator_is_zero
70 };
71
72 let new_rhs = pos.ins().select(replace_denominator, one, rhs);
74
75 let args = pos.func.dfg.inst_args_mut(inst);
77 args[1] = new_rhs;
78}