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