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 let TableOffset = &TypeVar::new( 1303 "TableOffset", 1304 "An unsigned table offset", 1305 TypeSetBuilder::new().ints(32..64).build(), 1306 ); 1307 1308 ig.push( 1309 Inst::new( 1310 "table_addr", 1311 r#" 1312 Bounds check and compute absolute address of a table entry. 1313 1314 Verify that the offset ``p`` is in bounds for the table T, and generate 1315 an absolute address that is safe to dereference. 1316 1317 ``Offset`` must be less than the size of a table element. 1318 1319 1. If ``p`` is not greater than the table bound, return an absolute 1320 address corresponding to a byte offset of ``p`` from the table's 1321 base address. 1322 2. If ``p`` is greater than the table bound, generate a trap. 1323 "#, 1324 &formats.table_addr, 1325 ) 1326 .operands_in(vec![ 1327 Operand::new("T", &entities.table), 1328 Operand::new("p", TableOffset), 1329 Operand::new("Offset", &imm.offset32).with_doc("Byte offset from element address"), 1330 ]) 1331 .operands_out(vec![Operand::new("addr", iAddr)]), 1332 ); 1333 1334 ig.push( 1335 Inst::new( 1336 "iconst", 1337 r#" 1338 Integer constant. 1339 1340 Create a scalar integer SSA value with an immediate constant value, or 1341 an integer vector where all the lanes have the same value. 1342 "#, 1343 &formats.unary_imm, 1344 ) 1345 .operands_in(vec![Operand::new("N", &imm.imm64)]) 1346 .operands_out(vec![ 1347 Operand::new("a", NarrowInt).with_doc("A constant integer scalar or vector value") 1348 ]), 1349 ); 1350 1351 ig.push( 1352 Inst::new( 1353 "f32const", 1354 r#" 1355 Floating point constant. 1356 1357 Create a `f32` SSA value with an immediate constant value. 1358 "#, 1359 &formats.unary_ieee32, 1360 ) 1361 .operands_in(vec![Operand::new("N", &imm.ieee32)]) 1362 .operands_out(vec![ 1363 Operand::new("a", f32_).with_doc("A constant f32 scalar value") 1364 ]), 1365 ); 1366 1367 ig.push( 1368 Inst::new( 1369 "f64const", 1370 r#" 1371 Floating point constant. 1372 1373 Create a `f64` SSA value with an immediate constant value. 1374 "#, 1375 &formats.unary_ieee64, 1376 ) 1377 .operands_in(vec![Operand::new("N", &imm.ieee64)]) 1378 .operands_out(vec![ 1379 Operand::new("a", f64_).with_doc("A constant f64 scalar value") 1380 ]), 1381 ); 1382 1383 ig.push( 1384 Inst::new( 1385 "vconst", 1386 r#" 1387 SIMD vector constant. 1388 1389 Construct a vector with the given immediate bytes. 1390 "#, 1391 &formats.unary_const, 1392 ) 1393 .operands_in(vec![Operand::new("N", &imm.pool_constant) 1394 .with_doc("The 16 immediate bytes of a 128-bit vector")]) 1395 .operands_out(vec![ 1396 Operand::new("a", TxN).with_doc("A constant vector value") 1397 ]), 1398 ); 1399 1400 let Tx16 = &TypeVar::new( 1401 "Tx16", 1402 "A SIMD vector with exactly 16 lanes of 8-bit values; eventually this may support other \ 1403 lane counts and widths", 1404 TypeSetBuilder::new() 1405 .ints(8..8) 1406 .simd_lanes(16..16) 1407 .includes_scalars(false) 1408 .build(), 1409 ); 1410 1411 ig.push( 1412 Inst::new( 1413 "shuffle", 1414 r#" 1415 SIMD vector shuffle. 1416 1417 Shuffle two vectors using the given immediate bytes. For each of the 16 bytes of the 1418 immediate, a value i of 0-15 selects the i-th element of the first vector and a value i of 1419 16-31 selects the (i-16)th element of the second vector. Immediate values outside of the 1420 0-31 range are not valid. 1421 "#, 1422 &formats.shuffle, 1423 ) 1424 .operands_in(vec![ 1425 Operand::new("a", Tx16).with_doc("A vector value"), 1426 Operand::new("b", Tx16).with_doc("A vector value"), 1427 Operand::new("mask", &imm.uimm128) 1428 .with_doc("The 16 immediate bytes used for selecting the elements to shuffle"), 1429 ]) 1430 .operands_out(vec![Operand::new("a", Tx16).with_doc("A vector value")]), 1431 ); 1432 1433 ig.push( 1434 Inst::new( 1435 "null", 1436 r#" 1437 Null constant value for reference types. 1438 1439 Create a scalar reference SSA value with a constant null value. 1440 "#, 1441 &formats.nullary, 1442 ) 1443 .operands_out(vec![ 1444 Operand::new("a", Ref).with_doc("A constant reference null value") 1445 ]), 1446 ); 1447 1448 ig.push(Inst::new( 1449 "nop", 1450 r#" 1451 Just a dummy instruction. 1452 1453 Note: this doesn't compile to a machine code nop. 1454 "#, 1455 &formats.nullary, 1456 )); 1457 1458 ig.push( 1459 Inst::new( 1460 "select", 1461 r#" 1462 Conditional select. 1463 1464 This instruction selects whole values. Use `bitselect` to choose each 1465 bit according to a mask. 1466 "#, 1467 &formats.ternary, 1468 ) 1469 .operands_in(vec![ 1470 Operand::new("c", ScalarTruthy).with_doc("Controlling value to test"), 1471 Operand::new("x", Any).with_doc("Value to use when `c` is true"), 1472 Operand::new("y", Any).with_doc("Value to use when `c` is false"), 1473 ]) 1474 .operands_out(vec![Operand::new("a", Any)]), 1475 ); 1476 1477 ig.push( 1478 Inst::new( 1479 "select_spectre_guard", 1480 r#" 1481 Conditional select intended for Spectre guards. 1482 1483 This operation is semantically equivalent to a select instruction. 1484 However, it is guaranteed to not be removed or otherwise altered by any 1485 optimization pass, and is guaranteed to result in a conditional-move 1486 instruction, not a branch-based lowering. As such, it is suitable 1487 for use when producing Spectre guards. For example, a bounds-check 1488 may guard against unsafe speculation past a bounds-check conditional 1489 branch by passing the address or index to be accessed through a 1490 conditional move, also gated on the same condition. Because no 1491 Spectre-vulnerable processors are known to perform speculation on 1492 conditional move instructions, this is guaranteed to pick the 1493 correct input. If the selected input in case of overflow is a "safe" 1494 value, for example a null pointer that causes an exception in the 1495 speculative path, this ensures that no Spectre vulnerability will 1496 exist. 1497 "#, 1498 &formats.ternary, 1499 ) 1500 .operands_in(vec![ 1501 Operand::new("c", ScalarTruthy).with_doc("Controlling value to test"), 1502 Operand::new("x", Any).with_doc("Value to use when `c` is true"), 1503 Operand::new("y", Any).with_doc("Value to use when `c` is false"), 1504 ]) 1505 .operands_out(vec![Operand::new("a", Any)]) 1506 .other_side_effects() 1507 // We can de-duplicate spectre selects since the side effect is 1508 // idempotent. 1509 .side_effects_idempotent(), 1510 ); 1511 1512 ig.push( 1513 Inst::new( 1514 "bitselect", 1515 r#" 1516 Conditional select of bits. 1517 1518 For each bit in `c`, this instruction selects the corresponding bit from `x` if the bit 1519 in `x` is 1 and the corresponding bit from `y` if the bit in `c` is 0. See also: 1520 `select`. 1521 "#, 1522 &formats.ternary, 1523 ) 1524 .operands_in(vec![ 1525 Operand::new("c", Any).with_doc("Controlling value to test"), 1526 Operand::new("x", Any).with_doc("Value to use when `c` is true"), 1527 Operand::new("y", Any).with_doc("Value to use when `c` is false"), 1528 ]) 1529 .operands_out(vec![Operand::new("a", Any)]), 1530 ); 1531 1532 ig.push( 1533 Inst::new( 1534 "x86_blendv", 1535 r#" 1536 A bitselect-lookalike instruction except with the semantics of 1537 `blendv`-related instructions on x86. 1538 1539 This instruction will use the top bit of each lane in `c`, the condition 1540 mask. If the bit is 1 then the corresponding lane from `x` is chosen. 1541 Otherwise the corresponding lane from `y` is chosen. 1542 1543 "#, 1544 &formats.ternary, 1545 ) 1546 .operands_in(vec![ 1547 Operand::new("c", Any).with_doc("Controlling value to test"), 1548 Operand::new("x", Any).with_doc("Value to use when `c` is true"), 1549 Operand::new("y", Any).with_doc("Value to use when `c` is false"), 1550 ]) 1551 .operands_out(vec![Operand::new("a", Any)]), 1552 ); 1553 1554 ig.push( 1555 Inst::new( 1556 "vany_true", 1557 r#" 1558 Reduce a vector to a scalar boolean. 1559 1560 Return a scalar boolean true if any lane in ``a`` is non-zero, false otherwise. 1561 "#, 1562 &formats.unary, 1563 ) 1564 .operands_in(vec![Operand::new("a", TxN)]) 1565 .operands_out(vec![Operand::new("s", i8)]), 1566 ); 1567 1568 ig.push( 1569 Inst::new( 1570 "vall_true", 1571 r#" 1572 Reduce a vector to a scalar boolean. 1573 1574 Return a scalar boolean true if all lanes in ``i`` are non-zero, false otherwise. 1575 "#, 1576 &formats.unary, 1577 ) 1578 .operands_in(vec![Operand::new("a", TxN)]) 1579 .operands_out(vec![Operand::new("s", i8)]), 1580 ); 1581 1582 ig.push( 1583 Inst::new( 1584 "vhigh_bits", 1585 r#" 1586 Reduce a vector to a scalar integer. 1587 1588 Return a scalar integer, consisting of the concatenation of the most significant bit 1589 of each lane of ``a``. 1590 "#, 1591 &formats.unary, 1592 ) 1593 .operands_in(vec![Operand::new("a", TxN)]) 1594 .operands_out(vec![Operand::new("x", NarrowInt)]), 1595 ); 1596 1597 ig.push( 1598 Inst::new( 1599 "icmp", 1600 r#" 1601 Integer comparison. 1602 1603 The condition code determines if the operands are interpreted as signed 1604 or unsigned integers. 1605 1606 | Signed | Unsigned | Condition | 1607 |--------|----------|-----------------------| 1608 | eq | eq | Equal | 1609 | ne | ne | Not equal | 1610 | slt | ult | Less than | 1611 | sge | uge | Greater than or equal | 1612 | sgt | ugt | Greater than | 1613 | sle | ule | Less than or equal | 1614 1615 When this instruction compares integer vectors, it returns a vector of 1616 lane-wise comparisons. 1617 1618 When comparing scalars, the result is: 1619 - `1` if the condition holds. 1620 - `0` if the condition does not hold. 1621 1622 When comparing vectors, the result is: 1623 - `-1` (i.e. all ones) in each lane where the condition holds. 1624 - `0` in each lane where the condition does not hold. 1625 "#, 1626 &formats.int_compare, 1627 ) 1628 .operands_in(vec![ 1629 Operand::new("Cond", &imm.intcc), 1630 Operand::new("x", Int), 1631 Operand::new("y", Int), 1632 ]) 1633 .operands_out(vec![Operand::new("a", &Int.as_truthy())]), 1634 ); 1635 1636 ig.push( 1637 Inst::new( 1638 "icmp_imm", 1639 r#" 1640 Compare scalar integer to a constant. 1641 1642 This is the same as the `icmp` instruction, except one operand is 1643 a sign extended 64 bit immediate constant. 1644 1645 This instruction can only compare scalars. Use `icmp` for 1646 lane-wise vector comparisons. 1647 "#, 1648 &formats.int_compare_imm, 1649 ) 1650 .operands_in(vec![ 1651 Operand::new("Cond", &imm.intcc), 1652 Operand::new("x", iB), 1653 Operand::new("Y", &imm.imm64), 1654 ]) 1655 .operands_out(vec![Operand::new("a", i8)]), 1656 ); 1657 1658 ig.push( 1659 Inst::new( 1660 "iadd", 1661 r#" 1662 Wrapping integer addition: `a := x + y \pmod{2^B}`. 1663 1664 This instruction does not depend on the signed/unsigned interpretation 1665 of the operands. 1666 "#, 1667 &formats.binary, 1668 ) 1669 .operands_in(vec![Operand::new("x", Int), Operand::new("y", Int)]) 1670 .operands_out(vec![Operand::new("a", Int)]), 1671 ); 1672 1673 ig.push( 1674 Inst::new( 1675 "isub", 1676 r#" 1677 Wrapping integer subtraction: `a := x - y \pmod{2^B}`. 1678 1679 This instruction does not depend on the signed/unsigned interpretation 1680 of the operands. 1681 "#, 1682 &formats.binary, 1683 ) 1684 .operands_in(vec![Operand::new("x", Int), Operand::new("y", Int)]) 1685 .operands_out(vec![Operand::new("a", Int)]), 1686 ); 1687 1688 ig.push( 1689 Inst::new( 1690 "ineg", 1691 r#" 1692 Integer negation: `a := -x \pmod{2^B}`. 1693 "#, 1694 &formats.unary, 1695 ) 1696 .operands_in(vec![Operand::new("x", Int)]) 1697 .operands_out(vec![Operand::new("a", Int)]), 1698 ); 1699 1700 ig.push( 1701 Inst::new( 1702 "iabs", 1703 r#" 1704 Integer absolute value with wrapping: `a := |x|`. 1705 "#, 1706 &formats.unary, 1707 ) 1708 .operands_in(vec![Operand::new("x", Int)]) 1709 .operands_out(vec![Operand::new("a", Int)]), 1710 ); 1711 1712 ig.push( 1713 Inst::new( 1714 "imul", 1715 r#" 1716 Wrapping integer multiplication: `a := x y \pmod{2^B}`. 1717 1718 This instruction does not depend on the signed/unsigned interpretation 1719 of the operands. 1720 1721 Polymorphic over all integer types (vector and scalar). 1722 "#, 1723 &formats.binary, 1724 ) 1725 .operands_in(vec![Operand::new("x", Int), Operand::new("y", Int)]) 1726 .operands_out(vec![Operand::new("a", Int)]), 1727 ); 1728 1729 ig.push( 1730 Inst::new( 1731 "umulhi", 1732 r#" 1733 Unsigned integer multiplication, producing the high half of a 1734 double-length result. 1735 1736 Polymorphic over all integer types (vector and scalar). 1737 "#, 1738 &formats.binary, 1739 ) 1740 .operands_in(vec![Operand::new("x", Int), Operand::new("y", Int)]) 1741 .operands_out(vec![Operand::new("a", Int)]), 1742 ); 1743 1744 ig.push( 1745 Inst::new( 1746 "smulhi", 1747 r#" 1748 Signed integer multiplication, producing the high half of a 1749 double-length result. 1750 1751 Polymorphic over all integer types (vector and scalar). 1752 "#, 1753 &formats.binary, 1754 ) 1755 .operands_in(vec![Operand::new("x", Int), Operand::new("y", Int)]) 1756 .operands_out(vec![Operand::new("a", Int)]), 1757 ); 1758 1759 let I16or32 = &TypeVar::new( 1760 "I16or32", 1761 "A vector integer type with 16- or 32-bit numbers", 1762 TypeSetBuilder::new().ints(16..32).simd_lanes(4..8).build(), 1763 ); 1764 1765 ig.push( 1766 Inst::new( 1767 "sqmul_round_sat", 1768 r#" 1769 Fixed-point multiplication of numbers in the QN format, where N + 1 1770 is the number bitwidth: 1771 `a := signed_saturate((x * y + 1 << (Q - 1)) >> Q)` 1772 1773 Polymorphic over all integer vector types with 16- or 32-bit numbers. 1774 "#, 1775 &formats.binary, 1776 ) 1777 .operands_in(vec![Operand::new("x", I16or32), Operand::new("y", I16or32)]) 1778 .operands_out(vec![Operand::new("a", I16or32)]), 1779 ); 1780 1781 ig.push( 1782 Inst::new( 1783 "x86_pmulhrsw", 1784 r#" 1785 A similar instruction to `sqmul_round_sat` except with the semantics 1786 of x86's `pmulhrsw` instruction. 1787 1788 This is the same as `sqmul_round_sat` except when both input lanes are 1789 `i16::MIN`. 1790 "#, 1791 &formats.binary, 1792 ) 1793 .operands_in(vec![Operand::new("x", I16or32), Operand::new("y", I16or32)]) 1794 .operands_out(vec![Operand::new("a", I16or32)]), 1795 ); 1796 1797 // Integer division and remainder are scalar-only; most 1798 // hardware does not directly support vector integer division. 1799 1800 ig.push( 1801 Inst::new( 1802 "udiv", 1803 r#" 1804 Unsigned integer division: `a := \lfloor {x \over y} \rfloor`. 1805 1806 This operation traps if the divisor is zero. 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 "sdiv", 1819 r#" 1820 Signed integer division rounded toward zero: `a := sign(xy) 1821 \lfloor {|x| \over |y|}\rfloor`. 1822 1823 This operation traps if the divisor is zero, or if the result is not 1824 representable in `B` bits two's complement. This only happens 1825 when `x = -2^{B-1}, y = -1`. 1826 "#, 1827 &formats.binary, 1828 ) 1829 .operands_in(vec![Operand::new("x", iB), Operand::new("y", iB)]) 1830 .operands_out(vec![Operand::new("a", iB)]) 1831 .can_trap() 1832 .side_effects_idempotent(), 1833 ); 1834 1835 ig.push( 1836 Inst::new( 1837 "urem", 1838 r#" 1839 Unsigned integer remainder. 1840 1841 This operation traps if the divisor is zero. 1842 "#, 1843 &formats.binary, 1844 ) 1845 .operands_in(vec![Operand::new("x", iB), Operand::new("y", iB)]) 1846 .operands_out(vec![Operand::new("a", iB)]) 1847 .can_trap() 1848 .side_effects_idempotent(), 1849 ); 1850 1851 ig.push( 1852 Inst::new( 1853 "srem", 1854 r#" 1855 Signed integer remainder. The result has the sign of the dividend. 1856 1857 This operation traps if the divisor is zero. 1858 "#, 1859 &formats.binary, 1860 ) 1861 .operands_in(vec![Operand::new("x", iB), Operand::new("y", iB)]) 1862 .operands_out(vec![Operand::new("a", iB)]) 1863 .can_trap() 1864 .side_effects_idempotent(), 1865 ); 1866 1867 ig.push( 1868 Inst::new( 1869 "iadd_imm", 1870 r#" 1871 Add immediate integer. 1872 1873 Same as `iadd`, but one operand is a sign extended 64 bit immediate constant. 1874 1875 Polymorphic over all scalar integer types, but does not support vector 1876 types. 1877 "#, 1878 &formats.binary_imm64, 1879 ) 1880 .operands_in(vec![Operand::new("x", iB), Operand::new("Y", &imm.imm64)]) 1881 .operands_out(vec![Operand::new("a", iB)]), 1882 ); 1883 1884 ig.push( 1885 Inst::new( 1886 "imul_imm", 1887 r#" 1888 Integer multiplication by immediate constant. 1889 1890 Same as `imul`, but one operand is a sign extended 64 bit immediate constant. 1891 1892 Polymorphic over all scalar integer types, but does not support vector 1893 types. 1894 "#, 1895 &formats.binary_imm64, 1896 ) 1897 .operands_in(vec![Operand::new("x", iB), Operand::new("Y", &imm.imm64)]) 1898 .operands_out(vec![Operand::new("a", iB)]), 1899 ); 1900 1901 ig.push( 1902 Inst::new( 1903 "udiv_imm", 1904 r#" 1905 Unsigned integer division by an immediate constant. 1906 1907 Same as `udiv`, but one operand is a zero extended 64 bit immediate constant. 1908 1909 This operation traps if the divisor is zero. 1910 "#, 1911 &formats.binary_imm64, 1912 ) 1913 .operands_in(vec![Operand::new("x", iB), Operand::new("Y", &imm.imm64)]) 1914 .operands_out(vec![Operand::new("a", iB)]), 1915 ); 1916 1917 ig.push( 1918 Inst::new( 1919 "sdiv_imm", 1920 r#" 1921 Signed integer division by an immediate constant. 1922 1923 Same as `sdiv`, but one operand is a sign extended 64 bit immediate constant. 1924 1925 This operation traps if the divisor is zero, or if the result is not 1926 representable in `B` bits two's complement. This only happens 1927 when `x = -2^{B-1}, Y = -1`. 1928 "#, 1929 &formats.binary_imm64, 1930 ) 1931 .operands_in(vec![Operand::new("x", iB), Operand::new("Y", &imm.imm64)]) 1932 .operands_out(vec![Operand::new("a", iB)]), 1933 ); 1934 1935 ig.push( 1936 Inst::new( 1937 "urem_imm", 1938 r#" 1939 Unsigned integer remainder with immediate divisor. 1940 1941 Same as `urem`, but one operand is a zero extended 64 bit immediate constant. 1942 1943 This operation traps if the divisor is zero. 1944 "#, 1945 &formats.binary_imm64, 1946 ) 1947 .operands_in(vec![Operand::new("x", iB), Operand::new("Y", &imm.imm64)]) 1948 .operands_out(vec![Operand::new("a", iB)]), 1949 ); 1950 1951 ig.push( 1952 Inst::new( 1953 "srem_imm", 1954 r#" 1955 Signed integer remainder with immediate divisor. 1956 1957 Same as `srem`, but one operand is a sign extended 64 bit immediate constant. 1958 1959 This operation traps if the divisor is zero. 1960 "#, 1961 &formats.binary_imm64, 1962 ) 1963 .operands_in(vec![Operand::new("x", iB), Operand::new("Y", &imm.imm64)]) 1964 .operands_out(vec![Operand::new("a", iB)]), 1965 ); 1966 1967 ig.push( 1968 Inst::new( 1969 "irsub_imm", 1970 r#" 1971 Immediate reverse wrapping subtraction: `a := Y - x \pmod{2^B}`. 1972 1973 The immediate operand is a sign extended 64 bit constant. 1974 1975 Also works as integer negation when `Y = 0`. Use `iadd_imm` 1976 with a negative immediate operand for the reverse immediate 1977 subtraction. 1978 1979 Polymorphic over all scalar integer types, but does not support vector 1980 types. 1981 "#, 1982 &formats.binary_imm64, 1983 ) 1984 .operands_in(vec![Operand::new("x", iB), Operand::new("Y", &imm.imm64)]) 1985 .operands_out(vec![Operand::new("a", iB)]), 1986 ); 1987 1988 ig.push( 1989 Inst::new( 1990 "iadd_cin", 1991 r#" 1992 Add integers with carry in. 1993 1994 Same as `iadd` with an additional carry input. Computes: 1995 1996 ```text 1997 a = x + y + c_{in} \pmod 2^B 1998 ``` 1999 2000 Polymorphic over all scalar integer types, but does not support vector 2001 types. 2002 "#, 2003 &formats.ternary, 2004 ) 2005 .operands_in(vec![ 2006 Operand::new("x", iB), 2007 Operand::new("y", iB), 2008 Operand::new("c_in", i8).with_doc("Input carry flag"), 2009 ]) 2010 .operands_out(vec![Operand::new("a", iB)]), 2011 ); 2012 2013 ig.push( 2014 Inst::new( 2015 "iadd_carry", 2016 r#" 2017 Add integers with carry in and out. 2018 2019 Same as `iadd` with an additional carry input and output. 2020 2021 ```text 2022 a &= x + y + c_{in} \pmod 2^B \\ 2023 c_{out} &= x + y + c_{in} >= 2^B 2024 ``` 2025 2026 Polymorphic over all scalar integer types, but does not support vector 2027 types. 2028 "#, 2029 &formats.ternary, 2030 ) 2031 .operands_in(vec![ 2032 Operand::new("x", iB), 2033 Operand::new("y", iB), 2034 Operand::new("c_in", i8).with_doc("Input carry flag"), 2035 ]) 2036 .operands_out(vec![ 2037 Operand::new("a", iB), 2038 Operand::new("c_out", i8).with_doc("Output carry flag"), 2039 ]), 2040 ); 2041 2042 { 2043 let of_out = Operand::new("of", i8).with_doc("Overflow flag"); 2044 ig.push( 2045 Inst::new( 2046 "uadd_overflow", 2047 r#" 2048 Add integers unsigned with overflow out. 2049 ``of`` is set when the addition overflowed. 2050 ```text 2051 a &= x + y \pmod 2^B \\ 2052 of &= x+y >= 2^B 2053 ``` 2054 Polymorphic over all scalar integer types, but does not support vector 2055 types. 2056 "#, 2057 &formats.binary, 2058 ) 2059 .operands_in(vec![Operand::new("x", iB), Operand::new("y", iB)]) 2060 .operands_out(vec![Operand::new("a", iB), of_out.clone()]), 2061 ); 2062 2063 ig.push( 2064 Inst::new( 2065 "sadd_overflow", 2066 r#" 2067 Add integers signed with overflow out. 2068 ``of`` is set when the addition over- or underflowed. 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 "usub_overflow", 2081 r#" 2082 Subtract integers unsigned with overflow out. 2083 ``of`` is set when the subtraction underflowed. 2084 ```text 2085 a &= x - y \pmod 2^B \\ 2086 of &= x - y < 0 2087 ``` 2088 Polymorphic over all scalar integer types, but does not support vector 2089 types. 2090 "#, 2091 &formats.binary, 2092 ) 2093 .operands_in(vec![Operand::new("x", iB), Operand::new("y", iB)]) 2094 .operands_out(vec![Operand::new("a", iB), of_out.clone()]), 2095 ); 2096 2097 ig.push( 2098 Inst::new( 2099 "ssub_overflow", 2100 r#" 2101 Subtract integers signed with overflow out. 2102 ``of`` is set when the subtraction over- or underflowed. 2103 Polymorphic over all scalar integer types, but does not support vector 2104 types. 2105 "#, 2106 &formats.binary, 2107 ) 2108 .operands_in(vec![Operand::new("x", iB), Operand::new("y", iB)]) 2109 .operands_out(vec![Operand::new("a", iB), of_out.clone()]), 2110 ); 2111 2112 { 2113 let NarrowScalar = &TypeVar::new( 2114 "NarrowScalar", 2115 "A scalar integer type up to 64 bits", 2116 TypeSetBuilder::new().ints(8..64).build(), 2117 ); 2118 2119 ig.push( 2120 Inst::new( 2121 "umul_overflow", 2122 r#" 2123 Multiply integers unsigned with overflow out. 2124 ``of`` is set when the multiplication overflowed. 2125 ```text 2126 a &= x * y \pmod 2^B \\ 2127 of &= x * y > 2^B 2128 ``` 2129 Polymorphic over all scalar integer types except i128, but does not support vector 2130 types. 2131 "#, 2132 &formats.binary, 2133 ) 2134 .operands_in(vec![ 2135 Operand::new("x", NarrowScalar), 2136 Operand::new("y", NarrowScalar), 2137 ]) 2138 .operands_out(vec![Operand::new("a", NarrowScalar), of_out.clone()]), 2139 ); 2140 2141 ig.push( 2142 Inst::new( 2143 "smul_overflow", 2144 r#" 2145 Multiply integers signed with overflow out. 2146 ``of`` is set when the multiplication over- or underflowed. 2147 Polymorphic over all scalar integer types except i128, but does not support vector 2148 types. 2149 "#, 2150 &formats.binary, 2151 ) 2152 .operands_in(vec![ 2153 Operand::new("x", NarrowScalar), 2154 Operand::new("y", NarrowScalar), 2155 ]) 2156 .operands_out(vec![Operand::new("a", NarrowScalar), of_out.clone()]), 2157 ); 2158 } 2159 } 2160 2161 let i32_64 = &TypeVar::new( 2162 "i32_64", 2163 "A 32 or 64-bit scalar integer type", 2164 TypeSetBuilder::new().ints(32..64).build(), 2165 ); 2166 2167 ig.push( 2168 Inst::new( 2169 "uadd_overflow_trap", 2170 r#" 2171 Unsigned addition of x and y, trapping if the result overflows. 2172 2173 Accepts 32 or 64-bit integers, and does not support vector types. 2174 "#, 2175 &formats.int_add_trap, 2176 ) 2177 .operands_in(vec![ 2178 Operand::new("x", i32_64), 2179 Operand::new("y", i32_64), 2180 Operand::new("code", &imm.trapcode), 2181 ]) 2182 .operands_out(vec![Operand::new("a", i32_64)]) 2183 .can_trap() 2184 .side_effects_idempotent(), 2185 ); 2186 2187 ig.push( 2188 Inst::new( 2189 "isub_bin", 2190 r#" 2191 Subtract integers with borrow in. 2192 2193 Same as `isub` with an additional borrow flag input. Computes: 2194 2195 ```text 2196 a = x - (y + b_{in}) \pmod 2^B 2197 ``` 2198 2199 Polymorphic over all scalar integer types, but does not support vector 2200 types. 2201 "#, 2202 &formats.ternary, 2203 ) 2204 .operands_in(vec![ 2205 Operand::new("x", iB), 2206 Operand::new("y", iB), 2207 Operand::new("b_in", i8).with_doc("Input borrow flag"), 2208 ]) 2209 .operands_out(vec![Operand::new("a", iB)]), 2210 ); 2211 2212 ig.push( 2213 Inst::new( 2214 "isub_borrow", 2215 r#" 2216 Subtract integers with borrow in and out. 2217 2218 Same as `isub` with an additional borrow flag input and output. 2219 2220 ```text 2221 a &= x - (y + b_{in}) \pmod 2^B \\ 2222 b_{out} &= x < y + b_{in} 2223 ``` 2224 2225 Polymorphic over all scalar integer types, but does not support vector 2226 types. 2227 "#, 2228 &formats.ternary, 2229 ) 2230 .operands_in(vec![ 2231 Operand::new("x", iB), 2232 Operand::new("y", iB), 2233 Operand::new("b_in", i8).with_doc("Input borrow flag"), 2234 ]) 2235 .operands_out(vec![ 2236 Operand::new("a", iB), 2237 Operand::new("b_out", i8).with_doc("Output borrow flag"), 2238 ]), 2239 ); 2240 2241 let bits = &TypeVar::new( 2242 "bits", 2243 "Any integer, float, or vector type", 2244 TypeSetBuilder::new() 2245 .ints(Interval::All) 2246 .floats(Interval::All) 2247 .simd_lanes(Interval::All) 2248 .includes_scalars(true) 2249 .build(), 2250 ); 2251 2252 ig.push( 2253 Inst::new( 2254 "band", 2255 r#" 2256 Bitwise and. 2257 "#, 2258 &formats.binary, 2259 ) 2260 .operands_in(vec![Operand::new("x", bits), Operand::new("y", bits)]) 2261 .operands_out(vec![Operand::new("a", bits)]), 2262 ); 2263 2264 ig.push( 2265 Inst::new( 2266 "bor", 2267 r#" 2268 Bitwise or. 2269 "#, 2270 &formats.binary, 2271 ) 2272 .operands_in(vec![Operand::new("x", bits), Operand::new("y", bits)]) 2273 .operands_out(vec![Operand::new("a", bits)]), 2274 ); 2275 2276 ig.push( 2277 Inst::new( 2278 "bxor", 2279 r#" 2280 Bitwise xor. 2281 "#, 2282 &formats.binary, 2283 ) 2284 .operands_in(vec![Operand::new("x", bits), Operand::new("y", bits)]) 2285 .operands_out(vec![Operand::new("a", bits)]), 2286 ); 2287 2288 ig.push( 2289 Inst::new( 2290 "bnot", 2291 r#" 2292 Bitwise not. 2293 "#, 2294 &formats.unary, 2295 ) 2296 .operands_in(vec![Operand::new("x", bits)]) 2297 .operands_out(vec![Operand::new("a", bits)]), 2298 ); 2299 2300 ig.push( 2301 Inst::new( 2302 "band_not", 2303 r#" 2304 Bitwise and not. 2305 2306 Computes `x & ~y`. 2307 "#, 2308 &formats.binary, 2309 ) 2310 .operands_in(vec![Operand::new("x", bits), Operand::new("y", bits)]) 2311 .operands_out(vec![Operand::new("a", bits)]), 2312 ); 2313 2314 ig.push( 2315 Inst::new( 2316 "bor_not", 2317 r#" 2318 Bitwise or not. 2319 2320 Computes `x | ~y`. 2321 "#, 2322 &formats.binary, 2323 ) 2324 .operands_in(vec![Operand::new("x", bits), Operand::new("y", bits)]) 2325 .operands_out(vec![Operand::new("a", bits)]), 2326 ); 2327 2328 ig.push( 2329 Inst::new( 2330 "bxor_not", 2331 r#" 2332 Bitwise xor not. 2333 2334 Computes `x ^ ~y`. 2335 "#, 2336 &formats.binary, 2337 ) 2338 .operands_in(vec![Operand::new("x", bits), Operand::new("y", bits)]) 2339 .operands_out(vec![Operand::new("a", bits)]), 2340 ); 2341 2342 ig.push( 2343 Inst::new( 2344 "band_imm", 2345 r#" 2346 Bitwise and with immediate. 2347 2348 Same as `band`, but one operand is a zero extended 64 bit immediate constant. 2349 2350 Polymorphic over all scalar integer types, but does not support vector 2351 types. 2352 "#, 2353 &formats.binary_imm64, 2354 ) 2355 .operands_in(vec![Operand::new("x", iB), Operand::new("Y", &imm.imm64)]) 2356 .operands_out(vec![Operand::new("a", iB)]), 2357 ); 2358 2359 ig.push( 2360 Inst::new( 2361 "bor_imm", 2362 r#" 2363 Bitwise or with immediate. 2364 2365 Same as `bor`, but one operand is a zero extended 64 bit immediate constant. 2366 2367 Polymorphic over all scalar integer types, but does not support vector 2368 types. 2369 "#, 2370 &formats.binary_imm64, 2371 ) 2372 .operands_in(vec![Operand::new("x", iB), Operand::new("Y", &imm.imm64)]) 2373 .operands_out(vec![Operand::new("a", iB)]), 2374 ); 2375 2376 ig.push( 2377 Inst::new( 2378 "bxor_imm", 2379 r#" 2380 Bitwise xor with immediate. 2381 2382 Same as `bxor`, but one operand is a zero extended 64 bit immediate constant. 2383 2384 Polymorphic over all scalar integer types, but does not support vector 2385 types. 2386 "#, 2387 &formats.binary_imm64, 2388 ) 2389 .operands_in(vec![Operand::new("x", iB), Operand::new("Y", &imm.imm64)]) 2390 .operands_out(vec![Operand::new("a", iB)]), 2391 ); 2392 2393 ig.push( 2394 Inst::new( 2395 "rotl", 2396 r#" 2397 Rotate left. 2398 2399 Rotate the bits in ``x`` by ``y`` places. 2400 "#, 2401 &formats.binary, 2402 ) 2403 .operands_in(vec![ 2404 Operand::new("x", Int).with_doc("Scalar or vector value to shift"), 2405 Operand::new("y", iB).with_doc("Number of bits to shift"), 2406 ]) 2407 .operands_out(vec![Operand::new("a", Int)]), 2408 ); 2409 2410 ig.push( 2411 Inst::new( 2412 "rotr", 2413 r#" 2414 Rotate right. 2415 2416 Rotate the bits in ``x`` by ``y`` places. 2417 "#, 2418 &formats.binary, 2419 ) 2420 .operands_in(vec![ 2421 Operand::new("x", Int).with_doc("Scalar or vector value to shift"), 2422 Operand::new("y", iB).with_doc("Number of bits to shift"), 2423 ]) 2424 .operands_out(vec![Operand::new("a", Int)]), 2425 ); 2426 2427 ig.push( 2428 Inst::new( 2429 "rotl_imm", 2430 r#" 2431 Rotate left by immediate. 2432 2433 Same as `rotl`, but one operand is a zero extended 64 bit immediate constant. 2434 "#, 2435 &formats.binary_imm64, 2436 ) 2437 .operands_in(vec![ 2438 Operand::new("x", Int).with_doc("Scalar or vector value to shift"), 2439 Operand::new("Y", &imm.imm64), 2440 ]) 2441 .operands_out(vec![Operand::new("a", Int)]), 2442 ); 2443 2444 ig.push( 2445 Inst::new( 2446 "rotr_imm", 2447 r#" 2448 Rotate right by immediate. 2449 2450 Same as `rotr`, but one operand is a zero extended 64 bit immediate constant. 2451 "#, 2452 &formats.binary_imm64, 2453 ) 2454 .operands_in(vec![ 2455 Operand::new("x", Int).with_doc("Scalar or vector value to shift"), 2456 Operand::new("Y", &imm.imm64), 2457 ]) 2458 .operands_out(vec![Operand::new("a", Int)]), 2459 ); 2460 2461 ig.push( 2462 Inst::new( 2463 "ishl", 2464 r#" 2465 Integer shift left. Shift the bits in ``x`` towards the MSB by ``y`` 2466 places. Shift in zero bits to the LSB. 2467 2468 The shift amount is masked to the size of ``x``. 2469 2470 When shifting a B-bits integer type, this instruction computes: 2471 2472 ```text 2473 s &:= y \pmod B, 2474 a &:= x \cdot 2^s \pmod{2^B}. 2475 ``` 2476 "#, 2477 &formats.binary, 2478 ) 2479 .operands_in(vec![ 2480 Operand::new("x", Int).with_doc("Scalar or vector value to shift"), 2481 Operand::new("y", iB).with_doc("Number of bits to shift"), 2482 ]) 2483 .operands_out(vec![Operand::new("a", Int)]), 2484 ); 2485 2486 ig.push( 2487 Inst::new( 2488 "ushr", 2489 r#" 2490 Unsigned shift right. Shift bits in ``x`` towards the LSB by ``y`` 2491 places, shifting in zero bits to the MSB. Also called a *logical 2492 shift*. 2493 2494 The shift amount is masked to the size of ``x``. 2495 2496 When shifting a B-bits integer type, this instruction computes: 2497 2498 ```text 2499 s &:= y \pmod B, 2500 a &:= \lfloor x \cdot 2^{-s} \rfloor. 2501 ``` 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 "sshr", 2515 r#" 2516 Signed shift right. Shift bits in ``x`` towards the LSB by ``y`` 2517 places, shifting in sign bits to the MSB. Also called an *arithmetic 2518 shift*. 2519 2520 The shift amount is masked to the size of ``x``. 2521 "#, 2522 &formats.binary, 2523 ) 2524 .operands_in(vec![ 2525 Operand::new("x", Int).with_doc("Scalar or vector value to shift"), 2526 Operand::new("y", iB).with_doc("Number of bits to shift"), 2527 ]) 2528 .operands_out(vec![Operand::new("a", Int)]), 2529 ); 2530 2531 ig.push( 2532 Inst::new( 2533 "ishl_imm", 2534 r#" 2535 Integer shift left by immediate. 2536 2537 The shift amount is masked to the size of ``x``. 2538 "#, 2539 &formats.binary_imm64, 2540 ) 2541 .operands_in(vec![ 2542 Operand::new("x", Int).with_doc("Scalar or vector value to shift"), 2543 Operand::new("Y", &imm.imm64), 2544 ]) 2545 .operands_out(vec![Operand::new("a", Int)]), 2546 ); 2547 2548 ig.push( 2549 Inst::new( 2550 "ushr_imm", 2551 r#" 2552 Unsigned shift right by immediate. 2553 2554 The shift amount is masked to the size of ``x``. 2555 "#, 2556 &formats.binary_imm64, 2557 ) 2558 .operands_in(vec![ 2559 Operand::new("x", Int).with_doc("Scalar or vector value to shift"), 2560 Operand::new("Y", &imm.imm64), 2561 ]) 2562 .operands_out(vec![Operand::new("a", Int)]), 2563 ); 2564 2565 ig.push( 2566 Inst::new( 2567 "sshr_imm", 2568 r#" 2569 Signed shift right by immediate. 2570 2571 The shift amount is masked to the size of ``x``. 2572 "#, 2573 &formats.binary_imm64, 2574 ) 2575 .operands_in(vec![ 2576 Operand::new("x", Int).with_doc("Scalar or vector value to shift"), 2577 Operand::new("Y", &imm.imm64), 2578 ]) 2579 .operands_out(vec![Operand::new("a", Int)]), 2580 ); 2581 2582 ig.push( 2583 Inst::new( 2584 "bitrev", 2585 r#" 2586 Reverse the bits of a integer. 2587 2588 Reverses the bits in ``x``. 2589 "#, 2590 &formats.unary, 2591 ) 2592 .operands_in(vec![Operand::new("x", iB)]) 2593 .operands_out(vec![Operand::new("a", iB)]), 2594 ); 2595 2596 ig.push( 2597 Inst::new( 2598 "clz", 2599 r#" 2600 Count leading zero bits. 2601 2602 Starting from the MSB in ``x``, count the number of zero bits before 2603 reaching the first one bit. When ``x`` is zero, returns the size of x 2604 in bits. 2605 "#, 2606 &formats.unary, 2607 ) 2608 .operands_in(vec![Operand::new("x", iB)]) 2609 .operands_out(vec![Operand::new("a", iB)]), 2610 ); 2611 2612 ig.push( 2613 Inst::new( 2614 "cls", 2615 r#" 2616 Count leading sign bits. 2617 2618 Starting from the MSB after the sign bit in ``x``, count the number of 2619 consecutive bits identical to the sign bit. When ``x`` is 0 or -1, 2620 returns one less than the size of x in bits. 2621 "#, 2622 &formats.unary, 2623 ) 2624 .operands_in(vec![Operand::new("x", iB)]) 2625 .operands_out(vec![Operand::new("a", iB)]), 2626 ); 2627 2628 ig.push( 2629 Inst::new( 2630 "ctz", 2631 r#" 2632 Count trailing zeros. 2633 2634 Starting from the LSB in ``x``, count the number of zero bits before 2635 reaching the first one bit. When ``x`` is zero, returns the size of x 2636 in bits. 2637 "#, 2638 &formats.unary, 2639 ) 2640 .operands_in(vec![Operand::new("x", iB)]) 2641 .operands_out(vec![Operand::new("a", iB)]), 2642 ); 2643 2644 ig.push( 2645 Inst::new( 2646 "bswap", 2647 r#" 2648 Reverse the byte order of an integer. 2649 2650 Reverses the bytes in ``x``. 2651 "#, 2652 &formats.unary, 2653 ) 2654 .operands_in(vec![Operand::new("x", iSwappable)]) 2655 .operands_out(vec![Operand::new("a", iSwappable)]), 2656 ); 2657 2658 ig.push( 2659 Inst::new( 2660 "popcnt", 2661 r#" 2662 Population count 2663 2664 Count the number of one bits in ``x``. 2665 "#, 2666 &formats.unary, 2667 ) 2668 .operands_in(vec![Operand::new("x", Int)]) 2669 .operands_out(vec![Operand::new("a", Int)]), 2670 ); 2671 2672 let Float = &TypeVar::new( 2673 "Float", 2674 "A scalar or vector floating point number", 2675 TypeSetBuilder::new() 2676 .floats(Interval::All) 2677 .simd_lanes(Interval::All) 2678 .dynamic_simd_lanes(Interval::All) 2679 .build(), 2680 ); 2681 2682 ig.push( 2683 Inst::new( 2684 "fcmp", 2685 r#" 2686 Floating point comparison. 2687 2688 Two IEEE 754-2008 floating point numbers, `x` and `y`, relate to each 2689 other in exactly one of four ways: 2690 2691 ```text 2692 == ========================================== 2693 UN Unordered when one or both numbers is NaN. 2694 EQ When `x = y`. (And `0.0 = -0.0`). 2695 LT When `x < y`. 2696 GT When `x > y`. 2697 == ========================================== 2698 ``` 2699 2700 The 14 `floatcc` condition codes each correspond to a subset of 2701 the four relations, except for the empty set which would always be 2702 false, and the full set which would always be true. 2703 2704 The condition codes are divided into 7 'ordered' conditions which don't 2705 include UN, and 7 unordered conditions which all include UN. 2706 2707 ```text 2708 +-------+------------+---------+------------+-------------------------+ 2709 |Ordered |Unordered |Condition | 2710 +=======+============+=========+============+=========================+ 2711 |ord |EQ | LT | GT|uno |UN |NaNs absent / present. | 2712 +-------+------------+---------+------------+-------------------------+ 2713 |eq |EQ |ueq |UN | EQ |Equal | 2714 +-------+------------+---------+------------+-------------------------+ 2715 |one |LT | GT |ne |UN | LT | GT|Not equal | 2716 +-------+------------+---------+------------+-------------------------+ 2717 |lt |LT |ult |UN | LT |Less than | 2718 +-------+------------+---------+------------+-------------------------+ 2719 |le |LT | EQ |ule |UN | LT | EQ|Less than or equal | 2720 +-------+------------+---------+------------+-------------------------+ 2721 |gt |GT |ugt |UN | GT |Greater than | 2722 +-------+------------+---------+------------+-------------------------+ 2723 |ge |GT | EQ |uge |UN | GT | EQ|Greater than or equal | 2724 +-------+------------+---------+------------+-------------------------+ 2725 ``` 2726 2727 The standard C comparison operators, `<, <=, >, >=`, are all ordered, 2728 so they are false if either operand is NaN. The C equality operator, 2729 `==`, is ordered, and since inequality is defined as the logical 2730 inverse it is *unordered*. They map to the `floatcc` condition 2731 codes as follows: 2732 2733 ```text 2734 ==== ====== ============ 2735 C `Cond` Subset 2736 ==== ====== ============ 2737 `==` eq EQ 2738 `!=` ne UN | LT | GT 2739 `<` lt LT 2740 `<=` le LT | EQ 2741 `>` gt GT 2742 `>=` ge GT | EQ 2743 ==== ====== ============ 2744 ``` 2745 2746 This subset of condition codes also corresponds to the WebAssembly 2747 floating point comparisons of the same name. 2748 2749 When this instruction compares floating point vectors, it returns a 2750 vector with the results of lane-wise comparisons. 2751 2752 When comparing scalars, the result is: 2753 - `1` if the condition holds. 2754 - `0` if the condition does not hold. 2755 2756 When comparing vectors, the result is: 2757 - `-1` (i.e. all ones) in each lane where the condition holds. 2758 - `0` in each lane where the condition does not hold. 2759 "#, 2760 &formats.float_compare, 2761 ) 2762 .operands_in(vec![ 2763 Operand::new("Cond", &imm.floatcc), 2764 Operand::new("x", Float), 2765 Operand::new("y", Float), 2766 ]) 2767 .operands_out(vec![Operand::new("a", &Float.as_truthy())]), 2768 ); 2769 2770 ig.push( 2771 Inst::new( 2772 "fadd", 2773 r#" 2774 Floating point addition. 2775 "#, 2776 &formats.binary, 2777 ) 2778 .operands_in(vec![Operand::new("x", Float), Operand::new("y", Float)]) 2779 .operands_out(vec![ 2780 Operand::new("a", Float).with_doc("Result of applying operator to each lane") 2781 ]), 2782 ); 2783 2784 ig.push( 2785 Inst::new( 2786 "fsub", 2787 r#" 2788 Floating point subtraction. 2789 "#, 2790 &formats.binary, 2791 ) 2792 .operands_in(vec![Operand::new("x", Float), Operand::new("y", Float)]) 2793 .operands_out(vec![ 2794 Operand::new("a", Float).with_doc("Result of applying operator to each lane") 2795 ]), 2796 ); 2797 2798 ig.push( 2799 Inst::new( 2800 "fmul", 2801 r#" 2802 Floating point multiplication. 2803 "#, 2804 &formats.binary, 2805 ) 2806 .operands_in(vec![Operand::new("x", Float), Operand::new("y", Float)]) 2807 .operands_out(vec![ 2808 Operand::new("a", Float).with_doc("Result of applying operator to each lane") 2809 ]), 2810 ); 2811 2812 ig.push( 2813 Inst::new( 2814 "fdiv", 2815 r#" 2816 Floating point division. 2817 2818 Unlike the integer division instructions ` and 2819 `udiv`, this can't trap. Division by zero is infinity or 2820 NaN, depending on the dividend. 2821 "#, 2822 &formats.binary, 2823 ) 2824 .operands_in(vec![Operand::new("x", Float), Operand::new("y", Float)]) 2825 .operands_out(vec![ 2826 Operand::new("a", Float).with_doc("Result of applying operator to each lane") 2827 ]), 2828 ); 2829 2830 ig.push( 2831 Inst::new( 2832 "sqrt", 2833 r#" 2834 Floating point square root. 2835 "#, 2836 &formats.unary, 2837 ) 2838 .operands_in(vec![Operand::new("x", Float)]) 2839 .operands_out(vec![ 2840 Operand::new("a", Float).with_doc("Result of applying operator to each lane") 2841 ]), 2842 ); 2843 2844 ig.push( 2845 Inst::new( 2846 "fma", 2847 r#" 2848 Floating point fused multiply-and-add. 2849 2850 Computes `a := xy+z` without any intermediate rounding of the 2851 product. 2852 "#, 2853 &formats.ternary, 2854 ) 2855 .operands_in(vec![ 2856 Operand::new("x", Float), 2857 Operand::new("y", Float), 2858 Operand::new("z", Float), 2859 ]) 2860 .operands_out(vec![ 2861 Operand::new("a", Float).with_doc("Result of applying operator to each lane") 2862 ]), 2863 ); 2864 2865 ig.push( 2866 Inst::new( 2867 "fneg", 2868 r#" 2869 Floating point negation. 2870 2871 Note that this is a pure bitwise operation. 2872 "#, 2873 &formats.unary, 2874 ) 2875 .operands_in(vec![Operand::new("x", Float)]) 2876 .operands_out(vec![ 2877 Operand::new("a", Float).with_doc("``x`` with its sign bit inverted") 2878 ]), 2879 ); 2880 2881 ig.push( 2882 Inst::new( 2883 "fabs", 2884 r#" 2885 Floating point absolute value. 2886 2887 Note that this is a pure bitwise operation. 2888 "#, 2889 &formats.unary, 2890 ) 2891 .operands_in(vec![Operand::new("x", Float)]) 2892 .operands_out(vec![ 2893 Operand::new("a", Float).with_doc("``x`` with its sign bit cleared") 2894 ]), 2895 ); 2896 2897 ig.push( 2898 Inst::new( 2899 "fcopysign", 2900 r#" 2901 Floating point copy sign. 2902 2903 Note that this is a pure bitwise operation. The sign bit from ``y`` is 2904 copied to the sign bit of ``x``. 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("``x`` with its sign bit changed to that of ``y``") 2911 ]), 2912 ); 2913 2914 ig.push( 2915 Inst::new( 2916 "fmin", 2917 r#" 2918 Floating point minimum, 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 smaller of ``x`` and ``y``") 2930 ]), 2931 ); 2932 2933 ig.push( 2934 Inst::new( 2935 "fmax", 2936 r#" 2937 Floating point maximum, propagating NaNs using the WebAssembly rules. 2938 2939 If either operand is NaN, this returns NaN with an unspecified sign. Furthermore, if 2940 each input NaN consists of a mantissa whose most significant bit is 1 and the rest is 2941 0, then the output has the same form. Otherwise, the output mantissa's most significant 2942 bit is 1 and the rest is unspecified. 2943 "#, 2944 &formats.binary, 2945 ) 2946 .operands_in(vec![Operand::new("x", Float), Operand::new("y", Float)]) 2947 .operands_out(vec![ 2948 Operand::new("a", Float).with_doc("The larger of ``x`` and ``y``") 2949 ]), 2950 ); 2951 2952 ig.push( 2953 Inst::new( 2954 "ceil", 2955 r#" 2956 Round floating point round to integral, towards positive infinity. 2957 "#, 2958 &formats.unary, 2959 ) 2960 .operands_in(vec![Operand::new("x", Float)]) 2961 .operands_out(vec![ 2962 Operand::new("a", Float).with_doc("``x`` rounded to integral value") 2963 ]), 2964 ); 2965 2966 ig.push( 2967 Inst::new( 2968 "floor", 2969 r#" 2970 Round floating point round to integral, towards negative infinity. 2971 "#, 2972 &formats.unary, 2973 ) 2974 .operands_in(vec![Operand::new("x", Float)]) 2975 .operands_out(vec![ 2976 Operand::new("a", Float).with_doc("``x`` rounded to integral value") 2977 ]), 2978 ); 2979 2980 ig.push( 2981 Inst::new( 2982 "trunc", 2983 r#" 2984 Round floating point round to integral, towards zero. 2985 "#, 2986 &formats.unary, 2987 ) 2988 .operands_in(vec![Operand::new("x", Float)]) 2989 .operands_out(vec![ 2990 Operand::new("a", Float).with_doc("``x`` rounded to integral value") 2991 ]), 2992 ); 2993 2994 ig.push( 2995 Inst::new( 2996 "nearest", 2997 r#" 2998 Round floating point round to integral, towards nearest with ties to 2999 even. 3000 "#, 3001 &formats.unary, 3002 ) 3003 .operands_in(vec![Operand::new("x", Float)]) 3004 .operands_out(vec![ 3005 Operand::new("a", Float).with_doc("``x`` rounded to integral value") 3006 ]), 3007 ); 3008 3009 ig.push( 3010 Inst::new( 3011 "is_null", 3012 r#" 3013 Reference verification. 3014 3015 The condition code determines if the reference type in question is 3016 null or not. 3017 "#, 3018 &formats.unary, 3019 ) 3020 .operands_in(vec![Operand::new("x", Ref)]) 3021 .operands_out(vec![Operand::new("a", i8)]), 3022 ); 3023 3024 ig.push( 3025 Inst::new( 3026 "is_invalid", 3027 r#" 3028 Reference verification. 3029 3030 The condition code determines if the reference type in question is 3031 invalid or not. 3032 "#, 3033 &formats.unary, 3034 ) 3035 .operands_in(vec![Operand::new("x", Ref)]) 3036 .operands_out(vec![Operand::new("a", i8)]), 3037 ); 3038 3039 ig.push( 3040 Inst::new( 3041 "bitcast", 3042 r#" 3043 Reinterpret the bits in `x` as a different type. 3044 3045 The input and output types must be storable to memory and of the same 3046 size. A bitcast is equivalent to storing one type and loading the other 3047 type from the same address, both using the specified MemFlags. 3048 3049 Note that this operation only supports the `big` or `little` MemFlags. 3050 The specified byte order only affects the result in the case where 3051 input and output types differ in lane count/size. In this case, the 3052 operation is only valid if a byte order specifier is provided. 3053 "#, 3054 &formats.load_no_offset, 3055 ) 3056 .operands_in(vec![ 3057 Operand::new("MemFlags", &imm.memflags), 3058 Operand::new("x", Mem), 3059 ]) 3060 .operands_out(vec![ 3061 Operand::new("a", MemTo).with_doc("Bits of `x` reinterpreted") 3062 ]), 3063 ); 3064 3065 ig.push( 3066 Inst::new( 3067 "scalar_to_vector", 3068 r#" 3069 Copies a scalar value to a vector value. The scalar is copied into the 3070 least significant lane of the vector, and all other lanes will be zero. 3071 "#, 3072 &formats.unary, 3073 ) 3074 .operands_in(vec![ 3075 Operand::new("s", &TxN.lane_of()).with_doc("A scalar value") 3076 ]) 3077 .operands_out(vec![Operand::new("a", TxN).with_doc("A vector value")]), 3078 ); 3079 3080 let Truthy = &TypeVar::new( 3081 "Truthy", 3082 "A scalar whose values are truthy", 3083 TypeSetBuilder::new().ints(Interval::All).build(), 3084 ); 3085 let IntTo = &TypeVar::new( 3086 "IntTo", 3087 "An integer type", 3088 TypeSetBuilder::new().ints(Interval::All).build(), 3089 ); 3090 3091 ig.push( 3092 Inst::new( 3093 "bmask", 3094 r#" 3095 Convert `x` to an integer mask. 3096 3097 Non-zero maps to all 1s and zero maps to all 0s. 3098 "#, 3099 &formats.unary, 3100 ) 3101 .operands_in(vec![Operand::new("x", Truthy)]) 3102 .operands_out(vec![Operand::new("a", IntTo)]), 3103 ); 3104 3105 let Int = &TypeVar::new( 3106 "Int", 3107 "A scalar integer type", 3108 TypeSetBuilder::new().ints(Interval::All).build(), 3109 ); 3110 3111 ig.push( 3112 Inst::new( 3113 "ireduce", 3114 r#" 3115 Convert `x` to a smaller integer type by discarding 3116 the most significant bits. 3117 3118 This is the same as reducing modulo `2^n`. 3119 "#, 3120 &formats.unary, 3121 ) 3122 .operands_in(vec![Operand::new("x", &Int.wider()) 3123 .with_doc("A scalar integer type, wider than the controlling type")]) 3124 .operands_out(vec![Operand::new("a", Int)]), 3125 ); 3126 3127 let I16or32or64xN = &TypeVar::new( 3128 "I16or32or64xN", 3129 "A SIMD vector type containing integer lanes 16, 32, or 64 bits wide", 3130 TypeSetBuilder::new() 3131 .ints(16..64) 3132 .simd_lanes(2..8) 3133 .dynamic_simd_lanes(2..8) 3134 .includes_scalars(false) 3135 .build(), 3136 ); 3137 3138 ig.push( 3139 Inst::new( 3140 "snarrow", 3141 r#" 3142 Combine `x` and `y` into a vector with twice the lanes but half the integer width while 3143 saturating overflowing values to the signed maximum and minimum. 3144 3145 The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4` 3146 and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value 3147 returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`. 3148 "#, 3149 &formats.binary, 3150 ) 3151 .operands_in(vec![ 3152 Operand::new("x", I16or32or64xN), 3153 Operand::new("y", I16or32or64xN), 3154 ]) 3155 .operands_out(vec![Operand::new("a", &I16or32or64xN.split_lanes())]), 3156 ); 3157 3158 ig.push( 3159 Inst::new( 3160 "unarrow", 3161 r#" 3162 Combine `x` and `y` into a vector with twice the lanes but half the integer width while 3163 saturating overflowing values to the unsigned maximum and minimum. 3164 3165 Note that all input lanes are considered signed: any negative lanes will overflow and be 3166 replaced with the unsigned minimum, `0x00`. 3167 3168 The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4` 3169 and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value 3170 returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`. 3171 "#, 3172 &formats.binary, 3173 ) 3174 .operands_in(vec![ 3175 Operand::new("x", I16or32or64xN), 3176 Operand::new("y", I16or32or64xN), 3177 ]) 3178 .operands_out(vec![Operand::new("a", &I16or32or64xN.split_lanes())]), 3179 ); 3180 3181 ig.push( 3182 Inst::new( 3183 "uunarrow", 3184 r#" 3185 Combine `x` and `y` into a vector with twice the lanes but half the integer width while 3186 saturating overflowing values to the unsigned maximum and minimum. 3187 3188 Note that all input lanes are considered unsigned: any negative values will be interpreted as unsigned, overflowing and being replaced with the unsigned maximum. 3189 3190 The lanes will be concatenated after narrowing. For example, when `x` and `y` are `i32x4` 3191 and `x = [x3, x2, x1, x0]` and `y = [y3, y2, y1, y0]`, then after narrowing the value 3192 returned is an `i16x8`: `a = [y3', y2', y1', y0', x3', x2', x1', x0']`. 3193 "#, 3194 &formats.binary, 3195 ) 3196 .operands_in(vec![Operand::new("x", I16or32or64xN), Operand::new("y", I16or32or64xN)]) 3197 .operands_out(vec![Operand::new("a", &I16or32or64xN.split_lanes())]), 3198 ); 3199 3200 let I8or16or32xN = &TypeVar::new( 3201 "I8or16or32xN", 3202 "A SIMD vector type containing integer lanes 8, 16, or 32 bits wide.", 3203 TypeSetBuilder::new() 3204 .ints(8..32) 3205 .simd_lanes(2..16) 3206 .dynamic_simd_lanes(2..16) 3207 .includes_scalars(false) 3208 .build(), 3209 ); 3210 3211 ig.push( 3212 Inst::new( 3213 "swiden_low", 3214 r#" 3215 Widen the low lanes of `x` using signed extension. 3216 3217 This will double the lane width and halve the number of lanes. 3218 "#, 3219 &formats.unary, 3220 ) 3221 .operands_in(vec![Operand::new("x", I8or16or32xN)]) 3222 .operands_out(vec![Operand::new("a", &I8or16or32xN.merge_lanes())]), 3223 ); 3224 3225 ig.push( 3226 Inst::new( 3227 "swiden_high", 3228 r#" 3229 Widen the high lanes of `x` using signed extension. 3230 3231 This will double the lane width and halve the number of lanes. 3232 "#, 3233 &formats.unary, 3234 ) 3235 .operands_in(vec![Operand::new("x", I8or16or32xN)]) 3236 .operands_out(vec![Operand::new("a", &I8or16or32xN.merge_lanes())]), 3237 ); 3238 3239 ig.push( 3240 Inst::new( 3241 "uwiden_low", 3242 r#" 3243 Widen the low lanes of `x` using unsigned extension. 3244 3245 This will double the lane width and halve the number of lanes. 3246 "#, 3247 &formats.unary, 3248 ) 3249 .operands_in(vec![Operand::new("x", I8or16or32xN)]) 3250 .operands_out(vec![Operand::new("a", &I8or16or32xN.merge_lanes())]), 3251 ); 3252 3253 ig.push( 3254 Inst::new( 3255 "uwiden_high", 3256 r#" 3257 Widen the high lanes of `x` using unsigned extension. 3258 3259 This will double the lane width and halve the number of lanes. 3260 "#, 3261 &formats.unary, 3262 ) 3263 .operands_in(vec![Operand::new("x", I8or16or32xN)]) 3264 .operands_out(vec![Operand::new("a", &I8or16or32xN.merge_lanes())]), 3265 ); 3266 3267 ig.push( 3268 Inst::new( 3269 "iadd_pairwise", 3270 r#" 3271 Does lane-wise integer pairwise addition on two operands, putting the 3272 combined results into a single vector result. Here a pair refers to adjacent 3273 lanes in a vector, i.e. i*2 + (i*2+1) for i == num_lanes/2. The first operand 3274 pairwise add results will make up the low half of the resulting vector while 3275 the second operand pairwise add results will make up the upper half of the 3276 resulting vector. 3277 "#, 3278 &formats.binary, 3279 ) 3280 .operands_in(vec![ 3281 Operand::new("x", I8or16or32xN), 3282 Operand::new("y", I8or16or32xN), 3283 ]) 3284 .operands_out(vec![Operand::new("a", I8or16or32xN)]), 3285 ); 3286 3287 let I8x16 = &TypeVar::new( 3288 "I8x16", 3289 "A SIMD vector type consisting of 16 lanes of 8-bit integers", 3290 TypeSetBuilder::new() 3291 .ints(8..8) 3292 .simd_lanes(16..16) 3293 .includes_scalars(false) 3294 .build(), 3295 ); 3296 3297 ig.push( 3298 Inst::new( 3299 "x86_pmaddubsw", 3300 r#" 3301 An instruction with equivalent semantics to `pmaddubsw` on x86. 3302 3303 This instruction will take signed bytes from the first argument and 3304 multiply them against unsigned bytes in the second argument. Adjacent 3305 pairs are then added, with saturating, to a 16-bit value and are packed 3306 into the result. 3307 "#, 3308 &formats.binary, 3309 ) 3310 .operands_in(vec![Operand::new("x", I8x16), Operand::new("y", I8x16)]) 3311 .operands_out(vec![Operand::new("a", I16x8)]), 3312 ); 3313 3314 ig.push( 3315 Inst::new( 3316 "uextend", 3317 r#" 3318 Convert `x` to a larger integer type by zero-extending. 3319 3320 Each lane in `x` is converted to a larger integer type by adding 3321 zeroes. The result has the same numerical value as `x` when both are 3322 interpreted as unsigned integers. 3323 3324 The result type must have the same number of vector lanes as the input, 3325 and each lane must not have fewer bits that the input lanes. If the 3326 input and output types are the same, this is a no-op. 3327 "#, 3328 &formats.unary, 3329 ) 3330 .operands_in(vec![Operand::new("x", &Int.narrower()).with_doc( 3331 "A scalar integer type, narrower than the controlling type", 3332 )]) 3333 .operands_out(vec![Operand::new("a", Int)]), 3334 ); 3335 3336 ig.push( 3337 Inst::new( 3338 "sextend", 3339 r#" 3340 Convert `x` to a larger integer type by sign-extending. 3341 3342 Each lane in `x` is converted to a larger integer type by replicating 3343 the sign bit. The result has the same numerical value as `x` when both 3344 are interpreted as signed integers. 3345 3346 The result type must have the same number of vector lanes as the input, 3347 and each lane must not have fewer bits that the input lanes. If the 3348 input and output types are the same, this is a no-op. 3349 "#, 3350 &formats.unary, 3351 ) 3352 .operands_in(vec![Operand::new("x", &Int.narrower()).with_doc( 3353 "A scalar integer type, narrower than the controlling type", 3354 )]) 3355 .operands_out(vec![Operand::new("a", Int)]), 3356 ); 3357 3358 let FloatScalar = &TypeVar::new( 3359 "FloatScalar", 3360 "A scalar only floating point number", 3361 TypeSetBuilder::new().floats(Interval::All).build(), 3362 ); 3363 3364 ig.push( 3365 Inst::new( 3366 "fpromote", 3367 r#" 3368 Convert `x` to a larger floating point format. 3369 3370 Each lane in `x` is converted to the destination floating point format. 3371 This is an exact operation. 3372 3373 Cranelift currently only supports two floating point formats 3374 - `f32` and `f64`. This may change in the future. 3375 3376 The result type must have the same number of vector lanes as the input, 3377 and the result lanes must not have fewer bits than the input lanes. 3378 "#, 3379 &formats.unary, 3380 ) 3381 .operands_in(vec![Operand::new("x", &FloatScalar.narrower()).with_doc( 3382 "A scalar only floating point number, narrower than the controlling type", 3383 )]) 3384 .operands_out(vec![Operand::new("a", FloatScalar)]), 3385 ); 3386 3387 ig.push( 3388 Inst::new( 3389 "fdemote", 3390 r#" 3391 Convert `x` to a smaller floating point format. 3392 3393 Each lane in `x` is converted to the destination floating point format 3394 by rounding to nearest, ties to even. 3395 3396 Cranelift currently only supports two floating point formats 3397 - `f32` and `f64`. This may change in the future. 3398 3399 The result type must have the same number of vector lanes as the input, 3400 and the result lanes must not have more bits than the input lanes. 3401 "#, 3402 &formats.unary, 3403 ) 3404 .operands_in(vec![Operand::new("x", &FloatScalar.wider()).with_doc( 3405 "A scalar only floating point number, wider than the controlling type", 3406 )]) 3407 .operands_out(vec![Operand::new("a", FloatScalar)]), 3408 ); 3409 3410 let F64x2 = &TypeVar::new( 3411 "F64x2", 3412 "A SIMD vector type consisting of 2 lanes of 64-bit floats", 3413 TypeSetBuilder::new() 3414 .floats(64..64) 3415 .simd_lanes(2..2) 3416 .includes_scalars(false) 3417 .build(), 3418 ); 3419 let F32x4 = &TypeVar::new( 3420 "F32x4", 3421 "A SIMD vector type consisting of 4 lanes of 32-bit floats", 3422 TypeSetBuilder::new() 3423 .floats(32..32) 3424 .simd_lanes(4..4) 3425 .includes_scalars(false) 3426 .build(), 3427 ); 3428 3429 ig.push( 3430 Inst::new( 3431 "fvdemote", 3432 r#" 3433 Convert `x` to a smaller floating point format. 3434 3435 Each lane in `x` is converted to the destination floating point format 3436 by rounding to nearest, ties to even. 3437 3438 Cranelift currently only supports two floating point formats 3439 - `f32` and `f64`. This may change in the future. 3440 3441 Fvdemote differs from fdemote in that with fvdemote it targets vectors. 3442 Fvdemote is constrained to having the input type being F64x2 and the result 3443 type being F32x4. The result lane that was the upper half of the input lane 3444 is initialized to zero. 3445 "#, 3446 &formats.unary, 3447 ) 3448 .operands_in(vec![Operand::new("x", F64x2)]) 3449 .operands_out(vec![Operand::new("a", F32x4)]), 3450 ); 3451 3452 ig.push( 3453 Inst::new( 3454 "fvpromote_low", 3455 r#" 3456 Converts packed single precision floating point to packed double precision floating point. 3457 3458 Considering only the lower half of the register, the low lanes in `x` are interpreted as 3459 single precision floats that are then converted to a double precision floats. 3460 3461 The result type will have half the number of vector lanes as the input. Fvpromote_low is 3462 constrained to input F32x4 with a result type of F64x2. 3463 "#, 3464 &formats.unary, 3465 ) 3466 .operands_in(vec![Operand::new("a", F32x4)]) 3467 .operands_out(vec![Operand::new("x", F64x2)]), 3468 ); 3469 3470 let IntTo = &TypeVar::new( 3471 "IntTo", 3472 "An scalar only integer type", 3473 TypeSetBuilder::new().ints(Interval::All).build(), 3474 ); 3475 3476 ig.push( 3477 Inst::new( 3478 "fcvt_to_uint", 3479 r#" 3480 Converts floating point scalars to unsigned 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 ig.push( 3496 Inst::new( 3497 "fcvt_to_sint", 3498 r#" 3499 Converts floating point scalars to signed integer. 3500 3501 Only operates on `x` if it is a scalar. If `x` is NaN or if 3502 the unsigned integral value cannot be represented in the result 3503 type, this instruction traps. 3504 3505 "#, 3506 &formats.unary, 3507 ) 3508 .operands_in(vec![Operand::new("x", FloatScalar)]) 3509 .operands_out(vec![Operand::new("a", IntTo)]) 3510 .can_trap() 3511 .side_effects_idempotent(), 3512 ); 3513 3514 let IntTo = &TypeVar::new( 3515 "IntTo", 3516 "A larger integer type with the same number of lanes", 3517 TypeSetBuilder::new() 3518 .ints(Interval::All) 3519 .simd_lanes(Interval::All) 3520 .build(), 3521 ); 3522 3523 ig.push( 3524 Inst::new( 3525 "fcvt_to_uint_sat", 3526 r#" 3527 Convert floating point to unsigned integer as fcvt_to_uint does, but 3528 saturates the input instead of trapping. NaN and negative values are 3529 converted to 0. 3530 "#, 3531 &formats.unary, 3532 ) 3533 .operands_in(vec![Operand::new("x", Float)]) 3534 .operands_out(vec![Operand::new("a", IntTo)]), 3535 ); 3536 3537 ig.push( 3538 Inst::new( 3539 "fcvt_to_sint_sat", 3540 r#" 3541 Convert floating point to signed integer as fcvt_to_sint does, but 3542 saturates the input instead of trapping. NaN values are converted to 0. 3543 "#, 3544 &formats.unary, 3545 ) 3546 .operands_in(vec![Operand::new("x", Float)]) 3547 .operands_out(vec![Operand::new("a", IntTo)]), 3548 ); 3549 3550 ig.push( 3551 Inst::new( 3552 "x86_cvtt2dq", 3553 r#" 3554 A float-to-integer conversion instruction for vectors-of-floats which 3555 has the same semantics as `cvttp{s,d}2dq` on x86. This specifically 3556 returns `INT_MIN` for NaN or out-of-bounds lanes. 3557 "#, 3558 &formats.unary, 3559 ) 3560 .operands_in(vec![Operand::new("x", Float)]) 3561 .operands_out(vec![Operand::new("a", IntTo)]), 3562 ); 3563 3564 let Int = &TypeVar::new( 3565 "Int", 3566 "A scalar or vector integer type", 3567 TypeSetBuilder::new() 3568 .ints(Interval::All) 3569 .simd_lanes(Interval::All) 3570 .build(), 3571 ); 3572 3573 let FloatTo = &TypeVar::new( 3574 "FloatTo", 3575 "A scalar or vector floating point number", 3576 TypeSetBuilder::new() 3577 .floats(Interval::All) 3578 .simd_lanes(Interval::All) 3579 .build(), 3580 ); 3581 3582 ig.push( 3583 Inst::new( 3584 "fcvt_from_uint", 3585 r#" 3586 Convert unsigned integer to floating point. 3587 3588 Each lane in `x` is interpreted as an unsigned integer and converted to 3589 floating point using round to nearest, ties to even. 3590 3591 The result type must have the same number of vector lanes as the input. 3592 "#, 3593 &formats.unary, 3594 ) 3595 .operands_in(vec![Operand::new("x", Int)]) 3596 .operands_out(vec![Operand::new("a", FloatTo)]), 3597 ); 3598 3599 ig.push( 3600 Inst::new( 3601 "fcvt_from_sint", 3602 r#" 3603 Convert signed integer to floating point. 3604 3605 Each lane in `x` is interpreted as a signed integer and converted to 3606 floating point using round to nearest, ties to even. 3607 3608 The result type must have the same number of vector lanes as the input. 3609 "#, 3610 &formats.unary, 3611 ) 3612 .operands_in(vec![Operand::new("x", Int)]) 3613 .operands_out(vec![Operand::new("a", FloatTo)]), 3614 ); 3615 3616 let WideInt = &TypeVar::new( 3617 "WideInt", 3618 "An integer type of width `i16` upwards", 3619 TypeSetBuilder::new().ints(16..128).build(), 3620 ); 3621 3622 ig.push( 3623 Inst::new( 3624 "isplit", 3625 r#" 3626 Split an integer into low and high parts. 3627 3628 Vectors of integers are split lane-wise, so the results have the same 3629 number of lanes as the input, but the lanes are half the size. 3630 3631 Returns the low half of `x` and the high half of `x` as two independent 3632 values. 3633 "#, 3634 &formats.unary, 3635 ) 3636 .operands_in(vec![Operand::new("x", WideInt)]) 3637 .operands_out(vec![ 3638 Operand::new("lo", &WideInt.half_width()).with_doc("The low bits of `x`"), 3639 Operand::new("hi", &WideInt.half_width()).with_doc("The high bits of `x`"), 3640 ]), 3641 ); 3642 3643 ig.push( 3644 Inst::new( 3645 "iconcat", 3646 r#" 3647 Concatenate low and high bits to form a larger integer type. 3648 3649 Vectors of integers are concatenated lane-wise such that the result has 3650 the same number of lanes as the inputs, but the lanes are twice the 3651 size. 3652 "#, 3653 &formats.binary, 3654 ) 3655 .operands_in(vec![ 3656 Operand::new("lo", NarrowInt), 3657 Operand::new("hi", NarrowInt), 3658 ]) 3659 .operands_out(vec![Operand::new("a", &NarrowInt.double_width()) 3660 .with_doc("The concatenation of `lo` and `hi`")]), 3661 ); 3662 3663 // Instructions relating to atomic memory accesses and fences 3664 let AtomicMem = &TypeVar::new( 3665 "AtomicMem", 3666 "Any type that can be stored in memory, which can be used in an atomic operation", 3667 TypeSetBuilder::new().ints(8..64).build(), 3668 ); 3669 3670 ig.push( 3671 Inst::new( 3672 "atomic_rmw", 3673 r#" 3674 Atomically read-modify-write memory at `p`, with second operand `x`. The old value is 3675 returned. `p` has the type of the target word size, and `x` may be an integer type of 3676 8, 16, 32 or 64 bits, even on a 32-bit target. The type of the returned value is the 3677 same as the type of `x`. This operation is sequentially consistent and creates 3678 happens-before edges that order normal (non-atomic) loads and stores. 3679 "#, 3680 &formats.atomic_rmw, 3681 ) 3682 .operands_in(vec![ 3683 Operand::new("MemFlags", &imm.memflags), 3684 Operand::new("AtomicRmwOp", &imm.atomic_rmw_op), 3685 Operand::new("p", iAddr), 3686 Operand::new("x", AtomicMem).with_doc("Value to be atomically stored"), 3687 ]) 3688 .operands_out(vec![ 3689 Operand::new("a", AtomicMem).with_doc("Value atomically loaded") 3690 ]) 3691 .can_load() 3692 .can_store() 3693 .other_side_effects(), 3694 ); 3695 3696 ig.push( 3697 Inst::new( 3698 "atomic_cas", 3699 r#" 3700 Perform an atomic compare-and-swap operation on memory at `p`, with expected value `e`, 3701 storing `x` if the value at `p` equals `e`. The old value at `p` is returned, 3702 regardless of whether the operation succeeds or fails. `p` has the type of the target 3703 word size, and `x` and `e` must have the same type and the same size, which may be an 3704 integer type of 8, 16, 32 or 64 bits, even on a 32-bit target. The type of the returned 3705 value is the same as the type of `x` and `e`. This operation is sequentially 3706 consistent and creates happens-before edges that order normal (non-atomic) loads and 3707 stores. 3708 "#, 3709 &formats.atomic_cas, 3710 ) 3711 .operands_in(vec![ 3712 Operand::new("MemFlags", &imm.memflags), 3713 Operand::new("p", iAddr), 3714 Operand::new("e", AtomicMem).with_doc("Expected value in CAS"), 3715 Operand::new("x", AtomicMem).with_doc("Value to be atomically stored"), 3716 ]) 3717 .operands_out(vec![ 3718 Operand::new("a", AtomicMem).with_doc("Value atomically loaded") 3719 ]) 3720 .can_load() 3721 .can_store() 3722 .other_side_effects(), 3723 ); 3724 3725 ig.push( 3726 Inst::new( 3727 "atomic_load", 3728 r#" 3729 Atomically load from memory at `p`. 3730 3731 This is a polymorphic instruction that can load any value type which has a memory 3732 representation. It should only be used for integer types with 8, 16, 32 or 64 bits. 3733 This operation is sequentially consistent and creates happens-before edges that order 3734 normal (non-atomic) loads and stores. 3735 "#, 3736 &formats.load_no_offset, 3737 ) 3738 .operands_in(vec![ 3739 Operand::new("MemFlags", &imm.memflags), 3740 Operand::new("p", iAddr), 3741 ]) 3742 .operands_out(vec![ 3743 Operand::new("a", AtomicMem).with_doc("Value atomically loaded") 3744 ]) 3745 .can_load() 3746 .other_side_effects(), 3747 ); 3748 3749 ig.push( 3750 Inst::new( 3751 "atomic_store", 3752 r#" 3753 Atomically store `x` to memory at `p`. 3754 3755 This is a polymorphic instruction that can store any value type with a memory 3756 representation. It should only be used for integer types with 8, 16, 32 or 64 bits. 3757 This operation is sequentially consistent and creates happens-before edges that order 3758 normal (non-atomic) loads and stores. 3759 "#, 3760 &formats.store_no_offset, 3761 ) 3762 .operands_in(vec![ 3763 Operand::new("MemFlags", &imm.memflags), 3764 Operand::new("x", AtomicMem).with_doc("Value to be atomically stored"), 3765 Operand::new("p", iAddr), 3766 ]) 3767 .can_store() 3768 .other_side_effects(), 3769 ); 3770 3771 ig.push( 3772 Inst::new( 3773 "fence", 3774 r#" 3775 A memory fence. This must provide ordering to ensure that, at a minimum, neither loads 3776 nor stores of any kind may move forwards or backwards across the fence. This operation 3777 is sequentially consistent. 3778 "#, 3779 &formats.nullary, 3780 ) 3781 .other_side_effects(), 3782 ); 3783 3784 let TxN = &TypeVar::new( 3785 "TxN", 3786 "A dynamic vector type", 3787 TypeSetBuilder::new() 3788 .ints(Interval::All) 3789 .floats(Interval::All) 3790 .dynamic_simd_lanes(Interval::All) 3791 .build(), 3792 ); 3793 3794 ig.push( 3795 Inst::new( 3796 "extract_vector", 3797 r#" 3798 Return a fixed length sub vector, extracted from a dynamic vector. 3799 "#, 3800 &formats.binary_imm8, 3801 ) 3802 .operands_in(vec![ 3803 Operand::new("x", TxN).with_doc("The dynamic vector to extract from"), 3804 Operand::new("y", &imm.uimm8).with_doc("128-bit vector index"), 3805 ]) 3806 .operands_out(vec![ 3807 Operand::new("a", &TxN.dynamic_to_vector()).with_doc("New fixed vector") 3808 ]), 3809 ); 3810 } 3811