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 For vector types, the lane types must also be the same size (see 3285 `raw_bitcast` for changing the lane size). 3286 "#, 3287 &formats.unary, 3288 ) 3289 .operands_in(vec![x]) 3290 .operands_out(vec![a]), 3291 ); 3292 3293 let x = &Operand::new("x", Any); 3294 let a = &Operand::new("a", AnyTo).with_doc("Bits of `x` reinterpreted"); 3295 3296 ig.push( 3297 Inst::new( 3298 "raw_bitcast", 3299 r#" 3300 Cast the bits in `x` as a different type of the same bit width. 3301 3302 This instruction does not change the data's representation but allows 3303 data in registers to be used as different types, e.g. an i32x4 as a 3304 b8x16. The only constraint on the result `a` is that it can be 3305 `raw_bitcast` back to the original type. Also, in a raw_bitcast between 3306 vector types with the same number of lanes, the value of each result 3307 lane is a raw_bitcast of the corresponding operand lane. TODO there is 3308 currently no mechanism for enforcing the bit width constraint. 3309 "#, 3310 &formats.unary, 3311 ) 3312 .operands_in(vec![x]) 3313 .operands_out(vec![a]), 3314 ); 3315 3316 let a = &Operand::new("a", TxN).with_doc("A vector value"); 3317 let s = &Operand::new("s", &TxN.lane_of()).with_doc("A scalar value"); 3318 3319 ig.push( 3320 Inst::new( 3321 "scalar_to_vector", 3322 r#" 3323 Copies a scalar value to a vector value. The scalar is copied into the 3324 least significant lane of the vector, and all other lanes will be zero. 3325 "#, 3326 &formats.unary, 3327 ) 3328 .operands_in(vec![s]) 3329 .operands_out(vec![a]), 3330 ); 3331 3332 let Bool = &TypeVar::new( 3333 "Bool", 3334 "A scalar boolean type", 3335 TypeSetBuilder::new().bools(Interval::All).build(), 3336 ); 3337 3338 let BoolTo = &TypeVar::new( 3339 "BoolTo", 3340 "A smaller boolean type", 3341 TypeSetBuilder::new().bools(Interval::All).build(), 3342 ); 3343 3344 let x = &Operand::new("x", Bool); 3345 let a = &Operand::new("a", BoolTo); 3346 3347 ig.push( 3348 Inst::new( 3349 "breduce", 3350 r#" 3351 Convert `x` to a smaller boolean type by discarding the most significant bits. 3352 "#, 3353 &formats.unary, 3354 ) 3355 .operands_in(vec![x]) 3356 .operands_out(vec![a]), 3357 ); 3358 3359 let BoolTo = &TypeVar::new( 3360 "BoolTo", 3361 "A larger boolean type", 3362 TypeSetBuilder::new().bools(Interval::All).build(), 3363 ); 3364 let x = &Operand::new("x", Bool); 3365 let a = &Operand::new("a", BoolTo); 3366 3367 ig.push( 3368 Inst::new( 3369 "bextend", 3370 r#" 3371 Convert `x` to a larger boolean type 3372 "#, 3373 &formats.unary, 3374 ) 3375 .operands_in(vec![x]) 3376 .operands_out(vec![a]), 3377 ); 3378 3379 let IntTo = &TypeVar::new( 3380 "IntTo", 3381 "A scalar integer type", 3382 TypeSetBuilder::new().ints(Interval::All).build(), 3383 ); 3384 let x = &Operand::new("x", ScalarBool); 3385 let a = &Operand::new("a", IntTo); 3386 3387 ig.push( 3388 Inst::new( 3389 "bint", 3390 r#" 3391 Convert `x` to an integer. 3392 3393 True maps to 1 and false maps to 0. 3394 "#, 3395 &formats.unary, 3396 ) 3397 .operands_in(vec![x]) 3398 .operands_out(vec![a]), 3399 ); 3400 3401 let Bool = &TypeVar::new( 3402 "Bool", 3403 "A scalar or vector boolean type", 3404 TypeSetBuilder::new() 3405 .bools(Interval::All) 3406 .simd_lanes(Interval::All) 3407 .build(), 3408 ); 3409 let IntTo = &TypeVar::new( 3410 "IntTo", 3411 "An integer type with the same number of lanes", 3412 TypeSetBuilder::new() 3413 .ints(Interval::All) 3414 .simd_lanes(Interval::All) 3415 .build(), 3416 ); 3417 let x = &Operand::new("x", Bool); 3418 let a = &Operand::new("a", IntTo); 3419 3420 ig.push( 3421 Inst::new( 3422 "bmask", 3423 r#" 3424 Convert `x` to an integer mask. 3425 3426 True maps to all 1s and false maps to all 0s. The result type must have 3427 the same number of vector lanes as the input. 3428 "#, 3429 &formats.unary, 3430 ) 3431 .operands_in(vec![x]) 3432 .operands_out(vec![a]), 3433 ); 3434 3435 let Int = &TypeVar::new( 3436 "Int", 3437 "A scalar integer type", 3438 TypeSetBuilder::new().ints(Interval::All).build(), 3439 ); 3440 3441 let IntTo = &TypeVar::new( 3442 "IntTo", 3443 "A smaller integer type", 3444 TypeSetBuilder::new().ints(Interval::All).build(), 3445 ); 3446 let x = &Operand::new("x", Int); 3447 let a = &Operand::new("a", IntTo); 3448 3449 ig.push( 3450 Inst::new( 3451 "ireduce", 3452 r#" 3453 Convert `x` to a smaller integer type by discarding 3454 the most significant bits. 3455 3456 This is the same as reducing modulo `2^n`. 3457 "#, 3458 &formats.unary, 3459 ) 3460 .operands_in(vec![x]) 3461 .operands_out(vec![a]), 3462 ); 3463 3464 let I16or32or64xN = &TypeVar::new( 3465 "I16or32or64xN", 3466 "A SIMD vector type containing integer lanes 16, 32, or 64 bits wide", 3467 TypeSetBuilder::new() 3468 .ints(16..64) 3469 .simd_lanes(2..8) 3470 .dynamic_simd_lanes(2..8) 3471 .includes_scalars(false) 3472 .build(), 3473 ); 3474 3475 let x = &Operand::new("x", I16or32or64xN); 3476 let y = &Operand::new("y", I16or32or64xN); 3477 let a = &Operand::new("a", &I16or32or64xN.split_lanes()); 3478 3479 ig.push( 3480 Inst::new( 3481 "snarrow", 3482 r#" 3483 Combine `x` and `y` into a vector with twice the lanes but half the integer width while 3484 saturating overflowing values to the signed maximum and minimum. 3485 3486 The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4` 3487 and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value 3488 returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`. 3489 "#, 3490 &formats.binary, 3491 ) 3492 .operands_in(vec![x, y]) 3493 .operands_out(vec![a]), 3494 ); 3495 3496 ig.push( 3497 Inst::new( 3498 "unarrow", 3499 r#" 3500 Combine `x` and `y` into a vector with twice the lanes but half the integer width while 3501 saturating overflowing values to the unsigned maximum and minimum. 3502 3503 Note that all input lanes are considered signed: any negative lanes will overflow and be 3504 replaced with the unsigned minimum, `0x00`. 3505 3506 The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4` 3507 and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value 3508 returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`. 3509 "#, 3510 &formats.binary, 3511 ) 3512 .operands_in(vec![x, y]) 3513 .operands_out(vec![a]), 3514 ); 3515 3516 ig.push( 3517 Inst::new( 3518 "uunarrow", 3519 r#" 3520 Combine `x` and `y` into a vector with twice the lanes but half the integer width while 3521 saturating overflowing values to the unsigned maximum and minimum. 3522 3523 Note that all input lanes are considered unsigned: any negative values will be interpreted as unsigned, overflowing and being replaced with the unsigned maximum. 3524 3525 The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4` 3526 and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value 3527 returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`. 3528 "#, 3529 &formats.binary, 3530 ) 3531 .operands_in(vec![x, y]) 3532 .operands_out(vec![a]), 3533 ); 3534 3535 let I8or16or32xN = &TypeVar::new( 3536 "I8or16or32xN", 3537 "A SIMD vector type containing integer lanes 8, 16, or 32 bits wide.", 3538 TypeSetBuilder::new() 3539 .ints(8..32) 3540 .simd_lanes(2..16) 3541 .dynamic_simd_lanes(2..16) 3542 .includes_scalars(false) 3543 .build(), 3544 ); 3545 3546 let x = &Operand::new("x", I8or16or32xN); 3547 let a = &Operand::new("a", &I8or16or32xN.merge_lanes()); 3548 3549 ig.push( 3550 Inst::new( 3551 "swiden_low", 3552 r#" 3553 Widen the low lanes of `x` using signed extension. 3554 3555 This will double the lane width and halve the number of lanes. 3556 "#, 3557 &formats.unary, 3558 ) 3559 .operands_in(vec![x]) 3560 .operands_out(vec![a]), 3561 ); 3562 3563 ig.push( 3564 Inst::new( 3565 "swiden_high", 3566 r#" 3567 Widen the high lanes of `x` using signed extension. 3568 3569 This will double the lane width and halve the number of lanes. 3570 "#, 3571 &formats.unary, 3572 ) 3573 .operands_in(vec![x]) 3574 .operands_out(vec![a]), 3575 ); 3576 3577 ig.push( 3578 Inst::new( 3579 "uwiden_low", 3580 r#" 3581 Widen the low lanes of `x` using unsigned extension. 3582 3583 This will double the lane width and halve the number of lanes. 3584 "#, 3585 &formats.unary, 3586 ) 3587 .operands_in(vec![x]) 3588 .operands_out(vec![a]), 3589 ); 3590 3591 ig.push( 3592 Inst::new( 3593 "uwiden_high", 3594 r#" 3595 Widen the high lanes of `x` using unsigned extension. 3596 3597 This will double the lane width and halve the number of lanes. 3598 "#, 3599 &formats.unary, 3600 ) 3601 .operands_in(vec![x]) 3602 .operands_out(vec![a]), 3603 ); 3604 3605 let x = &Operand::new("x", I8or16or32xN); 3606 let y = &Operand::new("y", I8or16or32xN); 3607 let a = &Operand::new("a", I8or16or32xN); 3608 3609 ig.push( 3610 Inst::new( 3611 "iadd_pairwise", 3612 r#" 3613 Does lane-wise integer pairwise addition on two operands, putting the 3614 combined results into a single vector result. Here a pair refers to adjacent 3615 lanes in a vector, i.e. i*2 + (i*2+1) for i == num_lanes/2. The first operand 3616 pairwise add results will make up the low half of the resulting vector while 3617 the second operand pairwise add results will make up the upper half of the 3618 resulting vector. 3619 "#, 3620 &formats.binary, 3621 ) 3622 .operands_in(vec![x, y]) 3623 .operands_out(vec![a]), 3624 ); 3625 3626 let I16x8 = &TypeVar::new( 3627 "I16x8", 3628 "A SIMD vector type containing 8 integer lanes each 16 bits wide.", 3629 TypeSetBuilder::new() 3630 .ints(16..16) 3631 .simd_lanes(8..8) 3632 .includes_scalars(false) 3633 .build(), 3634 ); 3635 3636 let x = &Operand::new("x", I16x8); 3637 let y = &Operand::new("y", I16x8); 3638 let a = &Operand::new("a", &I16x8.merge_lanes()); 3639 3640 ig.push( 3641 Inst::new( 3642 "widening_pairwise_dot_product_s", 3643 r#" 3644 Takes corresponding elements in `x` and `y`, performs a sign-extending length-doubling 3645 multiplication on them, then adds adjacent pairs of elements to form the result. For 3646 example, if the input vectors are `[x3, x2, x1, x0]` and `[y3, y2, y1, y0]`, it produces 3647 the vector `[r1, r0]`, where `r1 = sx(x3) * sx(y3) + sx(x2) * sx(y2)` and 3648 `r0 = sx(x1) * sx(y1) + sx(x0) * sx(y0)`, and `sx(n)` sign-extends `n` to twice its width. 3649 3650 This will double the lane width and halve the number of lanes. So the resulting 3651 vector has the same number of bits as `x` and `y` do (individually). 3652 3653 See <https://github.com/WebAssembly/simd/pull/127> for background info. 3654 "#, 3655 &formats.binary, 3656 ) 3657 .operands_in(vec![x, y]) 3658 .operands_out(vec![a]), 3659 ); 3660 3661 let IntTo = &TypeVar::new( 3662 "IntTo", 3663 "A larger integer type with the same number of lanes", 3664 TypeSetBuilder::new() 3665 .ints(Interval::All) 3666 .simd_lanes(Interval::All) 3667 .build(), 3668 ); 3669 let x = &Operand::new("x", Int); 3670 let a = &Operand::new("a", IntTo); 3671 3672 ig.push( 3673 Inst::new( 3674 "uextend", 3675 r#" 3676 Convert `x` to a larger integer type by zero-extending. 3677 3678 Each lane in `x` is converted to a larger integer type by adding 3679 zeroes. The result has the same numerical value as `x` when both are 3680 interpreted as unsigned integers. 3681 3682 The result type must have the same number of vector lanes as the input, 3683 and each lane must not have fewer bits that the input lanes. If the 3684 input and output types are the same, this is a no-op. 3685 "#, 3686 &formats.unary, 3687 ) 3688 .operands_in(vec![x]) 3689 .operands_out(vec![a]), 3690 ); 3691 3692 ig.push( 3693 Inst::new( 3694 "sextend", 3695 r#" 3696 Convert `x` to a larger integer type by sign-extending. 3697 3698 Each lane in `x` is converted to a larger integer type by replicating 3699 the sign bit. The result has the same numerical value as `x` when both 3700 are interpreted as signed integers. 3701 3702 The result type must have the same number of vector lanes as the input, 3703 and each lane must not have fewer bits that the input lanes. If the 3704 input and output types are the same, this is a no-op. 3705 "#, 3706 &formats.unary, 3707 ) 3708 .operands_in(vec![x]) 3709 .operands_out(vec![a]), 3710 ); 3711 3712 let FloatTo = &TypeVar::new( 3713 "FloatTo", 3714 "A scalar or vector floating point number", 3715 TypeSetBuilder::new() 3716 .floats(Interval::All) 3717 .simd_lanes(Interval::All) 3718 .build(), 3719 ); 3720 let x = &Operand::new("x", Float); 3721 let a = &Operand::new("a", FloatTo); 3722 3723 ig.push( 3724 Inst::new( 3725 "fpromote", 3726 r#" 3727 Convert `x` to a larger floating point format. 3728 3729 Each lane in `x` is converted to the destination floating point format. 3730 This is an exact operation. 3731 3732 Cranelift currently only supports two floating point formats 3733 - `f32` and `f64`. This may change in the future. 3734 3735 The result type must have the same number of vector lanes as the input, 3736 and the result lanes must not have fewer bits than the input lanes. If 3737 the input and output types are the same, this is a no-op. 3738 "#, 3739 &formats.unary, 3740 ) 3741 .operands_in(vec![x]) 3742 .operands_out(vec![a]), 3743 ); 3744 3745 ig.push( 3746 Inst::new( 3747 "fdemote", 3748 r#" 3749 Convert `x` to a smaller floating point format. 3750 3751 Each lane in `x` is converted to the destination floating point format 3752 by rounding to nearest, ties to even. 3753 3754 Cranelift currently only supports two floating point formats 3755 - `f32` and `f64`. This may change in the future. 3756 3757 The result type must have the same number of vector lanes as the input, 3758 and the result lanes must not have more bits than the input lanes. If 3759 the input and output types are the same, this is a no-op. 3760 "#, 3761 &formats.unary, 3762 ) 3763 .operands_in(vec![x]) 3764 .operands_out(vec![a]), 3765 ); 3766 3767 let F64x2 = &TypeVar::new( 3768 "F64x2", 3769 "A SIMD vector type consisting of 2 lanes of 64-bit floats", 3770 TypeSetBuilder::new() 3771 .floats(64..64) 3772 .simd_lanes(2..2) 3773 .includes_scalars(false) 3774 .build(), 3775 ); 3776 let F32x4 = &TypeVar::new( 3777 "F32x4", 3778 "A SIMD vector type consisting of 4 lanes of 32-bit floats", 3779 TypeSetBuilder::new() 3780 .floats(32..32) 3781 .simd_lanes(4..4) 3782 .includes_scalars(false) 3783 .build(), 3784 ); 3785 3786 let x = &Operand::new("x", F64x2); 3787 let a = &Operand::new("a", F32x4); 3788 3789 ig.push( 3790 Inst::new( 3791 "fvdemote", 3792 r#" 3793 Convert `x` to a smaller floating point format. 3794 3795 Each lane in `x` is converted to the destination floating point format 3796 by rounding to nearest, ties to even. 3797 3798 Cranelift currently only supports two floating point formats 3799 - `f32` and `f64`. This may change in the future. 3800 3801 Fvdemote differs from fdemote in that with fvdemote it targets vectors. 3802 Fvdemote is constrained to having the input type being F64x2 and the result 3803 type being F32x4. The result lane that was the upper half of the input lane 3804 is initialized to zero. 3805 "#, 3806 &formats.unary, 3807 ) 3808 .operands_in(vec![x]) 3809 .operands_out(vec![a]), 3810 ); 3811 3812 ig.push( 3813 Inst::new( 3814 "fvpromote_low", 3815 r#" 3816 Converts packed single precision floating point to packed double precision floating point. 3817 3818 Considering only the lower half of the register, the low lanes in `x` are interpreted as 3819 single precision floats that are then converted to a double precision floats. 3820 3821 The result type will have half the number of vector lanes as the input. Fvpromote_low is 3822 constrained to input F32x4 with a result type of F64x2. 3823 "#, 3824 &formats.unary, 3825 ) 3826 .operands_in(vec![a]) 3827 .operands_out(vec![x]), 3828 ); 3829 3830 let FloatScalar = &TypeVar::new( 3831 "FloatScalar", 3832 "A scalar only floating point number", 3833 TypeSetBuilder::new().floats(Interval::All).build(), 3834 ); 3835 let x = &Operand::new("x", FloatScalar); 3836 let a = &Operand::new("a", IntTo); 3837 3838 ig.push( 3839 Inst::new( 3840 "fcvt_to_uint", 3841 r#" 3842 Converts floating point scalars to unsigned integer. 3843 3844 Only operates on `x` if it is a scalar. If `x` is NaN or if 3845 the unsigned integral value cannot be represented in the result 3846 type, this instruction traps. 3847 3848 "#, 3849 &formats.unary, 3850 ) 3851 .operands_in(vec![x]) 3852 .operands_out(vec![a]) 3853 .can_trap(true), 3854 ); 3855 3856 ig.push( 3857 Inst::new( 3858 "fcvt_to_sint", 3859 r#" 3860 Converts floating point scalars to signed integer. 3861 3862 Only operates on `x` if it is a scalar. If `x` is NaN or if 3863 the unsigned integral value cannot be represented in the result 3864 type, this instruction traps. 3865 3866 "#, 3867 &formats.unary, 3868 ) 3869 .operands_in(vec![x]) 3870 .operands_out(vec![a]) 3871 .can_trap(true), 3872 ); 3873 3874 let x = &Operand::new("x", Float); 3875 let a = &Operand::new("a", IntTo); 3876 3877 ig.push( 3878 Inst::new( 3879 "fcvt_to_uint_sat", 3880 r#" 3881 Convert floating point to unsigned integer as fcvt_to_uint does, but 3882 saturates the input instead of trapping. NaN and negative values are 3883 converted to 0. 3884 "#, 3885 &formats.unary, 3886 ) 3887 .operands_in(vec![x]) 3888 .operands_out(vec![a]), 3889 ); 3890 3891 ig.push( 3892 Inst::new( 3893 "fcvt_to_sint_sat", 3894 r#" 3895 Convert floating point to signed integer as fcvt_to_sint does, but 3896 saturates the input instead of trapping. NaN values are converted to 0. 3897 "#, 3898 &formats.unary, 3899 ) 3900 .operands_in(vec![x]) 3901 .operands_out(vec![a]), 3902 ); 3903 3904 let Int = &TypeVar::new( 3905 "Int", 3906 "A scalar or vector integer type", 3907 TypeSetBuilder::new() 3908 .ints(Interval::All) 3909 .simd_lanes(Interval::All) 3910 .build(), 3911 ); 3912 let x = &Operand::new("x", Int); 3913 let a = &Operand::new("a", FloatTo); 3914 3915 ig.push( 3916 Inst::new( 3917 "fcvt_from_uint", 3918 r#" 3919 Convert unsigned integer to floating point. 3920 3921 Each lane in `x` is interpreted as an unsigned integer and converted to 3922 floating point using round to nearest, ties to even. 3923 3924 The result type must have the same number of vector lanes as the input. 3925 "#, 3926 &formats.unary, 3927 ) 3928 .operands_in(vec![x]) 3929 .operands_out(vec![a]), 3930 ); 3931 3932 ig.push( 3933 Inst::new( 3934 "fcvt_from_sint", 3935 r#" 3936 Convert signed integer to floating point. 3937 3938 Each lane in `x` is interpreted as a signed integer and converted to 3939 floating point using round to nearest, ties to even. 3940 3941 The result type must have the same number of vector lanes as the input. 3942 "#, 3943 &formats.unary, 3944 ) 3945 .operands_in(vec![x]) 3946 .operands_out(vec![a]), 3947 ); 3948 3949 ig.push( 3950 Inst::new( 3951 "fcvt_low_from_sint", 3952 r#" 3953 Converts packed signed 32-bit integers to packed double precision floating point. 3954 3955 Considering only the low half of the register, each lane in `x` is interpreted as a 3956 signed 32-bit integer that is then converted to a double precision float. This 3957 instruction differs from fcvt_from_sint in that it converts half the number of lanes 3958 which are converted to occupy twice the number of bits. No rounding should be needed 3959 for the resulting float. 3960 3961 The result type will have half the number of vector lanes as the input. 3962 "#, 3963 &formats.unary, 3964 ) 3965 .operands_in(vec![x]) 3966 .operands_out(vec![a]), 3967 ); 3968 3969 let WideInt = &TypeVar::new( 3970 "WideInt", 3971 "An integer type with lanes from `i16` upwards", 3972 TypeSetBuilder::new() 3973 .ints(16..128) 3974 .simd_lanes(Interval::All) 3975 .build(), 3976 ); 3977 let x = &Operand::new("x", WideInt); 3978 let lo = &Operand::new("lo", &WideInt.half_width()).with_doc("The low bits of `x`"); 3979 let hi = &Operand::new("hi", &WideInt.half_width()).with_doc("The high bits of `x`"); 3980 3981 ig.push( 3982 Inst::new( 3983 "isplit", 3984 r#" 3985 Split an integer into low and high parts. 3986 3987 Vectors of integers are split lane-wise, so the results have the same 3988 number of lanes as the input, but the lanes are half the size. 3989 3990 Returns the low half of `x` and the high half of `x` as two independent 3991 values. 3992 "#, 3993 &formats.unary, 3994 ) 3995 .operands_in(vec![x]) 3996 .operands_out(vec![lo, hi]), 3997 ); 3998 3999 let NarrowInt = &TypeVar::new( 4000 "NarrowInt", 4001 "An integer type with lanes type to `i64`", 4002 TypeSetBuilder::new() 4003 .ints(8..64) 4004 .simd_lanes(Interval::All) 4005 .build(), 4006 ); 4007 4008 let lo = &Operand::new("lo", NarrowInt); 4009 let hi = &Operand::new("hi", NarrowInt); 4010 let a = &Operand::new("a", &NarrowInt.double_width()) 4011 .with_doc("The concatenation of `lo` and `hi`"); 4012 4013 ig.push( 4014 Inst::new( 4015 "iconcat", 4016 r#" 4017 Concatenate low and high bits to form a larger integer type. 4018 4019 Vectors of integers are concatenated lane-wise such that the result has 4020 the same number of lanes as the inputs, but the lanes are twice the 4021 size. 4022 "#, 4023 &formats.binary, 4024 ) 4025 .operands_in(vec![lo, hi]) 4026 .operands_out(vec![a]), 4027 ); 4028 4029 // Instructions relating to atomic memory accesses and fences 4030 let AtomicMem = &TypeVar::new( 4031 "AtomicMem", 4032 "Any type that can be stored in memory, which can be used in an atomic operation", 4033 TypeSetBuilder::new().ints(8..64).build(), 4034 ); 4035 let x = &Operand::new("x", AtomicMem).with_doc("Value to be atomically stored"); 4036 let a = &Operand::new("a", AtomicMem).with_doc("Value atomically loaded"); 4037 let e = &Operand::new("e", AtomicMem).with_doc("Expected value in CAS"); 4038 let p = &Operand::new("p", iAddr); 4039 let MemFlags = &Operand::new("MemFlags", &imm.memflags); 4040 let AtomicRmwOp = &Operand::new("AtomicRmwOp", &imm.atomic_rmw_op); 4041 4042 ig.push( 4043 Inst::new( 4044 "atomic_rmw", 4045 r#" 4046 Atomically read-modify-write memory at `p`, with second operand `x`. The old value is 4047 returned. `p` has the type of the target word size, and `x` may be an integer type of 4048 8, 16, 32 or 64 bits, even on a 32-bit target. The type of the returned value is the 4049 same as the type of `x`. This operation is sequentially consistent and creates 4050 happens-before edges that order normal (non-atomic) loads and stores. 4051 "#, 4052 &formats.atomic_rmw, 4053 ) 4054 .operands_in(vec![MemFlags, AtomicRmwOp, p, x]) 4055 .operands_out(vec![a]) 4056 .can_load(true) 4057 .can_store(true) 4058 .other_side_effects(true), 4059 ); 4060 4061 ig.push( 4062 Inst::new( 4063 "atomic_cas", 4064 r#" 4065 Perform an atomic compare-and-swap operation on memory at `p`, with expected value `e`, 4066 storing `x` if the value at `p` equals `e`. The old value at `p` is returned, 4067 regardless of whether the operation succeeds or fails. `p` has the type of the target 4068 word size, and `x` and `e` must have the same type and the same size, which may be an 4069 integer type of 8, 16, 32 or 64 bits, even on a 32-bit target. The type of the returned 4070 value is the same as the type of `x` and `e`. This operation is sequentially 4071 consistent and creates happens-before edges that order normal (non-atomic) loads and 4072 stores. 4073 "#, 4074 &formats.atomic_cas, 4075 ) 4076 .operands_in(vec![MemFlags, p, e, x]) 4077 .operands_out(vec![a]) 4078 .can_load(true) 4079 .can_store(true) 4080 .other_side_effects(true), 4081 ); 4082 4083 ig.push( 4084 Inst::new( 4085 "atomic_load", 4086 r#" 4087 Atomically load from memory at `p`. 4088 4089 This is a polymorphic instruction that can load any value type which has a memory 4090 representation. It should only be used for integer types with 8, 16, 32 or 64 bits. 4091 This operation is sequentially consistent and creates happens-before edges that order 4092 normal (non-atomic) loads and stores. 4093 "#, 4094 &formats.load_no_offset, 4095 ) 4096 .operands_in(vec![MemFlags, p]) 4097 .operands_out(vec![a]) 4098 .can_load(true) 4099 .other_side_effects(true), 4100 ); 4101 4102 ig.push( 4103 Inst::new( 4104 "atomic_store", 4105 r#" 4106 Atomically store `x` to memory at `p`. 4107 4108 This is a polymorphic instruction that can store any value type with a memory 4109 representation. It should only be used for integer types with 8, 16, 32 or 64 bits. 4110 This operation is sequentially consistent and creates happens-before edges that order 4111 normal (non-atomic) loads and stores. 4112 "#, 4113 &formats.store_no_offset, 4114 ) 4115 .operands_in(vec![MemFlags, x, p]) 4116 .can_store(true) 4117 .other_side_effects(true), 4118 ); 4119 4120 ig.push( 4121 Inst::new( 4122 "fence", 4123 r#" 4124 A memory fence. This must provide ordering to ensure that, at a minimum, neither loads 4125 nor stores of any kind may move forwards or backwards across the fence. This operation 4126 is sequentially consistent. 4127 "#, 4128 &formats.nullary, 4129 ) 4130 .other_side_effects(true), 4131 ); 4132 4133 let TxN = &TypeVar::new( 4134 "TxN", 4135 "A dynamic vector type", 4136 TypeSetBuilder::new() 4137 .ints(Interval::All) 4138 .floats(Interval::All) 4139 .bools(Interval::All) 4140 .dynamic_simd_lanes(Interval::All) 4141 .build(), 4142 ); 4143 let x = &Operand::new("x", TxN).with_doc("The dynamic vector to extract from"); 4144 let y = &Operand::new("y", &imm.uimm8).with_doc("128-bit vector index"); 4145 let a = &Operand::new("a", &TxN.dynamic_to_vector()).with_doc("New fixed vector"); 4146 4147 ig.push( 4148 Inst::new( 4149 "extract_vector", 4150 r#" 4151 Return a fixed length sub vector, extracted from a dynamic vector. 4152 "#, 4153 &formats.binary_imm8, 4154 ) 4155 .operands_in(vec![x, y]) 4156 .operands_out(vec![a]), 4157 ); 4158 } 4159