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