cranelift_codegen_meta/shared/
instructions.rs

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