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