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