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