1 #![expect(non_snake_case, reason = "DSL style here")]
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             "sadd_overflow_cin",
2012             r#"
2013         Add signed integers with carry in and overflow out.
2014 
2015         Same as `sadd_overflow` with an additional carry input. The `c_in` type
2016         is interpreted as 1 if it's nonzero or 0 if it's zero.
2017         "#,
2018             &formats.ternary,
2019         )
2020         .operands_in(vec![
2021             Operand::new("x", iB),
2022             Operand::new("y", iB),
2023             Operand::new("c_in", i8).with_doc("Input carry flag"),
2024         ])
2025         .operands_out(vec![
2026             Operand::new("a", iB),
2027             Operand::new("c_out", i8).with_doc("Output carry flag"),
2028         ]),
2029     );
2030 
2031     ig.push(
2032         Inst::new(
2033             "uadd_overflow_cin",
2034             r#"
2035         Add unsigned integers with carry in and overflow out.
2036 
2037         Same as `uadd_overflow` with an additional carry input. The `c_in` type
2038         is interpreted as 1 if it's nonzero or 0 if it's zero.
2039         "#,
2040             &formats.ternary,
2041         )
2042         .operands_in(vec![
2043             Operand::new("x", iB),
2044             Operand::new("y", iB),
2045             Operand::new("c_in", i8).with_doc("Input carry flag"),
2046         ])
2047         .operands_out(vec![
2048             Operand::new("a", iB),
2049             Operand::new("c_out", i8).with_doc("Output carry flag"),
2050         ]),
2051     );
2052 
2053     {
2054         let of_out = Operand::new("of", i8).with_doc("Overflow flag");
2055         ig.push(
2056             Inst::new(
2057                 "uadd_overflow",
2058                 r#"
2059             Add integers unsigned with overflow out.
2060             ``of`` is set when the addition overflowed.
2061             ```text
2062                 a &= x + y \pmod 2^B \\
2063                 of &= x+y >= 2^B
2064             ```
2065             Polymorphic over all scalar integer types, but does not support vector
2066             types.
2067             "#,
2068                 &formats.binary,
2069             )
2070             .operands_in(vec![Operand::new("x", iB), Operand::new("y", iB)])
2071             .operands_out(vec![Operand::new("a", iB), of_out.clone()]),
2072         );
2073 
2074         ig.push(
2075             Inst::new(
2076                 "sadd_overflow",
2077                 r#"
2078             Add integers signed with overflow out.
2079             ``of`` is set when the addition over- or underflowed.
2080             Polymorphic over all scalar integer types, but does not support vector
2081             types.
2082             "#,
2083                 &formats.binary,
2084             )
2085             .operands_in(vec![Operand::new("x", iB), Operand::new("y", iB)])
2086             .operands_out(vec![Operand::new("a", iB), of_out.clone()]),
2087         );
2088 
2089         ig.push(
2090             Inst::new(
2091                 "usub_overflow",
2092                 r#"
2093             Subtract integers unsigned with overflow out.
2094             ``of`` is set when the subtraction underflowed.
2095             ```text
2096                 a &= x - y \pmod 2^B \\
2097                 of &= x - y < 0
2098             ```
2099             Polymorphic over all scalar integer types, but does not support vector
2100             types.
2101             "#,
2102                 &formats.binary,
2103             )
2104             .operands_in(vec![Operand::new("x", iB), Operand::new("y", iB)])
2105             .operands_out(vec![Operand::new("a", iB), of_out.clone()]),
2106         );
2107 
2108         ig.push(
2109             Inst::new(
2110                 "ssub_overflow",
2111                 r#"
2112             Subtract integers signed with overflow out.
2113             ``of`` is set when the subtraction over- or underflowed.
2114             Polymorphic over all scalar integer types, but does not support vector
2115             types.
2116             "#,
2117                 &formats.binary,
2118             )
2119             .operands_in(vec![Operand::new("x", iB), Operand::new("y", iB)])
2120             .operands_out(vec![Operand::new("a", iB), of_out.clone()]),
2121         );
2122 
2123         {
2124             let NarrowScalar = &TypeVar::new(
2125                 "NarrowScalar",
2126                 "A scalar integer type up to 64 bits",
2127                 TypeSetBuilder::new().ints(8..64).build(),
2128             );
2129 
2130             ig.push(
2131                 Inst::new(
2132                     "umul_overflow",
2133                     r#"
2134                 Multiply integers unsigned with overflow out.
2135                 ``of`` is set when the multiplication overflowed.
2136                 ```text
2137                     a &= x * y \pmod 2^B \\
2138                     of &= x * y > 2^B
2139                 ```
2140                 Polymorphic over all scalar integer types except i128, but does not support vector
2141                 types.
2142                 "#,
2143                     &formats.binary,
2144                 )
2145                 .operands_in(vec![
2146                     Operand::new("x", NarrowScalar),
2147                     Operand::new("y", NarrowScalar),
2148                 ])
2149                 .operands_out(vec![Operand::new("a", NarrowScalar), of_out.clone()]),
2150             );
2151 
2152             ig.push(
2153                 Inst::new(
2154                     "smul_overflow",
2155                     r#"
2156                 Multiply integers signed with overflow out.
2157                 ``of`` is set when the multiplication over- or underflowed.
2158                 Polymorphic over all scalar integer types except i128, but does not support vector
2159                 types.
2160                 "#,
2161                     &formats.binary,
2162                 )
2163                 .operands_in(vec![
2164                     Operand::new("x", NarrowScalar),
2165                     Operand::new("y", NarrowScalar),
2166                 ])
2167                 .operands_out(vec![Operand::new("a", NarrowScalar), of_out.clone()]),
2168             );
2169         }
2170     }
2171 
2172     let i32_64 = &TypeVar::new(
2173         "i32_64",
2174         "A 32 or 64-bit scalar integer type",
2175         TypeSetBuilder::new().ints(32..64).build(),
2176     );
2177 
2178     ig.push(
2179         Inst::new(
2180             "uadd_overflow_trap",
2181             r#"
2182         Unsigned addition of x and y, trapping if the result overflows.
2183 
2184         Accepts 32 or 64-bit integers, and does not support vector types.
2185         "#,
2186             &formats.int_add_trap,
2187         )
2188         .operands_in(vec![
2189             Operand::new("x", i32_64),
2190             Operand::new("y", i32_64),
2191             Operand::new("code", &imm.trapcode),
2192         ])
2193         .operands_out(vec![Operand::new("a", i32_64)])
2194         .can_trap()
2195         .side_effects_idempotent(),
2196     );
2197 
2198     ig.push(
2199         Inst::new(
2200             "ssub_overflow_bin",
2201             r#"
2202         Subtract signed integers with borrow in and overflow out.
2203 
2204         Same as `ssub_overflow` with an additional borrow input. The `b_in` type
2205         is interpreted as 1 if it's nonzero or 0 if it's zero. The computation
2206         performed here is `x - (y + (b_in != 0))`.
2207         "#,
2208             &formats.ternary,
2209         )
2210         .operands_in(vec![
2211             Operand::new("x", iB),
2212             Operand::new("y", iB),
2213             Operand::new("b_in", i8).with_doc("Input borrow flag"),
2214         ])
2215         .operands_out(vec![
2216             Operand::new("a", iB),
2217             Operand::new("b_out", i8).with_doc("Output borrow flag"),
2218         ]),
2219     );
2220 
2221     ig.push(
2222         Inst::new(
2223             "usub_overflow_bin",
2224             r#"
2225         Subtract unsigned integers with borrow in and overflow out.
2226 
2227         Same as `usub_overflow` with an additional borrow input. The `b_in` type
2228         is interpreted as 1 if it's nonzero or 0 if it's zero. The computation
2229         performed here is `x - (y + (b_in != 0))`.
2230         "#,
2231             &formats.ternary,
2232         )
2233         .operands_in(vec![
2234             Operand::new("x", iB),
2235             Operand::new("y", iB),
2236             Operand::new("b_in", i8).with_doc("Input borrow flag"),
2237         ])
2238         .operands_out(vec![
2239             Operand::new("a", iB),
2240             Operand::new("b_out", i8).with_doc("Output borrow flag"),
2241         ]),
2242     );
2243 
2244     let bits = &TypeVar::new(
2245         "bits",
2246         "Any integer, float, or vector type",
2247         TypeSetBuilder::new()
2248             .ints(Interval::All)
2249             .floats(Interval::All)
2250             .simd_lanes(Interval::All)
2251             .includes_scalars(true)
2252             .build(),
2253     );
2254 
2255     ig.push(
2256         Inst::new(
2257             "band",
2258             r#"
2259         Bitwise and.
2260         "#,
2261             &formats.binary,
2262         )
2263         .operands_in(vec![Operand::new("x", bits), Operand::new("y", bits)])
2264         .operands_out(vec![Operand::new("a", bits)]),
2265     );
2266 
2267     ig.push(
2268         Inst::new(
2269             "bor",
2270             r#"
2271         Bitwise or.
2272         "#,
2273             &formats.binary,
2274         )
2275         .operands_in(vec![Operand::new("x", bits), Operand::new("y", bits)])
2276         .operands_out(vec![Operand::new("a", bits)]),
2277     );
2278 
2279     ig.push(
2280         Inst::new(
2281             "bxor",
2282             r#"
2283         Bitwise xor.
2284         "#,
2285             &formats.binary,
2286         )
2287         .operands_in(vec![Operand::new("x", bits), Operand::new("y", bits)])
2288         .operands_out(vec![Operand::new("a", bits)]),
2289     );
2290 
2291     ig.push(
2292         Inst::new(
2293             "bnot",
2294             r#"
2295         Bitwise not.
2296         "#,
2297             &formats.unary,
2298         )
2299         .operands_in(vec![Operand::new("x", bits)])
2300         .operands_out(vec![Operand::new("a", bits)]),
2301     );
2302 
2303     ig.push(
2304         Inst::new(
2305             "band_not",
2306             r#"
2307         Bitwise and not.
2308 
2309         Computes `x & ~y`.
2310         "#,
2311             &formats.binary,
2312         )
2313         .operands_in(vec![Operand::new("x", bits), Operand::new("y", bits)])
2314         .operands_out(vec![Operand::new("a", bits)]),
2315     );
2316 
2317     ig.push(
2318         Inst::new(
2319             "bor_not",
2320             r#"
2321         Bitwise or not.
2322 
2323         Computes `x | ~y`.
2324         "#,
2325             &formats.binary,
2326         )
2327         .operands_in(vec![Operand::new("x", bits), Operand::new("y", bits)])
2328         .operands_out(vec![Operand::new("a", bits)]),
2329     );
2330 
2331     ig.push(
2332         Inst::new(
2333             "bxor_not",
2334             r#"
2335         Bitwise xor not.
2336 
2337         Computes `x ^ ~y`.
2338         "#,
2339             &formats.binary,
2340         )
2341         .operands_in(vec![Operand::new("x", bits), Operand::new("y", bits)])
2342         .operands_out(vec![Operand::new("a", bits)]),
2343     );
2344 
2345     ig.push(
2346         Inst::new(
2347             "band_imm",
2348             r#"
2349         Bitwise and with immediate.
2350 
2351         Same as `band`, but one operand is a zero extended 64 bit immediate constant.
2352 
2353         Polymorphic over all scalar integer types, but does not support vector
2354         types.
2355         "#,
2356             &formats.binary_imm64,
2357         )
2358         .operands_in(vec![Operand::new("x", iB), Operand::new("Y", &imm.imm64)])
2359         .operands_out(vec![Operand::new("a", iB)]),
2360     );
2361 
2362     ig.push(
2363         Inst::new(
2364             "bor_imm",
2365             r#"
2366         Bitwise or with immediate.
2367 
2368         Same as `bor`, but one operand is a zero extended 64 bit immediate constant.
2369 
2370         Polymorphic over all scalar integer types, but does not support vector
2371         types.
2372         "#,
2373             &formats.binary_imm64,
2374         )
2375         .operands_in(vec![Operand::new("x", iB), Operand::new("Y", &imm.imm64)])
2376         .operands_out(vec![Operand::new("a", iB)]),
2377     );
2378 
2379     ig.push(
2380         Inst::new(
2381             "bxor_imm",
2382             r#"
2383         Bitwise xor with immediate.
2384 
2385         Same as `bxor`, but one operand is a zero extended 64 bit immediate constant.
2386 
2387         Polymorphic over all scalar integer types, but does not support vector
2388         types.
2389         "#,
2390             &formats.binary_imm64,
2391         )
2392         .operands_in(vec![Operand::new("x", iB), Operand::new("Y", &imm.imm64)])
2393         .operands_out(vec![Operand::new("a", iB)]),
2394     );
2395 
2396     ig.push(
2397         Inst::new(
2398             "rotl",
2399             r#"
2400         Rotate left.
2401 
2402         Rotate the bits in ``x`` by ``y`` places.
2403         "#,
2404             &formats.binary,
2405         )
2406         .operands_in(vec![
2407             Operand::new("x", Int).with_doc("Scalar or vector value to shift"),
2408             Operand::new("y", iB).with_doc("Number of bits to shift"),
2409         ])
2410         .operands_out(vec![Operand::new("a", Int)]),
2411     );
2412 
2413     ig.push(
2414         Inst::new(
2415             "rotr",
2416             r#"
2417         Rotate right.
2418 
2419         Rotate the bits in ``x`` by ``y`` places.
2420         "#,
2421             &formats.binary,
2422         )
2423         .operands_in(vec![
2424             Operand::new("x", Int).with_doc("Scalar or vector value to shift"),
2425             Operand::new("y", iB).with_doc("Number of bits to shift"),
2426         ])
2427         .operands_out(vec![Operand::new("a", Int)]),
2428     );
2429 
2430     ig.push(
2431         Inst::new(
2432             "rotl_imm",
2433             r#"
2434         Rotate left by immediate.
2435 
2436         Same as `rotl`, but one operand is a zero extended 64 bit immediate constant.
2437         "#,
2438             &formats.binary_imm64,
2439         )
2440         .operands_in(vec![
2441             Operand::new("x", Int).with_doc("Scalar or vector value to shift"),
2442             Operand::new("Y", &imm.imm64),
2443         ])
2444         .operands_out(vec![Operand::new("a", Int)]),
2445     );
2446 
2447     ig.push(
2448         Inst::new(
2449             "rotr_imm",
2450             r#"
2451         Rotate right by immediate.
2452 
2453         Same as `rotr`, but one operand is a zero extended 64 bit immediate constant.
2454         "#,
2455             &formats.binary_imm64,
2456         )
2457         .operands_in(vec![
2458             Operand::new("x", Int).with_doc("Scalar or vector value to shift"),
2459             Operand::new("Y", &imm.imm64),
2460         ])
2461         .operands_out(vec![Operand::new("a", Int)]),
2462     );
2463 
2464     ig.push(
2465         Inst::new(
2466             "ishl",
2467             r#"
2468         Integer shift left. Shift the bits in ``x`` towards the MSB by ``y``
2469         places. Shift in zero bits to the LSB.
2470 
2471         The shift amount is masked to the size of ``x``.
2472 
2473         When shifting a B-bits integer type, this instruction computes:
2474 
2475         ```text
2476             s &:= y \pmod B,
2477             a &:= x \cdot 2^s \pmod{2^B}.
2478         ```
2479         "#,
2480             &formats.binary,
2481         )
2482         .operands_in(vec![
2483             Operand::new("x", Int).with_doc("Scalar or vector value to shift"),
2484             Operand::new("y", iB).with_doc("Number of bits to shift"),
2485         ])
2486         .operands_out(vec![Operand::new("a", Int)]),
2487     );
2488 
2489     ig.push(
2490         Inst::new(
2491             "ushr",
2492             r#"
2493         Unsigned shift right. Shift bits in ``x`` towards the LSB by ``y``
2494         places, shifting in zero bits to the MSB. Also called a *logical
2495         shift*.
2496 
2497         The shift amount is masked to the size of ``x``.
2498 
2499         When shifting a B-bits integer type, this instruction computes:
2500 
2501         ```text
2502             s &:= y \pmod B,
2503             a &:= \lfloor x \cdot 2^{-s} \rfloor.
2504         ```
2505         "#,
2506             &formats.binary,
2507         )
2508         .operands_in(vec![
2509             Operand::new("x", Int).with_doc("Scalar or vector value to shift"),
2510             Operand::new("y", iB).with_doc("Number of bits to shift"),
2511         ])
2512         .operands_out(vec![Operand::new("a", Int)]),
2513     );
2514 
2515     ig.push(
2516         Inst::new(
2517             "sshr",
2518             r#"
2519         Signed shift right. Shift bits in ``x`` towards the LSB by ``y``
2520         places, shifting in sign bits to the MSB. Also called an *arithmetic
2521         shift*.
2522 
2523         The shift amount is masked to the size of ``x``.
2524         "#,
2525             &formats.binary,
2526         )
2527         .operands_in(vec![
2528             Operand::new("x", Int).with_doc("Scalar or vector value to shift"),
2529             Operand::new("y", iB).with_doc("Number of bits to shift"),
2530         ])
2531         .operands_out(vec![Operand::new("a", Int)]),
2532     );
2533 
2534     ig.push(
2535         Inst::new(
2536             "ishl_imm",
2537             r#"
2538         Integer shift left by immediate.
2539 
2540         The shift amount is masked to the size of ``x``.
2541         "#,
2542             &formats.binary_imm64,
2543         )
2544         .operands_in(vec![
2545             Operand::new("x", Int).with_doc("Scalar or vector value to shift"),
2546             Operand::new("Y", &imm.imm64),
2547         ])
2548         .operands_out(vec![Operand::new("a", Int)]),
2549     );
2550 
2551     ig.push(
2552         Inst::new(
2553             "ushr_imm",
2554             r#"
2555         Unsigned shift right by immediate.
2556 
2557         The shift amount is masked to the size of ``x``.
2558         "#,
2559             &formats.binary_imm64,
2560         )
2561         .operands_in(vec![
2562             Operand::new("x", Int).with_doc("Scalar or vector value to shift"),
2563             Operand::new("Y", &imm.imm64),
2564         ])
2565         .operands_out(vec![Operand::new("a", Int)]),
2566     );
2567 
2568     ig.push(
2569         Inst::new(
2570             "sshr_imm",
2571             r#"
2572         Signed shift right by immediate.
2573 
2574         The shift amount is masked to the size of ``x``.
2575         "#,
2576             &formats.binary_imm64,
2577         )
2578         .operands_in(vec![
2579             Operand::new("x", Int).with_doc("Scalar or vector value to shift"),
2580             Operand::new("Y", &imm.imm64),
2581         ])
2582         .operands_out(vec![Operand::new("a", Int)]),
2583     );
2584 
2585     ig.push(
2586         Inst::new(
2587             "bitrev",
2588             r#"
2589         Reverse the bits of a integer.
2590 
2591         Reverses the bits in ``x``.
2592         "#,
2593             &formats.unary,
2594         )
2595         .operands_in(vec![Operand::new("x", iB)])
2596         .operands_out(vec![Operand::new("a", iB)]),
2597     );
2598 
2599     ig.push(
2600         Inst::new(
2601             "clz",
2602             r#"
2603         Count leading zero bits.
2604 
2605         Starting from the MSB in ``x``, count the number of zero bits before
2606         reaching the first one bit. When ``x`` is zero, returns the size of x
2607         in bits.
2608         "#,
2609             &formats.unary,
2610         )
2611         .operands_in(vec![Operand::new("x", iB)])
2612         .operands_out(vec![Operand::new("a", iB)]),
2613     );
2614 
2615     ig.push(
2616         Inst::new(
2617             "cls",
2618             r#"
2619         Count leading sign bits.
2620 
2621         Starting from the MSB after the sign bit in ``x``, count the number of
2622         consecutive bits identical to the sign bit. When ``x`` is 0 or -1,
2623         returns one less than the size of x in bits.
2624         "#,
2625             &formats.unary,
2626         )
2627         .operands_in(vec![Operand::new("x", iB)])
2628         .operands_out(vec![Operand::new("a", iB)]),
2629     );
2630 
2631     ig.push(
2632         Inst::new(
2633             "ctz",
2634             r#"
2635         Count trailing zeros.
2636 
2637         Starting from the LSB in ``x``, count the number of zero bits before
2638         reaching the first one bit. When ``x`` is zero, returns the size of x
2639         in bits.
2640         "#,
2641             &formats.unary,
2642         )
2643         .operands_in(vec![Operand::new("x", iB)])
2644         .operands_out(vec![Operand::new("a", iB)]),
2645     );
2646 
2647     ig.push(
2648         Inst::new(
2649             "bswap",
2650             r#"
2651         Reverse the byte order of an integer.
2652 
2653         Reverses the bytes in ``x``.
2654         "#,
2655             &formats.unary,
2656         )
2657         .operands_in(vec![Operand::new("x", iSwappable)])
2658         .operands_out(vec![Operand::new("a", iSwappable)]),
2659     );
2660 
2661     ig.push(
2662         Inst::new(
2663             "popcnt",
2664             r#"
2665         Population count
2666 
2667         Count the number of one bits in ``x``.
2668         "#,
2669             &formats.unary,
2670         )
2671         .operands_in(vec![Operand::new("x", Int)])
2672         .operands_out(vec![Operand::new("a", Int)]),
2673     );
2674 
2675     let Float = &TypeVar::new(
2676         "Float",
2677         "A scalar or vector floating point number",
2678         TypeSetBuilder::new()
2679             .floats(Interval::All)
2680             .simd_lanes(Interval::All)
2681             .dynamic_simd_lanes(Interval::All)
2682             .build(),
2683     );
2684 
2685     ig.push(
2686         Inst::new(
2687             "fcmp",
2688             r#"
2689         Floating point comparison.
2690 
2691         Two IEEE 754-2008 floating point numbers, `x` and `y`, relate to each
2692         other in exactly one of four ways:
2693 
2694         ```text
2695         == ==========================================
2696         UN Unordered when one or both numbers is NaN.
2697         EQ When `x = y`. (And `0.0 = -0.0`).
2698         LT When `x < y`.
2699         GT When `x > y`.
2700         == ==========================================
2701         ```
2702 
2703         The 14 `floatcc` condition codes each correspond to a subset of
2704         the four relations, except for the empty set which would always be
2705         false, and the full set which would always be true.
2706 
2707         The condition codes are divided into 7 'ordered' conditions which don't
2708         include UN, and 7 unordered conditions which all include UN.
2709 
2710         ```text
2711         +-------+------------+---------+------------+-------------------------+
2712         |Ordered             |Unordered             |Condition                |
2713         +=======+============+=========+============+=========================+
2714         |ord    |EQ | LT | GT|uno      |UN          |NaNs absent / present.   |
2715         +-------+------------+---------+------------+-------------------------+
2716         |eq     |EQ          |ueq      |UN | EQ     |Equal                    |
2717         +-------+------------+---------+------------+-------------------------+
2718         |one    |LT | GT     |ne       |UN | LT | GT|Not equal                |
2719         +-------+------------+---------+------------+-------------------------+
2720         |lt     |LT          |ult      |UN | LT     |Less than                |
2721         +-------+------------+---------+------------+-------------------------+
2722         |le     |LT | EQ     |ule      |UN | LT | EQ|Less than or equal       |
2723         +-------+------------+---------+------------+-------------------------+
2724         |gt     |GT          |ugt      |UN | GT     |Greater than             |
2725         +-------+------------+---------+------------+-------------------------+
2726         |ge     |GT | EQ     |uge      |UN | GT | EQ|Greater than or equal    |
2727         +-------+------------+---------+------------+-------------------------+
2728         ```
2729 
2730         The standard C comparison operators, `<, <=, >, >=`, are all ordered,
2731         so they are false if either operand is NaN. The C equality operator,
2732         `==`, is ordered, and since inequality is defined as the logical
2733         inverse it is *unordered*. They map to the `floatcc` condition
2734         codes as follows:
2735 
2736         ```text
2737         ==== ====== ============
2738         C    `Cond` Subset
2739         ==== ====== ============
2740         `==` eq     EQ
2741         `!=` ne     UN | LT | GT
2742         `<`  lt     LT
2743         `<=` le     LT | EQ
2744         `>`  gt     GT
2745         `>=` ge     GT | EQ
2746         ==== ====== ============
2747         ```
2748 
2749         This subset of condition codes also corresponds to the WebAssembly
2750         floating point comparisons of the same name.
2751 
2752         When this instruction compares floating point vectors, it returns a
2753         vector with the results of lane-wise comparisons.
2754 
2755         When comparing scalars, the result is:
2756             - `1` if the condition holds.
2757             - `0` if the condition does not hold.
2758 
2759         When comparing vectors, the result is:
2760             - `-1` (i.e. all ones) in each lane where the condition holds.
2761             - `0` in each lane where the condition does not hold.
2762         "#,
2763             &formats.float_compare,
2764         )
2765         .operands_in(vec![
2766             Operand::new("Cond", &imm.floatcc),
2767             Operand::new("x", Float),
2768             Operand::new("y", Float),
2769         ])
2770         .operands_out(vec![Operand::new("a", &Float.as_truthy())]),
2771     );
2772 
2773     ig.push(
2774         Inst::new(
2775             "fadd",
2776             r#"
2777         Floating point addition.
2778         "#,
2779             &formats.binary,
2780         )
2781         .operands_in(vec![Operand::new("x", Float), Operand::new("y", Float)])
2782         .operands_out(vec![
2783             Operand::new("a", Float).with_doc("Result of applying operator to each lane")
2784         ]),
2785     );
2786 
2787     ig.push(
2788         Inst::new(
2789             "fsub",
2790             r#"
2791         Floating point subtraction.
2792         "#,
2793             &formats.binary,
2794         )
2795         .operands_in(vec![Operand::new("x", Float), Operand::new("y", Float)])
2796         .operands_out(vec![
2797             Operand::new("a", Float).with_doc("Result of applying operator to each lane")
2798         ]),
2799     );
2800 
2801     ig.push(
2802         Inst::new(
2803             "fmul",
2804             r#"
2805         Floating point multiplication.
2806         "#,
2807             &formats.binary,
2808         )
2809         .operands_in(vec![Operand::new("x", Float), Operand::new("y", Float)])
2810         .operands_out(vec![
2811             Operand::new("a", Float).with_doc("Result of applying operator to each lane")
2812         ]),
2813     );
2814 
2815     ig.push(
2816         Inst::new(
2817             "fdiv",
2818             r#"
2819         Floating point division.
2820 
2821         Unlike the integer division instructions ` and
2822         `udiv`, this can't trap. Division by zero is infinity or
2823         NaN, depending on the dividend.
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             "sqrt",
2836             r#"
2837         Floating point square root.
2838         "#,
2839             &formats.unary,
2840         )
2841         .operands_in(vec![Operand::new("x", Float)])
2842         .operands_out(vec![
2843             Operand::new("a", Float).with_doc("Result of applying operator to each lane")
2844         ]),
2845     );
2846 
2847     ig.push(
2848         Inst::new(
2849             "fma",
2850             r#"
2851         Floating point fused multiply-and-add.
2852 
2853         Computes `a := xy+z` without any intermediate rounding of the
2854         product.
2855         "#,
2856             &formats.ternary,
2857         )
2858         .operands_in(vec![
2859             Operand::new("x", Float),
2860             Operand::new("y", Float),
2861             Operand::new("z", Float),
2862         ])
2863         .operands_out(vec![
2864             Operand::new("a", Float).with_doc("Result of applying operator to each lane")
2865         ]),
2866     );
2867 
2868     ig.push(
2869         Inst::new(
2870             "fneg",
2871             r#"
2872         Floating point negation.
2873 
2874         Note that this is a pure bitwise operation.
2875         "#,
2876             &formats.unary,
2877         )
2878         .operands_in(vec![Operand::new("x", Float)])
2879         .operands_out(vec![
2880             Operand::new("a", Float).with_doc("``x`` with its sign bit inverted")
2881         ]),
2882     );
2883 
2884     ig.push(
2885         Inst::new(
2886             "fabs",
2887             r#"
2888         Floating point absolute value.
2889 
2890         Note that this is a pure bitwise operation.
2891         "#,
2892             &formats.unary,
2893         )
2894         .operands_in(vec![Operand::new("x", Float)])
2895         .operands_out(vec![
2896             Operand::new("a", Float).with_doc("``x`` with its sign bit cleared")
2897         ]),
2898     );
2899 
2900     ig.push(
2901         Inst::new(
2902             "fcopysign",
2903             r#"
2904         Floating point copy sign.
2905 
2906         Note that this is a pure bitwise operation. The sign bit from ``y`` is
2907         copied to the sign bit of ``x``.
2908         "#,
2909             &formats.binary,
2910         )
2911         .operands_in(vec![Operand::new("x", Float), Operand::new("y", Float)])
2912         .operands_out(vec![
2913             Operand::new("a", Float).with_doc("``x`` with its sign bit changed to that of ``y``")
2914         ]),
2915     );
2916 
2917     ig.push(
2918         Inst::new(
2919             "fmin",
2920             r#"
2921         Floating point minimum, propagating NaNs using the WebAssembly rules.
2922 
2923         If either operand is NaN, this returns NaN with an unspecified sign. Furthermore, if
2924         each input NaN consists of a mantissa whose most significant bit is 1 and the rest is
2925         0, then the output has the same form. Otherwise, the output mantissa's most significant
2926         bit is 1 and the rest is unspecified.
2927         "#,
2928             &formats.binary,
2929         )
2930         .operands_in(vec![Operand::new("x", Float), Operand::new("y", Float)])
2931         .operands_out(vec![
2932             Operand::new("a", Float).with_doc("The smaller of ``x`` and ``y``")
2933         ]),
2934     );
2935 
2936     ig.push(
2937         Inst::new(
2938             "fmax",
2939             r#"
2940         Floating point maximum, propagating NaNs using the WebAssembly rules.
2941 
2942         If either operand is NaN, this returns NaN with an unspecified sign. Furthermore, if
2943         each input NaN consists of a mantissa whose most significant bit is 1 and the rest is
2944         0, then the output has the same form. Otherwise, the output mantissa's most significant
2945         bit is 1 and the rest is unspecified.
2946         "#,
2947             &formats.binary,
2948         )
2949         .operands_in(vec![Operand::new("x", Float), Operand::new("y", Float)])
2950         .operands_out(vec![
2951             Operand::new("a", Float).with_doc("The larger of ``x`` and ``y``")
2952         ]),
2953     );
2954 
2955     ig.push(
2956         Inst::new(
2957             "ceil",
2958             r#"
2959         Round floating point round to integral, towards positive infinity.
2960         "#,
2961             &formats.unary,
2962         )
2963         .operands_in(vec![Operand::new("x", Float)])
2964         .operands_out(vec![
2965             Operand::new("a", Float).with_doc("``x`` rounded to integral value")
2966         ]),
2967     );
2968 
2969     ig.push(
2970         Inst::new(
2971             "floor",
2972             r#"
2973         Round floating point round to integral, towards negative infinity.
2974         "#,
2975             &formats.unary,
2976         )
2977         .operands_in(vec![Operand::new("x", Float)])
2978         .operands_out(vec![
2979             Operand::new("a", Float).with_doc("``x`` rounded to integral value")
2980         ]),
2981     );
2982 
2983     ig.push(
2984         Inst::new(
2985             "trunc",
2986             r#"
2987         Round floating point round to integral, towards zero.
2988         "#,
2989             &formats.unary,
2990         )
2991         .operands_in(vec![Operand::new("x", Float)])
2992         .operands_out(vec![
2993             Operand::new("a", Float).with_doc("``x`` rounded to integral value")
2994         ]),
2995     );
2996 
2997     ig.push(
2998         Inst::new(
2999             "nearest",
3000             r#"
3001         Round floating point round to integral, towards nearest with ties to
3002         even.
3003         "#,
3004             &formats.unary,
3005         )
3006         .operands_in(vec![Operand::new("x", Float)])
3007         .operands_out(vec![
3008             Operand::new("a", Float).with_doc("``x`` rounded to integral value")
3009         ]),
3010     );
3011 
3012     ig.push(
3013         Inst::new(
3014             "bitcast",
3015             r#"
3016         Reinterpret the bits in `x` as a different type.
3017 
3018         The input and output types must be storable to memory and of the same
3019         size. A bitcast is equivalent to storing one type and loading the other
3020         type from the same address, both using the specified MemFlags.
3021 
3022         Note that this operation only supports the `big` or `little` MemFlags.
3023         The specified byte order only affects the result in the case where
3024         input and output types differ in lane count/size.  In this case, the
3025         operation is only valid if a byte order specifier is provided.
3026         "#,
3027             &formats.load_no_offset,
3028         )
3029         .operands_in(vec![
3030             Operand::new("MemFlags", &imm.memflags),
3031             Operand::new("x", Mem),
3032         ])
3033         .operands_out(vec![
3034             Operand::new("a", MemTo).with_doc("Bits of `x` reinterpreted")
3035         ]),
3036     );
3037 
3038     ig.push(
3039         Inst::new(
3040             "scalar_to_vector",
3041             r#"
3042             Copies a scalar value to a vector value.  The scalar is copied into the
3043             least significant lane of the vector, and all other lanes will be zero.
3044             "#,
3045             &formats.unary,
3046         )
3047         .operands_in(vec![
3048             Operand::new("s", &TxN.lane_of()).with_doc("A scalar value")
3049         ])
3050         .operands_out(vec![Operand::new("a", TxN).with_doc("A vector value")]),
3051     );
3052 
3053     let Truthy = &TypeVar::new(
3054         "Truthy",
3055         "A scalar whose values are truthy",
3056         TypeSetBuilder::new().ints(Interval::All).build(),
3057     );
3058     let IntTo = &TypeVar::new(
3059         "IntTo",
3060         "An integer type",
3061         TypeSetBuilder::new().ints(Interval::All).build(),
3062     );
3063 
3064     ig.push(
3065         Inst::new(
3066             "bmask",
3067             r#"
3068         Convert `x` to an integer mask.
3069 
3070         Non-zero maps to all 1s and zero maps to all 0s.
3071         "#,
3072             &formats.unary,
3073         )
3074         .operands_in(vec![Operand::new("x", Truthy)])
3075         .operands_out(vec![Operand::new("a", IntTo)]),
3076     );
3077 
3078     let Int = &TypeVar::new(
3079         "Int",
3080         "A scalar integer type",
3081         TypeSetBuilder::new().ints(Interval::All).build(),
3082     );
3083 
3084     ig.push(
3085         Inst::new(
3086             "ireduce",
3087             r#"
3088         Convert `x` to a smaller integer type by discarding
3089         the most significant bits.
3090 
3091         This is the same as reducing modulo `2^n`.
3092         "#,
3093             &formats.unary,
3094         )
3095         .operands_in(vec![Operand::new("x", &Int.wider())
3096             .with_doc("A scalar integer type, wider than the controlling type")])
3097         .operands_out(vec![Operand::new("a", Int)]),
3098     );
3099 
3100     let I16or32or64xN = &TypeVar::new(
3101         "I16or32or64xN",
3102         "A SIMD vector type containing integer lanes 16, 32, or 64 bits wide",
3103         TypeSetBuilder::new()
3104             .ints(16..64)
3105             .simd_lanes(2..8)
3106             .dynamic_simd_lanes(2..8)
3107             .includes_scalars(false)
3108             .build(),
3109     );
3110 
3111     ig.push(
3112         Inst::new(
3113             "snarrow",
3114             r#"
3115         Combine `x` and `y` into a vector with twice the lanes but half the integer width while
3116         saturating overflowing values to the signed maximum and minimum.
3117 
3118         The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4`
3119         and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value
3120         returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`.
3121             "#,
3122             &formats.binary,
3123         )
3124         .operands_in(vec![
3125             Operand::new("x", I16or32or64xN),
3126             Operand::new("y", I16or32or64xN),
3127         ])
3128         .operands_out(vec![Operand::new("a", &I16or32or64xN.split_lanes())]),
3129     );
3130 
3131     ig.push(
3132         Inst::new(
3133             "unarrow",
3134             r#"
3135         Combine `x` and `y` into a vector with twice the lanes but half the integer width while
3136         saturating overflowing values to the unsigned maximum and minimum.
3137 
3138         Note that all input lanes are considered signed: any negative lanes will overflow and be
3139         replaced with the unsigned minimum, `0x00`.
3140 
3141         The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4`
3142         and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value
3143         returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`.
3144             "#,
3145             &formats.binary,
3146         )
3147         .operands_in(vec![
3148             Operand::new("x", I16or32or64xN),
3149             Operand::new("y", I16or32or64xN),
3150         ])
3151         .operands_out(vec![Operand::new("a", &I16or32or64xN.split_lanes())]),
3152     );
3153 
3154     ig.push(
3155         Inst::new(
3156             "uunarrow",
3157             r#"
3158         Combine `x` and `y` into a vector with twice the lanes but half the integer width while
3159         saturating overflowing values to the unsigned maximum and minimum.
3160 
3161         Note that all input lanes are considered unsigned: any negative values will be interpreted as unsigned, overflowing and being replaced with the unsigned maximum.
3162 
3163         The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4`
3164         and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value
3165         returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`.
3166             "#,
3167             &formats.binary,
3168         )
3169         .operands_in(vec![Operand::new("x", I16or32or64xN), Operand::new("y", I16or32or64xN)])
3170         .operands_out(vec![Operand::new("a", &I16or32or64xN.split_lanes())]),
3171     );
3172 
3173     let I8or16or32xN = &TypeVar::new(
3174         "I8or16or32xN",
3175         "A SIMD vector type containing integer lanes 8, 16, or 32 bits wide.",
3176         TypeSetBuilder::new()
3177             .ints(8..32)
3178             .simd_lanes(2..16)
3179             .dynamic_simd_lanes(2..16)
3180             .includes_scalars(false)
3181             .build(),
3182     );
3183 
3184     ig.push(
3185         Inst::new(
3186             "swiden_low",
3187             r#"
3188         Widen the low lanes of `x` using signed extension.
3189 
3190         This will double the lane width and halve the number of lanes.
3191             "#,
3192             &formats.unary,
3193         )
3194         .operands_in(vec![Operand::new("x", I8or16or32xN)])
3195         .operands_out(vec![Operand::new("a", &I8or16or32xN.merge_lanes())]),
3196     );
3197 
3198     ig.push(
3199         Inst::new(
3200             "swiden_high",
3201             r#"
3202         Widen the high lanes of `x` using signed extension.
3203 
3204         This will double the lane width and halve the number of lanes.
3205             "#,
3206             &formats.unary,
3207         )
3208         .operands_in(vec![Operand::new("x", I8or16or32xN)])
3209         .operands_out(vec![Operand::new("a", &I8or16or32xN.merge_lanes())]),
3210     );
3211 
3212     ig.push(
3213         Inst::new(
3214             "uwiden_low",
3215             r#"
3216         Widen the low lanes of `x` using unsigned extension.
3217 
3218         This will double the lane width and halve the number of lanes.
3219             "#,
3220             &formats.unary,
3221         )
3222         .operands_in(vec![Operand::new("x", I8or16or32xN)])
3223         .operands_out(vec![Operand::new("a", &I8or16or32xN.merge_lanes())]),
3224     );
3225 
3226     ig.push(
3227         Inst::new(
3228             "uwiden_high",
3229             r#"
3230             Widen the high lanes of `x` using unsigned extension.
3231 
3232             This will double the lane width and halve the number of lanes.
3233             "#,
3234             &formats.unary,
3235         )
3236         .operands_in(vec![Operand::new("x", I8or16or32xN)])
3237         .operands_out(vec![Operand::new("a", &I8or16or32xN.merge_lanes())]),
3238     );
3239 
3240     ig.push(
3241         Inst::new(
3242             "iadd_pairwise",
3243             r#"
3244         Does lane-wise integer pairwise addition on two operands, putting the
3245         combined results into a single vector result. Here a pair refers to adjacent
3246         lanes in a vector, i.e. i*2 + (i*2+1) for i == num_lanes/2. The first operand
3247         pairwise add results will make up the low half of the resulting vector while
3248         the second operand pairwise add results will make up the upper half of the
3249         resulting vector.
3250             "#,
3251             &formats.binary,
3252         )
3253         .operands_in(vec![
3254             Operand::new("x", I8or16or32xN),
3255             Operand::new("y", I8or16or32xN),
3256         ])
3257         .operands_out(vec![Operand::new("a", I8or16or32xN)]),
3258     );
3259 
3260     let I8x16 = &TypeVar::new(
3261         "I8x16",
3262         "A SIMD vector type consisting of 16 lanes of 8-bit integers",
3263         TypeSetBuilder::new()
3264             .ints(8..8)
3265             .simd_lanes(16..16)
3266             .includes_scalars(false)
3267             .build(),
3268     );
3269 
3270     ig.push(
3271         Inst::new(
3272             "x86_pmaddubsw",
3273             r#"
3274         An instruction with equivalent semantics to `pmaddubsw` on x86.
3275 
3276         This instruction will take signed bytes from the first argument and
3277         multiply them against unsigned bytes in the second argument. Adjacent
3278         pairs are then added, with saturating, to a 16-bit value and are packed
3279         into the result.
3280             "#,
3281             &formats.binary,
3282         )
3283         .operands_in(vec![Operand::new("x", I8x16), Operand::new("y", I8x16)])
3284         .operands_out(vec![Operand::new("a", I16x8)]),
3285     );
3286 
3287     ig.push(
3288         Inst::new(
3289             "uextend",
3290             r#"
3291         Convert `x` to a larger integer type by zero-extending.
3292 
3293         Each lane in `x` is converted to a larger integer type by adding
3294         zeroes. The result has the same numerical value as `x` when both are
3295         interpreted as unsigned integers.
3296 
3297         The result type must have the same number of vector lanes as the input,
3298         and each lane must not have fewer bits that the input lanes. If the
3299         input and output types are the same, this is a no-op.
3300         "#,
3301             &formats.unary,
3302         )
3303         .operands_in(vec![Operand::new("x", &Int.narrower()).with_doc(
3304             "A scalar integer type, narrower than the controlling type",
3305         )])
3306         .operands_out(vec![Operand::new("a", Int)]),
3307     );
3308 
3309     ig.push(
3310         Inst::new(
3311             "sextend",
3312             r#"
3313         Convert `x` to a larger integer type by sign-extending.
3314 
3315         Each lane in `x` is converted to a larger integer type by replicating
3316         the sign bit. The result has the same numerical value as `x` when both
3317         are interpreted as signed integers.
3318 
3319         The result type must have the same number of vector lanes as the input,
3320         and each lane must not have fewer bits that the input lanes. If the
3321         input and output types are the same, this is a no-op.
3322         "#,
3323             &formats.unary,
3324         )
3325         .operands_in(vec![Operand::new("x", &Int.narrower()).with_doc(
3326             "A scalar integer type, narrower than the controlling type",
3327         )])
3328         .operands_out(vec![Operand::new("a", Int)]),
3329     );
3330 
3331     let FloatScalar = &TypeVar::new(
3332         "FloatScalar",
3333         "A scalar only floating point number",
3334         TypeSetBuilder::new().floats(Interval::All).build(),
3335     );
3336 
3337     ig.push(
3338         Inst::new(
3339             "fpromote",
3340             r#"
3341         Convert `x` to a larger floating point format.
3342 
3343         Each lane in `x` is converted to the destination floating point format.
3344         This is an exact operation.
3345 
3346         Cranelift currently only supports two floating point formats
3347         - `f32` and `f64`. This may change in the future.
3348 
3349         The result type must have the same number of vector lanes as the input,
3350         and the result lanes must not have fewer bits than the input lanes.
3351         "#,
3352             &formats.unary,
3353         )
3354         .operands_in(vec![Operand::new("x", &FloatScalar.narrower()).with_doc(
3355             "A scalar only floating point number, narrower than the controlling type",
3356         )])
3357         .operands_out(vec![Operand::new("a", FloatScalar)]),
3358     );
3359 
3360     ig.push(
3361         Inst::new(
3362             "fdemote",
3363             r#"
3364         Convert `x` to a smaller floating point format.
3365 
3366         Each lane in `x` is converted to the destination floating point format
3367         by rounding to nearest, ties to even.
3368 
3369         Cranelift currently only supports two floating point formats
3370         - `f32` and `f64`. This may change in the future.
3371 
3372         The result type must have the same number of vector lanes as the input,
3373         and the result lanes must not have more bits than the input lanes.
3374         "#,
3375             &formats.unary,
3376         )
3377         .operands_in(vec![Operand::new("x", &FloatScalar.wider()).with_doc(
3378             "A scalar only floating point number, wider than the controlling type",
3379         )])
3380         .operands_out(vec![Operand::new("a", FloatScalar)]),
3381     );
3382 
3383     let F64x2 = &TypeVar::new(
3384         "F64x2",
3385         "A SIMD vector type consisting of 2 lanes of 64-bit floats",
3386         TypeSetBuilder::new()
3387             .floats(64..64)
3388             .simd_lanes(2..2)
3389             .includes_scalars(false)
3390             .build(),
3391     );
3392     let F32x4 = &TypeVar::new(
3393         "F32x4",
3394         "A SIMD vector type consisting of 4 lanes of 32-bit floats",
3395         TypeSetBuilder::new()
3396             .floats(32..32)
3397             .simd_lanes(4..4)
3398             .includes_scalars(false)
3399             .build(),
3400     );
3401 
3402     ig.push(
3403         Inst::new(
3404             "fvdemote",
3405             r#"
3406                 Convert `x` to a smaller floating point format.
3407 
3408                 Each lane in `x` is converted to the destination floating point format
3409                 by rounding to nearest, ties to even.
3410 
3411                 Cranelift currently only supports two floating point formats
3412                 - `f32` and `f64`. This may change in the future.
3413 
3414                 Fvdemote differs from fdemote in that with fvdemote it targets vectors.
3415                 Fvdemote is constrained to having the input type being F64x2 and the result
3416                 type being F32x4. The result lane that was the upper half of the input lane
3417                 is initialized to zero.
3418                 "#,
3419             &formats.unary,
3420         )
3421         .operands_in(vec![Operand::new("x", F64x2)])
3422         .operands_out(vec![Operand::new("a", F32x4)]),
3423     );
3424 
3425     ig.push(
3426         Inst::new(
3427             "fvpromote_low",
3428             r#"
3429         Converts packed single precision floating point to packed double precision floating point.
3430 
3431         Considering only the lower half of the register, the low lanes in `x` are interpreted as
3432         single precision floats that are then converted to a double precision floats.
3433 
3434         The result type will have half the number of vector lanes as the input. Fvpromote_low is
3435         constrained to input F32x4 with a result type of F64x2.
3436         "#,
3437             &formats.unary,
3438         )
3439         .operands_in(vec![Operand::new("a", F32x4)])
3440         .operands_out(vec![Operand::new("x", F64x2)]),
3441     );
3442 
3443     let IntTo = &TypeVar::new(
3444         "IntTo",
3445         "An scalar only integer type",
3446         TypeSetBuilder::new().ints(Interval::All).build(),
3447     );
3448 
3449     ig.push(
3450         Inst::new(
3451             "fcvt_to_uint",
3452             r#"
3453         Converts floating point scalars to unsigned integer.
3454 
3455         Only operates on `x` if it is a scalar. If `x` is NaN or if
3456         the unsigned integral value cannot be represented in the result
3457         type, this instruction traps.
3458 
3459         "#,
3460             &formats.unary,
3461         )
3462         .operands_in(vec![Operand::new("x", FloatScalar)])
3463         .operands_out(vec![Operand::new("a", IntTo)])
3464         .can_trap()
3465         .side_effects_idempotent(),
3466     );
3467 
3468     ig.push(
3469         Inst::new(
3470             "fcvt_to_sint",
3471             r#"
3472         Converts floating point scalars to signed integer.
3473 
3474         Only operates on `x` if it is a scalar. If `x` is NaN or if
3475         the unsigned integral value cannot be represented in the result
3476         type, this instruction traps.
3477 
3478         "#,
3479             &formats.unary,
3480         )
3481         .operands_in(vec![Operand::new("x", FloatScalar)])
3482         .operands_out(vec![Operand::new("a", IntTo)])
3483         .can_trap()
3484         .side_effects_idempotent(),
3485     );
3486 
3487     let IntTo = &TypeVar::new(
3488         "IntTo",
3489         "A larger integer type with the same number of lanes",
3490         TypeSetBuilder::new()
3491             .ints(Interval::All)
3492             .simd_lanes(Interval::All)
3493             .build(),
3494     );
3495 
3496     ig.push(
3497         Inst::new(
3498             "fcvt_to_uint_sat",
3499             r#"
3500         Convert floating point to unsigned integer as fcvt_to_uint does, but
3501         saturates the input instead of trapping. NaN and negative values are
3502         converted to 0.
3503         "#,
3504             &formats.unary,
3505         )
3506         .operands_in(vec![Operand::new("x", Float)])
3507         .operands_out(vec![Operand::new("a", IntTo)]),
3508     );
3509 
3510     ig.push(
3511         Inst::new(
3512             "fcvt_to_sint_sat",
3513             r#"
3514         Convert floating point to signed integer as fcvt_to_sint does, but
3515         saturates the input instead of trapping. NaN values are converted to 0.
3516         "#,
3517             &formats.unary,
3518         )
3519         .operands_in(vec![Operand::new("x", Float)])
3520         .operands_out(vec![Operand::new("a", IntTo)]),
3521     );
3522 
3523     ig.push(
3524         Inst::new(
3525             "x86_cvtt2dq",
3526             r#"
3527         A float-to-integer conversion instruction for vectors-of-floats which
3528         has the same semantics as `cvttp{s,d}2dq` on x86. This specifically
3529         returns `INT_MIN` for NaN or out-of-bounds lanes.
3530         "#,
3531             &formats.unary,
3532         )
3533         .operands_in(vec![Operand::new("x", Float)])
3534         .operands_out(vec![Operand::new("a", IntTo)]),
3535     );
3536 
3537     let Int = &TypeVar::new(
3538         "Int",
3539         "A scalar or vector integer type",
3540         TypeSetBuilder::new()
3541             .ints(Interval::All)
3542             .simd_lanes(Interval::All)
3543             .build(),
3544     );
3545 
3546     let FloatTo = &TypeVar::new(
3547         "FloatTo",
3548         "A scalar or vector floating point number",
3549         TypeSetBuilder::new()
3550             .floats(Interval::All)
3551             .simd_lanes(Interval::All)
3552             .build(),
3553     );
3554 
3555     ig.push(
3556         Inst::new(
3557             "fcvt_from_uint",
3558             r#"
3559         Convert unsigned integer to floating point.
3560 
3561         Each lane in `x` is interpreted as an unsigned integer and converted to
3562         floating point using round to nearest, ties to even.
3563 
3564         The result type must have the same number of vector lanes as the input.
3565         "#,
3566             &formats.unary,
3567         )
3568         .operands_in(vec![Operand::new("x", Int)])
3569         .operands_out(vec![Operand::new("a", FloatTo)]),
3570     );
3571 
3572     ig.push(
3573         Inst::new(
3574             "fcvt_from_sint",
3575             r#"
3576         Convert signed integer to floating point.
3577 
3578         Each lane in `x` is interpreted as a signed integer and converted to
3579         floating point using round to nearest, ties to even.
3580 
3581         The result type must have the same number of vector lanes as the input.
3582         "#,
3583             &formats.unary,
3584         )
3585         .operands_in(vec![Operand::new("x", Int)])
3586         .operands_out(vec![Operand::new("a", FloatTo)]),
3587     );
3588 
3589     let WideInt = &TypeVar::new(
3590         "WideInt",
3591         "An integer type of width `i16` upwards",
3592         TypeSetBuilder::new().ints(16..128).build(),
3593     );
3594 
3595     ig.push(
3596         Inst::new(
3597             "isplit",
3598             r#"
3599         Split an integer into low and high parts.
3600 
3601         Vectors of integers are split lane-wise, so the results have the same
3602         number of lanes as the input, but the lanes are half the size.
3603 
3604         Returns the low half of `x` and the high half of `x` as two independent
3605         values.
3606         "#,
3607             &formats.unary,
3608         )
3609         .operands_in(vec![Operand::new("x", WideInt)])
3610         .operands_out(vec![
3611             Operand::new("lo", &WideInt.half_width()).with_doc("The low bits of `x`"),
3612             Operand::new("hi", &WideInt.half_width()).with_doc("The high bits of `x`"),
3613         ]),
3614     );
3615 
3616     ig.push(
3617         Inst::new(
3618             "iconcat",
3619             r#"
3620         Concatenate low and high bits to form a larger integer type.
3621 
3622         Vectors of integers are concatenated lane-wise such that the result has
3623         the same number of lanes as the inputs, but the lanes are twice the
3624         size.
3625         "#,
3626             &formats.binary,
3627         )
3628         .operands_in(vec![
3629             Operand::new("lo", NarrowInt),
3630             Operand::new("hi", NarrowInt),
3631         ])
3632         .operands_out(vec![Operand::new("a", &NarrowInt.double_width())
3633             .with_doc("The concatenation of `lo` and `hi`")]),
3634     );
3635 
3636     // Instructions relating to atomic memory accesses and fences
3637     let AtomicMem = &TypeVar::new(
3638         "AtomicMem",
3639         "Any type that can be stored in memory, which can be used in an atomic operation",
3640         TypeSetBuilder::new().ints(8..128).build(),
3641     );
3642 
3643     ig.push(
3644         Inst::new(
3645             "atomic_rmw",
3646             r#"
3647         Atomically read-modify-write memory at `p`, with second operand `x`.  The old value is
3648         returned.  `p` has the type of the target word size, and `x` may be any integer type; note
3649         that some targets require specific target features to be enabled in order to support 128-bit
3650         integer atomics.  The type of the returned value is the same as the type of `x`.  This
3651         operation is sequentially consistent and creates happens-before edges that order normal
3652         (non-atomic) loads and stores.
3653         "#,
3654             &formats.atomic_rmw,
3655         )
3656         .operands_in(vec![
3657             Operand::new("MemFlags", &imm.memflags),
3658             Operand::new("AtomicRmwOp", &imm.atomic_rmw_op),
3659             Operand::new("p", iAddr),
3660             Operand::new("x", AtomicMem).with_doc("Value to be atomically stored"),
3661         ])
3662         .operands_out(vec![
3663             Operand::new("a", AtomicMem).with_doc("Value atomically loaded")
3664         ])
3665         .can_load()
3666         .can_store()
3667         .other_side_effects(),
3668     );
3669 
3670     ig.push(
3671         Inst::new(
3672             "atomic_cas",
3673             r#"
3674         Perform an atomic compare-and-swap operation on memory at `p`, with expected value `e`,
3675         storing `x` if the value at `p` equals `e`.  The old value at `p` is returned,
3676         regardless of whether the operation succeeds or fails.  `p` has the type of the target
3677         word size, and `x` and `e` must have the same type and the same size, which may be any
3678         integer type; note that some targets require specific target features to be enabled in order
3679         to support 128-bit integer atomics.  The type of the returned value is the same as the type
3680         of `x` and `e`.  This operation is sequentially consistent and creates happens-before edges
3681         that order normal (non-atomic) loads and stores.
3682         "#,
3683             &formats.atomic_cas,
3684         )
3685         .operands_in(vec![
3686             Operand::new("MemFlags", &imm.memflags),
3687             Operand::new("p", iAddr),
3688             Operand::new("e", AtomicMem).with_doc("Expected value in CAS"),
3689             Operand::new("x", AtomicMem).with_doc("Value to be atomically stored"),
3690         ])
3691         .operands_out(vec![
3692             Operand::new("a", AtomicMem).with_doc("Value atomically loaded")
3693         ])
3694         .can_load()
3695         .can_store()
3696         .other_side_effects(),
3697     );
3698 
3699     ig.push(
3700         Inst::new(
3701             "atomic_load",
3702             r#"
3703         Atomically load from memory at `p`.
3704 
3705         This is a polymorphic instruction that can load any value type which has a memory
3706         representation.  It can only be used for integer types; note that some targets require
3707         specific target features to be enabled in order to support 128-bit integer atomics. This
3708         operation is sequentially consistent and creates happens-before edges that order normal
3709         (non-atomic) loads and stores.
3710         "#,
3711             &formats.load_no_offset,
3712         )
3713         .operands_in(vec![
3714             Operand::new("MemFlags", &imm.memflags),
3715             Operand::new("p", iAddr),
3716         ])
3717         .operands_out(vec![
3718             Operand::new("a", AtomicMem).with_doc("Value atomically loaded")
3719         ])
3720         .can_load()
3721         .other_side_effects(),
3722     );
3723 
3724     ig.push(
3725         Inst::new(
3726             "atomic_store",
3727             r#"
3728         Atomically store `x` to memory at `p`.
3729 
3730         This is a polymorphic instruction that can store any value type with a memory
3731         representation.  It can only be used for integer types; note that some targets require
3732         specific target features to be enabled in order to support 128-bit integer atomics This
3733         operation is sequentially consistent and creates happens-before edges that order normal
3734         (non-atomic) loads and stores.
3735         "#,
3736             &formats.store_no_offset,
3737         )
3738         .operands_in(vec![
3739             Operand::new("MemFlags", &imm.memflags),
3740             Operand::new("x", AtomicMem).with_doc("Value to be atomically stored"),
3741             Operand::new("p", iAddr),
3742         ])
3743         .can_store()
3744         .other_side_effects(),
3745     );
3746 
3747     ig.push(
3748         Inst::new(
3749             "fence",
3750             r#"
3751         A memory fence.  This must provide ordering to ensure that, at a minimum, neither loads
3752         nor stores of any kind may move forwards or backwards across the fence.  This operation
3753         is sequentially consistent.
3754         "#,
3755             &formats.nullary,
3756         )
3757         .other_side_effects(),
3758     );
3759 
3760     let TxN = &TypeVar::new(
3761         "TxN",
3762         "A dynamic vector type",
3763         TypeSetBuilder::new()
3764             .ints(Interval::All)
3765             .floats(Interval::All)
3766             .dynamic_simd_lanes(Interval::All)
3767             .build(),
3768     );
3769 
3770     ig.push(
3771         Inst::new(
3772             "extract_vector",
3773             r#"
3774         Return a fixed length sub vector, extracted from a dynamic vector.
3775         "#,
3776             &formats.binary_imm8,
3777         )
3778         .operands_in(vec![
3779             Operand::new("x", TxN).with_doc("The dynamic vector to extract from"),
3780             Operand::new("y", &imm.uimm8).with_doc("128-bit vector index"),
3781         ])
3782         .operands_out(vec![
3783             Operand::new("a", &TxN.dynamic_to_vector()).with_doc("New fixed vector")
3784         ]),
3785     );
3786 }
3787