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