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 using the WebAssembly rules. 3601 3602 If either operand is NaN, this returns NaN with an unspecified sign. Furthermore, if 3603 each input NaN consists of a mantissa whose most significant bit is 1 and the rest is 3604 0, then the output has the same form. Otherwise, the output mantissa's most significant 3605 bit is 1 and the rest is unspecified. 3606 "#, 3607 &formats.binary, 3608 ) 3609 .operands_in(vec![x, y]) 3610 .operands_out(vec![a]), 3611 ); 3612 3613 ig.push( 3614 Inst::new( 3615 "fmin_pseudo", 3616 r#" 3617 Floating point pseudo-minimum, propagating NaNs. This behaves differently from ``fmin``. 3618 See <https://github.com/WebAssembly/simd/pull/122> for background. 3619 3620 The behaviour is defined as ``fmin_pseudo(a, b) = (b < a) ? b : a``, and the behaviour 3621 for zero or NaN inputs follows from the behaviour of ``<`` with such inputs. 3622 "#, 3623 &formats.binary, 3624 ) 3625 .operands_in(vec![x, y]) 3626 .operands_out(vec![a]), 3627 ); 3628 3629 let a = &Operand::new("a", Float).with_doc("The larger of ``x`` and ``y``"); 3630 3631 ig.push( 3632 Inst::new( 3633 "fmax", 3634 r#" 3635 Floating point maximum, propagating NaNs using the WebAssembly rules. 3636 3637 If either operand is NaN, this returns NaN with an unspecified sign. Furthermore, if 3638 each input NaN consists of a mantissa whose most significant bit is 1 and the rest is 3639 0, then the output has the same form. Otherwise, the output mantissa's most significant 3640 bit is 1 and the rest is unspecified. 3641 "#, 3642 &formats.binary, 3643 ) 3644 .operands_in(vec![x, y]) 3645 .operands_out(vec![a]), 3646 ); 3647 3648 ig.push( 3649 Inst::new( 3650 "fmax_pseudo", 3651 r#" 3652 Floating point pseudo-maximum, propagating NaNs. This behaves differently from ``fmax``. 3653 See <https://github.com/WebAssembly/simd/pull/122> for background. 3654 3655 The behaviour is defined as ``fmax_pseudo(a, b) = (a < b) ? b : a``, and the behaviour 3656 for zero or NaN inputs follows from the behaviour of ``<`` with such inputs. 3657 "#, 3658 &formats.binary, 3659 ) 3660 .operands_in(vec![x, y]) 3661 .operands_out(vec![a]), 3662 ); 3663 3664 let a = &Operand::new("a", Float).with_doc("``x`` rounded to integral value"); 3665 3666 ig.push( 3667 Inst::new( 3668 "ceil", 3669 r#" 3670 Round floating point round to integral, towards positive infinity. 3671 "#, 3672 &formats.unary, 3673 ) 3674 .operands_in(vec![x]) 3675 .operands_out(vec![a]), 3676 ); 3677 3678 ig.push( 3679 Inst::new( 3680 "floor", 3681 r#" 3682 Round floating point round to integral, towards negative infinity. 3683 "#, 3684 &formats.unary, 3685 ) 3686 .operands_in(vec![x]) 3687 .operands_out(vec![a]), 3688 ); 3689 3690 ig.push( 3691 Inst::new( 3692 "trunc", 3693 r#" 3694 Round floating point round to integral, towards zero. 3695 "#, 3696 &formats.unary, 3697 ) 3698 .operands_in(vec![x]) 3699 .operands_out(vec![a]), 3700 ); 3701 3702 ig.push( 3703 Inst::new( 3704 "nearest", 3705 r#" 3706 Round floating point round to integral, towards nearest with ties to 3707 even. 3708 "#, 3709 &formats.unary, 3710 ) 3711 .operands_in(vec![x]) 3712 .operands_out(vec![a]), 3713 ); 3714 3715 let a = &Operand::new("a", b1); 3716 let x = &Operand::new("x", Ref); 3717 3718 ig.push( 3719 Inst::new( 3720 "is_null", 3721 r#" 3722 Reference verification. 3723 3724 The condition code determines if the reference type in question is 3725 null or not. 3726 "#, 3727 &formats.unary, 3728 ) 3729 .operands_in(vec![x]) 3730 .operands_out(vec![a]), 3731 ); 3732 3733 let a = &Operand::new("a", b1); 3734 let x = &Operand::new("x", Ref); 3735 3736 ig.push( 3737 Inst::new( 3738 "is_invalid", 3739 r#" 3740 Reference verification. 3741 3742 The condition code determines if the reference type in question is 3743 invalid or not. 3744 "#, 3745 &formats.unary, 3746 ) 3747 .operands_in(vec![x]) 3748 .operands_out(vec![a]), 3749 ); 3750 3751 let Cond = &Operand::new("Cond", &imm.intcc); 3752 let f = &Operand::new("f", iflags); 3753 let a = &Operand::new("a", b1); 3754 3755 ig.push( 3756 Inst::new( 3757 "trueif", 3758 r#" 3759 Test integer CPU flags for a specific condition. 3760 3761 Check the CPU flags in ``f`` against the ``Cond`` condition code and 3762 return true when the condition code is satisfied. 3763 "#, 3764 &formats.int_cond, 3765 ) 3766 .operands_in(vec![Cond, f]) 3767 .operands_out(vec![a]), 3768 ); 3769 3770 let Cond = &Operand::new("Cond", &imm.floatcc); 3771 let f = &Operand::new("f", fflags); 3772 3773 ig.push( 3774 Inst::new( 3775 "trueff", 3776 r#" 3777 Test floating point CPU flags for a specific condition. 3778 3779 Check the CPU flags in ``f`` against the ``Cond`` condition code and 3780 return true when the condition code is satisfied. 3781 "#, 3782 &formats.float_cond, 3783 ) 3784 .operands_in(vec![Cond, f]) 3785 .operands_out(vec![a]), 3786 ); 3787 3788 let x = &Operand::new("x", Mem); 3789 let a = &Operand::new("a", MemTo).with_doc("Bits of `x` reinterpreted"); 3790 3791 ig.push( 3792 Inst::new( 3793 "bitcast", 3794 r#" 3795 Reinterpret the bits in `x` as a different type. 3796 3797 The input and output types must be storable to memory and of the same 3798 size. A bitcast is equivalent to storing one type and loading the other 3799 type from the same address. 3800 "#, 3801 &formats.unary, 3802 ) 3803 .operands_in(vec![x]) 3804 .operands_out(vec![a]), 3805 ); 3806 3807 let x = &Operand::new("x", Any); 3808 let a = &Operand::new("a", AnyTo).with_doc("Bits of `x` reinterpreted"); 3809 3810 ig.push( 3811 Inst::new( 3812 "raw_bitcast", 3813 r#" 3814 Cast the bits in `x` as a different type of the same bit width. 3815 3816 This instruction does not change the data's representation but allows 3817 data in registers to be used as different types, e.g. an i32x4 as a 3818 b8x16. The only constraint on the result `a` is that it can be 3819 `raw_bitcast` back to the original type. Also, in a raw_bitcast between 3820 vector types with the same number of lanes, the value of each result 3821 lane is a raw_bitcast of the corresponding operand lane. TODO there is 3822 currently no mechanism for enforcing the bit width constraint. 3823 "#, 3824 &formats.unary, 3825 ) 3826 .operands_in(vec![x]) 3827 .operands_out(vec![a]), 3828 ); 3829 3830 let a = &Operand::new("a", TxN).with_doc("A vector value"); 3831 let s = &Operand::new("s", &TxN.lane_of()).with_doc("A scalar value"); 3832 3833 ig.push( 3834 Inst::new( 3835 "scalar_to_vector", 3836 r#" 3837 Copies a scalar value to a vector value. The scalar is copied into the 3838 least significant lane of the vector, and all other lanes will be zero. 3839 "#, 3840 &formats.unary, 3841 ) 3842 .operands_in(vec![s]) 3843 .operands_out(vec![a]), 3844 ); 3845 3846 let Bool = &TypeVar::new( 3847 "Bool", 3848 "A scalar or vector boolean type", 3849 TypeSetBuilder::new() 3850 .bools(Interval::All) 3851 .simd_lanes(Interval::All) 3852 .build(), 3853 ); 3854 3855 let BoolTo = &TypeVar::new( 3856 "BoolTo", 3857 "A smaller boolean type with the same number of lanes", 3858 TypeSetBuilder::new() 3859 .bools(Interval::All) 3860 .simd_lanes(Interval::All) 3861 .build(), 3862 ); 3863 3864 let x = &Operand::new("x", Bool); 3865 let a = &Operand::new("a", BoolTo); 3866 3867 ig.push( 3868 Inst::new( 3869 "breduce", 3870 r#" 3871 Convert `x` to a smaller boolean type in the platform-defined way. 3872 3873 The result type must have the same number of vector lanes as the input, 3874 and each lane must not have more bits that the input lanes. If the 3875 input and output types are the same, this is a no-op. 3876 "#, 3877 &formats.unary, 3878 ) 3879 .operands_in(vec![x]) 3880 .operands_out(vec![a]) 3881 .constraints(vec![WiderOrEq(Bool.clone(), BoolTo.clone())]), 3882 ); 3883 3884 let BoolTo = &TypeVar::new( 3885 "BoolTo", 3886 "A larger boolean type with the same number of lanes", 3887 TypeSetBuilder::new() 3888 .bools(Interval::All) 3889 .simd_lanes(Interval::All) 3890 .build(), 3891 ); 3892 let x = &Operand::new("x", Bool); 3893 let a = &Operand::new("a", BoolTo); 3894 3895 ig.push( 3896 Inst::new( 3897 "bextend", 3898 r#" 3899 Convert `x` to a larger boolean type in the platform-defined way. 3900 3901 The result type must have the same number of vector lanes as the input, 3902 and each lane must not have fewer bits that the input lanes. If the 3903 input and output types are the same, this is a no-op. 3904 "#, 3905 &formats.unary, 3906 ) 3907 .operands_in(vec![x]) 3908 .operands_out(vec![a]) 3909 .constraints(vec![WiderOrEq(BoolTo.clone(), Bool.clone())]), 3910 ); 3911 3912 let IntTo = &TypeVar::new( 3913 "IntTo", 3914 "An integer type with the same number of lanes", 3915 TypeSetBuilder::new() 3916 .ints(Interval::All) 3917 .simd_lanes(Interval::All) 3918 .build(), 3919 ); 3920 let x = &Operand::new("x", Bool); 3921 let a = &Operand::new("a", IntTo); 3922 3923 ig.push( 3924 Inst::new( 3925 "bint", 3926 r#" 3927 Convert `x` to an integer. 3928 3929 True maps to 1 and false maps to 0. The result type must have the same 3930 number of vector lanes as the input. 3931 "#, 3932 &formats.unary, 3933 ) 3934 .operands_in(vec![x]) 3935 .operands_out(vec![a]), 3936 ); 3937 3938 ig.push( 3939 Inst::new( 3940 "bmask", 3941 r#" 3942 Convert `x` to an integer mask. 3943 3944 True maps to all 1s and false maps to all 0s. The result type must have 3945 the same number of vector lanes as the input. 3946 "#, 3947 &formats.unary, 3948 ) 3949 .operands_in(vec![x]) 3950 .operands_out(vec![a]), 3951 ); 3952 3953 let Int = &TypeVar::new( 3954 "Int", 3955 "A scalar or vector integer type", 3956 TypeSetBuilder::new() 3957 .ints(Interval::All) 3958 .simd_lanes(Interval::All) 3959 .build(), 3960 ); 3961 3962 let IntTo = &TypeVar::new( 3963 "IntTo", 3964 "A smaller integer type with the same number of lanes", 3965 TypeSetBuilder::new() 3966 .ints(Interval::All) 3967 .simd_lanes(Interval::All) 3968 .build(), 3969 ); 3970 let x = &Operand::new("x", Int); 3971 let a = &Operand::new("a", IntTo); 3972 3973 ig.push( 3974 Inst::new( 3975 "ireduce", 3976 r#" 3977 Convert `x` to a smaller integer type by dropping high bits. 3978 3979 Each lane in `x` is converted to a smaller integer type by discarding 3980 the most significant bits. This is the same as reducing modulo 3981 `2^n`. 3982 3983 The result type must have the same number of vector lanes as the input, 3984 and each lane must not have more bits that the input lanes. If the 3985 input and output types are the same, this is a no-op. 3986 "#, 3987 &formats.unary, 3988 ) 3989 .operands_in(vec![x]) 3990 .operands_out(vec![a]) 3991 .constraints(vec![WiderOrEq(Int.clone(), IntTo.clone())]), 3992 ); 3993 3994 let I16or32or64xN = &TypeVar::new( 3995 "I16or32or64xN", 3996 "A SIMD vector type containing integer lanes 16, 32, or 64 bits wide", 3997 TypeSetBuilder::new() 3998 .ints(16..64) 3999 .simd_lanes(2..8) 4000 .includes_scalars(false) 4001 .build(), 4002 ); 4003 4004 let x = &Operand::new("x", I16or32or64xN); 4005 let y = &Operand::new("y", I16or32or64xN); 4006 let a = &Operand::new("a", &I16or32or64xN.split_lanes()); 4007 4008 ig.push( 4009 Inst::new( 4010 "snarrow", 4011 r#" 4012 Combine `x` and `y` into a vector with twice the lanes but half the integer width while 4013 saturating overflowing values to the signed maximum and minimum. 4014 4015 The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4` 4016 and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value 4017 returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`. 4018 "#, 4019 &formats.binary, 4020 ) 4021 .operands_in(vec![x, y]) 4022 .operands_out(vec![a]), 4023 ); 4024 4025 ig.push( 4026 Inst::new( 4027 "unarrow", 4028 r#" 4029 Combine `x` and `y` into a vector with twice the lanes but half the integer width while 4030 saturating overflowing values to the unsigned maximum and minimum. 4031 4032 Note that all input lanes are considered signed: any negative lanes will overflow and be 4033 replaced with the unsigned minimum, `0x00`. 4034 4035 The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4` 4036 and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value 4037 returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`. 4038 "#, 4039 &formats.binary, 4040 ) 4041 .operands_in(vec![x, y]) 4042 .operands_out(vec![a]), 4043 ); 4044 4045 ig.push( 4046 Inst::new( 4047 "uunarrow", 4048 r#" 4049 Combine `x` and `y` into a vector with twice the lanes but half the integer width while 4050 saturating overflowing values to the unsigned maximum and minimum. 4051 4052 Note that all input lanes are considered unsigned. 4053 4054 The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4` 4055 and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value 4056 returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`. 4057 "#, 4058 &formats.binary, 4059 ) 4060 .operands_in(vec![x, y]) 4061 .operands_out(vec![a]), 4062 ); 4063 4064 let I8or16or32xN = &TypeVar::new( 4065 "I8or16or32xN", 4066 "A SIMD vector type containing integer lanes 8, 16, or 32 bits wide.", 4067 TypeSetBuilder::new() 4068 .ints(8..32) 4069 .simd_lanes(4..16) 4070 .includes_scalars(false) 4071 .build(), 4072 ); 4073 4074 let x = &Operand::new("x", I8or16or32xN); 4075 let a = &Operand::new("a", &I8or16or32xN.merge_lanes()); 4076 4077 ig.push( 4078 Inst::new( 4079 "swiden_low", 4080 r#" 4081 Widen the low lanes of `x` using signed extension. 4082 4083 This will double the lane width and halve the number of lanes. 4084 "#, 4085 &formats.unary, 4086 ) 4087 .operands_in(vec![x]) 4088 .operands_out(vec![a]), 4089 ); 4090 4091 ig.push( 4092 Inst::new( 4093 "swiden_high", 4094 r#" 4095 Widen the high lanes of `x` using signed extension. 4096 4097 This will double the lane width and halve the number of lanes. 4098 "#, 4099 &formats.unary, 4100 ) 4101 .operands_in(vec![x]) 4102 .operands_out(vec![a]), 4103 ); 4104 4105 ig.push( 4106 Inst::new( 4107 "uwiden_low", 4108 r#" 4109 Widen the low lanes of `x` using unsigned extension. 4110 4111 This will double the lane width and halve the number of lanes. 4112 "#, 4113 &formats.unary, 4114 ) 4115 .operands_in(vec![x]) 4116 .operands_out(vec![a]), 4117 ); 4118 4119 ig.push( 4120 Inst::new( 4121 "uwiden_high", 4122 r#" 4123 Widen the high lanes of `x` using unsigned extension. 4124 4125 This will double the lane width and halve the number of lanes. 4126 "#, 4127 &formats.unary, 4128 ) 4129 .operands_in(vec![x]) 4130 .operands_out(vec![a]), 4131 ); 4132 4133 let x = &Operand::new("x", I8or16or32xN); 4134 let y = &Operand::new("y", I8or16or32xN); 4135 let a = &Operand::new("a", I8or16or32xN); 4136 4137 ig.push( 4138 Inst::new( 4139 "iadd_pairwise", 4140 r#" 4141 Does lane-wise integer pairwise addition on two operands, putting the 4142 combined results into a single vector result. Here a pair refers to adjacent 4143 lanes in a vector, i.e. i*2 + (i*2+1) for i == num_lanes/2. The first operand 4144 pairwise add results will make up the low half of the resulting vector while 4145 the second operand pairwise add results will make up the upper half of the 4146 resulting vector. 4147 "#, 4148 &formats.binary, 4149 ) 4150 .operands_in(vec![x, y]) 4151 .operands_out(vec![a]), 4152 ); 4153 4154 let I16x8 = &TypeVar::new( 4155 "I16x8", 4156 "A SIMD vector type containing 8 integer lanes each 16 bits wide.", 4157 TypeSetBuilder::new() 4158 .ints(16..16) 4159 .simd_lanes(8..8) 4160 .includes_scalars(false) 4161 .build(), 4162 ); 4163 4164 let x = &Operand::new("x", I16x8); 4165 let y = &Operand::new("y", I16x8); 4166 let a = &Operand::new("a", &I16x8.merge_lanes()); 4167 4168 ig.push( 4169 Inst::new( 4170 "widening_pairwise_dot_product_s", 4171 r#" 4172 Takes corresponding elements in `x` and `y`, performs a sign-extending length-doubling 4173 multiplication on them, then adds adjacent pairs of elements to form the result. For 4174 example, if the input vectors are `[x3, x2, x1, x0]` and `[y3, y2, y1, y0]`, it produces 4175 the vector `[r1, r0]`, where `r1 = sx(x3) * sx(y3) + sx(x2) * sx(y2)` and 4176 `r0 = sx(x1) * sx(y1) + sx(x0) * sx(y0)`, and `sx(n)` sign-extends `n` to twice its width. 4177 4178 This will double the lane width and halve the number of lanes. So the resulting 4179 vector has the same number of bits as `x` and `y` do (individually). 4180 4181 See <https://github.com/WebAssembly/simd/pull/127> for background info. 4182 "#, 4183 &formats.binary, 4184 ) 4185 .operands_in(vec![x, y]) 4186 .operands_out(vec![a]), 4187 ); 4188 4189 let IntTo = &TypeVar::new( 4190 "IntTo", 4191 "A larger integer type with the same number of lanes", 4192 TypeSetBuilder::new() 4193 .ints(Interval::All) 4194 .simd_lanes(Interval::All) 4195 .build(), 4196 ); 4197 let x = &Operand::new("x", Int); 4198 let a = &Operand::new("a", IntTo); 4199 4200 ig.push( 4201 Inst::new( 4202 "uextend", 4203 r#" 4204 Convert `x` to a larger integer type by zero-extending. 4205 4206 Each lane in `x` is converted to a larger integer type by adding 4207 zeroes. The result has the same numerical value as `x` when both are 4208 interpreted as unsigned integers. 4209 4210 The result type must have the same number of vector lanes as the input, 4211 and each lane must not have fewer bits that the input lanes. If the 4212 input and output types are the same, this is a no-op. 4213 "#, 4214 &formats.unary, 4215 ) 4216 .operands_in(vec![x]) 4217 .operands_out(vec![a]) 4218 .constraints(vec![WiderOrEq(IntTo.clone(), Int.clone())]), 4219 ); 4220 4221 ig.push( 4222 Inst::new( 4223 "sextend", 4224 r#" 4225 Convert `x` to a larger integer type by sign-extending. 4226 4227 Each lane in `x` is converted to a larger integer type by replicating 4228 the sign bit. The result has the same numerical value as `x` when both 4229 are interpreted as signed integers. 4230 4231 The result type must have the same number of vector lanes as the input, 4232 and each lane must not have fewer bits that the input lanes. If the 4233 input and output types are the same, this is a no-op. 4234 "#, 4235 &formats.unary, 4236 ) 4237 .operands_in(vec![x]) 4238 .operands_out(vec![a]) 4239 .constraints(vec![WiderOrEq(IntTo.clone(), Int.clone())]), 4240 ); 4241 4242 let FloatTo = &TypeVar::new( 4243 "FloatTo", 4244 "A scalar or vector floating point number", 4245 TypeSetBuilder::new() 4246 .floats(Interval::All) 4247 .simd_lanes(Interval::All) 4248 .build(), 4249 ); 4250 let x = &Operand::new("x", Float); 4251 let a = &Operand::new("a", FloatTo); 4252 4253 ig.push( 4254 Inst::new( 4255 "fpromote", 4256 r#" 4257 Convert `x` to a larger floating point format. 4258 4259 Each lane in `x` is converted to the destination floating point format. 4260 This is an exact operation. 4261 4262 Cranelift currently only supports two floating point formats 4263 - `f32` and `f64`. This may change in the future. 4264 4265 The result type must have the same number of vector lanes as the input, 4266 and the result lanes must not have fewer bits than the input lanes. If 4267 the input and output types are the same, this is a no-op. 4268 "#, 4269 &formats.unary, 4270 ) 4271 .operands_in(vec![x]) 4272 .operands_out(vec![a]) 4273 .constraints(vec![WiderOrEq(FloatTo.clone(), Float.clone())]), 4274 ); 4275 4276 ig.push( 4277 Inst::new( 4278 "fdemote", 4279 r#" 4280 Convert `x` to a smaller floating point format. 4281 4282 Each lane in `x` is converted to the destination floating point format 4283 by rounding to nearest, ties to even. 4284 4285 Cranelift currently only supports two floating point formats 4286 - `f32` and `f64`. This may change in the future. 4287 4288 The result type must have the same number of vector lanes as the input, 4289 and the result lanes must not have more bits than the input lanes. If 4290 the input and output types are the same, this is a no-op. 4291 "#, 4292 &formats.unary, 4293 ) 4294 .operands_in(vec![x]) 4295 .operands_out(vec![a]) 4296 .constraints(vec![WiderOrEq(Float.clone(), FloatTo.clone())]), 4297 ); 4298 4299 let F64x2 = &TypeVar::new( 4300 "F64x2", 4301 "A SIMD vector type consisting of 2 lanes of 64-bit floats", 4302 TypeSetBuilder::new() 4303 .floats(64..64) 4304 .simd_lanes(2..2) 4305 .includes_scalars(false) 4306 .build(), 4307 ); 4308 let F32x4 = &TypeVar::new( 4309 "F32x4", 4310 "A SIMD vector type consisting of 4 lanes of 32-bit floats", 4311 TypeSetBuilder::new() 4312 .floats(32..32) 4313 .simd_lanes(4..4) 4314 .includes_scalars(false) 4315 .build(), 4316 ); 4317 4318 let x = &Operand::new("x", F64x2); 4319 let a = &Operand::new("a", F32x4); 4320 4321 ig.push( 4322 Inst::new( 4323 "fvdemote", 4324 r#" 4325 Convert `x` to a smaller floating point format. 4326 4327 Each lane in `x` is converted to the destination floating point format 4328 by rounding to nearest, ties to even. 4329 4330 Cranelift currently only supports two floating point formats 4331 - `f32` and `f64`. This may change in the future. 4332 4333 Fvdemote differs from fdemote in that with fvdemote it targets vectors. 4334 Fvdemote is constrained to having the input type being F64x2 and the result 4335 type being F32x4. The result lane that was the upper half of the input lane 4336 is initialized to zero. 4337 "#, 4338 &formats.unary, 4339 ) 4340 .operands_in(vec![x]) 4341 .operands_out(vec![a]), 4342 ); 4343 4344 ig.push( 4345 Inst::new( 4346 "fvpromote_low", 4347 r#" 4348 Converts packed single precision floating point to packed double precision floating point. 4349 4350 Considering only the lower half of the register, the low lanes in `x` are interpreted as 4351 single precision floats that are then converted to a double precision floats. 4352 4353 The result type will have half the number of vector lanes as the input. Fvpromote_low is 4354 constrained to input F32x4 with a result type of F64x2. 4355 "#, 4356 &formats.unary, 4357 ) 4358 .operands_in(vec![a]) 4359 .operands_out(vec![x]), 4360 ); 4361 4362 let x = &Operand::new("x", Float); 4363 let a = &Operand::new("a", IntTo); 4364 4365 ig.push( 4366 Inst::new( 4367 "fcvt_to_uint", 4368 r#" 4369 Convert floating point to unsigned integer. 4370 4371 Each lane in `x` is converted to an unsigned integer by rounding 4372 towards zero. If `x` is NaN or if the unsigned integral value cannot be 4373 represented in the result type, this instruction traps. 4374 4375 The result type must have the same number of vector lanes as the input. 4376 "#, 4377 &formats.unary, 4378 ) 4379 .operands_in(vec![x]) 4380 .operands_out(vec![a]) 4381 .can_trap(true), 4382 ); 4383 4384 ig.push( 4385 Inst::new( 4386 "fcvt_to_uint_sat", 4387 r#" 4388 Convert floating point to unsigned integer as fcvt_to_uint does, but 4389 saturates the input instead of trapping. NaN and negative values are 4390 converted to 0. 4391 "#, 4392 &formats.unary, 4393 ) 4394 .operands_in(vec![x]) 4395 .operands_out(vec![a]), 4396 ); 4397 4398 ig.push( 4399 Inst::new( 4400 "fcvt_to_sint", 4401 r#" 4402 Convert floating point to signed integer. 4403 4404 Each lane in `x` is converted to a signed integer by rounding towards 4405 zero. If `x` is NaN or if the signed integral value cannot be 4406 represented in the result type, this instruction traps. 4407 4408 The result type must have the same number of vector lanes as the input. 4409 "#, 4410 &formats.unary, 4411 ) 4412 .operands_in(vec![x]) 4413 .operands_out(vec![a]) 4414 .can_trap(true), 4415 ); 4416 4417 ig.push( 4418 Inst::new( 4419 "fcvt_to_sint_sat", 4420 r#" 4421 Convert floating point to signed integer as fcvt_to_sint does, but 4422 saturates the input instead of trapping. NaN values are converted to 0. 4423 "#, 4424 &formats.unary, 4425 ) 4426 .operands_in(vec![x]) 4427 .operands_out(vec![a]), 4428 ); 4429 4430 let x = &Operand::new("x", Int); 4431 let a = &Operand::new("a", FloatTo); 4432 4433 ig.push( 4434 Inst::new( 4435 "fcvt_from_uint", 4436 r#" 4437 Convert unsigned integer to floating point. 4438 4439 Each lane in `x` is interpreted as an unsigned integer and converted to 4440 floating point using round to nearest, ties to even. 4441 4442 The result type must have the same number of vector lanes as the input. 4443 "#, 4444 &formats.unary, 4445 ) 4446 .operands_in(vec![x]) 4447 .operands_out(vec![a]), 4448 ); 4449 4450 ig.push( 4451 Inst::new( 4452 "fcvt_from_sint", 4453 r#" 4454 Convert signed integer to floating point. 4455 4456 Each lane in `x` is interpreted as a signed integer and converted to 4457 floating point using round to nearest, ties to even. 4458 4459 The result type must have the same number of vector lanes as the input. 4460 "#, 4461 &formats.unary, 4462 ) 4463 .operands_in(vec![x]) 4464 .operands_out(vec![a]), 4465 ); 4466 4467 ig.push( 4468 Inst::new( 4469 "fcvt_low_from_sint", 4470 r#" 4471 Converts packed signed 32-bit integers to packed double precision floating point. 4472 4473 Considering only the low half of the register, each lane in `x` is interpreted as a 4474 signed 32-bit integer that is then converted to a double precision float. This 4475 instruction differs from fcvt_from_sint in that it converts half the number of lanes 4476 which are converted to occupy twice the number of bits. No rounding should be needed 4477 for the resulting float. 4478 4479 The result type will have half the number of vector lanes as the input. 4480 "#, 4481 &formats.unary, 4482 ) 4483 .operands_in(vec![x]) 4484 .operands_out(vec![a]), 4485 ); 4486 4487 let WideInt = &TypeVar::new( 4488 "WideInt", 4489 "An integer type with lanes from `i16` upwards", 4490 TypeSetBuilder::new() 4491 .ints(16..128) 4492 .simd_lanes(Interval::All) 4493 .build(), 4494 ); 4495 let x = &Operand::new("x", WideInt); 4496 let lo = &Operand::new("lo", &WideInt.half_width()).with_doc("The low bits of `x`"); 4497 let hi = &Operand::new("hi", &WideInt.half_width()).with_doc("The high bits of `x`"); 4498 4499 ig.push( 4500 Inst::new( 4501 "isplit", 4502 r#" 4503 Split an integer into low and high parts. 4504 4505 Vectors of integers are split lane-wise, so the results have the same 4506 number of lanes as the input, but the lanes are half the size. 4507 4508 Returns the low half of `x` and the high half of `x` as two independent 4509 values. 4510 "#, 4511 &formats.unary, 4512 ) 4513 .operands_in(vec![x]) 4514 .operands_out(vec![lo, hi]) 4515 .is_ghost(true), 4516 ); 4517 4518 let NarrowInt = &TypeVar::new( 4519 "NarrowInt", 4520 "An integer type with lanes type to `i64`", 4521 TypeSetBuilder::new() 4522 .ints(8..64) 4523 .simd_lanes(Interval::All) 4524 .build(), 4525 ); 4526 4527 let lo = &Operand::new("lo", NarrowInt); 4528 let hi = &Operand::new("hi", NarrowInt); 4529 let a = &Operand::new("a", &NarrowInt.double_width()) 4530 .with_doc("The concatenation of `lo` and `hi`"); 4531 4532 ig.push( 4533 Inst::new( 4534 "iconcat", 4535 r#" 4536 Concatenate low and high bits to form a larger integer type. 4537 4538 Vectors of integers are concatenated lane-wise such that the result has 4539 the same number of lanes as the inputs, but the lanes are twice the 4540 size. 4541 "#, 4542 &formats.binary, 4543 ) 4544 .operands_in(vec![lo, hi]) 4545 .operands_out(vec![a]) 4546 .is_ghost(true), 4547 ); 4548 4549 // Instructions relating to atomic memory accesses and fences 4550 let AtomicMem = &TypeVar::new( 4551 "AtomicMem", 4552 "Any type that can be stored in memory, which can be used in an atomic operation", 4553 TypeSetBuilder::new().ints(8..64).build(), 4554 ); 4555 let x = &Operand::new("x", AtomicMem).with_doc("Value to be atomically stored"); 4556 let a = &Operand::new("a", AtomicMem).with_doc("Value atomically loaded"); 4557 let e = &Operand::new("e", AtomicMem).with_doc("Expected value in CAS"); 4558 let p = &Operand::new("p", iAddr); 4559 let MemFlags = &Operand::new("MemFlags", &imm.memflags); 4560 let AtomicRmwOp = &Operand::new("AtomicRmwOp", &imm.atomic_rmw_op); 4561 4562 ig.push( 4563 Inst::new( 4564 "atomic_rmw", 4565 r#" 4566 Atomically read-modify-write memory at `p`, with second operand `x`. The old value is 4567 returned. `p` has the type of the target word size, and `x` may be an integer type of 4568 8, 16, 32 or 64 bits, even on a 32-bit target. The type of the returned value is the 4569 same as the type of `x`. This operation is sequentially consistent and creates 4570 happens-before edges that order normal (non-atomic) loads and stores. 4571 "#, 4572 &formats.atomic_rmw, 4573 ) 4574 .operands_in(vec![MemFlags, AtomicRmwOp, p, x]) 4575 .operands_out(vec![a]) 4576 .can_load(true) 4577 .can_store(true) 4578 .other_side_effects(true), 4579 ); 4580 4581 ig.push( 4582 Inst::new( 4583 "atomic_cas", 4584 r#" 4585 Perform an atomic compare-and-swap operation on memory at `p`, with expected value `e`, 4586 storing `x` if the value at `p` equals `e`. The old value at `p` is returned, 4587 regardless of whether the operation succeeds or fails. `p` has the type of the target 4588 word size, and `x` and `e` must have the same type and the same size, which may be an 4589 integer type of 8, 16, 32 or 64 bits, even on a 32-bit target. The type of the returned 4590 value is the same as the type of `x` and `e`. This operation is sequentially 4591 consistent and creates happens-before edges that order normal (non-atomic) loads and 4592 stores. 4593 "#, 4594 &formats.atomic_cas, 4595 ) 4596 .operands_in(vec![MemFlags, p, e, x]) 4597 .operands_out(vec![a]) 4598 .can_load(true) 4599 .can_store(true) 4600 .other_side_effects(true), 4601 ); 4602 4603 ig.push( 4604 Inst::new( 4605 "atomic_load", 4606 r#" 4607 Atomically load from memory at `p`. 4608 4609 This is a polymorphic instruction that can load any value type which has a memory 4610 representation. It should only be used for integer types with 8, 16, 32 or 64 bits. 4611 This operation is sequentially consistent and creates happens-before edges that order 4612 normal (non-atomic) loads and stores. 4613 "#, 4614 &formats.load_no_offset, 4615 ) 4616 .operands_in(vec![MemFlags, p]) 4617 .operands_out(vec![a]) 4618 .can_load(true) 4619 .other_side_effects(true), 4620 ); 4621 4622 ig.push( 4623 Inst::new( 4624 "atomic_store", 4625 r#" 4626 Atomically store `x` to memory at `p`. 4627 4628 This is a polymorphic instruction that can store any value type with a memory 4629 representation. It should only be used for integer types with 8, 16, 32 or 64 bits. 4630 This operation is sequentially consistent and creates happens-before edges that order 4631 normal (non-atomic) loads and stores. 4632 "#, 4633 &formats.store_no_offset, 4634 ) 4635 .operands_in(vec![MemFlags, x, p]) 4636 .can_store(true) 4637 .other_side_effects(true), 4638 ); 4639 4640 ig.push( 4641 Inst::new( 4642 "fence", 4643 r#" 4644 A memory fence. This must provide ordering to ensure that, at a minimum, neither loads 4645 nor stores of any kind may move forwards or backwards across the fence. This operation 4646 is sequentially consistent. 4647 "#, 4648 &formats.nullary, 4649 ) 4650 .other_side_effects(true), 4651 ); 4652 4653 ig.build() 4654 } 4655