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     ig.push(
2483         Inst::new(
2484             "udiv",
2485             r#"
2486         Unsigned integer division: `a := \lfloor {x \over y} \rfloor`.
2487 
2488         This operation traps if the divisor is zero.
2489         "#,
2490             &formats.binary,
2491         )
2492         .operands_in(vec![x, y])
2493         .operands_out(vec![a])
2494         .can_trap(true),
2495     );
2496 
2497     ig.push(
2498         Inst::new(
2499             "sdiv",
2500             r#"
2501         Signed integer division rounded toward zero: `a := sign(xy)
2502         \lfloor {|x| \over |y|}\rfloor`.
2503 
2504         This operation traps if the divisor is zero, or if the result is not
2505         representable in `B` bits two's complement. This only happens
2506         when `x = -2^{B-1}, y = -1`.
2507         "#,
2508             &formats.binary,
2509         )
2510         .operands_in(vec![x, y])
2511         .operands_out(vec![a])
2512         .can_trap(true),
2513     );
2514 
2515     ig.push(
2516         Inst::new(
2517             "urem",
2518             r#"
2519         Unsigned integer remainder.
2520 
2521         This operation traps if the divisor is zero.
2522         "#,
2523             &formats.binary,
2524         )
2525         .operands_in(vec![x, y])
2526         .operands_out(vec![a])
2527         .can_trap(true),
2528     );
2529 
2530     ig.push(
2531         Inst::new(
2532             "srem",
2533             r#"
2534         Signed integer remainder. The result has the sign of the dividend.
2535 
2536         This operation traps if the divisor is zero.
2537         "#,
2538             &formats.binary,
2539         )
2540         .operands_in(vec![x, y])
2541         .operands_out(vec![a])
2542         .can_trap(true),
2543     );
2544 
2545     let a = &Operand::new("a", iB);
2546     let x = &Operand::new("x", iB);
2547     let Y = &Operand::new("Y", &imm.imm64);
2548 
2549     ig.push(
2550         Inst::new(
2551             "iadd_imm",
2552             r#"
2553         Add immediate integer.
2554 
2555         Same as `iadd`, but one operand is an immediate constant.
2556 
2557         Polymorphic over all scalar integer types, but does not support vector
2558         types.
2559         "#,
2560             &formats.binary_imm64,
2561         )
2562         .operands_in(vec![x, Y])
2563         .operands_out(vec![a]),
2564     );
2565 
2566     ig.push(
2567         Inst::new(
2568             "imul_imm",
2569             r#"
2570         Integer multiplication by immediate constant.
2571 
2572         Polymorphic over all scalar integer types, but does not support vector
2573         types.
2574         "#,
2575             &formats.binary_imm64,
2576         )
2577         .operands_in(vec![x, Y])
2578         .operands_out(vec![a]),
2579     );
2580 
2581     ig.push(
2582         Inst::new(
2583             "udiv_imm",
2584             r#"
2585         Unsigned integer division by an immediate constant.
2586 
2587         This operation traps if the divisor is zero.
2588         "#,
2589             &formats.binary_imm64,
2590         )
2591         .operands_in(vec![x, Y])
2592         .operands_out(vec![a]),
2593     );
2594 
2595     ig.push(
2596         Inst::new(
2597             "sdiv_imm",
2598             r#"
2599         Signed integer division by an immediate constant.
2600 
2601         This operation traps if the divisor is zero, or if the result is not
2602         representable in `B` bits two's complement. This only happens
2603         when `x = -2^{B-1}, Y = -1`.
2604         "#,
2605             &formats.binary_imm64,
2606         )
2607         .operands_in(vec![x, Y])
2608         .operands_out(vec![a]),
2609     );
2610 
2611     ig.push(
2612         Inst::new(
2613             "urem_imm",
2614             r#"
2615         Unsigned integer remainder with immediate divisor.
2616 
2617         This operation traps if the divisor is zero.
2618         "#,
2619             &formats.binary_imm64,
2620         )
2621         .operands_in(vec![x, Y])
2622         .operands_out(vec![a]),
2623     );
2624 
2625     ig.push(
2626         Inst::new(
2627             "srem_imm",
2628             r#"
2629         Signed integer remainder with immediate divisor.
2630 
2631         This operation traps if the divisor is zero.
2632         "#,
2633             &formats.binary_imm64,
2634         )
2635         .operands_in(vec![x, Y])
2636         .operands_out(vec![a]),
2637     );
2638 
2639     ig.push(
2640         Inst::new(
2641             "irsub_imm",
2642             r#"
2643         Immediate reverse wrapping subtraction: `a := Y - x \pmod{2^B}`.
2644 
2645         Also works as integer negation when `Y = 0`. Use `iadd_imm`
2646         with a negative immediate operand for the reverse immediate
2647         subtraction.
2648 
2649         Polymorphic over all scalar integer types, but does not support vector
2650         types.
2651         "#,
2652             &formats.binary_imm64,
2653         )
2654         .operands_in(vec![x, Y])
2655         .operands_out(vec![a]),
2656     );
2657 
2658     let a = &Operand::new("a", iB);
2659     let x = &Operand::new("x", iB);
2660     let y = &Operand::new("y", iB);
2661 
2662     let c_in = &Operand::new("c_in", b1).with_doc("Input carry flag");
2663     let c_out = &Operand::new("c_out", b1).with_doc("Output carry flag");
2664     let b_in = &Operand::new("b_in", b1).with_doc("Input borrow flag");
2665     let b_out = &Operand::new("b_out", b1).with_doc("Output borrow flag");
2666 
2667     let c_if_in = &Operand::new("c_in", iflags);
2668     let c_if_out = &Operand::new("c_out", iflags);
2669     let b_if_in = &Operand::new("b_in", iflags);
2670     let b_if_out = &Operand::new("b_out", iflags);
2671 
2672     ig.push(
2673         Inst::new(
2674             "iadd_cin",
2675             r#"
2676         Add integers with carry in.
2677 
2678         Same as `iadd` with an additional carry input. Computes:
2679 
2680         ```text
2681             a = x + y + c_{in} \pmod 2^B
2682         ```
2683 
2684         Polymorphic over all scalar integer types, but does not support vector
2685         types.
2686         "#,
2687             &formats.ternary,
2688         )
2689         .operands_in(vec![x, y, c_in])
2690         .operands_out(vec![a]),
2691     );
2692 
2693     ig.push(
2694         Inst::new(
2695             "iadd_ifcin",
2696             r#"
2697         Add integers with carry in.
2698 
2699         Same as `iadd` with an additional carry flag input. Computes:
2700 
2701         ```text
2702             a = x + y + c_{in} \pmod 2^B
2703         ```
2704 
2705         Polymorphic over all scalar integer types, but does not support vector
2706         types.
2707         "#,
2708             &formats.ternary,
2709         )
2710         .operands_in(vec![x, y, c_if_in])
2711         .operands_out(vec![a]),
2712     );
2713 
2714     ig.push(
2715         Inst::new(
2716             "iadd_cout",
2717             r#"
2718         Add integers with carry out.
2719 
2720         Same as `iadd` with an additional carry output.
2721 
2722         ```text
2723             a &= x + y \pmod 2^B \\
2724             c_{out} &= x+y >= 2^B
2725         ```
2726 
2727         Polymorphic over all scalar integer types, but does not support vector
2728         types.
2729         "#,
2730             &formats.binary,
2731         )
2732         .operands_in(vec![x, y])
2733         .operands_out(vec![a, c_out]),
2734     );
2735 
2736     ig.push(
2737         Inst::new(
2738             "iadd_ifcout",
2739             r#"
2740         Add integers with carry out.
2741 
2742         Same as `iadd` with an additional carry flag output.
2743 
2744         ```text
2745             a &= x + y \pmod 2^B \\
2746             c_{out} &= x+y >= 2^B
2747         ```
2748 
2749         Polymorphic over all scalar integer types, but does not support vector
2750         types.
2751         "#,
2752             &formats.binary,
2753         )
2754         .operands_in(vec![x, y])
2755         .operands_out(vec![a, c_if_out]),
2756     );
2757 
2758     ig.push(
2759         Inst::new(
2760             "iadd_carry",
2761             r#"
2762         Add integers with carry in and out.
2763 
2764         Same as `iadd` with an additional carry input and output.
2765 
2766         ```text
2767             a &= x + y + c_{in} \pmod 2^B \\
2768             c_{out} &= x + y + c_{in} >= 2^B
2769         ```
2770 
2771         Polymorphic over all scalar integer types, but does not support vector
2772         types.
2773         "#,
2774             &formats.ternary,
2775         )
2776         .operands_in(vec![x, y, c_in])
2777         .operands_out(vec![a, c_out]),
2778     );
2779 
2780     ig.push(
2781         Inst::new(
2782             "iadd_ifcarry",
2783             r#"
2784         Add integers with carry in and out.
2785 
2786         Same as `iadd` with an additional carry flag input and output.
2787 
2788         ```text
2789             a &= x + y + c_{in} \pmod 2^B \\
2790             c_{out} &= x + y + c_{in} >= 2^B
2791         ```
2792 
2793         Polymorphic over all scalar integer types, but does not support vector
2794         types.
2795         "#,
2796             &formats.ternary,
2797         )
2798         .operands_in(vec![x, y, c_if_in])
2799         .operands_out(vec![a, c_if_out]),
2800     );
2801 
2802     ig.push(
2803         Inst::new(
2804             "isub_bin",
2805             r#"
2806         Subtract integers with borrow in.
2807 
2808         Same as `isub` with an additional borrow flag input. Computes:
2809 
2810         ```text
2811             a = x - (y + b_{in}) \pmod 2^B
2812         ```
2813 
2814         Polymorphic over all scalar integer types, but does not support vector
2815         types.
2816         "#,
2817             &formats.ternary,
2818         )
2819         .operands_in(vec![x, y, b_in])
2820         .operands_out(vec![a]),
2821     );
2822 
2823     ig.push(
2824         Inst::new(
2825             "isub_ifbin",
2826             r#"
2827         Subtract integers with borrow in.
2828 
2829         Same as `isub` with an additional borrow flag input. Computes:
2830 
2831         ```text
2832             a = x - (y + b_{in}) \pmod 2^B
2833         ```
2834 
2835         Polymorphic over all scalar integer types, but does not support vector
2836         types.
2837         "#,
2838             &formats.ternary,
2839         )
2840         .operands_in(vec![x, y, b_if_in])
2841         .operands_out(vec![a]),
2842     );
2843 
2844     ig.push(
2845         Inst::new(
2846             "isub_bout",
2847             r#"
2848         Subtract integers with borrow out.
2849 
2850         Same as `isub` with an additional borrow flag output.
2851 
2852         ```text
2853             a &= x - y \pmod 2^B \\
2854             b_{out} &= x < y
2855         ```
2856 
2857         Polymorphic over all scalar integer types, but does not support vector
2858         types.
2859         "#,
2860             &formats.binary,
2861         )
2862         .operands_in(vec![x, y])
2863         .operands_out(vec![a, b_out]),
2864     );
2865 
2866     ig.push(
2867         Inst::new(
2868             "isub_ifbout",
2869             r#"
2870         Subtract integers with borrow out.
2871 
2872         Same as `isub` with an additional borrow flag output.
2873 
2874         ```text
2875             a &= x - y \pmod 2^B \\
2876             b_{out} &= x < y
2877         ```
2878 
2879         Polymorphic over all scalar integer types, but does not support vector
2880         types.
2881         "#,
2882             &formats.binary,
2883         )
2884         .operands_in(vec![x, y])
2885         .operands_out(vec![a, b_if_out]),
2886     );
2887 
2888     ig.push(
2889         Inst::new(
2890             "isub_borrow",
2891             r#"
2892         Subtract integers with borrow in and out.
2893 
2894         Same as `isub` with an additional borrow flag input and output.
2895 
2896         ```text
2897             a &= x - (y + b_{in}) \pmod 2^B \\
2898             b_{out} &= x < y + b_{in}
2899         ```
2900 
2901         Polymorphic over all scalar integer types, but does not support vector
2902         types.
2903         "#,
2904             &formats.ternary,
2905         )
2906         .operands_in(vec![x, y, b_in])
2907         .operands_out(vec![a, b_out]),
2908     );
2909 
2910     ig.push(
2911         Inst::new(
2912             "isub_ifborrow",
2913             r#"
2914         Subtract integers with borrow in and out.
2915 
2916         Same as `isub` with an additional borrow flag input and output.
2917 
2918         ```text
2919             a &= x - (y + b_{in}) \pmod 2^B \\
2920             b_{out} &= x < y + b_{in}
2921         ```
2922 
2923         Polymorphic over all scalar integer types, but does not support vector
2924         types.
2925         "#,
2926             &formats.ternary,
2927         )
2928         .operands_in(vec![x, y, b_if_in])
2929         .operands_out(vec![a, b_if_out]),
2930     );
2931 
2932     let bits = &TypeVar::new(
2933         "bits",
2934         "Any integer, float, or boolean scalar or vector type",
2935         TypeSetBuilder::new()
2936             .ints(Interval::All)
2937             .floats(Interval::All)
2938             .bools(Interval::All)
2939             .simd_lanes(Interval::All)
2940             .includes_scalars(true)
2941             .build(),
2942     );
2943     let x = &Operand::new("x", bits);
2944     let y = &Operand::new("y", bits);
2945     let a = &Operand::new("a", bits);
2946 
2947     ig.push(
2948         Inst::new(
2949             "band",
2950             r#"
2951         Bitwise and.
2952         "#,
2953             &formats.binary,
2954         )
2955         .operands_in(vec![x, y])
2956         .operands_out(vec![a]),
2957     );
2958 
2959     ig.push(
2960         Inst::new(
2961             "bor",
2962             r#"
2963         Bitwise or.
2964         "#,
2965             &formats.binary,
2966         )
2967         .operands_in(vec![x, y])
2968         .operands_out(vec![a]),
2969     );
2970 
2971     ig.push(
2972         Inst::new(
2973             "bxor",
2974             r#"
2975         Bitwise xor.
2976         "#,
2977             &formats.binary,
2978         )
2979         .operands_in(vec![x, y])
2980         .operands_out(vec![a]),
2981     );
2982 
2983     ig.push(
2984         Inst::new(
2985             "bnot",
2986             r#"
2987         Bitwise not.
2988         "#,
2989             &formats.unary,
2990         )
2991         .operands_in(vec![x])
2992         .operands_out(vec![a]),
2993     );
2994 
2995     ig.push(
2996         Inst::new(
2997             "band_not",
2998             r#"
2999         Bitwise and not.
3000 
3001         Computes `x & ~y`.
3002         "#,
3003             &formats.binary,
3004         )
3005         .operands_in(vec![x, y])
3006         .operands_out(vec![a]),
3007     );
3008 
3009     ig.push(
3010         Inst::new(
3011             "bor_not",
3012             r#"
3013         Bitwise or not.
3014 
3015         Computes `x | ~y`.
3016         "#,
3017             &formats.binary,
3018         )
3019         .operands_in(vec![x, y])
3020         .operands_out(vec![a]),
3021     );
3022 
3023     ig.push(
3024         Inst::new(
3025             "bxor_not",
3026             r#"
3027         Bitwise xor not.
3028 
3029         Computes `x ^ ~y`.
3030         "#,
3031             &formats.binary,
3032         )
3033         .operands_in(vec![x, y])
3034         .operands_out(vec![a]),
3035     );
3036 
3037     let x = &Operand::new("x", iB);
3038     let Y = &Operand::new("Y", &imm.imm64);
3039     let a = &Operand::new("a", iB);
3040 
3041     ig.push(
3042         Inst::new(
3043             "band_imm",
3044             r#"
3045         Bitwise and with immediate.
3046 
3047         Same as `band`, but one operand is an immediate constant.
3048 
3049         Polymorphic over all scalar integer types, but does not support vector
3050         types.
3051         "#,
3052             &formats.binary_imm64,
3053         )
3054         .operands_in(vec![x, Y])
3055         .operands_out(vec![a]),
3056     );
3057 
3058     ig.push(
3059         Inst::new(
3060             "bor_imm",
3061             r#"
3062         Bitwise or with immediate.
3063 
3064         Same as `bor`, but one operand is an immediate constant.
3065 
3066         Polymorphic over all scalar integer types, but does not support vector
3067         types.
3068         "#,
3069             &formats.binary_imm64,
3070         )
3071         .operands_in(vec![x, Y])
3072         .operands_out(vec![a]),
3073     );
3074 
3075     ig.push(
3076         Inst::new(
3077             "bxor_imm",
3078             r#"
3079         Bitwise xor with immediate.
3080 
3081         Same as `bxor`, but one operand is an immediate constant.
3082 
3083         Polymorphic over all scalar integer types, but does not support vector
3084         types.
3085         "#,
3086             &formats.binary_imm64,
3087         )
3088         .operands_in(vec![x, Y])
3089         .operands_out(vec![a]),
3090     );
3091 
3092     let x = &Operand::new("x", Int).with_doc("Scalar or vector value to shift");
3093     let y = &Operand::new("y", iB).with_doc("Number of bits to shift");
3094     let Y = &Operand::new("Y", &imm.imm64);
3095     let a = &Operand::new("a", Int);
3096 
3097     ig.push(
3098         Inst::new(
3099             "rotl",
3100             r#"
3101         Rotate left.
3102 
3103         Rotate the bits in ``x`` by ``y`` places.
3104         "#,
3105             &formats.binary,
3106         )
3107         .operands_in(vec![x, y])
3108         .operands_out(vec![a]),
3109     );
3110 
3111     ig.push(
3112         Inst::new(
3113             "rotr",
3114             r#"
3115         Rotate right.
3116 
3117         Rotate the bits in ``x`` by ``y`` places.
3118         "#,
3119             &formats.binary,
3120         )
3121         .operands_in(vec![x, y])
3122         .operands_out(vec![a]),
3123     );
3124 
3125     ig.push(
3126         Inst::new(
3127             "rotl_imm",
3128             r#"
3129         Rotate left by immediate.
3130         "#,
3131             &formats.binary_imm64,
3132         )
3133         .operands_in(vec![x, Y])
3134         .operands_out(vec![a]),
3135     );
3136 
3137     ig.push(
3138         Inst::new(
3139             "rotr_imm",
3140             r#"
3141         Rotate right by immediate.
3142         "#,
3143             &formats.binary_imm64,
3144         )
3145         .operands_in(vec![x, Y])
3146         .operands_out(vec![a]),
3147     );
3148 
3149     ig.push(
3150         Inst::new(
3151             "ishl",
3152             r#"
3153         Integer shift left. Shift the bits in ``x`` towards the MSB by ``y``
3154         places. Shift in zero bits to the LSB.
3155 
3156         The shift amount is masked to the size of ``x``.
3157 
3158         When shifting a B-bits integer type, this instruction computes:
3159 
3160         ```text
3161             s &:= y \pmod B,
3162             a &:= x \cdot 2^s \pmod{2^B}.
3163         ```
3164         "#,
3165             &formats.binary,
3166         )
3167         .operands_in(vec![x, y])
3168         .operands_out(vec![a]),
3169     );
3170 
3171     ig.push(
3172         Inst::new(
3173             "ushr",
3174             r#"
3175         Unsigned shift right. Shift bits in ``x`` towards the LSB by ``y``
3176         places, shifting in zero bits to the MSB. Also called a *logical
3177         shift*.
3178 
3179         The shift amount is masked to the size of the register.
3180 
3181         When shifting a B-bits integer type, this instruction computes:
3182 
3183         ```text
3184             s &:= y \pmod B,
3185             a &:= \lfloor x \cdot 2^{-s} \rfloor.
3186         ```
3187         "#,
3188             &formats.binary,
3189         )
3190         .operands_in(vec![x, y])
3191         .operands_out(vec![a]),
3192     );
3193 
3194     ig.push(
3195         Inst::new(
3196             "sshr",
3197             r#"
3198         Signed shift right. Shift bits in ``x`` towards the LSB by ``y``
3199         places, shifting in sign bits to the MSB. Also called an *arithmetic
3200         shift*.
3201 
3202         The shift amount is masked to the size of the register.
3203         "#,
3204             &formats.binary,
3205         )
3206         .operands_in(vec![x, y])
3207         .operands_out(vec![a]),
3208     );
3209 
3210     ig.push(
3211         Inst::new(
3212             "ishl_imm",
3213             r#"
3214         Integer shift left by immediate.
3215 
3216         The shift amount is masked to the size of ``x``.
3217         "#,
3218             &formats.binary_imm64,
3219         )
3220         .operands_in(vec![x, Y])
3221         .operands_out(vec![a]),
3222     );
3223 
3224     ig.push(
3225         Inst::new(
3226             "ushr_imm",
3227             r#"
3228         Unsigned shift right by immediate.
3229 
3230         The shift amount is masked to the size of the register.
3231         "#,
3232             &formats.binary_imm64,
3233         )
3234         .operands_in(vec![x, Y])
3235         .operands_out(vec![a]),
3236     );
3237 
3238     ig.push(
3239         Inst::new(
3240             "sshr_imm",
3241             r#"
3242         Signed shift right by immediate.
3243 
3244         The shift amount is masked to the size of the register.
3245         "#,
3246             &formats.binary_imm64,
3247         )
3248         .operands_in(vec![x, Y])
3249         .operands_out(vec![a]),
3250     );
3251 
3252     let x = &Operand::new("x", iB);
3253     let a = &Operand::new("a", iB);
3254 
3255     ig.push(
3256         Inst::new(
3257             "bitrev",
3258             r#"
3259         Reverse the bits of a integer.
3260 
3261         Reverses the bits in ``x``.
3262         "#,
3263             &formats.unary,
3264         )
3265         .operands_in(vec![x])
3266         .operands_out(vec![a]),
3267     );
3268 
3269     ig.push(
3270         Inst::new(
3271             "clz",
3272             r#"
3273         Count leading zero bits.
3274 
3275         Starting from the MSB in ``x``, count the number of zero bits before
3276         reaching the first one bit. When ``x`` is zero, returns the size of x
3277         in bits.
3278         "#,
3279             &formats.unary,
3280         )
3281         .operands_in(vec![x])
3282         .operands_out(vec![a]),
3283     );
3284 
3285     ig.push(
3286         Inst::new(
3287             "cls",
3288             r#"
3289         Count leading sign bits.
3290 
3291         Starting from the MSB after the sign bit in ``x``, count the number of
3292         consecutive bits identical to the sign bit. When ``x`` is 0 or -1,
3293         returns one less than the size of x in bits.
3294         "#,
3295             &formats.unary,
3296         )
3297         .operands_in(vec![x])
3298         .operands_out(vec![a]),
3299     );
3300 
3301     ig.push(
3302         Inst::new(
3303             "ctz",
3304             r#"
3305         Count trailing zeros.
3306 
3307         Starting from the LSB in ``x``, count the number of zero bits before
3308         reaching the first one bit. When ``x`` is zero, returns the size of x
3309         in bits.
3310         "#,
3311             &formats.unary,
3312         )
3313         .operands_in(vec![x])
3314         .operands_out(vec![a]),
3315     );
3316 
3317     ig.push(
3318         Inst::new(
3319             "popcnt",
3320             r#"
3321         Population count
3322 
3323         Count the number of one bits in ``x``.
3324         "#,
3325             &formats.unary,
3326         )
3327         .operands_in(vec![x])
3328         .operands_out(vec![a]),
3329     );
3330 
3331     let Float = &TypeVar::new(
3332         "Float",
3333         "A scalar or vector floating point number",
3334         TypeSetBuilder::new()
3335             .floats(Interval::All)
3336             .simd_lanes(Interval::All)
3337             .build(),
3338     );
3339     let Cond = &Operand::new("Cond", &imm.floatcc);
3340     let x = &Operand::new("x", Float);
3341     let y = &Operand::new("y", Float);
3342     let a = &Operand::new("a", &Float.as_bool());
3343 
3344     ig.push(
3345         Inst::new(
3346             "fcmp",
3347             r#"
3348         Floating point comparison.
3349 
3350         Two IEEE 754-2008 floating point numbers, `x` and `y`, relate to each
3351         other in exactly one of four ways:
3352 
3353         == ==========================================
3354         UN Unordered when one or both numbers is NaN.
3355         EQ When `x = y`. (And `0.0 = -0.0`).
3356         LT When `x < y`.
3357         GT When `x > y`.
3358         == ==========================================
3359 
3360         The 14 `floatcc` condition codes each correspond to a subset of
3361         the four relations, except for the empty set which would always be
3362         false, and the full set which would always be true.
3363 
3364         The condition codes are divided into 7 'ordered' conditions which don't
3365         include UN, and 7 unordered conditions which all include UN.
3366 
3367         +-------+------------+---------+------------+-------------------------+
3368         |Ordered             |Unordered             |Condition                |
3369         +=======+============+=========+============+=========================+
3370         |ord    |EQ | LT | GT|uno      |UN          |NaNs absent / present.   |
3371         +-------+------------+---------+------------+-------------------------+
3372         |eq     |EQ          |ueq      |UN | EQ     |Equal                    |
3373         +-------+------------+---------+------------+-------------------------+
3374         |one    |LT | GT     |ne       |UN | LT | GT|Not equal                |
3375         +-------+------------+---------+------------+-------------------------+
3376         |lt     |LT          |ult      |UN | LT     |Less than                |
3377         +-------+------------+---------+------------+-------------------------+
3378         |le     |LT | EQ     |ule      |UN | LT | EQ|Less than or equal       |
3379         +-------+------------+---------+------------+-------------------------+
3380         |gt     |GT          |ugt      |UN | GT     |Greater than             |
3381         +-------+------------+---------+------------+-------------------------+
3382         |ge     |GT | EQ     |uge      |UN | GT | EQ|Greater than or equal    |
3383         +-------+------------+---------+------------+-------------------------+
3384 
3385         The standard C comparison operators, `<, <=, >, >=`, are all ordered,
3386         so they are false if either operand is NaN. The C equality operator,
3387         `==`, is ordered, and since inequality is defined as the logical
3388         inverse it is *unordered*. They map to the `floatcc` condition
3389         codes as follows:
3390 
3391         ==== ====== ============
3392         C    `Cond` Subset
3393         ==== ====== ============
3394         `==` eq     EQ
3395         `!=` ne     UN | LT | GT
3396         `<`  lt     LT
3397         `<=` le     LT | EQ
3398         `>`  gt     GT
3399         `>=` ge     GT | EQ
3400         ==== ====== ============
3401 
3402         This subset of condition codes also corresponds to the WebAssembly
3403         floating point comparisons of the same name.
3404 
3405         When this instruction compares floating point vectors, it returns a
3406         boolean vector with the results of lane-wise comparisons.
3407         "#,
3408             &formats.float_compare,
3409         )
3410         .operands_in(vec![Cond, x, y])
3411         .operands_out(vec![a]),
3412     );
3413 
3414     let f = &Operand::new("f", fflags);
3415 
3416     ig.push(
3417         Inst::new(
3418             "ffcmp",
3419             r#"
3420         Floating point comparison returning flags.
3421 
3422         Compares two numbers like `fcmp`, but returns floating point CPU
3423         flags instead of testing a specific condition.
3424         "#,
3425             &formats.binary,
3426         )
3427         .operands_in(vec![x, y])
3428         .operands_out(vec![f]),
3429     );
3430 
3431     let x = &Operand::new("x", Float);
3432     let y = &Operand::new("y", Float);
3433     let z = &Operand::new("z", Float);
3434     let a = &Operand::new("a", Float).with_doc("Result of applying operator to each lane");
3435 
3436     ig.push(
3437         Inst::new(
3438             "fadd",
3439             r#"
3440         Floating point addition.
3441         "#,
3442             &formats.binary,
3443         )
3444         .operands_in(vec![x, y])
3445         .operands_out(vec![a]),
3446     );
3447 
3448     ig.push(
3449         Inst::new(
3450             "fsub",
3451             r#"
3452         Floating point subtraction.
3453         "#,
3454             &formats.binary,
3455         )
3456         .operands_in(vec![x, y])
3457         .operands_out(vec![a]),
3458     );
3459 
3460     ig.push(
3461         Inst::new(
3462             "fmul",
3463             r#"
3464         Floating point multiplication.
3465         "#,
3466             &formats.binary,
3467         )
3468         .operands_in(vec![x, y])
3469         .operands_out(vec![a]),
3470     );
3471 
3472     ig.push(
3473         Inst::new(
3474             "fdiv",
3475             r#"
3476         Floating point division.
3477 
3478         Unlike the integer division instructions ` and
3479         `udiv`, this can't trap. Division by zero is infinity or
3480         NaN, depending on the dividend.
3481         "#,
3482             &formats.binary,
3483         )
3484         .operands_in(vec![x, y])
3485         .operands_out(vec![a]),
3486     );
3487 
3488     ig.push(
3489         Inst::new(
3490             "sqrt",
3491             r#"
3492         Floating point square root.
3493         "#,
3494             &formats.unary,
3495         )
3496         .operands_in(vec![x])
3497         .operands_out(vec![a]),
3498     );
3499 
3500     ig.push(
3501         Inst::new(
3502             "fma",
3503             r#"
3504         Floating point fused multiply-and-add.
3505 
3506         Computes `a := xy+z` without any intermediate rounding of the
3507         product.
3508         "#,
3509             &formats.ternary,
3510         )
3511         .operands_in(vec![x, y, z])
3512         .operands_out(vec![a]),
3513     );
3514 
3515     let a = &Operand::new("a", Float).with_doc("``x`` with its sign bit inverted");
3516 
3517     ig.push(
3518         Inst::new(
3519             "fneg",
3520             r#"
3521         Floating point negation.
3522 
3523         Note that this is a pure bitwise operation.
3524         "#,
3525             &formats.unary,
3526         )
3527         .operands_in(vec![x])
3528         .operands_out(vec![a]),
3529     );
3530 
3531     let a = &Operand::new("a", Float).with_doc("``x`` with its sign bit cleared");
3532 
3533     ig.push(
3534         Inst::new(
3535             "fabs",
3536             r#"
3537         Floating point absolute value.
3538 
3539         Note that this is a pure bitwise operation.
3540         "#,
3541             &formats.unary,
3542         )
3543         .operands_in(vec![x])
3544         .operands_out(vec![a]),
3545     );
3546 
3547     let a = &Operand::new("a", Float).with_doc("``x`` with its sign bit changed to that of ``y``");
3548 
3549     ig.push(
3550         Inst::new(
3551             "fcopysign",
3552             r#"
3553         Floating point copy sign.
3554 
3555         Note that this is a pure bitwise operation. The sign bit from ``y`` is
3556         copied to the sign bit of ``x``.
3557         "#,
3558             &formats.binary,
3559         )
3560         .operands_in(vec![x, y])
3561         .operands_out(vec![a]),
3562     );
3563 
3564     let a = &Operand::new("a", Float).with_doc("The smaller of ``x`` and ``y``");
3565 
3566     ig.push(
3567         Inst::new(
3568             "fmin",
3569             r#"
3570         Floating point minimum, propagating NaNs.
3571 
3572         If either operand is NaN, this returns a NaN.
3573         "#,
3574             &formats.binary,
3575         )
3576         .operands_in(vec![x, y])
3577         .operands_out(vec![a]),
3578     );
3579 
3580     ig.push(
3581         Inst::new(
3582             "fmin_pseudo",
3583             r#"
3584         Floating point pseudo-minimum, propagating NaNs.  This behaves differently from ``fmin``.
3585         See <https://github.com/WebAssembly/simd/pull/122> for background.
3586 
3587         The behaviour is defined as ``fmin_pseudo(a, b) = (b < a) ? b : a``, and the behaviour
3588         for zero or NaN inputs follows from the behaviour of ``<`` with such inputs.
3589         "#,
3590             &formats.binary,
3591         )
3592         .operands_in(vec![x, y])
3593         .operands_out(vec![a]),
3594     );
3595 
3596     let a = &Operand::new("a", Float).with_doc("The larger of ``x`` and ``y``");
3597 
3598     ig.push(
3599         Inst::new(
3600             "fmax",
3601             r#"
3602         Floating point maximum, propagating NaNs.
3603 
3604         If either operand is NaN, this returns a NaN.
3605         "#,
3606             &formats.binary,
3607         )
3608         .operands_in(vec![x, y])
3609         .operands_out(vec![a]),
3610     );
3611 
3612     ig.push(
3613         Inst::new(
3614             "fmax_pseudo",
3615             r#"
3616         Floating point pseudo-maximum, propagating NaNs.  This behaves differently from ``fmax``.
3617         See <https://github.com/WebAssembly/simd/pull/122> for background.
3618 
3619         The behaviour is defined as ``fmax_pseudo(a, b) = (a < b) ? b : a``, and the behaviour
3620         for zero or NaN inputs follows from the behaviour of ``<`` with such inputs.
3621         "#,
3622             &formats.binary,
3623         )
3624         .operands_in(vec![x, y])
3625         .operands_out(vec![a]),
3626     );
3627 
3628     let a = &Operand::new("a", Float).with_doc("``x`` rounded to integral value");
3629 
3630     ig.push(
3631         Inst::new(
3632             "ceil",
3633             r#"
3634         Round floating point round to integral, towards positive infinity.
3635         "#,
3636             &formats.unary,
3637         )
3638         .operands_in(vec![x])
3639         .operands_out(vec![a]),
3640     );
3641 
3642     ig.push(
3643         Inst::new(
3644             "floor",
3645             r#"
3646         Round floating point round to integral, towards negative infinity.
3647         "#,
3648             &formats.unary,
3649         )
3650         .operands_in(vec![x])
3651         .operands_out(vec![a]),
3652     );
3653 
3654     ig.push(
3655         Inst::new(
3656             "trunc",
3657             r#"
3658         Round floating point round to integral, towards zero.
3659         "#,
3660             &formats.unary,
3661         )
3662         .operands_in(vec![x])
3663         .operands_out(vec![a]),
3664     );
3665 
3666     ig.push(
3667         Inst::new(
3668             "nearest",
3669             r#"
3670         Round floating point round to integral, towards nearest with ties to
3671         even.
3672         "#,
3673             &formats.unary,
3674         )
3675         .operands_in(vec![x])
3676         .operands_out(vec![a]),
3677     );
3678 
3679     let a = &Operand::new("a", b1);
3680     let x = &Operand::new("x", Ref);
3681 
3682     ig.push(
3683         Inst::new(
3684             "is_null",
3685             r#"
3686         Reference verification.
3687 
3688         The condition code determines if the reference type in question is
3689         null or not.
3690         "#,
3691             &formats.unary,
3692         )
3693         .operands_in(vec![x])
3694         .operands_out(vec![a]),
3695     );
3696 
3697     let a = &Operand::new("a", b1);
3698     let x = &Operand::new("x", Ref);
3699 
3700     ig.push(
3701         Inst::new(
3702             "is_invalid",
3703             r#"
3704         Reference verification.
3705 
3706         The condition code determines if the reference type in question is
3707         invalid or not.
3708         "#,
3709             &formats.unary,
3710         )
3711         .operands_in(vec![x])
3712         .operands_out(vec![a]),
3713     );
3714 
3715     let Cond = &Operand::new("Cond", &imm.intcc);
3716     let f = &Operand::new("f", iflags);
3717     let a = &Operand::new("a", b1);
3718 
3719     ig.push(
3720         Inst::new(
3721             "trueif",
3722             r#"
3723         Test integer CPU flags for a specific condition.
3724 
3725         Check the CPU flags in ``f`` against the ``Cond`` condition code and
3726         return true when the condition code is satisfied.
3727         "#,
3728             &formats.int_cond,
3729         )
3730         .operands_in(vec![Cond, f])
3731         .operands_out(vec![a]),
3732     );
3733 
3734     let Cond = &Operand::new("Cond", &imm.floatcc);
3735     let f = &Operand::new("f", fflags);
3736 
3737     ig.push(
3738         Inst::new(
3739             "trueff",
3740             r#"
3741         Test floating point CPU flags for a specific condition.
3742 
3743         Check the CPU flags in ``f`` against the ``Cond`` condition code and
3744         return true when the condition code is satisfied.
3745         "#,
3746             &formats.float_cond,
3747         )
3748         .operands_in(vec![Cond, f])
3749         .operands_out(vec![a]),
3750     );
3751 
3752     let x = &Operand::new("x", Mem);
3753     let a = &Operand::new("a", MemTo).with_doc("Bits of `x` reinterpreted");
3754 
3755     ig.push(
3756         Inst::new(
3757             "bitcast",
3758             r#"
3759         Reinterpret the bits in `x` as a different type.
3760 
3761         The input and output types must be storable to memory and of the same
3762         size. A bitcast is equivalent to storing one type and loading the other
3763         type from the same address.
3764         "#,
3765             &formats.unary,
3766         )
3767         .operands_in(vec![x])
3768         .operands_out(vec![a]),
3769     );
3770 
3771     let x = &Operand::new("x", Any);
3772     let a = &Operand::new("a", AnyTo).with_doc("Bits of `x` reinterpreted");
3773 
3774     ig.push(
3775         Inst::new(
3776             "raw_bitcast",
3777             r#"
3778         Cast the bits in `x` as a different type of the same bit width.
3779 
3780         This instruction does not change the data's representation but allows
3781         data in registers to be used as different types, e.g. an i32x4 as a
3782         b8x16. The only constraint on the result `a` is that it can be
3783         `raw_bitcast` back to the original type. Also, in a raw_bitcast between
3784         vector types with the same number of lanes, the value of each result
3785         lane is a raw_bitcast of the corresponding operand lane. TODO there is
3786         currently no mechanism for enforcing the bit width constraint.
3787         "#,
3788             &formats.unary,
3789         )
3790         .operands_in(vec![x])
3791         .operands_out(vec![a]),
3792     );
3793 
3794     let a = &Operand::new("a", TxN).with_doc("A vector value");
3795     let s = &Operand::new("s", &TxN.lane_of()).with_doc("A scalar value");
3796 
3797     ig.push(
3798         Inst::new(
3799             "scalar_to_vector",
3800             r#"
3801             Copies a scalar value to a vector value.  The scalar is copied into the
3802             least significant lane of the vector, and all other lanes will be zero.
3803             "#,
3804             &formats.unary,
3805         )
3806         .operands_in(vec![s])
3807         .operands_out(vec![a]),
3808     );
3809 
3810     let Bool = &TypeVar::new(
3811         "Bool",
3812         "A scalar or vector boolean type",
3813         TypeSetBuilder::new()
3814             .bools(Interval::All)
3815             .simd_lanes(Interval::All)
3816             .build(),
3817     );
3818 
3819     let BoolTo = &TypeVar::new(
3820         "BoolTo",
3821         "A smaller boolean type with the same number of lanes",
3822         TypeSetBuilder::new()
3823             .bools(Interval::All)
3824             .simd_lanes(Interval::All)
3825             .build(),
3826     );
3827 
3828     let x = &Operand::new("x", Bool);
3829     let a = &Operand::new("a", BoolTo);
3830 
3831     ig.push(
3832         Inst::new(
3833             "breduce",
3834             r#"
3835         Convert `x` to a smaller boolean type in the platform-defined way.
3836 
3837         The result type must have the same number of vector lanes as the input,
3838         and each lane must not have more bits that the input lanes. If the
3839         input and output types are the same, this is a no-op.
3840         "#,
3841             &formats.unary,
3842         )
3843         .operands_in(vec![x])
3844         .operands_out(vec![a])
3845         .constraints(vec![WiderOrEq(Bool.clone(), BoolTo.clone())]),
3846     );
3847 
3848     let BoolTo = &TypeVar::new(
3849         "BoolTo",
3850         "A larger boolean type with the same number of lanes",
3851         TypeSetBuilder::new()
3852             .bools(Interval::All)
3853             .simd_lanes(Interval::All)
3854             .build(),
3855     );
3856     let x = &Operand::new("x", Bool);
3857     let a = &Operand::new("a", BoolTo);
3858 
3859     ig.push(
3860         Inst::new(
3861             "bextend",
3862             r#"
3863         Convert `x` to a larger boolean type in the platform-defined way.
3864 
3865         The result type must have the same number of vector lanes as the input,
3866         and each lane must not have fewer bits that the input lanes. If the
3867         input and output types are the same, this is a no-op.
3868         "#,
3869             &formats.unary,
3870         )
3871         .operands_in(vec![x])
3872         .operands_out(vec![a])
3873         .constraints(vec![WiderOrEq(BoolTo.clone(), Bool.clone())]),
3874     );
3875 
3876     let IntTo = &TypeVar::new(
3877         "IntTo",
3878         "An integer type with the same number of lanes",
3879         TypeSetBuilder::new()
3880             .ints(Interval::All)
3881             .simd_lanes(Interval::All)
3882             .build(),
3883     );
3884     let x = &Operand::new("x", Bool);
3885     let a = &Operand::new("a", IntTo);
3886 
3887     ig.push(
3888         Inst::new(
3889             "bint",
3890             r#"
3891         Convert `x` to an integer.
3892 
3893         True maps to 1 and false maps to 0. The result type must have the same
3894         number of vector lanes as the input.
3895         "#,
3896             &formats.unary,
3897         )
3898         .operands_in(vec![x])
3899         .operands_out(vec![a]),
3900     );
3901 
3902     ig.push(
3903         Inst::new(
3904             "bmask",
3905             r#"
3906         Convert `x` to an integer mask.
3907 
3908         True maps to all 1s and false maps to all 0s. The result type must have
3909         the same number of vector lanes as the input.
3910         "#,
3911             &formats.unary,
3912         )
3913         .operands_in(vec![x])
3914         .operands_out(vec![a]),
3915     );
3916 
3917     let Int = &TypeVar::new(
3918         "Int",
3919         "A scalar or vector integer type",
3920         TypeSetBuilder::new()
3921             .ints(Interval::All)
3922             .simd_lanes(Interval::All)
3923             .build(),
3924     );
3925 
3926     let IntTo = &TypeVar::new(
3927         "IntTo",
3928         "A smaller integer type with the same number of lanes",
3929         TypeSetBuilder::new()
3930             .ints(Interval::All)
3931             .simd_lanes(Interval::All)
3932             .build(),
3933     );
3934     let x = &Operand::new("x", Int);
3935     let a = &Operand::new("a", IntTo);
3936 
3937     ig.push(
3938         Inst::new(
3939             "ireduce",
3940             r#"
3941         Convert `x` to a smaller integer type by dropping high bits.
3942 
3943         Each lane in `x` is converted to a smaller integer type by discarding
3944         the most significant bits. This is the same as reducing modulo
3945         `2^n`.
3946 
3947         The result type must have the same number of vector lanes as the input,
3948         and each lane must not have more bits that the input lanes. If the
3949         input and output types are the same, this is a no-op.
3950         "#,
3951             &formats.unary,
3952         )
3953         .operands_in(vec![x])
3954         .operands_out(vec![a])
3955         .constraints(vec![WiderOrEq(Int.clone(), IntTo.clone())]),
3956     );
3957 
3958     let I16or32xN = &TypeVar::new(
3959         "I16or32xN",
3960         "A SIMD vector type containing integer lanes 16 or 32 bits wide",
3961         TypeSetBuilder::new()
3962             .ints(16..32)
3963             .simd_lanes(4..8)
3964             .includes_scalars(false)
3965             .build(),
3966     );
3967 
3968     let x = &Operand::new("x", I16or32xN);
3969     let y = &Operand::new("y", I16or32xN);
3970     let a = &Operand::new("a", &I16or32xN.split_lanes());
3971 
3972     ig.push(
3973         Inst::new(
3974             "snarrow",
3975             r#"
3976         Combine `x` and `y` into a vector with twice the lanes but half the integer width while
3977         saturating overflowing values to the signed maximum and minimum.
3978 
3979         The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4`
3980         and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value
3981         returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`.
3982             "#,
3983             &formats.binary,
3984         )
3985         .operands_in(vec![x, y])
3986         .operands_out(vec![a]),
3987     );
3988 
3989     ig.push(
3990         Inst::new(
3991             "unarrow",
3992             r#"
3993         Combine `x` and `y` into a vector with twice the lanes but half the integer width while
3994         saturating overflowing values to the unsigned maximum and minimum.
3995 
3996         Note that all input lanes are considered signed: any negative lanes will overflow and be
3997         replaced with the unsigned minimum, `0x00`.
3998 
3999         The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4`
4000         and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value
4001         returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`.
4002             "#,
4003             &formats.binary,
4004         )
4005         .operands_in(vec![x, y])
4006         .operands_out(vec![a]),
4007     );
4008 
4009     let I8or16xN = &TypeVar::new(
4010         "I8or16xN",
4011         "A SIMD vector type containing integer lanes 8 or 16 bits wide.",
4012         TypeSetBuilder::new()
4013             .ints(8..16)
4014             .simd_lanes(8..16)
4015             .includes_scalars(false)
4016             .build(),
4017     );
4018 
4019     let x = &Operand::new("x", I8or16xN);
4020     let a = &Operand::new("a", &I8or16xN.merge_lanes());
4021 
4022     ig.push(
4023         Inst::new(
4024             "swiden_low",
4025             r#"
4026         Widen the low lanes of `x` using signed extension.
4027 
4028         This will double the lane width and halve the number of lanes.
4029             "#,
4030             &formats.unary,
4031         )
4032         .operands_in(vec![x])
4033         .operands_out(vec![a]),
4034     );
4035 
4036     ig.push(
4037         Inst::new(
4038             "swiden_high",
4039             r#"
4040         Widen the high lanes of `x` using signed extension.
4041 
4042         This will double the lane width and halve the number of lanes.
4043             "#,
4044             &formats.unary,
4045         )
4046         .operands_in(vec![x])
4047         .operands_out(vec![a]),
4048     );
4049 
4050     ig.push(
4051         Inst::new(
4052             "uwiden_low",
4053             r#"
4054         Widen the low lanes of `x` using unsigned extension.
4055 
4056         This will double the lane width and halve the number of lanes.
4057             "#,
4058             &formats.unary,
4059         )
4060         .operands_in(vec![x])
4061         .operands_out(vec![a]),
4062     );
4063 
4064     ig.push(
4065         Inst::new(
4066             "uwiden_high",
4067             r#"
4068         Widen the high lanes of `x` using unsigned extension.
4069 
4070         This will double the lane width and halve the number of lanes.
4071             "#,
4072             &formats.unary,
4073         )
4074         .operands_in(vec![x])
4075         .operands_out(vec![a]),
4076     );
4077 
4078     let I16x8 = &TypeVar::new(
4079         "I16x8",
4080         "A SIMD vector type containing 8 integer lanes each 16 bits wide.",
4081         TypeSetBuilder::new()
4082             .ints(16..16)
4083             .simd_lanes(8..8)
4084             .includes_scalars(false)
4085             .build(),
4086     );
4087 
4088     let x = &Operand::new("x", I16x8);
4089     let y = &Operand::new("y", I16x8);
4090     let a = &Operand::new("a", &I16x8.merge_lanes());
4091 
4092     ig.push(
4093         Inst::new(
4094             "widening_pairwise_dot_product_s",
4095             r#"
4096         Takes corresponding elements in `x` and `y`, performs a sign-extending length-doubling
4097         multiplication on them, then adds adjacent pairs of elements to form the result.  For
4098         example, if the input vectors are `[x3, x2, x1, x0]` and `[y3, y2, y1, y0]`, it produces
4099         the vector `[r1, r0]`, where `r1 = sx(x3) * sx(y3) + sx(x2) * sx(y2)` and
4100         `r0 = sx(x1) * sx(y1) + sx(x0) * sx(y0)`, and `sx(n)` sign-extends `n` to twice its width.
4101 
4102         This will double the lane width and halve the number of lanes.  So the resulting
4103         vector has the same number of bits as `x` and `y` do (individually).
4104 
4105         See <https://github.com/WebAssembly/simd/pull/127> for background info.
4106             "#,
4107             &formats.binary,
4108         )
4109         .operands_in(vec![x, y])
4110         .operands_out(vec![a]),
4111     );
4112 
4113     let IntTo = &TypeVar::new(
4114         "IntTo",
4115         "A larger integer type with the same number of lanes",
4116         TypeSetBuilder::new()
4117             .ints(Interval::All)
4118             .simd_lanes(Interval::All)
4119             .build(),
4120     );
4121     let x = &Operand::new("x", Int);
4122     let a = &Operand::new("a", IntTo);
4123 
4124     ig.push(
4125         Inst::new(
4126             "uextend",
4127             r#"
4128         Convert `x` to a larger integer type by zero-extending.
4129 
4130         Each lane in `x` is converted to a larger integer type by adding
4131         zeroes. The result has the same numerical value as `x` when both are
4132         interpreted as unsigned integers.
4133 
4134         The result type must have the same number of vector lanes as the input,
4135         and each lane must not have fewer bits that the input lanes. If the
4136         input and output types are the same, this is a no-op.
4137         "#,
4138             &formats.unary,
4139         )
4140         .operands_in(vec![x])
4141         .operands_out(vec![a])
4142         .constraints(vec![WiderOrEq(IntTo.clone(), Int.clone())]),
4143     );
4144 
4145     ig.push(
4146         Inst::new(
4147             "sextend",
4148             r#"
4149         Convert `x` to a larger integer type by sign-extending.
4150 
4151         Each lane in `x` is converted to a larger integer type by replicating
4152         the sign bit. The result has the same numerical value as `x` when both
4153         are interpreted as signed integers.
4154 
4155         The result type must have the same number of vector lanes as the input,
4156         and each lane must not have fewer bits that the input lanes. If the
4157         input and output types are the same, this is a no-op.
4158         "#,
4159             &formats.unary,
4160         )
4161         .operands_in(vec![x])
4162         .operands_out(vec![a])
4163         .constraints(vec![WiderOrEq(IntTo.clone(), Int.clone())]),
4164     );
4165 
4166     let FloatTo = &TypeVar::new(
4167         "FloatTo",
4168         "A scalar or vector floating point number",
4169         TypeSetBuilder::new()
4170             .floats(Interval::All)
4171             .simd_lanes(Interval::All)
4172             .build(),
4173     );
4174     let x = &Operand::new("x", Float);
4175     let a = &Operand::new("a", FloatTo);
4176 
4177     ig.push(
4178         Inst::new(
4179             "fpromote",
4180             r#"
4181         Convert `x` to a larger floating point format.
4182 
4183         Each lane in `x` is converted to the destination floating point format.
4184         This is an exact operation.
4185 
4186         Cranelift currently only supports two floating point formats
4187         - `f32` and `f64`. This may change in the future.
4188 
4189         The result type must have the same number of vector lanes as the input,
4190         and the result lanes must not have fewer bits than the input lanes. If
4191         the input and output types are the same, this is a no-op.
4192         "#,
4193             &formats.unary,
4194         )
4195         .operands_in(vec![x])
4196         .operands_out(vec![a])
4197         .constraints(vec![WiderOrEq(FloatTo.clone(), Float.clone())]),
4198     );
4199 
4200     ig.push(
4201         Inst::new(
4202             "fdemote",
4203             r#"
4204         Convert `x` to a smaller floating point format.
4205 
4206         Each lane in `x` is converted to the destination floating point format
4207         by rounding to nearest, ties to even.
4208 
4209         Cranelift currently only supports two floating point formats
4210         - `f32` and `f64`. This may change in the future.
4211 
4212         The result type must have the same number of vector lanes as the input,
4213         and the result lanes must not have more bits than the input lanes. If
4214         the input and output types are the same, this is a no-op.
4215         "#,
4216             &formats.unary,
4217         )
4218         .operands_in(vec![x])
4219         .operands_out(vec![a])
4220         .constraints(vec![WiderOrEq(Float.clone(), FloatTo.clone())]),
4221     );
4222 
4223     let x = &Operand::new("x", Float);
4224     let a = &Operand::new("a", IntTo);
4225 
4226     ig.push(
4227         Inst::new(
4228             "fcvt_to_uint",
4229             r#"
4230         Convert floating point to unsigned integer.
4231 
4232         Each lane in `x` is converted to an unsigned integer by rounding
4233         towards zero. If `x` is NaN or if the unsigned integral value cannot be
4234         represented in the result type, this instruction traps.
4235 
4236         The result type must have the same number of vector lanes as the input.
4237         "#,
4238             &formats.unary,
4239         )
4240         .operands_in(vec![x])
4241         .operands_out(vec![a])
4242         .can_trap(true),
4243     );
4244 
4245     ig.push(
4246         Inst::new(
4247             "fcvt_to_uint_sat",
4248             r#"
4249         Convert floating point to unsigned integer as fcvt_to_uint does, but
4250         saturates the input instead of trapping. NaN and negative values are
4251         converted to 0.
4252         "#,
4253             &formats.unary,
4254         )
4255         .operands_in(vec![x])
4256         .operands_out(vec![a]),
4257     );
4258 
4259     ig.push(
4260         Inst::new(
4261             "fcvt_to_sint",
4262             r#"
4263         Convert floating point to signed integer.
4264 
4265         Each lane in `x` is converted to a signed integer by rounding towards
4266         zero. If `x` is NaN or if the signed integral value cannot be
4267         represented in the result type, this instruction traps.
4268 
4269         The result type must have the same number of vector lanes as the input.
4270         "#,
4271             &formats.unary,
4272         )
4273         .operands_in(vec![x])
4274         .operands_out(vec![a])
4275         .can_trap(true),
4276     );
4277 
4278     ig.push(
4279         Inst::new(
4280             "fcvt_to_sint_sat",
4281             r#"
4282         Convert floating point to signed integer as fcvt_to_sint does, but
4283         saturates the input instead of trapping. NaN values are converted to 0.
4284         "#,
4285             &formats.unary,
4286         )
4287         .operands_in(vec![x])
4288         .operands_out(vec![a]),
4289     );
4290 
4291     let x = &Operand::new("x", Int);
4292     let a = &Operand::new("a", FloatTo);
4293 
4294     ig.push(
4295         Inst::new(
4296             "fcvt_from_uint",
4297             r#"
4298         Convert unsigned integer to floating point.
4299 
4300         Each lane in `x` is interpreted as an unsigned integer and converted to
4301         floating point using round to nearest, ties to even.
4302 
4303         The result type must have the same number of vector lanes as the input.
4304         "#,
4305             &formats.unary,
4306         )
4307         .operands_in(vec![x])
4308         .operands_out(vec![a]),
4309     );
4310 
4311     ig.push(
4312         Inst::new(
4313             "fcvt_from_sint",
4314             r#"
4315         Convert signed integer to floating point.
4316 
4317         Each lane in `x` is interpreted as a signed integer and converted to
4318         floating point using round to nearest, ties to even.
4319 
4320         The result type must have the same number of vector lanes as the input.
4321         "#,
4322             &formats.unary,
4323         )
4324         .operands_in(vec![x])
4325         .operands_out(vec![a]),
4326     );
4327 
4328     ig.push(
4329         Inst::new(
4330             "fcvt_low_from_sint",
4331             r#"
4332         Converts packed signed doubleword integers to packed double precision floating point.
4333 
4334         Considering only the low half of the register, each lane in `x` is interpreted as a
4335         signed doubleword integer that is then converted to a double precision float. This
4336         instruction differs from fcvt_from_sint in that it converts half the number of lanes
4337         which are converted to occupy twice the number of bits. No rounding should be needed
4338         for the resulting float.
4339 
4340         The result type will have half the number of vector lanes as the input.
4341         "#,
4342             &formats.unary,
4343         )
4344         .operands_in(vec![x])
4345         .operands_out(vec![a]),
4346     );
4347 
4348     let WideInt = &TypeVar::new(
4349         "WideInt",
4350         "An integer type with lanes from `i16` upwards",
4351         TypeSetBuilder::new()
4352             .ints(16..128)
4353             .simd_lanes(Interval::All)
4354             .build(),
4355     );
4356     let x = &Operand::new("x", WideInt);
4357     let lo = &Operand::new("lo", &WideInt.half_width()).with_doc("The low bits of `x`");
4358     let hi = &Operand::new("hi", &WideInt.half_width()).with_doc("The high bits of `x`");
4359 
4360     ig.push(
4361         Inst::new(
4362             "isplit",
4363             r#"
4364         Split an integer into low and high parts.
4365 
4366         Vectors of integers are split lane-wise, so the results have the same
4367         number of lanes as the input, but the lanes are half the size.
4368 
4369         Returns the low half of `x` and the high half of `x` as two independent
4370         values.
4371         "#,
4372             &formats.unary,
4373         )
4374         .operands_in(vec![x])
4375         .operands_out(vec![lo, hi])
4376         .is_ghost(true),
4377     );
4378 
4379     let NarrowInt = &TypeVar::new(
4380         "NarrowInt",
4381         "An integer type with lanes type to `i64`",
4382         TypeSetBuilder::new()
4383             .ints(8..64)
4384             .simd_lanes(Interval::All)
4385             .build(),
4386     );
4387 
4388     let lo = &Operand::new("lo", NarrowInt);
4389     let hi = &Operand::new("hi", NarrowInt);
4390     let a = &Operand::new("a", &NarrowInt.double_width())
4391         .with_doc("The concatenation of `lo` and `hi`");
4392 
4393     ig.push(
4394         Inst::new(
4395             "iconcat",
4396             r#"
4397         Concatenate low and high bits to form a larger integer type.
4398 
4399         Vectors of integers are concatenated lane-wise such that the result has
4400         the same number of lanes as the inputs, but the lanes are twice the
4401         size.
4402         "#,
4403             &formats.binary,
4404         )
4405         .operands_in(vec![lo, hi])
4406         .operands_out(vec![a])
4407         .is_ghost(true),
4408     );
4409 
4410     // Instructions relating to atomic memory accesses and fences
4411     let AtomicMem = &TypeVar::new(
4412         "AtomicMem",
4413         "Any type that can be stored in memory, which can be used in an atomic operation",
4414         TypeSetBuilder::new().ints(8..64).build(),
4415     );
4416     let x = &Operand::new("x", AtomicMem).with_doc("Value to be atomically stored");
4417     let a = &Operand::new("a", AtomicMem).with_doc("Value atomically loaded");
4418     let e = &Operand::new("e", AtomicMem).with_doc("Expected value in CAS");
4419     let p = &Operand::new("p", iAddr);
4420     let MemFlags = &Operand::new("MemFlags", &imm.memflags);
4421     let AtomicRmwOp = &Operand::new("AtomicRmwOp", &imm.atomic_rmw_op);
4422 
4423     ig.push(
4424         Inst::new(
4425             "atomic_rmw",
4426             r#"
4427         Atomically read-modify-write memory at `p`, with second operand `x`.  The old value is
4428         returned.  `p` has the type of the target word size, and `x` may be an integer type of
4429         8, 16, 32 or 64 bits, even on a 32-bit target.  The type of the returned value is the
4430         same as the type of `x`.  This operation is sequentially consistent and creates
4431         happens-before edges that order normal (non-atomic) loads and stores.
4432         "#,
4433             &formats.atomic_rmw,
4434         )
4435         .operands_in(vec![MemFlags, AtomicRmwOp, p, x])
4436         .operands_out(vec![a])
4437         .can_load(true)
4438         .can_store(true)
4439         .other_side_effects(true),
4440     );
4441 
4442     ig.push(
4443         Inst::new(
4444             "atomic_cas",
4445             r#"
4446         Perform an atomic compare-and-swap operation on memory at `p`, with expected value `e`,
4447         storing `x` if the value at `p` equals `e`.  The old value at `p` is returned,
4448         regardless of whether the operation succeeds or fails.  `p` has the type of the target
4449         word size, and `x` and `e` must have the same type and the same size, which may be an
4450         integer type of 8, 16, 32 or 64 bits, even on a 32-bit target.  The type of the returned
4451         value is the same as the type of `x` and `e`.  This operation is sequentially
4452         consistent and creates happens-before edges that order normal (non-atomic) loads and
4453         stores.
4454         "#,
4455             &formats.atomic_cas,
4456         )
4457         .operands_in(vec![MemFlags, p, e, x])
4458         .operands_out(vec![a])
4459         .can_load(true)
4460         .can_store(true)
4461         .other_side_effects(true),
4462     );
4463 
4464     ig.push(
4465         Inst::new(
4466             "atomic_load",
4467             r#"
4468         Atomically load from memory at `p`.
4469 
4470         This is a polymorphic instruction that can load any value type which has a memory
4471         representation.  It should only be used for integer types with 8, 16, 32 or 64 bits.
4472         This operation is sequentially consistent and creates happens-before edges that order
4473         normal (non-atomic) loads and stores.
4474         "#,
4475             &formats.load_no_offset,
4476         )
4477         .operands_in(vec![MemFlags, p])
4478         .operands_out(vec![a])
4479         .can_load(true)
4480         .other_side_effects(true),
4481     );
4482 
4483     ig.push(
4484         Inst::new(
4485             "atomic_store",
4486             r#"
4487         Atomically store `x` to memory at `p`.
4488 
4489         This is a polymorphic instruction that can store any value type with a memory
4490         representation.  It should only be used for integer types with 8, 16, 32 or 64 bits.
4491         This operation is sequentially consistent and creates happens-before edges that order
4492         normal (non-atomic) loads and stores.
4493         "#,
4494             &formats.store_no_offset,
4495         )
4496         .operands_in(vec![MemFlags, x, p])
4497         .can_store(true)
4498         .other_side_effects(true),
4499     );
4500 
4501     ig.push(
4502         Inst::new(
4503             "fence",
4504             r#"
4505         A memory fence.  This must provide ordering to ensure that, at a minimum, neither loads
4506         nor stores of any kind may move forwards or backwards across the fence.  This operation
4507         is sequentially consistent.
4508         "#,
4509             &formats.nullary,
4510         )
4511         .other_side_effects(true),
4512     );
4513 
4514     ig.build()
4515 }
4516