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