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 constant = 1459 &Operand::new("constant", &imm.pool_constant).with_doc("A constant in the constant pool"); 1460 let address = &Operand::new("address", iAddr); 1461 ig.push( 1462 Inst::new( 1463 "const_addr", 1464 r#" 1465 Calculate the base address of a value in the constant pool. 1466 "#, 1467 &formats.unary_const, 1468 ) 1469 .operands_in(vec![constant]) 1470 .operands_out(vec![address]), 1471 ); 1472 1473 let mask = &Operand::new("mask", &imm.uimm128) 1474 .with_doc("The 16 immediate bytes used for selecting the elements to shuffle"); 1475 let Tx16 = &TypeVar::new( 1476 "Tx16", 1477 "A SIMD vector with exactly 16 lanes of 8-bit values; eventually this may support other \ 1478 lane counts and widths", 1479 TypeSetBuilder::new() 1480 .ints(8..8) 1481 .bools(8..8) 1482 .simd_lanes(16..16) 1483 .includes_scalars(false) 1484 .build(), 1485 ); 1486 let a = &Operand::new("a", Tx16).with_doc("A vector value"); 1487 let b = &Operand::new("b", Tx16).with_doc("A vector value"); 1488 1489 ig.push( 1490 Inst::new( 1491 "shuffle", 1492 r#" 1493 SIMD vector shuffle. 1494 1495 Shuffle two vectors using the given immediate bytes. For each of the 16 bytes of the 1496 immediate, a value i of 0-15 selects the i-th element of the first vector and a value i of 1497 16-31 selects the (i-16)th element of the second vector. Immediate values outside of the 1498 0-31 range place a 0 in the resulting vector lane. 1499 "#, 1500 &formats.shuffle, 1501 ) 1502 .operands_in(vec![a, b, mask]) 1503 .operands_out(vec![a]), 1504 ); 1505 1506 let a = &Operand::new("a", Ref).with_doc("A constant reference null value"); 1507 1508 ig.push( 1509 Inst::new( 1510 "null", 1511 r#" 1512 Null constant value for reference types. 1513 1514 Create a scalar reference SSA value with a constant null value. 1515 "#, 1516 &formats.nullary, 1517 ) 1518 .operands_out(vec![a]), 1519 ); 1520 1521 ig.push(Inst::new( 1522 "nop", 1523 r#" 1524 Just a dummy instruction. 1525 1526 Note: this doesn't compile to a machine code nop. 1527 "#, 1528 &formats.nullary, 1529 )); 1530 1531 let c = &Operand::new("c", Testable).with_doc("Controlling value to test"); 1532 let x = &Operand::new("x", Any).with_doc("Value to use when `c` is true"); 1533 let y = &Operand::new("y", Any).with_doc("Value to use when `c` is false"); 1534 let a = &Operand::new("a", Any); 1535 1536 ig.push( 1537 Inst::new( 1538 "select", 1539 r#" 1540 Conditional select. 1541 1542 This instruction selects whole values. Use `vselect` for 1543 lane-wise selection. 1544 "#, 1545 &formats.ternary, 1546 ) 1547 .operands_in(vec![c, x, y]) 1548 .operands_out(vec![a]), 1549 ); 1550 1551 let cc = &Operand::new("cc", &imm.intcc).with_doc("Controlling condition code"); 1552 let flags = &Operand::new("flags", iflags).with_doc("The machine's flag register"); 1553 1554 ig.push( 1555 Inst::new( 1556 "selectif", 1557 r#" 1558 Conditional select, dependent on integer condition codes. 1559 "#, 1560 &formats.int_select, 1561 ) 1562 .operands_in(vec![cc, flags, x, y]) 1563 .operands_out(vec![a]), 1564 ); 1565 1566 ig.push( 1567 Inst::new( 1568 "selectif_spectre_guard", 1569 r#" 1570 Conditional select intended for Spectre guards. 1571 1572 This operation is semantically equivalent to a selectif instruction. 1573 However, it is guaranteed to not be removed or otherwise altered by any 1574 optimization pass, and is guaranteed to result in a conditional-move 1575 instruction, not a branch-based lowering. As such, it is suitable 1576 for use when producing Spectre guards. For example, a bounds-check 1577 may guard against unsafe speculation past a bounds-check conditional 1578 branch by passing the address or index to be accessed through a 1579 conditional move, also gated on the same condition. Because no 1580 Spectre-vulnerable processors are known to perform speculation on 1581 conditional move instructions, this is guaranteed to pick the 1582 correct input. If the selected input in case of overflow is a "safe" 1583 value, for example a null pointer that causes an exception in the 1584 speculative path, this ensures that no Spectre vulnerability will 1585 exist. 1586 "#, 1587 &formats.int_select, 1588 ) 1589 .operands_in(vec![cc, flags, x, y]) 1590 .operands_out(vec![a]) 1591 .other_side_effects(true), 1592 ); 1593 1594 let c = &Operand::new("c", Any).with_doc("Controlling value to test"); 1595 ig.push( 1596 Inst::new( 1597 "bitselect", 1598 r#" 1599 Conditional select of bits. 1600 1601 For each bit in `c`, this instruction selects the corresponding bit from `x` if the bit 1602 in `c` is 1 and the corresponding bit from `y` if the bit in `c` is 0. See also: 1603 `select`, `vselect`. 1604 "#, 1605 &formats.ternary, 1606 ) 1607 .operands_in(vec![c, x, y]) 1608 .operands_out(vec![a]), 1609 ); 1610 1611 let x = &Operand::new("x", Any); 1612 1613 ig.push( 1614 Inst::new( 1615 "copy", 1616 r#" 1617 Register-register copy. 1618 1619 This instruction copies its input, preserving the value type. 1620 1621 A pure SSA-form program does not need to copy values, but this 1622 instruction is useful for representing intermediate stages during 1623 instruction transformations, and the register allocator needs a way of 1624 representing register copies. 1625 "#, 1626 &formats.unary, 1627 ) 1628 .operands_in(vec![x]) 1629 .operands_out(vec![a]), 1630 ); 1631 1632 let x = &Operand::new("x", TxN).with_doc("Vector to split"); 1633 let lo = &Operand::new("lo", &TxN.half_vector()).with_doc("Low-numbered lanes of `x`"); 1634 let hi = &Operand::new("hi", &TxN.half_vector()).with_doc("High-numbered lanes of `x`"); 1635 1636 ig.push( 1637 Inst::new( 1638 "vsplit", 1639 r#" 1640 Split a vector into two halves. 1641 1642 Split the vector `x` into two separate values, each containing half of 1643 the lanes from ``x``. The result may be two scalars if ``x`` only had 1644 two lanes. 1645 "#, 1646 &formats.unary, 1647 ) 1648 .operands_in(vec![x]) 1649 .operands_out(vec![lo, hi]), 1650 ); 1651 1652 let Any128 = &TypeVar::new( 1653 "Any128", 1654 "Any scalar or vector type with as most 128 lanes", 1655 TypeSetBuilder::new() 1656 .ints(Interval::All) 1657 .floats(Interval::All) 1658 .bools(Interval::All) 1659 .simd_lanes(1..128) 1660 .includes_scalars(true) 1661 .build(), 1662 ); 1663 1664 let x = &Operand::new("x", Any128).with_doc("Low-numbered lanes"); 1665 let y = &Operand::new("y", Any128).with_doc("High-numbered lanes"); 1666 let a = &Operand::new("a", &Any128.double_vector()).with_doc("Concatenation of `x` and `y`"); 1667 1668 ig.push( 1669 Inst::new( 1670 "vconcat", 1671 r#" 1672 Vector concatenation. 1673 1674 Return a vector formed by concatenating ``x`` and ``y``. The resulting 1675 vector type has twice as many lanes as each of the inputs. The lanes of 1676 ``x`` appear as the low-numbered lanes, and the lanes of ``y`` become 1677 the high-numbered lanes of ``a``. 1678 1679 It is possible to form a vector by concatenating two scalars. 1680 "#, 1681 &formats.binary, 1682 ) 1683 .operands_in(vec![x, y]) 1684 .operands_out(vec![a]), 1685 ); 1686 1687 let c = &Operand::new("c", &TxN.as_bool()).with_doc("Controlling vector"); 1688 let x = &Operand::new("x", TxN).with_doc("Value to use where `c` is true"); 1689 let y = &Operand::new("y", TxN).with_doc("Value to use where `c` is false"); 1690 let a = &Operand::new("a", TxN); 1691 1692 ig.push( 1693 Inst::new( 1694 "vselect", 1695 r#" 1696 Vector lane select. 1697 1698 Select lanes from ``x`` or ``y`` controlled by the lanes of the boolean 1699 vector ``c``. 1700 "#, 1701 &formats.ternary, 1702 ) 1703 .operands_in(vec![c, x, y]) 1704 .operands_out(vec![a]), 1705 ); 1706 1707 let s = &Operand::new("s", b1); 1708 1709 ig.push( 1710 Inst::new( 1711 "vany_true", 1712 r#" 1713 Reduce a vector to a scalar boolean. 1714 1715 Return a scalar boolean true if any lane in ``a`` is non-zero, false otherwise. 1716 "#, 1717 &formats.unary, 1718 ) 1719 .operands_in(vec![a]) 1720 .operands_out(vec![s]), 1721 ); 1722 1723 ig.push( 1724 Inst::new( 1725 "vall_true", 1726 r#" 1727 Reduce a vector to a scalar boolean. 1728 1729 Return a scalar boolean true if all lanes in ``i`` are non-zero, false otherwise. 1730 "#, 1731 &formats.unary, 1732 ) 1733 .operands_in(vec![a]) 1734 .operands_out(vec![s]), 1735 ); 1736 1737 let a = &Operand::new("a", TxN); 1738 let x = &Operand::new("x", Int); 1739 1740 ig.push( 1741 Inst::new( 1742 "vhigh_bits", 1743 r#" 1744 Reduce a vector to a scalar integer. 1745 1746 Return a scalar integer, consisting of the concatenation of the most significant bit 1747 of each lane of ``a``. 1748 "#, 1749 &formats.unary, 1750 ) 1751 .operands_in(vec![a]) 1752 .operands_out(vec![x]), 1753 ); 1754 1755 let a = &Operand::new("a", &Int.as_bool()); 1756 let Cond = &Operand::new("Cond", &imm.intcc); 1757 let x = &Operand::new("x", Int); 1758 let y = &Operand::new("y", Int); 1759 1760 ig.push( 1761 Inst::new( 1762 "icmp", 1763 r#" 1764 Integer comparison. 1765 1766 The condition code determines if the operands are interpreted as signed 1767 or unsigned integers. 1768 1769 | Signed | Unsigned | Condition | 1770 |--------|----------|-----------------------| 1771 | eq | eq | Equal | 1772 | ne | ne | Not equal | 1773 | slt | ult | Less than | 1774 | sge | uge | Greater than or equal | 1775 | sgt | ugt | Greater than | 1776 | sle | ule | Less than or equal | 1777 | of | * | Overflow | 1778 | nof | * | No Overflow | 1779 1780 \* The unsigned version of overflow condition for add has ISA-specific semantics and thus 1781 has been kept as a method on the TargetIsa trait as 1782 [unsigned_add_overflow_condition][crate::isa::TargetIsa::unsigned_add_overflow_condition]. 1783 1784 When this instruction compares integer vectors, it returns a boolean 1785 vector of lane-wise comparisons. 1786 "#, 1787 &formats.int_compare, 1788 ) 1789 .operands_in(vec![Cond, x, y]) 1790 .operands_out(vec![a]), 1791 ); 1792 1793 let a = &Operand::new("a", b1); 1794 let x = &Operand::new("x", iB); 1795 let Y = &Operand::new("Y", &imm.imm64); 1796 1797 ig.push( 1798 Inst::new( 1799 "icmp_imm", 1800 r#" 1801 Compare scalar integer to a constant. 1802 1803 This is the same as the `icmp` instruction, except one operand is 1804 an immediate constant. 1805 1806 This instruction can only compare scalars. Use `icmp` for 1807 lane-wise vector comparisons. 1808 "#, 1809 &formats.int_compare_imm, 1810 ) 1811 .operands_in(vec![Cond, x, Y]) 1812 .operands_out(vec![a]), 1813 ); 1814 1815 let f = &Operand::new("f", iflags); 1816 let x = &Operand::new("x", iB); 1817 let y = &Operand::new("y", iB); 1818 1819 ig.push( 1820 Inst::new( 1821 "ifcmp", 1822 r#" 1823 Compare scalar integers and return flags. 1824 1825 Compare two scalar integer values and return integer CPU flags 1826 representing the result. 1827 "#, 1828 &formats.binary, 1829 ) 1830 .operands_in(vec![x, y]) 1831 .operands_out(vec![f]), 1832 ); 1833 1834 ig.push( 1835 Inst::new( 1836 "ifcmp_imm", 1837 r#" 1838 Compare scalar integer to a constant and return flags. 1839 1840 Like `icmp_imm`, but returns integer CPU flags instead of testing 1841 a specific condition code. 1842 "#, 1843 &formats.binary_imm64, 1844 ) 1845 .operands_in(vec![x, Y]) 1846 .operands_out(vec![f]), 1847 ); 1848 1849 let a = &Operand::new("a", Int); 1850 let x = &Operand::new("x", Int); 1851 let y = &Operand::new("y", Int); 1852 1853 ig.push( 1854 Inst::new( 1855 "iadd", 1856 r#" 1857 Wrapping integer addition: `a := x + y \pmod{2^B}`. 1858 1859 This instruction does not depend on the signed/unsigned interpretation 1860 of the operands. 1861 "#, 1862 &formats.binary, 1863 ) 1864 .operands_in(vec![x, y]) 1865 .operands_out(vec![a]), 1866 ); 1867 1868 ig.push( 1869 Inst::new( 1870 "isub", 1871 r#" 1872 Wrapping integer subtraction: `a := x - y \pmod{2^B}`. 1873 1874 This instruction does not depend on the signed/unsigned interpretation 1875 of the operands. 1876 "#, 1877 &formats.binary, 1878 ) 1879 .operands_in(vec![x, y]) 1880 .operands_out(vec![a]), 1881 ); 1882 1883 ig.push( 1884 Inst::new( 1885 "ineg", 1886 r#" 1887 Integer negation: `a := -x \pmod{2^B}`. 1888 "#, 1889 &formats.unary, 1890 ) 1891 .operands_in(vec![x]) 1892 .operands_out(vec![a]), 1893 ); 1894 1895 ig.push( 1896 Inst::new( 1897 "iabs", 1898 r#" 1899 Integer absolute value with wrapping: `a := |x|`. 1900 "#, 1901 &formats.unary, 1902 ) 1903 .operands_in(vec![x]) 1904 .operands_out(vec![a]), 1905 ); 1906 1907 ig.push( 1908 Inst::new( 1909 "imul", 1910 r#" 1911 Wrapping integer multiplication: `a := x y \pmod{2^B}`. 1912 1913 This instruction does not depend on the signed/unsigned interpretation 1914 of the operands. 1915 1916 Polymorphic over all integer types (vector and scalar). 1917 "#, 1918 &formats.binary, 1919 ) 1920 .operands_in(vec![x, y]) 1921 .operands_out(vec![a]), 1922 ); 1923 1924 ig.push( 1925 Inst::new( 1926 "umulhi", 1927 r#" 1928 Unsigned integer multiplication, producing the high half of a 1929 double-length result. 1930 1931 Polymorphic over all integer types (vector and scalar). 1932 "#, 1933 &formats.binary, 1934 ) 1935 .operands_in(vec![x, y]) 1936 .operands_out(vec![a]), 1937 ); 1938 1939 ig.push( 1940 Inst::new( 1941 "smulhi", 1942 r#" 1943 Signed integer multiplication, producing the high half of a 1944 double-length result. 1945 1946 Polymorphic over all integer types (vector and scalar). 1947 "#, 1948 &formats.binary, 1949 ) 1950 .operands_in(vec![x, y]) 1951 .operands_out(vec![a]), 1952 ); 1953 1954 let I16or32 = &TypeVar::new( 1955 "I16or32", 1956 "A scalar or vector integer type with 16- or 32-bit numbers", 1957 TypeSetBuilder::new().ints(16..32).simd_lanes(4..8).build(), 1958 ); 1959 1960 let qx = &Operand::new("x", I16or32); 1961 let qy = &Operand::new("y", I16or32); 1962 let qa = &Operand::new("a", I16or32); 1963 1964 ig.push( 1965 Inst::new( 1966 "sqmul_round_sat", 1967 r#" 1968 Fixed-point multiplication of numbers in the QN format, where N + 1 1969 is the number bitwidth: 1970 `a := signed_saturate((x * y + 1 << (Q - 1)) >> Q)` 1971 1972 Polymorphic over all integer types (scalar and vector) with 16- or 1973 32-bit numbers. 1974 "#, 1975 &formats.binary, 1976 ) 1977 .operands_in(vec![qx, qy]) 1978 .operands_out(vec![qa]), 1979 ); 1980 1981 { 1982 // Integer division and remainder are scalar-only; most 1983 // hardware does not directly support vector integer division. 1984 1985 let x = &Operand::new("x", iB); 1986 let y = &Operand::new("y", iB); 1987 let a = &Operand::new("a", iB); 1988 1989 ig.push( 1990 Inst::new( 1991 "udiv", 1992 r#" 1993 Unsigned integer division: `a := \lfloor {x \over y} \rfloor`. 1994 1995 This operation traps if the divisor is zero. 1996 "#, 1997 &formats.binary, 1998 ) 1999 .operands_in(vec![x, y]) 2000 .operands_out(vec![a]) 2001 .can_trap(true), 2002 ); 2003 2004 ig.push( 2005 Inst::new( 2006 "sdiv", 2007 r#" 2008 Signed integer division rounded toward zero: `a := sign(xy) 2009 \lfloor {|x| \over |y|}\rfloor`. 2010 2011 This operation traps if the divisor is zero, or if the result is not 2012 representable in `B` bits two's complement. This only happens 2013 when `x = -2^{B-1}, y = -1`. 2014 "#, 2015 &formats.binary, 2016 ) 2017 .operands_in(vec![x, y]) 2018 .operands_out(vec![a]) 2019 .can_trap(true), 2020 ); 2021 2022 ig.push( 2023 Inst::new( 2024 "urem", 2025 r#" 2026 Unsigned integer remainder. 2027 2028 This operation traps if the divisor is zero. 2029 "#, 2030 &formats.binary, 2031 ) 2032 .operands_in(vec![x, y]) 2033 .operands_out(vec![a]) 2034 .can_trap(true), 2035 ); 2036 2037 ig.push( 2038 Inst::new( 2039 "srem", 2040 r#" 2041 Signed integer remainder. The result has the sign of the dividend. 2042 2043 This operation traps if the divisor is zero. 2044 "#, 2045 &formats.binary, 2046 ) 2047 .operands_in(vec![x, y]) 2048 .operands_out(vec![a]) 2049 .can_trap(true), 2050 ); 2051 } 2052 2053 let a = &Operand::new("a", iB); 2054 let x = &Operand::new("x", iB); 2055 let Y = &Operand::new("Y", &imm.imm64); 2056 2057 ig.push( 2058 Inst::new( 2059 "iadd_imm", 2060 r#" 2061 Add immediate integer. 2062 2063 Same as `iadd`, but one operand is an immediate constant. 2064 2065 Polymorphic over all scalar integer types, but does not support vector 2066 types. 2067 "#, 2068 &formats.binary_imm64, 2069 ) 2070 .operands_in(vec![x, Y]) 2071 .operands_out(vec![a]), 2072 ); 2073 2074 ig.push( 2075 Inst::new( 2076 "imul_imm", 2077 r#" 2078 Integer multiplication by immediate constant. 2079 2080 Polymorphic over all scalar integer types, but does not support vector 2081 types. 2082 "#, 2083 &formats.binary_imm64, 2084 ) 2085 .operands_in(vec![x, Y]) 2086 .operands_out(vec![a]), 2087 ); 2088 2089 ig.push( 2090 Inst::new( 2091 "udiv_imm", 2092 r#" 2093 Unsigned integer division by an immediate constant. 2094 2095 This operation traps if the divisor is zero. 2096 "#, 2097 &formats.binary_imm64, 2098 ) 2099 .operands_in(vec![x, Y]) 2100 .operands_out(vec![a]), 2101 ); 2102 2103 ig.push( 2104 Inst::new( 2105 "sdiv_imm", 2106 r#" 2107 Signed integer division by an immediate constant. 2108 2109 This operation traps if the divisor is zero, or if the result is not 2110 representable in `B` bits two's complement. This only happens 2111 when `x = -2^{B-1}, Y = -1`. 2112 "#, 2113 &formats.binary_imm64, 2114 ) 2115 .operands_in(vec![x, Y]) 2116 .operands_out(vec![a]), 2117 ); 2118 2119 ig.push( 2120 Inst::new( 2121 "urem_imm", 2122 r#" 2123 Unsigned integer remainder with immediate divisor. 2124 2125 This operation traps if the divisor is zero. 2126 "#, 2127 &formats.binary_imm64, 2128 ) 2129 .operands_in(vec![x, Y]) 2130 .operands_out(vec![a]), 2131 ); 2132 2133 ig.push( 2134 Inst::new( 2135 "srem_imm", 2136 r#" 2137 Signed integer remainder with immediate divisor. 2138 2139 This operation traps if the divisor is zero. 2140 "#, 2141 &formats.binary_imm64, 2142 ) 2143 .operands_in(vec![x, Y]) 2144 .operands_out(vec![a]), 2145 ); 2146 2147 ig.push( 2148 Inst::new( 2149 "irsub_imm", 2150 r#" 2151 Immediate reverse wrapping subtraction: `a := Y - x \pmod{2^B}`. 2152 2153 Also works as integer negation when `Y = 0`. Use `iadd_imm` 2154 with a negative immediate operand for the reverse immediate 2155 subtraction. 2156 2157 Polymorphic over all scalar integer types, but does not support vector 2158 types. 2159 "#, 2160 &formats.binary_imm64, 2161 ) 2162 .operands_in(vec![x, Y]) 2163 .operands_out(vec![a]), 2164 ); 2165 2166 let a = &Operand::new("a", iB); 2167 let x = &Operand::new("x", iB); 2168 let y = &Operand::new("y", iB); 2169 2170 let c_in = &Operand::new("c_in", b1).with_doc("Input carry flag"); 2171 let c_out = &Operand::new("c_out", b1).with_doc("Output carry flag"); 2172 let b_in = &Operand::new("b_in", b1).with_doc("Input borrow flag"); 2173 let b_out = &Operand::new("b_out", b1).with_doc("Output borrow flag"); 2174 2175 let c_if_in = &Operand::new("c_in", iflags); 2176 let c_if_out = &Operand::new("c_out", iflags); 2177 let b_if_in = &Operand::new("b_in", iflags); 2178 let b_if_out = &Operand::new("b_out", iflags); 2179 2180 ig.push( 2181 Inst::new( 2182 "iadd_cin", 2183 r#" 2184 Add integers with carry in. 2185 2186 Same as `iadd` with an additional carry input. Computes: 2187 2188 ```text 2189 a = x + y + c_{in} \pmod 2^B 2190 ``` 2191 2192 Polymorphic over all scalar integer types, but does not support vector 2193 types. 2194 "#, 2195 &formats.ternary, 2196 ) 2197 .operands_in(vec![x, y, c_in]) 2198 .operands_out(vec![a]), 2199 ); 2200 2201 ig.push( 2202 Inst::new( 2203 "iadd_ifcin", 2204 r#" 2205 Add integers with carry in. 2206 2207 Same as `iadd` with an additional carry flag input. Computes: 2208 2209 ```text 2210 a = x + y + c_{in} \pmod 2^B 2211 ``` 2212 2213 Polymorphic over all scalar integer types, but does not support vector 2214 types. 2215 "#, 2216 &formats.ternary, 2217 ) 2218 .operands_in(vec![x, y, c_if_in]) 2219 .operands_out(vec![a]), 2220 ); 2221 2222 ig.push( 2223 Inst::new( 2224 "iadd_cout", 2225 r#" 2226 Add integers with carry out. 2227 2228 Same as `iadd` with an additional carry output. 2229 2230 ```text 2231 a &= x + y \pmod 2^B \\ 2232 c_{out} &= x+y >= 2^B 2233 ``` 2234 2235 Polymorphic over all scalar integer types, but does not support vector 2236 types. 2237 "#, 2238 &formats.binary, 2239 ) 2240 .operands_in(vec![x, y]) 2241 .operands_out(vec![a, c_out]), 2242 ); 2243 2244 ig.push( 2245 Inst::new( 2246 "iadd_ifcout", 2247 r#" 2248 Add integers with carry out. 2249 2250 Same as `iadd` with an additional carry flag output. 2251 2252 ```text 2253 a &= x + y \pmod 2^B \\ 2254 c_{out} &= x+y >= 2^B 2255 ``` 2256 2257 Polymorphic over all scalar integer types, but does not support vector 2258 types. 2259 "#, 2260 &formats.binary, 2261 ) 2262 .operands_in(vec![x, y]) 2263 .operands_out(vec![a, c_if_out]), 2264 ); 2265 2266 ig.push( 2267 Inst::new( 2268 "iadd_carry", 2269 r#" 2270 Add integers with carry in and out. 2271 2272 Same as `iadd` with an additional carry input and output. 2273 2274 ```text 2275 a &= x + y + c_{in} \pmod 2^B \\ 2276 c_{out} &= x + y + c_{in} >= 2^B 2277 ``` 2278 2279 Polymorphic over all scalar integer types, but does not support vector 2280 types. 2281 "#, 2282 &formats.ternary, 2283 ) 2284 .operands_in(vec![x, y, c_in]) 2285 .operands_out(vec![a, c_out]), 2286 ); 2287 2288 ig.push( 2289 Inst::new( 2290 "iadd_ifcarry", 2291 r#" 2292 Add integers with carry in and out. 2293 2294 Same as `iadd` with an additional carry flag input and output. 2295 2296 ```text 2297 a &= x + y + c_{in} \pmod 2^B \\ 2298 c_{out} &= x + y + c_{in} >= 2^B 2299 ``` 2300 2301 Polymorphic over all scalar integer types, but does not support vector 2302 types. 2303 "#, 2304 &formats.ternary, 2305 ) 2306 .operands_in(vec![x, y, c_if_in]) 2307 .operands_out(vec![a, c_if_out]), 2308 ); 2309 2310 ig.push( 2311 Inst::new( 2312 "isub_bin", 2313 r#" 2314 Subtract integers with borrow in. 2315 2316 Same as `isub` with an additional borrow flag input. Computes: 2317 2318 ```text 2319 a = x - (y + b_{in}) \pmod 2^B 2320 ``` 2321 2322 Polymorphic over all scalar integer types, but does not support vector 2323 types. 2324 "#, 2325 &formats.ternary, 2326 ) 2327 .operands_in(vec![x, y, b_in]) 2328 .operands_out(vec![a]), 2329 ); 2330 2331 ig.push( 2332 Inst::new( 2333 "isub_ifbin", 2334 r#" 2335 Subtract integers with borrow in. 2336 2337 Same as `isub` with an additional borrow flag input. Computes: 2338 2339 ```text 2340 a = x - (y + b_{in}) \pmod 2^B 2341 ``` 2342 2343 Polymorphic over all scalar integer types, but does not support vector 2344 types. 2345 "#, 2346 &formats.ternary, 2347 ) 2348 .operands_in(vec![x, y, b_if_in]) 2349 .operands_out(vec![a]), 2350 ); 2351 2352 ig.push( 2353 Inst::new( 2354 "isub_bout", 2355 r#" 2356 Subtract integers with borrow out. 2357 2358 Same as `isub` with an additional borrow flag output. 2359 2360 ```text 2361 a &= x - y \pmod 2^B \\ 2362 b_{out} &= x < y 2363 ``` 2364 2365 Polymorphic over all scalar integer types, but does not support vector 2366 types. 2367 "#, 2368 &formats.binary, 2369 ) 2370 .operands_in(vec![x, y]) 2371 .operands_out(vec![a, b_out]), 2372 ); 2373 2374 ig.push( 2375 Inst::new( 2376 "isub_ifbout", 2377 r#" 2378 Subtract integers with borrow out. 2379 2380 Same as `isub` with an additional borrow flag output. 2381 2382 ```text 2383 a &= x - y \pmod 2^B \\ 2384 b_{out} &= x < y 2385 ``` 2386 2387 Polymorphic over all scalar integer types, but does not support vector 2388 types. 2389 "#, 2390 &formats.binary, 2391 ) 2392 .operands_in(vec![x, y]) 2393 .operands_out(vec![a, b_if_out]), 2394 ); 2395 2396 ig.push( 2397 Inst::new( 2398 "isub_borrow", 2399 r#" 2400 Subtract integers with borrow in and out. 2401 2402 Same as `isub` with an additional borrow flag input and output. 2403 2404 ```text 2405 a &= x - (y + b_{in}) \pmod 2^B \\ 2406 b_{out} &= x < y + b_{in} 2407 ``` 2408 2409 Polymorphic over all scalar integer types, but does not support vector 2410 types. 2411 "#, 2412 &formats.ternary, 2413 ) 2414 .operands_in(vec![x, y, b_in]) 2415 .operands_out(vec![a, b_out]), 2416 ); 2417 2418 ig.push( 2419 Inst::new( 2420 "isub_ifborrow", 2421 r#" 2422 Subtract integers with borrow in and out. 2423 2424 Same as `isub` with an additional borrow flag input and output. 2425 2426 ```text 2427 a &= x - (y + b_{in}) \pmod 2^B \\ 2428 b_{out} &= x < y + b_{in} 2429 ``` 2430 2431 Polymorphic over all scalar integer types, but does not support vector 2432 types. 2433 "#, 2434 &formats.ternary, 2435 ) 2436 .operands_in(vec![x, y, b_if_in]) 2437 .operands_out(vec![a, b_if_out]), 2438 ); 2439 2440 let bits = &TypeVar::new( 2441 "bits", 2442 "Any integer, float, or boolean scalar or vector type", 2443 TypeSetBuilder::new() 2444 .ints(Interval::All) 2445 .floats(Interval::All) 2446 .bools(Interval::All) 2447 .simd_lanes(Interval::All) 2448 .includes_scalars(true) 2449 .build(), 2450 ); 2451 let x = &Operand::new("x", bits); 2452 let y = &Operand::new("y", bits); 2453 let a = &Operand::new("a", bits); 2454 2455 ig.push( 2456 Inst::new( 2457 "band", 2458 r#" 2459 Bitwise and. 2460 "#, 2461 &formats.binary, 2462 ) 2463 .operands_in(vec![x, y]) 2464 .operands_out(vec![a]), 2465 ); 2466 2467 ig.push( 2468 Inst::new( 2469 "bor", 2470 r#" 2471 Bitwise or. 2472 "#, 2473 &formats.binary, 2474 ) 2475 .operands_in(vec![x, y]) 2476 .operands_out(vec![a]), 2477 ); 2478 2479 ig.push( 2480 Inst::new( 2481 "bxor", 2482 r#" 2483 Bitwise xor. 2484 "#, 2485 &formats.binary, 2486 ) 2487 .operands_in(vec![x, y]) 2488 .operands_out(vec![a]), 2489 ); 2490 2491 ig.push( 2492 Inst::new( 2493 "bnot", 2494 r#" 2495 Bitwise not. 2496 "#, 2497 &formats.unary, 2498 ) 2499 .operands_in(vec![x]) 2500 .operands_out(vec![a]), 2501 ); 2502 2503 ig.push( 2504 Inst::new( 2505 "band_not", 2506 r#" 2507 Bitwise and not. 2508 2509 Computes `x & ~y`. 2510 "#, 2511 &formats.binary, 2512 ) 2513 .operands_in(vec![x, y]) 2514 .operands_out(vec![a]), 2515 ); 2516 2517 ig.push( 2518 Inst::new( 2519 "bor_not", 2520 r#" 2521 Bitwise or not. 2522 2523 Computes `x | ~y`. 2524 "#, 2525 &formats.binary, 2526 ) 2527 .operands_in(vec![x, y]) 2528 .operands_out(vec![a]), 2529 ); 2530 2531 ig.push( 2532 Inst::new( 2533 "bxor_not", 2534 r#" 2535 Bitwise xor not. 2536 2537 Computes `x ^ ~y`. 2538 "#, 2539 &formats.binary, 2540 ) 2541 .operands_in(vec![x, y]) 2542 .operands_out(vec![a]), 2543 ); 2544 2545 let x = &Operand::new("x", iB); 2546 let Y = &Operand::new("Y", &imm.imm64); 2547 let a = &Operand::new("a", iB); 2548 2549 ig.push( 2550 Inst::new( 2551 "band_imm", 2552 r#" 2553 Bitwise and with immediate. 2554 2555 Same as `band`, but one operand is an immediate constant. 2556 2557 Polymorphic over all scalar integer types, but does not support vector 2558 types. 2559 "#, 2560 &formats.binary_imm64, 2561 ) 2562 .operands_in(vec![x, Y]) 2563 .operands_out(vec![a]), 2564 ); 2565 2566 ig.push( 2567 Inst::new( 2568 "bor_imm", 2569 r#" 2570 Bitwise or with immediate. 2571 2572 Same as `bor`, but one operand is an immediate constant. 2573 2574 Polymorphic over all scalar integer types, but does not support vector 2575 types. 2576 "#, 2577 &formats.binary_imm64, 2578 ) 2579 .operands_in(vec![x, Y]) 2580 .operands_out(vec![a]), 2581 ); 2582 2583 ig.push( 2584 Inst::new( 2585 "bxor_imm", 2586 r#" 2587 Bitwise xor with immediate. 2588 2589 Same as `bxor`, but one operand is an immediate constant. 2590 2591 Polymorphic over all scalar integer types, but does not support vector 2592 types. 2593 "#, 2594 &formats.binary_imm64, 2595 ) 2596 .operands_in(vec![x, Y]) 2597 .operands_out(vec![a]), 2598 ); 2599 2600 let x = &Operand::new("x", Int).with_doc("Scalar or vector value to shift"); 2601 let y = &Operand::new("y", iB).with_doc("Number of bits to shift"); 2602 let Y = &Operand::new("Y", &imm.imm64); 2603 let a = &Operand::new("a", Int); 2604 2605 ig.push( 2606 Inst::new( 2607 "rotl", 2608 r#" 2609 Rotate left. 2610 2611 Rotate the bits in ``x`` by ``y`` places. 2612 "#, 2613 &formats.binary, 2614 ) 2615 .operands_in(vec![x, y]) 2616 .operands_out(vec![a]), 2617 ); 2618 2619 ig.push( 2620 Inst::new( 2621 "rotr", 2622 r#" 2623 Rotate right. 2624 2625 Rotate the bits in ``x`` by ``y`` places. 2626 "#, 2627 &formats.binary, 2628 ) 2629 .operands_in(vec![x, y]) 2630 .operands_out(vec![a]), 2631 ); 2632 2633 ig.push( 2634 Inst::new( 2635 "rotl_imm", 2636 r#" 2637 Rotate left by immediate. 2638 "#, 2639 &formats.binary_imm64, 2640 ) 2641 .operands_in(vec![x, Y]) 2642 .operands_out(vec![a]), 2643 ); 2644 2645 ig.push( 2646 Inst::new( 2647 "rotr_imm", 2648 r#" 2649 Rotate right by immediate. 2650 "#, 2651 &formats.binary_imm64, 2652 ) 2653 .operands_in(vec![x, Y]) 2654 .operands_out(vec![a]), 2655 ); 2656 2657 ig.push( 2658 Inst::new( 2659 "ishl", 2660 r#" 2661 Integer shift left. Shift the bits in ``x`` towards the MSB by ``y`` 2662 places. Shift in zero bits to the LSB. 2663 2664 The shift amount is masked to the size of ``x``. 2665 2666 When shifting a B-bits integer type, this instruction computes: 2667 2668 ```text 2669 s &:= y \pmod B, 2670 a &:= x \cdot 2^s \pmod{2^B}. 2671 ``` 2672 "#, 2673 &formats.binary, 2674 ) 2675 .operands_in(vec![x, y]) 2676 .operands_out(vec![a]), 2677 ); 2678 2679 ig.push( 2680 Inst::new( 2681 "ushr", 2682 r#" 2683 Unsigned shift right. Shift bits in ``x`` towards the LSB by ``y`` 2684 places, shifting in zero bits to the MSB. Also called a *logical 2685 shift*. 2686 2687 The shift amount is masked to the size of the register. 2688 2689 When shifting a B-bits integer type, this instruction computes: 2690 2691 ```text 2692 s &:= y \pmod B, 2693 a &:= \lfloor x \cdot 2^{-s} \rfloor. 2694 ``` 2695 "#, 2696 &formats.binary, 2697 ) 2698 .operands_in(vec![x, y]) 2699 .operands_out(vec![a]), 2700 ); 2701 2702 ig.push( 2703 Inst::new( 2704 "sshr", 2705 r#" 2706 Signed shift right. Shift bits in ``x`` towards the LSB by ``y`` 2707 places, shifting in sign bits to the MSB. Also called an *arithmetic 2708 shift*. 2709 2710 The shift amount is masked to the size of the register. 2711 "#, 2712 &formats.binary, 2713 ) 2714 .operands_in(vec![x, y]) 2715 .operands_out(vec![a]), 2716 ); 2717 2718 ig.push( 2719 Inst::new( 2720 "ishl_imm", 2721 r#" 2722 Integer shift left by immediate. 2723 2724 The shift amount is masked to the size of ``x``. 2725 "#, 2726 &formats.binary_imm64, 2727 ) 2728 .operands_in(vec![x, Y]) 2729 .operands_out(vec![a]), 2730 ); 2731 2732 ig.push( 2733 Inst::new( 2734 "ushr_imm", 2735 r#" 2736 Unsigned shift right by immediate. 2737 2738 The shift amount is masked to the size of the register. 2739 "#, 2740 &formats.binary_imm64, 2741 ) 2742 .operands_in(vec![x, Y]) 2743 .operands_out(vec![a]), 2744 ); 2745 2746 ig.push( 2747 Inst::new( 2748 "sshr_imm", 2749 r#" 2750 Signed shift right by immediate. 2751 2752 The shift amount is masked to the size of the register. 2753 "#, 2754 &formats.binary_imm64, 2755 ) 2756 .operands_in(vec![x, Y]) 2757 .operands_out(vec![a]), 2758 ); 2759 2760 let x = &Operand::new("x", iB); 2761 let a = &Operand::new("a", iB); 2762 2763 ig.push( 2764 Inst::new( 2765 "bitrev", 2766 r#" 2767 Reverse the bits of a integer. 2768 2769 Reverses the bits in ``x``. 2770 "#, 2771 &formats.unary, 2772 ) 2773 .operands_in(vec![x]) 2774 .operands_out(vec![a]), 2775 ); 2776 2777 ig.push( 2778 Inst::new( 2779 "clz", 2780 r#" 2781 Count leading zero bits. 2782 2783 Starting from the MSB in ``x``, count the number of zero bits before 2784 reaching the first one bit. When ``x`` is zero, returns the size of x 2785 in bits. 2786 "#, 2787 &formats.unary, 2788 ) 2789 .operands_in(vec![x]) 2790 .operands_out(vec![a]), 2791 ); 2792 2793 ig.push( 2794 Inst::new( 2795 "cls", 2796 r#" 2797 Count leading sign bits. 2798 2799 Starting from the MSB after the sign bit in ``x``, count the number of 2800 consecutive bits identical to the sign bit. When ``x`` is 0 or -1, 2801 returns one less than the size of x in bits. 2802 "#, 2803 &formats.unary, 2804 ) 2805 .operands_in(vec![x]) 2806 .operands_out(vec![a]), 2807 ); 2808 2809 ig.push( 2810 Inst::new( 2811 "ctz", 2812 r#" 2813 Count trailing zeros. 2814 2815 Starting from the LSB in ``x``, count the number of zero bits before 2816 reaching the first one bit. When ``x`` is zero, returns the size of x 2817 in bits. 2818 "#, 2819 &formats.unary, 2820 ) 2821 .operands_in(vec![x]) 2822 .operands_out(vec![a]), 2823 ); 2824 2825 let x = &Operand::new("x", Int); 2826 let a = &Operand::new("a", Int); 2827 2828 ig.push( 2829 Inst::new( 2830 "popcnt", 2831 r#" 2832 Population count 2833 2834 Count the number of one bits in ``x``. 2835 "#, 2836 &formats.unary, 2837 ) 2838 .operands_in(vec![x]) 2839 .operands_out(vec![a]), 2840 ); 2841 2842 let Float = &TypeVar::new( 2843 "Float", 2844 "A scalar or vector floating point number", 2845 TypeSetBuilder::new() 2846 .floats(Interval::All) 2847 .simd_lanes(Interval::All) 2848 .dynamic_simd_lanes(Interval::All) 2849 .build(), 2850 ); 2851 let Cond = &Operand::new("Cond", &imm.floatcc); 2852 let x = &Operand::new("x", Float); 2853 let y = &Operand::new("y", Float); 2854 let a = &Operand::new("a", &Float.as_bool()); 2855 2856 ig.push( 2857 Inst::new( 2858 "fcmp", 2859 r#" 2860 Floating point comparison. 2861 2862 Two IEEE 754-2008 floating point numbers, `x` and `y`, relate to each 2863 other in exactly one of four ways: 2864 2865 ```text 2866 == ========================================== 2867 UN Unordered when one or both numbers is NaN. 2868 EQ When `x = y`. (And `0.0 = -0.0`). 2869 LT When `x < y`. 2870 GT When `x > y`. 2871 == ========================================== 2872 ``` 2873 2874 The 14 `floatcc` condition codes each correspond to a subset of 2875 the four relations, except for the empty set which would always be 2876 false, and the full set which would always be true. 2877 2878 The condition codes are divided into 7 'ordered' conditions which don't 2879 include UN, and 7 unordered conditions which all include UN. 2880 2881 ```text 2882 +-------+------------+---------+------------+-------------------------+ 2883 |Ordered |Unordered |Condition | 2884 +=======+============+=========+============+=========================+ 2885 |ord |EQ | LT | GT|uno |UN |NaNs absent / present. | 2886 +-------+------------+---------+------------+-------------------------+ 2887 |eq |EQ |ueq |UN | EQ |Equal | 2888 +-------+------------+---------+------------+-------------------------+ 2889 |one |LT | GT |ne |UN | LT | GT|Not equal | 2890 +-------+------------+---------+------------+-------------------------+ 2891 |lt |LT |ult |UN | LT |Less than | 2892 +-------+------------+---------+------------+-------------------------+ 2893 |le |LT | EQ |ule |UN | LT | EQ|Less than or equal | 2894 +-------+------------+---------+------------+-------------------------+ 2895 |gt |GT |ugt |UN | GT |Greater than | 2896 +-------+------------+---------+------------+-------------------------+ 2897 |ge |GT | EQ |uge |UN | GT | EQ|Greater than or equal | 2898 +-------+------------+---------+------------+-------------------------+ 2899 ``` 2900 2901 The standard C comparison operators, `<, <=, >, >=`, are all ordered, 2902 so they are false if either operand is NaN. The C equality operator, 2903 `==`, is ordered, and since inequality is defined as the logical 2904 inverse it is *unordered*. They map to the `floatcc` condition 2905 codes as follows: 2906 2907 ```text 2908 ==== ====== ============ 2909 C `Cond` Subset 2910 ==== ====== ============ 2911 `==` eq EQ 2912 `!=` ne UN | LT | GT 2913 `<` lt LT 2914 `<=` le LT | EQ 2915 `>` gt GT 2916 `>=` ge GT | EQ 2917 ==== ====== ============ 2918 ``` 2919 2920 This subset of condition codes also corresponds to the WebAssembly 2921 floating point comparisons of the same name. 2922 2923 When this instruction compares floating point vectors, it returns a 2924 boolean vector with the results of lane-wise comparisons. 2925 "#, 2926 &formats.float_compare, 2927 ) 2928 .operands_in(vec![Cond, x, y]) 2929 .operands_out(vec![a]), 2930 ); 2931 2932 let f = &Operand::new("f", fflags); 2933 2934 ig.push( 2935 Inst::new( 2936 "ffcmp", 2937 r#" 2938 Floating point comparison returning flags. 2939 2940 Compares two numbers like `fcmp`, but returns floating point CPU 2941 flags instead of testing a specific condition. 2942 "#, 2943 &formats.binary, 2944 ) 2945 .operands_in(vec![x, y]) 2946 .operands_out(vec![f]), 2947 ); 2948 2949 let x = &Operand::new("x", Float); 2950 let y = &Operand::new("y", Float); 2951 let z = &Operand::new("z", Float); 2952 let a = &Operand::new("a", Float).with_doc("Result of applying operator to each lane"); 2953 2954 ig.push( 2955 Inst::new( 2956 "fadd", 2957 r#" 2958 Floating point addition. 2959 "#, 2960 &formats.binary, 2961 ) 2962 .operands_in(vec![x, y]) 2963 .operands_out(vec![a]), 2964 ); 2965 2966 ig.push( 2967 Inst::new( 2968 "fsub", 2969 r#" 2970 Floating point subtraction. 2971 "#, 2972 &formats.binary, 2973 ) 2974 .operands_in(vec![x, y]) 2975 .operands_out(vec![a]), 2976 ); 2977 2978 ig.push( 2979 Inst::new( 2980 "fmul", 2981 r#" 2982 Floating point multiplication. 2983 "#, 2984 &formats.binary, 2985 ) 2986 .operands_in(vec![x, y]) 2987 .operands_out(vec![a]), 2988 ); 2989 2990 ig.push( 2991 Inst::new( 2992 "fdiv", 2993 r#" 2994 Floating point division. 2995 2996 Unlike the integer division instructions ` and 2997 `udiv`, this can't trap. Division by zero is infinity or 2998 NaN, depending on the dividend. 2999 "#, 3000 &formats.binary, 3001 ) 3002 .operands_in(vec![x, y]) 3003 .operands_out(vec![a]), 3004 ); 3005 3006 ig.push( 3007 Inst::new( 3008 "sqrt", 3009 r#" 3010 Floating point square root. 3011 "#, 3012 &formats.unary, 3013 ) 3014 .operands_in(vec![x]) 3015 .operands_out(vec![a]), 3016 ); 3017 3018 ig.push( 3019 Inst::new( 3020 "fma", 3021 r#" 3022 Floating point fused multiply-and-add. 3023 3024 Computes `a := xy+z` without any intermediate rounding of the 3025 product. 3026 "#, 3027 &formats.ternary, 3028 ) 3029 .operands_in(vec![x, y, z]) 3030 .operands_out(vec![a]), 3031 ); 3032 3033 let a = &Operand::new("a", Float).with_doc("``x`` with its sign bit inverted"); 3034 3035 ig.push( 3036 Inst::new( 3037 "fneg", 3038 r#" 3039 Floating point negation. 3040 3041 Note that this is a pure bitwise operation. 3042 "#, 3043 &formats.unary, 3044 ) 3045 .operands_in(vec![x]) 3046 .operands_out(vec![a]), 3047 ); 3048 3049 let a = &Operand::new("a", Float).with_doc("``x`` with its sign bit cleared"); 3050 3051 ig.push( 3052 Inst::new( 3053 "fabs", 3054 r#" 3055 Floating point absolute value. 3056 3057 Note that this is a pure bitwise operation. 3058 "#, 3059 &formats.unary, 3060 ) 3061 .operands_in(vec![x]) 3062 .operands_out(vec![a]), 3063 ); 3064 3065 let a = &Operand::new("a", Float).with_doc("``x`` with its sign bit changed to that of ``y``"); 3066 3067 ig.push( 3068 Inst::new( 3069 "fcopysign", 3070 r#" 3071 Floating point copy sign. 3072 3073 Note that this is a pure bitwise operation. The sign bit from ``y`` is 3074 copied to the sign bit of ``x``. 3075 "#, 3076 &formats.binary, 3077 ) 3078 .operands_in(vec![x, y]) 3079 .operands_out(vec![a]), 3080 ); 3081 3082 let a = &Operand::new("a", Float).with_doc("The smaller of ``x`` and ``y``"); 3083 3084 ig.push( 3085 Inst::new( 3086 "fmin", 3087 r#" 3088 Floating point minimum, propagating NaNs using the WebAssembly rules. 3089 3090 If either operand is NaN, this returns NaN with an unspecified sign. Furthermore, if 3091 each input NaN consists of a mantissa whose most significant bit is 1 and the rest is 3092 0, then the output has the same form. Otherwise, the output mantissa's most significant 3093 bit is 1 and the rest is unspecified. 3094 "#, 3095 &formats.binary, 3096 ) 3097 .operands_in(vec![x, y]) 3098 .operands_out(vec![a]), 3099 ); 3100 3101 ig.push( 3102 Inst::new( 3103 "fmin_pseudo", 3104 r#" 3105 Floating point pseudo-minimum, propagating NaNs. This behaves differently from ``fmin``. 3106 See <https://github.com/WebAssembly/simd/pull/122> for background. 3107 3108 The behaviour is defined as ``fmin_pseudo(a, b) = (b < a) ? b : a``, and the behaviour 3109 for zero or NaN inputs follows from the behaviour of ``<`` with such inputs. 3110 "#, 3111 &formats.binary, 3112 ) 3113 .operands_in(vec![x, y]) 3114 .operands_out(vec![a]), 3115 ); 3116 3117 let a = &Operand::new("a", Float).with_doc("The larger of ``x`` and ``y``"); 3118 3119 ig.push( 3120 Inst::new( 3121 "fmax", 3122 r#" 3123 Floating point maximum, propagating NaNs using the WebAssembly rules. 3124 3125 If either operand is NaN, this returns NaN with an unspecified sign. Furthermore, if 3126 each input NaN consists of a mantissa whose most significant bit is 1 and the rest is 3127 0, then the output has the same form. Otherwise, the output mantissa's most significant 3128 bit is 1 and the rest is unspecified. 3129 "#, 3130 &formats.binary, 3131 ) 3132 .operands_in(vec![x, y]) 3133 .operands_out(vec![a]), 3134 ); 3135 3136 ig.push( 3137 Inst::new( 3138 "fmax_pseudo", 3139 r#" 3140 Floating point pseudo-maximum, propagating NaNs. This behaves differently from ``fmax``. 3141 See <https://github.com/WebAssembly/simd/pull/122> for background. 3142 3143 The behaviour is defined as ``fmax_pseudo(a, b) = (a < b) ? b : a``, and the behaviour 3144 for zero or NaN inputs follows from the behaviour of ``<`` with such inputs. 3145 "#, 3146 &formats.binary, 3147 ) 3148 .operands_in(vec![x, y]) 3149 .operands_out(vec![a]), 3150 ); 3151 3152 let a = &Operand::new("a", Float).with_doc("``x`` rounded to integral value"); 3153 3154 ig.push( 3155 Inst::new( 3156 "ceil", 3157 r#" 3158 Round floating point round to integral, towards positive infinity. 3159 "#, 3160 &formats.unary, 3161 ) 3162 .operands_in(vec![x]) 3163 .operands_out(vec![a]), 3164 ); 3165 3166 ig.push( 3167 Inst::new( 3168 "floor", 3169 r#" 3170 Round floating point round to integral, towards negative infinity. 3171 "#, 3172 &formats.unary, 3173 ) 3174 .operands_in(vec![x]) 3175 .operands_out(vec![a]), 3176 ); 3177 3178 ig.push( 3179 Inst::new( 3180 "trunc", 3181 r#" 3182 Round floating point round to integral, towards zero. 3183 "#, 3184 &formats.unary, 3185 ) 3186 .operands_in(vec![x]) 3187 .operands_out(vec![a]), 3188 ); 3189 3190 ig.push( 3191 Inst::new( 3192 "nearest", 3193 r#" 3194 Round floating point round to integral, towards nearest with ties to 3195 even. 3196 "#, 3197 &formats.unary, 3198 ) 3199 .operands_in(vec![x]) 3200 .operands_out(vec![a]), 3201 ); 3202 3203 let a = &Operand::new("a", b1); 3204 let x = &Operand::new("x", Ref); 3205 3206 ig.push( 3207 Inst::new( 3208 "is_null", 3209 r#" 3210 Reference verification. 3211 3212 The condition code determines if the reference type in question is 3213 null or not. 3214 "#, 3215 &formats.unary, 3216 ) 3217 .operands_in(vec![x]) 3218 .operands_out(vec![a]), 3219 ); 3220 3221 let a = &Operand::new("a", b1); 3222 let x = &Operand::new("x", Ref); 3223 3224 ig.push( 3225 Inst::new( 3226 "is_invalid", 3227 r#" 3228 Reference verification. 3229 3230 The condition code determines if the reference type in question is 3231 invalid or not. 3232 "#, 3233 &formats.unary, 3234 ) 3235 .operands_in(vec![x]) 3236 .operands_out(vec![a]), 3237 ); 3238 3239 let Cond = &Operand::new("Cond", &imm.intcc); 3240 let f = &Operand::new("f", iflags); 3241 let a = &Operand::new("a", b1); 3242 3243 ig.push( 3244 Inst::new( 3245 "trueif", 3246 r#" 3247 Test integer CPU flags for a specific condition. 3248 3249 Check the CPU flags in ``f`` against the ``Cond`` condition code and 3250 return true when the condition code is satisfied. 3251 "#, 3252 &formats.int_cond, 3253 ) 3254 .operands_in(vec![Cond, f]) 3255 .operands_out(vec![a]), 3256 ); 3257 3258 let Cond = &Operand::new("Cond", &imm.floatcc); 3259 let f = &Operand::new("f", fflags); 3260 3261 ig.push( 3262 Inst::new( 3263 "trueff", 3264 r#" 3265 Test floating point CPU flags for a specific condition. 3266 3267 Check the CPU flags in ``f`` against the ``Cond`` condition code and 3268 return true when the condition code is satisfied. 3269 "#, 3270 &formats.float_cond, 3271 ) 3272 .operands_in(vec![Cond, f]) 3273 .operands_out(vec![a]), 3274 ); 3275 3276 let x = &Operand::new("x", Mem); 3277 let a = &Operand::new("a", MemTo).with_doc("Bits of `x` reinterpreted"); 3278 3279 ig.push( 3280 Inst::new( 3281 "bitcast", 3282 r#" 3283 Reinterpret the bits in `x` as a different type. 3284 3285 The input and output types must be storable to memory and of the same 3286 size. A bitcast is equivalent to storing one type and loading the other 3287 type from the same address. 3288 "#, 3289 &formats.unary, 3290 ) 3291 .operands_in(vec![x]) 3292 .operands_out(vec![a]), 3293 ); 3294 3295 let x = &Operand::new("x", Any); 3296 let a = &Operand::new("a", AnyTo).with_doc("Bits of `x` reinterpreted"); 3297 3298 ig.push( 3299 Inst::new( 3300 "raw_bitcast", 3301 r#" 3302 Cast the bits in `x` as a different type of the same bit width. 3303 3304 This instruction does not change the data's representation but allows 3305 data in registers to be used as different types, e.g. an i32x4 as a 3306 b8x16. The only constraint on the result `a` is that it can be 3307 `raw_bitcast` back to the original type. Also, in a raw_bitcast between 3308 vector types with the same number of lanes, the value of each result 3309 lane is a raw_bitcast of the corresponding operand lane. TODO there is 3310 currently no mechanism for enforcing the bit width constraint. 3311 "#, 3312 &formats.unary, 3313 ) 3314 .operands_in(vec![x]) 3315 .operands_out(vec![a]), 3316 ); 3317 3318 let a = &Operand::new("a", TxN).with_doc("A vector value"); 3319 let s = &Operand::new("s", &TxN.lane_of()).with_doc("A scalar value"); 3320 3321 ig.push( 3322 Inst::new( 3323 "scalar_to_vector", 3324 r#" 3325 Copies a scalar value to a vector value. The scalar is copied into the 3326 least significant lane of the vector, and all other lanes will be zero. 3327 "#, 3328 &formats.unary, 3329 ) 3330 .operands_in(vec![s]) 3331 .operands_out(vec![a]), 3332 ); 3333 3334 let Bool = &TypeVar::new( 3335 "Bool", 3336 "A scalar boolean type", 3337 TypeSetBuilder::new().bools(Interval::All).build(), 3338 ); 3339 3340 let BoolTo = &TypeVar::new( 3341 "BoolTo", 3342 "A smaller boolean type", 3343 TypeSetBuilder::new().bools(Interval::All).build(), 3344 ); 3345 3346 let x = &Operand::new("x", Bool); 3347 let a = &Operand::new("a", BoolTo); 3348 3349 ig.push( 3350 Inst::new( 3351 "breduce", 3352 r#" 3353 Convert `x` to a smaller boolean type by discarding the most significant bits. 3354 "#, 3355 &formats.unary, 3356 ) 3357 .operands_in(vec![x]) 3358 .operands_out(vec![a]), 3359 ); 3360 3361 let BoolTo = &TypeVar::new( 3362 "BoolTo", 3363 "A larger boolean type", 3364 TypeSetBuilder::new().bools(Interval::All).build(), 3365 ); 3366 let x = &Operand::new("x", Bool); 3367 let a = &Operand::new("a", BoolTo); 3368 3369 ig.push( 3370 Inst::new( 3371 "bextend", 3372 r#" 3373 Convert `x` to a larger boolean type 3374 "#, 3375 &formats.unary, 3376 ) 3377 .operands_in(vec![x]) 3378 .operands_out(vec![a]), 3379 ); 3380 3381 let IntTo = &TypeVar::new( 3382 "IntTo", 3383 "A scalar integer type", 3384 TypeSetBuilder::new().ints(Interval::All).build(), 3385 ); 3386 let x = &Operand::new("x", ScalarBool); 3387 let a = &Operand::new("a", IntTo); 3388 3389 ig.push( 3390 Inst::new( 3391 "bint", 3392 r#" 3393 Convert `x` to an integer. 3394 3395 True maps to 1 and false maps to 0. 3396 "#, 3397 &formats.unary, 3398 ) 3399 .operands_in(vec![x]) 3400 .operands_out(vec![a]), 3401 ); 3402 3403 let Bool = &TypeVar::new( 3404 "Bool", 3405 "A scalar or vector boolean type", 3406 TypeSetBuilder::new() 3407 .bools(Interval::All) 3408 .simd_lanes(Interval::All) 3409 .build(), 3410 ); 3411 let IntTo = &TypeVar::new( 3412 "IntTo", 3413 "An integer type with the same number of lanes", 3414 TypeSetBuilder::new() 3415 .ints(Interval::All) 3416 .simd_lanes(Interval::All) 3417 .build(), 3418 ); 3419 let x = &Operand::new("x", Bool); 3420 let a = &Operand::new("a", IntTo); 3421 3422 ig.push( 3423 Inst::new( 3424 "bmask", 3425 r#" 3426 Convert `x` to an integer mask. 3427 3428 True maps to all 1s and false maps to all 0s. The result type must have 3429 the same number of vector lanes as the input. 3430 "#, 3431 &formats.unary, 3432 ) 3433 .operands_in(vec![x]) 3434 .operands_out(vec![a]), 3435 ); 3436 3437 let Int = &TypeVar::new( 3438 "Int", 3439 "A scalar integer type", 3440 TypeSetBuilder::new().ints(Interval::All).build(), 3441 ); 3442 3443 let IntTo = &TypeVar::new( 3444 "IntTo", 3445 "A smaller integer type", 3446 TypeSetBuilder::new().ints(Interval::All).build(), 3447 ); 3448 let x = &Operand::new("x", Int); 3449 let a = &Operand::new("a", IntTo); 3450 3451 ig.push( 3452 Inst::new( 3453 "ireduce", 3454 r#" 3455 Convert `x` to a smaller integer type by discarding 3456 the most significant bits. 3457 3458 This is the same as reducing modulo `2^n`. 3459 "#, 3460 &formats.unary, 3461 ) 3462 .operands_in(vec![x]) 3463 .operands_out(vec![a]), 3464 ); 3465 3466 let I16or32or64xN = &TypeVar::new( 3467 "I16or32or64xN", 3468 "A SIMD vector type containing integer lanes 16, 32, or 64 bits wide", 3469 TypeSetBuilder::new() 3470 .ints(16..64) 3471 .simd_lanes(2..8) 3472 .dynamic_simd_lanes(2..8) 3473 .includes_scalars(false) 3474 .build(), 3475 ); 3476 3477 let x = &Operand::new("x", I16or32or64xN); 3478 let y = &Operand::new("y", I16or32or64xN); 3479 let a = &Operand::new("a", &I16or32or64xN.split_lanes()); 3480 3481 ig.push( 3482 Inst::new( 3483 "snarrow", 3484 r#" 3485 Combine `x` and `y` into a vector with twice the lanes but half the integer width while 3486 saturating overflowing values to the signed maximum and minimum. 3487 3488 The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4` 3489 and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value 3490 returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`. 3491 "#, 3492 &formats.binary, 3493 ) 3494 .operands_in(vec![x, y]) 3495 .operands_out(vec![a]), 3496 ); 3497 3498 ig.push( 3499 Inst::new( 3500 "unarrow", 3501 r#" 3502 Combine `x` and `y` into a vector with twice the lanes but half the integer width while 3503 saturating overflowing values to the unsigned maximum and minimum. 3504 3505 Note that all input lanes are considered signed: any negative lanes will overflow and be 3506 replaced with the unsigned minimum, `0x00`. 3507 3508 The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4` 3509 and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value 3510 returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`. 3511 "#, 3512 &formats.binary, 3513 ) 3514 .operands_in(vec![x, y]) 3515 .operands_out(vec![a]), 3516 ); 3517 3518 ig.push( 3519 Inst::new( 3520 "uunarrow", 3521 r#" 3522 Combine `x` and `y` into a vector with twice the lanes but half the integer width while 3523 saturating overflowing values to the unsigned maximum and minimum. 3524 3525 Note that all input lanes are considered unsigned: any negative values will be interpreted as unsigned, overflowing and being replaced with the unsigned maximum. 3526 3527 The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4` 3528 and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value 3529 returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`. 3530 "#, 3531 &formats.binary, 3532 ) 3533 .operands_in(vec![x, y]) 3534 .operands_out(vec![a]), 3535 ); 3536 3537 let I8or16or32xN = &TypeVar::new( 3538 "I8or16or32xN", 3539 "A SIMD vector type containing integer lanes 8, 16, or 32 bits wide.", 3540 TypeSetBuilder::new() 3541 .ints(8..32) 3542 .simd_lanes(2..16) 3543 .dynamic_simd_lanes(2..16) 3544 .includes_scalars(false) 3545 .build(), 3546 ); 3547 3548 let x = &Operand::new("x", I8or16or32xN); 3549 let a = &Operand::new("a", &I8or16or32xN.merge_lanes()); 3550 3551 ig.push( 3552 Inst::new( 3553 "swiden_low", 3554 r#" 3555 Widen the low lanes of `x` using signed extension. 3556 3557 This will double the lane width and halve the number of lanes. 3558 "#, 3559 &formats.unary, 3560 ) 3561 .operands_in(vec![x]) 3562 .operands_out(vec![a]), 3563 ); 3564 3565 ig.push( 3566 Inst::new( 3567 "swiden_high", 3568 r#" 3569 Widen the high lanes of `x` using signed extension. 3570 3571 This will double the lane width and halve the number of lanes. 3572 "#, 3573 &formats.unary, 3574 ) 3575 .operands_in(vec![x]) 3576 .operands_out(vec![a]), 3577 ); 3578 3579 ig.push( 3580 Inst::new( 3581 "uwiden_low", 3582 r#" 3583 Widen the low lanes of `x` using unsigned extension. 3584 3585 This will double the lane width and halve the number of lanes. 3586 "#, 3587 &formats.unary, 3588 ) 3589 .operands_in(vec![x]) 3590 .operands_out(vec![a]), 3591 ); 3592 3593 ig.push( 3594 Inst::new( 3595 "uwiden_high", 3596 r#" 3597 Widen the high lanes of `x` using unsigned extension. 3598 3599 This will double the lane width and halve the number of lanes. 3600 "#, 3601 &formats.unary, 3602 ) 3603 .operands_in(vec![x]) 3604 .operands_out(vec![a]), 3605 ); 3606 3607 let x = &Operand::new("x", I8or16or32xN); 3608 let y = &Operand::new("y", I8or16or32xN); 3609 let a = &Operand::new("a", I8or16or32xN); 3610 3611 ig.push( 3612 Inst::new( 3613 "iadd_pairwise", 3614 r#" 3615 Does lane-wise integer pairwise addition on two operands, putting the 3616 combined results into a single vector result. Here a pair refers to adjacent 3617 lanes in a vector, i.e. i*2 + (i*2+1) for i == num_lanes/2. The first operand 3618 pairwise add results will make up the low half of the resulting vector while 3619 the second operand pairwise add results will make up the upper half of the 3620 resulting vector. 3621 "#, 3622 &formats.binary, 3623 ) 3624 .operands_in(vec![x, y]) 3625 .operands_out(vec![a]), 3626 ); 3627 3628 let I16x8 = &TypeVar::new( 3629 "I16x8", 3630 "A SIMD vector type containing 8 integer lanes each 16 bits wide.", 3631 TypeSetBuilder::new() 3632 .ints(16..16) 3633 .simd_lanes(8..8) 3634 .includes_scalars(false) 3635 .build(), 3636 ); 3637 3638 let x = &Operand::new("x", I16x8); 3639 let y = &Operand::new("y", I16x8); 3640 let a = &Operand::new("a", &I16x8.merge_lanes()); 3641 3642 ig.push( 3643 Inst::new( 3644 "widening_pairwise_dot_product_s", 3645 r#" 3646 Takes corresponding elements in `x` and `y`, performs a sign-extending length-doubling 3647 multiplication on them, then adds adjacent pairs of elements to form the result. For 3648 example, if the input vectors are `[x3, x2, x1, x0]` and `[y3, y2, y1, y0]`, it produces 3649 the vector `[r1, r0]`, where `r1 = sx(x3) * sx(y3) + sx(x2) * sx(y2)` and 3650 `r0 = sx(x1) * sx(y1) + sx(x0) * sx(y0)`, and `sx(n)` sign-extends `n` to twice its width. 3651 3652 This will double the lane width and halve the number of lanes. So the resulting 3653 vector has the same number of bits as `x` and `y` do (individually). 3654 3655 See <https://github.com/WebAssembly/simd/pull/127> for background info. 3656 "#, 3657 &formats.binary, 3658 ) 3659 .operands_in(vec![x, y]) 3660 .operands_out(vec![a]), 3661 ); 3662 3663 let IntTo = &TypeVar::new( 3664 "IntTo", 3665 "A larger integer type with the same number of lanes", 3666 TypeSetBuilder::new() 3667 .ints(Interval::All) 3668 .simd_lanes(Interval::All) 3669 .build(), 3670 ); 3671 let x = &Operand::new("x", Int); 3672 let a = &Operand::new("a", IntTo); 3673 3674 ig.push( 3675 Inst::new( 3676 "uextend", 3677 r#" 3678 Convert `x` to a larger integer type by zero-extending. 3679 3680 Each lane in `x` is converted to a larger integer type by adding 3681 zeroes. The result has the same numerical value as `x` when both are 3682 interpreted as unsigned integers. 3683 3684 The result type must have the same number of vector lanes as the input, 3685 and each lane must not have fewer bits that the input lanes. If the 3686 input and output types are the same, this is a no-op. 3687 "#, 3688 &formats.unary, 3689 ) 3690 .operands_in(vec![x]) 3691 .operands_out(vec![a]), 3692 ); 3693 3694 ig.push( 3695 Inst::new( 3696 "sextend", 3697 r#" 3698 Convert `x` to a larger integer type by sign-extending. 3699 3700 Each lane in `x` is converted to a larger integer type by replicating 3701 the sign bit. The result has the same numerical value as `x` when both 3702 are interpreted as signed integers. 3703 3704 The result type must have the same number of vector lanes as the input, 3705 and each lane must not have fewer bits that the input lanes. If the 3706 input and output types are the same, this is a no-op. 3707 "#, 3708 &formats.unary, 3709 ) 3710 .operands_in(vec![x]) 3711 .operands_out(vec![a]), 3712 ); 3713 3714 let FloatTo = &TypeVar::new( 3715 "FloatTo", 3716 "A scalar or vector floating point number", 3717 TypeSetBuilder::new() 3718 .floats(Interval::All) 3719 .simd_lanes(Interval::All) 3720 .build(), 3721 ); 3722 let x = &Operand::new("x", Float); 3723 let a = &Operand::new("a", FloatTo); 3724 3725 ig.push( 3726 Inst::new( 3727 "fpromote", 3728 r#" 3729 Convert `x` to a larger floating point format. 3730 3731 Each lane in `x` is converted to the destination floating point format. 3732 This is an exact operation. 3733 3734 Cranelift currently only supports two floating point formats 3735 - `f32` and `f64`. This may change in the future. 3736 3737 The result type must have the same number of vector lanes as the input, 3738 and the result lanes must not have fewer bits than the input lanes. If 3739 the input and output types are the same, this is a no-op. 3740 "#, 3741 &formats.unary, 3742 ) 3743 .operands_in(vec![x]) 3744 .operands_out(vec![a]), 3745 ); 3746 3747 ig.push( 3748 Inst::new( 3749 "fdemote", 3750 r#" 3751 Convert `x` to a smaller floating point format. 3752 3753 Each lane in `x` is converted to the destination floating point format 3754 by rounding to nearest, ties to even. 3755 3756 Cranelift currently only supports two floating point formats 3757 - `f32` and `f64`. This may change in the future. 3758 3759 The result type must have the same number of vector lanes as the input, 3760 and the result lanes must not have more bits than the input lanes. If 3761 the input and output types are the same, this is a no-op. 3762 "#, 3763 &formats.unary, 3764 ) 3765 .operands_in(vec![x]) 3766 .operands_out(vec![a]), 3767 ); 3768 3769 let F64x2 = &TypeVar::new( 3770 "F64x2", 3771 "A SIMD vector type consisting of 2 lanes of 64-bit floats", 3772 TypeSetBuilder::new() 3773 .floats(64..64) 3774 .simd_lanes(2..2) 3775 .includes_scalars(false) 3776 .build(), 3777 ); 3778 let F32x4 = &TypeVar::new( 3779 "F32x4", 3780 "A SIMD vector type consisting of 4 lanes of 32-bit floats", 3781 TypeSetBuilder::new() 3782 .floats(32..32) 3783 .simd_lanes(4..4) 3784 .includes_scalars(false) 3785 .build(), 3786 ); 3787 3788 let x = &Operand::new("x", F64x2); 3789 let a = &Operand::new("a", F32x4); 3790 3791 ig.push( 3792 Inst::new( 3793 "fvdemote", 3794 r#" 3795 Convert `x` to a smaller floating point format. 3796 3797 Each lane in `x` is converted to the destination floating point format 3798 by rounding to nearest, ties to even. 3799 3800 Cranelift currently only supports two floating point formats 3801 - `f32` and `f64`. This may change in the future. 3802 3803 Fvdemote differs from fdemote in that with fvdemote it targets vectors. 3804 Fvdemote is constrained to having the input type being F64x2 and the result 3805 type being F32x4. The result lane that was the upper half of the input lane 3806 is initialized to zero. 3807 "#, 3808 &formats.unary, 3809 ) 3810 .operands_in(vec![x]) 3811 .operands_out(vec![a]), 3812 ); 3813 3814 ig.push( 3815 Inst::new( 3816 "fvpromote_low", 3817 r#" 3818 Converts packed single precision floating point to packed double precision floating point. 3819 3820 Considering only the lower half of the register, the low lanes in `x` are interpreted as 3821 single precision floats that are then converted to a double precision floats. 3822 3823 The result type will have half the number of vector lanes as the input. Fvpromote_low is 3824 constrained to input F32x4 with a result type of F64x2. 3825 "#, 3826 &formats.unary, 3827 ) 3828 .operands_in(vec![a]) 3829 .operands_out(vec![x]), 3830 ); 3831 3832 let x = &Operand::new("x", Float); 3833 let a = &Operand::new("a", IntTo); 3834 3835 ig.push( 3836 Inst::new( 3837 "fcvt_to_uint", 3838 r#" 3839 Convert floating point to unsigned integer. 3840 3841 Each lane in `x` is converted to an unsigned integer by rounding 3842 towards zero. If `x` is NaN or if the unsigned integral value cannot be 3843 represented in the result type, this instruction traps. 3844 3845 The result type must have the same number of vector lanes as the input. 3846 "#, 3847 &formats.unary, 3848 ) 3849 .operands_in(vec![x]) 3850 .operands_out(vec![a]) 3851 .can_trap(true), 3852 ); 3853 3854 ig.push( 3855 Inst::new( 3856 "fcvt_to_uint_sat", 3857 r#" 3858 Convert floating point to unsigned integer as fcvt_to_uint does, but 3859 saturates the input instead of trapping. NaN and negative values are 3860 converted to 0. 3861 "#, 3862 &formats.unary, 3863 ) 3864 .operands_in(vec![x]) 3865 .operands_out(vec![a]), 3866 ); 3867 3868 ig.push( 3869 Inst::new( 3870 "fcvt_to_sint", 3871 r#" 3872 Convert floating point to signed integer. 3873 3874 Each lane in `x` is converted to a signed integer by rounding towards 3875 zero. If `x` is NaN or if the signed integral value cannot be 3876 represented in the result type, this instruction traps. 3877 3878 The result type must have the same number of vector lanes as the input. 3879 "#, 3880 &formats.unary, 3881 ) 3882 .operands_in(vec![x]) 3883 .operands_out(vec![a]) 3884 .can_trap(true), 3885 ); 3886 3887 ig.push( 3888 Inst::new( 3889 "fcvt_to_sint_sat", 3890 r#" 3891 Convert floating point to signed integer as fcvt_to_sint does, but 3892 saturates the input instead of trapping. NaN values are converted to 0. 3893 "#, 3894 &formats.unary, 3895 ) 3896 .operands_in(vec![x]) 3897 .operands_out(vec![a]), 3898 ); 3899 3900 let Int = &TypeVar::new( 3901 "Int", 3902 "A scalar or vector integer type", 3903 TypeSetBuilder::new() 3904 .ints(Interval::All) 3905 .simd_lanes(Interval::All) 3906 .build(), 3907 ); 3908 let x = &Operand::new("x", Int); 3909 let a = &Operand::new("a", FloatTo); 3910 3911 ig.push( 3912 Inst::new( 3913 "fcvt_from_uint", 3914 r#" 3915 Convert unsigned integer to floating point. 3916 3917 Each lane in `x` is interpreted as an unsigned integer and converted to 3918 floating point using round to nearest, ties to even. 3919 3920 The result type must have the same number of vector lanes as the input. 3921 "#, 3922 &formats.unary, 3923 ) 3924 .operands_in(vec![x]) 3925 .operands_out(vec![a]), 3926 ); 3927 3928 ig.push( 3929 Inst::new( 3930 "fcvt_from_sint", 3931 r#" 3932 Convert signed integer to floating point. 3933 3934 Each lane in `x` is interpreted as a signed integer and converted to 3935 floating point using round to nearest, ties to even. 3936 3937 The result type must have the same number of vector lanes as the input. 3938 "#, 3939 &formats.unary, 3940 ) 3941 .operands_in(vec![x]) 3942 .operands_out(vec![a]), 3943 ); 3944 3945 ig.push( 3946 Inst::new( 3947 "fcvt_low_from_sint", 3948 r#" 3949 Converts packed signed 32-bit integers to packed double precision floating point. 3950 3951 Considering only the low half of the register, each lane in `x` is interpreted as a 3952 signed 32-bit integer that is then converted to a double precision float. This 3953 instruction differs from fcvt_from_sint in that it converts half the number of lanes 3954 which are converted to occupy twice the number of bits. No rounding should be needed 3955 for the resulting float. 3956 3957 The result type will have half the number of vector lanes as the input. 3958 "#, 3959 &formats.unary, 3960 ) 3961 .operands_in(vec![x]) 3962 .operands_out(vec![a]), 3963 ); 3964 3965 let WideInt = &TypeVar::new( 3966 "WideInt", 3967 "An integer type with lanes from `i16` upwards", 3968 TypeSetBuilder::new() 3969 .ints(16..128) 3970 .simd_lanes(Interval::All) 3971 .build(), 3972 ); 3973 let x = &Operand::new("x", WideInt); 3974 let lo = &Operand::new("lo", &WideInt.half_width()).with_doc("The low bits of `x`"); 3975 let hi = &Operand::new("hi", &WideInt.half_width()).with_doc("The high bits of `x`"); 3976 3977 ig.push( 3978 Inst::new( 3979 "isplit", 3980 r#" 3981 Split an integer into low and high parts. 3982 3983 Vectors of integers are split lane-wise, so the results have the same 3984 number of lanes as the input, but the lanes are half the size. 3985 3986 Returns the low half of `x` and the high half of `x` as two independent 3987 values. 3988 "#, 3989 &formats.unary, 3990 ) 3991 .operands_in(vec![x]) 3992 .operands_out(vec![lo, hi]), 3993 ); 3994 3995 let NarrowInt = &TypeVar::new( 3996 "NarrowInt", 3997 "An integer type with lanes type to `i64`", 3998 TypeSetBuilder::new() 3999 .ints(8..64) 4000 .simd_lanes(Interval::All) 4001 .build(), 4002 ); 4003 4004 let lo = &Operand::new("lo", NarrowInt); 4005 let hi = &Operand::new("hi", NarrowInt); 4006 let a = &Operand::new("a", &NarrowInt.double_width()) 4007 .with_doc("The concatenation of `lo` and `hi`"); 4008 4009 ig.push( 4010 Inst::new( 4011 "iconcat", 4012 r#" 4013 Concatenate low and high bits to form a larger integer type. 4014 4015 Vectors of integers are concatenated lane-wise such that the result has 4016 the same number of lanes as the inputs, but the lanes are twice the 4017 size. 4018 "#, 4019 &formats.binary, 4020 ) 4021 .operands_in(vec![lo, hi]) 4022 .operands_out(vec![a]), 4023 ); 4024 4025 // Instructions relating to atomic memory accesses and fences 4026 let AtomicMem = &TypeVar::new( 4027 "AtomicMem", 4028 "Any type that can be stored in memory, which can be used in an atomic operation", 4029 TypeSetBuilder::new().ints(8..64).build(), 4030 ); 4031 let x = &Operand::new("x", AtomicMem).with_doc("Value to be atomically stored"); 4032 let a = &Operand::new("a", AtomicMem).with_doc("Value atomically loaded"); 4033 let e = &Operand::new("e", AtomicMem).with_doc("Expected value in CAS"); 4034 let p = &Operand::new("p", iAddr); 4035 let MemFlags = &Operand::new("MemFlags", &imm.memflags); 4036 let AtomicRmwOp = &Operand::new("AtomicRmwOp", &imm.atomic_rmw_op); 4037 4038 ig.push( 4039 Inst::new( 4040 "atomic_rmw", 4041 r#" 4042 Atomically read-modify-write memory at `p`, with second operand `x`. The old value is 4043 returned. `p` has the type of the target word size, and `x` may be an integer type of 4044 8, 16, 32 or 64 bits, even on a 32-bit target. The type of the returned value is the 4045 same as the type of `x`. This operation is sequentially consistent and creates 4046 happens-before edges that order normal (non-atomic) loads and stores. 4047 "#, 4048 &formats.atomic_rmw, 4049 ) 4050 .operands_in(vec![MemFlags, AtomicRmwOp, p, x]) 4051 .operands_out(vec![a]) 4052 .can_load(true) 4053 .can_store(true) 4054 .other_side_effects(true), 4055 ); 4056 4057 ig.push( 4058 Inst::new( 4059 "atomic_cas", 4060 r#" 4061 Perform an atomic compare-and-swap operation on memory at `p`, with expected value `e`, 4062 storing `x` if the value at `p` equals `e`. The old value at `p` is returned, 4063 regardless of whether the operation succeeds or fails. `p` has the type of the target 4064 word size, and `x` and `e` must have the same type and the same size, which may be an 4065 integer type of 8, 16, 32 or 64 bits, even on a 32-bit target. The type of the returned 4066 value is the same as the type of `x` and `e`. This operation is sequentially 4067 consistent and creates happens-before edges that order normal (non-atomic) loads and 4068 stores. 4069 "#, 4070 &formats.atomic_cas, 4071 ) 4072 .operands_in(vec![MemFlags, p, e, x]) 4073 .operands_out(vec![a]) 4074 .can_load(true) 4075 .can_store(true) 4076 .other_side_effects(true), 4077 ); 4078 4079 ig.push( 4080 Inst::new( 4081 "atomic_load", 4082 r#" 4083 Atomically load from memory at `p`. 4084 4085 This is a polymorphic instruction that can load any value type which has a memory 4086 representation. It should only be used for integer types with 8, 16, 32 or 64 bits. 4087 This operation is sequentially consistent and creates happens-before edges that order 4088 normal (non-atomic) loads and stores. 4089 "#, 4090 &formats.load_no_offset, 4091 ) 4092 .operands_in(vec![MemFlags, p]) 4093 .operands_out(vec![a]) 4094 .can_load(true) 4095 .other_side_effects(true), 4096 ); 4097 4098 ig.push( 4099 Inst::new( 4100 "atomic_store", 4101 r#" 4102 Atomically store `x` to memory at `p`. 4103 4104 This is a polymorphic instruction that can store any value type with a memory 4105 representation. It should only be used for integer types with 8, 16, 32 or 64 bits. 4106 This operation is sequentially consistent and creates happens-before edges that order 4107 normal (non-atomic) loads and stores. 4108 "#, 4109 &formats.store_no_offset, 4110 ) 4111 .operands_in(vec![MemFlags, x, p]) 4112 .can_store(true) 4113 .other_side_effects(true), 4114 ); 4115 4116 ig.push( 4117 Inst::new( 4118 "fence", 4119 r#" 4120 A memory fence. This must provide ordering to ensure that, at a minimum, neither loads 4121 nor stores of any kind may move forwards or backwards across the fence. This operation 4122 is sequentially consistent. 4123 "#, 4124 &formats.nullary, 4125 ) 4126 .other_side_effects(true), 4127 ); 4128 4129 let TxN = &TypeVar::new( 4130 "TxN", 4131 "A dynamic vector type", 4132 TypeSetBuilder::new() 4133 .ints(Interval::All) 4134 .floats(Interval::All) 4135 .bools(Interval::All) 4136 .dynamic_simd_lanes(Interval::All) 4137 .build(), 4138 ); 4139 let x = &Operand::new("x", TxN).with_doc("The dynamic vector to extract from"); 4140 let y = &Operand::new("y", &imm.uimm8).with_doc("128-bit vector index"); 4141 let a = &Operand::new("a", &TxN.dynamic_to_vector()).with_doc("New fixed vector"); 4142 4143 ig.push( 4144 Inst::new( 4145 "extract_vector", 4146 r#" 4147 Return a fixed length sub vector, extracted from a dynamic vector. 4148 "#, 4149 &formats.binary_imm8, 4150 ) 4151 .operands_in(vec![x, y]) 4152 .operands_out(vec![a]), 4153 ); 4154 } 4155