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