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