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         a sign extended 64 bit 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 a sign extended 64 bit 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         Same as `imul`, but one operand is a sign extended 64 bit immediate constant.
2081 
2082         Polymorphic over all scalar integer types, but does not support vector
2083         types.
2084         "#,
2085             &formats.binary_imm64,
2086         )
2087         .operands_in(vec![x, Y])
2088         .operands_out(vec![a]),
2089     );
2090 
2091     ig.push(
2092         Inst::new(
2093             "udiv_imm",
2094             r#"
2095         Unsigned integer division by an immediate constant.
2096 
2097         Same as `udiv`, but one operand is a zero extended 64 bit immediate constant.
2098 
2099         This operation traps if the divisor is zero.
2100         "#,
2101             &formats.binary_imm64,
2102         )
2103         .operands_in(vec![x, Y])
2104         .operands_out(vec![a]),
2105     );
2106 
2107     ig.push(
2108         Inst::new(
2109             "sdiv_imm",
2110             r#"
2111         Signed integer division by an immediate constant.
2112 
2113         Same as `sdiv`, but one operand is a sign extended 64 bit immediate constant.
2114 
2115         This operation traps if the divisor is zero, or if the result is not
2116         representable in `B` bits two's complement. This only happens
2117         when `x = -2^{B-1}, Y = -1`.
2118         "#,
2119             &formats.binary_imm64,
2120         )
2121         .operands_in(vec![x, Y])
2122         .operands_out(vec![a]),
2123     );
2124 
2125     ig.push(
2126         Inst::new(
2127             "urem_imm",
2128             r#"
2129         Unsigned integer remainder with immediate divisor.
2130 
2131         Same as `urem`, but one operand is a zero extended 64 bit immediate constant.
2132 
2133         This operation traps if the divisor is zero.
2134         "#,
2135             &formats.binary_imm64,
2136         )
2137         .operands_in(vec![x, Y])
2138         .operands_out(vec![a]),
2139     );
2140 
2141     ig.push(
2142         Inst::new(
2143             "srem_imm",
2144             r#"
2145         Signed integer remainder with immediate divisor.
2146 
2147         Same as `srem`, but one operand is a sign extended 64 bit immediate constant.
2148 
2149         This operation traps if the divisor is zero.
2150         "#,
2151             &formats.binary_imm64,
2152         )
2153         .operands_in(vec![x, Y])
2154         .operands_out(vec![a]),
2155     );
2156 
2157     ig.push(
2158         Inst::new(
2159             "irsub_imm",
2160             r#"
2161         Immediate reverse wrapping subtraction: `a := Y - x \pmod{2^B}`.
2162 
2163         The immediate operand is a sign extended 64 bit constant.
2164 
2165         Also works as integer negation when `Y = 0`. Use `iadd_imm`
2166         with a negative immediate operand for the reverse immediate
2167         subtraction.
2168 
2169         Polymorphic over all scalar integer types, but does not support vector
2170         types.
2171         "#,
2172             &formats.binary_imm64,
2173         )
2174         .operands_in(vec![x, Y])
2175         .operands_out(vec![a]),
2176     );
2177 
2178     let a = &Operand::new("a", iB);
2179     let x = &Operand::new("x", iB);
2180     let y = &Operand::new("y", iB);
2181 
2182     let c_in = &Operand::new("c_in", b1).with_doc("Input carry flag");
2183     let c_out = &Operand::new("c_out", b1).with_doc("Output carry flag");
2184     let b_in = &Operand::new("b_in", b1).with_doc("Input borrow flag");
2185     let b_out = &Operand::new("b_out", b1).with_doc("Output borrow flag");
2186 
2187     let c_if_in = &Operand::new("c_in", iflags);
2188     let c_if_out = &Operand::new("c_out", iflags);
2189     let b_if_in = &Operand::new("b_in", iflags);
2190     let b_if_out = &Operand::new("b_out", iflags);
2191 
2192     ig.push(
2193         Inst::new(
2194             "iadd_cin",
2195             r#"
2196         Add integers with carry in.
2197 
2198         Same as `iadd` with an additional carry input. Computes:
2199 
2200         ```text
2201             a = x + y + c_{in} \pmod 2^B
2202         ```
2203 
2204         Polymorphic over all scalar integer types, but does not support vector
2205         types.
2206         "#,
2207             &formats.ternary,
2208         )
2209         .operands_in(vec![x, y, c_in])
2210         .operands_out(vec![a]),
2211     );
2212 
2213     ig.push(
2214         Inst::new(
2215             "iadd_ifcin",
2216             r#"
2217         Add integers with carry in.
2218 
2219         Same as `iadd` with an additional carry flag input. Computes:
2220 
2221         ```text
2222             a = x + y + c_{in} \pmod 2^B
2223         ```
2224 
2225         Polymorphic over all scalar integer types, but does not support vector
2226         types.
2227         "#,
2228             &formats.ternary,
2229         )
2230         .operands_in(vec![x, y, c_if_in])
2231         .operands_out(vec![a]),
2232     );
2233 
2234     ig.push(
2235         Inst::new(
2236             "iadd_cout",
2237             r#"
2238         Add integers with carry out.
2239 
2240         Same as `iadd` with an additional carry output.
2241 
2242         ```text
2243             a &= x + y \pmod 2^B \\
2244             c_{out} &= x+y >= 2^B
2245         ```
2246 
2247         Polymorphic over all scalar integer types, but does not support vector
2248         types.
2249         "#,
2250             &formats.binary,
2251         )
2252         .operands_in(vec![x, y])
2253         .operands_out(vec![a, c_out]),
2254     );
2255 
2256     ig.push(
2257         Inst::new(
2258             "iadd_ifcout",
2259             r#"
2260         Add integers with carry out.
2261 
2262         Same as `iadd` with an additional carry flag output.
2263 
2264         ```text
2265             a &= x + y \pmod 2^B \\
2266             c_{out} &= x+y >= 2^B
2267         ```
2268 
2269         Polymorphic over all scalar integer types, but does not support vector
2270         types.
2271         "#,
2272             &formats.binary,
2273         )
2274         .operands_in(vec![x, y])
2275         .operands_out(vec![a, c_if_out]),
2276     );
2277 
2278     ig.push(
2279         Inst::new(
2280             "iadd_carry",
2281             r#"
2282         Add integers with carry in and out.
2283 
2284         Same as `iadd` with an additional carry input and output.
2285 
2286         ```text
2287             a &= x + y + c_{in} \pmod 2^B \\
2288             c_{out} &= x + y + c_{in} >= 2^B
2289         ```
2290 
2291         Polymorphic over all scalar integer types, but does not support vector
2292         types.
2293         "#,
2294             &formats.ternary,
2295         )
2296         .operands_in(vec![x, y, c_in])
2297         .operands_out(vec![a, c_out]),
2298     );
2299 
2300     ig.push(
2301         Inst::new(
2302             "iadd_ifcarry",
2303             r#"
2304         Add integers with carry in and out.
2305 
2306         Same as `iadd` with an additional carry flag input and output.
2307 
2308         ```text
2309             a &= x + y + c_{in} \pmod 2^B \\
2310             c_{out} &= x + y + c_{in} >= 2^B
2311         ```
2312 
2313         Polymorphic over all scalar integer types, but does not support vector
2314         types.
2315         "#,
2316             &formats.ternary,
2317         )
2318         .operands_in(vec![x, y, c_if_in])
2319         .operands_out(vec![a, c_if_out]),
2320     );
2321 
2322     ig.push(
2323         Inst::new(
2324             "isub_bin",
2325             r#"
2326         Subtract integers with borrow in.
2327 
2328         Same as `isub` with an additional borrow flag input. Computes:
2329 
2330         ```text
2331             a = x - (y + b_{in}) \pmod 2^B
2332         ```
2333 
2334         Polymorphic over all scalar integer types, but does not support vector
2335         types.
2336         "#,
2337             &formats.ternary,
2338         )
2339         .operands_in(vec![x, y, b_in])
2340         .operands_out(vec![a]),
2341     );
2342 
2343     ig.push(
2344         Inst::new(
2345             "isub_ifbin",
2346             r#"
2347         Subtract integers with borrow in.
2348 
2349         Same as `isub` with an additional borrow flag input. Computes:
2350 
2351         ```text
2352             a = x - (y + b_{in}) \pmod 2^B
2353         ```
2354 
2355         Polymorphic over all scalar integer types, but does not support vector
2356         types.
2357         "#,
2358             &formats.ternary,
2359         )
2360         .operands_in(vec![x, y, b_if_in])
2361         .operands_out(vec![a]),
2362     );
2363 
2364     ig.push(
2365         Inst::new(
2366             "isub_bout",
2367             r#"
2368         Subtract integers with borrow out.
2369 
2370         Same as `isub` with an additional borrow flag output.
2371 
2372         ```text
2373             a &= x - y \pmod 2^B \\
2374             b_{out} &= x < y
2375         ```
2376 
2377         Polymorphic over all scalar integer types, but does not support vector
2378         types.
2379         "#,
2380             &formats.binary,
2381         )
2382         .operands_in(vec![x, y])
2383         .operands_out(vec![a, b_out]),
2384     );
2385 
2386     ig.push(
2387         Inst::new(
2388             "isub_ifbout",
2389             r#"
2390         Subtract integers with borrow out.
2391 
2392         Same as `isub` with an additional borrow flag output.
2393 
2394         ```text
2395             a &= x - y \pmod 2^B \\
2396             b_{out} &= x < y
2397         ```
2398 
2399         Polymorphic over all scalar integer types, but does not support vector
2400         types.
2401         "#,
2402             &formats.binary,
2403         )
2404         .operands_in(vec![x, y])
2405         .operands_out(vec![a, b_if_out]),
2406     );
2407 
2408     ig.push(
2409         Inst::new(
2410             "isub_borrow",
2411             r#"
2412         Subtract integers with borrow in and out.
2413 
2414         Same as `isub` with an additional borrow flag input and output.
2415 
2416         ```text
2417             a &= x - (y + b_{in}) \pmod 2^B \\
2418             b_{out} &= x < y + b_{in}
2419         ```
2420 
2421         Polymorphic over all scalar integer types, but does not support vector
2422         types.
2423         "#,
2424             &formats.ternary,
2425         )
2426         .operands_in(vec![x, y, b_in])
2427         .operands_out(vec![a, b_out]),
2428     );
2429 
2430     ig.push(
2431         Inst::new(
2432             "isub_ifborrow",
2433             r#"
2434         Subtract integers with borrow in and out.
2435 
2436         Same as `isub` with an additional borrow flag input and output.
2437 
2438         ```text
2439             a &= x - (y + b_{in}) \pmod 2^B \\
2440             b_{out} &= x < y + b_{in}
2441         ```
2442 
2443         Polymorphic over all scalar integer types, but does not support vector
2444         types.
2445         "#,
2446             &formats.ternary,
2447         )
2448         .operands_in(vec![x, y, b_if_in])
2449         .operands_out(vec![a, b_if_out]),
2450     );
2451 
2452     let bits = &TypeVar::new(
2453         "bits",
2454         "Any integer, float, or boolean scalar or vector type",
2455         TypeSetBuilder::new()
2456             .ints(Interval::All)
2457             .floats(Interval::All)
2458             .bools(Interval::All)
2459             .simd_lanes(Interval::All)
2460             .includes_scalars(true)
2461             .build(),
2462     );
2463     let x = &Operand::new("x", bits);
2464     let y = &Operand::new("y", bits);
2465     let a = &Operand::new("a", bits);
2466 
2467     ig.push(
2468         Inst::new(
2469             "band",
2470             r#"
2471         Bitwise and.
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             "bor",
2482             r#"
2483         Bitwise or.
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             "bxor",
2494             r#"
2495         Bitwise xor.
2496         "#,
2497             &formats.binary,
2498         )
2499         .operands_in(vec![x, y])
2500         .operands_out(vec![a]),
2501     );
2502 
2503     ig.push(
2504         Inst::new(
2505             "bnot",
2506             r#"
2507         Bitwise not.
2508         "#,
2509             &formats.unary,
2510         )
2511         .operands_in(vec![x])
2512         .operands_out(vec![a]),
2513     );
2514 
2515     ig.push(
2516         Inst::new(
2517             "band_not",
2518             r#"
2519         Bitwise and not.
2520 
2521         Computes `x & ~y`.
2522         "#,
2523             &formats.binary,
2524         )
2525         .operands_in(vec![x, y])
2526         .operands_out(vec![a]),
2527     );
2528 
2529     ig.push(
2530         Inst::new(
2531             "bor_not",
2532             r#"
2533         Bitwise or not.
2534 
2535         Computes `x | ~y`.
2536         "#,
2537             &formats.binary,
2538         )
2539         .operands_in(vec![x, y])
2540         .operands_out(vec![a]),
2541     );
2542 
2543     ig.push(
2544         Inst::new(
2545             "bxor_not",
2546             r#"
2547         Bitwise xor not.
2548 
2549         Computes `x ^ ~y`.
2550         "#,
2551             &formats.binary,
2552         )
2553         .operands_in(vec![x, y])
2554         .operands_out(vec![a]),
2555     );
2556 
2557     let x = &Operand::new("x", iB);
2558     let Y = &Operand::new("Y", &imm.imm64);
2559     let a = &Operand::new("a", iB);
2560 
2561     ig.push(
2562         Inst::new(
2563             "band_imm",
2564             r#"
2565         Bitwise and with immediate.
2566 
2567         Same as `band`, but one operand is a zero extended 64 bit immediate constant.
2568 
2569         Polymorphic over all scalar integer types, but does not support vector
2570         types.
2571         "#,
2572             &formats.binary_imm64,
2573         )
2574         .operands_in(vec![x, Y])
2575         .operands_out(vec![a]),
2576     );
2577 
2578     ig.push(
2579         Inst::new(
2580             "bor_imm",
2581             r#"
2582         Bitwise or with immediate.
2583 
2584         Same as `bor`, but one operand is a zero extended 64 bit immediate constant.
2585 
2586         Polymorphic over all scalar integer types, but does not support vector
2587         types.
2588         "#,
2589             &formats.binary_imm64,
2590         )
2591         .operands_in(vec![x, Y])
2592         .operands_out(vec![a]),
2593     );
2594 
2595     ig.push(
2596         Inst::new(
2597             "bxor_imm",
2598             r#"
2599         Bitwise xor with immediate.
2600 
2601         Same as `bxor`, but one operand is a zero extended 64 bit immediate constant.
2602 
2603         Polymorphic over all scalar integer types, but does not support vector
2604         types.
2605         "#,
2606             &formats.binary_imm64,
2607         )
2608         .operands_in(vec![x, Y])
2609         .operands_out(vec![a]),
2610     );
2611 
2612     let x = &Operand::new("x", Int).with_doc("Scalar or vector value to shift");
2613     let y = &Operand::new("y", iB).with_doc("Number of bits to shift");
2614     let Y = &Operand::new("Y", &imm.imm64);
2615     let a = &Operand::new("a", Int);
2616 
2617     ig.push(
2618         Inst::new(
2619             "rotl",
2620             r#"
2621         Rotate left.
2622 
2623         Rotate the bits in ``x`` by ``y`` places.
2624         "#,
2625             &formats.binary,
2626         )
2627         .operands_in(vec![x, y])
2628         .operands_out(vec![a]),
2629     );
2630 
2631     ig.push(
2632         Inst::new(
2633             "rotr",
2634             r#"
2635         Rotate right.
2636 
2637         Rotate the bits in ``x`` by ``y`` places.
2638         "#,
2639             &formats.binary,
2640         )
2641         .operands_in(vec![x, y])
2642         .operands_out(vec![a]),
2643     );
2644 
2645     ig.push(
2646         Inst::new(
2647             "rotl_imm",
2648             r#"
2649         Rotate left by immediate.
2650 
2651         Same as `rotl`, but one operand is a zero extended 64 bit immediate constant.
2652         "#,
2653             &formats.binary_imm64,
2654         )
2655         .operands_in(vec![x, Y])
2656         .operands_out(vec![a]),
2657     );
2658 
2659     ig.push(
2660         Inst::new(
2661             "rotr_imm",
2662             r#"
2663         Rotate right by immediate.
2664 
2665         Same as `rotr`, but one operand is a zero extended 64 bit immediate constant.
2666         "#,
2667             &formats.binary_imm64,
2668         )
2669         .operands_in(vec![x, Y])
2670         .operands_out(vec![a]),
2671     );
2672 
2673     ig.push(
2674         Inst::new(
2675             "ishl",
2676             r#"
2677         Integer shift left. Shift the bits in ``x`` towards the MSB by ``y``
2678         places. Shift in zero bits to the LSB.
2679 
2680         The shift amount is masked to the size of ``x``.
2681 
2682         When shifting a B-bits integer type, this instruction computes:
2683 
2684         ```text
2685             s &:= y \pmod B,
2686             a &:= x \cdot 2^s \pmod{2^B}.
2687         ```
2688         "#,
2689             &formats.binary,
2690         )
2691         .operands_in(vec![x, y])
2692         .operands_out(vec![a]),
2693     );
2694 
2695     ig.push(
2696         Inst::new(
2697             "ushr",
2698             r#"
2699         Unsigned shift right. Shift bits in ``x`` towards the LSB by ``y``
2700         places, shifting in zero bits to the MSB. Also called a *logical
2701         shift*.
2702 
2703         The shift amount is masked to the size of the register.
2704 
2705         When shifting a B-bits integer type, this instruction computes:
2706 
2707         ```text
2708             s &:= y \pmod B,
2709             a &:= \lfloor x \cdot 2^{-s} \rfloor.
2710         ```
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             "sshr",
2721             r#"
2722         Signed shift right. Shift bits in ``x`` towards the LSB by ``y``
2723         places, shifting in sign bits to the MSB. Also called an *arithmetic
2724         shift*.
2725 
2726         The shift amount is masked to the size of the register.
2727         "#,
2728             &formats.binary,
2729         )
2730         .operands_in(vec![x, y])
2731         .operands_out(vec![a]),
2732     );
2733 
2734     ig.push(
2735         Inst::new(
2736             "ishl_imm",
2737             r#"
2738         Integer shift left by immediate.
2739 
2740         The shift amount is masked to the size of ``x``.
2741         "#,
2742             &formats.binary_imm64,
2743         )
2744         .operands_in(vec![x, Y])
2745         .operands_out(vec![a]),
2746     );
2747 
2748     ig.push(
2749         Inst::new(
2750             "ushr_imm",
2751             r#"
2752         Unsigned shift right by immediate.
2753 
2754         The shift amount is masked to the size of the register.
2755         "#,
2756             &formats.binary_imm64,
2757         )
2758         .operands_in(vec![x, Y])
2759         .operands_out(vec![a]),
2760     );
2761 
2762     ig.push(
2763         Inst::new(
2764             "sshr_imm",
2765             r#"
2766         Signed shift right by immediate.
2767 
2768         The shift amount is masked to the size of the register.
2769         "#,
2770             &formats.binary_imm64,
2771         )
2772         .operands_in(vec![x, Y])
2773         .operands_out(vec![a]),
2774     );
2775 
2776     let x = &Operand::new("x", iB);
2777     let a = &Operand::new("a", iB);
2778 
2779     ig.push(
2780         Inst::new(
2781             "bitrev",
2782             r#"
2783         Reverse the bits of a integer.
2784 
2785         Reverses the bits in ``x``.
2786         "#,
2787             &formats.unary,
2788         )
2789         .operands_in(vec![x])
2790         .operands_out(vec![a]),
2791     );
2792 
2793     ig.push(
2794         Inst::new(
2795             "clz",
2796             r#"
2797         Count leading zero bits.
2798 
2799         Starting from the MSB in ``x``, count the number of zero bits before
2800         reaching the first one bit. When ``x`` is zero, returns the size of x
2801         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             "cls",
2812             r#"
2813         Count leading sign bits.
2814 
2815         Starting from the MSB after the sign bit in ``x``, count the number of
2816         consecutive bits identical to the sign bit. When ``x`` is 0 or -1,
2817         returns one less than the size of x in bits.
2818         "#,
2819             &formats.unary,
2820         )
2821         .operands_in(vec![x])
2822         .operands_out(vec![a]),
2823     );
2824 
2825     ig.push(
2826         Inst::new(
2827             "ctz",
2828             r#"
2829         Count trailing zeros.
2830 
2831         Starting from the LSB in ``x``, count the number of zero bits before
2832         reaching the first one bit. When ``x`` is zero, returns the size of x
2833         in bits.
2834         "#,
2835             &formats.unary,
2836         )
2837         .operands_in(vec![x])
2838         .operands_out(vec![a]),
2839     );
2840 
2841     let x = &Operand::new("x", Int);
2842     let a = &Operand::new("a", Int);
2843 
2844     ig.push(
2845         Inst::new(
2846             "popcnt",
2847             r#"
2848         Population count
2849 
2850         Count the number of one bits in ``x``.
2851         "#,
2852             &formats.unary,
2853         )
2854         .operands_in(vec![x])
2855         .operands_out(vec![a]),
2856     );
2857 
2858     let Float = &TypeVar::new(
2859         "Float",
2860         "A scalar or vector floating point number",
2861         TypeSetBuilder::new()
2862             .floats(Interval::All)
2863             .simd_lanes(Interval::All)
2864             .dynamic_simd_lanes(Interval::All)
2865             .build(),
2866     );
2867     let Cond = &Operand::new("Cond", &imm.floatcc);
2868     let x = &Operand::new("x", Float);
2869     let y = &Operand::new("y", Float);
2870     let a = &Operand::new("a", &Float.as_bool());
2871 
2872     ig.push(
2873         Inst::new(
2874             "fcmp",
2875             r#"
2876         Floating point comparison.
2877 
2878         Two IEEE 754-2008 floating point numbers, `x` and `y`, relate to each
2879         other in exactly one of four ways:
2880 
2881         ```text
2882         == ==========================================
2883         UN Unordered when one or both numbers is NaN.
2884         EQ When `x = y`. (And `0.0 = -0.0`).
2885         LT When `x < y`.
2886         GT When `x > y`.
2887         == ==========================================
2888         ```
2889 
2890         The 14 `floatcc` condition codes each correspond to a subset of
2891         the four relations, except for the empty set which would always be
2892         false, and the full set which would always be true.
2893 
2894         The condition codes are divided into 7 'ordered' conditions which don't
2895         include UN, and 7 unordered conditions which all include UN.
2896 
2897         ```text
2898         +-------+------------+---------+------------+-------------------------+
2899         |Ordered             |Unordered             |Condition                |
2900         +=======+============+=========+============+=========================+
2901         |ord    |EQ | LT | GT|uno      |UN          |NaNs absent / present.   |
2902         +-------+------------+---------+------------+-------------------------+
2903         |eq     |EQ          |ueq      |UN | EQ     |Equal                    |
2904         +-------+------------+---------+------------+-------------------------+
2905         |one    |LT | GT     |ne       |UN | LT | GT|Not equal                |
2906         +-------+------------+---------+------------+-------------------------+
2907         |lt     |LT          |ult      |UN | LT     |Less than                |
2908         +-------+------------+---------+------------+-------------------------+
2909         |le     |LT | EQ     |ule      |UN | LT | EQ|Less than or equal       |
2910         +-------+------------+---------+------------+-------------------------+
2911         |gt     |GT          |ugt      |UN | GT     |Greater than             |
2912         +-------+------------+---------+------------+-------------------------+
2913         |ge     |GT | EQ     |uge      |UN | GT | EQ|Greater than or equal    |
2914         +-------+------------+---------+------------+-------------------------+
2915         ```
2916 
2917         The standard C comparison operators, `<, <=, >, >=`, are all ordered,
2918         so they are false if either operand is NaN. The C equality operator,
2919         `==`, is ordered, and since inequality is defined as the logical
2920         inverse it is *unordered*. They map to the `floatcc` condition
2921         codes as follows:
2922 
2923         ```text
2924         ==== ====== ============
2925         C    `Cond` Subset
2926         ==== ====== ============
2927         `==` eq     EQ
2928         `!=` ne     UN | LT | GT
2929         `<`  lt     LT
2930         `<=` le     LT | EQ
2931         `>`  gt     GT
2932         `>=` ge     GT | EQ
2933         ==== ====== ============
2934         ```
2935 
2936         This subset of condition codes also corresponds to the WebAssembly
2937         floating point comparisons of the same name.
2938 
2939         When this instruction compares floating point vectors, it returns a
2940         boolean vector with the results of lane-wise comparisons.
2941         "#,
2942             &formats.float_compare,
2943         )
2944         .operands_in(vec![Cond, x, y])
2945         .operands_out(vec![a]),
2946     );
2947 
2948     let f = &Operand::new("f", fflags);
2949 
2950     ig.push(
2951         Inst::new(
2952             "ffcmp",
2953             r#"
2954         Floating point comparison returning flags.
2955 
2956         Compares two numbers like `fcmp`, but returns floating point CPU
2957         flags instead of testing a specific condition.
2958         "#,
2959             &formats.binary,
2960         )
2961         .operands_in(vec![x, y])
2962         .operands_out(vec![f]),
2963     );
2964 
2965     let x = &Operand::new("x", Float);
2966     let y = &Operand::new("y", Float);
2967     let z = &Operand::new("z", Float);
2968     let a = &Operand::new("a", Float).with_doc("Result of applying operator to each lane");
2969 
2970     ig.push(
2971         Inst::new(
2972             "fadd",
2973             r#"
2974         Floating point addition.
2975         "#,
2976             &formats.binary,
2977         )
2978         .operands_in(vec![x, y])
2979         .operands_out(vec![a]),
2980     );
2981 
2982     ig.push(
2983         Inst::new(
2984             "fsub",
2985             r#"
2986         Floating point subtraction.
2987         "#,
2988             &formats.binary,
2989         )
2990         .operands_in(vec![x, y])
2991         .operands_out(vec![a]),
2992     );
2993 
2994     ig.push(
2995         Inst::new(
2996             "fmul",
2997             r#"
2998         Floating point multiplication.
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             "fdiv",
3009             r#"
3010         Floating point division.
3011 
3012         Unlike the integer division instructions ` and
3013         `udiv`, this can't trap. Division by zero is infinity or
3014         NaN, depending on the dividend.
3015         "#,
3016             &formats.binary,
3017         )
3018         .operands_in(vec![x, y])
3019         .operands_out(vec![a]),
3020     );
3021 
3022     ig.push(
3023         Inst::new(
3024             "sqrt",
3025             r#"
3026         Floating point square root.
3027         "#,
3028             &formats.unary,
3029         )
3030         .operands_in(vec![x])
3031         .operands_out(vec![a]),
3032     );
3033 
3034     ig.push(
3035         Inst::new(
3036             "fma",
3037             r#"
3038         Floating point fused multiply-and-add.
3039 
3040         Computes `a := xy+z` without any intermediate rounding of the
3041         product.
3042         "#,
3043             &formats.ternary,
3044         )
3045         .operands_in(vec![x, y, z])
3046         .operands_out(vec![a]),
3047     );
3048 
3049     let a = &Operand::new("a", Float).with_doc("``x`` with its sign bit inverted");
3050 
3051     ig.push(
3052         Inst::new(
3053             "fneg",
3054             r#"
3055         Floating point negation.
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 cleared");
3066 
3067     ig.push(
3068         Inst::new(
3069             "fabs",
3070             r#"
3071         Floating point absolute value.
3072 
3073         Note that this is a pure bitwise operation.
3074         "#,
3075             &formats.unary,
3076         )
3077         .operands_in(vec![x])
3078         .operands_out(vec![a]),
3079     );
3080 
3081     let a = &Operand::new("a", Float).with_doc("``x`` with its sign bit changed to that of ``y``");
3082 
3083     ig.push(
3084         Inst::new(
3085             "fcopysign",
3086             r#"
3087         Floating point copy sign.
3088 
3089         Note that this is a pure bitwise operation. The sign bit from ``y`` is
3090         copied to the sign bit of ``x``.
3091         "#,
3092             &formats.binary,
3093         )
3094         .operands_in(vec![x, y])
3095         .operands_out(vec![a]),
3096     );
3097 
3098     let a = &Operand::new("a", Float).with_doc("The smaller of ``x`` and ``y``");
3099 
3100     ig.push(
3101         Inst::new(
3102             "fmin",
3103             r#"
3104         Floating point minimum, propagating NaNs using the WebAssembly rules.
3105 
3106         If either operand is NaN, this returns NaN with an unspecified sign. Furthermore, if
3107         each input NaN consists of a mantissa whose most significant bit is 1 and the rest is
3108         0, then the output has the same form. Otherwise, the output mantissa's most significant
3109         bit is 1 and the rest is unspecified.
3110         "#,
3111             &formats.binary,
3112         )
3113         .operands_in(vec![x, y])
3114         .operands_out(vec![a]),
3115     );
3116 
3117     ig.push(
3118         Inst::new(
3119             "fmin_pseudo",
3120             r#"
3121         Floating point pseudo-minimum, propagating NaNs.  This behaves differently from ``fmin``.
3122         See <https://github.com/WebAssembly/simd/pull/122> for background.
3123 
3124         The behaviour is defined as ``fmin_pseudo(a, b) = (b < a) ? b : a``, and the behaviour
3125         for zero or NaN inputs follows from the behaviour of ``<`` with such inputs.
3126         "#,
3127             &formats.binary,
3128         )
3129         .operands_in(vec![x, y])
3130         .operands_out(vec![a]),
3131     );
3132 
3133     let a = &Operand::new("a", Float).with_doc("The larger of ``x`` and ``y``");
3134 
3135     ig.push(
3136         Inst::new(
3137             "fmax",
3138             r#"
3139         Floating point maximum, propagating NaNs using the WebAssembly rules.
3140 
3141         If either operand is NaN, this returns NaN with an unspecified sign. Furthermore, if
3142         each input NaN consists of a mantissa whose most significant bit is 1 and the rest is
3143         0, then the output has the same form. Otherwise, the output mantissa's most significant
3144         bit is 1 and the rest is unspecified.
3145         "#,
3146             &formats.binary,
3147         )
3148         .operands_in(vec![x, y])
3149         .operands_out(vec![a]),
3150     );
3151 
3152     ig.push(
3153         Inst::new(
3154             "fmax_pseudo",
3155             r#"
3156         Floating point pseudo-maximum, propagating NaNs.  This behaves differently from ``fmax``.
3157         See <https://github.com/WebAssembly/simd/pull/122> for background.
3158 
3159         The behaviour is defined as ``fmax_pseudo(a, b) = (a < b) ? b : a``, and the behaviour
3160         for zero or NaN inputs follows from the behaviour of ``<`` with such inputs.
3161         "#,
3162             &formats.binary,
3163         )
3164         .operands_in(vec![x, y])
3165         .operands_out(vec![a]),
3166     );
3167 
3168     let a = &Operand::new("a", Float).with_doc("``x`` rounded to integral value");
3169 
3170     ig.push(
3171         Inst::new(
3172             "ceil",
3173             r#"
3174         Round floating point round to integral, towards positive infinity.
3175         "#,
3176             &formats.unary,
3177         )
3178         .operands_in(vec![x])
3179         .operands_out(vec![a]),
3180     );
3181 
3182     ig.push(
3183         Inst::new(
3184             "floor",
3185             r#"
3186         Round floating point round to integral, towards negative infinity.
3187         "#,
3188             &formats.unary,
3189         )
3190         .operands_in(vec![x])
3191         .operands_out(vec![a]),
3192     );
3193 
3194     ig.push(
3195         Inst::new(
3196             "trunc",
3197             r#"
3198         Round floating point round to integral, towards zero.
3199         "#,
3200             &formats.unary,
3201         )
3202         .operands_in(vec![x])
3203         .operands_out(vec![a]),
3204     );
3205 
3206     ig.push(
3207         Inst::new(
3208             "nearest",
3209             r#"
3210         Round floating point round to integral, towards nearest with ties to
3211         even.
3212         "#,
3213             &formats.unary,
3214         )
3215         .operands_in(vec![x])
3216         .operands_out(vec![a]),
3217     );
3218 
3219     let a = &Operand::new("a", b1);
3220     let x = &Operand::new("x", Ref);
3221 
3222     ig.push(
3223         Inst::new(
3224             "is_null",
3225             r#"
3226         Reference verification.
3227 
3228         The condition code determines if the reference type in question is
3229         null or not.
3230         "#,
3231             &formats.unary,
3232         )
3233         .operands_in(vec![x])
3234         .operands_out(vec![a]),
3235     );
3236 
3237     let a = &Operand::new("a", b1);
3238     let x = &Operand::new("x", Ref);
3239 
3240     ig.push(
3241         Inst::new(
3242             "is_invalid",
3243             r#"
3244         Reference verification.
3245 
3246         The condition code determines if the reference type in question is
3247         invalid or not.
3248         "#,
3249             &formats.unary,
3250         )
3251         .operands_in(vec![x])
3252         .operands_out(vec![a]),
3253     );
3254 
3255     let Cond = &Operand::new("Cond", &imm.intcc);
3256     let f = &Operand::new("f", iflags);
3257     let a = &Operand::new("a", b1);
3258 
3259     ig.push(
3260         Inst::new(
3261             "trueif",
3262             r#"
3263         Test integer CPU flags for a specific condition.
3264 
3265         Check the CPU flags in ``f`` against the ``Cond`` condition code and
3266         return true when the condition code is satisfied.
3267         "#,
3268             &formats.int_cond,
3269         )
3270         .operands_in(vec![Cond, f])
3271         .operands_out(vec![a]),
3272     );
3273 
3274     let Cond = &Operand::new("Cond", &imm.floatcc);
3275     let f = &Operand::new("f", fflags);
3276 
3277     ig.push(
3278         Inst::new(
3279             "trueff",
3280             r#"
3281         Test floating point CPU flags for a specific condition.
3282 
3283         Check the CPU flags in ``f`` against the ``Cond`` condition code and
3284         return true when the condition code is satisfied.
3285         "#,
3286             &formats.float_cond,
3287         )
3288         .operands_in(vec![Cond, f])
3289         .operands_out(vec![a]),
3290     );
3291 
3292     let x = &Operand::new("x", Mem);
3293     let a = &Operand::new("a", MemTo).with_doc("Bits of `x` reinterpreted");
3294 
3295     ig.push(
3296         Inst::new(
3297             "bitcast",
3298             r#"
3299         Reinterpret the bits in `x` as a different type.
3300 
3301         The input and output types must be storable to memory and of the same
3302         size. A bitcast is equivalent to storing one type and loading the other
3303         type from the same address.
3304         "#,
3305             &formats.unary,
3306         )
3307         .operands_in(vec![x])
3308         .operands_out(vec![a]),
3309     );
3310 
3311     let x = &Operand::new("x", Any);
3312     let a = &Operand::new("a", AnyTo).with_doc("Bits of `x` reinterpreted");
3313 
3314     ig.push(
3315         Inst::new(
3316             "raw_bitcast",
3317             r#"
3318         Cast the bits in `x` as a different type of the same bit width.
3319 
3320         This instruction does not change the data's representation but allows
3321         data in registers to be used as different types, e.g. an i32x4 as a
3322         b8x16. The only constraint on the result `a` is that it can be
3323         `raw_bitcast` back to the original type. Also, in a raw_bitcast between
3324         vector types with the same number of lanes, the value of each result
3325         lane is a raw_bitcast of the corresponding operand lane. TODO there is
3326         currently no mechanism for enforcing the bit width constraint.
3327         "#,
3328             &formats.unary,
3329         )
3330         .operands_in(vec![x])
3331         .operands_out(vec![a]),
3332     );
3333 
3334     let a = &Operand::new("a", TxN).with_doc("A vector value");
3335     let s = &Operand::new("s", &TxN.lane_of()).with_doc("A scalar value");
3336 
3337     ig.push(
3338         Inst::new(
3339             "scalar_to_vector",
3340             r#"
3341             Copies a scalar value to a vector value.  The scalar is copied into the
3342             least significant lane of the vector, and all other lanes will be zero.
3343             "#,
3344             &formats.unary,
3345         )
3346         .operands_in(vec![s])
3347         .operands_out(vec![a]),
3348     );
3349 
3350     let Bool = &TypeVar::new(
3351         "Bool",
3352         "A scalar boolean type",
3353         TypeSetBuilder::new().bools(Interval::All).build(),
3354     );
3355 
3356     let BoolTo = &TypeVar::new(
3357         "BoolTo",
3358         "A smaller boolean type",
3359         TypeSetBuilder::new().bools(Interval::All).build(),
3360     );
3361 
3362     let x = &Operand::new("x", Bool);
3363     let a = &Operand::new("a", BoolTo);
3364 
3365     ig.push(
3366         Inst::new(
3367             "breduce",
3368             r#"
3369         Convert `x` to a smaller boolean type by discarding the most significant bits.
3370         "#,
3371             &formats.unary,
3372         )
3373         .operands_in(vec![x])
3374         .operands_out(vec![a]),
3375     );
3376 
3377     let BoolTo = &TypeVar::new(
3378         "BoolTo",
3379         "A larger boolean type",
3380         TypeSetBuilder::new().bools(Interval::All).build(),
3381     );
3382     let x = &Operand::new("x", Bool);
3383     let a = &Operand::new("a", BoolTo);
3384 
3385     ig.push(
3386         Inst::new(
3387             "bextend",
3388             r#"
3389         Convert `x` to a larger boolean type
3390         "#,
3391             &formats.unary,
3392         )
3393         .operands_in(vec![x])
3394         .operands_out(vec![a]),
3395     );
3396 
3397     let IntTo = &TypeVar::new(
3398         "IntTo",
3399         "A scalar integer type",
3400         TypeSetBuilder::new().ints(Interval::All).build(),
3401     );
3402     let x = &Operand::new("x", ScalarBool);
3403     let a = &Operand::new("a", IntTo);
3404 
3405     ig.push(
3406         Inst::new(
3407             "bint",
3408             r#"
3409         Convert `x` to an integer.
3410 
3411         True maps to 1 and false maps to 0.
3412         "#,
3413             &formats.unary,
3414         )
3415         .operands_in(vec![x])
3416         .operands_out(vec![a]),
3417     );
3418 
3419     let Bool = &TypeVar::new(
3420         "Bool",
3421         "A scalar or vector boolean type",
3422         TypeSetBuilder::new()
3423             .bools(Interval::All)
3424             .simd_lanes(Interval::All)
3425             .build(),
3426     );
3427     let IntTo = &TypeVar::new(
3428         "IntTo",
3429         "An integer type with the same number of lanes",
3430         TypeSetBuilder::new()
3431             .ints(Interval::All)
3432             .simd_lanes(Interval::All)
3433             .build(),
3434     );
3435     let x = &Operand::new("x", Bool);
3436     let a = &Operand::new("a", IntTo);
3437 
3438     ig.push(
3439         Inst::new(
3440             "bmask",
3441             r#"
3442         Convert `x` to an integer mask.
3443 
3444         True maps to all 1s and false maps to all 0s. The result type must have
3445         the same number of vector lanes as the input.
3446         "#,
3447             &formats.unary,
3448         )
3449         .operands_in(vec![x])
3450         .operands_out(vec![a]),
3451     );
3452 
3453     let Int = &TypeVar::new(
3454         "Int",
3455         "A scalar integer type",
3456         TypeSetBuilder::new().ints(Interval::All).build(),
3457     );
3458 
3459     let IntTo = &TypeVar::new(
3460         "IntTo",
3461         "A smaller integer type",
3462         TypeSetBuilder::new().ints(Interval::All).build(),
3463     );
3464     let x = &Operand::new("x", Int);
3465     let a = &Operand::new("a", IntTo);
3466 
3467     ig.push(
3468         Inst::new(
3469             "ireduce",
3470             r#"
3471         Convert `x` to a smaller integer type by discarding
3472         the most significant bits.
3473 
3474         This is the same as reducing modulo `2^n`.
3475         "#,
3476             &formats.unary,
3477         )
3478         .operands_in(vec![x])
3479         .operands_out(vec![a]),
3480     );
3481 
3482     let I16or32or64xN = &TypeVar::new(
3483         "I16or32or64xN",
3484         "A SIMD vector type containing integer lanes 16, 32, or 64 bits wide",
3485         TypeSetBuilder::new()
3486             .ints(16..64)
3487             .simd_lanes(2..8)
3488             .dynamic_simd_lanes(2..8)
3489             .includes_scalars(false)
3490             .build(),
3491     );
3492 
3493     let x = &Operand::new("x", I16or32or64xN);
3494     let y = &Operand::new("y", I16or32or64xN);
3495     let a = &Operand::new("a", &I16or32or64xN.split_lanes());
3496 
3497     ig.push(
3498         Inst::new(
3499             "snarrow",
3500             r#"
3501         Combine `x` and `y` into a vector with twice the lanes but half the integer width while
3502         saturating overflowing values to the signed maximum and minimum.
3503 
3504         The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4`
3505         and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value
3506         returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`.
3507             "#,
3508             &formats.binary,
3509         )
3510         .operands_in(vec![x, y])
3511         .operands_out(vec![a]),
3512     );
3513 
3514     ig.push(
3515         Inst::new(
3516             "unarrow",
3517             r#"
3518         Combine `x` and `y` into a vector with twice the lanes but half the integer width while
3519         saturating overflowing values to the unsigned maximum and minimum.
3520 
3521         Note that all input lanes are considered signed: any negative lanes will overflow and be
3522         replaced with the unsigned minimum, `0x00`.
3523 
3524         The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4`
3525         and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value
3526         returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`.
3527             "#,
3528             &formats.binary,
3529         )
3530         .operands_in(vec![x, y])
3531         .operands_out(vec![a]),
3532     );
3533 
3534     ig.push(
3535         Inst::new(
3536             "uunarrow",
3537             r#"
3538         Combine `x` and `y` into a vector with twice the lanes but half the integer width while
3539         saturating overflowing values to the unsigned maximum and minimum.
3540 
3541         Note that all input lanes are considered unsigned: any negative values will be interpreted as unsigned, overflowing and being replaced with the unsigned maximum.
3542 
3543         The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4`
3544         and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value
3545         returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`.
3546             "#,
3547             &formats.binary,
3548         )
3549         .operands_in(vec![x, y])
3550         .operands_out(vec![a]),
3551     );
3552 
3553     let I8or16or32xN = &TypeVar::new(
3554         "I8or16or32xN",
3555         "A SIMD vector type containing integer lanes 8, 16, or 32 bits wide.",
3556         TypeSetBuilder::new()
3557             .ints(8..32)
3558             .simd_lanes(2..16)
3559             .dynamic_simd_lanes(2..16)
3560             .includes_scalars(false)
3561             .build(),
3562     );
3563 
3564     let x = &Operand::new("x", I8or16or32xN);
3565     let a = &Operand::new("a", &I8or16or32xN.merge_lanes());
3566 
3567     ig.push(
3568         Inst::new(
3569             "swiden_low",
3570             r#"
3571         Widen the low lanes of `x` using signed extension.
3572 
3573         This will double the lane width and halve the number of lanes.
3574             "#,
3575             &formats.unary,
3576         )
3577         .operands_in(vec![x])
3578         .operands_out(vec![a]),
3579     );
3580 
3581     ig.push(
3582         Inst::new(
3583             "swiden_high",
3584             r#"
3585         Widen the high lanes of `x` using signed extension.
3586 
3587         This will double the lane width and halve the number of lanes.
3588             "#,
3589             &formats.unary,
3590         )
3591         .operands_in(vec![x])
3592         .operands_out(vec![a]),
3593     );
3594 
3595     ig.push(
3596         Inst::new(
3597             "uwiden_low",
3598             r#"
3599         Widen the low lanes of `x` using unsigned extension.
3600 
3601         This will double the lane width and halve the number of lanes.
3602             "#,
3603             &formats.unary,
3604         )
3605         .operands_in(vec![x])
3606         .operands_out(vec![a]),
3607     );
3608 
3609     ig.push(
3610         Inst::new(
3611             "uwiden_high",
3612             r#"
3613             Widen the high lanes of `x` using unsigned extension.
3614 
3615             This will double the lane width and halve the number of lanes.
3616             "#,
3617             &formats.unary,
3618         )
3619         .operands_in(vec![x])
3620         .operands_out(vec![a]),
3621     );
3622 
3623     let x = &Operand::new("x", I8or16or32xN);
3624     let y = &Operand::new("y", I8or16or32xN);
3625     let a = &Operand::new("a", I8or16or32xN);
3626 
3627     ig.push(
3628         Inst::new(
3629             "iadd_pairwise",
3630             r#"
3631         Does lane-wise integer pairwise addition on two operands, putting the
3632         combined results into a single vector result. Here a pair refers to adjacent
3633         lanes in a vector, i.e. i*2 + (i*2+1) for i == num_lanes/2. The first operand
3634         pairwise add results will make up the low half of the resulting vector while
3635         the second operand pairwise add results will make up the upper half of the
3636         resulting vector.
3637             "#,
3638             &formats.binary,
3639         )
3640         .operands_in(vec![x, y])
3641         .operands_out(vec![a]),
3642     );
3643 
3644     let I16x8 = &TypeVar::new(
3645         "I16x8",
3646         "A SIMD vector type containing 8 integer lanes each 16 bits wide.",
3647         TypeSetBuilder::new()
3648             .ints(16..16)
3649             .simd_lanes(8..8)
3650             .includes_scalars(false)
3651             .build(),
3652     );
3653 
3654     let x = &Operand::new("x", I16x8);
3655     let y = &Operand::new("y", I16x8);
3656     let a = &Operand::new("a", &I16x8.merge_lanes());
3657 
3658     ig.push(
3659         Inst::new(
3660             "widening_pairwise_dot_product_s",
3661             r#"
3662         Takes corresponding elements in `x` and `y`, performs a sign-extending length-doubling
3663         multiplication on them, then adds adjacent pairs of elements to form the result.  For
3664         example, if the input vectors are `[x3, x2, x1, x0]` and `[y3, y2, y1, y0]`, it produces
3665         the vector `[r1, r0]`, where `r1 = sx(x3) * sx(y3) + sx(x2) * sx(y2)` and
3666         `r0 = sx(x1) * sx(y1) + sx(x0) * sx(y0)`, and `sx(n)` sign-extends `n` to twice its width.
3667 
3668         This will double the lane width and halve the number of lanes.  So the resulting
3669         vector has the same number of bits as `x` and `y` do (individually).
3670 
3671         See <https://github.com/WebAssembly/simd/pull/127> for background info.
3672             "#,
3673             &formats.binary,
3674         )
3675         .operands_in(vec![x, y])
3676         .operands_out(vec![a]),
3677     );
3678 
3679     let IntTo = &TypeVar::new(
3680         "IntTo",
3681         "A larger integer type with the same number of lanes",
3682         TypeSetBuilder::new()
3683             .ints(Interval::All)
3684             .simd_lanes(Interval::All)
3685             .build(),
3686     );
3687     let x = &Operand::new("x", Int);
3688     let a = &Operand::new("a", IntTo);
3689 
3690     ig.push(
3691         Inst::new(
3692             "uextend",
3693             r#"
3694         Convert `x` to a larger integer type by zero-extending.
3695 
3696         Each lane in `x` is converted to a larger integer type by adding
3697         zeroes. The result has the same numerical value as `x` when both are
3698         interpreted as unsigned integers.
3699 
3700         The result type must have the same number of vector lanes as the input,
3701         and each lane must not have fewer bits that the input lanes. If the
3702         input and output types are the same, this is a no-op.
3703         "#,
3704             &formats.unary,
3705         )
3706         .operands_in(vec![x])
3707         .operands_out(vec![a]),
3708     );
3709 
3710     ig.push(
3711         Inst::new(
3712             "sextend",
3713             r#"
3714         Convert `x` to a larger integer type by sign-extending.
3715 
3716         Each lane in `x` is converted to a larger integer type by replicating
3717         the sign bit. The result has the same numerical value as `x` when both
3718         are interpreted as signed integers.
3719 
3720         The result type must have the same number of vector lanes as the input,
3721         and each lane must not have fewer bits that the input lanes. If the
3722         input and output types are the same, this is a no-op.
3723         "#,
3724             &formats.unary,
3725         )
3726         .operands_in(vec![x])
3727         .operands_out(vec![a]),
3728     );
3729 
3730     let FloatTo = &TypeVar::new(
3731         "FloatTo",
3732         "A scalar or vector floating point number",
3733         TypeSetBuilder::new()
3734             .floats(Interval::All)
3735             .simd_lanes(Interval::All)
3736             .build(),
3737     );
3738     let x = &Operand::new("x", Float);
3739     let a = &Operand::new("a", FloatTo);
3740 
3741     ig.push(
3742         Inst::new(
3743             "fpromote",
3744             r#"
3745         Convert `x` to a larger floating point format.
3746 
3747         Each lane in `x` is converted to the destination floating point format.
3748         This is an exact operation.
3749 
3750         Cranelift currently only supports two floating point formats
3751         - `f32` and `f64`. This may change in the future.
3752 
3753         The result type must have the same number of vector lanes as the input,
3754         and the result lanes must not have fewer bits than the input lanes. If
3755         the input and output types are the same, this is a no-op.
3756         "#,
3757             &formats.unary,
3758         )
3759         .operands_in(vec![x])
3760         .operands_out(vec![a]),
3761     );
3762 
3763     ig.push(
3764         Inst::new(
3765             "fdemote",
3766             r#"
3767         Convert `x` to a smaller floating point format.
3768 
3769         Each lane in `x` is converted to the destination floating point format
3770         by rounding to nearest, ties to even.
3771 
3772         Cranelift currently only supports two floating point formats
3773         - `f32` and `f64`. This may change in the future.
3774 
3775         The result type must have the same number of vector lanes as the input,
3776         and the result lanes must not have more bits than the input lanes. If
3777         the input and output types are the same, this is a no-op.
3778         "#,
3779             &formats.unary,
3780         )
3781         .operands_in(vec![x])
3782         .operands_out(vec![a]),
3783     );
3784 
3785     let F64x2 = &TypeVar::new(
3786         "F64x2",
3787         "A SIMD vector type consisting of 2 lanes of 64-bit floats",
3788         TypeSetBuilder::new()
3789             .floats(64..64)
3790             .simd_lanes(2..2)
3791             .includes_scalars(false)
3792             .build(),
3793     );
3794     let F32x4 = &TypeVar::new(
3795         "F32x4",
3796         "A SIMD vector type consisting of 4 lanes of 32-bit floats",
3797         TypeSetBuilder::new()
3798             .floats(32..32)
3799             .simd_lanes(4..4)
3800             .includes_scalars(false)
3801             .build(),
3802     );
3803 
3804     let x = &Operand::new("x", F64x2);
3805     let a = &Operand::new("a", F32x4);
3806 
3807     ig.push(
3808         Inst::new(
3809             "fvdemote",
3810             r#"
3811                 Convert `x` to a smaller floating point format.
3812 
3813                 Each lane in `x` is converted to the destination floating point format
3814                 by rounding to nearest, ties to even.
3815 
3816                 Cranelift currently only supports two floating point formats
3817                 - `f32` and `f64`. This may change in the future.
3818 
3819                 Fvdemote differs from fdemote in that with fvdemote it targets vectors.
3820                 Fvdemote is constrained to having the input type being F64x2 and the result
3821                 type being F32x4. The result lane that was the upper half of the input lane
3822                 is initialized to zero.
3823                 "#,
3824             &formats.unary,
3825         )
3826         .operands_in(vec![x])
3827         .operands_out(vec![a]),
3828     );
3829 
3830     ig.push(
3831         Inst::new(
3832             "fvpromote_low",
3833             r#"
3834         Converts packed single precision floating point to packed double precision floating point.
3835 
3836         Considering only the lower half of the register, the low lanes in `x` are interpreted as
3837         single precision floats that are then converted to a double precision floats.
3838 
3839         The result type will have half the number of vector lanes as the input. Fvpromote_low is
3840         constrained to input F32x4 with a result type of F64x2.
3841         "#,
3842             &formats.unary,
3843         )
3844         .operands_in(vec![a])
3845         .operands_out(vec![x]),
3846     );
3847 
3848     let FloatScalar = &TypeVar::new(
3849         "FloatScalar",
3850         "A scalar only floating point number",
3851         TypeSetBuilder::new().floats(Interval::All).build(),
3852     );
3853     let x = &Operand::new("x", FloatScalar);
3854     let a = &Operand::new("a", IntTo);
3855 
3856     ig.push(
3857         Inst::new(
3858             "fcvt_to_uint",
3859             r#"
3860         Converts floating point scalars to unsigned integer.
3861 
3862         Only operates on `x` if it is a scalar. If `x` is NaN or if
3863         the unsigned integral value cannot be represented in the result
3864         type, this instruction traps.
3865 
3866         "#,
3867             &formats.unary,
3868         )
3869         .operands_in(vec![x])
3870         .operands_out(vec![a])
3871         .can_trap(true),
3872     );
3873 
3874     ig.push(
3875         Inst::new(
3876             "fcvt_to_sint",
3877             r#"
3878         Converts floating point scalars to signed integer.
3879 
3880         Only operates on `x` if it is a scalar. If `x` is NaN or if
3881         the unsigned integral value cannot be represented in the result
3882         type, this instruction traps.
3883 
3884         "#,
3885             &formats.unary,
3886         )
3887         .operands_in(vec![x])
3888         .operands_out(vec![a])
3889         .can_trap(true),
3890     );
3891 
3892     let x = &Operand::new("x", Float);
3893     let a = &Operand::new("a", IntTo);
3894 
3895     ig.push(
3896         Inst::new(
3897             "fcvt_to_uint_sat",
3898             r#"
3899         Convert floating point to unsigned integer as fcvt_to_uint does, but
3900         saturates the input instead of trapping. NaN and negative values are
3901         converted to 0.
3902         "#,
3903             &formats.unary,
3904         )
3905         .operands_in(vec![x])
3906         .operands_out(vec![a]),
3907     );
3908 
3909     ig.push(
3910         Inst::new(
3911             "fcvt_to_sint_sat",
3912             r#"
3913         Convert floating point to signed integer as fcvt_to_sint does, but
3914         saturates the input instead of trapping. NaN values are converted to 0.
3915         "#,
3916             &formats.unary,
3917         )
3918         .operands_in(vec![x])
3919         .operands_out(vec![a]),
3920     );
3921 
3922     let Int = &TypeVar::new(
3923         "Int",
3924         "A scalar or vector integer type",
3925         TypeSetBuilder::new()
3926             .ints(Interval::All)
3927             .simd_lanes(Interval::All)
3928             .build(),
3929     );
3930     let x = &Operand::new("x", Int);
3931     let a = &Operand::new("a", FloatTo);
3932 
3933     ig.push(
3934         Inst::new(
3935             "fcvt_from_uint",
3936             r#"
3937         Convert unsigned integer to floating point.
3938 
3939         Each lane in `x` is interpreted as an unsigned integer and converted to
3940         floating point using round to nearest, ties to even.
3941 
3942         The result type must have the same number of vector lanes as the input.
3943         "#,
3944             &formats.unary,
3945         )
3946         .operands_in(vec![x])
3947         .operands_out(vec![a]),
3948     );
3949 
3950     ig.push(
3951         Inst::new(
3952             "fcvt_from_sint",
3953             r#"
3954         Convert signed integer to floating point.
3955 
3956         Each lane in `x` is interpreted as a signed integer and converted to
3957         floating point using round to nearest, ties to even.
3958 
3959         The result type must have the same number of vector lanes as the input.
3960         "#,
3961             &formats.unary,
3962         )
3963         .operands_in(vec![x])
3964         .operands_out(vec![a]),
3965     );
3966 
3967     ig.push(
3968         Inst::new(
3969             "fcvt_low_from_sint",
3970             r#"
3971         Converts packed signed 32-bit integers to packed double precision floating point.
3972 
3973         Considering only the low half of the register, each lane in `x` is interpreted as a
3974         signed 32-bit integer that is then converted to a double precision float. This
3975         instruction differs from fcvt_from_sint in that it converts half the number of lanes
3976         which are converted to occupy twice the number of bits. No rounding should be needed
3977         for the resulting float.
3978 
3979         The result type will have half the number of vector lanes as the input.
3980         "#,
3981             &formats.unary,
3982         )
3983         .operands_in(vec![x])
3984         .operands_out(vec![a]),
3985     );
3986 
3987     let WideInt = &TypeVar::new(
3988         "WideInt",
3989         "An integer type with lanes from `i16` upwards",
3990         TypeSetBuilder::new()
3991             .ints(16..128)
3992             .simd_lanes(Interval::All)
3993             .build(),
3994     );
3995     let x = &Operand::new("x", WideInt);
3996     let lo = &Operand::new("lo", &WideInt.half_width()).with_doc("The low bits of `x`");
3997     let hi = &Operand::new("hi", &WideInt.half_width()).with_doc("The high bits of `x`");
3998 
3999     ig.push(
4000         Inst::new(
4001             "isplit",
4002             r#"
4003         Split an integer into low and high parts.
4004 
4005         Vectors of integers are split lane-wise, so the results have the same
4006         number of lanes as the input, but the lanes are half the size.
4007 
4008         Returns the low half of `x` and the high half of `x` as two independent
4009         values.
4010         "#,
4011             &formats.unary,
4012         )
4013         .operands_in(vec![x])
4014         .operands_out(vec![lo, hi]),
4015     );
4016 
4017     let NarrowInt = &TypeVar::new(
4018         "NarrowInt",
4019         "An integer type with lanes type to `i64`",
4020         TypeSetBuilder::new()
4021             .ints(8..64)
4022             .simd_lanes(Interval::All)
4023             .build(),
4024     );
4025 
4026     let lo = &Operand::new("lo", NarrowInt);
4027     let hi = &Operand::new("hi", NarrowInt);
4028     let a = &Operand::new("a", &NarrowInt.double_width())
4029         .with_doc("The concatenation of `lo` and `hi`");
4030 
4031     ig.push(
4032         Inst::new(
4033             "iconcat",
4034             r#"
4035         Concatenate low and high bits to form a larger integer type.
4036 
4037         Vectors of integers are concatenated lane-wise such that the result has
4038         the same number of lanes as the inputs, but the lanes are twice the
4039         size.
4040         "#,
4041             &formats.binary,
4042         )
4043         .operands_in(vec![lo, hi])
4044         .operands_out(vec![a]),
4045     );
4046 
4047     // Instructions relating to atomic memory accesses and fences
4048     let AtomicMem = &TypeVar::new(
4049         "AtomicMem",
4050         "Any type that can be stored in memory, which can be used in an atomic operation",
4051         TypeSetBuilder::new().ints(8..64).build(),
4052     );
4053     let x = &Operand::new("x", AtomicMem).with_doc("Value to be atomically stored");
4054     let a = &Operand::new("a", AtomicMem).with_doc("Value atomically loaded");
4055     let e = &Operand::new("e", AtomicMem).with_doc("Expected value in CAS");
4056     let p = &Operand::new("p", iAddr);
4057     let MemFlags = &Operand::new("MemFlags", &imm.memflags);
4058     let AtomicRmwOp = &Operand::new("AtomicRmwOp", &imm.atomic_rmw_op);
4059 
4060     ig.push(
4061         Inst::new(
4062             "atomic_rmw",
4063             r#"
4064         Atomically read-modify-write memory at `p`, with second operand `x`.  The old value is
4065         returned.  `p` has the type of the target word size, and `x` may be an integer type of
4066         8, 16, 32 or 64 bits, even on a 32-bit target.  The type of the returned value is the
4067         same as the type of `x`.  This operation is sequentially consistent and creates
4068         happens-before edges that order normal (non-atomic) loads and stores.
4069         "#,
4070             &formats.atomic_rmw,
4071         )
4072         .operands_in(vec![MemFlags, AtomicRmwOp, p, 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_cas",
4082             r#"
4083         Perform an atomic compare-and-swap operation on memory at `p`, with expected value `e`,
4084         storing `x` if the value at `p` equals `e`.  The old value at `p` is returned,
4085         regardless of whether the operation succeeds or fails.  `p` has the type of the target
4086         word size, and `x` and `e` must have the same type and the same size, which may be an
4087         integer type of 8, 16, 32 or 64 bits, even on a 32-bit target.  The type of the returned
4088         value is the same as the type of `x` and `e`.  This operation is sequentially
4089         consistent and creates happens-before edges that order normal (non-atomic) loads and
4090         stores.
4091         "#,
4092             &formats.atomic_cas,
4093         )
4094         .operands_in(vec![MemFlags, p, e, x])
4095         .operands_out(vec![a])
4096         .can_load(true)
4097         .can_store(true)
4098         .other_side_effects(true),
4099     );
4100 
4101     ig.push(
4102         Inst::new(
4103             "atomic_load",
4104             r#"
4105         Atomically load from memory at `p`.
4106 
4107         This is a polymorphic instruction that can load any value type which has a memory
4108         representation.  It should only be used for integer types with 8, 16, 32 or 64 bits.
4109         This operation is sequentially consistent and creates happens-before edges that order
4110         normal (non-atomic) loads and stores.
4111         "#,
4112             &formats.load_no_offset,
4113         )
4114         .operands_in(vec![MemFlags, p])
4115         .operands_out(vec![a])
4116         .can_load(true)
4117         .other_side_effects(true),
4118     );
4119 
4120     ig.push(
4121         Inst::new(
4122             "atomic_store",
4123             r#"
4124         Atomically store `x` to memory at `p`.
4125 
4126         This is a polymorphic instruction that can store any value type with a memory
4127         representation.  It should only be used for integer types with 8, 16, 32 or 64 bits.
4128         This operation is sequentially consistent and creates happens-before edges that order
4129         normal (non-atomic) loads and stores.
4130         "#,
4131             &formats.store_no_offset,
4132         )
4133         .operands_in(vec![MemFlags, x, p])
4134         .can_store(true)
4135         .other_side_effects(true),
4136     );
4137 
4138     ig.push(
4139         Inst::new(
4140             "fence",
4141             r#"
4142         A memory fence.  This must provide ordering to ensure that, at a minimum, neither loads
4143         nor stores of any kind may move forwards or backwards across the fence.  This operation
4144         is sequentially consistent.
4145         "#,
4146             &formats.nullary,
4147         )
4148         .other_side_effects(true),
4149     );
4150 
4151     let TxN = &TypeVar::new(
4152         "TxN",
4153         "A dynamic vector type",
4154         TypeSetBuilder::new()
4155             .ints(Interval::All)
4156             .floats(Interval::All)
4157             .bools(Interval::All)
4158             .dynamic_simd_lanes(Interval::All)
4159             .build(),
4160     );
4161     let x = &Operand::new("x", TxN).with_doc("The dynamic vector to extract from");
4162     let y = &Operand::new("y", &imm.uimm8).with_doc("128-bit vector index");
4163     let a = &Operand::new("a", &TxN.dynamic_to_vector()).with_doc("New fixed vector");
4164 
4165     ig.push(
4166         Inst::new(
4167             "extract_vector",
4168             r#"
4169         Return a fixed length sub vector, extracted from a dynamic vector.
4170         "#,
4171             &formats.binary_imm8,
4172         )
4173         .operands_in(vec![x, y])
4174         .operands_out(vec![a]),
4175     );
4176 }
4177