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