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