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