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