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