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