Skip to main content

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