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