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