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 a sign extended 64 bit 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 a sign extended 64 bit 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 Same as `imul`, but one operand is a sign extended 64 bit immediate constant. 2081 2082 Polymorphic over all scalar integer types, but does not support vector 2083 types. 2084 "#, 2085 &formats.binary_imm64, 2086 ) 2087 .operands_in(vec![x, Y]) 2088 .operands_out(vec![a]), 2089 ); 2090 2091 ig.push( 2092 Inst::new( 2093 "udiv_imm", 2094 r#" 2095 Unsigned integer division by an immediate constant. 2096 2097 Same as `udiv`, but one operand is a zero extended 64 bit immediate constant. 2098 2099 This operation traps if the divisor is zero. 2100 "#, 2101 &formats.binary_imm64, 2102 ) 2103 .operands_in(vec![x, Y]) 2104 .operands_out(vec![a]), 2105 ); 2106 2107 ig.push( 2108 Inst::new( 2109 "sdiv_imm", 2110 r#" 2111 Signed integer division by an immediate constant. 2112 2113 Same as `sdiv`, but one operand is a sign extended 64 bit immediate constant. 2114 2115 This operation traps if the divisor is zero, or if the result is not 2116 representable in `B` bits two's complement. This only happens 2117 when `x = -2^{B-1}, Y = -1`. 2118 "#, 2119 &formats.binary_imm64, 2120 ) 2121 .operands_in(vec![x, Y]) 2122 .operands_out(vec![a]), 2123 ); 2124 2125 ig.push( 2126 Inst::new( 2127 "urem_imm", 2128 r#" 2129 Unsigned integer remainder with immediate divisor. 2130 2131 Same as `urem`, but one operand is a zero extended 64 bit immediate constant. 2132 2133 This operation traps if the divisor is zero. 2134 "#, 2135 &formats.binary_imm64, 2136 ) 2137 .operands_in(vec![x, Y]) 2138 .operands_out(vec![a]), 2139 ); 2140 2141 ig.push( 2142 Inst::new( 2143 "srem_imm", 2144 r#" 2145 Signed integer remainder with immediate divisor. 2146 2147 Same as `srem`, but one operand is a sign extended 64 bit immediate constant. 2148 2149 This operation traps if the divisor is zero. 2150 "#, 2151 &formats.binary_imm64, 2152 ) 2153 .operands_in(vec![x, Y]) 2154 .operands_out(vec![a]), 2155 ); 2156 2157 ig.push( 2158 Inst::new( 2159 "irsub_imm", 2160 r#" 2161 Immediate reverse wrapping subtraction: `a := Y - x \pmod{2^B}`. 2162 2163 The immediate operand is a sign extended 64 bit constant. 2164 2165 Also works as integer negation when `Y = 0`. Use `iadd_imm` 2166 with a negative immediate operand for the reverse immediate 2167 subtraction. 2168 2169 Polymorphic over all scalar integer types, but does not support vector 2170 types. 2171 "#, 2172 &formats.binary_imm64, 2173 ) 2174 .operands_in(vec![x, Y]) 2175 .operands_out(vec![a]), 2176 ); 2177 2178 let a = &Operand::new("a", iB); 2179 let x = &Operand::new("x", iB); 2180 let y = &Operand::new("y", iB); 2181 2182 let c_in = &Operand::new("c_in", b1).with_doc("Input carry flag"); 2183 let c_out = &Operand::new("c_out", b1).with_doc("Output carry flag"); 2184 let b_in = &Operand::new("b_in", b1).with_doc("Input borrow flag"); 2185 let b_out = &Operand::new("b_out", b1).with_doc("Output borrow flag"); 2186 2187 let c_if_in = &Operand::new("c_in", iflags); 2188 let c_if_out = &Operand::new("c_out", iflags); 2189 let b_if_in = &Operand::new("b_in", iflags); 2190 let b_if_out = &Operand::new("b_out", iflags); 2191 2192 ig.push( 2193 Inst::new( 2194 "iadd_cin", 2195 r#" 2196 Add integers with carry in. 2197 2198 Same as `iadd` with an additional carry input. Computes: 2199 2200 ```text 2201 a = x + y + c_{in} \pmod 2^B 2202 ``` 2203 2204 Polymorphic over all scalar integer types, but does not support vector 2205 types. 2206 "#, 2207 &formats.ternary, 2208 ) 2209 .operands_in(vec![x, y, c_in]) 2210 .operands_out(vec![a]), 2211 ); 2212 2213 ig.push( 2214 Inst::new( 2215 "iadd_ifcin", 2216 r#" 2217 Add integers with carry in. 2218 2219 Same as `iadd` with an additional carry flag input. Computes: 2220 2221 ```text 2222 a = x + y + c_{in} \pmod 2^B 2223 ``` 2224 2225 Polymorphic over all scalar integer types, but does not support vector 2226 types. 2227 "#, 2228 &formats.ternary, 2229 ) 2230 .operands_in(vec![x, y, c_if_in]) 2231 .operands_out(vec![a]), 2232 ); 2233 2234 ig.push( 2235 Inst::new( 2236 "iadd_cout", 2237 r#" 2238 Add integers with carry out. 2239 2240 Same as `iadd` with an additional carry output. 2241 2242 ```text 2243 a &= x + y \pmod 2^B \\ 2244 c_{out} &= x+y >= 2^B 2245 ``` 2246 2247 Polymorphic over all scalar integer types, but does not support vector 2248 types. 2249 "#, 2250 &formats.binary, 2251 ) 2252 .operands_in(vec![x, y]) 2253 .operands_out(vec![a, c_out]), 2254 ); 2255 2256 ig.push( 2257 Inst::new( 2258 "iadd_ifcout", 2259 r#" 2260 Add integers with carry out. 2261 2262 Same as `iadd` with an additional carry flag output. 2263 2264 ```text 2265 a &= x + y \pmod 2^B \\ 2266 c_{out} &= x+y >= 2^B 2267 ``` 2268 2269 Polymorphic over all scalar integer types, but does not support vector 2270 types. 2271 "#, 2272 &formats.binary, 2273 ) 2274 .operands_in(vec![x, y]) 2275 .operands_out(vec![a, c_if_out]), 2276 ); 2277 2278 ig.push( 2279 Inst::new( 2280 "iadd_carry", 2281 r#" 2282 Add integers with carry in and out. 2283 2284 Same as `iadd` with an additional carry input and output. 2285 2286 ```text 2287 a &= x + y + c_{in} \pmod 2^B \\ 2288 c_{out} &= x + y + c_{in} >= 2^B 2289 ``` 2290 2291 Polymorphic over all scalar integer types, but does not support vector 2292 types. 2293 "#, 2294 &formats.ternary, 2295 ) 2296 .operands_in(vec![x, y, c_in]) 2297 .operands_out(vec![a, c_out]), 2298 ); 2299 2300 ig.push( 2301 Inst::new( 2302 "iadd_ifcarry", 2303 r#" 2304 Add integers with carry in and out. 2305 2306 Same as `iadd` with an additional carry flag input and output. 2307 2308 ```text 2309 a &= x + y + c_{in} \pmod 2^B \\ 2310 c_{out} &= x + y + c_{in} >= 2^B 2311 ``` 2312 2313 Polymorphic over all scalar integer types, but does not support vector 2314 types. 2315 "#, 2316 &formats.ternary, 2317 ) 2318 .operands_in(vec![x, y, c_if_in]) 2319 .operands_out(vec![a, c_if_out]), 2320 ); 2321 2322 ig.push( 2323 Inst::new( 2324 "isub_bin", 2325 r#" 2326 Subtract integers with borrow in. 2327 2328 Same as `isub` with an additional borrow flag input. Computes: 2329 2330 ```text 2331 a = x - (y + b_{in}) \pmod 2^B 2332 ``` 2333 2334 Polymorphic over all scalar integer types, but does not support vector 2335 types. 2336 "#, 2337 &formats.ternary, 2338 ) 2339 .operands_in(vec![x, y, b_in]) 2340 .operands_out(vec![a]), 2341 ); 2342 2343 ig.push( 2344 Inst::new( 2345 "isub_ifbin", 2346 r#" 2347 Subtract integers with borrow in. 2348 2349 Same as `isub` with an additional borrow flag input. Computes: 2350 2351 ```text 2352 a = x - (y + b_{in}) \pmod 2^B 2353 ``` 2354 2355 Polymorphic over all scalar integer types, but does not support vector 2356 types. 2357 "#, 2358 &formats.ternary, 2359 ) 2360 .operands_in(vec![x, y, b_if_in]) 2361 .operands_out(vec![a]), 2362 ); 2363 2364 ig.push( 2365 Inst::new( 2366 "isub_bout", 2367 r#" 2368 Subtract integers with borrow out. 2369 2370 Same as `isub` with an additional borrow flag output. 2371 2372 ```text 2373 a &= x - y \pmod 2^B \\ 2374 b_{out} &= x < y 2375 ``` 2376 2377 Polymorphic over all scalar integer types, but does not support vector 2378 types. 2379 "#, 2380 &formats.binary, 2381 ) 2382 .operands_in(vec![x, y]) 2383 .operands_out(vec![a, b_out]), 2384 ); 2385 2386 ig.push( 2387 Inst::new( 2388 "isub_ifbout", 2389 r#" 2390 Subtract integers with borrow out. 2391 2392 Same as `isub` with an additional borrow flag output. 2393 2394 ```text 2395 a &= x - y \pmod 2^B \\ 2396 b_{out} &= x < y 2397 ``` 2398 2399 Polymorphic over all scalar integer types, but does not support vector 2400 types. 2401 "#, 2402 &formats.binary, 2403 ) 2404 .operands_in(vec![x, y]) 2405 .operands_out(vec![a, b_if_out]), 2406 ); 2407 2408 ig.push( 2409 Inst::new( 2410 "isub_borrow", 2411 r#" 2412 Subtract integers with borrow in and out. 2413 2414 Same as `isub` with an additional borrow flag input and output. 2415 2416 ```text 2417 a &= x - (y + b_{in}) \pmod 2^B \\ 2418 b_{out} &= x < y + b_{in} 2419 ``` 2420 2421 Polymorphic over all scalar integer types, but does not support vector 2422 types. 2423 "#, 2424 &formats.ternary, 2425 ) 2426 .operands_in(vec![x, y, b_in]) 2427 .operands_out(vec![a, b_out]), 2428 ); 2429 2430 ig.push( 2431 Inst::new( 2432 "isub_ifborrow", 2433 r#" 2434 Subtract integers with borrow in and out. 2435 2436 Same as `isub` with an additional borrow flag input and output. 2437 2438 ```text 2439 a &= x - (y + b_{in}) \pmod 2^B \\ 2440 b_{out} &= x < y + b_{in} 2441 ``` 2442 2443 Polymorphic over all scalar integer types, but does not support vector 2444 types. 2445 "#, 2446 &formats.ternary, 2447 ) 2448 .operands_in(vec![x, y, b_if_in]) 2449 .operands_out(vec![a, b_if_out]), 2450 ); 2451 2452 let bits = &TypeVar::new( 2453 "bits", 2454 "Any integer, float, or boolean scalar or vector type", 2455 TypeSetBuilder::new() 2456 .ints(Interval::All) 2457 .floats(Interval::All) 2458 .bools(Interval::All) 2459 .simd_lanes(Interval::All) 2460 .includes_scalars(true) 2461 .build(), 2462 ); 2463 let x = &Operand::new("x", bits); 2464 let y = &Operand::new("y", bits); 2465 let a = &Operand::new("a", bits); 2466 2467 ig.push( 2468 Inst::new( 2469 "band", 2470 r#" 2471 Bitwise and. 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 "bor", 2482 r#" 2483 Bitwise or. 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 "bxor", 2494 r#" 2495 Bitwise xor. 2496 "#, 2497 &formats.binary, 2498 ) 2499 .operands_in(vec![x, y]) 2500 .operands_out(vec![a]), 2501 ); 2502 2503 ig.push( 2504 Inst::new( 2505 "bnot", 2506 r#" 2507 Bitwise not. 2508 "#, 2509 &formats.unary, 2510 ) 2511 .operands_in(vec![x]) 2512 .operands_out(vec![a]), 2513 ); 2514 2515 ig.push( 2516 Inst::new( 2517 "band_not", 2518 r#" 2519 Bitwise and not. 2520 2521 Computes `x & ~y`. 2522 "#, 2523 &formats.binary, 2524 ) 2525 .operands_in(vec![x, y]) 2526 .operands_out(vec![a]), 2527 ); 2528 2529 ig.push( 2530 Inst::new( 2531 "bor_not", 2532 r#" 2533 Bitwise or not. 2534 2535 Computes `x | ~y`. 2536 "#, 2537 &formats.binary, 2538 ) 2539 .operands_in(vec![x, y]) 2540 .operands_out(vec![a]), 2541 ); 2542 2543 ig.push( 2544 Inst::new( 2545 "bxor_not", 2546 r#" 2547 Bitwise xor not. 2548 2549 Computes `x ^ ~y`. 2550 "#, 2551 &formats.binary, 2552 ) 2553 .operands_in(vec![x, y]) 2554 .operands_out(vec![a]), 2555 ); 2556 2557 let x = &Operand::new("x", iB); 2558 let Y = &Operand::new("Y", &imm.imm64); 2559 let a = &Operand::new("a", iB); 2560 2561 ig.push( 2562 Inst::new( 2563 "band_imm", 2564 r#" 2565 Bitwise and with immediate. 2566 2567 Same as `band`, but one operand is a zero extended 64 bit immediate constant. 2568 2569 Polymorphic over all scalar integer types, but does not support vector 2570 types. 2571 "#, 2572 &formats.binary_imm64, 2573 ) 2574 .operands_in(vec![x, Y]) 2575 .operands_out(vec![a]), 2576 ); 2577 2578 ig.push( 2579 Inst::new( 2580 "bor_imm", 2581 r#" 2582 Bitwise or with immediate. 2583 2584 Same as `bor`, but one operand is a zero extended 64 bit immediate constant. 2585 2586 Polymorphic over all scalar integer types, but does not support vector 2587 types. 2588 "#, 2589 &formats.binary_imm64, 2590 ) 2591 .operands_in(vec![x, Y]) 2592 .operands_out(vec![a]), 2593 ); 2594 2595 ig.push( 2596 Inst::new( 2597 "bxor_imm", 2598 r#" 2599 Bitwise xor with immediate. 2600 2601 Same as `bxor`, but one operand is a zero extended 64 bit immediate constant. 2602 2603 Polymorphic over all scalar integer types, but does not support vector 2604 types. 2605 "#, 2606 &formats.binary_imm64, 2607 ) 2608 .operands_in(vec![x, Y]) 2609 .operands_out(vec![a]), 2610 ); 2611 2612 let x = &Operand::new("x", Int).with_doc("Scalar or vector value to shift"); 2613 let y = &Operand::new("y", iB).with_doc("Number of bits to shift"); 2614 let Y = &Operand::new("Y", &imm.imm64); 2615 let a = &Operand::new("a", Int); 2616 2617 ig.push( 2618 Inst::new( 2619 "rotl", 2620 r#" 2621 Rotate left. 2622 2623 Rotate the bits in ``x`` by ``y`` places. 2624 "#, 2625 &formats.binary, 2626 ) 2627 .operands_in(vec![x, y]) 2628 .operands_out(vec![a]), 2629 ); 2630 2631 ig.push( 2632 Inst::new( 2633 "rotr", 2634 r#" 2635 Rotate right. 2636 2637 Rotate the bits in ``x`` by ``y`` places. 2638 "#, 2639 &formats.binary, 2640 ) 2641 .operands_in(vec![x, y]) 2642 .operands_out(vec![a]), 2643 ); 2644 2645 ig.push( 2646 Inst::new( 2647 "rotl_imm", 2648 r#" 2649 Rotate left by immediate. 2650 2651 Same as `rotl`, but one operand is a zero extended 64 bit immediate constant. 2652 "#, 2653 &formats.binary_imm64, 2654 ) 2655 .operands_in(vec![x, Y]) 2656 .operands_out(vec![a]), 2657 ); 2658 2659 ig.push( 2660 Inst::new( 2661 "rotr_imm", 2662 r#" 2663 Rotate right by immediate. 2664 2665 Same as `rotr`, but one operand is a zero extended 64 bit immediate constant. 2666 "#, 2667 &formats.binary_imm64, 2668 ) 2669 .operands_in(vec![x, Y]) 2670 .operands_out(vec![a]), 2671 ); 2672 2673 ig.push( 2674 Inst::new( 2675 "ishl", 2676 r#" 2677 Integer shift left. Shift the bits in ``x`` towards the MSB by ``y`` 2678 places. Shift in zero bits to the LSB. 2679 2680 The shift amount is masked to the size of ``x``. 2681 2682 When shifting a B-bits integer type, this instruction computes: 2683 2684 ```text 2685 s &:= y \pmod B, 2686 a &:= x \cdot 2^s \pmod{2^B}. 2687 ``` 2688 "#, 2689 &formats.binary, 2690 ) 2691 .operands_in(vec![x, y]) 2692 .operands_out(vec![a]), 2693 ); 2694 2695 ig.push( 2696 Inst::new( 2697 "ushr", 2698 r#" 2699 Unsigned shift right. Shift bits in ``x`` towards the LSB by ``y`` 2700 places, shifting in zero bits to the MSB. Also called a *logical 2701 shift*. 2702 2703 The shift amount is masked to the size of the register. 2704 2705 When shifting a B-bits integer type, this instruction computes: 2706 2707 ```text 2708 s &:= y \pmod B, 2709 a &:= \lfloor x \cdot 2^{-s} \rfloor. 2710 ``` 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 "sshr", 2721 r#" 2722 Signed shift right. Shift bits in ``x`` towards the LSB by ``y`` 2723 places, shifting in sign bits to the MSB. Also called an *arithmetic 2724 shift*. 2725 2726 The shift amount is masked to the size of the register. 2727 "#, 2728 &formats.binary, 2729 ) 2730 .operands_in(vec![x, y]) 2731 .operands_out(vec![a]), 2732 ); 2733 2734 ig.push( 2735 Inst::new( 2736 "ishl_imm", 2737 r#" 2738 Integer shift left by immediate. 2739 2740 The shift amount is masked to the size of ``x``. 2741 "#, 2742 &formats.binary_imm64, 2743 ) 2744 .operands_in(vec![x, Y]) 2745 .operands_out(vec![a]), 2746 ); 2747 2748 ig.push( 2749 Inst::new( 2750 "ushr_imm", 2751 r#" 2752 Unsigned shift right by immediate. 2753 2754 The shift amount is masked to the size of the register. 2755 "#, 2756 &formats.binary_imm64, 2757 ) 2758 .operands_in(vec![x, Y]) 2759 .operands_out(vec![a]), 2760 ); 2761 2762 ig.push( 2763 Inst::new( 2764 "sshr_imm", 2765 r#" 2766 Signed shift right by immediate. 2767 2768 The shift amount is masked to the size of the register. 2769 "#, 2770 &formats.binary_imm64, 2771 ) 2772 .operands_in(vec![x, Y]) 2773 .operands_out(vec![a]), 2774 ); 2775 2776 let x = &Operand::new("x", iB); 2777 let a = &Operand::new("a", iB); 2778 2779 ig.push( 2780 Inst::new( 2781 "bitrev", 2782 r#" 2783 Reverse the bits of a integer. 2784 2785 Reverses the bits in ``x``. 2786 "#, 2787 &formats.unary, 2788 ) 2789 .operands_in(vec![x]) 2790 .operands_out(vec![a]), 2791 ); 2792 2793 ig.push( 2794 Inst::new( 2795 "clz", 2796 r#" 2797 Count leading zero bits. 2798 2799 Starting from the MSB in ``x``, count the number of zero bits before 2800 reaching the first one bit. When ``x`` is zero, returns the size of x 2801 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 "cls", 2812 r#" 2813 Count leading sign bits. 2814 2815 Starting from the MSB after the sign bit in ``x``, count the number of 2816 consecutive bits identical to the sign bit. When ``x`` is 0 or -1, 2817 returns one less than the size of x in bits. 2818 "#, 2819 &formats.unary, 2820 ) 2821 .operands_in(vec![x]) 2822 .operands_out(vec![a]), 2823 ); 2824 2825 ig.push( 2826 Inst::new( 2827 "ctz", 2828 r#" 2829 Count trailing zeros. 2830 2831 Starting from the LSB in ``x``, count the number of zero bits before 2832 reaching the first one bit. When ``x`` is zero, returns the size of x 2833 in bits. 2834 "#, 2835 &formats.unary, 2836 ) 2837 .operands_in(vec![x]) 2838 .operands_out(vec![a]), 2839 ); 2840 2841 let x = &Operand::new("x", Int); 2842 let a = &Operand::new("a", Int); 2843 2844 ig.push( 2845 Inst::new( 2846 "popcnt", 2847 r#" 2848 Population count 2849 2850 Count the number of one bits in ``x``. 2851 "#, 2852 &formats.unary, 2853 ) 2854 .operands_in(vec![x]) 2855 .operands_out(vec![a]), 2856 ); 2857 2858 let Float = &TypeVar::new( 2859 "Float", 2860 "A scalar or vector floating point number", 2861 TypeSetBuilder::new() 2862 .floats(Interval::All) 2863 .simd_lanes(Interval::All) 2864 .dynamic_simd_lanes(Interval::All) 2865 .build(), 2866 ); 2867 let Cond = &Operand::new("Cond", &imm.floatcc); 2868 let x = &Operand::new("x", Float); 2869 let y = &Operand::new("y", Float); 2870 let a = &Operand::new("a", &Float.as_bool()); 2871 2872 ig.push( 2873 Inst::new( 2874 "fcmp", 2875 r#" 2876 Floating point comparison. 2877 2878 Two IEEE 754-2008 floating point numbers, `x` and `y`, relate to each 2879 other in exactly one of four ways: 2880 2881 ```text 2882 == ========================================== 2883 UN Unordered when one or both numbers is NaN. 2884 EQ When `x = y`. (And `0.0 = -0.0`). 2885 LT When `x < y`. 2886 GT When `x > y`. 2887 == ========================================== 2888 ``` 2889 2890 The 14 `floatcc` condition codes each correspond to a subset of 2891 the four relations, except for the empty set which would always be 2892 false, and the full set which would always be true. 2893 2894 The condition codes are divided into 7 'ordered' conditions which don't 2895 include UN, and 7 unordered conditions which all include UN. 2896 2897 ```text 2898 +-------+------------+---------+------------+-------------------------+ 2899 |Ordered |Unordered |Condition | 2900 +=======+============+=========+============+=========================+ 2901 |ord |EQ | LT | GT|uno |UN |NaNs absent / present. | 2902 +-------+------------+---------+------------+-------------------------+ 2903 |eq |EQ |ueq |UN | EQ |Equal | 2904 +-------+------------+---------+------------+-------------------------+ 2905 |one |LT | GT |ne |UN | LT | GT|Not equal | 2906 +-------+------------+---------+------------+-------------------------+ 2907 |lt |LT |ult |UN | LT |Less than | 2908 +-------+------------+---------+------------+-------------------------+ 2909 |le |LT | EQ |ule |UN | LT | EQ|Less than or equal | 2910 +-------+------------+---------+------------+-------------------------+ 2911 |gt |GT |ugt |UN | GT |Greater than | 2912 +-------+------------+---------+------------+-------------------------+ 2913 |ge |GT | EQ |uge |UN | GT | EQ|Greater than or equal | 2914 +-------+------------+---------+------------+-------------------------+ 2915 ``` 2916 2917 The standard C comparison operators, `<, <=, >, >=`, are all ordered, 2918 so they are false if either operand is NaN. The C equality operator, 2919 `==`, is ordered, and since inequality is defined as the logical 2920 inverse it is *unordered*. They map to the `floatcc` condition 2921 codes as follows: 2922 2923 ```text 2924 ==== ====== ============ 2925 C `Cond` Subset 2926 ==== ====== ============ 2927 `==` eq EQ 2928 `!=` ne UN | LT | GT 2929 `<` lt LT 2930 `<=` le LT | EQ 2931 `>` gt GT 2932 `>=` ge GT | EQ 2933 ==== ====== ============ 2934 ``` 2935 2936 This subset of condition codes also corresponds to the WebAssembly 2937 floating point comparisons of the same name. 2938 2939 When this instruction compares floating point vectors, it returns a 2940 boolean vector with the results of lane-wise comparisons. 2941 "#, 2942 &formats.float_compare, 2943 ) 2944 .operands_in(vec![Cond, x, y]) 2945 .operands_out(vec![a]), 2946 ); 2947 2948 let f = &Operand::new("f", fflags); 2949 2950 ig.push( 2951 Inst::new( 2952 "ffcmp", 2953 r#" 2954 Floating point comparison returning flags. 2955 2956 Compares two numbers like `fcmp`, but returns floating point CPU 2957 flags instead of testing a specific condition. 2958 "#, 2959 &formats.binary, 2960 ) 2961 .operands_in(vec![x, y]) 2962 .operands_out(vec![f]), 2963 ); 2964 2965 let x = &Operand::new("x", Float); 2966 let y = &Operand::new("y", Float); 2967 let z = &Operand::new("z", Float); 2968 let a = &Operand::new("a", Float).with_doc("Result of applying operator to each lane"); 2969 2970 ig.push( 2971 Inst::new( 2972 "fadd", 2973 r#" 2974 Floating point addition. 2975 "#, 2976 &formats.binary, 2977 ) 2978 .operands_in(vec![x, y]) 2979 .operands_out(vec![a]), 2980 ); 2981 2982 ig.push( 2983 Inst::new( 2984 "fsub", 2985 r#" 2986 Floating point subtraction. 2987 "#, 2988 &formats.binary, 2989 ) 2990 .operands_in(vec![x, y]) 2991 .operands_out(vec![a]), 2992 ); 2993 2994 ig.push( 2995 Inst::new( 2996 "fmul", 2997 r#" 2998 Floating point multiplication. 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 "fdiv", 3009 r#" 3010 Floating point division. 3011 3012 Unlike the integer division instructions ` and 3013 `udiv`, this can't trap. Division by zero is infinity or 3014 NaN, depending on the dividend. 3015 "#, 3016 &formats.binary, 3017 ) 3018 .operands_in(vec![x, y]) 3019 .operands_out(vec![a]), 3020 ); 3021 3022 ig.push( 3023 Inst::new( 3024 "sqrt", 3025 r#" 3026 Floating point square root. 3027 "#, 3028 &formats.unary, 3029 ) 3030 .operands_in(vec![x]) 3031 .operands_out(vec![a]), 3032 ); 3033 3034 ig.push( 3035 Inst::new( 3036 "fma", 3037 r#" 3038 Floating point fused multiply-and-add. 3039 3040 Computes `a := xy+z` without any intermediate rounding of the 3041 product. 3042 "#, 3043 &formats.ternary, 3044 ) 3045 .operands_in(vec![x, y, z]) 3046 .operands_out(vec![a]), 3047 ); 3048 3049 let a = &Operand::new("a", Float).with_doc("``x`` with its sign bit inverted"); 3050 3051 ig.push( 3052 Inst::new( 3053 "fneg", 3054 r#" 3055 Floating point negation. 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 cleared"); 3066 3067 ig.push( 3068 Inst::new( 3069 "fabs", 3070 r#" 3071 Floating point absolute value. 3072 3073 Note that this is a pure bitwise operation. 3074 "#, 3075 &formats.unary, 3076 ) 3077 .operands_in(vec![x]) 3078 .operands_out(vec![a]), 3079 ); 3080 3081 let a = &Operand::new("a", Float).with_doc("``x`` with its sign bit changed to that of ``y``"); 3082 3083 ig.push( 3084 Inst::new( 3085 "fcopysign", 3086 r#" 3087 Floating point copy sign. 3088 3089 Note that this is a pure bitwise operation. The sign bit from ``y`` is 3090 copied to the sign bit of ``x``. 3091 "#, 3092 &formats.binary, 3093 ) 3094 .operands_in(vec![x, y]) 3095 .operands_out(vec![a]), 3096 ); 3097 3098 let a = &Operand::new("a", Float).with_doc("The smaller of ``x`` and ``y``"); 3099 3100 ig.push( 3101 Inst::new( 3102 "fmin", 3103 r#" 3104 Floating point minimum, propagating NaNs using the WebAssembly rules. 3105 3106 If either operand is NaN, this returns NaN with an unspecified sign. Furthermore, if 3107 each input NaN consists of a mantissa whose most significant bit is 1 and the rest is 3108 0, then the output has the same form. Otherwise, the output mantissa's most significant 3109 bit is 1 and the rest is unspecified. 3110 "#, 3111 &formats.binary, 3112 ) 3113 .operands_in(vec![x, y]) 3114 .operands_out(vec![a]), 3115 ); 3116 3117 ig.push( 3118 Inst::new( 3119 "fmin_pseudo", 3120 r#" 3121 Floating point pseudo-minimum, propagating NaNs. This behaves differently from ``fmin``. 3122 See <https://github.com/WebAssembly/simd/pull/122> for background. 3123 3124 The behaviour is defined as ``fmin_pseudo(a, b) = (b < a) ? b : a``, and the behaviour 3125 for zero or NaN inputs follows from the behaviour of ``<`` with such inputs. 3126 "#, 3127 &formats.binary, 3128 ) 3129 .operands_in(vec![x, y]) 3130 .operands_out(vec![a]), 3131 ); 3132 3133 let a = &Operand::new("a", Float).with_doc("The larger of ``x`` and ``y``"); 3134 3135 ig.push( 3136 Inst::new( 3137 "fmax", 3138 r#" 3139 Floating point maximum, propagating NaNs using the WebAssembly rules. 3140 3141 If either operand is NaN, this returns NaN with an unspecified sign. Furthermore, if 3142 each input NaN consists of a mantissa whose most significant bit is 1 and the rest is 3143 0, then the output has the same form. Otherwise, the output mantissa's most significant 3144 bit is 1 and the rest is unspecified. 3145 "#, 3146 &formats.binary, 3147 ) 3148 .operands_in(vec![x, y]) 3149 .operands_out(vec![a]), 3150 ); 3151 3152 ig.push( 3153 Inst::new( 3154 "fmax_pseudo", 3155 r#" 3156 Floating point pseudo-maximum, propagating NaNs. This behaves differently from ``fmax``. 3157 See <https://github.com/WebAssembly/simd/pull/122> for background. 3158 3159 The behaviour is defined as ``fmax_pseudo(a, b) = (a < b) ? b : a``, and the behaviour 3160 for zero or NaN inputs follows from the behaviour of ``<`` with such inputs. 3161 "#, 3162 &formats.binary, 3163 ) 3164 .operands_in(vec![x, y]) 3165 .operands_out(vec![a]), 3166 ); 3167 3168 let a = &Operand::new("a", Float).with_doc("``x`` rounded to integral value"); 3169 3170 ig.push( 3171 Inst::new( 3172 "ceil", 3173 r#" 3174 Round floating point round to integral, towards positive infinity. 3175 "#, 3176 &formats.unary, 3177 ) 3178 .operands_in(vec![x]) 3179 .operands_out(vec![a]), 3180 ); 3181 3182 ig.push( 3183 Inst::new( 3184 "floor", 3185 r#" 3186 Round floating point round to integral, towards negative infinity. 3187 "#, 3188 &formats.unary, 3189 ) 3190 .operands_in(vec![x]) 3191 .operands_out(vec![a]), 3192 ); 3193 3194 ig.push( 3195 Inst::new( 3196 "trunc", 3197 r#" 3198 Round floating point round to integral, towards zero. 3199 "#, 3200 &formats.unary, 3201 ) 3202 .operands_in(vec![x]) 3203 .operands_out(vec![a]), 3204 ); 3205 3206 ig.push( 3207 Inst::new( 3208 "nearest", 3209 r#" 3210 Round floating point round to integral, towards nearest with ties to 3211 even. 3212 "#, 3213 &formats.unary, 3214 ) 3215 .operands_in(vec![x]) 3216 .operands_out(vec![a]), 3217 ); 3218 3219 let a = &Operand::new("a", b1); 3220 let x = &Operand::new("x", Ref); 3221 3222 ig.push( 3223 Inst::new( 3224 "is_null", 3225 r#" 3226 Reference verification. 3227 3228 The condition code determines if the reference type in question is 3229 null or not. 3230 "#, 3231 &formats.unary, 3232 ) 3233 .operands_in(vec![x]) 3234 .operands_out(vec![a]), 3235 ); 3236 3237 let a = &Operand::new("a", b1); 3238 let x = &Operand::new("x", Ref); 3239 3240 ig.push( 3241 Inst::new( 3242 "is_invalid", 3243 r#" 3244 Reference verification. 3245 3246 The condition code determines if the reference type in question is 3247 invalid or not. 3248 "#, 3249 &formats.unary, 3250 ) 3251 .operands_in(vec![x]) 3252 .operands_out(vec![a]), 3253 ); 3254 3255 let Cond = &Operand::new("Cond", &imm.intcc); 3256 let f = &Operand::new("f", iflags); 3257 let a = &Operand::new("a", b1); 3258 3259 ig.push( 3260 Inst::new( 3261 "trueif", 3262 r#" 3263 Test integer CPU flags for a specific condition. 3264 3265 Check the CPU flags in ``f`` against the ``Cond`` condition code and 3266 return true when the condition code is satisfied. 3267 "#, 3268 &formats.int_cond, 3269 ) 3270 .operands_in(vec![Cond, f]) 3271 .operands_out(vec![a]), 3272 ); 3273 3274 let Cond = &Operand::new("Cond", &imm.floatcc); 3275 let f = &Operand::new("f", fflags); 3276 3277 ig.push( 3278 Inst::new( 3279 "trueff", 3280 r#" 3281 Test floating point CPU flags for a specific condition. 3282 3283 Check the CPU flags in ``f`` against the ``Cond`` condition code and 3284 return true when the condition code is satisfied. 3285 "#, 3286 &formats.float_cond, 3287 ) 3288 .operands_in(vec![Cond, f]) 3289 .operands_out(vec![a]), 3290 ); 3291 3292 let x = &Operand::new("x", Mem); 3293 let a = &Operand::new("a", MemTo).with_doc("Bits of `x` reinterpreted"); 3294 3295 ig.push( 3296 Inst::new( 3297 "bitcast", 3298 r#" 3299 Reinterpret the bits in `x` as a different type. 3300 3301 The input and output types must be storable to memory and of the same 3302 size. A bitcast is equivalent to storing one type and loading the other 3303 type from the same address. 3304 "#, 3305 &formats.unary, 3306 ) 3307 .operands_in(vec![x]) 3308 .operands_out(vec![a]), 3309 ); 3310 3311 let x = &Operand::new("x", Any); 3312 let a = &Operand::new("a", AnyTo).with_doc("Bits of `x` reinterpreted"); 3313 3314 ig.push( 3315 Inst::new( 3316 "raw_bitcast", 3317 r#" 3318 Cast the bits in `x` as a different type of the same bit width. 3319 3320 This instruction does not change the data's representation but allows 3321 data in registers to be used as different types, e.g. an i32x4 as a 3322 b8x16. The only constraint on the result `a` is that it can be 3323 `raw_bitcast` back to the original type. Also, in a raw_bitcast between 3324 vector types with the same number of lanes, the value of each result 3325 lane is a raw_bitcast of the corresponding operand lane. TODO there is 3326 currently no mechanism for enforcing the bit width constraint. 3327 "#, 3328 &formats.unary, 3329 ) 3330 .operands_in(vec![x]) 3331 .operands_out(vec![a]), 3332 ); 3333 3334 let a = &Operand::new("a", TxN).with_doc("A vector value"); 3335 let s = &Operand::new("s", &TxN.lane_of()).with_doc("A scalar value"); 3336 3337 ig.push( 3338 Inst::new( 3339 "scalar_to_vector", 3340 r#" 3341 Copies a scalar value to a vector value. The scalar is copied into the 3342 least significant lane of the vector, and all other lanes will be zero. 3343 "#, 3344 &formats.unary, 3345 ) 3346 .operands_in(vec![s]) 3347 .operands_out(vec![a]), 3348 ); 3349 3350 let Bool = &TypeVar::new( 3351 "Bool", 3352 "A scalar boolean type", 3353 TypeSetBuilder::new().bools(Interval::All).build(), 3354 ); 3355 3356 let BoolTo = &TypeVar::new( 3357 "BoolTo", 3358 "A smaller boolean type", 3359 TypeSetBuilder::new().bools(Interval::All).build(), 3360 ); 3361 3362 let x = &Operand::new("x", Bool); 3363 let a = &Operand::new("a", BoolTo); 3364 3365 ig.push( 3366 Inst::new( 3367 "breduce", 3368 r#" 3369 Convert `x` to a smaller boolean type by discarding the most significant bits. 3370 "#, 3371 &formats.unary, 3372 ) 3373 .operands_in(vec![x]) 3374 .operands_out(vec![a]), 3375 ); 3376 3377 let BoolTo = &TypeVar::new( 3378 "BoolTo", 3379 "A larger boolean type", 3380 TypeSetBuilder::new().bools(Interval::All).build(), 3381 ); 3382 let x = &Operand::new("x", Bool); 3383 let a = &Operand::new("a", BoolTo); 3384 3385 ig.push( 3386 Inst::new( 3387 "bextend", 3388 r#" 3389 Convert `x` to a larger boolean type 3390 "#, 3391 &formats.unary, 3392 ) 3393 .operands_in(vec![x]) 3394 .operands_out(vec![a]), 3395 ); 3396 3397 let IntTo = &TypeVar::new( 3398 "IntTo", 3399 "A scalar integer type", 3400 TypeSetBuilder::new().ints(Interval::All).build(), 3401 ); 3402 let x = &Operand::new("x", ScalarBool); 3403 let a = &Operand::new("a", IntTo); 3404 3405 ig.push( 3406 Inst::new( 3407 "bint", 3408 r#" 3409 Convert `x` to an integer. 3410 3411 True maps to 1 and false maps to 0. 3412 "#, 3413 &formats.unary, 3414 ) 3415 .operands_in(vec![x]) 3416 .operands_out(vec![a]), 3417 ); 3418 3419 let Bool = &TypeVar::new( 3420 "Bool", 3421 "A scalar or vector boolean type", 3422 TypeSetBuilder::new() 3423 .bools(Interval::All) 3424 .simd_lanes(Interval::All) 3425 .build(), 3426 ); 3427 let IntTo = &TypeVar::new( 3428 "IntTo", 3429 "An integer type with the same number of lanes", 3430 TypeSetBuilder::new() 3431 .ints(Interval::All) 3432 .simd_lanes(Interval::All) 3433 .build(), 3434 ); 3435 let x = &Operand::new("x", Bool); 3436 let a = &Operand::new("a", IntTo); 3437 3438 ig.push( 3439 Inst::new( 3440 "bmask", 3441 r#" 3442 Convert `x` to an integer mask. 3443 3444 True maps to all 1s and false maps to all 0s. The result type must have 3445 the same number of vector lanes as the input. 3446 "#, 3447 &formats.unary, 3448 ) 3449 .operands_in(vec![x]) 3450 .operands_out(vec![a]), 3451 ); 3452 3453 let Int = &TypeVar::new( 3454 "Int", 3455 "A scalar integer type", 3456 TypeSetBuilder::new().ints(Interval::All).build(), 3457 ); 3458 3459 let IntTo = &TypeVar::new( 3460 "IntTo", 3461 "A smaller integer type", 3462 TypeSetBuilder::new().ints(Interval::All).build(), 3463 ); 3464 let x = &Operand::new("x", Int); 3465 let a = &Operand::new("a", IntTo); 3466 3467 ig.push( 3468 Inst::new( 3469 "ireduce", 3470 r#" 3471 Convert `x` to a smaller integer type by discarding 3472 the most significant bits. 3473 3474 This is the same as reducing modulo `2^n`. 3475 "#, 3476 &formats.unary, 3477 ) 3478 .operands_in(vec![x]) 3479 .operands_out(vec![a]), 3480 ); 3481 3482 let I16or32or64xN = &TypeVar::new( 3483 "I16or32or64xN", 3484 "A SIMD vector type containing integer lanes 16, 32, or 64 bits wide", 3485 TypeSetBuilder::new() 3486 .ints(16..64) 3487 .simd_lanes(2..8) 3488 .dynamic_simd_lanes(2..8) 3489 .includes_scalars(false) 3490 .build(), 3491 ); 3492 3493 let x = &Operand::new("x", I16or32or64xN); 3494 let y = &Operand::new("y", I16or32or64xN); 3495 let a = &Operand::new("a", &I16or32or64xN.split_lanes()); 3496 3497 ig.push( 3498 Inst::new( 3499 "snarrow", 3500 r#" 3501 Combine `x` and `y` into a vector with twice the lanes but half the integer width while 3502 saturating overflowing values to the signed maximum and minimum. 3503 3504 The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4` 3505 and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value 3506 returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`. 3507 "#, 3508 &formats.binary, 3509 ) 3510 .operands_in(vec![x, y]) 3511 .operands_out(vec![a]), 3512 ); 3513 3514 ig.push( 3515 Inst::new( 3516 "unarrow", 3517 r#" 3518 Combine `x` and `y` into a vector with twice the lanes but half the integer width while 3519 saturating overflowing values to the unsigned maximum and minimum. 3520 3521 Note that all input lanes are considered signed: any negative lanes will overflow and be 3522 replaced with the unsigned minimum, `0x00`. 3523 3524 The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4` 3525 and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value 3526 returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`. 3527 "#, 3528 &formats.binary, 3529 ) 3530 .operands_in(vec![x, y]) 3531 .operands_out(vec![a]), 3532 ); 3533 3534 ig.push( 3535 Inst::new( 3536 "uunarrow", 3537 r#" 3538 Combine `x` and `y` into a vector with twice the lanes but half the integer width while 3539 saturating overflowing values to the unsigned maximum and minimum. 3540 3541 Note that all input lanes are considered unsigned: any negative values will be interpreted as unsigned, overflowing and being replaced with the unsigned maximum. 3542 3543 The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4` 3544 and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value 3545 returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`. 3546 "#, 3547 &formats.binary, 3548 ) 3549 .operands_in(vec![x, y]) 3550 .operands_out(vec![a]), 3551 ); 3552 3553 let I8or16or32xN = &TypeVar::new( 3554 "I8or16or32xN", 3555 "A SIMD vector type containing integer lanes 8, 16, or 32 bits wide.", 3556 TypeSetBuilder::new() 3557 .ints(8..32) 3558 .simd_lanes(2..16) 3559 .dynamic_simd_lanes(2..16) 3560 .includes_scalars(false) 3561 .build(), 3562 ); 3563 3564 let x = &Operand::new("x", I8or16or32xN); 3565 let a = &Operand::new("a", &I8or16or32xN.merge_lanes()); 3566 3567 ig.push( 3568 Inst::new( 3569 "swiden_low", 3570 r#" 3571 Widen the low lanes of `x` using signed extension. 3572 3573 This will double the lane width and halve the number of lanes. 3574 "#, 3575 &formats.unary, 3576 ) 3577 .operands_in(vec![x]) 3578 .operands_out(vec![a]), 3579 ); 3580 3581 ig.push( 3582 Inst::new( 3583 "swiden_high", 3584 r#" 3585 Widen the high lanes of `x` using signed extension. 3586 3587 This will double the lane width and halve the number of lanes. 3588 "#, 3589 &formats.unary, 3590 ) 3591 .operands_in(vec![x]) 3592 .operands_out(vec![a]), 3593 ); 3594 3595 ig.push( 3596 Inst::new( 3597 "uwiden_low", 3598 r#" 3599 Widen the low lanes of `x` using unsigned extension. 3600 3601 This will double the lane width and halve the number of lanes. 3602 "#, 3603 &formats.unary, 3604 ) 3605 .operands_in(vec![x]) 3606 .operands_out(vec![a]), 3607 ); 3608 3609 ig.push( 3610 Inst::new( 3611 "uwiden_high", 3612 r#" 3613 Widen the high lanes of `x` using unsigned extension. 3614 3615 This will double the lane width and halve the number of lanes. 3616 "#, 3617 &formats.unary, 3618 ) 3619 .operands_in(vec![x]) 3620 .operands_out(vec![a]), 3621 ); 3622 3623 let x = &Operand::new("x", I8or16or32xN); 3624 let y = &Operand::new("y", I8or16or32xN); 3625 let a = &Operand::new("a", I8or16or32xN); 3626 3627 ig.push( 3628 Inst::new( 3629 "iadd_pairwise", 3630 r#" 3631 Does lane-wise integer pairwise addition on two operands, putting the 3632 combined results into a single vector result. Here a pair refers to adjacent 3633 lanes in a vector, i.e. i*2 + (i*2+1) for i == num_lanes/2. The first operand 3634 pairwise add results will make up the low half of the resulting vector while 3635 the second operand pairwise add results will make up the upper half of the 3636 resulting vector. 3637 "#, 3638 &formats.binary, 3639 ) 3640 .operands_in(vec![x, y]) 3641 .operands_out(vec![a]), 3642 ); 3643 3644 let I16x8 = &TypeVar::new( 3645 "I16x8", 3646 "A SIMD vector type containing 8 integer lanes each 16 bits wide.", 3647 TypeSetBuilder::new() 3648 .ints(16..16) 3649 .simd_lanes(8..8) 3650 .includes_scalars(false) 3651 .build(), 3652 ); 3653 3654 let x = &Operand::new("x", I16x8); 3655 let y = &Operand::new("y", I16x8); 3656 let a = &Operand::new("a", &I16x8.merge_lanes()); 3657 3658 ig.push( 3659 Inst::new( 3660 "widening_pairwise_dot_product_s", 3661 r#" 3662 Takes corresponding elements in `x` and `y`, performs a sign-extending length-doubling 3663 multiplication on them, then adds adjacent pairs of elements to form the result. For 3664 example, if the input vectors are `[x3, x2, x1, x0]` and `[y3, y2, y1, y0]`, it produces 3665 the vector `[r1, r0]`, where `r1 = sx(x3) * sx(y3) + sx(x2) * sx(y2)` and 3666 `r0 = sx(x1) * sx(y1) + sx(x0) * sx(y0)`, and `sx(n)` sign-extends `n` to twice its width. 3667 3668 This will double the lane width and halve the number of lanes. So the resulting 3669 vector has the same number of bits as `x` and `y` do (individually). 3670 3671 See <https://github.com/WebAssembly/simd/pull/127> for background info. 3672 "#, 3673 &formats.binary, 3674 ) 3675 .operands_in(vec![x, y]) 3676 .operands_out(vec![a]), 3677 ); 3678 3679 let IntTo = &TypeVar::new( 3680 "IntTo", 3681 "A larger integer type with the same number of lanes", 3682 TypeSetBuilder::new() 3683 .ints(Interval::All) 3684 .simd_lanes(Interval::All) 3685 .build(), 3686 ); 3687 let x = &Operand::new("x", Int); 3688 let a = &Operand::new("a", IntTo); 3689 3690 ig.push( 3691 Inst::new( 3692 "uextend", 3693 r#" 3694 Convert `x` to a larger integer type by zero-extending. 3695 3696 Each lane in `x` is converted to a larger integer type by adding 3697 zeroes. The result has the same numerical value as `x` when both are 3698 interpreted as unsigned integers. 3699 3700 The result type must have the same number of vector lanes as the input, 3701 and each lane must not have fewer bits that the input lanes. If the 3702 input and output types are the same, this is a no-op. 3703 "#, 3704 &formats.unary, 3705 ) 3706 .operands_in(vec![x]) 3707 .operands_out(vec![a]), 3708 ); 3709 3710 ig.push( 3711 Inst::new( 3712 "sextend", 3713 r#" 3714 Convert `x` to a larger integer type by sign-extending. 3715 3716 Each lane in `x` is converted to a larger integer type by replicating 3717 the sign bit. The result has the same numerical value as `x` when both 3718 are interpreted as signed integers. 3719 3720 The result type must have the same number of vector lanes as the input, 3721 and each lane must not have fewer bits that the input lanes. If the 3722 input and output types are the same, this is a no-op. 3723 "#, 3724 &formats.unary, 3725 ) 3726 .operands_in(vec![x]) 3727 .operands_out(vec![a]), 3728 ); 3729 3730 let FloatTo = &TypeVar::new( 3731 "FloatTo", 3732 "A scalar or vector floating point number", 3733 TypeSetBuilder::new() 3734 .floats(Interval::All) 3735 .simd_lanes(Interval::All) 3736 .build(), 3737 ); 3738 let x = &Operand::new("x", Float); 3739 let a = &Operand::new("a", FloatTo); 3740 3741 ig.push( 3742 Inst::new( 3743 "fpromote", 3744 r#" 3745 Convert `x` to a larger floating point format. 3746 3747 Each lane in `x` is converted to the destination floating point format. 3748 This is an exact operation. 3749 3750 Cranelift currently only supports two floating point formats 3751 - `f32` and `f64`. This may change in the future. 3752 3753 The result type must have the same number of vector lanes as the input, 3754 and the result lanes must not have fewer bits than the input lanes. If 3755 the input and output types are the same, this is a no-op. 3756 "#, 3757 &formats.unary, 3758 ) 3759 .operands_in(vec![x]) 3760 .operands_out(vec![a]), 3761 ); 3762 3763 ig.push( 3764 Inst::new( 3765 "fdemote", 3766 r#" 3767 Convert `x` to a smaller floating point format. 3768 3769 Each lane in `x` is converted to the destination floating point format 3770 by rounding to nearest, ties to even. 3771 3772 Cranelift currently only supports two floating point formats 3773 - `f32` and `f64`. This may change in the future. 3774 3775 The result type must have the same number of vector lanes as the input, 3776 and the result lanes must not have more bits than the input lanes. If 3777 the input and output types are the same, this is a no-op. 3778 "#, 3779 &formats.unary, 3780 ) 3781 .operands_in(vec![x]) 3782 .operands_out(vec![a]), 3783 ); 3784 3785 let F64x2 = &TypeVar::new( 3786 "F64x2", 3787 "A SIMD vector type consisting of 2 lanes of 64-bit floats", 3788 TypeSetBuilder::new() 3789 .floats(64..64) 3790 .simd_lanes(2..2) 3791 .includes_scalars(false) 3792 .build(), 3793 ); 3794 let F32x4 = &TypeVar::new( 3795 "F32x4", 3796 "A SIMD vector type consisting of 4 lanes of 32-bit floats", 3797 TypeSetBuilder::new() 3798 .floats(32..32) 3799 .simd_lanes(4..4) 3800 .includes_scalars(false) 3801 .build(), 3802 ); 3803 3804 let x = &Operand::new("x", F64x2); 3805 let a = &Operand::new("a", F32x4); 3806 3807 ig.push( 3808 Inst::new( 3809 "fvdemote", 3810 r#" 3811 Convert `x` to a smaller floating point format. 3812 3813 Each lane in `x` is converted to the destination floating point format 3814 by rounding to nearest, ties to even. 3815 3816 Cranelift currently only supports two floating point formats 3817 - `f32` and `f64`. This may change in the future. 3818 3819 Fvdemote differs from fdemote in that with fvdemote it targets vectors. 3820 Fvdemote is constrained to having the input type being F64x2 and the result 3821 type being F32x4. The result lane that was the upper half of the input lane 3822 is initialized to zero. 3823 "#, 3824 &formats.unary, 3825 ) 3826 .operands_in(vec![x]) 3827 .operands_out(vec![a]), 3828 ); 3829 3830 ig.push( 3831 Inst::new( 3832 "fvpromote_low", 3833 r#" 3834 Converts packed single precision floating point to packed double precision floating point. 3835 3836 Considering only the lower half of the register, the low lanes in `x` are interpreted as 3837 single precision floats that are then converted to a double precision floats. 3838 3839 The result type will have half the number of vector lanes as the input. Fvpromote_low is 3840 constrained to input F32x4 with a result type of F64x2. 3841 "#, 3842 &formats.unary, 3843 ) 3844 .operands_in(vec![a]) 3845 .operands_out(vec![x]), 3846 ); 3847 3848 let FloatScalar = &TypeVar::new( 3849 "FloatScalar", 3850 "A scalar only floating point number", 3851 TypeSetBuilder::new().floats(Interval::All).build(), 3852 ); 3853 let x = &Operand::new("x", FloatScalar); 3854 let a = &Operand::new("a", IntTo); 3855 3856 ig.push( 3857 Inst::new( 3858 "fcvt_to_uint", 3859 r#" 3860 Converts floating point scalars to unsigned integer. 3861 3862 Only operates on `x` if it is a scalar. If `x` is NaN or if 3863 the unsigned integral value cannot be represented in the result 3864 type, this instruction traps. 3865 3866 "#, 3867 &formats.unary, 3868 ) 3869 .operands_in(vec![x]) 3870 .operands_out(vec![a]) 3871 .can_trap(true), 3872 ); 3873 3874 ig.push( 3875 Inst::new( 3876 "fcvt_to_sint", 3877 r#" 3878 Converts floating point scalars to signed integer. 3879 3880 Only operates on `x` if it is a scalar. If `x` is NaN or if 3881 the unsigned integral value cannot be represented in the result 3882 type, this instruction traps. 3883 3884 "#, 3885 &formats.unary, 3886 ) 3887 .operands_in(vec![x]) 3888 .operands_out(vec![a]) 3889 .can_trap(true), 3890 ); 3891 3892 let x = &Operand::new("x", Float); 3893 let a = &Operand::new("a", IntTo); 3894 3895 ig.push( 3896 Inst::new( 3897 "fcvt_to_uint_sat", 3898 r#" 3899 Convert floating point to unsigned integer as fcvt_to_uint does, but 3900 saturates the input instead of trapping. NaN and negative values are 3901 converted to 0. 3902 "#, 3903 &formats.unary, 3904 ) 3905 .operands_in(vec![x]) 3906 .operands_out(vec![a]), 3907 ); 3908 3909 ig.push( 3910 Inst::new( 3911 "fcvt_to_sint_sat", 3912 r#" 3913 Convert floating point to signed integer as fcvt_to_sint does, but 3914 saturates the input instead of trapping. NaN values are converted to 0. 3915 "#, 3916 &formats.unary, 3917 ) 3918 .operands_in(vec![x]) 3919 .operands_out(vec![a]), 3920 ); 3921 3922 let Int = &TypeVar::new( 3923 "Int", 3924 "A scalar or vector integer type", 3925 TypeSetBuilder::new() 3926 .ints(Interval::All) 3927 .simd_lanes(Interval::All) 3928 .build(), 3929 ); 3930 let x = &Operand::new("x", Int); 3931 let a = &Operand::new("a", FloatTo); 3932 3933 ig.push( 3934 Inst::new( 3935 "fcvt_from_uint", 3936 r#" 3937 Convert unsigned integer to floating point. 3938 3939 Each lane in `x` is interpreted as an unsigned integer and converted to 3940 floating point using round to nearest, ties to even. 3941 3942 The result type must have the same number of vector lanes as the input. 3943 "#, 3944 &formats.unary, 3945 ) 3946 .operands_in(vec![x]) 3947 .operands_out(vec![a]), 3948 ); 3949 3950 ig.push( 3951 Inst::new( 3952 "fcvt_from_sint", 3953 r#" 3954 Convert signed integer to floating point. 3955 3956 Each lane in `x` is interpreted as a signed integer and converted to 3957 floating point using round to nearest, ties to even. 3958 3959 The result type must have the same number of vector lanes as the input. 3960 "#, 3961 &formats.unary, 3962 ) 3963 .operands_in(vec![x]) 3964 .operands_out(vec![a]), 3965 ); 3966 3967 ig.push( 3968 Inst::new( 3969 "fcvt_low_from_sint", 3970 r#" 3971 Converts packed signed 32-bit integers to packed double precision floating point. 3972 3973 Considering only the low half of the register, each lane in `x` is interpreted as a 3974 signed 32-bit integer that is then converted to a double precision float. This 3975 instruction differs from fcvt_from_sint in that it converts half the number of lanes 3976 which are converted to occupy twice the number of bits. No rounding should be needed 3977 for the resulting float. 3978 3979 The result type will have half the number of vector lanes as the input. 3980 "#, 3981 &formats.unary, 3982 ) 3983 .operands_in(vec![x]) 3984 .operands_out(vec![a]), 3985 ); 3986 3987 let WideInt = &TypeVar::new( 3988 "WideInt", 3989 "An integer type with lanes from `i16` upwards", 3990 TypeSetBuilder::new() 3991 .ints(16..128) 3992 .simd_lanes(Interval::All) 3993 .build(), 3994 ); 3995 let x = &Operand::new("x", WideInt); 3996 let lo = &Operand::new("lo", &WideInt.half_width()).with_doc("The low bits of `x`"); 3997 let hi = &Operand::new("hi", &WideInt.half_width()).with_doc("The high bits of `x`"); 3998 3999 ig.push( 4000 Inst::new( 4001 "isplit", 4002 r#" 4003 Split an integer into low and high parts. 4004 4005 Vectors of integers are split lane-wise, so the results have the same 4006 number of lanes as the input, but the lanes are half the size. 4007 4008 Returns the low half of `x` and the high half of `x` as two independent 4009 values. 4010 "#, 4011 &formats.unary, 4012 ) 4013 .operands_in(vec![x]) 4014 .operands_out(vec![lo, hi]), 4015 ); 4016 4017 let NarrowInt = &TypeVar::new( 4018 "NarrowInt", 4019 "An integer type with lanes type to `i64`", 4020 TypeSetBuilder::new() 4021 .ints(8..64) 4022 .simd_lanes(Interval::All) 4023 .build(), 4024 ); 4025 4026 let lo = &Operand::new("lo", NarrowInt); 4027 let hi = &Operand::new("hi", NarrowInt); 4028 let a = &Operand::new("a", &NarrowInt.double_width()) 4029 .with_doc("The concatenation of `lo` and `hi`"); 4030 4031 ig.push( 4032 Inst::new( 4033 "iconcat", 4034 r#" 4035 Concatenate low and high bits to form a larger integer type. 4036 4037 Vectors of integers are concatenated lane-wise such that the result has 4038 the same number of lanes as the inputs, but the lanes are twice the 4039 size. 4040 "#, 4041 &formats.binary, 4042 ) 4043 .operands_in(vec![lo, hi]) 4044 .operands_out(vec![a]), 4045 ); 4046 4047 // Instructions relating to atomic memory accesses and fences 4048 let AtomicMem = &TypeVar::new( 4049 "AtomicMem", 4050 "Any type that can be stored in memory, which can be used in an atomic operation", 4051 TypeSetBuilder::new().ints(8..64).build(), 4052 ); 4053 let x = &Operand::new("x", AtomicMem).with_doc("Value to be atomically stored"); 4054 let a = &Operand::new("a", AtomicMem).with_doc("Value atomically loaded"); 4055 let e = &Operand::new("e", AtomicMem).with_doc("Expected value in CAS"); 4056 let p = &Operand::new("p", iAddr); 4057 let MemFlags = &Operand::new("MemFlags", &imm.memflags); 4058 let AtomicRmwOp = &Operand::new("AtomicRmwOp", &imm.atomic_rmw_op); 4059 4060 ig.push( 4061 Inst::new( 4062 "atomic_rmw", 4063 r#" 4064 Atomically read-modify-write memory at `p`, with second operand `x`. The old value is 4065 returned. `p` has the type of the target word size, and `x` may be an integer type of 4066 8, 16, 32 or 64 bits, even on a 32-bit target. The type of the returned value is the 4067 same as the type of `x`. This operation is sequentially consistent and creates 4068 happens-before edges that order normal (non-atomic) loads and stores. 4069 "#, 4070 &formats.atomic_rmw, 4071 ) 4072 .operands_in(vec![MemFlags, AtomicRmwOp, p, 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_cas", 4082 r#" 4083 Perform an atomic compare-and-swap operation on memory at `p`, with expected value `e`, 4084 storing `x` if the value at `p` equals `e`. The old value at `p` is returned, 4085 regardless of whether the operation succeeds or fails. `p` has the type of the target 4086 word size, and `x` and `e` must have the same type and the same size, which may be an 4087 integer type of 8, 16, 32 or 64 bits, even on a 32-bit target. The type of the returned 4088 value is the same as the type of `x` and `e`. This operation is sequentially 4089 consistent and creates happens-before edges that order normal (non-atomic) loads and 4090 stores. 4091 "#, 4092 &formats.atomic_cas, 4093 ) 4094 .operands_in(vec![MemFlags, p, e, x]) 4095 .operands_out(vec![a]) 4096 .can_load(true) 4097 .can_store(true) 4098 .other_side_effects(true), 4099 ); 4100 4101 ig.push( 4102 Inst::new( 4103 "atomic_load", 4104 r#" 4105 Atomically load from memory at `p`. 4106 4107 This is a polymorphic instruction that can load any value type which has a memory 4108 representation. It should only be used for integer types with 8, 16, 32 or 64 bits. 4109 This operation is sequentially consistent and creates happens-before edges that order 4110 normal (non-atomic) loads and stores. 4111 "#, 4112 &formats.load_no_offset, 4113 ) 4114 .operands_in(vec![MemFlags, p]) 4115 .operands_out(vec![a]) 4116 .can_load(true) 4117 .other_side_effects(true), 4118 ); 4119 4120 ig.push( 4121 Inst::new( 4122 "atomic_store", 4123 r#" 4124 Atomically store `x` to memory at `p`. 4125 4126 This is a polymorphic instruction that can store any value type with a memory 4127 representation. It should only be used for integer types with 8, 16, 32 or 64 bits. 4128 This operation is sequentially consistent and creates happens-before edges that order 4129 normal (non-atomic) loads and stores. 4130 "#, 4131 &formats.store_no_offset, 4132 ) 4133 .operands_in(vec![MemFlags, x, p]) 4134 .can_store(true) 4135 .other_side_effects(true), 4136 ); 4137 4138 ig.push( 4139 Inst::new( 4140 "fence", 4141 r#" 4142 A memory fence. This must provide ordering to ensure that, at a minimum, neither loads 4143 nor stores of any kind may move forwards or backwards across the fence. This operation 4144 is sequentially consistent. 4145 "#, 4146 &formats.nullary, 4147 ) 4148 .other_side_effects(true), 4149 ); 4150 4151 let TxN = &TypeVar::new( 4152 "TxN", 4153 "A dynamic vector type", 4154 TypeSetBuilder::new() 4155 .ints(Interval::All) 4156 .floats(Interval::All) 4157 .bools(Interval::All) 4158 .dynamic_simd_lanes(Interval::All) 4159 .build(), 4160 ); 4161 let x = &Operand::new("x", TxN).with_doc("The dynamic vector to extract from"); 4162 let y = &Operand::new("y", &imm.uimm8).with_doc("128-bit vector index"); 4163 let a = &Operand::new("a", &TxN.dynamic_to_vector()).with_doc("New fixed vector"); 4164 4165 ig.push( 4166 Inst::new( 4167 "extract_vector", 4168 r#" 4169 Return a fixed length sub vector, extracted from a dynamic vector. 4170 "#, 4171 &formats.binary_imm8, 4172 ) 4173 .operands_in(vec![x, y]) 4174 .operands_out(vec![a]), 4175 ); 4176 } 4177