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