1 use crate::config::Config; 2 use crate::cranelift_arbitrary::CraneliftArbitrary; 3 use anyhow::Result; 4 use arbitrary::{Arbitrary, Unstructured}; 5 use cranelift::codegen::data_value::DataValue; 6 use cranelift::codegen::ir::immediates::Offset32; 7 use cranelift::codegen::ir::instructions::{InstructionFormat, ResolvedConstraint}; 8 use cranelift::codegen::ir::stackslot::StackSize; 9 10 use cranelift::codegen::ir::{ 11 types::*, AtomicRmwOp, Block, ConstantData, ExternalName, FuncRef, Function, LibCall, Opcode, 12 SigRef, Signature, StackSlot, Type, UserExternalName, UserFuncName, Value, 13 }; 14 use cranelift::codegen::isa::CallConv; 15 use cranelift::frontend::{FunctionBuilder, FunctionBuilderContext, Switch, Variable}; 16 use cranelift::prelude::{ 17 EntityRef, ExtFuncData, FloatCC, InstBuilder, IntCC, JumpTableData, MemFlags, StackSlotData, 18 StackSlotKind, 19 }; 20 use once_cell::sync::Lazy; 21 use std::collections::HashMap; 22 use std::ops::RangeInclusive; 23 use target_lexicon::{Architecture, Triple}; 24 25 type BlockSignature = Vec<Type>; 26 27 fn insert_opcode( 28 fgen: &mut FunctionGenerator, 29 builder: &mut FunctionBuilder, 30 opcode: Opcode, 31 args: &[Type], 32 rets: &[Type], 33 ) -> Result<()> { 34 let mut vals = Vec::with_capacity(args.len()); 35 for &arg in args.into_iter() { 36 let var = fgen.get_variable_of_type(arg)?; 37 let val = builder.use_var(var); 38 vals.push(val); 39 } 40 41 // Some opcodes require us to look at their input arguments to determine the 42 // controlling type. This is not the general case, but we can neatly check this 43 // using `requires_typevar_operand`. 44 let ctrl_type = if opcode.constraints().requires_typevar_operand() { 45 args.first() 46 } else { 47 rets.first() 48 } 49 .copied() 50 .unwrap_or(INVALID); 51 52 // Choose the appropriate instruction format for this opcode 53 let (inst, dfg) = match opcode.format() { 54 InstructionFormat::NullAry => builder.ins().NullAry(opcode, ctrl_type), 55 InstructionFormat::Unary => builder.ins().Unary(opcode, ctrl_type, vals[0]), 56 InstructionFormat::Binary => builder.ins().Binary(opcode, ctrl_type, vals[0], vals[1]), 57 InstructionFormat::Ternary => builder 58 .ins() 59 .Ternary(opcode, ctrl_type, vals[0], vals[1], vals[2]), 60 _ => unimplemented!(), 61 }; 62 let results = dfg.inst_results(inst).to_vec(); 63 64 for (val, &ty) in results.into_iter().zip(rets) { 65 let var = fgen.get_variable_of_type(ty)?; 66 builder.def_var(var, val); 67 } 68 Ok(()) 69 } 70 71 fn insert_call( 72 fgen: &mut FunctionGenerator, 73 builder: &mut FunctionBuilder, 74 opcode: Opcode, 75 args: &[Type], 76 _rets: &[Type], 77 ) -> Result<()> { 78 assert!(matches!(opcode, Opcode::Call | Opcode::CallIndirect)); 79 let (sig, sig_ref, func_ref) = fgen.u.choose(&fgen.resources.func_refs)?.clone(); 80 81 let actuals = fgen.generate_values_for_signature( 82 builder, 83 sig.params.iter().map(|abi_param| abi_param.value_type), 84 )?; 85 86 let call = if opcode == Opcode::Call { 87 builder.ins().call(func_ref, &actuals) 88 } else { 89 let addr_ty = args[0]; 90 let addr = builder.ins().func_addr(addr_ty, func_ref); 91 builder.ins().call_indirect(sig_ref, addr, &actuals) 92 }; 93 94 // Assign the return values to random variables 95 let ret_values = builder.inst_results(call).to_vec(); 96 let ret_types = sig.returns.iter().map(|p| p.value_type); 97 for (ty, val) in ret_types.zip(ret_values) { 98 let var = fgen.get_variable_of_type(ty)?; 99 builder.def_var(var, val); 100 } 101 102 Ok(()) 103 } 104 105 fn insert_stack_load( 106 fgen: &mut FunctionGenerator, 107 builder: &mut FunctionBuilder, 108 _opcode: Opcode, 109 _args: &[Type], 110 rets: &[Type], 111 ) -> Result<()> { 112 let typevar = rets[0]; 113 let type_size = typevar.bytes(); 114 let (slot, slot_size) = fgen.stack_slot_with_size(type_size)?; 115 let offset = fgen.u.int_in_range(0..=(slot_size - type_size))? as i32; 116 117 let val = builder.ins().stack_load(typevar, slot, offset); 118 let var = fgen.get_variable_of_type(typevar)?; 119 builder.def_var(var, val); 120 121 Ok(()) 122 } 123 124 fn insert_stack_store( 125 fgen: &mut FunctionGenerator, 126 builder: &mut FunctionBuilder, 127 _opcode: Opcode, 128 args: &[Type], 129 _rets: &[Type], 130 ) -> Result<()> { 131 let typevar = args[0]; 132 let type_size = typevar.bytes(); 133 let (slot, slot_size) = fgen.stack_slot_with_size(type_size)?; 134 let offset = fgen.u.int_in_range(0..=(slot_size - type_size))? as i32; 135 136 let arg0 = fgen.get_variable_of_type(typevar)?; 137 let arg0 = builder.use_var(arg0); 138 139 builder.ins().stack_store(arg0, slot, offset); 140 Ok(()) 141 } 142 143 fn insert_cmp( 144 fgen: &mut FunctionGenerator, 145 builder: &mut FunctionBuilder, 146 opcode: Opcode, 147 args: &[Type], 148 rets: &[Type], 149 ) -> Result<()> { 150 let lhs = fgen.get_variable_of_type(args[0])?; 151 let lhs = builder.use_var(lhs); 152 153 let rhs = fgen.get_variable_of_type(args[1])?; 154 let rhs = builder.use_var(rhs); 155 156 let res = if opcode == Opcode::Fcmp { 157 let cc = *fgen.u.choose(FloatCC::all())?; 158 159 // We filter out condition codes that aren't supported by the target at 160 // this point after randomly choosing one, instead of randomly choosing a 161 // supported one, to avoid invalidating the corpus when these get implemented. 162 let unimplemented_cc = match (fgen.target_triple.architecture, cc) { 163 // Some FloatCC's are not implemented on AArch64, see: 164 // https://github.com/bytecodealliance/wasmtime/issues/4850 165 (Architecture::Aarch64(_), FloatCC::OrderedNotEqual) => true, 166 (Architecture::Aarch64(_), FloatCC::UnorderedOrEqual) => true, 167 (Architecture::Aarch64(_), FloatCC::UnorderedOrLessThan) => true, 168 (Architecture::Aarch64(_), FloatCC::UnorderedOrLessThanOrEqual) => true, 169 (Architecture::Aarch64(_), FloatCC::UnorderedOrGreaterThan) => true, 170 (Architecture::Aarch64(_), FloatCC::UnorderedOrGreaterThanOrEqual) => true, 171 172 // These are not implemented on x86_64, for vectors. 173 (Architecture::X86_64, FloatCC::UnorderedOrEqual | FloatCC::OrderedNotEqual) => { 174 args[0].is_vector() 175 } 176 _ => false, 177 }; 178 if unimplemented_cc { 179 return Err(arbitrary::Error::IncorrectFormat.into()); 180 } 181 182 builder.ins().fcmp(cc, lhs, rhs) 183 } else { 184 let cc = *fgen.u.choose(IntCC::all())?; 185 builder.ins().icmp(cc, lhs, rhs) 186 }; 187 188 let var = fgen.get_variable_of_type(rets[0])?; 189 builder.def_var(var, res); 190 191 Ok(()) 192 } 193 194 fn insert_const( 195 fgen: &mut FunctionGenerator, 196 builder: &mut FunctionBuilder, 197 _opcode: Opcode, 198 _args: &[Type], 199 rets: &[Type], 200 ) -> Result<()> { 201 let typevar = rets[0]; 202 let var = fgen.get_variable_of_type(typevar)?; 203 let val = fgen.generate_const(builder, typevar)?; 204 builder.def_var(var, val); 205 Ok(()) 206 } 207 208 fn insert_bitcast( 209 fgen: &mut FunctionGenerator, 210 builder: &mut FunctionBuilder, 211 args: &[Type], 212 rets: &[Type], 213 ) -> Result<()> { 214 let from_var = fgen.get_variable_of_type(args[0])?; 215 let from_val = builder.use_var(from_var); 216 217 let to_var = fgen.get_variable_of_type(rets[0])?; 218 219 // TODO: We can generate little/big endian flags here. 220 let memflags = MemFlags::new(); 221 222 let res = builder.ins().bitcast(rets[0], memflags, from_val); 223 builder.def_var(to_var, res); 224 Ok(()) 225 } 226 227 fn insert_load_store( 228 fgen: &mut FunctionGenerator, 229 builder: &mut FunctionBuilder, 230 opcode: Opcode, 231 args: &[Type], 232 rets: &[Type], 233 ) -> Result<()> { 234 if opcode == Opcode::Bitcast { 235 return insert_bitcast(fgen, builder, args, rets); 236 } 237 238 let ctrl_type = *rets.first().or(args.first()).unwrap(); 239 let type_size = ctrl_type.bytes(); 240 241 let is_atomic = [Opcode::AtomicLoad, Opcode::AtomicStore].contains(&opcode); 242 let (address, flags, offset) = 243 fgen.generate_address_and_memflags(builder, type_size, is_atomic)?; 244 245 // The variable being loaded or stored into 246 let var = fgen.get_variable_of_type(ctrl_type)?; 247 248 match opcode.format() { 249 InstructionFormat::LoadNoOffset => { 250 let (inst, dfg) = builder 251 .ins() 252 .LoadNoOffset(opcode, ctrl_type, flags, address); 253 254 let new_val = dfg.first_result(inst); 255 builder.def_var(var, new_val); 256 } 257 InstructionFormat::StoreNoOffset => { 258 let val = builder.use_var(var); 259 260 builder 261 .ins() 262 .StoreNoOffset(opcode, ctrl_type, flags, val, address); 263 } 264 InstructionFormat::Store => { 265 let val = builder.use_var(var); 266 267 builder 268 .ins() 269 .Store(opcode, ctrl_type, flags, offset, val, address); 270 } 271 InstructionFormat::Load => { 272 let (inst, dfg) = builder 273 .ins() 274 .Load(opcode, ctrl_type, flags, offset, address); 275 276 let new_val = dfg.first_result(inst); 277 builder.def_var(var, new_val); 278 } 279 _ => unimplemented!(), 280 } 281 282 Ok(()) 283 } 284 285 fn insert_atomic_rmw( 286 fgen: &mut FunctionGenerator, 287 builder: &mut FunctionBuilder, 288 _: Opcode, 289 _: &[Type], 290 rets: &[Type], 291 ) -> Result<()> { 292 let ctrl_type = *rets.first().unwrap(); 293 let type_size = ctrl_type.bytes(); 294 295 let rmw_op = *fgen.u.choose(AtomicRmwOp::all())?; 296 297 let (address, flags, offset) = fgen.generate_address_and_memflags(builder, type_size, true)?; 298 299 // AtomicRMW does not directly support offsets, so add the offset to the address separately. 300 let address = builder.ins().iadd_imm(address, i64::from(offset)); 301 302 // Load and store target variables 303 let source_var = fgen.get_variable_of_type(ctrl_type)?; 304 let target_var = fgen.get_variable_of_type(ctrl_type)?; 305 306 let source_val = builder.use_var(source_var); 307 let new_val = builder 308 .ins() 309 .atomic_rmw(ctrl_type, flags, rmw_op, address, source_val); 310 311 builder.def_var(target_var, new_val); 312 Ok(()) 313 } 314 315 fn insert_atomic_cas( 316 fgen: &mut FunctionGenerator, 317 builder: &mut FunctionBuilder, 318 _: Opcode, 319 _: &[Type], 320 rets: &[Type], 321 ) -> Result<()> { 322 let ctrl_type = *rets.first().unwrap(); 323 let type_size = ctrl_type.bytes(); 324 325 let (address, flags, offset) = fgen.generate_address_and_memflags(builder, type_size, true)?; 326 327 // AtomicCas does not directly support offsets, so add the offset to the address separately. 328 let address = builder.ins().iadd_imm(address, i64::from(offset)); 329 330 // Source and Target variables 331 let expected_var = fgen.get_variable_of_type(ctrl_type)?; 332 let store_var = fgen.get_variable_of_type(ctrl_type)?; 333 let loaded_var = fgen.get_variable_of_type(ctrl_type)?; 334 335 let expected_val = builder.use_var(expected_var); 336 let store_val = builder.use_var(store_var); 337 let new_val = builder 338 .ins() 339 .atomic_cas(flags, address, expected_val, store_val); 340 341 builder.def_var(loaded_var, new_val); 342 Ok(()) 343 } 344 345 fn insert_shuffle( 346 fgen: &mut FunctionGenerator, 347 builder: &mut FunctionBuilder, 348 opcode: Opcode, 349 _: &[Type], 350 rets: &[Type], 351 ) -> Result<()> { 352 let ctrl_type = *rets.first().unwrap(); 353 354 let lhs = builder.use_var(fgen.get_variable_of_type(ctrl_type)?); 355 let rhs = builder.use_var(fgen.get_variable_of_type(ctrl_type)?); 356 357 let mask = { 358 let mut lanes = [0u8; 16]; 359 for lane in lanes.iter_mut() { 360 *lane = fgen.u.int_in_range(0..=31)?; 361 } 362 let lanes = ConstantData::from(lanes.as_ref()); 363 builder.func.dfg.immediates.push(lanes) 364 }; 365 366 // This function is called for any `InstructionFormat::Shuffle`. Which today is just 367 // `shuffle`, but lets assert that, just to be sure we don't accidentally insert 368 // something else. 369 assert_eq!(opcode, Opcode::Shuffle); 370 let res = builder.ins().shuffle(lhs, rhs, mask); 371 372 let target_var = fgen.get_variable_of_type(ctrl_type)?; 373 builder.def_var(target_var, res); 374 375 Ok(()) 376 } 377 378 fn insert_ins_ext_lane( 379 fgen: &mut FunctionGenerator, 380 builder: &mut FunctionBuilder, 381 opcode: Opcode, 382 args: &[Type], 383 rets: &[Type], 384 ) -> Result<()> { 385 let vector_type = *args.first().unwrap(); 386 let ret_type = *rets.first().unwrap(); 387 388 let lhs = builder.use_var(fgen.get_variable_of_type(vector_type)?); 389 let max_lane = (vector_type.lane_count() as u8) - 1; 390 let lane = fgen.u.int_in_range(0..=max_lane)?; 391 392 let res = match opcode { 393 Opcode::Insertlane => { 394 let rhs = builder.use_var(fgen.get_variable_of_type(args[1])?); 395 builder.ins().insertlane(lhs, rhs, lane) 396 } 397 Opcode::Extractlane => builder.ins().extractlane(lhs, lane), 398 _ => todo!(), 399 }; 400 401 let target_var = fgen.get_variable_of_type(ret_type)?; 402 builder.def_var(target_var, res); 403 404 Ok(()) 405 } 406 407 type OpcodeInserter = fn( 408 fgen: &mut FunctionGenerator, 409 builder: &mut FunctionBuilder, 410 Opcode, 411 &[Type], 412 &[Type], 413 ) -> Result<()>; 414 415 macro_rules! exceptions { 416 ($op:expr, $args:expr, $rets:expr, $(($($cases:pat),*)),* $(,)?) => { 417 match ($op, $args, $rets) { 418 $( ($($cases,)* ..) => return false, )* 419 _ => true, 420 } 421 } 422 } 423 424 /// Returns true if we believe this `OpcodeSignature` should compile correctly 425 /// for the given target triple. We currently have a range of known issues 426 /// with specific lowerings on specific backends, and we don't want to get 427 /// fuzz bug reports for those. Over time our goal is to eliminate all of these 428 /// exceptions. 429 fn valid_for_target(triple: &Triple, op: Opcode, args: &[Type], rets: &[Type]) -> bool { 430 // Rule out invalid combinations that we don't yet have a good way of rejecting with the 431 // instruction DSL type constraints. 432 match op { 433 Opcode::FcvtToUintSat | Opcode::FcvtToSintSat => { 434 assert_eq!(args.len(), 1); 435 assert_eq!(rets.len(), 1); 436 437 let arg = args[0]; 438 let ret = args[0]; 439 440 // Vector arguments must produce vector results, and scalar arguments must produce 441 // scalar results. 442 if arg.is_vector() != ret.is_vector() { 443 return false; 444 } 445 446 if arg.is_vector() && arg.is_vector() { 447 // Vector conversions must have the same number of lanes, and the lanes must be the 448 // same bit-width. 449 if arg.lane_count() != ret.lane_count() { 450 return false; 451 } 452 453 if arg.lane_of().bits() != ret.lane_of().bits() { 454 return false; 455 } 456 } 457 } 458 459 _ => {} 460 } 461 462 match triple.architecture { 463 Architecture::X86_64 => { 464 exceptions!( 465 op, 466 args, 467 rets, 468 (Opcode::UmulOverflow | Opcode::SmulOverflow, &[I128, I128]), 469 (Opcode::Imul, &[I8X16, I8X16]), 470 // https://github.com/bytecodealliance/wasmtime/issues/5468 471 (Opcode::Smulhi | Opcode::Umulhi, &[I8, I8]), 472 // https://github.com/bytecodealliance/wasmtime/issues/4756 473 (Opcode::Udiv | Opcode::Sdiv, &[I128, I128]), 474 // https://github.com/bytecodealliance/wasmtime/issues/5474 475 (Opcode::Urem | Opcode::Srem, &[I128, I128]), 476 // https://github.com/bytecodealliance/wasmtime/issues/5466 477 (Opcode::Iabs, &[I128]), 478 // https://github.com/bytecodealliance/wasmtime/issues/3370 479 ( 480 Opcode::Smin | Opcode::Umin | Opcode::Smax | Opcode::Umax, 481 &[I128, I128] 482 ), 483 // https://github.com/bytecodealliance/wasmtime/issues/4870 484 (Opcode::Bnot, &[F32 | F64]), 485 ( 486 Opcode::Band 487 | Opcode::Bor 488 | Opcode::Bxor 489 | Opcode::BandNot 490 | Opcode::BorNot 491 | Opcode::BxorNot, 492 &([F32, F32] | [F64, F64]) 493 ), 494 // https://github.com/bytecodealliance/wasmtime/issues/5041 495 ( 496 Opcode::BandNot | Opcode::BorNot | Opcode::BxorNot, 497 &([I8, I8] | [I16, I16] | [I32, I32] | [I64, I64] | [I128, I128]) 498 ), 499 // https://github.com/bytecodealliance/wasmtime/issues/5107 500 (Opcode::Cls, &[I8], &[I8]), 501 (Opcode::Cls, &[I16], &[I16]), 502 (Opcode::Cls, &[I32], &[I32]), 503 (Opcode::Cls, &[I64], &[I64]), 504 (Opcode::Cls, &[I128], &[I128]), 505 // https://github.com/bytecodealliance/wasmtime/issues/5197 506 ( 507 Opcode::Bitselect, 508 &([I8, I8, I8] 509 | [I16, I16, I16] 510 | [I32, I32, I32] 511 | [I64, I64, I64] 512 | [I128, I128, I128]) 513 ), 514 // https://github.com/bytecodealliance/wasmtime/issues/4897 515 // https://github.com/bytecodealliance/wasmtime/issues/4899 516 ( 517 Opcode::FcvtToUint 518 | Opcode::FcvtToUintSat 519 | Opcode::FcvtToSint 520 | Opcode::FcvtToSintSat, 521 &[F32 | F64], 522 &[I8 | I16 | I128] 523 ), 524 (Opcode::FcvtToUint | Opcode::FcvtToSint, &[F32X4], &[I32X4]), 525 ( 526 Opcode::FcvtToUint 527 | Opcode::FcvtToUintSat 528 | Opcode::FcvtToSint 529 | Opcode::FcvtToSintSat, 530 &[F64X2], 531 &[I64X2] 532 ), 533 // https://github.com/bytecodealliance/wasmtime/issues/4900 534 (Opcode::FcvtFromUint, &[I128], &[F32 | F64]), 535 // This has a lowering, but only when preceded by `uwiden_low`. 536 (Opcode::FcvtFromUint, &[I64X2], &[F64X2]), 537 // https://github.com/bytecodealliance/wasmtime/issues/4900 538 (Opcode::FcvtFromSint, &[I128], &[F32 | F64]), 539 (Opcode::FcvtFromSint, &[I64X2], &[F64X2]), 540 ( 541 Opcode::Umulhi | Opcode::Smulhi, 542 &([I8X16, I8X16] | [I16X8, I16X8] | [I32X4, I32X4] | [I64X2, I64X2]) 543 ), 544 ( 545 Opcode::UaddSat | Opcode::SaddSat | Opcode::UsubSat | Opcode::SsubSat, 546 &([I32X4, I32X4] | [I64X2, I64X2]) 547 ), 548 (Opcode::Fcopysign, &([F32X4, F32X4] | [F64X2, F64X2])), 549 (Opcode::Popcnt, &([I8X16] | [I16X8] | [I32X4] | [I64X2])), 550 ( 551 Opcode::Umax | Opcode::Smax | Opcode::Umin | Opcode::Smin, 552 &[I64X2, I64X2] 553 ), 554 (Opcode::Bitcast, &[I128], &[_]), 555 (Opcode::Bitcast, &[_], &[I128]), 556 (Opcode::Uunarrow), 557 (Opcode::Snarrow | Opcode::Unarrow, &[I64X2, I64X2]), 558 (Opcode::SqmulRoundSat, &[I32X4, I32X4]), 559 // This Icmp is not implemented: #5529 560 (Opcode::Icmp, &[I64X2, I64X2]), 561 // IaddPairwise is implemented, but only for some types, and with some preceding ops. 562 (Opcode::IaddPairwise), 563 // Nothing wrong with this select. But we have an isle rule that can optimize it 564 // into a `min`/`max` instructions, which we don't have implemented yet. 565 (Opcode::Select, &[_, I128, I128]), 566 // These stack accesses can cause segfaults if they are merged into an SSE instruction. 567 // See: #5922 568 ( 569 Opcode::StackStore, 570 &[I8X16 | I16X8 | I32X4 | I64X2 | F32X4 | F64X2] 571 ), 572 ( 573 Opcode::StackLoad, 574 &[], 575 &[I8X16 | I16X8 | I32X4 | I64X2 | F32X4 | F64X2] 576 ), 577 ) 578 } 579 580 Architecture::Aarch64(_) => { 581 exceptions!( 582 op, 583 args, 584 rets, 585 (Opcode::UmulOverflow | Opcode::SmulOverflow, &[I128, I128]), 586 // https://github.com/bytecodealliance/wasmtime/issues/4864 587 (Opcode::Udiv | Opcode::Sdiv, &[I128, I128]), 588 // https://github.com/bytecodealliance/wasmtime/issues/5472 589 (Opcode::Urem | Opcode::Srem, &[I128, I128]), 590 // https://github.com/bytecodealliance/wasmtime/issues/5467 591 (Opcode::Iabs, &[I128]), 592 // https://github.com/bytecodealliance/wasmtime/issues/4313 593 ( 594 Opcode::Smin | Opcode::Umin | Opcode::Smax | Opcode::Umax, 595 &[I128, I128] 596 ), 597 // https://github.com/bytecodealliance/wasmtime/issues/4870 598 (Opcode::Bnot, &[F32 | F64]), 599 ( 600 Opcode::Band 601 | Opcode::Bor 602 | Opcode::Bxor 603 | Opcode::BandNot 604 | Opcode::BorNot 605 | Opcode::BxorNot, 606 &([F32, F32] | [F64, F64]) 607 ), 608 // https://github.com/bytecodealliance/wasmtime/issues/5198 609 (Opcode::Bitselect, &[I128, I128, I128]), 610 // https://github.com/bytecodealliance/wasmtime/issues/4934 611 ( 612 Opcode::FcvtToUint 613 | Opcode::FcvtToUintSat 614 | Opcode::FcvtToSint 615 | Opcode::FcvtToSintSat, 616 &[F32 | F64] 617 ), 618 // https://github.com/bytecodealliance/wasmtime/issues/4933 619 ( 620 Opcode::FcvtFromUint | Opcode::FcvtFromSint, 621 &[I128], 622 &[F32 | F64] 623 ), 624 ( 625 Opcode::Umulhi | Opcode::Smulhi, 626 &([I8X16, I8X16] | [I16X8, I16X8] | [I32X4, I32X4] | [I64X2, I64X2]) 627 ), 628 (Opcode::Popcnt, &[I16X8 | I32X4 | I64X2]), 629 // Nothing wrong with this select. But we have an isle rule that can optimize it 630 // into a `min`/`max` instructions, which we don't have implemented yet. 631 (Opcode::Select, &[I8, I128, I128]), 632 ) 633 } 634 635 Architecture::S390x => { 636 exceptions!( 637 op, 638 args, 639 rets, 640 (Opcode::UaddOverflow | Opcode::SaddOverflow), 641 (Opcode::UsubOverflow | Opcode::SsubOverflow), 642 (Opcode::UmulOverflow | Opcode::SmulOverflow), 643 ( 644 Opcode::Udiv | Opcode::Sdiv | Opcode::Urem | Opcode::Srem, 645 &[I128, I128] 646 ), 647 (Opcode::Bnot, &[F32 | F64]), 648 ( 649 Opcode::Band 650 | Opcode::Bor 651 | Opcode::Bxor 652 | Opcode::BandNot 653 | Opcode::BorNot 654 | Opcode::BxorNot, 655 &([F32, F32] | [F64, F64]) 656 ), 657 ( 658 Opcode::FcvtToUint 659 | Opcode::FcvtToUintSat 660 | Opcode::FcvtToSint 661 | Opcode::FcvtToSintSat, 662 &[F32 | F64], 663 &[I128] 664 ), 665 ( 666 Opcode::FcvtFromUint | Opcode::FcvtFromSint, 667 &[I128], 668 &[F32 | F64] 669 ), 670 (Opcode::SsubSat | Opcode::SaddSat, &[I64X2, I64X2]), 671 ) 672 } 673 674 Architecture::Riscv64(_) => { 675 // RISC-V Does not support SIMD at all 676 let is_simd = args.iter().chain(rets).any(|t| t.is_vector()); 677 if is_simd { 678 return false; 679 } 680 681 exceptions!( 682 op, 683 args, 684 rets, 685 // TODO 686 (Opcode::UaddOverflow | Opcode::SaddOverflow), 687 (Opcode::UsubOverflow | Opcode::SsubOverflow), 688 (Opcode::UmulOverflow | Opcode::SmulOverflow), 689 // TODO 690 ( 691 Opcode::Udiv | Opcode::Sdiv | Opcode::Urem | Opcode::Srem, 692 &[I128, I128] 693 ), 694 // TODO 695 (Opcode::Iabs, &[I128]), 696 // TODO 697 (Opcode::Bitselect, &[I128, I128, I128]), 698 // TODO 699 (Opcode::Bswap), 700 // https://github.com/bytecodealliance/wasmtime/issues/5528 701 ( 702 Opcode::FcvtToUint | Opcode::FcvtToSint, 703 [F32 | F64], 704 &[I128] 705 ), 706 ( 707 Opcode::FcvtToUintSat | Opcode::FcvtToSintSat, 708 &[F32 | F64], 709 &[I8 | I16 | I128] 710 ), 711 // https://github.com/bytecodealliance/wasmtime/issues/5528 712 ( 713 Opcode::FcvtFromUint | Opcode::FcvtFromSint, 714 &[I128], 715 &[F32 | F64] 716 ), 717 ) 718 } 719 720 _ => true, 721 } 722 } 723 724 type OpcodeSignature = (Opcode, Vec<Type>, Vec<Type>); 725 726 static OPCODE_SIGNATURES: Lazy<Vec<OpcodeSignature>> = Lazy::new(|| { 727 let types = &[ 728 I8, I16, I32, I64, I128, // Scalar Integers 729 F32, F64, // Scalar Floats 730 I8X16, I16X8, I32X4, I64X2, // SIMD Integers 731 F32X4, F64X2, // SIMD Floats 732 ]; 733 734 Opcode::all() 735 .iter() 736 .filter(|op| { 737 match op { 738 // Control flow opcodes should not be generated through `generate_instructions`. 739 Opcode::BrTable | Opcode::Brif | Opcode::Jump | Opcode::Return => false, 740 741 // Constants are generated outside of `generate_instructions` 742 Opcode::Iconst => false, 743 744 // TODO: extract_vector raises exceptions during return type generation becuase it 745 // uses dynamic vectors. 746 Opcode::ExtractVector => false, 747 748 _ => true, 749 } 750 }) 751 .flat_map(|op| { 752 let constraints = op.constraints(); 753 754 let ctrl_types = if let Some(ctrls) = constraints.ctrl_typeset() { 755 Vec::from_iter(types.iter().copied().filter(|ty| ctrls.contains(*ty))) 756 } else { 757 vec![INVALID] 758 }; 759 760 ctrl_types.into_iter().flat_map(move |ctrl_type| { 761 let rets = Vec::from_iter( 762 (0..constraints.num_fixed_results()) 763 .map(|i| constraints.result_type(i, ctrl_type)), 764 ); 765 766 // Cols is a vector whose length will match `num_fixed_value_arguments`, and whose 767 // elements will be vectors of types that are valid for that fixed argument 768 // position. 769 let mut cols = vec![]; 770 771 for i in 0..constraints.num_fixed_value_arguments() { 772 match constraints.value_argument_constraint(i, ctrl_type) { 773 ResolvedConstraint::Bound(ty) => cols.push(Vec::from([ty])), 774 ResolvedConstraint::Free(tys) => cols.push(Vec::from_iter( 775 types.iter().copied().filter(|ty| tys.contains(*ty)), 776 )), 777 } 778 } 779 780 // Generate the cartesian product of cols to produce a vector of argument lists, 781 // argss. The argss vector is seeded with the empty argument list, so there's an 782 // initial value to be extended in the loop below. 783 let mut argss = vec![vec![]]; 784 let mut cols = cols.as_slice(); 785 while let Some((col, rest)) = cols.split_last() { 786 cols = rest; 787 788 let mut next = vec![]; 789 for current in argss.iter() { 790 // Extend the front of each argument candidate with every type in `col`. 791 for ty in col { 792 let mut args = vec![*ty]; 793 args.extend_from_slice(¤t); 794 next.push(args); 795 } 796 } 797 798 let _ = std::mem::replace(&mut argss, next); 799 } 800 801 argss.into_iter().map(move |args| (*op, args, rets.clone())) 802 }) 803 }) 804 .filter(|(op, args, rets)| { 805 // These op/signature combinations need to be vetted 806 exceptions!( 807 op, 808 args.as_slice(), 809 rets.as_slice(), 810 (Opcode::Debugtrap), 811 (Opcode::Trap), 812 (Opcode::Trapz), 813 (Opcode::ResumableTrap), 814 (Opcode::Trapnz), 815 (Opcode::ResumableTrapnz), 816 (Opcode::CallIndirect, &[I32]), 817 (Opcode::ReturnCall), 818 (Opcode::ReturnCallIndirect), 819 (Opcode::FuncAddr), 820 (Opcode::X86Pshufb), 821 (Opcode::AvgRound), 822 (Opcode::Uload8x8), 823 (Opcode::Sload8x8), 824 (Opcode::Uload16x4), 825 (Opcode::Sload16x4), 826 (Opcode::Uload32x2), 827 (Opcode::Sload32x2), 828 (Opcode::StackAddr), 829 (Opcode::DynamicStackLoad), 830 (Opcode::DynamicStackStore), 831 (Opcode::DynamicStackAddr), 832 (Opcode::GlobalValue), 833 (Opcode::SymbolValue), 834 (Opcode::TlsValue), 835 (Opcode::GetPinnedReg), 836 (Opcode::SetPinnedReg), 837 (Opcode::GetFramePointer), 838 (Opcode::GetStackPointer), 839 (Opcode::GetReturnAddress), 840 (Opcode::TableAddr), 841 (Opcode::Null), 842 (Opcode::X86Blendv), 843 (Opcode::VallTrue), 844 (Opcode::IcmpImm), 845 (Opcode::X86Pmulhrsw), 846 (Opcode::IaddImm), 847 (Opcode::ImulImm), 848 (Opcode::UdivImm), 849 (Opcode::SdivImm), 850 (Opcode::UremImm), 851 (Opcode::SremImm), 852 (Opcode::IrsubImm), 853 (Opcode::IaddCin), 854 (Opcode::IaddCarry), 855 (Opcode::UaddOverflowTrap), 856 (Opcode::IsubBin), 857 (Opcode::IsubBorrow), 858 (Opcode::BandImm), 859 (Opcode::BorImm), 860 (Opcode::BxorImm), 861 (Opcode::RotlImm), 862 (Opcode::RotrImm), 863 (Opcode::IshlImm), 864 (Opcode::UshrImm), 865 (Opcode::SshrImm), 866 (Opcode::IsNull), 867 (Opcode::IsInvalid), 868 (Opcode::ScalarToVector), 869 (Opcode::X86Pmaddubsw), 870 (Opcode::X86Cvtt2dq), 871 (Opcode::Select, &[I8, F32, F32], &[F32]), 872 (Opcode::Select, &[I16, F32, F32], &[F32]), 873 (Opcode::Select, &[I32, F32, F32], &[F32]), 874 (Opcode::Select, &[I64, F32, F32], &[F32]), 875 (Opcode::Select, &[I128, F32, F32], &[F32]), 876 (Opcode::Select, &[I8, F64, F64], &[F64]), 877 (Opcode::Select, &[I16, F64, F64], &[F64]), 878 (Opcode::Select, &[I32, F64, F64], &[F64]), 879 (Opcode::Select, &[I64, F64, F64], &[F64]), 880 (Opcode::Select, &[I128, F64, F64], &[F64]), 881 (Opcode::Select, &[I8, I8X16, I8X16], &[I8X16]), 882 (Opcode::Select, &[I16, I8X16, I8X16], &[I8X16]), 883 (Opcode::Select, &[I32, I8X16, I8X16], &[I8X16]), 884 (Opcode::Select, &[I64, I8X16, I8X16], &[I8X16]), 885 (Opcode::Select, &[I128, I8X16, I8X16], &[I8X16]), 886 (Opcode::Select, &[I8, I16X8, I16X8], &[I16X8]), 887 (Opcode::Select, &[I16, I16X8, I16X8], &[I16X8]), 888 (Opcode::Select, &[I32, I16X8, I16X8], &[I16X8]), 889 (Opcode::Select, &[I64, I16X8, I16X8], &[I16X8]), 890 (Opcode::Select, &[I128, I16X8, I16X8], &[I16X8]), 891 (Opcode::Select, &[I8, I32X4, I32X4], &[I32X4]), 892 (Opcode::Select, &[I16, I32X4, I32X4], &[I32X4]), 893 (Opcode::Select, &[I32, I32X4, I32X4], &[I32X4]), 894 (Opcode::Select, &[I64, I32X4, I32X4], &[I32X4]), 895 (Opcode::Select, &[I128, I32X4, I32X4], &[I32X4]), 896 (Opcode::Select, &[I8, I64X2, I64X2], &[I64X2]), 897 (Opcode::Select, &[I16, I64X2, I64X2], &[I64X2]), 898 (Opcode::Select, &[I32, I64X2, I64X2], &[I64X2]), 899 (Opcode::Select, &[I64, I64X2, I64X2], &[I64X2]), 900 (Opcode::Select, &[I128, I64X2, I64X2], &[I64X2]), 901 (Opcode::Select, &[I8, F32X4, F32X4], &[F32X4]), 902 (Opcode::Select, &[I16, F32X4, F32X4], &[F32X4]), 903 (Opcode::Select, &[I32, F32X4, F32X4], &[F32X4]), 904 (Opcode::Select, &[I64, F32X4, F32X4], &[F32X4]), 905 (Opcode::Select, &[I128, F32X4, F32X4], &[F32X4]), 906 (Opcode::Select, &[I8, F64X2, F64X2], &[F64X2]), 907 (Opcode::Select, &[I16, F64X2, F64X2], &[F64X2]), 908 (Opcode::Select, &[I32, F64X2, F64X2], &[F64X2]), 909 (Opcode::Select, &[I64, F64X2, F64X2], &[F64X2]), 910 (Opcode::Select, &[I128, F64X2, F64X2], &[F64X2]), 911 (Opcode::SelectSpectreGuard, &[I8, F32, F32], &[F32]), 912 (Opcode::SelectSpectreGuard, &[I16, F32, F32], &[F32]), 913 (Opcode::SelectSpectreGuard, &[I32, F32, F32], &[F32]), 914 (Opcode::SelectSpectreGuard, &[I64, F32, F32], &[F32]), 915 (Opcode::SelectSpectreGuard, &[I128, F32, F32], &[F32]), 916 (Opcode::SelectSpectreGuard, &[I8, F64, F64], &[F64]), 917 (Opcode::SelectSpectreGuard, &[I16, F64, F64], &[F64]), 918 (Opcode::SelectSpectreGuard, &[I32, F64, F64], &[F64]), 919 (Opcode::SelectSpectreGuard, &[I64, F64, F64], &[F64]), 920 (Opcode::SelectSpectreGuard, &[I128, F64, F64], &[F64]), 921 (Opcode::SelectSpectreGuard, &[I8, I8X16, I8X16], &[I8X16]), 922 (Opcode::SelectSpectreGuard, &[I16, I8X16, I8X16], &[I8X16]), 923 (Opcode::SelectSpectreGuard, &[I32, I8X16, I8X16], &[I8X16]), 924 (Opcode::SelectSpectreGuard, &[I64, I8X16, I8X16], &[I8X16]), 925 (Opcode::SelectSpectreGuard, &[I128, I8X16, I8X16], &[I8X16]), 926 (Opcode::SelectSpectreGuard, &[I8, I16X8, I16X8], &[I16X8]), 927 (Opcode::SelectSpectreGuard, &[I16, I16X8, I16X8], &[I16X8]), 928 (Opcode::SelectSpectreGuard, &[I32, I16X8, I16X8], &[I16X8]), 929 (Opcode::SelectSpectreGuard, &[I64, I16X8, I16X8], &[I16X8]), 930 (Opcode::SelectSpectreGuard, &[I128, I16X8, I16X8], &[I16X8]), 931 (Opcode::SelectSpectreGuard, &[I8, I32X4, I32X4], &[I32X4]), 932 (Opcode::SelectSpectreGuard, &[I16, I32X4, I32X4], &[I32X4]), 933 (Opcode::SelectSpectreGuard, &[I32, I32X4, I32X4], &[I32X4]), 934 (Opcode::SelectSpectreGuard, &[I64, I32X4, I32X4], &[I32X4]), 935 (Opcode::SelectSpectreGuard, &[I128, I32X4, I32X4], &[I32X4]), 936 (Opcode::SelectSpectreGuard, &[I8, I64X2, I64X2], &[I64X2]), 937 (Opcode::SelectSpectreGuard, &[I16, I64X2, I64X2], &[I64X2]), 938 (Opcode::SelectSpectreGuard, &[I32, I64X2, I64X2], &[I64X2]), 939 (Opcode::SelectSpectreGuard, &[I64, I64X2, I64X2], &[I64X2]), 940 (Opcode::SelectSpectreGuard, &[I128, I64X2, I64X2], &[I64X2]), 941 (Opcode::SelectSpectreGuard, &[I8, F32X4, F32X4], &[F32X4]), 942 (Opcode::SelectSpectreGuard, &[I16, F32X4, F32X4], &[F32X4]), 943 (Opcode::SelectSpectreGuard, &[I32, F32X4, F32X4], &[F32X4]), 944 (Opcode::SelectSpectreGuard, &[I64, F32X4, F32X4], &[F32X4]), 945 (Opcode::SelectSpectreGuard, &[I128, F32X4, F32X4], &[F32X4]), 946 (Opcode::SelectSpectreGuard, &[I8, F64X2, F64X2], &[F64X2]), 947 (Opcode::SelectSpectreGuard, &[I16, F64X2, F64X2], &[F64X2]), 948 (Opcode::SelectSpectreGuard, &[I32, F64X2, F64X2], &[F64X2]), 949 (Opcode::SelectSpectreGuard, &[I64, F64X2, F64X2], &[F64X2]), 950 (Opcode::SelectSpectreGuard, &[I128, F64X2, F64X2], &[F64X2]), 951 (Opcode::Bitselect, &[F32, F32, F32], &[F32]), 952 (Opcode::Bitselect, &[F64, F64, F64], &[F64]), 953 (Opcode::Bitselect, &[F32X4, F32X4, F32X4], &[F32X4]), 954 (Opcode::Bitselect, &[F64X2, F64X2, F64X2], &[F64X2]), 955 (Opcode::VanyTrue, &[F32X4], &[I8]), 956 (Opcode::VanyTrue, &[F64X2], &[I8]), 957 (Opcode::VhighBits, &[F32X4], &[I8]), 958 (Opcode::VhighBits, &[F64X2], &[I8]), 959 (Opcode::VhighBits, &[I8X16], &[I16]), 960 (Opcode::VhighBits, &[I16X8], &[I16]), 961 (Opcode::VhighBits, &[I32X4], &[I16]), 962 (Opcode::VhighBits, &[I64X2], &[I16]), 963 (Opcode::VhighBits, &[F32X4], &[I16]), 964 (Opcode::VhighBits, &[F64X2], &[I16]), 965 (Opcode::VhighBits, &[I8X16], &[I32]), 966 (Opcode::VhighBits, &[I16X8], &[I32]), 967 (Opcode::VhighBits, &[I32X4], &[I32]), 968 (Opcode::VhighBits, &[I64X2], &[I32]), 969 (Opcode::VhighBits, &[F32X4], &[I32]), 970 (Opcode::VhighBits, &[F64X2], &[I32]), 971 (Opcode::VhighBits, &[I8X16], &[I64]), 972 (Opcode::VhighBits, &[I16X8], &[I64]), 973 (Opcode::VhighBits, &[I32X4], &[I64]), 974 (Opcode::VhighBits, &[I64X2], &[I64]), 975 (Opcode::VhighBits, &[F32X4], &[I64]), 976 (Opcode::VhighBits, &[F64X2], &[I64]), 977 (Opcode::VhighBits, &[I8X16], &[I128]), 978 (Opcode::VhighBits, &[I16X8], &[I128]), 979 (Opcode::VhighBits, &[I32X4], &[I128]), 980 (Opcode::VhighBits, &[I64X2], &[I128]), 981 (Opcode::VhighBits, &[F32X4], &[I128]), 982 (Opcode::VhighBits, &[F64X2], &[I128]), 983 (Opcode::VhighBits, &[I8X16], &[I8X16]), 984 (Opcode::VhighBits, &[I16X8], &[I8X16]), 985 (Opcode::VhighBits, &[I32X4], &[I8X16]), 986 (Opcode::VhighBits, &[I64X2], &[I8X16]), 987 (Opcode::VhighBits, &[F32X4], &[I8X16]), 988 (Opcode::VhighBits, &[F64X2], &[I8X16]), 989 (Opcode::VhighBits, &[I8X16], &[I16X8]), 990 (Opcode::VhighBits, &[I16X8], &[I16X8]), 991 (Opcode::VhighBits, &[I32X4], &[I16X8]), 992 (Opcode::VhighBits, &[I64X2], &[I16X8]), 993 (Opcode::VhighBits, &[F32X4], &[I16X8]), 994 (Opcode::VhighBits, &[F64X2], &[I16X8]), 995 (Opcode::VhighBits, &[I8X16], &[I32X4]), 996 (Opcode::VhighBits, &[I16X8], &[I32X4]), 997 (Opcode::VhighBits, &[I32X4], &[I32X4]), 998 (Opcode::VhighBits, &[I64X2], &[I32X4]), 999 (Opcode::VhighBits, &[F32X4], &[I32X4]), 1000 (Opcode::VhighBits, &[F64X2], &[I32X4]), 1001 (Opcode::VhighBits, &[I8X16], &[I64X2]), 1002 (Opcode::VhighBits, &[I16X8], &[I64X2]), 1003 (Opcode::VhighBits, &[I32X4], &[I64X2]), 1004 (Opcode::VhighBits, &[I64X2], &[I64X2]), 1005 (Opcode::VhighBits, &[F32X4], &[I64X2]), 1006 (Opcode::VhighBits, &[F64X2], &[I64X2]), 1007 (Opcode::Ineg, &[I8X16], &[I8X16]), 1008 (Opcode::Ineg, &[I16X8], &[I16X8]), 1009 (Opcode::Ineg, &[I32X4], &[I32X4]), 1010 (Opcode::Ineg, &[I64X2], &[I64X2]), 1011 (Opcode::Umulhi, &[I128, I128], &[I128]), 1012 (Opcode::Smulhi, &[I128, I128], &[I128]), 1013 // https://github.com/bytecodealliance/wasmtime/issues/6073 1014 (Opcode::Iconcat, &[I32, I32], &[I64]), 1015 (Opcode::Iconcat, &[I16, I16], &[I32]), 1016 (Opcode::Iconcat, &[I8, I8], &[I16]), 1017 // https://github.com/bytecodealliance/wasmtime/issues/6073 1018 (Opcode::Isplit, &[I64], &[I32, I32]), 1019 (Opcode::Isplit, &[I32], &[I16, I16]), 1020 (Opcode::Isplit, &[I16], &[I8, I8]), 1021 (Opcode::Rotl, &[I8X16, I8], &[I8X16]), 1022 (Opcode::Rotl, &[I8X16, I16], &[I8X16]), 1023 (Opcode::Rotl, &[I8X16, I32], &[I8X16]), 1024 (Opcode::Rotl, &[I8X16, I64], &[I8X16]), 1025 (Opcode::Rotl, &[I8X16, I128], &[I8X16]), 1026 (Opcode::Rotl, &[I16X8, I8], &[I16X8]), 1027 (Opcode::Rotl, &[I16X8, I16], &[I16X8]), 1028 (Opcode::Rotl, &[I16X8, I32], &[I16X8]), 1029 (Opcode::Rotl, &[I16X8, I64], &[I16X8]), 1030 (Opcode::Rotl, &[I16X8, I128], &[I16X8]), 1031 (Opcode::Rotl, &[I32X4, I8], &[I32X4]), 1032 (Opcode::Rotl, &[I32X4, I16], &[I32X4]), 1033 (Opcode::Rotl, &[I32X4, I32], &[I32X4]), 1034 (Opcode::Rotl, &[I32X4, I64], &[I32X4]), 1035 (Opcode::Rotl, &[I32X4, I128], &[I32X4]), 1036 (Opcode::Rotl, &[I64X2, I8], &[I64X2]), 1037 (Opcode::Rotl, &[I64X2, I16], &[I64X2]), 1038 (Opcode::Rotl, &[I64X2, I32], &[I64X2]), 1039 (Opcode::Rotl, &[I64X2, I64], &[I64X2]), 1040 (Opcode::Rotl, &[I64X2, I128], &[I64X2]), 1041 (Opcode::Rotr, &[I8X16, I8], &[I8X16]), 1042 (Opcode::Rotr, &[I8X16, I16], &[I8X16]), 1043 (Opcode::Rotr, &[I8X16, I32], &[I8X16]), 1044 (Opcode::Rotr, &[I8X16, I64], &[I8X16]), 1045 (Opcode::Rotr, &[I8X16, I128], &[I8X16]), 1046 (Opcode::Rotr, &[I16X8, I8], &[I16X8]), 1047 (Opcode::Rotr, &[I16X8, I16], &[I16X8]), 1048 (Opcode::Rotr, &[I16X8, I32], &[I16X8]), 1049 (Opcode::Rotr, &[I16X8, I64], &[I16X8]), 1050 (Opcode::Rotr, &[I16X8, I128], &[I16X8]), 1051 (Opcode::Rotr, &[I32X4, I8], &[I32X4]), 1052 (Opcode::Rotr, &[I32X4, I16], &[I32X4]), 1053 (Opcode::Rotr, &[I32X4, I32], &[I32X4]), 1054 (Opcode::Rotr, &[I32X4, I64], &[I32X4]), 1055 (Opcode::Rotr, &[I32X4, I128], &[I32X4]), 1056 (Opcode::Rotr, &[I64X2, I8], &[I64X2]), 1057 (Opcode::Rotr, &[I64X2, I16], &[I64X2]), 1058 (Opcode::Rotr, &[I64X2, I32], &[I64X2]), 1059 (Opcode::Rotr, &[I64X2, I64], &[I64X2]), 1060 (Opcode::Rotr, &[I64X2, I128], &[I64X2]), 1061 (Opcode::Ishl, &[I8X16, I8], &[I8X16]), 1062 (Opcode::Ishl, &[I8X16, I16], &[I8X16]), 1063 (Opcode::Ishl, &[I8X16, I32], &[I8X16]), 1064 (Opcode::Ishl, &[I8X16, I64], &[I8X16]), 1065 (Opcode::Ishl, &[I8X16, I128], &[I8X16]), 1066 (Opcode::Ishl, &[I16X8, I8], &[I16X8]), 1067 (Opcode::Ishl, &[I16X8, I16], &[I16X8]), 1068 (Opcode::Ishl, &[I16X8, I32], &[I16X8]), 1069 (Opcode::Ishl, &[I16X8, I64], &[I16X8]), 1070 (Opcode::Ishl, &[I16X8, I128], &[I16X8]), 1071 (Opcode::Ishl, &[I32X4, I8], &[I32X4]), 1072 (Opcode::Ishl, &[I32X4, I16], &[I32X4]), 1073 (Opcode::Ishl, &[I32X4, I32], &[I32X4]), 1074 (Opcode::Ishl, &[I32X4, I64], &[I32X4]), 1075 (Opcode::Ishl, &[I32X4, I128], &[I32X4]), 1076 (Opcode::Ishl, &[I64X2, I8], &[I64X2]), 1077 (Opcode::Ishl, &[I64X2, I16], &[I64X2]), 1078 (Opcode::Ishl, &[I64X2, I32], &[I64X2]), 1079 (Opcode::Ishl, &[I64X2, I64], &[I64X2]), 1080 (Opcode::Ishl, &[I64X2, I128], &[I64X2]), 1081 (Opcode::Ushr, &[I8X16, I8], &[I8X16]), 1082 (Opcode::Ushr, &[I8X16, I16], &[I8X16]), 1083 (Opcode::Ushr, &[I8X16, I32], &[I8X16]), 1084 (Opcode::Ushr, &[I8X16, I64], &[I8X16]), 1085 (Opcode::Ushr, &[I8X16, I128], &[I8X16]), 1086 (Opcode::Ushr, &[I16X8, I8], &[I16X8]), 1087 (Opcode::Ushr, &[I16X8, I16], &[I16X8]), 1088 (Opcode::Ushr, &[I16X8, I32], &[I16X8]), 1089 (Opcode::Ushr, &[I16X8, I64], &[I16X8]), 1090 (Opcode::Ushr, &[I16X8, I128], &[I16X8]), 1091 (Opcode::Ushr, &[I32X4, I8], &[I32X4]), 1092 (Opcode::Ushr, &[I32X4, I16], &[I32X4]), 1093 (Opcode::Ushr, &[I32X4, I32], &[I32X4]), 1094 (Opcode::Ushr, &[I32X4, I64], &[I32X4]), 1095 (Opcode::Ushr, &[I32X4, I128], &[I32X4]), 1096 (Opcode::Ushr, &[I64X2, I8], &[I64X2]), 1097 (Opcode::Ushr, &[I64X2, I16], &[I64X2]), 1098 (Opcode::Ushr, &[I64X2, I32], &[I64X2]), 1099 (Opcode::Ushr, &[I64X2, I64], &[I64X2]), 1100 (Opcode::Ushr, &[I64X2, I128], &[I64X2]), 1101 (Opcode::Sshr, &[I8X16, I8], &[I8X16]), 1102 (Opcode::Sshr, &[I8X16, I16], &[I8X16]), 1103 (Opcode::Sshr, &[I8X16, I32], &[I8X16]), 1104 (Opcode::Sshr, &[I8X16, I64], &[I8X16]), 1105 (Opcode::Sshr, &[I8X16, I128], &[I8X16]), 1106 (Opcode::Sshr, &[I16X8, I8], &[I16X8]), 1107 (Opcode::Sshr, &[I16X8, I16], &[I16X8]), 1108 (Opcode::Sshr, &[I16X8, I32], &[I16X8]), 1109 (Opcode::Sshr, &[I16X8, I64], &[I16X8]), 1110 (Opcode::Sshr, &[I16X8, I128], &[I16X8]), 1111 (Opcode::Sshr, &[I32X4, I8], &[I32X4]), 1112 (Opcode::Sshr, &[I32X4, I16], &[I32X4]), 1113 (Opcode::Sshr, &[I32X4, I32], &[I32X4]), 1114 (Opcode::Sshr, &[I32X4, I64], &[I32X4]), 1115 (Opcode::Sshr, &[I32X4, I128], &[I32X4]), 1116 (Opcode::Sshr, &[I64X2, I8], &[I64X2]), 1117 (Opcode::Sshr, &[I64X2, I16], &[I64X2]), 1118 (Opcode::Sshr, &[I64X2, I32], &[I64X2]), 1119 (Opcode::Sshr, &[I64X2, I64], &[I64X2]), 1120 (Opcode::Sshr, &[I64X2, I128], &[I64X2]), 1121 (Opcode::Fmin, &[F32X4, F32X4], &[F32X4]), 1122 (Opcode::Fmin, &[F64X2, F64X2], &[F64X2]), 1123 (Opcode::FminPseudo, &[F32X4, F32X4], &[F32X4]), 1124 (Opcode::FminPseudo, &[F64X2, F64X2], &[F64X2]), 1125 (Opcode::Fmax, &[F32X4, F32X4], &[F32X4]), 1126 (Opcode::Fmax, &[F64X2, F64X2], &[F64X2]), 1127 (Opcode::FmaxPseudo, &[F32X4, F32X4], &[F32X4]), 1128 (Opcode::FmaxPseudo, &[F64X2, F64X2], &[F64X2]), 1129 (Opcode::Bitcast, &[I8], &[I8]), 1130 (Opcode::Bitcast, &[I16], &[I8]), 1131 (Opcode::Bitcast, &[I32], &[I8]), 1132 (Opcode::Bitcast, &[I64], &[I8]), 1133 (Opcode::Bitcast, &[I128], &[I8]), 1134 (Opcode::Bitcast, &[F32], &[I8]), 1135 (Opcode::Bitcast, &[F64], &[I8]), 1136 (Opcode::Bitcast, &[I8X16], &[I8]), 1137 (Opcode::Bitcast, &[I16X8], &[I8]), 1138 (Opcode::Bitcast, &[I32X4], &[I8]), 1139 (Opcode::Bitcast, &[I64X2], &[I8]), 1140 (Opcode::Bitcast, &[F32X4], &[I8]), 1141 (Opcode::Bitcast, &[F64X2], &[I8]), 1142 (Opcode::Bitcast, &[I8], &[I16]), 1143 (Opcode::Bitcast, &[I16], &[I16]), 1144 (Opcode::Bitcast, &[I32], &[I16]), 1145 (Opcode::Bitcast, &[I64], &[I16]), 1146 (Opcode::Bitcast, &[I128], &[I16]), 1147 (Opcode::Bitcast, &[F32], &[I16]), 1148 (Opcode::Bitcast, &[F64], &[I16]), 1149 (Opcode::Bitcast, &[I8X16], &[I16]), 1150 (Opcode::Bitcast, &[I16X8], &[I16]), 1151 (Opcode::Bitcast, &[I32X4], &[I16]), 1152 (Opcode::Bitcast, &[I64X2], &[I16]), 1153 (Opcode::Bitcast, &[F32X4], &[I16]), 1154 (Opcode::Bitcast, &[F64X2], &[I16]), 1155 (Opcode::Bitcast, &[I8], &[I32]), 1156 (Opcode::Bitcast, &[I16], &[I32]), 1157 (Opcode::Bitcast, &[I32], &[I32]), 1158 (Opcode::Bitcast, &[I64], &[I32]), 1159 (Opcode::Bitcast, &[I128], &[I32]), 1160 (Opcode::Bitcast, &[F64], &[I32]), 1161 (Opcode::Bitcast, &[I8X16], &[I32]), 1162 (Opcode::Bitcast, &[I16X8], &[I32]), 1163 (Opcode::Bitcast, &[I32X4], &[I32]), 1164 (Opcode::Bitcast, &[I64X2], &[I32]), 1165 (Opcode::Bitcast, &[F32X4], &[I32]), 1166 (Opcode::Bitcast, &[F64X2], &[I32]), 1167 (Opcode::Bitcast, &[I8], &[I64]), 1168 (Opcode::Bitcast, &[I16], &[I64]), 1169 (Opcode::Bitcast, &[I32], &[I64]), 1170 (Opcode::Bitcast, &[I64], &[I64]), 1171 (Opcode::Bitcast, &[I128], &[I64]), 1172 (Opcode::Bitcast, &[F32], &[I64]), 1173 (Opcode::Bitcast, &[I8X16], &[I64]), 1174 (Opcode::Bitcast, &[I16X8], &[I64]), 1175 (Opcode::Bitcast, &[I32X4], &[I64]), 1176 (Opcode::Bitcast, &[I64X2], &[I64]), 1177 (Opcode::Bitcast, &[F32X4], &[I64]), 1178 (Opcode::Bitcast, &[F64X2], &[I64]), 1179 (Opcode::Bitcast, &[I8], &[I128]), 1180 (Opcode::Bitcast, &[I16], &[I128]), 1181 (Opcode::Bitcast, &[I32], &[I128]), 1182 (Opcode::Bitcast, &[I64], &[I128]), 1183 (Opcode::Bitcast, &[I128], &[I128]), 1184 (Opcode::Bitcast, &[F32], &[I128]), 1185 (Opcode::Bitcast, &[F64], &[I128]), 1186 (Opcode::Bitcast, &[I8X16], &[I128]), 1187 (Opcode::Bitcast, &[I16X8], &[I128]), 1188 (Opcode::Bitcast, &[I32X4], &[I128]), 1189 (Opcode::Bitcast, &[I64X2], &[I128]), 1190 (Opcode::Bitcast, &[F32X4], &[I128]), 1191 (Opcode::Bitcast, &[F64X2], &[I128]), 1192 (Opcode::Bitcast, &[I8], &[F32]), 1193 (Opcode::Bitcast, &[I16], &[F32]), 1194 (Opcode::Bitcast, &[I64], &[F32]), 1195 (Opcode::Bitcast, &[I128], &[F32]), 1196 (Opcode::Bitcast, &[F32], &[F32]), 1197 (Opcode::Bitcast, &[F64], &[F32]), 1198 (Opcode::Bitcast, &[I8X16], &[F32]), 1199 (Opcode::Bitcast, &[I16X8], &[F32]), 1200 (Opcode::Bitcast, &[I32X4], &[F32]), 1201 (Opcode::Bitcast, &[I64X2], &[F32]), 1202 (Opcode::Bitcast, &[F32X4], &[F32]), 1203 (Opcode::Bitcast, &[F64X2], &[F32]), 1204 (Opcode::Bitcast, &[I8], &[F64]), 1205 (Opcode::Bitcast, &[I16], &[F64]), 1206 (Opcode::Bitcast, &[I32], &[F64]), 1207 (Opcode::Bitcast, &[I128], &[F64]), 1208 (Opcode::Bitcast, &[F32], &[F64]), 1209 (Opcode::Bitcast, &[F64], &[F64]), 1210 (Opcode::Bitcast, &[I8X16], &[F64]), 1211 (Opcode::Bitcast, &[I16X8], &[F64]), 1212 (Opcode::Bitcast, &[I32X4], &[F64]), 1213 (Opcode::Bitcast, &[I64X2], &[F64]), 1214 (Opcode::Bitcast, &[F32X4], &[F64]), 1215 (Opcode::Bitcast, &[F64X2], &[F64]), 1216 (Opcode::Bitcast, &[I8], &[I8X16]), 1217 (Opcode::Bitcast, &[I16], &[I8X16]), 1218 (Opcode::Bitcast, &[I32], &[I8X16]), 1219 (Opcode::Bitcast, &[I64], &[I8X16]), 1220 (Opcode::Bitcast, &[I128], &[I8X16]), 1221 (Opcode::Bitcast, &[F32], &[I8X16]), 1222 (Opcode::Bitcast, &[F64], &[I8X16]), 1223 (Opcode::Bitcast, &[I8X16], &[I8X16]), 1224 (Opcode::Bitcast, &[I16X8], &[I8X16]), 1225 (Opcode::Bitcast, &[I32X4], &[I8X16]), 1226 (Opcode::Bitcast, &[I64X2], &[I8X16]), 1227 (Opcode::Bitcast, &[F32X4], &[I8X16]), 1228 (Opcode::Bitcast, &[F64X2], &[I8X16]), 1229 (Opcode::Bitcast, &[I8], &[I16X8]), 1230 (Opcode::Bitcast, &[I16], &[I16X8]), 1231 (Opcode::Bitcast, &[I32], &[I16X8]), 1232 (Opcode::Bitcast, &[I64], &[I16X8]), 1233 (Opcode::Bitcast, &[I128], &[I16X8]), 1234 (Opcode::Bitcast, &[F32], &[I16X8]), 1235 (Opcode::Bitcast, &[F64], &[I16X8]), 1236 (Opcode::Bitcast, &[I8X16], &[I16X8]), 1237 (Opcode::Bitcast, &[I16X8], &[I16X8]), 1238 (Opcode::Bitcast, &[I32X4], &[I16X8]), 1239 (Opcode::Bitcast, &[I64X2], &[I16X8]), 1240 (Opcode::Bitcast, &[F32X4], &[I16X8]), 1241 (Opcode::Bitcast, &[F64X2], &[I16X8]), 1242 (Opcode::Bitcast, &[I8], &[I32X4]), 1243 (Opcode::Bitcast, &[I16], &[I32X4]), 1244 (Opcode::Bitcast, &[I32], &[I32X4]), 1245 (Opcode::Bitcast, &[I64], &[I32X4]), 1246 (Opcode::Bitcast, &[I128], &[I32X4]), 1247 (Opcode::Bitcast, &[F32], &[I32X4]), 1248 (Opcode::Bitcast, &[F64], &[I32X4]), 1249 (Opcode::Bitcast, &[I8X16], &[I32X4]), 1250 (Opcode::Bitcast, &[I16X8], &[I32X4]), 1251 (Opcode::Bitcast, &[I32X4], &[I32X4]), 1252 (Opcode::Bitcast, &[I64X2], &[I32X4]), 1253 (Opcode::Bitcast, &[F32X4], &[I32X4]), 1254 (Opcode::Bitcast, &[F64X2], &[I32X4]), 1255 (Opcode::Bitcast, &[I8], &[I64X2]), 1256 (Opcode::Bitcast, &[I16], &[I64X2]), 1257 (Opcode::Bitcast, &[I32], &[I64X2]), 1258 (Opcode::Bitcast, &[I64], &[I64X2]), 1259 (Opcode::Bitcast, &[I128], &[I64X2]), 1260 (Opcode::Bitcast, &[F32], &[I64X2]), 1261 (Opcode::Bitcast, &[F64], &[I64X2]), 1262 (Opcode::Bitcast, &[I8X16], &[I64X2]), 1263 (Opcode::Bitcast, &[I16X8], &[I64X2]), 1264 (Opcode::Bitcast, &[I32X4], &[I64X2]), 1265 (Opcode::Bitcast, &[I64X2], &[I64X2]), 1266 (Opcode::Bitcast, &[F32X4], &[I64X2]), 1267 (Opcode::Bitcast, &[F64X2], &[I64X2]), 1268 (Opcode::Bitcast, &[I8], &[F32X4]), 1269 (Opcode::Bitcast, &[I16], &[F32X4]), 1270 (Opcode::Bitcast, &[I32], &[F32X4]), 1271 (Opcode::Bitcast, &[I64], &[F32X4]), 1272 (Opcode::Bitcast, &[I128], &[F32X4]), 1273 (Opcode::Bitcast, &[F32], &[F32X4]), 1274 (Opcode::Bitcast, &[F64], &[F32X4]), 1275 (Opcode::Bitcast, &[I8X16], &[F32X4]), 1276 (Opcode::Bitcast, &[I16X8], &[F32X4]), 1277 (Opcode::Bitcast, &[I32X4], &[F32X4]), 1278 (Opcode::Bitcast, &[I64X2], &[F32X4]), 1279 (Opcode::Bitcast, &[F32X4], &[F32X4]), 1280 (Opcode::Bitcast, &[F64X2], &[F32X4]), 1281 (Opcode::Bitcast, &[I8], &[F64X2]), 1282 (Opcode::Bitcast, &[I16], &[F64X2]), 1283 (Opcode::Bitcast, &[I32], &[F64X2]), 1284 (Opcode::Bitcast, &[I64], &[F64X2]), 1285 (Opcode::Bitcast, &[I128], &[F64X2]), 1286 (Opcode::Bitcast, &[F32], &[F64X2]), 1287 (Opcode::Bitcast, &[F64], &[F64X2]), 1288 (Opcode::Bitcast, &[I8X16], &[F64X2]), 1289 (Opcode::Bitcast, &[I16X8], &[F64X2]), 1290 (Opcode::Bitcast, &[I32X4], &[F64X2]), 1291 (Opcode::Bitcast, &[I64X2], &[F64X2]), 1292 (Opcode::Bitcast, &[F32X4], &[F64X2]), 1293 (Opcode::Bitcast, &[F64X2], &[F64X2]), 1294 (Opcode::FcvtToUintSat, &[F32X4], &[I8]), 1295 (Opcode::FcvtToUintSat, &[F64X2], &[I8]), 1296 (Opcode::FcvtToUintSat, &[F32X4], &[I16]), 1297 (Opcode::FcvtToUintSat, &[F64X2], &[I16]), 1298 (Opcode::FcvtToUintSat, &[F32X4], &[I32]), 1299 (Opcode::FcvtToUintSat, &[F64X2], &[I32]), 1300 (Opcode::FcvtToUintSat, &[F32X4], &[I64]), 1301 (Opcode::FcvtToUintSat, &[F64X2], &[I64]), 1302 (Opcode::FcvtToUintSat, &[F32X4], &[I128]), 1303 (Opcode::FcvtToUintSat, &[F64X2], &[I128]), 1304 (Opcode::FcvtToUintSat, &[F32], &[I8X16]), 1305 (Opcode::FcvtToUintSat, &[F64], &[I8X16]), 1306 (Opcode::FcvtToUintSat, &[F32X4], &[I8X16]), 1307 (Opcode::FcvtToUintSat, &[F64X2], &[I8X16]), 1308 (Opcode::FcvtToUintSat, &[F32], &[I16X8]), 1309 (Opcode::FcvtToUintSat, &[F64], &[I16X8]), 1310 (Opcode::FcvtToUintSat, &[F32X4], &[I16X8]), 1311 (Opcode::FcvtToUintSat, &[F64X2], &[I16X8]), 1312 (Opcode::FcvtToUintSat, &[F32], &[I32X4]), 1313 (Opcode::FcvtToUintSat, &[F64], &[I32X4]), 1314 (Opcode::FcvtToUintSat, &[F64X2], &[I32X4]), 1315 (Opcode::FcvtToUintSat, &[F32], &[I64X2]), 1316 (Opcode::FcvtToUintSat, &[F64], &[I64X2]), 1317 (Opcode::FcvtToUintSat, &[F32X4], &[I64X2]), 1318 (Opcode::FcvtToSintSat, &[F32X4], &[I8]), 1319 (Opcode::FcvtToSintSat, &[F64X2], &[I8]), 1320 (Opcode::FcvtToSintSat, &[F32X4], &[I16]), 1321 (Opcode::FcvtToSintSat, &[F64X2], &[I16]), 1322 (Opcode::FcvtToSintSat, &[F32X4], &[I32]), 1323 (Opcode::FcvtToSintSat, &[F64X2], &[I32]), 1324 (Opcode::FcvtToSintSat, &[F32X4], &[I64]), 1325 (Opcode::FcvtToSintSat, &[F64X2], &[I64]), 1326 (Opcode::FcvtToSintSat, &[F32X4], &[I128]), 1327 (Opcode::FcvtToSintSat, &[F64X2], &[I128]), 1328 (Opcode::FcvtToSintSat, &[F32], &[I8X16]), 1329 (Opcode::FcvtToSintSat, &[F64], &[I8X16]), 1330 (Opcode::FcvtToSintSat, &[F32X4], &[I8X16]), 1331 (Opcode::FcvtToSintSat, &[F64X2], &[I8X16]), 1332 (Opcode::FcvtToSintSat, &[F32], &[I16X8]), 1333 (Opcode::FcvtToSintSat, &[F64], &[I16X8]), 1334 (Opcode::FcvtToSintSat, &[F32X4], &[I16X8]), 1335 (Opcode::FcvtToSintSat, &[F64X2], &[I16X8]), 1336 (Opcode::FcvtToSintSat, &[F32], &[I32X4]), 1337 (Opcode::FcvtToSintSat, &[F64], &[I32X4]), 1338 (Opcode::FcvtToSintSat, &[F64X2], &[I32X4]), 1339 (Opcode::FcvtToSintSat, &[F32], &[I64X2]), 1340 (Opcode::FcvtToSintSat, &[F64], &[I64X2]), 1341 (Opcode::FcvtToSintSat, &[F32X4], &[I64X2]), 1342 (Opcode::FcvtFromUint, &[I8X16], &[F32]), 1343 (Opcode::FcvtFromUint, &[I16X8], &[F32]), 1344 (Opcode::FcvtFromUint, &[I32X4], &[F32]), 1345 (Opcode::FcvtFromUint, &[I64X2], &[F32]), 1346 (Opcode::FcvtFromUint, &[I8X16], &[F64]), 1347 (Opcode::FcvtFromUint, &[I16X8], &[F64]), 1348 (Opcode::FcvtFromUint, &[I32X4], &[F64]), 1349 (Opcode::FcvtFromUint, &[I64X2], &[F64]), 1350 (Opcode::FcvtFromUint, &[I8], &[F32X4]), 1351 (Opcode::FcvtFromUint, &[I16], &[F32X4]), 1352 (Opcode::FcvtFromUint, &[I32], &[F32X4]), 1353 (Opcode::FcvtFromUint, &[I64], &[F32X4]), 1354 (Opcode::FcvtFromUint, &[I128], &[F32X4]), 1355 (Opcode::FcvtFromUint, &[I8X16], &[F32X4]), 1356 (Opcode::FcvtFromUint, &[I16X8], &[F32X4]), 1357 (Opcode::FcvtFromUint, &[I64X2], &[F32X4]), 1358 (Opcode::FcvtFromUint, &[I8], &[F64X2]), 1359 (Opcode::FcvtFromUint, &[I16], &[F64X2]), 1360 (Opcode::FcvtFromUint, &[I32], &[F64X2]), 1361 (Opcode::FcvtFromUint, &[I64], &[F64X2]), 1362 (Opcode::FcvtFromUint, &[I128], &[F64X2]), 1363 (Opcode::FcvtFromUint, &[I8X16], &[F64X2]), 1364 (Opcode::FcvtFromUint, &[I16X8], &[F64X2]), 1365 (Opcode::FcvtFromUint, &[I32X4], &[F64X2]), 1366 (Opcode::FcvtFromSint, &[I8X16], &[F32]), 1367 (Opcode::FcvtFromSint, &[I16X8], &[F32]), 1368 (Opcode::FcvtFromSint, &[I32X4], &[F32]), 1369 (Opcode::FcvtFromSint, &[I64X2], &[F32]), 1370 (Opcode::FcvtFromSint, &[I8X16], &[F64]), 1371 (Opcode::FcvtFromSint, &[I16X8], &[F64]), 1372 (Opcode::FcvtFromSint, &[I32X4], &[F64]), 1373 (Opcode::FcvtFromSint, &[I64X2], &[F64]), 1374 (Opcode::FcvtFromSint, &[I8], &[F32X4]), 1375 (Opcode::FcvtFromSint, &[I16], &[F32X4]), 1376 (Opcode::FcvtFromSint, &[I32], &[F32X4]), 1377 (Opcode::FcvtFromSint, &[I64], &[F32X4]), 1378 (Opcode::FcvtFromSint, &[I128], &[F32X4]), 1379 (Opcode::FcvtFromSint, &[I8X16], &[F32X4]), 1380 (Opcode::FcvtFromSint, &[I16X8], &[F32X4]), 1381 (Opcode::FcvtFromSint, &[I64X2], &[F32X4]), 1382 (Opcode::FcvtFromSint, &[I8], &[F64X2]), 1383 (Opcode::FcvtFromSint, &[I16], &[F64X2]), 1384 (Opcode::FcvtFromSint, &[I32], &[F64X2]), 1385 (Opcode::FcvtFromSint, &[I64], &[F64X2]), 1386 (Opcode::FcvtFromSint, &[I128], &[F64X2]), 1387 (Opcode::FcvtFromSint, &[I8X16], &[F64X2]), 1388 (Opcode::FcvtFromSint, &[I16X8], &[F64X2]), 1389 (Opcode::FcvtFromSint, &[I32X4], &[F64X2]), 1390 (Opcode::FcvtLowFromSint, &[I8], &[F32]), 1391 (Opcode::FcvtLowFromSint, &[I16], &[F32]), 1392 (Opcode::FcvtLowFromSint, &[I32], &[F32]), 1393 (Opcode::FcvtLowFromSint, &[I64], &[F32]), 1394 (Opcode::FcvtLowFromSint, &[I128], &[F32]), 1395 (Opcode::FcvtLowFromSint, &[I8X16], &[F32]), 1396 (Opcode::FcvtLowFromSint, &[I16X8], &[F32]), 1397 (Opcode::FcvtLowFromSint, &[I32X4], &[F32]), 1398 (Opcode::FcvtLowFromSint, &[I64X2], &[F32]), 1399 (Opcode::FcvtLowFromSint, &[I8], &[F64]), 1400 (Opcode::FcvtLowFromSint, &[I16], &[F64]), 1401 (Opcode::FcvtLowFromSint, &[I32], &[F64]), 1402 (Opcode::FcvtLowFromSint, &[I64], &[F64]), 1403 (Opcode::FcvtLowFromSint, &[I128], &[F64]), 1404 (Opcode::FcvtLowFromSint, &[I8X16], &[F64]), 1405 (Opcode::FcvtLowFromSint, &[I16X8], &[F64]), 1406 (Opcode::FcvtLowFromSint, &[I32X4], &[F64]), 1407 (Opcode::FcvtLowFromSint, &[I64X2], &[F64]), 1408 (Opcode::FcvtLowFromSint, &[I8], &[F32X4]), 1409 (Opcode::FcvtLowFromSint, &[I16], &[F32X4]), 1410 (Opcode::FcvtLowFromSint, &[I32], &[F32X4]), 1411 (Opcode::FcvtLowFromSint, &[I64], &[F32X4]), 1412 (Opcode::FcvtLowFromSint, &[I128], &[F32X4]), 1413 (Opcode::FcvtLowFromSint, &[I8X16], &[F32X4]), 1414 (Opcode::FcvtLowFromSint, &[I16X8], &[F32X4]), 1415 (Opcode::FcvtLowFromSint, &[I32X4], &[F32X4]), 1416 (Opcode::FcvtLowFromSint, &[I64X2], &[F32X4]), 1417 (Opcode::FcvtLowFromSint, &[I8], &[F64X2]), 1418 (Opcode::FcvtLowFromSint, &[I16], &[F64X2]), 1419 (Opcode::FcvtLowFromSint, &[I32], &[F64X2]), 1420 (Opcode::FcvtLowFromSint, &[I64], &[F64X2]), 1421 (Opcode::FcvtLowFromSint, &[I128], &[F64X2]), 1422 (Opcode::FcvtLowFromSint, &[I8X16], &[F64X2]), 1423 (Opcode::FcvtLowFromSint, &[I16X8], &[F64X2]), 1424 (Opcode::FcvtLowFromSint, &[I64X2], &[F64X2]), 1425 ) 1426 }) 1427 .collect() 1428 }); 1429 1430 fn inserter_for_format(fmt: InstructionFormat) -> OpcodeInserter { 1431 match fmt { 1432 InstructionFormat::AtomicCas => insert_atomic_cas, 1433 InstructionFormat::AtomicRmw => insert_atomic_rmw, 1434 InstructionFormat::Binary => insert_opcode, 1435 InstructionFormat::BinaryImm64 => todo!(), 1436 InstructionFormat::BinaryImm8 => insert_ins_ext_lane, 1437 InstructionFormat::Call => insert_call, 1438 InstructionFormat::CallIndirect => insert_call, 1439 InstructionFormat::CondTrap => todo!(), 1440 InstructionFormat::DynamicStackLoad => todo!(), 1441 InstructionFormat::DynamicStackStore => todo!(), 1442 InstructionFormat::FloatCompare => insert_cmp, 1443 InstructionFormat::FuncAddr => todo!(), 1444 InstructionFormat::IntAddTrap => todo!(), 1445 InstructionFormat::IntCompare => insert_cmp, 1446 InstructionFormat::IntCompareImm => todo!(), 1447 InstructionFormat::Load => insert_load_store, 1448 InstructionFormat::LoadNoOffset => insert_load_store, 1449 InstructionFormat::NullAry => insert_opcode, 1450 InstructionFormat::Shuffle => insert_shuffle, 1451 InstructionFormat::StackLoad => insert_stack_load, 1452 InstructionFormat::StackStore => insert_stack_store, 1453 InstructionFormat::Store => insert_load_store, 1454 InstructionFormat::StoreNoOffset => insert_load_store, 1455 InstructionFormat::TableAddr => todo!(), 1456 InstructionFormat::Ternary => insert_opcode, 1457 InstructionFormat::TernaryImm8 => insert_ins_ext_lane, 1458 InstructionFormat::Trap => todo!(), 1459 InstructionFormat::Unary => insert_opcode, 1460 InstructionFormat::UnaryConst => insert_const, 1461 InstructionFormat::UnaryGlobalValue => todo!(), 1462 InstructionFormat::UnaryIeee32 => insert_const, 1463 InstructionFormat::UnaryIeee64 => insert_const, 1464 InstructionFormat::UnaryImm => insert_const, 1465 1466 InstructionFormat::BranchTable 1467 | InstructionFormat::Brif 1468 | InstructionFormat::Jump 1469 | InstructionFormat::MultiAry => { 1470 panic!( 1471 "Control-flow instructions should be handled by 'insert_terminator': {:?}", 1472 fmt 1473 ) 1474 } 1475 } 1476 } 1477 1478 pub struct FunctionGenerator<'r, 'data> 1479 where 1480 'data: 'r, 1481 { 1482 u: &'r mut Unstructured<'data>, 1483 config: &'r Config, 1484 resources: Resources, 1485 target_triple: Triple, 1486 name: UserFuncName, 1487 signature: Signature, 1488 } 1489 1490 #[derive(Debug, Clone)] 1491 enum BlockTerminator { 1492 Return, 1493 Jump(Block), 1494 Br(Block, Block), 1495 BrTable(Block, Vec<Block>), 1496 Switch(Type, Block, HashMap<u128, Block>), 1497 } 1498 1499 #[derive(Debug, Clone)] 1500 enum BlockTerminatorKind { 1501 Return, 1502 Jump, 1503 Br, 1504 BrTable, 1505 Switch, 1506 } 1507 1508 #[derive(Default)] 1509 struct Resources { 1510 vars: HashMap<Type, Vec<Variable>>, 1511 blocks: Vec<(Block, BlockSignature)>, 1512 blocks_without_params: Vec<Block>, 1513 block_terminators: Vec<BlockTerminator>, 1514 func_refs: Vec<(Signature, SigRef, FuncRef)>, 1515 stack_slots: Vec<(StackSlot, StackSize)>, 1516 usercalls: Vec<(UserExternalName, Signature)>, 1517 libcalls: Vec<LibCall>, 1518 } 1519 1520 impl Resources { 1521 /// Partitions blocks at `block`. Only blocks that can be targeted by branches are considered. 1522 /// 1523 /// The first slice includes all blocks up to and including `block`. 1524 /// The second slice includes all remaining blocks. 1525 fn partition_target_blocks( 1526 &self, 1527 block: Block, 1528 ) -> (&[(Block, BlockSignature)], &[(Block, BlockSignature)]) { 1529 // Blocks are stored in-order and have no gaps, this means that we can simply index them by 1530 // their number. We also need to exclude the entry block since it isn't a valid target. 1531 let target_blocks = &self.blocks[1..]; 1532 target_blocks.split_at(block.as_u32() as usize) 1533 } 1534 1535 /// Returns blocks forward of `block`. Only blocks that can be targeted by branches are considered. 1536 fn forward_blocks(&self, block: Block) -> &[(Block, BlockSignature)] { 1537 let (_, forward_blocks) = self.partition_target_blocks(block); 1538 forward_blocks 1539 } 1540 1541 /// Generates a slice of `blocks_without_params` ahead of `block` 1542 fn forward_blocks_without_params(&self, block: Block) -> &[Block] { 1543 let partition_point = self.blocks_without_params.partition_point(|b| *b <= block); 1544 &self.blocks_without_params[partition_point..] 1545 } 1546 } 1547 1548 impl<'r, 'data> FunctionGenerator<'r, 'data> 1549 where 1550 'data: 'r, 1551 { 1552 pub fn new( 1553 u: &'r mut Unstructured<'data>, 1554 config: &'r Config, 1555 target_triple: Triple, 1556 name: UserFuncName, 1557 signature: Signature, 1558 usercalls: Vec<(UserExternalName, Signature)>, 1559 libcalls: Vec<LibCall>, 1560 ) -> Self { 1561 Self { 1562 u, 1563 config, 1564 resources: Resources { 1565 usercalls, 1566 libcalls, 1567 ..Resources::default() 1568 }, 1569 target_triple, 1570 name, 1571 signature, 1572 } 1573 } 1574 1575 /// Generates a random value for config `param` 1576 fn param(&mut self, param: &RangeInclusive<usize>) -> Result<usize> { 1577 Ok(self.u.int_in_range(param.clone())?) 1578 } 1579 1580 fn system_callconv(&mut self) -> CallConv { 1581 // TODO: This currently only runs on linux, so this is the only choice 1582 // We should improve this once we generate flags and targets 1583 CallConv::SystemV 1584 } 1585 1586 /// Finds a stack slot with size of at least n bytes 1587 fn stack_slot_with_size(&mut self, n: u32) -> Result<(StackSlot, StackSize)> { 1588 let first = self 1589 .resources 1590 .stack_slots 1591 .partition_point(|&(_slot, size)| size < n); 1592 Ok(*self.u.choose(&self.resources.stack_slots[first..])?) 1593 } 1594 1595 /// Generates an address that should allow for a store or a load. 1596 /// 1597 /// Addresses aren't generated like other values. They are never stored in variables so that 1598 /// we don't run the risk of returning them from a function, which would make the fuzzer 1599 /// complain since they are different from the interpreter to the backend. 1600 /// 1601 /// `min_size`: Controls the amount of space that the address should have. 1602 /// 1603 /// `aligned`: When passed as true, the resulting address is guaranteed to be aligned 1604 /// on an 8 byte boundary. 1605 /// 1606 /// Returns a valid address and the maximum possible offset that still respects `min_size`. 1607 fn generate_load_store_address( 1608 &mut self, 1609 builder: &mut FunctionBuilder, 1610 min_size: u32, 1611 aligned: bool, 1612 ) -> Result<(Value, u32)> { 1613 // TODO: Currently our only source of addresses is stack_addr, but we 1614 // should add global_value, symbol_value eventually 1615 let (addr, available_size) = { 1616 let (ss, slot_size) = self.stack_slot_with_size(min_size)?; 1617 1618 // stack_slot_with_size guarantees that slot_size >= min_size 1619 let max_offset = slot_size - min_size; 1620 let offset = if aligned { 1621 self.u.int_in_range(0..=max_offset / min_size)? * min_size 1622 } else { 1623 self.u.int_in_range(0..=max_offset)? 1624 }; 1625 1626 let base_addr = builder.ins().stack_addr(I64, ss, offset as i32); 1627 let available_size = slot_size.saturating_sub(offset); 1628 (base_addr, available_size) 1629 }; 1630 1631 // TODO: Insert a bunch of amode opcodes here to modify the address! 1632 1633 // Now that we have an address and a size, we just choose a random offset to return to the 1634 // caller. Preserving min_size bytes. 1635 let max_offset = available_size.saturating_sub(min_size); 1636 Ok((addr, max_offset)) 1637 } 1638 1639 // Generates an address and memflags for a load or store. 1640 fn generate_address_and_memflags( 1641 &mut self, 1642 builder: &mut FunctionBuilder, 1643 min_size: u32, 1644 is_atomic: bool, 1645 ) -> Result<(Value, MemFlags, Offset32)> { 1646 // Should we generate an aligned address 1647 // Some backends have issues with unaligned atomics. 1648 // AArch64: https://github.com/bytecodealliance/wasmtime/issues/5483 1649 // RISCV: https://github.com/bytecodealliance/wasmtime/issues/5882 1650 let requires_aligned_atomics = matches!( 1651 self.target_triple.architecture, 1652 Architecture::Aarch64(_) | Architecture::Riscv64(_) 1653 ); 1654 let aligned = if is_atomic && requires_aligned_atomics { 1655 true 1656 } else if min_size > 8 { 1657 // TODO: We currently can't guarantee that a stack_slot will be aligned on a 16 byte 1658 // boundary. We don't have a way to specify alignment when creating stack slots, and 1659 // cranelift only guarantees 8 byte alignment between stack slots. 1660 // See: https://github.com/bytecodealliance/wasmtime/issues/5922#issuecomment-1457926624 1661 false 1662 } else { 1663 bool::arbitrary(self.u)? 1664 }; 1665 1666 let mut flags = MemFlags::new(); 1667 // Even if we picked an aligned address, we can always generate unaligned memflags 1668 if aligned && bool::arbitrary(self.u)? { 1669 flags.set_aligned(); 1670 } 1671 // If the address is aligned, then we know it won't trap 1672 if aligned && bool::arbitrary(self.u)? { 1673 flags.set_notrap(); 1674 } 1675 1676 let (address, max_offset) = self.generate_load_store_address(builder, min_size, aligned)?; 1677 1678 // Pick an offset to pass into the load/store. 1679 let offset = if aligned { 1680 0 1681 } else { 1682 self.u.int_in_range(0..=max_offset)? as i32 1683 } 1684 .into(); 1685 1686 Ok((address, flags, offset)) 1687 } 1688 1689 /// Get a variable of type `ty` from the current function 1690 fn get_variable_of_type(&mut self, ty: Type) -> Result<Variable> { 1691 let opts = self.resources.vars.get(&ty).map_or(&[][..], Vec::as_slice); 1692 let var = self.u.choose(opts)?; 1693 Ok(*var) 1694 } 1695 1696 /// Generates an instruction(`iconst`/`fconst`/etc...) to introduce a constant value 1697 fn generate_const(&mut self, builder: &mut FunctionBuilder, ty: Type) -> Result<Value> { 1698 Ok(match self.u.datavalue(ty)? { 1699 DataValue::I8(i) => builder.ins().iconst(ty, i as i64), 1700 DataValue::I16(i) => builder.ins().iconst(ty, i as i64), 1701 DataValue::I32(i) => builder.ins().iconst(ty, i as i64), 1702 DataValue::I64(i) => builder.ins().iconst(ty, i as i64), 1703 DataValue::I128(i) => { 1704 let hi = builder.ins().iconst(I64, (i >> 64) as i64); 1705 let lo = builder.ins().iconst(I64, i as i64); 1706 builder.ins().iconcat(lo, hi) 1707 } 1708 DataValue::F32(f) => builder.ins().f32const(f), 1709 DataValue::F64(f) => builder.ins().f64const(f), 1710 DataValue::V128(bytes) => { 1711 let data = bytes.to_vec().into(); 1712 let handle = builder.func.dfg.constants.insert(data); 1713 builder.ins().vconst(ty, handle) 1714 } 1715 _ => unimplemented!(), 1716 }) 1717 } 1718 1719 /// Chooses a random block which can be targeted by a jump / branch. 1720 /// This means any block that is not the first block. 1721 fn generate_target_block(&mut self, source_block: Block) -> Result<Block> { 1722 // We try to mostly generate forward branches to avoid generating an excessive amount of 1723 // infinite loops. But they are still important, so give them a small chance of existing. 1724 let (backwards_blocks, forward_blocks) = 1725 self.resources.partition_target_blocks(source_block); 1726 let ratio = self.config.backwards_branch_ratio; 1727 let block_targets = if !backwards_blocks.is_empty() && self.u.ratio(ratio.0, ratio.1)? { 1728 backwards_blocks 1729 } else { 1730 forward_blocks 1731 }; 1732 assert!(!block_targets.is_empty()); 1733 1734 let (block, _) = self.u.choose(block_targets)?.clone(); 1735 Ok(block) 1736 } 1737 1738 fn generate_values_for_block( 1739 &mut self, 1740 builder: &mut FunctionBuilder, 1741 block: Block, 1742 ) -> Result<Vec<Value>> { 1743 let (_, sig) = self.resources.blocks[block.as_u32() as usize].clone(); 1744 self.generate_values_for_signature(builder, sig.iter().copied()) 1745 } 1746 1747 fn generate_values_for_signature<I: Iterator<Item = Type>>( 1748 &mut self, 1749 builder: &mut FunctionBuilder, 1750 signature: I, 1751 ) -> Result<Vec<Value>> { 1752 signature 1753 .map(|ty| { 1754 let var = self.get_variable_of_type(ty)?; 1755 let val = builder.use_var(var); 1756 Ok(val) 1757 }) 1758 .collect() 1759 } 1760 1761 /// The terminator that we need to insert has already been picked ahead of time 1762 /// we just need to build the instructions for it 1763 fn insert_terminator( 1764 &mut self, 1765 builder: &mut FunctionBuilder, 1766 source_block: Block, 1767 ) -> Result<()> { 1768 let terminator = self.resources.block_terminators[source_block.as_u32() as usize].clone(); 1769 1770 match terminator { 1771 BlockTerminator::Return => { 1772 let types: Vec<Type> = { 1773 let rets = &builder.func.signature.returns; 1774 rets.iter().map(|p| p.value_type).collect() 1775 }; 1776 let vals = self.generate_values_for_signature(builder, types.into_iter())?; 1777 1778 builder.ins().return_(&vals[..]); 1779 } 1780 BlockTerminator::Jump(target) => { 1781 let args = self.generate_values_for_block(builder, target)?; 1782 builder.ins().jump(target, &args[..]); 1783 } 1784 BlockTerminator::Br(left, right) => { 1785 let left_args = self.generate_values_for_block(builder, left)?; 1786 let right_args = self.generate_values_for_block(builder, right)?; 1787 1788 let condbr_types = [I8, I16, I32, I64, I128]; 1789 let _type = *self.u.choose(&condbr_types[..])?; 1790 let val = builder.use_var(self.get_variable_of_type(_type)?); 1791 builder 1792 .ins() 1793 .brif(val, left, &left_args[..], right, &right_args[..]); 1794 } 1795 BlockTerminator::BrTable(default, targets) => { 1796 // Create jump tables on demand 1797 let mut jt = Vec::with_capacity(targets.len()); 1798 for block in targets { 1799 let args = self.generate_values_for_block(builder, block)?; 1800 jt.push(builder.func.dfg.block_call(block, &args)) 1801 } 1802 1803 let args = self.generate_values_for_block(builder, default)?; 1804 let jt_data = JumpTableData::new(builder.func.dfg.block_call(default, &args), &jt); 1805 let jt = builder.create_jump_table(jt_data); 1806 1807 // br_table only supports I32 1808 let val = builder.use_var(self.get_variable_of_type(I32)?); 1809 1810 builder.ins().br_table(val, jt); 1811 } 1812 BlockTerminator::Switch(_type, default, entries) => { 1813 let mut switch = Switch::new(); 1814 for (&entry, &block) in entries.iter() { 1815 switch.set_entry(entry, block); 1816 } 1817 1818 let switch_val = builder.use_var(self.get_variable_of_type(_type)?); 1819 1820 switch.emit(builder, switch_val, default); 1821 } 1822 } 1823 1824 Ok(()) 1825 } 1826 1827 /// Fills the current block with random instructions 1828 fn generate_instructions(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 1829 for _ in 0..self.param(&self.config.instructions_per_block)? { 1830 let (op, args, rets) = self.u.choose(&OPCODE_SIGNATURES)?; 1831 1832 // We filter out instructions that aren't supported by the target at this point instead 1833 // of building a single vector of valid instructions at the beginning of function 1834 // generation, to avoid invalidating the corpus when instructions are enabled/disabled. 1835 if !valid_for_target(&self.target_triple, *op, &args, &rets) { 1836 return Err(arbitrary::Error::IncorrectFormat.into()); 1837 } 1838 1839 let inserter = inserter_for_format(op.format()); 1840 inserter(self, builder, *op, &args, &rets)?; 1841 } 1842 1843 Ok(()) 1844 } 1845 1846 fn generate_funcrefs(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 1847 let usercalls: Vec<(ExternalName, Signature)> = self 1848 .resources 1849 .usercalls 1850 .iter() 1851 .map(|(name, signature)| { 1852 let user_func_ref = builder.func.declare_imported_user_function(name.clone()); 1853 let name = ExternalName::User(user_func_ref); 1854 (name, signature.clone()) 1855 }) 1856 .collect(); 1857 1858 let lib_callconv = self.system_callconv(); 1859 let libcalls: Vec<(ExternalName, Signature)> = self 1860 .resources 1861 .libcalls 1862 .iter() 1863 .map(|libcall| { 1864 let pointer_type = Type::int_with_byte_size( 1865 self.target_triple.pointer_width().unwrap().bytes().into(), 1866 ) 1867 .unwrap(); 1868 let signature = libcall.signature(lib_callconv, pointer_type); 1869 let name = ExternalName::LibCall(*libcall); 1870 (name, signature) 1871 }) 1872 .collect(); 1873 1874 for (name, signature) in usercalls.into_iter().chain(libcalls) { 1875 let sig_ref = builder.import_signature(signature.clone()); 1876 let func_ref = builder.import_function(ExtFuncData { 1877 name, 1878 signature: sig_ref, 1879 colocated: self.u.arbitrary()?, 1880 }); 1881 1882 self.resources 1883 .func_refs 1884 .push((signature, sig_ref, func_ref)); 1885 } 1886 1887 Ok(()) 1888 } 1889 1890 fn generate_stack_slots(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 1891 for _ in 0..self.param(&self.config.static_stack_slots_per_function)? { 1892 let bytes = self.param(&self.config.static_stack_slot_size)? as u32; 1893 let ss_data = StackSlotData::new(StackSlotKind::ExplicitSlot, bytes); 1894 let slot = builder.create_sized_stack_slot(ss_data); 1895 self.resources.stack_slots.push((slot, bytes)); 1896 } 1897 1898 self.resources 1899 .stack_slots 1900 .sort_unstable_by_key(|&(_slot, bytes)| bytes); 1901 1902 Ok(()) 1903 } 1904 1905 /// Zero initializes the stack slot by inserting `stack_store`'s. 1906 fn initialize_stack_slots(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 1907 let i8_zero = builder.ins().iconst(I8, 0); 1908 let i16_zero = builder.ins().iconst(I16, 0); 1909 let i32_zero = builder.ins().iconst(I32, 0); 1910 let i64_zero = builder.ins().iconst(I64, 0); 1911 let i128_zero = builder.ins().uextend(I128, i64_zero); 1912 1913 for &(slot, init_size) in self.resources.stack_slots.iter() { 1914 let mut size = init_size; 1915 1916 // Insert the largest available store for the remaining size. 1917 while size != 0 { 1918 let offset = (init_size - size) as i32; 1919 let (val, filled) = match size { 1920 sz if sz / 16 > 0 => (i128_zero, 16), 1921 sz if sz / 8 > 0 => (i64_zero, 8), 1922 sz if sz / 4 > 0 => (i32_zero, 4), 1923 sz if sz / 2 > 0 => (i16_zero, 2), 1924 _ => (i8_zero, 1), 1925 }; 1926 builder.ins().stack_store(val, slot, offset); 1927 size -= filled; 1928 } 1929 } 1930 Ok(()) 1931 } 1932 1933 /// Creates a random amount of blocks in this function 1934 fn generate_blocks(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 1935 let extra_block_count = self.param(&self.config.blocks_per_function)?; 1936 1937 // We must always have at least one block, so we generate the "extra" blocks and add 1 for 1938 // the entry block. 1939 let block_count = 1 + extra_block_count; 1940 1941 // Blocks need to be sorted in ascending order 1942 self.resources.blocks = (0..block_count) 1943 .map(|i| { 1944 let is_entry = i == 0; 1945 let block = builder.create_block(); 1946 1947 // Optionally mark blocks that are not the entry block as cold 1948 if !is_entry { 1949 if bool::arbitrary(self.u)? { 1950 builder.set_cold_block(block); 1951 } 1952 } 1953 1954 // The first block has to have the function signature, but for the rest of them we generate 1955 // a random signature; 1956 if is_entry { 1957 builder.append_block_params_for_function_params(block); 1958 Ok(( 1959 block, 1960 self.signature.params.iter().map(|a| a.value_type).collect(), 1961 )) 1962 } else { 1963 let sig = self.generate_block_signature()?; 1964 sig.iter().for_each(|ty| { 1965 builder.append_block_param(block, *ty); 1966 }); 1967 Ok((block, sig)) 1968 } 1969 }) 1970 .collect::<Result<Vec<_>>>()?; 1971 1972 // Valid blocks for jump tables have to have no parameters in the signature, and must also 1973 // not be the first block. 1974 self.resources.blocks_without_params = self.resources.blocks[1..] 1975 .iter() 1976 .filter(|(_, sig)| sig.len() == 0) 1977 .map(|(b, _)| *b) 1978 .collect(); 1979 1980 // Compute the block CFG 1981 // 1982 // cranelift-frontend requires us to never generate unreachable blocks 1983 // To ensure this property we start by constructing a main "spine" of blocks. So block1 can 1984 // always jump to block2, and block2 can always jump to block3, etc... 1985 // 1986 // That is not a very interesting CFG, so we introduce variations on that, but always 1987 // ensuring that the property of pointing to the next block is maintained whatever the 1988 // branching mechanism we use. 1989 let blocks = self.resources.blocks.clone(); 1990 self.resources.block_terminators = blocks 1991 .iter() 1992 .map(|&(block, _)| { 1993 let next_block = Block::with_number(block.as_u32() + 1).unwrap(); 1994 let forward_blocks = self.resources.forward_blocks(block); 1995 let paramless_targets = self.resources.forward_blocks_without_params(block); 1996 let has_paramless_targets = !paramless_targets.is_empty(); 1997 let next_block_is_paramless = paramless_targets.contains(&next_block); 1998 1999 let mut valid_terminators = vec![]; 2000 2001 if forward_blocks.is_empty() { 2002 // Return is only valid on the last block. 2003 valid_terminators.push(BlockTerminatorKind::Return); 2004 } else { 2005 // If we have more than one block we can allow terminators that target blocks. 2006 // TODO: We could add some kind of BrReturn here, to explore edges where we 2007 // exit in the middle of the function 2008 valid_terminators.extend_from_slice(&[ 2009 BlockTerminatorKind::Jump, 2010 BlockTerminatorKind::Br, 2011 BlockTerminatorKind::BrTable, 2012 ]); 2013 } 2014 2015 // As the Switch interface only allows targeting blocks without params we need 2016 // to ensure that the next block has no params, since that one is guaranteed to be 2017 // picked in either case. 2018 if has_paramless_targets && next_block_is_paramless { 2019 valid_terminators.push(BlockTerminatorKind::Switch); 2020 } 2021 2022 let terminator = self.u.choose(&valid_terminators)?; 2023 2024 // Choose block targets for the terminators that we picked above 2025 Ok(match terminator { 2026 BlockTerminatorKind::Return => BlockTerminator::Return, 2027 BlockTerminatorKind::Jump => BlockTerminator::Jump(next_block), 2028 BlockTerminatorKind::Br => { 2029 BlockTerminator::Br(next_block, self.generate_target_block(block)?) 2030 } 2031 // TODO: Allow generating backwards branches here 2032 BlockTerminatorKind::BrTable => { 2033 // Make the default the next block, and then we don't have to worry 2034 // that we can reach it via the targets 2035 let default = next_block; 2036 2037 let target_count = self.param(&self.config.jump_table_entries)?; 2038 let targets = Result::from_iter( 2039 (0..target_count).map(|_| self.generate_target_block(block)), 2040 )?; 2041 2042 BlockTerminator::BrTable(default, targets) 2043 } 2044 BlockTerminatorKind::Switch => { 2045 // Make the default the next block, and then we don't have to worry 2046 // that we can reach it via the entries below 2047 let default_block = next_block; 2048 2049 let _type = *self.u.choose(&[I8, I16, I32, I64, I128][..])?; 2050 2051 // Build this into a HashMap since we cannot have duplicate entries. 2052 let mut entries = HashMap::new(); 2053 for _ in 0..self.param(&self.config.switch_cases)? { 2054 // The Switch API only allows for entries that are addressable by the index type 2055 // so we need to limit the range of values that we generate. 2056 let (ty_min, ty_max) = _type.bounds(false); 2057 let range_start = self.u.int_in_range(ty_min..=ty_max)?; 2058 2059 // We can either insert a contiguous range of blocks or a individual block 2060 // This is done because the Switch API specializes contiguous ranges. 2061 let range_size = if bool::arbitrary(self.u)? { 2062 1 2063 } else { 2064 self.param(&self.config.switch_max_range_size)? 2065 } as u128; 2066 2067 // Build the switch entries 2068 for i in 0..range_size { 2069 let index = range_start.wrapping_add(i) % ty_max; 2070 let block = *self 2071 .u 2072 .choose(self.resources.forward_blocks_without_params(block))?; 2073 2074 entries.insert(index, block); 2075 } 2076 } 2077 2078 BlockTerminator::Switch(_type, default_block, entries) 2079 } 2080 }) 2081 }) 2082 .collect::<Result<_>>()?; 2083 2084 Ok(()) 2085 } 2086 2087 fn generate_block_signature(&mut self) -> Result<BlockSignature> { 2088 let param_count = self.param(&self.config.block_signature_params)?; 2089 2090 let mut params = Vec::with_capacity(param_count); 2091 for _ in 0..param_count { 2092 params.push(self.u._type(self.target_triple.architecture)?); 2093 } 2094 Ok(params) 2095 } 2096 2097 fn build_variable_pool(&mut self, builder: &mut FunctionBuilder) -> Result<()> { 2098 let block = builder.current_block().unwrap(); 2099 2100 // Define variables for the function signature 2101 let mut vars: Vec<_> = builder 2102 .func 2103 .signature 2104 .params 2105 .iter() 2106 .map(|param| param.value_type) 2107 .zip(builder.block_params(block).iter().copied()) 2108 .collect(); 2109 2110 // Create a pool of vars that are going to be used in this function 2111 for _ in 0..self.param(&self.config.vars_per_function)? { 2112 let ty = self.u._type(self.target_triple.architecture)?; 2113 let value = self.generate_const(builder, ty)?; 2114 vars.push((ty, value)); 2115 } 2116 2117 for (id, (ty, value)) in vars.into_iter().enumerate() { 2118 let var = Variable::new(id); 2119 builder.declare_var(var, ty); 2120 builder.def_var(var, value); 2121 self.resources 2122 .vars 2123 .entry(ty) 2124 .or_insert_with(Vec::new) 2125 .push(var); 2126 } 2127 2128 Ok(()) 2129 } 2130 2131 /// We generate a function in multiple stages: 2132 /// 2133 /// * First we generate a random number of empty blocks 2134 /// * Then we generate a random pool of variables to be used throughout the function 2135 /// * We then visit each block and generate random instructions 2136 /// 2137 /// Because we generate all blocks and variables up front we already know everything that 2138 /// we need when generating instructions (i.e. jump targets / variables) 2139 pub fn generate(mut self) -> Result<Function> { 2140 let mut fn_builder_ctx = FunctionBuilderContext::new(); 2141 let mut func = Function::with_name_signature(self.name.clone(), self.signature.clone()); 2142 2143 let mut builder = FunctionBuilder::new(&mut func, &mut fn_builder_ctx); 2144 2145 self.generate_blocks(&mut builder)?; 2146 2147 // Function preamble 2148 self.generate_funcrefs(&mut builder)?; 2149 self.generate_stack_slots(&mut builder)?; 2150 2151 // Main instruction generation loop 2152 for (block, block_sig) in self.resources.blocks.clone().into_iter() { 2153 let is_block0 = block.as_u32() == 0; 2154 builder.switch_to_block(block); 2155 2156 if is_block0 { 2157 // The first block is special because we must create variables both for the 2158 // block signature and for the variable pool. Additionally, we must also define 2159 // initial values for all variables that are not the function signature. 2160 self.build_variable_pool(&mut builder)?; 2161 2162 // Stack slots have random bytes at the beginning of the function 2163 // initialize them to a constant value so that execution stays predictable. 2164 self.initialize_stack_slots(&mut builder)?; 2165 } else { 2166 // Define variables for the block params 2167 for (i, ty) in block_sig.iter().enumerate() { 2168 let var = self.get_variable_of_type(*ty)?; 2169 let block_param = builder.block_params(block)[i]; 2170 builder.def_var(var, block_param); 2171 } 2172 } 2173 2174 // Generate block instructions 2175 self.generate_instructions(&mut builder)?; 2176 2177 // Insert a terminator to safely exit the block 2178 self.insert_terminator(&mut builder, block)?; 2179 } 2180 2181 builder.seal_all_blocks(); 2182 builder.finalize(); 2183 2184 Ok(func) 2185 } 2186 } 2187