cranelift_fuzzgen/passes/
fcvt.rs1use crate::FuzzGen;
2use anyhow::Result;
3use cranelift::codegen::cursor::{Cursor, FuncCursor};
4use cranelift::codegen::ir::{Function, Inst, Opcode};
5use cranelift::prelude::{types::*, *};
6
7pub fn do_fcvt_trap_pass(fuzz: &mut FuzzGen, func: &mut Function) -> Result<()> {
8 let ratio = fuzz.config.allowed_fcvt_traps_ratio;
9 let insert_seq = !fuzz.u.ratio(ratio.0, ratio.1)?;
10 if !insert_seq {
11 return Ok(());
12 }
13
14 let mut pos = FuncCursor::new(func);
15 while let Some(_block) = pos.next_block() {
16 while let Some(inst) = pos.next_inst() {
17 if can_fcvt_trap(&pos, inst) {
18 insert_fcvt_sequence(&mut pos, inst);
19 }
20 }
21 }
22 Ok(())
23}
24
25fn can_fcvt_trap(pos: &FuncCursor, inst: Inst) -> bool {
27 let opcode = pos.func.dfg.insts[inst].opcode();
28
29 matches!(opcode, Opcode::FcvtToUint | Opcode::FcvtToSint)
30}
31
32fn float_limits(
40 pos: &mut FuncCursor,
41 float_ty: Type,
42 int_ty: Type,
43 is_signed: bool,
44) -> (Value, Value) {
45 let (min_int, max_int) = int_ty.bounds(is_signed);
46
47 if float_ty == F32 {
48 let (min, max) = if is_signed {
49 ((min_int as i128) as f32, (max_int as i128) as f32)
50 } else {
51 (min_int as f32, max_int as f32)
52 };
53
54 (pos.ins().f32const(min - 1.0), pos.ins().f32const(max + 1.0))
55 } else {
56 let (min, max) = if is_signed {
57 ((min_int as i128) as f64, (max_int as i128) as f64)
58 } else {
59 (min_int as f64, max_int as f64)
60 };
61
62 (pos.ins().f64const(min - 1.0), pos.ins().f64const(max + 1.0))
63 }
64}
65
66fn insert_fcvt_sequence(pos: &mut FuncCursor, inst: Inst) {
68 let dfg = &pos.func.dfg;
69 let opcode = dfg.insts[inst].opcode();
70 let arg = dfg.inst_args(inst)[0];
71 let float_ty = dfg.value_type(arg);
72 let int_ty = dfg.value_type(dfg.first_result(inst));
73
74 let is_nan = pos.ins().fcmp(FloatCC::NotEqual, arg, arg);
76
77 let is_signed = opcode == Opcode::FcvtToSint;
81 let (min, max) = float_limits(pos, float_ty, int_ty, is_signed);
82 let underflows = pos.ins().fcmp(FloatCC::LessThanOrEqual, arg, min);
83 let overflows = pos.ins().fcmp(FloatCC::GreaterThanOrEqual, arg, max);
84
85 let overflows_int = pos.ins().bor(underflows, overflows);
87 let is_invalid = pos.ins().bor(is_nan, overflows_int);
88
89 let one = if float_ty == F32 {
90 pos.ins().f32const(1.0)
91 } else {
92 pos.ins().f64const(1.0)
93 };
94 let new_arg = pos.ins().select(is_invalid, one, arg);
95
96 pos.func.dfg.inst_args_mut(inst)[0] = new_arg;
98}