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::immediates::Offset32; 6 use cranelift::codegen::ir::instructions::InstructionFormat; 7 use cranelift::codegen::ir::stackslot::StackSize; 8 use cranelift::codegen::ir::{types::*, FuncRef, LibCall, UserExternalName, UserFuncName}; 9 use cranelift::codegen::ir::{ 10 AbiParam, Block, ExternalName, Function, JumpTable, Opcode, Signature, StackSlot, Type, Value, 11 }; 12 use cranelift::codegen::isa::CallConv; 13 use cranelift::frontend::{FunctionBuilder, FunctionBuilderContext, Switch, Variable}; 14 use cranelift::prelude::{ 15 EntityRef, ExtFuncData, FloatCC, InstBuilder, IntCC, JumpTableData, MemFlags, StackSlotData, 16 StackSlotKind, 17 }; 18 use std::collections::HashMap; 19 use std::ops::RangeInclusive; 20 21 type BlockSignature = Vec<Type>; 22 23 fn insert_opcode( 24 fgen: &mut FunctionGenerator, 25 builder: &mut FunctionBuilder, 26 opcode: Opcode, 27 args: &'static [Type], 28 rets: &'static [Type], 29 ) -> Result<()> { 30 let mut vals = Vec::with_capacity(args.len()); 31 for &arg in args.into_iter() { 32 let var = fgen.get_variable_of_type(arg)?; 33 let val = builder.use_var(var); 34 vals.push(val); 35 } 36 37 // For pretty much every instruction the control type is the return type 38 // except for Iconcat and Isplit which are *special* and the control type 39 // is the input type. 40 let ctrl_type = if opcode == Opcode::Iconcat || opcode == Opcode::Isplit { 41 args.first() 42 } else { 43 rets.first() 44 } 45 .copied() 46 .unwrap_or(INVALID); 47 48 // Choose the appropriate instruction format for this opcode 49 let (inst, dfg) = match opcode.format() { 50 InstructionFormat::NullAry => builder.ins().NullAry(opcode, ctrl_type), 51 InstructionFormat::Unary => builder.ins().Unary(opcode, ctrl_type, vals[0]), 52 InstructionFormat::Binary => builder.ins().Binary(opcode, ctrl_type, vals[0], vals[1]), 53 InstructionFormat::Ternary => builder 54 .ins() 55 .Ternary(opcode, ctrl_type, vals[0], vals[1], vals[2]), 56 _ => unimplemented!(), 57 }; 58 let results = dfg.inst_results(inst).to_vec(); 59 60 for (val, &ty) in results.into_iter().zip(rets) { 61 let var = fgen.get_variable_of_type(ty)?; 62 builder.def_var(var, val); 63 } 64 Ok(()) 65 } 66 67 fn insert_call( 68 fgen: &mut FunctionGenerator, 69 builder: &mut FunctionBuilder, 70 opcode: Opcode, 71 _args: &'static [Type], 72 _rets: &'static [Type], 73 ) -> Result<()> { 74 assert_eq!(opcode, Opcode::Call, "only call handled at the moment"); 75 let (sig, func_ref) = fgen.u.choose(&fgen.resources.func_refs)?.clone(); 76 77 let actuals = fgen.generate_values_for_signature( 78 builder, 79 sig.params.iter().map(|abi_param| abi_param.value_type), 80 )?; 81 82 builder.ins().call(func_ref, &actuals); 83 Ok(()) 84 } 85 86 fn insert_stack_load( 87 fgen: &mut FunctionGenerator, 88 builder: &mut FunctionBuilder, 89 _opcode: Opcode, 90 _args: &'static [Type], 91 rets: &'static [Type], 92 ) -> Result<()> { 93 let typevar = rets[0]; 94 let type_size = typevar.bytes(); 95 let (slot, slot_size) = fgen.stack_slot_with_size(type_size)?; 96 let offset = fgen.u.int_in_range(0..=(slot_size - type_size))? as i32; 97 98 let val = builder.ins().stack_load(typevar, slot, offset); 99 let var = fgen.get_variable_of_type(typevar)?; 100 builder.def_var(var, val); 101 102 Ok(()) 103 } 104 105 fn insert_stack_store( 106 fgen: &mut FunctionGenerator, 107 builder: &mut FunctionBuilder, 108 _opcode: Opcode, 109 args: &'static [Type], 110 _rets: &'static [Type], 111 ) -> Result<()> { 112 let typevar = args[0]; 113 let type_size = typevar.bytes(); 114 let (slot, slot_size) = fgen.stack_slot_with_size(type_size)?; 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 // Some FloatCC's are not implemented on AArch64, see: 139 // https://github.com/bytecodealliance/wasmtime/issues/4850 140 let float_cc = if cfg!(target_arch = "aarch64") { 141 &[ 142 FloatCC::Ordered, 143 FloatCC::Unordered, 144 FloatCC::Equal, 145 FloatCC::NotEqual, 146 FloatCC::LessThan, 147 FloatCC::LessThanOrEqual, 148 FloatCC::GreaterThan, 149 FloatCC::GreaterThanOrEqual, 150 ] 151 } else { 152 FloatCC::all() 153 }; 154 155 let cc = *fgen.u.choose(float_cc)?; 156 builder.ins().fcmp(cc, lhs, rhs) 157 } else { 158 let cc = *fgen.u.choose(IntCC::all())?; 159 builder.ins().icmp(cc, lhs, rhs) 160 }; 161 162 let var = fgen.get_variable_of_type(rets[0])?; 163 builder.def_var(var, res); 164 165 Ok(()) 166 } 167 168 fn insert_const( 169 fgen: &mut FunctionGenerator, 170 builder: &mut FunctionBuilder, 171 _opcode: Opcode, 172 _args: &'static [Type], 173 rets: &'static [Type], 174 ) -> Result<()> { 175 let typevar = rets[0]; 176 let var = fgen.get_variable_of_type(typevar)?; 177 let val = fgen.generate_const(builder, typevar)?; 178 builder.def_var(var, val); 179 Ok(()) 180 } 181 182 fn insert_load_store( 183 fgen: &mut FunctionGenerator, 184 builder: &mut FunctionBuilder, 185 opcode: Opcode, 186 args: &'static [Type], 187 rets: &'static [Type], 188 ) -> Result<()> { 189 let ctrl_type = *rets.first().or(args.first()).unwrap(); 190 let type_size = ctrl_type.bytes(); 191 let (address, offset) = fgen.generate_load_store_address(builder, type_size)?; 192 193 // TODO: More advanced MemFlags 194 let flags = MemFlags::new(); 195 196 // The variable being loaded or stored into 197 let var = fgen.get_variable_of_type(ctrl_type)?; 198 199 if opcode.can_store() { 200 let val = builder.use_var(var); 201 202 builder 203 .ins() 204 .Store(opcode, ctrl_type, flags, offset, val, address); 205 } else { 206 let (inst, dfg) = builder 207 .ins() 208 .Load(opcode, ctrl_type, flags, offset, address); 209 210 let new_val = dfg.first_result(inst); 211 builder.def_var(var, new_val); 212 } 213 214 Ok(()) 215 } 216 217 type OpcodeInserter = fn( 218 fgen: &mut FunctionGenerator, 219 builder: &mut FunctionBuilder, 220 Opcode, 221 &'static [Type], 222 &'static [Type], 223 ) -> Result<()>; 224 225 // TODO: Derive this from the `cranelift-meta` generator. 226 const OPCODE_SIGNATURES: &'static [( 227 Opcode, 228 &'static [Type], // Args 229 &'static [Type], // Rets 230 OpcodeInserter, 231 )] = &[ 232 (Opcode::Nop, &[], &[], insert_opcode), 233 // Iadd 234 (Opcode::Iadd, &[I8, I8], &[I8], insert_opcode), 235 (Opcode::Iadd, &[I16, I16], &[I16], insert_opcode), 236 (Opcode::Iadd, &[I32, I32], &[I32], insert_opcode), 237 (Opcode::Iadd, &[I64, I64], &[I64], insert_opcode), 238 (Opcode::Iadd, &[I128, I128], &[I128], insert_opcode), 239 // Isub 240 (Opcode::Isub, &[I8, I8], &[I8], insert_opcode), 241 (Opcode::Isub, &[I16, I16], &[I16], insert_opcode), 242 (Opcode::Isub, &[I32, I32], &[I32], insert_opcode), 243 (Opcode::Isub, &[I64, I64], &[I64], insert_opcode), 244 (Opcode::Isub, &[I128, I128], &[I128], insert_opcode), 245 // Imul 246 (Opcode::Imul, &[I8, I8], &[I8], insert_opcode), 247 (Opcode::Imul, &[I16, I16], &[I16], insert_opcode), 248 (Opcode::Imul, &[I32, I32], &[I32], insert_opcode), 249 (Opcode::Imul, &[I64, I64], &[I64], insert_opcode), 250 (Opcode::Imul, &[I128, I128], &[I128], insert_opcode), 251 // Udiv 252 (Opcode::Udiv, &[I8, I8], &[I8], insert_opcode), 253 (Opcode::Udiv, &[I16, I16], &[I16], insert_opcode), 254 (Opcode::Udiv, &[I32, I32], &[I32], insert_opcode), 255 (Opcode::Udiv, &[I64, I64], &[I64], insert_opcode), 256 // udiv.i128 not implemented in some backends: 257 // x64: https://github.com/bytecodealliance/wasmtime/issues/4756 258 // aarch64: https://github.com/bytecodealliance/wasmtime/issues/4864 259 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 260 (Opcode::Udiv, &[I128, I128], &[I128], insert_opcode), 261 // Sdiv 262 (Opcode::Sdiv, &[I8, I8], &[I8], insert_opcode), 263 (Opcode::Sdiv, &[I16, I16], &[I16], insert_opcode), 264 (Opcode::Sdiv, &[I32, I32], &[I32], insert_opcode), 265 (Opcode::Sdiv, &[I64, I64], &[I64], insert_opcode), 266 // sdiv.i128 not implemented in some backends: 267 // x64: https://github.com/bytecodealliance/wasmtime/issues/4770 268 // aarch64: https://github.com/bytecodealliance/wasmtime/issues/4864 269 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 270 (Opcode::Sdiv, &[I128, I128], &[I128], insert_opcode), 271 // Rotr 272 (Opcode::Rotr, &[I8, I8], &[I8], insert_opcode), 273 (Opcode::Rotr, &[I8, I16], &[I8], insert_opcode), 274 (Opcode::Rotr, &[I8, I32], &[I8], insert_opcode), 275 (Opcode::Rotr, &[I8, I64], &[I8], insert_opcode), 276 (Opcode::Rotr, &[I8, I128], &[I8], insert_opcode), 277 (Opcode::Rotr, &[I16, I8], &[I16], insert_opcode), 278 (Opcode::Rotr, &[I16, I16], &[I16], insert_opcode), 279 (Opcode::Rotr, &[I16, I32], &[I16], insert_opcode), 280 (Opcode::Rotr, &[I16, I64], &[I16], insert_opcode), 281 (Opcode::Rotr, &[I16, I128], &[I16], insert_opcode), 282 (Opcode::Rotr, &[I32, I8], &[I32], insert_opcode), 283 (Opcode::Rotr, &[I32, I16], &[I32], insert_opcode), 284 (Opcode::Rotr, &[I32, I32], &[I32], insert_opcode), 285 (Opcode::Rotr, &[I32, I64], &[I32], insert_opcode), 286 (Opcode::Rotr, &[I32, I128], &[I32], insert_opcode), 287 (Opcode::Rotr, &[I64, I8], &[I64], insert_opcode), 288 (Opcode::Rotr, &[I64, I16], &[I64], insert_opcode), 289 (Opcode::Rotr, &[I64, I32], &[I64], insert_opcode), 290 (Opcode::Rotr, &[I64, I64], &[I64], insert_opcode), 291 (Opcode::Rotr, &[I64, I128], &[I64], insert_opcode), 292 (Opcode::Rotr, &[I128, I8], &[I128], insert_opcode), 293 (Opcode::Rotr, &[I128, I16], &[I128], insert_opcode), 294 (Opcode::Rotr, &[I128, I32], &[I128], insert_opcode), 295 (Opcode::Rotr, &[I128, I64], &[I128], insert_opcode), 296 (Opcode::Rotr, &[I128, I128], &[I128], insert_opcode), 297 // Rotl 298 (Opcode::Rotl, &[I8, I8], &[I8], insert_opcode), 299 (Opcode::Rotl, &[I8, I16], &[I8], insert_opcode), 300 (Opcode::Rotl, &[I8, I32], &[I8], insert_opcode), 301 (Opcode::Rotl, &[I8, I64], &[I8], insert_opcode), 302 (Opcode::Rotl, &[I8, I128], &[I8], insert_opcode), 303 (Opcode::Rotl, &[I16, I8], &[I16], insert_opcode), 304 (Opcode::Rotl, &[I16, I16], &[I16], insert_opcode), 305 (Opcode::Rotl, &[I16, I32], &[I16], insert_opcode), 306 (Opcode::Rotl, &[I16, I64], &[I16], insert_opcode), 307 (Opcode::Rotl, &[I16, I128], &[I16], insert_opcode), 308 (Opcode::Rotl, &[I32, I8], &[I32], insert_opcode), 309 (Opcode::Rotl, &[I32, I16], &[I32], insert_opcode), 310 (Opcode::Rotl, &[I32, I32], &[I32], insert_opcode), 311 (Opcode::Rotl, &[I32, I64], &[I32], insert_opcode), 312 (Opcode::Rotl, &[I32, I128], &[I32], insert_opcode), 313 (Opcode::Rotl, &[I64, I8], &[I64], insert_opcode), 314 (Opcode::Rotl, &[I64, I16], &[I64], insert_opcode), 315 (Opcode::Rotl, &[I64, I32], &[I64], insert_opcode), 316 (Opcode::Rotl, &[I64, I64], &[I64], insert_opcode), 317 (Opcode::Rotl, &[I64, I128], &[I64], insert_opcode), 318 (Opcode::Rotl, &[I128, I8], &[I128], insert_opcode), 319 (Opcode::Rotl, &[I128, I16], &[I128], insert_opcode), 320 (Opcode::Rotl, &[I128, I32], &[I128], insert_opcode), 321 (Opcode::Rotl, &[I128, I64], &[I128], insert_opcode), 322 (Opcode::Rotl, &[I128, I128], &[I128], insert_opcode), 323 // Ishl 324 (Opcode::Ishl, &[I8, I8], &[I8], insert_opcode), 325 (Opcode::Ishl, &[I8, I16], &[I8], insert_opcode), 326 (Opcode::Ishl, &[I8, I32], &[I8], insert_opcode), 327 (Opcode::Ishl, &[I8, I64], &[I8], insert_opcode), 328 (Opcode::Ishl, &[I8, I128], &[I8], insert_opcode), 329 (Opcode::Ishl, &[I16, I8], &[I16], insert_opcode), 330 (Opcode::Ishl, &[I16, I16], &[I16], insert_opcode), 331 (Opcode::Ishl, &[I16, I32], &[I16], insert_opcode), 332 (Opcode::Ishl, &[I16, I64], &[I16], insert_opcode), 333 (Opcode::Ishl, &[I16, I128], &[I16], insert_opcode), 334 (Opcode::Ishl, &[I32, I8], &[I32], insert_opcode), 335 (Opcode::Ishl, &[I32, I16], &[I32], insert_opcode), 336 (Opcode::Ishl, &[I32, I32], &[I32], insert_opcode), 337 (Opcode::Ishl, &[I32, I64], &[I32], insert_opcode), 338 (Opcode::Ishl, &[I32, I128], &[I32], insert_opcode), 339 (Opcode::Ishl, &[I64, I8], &[I64], insert_opcode), 340 (Opcode::Ishl, &[I64, I16], &[I64], insert_opcode), 341 (Opcode::Ishl, &[I64, I32], &[I64], insert_opcode), 342 (Opcode::Ishl, &[I64, I64], &[I64], insert_opcode), 343 (Opcode::Ishl, &[I64, I128], &[I64], insert_opcode), 344 (Opcode::Ishl, &[I128, I8], &[I128], insert_opcode), 345 (Opcode::Ishl, &[I128, I16], &[I128], insert_opcode), 346 (Opcode::Ishl, &[I128, I32], &[I128], insert_opcode), 347 (Opcode::Ishl, &[I128, I64], &[I128], insert_opcode), 348 (Opcode::Ishl, &[I128, I128], &[I128], insert_opcode), 349 // Sshr 350 (Opcode::Sshr, &[I8, I8], &[I8], insert_opcode), 351 (Opcode::Sshr, &[I8, I16], &[I8], insert_opcode), 352 (Opcode::Sshr, &[I8, I32], &[I8], insert_opcode), 353 (Opcode::Sshr, &[I8, I64], &[I8], insert_opcode), 354 (Opcode::Sshr, &[I8, I128], &[I8], insert_opcode), 355 (Opcode::Sshr, &[I16, I8], &[I16], insert_opcode), 356 (Opcode::Sshr, &[I16, I16], &[I16], insert_opcode), 357 (Opcode::Sshr, &[I16, I32], &[I16], insert_opcode), 358 (Opcode::Sshr, &[I16, I64], &[I16], insert_opcode), 359 (Opcode::Sshr, &[I16, I128], &[I16], insert_opcode), 360 (Opcode::Sshr, &[I32, I8], &[I32], insert_opcode), 361 (Opcode::Sshr, &[I32, I16], &[I32], insert_opcode), 362 (Opcode::Sshr, &[I32, I32], &[I32], insert_opcode), 363 (Opcode::Sshr, &[I32, I64], &[I32], insert_opcode), 364 (Opcode::Sshr, &[I32, I128], &[I32], insert_opcode), 365 (Opcode::Sshr, &[I64, I8], &[I64], insert_opcode), 366 (Opcode::Sshr, &[I64, I16], &[I64], insert_opcode), 367 (Opcode::Sshr, &[I64, I32], &[I64], insert_opcode), 368 (Opcode::Sshr, &[I64, I64], &[I64], insert_opcode), 369 (Opcode::Sshr, &[I64, I128], &[I64], insert_opcode), 370 (Opcode::Sshr, &[I128, I8], &[I128], insert_opcode), 371 (Opcode::Sshr, &[I128, I16], &[I128], insert_opcode), 372 (Opcode::Sshr, &[I128, I32], &[I128], insert_opcode), 373 (Opcode::Sshr, &[I128, I64], &[I128], insert_opcode), 374 (Opcode::Sshr, &[I128, I128], &[I128], insert_opcode), 375 // Ushr 376 (Opcode::Ushr, &[I8, I8], &[I8], insert_opcode), 377 (Opcode::Ushr, &[I8, I16], &[I8], insert_opcode), 378 (Opcode::Ushr, &[I8, I32], &[I8], insert_opcode), 379 (Opcode::Ushr, &[I8, I64], &[I8], insert_opcode), 380 (Opcode::Ushr, &[I8, I128], &[I8], insert_opcode), 381 (Opcode::Ushr, &[I16, I8], &[I16], insert_opcode), 382 (Opcode::Ushr, &[I16, I16], &[I16], insert_opcode), 383 (Opcode::Ushr, &[I16, I32], &[I16], insert_opcode), 384 (Opcode::Ushr, &[I16, I64], &[I16], insert_opcode), 385 (Opcode::Ushr, &[I16, I128], &[I16], insert_opcode), 386 (Opcode::Ushr, &[I32, I8], &[I32], insert_opcode), 387 (Opcode::Ushr, &[I32, I16], &[I32], insert_opcode), 388 (Opcode::Ushr, &[I32, I32], &[I32], insert_opcode), 389 (Opcode::Ushr, &[I32, I64], &[I32], insert_opcode), 390 (Opcode::Ushr, &[I32, I128], &[I32], insert_opcode), 391 (Opcode::Ushr, &[I64, I8], &[I64], insert_opcode), 392 (Opcode::Ushr, &[I64, I16], &[I64], insert_opcode), 393 (Opcode::Ushr, &[I64, I32], &[I64], insert_opcode), 394 (Opcode::Ushr, &[I64, I64], &[I64], insert_opcode), 395 (Opcode::Ushr, &[I64, I128], &[I64], insert_opcode), 396 (Opcode::Ushr, &[I128, I8], &[I128], insert_opcode), 397 (Opcode::Ushr, &[I128, I16], &[I128], insert_opcode), 398 (Opcode::Ushr, &[I128, I32], &[I128], insert_opcode), 399 (Opcode::Ushr, &[I128, I64], &[I128], insert_opcode), 400 (Opcode::Ushr, &[I128, I128], &[I128], insert_opcode), 401 // Uextend 402 (Opcode::Uextend, &[I8], &[I16], insert_opcode), 403 (Opcode::Uextend, &[I8], &[I32], insert_opcode), 404 (Opcode::Uextend, &[I8], &[I64], insert_opcode), 405 (Opcode::Uextend, &[I8], &[I128], insert_opcode), 406 (Opcode::Uextend, &[I16], &[I32], insert_opcode), 407 (Opcode::Uextend, &[I16], &[I64], insert_opcode), 408 (Opcode::Uextend, &[I16], &[I128], insert_opcode), 409 (Opcode::Uextend, &[I32], &[I64], insert_opcode), 410 (Opcode::Uextend, &[I32], &[I128], insert_opcode), 411 (Opcode::Uextend, &[I64], &[I128], insert_opcode), 412 // Sextend 413 (Opcode::Sextend, &[I8], &[I16], insert_opcode), 414 (Opcode::Sextend, &[I8], &[I32], insert_opcode), 415 (Opcode::Sextend, &[I8], &[I64], insert_opcode), 416 (Opcode::Sextend, &[I8], &[I128], insert_opcode), 417 (Opcode::Sextend, &[I16], &[I32], insert_opcode), 418 (Opcode::Sextend, &[I16], &[I64], insert_opcode), 419 (Opcode::Sextend, &[I16], &[I128], insert_opcode), 420 (Opcode::Sextend, &[I32], &[I64], insert_opcode), 421 (Opcode::Sextend, &[I32], &[I128], insert_opcode), 422 (Opcode::Sextend, &[I64], &[I128], insert_opcode), 423 // Ireduce 424 (Opcode::Ireduce, &[I16], &[I8], insert_opcode), 425 (Opcode::Ireduce, &[I32], &[I8], insert_opcode), 426 (Opcode::Ireduce, &[I32], &[I16], insert_opcode), 427 (Opcode::Ireduce, &[I64], &[I8], insert_opcode), 428 (Opcode::Ireduce, &[I64], &[I16], insert_opcode), 429 (Opcode::Ireduce, &[I64], &[I32], insert_opcode), 430 (Opcode::Ireduce, &[I128], &[I8], insert_opcode), 431 (Opcode::Ireduce, &[I128], &[I16], insert_opcode), 432 (Opcode::Ireduce, &[I128], &[I32], insert_opcode), 433 (Opcode::Ireduce, &[I128], &[I64], insert_opcode), 434 // Isplit 435 (Opcode::Isplit, &[I128], &[I64, I64], insert_opcode), 436 // Iconcat 437 (Opcode::Iconcat, &[I64, I64], &[I128], insert_opcode), 438 // Fadd 439 (Opcode::Fadd, &[F32, F32], &[F32], insert_opcode), 440 (Opcode::Fadd, &[F64, F64], &[F64], insert_opcode), 441 // Fmul 442 (Opcode::Fmul, &[F32, F32], &[F32], insert_opcode), 443 (Opcode::Fmul, &[F64, F64], &[F64], insert_opcode), 444 // Fsub 445 (Opcode::Fsub, &[F32, F32], &[F32], insert_opcode), 446 (Opcode::Fsub, &[F64, F64], &[F64], insert_opcode), 447 // Fdiv 448 (Opcode::Fdiv, &[F32, F32], &[F32], insert_opcode), 449 (Opcode::Fdiv, &[F64, F64], &[F64], insert_opcode), 450 // Fmin 451 (Opcode::Fmin, &[F32, F32], &[F32], insert_opcode), 452 (Opcode::Fmin, &[F64, F64], &[F64], insert_opcode), 453 // Fmax 454 (Opcode::Fmax, &[F32, F32], &[F32], insert_opcode), 455 (Opcode::Fmax, &[F64, F64], &[F64], insert_opcode), 456 // FminPseudo 457 (Opcode::FminPseudo, &[F32, F32], &[F32], insert_opcode), 458 (Opcode::FminPseudo, &[F64, F64], &[F64], insert_opcode), 459 // FmaxPseudo 460 (Opcode::FmaxPseudo, &[F32, F32], &[F32], insert_opcode), 461 (Opcode::FmaxPseudo, &[F64, F64], &[F64], insert_opcode), 462 // Fcopysign 463 (Opcode::Fcopysign, &[F32, F32], &[F32], insert_opcode), 464 (Opcode::Fcopysign, &[F64, F64], &[F64], insert_opcode), 465 // Fma 466 (Opcode::Fma, &[F32, F32, F32], &[F32], insert_opcode), 467 (Opcode::Fma, &[F64, F64, F64], &[F64], insert_opcode), 468 // Fabs 469 (Opcode::Fabs, &[F32], &[F32], insert_opcode), 470 (Opcode::Fabs, &[F64], &[F64], insert_opcode), 471 // Fneg 472 (Opcode::Fneg, &[F32], &[F32], insert_opcode), 473 (Opcode::Fneg, &[F64], &[F64], insert_opcode), 474 // Sqrt 475 (Opcode::Sqrt, &[F32], &[F32], insert_opcode), 476 (Opcode::Sqrt, &[F64], &[F64], insert_opcode), 477 // Ceil 478 (Opcode::Ceil, &[F32], &[F32], insert_opcode), 479 (Opcode::Ceil, &[F64], &[F64], insert_opcode), 480 // Floor 481 (Opcode::Floor, &[F32], &[F32], insert_opcode), 482 (Opcode::Floor, &[F64], &[F64], insert_opcode), 483 // Trunc 484 (Opcode::Trunc, &[F32], &[F32], insert_opcode), 485 (Opcode::Trunc, &[F64], &[F64], insert_opcode), 486 // Nearest 487 (Opcode::Nearest, &[F32], &[F32], insert_opcode), 488 (Opcode::Nearest, &[F64], &[F64], insert_opcode), 489 // FcvtToUint 490 // TODO: Some ops disabled: 491 // x64: https://github.com/bytecodealliance/wasmtime/issues/4897 492 // x64: https://github.com/bytecodealliance/wasmtime/issues/4899 493 // aarch64: https://github.com/bytecodealliance/wasmtime/issues/4934 494 #[cfg(not(target_arch = "x86_64"))] 495 (Opcode::FcvtToUint, &[F32], &[I8], insert_opcode), 496 #[cfg(not(target_arch = "x86_64"))] 497 (Opcode::FcvtToUint, &[F32], &[I16], insert_opcode), 498 (Opcode::FcvtToUint, &[F32], &[I32], insert_opcode), 499 (Opcode::FcvtToUint, &[F32], &[I64], insert_opcode), 500 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 501 (Opcode::FcvtToUint, &[F32], &[I128], insert_opcode), 502 #[cfg(not(target_arch = "x86_64"))] 503 (Opcode::FcvtToUint, &[F64], &[I8], insert_opcode), 504 #[cfg(not(target_arch = "x86_64"))] 505 (Opcode::FcvtToUint, &[F64], &[I16], insert_opcode), 506 (Opcode::FcvtToUint, &[F64], &[I32], insert_opcode), 507 (Opcode::FcvtToUint, &[F64], &[I64], insert_opcode), 508 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 509 (Opcode::FcvtToUint, &[F64], &[I128], insert_opcode), 510 // FcvtToUintSat 511 // TODO: Some ops disabled: 512 // x64: https://github.com/bytecodealliance/wasmtime/issues/4897 513 // x64: https://github.com/bytecodealliance/wasmtime/issues/4899 514 // aarch64: https://github.com/bytecodealliance/wasmtime/issues/4934 515 #[cfg(not(target_arch = "x86_64"))] 516 (Opcode::FcvtToUintSat, &[F32], &[I8], insert_opcode), 517 #[cfg(not(target_arch = "x86_64"))] 518 (Opcode::FcvtToUintSat, &[F32], &[I16], insert_opcode), 519 (Opcode::FcvtToUintSat, &[F32], &[I32], insert_opcode), 520 (Opcode::FcvtToUintSat, &[F32], &[I64], insert_opcode), 521 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 522 (Opcode::FcvtToUintSat, &[F32], &[I128], insert_opcode), 523 #[cfg(not(target_arch = "x86_64"))] 524 (Opcode::FcvtToUintSat, &[F64], &[I8], insert_opcode), 525 #[cfg(not(target_arch = "x86_64"))] 526 (Opcode::FcvtToUintSat, &[F64], &[I16], insert_opcode), 527 (Opcode::FcvtToUintSat, &[F64], &[I32], insert_opcode), 528 (Opcode::FcvtToUintSat, &[F64], &[I64], insert_opcode), 529 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 530 (Opcode::FcvtToUintSat, &[F64], &[I128], insert_opcode), 531 // FcvtToSint 532 // TODO: Some ops disabled: 533 // x64: https://github.com/bytecodealliance/wasmtime/issues/4897 534 // x64: https://github.com/bytecodealliance/wasmtime/issues/4899 535 // aarch64: https://github.com/bytecodealliance/wasmtime/issues/4934 536 #[cfg(not(target_arch = "x86_64"))] 537 (Opcode::FcvtToSint, &[F32], &[I8], insert_opcode), 538 #[cfg(not(target_arch = "x86_64"))] 539 (Opcode::FcvtToSint, &[F32], &[I16], insert_opcode), 540 (Opcode::FcvtToSint, &[F32], &[I32], insert_opcode), 541 (Opcode::FcvtToSint, &[F32], &[I64], insert_opcode), 542 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 543 (Opcode::FcvtToSint, &[F32], &[I128], insert_opcode), 544 #[cfg(not(target_arch = "x86_64"))] 545 (Opcode::FcvtToSint, &[F64], &[I8], insert_opcode), 546 #[cfg(not(target_arch = "x86_64"))] 547 (Opcode::FcvtToSint, &[F64], &[I16], insert_opcode), 548 (Opcode::FcvtToSint, &[F64], &[I32], insert_opcode), 549 (Opcode::FcvtToSint, &[F64], &[I64], insert_opcode), 550 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 551 (Opcode::FcvtToSint, &[F64], &[I128], insert_opcode), 552 // FcvtToSintSat 553 // TODO: Some ops disabled: 554 // x64: https://github.com/bytecodealliance/wasmtime/issues/4897 555 // x64: https://github.com/bytecodealliance/wasmtime/issues/4899 556 // aarch64: https://github.com/bytecodealliance/wasmtime/issues/4934 557 #[cfg(not(target_arch = "x86_64"))] 558 (Opcode::FcvtToSintSat, &[F32], &[I8], insert_opcode), 559 #[cfg(not(target_arch = "x86_64"))] 560 (Opcode::FcvtToSintSat, &[F32], &[I16], insert_opcode), 561 (Opcode::FcvtToSintSat, &[F32], &[I32], insert_opcode), 562 (Opcode::FcvtToSintSat, &[F32], &[I64], insert_opcode), 563 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 564 (Opcode::FcvtToSintSat, &[F32], &[I128], insert_opcode), 565 #[cfg(not(target_arch = "x86_64"))] 566 (Opcode::FcvtToSintSat, &[F64], &[I8], insert_opcode), 567 #[cfg(not(target_arch = "x86_64"))] 568 (Opcode::FcvtToSintSat, &[F64], &[I16], insert_opcode), 569 (Opcode::FcvtToSintSat, &[F64], &[I32], insert_opcode), 570 (Opcode::FcvtToSintSat, &[F64], &[I64], insert_opcode), 571 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 572 (Opcode::FcvtToSintSat, &[F64], &[I128], insert_opcode), 573 // FcvtFromUint 574 // TODO: Some ops disabled: 575 // x64: https://github.com/bytecodealliance/wasmtime/issues/4900 576 // aarch64: https://github.com/bytecodealliance/wasmtime/issues/4933 577 (Opcode::FcvtFromUint, &[I8], &[F32], insert_opcode), 578 (Opcode::FcvtFromUint, &[I16], &[F32], insert_opcode), 579 (Opcode::FcvtFromUint, &[I32], &[F32], insert_opcode), 580 (Opcode::FcvtFromUint, &[I64], &[F32], insert_opcode), 581 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 582 (Opcode::FcvtFromUint, &[I128], &[F32], insert_opcode), 583 (Opcode::FcvtFromUint, &[I8], &[F64], insert_opcode), 584 (Opcode::FcvtFromUint, &[I16], &[F64], insert_opcode), 585 (Opcode::FcvtFromUint, &[I32], &[F64], insert_opcode), 586 (Opcode::FcvtFromUint, &[I64], &[F64], insert_opcode), 587 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 588 (Opcode::FcvtFromUint, &[I128], &[F64], insert_opcode), 589 // FcvtFromSint 590 // TODO: Some ops disabled: 591 // x64: https://github.com/bytecodealliance/wasmtime/issues/4900 592 // aarch64: https://github.com/bytecodealliance/wasmtime/issues/4933 593 (Opcode::FcvtFromSint, &[I8], &[F32], insert_opcode), 594 (Opcode::FcvtFromSint, &[I16], &[F32], insert_opcode), 595 (Opcode::FcvtFromSint, &[I32], &[F32], insert_opcode), 596 (Opcode::FcvtFromSint, &[I64], &[F32], insert_opcode), 597 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 598 (Opcode::FcvtFromSint, &[I128], &[F32], insert_opcode), 599 (Opcode::FcvtFromSint, &[I8], &[F64], insert_opcode), 600 (Opcode::FcvtFromSint, &[I16], &[F64], insert_opcode), 601 (Opcode::FcvtFromSint, &[I32], &[F64], insert_opcode), 602 (Opcode::FcvtFromSint, &[I64], &[F64], insert_opcode), 603 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 604 (Opcode::FcvtFromSint, &[I128], &[F64], insert_opcode), 605 // Fcmp 606 (Opcode::Fcmp, &[F32, F32], &[B1], insert_cmp), 607 (Opcode::Fcmp, &[F64, F64], &[B1], insert_cmp), 608 // Icmp 609 (Opcode::Icmp, &[I8, I8], &[B1], insert_cmp), 610 (Opcode::Icmp, &[I16, I16], &[B1], insert_cmp), 611 (Opcode::Icmp, &[I32, I32], &[B1], insert_cmp), 612 (Opcode::Icmp, &[I64, I64], &[B1], insert_cmp), 613 (Opcode::Icmp, &[I128, I128], &[B1], insert_cmp), 614 // Stack Access 615 (Opcode::StackStore, &[I8], &[], insert_stack_store), 616 (Opcode::StackStore, &[I16], &[], insert_stack_store), 617 (Opcode::StackStore, &[I32], &[], insert_stack_store), 618 (Opcode::StackStore, &[I64], &[], insert_stack_store), 619 (Opcode::StackStore, &[I128], &[], insert_stack_store), 620 (Opcode::StackLoad, &[], &[I8], insert_stack_load), 621 (Opcode::StackLoad, &[], &[I16], insert_stack_load), 622 (Opcode::StackLoad, &[], &[I32], insert_stack_load), 623 (Opcode::StackLoad, &[], &[I64], insert_stack_load), 624 (Opcode::StackLoad, &[], &[I128], insert_stack_load), 625 // Loads 626 (Opcode::Load, &[], &[I8], insert_load_store), 627 (Opcode::Load, &[], &[I16], insert_load_store), 628 (Opcode::Load, &[], &[I32], insert_load_store), 629 (Opcode::Load, &[], &[I64], insert_load_store), 630 (Opcode::Load, &[], &[I128], insert_load_store), 631 (Opcode::Load, &[], &[F32], insert_load_store), 632 (Opcode::Load, &[], &[F64], insert_load_store), 633 // Special Loads 634 (Opcode::Uload8, &[], &[I16], insert_load_store), 635 (Opcode::Uload8, &[], &[I32], insert_load_store), 636 (Opcode::Uload8, &[], &[I64], insert_load_store), 637 (Opcode::Uload16, &[], &[I32], insert_load_store), 638 (Opcode::Uload16, &[], &[I64], insert_load_store), 639 (Opcode::Uload32, &[], &[I64], insert_load_store), 640 (Opcode::Sload8, &[], &[I16], insert_load_store), 641 (Opcode::Sload8, &[], &[I32], insert_load_store), 642 (Opcode::Sload8, &[], &[I64], insert_load_store), 643 (Opcode::Sload16, &[], &[I32], insert_load_store), 644 (Opcode::Sload16, &[], &[I64], insert_load_store), 645 (Opcode::Sload32, &[], &[I64], insert_load_store), 646 // TODO: Unimplemented in the interpreter 647 // Opcode::Uload8x8 648 // Opcode::Sload8x8 649 // Opcode::Uload16x4 650 // Opcode::Sload16x4 651 // Opcode::Uload32x2 652 // Opcode::Sload32x2 653 // Stores 654 (Opcode::Store, &[I8], &[], insert_load_store), 655 (Opcode::Store, &[I16], &[], insert_load_store), 656 (Opcode::Store, &[I32], &[], insert_load_store), 657 (Opcode::Store, &[I64], &[], insert_load_store), 658 (Opcode::Store, &[I128], &[], insert_load_store), 659 (Opcode::Store, &[F32], &[], insert_load_store), 660 (Opcode::Store, &[F64], &[], insert_load_store), 661 // Special Stores 662 (Opcode::Istore8, &[I16], &[], insert_load_store), 663 (Opcode::Istore8, &[I32], &[], insert_load_store), 664 (Opcode::Istore8, &[I64], &[], insert_load_store), 665 (Opcode::Istore16, &[I32], &[], insert_load_store), 666 (Opcode::Istore16, &[I64], &[], insert_load_store), 667 (Opcode::Istore32, &[I64], &[], insert_load_store), 668 // Integer Consts 669 (Opcode::Iconst, &[], &[I8], insert_const), 670 (Opcode::Iconst, &[], &[I16], insert_const), 671 (Opcode::Iconst, &[], &[I32], insert_const), 672 (Opcode::Iconst, &[], &[I64], insert_const), 673 (Opcode::Iconst, &[], &[I128], insert_const), 674 // Float Consts 675 (Opcode::F32const, &[], &[F32], insert_const), 676 (Opcode::F64const, &[], &[F64], insert_const), 677 // Bool Consts 678 (Opcode::Bconst, &[], &[B1], insert_const), 679 // Call 680 (Opcode::Call, &[], &[], insert_call), 681 ]; 682 683 type BlockTerminator = fn( 684 fgen: &mut FunctionGenerator, 685 builder: &mut FunctionBuilder, 686 source_block: Block, 687 ) -> Result<()>; 688 689 fn insert_return( 690 fgen: &mut FunctionGenerator, 691 builder: &mut FunctionBuilder, 692 _source_block: Block, 693 ) -> Result<()> { 694 let types: Vec<Type> = { 695 let rets = &builder.func.signature.returns; 696 rets.iter().map(|p| p.value_type).collect() 697 }; 698 let vals = fgen.generate_values_for_signature(builder, types.into_iter())?; 699 700 builder.ins().return_(&vals[..]); 701 Ok(()) 702 } 703 704 fn insert_jump( 705 fgen: &mut FunctionGenerator, 706 builder: &mut FunctionBuilder, 707 source_block: Block, 708 ) -> Result<()> { 709 let (block, args) = fgen.generate_target_block(builder, source_block)?; 710 builder.ins().jump(block, &args[..]); 711 Ok(()) 712 } 713 714 /// Generates a br_table into a random block 715 fn insert_br_table( 716 fgen: &mut FunctionGenerator, 717 builder: &mut FunctionBuilder, 718 source_block: Block, 719 ) -> Result<()> { 720 let var = fgen.get_variable_of_type(I32)?; // br_table only supports I32 721 let val = builder.use_var(var); 722 723 let target_blocks = fgen.resources.forward_blocks_without_params(source_block); 724 let default_block = *fgen.u.choose(target_blocks)?; 725 726 // We can still select a backwards branching jump table here! 727 let tables = fgen.resources.forward_jump_tables(builder, source_block); 728 let jt = *fgen.u.choose(&tables[..])?; 729 builder.ins().br_table(val, default_block, jt); 730 Ok(()) 731 } 732 733 /// Generates a brz/brnz into a random block 734 fn insert_br( 735 fgen: &mut FunctionGenerator, 736 builder: &mut FunctionBuilder, 737 source_block: Block, 738 ) -> Result<()> { 739 let (block, args) = fgen.generate_target_block(builder, source_block)?; 740 741 let condbr_types = [I8, I16, I32, I64, I128, B1]; 742 let _type = *fgen.u.choose(&condbr_types[..])?; 743 let var = fgen.get_variable_of_type(_type)?; 744 let val = builder.use_var(var); 745 746 if bool::arbitrary(fgen.u)? { 747 builder.ins().brz(val, block, &args[..]); 748 } else { 749 builder.ins().brnz(val, block, &args[..]); 750 } 751 752 // After brz/brnz we must generate a jump 753 insert_jump(fgen, builder, source_block)?; 754 Ok(()) 755 } 756 757 fn insert_bricmp( 758 fgen: &mut FunctionGenerator, 759 builder: &mut FunctionBuilder, 760 source_block: Block, 761 ) -> Result<()> { 762 let (block, args) = fgen.generate_target_block(builder, source_block)?; 763 764 let cc = *fgen.u.choose(IntCC::all())?; 765 let _type = *fgen.u.choose(&[I8, I16, I32, I64, I128])?; 766 767 let lhs_var = fgen.get_variable_of_type(_type)?; 768 let lhs_val = builder.use_var(lhs_var); 769 770 let rhs_var = fgen.get_variable_of_type(_type)?; 771 let rhs_val = builder.use_var(rhs_var); 772 773 builder 774 .ins() 775 .br_icmp(cc, lhs_val, rhs_val, block, &args[..]); 776 777 // After bricmp's we must generate a jump 778 insert_jump(fgen, builder, source_block)?; 779 Ok(()) 780 } 781 782 fn insert_switch( 783 fgen: &mut FunctionGenerator, 784 builder: &mut FunctionBuilder, 785 source_block: Block, 786 ) -> Result<()> { 787 let _type = *fgen.u.choose(&[I8, I16, I32, I64, I128][..])?; 788 let switch_var = fgen.get_variable_of_type(_type)?; 789 let switch_val = builder.use_var(switch_var); 790 791 // TODO: We should also generate backwards branches in switches 792 let default_block = { 793 let target_blocks = fgen.resources.forward_blocks_without_params(source_block); 794 *fgen.u.choose(target_blocks)? 795 }; 796 797 // Build this into a HashMap since we cannot have duplicate entries. 798 let mut entries = HashMap::new(); 799 for _ in 0..fgen.param(&fgen.config.switch_cases)? { 800 // The Switch API only allows for entries that are addressable by the index type 801 // so we need to limit the range of values that we generate. 802 let (ty_min, ty_max) = _type.bounds(false); 803 let range_start = fgen.u.int_in_range(ty_min..=ty_max)?; 804 805 // We can either insert a contiguous range of blocks or a individual block 806 // This is done because the Switch API specializes contiguous ranges. 807 let range_size = if bool::arbitrary(fgen.u)? { 808 1 809 } else { 810 fgen.param(&fgen.config.switch_max_range_size)? 811 } as u128; 812 813 // Build the switch entries 814 for i in 0..range_size { 815 let index = range_start.wrapping_add(i) % ty_max; 816 let block = { 817 let target_blocks = fgen.resources.forward_blocks_without_params(source_block); 818 *fgen.u.choose(target_blocks)? 819 }; 820 821 entries.insert(index, block); 822 } 823 } 824 825 let mut switch = Switch::new(); 826 for (entry, block) in entries.into_iter() { 827 switch.set_entry(entry, block); 828 } 829 switch.emit(builder, switch_val, default_block); 830 831 Ok(()) 832 } 833 834 /// These libcalls need a interpreter implementation in `cranelift-fuzzgen.rs` 835 const ALLOWED_LIBCALLS: &'static [LibCall] = &[ 836 LibCall::CeilF32, 837 LibCall::CeilF64, 838 LibCall::FloorF32, 839 LibCall::FloorF64, 840 LibCall::TruncF32, 841 LibCall::TruncF64, 842 ]; 843 844 pub struct FunctionGenerator<'r, 'data> 845 where 846 'data: 'r, 847 { 848 u: &'r mut Unstructured<'data>, 849 config: &'r Config, 850 resources: Resources, 851 } 852 853 #[derive(Default)] 854 struct Resources { 855 vars: HashMap<Type, Vec<Variable>>, 856 blocks: Vec<(Block, BlockSignature)>, 857 blocks_without_params: Vec<Block>, 858 jump_tables: Vec<JumpTable>, 859 func_refs: Vec<(Signature, FuncRef)>, 860 stack_slots: Vec<(StackSlot, StackSize)>, 861 } 862 863 impl Resources { 864 /// Returns [JumpTable]'s where all blocks are forward of `block` 865 fn forward_jump_tables(&self, builder: &FunctionBuilder, block: Block) -> Vec<JumpTable> { 866 // TODO: We can avoid allocating a Vec here by sorting self.jump_tables based 867 // on the minimum block and returning a slice based on that. 868 // See https://github.com/bytecodealliance/wasmtime/pull/4894#discussion_r971241430 for more details 869 870 // Unlike with the blocks below jump table targets are not ordered, thus we do need 871 // to allocate a Vec here. 872 let jump_tables = &builder.func.jump_tables; 873 self.jump_tables 874 .iter() 875 .copied() 876 .filter(|jt| jump_tables[*jt].iter().all(|target| *target > block)) 877 .collect() 878 } 879 880 /// Partitions blocks at `block`. Only blocks that can be targeted by branches are considered. 881 /// 882 /// The first slice includes all blocks up to and including `block`. 883 /// The second slice includes all remaining blocks. 884 fn partition_target_blocks( 885 &self, 886 block: Block, 887 ) -> (&[(Block, BlockSignature)], &[(Block, BlockSignature)]) { 888 // Blocks are stored in-order and have no gaps, this means that we can simply index them by 889 // their number. We also need to exclude the entry block since it isn't a valid target. 890 let target_blocks = &self.blocks[1..]; 891 target_blocks.split_at(block.as_u32() as usize) 892 } 893 894 /// Generates a slice of `blocks_without_params` ahead of `block` 895 fn forward_blocks_without_params(&self, block: Block) -> &[Block] { 896 let partition_point = self.blocks_without_params.partition_point(|b| *b <= block); 897 &self.blocks_without_params[partition_point..] 898 } 899 } 900 901 impl<'r, 'data> FunctionGenerator<'r, 'data> 902 where 903 'data: 'r, 904 { 905 pub fn new(u: &'r mut Unstructured<'data>, config: &'r Config) -> Self { 906 Self { 907 u, 908 config, 909 resources: Resources::default(), 910 } 911 } 912 913 /// Generates a random value for config `param` 914 fn param(&mut self, param: &RangeInclusive<usize>) -> Result<usize> { 915 Ok(self.u.int_in_range(param.clone())?) 916 } 917 918 fn generate_callconv(&mut self) -> Result<CallConv> { 919 // TODO: Generate random CallConvs per target 920 Ok(CallConv::SystemV) 921 } 922 923 fn system_callconv(&mut self) -> CallConv { 924 // TODO: This currently only runs on linux, so this is the only choice 925 // We should improve this once we generate flags and targets 926 CallConv::SystemV 927 } 928 929 fn generate_type(&mut self) -> Result<Type> { 930 // TODO: It would be nice if we could get these directly from cranelift 931 let scalars = [ 932 // IFLAGS, FFLAGS, 933 B1, // B8, B16, B32, B64, B128, 934 I8, I16, I32, I64, I128, F32, F64, 935 // R32, R64, 936 ]; 937 // TODO: vector types 938 939 let ty = self.u.choose(&scalars[..])?; 940 Ok(*ty) 941 } 942 943 fn generate_abi_param(&mut self) -> Result<AbiParam> { 944 let value_type = self.generate_type()?; 945 // TODO: There are more argument purposes to be explored... 946 let purpose = ArgumentPurpose::Normal; 947 let extension = match self.u.int_in_range(0..=2)? { 948 2 => ArgumentExtension::Sext, 949 1 => ArgumentExtension::Uext, 950 _ => ArgumentExtension::None, 951 }; 952 953 Ok(AbiParam { 954 value_type, 955 purpose, 956 extension, 957 }) 958 } 959 960 fn generate_signature(&mut self) -> Result<Signature> { 961 let callconv = self.generate_callconv()?; 962 let mut sig = Signature::new(callconv); 963 964 for _ in 0..self.param(&self.config.signature_params)? { 965 sig.params.push(self.generate_abi_param()?); 966 } 967 968 for _ in 0..self.param(&self.config.signature_rets)? { 969 sig.returns.push(self.generate_abi_param()?); 970 } 971 972 Ok(sig) 973 } 974 975 /// Finds a stack slot with size of at least n bytes 976 fn stack_slot_with_size(&mut self, n: u32) -> Result<(StackSlot, StackSize)> { 977 let first = self 978 .resources 979 .stack_slots 980 .partition_point(|&(_slot, size)| size < n); 981 Ok(*self.u.choose(&self.resources.stack_slots[first..])?) 982 } 983 984 /// Generates an address that should allow for a store or a load. 985 /// 986 /// Addresses aren't generated like other values. They are never stored in variables so that 987 /// we don't run the risk of returning them from a function, which would make the fuzzer 988 /// complain since they are different from the interpreter to the backend. 989 /// 990 /// The address is not guaranteed to be valid, but there's a chance that it is. 991 /// 992 /// `min_size`: Controls the amount of space that the address should have.This is not 993 /// guaranteed to be respected 994 fn generate_load_store_address( 995 &mut self, 996 builder: &mut FunctionBuilder, 997 min_size: u32, 998 ) -> Result<(Value, Offset32)> { 999 // TODO: Currently our only source of addresses is stack_addr, but we should 1000 // add heap_addr, global_value, symbol_value eventually 1001 let (addr, available_size) = { 1002 let (ss, slot_size) = self.stack_slot_with_size(min_size)?; 1003 let max_offset = slot_size.saturating_sub(min_size); 1004 let offset = self.u.int_in_range(0..=max_offset)? as i32; 1005 let base_addr = builder.ins().stack_addr(I64, ss, offset); 1006 let available_size = (slot_size as i32).saturating_sub(offset); 1007 (base_addr, available_size) 1008 }; 1009 1010 // TODO: Insert a bunch of amode opcodes here to modify the address! 1011 1012 // Now that we have an address and a size, we just choose a random offset to return to the 1013 // caller. Try to preserve min_size bytes. 1014 let max_offset = available_size.saturating_sub(min_size as i32); 1015 let offset = self.u.int_in_range(0..=max_offset)? as i32; 1016 1017 Ok((addr, offset.into())) 1018 } 1019 1020 /// Get a variable of type `ty` from the current function 1021 fn get_variable_of_type(&mut self, ty: Type) -> Result<Variable> { 1022 let opts = self.resources.vars.get(&ty).map_or(&[][..], Vec::as_slice); 1023 let var = self.u.choose(opts)?; 1024 Ok(*var) 1025 } 1026 1027 /// Generates an instruction(`iconst`/`fconst`/etc...) to introduce a constant value 1028 fn generate_const(&mut self, builder: &mut FunctionBuilder, ty: Type) -> Result<Value> { 1029 Ok(match ty { 1030 I128 => { 1031 // See: https://github.com/bytecodealliance/wasmtime/issues/2906 1032 let hi = builder.ins().iconst(I64, self.u.arbitrary::<i64>()?); 1033 let lo = builder.ins().iconst(I64, self.u.arbitrary::<i64>()?); 1034 builder.ins().iconcat(lo, hi) 1035 } 1036 ty if ty.is_int() => { 1037 let imm64 = match ty { 1038 I8 => self.u.arbitrary::<i8>()? as i64, 1039 I16 => self.u.arbitrary::<i16>()? as i64, 1040 I32 => self.u.arbitrary::<i32>()? as i64, 1041 I64 => self.u.arbitrary::<i64>()?, 1042 _ => unreachable!(), 1043 }; 1044 builder.ins().iconst(ty, imm64) 1045 } 1046 ty if ty.is_bool() => builder.ins().bconst(ty, bool::arbitrary(self.u)?), 1047 // f{32,64}::arbitrary does not generate a bunch of important values 1048 // such as Signaling NaN's / NaN's with payload, so generate floats from integers. 1049 F32 => builder 1050 .ins() 1051 .f32const(f32::from_bits(u32::arbitrary(self.u)?)), 1052 F64 => builder 1053 .ins() 1054 .f64const(f64::from_bits(u64::arbitrary(self.u)?)), 1055 _ => unimplemented!(), 1056 }) 1057 } 1058 1059 /// Chooses a random block which can be targeted by a jump / branch. 1060 /// This means any block that is not the first block. 1061 /// 1062 /// For convenience we also generate values that match the block's signature 1063 fn generate_target_block( 1064 &mut self, 1065 builder: &mut FunctionBuilder, 1066 source_block: Block, 1067 ) -> Result<(Block, Vec<Value>)> { 1068 // We try to mostly generate forward branches to avoid generating an excessive amount of 1069 // infinite loops. But they are still important, so give them a small chance of existing. 1070 let (backwards_blocks, forward_blocks) = 1071 self.resources.partition_target_blocks(source_block); 1072 let ratio = self.config.backwards_branch_ratio; 1073 let block_targets = if !backwards_blocks.is_empty() && self.u.ratio(ratio.0, ratio.1)? { 1074 backwards_blocks 1075 } else { 1076 forward_blocks 1077 }; 1078 assert!(!block_targets.is_empty()); 1079 1080 let (block, signature) = self.u.choose(block_targets)?.clone(); 1081 let args = self.generate_values_for_signature(builder, signature.into_iter())?; 1082 Ok((block, args)) 1083 } 1084 1085 fn generate_values_for_signature<I: Iterator<Item = Type>>( 1086 &mut self, 1087 builder: &mut FunctionBuilder, 1088 signature: I, 1089 ) -> Result<Vec<Value>> { 1090 signature 1091 .map(|ty| { 1092 let var = self.get_variable_of_type(ty)?; 1093 let val = builder.use_var(var); 1094 Ok(val) 1095 }) 1096 .collect() 1097 } 1098 1099 /// We always need to exit safely out of a block. 1100 /// This either means a jump into another block or a return. 1101 fn finalize_block(&mut self, builder: &mut FunctionBuilder, source_block: Block) -> Result<()> { 1102 let has_jump_tables = !self 1103 .resources 1104 .forward_jump_tables(builder, source_block) 1105 .is_empty(); 1106 1107 let has_forward_blocks = { 1108 let (_, forward_blocks) = self.resources.partition_target_blocks(source_block); 1109 !forward_blocks.is_empty() 1110 }; 1111 1112 let has_forward_blocks_without_params = !self 1113 .resources 1114 .forward_blocks_without_params(source_block) 1115 .is_empty(); 1116 1117 let terminators: &[(BlockTerminator, bool)] = &[ 1118 // Return is always a valid option 1119 (insert_return, true), 1120 // If we have forward blocks, we can allow generating jumps and branches 1121 (insert_jump, has_forward_blocks), 1122 (insert_br, has_forward_blocks), 1123 (insert_bricmp, has_forward_blocks), 1124 // Switches can only use blocks without params 1125 (insert_switch, has_forward_blocks_without_params), 1126 // We need both jump tables and a default block for br_table 1127 ( 1128 insert_br_table, 1129 has_jump_tables && has_forward_blocks_without_params, 1130 ), 1131 ]; 1132 1133 let terminators: Vec<_> = terminators 1134 .into_iter() 1135 .filter(|(_, valid)| *valid) 1136 .map(|(term, _)| term) 1137 .collect(); 1138 1139 let inserter = self.u.choose(&terminators[..])?; 1140 inserter(self, builder, source_block)?; 1141 1142 Ok(()) 1143 } 1144 1145 /// Fills the current block with random instructions 1146 fn generate_instructions(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 1147 for _ in 0..self.param(&self.config.instructions_per_block)? { 1148 let (op, args, rets, inserter) = *self.u.choose(OPCODE_SIGNATURES)?; 1149 inserter(self, builder, op, args, rets)?; 1150 } 1151 1152 Ok(()) 1153 } 1154 1155 fn generate_jumptables(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 1156 // We shouldn't try to generate jumptables if we don't have any valid targets! 1157 if self.resources.blocks_without_params.is_empty() { 1158 return Ok(()); 1159 } 1160 1161 for _ in 0..self.param(&self.config.jump_tables_per_function)? { 1162 let mut jt_data = JumpTableData::new(); 1163 1164 for _ in 0..self.param(&self.config.jump_table_entries)? { 1165 let block = *self.u.choose(&self.resources.blocks_without_params)?; 1166 jt_data.push_entry(block); 1167 } 1168 1169 self.resources 1170 .jump_tables 1171 .push(builder.create_jump_table(jt_data)); 1172 } 1173 Ok(()) 1174 } 1175 1176 fn generate_funcrefs(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 1177 let count = self.param(&self.config.funcrefs_per_function)?; 1178 for func_index in 0..count.try_into().unwrap() { 1179 let (ext_name, sig) = if self.u.arbitrary::<bool>()? { 1180 let user_func_ref = builder 1181 .func 1182 .declare_imported_user_function(UserExternalName { 1183 namespace: 0, 1184 index: func_index, 1185 }); 1186 let name = ExternalName::User(user_func_ref); 1187 let signature = self.generate_signature()?; 1188 (name, signature) 1189 } else { 1190 let libcall = *self.u.choose(ALLOWED_LIBCALLS)?; 1191 // TODO: Use [CallConv::for_libcall] once we generate flags. 1192 let callconv = self.system_callconv(); 1193 let signature = libcall.signature(callconv); 1194 (ExternalName::LibCall(libcall), signature) 1195 }; 1196 1197 let sig_ref = builder.import_signature(sig.clone()); 1198 let func_ref = builder.import_function(ExtFuncData { 1199 name: ext_name, 1200 signature: sig_ref, 1201 colocated: self.u.arbitrary()?, 1202 }); 1203 1204 self.resources.func_refs.push((sig, func_ref)); 1205 } 1206 1207 Ok(()) 1208 } 1209 1210 fn generate_stack_slots(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 1211 for _ in 0..self.param(&self.config.static_stack_slots_per_function)? { 1212 let bytes = self.param(&self.config.static_stack_slot_size)? as u32; 1213 let ss_data = StackSlotData::new(StackSlotKind::ExplicitSlot, bytes); 1214 let slot = builder.create_sized_stack_slot(ss_data); 1215 self.resources.stack_slots.push((slot, bytes)); 1216 } 1217 1218 self.resources 1219 .stack_slots 1220 .sort_unstable_by_key(|&(_slot, bytes)| bytes); 1221 1222 Ok(()) 1223 } 1224 1225 /// Zero initializes the stack slot by inserting `stack_store`'s. 1226 fn initialize_stack_slots(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 1227 let i128_zero = builder.ins().iconst(I128, 0); 1228 let i64_zero = builder.ins().iconst(I64, 0); 1229 let i32_zero = builder.ins().iconst(I32, 0); 1230 let i16_zero = builder.ins().iconst(I16, 0); 1231 let i8_zero = builder.ins().iconst(I8, 0); 1232 1233 for &(slot, init_size) in self.resources.stack_slots.iter() { 1234 let mut size = init_size; 1235 1236 // Insert the largest available store for the remaining size. 1237 while size != 0 { 1238 let offset = (init_size - size) as i32; 1239 let (val, filled) = match size { 1240 sz if sz / 16 > 0 => (i128_zero, 16), 1241 sz if sz / 8 > 0 => (i64_zero, 8), 1242 sz if sz / 4 > 0 => (i32_zero, 4), 1243 sz if sz / 2 > 0 => (i16_zero, 2), 1244 _ => (i8_zero, 1), 1245 }; 1246 builder.ins().stack_store(val, slot, offset); 1247 size -= filled; 1248 } 1249 } 1250 Ok(()) 1251 } 1252 1253 /// Creates a random amount of blocks in this function 1254 fn generate_blocks(&mut self, builder: &mut FunctionBuilder, sig: &Signature) -> Result<()> { 1255 let extra_block_count = self.param(&self.config.blocks_per_function)?; 1256 1257 // We must always have at least one block, so we generate the "extra" blocks and add 1 for 1258 // the entry block. 1259 let block_count = 1 + extra_block_count; 1260 1261 // Blocks need to be sorted in ascending order 1262 self.resources.blocks = (0..block_count) 1263 .map(|i| { 1264 let is_entry = i == 0; 1265 let block = builder.create_block(); 1266 1267 // Optionally mark blocks that are not the entry block as cold 1268 if !is_entry { 1269 if bool::arbitrary(self.u)? { 1270 builder.set_cold_block(block); 1271 } 1272 } 1273 1274 // The first block has to have the function signature, but for the rest of them we generate 1275 // a random signature; 1276 if is_entry { 1277 builder.append_block_params_for_function_params(block); 1278 Ok((block, sig.params.iter().map(|a| a.value_type).collect())) 1279 } else { 1280 let sig = self.generate_block_signature()?; 1281 sig.iter().for_each(|ty| { 1282 builder.append_block_param(block, *ty); 1283 }); 1284 Ok((block, sig)) 1285 } 1286 }) 1287 .collect::<Result<Vec<_>>>()?; 1288 1289 // Valid blocks for jump tables have to have no parameters in the signature, and must also 1290 // not be the first block. 1291 self.resources.blocks_without_params = self.resources.blocks[1..] 1292 .iter() 1293 .filter(|(_, sig)| sig.len() == 0) 1294 .map(|(b, _)| *b) 1295 .collect(); 1296 1297 Ok(()) 1298 } 1299 1300 fn generate_block_signature(&mut self) -> Result<BlockSignature> { 1301 let param_count = self.param(&self.config.block_signature_params)?; 1302 1303 let mut params = Vec::with_capacity(param_count); 1304 for _ in 0..param_count { 1305 params.push(self.generate_type()?); 1306 } 1307 Ok(params) 1308 } 1309 1310 fn build_variable_pool(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 1311 let block = builder.current_block().unwrap(); 1312 1313 // Define variables for the function signature 1314 let mut vars: Vec<_> = builder 1315 .func 1316 .signature 1317 .params 1318 .iter() 1319 .map(|param| param.value_type) 1320 .zip(builder.block_params(block).iter().copied()) 1321 .collect(); 1322 1323 // Create a pool of vars that are going to be used in this function 1324 for _ in 0..self.param(&self.config.vars_per_function)? { 1325 let ty = self.generate_type()?; 1326 let value = self.generate_const(builder, ty)?; 1327 vars.push((ty, value)); 1328 } 1329 1330 for (id, (ty, value)) in vars.into_iter().enumerate() { 1331 let var = Variable::new(id); 1332 builder.declare_var(var, ty); 1333 builder.def_var(var, value); 1334 self.resources 1335 .vars 1336 .entry(ty) 1337 .or_insert_with(Vec::new) 1338 .push(var); 1339 } 1340 1341 Ok(()) 1342 } 1343 1344 /// We generate a function in multiple stages: 1345 /// 1346 /// * First we generate a random number of empty blocks 1347 /// * Then we generate a random pool of variables to be used throughout the function 1348 /// * We then visit each block and generate random instructions 1349 /// 1350 /// Because we generate all blocks and variables up front we already know everything that 1351 /// we need when generating instructions (i.e. jump targets / variables) 1352 pub fn generate(mut self) -> Result<Function> { 1353 let sig = self.generate_signature()?; 1354 1355 let mut fn_builder_ctx = FunctionBuilderContext::new(); 1356 // function name must be in a different namespace than TESTFILE_NAMESPACE (0) 1357 let mut func = Function::with_name_signature(UserFuncName::user(1, 0), sig.clone()); 1358 1359 let mut builder = FunctionBuilder::new(&mut func, &mut fn_builder_ctx); 1360 1361 self.generate_blocks(&mut builder, &sig)?; 1362 1363 // Function preamble 1364 self.generate_jumptables(&mut builder)?; 1365 self.generate_funcrefs(&mut builder)?; 1366 self.generate_stack_slots(&mut builder)?; 1367 1368 // Main instruction generation loop 1369 for (block, block_sig) in self.resources.blocks.clone().into_iter() { 1370 let is_block0 = block.as_u32() == 0; 1371 builder.switch_to_block(block); 1372 1373 if is_block0 { 1374 // The first block is special because we must create variables both for the 1375 // block signature and for the variable pool. Additionally, we must also define 1376 // initial values for all variables that are not the function signature. 1377 self.build_variable_pool(&mut builder)?; 1378 1379 // Stack slots have random bytes at the beginning of the function 1380 // initialize them to a constant value so that execution stays predictable. 1381 self.initialize_stack_slots(&mut builder)?; 1382 } else { 1383 // Define variables for the block params 1384 for (i, ty) in block_sig.iter().enumerate() { 1385 let var = self.get_variable_of_type(*ty)?; 1386 let block_param = builder.block_params(block)[i]; 1387 builder.def_var(var, block_param); 1388 } 1389 } 1390 1391 // Generate block instructions 1392 self.generate_instructions(&mut builder)?; 1393 1394 self.finalize_block(&mut builder, block)?; 1395 } 1396 1397 builder.seal_all_blocks(); 1398 builder.finalize(); 1399 1400 Ok(func) 1401 } 1402 } 1403