cranelift_codegen_meta/shared/
instructions.rs

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