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