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