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