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