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