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