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