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