1 #![allow(non_snake_case)]
2 
3 use crate::cdsl::instructions::{
4     AllInstructions, InstructionBuilder as Inst, InstructionGroupBuilder,
5 };
6 use crate::cdsl::operands::Operand;
7 use crate::cdsl::types::{LaneType, ValueType};
8 use crate::cdsl::typevar::{Interval, TypeSetBuilder, TypeVar};
9 use crate::shared::formats::Formats;
10 use crate::shared::types;
11 use crate::shared::{entities::EntityRefs, immediates::Immediates};
12 
13 #[inline(never)]
14 fn define_control_flow(
15     ig: &mut InstructionGroupBuilder,
16     formats: &Formats,
17     imm: &Immediates,
18     entities: &EntityRefs,
19 ) {
20     let block = &Operand::new("block", &entities.block).with_doc("Destination basic block");
21     let args = &Operand::new("args", &entities.varargs).with_doc("block arguments");
22 
23     ig.push(
24         Inst::new(
25             "jump",
26             r#"
27         Jump.
28 
29         Unconditionally jump to a basic block, passing the specified
30         block arguments. The number and types of arguments must match the
31         destination block.
32         "#,
33             &formats.jump,
34         )
35         .operands_in(vec![block, args])
36         .is_terminator(true)
37         .is_branch(true),
38     );
39 
40     let Testable = &TypeVar::new(
41         "Testable",
42         "A scalar boolean or integer type",
43         TypeSetBuilder::new()
44             .ints(Interval::All)
45             .bools(Interval::All)
46             .build(),
47     );
48 
49     {
50         let c = &Operand::new("c", Testable).with_doc("Controlling value to test");
51 
52         ig.push(
53             Inst::new(
54                 "brz",
55                 r#"
56         Branch when zero.
57 
58         If ``c`` is a `b1` value, take the branch when ``c`` is false. If
59         ``c`` is an integer value, take the branch when ``c = 0``.
60         "#,
61                 &formats.branch,
62             )
63             .operands_in(vec![c, block, args])
64             .is_branch(true),
65         );
66 
67         ig.push(
68             Inst::new(
69                 "brnz",
70                 r#"
71         Branch when non-zero.
72 
73         If ``c`` is a `b1` value, take the branch when ``c`` is true. If
74         ``c`` is an integer value, take the branch when ``c != 0``.
75         "#,
76                 &formats.branch,
77             )
78             .operands_in(vec![c, block, args])
79             .is_branch(true),
80         );
81     }
82 
83     let iB = &TypeVar::new(
84         "iB",
85         "A scalar integer type",
86         TypeSetBuilder::new().ints(Interval::All).build(),
87     );
88     let iflags: &TypeVar = &ValueType::Special(types::Flag::IFlags.into()).into();
89     let fflags: &TypeVar = &ValueType::Special(types::Flag::FFlags.into()).into();
90 
91     {
92         let Cond = &Operand::new("Cond", &imm.intcc);
93         let x = &Operand::new("x", iB);
94         let y = &Operand::new("y", iB);
95 
96         ig.push(
97             Inst::new(
98                 "br_icmp",
99                 r#"
100         Compare scalar integers and branch.
101 
102         Compare ``x`` and ``y`` in the same way as the `icmp` instruction
103         and take the branch if the condition is true:
104 
105         ```text
106             br_icmp ugt v1, v2, block4(v5, v6)
107         ```
108 
109         is semantically equivalent to:
110 
111         ```text
112             v10 = icmp ugt, v1, v2
113             brnz v10, block4(v5, v6)
114         ```
115 
116         Some RISC architectures like MIPS and RISC-V provide instructions that
117         implement all or some of the condition codes. The instruction can also
118         be used to represent *macro-op fusion* on architectures like Intel's.
119         "#,
120                 &formats.branch_icmp,
121             )
122             .operands_in(vec![Cond, x, y, block, args])
123             .is_branch(true),
124         );
125 
126         let f = &Operand::new("f", iflags);
127 
128         ig.push(
129             Inst::new(
130                 "brif",
131                 r#"
132         Branch when condition is true in integer CPU flags.
133         "#,
134                 &formats.branch_int,
135             )
136             .operands_in(vec![Cond, f, block, args])
137             .is_branch(true),
138         );
139     }
140 
141     {
142         let Cond = &Operand::new("Cond", &imm.floatcc);
143 
144         let f = &Operand::new("f", fflags);
145 
146         ig.push(
147             Inst::new(
148                 "brff",
149                 r#"
150         Branch when condition is true in floating point CPU flags.
151         "#,
152                 &formats.branch_float,
153             )
154             .operands_in(vec![Cond, f, block, args])
155             .is_branch(true),
156         );
157     }
158 
159     {
160         let _i32 = &TypeVar::new(
161             "i32",
162             "A 32 bit scalar integer type",
163             TypeSetBuilder::new().ints(32..32).build(),
164         );
165         let x = &Operand::new("x", _i32).with_doc("i32 index into jump table");
166         let JT = &Operand::new("JT", &entities.jump_table);
167 
168         ig.push(
169             Inst::new(
170                 "br_table",
171                 r#"
172         Indirect branch via jump table.
173 
174         Use ``x`` as an unsigned index into the jump table ``JT``. If a jump
175         table entry is found, branch to the corresponding block. If no entry was
176         found or the index is out-of-bounds, branch to the given default block.
177 
178         Note that this branch instruction can't pass arguments to the targeted
179         blocks. Split critical edges as needed to work around this.
180 
181         Do not confuse this with "tables" in WebAssembly. ``br_table`` is for
182         jump tables with destinations within the current function only -- think
183         of a ``match`` in Rust or a ``switch`` in C.  If you want to call a
184         function in a dynamic library, that will typically use
185         ``call_indirect``.
186         "#,
187                 &formats.branch_table,
188             )
189             .operands_in(vec![x, block, JT])
190             .is_terminator(true)
191             .is_branch(true),
192         );
193     }
194 
195     let iAddr = &TypeVar::new(
196         "iAddr",
197         "An integer address type",
198         TypeSetBuilder::new().ints(32..64).refs(32..64).build(),
199     );
200 
201     ig.push(
202         Inst::new(
203             "debugtrap",
204             r#"
205     Encodes an assembly debug trap.
206     "#,
207             &formats.nullary,
208         )
209         .other_side_effects(true)
210         .can_load(true)
211         .can_store(true),
212     );
213 
214     {
215         let code = &Operand::new("code", &imm.trapcode);
216         ig.push(
217             Inst::new(
218                 "trap",
219                 r#"
220         Terminate execution unconditionally.
221         "#,
222                 &formats.trap,
223             )
224             .operands_in(vec![code])
225             .can_trap(true)
226             .is_terminator(true),
227         );
228 
229         let c = &Operand::new("c", Testable).with_doc("Controlling value to test");
230         ig.push(
231             Inst::new(
232                 "trapz",
233                 r#"
234         Trap when zero.
235 
236         if ``c`` is non-zero, execution continues at the following instruction.
237         "#,
238                 &formats.cond_trap,
239             )
240             .operands_in(vec![c, code])
241             .can_trap(true),
242         );
243 
244         ig.push(
245             Inst::new(
246                 "resumable_trap",
247                 r#"
248         A resumable trap.
249 
250         This instruction allows non-conditional traps to be used as non-terminal instructions.
251         "#,
252                 &formats.trap,
253             )
254             .operands_in(vec![code])
255             .can_trap(true),
256         );
257 
258         let c = &Operand::new("c", Testable).with_doc("Controlling value to test");
259         ig.push(
260             Inst::new(
261                 "trapnz",
262                 r#"
263         Trap when non-zero.
264 
265         If ``c`` is zero, execution continues at the following instruction.
266         "#,
267                 &formats.cond_trap,
268             )
269             .operands_in(vec![c, code])
270             .can_trap(true),
271         );
272 
273         ig.push(
274             Inst::new(
275                 "resumable_trapnz",
276                 r#"
277         A resumable trap to be called when the passed condition is non-zero.
278 
279         If ``c`` is zero, execution continues at the following instruction.
280         "#,
281                 &formats.cond_trap,
282             )
283             .operands_in(vec![c, code])
284             .can_trap(true),
285         );
286 
287         let Cond = &Operand::new("Cond", &imm.intcc);
288         let f = &Operand::new("f", iflags);
289         ig.push(
290             Inst::new(
291                 "trapif",
292                 r#"
293         Trap when condition is true in integer CPU flags.
294         "#,
295                 &formats.int_cond_trap,
296             )
297             .operands_in(vec![Cond, f, code])
298             .can_trap(true),
299         );
300 
301         let Cond = &Operand::new("Cond", &imm.floatcc);
302         let f = &Operand::new("f", fflags);
303         let code = &Operand::new("code", &imm.trapcode);
304         ig.push(
305             Inst::new(
306                 "trapff",
307                 r#"
308         Trap when condition is true in floating point CPU flags.
309         "#,
310                 &formats.float_cond_trap,
311             )
312             .operands_in(vec![Cond, f, code])
313             .can_trap(true),
314         );
315     }
316 
317     let rvals = &Operand::new("rvals", &entities.varargs).with_doc("return values");
318     ig.push(
319         Inst::new(
320             "return",
321             r#"
322         Return from the function.
323 
324         Unconditionally transfer control to the calling function, passing the
325         provided return values. The list of return values must match the
326         function signature's return types.
327         "#,
328             &formats.multiary,
329         )
330         .operands_in(vec![rvals])
331         .is_return(true)
332         .is_terminator(true),
333     );
334 
335     let FN = &Operand::new("FN", &entities.func_ref)
336         .with_doc("function to call, declared by `function`");
337     let args = &Operand::new("args", &entities.varargs).with_doc("call arguments");
338     let rvals = &Operand::new("rvals", &entities.varargs).with_doc("return values");
339     ig.push(
340         Inst::new(
341             "call",
342             r#"
343         Direct function call.
344 
345         Call a function which has been declared in the preamble. The argument
346         types must match the function's signature.
347         "#,
348             &formats.call,
349         )
350         .operands_in(vec![FN, args])
351         .operands_out(vec![rvals])
352         .is_call(true),
353     );
354 
355     let SIG = &Operand::new("SIG", &entities.sig_ref).with_doc("function signature");
356     let callee = &Operand::new("callee", iAddr).with_doc("address of function to call");
357     let args = &Operand::new("args", &entities.varargs).with_doc("call arguments");
358     let rvals = &Operand::new("rvals", &entities.varargs).with_doc("return values");
359     ig.push(
360         Inst::new(
361             "call_indirect",
362             r#"
363         Indirect function call.
364 
365         Call the function pointed to by `callee` with the given arguments. The
366         called function must match the specified signature.
367 
368         Note that this is different from WebAssembly's ``call_indirect``; the
369         callee is a native address, rather than a table index. For WebAssembly,
370         `table_addr` and `load` are used to obtain a native address
371         from a table.
372         "#,
373             &formats.call_indirect,
374         )
375         .operands_in(vec![SIG, callee, args])
376         .operands_out(vec![rvals])
377         .is_call(true),
378     );
379 
380     let FN = &Operand::new("FN", &entities.func_ref)
381         .with_doc("function to call, declared by `function`");
382     let addr = &Operand::new("addr", iAddr);
383     ig.push(
384         Inst::new(
385             "func_addr",
386             r#"
387         Get the address of a function.
388 
389         Compute the absolute address of a function declared in the preamble.
390         The returned address can be used as a ``callee`` argument to
391         `call_indirect`. This is also a method for calling functions that
392         are too far away to be addressable by a direct `call`
393         instruction.
394         "#,
395             &formats.func_addr,
396         )
397         .operands_in(vec![FN])
398         .operands_out(vec![addr]),
399     );
400 }
401 
402 #[inline(never)]
403 fn define_simd_lane_access(
404     ig: &mut InstructionGroupBuilder,
405     formats: &Formats,
406     imm: &Immediates,
407     _: &EntityRefs,
408 ) {
409     let TxN = &TypeVar::new(
410         "TxN",
411         "A SIMD vector type",
412         TypeSetBuilder::new()
413             .ints(Interval::All)
414             .floats(Interval::All)
415             .bools(Interval::All)
416             .simd_lanes(Interval::All)
417             .dynamic_simd_lanes(Interval::All)
418             .includes_scalars(false)
419             .build(),
420     );
421 
422     let x = &Operand::new("x", &TxN.lane_of()).with_doc("Value to splat to all lanes");
423     let a = &Operand::new("a", TxN);
424 
425     ig.push(
426         Inst::new(
427             "splat",
428             r#"
429         Vector splat.
430 
431         Return a vector whose lanes are all ``x``.
432         "#,
433             &formats.unary,
434         )
435         .operands_in(vec![x])
436         .operands_out(vec![a]),
437     );
438 
439     let I8x16 = &TypeVar::new(
440         "I8x16",
441         "A SIMD vector type consisting of 16 lanes of 8-bit integers",
442         TypeSetBuilder::new()
443             .ints(8..8)
444             .simd_lanes(16..16)
445             .includes_scalars(false)
446             .build(),
447     );
448     let x = &Operand::new("x", I8x16).with_doc("Vector to modify by re-arranging lanes");
449     let y = &Operand::new("y", I8x16).with_doc("Mask for re-arranging lanes");
450 
451     ig.push(
452         Inst::new(
453             "swizzle",
454             r#"
455         Vector swizzle.
456 
457         Returns a new vector with byte-width lanes selected from the lanes of the first input
458         vector ``x`` specified in the second input vector ``s``. The indices ``i`` in range
459         ``[0, 15]`` select the ``i``-th element of ``x``. For indices outside of the range the
460         resulting lane is 0. Note that this operates on byte-width lanes.
461         "#,
462             &formats.binary,
463         )
464         .operands_in(vec![x, y])
465         .operands_out(vec![a]),
466     );
467 
468     let x = &Operand::new("x", TxN).with_doc("The vector to modify");
469     let y = &Operand::new("y", &TxN.lane_of()).with_doc("New lane value");
470     let Idx = &Operand::new("Idx", &imm.uimm8).with_doc("Lane index");
471 
472     ig.push(
473         Inst::new(
474             "insertlane",
475             r#"
476         Insert ``y`` as lane ``Idx`` in x.
477 
478         The lane index, ``Idx``, is an immediate value, not an SSA value. It
479         must indicate a valid lane index for the type of ``x``.
480         "#,
481             &formats.ternary_imm8,
482         )
483         .operands_in(vec![x, y, Idx])
484         .operands_out(vec![a]),
485     );
486 
487     let x = &Operand::new("x", TxN);
488     let a = &Operand::new("a", &TxN.lane_of());
489 
490     ig.push(
491         Inst::new(
492             "extractlane",
493             r#"
494         Extract lane ``Idx`` from ``x``.
495 
496         The lane index, ``Idx``, is an immediate value, not an SSA value. It
497         must indicate a valid lane index for the type of ``x``. Note that the upper bits of ``a``
498         may or may not be zeroed depending on the ISA but the type system should prevent using
499         ``a`` as anything other than the extracted value.
500         "#,
501             &formats.binary_imm8,
502         )
503         .operands_in(vec![x, Idx])
504         .operands_out(vec![a]),
505     );
506 }
507 
508 #[inline(never)]
509 fn define_simd_arithmetic(
510     ig: &mut InstructionGroupBuilder,
511     formats: &Formats,
512     _: &Immediates,
513     _: &EntityRefs,
514 ) {
515     let Int = &TypeVar::new(
516         "Int",
517         "A scalar or vector integer type",
518         TypeSetBuilder::new()
519             .ints(Interval::All)
520             .simd_lanes(Interval::All)
521             .build(),
522     );
523 
524     let a = &Operand::new("a", Int);
525     let x = &Operand::new("x", Int);
526     let y = &Operand::new("y", Int);
527 
528     ig.push(
529         Inst::new(
530             "imin",
531             r#"
532         Signed integer minimum.
533         "#,
534             &formats.binary,
535         )
536         .operands_in(vec![x, y])
537         .operands_out(vec![a]),
538     );
539 
540     ig.push(
541         Inst::new(
542             "umin",
543             r#"
544         Unsigned integer minimum.
545         "#,
546             &formats.binary,
547         )
548         .operands_in(vec![x, y])
549         .operands_out(vec![a]),
550     );
551 
552     ig.push(
553         Inst::new(
554             "imax",
555             r#"
556         Signed integer maximum.
557         "#,
558             &formats.binary,
559         )
560         .operands_in(vec![x, y])
561         .operands_out(vec![a]),
562     );
563 
564     ig.push(
565         Inst::new(
566             "umax",
567             r#"
568         Unsigned integer maximum.
569         "#,
570             &formats.binary,
571         )
572         .operands_in(vec![x, y])
573         .operands_out(vec![a]),
574     );
575 
576     let IxN = &TypeVar::new(
577         "IxN",
578         "A SIMD vector type containing integers",
579         TypeSetBuilder::new()
580             .ints(Interval::All)
581             .simd_lanes(Interval::All)
582             .includes_scalars(false)
583             .build(),
584     );
585 
586     let a = &Operand::new("a", IxN);
587     let x = &Operand::new("x", IxN);
588     let y = &Operand::new("y", IxN);
589 
590     ig.push(
591         Inst::new(
592             "avg_round",
593             r#"
594         Unsigned average with rounding: `a := (x + y + 1) // 2`
595 
596         The addition does not lose any information (such as from overflow).
597         "#,
598             &formats.binary,
599         )
600         .operands_in(vec![x, y])
601         .operands_out(vec![a]),
602     );
603 
604     ig.push(
605         Inst::new(
606             "uadd_sat",
607             r#"
608         Add with unsigned saturation.
609 
610         This is similar to `iadd` but the operands are interpreted as unsigned integers and their
611         summed result, instead of wrapping, will be saturated to the highest unsigned integer for
612         the controlling type (e.g. `0xFF` for i8).
613         "#,
614             &formats.binary,
615         )
616         .operands_in(vec![x, y])
617         .operands_out(vec![a]),
618     );
619 
620     ig.push(
621         Inst::new(
622             "sadd_sat",
623             r#"
624         Add with signed saturation.
625 
626         This is similar to `iadd` but the operands are interpreted as signed integers and their
627         summed result, instead of wrapping, will be saturated to the lowest or highest
628         signed integer for the controlling type (e.g. `0x80` or `0x7F` for i8). For example,
629         since an `sadd_sat.i8` of `0x70` and `0x70` is greater than `0x7F`, the result will be
630         clamped to `0x7F`.
631         "#,
632             &formats.binary,
633         )
634         .operands_in(vec![x, y])
635         .operands_out(vec![a]),
636     );
637 
638     ig.push(
639         Inst::new(
640             "usub_sat",
641             r#"
642         Subtract with unsigned saturation.
643 
644         This is similar to `isub` but the operands are interpreted as unsigned integers and their
645         difference, instead of wrapping, will be saturated to the lowest unsigned integer for
646         the controlling type (e.g. `0x00` for i8).
647         "#,
648             &formats.binary,
649         )
650         .operands_in(vec![x, y])
651         .operands_out(vec![a]),
652     );
653 
654     ig.push(
655         Inst::new(
656             "ssub_sat",
657             r#"
658         Subtract with signed saturation.
659 
660         This is similar to `isub` but the operands are interpreted as signed integers and their
661         difference, instead of wrapping, will be saturated to the lowest or highest
662         signed integer for the controlling type (e.g. `0x80` or `0x7F` for i8).
663         "#,
664             &formats.binary,
665         )
666         .operands_in(vec![x, y])
667         .operands_out(vec![a]),
668     );
669 }
670 
671 #[allow(clippy::many_single_char_names)]
672 pub(crate) fn define(
673     all_instructions: &mut AllInstructions,
674     formats: &Formats,
675     imm: &Immediates,
676     entities: &EntityRefs,
677 ) {
678     let mut ig = InstructionGroupBuilder::new(all_instructions);
679 
680     define_control_flow(&mut ig, formats, imm, entities);
681     define_simd_lane_access(&mut ig, formats, imm, entities);
682     define_simd_arithmetic(&mut ig, formats, imm, entities);
683 
684     // Operand kind shorthands.
685     let iflags: &TypeVar = &ValueType::Special(types::Flag::IFlags.into()).into();
686     let fflags: &TypeVar = &ValueType::Special(types::Flag::FFlags.into()).into();
687 
688     let b1: &TypeVar = &ValueType::from(LaneType::from(types::Bool::B1)).into();
689     let f32_: &TypeVar = &ValueType::from(LaneType::from(types::Float::F32)).into();
690     let f64_: &TypeVar = &ValueType::from(LaneType::from(types::Float::F64)).into();
691 
692     // Starting definitions.
693     let Int = &TypeVar::new(
694         "Int",
695         "A scalar or vector integer type",
696         TypeSetBuilder::new()
697             .ints(Interval::All)
698             .simd_lanes(Interval::All)
699             .dynamic_simd_lanes(Interval::All)
700             .build(),
701     );
702 
703     let Bool = &TypeVar::new(
704         "Bool",
705         "A scalar or vector boolean type",
706         TypeSetBuilder::new()
707             .bools(Interval::All)
708             .simd_lanes(Interval::All)
709             .build(),
710     );
711 
712     let ScalarBool = &TypeVar::new(
713         "ScalarBool",
714         "A scalar boolean type",
715         TypeSetBuilder::new().bools(Interval::All).build(),
716     );
717 
718     let iB = &TypeVar::new(
719         "iB",
720         "A scalar integer type",
721         TypeSetBuilder::new().ints(Interval::All).build(),
722     );
723 
724     let iAddr = &TypeVar::new(
725         "iAddr",
726         "An integer address type",
727         TypeSetBuilder::new().ints(32..64).refs(32..64).build(),
728     );
729 
730     let Ref = &TypeVar::new(
731         "Ref",
732         "A scalar reference type",
733         TypeSetBuilder::new().refs(Interval::All).build(),
734     );
735 
736     let Testable = &TypeVar::new(
737         "Testable",
738         "A scalar boolean or integer type",
739         TypeSetBuilder::new()
740             .ints(Interval::All)
741             .bools(Interval::All)
742             .build(),
743     );
744 
745     let TxN = &TypeVar::new(
746         "TxN",
747         "A SIMD vector type",
748         TypeSetBuilder::new()
749             .ints(Interval::All)
750             .floats(Interval::All)
751             .bools(Interval::All)
752             .simd_lanes(Interval::All)
753             .includes_scalars(false)
754             .build(),
755     );
756     let Any = &TypeVar::new(
757         "Any",
758         "Any integer, float, boolean, or reference scalar or vector type",
759         TypeSetBuilder::new()
760             .ints(Interval::All)
761             .floats(Interval::All)
762             .bools(Interval::All)
763             .refs(Interval::All)
764             .simd_lanes(Interval::All)
765             .includes_scalars(true)
766             .build(),
767     );
768 
769     let AnyTo = &TypeVar::copy_from(Any, "AnyTo".to_string());
770 
771     let Mem = &TypeVar::new(
772         "Mem",
773         "Any type that can be stored in memory",
774         TypeSetBuilder::new()
775             .ints(Interval::All)
776             .floats(Interval::All)
777             .simd_lanes(Interval::All)
778             .refs(Interval::All)
779             .dynamic_simd_lanes(Interval::All)
780             .build(),
781     );
782 
783     let MemTo = &TypeVar::copy_from(Mem, "MemTo".to_string());
784 
785     let addr = &Operand::new("addr", iAddr);
786 
787     let SS = &Operand::new("SS", &entities.stack_slot);
788     let DSS = &Operand::new("DSS", &entities.dynamic_stack_slot);
789     let Offset = &Operand::new("Offset", &imm.offset32).with_doc("Byte offset from base address");
790     let x = &Operand::new("x", Mem).with_doc("Value to be stored");
791     let a = &Operand::new("a", Mem).with_doc("Value loaded");
792     let p = &Operand::new("p", iAddr);
793     let MemFlags = &Operand::new("MemFlags", &imm.memflags);
794 
795     ig.push(
796         Inst::new(
797             "load",
798             r#"
799         Load from memory at ``p + Offset``.
800 
801         This is a polymorphic instruction that can load any value type which
802         has a memory representation.
803         "#,
804             &formats.load,
805         )
806         .operands_in(vec![MemFlags, p, Offset])
807         .operands_out(vec![a])
808         .can_load(true),
809     );
810 
811     ig.push(
812         Inst::new(
813             "store",
814             r#"
815         Store ``x`` to memory at ``p + Offset``.
816 
817         This is a polymorphic instruction that can store any value type with a
818         memory representation.
819         "#,
820             &formats.store,
821         )
822         .operands_in(vec![MemFlags, x, p, Offset])
823         .can_store(true),
824     );
825 
826     let iExt8 = &TypeVar::new(
827         "iExt8",
828         "An integer type with more than 8 bits",
829         TypeSetBuilder::new().ints(16..64).build(),
830     );
831     let x = &Operand::new("x", iExt8);
832     let a = &Operand::new("a", iExt8);
833 
834     ig.push(
835         Inst::new(
836             "uload8",
837             r#"
838         Load 8 bits from memory at ``p + Offset`` and zero-extend.
839 
840         This is equivalent to ``load.i8`` followed by ``uextend``.
841         "#,
842             &formats.load,
843         )
844         .operands_in(vec![MemFlags, p, Offset])
845         .operands_out(vec![a])
846         .can_load(true),
847     );
848 
849     ig.push(
850         Inst::new(
851             "sload8",
852             r#"
853         Load 8 bits from memory at ``p + Offset`` and sign-extend.
854 
855         This is equivalent to ``load.i8`` followed by ``sextend``.
856         "#,
857             &formats.load,
858         )
859         .operands_in(vec![MemFlags, p, Offset])
860         .operands_out(vec![a])
861         .can_load(true),
862     );
863 
864     ig.push(
865         Inst::new(
866             "istore8",
867             r#"
868         Store the low 8 bits of ``x`` to memory at ``p + Offset``.
869 
870         This is equivalent to ``ireduce.i8`` followed by ``store.i8``.
871         "#,
872             &formats.store,
873         )
874         .operands_in(vec![MemFlags, x, p, Offset])
875         .can_store(true),
876     );
877 
878     let iExt16 = &TypeVar::new(
879         "iExt16",
880         "An integer type with more than 16 bits",
881         TypeSetBuilder::new().ints(32..64).build(),
882     );
883     let x = &Operand::new("x", iExt16);
884     let a = &Operand::new("a", iExt16);
885 
886     ig.push(
887         Inst::new(
888             "uload16",
889             r#"
890         Load 16 bits from memory at ``p + Offset`` and zero-extend.
891 
892         This is equivalent to ``load.i16`` followed by ``uextend``.
893         "#,
894             &formats.load,
895         )
896         .operands_in(vec![MemFlags, p, Offset])
897         .operands_out(vec![a])
898         .can_load(true),
899     );
900 
901     ig.push(
902         Inst::new(
903             "sload16",
904             r#"
905         Load 16 bits from memory at ``p + Offset`` and sign-extend.
906 
907         This is equivalent to ``load.i16`` followed by ``sextend``.
908         "#,
909             &formats.load,
910         )
911         .operands_in(vec![MemFlags, p, Offset])
912         .operands_out(vec![a])
913         .can_load(true),
914     );
915 
916     ig.push(
917         Inst::new(
918             "istore16",
919             r#"
920         Store the low 16 bits of ``x`` to memory at ``p + Offset``.
921 
922         This is equivalent to ``ireduce.i16`` followed by ``store.i16``.
923         "#,
924             &formats.store,
925         )
926         .operands_in(vec![MemFlags, x, p, Offset])
927         .can_store(true),
928     );
929 
930     let iExt32 = &TypeVar::new(
931         "iExt32",
932         "An integer type with more than 32 bits",
933         TypeSetBuilder::new().ints(64..64).build(),
934     );
935     let x = &Operand::new("x", iExt32);
936     let a = &Operand::new("a", iExt32);
937 
938     ig.push(
939         Inst::new(
940             "uload32",
941             r#"
942         Load 32 bits from memory at ``p + Offset`` and zero-extend.
943 
944         This is equivalent to ``load.i32`` followed by ``uextend``.
945         "#,
946             &formats.load,
947         )
948         .operands_in(vec![MemFlags, p, Offset])
949         .operands_out(vec![a])
950         .can_load(true),
951     );
952 
953     ig.push(
954         Inst::new(
955             "sload32",
956             r#"
957         Load 32 bits from memory at ``p + Offset`` and sign-extend.
958 
959         This is equivalent to ``load.i32`` followed by ``sextend``.
960         "#,
961             &formats.load,
962         )
963         .operands_in(vec![MemFlags, p, Offset])
964         .operands_out(vec![a])
965         .can_load(true),
966     );
967 
968     ig.push(
969         Inst::new(
970             "istore32",
971             r#"
972         Store the low 32 bits of ``x`` to memory at ``p + Offset``.
973 
974         This is equivalent to ``ireduce.i32`` followed by ``store.i32``.
975         "#,
976             &formats.store,
977         )
978         .operands_in(vec![MemFlags, x, p, Offset])
979         .can_store(true),
980     );
981 
982     let I16x8 = &TypeVar::new(
983         "I16x8",
984         "A SIMD vector with exactly 8 lanes of 16-bit values",
985         TypeSetBuilder::new()
986             .ints(16..16)
987             .simd_lanes(8..8)
988             .includes_scalars(false)
989             .build(),
990     );
991     let a = &Operand::new("a", I16x8).with_doc("Value loaded");
992 
993     ig.push(
994         Inst::new(
995             "uload8x8",
996             r#"
997         Load an 8x8 vector (64 bits) from memory at ``p + Offset`` and zero-extend into an i16x8
998         vector.
999         "#,
1000             &formats.load,
1001         )
1002         .operands_in(vec![MemFlags, p, Offset])
1003         .operands_out(vec![a])
1004         .can_load(true),
1005     );
1006 
1007     ig.push(
1008         Inst::new(
1009             "sload8x8",
1010             r#"
1011         Load an 8x8 vector (64 bits) from memory at ``p + Offset`` and sign-extend into an i16x8
1012         vector.
1013         "#,
1014             &formats.load,
1015         )
1016         .operands_in(vec![MemFlags, p, Offset])
1017         .operands_out(vec![a])
1018         .can_load(true),
1019     );
1020 
1021     let I32x4 = &TypeVar::new(
1022         "I32x4",
1023         "A SIMD vector with exactly 4 lanes of 32-bit values",
1024         TypeSetBuilder::new()
1025             .ints(32..32)
1026             .simd_lanes(4..4)
1027             .includes_scalars(false)
1028             .build(),
1029     );
1030     let a = &Operand::new("a", I32x4).with_doc("Value loaded");
1031 
1032     ig.push(
1033         Inst::new(
1034             "uload16x4",
1035             r#"
1036         Load a 16x4 vector (64 bits) from memory at ``p + Offset`` and zero-extend into an i32x4
1037         vector.
1038         "#,
1039             &formats.load,
1040         )
1041         .operands_in(vec![MemFlags, p, Offset])
1042         .operands_out(vec![a])
1043         .can_load(true),
1044     );
1045 
1046     ig.push(
1047         Inst::new(
1048             "sload16x4",
1049             r#"
1050         Load a 16x4 vector (64 bits) from memory at ``p + Offset`` and sign-extend into an i32x4
1051         vector.
1052         "#,
1053             &formats.load,
1054         )
1055         .operands_in(vec![MemFlags, p, Offset])
1056         .operands_out(vec![a])
1057         .can_load(true),
1058     );
1059 
1060     let I64x2 = &TypeVar::new(
1061         "I64x2",
1062         "A SIMD vector with exactly 2 lanes of 64-bit values",
1063         TypeSetBuilder::new()
1064             .ints(64..64)
1065             .simd_lanes(2..2)
1066             .includes_scalars(false)
1067             .build(),
1068     );
1069     let a = &Operand::new("a", I64x2).with_doc("Value loaded");
1070 
1071     ig.push(
1072         Inst::new(
1073             "uload32x2",
1074             r#"
1075         Load an 32x2 vector (64 bits) from memory at ``p + Offset`` and zero-extend into an i64x2
1076         vector.
1077         "#,
1078             &formats.load,
1079         )
1080         .operands_in(vec![MemFlags, p, Offset])
1081         .operands_out(vec![a])
1082         .can_load(true),
1083     );
1084 
1085     ig.push(
1086         Inst::new(
1087             "sload32x2",
1088             r#"
1089         Load a 32x2 vector (64 bits) from memory at ``p + Offset`` and sign-extend into an i64x2
1090         vector.
1091         "#,
1092             &formats.load,
1093         )
1094         .operands_in(vec![MemFlags, p, Offset])
1095         .operands_out(vec![a])
1096         .can_load(true),
1097     );
1098 
1099     let x = &Operand::new("x", Mem).with_doc("Value to be stored");
1100     let a = &Operand::new("a", Mem).with_doc("Value loaded");
1101     let Offset =
1102         &Operand::new("Offset", &imm.offset32).with_doc("In-bounds offset into stack slot");
1103 
1104     ig.push(
1105         Inst::new(
1106             "stack_load",
1107             r#"
1108         Load a value from a stack slot at the constant offset.
1109 
1110         This is a polymorphic instruction that can load any value type which
1111         has a memory representation.
1112 
1113         The offset is an immediate constant, not an SSA value. The memory
1114         access cannot go out of bounds, i.e.
1115         `sizeof(a) + Offset <= sizeof(SS)`.
1116         "#,
1117             &formats.stack_load,
1118         )
1119         .operands_in(vec![SS, Offset])
1120         .operands_out(vec![a])
1121         .can_load(true),
1122     );
1123 
1124     ig.push(
1125         Inst::new(
1126             "stack_store",
1127             r#"
1128         Store a value to a stack slot at a constant offset.
1129 
1130         This is a polymorphic instruction that can store any value type with a
1131         memory representation.
1132 
1133         The offset is an immediate constant, not an SSA value. The memory
1134         access cannot go out of bounds, i.e.
1135         `sizeof(a) + Offset <= sizeof(SS)`.
1136         "#,
1137             &formats.stack_store,
1138         )
1139         .operands_in(vec![x, SS, Offset])
1140         .can_store(true),
1141     );
1142 
1143     ig.push(
1144         Inst::new(
1145             "stack_addr",
1146             r#"
1147         Get the address of a stack slot.
1148 
1149         Compute the absolute address of a byte in a stack slot. The offset must
1150         refer to a byte inside the stack slot:
1151         `0 <= Offset < sizeof(SS)`.
1152         "#,
1153             &formats.stack_load,
1154         )
1155         .operands_in(vec![SS, Offset])
1156         .operands_out(vec![addr]),
1157     );
1158 
1159     ig.push(
1160         Inst::new(
1161             "dynamic_stack_load",
1162             r#"
1163         Load a value from a dynamic stack slot.
1164 
1165         This is a polymorphic instruction that can load any value type which
1166         has a memory representation.
1167         "#,
1168             &formats.dynamic_stack_load,
1169         )
1170         .operands_in(vec![DSS])
1171         .operands_out(vec![a])
1172         .can_load(true),
1173     );
1174 
1175     ig.push(
1176         Inst::new(
1177             "dynamic_stack_store",
1178             r#"
1179         Store a value to a dynamic stack slot.
1180 
1181         This is a polymorphic instruction that can store any dynamic value type with a
1182         memory representation.
1183         "#,
1184             &formats.dynamic_stack_store,
1185         )
1186         .operands_in(vec![x, DSS])
1187         .can_store(true),
1188     );
1189 
1190     let GV = &Operand::new("GV", &entities.global_value);
1191     ig.push(
1192         Inst::new(
1193             "dynamic_stack_addr",
1194             r#"
1195         Get the address of a dynamic stack slot.
1196 
1197         Compute the absolute address of the first byte of a dynamic stack slot.
1198         "#,
1199             &formats.dynamic_stack_load,
1200         )
1201         .operands_in(vec![DSS])
1202         .operands_out(vec![addr]),
1203     );
1204 
1205     ig.push(
1206         Inst::new(
1207             "global_value",
1208             r#"
1209         Compute the value of global GV.
1210         "#,
1211             &formats.unary_global_value,
1212         )
1213         .operands_in(vec![GV])
1214         .operands_out(vec![a]),
1215     );
1216 
1217     ig.push(
1218         Inst::new(
1219             "symbol_value",
1220             r#"
1221         Compute the value of global GV, which is a symbolic value.
1222         "#,
1223             &formats.unary_global_value,
1224         )
1225         .operands_in(vec![GV])
1226         .operands_out(vec![a]),
1227     );
1228 
1229     ig.push(
1230         Inst::new(
1231             "tls_value",
1232             r#"
1233         Compute the value of global GV, which is a TLS (thread local storage) value.
1234         "#,
1235             &formats.unary_global_value,
1236         )
1237         .operands_in(vec![GV])
1238         .operands_out(vec![a]),
1239     );
1240 
1241     let HeapOffset = &TypeVar::new(
1242         "HeapOffset",
1243         "An unsigned heap offset",
1244         TypeSetBuilder::new().ints(32..64).build(),
1245     );
1246 
1247     let H = &Operand::new("H", &entities.heap);
1248     let p = &Operand::new("p", HeapOffset);
1249     let Size = &Operand::new("Size", &imm.uimm32).with_doc("Size in bytes");
1250 
1251     ig.push(
1252         Inst::new(
1253             "heap_addr",
1254             r#"
1255         Bounds check and compute absolute address of heap memory.
1256 
1257         Verify that the offset range ``p .. p + Size - 1`` is in bounds for the
1258         heap H, and generate an absolute address that is safe to dereference.
1259 
1260         1. If ``p + Size`` is not greater than the heap bound, return an
1261            absolute address corresponding to a byte offset of ``p`` from the
1262            heap's base address.
1263         2. If ``p + Size`` is greater than the heap bound, generate a trap.
1264         "#,
1265             &formats.heap_addr,
1266         )
1267         .operands_in(vec![H, p, Size])
1268         .operands_out(vec![addr]),
1269     );
1270 
1271     // Note this instruction is marked as having other side-effects, so GVN won't try to hoist it,
1272     // which would result in it being subject to spilling. While not hoisting would generally hurt
1273     // performance, since a computed value used many times may need to be regenerated before each
1274     // use, it is not the case here: this instruction doesn't generate any code.  That's because,
1275     // by definition the pinned register is never used by the register allocator, but is written to
1276     // and read explicitly and exclusively by set_pinned_reg and get_pinned_reg.
1277     ig.push(
1278         Inst::new(
1279             "get_pinned_reg",
1280             r#"
1281             Gets the content of the pinned register, when it's enabled.
1282         "#,
1283             &formats.nullary,
1284         )
1285         .operands_out(vec![addr])
1286         .other_side_effects(true),
1287     );
1288 
1289     ig.push(
1290         Inst::new(
1291             "set_pinned_reg",
1292             r#"
1293         Sets the content of the pinned register, when it's enabled.
1294         "#,
1295             &formats.unary,
1296         )
1297         .operands_in(vec![addr])
1298         .other_side_effects(true),
1299     );
1300 
1301     ig.push(
1302         Inst::new(
1303             "get_frame_pointer",
1304             r#"
1305         Get the address in the frame pointer register.
1306 
1307         Usage of this instruction requires setting `preserve_frame_pointers` to `true`.
1308         "#,
1309             &formats.nullary,
1310         )
1311         .operands_out(vec![addr]),
1312     );
1313 
1314     ig.push(
1315         Inst::new(
1316             "get_stack_pointer",
1317             r#"
1318         Get the address in the stack pointer register.
1319         "#,
1320             &formats.nullary,
1321         )
1322         .operands_out(vec![addr]),
1323     );
1324 
1325     ig.push(
1326         Inst::new(
1327             "get_return_address",
1328             r#"
1329         Get the PC where this function will transfer control to when it returns.
1330 
1331         Usage of this instruction requires setting `preserve_frame_pointers` to `true`.
1332         "#,
1333             &formats.nullary,
1334         )
1335         .operands_out(vec![addr]),
1336     );
1337 
1338     let TableOffset = &TypeVar::new(
1339         "TableOffset",
1340         "An unsigned table offset",
1341         TypeSetBuilder::new().ints(32..64).build(),
1342     );
1343     let T = &Operand::new("T", &entities.table);
1344     let p = &Operand::new("p", TableOffset);
1345     let Offset =
1346         &Operand::new("Offset", &imm.offset32).with_doc("Byte offset from element address");
1347 
1348     ig.push(
1349         Inst::new(
1350             "table_addr",
1351             r#"
1352         Bounds check and compute absolute address of a table entry.
1353 
1354         Verify that the offset ``p`` is in bounds for the table T, and generate
1355         an absolute address that is safe to dereference.
1356 
1357         ``Offset`` must be less than the size of a table element.
1358 
1359         1. If ``p`` is not greater than the table bound, return an absolute
1360            address corresponding to a byte offset of ``p`` from the table's
1361            base address.
1362         2. If ``p`` is greater than the table bound, generate a trap.
1363         "#,
1364             &formats.table_addr,
1365         )
1366         .operands_in(vec![T, p, Offset])
1367         .operands_out(vec![addr]),
1368     );
1369 
1370     let N = &Operand::new("N", &imm.imm64);
1371     let a = &Operand::new("a", Int).with_doc("A constant integer scalar or vector value");
1372 
1373     ig.push(
1374         Inst::new(
1375             "iconst",
1376             r#"
1377         Integer constant.
1378 
1379         Create a scalar integer SSA value with an immediate constant value, or
1380         an integer vector where all the lanes have the same value.
1381         "#,
1382             &formats.unary_imm,
1383         )
1384         .operands_in(vec![N])
1385         .operands_out(vec![a]),
1386     );
1387 
1388     let N = &Operand::new("N", &imm.ieee32);
1389     let a = &Operand::new("a", f32_).with_doc("A constant f32 scalar value");
1390 
1391     ig.push(
1392         Inst::new(
1393             "f32const",
1394             r#"
1395         Floating point constant.
1396 
1397         Create a `f32` SSA value with an immediate constant value.
1398         "#,
1399             &formats.unary_ieee32,
1400         )
1401         .operands_in(vec![N])
1402         .operands_out(vec![a]),
1403     );
1404 
1405     let N = &Operand::new("N", &imm.ieee64);
1406     let a = &Operand::new("a", f64_).with_doc("A constant f64 scalar value");
1407 
1408     ig.push(
1409         Inst::new(
1410             "f64const",
1411             r#"
1412         Floating point constant.
1413 
1414         Create a `f64` SSA value with an immediate constant value.
1415         "#,
1416             &formats.unary_ieee64,
1417         )
1418         .operands_in(vec![N])
1419         .operands_out(vec![a]),
1420     );
1421 
1422     let N = &Operand::new("N", &imm.boolean);
1423     let a = &Operand::new("a", Bool).with_doc("A constant boolean scalar or vector value");
1424 
1425     ig.push(
1426         Inst::new(
1427             "bconst",
1428             r#"
1429         Boolean constant.
1430 
1431         Create a scalar boolean SSA value with an immediate constant value, or
1432         a boolean vector where all the lanes have the same value.
1433         "#,
1434             &formats.unary_bool,
1435         )
1436         .operands_in(vec![N])
1437         .operands_out(vec![a]),
1438     );
1439 
1440     let N = &Operand::new("N", &imm.pool_constant)
1441         .with_doc("The 16 immediate bytes of a 128-bit vector");
1442     let a = &Operand::new("a", TxN).with_doc("A constant vector value");
1443 
1444     ig.push(
1445         Inst::new(
1446             "vconst",
1447             r#"
1448         SIMD vector constant.
1449 
1450         Construct a vector with the given immediate bytes.
1451         "#,
1452             &formats.unary_const,
1453         )
1454         .operands_in(vec![N])
1455         .operands_out(vec![a]),
1456     );
1457 
1458     let mask = &Operand::new("mask", &imm.uimm128)
1459         .with_doc("The 16 immediate bytes used for selecting the elements to shuffle");
1460     let Tx16 = &TypeVar::new(
1461         "Tx16",
1462         "A SIMD vector with exactly 16 lanes of 8-bit values; eventually this may support other \
1463          lane counts and widths",
1464         TypeSetBuilder::new()
1465             .ints(8..8)
1466             .bools(8..8)
1467             .simd_lanes(16..16)
1468             .includes_scalars(false)
1469             .build(),
1470     );
1471     let a = &Operand::new("a", Tx16).with_doc("A vector value");
1472     let b = &Operand::new("b", Tx16).with_doc("A vector value");
1473 
1474     ig.push(
1475         Inst::new(
1476             "shuffle",
1477             r#"
1478         SIMD vector shuffle.
1479 
1480         Shuffle two vectors using the given immediate bytes. For each of the 16 bytes of the
1481         immediate, a value i of 0-15 selects the i-th element of the first vector and a value i of
1482         16-31 selects the (i-16)th element of the second vector. Immediate values outside of the
1483         0-31 range place a 0 in the resulting vector lane.
1484         "#,
1485             &formats.shuffle,
1486         )
1487         .operands_in(vec![a, b, mask])
1488         .operands_out(vec![a]),
1489     );
1490 
1491     let a = &Operand::new("a", Ref).with_doc("A constant reference null value");
1492 
1493     ig.push(
1494         Inst::new(
1495             "null",
1496             r#"
1497         Null constant value for reference types.
1498 
1499         Create a scalar reference SSA value with a constant null value.
1500         "#,
1501             &formats.nullary,
1502         )
1503         .operands_out(vec![a]),
1504     );
1505 
1506     ig.push(Inst::new(
1507         "nop",
1508         r#"
1509         Just a dummy instruction.
1510 
1511         Note: this doesn't compile to a machine code nop.
1512         "#,
1513         &formats.nullary,
1514     ));
1515 
1516     let c = &Operand::new("c", Testable).with_doc("Controlling value to test");
1517     let x = &Operand::new("x", Any).with_doc("Value to use when `c` is true");
1518     let y = &Operand::new("y", Any).with_doc("Value to use when `c` is false");
1519     let a = &Operand::new("a", Any);
1520 
1521     ig.push(
1522         Inst::new(
1523             "select",
1524             r#"
1525         Conditional select.
1526 
1527         This instruction selects whole values. Use `vselect` for
1528         lane-wise selection.
1529         "#,
1530             &formats.ternary,
1531         )
1532         .operands_in(vec![c, x, y])
1533         .operands_out(vec![a]),
1534     );
1535 
1536     let cc = &Operand::new("cc", &imm.intcc).with_doc("Controlling condition code");
1537     let flags = &Operand::new("flags", iflags).with_doc("The machine's flag register");
1538 
1539     ig.push(
1540         Inst::new(
1541             "selectif",
1542             r#"
1543         Conditional select, dependent on integer condition codes.
1544         "#,
1545             &formats.int_select,
1546         )
1547         .operands_in(vec![cc, flags, x, y])
1548         .operands_out(vec![a]),
1549     );
1550 
1551     ig.push(
1552         Inst::new(
1553             "selectif_spectre_guard",
1554             r#"
1555             Conditional select intended for Spectre guards.
1556 
1557             This operation is semantically equivalent to a selectif instruction.
1558             However, it is guaranteed to not be removed or otherwise altered by any
1559             optimization pass, and is guaranteed to result in a conditional-move
1560             instruction, not a branch-based lowering.  As such, it is suitable
1561             for use when producing Spectre guards. For example, a bounds-check
1562             may guard against unsafe speculation past a bounds-check conditional
1563             branch by passing the address or index to be accessed through a
1564             conditional move, also gated on the same condition. Because no
1565             Spectre-vulnerable processors are known to perform speculation on
1566             conditional move instructions, this is guaranteed to pick the
1567             correct input. If the selected input in case of overflow is a "safe"
1568             value, for example a null pointer that causes an exception in the
1569             speculative path, this ensures that no Spectre vulnerability will
1570             exist.
1571             "#,
1572             &formats.int_select,
1573         )
1574         .operands_in(vec![cc, flags, x, y])
1575         .operands_out(vec![a])
1576         .other_side_effects(true),
1577     );
1578 
1579     let c = &Operand::new("c", Any).with_doc("Controlling value to test");
1580     ig.push(
1581         Inst::new(
1582             "bitselect",
1583             r#"
1584         Conditional select of bits.
1585 
1586         For each bit in `c`, this instruction selects the corresponding bit from `x` if the bit
1587         in `c` is 1 and the corresponding bit from `y` if the bit in `c` is 0. See also:
1588         `select`, `vselect`.
1589         "#,
1590             &formats.ternary,
1591         )
1592         .operands_in(vec![c, x, y])
1593         .operands_out(vec![a]),
1594     );
1595 
1596     let x = &Operand::new("x", Any);
1597 
1598     ig.push(
1599         Inst::new(
1600             "copy",
1601             r#"
1602         Register-register copy.
1603 
1604         This instruction copies its input, preserving the value type.
1605 
1606         A pure SSA-form program does not need to copy values, but this
1607         instruction is useful for representing intermediate stages during
1608         instruction transformations, and the register allocator needs a way of
1609         representing register copies.
1610         "#,
1611             &formats.unary,
1612         )
1613         .operands_in(vec![x])
1614         .operands_out(vec![a]),
1615     );
1616 
1617     let x = &Operand::new("x", TxN).with_doc("Vector to split");
1618     let lo = &Operand::new("lo", &TxN.half_vector()).with_doc("Low-numbered lanes of `x`");
1619     let hi = &Operand::new("hi", &TxN.half_vector()).with_doc("High-numbered lanes of `x`");
1620 
1621     ig.push(
1622         Inst::new(
1623             "vsplit",
1624             r#"
1625         Split a vector into two halves.
1626 
1627         Split the vector `x` into two separate values, each containing half of
1628         the lanes from ``x``. The result may be two scalars if ``x`` only had
1629         two lanes.
1630         "#,
1631             &formats.unary,
1632         )
1633         .operands_in(vec![x])
1634         .operands_out(vec![lo, hi]),
1635     );
1636 
1637     let Any128 = &TypeVar::new(
1638         "Any128",
1639         "Any scalar or vector type with as most 128 lanes",
1640         TypeSetBuilder::new()
1641             .ints(Interval::All)
1642             .floats(Interval::All)
1643             .bools(Interval::All)
1644             .simd_lanes(1..128)
1645             .includes_scalars(true)
1646             .build(),
1647     );
1648 
1649     let x = &Operand::new("x", Any128).with_doc("Low-numbered lanes");
1650     let y = &Operand::new("y", Any128).with_doc("High-numbered lanes");
1651     let a = &Operand::new("a", &Any128.double_vector()).with_doc("Concatenation of `x` and `y`");
1652 
1653     ig.push(
1654         Inst::new(
1655             "vconcat",
1656             r#"
1657         Vector concatenation.
1658 
1659         Return a vector formed by concatenating ``x`` and ``y``. The resulting
1660         vector type has twice as many lanes as each of the inputs. The lanes of
1661         ``x`` appear as the low-numbered lanes, and the lanes of ``y`` become
1662         the high-numbered lanes of ``a``.
1663 
1664         It is possible to form a vector by concatenating two scalars.
1665         "#,
1666             &formats.binary,
1667         )
1668         .operands_in(vec![x, y])
1669         .operands_out(vec![a]),
1670     );
1671 
1672     let c = &Operand::new("c", &TxN.as_bool()).with_doc("Controlling vector");
1673     let x = &Operand::new("x", TxN).with_doc("Value to use where `c` is true");
1674     let y = &Operand::new("y", TxN).with_doc("Value to use where `c` is false");
1675     let a = &Operand::new("a", TxN);
1676 
1677     ig.push(
1678         Inst::new(
1679             "vselect",
1680             r#"
1681         Vector lane select.
1682 
1683         Select lanes from ``x`` or ``y`` controlled by the lanes of the boolean
1684         vector ``c``.
1685         "#,
1686             &formats.ternary,
1687         )
1688         .operands_in(vec![c, x, y])
1689         .operands_out(vec![a]),
1690     );
1691 
1692     let s = &Operand::new("s", b1);
1693 
1694     ig.push(
1695         Inst::new(
1696             "vany_true",
1697             r#"
1698         Reduce a vector to a scalar boolean.
1699 
1700         Return a scalar boolean true if any lane in ``a`` is non-zero, false otherwise.
1701         "#,
1702             &formats.unary,
1703         )
1704         .operands_in(vec![a])
1705         .operands_out(vec![s]),
1706     );
1707 
1708     ig.push(
1709         Inst::new(
1710             "vall_true",
1711             r#"
1712         Reduce a vector to a scalar boolean.
1713 
1714         Return a scalar boolean true if all lanes in ``i`` are non-zero, false otherwise.
1715         "#,
1716             &formats.unary,
1717         )
1718         .operands_in(vec![a])
1719         .operands_out(vec![s]),
1720     );
1721 
1722     let a = &Operand::new("a", TxN);
1723     let x = &Operand::new("x", Int);
1724 
1725     ig.push(
1726         Inst::new(
1727             "vhigh_bits",
1728             r#"
1729         Reduce a vector to a scalar integer.
1730 
1731         Return a scalar integer, consisting of the concatenation of the most significant bit
1732         of each lane of ``a``.
1733         "#,
1734             &formats.unary,
1735         )
1736         .operands_in(vec![a])
1737         .operands_out(vec![x]),
1738     );
1739 
1740     let a = &Operand::new("a", &Int.as_bool());
1741     let Cond = &Operand::new("Cond", &imm.intcc);
1742     let x = &Operand::new("x", Int);
1743     let y = &Operand::new("y", Int);
1744 
1745     ig.push(
1746         Inst::new(
1747             "icmp",
1748             r#"
1749         Integer comparison.
1750 
1751         The condition code determines if the operands are interpreted as signed
1752         or unsigned integers.
1753 
1754         | Signed | Unsigned | Condition             |
1755         |--------|----------|-----------------------|
1756         | eq     | eq       | Equal                 |
1757         | ne     | ne       | Not equal             |
1758         | slt    | ult      | Less than             |
1759         | sge    | uge      | Greater than or equal |
1760         | sgt    | ugt      | Greater than          |
1761         | sle    | ule      | Less than or equal    |
1762 
1763         When this instruction compares integer vectors, it returns a boolean
1764         vector of lane-wise comparisons.
1765         "#,
1766             &formats.int_compare,
1767         )
1768         .operands_in(vec![Cond, x, y])
1769         .operands_out(vec![a]),
1770     );
1771 
1772     let a = &Operand::new("a", b1);
1773     let x = &Operand::new("x", iB);
1774     let Y = &Operand::new("Y", &imm.imm64);
1775 
1776     ig.push(
1777         Inst::new(
1778             "icmp_imm",
1779             r#"
1780         Compare scalar integer to a constant.
1781 
1782         This is the same as the `icmp` instruction, except one operand is
1783         a sign extended 64 bit immediate constant.
1784 
1785         This instruction can only compare scalars. Use `icmp` for
1786         lane-wise vector comparisons.
1787         "#,
1788             &formats.int_compare_imm,
1789         )
1790         .operands_in(vec![Cond, x, Y])
1791         .operands_out(vec![a]),
1792     );
1793 
1794     let f = &Operand::new("f", iflags);
1795     let x = &Operand::new("x", iB);
1796     let y = &Operand::new("y", iB);
1797 
1798     ig.push(
1799         Inst::new(
1800             "ifcmp",
1801             r#"
1802         Compare scalar integers and return flags.
1803 
1804         Compare two scalar integer values and return integer CPU flags
1805         representing the result.
1806         "#,
1807             &formats.binary,
1808         )
1809         .operands_in(vec![x, y])
1810         .operands_out(vec![f]),
1811     );
1812 
1813     ig.push(
1814         Inst::new(
1815             "ifcmp_imm",
1816             r#"
1817         Compare scalar integer to a constant and return flags.
1818 
1819         Like `icmp_imm`, but returns integer CPU flags instead of testing
1820         a specific condition code.
1821         "#,
1822             &formats.binary_imm64,
1823         )
1824         .operands_in(vec![x, Y])
1825         .operands_out(vec![f]),
1826     );
1827 
1828     let a = &Operand::new("a", Int);
1829     let x = &Operand::new("x", Int);
1830     let y = &Operand::new("y", Int);
1831 
1832     ig.push(
1833         Inst::new(
1834             "iadd",
1835             r#"
1836         Wrapping integer addition: `a := x + y \pmod{2^B}`.
1837 
1838         This instruction does not depend on the signed/unsigned interpretation
1839         of the operands.
1840         "#,
1841             &formats.binary,
1842         )
1843         .operands_in(vec![x, y])
1844         .operands_out(vec![a]),
1845     );
1846 
1847     ig.push(
1848         Inst::new(
1849             "isub",
1850             r#"
1851         Wrapping integer subtraction: `a := x - y \pmod{2^B}`.
1852 
1853         This instruction does not depend on the signed/unsigned interpretation
1854         of the operands.
1855         "#,
1856             &formats.binary,
1857         )
1858         .operands_in(vec![x, y])
1859         .operands_out(vec![a]),
1860     );
1861 
1862     ig.push(
1863         Inst::new(
1864             "ineg",
1865             r#"
1866         Integer negation: `a := -x \pmod{2^B}`.
1867         "#,
1868             &formats.unary,
1869         )
1870         .operands_in(vec![x])
1871         .operands_out(vec![a]),
1872     );
1873 
1874     ig.push(
1875         Inst::new(
1876             "iabs",
1877             r#"
1878         Integer absolute value with wrapping: `a := |x|`.
1879         "#,
1880             &formats.unary,
1881         )
1882         .operands_in(vec![x])
1883         .operands_out(vec![a]),
1884     );
1885 
1886     ig.push(
1887         Inst::new(
1888             "imul",
1889             r#"
1890         Wrapping integer multiplication: `a := x y \pmod{2^B}`.
1891 
1892         This instruction does not depend on the signed/unsigned interpretation
1893         of the operands.
1894 
1895         Polymorphic over all integer types (vector and scalar).
1896         "#,
1897             &formats.binary,
1898         )
1899         .operands_in(vec![x, y])
1900         .operands_out(vec![a]),
1901     );
1902 
1903     ig.push(
1904         Inst::new(
1905             "umulhi",
1906             r#"
1907         Unsigned integer multiplication, producing the high half of a
1908         double-length result.
1909 
1910         Polymorphic over all integer types (vector and scalar).
1911         "#,
1912             &formats.binary,
1913         )
1914         .operands_in(vec![x, y])
1915         .operands_out(vec![a]),
1916     );
1917 
1918     ig.push(
1919         Inst::new(
1920             "smulhi",
1921             r#"
1922         Signed integer multiplication, producing the high half of a
1923         double-length result.
1924 
1925         Polymorphic over all integer types (vector and scalar).
1926         "#,
1927             &formats.binary,
1928         )
1929         .operands_in(vec![x, y])
1930         .operands_out(vec![a]),
1931     );
1932 
1933     let I16or32 = &TypeVar::new(
1934         "I16or32",
1935         "A scalar or vector integer type with 16- or 32-bit numbers",
1936         TypeSetBuilder::new().ints(16..32).simd_lanes(4..8).build(),
1937     );
1938 
1939     let qx = &Operand::new("x", I16or32);
1940     let qy = &Operand::new("y", I16or32);
1941     let qa = &Operand::new("a", I16or32);
1942 
1943     ig.push(
1944         Inst::new(
1945             "sqmul_round_sat",
1946             r#"
1947         Fixed-point multiplication of numbers in the QN format, where N + 1
1948         is the number bitwidth:
1949         `a := signed_saturate((x * y + 1 << (Q - 1)) >> Q)`
1950 
1951         Polymorphic over all integer types (scalar and vector) with 16- or
1952         32-bit numbers.
1953         "#,
1954             &formats.binary,
1955         )
1956         .operands_in(vec![qx, qy])
1957         .operands_out(vec![qa]),
1958     );
1959 
1960     {
1961         // Integer division and remainder are scalar-only; most
1962         // hardware does not directly support vector integer division.
1963 
1964         let x = &Operand::new("x", iB);
1965         let y = &Operand::new("y", iB);
1966         let a = &Operand::new("a", iB);
1967 
1968         ig.push(
1969             Inst::new(
1970                 "udiv",
1971                 r#"
1972             Unsigned integer division: `a := \lfloor {x \over y} \rfloor`.
1973 
1974             This operation traps if the divisor is zero.
1975             "#,
1976                 &formats.binary,
1977             )
1978             .operands_in(vec![x, y])
1979             .operands_out(vec![a])
1980             .can_trap(true),
1981         );
1982 
1983         ig.push(
1984             Inst::new(
1985                 "sdiv",
1986                 r#"
1987             Signed integer division rounded toward zero: `a := sign(xy)
1988             \lfloor {|x| \over |y|}\rfloor`.
1989 
1990             This operation traps if the divisor is zero, or if the result is not
1991             representable in `B` bits two's complement. This only happens
1992             when `x = -2^{B-1}, y = -1`.
1993             "#,
1994                 &formats.binary,
1995             )
1996             .operands_in(vec![x, y])
1997             .operands_out(vec![a])
1998             .can_trap(true),
1999         );
2000 
2001         ig.push(
2002             Inst::new(
2003                 "urem",
2004                 r#"
2005             Unsigned integer remainder.
2006 
2007             This operation traps if the divisor is zero.
2008             "#,
2009                 &formats.binary,
2010             )
2011             .operands_in(vec![x, y])
2012             .operands_out(vec![a])
2013             .can_trap(true),
2014         );
2015 
2016         ig.push(
2017             Inst::new(
2018                 "srem",
2019                 r#"
2020             Signed integer remainder. The result has the sign of the dividend.
2021 
2022             This operation traps if the divisor is zero.
2023             "#,
2024                 &formats.binary,
2025             )
2026             .operands_in(vec![x, y])
2027             .operands_out(vec![a])
2028             .can_trap(true),
2029         );
2030     }
2031 
2032     let a = &Operand::new("a", iB);
2033     let x = &Operand::new("x", iB);
2034     let Y = &Operand::new("Y", &imm.imm64);
2035 
2036     ig.push(
2037         Inst::new(
2038             "iadd_imm",
2039             r#"
2040         Add immediate integer.
2041 
2042         Same as `iadd`, but one operand is a sign extended 64 bit immediate constant.
2043 
2044         Polymorphic over all scalar integer types, but does not support vector
2045         types.
2046         "#,
2047             &formats.binary_imm64,
2048         )
2049         .operands_in(vec![x, Y])
2050         .operands_out(vec![a]),
2051     );
2052 
2053     ig.push(
2054         Inst::new(
2055             "imul_imm",
2056             r#"
2057         Integer multiplication by immediate constant.
2058 
2059         Same as `imul`, but one operand is a sign extended 64 bit immediate constant.
2060 
2061         Polymorphic over all scalar integer types, but does not support vector
2062         types.
2063         "#,
2064             &formats.binary_imm64,
2065         )
2066         .operands_in(vec![x, Y])
2067         .operands_out(vec![a]),
2068     );
2069 
2070     ig.push(
2071         Inst::new(
2072             "udiv_imm",
2073             r#"
2074         Unsigned integer division by an immediate constant.
2075 
2076         Same as `udiv`, but one operand is a zero extended 64 bit immediate constant.
2077 
2078         This operation traps if the divisor is zero.
2079         "#,
2080             &formats.binary_imm64,
2081         )
2082         .operands_in(vec![x, Y])
2083         .operands_out(vec![a]),
2084     );
2085 
2086     ig.push(
2087         Inst::new(
2088             "sdiv_imm",
2089             r#"
2090         Signed integer division by an immediate constant.
2091 
2092         Same as `sdiv`, but one operand is a sign extended 64 bit immediate constant.
2093 
2094         This operation traps if the divisor is zero, or if the result is not
2095         representable in `B` bits two's complement. This only happens
2096         when `x = -2^{B-1}, Y = -1`.
2097         "#,
2098             &formats.binary_imm64,
2099         )
2100         .operands_in(vec![x, Y])
2101         .operands_out(vec![a]),
2102     );
2103 
2104     ig.push(
2105         Inst::new(
2106             "urem_imm",
2107             r#"
2108         Unsigned integer remainder with immediate divisor.
2109 
2110         Same as `urem`, but one operand is a zero extended 64 bit immediate constant.
2111 
2112         This operation traps if the divisor is zero.
2113         "#,
2114             &formats.binary_imm64,
2115         )
2116         .operands_in(vec![x, Y])
2117         .operands_out(vec![a]),
2118     );
2119 
2120     ig.push(
2121         Inst::new(
2122             "srem_imm",
2123             r#"
2124         Signed integer remainder with immediate divisor.
2125 
2126         Same as `srem`, but one operand is a sign extended 64 bit immediate constant.
2127 
2128         This operation traps if the divisor is zero.
2129         "#,
2130             &formats.binary_imm64,
2131         )
2132         .operands_in(vec![x, Y])
2133         .operands_out(vec![a]),
2134     );
2135 
2136     ig.push(
2137         Inst::new(
2138             "irsub_imm",
2139             r#"
2140         Immediate reverse wrapping subtraction: `a := Y - x \pmod{2^B}`.
2141 
2142         The immediate operand is a sign extended 64 bit constant.
2143 
2144         Also works as integer negation when `Y = 0`. Use `iadd_imm`
2145         with a negative immediate operand for the reverse immediate
2146         subtraction.
2147 
2148         Polymorphic over all scalar integer types, but does not support vector
2149         types.
2150         "#,
2151             &formats.binary_imm64,
2152         )
2153         .operands_in(vec![x, Y])
2154         .operands_out(vec![a]),
2155     );
2156 
2157     let a = &Operand::new("a", iB);
2158     let x = &Operand::new("x", iB);
2159     let y = &Operand::new("y", iB);
2160 
2161     let c_in = &Operand::new("c_in", b1).with_doc("Input carry flag");
2162     let c_out = &Operand::new("c_out", b1).with_doc("Output carry flag");
2163     let b_in = &Operand::new("b_in", b1).with_doc("Input borrow flag");
2164     let b_out = &Operand::new("b_out", b1).with_doc("Output borrow flag");
2165 
2166     let c_if_in = &Operand::new("c_in", iflags);
2167     let c_if_out = &Operand::new("c_out", iflags);
2168     let b_if_in = &Operand::new("b_in", iflags);
2169     let b_if_out = &Operand::new("b_out", iflags);
2170 
2171     ig.push(
2172         Inst::new(
2173             "iadd_cin",
2174             r#"
2175         Add integers with carry in.
2176 
2177         Same as `iadd` with an additional carry input. Computes:
2178 
2179         ```text
2180             a = x + y + c_{in} \pmod 2^B
2181         ```
2182 
2183         Polymorphic over all scalar integer types, but does not support vector
2184         types.
2185         "#,
2186             &formats.ternary,
2187         )
2188         .operands_in(vec![x, y, c_in])
2189         .operands_out(vec![a]),
2190     );
2191 
2192     ig.push(
2193         Inst::new(
2194             "iadd_ifcin",
2195             r#"
2196         Add integers with carry in.
2197 
2198         Same as `iadd` with an additional carry flag input. Computes:
2199 
2200         ```text
2201             a = x + y + c_{in} \pmod 2^B
2202         ```
2203 
2204         Polymorphic over all scalar integer types, but does not support vector
2205         types.
2206         "#,
2207             &formats.ternary,
2208         )
2209         .operands_in(vec![x, y, c_if_in])
2210         .operands_out(vec![a]),
2211     );
2212 
2213     ig.push(
2214         Inst::new(
2215             "iadd_cout",
2216             r#"
2217         Add integers with carry out.
2218 
2219         Same as `iadd` with an additional carry output.
2220 
2221         ```text
2222             a &= x + y \pmod 2^B \\
2223             c_{out} &= x+y >= 2^B
2224         ```
2225 
2226         Polymorphic over all scalar integer types, but does not support vector
2227         types.
2228         "#,
2229             &formats.binary,
2230         )
2231         .operands_in(vec![x, y])
2232         .operands_out(vec![a, c_out]),
2233     );
2234 
2235     ig.push(
2236         Inst::new(
2237             "iadd_ifcout",
2238             r#"
2239         Add integers with carry out.
2240 
2241         Same as `iadd` with an additional carry flag output.
2242 
2243         ```text
2244             a &= x + y \pmod 2^B \\
2245             c_{out} &= x+y >= 2^B
2246         ```
2247 
2248         Polymorphic over all scalar integer types, but does not support vector
2249         types.
2250         "#,
2251             &formats.binary,
2252         )
2253         .operands_in(vec![x, y])
2254         .operands_out(vec![a, c_if_out]),
2255     );
2256 
2257     ig.push(
2258         Inst::new(
2259             "iadd_carry",
2260             r#"
2261         Add integers with carry in and out.
2262 
2263         Same as `iadd` with an additional carry input and output.
2264 
2265         ```text
2266             a &= x + y + c_{in} \pmod 2^B \\
2267             c_{out} &= x + y + c_{in} >= 2^B
2268         ```
2269 
2270         Polymorphic over all scalar integer types, but does not support vector
2271         types.
2272         "#,
2273             &formats.ternary,
2274         )
2275         .operands_in(vec![x, y, c_in])
2276         .operands_out(vec![a, c_out]),
2277     );
2278 
2279     ig.push(
2280         Inst::new(
2281             "iadd_ifcarry",
2282             r#"
2283         Add integers with carry in and out.
2284 
2285         Same as `iadd` with an additional carry flag input and output.
2286 
2287         ```text
2288             a &= x + y + c_{in} \pmod 2^B \\
2289             c_{out} &= x + y + c_{in} >= 2^B
2290         ```
2291 
2292         Polymorphic over all scalar integer types, but does not support vector
2293         types.
2294         "#,
2295             &formats.ternary,
2296         )
2297         .operands_in(vec![x, y, c_if_in])
2298         .operands_out(vec![a, c_if_out]),
2299     );
2300 
2301     ig.push(
2302         Inst::new(
2303             "isub_bin",
2304             r#"
2305         Subtract integers with borrow in.
2306 
2307         Same as `isub` with an additional borrow flag input. Computes:
2308 
2309         ```text
2310             a = x - (y + b_{in}) \pmod 2^B
2311         ```
2312 
2313         Polymorphic over all scalar integer types, but does not support vector
2314         types.
2315         "#,
2316             &formats.ternary,
2317         )
2318         .operands_in(vec![x, y, b_in])
2319         .operands_out(vec![a]),
2320     );
2321 
2322     ig.push(
2323         Inst::new(
2324             "isub_ifbin",
2325             r#"
2326         Subtract integers with borrow in.
2327 
2328         Same as `isub` with an additional borrow flag input. Computes:
2329 
2330         ```text
2331             a = x - (y + b_{in}) \pmod 2^B
2332         ```
2333 
2334         Polymorphic over all scalar integer types, but does not support vector
2335         types.
2336         "#,
2337             &formats.ternary,
2338         )
2339         .operands_in(vec![x, y, b_if_in])
2340         .operands_out(vec![a]),
2341     );
2342 
2343     ig.push(
2344         Inst::new(
2345             "isub_bout",
2346             r#"
2347         Subtract integers with borrow out.
2348 
2349         Same as `isub` with an additional borrow flag output.
2350 
2351         ```text
2352             a &= x - y \pmod 2^B \\
2353             b_{out} &= x < y
2354         ```
2355 
2356         Polymorphic over all scalar integer types, but does not support vector
2357         types.
2358         "#,
2359             &formats.binary,
2360         )
2361         .operands_in(vec![x, y])
2362         .operands_out(vec![a, b_out]),
2363     );
2364 
2365     ig.push(
2366         Inst::new(
2367             "isub_ifbout",
2368             r#"
2369         Subtract integers with borrow out.
2370 
2371         Same as `isub` with an additional borrow flag output.
2372 
2373         ```text
2374             a &= x - y \pmod 2^B \\
2375             b_{out} &= x < y
2376         ```
2377 
2378         Polymorphic over all scalar integer types, but does not support vector
2379         types.
2380         "#,
2381             &formats.binary,
2382         )
2383         .operands_in(vec![x, y])
2384         .operands_out(vec![a, b_if_out]),
2385     );
2386 
2387     ig.push(
2388         Inst::new(
2389             "isub_borrow",
2390             r#"
2391         Subtract integers with borrow in and out.
2392 
2393         Same as `isub` with an additional borrow flag input and output.
2394 
2395         ```text
2396             a &= x - (y + b_{in}) \pmod 2^B \\
2397             b_{out} &= x < y + b_{in}
2398         ```
2399 
2400         Polymorphic over all scalar integer types, but does not support vector
2401         types.
2402         "#,
2403             &formats.ternary,
2404         )
2405         .operands_in(vec![x, y, b_in])
2406         .operands_out(vec![a, b_out]),
2407     );
2408 
2409     ig.push(
2410         Inst::new(
2411             "isub_ifborrow",
2412             r#"
2413         Subtract integers with borrow in and out.
2414 
2415         Same as `isub` with an additional borrow flag input and output.
2416 
2417         ```text
2418             a &= x - (y + b_{in}) \pmod 2^B \\
2419             b_{out} &= x < y + b_{in}
2420         ```
2421 
2422         Polymorphic over all scalar integer types, but does not support vector
2423         types.
2424         "#,
2425             &formats.ternary,
2426         )
2427         .operands_in(vec![x, y, b_if_in])
2428         .operands_out(vec![a, b_if_out]),
2429     );
2430 
2431     let bits = &TypeVar::new(
2432         "bits",
2433         "Any integer, float, or boolean scalar or vector type",
2434         TypeSetBuilder::new()
2435             .ints(Interval::All)
2436             .floats(Interval::All)
2437             .bools(Interval::All)
2438             .simd_lanes(Interval::All)
2439             .includes_scalars(true)
2440             .build(),
2441     );
2442     let x = &Operand::new("x", bits);
2443     let y = &Operand::new("y", bits);
2444     let a = &Operand::new("a", bits);
2445 
2446     ig.push(
2447         Inst::new(
2448             "band",
2449             r#"
2450         Bitwise and.
2451         "#,
2452             &formats.binary,
2453         )
2454         .operands_in(vec![x, y])
2455         .operands_out(vec![a]),
2456     );
2457 
2458     ig.push(
2459         Inst::new(
2460             "bor",
2461             r#"
2462         Bitwise or.
2463         "#,
2464             &formats.binary,
2465         )
2466         .operands_in(vec![x, y])
2467         .operands_out(vec![a]),
2468     );
2469 
2470     ig.push(
2471         Inst::new(
2472             "bxor",
2473             r#"
2474         Bitwise xor.
2475         "#,
2476             &formats.binary,
2477         )
2478         .operands_in(vec![x, y])
2479         .operands_out(vec![a]),
2480     );
2481 
2482     ig.push(
2483         Inst::new(
2484             "bnot",
2485             r#"
2486         Bitwise not.
2487         "#,
2488             &formats.unary,
2489         )
2490         .operands_in(vec![x])
2491         .operands_out(vec![a]),
2492     );
2493 
2494     ig.push(
2495         Inst::new(
2496             "band_not",
2497             r#"
2498         Bitwise and not.
2499 
2500         Computes `x & ~y`.
2501         "#,
2502             &formats.binary,
2503         )
2504         .operands_in(vec![x, y])
2505         .operands_out(vec![a]),
2506     );
2507 
2508     ig.push(
2509         Inst::new(
2510             "bor_not",
2511             r#"
2512         Bitwise or not.
2513 
2514         Computes `x | ~y`.
2515         "#,
2516             &formats.binary,
2517         )
2518         .operands_in(vec![x, y])
2519         .operands_out(vec![a]),
2520     );
2521 
2522     ig.push(
2523         Inst::new(
2524             "bxor_not",
2525             r#"
2526         Bitwise xor not.
2527 
2528         Computes `x ^ ~y`.
2529         "#,
2530             &formats.binary,
2531         )
2532         .operands_in(vec![x, y])
2533         .operands_out(vec![a]),
2534     );
2535 
2536     let x = &Operand::new("x", iB);
2537     let Y = &Operand::new("Y", &imm.imm64);
2538     let a = &Operand::new("a", iB);
2539 
2540     ig.push(
2541         Inst::new(
2542             "band_imm",
2543             r#"
2544         Bitwise and with immediate.
2545 
2546         Same as `band`, but one operand is a zero extended 64 bit immediate constant.
2547 
2548         Polymorphic over all scalar integer types, but does not support vector
2549         types.
2550         "#,
2551             &formats.binary_imm64,
2552         )
2553         .operands_in(vec![x, Y])
2554         .operands_out(vec![a]),
2555     );
2556 
2557     ig.push(
2558         Inst::new(
2559             "bor_imm",
2560             r#"
2561         Bitwise or with immediate.
2562 
2563         Same as `bor`, but one operand is a zero extended 64 bit immediate constant.
2564 
2565         Polymorphic over all scalar integer types, but does not support vector
2566         types.
2567         "#,
2568             &formats.binary_imm64,
2569         )
2570         .operands_in(vec![x, Y])
2571         .operands_out(vec![a]),
2572     );
2573 
2574     ig.push(
2575         Inst::new(
2576             "bxor_imm",
2577             r#"
2578         Bitwise xor with immediate.
2579 
2580         Same as `bxor`, but one operand is a zero extended 64 bit immediate constant.
2581 
2582         Polymorphic over all scalar integer types, but does not support vector
2583         types.
2584         "#,
2585             &formats.binary_imm64,
2586         )
2587         .operands_in(vec![x, Y])
2588         .operands_out(vec![a]),
2589     );
2590 
2591     let x = &Operand::new("x", Int).with_doc("Scalar or vector value to shift");
2592     let y = &Operand::new("y", iB).with_doc("Number of bits to shift");
2593     let Y = &Operand::new("Y", &imm.imm64);
2594     let a = &Operand::new("a", Int);
2595 
2596     ig.push(
2597         Inst::new(
2598             "rotl",
2599             r#"
2600         Rotate left.
2601 
2602         Rotate the bits in ``x`` by ``y`` places.
2603         "#,
2604             &formats.binary,
2605         )
2606         .operands_in(vec![x, y])
2607         .operands_out(vec![a]),
2608     );
2609 
2610     ig.push(
2611         Inst::new(
2612             "rotr",
2613             r#"
2614         Rotate right.
2615 
2616         Rotate the bits in ``x`` by ``y`` places.
2617         "#,
2618             &formats.binary,
2619         )
2620         .operands_in(vec![x, y])
2621         .operands_out(vec![a]),
2622     );
2623 
2624     ig.push(
2625         Inst::new(
2626             "rotl_imm",
2627             r#"
2628         Rotate left by immediate.
2629 
2630         Same as `rotl`, but one operand is a zero extended 64 bit immediate constant.
2631         "#,
2632             &formats.binary_imm64,
2633         )
2634         .operands_in(vec![x, Y])
2635         .operands_out(vec![a]),
2636     );
2637 
2638     ig.push(
2639         Inst::new(
2640             "rotr_imm",
2641             r#"
2642         Rotate right by immediate.
2643 
2644         Same as `rotr`, but one operand is a zero extended 64 bit immediate constant.
2645         "#,
2646             &formats.binary_imm64,
2647         )
2648         .operands_in(vec![x, Y])
2649         .operands_out(vec![a]),
2650     );
2651 
2652     ig.push(
2653         Inst::new(
2654             "ishl",
2655             r#"
2656         Integer shift left. Shift the bits in ``x`` towards the MSB by ``y``
2657         places. Shift in zero bits to the LSB.
2658 
2659         The shift amount is masked to the size of ``x``.
2660 
2661         When shifting a B-bits integer type, this instruction computes:
2662 
2663         ```text
2664             s &:= y \pmod B,
2665             a &:= x \cdot 2^s \pmod{2^B}.
2666         ```
2667         "#,
2668             &formats.binary,
2669         )
2670         .operands_in(vec![x, y])
2671         .operands_out(vec![a]),
2672     );
2673 
2674     ig.push(
2675         Inst::new(
2676             "ushr",
2677             r#"
2678         Unsigned shift right. Shift bits in ``x`` towards the LSB by ``y``
2679         places, shifting in zero bits to the MSB. Also called a *logical
2680         shift*.
2681 
2682         The shift amount is masked to the size of the register.
2683 
2684         When shifting a B-bits integer type, this instruction computes:
2685 
2686         ```text
2687             s &:= y \pmod B,
2688             a &:= \lfloor x \cdot 2^{-s} \rfloor.
2689         ```
2690         "#,
2691             &formats.binary,
2692         )
2693         .operands_in(vec![x, y])
2694         .operands_out(vec![a]),
2695     );
2696 
2697     ig.push(
2698         Inst::new(
2699             "sshr",
2700             r#"
2701         Signed shift right. Shift bits in ``x`` towards the LSB by ``y``
2702         places, shifting in sign bits to the MSB. Also called an *arithmetic
2703         shift*.
2704 
2705         The shift amount is masked to the size of the register.
2706         "#,
2707             &formats.binary,
2708         )
2709         .operands_in(vec![x, y])
2710         .operands_out(vec![a]),
2711     );
2712 
2713     ig.push(
2714         Inst::new(
2715             "ishl_imm",
2716             r#"
2717         Integer shift left by immediate.
2718 
2719         The shift amount is masked to the size of ``x``.
2720         "#,
2721             &formats.binary_imm64,
2722         )
2723         .operands_in(vec![x, Y])
2724         .operands_out(vec![a]),
2725     );
2726 
2727     ig.push(
2728         Inst::new(
2729             "ushr_imm",
2730             r#"
2731         Unsigned shift right by immediate.
2732 
2733         The shift amount is masked to the size of the register.
2734         "#,
2735             &formats.binary_imm64,
2736         )
2737         .operands_in(vec![x, Y])
2738         .operands_out(vec![a]),
2739     );
2740 
2741     ig.push(
2742         Inst::new(
2743             "sshr_imm",
2744             r#"
2745         Signed shift right by immediate.
2746 
2747         The shift amount is masked to the size of the register.
2748         "#,
2749             &formats.binary_imm64,
2750         )
2751         .operands_in(vec![x, Y])
2752         .operands_out(vec![a]),
2753     );
2754 
2755     let x = &Operand::new("x", iB);
2756     let a = &Operand::new("a", iB);
2757 
2758     ig.push(
2759         Inst::new(
2760             "bitrev",
2761             r#"
2762         Reverse the bits of a integer.
2763 
2764         Reverses the bits in ``x``.
2765         "#,
2766             &formats.unary,
2767         )
2768         .operands_in(vec![x])
2769         .operands_out(vec![a]),
2770     );
2771 
2772     ig.push(
2773         Inst::new(
2774             "clz",
2775             r#"
2776         Count leading zero bits.
2777 
2778         Starting from the MSB in ``x``, count the number of zero bits before
2779         reaching the first one bit. When ``x`` is zero, returns the size of x
2780         in bits.
2781         "#,
2782             &formats.unary,
2783         )
2784         .operands_in(vec![x])
2785         .operands_out(vec![a]),
2786     );
2787 
2788     ig.push(
2789         Inst::new(
2790             "cls",
2791             r#"
2792         Count leading sign bits.
2793 
2794         Starting from the MSB after the sign bit in ``x``, count the number of
2795         consecutive bits identical to the sign bit. When ``x`` is 0 or -1,
2796         returns one less than the size of x in bits.
2797         "#,
2798             &formats.unary,
2799         )
2800         .operands_in(vec![x])
2801         .operands_out(vec![a]),
2802     );
2803 
2804     ig.push(
2805         Inst::new(
2806             "ctz",
2807             r#"
2808         Count trailing zeros.
2809 
2810         Starting from the LSB in ``x``, count the number of zero bits before
2811         reaching the first one bit. When ``x`` is zero, returns the size of x
2812         in bits.
2813         "#,
2814             &formats.unary,
2815         )
2816         .operands_in(vec![x])
2817         .operands_out(vec![a]),
2818     );
2819 
2820     let x = &Operand::new("x", Int);
2821     let a = &Operand::new("a", Int);
2822 
2823     ig.push(
2824         Inst::new(
2825             "popcnt",
2826             r#"
2827         Population count
2828 
2829         Count the number of one bits in ``x``.
2830         "#,
2831             &formats.unary,
2832         )
2833         .operands_in(vec![x])
2834         .operands_out(vec![a]),
2835     );
2836 
2837     let Float = &TypeVar::new(
2838         "Float",
2839         "A scalar or vector floating point number",
2840         TypeSetBuilder::new()
2841             .floats(Interval::All)
2842             .simd_lanes(Interval::All)
2843             .dynamic_simd_lanes(Interval::All)
2844             .build(),
2845     );
2846     let Cond = &Operand::new("Cond", &imm.floatcc);
2847     let x = &Operand::new("x", Float);
2848     let y = &Operand::new("y", Float);
2849     let a = &Operand::new("a", &Float.as_bool());
2850 
2851     ig.push(
2852         Inst::new(
2853             "fcmp",
2854             r#"
2855         Floating point comparison.
2856 
2857         Two IEEE 754-2008 floating point numbers, `x` and `y`, relate to each
2858         other in exactly one of four ways:
2859 
2860         ```text
2861         == ==========================================
2862         UN Unordered when one or both numbers is NaN.
2863         EQ When `x = y`. (And `0.0 = -0.0`).
2864         LT When `x < y`.
2865         GT When `x > y`.
2866         == ==========================================
2867         ```
2868 
2869         The 14 `floatcc` condition codes each correspond to a subset of
2870         the four relations, except for the empty set which would always be
2871         false, and the full set which would always be true.
2872 
2873         The condition codes are divided into 7 'ordered' conditions which don't
2874         include UN, and 7 unordered conditions which all include UN.
2875 
2876         ```text
2877         +-------+------------+---------+------------+-------------------------+
2878         |Ordered             |Unordered             |Condition                |
2879         +=======+============+=========+============+=========================+
2880         |ord    |EQ | LT | GT|uno      |UN          |NaNs absent / present.   |
2881         +-------+------------+---------+------------+-------------------------+
2882         |eq     |EQ          |ueq      |UN | EQ     |Equal                    |
2883         +-------+------------+---------+------------+-------------------------+
2884         |one    |LT | GT     |ne       |UN | LT | GT|Not equal                |
2885         +-------+------------+---------+------------+-------------------------+
2886         |lt     |LT          |ult      |UN | LT     |Less than                |
2887         +-------+------------+---------+------------+-------------------------+
2888         |le     |LT | EQ     |ule      |UN | LT | EQ|Less than or equal       |
2889         +-------+------------+---------+------------+-------------------------+
2890         |gt     |GT          |ugt      |UN | GT     |Greater than             |
2891         +-------+------------+---------+------------+-------------------------+
2892         |ge     |GT | EQ     |uge      |UN | GT | EQ|Greater than or equal    |
2893         +-------+------------+---------+------------+-------------------------+
2894         ```
2895 
2896         The standard C comparison operators, `<, <=, >, >=`, are all ordered,
2897         so they are false if either operand is NaN. The C equality operator,
2898         `==`, is ordered, and since inequality is defined as the logical
2899         inverse it is *unordered*. They map to the `floatcc` condition
2900         codes as follows:
2901 
2902         ```text
2903         ==== ====== ============
2904         C    `Cond` Subset
2905         ==== ====== ============
2906         `==` eq     EQ
2907         `!=` ne     UN | LT | GT
2908         `<`  lt     LT
2909         `<=` le     LT | EQ
2910         `>`  gt     GT
2911         `>=` ge     GT | EQ
2912         ==== ====== ============
2913         ```
2914 
2915         This subset of condition codes also corresponds to the WebAssembly
2916         floating point comparisons of the same name.
2917 
2918         When this instruction compares floating point vectors, it returns a
2919         boolean vector with the results of lane-wise comparisons.
2920         "#,
2921             &formats.float_compare,
2922         )
2923         .operands_in(vec![Cond, x, y])
2924         .operands_out(vec![a]),
2925     );
2926 
2927     let f = &Operand::new("f", fflags);
2928 
2929     ig.push(
2930         Inst::new(
2931             "ffcmp",
2932             r#"
2933         Floating point comparison returning flags.
2934 
2935         Compares two numbers like `fcmp`, but returns floating point CPU
2936         flags instead of testing a specific condition.
2937         "#,
2938             &formats.binary,
2939         )
2940         .operands_in(vec![x, y])
2941         .operands_out(vec![f]),
2942     );
2943 
2944     let x = &Operand::new("x", Float);
2945     let y = &Operand::new("y", Float);
2946     let z = &Operand::new("z", Float);
2947     let a = &Operand::new("a", Float).with_doc("Result of applying operator to each lane");
2948 
2949     ig.push(
2950         Inst::new(
2951             "fadd",
2952             r#"
2953         Floating point addition.
2954         "#,
2955             &formats.binary,
2956         )
2957         .operands_in(vec![x, y])
2958         .operands_out(vec![a]),
2959     );
2960 
2961     ig.push(
2962         Inst::new(
2963             "fsub",
2964             r#"
2965         Floating point subtraction.
2966         "#,
2967             &formats.binary,
2968         )
2969         .operands_in(vec![x, y])
2970         .operands_out(vec![a]),
2971     );
2972 
2973     ig.push(
2974         Inst::new(
2975             "fmul",
2976             r#"
2977         Floating point multiplication.
2978         "#,
2979             &formats.binary,
2980         )
2981         .operands_in(vec![x, y])
2982         .operands_out(vec![a]),
2983     );
2984 
2985     ig.push(
2986         Inst::new(
2987             "fdiv",
2988             r#"
2989         Floating point division.
2990 
2991         Unlike the integer division instructions ` and
2992         `udiv`, this can't trap. Division by zero is infinity or
2993         NaN, depending on the dividend.
2994         "#,
2995             &formats.binary,
2996         )
2997         .operands_in(vec![x, y])
2998         .operands_out(vec![a]),
2999     );
3000 
3001     ig.push(
3002         Inst::new(
3003             "sqrt",
3004             r#"
3005         Floating point square root.
3006         "#,
3007             &formats.unary,
3008         )
3009         .operands_in(vec![x])
3010         .operands_out(vec![a]),
3011     );
3012 
3013     ig.push(
3014         Inst::new(
3015             "fma",
3016             r#"
3017         Floating point fused multiply-and-add.
3018 
3019         Computes `a := xy+z` without any intermediate rounding of the
3020         product.
3021         "#,
3022             &formats.ternary,
3023         )
3024         .operands_in(vec![x, y, z])
3025         .operands_out(vec![a]),
3026     );
3027 
3028     let a = &Operand::new("a", Float).with_doc("``x`` with its sign bit inverted");
3029 
3030     ig.push(
3031         Inst::new(
3032             "fneg",
3033             r#"
3034         Floating point negation.
3035 
3036         Note that this is a pure bitwise operation.
3037         "#,
3038             &formats.unary,
3039         )
3040         .operands_in(vec![x])
3041         .operands_out(vec![a]),
3042     );
3043 
3044     let a = &Operand::new("a", Float).with_doc("``x`` with its sign bit cleared");
3045 
3046     ig.push(
3047         Inst::new(
3048             "fabs",
3049             r#"
3050         Floating point absolute value.
3051 
3052         Note that this is a pure bitwise operation.
3053         "#,
3054             &formats.unary,
3055         )
3056         .operands_in(vec![x])
3057         .operands_out(vec![a]),
3058     );
3059 
3060     let a = &Operand::new("a", Float).with_doc("``x`` with its sign bit changed to that of ``y``");
3061 
3062     ig.push(
3063         Inst::new(
3064             "fcopysign",
3065             r#"
3066         Floating point copy sign.
3067 
3068         Note that this is a pure bitwise operation. The sign bit from ``y`` is
3069         copied to the sign bit of ``x``.
3070         "#,
3071             &formats.binary,
3072         )
3073         .operands_in(vec![x, y])
3074         .operands_out(vec![a]),
3075     );
3076 
3077     let a = &Operand::new("a", Float).with_doc("The smaller of ``x`` and ``y``");
3078 
3079     ig.push(
3080         Inst::new(
3081             "fmin",
3082             r#"
3083         Floating point minimum, propagating NaNs using the WebAssembly rules.
3084 
3085         If either operand is NaN, this returns NaN with an unspecified sign. Furthermore, if
3086         each input NaN consists of a mantissa whose most significant bit is 1 and the rest is
3087         0, then the output has the same form. Otherwise, the output mantissa's most significant
3088         bit is 1 and the rest is unspecified.
3089         "#,
3090             &formats.binary,
3091         )
3092         .operands_in(vec![x, y])
3093         .operands_out(vec![a]),
3094     );
3095 
3096     ig.push(
3097         Inst::new(
3098             "fmin_pseudo",
3099             r#"
3100         Floating point pseudo-minimum, propagating NaNs.  This behaves differently from ``fmin``.
3101         See <https://github.com/WebAssembly/simd/pull/122> for background.
3102 
3103         The behaviour is defined as ``fmin_pseudo(a, b) = (b < a) ? b : a``, and the behaviour
3104         for zero or NaN inputs follows from the behaviour of ``<`` with such inputs.
3105         "#,
3106             &formats.binary,
3107         )
3108         .operands_in(vec![x, y])
3109         .operands_out(vec![a]),
3110     );
3111 
3112     let a = &Operand::new("a", Float).with_doc("The larger of ``x`` and ``y``");
3113 
3114     ig.push(
3115         Inst::new(
3116             "fmax",
3117             r#"
3118         Floating point maximum, propagating NaNs using the WebAssembly rules.
3119 
3120         If either operand is NaN, this returns NaN with an unspecified sign. Furthermore, if
3121         each input NaN consists of a mantissa whose most significant bit is 1 and the rest is
3122         0, then the output has the same form. Otherwise, the output mantissa's most significant
3123         bit is 1 and the rest is unspecified.
3124         "#,
3125             &formats.binary,
3126         )
3127         .operands_in(vec![x, y])
3128         .operands_out(vec![a]),
3129     );
3130 
3131     ig.push(
3132         Inst::new(
3133             "fmax_pseudo",
3134             r#"
3135         Floating point pseudo-maximum, propagating NaNs.  This behaves differently from ``fmax``.
3136         See <https://github.com/WebAssembly/simd/pull/122> for background.
3137 
3138         The behaviour is defined as ``fmax_pseudo(a, b) = (a < b) ? b : a``, and the behaviour
3139         for zero or NaN inputs follows from the behaviour of ``<`` with such inputs.
3140         "#,
3141             &formats.binary,
3142         )
3143         .operands_in(vec![x, y])
3144         .operands_out(vec![a]),
3145     );
3146 
3147     let a = &Operand::new("a", Float).with_doc("``x`` rounded to integral value");
3148 
3149     ig.push(
3150         Inst::new(
3151             "ceil",
3152             r#"
3153         Round floating point round to integral, towards positive infinity.
3154         "#,
3155             &formats.unary,
3156         )
3157         .operands_in(vec![x])
3158         .operands_out(vec![a]),
3159     );
3160 
3161     ig.push(
3162         Inst::new(
3163             "floor",
3164             r#"
3165         Round floating point round to integral, towards negative infinity.
3166         "#,
3167             &formats.unary,
3168         )
3169         .operands_in(vec![x])
3170         .operands_out(vec![a]),
3171     );
3172 
3173     ig.push(
3174         Inst::new(
3175             "trunc",
3176             r#"
3177         Round floating point round to integral, towards zero.
3178         "#,
3179             &formats.unary,
3180         )
3181         .operands_in(vec![x])
3182         .operands_out(vec![a]),
3183     );
3184 
3185     ig.push(
3186         Inst::new(
3187             "nearest",
3188             r#"
3189         Round floating point round to integral, towards nearest with ties to
3190         even.
3191         "#,
3192             &formats.unary,
3193         )
3194         .operands_in(vec![x])
3195         .operands_out(vec![a]),
3196     );
3197 
3198     let a = &Operand::new("a", b1);
3199     let x = &Operand::new("x", Ref);
3200 
3201     ig.push(
3202         Inst::new(
3203             "is_null",
3204             r#"
3205         Reference verification.
3206 
3207         The condition code determines if the reference type in question is
3208         null or not.
3209         "#,
3210             &formats.unary,
3211         )
3212         .operands_in(vec![x])
3213         .operands_out(vec![a]),
3214     );
3215 
3216     let a = &Operand::new("a", b1);
3217     let x = &Operand::new("x", Ref);
3218 
3219     ig.push(
3220         Inst::new(
3221             "is_invalid",
3222             r#"
3223         Reference verification.
3224 
3225         The condition code determines if the reference type in question is
3226         invalid or not.
3227         "#,
3228             &formats.unary,
3229         )
3230         .operands_in(vec![x])
3231         .operands_out(vec![a]),
3232     );
3233 
3234     let Cond = &Operand::new("Cond", &imm.intcc);
3235     let f = &Operand::new("f", iflags);
3236     let a = &Operand::new("a", b1);
3237 
3238     ig.push(
3239         Inst::new(
3240             "trueif",
3241             r#"
3242         Test integer CPU flags for a specific condition.
3243 
3244         Check the CPU flags in ``f`` against the ``Cond`` condition code and
3245         return true when the condition code is satisfied.
3246         "#,
3247             &formats.int_cond,
3248         )
3249         .operands_in(vec![Cond, f])
3250         .operands_out(vec![a]),
3251     );
3252 
3253     let Cond = &Operand::new("Cond", &imm.floatcc);
3254     let f = &Operand::new("f", fflags);
3255 
3256     ig.push(
3257         Inst::new(
3258             "trueff",
3259             r#"
3260         Test floating point CPU flags for a specific condition.
3261 
3262         Check the CPU flags in ``f`` against the ``Cond`` condition code and
3263         return true when the condition code is satisfied.
3264         "#,
3265             &formats.float_cond,
3266         )
3267         .operands_in(vec![Cond, f])
3268         .operands_out(vec![a]),
3269     );
3270 
3271     let x = &Operand::new("x", Mem);
3272     let a = &Operand::new("a", MemTo).with_doc("Bits of `x` reinterpreted");
3273 
3274     ig.push(
3275         Inst::new(
3276             "bitcast",
3277             r#"
3278         Reinterpret the bits in `x` as a different type.
3279 
3280         The input and output types must be storable to memory and of the same
3281         size. A bitcast is equivalent to storing one type and loading the other
3282         type from the same address.
3283 
3284         For vector types, the lane types must also be the same size (see
3285         `raw_bitcast` for changing the lane size).
3286         "#,
3287             &formats.unary,
3288         )
3289         .operands_in(vec![x])
3290         .operands_out(vec![a]),
3291     );
3292 
3293     let x = &Operand::new("x", Any);
3294     let a = &Operand::new("a", AnyTo).with_doc("Bits of `x` reinterpreted");
3295 
3296     ig.push(
3297         Inst::new(
3298             "raw_bitcast",
3299             r#"
3300         Cast the bits in `x` as a different type of the same bit width.
3301 
3302         This instruction does not change the data's representation but allows
3303         data in registers to be used as different types, e.g. an i32x4 as a
3304         b8x16. The only constraint on the result `a` is that it can be
3305         `raw_bitcast` back to the original type. Also, in a raw_bitcast between
3306         vector types with the same number of lanes, the value of each result
3307         lane is a raw_bitcast of the corresponding operand lane. TODO there is
3308         currently no mechanism for enforcing the bit width constraint.
3309         "#,
3310             &formats.unary,
3311         )
3312         .operands_in(vec![x])
3313         .operands_out(vec![a]),
3314     );
3315 
3316     let a = &Operand::new("a", TxN).with_doc("A vector value");
3317     let s = &Operand::new("s", &TxN.lane_of()).with_doc("A scalar value");
3318 
3319     ig.push(
3320         Inst::new(
3321             "scalar_to_vector",
3322             r#"
3323             Copies a scalar value to a vector value.  The scalar is copied into the
3324             least significant lane of the vector, and all other lanes will be zero.
3325             "#,
3326             &formats.unary,
3327         )
3328         .operands_in(vec![s])
3329         .operands_out(vec![a]),
3330     );
3331 
3332     let Bool = &TypeVar::new(
3333         "Bool",
3334         "A scalar boolean type",
3335         TypeSetBuilder::new().bools(Interval::All).build(),
3336     );
3337 
3338     let BoolTo = &TypeVar::new(
3339         "BoolTo",
3340         "A smaller boolean type",
3341         TypeSetBuilder::new().bools(Interval::All).build(),
3342     );
3343 
3344     let x = &Operand::new("x", Bool);
3345     let a = &Operand::new("a", BoolTo);
3346 
3347     ig.push(
3348         Inst::new(
3349             "breduce",
3350             r#"
3351         Convert `x` to a smaller boolean type by discarding the most significant bits.
3352         "#,
3353             &formats.unary,
3354         )
3355         .operands_in(vec![x])
3356         .operands_out(vec![a]),
3357     );
3358 
3359     let BoolTo = &TypeVar::new(
3360         "BoolTo",
3361         "A larger boolean type",
3362         TypeSetBuilder::new().bools(Interval::All).build(),
3363     );
3364     let x = &Operand::new("x", Bool);
3365     let a = &Operand::new("a", BoolTo);
3366 
3367     ig.push(
3368         Inst::new(
3369             "bextend",
3370             r#"
3371         Convert `x` to a larger boolean type
3372         "#,
3373             &formats.unary,
3374         )
3375         .operands_in(vec![x])
3376         .operands_out(vec![a]),
3377     );
3378 
3379     let IntTo = &TypeVar::new(
3380         "IntTo",
3381         "A scalar integer type",
3382         TypeSetBuilder::new().ints(Interval::All).build(),
3383     );
3384     let x = &Operand::new("x", ScalarBool);
3385     let a = &Operand::new("a", IntTo);
3386 
3387     ig.push(
3388         Inst::new(
3389             "bint",
3390             r#"
3391         Convert `x` to an integer.
3392 
3393         True maps to 1 and false maps to 0.
3394         "#,
3395             &formats.unary,
3396         )
3397         .operands_in(vec![x])
3398         .operands_out(vec![a]),
3399     );
3400 
3401     let Bool = &TypeVar::new(
3402         "Bool",
3403         "A scalar or vector boolean type",
3404         TypeSetBuilder::new()
3405             .bools(Interval::All)
3406             .simd_lanes(Interval::All)
3407             .build(),
3408     );
3409     let IntTo = &TypeVar::new(
3410         "IntTo",
3411         "An integer type with the same number of lanes",
3412         TypeSetBuilder::new()
3413             .ints(Interval::All)
3414             .simd_lanes(Interval::All)
3415             .build(),
3416     );
3417     let x = &Operand::new("x", Bool);
3418     let a = &Operand::new("a", IntTo);
3419 
3420     ig.push(
3421         Inst::new(
3422             "bmask",
3423             r#"
3424         Convert `x` to an integer mask.
3425 
3426         True maps to all 1s and false maps to all 0s. The result type must have
3427         the same number of vector lanes as the input.
3428         "#,
3429             &formats.unary,
3430         )
3431         .operands_in(vec![x])
3432         .operands_out(vec![a]),
3433     );
3434 
3435     let Int = &TypeVar::new(
3436         "Int",
3437         "A scalar integer type",
3438         TypeSetBuilder::new().ints(Interval::All).build(),
3439     );
3440 
3441     let IntTo = &TypeVar::new(
3442         "IntTo",
3443         "A smaller integer type",
3444         TypeSetBuilder::new().ints(Interval::All).build(),
3445     );
3446     let x = &Operand::new("x", Int);
3447     let a = &Operand::new("a", IntTo);
3448 
3449     ig.push(
3450         Inst::new(
3451             "ireduce",
3452             r#"
3453         Convert `x` to a smaller integer type by discarding
3454         the most significant bits.
3455 
3456         This is the same as reducing modulo `2^n`.
3457         "#,
3458             &formats.unary,
3459         )
3460         .operands_in(vec![x])
3461         .operands_out(vec![a]),
3462     );
3463 
3464     let I16or32or64xN = &TypeVar::new(
3465         "I16or32or64xN",
3466         "A SIMD vector type containing integer lanes 16, 32, or 64 bits wide",
3467         TypeSetBuilder::new()
3468             .ints(16..64)
3469             .simd_lanes(2..8)
3470             .dynamic_simd_lanes(2..8)
3471             .includes_scalars(false)
3472             .build(),
3473     );
3474 
3475     let x = &Operand::new("x", I16or32or64xN);
3476     let y = &Operand::new("y", I16or32or64xN);
3477     let a = &Operand::new("a", &I16or32or64xN.split_lanes());
3478 
3479     ig.push(
3480         Inst::new(
3481             "snarrow",
3482             r#"
3483         Combine `x` and `y` into a vector with twice the lanes but half the integer width while
3484         saturating overflowing values to the signed maximum and minimum.
3485 
3486         The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4`
3487         and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value
3488         returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`.
3489             "#,
3490             &formats.binary,
3491         )
3492         .operands_in(vec![x, y])
3493         .operands_out(vec![a]),
3494     );
3495 
3496     ig.push(
3497         Inst::new(
3498             "unarrow",
3499             r#"
3500         Combine `x` and `y` into a vector with twice the lanes but half the integer width while
3501         saturating overflowing values to the unsigned maximum and minimum.
3502 
3503         Note that all input lanes are considered signed: any negative lanes will overflow and be
3504         replaced with the unsigned minimum, `0x00`.
3505 
3506         The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4`
3507         and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value
3508         returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`.
3509             "#,
3510             &formats.binary,
3511         )
3512         .operands_in(vec![x, y])
3513         .operands_out(vec![a]),
3514     );
3515 
3516     ig.push(
3517         Inst::new(
3518             "uunarrow",
3519             r#"
3520         Combine `x` and `y` into a vector with twice the lanes but half the integer width while
3521         saturating overflowing values to the unsigned maximum and minimum.
3522 
3523         Note that all input lanes are considered unsigned: any negative values will be interpreted as unsigned, overflowing and being replaced with the unsigned maximum.
3524 
3525         The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4`
3526         and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value
3527         returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`.
3528             "#,
3529             &formats.binary,
3530         )
3531         .operands_in(vec![x, y])
3532         .operands_out(vec![a]),
3533     );
3534 
3535     let I8or16or32xN = &TypeVar::new(
3536         "I8or16or32xN",
3537         "A SIMD vector type containing integer lanes 8, 16, or 32 bits wide.",
3538         TypeSetBuilder::new()
3539             .ints(8..32)
3540             .simd_lanes(2..16)
3541             .dynamic_simd_lanes(2..16)
3542             .includes_scalars(false)
3543             .build(),
3544     );
3545 
3546     let x = &Operand::new("x", I8or16or32xN);
3547     let a = &Operand::new("a", &I8or16or32xN.merge_lanes());
3548 
3549     ig.push(
3550         Inst::new(
3551             "swiden_low",
3552             r#"
3553         Widen the low lanes of `x` using signed extension.
3554 
3555         This will double the lane width and halve the number of lanes.
3556             "#,
3557             &formats.unary,
3558         )
3559         .operands_in(vec![x])
3560         .operands_out(vec![a]),
3561     );
3562 
3563     ig.push(
3564         Inst::new(
3565             "swiden_high",
3566             r#"
3567         Widen the high lanes of `x` using signed extension.
3568 
3569         This will double the lane width and halve the number of lanes.
3570             "#,
3571             &formats.unary,
3572         )
3573         .operands_in(vec![x])
3574         .operands_out(vec![a]),
3575     );
3576 
3577     ig.push(
3578         Inst::new(
3579             "uwiden_low",
3580             r#"
3581         Widen the low lanes of `x` using unsigned extension.
3582 
3583         This will double the lane width and halve the number of lanes.
3584             "#,
3585             &formats.unary,
3586         )
3587         .operands_in(vec![x])
3588         .operands_out(vec![a]),
3589     );
3590 
3591     ig.push(
3592         Inst::new(
3593             "uwiden_high",
3594             r#"
3595             Widen the high lanes of `x` using unsigned extension.
3596 
3597             This will double the lane width and halve the number of lanes.
3598             "#,
3599             &formats.unary,
3600         )
3601         .operands_in(vec![x])
3602         .operands_out(vec![a]),
3603     );
3604 
3605     let x = &Operand::new("x", I8or16or32xN);
3606     let y = &Operand::new("y", I8or16or32xN);
3607     let a = &Operand::new("a", I8or16or32xN);
3608 
3609     ig.push(
3610         Inst::new(
3611             "iadd_pairwise",
3612             r#"
3613         Does lane-wise integer pairwise addition on two operands, putting the
3614         combined results into a single vector result. Here a pair refers to adjacent
3615         lanes in a vector, i.e. i*2 + (i*2+1) for i == num_lanes/2. The first operand
3616         pairwise add results will make up the low half of the resulting vector while
3617         the second operand pairwise add results will make up the upper half of the
3618         resulting vector.
3619             "#,
3620             &formats.binary,
3621         )
3622         .operands_in(vec![x, y])
3623         .operands_out(vec![a]),
3624     );
3625 
3626     let I16x8 = &TypeVar::new(
3627         "I16x8",
3628         "A SIMD vector type containing 8 integer lanes each 16 bits wide.",
3629         TypeSetBuilder::new()
3630             .ints(16..16)
3631             .simd_lanes(8..8)
3632             .includes_scalars(false)
3633             .build(),
3634     );
3635 
3636     let x = &Operand::new("x", I16x8);
3637     let y = &Operand::new("y", I16x8);
3638     let a = &Operand::new("a", &I16x8.merge_lanes());
3639 
3640     ig.push(
3641         Inst::new(
3642             "widening_pairwise_dot_product_s",
3643             r#"
3644         Takes corresponding elements in `x` and `y`, performs a sign-extending length-doubling
3645         multiplication on them, then adds adjacent pairs of elements to form the result.  For
3646         example, if the input vectors are `[x3, x2, x1, x0]` and `[y3, y2, y1, y0]`, it produces
3647         the vector `[r1, r0]`, where `r1 = sx(x3) * sx(y3) + sx(x2) * sx(y2)` and
3648         `r0 = sx(x1) * sx(y1) + sx(x0) * sx(y0)`, and `sx(n)` sign-extends `n` to twice its width.
3649 
3650         This will double the lane width and halve the number of lanes.  So the resulting
3651         vector has the same number of bits as `x` and `y` do (individually).
3652 
3653         See <https://github.com/WebAssembly/simd/pull/127> for background info.
3654             "#,
3655             &formats.binary,
3656         )
3657         .operands_in(vec![x, y])
3658         .operands_out(vec![a]),
3659     );
3660 
3661     let IntTo = &TypeVar::new(
3662         "IntTo",
3663         "A larger integer type with the same number of lanes",
3664         TypeSetBuilder::new()
3665             .ints(Interval::All)
3666             .simd_lanes(Interval::All)
3667             .build(),
3668     );
3669     let x = &Operand::new("x", Int);
3670     let a = &Operand::new("a", IntTo);
3671 
3672     ig.push(
3673         Inst::new(
3674             "uextend",
3675             r#"
3676         Convert `x` to a larger integer type by zero-extending.
3677 
3678         Each lane in `x` is converted to a larger integer type by adding
3679         zeroes. The result has the same numerical value as `x` when both are
3680         interpreted as unsigned integers.
3681 
3682         The result type must have the same number of vector lanes as the input,
3683         and each lane must not have fewer bits that the input lanes. If the
3684         input and output types are the same, this is a no-op.
3685         "#,
3686             &formats.unary,
3687         )
3688         .operands_in(vec![x])
3689         .operands_out(vec![a]),
3690     );
3691 
3692     ig.push(
3693         Inst::new(
3694             "sextend",
3695             r#"
3696         Convert `x` to a larger integer type by sign-extending.
3697 
3698         Each lane in `x` is converted to a larger integer type by replicating
3699         the sign bit. The result has the same numerical value as `x` when both
3700         are interpreted as signed integers.
3701 
3702         The result type must have the same number of vector lanes as the input,
3703         and each lane must not have fewer bits that the input lanes. If the
3704         input and output types are the same, this is a no-op.
3705         "#,
3706             &formats.unary,
3707         )
3708         .operands_in(vec![x])
3709         .operands_out(vec![a]),
3710     );
3711 
3712     let FloatTo = &TypeVar::new(
3713         "FloatTo",
3714         "A scalar or vector floating point number",
3715         TypeSetBuilder::new()
3716             .floats(Interval::All)
3717             .simd_lanes(Interval::All)
3718             .build(),
3719     );
3720     let x = &Operand::new("x", Float);
3721     let a = &Operand::new("a", FloatTo);
3722 
3723     ig.push(
3724         Inst::new(
3725             "fpromote",
3726             r#"
3727         Convert `x` to a larger floating point format.
3728 
3729         Each lane in `x` is converted to the destination floating point format.
3730         This is an exact operation.
3731 
3732         Cranelift currently only supports two floating point formats
3733         - `f32` and `f64`. This may change in the future.
3734 
3735         The result type must have the same number of vector lanes as the input,
3736         and the result lanes must not have fewer bits than the input lanes. If
3737         the input and output types are the same, this is a no-op.
3738         "#,
3739             &formats.unary,
3740         )
3741         .operands_in(vec![x])
3742         .operands_out(vec![a]),
3743     );
3744 
3745     ig.push(
3746         Inst::new(
3747             "fdemote",
3748             r#"
3749         Convert `x` to a smaller floating point format.
3750 
3751         Each lane in `x` is converted to the destination floating point format
3752         by rounding to nearest, ties to even.
3753 
3754         Cranelift currently only supports two floating point formats
3755         - `f32` and `f64`. This may change in the future.
3756 
3757         The result type must have the same number of vector lanes as the input,
3758         and the result lanes must not have more bits than the input lanes. If
3759         the input and output types are the same, this is a no-op.
3760         "#,
3761             &formats.unary,
3762         )
3763         .operands_in(vec![x])
3764         .operands_out(vec![a]),
3765     );
3766 
3767     let F64x2 = &TypeVar::new(
3768         "F64x2",
3769         "A SIMD vector type consisting of 2 lanes of 64-bit floats",
3770         TypeSetBuilder::new()
3771             .floats(64..64)
3772             .simd_lanes(2..2)
3773             .includes_scalars(false)
3774             .build(),
3775     );
3776     let F32x4 = &TypeVar::new(
3777         "F32x4",
3778         "A SIMD vector type consisting of 4 lanes of 32-bit floats",
3779         TypeSetBuilder::new()
3780             .floats(32..32)
3781             .simd_lanes(4..4)
3782             .includes_scalars(false)
3783             .build(),
3784     );
3785 
3786     let x = &Operand::new("x", F64x2);
3787     let a = &Operand::new("a", F32x4);
3788 
3789     ig.push(
3790         Inst::new(
3791             "fvdemote",
3792             r#"
3793                 Convert `x` to a smaller floating point format.
3794 
3795                 Each lane in `x` is converted to the destination floating point format
3796                 by rounding to nearest, ties to even.
3797 
3798                 Cranelift currently only supports two floating point formats
3799                 - `f32` and `f64`. This may change in the future.
3800 
3801                 Fvdemote differs from fdemote in that with fvdemote it targets vectors.
3802                 Fvdemote is constrained to having the input type being F64x2 and the result
3803                 type being F32x4. The result lane that was the upper half of the input lane
3804                 is initialized to zero.
3805                 "#,
3806             &formats.unary,
3807         )
3808         .operands_in(vec![x])
3809         .operands_out(vec![a]),
3810     );
3811 
3812     ig.push(
3813         Inst::new(
3814             "fvpromote_low",
3815             r#"
3816         Converts packed single precision floating point to packed double precision floating point.
3817 
3818         Considering only the lower half of the register, the low lanes in `x` are interpreted as
3819         single precision floats that are then converted to a double precision floats.
3820 
3821         The result type will have half the number of vector lanes as the input. Fvpromote_low is
3822         constrained to input F32x4 with a result type of F64x2.
3823         "#,
3824             &formats.unary,
3825         )
3826         .operands_in(vec![a])
3827         .operands_out(vec![x]),
3828     );
3829 
3830     let FloatScalar = &TypeVar::new(
3831         "FloatScalar",
3832         "A scalar only floating point number",
3833         TypeSetBuilder::new().floats(Interval::All).build(),
3834     );
3835     let x = &Operand::new("x", FloatScalar);
3836     let a = &Operand::new("a", IntTo);
3837 
3838     ig.push(
3839         Inst::new(
3840             "fcvt_to_uint",
3841             r#"
3842         Converts floating point scalars to unsigned integer.
3843 
3844         Only operates on `x` if it is a scalar. If `x` is NaN or if
3845         the unsigned integral value cannot be represented in the result
3846         type, this instruction traps.
3847 
3848         "#,
3849             &formats.unary,
3850         )
3851         .operands_in(vec![x])
3852         .operands_out(vec![a])
3853         .can_trap(true),
3854     );
3855 
3856     ig.push(
3857         Inst::new(
3858             "fcvt_to_sint",
3859             r#"
3860         Converts floating point scalars to signed integer.
3861 
3862         Only operates on `x` if it is a scalar. If `x` is NaN or if
3863         the unsigned integral value cannot be represented in the result
3864         type, this instruction traps.
3865 
3866         "#,
3867             &formats.unary,
3868         )
3869         .operands_in(vec![x])
3870         .operands_out(vec![a])
3871         .can_trap(true),
3872     );
3873 
3874     let x = &Operand::new("x", Float);
3875     let a = &Operand::new("a", IntTo);
3876 
3877     ig.push(
3878         Inst::new(
3879             "fcvt_to_uint_sat",
3880             r#"
3881         Convert floating point to unsigned integer as fcvt_to_uint does, but
3882         saturates the input instead of trapping. NaN and negative values are
3883         converted to 0.
3884         "#,
3885             &formats.unary,
3886         )
3887         .operands_in(vec![x])
3888         .operands_out(vec![a]),
3889     );
3890 
3891     ig.push(
3892         Inst::new(
3893             "fcvt_to_sint_sat",
3894             r#"
3895         Convert floating point to signed integer as fcvt_to_sint does, but
3896         saturates the input instead of trapping. NaN values are converted to 0.
3897         "#,
3898             &formats.unary,
3899         )
3900         .operands_in(vec![x])
3901         .operands_out(vec![a]),
3902     );
3903 
3904     let Int = &TypeVar::new(
3905         "Int",
3906         "A scalar or vector integer type",
3907         TypeSetBuilder::new()
3908             .ints(Interval::All)
3909             .simd_lanes(Interval::All)
3910             .build(),
3911     );
3912     let x = &Operand::new("x", Int);
3913     let a = &Operand::new("a", FloatTo);
3914 
3915     ig.push(
3916         Inst::new(
3917             "fcvt_from_uint",
3918             r#"
3919         Convert unsigned integer to floating point.
3920 
3921         Each lane in `x` is interpreted as an unsigned integer and converted to
3922         floating point using round to nearest, ties to even.
3923 
3924         The result type must have the same number of vector lanes as the input.
3925         "#,
3926             &formats.unary,
3927         )
3928         .operands_in(vec![x])
3929         .operands_out(vec![a]),
3930     );
3931 
3932     ig.push(
3933         Inst::new(
3934             "fcvt_from_sint",
3935             r#"
3936         Convert signed integer to floating point.
3937 
3938         Each lane in `x` is interpreted as a signed integer and converted to
3939         floating point using round to nearest, ties to even.
3940 
3941         The result type must have the same number of vector lanes as the input.
3942         "#,
3943             &formats.unary,
3944         )
3945         .operands_in(vec![x])
3946         .operands_out(vec![a]),
3947     );
3948 
3949     ig.push(
3950         Inst::new(
3951             "fcvt_low_from_sint",
3952             r#"
3953         Converts packed signed 32-bit integers to packed double precision floating point.
3954 
3955         Considering only the low half of the register, each lane in `x` is interpreted as a
3956         signed 32-bit integer that is then converted to a double precision float. This
3957         instruction differs from fcvt_from_sint in that it converts half the number of lanes
3958         which are converted to occupy twice the number of bits. No rounding should be needed
3959         for the resulting float.
3960 
3961         The result type will have half the number of vector lanes as the input.
3962         "#,
3963             &formats.unary,
3964         )
3965         .operands_in(vec![x])
3966         .operands_out(vec![a]),
3967     );
3968 
3969     let WideInt = &TypeVar::new(
3970         "WideInt",
3971         "An integer type with lanes from `i16` upwards",
3972         TypeSetBuilder::new()
3973             .ints(16..128)
3974             .simd_lanes(Interval::All)
3975             .build(),
3976     );
3977     let x = &Operand::new("x", WideInt);
3978     let lo = &Operand::new("lo", &WideInt.half_width()).with_doc("The low bits of `x`");
3979     let hi = &Operand::new("hi", &WideInt.half_width()).with_doc("The high bits of `x`");
3980 
3981     ig.push(
3982         Inst::new(
3983             "isplit",
3984             r#"
3985         Split an integer into low and high parts.
3986 
3987         Vectors of integers are split lane-wise, so the results have the same
3988         number of lanes as the input, but the lanes are half the size.
3989 
3990         Returns the low half of `x` and the high half of `x` as two independent
3991         values.
3992         "#,
3993             &formats.unary,
3994         )
3995         .operands_in(vec![x])
3996         .operands_out(vec![lo, hi]),
3997     );
3998 
3999     let NarrowInt = &TypeVar::new(
4000         "NarrowInt",
4001         "An integer type with lanes type to `i64`",
4002         TypeSetBuilder::new()
4003             .ints(8..64)
4004             .simd_lanes(Interval::All)
4005             .build(),
4006     );
4007 
4008     let lo = &Operand::new("lo", NarrowInt);
4009     let hi = &Operand::new("hi", NarrowInt);
4010     let a = &Operand::new("a", &NarrowInt.double_width())
4011         .with_doc("The concatenation of `lo` and `hi`");
4012 
4013     ig.push(
4014         Inst::new(
4015             "iconcat",
4016             r#"
4017         Concatenate low and high bits to form a larger integer type.
4018 
4019         Vectors of integers are concatenated lane-wise such that the result has
4020         the same number of lanes as the inputs, but the lanes are twice the
4021         size.
4022         "#,
4023             &formats.binary,
4024         )
4025         .operands_in(vec![lo, hi])
4026         .operands_out(vec![a]),
4027     );
4028 
4029     // Instructions relating to atomic memory accesses and fences
4030     let AtomicMem = &TypeVar::new(
4031         "AtomicMem",
4032         "Any type that can be stored in memory, which can be used in an atomic operation",
4033         TypeSetBuilder::new().ints(8..64).build(),
4034     );
4035     let x = &Operand::new("x", AtomicMem).with_doc("Value to be atomically stored");
4036     let a = &Operand::new("a", AtomicMem).with_doc("Value atomically loaded");
4037     let e = &Operand::new("e", AtomicMem).with_doc("Expected value in CAS");
4038     let p = &Operand::new("p", iAddr);
4039     let MemFlags = &Operand::new("MemFlags", &imm.memflags);
4040     let AtomicRmwOp = &Operand::new("AtomicRmwOp", &imm.atomic_rmw_op);
4041 
4042     ig.push(
4043         Inst::new(
4044             "atomic_rmw",
4045             r#"
4046         Atomically read-modify-write memory at `p`, with second operand `x`.  The old value is
4047         returned.  `p` has the type of the target word size, and `x` may be an integer type of
4048         8, 16, 32 or 64 bits, even on a 32-bit target.  The type of the returned value is the
4049         same as the type of `x`.  This operation is sequentially consistent and creates
4050         happens-before edges that order normal (non-atomic) loads and stores.
4051         "#,
4052             &formats.atomic_rmw,
4053         )
4054         .operands_in(vec![MemFlags, AtomicRmwOp, p, x])
4055         .operands_out(vec![a])
4056         .can_load(true)
4057         .can_store(true)
4058         .other_side_effects(true),
4059     );
4060 
4061     ig.push(
4062         Inst::new(
4063             "atomic_cas",
4064             r#"
4065         Perform an atomic compare-and-swap operation on memory at `p`, with expected value `e`,
4066         storing `x` if the value at `p` equals `e`.  The old value at `p` is returned,
4067         regardless of whether the operation succeeds or fails.  `p` has the type of the target
4068         word size, and `x` and `e` must have the same type and the same size, which may be an
4069         integer type of 8, 16, 32 or 64 bits, even on a 32-bit target.  The type of the returned
4070         value is the same as the type of `x` and `e`.  This operation is sequentially
4071         consistent and creates happens-before edges that order normal (non-atomic) loads and
4072         stores.
4073         "#,
4074             &formats.atomic_cas,
4075         )
4076         .operands_in(vec![MemFlags, p, e, x])
4077         .operands_out(vec![a])
4078         .can_load(true)
4079         .can_store(true)
4080         .other_side_effects(true),
4081     );
4082 
4083     ig.push(
4084         Inst::new(
4085             "atomic_load",
4086             r#"
4087         Atomically load from memory at `p`.
4088 
4089         This is a polymorphic instruction that can load any value type which has a memory
4090         representation.  It should only be used for integer types with 8, 16, 32 or 64 bits.
4091         This operation is sequentially consistent and creates happens-before edges that order
4092         normal (non-atomic) loads and stores.
4093         "#,
4094             &formats.load_no_offset,
4095         )
4096         .operands_in(vec![MemFlags, p])
4097         .operands_out(vec![a])
4098         .can_load(true)
4099         .other_side_effects(true),
4100     );
4101 
4102     ig.push(
4103         Inst::new(
4104             "atomic_store",
4105             r#"
4106         Atomically store `x` to memory at `p`.
4107 
4108         This is a polymorphic instruction that can store any value type with a memory
4109         representation.  It should only be used for integer types with 8, 16, 32 or 64 bits.
4110         This operation is sequentially consistent and creates happens-before edges that order
4111         normal (non-atomic) loads and stores.
4112         "#,
4113             &formats.store_no_offset,
4114         )
4115         .operands_in(vec![MemFlags, x, p])
4116         .can_store(true)
4117         .other_side_effects(true),
4118     );
4119 
4120     ig.push(
4121         Inst::new(
4122             "fence",
4123             r#"
4124         A memory fence.  This must provide ordering to ensure that, at a minimum, neither loads
4125         nor stores of any kind may move forwards or backwards across the fence.  This operation
4126         is sequentially consistent.
4127         "#,
4128             &formats.nullary,
4129         )
4130         .other_side_effects(true),
4131     );
4132 
4133     let TxN = &TypeVar::new(
4134         "TxN",
4135         "A dynamic vector type",
4136         TypeSetBuilder::new()
4137             .ints(Interval::All)
4138             .floats(Interval::All)
4139             .bools(Interval::All)
4140             .dynamic_simd_lanes(Interval::All)
4141             .build(),
4142     );
4143     let x = &Operand::new("x", TxN).with_doc("The dynamic vector to extract from");
4144     let y = &Operand::new("y", &imm.uimm8).with_doc("128-bit vector index");
4145     let a = &Operand::new("a", &TxN.dynamic_to_vector()).with_doc("New fixed vector");
4146 
4147     ig.push(
4148         Inst::new(
4149             "extract_vector",
4150             r#"
4151         Return a fixed length sub vector, extracted from a dynamic vector.
4152         "#,
4153             &formats.binary_imm8,
4154         )
4155         .operands_in(vec![x, y])
4156         .operands_out(vec![a]),
4157     );
4158 }
4159