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