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 constant =
1459         &Operand::new("constant", &imm.pool_constant).with_doc("A constant in the constant pool");
1460     let address = &Operand::new("address", iAddr);
1461     ig.push(
1462         Inst::new(
1463             "const_addr",
1464             r#"
1465         Calculate the base address of a value in the constant pool.
1466         "#,
1467             &formats.unary_const,
1468         )
1469         .operands_in(vec![constant])
1470         .operands_out(vec![address]),
1471     );
1472 
1473     let mask = &Operand::new("mask", &imm.uimm128)
1474         .with_doc("The 16 immediate bytes used for selecting the elements to shuffle");
1475     let Tx16 = &TypeVar::new(
1476         "Tx16",
1477         "A SIMD vector with exactly 16 lanes of 8-bit values; eventually this may support other \
1478          lane counts and widths",
1479         TypeSetBuilder::new()
1480             .ints(8..8)
1481             .bools(8..8)
1482             .simd_lanes(16..16)
1483             .includes_scalars(false)
1484             .build(),
1485     );
1486     let a = &Operand::new("a", Tx16).with_doc("A vector value");
1487     let b = &Operand::new("b", Tx16).with_doc("A vector value");
1488 
1489     ig.push(
1490         Inst::new(
1491             "shuffle",
1492             r#"
1493         SIMD vector shuffle.
1494 
1495         Shuffle two vectors using the given immediate bytes. For each of the 16 bytes of the
1496         immediate, a value i of 0-15 selects the i-th element of the first vector and a value i of
1497         16-31 selects the (i-16)th element of the second vector. Immediate values outside of the
1498         0-31 range place a 0 in the resulting vector lane.
1499         "#,
1500             &formats.shuffle,
1501         )
1502         .operands_in(vec![a, b, mask])
1503         .operands_out(vec![a]),
1504     );
1505 
1506     let a = &Operand::new("a", Ref).with_doc("A constant reference null value");
1507 
1508     ig.push(
1509         Inst::new(
1510             "null",
1511             r#"
1512         Null constant value for reference types.
1513 
1514         Create a scalar reference SSA value with a constant null value.
1515         "#,
1516             &formats.nullary,
1517         )
1518         .operands_out(vec![a]),
1519     );
1520 
1521     ig.push(Inst::new(
1522         "nop",
1523         r#"
1524         Just a dummy instruction.
1525 
1526         Note: this doesn't compile to a machine code nop.
1527         "#,
1528         &formats.nullary,
1529     ));
1530 
1531     let c = &Operand::new("c", Testable).with_doc("Controlling value to test");
1532     let x = &Operand::new("x", Any).with_doc("Value to use when `c` is true");
1533     let y = &Operand::new("y", Any).with_doc("Value to use when `c` is false");
1534     let a = &Operand::new("a", Any);
1535 
1536     ig.push(
1537         Inst::new(
1538             "select",
1539             r#"
1540         Conditional select.
1541 
1542         This instruction selects whole values. Use `vselect` for
1543         lane-wise selection.
1544         "#,
1545             &formats.ternary,
1546         )
1547         .operands_in(vec![c, x, y])
1548         .operands_out(vec![a]),
1549     );
1550 
1551     let cc = &Operand::new("cc", &imm.intcc).with_doc("Controlling condition code");
1552     let flags = &Operand::new("flags", iflags).with_doc("The machine's flag register");
1553 
1554     ig.push(
1555         Inst::new(
1556             "selectif",
1557             r#"
1558         Conditional select, dependent on integer condition codes.
1559         "#,
1560             &formats.int_select,
1561         )
1562         .operands_in(vec![cc, flags, x, y])
1563         .operands_out(vec![a]),
1564     );
1565 
1566     ig.push(
1567         Inst::new(
1568             "selectif_spectre_guard",
1569             r#"
1570             Conditional select intended for Spectre guards.
1571 
1572             This operation is semantically equivalent to a selectif instruction.
1573             However, it is guaranteed to not be removed or otherwise altered by any
1574             optimization pass, and is guaranteed to result in a conditional-move
1575             instruction, not a branch-based lowering.  As such, it is suitable
1576             for use when producing Spectre guards. For example, a bounds-check
1577             may guard against unsafe speculation past a bounds-check conditional
1578             branch by passing the address or index to be accessed through a
1579             conditional move, also gated on the same condition. Because no
1580             Spectre-vulnerable processors are known to perform speculation on
1581             conditional move instructions, this is guaranteed to pick the
1582             correct input. If the selected input in case of overflow is a "safe"
1583             value, for example a null pointer that causes an exception in the
1584             speculative path, this ensures that no Spectre vulnerability will
1585             exist.
1586             "#,
1587             &formats.int_select,
1588         )
1589         .operands_in(vec![cc, flags, x, y])
1590         .operands_out(vec![a])
1591         .other_side_effects(true),
1592     );
1593 
1594     let c = &Operand::new("c", Any).with_doc("Controlling value to test");
1595     ig.push(
1596         Inst::new(
1597             "bitselect",
1598             r#"
1599         Conditional select of bits.
1600 
1601         For each bit in `c`, this instruction selects the corresponding bit from `x` if the bit
1602         in `c` is 1 and the corresponding bit from `y` if the bit in `c` is 0. See also:
1603         `select`, `vselect`.
1604         "#,
1605             &formats.ternary,
1606         )
1607         .operands_in(vec![c, x, y])
1608         .operands_out(vec![a]),
1609     );
1610 
1611     let x = &Operand::new("x", Any);
1612 
1613     ig.push(
1614         Inst::new(
1615             "copy",
1616             r#"
1617         Register-register copy.
1618 
1619         This instruction copies its input, preserving the value type.
1620 
1621         A pure SSA-form program does not need to copy values, but this
1622         instruction is useful for representing intermediate stages during
1623         instruction transformations, and the register allocator needs a way of
1624         representing register copies.
1625         "#,
1626             &formats.unary,
1627         )
1628         .operands_in(vec![x])
1629         .operands_out(vec![a]),
1630     );
1631 
1632     let x = &Operand::new("x", TxN).with_doc("Vector to split");
1633     let lo = &Operand::new("lo", &TxN.half_vector()).with_doc("Low-numbered lanes of `x`");
1634     let hi = &Operand::new("hi", &TxN.half_vector()).with_doc("High-numbered lanes of `x`");
1635 
1636     ig.push(
1637         Inst::new(
1638             "vsplit",
1639             r#"
1640         Split a vector into two halves.
1641 
1642         Split the vector `x` into two separate values, each containing half of
1643         the lanes from ``x``. The result may be two scalars if ``x`` only had
1644         two lanes.
1645         "#,
1646             &formats.unary,
1647         )
1648         .operands_in(vec![x])
1649         .operands_out(vec![lo, hi]),
1650     );
1651 
1652     let Any128 = &TypeVar::new(
1653         "Any128",
1654         "Any scalar or vector type with as most 128 lanes",
1655         TypeSetBuilder::new()
1656             .ints(Interval::All)
1657             .floats(Interval::All)
1658             .bools(Interval::All)
1659             .simd_lanes(1..128)
1660             .includes_scalars(true)
1661             .build(),
1662     );
1663 
1664     let x = &Operand::new("x", Any128).with_doc("Low-numbered lanes");
1665     let y = &Operand::new("y", Any128).with_doc("High-numbered lanes");
1666     let a = &Operand::new("a", &Any128.double_vector()).with_doc("Concatenation of `x` and `y`");
1667 
1668     ig.push(
1669         Inst::new(
1670             "vconcat",
1671             r#"
1672         Vector concatenation.
1673 
1674         Return a vector formed by concatenating ``x`` and ``y``. The resulting
1675         vector type has twice as many lanes as each of the inputs. The lanes of
1676         ``x`` appear as the low-numbered lanes, and the lanes of ``y`` become
1677         the high-numbered lanes of ``a``.
1678 
1679         It is possible to form a vector by concatenating two scalars.
1680         "#,
1681             &formats.binary,
1682         )
1683         .operands_in(vec![x, y])
1684         .operands_out(vec![a]),
1685     );
1686 
1687     let c = &Operand::new("c", &TxN.as_bool()).with_doc("Controlling vector");
1688     let x = &Operand::new("x", TxN).with_doc("Value to use where `c` is true");
1689     let y = &Operand::new("y", TxN).with_doc("Value to use where `c` is false");
1690     let a = &Operand::new("a", TxN);
1691 
1692     ig.push(
1693         Inst::new(
1694             "vselect",
1695             r#"
1696         Vector lane select.
1697 
1698         Select lanes from ``x`` or ``y`` controlled by the lanes of the boolean
1699         vector ``c``.
1700         "#,
1701             &formats.ternary,
1702         )
1703         .operands_in(vec![c, x, y])
1704         .operands_out(vec![a]),
1705     );
1706 
1707     let s = &Operand::new("s", b1);
1708 
1709     ig.push(
1710         Inst::new(
1711             "vany_true",
1712             r#"
1713         Reduce a vector to a scalar boolean.
1714 
1715         Return a scalar boolean true if any lane in ``a`` is non-zero, false otherwise.
1716         "#,
1717             &formats.unary,
1718         )
1719         .operands_in(vec![a])
1720         .operands_out(vec![s]),
1721     );
1722 
1723     ig.push(
1724         Inst::new(
1725             "vall_true",
1726             r#"
1727         Reduce a vector to a scalar boolean.
1728 
1729         Return a scalar boolean true if all lanes in ``i`` are non-zero, false otherwise.
1730         "#,
1731             &formats.unary,
1732         )
1733         .operands_in(vec![a])
1734         .operands_out(vec![s]),
1735     );
1736 
1737     let a = &Operand::new("a", TxN);
1738     let x = &Operand::new("x", Int);
1739 
1740     ig.push(
1741         Inst::new(
1742             "vhigh_bits",
1743             r#"
1744         Reduce a vector to a scalar integer.
1745 
1746         Return a scalar integer, consisting of the concatenation of the most significant bit
1747         of each lane of ``a``.
1748         "#,
1749             &formats.unary,
1750         )
1751         .operands_in(vec![a])
1752         .operands_out(vec![x]),
1753     );
1754 
1755     let a = &Operand::new("a", &Int.as_bool());
1756     let Cond = &Operand::new("Cond", &imm.intcc);
1757     let x = &Operand::new("x", Int);
1758     let y = &Operand::new("y", Int);
1759 
1760     ig.push(
1761         Inst::new(
1762             "icmp",
1763             r#"
1764         Integer comparison.
1765 
1766         The condition code determines if the operands are interpreted as signed
1767         or unsigned integers.
1768 
1769         | Signed | Unsigned | Condition             |
1770         |--------|----------|-----------------------|
1771         | eq     | eq       | Equal                 |
1772         | ne     | ne       | Not equal             |
1773         | slt    | ult      | Less than             |
1774         | sge    | uge      | Greater than or equal |
1775         | sgt    | ugt      | Greater than          |
1776         | sle    | ule      | Less than or equal    |
1777         | of     | *        | Overflow              |
1778         | nof    | *        | No Overflow           |
1779 
1780         \* The unsigned version of overflow condition for add has ISA-specific semantics and thus
1781         has been kept as a method on the TargetIsa trait as
1782         [unsigned_add_overflow_condition][crate::isa::TargetIsa::unsigned_add_overflow_condition].
1783 
1784         When this instruction compares integer vectors, it returns a boolean
1785         vector of lane-wise comparisons.
1786         "#,
1787             &formats.int_compare,
1788         )
1789         .operands_in(vec![Cond, x, y])
1790         .operands_out(vec![a]),
1791     );
1792 
1793     let a = &Operand::new("a", b1);
1794     let x = &Operand::new("x", iB);
1795     let Y = &Operand::new("Y", &imm.imm64);
1796 
1797     ig.push(
1798         Inst::new(
1799             "icmp_imm",
1800             r#"
1801         Compare scalar integer to a constant.
1802 
1803         This is the same as the `icmp` instruction, except one operand is
1804         an immediate constant.
1805 
1806         This instruction can only compare scalars. Use `icmp` for
1807         lane-wise vector comparisons.
1808         "#,
1809             &formats.int_compare_imm,
1810         )
1811         .operands_in(vec![Cond, x, Y])
1812         .operands_out(vec![a]),
1813     );
1814 
1815     let f = &Operand::new("f", iflags);
1816     let x = &Operand::new("x", iB);
1817     let y = &Operand::new("y", iB);
1818 
1819     ig.push(
1820         Inst::new(
1821             "ifcmp",
1822             r#"
1823         Compare scalar integers and return flags.
1824 
1825         Compare two scalar integer values and return integer CPU flags
1826         representing the result.
1827         "#,
1828             &formats.binary,
1829         )
1830         .operands_in(vec![x, y])
1831         .operands_out(vec![f]),
1832     );
1833 
1834     ig.push(
1835         Inst::new(
1836             "ifcmp_imm",
1837             r#"
1838         Compare scalar integer to a constant and return flags.
1839 
1840         Like `icmp_imm`, but returns integer CPU flags instead of testing
1841         a specific condition code.
1842         "#,
1843             &formats.binary_imm64,
1844         )
1845         .operands_in(vec![x, Y])
1846         .operands_out(vec![f]),
1847     );
1848 
1849     let a = &Operand::new("a", Int);
1850     let x = &Operand::new("x", Int);
1851     let y = &Operand::new("y", Int);
1852 
1853     ig.push(
1854         Inst::new(
1855             "iadd",
1856             r#"
1857         Wrapping integer addition: `a := x + y \pmod{2^B}`.
1858 
1859         This instruction does not depend on the signed/unsigned interpretation
1860         of the operands.
1861         "#,
1862             &formats.binary,
1863         )
1864         .operands_in(vec![x, y])
1865         .operands_out(vec![a]),
1866     );
1867 
1868     ig.push(
1869         Inst::new(
1870             "isub",
1871             r#"
1872         Wrapping integer subtraction: `a := x - y \pmod{2^B}`.
1873 
1874         This instruction does not depend on the signed/unsigned interpretation
1875         of the operands.
1876         "#,
1877             &formats.binary,
1878         )
1879         .operands_in(vec![x, y])
1880         .operands_out(vec![a]),
1881     );
1882 
1883     ig.push(
1884         Inst::new(
1885             "ineg",
1886             r#"
1887         Integer negation: `a := -x \pmod{2^B}`.
1888         "#,
1889             &formats.unary,
1890         )
1891         .operands_in(vec![x])
1892         .operands_out(vec![a]),
1893     );
1894 
1895     ig.push(
1896         Inst::new(
1897             "iabs",
1898             r#"
1899         Integer absolute value with wrapping: `a := |x|`.
1900         "#,
1901             &formats.unary,
1902         )
1903         .operands_in(vec![x])
1904         .operands_out(vec![a]),
1905     );
1906 
1907     ig.push(
1908         Inst::new(
1909             "imul",
1910             r#"
1911         Wrapping integer multiplication: `a := x y \pmod{2^B}`.
1912 
1913         This instruction does not depend on the signed/unsigned interpretation
1914         of the operands.
1915 
1916         Polymorphic over all integer types (vector and scalar).
1917         "#,
1918             &formats.binary,
1919         )
1920         .operands_in(vec![x, y])
1921         .operands_out(vec![a]),
1922     );
1923 
1924     ig.push(
1925         Inst::new(
1926             "umulhi",
1927             r#"
1928         Unsigned integer multiplication, producing the high half of a
1929         double-length result.
1930 
1931         Polymorphic over all integer types (vector and scalar).
1932         "#,
1933             &formats.binary,
1934         )
1935         .operands_in(vec![x, y])
1936         .operands_out(vec![a]),
1937     );
1938 
1939     ig.push(
1940         Inst::new(
1941             "smulhi",
1942             r#"
1943         Signed integer multiplication, producing the high half of a
1944         double-length result.
1945 
1946         Polymorphic over all integer types (vector and scalar).
1947         "#,
1948             &formats.binary,
1949         )
1950         .operands_in(vec![x, y])
1951         .operands_out(vec![a]),
1952     );
1953 
1954     let I16or32 = &TypeVar::new(
1955         "I16or32",
1956         "A scalar or vector integer type with 16- or 32-bit numbers",
1957         TypeSetBuilder::new().ints(16..32).simd_lanes(4..8).build(),
1958     );
1959 
1960     let qx = &Operand::new("x", I16or32);
1961     let qy = &Operand::new("y", I16or32);
1962     let qa = &Operand::new("a", I16or32);
1963 
1964     ig.push(
1965         Inst::new(
1966             "sqmul_round_sat",
1967             r#"
1968         Fixed-point multiplication of numbers in the QN format, where N + 1
1969         is the number bitwidth:
1970         `a := signed_saturate((x * y + 1 << (Q - 1)) >> Q)`
1971 
1972         Polymorphic over all integer types (scalar and vector) with 16- or
1973         32-bit numbers.
1974         "#,
1975             &formats.binary,
1976         )
1977         .operands_in(vec![qx, qy])
1978         .operands_out(vec![qa]),
1979     );
1980 
1981     {
1982         // Integer division and remainder are scalar-only; most
1983         // hardware does not directly support vector integer division.
1984 
1985         let x = &Operand::new("x", iB);
1986         let y = &Operand::new("y", iB);
1987         let a = &Operand::new("a", iB);
1988 
1989         ig.push(
1990             Inst::new(
1991                 "udiv",
1992                 r#"
1993             Unsigned integer division: `a := \lfloor {x \over y} \rfloor`.
1994 
1995             This operation traps if the divisor is zero.
1996             "#,
1997                 &formats.binary,
1998             )
1999             .operands_in(vec![x, y])
2000             .operands_out(vec![a])
2001             .can_trap(true),
2002         );
2003 
2004         ig.push(
2005             Inst::new(
2006                 "sdiv",
2007                 r#"
2008             Signed integer division rounded toward zero: `a := sign(xy)
2009             \lfloor {|x| \over |y|}\rfloor`.
2010 
2011             This operation traps if the divisor is zero, or if the result is not
2012             representable in `B` bits two's complement. This only happens
2013             when `x = -2^{B-1}, y = -1`.
2014             "#,
2015                 &formats.binary,
2016             )
2017             .operands_in(vec![x, y])
2018             .operands_out(vec![a])
2019             .can_trap(true),
2020         );
2021 
2022         ig.push(
2023             Inst::new(
2024                 "urem",
2025                 r#"
2026             Unsigned integer remainder.
2027 
2028             This operation traps if the divisor is zero.
2029             "#,
2030                 &formats.binary,
2031             )
2032             .operands_in(vec![x, y])
2033             .operands_out(vec![a])
2034             .can_trap(true),
2035         );
2036 
2037         ig.push(
2038             Inst::new(
2039                 "srem",
2040                 r#"
2041             Signed integer remainder. The result has the sign of the dividend.
2042 
2043             This operation traps if the divisor is zero.
2044             "#,
2045                 &formats.binary,
2046             )
2047             .operands_in(vec![x, y])
2048             .operands_out(vec![a])
2049             .can_trap(true),
2050         );
2051     }
2052 
2053     let a = &Operand::new("a", iB);
2054     let x = &Operand::new("x", iB);
2055     let Y = &Operand::new("Y", &imm.imm64);
2056 
2057     ig.push(
2058         Inst::new(
2059             "iadd_imm",
2060             r#"
2061         Add immediate integer.
2062 
2063         Same as `iadd`, but one operand is an immediate constant.
2064 
2065         Polymorphic over all scalar integer types, but does not support vector
2066         types.
2067         "#,
2068             &formats.binary_imm64,
2069         )
2070         .operands_in(vec![x, Y])
2071         .operands_out(vec![a]),
2072     );
2073 
2074     ig.push(
2075         Inst::new(
2076             "imul_imm",
2077             r#"
2078         Integer multiplication by immediate constant.
2079 
2080         Polymorphic over all scalar integer types, but does not support vector
2081         types.
2082         "#,
2083             &formats.binary_imm64,
2084         )
2085         .operands_in(vec![x, Y])
2086         .operands_out(vec![a]),
2087     );
2088 
2089     ig.push(
2090         Inst::new(
2091             "udiv_imm",
2092             r#"
2093         Unsigned integer division by an immediate constant.
2094 
2095         This operation traps if the divisor is zero.
2096         "#,
2097             &formats.binary_imm64,
2098         )
2099         .operands_in(vec![x, Y])
2100         .operands_out(vec![a]),
2101     );
2102 
2103     ig.push(
2104         Inst::new(
2105             "sdiv_imm",
2106             r#"
2107         Signed integer division by an immediate constant.
2108 
2109         This operation traps if the divisor is zero, or if the result is not
2110         representable in `B` bits two's complement. This only happens
2111         when `x = -2^{B-1}, Y = -1`.
2112         "#,
2113             &formats.binary_imm64,
2114         )
2115         .operands_in(vec![x, Y])
2116         .operands_out(vec![a]),
2117     );
2118 
2119     ig.push(
2120         Inst::new(
2121             "urem_imm",
2122             r#"
2123         Unsigned integer remainder with immediate divisor.
2124 
2125         This operation traps if the divisor is zero.
2126         "#,
2127             &formats.binary_imm64,
2128         )
2129         .operands_in(vec![x, Y])
2130         .operands_out(vec![a]),
2131     );
2132 
2133     ig.push(
2134         Inst::new(
2135             "srem_imm",
2136             r#"
2137         Signed integer remainder with immediate divisor.
2138 
2139         This operation traps if the divisor is zero.
2140         "#,
2141             &formats.binary_imm64,
2142         )
2143         .operands_in(vec![x, Y])
2144         .operands_out(vec![a]),
2145     );
2146 
2147     ig.push(
2148         Inst::new(
2149             "irsub_imm",
2150             r#"
2151         Immediate reverse wrapping subtraction: `a := Y - x \pmod{2^B}`.
2152 
2153         Also works as integer negation when `Y = 0`. Use `iadd_imm`
2154         with a negative immediate operand for the reverse immediate
2155         subtraction.
2156 
2157         Polymorphic over all scalar integer types, but does not support vector
2158         types.
2159         "#,
2160             &formats.binary_imm64,
2161         )
2162         .operands_in(vec![x, Y])
2163         .operands_out(vec![a]),
2164     );
2165 
2166     let a = &Operand::new("a", iB);
2167     let x = &Operand::new("x", iB);
2168     let y = &Operand::new("y", iB);
2169 
2170     let c_in = &Operand::new("c_in", b1).with_doc("Input carry flag");
2171     let c_out = &Operand::new("c_out", b1).with_doc("Output carry flag");
2172     let b_in = &Operand::new("b_in", b1).with_doc("Input borrow flag");
2173     let b_out = &Operand::new("b_out", b1).with_doc("Output borrow flag");
2174 
2175     let c_if_in = &Operand::new("c_in", iflags);
2176     let c_if_out = &Operand::new("c_out", iflags);
2177     let b_if_in = &Operand::new("b_in", iflags);
2178     let b_if_out = &Operand::new("b_out", iflags);
2179 
2180     ig.push(
2181         Inst::new(
2182             "iadd_cin",
2183             r#"
2184         Add integers with carry in.
2185 
2186         Same as `iadd` with an additional carry input. Computes:
2187 
2188         ```text
2189             a = x + y + c_{in} \pmod 2^B
2190         ```
2191 
2192         Polymorphic over all scalar integer types, but does not support vector
2193         types.
2194         "#,
2195             &formats.ternary,
2196         )
2197         .operands_in(vec![x, y, c_in])
2198         .operands_out(vec![a]),
2199     );
2200 
2201     ig.push(
2202         Inst::new(
2203             "iadd_ifcin",
2204             r#"
2205         Add integers with carry in.
2206 
2207         Same as `iadd` with an additional carry flag input. Computes:
2208 
2209         ```text
2210             a = x + y + c_{in} \pmod 2^B
2211         ```
2212 
2213         Polymorphic over all scalar integer types, but does not support vector
2214         types.
2215         "#,
2216             &formats.ternary,
2217         )
2218         .operands_in(vec![x, y, c_if_in])
2219         .operands_out(vec![a]),
2220     );
2221 
2222     ig.push(
2223         Inst::new(
2224             "iadd_cout",
2225             r#"
2226         Add integers with carry out.
2227 
2228         Same as `iadd` with an additional carry output.
2229 
2230         ```text
2231             a &= x + y \pmod 2^B \\
2232             c_{out} &= x+y >= 2^B
2233         ```
2234 
2235         Polymorphic over all scalar integer types, but does not support vector
2236         types.
2237         "#,
2238             &formats.binary,
2239         )
2240         .operands_in(vec![x, y])
2241         .operands_out(vec![a, c_out]),
2242     );
2243 
2244     ig.push(
2245         Inst::new(
2246             "iadd_ifcout",
2247             r#"
2248         Add integers with carry out.
2249 
2250         Same as `iadd` with an additional carry flag output.
2251 
2252         ```text
2253             a &= x + y \pmod 2^B \\
2254             c_{out} &= x+y >= 2^B
2255         ```
2256 
2257         Polymorphic over all scalar integer types, but does not support vector
2258         types.
2259         "#,
2260             &formats.binary,
2261         )
2262         .operands_in(vec![x, y])
2263         .operands_out(vec![a, c_if_out]),
2264     );
2265 
2266     ig.push(
2267         Inst::new(
2268             "iadd_carry",
2269             r#"
2270         Add integers with carry in and out.
2271 
2272         Same as `iadd` with an additional carry input and output.
2273 
2274         ```text
2275             a &= x + y + c_{in} \pmod 2^B \\
2276             c_{out} &= x + y + c_{in} >= 2^B
2277         ```
2278 
2279         Polymorphic over all scalar integer types, but does not support vector
2280         types.
2281         "#,
2282             &formats.ternary,
2283         )
2284         .operands_in(vec![x, y, c_in])
2285         .operands_out(vec![a, c_out]),
2286     );
2287 
2288     ig.push(
2289         Inst::new(
2290             "iadd_ifcarry",
2291             r#"
2292         Add integers with carry in and out.
2293 
2294         Same as `iadd` with an additional carry flag input and output.
2295 
2296         ```text
2297             a &= x + y + c_{in} \pmod 2^B \\
2298             c_{out} &= x + y + c_{in} >= 2^B
2299         ```
2300 
2301         Polymorphic over all scalar integer types, but does not support vector
2302         types.
2303         "#,
2304             &formats.ternary,
2305         )
2306         .operands_in(vec![x, y, c_if_in])
2307         .operands_out(vec![a, c_if_out]),
2308     );
2309 
2310     ig.push(
2311         Inst::new(
2312             "isub_bin",
2313             r#"
2314         Subtract integers with borrow in.
2315 
2316         Same as `isub` with an additional borrow flag input. Computes:
2317 
2318         ```text
2319             a = x - (y + b_{in}) \pmod 2^B
2320         ```
2321 
2322         Polymorphic over all scalar integer types, but does not support vector
2323         types.
2324         "#,
2325             &formats.ternary,
2326         )
2327         .operands_in(vec![x, y, b_in])
2328         .operands_out(vec![a]),
2329     );
2330 
2331     ig.push(
2332         Inst::new(
2333             "isub_ifbin",
2334             r#"
2335         Subtract integers with borrow in.
2336 
2337         Same as `isub` with an additional borrow flag input. Computes:
2338 
2339         ```text
2340             a = x - (y + b_{in}) \pmod 2^B
2341         ```
2342 
2343         Polymorphic over all scalar integer types, but does not support vector
2344         types.
2345         "#,
2346             &formats.ternary,
2347         )
2348         .operands_in(vec![x, y, b_if_in])
2349         .operands_out(vec![a]),
2350     );
2351 
2352     ig.push(
2353         Inst::new(
2354             "isub_bout",
2355             r#"
2356         Subtract integers with borrow out.
2357 
2358         Same as `isub` with an additional borrow flag output.
2359 
2360         ```text
2361             a &= x - y \pmod 2^B \\
2362             b_{out} &= x < y
2363         ```
2364 
2365         Polymorphic over all scalar integer types, but does not support vector
2366         types.
2367         "#,
2368             &formats.binary,
2369         )
2370         .operands_in(vec![x, y])
2371         .operands_out(vec![a, b_out]),
2372     );
2373 
2374     ig.push(
2375         Inst::new(
2376             "isub_ifbout",
2377             r#"
2378         Subtract integers with borrow out.
2379 
2380         Same as `isub` with an additional borrow flag output.
2381 
2382         ```text
2383             a &= x - y \pmod 2^B \\
2384             b_{out} &= x < y
2385         ```
2386 
2387         Polymorphic over all scalar integer types, but does not support vector
2388         types.
2389         "#,
2390             &formats.binary,
2391         )
2392         .operands_in(vec![x, y])
2393         .operands_out(vec![a, b_if_out]),
2394     );
2395 
2396     ig.push(
2397         Inst::new(
2398             "isub_borrow",
2399             r#"
2400         Subtract integers with borrow in and out.
2401 
2402         Same as `isub` with an additional borrow flag input and output.
2403 
2404         ```text
2405             a &= x - (y + b_{in}) \pmod 2^B \\
2406             b_{out} &= x < y + b_{in}
2407         ```
2408 
2409         Polymorphic over all scalar integer types, but does not support vector
2410         types.
2411         "#,
2412             &formats.ternary,
2413         )
2414         .operands_in(vec![x, y, b_in])
2415         .operands_out(vec![a, b_out]),
2416     );
2417 
2418     ig.push(
2419         Inst::new(
2420             "isub_ifborrow",
2421             r#"
2422         Subtract integers with borrow in and out.
2423 
2424         Same as `isub` with an additional borrow flag input and output.
2425 
2426         ```text
2427             a &= x - (y + b_{in}) \pmod 2^B \\
2428             b_{out} &= x < y + b_{in}
2429         ```
2430 
2431         Polymorphic over all scalar integer types, but does not support vector
2432         types.
2433         "#,
2434             &formats.ternary,
2435         )
2436         .operands_in(vec![x, y, b_if_in])
2437         .operands_out(vec![a, b_if_out]),
2438     );
2439 
2440     let bits = &TypeVar::new(
2441         "bits",
2442         "Any integer, float, or boolean scalar or vector type",
2443         TypeSetBuilder::new()
2444             .ints(Interval::All)
2445             .floats(Interval::All)
2446             .bools(Interval::All)
2447             .simd_lanes(Interval::All)
2448             .includes_scalars(true)
2449             .build(),
2450     );
2451     let x = &Operand::new("x", bits);
2452     let y = &Operand::new("y", bits);
2453     let a = &Operand::new("a", bits);
2454 
2455     ig.push(
2456         Inst::new(
2457             "band",
2458             r#"
2459         Bitwise and.
2460         "#,
2461             &formats.binary,
2462         )
2463         .operands_in(vec![x, y])
2464         .operands_out(vec![a]),
2465     );
2466 
2467     ig.push(
2468         Inst::new(
2469             "bor",
2470             r#"
2471         Bitwise or.
2472         "#,
2473             &formats.binary,
2474         )
2475         .operands_in(vec![x, y])
2476         .operands_out(vec![a]),
2477     );
2478 
2479     ig.push(
2480         Inst::new(
2481             "bxor",
2482             r#"
2483         Bitwise xor.
2484         "#,
2485             &formats.binary,
2486         )
2487         .operands_in(vec![x, y])
2488         .operands_out(vec![a]),
2489     );
2490 
2491     ig.push(
2492         Inst::new(
2493             "bnot",
2494             r#"
2495         Bitwise not.
2496         "#,
2497             &formats.unary,
2498         )
2499         .operands_in(vec![x])
2500         .operands_out(vec![a]),
2501     );
2502 
2503     ig.push(
2504         Inst::new(
2505             "band_not",
2506             r#"
2507         Bitwise and not.
2508 
2509         Computes `x & ~y`.
2510         "#,
2511             &formats.binary,
2512         )
2513         .operands_in(vec![x, y])
2514         .operands_out(vec![a]),
2515     );
2516 
2517     ig.push(
2518         Inst::new(
2519             "bor_not",
2520             r#"
2521         Bitwise or not.
2522 
2523         Computes `x | ~y`.
2524         "#,
2525             &formats.binary,
2526         )
2527         .operands_in(vec![x, y])
2528         .operands_out(vec![a]),
2529     );
2530 
2531     ig.push(
2532         Inst::new(
2533             "bxor_not",
2534             r#"
2535         Bitwise xor not.
2536 
2537         Computes `x ^ ~y`.
2538         "#,
2539             &formats.binary,
2540         )
2541         .operands_in(vec![x, y])
2542         .operands_out(vec![a]),
2543     );
2544 
2545     let x = &Operand::new("x", iB);
2546     let Y = &Operand::new("Y", &imm.imm64);
2547     let a = &Operand::new("a", iB);
2548 
2549     ig.push(
2550         Inst::new(
2551             "band_imm",
2552             r#"
2553         Bitwise and with immediate.
2554 
2555         Same as `band`, but one operand is an immediate constant.
2556 
2557         Polymorphic over all scalar integer types, but does not support vector
2558         types.
2559         "#,
2560             &formats.binary_imm64,
2561         )
2562         .operands_in(vec![x, Y])
2563         .operands_out(vec![a]),
2564     );
2565 
2566     ig.push(
2567         Inst::new(
2568             "bor_imm",
2569             r#"
2570         Bitwise or with immediate.
2571 
2572         Same as `bor`, but one operand is an immediate constant.
2573 
2574         Polymorphic over all scalar integer types, but does not support vector
2575         types.
2576         "#,
2577             &formats.binary_imm64,
2578         )
2579         .operands_in(vec![x, Y])
2580         .operands_out(vec![a]),
2581     );
2582 
2583     ig.push(
2584         Inst::new(
2585             "bxor_imm",
2586             r#"
2587         Bitwise xor with immediate.
2588 
2589         Same as `bxor`, but one operand is an immediate constant.
2590 
2591         Polymorphic over all scalar integer types, but does not support vector
2592         types.
2593         "#,
2594             &formats.binary_imm64,
2595         )
2596         .operands_in(vec![x, Y])
2597         .operands_out(vec![a]),
2598     );
2599 
2600     let x = &Operand::new("x", Int).with_doc("Scalar or vector value to shift");
2601     let y = &Operand::new("y", iB).with_doc("Number of bits to shift");
2602     let Y = &Operand::new("Y", &imm.imm64);
2603     let a = &Operand::new("a", Int);
2604 
2605     ig.push(
2606         Inst::new(
2607             "rotl",
2608             r#"
2609         Rotate left.
2610 
2611         Rotate the bits in ``x`` by ``y`` places.
2612         "#,
2613             &formats.binary,
2614         )
2615         .operands_in(vec![x, y])
2616         .operands_out(vec![a]),
2617     );
2618 
2619     ig.push(
2620         Inst::new(
2621             "rotr",
2622             r#"
2623         Rotate right.
2624 
2625         Rotate the bits in ``x`` by ``y`` places.
2626         "#,
2627             &formats.binary,
2628         )
2629         .operands_in(vec![x, y])
2630         .operands_out(vec![a]),
2631     );
2632 
2633     ig.push(
2634         Inst::new(
2635             "rotl_imm",
2636             r#"
2637         Rotate left by immediate.
2638         "#,
2639             &formats.binary_imm64,
2640         )
2641         .operands_in(vec![x, Y])
2642         .operands_out(vec![a]),
2643     );
2644 
2645     ig.push(
2646         Inst::new(
2647             "rotr_imm",
2648             r#"
2649         Rotate right by immediate.
2650         "#,
2651             &formats.binary_imm64,
2652         )
2653         .operands_in(vec![x, Y])
2654         .operands_out(vec![a]),
2655     );
2656 
2657     ig.push(
2658         Inst::new(
2659             "ishl",
2660             r#"
2661         Integer shift left. Shift the bits in ``x`` towards the MSB by ``y``
2662         places. Shift in zero bits to the LSB.
2663 
2664         The shift amount is masked to the size of ``x``.
2665 
2666         When shifting a B-bits integer type, this instruction computes:
2667 
2668         ```text
2669             s &:= y \pmod B,
2670             a &:= x \cdot 2^s \pmod{2^B}.
2671         ```
2672         "#,
2673             &formats.binary,
2674         )
2675         .operands_in(vec![x, y])
2676         .operands_out(vec![a]),
2677     );
2678 
2679     ig.push(
2680         Inst::new(
2681             "ushr",
2682             r#"
2683         Unsigned shift right. Shift bits in ``x`` towards the LSB by ``y``
2684         places, shifting in zero bits to the MSB. Also called a *logical
2685         shift*.
2686 
2687         The shift amount is masked to the size of the register.
2688 
2689         When shifting a B-bits integer type, this instruction computes:
2690 
2691         ```text
2692             s &:= y \pmod B,
2693             a &:= \lfloor x \cdot 2^{-s} \rfloor.
2694         ```
2695         "#,
2696             &formats.binary,
2697         )
2698         .operands_in(vec![x, y])
2699         .operands_out(vec![a]),
2700     );
2701 
2702     ig.push(
2703         Inst::new(
2704             "sshr",
2705             r#"
2706         Signed shift right. Shift bits in ``x`` towards the LSB by ``y``
2707         places, shifting in sign bits to the MSB. Also called an *arithmetic
2708         shift*.
2709 
2710         The shift amount is masked to the size of the register.
2711         "#,
2712             &formats.binary,
2713         )
2714         .operands_in(vec![x, y])
2715         .operands_out(vec![a]),
2716     );
2717 
2718     ig.push(
2719         Inst::new(
2720             "ishl_imm",
2721             r#"
2722         Integer shift left by immediate.
2723 
2724         The shift amount is masked to the size of ``x``.
2725         "#,
2726             &formats.binary_imm64,
2727         )
2728         .operands_in(vec![x, Y])
2729         .operands_out(vec![a]),
2730     );
2731 
2732     ig.push(
2733         Inst::new(
2734             "ushr_imm",
2735             r#"
2736         Unsigned shift right by immediate.
2737 
2738         The shift amount is masked to the size of the register.
2739         "#,
2740             &formats.binary_imm64,
2741         )
2742         .operands_in(vec![x, Y])
2743         .operands_out(vec![a]),
2744     );
2745 
2746     ig.push(
2747         Inst::new(
2748             "sshr_imm",
2749             r#"
2750         Signed shift right by immediate.
2751 
2752         The shift amount is masked to the size of the register.
2753         "#,
2754             &formats.binary_imm64,
2755         )
2756         .operands_in(vec![x, Y])
2757         .operands_out(vec![a]),
2758     );
2759 
2760     let x = &Operand::new("x", iB);
2761     let a = &Operand::new("a", iB);
2762 
2763     ig.push(
2764         Inst::new(
2765             "bitrev",
2766             r#"
2767         Reverse the bits of a integer.
2768 
2769         Reverses the bits in ``x``.
2770         "#,
2771             &formats.unary,
2772         )
2773         .operands_in(vec![x])
2774         .operands_out(vec![a]),
2775     );
2776 
2777     ig.push(
2778         Inst::new(
2779             "clz",
2780             r#"
2781         Count leading zero bits.
2782 
2783         Starting from the MSB in ``x``, count the number of zero bits before
2784         reaching the first one bit. When ``x`` is zero, returns the size of x
2785         in bits.
2786         "#,
2787             &formats.unary,
2788         )
2789         .operands_in(vec![x])
2790         .operands_out(vec![a]),
2791     );
2792 
2793     ig.push(
2794         Inst::new(
2795             "cls",
2796             r#"
2797         Count leading sign bits.
2798 
2799         Starting from the MSB after the sign bit in ``x``, count the number of
2800         consecutive bits identical to the sign bit. When ``x`` is 0 or -1,
2801         returns one less than the size of x in bits.
2802         "#,
2803             &formats.unary,
2804         )
2805         .operands_in(vec![x])
2806         .operands_out(vec![a]),
2807     );
2808 
2809     ig.push(
2810         Inst::new(
2811             "ctz",
2812             r#"
2813         Count trailing zeros.
2814 
2815         Starting from the LSB in ``x``, count the number of zero bits before
2816         reaching the first one bit. When ``x`` is zero, returns the size of x
2817         in bits.
2818         "#,
2819             &formats.unary,
2820         )
2821         .operands_in(vec![x])
2822         .operands_out(vec![a]),
2823     );
2824 
2825     let x = &Operand::new("x", Int);
2826     let a = &Operand::new("a", Int);
2827 
2828     ig.push(
2829         Inst::new(
2830             "popcnt",
2831             r#"
2832         Population count
2833 
2834         Count the number of one bits in ``x``.
2835         "#,
2836             &formats.unary,
2837         )
2838         .operands_in(vec![x])
2839         .operands_out(vec![a]),
2840     );
2841 
2842     let Float = &TypeVar::new(
2843         "Float",
2844         "A scalar or vector floating point number",
2845         TypeSetBuilder::new()
2846             .floats(Interval::All)
2847             .simd_lanes(Interval::All)
2848             .dynamic_simd_lanes(Interval::All)
2849             .build(),
2850     );
2851     let Cond = &Operand::new("Cond", &imm.floatcc);
2852     let x = &Operand::new("x", Float);
2853     let y = &Operand::new("y", Float);
2854     let a = &Operand::new("a", &Float.as_bool());
2855 
2856     ig.push(
2857         Inst::new(
2858             "fcmp",
2859             r#"
2860         Floating point comparison.
2861 
2862         Two IEEE 754-2008 floating point numbers, `x` and `y`, relate to each
2863         other in exactly one of four ways:
2864 
2865         ```text
2866         == ==========================================
2867         UN Unordered when one or both numbers is NaN.
2868         EQ When `x = y`. (And `0.0 = -0.0`).
2869         LT When `x < y`.
2870         GT When `x > y`.
2871         == ==========================================
2872         ```
2873 
2874         The 14 `floatcc` condition codes each correspond to a subset of
2875         the four relations, except for the empty set which would always be
2876         false, and the full set which would always be true.
2877 
2878         The condition codes are divided into 7 'ordered' conditions which don't
2879         include UN, and 7 unordered conditions which all include UN.
2880 
2881         ```text
2882         +-------+------------+---------+------------+-------------------------+
2883         |Ordered             |Unordered             |Condition                |
2884         +=======+============+=========+============+=========================+
2885         |ord    |EQ | LT | GT|uno      |UN          |NaNs absent / present.   |
2886         +-------+------------+---------+------------+-------------------------+
2887         |eq     |EQ          |ueq      |UN | EQ     |Equal                    |
2888         +-------+------------+---------+------------+-------------------------+
2889         |one    |LT | GT     |ne       |UN | LT | GT|Not equal                |
2890         +-------+------------+---------+------------+-------------------------+
2891         |lt     |LT          |ult      |UN | LT     |Less than                |
2892         +-------+------------+---------+------------+-------------------------+
2893         |le     |LT | EQ     |ule      |UN | LT | EQ|Less than or equal       |
2894         +-------+------------+---------+------------+-------------------------+
2895         |gt     |GT          |ugt      |UN | GT     |Greater than             |
2896         +-------+------------+---------+------------+-------------------------+
2897         |ge     |GT | EQ     |uge      |UN | GT | EQ|Greater than or equal    |
2898         +-------+------------+---------+------------+-------------------------+
2899         ```
2900 
2901         The standard C comparison operators, `<, <=, >, >=`, are all ordered,
2902         so they are false if either operand is NaN. The C equality operator,
2903         `==`, is ordered, and since inequality is defined as the logical
2904         inverse it is *unordered*. They map to the `floatcc` condition
2905         codes as follows:
2906 
2907         ```text
2908         ==== ====== ============
2909         C    `Cond` Subset
2910         ==== ====== ============
2911         `==` eq     EQ
2912         `!=` ne     UN | LT | GT
2913         `<`  lt     LT
2914         `<=` le     LT | EQ
2915         `>`  gt     GT
2916         `>=` ge     GT | EQ
2917         ==== ====== ============
2918         ```
2919 
2920         This subset of condition codes also corresponds to the WebAssembly
2921         floating point comparisons of the same name.
2922 
2923         When this instruction compares floating point vectors, it returns a
2924         boolean vector with the results of lane-wise comparisons.
2925         "#,
2926             &formats.float_compare,
2927         )
2928         .operands_in(vec![Cond, x, y])
2929         .operands_out(vec![a]),
2930     );
2931 
2932     let f = &Operand::new("f", fflags);
2933 
2934     ig.push(
2935         Inst::new(
2936             "ffcmp",
2937             r#"
2938         Floating point comparison returning flags.
2939 
2940         Compares two numbers like `fcmp`, but returns floating point CPU
2941         flags instead of testing a specific condition.
2942         "#,
2943             &formats.binary,
2944         )
2945         .operands_in(vec![x, y])
2946         .operands_out(vec![f]),
2947     );
2948 
2949     let x = &Operand::new("x", Float);
2950     let y = &Operand::new("y", Float);
2951     let z = &Operand::new("z", Float);
2952     let a = &Operand::new("a", Float).with_doc("Result of applying operator to each lane");
2953 
2954     ig.push(
2955         Inst::new(
2956             "fadd",
2957             r#"
2958         Floating point addition.
2959         "#,
2960             &formats.binary,
2961         )
2962         .operands_in(vec![x, y])
2963         .operands_out(vec![a]),
2964     );
2965 
2966     ig.push(
2967         Inst::new(
2968             "fsub",
2969             r#"
2970         Floating point subtraction.
2971         "#,
2972             &formats.binary,
2973         )
2974         .operands_in(vec![x, y])
2975         .operands_out(vec![a]),
2976     );
2977 
2978     ig.push(
2979         Inst::new(
2980             "fmul",
2981             r#"
2982         Floating point multiplication.
2983         "#,
2984             &formats.binary,
2985         )
2986         .operands_in(vec![x, y])
2987         .operands_out(vec![a]),
2988     );
2989 
2990     ig.push(
2991         Inst::new(
2992             "fdiv",
2993             r#"
2994         Floating point division.
2995 
2996         Unlike the integer division instructions ` and
2997         `udiv`, this can't trap. Division by zero is infinity or
2998         NaN, depending on the dividend.
2999         "#,
3000             &formats.binary,
3001         )
3002         .operands_in(vec![x, y])
3003         .operands_out(vec![a]),
3004     );
3005 
3006     ig.push(
3007         Inst::new(
3008             "sqrt",
3009             r#"
3010         Floating point square root.
3011         "#,
3012             &formats.unary,
3013         )
3014         .operands_in(vec![x])
3015         .operands_out(vec![a]),
3016     );
3017 
3018     ig.push(
3019         Inst::new(
3020             "fma",
3021             r#"
3022         Floating point fused multiply-and-add.
3023 
3024         Computes `a := xy+z` without any intermediate rounding of the
3025         product.
3026         "#,
3027             &formats.ternary,
3028         )
3029         .operands_in(vec![x, y, z])
3030         .operands_out(vec![a]),
3031     );
3032 
3033     let a = &Operand::new("a", Float).with_doc("``x`` with its sign bit inverted");
3034 
3035     ig.push(
3036         Inst::new(
3037             "fneg",
3038             r#"
3039         Floating point negation.
3040 
3041         Note that this is a pure bitwise operation.
3042         "#,
3043             &formats.unary,
3044         )
3045         .operands_in(vec![x])
3046         .operands_out(vec![a]),
3047     );
3048 
3049     let a = &Operand::new("a", Float).with_doc("``x`` with its sign bit cleared");
3050 
3051     ig.push(
3052         Inst::new(
3053             "fabs",
3054             r#"
3055         Floating point absolute value.
3056 
3057         Note that this is a pure bitwise operation.
3058         "#,
3059             &formats.unary,
3060         )
3061         .operands_in(vec![x])
3062         .operands_out(vec![a]),
3063     );
3064 
3065     let a = &Operand::new("a", Float).with_doc("``x`` with its sign bit changed to that of ``y``");
3066 
3067     ig.push(
3068         Inst::new(
3069             "fcopysign",
3070             r#"
3071         Floating point copy sign.
3072 
3073         Note that this is a pure bitwise operation. The sign bit from ``y`` is
3074         copied to the sign bit of ``x``.
3075         "#,
3076             &formats.binary,
3077         )
3078         .operands_in(vec![x, y])
3079         .operands_out(vec![a]),
3080     );
3081 
3082     let a = &Operand::new("a", Float).with_doc("The smaller of ``x`` and ``y``");
3083 
3084     ig.push(
3085         Inst::new(
3086             "fmin",
3087             r#"
3088         Floating point minimum, propagating NaNs using the WebAssembly rules.
3089 
3090         If either operand is NaN, this returns NaN with an unspecified sign. Furthermore, if
3091         each input NaN consists of a mantissa whose most significant bit is 1 and the rest is
3092         0, then the output has the same form. Otherwise, the output mantissa's most significant
3093         bit is 1 and the rest is unspecified.
3094         "#,
3095             &formats.binary,
3096         )
3097         .operands_in(vec![x, y])
3098         .operands_out(vec![a]),
3099     );
3100 
3101     ig.push(
3102         Inst::new(
3103             "fmin_pseudo",
3104             r#"
3105         Floating point pseudo-minimum, propagating NaNs.  This behaves differently from ``fmin``.
3106         See <https://github.com/WebAssembly/simd/pull/122> for background.
3107 
3108         The behaviour is defined as ``fmin_pseudo(a, b) = (b < a) ? b : a``, and the behaviour
3109         for zero or NaN inputs follows from the behaviour of ``<`` with such inputs.
3110         "#,
3111             &formats.binary,
3112         )
3113         .operands_in(vec![x, y])
3114         .operands_out(vec![a]),
3115     );
3116 
3117     let a = &Operand::new("a", Float).with_doc("The larger of ``x`` and ``y``");
3118 
3119     ig.push(
3120         Inst::new(
3121             "fmax",
3122             r#"
3123         Floating point maximum, propagating NaNs using the WebAssembly rules.
3124 
3125         If either operand is NaN, this returns NaN with an unspecified sign. Furthermore, if
3126         each input NaN consists of a mantissa whose most significant bit is 1 and the rest is
3127         0, then the output has the same form. Otherwise, the output mantissa's most significant
3128         bit is 1 and the rest is unspecified.
3129         "#,
3130             &formats.binary,
3131         )
3132         .operands_in(vec![x, y])
3133         .operands_out(vec![a]),
3134     );
3135 
3136     ig.push(
3137         Inst::new(
3138             "fmax_pseudo",
3139             r#"
3140         Floating point pseudo-maximum, propagating NaNs.  This behaves differently from ``fmax``.
3141         See <https://github.com/WebAssembly/simd/pull/122> for background.
3142 
3143         The behaviour is defined as ``fmax_pseudo(a, b) = (a < b) ? b : a``, and the behaviour
3144         for zero or NaN inputs follows from the behaviour of ``<`` with such inputs.
3145         "#,
3146             &formats.binary,
3147         )
3148         .operands_in(vec![x, y])
3149         .operands_out(vec![a]),
3150     );
3151 
3152     let a = &Operand::new("a", Float).with_doc("``x`` rounded to integral value");
3153 
3154     ig.push(
3155         Inst::new(
3156             "ceil",
3157             r#"
3158         Round floating point round to integral, towards positive infinity.
3159         "#,
3160             &formats.unary,
3161         )
3162         .operands_in(vec![x])
3163         .operands_out(vec![a]),
3164     );
3165 
3166     ig.push(
3167         Inst::new(
3168             "floor",
3169             r#"
3170         Round floating point round to integral, towards negative infinity.
3171         "#,
3172             &formats.unary,
3173         )
3174         .operands_in(vec![x])
3175         .operands_out(vec![a]),
3176     );
3177 
3178     ig.push(
3179         Inst::new(
3180             "trunc",
3181             r#"
3182         Round floating point round to integral, towards zero.
3183         "#,
3184             &formats.unary,
3185         )
3186         .operands_in(vec![x])
3187         .operands_out(vec![a]),
3188     );
3189 
3190     ig.push(
3191         Inst::new(
3192             "nearest",
3193             r#"
3194         Round floating point round to integral, towards nearest with ties to
3195         even.
3196         "#,
3197             &formats.unary,
3198         )
3199         .operands_in(vec![x])
3200         .operands_out(vec![a]),
3201     );
3202 
3203     let a = &Operand::new("a", b1);
3204     let x = &Operand::new("x", Ref);
3205 
3206     ig.push(
3207         Inst::new(
3208             "is_null",
3209             r#"
3210         Reference verification.
3211 
3212         The condition code determines if the reference type in question is
3213         null or not.
3214         "#,
3215             &formats.unary,
3216         )
3217         .operands_in(vec![x])
3218         .operands_out(vec![a]),
3219     );
3220 
3221     let a = &Operand::new("a", b1);
3222     let x = &Operand::new("x", Ref);
3223 
3224     ig.push(
3225         Inst::new(
3226             "is_invalid",
3227             r#"
3228         Reference verification.
3229 
3230         The condition code determines if the reference type in question is
3231         invalid or not.
3232         "#,
3233             &formats.unary,
3234         )
3235         .operands_in(vec![x])
3236         .operands_out(vec![a]),
3237     );
3238 
3239     let Cond = &Operand::new("Cond", &imm.intcc);
3240     let f = &Operand::new("f", iflags);
3241     let a = &Operand::new("a", b1);
3242 
3243     ig.push(
3244         Inst::new(
3245             "trueif",
3246             r#"
3247         Test integer CPU flags for a specific condition.
3248 
3249         Check the CPU flags in ``f`` against the ``Cond`` condition code and
3250         return true when the condition code is satisfied.
3251         "#,
3252             &formats.int_cond,
3253         )
3254         .operands_in(vec![Cond, f])
3255         .operands_out(vec![a]),
3256     );
3257 
3258     let Cond = &Operand::new("Cond", &imm.floatcc);
3259     let f = &Operand::new("f", fflags);
3260 
3261     ig.push(
3262         Inst::new(
3263             "trueff",
3264             r#"
3265         Test floating point CPU flags for a specific condition.
3266 
3267         Check the CPU flags in ``f`` against the ``Cond`` condition code and
3268         return true when the condition code is satisfied.
3269         "#,
3270             &formats.float_cond,
3271         )
3272         .operands_in(vec![Cond, f])
3273         .operands_out(vec![a]),
3274     );
3275 
3276     let x = &Operand::new("x", Mem);
3277     let a = &Operand::new("a", MemTo).with_doc("Bits of `x` reinterpreted");
3278 
3279     ig.push(
3280         Inst::new(
3281             "bitcast",
3282             r#"
3283         Reinterpret the bits in `x` as a different type.
3284 
3285         The input and output types must be storable to memory and of the same
3286         size. A bitcast is equivalent to storing one type and loading the other
3287         type from the same address.
3288         "#,
3289             &formats.unary,
3290         )
3291         .operands_in(vec![x])
3292         .operands_out(vec![a]),
3293     );
3294 
3295     let x = &Operand::new("x", Any);
3296     let a = &Operand::new("a", AnyTo).with_doc("Bits of `x` reinterpreted");
3297 
3298     ig.push(
3299         Inst::new(
3300             "raw_bitcast",
3301             r#"
3302         Cast the bits in `x` as a different type of the same bit width.
3303 
3304         This instruction does not change the data's representation but allows
3305         data in registers to be used as different types, e.g. an i32x4 as a
3306         b8x16. The only constraint on the result `a` is that it can be
3307         `raw_bitcast` back to the original type. Also, in a raw_bitcast between
3308         vector types with the same number of lanes, the value of each result
3309         lane is a raw_bitcast of the corresponding operand lane. TODO there is
3310         currently no mechanism for enforcing the bit width constraint.
3311         "#,
3312             &formats.unary,
3313         )
3314         .operands_in(vec![x])
3315         .operands_out(vec![a]),
3316     );
3317 
3318     let a = &Operand::new("a", TxN).with_doc("A vector value");
3319     let s = &Operand::new("s", &TxN.lane_of()).with_doc("A scalar value");
3320 
3321     ig.push(
3322         Inst::new(
3323             "scalar_to_vector",
3324             r#"
3325             Copies a scalar value to a vector value.  The scalar is copied into the
3326             least significant lane of the vector, and all other lanes will be zero.
3327             "#,
3328             &formats.unary,
3329         )
3330         .operands_in(vec![s])
3331         .operands_out(vec![a]),
3332     );
3333 
3334     let Bool = &TypeVar::new(
3335         "Bool",
3336         "A scalar boolean type",
3337         TypeSetBuilder::new().bools(Interval::All).build(),
3338     );
3339 
3340     let BoolTo = &TypeVar::new(
3341         "BoolTo",
3342         "A smaller boolean type",
3343         TypeSetBuilder::new().bools(Interval::All).build(),
3344     );
3345 
3346     let x = &Operand::new("x", Bool);
3347     let a = &Operand::new("a", BoolTo);
3348 
3349     ig.push(
3350         Inst::new(
3351             "breduce",
3352             r#"
3353         Convert `x` to a smaller boolean type by discarding the most significant bits.
3354         "#,
3355             &formats.unary,
3356         )
3357         .operands_in(vec![x])
3358         .operands_out(vec![a]),
3359     );
3360 
3361     let BoolTo = &TypeVar::new(
3362         "BoolTo",
3363         "A larger boolean type",
3364         TypeSetBuilder::new().bools(Interval::All).build(),
3365     );
3366     let x = &Operand::new("x", Bool);
3367     let a = &Operand::new("a", BoolTo);
3368 
3369     ig.push(
3370         Inst::new(
3371             "bextend",
3372             r#"
3373         Convert `x` to a larger boolean type
3374         "#,
3375             &formats.unary,
3376         )
3377         .operands_in(vec![x])
3378         .operands_out(vec![a]),
3379     );
3380 
3381     let IntTo = &TypeVar::new(
3382         "IntTo",
3383         "A scalar integer type",
3384         TypeSetBuilder::new().ints(Interval::All).build(),
3385     );
3386     let x = &Operand::new("x", ScalarBool);
3387     let a = &Operand::new("a", IntTo);
3388 
3389     ig.push(
3390         Inst::new(
3391             "bint",
3392             r#"
3393         Convert `x` to an integer.
3394 
3395         True maps to 1 and false maps to 0.
3396         "#,
3397             &formats.unary,
3398         )
3399         .operands_in(vec![x])
3400         .operands_out(vec![a]),
3401     );
3402 
3403     let Bool = &TypeVar::new(
3404         "Bool",
3405         "A scalar or vector boolean type",
3406         TypeSetBuilder::new()
3407             .bools(Interval::All)
3408             .simd_lanes(Interval::All)
3409             .build(),
3410     );
3411     let IntTo = &TypeVar::new(
3412         "IntTo",
3413         "An integer type with the same number of lanes",
3414         TypeSetBuilder::new()
3415             .ints(Interval::All)
3416             .simd_lanes(Interval::All)
3417             .build(),
3418     );
3419     let x = &Operand::new("x", Bool);
3420     let a = &Operand::new("a", IntTo);
3421 
3422     ig.push(
3423         Inst::new(
3424             "bmask",
3425             r#"
3426         Convert `x` to an integer mask.
3427 
3428         True maps to all 1s and false maps to all 0s. The result type must have
3429         the same number of vector lanes as the input.
3430         "#,
3431             &formats.unary,
3432         )
3433         .operands_in(vec![x])
3434         .operands_out(vec![a]),
3435     );
3436 
3437     let Int = &TypeVar::new(
3438         "Int",
3439         "A scalar integer type",
3440         TypeSetBuilder::new().ints(Interval::All).build(),
3441     );
3442 
3443     let IntTo = &TypeVar::new(
3444         "IntTo",
3445         "A smaller integer type",
3446         TypeSetBuilder::new().ints(Interval::All).build(),
3447     );
3448     let x = &Operand::new("x", Int);
3449     let a = &Operand::new("a", IntTo);
3450 
3451     ig.push(
3452         Inst::new(
3453             "ireduce",
3454             r#"
3455         Convert `x` to a smaller integer type by discarding
3456         the most significant bits.
3457 
3458         This is the same as reducing modulo `2^n`.
3459         "#,
3460             &formats.unary,
3461         )
3462         .operands_in(vec![x])
3463         .operands_out(vec![a]),
3464     );
3465 
3466     let I16or32or64xN = &TypeVar::new(
3467         "I16or32or64xN",
3468         "A SIMD vector type containing integer lanes 16, 32, or 64 bits wide",
3469         TypeSetBuilder::new()
3470             .ints(16..64)
3471             .simd_lanes(2..8)
3472             .dynamic_simd_lanes(2..8)
3473             .includes_scalars(false)
3474             .build(),
3475     );
3476 
3477     let x = &Operand::new("x", I16or32or64xN);
3478     let y = &Operand::new("y", I16or32or64xN);
3479     let a = &Operand::new("a", &I16or32or64xN.split_lanes());
3480 
3481     ig.push(
3482         Inst::new(
3483             "snarrow",
3484             r#"
3485         Combine `x` and `y` into a vector with twice the lanes but half the integer width while
3486         saturating overflowing values to the signed maximum and minimum.
3487 
3488         The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4`
3489         and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value
3490         returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`.
3491             "#,
3492             &formats.binary,
3493         )
3494         .operands_in(vec![x, y])
3495         .operands_out(vec![a]),
3496     );
3497 
3498     ig.push(
3499         Inst::new(
3500             "unarrow",
3501             r#"
3502         Combine `x` and `y` into a vector with twice the lanes but half the integer width while
3503         saturating overflowing values to the unsigned maximum and minimum.
3504 
3505         Note that all input lanes are considered signed: any negative lanes will overflow and be
3506         replaced with the unsigned minimum, `0x00`.
3507 
3508         The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4`
3509         and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value
3510         returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`.
3511             "#,
3512             &formats.binary,
3513         )
3514         .operands_in(vec![x, y])
3515         .operands_out(vec![a]),
3516     );
3517 
3518     ig.push(
3519         Inst::new(
3520             "uunarrow",
3521             r#"
3522         Combine `x` and `y` into a vector with twice the lanes but half the integer width while
3523         saturating overflowing values to the unsigned maximum and minimum.
3524 
3525         Note that all input lanes are considered unsigned: any negative values will be interpreted as unsigned, overflowing and being replaced with the unsigned maximum.
3526 
3527         The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4`
3528         and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value
3529         returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`.
3530             "#,
3531             &formats.binary,
3532         )
3533         .operands_in(vec![x, y])
3534         .operands_out(vec![a]),
3535     );
3536 
3537     let I8or16or32xN = &TypeVar::new(
3538         "I8or16or32xN",
3539         "A SIMD vector type containing integer lanes 8, 16, or 32 bits wide.",
3540         TypeSetBuilder::new()
3541             .ints(8..32)
3542             .simd_lanes(2..16)
3543             .dynamic_simd_lanes(2..16)
3544             .includes_scalars(false)
3545             .build(),
3546     );
3547 
3548     let x = &Operand::new("x", I8or16or32xN);
3549     let a = &Operand::new("a", &I8or16or32xN.merge_lanes());
3550 
3551     ig.push(
3552         Inst::new(
3553             "swiden_low",
3554             r#"
3555         Widen the low lanes of `x` using signed extension.
3556 
3557         This will double the lane width and halve the number of lanes.
3558             "#,
3559             &formats.unary,
3560         )
3561         .operands_in(vec![x])
3562         .operands_out(vec![a]),
3563     );
3564 
3565     ig.push(
3566         Inst::new(
3567             "swiden_high",
3568             r#"
3569         Widen the high lanes of `x` using signed extension.
3570 
3571         This will double the lane width and halve the number of lanes.
3572             "#,
3573             &formats.unary,
3574         )
3575         .operands_in(vec![x])
3576         .operands_out(vec![a]),
3577     );
3578 
3579     ig.push(
3580         Inst::new(
3581             "uwiden_low",
3582             r#"
3583         Widen the low lanes of `x` using unsigned extension.
3584 
3585         This will double the lane width and halve the number of lanes.
3586             "#,
3587             &formats.unary,
3588         )
3589         .operands_in(vec![x])
3590         .operands_out(vec![a]),
3591     );
3592 
3593     ig.push(
3594         Inst::new(
3595             "uwiden_high",
3596             r#"
3597             Widen the high lanes of `x` using unsigned extension.
3598 
3599             This will double the lane width and halve the number of lanes.
3600             "#,
3601             &formats.unary,
3602         )
3603         .operands_in(vec![x])
3604         .operands_out(vec![a]),
3605     );
3606 
3607     let x = &Operand::new("x", I8or16or32xN);
3608     let y = &Operand::new("y", I8or16or32xN);
3609     let a = &Operand::new("a", I8or16or32xN);
3610 
3611     ig.push(
3612         Inst::new(
3613             "iadd_pairwise",
3614             r#"
3615         Does lane-wise integer pairwise addition on two operands, putting the
3616         combined results into a single vector result. Here a pair refers to adjacent
3617         lanes in a vector, i.e. i*2 + (i*2+1) for i == num_lanes/2. The first operand
3618         pairwise add results will make up the low half of the resulting vector while
3619         the second operand pairwise add results will make up the upper half of the
3620         resulting vector.
3621             "#,
3622             &formats.binary,
3623         )
3624         .operands_in(vec![x, y])
3625         .operands_out(vec![a]),
3626     );
3627 
3628     let I16x8 = &TypeVar::new(
3629         "I16x8",
3630         "A SIMD vector type containing 8 integer lanes each 16 bits wide.",
3631         TypeSetBuilder::new()
3632             .ints(16..16)
3633             .simd_lanes(8..8)
3634             .includes_scalars(false)
3635             .build(),
3636     );
3637 
3638     let x = &Operand::new("x", I16x8);
3639     let y = &Operand::new("y", I16x8);
3640     let a = &Operand::new("a", &I16x8.merge_lanes());
3641 
3642     ig.push(
3643         Inst::new(
3644             "widening_pairwise_dot_product_s",
3645             r#"
3646         Takes corresponding elements in `x` and `y`, performs a sign-extending length-doubling
3647         multiplication on them, then adds adjacent pairs of elements to form the result.  For
3648         example, if the input vectors are `[x3, x2, x1, x0]` and `[y3, y2, y1, y0]`, it produces
3649         the vector `[r1, r0]`, where `r1 = sx(x3) * sx(y3) + sx(x2) * sx(y2)` and
3650         `r0 = sx(x1) * sx(y1) + sx(x0) * sx(y0)`, and `sx(n)` sign-extends `n` to twice its width.
3651 
3652         This will double the lane width and halve the number of lanes.  So the resulting
3653         vector has the same number of bits as `x` and `y` do (individually).
3654 
3655         See <https://github.com/WebAssembly/simd/pull/127> for background info.
3656             "#,
3657             &formats.binary,
3658         )
3659         .operands_in(vec![x, y])
3660         .operands_out(vec![a]),
3661     );
3662 
3663     let IntTo = &TypeVar::new(
3664         "IntTo",
3665         "A larger integer type with the same number of lanes",
3666         TypeSetBuilder::new()
3667             .ints(Interval::All)
3668             .simd_lanes(Interval::All)
3669             .build(),
3670     );
3671     let x = &Operand::new("x", Int);
3672     let a = &Operand::new("a", IntTo);
3673 
3674     ig.push(
3675         Inst::new(
3676             "uextend",
3677             r#"
3678         Convert `x` to a larger integer type by zero-extending.
3679 
3680         Each lane in `x` is converted to a larger integer type by adding
3681         zeroes. The result has the same numerical value as `x` when both are
3682         interpreted as unsigned integers.
3683 
3684         The result type must have the same number of vector lanes as the input,
3685         and each lane must not have fewer bits that the input lanes. If the
3686         input and output types are the same, this is a no-op.
3687         "#,
3688             &formats.unary,
3689         )
3690         .operands_in(vec![x])
3691         .operands_out(vec![a]),
3692     );
3693 
3694     ig.push(
3695         Inst::new(
3696             "sextend",
3697             r#"
3698         Convert `x` to a larger integer type by sign-extending.
3699 
3700         Each lane in `x` is converted to a larger integer type by replicating
3701         the sign bit. The result has the same numerical value as `x` when both
3702         are interpreted as signed integers.
3703 
3704         The result type must have the same number of vector lanes as the input,
3705         and each lane must not have fewer bits that the input lanes. If the
3706         input and output types are the same, this is a no-op.
3707         "#,
3708             &formats.unary,
3709         )
3710         .operands_in(vec![x])
3711         .operands_out(vec![a]),
3712     );
3713 
3714     let FloatTo = &TypeVar::new(
3715         "FloatTo",
3716         "A scalar or vector floating point number",
3717         TypeSetBuilder::new()
3718             .floats(Interval::All)
3719             .simd_lanes(Interval::All)
3720             .build(),
3721     );
3722     let x = &Operand::new("x", Float);
3723     let a = &Operand::new("a", FloatTo);
3724 
3725     ig.push(
3726         Inst::new(
3727             "fpromote",
3728             r#"
3729         Convert `x` to a larger floating point format.
3730 
3731         Each lane in `x` is converted to the destination floating point format.
3732         This is an exact operation.
3733 
3734         Cranelift currently only supports two floating point formats
3735         - `f32` and `f64`. This may change in the future.
3736 
3737         The result type must have the same number of vector lanes as the input,
3738         and the result lanes must not have fewer bits than the input lanes. If
3739         the input and output types are the same, this is a no-op.
3740         "#,
3741             &formats.unary,
3742         )
3743         .operands_in(vec![x])
3744         .operands_out(vec![a]),
3745     );
3746 
3747     ig.push(
3748         Inst::new(
3749             "fdemote",
3750             r#"
3751         Convert `x` to a smaller floating point format.
3752 
3753         Each lane in `x` is converted to the destination floating point format
3754         by rounding to nearest, ties to even.
3755 
3756         Cranelift currently only supports two floating point formats
3757         - `f32` and `f64`. This may change in the future.
3758 
3759         The result type must have the same number of vector lanes as the input,
3760         and the result lanes must not have more bits than the input lanes. If
3761         the input and output types are the same, this is a no-op.
3762         "#,
3763             &formats.unary,
3764         )
3765         .operands_in(vec![x])
3766         .operands_out(vec![a]),
3767     );
3768 
3769     let F64x2 = &TypeVar::new(
3770         "F64x2",
3771         "A SIMD vector type consisting of 2 lanes of 64-bit floats",
3772         TypeSetBuilder::new()
3773             .floats(64..64)
3774             .simd_lanes(2..2)
3775             .includes_scalars(false)
3776             .build(),
3777     );
3778     let F32x4 = &TypeVar::new(
3779         "F32x4",
3780         "A SIMD vector type consisting of 4 lanes of 32-bit floats",
3781         TypeSetBuilder::new()
3782             .floats(32..32)
3783             .simd_lanes(4..4)
3784             .includes_scalars(false)
3785             .build(),
3786     );
3787 
3788     let x = &Operand::new("x", F64x2);
3789     let a = &Operand::new("a", F32x4);
3790 
3791     ig.push(
3792         Inst::new(
3793             "fvdemote",
3794             r#"
3795                 Convert `x` to a smaller floating point format.
3796 
3797                 Each lane in `x` is converted to the destination floating point format
3798                 by rounding to nearest, ties to even.
3799 
3800                 Cranelift currently only supports two floating point formats
3801                 - `f32` and `f64`. This may change in the future.
3802 
3803                 Fvdemote differs from fdemote in that with fvdemote it targets vectors.
3804                 Fvdemote is constrained to having the input type being F64x2 and the result
3805                 type being F32x4. The result lane that was the upper half of the input lane
3806                 is initialized to zero.
3807                 "#,
3808             &formats.unary,
3809         )
3810         .operands_in(vec![x])
3811         .operands_out(vec![a]),
3812     );
3813 
3814     ig.push(
3815         Inst::new(
3816             "fvpromote_low",
3817             r#"
3818         Converts packed single precision floating point to packed double precision floating point.
3819 
3820         Considering only the lower half of the register, the low lanes in `x` are interpreted as
3821         single precision floats that are then converted to a double precision floats.
3822 
3823         The result type will have half the number of vector lanes as the input. Fvpromote_low is
3824         constrained to input F32x4 with a result type of F64x2.
3825         "#,
3826             &formats.unary,
3827         )
3828         .operands_in(vec![a])
3829         .operands_out(vec![x]),
3830     );
3831 
3832     let x = &Operand::new("x", Float);
3833     let a = &Operand::new("a", IntTo);
3834 
3835     ig.push(
3836         Inst::new(
3837             "fcvt_to_uint",
3838             r#"
3839         Convert floating point to unsigned integer.
3840 
3841         Each lane in `x` is converted to an unsigned integer by rounding
3842         towards zero. If `x` is NaN or if the unsigned integral value cannot be
3843         represented in the result type, this instruction traps.
3844 
3845         The result type must have the same number of vector lanes as the input.
3846         "#,
3847             &formats.unary,
3848         )
3849         .operands_in(vec![x])
3850         .operands_out(vec![a])
3851         .can_trap(true),
3852     );
3853 
3854     ig.push(
3855         Inst::new(
3856             "fcvt_to_uint_sat",
3857             r#"
3858         Convert floating point to unsigned integer as fcvt_to_uint does, but
3859         saturates the input instead of trapping. NaN and negative values are
3860         converted to 0.
3861         "#,
3862             &formats.unary,
3863         )
3864         .operands_in(vec![x])
3865         .operands_out(vec![a]),
3866     );
3867 
3868     ig.push(
3869         Inst::new(
3870             "fcvt_to_sint",
3871             r#"
3872         Convert floating point to signed integer.
3873 
3874         Each lane in `x` is converted to a signed integer by rounding towards
3875         zero. If `x` is NaN or if the signed integral value cannot be
3876         represented in the result type, this instruction traps.
3877 
3878         The result type must have the same number of vector lanes as the input.
3879         "#,
3880             &formats.unary,
3881         )
3882         .operands_in(vec![x])
3883         .operands_out(vec![a])
3884         .can_trap(true),
3885     );
3886 
3887     ig.push(
3888         Inst::new(
3889             "fcvt_to_sint_sat",
3890             r#"
3891         Convert floating point to signed integer as fcvt_to_sint does, but
3892         saturates the input instead of trapping. NaN values are converted to 0.
3893         "#,
3894             &formats.unary,
3895         )
3896         .operands_in(vec![x])
3897         .operands_out(vec![a]),
3898     );
3899 
3900     let Int = &TypeVar::new(
3901         "Int",
3902         "A scalar or vector integer type",
3903         TypeSetBuilder::new()
3904             .ints(Interval::All)
3905             .simd_lanes(Interval::All)
3906             .build(),
3907     );
3908     let x = &Operand::new("x", Int);
3909     let a = &Operand::new("a", FloatTo);
3910 
3911     ig.push(
3912         Inst::new(
3913             "fcvt_from_uint",
3914             r#"
3915         Convert unsigned integer to floating point.
3916 
3917         Each lane in `x` is interpreted as an unsigned integer and converted to
3918         floating point using round to nearest, ties to even.
3919 
3920         The result type must have the same number of vector lanes as the input.
3921         "#,
3922             &formats.unary,
3923         )
3924         .operands_in(vec![x])
3925         .operands_out(vec![a]),
3926     );
3927 
3928     ig.push(
3929         Inst::new(
3930             "fcvt_from_sint",
3931             r#"
3932         Convert signed integer to floating point.
3933 
3934         Each lane in `x` is interpreted as a signed integer and converted to
3935         floating point using round to nearest, ties to even.
3936 
3937         The result type must have the same number of vector lanes as the input.
3938         "#,
3939             &formats.unary,
3940         )
3941         .operands_in(vec![x])
3942         .operands_out(vec![a]),
3943     );
3944 
3945     ig.push(
3946         Inst::new(
3947             "fcvt_low_from_sint",
3948             r#"
3949         Converts packed signed 32-bit integers to packed double precision floating point.
3950 
3951         Considering only the low half of the register, each lane in `x` is interpreted as a
3952         signed 32-bit integer that is then converted to a double precision float. This
3953         instruction differs from fcvt_from_sint in that it converts half the number of lanes
3954         which are converted to occupy twice the number of bits. No rounding should be needed
3955         for the resulting float.
3956 
3957         The result type will have half the number of vector lanes as the input.
3958         "#,
3959             &formats.unary,
3960         )
3961         .operands_in(vec![x])
3962         .operands_out(vec![a]),
3963     );
3964 
3965     let WideInt = &TypeVar::new(
3966         "WideInt",
3967         "An integer type with lanes from `i16` upwards",
3968         TypeSetBuilder::new()
3969             .ints(16..128)
3970             .simd_lanes(Interval::All)
3971             .build(),
3972     );
3973     let x = &Operand::new("x", WideInt);
3974     let lo = &Operand::new("lo", &WideInt.half_width()).with_doc("The low bits of `x`");
3975     let hi = &Operand::new("hi", &WideInt.half_width()).with_doc("The high bits of `x`");
3976 
3977     ig.push(
3978         Inst::new(
3979             "isplit",
3980             r#"
3981         Split an integer into low and high parts.
3982 
3983         Vectors of integers are split lane-wise, so the results have the same
3984         number of lanes as the input, but the lanes are half the size.
3985 
3986         Returns the low half of `x` and the high half of `x` as two independent
3987         values.
3988         "#,
3989             &formats.unary,
3990         )
3991         .operands_in(vec![x])
3992         .operands_out(vec![lo, hi]),
3993     );
3994 
3995     let NarrowInt = &TypeVar::new(
3996         "NarrowInt",
3997         "An integer type with lanes type to `i64`",
3998         TypeSetBuilder::new()
3999             .ints(8..64)
4000             .simd_lanes(Interval::All)
4001             .build(),
4002     );
4003 
4004     let lo = &Operand::new("lo", NarrowInt);
4005     let hi = &Operand::new("hi", NarrowInt);
4006     let a = &Operand::new("a", &NarrowInt.double_width())
4007         .with_doc("The concatenation of `lo` and `hi`");
4008 
4009     ig.push(
4010         Inst::new(
4011             "iconcat",
4012             r#"
4013         Concatenate low and high bits to form a larger integer type.
4014 
4015         Vectors of integers are concatenated lane-wise such that the result has
4016         the same number of lanes as the inputs, but the lanes are twice the
4017         size.
4018         "#,
4019             &formats.binary,
4020         )
4021         .operands_in(vec![lo, hi])
4022         .operands_out(vec![a]),
4023     );
4024 
4025     // Instructions relating to atomic memory accesses and fences
4026     let AtomicMem = &TypeVar::new(
4027         "AtomicMem",
4028         "Any type that can be stored in memory, which can be used in an atomic operation",
4029         TypeSetBuilder::new().ints(8..64).build(),
4030     );
4031     let x = &Operand::new("x", AtomicMem).with_doc("Value to be atomically stored");
4032     let a = &Operand::new("a", AtomicMem).with_doc("Value atomically loaded");
4033     let e = &Operand::new("e", AtomicMem).with_doc("Expected value in CAS");
4034     let p = &Operand::new("p", iAddr);
4035     let MemFlags = &Operand::new("MemFlags", &imm.memflags);
4036     let AtomicRmwOp = &Operand::new("AtomicRmwOp", &imm.atomic_rmw_op);
4037 
4038     ig.push(
4039         Inst::new(
4040             "atomic_rmw",
4041             r#"
4042         Atomically read-modify-write memory at `p`, with second operand `x`.  The old value is
4043         returned.  `p` has the type of the target word size, and `x` may be an integer type of
4044         8, 16, 32 or 64 bits, even on a 32-bit target.  The type of the returned value is the
4045         same as the type of `x`.  This operation is sequentially consistent and creates
4046         happens-before edges that order normal (non-atomic) loads and stores.
4047         "#,
4048             &formats.atomic_rmw,
4049         )
4050         .operands_in(vec![MemFlags, AtomicRmwOp, p, x])
4051         .operands_out(vec![a])
4052         .can_load(true)
4053         .can_store(true)
4054         .other_side_effects(true),
4055     );
4056 
4057     ig.push(
4058         Inst::new(
4059             "atomic_cas",
4060             r#"
4061         Perform an atomic compare-and-swap operation on memory at `p`, with expected value `e`,
4062         storing `x` if the value at `p` equals `e`.  The old value at `p` is returned,
4063         regardless of whether the operation succeeds or fails.  `p` has the type of the target
4064         word size, and `x` and `e` must have the same type and the same size, which may be an
4065         integer type of 8, 16, 32 or 64 bits, even on a 32-bit target.  The type of the returned
4066         value is the same as the type of `x` and `e`.  This operation is sequentially
4067         consistent and creates happens-before edges that order normal (non-atomic) loads and
4068         stores.
4069         "#,
4070             &formats.atomic_cas,
4071         )
4072         .operands_in(vec![MemFlags, p, e, x])
4073         .operands_out(vec![a])
4074         .can_load(true)
4075         .can_store(true)
4076         .other_side_effects(true),
4077     );
4078 
4079     ig.push(
4080         Inst::new(
4081             "atomic_load",
4082             r#"
4083         Atomically load from memory at `p`.
4084 
4085         This is a polymorphic instruction that can load any value type which has a memory
4086         representation.  It should only be used for integer types with 8, 16, 32 or 64 bits.
4087         This operation is sequentially consistent and creates happens-before edges that order
4088         normal (non-atomic) loads and stores.
4089         "#,
4090             &formats.load_no_offset,
4091         )
4092         .operands_in(vec![MemFlags, p])
4093         .operands_out(vec![a])
4094         .can_load(true)
4095         .other_side_effects(true),
4096     );
4097 
4098     ig.push(
4099         Inst::new(
4100             "atomic_store",
4101             r#"
4102         Atomically store `x` to memory at `p`.
4103 
4104         This is a polymorphic instruction that can store any value type with a memory
4105         representation.  It should only be used for integer types with 8, 16, 32 or 64 bits.
4106         This operation is sequentially consistent and creates happens-before edges that order
4107         normal (non-atomic) loads and stores.
4108         "#,
4109             &formats.store_no_offset,
4110         )
4111         .operands_in(vec![MemFlags, x, p])
4112         .can_store(true)
4113         .other_side_effects(true),
4114     );
4115 
4116     ig.push(
4117         Inst::new(
4118             "fence",
4119             r#"
4120         A memory fence.  This must provide ordering to ensure that, at a minimum, neither loads
4121         nor stores of any kind may move forwards or backwards across the fence.  This operation
4122         is sequentially consistent.
4123         "#,
4124             &formats.nullary,
4125         )
4126         .other_side_effects(true),
4127     );
4128 
4129     let TxN = &TypeVar::new(
4130         "TxN",
4131         "A dynamic vector type",
4132         TypeSetBuilder::new()
4133             .ints(Interval::All)
4134             .floats(Interval::All)
4135             .bools(Interval::All)
4136             .dynamic_simd_lanes(Interval::All)
4137             .build(),
4138     );
4139     let x = &Operand::new("x", TxN).with_doc("The dynamic vector to extract from");
4140     let y = &Operand::new("y", &imm.uimm8).with_doc("128-bit vector index");
4141     let a = &Operand::new("a", &TxN.dynamic_to_vector()).with_doc("New fixed vector");
4142 
4143     ig.push(
4144         Inst::new(
4145             "extract_vector",
4146             r#"
4147         Return a fixed length sub vector, extracted from a dynamic vector.
4148         "#,
4149             &formats.binary_imm8,
4150         )
4151         .operands_in(vec![x, y])
4152         .operands_out(vec![a]),
4153     );
4154 }
4155