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