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