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