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