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