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