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 using the WebAssembly rules.
3601 
3602         If either operand is NaN, this returns NaN with an unspecified sign. Furthermore, if
3603         each input NaN consists of a mantissa whose most significant bit is 1 and the rest is
3604         0, then the output has the same form. Otherwise, the output mantissa's most significant
3605         bit is 1 and the rest is unspecified.
3606         "#,
3607             &formats.binary,
3608         )
3609         .operands_in(vec![x, y])
3610         .operands_out(vec![a]),
3611     );
3612 
3613     ig.push(
3614         Inst::new(
3615             "fmin_pseudo",
3616             r#"
3617         Floating point pseudo-minimum, propagating NaNs.  This behaves differently from ``fmin``.
3618         See <https://github.com/WebAssembly/simd/pull/122> for background.
3619 
3620         The behaviour is defined as ``fmin_pseudo(a, b) = (b < a) ? b : a``, and the behaviour
3621         for zero or NaN inputs follows from the behaviour of ``<`` with such inputs.
3622         "#,
3623             &formats.binary,
3624         )
3625         .operands_in(vec![x, y])
3626         .operands_out(vec![a]),
3627     );
3628 
3629     let a = &Operand::new("a", Float).with_doc("The larger of ``x`` and ``y``");
3630 
3631     ig.push(
3632         Inst::new(
3633             "fmax",
3634             r#"
3635         Floating point maximum, propagating NaNs using the WebAssembly rules.
3636 
3637         If either operand is NaN, this returns NaN with an unspecified sign. Furthermore, if
3638         each input NaN consists of a mantissa whose most significant bit is 1 and the rest is
3639         0, then the output has the same form. Otherwise, the output mantissa's most significant
3640         bit is 1 and the rest is unspecified.
3641         "#,
3642             &formats.binary,
3643         )
3644         .operands_in(vec![x, y])
3645         .operands_out(vec![a]),
3646     );
3647 
3648     ig.push(
3649         Inst::new(
3650             "fmax_pseudo",
3651             r#"
3652         Floating point pseudo-maximum, propagating NaNs.  This behaves differently from ``fmax``.
3653         See <https://github.com/WebAssembly/simd/pull/122> for background.
3654 
3655         The behaviour is defined as ``fmax_pseudo(a, b) = (a < b) ? b : a``, and the behaviour
3656         for zero or NaN inputs follows from the behaviour of ``<`` with such inputs.
3657         "#,
3658             &formats.binary,
3659         )
3660         .operands_in(vec![x, y])
3661         .operands_out(vec![a]),
3662     );
3663 
3664     let a = &Operand::new("a", Float).with_doc("``x`` rounded to integral value");
3665 
3666     ig.push(
3667         Inst::new(
3668             "ceil",
3669             r#"
3670         Round floating point round to integral, towards positive infinity.
3671         "#,
3672             &formats.unary,
3673         )
3674         .operands_in(vec![x])
3675         .operands_out(vec![a]),
3676     );
3677 
3678     ig.push(
3679         Inst::new(
3680             "floor",
3681             r#"
3682         Round floating point round to integral, towards negative infinity.
3683         "#,
3684             &formats.unary,
3685         )
3686         .operands_in(vec![x])
3687         .operands_out(vec![a]),
3688     );
3689 
3690     ig.push(
3691         Inst::new(
3692             "trunc",
3693             r#"
3694         Round floating point round to integral, towards zero.
3695         "#,
3696             &formats.unary,
3697         )
3698         .operands_in(vec![x])
3699         .operands_out(vec![a]),
3700     );
3701 
3702     ig.push(
3703         Inst::new(
3704             "nearest",
3705             r#"
3706         Round floating point round to integral, towards nearest with ties to
3707         even.
3708         "#,
3709             &formats.unary,
3710         )
3711         .operands_in(vec![x])
3712         .operands_out(vec![a]),
3713     );
3714 
3715     let a = &Operand::new("a", b1);
3716     let x = &Operand::new("x", Ref);
3717 
3718     ig.push(
3719         Inst::new(
3720             "is_null",
3721             r#"
3722         Reference verification.
3723 
3724         The condition code determines if the reference type in question is
3725         null or not.
3726         "#,
3727             &formats.unary,
3728         )
3729         .operands_in(vec![x])
3730         .operands_out(vec![a]),
3731     );
3732 
3733     let a = &Operand::new("a", b1);
3734     let x = &Operand::new("x", Ref);
3735 
3736     ig.push(
3737         Inst::new(
3738             "is_invalid",
3739             r#"
3740         Reference verification.
3741 
3742         The condition code determines if the reference type in question is
3743         invalid or not.
3744         "#,
3745             &formats.unary,
3746         )
3747         .operands_in(vec![x])
3748         .operands_out(vec![a]),
3749     );
3750 
3751     let Cond = &Operand::new("Cond", &imm.intcc);
3752     let f = &Operand::new("f", iflags);
3753     let a = &Operand::new("a", b1);
3754 
3755     ig.push(
3756         Inst::new(
3757             "trueif",
3758             r#"
3759         Test integer CPU flags for a specific condition.
3760 
3761         Check the CPU flags in ``f`` against the ``Cond`` condition code and
3762         return true when the condition code is satisfied.
3763         "#,
3764             &formats.int_cond,
3765         )
3766         .operands_in(vec![Cond, f])
3767         .operands_out(vec![a]),
3768     );
3769 
3770     let Cond = &Operand::new("Cond", &imm.floatcc);
3771     let f = &Operand::new("f", fflags);
3772 
3773     ig.push(
3774         Inst::new(
3775             "trueff",
3776             r#"
3777         Test floating point CPU flags for a specific condition.
3778 
3779         Check the CPU flags in ``f`` against the ``Cond`` condition code and
3780         return true when the condition code is satisfied.
3781         "#,
3782             &formats.float_cond,
3783         )
3784         .operands_in(vec![Cond, f])
3785         .operands_out(vec![a]),
3786     );
3787 
3788     let x = &Operand::new("x", Mem);
3789     let a = &Operand::new("a", MemTo).with_doc("Bits of `x` reinterpreted");
3790 
3791     ig.push(
3792         Inst::new(
3793             "bitcast",
3794             r#"
3795         Reinterpret the bits in `x` as a different type.
3796 
3797         The input and output types must be storable to memory and of the same
3798         size. A bitcast is equivalent to storing one type and loading the other
3799         type from the same address.
3800         "#,
3801             &formats.unary,
3802         )
3803         .operands_in(vec![x])
3804         .operands_out(vec![a]),
3805     );
3806 
3807     let x = &Operand::new("x", Any);
3808     let a = &Operand::new("a", AnyTo).with_doc("Bits of `x` reinterpreted");
3809 
3810     ig.push(
3811         Inst::new(
3812             "raw_bitcast",
3813             r#"
3814         Cast the bits in `x` as a different type of the same bit width.
3815 
3816         This instruction does not change the data's representation but allows
3817         data in registers to be used as different types, e.g. an i32x4 as a
3818         b8x16. The only constraint on the result `a` is that it can be
3819         `raw_bitcast` back to the original type. Also, in a raw_bitcast between
3820         vector types with the same number of lanes, the value of each result
3821         lane is a raw_bitcast of the corresponding operand lane. TODO there is
3822         currently no mechanism for enforcing the bit width constraint.
3823         "#,
3824             &formats.unary,
3825         )
3826         .operands_in(vec![x])
3827         .operands_out(vec![a]),
3828     );
3829 
3830     let a = &Operand::new("a", TxN).with_doc("A vector value");
3831     let s = &Operand::new("s", &TxN.lane_of()).with_doc("A scalar value");
3832 
3833     ig.push(
3834         Inst::new(
3835             "scalar_to_vector",
3836             r#"
3837             Copies a scalar value to a vector value.  The scalar is copied into the
3838             least significant lane of the vector, and all other lanes will be zero.
3839             "#,
3840             &formats.unary,
3841         )
3842         .operands_in(vec![s])
3843         .operands_out(vec![a]),
3844     );
3845 
3846     let Bool = &TypeVar::new(
3847         "Bool",
3848         "A scalar or vector boolean type",
3849         TypeSetBuilder::new()
3850             .bools(Interval::All)
3851             .simd_lanes(Interval::All)
3852             .build(),
3853     );
3854 
3855     let BoolTo = &TypeVar::new(
3856         "BoolTo",
3857         "A smaller boolean type with the same number of lanes",
3858         TypeSetBuilder::new()
3859             .bools(Interval::All)
3860             .simd_lanes(Interval::All)
3861             .build(),
3862     );
3863 
3864     let x = &Operand::new("x", Bool);
3865     let a = &Operand::new("a", BoolTo);
3866 
3867     ig.push(
3868         Inst::new(
3869             "breduce",
3870             r#"
3871         Convert `x` to a smaller boolean type in the platform-defined way.
3872 
3873         The result type must have the same number of vector lanes as the input,
3874         and each lane must not have more bits that the input lanes. If the
3875         input and output types are the same, this is a no-op.
3876         "#,
3877             &formats.unary,
3878         )
3879         .operands_in(vec![x])
3880         .operands_out(vec![a])
3881         .constraints(vec![WiderOrEq(Bool.clone(), BoolTo.clone())]),
3882     );
3883 
3884     let BoolTo = &TypeVar::new(
3885         "BoolTo",
3886         "A larger boolean type with the same number of lanes",
3887         TypeSetBuilder::new()
3888             .bools(Interval::All)
3889             .simd_lanes(Interval::All)
3890             .build(),
3891     );
3892     let x = &Operand::new("x", Bool);
3893     let a = &Operand::new("a", BoolTo);
3894 
3895     ig.push(
3896         Inst::new(
3897             "bextend",
3898             r#"
3899         Convert `x` to a larger boolean type in the platform-defined way.
3900 
3901         The result type must have the same number of vector lanes as the input,
3902         and each lane must not have fewer bits that the input lanes. If the
3903         input and output types are the same, this is a no-op.
3904         "#,
3905             &formats.unary,
3906         )
3907         .operands_in(vec![x])
3908         .operands_out(vec![a])
3909         .constraints(vec![WiderOrEq(BoolTo.clone(), Bool.clone())]),
3910     );
3911 
3912     let IntTo = &TypeVar::new(
3913         "IntTo",
3914         "An integer type with the same number of lanes",
3915         TypeSetBuilder::new()
3916             .ints(Interval::All)
3917             .simd_lanes(Interval::All)
3918             .build(),
3919     );
3920     let x = &Operand::new("x", Bool);
3921     let a = &Operand::new("a", IntTo);
3922 
3923     ig.push(
3924         Inst::new(
3925             "bint",
3926             r#"
3927         Convert `x` to an integer.
3928 
3929         True maps to 1 and false maps to 0. The result type must have the same
3930         number of vector lanes as the input.
3931         "#,
3932             &formats.unary,
3933         )
3934         .operands_in(vec![x])
3935         .operands_out(vec![a]),
3936     );
3937 
3938     ig.push(
3939         Inst::new(
3940             "bmask",
3941             r#"
3942         Convert `x` to an integer mask.
3943 
3944         True maps to all 1s and false maps to all 0s. The result type must have
3945         the same number of vector lanes as the input.
3946         "#,
3947             &formats.unary,
3948         )
3949         .operands_in(vec![x])
3950         .operands_out(vec![a]),
3951     );
3952 
3953     let Int = &TypeVar::new(
3954         "Int",
3955         "A scalar or vector integer type",
3956         TypeSetBuilder::new()
3957             .ints(Interval::All)
3958             .simd_lanes(Interval::All)
3959             .build(),
3960     );
3961 
3962     let IntTo = &TypeVar::new(
3963         "IntTo",
3964         "A smaller integer type with the same number of lanes",
3965         TypeSetBuilder::new()
3966             .ints(Interval::All)
3967             .simd_lanes(Interval::All)
3968             .build(),
3969     );
3970     let x = &Operand::new("x", Int);
3971     let a = &Operand::new("a", IntTo);
3972 
3973     ig.push(
3974         Inst::new(
3975             "ireduce",
3976             r#"
3977         Convert `x` to a smaller integer type by dropping high bits.
3978 
3979         Each lane in `x` is converted to a smaller integer type by discarding
3980         the most significant bits. This is the same as reducing modulo
3981         `2^n`.
3982 
3983         The result type must have the same number of vector lanes as the input,
3984         and each lane must not have more bits that the input lanes. If the
3985         input and output types are the same, this is a no-op.
3986         "#,
3987             &formats.unary,
3988         )
3989         .operands_in(vec![x])
3990         .operands_out(vec![a])
3991         .constraints(vec![WiderOrEq(Int.clone(), IntTo.clone())]),
3992     );
3993 
3994     let I16or32or64xN = &TypeVar::new(
3995         "I16or32or64xN",
3996         "A SIMD vector type containing integer lanes 16, 32, or 64 bits wide",
3997         TypeSetBuilder::new()
3998             .ints(16..64)
3999             .simd_lanes(2..8)
4000             .includes_scalars(false)
4001             .build(),
4002     );
4003 
4004     let x = &Operand::new("x", I16or32or64xN);
4005     let y = &Operand::new("y", I16or32or64xN);
4006     let a = &Operand::new("a", &I16or32or64xN.split_lanes());
4007 
4008     ig.push(
4009         Inst::new(
4010             "snarrow",
4011             r#"
4012         Combine `x` and `y` into a vector with twice the lanes but half the integer width while
4013         saturating overflowing values to the signed maximum and minimum.
4014 
4015         The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4`
4016         and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value
4017         returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`.
4018             "#,
4019             &formats.binary,
4020         )
4021         .operands_in(vec![x, y])
4022         .operands_out(vec![a]),
4023     );
4024 
4025     ig.push(
4026         Inst::new(
4027             "unarrow",
4028             r#"
4029         Combine `x` and `y` into a vector with twice the lanes but half the integer width while
4030         saturating overflowing values to the unsigned maximum and minimum.
4031 
4032         Note that all input lanes are considered signed: any negative lanes will overflow and be
4033         replaced with the unsigned minimum, `0x00`.
4034 
4035         The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4`
4036         and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value
4037         returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`.
4038             "#,
4039             &formats.binary,
4040         )
4041         .operands_in(vec![x, y])
4042         .operands_out(vec![a]),
4043     );
4044 
4045     ig.push(
4046         Inst::new(
4047             "uunarrow",
4048             r#"
4049         Combine `x` and `y` into a vector with twice the lanes but half the integer width while
4050         saturating overflowing values to the unsigned maximum and minimum.
4051 
4052         Note that all input lanes are considered unsigned.
4053 
4054         The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4`
4055         and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value
4056         returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`.
4057             "#,
4058             &formats.binary,
4059         )
4060         .operands_in(vec![x, y])
4061         .operands_out(vec![a]),
4062     );
4063 
4064     let I8or16or32xN = &TypeVar::new(
4065         "I8or16or32xN",
4066         "A SIMD vector type containing integer lanes 8, 16, or 32 bits wide.",
4067         TypeSetBuilder::new()
4068             .ints(8..32)
4069             .simd_lanes(4..16)
4070             .includes_scalars(false)
4071             .build(),
4072     );
4073 
4074     let x = &Operand::new("x", I8or16or32xN);
4075     let a = &Operand::new("a", &I8or16or32xN.merge_lanes());
4076 
4077     ig.push(
4078         Inst::new(
4079             "swiden_low",
4080             r#"
4081         Widen the low lanes of `x` using signed extension.
4082 
4083         This will double the lane width and halve the number of lanes.
4084             "#,
4085             &formats.unary,
4086         )
4087         .operands_in(vec![x])
4088         .operands_out(vec![a]),
4089     );
4090 
4091     ig.push(
4092         Inst::new(
4093             "swiden_high",
4094             r#"
4095         Widen the high lanes of `x` using signed extension.
4096 
4097         This will double the lane width and halve the number of lanes.
4098             "#,
4099             &formats.unary,
4100         )
4101         .operands_in(vec![x])
4102         .operands_out(vec![a]),
4103     );
4104 
4105     ig.push(
4106         Inst::new(
4107             "uwiden_low",
4108             r#"
4109         Widen the low lanes of `x` using unsigned extension.
4110 
4111         This will double the lane width and halve the number of lanes.
4112             "#,
4113             &formats.unary,
4114         )
4115         .operands_in(vec![x])
4116         .operands_out(vec![a]),
4117     );
4118 
4119     ig.push(
4120         Inst::new(
4121             "uwiden_high",
4122             r#"
4123             Widen the high lanes of `x` using unsigned extension.
4124 
4125             This will double the lane width and halve the number of lanes.
4126             "#,
4127             &formats.unary,
4128         )
4129         .operands_in(vec![x])
4130         .operands_out(vec![a]),
4131     );
4132 
4133     let x = &Operand::new("x", I8or16or32xN);
4134     let y = &Operand::new("y", I8or16or32xN);
4135     let a = &Operand::new("a", I8or16or32xN);
4136 
4137     ig.push(
4138         Inst::new(
4139             "iadd_pairwise",
4140             r#"
4141         Does lane-wise integer pairwise addition on two operands, putting the
4142         combined results into a single vector result. Here a pair refers to adjacent
4143         lanes in a vector, i.e. i*2 + (i*2+1) for i == num_lanes/2. The first operand
4144         pairwise add results will make up the low half of the resulting vector while
4145         the second operand pairwise add results will make up the upper half of the
4146         resulting vector.
4147             "#,
4148             &formats.binary,
4149         )
4150         .operands_in(vec![x, y])
4151         .operands_out(vec![a]),
4152     );
4153 
4154     let I16x8 = &TypeVar::new(
4155         "I16x8",
4156         "A SIMD vector type containing 8 integer lanes each 16 bits wide.",
4157         TypeSetBuilder::new()
4158             .ints(16..16)
4159             .simd_lanes(8..8)
4160             .includes_scalars(false)
4161             .build(),
4162     );
4163 
4164     let x = &Operand::new("x", I16x8);
4165     let y = &Operand::new("y", I16x8);
4166     let a = &Operand::new("a", &I16x8.merge_lanes());
4167 
4168     ig.push(
4169         Inst::new(
4170             "widening_pairwise_dot_product_s",
4171             r#"
4172         Takes corresponding elements in `x` and `y`, performs a sign-extending length-doubling
4173         multiplication on them, then adds adjacent pairs of elements to form the result.  For
4174         example, if the input vectors are `[x3, x2, x1, x0]` and `[y3, y2, y1, y0]`, it produces
4175         the vector `[r1, r0]`, where `r1 = sx(x3) * sx(y3) + sx(x2) * sx(y2)` and
4176         `r0 = sx(x1) * sx(y1) + sx(x0) * sx(y0)`, and `sx(n)` sign-extends `n` to twice its width.
4177 
4178         This will double the lane width and halve the number of lanes.  So the resulting
4179         vector has the same number of bits as `x` and `y` do (individually).
4180 
4181         See <https://github.com/WebAssembly/simd/pull/127> for background info.
4182             "#,
4183             &formats.binary,
4184         )
4185         .operands_in(vec![x, y])
4186         .operands_out(vec![a]),
4187     );
4188 
4189     let IntTo = &TypeVar::new(
4190         "IntTo",
4191         "A larger integer type with the same number of lanes",
4192         TypeSetBuilder::new()
4193             .ints(Interval::All)
4194             .simd_lanes(Interval::All)
4195             .build(),
4196     );
4197     let x = &Operand::new("x", Int);
4198     let a = &Operand::new("a", IntTo);
4199 
4200     ig.push(
4201         Inst::new(
4202             "uextend",
4203             r#"
4204         Convert `x` to a larger integer type by zero-extending.
4205 
4206         Each lane in `x` is converted to a larger integer type by adding
4207         zeroes. The result has the same numerical value as `x` when both are
4208         interpreted as unsigned integers.
4209 
4210         The result type must have the same number of vector lanes as the input,
4211         and each lane must not have fewer bits that the input lanes. If the
4212         input and output types are the same, this is a no-op.
4213         "#,
4214             &formats.unary,
4215         )
4216         .operands_in(vec![x])
4217         .operands_out(vec![a])
4218         .constraints(vec![WiderOrEq(IntTo.clone(), Int.clone())]),
4219     );
4220 
4221     ig.push(
4222         Inst::new(
4223             "sextend",
4224             r#"
4225         Convert `x` to a larger integer type by sign-extending.
4226 
4227         Each lane in `x` is converted to a larger integer type by replicating
4228         the sign bit. The result has the same numerical value as `x` when both
4229         are interpreted as signed integers.
4230 
4231         The result type must have the same number of vector lanes as the input,
4232         and each lane must not have fewer bits that the input lanes. If the
4233         input and output types are the same, this is a no-op.
4234         "#,
4235             &formats.unary,
4236         )
4237         .operands_in(vec![x])
4238         .operands_out(vec![a])
4239         .constraints(vec![WiderOrEq(IntTo.clone(), Int.clone())]),
4240     );
4241 
4242     let FloatTo = &TypeVar::new(
4243         "FloatTo",
4244         "A scalar or vector floating point number",
4245         TypeSetBuilder::new()
4246             .floats(Interval::All)
4247             .simd_lanes(Interval::All)
4248             .build(),
4249     );
4250     let x = &Operand::new("x", Float);
4251     let a = &Operand::new("a", FloatTo);
4252 
4253     ig.push(
4254         Inst::new(
4255             "fpromote",
4256             r#"
4257         Convert `x` to a larger floating point format.
4258 
4259         Each lane in `x` is converted to the destination floating point format.
4260         This is an exact operation.
4261 
4262         Cranelift currently only supports two floating point formats
4263         - `f32` and `f64`. This may change in the future.
4264 
4265         The result type must have the same number of vector lanes as the input,
4266         and the result lanes must not have fewer bits than the input lanes. If
4267         the input and output types are the same, this is a no-op.
4268         "#,
4269             &formats.unary,
4270         )
4271         .operands_in(vec![x])
4272         .operands_out(vec![a])
4273         .constraints(vec![WiderOrEq(FloatTo.clone(), Float.clone())]),
4274     );
4275 
4276     ig.push(
4277         Inst::new(
4278             "fdemote",
4279             r#"
4280         Convert `x` to a smaller floating point format.
4281 
4282         Each lane in `x` is converted to the destination floating point format
4283         by rounding to nearest, ties to even.
4284 
4285         Cranelift currently only supports two floating point formats
4286         - `f32` and `f64`. This may change in the future.
4287 
4288         The result type must have the same number of vector lanes as the input,
4289         and the result lanes must not have more bits than the input lanes. If
4290         the input and output types are the same, this is a no-op.
4291         "#,
4292             &formats.unary,
4293         )
4294         .operands_in(vec![x])
4295         .operands_out(vec![a])
4296         .constraints(vec![WiderOrEq(Float.clone(), FloatTo.clone())]),
4297     );
4298 
4299     let F64x2 = &TypeVar::new(
4300         "F64x2",
4301         "A SIMD vector type consisting of 2 lanes of 64-bit floats",
4302         TypeSetBuilder::new()
4303             .floats(64..64)
4304             .simd_lanes(2..2)
4305             .includes_scalars(false)
4306             .build(),
4307     );
4308     let F32x4 = &TypeVar::new(
4309         "F32x4",
4310         "A SIMD vector type consisting of 4 lanes of 32-bit floats",
4311         TypeSetBuilder::new()
4312             .floats(32..32)
4313             .simd_lanes(4..4)
4314             .includes_scalars(false)
4315             .build(),
4316     );
4317 
4318     let x = &Operand::new("x", F64x2);
4319     let a = &Operand::new("a", F32x4);
4320 
4321     ig.push(
4322         Inst::new(
4323             "fvdemote",
4324             r#"
4325                 Convert `x` to a smaller floating point format.
4326 
4327                 Each lane in `x` is converted to the destination floating point format
4328                 by rounding to nearest, ties to even.
4329 
4330                 Cranelift currently only supports two floating point formats
4331                 - `f32` and `f64`. This may change in the future.
4332 
4333                 Fvdemote differs from fdemote in that with fvdemote it targets vectors.
4334                 Fvdemote is constrained to having the input type being F64x2 and the result
4335                 type being F32x4. The result lane that was the upper half of the input lane
4336                 is initialized to zero.
4337                 "#,
4338             &formats.unary,
4339         )
4340         .operands_in(vec![x])
4341         .operands_out(vec![a]),
4342     );
4343 
4344     ig.push(
4345         Inst::new(
4346             "fvpromote_low",
4347             r#"
4348         Converts packed single precision floating point to packed double precision floating point.
4349 
4350         Considering only the lower half of the register, the low lanes in `x` are interpreted as
4351         single precision floats that are then converted to a double precision floats.
4352 
4353         The result type will have half the number of vector lanes as the input. Fvpromote_low is
4354         constrained to input F32x4 with a result type of F64x2.
4355         "#,
4356             &formats.unary,
4357         )
4358         .operands_in(vec![a])
4359         .operands_out(vec![x]),
4360     );
4361 
4362     let x = &Operand::new("x", Float);
4363     let a = &Operand::new("a", IntTo);
4364 
4365     ig.push(
4366         Inst::new(
4367             "fcvt_to_uint",
4368             r#"
4369         Convert floating point to unsigned integer.
4370 
4371         Each lane in `x` is converted to an unsigned integer by rounding
4372         towards zero. If `x` is NaN or if the unsigned integral value cannot be
4373         represented in the result type, this instruction traps.
4374 
4375         The result type must have the same number of vector lanes as the input.
4376         "#,
4377             &formats.unary,
4378         )
4379         .operands_in(vec![x])
4380         .operands_out(vec![a])
4381         .can_trap(true),
4382     );
4383 
4384     ig.push(
4385         Inst::new(
4386             "fcvt_to_uint_sat",
4387             r#"
4388         Convert floating point to unsigned integer as fcvt_to_uint does, but
4389         saturates the input instead of trapping. NaN and negative values are
4390         converted to 0.
4391         "#,
4392             &formats.unary,
4393         )
4394         .operands_in(vec![x])
4395         .operands_out(vec![a]),
4396     );
4397 
4398     ig.push(
4399         Inst::new(
4400             "fcvt_to_sint",
4401             r#"
4402         Convert floating point to signed integer.
4403 
4404         Each lane in `x` is converted to a signed integer by rounding towards
4405         zero. If `x` is NaN or if the signed integral value cannot be
4406         represented in the result type, this instruction traps.
4407 
4408         The result type must have the same number of vector lanes as the input.
4409         "#,
4410             &formats.unary,
4411         )
4412         .operands_in(vec![x])
4413         .operands_out(vec![a])
4414         .can_trap(true),
4415     );
4416 
4417     ig.push(
4418         Inst::new(
4419             "fcvt_to_sint_sat",
4420             r#"
4421         Convert floating point to signed integer as fcvt_to_sint does, but
4422         saturates the input instead of trapping. NaN values are converted to 0.
4423         "#,
4424             &formats.unary,
4425         )
4426         .operands_in(vec![x])
4427         .operands_out(vec![a]),
4428     );
4429 
4430     let x = &Operand::new("x", Int);
4431     let a = &Operand::new("a", FloatTo);
4432 
4433     ig.push(
4434         Inst::new(
4435             "fcvt_from_uint",
4436             r#"
4437         Convert unsigned integer to floating point.
4438 
4439         Each lane in `x` is interpreted as an unsigned integer and converted to
4440         floating point using round to nearest, ties to even.
4441 
4442         The result type must have the same number of vector lanes as the input.
4443         "#,
4444             &formats.unary,
4445         )
4446         .operands_in(vec![x])
4447         .operands_out(vec![a]),
4448     );
4449 
4450     ig.push(
4451         Inst::new(
4452             "fcvt_from_sint",
4453             r#"
4454         Convert signed integer to floating point.
4455 
4456         Each lane in `x` is interpreted as a signed integer and converted to
4457         floating point using round to nearest, ties to even.
4458 
4459         The result type must have the same number of vector lanes as the input.
4460         "#,
4461             &formats.unary,
4462         )
4463         .operands_in(vec![x])
4464         .operands_out(vec![a]),
4465     );
4466 
4467     ig.push(
4468         Inst::new(
4469             "fcvt_low_from_sint",
4470             r#"
4471         Converts packed signed 32-bit integers to packed double precision floating point.
4472 
4473         Considering only the low half of the register, each lane in `x` is interpreted as a
4474         signed 32-bit integer that is then converted to a double precision float. This
4475         instruction differs from fcvt_from_sint in that it converts half the number of lanes
4476         which are converted to occupy twice the number of bits. No rounding should be needed
4477         for the resulting float.
4478 
4479         The result type will have half the number of vector lanes as the input.
4480         "#,
4481             &formats.unary,
4482         )
4483         .operands_in(vec![x])
4484         .operands_out(vec![a]),
4485     );
4486 
4487     let WideInt = &TypeVar::new(
4488         "WideInt",
4489         "An integer type with lanes from `i16` upwards",
4490         TypeSetBuilder::new()
4491             .ints(16..128)
4492             .simd_lanes(Interval::All)
4493             .build(),
4494     );
4495     let x = &Operand::new("x", WideInt);
4496     let lo = &Operand::new("lo", &WideInt.half_width()).with_doc("The low bits of `x`");
4497     let hi = &Operand::new("hi", &WideInt.half_width()).with_doc("The high bits of `x`");
4498 
4499     ig.push(
4500         Inst::new(
4501             "isplit",
4502             r#"
4503         Split an integer into low and high parts.
4504 
4505         Vectors of integers are split lane-wise, so the results have the same
4506         number of lanes as the input, but the lanes are half the size.
4507 
4508         Returns the low half of `x` and the high half of `x` as two independent
4509         values.
4510         "#,
4511             &formats.unary,
4512         )
4513         .operands_in(vec![x])
4514         .operands_out(vec![lo, hi])
4515         .is_ghost(true),
4516     );
4517 
4518     let NarrowInt = &TypeVar::new(
4519         "NarrowInt",
4520         "An integer type with lanes type to `i64`",
4521         TypeSetBuilder::new()
4522             .ints(8..64)
4523             .simd_lanes(Interval::All)
4524             .build(),
4525     );
4526 
4527     let lo = &Operand::new("lo", NarrowInt);
4528     let hi = &Operand::new("hi", NarrowInt);
4529     let a = &Operand::new("a", &NarrowInt.double_width())
4530         .with_doc("The concatenation of `lo` and `hi`");
4531 
4532     ig.push(
4533         Inst::new(
4534             "iconcat",
4535             r#"
4536         Concatenate low and high bits to form a larger integer type.
4537 
4538         Vectors of integers are concatenated lane-wise such that the result has
4539         the same number of lanes as the inputs, but the lanes are twice the
4540         size.
4541         "#,
4542             &formats.binary,
4543         )
4544         .operands_in(vec![lo, hi])
4545         .operands_out(vec![a])
4546         .is_ghost(true),
4547     );
4548 
4549     // Instructions relating to atomic memory accesses and fences
4550     let AtomicMem = &TypeVar::new(
4551         "AtomicMem",
4552         "Any type that can be stored in memory, which can be used in an atomic operation",
4553         TypeSetBuilder::new().ints(8..64).build(),
4554     );
4555     let x = &Operand::new("x", AtomicMem).with_doc("Value to be atomically stored");
4556     let a = &Operand::new("a", AtomicMem).with_doc("Value atomically loaded");
4557     let e = &Operand::new("e", AtomicMem).with_doc("Expected value in CAS");
4558     let p = &Operand::new("p", iAddr);
4559     let MemFlags = &Operand::new("MemFlags", &imm.memflags);
4560     let AtomicRmwOp = &Operand::new("AtomicRmwOp", &imm.atomic_rmw_op);
4561 
4562     ig.push(
4563         Inst::new(
4564             "atomic_rmw",
4565             r#"
4566         Atomically read-modify-write memory at `p`, with second operand `x`.  The old value is
4567         returned.  `p` has the type of the target word size, and `x` may be an integer type of
4568         8, 16, 32 or 64 bits, even on a 32-bit target.  The type of the returned value is the
4569         same as the type of `x`.  This operation is sequentially consistent and creates
4570         happens-before edges that order normal (non-atomic) loads and stores.
4571         "#,
4572             &formats.atomic_rmw,
4573         )
4574         .operands_in(vec![MemFlags, AtomicRmwOp, p, x])
4575         .operands_out(vec![a])
4576         .can_load(true)
4577         .can_store(true)
4578         .other_side_effects(true),
4579     );
4580 
4581     ig.push(
4582         Inst::new(
4583             "atomic_cas",
4584             r#"
4585         Perform an atomic compare-and-swap operation on memory at `p`, with expected value `e`,
4586         storing `x` if the value at `p` equals `e`.  The old value at `p` is returned,
4587         regardless of whether the operation succeeds or fails.  `p` has the type of the target
4588         word size, and `x` and `e` must have the same type and the same size, which may be an
4589         integer type of 8, 16, 32 or 64 bits, even on a 32-bit target.  The type of the returned
4590         value is the same as the type of `x` and `e`.  This operation is sequentially
4591         consistent and creates happens-before edges that order normal (non-atomic) loads and
4592         stores.
4593         "#,
4594             &formats.atomic_cas,
4595         )
4596         .operands_in(vec![MemFlags, p, e, x])
4597         .operands_out(vec![a])
4598         .can_load(true)
4599         .can_store(true)
4600         .other_side_effects(true),
4601     );
4602 
4603     ig.push(
4604         Inst::new(
4605             "atomic_load",
4606             r#"
4607         Atomically load from memory at `p`.
4608 
4609         This is a polymorphic instruction that can load any value type which has a memory
4610         representation.  It should only be used for integer types with 8, 16, 32 or 64 bits.
4611         This operation is sequentially consistent and creates happens-before edges that order
4612         normal (non-atomic) loads and stores.
4613         "#,
4614             &formats.load_no_offset,
4615         )
4616         .operands_in(vec![MemFlags, p])
4617         .operands_out(vec![a])
4618         .can_load(true)
4619         .other_side_effects(true),
4620     );
4621 
4622     ig.push(
4623         Inst::new(
4624             "atomic_store",
4625             r#"
4626         Atomically store `x` to memory at `p`.
4627 
4628         This is a polymorphic instruction that can store any value type with a memory
4629         representation.  It should only be used for integer types with 8, 16, 32 or 64 bits.
4630         This operation is sequentially consistent and creates happens-before edges that order
4631         normal (non-atomic) loads and stores.
4632         "#,
4633             &formats.store_no_offset,
4634         )
4635         .operands_in(vec![MemFlags, x, p])
4636         .can_store(true)
4637         .other_side_effects(true),
4638     );
4639 
4640     ig.push(
4641         Inst::new(
4642             "fence",
4643             r#"
4644         A memory fence.  This must provide ordering to ensure that, at a minimum, neither loads
4645         nor stores of any kind may move forwards or backwards across the fence.  This operation
4646         is sequentially consistent.
4647         "#,
4648             &formats.nullary,
4649         )
4650         .other_side_effects(true),
4651     );
4652 
4653     ig.build()
4654 }
4655