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 
698 #[allow(clippy::many_single_char_names)]
699 pub(crate) fn define(
700     all_instructions: &mut AllInstructions,
701     formats: &Formats,
702     imm: &Immediates,
703     entities: &EntityRefs,
704 ) -> InstructionGroup {
705     let mut ig = InstructionGroupBuilder::new(all_instructions);
706 
707     define_control_flow(&mut ig, formats, imm, entities);
708     define_simd_lane_access(&mut ig, formats, imm, entities);
709     define_simd_arithmetic(&mut ig, formats, imm, entities);
710 
711     // Operand kind shorthands.
712     let iflags: &TypeVar = &ValueType::Special(types::Flag::IFlags.into()).into();
713     let fflags: &TypeVar = &ValueType::Special(types::Flag::FFlags.into()).into();
714 
715     let b1: &TypeVar = &ValueType::from(LaneType::from(types::Bool::B1)).into();
716     let f32_: &TypeVar = &ValueType::from(LaneType::from(types::Float::F32)).into();
717     let f64_: &TypeVar = &ValueType::from(LaneType::from(types::Float::F64)).into();
718 
719     // Starting definitions.
720     let Int = &TypeVar::new(
721         "Int",
722         "A scalar or vector integer type",
723         TypeSetBuilder::new()
724             .ints(Interval::All)
725             .simd_lanes(Interval::All)
726             .build(),
727     );
728 
729     let Bool = &TypeVar::new(
730         "Bool",
731         "A scalar or vector boolean type",
732         TypeSetBuilder::new()
733             .bools(Interval::All)
734             .simd_lanes(Interval::All)
735             .build(),
736     );
737 
738     let iB = &TypeVar::new(
739         "iB",
740         "A scalar integer type",
741         TypeSetBuilder::new().ints(Interval::All).build(),
742     );
743 
744     let iAddr = &TypeVar::new(
745         "iAddr",
746         "An integer address type",
747         TypeSetBuilder::new().ints(32..64).refs(32..64).build(),
748     );
749 
750     let Ref = &TypeVar::new(
751         "Ref",
752         "A scalar reference type",
753         TypeSetBuilder::new().refs(Interval::All).build(),
754     );
755 
756     let Testable = &TypeVar::new(
757         "Testable",
758         "A scalar boolean or integer type",
759         TypeSetBuilder::new()
760             .ints(Interval::All)
761             .bools(Interval::All)
762             .build(),
763     );
764 
765     let TxN = &TypeVar::new(
766         "TxN",
767         "A SIMD vector type",
768         TypeSetBuilder::new()
769             .ints(Interval::All)
770             .floats(Interval::All)
771             .bools(Interval::All)
772             .simd_lanes(Interval::All)
773             .includes_scalars(false)
774             .build(),
775     );
776     let Any = &TypeVar::new(
777         "Any",
778         "Any integer, float, boolean, or reference scalar or vector type",
779         TypeSetBuilder::new()
780             .ints(Interval::All)
781             .floats(Interval::All)
782             .bools(Interval::All)
783             .refs(Interval::All)
784             .simd_lanes(Interval::All)
785             .includes_scalars(true)
786             .build(),
787     );
788 
789     let AnyTo = &TypeVar::copy_from(Any, "AnyTo".to_string());
790 
791     let Mem = &TypeVar::new(
792         "Mem",
793         "Any type that can be stored in memory",
794         TypeSetBuilder::new()
795             .ints(Interval::All)
796             .floats(Interval::All)
797             .simd_lanes(Interval::All)
798             .refs(Interval::All)
799             .build(),
800     );
801 
802     let MemTo = &TypeVar::copy_from(Mem, "MemTo".to_string());
803 
804     let addr = &Operand::new("addr", iAddr);
805 
806     let SS = &Operand::new("SS", &entities.stack_slot);
807     let Offset = &Operand::new("Offset", &imm.offset32).with_doc("Byte offset from base address");
808     let x = &Operand::new("x", Mem).with_doc("Value to be stored");
809     let a = &Operand::new("a", Mem).with_doc("Value loaded");
810     let p = &Operand::new("p", iAddr);
811     let MemFlags = &Operand::new("MemFlags", &imm.memflags);
812     let args = &Operand::new("args", &entities.varargs).with_doc("Address arguments");
813 
814     ig.push(
815         Inst::new(
816             "load",
817             r#"
818         Load from memory at ``p + Offset``.
819 
820         This is a polymorphic instruction that can load any value type which
821         has a memory representation.
822         "#,
823             &formats.load,
824         )
825         .operands_in(vec![MemFlags, p, Offset])
826         .operands_out(vec![a])
827         .can_load(true),
828     );
829 
830     ig.push(
831         Inst::new(
832             "load_complex",
833             r#"
834         Load from memory at ``sum(args) + Offset``.
835 
836         This is a polymorphic instruction that can load any value type which
837         has a memory representation.
838         "#,
839             &formats.load_complex,
840         )
841         .operands_in(vec![MemFlags, args, Offset])
842         .operands_out(vec![a])
843         .can_load(true),
844     );
845 
846     ig.push(
847         Inst::new(
848             "store",
849             r#"
850         Store ``x`` to memory at ``p + Offset``.
851 
852         This is a polymorphic instruction that can store any value type with a
853         memory representation.
854         "#,
855             &formats.store,
856         )
857         .operands_in(vec![MemFlags, x, p, Offset])
858         .can_store(true),
859     );
860 
861     ig.push(
862         Inst::new(
863             "store_complex",
864             r#"
865         Store ``x`` to memory at ``sum(args) + Offset``.
866 
867         This is a polymorphic instruction that can store any value type with a
868         memory representation.
869         "#,
870             &formats.store_complex,
871         )
872         .operands_in(vec![MemFlags, x, args, Offset])
873         .can_store(true),
874     );
875 
876     let iExt8 = &TypeVar::new(
877         "iExt8",
878         "An integer type with more than 8 bits",
879         TypeSetBuilder::new().ints(16..64).build(),
880     );
881     let x = &Operand::new("x", iExt8);
882     let a = &Operand::new("a", iExt8);
883 
884     ig.push(
885         Inst::new(
886             "uload8",
887             r#"
888         Load 8 bits from memory at ``p + Offset`` and zero-extend.
889 
890         This is equivalent to ``load.i8`` followed by ``uextend``.
891         "#,
892             &formats.load,
893         )
894         .operands_in(vec![MemFlags, p, Offset])
895         .operands_out(vec![a])
896         .can_load(true),
897     );
898 
899     ig.push(
900         Inst::new(
901             "uload8_complex",
902             r#"
903         Load 8 bits from memory at ``sum(args) + Offset`` and zero-extend.
904 
905         This is equivalent to ``load.i8`` followed by ``uextend``.
906         "#,
907             &formats.load_complex,
908         )
909         .operands_in(vec![MemFlags, args, Offset])
910         .operands_out(vec![a])
911         .can_load(true),
912     );
913 
914     ig.push(
915         Inst::new(
916             "sload8",
917             r#"
918         Load 8 bits from memory at ``p + Offset`` and sign-extend.
919 
920         This is equivalent to ``load.i8`` followed by ``sextend``.
921         "#,
922             &formats.load,
923         )
924         .operands_in(vec![MemFlags, p, Offset])
925         .operands_out(vec![a])
926         .can_load(true),
927     );
928 
929     ig.push(
930         Inst::new(
931             "sload8_complex",
932             r#"
933         Load 8 bits from memory at ``sum(args) + Offset`` and sign-extend.
934 
935         This is equivalent to ``load.i8`` followed by ``sextend``.
936         "#,
937             &formats.load_complex,
938         )
939         .operands_in(vec![MemFlags, args, Offset])
940         .operands_out(vec![a])
941         .can_load(true),
942     );
943 
944     ig.push(
945         Inst::new(
946             "istore8",
947             r#"
948         Store the low 8 bits of ``x`` to memory at ``p + Offset``.
949 
950         This is equivalent to ``ireduce.i8`` followed by ``store.i8``.
951         "#,
952             &formats.store,
953         )
954         .operands_in(vec![MemFlags, x, p, Offset])
955         .can_store(true),
956     );
957 
958     ig.push(
959         Inst::new(
960             "istore8_complex",
961             r#"
962         Store the low 8 bits of ``x`` to memory at ``sum(args) + Offset``.
963 
964         This is equivalent to ``ireduce.i8`` followed by ``store.i8``.
965         "#,
966             &formats.store_complex,
967         )
968         .operands_in(vec![MemFlags, x, args, Offset])
969         .can_store(true),
970     );
971 
972     let iExt16 = &TypeVar::new(
973         "iExt16",
974         "An integer type with more than 16 bits",
975         TypeSetBuilder::new().ints(32..64).build(),
976     );
977     let x = &Operand::new("x", iExt16);
978     let a = &Operand::new("a", iExt16);
979 
980     ig.push(
981         Inst::new(
982             "uload16",
983             r#"
984         Load 16 bits from memory at ``p + Offset`` and zero-extend.
985 
986         This is equivalent to ``load.i16`` followed by ``uextend``.
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             "uload16_complex",
998             r#"
999         Load 16 bits from memory at ``sum(args) + Offset`` and zero-extend.
1000 
1001         This is equivalent to ``load.i16`` followed by ``uextend``.
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             "sload16",
1013             r#"
1014         Load 16 bits from memory at ``p + Offset`` and sign-extend.
1015 
1016         This is equivalent to ``load.i16`` followed by ``sextend``.
1017         "#,
1018             &formats.load,
1019         )
1020         .operands_in(vec![MemFlags, p, Offset])
1021         .operands_out(vec![a])
1022         .can_load(true),
1023     );
1024 
1025     ig.push(
1026         Inst::new(
1027             "sload16_complex",
1028             r#"
1029         Load 16 bits from memory at ``sum(args) + Offset`` and sign-extend.
1030 
1031         This is equivalent to ``load.i16`` followed by ``sextend``.
1032         "#,
1033             &formats.load_complex,
1034         )
1035         .operands_in(vec![MemFlags, args, Offset])
1036         .operands_out(vec![a])
1037         .can_load(true),
1038     );
1039 
1040     ig.push(
1041         Inst::new(
1042             "istore16",
1043             r#"
1044         Store the low 16 bits of ``x`` to memory at ``p + Offset``.
1045 
1046         This is equivalent to ``ireduce.i16`` followed by ``store.i16``.
1047         "#,
1048             &formats.store,
1049         )
1050         .operands_in(vec![MemFlags, x, p, Offset])
1051         .can_store(true),
1052     );
1053 
1054     ig.push(
1055         Inst::new(
1056             "istore16_complex",
1057             r#"
1058         Store the low 16 bits of ``x`` to memory at ``sum(args) + Offset``.
1059 
1060         This is equivalent to ``ireduce.i16`` followed by ``store.i16``.
1061         "#,
1062             &formats.store_complex,
1063         )
1064         .operands_in(vec![MemFlags, x, args, Offset])
1065         .can_store(true),
1066     );
1067 
1068     let iExt32 = &TypeVar::new(
1069         "iExt32",
1070         "An integer type with more than 32 bits",
1071         TypeSetBuilder::new().ints(64..64).build(),
1072     );
1073     let x = &Operand::new("x", iExt32);
1074     let a = &Operand::new("a", iExt32);
1075 
1076     ig.push(
1077         Inst::new(
1078             "uload32",
1079             r#"
1080         Load 32 bits from memory at ``p + Offset`` and zero-extend.
1081 
1082         This is equivalent to ``load.i32`` followed by ``uextend``.
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             "uload32_complex",
1094             r#"
1095         Load 32 bits from memory at ``sum(args) + Offset`` and zero-extend.
1096 
1097         This is equivalent to ``load.i32`` followed by ``uextend``.
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             "sload32",
1109             r#"
1110         Load 32 bits from memory at ``p + Offset`` and sign-extend.
1111 
1112         This is equivalent to ``load.i32`` followed by ``sextend``.
1113         "#,
1114             &formats.load,
1115         )
1116         .operands_in(vec![MemFlags, p, Offset])
1117         .operands_out(vec![a])
1118         .can_load(true),
1119     );
1120 
1121     ig.push(
1122         Inst::new(
1123             "sload32_complex",
1124             r#"
1125         Load 32 bits from memory at ``sum(args) + Offset`` and sign-extend.
1126 
1127         This is equivalent to ``load.i32`` followed by ``sextend``.
1128         "#,
1129             &formats.load_complex,
1130         )
1131         .operands_in(vec![MemFlags, args, Offset])
1132         .operands_out(vec![a])
1133         .can_load(true),
1134     );
1135 
1136     ig.push(
1137         Inst::new(
1138             "istore32",
1139             r#"
1140         Store the low 32 bits of ``x`` to memory at ``p + Offset``.
1141 
1142         This is equivalent to ``ireduce.i32`` followed by ``store.i32``.
1143         "#,
1144             &formats.store,
1145         )
1146         .operands_in(vec![MemFlags, x, p, Offset])
1147         .can_store(true),
1148     );
1149 
1150     ig.push(
1151         Inst::new(
1152             "istore32_complex",
1153             r#"
1154         Store the low 32 bits of ``x`` to memory at ``sum(args) + Offset``.
1155 
1156         This is equivalent to ``ireduce.i32`` followed by ``store.i32``.
1157         "#,
1158             &formats.store_complex,
1159         )
1160         .operands_in(vec![MemFlags, x, args, Offset])
1161         .can_store(true),
1162     );
1163 
1164     let I16x8 = &TypeVar::new(
1165         "I16x8",
1166         "A SIMD vector with exactly 8 lanes of 16-bit values",
1167         TypeSetBuilder::new()
1168             .ints(16..16)
1169             .simd_lanes(8..8)
1170             .includes_scalars(false)
1171             .build(),
1172     );
1173     let a = &Operand::new("a", I16x8).with_doc("Value loaded");
1174 
1175     ig.push(
1176         Inst::new(
1177             "uload8x8",
1178             r#"
1179         Load an 8x8 vector (64 bits) from memory at ``p + Offset`` and zero-extend into an i16x8
1180         vector.
1181         "#,
1182             &formats.load,
1183         )
1184         .operands_in(vec![MemFlags, p, Offset])
1185         .operands_out(vec![a])
1186         .can_load(true),
1187     );
1188 
1189     ig.push(
1190         Inst::new(
1191             "uload8x8_complex",
1192             r#"
1193         Load an 8x8 vector (64 bits) from memory at ``sum(args) + Offset`` and zero-extend into an
1194         i16x8 vector.
1195         "#,
1196             &formats.load_complex,
1197         )
1198         .operands_in(vec![MemFlags, args, Offset])
1199         .operands_out(vec![a])
1200         .can_load(true),
1201     );
1202 
1203     ig.push(
1204         Inst::new(
1205             "sload8x8",
1206             r#"
1207         Load an 8x8 vector (64 bits) from memory at ``p + Offset`` and sign-extend into an i16x8
1208         vector.
1209         "#,
1210             &formats.load,
1211         )
1212         .operands_in(vec![MemFlags, p, Offset])
1213         .operands_out(vec![a])
1214         .can_load(true),
1215     );
1216 
1217     ig.push(
1218         Inst::new(
1219             "sload8x8_complex",
1220             r#"
1221         Load an 8x8 vector (64 bits) from memory at ``sum(args) + Offset`` and sign-extend into an
1222         i16x8 vector.
1223         "#,
1224             &formats.load_complex,
1225         )
1226         .operands_in(vec![MemFlags, args, Offset])
1227         .operands_out(vec![a])
1228         .can_load(true),
1229     );
1230 
1231     let I32x4 = &TypeVar::new(
1232         "I32x4",
1233         "A SIMD vector with exactly 4 lanes of 32-bit values",
1234         TypeSetBuilder::new()
1235             .ints(32..32)
1236             .simd_lanes(4..4)
1237             .includes_scalars(false)
1238             .build(),
1239     );
1240     let a = &Operand::new("a", I32x4).with_doc("Value loaded");
1241 
1242     ig.push(
1243         Inst::new(
1244             "uload16x4",
1245             r#"
1246         Load a 16x4 vector (64 bits) from memory at ``p + Offset`` and zero-extend into an i32x4
1247         vector.
1248         "#,
1249             &formats.load,
1250         )
1251         .operands_in(vec![MemFlags, p, Offset])
1252         .operands_out(vec![a])
1253         .can_load(true),
1254     );
1255 
1256     ig.push(
1257         Inst::new(
1258             "uload16x4_complex",
1259             r#"
1260         Load a 16x4 vector (64 bits) from memory at ``sum(args) + Offset`` and zero-extend into an
1261         i32x4 vector.
1262         "#,
1263             &formats.load_complex,
1264         )
1265         .operands_in(vec![MemFlags, args, Offset])
1266         .operands_out(vec![a])
1267         .can_load(true),
1268     );
1269 
1270     ig.push(
1271         Inst::new(
1272             "sload16x4",
1273             r#"
1274         Load a 16x4 vector (64 bits) from memory at ``p + Offset`` and sign-extend into an i32x4
1275         vector.
1276         "#,
1277             &formats.load,
1278         )
1279         .operands_in(vec![MemFlags, p, Offset])
1280         .operands_out(vec![a])
1281         .can_load(true),
1282     );
1283 
1284     ig.push(
1285         Inst::new(
1286             "sload16x4_complex",
1287             r#"
1288         Load a 16x4 vector (64 bits) from memory at ``sum(args) + Offset`` and sign-extend into an
1289         i32x4 vector.
1290         "#,
1291             &formats.load_complex,
1292         )
1293         .operands_in(vec![MemFlags, args, Offset])
1294         .operands_out(vec![a])
1295         .can_load(true),
1296     );
1297 
1298     let I64x2 = &TypeVar::new(
1299         "I64x2",
1300         "A SIMD vector with exactly 2 lanes of 64-bit values",
1301         TypeSetBuilder::new()
1302             .ints(64..64)
1303             .simd_lanes(2..2)
1304             .includes_scalars(false)
1305             .build(),
1306     );
1307     let a = &Operand::new("a", I64x2).with_doc("Value loaded");
1308 
1309     ig.push(
1310         Inst::new(
1311             "uload32x2",
1312             r#"
1313         Load an 32x2 vector (64 bits) from memory at ``p + Offset`` and zero-extend into an i64x2
1314         vector.
1315         "#,
1316             &formats.load,
1317         )
1318         .operands_in(vec![MemFlags, p, Offset])
1319         .operands_out(vec![a])
1320         .can_load(true),
1321     );
1322 
1323     ig.push(
1324         Inst::new(
1325             "uload32x2_complex",
1326             r#"
1327         Load a 32x2 vector (64 bits) from memory at ``sum(args) + Offset`` and zero-extend into an
1328         i64x2 vector.
1329         "#,
1330             &formats.load_complex,
1331         )
1332         .operands_in(vec![MemFlags, args, Offset])
1333         .operands_out(vec![a])
1334         .can_load(true),
1335     );
1336 
1337     ig.push(
1338         Inst::new(
1339             "sload32x2",
1340             r#"
1341         Load a 32x2 vector (64 bits) from memory at ``p + Offset`` and sign-extend into an i64x2
1342         vector.
1343         "#,
1344             &formats.load,
1345         )
1346         .operands_in(vec![MemFlags, p, Offset])
1347         .operands_out(vec![a])
1348         .can_load(true),
1349     );
1350 
1351     ig.push(
1352         Inst::new(
1353             "sload32x2_complex",
1354             r#"
1355         Load a 32x2 vector (64 bits) from memory at ``sum(args) + Offset`` and sign-extend into an
1356         i64x2 vector.
1357         "#,
1358             &formats.load_complex,
1359         )
1360         .operands_in(vec![MemFlags, args, Offset])
1361         .operands_out(vec![a])
1362         .can_load(true),
1363     );
1364 
1365     let x = &Operand::new("x", Mem).with_doc("Value to be stored");
1366     let a = &Operand::new("a", Mem).with_doc("Value loaded");
1367     let Offset =
1368         &Operand::new("Offset", &imm.offset32).with_doc("In-bounds offset into stack slot");
1369 
1370     ig.push(
1371         Inst::new(
1372             "stack_load",
1373             r#"
1374         Load a value from a stack slot at the constant offset.
1375 
1376         This is a polymorphic instruction that can load any value type which
1377         has a memory representation.
1378 
1379         The offset is an immediate constant, not an SSA value. The memory
1380         access cannot go out of bounds, i.e.
1381         `sizeof(a) + Offset <= sizeof(SS)`.
1382         "#,
1383             &formats.stack_load,
1384         )
1385         .operands_in(vec![SS, Offset])
1386         .operands_out(vec![a])
1387         .can_load(true),
1388     );
1389 
1390     ig.push(
1391         Inst::new(
1392             "stack_store",
1393             r#"
1394         Store a value to a stack slot at a constant offset.
1395 
1396         This is a polymorphic instruction that can store any value type with a
1397         memory representation.
1398 
1399         The offset is an immediate constant, not an SSA value. The memory
1400         access cannot go out of bounds, i.e.
1401         `sizeof(a) + Offset <= sizeof(SS)`.
1402         "#,
1403             &formats.stack_store,
1404         )
1405         .operands_in(vec![x, SS, Offset])
1406         .can_store(true),
1407     );
1408 
1409     ig.push(
1410         Inst::new(
1411             "stack_addr",
1412             r#"
1413         Get the address of a stack slot.
1414 
1415         Compute the absolute address of a byte in a stack slot. The offset must
1416         refer to a byte inside the stack slot:
1417         `0 <= Offset < sizeof(SS)`.
1418         "#,
1419             &formats.stack_load,
1420         )
1421         .operands_in(vec![SS, Offset])
1422         .operands_out(vec![addr]),
1423     );
1424 
1425     let GV = &Operand::new("GV", &entities.global_value);
1426 
1427     ig.push(
1428         Inst::new(
1429             "global_value",
1430             r#"
1431         Compute the value of global GV.
1432         "#,
1433             &formats.unary_global_value,
1434         )
1435         .operands_in(vec![GV])
1436         .operands_out(vec![a]),
1437     );
1438 
1439     ig.push(
1440         Inst::new(
1441             "symbol_value",
1442             r#"
1443         Compute the value of global GV, which is a symbolic value.
1444         "#,
1445             &formats.unary_global_value,
1446         )
1447         .operands_in(vec![GV])
1448         .operands_out(vec![a]),
1449     );
1450 
1451     ig.push(
1452         Inst::new(
1453             "tls_value",
1454             r#"
1455         Compute the value of global GV, which is a TLS (thread local storage) value.
1456         "#,
1457             &formats.unary_global_value,
1458         )
1459         .operands_in(vec![GV])
1460         .operands_out(vec![a]),
1461     );
1462 
1463     let HeapOffset = &TypeVar::new(
1464         "HeapOffset",
1465         "An unsigned heap offset",
1466         TypeSetBuilder::new().ints(32..64).build(),
1467     );
1468 
1469     let H = &Operand::new("H", &entities.heap);
1470     let p = &Operand::new("p", HeapOffset);
1471     let Size = &Operand::new("Size", &imm.uimm32).with_doc("Size in bytes");
1472 
1473     ig.push(
1474         Inst::new(
1475             "heap_addr",
1476             r#"
1477         Bounds check and compute absolute address of heap memory.
1478 
1479         Verify that the offset range ``p .. p + Size - 1`` is in bounds for the
1480         heap H, and generate an absolute address that is safe to dereference.
1481 
1482         1. If ``p + Size`` is not greater than the heap bound, return an
1483            absolute address corresponding to a byte offset of ``p`` from the
1484            heap's base address.
1485         2. If ``p + Size`` is greater than the heap bound, generate a trap.
1486         "#,
1487             &formats.heap_addr,
1488         )
1489         .operands_in(vec![H, p, Size])
1490         .operands_out(vec![addr]),
1491     );
1492 
1493     // Note this instruction is marked as having other side-effects, so GVN won't try to hoist it,
1494     // which would result in it being subject to spilling. While not hoisting would generally hurt
1495     // performance, since a computed value used many times may need to be regenerated before each
1496     // use, it is not the case here: this instruction doesn't generate any code.  That's because,
1497     // by definition the pinned register is never used by the register allocator, but is written to
1498     // and read explicitly and exclusively by set_pinned_reg and get_pinned_reg.
1499     ig.push(
1500         Inst::new(
1501             "get_pinned_reg",
1502             r#"
1503             Gets the content of the pinned register, when it's enabled.
1504         "#,
1505             &formats.nullary,
1506         )
1507         .operands_out(vec![addr])
1508         .other_side_effects(true),
1509     );
1510 
1511     ig.push(
1512         Inst::new(
1513             "set_pinned_reg",
1514             r#"
1515         Sets the content of the pinned register, when it's enabled.
1516         "#,
1517             &formats.unary,
1518         )
1519         .operands_in(vec![addr])
1520         .other_side_effects(true),
1521     );
1522 
1523     let TableOffset = &TypeVar::new(
1524         "TableOffset",
1525         "An unsigned table offset",
1526         TypeSetBuilder::new().ints(32..64).build(),
1527     );
1528     let T = &Operand::new("T", &entities.table);
1529     let p = &Operand::new("p", TableOffset);
1530     let Offset =
1531         &Operand::new("Offset", &imm.offset32).with_doc("Byte offset from element address");
1532 
1533     ig.push(
1534         Inst::new(
1535             "table_addr",
1536             r#"
1537         Bounds check and compute absolute address of a table entry.
1538 
1539         Verify that the offset ``p`` is in bounds for the table T, and generate
1540         an absolute address that is safe to dereference.
1541 
1542         ``Offset`` must be less than the size of a table element.
1543 
1544         1. If ``p`` is not greater than the table bound, return an absolute
1545            address corresponding to a byte offset of ``p`` from the table's
1546            base address.
1547         2. If ``p`` is greater than the table bound, generate a trap.
1548         "#,
1549             &formats.table_addr,
1550         )
1551         .operands_in(vec![T, p, Offset])
1552         .operands_out(vec![addr]),
1553     );
1554 
1555     let N = &Operand::new("N", &imm.imm64);
1556     let a = &Operand::new("a", Int).with_doc("A constant integer scalar or vector value");
1557 
1558     ig.push(
1559         Inst::new(
1560             "iconst",
1561             r#"
1562         Integer constant.
1563 
1564         Create a scalar integer SSA value with an immediate constant value, or
1565         an integer vector where all the lanes have the same value.
1566         "#,
1567             &formats.unary_imm,
1568         )
1569         .operands_in(vec![N])
1570         .operands_out(vec![a]),
1571     );
1572 
1573     let N = &Operand::new("N", &imm.ieee32);
1574     let a = &Operand::new("a", f32_).with_doc("A constant f32 scalar value");
1575 
1576     ig.push(
1577         Inst::new(
1578             "f32const",
1579             r#"
1580         Floating point constant.
1581 
1582         Create a `f32` SSA value with an immediate constant value.
1583         "#,
1584             &formats.unary_ieee32,
1585         )
1586         .operands_in(vec![N])
1587         .operands_out(vec![a]),
1588     );
1589 
1590     let N = &Operand::new("N", &imm.ieee64);
1591     let a = &Operand::new("a", f64_).with_doc("A constant f64 scalar value");
1592 
1593     ig.push(
1594         Inst::new(
1595             "f64const",
1596             r#"
1597         Floating point constant.
1598 
1599         Create a `f64` SSA value with an immediate constant value.
1600         "#,
1601             &formats.unary_ieee64,
1602         )
1603         .operands_in(vec![N])
1604         .operands_out(vec![a]),
1605     );
1606 
1607     let N = &Operand::new("N", &imm.boolean);
1608     let a = &Operand::new("a", Bool).with_doc("A constant boolean scalar or vector value");
1609 
1610     ig.push(
1611         Inst::new(
1612             "bconst",
1613             r#"
1614         Boolean constant.
1615 
1616         Create a scalar boolean SSA value with an immediate constant value, or
1617         a boolean vector where all the lanes have the same value.
1618         "#,
1619             &formats.unary_bool,
1620         )
1621         .operands_in(vec![N])
1622         .operands_out(vec![a]),
1623     );
1624 
1625     let N = &Operand::new("N", &imm.pool_constant)
1626         .with_doc("The 16 immediate bytes of a 128-bit vector");
1627     let a = &Operand::new("a", TxN).with_doc("A constant vector value");
1628 
1629     ig.push(
1630         Inst::new(
1631             "vconst",
1632             r#"
1633         SIMD vector constant.
1634 
1635         Construct a vector with the given immediate bytes.
1636         "#,
1637             &formats.unary_const,
1638         )
1639         .operands_in(vec![N])
1640         .operands_out(vec![a]),
1641     );
1642 
1643     let constant =
1644         &Operand::new("constant", &imm.pool_constant).with_doc("A constant in the constant pool");
1645     let address = &Operand::new("address", iAddr);
1646     ig.push(
1647         Inst::new(
1648             "const_addr",
1649             r#"
1650         Calculate the base address of a value in the constant pool.
1651         "#,
1652             &formats.unary_const,
1653         )
1654         .operands_in(vec![constant])
1655         .operands_out(vec![address]),
1656     );
1657 
1658     let mask = &Operand::new("mask", &imm.uimm128)
1659         .with_doc("The 16 immediate bytes used for selecting the elements to shuffle");
1660     let Tx16 = &TypeVar::new(
1661         "Tx16",
1662         "A SIMD vector with exactly 16 lanes of 8-bit values; eventually this may support other \
1663          lane counts and widths",
1664         TypeSetBuilder::new()
1665             .ints(8..8)
1666             .bools(8..8)
1667             .simd_lanes(16..16)
1668             .includes_scalars(false)
1669             .build(),
1670     );
1671     let a = &Operand::new("a", Tx16).with_doc("A vector value");
1672     let b = &Operand::new("b", Tx16).with_doc("A vector value");
1673 
1674     ig.push(
1675         Inst::new(
1676             "shuffle",
1677             r#"
1678         SIMD vector shuffle.
1679 
1680         Shuffle two vectors using the given immediate bytes. For each of the 16 bytes of the
1681         immediate, a value i of 0-15 selects the i-th element of the first vector and a value i of
1682         16-31 selects the (i-16)th element of the second vector. Immediate values outside of the
1683         0-31 range place a 0 in the resulting vector lane.
1684         "#,
1685             &formats.shuffle,
1686         )
1687         .operands_in(vec![a, b, mask])
1688         .operands_out(vec![a]),
1689     );
1690 
1691     let a = &Operand::new("a", Ref).with_doc("A constant reference null value");
1692 
1693     ig.push(
1694         Inst::new(
1695             "null",
1696             r#"
1697         Null constant value for reference types.
1698 
1699         Create a scalar reference SSA value with a constant null value.
1700         "#,
1701             &formats.nullary,
1702         )
1703         .operands_out(vec![a]),
1704     );
1705 
1706     ig.push(Inst::new(
1707         "nop",
1708         r#"
1709         Just a dummy instruction.
1710 
1711         Note: this doesn't compile to a machine code nop.
1712         "#,
1713         &formats.nullary,
1714     ));
1715 
1716     let c = &Operand::new("c", Testable).with_doc("Controlling value to test");
1717     let x = &Operand::new("x", Any).with_doc("Value to use when `c` is true");
1718     let y = &Operand::new("y", Any).with_doc("Value to use when `c` is false");
1719     let a = &Operand::new("a", Any);
1720 
1721     ig.push(
1722         Inst::new(
1723             "select",
1724             r#"
1725         Conditional select.
1726 
1727         This instruction selects whole values. Use `vselect` for
1728         lane-wise selection.
1729         "#,
1730             &formats.ternary,
1731         )
1732         .operands_in(vec![c, x, y])
1733         .operands_out(vec![a]),
1734     );
1735 
1736     let cc = &Operand::new("cc", &imm.intcc).with_doc("Controlling condition code");
1737     let flags = &Operand::new("flags", iflags).with_doc("The machine's flag register");
1738 
1739     ig.push(
1740         Inst::new(
1741             "selectif",
1742             r#"
1743         Conditional select, dependent on integer condition codes.
1744         "#,
1745             &formats.int_select,
1746         )
1747         .operands_in(vec![cc, flags, x, y])
1748         .operands_out(vec![a]),
1749     );
1750 
1751     ig.push(
1752         Inst::new(
1753             "selectif_spectre_guard",
1754             r#"
1755             Conditional select intended for Spectre guards.
1756 
1757             This operation is semantically equivalent to a selectif instruction.
1758             However, it is guaranteed to not be removed or otherwise altered by any
1759             optimization pass, and is guaranteed to result in a conditional-move
1760             instruction, not a branch-based lowering.  As such, it is suitable
1761             for use when producing Spectre guards. For example, a bounds-check
1762             may guard against unsafe speculation past a bounds-check conditional
1763             branch by passing the address or index to be accessed through a
1764             conditional move, also gated on the same condition. Because no
1765             Spectre-vulnerable processors are known to perform speculation on
1766             conditional move instructions, this is guaranteed to pick the
1767             correct input. If the selected input in case of overflow is a "safe"
1768             value, for example a null pointer that causes an exception in the
1769             speculative path, this ensures that no Spectre vulnerability will
1770             exist.
1771             "#,
1772             &formats.int_select,
1773         )
1774         .operands_in(vec![cc, flags, x, y])
1775         .operands_out(vec![a])
1776         .other_side_effects(true),
1777     );
1778 
1779     let c = &Operand::new("c", Any).with_doc("Controlling value to test");
1780     ig.push(
1781         Inst::new(
1782             "bitselect",
1783             r#"
1784         Conditional select of bits.
1785 
1786         For each bit in `c`, this instruction selects the corresponding bit from `x` if the bit
1787         in `c` is 1 and the corresponding bit from `y` if the bit in `c` is 0. See also:
1788         `select`, `vselect`.
1789         "#,
1790             &formats.ternary,
1791         )
1792         .operands_in(vec![c, x, y])
1793         .operands_out(vec![a]),
1794     );
1795 
1796     let x = &Operand::new("x", Any);
1797 
1798     ig.push(
1799         Inst::new(
1800             "copy",
1801             r#"
1802         Register-register copy.
1803 
1804         This instruction copies its input, preserving the value type.
1805 
1806         A pure SSA-form program does not need to copy values, but this
1807         instruction is useful for representing intermediate stages during
1808         instruction transformations, and the register allocator needs a way of
1809         representing register copies.
1810         "#,
1811             &formats.unary,
1812         )
1813         .operands_in(vec![x])
1814         .operands_out(vec![a]),
1815     );
1816 
1817     ig.push(
1818         Inst::new(
1819             "spill",
1820             r#"
1821         Spill a register value to a stack slot.
1822 
1823         This instruction behaves exactly like `copy`, but the result
1824         value is assigned to a spill slot.
1825         "#,
1826             &formats.unary,
1827         )
1828         .operands_in(vec![x])
1829         .operands_out(vec![a])
1830         .can_store(true),
1831     );
1832 
1833     ig.push(
1834         Inst::new(
1835             "fill",
1836             r#"
1837         Load a register value from a stack slot.
1838 
1839         This instruction behaves exactly like `copy`, but creates a new
1840         SSA value for the spilled input value.
1841         "#,
1842             &formats.unary,
1843         )
1844         .operands_in(vec![x])
1845         .operands_out(vec![a])
1846         .can_load(true),
1847     );
1848 
1849     ig.push(
1850         Inst::new(
1851             "fill_nop",
1852             r#"
1853         This is identical to `fill`, except it has no encoding, since it is a no-op.
1854 
1855         This instruction is created only during late-stage redundant-reload removal, after all
1856         registers and stack slots have been assigned.  It is used to replace `fill`s that have
1857         been identified as redundant.
1858         "#,
1859             &formats.unary,
1860         )
1861         .operands_in(vec![x])
1862         .operands_out(vec![a])
1863         .can_load(true),
1864     );
1865 
1866     let Sarg = &TypeVar::new(
1867         "Sarg",
1868         "Any scalar or vector type with at most 128 lanes",
1869         TypeSetBuilder::new()
1870             .specials(vec![crate::cdsl::types::SpecialType::StructArgument])
1871             .build(),
1872     );
1873     let sarg_t = &Operand::new("sarg_t", Sarg);
1874 
1875     // FIXME remove once the old style codegen backends are removed.
1876     ig.push(
1877         Inst::new(
1878             "dummy_sarg_t",
1879             r#"
1880         This creates a sarg_t
1881 
1882         This instruction is internal and should not be created by
1883         Cranelift users.
1884         "#,
1885             &formats.nullary,
1886         )
1887         .operands_in(vec![])
1888         .operands_out(vec![sarg_t]),
1889     );
1890 
1891     let src = &Operand::new("src", &imm.regunit);
1892     let dst = &Operand::new("dst", &imm.regunit);
1893 
1894     ig.push(
1895         Inst::new(
1896             "regmove",
1897             r#"
1898         Temporarily divert ``x`` from ``src`` to ``dst``.
1899 
1900         This instruction moves the location of a value from one register to
1901         another without creating a new SSA value. It is used by the register
1902         allocator to temporarily rearrange register assignments in order to
1903         satisfy instruction constraints.
1904 
1905         The register diversions created by this instruction must be undone
1906         before the value leaves the block. At the entry to a new block, all live
1907         values must be in their originally assigned registers.
1908         "#,
1909             &formats.reg_move,
1910         )
1911         .operands_in(vec![x, src, dst])
1912         .other_side_effects(true),
1913     );
1914 
1915     ig.push(
1916         Inst::new(
1917             "copy_special",
1918             r#"
1919         Copies the contents of ''src'' register to ''dst'' register.
1920 
1921         This instructions copies the contents of one register to another
1922         register without involving any SSA values. This is used for copying
1923         special registers, e.g. copying the stack register to the frame
1924         register in a function prologue.
1925         "#,
1926             &formats.copy_special,
1927         )
1928         .operands_in(vec![src, dst])
1929         .other_side_effects(true),
1930     );
1931 
1932     ig.push(
1933         Inst::new(
1934             "copy_to_ssa",
1935             r#"
1936         Copies the contents of ''src'' register to ''a'' SSA name.
1937 
1938         This instruction copies the contents of one register, regardless of its SSA name, to
1939         another register, creating a new SSA name.  In that sense it is a one-sided version
1940         of ''copy_special''.  This instruction is internal and should not be created by
1941         Cranelift users.
1942         "#,
1943             &formats.copy_to_ssa,
1944         )
1945         .operands_in(vec![src])
1946         .operands_out(vec![a])
1947         .other_side_effects(true),
1948     );
1949 
1950     ig.push(
1951         Inst::new(
1952             "copy_nop",
1953             r#"
1954         Stack-slot-to-the-same-stack-slot copy, which is guaranteed to turn
1955         into a no-op.  This instruction is for use only within Cranelift itself.
1956 
1957         This instruction copies its input, preserving the value type.
1958         "#,
1959             &formats.unary,
1960         )
1961         .operands_in(vec![x])
1962         .operands_out(vec![a]),
1963     );
1964 
1965     let delta = &Operand::new("delta", Int);
1966 
1967     ig.push(
1968         Inst::new(
1969             "adjust_sp_down",
1970             r#"
1971     Subtracts ``delta`` offset value from the stack pointer register.
1972 
1973     This instruction is used to adjust the stack pointer by a dynamic amount.
1974     "#,
1975             &formats.unary,
1976         )
1977         .operands_in(vec![delta])
1978         .other_side_effects(true),
1979     );
1980 
1981     let Offset = &Operand::new("Offset", &imm.imm64).with_doc("Offset from current stack pointer");
1982 
1983     ig.push(
1984         Inst::new(
1985             "adjust_sp_up_imm",
1986             r#"
1987     Adds ``Offset`` immediate offset value to the stack pointer register.
1988 
1989     This instruction is used to adjust the stack pointer, primarily in function
1990     prologues and epilogues. ``Offset`` is constrained to the size of a signed
1991     32-bit integer.
1992     "#,
1993             &formats.unary_imm,
1994         )
1995         .operands_in(vec![Offset])
1996         .other_side_effects(true),
1997     );
1998 
1999     let Offset = &Operand::new("Offset", &imm.imm64).with_doc("Offset from current stack pointer");
2000 
2001     ig.push(
2002         Inst::new(
2003             "adjust_sp_down_imm",
2004             r#"
2005     Subtracts ``Offset`` immediate offset value from the stack pointer
2006     register.
2007 
2008     This instruction is used to adjust the stack pointer, primarily in function
2009     prologues and epilogues. ``Offset`` is constrained to the size of a signed
2010     32-bit integer.
2011     "#,
2012             &formats.unary_imm,
2013         )
2014         .operands_in(vec![Offset])
2015         .other_side_effects(true),
2016     );
2017 
2018     let f = &Operand::new("f", iflags);
2019 
2020     ig.push(
2021         Inst::new(
2022             "ifcmp_sp",
2023             r#"
2024     Compare ``addr`` with the stack pointer and set the CPU flags.
2025 
2026     This is like `ifcmp` where ``addr`` is the LHS operand and the stack
2027     pointer is the RHS.
2028     "#,
2029             &formats.unary,
2030         )
2031         .operands_in(vec![addr])
2032         .operands_out(vec![f]),
2033     );
2034 
2035     ig.push(
2036         Inst::new(
2037             "regspill",
2038             r#"
2039         Temporarily divert ``x`` from ``src`` to ``SS``.
2040 
2041         This instruction moves the location of a value from a register to a
2042         stack slot without creating a new SSA value. It is used by the register
2043         allocator to temporarily rearrange register assignments in order to
2044         satisfy instruction constraints.
2045 
2046         See also `regmove`.
2047         "#,
2048             &formats.reg_spill,
2049         )
2050         .operands_in(vec![x, src, SS])
2051         .other_side_effects(true),
2052     );
2053 
2054     ig.push(
2055         Inst::new(
2056             "regfill",
2057             r#"
2058         Temporarily divert ``x`` from ``SS`` to ``dst``.
2059 
2060         This instruction moves the location of a value from a stack slot to a
2061         register without creating a new SSA value. It is used by the register
2062         allocator to temporarily rearrange register assignments in order to
2063         satisfy instruction constraints.
2064 
2065         See also `regmove`.
2066         "#,
2067             &formats.reg_fill,
2068         )
2069         .operands_in(vec![x, SS, dst])
2070         .other_side_effects(true),
2071     );
2072 
2073     let N =
2074         &Operand::new("args", &entities.varargs).with_doc("Variable number of args for StackMap");
2075 
2076     ig.push(
2077         Inst::new(
2078             "safepoint",
2079             r#"
2080         This instruction will provide live reference values at a point in
2081         the function. It can only be used by the compiler.
2082         "#,
2083             &formats.multiary,
2084         )
2085         .operands_in(vec![N])
2086         .other_side_effects(true),
2087     );
2088 
2089     let x = &Operand::new("x", TxN).with_doc("Vector to split");
2090     let lo = &Operand::new("lo", &TxN.half_vector()).with_doc("Low-numbered lanes of `x`");
2091     let hi = &Operand::new("hi", &TxN.half_vector()).with_doc("High-numbered lanes of `x`");
2092 
2093     ig.push(
2094         Inst::new(
2095             "vsplit",
2096             r#"
2097         Split a vector into two halves.
2098 
2099         Split the vector `x` into two separate values, each containing half of
2100         the lanes from ``x``. The result may be two scalars if ``x`` only had
2101         two lanes.
2102         "#,
2103             &formats.unary,
2104         )
2105         .operands_in(vec![x])
2106         .operands_out(vec![lo, hi])
2107         .is_ghost(true),
2108     );
2109 
2110     let Any128 = &TypeVar::new(
2111         "Any128",
2112         "Any scalar or vector type with as most 128 lanes",
2113         TypeSetBuilder::new()
2114             .ints(Interval::All)
2115             .floats(Interval::All)
2116             .bools(Interval::All)
2117             .simd_lanes(1..128)
2118             .includes_scalars(true)
2119             .build(),
2120     );
2121 
2122     let x = &Operand::new("x", Any128).with_doc("Low-numbered lanes");
2123     let y = &Operand::new("y", Any128).with_doc("High-numbered lanes");
2124     let a = &Operand::new("a", &Any128.double_vector()).with_doc("Concatenation of `x` and `y`");
2125 
2126     ig.push(
2127         Inst::new(
2128             "vconcat",
2129             r#"
2130         Vector concatenation.
2131 
2132         Return a vector formed by concatenating ``x`` and ``y``. The resulting
2133         vector type has twice as many lanes as each of the inputs. The lanes of
2134         ``x`` appear as the low-numbered lanes, and the lanes of ``y`` become
2135         the high-numbered lanes of ``a``.
2136 
2137         It is possible to form a vector by concatenating two scalars.
2138         "#,
2139             &formats.binary,
2140         )
2141         .operands_in(vec![x, y])
2142         .operands_out(vec![a])
2143         .is_ghost(true),
2144     );
2145 
2146     let c = &Operand::new("c", &TxN.as_bool()).with_doc("Controlling vector");
2147     let x = &Operand::new("x", TxN).with_doc("Value to use where `c` is true");
2148     let y = &Operand::new("y", TxN).with_doc("Value to use where `c` is false");
2149     let a = &Operand::new("a", TxN);
2150 
2151     ig.push(
2152         Inst::new(
2153             "vselect",
2154             r#"
2155         Vector lane select.
2156 
2157         Select lanes from ``x`` or ``y`` controlled by the lanes of the boolean
2158         vector ``c``.
2159         "#,
2160             &formats.ternary,
2161         )
2162         .operands_in(vec![c, x, y])
2163         .operands_out(vec![a]),
2164     );
2165 
2166     let s = &Operand::new("s", b1);
2167 
2168     ig.push(
2169         Inst::new(
2170             "vany_true",
2171             r#"
2172         Reduce a vector to a scalar boolean.
2173 
2174         Return a scalar boolean true if any lane in ``a`` is non-zero, false otherwise.
2175         "#,
2176             &formats.unary,
2177         )
2178         .operands_in(vec![a])
2179         .operands_out(vec![s]),
2180     );
2181 
2182     ig.push(
2183         Inst::new(
2184             "vall_true",
2185             r#"
2186         Reduce a vector to a scalar boolean.
2187 
2188         Return a scalar boolean true if all lanes in ``i`` are non-zero, false otherwise.
2189         "#,
2190             &formats.unary,
2191         )
2192         .operands_in(vec![a])
2193         .operands_out(vec![s]),
2194     );
2195 
2196     let a = &Operand::new("a", TxN);
2197     let x = &Operand::new("x", Int);
2198 
2199     ig.push(
2200         Inst::new(
2201             "vhigh_bits",
2202             r#"
2203         Reduce a vector to a scalar integer.
2204 
2205         Return a scalar integer, consisting of the concatenation of the most significant bit
2206         of each lane of ``a``.
2207         "#,
2208             &formats.unary,
2209         )
2210         .operands_in(vec![a])
2211         .operands_out(vec![x]),
2212     );
2213 
2214     let a = &Operand::new("a", &Int.as_bool());
2215     let Cond = &Operand::new("Cond", &imm.intcc);
2216     let x = &Operand::new("x", Int);
2217     let y = &Operand::new("y", Int);
2218 
2219     ig.push(
2220         Inst::new(
2221             "icmp",
2222             r#"
2223         Integer comparison.
2224 
2225         The condition code determines if the operands are interpreted as signed
2226         or unsigned integers.
2227 
2228         | Signed | Unsigned | Condition             |
2229         |--------|----------|-----------------------|
2230         | eq     | eq       | Equal                 |
2231         | ne     | ne       | Not equal             |
2232         | slt    | ult      | Less than             |
2233         | sge    | uge      | Greater than or equal |
2234         | sgt    | ugt      | Greater than          |
2235         | sle    | ule      | Less than or equal    |
2236         | of     | *        | Overflow              |
2237         | nof    | *        | No Overflow           |
2238 
2239         \* The unsigned version of overflow conditions have ISA-specific
2240         semantics and thus have been kept as methods on the TargetIsa trait as
2241         [unsigned_add_overflow_condition][isa::TargetIsa::unsigned_add_overflow_condition] and
2242         [unsigned_sub_overflow_condition][isa::TargetIsa::unsigned_sub_overflow_condition].
2243 
2244         When this instruction compares integer vectors, it returns a boolean
2245         vector of lane-wise comparisons.
2246         "#,
2247             &formats.int_compare,
2248         )
2249         .operands_in(vec![Cond, x, y])
2250         .operands_out(vec![a]),
2251     );
2252 
2253     let a = &Operand::new("a", b1);
2254     let x = &Operand::new("x", iB);
2255     let Y = &Operand::new("Y", &imm.imm64);
2256 
2257     ig.push(
2258         Inst::new(
2259             "icmp_imm",
2260             r#"
2261         Compare scalar integer to a constant.
2262 
2263         This is the same as the `icmp` instruction, except one operand is
2264         an immediate constant.
2265 
2266         This instruction can only compare scalars. Use `icmp` for
2267         lane-wise vector comparisons.
2268         "#,
2269             &formats.int_compare_imm,
2270         )
2271         .operands_in(vec![Cond, x, Y])
2272         .operands_out(vec![a]),
2273     );
2274 
2275     let f = &Operand::new("f", iflags);
2276     let x = &Operand::new("x", iB);
2277     let y = &Operand::new("y", iB);
2278 
2279     ig.push(
2280         Inst::new(
2281             "ifcmp",
2282             r#"
2283         Compare scalar integers and return flags.
2284 
2285         Compare two scalar integer values and return integer CPU flags
2286         representing the result.
2287         "#,
2288             &formats.binary,
2289         )
2290         .operands_in(vec![x, y])
2291         .operands_out(vec![f]),
2292     );
2293 
2294     ig.push(
2295         Inst::new(
2296             "ifcmp_imm",
2297             r#"
2298         Compare scalar integer to a constant and return flags.
2299 
2300         Like `icmp_imm`, but returns integer CPU flags instead of testing
2301         a specific condition code.
2302         "#,
2303             &formats.binary_imm64,
2304         )
2305         .operands_in(vec![x, Y])
2306         .operands_out(vec![f]),
2307     );
2308 
2309     let a = &Operand::new("a", Int);
2310     let x = &Operand::new("x", Int);
2311     let y = &Operand::new("y", Int);
2312 
2313     ig.push(
2314         Inst::new(
2315             "iadd",
2316             r#"
2317         Wrapping integer addition: `a := x + y \pmod{2^B}`.
2318 
2319         This instruction does not depend on the signed/unsigned interpretation
2320         of the operands.
2321         "#,
2322             &formats.binary,
2323         )
2324         .operands_in(vec![x, y])
2325         .operands_out(vec![a]),
2326     );
2327 
2328     ig.push(
2329         Inst::new(
2330             "uadd_sat",
2331             r#"
2332         Add with unsigned saturation.
2333 
2334         This is similar to `iadd` but the operands are interpreted as unsigned integers and their
2335         summed result, instead of wrapping, will be saturated to the highest unsigned integer for
2336         the controlling type (e.g. `0xFF` for i8).
2337         "#,
2338             &formats.binary,
2339         )
2340         .operands_in(vec![x, y])
2341         .operands_out(vec![a]),
2342     );
2343 
2344     ig.push(
2345         Inst::new(
2346             "sadd_sat",
2347             r#"
2348         Add with signed saturation.
2349 
2350         This is similar to `iadd` but the operands are interpreted as signed integers and their
2351         summed result, instead of wrapping, will be saturated to the lowest or highest
2352         signed integer for the controlling type (e.g. `0x80` or `0x7F` for i8). For example,
2353         since an `sadd_sat.i8` of `0x70` and `0x70` is greater than `0x7F`, the result will be
2354         clamped to `0x7F`.
2355         "#,
2356             &formats.binary,
2357         )
2358         .operands_in(vec![x, y])
2359         .operands_out(vec![a]),
2360     );
2361 
2362     ig.push(
2363         Inst::new(
2364             "isub",
2365             r#"
2366         Wrapping integer subtraction: `a := x - y \pmod{2^B}`.
2367 
2368         This instruction does not depend on the signed/unsigned interpretation
2369         of the operands.
2370         "#,
2371             &formats.binary,
2372         )
2373         .operands_in(vec![x, y])
2374         .operands_out(vec![a]),
2375     );
2376 
2377     ig.push(
2378         Inst::new(
2379             "usub_sat",
2380             r#"
2381         Subtract with unsigned saturation.
2382 
2383         This is similar to `isub` but the operands are interpreted as unsigned integers and their
2384         difference, instead of wrapping, will be saturated to the lowest unsigned integer for
2385         the controlling type (e.g. `0x00` for i8).
2386         "#,
2387             &formats.binary,
2388         )
2389         .operands_in(vec![x, y])
2390         .operands_out(vec![a]),
2391     );
2392 
2393     ig.push(
2394         Inst::new(
2395             "ssub_sat",
2396             r#"
2397         Subtract with signed saturation.
2398 
2399         This is similar to `isub` but the operands are interpreted as signed integers and their
2400         difference, instead of wrapping, will be saturated to the lowest or highest
2401         signed integer for the controlling type (e.g. `0x80` or `0x7F` for i8).
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     let WideInt = &TypeVar::new(
4329         "WideInt",
4330         "An integer type with lanes from `i16` upwards",
4331         TypeSetBuilder::new()
4332             .ints(16..128)
4333             .simd_lanes(Interval::All)
4334             .build(),
4335     );
4336     let x = &Operand::new("x", WideInt);
4337     let lo = &Operand::new("lo", &WideInt.half_width()).with_doc("The low bits of `x`");
4338     let hi = &Operand::new("hi", &WideInt.half_width()).with_doc("The high bits of `x`");
4339 
4340     ig.push(
4341         Inst::new(
4342             "isplit",
4343             r#"
4344         Split an integer into low and high parts.
4345 
4346         Vectors of integers are split lane-wise, so the results have the same
4347         number of lanes as the input, but the lanes are half the size.
4348 
4349         Returns the low half of `x` and the high half of `x` as two independent
4350         values.
4351         "#,
4352             &formats.unary,
4353         )
4354         .operands_in(vec![x])
4355         .operands_out(vec![lo, hi])
4356         .is_ghost(true),
4357     );
4358 
4359     let NarrowInt = &TypeVar::new(
4360         "NarrowInt",
4361         "An integer type with lanes type to `i64`",
4362         TypeSetBuilder::new()
4363             .ints(8..64)
4364             .simd_lanes(Interval::All)
4365             .build(),
4366     );
4367 
4368     let lo = &Operand::new("lo", NarrowInt);
4369     let hi = &Operand::new("hi", NarrowInt);
4370     let a = &Operand::new("a", &NarrowInt.double_width())
4371         .with_doc("The concatenation of `lo` and `hi`");
4372 
4373     ig.push(
4374         Inst::new(
4375             "iconcat",
4376             r#"
4377         Concatenate low and high bits to form a larger integer type.
4378 
4379         Vectors of integers are concatenated lane-wise such that the result has
4380         the same number of lanes as the inputs, but the lanes are twice the
4381         size.
4382         "#,
4383             &formats.binary,
4384         )
4385         .operands_in(vec![lo, hi])
4386         .operands_out(vec![a])
4387         .is_ghost(true),
4388     );
4389 
4390     // Instructions relating to atomic memory accesses and fences
4391     let AtomicMem = &TypeVar::new(
4392         "AtomicMem",
4393         "Any type that can be stored in memory, which can be used in an atomic operation",
4394         TypeSetBuilder::new().ints(8..64).build(),
4395     );
4396     let x = &Operand::new("x", AtomicMem).with_doc("Value to be atomically stored");
4397     let a = &Operand::new("a", AtomicMem).with_doc("Value atomically loaded");
4398     let e = &Operand::new("e", AtomicMem).with_doc("Expected value in CAS");
4399     let p = &Operand::new("p", iAddr);
4400     let MemFlags = &Operand::new("MemFlags", &imm.memflags);
4401     let AtomicRmwOp = &Operand::new("AtomicRmwOp", &imm.atomic_rmw_op);
4402 
4403     ig.push(
4404         Inst::new(
4405             "atomic_rmw",
4406             r#"
4407         Atomically read-modify-write memory at `p`, with second operand `x`.  The old value is
4408         returned.  `p` has the type of the target word size, and `x` may be an integer type of
4409         8, 16, 32 or 64 bits, even on a 32-bit target.  The type of the returned value is the
4410         same as the type of `x`.  This operation is sequentially consistent and creates
4411         happens-before edges that order normal (non-atomic) loads and stores.
4412         "#,
4413             &formats.atomic_rmw,
4414         )
4415         .operands_in(vec![MemFlags, AtomicRmwOp, p, x])
4416         .operands_out(vec![a])
4417         .can_load(true)
4418         .can_store(true)
4419         .other_side_effects(true),
4420     );
4421 
4422     ig.push(
4423         Inst::new(
4424             "atomic_cas",
4425             r#"
4426         Perform an atomic compare-and-swap operation on memory at `p`, with expected value `e`,
4427         storing `x` if the value at `p` equals `e`.  The old value at `p` is returned,
4428         regardless of whether the operation succeeds or fails.  `p` has the type of the target
4429         word size, and `x` and `e` must have the same type and the same size, which may be an
4430         integer type of 8, 16, 32 or 64 bits, even on a 32-bit target.  The type of the returned
4431         value is the same as the type of `x` and `e`.  This operation is sequentially
4432         consistent and creates happens-before edges that order normal (non-atomic) loads and
4433         stores.
4434         "#,
4435             &formats.atomic_cas,
4436         )
4437         .operands_in(vec![MemFlags, p, e, x])
4438         .operands_out(vec![a])
4439         .can_load(true)
4440         .can_store(true)
4441         .other_side_effects(true),
4442     );
4443 
4444     ig.push(
4445         Inst::new(
4446             "atomic_load",
4447             r#"
4448         Atomically load from memory at `p`.
4449 
4450         This is a polymorphic instruction that can load any value type which has a memory
4451         representation.  It should only be used for integer types with 8, 16, 32 or 64 bits.
4452         This operation is sequentially consistent and creates happens-before edges that order
4453         normal (non-atomic) loads and stores.
4454         "#,
4455             &formats.load_no_offset,
4456         )
4457         .operands_in(vec![MemFlags, p])
4458         .operands_out(vec![a])
4459         .can_load(true)
4460         .other_side_effects(true),
4461     );
4462 
4463     ig.push(
4464         Inst::new(
4465             "atomic_store",
4466             r#"
4467         Atomically store `x` to memory at `p`.
4468 
4469         This is a polymorphic instruction that can store any value type with a memory
4470         representation.  It should only be used for integer types with 8, 16, 32 or 64 bits.
4471         This operation is sequentially consistent and creates happens-before edges that order
4472         normal (non-atomic) loads and stores.
4473         "#,
4474             &formats.store_no_offset,
4475         )
4476         .operands_in(vec![MemFlags, x, p])
4477         .can_store(true)
4478         .other_side_effects(true),
4479     );
4480 
4481     ig.push(
4482         Inst::new(
4483             "fence",
4484             r#"
4485         A memory fence.  This must provide ordering to ensure that, at a minimum, neither loads
4486         nor stores of any kind may move forwards or backwards across the fence.  This operation
4487         is sequentially consistent.
4488         "#,
4489             &formats.nullary,
4490         )
4491         .other_side_effects(true),
4492     );
4493 
4494     ig.build()
4495 }
4496