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