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