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