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