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, 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 /// Generates a Vec with `len` elements comprised of `options` 22 fn arbitrary_vec<T: Clone>( 23 u: &mut Unstructured, 24 len: usize, 25 options: &[T], 26 ) -> arbitrary::Result<Vec<T>> { 27 (0..len).map(|_| u.choose(options).cloned()).collect() 28 } 29 30 type BlockSignature = Vec<Type>; 31 32 fn insert_opcode( 33 fgen: &mut FunctionGenerator, 34 builder: &mut FunctionBuilder, 35 opcode: Opcode, 36 args: &'static [Type], 37 rets: &'static [Type], 38 ) -> Result<()> { 39 let mut vals = Vec::with_capacity(args.len()); 40 for &arg in args.into_iter() { 41 let var = fgen.get_variable_of_type(arg)?; 42 let val = builder.use_var(var); 43 vals.push(val); 44 } 45 46 // For pretty much every instruction the control type is the return type 47 // except for Iconcat and Isplit which are *special* and the control type 48 // is the input type. 49 let ctrl_type = if opcode == Opcode::Iconcat || opcode == Opcode::Isplit { 50 args.first() 51 } else { 52 rets.first() 53 } 54 .copied() 55 .unwrap_or(INVALID); 56 57 // Choose the appropriate instruction format for this opcode 58 let (inst, dfg) = match opcode.format() { 59 InstructionFormat::NullAry => builder.ins().NullAry(opcode, ctrl_type), 60 InstructionFormat::Unary => builder.ins().Unary(opcode, ctrl_type, vals[0]), 61 InstructionFormat::Binary => builder.ins().Binary(opcode, ctrl_type, vals[0], vals[1]), 62 InstructionFormat::Ternary => builder 63 .ins() 64 .Ternary(opcode, ctrl_type, vals[0], vals[1], vals[2]), 65 _ => unimplemented!(), 66 }; 67 let results = dfg.inst_results(inst).to_vec(); 68 69 for (val, &ty) in results.into_iter().zip(rets) { 70 let var = fgen.get_variable_of_type(ty)?; 71 builder.def_var(var, val); 72 } 73 Ok(()) 74 } 75 76 // `select_spectre_guard` is only implemented when preceded by a `icmp` 77 // This ensures that we always insert it that way. 78 fn insert_select_spectre_guard( 79 fgen: &mut FunctionGenerator, 80 builder: &mut FunctionBuilder, 81 _opcode: Opcode, 82 args: &'static [Type], 83 rets: &'static [Type], 84 ) -> Result<()> { 85 let icmp_ty = args[0]; 86 let icmp_lhs = builder.use_var(fgen.get_variable_of_type(icmp_ty)?); 87 let icmp_rhs = builder.use_var(fgen.get_variable_of_type(icmp_ty)?); 88 let cc = *fgen.u.choose(IntCC::all())?; 89 let icmp_res = builder.ins().icmp(cc, icmp_lhs, icmp_rhs); 90 91 let select_lhs = builder.use_var(fgen.get_variable_of_type(args[1])?); 92 let select_rhs = builder.use_var(fgen.get_variable_of_type(args[2])?); 93 let select_res = builder 94 .ins() 95 .select_spectre_guard(icmp_res, select_lhs, select_rhs); 96 97 let var = fgen.get_variable_of_type(rets[0])?; 98 builder.def_var(var, select_res); 99 100 Ok(()) 101 } 102 103 fn insert_call( 104 fgen: &mut FunctionGenerator, 105 builder: &mut FunctionBuilder, 106 opcode: Opcode, 107 _args: &'static [Type], 108 _rets: &'static [Type], 109 ) -> Result<()> { 110 assert_eq!(opcode, Opcode::Call, "only call handled at the moment"); 111 let (sig, func_ref) = fgen.u.choose(&fgen.resources.func_refs)?.clone(); 112 113 let actuals = fgen.generate_values_for_signature( 114 builder, 115 sig.params.iter().map(|abi_param| abi_param.value_type), 116 )?; 117 118 builder.ins().call(func_ref, &actuals); 119 Ok(()) 120 } 121 122 fn insert_stack_load( 123 fgen: &mut FunctionGenerator, 124 builder: &mut FunctionBuilder, 125 _opcode: Opcode, 126 _args: &'static [Type], 127 rets: &'static [Type], 128 ) -> Result<()> { 129 let typevar = rets[0]; 130 let type_size = typevar.bytes(); 131 let (slot, slot_size) = fgen.stack_slot_with_size(type_size)?; 132 let offset = fgen.u.int_in_range(0..=(slot_size - type_size))? as i32; 133 134 let val = builder.ins().stack_load(typevar, slot, offset); 135 let var = fgen.get_variable_of_type(typevar)?; 136 builder.def_var(var, val); 137 138 Ok(()) 139 } 140 141 fn insert_stack_store( 142 fgen: &mut FunctionGenerator, 143 builder: &mut FunctionBuilder, 144 _opcode: Opcode, 145 args: &'static [Type], 146 _rets: &'static [Type], 147 ) -> Result<()> { 148 let typevar = args[0]; 149 let type_size = typevar.bytes(); 150 let (slot, slot_size) = fgen.stack_slot_with_size(type_size)?; 151 let offset = fgen.u.int_in_range(0..=(slot_size - type_size))? as i32; 152 153 let arg0 = fgen.get_variable_of_type(typevar)?; 154 let arg0 = builder.use_var(arg0); 155 156 builder.ins().stack_store(arg0, slot, offset); 157 Ok(()) 158 } 159 160 fn insert_cmp( 161 fgen: &mut FunctionGenerator, 162 builder: &mut FunctionBuilder, 163 opcode: Opcode, 164 args: &'static [Type], 165 rets: &'static [Type], 166 ) -> Result<()> { 167 let lhs = fgen.get_variable_of_type(args[0])?; 168 let lhs = builder.use_var(lhs); 169 170 let rhs = fgen.get_variable_of_type(args[1])?; 171 let rhs = builder.use_var(rhs); 172 173 let res = if opcode == Opcode::Fcmp { 174 // Some FloatCC's are not implemented on AArch64, see: 175 // https://github.com/bytecodealliance/wasmtime/issues/4850 176 let float_cc = if cfg!(target_arch = "aarch64") { 177 &[ 178 FloatCC::Ordered, 179 FloatCC::Unordered, 180 FloatCC::Equal, 181 FloatCC::NotEqual, 182 FloatCC::LessThan, 183 FloatCC::LessThanOrEqual, 184 FloatCC::GreaterThan, 185 FloatCC::GreaterThanOrEqual, 186 ] 187 } else { 188 FloatCC::all() 189 }; 190 191 let cc = *fgen.u.choose(float_cc)?; 192 builder.ins().fcmp(cc, lhs, rhs) 193 } else { 194 let cc = *fgen.u.choose(IntCC::all())?; 195 builder.ins().icmp(cc, lhs, rhs) 196 }; 197 198 let var = fgen.get_variable_of_type(rets[0])?; 199 builder.def_var(var, res); 200 201 Ok(()) 202 } 203 204 fn insert_const( 205 fgen: &mut FunctionGenerator, 206 builder: &mut FunctionBuilder, 207 _opcode: Opcode, 208 _args: &'static [Type], 209 rets: &'static [Type], 210 ) -> Result<()> { 211 let typevar = rets[0]; 212 let var = fgen.get_variable_of_type(typevar)?; 213 let val = fgen.generate_const(builder, typevar)?; 214 builder.def_var(var, val); 215 Ok(()) 216 } 217 218 fn insert_load_store( 219 fgen: &mut FunctionGenerator, 220 builder: &mut FunctionBuilder, 221 opcode: Opcode, 222 args: &'static [Type], 223 rets: &'static [Type], 224 ) -> Result<()> { 225 let ctrl_type = *rets.first().or(args.first()).unwrap(); 226 let type_size = ctrl_type.bytes(); 227 let (address, offset) = fgen.generate_load_store_address(builder, type_size)?; 228 229 // TODO: More advanced MemFlags 230 let flags = MemFlags::new(); 231 232 // The variable being loaded or stored into 233 let var = fgen.get_variable_of_type(ctrl_type)?; 234 235 if opcode.can_store() { 236 let val = builder.use_var(var); 237 238 builder 239 .ins() 240 .Store(opcode, ctrl_type, flags, offset, val, address); 241 } else { 242 let (inst, dfg) = builder 243 .ins() 244 .Load(opcode, ctrl_type, flags, offset, address); 245 246 let new_val = dfg.first_result(inst); 247 builder.def_var(var, new_val); 248 } 249 250 Ok(()) 251 } 252 253 type OpcodeInserter = fn( 254 fgen: &mut FunctionGenerator, 255 builder: &mut FunctionBuilder, 256 Opcode, 257 &'static [Type], 258 &'static [Type], 259 ) -> Result<()>; 260 261 // TODO: Derive this from the `cranelift-meta` generator. 262 #[rustfmt::skip] 263 const OPCODE_SIGNATURES: &'static [( 264 Opcode, 265 &'static [Type], // Args 266 &'static [Type], // Rets 267 OpcodeInserter, 268 )] = &[ 269 (Opcode::Nop, &[], &[], insert_opcode), 270 // Iadd 271 (Opcode::Iadd, &[I8, I8], &[I8], insert_opcode), 272 (Opcode::Iadd, &[I16, I16], &[I16], insert_opcode), 273 (Opcode::Iadd, &[I32, I32], &[I32], insert_opcode), 274 (Opcode::Iadd, &[I64, I64], &[I64], insert_opcode), 275 (Opcode::Iadd, &[I128, I128], &[I128], insert_opcode), 276 // IaddCout 277 // IaddCout not implemented in x64 278 #[cfg(not(target_arch = "x86_64"))] 279 (Opcode::IaddCout, &[I8, I8], &[I8, I8], insert_opcode), 280 #[cfg(not(target_arch = "x86_64"))] 281 (Opcode::IaddCout, &[I16, I16], &[I16, I8], insert_opcode), 282 #[cfg(not(target_arch = "x86_64"))] 283 (Opcode::IaddCout, &[I32, I32], &[I32, I8], insert_opcode), 284 #[cfg(not(target_arch = "x86_64"))] 285 (Opcode::IaddCout, &[I64, I64], &[I64, I8], insert_opcode), 286 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 287 (Opcode::IaddCout, &[I128, I128], &[I128, I8], insert_opcode), 288 // Isub 289 (Opcode::Isub, &[I8, I8], &[I8], insert_opcode), 290 (Opcode::Isub, &[I16, I16], &[I16], insert_opcode), 291 (Opcode::Isub, &[I32, I32], &[I32], insert_opcode), 292 (Opcode::Isub, &[I64, I64], &[I64], insert_opcode), 293 (Opcode::Isub, &[I128, I128], &[I128], insert_opcode), 294 // Imul 295 (Opcode::Imul, &[I8, I8], &[I8], insert_opcode), 296 (Opcode::Imul, &[I16, I16], &[I16], insert_opcode), 297 (Opcode::Imul, &[I32, I32], &[I32], insert_opcode), 298 (Opcode::Imul, &[I64, I64], &[I64], insert_opcode), 299 (Opcode::Imul, &[I128, I128], &[I128], insert_opcode), 300 // Udiv 301 (Opcode::Udiv, &[I8, I8], &[I8], insert_opcode), 302 (Opcode::Udiv, &[I16, I16], &[I16], insert_opcode), 303 (Opcode::Udiv, &[I32, I32], &[I32], insert_opcode), 304 (Opcode::Udiv, &[I64, I64], &[I64], insert_opcode), 305 // udiv.i128 not implemented in some backends: 306 // x64: https://github.com/bytecodealliance/wasmtime/issues/4756 307 // aarch64: https://github.com/bytecodealliance/wasmtime/issues/4864 308 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 309 (Opcode::Udiv, &[I128, I128], &[I128], insert_opcode), 310 // Sdiv 311 (Opcode::Sdiv, &[I8, I8], &[I8], insert_opcode), 312 (Opcode::Sdiv, &[I16, I16], &[I16], insert_opcode), 313 (Opcode::Sdiv, &[I32, I32], &[I32], insert_opcode), 314 (Opcode::Sdiv, &[I64, I64], &[I64], insert_opcode), 315 // sdiv.i128 not implemented in some backends: 316 // x64: https://github.com/bytecodealliance/wasmtime/issues/4770 317 // aarch64: https://github.com/bytecodealliance/wasmtime/issues/4864 318 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 319 (Opcode::Sdiv, &[I128, I128], &[I128], insert_opcode), 320 // Ineg 321 (Opcode::Ineg, &[I8, I8], &[I8], insert_opcode), 322 (Opcode::Ineg, &[I16, I16], &[I16], insert_opcode), 323 (Opcode::Ineg, &[I32, I32], &[I32], insert_opcode), 324 (Opcode::Ineg, &[I64, I64], &[I64], insert_opcode), 325 (Opcode::Ineg, &[I128, I128], &[I128], insert_opcode), 326 // Smin 327 // smin not implemented in some backends: 328 // x64: https://github.com/bytecodealliance/wasmtime/issues/3370 329 // aarch64: https://github.com/bytecodealliance/wasmtime/issues/4313 330 #[cfg(not(target_arch = "aarch64"))] 331 (Opcode::Smin, &[I8, I8], &[I8], insert_opcode), 332 #[cfg(not(target_arch = "aarch64"))] 333 (Opcode::Smin, &[I16, I16], &[I16], insert_opcode), 334 #[cfg(not(target_arch = "aarch64"))] 335 (Opcode::Smin, &[I32, I32], &[I32], insert_opcode), 336 #[cfg(not(target_arch = "aarch64"))] 337 (Opcode::Smin, &[I64, I64], &[I64], insert_opcode), 338 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 339 (Opcode::Smin, &[I128, I128], &[I128], insert_opcode), 340 // Umin 341 // umin not implemented in some backends: 342 // x64: https://github.com/bytecodealliance/wasmtime/issues/3370 343 // aarch64: https://github.com/bytecodealliance/wasmtime/issues/4313 344 #[cfg(not(target_arch = "aarch64"))] 345 (Opcode::Umin, &[I8, I8], &[I8], insert_opcode), 346 #[cfg(not(target_arch = "aarch64"))] 347 (Opcode::Umin, &[I16, I16], &[I16], insert_opcode), 348 #[cfg(not(target_arch = "aarch64"))] 349 (Opcode::Umin, &[I32, I32], &[I32], insert_opcode), 350 #[cfg(not(target_arch = "aarch64"))] 351 (Opcode::Umin, &[I64, I64], &[I64], insert_opcode), 352 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 353 (Opcode::Umin, &[I128, I128], &[I128], insert_opcode), 354 // Smax 355 // smax not implemented in some backends: 356 // x64: https://github.com/bytecodealliance/wasmtime/issues/3370 357 // aarch64: https://github.com/bytecodealliance/wasmtime/issues/4313 358 #[cfg(not(target_arch = "aarch64"))] 359 (Opcode::Smax, &[I8, I8], &[I8], insert_opcode), 360 #[cfg(not(target_arch = "aarch64"))] 361 (Opcode::Smax, &[I16, I16], &[I16], insert_opcode), 362 #[cfg(not(target_arch = "aarch64"))] 363 (Opcode::Smax, &[I32, I32], &[I32], insert_opcode), 364 #[cfg(not(target_arch = "aarch64"))] 365 (Opcode::Smax, &[I64, I64], &[I64], insert_opcode), 366 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 367 (Opcode::Smax, &[I128, I128], &[I128], insert_opcode), 368 // Umax 369 // umax not implemented in some backends: 370 // x64: https://github.com/bytecodealliance/wasmtime/issues/3370 371 // aarch64: https://github.com/bytecodealliance/wasmtime/issues/4313 372 #[cfg(not(target_arch = "aarch64"))] 373 (Opcode::Umax, &[I8, I8], &[I8], insert_opcode), 374 #[cfg(not(target_arch = "aarch64"))] 375 (Opcode::Umax, &[I16, I16], &[I16], insert_opcode), 376 #[cfg(not(target_arch = "aarch64"))] 377 (Opcode::Umax, &[I32, I32], &[I32], insert_opcode), 378 #[cfg(not(target_arch = "aarch64"))] 379 (Opcode::Umax, &[I64, I64], &[I64], insert_opcode), 380 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 381 (Opcode::Umax, &[I128, I128], &[I128], insert_opcode), 382 // Rotr 383 (Opcode::Rotr, &[I8, I8], &[I8], insert_opcode), 384 (Opcode::Rotr, &[I8, I16], &[I8], insert_opcode), 385 (Opcode::Rotr, &[I8, I32], &[I8], insert_opcode), 386 (Opcode::Rotr, &[I8, I64], &[I8], insert_opcode), 387 (Opcode::Rotr, &[I8, I128], &[I8], insert_opcode), 388 (Opcode::Rotr, &[I16, I8], &[I16], insert_opcode), 389 (Opcode::Rotr, &[I16, I16], &[I16], insert_opcode), 390 (Opcode::Rotr, &[I16, I32], &[I16], insert_opcode), 391 (Opcode::Rotr, &[I16, I64], &[I16], insert_opcode), 392 (Opcode::Rotr, &[I16, I128], &[I16], insert_opcode), 393 (Opcode::Rotr, &[I32, I8], &[I32], insert_opcode), 394 (Opcode::Rotr, &[I32, I16], &[I32], insert_opcode), 395 (Opcode::Rotr, &[I32, I32], &[I32], insert_opcode), 396 (Opcode::Rotr, &[I32, I64], &[I32], insert_opcode), 397 (Opcode::Rotr, &[I32, I128], &[I32], insert_opcode), 398 (Opcode::Rotr, &[I64, I8], &[I64], insert_opcode), 399 (Opcode::Rotr, &[I64, I16], &[I64], insert_opcode), 400 (Opcode::Rotr, &[I64, I32], &[I64], insert_opcode), 401 (Opcode::Rotr, &[I64, I64], &[I64], insert_opcode), 402 (Opcode::Rotr, &[I64, I128], &[I64], insert_opcode), 403 (Opcode::Rotr, &[I128, I8], &[I128], insert_opcode), 404 (Opcode::Rotr, &[I128, I16], &[I128], insert_opcode), 405 (Opcode::Rotr, &[I128, I32], &[I128], insert_opcode), 406 (Opcode::Rotr, &[I128, I64], &[I128], insert_opcode), 407 (Opcode::Rotr, &[I128, I128], &[I128], insert_opcode), 408 // Rotl 409 (Opcode::Rotl, &[I8, I8], &[I8], insert_opcode), 410 (Opcode::Rotl, &[I8, I16], &[I8], insert_opcode), 411 (Opcode::Rotl, &[I8, I32], &[I8], insert_opcode), 412 (Opcode::Rotl, &[I8, I64], &[I8], insert_opcode), 413 (Opcode::Rotl, &[I8, I128], &[I8], insert_opcode), 414 (Opcode::Rotl, &[I16, I8], &[I16], insert_opcode), 415 (Opcode::Rotl, &[I16, I16], &[I16], insert_opcode), 416 (Opcode::Rotl, &[I16, I32], &[I16], insert_opcode), 417 (Opcode::Rotl, &[I16, I64], &[I16], insert_opcode), 418 (Opcode::Rotl, &[I16, I128], &[I16], insert_opcode), 419 (Opcode::Rotl, &[I32, I8], &[I32], insert_opcode), 420 (Opcode::Rotl, &[I32, I16], &[I32], insert_opcode), 421 (Opcode::Rotl, &[I32, I32], &[I32], insert_opcode), 422 (Opcode::Rotl, &[I32, I64], &[I32], insert_opcode), 423 (Opcode::Rotl, &[I32, I128], &[I32], insert_opcode), 424 (Opcode::Rotl, &[I64, I8], &[I64], insert_opcode), 425 (Opcode::Rotl, &[I64, I16], &[I64], insert_opcode), 426 (Opcode::Rotl, &[I64, I32], &[I64], insert_opcode), 427 (Opcode::Rotl, &[I64, I64], &[I64], insert_opcode), 428 (Opcode::Rotl, &[I64, I128], &[I64], insert_opcode), 429 (Opcode::Rotl, &[I128, I8], &[I128], insert_opcode), 430 (Opcode::Rotl, &[I128, I16], &[I128], insert_opcode), 431 (Opcode::Rotl, &[I128, I32], &[I128], insert_opcode), 432 (Opcode::Rotl, &[I128, I64], &[I128], insert_opcode), 433 (Opcode::Rotl, &[I128, I128], &[I128], insert_opcode), 434 // Ishl 435 (Opcode::Ishl, &[I8, I8], &[I8], insert_opcode), 436 (Opcode::Ishl, &[I8, I16], &[I8], insert_opcode), 437 (Opcode::Ishl, &[I8, I32], &[I8], insert_opcode), 438 (Opcode::Ishl, &[I8, I64], &[I8], insert_opcode), 439 (Opcode::Ishl, &[I8, I128], &[I8], insert_opcode), 440 (Opcode::Ishl, &[I16, I8], &[I16], insert_opcode), 441 (Opcode::Ishl, &[I16, I16], &[I16], insert_opcode), 442 (Opcode::Ishl, &[I16, I32], &[I16], insert_opcode), 443 (Opcode::Ishl, &[I16, I64], &[I16], insert_opcode), 444 (Opcode::Ishl, &[I16, I128], &[I16], insert_opcode), 445 (Opcode::Ishl, &[I32, I8], &[I32], insert_opcode), 446 (Opcode::Ishl, &[I32, I16], &[I32], insert_opcode), 447 (Opcode::Ishl, &[I32, I32], &[I32], insert_opcode), 448 (Opcode::Ishl, &[I32, I64], &[I32], insert_opcode), 449 (Opcode::Ishl, &[I32, I128], &[I32], insert_opcode), 450 (Opcode::Ishl, &[I64, I8], &[I64], insert_opcode), 451 (Opcode::Ishl, &[I64, I16], &[I64], insert_opcode), 452 (Opcode::Ishl, &[I64, I32], &[I64], insert_opcode), 453 (Opcode::Ishl, &[I64, I64], &[I64], insert_opcode), 454 (Opcode::Ishl, &[I64, I128], &[I64], insert_opcode), 455 (Opcode::Ishl, &[I128, I8], &[I128], insert_opcode), 456 (Opcode::Ishl, &[I128, I16], &[I128], insert_opcode), 457 (Opcode::Ishl, &[I128, I32], &[I128], insert_opcode), 458 (Opcode::Ishl, &[I128, I64], &[I128], insert_opcode), 459 (Opcode::Ishl, &[I128, I128], &[I128], insert_opcode), 460 // Sshr 461 (Opcode::Sshr, &[I8, I8], &[I8], insert_opcode), 462 (Opcode::Sshr, &[I8, I16], &[I8], insert_opcode), 463 (Opcode::Sshr, &[I8, I32], &[I8], insert_opcode), 464 (Opcode::Sshr, &[I8, I64], &[I8], insert_opcode), 465 (Opcode::Sshr, &[I8, I128], &[I8], insert_opcode), 466 (Opcode::Sshr, &[I16, I8], &[I16], insert_opcode), 467 (Opcode::Sshr, &[I16, I16], &[I16], insert_opcode), 468 (Opcode::Sshr, &[I16, I32], &[I16], insert_opcode), 469 (Opcode::Sshr, &[I16, I64], &[I16], insert_opcode), 470 (Opcode::Sshr, &[I16, I128], &[I16], insert_opcode), 471 (Opcode::Sshr, &[I32, I8], &[I32], insert_opcode), 472 (Opcode::Sshr, &[I32, I16], &[I32], insert_opcode), 473 (Opcode::Sshr, &[I32, I32], &[I32], insert_opcode), 474 (Opcode::Sshr, &[I32, I64], &[I32], insert_opcode), 475 (Opcode::Sshr, &[I32, I128], &[I32], insert_opcode), 476 (Opcode::Sshr, &[I64, I8], &[I64], insert_opcode), 477 (Opcode::Sshr, &[I64, I16], &[I64], insert_opcode), 478 (Opcode::Sshr, &[I64, I32], &[I64], insert_opcode), 479 (Opcode::Sshr, &[I64, I64], &[I64], insert_opcode), 480 (Opcode::Sshr, &[I64, I128], &[I64], insert_opcode), 481 (Opcode::Sshr, &[I128, I8], &[I128], insert_opcode), 482 (Opcode::Sshr, &[I128, I16], &[I128], insert_opcode), 483 (Opcode::Sshr, &[I128, I32], &[I128], insert_opcode), 484 (Opcode::Sshr, &[I128, I64], &[I128], insert_opcode), 485 (Opcode::Sshr, &[I128, I128], &[I128], insert_opcode), 486 // Ushr 487 (Opcode::Ushr, &[I8, I8], &[I8], insert_opcode), 488 (Opcode::Ushr, &[I8, I16], &[I8], insert_opcode), 489 (Opcode::Ushr, &[I8, I32], &[I8], insert_opcode), 490 (Opcode::Ushr, &[I8, I64], &[I8], insert_opcode), 491 (Opcode::Ushr, &[I8, I128], &[I8], insert_opcode), 492 (Opcode::Ushr, &[I16, I8], &[I16], insert_opcode), 493 (Opcode::Ushr, &[I16, I16], &[I16], insert_opcode), 494 (Opcode::Ushr, &[I16, I32], &[I16], insert_opcode), 495 (Opcode::Ushr, &[I16, I64], &[I16], insert_opcode), 496 (Opcode::Ushr, &[I16, I128], &[I16], insert_opcode), 497 (Opcode::Ushr, &[I32, I8], &[I32], insert_opcode), 498 (Opcode::Ushr, &[I32, I16], &[I32], insert_opcode), 499 (Opcode::Ushr, &[I32, I32], &[I32], insert_opcode), 500 (Opcode::Ushr, &[I32, I64], &[I32], insert_opcode), 501 (Opcode::Ushr, &[I32, I128], &[I32], insert_opcode), 502 (Opcode::Ushr, &[I64, I8], &[I64], insert_opcode), 503 (Opcode::Ushr, &[I64, I16], &[I64], insert_opcode), 504 (Opcode::Ushr, &[I64, I32], &[I64], insert_opcode), 505 (Opcode::Ushr, &[I64, I64], &[I64], insert_opcode), 506 (Opcode::Ushr, &[I64, I128], &[I64], insert_opcode), 507 (Opcode::Ushr, &[I128, I8], &[I128], insert_opcode), 508 (Opcode::Ushr, &[I128, I16], &[I128], insert_opcode), 509 (Opcode::Ushr, &[I128, I32], &[I128], insert_opcode), 510 (Opcode::Ushr, &[I128, I64], &[I128], insert_opcode), 511 (Opcode::Ushr, &[I128, I128], &[I128], insert_opcode), 512 // Uextend 513 (Opcode::Uextend, &[I8], &[I16], insert_opcode), 514 (Opcode::Uextend, &[I8], &[I32], insert_opcode), 515 (Opcode::Uextend, &[I8], &[I64], insert_opcode), 516 (Opcode::Uextend, &[I8], &[I128], insert_opcode), 517 (Opcode::Uextend, &[I16], &[I32], insert_opcode), 518 (Opcode::Uextend, &[I16], &[I64], insert_opcode), 519 (Opcode::Uextend, &[I16], &[I128], insert_opcode), 520 (Opcode::Uextend, &[I32], &[I64], insert_opcode), 521 (Opcode::Uextend, &[I32], &[I128], insert_opcode), 522 (Opcode::Uextend, &[I64], &[I128], insert_opcode), 523 // Sextend 524 (Opcode::Sextend, &[I8], &[I16], insert_opcode), 525 (Opcode::Sextend, &[I8], &[I32], insert_opcode), 526 (Opcode::Sextend, &[I8], &[I64], insert_opcode), 527 (Opcode::Sextend, &[I8], &[I128], insert_opcode), 528 (Opcode::Sextend, &[I16], &[I32], insert_opcode), 529 (Opcode::Sextend, &[I16], &[I64], insert_opcode), 530 (Opcode::Sextend, &[I16], &[I128], insert_opcode), 531 (Opcode::Sextend, &[I32], &[I64], insert_opcode), 532 (Opcode::Sextend, &[I32], &[I128], insert_opcode), 533 (Opcode::Sextend, &[I64], &[I128], insert_opcode), 534 // Ireduce 535 (Opcode::Ireduce, &[I16], &[I8], insert_opcode), 536 (Opcode::Ireduce, &[I32], &[I8], insert_opcode), 537 (Opcode::Ireduce, &[I32], &[I16], insert_opcode), 538 (Opcode::Ireduce, &[I64], &[I8], insert_opcode), 539 (Opcode::Ireduce, &[I64], &[I16], insert_opcode), 540 (Opcode::Ireduce, &[I64], &[I32], insert_opcode), 541 (Opcode::Ireduce, &[I128], &[I8], insert_opcode), 542 (Opcode::Ireduce, &[I128], &[I16], insert_opcode), 543 (Opcode::Ireduce, &[I128], &[I32], insert_opcode), 544 (Opcode::Ireduce, &[I128], &[I64], insert_opcode), 545 // Isplit 546 (Opcode::Isplit, &[I128], &[I64, I64], insert_opcode), 547 // Iconcat 548 (Opcode::Iconcat, &[I64, I64], &[I128], insert_opcode), 549 // Band 550 (Opcode::Band, &[I8, I8], &[I8], insert_opcode), 551 (Opcode::Band, &[I16, I16], &[I16], insert_opcode), 552 (Opcode::Band, &[I32, I32], &[I32], insert_opcode), 553 (Opcode::Band, &[I64, I64], &[I64], insert_opcode), 554 (Opcode::Band, &[I128, I128], &[I128], insert_opcode), 555 // Float bitops are currently not supported: 556 // See: https://github.com/bytecodealliance/wasmtime/issues/4870 557 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 558 (Opcode::Band, &[F32, F32], &[F32], insert_opcode), 559 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 560 (Opcode::Band, &[F64, F64], &[F64], insert_opcode), 561 // Bor 562 (Opcode::Bor, &[I8, I8], &[I8], insert_opcode), 563 (Opcode::Bor, &[I16, I16], &[I16], insert_opcode), 564 (Opcode::Bor, &[I32, I32], &[I32], insert_opcode), 565 (Opcode::Bor, &[I64, I64], &[I64], insert_opcode), 566 (Opcode::Bor, &[I128, I128], &[I128], insert_opcode), 567 // Float bitops are currently not supported: 568 // See: https://github.com/bytecodealliance/wasmtime/issues/4870 569 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 570 (Opcode::Bor, &[F32, F32], &[F32], insert_opcode), 571 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 572 (Opcode::Bor, &[F64, F64], &[F64], insert_opcode), 573 // Bxor 574 (Opcode::Bxor, &[I8, I8], &[I8], insert_opcode), 575 (Opcode::Bxor, &[I16, I16], &[I16], insert_opcode), 576 (Opcode::Bxor, &[I32, I32], &[I32], insert_opcode), 577 (Opcode::Bxor, &[I64, I64], &[I64], insert_opcode), 578 (Opcode::Bxor, &[I128, I128], &[I128], insert_opcode), 579 // Float bitops are currently not supported: 580 // See: https://github.com/bytecodealliance/wasmtime/issues/4870 581 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 582 (Opcode::Bxor, &[F32, F32], &[F32], insert_opcode), 583 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 584 (Opcode::Bxor, &[F64, F64], &[F64], insert_opcode), 585 // Bnot 586 (Opcode::Bnot, &[I8, I8], &[I8], insert_opcode), 587 (Opcode::Bnot, &[I16, I16], &[I16], insert_opcode), 588 (Opcode::Bnot, &[I32, I32], &[I32], insert_opcode), 589 (Opcode::Bnot, &[I64, I64], &[I64], insert_opcode), 590 (Opcode::Bnot, &[I128, I128], &[I128], insert_opcode), 591 // Float bitops are currently not supported: 592 // See: https://github.com/bytecodealliance/wasmtime/issues/4870 593 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 594 (Opcode::Bnot, &[F32, F32], &[F32], insert_opcode), 595 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 596 (Opcode::Bnot, &[F64, F64], &[F64], insert_opcode), 597 // BandNot 598 // Some Integer ops not supported on x86: https://github.com/bytecodealliance/wasmtime/issues/5041 599 #[cfg(not(target_arch = "x86_64"))] 600 (Opcode::BandNot, &[I8, I8], &[I8], insert_opcode), 601 #[cfg(not(target_arch = "x86_64"))] 602 (Opcode::BandNot, &[I16, I16], &[I16], insert_opcode), 603 #[cfg(not(target_arch = "x86_64"))] 604 (Opcode::BandNot, &[I32, I32], &[I32], insert_opcode), 605 #[cfg(not(target_arch = "x86_64"))] 606 (Opcode::BandNot, &[I64, I64], &[I64], insert_opcode), 607 #[cfg(not(target_arch = "x86_64"))] 608 (Opcode::BandNot, &[I128, I128], &[I128], insert_opcode), 609 // Float bitops are currently not supported: 610 // See: https://github.com/bytecodealliance/wasmtime/issues/4870 611 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 612 (Opcode::BandNot, &[F32, F32], &[F32], insert_opcode), 613 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 614 (Opcode::BandNot, &[F64, F64], &[F64], insert_opcode), 615 // BorNot 616 // Some Integer ops not supported on x86: https://github.com/bytecodealliance/wasmtime/issues/5041 617 #[cfg(not(target_arch = "x86_64"))] 618 (Opcode::BorNot, &[I8, I8], &[I8], insert_opcode), 619 #[cfg(not(target_arch = "x86_64"))] 620 (Opcode::BorNot, &[I16, I16], &[I16], insert_opcode), 621 #[cfg(not(target_arch = "x86_64"))] 622 (Opcode::BorNot, &[I32, I32], &[I32], insert_opcode), 623 #[cfg(not(target_arch = "x86_64"))] 624 (Opcode::BorNot, &[I64, I64], &[I64], insert_opcode), 625 #[cfg(not(target_arch = "x86_64"))] 626 (Opcode::BorNot, &[I128, I128], &[I128], insert_opcode), 627 // Float bitops are currently not supported: 628 // See: https://github.com/bytecodealliance/wasmtime/issues/4870 629 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 630 (Opcode::BorNot, &[F32, F32], &[F32], insert_opcode), 631 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 632 (Opcode::BorNot, &[F64, F64], &[F64], insert_opcode), 633 // BxorNot 634 // Some Integer ops not supported on x86: https://github.com/bytecodealliance/wasmtime/issues/5041 635 #[cfg(not(target_arch = "x86_64"))] 636 (Opcode::BxorNot, &[I8, I8], &[I8], insert_opcode), 637 #[cfg(not(target_arch = "x86_64"))] 638 (Opcode::BxorNot, &[I16, I16], &[I16], insert_opcode), 639 #[cfg(not(target_arch = "x86_64"))] 640 (Opcode::BxorNot, &[I32, I32], &[I32], insert_opcode), 641 #[cfg(not(target_arch = "x86_64"))] 642 (Opcode::BxorNot, &[I64, I64], &[I64], insert_opcode), 643 #[cfg(not(target_arch = "x86_64"))] 644 (Opcode::BxorNot, &[I128, I128], &[I128], insert_opcode), 645 // Float bitops are currently not supported: 646 // See: https://github.com/bytecodealliance/wasmtime/issues/4870 647 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 648 (Opcode::BxorNot, &[F32, F32], &[F32], insert_opcode), 649 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 650 (Opcode::BxorNot, &[F64, F64], &[F64], insert_opcode), 651 // Bitrev 652 (Opcode::Bitrev, &[I8], &[I8], insert_opcode), 653 (Opcode::Bitrev, &[I16], &[I16], insert_opcode), 654 (Opcode::Bitrev, &[I32], &[I32], insert_opcode), 655 (Opcode::Bitrev, &[I64], &[I64], insert_opcode), 656 (Opcode::Bitrev, &[I128], &[I128], insert_opcode), 657 // Clz 658 (Opcode::Clz, &[I8], &[I8], insert_opcode), 659 (Opcode::Clz, &[I16], &[I16], insert_opcode), 660 (Opcode::Clz, &[I32], &[I32], insert_opcode), 661 (Opcode::Clz, &[I64], &[I64], insert_opcode), 662 (Opcode::Clz, &[I128], &[I128], insert_opcode), 663 // Cls 664 // cls not implemented in some backends: 665 // x64: https://github.com/bytecodealliance/wasmtime/issues/5107 666 #[cfg(not(target_arch = "x86_64"))] 667 (Opcode::Cls, &[I8], &[I8], insert_opcode), 668 #[cfg(not(target_arch = "x86_64"))] 669 (Opcode::Cls, &[I16], &[I16], insert_opcode), 670 #[cfg(not(target_arch = "x86_64"))] 671 (Opcode::Cls, &[I32], &[I32], insert_opcode), 672 #[cfg(not(target_arch = "x86_64"))] 673 (Opcode::Cls, &[I64], &[I64], insert_opcode), 674 #[cfg(not(target_arch = "x86_64"))] 675 (Opcode::Cls, &[I128], &[I128], insert_opcode), 676 // Ctz 677 (Opcode::Ctz, &[I8], &[I8], insert_opcode), 678 (Opcode::Ctz, &[I16], &[I16], insert_opcode), 679 (Opcode::Ctz, &[I32], &[I32], insert_opcode), 680 (Opcode::Ctz, &[I64], &[I64], insert_opcode), 681 (Opcode::Ctz, &[I128], &[I128], insert_opcode), 682 // Popcnt 683 (Opcode::Popcnt, &[I8], &[I8], insert_opcode), 684 (Opcode::Popcnt, &[I16], &[I16], insert_opcode), 685 (Opcode::Popcnt, &[I32], &[I32], insert_opcode), 686 (Opcode::Popcnt, &[I64], &[I64], insert_opcode), 687 (Opcode::Popcnt, &[I128], &[I128], insert_opcode), 688 // Bmask 689 (Opcode::Bmask, &[I8], &[I8], insert_opcode), 690 (Opcode::Bmask, &[I16], &[I8], insert_opcode), 691 (Opcode::Bmask, &[I32], &[I8], insert_opcode), 692 (Opcode::Bmask, &[I64], &[I8], insert_opcode), 693 (Opcode::Bmask, &[I128], &[I8], insert_opcode), 694 (Opcode::Bmask, &[I8], &[I16], insert_opcode), 695 (Opcode::Bmask, &[I16], &[I16], insert_opcode), 696 (Opcode::Bmask, &[I32], &[I16], insert_opcode), 697 (Opcode::Bmask, &[I64], &[I16], insert_opcode), 698 (Opcode::Bmask, &[I128], &[I16], insert_opcode), 699 (Opcode::Bmask, &[I8], &[I32], insert_opcode), 700 (Opcode::Bmask, &[I16], &[I32], insert_opcode), 701 (Opcode::Bmask, &[I32], &[I32], insert_opcode), 702 (Opcode::Bmask, &[I64], &[I32], insert_opcode), 703 (Opcode::Bmask, &[I128], &[I32], insert_opcode), 704 (Opcode::Bmask, &[I8], &[I64], insert_opcode), 705 (Opcode::Bmask, &[I16], &[I64], insert_opcode), 706 (Opcode::Bmask, &[I32], &[I64], insert_opcode), 707 (Opcode::Bmask, &[I64], &[I64], insert_opcode), 708 (Opcode::Bmask, &[I128], &[I64], insert_opcode), 709 (Opcode::Bmask, &[I8], &[I128], insert_opcode), 710 (Opcode::Bmask, &[I16], &[I128], insert_opcode), 711 (Opcode::Bmask, &[I32], &[I128], insert_opcode), 712 (Opcode::Bmask, &[I64], &[I128], insert_opcode), 713 (Opcode::Bmask, &[I128], &[I128], insert_opcode), 714 // Bswap 715 (Opcode::Bswap, &[I16], &[I16], insert_opcode), 716 (Opcode::Bswap, &[I32], &[I32], insert_opcode), 717 (Opcode::Bswap, &[I64], &[I64], insert_opcode), 718 (Opcode::Bswap, &[I128], &[I128], insert_opcode), 719 // Bitselect 720 // TODO: Some ops disabled: 721 // x64: https://github.com/bytecodealliance/wasmtime/issues/5197 722 // AArch64: https://github.com/bytecodealliance/wasmtime/issues/5198 723 #[cfg(not(target_arch = "x86_64"))] 724 (Opcode::Bitselect, &[I8, I8, I8], &[I8], insert_opcode), 725 #[cfg(not(target_arch = "x86_64"))] 726 (Opcode::Bitselect, &[I16, I16, I16], &[I16], insert_opcode), 727 #[cfg(not(target_arch = "x86_64"))] 728 (Opcode::Bitselect, &[I32, I32, I32], &[I32], insert_opcode), 729 #[cfg(not(target_arch = "x86_64"))] 730 (Opcode::Bitselect, &[I64, I64, I64], &[I64], insert_opcode), 731 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 732 (Opcode::Bitselect, &[I128, I128, I128], &[I128], insert_opcode), 733 // Select 734 // TODO: Some ops disabled: 735 // x64: https://github.com/bytecodealliance/wasmtime/issues/5199 736 // AArch64: https://github.com/bytecodealliance/wasmtime/issues/5200 737 (Opcode::Select, &[I8, I8, I8], &[I8], insert_opcode), 738 (Opcode::Select, &[I8, I16, I16], &[I16], insert_opcode), 739 (Opcode::Select, &[I8, I32, I32], &[I32], insert_opcode), 740 (Opcode::Select, &[I8, I64, I64], &[I64], insert_opcode), 741 (Opcode::Select, &[I8, I128, I128], &[I128], insert_opcode), 742 (Opcode::Select, &[I16, I8, I8], &[I8], insert_opcode), 743 (Opcode::Select, &[I16, I16, I16], &[I16], insert_opcode), 744 (Opcode::Select, &[I16, I32, I32], &[I32], insert_opcode), 745 (Opcode::Select, &[I16, I64, I64], &[I64], insert_opcode), 746 (Opcode::Select, &[I16, I128, I128], &[I128], insert_opcode), 747 (Opcode::Select, &[I32, I8, I8], &[I8], insert_opcode), 748 (Opcode::Select, &[I32, I16, I16], &[I16], insert_opcode), 749 (Opcode::Select, &[I32, I32, I32], &[I32], insert_opcode), 750 (Opcode::Select, &[I32, I64, I64], &[I64], insert_opcode), 751 (Opcode::Select, &[I32, I128, I128], &[I128], insert_opcode), 752 (Opcode::Select, &[I64, I8, I8], &[I8], insert_opcode), 753 (Opcode::Select, &[I64, I16, I16], &[I16], insert_opcode), 754 (Opcode::Select, &[I64, I32, I32], &[I32], insert_opcode), 755 (Opcode::Select, &[I64, I64, I64], &[I64], insert_opcode), 756 (Opcode::Select, &[I64, I128, I128], &[I128], insert_opcode), 757 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 758 (Opcode::Select, &[I128, I8, I8], &[I8], insert_opcode), 759 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 760 (Opcode::Select, &[I128, I16, I16], &[I16], insert_opcode), 761 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 762 (Opcode::Select, &[I128, I32, I32], &[I32], insert_opcode), 763 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 764 (Opcode::Select, &[I128, I64, I64], &[I64], insert_opcode), 765 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 766 (Opcode::Select, &[I128, I128, I128], &[I128], insert_opcode), 767 // SelectSpectreGuard 768 // select_spectre_guard is only implemented on x86_64 and aarch64 769 // when a icmp is preceding it. 770 (Opcode::SelectSpectreGuard, &[I8, I8, I8], &[I8], insert_select_spectre_guard), 771 (Opcode::SelectSpectreGuard, &[I8, I16, I16], &[I16], insert_select_spectre_guard), 772 (Opcode::SelectSpectreGuard, &[I8, I32, I32], &[I32], insert_select_spectre_guard), 773 (Opcode::SelectSpectreGuard, &[I8, I64, I64], &[I64], insert_select_spectre_guard), 774 (Opcode::SelectSpectreGuard, &[I8, I128, I128], &[I128], insert_select_spectre_guard), 775 (Opcode::SelectSpectreGuard, &[I16, I8, I8], &[I8], insert_select_spectre_guard), 776 (Opcode::SelectSpectreGuard, &[I16, I16, I16], &[I16], insert_select_spectre_guard), 777 (Opcode::SelectSpectreGuard, &[I16, I32, I32], &[I32], insert_select_spectre_guard), 778 (Opcode::SelectSpectreGuard, &[I16, I64, I64], &[I64], insert_select_spectre_guard), 779 (Opcode::SelectSpectreGuard, &[I16, I128, I128], &[I128], insert_select_spectre_guard), 780 (Opcode::SelectSpectreGuard, &[I32, I8, I8], &[I8], insert_select_spectre_guard), 781 (Opcode::SelectSpectreGuard, &[I32, I16, I16], &[I16], insert_select_spectre_guard), 782 (Opcode::SelectSpectreGuard, &[I32, I32, I32], &[I32], insert_select_spectre_guard), 783 (Opcode::SelectSpectreGuard, &[I32, I64, I64], &[I64], insert_select_spectre_guard), 784 (Opcode::SelectSpectreGuard, &[I32, I128, I128], &[I128], insert_select_spectre_guard), 785 (Opcode::SelectSpectreGuard, &[I64, I8, I8], &[I8], insert_select_spectre_guard), 786 (Opcode::SelectSpectreGuard, &[I64, I16, I16], &[I16], insert_select_spectre_guard), 787 (Opcode::SelectSpectreGuard, &[I64, I32, I32], &[I32], insert_select_spectre_guard), 788 (Opcode::SelectSpectreGuard, &[I64, I64, I64], &[I64], insert_select_spectre_guard), 789 (Opcode::SelectSpectreGuard, &[I64, I128, I128], &[I128], insert_select_spectre_guard), 790 (Opcode::SelectSpectreGuard, &[I128, I8, I8], &[I8], insert_select_spectre_guard), 791 (Opcode::SelectSpectreGuard, &[I128, I16, I16], &[I16], insert_select_spectre_guard), 792 (Opcode::SelectSpectreGuard, &[I128, I32, I32], &[I32], insert_select_spectre_guard), 793 (Opcode::SelectSpectreGuard, &[I128, I64, I64], &[I64], insert_select_spectre_guard), 794 (Opcode::SelectSpectreGuard, &[I128, I128, I128], &[I128], insert_select_spectre_guard), 795 // Fadd 796 (Opcode::Fadd, &[F32, F32], &[F32], insert_opcode), 797 (Opcode::Fadd, &[F64, F64], &[F64], insert_opcode), 798 // Fmul 799 (Opcode::Fmul, &[F32, F32], &[F32], insert_opcode), 800 (Opcode::Fmul, &[F64, F64], &[F64], insert_opcode), 801 // Fsub 802 (Opcode::Fsub, &[F32, F32], &[F32], insert_opcode), 803 (Opcode::Fsub, &[F64, F64], &[F64], insert_opcode), 804 // Fdiv 805 (Opcode::Fdiv, &[F32, F32], &[F32], insert_opcode), 806 (Opcode::Fdiv, &[F64, F64], &[F64], insert_opcode), 807 // Fmin 808 (Opcode::Fmin, &[F32, F32], &[F32], insert_opcode), 809 (Opcode::Fmin, &[F64, F64], &[F64], insert_opcode), 810 // Fmax 811 (Opcode::Fmax, &[F32, F32], &[F32], insert_opcode), 812 (Opcode::Fmax, &[F64, F64], &[F64], insert_opcode), 813 // FminPseudo 814 (Opcode::FminPseudo, &[F32, F32], &[F32], insert_opcode), 815 (Opcode::FminPseudo, &[F64, F64], &[F64], insert_opcode), 816 // FmaxPseudo 817 (Opcode::FmaxPseudo, &[F32, F32], &[F32], insert_opcode), 818 (Opcode::FmaxPseudo, &[F64, F64], &[F64], insert_opcode), 819 // Fcopysign 820 (Opcode::Fcopysign, &[F32, F32], &[F32], insert_opcode), 821 (Opcode::Fcopysign, &[F64, F64], &[F64], insert_opcode), 822 // Fma 823 (Opcode::Fma, &[F32, F32, F32], &[F32], insert_opcode), 824 (Opcode::Fma, &[F64, F64, F64], &[F64], insert_opcode), 825 // Fabs 826 (Opcode::Fabs, &[F32], &[F32], insert_opcode), 827 (Opcode::Fabs, &[F64], &[F64], insert_opcode), 828 // Fneg 829 (Opcode::Fneg, &[F32], &[F32], insert_opcode), 830 (Opcode::Fneg, &[F64], &[F64], insert_opcode), 831 // Sqrt 832 (Opcode::Sqrt, &[F32], &[F32], insert_opcode), 833 (Opcode::Sqrt, &[F64], &[F64], insert_opcode), 834 // Ceil 835 (Opcode::Ceil, &[F32], &[F32], insert_opcode), 836 (Opcode::Ceil, &[F64], &[F64], insert_opcode), 837 // Floor 838 (Opcode::Floor, &[F32], &[F32], insert_opcode), 839 (Opcode::Floor, &[F64], &[F64], insert_opcode), 840 // Trunc 841 (Opcode::Trunc, &[F32], &[F32], insert_opcode), 842 (Opcode::Trunc, &[F64], &[F64], insert_opcode), 843 // Nearest 844 (Opcode::Nearest, &[F32], &[F32], insert_opcode), 845 (Opcode::Nearest, &[F64], &[F64], insert_opcode), 846 // Fpromote 847 (Opcode::Fpromote, &[F32], &[F64], insert_opcode), 848 // Fdemote 849 (Opcode::Fdemote, &[F64], &[F32], insert_opcode), 850 // FcvtToUint 851 // TODO: Some ops disabled: 852 // x64: https://github.com/bytecodealliance/wasmtime/issues/4897 853 // x64: https://github.com/bytecodealliance/wasmtime/issues/4899 854 // aarch64: https://github.com/bytecodealliance/wasmtime/issues/4934 855 #[cfg(not(target_arch = "x86_64"))] 856 (Opcode::FcvtToUint, &[F32], &[I8], insert_opcode), 857 #[cfg(not(target_arch = "x86_64"))] 858 (Opcode::FcvtToUint, &[F32], &[I16], insert_opcode), 859 (Opcode::FcvtToUint, &[F32], &[I32], insert_opcode), 860 (Opcode::FcvtToUint, &[F32], &[I64], insert_opcode), 861 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 862 (Opcode::FcvtToUint, &[F32], &[I128], insert_opcode), 863 #[cfg(not(target_arch = "x86_64"))] 864 (Opcode::FcvtToUint, &[F64], &[I8], insert_opcode), 865 #[cfg(not(target_arch = "x86_64"))] 866 (Opcode::FcvtToUint, &[F64], &[I16], insert_opcode), 867 (Opcode::FcvtToUint, &[F64], &[I32], insert_opcode), 868 (Opcode::FcvtToUint, &[F64], &[I64], insert_opcode), 869 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 870 (Opcode::FcvtToUint, &[F64], &[I128], insert_opcode), 871 // FcvtToUintSat 872 // TODO: Some ops disabled: 873 // x64: https://github.com/bytecodealliance/wasmtime/issues/4897 874 // x64: https://github.com/bytecodealliance/wasmtime/issues/4899 875 // aarch64: https://github.com/bytecodealliance/wasmtime/issues/4934 876 #[cfg(not(target_arch = "x86_64"))] 877 (Opcode::FcvtToUintSat, &[F32], &[I8], insert_opcode), 878 #[cfg(not(target_arch = "x86_64"))] 879 (Opcode::FcvtToUintSat, &[F32], &[I16], insert_opcode), 880 (Opcode::FcvtToUintSat, &[F32], &[I32], insert_opcode), 881 (Opcode::FcvtToUintSat, &[F32], &[I64], insert_opcode), 882 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 883 (Opcode::FcvtToUintSat, &[F32], &[I128], insert_opcode), 884 #[cfg(not(target_arch = "x86_64"))] 885 (Opcode::FcvtToUintSat, &[F64], &[I8], insert_opcode), 886 #[cfg(not(target_arch = "x86_64"))] 887 (Opcode::FcvtToUintSat, &[F64], &[I16], insert_opcode), 888 (Opcode::FcvtToUintSat, &[F64], &[I32], insert_opcode), 889 (Opcode::FcvtToUintSat, &[F64], &[I64], insert_opcode), 890 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 891 (Opcode::FcvtToUintSat, &[F64], &[I128], insert_opcode), 892 // FcvtToSint 893 // TODO: Some ops disabled: 894 // x64: https://github.com/bytecodealliance/wasmtime/issues/4897 895 // x64: https://github.com/bytecodealliance/wasmtime/issues/4899 896 // aarch64: https://github.com/bytecodealliance/wasmtime/issues/4934 897 #[cfg(not(target_arch = "x86_64"))] 898 (Opcode::FcvtToSint, &[F32], &[I8], insert_opcode), 899 #[cfg(not(target_arch = "x86_64"))] 900 (Opcode::FcvtToSint, &[F32], &[I16], insert_opcode), 901 (Opcode::FcvtToSint, &[F32], &[I32], insert_opcode), 902 (Opcode::FcvtToSint, &[F32], &[I64], insert_opcode), 903 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 904 (Opcode::FcvtToSint, &[F32], &[I128], insert_opcode), 905 #[cfg(not(target_arch = "x86_64"))] 906 (Opcode::FcvtToSint, &[F64], &[I8], insert_opcode), 907 #[cfg(not(target_arch = "x86_64"))] 908 (Opcode::FcvtToSint, &[F64], &[I16], insert_opcode), 909 (Opcode::FcvtToSint, &[F64], &[I32], insert_opcode), 910 (Opcode::FcvtToSint, &[F64], &[I64], insert_opcode), 911 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 912 (Opcode::FcvtToSint, &[F64], &[I128], insert_opcode), 913 // FcvtToSintSat 914 // TODO: Some ops disabled: 915 // x64: https://github.com/bytecodealliance/wasmtime/issues/4897 916 // x64: https://github.com/bytecodealliance/wasmtime/issues/4899 917 // aarch64: https://github.com/bytecodealliance/wasmtime/issues/4934 918 #[cfg(not(target_arch = "x86_64"))] 919 (Opcode::FcvtToSintSat, &[F32], &[I8], insert_opcode), 920 #[cfg(not(target_arch = "x86_64"))] 921 (Opcode::FcvtToSintSat, &[F32], &[I16], insert_opcode), 922 (Opcode::FcvtToSintSat, &[F32], &[I32], insert_opcode), 923 (Opcode::FcvtToSintSat, &[F32], &[I64], insert_opcode), 924 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 925 (Opcode::FcvtToSintSat, &[F32], &[I128], insert_opcode), 926 #[cfg(not(target_arch = "x86_64"))] 927 (Opcode::FcvtToSintSat, &[F64], &[I8], insert_opcode), 928 #[cfg(not(target_arch = "x86_64"))] 929 (Opcode::FcvtToSintSat, &[F64], &[I16], insert_opcode), 930 (Opcode::FcvtToSintSat, &[F64], &[I32], insert_opcode), 931 (Opcode::FcvtToSintSat, &[F64], &[I64], insert_opcode), 932 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 933 (Opcode::FcvtToSintSat, &[F64], &[I128], insert_opcode), 934 // FcvtFromUint 935 // TODO: Some ops disabled: 936 // x64: https://github.com/bytecodealliance/wasmtime/issues/4900 937 // aarch64: https://github.com/bytecodealliance/wasmtime/issues/4933 938 (Opcode::FcvtFromUint, &[I8], &[F32], insert_opcode), 939 (Opcode::FcvtFromUint, &[I16], &[F32], insert_opcode), 940 (Opcode::FcvtFromUint, &[I32], &[F32], insert_opcode), 941 (Opcode::FcvtFromUint, &[I64], &[F32], insert_opcode), 942 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 943 (Opcode::FcvtFromUint, &[I128], &[F32], insert_opcode), 944 (Opcode::FcvtFromUint, &[I8], &[F64], insert_opcode), 945 (Opcode::FcvtFromUint, &[I16], &[F64], insert_opcode), 946 (Opcode::FcvtFromUint, &[I32], &[F64], insert_opcode), 947 (Opcode::FcvtFromUint, &[I64], &[F64], insert_opcode), 948 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 949 (Opcode::FcvtFromUint, &[I128], &[F64], insert_opcode), 950 // FcvtFromSint 951 // TODO: Some ops disabled: 952 // x64: https://github.com/bytecodealliance/wasmtime/issues/4900 953 // aarch64: https://github.com/bytecodealliance/wasmtime/issues/4933 954 (Opcode::FcvtFromSint, &[I8], &[F32], insert_opcode), 955 (Opcode::FcvtFromSint, &[I16], &[F32], insert_opcode), 956 (Opcode::FcvtFromSint, &[I32], &[F32], insert_opcode), 957 (Opcode::FcvtFromSint, &[I64], &[F32], insert_opcode), 958 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 959 (Opcode::FcvtFromSint, &[I128], &[F32], insert_opcode), 960 (Opcode::FcvtFromSint, &[I8], &[F64], insert_opcode), 961 (Opcode::FcvtFromSint, &[I16], &[F64], insert_opcode), 962 (Opcode::FcvtFromSint, &[I32], &[F64], insert_opcode), 963 (Opcode::FcvtFromSint, &[I64], &[F64], insert_opcode), 964 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] 965 (Opcode::FcvtFromSint, &[I128], &[F64], insert_opcode), 966 // Fcmp 967 (Opcode::Fcmp, &[F32, F32], &[I8], insert_cmp), 968 (Opcode::Fcmp, &[F64, F64], &[I8], insert_cmp), 969 // Icmp 970 (Opcode::Icmp, &[I8, I8], &[I8], insert_cmp), 971 (Opcode::Icmp, &[I16, I16], &[I8], insert_cmp), 972 (Opcode::Icmp, &[I32, I32], &[I8], insert_cmp), 973 (Opcode::Icmp, &[I64, I64], &[I8], insert_cmp), 974 (Opcode::Icmp, &[I128, I128], &[I8], insert_cmp), 975 // Stack Access 976 (Opcode::StackStore, &[I8], &[], insert_stack_store), 977 (Opcode::StackStore, &[I16], &[], insert_stack_store), 978 (Opcode::StackStore, &[I32], &[], insert_stack_store), 979 (Opcode::StackStore, &[I64], &[], insert_stack_store), 980 (Opcode::StackStore, &[I128], &[], insert_stack_store), 981 (Opcode::StackLoad, &[], &[I8], insert_stack_load), 982 (Opcode::StackLoad, &[], &[I16], insert_stack_load), 983 (Opcode::StackLoad, &[], &[I32], insert_stack_load), 984 (Opcode::StackLoad, &[], &[I64], insert_stack_load), 985 (Opcode::StackLoad, &[], &[I128], insert_stack_load), 986 // Loads 987 (Opcode::Load, &[], &[I8], insert_load_store), 988 (Opcode::Load, &[], &[I16], insert_load_store), 989 (Opcode::Load, &[], &[I32], insert_load_store), 990 (Opcode::Load, &[], &[I64], insert_load_store), 991 (Opcode::Load, &[], &[I128], insert_load_store), 992 (Opcode::Load, &[], &[F32], insert_load_store), 993 (Opcode::Load, &[], &[F64], insert_load_store), 994 // Special Loads 995 (Opcode::Uload8, &[], &[I16], insert_load_store), 996 (Opcode::Uload8, &[], &[I32], insert_load_store), 997 (Opcode::Uload8, &[], &[I64], insert_load_store), 998 (Opcode::Uload16, &[], &[I32], insert_load_store), 999 (Opcode::Uload16, &[], &[I64], insert_load_store), 1000 (Opcode::Uload32, &[], &[I64], insert_load_store), 1001 (Opcode::Sload8, &[], &[I16], insert_load_store), 1002 (Opcode::Sload8, &[], &[I32], insert_load_store), 1003 (Opcode::Sload8, &[], &[I64], insert_load_store), 1004 (Opcode::Sload16, &[], &[I32], insert_load_store), 1005 (Opcode::Sload16, &[], &[I64], insert_load_store), 1006 (Opcode::Sload32, &[], &[I64], insert_load_store), 1007 // TODO: Unimplemented in the interpreter 1008 // Opcode::Uload8x8 1009 // Opcode::Sload8x8 1010 // Opcode::Uload16x4 1011 // Opcode::Sload16x4 1012 // Opcode::Uload32x2 1013 // Opcode::Sload32x2 1014 // Stores 1015 (Opcode::Store, &[I8], &[], insert_load_store), 1016 (Opcode::Store, &[I16], &[], insert_load_store), 1017 (Opcode::Store, &[I32], &[], insert_load_store), 1018 (Opcode::Store, &[I64], &[], insert_load_store), 1019 (Opcode::Store, &[I128], &[], insert_load_store), 1020 (Opcode::Store, &[F32], &[], insert_load_store), 1021 (Opcode::Store, &[F64], &[], insert_load_store), 1022 // Special Stores 1023 (Opcode::Istore8, &[I16], &[], insert_load_store), 1024 (Opcode::Istore8, &[I32], &[], insert_load_store), 1025 (Opcode::Istore8, &[I64], &[], insert_load_store), 1026 (Opcode::Istore16, &[I32], &[], insert_load_store), 1027 (Opcode::Istore16, &[I64], &[], insert_load_store), 1028 (Opcode::Istore32, &[I64], &[], insert_load_store), 1029 // Integer Consts 1030 (Opcode::Iconst, &[], &[I8], insert_const), 1031 (Opcode::Iconst, &[], &[I16], insert_const), 1032 (Opcode::Iconst, &[], &[I32], insert_const), 1033 (Opcode::Iconst, &[], &[I64], insert_const), 1034 // Float Consts 1035 (Opcode::F32const, &[], &[F32], insert_const), 1036 (Opcode::F64const, &[], &[F64], insert_const), 1037 // Call 1038 (Opcode::Call, &[], &[], insert_call), 1039 ]; 1040 1041 /// These libcalls need a interpreter implementation in `cranelift-fuzzgen.rs` 1042 const ALLOWED_LIBCALLS: &'static [LibCall] = &[ 1043 LibCall::CeilF32, 1044 LibCall::CeilF64, 1045 LibCall::FloorF32, 1046 LibCall::FloorF64, 1047 LibCall::TruncF32, 1048 LibCall::TruncF64, 1049 ]; 1050 1051 pub struct FunctionGenerator<'r, 'data> 1052 where 1053 'data: 'r, 1054 { 1055 u: &'r mut Unstructured<'data>, 1056 config: &'r Config, 1057 resources: Resources, 1058 } 1059 1060 #[derive(Debug, Clone)] 1061 enum BlockTerminator { 1062 Return, 1063 Jump(Block), 1064 Br(Block, Block), 1065 BrTable(Block, Vec<Block>), 1066 Switch(Type, Block, HashMap<u128, Block>), 1067 } 1068 1069 #[derive(Debug, Clone)] 1070 enum BlockTerminatorKind { 1071 Return, 1072 Jump, 1073 Br, 1074 BrTable, 1075 Switch, 1076 } 1077 1078 #[derive(Default)] 1079 struct Resources { 1080 vars: HashMap<Type, Vec<Variable>>, 1081 blocks: Vec<(Block, BlockSignature)>, 1082 blocks_without_params: Vec<Block>, 1083 block_terminators: Vec<BlockTerminator>, 1084 func_refs: Vec<(Signature, FuncRef)>, 1085 stack_slots: Vec<(StackSlot, StackSize)>, 1086 } 1087 1088 impl Resources { 1089 /// Partitions blocks at `block`. Only blocks that can be targeted by branches are considered. 1090 /// 1091 /// The first slice includes all blocks up to and including `block`. 1092 /// The second slice includes all remaining blocks. 1093 fn partition_target_blocks( 1094 &self, 1095 block: Block, 1096 ) -> (&[(Block, BlockSignature)], &[(Block, BlockSignature)]) { 1097 // Blocks are stored in-order and have no gaps, this means that we can simply index them by 1098 // their number. We also need to exclude the entry block since it isn't a valid target. 1099 let target_blocks = &self.blocks[1..]; 1100 target_blocks.split_at(block.as_u32() as usize) 1101 } 1102 1103 /// Returns blocks forward of `block`. Only blocks that can be targeted by branches are considered. 1104 fn forward_blocks(&self, block: Block) -> &[(Block, BlockSignature)] { 1105 let (_, forward_blocks) = self.partition_target_blocks(block); 1106 forward_blocks 1107 } 1108 1109 /// Generates a slice of `blocks_without_params` ahead of `block` 1110 fn forward_blocks_without_params(&self, block: Block) -> &[Block] { 1111 let partition_point = self.blocks_without_params.partition_point(|b| *b <= block); 1112 &self.blocks_without_params[partition_point..] 1113 } 1114 } 1115 1116 impl<'r, 'data> FunctionGenerator<'r, 'data> 1117 where 1118 'data: 'r, 1119 { 1120 pub fn new(u: &'r mut Unstructured<'data>, config: &'r Config) -> Self { 1121 Self { 1122 u, 1123 config, 1124 resources: Resources::default(), 1125 } 1126 } 1127 1128 /// Generates a random value for config `param` 1129 fn param(&mut self, param: &RangeInclusive<usize>) -> Result<usize> { 1130 Ok(self.u.int_in_range(param.clone())?) 1131 } 1132 1133 fn generate_callconv(&mut self) -> Result<CallConv> { 1134 // TODO: Generate random CallConvs per target 1135 Ok(CallConv::SystemV) 1136 } 1137 1138 fn system_callconv(&mut self) -> CallConv { 1139 // TODO: This currently only runs on linux, so this is the only choice 1140 // We should improve this once we generate flags and targets 1141 CallConv::SystemV 1142 } 1143 1144 fn generate_type(&mut self) -> Result<Type> { 1145 // TODO: It would be nice if we could get these directly from cranelift 1146 let scalars = [ 1147 // IFLAGS, FFLAGS, 1148 I8, I16, I32, I64, I128, F32, F64, 1149 // R32, R64, 1150 ]; 1151 // TODO: vector types 1152 1153 let ty = self.u.choose(&scalars[..])?; 1154 Ok(*ty) 1155 } 1156 1157 fn generate_abi_param(&mut self) -> Result<AbiParam> { 1158 let value_type = self.generate_type()?; 1159 // TODO: There are more argument purposes to be explored... 1160 let purpose = ArgumentPurpose::Normal; 1161 let extension = match self.u.int_in_range(0..=2)? { 1162 2 => ArgumentExtension::Sext, 1163 1 => ArgumentExtension::Uext, 1164 _ => ArgumentExtension::None, 1165 }; 1166 1167 Ok(AbiParam { 1168 value_type, 1169 purpose, 1170 extension, 1171 }) 1172 } 1173 1174 fn generate_signature(&mut self) -> Result<Signature> { 1175 let callconv = self.generate_callconv()?; 1176 let mut sig = Signature::new(callconv); 1177 1178 for _ in 0..self.param(&self.config.signature_params)? { 1179 sig.params.push(self.generate_abi_param()?); 1180 } 1181 1182 for _ in 0..self.param(&self.config.signature_rets)? { 1183 sig.returns.push(self.generate_abi_param()?); 1184 } 1185 1186 Ok(sig) 1187 } 1188 1189 /// Finds a stack slot with size of at least n bytes 1190 fn stack_slot_with_size(&mut self, n: u32) -> Result<(StackSlot, StackSize)> { 1191 let first = self 1192 .resources 1193 .stack_slots 1194 .partition_point(|&(_slot, size)| size < n); 1195 Ok(*self.u.choose(&self.resources.stack_slots[first..])?) 1196 } 1197 1198 /// Generates an address that should allow for a store or a load. 1199 /// 1200 /// Addresses aren't generated like other values. They are never stored in variables so that 1201 /// we don't run the risk of returning them from a function, which would make the fuzzer 1202 /// complain since they are different from the interpreter to the backend. 1203 /// 1204 /// The address is not guaranteed to be valid, but there's a chance that it is. 1205 /// 1206 /// `min_size`: Controls the amount of space that the address should have.This is not 1207 /// guaranteed to be respected 1208 fn generate_load_store_address( 1209 &mut self, 1210 builder: &mut FunctionBuilder, 1211 min_size: u32, 1212 ) -> Result<(Value, Offset32)> { 1213 // TODO: Currently our only source of addresses is stack_addr, but we should 1214 // add heap_addr, global_value, symbol_value eventually 1215 let (addr, available_size) = { 1216 let (ss, slot_size) = self.stack_slot_with_size(min_size)?; 1217 let max_offset = slot_size.saturating_sub(min_size); 1218 let offset = self.u.int_in_range(0..=max_offset)? as i32; 1219 let base_addr = builder.ins().stack_addr(I64, ss, offset); 1220 let available_size = (slot_size as i32).saturating_sub(offset); 1221 (base_addr, available_size) 1222 }; 1223 1224 // TODO: Insert a bunch of amode opcodes here to modify the address! 1225 1226 // Now that we have an address and a size, we just choose a random offset to return to the 1227 // caller. Try to preserve min_size bytes. 1228 let max_offset = available_size.saturating_sub(min_size as i32); 1229 let offset = self.u.int_in_range(0..=max_offset)? as i32; 1230 1231 Ok((addr, offset.into())) 1232 } 1233 1234 /// Get a variable of type `ty` from the current function 1235 fn get_variable_of_type(&mut self, ty: Type) -> Result<Variable> { 1236 let opts = self.resources.vars.get(&ty).map_or(&[][..], Vec::as_slice); 1237 let var = self.u.choose(opts)?; 1238 Ok(*var) 1239 } 1240 1241 /// Generates an instruction(`iconst`/`fconst`/etc...) to introduce a constant value 1242 fn generate_const(&mut self, builder: &mut FunctionBuilder, ty: Type) -> Result<Value> { 1243 Ok(match ty { 1244 I128 => { 1245 // See: https://github.com/bytecodealliance/wasmtime/issues/2906 1246 let hi = builder.ins().iconst(I64, self.u.arbitrary::<i64>()?); 1247 let lo = builder.ins().iconst(I64, self.u.arbitrary::<i64>()?); 1248 builder.ins().iconcat(lo, hi) 1249 } 1250 ty if ty.is_int() => { 1251 let imm64 = match ty { 1252 I8 => self.u.arbitrary::<i8>()? as i64, 1253 I16 => self.u.arbitrary::<i16>()? as i64, 1254 I32 => self.u.arbitrary::<i32>()? as i64, 1255 I64 => self.u.arbitrary::<i64>()?, 1256 _ => unreachable!(), 1257 }; 1258 builder.ins().iconst(ty, imm64) 1259 } 1260 // f{32,64}::arbitrary does not generate a bunch of important values 1261 // such as Signaling NaN's / NaN's with payload, so generate floats from integers. 1262 F32 => builder 1263 .ins() 1264 .f32const(f32::from_bits(u32::arbitrary(self.u)?)), 1265 F64 => builder 1266 .ins() 1267 .f64const(f64::from_bits(u64::arbitrary(self.u)?)), 1268 _ => unimplemented!(), 1269 }) 1270 } 1271 1272 /// Chooses a random block which can be targeted by a jump / branch. 1273 /// This means any block that is not the first block. 1274 fn generate_target_block(&mut self, source_block: Block) -> Result<Block> { 1275 // We try to mostly generate forward branches to avoid generating an excessive amount of 1276 // infinite loops. But they are still important, so give them a small chance of existing. 1277 let (backwards_blocks, forward_blocks) = 1278 self.resources.partition_target_blocks(source_block); 1279 let ratio = self.config.backwards_branch_ratio; 1280 let block_targets = if !backwards_blocks.is_empty() && self.u.ratio(ratio.0, ratio.1)? { 1281 backwards_blocks 1282 } else { 1283 forward_blocks 1284 }; 1285 assert!(!block_targets.is_empty()); 1286 1287 let (block, _) = self.u.choose(block_targets)?.clone(); 1288 Ok(block) 1289 } 1290 1291 fn generate_values_for_block( 1292 &mut self, 1293 builder: &mut FunctionBuilder, 1294 block: Block, 1295 ) -> Result<Vec<Value>> { 1296 let (_, sig) = self.resources.blocks[block.as_u32() as usize].clone(); 1297 self.generate_values_for_signature(builder, sig.iter().copied()) 1298 } 1299 1300 fn generate_values_for_signature<I: Iterator<Item = Type>>( 1301 &mut self, 1302 builder: &mut FunctionBuilder, 1303 signature: I, 1304 ) -> Result<Vec<Value>> { 1305 signature 1306 .map(|ty| { 1307 let var = self.get_variable_of_type(ty)?; 1308 let val = builder.use_var(var); 1309 Ok(val) 1310 }) 1311 .collect() 1312 } 1313 1314 /// The terminator that we need to insert has already been picked ahead of time 1315 /// we just need to build the instructions for it 1316 fn insert_terminator( 1317 &mut self, 1318 builder: &mut FunctionBuilder, 1319 source_block: Block, 1320 ) -> Result<()> { 1321 let terminator = self.resources.block_terminators[source_block.as_u32() as usize].clone(); 1322 1323 match terminator { 1324 BlockTerminator::Return => { 1325 let types: Vec<Type> = { 1326 let rets = &builder.func.signature.returns; 1327 rets.iter().map(|p| p.value_type).collect() 1328 }; 1329 let vals = self.generate_values_for_signature(builder, types.into_iter())?; 1330 1331 builder.ins().return_(&vals[..]); 1332 } 1333 BlockTerminator::Jump(target) => { 1334 let args = self.generate_values_for_block(builder, target)?; 1335 builder.ins().jump(target, &args[..]); 1336 } 1337 BlockTerminator::Br(left, right) => { 1338 let left_args = self.generate_values_for_block(builder, left)?; 1339 let right_args = self.generate_values_for_block(builder, right)?; 1340 1341 let condbr_types = [I8, I16, I32, I64, I128]; 1342 let _type = *self.u.choose(&condbr_types[..])?; 1343 let val = builder.use_var(self.get_variable_of_type(_type)?); 1344 1345 if bool::arbitrary(self.u)? { 1346 builder.ins().brz(val, left, &left_args[..]); 1347 } else { 1348 builder.ins().brnz(val, left, &left_args[..]); 1349 } 1350 builder.ins().jump(right, &right_args[..]); 1351 } 1352 BlockTerminator::BrTable(default, targets) => { 1353 // Create jump tables on demand 1354 let jt = builder.create_jump_table(JumpTableData::with_blocks(targets)); 1355 1356 // br_table only supports I32 1357 let val = builder.use_var(self.get_variable_of_type(I32)?); 1358 1359 builder.ins().br_table(val, default, jt); 1360 } 1361 BlockTerminator::Switch(_type, default, entries) => { 1362 let mut switch = Switch::new(); 1363 for (&entry, &block) in entries.iter() { 1364 switch.set_entry(entry, block); 1365 } 1366 1367 let switch_val = builder.use_var(self.get_variable_of_type(_type)?); 1368 1369 switch.emit(builder, switch_val, default); 1370 } 1371 } 1372 1373 Ok(()) 1374 } 1375 1376 /// Fills the current block with random instructions 1377 fn generate_instructions(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 1378 for _ in 0..self.param(&self.config.instructions_per_block)? { 1379 let (op, args, rets, inserter) = *self.u.choose(OPCODE_SIGNATURES)?; 1380 inserter(self, builder, op, args, rets)?; 1381 } 1382 1383 Ok(()) 1384 } 1385 1386 fn generate_funcrefs(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 1387 let count = self.param(&self.config.funcrefs_per_function)?; 1388 for func_index in 0..count.try_into().unwrap() { 1389 let (ext_name, sig) = if self.u.arbitrary::<bool>()? { 1390 let user_func_ref = builder 1391 .func 1392 .declare_imported_user_function(UserExternalName { 1393 namespace: 0, 1394 index: func_index, 1395 }); 1396 let name = ExternalName::User(user_func_ref); 1397 let signature = self.generate_signature()?; 1398 (name, signature) 1399 } else { 1400 let libcall = *self.u.choose(ALLOWED_LIBCALLS)?; 1401 // TODO: Use [CallConv::for_libcall] once we generate flags. 1402 let callconv = self.system_callconv(); 1403 let signature = libcall.signature(callconv); 1404 (ExternalName::LibCall(libcall), signature) 1405 }; 1406 1407 let sig_ref = builder.import_signature(sig.clone()); 1408 let func_ref = builder.import_function(ExtFuncData { 1409 name: ext_name, 1410 signature: sig_ref, 1411 colocated: self.u.arbitrary()?, 1412 }); 1413 1414 self.resources.func_refs.push((sig, func_ref)); 1415 } 1416 1417 Ok(()) 1418 } 1419 1420 fn generate_stack_slots(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 1421 for _ in 0..self.param(&self.config.static_stack_slots_per_function)? { 1422 let bytes = self.param(&self.config.static_stack_slot_size)? as u32; 1423 let ss_data = StackSlotData::new(StackSlotKind::ExplicitSlot, bytes); 1424 let slot = builder.create_sized_stack_slot(ss_data); 1425 self.resources.stack_slots.push((slot, bytes)); 1426 } 1427 1428 self.resources 1429 .stack_slots 1430 .sort_unstable_by_key(|&(_slot, bytes)| bytes); 1431 1432 Ok(()) 1433 } 1434 1435 /// Zero initializes the stack slot by inserting `stack_store`'s. 1436 fn initialize_stack_slots(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 1437 let i8_zero = builder.ins().iconst(I8, 0); 1438 let i16_zero = builder.ins().iconst(I16, 0); 1439 let i32_zero = builder.ins().iconst(I32, 0); 1440 let i64_zero = builder.ins().iconst(I64, 0); 1441 let i128_zero = builder.ins().uextend(I128, i64_zero); 1442 1443 for &(slot, init_size) in self.resources.stack_slots.iter() { 1444 let mut size = init_size; 1445 1446 // Insert the largest available store for the remaining size. 1447 while size != 0 { 1448 let offset = (init_size - size) as i32; 1449 let (val, filled) = match size { 1450 sz if sz / 16 > 0 => (i128_zero, 16), 1451 sz if sz / 8 > 0 => (i64_zero, 8), 1452 sz if sz / 4 > 0 => (i32_zero, 4), 1453 sz if sz / 2 > 0 => (i16_zero, 2), 1454 _ => (i8_zero, 1), 1455 }; 1456 builder.ins().stack_store(val, slot, offset); 1457 size -= filled; 1458 } 1459 } 1460 Ok(()) 1461 } 1462 1463 /// Creates a random amount of blocks in this function 1464 fn generate_blocks(&mut self, builder: &mut FunctionBuilder, sig: &Signature) -> Result<()> { 1465 let extra_block_count = self.param(&self.config.blocks_per_function)?; 1466 1467 // We must always have at least one block, so we generate the "extra" blocks and add 1 for 1468 // the entry block. 1469 let block_count = 1 + extra_block_count; 1470 1471 // Blocks need to be sorted in ascending order 1472 self.resources.blocks = (0..block_count) 1473 .map(|i| { 1474 let is_entry = i == 0; 1475 let block = builder.create_block(); 1476 1477 // Optionally mark blocks that are not the entry block as cold 1478 if !is_entry { 1479 if bool::arbitrary(self.u)? { 1480 builder.set_cold_block(block); 1481 } 1482 } 1483 1484 // The first block has to have the function signature, but for the rest of them we generate 1485 // a random signature; 1486 if is_entry { 1487 builder.append_block_params_for_function_params(block); 1488 Ok((block, sig.params.iter().map(|a| a.value_type).collect())) 1489 } else { 1490 let sig = self.generate_block_signature()?; 1491 sig.iter().for_each(|ty| { 1492 builder.append_block_param(block, *ty); 1493 }); 1494 Ok((block, sig)) 1495 } 1496 }) 1497 .collect::<Result<Vec<_>>>()?; 1498 1499 // Valid blocks for jump tables have to have no parameters in the signature, and must also 1500 // not be the first block. 1501 self.resources.blocks_without_params = self.resources.blocks[1..] 1502 .iter() 1503 .filter(|(_, sig)| sig.len() == 0) 1504 .map(|(b, _)| *b) 1505 .collect(); 1506 1507 // Compute the block CFG 1508 // 1509 // cranelift-frontend requires us to never generate unreachable blocks 1510 // To ensure this property we start by constructing a main "spine" of blocks. So block1 can 1511 // always jump to block2, and block2 can always jump to block3, etc... 1512 // 1513 // That is not a very interesting CFG, so we introduce variations on that, but always 1514 // ensuring that the property of pointing to the next block is maintained whatever the 1515 // branching mechanism we use. 1516 let blocks = self.resources.blocks.clone(); 1517 self.resources.block_terminators = blocks 1518 .iter() 1519 .map(|&(block, _)| { 1520 let next_block = Block::with_number(block.as_u32() + 1).unwrap(); 1521 let forward_blocks = self.resources.forward_blocks(block); 1522 let paramless_targets = self.resources.forward_blocks_without_params(block); 1523 let has_paramless_targets = !paramless_targets.is_empty(); 1524 let next_block_is_paramless = paramless_targets.contains(&next_block); 1525 1526 let mut valid_terminators = vec![]; 1527 1528 if forward_blocks.is_empty() { 1529 // Return is only valid on the last block. 1530 valid_terminators.push(BlockTerminatorKind::Return); 1531 } else { 1532 // If we have more than one block we can allow terminators that target blocks. 1533 // TODO: We could add some kind of BrReturn here, to explore edges where we 1534 // exit in the middle of the function 1535 valid_terminators 1536 .extend_from_slice(&[BlockTerminatorKind::Jump, BlockTerminatorKind::Br]); 1537 } 1538 1539 // BrTable and the Switch interface only allow targeting blocks without params 1540 // we also need to ensure that the next block has no params, since that one is 1541 // guaranteed to be picked in either case. 1542 if has_paramless_targets && next_block_is_paramless { 1543 valid_terminators.extend_from_slice(&[ 1544 BlockTerminatorKind::BrTable, 1545 BlockTerminatorKind::Switch, 1546 ]); 1547 } 1548 1549 let terminator = self.u.choose(&valid_terminators[..])?; 1550 1551 // Choose block targets for the terminators that we picked above 1552 Ok(match terminator { 1553 BlockTerminatorKind::Return => BlockTerminator::Return, 1554 BlockTerminatorKind::Jump => BlockTerminator::Jump(next_block), 1555 BlockTerminatorKind::Br => { 1556 BlockTerminator::Br(next_block, self.generate_target_block(block)?) 1557 } 1558 // TODO: Allow generating backwards branches here 1559 BlockTerminatorKind::BrTable => { 1560 // Make the default the next block, and then we don't have to worry 1561 // that we can reach it via the targets 1562 let default = next_block; 1563 1564 let target_count = self.param(&self.config.jump_table_entries)?; 1565 let targets = arbitrary_vec( 1566 self.u, 1567 target_count, 1568 self.resources.forward_blocks_without_params(block), 1569 )?; 1570 1571 BlockTerminator::BrTable(default, targets) 1572 } 1573 BlockTerminatorKind::Switch => { 1574 // Make the default the next block, and then we don't have to worry 1575 // that we can reach it via the entries below 1576 let default_block = next_block; 1577 1578 let _type = *self.u.choose(&[I8, I16, I32, I64, I128][..])?; 1579 1580 // Build this into a HashMap since we cannot have duplicate entries. 1581 let mut entries = HashMap::new(); 1582 for _ in 0..self.param(&self.config.switch_cases)? { 1583 // The Switch API only allows for entries that are addressable by the index type 1584 // so we need to limit the range of values that we generate. 1585 let (ty_min, ty_max) = _type.bounds(false); 1586 let range_start = self.u.int_in_range(ty_min..=ty_max)?; 1587 1588 // We can either insert a contiguous range of blocks or a individual block 1589 // This is done because the Switch API specializes contiguous ranges. 1590 let range_size = if bool::arbitrary(self.u)? { 1591 1 1592 } else { 1593 self.param(&self.config.switch_max_range_size)? 1594 } as u128; 1595 1596 // Build the switch entries 1597 for i in 0..range_size { 1598 let index = range_start.wrapping_add(i) % ty_max; 1599 let block = *self 1600 .u 1601 .choose(self.resources.forward_blocks_without_params(block))?; 1602 1603 entries.insert(index, block); 1604 } 1605 } 1606 1607 BlockTerminator::Switch(_type, default_block, entries) 1608 } 1609 }) 1610 }) 1611 .collect::<Result<_>>()?; 1612 1613 Ok(()) 1614 } 1615 1616 fn generate_block_signature(&mut self) -> Result<BlockSignature> { 1617 let param_count = self.param(&self.config.block_signature_params)?; 1618 1619 let mut params = Vec::with_capacity(param_count); 1620 for _ in 0..param_count { 1621 params.push(self.generate_type()?); 1622 } 1623 Ok(params) 1624 } 1625 1626 fn build_variable_pool(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 1627 let block = builder.current_block().unwrap(); 1628 1629 // Define variables for the function signature 1630 let mut vars: Vec<_> = builder 1631 .func 1632 .signature 1633 .params 1634 .iter() 1635 .map(|param| param.value_type) 1636 .zip(builder.block_params(block).iter().copied()) 1637 .collect(); 1638 1639 // Create a pool of vars that are going to be used in this function 1640 for _ in 0..self.param(&self.config.vars_per_function)? { 1641 let ty = self.generate_type()?; 1642 let value = self.generate_const(builder, ty)?; 1643 vars.push((ty, value)); 1644 } 1645 1646 for (id, (ty, value)) in vars.into_iter().enumerate() { 1647 let var = Variable::new(id); 1648 builder.declare_var(var, ty); 1649 builder.def_var(var, value); 1650 self.resources 1651 .vars 1652 .entry(ty) 1653 .or_insert_with(Vec::new) 1654 .push(var); 1655 } 1656 1657 Ok(()) 1658 } 1659 1660 /// We generate a function in multiple stages: 1661 /// 1662 /// * First we generate a random number of empty blocks 1663 /// * Then we generate a random pool of variables to be used throughout the function 1664 /// * We then visit each block and generate random instructions 1665 /// 1666 /// Because we generate all blocks and variables up front we already know everything that 1667 /// we need when generating instructions (i.e. jump targets / variables) 1668 pub fn generate(mut self) -> Result<Function> { 1669 let sig = self.generate_signature()?; 1670 1671 let mut fn_builder_ctx = FunctionBuilderContext::new(); 1672 // function name must be in a different namespace than TESTFILE_NAMESPACE (0) 1673 let mut func = Function::with_name_signature(UserFuncName::user(1, 0), sig.clone()); 1674 1675 let mut builder = FunctionBuilder::new(&mut func, &mut fn_builder_ctx); 1676 1677 self.generate_blocks(&mut builder, &sig)?; 1678 1679 // Function preamble 1680 self.generate_funcrefs(&mut builder)?; 1681 self.generate_stack_slots(&mut builder)?; 1682 1683 // Main instruction generation loop 1684 for (block, block_sig) in self.resources.blocks.clone().into_iter() { 1685 let is_block0 = block.as_u32() == 0; 1686 builder.switch_to_block(block); 1687 1688 if is_block0 { 1689 // The first block is special because we must create variables both for the 1690 // block signature and for the variable pool. Additionally, we must also define 1691 // initial values for all variables that are not the function signature. 1692 self.build_variable_pool(&mut builder)?; 1693 1694 // Stack slots have random bytes at the beginning of the function 1695 // initialize them to a constant value so that execution stays predictable. 1696 self.initialize_stack_slots(&mut builder)?; 1697 } else { 1698 // Define variables for the block params 1699 for (i, ty) in block_sig.iter().enumerate() { 1700 let var = self.get_variable_of_type(*ty)?; 1701 let block_param = builder.block_params(block)[i]; 1702 builder.def_var(var, block_param); 1703 } 1704 } 1705 1706 // Generate block instructions 1707 self.generate_instructions(&mut builder)?; 1708 1709 // Insert a terminator to safely exit the block 1710 self.insert_terminator(&mut builder, block)?; 1711 } 1712 1713 builder.seal_all_blocks(); 1714 builder.finalize(); 1715 1716 Ok(func) 1717 } 1718 } 1719