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 { 1917 // Integer division and remainder are scalar-only; most 1918 // hardware does not directly support vector integer division. 1919 1920 let x = &Operand::new("x", iB); 1921 let y = &Operand::new("y", iB); 1922 let a = &Operand::new("a", iB); 1923 1924 ig.push( 1925 Inst::new( 1926 "udiv", 1927 r#" 1928 Unsigned integer division: `a := \lfloor {x \over y} \rfloor`. 1929 1930 This operation traps if the divisor is zero. 1931 "#, 1932 &formats.binary, 1933 ) 1934 .operands_in(vec![x, y]) 1935 .operands_out(vec![a]) 1936 .can_trap(true), 1937 ); 1938 1939 ig.push( 1940 Inst::new( 1941 "sdiv", 1942 r#" 1943 Signed integer division rounded toward zero: `a := sign(xy) 1944 \lfloor {|x| \over |y|}\rfloor`. 1945 1946 This operation traps if the divisor is zero, or if the result is not 1947 representable in `B` bits two's complement. This only happens 1948 when `x = -2^{B-1}, y = -1`. 1949 "#, 1950 &formats.binary, 1951 ) 1952 .operands_in(vec![x, y]) 1953 .operands_out(vec![a]) 1954 .can_trap(true), 1955 ); 1956 1957 ig.push( 1958 Inst::new( 1959 "urem", 1960 r#" 1961 Unsigned integer remainder. 1962 1963 This operation traps if the divisor is zero. 1964 "#, 1965 &formats.binary, 1966 ) 1967 .operands_in(vec![x, y]) 1968 .operands_out(vec![a]) 1969 .can_trap(true), 1970 ); 1971 1972 ig.push( 1973 Inst::new( 1974 "srem", 1975 r#" 1976 Signed integer remainder. The result has the sign of the dividend. 1977 1978 This operation traps if the divisor is zero. 1979 "#, 1980 &formats.binary, 1981 ) 1982 .operands_in(vec![x, y]) 1983 .operands_out(vec![a]) 1984 .can_trap(true), 1985 ); 1986 } 1987 1988 let a = &Operand::new("a", iB); 1989 let x = &Operand::new("x", iB); 1990 let Y = &Operand::new("Y", &imm.imm64); 1991 1992 ig.push( 1993 Inst::new( 1994 "iadd_imm", 1995 r#" 1996 Add immediate integer. 1997 1998 Same as `iadd`, but one operand is an immediate constant. 1999 2000 Polymorphic over all scalar integer types, but does not support vector 2001 types. 2002 "#, 2003 &formats.binary_imm64, 2004 ) 2005 .operands_in(vec![x, Y]) 2006 .operands_out(vec![a]), 2007 ); 2008 2009 ig.push( 2010 Inst::new( 2011 "imul_imm", 2012 r#" 2013 Integer multiplication by immediate constant. 2014 2015 Polymorphic over all scalar integer types, but does not support vector 2016 types. 2017 "#, 2018 &formats.binary_imm64, 2019 ) 2020 .operands_in(vec![x, Y]) 2021 .operands_out(vec![a]), 2022 ); 2023 2024 ig.push( 2025 Inst::new( 2026 "udiv_imm", 2027 r#" 2028 Unsigned integer division by an immediate constant. 2029 2030 This operation traps if the divisor is zero. 2031 "#, 2032 &formats.binary_imm64, 2033 ) 2034 .operands_in(vec![x, Y]) 2035 .operands_out(vec![a]), 2036 ); 2037 2038 ig.push( 2039 Inst::new( 2040 "sdiv_imm", 2041 r#" 2042 Signed integer division by an immediate constant. 2043 2044 This operation traps if the divisor is zero, or if the result is not 2045 representable in `B` bits two's complement. This only happens 2046 when `x = -2^{B-1}, Y = -1`. 2047 "#, 2048 &formats.binary_imm64, 2049 ) 2050 .operands_in(vec![x, Y]) 2051 .operands_out(vec![a]), 2052 ); 2053 2054 ig.push( 2055 Inst::new( 2056 "urem_imm", 2057 r#" 2058 Unsigned integer remainder with immediate divisor. 2059 2060 This operation traps if the divisor is zero. 2061 "#, 2062 &formats.binary_imm64, 2063 ) 2064 .operands_in(vec![x, Y]) 2065 .operands_out(vec![a]), 2066 ); 2067 2068 ig.push( 2069 Inst::new( 2070 "srem_imm", 2071 r#" 2072 Signed integer remainder with immediate divisor. 2073 2074 This operation traps if the divisor is zero. 2075 "#, 2076 &formats.binary_imm64, 2077 ) 2078 .operands_in(vec![x, Y]) 2079 .operands_out(vec![a]), 2080 ); 2081 2082 ig.push( 2083 Inst::new( 2084 "irsub_imm", 2085 r#" 2086 Immediate reverse wrapping subtraction: `a := Y - x \pmod{2^B}`. 2087 2088 Also works as integer negation when `Y = 0`. Use `iadd_imm` 2089 with a negative immediate operand for the reverse immediate 2090 subtraction. 2091 2092 Polymorphic over all scalar integer types, but does not support vector 2093 types. 2094 "#, 2095 &formats.binary_imm64, 2096 ) 2097 .operands_in(vec![x, Y]) 2098 .operands_out(vec![a]), 2099 ); 2100 2101 let a = &Operand::new("a", iB); 2102 let x = &Operand::new("x", iB); 2103 let y = &Operand::new("y", iB); 2104 2105 let c_in = &Operand::new("c_in", b1).with_doc("Input carry flag"); 2106 let c_out = &Operand::new("c_out", b1).with_doc("Output carry flag"); 2107 let b_in = &Operand::new("b_in", b1).with_doc("Input borrow flag"); 2108 let b_out = &Operand::new("b_out", b1).with_doc("Output borrow flag"); 2109 2110 let c_if_in = &Operand::new("c_in", iflags); 2111 let c_if_out = &Operand::new("c_out", iflags); 2112 let b_if_in = &Operand::new("b_in", iflags); 2113 let b_if_out = &Operand::new("b_out", iflags); 2114 2115 ig.push( 2116 Inst::new( 2117 "iadd_cin", 2118 r#" 2119 Add integers with carry in. 2120 2121 Same as `iadd` with an additional carry input. Computes: 2122 2123 ```text 2124 a = x + y + c_{in} \pmod 2^B 2125 ``` 2126 2127 Polymorphic over all scalar integer types, but does not support vector 2128 types. 2129 "#, 2130 &formats.ternary, 2131 ) 2132 .operands_in(vec![x, y, c_in]) 2133 .operands_out(vec![a]), 2134 ); 2135 2136 ig.push( 2137 Inst::new( 2138 "iadd_ifcin", 2139 r#" 2140 Add integers with carry in. 2141 2142 Same as `iadd` with an additional carry flag input. Computes: 2143 2144 ```text 2145 a = x + y + c_{in} \pmod 2^B 2146 ``` 2147 2148 Polymorphic over all scalar integer types, but does not support vector 2149 types. 2150 "#, 2151 &formats.ternary, 2152 ) 2153 .operands_in(vec![x, y, c_if_in]) 2154 .operands_out(vec![a]), 2155 ); 2156 2157 ig.push( 2158 Inst::new( 2159 "iadd_cout", 2160 r#" 2161 Add integers with carry out. 2162 2163 Same as `iadd` with an additional carry output. 2164 2165 ```text 2166 a &= x + y \pmod 2^B \\ 2167 c_{out} &= x+y >= 2^B 2168 ``` 2169 2170 Polymorphic over all scalar integer types, but does not support vector 2171 types. 2172 "#, 2173 &formats.binary, 2174 ) 2175 .operands_in(vec![x, y]) 2176 .operands_out(vec![a, c_out]), 2177 ); 2178 2179 ig.push( 2180 Inst::new( 2181 "iadd_ifcout", 2182 r#" 2183 Add integers with carry out. 2184 2185 Same as `iadd` with an additional carry flag output. 2186 2187 ```text 2188 a &= x + y \pmod 2^B \\ 2189 c_{out} &= x+y >= 2^B 2190 ``` 2191 2192 Polymorphic over all scalar integer types, but does not support vector 2193 types. 2194 "#, 2195 &formats.binary, 2196 ) 2197 .operands_in(vec![x, y]) 2198 .operands_out(vec![a, c_if_out]), 2199 ); 2200 2201 ig.push( 2202 Inst::new( 2203 "iadd_carry", 2204 r#" 2205 Add integers with carry in and out. 2206 2207 Same as `iadd` with an additional carry input and output. 2208 2209 ```text 2210 a &= x + y + c_{in} \pmod 2^B \\ 2211 c_{out} &= x + y + c_{in} >= 2^B 2212 ``` 2213 2214 Polymorphic over all scalar integer types, but does not support vector 2215 types. 2216 "#, 2217 &formats.ternary, 2218 ) 2219 .operands_in(vec![x, y, c_in]) 2220 .operands_out(vec![a, c_out]), 2221 ); 2222 2223 ig.push( 2224 Inst::new( 2225 "iadd_ifcarry", 2226 r#" 2227 Add integers with carry in and out. 2228 2229 Same as `iadd` with an additional carry flag input and output. 2230 2231 ```text 2232 a &= x + y + c_{in} \pmod 2^B \\ 2233 c_{out} &= x + y + c_{in} >= 2^B 2234 ``` 2235 2236 Polymorphic over all scalar integer types, but does not support vector 2237 types. 2238 "#, 2239 &formats.ternary, 2240 ) 2241 .operands_in(vec![x, y, c_if_in]) 2242 .operands_out(vec![a, c_if_out]), 2243 ); 2244 2245 ig.push( 2246 Inst::new( 2247 "isub_bin", 2248 r#" 2249 Subtract integers with borrow in. 2250 2251 Same as `isub` with an additional borrow flag input. Computes: 2252 2253 ```text 2254 a = x - (y + b_{in}) \pmod 2^B 2255 ``` 2256 2257 Polymorphic over all scalar integer types, but does not support vector 2258 types. 2259 "#, 2260 &formats.ternary, 2261 ) 2262 .operands_in(vec![x, y, b_in]) 2263 .operands_out(vec![a]), 2264 ); 2265 2266 ig.push( 2267 Inst::new( 2268 "isub_ifbin", 2269 r#" 2270 Subtract integers with borrow in. 2271 2272 Same as `isub` with an additional borrow flag input. Computes: 2273 2274 ```text 2275 a = x - (y + b_{in}) \pmod 2^B 2276 ``` 2277 2278 Polymorphic over all scalar integer types, but does not support vector 2279 types. 2280 "#, 2281 &formats.ternary, 2282 ) 2283 .operands_in(vec![x, y, b_if_in]) 2284 .operands_out(vec![a]), 2285 ); 2286 2287 ig.push( 2288 Inst::new( 2289 "isub_bout", 2290 r#" 2291 Subtract integers with borrow out. 2292 2293 Same as `isub` with an additional borrow flag output. 2294 2295 ```text 2296 a &= x - y \pmod 2^B \\ 2297 b_{out} &= x < y 2298 ``` 2299 2300 Polymorphic over all scalar integer types, but does not support vector 2301 types. 2302 "#, 2303 &formats.binary, 2304 ) 2305 .operands_in(vec![x, y]) 2306 .operands_out(vec![a, b_out]), 2307 ); 2308 2309 ig.push( 2310 Inst::new( 2311 "isub_ifbout", 2312 r#" 2313 Subtract integers with borrow out. 2314 2315 Same as `isub` with an additional borrow flag output. 2316 2317 ```text 2318 a &= x - y \pmod 2^B \\ 2319 b_{out} &= x < y 2320 ``` 2321 2322 Polymorphic over all scalar integer types, but does not support vector 2323 types. 2324 "#, 2325 &formats.binary, 2326 ) 2327 .operands_in(vec![x, y]) 2328 .operands_out(vec![a, b_if_out]), 2329 ); 2330 2331 ig.push( 2332 Inst::new( 2333 "isub_borrow", 2334 r#" 2335 Subtract integers with borrow in and out. 2336 2337 Same as `isub` with an additional borrow flag input and output. 2338 2339 ```text 2340 a &= x - (y + b_{in}) \pmod 2^B \\ 2341 b_{out} &= x < y + b_{in} 2342 ``` 2343 2344 Polymorphic over all scalar integer types, but does not support vector 2345 types. 2346 "#, 2347 &formats.ternary, 2348 ) 2349 .operands_in(vec![x, y, b_in]) 2350 .operands_out(vec![a, b_out]), 2351 ); 2352 2353 ig.push( 2354 Inst::new( 2355 "isub_ifborrow", 2356 r#" 2357 Subtract integers with borrow in and out. 2358 2359 Same as `isub` with an additional borrow flag input and output. 2360 2361 ```text 2362 a &= x - (y + b_{in}) \pmod 2^B \\ 2363 b_{out} &= x < y + b_{in} 2364 ``` 2365 2366 Polymorphic over all scalar integer types, but does not support vector 2367 types. 2368 "#, 2369 &formats.ternary, 2370 ) 2371 .operands_in(vec![x, y, b_if_in]) 2372 .operands_out(vec![a, b_if_out]), 2373 ); 2374 2375 let bits = &TypeVar::new( 2376 "bits", 2377 "Any integer, float, or boolean scalar or vector type", 2378 TypeSetBuilder::new() 2379 .ints(Interval::All) 2380 .floats(Interval::All) 2381 .bools(Interval::All) 2382 .simd_lanes(Interval::All) 2383 .includes_scalars(true) 2384 .build(), 2385 ); 2386 let x = &Operand::new("x", bits); 2387 let y = &Operand::new("y", bits); 2388 let a = &Operand::new("a", bits); 2389 2390 ig.push( 2391 Inst::new( 2392 "band", 2393 r#" 2394 Bitwise and. 2395 "#, 2396 &formats.binary, 2397 ) 2398 .operands_in(vec![x, y]) 2399 .operands_out(vec![a]), 2400 ); 2401 2402 ig.push( 2403 Inst::new( 2404 "bor", 2405 r#" 2406 Bitwise or. 2407 "#, 2408 &formats.binary, 2409 ) 2410 .operands_in(vec![x, y]) 2411 .operands_out(vec![a]), 2412 ); 2413 2414 ig.push( 2415 Inst::new( 2416 "bxor", 2417 r#" 2418 Bitwise xor. 2419 "#, 2420 &formats.binary, 2421 ) 2422 .operands_in(vec![x, y]) 2423 .operands_out(vec![a]), 2424 ); 2425 2426 ig.push( 2427 Inst::new( 2428 "bnot", 2429 r#" 2430 Bitwise not. 2431 "#, 2432 &formats.unary, 2433 ) 2434 .operands_in(vec![x]) 2435 .operands_out(vec![a]), 2436 ); 2437 2438 ig.push( 2439 Inst::new( 2440 "band_not", 2441 r#" 2442 Bitwise and not. 2443 2444 Computes `x & ~y`. 2445 "#, 2446 &formats.binary, 2447 ) 2448 .operands_in(vec![x, y]) 2449 .operands_out(vec![a]), 2450 ); 2451 2452 ig.push( 2453 Inst::new( 2454 "bor_not", 2455 r#" 2456 Bitwise or not. 2457 2458 Computes `x | ~y`. 2459 "#, 2460 &formats.binary, 2461 ) 2462 .operands_in(vec![x, y]) 2463 .operands_out(vec![a]), 2464 ); 2465 2466 ig.push( 2467 Inst::new( 2468 "bxor_not", 2469 r#" 2470 Bitwise xor not. 2471 2472 Computes `x ^ ~y`. 2473 "#, 2474 &formats.binary, 2475 ) 2476 .operands_in(vec![x, y]) 2477 .operands_out(vec![a]), 2478 ); 2479 2480 let x = &Operand::new("x", iB); 2481 let Y = &Operand::new("Y", &imm.imm64); 2482 let a = &Operand::new("a", iB); 2483 2484 ig.push( 2485 Inst::new( 2486 "band_imm", 2487 r#" 2488 Bitwise and with immediate. 2489 2490 Same as `band`, but one operand is an immediate constant. 2491 2492 Polymorphic over all scalar integer types, but does not support vector 2493 types. 2494 "#, 2495 &formats.binary_imm64, 2496 ) 2497 .operands_in(vec![x, Y]) 2498 .operands_out(vec![a]), 2499 ); 2500 2501 ig.push( 2502 Inst::new( 2503 "bor_imm", 2504 r#" 2505 Bitwise or with immediate. 2506 2507 Same as `bor`, but one operand is an immediate constant. 2508 2509 Polymorphic over all scalar integer types, but does not support vector 2510 types. 2511 "#, 2512 &formats.binary_imm64, 2513 ) 2514 .operands_in(vec![x, Y]) 2515 .operands_out(vec![a]), 2516 ); 2517 2518 ig.push( 2519 Inst::new( 2520 "bxor_imm", 2521 r#" 2522 Bitwise xor with immediate. 2523 2524 Same as `bxor`, but one operand is an immediate constant. 2525 2526 Polymorphic over all scalar integer types, but does not support vector 2527 types. 2528 "#, 2529 &formats.binary_imm64, 2530 ) 2531 .operands_in(vec![x, Y]) 2532 .operands_out(vec![a]), 2533 ); 2534 2535 let x = &Operand::new("x", Int).with_doc("Scalar or vector value to shift"); 2536 let y = &Operand::new("y", iB).with_doc("Number of bits to shift"); 2537 let Y = &Operand::new("Y", &imm.imm64); 2538 let a = &Operand::new("a", Int); 2539 2540 ig.push( 2541 Inst::new( 2542 "rotl", 2543 r#" 2544 Rotate left. 2545 2546 Rotate the bits in ``x`` by ``y`` places. 2547 "#, 2548 &formats.binary, 2549 ) 2550 .operands_in(vec![x, y]) 2551 .operands_out(vec![a]), 2552 ); 2553 2554 ig.push( 2555 Inst::new( 2556 "rotr", 2557 r#" 2558 Rotate right. 2559 2560 Rotate the bits in ``x`` by ``y`` places. 2561 "#, 2562 &formats.binary, 2563 ) 2564 .operands_in(vec![x, y]) 2565 .operands_out(vec![a]), 2566 ); 2567 2568 ig.push( 2569 Inst::new( 2570 "rotl_imm", 2571 r#" 2572 Rotate left by immediate. 2573 "#, 2574 &formats.binary_imm64, 2575 ) 2576 .operands_in(vec![x, Y]) 2577 .operands_out(vec![a]), 2578 ); 2579 2580 ig.push( 2581 Inst::new( 2582 "rotr_imm", 2583 r#" 2584 Rotate right by immediate. 2585 "#, 2586 &formats.binary_imm64, 2587 ) 2588 .operands_in(vec![x, Y]) 2589 .operands_out(vec![a]), 2590 ); 2591 2592 ig.push( 2593 Inst::new( 2594 "ishl", 2595 r#" 2596 Integer shift left. Shift the bits in ``x`` towards the MSB by ``y`` 2597 places. Shift in zero bits to the LSB. 2598 2599 The shift amount is masked to the size of ``x``. 2600 2601 When shifting a B-bits integer type, this instruction computes: 2602 2603 ```text 2604 s &:= y \pmod B, 2605 a &:= x \cdot 2^s \pmod{2^B}. 2606 ``` 2607 "#, 2608 &formats.binary, 2609 ) 2610 .operands_in(vec![x, y]) 2611 .operands_out(vec![a]), 2612 ); 2613 2614 ig.push( 2615 Inst::new( 2616 "ushr", 2617 r#" 2618 Unsigned shift right. Shift bits in ``x`` towards the LSB by ``y`` 2619 places, shifting in zero bits to the MSB. Also called a *logical 2620 shift*. 2621 2622 The shift amount is masked to the size of the register. 2623 2624 When shifting a B-bits integer type, this instruction computes: 2625 2626 ```text 2627 s &:= y \pmod B, 2628 a &:= \lfloor x \cdot 2^{-s} \rfloor. 2629 ``` 2630 "#, 2631 &formats.binary, 2632 ) 2633 .operands_in(vec![x, y]) 2634 .operands_out(vec![a]), 2635 ); 2636 2637 ig.push( 2638 Inst::new( 2639 "sshr", 2640 r#" 2641 Signed shift right. Shift bits in ``x`` towards the LSB by ``y`` 2642 places, shifting in sign bits to the MSB. Also called an *arithmetic 2643 shift*. 2644 2645 The shift amount is masked to the size of the register. 2646 "#, 2647 &formats.binary, 2648 ) 2649 .operands_in(vec![x, y]) 2650 .operands_out(vec![a]), 2651 ); 2652 2653 ig.push( 2654 Inst::new( 2655 "ishl_imm", 2656 r#" 2657 Integer shift left by immediate. 2658 2659 The shift amount is masked to the size of ``x``. 2660 "#, 2661 &formats.binary_imm64, 2662 ) 2663 .operands_in(vec![x, Y]) 2664 .operands_out(vec![a]), 2665 ); 2666 2667 ig.push( 2668 Inst::new( 2669 "ushr_imm", 2670 r#" 2671 Unsigned shift right by immediate. 2672 2673 The shift amount is masked to the size of the register. 2674 "#, 2675 &formats.binary_imm64, 2676 ) 2677 .operands_in(vec![x, Y]) 2678 .operands_out(vec![a]), 2679 ); 2680 2681 ig.push( 2682 Inst::new( 2683 "sshr_imm", 2684 r#" 2685 Signed shift right by immediate. 2686 2687 The shift amount is masked to the size of the register. 2688 "#, 2689 &formats.binary_imm64, 2690 ) 2691 .operands_in(vec![x, Y]) 2692 .operands_out(vec![a]), 2693 ); 2694 2695 let x = &Operand::new("x", iB); 2696 let a = &Operand::new("a", iB); 2697 2698 ig.push( 2699 Inst::new( 2700 "bitrev", 2701 r#" 2702 Reverse the bits of a integer. 2703 2704 Reverses the bits in ``x``. 2705 "#, 2706 &formats.unary, 2707 ) 2708 .operands_in(vec![x]) 2709 .operands_out(vec![a]), 2710 ); 2711 2712 ig.push( 2713 Inst::new( 2714 "clz", 2715 r#" 2716 Count leading zero bits. 2717 2718 Starting from the MSB in ``x``, count the number of zero bits before 2719 reaching the first one bit. When ``x`` is zero, returns the size of x 2720 in bits. 2721 "#, 2722 &formats.unary, 2723 ) 2724 .operands_in(vec![x]) 2725 .operands_out(vec![a]), 2726 ); 2727 2728 ig.push( 2729 Inst::new( 2730 "cls", 2731 r#" 2732 Count leading sign bits. 2733 2734 Starting from the MSB after the sign bit in ``x``, count the number of 2735 consecutive bits identical to the sign bit. When ``x`` is 0 or -1, 2736 returns one less than the size of x in bits. 2737 "#, 2738 &formats.unary, 2739 ) 2740 .operands_in(vec![x]) 2741 .operands_out(vec![a]), 2742 ); 2743 2744 ig.push( 2745 Inst::new( 2746 "ctz", 2747 r#" 2748 Count trailing zeros. 2749 2750 Starting from the LSB in ``x``, count the number of zero bits before 2751 reaching the first one bit. When ``x`` is zero, returns the size of x 2752 in bits. 2753 "#, 2754 &formats.unary, 2755 ) 2756 .operands_in(vec![x]) 2757 .operands_out(vec![a]), 2758 ); 2759 2760 let x = &Operand::new("x", Int); 2761 let a = &Operand::new("a", Int); 2762 2763 ig.push( 2764 Inst::new( 2765 "popcnt", 2766 r#" 2767 Population count 2768 2769 Count the number of one bits in ``x``. 2770 "#, 2771 &formats.unary, 2772 ) 2773 .operands_in(vec![x]) 2774 .operands_out(vec![a]), 2775 ); 2776 2777 let Float = &TypeVar::new( 2778 "Float", 2779 "A scalar or vector floating point number", 2780 TypeSetBuilder::new() 2781 .floats(Interval::All) 2782 .simd_lanes(Interval::All) 2783 .build(), 2784 ); 2785 let Cond = &Operand::new("Cond", &imm.floatcc); 2786 let x = &Operand::new("x", Float); 2787 let y = &Operand::new("y", Float); 2788 let a = &Operand::new("a", &Float.as_bool()); 2789 2790 ig.push( 2791 Inst::new( 2792 "fcmp", 2793 r#" 2794 Floating point comparison. 2795 2796 Two IEEE 754-2008 floating point numbers, `x` and `y`, relate to each 2797 other in exactly one of four ways: 2798 2799 ```text 2800 == ========================================== 2801 UN Unordered when one or both numbers is NaN. 2802 EQ When `x = y`. (And `0.0 = -0.0`). 2803 LT When `x < y`. 2804 GT When `x > y`. 2805 == ========================================== 2806 ``` 2807 2808 The 14 `floatcc` condition codes each correspond to a subset of 2809 the four relations, except for the empty set which would always be 2810 false, and the full set which would always be true. 2811 2812 The condition codes are divided into 7 'ordered' conditions which don't 2813 include UN, and 7 unordered conditions which all include UN. 2814 2815 ```text 2816 +-------+------------+---------+------------+-------------------------+ 2817 |Ordered |Unordered |Condition | 2818 +=======+============+=========+============+=========================+ 2819 |ord |EQ | LT | GT|uno |UN |NaNs absent / present. | 2820 +-------+------------+---------+------------+-------------------------+ 2821 |eq |EQ |ueq |UN | EQ |Equal | 2822 +-------+------------+---------+------------+-------------------------+ 2823 |one |LT | GT |ne |UN | LT | GT|Not equal | 2824 +-------+------------+---------+------------+-------------------------+ 2825 |lt |LT |ult |UN | LT |Less than | 2826 +-------+------------+---------+------------+-------------------------+ 2827 |le |LT | EQ |ule |UN | LT | EQ|Less than or equal | 2828 +-------+------------+---------+------------+-------------------------+ 2829 |gt |GT |ugt |UN | GT |Greater than | 2830 +-------+------------+---------+------------+-------------------------+ 2831 |ge |GT | EQ |uge |UN | GT | EQ|Greater than or equal | 2832 +-------+------------+---------+------------+-------------------------+ 2833 ``` 2834 2835 The standard C comparison operators, `<, <=, >, >=`, are all ordered, 2836 so they are false if either operand is NaN. The C equality operator, 2837 `==`, is ordered, and since inequality is defined as the logical 2838 inverse it is *unordered*. They map to the `floatcc` condition 2839 codes as follows: 2840 2841 ```text 2842 ==== ====== ============ 2843 C `Cond` Subset 2844 ==== ====== ============ 2845 `==` eq EQ 2846 `!=` ne UN | LT | GT 2847 `<` lt LT 2848 `<=` le LT | EQ 2849 `>` gt GT 2850 `>=` ge GT | EQ 2851 ==== ====== ============ 2852 ``` 2853 2854 This subset of condition codes also corresponds to the WebAssembly 2855 floating point comparisons of the same name. 2856 2857 When this instruction compares floating point vectors, it returns a 2858 boolean vector with the results of lane-wise comparisons. 2859 "#, 2860 &formats.float_compare, 2861 ) 2862 .operands_in(vec![Cond, x, y]) 2863 .operands_out(vec![a]), 2864 ); 2865 2866 let f = &Operand::new("f", fflags); 2867 2868 ig.push( 2869 Inst::new( 2870 "ffcmp", 2871 r#" 2872 Floating point comparison returning flags. 2873 2874 Compares two numbers like `fcmp`, but returns floating point CPU 2875 flags instead of testing a specific condition. 2876 "#, 2877 &formats.binary, 2878 ) 2879 .operands_in(vec![x, y]) 2880 .operands_out(vec![f]), 2881 ); 2882 2883 let x = &Operand::new("x", Float); 2884 let y = &Operand::new("y", Float); 2885 let z = &Operand::new("z", Float); 2886 let a = &Operand::new("a", Float).with_doc("Result of applying operator to each lane"); 2887 2888 ig.push( 2889 Inst::new( 2890 "fadd", 2891 r#" 2892 Floating point addition. 2893 "#, 2894 &formats.binary, 2895 ) 2896 .operands_in(vec![x, y]) 2897 .operands_out(vec![a]), 2898 ); 2899 2900 ig.push( 2901 Inst::new( 2902 "fsub", 2903 r#" 2904 Floating point subtraction. 2905 "#, 2906 &formats.binary, 2907 ) 2908 .operands_in(vec![x, y]) 2909 .operands_out(vec![a]), 2910 ); 2911 2912 ig.push( 2913 Inst::new( 2914 "fmul", 2915 r#" 2916 Floating point multiplication. 2917 "#, 2918 &formats.binary, 2919 ) 2920 .operands_in(vec![x, y]) 2921 .operands_out(vec![a]), 2922 ); 2923 2924 ig.push( 2925 Inst::new( 2926 "fdiv", 2927 r#" 2928 Floating point division. 2929 2930 Unlike the integer division instructions ` and 2931 `udiv`, this can't trap. Division by zero is infinity or 2932 NaN, depending on the dividend. 2933 "#, 2934 &formats.binary, 2935 ) 2936 .operands_in(vec![x, y]) 2937 .operands_out(vec![a]), 2938 ); 2939 2940 ig.push( 2941 Inst::new( 2942 "sqrt", 2943 r#" 2944 Floating point square root. 2945 "#, 2946 &formats.unary, 2947 ) 2948 .operands_in(vec![x]) 2949 .operands_out(vec![a]), 2950 ); 2951 2952 ig.push( 2953 Inst::new( 2954 "fma", 2955 r#" 2956 Floating point fused multiply-and-add. 2957 2958 Computes `a := xy+z` without any intermediate rounding of the 2959 product. 2960 "#, 2961 &formats.ternary, 2962 ) 2963 .operands_in(vec![x, y, z]) 2964 .operands_out(vec![a]), 2965 ); 2966 2967 let a = &Operand::new("a", Float).with_doc("``x`` with its sign bit inverted"); 2968 2969 ig.push( 2970 Inst::new( 2971 "fneg", 2972 r#" 2973 Floating point negation. 2974 2975 Note that this is a pure bitwise operation. 2976 "#, 2977 &formats.unary, 2978 ) 2979 .operands_in(vec![x]) 2980 .operands_out(vec![a]), 2981 ); 2982 2983 let a = &Operand::new("a", Float).with_doc("``x`` with its sign bit cleared"); 2984 2985 ig.push( 2986 Inst::new( 2987 "fabs", 2988 r#" 2989 Floating point absolute value. 2990 2991 Note that this is a pure bitwise operation. 2992 "#, 2993 &formats.unary, 2994 ) 2995 .operands_in(vec![x]) 2996 .operands_out(vec![a]), 2997 ); 2998 2999 let a = &Operand::new("a", Float).with_doc("``x`` with its sign bit changed to that of ``y``"); 3000 3001 ig.push( 3002 Inst::new( 3003 "fcopysign", 3004 r#" 3005 Floating point copy sign. 3006 3007 Note that this is a pure bitwise operation. The sign bit from ``y`` is 3008 copied to the sign bit of ``x``. 3009 "#, 3010 &formats.binary, 3011 ) 3012 .operands_in(vec![x, y]) 3013 .operands_out(vec![a]), 3014 ); 3015 3016 let a = &Operand::new("a", Float).with_doc("The smaller of ``x`` and ``y``"); 3017 3018 ig.push( 3019 Inst::new( 3020 "fmin", 3021 r#" 3022 Floating point minimum, propagating NaNs using the WebAssembly rules. 3023 3024 If either operand is NaN, this returns NaN with an unspecified sign. Furthermore, if 3025 each input NaN consists of a mantissa whose most significant bit is 1 and the rest is 3026 0, then the output has the same form. Otherwise, the output mantissa's most significant 3027 bit is 1 and the rest is unspecified. 3028 "#, 3029 &formats.binary, 3030 ) 3031 .operands_in(vec![x, y]) 3032 .operands_out(vec![a]), 3033 ); 3034 3035 ig.push( 3036 Inst::new( 3037 "fmin_pseudo", 3038 r#" 3039 Floating point pseudo-minimum, propagating NaNs. This behaves differently from ``fmin``. 3040 See <https://github.com/WebAssembly/simd/pull/122> for background. 3041 3042 The behaviour is defined as ``fmin_pseudo(a, b) = (b < a) ? b : a``, and the behaviour 3043 for zero or NaN inputs follows from the behaviour of ``<`` with such inputs. 3044 "#, 3045 &formats.binary, 3046 ) 3047 .operands_in(vec![x, y]) 3048 .operands_out(vec![a]), 3049 ); 3050 3051 let a = &Operand::new("a", Float).with_doc("The larger of ``x`` and ``y``"); 3052 3053 ig.push( 3054 Inst::new( 3055 "fmax", 3056 r#" 3057 Floating point maximum, propagating NaNs using the WebAssembly rules. 3058 3059 If either operand is NaN, this returns NaN with an unspecified sign. Furthermore, if 3060 each input NaN consists of a mantissa whose most significant bit is 1 and the rest is 3061 0, then the output has the same form. Otherwise, the output mantissa's most significant 3062 bit is 1 and the rest is unspecified. 3063 "#, 3064 &formats.binary, 3065 ) 3066 .operands_in(vec![x, y]) 3067 .operands_out(vec![a]), 3068 ); 3069 3070 ig.push( 3071 Inst::new( 3072 "fmax_pseudo", 3073 r#" 3074 Floating point pseudo-maximum, propagating NaNs. This behaves differently from ``fmax``. 3075 See <https://github.com/WebAssembly/simd/pull/122> for background. 3076 3077 The behaviour is defined as ``fmax_pseudo(a, b) = (a < b) ? b : a``, and the behaviour 3078 for zero or NaN inputs follows from the behaviour of ``<`` with such inputs. 3079 "#, 3080 &formats.binary, 3081 ) 3082 .operands_in(vec![x, y]) 3083 .operands_out(vec![a]), 3084 ); 3085 3086 let a = &Operand::new("a", Float).with_doc("``x`` rounded to integral value"); 3087 3088 ig.push( 3089 Inst::new( 3090 "ceil", 3091 r#" 3092 Round floating point round to integral, towards positive infinity. 3093 "#, 3094 &formats.unary, 3095 ) 3096 .operands_in(vec![x]) 3097 .operands_out(vec![a]), 3098 ); 3099 3100 ig.push( 3101 Inst::new( 3102 "floor", 3103 r#" 3104 Round floating point round to integral, towards negative infinity. 3105 "#, 3106 &formats.unary, 3107 ) 3108 .operands_in(vec![x]) 3109 .operands_out(vec![a]), 3110 ); 3111 3112 ig.push( 3113 Inst::new( 3114 "trunc", 3115 r#" 3116 Round floating point round to integral, towards zero. 3117 "#, 3118 &formats.unary, 3119 ) 3120 .operands_in(vec![x]) 3121 .operands_out(vec![a]), 3122 ); 3123 3124 ig.push( 3125 Inst::new( 3126 "nearest", 3127 r#" 3128 Round floating point round to integral, towards nearest with ties to 3129 even. 3130 "#, 3131 &formats.unary, 3132 ) 3133 .operands_in(vec![x]) 3134 .operands_out(vec![a]), 3135 ); 3136 3137 let a = &Operand::new("a", b1); 3138 let x = &Operand::new("x", Ref); 3139 3140 ig.push( 3141 Inst::new( 3142 "is_null", 3143 r#" 3144 Reference verification. 3145 3146 The condition code determines if the reference type in question is 3147 null or not. 3148 "#, 3149 &formats.unary, 3150 ) 3151 .operands_in(vec![x]) 3152 .operands_out(vec![a]), 3153 ); 3154 3155 let a = &Operand::new("a", b1); 3156 let x = &Operand::new("x", Ref); 3157 3158 ig.push( 3159 Inst::new( 3160 "is_invalid", 3161 r#" 3162 Reference verification. 3163 3164 The condition code determines if the reference type in question is 3165 invalid or not. 3166 "#, 3167 &formats.unary, 3168 ) 3169 .operands_in(vec![x]) 3170 .operands_out(vec![a]), 3171 ); 3172 3173 let Cond = &Operand::new("Cond", &imm.intcc); 3174 let f = &Operand::new("f", iflags); 3175 let a = &Operand::new("a", b1); 3176 3177 ig.push( 3178 Inst::new( 3179 "trueif", 3180 r#" 3181 Test integer CPU flags for a specific condition. 3182 3183 Check the CPU flags in ``f`` against the ``Cond`` condition code and 3184 return true when the condition code is satisfied. 3185 "#, 3186 &formats.int_cond, 3187 ) 3188 .operands_in(vec![Cond, f]) 3189 .operands_out(vec![a]), 3190 ); 3191 3192 let Cond = &Operand::new("Cond", &imm.floatcc); 3193 let f = &Operand::new("f", fflags); 3194 3195 ig.push( 3196 Inst::new( 3197 "trueff", 3198 r#" 3199 Test floating point CPU flags for a specific condition. 3200 3201 Check the CPU flags in ``f`` against the ``Cond`` condition code and 3202 return true when the condition code is satisfied. 3203 "#, 3204 &formats.float_cond, 3205 ) 3206 .operands_in(vec![Cond, f]) 3207 .operands_out(vec![a]), 3208 ); 3209 3210 let x = &Operand::new("x", Mem); 3211 let a = &Operand::new("a", MemTo).with_doc("Bits of `x` reinterpreted"); 3212 3213 ig.push( 3214 Inst::new( 3215 "bitcast", 3216 r#" 3217 Reinterpret the bits in `x` as a different type. 3218 3219 The input and output types must be storable to memory and of the same 3220 size. A bitcast is equivalent to storing one type and loading the other 3221 type from the same address. 3222 "#, 3223 &formats.unary, 3224 ) 3225 .operands_in(vec![x]) 3226 .operands_out(vec![a]), 3227 ); 3228 3229 let x = &Operand::new("x", Any); 3230 let a = &Operand::new("a", AnyTo).with_doc("Bits of `x` reinterpreted"); 3231 3232 ig.push( 3233 Inst::new( 3234 "raw_bitcast", 3235 r#" 3236 Cast the bits in `x` as a different type of the same bit width. 3237 3238 This instruction does not change the data's representation but allows 3239 data in registers to be used as different types, e.g. an i32x4 as a 3240 b8x16. The only constraint on the result `a` is that it can be 3241 `raw_bitcast` back to the original type. Also, in a raw_bitcast between 3242 vector types with the same number of lanes, the value of each result 3243 lane is a raw_bitcast of the corresponding operand lane. TODO there is 3244 currently no mechanism for enforcing the bit width constraint. 3245 "#, 3246 &formats.unary, 3247 ) 3248 .operands_in(vec![x]) 3249 .operands_out(vec![a]), 3250 ); 3251 3252 let a = &Operand::new("a", TxN).with_doc("A vector value"); 3253 let s = &Operand::new("s", &TxN.lane_of()).with_doc("A scalar value"); 3254 3255 ig.push( 3256 Inst::new( 3257 "scalar_to_vector", 3258 r#" 3259 Copies a scalar value to a vector value. The scalar is copied into the 3260 least significant lane of the vector, and all other lanes will be zero. 3261 "#, 3262 &formats.unary, 3263 ) 3264 .operands_in(vec![s]) 3265 .operands_out(vec![a]), 3266 ); 3267 3268 let Bool = &TypeVar::new( 3269 "Bool", 3270 "A scalar or vector boolean type", 3271 TypeSetBuilder::new() 3272 .bools(Interval::All) 3273 .simd_lanes(Interval::All) 3274 .build(), 3275 ); 3276 3277 let BoolTo = &TypeVar::new( 3278 "BoolTo", 3279 "A smaller boolean type with the same number of lanes", 3280 TypeSetBuilder::new() 3281 .bools(Interval::All) 3282 .simd_lanes(Interval::All) 3283 .build(), 3284 ); 3285 3286 let x = &Operand::new("x", Bool); 3287 let a = &Operand::new("a", BoolTo); 3288 3289 ig.push( 3290 Inst::new( 3291 "breduce", 3292 r#" 3293 Convert `x` to a smaller boolean type in the platform-defined way. 3294 3295 The result type must have the same number of vector lanes as the input, 3296 and each lane must not have more bits that the input lanes. If the 3297 input and output types are the same, this is a no-op. 3298 "#, 3299 &formats.unary, 3300 ) 3301 .operands_in(vec![x]) 3302 .operands_out(vec![a]), 3303 ); 3304 3305 let BoolTo = &TypeVar::new( 3306 "BoolTo", 3307 "A larger boolean type with the same number of lanes", 3308 TypeSetBuilder::new() 3309 .bools(Interval::All) 3310 .simd_lanes(Interval::All) 3311 .build(), 3312 ); 3313 let x = &Operand::new("x", Bool); 3314 let a = &Operand::new("a", BoolTo); 3315 3316 ig.push( 3317 Inst::new( 3318 "bextend", 3319 r#" 3320 Convert `x` to a larger boolean type in the platform-defined way. 3321 3322 The result type must have the same number of vector lanes as the input, 3323 and each lane must not have fewer bits that the input lanes. If the 3324 input and output types are the same, this is a no-op. 3325 "#, 3326 &formats.unary, 3327 ) 3328 .operands_in(vec![x]) 3329 .operands_out(vec![a]), 3330 ); 3331 3332 let IntTo = &TypeVar::new( 3333 "IntTo", 3334 "An integer type with the same number of lanes", 3335 TypeSetBuilder::new() 3336 .ints(Interval::All) 3337 .simd_lanes(Interval::All) 3338 .build(), 3339 ); 3340 let x = &Operand::new("x", Bool); 3341 let a = &Operand::new("a", IntTo); 3342 3343 ig.push( 3344 Inst::new( 3345 "bint", 3346 r#" 3347 Convert `x` to an integer. 3348 3349 True maps to 1 and false maps to 0. The result type must have the same 3350 number of vector lanes as the input. 3351 "#, 3352 &formats.unary, 3353 ) 3354 .operands_in(vec![x]) 3355 .operands_out(vec![a]), 3356 ); 3357 3358 ig.push( 3359 Inst::new( 3360 "bmask", 3361 r#" 3362 Convert `x` to an integer mask. 3363 3364 True maps to all 1s and false maps to all 0s. The result type must have 3365 the same number of vector lanes as the input. 3366 "#, 3367 &formats.unary, 3368 ) 3369 .operands_in(vec![x]) 3370 .operands_out(vec![a]), 3371 ); 3372 3373 let Int = &TypeVar::new( 3374 "Int", 3375 "A scalar or vector integer type", 3376 TypeSetBuilder::new() 3377 .ints(Interval::All) 3378 .simd_lanes(Interval::All) 3379 .build(), 3380 ); 3381 3382 let IntTo = &TypeVar::new( 3383 "IntTo", 3384 "A smaller integer type with the same number of lanes", 3385 TypeSetBuilder::new() 3386 .ints(Interval::All) 3387 .simd_lanes(Interval::All) 3388 .build(), 3389 ); 3390 let x = &Operand::new("x", Int); 3391 let a = &Operand::new("a", IntTo); 3392 3393 ig.push( 3394 Inst::new( 3395 "ireduce", 3396 r#" 3397 Convert `x` to a smaller integer type by dropping high bits. 3398 3399 Each lane in `x` is converted to a smaller integer type by discarding 3400 the most significant bits. This is the same as reducing modulo 3401 `2^n`. 3402 3403 The result type must have the same number of vector lanes as the input, 3404 and each lane must not have more bits that the input lanes. If the 3405 input and output types are the same, this is a no-op. 3406 "#, 3407 &formats.unary, 3408 ) 3409 .operands_in(vec![x]) 3410 .operands_out(vec![a]), 3411 ); 3412 3413 let I16or32or64xN = &TypeVar::new( 3414 "I16or32or64xN", 3415 "A SIMD vector type containing integer lanes 16, 32, or 64 bits wide", 3416 TypeSetBuilder::new() 3417 .ints(16..64) 3418 .simd_lanes(2..8) 3419 .includes_scalars(false) 3420 .build(), 3421 ); 3422 3423 let x = &Operand::new("x", I16or32or64xN); 3424 let y = &Operand::new("y", I16or32or64xN); 3425 let a = &Operand::new("a", &I16or32or64xN.split_lanes()); 3426 3427 ig.push( 3428 Inst::new( 3429 "snarrow", 3430 r#" 3431 Combine `x` and `y` into a vector with twice the lanes but half the integer width while 3432 saturating overflowing values to the signed maximum and minimum. 3433 3434 The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4` 3435 and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value 3436 returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`. 3437 "#, 3438 &formats.binary, 3439 ) 3440 .operands_in(vec![x, y]) 3441 .operands_out(vec![a]), 3442 ); 3443 3444 ig.push( 3445 Inst::new( 3446 "unarrow", 3447 r#" 3448 Combine `x` and `y` into a vector with twice the lanes but half the integer width while 3449 saturating overflowing values to the unsigned maximum and minimum. 3450 3451 Note that all input lanes are considered signed: any negative lanes will overflow and be 3452 replaced with the unsigned minimum, `0x00`. 3453 3454 The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4` 3455 and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value 3456 returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`. 3457 "#, 3458 &formats.binary, 3459 ) 3460 .operands_in(vec![x, y]) 3461 .operands_out(vec![a]), 3462 ); 3463 3464 ig.push( 3465 Inst::new( 3466 "uunarrow", 3467 r#" 3468 Combine `x` and `y` into a vector with twice the lanes but half the integer width while 3469 saturating overflowing values to the unsigned maximum and minimum. 3470 3471 Note that all input lanes are considered unsigned: any negative values will be interpreted as unsigned, overflowing and being replaced with the unsigned maximum. 3472 3473 The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4` 3474 and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value 3475 returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`. 3476 "#, 3477 &formats.binary, 3478 ) 3479 .operands_in(vec![x, y]) 3480 .operands_out(vec![a]), 3481 ); 3482 3483 let I8or16or32xN = &TypeVar::new( 3484 "I8or16or32xN", 3485 "A SIMD vector type containing integer lanes 8, 16, or 32 bits wide.", 3486 TypeSetBuilder::new() 3487 .ints(8..32) 3488 .simd_lanes(4..16) 3489 .includes_scalars(false) 3490 .build(), 3491 ); 3492 3493 let x = &Operand::new("x", I8or16or32xN); 3494 let a = &Operand::new("a", &I8or16or32xN.merge_lanes()); 3495 3496 ig.push( 3497 Inst::new( 3498 "swiden_low", 3499 r#" 3500 Widen the low lanes of `x` using signed extension. 3501 3502 This will double the lane width and halve the number of lanes. 3503 "#, 3504 &formats.unary, 3505 ) 3506 .operands_in(vec![x]) 3507 .operands_out(vec![a]), 3508 ); 3509 3510 ig.push( 3511 Inst::new( 3512 "swiden_high", 3513 r#" 3514 Widen the high lanes of `x` using signed extension. 3515 3516 This will double the lane width and halve the number of lanes. 3517 "#, 3518 &formats.unary, 3519 ) 3520 .operands_in(vec![x]) 3521 .operands_out(vec![a]), 3522 ); 3523 3524 ig.push( 3525 Inst::new( 3526 "uwiden_low", 3527 r#" 3528 Widen the low lanes of `x` using unsigned extension. 3529 3530 This will double the lane width and halve the number of lanes. 3531 "#, 3532 &formats.unary, 3533 ) 3534 .operands_in(vec![x]) 3535 .operands_out(vec![a]), 3536 ); 3537 3538 ig.push( 3539 Inst::new( 3540 "uwiden_high", 3541 r#" 3542 Widen the high lanes of `x` using unsigned extension. 3543 3544 This will double the lane width and halve the number of lanes. 3545 "#, 3546 &formats.unary, 3547 ) 3548 .operands_in(vec![x]) 3549 .operands_out(vec![a]), 3550 ); 3551 3552 let x = &Operand::new("x", I8or16or32xN); 3553 let y = &Operand::new("y", I8or16or32xN); 3554 let a = &Operand::new("a", I8or16or32xN); 3555 3556 ig.push( 3557 Inst::new( 3558 "iadd_pairwise", 3559 r#" 3560 Does lane-wise integer pairwise addition on two operands, putting the 3561 combined results into a single vector result. Here a pair refers to adjacent 3562 lanes in a vector, i.e. i*2 + (i*2+1) for i == num_lanes/2. The first operand 3563 pairwise add results will make up the low half of the resulting vector while 3564 the second operand pairwise add results will make up the upper half of the 3565 resulting vector. 3566 "#, 3567 &formats.binary, 3568 ) 3569 .operands_in(vec![x, y]) 3570 .operands_out(vec![a]), 3571 ); 3572 3573 let I16x8 = &TypeVar::new( 3574 "I16x8", 3575 "A SIMD vector type containing 8 integer lanes each 16 bits wide.", 3576 TypeSetBuilder::new() 3577 .ints(16..16) 3578 .simd_lanes(8..8) 3579 .includes_scalars(false) 3580 .build(), 3581 ); 3582 3583 let x = &Operand::new("x", I16x8); 3584 let y = &Operand::new("y", I16x8); 3585 let a = &Operand::new("a", &I16x8.merge_lanes()); 3586 3587 ig.push( 3588 Inst::new( 3589 "widening_pairwise_dot_product_s", 3590 r#" 3591 Takes corresponding elements in `x` and `y`, performs a sign-extending length-doubling 3592 multiplication on them, then adds adjacent pairs of elements to form the result. For 3593 example, if the input vectors are `[x3, x2, x1, x0]` and `[y3, y2, y1, y0]`, it produces 3594 the vector `[r1, r0]`, where `r1 = sx(x3) * sx(y3) + sx(x2) * sx(y2)` and 3595 `r0 = sx(x1) * sx(y1) + sx(x0) * sx(y0)`, and `sx(n)` sign-extends `n` to twice its width. 3596 3597 This will double the lane width and halve the number of lanes. So the resulting 3598 vector has the same number of bits as `x` and `y` do (individually). 3599 3600 See <https://github.com/WebAssembly/simd/pull/127> for background info. 3601 "#, 3602 &formats.binary, 3603 ) 3604 .operands_in(vec![x, y]) 3605 .operands_out(vec![a]), 3606 ); 3607 3608 let IntTo = &TypeVar::new( 3609 "IntTo", 3610 "A larger integer type with the same number of lanes", 3611 TypeSetBuilder::new() 3612 .ints(Interval::All) 3613 .simd_lanes(Interval::All) 3614 .build(), 3615 ); 3616 let x = &Operand::new("x", Int); 3617 let a = &Operand::new("a", IntTo); 3618 3619 ig.push( 3620 Inst::new( 3621 "uextend", 3622 r#" 3623 Convert `x` to a larger integer type by zero-extending. 3624 3625 Each lane in `x` is converted to a larger integer type by adding 3626 zeroes. The result has the same numerical value as `x` when both are 3627 interpreted as unsigned integers. 3628 3629 The result type must have the same number of vector lanes as the input, 3630 and each lane must not have fewer bits that the input lanes. If the 3631 input and output types are the same, this is a no-op. 3632 "#, 3633 &formats.unary, 3634 ) 3635 .operands_in(vec![x]) 3636 .operands_out(vec![a]), 3637 ); 3638 3639 ig.push( 3640 Inst::new( 3641 "sextend", 3642 r#" 3643 Convert `x` to a larger integer type by sign-extending. 3644 3645 Each lane in `x` is converted to a larger integer type by replicating 3646 the sign bit. The result has the same numerical value as `x` when both 3647 are interpreted as signed integers. 3648 3649 The result type must have the same number of vector lanes as the input, 3650 and each lane must not have fewer bits that the input lanes. If the 3651 input and output types are the same, this is a no-op. 3652 "#, 3653 &formats.unary, 3654 ) 3655 .operands_in(vec![x]) 3656 .operands_out(vec![a]), 3657 ); 3658 3659 let FloatTo = &TypeVar::new( 3660 "FloatTo", 3661 "A scalar or vector floating point number", 3662 TypeSetBuilder::new() 3663 .floats(Interval::All) 3664 .simd_lanes(Interval::All) 3665 .build(), 3666 ); 3667 let x = &Operand::new("x", Float); 3668 let a = &Operand::new("a", FloatTo); 3669 3670 ig.push( 3671 Inst::new( 3672 "fpromote", 3673 r#" 3674 Convert `x` to a larger floating point format. 3675 3676 Each lane in `x` is converted to the destination floating point format. 3677 This is an exact operation. 3678 3679 Cranelift currently only supports two floating point formats 3680 - `f32` and `f64`. This may change in the future. 3681 3682 The result type must have the same number of vector lanes as the input, 3683 and the result lanes must not have fewer bits than the input lanes. If 3684 the input and output types are the same, this is a no-op. 3685 "#, 3686 &formats.unary, 3687 ) 3688 .operands_in(vec![x]) 3689 .operands_out(vec![a]), 3690 ); 3691 3692 ig.push( 3693 Inst::new( 3694 "fdemote", 3695 r#" 3696 Convert `x` to a smaller floating point format. 3697 3698 Each lane in `x` is converted to the destination floating point format 3699 by rounding to nearest, ties to even. 3700 3701 Cranelift currently only supports two floating point formats 3702 - `f32` and `f64`. This may change in the future. 3703 3704 The result type must have the same number of vector lanes as the input, 3705 and the result lanes must not have more bits than the input lanes. If 3706 the input and output types are the same, this is a no-op. 3707 "#, 3708 &formats.unary, 3709 ) 3710 .operands_in(vec![x]) 3711 .operands_out(vec![a]), 3712 ); 3713 3714 let F64x2 = &TypeVar::new( 3715 "F64x2", 3716 "A SIMD vector type consisting of 2 lanes of 64-bit floats", 3717 TypeSetBuilder::new() 3718 .floats(64..64) 3719 .simd_lanes(2..2) 3720 .includes_scalars(false) 3721 .build(), 3722 ); 3723 let F32x4 = &TypeVar::new( 3724 "F32x4", 3725 "A SIMD vector type consisting of 4 lanes of 32-bit floats", 3726 TypeSetBuilder::new() 3727 .floats(32..32) 3728 .simd_lanes(4..4) 3729 .includes_scalars(false) 3730 .build(), 3731 ); 3732 3733 let x = &Operand::new("x", F64x2); 3734 let a = &Operand::new("a", F32x4); 3735 3736 ig.push( 3737 Inst::new( 3738 "fvdemote", 3739 r#" 3740 Convert `x` to a smaller floating point format. 3741 3742 Each lane in `x` is converted to the destination floating point format 3743 by rounding to nearest, ties to even. 3744 3745 Cranelift currently only supports two floating point formats 3746 - `f32` and `f64`. This may change in the future. 3747 3748 Fvdemote differs from fdemote in that with fvdemote it targets vectors. 3749 Fvdemote is constrained to having the input type being F64x2 and the result 3750 type being F32x4. The result lane that was the upper half of the input lane 3751 is initialized to zero. 3752 "#, 3753 &formats.unary, 3754 ) 3755 .operands_in(vec![x]) 3756 .operands_out(vec![a]), 3757 ); 3758 3759 ig.push( 3760 Inst::new( 3761 "fvpromote_low", 3762 r#" 3763 Converts packed single precision floating point to packed double precision floating point. 3764 3765 Considering only the lower half of the register, the low lanes in `x` are interpreted as 3766 single precision floats that are then converted to a double precision floats. 3767 3768 The result type will have half the number of vector lanes as the input. Fvpromote_low is 3769 constrained to input F32x4 with a result type of F64x2. 3770 "#, 3771 &formats.unary, 3772 ) 3773 .operands_in(vec![a]) 3774 .operands_out(vec![x]), 3775 ); 3776 3777 let x = &Operand::new("x", Float); 3778 let a = &Operand::new("a", IntTo); 3779 3780 ig.push( 3781 Inst::new( 3782 "fcvt_to_uint", 3783 r#" 3784 Convert floating point to unsigned integer. 3785 3786 Each lane in `x` is converted to an unsigned integer by rounding 3787 towards zero. If `x` is NaN or if the unsigned integral value cannot be 3788 represented in the result type, this instruction traps. 3789 3790 The result type must have the same number of vector lanes as the input. 3791 "#, 3792 &formats.unary, 3793 ) 3794 .operands_in(vec![x]) 3795 .operands_out(vec![a]) 3796 .can_trap(true), 3797 ); 3798 3799 ig.push( 3800 Inst::new( 3801 "fcvt_to_uint_sat", 3802 r#" 3803 Convert floating point to unsigned integer as fcvt_to_uint does, but 3804 saturates the input instead of trapping. NaN and negative values are 3805 converted to 0. 3806 "#, 3807 &formats.unary, 3808 ) 3809 .operands_in(vec![x]) 3810 .operands_out(vec![a]), 3811 ); 3812 3813 ig.push( 3814 Inst::new( 3815 "fcvt_to_sint", 3816 r#" 3817 Convert floating point to signed integer. 3818 3819 Each lane in `x` is converted to a signed integer by rounding towards 3820 zero. If `x` is NaN or if the signed integral value cannot be 3821 represented in the result type, this instruction traps. 3822 3823 The result type must have the same number of vector lanes as the input. 3824 "#, 3825 &formats.unary, 3826 ) 3827 .operands_in(vec![x]) 3828 .operands_out(vec![a]) 3829 .can_trap(true), 3830 ); 3831 3832 ig.push( 3833 Inst::new( 3834 "fcvt_to_sint_sat", 3835 r#" 3836 Convert floating point to signed integer as fcvt_to_sint does, but 3837 saturates the input instead of trapping. NaN values are converted to 0. 3838 "#, 3839 &formats.unary, 3840 ) 3841 .operands_in(vec![x]) 3842 .operands_out(vec![a]), 3843 ); 3844 3845 let x = &Operand::new("x", Int); 3846 let a = &Operand::new("a", FloatTo); 3847 3848 ig.push( 3849 Inst::new( 3850 "fcvt_from_uint", 3851 r#" 3852 Convert unsigned integer to floating point. 3853 3854 Each lane in `x` is interpreted as an unsigned integer and converted to 3855 floating point using round to nearest, ties to even. 3856 3857 The result type must have the same number of vector lanes as the input. 3858 "#, 3859 &formats.unary, 3860 ) 3861 .operands_in(vec![x]) 3862 .operands_out(vec![a]), 3863 ); 3864 3865 ig.push( 3866 Inst::new( 3867 "fcvt_from_sint", 3868 r#" 3869 Convert signed integer to floating point. 3870 3871 Each lane in `x` is interpreted as a signed integer and converted to 3872 floating point using round to nearest, ties to even. 3873 3874 The result type must have the same number of vector lanes as the input. 3875 "#, 3876 &formats.unary, 3877 ) 3878 .operands_in(vec![x]) 3879 .operands_out(vec![a]), 3880 ); 3881 3882 ig.push( 3883 Inst::new( 3884 "fcvt_low_from_sint", 3885 r#" 3886 Converts packed signed 32-bit integers to packed double precision floating point. 3887 3888 Considering only the low half of the register, each lane in `x` is interpreted as a 3889 signed 32-bit integer that is then converted to a double precision float. This 3890 instruction differs from fcvt_from_sint in that it converts half the number of lanes 3891 which are converted to occupy twice the number of bits. No rounding should be needed 3892 for the resulting float. 3893 3894 The result type will have half the number of vector lanes as the input. 3895 "#, 3896 &formats.unary, 3897 ) 3898 .operands_in(vec![x]) 3899 .operands_out(vec![a]), 3900 ); 3901 3902 let WideInt = &TypeVar::new( 3903 "WideInt", 3904 "An integer type with lanes from `i16` upwards", 3905 TypeSetBuilder::new() 3906 .ints(16..128) 3907 .simd_lanes(Interval::All) 3908 .build(), 3909 ); 3910 let x = &Operand::new("x", WideInt); 3911 let lo = &Operand::new("lo", &WideInt.half_width()).with_doc("The low bits of `x`"); 3912 let hi = &Operand::new("hi", &WideInt.half_width()).with_doc("The high bits of `x`"); 3913 3914 ig.push( 3915 Inst::new( 3916 "isplit", 3917 r#" 3918 Split an integer into low and high parts. 3919 3920 Vectors of integers are split lane-wise, so the results have the same 3921 number of lanes as the input, but the lanes are half the size. 3922 3923 Returns the low half of `x` and the high half of `x` as two independent 3924 values. 3925 "#, 3926 &formats.unary, 3927 ) 3928 .operands_in(vec![x]) 3929 .operands_out(vec![lo, hi]), 3930 ); 3931 3932 let NarrowInt = &TypeVar::new( 3933 "NarrowInt", 3934 "An integer type with lanes type to `i64`", 3935 TypeSetBuilder::new() 3936 .ints(8..64) 3937 .simd_lanes(Interval::All) 3938 .build(), 3939 ); 3940 3941 let lo = &Operand::new("lo", NarrowInt); 3942 let hi = &Operand::new("hi", NarrowInt); 3943 let a = &Operand::new("a", &NarrowInt.double_width()) 3944 .with_doc("The concatenation of `lo` and `hi`"); 3945 3946 ig.push( 3947 Inst::new( 3948 "iconcat", 3949 r#" 3950 Concatenate low and high bits to form a larger integer type. 3951 3952 Vectors of integers are concatenated lane-wise such that the result has 3953 the same number of lanes as the inputs, but the lanes are twice the 3954 size. 3955 "#, 3956 &formats.binary, 3957 ) 3958 .operands_in(vec![lo, hi]) 3959 .operands_out(vec![a]), 3960 ); 3961 3962 // Instructions relating to atomic memory accesses and fences 3963 let AtomicMem = &TypeVar::new( 3964 "AtomicMem", 3965 "Any type that can be stored in memory, which can be used in an atomic operation", 3966 TypeSetBuilder::new().ints(8..64).build(), 3967 ); 3968 let x = &Operand::new("x", AtomicMem).with_doc("Value to be atomically stored"); 3969 let a = &Operand::new("a", AtomicMem).with_doc("Value atomically loaded"); 3970 let e = &Operand::new("e", AtomicMem).with_doc("Expected value in CAS"); 3971 let p = &Operand::new("p", iAddr); 3972 let MemFlags = &Operand::new("MemFlags", &imm.memflags); 3973 let AtomicRmwOp = &Operand::new("AtomicRmwOp", &imm.atomic_rmw_op); 3974 3975 ig.push( 3976 Inst::new( 3977 "atomic_rmw", 3978 r#" 3979 Atomically read-modify-write memory at `p`, with second operand `x`. The old value is 3980 returned. `p` has the type of the target word size, and `x` may be an integer type of 3981 8, 16, 32 or 64 bits, even on a 32-bit target. The type of the returned value is the 3982 same as the type of `x`. This operation is sequentially consistent and creates 3983 happens-before edges that order normal (non-atomic) loads and stores. 3984 "#, 3985 &formats.atomic_rmw, 3986 ) 3987 .operands_in(vec![MemFlags, AtomicRmwOp, p, x]) 3988 .operands_out(vec![a]) 3989 .can_load(true) 3990 .can_store(true) 3991 .other_side_effects(true), 3992 ); 3993 3994 ig.push( 3995 Inst::new( 3996 "atomic_cas", 3997 r#" 3998 Perform an atomic compare-and-swap operation on memory at `p`, with expected value `e`, 3999 storing `x` if the value at `p` equals `e`. The old value at `p` is returned, 4000 regardless of whether the operation succeeds or fails. `p` has the type of the target 4001 word size, and `x` and `e` must have the same type and the same size, which may be an 4002 integer type of 8, 16, 32 or 64 bits, even on a 32-bit target. The type of the returned 4003 value is the same as the type of `x` and `e`. This operation is sequentially 4004 consistent and creates happens-before edges that order normal (non-atomic) loads and 4005 stores. 4006 "#, 4007 &formats.atomic_cas, 4008 ) 4009 .operands_in(vec![MemFlags, p, e, x]) 4010 .operands_out(vec![a]) 4011 .can_load(true) 4012 .can_store(true) 4013 .other_side_effects(true), 4014 ); 4015 4016 ig.push( 4017 Inst::new( 4018 "atomic_load", 4019 r#" 4020 Atomically load from memory at `p`. 4021 4022 This is a polymorphic instruction that can load any value type which has a memory 4023 representation. It should only be used for integer types with 8, 16, 32 or 64 bits. 4024 This operation is sequentially consistent and creates happens-before edges that order 4025 normal (non-atomic) loads and stores. 4026 "#, 4027 &formats.load_no_offset, 4028 ) 4029 .operands_in(vec![MemFlags, p]) 4030 .operands_out(vec![a]) 4031 .can_load(true) 4032 .other_side_effects(true), 4033 ); 4034 4035 ig.push( 4036 Inst::new( 4037 "atomic_store", 4038 r#" 4039 Atomically store `x` to memory at `p`. 4040 4041 This is a polymorphic instruction that can store any value type with a memory 4042 representation. It should only be used for integer types with 8, 16, 32 or 64 bits. 4043 This operation is sequentially consistent and creates happens-before edges that order 4044 normal (non-atomic) loads and stores. 4045 "#, 4046 &formats.store_no_offset, 4047 ) 4048 .operands_in(vec![MemFlags, x, p]) 4049 .can_store(true) 4050 .other_side_effects(true), 4051 ); 4052 4053 ig.push( 4054 Inst::new( 4055 "fence", 4056 r#" 4057 A memory fence. This must provide ordering to ensure that, at a minimum, neither loads 4058 nor stores of any kind may move forwards or backwards across the fence. This operation 4059 is sequentially consistent. 4060 "#, 4061 &formats.nullary, 4062 ) 4063 .other_side_effects(true), 4064 ); 4065 } 4066