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