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