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::Fmax, &[F32X4, F32X4], &[F32X4]),
1174                 (Opcode::Fmax, &[F64X2, F64X2], &[F64X2]),
1175                 (Opcode::FcvtToUintSat, &[F32X4], &[I8]),
1176                 (Opcode::FcvtToUintSat, &[F64X2], &[I8]),
1177                 (Opcode::FcvtToUintSat, &[F32X4], &[I16]),
1178                 (Opcode::FcvtToUintSat, &[F64X2], &[I16]),
1179                 (Opcode::FcvtToUintSat, &[F32X4], &[I32]),
1180                 (Opcode::FcvtToUintSat, &[F64X2], &[I32]),
1181                 (Opcode::FcvtToUintSat, &[F32X4], &[I64]),
1182                 (Opcode::FcvtToUintSat, &[F64X2], &[I64]),
1183                 (Opcode::FcvtToUintSat, &[F32X4], &[I128]),
1184                 (Opcode::FcvtToUintSat, &[F64X2], &[I128]),
1185                 (Opcode::FcvtToUintSat, &[F32], &[I8X16]),
1186                 (Opcode::FcvtToUintSat, &[F64], &[I8X16]),
1187                 (Opcode::FcvtToUintSat, &[F32X4], &[I8X16]),
1188                 (Opcode::FcvtToUintSat, &[F64X2], &[I8X16]),
1189                 (Opcode::FcvtToUintSat, &[F32], &[I16X8]),
1190                 (Opcode::FcvtToUintSat, &[F64], &[I16X8]),
1191                 (Opcode::FcvtToUintSat, &[F32X4], &[I16X8]),
1192                 (Opcode::FcvtToUintSat, &[F64X2], &[I16X8]),
1193                 (Opcode::FcvtToUintSat, &[F32], &[I32X4]),
1194                 (Opcode::FcvtToUintSat, &[F64], &[I32X4]),
1195                 (Opcode::FcvtToUintSat, &[F64X2], &[I32X4]),
1196                 (Opcode::FcvtToUintSat, &[F32], &[I64X2]),
1197                 (Opcode::FcvtToUintSat, &[F64], &[I64X2]),
1198                 (Opcode::FcvtToUintSat, &[F32X4], &[I64X2]),
1199                 (Opcode::FcvtToSintSat, &[F32X4], &[I8]),
1200                 (Opcode::FcvtToSintSat, &[F64X2], &[I8]),
1201                 (Opcode::FcvtToSintSat, &[F32X4], &[I16]),
1202                 (Opcode::FcvtToSintSat, &[F64X2], &[I16]),
1203                 (Opcode::FcvtToSintSat, &[F32X4], &[I32]),
1204                 (Opcode::FcvtToSintSat, &[F64X2], &[I32]),
1205                 (Opcode::FcvtToSintSat, &[F32X4], &[I64]),
1206                 (Opcode::FcvtToSintSat, &[F64X2], &[I64]),
1207                 (Opcode::FcvtToSintSat, &[F32X4], &[I128]),
1208                 (Opcode::FcvtToSintSat, &[F64X2], &[I128]),
1209                 (Opcode::FcvtToSintSat, &[F32], &[I8X16]),
1210                 (Opcode::FcvtToSintSat, &[F64], &[I8X16]),
1211                 (Opcode::FcvtToSintSat, &[F32X4], &[I8X16]),
1212                 (Opcode::FcvtToSintSat, &[F64X2], &[I8X16]),
1213                 (Opcode::FcvtToSintSat, &[F32], &[I16X8]),
1214                 (Opcode::FcvtToSintSat, &[F64], &[I16X8]),
1215                 (Opcode::FcvtToSintSat, &[F32X4], &[I16X8]),
1216                 (Opcode::FcvtToSintSat, &[F64X2], &[I16X8]),
1217                 (Opcode::FcvtToSintSat, &[F32], &[I32X4]),
1218                 (Opcode::FcvtToSintSat, &[F64], &[I32X4]),
1219                 (Opcode::FcvtToSintSat, &[F64X2], &[I32X4]),
1220                 (Opcode::FcvtToSintSat, &[F32], &[I64X2]),
1221                 (Opcode::FcvtToSintSat, &[F64], &[I64X2]),
1222                 (Opcode::FcvtToSintSat, &[F32X4], &[I64X2]),
1223                 (Opcode::FcvtFromUint, &[I8X16], &[F32]),
1224                 (Opcode::FcvtFromUint, &[I16X8], &[F32]),
1225                 (Opcode::FcvtFromUint, &[I32X4], &[F32]),
1226                 (Opcode::FcvtFromUint, &[I64X2], &[F32]),
1227                 (Opcode::FcvtFromUint, &[I8X16], &[F64]),
1228                 (Opcode::FcvtFromUint, &[I16X8], &[F64]),
1229                 (Opcode::FcvtFromUint, &[I32X4], &[F64]),
1230                 (Opcode::FcvtFromUint, &[I64X2], &[F64]),
1231                 (Opcode::FcvtFromUint, &[I8], &[F32X4]),
1232                 (Opcode::FcvtFromUint, &[I16], &[F32X4]),
1233                 (Opcode::FcvtFromUint, &[I32], &[F32X4]),
1234                 (Opcode::FcvtFromUint, &[I64], &[F32X4]),
1235                 (Opcode::FcvtFromUint, &[I128], &[F32X4]),
1236                 (Opcode::FcvtFromUint, &[I8X16], &[F32X4]),
1237                 (Opcode::FcvtFromUint, &[I16X8], &[F32X4]),
1238                 (Opcode::FcvtFromUint, &[I64X2], &[F32X4]),
1239                 (Opcode::FcvtFromUint, &[I8], &[F64X2]),
1240                 (Opcode::FcvtFromUint, &[I16], &[F64X2]),
1241                 (Opcode::FcvtFromUint, &[I32], &[F64X2]),
1242                 (Opcode::FcvtFromUint, &[I64], &[F64X2]),
1243                 (Opcode::FcvtFromUint, &[I128], &[F64X2]),
1244                 (Opcode::FcvtFromUint, &[I8X16], &[F64X2]),
1245                 (Opcode::FcvtFromUint, &[I16X8], &[F64X2]),
1246                 (Opcode::FcvtFromUint, &[I32X4], &[F64X2]),
1247                 (Opcode::FcvtFromSint, &[I8X16], &[F32]),
1248                 (Opcode::FcvtFromSint, &[I16X8], &[F32]),
1249                 (Opcode::FcvtFromSint, &[I32X4], &[F32]),
1250                 (Opcode::FcvtFromSint, &[I64X2], &[F32]),
1251                 (Opcode::FcvtFromSint, &[I8X16], &[F64]),
1252                 (Opcode::FcvtFromSint, &[I16X8], &[F64]),
1253                 (Opcode::FcvtFromSint, &[I32X4], &[F64]),
1254                 (Opcode::FcvtFromSint, &[I64X2], &[F64]),
1255                 (Opcode::FcvtFromSint, &[I8], &[F32X4]),
1256                 (Opcode::FcvtFromSint, &[I16], &[F32X4]),
1257                 (Opcode::FcvtFromSint, &[I32], &[F32X4]),
1258                 (Opcode::FcvtFromSint, &[I64], &[F32X4]),
1259                 (Opcode::FcvtFromSint, &[I128], &[F32X4]),
1260                 (Opcode::FcvtFromSint, &[I8X16], &[F32X4]),
1261                 (Opcode::FcvtFromSint, &[I16X8], &[F32X4]),
1262                 (Opcode::FcvtFromSint, &[I64X2], &[F32X4]),
1263                 (Opcode::FcvtFromSint, &[I8], &[F64X2]),
1264                 (Opcode::FcvtFromSint, &[I16], &[F64X2]),
1265                 (Opcode::FcvtFromSint, &[I32], &[F64X2]),
1266                 (Opcode::FcvtFromSint, &[I64], &[F64X2]),
1267                 (Opcode::FcvtFromSint, &[I128], &[F64X2]),
1268                 (Opcode::FcvtFromSint, &[I8X16], &[F64X2]),
1269                 (Opcode::FcvtFromSint, &[I16X8], &[F64X2]),
1270                 (Opcode::FcvtFromSint, &[I32X4], &[F64X2]),
1271             )
1272         })
1273         .collect()
1274 });
1275 
1276 fn inserter_for_format(fmt: InstructionFormat) -> OpcodeInserter {
1277     match fmt {
1278         InstructionFormat::AtomicCas => insert_atomic_cas,
1279         InstructionFormat::AtomicRmw => insert_atomic_rmw,
1280         InstructionFormat::Binary => insert_opcode,
1281         InstructionFormat::BinaryImm64 => todo!(),
1282         InstructionFormat::BinaryImm8 => insert_ins_ext_lane,
1283         InstructionFormat::Call => insert_call,
1284         InstructionFormat::CallIndirect => insert_call,
1285         InstructionFormat::CondTrap => todo!(),
1286         InstructionFormat::DynamicStackLoad => todo!(),
1287         InstructionFormat::DynamicStackStore => todo!(),
1288         InstructionFormat::FloatCompare => insert_cmp,
1289         InstructionFormat::FuncAddr => todo!(),
1290         InstructionFormat::IntAddTrap => todo!(),
1291         InstructionFormat::IntCompare => insert_cmp,
1292         InstructionFormat::IntCompareImm => todo!(),
1293         InstructionFormat::Load => insert_load_store,
1294         InstructionFormat::LoadNoOffset => insert_load_store,
1295         InstructionFormat::NullAry => insert_opcode,
1296         InstructionFormat::Shuffle => insert_shuffle,
1297         InstructionFormat::StackLoad => insert_stack_load,
1298         InstructionFormat::StackStore => insert_stack_store,
1299         InstructionFormat::Store => insert_load_store,
1300         InstructionFormat::StoreNoOffset => insert_load_store,
1301         InstructionFormat::TableAddr => todo!(),
1302         InstructionFormat::Ternary => insert_opcode,
1303         InstructionFormat::TernaryImm8 => insert_ins_ext_lane,
1304         InstructionFormat::Trap => todo!(),
1305         InstructionFormat::Unary => insert_opcode,
1306         InstructionFormat::UnaryConst => insert_const,
1307         InstructionFormat::UnaryGlobalValue => todo!(),
1308         InstructionFormat::UnaryIeee32 => insert_const,
1309         InstructionFormat::UnaryIeee64 => insert_const,
1310         InstructionFormat::UnaryImm => insert_const,
1311 
1312         InstructionFormat::BranchTable
1313         | InstructionFormat::Brif
1314         | InstructionFormat::Jump
1315         | InstructionFormat::MultiAry => {
1316             panic!(
1317                 "Control-flow instructions should be handled by 'insert_terminator': {:?}",
1318                 fmt
1319             )
1320         }
1321     }
1322 }
1323 
1324 pub struct FunctionGenerator<'r, 'data>
1325 where
1326     'data: 'r,
1327 {
1328     u: &'r mut Unstructured<'data>,
1329     config: &'r Config,
1330     resources: Resources,
1331     isa: OwnedTargetIsa,
1332     name: UserFuncName,
1333     signature: Signature,
1334 }
1335 
1336 #[derive(Debug, Clone)]
1337 enum BlockTerminator {
1338     Return,
1339     Jump(Block),
1340     Br(Block, Block),
1341     BrTable(Block, Vec<Block>),
1342     Switch(Type, Block, HashMap<u128, Block>),
1343     TailCall(FuncRef),
1344     TailCallIndirect(FuncRef),
1345 }
1346 
1347 #[derive(Debug, Clone)]
1348 enum BlockTerminatorKind {
1349     Return,
1350     Jump,
1351     Br,
1352     BrTable,
1353     Switch,
1354     TailCall,
1355     TailCallIndirect,
1356 }
1357 
1358 #[derive(Default)]
1359 struct Resources {
1360     vars: HashMap<Type, Vec<Variable>>,
1361     blocks: Vec<(Block, BlockSignature)>,
1362     blocks_without_params: Vec<Block>,
1363     block_terminators: Vec<BlockTerminator>,
1364     func_refs: Vec<(Signature, SigRef, FuncRef)>,
1365     stack_slots: Vec<(StackSlot, StackSize)>,
1366     usercalls: Vec<(UserExternalName, Signature)>,
1367     libcalls: Vec<LibCall>,
1368 }
1369 
1370 impl Resources {
1371     /// Partitions blocks at `block`. Only blocks that can be targeted by branches are considered.
1372     ///
1373     /// The first slice includes all blocks up to and including `block`.
1374     /// The second slice includes all remaining blocks.
1375     fn partition_target_blocks(
1376         &self,
1377         block: Block,
1378     ) -> (&[(Block, BlockSignature)], &[(Block, BlockSignature)]) {
1379         // Blocks are stored in-order and have no gaps, this means that we can simply index them by
1380         // their number. We also need to exclude the entry block since it isn't a valid target.
1381         let target_blocks = &self.blocks[1..];
1382         target_blocks.split_at(block.as_u32() as usize)
1383     }
1384 
1385     /// Returns blocks forward of `block`. Only blocks that can be targeted by branches are considered.
1386     fn forward_blocks(&self, block: Block) -> &[(Block, BlockSignature)] {
1387         let (_, forward_blocks) = self.partition_target_blocks(block);
1388         forward_blocks
1389     }
1390 
1391     /// Generates a slice of `blocks_without_params` ahead of `block`
1392     fn forward_blocks_without_params(&self, block: Block) -> &[Block] {
1393         let partition_point = self.blocks_without_params.partition_point(|b| *b <= block);
1394         &self.blocks_without_params[partition_point..]
1395     }
1396 
1397     /// Generates an iterator of all valid tail call targets. This includes all functions with both
1398     ///  the `tail` calling convention and the same return values as the caller.
1399     fn tail_call_targets<'a>(
1400         &'a self,
1401         caller_sig: &'a Signature,
1402     ) -> impl Iterator<Item = &'a (Signature, SigRef, FuncRef)> {
1403         self.func_refs.iter().filter(|(sig, _, _)| {
1404             sig.call_conv == CallConv::Tail && sig.returns == caller_sig.returns
1405         })
1406     }
1407 }
1408 
1409 impl<'r, 'data> FunctionGenerator<'r, 'data>
1410 where
1411     'data: 'r,
1412 {
1413     pub fn new(
1414         u: &'r mut Unstructured<'data>,
1415         config: &'r Config,
1416         isa: OwnedTargetIsa,
1417         name: UserFuncName,
1418         signature: Signature,
1419         usercalls: Vec<(UserExternalName, Signature)>,
1420         libcalls: Vec<LibCall>,
1421     ) -> Self {
1422         Self {
1423             u,
1424             config,
1425             resources: Resources {
1426                 usercalls,
1427                 libcalls,
1428                 ..Resources::default()
1429             },
1430             isa,
1431             name,
1432             signature,
1433         }
1434     }
1435 
1436     /// Generates a random value for config `param`
1437     fn param(&mut self, param: &RangeInclusive<usize>) -> Result<usize> {
1438         Ok(self.u.int_in_range(param.clone())?)
1439     }
1440 
1441     fn system_callconv(&mut self) -> CallConv {
1442         // TODO: This currently only runs on linux, so this is the only choice
1443         // We should improve this once we generate flags and targets
1444         CallConv::SystemV
1445     }
1446 
1447     /// Finds a stack slot with size of at least n bytes
1448     fn stack_slot_with_size(&mut self, n: u32) -> Result<(StackSlot, StackSize)> {
1449         let first = self
1450             .resources
1451             .stack_slots
1452             .partition_point(|&(_slot, size)| size < n);
1453         Ok(*self.u.choose(&self.resources.stack_slots[first..])?)
1454     }
1455 
1456     /// Generates an address that should allow for a store or a load.
1457     ///
1458     /// Addresses aren't generated like other values. They are never stored in variables so that
1459     /// we don't run the risk of returning them from a function, which would make the fuzzer
1460     /// complain since they are different from the interpreter to the backend.
1461     ///
1462     /// `min_size`: Controls the amount of space that the address should have.
1463     ///
1464     /// `aligned`: When passed as true, the resulting address is guaranteed to be aligned
1465     /// on an 8 byte boundary.
1466     ///
1467     /// Returns a valid address and the maximum possible offset that still respects `min_size`.
1468     fn generate_load_store_address(
1469         &mut self,
1470         builder: &mut FunctionBuilder,
1471         min_size: u32,
1472         aligned: bool,
1473     ) -> Result<(Value, u32)> {
1474         // TODO: Currently our only source of addresses is stack_addr, but we
1475         // should add global_value, symbol_value eventually
1476         let (addr, available_size) = {
1477             let (ss, slot_size) = self.stack_slot_with_size(min_size)?;
1478 
1479             // stack_slot_with_size guarantees that slot_size >= min_size
1480             let max_offset = slot_size - min_size;
1481             let offset = if aligned {
1482                 self.u.int_in_range(0..=max_offset / min_size)? * min_size
1483             } else {
1484                 self.u.int_in_range(0..=max_offset)?
1485             };
1486 
1487             let base_addr = builder.ins().stack_addr(I64, ss, offset as i32);
1488             let available_size = slot_size.saturating_sub(offset);
1489             (base_addr, available_size)
1490         };
1491 
1492         // TODO: Insert a bunch of amode opcodes here to modify the address!
1493 
1494         // Now that we have an address and a size, we just choose a random offset to return to the
1495         // caller. Preserving min_size bytes.
1496         let max_offset = available_size.saturating_sub(min_size);
1497         Ok((addr, max_offset))
1498     }
1499 
1500     // Generates an address and memflags for a load or store.
1501     fn generate_address_and_memflags(
1502         &mut self,
1503         builder: &mut FunctionBuilder,
1504         min_size: u32,
1505         is_atomic: bool,
1506     ) -> Result<(Value, MemFlags, Offset32)> {
1507         // Should we generate an aligned address
1508         // Some backends have issues with unaligned atomics.
1509         // AArch64: https://github.com/bytecodealliance/wasmtime/issues/5483
1510         // RISCV: https://github.com/bytecodealliance/wasmtime/issues/5882
1511         let requires_aligned_atomics = matches!(
1512             self.isa.triple().architecture,
1513             Architecture::Aarch64(_) | Architecture::Riscv64(_)
1514         );
1515         let aligned = if is_atomic && requires_aligned_atomics {
1516             true
1517         } else if min_size > 8 {
1518             // TODO: We currently can't guarantee that a stack_slot will be aligned on a 16 byte
1519             // boundary. We don't have a way to specify alignment when creating stack slots, and
1520             // cranelift only guarantees 8 byte alignment between stack slots.
1521             // See: https://github.com/bytecodealliance/wasmtime/issues/5922#issuecomment-1457926624
1522             false
1523         } else {
1524             bool::arbitrary(self.u)?
1525         };
1526 
1527         let mut flags = MemFlags::new();
1528         // Even if we picked an aligned address, we can always generate unaligned memflags
1529         if aligned && bool::arbitrary(self.u)? {
1530             flags.set_aligned();
1531         }
1532         // If the address is aligned, then we know it won't trap
1533         if aligned && bool::arbitrary(self.u)? {
1534             flags.set_notrap();
1535         }
1536 
1537         let (address, max_offset) = self.generate_load_store_address(builder, min_size, aligned)?;
1538 
1539         // Pick an offset to pass into the load/store.
1540         let offset = if aligned {
1541             0
1542         } else {
1543             self.u.int_in_range(0..=max_offset)? as i32
1544         }
1545         .into();
1546 
1547         Ok((address, flags, offset))
1548     }
1549 
1550     /// Get a variable of type `ty` from the current function
1551     fn get_variable_of_type(&mut self, ty: Type) -> Result<Variable> {
1552         let opts = self.resources.vars.get(&ty).map_or(&[][..], Vec::as_slice);
1553         let var = self.u.choose(opts)?;
1554         Ok(*var)
1555     }
1556 
1557     /// Generates an instruction(`iconst`/`fconst`/etc...) to introduce a constant value
1558     fn generate_const(&mut self, builder: &mut FunctionBuilder, ty: Type) -> Result<Value> {
1559         Ok(match self.u.datavalue(ty)? {
1560             DataValue::I8(i) => builder.ins().iconst(ty, i as i64),
1561             DataValue::I16(i) => builder.ins().iconst(ty, i as i64),
1562             DataValue::I32(i) => builder.ins().iconst(ty, i as i64),
1563             DataValue::I64(i) => builder.ins().iconst(ty, i as i64),
1564             DataValue::I128(i) => {
1565                 let hi = builder.ins().iconst(I64, (i >> 64) as i64);
1566                 let lo = builder.ins().iconst(I64, i as i64);
1567                 builder.ins().iconcat(lo, hi)
1568             }
1569             DataValue::F32(f) => builder.ins().f32const(f),
1570             DataValue::F64(f) => builder.ins().f64const(f),
1571             DataValue::V128(bytes) => {
1572                 let data = bytes.to_vec().into();
1573                 let handle = builder.func.dfg.constants.insert(data);
1574                 builder.ins().vconst(ty, handle)
1575             }
1576             _ => unimplemented!(),
1577         })
1578     }
1579 
1580     /// Chooses a random block which can be targeted by a jump / branch.
1581     /// This means any block that is not the first block.
1582     fn generate_target_block(&mut self, source_block: Block) -> Result<Block> {
1583         // We try to mostly generate forward branches to avoid generating an excessive amount of
1584         // infinite loops. But they are still important, so give them a small chance of existing.
1585         let (backwards_blocks, forward_blocks) =
1586             self.resources.partition_target_blocks(source_block);
1587         let ratio = self.config.backwards_branch_ratio;
1588         let block_targets = if !backwards_blocks.is_empty() && self.u.ratio(ratio.0, ratio.1)? {
1589             backwards_blocks
1590         } else {
1591             forward_blocks
1592         };
1593         assert!(!block_targets.is_empty());
1594 
1595         let (block, _) = self.u.choose(block_targets)?.clone();
1596         Ok(block)
1597     }
1598 
1599     fn generate_values_for_block(
1600         &mut self,
1601         builder: &mut FunctionBuilder,
1602         block: Block,
1603     ) -> Result<Vec<Value>> {
1604         let (_, sig) = self.resources.blocks[block.as_u32() as usize].clone();
1605         self.generate_values_for_signature(builder, sig.iter().copied())
1606     }
1607 
1608     fn generate_values_for_signature<I: Iterator<Item = Type>>(
1609         &mut self,
1610         builder: &mut FunctionBuilder,
1611         signature: I,
1612     ) -> Result<Vec<Value>> {
1613         signature
1614             .map(|ty| {
1615                 let var = self.get_variable_of_type(ty)?;
1616                 let val = builder.use_var(var);
1617                 Ok(val)
1618             })
1619             .collect()
1620     }
1621 
1622     /// The terminator that we need to insert has already been picked ahead of time
1623     /// we just need to build the instructions for it
1624     fn insert_terminator(
1625         &mut self,
1626         builder: &mut FunctionBuilder,
1627         source_block: Block,
1628     ) -> Result<()> {
1629         let terminator = self.resources.block_terminators[source_block.as_u32() as usize].clone();
1630 
1631         match terminator {
1632             BlockTerminator::Return => {
1633                 let types: Vec<Type> = {
1634                     let rets = &builder.func.signature.returns;
1635                     rets.iter().map(|p| p.value_type).collect()
1636                 };
1637                 let vals = self.generate_values_for_signature(builder, types.into_iter())?;
1638 
1639                 builder.ins().return_(&vals[..]);
1640             }
1641             BlockTerminator::Jump(target) => {
1642                 let args = self.generate_values_for_block(builder, target)?;
1643                 builder.ins().jump(target, &args[..]);
1644             }
1645             BlockTerminator::Br(left, right) => {
1646                 let left_args = self.generate_values_for_block(builder, left)?;
1647                 let right_args = self.generate_values_for_block(builder, right)?;
1648 
1649                 let condbr_types = [I8, I16, I32, I64, I128];
1650                 let _type = *self.u.choose(&condbr_types[..])?;
1651                 let val = builder.use_var(self.get_variable_of_type(_type)?);
1652                 builder
1653                     .ins()
1654                     .brif(val, left, &left_args[..], right, &right_args[..]);
1655             }
1656             BlockTerminator::BrTable(default, targets) => {
1657                 // Create jump tables on demand
1658                 let mut jt = Vec::with_capacity(targets.len());
1659                 for block in targets {
1660                     let args = self.generate_values_for_block(builder, block)?;
1661                     jt.push(builder.func.dfg.block_call(block, &args))
1662                 }
1663 
1664                 let args = self.generate_values_for_block(builder, default)?;
1665                 let jt_data = JumpTableData::new(builder.func.dfg.block_call(default, &args), &jt);
1666                 let jt = builder.create_jump_table(jt_data);
1667 
1668                 // br_table only supports I32
1669                 let val = builder.use_var(self.get_variable_of_type(I32)?);
1670 
1671                 builder.ins().br_table(val, jt);
1672             }
1673             BlockTerminator::Switch(_type, default, entries) => {
1674                 let mut switch = Switch::new();
1675                 for (&entry, &block) in entries.iter() {
1676                     switch.set_entry(entry, block);
1677                 }
1678 
1679                 let switch_val = builder.use_var(self.get_variable_of_type(_type)?);
1680 
1681                 switch.emit(builder, switch_val, default);
1682             }
1683             BlockTerminator::TailCall(target) | BlockTerminator::TailCallIndirect(target) => {
1684                 let (sig, sig_ref, func_ref) = self
1685                     .resources
1686                     .func_refs
1687                     .iter()
1688                     .find(|(_, _, f)| *f == target)
1689                     .expect("Failed to find previously selected function")
1690                     .clone();
1691 
1692                 let opcode = match terminator {
1693                     BlockTerminator::TailCall(_) => Opcode::ReturnCall,
1694                     BlockTerminator::TailCallIndirect(_) => Opcode::ReturnCallIndirect,
1695                     _ => unreachable!(),
1696                 };
1697 
1698                 insert_call_to_function(self, builder, opcode, &sig, sig_ref, func_ref)?;
1699             }
1700         }
1701 
1702         Ok(())
1703     }
1704 
1705     /// Fills the current block with random instructions
1706     fn generate_instructions(&mut self, builder: &mut FunctionBuilder) -> Result<()> {
1707         for _ in 0..self.param(&self.config.instructions_per_block)? {
1708             let (op, args, rets) = self.u.choose(&OPCODE_SIGNATURES)?;
1709 
1710             // We filter out instructions that aren't supported by the target at this point instead
1711             // of building a single vector of valid instructions at the beginning of function
1712             // generation, to avoid invalidating the corpus when instructions are enabled/disabled.
1713             if !valid_for_target(&self.isa.triple(), *op, &args, &rets) {
1714                 return Err(arbitrary::Error::IncorrectFormat.into());
1715             }
1716 
1717             let inserter = inserter_for_format(op.format());
1718             inserter(self, builder, *op, &args, &rets)?;
1719         }
1720 
1721         Ok(())
1722     }
1723 
1724     fn generate_funcrefs(&mut self, builder: &mut FunctionBuilder) -> Result<()> {
1725         let usercalls: Vec<(ExternalName, Signature)> = self
1726             .resources
1727             .usercalls
1728             .iter()
1729             .map(|(name, signature)| {
1730                 let user_func_ref = builder.func.declare_imported_user_function(name.clone());
1731                 let name = ExternalName::User(user_func_ref);
1732                 (name, signature.clone())
1733             })
1734             .collect();
1735 
1736         let lib_callconv = self.system_callconv();
1737         let libcalls: Vec<(ExternalName, Signature)> = self
1738             .resources
1739             .libcalls
1740             .iter()
1741             .map(|libcall| {
1742                 let pointer_type = Type::int_with_byte_size(
1743                     self.isa.triple().pointer_width().unwrap().bytes().into(),
1744                 )
1745                 .unwrap();
1746                 let signature = libcall.signature(lib_callconv, pointer_type);
1747                 let name = ExternalName::LibCall(*libcall);
1748                 (name, signature)
1749             })
1750             .collect();
1751 
1752         for (name, signature) in usercalls.into_iter().chain(libcalls) {
1753             let sig_ref = builder.import_signature(signature.clone());
1754             let func_ref = builder.import_function(ExtFuncData {
1755                 name,
1756                 signature: sig_ref,
1757                 colocated: self.u.arbitrary()?,
1758             });
1759 
1760             self.resources
1761                 .func_refs
1762                 .push((signature, sig_ref, func_ref));
1763         }
1764 
1765         Ok(())
1766     }
1767 
1768     fn generate_stack_slots(&mut self, builder: &mut FunctionBuilder) -> Result<()> {
1769         for _ in 0..self.param(&self.config.static_stack_slots_per_function)? {
1770             let bytes = self.param(&self.config.static_stack_slot_size)? as u32;
1771             let ss_data = StackSlotData::new(StackSlotKind::ExplicitSlot, bytes);
1772             let slot = builder.create_sized_stack_slot(ss_data);
1773             self.resources.stack_slots.push((slot, bytes));
1774         }
1775 
1776         self.resources
1777             .stack_slots
1778             .sort_unstable_by_key(|&(_slot, bytes)| bytes);
1779 
1780         Ok(())
1781     }
1782 
1783     /// Zero initializes the stack slot by inserting `stack_store`'s.
1784     fn initialize_stack_slots(&mut self, builder: &mut FunctionBuilder) -> Result<()> {
1785         let i8_zero = builder.ins().iconst(I8, 0);
1786         let i16_zero = builder.ins().iconst(I16, 0);
1787         let i32_zero = builder.ins().iconst(I32, 0);
1788         let i64_zero = builder.ins().iconst(I64, 0);
1789         let i128_zero = builder.ins().uextend(I128, i64_zero);
1790 
1791         for &(slot, init_size) in self.resources.stack_slots.iter() {
1792             let mut size = init_size;
1793 
1794             // Insert the largest available store for the remaining size.
1795             while size != 0 {
1796                 let offset = (init_size - size) as i32;
1797                 let (val, filled) = match size {
1798                     sz if sz / 16 > 0 => (i128_zero, 16),
1799                     sz if sz / 8 > 0 => (i64_zero, 8),
1800                     sz if sz / 4 > 0 => (i32_zero, 4),
1801                     sz if sz / 2 > 0 => (i16_zero, 2),
1802                     _ => (i8_zero, 1),
1803                 };
1804                 builder.ins().stack_store(val, slot, offset);
1805                 size -= filled;
1806             }
1807         }
1808         Ok(())
1809     }
1810 
1811     /// Creates a random amount of blocks in this function
1812     fn generate_blocks(&mut self, builder: &mut FunctionBuilder) -> Result<()> {
1813         let extra_block_count = self.param(&self.config.blocks_per_function)?;
1814 
1815         // We must always have at least one block, so we generate the "extra" blocks and add 1 for
1816         // the entry block.
1817         let block_count = 1 + extra_block_count;
1818 
1819         // Blocks need to be sorted in ascending order
1820         self.resources.blocks = (0..block_count)
1821             .map(|i| {
1822                 let is_entry = i == 0;
1823                 let block = builder.create_block();
1824 
1825                 // Optionally mark blocks that are not the entry block as cold
1826                 if !is_entry {
1827                     if bool::arbitrary(self.u)? {
1828                         builder.set_cold_block(block);
1829                     }
1830                 }
1831 
1832                 // The first block has to have the function signature, but for the rest of them we generate
1833                 // a random signature;
1834                 if is_entry {
1835                     builder.append_block_params_for_function_params(block);
1836                     Ok((
1837                         block,
1838                         self.signature.params.iter().map(|a| a.value_type).collect(),
1839                     ))
1840                 } else {
1841                     let sig = self.generate_block_signature()?;
1842                     sig.iter().for_each(|ty| {
1843                         builder.append_block_param(block, *ty);
1844                     });
1845                     Ok((block, sig))
1846                 }
1847             })
1848             .collect::<Result<Vec<_>>>()?;
1849 
1850         // Valid blocks for jump tables have to have no parameters in the signature, and must also
1851         // not be the first block.
1852         self.resources.blocks_without_params = self.resources.blocks[1..]
1853             .iter()
1854             .filter(|(_, sig)| sig.len() == 0)
1855             .map(|(b, _)| *b)
1856             .collect();
1857 
1858         // Compute the block CFG
1859         //
1860         // cranelift-frontend requires us to never generate unreachable blocks
1861         // To ensure this property we start by constructing a main "spine" of blocks. So block1 can
1862         // always jump to block2, and block2 can always jump to block3, etc...
1863         //
1864         // That is not a very interesting CFG, so we introduce variations on that, but always
1865         // ensuring that the property of pointing to the next block is maintained whatever the
1866         // branching mechanism we use.
1867         let blocks = self.resources.blocks.clone();
1868         self.resources.block_terminators = blocks
1869             .iter()
1870             .map(|&(block, _)| {
1871                 let next_block = Block::with_number(block.as_u32() + 1).unwrap();
1872                 let forward_blocks = self.resources.forward_blocks(block);
1873                 let paramless_targets = self.resources.forward_blocks_without_params(block);
1874                 let has_paramless_targets = !paramless_targets.is_empty();
1875                 let next_block_is_paramless = paramless_targets.contains(&next_block);
1876 
1877                 let mut valid_terminators = vec![];
1878 
1879                 if forward_blocks.is_empty() {
1880                     // Return is only valid on the last block.
1881                     valid_terminators.push(BlockTerminatorKind::Return);
1882                 } else {
1883                     // If we have more than one block we can allow terminators that target blocks.
1884                     // TODO: We could add some kind of BrReturn here, to explore edges where we
1885                     // exit in the middle of the function
1886                     valid_terminators.extend_from_slice(&[
1887                         BlockTerminatorKind::Jump,
1888                         BlockTerminatorKind::Br,
1889                         BlockTerminatorKind::BrTable,
1890                     ]);
1891                 }
1892 
1893                 // As the Switch interface only allows targeting blocks without params we need
1894                 // to ensure that the next block has no params, since that one is guaranteed to be
1895                 // picked in either case.
1896                 if has_paramless_targets && next_block_is_paramless {
1897                     valid_terminators.push(BlockTerminatorKind::Switch);
1898                 }
1899 
1900                 // Tail Calls are a block terminator, so we should insert them as any other block
1901                 // terminator. We should ensure that we can select at least one target before considering
1902                 // them as candidate instructions.
1903                 let has_tail_callees = self
1904                     .resources
1905                     .tail_call_targets(&self.signature)
1906                     .next()
1907                     .is_some();
1908                 let is_tail_caller = self.signature.call_conv == CallConv::Tail;
1909 
1910                 let supports_tail_calls = match self.isa.triple().architecture {
1911                     Architecture::Aarch64(_) | Architecture::Riscv64(_) => true,
1912                     // TODO: x64 currently requires frame pointers for tail calls.
1913                     Architecture::X86_64 => self.isa.flags().preserve_frame_pointers(),
1914                     // TODO: Other platforms do not support tail calls yet.
1915                     _ => false,
1916                 };
1917 
1918                 if is_tail_caller && has_tail_callees && supports_tail_calls {
1919                     valid_terminators.extend([
1920                         BlockTerminatorKind::TailCall,
1921                         BlockTerminatorKind::TailCallIndirect,
1922                     ]);
1923                 }
1924 
1925                 let terminator = self.u.choose(&valid_terminators)?;
1926 
1927                 // Choose block targets for the terminators that we picked above
1928                 Ok(match terminator {
1929                     BlockTerminatorKind::Return => BlockTerminator::Return,
1930                     BlockTerminatorKind::Jump => BlockTerminator::Jump(next_block),
1931                     BlockTerminatorKind::Br => {
1932                         BlockTerminator::Br(next_block, self.generate_target_block(block)?)
1933                     }
1934                     // TODO: Allow generating backwards branches here
1935                     BlockTerminatorKind::BrTable => {
1936                         // Make the default the next block, and then we don't have to worry
1937                         // that we can reach it via the targets
1938                         let default = next_block;
1939 
1940                         let target_count = self.param(&self.config.jump_table_entries)?;
1941                         let targets = Result::from_iter(
1942                             (0..target_count).map(|_| self.generate_target_block(block)),
1943                         )?;
1944 
1945                         BlockTerminator::BrTable(default, targets)
1946                     }
1947                     BlockTerminatorKind::Switch => {
1948                         // Make the default the next block, and then we don't have to worry
1949                         // that we can reach it via the entries below
1950                         let default_block = next_block;
1951 
1952                         let _type = *self.u.choose(&[I8, I16, I32, I64, I128][..])?;
1953 
1954                         // Build this into a HashMap since we cannot have duplicate entries.
1955                         let mut entries = HashMap::new();
1956                         for _ in 0..self.param(&self.config.switch_cases)? {
1957                             // The Switch API only allows for entries that are addressable by the index type
1958                             // so we need to limit the range of values that we generate.
1959                             let (ty_min, ty_max) = _type.bounds(false);
1960                             let range_start = self.u.int_in_range(ty_min..=ty_max)?;
1961 
1962                             // We can either insert a contiguous range of blocks or a individual block
1963                             // This is done because the Switch API specializes contiguous ranges.
1964                             let range_size = if bool::arbitrary(self.u)? {
1965                                 1
1966                             } else {
1967                                 self.param(&self.config.switch_max_range_size)?
1968                             } as u128;
1969 
1970                             // Build the switch entries
1971                             for i in 0..range_size {
1972                                 let index = range_start.wrapping_add(i) % ty_max;
1973                                 let block = *self
1974                                     .u
1975                                     .choose(self.resources.forward_blocks_without_params(block))?;
1976 
1977                                 entries.insert(index, block);
1978                             }
1979                         }
1980 
1981                         BlockTerminator::Switch(_type, default_block, entries)
1982                     }
1983                     BlockTerminatorKind::TailCall => {
1984                         let targets = self
1985                             .resources
1986                             .tail_call_targets(&self.signature)
1987                             .collect::<Vec<_>>();
1988                         let (_, _, funcref) = *self.u.choose(&targets[..])?;
1989                         BlockTerminator::TailCall(*funcref)
1990                     }
1991                     BlockTerminatorKind::TailCallIndirect => {
1992                         let targets = self
1993                             .resources
1994                             .tail_call_targets(&self.signature)
1995                             .collect::<Vec<_>>();
1996                         let (_, _, funcref) = *self.u.choose(&targets[..])?;
1997                         BlockTerminator::TailCallIndirect(*funcref)
1998                     }
1999                 })
2000             })
2001             .collect::<Result<_>>()?;
2002 
2003         Ok(())
2004     }
2005 
2006     fn generate_block_signature(&mut self) -> Result<BlockSignature> {
2007         let param_count = self.param(&self.config.block_signature_params)?;
2008 
2009         let mut params = Vec::with_capacity(param_count);
2010         for _ in 0..param_count {
2011             params.push(self.u._type(self.isa.triple().architecture)?);
2012         }
2013         Ok(params)
2014     }
2015 
2016     fn build_variable_pool(&mut self, builder: &mut FunctionBuilder) -> Result<()> {
2017         let block = builder.current_block().unwrap();
2018 
2019         // Define variables for the function signature
2020         let mut vars: Vec<_> = builder
2021             .func
2022             .signature
2023             .params
2024             .iter()
2025             .map(|param| param.value_type)
2026             .zip(builder.block_params(block).iter().copied())
2027             .collect();
2028 
2029         // Create a pool of vars that are going to be used in this function
2030         for _ in 0..self.param(&self.config.vars_per_function)? {
2031             let ty = self.u._type(self.isa.triple().architecture)?;
2032             let value = self.generate_const(builder, ty)?;
2033             vars.push((ty, value));
2034         }
2035 
2036         for (id, (ty, value)) in vars.into_iter().enumerate() {
2037             let var = Variable::new(id);
2038             builder.declare_var(var, ty);
2039             builder.def_var(var, value);
2040             self.resources
2041                 .vars
2042                 .entry(ty)
2043                 .or_insert_with(Vec::new)
2044                 .push(var);
2045         }
2046 
2047         Ok(())
2048     }
2049 
2050     /// We generate a function in multiple stages:
2051     ///
2052     /// * First we generate a random number of empty blocks
2053     /// * Then we generate a random pool of variables to be used throughout the function
2054     /// * We then visit each block and generate random instructions
2055     ///
2056     /// Because we generate all blocks and variables up front we already know everything that
2057     /// we need when generating instructions (i.e. jump targets / variables)
2058     pub fn generate(mut self) -> Result<Function> {
2059         let mut fn_builder_ctx = FunctionBuilderContext::new();
2060         let mut func = Function::with_name_signature(self.name.clone(), self.signature.clone());
2061 
2062         let mut builder = FunctionBuilder::new(&mut func, &mut fn_builder_ctx);
2063 
2064         // Build the function references before generating the block CFG since we store
2065         // function references in the CFG.
2066         self.generate_funcrefs(&mut builder)?;
2067         self.generate_blocks(&mut builder)?;
2068 
2069         // Function preamble
2070         self.generate_stack_slots(&mut builder)?;
2071 
2072         // Main instruction generation loop
2073         for (block, block_sig) in self.resources.blocks.clone().into_iter() {
2074             let is_block0 = block.as_u32() == 0;
2075             builder.switch_to_block(block);
2076 
2077             if is_block0 {
2078                 // The first block is special because we must create variables both for the
2079                 // block signature and for the variable pool. Additionally, we must also define
2080                 // initial values for all variables that are not the function signature.
2081                 self.build_variable_pool(&mut builder)?;
2082 
2083                 // Stack slots have random bytes at the beginning of the function
2084                 // initialize them to a constant value so that execution stays predictable.
2085                 self.initialize_stack_slots(&mut builder)?;
2086             } else {
2087                 // Define variables for the block params
2088                 for (i, ty) in block_sig.iter().enumerate() {
2089                     let var = self.get_variable_of_type(*ty)?;
2090                     let block_param = builder.block_params(block)[i];
2091                     builder.def_var(var, block_param);
2092                 }
2093             }
2094 
2095             // Generate block instructions
2096             self.generate_instructions(&mut builder)?;
2097 
2098             // Insert a terminator to safely exit the block
2099             self.insert_terminator(&mut builder, block)?;
2100         }
2101 
2102         builder.seal_all_blocks();
2103         builder.finalize();
2104 
2105         Ok(func)
2106     }
2107 }
2108