cranelift_codegen_meta/shared/
instructions.rs

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