1 #![allow(non_snake_case)]
2 
3 use crate::cdsl::instructions::{
4     AllInstructions, InstructionBuilder as Inst, InstructionGroupBuilder,
5 };
6 use crate::cdsl::operands::Operand;
7 use crate::cdsl::types::{LaneType, ValueType};
8 use crate::cdsl::typevar::{Interval, TypeSetBuilder, TypeVar};
9 use crate::shared::formats::Formats;
10 use crate::shared::types;
11 use crate::shared::{entities::EntityRefs, immediates::Immediates};
12 
13 #[inline(never)]
14 fn define_control_flow(
15     ig: &mut InstructionGroupBuilder,
16     formats: &Formats,
17     imm: &Immediates,
18     entities: &EntityRefs,
19 ) {
20     let block = &Operand::new("block", &entities.block).with_doc("Destination basic block");
21     let args = &Operand::new("args", &entities.varargs).with_doc("block arguments");
22 
23     ig.push(
24         Inst::new(
25             "jump",
26             r#"
27         Jump.
28 
29         Unconditionally jump to a basic block, passing the specified
30         block arguments. The number and types of arguments must match the
31         destination block.
32         "#,
33             &formats.jump,
34         )
35         .operands_in(vec![block, args])
36         .is_terminator(true)
37         .is_branch(true),
38     );
39 
40     let ScalarTruthy = &TypeVar::new(
41         "ScalarTruthy",
42         "A scalar truthy type",
43         TypeSetBuilder::new().ints(Interval::All).build(),
44     );
45 
46     {
47         let c = &Operand::new("c", ScalarTruthy).with_doc("Controlling value to test");
48 
49         ig.push(
50             Inst::new(
51                 "brz",
52                 r#"
53         Branch when zero.
54 
55         Take the branch when ``c = 0``.
56         "#,
57                 &formats.branch,
58             )
59             .operands_in(vec![c, block, args])
60             .is_branch(true),
61         );
62 
63         ig.push(
64             Inst::new(
65                 "brnz",
66                 r#"
67         Branch when non-zero.
68 
69         Take the branch when ``c != 0``.
70         "#,
71                 &formats.branch,
72             )
73             .operands_in(vec![c, block, args])
74             .is_branch(true),
75         );
76     }
77 
78     {
79         let _i32 = &TypeVar::new(
80             "i32",
81             "A 32 bit scalar integer type",
82             TypeSetBuilder::new().ints(32..32).build(),
83         );
84         let x = &Operand::new("x", _i32).with_doc("i32 index into jump table");
85         let JT = &Operand::new("JT", &entities.jump_table);
86 
87         ig.push(
88             Inst::new(
89                 "br_table",
90                 r#"
91         Indirect branch via jump table.
92 
93         Use ``x`` as an unsigned index into the jump table ``JT``. If a jump
94         table entry is found, branch to the corresponding block. If no entry was
95         found or the index is out-of-bounds, branch to the given default block.
96 
97         Note that this branch instruction can't pass arguments to the targeted
98         blocks. Split critical edges as needed to work around this.
99 
100         Do not confuse this with "tables" in WebAssembly. ``br_table`` is for
101         jump tables with destinations within the current function only -- think
102         of a ``match`` in Rust or a ``switch`` in C.  If you want to call a
103         function in a dynamic library, that will typically use
104         ``call_indirect``.
105         "#,
106                 &formats.branch_table,
107             )
108             .operands_in(vec![x, block, JT])
109             .is_terminator(true)
110             .is_branch(true),
111         );
112     }
113 
114     let iAddr = &TypeVar::new(
115         "iAddr",
116         "An integer address type",
117         TypeSetBuilder::new().ints(32..64).refs(32..64).build(),
118     );
119 
120     ig.push(
121         Inst::new(
122             "debugtrap",
123             r#"
124     Encodes an assembly debug trap.
125     "#,
126             &formats.nullary,
127         )
128         .other_side_effects(true)
129         .can_load(true)
130         .can_store(true),
131     );
132 
133     {
134         let code = &Operand::new("code", &imm.trapcode);
135         ig.push(
136             Inst::new(
137                 "trap",
138                 r#"
139         Terminate execution unconditionally.
140         "#,
141                 &formats.trap,
142             )
143             .operands_in(vec![code])
144             .can_trap(true)
145             .is_terminator(true),
146         );
147 
148         let c = &Operand::new("c", ScalarTruthy).with_doc("Controlling value to test");
149         ig.push(
150             Inst::new(
151                 "trapz",
152                 r#"
153         Trap when zero.
154 
155         if ``c`` is non-zero, execution continues at the following instruction.
156         "#,
157                 &formats.cond_trap,
158             )
159             .operands_in(vec![c, code])
160             .can_trap(true),
161         );
162 
163         ig.push(
164             Inst::new(
165                 "resumable_trap",
166                 r#"
167         A resumable trap.
168 
169         This instruction allows non-conditional traps to be used as non-terminal instructions.
170         "#,
171                 &formats.trap,
172             )
173             .operands_in(vec![code])
174             .can_trap(true),
175         );
176 
177         let c = &Operand::new("c", ScalarTruthy).with_doc("Controlling value to test");
178         ig.push(
179             Inst::new(
180                 "trapnz",
181                 r#"
182         Trap when non-zero.
183 
184         If ``c`` is zero, execution continues at the following instruction.
185         "#,
186                 &formats.cond_trap,
187             )
188             .operands_in(vec![c, code])
189             .can_trap(true),
190         );
191 
192         ig.push(
193             Inst::new(
194                 "resumable_trapnz",
195                 r#"
196         A resumable trap to be called when the passed condition is non-zero.
197 
198         If ``c`` is zero, execution continues at the following instruction.
199         "#,
200                 &formats.cond_trap,
201             )
202             .operands_in(vec![c, code])
203             .can_trap(true),
204         );
205     }
206 
207     let rvals = &Operand::new("rvals", &entities.varargs).with_doc("return values");
208     ig.push(
209         Inst::new(
210             "return",
211             r#"
212         Return from the function.
213 
214         Unconditionally transfer control to the calling function, passing the
215         provided return values. The list of return values must match the
216         function signature's return types.
217         "#,
218             &formats.multiary,
219         )
220         .operands_in(vec![rvals])
221         .is_return(true)
222         .is_terminator(true),
223     );
224 
225     let FN = &Operand::new("FN", &entities.func_ref)
226         .with_doc("function to call, declared by `function`");
227     let args = &Operand::new("args", &entities.varargs).with_doc("call arguments");
228     let rvals = &Operand::new("rvals", &entities.varargs).with_doc("return values");
229     ig.push(
230         Inst::new(
231             "call",
232             r#"
233         Direct function call.
234 
235         Call a function which has been declared in the preamble. The argument
236         types must match the function's signature.
237         "#,
238             &formats.call,
239         )
240         .operands_in(vec![FN, args])
241         .operands_out(vec![rvals])
242         .is_call(true),
243     );
244 
245     let SIG = &Operand::new("SIG", &entities.sig_ref).with_doc("function signature");
246     let callee = &Operand::new("callee", iAddr).with_doc("address of function to call");
247     let args = &Operand::new("args", &entities.varargs).with_doc("call arguments");
248     let rvals = &Operand::new("rvals", &entities.varargs).with_doc("return values");
249     ig.push(
250         Inst::new(
251             "call_indirect",
252             r#"
253         Indirect function call.
254 
255         Call the function pointed to by `callee` with the given arguments. The
256         called function must match the specified signature.
257 
258         Note that this is different from WebAssembly's ``call_indirect``; the
259         callee is a native address, rather than a table index. For WebAssembly,
260         `table_addr` and `load` are used to obtain a native address
261         from a table.
262         "#,
263             &formats.call_indirect,
264         )
265         .operands_in(vec![SIG, callee, args])
266         .operands_out(vec![rvals])
267         .is_call(true),
268     );
269 
270     let FN = &Operand::new("FN", &entities.func_ref)
271         .with_doc("function to call, declared by `function`");
272     let addr = &Operand::new("addr", iAddr);
273     ig.push(
274         Inst::new(
275             "func_addr",
276             r#"
277         Get the address of a function.
278 
279         Compute the absolute address of a function declared in the preamble.
280         The returned address can be used as a ``callee`` argument to
281         `call_indirect`. This is also a method for calling functions that
282         are too far away to be addressable by a direct `call`
283         instruction.
284         "#,
285             &formats.func_addr,
286         )
287         .operands_in(vec![FN])
288         .operands_out(vec![addr]),
289     );
290 }
291 
292 #[inline(never)]
293 fn define_simd_lane_access(
294     ig: &mut InstructionGroupBuilder,
295     formats: &Formats,
296     imm: &Immediates,
297     _: &EntityRefs,
298 ) {
299     let TxN = &TypeVar::new(
300         "TxN",
301         "A SIMD vector type",
302         TypeSetBuilder::new()
303             .ints(Interval::All)
304             .floats(Interval::All)
305             .simd_lanes(Interval::All)
306             .dynamic_simd_lanes(Interval::All)
307             .includes_scalars(false)
308             .build(),
309     );
310 
311     let x = &Operand::new("x", &TxN.lane_of()).with_doc("Value to splat to all lanes");
312     let a = &Operand::new("a", TxN);
313 
314     ig.push(
315         Inst::new(
316             "splat",
317             r#"
318         Vector splat.
319 
320         Return a vector whose lanes are all ``x``.
321         "#,
322             &formats.unary,
323         )
324         .operands_in(vec![x])
325         .operands_out(vec![a]),
326     );
327 
328     let I8x16 = &TypeVar::new(
329         "I8x16",
330         "A SIMD vector type consisting of 16 lanes of 8-bit integers",
331         TypeSetBuilder::new()
332             .ints(8..8)
333             .simd_lanes(16..16)
334             .includes_scalars(false)
335             .build(),
336     );
337     let x = &Operand::new("x", I8x16).with_doc("Vector to modify by re-arranging lanes");
338     let y = &Operand::new("y", I8x16).with_doc("Mask for re-arranging lanes");
339 
340     ig.push(
341         Inst::new(
342             "swizzle",
343             r#"
344         Vector swizzle.
345 
346         Returns a new vector with byte-width lanes selected from the lanes of the first input
347         vector ``x`` specified in the second input vector ``s``. The indices ``i`` in range
348         ``[0, 15]`` select the ``i``-th element of ``x``. For indices outside of the range the
349         resulting lane is 0. Note that this operates on byte-width lanes.
350         "#,
351             &formats.binary,
352         )
353         .operands_in(vec![x, y])
354         .operands_out(vec![a]),
355     );
356 
357     let x = &Operand::new("x", TxN).with_doc("The vector to modify");
358     let y = &Operand::new("y", &TxN.lane_of()).with_doc("New lane value");
359     let Idx = &Operand::new("Idx", &imm.uimm8).with_doc("Lane index");
360 
361     ig.push(
362         Inst::new(
363             "insertlane",
364             r#"
365         Insert ``y`` as lane ``Idx`` in x.
366 
367         The lane index, ``Idx``, is an immediate value, not an SSA value. It
368         must indicate a valid lane index for the type of ``x``.
369         "#,
370             &formats.ternary_imm8,
371         )
372         .operands_in(vec![x, y, Idx])
373         .operands_out(vec![a]),
374     );
375 
376     let x = &Operand::new("x", TxN);
377     let a = &Operand::new("a", &TxN.lane_of());
378 
379     ig.push(
380         Inst::new(
381             "extractlane",
382             r#"
383         Extract lane ``Idx`` from ``x``.
384 
385         The lane index, ``Idx``, is an immediate value, not an SSA value. It
386         must indicate a valid lane index for the type of ``x``. Note that the upper bits of ``a``
387         may or may not be zeroed depending on the ISA but the type system should prevent using
388         ``a`` as anything other than the extracted value.
389         "#,
390             &formats.binary_imm8,
391         )
392         .operands_in(vec![x, Idx])
393         .operands_out(vec![a]),
394     );
395 }
396 
397 #[inline(never)]
398 fn define_simd_arithmetic(
399     ig: &mut InstructionGroupBuilder,
400     formats: &Formats,
401     _: &Immediates,
402     _: &EntityRefs,
403 ) {
404     let Int = &TypeVar::new(
405         "Int",
406         "A scalar or vector integer type",
407         TypeSetBuilder::new()
408             .ints(Interval::All)
409             .simd_lanes(Interval::All)
410             .build(),
411     );
412 
413     let a = &Operand::new("a", Int);
414     let x = &Operand::new("x", Int);
415     let y = &Operand::new("y", Int);
416 
417     ig.push(
418         Inst::new(
419             "smin",
420             r#"
421         Signed integer minimum.
422         "#,
423             &formats.binary,
424         )
425         .operands_in(vec![x, y])
426         .operands_out(vec![a]),
427     );
428 
429     ig.push(
430         Inst::new(
431             "umin",
432             r#"
433         Unsigned integer minimum.
434         "#,
435             &formats.binary,
436         )
437         .operands_in(vec![x, y])
438         .operands_out(vec![a]),
439     );
440 
441     ig.push(
442         Inst::new(
443             "smax",
444             r#"
445         Signed integer maximum.
446         "#,
447             &formats.binary,
448         )
449         .operands_in(vec![x, y])
450         .operands_out(vec![a]),
451     );
452 
453     ig.push(
454         Inst::new(
455             "umax",
456             r#"
457         Unsigned integer maximum.
458         "#,
459             &formats.binary,
460         )
461         .operands_in(vec![x, y])
462         .operands_out(vec![a]),
463     );
464 
465     let IxN = &TypeVar::new(
466         "IxN",
467         "A SIMD vector type containing integers",
468         TypeSetBuilder::new()
469             .ints(Interval::All)
470             .simd_lanes(Interval::All)
471             .includes_scalars(false)
472             .build(),
473     );
474 
475     let a = &Operand::new("a", IxN);
476     let x = &Operand::new("x", IxN);
477     let y = &Operand::new("y", IxN);
478 
479     ig.push(
480         Inst::new(
481             "avg_round",
482             r#"
483         Unsigned average with rounding: `a := (x + y + 1) // 2`
484 
485         The addition does not lose any information (such as from overflow).
486         "#,
487             &formats.binary,
488         )
489         .operands_in(vec![x, y])
490         .operands_out(vec![a]),
491     );
492 
493     ig.push(
494         Inst::new(
495             "uadd_sat",
496             r#"
497         Add with unsigned saturation.
498 
499         This is similar to `iadd` but the operands are interpreted as unsigned integers and their
500         summed result, instead of wrapping, will be saturated to the highest unsigned integer for
501         the controlling type (e.g. `0xFF` for i8).
502         "#,
503             &formats.binary,
504         )
505         .operands_in(vec![x, y])
506         .operands_out(vec![a]),
507     );
508 
509     ig.push(
510         Inst::new(
511             "sadd_sat",
512             r#"
513         Add with signed saturation.
514 
515         This is similar to `iadd` but the operands are interpreted as signed integers and their
516         summed result, instead of wrapping, will be saturated to the lowest or highest
517         signed integer for the controlling type (e.g. `0x80` or `0x7F` for i8). For example,
518         since an `sadd_sat.i8` of `0x70` and `0x70` is greater than `0x7F`, the result will be
519         clamped to `0x7F`.
520         "#,
521             &formats.binary,
522         )
523         .operands_in(vec![x, y])
524         .operands_out(vec![a]),
525     );
526 
527     ig.push(
528         Inst::new(
529             "usub_sat",
530             r#"
531         Subtract with unsigned saturation.
532 
533         This is similar to `isub` but the operands are interpreted as unsigned integers and their
534         difference, instead of wrapping, will be saturated to the lowest unsigned integer for
535         the controlling type (e.g. `0x00` for i8).
536         "#,
537             &formats.binary,
538         )
539         .operands_in(vec![x, y])
540         .operands_out(vec![a]),
541     );
542 
543     ig.push(
544         Inst::new(
545             "ssub_sat",
546             r#"
547         Subtract with signed saturation.
548 
549         This is similar to `isub` but the operands are interpreted as signed integers and their
550         difference, instead of wrapping, will be saturated to the lowest or highest
551         signed integer for the controlling type (e.g. `0x80` or `0x7F` for i8).
552         "#,
553             &formats.binary,
554         )
555         .operands_in(vec![x, y])
556         .operands_out(vec![a]),
557     );
558 }
559 
560 #[allow(clippy::many_single_char_names)]
561 pub(crate) fn define(
562     all_instructions: &mut AllInstructions,
563     formats: &Formats,
564     imm: &Immediates,
565     entities: &EntityRefs,
566 ) {
567     let mut ig = InstructionGroupBuilder::new(all_instructions);
568 
569     define_control_flow(&mut ig, formats, imm, entities);
570     define_simd_lane_access(&mut ig, formats, imm, entities);
571     define_simd_arithmetic(&mut ig, formats, imm, entities);
572 
573     // Operand kind shorthands.
574     let i8: &TypeVar = &ValueType::from(LaneType::from(types::Int::I8)).into();
575     let f32_: &TypeVar = &ValueType::from(LaneType::from(types::Float::F32)).into();
576     let f64_: &TypeVar = &ValueType::from(LaneType::from(types::Float::F64)).into();
577 
578     // Starting definitions.
579     let Int = &TypeVar::new(
580         "Int",
581         "A scalar or vector integer type",
582         TypeSetBuilder::new()
583             .ints(Interval::All)
584             .simd_lanes(Interval::All)
585             .dynamic_simd_lanes(Interval::All)
586             .build(),
587     );
588 
589     let NarrowInt = &TypeVar::new(
590         "NarrowInt",
591         "An integer type with lanes type to `i64`",
592         TypeSetBuilder::new()
593             .ints(8..64)
594             .simd_lanes(Interval::All)
595             .dynamic_simd_lanes(Interval::All)
596             .build(),
597     );
598 
599     let ScalarTruthy = &TypeVar::new(
600         "ScalarTruthy",
601         "A scalar truthy type",
602         TypeSetBuilder::new().ints(Interval::All).build(),
603     );
604 
605     let iB = &TypeVar::new(
606         "iB",
607         "A scalar integer type",
608         TypeSetBuilder::new().ints(Interval::All).build(),
609     );
610 
611     let iSwappable = &TypeVar::new(
612         "iSwappable",
613         "A multi byte scalar integer type",
614         TypeSetBuilder::new().ints(16..128).build(),
615     );
616 
617     let iAddr = &TypeVar::new(
618         "iAddr",
619         "An integer address type",
620         TypeSetBuilder::new().ints(32..64).refs(32..64).build(),
621     );
622 
623     let Ref = &TypeVar::new(
624         "Ref",
625         "A scalar reference type",
626         TypeSetBuilder::new().refs(Interval::All).build(),
627     );
628 
629     let TxN = &TypeVar::new(
630         "TxN",
631         "A SIMD vector type",
632         TypeSetBuilder::new()
633             .ints(Interval::All)
634             .floats(Interval::All)
635             .simd_lanes(Interval::All)
636             .includes_scalars(false)
637             .build(),
638     );
639     let Any = &TypeVar::new(
640         "Any",
641         "Any integer, float, or reference scalar or vector type",
642         TypeSetBuilder::new()
643             .ints(Interval::All)
644             .floats(Interval::All)
645             .refs(Interval::All)
646             .simd_lanes(Interval::All)
647             .includes_scalars(true)
648             .build(),
649     );
650 
651     let Mem = &TypeVar::new(
652         "Mem",
653         "Any type that can be stored in memory",
654         TypeSetBuilder::new()
655             .ints(Interval::All)
656             .floats(Interval::All)
657             .simd_lanes(Interval::All)
658             .refs(Interval::All)
659             .dynamic_simd_lanes(Interval::All)
660             .build(),
661     );
662 
663     let MemTo = &TypeVar::copy_from(Mem, "MemTo".to_string());
664 
665     let addr = &Operand::new("addr", iAddr);
666 
667     let SS = &Operand::new("SS", &entities.stack_slot);
668     let DSS = &Operand::new("DSS", &entities.dynamic_stack_slot);
669     let Offset = &Operand::new("Offset", &imm.offset32).with_doc("Byte offset from base address");
670     let x = &Operand::new("x", Mem).with_doc("Value to be stored");
671     let a = &Operand::new("a", Mem).with_doc("Value loaded");
672     let p = &Operand::new("p", iAddr);
673     let MemFlags = &Operand::new("MemFlags", &imm.memflags);
674 
675     ig.push(
676         Inst::new(
677             "load",
678             r#"
679         Load from memory at ``p + Offset``.
680 
681         This is a polymorphic instruction that can load any value type which
682         has a memory representation.
683         "#,
684             &formats.load,
685         )
686         .operands_in(vec![MemFlags, p, Offset])
687         .operands_out(vec![a])
688         .can_load(true),
689     );
690 
691     ig.push(
692         Inst::new(
693             "store",
694             r#"
695         Store ``x`` to memory at ``p + Offset``.
696 
697         This is a polymorphic instruction that can store any value type with a
698         memory representation.
699         "#,
700             &formats.store,
701         )
702         .operands_in(vec![MemFlags, x, p, Offset])
703         .can_store(true),
704     );
705 
706     let iExt8 = &TypeVar::new(
707         "iExt8",
708         "An integer type with more than 8 bits",
709         TypeSetBuilder::new().ints(16..64).build(),
710     );
711     let x = &Operand::new("x", iExt8);
712     let a = &Operand::new("a", iExt8);
713 
714     ig.push(
715         Inst::new(
716             "uload8",
717             r#"
718         Load 8 bits from memory at ``p + Offset`` and zero-extend.
719 
720         This is equivalent to ``load.i8`` followed by ``uextend``.
721         "#,
722             &formats.load,
723         )
724         .operands_in(vec![MemFlags, p, Offset])
725         .operands_out(vec![a])
726         .can_load(true),
727     );
728 
729     ig.push(
730         Inst::new(
731             "sload8",
732             r#"
733         Load 8 bits from memory at ``p + Offset`` and sign-extend.
734 
735         This is equivalent to ``load.i8`` followed by ``sextend``.
736         "#,
737             &formats.load,
738         )
739         .operands_in(vec![MemFlags, p, Offset])
740         .operands_out(vec![a])
741         .can_load(true),
742     );
743 
744     ig.push(
745         Inst::new(
746             "istore8",
747             r#"
748         Store the low 8 bits of ``x`` to memory at ``p + Offset``.
749 
750         This is equivalent to ``ireduce.i8`` followed by ``store.i8``.
751         "#,
752             &formats.store,
753         )
754         .operands_in(vec![MemFlags, x, p, Offset])
755         .can_store(true),
756     );
757 
758     let iExt16 = &TypeVar::new(
759         "iExt16",
760         "An integer type with more than 16 bits",
761         TypeSetBuilder::new().ints(32..64).build(),
762     );
763     let x = &Operand::new("x", iExt16);
764     let a = &Operand::new("a", iExt16);
765 
766     ig.push(
767         Inst::new(
768             "uload16",
769             r#"
770         Load 16 bits from memory at ``p + Offset`` and zero-extend.
771 
772         This is equivalent to ``load.i16`` followed by ``uextend``.
773         "#,
774             &formats.load,
775         )
776         .operands_in(vec![MemFlags, p, Offset])
777         .operands_out(vec![a])
778         .can_load(true),
779     );
780 
781     ig.push(
782         Inst::new(
783             "sload16",
784             r#"
785         Load 16 bits from memory at ``p + Offset`` and sign-extend.
786 
787         This is equivalent to ``load.i16`` followed by ``sextend``.
788         "#,
789             &formats.load,
790         )
791         .operands_in(vec![MemFlags, p, Offset])
792         .operands_out(vec![a])
793         .can_load(true),
794     );
795 
796     ig.push(
797         Inst::new(
798             "istore16",
799             r#"
800         Store the low 16 bits of ``x`` to memory at ``p + Offset``.
801 
802         This is equivalent to ``ireduce.i16`` followed by ``store.i16``.
803         "#,
804             &formats.store,
805         )
806         .operands_in(vec![MemFlags, x, p, Offset])
807         .can_store(true),
808     );
809 
810     let iExt32 = &TypeVar::new(
811         "iExt32",
812         "An integer type with more than 32 bits",
813         TypeSetBuilder::new().ints(64..64).build(),
814     );
815     let x = &Operand::new("x", iExt32);
816     let a = &Operand::new("a", iExt32);
817 
818     ig.push(
819         Inst::new(
820             "uload32",
821             r#"
822         Load 32 bits from memory at ``p + Offset`` and zero-extend.
823 
824         This is equivalent to ``load.i32`` followed by ``uextend``.
825         "#,
826             &formats.load,
827         )
828         .operands_in(vec![MemFlags, p, Offset])
829         .operands_out(vec![a])
830         .can_load(true),
831     );
832 
833     ig.push(
834         Inst::new(
835             "sload32",
836             r#"
837         Load 32 bits from memory at ``p + Offset`` and sign-extend.
838 
839         This is equivalent to ``load.i32`` followed by ``sextend``.
840         "#,
841             &formats.load,
842         )
843         .operands_in(vec![MemFlags, p, Offset])
844         .operands_out(vec![a])
845         .can_load(true),
846     );
847 
848     ig.push(
849         Inst::new(
850             "istore32",
851             r#"
852         Store the low 32 bits of ``x`` to memory at ``p + Offset``.
853 
854         This is equivalent to ``ireduce.i32`` followed by ``store.i32``.
855         "#,
856             &formats.store,
857         )
858         .operands_in(vec![MemFlags, x, p, Offset])
859         .can_store(true),
860     );
861 
862     let I16x8 = &TypeVar::new(
863         "I16x8",
864         "A SIMD vector with exactly 8 lanes of 16-bit values",
865         TypeSetBuilder::new()
866             .ints(16..16)
867             .simd_lanes(8..8)
868             .includes_scalars(false)
869             .build(),
870     );
871     let a = &Operand::new("a", I16x8).with_doc("Value loaded");
872 
873     ig.push(
874         Inst::new(
875             "uload8x8",
876             r#"
877         Load an 8x8 vector (64 bits) from memory at ``p + Offset`` and zero-extend into an i16x8
878         vector.
879         "#,
880             &formats.load,
881         )
882         .operands_in(vec![MemFlags, p, Offset])
883         .operands_out(vec![a])
884         .can_load(true),
885     );
886 
887     ig.push(
888         Inst::new(
889             "sload8x8",
890             r#"
891         Load an 8x8 vector (64 bits) from memory at ``p + Offset`` and sign-extend into an i16x8
892         vector.
893         "#,
894             &formats.load,
895         )
896         .operands_in(vec![MemFlags, p, Offset])
897         .operands_out(vec![a])
898         .can_load(true),
899     );
900 
901     let I32x4 = &TypeVar::new(
902         "I32x4",
903         "A SIMD vector with exactly 4 lanes of 32-bit values",
904         TypeSetBuilder::new()
905             .ints(32..32)
906             .simd_lanes(4..4)
907             .includes_scalars(false)
908             .build(),
909     );
910     let a = &Operand::new("a", I32x4).with_doc("Value loaded");
911 
912     ig.push(
913         Inst::new(
914             "uload16x4",
915             r#"
916         Load a 16x4 vector (64 bits) from memory at ``p + Offset`` and zero-extend into an i32x4
917         vector.
918         "#,
919             &formats.load,
920         )
921         .operands_in(vec![MemFlags, p, Offset])
922         .operands_out(vec![a])
923         .can_load(true),
924     );
925 
926     ig.push(
927         Inst::new(
928             "sload16x4",
929             r#"
930         Load a 16x4 vector (64 bits) from memory at ``p + Offset`` and sign-extend into an i32x4
931         vector.
932         "#,
933             &formats.load,
934         )
935         .operands_in(vec![MemFlags, p, Offset])
936         .operands_out(vec![a])
937         .can_load(true),
938     );
939 
940     let I64x2 = &TypeVar::new(
941         "I64x2",
942         "A SIMD vector with exactly 2 lanes of 64-bit values",
943         TypeSetBuilder::new()
944             .ints(64..64)
945             .simd_lanes(2..2)
946             .includes_scalars(false)
947             .build(),
948     );
949     let a = &Operand::new("a", I64x2).with_doc("Value loaded");
950 
951     ig.push(
952         Inst::new(
953             "uload32x2",
954             r#"
955         Load an 32x2 vector (64 bits) from memory at ``p + Offset`` and zero-extend into an i64x2
956         vector.
957         "#,
958             &formats.load,
959         )
960         .operands_in(vec![MemFlags, p, Offset])
961         .operands_out(vec![a])
962         .can_load(true),
963     );
964 
965     ig.push(
966         Inst::new(
967             "sload32x2",
968             r#"
969         Load a 32x2 vector (64 bits) from memory at ``p + Offset`` and sign-extend into an i64x2
970         vector.
971         "#,
972             &formats.load,
973         )
974         .operands_in(vec![MemFlags, p, Offset])
975         .operands_out(vec![a])
976         .can_load(true),
977     );
978 
979     let x = &Operand::new("x", Mem).with_doc("Value to be stored");
980     let a = &Operand::new("a", Mem).with_doc("Value loaded");
981     let Offset =
982         &Operand::new("Offset", &imm.offset32).with_doc("In-bounds offset into stack slot");
983 
984     ig.push(
985         Inst::new(
986             "stack_load",
987             r#"
988         Load a value from a stack slot at the constant offset.
989 
990         This is a polymorphic instruction that can load any value type which
991         has a memory representation.
992 
993         The offset is an immediate constant, not an SSA value. The memory
994         access cannot go out of bounds, i.e.
995         `sizeof(a) + Offset <= sizeof(SS)`.
996         "#,
997             &formats.stack_load,
998         )
999         .operands_in(vec![SS, Offset])
1000         .operands_out(vec![a])
1001         .can_load(true),
1002     );
1003 
1004     ig.push(
1005         Inst::new(
1006             "stack_store",
1007             r#"
1008         Store a value to a stack slot at a constant offset.
1009 
1010         This is a polymorphic instruction that can store any value type with a
1011         memory representation.
1012 
1013         The offset is an immediate constant, not an SSA value. The memory
1014         access cannot go out of bounds, i.e.
1015         `sizeof(a) + Offset <= sizeof(SS)`.
1016         "#,
1017             &formats.stack_store,
1018         )
1019         .operands_in(vec![x, SS, Offset])
1020         .can_store(true),
1021     );
1022 
1023     ig.push(
1024         Inst::new(
1025             "stack_addr",
1026             r#"
1027         Get the address of a stack slot.
1028 
1029         Compute the absolute address of a byte in a stack slot. The offset must
1030         refer to a byte inside the stack slot:
1031         `0 <= Offset < sizeof(SS)`.
1032         "#,
1033             &formats.stack_load,
1034         )
1035         .operands_in(vec![SS, Offset])
1036         .operands_out(vec![addr]),
1037     );
1038 
1039     ig.push(
1040         Inst::new(
1041             "dynamic_stack_load",
1042             r#"
1043         Load a value from a dynamic stack slot.
1044 
1045         This is a polymorphic instruction that can load any value type which
1046         has a memory representation.
1047         "#,
1048             &formats.dynamic_stack_load,
1049         )
1050         .operands_in(vec![DSS])
1051         .operands_out(vec![a])
1052         .can_load(true),
1053     );
1054 
1055     ig.push(
1056         Inst::new(
1057             "dynamic_stack_store",
1058             r#"
1059         Store a value to a dynamic stack slot.
1060 
1061         This is a polymorphic instruction that can store any dynamic value type with a
1062         memory representation.
1063         "#,
1064             &formats.dynamic_stack_store,
1065         )
1066         .operands_in(vec![x, DSS])
1067         .can_store(true),
1068     );
1069 
1070     let GV = &Operand::new("GV", &entities.global_value);
1071     ig.push(
1072         Inst::new(
1073             "dynamic_stack_addr",
1074             r#"
1075         Get the address of a dynamic stack slot.
1076 
1077         Compute the absolute address of the first byte of a dynamic stack slot.
1078         "#,
1079             &formats.dynamic_stack_load,
1080         )
1081         .operands_in(vec![DSS])
1082         .operands_out(vec![addr]),
1083     );
1084 
1085     ig.push(
1086         Inst::new(
1087             "global_value",
1088             r#"
1089         Compute the value of global GV.
1090         "#,
1091             &formats.unary_global_value,
1092         )
1093         .operands_in(vec![GV])
1094         .operands_out(vec![a]),
1095     );
1096 
1097     ig.push(
1098         Inst::new(
1099             "symbol_value",
1100             r#"
1101         Compute the value of global GV, which is a symbolic value.
1102         "#,
1103             &formats.unary_global_value,
1104         )
1105         .operands_in(vec![GV])
1106         .operands_out(vec![a]),
1107     );
1108 
1109     ig.push(
1110         Inst::new(
1111             "tls_value",
1112             r#"
1113         Compute the value of global GV, which is a TLS (thread local storage) value.
1114         "#,
1115             &formats.unary_global_value,
1116         )
1117         .operands_in(vec![GV])
1118         .operands_out(vec![a]),
1119     );
1120 
1121     // Note this instruction is marked as having other side-effects, so GVN won't try to hoist it,
1122     // which would result in it being subject to spilling. While not hoisting would generally hurt
1123     // performance, since a computed value used many times may need to be regenerated before each
1124     // use, it is not the case here: this instruction doesn't generate any code.  That's because,
1125     // by definition the pinned register is never used by the register allocator, but is written to
1126     // and read explicitly and exclusively by set_pinned_reg and get_pinned_reg.
1127     ig.push(
1128         Inst::new(
1129             "get_pinned_reg",
1130             r#"
1131             Gets the content of the pinned register, when it's enabled.
1132         "#,
1133             &formats.nullary,
1134         )
1135         .operands_out(vec![addr])
1136         .other_side_effects(true),
1137     );
1138 
1139     ig.push(
1140         Inst::new(
1141             "set_pinned_reg",
1142             r#"
1143         Sets the content of the pinned register, when it's enabled.
1144         "#,
1145             &formats.unary,
1146         )
1147         .operands_in(vec![addr])
1148         .other_side_effects(true),
1149     );
1150 
1151     ig.push(
1152         Inst::new(
1153             "get_frame_pointer",
1154             r#"
1155         Get the address in the frame pointer register.
1156 
1157         Usage of this instruction requires setting `preserve_frame_pointers` to `true`.
1158         "#,
1159             &formats.nullary,
1160         )
1161         .operands_out(vec![addr]),
1162     );
1163 
1164     ig.push(
1165         Inst::new(
1166             "get_stack_pointer",
1167             r#"
1168         Get the address in the stack pointer register.
1169         "#,
1170             &formats.nullary,
1171         )
1172         .operands_out(vec![addr]),
1173     );
1174 
1175     ig.push(
1176         Inst::new(
1177             "get_return_address",
1178             r#"
1179         Get the PC where this function will transfer control to when it returns.
1180 
1181         Usage of this instruction requires setting `preserve_frame_pointers` to `true`.
1182         "#,
1183             &formats.nullary,
1184         )
1185         .operands_out(vec![addr]),
1186     );
1187 
1188     let TableOffset = &TypeVar::new(
1189         "TableOffset",
1190         "An unsigned table offset",
1191         TypeSetBuilder::new().ints(32..64).build(),
1192     );
1193     let T = &Operand::new("T", &entities.table);
1194     let p = &Operand::new("p", TableOffset);
1195     let Offset =
1196         &Operand::new("Offset", &imm.offset32).with_doc("Byte offset from element address");
1197 
1198     ig.push(
1199         Inst::new(
1200             "table_addr",
1201             r#"
1202         Bounds check and compute absolute address of a table entry.
1203 
1204         Verify that the offset ``p`` is in bounds for the table T, and generate
1205         an absolute address that is safe to dereference.
1206 
1207         ``Offset`` must be less than the size of a table element.
1208 
1209         1. If ``p`` is not greater than the table bound, return an absolute
1210            address corresponding to a byte offset of ``p`` from the table's
1211            base address.
1212         2. If ``p`` is greater than the table bound, generate a trap.
1213         "#,
1214             &formats.table_addr,
1215         )
1216         .operands_in(vec![T, p, Offset])
1217         .operands_out(vec![addr]),
1218     );
1219 
1220     let N = &Operand::new("N", &imm.imm64);
1221     let a = &Operand::new("a", NarrowInt).with_doc("A constant integer scalar or vector value");
1222 
1223     ig.push(
1224         Inst::new(
1225             "iconst",
1226             r#"
1227         Integer constant.
1228 
1229         Create a scalar integer SSA value with an immediate constant value, or
1230         an integer vector where all the lanes have the same value.
1231         "#,
1232             &formats.unary_imm,
1233         )
1234         .operands_in(vec![N])
1235         .operands_out(vec![a]),
1236     );
1237 
1238     let N = &Operand::new("N", &imm.ieee32);
1239     let a = &Operand::new("a", f32_).with_doc("A constant f32 scalar value");
1240 
1241     ig.push(
1242         Inst::new(
1243             "f32const",
1244             r#"
1245         Floating point constant.
1246 
1247         Create a `f32` SSA value with an immediate constant value.
1248         "#,
1249             &formats.unary_ieee32,
1250         )
1251         .operands_in(vec![N])
1252         .operands_out(vec![a]),
1253     );
1254 
1255     let N = &Operand::new("N", &imm.ieee64);
1256     let a = &Operand::new("a", f64_).with_doc("A constant f64 scalar value");
1257 
1258     ig.push(
1259         Inst::new(
1260             "f64const",
1261             r#"
1262         Floating point constant.
1263 
1264         Create a `f64` SSA value with an immediate constant value.
1265         "#,
1266             &formats.unary_ieee64,
1267         )
1268         .operands_in(vec![N])
1269         .operands_out(vec![a]),
1270     );
1271 
1272     let N = &Operand::new("N", &imm.pool_constant)
1273         .with_doc("The 16 immediate bytes of a 128-bit vector");
1274     let a = &Operand::new("a", TxN).with_doc("A constant vector value");
1275 
1276     ig.push(
1277         Inst::new(
1278             "vconst",
1279             r#"
1280         SIMD vector constant.
1281 
1282         Construct a vector with the given immediate bytes.
1283         "#,
1284             &formats.unary_const,
1285         )
1286         .operands_in(vec![N])
1287         .operands_out(vec![a]),
1288     );
1289 
1290     let mask = &Operand::new("mask", &imm.uimm128)
1291         .with_doc("The 16 immediate bytes used for selecting the elements to shuffle");
1292     let Tx16 = &TypeVar::new(
1293         "Tx16",
1294         "A SIMD vector with exactly 16 lanes of 8-bit values; eventually this may support other \
1295          lane counts and widths",
1296         TypeSetBuilder::new()
1297             .ints(8..8)
1298             .simd_lanes(16..16)
1299             .includes_scalars(false)
1300             .build(),
1301     );
1302     let a = &Operand::new("a", Tx16).with_doc("A vector value");
1303     let b = &Operand::new("b", Tx16).with_doc("A vector value");
1304 
1305     ig.push(
1306         Inst::new(
1307             "shuffle",
1308             r#"
1309         SIMD vector shuffle.
1310 
1311         Shuffle two vectors using the given immediate bytes. For each of the 16 bytes of the
1312         immediate, a value i of 0-15 selects the i-th element of the first vector and a value i of
1313         16-31 selects the (i-16)th element of the second vector. Immediate values outside of the
1314         0-31 range place a 0 in the resulting vector lane.
1315         "#,
1316             &formats.shuffle,
1317         )
1318         .operands_in(vec![a, b, mask])
1319         .operands_out(vec![a]),
1320     );
1321 
1322     let a = &Operand::new("a", Ref).with_doc("A constant reference null value");
1323 
1324     ig.push(
1325         Inst::new(
1326             "null",
1327             r#"
1328         Null constant value for reference types.
1329 
1330         Create a scalar reference SSA value with a constant null value.
1331         "#,
1332             &formats.nullary,
1333         )
1334         .operands_out(vec![a]),
1335     );
1336 
1337     ig.push(Inst::new(
1338         "nop",
1339         r#"
1340         Just a dummy instruction.
1341 
1342         Note: this doesn't compile to a machine code nop.
1343         "#,
1344         &formats.nullary,
1345     ));
1346 
1347     let c = &Operand::new("c", ScalarTruthy).with_doc("Controlling value to test");
1348     let x = &Operand::new("x", Any).with_doc("Value to use when `c` is true");
1349     let y = &Operand::new("y", Any).with_doc("Value to use when `c` is false");
1350     let a = &Operand::new("a", Any);
1351 
1352     ig.push(
1353         Inst::new(
1354             "select",
1355             r#"
1356         Conditional select.
1357 
1358         This instruction selects whole values. Use `vselect` for
1359         lane-wise selection.
1360         "#,
1361             &formats.ternary,
1362         )
1363         .operands_in(vec![c, x, y])
1364         .operands_out(vec![a]),
1365     );
1366 
1367     ig.push(
1368         Inst::new(
1369             "select_spectre_guard",
1370             r#"
1371             Conditional select intended for Spectre guards.
1372 
1373             This operation is semantically equivalent to a select instruction.
1374             However, it is guaranteed to not be removed or otherwise altered by any
1375             optimization pass, and is guaranteed to result in a conditional-move
1376             instruction, not a branch-based lowering.  As such, it is suitable
1377             for use when producing Spectre guards. For example, a bounds-check
1378             may guard against unsafe speculation past a bounds-check conditional
1379             branch by passing the address or index to be accessed through a
1380             conditional move, also gated on the same condition. Because no
1381             Spectre-vulnerable processors are known to perform speculation on
1382             conditional move instructions, this is guaranteed to pick the
1383             correct input. If the selected input in case of overflow is a "safe"
1384             value, for example a null pointer that causes an exception in the
1385             speculative path, this ensures that no Spectre vulnerability will
1386             exist.
1387             "#,
1388             &formats.ternary,
1389         )
1390         .operands_in(vec![c, x, y])
1391         .operands_out(vec![a])
1392         .other_side_effects(true),
1393     );
1394 
1395     let c = &Operand::new("c", Any).with_doc("Controlling value to test");
1396     ig.push(
1397         Inst::new(
1398             "bitselect",
1399             r#"
1400         Conditional select of bits.
1401 
1402         For each bit in `c`, this instruction selects the corresponding bit from `x` if the bit
1403         in `c` is 1 and the corresponding bit from `y` if the bit in `c` is 0. See also:
1404         `select`, `vselect`.
1405         "#,
1406             &formats.ternary,
1407         )
1408         .operands_in(vec![c, x, y])
1409         .operands_out(vec![a]),
1410     );
1411 
1412     let x = &Operand::new("x", TxN).with_doc("Vector to split");
1413     let lo = &Operand::new("lo", &TxN.half_vector()).with_doc("Low-numbered lanes of `x`");
1414     let hi = &Operand::new("hi", &TxN.half_vector()).with_doc("High-numbered lanes of `x`");
1415 
1416     ig.push(
1417         Inst::new(
1418             "vsplit",
1419             r#"
1420         Split a vector into two halves.
1421 
1422         Split the vector `x` into two separate values, each containing half of
1423         the lanes from ``x``. The result may be two scalars if ``x`` only had
1424         two lanes.
1425         "#,
1426             &formats.unary,
1427         )
1428         .operands_in(vec![x])
1429         .operands_out(vec![lo, hi]),
1430     );
1431 
1432     let Any128 = &TypeVar::new(
1433         "Any128",
1434         "Any scalar or vector type with as most 128 lanes",
1435         TypeSetBuilder::new()
1436             .ints(Interval::All)
1437             .floats(Interval::All)
1438             .simd_lanes(1..128)
1439             .includes_scalars(true)
1440             .build(),
1441     );
1442 
1443     let x = &Operand::new("x", Any128).with_doc("Low-numbered lanes");
1444     let y = &Operand::new("y", Any128).with_doc("High-numbered lanes");
1445     let a = &Operand::new("a", &Any128.double_vector()).with_doc("Concatenation of `x` and `y`");
1446 
1447     ig.push(
1448         Inst::new(
1449             "vconcat",
1450             r#"
1451         Vector concatenation.
1452 
1453         Return a vector formed by concatenating ``x`` and ``y``. The resulting
1454         vector type has twice as many lanes as each of the inputs. The lanes of
1455         ``x`` appear as the low-numbered lanes, and the lanes of ``y`` become
1456         the high-numbered lanes of ``a``.
1457 
1458         It is possible to form a vector by concatenating two scalars.
1459         "#,
1460             &formats.binary,
1461         )
1462         .operands_in(vec![x, y])
1463         .operands_out(vec![a]),
1464     );
1465 
1466     let c = &Operand::new("c", &TxN.as_bool()).with_doc("Controlling vector");
1467     let x = &Operand::new("x", TxN).with_doc("Value to use where `c` is true");
1468     let y = &Operand::new("y", TxN).with_doc("Value to use where `c` is false");
1469     let a = &Operand::new("a", TxN);
1470 
1471     ig.push(
1472         Inst::new(
1473             "vselect",
1474             r#"
1475         Vector lane select.
1476 
1477         Select lanes from ``x`` or ``y`` controlled by the lanes of the truthy
1478         vector ``c``.
1479         "#,
1480             &formats.ternary,
1481         )
1482         .operands_in(vec![c, x, y])
1483         .operands_out(vec![a]),
1484     );
1485 
1486     let s = &Operand::new("s", i8);
1487 
1488     ig.push(
1489         Inst::new(
1490             "vany_true",
1491             r#"
1492         Reduce a vector to a scalar boolean.
1493 
1494         Return a scalar boolean true if any lane in ``a`` is non-zero, false otherwise.
1495         "#,
1496             &formats.unary,
1497         )
1498         .operands_in(vec![a])
1499         .operands_out(vec![s]),
1500     );
1501 
1502     ig.push(
1503         Inst::new(
1504             "vall_true",
1505             r#"
1506         Reduce a vector to a scalar boolean.
1507 
1508         Return a scalar boolean true if all lanes in ``i`` are non-zero, false otherwise.
1509         "#,
1510             &formats.unary,
1511         )
1512         .operands_in(vec![a])
1513         .operands_out(vec![s]),
1514     );
1515 
1516     let a = &Operand::new("a", TxN);
1517     let x = &Operand::new("x", Int);
1518 
1519     ig.push(
1520         Inst::new(
1521             "vhigh_bits",
1522             r#"
1523         Reduce a vector to a scalar integer.
1524 
1525         Return a scalar integer, consisting of the concatenation of the most significant bit
1526         of each lane of ``a``.
1527         "#,
1528             &formats.unary,
1529         )
1530         .operands_in(vec![a])
1531         .operands_out(vec![x]),
1532     );
1533 
1534     let a = &Operand::new("a", &Int.as_bool());
1535     let Cond = &Operand::new("Cond", &imm.intcc);
1536     let x = &Operand::new("x", Int);
1537     let y = &Operand::new("y", Int);
1538 
1539     ig.push(
1540         Inst::new(
1541             "icmp",
1542             r#"
1543         Integer comparison.
1544 
1545         The condition code determines if the operands are interpreted as signed
1546         or unsigned integers.
1547 
1548         | Signed | Unsigned | Condition             |
1549         |--------|----------|-----------------------|
1550         | eq     | eq       | Equal                 |
1551         | ne     | ne       | Not equal             |
1552         | slt    | ult      | Less than             |
1553         | sge    | uge      | Greater than or equal |
1554         | sgt    | ugt      | Greater than          |
1555         | sle    | ule      | Less than or equal    |
1556 
1557         When this instruction compares integer vectors, it returns a vector of
1558         lane-wise comparisons.
1559         "#,
1560             &formats.int_compare,
1561         )
1562         .operands_in(vec![Cond, x, y])
1563         .operands_out(vec![a]),
1564     );
1565 
1566     let a = &Operand::new("a", i8);
1567     let x = &Operand::new("x", iB);
1568     let Y = &Operand::new("Y", &imm.imm64);
1569 
1570     ig.push(
1571         Inst::new(
1572             "icmp_imm",
1573             r#"
1574         Compare scalar integer to a constant.
1575 
1576         This is the same as the `icmp` instruction, except one operand is
1577         a sign extended 64 bit immediate constant.
1578 
1579         This instruction can only compare scalars. Use `icmp` for
1580         lane-wise vector comparisons.
1581         "#,
1582             &formats.int_compare_imm,
1583         )
1584         .operands_in(vec![Cond, x, Y])
1585         .operands_out(vec![a]),
1586     );
1587 
1588     let a = &Operand::new("a", Int);
1589     let x = &Operand::new("x", Int);
1590     let y = &Operand::new("y", Int);
1591 
1592     ig.push(
1593         Inst::new(
1594             "iadd",
1595             r#"
1596         Wrapping integer addition: `a := x + y \pmod{2^B}`.
1597 
1598         This instruction does not depend on the signed/unsigned interpretation
1599         of the operands.
1600         "#,
1601             &formats.binary,
1602         )
1603         .operands_in(vec![x, y])
1604         .operands_out(vec![a]),
1605     );
1606 
1607     ig.push(
1608         Inst::new(
1609             "isub",
1610             r#"
1611         Wrapping integer subtraction: `a := x - y \pmod{2^B}`.
1612 
1613         This instruction does not depend on the signed/unsigned interpretation
1614         of the operands.
1615         "#,
1616             &formats.binary,
1617         )
1618         .operands_in(vec![x, y])
1619         .operands_out(vec![a]),
1620     );
1621 
1622     ig.push(
1623         Inst::new(
1624             "ineg",
1625             r#"
1626         Integer negation: `a := -x \pmod{2^B}`.
1627         "#,
1628             &formats.unary,
1629         )
1630         .operands_in(vec![x])
1631         .operands_out(vec![a]),
1632     );
1633 
1634     ig.push(
1635         Inst::new(
1636             "iabs",
1637             r#"
1638         Integer absolute value with wrapping: `a := |x|`.
1639         "#,
1640             &formats.unary,
1641         )
1642         .operands_in(vec![x])
1643         .operands_out(vec![a]),
1644     );
1645 
1646     ig.push(
1647         Inst::new(
1648             "imul",
1649             r#"
1650         Wrapping integer multiplication: `a := x y \pmod{2^B}`.
1651 
1652         This instruction does not depend on the signed/unsigned interpretation
1653         of the operands.
1654 
1655         Polymorphic over all integer types (vector and scalar).
1656         "#,
1657             &formats.binary,
1658         )
1659         .operands_in(vec![x, y])
1660         .operands_out(vec![a]),
1661     );
1662 
1663     ig.push(
1664         Inst::new(
1665             "umulhi",
1666             r#"
1667         Unsigned integer multiplication, producing the high half of a
1668         double-length result.
1669 
1670         Polymorphic over all integer types (vector and scalar).
1671         "#,
1672             &formats.binary,
1673         )
1674         .operands_in(vec![x, y])
1675         .operands_out(vec![a]),
1676     );
1677 
1678     ig.push(
1679         Inst::new(
1680             "smulhi",
1681             r#"
1682         Signed integer multiplication, producing the high half of a
1683         double-length result.
1684 
1685         Polymorphic over all integer types (vector and scalar).
1686         "#,
1687             &formats.binary,
1688         )
1689         .operands_in(vec![x, y])
1690         .operands_out(vec![a]),
1691     );
1692 
1693     let I16or32 = &TypeVar::new(
1694         "I16or32",
1695         "A scalar or vector integer type with 16- or 32-bit numbers",
1696         TypeSetBuilder::new().ints(16..32).simd_lanes(4..8).build(),
1697     );
1698 
1699     let qx = &Operand::new("x", I16or32);
1700     let qy = &Operand::new("y", I16or32);
1701     let qa = &Operand::new("a", I16or32);
1702 
1703     ig.push(
1704         Inst::new(
1705             "sqmul_round_sat",
1706             r#"
1707         Fixed-point multiplication of numbers in the QN format, where N + 1
1708         is the number bitwidth:
1709         `a := signed_saturate((x * y + 1 << (Q - 1)) >> Q)`
1710 
1711         Polymorphic over all integer types (scalar and vector) with 16- or
1712         32-bit numbers.
1713         "#,
1714             &formats.binary,
1715         )
1716         .operands_in(vec![qx, qy])
1717         .operands_out(vec![qa]),
1718     );
1719 
1720     {
1721         // Integer division and remainder are scalar-only; most
1722         // hardware does not directly support vector integer division.
1723 
1724         let x = &Operand::new("x", iB);
1725         let y = &Operand::new("y", iB);
1726         let a = &Operand::new("a", iB);
1727 
1728         ig.push(
1729             Inst::new(
1730                 "udiv",
1731                 r#"
1732             Unsigned integer division: `a := \lfloor {x \over y} \rfloor`.
1733 
1734             This operation traps if the divisor is zero.
1735             "#,
1736                 &formats.binary,
1737             )
1738             .operands_in(vec![x, y])
1739             .operands_out(vec![a])
1740             .can_trap(true),
1741         );
1742 
1743         ig.push(
1744             Inst::new(
1745                 "sdiv",
1746                 r#"
1747             Signed integer division rounded toward zero: `a := sign(xy)
1748             \lfloor {|x| \over |y|}\rfloor`.
1749 
1750             This operation traps if the divisor is zero, or if the result is not
1751             representable in `B` bits two's complement. This only happens
1752             when `x = -2^{B-1}, y = -1`.
1753             "#,
1754                 &formats.binary,
1755             )
1756             .operands_in(vec![x, y])
1757             .operands_out(vec![a])
1758             .can_trap(true),
1759         );
1760 
1761         ig.push(
1762             Inst::new(
1763                 "urem",
1764                 r#"
1765             Unsigned integer remainder.
1766 
1767             This operation traps if the divisor is zero.
1768             "#,
1769                 &formats.binary,
1770             )
1771             .operands_in(vec![x, y])
1772             .operands_out(vec![a])
1773             .can_trap(true),
1774         );
1775 
1776         ig.push(
1777             Inst::new(
1778                 "srem",
1779                 r#"
1780             Signed integer remainder. The result has the sign of the dividend.
1781 
1782             This operation traps if the divisor is zero.
1783             "#,
1784                 &formats.binary,
1785             )
1786             .operands_in(vec![x, y])
1787             .operands_out(vec![a])
1788             .can_trap(true),
1789         );
1790     }
1791 
1792     let a = &Operand::new("a", iB);
1793     let x = &Operand::new("x", iB);
1794     let Y = &Operand::new("Y", &imm.imm64);
1795 
1796     ig.push(
1797         Inst::new(
1798             "iadd_imm",
1799             r#"
1800         Add immediate integer.
1801 
1802         Same as `iadd`, but one operand is a sign extended 64 bit immediate constant.
1803 
1804         Polymorphic over all scalar integer types, but does not support vector
1805         types.
1806         "#,
1807             &formats.binary_imm64,
1808         )
1809         .operands_in(vec![x, Y])
1810         .operands_out(vec![a]),
1811     );
1812 
1813     ig.push(
1814         Inst::new(
1815             "imul_imm",
1816             r#"
1817         Integer multiplication by immediate constant.
1818 
1819         Same as `imul`, but one operand is a sign extended 64 bit immediate constant.
1820 
1821         Polymorphic over all scalar integer types, but does not support vector
1822         types.
1823         "#,
1824             &formats.binary_imm64,
1825         )
1826         .operands_in(vec![x, Y])
1827         .operands_out(vec![a]),
1828     );
1829 
1830     ig.push(
1831         Inst::new(
1832             "udiv_imm",
1833             r#"
1834         Unsigned integer division by an immediate constant.
1835 
1836         Same as `udiv`, but one operand is a zero extended 64 bit immediate constant.
1837 
1838         This operation traps if the divisor is zero.
1839         "#,
1840             &formats.binary_imm64,
1841         )
1842         .operands_in(vec![x, Y])
1843         .operands_out(vec![a]),
1844     );
1845 
1846     ig.push(
1847         Inst::new(
1848             "sdiv_imm",
1849             r#"
1850         Signed integer division by an immediate constant.
1851 
1852         Same as `sdiv`, but one operand is a sign extended 64 bit immediate constant.
1853 
1854         This operation traps if the divisor is zero, or if the result is not
1855         representable in `B` bits two's complement. This only happens
1856         when `x = -2^{B-1}, Y = -1`.
1857         "#,
1858             &formats.binary_imm64,
1859         )
1860         .operands_in(vec![x, Y])
1861         .operands_out(vec![a]),
1862     );
1863 
1864     ig.push(
1865         Inst::new(
1866             "urem_imm",
1867             r#"
1868         Unsigned integer remainder with immediate divisor.
1869 
1870         Same as `urem`, but one operand is a zero extended 64 bit immediate constant.
1871 
1872         This operation traps if the divisor is zero.
1873         "#,
1874             &formats.binary_imm64,
1875         )
1876         .operands_in(vec![x, Y])
1877         .operands_out(vec![a]),
1878     );
1879 
1880     ig.push(
1881         Inst::new(
1882             "srem_imm",
1883             r#"
1884         Signed integer remainder with immediate divisor.
1885 
1886         Same as `srem`, but one operand is a sign extended 64 bit immediate constant.
1887 
1888         This operation traps if the divisor is zero.
1889         "#,
1890             &formats.binary_imm64,
1891         )
1892         .operands_in(vec![x, Y])
1893         .operands_out(vec![a]),
1894     );
1895 
1896     ig.push(
1897         Inst::new(
1898             "irsub_imm",
1899             r#"
1900         Immediate reverse wrapping subtraction: `a := Y - x \pmod{2^B}`.
1901 
1902         The immediate operand is a sign extended 64 bit constant.
1903 
1904         Also works as integer negation when `Y = 0`. Use `iadd_imm`
1905         with a negative immediate operand for the reverse immediate
1906         subtraction.
1907 
1908         Polymorphic over all scalar integer types, but does not support vector
1909         types.
1910         "#,
1911             &formats.binary_imm64,
1912         )
1913         .operands_in(vec![x, Y])
1914         .operands_out(vec![a]),
1915     );
1916 
1917     let a = &Operand::new("a", iB);
1918     let x = &Operand::new("x", iB);
1919     let y = &Operand::new("y", iB);
1920 
1921     let c_in = &Operand::new("c_in", i8).with_doc("Input carry flag");
1922     let c_out = &Operand::new("c_out", i8).with_doc("Output carry flag");
1923     let b_in = &Operand::new("b_in", i8).with_doc("Input borrow flag");
1924     let b_out = &Operand::new("b_out", i8).with_doc("Output borrow flag");
1925 
1926     ig.push(
1927         Inst::new(
1928             "iadd_cin",
1929             r#"
1930         Add integers with carry in.
1931 
1932         Same as `iadd` with an additional carry input. Computes:
1933 
1934         ```text
1935             a = x + y + c_{in} \pmod 2^B
1936         ```
1937 
1938         Polymorphic over all scalar integer types, but does not support vector
1939         types.
1940         "#,
1941             &formats.ternary,
1942         )
1943         .operands_in(vec![x, y, c_in])
1944         .operands_out(vec![a]),
1945     );
1946 
1947     ig.push(
1948         Inst::new(
1949             "iadd_cout",
1950             r#"
1951         Add integers with carry out.
1952 
1953         Same as `iadd` with an additional carry output.
1954 
1955         ```text
1956             a &= x + y \pmod 2^B \\
1957             c_{out} &= x+y >= 2^B
1958         ```
1959 
1960         Polymorphic over all scalar integer types, but does not support vector
1961         types.
1962         "#,
1963             &formats.binary,
1964         )
1965         .operands_in(vec![x, y])
1966         .operands_out(vec![a, c_out]),
1967     );
1968 
1969     ig.push(
1970         Inst::new(
1971             "iadd_carry",
1972             r#"
1973         Add integers with carry in and out.
1974 
1975         Same as `iadd` with an additional carry input and output.
1976 
1977         ```text
1978             a &= x + y + c_{in} \pmod 2^B \\
1979             c_{out} &= x + y + c_{in} >= 2^B
1980         ```
1981 
1982         Polymorphic over all scalar integer types, but does not support vector
1983         types.
1984         "#,
1985             &formats.ternary,
1986         )
1987         .operands_in(vec![x, y, c_in])
1988         .operands_out(vec![a, c_out]),
1989     );
1990 
1991     {
1992         let code = &Operand::new("code", &imm.trapcode);
1993 
1994         let i32_64 = &TypeVar::new(
1995             "i32_64",
1996             "A 32 or 64-bit scalar integer type",
1997             TypeSetBuilder::new().ints(32..64).build(),
1998         );
1999 
2000         let a = &Operand::new("a", i32_64);
2001         let x = &Operand::new("x", i32_64);
2002         let y = &Operand::new("y", i32_64);
2003         ig.push(
2004             Inst::new(
2005                 "uadd_overflow_trap",
2006                 r#"
2007             Unsigned addition of x and y, trapping if the result overflows.
2008 
2009             Accepts 32 or 64-bit integers, and does not support vector types.
2010             "#,
2011                 &formats.int_add_trap,
2012             )
2013             .operands_in(vec![x, y, code])
2014             .operands_out(vec![a])
2015             .can_trap(true),
2016         );
2017     }
2018 
2019     ig.push(
2020         Inst::new(
2021             "isub_bin",
2022             r#"
2023         Subtract integers with borrow in.
2024 
2025         Same as `isub` with an additional borrow flag input. Computes:
2026 
2027         ```text
2028             a = x - (y + b_{in}) \pmod 2^B
2029         ```
2030 
2031         Polymorphic over all scalar integer types, but does not support vector
2032         types.
2033         "#,
2034             &formats.ternary,
2035         )
2036         .operands_in(vec![x, y, b_in])
2037         .operands_out(vec![a]),
2038     );
2039 
2040     ig.push(
2041         Inst::new(
2042             "isub_bout",
2043             r#"
2044         Subtract integers with borrow out.
2045 
2046         Same as `isub` with an additional borrow flag output.
2047 
2048         ```text
2049             a &= x - y \pmod 2^B \\
2050             b_{out} &= x < y
2051         ```
2052 
2053         Polymorphic over all scalar integer types, but does not support vector
2054         types.
2055         "#,
2056             &formats.binary,
2057         )
2058         .operands_in(vec![x, y])
2059         .operands_out(vec![a, b_out]),
2060     );
2061 
2062     ig.push(
2063         Inst::new(
2064             "isub_borrow",
2065             r#"
2066         Subtract integers with borrow in and out.
2067 
2068         Same as `isub` with an additional borrow flag input and output.
2069 
2070         ```text
2071             a &= x - (y + b_{in}) \pmod 2^B \\
2072             b_{out} &= x < y + b_{in}
2073         ```
2074 
2075         Polymorphic over all scalar integer types, but does not support vector
2076         types.
2077         "#,
2078             &formats.ternary,
2079         )
2080         .operands_in(vec![x, y, b_in])
2081         .operands_out(vec![a, b_out]),
2082     );
2083 
2084     let bits = &TypeVar::new(
2085         "bits",
2086         "Any integer, float, or vector type",
2087         TypeSetBuilder::new()
2088             .ints(Interval::All)
2089             .floats(Interval::All)
2090             .simd_lanes(Interval::All)
2091             .includes_scalars(true)
2092             .build(),
2093     );
2094     let x = &Operand::new("x", bits);
2095     let y = &Operand::new("y", bits);
2096     let a = &Operand::new("a", bits);
2097 
2098     ig.push(
2099         Inst::new(
2100             "band",
2101             r#"
2102         Bitwise and.
2103         "#,
2104             &formats.binary,
2105         )
2106         .operands_in(vec![x, y])
2107         .operands_out(vec![a]),
2108     );
2109 
2110     ig.push(
2111         Inst::new(
2112             "bor",
2113             r#"
2114         Bitwise or.
2115         "#,
2116             &formats.binary,
2117         )
2118         .operands_in(vec![x, y])
2119         .operands_out(vec![a]),
2120     );
2121 
2122     ig.push(
2123         Inst::new(
2124             "bxor",
2125             r#"
2126         Bitwise xor.
2127         "#,
2128             &formats.binary,
2129         )
2130         .operands_in(vec![x, y])
2131         .operands_out(vec![a]),
2132     );
2133 
2134     ig.push(
2135         Inst::new(
2136             "bnot",
2137             r#"
2138         Bitwise not.
2139         "#,
2140             &formats.unary,
2141         )
2142         .operands_in(vec![x])
2143         .operands_out(vec![a]),
2144     );
2145 
2146     ig.push(
2147         Inst::new(
2148             "band_not",
2149             r#"
2150         Bitwise and not.
2151 
2152         Computes `x & ~y`.
2153         "#,
2154             &formats.binary,
2155         )
2156         .operands_in(vec![x, y])
2157         .operands_out(vec![a]),
2158     );
2159 
2160     ig.push(
2161         Inst::new(
2162             "bor_not",
2163             r#"
2164         Bitwise or not.
2165 
2166         Computes `x | ~y`.
2167         "#,
2168             &formats.binary,
2169         )
2170         .operands_in(vec![x, y])
2171         .operands_out(vec![a]),
2172     );
2173 
2174     ig.push(
2175         Inst::new(
2176             "bxor_not",
2177             r#"
2178         Bitwise xor not.
2179 
2180         Computes `x ^ ~y`.
2181         "#,
2182             &formats.binary,
2183         )
2184         .operands_in(vec![x, y])
2185         .operands_out(vec![a]),
2186     );
2187 
2188     let x = &Operand::new("x", iB);
2189     let Y = &Operand::new("Y", &imm.imm64);
2190     let a = &Operand::new("a", iB);
2191 
2192     ig.push(
2193         Inst::new(
2194             "band_imm",
2195             r#"
2196         Bitwise and with immediate.
2197 
2198         Same as `band`, but one operand is a zero extended 64 bit immediate constant.
2199 
2200         Polymorphic over all scalar integer types, but does not support vector
2201         types.
2202         "#,
2203             &formats.binary_imm64,
2204         )
2205         .operands_in(vec![x, Y])
2206         .operands_out(vec![a]),
2207     );
2208 
2209     ig.push(
2210         Inst::new(
2211             "bor_imm",
2212             r#"
2213         Bitwise or with immediate.
2214 
2215         Same as `bor`, but one operand is a zero extended 64 bit immediate constant.
2216 
2217         Polymorphic over all scalar integer types, but does not support vector
2218         types.
2219         "#,
2220             &formats.binary_imm64,
2221         )
2222         .operands_in(vec![x, Y])
2223         .operands_out(vec![a]),
2224     );
2225 
2226     ig.push(
2227         Inst::new(
2228             "bxor_imm",
2229             r#"
2230         Bitwise xor with immediate.
2231 
2232         Same as `bxor`, but one operand is a zero extended 64 bit immediate constant.
2233 
2234         Polymorphic over all scalar integer types, but does not support vector
2235         types.
2236         "#,
2237             &formats.binary_imm64,
2238         )
2239         .operands_in(vec![x, Y])
2240         .operands_out(vec![a]),
2241     );
2242 
2243     let x = &Operand::new("x", Int).with_doc("Scalar or vector value to shift");
2244     let y = &Operand::new("y", iB).with_doc("Number of bits to shift");
2245     let Y = &Operand::new("Y", &imm.imm64);
2246     let a = &Operand::new("a", Int);
2247 
2248     ig.push(
2249         Inst::new(
2250             "rotl",
2251             r#"
2252         Rotate left.
2253 
2254         Rotate the bits in ``x`` by ``y`` places.
2255         "#,
2256             &formats.binary,
2257         )
2258         .operands_in(vec![x, y])
2259         .operands_out(vec![a]),
2260     );
2261 
2262     ig.push(
2263         Inst::new(
2264             "rotr",
2265             r#"
2266         Rotate right.
2267 
2268         Rotate the bits in ``x`` by ``y`` places.
2269         "#,
2270             &formats.binary,
2271         )
2272         .operands_in(vec![x, y])
2273         .operands_out(vec![a]),
2274     );
2275 
2276     ig.push(
2277         Inst::new(
2278             "rotl_imm",
2279             r#"
2280         Rotate left by immediate.
2281 
2282         Same as `rotl`, but one operand is a zero extended 64 bit immediate constant.
2283         "#,
2284             &formats.binary_imm64,
2285         )
2286         .operands_in(vec![x, Y])
2287         .operands_out(vec![a]),
2288     );
2289 
2290     ig.push(
2291         Inst::new(
2292             "rotr_imm",
2293             r#"
2294         Rotate right by immediate.
2295 
2296         Same as `rotr`, but one operand is a zero extended 64 bit immediate constant.
2297         "#,
2298             &formats.binary_imm64,
2299         )
2300         .operands_in(vec![x, Y])
2301         .operands_out(vec![a]),
2302     );
2303 
2304     ig.push(
2305         Inst::new(
2306             "ishl",
2307             r#"
2308         Integer shift left. Shift the bits in ``x`` towards the MSB by ``y``
2309         places. Shift in zero bits to the LSB.
2310 
2311         The shift amount is masked to the size of ``x``.
2312 
2313         When shifting a B-bits integer type, this instruction computes:
2314 
2315         ```text
2316             s &:= y \pmod B,
2317             a &:= x \cdot 2^s \pmod{2^B}.
2318         ```
2319         "#,
2320             &formats.binary,
2321         )
2322         .operands_in(vec![x, y])
2323         .operands_out(vec![a]),
2324     );
2325 
2326     ig.push(
2327         Inst::new(
2328             "ushr",
2329             r#"
2330         Unsigned shift right. Shift bits in ``x`` towards the LSB by ``y``
2331         places, shifting in zero bits to the MSB. Also called a *logical
2332         shift*.
2333 
2334         The shift amount is masked to the size of the register.
2335 
2336         When shifting a B-bits integer type, this instruction computes:
2337 
2338         ```text
2339             s &:= y \pmod B,
2340             a &:= \lfloor x \cdot 2^{-s} \rfloor.
2341         ```
2342         "#,
2343             &formats.binary,
2344         )
2345         .operands_in(vec![x, y])
2346         .operands_out(vec![a]),
2347     );
2348 
2349     ig.push(
2350         Inst::new(
2351             "sshr",
2352             r#"
2353         Signed shift right. Shift bits in ``x`` towards the LSB by ``y``
2354         places, shifting in sign bits to the MSB. Also called an *arithmetic
2355         shift*.
2356 
2357         The shift amount is masked to the size of the register.
2358         "#,
2359             &formats.binary,
2360         )
2361         .operands_in(vec![x, y])
2362         .operands_out(vec![a]),
2363     );
2364 
2365     ig.push(
2366         Inst::new(
2367             "ishl_imm",
2368             r#"
2369         Integer shift left by immediate.
2370 
2371         The shift amount is masked to the size of ``x``.
2372         "#,
2373             &formats.binary_imm64,
2374         )
2375         .operands_in(vec![x, Y])
2376         .operands_out(vec![a]),
2377     );
2378 
2379     ig.push(
2380         Inst::new(
2381             "ushr_imm",
2382             r#"
2383         Unsigned shift right by immediate.
2384 
2385         The shift amount is masked to the size of the register.
2386         "#,
2387             &formats.binary_imm64,
2388         )
2389         .operands_in(vec![x, Y])
2390         .operands_out(vec![a]),
2391     );
2392 
2393     ig.push(
2394         Inst::new(
2395             "sshr_imm",
2396             r#"
2397         Signed shift right by immediate.
2398 
2399         The shift amount is masked to the size of the register.
2400         "#,
2401             &formats.binary_imm64,
2402         )
2403         .operands_in(vec![x, Y])
2404         .operands_out(vec![a]),
2405     );
2406 
2407     let x = &Operand::new("x", iB);
2408     let a = &Operand::new("a", iB);
2409 
2410     ig.push(
2411         Inst::new(
2412             "bitrev",
2413             r#"
2414         Reverse the bits of a integer.
2415 
2416         Reverses the bits in ``x``.
2417         "#,
2418             &formats.unary,
2419         )
2420         .operands_in(vec![x])
2421         .operands_out(vec![a]),
2422     );
2423 
2424     ig.push(
2425         Inst::new(
2426             "clz",
2427             r#"
2428         Count leading zero bits.
2429 
2430         Starting from the MSB in ``x``, count the number of zero bits before
2431         reaching the first one bit. When ``x`` is zero, returns the size of x
2432         in bits.
2433         "#,
2434             &formats.unary,
2435         )
2436         .operands_in(vec![x])
2437         .operands_out(vec![a]),
2438     );
2439 
2440     ig.push(
2441         Inst::new(
2442             "cls",
2443             r#"
2444         Count leading sign bits.
2445 
2446         Starting from the MSB after the sign bit in ``x``, count the number of
2447         consecutive bits identical to the sign bit. When ``x`` is 0 or -1,
2448         returns one less than the size of x in bits.
2449         "#,
2450             &formats.unary,
2451         )
2452         .operands_in(vec![x])
2453         .operands_out(vec![a]),
2454     );
2455 
2456     ig.push(
2457         Inst::new(
2458             "ctz",
2459             r#"
2460         Count trailing zeros.
2461 
2462         Starting from the LSB in ``x``, count the number of zero bits before
2463         reaching the first one bit. When ``x`` is zero, returns the size of x
2464         in bits.
2465         "#,
2466             &formats.unary,
2467         )
2468         .operands_in(vec![x])
2469         .operands_out(vec![a]),
2470     );
2471 
2472     let x = &Operand::new("x", iSwappable);
2473     let a = &Operand::new("a", iSwappable);
2474 
2475     ig.push(
2476         Inst::new(
2477             "bswap",
2478             r#"
2479         Reverse the byte order of an integer.
2480 
2481         Reverses the bytes in ``x``.
2482         "#,
2483             &formats.unary,
2484         )
2485         .operands_in(vec![x])
2486         .operands_out(vec![a]),
2487     );
2488 
2489     let x = &Operand::new("x", Int);
2490     let a = &Operand::new("a", Int);
2491 
2492     ig.push(
2493         Inst::new(
2494             "popcnt",
2495             r#"
2496         Population count
2497 
2498         Count the number of one bits in ``x``.
2499         "#,
2500             &formats.unary,
2501         )
2502         .operands_in(vec![x])
2503         .operands_out(vec![a]),
2504     );
2505 
2506     let Float = &TypeVar::new(
2507         "Float",
2508         "A scalar or vector floating point number",
2509         TypeSetBuilder::new()
2510             .floats(Interval::All)
2511             .simd_lanes(Interval::All)
2512             .dynamic_simd_lanes(Interval::All)
2513             .build(),
2514     );
2515     let Cond = &Operand::new("Cond", &imm.floatcc);
2516     let x = &Operand::new("x", Float);
2517     let y = &Operand::new("y", Float);
2518     let a = &Operand::new("a", &Float.as_bool());
2519 
2520     ig.push(
2521         Inst::new(
2522             "fcmp",
2523             r#"
2524         Floating point comparison.
2525 
2526         Two IEEE 754-2008 floating point numbers, `x` and `y`, relate to each
2527         other in exactly one of four ways:
2528 
2529         ```text
2530         == ==========================================
2531         UN Unordered when one or both numbers is NaN.
2532         EQ When `x = y`. (And `0.0 = -0.0`).
2533         LT When `x < y`.
2534         GT When `x > y`.
2535         == ==========================================
2536         ```
2537 
2538         The 14 `floatcc` condition codes each correspond to a subset of
2539         the four relations, except for the empty set which would always be
2540         false, and the full set which would always be true.
2541 
2542         The condition codes are divided into 7 'ordered' conditions which don't
2543         include UN, and 7 unordered conditions which all include UN.
2544 
2545         ```text
2546         +-------+------------+---------+------------+-------------------------+
2547         |Ordered             |Unordered             |Condition                |
2548         +=======+============+=========+============+=========================+
2549         |ord    |EQ | LT | GT|uno      |UN          |NaNs absent / present.   |
2550         +-------+------------+---------+------------+-------------------------+
2551         |eq     |EQ          |ueq      |UN | EQ     |Equal                    |
2552         +-------+------------+---------+------------+-------------------------+
2553         |one    |LT | GT     |ne       |UN | LT | GT|Not equal                |
2554         +-------+------------+---------+------------+-------------------------+
2555         |lt     |LT          |ult      |UN | LT     |Less than                |
2556         +-------+------------+---------+------------+-------------------------+
2557         |le     |LT | EQ     |ule      |UN | LT | EQ|Less than or equal       |
2558         +-------+------------+---------+------------+-------------------------+
2559         |gt     |GT          |ugt      |UN | GT     |Greater than             |
2560         +-------+------------+---------+------------+-------------------------+
2561         |ge     |GT | EQ     |uge      |UN | GT | EQ|Greater than or equal    |
2562         +-------+------------+---------+------------+-------------------------+
2563         ```
2564 
2565         The standard C comparison operators, `<, <=, >, >=`, are all ordered,
2566         so they are false if either operand is NaN. The C equality operator,
2567         `==`, is ordered, and since inequality is defined as the logical
2568         inverse it is *unordered*. They map to the `floatcc` condition
2569         codes as follows:
2570 
2571         ```text
2572         ==== ====== ============
2573         C    `Cond` Subset
2574         ==== ====== ============
2575         `==` eq     EQ
2576         `!=` ne     UN | LT | GT
2577         `<`  lt     LT
2578         `<=` le     LT | EQ
2579         `>`  gt     GT
2580         `>=` ge     GT | EQ
2581         ==== ====== ============
2582         ```
2583 
2584         This subset of condition codes also corresponds to the WebAssembly
2585         floating point comparisons of the same name.
2586 
2587         When this instruction compares floating point vectors, it returns a
2588         vector with the results of lane-wise comparisons.
2589         "#,
2590             &formats.float_compare,
2591         )
2592         .operands_in(vec![Cond, x, y])
2593         .operands_out(vec![a]),
2594     );
2595 
2596     let x = &Operand::new("x", Float);
2597     let y = &Operand::new("y", Float);
2598     let z = &Operand::new("z", Float);
2599     let a = &Operand::new("a", Float).with_doc("Result of applying operator to each lane");
2600 
2601     ig.push(
2602         Inst::new(
2603             "fadd",
2604             r#"
2605         Floating point addition.
2606         "#,
2607             &formats.binary,
2608         )
2609         .operands_in(vec![x, y])
2610         .operands_out(vec![a]),
2611     );
2612 
2613     ig.push(
2614         Inst::new(
2615             "fsub",
2616             r#"
2617         Floating point subtraction.
2618         "#,
2619             &formats.binary,
2620         )
2621         .operands_in(vec![x, y])
2622         .operands_out(vec![a]),
2623     );
2624 
2625     ig.push(
2626         Inst::new(
2627             "fmul",
2628             r#"
2629         Floating point multiplication.
2630         "#,
2631             &formats.binary,
2632         )
2633         .operands_in(vec![x, y])
2634         .operands_out(vec![a]),
2635     );
2636 
2637     ig.push(
2638         Inst::new(
2639             "fdiv",
2640             r#"
2641         Floating point division.
2642 
2643         Unlike the integer division instructions ` and
2644         `udiv`, this can't trap. Division by zero is infinity or
2645         NaN, depending on the dividend.
2646         "#,
2647             &formats.binary,
2648         )
2649         .operands_in(vec![x, y])
2650         .operands_out(vec![a]),
2651     );
2652 
2653     ig.push(
2654         Inst::new(
2655             "sqrt",
2656             r#"
2657         Floating point square root.
2658         "#,
2659             &formats.unary,
2660         )
2661         .operands_in(vec![x])
2662         .operands_out(vec![a]),
2663     );
2664 
2665     ig.push(
2666         Inst::new(
2667             "fma",
2668             r#"
2669         Floating point fused multiply-and-add.
2670 
2671         Computes `a := xy+z` without any intermediate rounding of the
2672         product.
2673         "#,
2674             &formats.ternary,
2675         )
2676         .operands_in(vec![x, y, z])
2677         .operands_out(vec![a]),
2678     );
2679 
2680     let a = &Operand::new("a", Float).with_doc("``x`` with its sign bit inverted");
2681 
2682     ig.push(
2683         Inst::new(
2684             "fneg",
2685             r#"
2686         Floating point negation.
2687 
2688         Note that this is a pure bitwise operation.
2689         "#,
2690             &formats.unary,
2691         )
2692         .operands_in(vec![x])
2693         .operands_out(vec![a]),
2694     );
2695 
2696     let a = &Operand::new("a", Float).with_doc("``x`` with its sign bit cleared");
2697 
2698     ig.push(
2699         Inst::new(
2700             "fabs",
2701             r#"
2702         Floating point absolute value.
2703 
2704         Note that this is a pure bitwise operation.
2705         "#,
2706             &formats.unary,
2707         )
2708         .operands_in(vec![x])
2709         .operands_out(vec![a]),
2710     );
2711 
2712     let a = &Operand::new("a", Float).with_doc("``x`` with its sign bit changed to that of ``y``");
2713 
2714     ig.push(
2715         Inst::new(
2716             "fcopysign",
2717             r#"
2718         Floating point copy sign.
2719 
2720         Note that this is a pure bitwise operation. The sign bit from ``y`` is
2721         copied to the sign bit of ``x``.
2722         "#,
2723             &formats.binary,
2724         )
2725         .operands_in(vec![x, y])
2726         .operands_out(vec![a]),
2727     );
2728 
2729     let a = &Operand::new("a", Float).with_doc("The smaller of ``x`` and ``y``");
2730 
2731     ig.push(
2732         Inst::new(
2733             "fmin",
2734             r#"
2735         Floating point minimum, propagating NaNs using the WebAssembly rules.
2736 
2737         If either operand is NaN, this returns NaN with an unspecified sign. Furthermore, if
2738         each input NaN consists of a mantissa whose most significant bit is 1 and the rest is
2739         0, then the output has the same form. Otherwise, the output mantissa's most significant
2740         bit is 1 and the rest is unspecified.
2741         "#,
2742             &formats.binary,
2743         )
2744         .operands_in(vec![x, y])
2745         .operands_out(vec![a]),
2746     );
2747 
2748     ig.push(
2749         Inst::new(
2750             "fmin_pseudo",
2751             r#"
2752         Floating point pseudo-minimum, propagating NaNs.  This behaves differently from ``fmin``.
2753         See <https://github.com/WebAssembly/simd/pull/122> for background.
2754 
2755         The behaviour is defined as ``fmin_pseudo(a, b) = (b < a) ? b : a``, and the behaviour
2756         for zero or NaN inputs follows from the behaviour of ``<`` with such inputs.
2757         "#,
2758             &formats.binary,
2759         )
2760         .operands_in(vec![x, y])
2761         .operands_out(vec![a]),
2762     );
2763 
2764     let a = &Operand::new("a", Float).with_doc("The larger of ``x`` and ``y``");
2765 
2766     ig.push(
2767         Inst::new(
2768             "fmax",
2769             r#"
2770         Floating point maximum, propagating NaNs using the WebAssembly rules.
2771 
2772         If either operand is NaN, this returns NaN with an unspecified sign. Furthermore, if
2773         each input NaN consists of a mantissa whose most significant bit is 1 and the rest is
2774         0, then the output has the same form. Otherwise, the output mantissa's most significant
2775         bit is 1 and the rest is unspecified.
2776         "#,
2777             &formats.binary,
2778         )
2779         .operands_in(vec![x, y])
2780         .operands_out(vec![a]),
2781     );
2782 
2783     ig.push(
2784         Inst::new(
2785             "fmax_pseudo",
2786             r#"
2787         Floating point pseudo-maximum, propagating NaNs.  This behaves differently from ``fmax``.
2788         See <https://github.com/WebAssembly/simd/pull/122> for background.
2789 
2790         The behaviour is defined as ``fmax_pseudo(a, b) = (a < b) ? b : a``, and the behaviour
2791         for zero or NaN inputs follows from the behaviour of ``<`` with such inputs.
2792         "#,
2793             &formats.binary,
2794         )
2795         .operands_in(vec![x, y])
2796         .operands_out(vec![a]),
2797     );
2798 
2799     let a = &Operand::new("a", Float).with_doc("``x`` rounded to integral value");
2800 
2801     ig.push(
2802         Inst::new(
2803             "ceil",
2804             r#"
2805         Round floating point round to integral, towards positive infinity.
2806         "#,
2807             &formats.unary,
2808         )
2809         .operands_in(vec![x])
2810         .operands_out(vec![a]),
2811     );
2812 
2813     ig.push(
2814         Inst::new(
2815             "floor",
2816             r#"
2817         Round floating point round to integral, towards negative infinity.
2818         "#,
2819             &formats.unary,
2820         )
2821         .operands_in(vec![x])
2822         .operands_out(vec![a]),
2823     );
2824 
2825     ig.push(
2826         Inst::new(
2827             "trunc",
2828             r#"
2829         Round floating point round to integral, towards zero.
2830         "#,
2831             &formats.unary,
2832         )
2833         .operands_in(vec![x])
2834         .operands_out(vec![a]),
2835     );
2836 
2837     ig.push(
2838         Inst::new(
2839             "nearest",
2840             r#"
2841         Round floating point round to integral, towards nearest with ties to
2842         even.
2843         "#,
2844             &formats.unary,
2845         )
2846         .operands_in(vec![x])
2847         .operands_out(vec![a]),
2848     );
2849 
2850     let a = &Operand::new("a", i8);
2851     let x = &Operand::new("x", Ref);
2852 
2853     ig.push(
2854         Inst::new(
2855             "is_null",
2856             r#"
2857         Reference verification.
2858 
2859         The condition code determines if the reference type in question is
2860         null or not.
2861         "#,
2862             &formats.unary,
2863         )
2864         .operands_in(vec![x])
2865         .operands_out(vec![a]),
2866     );
2867 
2868     let a = &Operand::new("a", i8);
2869     let x = &Operand::new("x", Ref);
2870 
2871     ig.push(
2872         Inst::new(
2873             "is_invalid",
2874             r#"
2875         Reference verification.
2876 
2877         The condition code determines if the reference type in question is
2878         invalid or not.
2879         "#,
2880             &formats.unary,
2881         )
2882         .operands_in(vec![x])
2883         .operands_out(vec![a]),
2884     );
2885 
2886     let x = &Operand::new("x", Mem);
2887     let a = &Operand::new("a", MemTo).with_doc("Bits of `x` reinterpreted");
2888     let MemFlags = &Operand::new("MemFlags", &imm.memflags);
2889 
2890     ig.push(
2891         Inst::new(
2892             "bitcast",
2893             r#"
2894         Reinterpret the bits in `x` as a different type.
2895 
2896         The input and output types must be storable to memory and of the same
2897         size. A bitcast is equivalent to storing one type and loading the other
2898         type from the same address, both using the specified MemFlags.
2899 
2900         Note that this operation only supports the `big` or `little` MemFlags.
2901         The specified byte order only affects the result in the case where
2902         input and output types differ in lane count/size.  In this case, the
2903         operation is only valid if a byte order specifier is provided.
2904         "#,
2905             &formats.load_no_offset,
2906         )
2907         .operands_in(vec![MemFlags, x])
2908         .operands_out(vec![a]),
2909     );
2910 
2911     let a = &Operand::new("a", TxN).with_doc("A vector value");
2912     let s = &Operand::new("s", &TxN.lane_of()).with_doc("A scalar value");
2913 
2914     ig.push(
2915         Inst::new(
2916             "scalar_to_vector",
2917             r#"
2918             Copies a scalar value to a vector value.  The scalar is copied into the
2919             least significant lane of the vector, and all other lanes will be zero.
2920             "#,
2921             &formats.unary,
2922         )
2923         .operands_in(vec![s])
2924         .operands_out(vec![a]),
2925     );
2926 
2927     let Truthy = &TypeVar::new(
2928         "Truthy",
2929         "A scalar or vector whose values are truthy",
2930         TypeSetBuilder::new()
2931             .ints(Interval::All)
2932             .simd_lanes(Interval::All)
2933             .build(),
2934     );
2935     let IntTo = &TypeVar::new(
2936         "IntTo",
2937         "An integer type with the same number of lanes",
2938         TypeSetBuilder::new()
2939             .ints(Interval::All)
2940             .simd_lanes(Interval::All)
2941             .build(),
2942     );
2943     let x = &Operand::new("x", Truthy);
2944     let a = &Operand::new("a", IntTo);
2945 
2946     ig.push(
2947         Inst::new(
2948             "bmask",
2949             r#"
2950         Convert `x` to an integer mask.
2951 
2952         True maps to all 1s and false maps to all 0s. The result type must have
2953         the same number of vector lanes as the input.
2954         "#,
2955             &formats.unary,
2956         )
2957         .operands_in(vec![x])
2958         .operands_out(vec![a]),
2959     );
2960 
2961     let Int = &TypeVar::new(
2962         "Int",
2963         "A scalar integer type",
2964         TypeSetBuilder::new().ints(Interval::All).build(),
2965     );
2966 
2967     let IntTo = &TypeVar::new(
2968         "IntTo",
2969         "A smaller integer type",
2970         TypeSetBuilder::new().ints(Interval::All).build(),
2971     );
2972     let x = &Operand::new("x", Int);
2973     let a = &Operand::new("a", IntTo);
2974 
2975     ig.push(
2976         Inst::new(
2977             "ireduce",
2978             r#"
2979         Convert `x` to a smaller integer type by discarding
2980         the most significant bits.
2981 
2982         This is the same as reducing modulo `2^n`.
2983         "#,
2984             &formats.unary,
2985         )
2986         .operands_in(vec![x])
2987         .operands_out(vec![a]),
2988     );
2989 
2990     let I16or32or64xN = &TypeVar::new(
2991         "I16or32or64xN",
2992         "A SIMD vector type containing integer lanes 16, 32, or 64 bits wide",
2993         TypeSetBuilder::new()
2994             .ints(16..64)
2995             .simd_lanes(2..8)
2996             .dynamic_simd_lanes(2..8)
2997             .includes_scalars(false)
2998             .build(),
2999     );
3000 
3001     let x = &Operand::new("x", I16or32or64xN);
3002     let y = &Operand::new("y", I16or32or64xN);
3003     let a = &Operand::new("a", &I16or32or64xN.split_lanes());
3004 
3005     ig.push(
3006         Inst::new(
3007             "snarrow",
3008             r#"
3009         Combine `x` and `y` into a vector with twice the lanes but half the integer width while
3010         saturating overflowing values to the signed maximum and minimum.
3011 
3012         The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4`
3013         and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value
3014         returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`.
3015             "#,
3016             &formats.binary,
3017         )
3018         .operands_in(vec![x, y])
3019         .operands_out(vec![a]),
3020     );
3021 
3022     ig.push(
3023         Inst::new(
3024             "unarrow",
3025             r#"
3026         Combine `x` and `y` into a vector with twice the lanes but half the integer width while
3027         saturating overflowing values to the unsigned maximum and minimum.
3028 
3029         Note that all input lanes are considered signed: any negative lanes will overflow and be
3030         replaced with the unsigned minimum, `0x00`.
3031 
3032         The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4`
3033         and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value
3034         returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`.
3035             "#,
3036             &formats.binary,
3037         )
3038         .operands_in(vec![x, y])
3039         .operands_out(vec![a]),
3040     );
3041 
3042     ig.push(
3043         Inst::new(
3044             "uunarrow",
3045             r#"
3046         Combine `x` and `y` into a vector with twice the lanes but half the integer width while
3047         saturating overflowing values to the unsigned maximum and minimum.
3048 
3049         Note that all input lanes are considered unsigned: any negative values will be interpreted as unsigned, overflowing and being replaced with the unsigned maximum.
3050 
3051         The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4`
3052         and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value
3053         returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`.
3054             "#,
3055             &formats.binary,
3056         )
3057         .operands_in(vec![x, y])
3058         .operands_out(vec![a]),
3059     );
3060 
3061     let I8or16or32xN = &TypeVar::new(
3062         "I8or16or32xN",
3063         "A SIMD vector type containing integer lanes 8, 16, or 32 bits wide.",
3064         TypeSetBuilder::new()
3065             .ints(8..32)
3066             .simd_lanes(2..16)
3067             .dynamic_simd_lanes(2..16)
3068             .includes_scalars(false)
3069             .build(),
3070     );
3071 
3072     let x = &Operand::new("x", I8or16or32xN);
3073     let a = &Operand::new("a", &I8or16or32xN.merge_lanes());
3074 
3075     ig.push(
3076         Inst::new(
3077             "swiden_low",
3078             r#"
3079         Widen the low lanes of `x` using signed extension.
3080 
3081         This will double the lane width and halve the number of lanes.
3082             "#,
3083             &formats.unary,
3084         )
3085         .operands_in(vec![x])
3086         .operands_out(vec![a]),
3087     );
3088 
3089     ig.push(
3090         Inst::new(
3091             "swiden_high",
3092             r#"
3093         Widen the high lanes of `x` using signed extension.
3094 
3095         This will double the lane width and halve the number of lanes.
3096             "#,
3097             &formats.unary,
3098         )
3099         .operands_in(vec![x])
3100         .operands_out(vec![a]),
3101     );
3102 
3103     ig.push(
3104         Inst::new(
3105             "uwiden_low",
3106             r#"
3107         Widen the low lanes of `x` using unsigned extension.
3108 
3109         This will double the lane width and halve the number of lanes.
3110             "#,
3111             &formats.unary,
3112         )
3113         .operands_in(vec![x])
3114         .operands_out(vec![a]),
3115     );
3116 
3117     ig.push(
3118         Inst::new(
3119             "uwiden_high",
3120             r#"
3121             Widen the high lanes of `x` using unsigned extension.
3122 
3123             This will double the lane width and halve the number of lanes.
3124             "#,
3125             &formats.unary,
3126         )
3127         .operands_in(vec![x])
3128         .operands_out(vec![a]),
3129     );
3130 
3131     let x = &Operand::new("x", I8or16or32xN);
3132     let y = &Operand::new("y", I8or16or32xN);
3133     let a = &Operand::new("a", I8or16or32xN);
3134 
3135     ig.push(
3136         Inst::new(
3137             "iadd_pairwise",
3138             r#"
3139         Does lane-wise integer pairwise addition on two operands, putting the
3140         combined results into a single vector result. Here a pair refers to adjacent
3141         lanes in a vector, i.e. i*2 + (i*2+1) for i == num_lanes/2. The first operand
3142         pairwise add results will make up the low half of the resulting vector while
3143         the second operand pairwise add results will make up the upper half of the
3144         resulting vector.
3145             "#,
3146             &formats.binary,
3147         )
3148         .operands_in(vec![x, y])
3149         .operands_out(vec![a]),
3150     );
3151 
3152     let I16x8 = &TypeVar::new(
3153         "I16x8",
3154         "A SIMD vector type containing 8 integer lanes each 16 bits wide.",
3155         TypeSetBuilder::new()
3156             .ints(16..16)
3157             .simd_lanes(8..8)
3158             .includes_scalars(false)
3159             .build(),
3160     );
3161 
3162     let x = &Operand::new("x", I16x8);
3163     let y = &Operand::new("y", I16x8);
3164     let a = &Operand::new("a", &I16x8.merge_lanes());
3165 
3166     ig.push(
3167         Inst::new(
3168             "widening_pairwise_dot_product_s",
3169             r#"
3170         Takes corresponding elements in `x` and `y`, performs a sign-extending length-doubling
3171         multiplication on them, then adds adjacent pairs of elements to form the result.  For
3172         example, if the input vectors are `[x3, x2, x1, x0]` and `[y3, y2, y1, y0]`, it produces
3173         the vector `[r1, r0]`, where `r1 = sx(x3) * sx(y3) + sx(x2) * sx(y2)` and
3174         `r0 = sx(x1) * sx(y1) + sx(x0) * sx(y0)`, and `sx(n)` sign-extends `n` to twice its width.
3175 
3176         This will double the lane width and halve the number of lanes.  So the resulting
3177         vector has the same number of bits as `x` and `y` do (individually).
3178 
3179         See <https://github.com/WebAssembly/simd/pull/127> for background info.
3180             "#,
3181             &formats.binary,
3182         )
3183         .operands_in(vec![x, y])
3184         .operands_out(vec![a]),
3185     );
3186 
3187     let IntTo = &TypeVar::new(
3188         "IntTo",
3189         "A larger integer type with the same number of lanes",
3190         TypeSetBuilder::new()
3191             .ints(Interval::All)
3192             .simd_lanes(Interval::All)
3193             .build(),
3194     );
3195     let x = &Operand::new("x", Int);
3196     let a = &Operand::new("a", IntTo);
3197 
3198     ig.push(
3199         Inst::new(
3200             "uextend",
3201             r#"
3202         Convert `x` to a larger integer type by zero-extending.
3203 
3204         Each lane in `x` is converted to a larger integer type by adding
3205         zeroes. The result has the same numerical value as `x` when both are
3206         interpreted as unsigned integers.
3207 
3208         The result type must have the same number of vector lanes as the input,
3209         and each lane must not have fewer bits that the input lanes. If the
3210         input and output types are the same, this is a no-op.
3211         "#,
3212             &formats.unary,
3213         )
3214         .operands_in(vec![x])
3215         .operands_out(vec![a]),
3216     );
3217 
3218     ig.push(
3219         Inst::new(
3220             "sextend",
3221             r#"
3222         Convert `x` to a larger integer type by sign-extending.
3223 
3224         Each lane in `x` is converted to a larger integer type by replicating
3225         the sign bit. The result has the same numerical value as `x` when both
3226         are interpreted as signed integers.
3227 
3228         The result type must have the same number of vector lanes as the input,
3229         and each lane must not have fewer bits that the input lanes. If the
3230         input and output types are the same, this is a no-op.
3231         "#,
3232             &formats.unary,
3233         )
3234         .operands_in(vec![x])
3235         .operands_out(vec![a]),
3236     );
3237 
3238     let FloatTo = &TypeVar::new(
3239         "FloatTo",
3240         "A scalar or vector floating point number",
3241         TypeSetBuilder::new()
3242             .floats(Interval::All)
3243             .simd_lanes(Interval::All)
3244             .build(),
3245     );
3246     let x = &Operand::new("x", Float);
3247     let a = &Operand::new("a", FloatTo);
3248 
3249     ig.push(
3250         Inst::new(
3251             "fpromote",
3252             r#"
3253         Convert `x` to a larger floating point format.
3254 
3255         Each lane in `x` is converted to the destination floating point format.
3256         This is an exact operation.
3257 
3258         Cranelift currently only supports two floating point formats
3259         - `f32` and `f64`. This may change in the future.
3260 
3261         The result type must have the same number of vector lanes as the input,
3262         and the result lanes must not have fewer bits than the input lanes.
3263         "#,
3264             &formats.unary,
3265         )
3266         .operands_in(vec![x])
3267         .operands_out(vec![a]),
3268     );
3269 
3270     ig.push(
3271         Inst::new(
3272             "fdemote",
3273             r#"
3274         Convert `x` to a smaller floating point format.
3275 
3276         Each lane in `x` is converted to the destination floating point format
3277         by rounding to nearest, ties to even.
3278 
3279         Cranelift currently only supports two floating point formats
3280         - `f32` and `f64`. This may change in the future.
3281 
3282         The result type must have the same number of vector lanes as the input,
3283         and the result lanes must not have more bits than the input lanes.
3284         "#,
3285             &formats.unary,
3286         )
3287         .operands_in(vec![x])
3288         .operands_out(vec![a]),
3289     );
3290 
3291     let F64x2 = &TypeVar::new(
3292         "F64x2",
3293         "A SIMD vector type consisting of 2 lanes of 64-bit floats",
3294         TypeSetBuilder::new()
3295             .floats(64..64)
3296             .simd_lanes(2..2)
3297             .includes_scalars(false)
3298             .build(),
3299     );
3300     let F32x4 = &TypeVar::new(
3301         "F32x4",
3302         "A SIMD vector type consisting of 4 lanes of 32-bit floats",
3303         TypeSetBuilder::new()
3304             .floats(32..32)
3305             .simd_lanes(4..4)
3306             .includes_scalars(false)
3307             .build(),
3308     );
3309 
3310     let x = &Operand::new("x", F64x2);
3311     let a = &Operand::new("a", F32x4);
3312 
3313     ig.push(
3314         Inst::new(
3315             "fvdemote",
3316             r#"
3317                 Convert `x` to a smaller floating point format.
3318 
3319                 Each lane in `x` is converted to the destination floating point format
3320                 by rounding to nearest, ties to even.
3321 
3322                 Cranelift currently only supports two floating point formats
3323                 - `f32` and `f64`. This may change in the future.
3324 
3325                 Fvdemote differs from fdemote in that with fvdemote it targets vectors.
3326                 Fvdemote is constrained to having the input type being F64x2 and the result
3327                 type being F32x4. The result lane that was the upper half of the input lane
3328                 is initialized to zero.
3329                 "#,
3330             &formats.unary,
3331         )
3332         .operands_in(vec![x])
3333         .operands_out(vec![a]),
3334     );
3335 
3336     ig.push(
3337         Inst::new(
3338             "fvpromote_low",
3339             r#"
3340         Converts packed single precision floating point to packed double precision floating point.
3341 
3342         Considering only the lower half of the register, the low lanes in `x` are interpreted as
3343         single precision floats that are then converted to a double precision floats.
3344 
3345         The result type will have half the number of vector lanes as the input. Fvpromote_low is
3346         constrained to input F32x4 with a result type of F64x2.
3347         "#,
3348             &formats.unary,
3349         )
3350         .operands_in(vec![a])
3351         .operands_out(vec![x]),
3352     );
3353 
3354     let FloatScalar = &TypeVar::new(
3355         "FloatScalar",
3356         "A scalar only floating point number",
3357         TypeSetBuilder::new().floats(Interval::All).build(),
3358     );
3359     let x = &Operand::new("x", FloatScalar);
3360     let a = &Operand::new("a", IntTo);
3361 
3362     ig.push(
3363         Inst::new(
3364             "fcvt_to_uint",
3365             r#"
3366         Converts floating point scalars to unsigned integer.
3367 
3368         Only operates on `x` if it is a scalar. If `x` is NaN or if
3369         the unsigned integral value cannot be represented in the result
3370         type, this instruction traps.
3371 
3372         "#,
3373             &formats.unary,
3374         )
3375         .operands_in(vec![x])
3376         .operands_out(vec![a])
3377         .can_trap(true),
3378     );
3379 
3380     ig.push(
3381         Inst::new(
3382             "fcvt_to_sint",
3383             r#"
3384         Converts floating point scalars to signed integer.
3385 
3386         Only operates on `x` if it is a scalar. If `x` is NaN or if
3387         the unsigned integral value cannot be represented in the result
3388         type, this instruction traps.
3389 
3390         "#,
3391             &formats.unary,
3392         )
3393         .operands_in(vec![x])
3394         .operands_out(vec![a])
3395         .can_trap(true),
3396     );
3397 
3398     let x = &Operand::new("x", Float);
3399     let a = &Operand::new("a", IntTo);
3400 
3401     ig.push(
3402         Inst::new(
3403             "fcvt_to_uint_sat",
3404             r#"
3405         Convert floating point to unsigned integer as fcvt_to_uint does, but
3406         saturates the input instead of trapping. NaN and negative values are
3407         converted to 0.
3408         "#,
3409             &formats.unary,
3410         )
3411         .operands_in(vec![x])
3412         .operands_out(vec![a]),
3413     );
3414 
3415     ig.push(
3416         Inst::new(
3417             "fcvt_to_sint_sat",
3418             r#"
3419         Convert floating point to signed integer as fcvt_to_sint does, but
3420         saturates the input instead of trapping. NaN values are converted to 0.
3421         "#,
3422             &formats.unary,
3423         )
3424         .operands_in(vec![x])
3425         .operands_out(vec![a]),
3426     );
3427 
3428     let Int = &TypeVar::new(
3429         "Int",
3430         "A scalar or vector integer type",
3431         TypeSetBuilder::new()
3432             .ints(Interval::All)
3433             .simd_lanes(Interval::All)
3434             .build(),
3435     );
3436     let x = &Operand::new("x", Int);
3437     let a = &Operand::new("a", FloatTo);
3438 
3439     ig.push(
3440         Inst::new(
3441             "fcvt_from_uint",
3442             r#"
3443         Convert unsigned integer to floating point.
3444 
3445         Each lane in `x` is interpreted as an unsigned integer and converted to
3446         floating point using round to nearest, ties to even.
3447 
3448         The result type must have the same number of vector lanes as the input.
3449         "#,
3450             &formats.unary,
3451         )
3452         .operands_in(vec![x])
3453         .operands_out(vec![a]),
3454     );
3455 
3456     ig.push(
3457         Inst::new(
3458             "fcvt_from_sint",
3459             r#"
3460         Convert signed integer to floating point.
3461 
3462         Each lane in `x` is interpreted as a signed integer and converted to
3463         floating point using round to nearest, ties to even.
3464 
3465         The result type must have the same number of vector lanes as the input.
3466         "#,
3467             &formats.unary,
3468         )
3469         .operands_in(vec![x])
3470         .operands_out(vec![a]),
3471     );
3472 
3473     ig.push(
3474         Inst::new(
3475             "fcvt_low_from_sint",
3476             r#"
3477         Converts packed signed 32-bit integers to packed double precision floating point.
3478 
3479         Considering only the low half of the register, each lane in `x` is interpreted as a
3480         signed 32-bit integer that is then converted to a double precision float. This
3481         instruction differs from fcvt_from_sint in that it converts half the number of lanes
3482         which are converted to occupy twice the number of bits. No rounding should be needed
3483         for the resulting float.
3484 
3485         The result type will have half the number of vector lanes as the input.
3486         "#,
3487             &formats.unary,
3488         )
3489         .operands_in(vec![x])
3490         .operands_out(vec![a]),
3491     );
3492 
3493     let WideInt = &TypeVar::new(
3494         "WideInt",
3495         "An integer type with lanes from `i16` upwards",
3496         TypeSetBuilder::new()
3497             .ints(16..128)
3498             .simd_lanes(Interval::All)
3499             .build(),
3500     );
3501     let x = &Operand::new("x", WideInt);
3502     let lo = &Operand::new("lo", &WideInt.half_width()).with_doc("The low bits of `x`");
3503     let hi = &Operand::new("hi", &WideInt.half_width()).with_doc("The high bits of `x`");
3504 
3505     ig.push(
3506         Inst::new(
3507             "isplit",
3508             r#"
3509         Split an integer into low and high parts.
3510 
3511         Vectors of integers are split lane-wise, so the results have the same
3512         number of lanes as the input, but the lanes are half the size.
3513 
3514         Returns the low half of `x` and the high half of `x` as two independent
3515         values.
3516         "#,
3517             &formats.unary,
3518         )
3519         .operands_in(vec![x])
3520         .operands_out(vec![lo, hi]),
3521     );
3522 
3523     let lo = &Operand::new("lo", NarrowInt);
3524     let hi = &Operand::new("hi", NarrowInt);
3525     let a = &Operand::new("a", &NarrowInt.double_width())
3526         .with_doc("The concatenation of `lo` and `hi`");
3527 
3528     ig.push(
3529         Inst::new(
3530             "iconcat",
3531             r#"
3532         Concatenate low and high bits to form a larger integer type.
3533 
3534         Vectors of integers are concatenated lane-wise such that the result has
3535         the same number of lanes as the inputs, but the lanes are twice the
3536         size.
3537         "#,
3538             &formats.binary,
3539         )
3540         .operands_in(vec![lo, hi])
3541         .operands_out(vec![a]),
3542     );
3543 
3544     // Instructions relating to atomic memory accesses and fences
3545     let AtomicMem = &TypeVar::new(
3546         "AtomicMem",
3547         "Any type that can be stored in memory, which can be used in an atomic operation",
3548         TypeSetBuilder::new().ints(8..64).build(),
3549     );
3550     let x = &Operand::new("x", AtomicMem).with_doc("Value to be atomically stored");
3551     let a = &Operand::new("a", AtomicMem).with_doc("Value atomically loaded");
3552     let e = &Operand::new("e", AtomicMem).with_doc("Expected value in CAS");
3553     let p = &Operand::new("p", iAddr);
3554     let MemFlags = &Operand::new("MemFlags", &imm.memflags);
3555     let AtomicRmwOp = &Operand::new("AtomicRmwOp", &imm.atomic_rmw_op);
3556 
3557     ig.push(
3558         Inst::new(
3559             "atomic_rmw",
3560             r#"
3561         Atomically read-modify-write memory at `p`, with second operand `x`.  The old value is
3562         returned.  `p` has the type of the target word size, and `x` may be an integer type of
3563         8, 16, 32 or 64 bits, even on a 32-bit target.  The type of the returned value is the
3564         same as the type of `x`.  This operation is sequentially consistent and creates
3565         happens-before edges that order normal (non-atomic) loads and stores.
3566         "#,
3567             &formats.atomic_rmw,
3568         )
3569         .operands_in(vec![MemFlags, AtomicRmwOp, p, x])
3570         .operands_out(vec![a])
3571         .can_load(true)
3572         .can_store(true)
3573         .other_side_effects(true),
3574     );
3575 
3576     ig.push(
3577         Inst::new(
3578             "atomic_cas",
3579             r#"
3580         Perform an atomic compare-and-swap operation on memory at `p`, with expected value `e`,
3581         storing `x` if the value at `p` equals `e`.  The old value at `p` is returned,
3582         regardless of whether the operation succeeds or fails.  `p` has the type of the target
3583         word size, and `x` and `e` must have the same type and the same size, which may be an
3584         integer type of 8, 16, 32 or 64 bits, even on a 32-bit target.  The type of the returned
3585         value is the same as the type of `x` and `e`.  This operation is sequentially
3586         consistent and creates happens-before edges that order normal (non-atomic) loads and
3587         stores.
3588         "#,
3589             &formats.atomic_cas,
3590         )
3591         .operands_in(vec![MemFlags, p, e, x])
3592         .operands_out(vec![a])
3593         .can_load(true)
3594         .can_store(true)
3595         .other_side_effects(true),
3596     );
3597 
3598     ig.push(
3599         Inst::new(
3600             "atomic_load",
3601             r#"
3602         Atomically load from memory at `p`.
3603 
3604         This is a polymorphic instruction that can load any value type which has a memory
3605         representation.  It should only be used for integer types with 8, 16, 32 or 64 bits.
3606         This operation is sequentially consistent and creates happens-before edges that order
3607         normal (non-atomic) loads and stores.
3608         "#,
3609             &formats.load_no_offset,
3610         )
3611         .operands_in(vec![MemFlags, p])
3612         .operands_out(vec![a])
3613         .can_load(true)
3614         .other_side_effects(true),
3615     );
3616 
3617     ig.push(
3618         Inst::new(
3619             "atomic_store",
3620             r#"
3621         Atomically store `x` to memory at `p`.
3622 
3623         This is a polymorphic instruction that can store any value type with a memory
3624         representation.  It should only be used for integer types with 8, 16, 32 or 64 bits.
3625         This operation is sequentially consistent and creates happens-before edges that order
3626         normal (non-atomic) loads and stores.
3627         "#,
3628             &formats.store_no_offset,
3629         )
3630         .operands_in(vec![MemFlags, x, p])
3631         .can_store(true)
3632         .other_side_effects(true),
3633     );
3634 
3635     ig.push(
3636         Inst::new(
3637             "fence",
3638             r#"
3639         A memory fence.  This must provide ordering to ensure that, at a minimum, neither loads
3640         nor stores of any kind may move forwards or backwards across the fence.  This operation
3641         is sequentially consistent.
3642         "#,
3643             &formats.nullary,
3644         )
3645         .other_side_effects(true),
3646     );
3647 
3648     let TxN = &TypeVar::new(
3649         "TxN",
3650         "A dynamic vector type",
3651         TypeSetBuilder::new()
3652             .ints(Interval::All)
3653             .floats(Interval::All)
3654             .dynamic_simd_lanes(Interval::All)
3655             .build(),
3656     );
3657     let x = &Operand::new("x", TxN).with_doc("The dynamic vector to extract from");
3658     let y = &Operand::new("y", &imm.uimm8).with_doc("128-bit vector index");
3659     let a = &Operand::new("a", &TxN.dynamic_to_vector()).with_doc("New fixed vector");
3660 
3661     ig.push(
3662         Inst::new(
3663             "extract_vector",
3664             r#"
3665         Return a fixed length sub vector, extracted from a dynamic vector.
3666         "#,
3667             &formats.binary_imm8,
3668         )
3669         .operands_in(vec![x, y])
3670         .operands_out(vec![a]),
3671     );
3672 }
3673