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