1 //! Instruction formats and opcodes.
2 //!
3 //! The `instructions` module contains definitions for instruction formats, opcodes, and the
4 //! in-memory representation of IR instructions.
5 //!
6 //! A large part of this module is auto-generated from the instruction descriptions in the meta
7 //! directory.
8 
9 use alloc::vec::Vec;
10 use core::convert::{TryFrom, TryInto};
11 use core::fmt::{self, Display, Formatter};
12 use core::num::NonZeroU32;
13 use core::ops::{Deref, DerefMut};
14 use core::str::FromStr;
15 
16 #[cfg(feature = "enable-serde")]
17 use serde::{Deserialize, Serialize};
18 
19 use crate::bitset::BitSet;
20 use crate::data_value::DataValue;
21 use crate::entity;
22 use crate::ir::{
23     self,
24     condcodes::{FloatCC, IntCC},
25     trapcode::TrapCode,
26     types, Block, FuncRef, JumpTable, MemFlags, SigRef, StackSlot, Type, Value,
27 };
28 
29 /// Some instructions use an external list of argument values because there is not enough space in
30 /// the 16-byte `InstructionData` struct. These value lists are stored in a memory pool in
31 /// `dfg.value_lists`.
32 pub type ValueList = entity::EntityList<Value>;
33 
34 /// Memory pool for holding value lists. See `ValueList`.
35 pub type ValueListPool = entity::ListPool<Value>;
36 
37 // Include code generated by `cranelift-codegen/meta/src/gen_inst.rs`. This file contains:
38 //
39 // - The `pub enum InstructionFormat` enum with all the instruction formats.
40 // - The `pub enum InstructionData` enum with all the instruction data fields.
41 // - The `pub enum Opcode` definition with all known opcodes,
42 // - The `const OPCODE_FORMAT: [InstructionFormat; N]` table.
43 // - The private `fn opcode_name(Opcode) -> &'static str` function, and
44 // - The hash table `const OPCODE_HASH_TABLE: [Opcode; N]`.
45 //
46 // For value type constraints:
47 //
48 // - The `const OPCODE_CONSTRAINTS : [OpcodeConstraints; N]` table.
49 // - The `const TYPE_SETS : [ValueTypeSet; N]` table.
50 // - The `const OPERAND_CONSTRAINTS : [OperandConstraint; N]` table.
51 //
52 include!(concat!(env!("OUT_DIR"), "/opcodes.rs"));
53 
54 impl Display for Opcode {
55     fn fmt(&self, f: &mut Formatter) -> fmt::Result {
56         write!(f, "{}", opcode_name(*self))
57     }
58 }
59 
60 impl Opcode {
61     /// Get the instruction format for this opcode.
62     pub fn format(self) -> InstructionFormat {
63         OPCODE_FORMAT[self as usize - 1]
64     }
65 
66     /// Get the constraint descriptor for this opcode.
67     /// Panic if this is called on `NotAnOpcode`.
68     pub fn constraints(self) -> OpcodeConstraints {
69         OPCODE_CONSTRAINTS[self as usize - 1]
70     }
71 
72     /// Returns true if the instruction is a resumable trap.
73     pub fn is_resumable_trap(&self) -> bool {
74         match self {
75             Opcode::ResumableTrap | Opcode::ResumableTrapnz => true,
76             _ => false,
77         }
78     }
79 }
80 
81 impl TryFrom<NonZeroU32> for Opcode {
82     type Error = ();
83 
84     #[inline]
85     fn try_from(x: NonZeroU32) -> Result<Self, ()> {
86         let x: u16 = x.get().try_into().map_err(|_| ())?;
87         Self::try_from(x)
88     }
89 }
90 
91 impl From<Opcode> for NonZeroU32 {
92     #[inline]
93     fn from(op: Opcode) -> NonZeroU32 {
94         let x = op as u8;
95         NonZeroU32::new(x as u32).unwrap()
96     }
97 }
98 
99 // This trait really belongs in cranelift-reader where it is used by the `.clif` file parser, but since
100 // it critically depends on the `opcode_name()` function which is needed here anyway, it lives in
101 // this module. This also saves us from running the build script twice to generate code for the two
102 // separate crates.
103 impl FromStr for Opcode {
104     type Err = &'static str;
105 
106     /// Parse an Opcode name from a string.
107     fn from_str(s: &str) -> Result<Self, &'static str> {
108         use crate::constant_hash::{probe, simple_hash, Table};
109 
110         impl<'a> Table<&'a str> for [Option<Opcode>] {
111             fn len(&self) -> usize {
112                 self.len()
113             }
114 
115             fn key(&self, idx: usize) -> Option<&'a str> {
116                 self[idx].map(opcode_name)
117             }
118         }
119 
120         match probe::<&str, [Option<Self>]>(&OPCODE_HASH_TABLE, s, simple_hash(s)) {
121             Err(_) => Err("Unknown opcode"),
122             // We unwrap here because probe() should have ensured that the entry
123             // at this index is not None.
124             Ok(i) => Ok(OPCODE_HASH_TABLE[i].unwrap()),
125         }
126     }
127 }
128 
129 /// A variable list of `Value` operands used for function call arguments and passing arguments to
130 /// basic blocks.
131 #[derive(Clone, Debug)]
132 pub struct VariableArgs(Vec<Value>);
133 
134 impl VariableArgs {
135     /// Create an empty argument list.
136     pub fn new() -> Self {
137         Self(Vec::new())
138     }
139 
140     /// Add an argument to the end.
141     pub fn push(&mut self, v: Value) {
142         self.0.push(v)
143     }
144 
145     /// Check if the list is empty.
146     pub fn is_empty(&self) -> bool {
147         self.0.is_empty()
148     }
149 
150     /// Convert this to a value list in `pool` with `fixed` prepended.
151     pub fn into_value_list(self, fixed: &[Value], pool: &mut ValueListPool) -> ValueList {
152         let mut vlist = ValueList::default();
153         vlist.extend(fixed.iter().cloned(), pool);
154         vlist.extend(self.0, pool);
155         vlist
156     }
157 }
158 
159 // Coerce `VariableArgs` into a `&[Value]` slice.
160 impl Deref for VariableArgs {
161     type Target = [Value];
162 
163     fn deref(&self) -> &[Value] {
164         &self.0
165     }
166 }
167 
168 impl DerefMut for VariableArgs {
169     fn deref_mut(&mut self) -> &mut [Value] {
170         &mut self.0
171     }
172 }
173 
174 impl Display for VariableArgs {
175     fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
176         for (i, val) in self.0.iter().enumerate() {
177             if i == 0 {
178                 write!(fmt, "{}", val)?;
179             } else {
180                 write!(fmt, ", {}", val)?;
181             }
182         }
183         Ok(())
184     }
185 }
186 
187 impl Default for VariableArgs {
188     fn default() -> Self {
189         Self::new()
190     }
191 }
192 
193 /// Analyzing an instruction.
194 ///
195 /// Avoid large matches on instruction formats by using the methods defined here to examine
196 /// instructions.
197 impl InstructionData {
198     /// Return information about the destination of a branch or jump instruction.
199     ///
200     /// Any instruction that can transfer control to another block reveals its possible destinations
201     /// here.
202     pub fn analyze_branch<'a>(&'a self, pool: &'a ValueListPool) -> BranchInfo<'a> {
203         match *self {
204             Self::Jump {
205                 destination,
206                 ref args,
207                 ..
208             } => BranchInfo::SingleDest(destination, args.as_slice(pool)),
209             Self::BranchInt {
210                 destination,
211                 ref args,
212                 ..
213             }
214             | Self::BranchFloat {
215                 destination,
216                 ref args,
217                 ..
218             }
219             | Self::Branch {
220                 destination,
221                 ref args,
222                 ..
223             } => BranchInfo::SingleDest(destination, &args.as_slice(pool)[1..]),
224             Self::BranchIcmp {
225                 destination,
226                 ref args,
227                 ..
228             } => BranchInfo::SingleDest(destination, &args.as_slice(pool)[2..]),
229             Self::BranchTable {
230                 table, destination, ..
231             } => BranchInfo::Table(table, Some(destination)),
232             _ => {
233                 debug_assert!(!self.opcode().is_branch());
234                 BranchInfo::NotABranch
235             }
236         }
237     }
238 
239     /// Get the single destination of this branch instruction, if it is a single destination
240     /// branch or jump.
241     ///
242     /// Multi-destination branches like `br_table` return `None`.
243     pub fn branch_destination(&self) -> Option<Block> {
244         match *self {
245             Self::Jump { destination, .. }
246             | Self::Branch { destination, .. }
247             | Self::BranchInt { destination, .. }
248             | Self::BranchFloat { destination, .. }
249             | Self::BranchIcmp { destination, .. } => Some(destination),
250             Self::BranchTable { .. } => None,
251             _ => {
252                 debug_assert!(!self.opcode().is_branch());
253                 None
254             }
255         }
256     }
257 
258     /// Get a mutable reference to the single destination of this branch instruction, if it is a
259     /// single destination branch or jump.
260     ///
261     /// Multi-destination branches like `br_table` return `None`.
262     pub fn branch_destination_mut(&mut self) -> Option<&mut Block> {
263         match *self {
264             Self::Jump {
265                 ref mut destination,
266                 ..
267             }
268             | Self::Branch {
269                 ref mut destination,
270                 ..
271             }
272             | Self::BranchInt {
273                 ref mut destination,
274                 ..
275             }
276             | Self::BranchFloat {
277                 ref mut destination,
278                 ..
279             }
280             | Self::BranchIcmp {
281                 ref mut destination,
282                 ..
283             } => Some(destination),
284             Self::BranchTable { .. } => None,
285             _ => {
286                 debug_assert!(!self.opcode().is_branch());
287                 None
288             }
289         }
290     }
291 
292     /// Return the value of an immediate if the instruction has one or `None` otherwise. Only
293     /// immediate values are considered, not global values, constant handles, condition codes, etc.
294     pub fn imm_value(&self) -> Option<DataValue> {
295         match self {
296             &InstructionData::UnaryBool { imm, .. } => Some(DataValue::from(imm)),
297             // 8-bit.
298             &InstructionData::BinaryImm8 { imm, .. }
299             | &InstructionData::TernaryImm8 { imm, .. } => Some(DataValue::from(imm as i8)), // Note the switch from unsigned to signed.
300             // 32-bit
301             &InstructionData::UnaryIeee32 { imm, .. } => Some(DataValue::from(imm)),
302             &InstructionData::HeapAddr { imm, .. } => {
303                 let imm: u32 = imm.into();
304                 Some(DataValue::from(imm as i32)) // Note the switch from unsigned to signed.
305             }
306             &InstructionData::Load { offset, .. }
307             | &InstructionData::Store { offset, .. }
308             | &InstructionData::StackLoad { offset, .. }
309             | &InstructionData::StackStore { offset, .. }
310             | &InstructionData::TableAddr { offset, .. } => Some(DataValue::from(offset)),
311             // 64-bit.
312             &InstructionData::UnaryImm { imm, .. }
313             | &InstructionData::BinaryImm64 { imm, .. }
314             | &InstructionData::IntCompareImm { imm, .. } => Some(DataValue::from(imm.bits())),
315             &InstructionData::UnaryIeee64 { imm, .. } => Some(DataValue::from(imm)),
316             // 128-bit; though these immediates are present logically in the IR they are not
317             // included in the `InstructionData` for memory-size reasons. This case, returning
318             // `None`, is left here to alert users of this method that they should retrieve the
319             // value using the `DataFlowGraph`.
320             &InstructionData::Shuffle { imm: _, .. } => None,
321             _ => None,
322         }
323     }
324 
325     /// If this is a trapping instruction, get its trap code. Otherwise, return
326     /// `None`.
327     pub fn trap_code(&self) -> Option<TrapCode> {
328         match *self {
329             Self::CondTrap { code, .. }
330             | Self::FloatCondTrap { code, .. }
331             | Self::IntCondTrap { code, .. }
332             | Self::Trap { code, .. } => Some(code),
333             _ => None,
334         }
335     }
336 
337     /// If this is a control-flow instruction depending on an integer condition, gets its
338     /// condition.  Otherwise, return `None`.
339     pub fn cond_code(&self) -> Option<IntCC> {
340         match self {
341             &InstructionData::IntCond { cond, .. }
342             | &InstructionData::BranchIcmp { cond, .. }
343             | &InstructionData::IntCompare { cond, .. }
344             | &InstructionData::IntCondTrap { cond, .. }
345             | &InstructionData::BranchInt { cond, .. }
346             | &InstructionData::IntSelect { cond, .. }
347             | &InstructionData::IntCompareImm { cond, .. } => Some(cond),
348             _ => None,
349         }
350     }
351 
352     /// If this is a control-flow instruction depending on a floating-point condition, gets its
353     /// condition.  Otherwise, return `None`.
354     pub fn fp_cond_code(&self) -> Option<FloatCC> {
355         match self {
356             &InstructionData::BranchFloat { cond, .. }
357             | &InstructionData::FloatCompare { cond, .. }
358             | &InstructionData::FloatCond { cond, .. }
359             | &InstructionData::FloatCondTrap { cond, .. } => Some(cond),
360             _ => None,
361         }
362     }
363 
364     /// If this is a trapping instruction, get an exclusive reference to its
365     /// trap code. Otherwise, return `None`.
366     pub fn trap_code_mut(&mut self) -> Option<&mut TrapCode> {
367         match self {
368             Self::CondTrap { code, .. }
369             | Self::FloatCondTrap { code, .. }
370             | Self::IntCondTrap { code, .. }
371             | Self::Trap { code, .. } => Some(code),
372             _ => None,
373         }
374     }
375 
376     /// If this is an atomic read/modify/write instruction, return its subopcode.
377     pub fn atomic_rmw_op(&self) -> Option<ir::AtomicRmwOp> {
378         match self {
379             &InstructionData::AtomicRmw { op, .. } => Some(op),
380             _ => None,
381         }
382     }
383 
384     /// If this is a load/store instruction, returns its immediate offset.
385     pub fn load_store_offset(&self) -> Option<i32> {
386         match self {
387             &InstructionData::Load { offset, .. }
388             | &InstructionData::StackLoad { offset, .. }
389             | &InstructionData::Store { offset, .. }
390             | &InstructionData::StackStore { offset, .. } => Some(offset.into()),
391             _ => None,
392         }
393     }
394 
395     /// If this is a load/store instruction, return its memory flags.
396     pub fn memflags(&self) -> Option<MemFlags> {
397         match self {
398             &InstructionData::Load { flags, .. }
399             | &InstructionData::LoadNoOffset { flags, .. }
400             | &InstructionData::Store { flags, .. }
401             | &InstructionData::StoreNoOffset { flags, .. } => Some(flags),
402             _ => None,
403         }
404     }
405 
406     /// If this instruction references a stack slot, return it
407     pub fn stack_slot(&self) -> Option<StackSlot> {
408         match self {
409             &InstructionData::StackStore { stack_slot, .. }
410             | &InstructionData::StackLoad { stack_slot, .. } => Some(stack_slot),
411             _ => None,
412         }
413     }
414 
415     /// Return information about a call instruction.
416     ///
417     /// Any instruction that can call another function reveals its call signature here.
418     pub fn analyze_call<'a>(&'a self, pool: &'a ValueListPool) -> CallInfo<'a> {
419         match *self {
420             Self::Call {
421                 func_ref, ref args, ..
422             } => CallInfo::Direct(func_ref, args.as_slice(pool)),
423             Self::CallIndirect {
424                 sig_ref, ref args, ..
425             } => CallInfo::Indirect(sig_ref, &args.as_slice(pool)[1..]),
426             _ => {
427                 debug_assert!(!self.opcode().is_call());
428                 CallInfo::NotACall
429             }
430         }
431     }
432 
433     #[inline]
434     pub(crate) fn sign_extend_immediates(&mut self, ctrl_typevar: Type) {
435         if ctrl_typevar.is_invalid() {
436             return;
437         }
438 
439         let bit_width = ctrl_typevar.bits();
440 
441         match self {
442             Self::BinaryImm64 {
443                 opcode,
444                 arg: _,
445                 imm,
446             } => {
447                 if *opcode == Opcode::SdivImm || *opcode == Opcode::SremImm {
448                     imm.sign_extend_from_width(bit_width);
449                 }
450             }
451             Self::IntCompareImm {
452                 opcode,
453                 arg: _,
454                 cond,
455                 imm,
456             } => {
457                 debug_assert_eq!(*opcode, Opcode::IcmpImm);
458                 if cond.unsigned() != *cond {
459                     imm.sign_extend_from_width(bit_width);
460                 }
461             }
462             _ => {}
463         }
464     }
465 }
466 
467 /// Information about branch and jump instructions.
468 pub enum BranchInfo<'a> {
469     /// This is not a branch or jump instruction.
470     /// This instruction will not transfer control to another block in the function, but it may still
471     /// affect control flow by returning or trapping.
472     NotABranch,
473 
474     /// This is a branch or jump to a single destination block, possibly taking value arguments.
475     SingleDest(Block, &'a [Value]),
476 
477     /// This is a jump table branch which can have many destination blocks and maybe one default block.
478     Table(JumpTable, Option<Block>),
479 }
480 
481 /// Information about call instructions.
482 pub enum CallInfo<'a> {
483     /// This is not a call instruction.
484     NotACall,
485 
486     /// This is a direct call to an external function declared in the preamble. See
487     /// `DataFlowGraph.ext_funcs`.
488     Direct(FuncRef, &'a [Value]),
489 
490     /// This is an indirect call with the specified signature. See `DataFlowGraph.signatures`.
491     Indirect(SigRef, &'a [Value]),
492 }
493 
494 /// Value type constraints for a given opcode.
495 ///
496 /// The `InstructionFormat` determines the constraints on most operands, but `Value` operands and
497 /// results are not determined by the format. Every `Opcode` has an associated
498 /// `OpcodeConstraints` object that provides the missing details.
499 #[derive(Clone, Copy)]
500 pub struct OpcodeConstraints {
501     /// Flags for this opcode encoded as a bit field:
502     ///
503     /// Bits 0-2:
504     ///     Number of fixed result values. This does not include `variable_args` results as are
505     ///     produced by call instructions.
506     ///
507     /// Bit 3:
508     ///     This opcode is polymorphic and the controlling type variable can be inferred from the
509     ///     designated input operand. This is the `typevar_operand` index given to the
510     ///     `InstructionFormat` meta language object. When this bit is not set, the controlling
511     ///     type variable must be the first output value instead.
512     ///
513     /// Bit 4:
514     ///     This opcode is polymorphic and the controlling type variable does *not* appear as the
515     ///     first result type.
516     ///
517     /// Bits 5-7:
518     ///     Number of fixed value arguments. The minimum required number of value operands.
519     flags: u8,
520 
521     /// Permitted set of types for the controlling type variable as an index into `TYPE_SETS`.
522     typeset_offset: u8,
523 
524     /// Offset into `OPERAND_CONSTRAINT` table of the descriptors for this opcode. The first
525     /// `num_fixed_results()` entries describe the result constraints, then follows constraints for
526     /// the fixed `Value` input operands. (`num_fixed_value_arguments()` of them).
527     constraint_offset: u16,
528 }
529 
530 impl OpcodeConstraints {
531     /// Can the controlling type variable for this opcode be inferred from the designated value
532     /// input operand?
533     /// This also implies that this opcode is polymorphic.
534     pub fn use_typevar_operand(self) -> bool {
535         (self.flags & 0x8) != 0
536     }
537 
538     /// Is it necessary to look at the designated value input operand in order to determine the
539     /// controlling type variable, or is it good enough to use the first return type?
540     ///
541     /// Most polymorphic instructions produce a single result with the type of the controlling type
542     /// variable. A few polymorphic instructions either don't produce any results, or produce
543     /// results with a fixed type. These instructions return `true`.
544     pub fn requires_typevar_operand(self) -> bool {
545         (self.flags & 0x10) != 0
546     }
547 
548     /// Get the number of *fixed* result values produced by this opcode.
549     /// This does not include `variable_args` produced by calls.
550     pub fn num_fixed_results(self) -> usize {
551         (self.flags & 0x7) as usize
552     }
553 
554     /// Get the number of *fixed* input values required by this opcode.
555     ///
556     /// This does not include `variable_args` arguments on call and branch instructions.
557     ///
558     /// The number of fixed input values is usually implied by the instruction format, but
559     /// instruction formats that use a `ValueList` put both fixed and variable arguments in the
560     /// list. This method returns the *minimum* number of values required in the value list.
561     pub fn num_fixed_value_arguments(self) -> usize {
562         ((self.flags >> 5) & 0x7) as usize
563     }
564 
565     /// Get the offset into `TYPE_SETS` for the controlling type variable.
566     /// Returns `None` if the instruction is not polymorphic.
567     fn typeset_offset(self) -> Option<usize> {
568         let offset = usize::from(self.typeset_offset);
569         if offset < TYPE_SETS.len() {
570             Some(offset)
571         } else {
572             None
573         }
574     }
575 
576     /// Get the offset into OPERAND_CONSTRAINTS where the descriptors for this opcode begin.
577     fn constraint_offset(self) -> usize {
578         self.constraint_offset as usize
579     }
580 
581     /// Get the value type of result number `n`, having resolved the controlling type variable to
582     /// `ctrl_type`.
583     pub fn result_type(self, n: usize, ctrl_type: Type) -> Type {
584         debug_assert!(n < self.num_fixed_results(), "Invalid result index");
585         if let ResolvedConstraint::Bound(t) =
586             OPERAND_CONSTRAINTS[self.constraint_offset() + n].resolve(ctrl_type)
587         {
588             t
589         } else {
590             panic!("Result constraints can't be free");
591         }
592     }
593 
594     /// Get the value type of input value number `n`, having resolved the controlling type variable
595     /// to `ctrl_type`.
596     ///
597     /// Unlike results, it is possible for some input values to vary freely within a specific
598     /// `ValueTypeSet`. This is represented with the `ArgumentConstraint::Free` variant.
599     pub fn value_argument_constraint(self, n: usize, ctrl_type: Type) -> ResolvedConstraint {
600         debug_assert!(
601             n < self.num_fixed_value_arguments(),
602             "Invalid value argument index"
603         );
604         let offset = self.constraint_offset() + self.num_fixed_results();
605         OPERAND_CONSTRAINTS[offset + n].resolve(ctrl_type)
606     }
607 
608     /// Get the typeset of allowed types for the controlling type variable in a polymorphic
609     /// instruction.
610     pub fn ctrl_typeset(self) -> Option<ValueTypeSet> {
611         self.typeset_offset().map(|offset| TYPE_SETS[offset])
612     }
613 
614     /// Is this instruction polymorphic?
615     pub fn is_polymorphic(self) -> bool {
616         self.ctrl_typeset().is_some()
617     }
618 }
619 
620 type BitSet8 = BitSet<u8>;
621 type BitSet16 = BitSet<u16>;
622 
623 /// A value type set describes the permitted set of types for a type variable.
624 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
625 pub struct ValueTypeSet {
626     /// Allowed lane sizes
627     pub lanes: BitSet16,
628     /// Allowed int widths
629     pub ints: BitSet8,
630     /// Allowed float widths
631     pub floats: BitSet8,
632     /// Allowed bool widths
633     pub bools: BitSet8,
634     /// Allowed ref widths
635     pub refs: BitSet8,
636     /// Allowed dynamic vectors minimum lane sizes
637     pub dynamic_lanes: BitSet16,
638 }
639 
640 impl ValueTypeSet {
641     /// Is `scalar` part of the base type set?
642     ///
643     /// Note that the base type set does not have to be included in the type set proper.
644     fn is_base_type(self, scalar: Type) -> bool {
645         let l2b = scalar.log2_lane_bits();
646         if scalar.is_int() {
647             self.ints.contains(l2b)
648         } else if scalar.is_float() {
649             self.floats.contains(l2b)
650         } else if scalar.is_bool() {
651             self.bools.contains(l2b)
652         } else if scalar.is_ref() {
653             self.refs.contains(l2b)
654         } else {
655             false
656         }
657     }
658 
659     /// Does `typ` belong to this set?
660     pub fn contains(self, typ: Type) -> bool {
661         if typ.is_dynamic_vector() {
662             let l2l = typ.log2_min_lane_count();
663             self.dynamic_lanes.contains(l2l) && self.is_base_type(typ.lane_type())
664         } else {
665             let l2l = typ.log2_lane_count();
666             self.lanes.contains(l2l) && self.is_base_type(typ.lane_type())
667         }
668     }
669 
670     /// Get an example member of this type set.
671     ///
672     /// This is used for error messages to avoid suggesting invalid types.
673     pub fn example(self) -> Type {
674         let t = if self.ints.max().unwrap_or(0) > 5 {
675             types::I32
676         } else if self.floats.max().unwrap_or(0) > 5 {
677             types::F32
678         } else if self.bools.max().unwrap_or(0) > 5 {
679             types::B32
680         } else {
681             types::B1
682         };
683         t.by(1 << self.lanes.min().unwrap()).unwrap()
684     }
685 }
686 
687 /// Operand constraints. This describes the value type constraints on a single `Value` operand.
688 enum OperandConstraint {
689     /// This operand has a concrete value type.
690     Concrete(Type),
691 
692     /// This operand can vary freely within the given type set.
693     /// The type set is identified by its index into the TYPE_SETS constant table.
694     Free(u8),
695 
696     /// This operand is the same type as the controlling type variable.
697     Same,
698 
699     /// This operand is `ctrlType.lane_of()`.
700     LaneOf,
701 
702     /// This operand is `ctrlType.as_bool()`.
703     AsBool,
704 
705     /// This operand is `ctrlType.half_width()`.
706     HalfWidth,
707 
708     /// This operand is `ctrlType.double_width()`.
709     DoubleWidth,
710 
711     /// This operand is `ctrlType.half_vector()`.
712     HalfVector,
713 
714     /// This operand is `ctrlType.double_vector()`.
715     DoubleVector,
716 
717     /// This operand is `ctrlType.split_lanes()`.
718     SplitLanes,
719 
720     /// This operand is `ctrlType.merge_lanes()`.
721     MergeLanes,
722 
723     /// This operands is `ctrlType.dynamic_to_vector()`.
724     DynamicToVector,
725 }
726 
727 impl OperandConstraint {
728     /// Resolve this operand constraint into a concrete value type, given the value of the
729     /// controlling type variable.
730     pub fn resolve(&self, ctrl_type: Type) -> ResolvedConstraint {
731         use self::OperandConstraint::*;
732         use self::ResolvedConstraint::Bound;
733         match *self {
734             Concrete(t) => Bound(t),
735             Free(vts) => ResolvedConstraint::Free(TYPE_SETS[vts as usize]),
736             Same => Bound(ctrl_type),
737             LaneOf => Bound(ctrl_type.lane_of()),
738             AsBool => Bound(ctrl_type.as_bool()),
739             HalfWidth => Bound(ctrl_type.half_width().expect("invalid type for half_width")),
740             DoubleWidth => Bound(
741                 ctrl_type
742                     .double_width()
743                     .expect("invalid type for double_width"),
744             ),
745             HalfVector => Bound(
746                 ctrl_type
747                     .half_vector()
748                     .expect("invalid type for half_vector"),
749             ),
750             DoubleVector => Bound(ctrl_type.by(2).expect("invalid type for double_vector")),
751             SplitLanes => {
752                 if ctrl_type.is_dynamic_vector() {
753                     Bound(
754                         ctrl_type
755                             .dynamic_to_vector()
756                             .expect("invalid type for dynamic_to_vector")
757                             .split_lanes()
758                             .expect("invalid type for split_lanes")
759                             .vector_to_dynamic()
760                             .expect("invalid dynamic type"),
761                     )
762                 } else {
763                     Bound(
764                         ctrl_type
765                             .split_lanes()
766                             .expect("invalid type for split_lanes"),
767                     )
768                 }
769             }
770             MergeLanes => {
771                 if ctrl_type.is_dynamic_vector() {
772                     Bound(
773                         ctrl_type
774                             .dynamic_to_vector()
775                             .expect("invalid type for dynamic_to_vector")
776                             .merge_lanes()
777                             .expect("invalid type for merge_lanes")
778                             .vector_to_dynamic()
779                             .expect("invalid dynamic type"),
780                     )
781                 } else {
782                     Bound(
783                         ctrl_type
784                             .merge_lanes()
785                             .expect("invalid type for merge_lanes"),
786                     )
787                 }
788             }
789             DynamicToVector => Bound(
790                 ctrl_type
791                     .dynamic_to_vector()
792                     .expect("invalid type for dynamic_to_vector"),
793             ),
794         }
795     }
796 }
797 
798 /// The type constraint on a value argument once the controlling type variable is known.
799 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
800 pub enum ResolvedConstraint {
801     /// The operand is bound to a known type.
802     Bound(Type),
803     /// The operand type can vary freely within the given set.
804     Free(ValueTypeSet),
805 }
806 
807 #[cfg(test)]
808 mod tests {
809     use super::*;
810     use alloc::string::ToString;
811 
812     #[test]
813     fn opcodes() {
814         use core::mem;
815 
816         let x = Opcode::Iadd;
817         let mut y = Opcode::Isub;
818 
819         assert!(x != y);
820         y = Opcode::Iadd;
821         assert_eq!(x, y);
822         assert_eq!(x.format(), InstructionFormat::Binary);
823 
824         assert_eq!(format!("{:?}", Opcode::IaddImm), "IaddImm");
825         assert_eq!(Opcode::IaddImm.to_string(), "iadd_imm");
826 
827         // Check the matcher.
828         assert_eq!("iadd".parse::<Opcode>(), Ok(Opcode::Iadd));
829         assert_eq!("iadd_imm".parse::<Opcode>(), Ok(Opcode::IaddImm));
830         assert_eq!("iadd\0".parse::<Opcode>(), Err("Unknown opcode"));
831         assert_eq!("".parse::<Opcode>(), Err("Unknown opcode"));
832         assert_eq!("\0".parse::<Opcode>(), Err("Unknown opcode"));
833 
834         // Opcode is a single byte, and because Option<Opcode> originally came to 2 bytes, early on
835         // Opcode included a variant NotAnOpcode to avoid the unnecessary bloat. Since then the Rust
836         // compiler has brought in NonZero optimization, meaning that an enum not using the 0 value
837         // can be optional for no size cost. We want to ensure Option<Opcode> remains small.
838         assert_eq!(mem::size_of::<Opcode>(), mem::size_of::<Option<Opcode>>());
839     }
840 
841     #[test]
842     fn instruction_data() {
843         use core::mem;
844         // The size of the `InstructionData` enum is important for performance. It should not
845         // exceed 16 bytes. Use `Box<FooData>` out-of-line payloads for instruction formats that
846         // require more space than that. It would be fine with a data structure smaller than 16
847         // bytes, but what are the odds of that?
848         assert_eq!(mem::size_of::<InstructionData>(), 16);
849     }
850 
851     #[test]
852     fn constraints() {
853         let a = Opcode::Iadd.constraints();
854         assert!(a.use_typevar_operand());
855         assert!(!a.requires_typevar_operand());
856         assert_eq!(a.num_fixed_results(), 1);
857         assert_eq!(a.num_fixed_value_arguments(), 2);
858         assert_eq!(a.result_type(0, types::I32), types::I32);
859         assert_eq!(a.result_type(0, types::I8), types::I8);
860         assert_eq!(
861             a.value_argument_constraint(0, types::I32),
862             ResolvedConstraint::Bound(types::I32)
863         );
864         assert_eq!(
865             a.value_argument_constraint(1, types::I32),
866             ResolvedConstraint::Bound(types::I32)
867         );
868 
869         let b = Opcode::Bitcast.constraints();
870         assert!(!b.use_typevar_operand());
871         assert!(!b.requires_typevar_operand());
872         assert_eq!(b.num_fixed_results(), 1);
873         assert_eq!(b.num_fixed_value_arguments(), 1);
874         assert_eq!(b.result_type(0, types::I32), types::I32);
875         assert_eq!(b.result_type(0, types::I8), types::I8);
876         match b.value_argument_constraint(0, types::I32) {
877             ResolvedConstraint::Free(vts) => assert!(vts.contains(types::F32)),
878             _ => panic!("Unexpected constraint from value_argument_constraint"),
879         }
880 
881         let c = Opcode::Call.constraints();
882         assert_eq!(c.num_fixed_results(), 0);
883         assert_eq!(c.num_fixed_value_arguments(), 0);
884 
885         let i = Opcode::CallIndirect.constraints();
886         assert_eq!(i.num_fixed_results(), 0);
887         assert_eq!(i.num_fixed_value_arguments(), 1);
888 
889         let cmp = Opcode::Icmp.constraints();
890         assert!(cmp.use_typevar_operand());
891         assert!(cmp.requires_typevar_operand());
892         assert_eq!(cmp.num_fixed_results(), 1);
893         assert_eq!(cmp.num_fixed_value_arguments(), 2);
894     }
895 
896     #[test]
897     fn value_set() {
898         use crate::ir::types::*;
899 
900         let vts = ValueTypeSet {
901             lanes: BitSet16::from_range(0, 8),
902             ints: BitSet8::from_range(4, 7),
903             floats: BitSet8::from_range(0, 0),
904             bools: BitSet8::from_range(3, 7),
905             refs: BitSet8::from_range(5, 7),
906             dynamic_lanes: BitSet16::from_range(0, 4),
907         };
908         assert!(!vts.contains(I8));
909         assert!(vts.contains(I32));
910         assert!(vts.contains(I64));
911         assert!(vts.contains(I32X4));
912         assert!(vts.contains(I32X4XN));
913         assert!(!vts.contains(F32));
914         assert!(!vts.contains(B1));
915         assert!(vts.contains(B8));
916         assert!(vts.contains(B64));
917         assert!(vts.contains(R32));
918         assert!(vts.contains(R64));
919         assert_eq!(vts.example().to_string(), "i32");
920 
921         let vts = ValueTypeSet {
922             lanes: BitSet16::from_range(0, 8),
923             ints: BitSet8::from_range(0, 0),
924             floats: BitSet8::from_range(5, 7),
925             bools: BitSet8::from_range(3, 7),
926             refs: BitSet8::from_range(0, 0),
927             dynamic_lanes: BitSet16::from_range(0, 8),
928         };
929         assert_eq!(vts.example().to_string(), "f32");
930 
931         let vts = ValueTypeSet {
932             lanes: BitSet16::from_range(1, 8),
933             ints: BitSet8::from_range(0, 0),
934             floats: BitSet8::from_range(5, 7),
935             bools: BitSet8::from_range(3, 7),
936             refs: BitSet8::from_range(0, 0),
937             dynamic_lanes: BitSet16::from_range(0, 8),
938         };
939         assert_eq!(vts.example().to_string(), "f32x2");
940 
941         let vts = ValueTypeSet {
942             lanes: BitSet16::from_range(2, 8),
943             ints: BitSet8::from_range(0, 0),
944             floats: BitSet8::from_range(0, 0),
945             bools: BitSet8::from_range(3, 7),
946             refs: BitSet8::from_range(0, 0),
947             dynamic_lanes: BitSet16::from_range(0, 8),
948         };
949         assert!(!vts.contains(B32X2));
950         assert!(vts.contains(B32X4));
951         assert!(vts.contains(B16X4XN));
952         assert_eq!(vts.example().to_string(), "b32x4");
953 
954         let vts = ValueTypeSet {
955             // TypeSet(lanes=(1, 256), ints=(8, 64))
956             lanes: BitSet16::from_range(0, 9),
957             ints: BitSet8::from_range(3, 7),
958             floats: BitSet8::from_range(0, 0),
959             bools: BitSet8::from_range(0, 0),
960             refs: BitSet8::from_range(0, 0),
961             dynamic_lanes: BitSet16::from_range(0, 8),
962         };
963         assert!(vts.contains(I32));
964         assert!(vts.contains(I32X4));
965         assert!(!vts.contains(R32));
966         assert!(!vts.contains(R64));
967     }
968 }
969