1 use crate::codegen::ir::{ArgumentExtension, ArgumentPurpose}; 2 use crate::config::Config; 3 use anyhow::Result; 4 use arbitrary::{Arbitrary, Unstructured}; 5 use cranelift::codegen::ir::instructions::InstructionFormat; 6 use cranelift::codegen::ir::{types::*, FuncRef, LibCall, UserExternalName, UserFuncName}; 7 use cranelift::codegen::ir::{ 8 AbiParam, Block, ExternalName, Function, JumpTable, Opcode, Signature, StackSlot, Type, Value, 9 }; 10 use cranelift::codegen::isa::CallConv; 11 use cranelift::frontend::{FunctionBuilder, FunctionBuilderContext, Switch, Variable}; 12 use cranelift::prelude::{ 13 EntityRef, ExtFuncData, FloatCC, InstBuilder, IntCC, JumpTableData, StackSlotData, 14 StackSlotKind, 15 }; 16 use std::collections::HashMap; 17 use std::ops::RangeInclusive; 18 19 type BlockSignature = Vec<Type>; 20 21 fn insert_opcode( 22 fgen: &mut FunctionGenerator, 23 builder: &mut FunctionBuilder, 24 opcode: Opcode, 25 args: &'static [Type], 26 rets: &'static [Type], 27 ) -> Result<()> { 28 let mut vals = Vec::with_capacity(args.len()); 29 for &arg in args.into_iter() { 30 let var = fgen.get_variable_of_type(arg)?; 31 let val = builder.use_var(var); 32 vals.push(val); 33 } 34 35 // For pretty much every instruction the control type is the return type 36 // except for Iconcat and Isplit which are *special* and the control type 37 // is the input type. 38 let ctrl_type = if opcode == Opcode::Iconcat || opcode == Opcode::Isplit { 39 args.first() 40 } else { 41 rets.first() 42 } 43 .copied() 44 .unwrap_or(INVALID); 45 46 // Choose the appropriate instruction format for this opcode 47 let (inst, dfg) = match opcode.format() { 48 InstructionFormat::NullAry => builder.ins().NullAry(opcode, ctrl_type), 49 InstructionFormat::Unary => builder.ins().Unary(opcode, ctrl_type, vals[0]), 50 InstructionFormat::Binary => builder.ins().Binary(opcode, ctrl_type, vals[0], vals[1]), 51 InstructionFormat::Ternary => builder 52 .ins() 53 .Ternary(opcode, ctrl_type, vals[0], vals[1], vals[2]), 54 _ => unimplemented!(), 55 }; 56 let results = dfg.inst_results(inst).to_vec(); 57 58 for (val, &ty) in results.into_iter().zip(rets) { 59 let var = fgen.get_variable_of_type(ty)?; 60 builder.def_var(var, val); 61 } 62 Ok(()) 63 } 64 65 fn insert_call( 66 fgen: &mut FunctionGenerator, 67 builder: &mut FunctionBuilder, 68 opcode: Opcode, 69 _args: &'static [Type], 70 _rets: &'static [Type], 71 ) -> Result<()> { 72 assert_eq!(opcode, Opcode::Call, "only call handled at the moment"); 73 let (sig, func_ref) = fgen.u.choose(&fgen.func_refs)?.clone(); 74 75 let actuals = fgen.generate_values_for_signature( 76 builder, 77 sig.params.iter().map(|abi_param| abi_param.value_type), 78 )?; 79 80 builder.ins().call(func_ref, &actuals); 81 Ok(()) 82 } 83 84 fn insert_stack_load( 85 fgen: &mut FunctionGenerator, 86 builder: &mut FunctionBuilder, 87 _opcode: Opcode, 88 _args: &'static [Type], 89 rets: &'static [Type], 90 ) -> Result<()> { 91 let typevar = rets[0]; 92 let slot = fgen.stack_slot_with_size(builder, typevar.bytes())?; 93 let slot_size = builder.func.sized_stack_slots[slot].size; 94 let type_size = typevar.bytes(); 95 let offset = fgen.u.int_in_range(0..=(slot_size - type_size))? as i32; 96 97 let val = builder.ins().stack_load(typevar, slot, offset); 98 let var = fgen.get_variable_of_type(typevar)?; 99 builder.def_var(var, val); 100 101 Ok(()) 102 } 103 104 fn insert_stack_store( 105 fgen: &mut FunctionGenerator, 106 builder: &mut FunctionBuilder, 107 _opcode: Opcode, 108 args: &'static [Type], 109 _rets: &'static [Type], 110 ) -> Result<()> { 111 let typevar = args[0]; 112 let slot = fgen.stack_slot_with_size(builder, typevar.bytes())?; 113 let slot_size = builder.func.sized_stack_slots[slot].size; 114 let type_size = typevar.bytes(); 115 let offset = fgen.u.int_in_range(0..=(slot_size - type_size))? as i32; 116 117 let arg0 = fgen.get_variable_of_type(typevar)?; 118 let arg0 = builder.use_var(arg0); 119 120 builder.ins().stack_store(arg0, slot, offset); 121 Ok(()) 122 } 123 124 fn insert_cmp( 125 fgen: &mut FunctionGenerator, 126 builder: &mut FunctionBuilder, 127 opcode: Opcode, 128 args: &'static [Type], 129 rets: &'static [Type], 130 ) -> Result<()> { 131 let lhs = fgen.get_variable_of_type(args[0])?; 132 let lhs = builder.use_var(lhs); 133 134 let rhs = fgen.get_variable_of_type(args[1])?; 135 let rhs = builder.use_var(rhs); 136 137 let res = if opcode == Opcode::Fcmp { 138 let cc = *fgen.u.choose(FloatCC::all())?; 139 builder.ins().fcmp(cc, lhs, rhs) 140 } else { 141 let cc = *fgen.u.choose(IntCC::all())?; 142 builder.ins().icmp(cc, lhs, rhs) 143 }; 144 145 let var = fgen.get_variable_of_type(rets[0])?; 146 builder.def_var(var, res); 147 Ok(()) 148 } 149 150 fn insert_const( 151 fgen: &mut FunctionGenerator, 152 builder: &mut FunctionBuilder, 153 _opcode: Opcode, 154 _args: &'static [Type], 155 rets: &'static [Type], 156 ) -> Result<()> { 157 let typevar = rets[0]; 158 let var = fgen.get_variable_of_type(typevar)?; 159 let val = fgen.generate_const(builder, typevar)?; 160 builder.def_var(var, val); 161 Ok(()) 162 } 163 164 type OpcodeInserter = fn( 165 fgen: &mut FunctionGenerator, 166 builder: &mut FunctionBuilder, 167 Opcode, 168 &'static [Type], 169 &'static [Type], 170 ) -> Result<()>; 171 172 // TODO: Derive this from the `cranelift-meta` generator. 173 const OPCODE_SIGNATURES: &'static [( 174 Opcode, 175 &'static [Type], // Args 176 &'static [Type], // Rets 177 OpcodeInserter, 178 )] = &[ 179 (Opcode::Nop, &[], &[], insert_opcode), 180 // Iadd 181 (Opcode::Iadd, &[I8, I8], &[I8], insert_opcode), 182 (Opcode::Iadd, &[I16, I16], &[I16], insert_opcode), 183 (Opcode::Iadd, &[I32, I32], &[I32], insert_opcode), 184 (Opcode::Iadd, &[I64, I64], &[I64], insert_opcode), 185 (Opcode::Iadd, &[I128, I128], &[I128], insert_opcode), 186 // Isub 187 (Opcode::Isub, &[I8, I8], &[I8], insert_opcode), 188 (Opcode::Isub, &[I16, I16], &[I16], insert_opcode), 189 (Opcode::Isub, &[I32, I32], &[I32], insert_opcode), 190 (Opcode::Isub, &[I64, I64], &[I64], insert_opcode), 191 (Opcode::Isub, &[I128, I128], &[I128], insert_opcode), 192 // Imul 193 (Opcode::Imul, &[I8, I8], &[I8], insert_opcode), 194 (Opcode::Imul, &[I16, I16], &[I16], insert_opcode), 195 (Opcode::Imul, &[I32, I32], &[I32], insert_opcode), 196 (Opcode::Imul, &[I64, I64], &[I64], insert_opcode), 197 (Opcode::Imul, &[I128, I128], &[I128], insert_opcode), 198 // Udiv 199 // udiv.i128 not implemented on x64: https://github.com/bytecodealliance/wasmtime/issues/4756 200 (Opcode::Udiv, &[I8, I8], &[I8], insert_opcode), 201 (Opcode::Udiv, &[I16, I16], &[I16], insert_opcode), 202 (Opcode::Udiv, &[I32, I32], &[I32], insert_opcode), 203 (Opcode::Udiv, &[I64, I64], &[I64], insert_opcode), 204 // (Opcode::Udiv, &[I128, I128], &[I128], insert_opcode), 205 // Sdiv 206 // sdiv.i128 not implemented on x64: https://github.com/bytecodealliance/wasmtime/issues/4770 207 (Opcode::Sdiv, &[I8, I8], &[I8], insert_opcode), 208 (Opcode::Sdiv, &[I16, I16], &[I16], insert_opcode), 209 (Opcode::Sdiv, &[I32, I32], &[I32], insert_opcode), 210 (Opcode::Sdiv, &[I64, I64], &[I64], insert_opcode), 211 // (Opcode::Sdiv, &[I128, I128], &[I128], insert_opcode), 212 // Rotr 213 (Opcode::Rotr, &[I8, I8], &[I8], insert_opcode), 214 (Opcode::Rotr, &[I8, I16], &[I8], insert_opcode), 215 (Opcode::Rotr, &[I8, I32], &[I8], insert_opcode), 216 (Opcode::Rotr, &[I8, I64], &[I8], insert_opcode), 217 (Opcode::Rotr, &[I8, I128], &[I8], insert_opcode), 218 (Opcode::Rotr, &[I16, I8], &[I16], insert_opcode), 219 (Opcode::Rotr, &[I16, I16], &[I16], insert_opcode), 220 (Opcode::Rotr, &[I16, I32], &[I16], insert_opcode), 221 (Opcode::Rotr, &[I16, I64], &[I16], insert_opcode), 222 (Opcode::Rotr, &[I16, I128], &[I16], insert_opcode), 223 (Opcode::Rotr, &[I32, I8], &[I32], insert_opcode), 224 (Opcode::Rotr, &[I32, I16], &[I32], insert_opcode), 225 (Opcode::Rotr, &[I32, I32], &[I32], insert_opcode), 226 (Opcode::Rotr, &[I32, I64], &[I32], insert_opcode), 227 (Opcode::Rotr, &[I32, I128], &[I32], insert_opcode), 228 (Opcode::Rotr, &[I64, I8], &[I64], insert_opcode), 229 (Opcode::Rotr, &[I64, I16], &[I64], insert_opcode), 230 (Opcode::Rotr, &[I64, I32], &[I64], insert_opcode), 231 (Opcode::Rotr, &[I64, I64], &[I64], insert_opcode), 232 (Opcode::Rotr, &[I64, I128], &[I64], insert_opcode), 233 (Opcode::Rotr, &[I128, I8], &[I128], insert_opcode), 234 (Opcode::Rotr, &[I128, I16], &[I128], insert_opcode), 235 (Opcode::Rotr, &[I128, I32], &[I128], insert_opcode), 236 (Opcode::Rotr, &[I128, I64], &[I128], insert_opcode), 237 (Opcode::Rotr, &[I128, I128], &[I128], insert_opcode), 238 // Rotl 239 (Opcode::Rotl, &[I8, I8], &[I8], insert_opcode), 240 (Opcode::Rotl, &[I8, I16], &[I8], insert_opcode), 241 (Opcode::Rotl, &[I8, I32], &[I8], insert_opcode), 242 (Opcode::Rotl, &[I8, I64], &[I8], insert_opcode), 243 (Opcode::Rotl, &[I8, I128], &[I8], insert_opcode), 244 (Opcode::Rotl, &[I16, I8], &[I16], insert_opcode), 245 (Opcode::Rotl, &[I16, I16], &[I16], insert_opcode), 246 (Opcode::Rotl, &[I16, I32], &[I16], insert_opcode), 247 (Opcode::Rotl, &[I16, I64], &[I16], insert_opcode), 248 (Opcode::Rotl, &[I16, I128], &[I16], insert_opcode), 249 (Opcode::Rotl, &[I32, I8], &[I32], insert_opcode), 250 (Opcode::Rotl, &[I32, I16], &[I32], insert_opcode), 251 (Opcode::Rotl, &[I32, I32], &[I32], insert_opcode), 252 (Opcode::Rotl, &[I32, I64], &[I32], insert_opcode), 253 (Opcode::Rotl, &[I32, I128], &[I32], insert_opcode), 254 (Opcode::Rotl, &[I64, I8], &[I64], insert_opcode), 255 (Opcode::Rotl, &[I64, I16], &[I64], insert_opcode), 256 (Opcode::Rotl, &[I64, I32], &[I64], insert_opcode), 257 (Opcode::Rotl, &[I64, I64], &[I64], insert_opcode), 258 (Opcode::Rotl, &[I64, I128], &[I64], insert_opcode), 259 (Opcode::Rotl, &[I128, I8], &[I128], insert_opcode), 260 (Opcode::Rotl, &[I128, I16], &[I128], insert_opcode), 261 (Opcode::Rotl, &[I128, I32], &[I128], insert_opcode), 262 (Opcode::Rotl, &[I128, I64], &[I128], insert_opcode), 263 (Opcode::Rotl, &[I128, I128], &[I128], insert_opcode), 264 // Ishl 265 // Some test cases disabled due to: https://github.com/bytecodealliance/wasmtime/issues/4699 266 (Opcode::Ishl, &[I8, I8], &[I8], insert_opcode), 267 (Opcode::Ishl, &[I8, I16], &[I8], insert_opcode), 268 (Opcode::Ishl, &[I8, I32], &[I8], insert_opcode), 269 (Opcode::Ishl, &[I8, I64], &[I8], insert_opcode), 270 // (Opcode::Ishl, &[I8, I128], &[I8], insert_opcode), 271 (Opcode::Ishl, &[I16, I8], &[I16], insert_opcode), 272 (Opcode::Ishl, &[I16, I16], &[I16], insert_opcode), 273 (Opcode::Ishl, &[I16, I32], &[I16], insert_opcode), 274 (Opcode::Ishl, &[I16, I64], &[I16], insert_opcode), 275 // (Opcode::Ishl, &[I16, I128], &[I16], insert_opcode), 276 (Opcode::Ishl, &[I32, I8], &[I32], insert_opcode), 277 (Opcode::Ishl, &[I32, I16], &[I32], insert_opcode), 278 (Opcode::Ishl, &[I32, I32], &[I32], insert_opcode), 279 (Opcode::Ishl, &[I32, I64], &[I32], insert_opcode), 280 (Opcode::Ishl, &[I32, I128], &[I32], insert_opcode), 281 (Opcode::Ishl, &[I64, I8], &[I64], insert_opcode), 282 (Opcode::Ishl, &[I64, I16], &[I64], insert_opcode), 283 (Opcode::Ishl, &[I64, I32], &[I64], insert_opcode), 284 (Opcode::Ishl, &[I64, I64], &[I64], insert_opcode), 285 (Opcode::Ishl, &[I64, I128], &[I64], insert_opcode), 286 (Opcode::Ishl, &[I128, I8], &[I128], insert_opcode), 287 (Opcode::Ishl, &[I128, I16], &[I128], insert_opcode), 288 (Opcode::Ishl, &[I128, I32], &[I128], insert_opcode), 289 (Opcode::Ishl, &[I128, I64], &[I128], insert_opcode), 290 (Opcode::Ishl, &[I128, I128], &[I128], insert_opcode), 291 // Sshr 292 (Opcode::Sshr, &[I8, I8], &[I8], insert_opcode), 293 (Opcode::Sshr, &[I8, I16], &[I8], insert_opcode), 294 (Opcode::Sshr, &[I8, I32], &[I8], insert_opcode), 295 (Opcode::Sshr, &[I8, I64], &[I8], insert_opcode), 296 (Opcode::Sshr, &[I8, I128], &[I8], insert_opcode), 297 (Opcode::Sshr, &[I16, I8], &[I16], insert_opcode), 298 (Opcode::Sshr, &[I16, I16], &[I16], insert_opcode), 299 (Opcode::Sshr, &[I16, I32], &[I16], insert_opcode), 300 (Opcode::Sshr, &[I16, I64], &[I16], insert_opcode), 301 (Opcode::Sshr, &[I16, I128], &[I16], insert_opcode), 302 (Opcode::Sshr, &[I32, I8], &[I32], insert_opcode), 303 (Opcode::Sshr, &[I32, I16], &[I32], insert_opcode), 304 (Opcode::Sshr, &[I32, I32], &[I32], insert_opcode), 305 (Opcode::Sshr, &[I32, I64], &[I32], insert_opcode), 306 (Opcode::Sshr, &[I32, I128], &[I32], insert_opcode), 307 (Opcode::Sshr, &[I64, I8], &[I64], insert_opcode), 308 (Opcode::Sshr, &[I64, I16], &[I64], insert_opcode), 309 (Opcode::Sshr, &[I64, I32], &[I64], insert_opcode), 310 (Opcode::Sshr, &[I64, I64], &[I64], insert_opcode), 311 (Opcode::Sshr, &[I64, I128], &[I64], insert_opcode), 312 (Opcode::Sshr, &[I128, I8], &[I128], insert_opcode), 313 (Opcode::Sshr, &[I128, I16], &[I128], insert_opcode), 314 (Opcode::Sshr, &[I128, I32], &[I128], insert_opcode), 315 (Opcode::Sshr, &[I128, I64], &[I128], insert_opcode), 316 (Opcode::Sshr, &[I128, I128], &[I128], insert_opcode), 317 // Ushr 318 (Opcode::Ushr, &[I8, I8], &[I8], insert_opcode), 319 (Opcode::Ushr, &[I8, I16], &[I8], insert_opcode), 320 (Opcode::Ushr, &[I8, I32], &[I8], insert_opcode), 321 (Opcode::Ushr, &[I8, I64], &[I8], insert_opcode), 322 (Opcode::Ushr, &[I8, I128], &[I8], insert_opcode), 323 (Opcode::Ushr, &[I16, I8], &[I16], insert_opcode), 324 (Opcode::Ushr, &[I16, I16], &[I16], insert_opcode), 325 (Opcode::Ushr, &[I16, I32], &[I16], insert_opcode), 326 (Opcode::Ushr, &[I16, I64], &[I16], insert_opcode), 327 (Opcode::Ushr, &[I16, I128], &[I16], insert_opcode), 328 (Opcode::Ushr, &[I32, I8], &[I32], insert_opcode), 329 (Opcode::Ushr, &[I32, I16], &[I32], insert_opcode), 330 (Opcode::Ushr, &[I32, I32], &[I32], insert_opcode), 331 (Opcode::Ushr, &[I32, I64], &[I32], insert_opcode), 332 (Opcode::Ushr, &[I32, I128], &[I32], insert_opcode), 333 (Opcode::Ushr, &[I64, I8], &[I64], insert_opcode), 334 (Opcode::Ushr, &[I64, I16], &[I64], insert_opcode), 335 (Opcode::Ushr, &[I64, I32], &[I64], insert_opcode), 336 (Opcode::Ushr, &[I64, I64], &[I64], insert_opcode), 337 (Opcode::Ushr, &[I64, I128], &[I64], insert_opcode), 338 (Opcode::Ushr, &[I128, I8], &[I128], insert_opcode), 339 (Opcode::Ushr, &[I128, I16], &[I128], insert_opcode), 340 (Opcode::Ushr, &[I128, I32], &[I128], insert_opcode), 341 (Opcode::Ushr, &[I128, I64], &[I128], insert_opcode), 342 (Opcode::Ushr, &[I128, I128], &[I128], insert_opcode), 343 // Uextend 344 (Opcode::Uextend, &[I8], &[I16], insert_opcode), 345 (Opcode::Uextend, &[I8], &[I32], insert_opcode), 346 (Opcode::Uextend, &[I8], &[I64], insert_opcode), 347 (Opcode::Uextend, &[I8], &[I128], insert_opcode), 348 (Opcode::Uextend, &[I16], &[I32], insert_opcode), 349 (Opcode::Uextend, &[I16], &[I64], insert_opcode), 350 (Opcode::Uextend, &[I16], &[I128], insert_opcode), 351 (Opcode::Uextend, &[I32], &[I64], insert_opcode), 352 (Opcode::Uextend, &[I32], &[I128], insert_opcode), 353 (Opcode::Uextend, &[I64], &[I128], insert_opcode), 354 // Sextend 355 (Opcode::Sextend, &[I8], &[I16], insert_opcode), 356 (Opcode::Sextend, &[I8], &[I32], insert_opcode), 357 (Opcode::Sextend, &[I8], &[I64], insert_opcode), 358 (Opcode::Sextend, &[I8], &[I128], insert_opcode), 359 (Opcode::Sextend, &[I16], &[I32], insert_opcode), 360 (Opcode::Sextend, &[I16], &[I64], insert_opcode), 361 (Opcode::Sextend, &[I16], &[I128], insert_opcode), 362 (Opcode::Sextend, &[I32], &[I64], insert_opcode), 363 (Opcode::Sextend, &[I32], &[I128], insert_opcode), 364 (Opcode::Sextend, &[I64], &[I128], insert_opcode), 365 // Ireduce 366 (Opcode::Ireduce, &[I16], &[I8], insert_opcode), 367 (Opcode::Ireduce, &[I32], &[I8], insert_opcode), 368 (Opcode::Ireduce, &[I32], &[I16], insert_opcode), 369 (Opcode::Ireduce, &[I64], &[I8], insert_opcode), 370 (Opcode::Ireduce, &[I64], &[I16], insert_opcode), 371 (Opcode::Ireduce, &[I64], &[I32], insert_opcode), 372 (Opcode::Ireduce, &[I128], &[I8], insert_opcode), 373 (Opcode::Ireduce, &[I128], &[I16], insert_opcode), 374 (Opcode::Ireduce, &[I128], &[I32], insert_opcode), 375 (Opcode::Ireduce, &[I128], &[I64], insert_opcode), 376 // Isplit 377 (Opcode::Isplit, &[I128], &[I64, I64], insert_opcode), 378 // Iconcat 379 (Opcode::Iconcat, &[I64, I64], &[I128], insert_opcode), 380 // Fadd 381 (Opcode::Fadd, &[F32, F32], &[F32], insert_opcode), 382 (Opcode::Fadd, &[F64, F64], &[F64], insert_opcode), 383 // Fmul 384 (Opcode::Fmul, &[F32, F32], &[F32], insert_opcode), 385 (Opcode::Fmul, &[F64, F64], &[F64], insert_opcode), 386 // Fsub 387 (Opcode::Fsub, &[F32, F32], &[F32], insert_opcode), 388 (Opcode::Fsub, &[F64, F64], &[F64], insert_opcode), 389 // Fdiv 390 (Opcode::Fdiv, &[F32, F32], &[F32], insert_opcode), 391 (Opcode::Fdiv, &[F64, F64], &[F64], insert_opcode), 392 // Fmin 393 (Opcode::Fmin, &[F32, F32], &[F32], insert_opcode), 394 (Opcode::Fmin, &[F64, F64], &[F64], insert_opcode), 395 // Fmax 396 (Opcode::Fmax, &[F32, F32], &[F32], insert_opcode), 397 (Opcode::Fmax, &[F64, F64], &[F64], insert_opcode), 398 // FminPseudo 399 (Opcode::FminPseudo, &[F32, F32], &[F32], insert_opcode), 400 (Opcode::FminPseudo, &[F64, F64], &[F64], insert_opcode), 401 // FmaxPseudo 402 (Opcode::FmaxPseudo, &[F32, F32], &[F32], insert_opcode), 403 (Opcode::FmaxPseudo, &[F64, F64], &[F64], insert_opcode), 404 // Fcopysign 405 (Opcode::Fcopysign, &[F32, F32], &[F32], insert_opcode), 406 (Opcode::Fcopysign, &[F64, F64], &[F64], insert_opcode), 407 // Fma 408 (Opcode::Fma, &[F32, F32, F32], &[F32], insert_opcode), 409 (Opcode::Fma, &[F64, F64, F64], &[F64], insert_opcode), 410 // Fabs 411 (Opcode::Fabs, &[F32], &[F32], insert_opcode), 412 (Opcode::Fabs, &[F64], &[F64], insert_opcode), 413 // Fneg 414 (Opcode::Fneg, &[F32], &[F32], insert_opcode), 415 (Opcode::Fneg, &[F64], &[F64], insert_opcode), 416 // Sqrt 417 (Opcode::Sqrt, &[F32], &[F32], insert_opcode), 418 (Opcode::Sqrt, &[F64], &[F64], insert_opcode), 419 // Ceil 420 (Opcode::Ceil, &[F32], &[F32], insert_opcode), 421 (Opcode::Ceil, &[F64], &[F64], insert_opcode), 422 // Floor 423 (Opcode::Floor, &[F32], &[F32], insert_opcode), 424 (Opcode::Floor, &[F64], &[F64], insert_opcode), 425 // Trunc 426 (Opcode::Trunc, &[F32], &[F32], insert_opcode), 427 (Opcode::Trunc, &[F64], &[F64], insert_opcode), 428 // Nearest 429 (Opcode::Nearest, &[F32], &[F32], insert_opcode), 430 (Opcode::Nearest, &[F64], &[F64], insert_opcode), 431 // Fcmp 432 (Opcode::Fcmp, &[F32, F32], &[B1], insert_cmp), 433 (Opcode::Fcmp, &[F64, F64], &[B1], insert_cmp), 434 // Icmp 435 (Opcode::Icmp, &[I8, I8], &[B1], insert_cmp), 436 (Opcode::Icmp, &[I16, I16], &[B1], insert_cmp), 437 (Opcode::Icmp, &[I32, I32], &[B1], insert_cmp), 438 (Opcode::Icmp, &[I64, I64], &[B1], insert_cmp), 439 // TODO: icmp of/nof broken for i128 on x86_64 440 // See: https://github.com/bytecodealliance/wasmtime/issues/4406 441 // (Opcode::Icmp, &[I128, I128], &[B1], insert_cmp), 442 // Stack Access 443 (Opcode::StackStore, &[I8], &[], insert_stack_store), 444 (Opcode::StackStore, &[I16], &[], insert_stack_store), 445 (Opcode::StackStore, &[I32], &[], insert_stack_store), 446 (Opcode::StackStore, &[I64], &[], insert_stack_store), 447 (Opcode::StackStore, &[I128], &[], insert_stack_store), 448 (Opcode::StackLoad, &[], &[I8], insert_stack_load), 449 (Opcode::StackLoad, &[], &[I16], insert_stack_load), 450 (Opcode::StackLoad, &[], &[I32], insert_stack_load), 451 (Opcode::StackLoad, &[], &[I64], insert_stack_load), 452 (Opcode::StackLoad, &[], &[I128], insert_stack_load), 453 // Integer Consts 454 (Opcode::Iconst, &[], &[I8], insert_const), 455 (Opcode::Iconst, &[], &[I16], insert_const), 456 (Opcode::Iconst, &[], &[I32], insert_const), 457 (Opcode::Iconst, &[], &[I64], insert_const), 458 (Opcode::Iconst, &[], &[I128], insert_const), 459 // Float Consts 460 (Opcode::F32const, &[], &[F32], insert_const), 461 (Opcode::F64const, &[], &[F64], insert_const), 462 // Bool Consts 463 (Opcode::Bconst, &[], &[B1], insert_const), 464 // Call 465 (Opcode::Call, &[], &[], insert_call), 466 ]; 467 468 /// These libcalls need a interpreter implementation in `cranelift-fuzzgen.rs` 469 const ALLOWED_LIBCALLS: &'static [LibCall] = &[ 470 LibCall::CeilF32, 471 LibCall::CeilF64, 472 LibCall::FloorF32, 473 LibCall::FloorF64, 474 LibCall::TruncF32, 475 LibCall::TruncF64, 476 ]; 477 478 pub struct FunctionGenerator<'r, 'data> 479 where 480 'data: 'r, 481 { 482 u: &'r mut Unstructured<'data>, 483 config: &'r Config, 484 vars: Vec<(Type, Variable)>, 485 blocks: Vec<(Block, BlockSignature)>, 486 jump_tables: Vec<JumpTable>, 487 func_refs: Vec<(Signature, FuncRef)>, 488 next_func_index: u32, 489 static_stack_slots: Vec<StackSlot>, 490 } 491 492 impl<'r, 'data> FunctionGenerator<'r, 'data> 493 where 494 'data: 'r, 495 { 496 pub fn new(u: &'r mut Unstructured<'data>, config: &'r Config) -> Self { 497 Self { 498 u, 499 config, 500 vars: vec![], 501 blocks: vec![], 502 jump_tables: vec![], 503 func_refs: vec![], 504 static_stack_slots: vec![], 505 next_func_index: 0, 506 } 507 } 508 509 /// Generates a random value for config `param` 510 fn param(&mut self, param: &RangeInclusive<usize>) -> Result<usize> { 511 Ok(self.u.int_in_range(param.clone())?) 512 } 513 514 fn generate_callconv(&mut self) -> Result<CallConv> { 515 // TODO: Generate random CallConvs per target 516 Ok(CallConv::SystemV) 517 } 518 519 fn system_callconv(&mut self) -> CallConv { 520 // TODO: This currently only runs on linux, so this is the only choice 521 // We should improve this once we generate flags and targets 522 CallConv::SystemV 523 } 524 525 fn generate_type(&mut self) -> Result<Type> { 526 // TODO: It would be nice if we could get these directly from cranelift 527 let scalars = [ 528 // IFLAGS, FFLAGS, 529 B1, // B8, B16, B32, B64, B128, 530 I8, I16, I32, I64, I128, F32, F64, 531 // R32, R64, 532 ]; 533 // TODO: vector types 534 535 let ty = self.u.choose(&scalars[..])?; 536 Ok(*ty) 537 } 538 539 fn generate_abi_param(&mut self) -> Result<AbiParam> { 540 let value_type = self.generate_type()?; 541 // TODO: There are more argument purposes to be explored... 542 let purpose = ArgumentPurpose::Normal; 543 let extension = match self.u.int_in_range(0..=2)? { 544 2 => ArgumentExtension::Sext, 545 1 => ArgumentExtension::Uext, 546 _ => ArgumentExtension::None, 547 }; 548 549 Ok(AbiParam { 550 value_type, 551 purpose, 552 extension, 553 }) 554 } 555 556 fn generate_signature(&mut self) -> Result<Signature> { 557 let callconv = self.generate_callconv()?; 558 let mut sig = Signature::new(callconv); 559 560 for _ in 0..self.param(&self.config.signature_params)? { 561 sig.params.push(self.generate_abi_param()?); 562 } 563 564 for _ in 0..self.param(&self.config.signature_rets)? { 565 sig.returns.push(self.generate_abi_param()?); 566 } 567 568 Ok(sig) 569 } 570 571 /// Finds a stack slot with size of at least n bytes 572 fn stack_slot_with_size(&mut self, builder: &mut FunctionBuilder, n: u32) -> Result<StackSlot> { 573 let opts: Vec<_> = self 574 .static_stack_slots 575 .iter() 576 .filter(|ss| builder.func.sized_stack_slots[**ss].size >= n) 577 .map(|ss| *ss) 578 .collect(); 579 580 Ok(*self.u.choose(&opts[..])?) 581 } 582 583 /// Creates a new var 584 fn create_var(&mut self, builder: &mut FunctionBuilder, ty: Type) -> Result<Variable> { 585 let id = self.vars.len(); 586 let var = Variable::new(id); 587 builder.declare_var(var, ty); 588 self.vars.push((ty, var)); 589 Ok(var) 590 } 591 592 fn vars_of_type(&self, ty: Type) -> Vec<Variable> { 593 self.vars 594 .iter() 595 .filter(|(var_ty, _)| *var_ty == ty) 596 .map(|(_, v)| *v) 597 .collect() 598 } 599 600 /// Get a variable of type `ty` from the current function 601 fn get_variable_of_type(&mut self, ty: Type) -> Result<Variable> { 602 let opts = self.vars_of_type(ty); 603 let var = self.u.choose(&opts[..])?; 604 Ok(*var) 605 } 606 607 /// Generates an instruction(`iconst`/`fconst`/etc...) to introduce a constant value 608 fn generate_const(&mut self, builder: &mut FunctionBuilder, ty: Type) -> Result<Value> { 609 Ok(match ty { 610 I128 => { 611 // See: https://github.com/bytecodealliance/wasmtime/issues/2906 612 let hi = builder.ins().iconst(I64, self.u.arbitrary::<i64>()?); 613 let lo = builder.ins().iconst(I64, self.u.arbitrary::<i64>()?); 614 builder.ins().iconcat(lo, hi) 615 } 616 ty if ty.is_int() => { 617 let imm64 = match ty { 618 I8 => self.u.arbitrary::<i8>()? as i64, 619 I16 => self.u.arbitrary::<i16>()? as i64, 620 I32 => self.u.arbitrary::<i32>()? as i64, 621 I64 => self.u.arbitrary::<i64>()?, 622 _ => unreachable!(), 623 }; 624 builder.ins().iconst(ty, imm64) 625 } 626 ty if ty.is_bool() => builder.ins().bconst(ty, bool::arbitrary(self.u)?), 627 // f{32,64}::arbitrary does not generate a bunch of important values 628 // such as Signaling NaN's / NaN's with payload, so generate floats from integers. 629 F32 => builder 630 .ins() 631 .f32const(f32::from_bits(u32::arbitrary(self.u)?)), 632 F64 => builder 633 .ins() 634 .f64const(f64::from_bits(u64::arbitrary(self.u)?)), 635 _ => unimplemented!(), 636 }) 637 } 638 639 /// Chooses a random block which can be targeted by a jump / branch. 640 /// This means any block that is not the first block. 641 /// 642 /// For convenience we also generate values that match the block's signature 643 fn generate_target_block( 644 &mut self, 645 builder: &mut FunctionBuilder, 646 ) -> Result<(Block, Vec<Value>)> { 647 let block_targets = &self.blocks[1..]; 648 let (block, signature) = self.u.choose(block_targets)?.clone(); 649 let args = self.generate_values_for_signature(builder, signature.into_iter())?; 650 Ok((block, args)) 651 } 652 653 /// Valid blocks for jump tables have to have no parameters in the signature, and must also 654 /// not be the first block. 655 fn generate_valid_jumptable_target_blocks(&mut self) -> Vec<Block> { 656 self.blocks[1..] 657 .iter() 658 .filter(|(_, sig)| sig.len() == 0) 659 .map(|(b, _)| *b) 660 .collect() 661 } 662 663 fn generate_values_for_signature<I: Iterator<Item = Type>>( 664 &mut self, 665 builder: &mut FunctionBuilder, 666 signature: I, 667 ) -> Result<Vec<Value>> { 668 signature 669 .map(|ty| { 670 let var = self.get_variable_of_type(ty)?; 671 let val = builder.use_var(var); 672 Ok(val) 673 }) 674 .collect() 675 } 676 677 fn generate_return(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 678 let types: Vec<Type> = { 679 let rets = &builder.func.signature.returns; 680 rets.iter().map(|p| p.value_type).collect() 681 }; 682 let vals = self.generate_values_for_signature(builder, types.into_iter())?; 683 684 builder.ins().return_(&vals[..]); 685 Ok(()) 686 } 687 688 fn generate_jump(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 689 let (block, args) = self.generate_target_block(builder)?; 690 builder.ins().jump(block, &args[..]); 691 Ok(()) 692 } 693 694 /// Generates a br_table into a random block 695 fn generate_br_table(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 696 let var = self.get_variable_of_type(I32)?; // br_table only supports I32 697 let val = builder.use_var(var); 698 699 let valid_blocks = self.generate_valid_jumptable_target_blocks(); 700 let default_block = *self.u.choose(&valid_blocks[..])?; 701 702 let jt = *self.u.choose(&self.jump_tables[..])?; 703 builder.ins().br_table(val, default_block, jt); 704 Ok(()) 705 } 706 707 /// Generates a brz/brnz into a random block 708 fn generate_br(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 709 let (block, args) = self.generate_target_block(builder)?; 710 711 let condbr_types = [I8, I16, I32, I64, I128, B1]; 712 let _type = *self.u.choose(&condbr_types[..])?; 713 let var = self.get_variable_of_type(_type)?; 714 let val = builder.use_var(var); 715 716 if bool::arbitrary(self.u)? { 717 builder.ins().brz(val, block, &args[..]); 718 } else { 719 builder.ins().brnz(val, block, &args[..]); 720 } 721 722 // After brz/brnz we must generate a jump 723 self.generate_jump(builder)?; 724 Ok(()) 725 } 726 727 fn generate_bricmp(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 728 let (block, args) = self.generate_target_block(builder)?; 729 let cond = *self.u.choose(IntCC::all())?; 730 731 let bricmp_types = [ 732 I8, I16, I32, 733 I64, 734 // I128 - TODO: https://github.com/bytecodealliance/wasmtime/issues/4406 735 ]; 736 let _type = *self.u.choose(&bricmp_types[..])?; 737 738 let lhs_var = self.get_variable_of_type(_type)?; 739 let lhs_val = builder.use_var(lhs_var); 740 741 let rhs_var = self.get_variable_of_type(_type)?; 742 let rhs_val = builder.use_var(rhs_var); 743 744 builder 745 .ins() 746 .br_icmp(cond, lhs_val, rhs_val, block, &args[..]); 747 748 // After bricmp's we must generate a jump 749 self.generate_jump(builder)?; 750 Ok(()) 751 } 752 753 fn generate_switch(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 754 let _type = *self.u.choose(&[I8, I16, I32, I64, I128][..])?; 755 let switch_var = self.get_variable_of_type(_type)?; 756 let switch_val = builder.use_var(switch_var); 757 758 let valid_blocks = self.generate_valid_jumptable_target_blocks(); 759 let default_block = *self.u.choose(&valid_blocks[..])?; 760 761 // Build this into a HashMap since we cannot have duplicate entries. 762 let mut entries = HashMap::new(); 763 for _ in 0..self.param(&self.config.switch_cases)? { 764 // The Switch API only allows for entries that are addressable by the index type 765 // so we need to limit the range of values that we generate. 766 let (ty_min, ty_max) = _type.bounds(false); 767 let range_start = self.u.int_in_range(ty_min..=ty_max)?; 768 769 // We can either insert a contiguous range of blocks or a individual block 770 // This is done because the Switch API specializes contiguous ranges. 771 let range_size = if bool::arbitrary(self.u)? { 772 1 773 } else { 774 self.param(&self.config.switch_max_range_size)? 775 } as u128; 776 777 // Build the switch entries 778 for i in 0..range_size { 779 let index = range_start.wrapping_add(i) % ty_max; 780 let block = *self.u.choose(&valid_blocks[..])?; 781 entries.insert(index, block); 782 } 783 } 784 785 let mut switch = Switch::new(); 786 for (entry, block) in entries.into_iter() { 787 switch.set_entry(entry, block); 788 } 789 switch.emit(builder, switch_val, default_block); 790 791 Ok(()) 792 } 793 794 /// We always need to exit safely out of a block. 795 /// This either means a jump into another block or a return. 796 fn finalize_block(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 797 let gen = self.u.choose( 798 &[ 799 Self::generate_bricmp, 800 Self::generate_br, 801 Self::generate_br_table, 802 Self::generate_jump, 803 Self::generate_return, 804 Self::generate_switch, 805 ][..], 806 )?; 807 808 gen(self, builder) 809 } 810 811 /// Fills the current block with random instructions 812 fn generate_instructions(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 813 for _ in 0..self.param(&self.config.instructions_per_block)? { 814 let (op, args, rets, inserter) = *self.u.choose(OPCODE_SIGNATURES)?; 815 inserter(self, builder, op, args, rets)?; 816 } 817 818 Ok(()) 819 } 820 821 fn generate_jumptables(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 822 let valid_blocks = self.generate_valid_jumptable_target_blocks(); 823 824 for _ in 0..self.param(&self.config.jump_tables_per_function)? { 825 let mut jt_data = JumpTableData::new(); 826 827 for _ in 0..self.param(&self.config.jump_table_entries)? { 828 let block = *self.u.choose(&valid_blocks[..])?; 829 jt_data.push_entry(block); 830 } 831 832 self.jump_tables.push(builder.create_jump_table(jt_data)); 833 } 834 Ok(()) 835 } 836 837 fn generate_funcrefs(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 838 for _ in 0..self.param(&self.config.funcrefs_per_function)? { 839 let (ext_name, sig) = if self.u.arbitrary::<bool>()? { 840 let func_index = self.next_func_index; 841 self.next_func_index = self.next_func_index.wrapping_add(1); 842 let user_func_ref = builder 843 .func 844 .declare_imported_user_function(UserExternalName { 845 namespace: 0, 846 index: func_index, 847 }); 848 let name = ExternalName::User(user_func_ref); 849 let signature = self.generate_signature()?; 850 (name, signature) 851 } else { 852 let libcall = *self.u.choose(ALLOWED_LIBCALLS)?; 853 // TODO: Use [CallConv::for_libcall] once we generate flags. 854 let callconv = self.system_callconv(); 855 let signature = libcall.signature(callconv); 856 (ExternalName::LibCall(libcall), signature) 857 }; 858 859 let sig_ref = builder.import_signature(sig.clone()); 860 let func_ref = builder.import_function(ExtFuncData { 861 name: ext_name, 862 signature: sig_ref, 863 colocated: self.u.arbitrary()?, 864 }); 865 866 self.func_refs.push((sig, func_ref)); 867 } 868 869 Ok(()) 870 } 871 872 fn generate_stack_slots(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 873 for _ in 0..self.param(&self.config.static_stack_slots_per_function)? { 874 let bytes = self.param(&self.config.static_stack_slot_size)? as u32; 875 let ss_data = StackSlotData::new(StackSlotKind::ExplicitSlot, bytes); 876 let slot = builder.create_sized_stack_slot(ss_data); 877 878 self.static_stack_slots.push(slot); 879 } 880 Ok(()) 881 } 882 883 /// Zero initializes the stack slot by inserting `stack_store`'s. 884 fn initialize_stack_slots(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 885 let i128_zero = builder.ins().iconst(I128, 0); 886 let i64_zero = builder.ins().iconst(I64, 0); 887 let i32_zero = builder.ins().iconst(I32, 0); 888 let i16_zero = builder.ins().iconst(I16, 0); 889 let i8_zero = builder.ins().iconst(I8, 0); 890 891 for &slot in self.static_stack_slots.iter() { 892 let init_size = builder.func.sized_stack_slots[slot].size; 893 let mut size = init_size; 894 895 // Insert the largest available store for the remaining size. 896 while size != 0 { 897 let offset = (init_size - size) as i32; 898 let (val, filled) = match size { 899 sz if sz / 16 > 0 => (i128_zero, 16), 900 sz if sz / 8 > 0 => (i64_zero, 8), 901 sz if sz / 4 > 0 => (i32_zero, 4), 902 sz if sz / 2 > 0 => (i16_zero, 2), 903 _ => (i8_zero, 1), 904 }; 905 builder.ins().stack_store(val, slot, offset); 906 size -= filled; 907 } 908 } 909 Ok(()) 910 } 911 912 /// Creates a random amount of blocks in this function 913 fn generate_blocks( 914 &mut self, 915 builder: &mut FunctionBuilder, 916 sig: &Signature, 917 ) -> Result<Vec<(Block, BlockSignature)>> { 918 let extra_block_count = self.param(&self.config.blocks_per_function)?; 919 920 // We must always have at least one block, so we generate the "extra" blocks and add 1 for 921 // the entry block. 922 let block_count = 1 + extra_block_count; 923 924 let blocks = (0..block_count) 925 .map(|i| { 926 let is_entry = i == 0; 927 let block = builder.create_block(); 928 929 // Optionally mark blocks that are not the entry block as cold 930 if !is_entry { 931 if bool::arbitrary(self.u)? { 932 builder.set_cold_block(block); 933 } 934 } 935 936 // The first block has to have the function signature, but for the rest of them we generate 937 // a random signature; 938 if is_entry { 939 builder.append_block_params_for_function_params(block); 940 Ok((block, sig.params.iter().map(|a| a.value_type).collect())) 941 } else { 942 let sig = self.generate_block_signature()?; 943 sig.iter().for_each(|ty| { 944 builder.append_block_param(block, *ty); 945 }); 946 Ok((block, sig)) 947 } 948 }) 949 .collect::<Result<Vec<_>>>()?; 950 951 Ok(blocks) 952 } 953 954 fn generate_block_signature(&mut self) -> Result<BlockSignature> { 955 let param_count = self.param(&self.config.block_signature_params)?; 956 957 let mut params = Vec::with_capacity(param_count); 958 for _ in 0..param_count { 959 params.push(self.generate_type()?); 960 } 961 Ok(params) 962 } 963 964 fn build_variable_pool(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 965 let block = builder.current_block().unwrap(); 966 let func_params = builder.func.signature.params.clone(); 967 968 // Define variables for the function signature 969 for (i, param) in func_params.iter().enumerate() { 970 let var = self.create_var(builder, param.value_type)?; 971 let block_param = builder.block_params(block)[i]; 972 builder.def_var(var, block_param); 973 } 974 975 // Create a pool of vars that are going to be used in this function 976 for _ in 0..self.param(&self.config.vars_per_function)? { 977 let ty = self.generate_type()?; 978 let var = self.create_var(builder, ty)?; 979 let value = self.generate_const(builder, ty)?; 980 builder.def_var(var, value); 981 } 982 983 Ok(()) 984 } 985 986 /// We generate a function in multiple stages: 987 /// 988 /// * First we generate a random number of empty blocks 989 /// * Then we generate a random pool of variables to be used throughout the function 990 /// * We then visit each block and generate random instructions 991 /// 992 /// Because we generate all blocks and variables up front we already know everything that 993 /// we need when generating instructions (i.e. jump targets / variables) 994 pub fn generate(mut self) -> Result<Function> { 995 let sig = self.generate_signature()?; 996 997 let mut fn_builder_ctx = FunctionBuilderContext::new(); 998 // function name must be in a different namespace than TESTFILE_NAMESPACE (0) 999 let mut func = Function::with_name_signature(UserFuncName::user(1, 0), sig.clone()); 1000 1001 let mut builder = FunctionBuilder::new(&mut func, &mut fn_builder_ctx); 1002 1003 self.blocks = self.generate_blocks(&mut builder, &sig)?; 1004 1005 // Function preamble 1006 self.generate_jumptables(&mut builder)?; 1007 self.generate_funcrefs(&mut builder)?; 1008 self.generate_stack_slots(&mut builder)?; 1009 1010 // Main instruction generation loop 1011 for (i, (block, block_sig)) in self.blocks.clone().iter().enumerate() { 1012 let is_block0 = i == 0; 1013 builder.switch_to_block(*block); 1014 1015 if is_block0 { 1016 // The first block is special because we must create variables both for the 1017 // block signature and for the variable pool. Additionally, we must also define 1018 // initial values for all variables that are not the function signature. 1019 self.build_variable_pool(&mut builder)?; 1020 1021 // Stack slots have random bytes at the beginning of the function 1022 // initialize them to a constant value so that execution stays predictable. 1023 self.initialize_stack_slots(&mut builder)?; 1024 } else { 1025 // Define variables for the block params 1026 for (i, ty) in block_sig.iter().enumerate() { 1027 let var = self.get_variable_of_type(*ty)?; 1028 let block_param = builder.block_params(*block)[i]; 1029 builder.def_var(var, block_param); 1030 } 1031 } 1032 1033 // Generate block instructions 1034 self.generate_instructions(&mut builder)?; 1035 1036 self.finalize_block(&mut builder)?; 1037 } 1038 1039 builder.seal_all_blocks(); 1040 builder.finalize(); 1041 1042 Ok(func) 1043 } 1044 } 1045