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     ig.push(
1917         Inst::new(
1918             "udiv",
1919             r#"
1920         Unsigned integer division: `a := \lfloor {x \over y} \rfloor`.
1921 
1922         This operation traps if the divisor is zero.
1923         "#,
1924             &formats.binary,
1925         )
1926         .operands_in(vec![x, y])
1927         .operands_out(vec![a])
1928         .can_trap(true),
1929     );
1930 
1931     ig.push(
1932         Inst::new(
1933             "sdiv",
1934             r#"
1935         Signed integer division rounded toward zero: `a := sign(xy)
1936         \lfloor {|x| \over |y|}\rfloor`.
1937 
1938         This operation traps if the divisor is zero, or if the result is not
1939         representable in `B` bits two's complement. This only happens
1940         when `x = -2^{B-1}, y = -1`.
1941         "#,
1942             &formats.binary,
1943         )
1944         .operands_in(vec![x, y])
1945         .operands_out(vec![a])
1946         .can_trap(true),
1947     );
1948 
1949     ig.push(
1950         Inst::new(
1951             "urem",
1952             r#"
1953         Unsigned integer remainder.
1954 
1955         This operation traps if the divisor is zero.
1956         "#,
1957             &formats.binary,
1958         )
1959         .operands_in(vec![x, y])
1960         .operands_out(vec![a])
1961         .can_trap(true),
1962     );
1963 
1964     ig.push(
1965         Inst::new(
1966             "srem",
1967             r#"
1968         Signed integer remainder. The result has the sign of the dividend.
1969 
1970         This operation traps if the divisor is zero.
1971         "#,
1972             &formats.binary,
1973         )
1974         .operands_in(vec![x, y])
1975         .operands_out(vec![a])
1976         .can_trap(true),
1977     );
1978 
1979     let a = &Operand::new("a", iB);
1980     let x = &Operand::new("x", iB);
1981     let Y = &Operand::new("Y", &imm.imm64);
1982 
1983     ig.push(
1984         Inst::new(
1985             "iadd_imm",
1986             r#"
1987         Add immediate integer.
1988 
1989         Same as `iadd`, but one operand is an immediate constant.
1990 
1991         Polymorphic over all scalar integer types, but does not support vector
1992         types.
1993         "#,
1994             &formats.binary_imm64,
1995         )
1996         .operands_in(vec![x, Y])
1997         .operands_out(vec![a]),
1998     );
1999 
2000     ig.push(
2001         Inst::new(
2002             "imul_imm",
2003             r#"
2004         Integer multiplication by immediate constant.
2005 
2006         Polymorphic over all scalar integer types, but does not support vector
2007         types.
2008         "#,
2009             &formats.binary_imm64,
2010         )
2011         .operands_in(vec![x, Y])
2012         .operands_out(vec![a]),
2013     );
2014 
2015     ig.push(
2016         Inst::new(
2017             "udiv_imm",
2018             r#"
2019         Unsigned integer division by an immediate constant.
2020 
2021         This operation traps if the divisor is zero.
2022         "#,
2023             &formats.binary_imm64,
2024         )
2025         .operands_in(vec![x, Y])
2026         .operands_out(vec![a]),
2027     );
2028 
2029     ig.push(
2030         Inst::new(
2031             "sdiv_imm",
2032             r#"
2033         Signed integer division by an immediate constant.
2034 
2035         This operation traps if the divisor is zero, or if the result is not
2036         representable in `B` bits two's complement. This only happens
2037         when `x = -2^{B-1}, Y = -1`.
2038         "#,
2039             &formats.binary_imm64,
2040         )
2041         .operands_in(vec![x, Y])
2042         .operands_out(vec![a]),
2043     );
2044 
2045     ig.push(
2046         Inst::new(
2047             "urem_imm",
2048             r#"
2049         Unsigned integer remainder with immediate divisor.
2050 
2051         This operation traps if the divisor is zero.
2052         "#,
2053             &formats.binary_imm64,
2054         )
2055         .operands_in(vec![x, Y])
2056         .operands_out(vec![a]),
2057     );
2058 
2059     ig.push(
2060         Inst::new(
2061             "srem_imm",
2062             r#"
2063         Signed integer remainder with immediate divisor.
2064 
2065         This operation traps if the divisor is zero.
2066         "#,
2067             &formats.binary_imm64,
2068         )
2069         .operands_in(vec![x, Y])
2070         .operands_out(vec![a]),
2071     );
2072 
2073     ig.push(
2074         Inst::new(
2075             "irsub_imm",
2076             r#"
2077         Immediate reverse wrapping subtraction: `a := Y - x \pmod{2^B}`.
2078 
2079         Also works as integer negation when `Y = 0`. Use `iadd_imm`
2080         with a negative immediate operand for the reverse immediate
2081         subtraction.
2082 
2083         Polymorphic over all scalar integer types, but does not support vector
2084         types.
2085         "#,
2086             &formats.binary_imm64,
2087         )
2088         .operands_in(vec![x, Y])
2089         .operands_out(vec![a]),
2090     );
2091 
2092     let a = &Operand::new("a", iB);
2093     let x = &Operand::new("x", iB);
2094     let y = &Operand::new("y", iB);
2095 
2096     let c_in = &Operand::new("c_in", b1).with_doc("Input carry flag");
2097     let c_out = &Operand::new("c_out", b1).with_doc("Output carry flag");
2098     let b_in = &Operand::new("b_in", b1).with_doc("Input borrow flag");
2099     let b_out = &Operand::new("b_out", b1).with_doc("Output borrow flag");
2100 
2101     let c_if_in = &Operand::new("c_in", iflags);
2102     let c_if_out = &Operand::new("c_out", iflags);
2103     let b_if_in = &Operand::new("b_in", iflags);
2104     let b_if_out = &Operand::new("b_out", iflags);
2105 
2106     ig.push(
2107         Inst::new(
2108             "iadd_cin",
2109             r#"
2110         Add integers with carry in.
2111 
2112         Same as `iadd` with an additional carry input. Computes:
2113 
2114         ```text
2115             a = x + y + c_{in} \pmod 2^B
2116         ```
2117 
2118         Polymorphic over all scalar integer types, but does not support vector
2119         types.
2120         "#,
2121             &formats.ternary,
2122         )
2123         .operands_in(vec![x, y, c_in])
2124         .operands_out(vec![a]),
2125     );
2126 
2127     ig.push(
2128         Inst::new(
2129             "iadd_ifcin",
2130             r#"
2131         Add integers with carry in.
2132 
2133         Same as `iadd` with an additional carry flag input. Computes:
2134 
2135         ```text
2136             a = x + y + c_{in} \pmod 2^B
2137         ```
2138 
2139         Polymorphic over all scalar integer types, but does not support vector
2140         types.
2141         "#,
2142             &formats.ternary,
2143         )
2144         .operands_in(vec![x, y, c_if_in])
2145         .operands_out(vec![a]),
2146     );
2147 
2148     ig.push(
2149         Inst::new(
2150             "iadd_cout",
2151             r#"
2152         Add integers with carry out.
2153 
2154         Same as `iadd` with an additional carry output.
2155 
2156         ```text
2157             a &= x + y \pmod 2^B \\
2158             c_{out} &= x+y >= 2^B
2159         ```
2160 
2161         Polymorphic over all scalar integer types, but does not support vector
2162         types.
2163         "#,
2164             &formats.binary,
2165         )
2166         .operands_in(vec![x, y])
2167         .operands_out(vec![a, c_out]),
2168     );
2169 
2170     ig.push(
2171         Inst::new(
2172             "iadd_ifcout",
2173             r#"
2174         Add integers with carry out.
2175 
2176         Same as `iadd` with an additional carry flag output.
2177 
2178         ```text
2179             a &= x + y \pmod 2^B \\
2180             c_{out} &= x+y >= 2^B
2181         ```
2182 
2183         Polymorphic over all scalar integer types, but does not support vector
2184         types.
2185         "#,
2186             &formats.binary,
2187         )
2188         .operands_in(vec![x, y])
2189         .operands_out(vec![a, c_if_out]),
2190     );
2191 
2192     ig.push(
2193         Inst::new(
2194             "iadd_carry",
2195             r#"
2196         Add integers with carry in and out.
2197 
2198         Same as `iadd` with an additional carry input and output.
2199 
2200         ```text
2201             a &= x + y + c_{in} \pmod 2^B \\
2202             c_{out} &= x + y + c_{in} >= 2^B
2203         ```
2204 
2205         Polymorphic over all scalar integer types, but does not support vector
2206         types.
2207         "#,
2208             &formats.ternary,
2209         )
2210         .operands_in(vec![x, y, c_in])
2211         .operands_out(vec![a, c_out]),
2212     );
2213 
2214     ig.push(
2215         Inst::new(
2216             "iadd_ifcarry",
2217             r#"
2218         Add integers with carry in and out.
2219 
2220         Same as `iadd` with an additional carry flag input and output.
2221 
2222         ```text
2223             a &= x + y + c_{in} \pmod 2^B \\
2224             c_{out} &= x + y + c_{in} >= 2^B
2225         ```
2226 
2227         Polymorphic over all scalar integer types, but does not support vector
2228         types.
2229         "#,
2230             &formats.ternary,
2231         )
2232         .operands_in(vec![x, y, c_if_in])
2233         .operands_out(vec![a, c_if_out]),
2234     );
2235 
2236     ig.push(
2237         Inst::new(
2238             "isub_bin",
2239             r#"
2240         Subtract integers with borrow in.
2241 
2242         Same as `isub` with an additional borrow flag input. Computes:
2243 
2244         ```text
2245             a = x - (y + b_{in}) \pmod 2^B
2246         ```
2247 
2248         Polymorphic over all scalar integer types, but does not support vector
2249         types.
2250         "#,
2251             &formats.ternary,
2252         )
2253         .operands_in(vec![x, y, b_in])
2254         .operands_out(vec![a]),
2255     );
2256 
2257     ig.push(
2258         Inst::new(
2259             "isub_ifbin",
2260             r#"
2261         Subtract integers with borrow in.
2262 
2263         Same as `isub` with an additional borrow flag input. Computes:
2264 
2265         ```text
2266             a = x - (y + b_{in}) \pmod 2^B
2267         ```
2268 
2269         Polymorphic over all scalar integer types, but does not support vector
2270         types.
2271         "#,
2272             &formats.ternary,
2273         )
2274         .operands_in(vec![x, y, b_if_in])
2275         .operands_out(vec![a]),
2276     );
2277 
2278     ig.push(
2279         Inst::new(
2280             "isub_bout",
2281             r#"
2282         Subtract integers with borrow out.
2283 
2284         Same as `isub` with an additional borrow flag output.
2285 
2286         ```text
2287             a &= x - y \pmod 2^B \\
2288             b_{out} &= x < y
2289         ```
2290 
2291         Polymorphic over all scalar integer types, but does not support vector
2292         types.
2293         "#,
2294             &formats.binary,
2295         )
2296         .operands_in(vec![x, y])
2297         .operands_out(vec![a, b_out]),
2298     );
2299 
2300     ig.push(
2301         Inst::new(
2302             "isub_ifbout",
2303             r#"
2304         Subtract integers with borrow out.
2305 
2306         Same as `isub` with an additional borrow flag output.
2307 
2308         ```text
2309             a &= x - y \pmod 2^B \\
2310             b_{out} &= x < y
2311         ```
2312 
2313         Polymorphic over all scalar integer types, but does not support vector
2314         types.
2315         "#,
2316             &formats.binary,
2317         )
2318         .operands_in(vec![x, y])
2319         .operands_out(vec![a, b_if_out]),
2320     );
2321 
2322     ig.push(
2323         Inst::new(
2324             "isub_borrow",
2325             r#"
2326         Subtract integers with borrow in and out.
2327 
2328         Same as `isub` with an additional borrow flag input and output.
2329 
2330         ```text
2331             a &= x - (y + b_{in}) \pmod 2^B \\
2332             b_{out} &= x < y + b_{in}
2333         ```
2334 
2335         Polymorphic over all scalar integer types, but does not support vector
2336         types.
2337         "#,
2338             &formats.ternary,
2339         )
2340         .operands_in(vec![x, y, b_in])
2341         .operands_out(vec![a, b_out]),
2342     );
2343 
2344     ig.push(
2345         Inst::new(
2346             "isub_ifborrow",
2347             r#"
2348         Subtract integers with borrow in and out.
2349 
2350         Same as `isub` with an additional borrow flag input and output.
2351 
2352         ```text
2353             a &= x - (y + b_{in}) \pmod 2^B \\
2354             b_{out} &= x < y + b_{in}
2355         ```
2356 
2357         Polymorphic over all scalar integer types, but does not support vector
2358         types.
2359         "#,
2360             &formats.ternary,
2361         )
2362         .operands_in(vec![x, y, b_if_in])
2363         .operands_out(vec![a, b_if_out]),
2364     );
2365 
2366     let bits = &TypeVar::new(
2367         "bits",
2368         "Any integer, float, or boolean scalar or vector type",
2369         TypeSetBuilder::new()
2370             .ints(Interval::All)
2371             .floats(Interval::All)
2372             .bools(Interval::All)
2373             .simd_lanes(Interval::All)
2374             .includes_scalars(true)
2375             .build(),
2376     );
2377     let x = &Operand::new("x", bits);
2378     let y = &Operand::new("y", bits);
2379     let a = &Operand::new("a", bits);
2380 
2381     ig.push(
2382         Inst::new(
2383             "band",
2384             r#"
2385         Bitwise and.
2386         "#,
2387             &formats.binary,
2388         )
2389         .operands_in(vec![x, y])
2390         .operands_out(vec![a]),
2391     );
2392 
2393     ig.push(
2394         Inst::new(
2395             "bor",
2396             r#"
2397         Bitwise or.
2398         "#,
2399             &formats.binary,
2400         )
2401         .operands_in(vec![x, y])
2402         .operands_out(vec![a]),
2403     );
2404 
2405     ig.push(
2406         Inst::new(
2407             "bxor",
2408             r#"
2409         Bitwise xor.
2410         "#,
2411             &formats.binary,
2412         )
2413         .operands_in(vec![x, y])
2414         .operands_out(vec![a]),
2415     );
2416 
2417     ig.push(
2418         Inst::new(
2419             "bnot",
2420             r#"
2421         Bitwise not.
2422         "#,
2423             &formats.unary,
2424         )
2425         .operands_in(vec![x])
2426         .operands_out(vec![a]),
2427     );
2428 
2429     ig.push(
2430         Inst::new(
2431             "band_not",
2432             r#"
2433         Bitwise and not.
2434 
2435         Computes `x & ~y`.
2436         "#,
2437             &formats.binary,
2438         )
2439         .operands_in(vec![x, y])
2440         .operands_out(vec![a]),
2441     );
2442 
2443     ig.push(
2444         Inst::new(
2445             "bor_not",
2446             r#"
2447         Bitwise or not.
2448 
2449         Computes `x | ~y`.
2450         "#,
2451             &formats.binary,
2452         )
2453         .operands_in(vec![x, y])
2454         .operands_out(vec![a]),
2455     );
2456 
2457     ig.push(
2458         Inst::new(
2459             "bxor_not",
2460             r#"
2461         Bitwise xor not.
2462 
2463         Computes `x ^ ~y`.
2464         "#,
2465             &formats.binary,
2466         )
2467         .operands_in(vec![x, y])
2468         .operands_out(vec![a]),
2469     );
2470 
2471     let x = &Operand::new("x", iB);
2472     let Y = &Operand::new("Y", &imm.imm64);
2473     let a = &Operand::new("a", iB);
2474 
2475     ig.push(
2476         Inst::new(
2477             "band_imm",
2478             r#"
2479         Bitwise and with immediate.
2480 
2481         Same as `band`, but one operand is an immediate constant.
2482 
2483         Polymorphic over all scalar integer types, but does not support vector
2484         types.
2485         "#,
2486             &formats.binary_imm64,
2487         )
2488         .operands_in(vec![x, Y])
2489         .operands_out(vec![a]),
2490     );
2491 
2492     ig.push(
2493         Inst::new(
2494             "bor_imm",
2495             r#"
2496         Bitwise or with immediate.
2497 
2498         Same as `bor`, but one operand is an immediate constant.
2499 
2500         Polymorphic over all scalar integer types, but does not support vector
2501         types.
2502         "#,
2503             &formats.binary_imm64,
2504         )
2505         .operands_in(vec![x, Y])
2506         .operands_out(vec![a]),
2507     );
2508 
2509     ig.push(
2510         Inst::new(
2511             "bxor_imm",
2512             r#"
2513         Bitwise xor with immediate.
2514 
2515         Same as `bxor`, but one operand is an immediate constant.
2516 
2517         Polymorphic over all scalar integer types, but does not support vector
2518         types.
2519         "#,
2520             &formats.binary_imm64,
2521         )
2522         .operands_in(vec![x, Y])
2523         .operands_out(vec![a]),
2524     );
2525 
2526     let x = &Operand::new("x", Int).with_doc("Scalar or vector value to shift");
2527     let y = &Operand::new("y", iB).with_doc("Number of bits to shift");
2528     let Y = &Operand::new("Y", &imm.imm64);
2529     let a = &Operand::new("a", Int);
2530 
2531     ig.push(
2532         Inst::new(
2533             "rotl",
2534             r#"
2535         Rotate left.
2536 
2537         Rotate the bits in ``x`` by ``y`` places.
2538         "#,
2539             &formats.binary,
2540         )
2541         .operands_in(vec![x, y])
2542         .operands_out(vec![a]),
2543     );
2544 
2545     ig.push(
2546         Inst::new(
2547             "rotr",
2548             r#"
2549         Rotate right.
2550 
2551         Rotate the bits in ``x`` by ``y`` places.
2552         "#,
2553             &formats.binary,
2554         )
2555         .operands_in(vec![x, y])
2556         .operands_out(vec![a]),
2557     );
2558 
2559     ig.push(
2560         Inst::new(
2561             "rotl_imm",
2562             r#"
2563         Rotate left by immediate.
2564         "#,
2565             &formats.binary_imm64,
2566         )
2567         .operands_in(vec![x, Y])
2568         .operands_out(vec![a]),
2569     );
2570 
2571     ig.push(
2572         Inst::new(
2573             "rotr_imm",
2574             r#"
2575         Rotate right by immediate.
2576         "#,
2577             &formats.binary_imm64,
2578         )
2579         .operands_in(vec![x, Y])
2580         .operands_out(vec![a]),
2581     );
2582 
2583     ig.push(
2584         Inst::new(
2585             "ishl",
2586             r#"
2587         Integer shift left. Shift the bits in ``x`` towards the MSB by ``y``
2588         places. Shift in zero bits to the LSB.
2589 
2590         The shift amount is masked to the size of ``x``.
2591 
2592         When shifting a B-bits integer type, this instruction computes:
2593 
2594         ```text
2595             s &:= y \pmod B,
2596             a &:= x \cdot 2^s \pmod{2^B}.
2597         ```
2598         "#,
2599             &formats.binary,
2600         )
2601         .operands_in(vec![x, y])
2602         .operands_out(vec![a]),
2603     );
2604 
2605     ig.push(
2606         Inst::new(
2607             "ushr",
2608             r#"
2609         Unsigned shift right. Shift bits in ``x`` towards the LSB by ``y``
2610         places, shifting in zero bits to the MSB. Also called a *logical
2611         shift*.
2612 
2613         The shift amount is masked to the size of the register.
2614 
2615         When shifting a B-bits integer type, this instruction computes:
2616 
2617         ```text
2618             s &:= y \pmod B,
2619             a &:= \lfloor x \cdot 2^{-s} \rfloor.
2620         ```
2621         "#,
2622             &formats.binary,
2623         )
2624         .operands_in(vec![x, y])
2625         .operands_out(vec![a]),
2626     );
2627 
2628     ig.push(
2629         Inst::new(
2630             "sshr",
2631             r#"
2632         Signed shift right. Shift bits in ``x`` towards the LSB by ``y``
2633         places, shifting in sign bits to the MSB. Also called an *arithmetic
2634         shift*.
2635 
2636         The shift amount is masked to the size of the register.
2637         "#,
2638             &formats.binary,
2639         )
2640         .operands_in(vec![x, y])
2641         .operands_out(vec![a]),
2642     );
2643 
2644     ig.push(
2645         Inst::new(
2646             "ishl_imm",
2647             r#"
2648         Integer shift left by immediate.
2649 
2650         The shift amount is masked to the size of ``x``.
2651         "#,
2652             &formats.binary_imm64,
2653         )
2654         .operands_in(vec![x, Y])
2655         .operands_out(vec![a]),
2656     );
2657 
2658     ig.push(
2659         Inst::new(
2660             "ushr_imm",
2661             r#"
2662         Unsigned shift right by immediate.
2663 
2664         The shift amount is masked to the size of the register.
2665         "#,
2666             &formats.binary_imm64,
2667         )
2668         .operands_in(vec![x, Y])
2669         .operands_out(vec![a]),
2670     );
2671 
2672     ig.push(
2673         Inst::new(
2674             "sshr_imm",
2675             r#"
2676         Signed shift right by immediate.
2677 
2678         The shift amount is masked to the size of the register.
2679         "#,
2680             &formats.binary_imm64,
2681         )
2682         .operands_in(vec![x, Y])
2683         .operands_out(vec![a]),
2684     );
2685 
2686     let x = &Operand::new("x", iB);
2687     let a = &Operand::new("a", iB);
2688 
2689     ig.push(
2690         Inst::new(
2691             "bitrev",
2692             r#"
2693         Reverse the bits of a integer.
2694 
2695         Reverses the bits in ``x``.
2696         "#,
2697             &formats.unary,
2698         )
2699         .operands_in(vec![x])
2700         .operands_out(vec![a]),
2701     );
2702 
2703     ig.push(
2704         Inst::new(
2705             "clz",
2706             r#"
2707         Count leading zero bits.
2708 
2709         Starting from the MSB in ``x``, count the number of zero bits before
2710         reaching the first one bit. When ``x`` is zero, returns the size of x
2711         in bits.
2712         "#,
2713             &formats.unary,
2714         )
2715         .operands_in(vec![x])
2716         .operands_out(vec![a]),
2717     );
2718 
2719     ig.push(
2720         Inst::new(
2721             "cls",
2722             r#"
2723         Count leading sign bits.
2724 
2725         Starting from the MSB after the sign bit in ``x``, count the number of
2726         consecutive bits identical to the sign bit. When ``x`` is 0 or -1,
2727         returns one less than the size of x in bits.
2728         "#,
2729             &formats.unary,
2730         )
2731         .operands_in(vec![x])
2732         .operands_out(vec![a]),
2733     );
2734 
2735     ig.push(
2736         Inst::new(
2737             "ctz",
2738             r#"
2739         Count trailing zeros.
2740 
2741         Starting from the LSB in ``x``, count the number of zero bits before
2742         reaching the first one bit. When ``x`` is zero, returns the size of x
2743         in bits.
2744         "#,
2745             &formats.unary,
2746         )
2747         .operands_in(vec![x])
2748         .operands_out(vec![a]),
2749     );
2750 
2751     let x = &Operand::new("x", Int);
2752     let a = &Operand::new("a", Int);
2753 
2754     ig.push(
2755         Inst::new(
2756             "popcnt",
2757             r#"
2758         Population count
2759 
2760         Count the number of one bits in ``x``.
2761         "#,
2762             &formats.unary,
2763         )
2764         .operands_in(vec![x])
2765         .operands_out(vec![a]),
2766     );
2767 
2768     let Float = &TypeVar::new(
2769         "Float",
2770         "A scalar or vector floating point number",
2771         TypeSetBuilder::new()
2772             .floats(Interval::All)
2773             .simd_lanes(Interval::All)
2774             .build(),
2775     );
2776     let Cond = &Operand::new("Cond", &imm.floatcc);
2777     let x = &Operand::new("x", Float);
2778     let y = &Operand::new("y", Float);
2779     let a = &Operand::new("a", &Float.as_bool());
2780 
2781     ig.push(
2782         Inst::new(
2783             "fcmp",
2784             r#"
2785         Floating point comparison.
2786 
2787         Two IEEE 754-2008 floating point numbers, `x` and `y`, relate to each
2788         other in exactly one of four ways:
2789 
2790         ```text
2791         == ==========================================
2792         UN Unordered when one or both numbers is NaN.
2793         EQ When `x = y`. (And `0.0 = -0.0`).
2794         LT When `x < y`.
2795         GT When `x > y`.
2796         == ==========================================
2797         ```
2798 
2799         The 14 `floatcc` condition codes each correspond to a subset of
2800         the four relations, except for the empty set which would always be
2801         false, and the full set which would always be true.
2802 
2803         The condition codes are divided into 7 'ordered' conditions which don't
2804         include UN, and 7 unordered conditions which all include UN.
2805 
2806         ```text
2807         +-------+------------+---------+------------+-------------------------+
2808         |Ordered             |Unordered             |Condition                |
2809         +=======+============+=========+============+=========================+
2810         |ord    |EQ | LT | GT|uno      |UN          |NaNs absent / present.   |
2811         +-------+------------+---------+------------+-------------------------+
2812         |eq     |EQ          |ueq      |UN | EQ     |Equal                    |
2813         +-------+------------+---------+------------+-------------------------+
2814         |one    |LT | GT     |ne       |UN | LT | GT|Not equal                |
2815         +-------+------------+---------+------------+-------------------------+
2816         |lt     |LT          |ult      |UN | LT     |Less than                |
2817         +-------+------------+---------+------------+-------------------------+
2818         |le     |LT | EQ     |ule      |UN | LT | EQ|Less than or equal       |
2819         +-------+------------+---------+------------+-------------------------+
2820         |gt     |GT          |ugt      |UN | GT     |Greater than             |
2821         +-------+------------+---------+------------+-------------------------+
2822         |ge     |GT | EQ     |uge      |UN | GT | EQ|Greater than or equal    |
2823         +-------+------------+---------+------------+-------------------------+
2824         ```
2825 
2826         The standard C comparison operators, `<, <=, >, >=`, are all ordered,
2827         so they are false if either operand is NaN. The C equality operator,
2828         `==`, is ordered, and since inequality is defined as the logical
2829         inverse it is *unordered*. They map to the `floatcc` condition
2830         codes as follows:
2831 
2832         ```text
2833         ==== ====== ============
2834         C    `Cond` Subset
2835         ==== ====== ============
2836         `==` eq     EQ
2837         `!=` ne     UN | LT | GT
2838         `<`  lt     LT
2839         `<=` le     LT | EQ
2840         `>`  gt     GT
2841         `>=` ge     GT | EQ
2842         ==== ====== ============
2843         ```
2844 
2845         This subset of condition codes also corresponds to the WebAssembly
2846         floating point comparisons of the same name.
2847 
2848         When this instruction compares floating point vectors, it returns a
2849         boolean vector with the results of lane-wise comparisons.
2850         "#,
2851             &formats.float_compare,
2852         )
2853         .operands_in(vec![Cond, x, y])
2854         .operands_out(vec![a]),
2855     );
2856 
2857     let f = &Operand::new("f", fflags);
2858 
2859     ig.push(
2860         Inst::new(
2861             "ffcmp",
2862             r#"
2863         Floating point comparison returning flags.
2864 
2865         Compares two numbers like `fcmp`, but returns floating point CPU
2866         flags instead of testing a specific condition.
2867         "#,
2868             &formats.binary,
2869         )
2870         .operands_in(vec![x, y])
2871         .operands_out(vec![f]),
2872     );
2873 
2874     let x = &Operand::new("x", Float);
2875     let y = &Operand::new("y", Float);
2876     let z = &Operand::new("z", Float);
2877     let a = &Operand::new("a", Float).with_doc("Result of applying operator to each lane");
2878 
2879     ig.push(
2880         Inst::new(
2881             "fadd",
2882             r#"
2883         Floating point addition.
2884         "#,
2885             &formats.binary,
2886         )
2887         .operands_in(vec![x, y])
2888         .operands_out(vec![a]),
2889     );
2890 
2891     ig.push(
2892         Inst::new(
2893             "fsub",
2894             r#"
2895         Floating point subtraction.
2896         "#,
2897             &formats.binary,
2898         )
2899         .operands_in(vec![x, y])
2900         .operands_out(vec![a]),
2901     );
2902 
2903     ig.push(
2904         Inst::new(
2905             "fmul",
2906             r#"
2907         Floating point multiplication.
2908         "#,
2909             &formats.binary,
2910         )
2911         .operands_in(vec![x, y])
2912         .operands_out(vec![a]),
2913     );
2914 
2915     ig.push(
2916         Inst::new(
2917             "fdiv",
2918             r#"
2919         Floating point division.
2920 
2921         Unlike the integer division instructions ` and
2922         `udiv`, this can't trap. Division by zero is infinity or
2923         NaN, depending on the dividend.
2924         "#,
2925             &formats.binary,
2926         )
2927         .operands_in(vec![x, y])
2928         .operands_out(vec![a]),
2929     );
2930 
2931     ig.push(
2932         Inst::new(
2933             "sqrt",
2934             r#"
2935         Floating point square root.
2936         "#,
2937             &formats.unary,
2938         )
2939         .operands_in(vec![x])
2940         .operands_out(vec![a]),
2941     );
2942 
2943     ig.push(
2944         Inst::new(
2945             "fma",
2946             r#"
2947         Floating point fused multiply-and-add.
2948 
2949         Computes `a := xy+z` without any intermediate rounding of the
2950         product.
2951         "#,
2952             &formats.ternary,
2953         )
2954         .operands_in(vec![x, y, z])
2955         .operands_out(vec![a]),
2956     );
2957 
2958     let a = &Operand::new("a", Float).with_doc("``x`` with its sign bit inverted");
2959 
2960     ig.push(
2961         Inst::new(
2962             "fneg",
2963             r#"
2964         Floating point negation.
2965 
2966         Note that this is a pure bitwise operation.
2967         "#,
2968             &formats.unary,
2969         )
2970         .operands_in(vec![x])
2971         .operands_out(vec![a]),
2972     );
2973 
2974     let a = &Operand::new("a", Float).with_doc("``x`` with its sign bit cleared");
2975 
2976     ig.push(
2977         Inst::new(
2978             "fabs",
2979             r#"
2980         Floating point absolute value.
2981 
2982         Note that this is a pure bitwise operation.
2983         "#,
2984             &formats.unary,
2985         )
2986         .operands_in(vec![x])
2987         .operands_out(vec![a]),
2988     );
2989 
2990     let a = &Operand::new("a", Float).with_doc("``x`` with its sign bit changed to that of ``y``");
2991 
2992     ig.push(
2993         Inst::new(
2994             "fcopysign",
2995             r#"
2996         Floating point copy sign.
2997 
2998         Note that this is a pure bitwise operation. The sign bit from ``y`` is
2999         copied to the sign bit of ``x``.
3000         "#,
3001             &formats.binary,
3002         )
3003         .operands_in(vec![x, y])
3004         .operands_out(vec![a]),
3005     );
3006 
3007     let a = &Operand::new("a", Float).with_doc("The smaller of ``x`` and ``y``");
3008 
3009     ig.push(
3010         Inst::new(
3011             "fmin",
3012             r#"
3013         Floating point minimum, propagating NaNs using the WebAssembly rules.
3014 
3015         If either operand is NaN, this returns NaN with an unspecified sign. Furthermore, if
3016         each input NaN consists of a mantissa whose most significant bit is 1 and the rest is
3017         0, then the output has the same form. Otherwise, the output mantissa's most significant
3018         bit is 1 and the rest is unspecified.
3019         "#,
3020             &formats.binary,
3021         )
3022         .operands_in(vec![x, y])
3023         .operands_out(vec![a]),
3024     );
3025 
3026     ig.push(
3027         Inst::new(
3028             "fmin_pseudo",
3029             r#"
3030         Floating point pseudo-minimum, propagating NaNs.  This behaves differently from ``fmin``.
3031         See <https://github.com/WebAssembly/simd/pull/122> for background.
3032 
3033         The behaviour is defined as ``fmin_pseudo(a, b) = (b < a) ? b : a``, and the behaviour
3034         for zero or NaN inputs follows from the behaviour of ``<`` with such inputs.
3035         "#,
3036             &formats.binary,
3037         )
3038         .operands_in(vec![x, y])
3039         .operands_out(vec![a]),
3040     );
3041 
3042     let a = &Operand::new("a", Float).with_doc("The larger of ``x`` and ``y``");
3043 
3044     ig.push(
3045         Inst::new(
3046             "fmax",
3047             r#"
3048         Floating point maximum, propagating NaNs using the WebAssembly rules.
3049 
3050         If either operand is NaN, this returns NaN with an unspecified sign. Furthermore, if
3051         each input NaN consists of a mantissa whose most significant bit is 1 and the rest is
3052         0, then the output has the same form. Otherwise, the output mantissa's most significant
3053         bit is 1 and the rest is unspecified.
3054         "#,
3055             &formats.binary,
3056         )
3057         .operands_in(vec![x, y])
3058         .operands_out(vec![a]),
3059     );
3060 
3061     ig.push(
3062         Inst::new(
3063             "fmax_pseudo",
3064             r#"
3065         Floating point pseudo-maximum, propagating NaNs.  This behaves differently from ``fmax``.
3066         See <https://github.com/WebAssembly/simd/pull/122> for background.
3067 
3068         The behaviour is defined as ``fmax_pseudo(a, b) = (a < b) ? b : a``, and the behaviour
3069         for zero or NaN inputs follows from the behaviour of ``<`` with such inputs.
3070         "#,
3071             &formats.binary,
3072         )
3073         .operands_in(vec![x, y])
3074         .operands_out(vec![a]),
3075     );
3076 
3077     let a = &Operand::new("a", Float).with_doc("``x`` rounded to integral value");
3078 
3079     ig.push(
3080         Inst::new(
3081             "ceil",
3082             r#"
3083         Round floating point round to integral, towards positive infinity.
3084         "#,
3085             &formats.unary,
3086         )
3087         .operands_in(vec![x])
3088         .operands_out(vec![a]),
3089     );
3090 
3091     ig.push(
3092         Inst::new(
3093             "floor",
3094             r#"
3095         Round floating point round to integral, towards negative infinity.
3096         "#,
3097             &formats.unary,
3098         )
3099         .operands_in(vec![x])
3100         .operands_out(vec![a]),
3101     );
3102 
3103     ig.push(
3104         Inst::new(
3105             "trunc",
3106             r#"
3107         Round floating point round to integral, towards zero.
3108         "#,
3109             &formats.unary,
3110         )
3111         .operands_in(vec![x])
3112         .operands_out(vec![a]),
3113     );
3114 
3115     ig.push(
3116         Inst::new(
3117             "nearest",
3118             r#"
3119         Round floating point round to integral, towards nearest with ties to
3120         even.
3121         "#,
3122             &formats.unary,
3123         )
3124         .operands_in(vec![x])
3125         .operands_out(vec![a]),
3126     );
3127 
3128     let a = &Operand::new("a", b1);
3129     let x = &Operand::new("x", Ref);
3130 
3131     ig.push(
3132         Inst::new(
3133             "is_null",
3134             r#"
3135         Reference verification.
3136 
3137         The condition code determines if the reference type in question is
3138         null or not.
3139         "#,
3140             &formats.unary,
3141         )
3142         .operands_in(vec![x])
3143         .operands_out(vec![a]),
3144     );
3145 
3146     let a = &Operand::new("a", b1);
3147     let x = &Operand::new("x", Ref);
3148 
3149     ig.push(
3150         Inst::new(
3151             "is_invalid",
3152             r#"
3153         Reference verification.
3154 
3155         The condition code determines if the reference type in question is
3156         invalid or not.
3157         "#,
3158             &formats.unary,
3159         )
3160         .operands_in(vec![x])
3161         .operands_out(vec![a]),
3162     );
3163 
3164     let Cond = &Operand::new("Cond", &imm.intcc);
3165     let f = &Operand::new("f", iflags);
3166     let a = &Operand::new("a", b1);
3167 
3168     ig.push(
3169         Inst::new(
3170             "trueif",
3171             r#"
3172         Test integer CPU flags for a specific condition.
3173 
3174         Check the CPU flags in ``f`` against the ``Cond`` condition code and
3175         return true when the condition code is satisfied.
3176         "#,
3177             &formats.int_cond,
3178         )
3179         .operands_in(vec![Cond, f])
3180         .operands_out(vec![a]),
3181     );
3182 
3183     let Cond = &Operand::new("Cond", &imm.floatcc);
3184     let f = &Operand::new("f", fflags);
3185 
3186     ig.push(
3187         Inst::new(
3188             "trueff",
3189             r#"
3190         Test floating point CPU flags for a specific condition.
3191 
3192         Check the CPU flags in ``f`` against the ``Cond`` condition code and
3193         return true when the condition code is satisfied.
3194         "#,
3195             &formats.float_cond,
3196         )
3197         .operands_in(vec![Cond, f])
3198         .operands_out(vec![a]),
3199     );
3200 
3201     let x = &Operand::new("x", Mem);
3202     let a = &Operand::new("a", MemTo).with_doc("Bits of `x` reinterpreted");
3203 
3204     ig.push(
3205         Inst::new(
3206             "bitcast",
3207             r#"
3208         Reinterpret the bits in `x` as a different type.
3209 
3210         The input and output types must be storable to memory and of the same
3211         size. A bitcast is equivalent to storing one type and loading the other
3212         type from the same address.
3213         "#,
3214             &formats.unary,
3215         )
3216         .operands_in(vec![x])
3217         .operands_out(vec![a]),
3218     );
3219 
3220     let x = &Operand::new("x", Any);
3221     let a = &Operand::new("a", AnyTo).with_doc("Bits of `x` reinterpreted");
3222 
3223     ig.push(
3224         Inst::new(
3225             "raw_bitcast",
3226             r#"
3227         Cast the bits in `x` as a different type of the same bit width.
3228 
3229         This instruction does not change the data's representation but allows
3230         data in registers to be used as different types, e.g. an i32x4 as a
3231         b8x16. The only constraint on the result `a` is that it can be
3232         `raw_bitcast` back to the original type. Also, in a raw_bitcast between
3233         vector types with the same number of lanes, the value of each result
3234         lane is a raw_bitcast of the corresponding operand lane. TODO there is
3235         currently no mechanism for enforcing the bit width constraint.
3236         "#,
3237             &formats.unary,
3238         )
3239         .operands_in(vec![x])
3240         .operands_out(vec![a]),
3241     );
3242 
3243     let a = &Operand::new("a", TxN).with_doc("A vector value");
3244     let s = &Operand::new("s", &TxN.lane_of()).with_doc("A scalar value");
3245 
3246     ig.push(
3247         Inst::new(
3248             "scalar_to_vector",
3249             r#"
3250             Copies a scalar value to a vector value.  The scalar is copied into the
3251             least significant lane of the vector, and all other lanes will be zero.
3252             "#,
3253             &formats.unary,
3254         )
3255         .operands_in(vec![s])
3256         .operands_out(vec![a]),
3257     );
3258 
3259     let Bool = &TypeVar::new(
3260         "Bool",
3261         "A scalar or vector boolean type",
3262         TypeSetBuilder::new()
3263             .bools(Interval::All)
3264             .simd_lanes(Interval::All)
3265             .build(),
3266     );
3267 
3268     let BoolTo = &TypeVar::new(
3269         "BoolTo",
3270         "A smaller boolean type with the same number of lanes",
3271         TypeSetBuilder::new()
3272             .bools(Interval::All)
3273             .simd_lanes(Interval::All)
3274             .build(),
3275     );
3276 
3277     let x = &Operand::new("x", Bool);
3278     let a = &Operand::new("a", BoolTo);
3279 
3280     ig.push(
3281         Inst::new(
3282             "breduce",
3283             r#"
3284         Convert `x` to a smaller boolean type in the platform-defined way.
3285 
3286         The result type must have the same number of vector lanes as the input,
3287         and each lane must not have more bits that the input lanes. If the
3288         input and output types are the same, this is a no-op.
3289         "#,
3290             &formats.unary,
3291         )
3292         .operands_in(vec![x])
3293         .operands_out(vec![a]),
3294     );
3295 
3296     let BoolTo = &TypeVar::new(
3297         "BoolTo",
3298         "A larger boolean type with the same number of lanes",
3299         TypeSetBuilder::new()
3300             .bools(Interval::All)
3301             .simd_lanes(Interval::All)
3302             .build(),
3303     );
3304     let x = &Operand::new("x", Bool);
3305     let a = &Operand::new("a", BoolTo);
3306 
3307     ig.push(
3308         Inst::new(
3309             "bextend",
3310             r#"
3311         Convert `x` to a larger boolean type in the platform-defined way.
3312 
3313         The result type must have the same number of vector lanes as the input,
3314         and each lane must not have fewer bits that the input lanes. If the
3315         input and output types are the same, this is a no-op.
3316         "#,
3317             &formats.unary,
3318         )
3319         .operands_in(vec![x])
3320         .operands_out(vec![a]),
3321     );
3322 
3323     let IntTo = &TypeVar::new(
3324         "IntTo",
3325         "An integer type with the same number of lanes",
3326         TypeSetBuilder::new()
3327             .ints(Interval::All)
3328             .simd_lanes(Interval::All)
3329             .build(),
3330     );
3331     let x = &Operand::new("x", Bool);
3332     let a = &Operand::new("a", IntTo);
3333 
3334     ig.push(
3335         Inst::new(
3336             "bint",
3337             r#"
3338         Convert `x` to an integer.
3339 
3340         True maps to 1 and false maps to 0. The result type must have the same
3341         number of vector lanes as the input.
3342         "#,
3343             &formats.unary,
3344         )
3345         .operands_in(vec![x])
3346         .operands_out(vec![a]),
3347     );
3348 
3349     ig.push(
3350         Inst::new(
3351             "bmask",
3352             r#"
3353         Convert `x` to an integer mask.
3354 
3355         True maps to all 1s and false maps to all 0s. The result type must have
3356         the same number of vector lanes as the input.
3357         "#,
3358             &formats.unary,
3359         )
3360         .operands_in(vec![x])
3361         .operands_out(vec![a]),
3362     );
3363 
3364     let Int = &TypeVar::new(
3365         "Int",
3366         "A scalar or vector integer type",
3367         TypeSetBuilder::new()
3368             .ints(Interval::All)
3369             .simd_lanes(Interval::All)
3370             .build(),
3371     );
3372 
3373     let IntTo = &TypeVar::new(
3374         "IntTo",
3375         "A smaller integer type with the same number of lanes",
3376         TypeSetBuilder::new()
3377             .ints(Interval::All)
3378             .simd_lanes(Interval::All)
3379             .build(),
3380     );
3381     let x = &Operand::new("x", Int);
3382     let a = &Operand::new("a", IntTo);
3383 
3384     ig.push(
3385         Inst::new(
3386             "ireduce",
3387             r#"
3388         Convert `x` to a smaller integer type by dropping high bits.
3389 
3390         Each lane in `x` is converted to a smaller integer type by discarding
3391         the most significant bits. This is the same as reducing modulo
3392         `2^n`.
3393 
3394         The result type must have the same number of vector lanes as the input,
3395         and each lane must not have more bits that the input lanes. If the
3396         input and output types are the same, this is a no-op.
3397         "#,
3398             &formats.unary,
3399         )
3400         .operands_in(vec![x])
3401         .operands_out(vec![a]),
3402     );
3403 
3404     let I16or32or64xN = &TypeVar::new(
3405         "I16or32or64xN",
3406         "A SIMD vector type containing integer lanes 16, 32, or 64 bits wide",
3407         TypeSetBuilder::new()
3408             .ints(16..64)
3409             .simd_lanes(2..8)
3410             .includes_scalars(false)
3411             .build(),
3412     );
3413 
3414     let x = &Operand::new("x", I16or32or64xN);
3415     let y = &Operand::new("y", I16or32or64xN);
3416     let a = &Operand::new("a", &I16or32or64xN.split_lanes());
3417 
3418     ig.push(
3419         Inst::new(
3420             "snarrow",
3421             r#"
3422         Combine `x` and `y` into a vector with twice the lanes but half the integer width while
3423         saturating overflowing values to the signed maximum and minimum.
3424 
3425         The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4`
3426         and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value
3427         returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`.
3428             "#,
3429             &formats.binary,
3430         )
3431         .operands_in(vec![x, y])
3432         .operands_out(vec![a]),
3433     );
3434 
3435     ig.push(
3436         Inst::new(
3437             "unarrow",
3438             r#"
3439         Combine `x` and `y` into a vector with twice the lanes but half the integer width while
3440         saturating overflowing values to the unsigned maximum and minimum.
3441 
3442         Note that all input lanes are considered signed: any negative lanes will overflow and be
3443         replaced with the unsigned minimum, `0x00`.
3444 
3445         The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4`
3446         and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value
3447         returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`.
3448             "#,
3449             &formats.binary,
3450         )
3451         .operands_in(vec![x, y])
3452         .operands_out(vec![a]),
3453     );
3454 
3455     ig.push(
3456         Inst::new(
3457             "uunarrow",
3458             r#"
3459         Combine `x` and `y` into a vector with twice the lanes but half the integer width while
3460         saturating overflowing values to the unsigned maximum and minimum.
3461 
3462         Note that all input lanes are considered unsigned: any negative values will be interpreted as unsigned, overflowing and being replaced with the unsigned maximum.
3463 
3464         The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4`
3465         and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value
3466         returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`.
3467             "#,
3468             &formats.binary,
3469         )
3470         .operands_in(vec![x, y])
3471         .operands_out(vec![a]),
3472     );
3473 
3474     let I8or16or32xN = &TypeVar::new(
3475         "I8or16or32xN",
3476         "A SIMD vector type containing integer lanes 8, 16, or 32 bits wide.",
3477         TypeSetBuilder::new()
3478             .ints(8..32)
3479             .simd_lanes(4..16)
3480             .includes_scalars(false)
3481             .build(),
3482     );
3483 
3484     let x = &Operand::new("x", I8or16or32xN);
3485     let a = &Operand::new("a", &I8or16or32xN.merge_lanes());
3486 
3487     ig.push(
3488         Inst::new(
3489             "swiden_low",
3490             r#"
3491         Widen the low lanes of `x` using signed extension.
3492 
3493         This will double the lane width and halve the number of lanes.
3494             "#,
3495             &formats.unary,
3496         )
3497         .operands_in(vec![x])
3498         .operands_out(vec![a]),
3499     );
3500 
3501     ig.push(
3502         Inst::new(
3503             "swiden_high",
3504             r#"
3505         Widen the high lanes of `x` using signed extension.
3506 
3507         This will double the lane width and halve the number of lanes.
3508             "#,
3509             &formats.unary,
3510         )
3511         .operands_in(vec![x])
3512         .operands_out(vec![a]),
3513     );
3514 
3515     ig.push(
3516         Inst::new(
3517             "uwiden_low",
3518             r#"
3519         Widen the low lanes of `x` using unsigned extension.
3520 
3521         This will double the lane width and halve the number of lanes.
3522             "#,
3523             &formats.unary,
3524         )
3525         .operands_in(vec![x])
3526         .operands_out(vec![a]),
3527     );
3528 
3529     ig.push(
3530         Inst::new(
3531             "uwiden_high",
3532             r#"
3533             Widen the high lanes of `x` using unsigned extension.
3534 
3535             This will double the lane width and halve the number of lanes.
3536             "#,
3537             &formats.unary,
3538         )
3539         .operands_in(vec![x])
3540         .operands_out(vec![a]),
3541     );
3542 
3543     let x = &Operand::new("x", I8or16or32xN);
3544     let y = &Operand::new("y", I8or16or32xN);
3545     let a = &Operand::new("a", I8or16or32xN);
3546 
3547     ig.push(
3548         Inst::new(
3549             "iadd_pairwise",
3550             r#"
3551         Does lane-wise integer pairwise addition on two operands, putting the
3552         combined results into a single vector result. Here a pair refers to adjacent
3553         lanes in a vector, i.e. i*2 + (i*2+1) for i == num_lanes/2. The first operand
3554         pairwise add results will make up the low half of the resulting vector while
3555         the second operand pairwise add results will make up the upper half of the
3556         resulting vector.
3557             "#,
3558             &formats.binary,
3559         )
3560         .operands_in(vec![x, y])
3561         .operands_out(vec![a]),
3562     );
3563 
3564     let I16x8 = &TypeVar::new(
3565         "I16x8",
3566         "A SIMD vector type containing 8 integer lanes each 16 bits wide.",
3567         TypeSetBuilder::new()
3568             .ints(16..16)
3569             .simd_lanes(8..8)
3570             .includes_scalars(false)
3571             .build(),
3572     );
3573 
3574     let x = &Operand::new("x", I16x8);
3575     let y = &Operand::new("y", I16x8);
3576     let a = &Operand::new("a", &I16x8.merge_lanes());
3577 
3578     ig.push(
3579         Inst::new(
3580             "widening_pairwise_dot_product_s",
3581             r#"
3582         Takes corresponding elements in `x` and `y`, performs a sign-extending length-doubling
3583         multiplication on them, then adds adjacent pairs of elements to form the result.  For
3584         example, if the input vectors are `[x3, x2, x1, x0]` and `[y3, y2, y1, y0]`, it produces
3585         the vector `[r1, r0]`, where `r1 = sx(x3) * sx(y3) + sx(x2) * sx(y2)` and
3586         `r0 = sx(x1) * sx(y1) + sx(x0) * sx(y0)`, and `sx(n)` sign-extends `n` to twice its width.
3587 
3588         This will double the lane width and halve the number of lanes.  So the resulting
3589         vector has the same number of bits as `x` and `y` do (individually).
3590 
3591         See <https://github.com/WebAssembly/simd/pull/127> for background info.
3592             "#,
3593             &formats.binary,
3594         )
3595         .operands_in(vec![x, y])
3596         .operands_out(vec![a]),
3597     );
3598 
3599     let IntTo = &TypeVar::new(
3600         "IntTo",
3601         "A larger integer type with the same number of lanes",
3602         TypeSetBuilder::new()
3603             .ints(Interval::All)
3604             .simd_lanes(Interval::All)
3605             .build(),
3606     );
3607     let x = &Operand::new("x", Int);
3608     let a = &Operand::new("a", IntTo);
3609 
3610     ig.push(
3611         Inst::new(
3612             "uextend",
3613             r#"
3614         Convert `x` to a larger integer type by zero-extending.
3615 
3616         Each lane in `x` is converted to a larger integer type by adding
3617         zeroes. The result has the same numerical value as `x` when both are
3618         interpreted as unsigned integers.
3619 
3620         The result type must have the same number of vector lanes as the input,
3621         and each lane must not have fewer bits that the input lanes. If the
3622         input and output types are the same, this is a no-op.
3623         "#,
3624             &formats.unary,
3625         )
3626         .operands_in(vec![x])
3627         .operands_out(vec![a]),
3628     );
3629 
3630     ig.push(
3631         Inst::new(
3632             "sextend",
3633             r#"
3634         Convert `x` to a larger integer type by sign-extending.
3635 
3636         Each lane in `x` is converted to a larger integer type by replicating
3637         the sign bit. The result has the same numerical value as `x` when both
3638         are interpreted as signed integers.
3639 
3640         The result type must have the same number of vector lanes as the input,
3641         and each lane must not have fewer bits that the input lanes. If the
3642         input and output types are the same, this is a no-op.
3643         "#,
3644             &formats.unary,
3645         )
3646         .operands_in(vec![x])
3647         .operands_out(vec![a]),
3648     );
3649 
3650     let FloatTo = &TypeVar::new(
3651         "FloatTo",
3652         "A scalar or vector floating point number",
3653         TypeSetBuilder::new()
3654             .floats(Interval::All)
3655             .simd_lanes(Interval::All)
3656             .build(),
3657     );
3658     let x = &Operand::new("x", Float);
3659     let a = &Operand::new("a", FloatTo);
3660 
3661     ig.push(
3662         Inst::new(
3663             "fpromote",
3664             r#"
3665         Convert `x` to a larger floating point format.
3666 
3667         Each lane in `x` is converted to the destination floating point format.
3668         This is an exact operation.
3669 
3670         Cranelift currently only supports two floating point formats
3671         - `f32` and `f64`. This may change in the future.
3672 
3673         The result type must have the same number of vector lanes as the input,
3674         and the result lanes must not have fewer bits than the input lanes. If
3675         the input and output types are the same, this is a no-op.
3676         "#,
3677             &formats.unary,
3678         )
3679         .operands_in(vec![x])
3680         .operands_out(vec![a]),
3681     );
3682 
3683     ig.push(
3684         Inst::new(
3685             "fdemote",
3686             r#"
3687         Convert `x` to a smaller floating point format.
3688 
3689         Each lane in `x` is converted to the destination floating point format
3690         by rounding to nearest, ties to even.
3691 
3692         Cranelift currently only supports two floating point formats
3693         - `f32` and `f64`. This may change in the future.
3694 
3695         The result type must have the same number of vector lanes as the input,
3696         and the result lanes must not have more bits than the input lanes. If
3697         the input and output types are the same, this is a no-op.
3698         "#,
3699             &formats.unary,
3700         )
3701         .operands_in(vec![x])
3702         .operands_out(vec![a]),
3703     );
3704 
3705     let F64x2 = &TypeVar::new(
3706         "F64x2",
3707         "A SIMD vector type consisting of 2 lanes of 64-bit floats",
3708         TypeSetBuilder::new()
3709             .floats(64..64)
3710             .simd_lanes(2..2)
3711             .includes_scalars(false)
3712             .build(),
3713     );
3714     let F32x4 = &TypeVar::new(
3715         "F32x4",
3716         "A SIMD vector type consisting of 4 lanes of 32-bit floats",
3717         TypeSetBuilder::new()
3718             .floats(32..32)
3719             .simd_lanes(4..4)
3720             .includes_scalars(false)
3721             .build(),
3722     );
3723 
3724     let x = &Operand::new("x", F64x2);
3725     let a = &Operand::new("a", F32x4);
3726 
3727     ig.push(
3728         Inst::new(
3729             "fvdemote",
3730             r#"
3731                 Convert `x` to a smaller floating point format.
3732 
3733                 Each lane in `x` is converted to the destination floating point format
3734                 by rounding to nearest, ties to even.
3735 
3736                 Cranelift currently only supports two floating point formats
3737                 - `f32` and `f64`. This may change in the future.
3738 
3739                 Fvdemote differs from fdemote in that with fvdemote it targets vectors.
3740                 Fvdemote is constrained to having the input type being F64x2 and the result
3741                 type being F32x4. The result lane that was the upper half of the input lane
3742                 is initialized to zero.
3743                 "#,
3744             &formats.unary,
3745         )
3746         .operands_in(vec![x])
3747         .operands_out(vec![a]),
3748     );
3749 
3750     ig.push(
3751         Inst::new(
3752             "fvpromote_low",
3753             r#"
3754         Converts packed single precision floating point to packed double precision floating point.
3755 
3756         Considering only the lower half of the register, the low lanes in `x` are interpreted as
3757         single precision floats that are then converted to a double precision floats.
3758 
3759         The result type will have half the number of vector lanes as the input. Fvpromote_low is
3760         constrained to input F32x4 with a result type of F64x2.
3761         "#,
3762             &formats.unary,
3763         )
3764         .operands_in(vec![a])
3765         .operands_out(vec![x]),
3766     );
3767 
3768     let x = &Operand::new("x", Float);
3769     let a = &Operand::new("a", IntTo);
3770 
3771     ig.push(
3772         Inst::new(
3773             "fcvt_to_uint",
3774             r#"
3775         Convert floating point to unsigned integer.
3776 
3777         Each lane in `x` is converted to an unsigned integer by rounding
3778         towards zero. If `x` is NaN or if the unsigned integral value cannot be
3779         represented in the result type, this instruction traps.
3780 
3781         The result type must have the same number of vector lanes as the input.
3782         "#,
3783             &formats.unary,
3784         )
3785         .operands_in(vec![x])
3786         .operands_out(vec![a])
3787         .can_trap(true),
3788     );
3789 
3790     ig.push(
3791         Inst::new(
3792             "fcvt_to_uint_sat",
3793             r#"
3794         Convert floating point to unsigned integer as fcvt_to_uint does, but
3795         saturates the input instead of trapping. NaN and negative values are
3796         converted to 0.
3797         "#,
3798             &formats.unary,
3799         )
3800         .operands_in(vec![x])
3801         .operands_out(vec![a]),
3802     );
3803 
3804     ig.push(
3805         Inst::new(
3806             "fcvt_to_sint",
3807             r#"
3808         Convert floating point to signed integer.
3809 
3810         Each lane in `x` is converted to a signed integer by rounding towards
3811         zero. If `x` is NaN or if the signed integral value cannot be
3812         represented in the result type, this instruction traps.
3813 
3814         The result type must have the same number of vector lanes as the input.
3815         "#,
3816             &formats.unary,
3817         )
3818         .operands_in(vec![x])
3819         .operands_out(vec![a])
3820         .can_trap(true),
3821     );
3822 
3823     ig.push(
3824         Inst::new(
3825             "fcvt_to_sint_sat",
3826             r#"
3827         Convert floating point to signed integer as fcvt_to_sint does, but
3828         saturates the input instead of trapping. NaN values are converted to 0.
3829         "#,
3830             &formats.unary,
3831         )
3832         .operands_in(vec![x])
3833         .operands_out(vec![a]),
3834     );
3835 
3836     let x = &Operand::new("x", Int);
3837     let a = &Operand::new("a", FloatTo);
3838 
3839     ig.push(
3840         Inst::new(
3841             "fcvt_from_uint",
3842             r#"
3843         Convert unsigned integer to floating point.
3844 
3845         Each lane in `x` is interpreted as an unsigned integer and converted to
3846         floating point using round to nearest, ties to even.
3847 
3848         The result type must have the same number of vector lanes as the input.
3849         "#,
3850             &formats.unary,
3851         )
3852         .operands_in(vec![x])
3853         .operands_out(vec![a]),
3854     );
3855 
3856     ig.push(
3857         Inst::new(
3858             "fcvt_from_sint",
3859             r#"
3860         Convert signed integer to floating point.
3861 
3862         Each lane in `x` is interpreted as a signed integer and converted to
3863         floating point using round to nearest, ties to even.
3864 
3865         The result type must have the same number of vector lanes as the input.
3866         "#,
3867             &formats.unary,
3868         )
3869         .operands_in(vec![x])
3870         .operands_out(vec![a]),
3871     );
3872 
3873     ig.push(
3874         Inst::new(
3875             "fcvt_low_from_sint",
3876             r#"
3877         Converts packed signed 32-bit integers to packed double precision floating point.
3878 
3879         Considering only the low half of the register, each lane in `x` is interpreted as a
3880         signed 32-bit integer that is then converted to a double precision float. This
3881         instruction differs from fcvt_from_sint in that it converts half the number of lanes
3882         which are converted to occupy twice the number of bits. No rounding should be needed
3883         for the resulting float.
3884 
3885         The result type will have half the number of vector lanes as the input.
3886         "#,
3887             &formats.unary,
3888         )
3889         .operands_in(vec![x])
3890         .operands_out(vec![a]),
3891     );
3892 
3893     let WideInt = &TypeVar::new(
3894         "WideInt",
3895         "An integer type with lanes from `i16` upwards",
3896         TypeSetBuilder::new()
3897             .ints(16..128)
3898             .simd_lanes(Interval::All)
3899             .build(),
3900     );
3901     let x = &Operand::new("x", WideInt);
3902     let lo = &Operand::new("lo", &WideInt.half_width()).with_doc("The low bits of `x`");
3903     let hi = &Operand::new("hi", &WideInt.half_width()).with_doc("The high bits of `x`");
3904 
3905     ig.push(
3906         Inst::new(
3907             "isplit",
3908             r#"
3909         Split an integer into low and high parts.
3910 
3911         Vectors of integers are split lane-wise, so the results have the same
3912         number of lanes as the input, but the lanes are half the size.
3913 
3914         Returns the low half of `x` and the high half of `x` as two independent
3915         values.
3916         "#,
3917             &formats.unary,
3918         )
3919         .operands_in(vec![x])
3920         .operands_out(vec![lo, hi]),
3921     );
3922 
3923     let NarrowInt = &TypeVar::new(
3924         "NarrowInt",
3925         "An integer type with lanes type to `i64`",
3926         TypeSetBuilder::new()
3927             .ints(8..64)
3928             .simd_lanes(Interval::All)
3929             .build(),
3930     );
3931 
3932     let lo = &Operand::new("lo", NarrowInt);
3933     let hi = &Operand::new("hi", NarrowInt);
3934     let a = &Operand::new("a", &NarrowInt.double_width())
3935         .with_doc("The concatenation of `lo` and `hi`");
3936 
3937     ig.push(
3938         Inst::new(
3939             "iconcat",
3940             r#"
3941         Concatenate low and high bits to form a larger integer type.
3942 
3943         Vectors of integers are concatenated lane-wise such that the result has
3944         the same number of lanes as the inputs, but the lanes are twice the
3945         size.
3946         "#,
3947             &formats.binary,
3948         )
3949         .operands_in(vec![lo, hi])
3950         .operands_out(vec![a]),
3951     );
3952 
3953     // Instructions relating to atomic memory accesses and fences
3954     let AtomicMem = &TypeVar::new(
3955         "AtomicMem",
3956         "Any type that can be stored in memory, which can be used in an atomic operation",
3957         TypeSetBuilder::new().ints(8..64).build(),
3958     );
3959     let x = &Operand::new("x", AtomicMem).with_doc("Value to be atomically stored");
3960     let a = &Operand::new("a", AtomicMem).with_doc("Value atomically loaded");
3961     let e = &Operand::new("e", AtomicMem).with_doc("Expected value in CAS");
3962     let p = &Operand::new("p", iAddr);
3963     let MemFlags = &Operand::new("MemFlags", &imm.memflags);
3964     let AtomicRmwOp = &Operand::new("AtomicRmwOp", &imm.atomic_rmw_op);
3965 
3966     ig.push(
3967         Inst::new(
3968             "atomic_rmw",
3969             r#"
3970         Atomically read-modify-write memory at `p`, with second operand `x`.  The old value is
3971         returned.  `p` has the type of the target word size, and `x` may be an integer type of
3972         8, 16, 32 or 64 bits, even on a 32-bit target.  The type of the returned value is the
3973         same as the type of `x`.  This operation is sequentially consistent and creates
3974         happens-before edges that order normal (non-atomic) loads and stores.
3975         "#,
3976             &formats.atomic_rmw,
3977         )
3978         .operands_in(vec![MemFlags, AtomicRmwOp, p, x])
3979         .operands_out(vec![a])
3980         .can_load(true)
3981         .can_store(true)
3982         .other_side_effects(true),
3983     );
3984 
3985     ig.push(
3986         Inst::new(
3987             "atomic_cas",
3988             r#"
3989         Perform an atomic compare-and-swap operation on memory at `p`, with expected value `e`,
3990         storing `x` if the value at `p` equals `e`.  The old value at `p` is returned,
3991         regardless of whether the operation succeeds or fails.  `p` has the type of the target
3992         word size, and `x` and `e` must have the same type and the same size, which may be an
3993         integer type of 8, 16, 32 or 64 bits, even on a 32-bit target.  The type of the returned
3994         value is the same as the type of `x` and `e`.  This operation is sequentially
3995         consistent and creates happens-before edges that order normal (non-atomic) loads and
3996         stores.
3997         "#,
3998             &formats.atomic_cas,
3999         )
4000         .operands_in(vec![MemFlags, p, e, x])
4001         .operands_out(vec![a])
4002         .can_load(true)
4003         .can_store(true)
4004         .other_side_effects(true),
4005     );
4006 
4007     ig.push(
4008         Inst::new(
4009             "atomic_load",
4010             r#"
4011         Atomically load from memory at `p`.
4012 
4013         This is a polymorphic instruction that can load any value type which has a memory
4014         representation.  It should only be used for integer types with 8, 16, 32 or 64 bits.
4015         This operation is sequentially consistent and creates happens-before edges that order
4016         normal (non-atomic) loads and stores.
4017         "#,
4018             &formats.load_no_offset,
4019         )
4020         .operands_in(vec![MemFlags, p])
4021         .operands_out(vec![a])
4022         .can_load(true)
4023         .other_side_effects(true),
4024     );
4025 
4026     ig.push(
4027         Inst::new(
4028             "atomic_store",
4029             r#"
4030         Atomically store `x` to memory at `p`.
4031 
4032         This is a polymorphic instruction that can store any value type with a memory
4033         representation.  It should only be used for integer types with 8, 16, 32 or 64 bits.
4034         This operation is sequentially consistent and creates happens-before edges that order
4035         normal (non-atomic) loads and stores.
4036         "#,
4037             &formats.store_no_offset,
4038         )
4039         .operands_in(vec![MemFlags, x, p])
4040         .can_store(true)
4041         .other_side_effects(true),
4042     );
4043 
4044     ig.push(
4045         Inst::new(
4046             "fence",
4047             r#"
4048         A memory fence.  This must provide ordering to ensure that, at a minimum, neither loads
4049         nor stores of any kind may move forwards or backwards across the fence.  This operation
4050         is sequentially consistent.
4051         "#,
4052             &formats.nullary,
4053         )
4054         .other_side_effects(true),
4055     );
4056 }
4057