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