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