1;; Instruction formats. 2(type MInst 3 (enum 4 ;; A no-op of zero size. 5 (Nop0) 6 7 ;; A no-op that is one instruction large. 8 (Nop4) 9 10 ;; An ALU operation with two register sources and a register destination. 11 (AluRRR 12 (alu_op ALUOp) 13 (size OperandSize) 14 (rd WritableReg) 15 (rn Reg) 16 (rm Reg)) 17 18 ;; An ALU operation with three register sources and a register destination. 19 (AluRRRR 20 (alu_op ALUOp3) 21 (size OperandSize) 22 (rd WritableReg) 23 (rn Reg) 24 (rm Reg) 25 (ra Reg)) 26 27 ;; An ALU operation with a register source and an immediate-12 source, and a register 28 ;; destination. 29 (AluRRImm12 30 (alu_op ALUOp) 31 (size OperandSize) 32 (rd WritableReg) 33 (rn Reg) 34 (imm12 Imm12)) 35 36 ;; An ALU operation with a register source and an immediate-logic source, and a register destination. 37 (AluRRImmLogic 38 (alu_op ALUOp) 39 (size OperandSize) 40 (rd WritableReg) 41 (rn Reg) 42 (imml ImmLogic)) 43 44 ;; An ALU operation with a register source and an immediate-shiftamt source, and a register destination. 45 (AluRRImmShift 46 (alu_op ALUOp) 47 (size OperandSize) 48 (rd WritableReg) 49 (rn Reg) 50 (immshift ImmShift)) 51 52 ;; An ALU operation with two register sources, one of which can be shifted, and a register 53 ;; destination. 54 (AluRRRShift 55 (alu_op ALUOp) 56 (size OperandSize) 57 (rd WritableReg) 58 (rn Reg) 59 (rm Reg) 60 (shiftop ShiftOpAndAmt)) 61 62 ;; An ALU operation with two register sources, one of which can be {zero,sign}-extended and 63 ;; shifted, and a register destination. 64 (AluRRRExtend 65 (alu_op ALUOp) 66 (size OperandSize) 67 (rd WritableReg) 68 (rn Reg) 69 (rm Reg) 70 (extendop ExtendOp)) 71 72 ;; A bit op instruction with a single register source. 73 (BitRR 74 (op BitOp) 75 (size OperandSize) 76 (rd WritableReg) 77 (rn Reg)) 78 79 ;; An unsigned (zero-extending) 8-bit load. 80 (ULoad8 81 (rd WritableReg) 82 (mem AMode) 83 (flags MemFlags)) 84 85 ;; A signed (sign-extending) 8-bit load. 86 (SLoad8 87 (rd WritableReg) 88 (mem AMode) 89 (flags MemFlags)) 90 91 ;; An unsigned (zero-extending) 16-bit load. 92 (ULoad16 93 (rd WritableReg) 94 (mem AMode) 95 (flags MemFlags)) 96 97 ;; A signed (sign-extending) 16-bit load. 98 (SLoad16 99 (rd WritableReg) 100 (mem AMode) 101 (flags MemFlags)) 102 103 ;; An unsigned (zero-extending) 32-bit load. 104 (ULoad32 105 (rd WritableReg) 106 (mem AMode) 107 (flags MemFlags)) 108 109 ;; A signed (sign-extending) 32-bit load. 110 (SLoad32 111 (rd WritableReg) 112 (mem AMode) 113 (flags MemFlags)) 114 115 ;; A 64-bit load. 116 (ULoad64 117 (rd WritableReg) 118 (mem AMode) 119 (flags MemFlags)) 120 121 ;; An 8-bit store. 122 (Store8 123 (rd Reg) 124 (mem AMode) 125 (flags MemFlags)) 126 127 ;; A 16-bit store. 128 (Store16 129 (rd Reg) 130 (mem AMode) 131 (flags MemFlags)) 132 133 ;; A 32-bit store. 134 (Store32 135 (rd Reg) 136 (mem AMode) 137 (flags MemFlags)) 138 139 ;; A 64-bit store. 140 (Store64 141 (rd Reg) 142 (mem AMode) 143 (flags MemFlags)) 144 145 ;; A store of a pair of registers. 146 (StoreP64 147 (rt Reg) 148 (rt2 Reg) 149 (mem PairAMode) 150 (flags MemFlags)) 151 152 ;; A load of a pair of registers. 153 (LoadP64 154 (rt WritableReg) 155 (rt2 WritableReg) 156 (mem PairAMode) 157 (flags MemFlags)) 158 159 ;; A MOV instruction. These are encoded as ORR's (AluRRR form). 160 ;; The 32-bit version zeroes the top 32 bits of the 161 ;; destination, which is effectively an alias for an unsigned 162 ;; 32-to-64-bit extension. 163 (Mov 164 (size OperandSize) 165 (rd WritableReg) 166 (rm Reg)) 167 168 ;; Like `Move` but with a particular `PReg` source (for implementing CLIF 169 ;; instructions like `get_stack_pointer`). 170 (MovFromPReg 171 (rd WritableReg) 172 (rm PReg)) 173 174 ;; Like `Move` but with a particular `PReg` destination (for 175 ;; implementing CLIF instructions like `set_pinned_reg`). 176 (MovToPReg 177 (rd PReg) 178 (rm Reg)) 179 180 ;; A MOV[Z,N] with a 16-bit immediate. 181 (MovWide 182 (op MoveWideOp) 183 (rd WritableReg) 184 (imm MoveWideConst) 185 (size OperandSize)) 186 187 ;; A MOVK with a 16-bit immediate. Modifies its register; we 188 ;; model this with a separate input `rn` and output `rd` virtual 189 ;; register, with a regalloc constraint to tie them together. 190 (MovK 191 (rd WritableReg) 192 (rn Reg) 193 (imm MoveWideConst) 194 (size OperandSize)) 195 196 197 ;; A sign- or zero-extend operation. 198 (Extend 199 (rd WritableReg) 200 (rn Reg) 201 (signed bool) 202 (from_bits u8) 203 (to_bits u8)) 204 205 ;; A conditional-select operation. 206 (CSel 207 (rd WritableReg) 208 (cond Cond) 209 (rn Reg) 210 (rm Reg)) 211 212 ;; A conditional-select negation operation. 213 (CSNeg 214 (rd WritableReg) 215 (cond Cond) 216 (rn Reg) 217 (rm Reg)) 218 219 ;; A conditional-set operation. 220 (CSet 221 (rd WritableReg) 222 (cond Cond)) 223 224 ;; A conditional-set-mask operation. 225 (CSetm 226 (rd WritableReg) 227 (cond Cond)) 228 229 ;; A conditional comparison with a second register. 230 (CCmp 231 (size OperandSize) 232 (rn Reg) 233 (rm Reg) 234 (nzcv NZCV) 235 (cond Cond)) 236 237 ;; A conditional comparison with an immediate. 238 (CCmpImm 239 (size OperandSize) 240 (rn Reg) 241 (imm UImm5) 242 (nzcv NZCV) 243 (cond Cond)) 244 245 ;; A synthetic insn, which is a load-linked store-conditional loop, that has the overall 246 ;; effect of atomically modifying a memory location in a particular way. Because we have 247 ;; no way to explain to the regalloc about earlyclobber registers, this instruction has 248 ;; completely fixed operand registers, and we rely on the RA's coalescing to remove copies 249 ;; in the surrounding code to the extent it can. Load- and store-exclusive instructions, 250 ;; with acquire-release semantics, are used to access memory. The operand conventions are: 251 ;; 252 ;; x25 (rd) address 253 ;; x26 (rd) second operand for `op` 254 ;; x27 (wr) old value 255 ;; x24 (wr) scratch reg; value afterwards has no meaning 256 ;; x28 (wr) scratch reg; value afterwards has no meaning 257 (AtomicRMWLoop 258 (ty Type) ;; I8, I16, I32 or I64 259 (op AtomicRMWLoopOp) 260 (flags MemFlags) 261 (addr Reg) 262 (operand Reg) 263 (oldval WritableReg) 264 (scratch1 WritableReg) 265 (scratch2 WritableReg)) 266 267 ;; Similar to AtomicRMWLoop, a compare-and-swap operation implemented using a load-linked 268 ;; store-conditional loop, with acquire-release semantics. 269 ;; Note that the operand conventions, although very similar to AtomicRMWLoop, are different: 270 ;; 271 ;; x25 (rd) address 272 ;; x26 (rd) expected value 273 ;; x28 (rd) replacement value 274 ;; x27 (wr) old value 275 ;; x24 (wr) scratch reg; value afterwards has no meaning 276 (AtomicCASLoop 277 (ty Type) ;; I8, I16, I32 or I64 278 (flags MemFlags) 279 (addr Reg) 280 (expected Reg) 281 (replacement Reg) 282 (oldval WritableReg) 283 (scratch WritableReg)) 284 285 ;; An atomic read-modify-write operation. These instructions require the 286 ;; Large System Extension (LSE) ISA support (FEAT_LSE). The instructions have 287 ;; acquire-release semantics. 288 (AtomicRMW 289 (op AtomicRMWOp) 290 (rs Reg) 291 (rt WritableReg) 292 (rn Reg) 293 (ty Type) 294 (flags MemFlags)) 295 296 ;; An atomic compare-and-swap operation. These instructions require the 297 ;; Large System Extension (LSE) ISA support (FEAT_LSE). The instructions have 298 ;; acquire-release semantics. 299 (AtomicCAS 300 ;; `rd` is really `rs` in the encoded instruction (so `rd` == `rs`); we separate 301 ;; them here to have separate use and def vregs for regalloc. 302 (rd WritableReg) 303 (rs Reg) 304 (rt Reg) 305 (rn Reg) 306 (ty Type) 307 (flags MemFlags)) 308 309 ;; Read `access_ty` bits from address `rt`, either 8, 16, 32 or 64-bits, and put 310 ;; it in `rn`, optionally zero-extending to fill a word or double word result. 311 ;; This instruction is sequentially consistent. 312 (LoadAcquire 313 (access_ty Type) ;; I8, I16, I32 or I64 314 (rt WritableReg) 315 (rn Reg) 316 (flags MemFlags)) 317 318 ;; Write the lowest `ty` bits of `rt` to address `rn`. 319 ;; This instruction is sequentially consistent. 320 (StoreRelease 321 (access_ty Type) ;; I8, I16, I32 or I64 322 (rt Reg) 323 (rn Reg) 324 (flags MemFlags)) 325 326 ;; A memory fence. This must provide ordering to ensure that, at a minimum, neither loads 327 ;; nor stores may move forwards or backwards across the fence. Currently emitted as "dmb 328 ;; ish". This instruction is sequentially consistent. 329 (Fence) 330 331 ;; Consumption of speculative data barrier. 332 (Csdb) 333 334 ;; FPU 32-bit move. 335 (FpuMove32 336 (rd WritableReg) 337 (rn Reg)) 338 339 ;; FPU move. Note that this is distinct from a vector-register 340 ;; move; moving just 64 bits seems to be significantly faster. 341 (FpuMove64 342 (rd WritableReg) 343 (rn Reg)) 344 345 ;; Vector register move. 346 (FpuMove128 347 (rd WritableReg) 348 (rn Reg)) 349 350 ;; Move to scalar from a vector element. 351 (FpuMoveFromVec 352 (rd WritableReg) 353 (rn Reg) 354 (idx u8) 355 (size VectorSize)) 356 357 ;; Zero-extend a SIMD & FP scalar to the full width of a vector register. 358 ;; 16-bit scalars require half-precision floating-point support (FEAT_FP16). 359 (FpuExtend 360 (rd WritableReg) 361 (rn Reg) 362 (size ScalarSize)) 363 364 ;; 1-op FPU instruction. 365 (FpuRR 366 (fpu_op FPUOp1) 367 (size ScalarSize) 368 (rd WritableReg) 369 (rn Reg)) 370 371 ;; 2-op FPU instruction. 372 (FpuRRR 373 (fpu_op FPUOp2) 374 (size ScalarSize) 375 (rd WritableReg) 376 (rn Reg) 377 (rm Reg)) 378 379 (FpuRRI 380 (fpu_op FPUOpRI) 381 (rd WritableReg) 382 (rn Reg)) 383 384 ;; Variant of FpuRRI that modifies its `rd`, and so we name the 385 ;; input state `ri` (for "input") and constrain the two 386 ;; together. 387 (FpuRRIMod 388 (fpu_op FPUOpRIMod) 389 (rd WritableReg) 390 (ri Reg) 391 (rn Reg)) 392 393 394 ;; 3-op FPU instruction. 395 ;; 16-bit scalars require half-precision floating-point support (FEAT_FP16). 396 (FpuRRRR 397 (fpu_op FPUOp3) 398 (size ScalarSize) 399 (rd WritableReg) 400 (rn Reg) 401 (rm Reg) 402 (ra Reg)) 403 404 ;; FPU comparison. 405 (FpuCmp 406 (size ScalarSize) 407 (rn Reg) 408 (rm Reg)) 409 410 ;; Floating-point load, half-precision (16 bit). 411 (FpuLoad16 412 (rd WritableReg) 413 (mem AMode) 414 (flags MemFlags)) 415 416 ;; Floating-point store, half-precision (16 bit). 417 (FpuStore16 418 (rd Reg) 419 (mem AMode) 420 (flags MemFlags)) 421 422 ;; Floating-point load, single-precision (32 bit). 423 (FpuLoad32 424 (rd WritableReg) 425 (mem AMode) 426 (flags MemFlags)) 427 428 ;; Floating-point store, single-precision (32 bit). 429 (FpuStore32 430 (rd Reg) 431 (mem AMode) 432 (flags MemFlags)) 433 434 ;; Floating-point load, double-precision (64 bit). 435 (FpuLoad64 436 (rd WritableReg) 437 (mem AMode) 438 (flags MemFlags)) 439 440 ;; Floating-point store, double-precision (64 bit). 441 (FpuStore64 442 (rd Reg) 443 (mem AMode) 444 (flags MemFlags)) 445 446 ;; Floating-point/vector load, 128 bit. 447 (FpuLoad128 448 (rd WritableReg) 449 (mem AMode) 450 (flags MemFlags)) 451 452 ;; Floating-point/vector store, 128 bit. 453 (FpuStore128 454 (rd Reg) 455 (mem AMode) 456 (flags MemFlags)) 457 458 ;; A load of a pair of floating-point registers, double precision (64-bit). 459 (FpuLoadP64 460 (rt WritableReg) 461 (rt2 WritableReg) 462 (mem PairAMode) 463 (flags MemFlags)) 464 465 ;; A store of a pair of floating-point registers, double precision (64-bit). 466 (FpuStoreP64 467 (rt Reg) 468 (rt2 Reg) 469 (mem PairAMode) 470 (flags MemFlags)) 471 472 ;; A load of a pair of floating-point registers, 128-bit. 473 (FpuLoadP128 474 (rt WritableReg) 475 (rt2 WritableReg) 476 (mem PairAMode) 477 (flags MemFlags)) 478 479 ;; A store of a pair of floating-point registers, 128-bit. 480 (FpuStoreP128 481 (rt Reg) 482 (rt2 Reg) 483 (mem PairAMode) 484 (flags MemFlags)) 485 486 ;; Conversion: FP -> integer. 487 (FpuToInt 488 (op FpuToIntOp) 489 (rd WritableReg) 490 (rn Reg)) 491 492 ;; Conversion: integer -> FP. 493 (IntToFpu 494 (op IntToFpuOp) 495 (rd WritableReg) 496 (rn Reg)) 497 498 ;; FP conditional select, 16 bit. 499 ;; Requires FEAT_FP16. 500 (FpuCSel16 501 (rd WritableReg) 502 (rn Reg) 503 (rm Reg) 504 (cond Cond)) 505 506 ;; FP conditional select, 32 bit. 507 (FpuCSel32 508 (rd WritableReg) 509 (rn Reg) 510 (rm Reg) 511 (cond Cond)) 512 513 ;; FP conditional select, 64 bit. 514 (FpuCSel64 515 (rd WritableReg) 516 (rn Reg) 517 (rm Reg) 518 (cond Cond)) 519 520 ;; Round to integer. 521 (FpuRound 522 (op FpuRoundMode) 523 (rd WritableReg) 524 (rn Reg)) 525 526 ;; Move from a GPR to a vector register. The scalar value is parked in the lowest lane 527 ;; of the destination, and all other lanes are zeroed out. Currently 16-, 32- and 64-bit 528 ;; transactions are supported. 16-bit moves require FEAT_FP16. 529 (MovToFpu 530 (rd WritableReg) 531 (rn Reg) 532 (size ScalarSize)) 533 534 ;; Loads a floating-point immediate. 535 (FpuMoveFPImm 536 (rd WritableReg) 537 (imm ASIMDFPModImm) 538 (size ScalarSize)) 539 540 ;; Move to a vector element from a GPR. 541 (MovToVec 542 (rd WritableReg) 543 (ri Reg) 544 (rn Reg) 545 (idx u8) 546 (size VectorSize)) 547 548 ;; Unsigned move from a vector element to a GPR. 549 (MovFromVec 550 (rd WritableReg) 551 (rn Reg) 552 (idx u8) 553 (size ScalarSize)) 554 555 ;; Signed move from a vector element to a GPR. 556 (MovFromVecSigned 557 (rd WritableReg) 558 (rn Reg) 559 (idx u8) 560 (size VectorSize) 561 (scalar_size OperandSize)) 562 563 ;; Duplicate general-purpose register to vector. 564 (VecDup 565 (rd WritableReg) 566 (rn Reg) 567 (size VectorSize)) 568 569 ;; Duplicate scalar to vector. 570 (VecDupFromFpu 571 (rd WritableReg) 572 (rn Reg) 573 (size VectorSize) 574 (lane u8)) 575 576 ;; Duplicate FP immediate to vector. 577 (VecDupFPImm 578 (rd WritableReg) 579 (imm ASIMDFPModImm) 580 (size VectorSize)) 581 582 ;; Duplicate immediate to vector. 583 (VecDupImm 584 (rd WritableReg) 585 (imm ASIMDMovModImm) 586 (invert bool) 587 (size VectorSize)) 588 589 ;; Vector extend. 590 (VecExtend 591 (t VecExtendOp) 592 (rd WritableReg) 593 (rn Reg) 594 (high_half bool) 595 (lane_size ScalarSize)) 596 597 ;; Move vector element to another vector element. 598 (VecMovElement 599 (rd WritableReg) 600 (ri Reg) 601 (rn Reg) 602 (dest_idx u8) 603 (src_idx u8) 604 (size VectorSize)) 605 606 ;; Vector widening operation. 607 (VecRRLong 608 (op VecRRLongOp) 609 (rd WritableReg) 610 (rn Reg) 611 (high_half bool)) 612 613 ;; Vector narrowing operation -- low half. 614 (VecRRNarrowLow 615 (op VecRRNarrowOp) 616 (rd WritableReg) 617 (rn Reg) 618 (lane_size ScalarSize)) 619 620 ;; Vector narrowing operation -- high half. 621 (VecRRNarrowHigh 622 (op VecRRNarrowOp) 623 (rd WritableReg) 624 (ri Reg) 625 (rn Reg) 626 (lane_size ScalarSize)) 627 628 ;; 1-operand vector instruction that operates on a pair of elements. 629 (VecRRPair 630 (op VecPairOp) 631 (rd WritableReg) 632 (rn Reg)) 633 634 ;; 2-operand vector instruction that produces a result with twice the 635 ;; lane width and half the number of lanes. 636 (VecRRRLong 637 (alu_op VecRRRLongOp) 638 (rd WritableReg) 639 (rn Reg) 640 (rm Reg) 641 (high_half bool)) 642 643 ;; 2-operand vector instruction that produces a result with 644 ;; twice the lane width and half the number of lanes. Variant 645 ;; that modifies `rd` (so takes its initial state as `ri`). 646 (VecRRRLongMod 647 (alu_op VecRRRLongModOp) 648 (rd WritableReg) 649 (ri Reg) 650 (rn Reg) 651 (rm Reg) 652 (high_half bool)) 653 654 ;; 1-operand vector instruction that extends elements of the input 655 ;; register and operates on a pair of elements. The output lane width 656 ;; is double that of the input. 657 (VecRRPairLong 658 (op VecRRPairLongOp) 659 (rd WritableReg) 660 (rn Reg)) 661 662 ;; A vector ALU op. 663 (VecRRR 664 (alu_op VecALUOp) 665 (rd WritableReg) 666 (rn Reg) 667 (rm Reg) 668 (size VectorSize)) 669 670 ;; A vector ALU op modifying a source register. 671 (VecRRRMod 672 (alu_op VecALUModOp) 673 (rd WritableReg) 674 (ri Reg) 675 (rn Reg) 676 (rm Reg) 677 (size VectorSize)) 678 679 ;; A vector ALU op modifying a source register. 680 (VecFmlaElem 681 (alu_op VecALUModOp) 682 (rd WritableReg) 683 (ri Reg) 684 (rn Reg) 685 (rm Reg) 686 (size VectorSize) 687 (idx u8)) 688 689 ;; Vector two register miscellaneous instruction. 690 (VecMisc 691 (op VecMisc2) 692 (rd WritableReg) 693 (rn Reg) 694 (size VectorSize)) 695 696 ;; Vector instruction across lanes. 697 (VecLanes 698 (op VecLanesOp) 699 (rd WritableReg) 700 (rn Reg) 701 (size VectorSize)) 702 703 ;; Vector shift by immediate Shift Left (immediate), Unsigned Shift Right (immediate) 704 ;; Signed Shift Right (immediate). These are somewhat unusual in that, for right shifts, 705 ;; the allowed range of `imm` values is 1 to lane-size-in-bits, inclusive. A zero 706 ;; right-shift cannot be encoded. Left shifts are "normal", though, having valid `imm` 707 ;; values from 0 to lane-size-in-bits - 1 inclusive. 708 (VecShiftImm 709 (op VecShiftImmOp) 710 (rd WritableReg) 711 (rn Reg) 712 (size VectorSize) 713 (imm u8)) 714 715 ;; Destructive vector shift by immediate. 716 (VecShiftImmMod 717 (op VecShiftImmModOp) 718 (rd WritableReg) 719 (ri Reg) 720 (rn Reg) 721 (size VectorSize) 722 (imm u8)) 723 724 ;; Vector extract - create a new vector, being the concatenation of the lowest `imm4` bytes 725 ;; of `rm` followed by the uppermost `16 - imm4` bytes of `rn`. 726 (VecExtract 727 (rd WritableReg) 728 (rn Reg) 729 (rm Reg) 730 (imm4 u8)) 731 732 ;; Table vector lookup - single register table. The table 733 ;; consists of 8-bit elements and is stored in `rn`, while `rm` 734 ;; contains 8-bit element indices. This variant emits `TBL`, 735 ;; which sets elements that correspond to out-of-range indices 736 ;; (greater than 15) to 0. 737 (VecTbl 738 (rd WritableReg) 739 (rn Reg) 740 (rm Reg)) 741 742 ;; Table vector lookup - single register table. The table 743 ;; consists of 8-bit elements and is stored in `rn`, while `rm` 744 ;; contains 8-bit element indices. This variant emits `TBX`, 745 ;; which leaves elements that correspond to out-of-range indices 746 ;; (greater than 15) unmodified. Hence, it takes an input vreg in 747 ;; `ri` that is constrained to the same allocation as `rd`. 748 (VecTblExt 749 (rd WritableReg) 750 (ri Reg) 751 (rn Reg) 752 (rm Reg)) 753 754 ;; Table vector lookup - two register table. The table consists 755 ;; of 8-bit elements and is stored in `rn` and `rn2`, while 756 ;; `rm` contains 8-bit element indices. The table registers 757 ;; `rn` and `rn2` must have consecutive numbers modulo 32, that 758 ;; is v31 and v0 (in that order) are consecutive registers. 759 ;; This variant emits `TBL`, which sets out-of-range results to 760 ;; 0. 761 (VecTbl2 762 (rd WritableReg) 763 (rn Reg) 764 (rn2 Reg) 765 (rm Reg)) 766 767 ;; Table vector lookup - two register table. The table consists 768 ;; of 8-bit elements and is stored in `rn` and `rn2`, while 769 ;; `rm` contains 8-bit element indices. The table registers 770 ;; `rn` and `rn2` must have consecutive numbers modulo 32, that 771 ;; is v31 and v0 (in that order) are consecutive registers. 772 ;; This variant emits `TBX`, which leaves out-of-range results 773 ;; unmodified, hence takes the initial state of the result 774 ;; register in vreg `ri`. 775 (VecTbl2Ext 776 (rd WritableReg) 777 (ri Reg) 778 (rn Reg) 779 (rn2 Reg) 780 (rm Reg)) 781 782 ;; Load an element and replicate to all lanes of a vector. 783 (VecLoadReplicate 784 (rd WritableReg) 785 (rn Reg) 786 (size VectorSize) 787 (flags MemFlags)) 788 789 ;; Vector conditional select, 128 bit. A synthetic instruction, which generates a 4-insn 790 ;; control-flow diamond. 791 (VecCSel 792 (rd WritableReg) 793 (rn Reg) 794 (rm Reg) 795 (cond Cond)) 796 797 ;; Move to the NZCV flags (actually a `MSR NZCV, Xn` insn). 798 (MovToNZCV 799 (rn Reg)) 800 801 ;; Move from the NZCV flags (actually a `MRS Xn, NZCV` insn). 802 (MovFromNZCV 803 (rd WritableReg)) 804 805 ;; A machine call instruction. N.B.: this allows only a +/- 128MB offset (it uses a relocation 806 ;; of type `Reloc::Arm64Call`); if the destination distance is not `RelocDistance::Near`, the 807 ;; code should use a `LoadExtName` / `CallInd` sequence instead, allowing an arbitrary 64-bit 808 ;; target. 809 (Call (info BoxCallInfo)) 810 811 ;; A machine indirect-call instruction. 812 (CallInd (info BoxCallIndInfo)) 813 814 ;; A return-call macro instruction. 815 (ReturnCall (info BoxReturnCallInfo)) 816 817 ;; An indirect return-call macro instruction. 818 (ReturnCallInd (info BoxReturnCallIndInfo)) 819 820 ;; A pseudo-instruction that captures register arguments in vregs. 821 (Args 822 (args VecArgPair)) 823 824 ;; A pseudo-instruction that moves vregs to return registers. 825 (Rets 826 (rets VecRetPair)) 827 828 ;; ---- branches (exactly one must appear at end of BB) ---- 829 830 ;; A machine return instruction. 831 (Ret) 832 833 ;; A machine return instruction with pointer authentication using SP as the 834 ;; modifier. This instruction requires pointer authentication support 835 ;; (FEAT_PAuth) unless `is_hint` is true, in which case it is equivalent to 836 ;; the combination of a no-op and a return instruction on platforms without 837 ;; the relevant support. 838 (AuthenticatedRet 839 (key APIKey) 840 (is_hint bool)) 841 842 ;; An unconditional branch. 843 (Jump 844 (dest BranchTarget)) 845 846 ;; A conditional branch. Contains two targets; at emission time, both are emitted, but 847 ;; the MachBuffer knows to truncate the trailing branch if fallthrough. We optimize the 848 ;; choice of taken/not_taken (inverting the branch polarity as needed) based on the 849 ;; fallthrough at the time of lowering. 850 (CondBr 851 (taken BranchTarget) 852 (not_taken BranchTarget) 853 (kind CondBrKind)) 854 855 ;; A conditional branch which tests the `bit` of `rn` and branches 856 ;; depending on `kind`. 857 (TestBitAndBranch 858 (kind TestBitAndBranchKind) 859 (taken BranchTarget) 860 (not_taken BranchTarget) 861 (rn Reg) 862 (bit u8)) 863 864 ;; A conditional trap: execute a `udf` if the condition is true. This is 865 ;; one VCode instruction because it uses embedded control flow; it is 866 ;; logically a single-in, single-out region, but needs to appear as one 867 ;; unit to the register allocator. 868 ;; 869 ;; The `CondBrKind` gives the conditional-branch condition that will 870 ;; *execute* the embedded `Inst`. (In the emitted code, we use the inverse 871 ;; of this condition in a branch that skips the trap instruction.) 872 (TrapIf 873 (kind CondBrKind) 874 (trap_code TrapCode)) 875 876 ;; An indirect branch through a register, augmented with set of all 877 ;; possible successors. 878 (IndirectBr 879 (rn Reg) 880 (targets VecMachLabel)) 881 882 ;; A "break" instruction, used for e.g. traps and debug breakpoints. 883 (Brk) 884 885 ;; An instruction guaranteed to always be undefined and to trigger an illegal instruction at 886 ;; runtime. 887 (Udf 888 (trap_code TrapCode)) 889 890 ;; Compute the address (using a PC-relative offset) of a memory location, using the `ADR` 891 ;; instruction. Note that we take a simple offset, not a `MemLabel`, here, because `Adr` is 892 ;; only used for now in fixed lowering sequences with hardcoded offsets. In the future we may 893 ;; need full `MemLabel` support. 894 (Adr 895 (rd WritableReg) 896 ;; Offset in range -2^20 .. 2^20. 897 (off i32)) 898 899 ;; Compute the address (using a PC-relative offset) of a 4KB page. 900 (Adrp 901 (rd WritableReg) 902 (off i32)) 903 904 ;; Raw 32-bit word, used for inline constants and jump-table entries. 905 (Word4 906 (data u32)) 907 908 ;; Raw 64-bit word, used for inline constants. 909 (Word8 910 (data u64)) 911 912 ;; Jump-table sequence, as one compound instruction (see note in lower_inst.rs for rationale). 913 (JTSequence 914 (default MachLabel) 915 (targets BoxVecMachLabel) 916 (ridx Reg) 917 (rtmp1 WritableReg) 918 (rtmp2 WritableReg)) 919 920 ;; Load an inline symbol reference. 921 (LoadExtNameGot 922 (rd WritableReg) 923 (name BoxExternalName)) 924 (LoadExtNameNear 925 (rd WritableReg) 926 (name BoxExternalName) 927 (offset i64)) 928 (LoadExtNameFar 929 (rd WritableReg) 930 (name BoxExternalName) 931 (offset i64)) 932 933 ;; Load address referenced by `mem` into `rd`. 934 (LoadAddr 935 (rd WritableReg) 936 (mem AMode)) 937 938 ;; Pointer authentication code for instruction address with modifier in SP; 939 ;; equivalent to a no-op if Pointer authentication (FEAT_PAuth) is not 940 ;; supported. 941 (Paci 942 (key APIKey)) 943 944 ;; Strip pointer authentication code from instruction address in LR; 945 ;; equivalent to a no-op if Pointer authentication (FEAT_PAuth) is not 946 ;; supported. 947 (Xpaclri) 948 949 ;; Branch target identification; equivalent to a no-op if Branch Target 950 ;; Identification (FEAT_BTI) is not supported. 951 (Bti 952 (targets BranchTargetType)) 953 954 ;; Meta-insn, no-op in generated code: emit constant/branch veneer island 955 ;; at this point (with a guard jump around it) if less than the needed 956 ;; space is available before the next branch deadline. See the `MachBuffer` 957 ;; implementation in `machinst/buffer.rs` for the overall algorithm. In 958 ;; brief, we retain a set of "pending/unresolved label references" from 959 ;; branches as we scan forward through instructions to emit machine code; 960 ;; if we notice we're about to go out of range on an unresolved reference, 961 ;; we stop, emit a bunch of "veneers" (branches in a form that has a longer 962 ;; range, e.g. a 26-bit-offset unconditional jump), and point the original 963 ;; label references to those. This is an "island" because it comes in the 964 ;; middle of the code. 965 ;; 966 ;; This meta-instruction is a necessary part of the logic that determines 967 ;; where to place islands. Ordinarily, we want to place them between basic 968 ;; blocks, so we compute the worst-case size of each block, and emit the 969 ;; island before starting a block if we would exceed a deadline before the 970 ;; end of the block. However, some sequences (such as an inline jumptable) 971 ;; are variable-length and not accounted for by this logic; so these 972 ;; lowered sequences include an `EmitIsland` to trigger island generation 973 ;; where necessary. 974 (EmitIsland 975 ;; The needed space before the next deadline. 976 (needed_space CodeOffset)) 977 978 ;; A call to the `ElfTlsGetAddr` libcall. Returns address of TLS symbol in x0. 979 (ElfTlsGetAddr 980 (symbol BoxExternalName) 981 (rd WritableReg) 982 (tmp WritableReg)) 983 984 (MachOTlsGetAddr 985 (symbol ExternalName) 986 (rd WritableReg)) 987 988 ;; An unwind pseudo-instruction. 989 (Unwind 990 (inst UnwindInst)) 991 992 ;; A dummy use, useful to keep a value alive. 993 (DummyUse 994 (reg Reg)) 995 996 ;; A pseudoinstruction that loads the address of a label. 997 (LabelAddress (dst WritableReg) 998 (label MachLabel)) 999 1000 ;; A pseudoinstruction that serves as a sequence point. 1001 (SequencePoint) 1002 1003 ;; Emits an inline stack probe loop. 1004 ;; 1005 ;; Note that this is emitted post-regalloc so `start` and `end` can be 1006 ;; temporary registers such as the spilltmp and tmp2 registers. This also 1007 ;; means that the internal codegen can't use these registers. 1008 (StackProbeLoop (start WritableReg) 1009 (end Reg) 1010 (step Imm12)))) 1011 1012(model ALUOp (enum 1013 (Add #x00) ;; 0 1014 (Sub #x01) 1015 (Orr #x02) 1016 (OrrNot #x03) 1017 (And #x04) 1018 (AndNot #x05) 1019 (Eor #x06) 1020 (EorNot #x07) 1021 (SubS #x08) 1022 (SDiv #x09) 1023 (UDiv #x0a) 1024 (Extr #x0b) 1025 (Lsr #x0c) 1026 (Asr #x0d) 1027 (Lsl #x0e))) 1028 1029;; An ALU operation. This can be paired with several instruction formats 1030;; below (see `Inst`) in any combination. 1031(type ALUOp 1032 (enum 1033 (Add) 1034 (Sub) 1035 (Orr) 1036 (OrrNot) 1037 (And) 1038 (AndS) 1039 (AndNot) 1040 ;; XOR (AArch64 calls this "EOR") 1041 (Eor) 1042 ;; XNOR (AArch64 calls this "EOR-NOT") 1043 (EorNot) 1044 ;; Add, setting flags 1045 (AddS) 1046 ;; Sub, setting flags 1047 (SubS) 1048 ;; Signed multiply, high-word result 1049 (SMulH) 1050 ;; Unsigned multiply, high-word result 1051 (UMulH) 1052 (SDiv) 1053 (UDiv) 1054 (Extr) 1055 (Lsr) 1056 (Asr) 1057 (Lsl) 1058 ;; Add with carry 1059 (Adc) 1060 ;; Add with carry, settings flags 1061 (AdcS) 1062 ;; Subtract with carry 1063 (Sbc) 1064 ;; Subtract with carry, settings flags 1065 (SbcS) 1066)) 1067 1068;; An ALU operation with three arguments. 1069(type ALUOp3 1070 (enum 1071 ;; Multiply-add 1072 (MAdd) 1073 ;; Multiply-sub 1074 (MSub) 1075 ;; Unsigned-Multiply-add 1076 (UMAddL) 1077 ;; Signed-Multiply-add 1078 (SMAddL) 1079)) 1080 1081(type MoveWideOp 1082 (enum 1083 (MovZ) 1084 (MovN) 1085)) 1086 1087(type UImm5 (primitive UImm5)) 1088(model Imm12 (type (bv 24))) 1089(type Imm12 (primitive Imm12)) 1090(model ImmLogic (type (bv 64))) 1091(type ImmLogic (primitive ImmLogic)) 1092(model ImmShift (type (bv 6))) 1093(type ImmShift (primitive ImmShift)) 1094(model ShiftOpAndAmt (type (bv 16))) 1095(type ShiftOpAndAmt (primitive ShiftOpAndAmt)) 1096(model MoveWideConst (type (bv 16))) 1097(type MoveWideConst (primitive MoveWideConst)) 1098(type NZCV (primitive NZCV)) 1099(type ASIMDFPModImm (primitive ASIMDFPModImm)) 1100(type ASIMDMovModImm (primitive ASIMDMovModImm)) 1101(type SImm7Scaled (primitive SImm7Scaled)) 1102 1103(type BoxCallInfo (primitive BoxCallInfo)) 1104(type BoxCallIndInfo (primitive BoxCallIndInfo)) 1105(type BoxReturnCallInfo (primitive BoxReturnCallInfo)) 1106(type BoxReturnCallIndInfo (primitive BoxReturnCallIndInfo)) 1107(type CondBrKind (primitive CondBrKind)) 1108(type BranchTarget (primitive BranchTarget)) 1109(type BoxJTSequenceInfo (primitive BoxJTSequenceInfo)) 1110(type CodeOffset (primitive CodeOffset)) 1111(type VecMachLabel extern (enum)) 1112 1113(model ExtendOp (enum 1114 (UXTB #b000) 1115 (UXTH #b001) 1116 (UXTW #b010) 1117 (UXTX #b011) 1118 (SXTB #b100) 1119 (SXTH #b101) 1120 (SXTW #b110) 1121 (SXTX #b111) 1122)) 1123 1124(type ExtendOp extern 1125 (enum 1126 (UXTB) 1127 (UXTH) 1128 (UXTW) 1129 (UXTX) 1130 (SXTB) 1131 (SXTH) 1132 (SXTW) 1133 (SXTX) 1134)) 1135 1136;; An operation on the bits of a register. This can be paired with several instruction formats 1137;; below (see `Inst`) in any combination. 1138(type BitOp 1139 (enum 1140 ;; Bit reverse 1141 (RBit) 1142 (Clz) 1143 (Cls) 1144 ;; Byte reverse 1145 (Rev16) 1146 (Rev32) 1147 (Rev64) 1148)) 1149 1150(type MemLabel extern (enum)) 1151(type SImm9 extern (enum)) 1152(type UImm12Scaled extern (enum)) 1153 1154;; An addressing mode specified for a load/store operation. 1155(type AMode 1156 (enum 1157 ;; 1158 ;; Real ARM64 addressing modes: 1159 ;; 1160 ;; "post-indexed" mode as per AArch64 docs: postincrement reg after 1161 ;; address computation. 1162 ;; Specialized here to SP so we don't have to emit regalloc metadata. 1163 (SPPostIndexed 1164 (simm9 SImm9)) 1165 1166 ;; "pre-indexed" mode as per AArch64 docs: preincrement reg before 1167 ;; address computation. 1168 ;; Specialized here to SP so we don't have to emit regalloc metadata. 1169 (SPPreIndexed 1170 (simm9 SImm9)) 1171 1172 ;; N.B.: RegReg, RegScaled, and RegScaledExtended all correspond to 1173 ;; what the ISA calls the "register offset" addressing mode. We split 1174 ;; out several options here for more ergonomic codegen. 1175 ;; 1176 ;; Register plus register offset. 1177 (RegReg 1178 (rn Reg) 1179 (rm Reg)) 1180 1181 ;; Register plus register offset, scaled by type's size. 1182 (RegScaled 1183 (rn Reg) 1184 (rm Reg)) 1185 1186 ;; Register plus register offset, scaled by type's size, with index 1187 ;; sign- or zero-extended first. 1188 (RegScaledExtended 1189 (rn Reg) 1190 (rm Reg) 1191 (extendop ExtendOp)) 1192 1193 ;; Register plus register offset, with index sign- or zero-extended 1194 ;; first. 1195 (RegExtended 1196 (rn Reg) 1197 (rm Reg) 1198 (extendop ExtendOp)) 1199 1200 ;; Unscaled signed 9-bit immediate offset from reg. 1201 (Unscaled 1202 (rn Reg) 1203 (simm9 SImm9)) 1204 1205 ;; Scaled (by size of a type) unsigned 12-bit immediate offset from reg. 1206 (UnsignedOffset 1207 (rn Reg) 1208 (uimm12 UImm12Scaled)) 1209 1210 ;; virtual addressing modes that are lowered at emission time: 1211 ;; 1212 ;; Reference to a "label": e.g., a symbol. 1213 (Label 1214 (label MemLabel)) 1215 1216 ;; Arbitrary offset from a register. Converted to generation of large 1217 ;; offsets with multiple instructions as necessary during code emission. 1218 (RegOffset 1219 (rn Reg) 1220 (off i64)) 1221 1222 ;; Offset from the stack pointer. 1223 (SPOffset 1224 (off i64)) 1225 1226 ;; Offset from the frame pointer. 1227 (FPOffset 1228 (off i64)) 1229 1230 ;; A reference to a constant which is placed outside of the function's 1231 ;; body, typically at the end. 1232 (Const 1233 (addr VCodeConstant)) 1234 1235 ;; Offset from the beginning of the argument area to the argument 1236 ;; referenced. This can only be determined when the function has been 1237 ;; processed fully, as the size of the argument area after the prologue 1238 ;; is only known once all return_call instructions in the function body 1239 ;; have been processed. 1240 (IncomingArg 1241 (off i64)) 1242 1243 ;; Offset into the slot area of the stack, which lies just above the 1244 ;; outgoing argument area that's setup by the function prologue. 1245 ;; At emission time, this is converted to `SPOffset` with a fixup added to 1246 ;; the offset constant. The fixup is a running value that is tracked as 1247 ;; emission iterates through instructions in linear order, and can be 1248 ;; adjusted up and down with [Inst::VirtualSPOffsetAdj]. 1249 ;; 1250 ;; The standard ABI is in charge of handling this (by emitting the 1251 ;; adjustment meta-instructions). See the diagram in the documentation 1252 ;; for [crate::isa::aarch64::abi](the ABI module) for more details. 1253 (SlotOffset 1254 (off i64)))) 1255 1256;; A memory argument to a load/store-pair. 1257(type PairAMode (enum 1258 ;; Signed, scaled 7-bit offset from a register. 1259 (SignedOffset 1260 (reg Reg) 1261 (simm7 SImm7Scaled)) 1262 1263 ;; Pre-increment register before address computation. 1264 (SPPreIndexed (simm7 SImm7Scaled)) 1265 1266 ;; Post-increment register after address computation. 1267 (SPPostIndexed (simm7 SImm7Scaled)) 1268)) 1269 1270(type FPUOpRI extern (enum)) 1271(type FPUOpRIMod extern (enum)) 1272 1273(model OperandSize 1274 (enum (Size32 32) 1275 (Size64 64))) 1276 1277(type OperandSize extern 1278 (enum Size32 1279 Size64)) 1280 1281(type TestBitAndBranchKind (enum (Z) (NZ))) 1282 1283;; Helper for calculating the `OperandSize` corresponding to a type 1284(spec (operand_size ty) 1285 (provide 1286 (= result (if (<= ty 32) 32 64))) 1287 (require 1288 (or (= ty 8) (= ty 16) (= ty 32) (= ty 64)))) 1289(instantiate operand_size 1290 ((args Int) (ret Int) (canon (bv 8))) 1291 ((args Int) (ret Int) (canon (bv 16))) 1292 ((args Int) (ret Int) (canon (bv 32))) 1293 ((args Int) (ret Int) (canon (bv 64))) 1294) 1295(decl operand_size (Type) OperandSize) 1296(rule operand_size_32 1 (operand_size (fits_in_32 _ty)) (OperandSize.Size32)) 1297(rule operand_size_64 (operand_size (fits_in_64 _ty)) (OperandSize.Size64)) 1298 1299(model ScalarSize 1300 (enum (Size8 8) 1301 (Size16 16) 1302 (Size32 32) 1303 (Size64 64) 1304 (Size128 128))) 1305 1306;; Difference (32 - ty), useful for narrow calculations with 32-bit 1307;; instructions. 1308(decl diff_from_32 (Type) u8) 1309(rule (diff_from_32 $I8) 24) 1310(rule (diff_from_32 $I16) 16) 1311 1312(type ScalarSize extern 1313 (enum Size8 1314 Size16 1315 Size32 1316 Size64 1317 Size128)) 1318 1319;; Helper for calculating the `ScalarSize` corresponding to a type 1320(decl scalar_size (Type) ScalarSize) 1321 1322(rule (scalar_size $I8) (ScalarSize.Size8)) 1323(rule (scalar_size $I16) (ScalarSize.Size16)) 1324(rule (scalar_size $I32) (ScalarSize.Size32)) 1325(rule (scalar_size $I64) (ScalarSize.Size64)) 1326(rule (scalar_size $I128) (ScalarSize.Size128)) 1327 1328(rule (scalar_size $F32) (ScalarSize.Size32)) 1329(rule (scalar_size $F64) (ScalarSize.Size64)) 1330 1331;; Helper for calculating the `ScalarSize` lane type from vector type 1332(decl lane_size (Type) ScalarSize) 1333(rule 1 (lane_size (multi_lane 8 _)) (ScalarSize.Size8)) 1334(rule 1 (lane_size (multi_lane 16 _)) (ScalarSize.Size16)) 1335(rule 1 (lane_size (multi_lane 32 _)) (ScalarSize.Size32)) 1336(rule 1 (lane_size (multi_lane 64 _)) (ScalarSize.Size64)) 1337(rule (lane_size (dynamic_lane 8 _)) (ScalarSize.Size8)) 1338(rule (lane_size (dynamic_lane 16 _)) (ScalarSize.Size16)) 1339(rule (lane_size (dynamic_lane 32 _)) (ScalarSize.Size32)) 1340(rule (lane_size (dynamic_lane 64 _)) (ScalarSize.Size64)) 1341 1342;; Helper for extracting the size of a lane from the input `VectorSize` 1343(decl pure vector_lane_size (VectorSize) ScalarSize) 1344(rule (vector_lane_size (VectorSize.Size8x16)) (ScalarSize.Size8)) 1345(rule (vector_lane_size (VectorSize.Size8x8)) (ScalarSize.Size8)) 1346(rule (vector_lane_size (VectorSize.Size16x8)) (ScalarSize.Size16)) 1347(rule (vector_lane_size (VectorSize.Size16x4)) (ScalarSize.Size16)) 1348(rule (vector_lane_size (VectorSize.Size32x4)) (ScalarSize.Size32)) 1349(rule (vector_lane_size (VectorSize.Size32x2)) (ScalarSize.Size32)) 1350(rule (vector_lane_size (VectorSize.Size64x2)) (ScalarSize.Size64)) 1351 1352(model Cond 1353 (enum (Lo #x03) 1354 (Hi #x08) 1355 (Lt #x0b) 1356 (Gt #x0c))) 1357 1358(type Cond extern 1359 (enum 1360 (Eq) 1361 (Ne) 1362 (Hs) 1363 (Lo) 1364 (Mi) 1365 (Pl) 1366 (Vs) 1367 (Vc) 1368 (Hi) 1369 (Ls) 1370 (Ge) 1371 (Lt) 1372 (Gt) 1373 (Le) 1374 (Al) 1375 (Nv) 1376)) 1377 1378(model VectorSize 1379 (enum 1380 (Size8x8 #x00) 1381 (Size8x16 #x01) 1382 (Size16x4 #x02) 1383 (Size16x8 #x03) 1384 (Size32x2 #x04) 1385 (Size32x4 #x05) 1386 (Size64x2 #x06))) 1387 1388(type VectorSize extern 1389 (enum 1390 (Size8x8) 1391 (Size8x16) 1392 (Size16x4) 1393 (Size16x8) 1394 (Size32x2) 1395 (Size32x4) 1396 (Size64x2) 1397)) 1398 1399;; Helper for calculating the `VectorSize` corresponding to a type 1400(decl vector_size (Type) VectorSize) 1401(rule 1 (vector_size (multi_lane 8 8)) (VectorSize.Size8x8)) 1402(rule 1 (vector_size (multi_lane 8 16)) (VectorSize.Size8x16)) 1403(rule 1 (vector_size (multi_lane 16 4)) (VectorSize.Size16x4)) 1404(rule 1 (vector_size (multi_lane 16 8)) (VectorSize.Size16x8)) 1405(rule 1 (vector_size (multi_lane 32 2)) (VectorSize.Size32x2)) 1406(rule 1 (vector_size (multi_lane 32 4)) (VectorSize.Size32x4)) 1407(rule 1 (vector_size (multi_lane 64 2)) (VectorSize.Size64x2)) 1408(rule (vector_size (dynamic_lane 8 8)) (VectorSize.Size8x8)) 1409(rule (vector_size (dynamic_lane 8 16)) (VectorSize.Size8x16)) 1410(rule (vector_size (dynamic_lane 16 4)) (VectorSize.Size16x4)) 1411(rule (vector_size (dynamic_lane 16 8)) (VectorSize.Size16x8)) 1412(rule (vector_size (dynamic_lane 32 2)) (VectorSize.Size32x2)) 1413(rule (vector_size (dynamic_lane 32 4)) (VectorSize.Size32x4)) 1414(rule (vector_size (dynamic_lane 64 2)) (VectorSize.Size64x2)) 1415 1416;; Helper for converting the `ScalarSize` of a float value to the corresponding `VectorSize` 1417(decl float_vector_size_in_64 (Type) VectorSize) 1418(rule (float_vector_size_in_64 $F16) (VectorSize.Size16x4)) 1419(rule (float_vector_size_in_64 $F32) (VectorSize.Size32x2)) 1420(rule (float_vector_size_in_64 $F64) (VectorSize.Size8x8)) 1421 1422;; A floating-point unit (FPU) operation with one arg. 1423(type FPUOp1 1424 (enum 1425 (Abs) 1426 (Neg) 1427 (Sqrt) 1428 (Cvt32To64) 1429 (Cvt64To32) 1430)) 1431 1432;; A floating-point unit (FPU) operation with two args. 1433(type FPUOp2 1434 (enum 1435 (Add) 1436 (Sub) 1437 (Mul) 1438 (Div) 1439 (Max) 1440 (Min) 1441)) 1442 1443;; A floating-point unit (FPU) operation with three args. 1444(type FPUOp3 1445 (enum 1446 ;; Multiply-add 1447 (MAdd) 1448 ;; Multiply-sub 1449 (MSub) 1450 ;; Negated fused Multiply-add 1451 (NMAdd) 1452 ;; Negated fused Multiply-sub 1453 (NMSub) 1454)) 1455 1456;; A conversion from an FP to an integer value. 1457(type FpuToIntOp 1458 (enum 1459 (F32ToU32) 1460 (F32ToI32) 1461 (F32ToU64) 1462 (F32ToI64) 1463 (F64ToU32) 1464 (F64ToI32) 1465 (F64ToU64) 1466 (F64ToI64) 1467)) 1468 1469;; A conversion from an integer to an FP value. 1470(type IntToFpuOp 1471 (enum 1472 (U32ToF32) 1473 (I32ToF32) 1474 (U32ToF64) 1475 (I32ToF64) 1476 (U64ToF32) 1477 (I64ToF32) 1478 (U64ToF64) 1479 (I64ToF64) 1480)) 1481 1482;; Modes for FP rounding ops: round down (floor) or up (ceil), or toward zero (trunc), or to 1483;; nearest, and for 32- or 64-bit FP values. 1484(type FpuRoundMode 1485 (enum 1486 (Minus32) 1487 (Minus64) 1488 (Plus32) 1489 (Plus64) 1490 (Zero32) 1491 (Zero64) 1492 (Nearest32) 1493 (Nearest64) 1494)) 1495 1496;; Type of vector element extensions. 1497(type VecExtendOp 1498 (enum 1499 ;; Signed extension 1500 (Sxtl) 1501 ;; Unsigned extension 1502 (Uxtl) 1503)) 1504 1505;; A vector ALU operation. 1506(type VecALUOp 1507 (enum 1508 ;; Signed saturating add 1509 (Sqadd) 1510 ;; Unsigned saturating add 1511 (Uqadd) 1512 ;; Signed saturating subtract 1513 (Sqsub) 1514 ;; Unsigned saturating subtract 1515 (Uqsub) 1516 ;; Compare bitwise equal 1517 (Cmeq) 1518 ;; Compare signed greater than or equal 1519 (Cmge) 1520 ;; Compare signed greater than 1521 (Cmgt) 1522 ;; Compare unsigned higher 1523 (Cmhs) 1524 ;; Compare unsigned higher or same 1525 (Cmhi) 1526 ;; Floating-point compare equal 1527 (Fcmeq) 1528 ;; Floating-point compare greater than 1529 (Fcmgt) 1530 ;; Floating-point compare greater than or equal 1531 (Fcmge) 1532 ;; Bitwise and 1533 (And) 1534 ;; Bitwise bit clear 1535 (Bic) 1536 ;; Bitwise inclusive or 1537 (Orr) 1538 ;; Bitwise inclusive or not 1539 (Orn) 1540 ;; Bitwise exclusive or 1541 (Eor) 1542 ;; Unsigned maximum pairwise 1543 (Umaxp) 1544 ;; Add 1545 (Add) 1546 ;; Subtract 1547 (Sub) 1548 ;; Multiply 1549 (Mul) 1550 ;; Signed shift left 1551 (Sshl) 1552 ;; Unsigned shift left 1553 (Ushl) 1554 ;; Unsigned minimum 1555 (Umin) 1556 ;; Signed minimum 1557 (Smin) 1558 ;; Unsigned maximum 1559 (Umax) 1560 ;; Signed maximum 1561 (Smax) 1562 ;; Unsigned rounding halving add 1563 (Urhadd) 1564 ;; Floating-point add 1565 (Fadd) 1566 ;; Floating-point subtract 1567 (Fsub) 1568 ;; Floating-point divide 1569 (Fdiv) 1570 ;; Floating-point maximum 1571 (Fmax) 1572 ;; Floating-point minimum 1573 (Fmin) 1574 ;; Floating-point multiply 1575 (Fmul) 1576 ;; Add pairwise 1577 (Addp) 1578 ;; Zip vectors (primary) [meaning, high halves] 1579 (Zip1) 1580 ;; Zip vectors (secondary) 1581 (Zip2) 1582 ;; Signed saturating rounding doubling multiply returning high half 1583 (Sqrdmulh) 1584 ;; Unzip vectors (primary) 1585 (Uzp1) 1586 ;; Unzip vectors (secondary) 1587 (Uzp2) 1588 ;; Transpose vectors (primary) 1589 (Trn1) 1590 ;; Transpose vectors (secondary) 1591 (Trn2) 1592)) 1593 1594;; A Vector ALU operation which modifies a source register. 1595(type VecALUModOp 1596 (enum 1597 ;; Bitwise select 1598 (Bsl) 1599 ;; Floating-point fused multiply-add vectors 1600 (Fmla) 1601 ;; Floating-point fused multiply-subtract vectors 1602 (Fmls) 1603)) 1604 1605;; A Vector miscellaneous operation with two registers. 1606(type VecMisc2 1607 (enum 1608 ;; Bitwise NOT 1609 (Not) 1610 ;; Negate 1611 (Neg) 1612 ;; Absolute value 1613 (Abs) 1614 ;; Floating-point absolute value 1615 (Fabs) 1616 ;; Floating-point negate 1617 (Fneg) 1618 ;; Floating-point square root 1619 (Fsqrt) 1620 ;; Reverse elements in 16-bit lanes 1621 (Rev16) 1622 ;; Reverse elements in 32-bit lanes 1623 (Rev32) 1624 ;; Reverse elements in 64-bit doublewords 1625 (Rev64) 1626 ;; Floating-point convert to signed integer, rounding toward zero 1627 (Fcvtzs) 1628 ;; Floating-point convert to unsigned integer, rounding toward zero 1629 (Fcvtzu) 1630 ;; Signed integer convert to floating-point 1631 (Scvtf) 1632 ;; Unsigned integer convert to floating-point 1633 (Ucvtf) 1634 ;; Floating point round to integral, rounding towards nearest 1635 (Frintn) 1636 ;; Floating point round to integral, rounding towards zero 1637 (Frintz) 1638 ;; Floating point round to integral, rounding towards minus infinity 1639 (Frintm) 1640 ;; Floating point round to integral, rounding towards plus infinity 1641 (Frintp) 1642 ;; Population count per byte 1643 (Cnt) 1644 ;; Compare bitwise equal to 0 1645 (Cmeq0) 1646 ;; Compare signed greater than or equal to 0 1647 (Cmge0) 1648 ;; Compare signed greater than 0 1649 (Cmgt0) 1650 ;; Compare signed less than or equal to 0 1651 (Cmle0) 1652 ;; Compare signed less than 0 1653 (Cmlt0) 1654 ;; Floating point compare equal to 0 1655 (Fcmeq0) 1656 ;; Floating point compare greater than or equal to 0 1657 (Fcmge0) 1658 ;; Floating point compare greater than 0 1659 (Fcmgt0) 1660 ;; Floating point compare less than or equal to 0 1661 (Fcmle0) 1662 ;; Floating point compare less than 0 1663 (Fcmlt0) 1664)) 1665 1666;; A vector widening operation with one argument. 1667(type VecRRLongOp 1668 (enum 1669 ;; Floating-point convert to higher precision long, 16-bit elements 1670 (Fcvtl16) 1671 ;; Floating-point convert to higher precision long, 32-bit elements 1672 (Fcvtl32) 1673 ;; Shift left long (by element size), 8-bit elements 1674 (Shll8) 1675 ;; Shift left long (by element size), 16-bit elements 1676 (Shll16) 1677 ;; Shift left long (by element size), 32-bit elements 1678 (Shll32) 1679)) 1680 1681;; A vector narrowing operation with one argument. 1682(type VecRRNarrowOp 1683 (enum 1684 ;; Extract narrow. 1685 (Xtn) 1686 ;; Signed saturating extract narrow. 1687 (Sqxtn) 1688 ;; Signed saturating extract unsigned narrow. 1689 (Sqxtun) 1690 ;; Unsigned saturating extract narrow. 1691 (Uqxtn) 1692 ;; Floating-point convert to lower precision narrow. 1693 (Fcvtn) 1694)) 1695 1696(type VecRRRLongOp 1697 (enum 1698 ;; Signed multiply long. 1699 (Smull8) 1700 (Smull16) 1701 (Smull32) 1702 ;; Unsigned multiply long. 1703 (Umull8) 1704 (Umull16) 1705 (Umull32) 1706)) 1707 1708(type VecRRRLongModOp 1709 (enum 1710 ;; Unsigned multiply add long 1711 (Umlal8) 1712 (Umlal16) 1713 (Umlal32) 1714)) 1715 1716;; A vector operation on a pair of elements with one register. 1717(type VecPairOp 1718 (enum 1719 ;; Add pair of elements 1720 (Addp) 1721)) 1722 1723;; 1-operand vector instruction that extends elements of the input register 1724;; and operates on a pair of elements. 1725(type VecRRPairLongOp 1726 (enum 1727 ;; Sign extend and add pair of elements 1728 (Saddlp8) 1729 (Saddlp16) 1730 ;; Unsigned extend and add pair of elements 1731 (Uaddlp8) 1732 (Uaddlp16) 1733)) 1734 1735;; An operation across the lanes of vectors. 1736(type VecLanesOp 1737 (enum 1738 ;; Integer addition across a vector 1739 (Addv) 1740 ;; Unsigned minimum across a vector 1741 (Uminv) 1742)) 1743 1744;; A shift-by-immediate operation on each lane of a vector. 1745(type VecShiftImmOp 1746 (enum 1747 ;; Unsigned shift left 1748 (Shl) 1749 ;; Unsigned shift right 1750 (Ushr) 1751 ;; Signed shift right 1752 (Sshr) 1753)) 1754 1755;; Destructive shift-by-immediate operation on each lane of a vector. 1756(type VecShiftImmModOp 1757 (enum 1758 ;; Shift left and insert 1759 (Sli) 1760)) 1761 1762;; Atomic read-modify-write operations with acquire-release semantics 1763(type AtomicRMWOp 1764 (enum 1765 (Add) 1766 (Clr) 1767 (Eor) 1768 (Set) 1769 (Smax) 1770 (Smin) 1771 (Umax) 1772 (Umin) 1773 (Swp) 1774)) 1775 1776;; Atomic read-modify-write operations, with acquire-release semantics, 1777;; implemented with a loop. 1778(type AtomicRMWLoopOp 1779 (enum 1780 (Add) 1781 (Sub) 1782 (And) 1783 (Nand) 1784 (Eor) 1785 (Orr) 1786 (Smax) 1787 (Smin) 1788 (Umax) 1789 (Umin) 1790 (Xchg) 1791)) 1792 1793;; Keys for instruction address PACs 1794(type APIKey 1795 (enum 1796 ;; API key A with the modifier of SP 1797 (ASP) 1798 ;; API key B with the modifier of SP 1799 (BSP) 1800 ;; API key A with the modifier of zero 1801 (AZ) 1802 ;; API key B with the modifier of zero 1803 (BZ) 1804)) 1805 1806;; Branch target types 1807(type BranchTargetType 1808 (enum 1809 (None) 1810 (C) 1811 (J) 1812 (JC) 1813)) 1814 1815;; Extractors for target features ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1816(decl pure partial sign_return_address_disabled () Unit) 1817(extern constructor sign_return_address_disabled sign_return_address_disabled) 1818 1819(decl use_lse () Inst) 1820(extern extractor use_lse use_lse) 1821 1822(decl pure use_fp16 () bool) 1823(extern constructor use_fp16 use_fp16) 1824 1825;; Extractor helpers for various immediate constants ;;;;;;;;;;;;;;;;;;;;;;;;;; 1826 1827(decl pure partial move_wide_const_from_u64 (Type u64) MoveWideConst) 1828(extern constructor move_wide_const_from_u64 move_wide_const_from_u64) 1829 1830(decl pure partial move_wide_const_from_inverted_u64 (Type u64) MoveWideConst) 1831(extern constructor move_wide_const_from_inverted_u64 move_wide_const_from_inverted_u64) 1832 1833(decl pure partial imm_logic_from_u64 (Type u64) ImmLogic) 1834(extern constructor imm_logic_from_u64 imm_logic_from_u64) 1835 1836(decl pure partial imm_size_from_type (Type) u16) 1837(extern constructor imm_size_from_type imm_size_from_type) 1838 1839(decl pure partial imm_logic_from_imm64 (Type Imm64) ImmLogic) 1840(extern constructor imm_logic_from_imm64 imm_logic_from_imm64) 1841 1842(spec (imm_shift_from_imm64 ty x) 1843 (provide (= result (extract 5 0 (bvand x (bvsub (int2bv 64 ty) #x0000000000000001))))) 1844 (require (bvult (bvand x (bvsub (int2bv 64 ty) #x0000000000000001)) #x0000000000000040))) 1845 1846(decl pure partial imm_shift_from_imm64 (Type Imm64) ImmShift) 1847(extern constructor imm_shift_from_imm64 imm_shift_from_imm64) 1848 1849(decl imm_shift_from_u8 (u8) ImmShift) 1850(extern constructor imm_shift_from_u8 imm_shift_from_u8) 1851 1852(spec (imm12_from_u64 imm12) 1853 (provide (= result (zero_ext 64 imm12))) 1854 (require 1855 ; REVIEW(mbm): correct formulation of imm12? 1856 (or 1857 (= imm12 (bvand imm12 #x000fff)) 1858 (= imm12 (bvand imm12 #xfff000)) 1859 ) 1860 ) 1861) 1862(decl imm12_from_u64 (Imm12) u64) 1863(extern extractor imm12_from_u64 imm12_from_u64) 1864 1865(decl u8_into_uimm5 (u8) UImm5) 1866(extern constructor u8_into_uimm5 u8_into_uimm5) 1867 1868(spec (u8_into_imm12 arg) 1869 (provide (= result (zero_ext 24 arg)))) 1870(decl u8_into_imm12 (u8) Imm12) 1871(extern constructor u8_into_imm12 u8_into_imm12) 1872 1873(spec (u64_into_imm_logic ty a) 1874 (provide (= result a)) 1875 (require (or (= ty 32) (= ty 64)))) 1876(decl u64_into_imm_logic (Type u64) ImmLogic) 1877(extern constructor u64_into_imm_logic u64_into_imm_logic) 1878 1879(decl branch_target (MachLabel) BranchTarget) 1880(extern constructor branch_target branch_target) 1881(convert MachLabel BranchTarget branch_target) 1882 1883(decl targets_jt_space (BoxVecMachLabel) CodeOffset) 1884(extern constructor targets_jt_space targets_jt_space) 1885 1886;; Calculate the minimum floating-point bound for a conversion to floating 1887;; point from an integer type. 1888;; Accepts whether the output is signed, the size of the input 1889;; floating point type in bits, and the size of the output integer type 1890;; in bits. 1891(decl min_fp_value (bool u8 u8) Reg) 1892(extern constructor min_fp_value min_fp_value) 1893 1894;; Calculate the maximum floating-point bound for a conversion to floating 1895;; point from an integer type. 1896;; Accepts whether the output is signed, the size of the input 1897;; floating point type in bits, and the size of the output integer type 1898;; in bits. 1899(decl max_fp_value (bool u8 u8) Reg) 1900(extern constructor max_fp_value max_fp_value) 1901 1902;; Constructs an FPUOpRI.Ushr* given the size in bits of the value (or lane) 1903;; and the amount to shift by. 1904(decl fpu_op_ri_ushr (u8 u8) FPUOpRI) 1905(extern constructor fpu_op_ri_ushr fpu_op_ri_ushr) 1906 1907;; Constructs an FPUOpRIMod.Sli* given the size in bits of the value (or lane) 1908;; and the amount to shift by. 1909(decl fpu_op_ri_sli (u8 u8) FPUOpRIMod) 1910(extern constructor fpu_op_ri_sli fpu_op_ri_sli) 1911 1912(decl pure partial lshr_from_u64 (Type u64) ShiftOpAndAmt) 1913(extern constructor lshr_from_u64 lshr_from_u64) 1914 1915(spec (lshl_from_imm64 ty a) 1916 (provide (= result (concat #x0e (extract 7 0 a)))) 1917 (require (= (extract 63 8 a) #b00000000000000000000000000000000000000000000000000000000))) 1918(decl pure partial lshl_from_imm64 (Type Imm64) ShiftOpAndAmt) 1919(extern constructor lshl_from_imm64 lshl_from_imm64) 1920 1921(decl pure partial lshl_from_u64 (Type u64) ShiftOpAndAmt) 1922(extern constructor lshl_from_u64 lshl_from_u64) 1923 1924(decl pure partial ashr_from_u64 (Type u64) ShiftOpAndAmt) 1925(extern constructor ashr_from_u64 ashr_from_u64) 1926 1927(decl integral_ty (Type) Type) 1928(extern extractor integral_ty integral_ty) 1929 1930(decl valid_atomic_transaction (Type) Type) 1931(extern extractor valid_atomic_transaction valid_atomic_transaction) 1932 1933(decl pure partial is_zero_simm9 (SImm9) Unit) 1934(extern constructor is_zero_simm9 is_zero_simm9) 1935 1936(decl pure partial is_zero_uimm12 (UImm12Scaled) Unit) 1937(extern constructor is_zero_uimm12 is_zero_uimm12) 1938 1939;; Helper to go directly from a `Value`, when it's an `iconst`, to an `Imm12`. 1940; REVIEW(mbm): is imm12_from_value spec correct? 1941; NOTE(mbm): compare with https://github.com/avanhatt/wasmtime/blob/94ccb9d4d55a479893cb04bc796ec620ed24cee2/cranelift/codegen/src/isa/aarch64/inst.isle#L1867-L1874 1942(spec (imm12_from_value imm12) 1943 (provide 1944 ; REVIEW(mbm): zero_ext vs conv_to? 1945 (= result (conv_to (widthof result) (zero_ext 64 imm12))) 1946 (= imm12 (conv_to (widthof imm12) (zero_ext 64 result))) 1947 ) 1948 (require 1949 ; REVIEW(mbm): correct formulation of imm12? 1950 (or 1951 (= imm12 (bvand imm12 #x000fff)) 1952 (= imm12 (bvand imm12 #xfff000)) 1953 ) 1954 ) 1955) 1956(decl imm12_from_value (Imm12) Value) 1957(extractor 1958 (imm12_from_value n) 1959 (iconst (u64_from_imm64 (imm12_from_u64 n)))) 1960;; Conceptually the same as `imm12_from_value`, but tries negating the constant 1961;; value (first sign-extending to handle narrow widths). 1962(spec (imm12_from_negated_value arg) 1963 (provide 1964 (= (bvneg (sign_ext 64 arg)) (zero_ext 64 result)) 1965 ) 1966 (require 1967 ; REVIEW(mbm): correct formulation of imm12? 1968 (or 1969 (= result (bvand result #x000fff)) 1970 (= result (bvand result #xfff000)) 1971 ) 1972 ) 1973) 1974 1975(instantiate imm12_from_negated_value 1976 ((args (bv 8)) (ret (bv 24)) (canon (bv 8))) 1977 ((args (bv 16)) (ret (bv 24)) (canon (bv 16))) 1978 ((args (bv 32)) (ret (bv 24)) (canon (bv 32))) 1979 ((args (bv 64)) (ret (bv 24)) (canon (bv 64))) 1980) 1981(decl pure partial imm12_from_negated_value (Value) Imm12) 1982(rule imm12_from_negated_value 1983 (imm12_from_negated_value (has_type ty (iconst n))) 1984 (if-let (imm12_from_u64 imm) (i64_cast_unsigned (i64_checked_neg (i64_sextend_imm64 ty n)))) 1985 imm) 1986 1987;; Helper type to represent a value and an extend operation fused together. 1988(model ExtendedValue (type (bv 67))) 1989(type ExtendedValue extern (enum)) 1990;; Only including the i8 to i32 opcodes, based on the impl of extended_value_from_value 1991(spec (extended_value_from_value x) 1992 (provide 1993 (switch (extract 66 64 x) 1994 ((ExtendOp.UXTB) (= (extract 63 0 x) (zero_ext 64 (extract 7 0 (zero_ext 64 result))))) 1995 ((ExtendOp.UXTH) (= (extract 63 0 x) (zero_ext 64 (extract 15 0 (zero_ext 64 result))))) 1996 ((ExtendOp.UXTW) (= (extract 63 0 x) (zero_ext 64 (extract 31 0 (zero_ext 64 result))))) 1997 ((ExtendOp.SXTB) (= (extract 63 0 x) (sign_ext 64 (extract 7 0 (zero_ext 64 result))))) 1998 ((ExtendOp.SXTH) (= (extract 63 0 x) (sign_ext 64 (extract 15 0 (zero_ext 64 result))))) 1999 ((ExtendOp.SXTW) (= (extract 63 0 x) (sign_ext 64 (extract 31 0 (zero_ext 64 result))))))) 2000 (require 2001 (bvult (extract 66 64 x) #b110) 2002 (not (= (extract 66 64 x) #b011)) 2003 (= result (conv_to (widthof result) x)) 2004 (or (= 8 (widthof result)) (= 16 (widthof result)) (= 32 (widthof result))))) 2005(decl extended_value_from_value (ExtendedValue) Value) 2006(extern extractor extended_value_from_value extended_value_from_value) 2007 2008;; Constructors used to poke at the fields of an `ExtendedValue`. 2009(decl put_extended_in_reg (ExtendedValue) Reg) 2010(extern constructor put_extended_in_reg put_extended_in_reg) 2011(decl get_extended_op (ExtendedValue) ExtendOp) 2012(extern constructor get_extended_op get_extended_op) 2013 2014(decl nzcv (bool bool bool bool) NZCV) 2015(extern constructor nzcv nzcv) 2016 2017(decl cond_br_zero (Reg OperandSize) CondBrKind) 2018(extern constructor cond_br_zero cond_br_zero) 2019 2020(decl cond_br_not_zero (Reg OperandSize) CondBrKind) 2021(extern constructor cond_br_not_zero cond_br_not_zero) 2022 2023(decl cond_br_cond (Cond) CondBrKind) 2024(extern constructor cond_br_cond cond_br_cond) 2025 2026;; Instruction creation helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2027 2028;; Helper for creating the zero register. 2029(spec (zero_reg) (provide (= result #x0000000000000000))) 2030(decl zero_reg () Reg) 2031(extern constructor zero_reg zero_reg) 2032 2033(decl fp_reg () Reg) 2034(extern constructor fp_reg fp_reg) 2035 2036(decl stack_reg () Reg) 2037(extern constructor stack_reg stack_reg) 2038 2039(decl writable_link_reg () WritableReg) 2040(extern constructor writable_link_reg writable_link_reg) 2041 2042(decl writable_zero_reg () WritableReg) 2043(extern constructor writable_zero_reg writable_zero_reg) 2044 2045(decl value_regs_zero () ValueRegs) 2046(rule (value_regs_zero) 2047 (value_regs 2048 (imm $I64 (ImmExtend.Zero) 0) 2049 (imm $I64 (ImmExtend.Zero) 0))) 2050 2051 2052;; Helper for emitting `MInst.Mov` instructions. 2053(decl mov (Reg Type) Reg) 2054(rule (mov src ty) 2055 (let ((dst WritableReg (temp_writable_reg $I64)) 2056 (_ Unit (emit (MInst.Mov (operand_size ty) dst src)))) 2057 dst)) 2058 2059;; Helper for emitting `MInst.MovZ` instructions. 2060(decl movz (MoveWideConst OperandSize) Reg) 2061(rule (movz imm size) 2062 (let ((dst WritableReg (temp_writable_reg $I64)) 2063 (_ Unit (emit (MInst.MovWide (MoveWideOp.MovZ) dst imm size)))) 2064 dst)) 2065 2066;; Helper for emitting `MInst.MovN` instructions. 2067(decl movn (MoveWideConst OperandSize) Reg) 2068(rule (movn imm size) 2069 (let ((dst WritableReg (temp_writable_reg $I64)) 2070 (_ Unit (emit (MInst.MovWide (MoveWideOp.MovN) dst imm size)))) 2071 dst)) 2072 2073;; Helper for emitting `MInst.AluRRImmLogic` instructions. 2074(decl alu_rr_imm_logic (ALUOp Type Reg ImmLogic) Reg) 2075(rule (alu_rr_imm_logic op ty src imm) 2076 (let ((dst WritableReg (temp_writable_reg $I64)) 2077 (_ Unit (emit (MInst.AluRRImmLogic op (operand_size ty) dst src imm)))) 2078 dst)) 2079 2080;; Helper for emitting `MInst.AluRRImmShift` instructions. 2081(spec (alu_rr_imm_shift op t a b) 2082 (provide 2083 (= result (switch op 2084 ((ALUOp.Lsr) 2085 (if (<= t 32) 2086 (conv_to 64 (bvlshr (extract 31 0 a) (bvand (bvsub (int2bv 32 32) #x00000001) (extract 31 0 (zero_ext 64 b))))) 2087 (bvlshr a (bvand (bvsub (int2bv 64 64) #x0000000000000001) (zero_ext 64 b))))) 2088 ((ALUOp.Asr) 2089 (if (<= t 32) 2090 (conv_to 64 (bvashr (extract 31 0 a) (bvand (bvsub (int2bv 32 32) #x00000001) (extract 31 0 (zero_ext 64 b))))) 2091 (bvashr a (bvand (bvsub (int2bv 64 64) #x0000000000000001) (zero_ext 64 b))))) 2092 ((ALUOp.Lsl) 2093 (if (<= t 32) 2094 (conv_to 64 (bvshl (extract 31 0 a) (bvand (bvsub (int2bv 32 32) #x00000001) (extract 31 0 (zero_ext 64 b))))) 2095 (bvshl a (bvand (bvsub (int2bv 64 64) #x0000000000000001) (zero_ext 64 b)))))))) 2096 (require 2097 (or (= op (ALUOp.Lsr)) (= op (ALUOp.Asr)) (= op (ALUOp.Lsl))) 2098 (or (= t 8) (= t 16) (= t 32) (= t 64)))) 2099(decl alu_rr_imm_shift (ALUOp Type Reg ImmShift) Reg) 2100(rule (alu_rr_imm_shift op ty src imm) 2101 (let ((dst WritableReg (temp_writable_reg $I64)) 2102 (_ Unit (emit (MInst.AluRRImmShift op (operand_size ty) dst src imm)))) 2103 dst)) 2104 2105;; Helper for emitting `MInst.AluRRR` instructions. 2106(spec (alu_rrr op t a b) 2107 (provide 2108 (= result (switch op 2109 ((ALUOp.Lsr) 2110 (if (<= t 32) 2111 (conv_to 64 (bvlshr (extract 31 0 a) (bvand (bvsub (int2bv 32 32) #x00000001) (extract 31 0 b)))) 2112 (bvlshr a (bvand (bvsub (int2bv 64 64) #x0000000000000001) b)))) 2113 ((ALUOp.Asr) 2114 (if (<= t 32) 2115 (conv_to 64 (bvashr (extract 31 0 a) (bvand (bvsub (int2bv 32 32) #x00000001) (extract 31 0 b)))) 2116 (bvashr a (bvand (bvsub (int2bv 64 64) #x0000000000000001) b)))) 2117 ((ALUOp.Lsl) 2118 (if (<= t 32) 2119 (conv_to 64 (bvshl (extract 31 0 a) (bvand (bvsub (int2bv 32 32) #x00000001) (extract 31 0 b)))) 2120 (bvshl a (bvand (bvsub (int2bv 64 64) #x0000000000000001) b))))))) 2121 (require 2122 (or (= op (ALUOp.Lsr)) (= op (ALUOp.Asr)) (= op (ALUOp.Lsl))) 2123 (or (= t 8) (= t 16) (= t 32) (= t 64)))) 2124(decl alu_rrr (ALUOp Type Reg Reg) Reg) 2125(rule (alu_rrr op ty src1 src2) 2126 (let ((dst WritableReg (temp_writable_reg $I64)) 2127 (_ Unit (emit (MInst.AluRRR op (operand_size ty) dst src1 src2)))) 2128 dst)) 2129 2130;; Helper for emitting `MInst.VecRRR` instructions. 2131(decl vec_rrr (VecALUOp Reg Reg VectorSize) Reg) 2132(rule (vec_rrr op src1 src2 size) 2133 (let ((dst WritableReg (temp_writable_reg $I8X16)) 2134 (_ Unit (emit (MInst.VecRRR op dst src1 src2 size)))) 2135 dst)) 2136 2137;; Helper for emitting `MInst.FpuRR` instructions. 2138(decl fpu_rr (FPUOp1 Reg ScalarSize) Reg) 2139(rule (fpu_rr op src size) 2140 (let ((dst WritableReg (temp_writable_reg $F64)) 2141 (_ Unit (emit (MInst.FpuRR op size dst src)))) 2142 dst)) 2143 2144;; Helper for emitting `MInst.VecRRRMod` instructions which use three registers, 2145;; one of which is both source and output. 2146(decl vec_rrr_mod (VecALUModOp Reg Reg Reg VectorSize) Reg) 2147(rule (vec_rrr_mod op src1 src2 src3 size) 2148 (let ((dst WritableReg (temp_writable_reg $I8X16)) 2149 (_1 Unit (emit (MInst.VecRRRMod op dst src1 src2 src3 size)))) 2150 dst)) 2151 2152;; Helper for emitting `MInst.VecFmlaElem` instructions which use three registers, 2153;; one of which is both source and output. 2154(decl vec_fmla_elem (VecALUModOp Reg Reg Reg VectorSize u8) Reg) 2155(rule (vec_fmla_elem op src1 src2 src3 size idx) 2156 (let ((dst WritableReg (temp_writable_reg $I8X16)) 2157 (_1 Unit (emit (MInst.VecFmlaElem op dst src1 src2 src3 size idx)))) 2158 dst)) 2159 2160(decl fpu_rri (FPUOpRI Reg) Reg) 2161(rule (fpu_rri op src) 2162 (let ((dst WritableReg (temp_writable_reg $F64)) 2163 (_ Unit (emit (MInst.FpuRRI op dst src)))) 2164 dst)) 2165 2166(decl fpu_rri_mod (FPUOpRIMod Reg Reg) Reg) 2167(rule (fpu_rri_mod op dst_src src) 2168 (let ((dst WritableReg (temp_writable_reg $F64)) 2169 (_ Unit (emit (MInst.FpuRRIMod op dst dst_src src)))) 2170 dst)) 2171 2172;; Helper for emitting `MInst.FpuRRR` instructions. 2173(decl fpu_rrr (FPUOp2 Reg Reg ScalarSize) Reg) 2174(rule (fpu_rrr op src1 src2 size) 2175 (let ((dst WritableReg (temp_writable_reg $F64)) 2176 (_ Unit (emit (MInst.FpuRRR op size dst src1 src2)))) 2177 dst)) 2178 2179;; Helper for emitting `MInst.FpuRRRR` instructions. 2180(decl fpu_rrrr (FPUOp3 ScalarSize Reg Reg Reg) Reg) 2181(rule (fpu_rrrr size op src1 src2 src3) 2182 (let ((dst WritableReg (temp_writable_reg $F64)) 2183 (_ Unit (emit (MInst.FpuRRRR size op dst src1 src2 src3)))) 2184 dst)) 2185 2186;; Helper for emitting `MInst.FpuCmp` instructions. 2187(decl fpu_cmp (ScalarSize Reg Reg) ProducesFlags) 2188(rule (fpu_cmp size rn rm) 2189 (ProducesFlags.ProducesFlagsSideEffect 2190 (MInst.FpuCmp size rn rm))) 2191 2192;; Helper for emitting `MInst.VecLanes` instructions. 2193(decl vec_lanes (VecLanesOp Reg VectorSize) Reg) 2194(rule (vec_lanes op src size) 2195 (let ((dst WritableReg (temp_writable_reg $I8X16)) 2196 (_ Unit (emit (MInst.VecLanes op dst src size)))) 2197 dst)) 2198 2199;; Helper for emitting `MInst.VecShiftImm` instructions. 2200(decl vec_shift_imm (VecShiftImmOp u8 Reg VectorSize) Reg) 2201(rule (vec_shift_imm op imm src size) 2202 (let ((dst WritableReg (temp_writable_reg $I8X16)) 2203 (_ Unit (emit (MInst.VecShiftImm op dst src size imm)))) 2204 dst)) 2205 2206;; Helper for emitting `MInst.VecDup` instructions. 2207(decl vec_dup (Reg VectorSize) Reg) 2208(rule (vec_dup src size) 2209 (let ((dst WritableReg (temp_writable_reg $I8X16)) 2210 (_ Unit (emit (MInst.VecDup dst src size)))) 2211 dst)) 2212 2213;; Helper for emitting `MInst.VecDupFromFpu` instructions. 2214(decl vec_dup_from_fpu (Reg VectorSize u8) Reg) 2215(rule (vec_dup_from_fpu src size lane) 2216 (let ((dst WritableReg (temp_writable_reg $I8X16)) 2217 (_ Unit (emit (MInst.VecDupFromFpu dst src size lane)))) 2218 dst)) 2219 2220;; Helper for emitting `MInst.VecDupImm` instructions. 2221(decl vec_dup_imm (ASIMDMovModImm bool VectorSize) Reg) 2222(rule (vec_dup_imm imm invert size) 2223 (let ((dst WritableReg (temp_writable_reg $I8X16)) 2224 (_ Unit (emit (MInst.VecDupImm dst imm invert size)))) 2225 dst)) 2226 2227;; Helper for emitting `MInst.AluRRImm12` instructions. 2228(decl alu_rr_imm12 (ALUOp Type Reg Imm12) Reg) 2229(rule (alu_rr_imm12 op ty src imm) 2230 (let ((dst WritableReg (temp_writable_reg $I64)) 2231 (_ Unit (emit (MInst.AluRRImm12 op (operand_size ty) dst src imm)))) 2232 dst)) 2233 2234;; Helper for emitting `MInst.AluRRRShift` instructions. 2235(decl alu_rrr_shift (ALUOp Type Reg Reg ShiftOpAndAmt) Reg) 2236(rule (alu_rrr_shift op ty src1 src2 shift) 2237 (let ((dst WritableReg (temp_writable_reg $I64)) 2238 (_ Unit (emit (MInst.AluRRRShift op (operand_size ty) dst src1 src2 shift)))) 2239 dst)) 2240 2241;; Helper for emitting `cmp` instructions, setting flags, with a right-shifted 2242;; second operand register. 2243(decl cmp_rr_shift (OperandSize Reg Reg u64) ProducesFlags) 2244(rule (cmp_rr_shift size src1 src2 shift_amount) 2245 (if-let shift (lshr_from_u64 $I64 shift_amount)) 2246 (ProducesFlags.ProducesFlagsSideEffect 2247 (MInst.AluRRRShift (ALUOp.SubS) size (writable_zero_reg) 2248 src1 src2 shift))) 2249 2250;; Helper for emitting `cmp` instructions, setting flags, with an arithmetic right-shifted 2251;; second operand register. 2252(decl cmp_rr_shift_asr (OperandSize Reg Reg u64) ProducesFlags) 2253(rule (cmp_rr_shift_asr size src1 src2 shift_amount) 2254 (if-let shift (ashr_from_u64 $I64 shift_amount)) 2255 (ProducesFlags.ProducesFlagsSideEffect 2256 (MInst.AluRRRShift (ALUOp.SubS) size (writable_zero_reg) 2257 src1 src2 shift))) 2258 2259;; Helper for emitting `MInst.AluRRRExtend` instructions. 2260(decl alu_rrr_extend (ALUOp Type Reg Reg ExtendOp) Reg) 2261(rule (alu_rrr_extend op ty src1 src2 extend) 2262 (let ((dst WritableReg (temp_writable_reg $I64)) 2263 (_ Unit (emit (MInst.AluRRRExtend op (operand_size ty) dst src1 src2 extend)))) 2264 dst)) 2265 2266;; Same as `alu_rrr_extend`, but takes an `ExtendedValue` packed "pair" instead 2267;; of a `Reg` and an `ExtendOp`. 2268(decl alu_rr_extend_reg (ALUOp Type Reg ExtendedValue) Reg) 2269(rule (alu_rr_extend_reg op ty src1 extended_reg) 2270 (let ((src2 Reg (put_extended_in_reg extended_reg)) 2271 (extend ExtendOp (get_extended_op extended_reg))) 2272 (alu_rrr_extend op ty src1 src2 extend))) 2273 2274;; Helper for emitting `MInst.AluRRRR` instructions. 2275(decl alu_rrrr (ALUOp3 Type Reg Reg Reg) Reg) 2276(rule (alu_rrrr op ty src1 src2 src3) 2277 (let ((dst WritableReg (temp_writable_reg $I64)) 2278 (_ Unit (emit (MInst.AluRRRR op (operand_size ty) dst src1 src2 src3)))) 2279 dst)) 2280 2281;; Helper for emitting paired `MInst.AluRRR` instructions 2282(decl alu_rrr_with_flags_paired (Type Reg Reg ALUOp) ProducesFlags) 2283(rule (alu_rrr_with_flags_paired ty src1 src2 alu_op) 2284 (let ((dst WritableReg (temp_writable_reg $I64))) 2285 (ProducesFlags.ProducesFlagsReturnsResultWithConsumer 2286 (MInst.AluRRR alu_op (operand_size ty) dst src1 src2) 2287 dst))) 2288 2289;; Should only be used for AdcS and SbcS 2290(decl alu_rrr_with_flags_chained (Type Reg Reg ALUOp) ConsumesAndProducesFlags) 2291(rule (alu_rrr_with_flags_chained ty src1 src2 alu_op) 2292 (let ((dst WritableReg (temp_writable_reg $I64))) 2293 (ConsumesAndProducesFlags.ReturnsReg 2294 (MInst.AluRRR alu_op (operand_size ty) dst src1 src2) 2295 dst))) 2296 2297;; Helper for emitting `MInst.BitRR` instructions. 2298(decl bit_rr (BitOp Type Reg) Reg) 2299(rule (bit_rr op ty src) 2300 (let ((dst WritableReg (temp_writable_reg $I64)) 2301 (_ Unit (emit (MInst.BitRR op (operand_size ty) dst src)))) 2302 dst)) 2303 2304;; Helper for emitting `adds` instructions. 2305(decl add_with_flags_paired (Type Reg Reg) ProducesFlags) 2306(rule (add_with_flags_paired ty src1 src2) 2307 (let ((dst WritableReg (temp_writable_reg $I64))) 2308 (ProducesFlags.ProducesFlagsReturnsResultWithConsumer 2309 (MInst.AluRRR (ALUOp.AddS) (operand_size ty) dst src1 src2) 2310 dst))) 2311 2312;; Helper for emitting `adc` instructions. 2313(decl adc_paired (Type Reg Reg) ConsumesFlags) 2314(rule (adc_paired ty src1 src2) 2315 (let ((dst WritableReg (temp_writable_reg $I64))) 2316 (ConsumesFlags.ConsumesFlagsReturnsResultWithProducer 2317 (MInst.AluRRR (ALUOp.Adc) (operand_size ty) dst src1 src2) 2318 dst))) 2319 2320;; Helper for emitting `subs` instructions. 2321(decl sub_with_flags_paired (Type Reg Reg) ProducesFlags) 2322(rule (sub_with_flags_paired ty src1 src2) 2323 (let ((dst WritableReg (temp_writable_reg $I64))) 2324 (ProducesFlags.ProducesFlagsReturnsResultWithConsumer 2325 (MInst.AluRRR (ALUOp.SubS) (operand_size ty) dst src1 src2) 2326 dst))) 2327 2328;; Helper for materializing a boolean value into a register from 2329;; flags. 2330(decl materialize_bool_result (Cond) ConsumesFlags) 2331(rule (materialize_bool_result cond) 2332 (let ((dst WritableReg (temp_writable_reg $I64))) 2333 (ConsumesFlags.ConsumesFlagsReturnsReg 2334 (MInst.CSet dst cond) 2335 dst))) 2336 2337(decl cmn_imm (OperandSize Reg Imm12) ProducesFlags) 2338(rule (cmn_imm size src1 src2) 2339 (ProducesFlags.ProducesFlagsSideEffect 2340 (MInst.AluRRImm12 (ALUOp.AddS) size (writable_zero_reg) 2341 src1 src2))) 2342 2343(spec (cmp ty x y) 2344 (provide (= result (subs ty x y))) 2345 (require 2346 (or (= ty 32) (= ty 64)))) 2347(decl cmp (OperandSize Reg Reg) ProducesFlags) 2348(rule (cmp size src1 src2) 2349 (ProducesFlags.ProducesFlagsSideEffect 2350 (MInst.AluRRR (ALUOp.SubS) size (writable_zero_reg) 2351 src1 src2))) 2352 2353(spec (cmp_imm ty x y) 2354 (provide (= result (subs ty x (zero_ext 64 y)))) 2355 (require (or (= ty 32) (= ty 64)))) 2356(decl cmp_imm (OperandSize Reg Imm12) ProducesFlags) 2357(rule (cmp_imm size src1 src2) 2358 (ProducesFlags.ProducesFlagsSideEffect 2359 (MInst.AluRRImm12 (ALUOp.SubS) size (writable_zero_reg) 2360 src1 src2))) 2361 2362(decl cmp64_imm (Reg Imm12) ProducesFlags) 2363(rule (cmp64_imm src1 src2) 2364 (cmp_imm (OperandSize.Size64) src1 src2)) 2365 2366(spec (cmp_extend ty x y extend) 2367 (provide 2368 (= result 2369 (subs ty x 2370 (switch extend 2371 ((ExtendOp.UXTB) (zero_ext 64 (extract 7 0 y))) 2372 ((ExtendOp.UXTH) (zero_ext 64 (extract 15 0 y))) 2373 ((ExtendOp.UXTW) (zero_ext 64 (extract 31 0 y))) 2374 ((ExtendOp.UXTX) (zero_ext 64 (extract 63 0 y))) 2375 ((ExtendOp.SXTB) (sign_ext 64 (extract 7 0 y))) 2376 ((ExtendOp.SXTH) (sign_ext 64 (extract 15 0 y))) 2377 ((ExtendOp.SXTW) (sign_ext 64 (extract 31 0 y))) 2378 ((ExtendOp.SXTX) (sign_ext 64 (extract 63 0 y))))))) 2379 (require (or (= ty 32) (= ty 64)))) 2380(decl cmp_extend (OperandSize Reg Reg ExtendOp) ProducesFlags) 2381(rule (cmp_extend size src1 src2 extend) 2382 (ProducesFlags.ProducesFlagsSideEffect 2383 (MInst.AluRRRExtend (ALUOp.SubS) size (writable_zero_reg) 2384 src1 src2 extend))) 2385 2386;; Helper for emitting `sbc` instructions. 2387(decl sbc_paired (Type Reg Reg) ConsumesFlags) 2388(rule (sbc_paired ty src1 src2) 2389 (let ((dst WritableReg (temp_writable_reg $I64))) 2390 (ConsumesFlags.ConsumesFlagsReturnsResultWithProducer 2391 (MInst.AluRRR (ALUOp.Sbc) (operand_size ty) dst src1 src2) 2392 dst))) 2393 2394;; Helper for emitting `MInst.VecMisc` instructions. 2395(decl vec_misc (VecMisc2 Reg VectorSize) Reg) 2396(rule (vec_misc op src size) 2397 (let ((dst WritableReg (temp_writable_reg $I8X16)) 2398 (_ Unit (emit (MInst.VecMisc op dst src size)))) 2399 dst)) 2400 2401;; Helper for emitting `MInst.VecTbl` instructions. 2402(decl vec_tbl (Reg Reg) Reg) 2403(rule (vec_tbl rn rm) 2404 (let ((dst WritableReg (temp_writable_reg $I8X16)) 2405 (_ Unit (emit (MInst.VecTbl dst rn rm)))) 2406 dst)) 2407 2408(decl vec_tbl_ext (Reg Reg Reg) Reg) 2409(rule (vec_tbl_ext ri rn rm) 2410 (let ((dst WritableReg (temp_writable_reg $I8X16)) 2411 (_ Unit (emit (MInst.VecTblExt dst ri rn rm)))) 2412 dst)) 2413 2414;; Helper for emitting `MInst.VecTbl2` instructions. 2415(decl vec_tbl2 (Reg Reg Reg Type) Reg) 2416(rule (vec_tbl2 rn rn2 rm ty) 2417 (let ( 2418 (dst WritableReg (temp_writable_reg $I8X16)) 2419 (_ Unit (emit (MInst.VecTbl2 dst rn rn2 rm))) 2420 ) 2421 dst)) 2422 2423;; Helper for emitting `MInst.VecTbl2Ext` instructions. 2424(decl vec_tbl2_ext (Reg Reg Reg Reg Type) Reg) 2425(rule (vec_tbl2_ext ri rn rn2 rm ty) 2426 (let ( 2427 (dst WritableReg (temp_writable_reg $I8X16)) 2428 (_ Unit (emit (MInst.VecTbl2Ext dst ri rn rn2 rm))) 2429 ) 2430 dst)) 2431 2432;; Helper for emitting `MInst.VecRRRLong` instructions. 2433(decl vec_rrr_long (VecRRRLongOp Reg Reg bool) Reg) 2434(rule (vec_rrr_long op src1 src2 high_half) 2435 (let ((dst WritableReg (temp_writable_reg $I8X16)) 2436 (_ Unit (emit (MInst.VecRRRLong op dst src1 src2 high_half)))) 2437 dst)) 2438 2439;; Helper for emitting `MInst.VecRRPairLong` instructions. 2440(decl vec_rr_pair_long (VecRRPairLongOp Reg) Reg) 2441(rule (vec_rr_pair_long op src) 2442 (let ((dst WritableReg (temp_writable_reg $I8X16)) 2443 (_ Unit (emit (MInst.VecRRPairLong op dst src)))) 2444 dst)) 2445 2446;; Helper for emitting `MInst.VecRRRLongMod` instructions. 2447(decl vec_rrrr_long (VecRRRLongModOp Reg Reg Reg bool) Reg) 2448(rule (vec_rrrr_long op src1 src2 src3 high_half) 2449 (let ((dst WritableReg (temp_writable_reg $I8X16)) 2450 (_ Unit (emit (MInst.VecRRRLongMod op dst src1 src2 src3 high_half)))) 2451 dst)) 2452 2453;; Helper for emitting `MInst.VecRRNarrow` instructions. 2454(decl vec_rr_narrow_low (VecRRNarrowOp Reg ScalarSize) Reg) 2455(rule (vec_rr_narrow_low op src size) 2456 (let ((dst WritableReg (temp_writable_reg $I8X16)) 2457 (_ Unit (emit (MInst.VecRRNarrowLow op dst src size)))) 2458 dst)) 2459 2460;; Helper for emitting `MInst.VecRRNarrow` instructions which update the 2461;; high half of the destination register. 2462(decl vec_rr_narrow_high (VecRRNarrowOp Reg Reg ScalarSize) Reg) 2463(rule (vec_rr_narrow_high op mod src size) 2464 (let ((dst WritableReg (temp_writable_reg $I8X16)) 2465 (_ Unit (emit (MInst.VecRRNarrowHigh op dst mod src size)))) 2466 dst)) 2467 2468;; Helper for emitting `MInst.VecRRLong` instructions. 2469(decl vec_rr_long (VecRRLongOp Reg bool) Reg) 2470(rule (vec_rr_long op src high_half) 2471 (let ((dst WritableReg (temp_writable_reg $I8X16)) 2472 (_ Unit (emit (MInst.VecRRLong op dst src high_half)))) 2473 dst)) 2474 2475;; Helper for emitting `MInst.FpuCSel16` / `MInst.FpuCSel32` / `MInst.FpuCSel64` 2476;; instructions. 2477;; 2478;; Recursion: may recurse once to downgrade from F16 to F32 when FP16 is not enabled. 2479(decl rec fpu_csel (Type Cond Reg Reg) ConsumesFlags) 2480(rule (fpu_csel $F16 cond if_true if_false) 2481 (fpu_csel $F32 cond if_true if_false)) 2482 2483(rule 1 (fpu_csel $F16 cond if_true if_false) 2484 (if-let true (use_fp16)) 2485 (let ((dst WritableReg (temp_writable_reg $F16))) 2486 (ConsumesFlags.ConsumesFlagsReturnsReg 2487 (MInst.FpuCSel16 dst if_true if_false cond) 2488 dst))) 2489 2490(rule (fpu_csel $F32 cond if_true if_false) 2491 (let ((dst WritableReg (temp_writable_reg $F32))) 2492 (ConsumesFlags.ConsumesFlagsReturnsReg 2493 (MInst.FpuCSel32 dst if_true if_false cond) 2494 dst))) 2495 2496(rule (fpu_csel $F64 cond if_true if_false) 2497 (let ((dst WritableReg (temp_writable_reg $F64))) 2498 (ConsumesFlags.ConsumesFlagsReturnsReg 2499 (MInst.FpuCSel64 dst if_true if_false cond) 2500 dst))) 2501 2502;; Helper for emitting `MInst.VecCSel` instructions. 2503(decl vec_csel (Cond Reg Reg) ConsumesFlags) 2504(rule (vec_csel cond if_true if_false) 2505 (let ((dst WritableReg (temp_writable_reg $I8X16))) 2506 (ConsumesFlags.ConsumesFlagsReturnsReg 2507 (MInst.VecCSel dst if_true if_false cond) 2508 dst))) 2509 2510;; Helper for emitting `MInst.FpuRound` instructions. 2511(decl fpu_round (FpuRoundMode Reg) Reg) 2512(rule (fpu_round op rn) 2513 (let ((dst WritableReg (temp_writable_reg $F64)) 2514 (_ Unit (emit (MInst.FpuRound op dst rn)))) 2515 dst)) 2516 2517;; Helper for emitting `MInst.FpuMove64` and `MInst.FpuMove128` instructions. 2518(decl fpu_move (Type Reg) Reg) 2519(rule (fpu_move _ src) 2520 (let ((dst WritableReg (temp_writable_reg $I8X16)) 2521 (_ Unit (emit (MInst.FpuMove128 dst src)))) 2522 dst)) 2523(rule 1 (fpu_move (fits_in_64 _) src) 2524 (let ((dst WritableReg (temp_writable_reg $F64)) 2525 (_ Unit (emit (MInst.FpuMove64 dst src)))) 2526 dst)) 2527 2528;; Helper for emitting `MInst.MovToFpu` instructions. 2529;; 2530;; Recursion: may recurse once to downgrade from F16 to F32 when FP16 is not enabled. 2531(spec (mov_to_fpu x s) 2532 (provide (= result (zero_ext 64 (conv_to s x))))) 2533(decl rec mov_to_fpu (Reg ScalarSize) Reg) 2534(rule (mov_to_fpu x size) 2535 (let ((dst WritableReg (temp_writable_reg $I8X16)) 2536 (_ Unit (emit (MInst.MovToFpu dst x size)))) 2537 dst)) 2538(rule 1 (mov_to_fpu x (ScalarSize.Size16)) 2539 (if-let false (use_fp16)) 2540 (mov_to_fpu x (ScalarSize.Size32))) 2541 2542;; Helper for emitting `MInst.FpuMoveFPImm` instructions. 2543(decl fpu_move_fp_imm (ASIMDFPModImm ScalarSize) Reg) 2544(rule (fpu_move_fp_imm imm size) 2545 (let ((dst WritableReg (temp_writable_reg $I8X16)) 2546 (_ Unit (emit (MInst.FpuMoveFPImm dst imm size)))) 2547 dst)) 2548 2549;; Helper for emitting `MInst.MovToVec` instructions. 2550(decl mov_to_vec (Reg Reg u8 VectorSize) Reg) 2551(rule (mov_to_vec src1 src2 lane size) 2552 (let ((dst WritableReg (temp_writable_reg $I8X16)) 2553 (_ Unit (emit (MInst.MovToVec dst src1 src2 lane size)))) 2554 dst)) 2555 2556;; Helper for emitting `MInst.VecMovElement` instructions. 2557(decl mov_vec_elem (Reg Reg u8 u8 VectorSize) Reg) 2558(rule (mov_vec_elem src1 src2 dst_idx src_idx size) 2559 (let ((dst WritableReg (temp_writable_reg $I8X16)) 2560 (_ Unit (emit (MInst.VecMovElement dst src1 src2 dst_idx src_idx size)))) 2561 dst)) 2562 2563;; Helper for emitting `MInst.MovFromVec` instructions. 2564(spec (mov_from_vec x i s) 2565 (provide 2566 (= result 2567 (switch s 2568 (8 2569 (switch i 2570 (#x00 (zero_ext 64 (extract 7 0 x))) 2571 (#x01 (zero_ext 64 (extract 15 8 x))) 2572 (#x02 (zero_ext 64 (extract 23 16 x))) 2573 (#x03 (zero_ext 64 (extract 31 24 x))) 2574 (#x04 (zero_ext 64 (extract 39 32 x))) 2575 (#x05 (zero_ext 64 (extract 47 40 x))) 2576 (#x06 (zero_ext 64 (extract 55 48 x))) 2577 (#x07 (zero_ext 64 (extract 63 56 x))))) 2578 (16 2579 (switch i 2580 (#x00 (zero_ext 64 (extract 15 0 x))) 2581 (#x01 (zero_ext 64 (extract 31 16 x))) 2582 (#x03 (zero_ext 64 (extract 47 32 x))) 2583 (#x04 (zero_ext 64 (extract 63 48 x))))) 2584 (32 2585 (switch i 2586 (#x00 (zero_ext 64 (extract 31 0 x))) 2587 (#x01 (zero_ext 64 (extract 63 32 x))))))))) 2588(decl mov_from_vec (Reg u8 ScalarSize) Reg) 2589(rule (mov_from_vec rn idx size) 2590 (let ((dst WritableReg (temp_writable_reg $I64)) 2591 (_ Unit (emit (MInst.MovFromVec dst rn idx size)))) 2592 dst)) 2593 2594;; Helper for emitting `MInst.MovFromVecSigned` instructions. 2595(decl mov_from_vec_signed (Reg u8 VectorSize OperandSize) Reg) 2596(rule (mov_from_vec_signed rn idx size scalar_size) 2597 (let ((dst WritableReg (temp_writable_reg $I64)) 2598 (_ Unit (emit (MInst.MovFromVecSigned dst rn idx size scalar_size)))) 2599 dst)) 2600 2601(decl fpu_move_from_vec (Reg u8 VectorSize) Reg) 2602(rule (fpu_move_from_vec rn idx size) 2603 (let ((dst WritableReg (temp_writable_reg $I8X16)) 2604 (_ Unit (emit (MInst.FpuMoveFromVec dst rn idx size)))) 2605 dst)) 2606 2607;; Helper for emitting `MInst.Extend` instructions. 2608(spec (extend a b c d) 2609 (provide 2610 (if b 2611 (= result (sign_ext (bv2int d) (conv_to (bv2int c) a))) 2612 (= result (zero_ext (bv2int d) (conv_to (bv2int c) a)))))) 2613(decl extend (Reg bool u8 u8) Reg) 2614(rule (extend rn signed from_bits to_bits) 2615 (let ((dst WritableReg (temp_writable_reg $I64)) 2616 (_ Unit (emit (MInst.Extend dst rn signed from_bits to_bits)))) 2617 dst)) 2618 2619;; Helper for emitting `MInst.FpuExtend` instructions. 2620(decl fpu_extend (Reg ScalarSize) Reg) 2621(rule (fpu_extend src size) 2622 (let ((dst WritableReg (temp_writable_reg $F32X4)) 2623 (_ Unit (emit (MInst.FpuExtend dst src size)))) 2624 dst)) 2625 2626;; Helper for emitting `MInst.VecExtend` instructions. 2627(decl vec_extend (VecExtendOp Reg bool ScalarSize) Reg) 2628(rule (vec_extend op src high_half size) 2629 (let ((dst WritableReg (temp_writable_reg $I8X16)) 2630 (_ Unit (emit (MInst.VecExtend op dst src high_half size)))) 2631 dst)) 2632 2633;; Helper for emitting `MInst.VecExtract` instructions. 2634(decl vec_extract (Reg Reg u8) Reg) 2635(rule (vec_extract src1 src2 idx) 2636 (let ((dst WritableReg (temp_writable_reg $I8X16)) 2637 (_ Unit (emit (MInst.VecExtract dst src1 src2 idx)))) 2638 dst)) 2639 2640;; Helper for emitting `MInst.LoadAcquire` instructions. 2641(decl load_acquire (Type MemFlags Reg) Reg) 2642(rule (load_acquire ty flags addr) 2643 (let ((dst WritableReg (temp_writable_reg $I64)) 2644 (_ Unit (emit (MInst.LoadAcquire ty dst addr flags)))) 2645 dst)) 2646 2647;; Helper for emitting `MInst.StoreRelease` instructions. 2648(decl store_release (Type MemFlags Reg Reg) SideEffectNoResult) 2649(rule (store_release ty flags src addr) 2650 (SideEffectNoResult.Inst (MInst.StoreRelease ty src addr flags))) 2651 2652;; Helper for generating a `tst` instruction. 2653;; 2654;; Produces a `ProducesFlags` rather than a register or emitted instruction 2655;; which must be paired with `with_flags*` helpers. 2656(decl tst_imm (Type Reg ImmLogic) ProducesFlags) 2657(rule (tst_imm ty reg imm) 2658 (ProducesFlags.ProducesFlagsSideEffect 2659 (MInst.AluRRImmLogic (ALUOp.AndS) 2660 (operand_size ty) 2661 (writable_zero_reg) 2662 reg 2663 imm))) 2664 2665;; Helper for generating a `CSel` instruction. 2666;; 2667;; Note that this doesn't actually emit anything, instead it produces a 2668;; `ConsumesFlags` instruction which must be consumed with `with_flags*` 2669;; helpers. 2670(decl csel (Cond Reg Reg) ConsumesFlags) 2671(rule (csel cond if_true if_false) 2672 (let ((dst WritableReg (temp_writable_reg $I64))) 2673 (ConsumesFlags.ConsumesFlagsReturnsReg 2674 (MInst.CSel dst cond if_true if_false) 2675 dst))) 2676 2677;; Helper for constructing `cset` instructions. 2678(decl cset (Cond) ConsumesFlags) 2679(rule (cset cond) 2680 (let ((dst WritableReg (temp_writable_reg $I64))) 2681 (ConsumesFlags.ConsumesFlagsReturnsReg (MInst.CSet dst cond) dst))) 2682 2683;; Helper for constructing `cset` instructions, when the flags producer will 2684;; also return a value. 2685(decl cset_paired (Cond) ConsumesFlags) 2686(rule (cset_paired cond) 2687 (let ((dst WritableReg (temp_writable_reg $I64))) 2688 (ConsumesFlags.ConsumesFlagsReturnsResultWithProducer (MInst.CSet dst cond) dst))) 2689 2690;; Helper for constructing `csetm` instructions. 2691(decl csetm (Cond) ConsumesFlags) 2692(rule (csetm cond) 2693 (let ((dst WritableReg (temp_writable_reg $I64))) 2694 (ConsumesFlags.ConsumesFlagsReturnsReg (MInst.CSetm dst cond) dst))) 2695 2696;; Helper for generating a `CSNeg` instruction. 2697;; 2698;; Note that this doesn't actually emit anything, instead it produces a 2699;; `ConsumesFlags` instruction which must be consumed with `with_flags*` 2700;; helpers. 2701(decl csneg (Cond Reg Reg) ConsumesFlags) 2702(rule (csneg cond if_true if_false) 2703 (let ((dst WritableReg (temp_writable_reg $I64))) 2704 (ConsumesFlags.ConsumesFlagsReturnsReg 2705 (MInst.CSNeg dst cond if_true if_false) 2706 dst))) 2707 2708;; Helper for generating `MInst.CCmp` instructions. 2709;; Creates a new `ProducesFlags` from the supplied `ProducesFlags` followed 2710;; immediately by the `MInst.CCmp` instruction. 2711(decl ccmp (OperandSize Reg Reg NZCV Cond ProducesFlags) ProducesFlags) 2712(rule (ccmp size rn rm nzcv cond inst_input) 2713 (produces_flags_concat inst_input (ProducesFlags.ProducesFlagsSideEffect (MInst.CCmp size rn rm nzcv cond)))) 2714 2715;; Helper for generating `MInst.CCmpImm` instructions. 2716(decl ccmp_imm (OperandSize Reg UImm5 NZCV Cond) ConsumesFlags) 2717(rule 1 (ccmp_imm size rn imm nzcv cond) 2718 (let ((dst WritableReg (temp_writable_reg $I64))) 2719 (ConsumesFlags.ConsumesFlagsTwiceReturnsValueRegs 2720 (MInst.CCmpImm size rn imm nzcv cond) 2721 (MInst.CSet dst cond) 2722 (value_reg dst)))) 2723 2724;; Helpers for generating `add` instructions. 2725(spec (add ty a b) 2726 (provide 2727 (= result 2728 (if (<= ty 32) 2729 (conv_to 64 (bvadd (extract 31 0 a) (extract 31 0 b))) 2730 (bvadd a b))))) 2731(decl add (Type Reg Reg) Reg) 2732(rule (add ty x y) (alu_rrr (ALUOp.Add) ty x y)) 2733 2734(spec (add_imm ty a b) 2735 (provide 2736 (= result 2737 (if (<= ty 32) 2738 (conv_to 64 (bvadd (extract 31 0 a) (zero_ext 32 b))) 2739 (bvadd a (zero_ext 64 b))))) 2740 (require 2741 (or 2742 (= b (bvand b #x000fff)) 2743 (= b (bvand b #xfff000))))) 2744(decl add_imm (Type Reg Imm12) Reg) 2745(rule (add_imm ty x y) (alu_rr_imm12 (ALUOp.Add) ty x y)) 2746 2747(spec (add_extend ty x y) 2748 (provide 2749 (= result 2750 (if (<= ty 32) 2751 (conv_to 64 (bvadd (extract 31 0 x) 2752 (switch (extract 66 64 y) 2753 ((ExtendOp.UXTB) (zero_ext 32 (extract 7 0 y))) 2754 ((ExtendOp.UXTH) (zero_ext 32 (extract 15 0 y))) 2755 ((ExtendOp.UXTW) (zero_ext 32 (extract 31 0 y))) 2756 ((ExtendOp.UXTX) (zero_ext 32 (extract 31 0 y))) 2757 ((ExtendOp.SXTB) (sign_ext 32 (extract 7 0 y))) 2758 ((ExtendOp.SXTH) (sign_ext 32 (extract 15 0 y))) 2759 ((ExtendOp.SXTW) (sign_ext 32 (extract 31 0 y))) 2760 ((ExtendOp.SXTX) (sign_ext 32 (extract 31 0 y)))))) 2761 (bvadd x 2762 (switch (extract 66 64 y) 2763 ((ExtendOp.UXTB) (zero_ext 64 (extract 7 0 y))) 2764 ((ExtendOp.UXTH) (zero_ext 64 (extract 15 0 y))) 2765 ((ExtendOp.UXTW) (zero_ext 64 (extract 31 0 y))) 2766 ((ExtendOp.UXTX) (zero_ext 64 (extract 63 0 y))) 2767 ((ExtendOp.SXTB) (sign_ext 64 (extract 7 0 y))) 2768 ((ExtendOp.SXTH) (sign_ext 64 (extract 15 0 y))) 2769 ((ExtendOp.SXTW) (sign_ext 64 (extract 31 0 y))) 2770 ((ExtendOp.SXTX) (sign_ext 64 (extract 63 0 y))))))))) 2771(decl add_extend (Type Reg ExtendedValue) Reg) 2772(rule (add_extend ty x y) (alu_rr_extend_reg (ALUOp.Add) ty x y)) 2773 2774(decl add_extend_op (Type Reg Reg ExtendOp) Reg) 2775(rule (add_extend_op ty x y extend) (alu_rrr_extend (ALUOp.Add) ty x y extend)) 2776 2777(spec (add_shift ty a b shift) 2778 (provide 2779 (= result (if (<= ty 32) 2780 (conv_to 64 (bvadd (extract 31 0 a) 2781 (switch (extract 15 8 shift) 2782 ((ALUOp.Lsl) (bvshl (extract 31 0 b) (zero_ext 32 (bvand (bvsub (int2bv 8 ty) #x01) (extract 7 0 shift))))) 2783 ((ALUOp.Lsr) (bvlshr (extract 31 0 b) (zero_ext 32 (bvand (bvsub (int2bv 8 ty) #x01) (extract 7 0 shift))))) 2784 ((ALUOp.Asr) (bvashr (extract 31 0 b) (zero_ext 32 (bvand (bvsub (int2bv 8 ty) #x01) (extract 7 0 shift)))))))) 2785 (bvadd a 2786 (switch (extract 15 8 shift) 2787 ((ALUOp.Lsl) (bvshl b (zero_ext 64 (bvand (bvsub (int2bv 8 ty) #x01) (extract 7 0 shift))))) 2788 ((ALUOp.Lsr) (bvlshr b (zero_ext 64 (bvand (bvsub (int2bv 8 ty) #x01) (extract 7 0 shift))))) 2789 ((ALUOp.Asr) (bvashr b (zero_ext 64 (bvand (bvsub (int2bv 8 ty) #x01) (extract 7 0 shift))))))))))) 2790(decl add_shift (Type Reg Reg ShiftOpAndAmt) Reg) 2791(rule (add_shift ty x y z) (alu_rrr_shift (ALUOp.Add) ty x y z)) 2792 2793(decl add_vec (Reg Reg VectorSize) Reg) 2794(rule (add_vec x y size) (vec_rrr (VecALUOp.Add) x y size)) 2795 2796;; Helpers for generating `sub` instructions. 2797(spec (sub ty a b) 2798 (provide 2799 (= result 2800 (if (<= ty 32) 2801 (conv_to 64 (bvsub (extract 31 0 a) (extract 31 0 b))) 2802 (bvsub a b))))) 2803(decl sub (Type Reg Reg) Reg) 2804(rule (sub ty x y) (alu_rrr (ALUOp.Sub) ty x y)) 2805 2806(spec (sub_imm ty a b) 2807 (provide 2808 (= result 2809 (if (<= ty 32) 2810 (conv_to 64 (bvsub (extract 31 0 a) (zero_ext 32 b))) 2811 (bvsub a (zero_ext 64 b))))) 2812 (require 2813 (or 2814 (= b (bvand b #x000fff)) 2815 (= b (bvand b #xfff000))))) 2816(decl sub_imm (Type Reg Imm12) Reg) 2817(rule (sub_imm ty x y) (alu_rr_imm12 (ALUOp.Sub) ty x y)) 2818 2819(spec (sub_extend ty x y) 2820 (provide 2821 (= result 2822 (if (<= ty 32) 2823 (conv_to 64 (bvsub (extract 31 0 x) 2824 (switch (extract 66 64 y) 2825 ((ExtendOp.UXTB) (zero_ext 32 (extract 7 0 y))) 2826 ((ExtendOp.UXTH) (zero_ext 32 (extract 15 0 y))) 2827 ((ExtendOp.UXTW) (zero_ext 32 (extract 31 0 y))) 2828 ((ExtendOp.UXTX) (zero_ext 32 (extract 31 0 y))) 2829 ((ExtendOp.SXTB) (sign_ext 32 (extract 7 0 y))) 2830 ((ExtendOp.SXTH) (sign_ext 32 (extract 15 0 y))) 2831 ((ExtendOp.SXTW) (sign_ext 32 (extract 31 0 y))) 2832 ((ExtendOp.SXTX) (sign_ext 32 (extract 31 0 y)))))) 2833 (bvsub x 2834 (switch (extract 66 64 y) 2835 ((ExtendOp.UXTB) (zero_ext 64 (extract 7 0 y))) 2836 ((ExtendOp.UXTH) (zero_ext 64 (extract 15 0 y))) 2837 ((ExtendOp.UXTW) (zero_ext 64 (extract 31 0 y))) 2838 ((ExtendOp.UXTX) (zero_ext 64 (extract 63 0 y))) 2839 ((ExtendOp.SXTB) (sign_ext 64 (extract 7 0 y))) 2840 ((ExtendOp.SXTH) (sign_ext 64 (extract 15 0 y))) 2841 ((ExtendOp.SXTW) (sign_ext 64 (extract 31 0 y))) 2842 ((ExtendOp.SXTX) (sign_ext 64 (extract 63 0 y))))))))) 2843(decl sub_extend (Type Reg ExtendedValue) Reg) 2844(rule (sub_extend ty x y) (alu_rr_extend_reg (ALUOp.Sub) ty x y)) 2845 2846(spec (sub_shift ty a b shift) 2847 (provide 2848 (= result (if (<= ty 32) 2849 (conv_to 64 (bvsub (extract 31 0 a) (switch (extract 15 8 shift) 2850 ((ALUOp.Lsl) (bvshl (extract 31 0 b) (zero_ext 32 (bvand (bvsub (int2bv 8 ty) #x01) (extract 7 0 shift))))) 2851 ((ALUOp.Lsr) (bvlshr (extract 31 0 b) (zero_ext 32 (bvand (bvsub (int2bv 8 ty) #x01) (extract 7 0 shift))))) 2852 ((ALUOp.Asr) (bvashr (extract 31 0 b) (zero_ext 32 (bvand (bvsub (int2bv 8 ty) #x01) (extract 7 0 shift)))))))) 2853 (bvsub a (switch (extract 15 8 shift) 2854 ((ALUOp.Lsl) (bvshl b (zero_ext 64 (bvand (bvsub (int2bv 8 ty) #x01) (extract 7 0 shift))))) 2855 ((ALUOp.Lsr) (bvlshr b (zero_ext 64 (bvand (bvsub (int2bv 8 ty) #x01) (extract 7 0 shift))))) 2856 ((ALUOp.Asr) (bvashr b (zero_ext 64 (bvand (bvsub (int2bv 8 ty) #x01) (extract 7 0 shift))))))))))) 2857(decl sub_shift (Type Reg Reg ShiftOpAndAmt) Reg) 2858(rule (sub_shift ty x y z) (alu_rrr_shift (ALUOp.Sub) ty x y z)) 2859 2860(decl sub_vec (Reg Reg VectorSize) Reg) 2861(rule (sub_vec x y size) (vec_rrr (VecALUOp.Sub) x y size)) 2862 2863(decl sub_i128 (ValueRegs ValueRegs) ValueRegs) 2864(rule (sub_i128 x y) 2865 (let 2866 ;; Get the high/low registers for `x`. 2867 ((x_regs ValueRegs x) 2868 (x_lo Reg (value_regs_get x_regs 0)) 2869 (x_hi Reg (value_regs_get x_regs 1)) 2870 2871 ;; Get the high/low registers for `y`. 2872 (y_regs ValueRegs y) 2873 (y_lo Reg (value_regs_get y_regs 0)) 2874 (y_hi Reg (value_regs_get y_regs 1))) 2875 ;; the actual subtraction is `subs` followed by `sbc` which comprises 2876 ;; the low/high bits of the result 2877 (with_flags 2878 (sub_with_flags_paired $I64 x_lo y_lo) 2879 (sbc_paired $I64 x_hi y_hi)))) 2880 2881;; Helpers for generating `madd` instructions. 2882(spec (madd ty a b c) 2883 (provide 2884 (= result 2885 (if (<= ty 32) 2886 (conv_to 64 (bvadd (extract 31 0 c) (bvmul (extract 31 0 a) (extract 31 0 b)))) 2887 (bvadd c (bvmul a b)))))) 2888(decl madd (Type Reg Reg Reg) Reg) 2889(rule (madd ty x y z) (alu_rrrr (ALUOp3.MAdd) ty x y z)) 2890 2891;; Helpers for generating `msub` instructions. 2892(spec (msub ty a b c) 2893 (provide 2894 (= result 2895 (if (<= ty 32) 2896 (conv_to 64 (bvsub (extract 31 0 c) (bvmul (extract 31 0 a) (extract 31 0 b)))) 2897 (bvsub c (bvmul a b)))))) 2898(decl msub (Type Reg Reg Reg) Reg) 2899(rule (msub ty x y z) (alu_rrrr (ALUOp3.MSub) ty x y z)) 2900 2901;; Helpers for generating `umaddl` instructions 2902(decl umaddl (Reg Reg Reg) Reg) 2903(rule (umaddl x y z) (alu_rrrr (ALUOp3.UMAddL) $I32 x y z)) 2904 2905;; Helpers for generating `smaddl` instructions 2906(decl smaddl (Reg Reg Reg) Reg) 2907(rule (smaddl x y z) (alu_rrrr (ALUOp3.SMAddL) $I32 x y z)) 2908 2909;; Helper for generating `uqadd` instructions. 2910(decl uqadd (Reg Reg VectorSize) Reg) 2911(rule (uqadd x y size) (vec_rrr (VecALUOp.Uqadd) x y size)) 2912 2913;; Helper for generating `sqadd` instructions. 2914(decl sqadd (Reg Reg VectorSize) Reg) 2915(rule (sqadd x y size) (vec_rrr (VecALUOp.Sqadd) x y size)) 2916 2917;; Helper for generating `uqsub` instructions. 2918(decl uqsub (Reg Reg VectorSize) Reg) 2919(rule (uqsub x y size) (vec_rrr (VecALUOp.Uqsub) x y size)) 2920 2921;; Helper for generating `sqsub` instructions. 2922(decl sqsub (Reg Reg VectorSize) Reg) 2923(rule (sqsub x y size) (vec_rrr (VecALUOp.Sqsub) x y size)) 2924 2925;; Helper for generating `umulh` instructions. 2926(decl umulh (Type Reg Reg) Reg) 2927(rule (umulh ty x y) (alu_rrr (ALUOp.UMulH) ty x y)) 2928 2929;; Helper for generating `smulh` instructions. 2930(decl smulh (Type Reg Reg) Reg) 2931(rule (smulh ty x y) (alu_rrr (ALUOp.SMulH) ty x y)) 2932 2933;; Helper for generating `mul` instructions. 2934(decl mul (Reg Reg VectorSize) Reg) 2935(rule (mul x y size) (vec_rrr (VecALUOp.Mul) x y size)) 2936 2937;; Helper for generating `neg` instructions. 2938(decl neg (Reg VectorSize) Reg) 2939(rule (neg x size) (vec_misc (VecMisc2.Neg) x size)) 2940 2941;; Helper for generating `rev16` instructions. 2942(decl rev16 (Reg VectorSize) Reg) 2943(rule (rev16 x size) (vec_misc (VecMisc2.Rev16) x size)) 2944 2945;; Helper for generating `rev32` instructions. 2946(decl rev32 (Reg VectorSize) Reg) 2947(rule (rev32 x size) (vec_misc (VecMisc2.Rev32) x size)) 2948 2949;; Helper for generating `rev64` instructions. 2950(decl rev64 (Reg VectorSize) Reg) 2951(rule (rev64 x size) (vec_misc (VecMisc2.Rev64) x size)) 2952 2953;; Helper for generating `xtn` instructions. 2954(decl xtn (Reg ScalarSize) Reg) 2955(rule (xtn x size) (vec_rr_narrow_low (VecRRNarrowOp.Xtn) x size)) 2956 2957;; Helper for generating `fcvtn` instructions. 2958(decl fcvtn (Reg ScalarSize) Reg) 2959(rule (fcvtn x size) (vec_rr_narrow_low (VecRRNarrowOp.Fcvtn) x size)) 2960 2961;; Helper for generating `sqxtn` instructions. 2962(decl sqxtn (Reg ScalarSize) Reg) 2963(rule (sqxtn x size) (vec_rr_narrow_low (VecRRNarrowOp.Sqxtn) x size)) 2964 2965;; Helper for generating `sqxtn2` instructions. 2966(decl sqxtn2 (Reg Reg ScalarSize) Reg) 2967(rule (sqxtn2 x y size) (vec_rr_narrow_high (VecRRNarrowOp.Sqxtn) x y size)) 2968 2969;; Helper for generating `sqxtun` instructions. 2970(decl sqxtun (Reg ScalarSize) Reg) 2971(rule (sqxtun x size) (vec_rr_narrow_low (VecRRNarrowOp.Sqxtun) x size)) 2972 2973;; Helper for generating `sqxtun2` instructions. 2974(decl sqxtun2 (Reg Reg ScalarSize) Reg) 2975(rule (sqxtun2 x y size) (vec_rr_narrow_high (VecRRNarrowOp.Sqxtun) x y size)) 2976 2977;; Helper for generating `uqxtn` instructions. 2978(decl uqxtn (Reg ScalarSize) Reg) 2979(rule (uqxtn x size) (vec_rr_narrow_low (VecRRNarrowOp.Uqxtn) x size)) 2980 2981;; Helper for generating `uqxtn2` instructions. 2982(decl uqxtn2 (Reg Reg ScalarSize) Reg) 2983(rule (uqxtn2 x y size) (vec_rr_narrow_high (VecRRNarrowOp.Uqxtn) x y size)) 2984 2985;; Helper for generating `fence` instructions. 2986(decl aarch64_fence () SideEffectNoResult) 2987(rule (aarch64_fence) 2988 (SideEffectNoResult.Inst (MInst.Fence))) 2989 2990;; Helper for generating `csdb` instructions. 2991(decl csdb () SideEffectNoResult) 2992(rule (csdb) 2993 (SideEffectNoResult.Inst (MInst.Csdb))) 2994 2995;; Helper for generating `brk` instructions, hinted as being debug traps. 2996(decl brk () SideEffectNoResult) 2997(rule (brk) 2998 (SideEffectNoResult.Inst (MInst.Brk))) 2999 3000;; Helper for generating `addp` instructions. 3001(spec (addp x y s) 3002 (provide 3003 (= result 3004 (switch s 3005 (#x00 (concat 3006 (bvadd (extract 55 48 x) (extract 63 56 x)) 3007 (bvadd (extract 39 32 x) (extract 47 40 x)) 3008 (bvadd (extract 23 16 x) (extract 31 24 x)) 3009 (bvadd (extract 7 0 x) (extract 15 8 x)) 3010 (bvadd (extract 55 48 y) (extract 63 56 y)) 3011 (bvadd (extract 39 32 y) (extract 47 40 y)) 3012 (bvadd (extract 23 16 y) (extract 31 24 y)) 3013 (bvadd (extract 7 0 y) (extract 15 8 y)))) 3014 (#x01 (concat 3015 (bvadd (extract 47 32 x) (extract 63 48 x)) 3016 (bvadd (extract 15 0 x) (extract 31 16 x)) 3017 (bvadd (extract 47 32 y) (extract 63 48 y)) 3018 (bvadd (extract 15 0 y) (extract 31 16 y)))) 3019 (#x02 (concat 3020 (bvadd (extract 31 0 x) (extract 63 32 x)) 3021 (bvadd (extract 31 0 y) (extract 63 32 y))))))) 3022 (require (or (= s #x00) (= s #x01) (= s #x02)))) 3023(decl addp (Reg Reg VectorSize) Reg) 3024(rule (addp x y size) (vec_rrr (VecALUOp.Addp) x y size)) 3025 3026;; Helper for generating `zip1` instructions. 3027(decl zip1 (Reg Reg VectorSize) Reg) 3028(rule (zip1 x y size) (vec_rrr (VecALUOp.Zip1) x y size)) 3029 3030;; Helper for generating vector `abs` instructions. 3031(decl vec_abs (Reg VectorSize) Reg) 3032(rule (vec_abs x size) (vec_misc (VecMisc2.Abs) x size)) 3033 3034;; Helper for generating instruction sequences to calculate a scalar absolute 3035;; value. 3036(spec (abs s x) 3037 (provide 3038 (= result 3039 (if (= s 32) 3040 (conv_to 64 3041 (if (bvsge (extract 31 0 x) #x00000000) 3042 (extract 31 0 x) 3043 (bvneg (extract 31 0 x)))) 3044 (if (bvsge x #x0000000000000000) x (bvneg x))))) 3045 (require (or (= s 32) (= s 64)))) 3046(decl abs (OperandSize Reg) Reg) 3047(rule (abs size x) 3048 (value_regs_get (with_flags (cmp_imm size x (u8_into_imm12 0)) 3049 (csneg (Cond.Gt) x x)) 0)) 3050 3051;; Helper for generating `addv` instructions. 3052(spec (addv x s) 3053 (provide 3054 (= result 3055 (switch s 3056 (#x00 (zero_ext 64 3057 (bvadd (extract 7 0 x) 3058 (bvadd (extract 15 8 x) 3059 (bvadd (extract 23 16 x) 3060 (bvadd (extract 31 24 x) 3061 (bvadd (extract 39 32 x) 3062 (bvadd (extract 47 40 x) 3063 (bvadd (extract 55 48 x) 3064 (extract 63 56 x)))))))))) 3065 (#x01 (zero_ext 64 3066 (bvadd (extract 15 0 x) 3067 (bvadd (extract 31 16 x) 3068 (bvadd (extract 47 32 x) 3069 (extract 63 48 x)))))) 3070 (#x02 (zero_ext 64 3071 (bvadd (extract 31 0 x) 3072 (extract 63 32 x))))))) 3073 (require (or (= s #x00) (or (= s #x01) (= s #x02))))) 3074(decl addv (Reg VectorSize) Reg) 3075(rule (addv x size) (vec_lanes (VecLanesOp.Addv) x size)) 3076 3077;; Helper for generating `shll32` instructions. 3078(decl shll32 (Reg bool) Reg) 3079(rule (shll32 x high_half) (vec_rr_long (VecRRLongOp.Shll32) x high_half)) 3080 3081;; Helpers for generating `addlp` instructions. 3082 3083(decl saddlp8 (Reg) Reg) 3084(rule (saddlp8 x) (vec_rr_pair_long (VecRRPairLongOp.Saddlp8) x)) 3085 3086(decl saddlp16 (Reg) Reg) 3087(rule (saddlp16 x) (vec_rr_pair_long (VecRRPairLongOp.Saddlp16) x)) 3088 3089(decl uaddlp8 (Reg) Reg) 3090(rule (uaddlp8 x) (vec_rr_pair_long (VecRRPairLongOp.Uaddlp8) x)) 3091 3092(decl uaddlp16 (Reg) Reg) 3093(rule (uaddlp16 x) (vec_rr_pair_long (VecRRPairLongOp.Uaddlp16) x)) 3094 3095;; Helper for generating `umlal32` instructions. 3096(decl umlal32 (Reg Reg Reg bool) Reg) 3097(rule (umlal32 x y z high_half) (vec_rrrr_long (VecRRRLongModOp.Umlal32) x y z high_half)) 3098 3099;; Helper for generating `smull8` instructions. 3100(decl smull8 (Reg Reg bool) Reg) 3101(rule (smull8 x y high_half) (vec_rrr_long (VecRRRLongOp.Smull8) x y high_half)) 3102 3103;; Helper for generating `umull8` instructions. 3104(decl umull8 (Reg Reg bool) Reg) 3105(rule (umull8 x y high_half) (vec_rrr_long (VecRRRLongOp.Umull8) x y high_half)) 3106 3107;; Helper for generating `smull16` instructions. 3108(decl smull16 (Reg Reg bool) Reg) 3109(rule (smull16 x y high_half) (vec_rrr_long (VecRRRLongOp.Smull16) x y high_half)) 3110 3111;; Helper for generating `umull16` instructions. 3112(decl umull16 (Reg Reg bool) Reg) 3113(rule (umull16 x y high_half) (vec_rrr_long (VecRRRLongOp.Umull16) x y high_half)) 3114 3115;; Helper for generating `smull32` instructions. 3116(decl smull32 (Reg Reg bool) Reg) 3117(rule (smull32 x y high_half) (vec_rrr_long (VecRRRLongOp.Smull32) x y high_half)) 3118 3119;; Helper for generating `umull32` instructions. 3120(decl umull32 (Reg Reg bool) Reg) 3121(rule (umull32 x y high_half) (vec_rrr_long (VecRRRLongOp.Umull32) x y high_half)) 3122 3123;; Helper for generating `asr` instructions. 3124(decl asr (Type Reg Reg) Reg) 3125(rule (asr ty x y) (alu_rrr (ALUOp.Asr) ty x y)) 3126 3127(decl asr_imm (Type Reg ImmShift) Reg) 3128(rule (asr_imm ty x imm) (alu_rr_imm_shift (ALUOp.Asr) ty x imm)) 3129 3130;; Helper for generating `lsr` instructions. 3131(spec (lsr ty a b) 3132 (provide 3133 (= result 3134 (switch ty 3135 (32 (conv_to 64 (bvlshr (extract 31 0 a) (extract 31 0 b)))) 3136 (64 (bvlshr a b)))))) 3137(decl lsr (Type Reg Reg) Reg) 3138(rule (lsr ty x y) (alu_rrr (ALUOp.Lsr) ty x y)) 3139 3140(spec (lsr_imm ty a b) 3141 (provide 3142 (= result 3143 (switch ty 3144 (32 (conv_to 64 (bvlshr (extract 31 0 a) (zero_ext 32 b)))) 3145 (64 (bvlshr a (zero_ext 64 b))))))) 3146(decl lsr_imm (Type Reg ImmShift) Reg) 3147(rule (lsr_imm ty x imm) (alu_rr_imm_shift (ALUOp.Lsr) ty x imm)) 3148 3149;; Helper for generating `lsl` instructions. 3150(spec (lsl ty a b) 3151 (provide 3152 (= result 3153 (switch ty 3154 (32 (conv_to 64 (bvshl (extract 31 0 a) (extract 31 0 b)))) 3155 (64 (bvshl a b)))))) 3156(decl lsl (Type Reg Reg) Reg) 3157(rule (lsl ty x y) (alu_rrr (ALUOp.Lsl) ty x y)) 3158 3159(spec (lsl_imm ty a b) 3160 (provide 3161 (= result 3162 (switch ty 3163 (32 (conv_to 64 (bvshl (extract 31 0 a) (zero_ext 32 b)))) 3164 (64 (bvshl a (zero_ext 64 b))))))) 3165(decl lsl_imm (Type Reg ImmShift) Reg) 3166(rule (lsl_imm ty x imm) (alu_rr_imm_shift (ALUOp.Lsl) ty x imm)) 3167 3168;; Helper for generating `udiv` instructions. 3169(spec (a64_udiv ty a b) 3170 (provide 3171 (= result 3172 (if (<= ty 32) 3173 (conv_to 64 (bvudiv (extract 31 0 a) (extract 31 0 b))) 3174 (bvudiv a b))))) 3175(decl a64_udiv (Type Reg Reg) Reg) 3176(rule (a64_udiv ty x y) (alu_rrr (ALUOp.UDiv) ty x y)) 3177 3178;; Helper for generating `sdiv` instructions. 3179(spec (a64_sdiv ty a b) 3180 (provide 3181 (= result 3182 (if (<= ty 32) 3183 (conv_to 64 (bvsdiv (extract 31 0 a) (extract 31 0 b))) 3184 (bvsdiv a b))))) 3185(decl a64_sdiv (Type Reg Reg) Reg) 3186(rule (a64_sdiv ty x y) (alu_rrr (ALUOp.SDiv) ty x y)) 3187 3188;; Helper for generating `not` instructions. 3189(decl not (Reg VectorSize) Reg) 3190(rule (not x size) (vec_misc (VecMisc2.Not) x size)) 3191 3192;; Helpers for generating `orr_not` instructions. 3193(spec (orr_not ty a b) 3194 (provide 3195 (= result 3196 (if (<= ty 32) 3197 (conv_to 64 (bvor (extract 31 0 a) (bvnot (extract 31 0 b)))) 3198 (bvor a (bvnot b)))))) 3199(decl orr_not (Type Reg Reg) Reg) 3200(rule (orr_not ty x y) (alu_rrr (ALUOp.OrrNot) ty x y)) 3201 3202(spec (orr_not_shift ty a b shift) 3203 (provide 3204 (= result (if (<= ty 32) 3205 (conv_to 64 (bvor a (bvnot (bvshl b (zero_ext 64 (bvand (bvsub (int2bv 8 ty) #x01) (extract 7 0 shift))))))) 3206 (bvor a (bvnot (bvshl b (zero_ext 64 (bvand (bvsub (int2bv 8 ty) #x01) (extract 7 0 shift)))))))))) 3207(decl orr_not_shift (Type Reg Reg ShiftOpAndAmt) Reg) 3208(rule (orr_not_shift ty x y shift) (alu_rrr_shift (ALUOp.OrrNot) ty x y shift)) 3209 3210;; Helpers for generating `orr` instructions. 3211(spec (orr ty a b) 3212 (provide 3213 (= result 3214 (if (<= ty 32) 3215 (conv_to 64 (bvor (extract 31 0 a) (extract 31 0 b))) 3216 (bvor a b)))) 3217 (require (or (= ty 8) (= ty 16) (= ty 32) (= ty 64)))) 3218(decl orr (Type Reg Reg) Reg) 3219(rule (orr ty x y) (alu_rrr (ALUOp.Orr) ty x y)) 3220 3221(spec (orr_imm ty x y) 3222 (provide 3223 (= result 3224 (switch ty 3225 (32 (conv_to 64 (bvor (extract 31 0 x) (extract 31 0 y)))) 3226 (64 (bvor x (zero_ext 64 y)))))) 3227 (require 3228 (or 3229 (= y (bvand y #x0000000000000fff)) 3230 (= y (bvand y #x0000000000fff000))))) 3231(decl orr_imm (Type Reg ImmLogic) Reg) 3232(rule (orr_imm ty x y) (alu_rr_imm_logic (ALUOp.Orr) ty x y)) 3233 3234(decl orr_shift (Type Reg Reg ShiftOpAndAmt) Reg) 3235(rule (orr_shift ty x y shift) (alu_rrr_shift (ALUOp.Orr) ty x y shift)) 3236 3237(decl orr_vec (Reg Reg VectorSize) Reg) 3238(rule (orr_vec x y size) (vec_rrr (VecALUOp.Orr) x y size)) 3239 3240(decl orn_vec (Reg Reg VectorSize) Reg) 3241(rule (orn_vec x y size) (vec_rrr (VecALUOp.Orn) x y size)) 3242 3243;; Helpers for generating `and` instructions. 3244(spec (and_reg ty a b) 3245 (provide 3246 (= result 3247 (if (<= ty 32) 3248 (conv_to 64 (bvand (extract 31 0 a) (extract 31 0 b))) 3249 (bvand a b)))) 3250 (require (or (= ty 8) (= ty 16) (= ty 32) (= ty 64)))) 3251(decl and_reg (Type Reg Reg) Reg) 3252(rule (and_reg ty x y) (alu_rrr (ALUOp.And) ty x y)) 3253 3254(spec (and_imm ty x y) 3255 (provide 3256 (= result 3257 (switch ty 3258 (32 (conv_to 64 (bvand (extract 31 0 x) (extract 31 0 y)))) 3259 (64 (bvand x (zero_ext 64 y)))))) 3260 (require 3261 (or 3262 (= y (bvand y #x0000000000000fff)) 3263 (= y (bvand y #x0000000000fff000))))) 3264(decl and_imm (Type Reg ImmLogic) Reg) 3265(rule (and_imm ty x y) (alu_rr_imm_logic (ALUOp.And) ty x y)) 3266 3267(decl and_vec (Reg Reg VectorSize) Reg) 3268(rule (and_vec x y size) (vec_rrr (VecALUOp.And) x y size)) 3269 3270;; Helpers for generating `eor` instructions. 3271(decl eor (Type Reg Reg) Reg) 3272(rule (eor ty x y) (alu_rrr (ALUOp.Eor) ty x y)) 3273 3274(decl eor_vec (Reg Reg VectorSize) Reg) 3275(rule (eor_vec x y size) (vec_rrr (VecALUOp.Eor) x y size)) 3276 3277;; Helpers for generating `bic` instructions. 3278(spec (bic ty a b) 3279 (provide 3280 (= result 3281 (if (<= ty 32) 3282 (conv_to 64 (bvand (extract 31 0 a) (bvnot (extract 31 0 b)))) 3283 (bvand a (bvnot b)) 3284 ) 3285 )) 3286 (require (or (= ty 8) (= ty 16) (= ty 32) (= ty 64)))) 3287(decl bic (Type Reg Reg) Reg) 3288(rule (bic ty x y) (alu_rrr (ALUOp.AndNot) ty x y)) 3289 3290(decl bic_vec (Reg Reg VectorSize) Reg) 3291(rule (bic_vec x y size) (vec_rrr (VecALUOp.Bic) x y size)) 3292 3293;; Helpers for generating `sshl` instructions. 3294(decl sshl (Reg Reg VectorSize) Reg) 3295(rule (sshl x y size) (vec_rrr (VecALUOp.Sshl) x y size)) 3296 3297;; Helpers for generating `ushl` instructions. 3298(decl ushl (Reg Reg VectorSize) Reg) 3299(rule (ushl x y size) (vec_rrr (VecALUOp.Ushl) x y size)) 3300 3301;; Helpers for generating `ushl` instructions. 3302(decl ushl_vec_imm (Reg u8 VectorSize) Reg) 3303(rule (ushl_vec_imm x amt size) (vec_shift_imm (VecShiftImmOp.Shl) amt x size)) 3304 3305;; Helpers for generating `ushr` instructions. 3306(decl ushr_vec_imm (Reg u8 VectorSize) Reg) 3307(rule (ushr_vec_imm x amt size) (vec_shift_imm (VecShiftImmOp.Ushr) amt x size)) 3308 3309;; Helpers for generating `sshr` instructions. 3310(decl sshr_vec_imm (Reg u8 VectorSize) Reg) 3311(rule (sshr_vec_imm x amt size) (vec_shift_imm (VecShiftImmOp.Sshr) amt x size)) 3312 3313;; Helpers for generating `rotr` instructions. 3314;; 3315;; Note that the `Extr` opcode is used here as `rotr` is an alias for that 3316;; instruction where two operands are the same register. 3317(spec (a64_rotr ty x y) 3318 (provide 3319 (= result 3320 (if (= ty 32) 3321 (zero_ext 64 (rotr (extract 31 0 x) (extract 31 0 y))) 3322 (rotr x y)))) 3323 (require (or (= ty 32) (= ty 64)))) 3324(decl a64_rotr (Type Reg Reg) Reg) 3325(rule (a64_rotr ty x y) (alu_rrr (ALUOp.Extr) ty x y)) 3326 3327(spec (a64_rotr_imm ty x y) 3328 (provide 3329 (= result 3330 (if (= ty 32) 3331 (zero_ext 64 (rotr (extract 31 0 x) (zero_ext 32 y))) 3332 (rotr x (zero_ext 64 y))))) 3333 (require (or (= ty 32) (= ty 64)))) 3334(decl a64_rotr_imm (Type Reg ImmShift) Reg) 3335(rule (a64_rotr_imm ty x y) (alu_rr_imm_shift (ALUOp.Extr) ty x y)) 3336 3337;; Helpers for generating `extr` instructions 3338(decl a64_extr (Type Reg Reg ImmShift) Reg) 3339(rule (a64_extr ty x y shift) (alu_rrr_shift (ALUOp.Extr) ty x y (a64_extr_imm ty shift))) 3340(decl a64_extr_imm (Type ImmShift) ShiftOpAndAmt) 3341(extern constructor a64_extr_imm a64_extr_imm) 3342 3343;; Helpers for generating `rbit` instructions. 3344(spec (rbit ty a) 3345 (provide 3346 (= result 3347 (if (= ty 32) 3348 (conv_to 64 (rev (extract 31 0 a))) 3349 (rev a)))) 3350 (require (or (= ty 32) (= ty 64)))) 3351(decl rbit (Type Reg) Reg) 3352(rule (rbit ty x) (bit_rr (BitOp.RBit) ty x)) 3353 3354;; Helpers for generating `clz` instructions. 3355(spec (a64_clz ty a) 3356 (provide 3357 (= result 3358 (if (= ty 32) 3359 (conv_to 64 (clz (extract 31 0 a))) 3360 (clz a)))) 3361 (require (or (= ty 32) (= ty 64)))) 3362(decl a64_clz (Type Reg) Reg) 3363(rule (a64_clz ty x) (bit_rr (BitOp.Clz) ty x)) 3364 3365;; Helpers for generating `cls` instructions. 3366(spec (a64_cls ty a) 3367 (provide 3368 (= result 3369 (if (= ty 32) 3370 (conv_to 64 (cls (extract 31 0 a))) 3371 (cls a)))) 3372 (require (or (= ty 32) (= ty 64)))) 3373(decl a64_cls (Type Reg) Reg) 3374(rule (a64_cls ty x) (bit_rr (BitOp.Cls) ty x)) 3375 3376;; Helpers for generating `rev` instructions 3377 3378(decl a64_rev16 (Type Reg) Reg) 3379(rule (a64_rev16 ty x) (bit_rr (BitOp.Rev16) ty x)) 3380 3381(decl a64_rev32 (Type Reg) Reg) 3382(rule (a64_rev32 ty x) (bit_rr (BitOp.Rev32) ty x)) 3383 3384(decl a64_rev64 (Type Reg) Reg) 3385(rule (a64_rev64 ty x) (bit_rr (BitOp.Rev64) ty x)) 3386 3387;; Helpers for generating `eon` instructions. 3388 3389(decl eon (Type Reg Reg) Reg) 3390(rule (eon ty x y) (alu_rrr (ALUOp.EorNot) ty x y)) 3391 3392;; Helpers for generating `cnt` instructions. 3393(spec (vec_cnt x s) 3394 (provide 3395 (= result 3396 (switch s 3397 ((VectorSize.Size8x8) 3398 (concat 3399 (popcnt (extract 63 56 x)) 3400 (popcnt (extract 55 48 x)) 3401 (popcnt (extract 47 40 x)) 3402 (popcnt (extract 39 32 x)) 3403 (popcnt (extract 31 24 x)) 3404 (popcnt (extract 23 16 x)) 3405 (popcnt (extract 15 8 x)) 3406 (popcnt (extract 7 0 x)))) 3407 ((VectorSize.Size16x4) result) 3408 ((VectorSize.Size32x2) result)))) 3409 (require 3410 (or (= s (VectorSize.Size8x8)) (= s (VectorSize.Size16x4)) (= s (VectorSize.Size32x2))))) 3411(decl vec_cnt (Reg VectorSize) Reg) 3412(rule (vec_cnt x size) (vec_misc (VecMisc2.Cnt) x size)) 3413 3414;; Helpers for generating a `bsl` instruction. 3415 3416(decl bsl (Type Reg Reg Reg) Reg) 3417(rule (bsl ty c x y) 3418 (vec_rrr_mod (VecALUModOp.Bsl) c x y (vector_size ty))) 3419 3420;; Helper for generating a `udf` instruction. 3421 3422(decl udf (TrapCode) SideEffectNoResult) 3423(rule (udf trap_code) 3424 (SideEffectNoResult.Inst (MInst.Udf trap_code))) 3425 3426;; Helpers for generating various load instructions, with varying 3427;; widths and sign/zero-extending properties. 3428(decl aarch64_uload8 (AMode MemFlags) Reg) 3429(spec (aarch64_uload8 amode flags) 3430 (provide (= result (zero_ext 32 (load_effect flags 8 amode)))) 3431 (require (= 32 (widthof result)))) 3432(rule (aarch64_uload8 amode flags) 3433 (let ((dst WritableReg (temp_writable_reg $I64)) 3434 (_ Unit (emit (MInst.ULoad8 dst amode flags)))) 3435 dst)) 3436(decl aarch64_sload8 (AMode MemFlags) Reg) 3437(rule (aarch64_sload8 amode flags) 3438 (let ((dst WritableReg (temp_writable_reg $I64)) 3439 (_ Unit (emit (MInst.SLoad8 dst amode flags)))) 3440 dst)) 3441(decl aarch64_uload16 (AMode MemFlags) Reg) 3442(spec (aarch64_uload16 amode flags) 3443 (provide (= result (zero_ext 32 (load_effect flags 16 amode)))) 3444 (require (= 32 (widthof result)))) 3445(rule (aarch64_uload16 amode flags) 3446 (let ((dst WritableReg (temp_writable_reg $I64)) 3447 (_ Unit (emit (MInst.ULoad16 dst amode flags)))) 3448 dst)) 3449(decl aarch64_sload16 (AMode MemFlags) Reg) 3450(rule (aarch64_sload16 amode flags) 3451 (let ((dst WritableReg (temp_writable_reg $I64)) 3452 (_ Unit (emit (MInst.SLoad16 dst amode flags)))) 3453 dst)) 3454(decl aarch64_uload32 (AMode MemFlags) Reg) 3455(spec (aarch64_uload32 amode flags) 3456 (provide (= result (load_effect flags 32 amode))) 3457 (require (= 32 (widthof result)))) 3458(rule (aarch64_uload32 amode flags) 3459 (let ((dst WritableReg (temp_writable_reg $I64)) 3460 (_ Unit (emit (MInst.ULoad32 dst amode flags)))) 3461 dst)) 3462(decl aarch64_sload32 (AMode MemFlags) Reg) 3463(rule (aarch64_sload32 amode flags) 3464 (let ((dst WritableReg (temp_writable_reg $I64)) 3465 (_ Unit (emit (MInst.SLoad32 dst amode flags)))) 3466 dst)) 3467(decl aarch64_uload64 (AMode MemFlags) Reg) 3468(spec (aarch64_uload64 amode flags) 3469 (provide (= result (load_effect flags 64 amode))) 3470 (require (= 64 (widthof result)))) 3471(rule (aarch64_uload64 amode flags) 3472 (let ((dst WritableReg (temp_writable_reg $I64)) 3473 (_ Unit (emit (MInst.ULoad64 dst amode flags)))) 3474 dst)) 3475(decl aarch64_fpuload16 (AMode MemFlags) Reg) 3476(rule (aarch64_fpuload16 amode flags) 3477 (let ((dst WritableReg (temp_writable_reg $F64)) 3478 (_ Unit (emit (MInst.FpuLoad16 dst amode flags)))) 3479 dst)) 3480(decl aarch64_fpuload32 (AMode MemFlags) Reg) 3481(rule (aarch64_fpuload32 amode flags) 3482 (let ((dst WritableReg (temp_writable_reg $F64)) 3483 (_ Unit (emit (MInst.FpuLoad32 dst amode flags)))) 3484 dst)) 3485(decl aarch64_fpuload64 (AMode MemFlags) Reg) 3486(rule (aarch64_fpuload64 amode flags) 3487 (let ((dst WritableReg (temp_writable_reg $F64)) 3488 (_ Unit (emit (MInst.FpuLoad64 dst amode flags)))) 3489 dst)) 3490(decl aarch64_fpuload128 (AMode MemFlags) Reg) 3491(rule (aarch64_fpuload128 amode flags) 3492 (let ((dst WritableReg (temp_writable_reg $F64X2)) 3493 (_ Unit (emit (MInst.FpuLoad128 dst amode flags)))) 3494 dst)) 3495(decl aarch64_loadp64 (PairAMode MemFlags) ValueRegs) 3496(rule (aarch64_loadp64 amode flags) 3497 (let ((dst1 WritableReg (temp_writable_reg $I64)) 3498 (dst2 WritableReg (temp_writable_reg $I64)) 3499 (_ Unit (emit (MInst.LoadP64 dst1 dst2 amode flags)))) 3500 (value_regs dst1 dst2))) 3501 3502;; Helpers for generating various store instructions with varying 3503;; widths. 3504(decl aarch64_store8 (AMode MemFlags Reg) SideEffectNoResult) 3505(spec (aarch64_store8 amode flags val) 3506 (provide (= result (store_effect flags 8 (extract 7 0 val) amode)))) 3507(rule (aarch64_store8 amode flags val) 3508 (SideEffectNoResult.Inst (MInst.Store8 val amode flags))) 3509(decl aarch64_store16 (AMode MemFlags Reg) SideEffectNoResult) 3510(spec (aarch64_store16 amode flags val) 3511 (provide (= result (store_effect flags 16 (extract 15 0 val) amode)))) 3512(rule (aarch64_store16 amode flags val) 3513 (SideEffectNoResult.Inst (MInst.Store16 val amode flags))) 3514(decl aarch64_store32 (AMode MemFlags Reg) SideEffectNoResult) 3515(spec (aarch64_store32 amode flags val) 3516 (provide (= result (store_effect flags 32 (extract 31 0 val) amode)))) 3517(rule (aarch64_store32 amode flags val) 3518 (SideEffectNoResult.Inst (MInst.Store32 val amode flags))) 3519(decl aarch64_store64 (AMode MemFlags Reg) SideEffectNoResult) 3520(spec (aarch64_store64 amode flags val) 3521 (provide (= result (store_effect flags 64 val amode)))) 3522(rule (aarch64_store64 amode flags val) 3523 (SideEffectNoResult.Inst (MInst.Store64 val amode flags))) 3524(decl aarch64_fpustore16 (AMode MemFlags Reg) SideEffectNoResult) 3525(rule (aarch64_fpustore16 amode flags val) 3526 (SideEffectNoResult.Inst (MInst.FpuStore16 val amode flags))) 3527(decl aarch64_fpustore32 (AMode MemFlags Reg) SideEffectNoResult) 3528(rule (aarch64_fpustore32 amode flags val) 3529 (SideEffectNoResult.Inst (MInst.FpuStore32 val amode flags))) 3530(decl aarch64_fpustore64 (AMode MemFlags Reg) SideEffectNoResult) 3531(rule (aarch64_fpustore64 amode flags val) 3532 (SideEffectNoResult.Inst (MInst.FpuStore64 val amode flags))) 3533(decl aarch64_fpustore128 (AMode MemFlags Reg) SideEffectNoResult) 3534(rule (aarch64_fpustore128 amode flags val) 3535 (SideEffectNoResult.Inst (MInst.FpuStore128 val amode flags))) 3536(decl aarch64_storep64 (PairAMode MemFlags Reg Reg) SideEffectNoResult) 3537(rule (aarch64_storep64 amode flags val1 val2) 3538 (SideEffectNoResult.Inst (MInst.StoreP64 val1 val2 amode flags))) 3539 3540;; Helper for generating a `trapif` instruction. 3541 3542(decl trap_if (ProducesFlags TrapCode Cond) InstOutput) 3543(rule (trap_if flags trap_code cond) 3544 (side_effect 3545 (with_flags_side_effect flags 3546 (ConsumesFlags.ConsumesFlagsSideEffect 3547 (MInst.TrapIf (cond_br_cond cond) trap_code))))) 3548 3549;; Helpers for lowering `trapz` and `trapnz`. 3550(type ZeroCond 3551 (enum 3552 Zero 3553 NonZero)) 3554 3555(decl zero_cond_to_cond_br (ZeroCond Reg OperandSize) CondBrKind) 3556(rule (zero_cond_to_cond_br (ZeroCond.Zero) reg size) 3557 (cond_br_zero reg size)) 3558 3559(rule (zero_cond_to_cond_br (ZeroCond.NonZero) reg size) 3560 (cond_br_not_zero reg size)) 3561 3562(decl trap_if_val (ZeroCond Value TrapCode) InstOutput) 3563(rule (trap_if_val zero_cond val @ (value_type (fits_in_64 _)) trap_code) 3564 (let ((reg Reg (put_in_reg_zext64 val))) 3565 (side_effect 3566 (SideEffectNoResult.Inst 3567 (MInst.TrapIf (zero_cond_to_cond_br zero_cond reg (operand_size $I64)) trap_code))))) 3568 3569(rule -1 (trap_if_val zero_cond val @ (value_type $I128) trap_code) 3570 (let ((c ValueRegs (put_in_regs val)) 3571 (c_lo Reg (value_regs_get c 0)) 3572 (c_hi Reg (value_regs_get c 1)) 3573 (c_test Reg (orr $I64 c_lo c_hi))) 3574 (side_effect 3575 (SideEffectNoResult.Inst 3576 (MInst.TrapIf (zero_cond_to_cond_br zero_cond c_test (operand_size $I64)) trap_code))))) 3577 3578;; Immediate value helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 3579 3580;; Type of extension performed by an immediate helper 3581(model ImmExtend 3582 (enum 3583 (Sign #b0) 3584 (Zero #b1))) 3585(type ImmExtend 3586 (enum 3587 (Sign) 3588 (Zero))) 3589 3590;; Arguments: 3591;; * Immediate type 3592;; * Way to extend the immediate value to the full width of the destination 3593;; register 3594;; * Immediate value - only the bits that fit within the type are used and 3595;; extended, while the rest are ignored 3596;; 3597;; Note that, unlike the convention in the AArch64 backend, this helper leaves 3598;; all bits in the destination register in a defined state, i.e. smaller types 3599;; such as `I8` are either sign- or zero-extended. 3600(spec (imm ty ext x) 3601 (provide 3602 (= result 3603 (switch ty 3604 (8 (if (= ext #b1) (zero_ext 64 (extract 7 0 x)) (sign_ext 64 (extract 7 0 x)))) 3605 (16 (if (= ext #b1) (zero_ext 64 (extract 15 0 x)) (sign_ext 64 (extract 15 0 x)))) 3606 (32 (if (= ext #b1) (zero_ext 64 (extract 32 0 x)) (sign_ext 64 (extract 32 0 x)))) 3607 (64 x)))) 3608 (require (or (= ty 8) (= ty 16) (= ty 32) (= ty 64)))) 3609(instantiate imm 3610 ((args Int (bv 64)) (ret (bv 64)) (canon (bv 8))) 3611 ((args Int (bv 64)) (ret (bv 64)) (canon (bv 16))) 3612 ((args Int (bv 64)) (ret (bv 64)) (canon (bv 32))) 3613 ((args Int (bv 64)) (ret (bv 64)) (canon (bv 64))) 3614) 3615(decl imm (Type ImmExtend u64) Reg) 3616 3617;; Move wide immediate instructions; to simplify, we only match when we 3618;; are zero-extending the value. 3619(rule 3 (imm (integral_ty ty) (ImmExtend.Zero) k) 3620 (if-let n (move_wide_const_from_u64 ty k)) 3621 (add_range_fact 3622 (movz n (operand_size ty)) 3623 64 k k)) 3624(rule 2 (imm (integral_ty (ty_32_or_64 ty)) (ImmExtend.Zero) k) 3625 (if-let n (move_wide_const_from_inverted_u64 ty k)) 3626 (add_range_fact 3627 (movn n (operand_size ty)) 3628 64 k k)) 3629 3630;; Weird logical-instruction immediate in ORI using zero register; to simplify, 3631;; we only match when we are zero-extending the value. 3632(rule 1 (imm (integral_ty ty) (ImmExtend.Zero) k) 3633 (if-let n (imm_logic_from_u64 ty k)) 3634 (if-let m (imm_size_from_type ty)) 3635 (add_range_fact 3636 (orr_imm ty (zero_reg) n) 3637 m k k)) 3638 3639(decl load_constant_full (Type ImmExtend OperandSize u64) Reg) 3640(extern constructor load_constant_full load_constant_full) 3641 3642;; Fallback for integral 32-bit constants 3643(rule (imm (fits_in_32 (integral_ty ty)) extend n) 3644 (load_constant_full ty extend (operand_size $I32) n)) 3645 3646;; Fallback for integral 64-bit constants 3647(rule -1 (imm (integral_ty $I64) extend n) 3648 (load_constant_full $I64 extend (operand_size $I64) n)) 3649 3650 3651;; Sign extension helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 3652 3653;; Place a `Value` into a register, sign extending it to 32-bits 3654(spec (put_in_reg_sext32 arg) 3655 (provide 3656 (= result 3657 (if (<= (widthof arg) 32) 3658 (conv_to 64 (sign_ext 32 arg)) 3659 (conv_to 64 arg))))) 3660(decl put_in_reg_sext32 (Value) Reg) 3661(rule -1 (put_in_reg_sext32 val @ (value_type (fits_in_32 ty))) 3662 (extend val true (ty_bits ty) 32)) 3663 3664;; 32/64-bit passthrough. 3665(rule (put_in_reg_sext32 val @ (value_type $I32)) val) 3666(rule (put_in_reg_sext32 val @ (value_type $I64)) val) 3667 3668;; Place a `Value` into a register, zero extending it to 32-bits 3669(spec (put_in_reg_zext32 arg) 3670 (provide 3671 (= result 3672 (if (<= (widthof arg) 32) 3673 (conv_to 64 (zero_ext 32 arg)) 3674 (conv_to 64 arg))))) 3675(decl put_in_reg_zext32 (Value) Reg) 3676(rule -1 (put_in_reg_zext32 val @ (value_type (fits_in_32 ty))) 3677 (extend val false (ty_bits ty) 32)) 3678 3679;; 32/64-bit passthrough. 3680(rule (put_in_reg_zext32 val @ (value_type $I32)) val) 3681(rule (put_in_reg_zext32 val @ (value_type $I64)) val) 3682 3683;; Place a `Value` into a register, sign extending it to 64-bits 3684(spec (put_in_reg_sext64 x) 3685 (provide (= (sign_ext 64 x) result))) 3686(decl put_in_reg_sext64 (Value) Reg) 3687(rule 1 (put_in_reg_sext64 val @ (value_type (fits_in_32 ty))) 3688 (extend val true (ty_bits ty) 64)) 3689 3690;; 64-bit passthrough. 3691(rule (put_in_reg_sext64 val @ (value_type $I64)) val) 3692 3693;; Place a `Value` into a register, zero extending it to 64-bits 3694(spec (put_in_reg_zext64 x) 3695 (provide (= result (zero_ext 64 x)))) 3696(decl put_in_reg_zext64 (Value) Reg) 3697(rule 1 (put_in_reg_zext64 val @ (value_type (fits_in_32 ty))) 3698 (extend val false (ty_bits ty) 64)) 3699 3700;; 64-bit passthrough. 3701(rule (put_in_reg_zext64 val @ (value_type $I64)) val) 3702 3703;; Misc instruction helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 3704 3705(decl trap_if_zero_divisor (Reg OperandSize) Reg) 3706(rule (trap_if_zero_divisor reg size) 3707 (let ((_ Unit (emit (MInst.TrapIf (cond_br_zero reg size ) (trap_code_division_by_zero))))) 3708 reg)) 3709 3710(decl size_from_ty (Type) OperandSize) 3711(rule 1 (size_from_ty (fits_in_32 _ty)) (OperandSize.Size32)) 3712(rule (size_from_ty $I64) (OperandSize.Size64)) 3713 3714;; Check for signed overflow. The only case is min_value / -1. 3715;; The following checks must be done in 32-bit or 64-bit, depending 3716;; on the input type. For 8- and 16- bit, the check for x == min_value 3717;; must use a possibly-shifted value, xcheck, to overflow as expected. 3718(decl trap_if_div_overflow (Type Reg Reg Reg) Reg) 3719(rule (trap_if_div_overflow ty xcheck x y) 3720 (let ( 3721 ;; Check RHS is -1. 3722 (_ Unit (emit (MInst.AluRRImm12 (ALUOp.AddS) (operand_size ty) (writable_zero_reg) y (u8_into_imm12 1)))) 3723 3724 ;; Check LHS is min_value, by subtracting 1 from the possibly-shifted 3725 ;; value and branching if there is overflow. 3726 (_ Unit (emit (MInst.CCmpImm (size_from_ty ty) 3727 xcheck 3728 (u8_into_uimm5 1) 3729 (nzcv false false false false) 3730 (Cond.Eq)))) 3731 (_ Unit (emit (MInst.TrapIf (cond_br_cond (Cond.Vs)) 3732 (trap_code_integer_overflow)))) 3733 ) 3734 x)) 3735 3736;; In the cases narrower than a register width, subtracting 1 from the 3737;; min_value will not cause overflow (e.g., I8's min_value of -128 stored in 3738;; a 32-bit register produces -129 with no overflow). However, if we left shift 3739;; x by (32 - ty), we then produce the 32-bit min_value for the respective min 3740;; values of I8 and I16. 3741;; E.g., I8's 0x00000080 left-shifted by 24 is 0x80000000, which overflows. 3742(decl intmin_check (Type Reg) Reg) 3743(rule intmin_check_fits_in_16 (intmin_check (fits_in_16 ty) x) 3744 (alu_rr_imm_shift (ALUOp.Lsl) ty x (imm_shift_from_u8 (diff_from_32 ty)))) 3745 3746;; In the I32 or I64 case, checking x itself against the min_value is fine. 3747(rule -1 (intmin_check ty x) x) 3748 3749;; Check for unsigned overflow. 3750(decl trap_if_overflow (ProducesFlags TrapCode) Reg) 3751(rule (trap_if_overflow producer tc) 3752 (with_flags_reg 3753 producer 3754 (ConsumesFlags.ConsumesFlagsSideEffect 3755 (MInst.TrapIf (cond_br_cond (Cond.Hs)) tc)))) 3756 3757(decl sink_atomic_load (Inst) Reg) 3758(rule (sink_atomic_load x @ (atomic_load _ addr)) 3759 (let ((_ Unit (sink_inst x))) 3760 (put_in_reg addr))) 3761 3762;; Helper for generating either an `AluRRR`, `AluRRRShift`, or `AluRRImmLogic` 3763;; instruction depending on the input. Note that this requires that the `ALUOp` 3764;; specified is commutative. 3765(spec (alu_rs_imm_logic_commutative op t a b) 3766 (provide 3767 (= result 3768 (conv_to 64 3769 (switch op 3770 ((ALUOp.Orr) (bvor a b)) 3771 ((ALUOp.And) (bvand a b)) 3772 ((ALUOp.Eor) (bvxor a b))))))) 3773(decl alu_rs_imm_logic_commutative (ALUOp Type Value Value) Reg) 3774 3775;; Base case of operating on registers. 3776(rule -1 (alu_rs_imm_logic_commutative op ty x y) 3777 (alu_rrr op ty x y)) 3778 3779;; Special cases for when one operand is a constant. 3780(rule (alu_rs_imm_logic_commutative op ty x (iconst k)) 3781 (if-let imm (imm_logic_from_imm64 ty k)) 3782 (alu_rr_imm_logic op ty x imm)) 3783(rule 1 (alu_rs_imm_logic_commutative op ty (iconst k) x) 3784 (if-let imm (imm_logic_from_imm64 ty k)) 3785 (alu_rr_imm_logic op ty x imm)) 3786 3787;; Special cases for when one operand is shifted left by a constant. 3788(rule (alu_rs_imm_logic_commutative op ty x (ishl y (iconst k))) 3789 (if-let amt (lshl_from_imm64 ty k)) 3790 (alu_rrr_shift op ty x y amt)) 3791(rule 1 (alu_rs_imm_logic_commutative op ty (ishl x (iconst k)) y) 3792 (if-let amt (lshl_from_imm64 ty k)) 3793 (alu_rrr_shift op ty y x amt)) 3794 3795;; Same as `alu_rs_imm_logic_commutative` above, except that it doesn't require 3796;; that the operation is commutative. 3797(spec (alu_rs_imm_logic op t a b) 3798 (provide 3799 (= result 3800 (conv_to 64 3801 (switch op 3802 ((ALUOp.OrrNot) (bvor a (bvnot b))) 3803 ((ALUOp.EorNot) (bvxor a (bvnot b))) 3804 ((ALUOp.AndNot) (bvand a (bvnot b)))))))) 3805(decl alu_rs_imm_logic (ALUOp Type Value Value) Reg) 3806(rule -1 (alu_rs_imm_logic op ty x y) 3807 (alu_rrr op ty x y)) 3808(rule (alu_rs_imm_logic op ty x (iconst k)) 3809 (if-let imm (imm_logic_from_imm64 ty k)) 3810 (alu_rr_imm_logic op ty x imm)) 3811(rule (alu_rs_imm_logic op ty x (ishl y (iconst k))) 3812 (if-let amt (lshl_from_imm64 ty k)) 3813 (alu_rrr_shift op ty x y amt)) 3814 3815;; Helper for generating i128 bitops which simply do the same operation to the 3816;; hi/lo registers. 3817;; 3818;; TODO: Support immlogic here 3819(decl i128_alu_bitop (ALUOp Type Value Value) ValueRegs) 3820(rule (i128_alu_bitop op ty x y) 3821 (let ( 3822 (x_regs ValueRegs (put_in_regs x)) 3823 (x_lo Reg (value_regs_get x_regs 0)) 3824 (x_hi Reg (value_regs_get x_regs 1)) 3825 (y_regs ValueRegs (put_in_regs y)) 3826 (y_lo Reg (value_regs_get y_regs 0)) 3827 (y_hi Reg (value_regs_get y_regs 1)) 3828 ) 3829 (value_regs 3830 (alu_rrr op ty x_lo y_lo) 3831 (alu_rrr op ty x_hi y_hi)))) 3832 3833;; Helper for emitting `MInst.VecLoadReplicate` instructions. 3834(decl ld1r (Reg VectorSize MemFlags) Reg) 3835(rule (ld1r src size flags) 3836 (let ((dst WritableReg (temp_writable_reg $I8X16)) 3837 (_ Unit (emit (MInst.VecLoadReplicate dst src size flags)))) 3838 dst)) 3839 3840(decl pure is_pic () bool) 3841(extern constructor is_pic is_pic) 3842 3843;; Helper loading an external name into a register via `MInst.LoadExt*` 3844(decl load_ext_name (BoxExternalName i64 RelocDistance) Reg) 3845 3846;; When `is_pic` is true all names are referenced through the GOT. Note that 3847;; the relocation is applied to the address of the GOT itself so the offset 3848;; requested must be manually added in (or skipped if it's 0). 3849(rule (load_ext_name name offset _) 3850 (if-let true (is_pic)) 3851 (add $I64 (load_ext_name_got name) (imm $I64 (ImmExtend.Zero) (i64_cast_unsigned offset)))) 3852(rule 1 (load_ext_name name 0 _) 3853 (if-let true (is_pic)) 3854 (load_ext_name_got name)) 3855 3856;; Relocations that are "near" do an `adr;add` combo. 3857(rule 1 (load_ext_name name offset (RelocDistance.Near)) 3858 (if-let false (is_pic)) 3859 (load_ext_name_near name offset)) 3860 3861;; Relocations that are "far" do an `Abs8` relocation. 3862(rule 1 (load_ext_name name offset (RelocDistance.Far)) 3863 (if-let false (is_pic)) 3864 (load_ext_name_far name offset)) 3865 3866;; Helper for emitting `MInst.LoadExtNameGot` instructions. 3867(decl load_ext_name_got (BoxExternalName) Reg) 3868(rule (load_ext_name_got extname) 3869 (let ((dst WritableReg (temp_writable_reg $I64)) 3870 (_ Unit (emit (MInst.LoadExtNameGot dst extname)))) 3871 dst)) 3872 3873;; Helper for emitting `MInst.LoadExtNameNear` instructions. 3874(decl load_ext_name_near (BoxExternalName i64) Reg) 3875(rule (load_ext_name_near extname offset) 3876 (let ((dst WritableReg (temp_writable_reg $I64)) 3877 (_ Unit (emit (MInst.LoadExtNameNear dst extname offset)))) 3878 dst)) 3879 3880;; Helper for emitting `MInst.LoadExtNameFar` instructions. 3881(decl load_ext_name_far (BoxExternalName i64) Reg) 3882(rule (load_ext_name_far extname offset) 3883 (let ((dst WritableReg (temp_writable_reg $I64)) 3884 (_ Unit (emit (MInst.LoadExtNameFar dst extname offset)))) 3885 dst)) 3886 3887;; Lower the address of a load or a store. 3888;; 3889;; This will create an `AMode` representing the address of the `Value` provided 3890;; at runtime plus the immediate offset `i32` provided. The `Type` here is used 3891;; to represent the size of the value being loaded or stored for offset scaling 3892;; if necessary. 3893;; 3894;; Note that this is broken up into two phases. In the first phase this attempts 3895;; to find constants within the `val` provided and fold them in to the `offset` 3896;; provided. Afterwards though the `amode_no_more_iconst` helper is used at 3897;; which pointer constants are no longer pattern-matched and instead only 3898;; various modes are generated. This in theory would not be necessary with 3899;; mid-end optimizations that fold constants into load/store immediate offsets 3900;; instead, but for now each backend needs to do this. 3901(decl amode (Type Value i32) AMode) 3902(spec (amode ty val offset) 3903 (provide (= result (bvadd val (sign_ext 64 offset)))) 3904 (require (= 64 (widthof val)))) 3905 3906(rule 0 (amode ty val offset) 3907 (amode_no_more_iconst ty val offset)) 3908(rule 1 (amode ty (iadd x (i32_from_iconst y)) offset) 3909 (if-let new_offset (i32_checked_add y offset)) 3910 (amode_no_more_iconst ty x new_offset)) 3911(rule 2 (amode ty (iadd (i32_from_iconst x) y) offset) 3912 (if-let new_offset (i32_checked_add x offset)) 3913 (amode_no_more_iconst ty y new_offset)) 3914 3915(rule 3 3916 (amode ty (stack_addr slot offset1) offset2) 3917 (AMode.SlotOffset 3918 (abi_stackslot_offset_into_slot_region slot offset1 offset2))) 3919 3920(decl amode_no_more_iconst (Type Value i32) AMode) 3921;; Base case: move the `offset` into a register and add it to `val` via the 3922;; amode 3923(rule 0 (amode_no_more_iconst ty val offset) 3924 (AMode.RegReg val (imm $I64 (ImmExtend.Zero) (i64_cast_unsigned offset)))) 3925 3926;; Optimize cases where the `offset` provided fits into a immediates of 3927;; various kinds of addressing modes. 3928(rule 1 (amode_no_more_iconst ty val offset) 3929 (if-let simm9 (simm9_from_i64 offset)) 3930 (AMode.Unscaled val simm9)) 3931(rule 2 (amode_no_more_iconst ty val offset) 3932 (if-let uimm12 (uimm12_scaled_from_i64 offset ty)) 3933 (AMode.UnsignedOffset val uimm12)) 3934 3935;; Optimizations where addition can fold some operations into the `amode`. 3936;; 3937;; Note that here these take higher priority than constants because an 3938;; add-of-extend can be folded into an amode, representing 2 otherwise emitted 3939;; instructions. Constants on the other hand added to the amode represent only 3940;; a single instruction folded in, so fewer instructions should be generated 3941;; with these higher priority than the rules above. 3942(rule 3 (amode_no_more_iconst ty (iadd x y) offset) 3943 (AMode.RegReg (amode_add x offset) y)) 3944(rule 4 (amode_no_more_iconst ty (iadd x (uextend y @ (value_type $I32))) offset) 3945 (AMode.RegExtended (amode_add x offset) y (ExtendOp.UXTW))) 3946(rule 4 (amode_no_more_iconst ty (iadd x (sextend y @ (value_type $I32))) offset) 3947 (AMode.RegExtended (amode_add x offset) y (ExtendOp.SXTW))) 3948(rule 5 (amode_no_more_iconst ty (iadd (uextend x @ (value_type $I32)) y) offset) 3949 (AMode.RegExtended (amode_add y offset) x (ExtendOp.UXTW))) 3950(rule 5 (amode_no_more_iconst ty (iadd (sextend x @ (value_type $I32)) y) offset) 3951 (AMode.RegExtended (amode_add y offset) x (ExtendOp.SXTW))) 3952 3953;; `RegScaled*` rules where this matches an addition of an "index register" to a 3954;; base register. The index register is shifted by the size of the type loaded 3955;; in bytes to enable this mode matching. 3956;; 3957;; Note that this can additionally bundle an extending operation but the 3958;; extension must happen before the shift. This will pattern-match the shift 3959;; first and then if that succeeds afterwards try to find an extend. 3960(rule 6 (amode_no_more_iconst ty (iadd x (ishl y (iconst (u64_from_imm64 n)))) offset) 3961 (if-let true (u64_eq (ty_bytes ty) (u64_wrapping_shl 1 (shift_masked_imm ty n)))) 3962 (amode_reg_scaled (amode_add x offset) y)) 3963(rule 7 (amode_no_more_iconst ty (iadd (ishl y (iconst (u64_from_imm64 n))) x) offset) 3964 (if-let true (u64_eq (ty_bytes ty) (u64_wrapping_shl 1 (shift_masked_imm ty n)))) 3965 (amode_reg_scaled (amode_add x offset) y)) 3966 3967(decl amode_reg_scaled (Reg Value) AMode) 3968(rule 0 (amode_reg_scaled base index) 3969 (AMode.RegScaled base index)) 3970(rule 1 (amode_reg_scaled base (uextend index @ (value_type $I32))) 3971 (AMode.RegScaledExtended base index (ExtendOp.UXTW))) 3972(rule 1 (amode_reg_scaled base (sextend index @ (value_type $I32))) 3973 (AMode.RegScaledExtended base index (ExtendOp.SXTW))) 3974 3975;; Helper to add a 32-bit signed immediate to the register provided. This will 3976;; select an appropriate `add` instruction to use. 3977(decl amode_add (Reg i32) Reg) 3978(rule 0 (amode_add x y) 3979 (add $I64 x (imm $I64 (ImmExtend.Zero) (i64_cast_unsigned y)))) 3980(rule 1 (amode_add x y) 3981 (if-let (imm12_from_u64 imm12) (i64_cast_unsigned y)) 3982 (add_imm $I64 x imm12)) 3983(rule 2 (amode_add x 0) x) 3984 3985;; Creates a `PairAMode` for the `Value` provided plus the `i32` constant 3986;; offset provided. 3987(decl pair_amode (Value i32) PairAMode) 3988 3989;; Base case where `val` and `offset` are combined with an `add` 3990(rule 0 (pair_amode val offset) 3991 (if-let simm7 (simm7_scaled_from_i64 0 $I64)) 3992 (PairAMode.SignedOffset (amode_add val offset) simm7)) 3993 3994;; Optimization when `offset` can fit into a `SImm7Scaled`. 3995(rule 1 (pair_amode val offset) 3996 (if-let simm7 (simm7_scaled_from_i64 offset $I64)) 3997 (PairAMode.SignedOffset val simm7)) 3998 3999(decl pure partial simm7_scaled_from_i64 (i64 Type) SImm7Scaled) 4000(extern constructor simm7_scaled_from_i64 simm7_scaled_from_i64) 4001 4002(decl pure partial uimm12_scaled_from_i64 (i64 Type) UImm12Scaled) 4003(extern constructor uimm12_scaled_from_i64 uimm12_scaled_from_i64) 4004 4005(decl pure partial simm9_from_i64 (i64) SImm9) 4006(extern constructor simm9_from_i64 simm9_from_i64) 4007 4008 4009(decl sink_load_into_addr (Type Inst) Reg) 4010(rule (sink_load_into_addr ty x @ (load _ addr (offset32 offset))) 4011 (let ((_ Unit (sink_inst x))) 4012 (add_imm_to_addr addr (i64_cast_unsigned offset)))) 4013 4014(decl add_imm_to_addr (Reg u64) Reg) 4015(rule 2 (add_imm_to_addr val 0) val) 4016(rule 1 (add_imm_to_addr val (imm12_from_u64 imm)) (add_imm $I64 val imm)) 4017(rule 0 (add_imm_to_addr val offset) (add $I64 val (imm $I64 (ImmExtend.Zero) offset))) 4018 4019;; Lower a constant f16. 4020;; 4021;; Note that we must make sure that all bits outside the lowest 16 are set to 0 4022;; because this function is also used to load wider constants (that have zeros 4023;; in their most significant bits). 4024;; 4025;; Recursion: forms cycle with `constant_f32`. Invokes 32-bit case when FP16 is not supported. 4026(decl rec constant_f16 (u16) Reg) 4027(rule 3 (constant_f16 n) 4028 (if-let false (use_fp16)) 4029 (constant_f32 n)) 4030(rule 2 (constant_f16 0) 4031 (vec_dup_imm (asimd_mov_mod_imm_zero (ScalarSize.Size32)) 4032 false 4033 (VectorSize.Size32x2))) 4034(rule 1 (constant_f16 n) 4035 (if-let imm (asimd_fp_mod_imm_from_u64 n (ScalarSize.Size16))) 4036 (fpu_move_fp_imm imm (ScalarSize.Size16))) 4037(rule (constant_f16 n) 4038 (mov_to_fpu (imm $I16 (ImmExtend.Zero) n) (ScalarSize.Size16))) 4039 4040;; Lower a constant f32. 4041;; 4042;; Note that we must make sure that all bits outside the lowest 32 are set to 0 4043;; because this function is also used to load wider constants (that have zeros 4044;; in their most significant bits). 4045;; 4046;; Recursion: forms cycle with `constant_f16`. Invokes 16-bit case when FP16 is supported. 4047(decl rec constant_f32 (u32) Reg) 4048(rule 3 (constant_f32 0) 4049 (vec_dup_imm (asimd_mov_mod_imm_zero (ScalarSize.Size32)) 4050 false 4051 (VectorSize.Size32x2))) 4052(rule 2 (constant_f32 n) 4053 (if-let imm (asimd_fp_mod_imm_from_u64 n (ScalarSize.Size32))) 4054 (fpu_move_fp_imm imm (ScalarSize.Size32))) 4055(rule 1 (constant_f32 (u16_from_u32 n)) 4056 (if-let true (use_fp16)) 4057 (constant_f16 n)) 4058(rule (constant_f32 n) 4059 (mov_to_fpu (imm $I32 (ImmExtend.Zero) n) (ScalarSize.Size32))) 4060 4061;; Lower a constant f64. 4062;; 4063;; Note that we must make sure that all bits outside the lowest 64 are set to 0 4064;; because this function is also used to load wider constants (that have zeros 4065;; in their most significant bits). 4066;; TODO: Treat as half of a 128 bit vector and consider replicated patterns. 4067;; Scalar MOVI might also be an option. 4068(decl constant_f64 (u64) Reg) 4069(rule 4 (constant_f64 0) 4070 (vec_dup_imm (asimd_mov_mod_imm_zero (ScalarSize.Size32)) 4071 false 4072 (VectorSize.Size32x2))) 4073(rule 3 (constant_f64 n) 4074 (if-let imm (asimd_fp_mod_imm_from_u64 n (ScalarSize.Size64))) 4075 (fpu_move_fp_imm imm (ScalarSize.Size64))) 4076(rule 2 (constant_f64 (u32_from_u64 n)) 4077 (constant_f32 n)) 4078(rule 1 (constant_f64 (u64_low32_bits_unset n)) 4079 (mov_to_fpu (imm $I64 (ImmExtend.Zero) n) (ScalarSize.Size64))) 4080(rule (constant_f64 n) 4081 (fpu_load64 (AMode.Const (emit_u64_le_const n)) (mem_flags_trusted))) 4082 4083;; Tests whether the low 32 bits in the input are all zero. 4084(decl u64_low32_bits_unset (u64) u64) 4085(extern extractor u64_low32_bits_unset u64_low32_bits_unset) 4086 4087;; Lower a constant f128. 4088(decl constant_f128 (u128) Reg) 4089(rule 3 (constant_f128 0) 4090 (vec_dup_imm (asimd_mov_mod_imm_zero (ScalarSize.Size8)) 4091 false 4092 (VectorSize.Size8x16))) 4093 4094;; If the upper 64-bits are all zero then defer to `constant_f64`. 4095(rule 2 (constant_f128 (u64_from_u128 n)) (constant_f64 n)) 4096 4097;; If the low half of the u128 equals the high half then delegate to the splat 4098;; logic as a splat of a 64-bit value. 4099(rule 1 (constant_f128 (u128_replicated_u64 n)) 4100 (splat_const n (VectorSize.Size64x2))) 4101 4102;; Base case is to load the constant from memory. 4103(rule (constant_f128 n) 4104 (fpu_load128 (AMode.Const (emit_u128_le_const n)) (mem_flags_trusted))) 4105 4106;; Lower a vector splat with a constant parameter. 4107;; 4108;; The 64-bit input here only uses the low bits for the lane size in 4109;; `VectorSize` and all other bits are ignored. 4110;; 4111;; Recursion: bounded since the recursive call always reduces lane size. 4112(decl rec splat_const (u64 VectorSize) Reg) 4113 4114;; If the splat'd constant can itself be reduced in size then attempt to do so 4115;; as it will make it easier to create the immediates in the instructions below. 4116(rule 5 (splat_const (u64_replicated_u32 n) (VectorSize.Size64x2)) 4117 (splat_const n (VectorSize.Size32x4))) 4118(rule 5 (splat_const (u32_replicated_u16 n) (VectorSize.Size32x4)) 4119 (splat_const n (VectorSize.Size16x8))) 4120(rule 5 (splat_const (u32_replicated_u16 n) (VectorSize.Size32x2)) 4121 (splat_const n (VectorSize.Size16x4))) 4122(rule 5 (splat_const (u16_replicated_u8 n) (VectorSize.Size16x8)) 4123 (splat_const n (VectorSize.Size8x16))) 4124(rule 5 (splat_const (u16_replicated_u8 n) (VectorSize.Size16x4)) 4125 (splat_const n (VectorSize.Size8x8))) 4126 4127;; Special cases for `vec_dup_imm` instructions where the input is either 4128;; negated or not. 4129(rule 4 (splat_const n size) 4130 (if-let imm (asimd_mov_mod_imm_from_u64 n (vector_lane_size size))) 4131 (vec_dup_imm imm false size)) 4132(rule 3 (splat_const n size) 4133 (if-let imm (asimd_mov_mod_imm_from_u64 (u64_not n) (vector_lane_size size))) 4134 (vec_dup_imm imm true size)) 4135 4136;; Special case a 32-bit splat where an immediate can be created by 4137;; concatenating the 32-bit constant into a 64-bit value 4138(rule 2 (splat_const n (VectorSize.Size32x4)) 4139 (if-let imm (asimd_mov_mod_imm_from_u64 (u64_or n (u64_wrapping_shl n 32)) (ScalarSize.Size64))) 4140 (vec_dup_imm imm false (VectorSize.Size64x2))) 4141(rule 2 (splat_const n (VectorSize.Size32x2)) 4142 (if-let imm (asimd_mov_mod_imm_from_u64 (u64_or n (u64_wrapping_shl n 32)) (ScalarSize.Size64))) 4143 (fpu_extend (vec_dup_imm imm false (VectorSize.Size64x2)) (ScalarSize.Size64))) 4144 4145(rule 1 (splat_const n size) 4146 (if-let true (vec_dup_fp_imm_supports_lane_size (vector_lane_size size))) 4147 (if-let imm (asimd_fp_mod_imm_from_u64 n (vector_lane_size size))) 4148 (vec_dup_fp_imm imm size)) 4149 4150(decl pure vec_dup_fp_imm_supports_lane_size (ScalarSize) bool) 4151(rule 1 (vec_dup_fp_imm_supports_lane_size (ScalarSize.Size32)) true) 4152(rule 1 (vec_dup_fp_imm_supports_lane_size (ScalarSize.Size64)) true) 4153(rule (vec_dup_fp_imm_supports_lane_size _) false) 4154 4155;; The base case for splat is to use `vec_dup` with the immediate loaded into a 4156;; register. 4157(rule (splat_const n size) 4158 (vec_dup (imm $I64 (ImmExtend.Zero) n) size)) 4159 4160;; Lower a FloatCC to a Cond. 4161(decl fp_cond_code (FloatCC) Cond) 4162;; TODO: Port lower_fp_condcode() to ISLE. 4163(extern constructor fp_cond_code fp_cond_code) 4164 4165;; Lower an integer cond code. 4166(spec (cond_code a) (provide (= a result))) 4167(decl cond_code (IntCC) Cond) 4168;; TODO: Port lower_condcode() to ISLE. 4169(extern constructor cond_code cond_code) 4170 4171;; Invert a condition code. 4172(decl invert_cond (Cond) Cond) 4173;; TODO: Port cond.invert() to ISLE. 4174(extern constructor invert_cond invert_cond) 4175 4176;; Generate comparison to zero operator from input condition code 4177(decl float_cc_cmp_zero_to_vec_misc_op (FloatCC) VecMisc2) 4178(extern constructor float_cc_cmp_zero_to_vec_misc_op float_cc_cmp_zero_to_vec_misc_op) 4179 4180(decl float_cc_cmp_zero_to_vec_misc_op_swap (FloatCC) VecMisc2) 4181(extern constructor float_cc_cmp_zero_to_vec_misc_op_swap float_cc_cmp_zero_to_vec_misc_op_swap) 4182 4183;; Match valid generic compare to zero cases 4184(decl fcmp_zero_cond (FloatCC) FloatCC) 4185(extern extractor fcmp_zero_cond fcmp_zero_cond) 4186 4187;; Match not equal compare to zero separately as it requires two output instructions 4188(decl fcmp_zero_cond_not_eq (FloatCC) FloatCC) 4189(extern extractor fcmp_zero_cond_not_eq fcmp_zero_cond_not_eq) 4190 4191;; Helper for generating float compare to zero instructions where 2nd argument is zero 4192(decl float_cmp_zero (FloatCC Reg VectorSize) Reg) 4193(rule (float_cmp_zero cond rn size) 4194 (vec_misc (float_cc_cmp_zero_to_vec_misc_op cond) rn size)) 4195 4196;; Helper for generating float compare to zero instructions in case where 1st argument is zero 4197(decl float_cmp_zero_swap (FloatCC Reg VectorSize) Reg) 4198(rule (float_cmp_zero_swap cond rn size) 4199 (vec_misc (float_cc_cmp_zero_to_vec_misc_op_swap cond) rn size)) 4200 4201;; Helper for generating float compare equal to zero instruction 4202(decl fcmeq0 (Reg VectorSize) Reg) 4203(rule (fcmeq0 rn size) 4204 (vec_misc (VecMisc2.Fcmeq0) rn size)) 4205 4206;; Generate comparison to zero operator from input condition code 4207(decl int_cc_cmp_zero_to_vec_misc_op (IntCC) VecMisc2) 4208(extern constructor int_cc_cmp_zero_to_vec_misc_op int_cc_cmp_zero_to_vec_misc_op) 4209 4210(decl int_cc_cmp_zero_to_vec_misc_op_swap (IntCC) VecMisc2) 4211(extern constructor int_cc_cmp_zero_to_vec_misc_op_swap int_cc_cmp_zero_to_vec_misc_op_swap) 4212 4213;; Match valid generic compare to zero cases 4214(decl icmp_zero_cond (IntCC) IntCC) 4215(extern extractor icmp_zero_cond icmp_zero_cond) 4216 4217;; Match not equal compare to zero separately as it requires two output instructions 4218(decl icmp_zero_cond_not_eq (IntCC) IntCC) 4219(extern extractor icmp_zero_cond_not_eq icmp_zero_cond_not_eq) 4220 4221;; Helper for generating int compare to zero instructions where 2nd argument is zero 4222(decl int_cmp_zero (IntCC Reg VectorSize) Reg) 4223(rule (int_cmp_zero cond rn size) 4224 (vec_misc (int_cc_cmp_zero_to_vec_misc_op cond) rn size)) 4225 4226;; Helper for generating int compare to zero instructions in case where 1st argument is zero 4227(decl int_cmp_zero_swap (IntCC Reg VectorSize) Reg) 4228(rule (int_cmp_zero_swap cond rn size) 4229 (vec_misc (int_cc_cmp_zero_to_vec_misc_op_swap cond) rn size)) 4230 4231;; Helper for generating int compare equal to zero instruction 4232(decl cmeq0 (Reg VectorSize) Reg) 4233(rule (cmeq0 rn size) 4234 (vec_misc (VecMisc2.Cmeq0) rn size)) 4235 4236;; Helper for emitting `MInst.AtomicRMW` instructions. 4237(decl lse_atomic_rmw (AtomicRMWOp Value Reg Type MemFlags) Reg) 4238(rule (lse_atomic_rmw op p r_arg2 ty flags) 4239 (let ( 4240 (r_addr Reg p) 4241 (dst WritableReg (temp_writable_reg ty)) 4242 (_ Unit (emit (MInst.AtomicRMW op r_arg2 dst r_addr ty flags))) 4243 ) 4244 dst)) 4245 4246;; Helper for emitting `MInst.AtomicCAS` instructions. 4247(decl lse_atomic_cas (Reg Reg Reg Type MemFlags) Reg) 4248(rule (lse_atomic_cas addr expect replace ty flags) 4249 (let ( 4250 (dst WritableReg (temp_writable_reg ty)) 4251 (_ Unit (emit (MInst.AtomicCAS dst expect replace addr ty flags))) 4252 ) 4253 dst)) 4254 4255;; Helper for emitting `MInst.AtomicRMWLoop` instructions. 4256;; - Make sure that both args are in virtual regs, since in effect 4257;; we have to do a parallel copy to get them safely to the AtomicRMW input 4258;; regs, and that's not guaranteed safe if either is in a real reg. 4259;; - Move the args to the preordained AtomicRMW input regs 4260;; - And finally, copy the preordained AtomicRMW output reg to its destination. 4261(decl atomic_rmw_loop (AtomicRMWLoopOp Reg Reg Type MemFlags) Reg) 4262(rule (atomic_rmw_loop op addr operand ty flags) 4263 (let ((dst WritableReg (temp_writable_reg $I64)) 4264 (scratch1 WritableReg (temp_writable_reg $I64)) 4265 (scratch2 WritableReg (temp_writable_reg $I64)) 4266 (_ Unit (emit (MInst.AtomicRMWLoop ty op flags addr operand dst scratch1 scratch2)))) 4267 dst)) 4268 4269;; Helper for emitting `MInst.AtomicCASLoop` instructions. 4270;; This is very similar to, but not identical to, the AtomicRmw case. Note 4271;; that the AtomicCASLoop sequence does its own masking, so we don't need to worry 4272;; about zero-extending narrow (I8/I16/I32) values here. 4273;; Make sure that all three args are in virtual regs. See corresponding comment 4274;; for `atomic_rmw_loop` above. 4275(decl atomic_cas_loop (Reg Reg Reg Type MemFlags) Reg) 4276(rule (atomic_cas_loop addr expect replace ty flags) 4277 (let ((dst WritableReg (temp_writable_reg $I64)) 4278 (scratch WritableReg (temp_writable_reg $I64)) 4279 (_ Unit (emit (MInst.AtomicCASLoop ty flags addr expect replace dst scratch)))) 4280 dst)) 4281 4282;; Helper for emitting `MInst.MovPReg` instructions. 4283(decl mov_from_preg (PReg) Reg) 4284(rule (mov_from_preg src) 4285 (let ((dst WritableReg (temp_writable_reg $I64)) 4286 (_ Unit (emit (MInst.MovFromPReg dst src)))) 4287 dst)) 4288 4289(decl mov_to_preg (PReg Reg) SideEffectNoResult) 4290(rule (mov_to_preg dst src) 4291 (SideEffectNoResult.Inst (MInst.MovToPReg dst src))) 4292 4293(decl preg_sp () PReg) 4294(extern constructor preg_sp preg_sp) 4295 4296(decl preg_fp () PReg) 4297(extern constructor preg_fp preg_fp) 4298 4299(decl preg_link () PReg) 4300(extern constructor preg_link preg_link) 4301 4302(decl preg_pinned () PReg) 4303(extern constructor preg_pinned preg_pinned) 4304 4305(decl aarch64_sp () Reg) 4306(rule (aarch64_sp) 4307 (mov_from_preg (preg_sp))) 4308 4309(decl aarch64_fp () Reg) 4310(rule (aarch64_fp) 4311 (mov_from_preg (preg_fp))) 4312 4313(decl aarch64_link () Reg) 4314(rule 1 (aarch64_link) 4315 (if (preserve_frame_pointers)) 4316 (if (sign_return_address_disabled)) 4317 (let ((dst WritableReg (temp_writable_reg $I64)) 4318 ;; Even though LR is not an allocatable register, whether it 4319 ;; contains the return address for the current function is 4320 ;; unknown at this point. For example, this operation may come 4321 ;; immediately after a call, in which case LR would not have a 4322 ;; valid value. That's why we must obtain the return address from 4323 ;; the frame record that corresponds to the current subroutine on 4324 ;; the stack; the presence of the record is guaranteed by the 4325 ;; `preserve_frame_pointers` setting. 4326 (addr AMode (AMode.FPOffset 8)) 4327 (_ Unit (emit (MInst.ULoad64 dst addr (mem_flags_trusted))))) 4328 dst)) 4329 4330(rule (aarch64_link) 4331 (if (preserve_frame_pointers)) 4332 ;; Similarly to the rule above, we must load the return address from the 4333 ;; the frame record. Furthermore, we can use LR as a scratch register 4334 ;; because the function will set it to the return address immediately 4335 ;; before returning. 4336 (let ((addr AMode (AMode.FPOffset 8)) 4337 (lr WritableReg (writable_link_reg)) 4338 (_ Unit (emit (MInst.ULoad64 lr addr (mem_flags_trusted)))) 4339 (_ Unit (emit (MInst.Xpaclri)))) 4340 (mov_from_preg (preg_link)))) 4341 4342;; Helper for getting the maximum shift amount for a type. 4343 4344(decl max_shift (Type) u8) 4345(rule (max_shift $F64) 63) 4346(rule (max_shift $F32) 31) 4347 4348;; Helper for generating `fcopysign` instruction sequences. 4349 4350(decl fcopy_sign (Reg Reg Type) Reg) 4351(rule 1 (fcopy_sign x y (ty_scalar_float ty)) 4352 (let ((dst WritableReg (temp_writable_reg $F64)) 4353 (tmp Reg (fpu_rri (fpu_op_ri_ushr (ty_bits ty) (max_shift ty)) y)) 4354 (_ Unit (emit (MInst.FpuRRIMod (fpu_op_ri_sli (ty_bits ty) (max_shift ty)) dst x tmp)))) 4355 dst)) 4356(rule (fcopy_sign x y ty @ (multi_lane _ _)) 4357 (let ((dst WritableReg (temp_writable_reg $I8X16)) 4358 (tmp Reg (ushr_vec_imm y (max_shift (lane_type ty)) (vector_size ty))) 4359 (_ Unit (emit (MInst.VecShiftImmMod (VecShiftImmModOp.Sli) dst x tmp (vector_size ty) (max_shift (lane_type ty)))))) 4360 dst)) 4361 4362;; Helpers for generating `MInst.FpuToInt` instructions. 4363 4364(decl fpu_to_int_nan_check (ScalarSize Reg) Reg) 4365(rule (fpu_to_int_nan_check size src) 4366 (let ((r ValueRegs 4367 (with_flags (fpu_cmp size src src) 4368 (ConsumesFlags.ConsumesFlagsReturnsReg 4369 (MInst.TrapIf (cond_br_cond (Cond.Vs)) 4370 (trap_code_bad_conversion_to_integer)) 4371 src)))) 4372 (value_regs_get r 0))) 4373 4374;; Checks that the value is not less than the minimum bound, 4375;; accepting a boolean (whether the type is signed), input type, 4376;; output type, and registers containing the source and minimum bound. 4377(decl fpu_to_int_underflow_check (bool Type Type Reg Reg) Reg) 4378(rule (fpu_to_int_underflow_check true $F32 (fits_in_16 out_ty) src min) 4379 (let ((r ValueRegs 4380 (with_flags (fpu_cmp (ScalarSize.Size32) src min) 4381 (ConsumesFlags.ConsumesFlagsReturnsReg 4382 (MInst.TrapIf (cond_br_cond (Cond.Le)) 4383 (trap_code_integer_overflow)) 4384 src)))) 4385 (value_regs_get r 0))) 4386(rule (fpu_to_int_underflow_check true $F64 (fits_in_32 out_ty) src min) 4387 (let ((r ValueRegs 4388 (with_flags (fpu_cmp (ScalarSize.Size64) src min) 4389 (ConsumesFlags.ConsumesFlagsReturnsReg 4390 (MInst.TrapIf (cond_br_cond (Cond.Le)) 4391 (trap_code_integer_overflow)) 4392 src)))) 4393 (value_regs_get r 0))) 4394(rule -1 (fpu_to_int_underflow_check true in_ty _out_ty src min) 4395 (let ((r ValueRegs 4396 (with_flags (fpu_cmp (scalar_size in_ty) src min) 4397 (ConsumesFlags.ConsumesFlagsReturnsReg 4398 (MInst.TrapIf (cond_br_cond (Cond.Lt)) 4399 (trap_code_integer_overflow)) 4400 src)))) 4401 (value_regs_get r 0))) 4402(rule (fpu_to_int_underflow_check false in_ty _out_ty src min) 4403 (let ((r ValueRegs 4404 (with_flags (fpu_cmp (scalar_size in_ty) src min) 4405 (ConsumesFlags.ConsumesFlagsReturnsReg 4406 (MInst.TrapIf (cond_br_cond (Cond.Le)) 4407 (trap_code_integer_overflow)) 4408 src)))) 4409 (value_regs_get r 0))) 4410 4411(decl fpu_to_int_overflow_check (ScalarSize Reg Reg) Reg) 4412(rule (fpu_to_int_overflow_check size src max) 4413 (let ((r ValueRegs 4414 (with_flags (fpu_cmp size src max) 4415 (ConsumesFlags.ConsumesFlagsReturnsReg 4416 (MInst.TrapIf (cond_br_cond (Cond.Ge)) 4417 (trap_code_integer_overflow)) 4418 src)))) 4419 (value_regs_get r 0))) 4420 4421;; Emits the appropriate instruction sequence to convert a 4422;; floating-point value to an integer, trapping if the value 4423;; is a NaN or does not fit in the target type. 4424;; Accepts the specific conversion op, the source register, 4425;; whether the input is signed, and finally the input and output 4426;; types. 4427(decl fpu_to_int_cvt (FpuToIntOp Reg bool Type Type) Reg) 4428(rule (fpu_to_int_cvt op src signed in_ty out_ty) 4429 (let ((size ScalarSize (scalar_size in_ty)) 4430 (in_bits u8 (ty_bits in_ty)) 4431 (out_bits u8 (ty_bits out_ty)) 4432 (src Reg (fpu_to_int_nan_check size src)) 4433 (min Reg (min_fp_value signed in_bits out_bits)) 4434 (src Reg (fpu_to_int_underflow_check signed in_ty out_ty src min)) 4435 (max Reg (max_fp_value signed in_bits out_bits)) 4436 (src Reg (fpu_to_int_overflow_check size src max))) 4437 (fpu_to_int op src))) 4438 4439;; Emits the appropriate instruction sequence to convert a 4440;; floating-point value to an integer, saturating if the value 4441;; does not fit in the target type. 4442;; Accepts the specific conversion op, the source register, 4443;; whether the input is signed, and finally the output type. 4444(decl fpu_to_int_cvt_sat (FpuToIntOp Reg bool Type) Reg) 4445(rule 1 (fpu_to_int_cvt_sat op src _ $I64) 4446 (fpu_to_int op src)) 4447(rule 1 (fpu_to_int_cvt_sat op src _ $I32) 4448 (fpu_to_int op src)) 4449(rule (fpu_to_int_cvt_sat op src false (fits_in_16 out_ty)) 4450 (let ((result Reg (fpu_to_int op src)) 4451 (max Reg (imm out_ty (ImmExtend.Zero) (ty_mask out_ty)))) 4452 (with_flags_reg 4453 (cmp (OperandSize.Size32) result max) 4454 (csel (Cond.Hi) max result)))) 4455(rule (fpu_to_int_cvt_sat op src true (fits_in_16 out_ty)) 4456 (let ((result Reg (fpu_to_int op src)) 4457 (max Reg (signed_max out_ty)) 4458 (min Reg (signed_min out_ty)) 4459 (result Reg (with_flags_reg 4460 (cmp (operand_size out_ty) result max) 4461 (csel (Cond.Gt) max result))) 4462 (result Reg (with_flags_reg 4463 (cmp (operand_size out_ty) result min) 4464 (csel (Cond.Lt) min result)))) 4465 result)) 4466 4467(decl signed_min (Type) Reg) 4468(rule (signed_min $I8) (imm $I8 (ImmExtend.Sign) 0x80)) 4469(rule (signed_min $I16) (imm $I16 (ImmExtend.Sign) 0x8000)) 4470 4471(decl signed_max (Type) Reg) 4472(rule (signed_max $I8) (imm $I8 (ImmExtend.Sign) 0x7F)) 4473(rule (signed_max $I16) (imm $I16 (ImmExtend.Sign) 0x7FFF)) 4474 4475(decl fpu_to_int (FpuToIntOp Reg) Reg) 4476(rule (fpu_to_int op src) 4477 (let ((dst WritableReg (temp_writable_reg $I64)) 4478 (_ Unit (emit (MInst.FpuToInt op dst src)))) 4479 dst)) 4480 4481;; Helper for generating `MInst.IntToFpu` instructions. 4482 4483(decl int_to_fpu (IntToFpuOp Reg) Reg) 4484(rule (int_to_fpu op src) 4485 (let ((dst WritableReg (temp_writable_reg $I8X16)) 4486 (_ Unit (emit (MInst.IntToFpu op dst src)))) 4487 dst)) 4488 4489;;;; Helpers for Emitting Calls ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 4490 4491(decl gen_call_info (Sig ExternalName CallArgList CallRetList OptionTryCallInfo bool) BoxCallInfo) 4492(extern constructor gen_call_info gen_call_info) 4493 4494(decl gen_call_ind_info (Sig Reg CallArgList CallRetList OptionTryCallInfo) BoxCallIndInfo) 4495(extern constructor gen_call_ind_info gen_call_ind_info) 4496 4497(decl gen_return_call_info (Sig ExternalName CallArgList) BoxReturnCallInfo) 4498(extern constructor gen_return_call_info gen_return_call_info) 4499 4500(decl gen_return_call_ind_info (Sig Reg CallArgList) BoxReturnCallIndInfo) 4501(extern constructor gen_return_call_ind_info gen_return_call_ind_info) 4502 4503;; Helper for creating `MInst.Call` instructions. 4504(decl call_impl (BoxCallInfo) SideEffectNoResult) 4505(rule (call_impl info) 4506 (SideEffectNoResult.Inst (MInst.Call info))) 4507 4508;; Helper for creating `MInst.CallInd` instructions. 4509(decl call_ind_impl (BoxCallIndInfo) SideEffectNoResult) 4510(rule (call_ind_impl info) 4511 (SideEffectNoResult.Inst (MInst.CallInd info))) 4512 4513;; Helper for creating `MInst.ReturnCall` instructions. 4514(decl return_call_impl (BoxReturnCallInfo) SideEffectNoResult) 4515(rule (return_call_impl info) 4516 (SideEffectNoResult.Inst (MInst.ReturnCall info))) 4517 4518;; Helper for creating `MInst.ReturnCallInd` instructions. 4519(decl return_call_ind_impl (BoxReturnCallIndInfo) SideEffectNoResult) 4520(rule (return_call_ind_impl info) 4521 (SideEffectNoResult.Inst (MInst.ReturnCallInd info))) 4522 4523;; Helpers for pinned register manipulation. 4524 4525(decl write_pinned_reg (Reg) SideEffectNoResult) 4526(rule (write_pinned_reg val) 4527 (mov_to_preg (preg_pinned) val)) 4528 4529;; Helpers for stackslot effective address generation. 4530 4531(decl compute_stack_addr (StackSlot Offset32) Reg) 4532(rule (compute_stack_addr stack_slot offset) 4533 (let ((dst WritableReg (temp_writable_reg $I64)) 4534 (_ Unit (emit (abi_stackslot_addr dst stack_slot offset)))) 4535 dst)) 4536 4537;; Helper for emitting instruction sequences to perform a vector comparison. 4538 4539(decl vec_cmp_vc (Reg Reg VectorSize) Reg) 4540(rule (vec_cmp_vc rn rm size) 4541 (let ((dst Reg (vec_rrr (VecALUOp.Fcmeq) rn rn size)) 4542 (tmp Reg (vec_rrr (VecALUOp.Fcmeq) rm rm size)) 4543 (dst Reg (vec_rrr (VecALUOp.And) dst tmp size))) 4544 dst)) 4545 4546(decl vec_cmp (Reg Reg Type Cond) Reg) 4547 4548;; Floating point Vs / Vc 4549(rule (vec_cmp rn rm ty (Cond.Vc)) 4550 (if (ty_vector_float ty)) 4551 (vec_cmp_vc rn rm (vector_size ty))) 4552(rule (vec_cmp rn rm ty (Cond.Vs)) 4553 (if (ty_vector_float ty)) 4554 (let ((tmp Reg (vec_cmp_vc rn rm (vector_size ty)))) 4555 (vec_misc (VecMisc2.Not) tmp (vector_size ty)))) 4556 4557;; 'Less than' operations are implemented by swapping the order of 4558;; operands and using the 'greater than' instructions. 4559;; 'Not equal' is implemented with 'equal' and inverting the result. 4560 4561;; Floating-point 4562(rule (vec_cmp rn rm ty (Cond.Eq)) 4563 (if (ty_vector_float ty)) 4564 (vec_rrr (VecALUOp.Fcmeq) rn rm (vector_size ty))) 4565(rule (vec_cmp rn rm ty (Cond.Ne)) 4566 (if (ty_vector_float ty)) 4567 (let ((tmp Reg (vec_rrr (VecALUOp.Fcmeq) rn rm (vector_size ty)))) 4568 (vec_misc (VecMisc2.Not) tmp (vector_size ty)))) 4569(rule (vec_cmp rn rm ty (Cond.Ge)) 4570 (if (ty_vector_float ty)) 4571 (vec_rrr (VecALUOp.Fcmge) rn rm (vector_size ty))) 4572(rule (vec_cmp rn rm ty (Cond.Gt)) 4573 (if (ty_vector_float ty)) 4574 (vec_rrr (VecALUOp.Fcmgt) rn rm (vector_size ty))) 4575;; Floating-point swapped-operands 4576(rule (vec_cmp rn rm ty (Cond.Mi)) 4577 (if (ty_vector_float ty)) 4578 (vec_rrr (VecALUOp.Fcmgt) rm rn (vector_size ty))) 4579(rule (vec_cmp rn rm ty (Cond.Ls)) 4580 (if (ty_vector_float ty)) 4581 (vec_rrr (VecALUOp.Fcmge) rm rn (vector_size ty))) 4582 4583;; Integer 4584(rule 1 (vec_cmp rn rm ty (Cond.Eq)) 4585 (if (ty_vector_not_float ty)) 4586 (vec_rrr (VecALUOp.Cmeq) rn rm (vector_size ty))) 4587(rule 1 (vec_cmp rn rm ty (Cond.Ne)) 4588 (if (ty_vector_not_float ty)) 4589 (let ((tmp Reg (vec_rrr (VecALUOp.Cmeq) rn rm (vector_size ty)))) 4590 (vec_misc (VecMisc2.Not) tmp (vector_size ty)))) 4591(rule 1 (vec_cmp rn rm ty (Cond.Ge)) 4592 (if (ty_vector_not_float ty)) 4593 (vec_rrr (VecALUOp.Cmge) rn rm (vector_size ty))) 4594(rule 1 (vec_cmp rn rm ty (Cond.Gt)) 4595 (if (ty_vector_not_float ty)) 4596 (vec_rrr (VecALUOp.Cmgt) rn rm (vector_size ty))) 4597(rule (vec_cmp rn rm ty (Cond.Hs)) 4598 (if (ty_vector_not_float ty)) 4599 (vec_rrr (VecALUOp.Cmhs) rn rm (vector_size ty))) 4600(rule (vec_cmp rn rm ty (Cond.Hi)) 4601 (if (ty_vector_not_float ty)) 4602 (vec_rrr (VecALUOp.Cmhi) rn rm (vector_size ty))) 4603;; Integer swapped-operands 4604(rule (vec_cmp rn rm ty (Cond.Le)) 4605 (if (ty_vector_not_float ty)) 4606 (vec_rrr (VecALUOp.Cmge) rm rn (vector_size ty))) 4607(rule (vec_cmp rn rm ty (Cond.Lt)) 4608 (if (ty_vector_not_float ty)) 4609 (vec_rrr (VecALUOp.Cmgt) rm rn (vector_size ty))) 4610(rule 1 (vec_cmp rn rm ty (Cond.Ls)) 4611 (if (ty_vector_not_float ty)) 4612 (vec_rrr (VecALUOp.Cmhs) rm rn (vector_size ty))) 4613(rule (vec_cmp rn rm ty (Cond.Lo)) 4614 (if (ty_vector_not_float ty)) 4615 (vec_rrr (VecALUOp.Cmhi) rm rn (vector_size ty))) 4616 4617;; Helper for determining if any value in a vector is true. 4618;; This operation is implemented by using umaxp to create a scalar value, which 4619;; is then compared against zero. 4620;; 4621;; umaxp vn.4s, vm.4s, vm.4s 4622;; mov xm, vn.d[0] 4623;; cmp xm, #0 4624(decl vanytrue (Reg Type) ProducesFlags) 4625(rule 1 (vanytrue src (ty_vec128 ty)) 4626 (let ((src Reg (vec_rrr (VecALUOp.Umaxp) src src (VectorSize.Size32x4))) 4627 (src Reg (mov_from_vec src 0 (ScalarSize.Size64)))) 4628 (cmp_imm (OperandSize.Size64) src (u8_into_imm12 0)))) 4629(rule (vanytrue src ty) 4630 (if (ty_vec64 ty)) 4631 (let ((src Reg (mov_from_vec src 0 (ScalarSize.Size64)))) 4632 (cmp_imm (OperandSize.Size64) src (u8_into_imm12 0)))) 4633 4634;;;; TLS Values ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 4635 4636;; Helper for emitting ElfTlsGetAddr. 4637(decl elf_tls_get_addr (ExternalName) Reg) 4638(rule (elf_tls_get_addr name) 4639 (let ((dst WritableReg (temp_writable_reg $I64)) 4640 (tmp WritableReg (temp_writable_reg $I64)) 4641 (_ Unit (emit (MInst.ElfTlsGetAddr (box_external_name name) dst tmp)))) 4642 dst)) 4643 4644(decl macho_tls_get_addr (ExternalName) Reg) 4645(rule (macho_tls_get_addr name) 4646 (let ((dst WritableReg (temp_writable_reg $I64)) 4647 (_ Unit (emit (MInst.MachOTlsGetAddr name dst)))) 4648 dst)) 4649 4650;; A tuple of `ProducesFlags` and `IntCC`. 4651(type FlagsAndCC (enum (FlagsAndCC (flags ProducesFlags) 4652 (cc IntCC)))) 4653 4654(spec (flags_and_cc flags cc) 4655 (provide 4656 (= result (concat (extract 67 64 flags) cc))) 4657 (require 4658 (or 4659 (= cc (IntCC.Equal)) 4660 (= cc (IntCC.NotEqual)) 4661 (= cc (IntCC.UnsignedGreaterThanOrEqual)) 4662 (= cc (IntCC.UnsignedGreaterThan)) 4663 (= cc (IntCC.UnsignedLessThanOrEqual)) 4664 (= cc (IntCC.UnsignedLessThan)) 4665 (= cc (IntCC.SignedGreaterThanOrEqual)) 4666 (= cc (IntCC.SignedGreaterThan)) 4667 (= cc (IntCC.SignedLessThanOrEqual)) 4668 (= cc (IntCC.SignedLessThan))))) 4669;; Helper constructor for `FlagsAndCC`. 4670(decl flags_and_cc (ProducesFlags IntCC) FlagsAndCC) 4671(rule (flags_and_cc flags cc) (FlagsAndCC.FlagsAndCC flags cc)) 4672 4673(spec (flags_and_cc_to_bool a) 4674 (provide 4675 (= result 4676 (switch (extract 7 0 a) 4677 ((IntCC.Equal) (if (= (extract 10 10 a) #b1) #x01 #x00)) 4678 ((IntCC.NotEqual) (if (= (extract 10 10 a) #b0) #x01 #x00)) 4679 ((IntCC.SignedGreaterThan) (if (and (= (extract 10 10 a) #b0) (= (extract 11 11 a) (extract 8 8 a))) #x01 #x00)) 4680 ((IntCC.SignedGreaterThanOrEqual) (if (= (extract 11 11 a) (extract 8 8 a)) #x01 #x00)) 4681 ((IntCC.SignedLessThan) (if (not (= (extract 11 11 a) (extract 8 8 a))) #x01 #x00)) 4682 ((IntCC.SignedLessThanOrEqual) (if (or (= (extract 10 10 a) #b1) (not (= (extract 11 11 a) (extract 8 8 a)))) #x01 #x00)) 4683 ((IntCC.UnsignedGreaterThan) (if (and (= (extract 9 9 a) #b1) (= (extract 10 10 a) #b0)) #x01 #x00)) 4684 ((IntCC.UnsignedGreaterThanOrEqual) (if (= (extract 9 9 a) #b1) #x01 #x00)) 4685 ((IntCC.UnsignedLessThan) (if (= (extract 9 9 a) #b0) #x01 #x00)) 4686 ((IntCC.UnsignedLessThanOrEqual) (if (or (= (extract 9 9 a) #b0) (= (extract 10 10 a) #b1)) #x01 #x00))))) 4687 (require 4688 (or 4689 (= (extract 7 0 a) (IntCC.Equal)) 4690 (= (extract 7 0 a) (IntCC.NotEqual)) 4691 (= (extract 7 0 a) (IntCC.UnsignedGreaterThanOrEqual)) 4692 (= (extract 7 0 a) (IntCC.UnsignedGreaterThan)) 4693 (= (extract 7 0 a) (IntCC.UnsignedLessThanOrEqual)) 4694 (= (extract 7 0 a) (IntCC.UnsignedLessThan)) 4695 (= (extract 7 0 a) (IntCC.SignedGreaterThanOrEqual)) 4696 (= (extract 7 0 a) (IntCC.SignedGreaterThan)) 4697 (= (extract 7 0 a) (IntCC.SignedLessThanOrEqual)) 4698 (= (extract 7 0 a) (IntCC.SignedLessThan))))) 4699;; Materialize a `FlagsAndCC` into a boolean `ValueRegs`. 4700(decl flags_and_cc_to_bool (FlagsAndCC) ValueRegs) 4701(rule (flags_and_cc_to_bool (FlagsAndCC.FlagsAndCC flags cc)) 4702 (with_flags flags (materialize_bool_result (cond_code cc)))) 4703 4704;; Get the `ProducesFlags` out of a `FlagsAndCC`. 4705(decl flags_and_cc_flags (FlagsAndCC) ProducesFlags) 4706(rule (flags_and_cc_flags (FlagsAndCC.FlagsAndCC flags _cc)) flags) 4707 4708;; Get the `IntCC` out of a `FlagsAndCC`. 4709(decl flags_and_cc_cc (FlagsAndCC) IntCC) 4710(rule (flags_and_cc_cc (FlagsAndCC.FlagsAndCC _flags cc)) cc) 4711 4712;; Helpers for lowering `icmp` sequences. 4713;; `lower_icmp` contains shared functionality for lowering `icmp` 4714;; sequences, which `lower_icmp_into_{reg,flags}` extend from. 4715(spec (lower_icmp c x y in_ty) 4716 (provide 4717 (= result 4718 (concat 4719 (extract 67 64 4720 (if (or (= c (IntCC.SignedGreaterThanOrEqual)) 4721 (= c (IntCC.SignedGreaterThan)) 4722 (= c (IntCC.SignedLessThanOrEqual)) 4723 (= c (IntCC.SignedLessThan))) 4724 (if (<= in_ty 32) 4725 (subs 32 (sign_ext 64 x) (sign_ext 64 y)) 4726 (subs 64 (sign_ext 64 x) (sign_ext 64 y))) 4727 (if (<= in_ty 32) 4728 (subs 32 (zero_ext 64 x) (zero_ext 64 y)) 4729 (subs 64 (zero_ext 64 x) (zero_ext 64 y))))) 4730 c))) 4731 (require 4732 (or 4733 (= c (IntCC.Equal)) 4734 (= c (IntCC.NotEqual)) 4735 (= c (IntCC.UnsignedGreaterThanOrEqual)) 4736 (= c (IntCC.UnsignedGreaterThan)) 4737 (= c (IntCC.UnsignedLessThanOrEqual)) 4738 (= c (IntCC.UnsignedLessThan)) 4739 (= c (IntCC.SignedGreaterThanOrEqual)) 4740 (= c (IntCC.SignedGreaterThan)) 4741 (= c (IntCC.SignedLessThanOrEqual)) 4742 (= c (IntCC.SignedLessThan))) 4743 (or (= in_ty 8) 4744 (= in_ty 16) 4745 (= in_ty 32) 4746 (= in_ty 64)) 4747 (= in_ty (widthof x)) 4748 (= in_ty (widthof y)))) 4749(instantiate lower_icmp 4750 ((args (bv 8) (bv 8) (bv 8) Int) (ret (bv 12)) (canon (bv 8))) 4751 ((args (bv 8) (bv 16) (bv 16) Int) (ret (bv 12)) (canon (bv 16))) 4752 ((args (bv 8) (bv 32) (bv 32) Int) (ret (bv 12)) (canon (bv 32))) 4753 ((args (bv 8) (bv 64) (bv 64) Int) (ret (bv 12)) (canon (bv 64))) 4754) 4755(decl lower_icmp (IntCC Value Value Type) FlagsAndCC) 4756 4757(spec (lower_icmp_into_reg c x y in_ty out_ty) 4758 (provide 4759 (= result 4760 (switch c 4761 ((IntCC.Equal) (if (= x y) #x01 #x00)) 4762 ((IntCC.NotEqual) (if (not (= x y)) #x01 #x00)) 4763 ((IntCC.SignedGreaterThan) (if (bvsgt x y) #x01 #x00)) 4764 ((IntCC.SignedGreaterThanOrEqual) (if (bvsge x y) #x01 #x00)) 4765 ((IntCC.SignedLessThan) (if (bvslt x y) #x01 #x00)) 4766 ((IntCC.SignedLessThanOrEqual) (if (bvsle x y) #x01 #x00)) 4767 ((IntCC.UnsignedGreaterThan) (if (bvugt x y) #x01 #x00)) 4768 ((IntCC.UnsignedGreaterThanOrEqual) (if (bvuge x y) #x01 #x00)) 4769 ((IntCC.UnsignedLessThan) (if (bvult x y) #x01 #x00)) 4770 ((IntCC.UnsignedLessThanOrEqual) (if (bvule x y) #x01 #x00))))) 4771 (require 4772 (or 4773 (= c (IntCC.Equal)) 4774 (= c (IntCC.NotEqual)) 4775 (= c (IntCC.UnsignedGreaterThanOrEqual)) 4776 (= c (IntCC.UnsignedGreaterThan)) 4777 (= c (IntCC.UnsignedLessThanOrEqual)) 4778 (= c (IntCC.UnsignedLessThan)) 4779 (= c (IntCC.SignedGreaterThanOrEqual)) 4780 (= c (IntCC.SignedGreaterThan)) 4781 (= c (IntCC.SignedLessThanOrEqual)) 4782 (= c (IntCC.SignedLessThan))) 4783 (or (= in_ty 8) 4784 (= in_ty 16) 4785 (= in_ty 32) 4786 (= in_ty 64)) 4787 (= in_ty (widthof x)) 4788 (= in_ty (widthof y)) 4789 (= out_ty 8))) 4790(instantiate lower_icmp_into_reg 4791 ((args (bv 8) (bv 8) (bv 8) Int Int) (ret (bv 8)) (canon (bv 8))) 4792 ((args (bv 8) (bv 16) (bv 16) Int Int) (ret (bv 8)) (canon (bv 16))) 4793 ((args (bv 8) (bv 32) (bv 32) Int Int) (ret (bv 8)) (canon (bv 32))) 4794 ((args (bv 8) (bv 64) (bv 64) Int Int) (ret (bv 8)) (canon (bv 64))) 4795) 4796(decl lower_icmp_into_reg (IntCC Value Value Type Type) ValueRegs) 4797(decl lower_icmp_into_flags (IntCC Value Value Type) FlagsAndCC) 4798 4799(spec (lower_icmp_const c x y in_ty) 4800 (provide 4801 (= result 4802 (concat (extract 67 64 4803 (if (or (= c (IntCC.SignedGreaterThanOrEqual)) 4804 (= c (IntCC.SignedGreaterThan)) 4805 (= c (IntCC.SignedLessThanOrEqual)) 4806 (= c (IntCC.SignedLessThan))) 4807 (if (<= in_ty 32) 4808 (subs 32 (sign_ext 64 x) y) 4809 (subs 64 (sign_ext 64 x) y)) 4810 (if (<= in_ty 32) 4811 (subs 32 (zero_ext 64 x) y) 4812 (subs 64 (zero_ext 64 x) y)))) 4813 c))) 4814 (require 4815 (or 4816 (= c (IntCC.Equal)) 4817 (= c (IntCC.NotEqual)) 4818 (= c (IntCC.UnsignedGreaterThanOrEqual)) 4819 (= c (IntCC.UnsignedGreaterThan)) 4820 (= c (IntCC.UnsignedLessThanOrEqual)) 4821 (= c (IntCC.UnsignedLessThan)) 4822 (= c (IntCC.SignedGreaterThanOrEqual)) 4823 (= c (IntCC.SignedGreaterThan)) 4824 (= c (IntCC.SignedLessThanOrEqual)) 4825 (= c (IntCC.SignedLessThan))) 4826 (or (= in_ty 32) (= in_ty 64)) 4827 (= in_ty (widthof x)))) 4828(instantiate lower_icmp_const 4829 ((args (bv 8) (bv 8) (bv 64) Int) (ret (bv 12)) (canon (bv 8))) 4830 ((args (bv 8) (bv 16) (bv 64) Int) (ret (bv 12)) (canon (bv 16))) 4831 ((args (bv 8) (bv 32) (bv 64) Int) (ret (bv 12)) (canon (bv 32))) 4832 ((args (bv 8) (bv 64) (bv 64) Int) (ret (bv 12)) (canon (bv 64))) 4833) 4834(decl lower_icmp_const (IntCC Value u64 Type) FlagsAndCC) 4835;; For most cases, `lower_icmp_into_flags` is the same as `lower_icmp`, 4836;; except for some I128 cases (see below). 4837(rule -1 (lower_icmp_into_flags cond x y ty) (lower_icmp cond x y ty)) 4838 4839;; Vectors. 4840;; `icmp` into flags for vectors is invalid. 4841(rule 1 (lower_icmp_into_reg cond x y in_ty @ (multi_lane _ _) _out_ty) 4842 (let ((cond Cond (cond_code cond)) 4843 (rn Reg (put_in_reg x)) 4844 (rm Reg (put_in_reg y))) 4845 (vec_cmp rn rm in_ty cond))) 4846 4847;; Determines the appropriate extend op given the value type and the given ArgumentExtension. 4848(spec (lower_extend_op ty b) 4849 (provide 4850 (= result 4851 (switch ty 4852 (8 (switch b ((ArgumentExtension.Sext) (ExtendOp.SXTB)) 4853 ((ArgumentExtension.Uext) (ExtendOp.UXTB)))) 4854 (16 (switch b ((ArgumentExtension.Sext) (ExtendOp.SXTH)) 4855 ((ArgumentExtension.Uext) (ExtendOp.UXTH))))))) 4856 (require (or (= ty 8) (= ty 16) (= ty 32) (= ty 64)))) 4857(decl lower_extend_op (Type ArgumentExtension) ExtendOp) 4858(rule (lower_extend_op $I8 (ArgumentExtension.Sext)) (ExtendOp.SXTB)) 4859(rule (lower_extend_op $I16 (ArgumentExtension.Sext)) (ExtendOp.SXTH)) 4860(rule (lower_extend_op $I8 (ArgumentExtension.Uext)) (ExtendOp.UXTB)) 4861(rule (lower_extend_op $I16 (ArgumentExtension.Uext)) (ExtendOp.UXTH)) 4862 4863;; Integers <= 64-bits. 4864(rule lower_icmp_into_reg_8_16_32_64 -2 (lower_icmp_into_reg cond rn rm in_ty out_ty) 4865 (if (ty_int_ref_scalar_64 in_ty)) 4866 (let ((cc Cond (cond_code cond))) 4867 (flags_and_cc_to_bool (lower_icmp cond rn rm in_ty)))) 4868 4869(rule lower_icmp_8_16_signed 1 (lower_icmp cond rn rm (fits_in_16 ty)) 4870 (if (signed_cond_code cond)) 4871 (let ((rn Reg (put_in_reg_sext32 rn))) 4872 (flags_and_cc (cmp_extend (operand_size ty) rn rm (lower_extend_op ty (ArgumentExtension.Sext))) cond))) 4873(rule lower_icmp_8_16_unsigned_imm -1 (lower_icmp cond rn (imm12_from_value rm) (fits_in_16 ty)) 4874 (let ((rn Reg (put_in_reg_zext32 rn))) 4875 (flags_and_cc (cmp_imm (operand_size ty) rn rm) cond))) 4876(rule lower_icmp_8_16_unsigned -2 (lower_icmp cond rn rm (fits_in_16 ty)) 4877 (let ((rn Reg (put_in_reg_zext32 rn))) 4878 (flags_and_cc (cmp_extend (operand_size ty) rn rm (lower_extend_op ty (ArgumentExtension.Uext))) cond))) 4879(rule lower_icmp_32_64_const -3 (lower_icmp cond rn (u64_from_iconst c) ty) 4880 (if (ty_int_ref_scalar_64 ty)) 4881 (lower_icmp_const cond rn c ty)) 4882(rule lower_icmp_32_64 -4 (lower_icmp cond rn rm ty) 4883 (if (ty_int_ref_scalar_64 ty)) 4884 (flags_and_cc (cmp (operand_size ty) rn rm) cond)) 4885 4886;; We get better encodings when testing against an immediate that's even instead 4887;; of odd, so rewrite comparisons to use even immediates: 4888;; 4889;; A >= B + 1 4890;; ==> A - 1 >= B 4891;; ==> A > B 4892(rule lower_icmp_const_32_64_ugte (lower_icmp_const (IntCC.UnsignedGreaterThanOrEqual) a b ty) 4893 (if (ty_int_ref_scalar_64 ty)) 4894 (if-let true (u64_is_odd b)) 4895 (if-let (imm12_from_u64 imm) (u64_wrapping_sub b 1)) 4896 (flags_and_cc (cmp_imm (operand_size ty) a imm) (IntCC.UnsignedGreaterThan))) 4897 4898(rule lower_icmp_const_32_64_sgte (lower_icmp_const (IntCC.SignedGreaterThanOrEqual) a b ty) 4899 (if (ty_int_ref_scalar_64 ty)) 4900 (if-let true (u64_is_odd b)) 4901 (if-let (imm12_from_u64 imm) (u64_wrapping_sub b 1)) 4902 (flags_and_cc (cmp_imm (operand_size ty) a imm) (IntCC.SignedGreaterThan))) 4903 4904(rule lower_icmp_const_32_64_imm -1 (lower_icmp_const cond rn (imm12_from_u64 c) ty) 4905 (if (ty_int_ref_scalar_64 ty)) 4906 (flags_and_cc (cmp_imm (operand_size ty) rn c) cond)) 4907(rule lower_icmp_const_32_64 -2 (lower_icmp_const cond rn c ty) 4908 (if (ty_int_ref_scalar_64 ty)) 4909 (flags_and_cc (cmp (operand_size ty) rn (imm ty (ImmExtend.Zero) c)) cond)) 4910 4911 4912;; 128-bit integers. 4913(rule (lower_icmp_into_reg cond @ (IntCC.Equal) rn rm $I128 $I8) 4914 (let ((cc Cond (cond_code cond))) 4915 (flags_and_cc_to_bool 4916 (lower_icmp cond rn rm $I128)))) 4917(rule (lower_icmp_into_reg cond @ (IntCC.NotEqual) rn rm $I128 $I8) 4918 (let ((cc Cond (cond_code cond))) 4919 (flags_and_cc_to_bool 4920 (lower_icmp cond rn rm $I128)))) 4921 4922;; cmp lhs_lo, rhs_lo 4923;; ccmp lhs_hi, rhs_hi, #0, eq 4924(decl lower_icmp_i128_eq_ne (Value Value) ProducesFlags) 4925(rule (lower_icmp_i128_eq_ne lhs rhs) 4926 (let ((lhs ValueRegs (put_in_regs lhs)) 4927 (rhs ValueRegs (put_in_regs rhs)) 4928 (lhs_lo Reg (value_regs_get lhs 0)) 4929 (lhs_hi Reg (value_regs_get lhs 1)) 4930 (rhs_lo Reg (value_regs_get rhs 0)) 4931 (rhs_hi Reg (value_regs_get rhs 1)) 4932 (cmp_inst ProducesFlags (cmp (OperandSize.Size64) lhs_lo rhs_lo))) 4933 (ccmp (OperandSize.Size64) lhs_hi rhs_hi 4934 (nzcv false false false false) (Cond.Eq) cmp_inst))) 4935 4936(rule (lower_icmp (IntCC.Equal) lhs rhs $I128) 4937 (flags_and_cc (lower_icmp_i128_eq_ne lhs rhs) (IntCC.Equal))) 4938(rule (lower_icmp (IntCC.NotEqual) lhs rhs $I128) 4939 (flags_and_cc (lower_icmp_i128_eq_ne lhs rhs) (IntCC.NotEqual))) 4940 4941;; cmp lhs_lo, rhs_lo 4942;; cset tmp1, unsigned_cond 4943;; cmp lhs_hi, rhs_hi 4944;; cset tmp2, cond 4945;; csel dst, tmp1, tmp2, eq 4946(rule -1 (lower_icmp_into_reg cond lhs rhs $I128 $I8) 4947 (let ((unsigned_cond Cond (cond_code (intcc_unsigned cond))) 4948 (cond Cond (cond_code cond)) 4949 (lhs ValueRegs (put_in_regs lhs)) 4950 (rhs ValueRegs (put_in_regs rhs)) 4951 (lhs_lo Reg (value_regs_get lhs 0)) 4952 (lhs_hi Reg (value_regs_get lhs 1)) 4953 (rhs_lo Reg (value_regs_get rhs 0)) 4954 (rhs_hi Reg (value_regs_get rhs 1)) 4955 (tmp1 Reg (with_flags_reg (cmp (OperandSize.Size64) lhs_lo rhs_lo) 4956 (materialize_bool_result unsigned_cond)))) 4957 (with_flags (cmp (OperandSize.Size64) lhs_hi rhs_hi) 4958 (lower_icmp_i128_consumer cond tmp1)))) 4959 4960(decl lower_icmp_i128_consumer (Cond Reg) ConsumesFlags) 4961(rule (lower_icmp_i128_consumer cond tmp1) 4962 (let ((tmp2 WritableReg (temp_writable_reg $I64)) 4963 (dst WritableReg (temp_writable_reg $I64))) 4964 (ConsumesFlags.ConsumesFlagsTwiceReturnsValueRegs 4965 (MInst.CSet tmp2 cond) 4966 (MInst.CSel dst (Cond.Eq) tmp1 tmp2) 4967 (value_reg dst)))) 4968 4969; Recursion: bounded since recursive calls reduce type width (128-bit to 64-bit). 4970(decl rec lower_bmask (Type Type ValueRegs) ValueRegs) 4971 4972 4973;; For conversions that exactly fit a register, we can use csetm. 4974;; 4975;; cmp val, #0 4976;; csetm res, ne 4977(rule 0 4978 (lower_bmask (fits_in_64 _) (ty_32_or_64 in_ty) val) 4979 (with_flags_reg 4980 (cmp_imm (operand_size in_ty) (value_regs_get val 0) (u8_into_imm12 0)) 4981 (csetm (Cond.Ne)))) 4982 4983;; For conversions from a 128-bit value into a 64-bit or smaller one, we or the 4984;; two registers of the 128-bit value together, and then recurse with the 4985;; combined value as a 64-bit test. 4986;; 4987;; orr val, lo, hi 4988;; cmp val, #0 4989;; csetm res, ne 4990(rule 1 4991 (lower_bmask (fits_in_64 ty) $I128 val) 4992 (let ((lo Reg (value_regs_get val 0)) 4993 (hi Reg (value_regs_get val 1)) 4994 (combined Reg (orr $I64 lo hi))) 4995 (lower_bmask ty $I64 (value_reg combined)))) 4996 4997;; For converting from any type into i128, duplicate the result of 4998;; converting to i64. 4999(rule 2 5000 (lower_bmask $I128 in_ty val) 5001 (let ((res ValueRegs (lower_bmask $I64 in_ty val)) 5002 (res Reg (value_regs_get res 0))) 5003 (value_regs res res))) 5004 5005;; For conversions smaller than a register, we need to mask off the high bits, and then 5006;; we can recurse into the general case. 5007;; 5008;; and tmp, val, #ty_mask 5009;; cmp tmp, #0 5010;; csetm res, ne 5011(rule 3 5012 (lower_bmask out_ty (fits_in_16 in_ty) val) 5013 ; This if-let can't fail due to ty_mask always producing 8/16 consecutive 1s. 5014 (if-let mask_bits (imm_logic_from_u64 $I32 (ty_mask in_ty))) 5015 (let ((masked Reg (and_imm $I32 (value_regs_get val 0) mask_bits))) 5016 (lower_bmask out_ty $I32 masked))) 5017 5018;; Exceptional `lower_icmp_into_flags` rules. 5019;; We need to guarantee that the flags for `cond` are correct, so we 5020;; compare `dst` with 1. 5021(rule (lower_icmp_into_flags cond @ (IntCC.SignedGreaterThanOrEqual) lhs rhs $I128) 5022 (let ((dst ValueRegs (lower_icmp_into_reg cond lhs rhs $I128 $I8)) 5023 (dst Reg (value_regs_get dst 0)) 5024 (tmp Reg (imm $I64 (ImmExtend.Sign) 1))) ;; mov tmp, #1 5025 (flags_and_cc (cmp (OperandSize.Size64) dst tmp) cond))) 5026(rule (lower_icmp_into_flags cond @ (IntCC.UnsignedGreaterThanOrEqual) lhs rhs $I128) 5027 (let ((dst ValueRegs (lower_icmp_into_reg cond lhs rhs $I128 $I8)) 5028 (dst Reg (value_regs_get dst 0)) 5029 (tmp Reg (imm $I64 (ImmExtend.Zero) 1))) 5030 (flags_and_cc (cmp (OperandSize.Size64) dst tmp) cond))) 5031(rule (lower_icmp_into_flags cond @ (IntCC.SignedLessThanOrEqual) lhs rhs $I128) 5032 (let ((dst ValueRegs (lower_icmp_into_reg cond lhs rhs $I128 $I8)) 5033 (dst Reg (value_regs_get dst 0)) 5034 (tmp Reg (imm $I64 (ImmExtend.Sign) 1))) 5035 (flags_and_cc (cmp (OperandSize.Size64) tmp dst) cond))) 5036(rule (lower_icmp_into_flags cond @ (IntCC.UnsignedLessThanOrEqual) lhs rhs $I128) 5037 (let ((dst ValueRegs (lower_icmp_into_reg cond lhs rhs $I128 $I8)) 5038 (dst Reg (value_regs_get dst 0)) 5039 (tmp Reg (imm $I64 (ImmExtend.Zero) 1))) 5040 (flags_and_cc (cmp (OperandSize.Size64) tmp dst) cond))) 5041;; For strict comparisons, we compare with 0. 5042(rule (lower_icmp_into_flags cond @ (IntCC.SignedGreaterThan) lhs rhs $I128) 5043 (let ((dst ValueRegs (lower_icmp_into_reg cond lhs rhs $I128 $I8)) 5044 (dst Reg (value_regs_get dst 0))) 5045 (flags_and_cc (cmp (OperandSize.Size64) dst (zero_reg)) cond))) 5046(rule (lower_icmp_into_flags cond @ (IntCC.UnsignedGreaterThan) lhs rhs $I128) 5047 (let ((dst ValueRegs (lower_icmp_into_reg cond lhs rhs $I128 $I8)) 5048 (dst Reg (value_regs_get dst 0))) 5049 (flags_and_cc (cmp (OperandSize.Size64) dst (zero_reg)) cond))) 5050(rule (lower_icmp_into_flags cond @ (IntCC.SignedLessThan) lhs rhs $I128) 5051 (let ((dst ValueRegs (lower_icmp_into_reg cond lhs rhs $I128 $I8)) 5052 (dst Reg (value_regs_get dst 0))) 5053 (flags_and_cc (cmp (OperandSize.Size64) (zero_reg) dst) cond))) 5054(rule (lower_icmp_into_flags cond @ (IntCC.UnsignedLessThan) lhs rhs $I128) 5055 (let ((dst ValueRegs (lower_icmp_into_reg cond lhs rhs $I128 $I8)) 5056 (dst Reg (value_regs_get dst 0))) 5057 (flags_and_cc (cmp (OperandSize.Size64) (zero_reg) dst) cond))) 5058 5059;; Helpers for generating select instruction sequences. 5060(decl lower_select (ProducesFlags Cond Type Value Value) ValueRegs) 5061(rule 2 (lower_select flags cond (ty_scalar_float (fits_in_64 ty)) rn rm) 5062 (with_flags flags (fpu_csel ty cond rn rm))) 5063(rule 4 (lower_select flags cond $F128 rn rm) 5064 (with_flags flags (vec_csel cond rn rm))) 5065(rule 3 (lower_select flags cond (ty_vec128 ty) rn rm) 5066 (with_flags flags (vec_csel cond rn rm))) 5067(rule (lower_select flags cond ty rn rm) 5068 (if (ty_vec64 ty)) 5069 (with_flags flags (fpu_csel $F64 cond rn rm))) 5070(rule 4 (lower_select flags cond $I128 rn rm) 5071 (let ((dst_lo WritableReg (temp_writable_reg $I64)) 5072 (dst_hi WritableReg (temp_writable_reg $I64)) 5073 (rn ValueRegs (put_in_regs rn)) 5074 (rm ValueRegs (put_in_regs rm)) 5075 (rn_lo Reg (value_regs_get rn 0)) 5076 (rn_hi Reg (value_regs_get rn 1)) 5077 (rm_lo Reg (value_regs_get rm 0)) 5078 (rm_hi Reg (value_regs_get rm 1))) 5079 (with_flags flags 5080 (ConsumesFlags.ConsumesFlagsTwiceReturnsValueRegs 5081 (MInst.CSel dst_lo cond rn_lo rm_lo) 5082 (MInst.CSel dst_hi cond rn_hi rm_hi) 5083 (value_regs dst_lo dst_hi))))) 5084(rule 1 (lower_select flags cond ty rn rm) 5085 (if (ty_int_ref_scalar_64 ty)) 5086 (with_flags flags (csel cond rn rm))) 5087 5088;; Helper for emitting `MInst.Jump` instructions. 5089(decl aarch64_jump (BranchTarget) SideEffectNoResult) 5090(rule (aarch64_jump target) 5091 (SideEffectNoResult.Inst (MInst.Jump target))) 5092 5093;; Helper for emitting `MInst.JTSequence` instructions. 5094;; Emit the compound instruction that does: 5095;; 5096;; b.hs default 5097;; csel rB, xzr, rIndex, hs 5098;; csdb 5099;; adr rA, jt 5100;; ldrsw rB, [rA, rB, uxtw #2] 5101;; add rA, rA, rB 5102;; br rA 5103;; [jt entries] 5104;; 5105;; This must be *one* instruction in the vcode because 5106;; we cannot allow regalloc to insert any spills/fills 5107;; in the middle of the sequence; otherwise, the ADR's 5108;; PC-rel offset to the jumptable would be incorrect. 5109;; (The alternative is to introduce a relocation pass 5110;; for inlined jumptables, which is much worse, IMHO.) 5111(decl jt_sequence (Reg MachLabel BoxVecMachLabel) ConsumesFlags) 5112(rule (jt_sequence ridx default targets) 5113 (let ((rtmp1 WritableReg (temp_writable_reg $I64)) 5114 (rtmp2 WritableReg (temp_writable_reg $I64))) 5115 (ConsumesFlags.ConsumesFlagsSideEffect 5116 (MInst.JTSequence default targets ridx rtmp1 rtmp2)))) 5117 5118;; Helper for emitting `MInst.CondBr` instructions. 5119(decl cond_br (BranchTarget BranchTarget CondBrKind) ConsumesFlags) 5120(rule (cond_br taken not_taken kind) 5121 (ConsumesFlags.ConsumesFlagsSideEffect 5122 (MInst.CondBr taken not_taken kind))) 5123 5124;; Helper for emitting `MInst.TestBitAndBranch` instructions. 5125(decl test_branch (TestBitAndBranchKind BranchTarget BranchTarget Reg u8) SideEffectNoResult) 5126(rule (test_branch kind taken not_taken rn bit) 5127 (SideEffectNoResult.Inst (MInst.TestBitAndBranch kind taken not_taken rn bit))) 5128 5129;; Helper for emitting `tbnz` instructions. 5130(decl tbnz (BranchTarget BranchTarget Reg u8) SideEffectNoResult) 5131(rule (tbnz taken not_taken rn bit) 5132 (test_branch (TestBitAndBranchKind.NZ) taken not_taken rn bit)) 5133 5134;; Helper for emitting `tbz` instructions. 5135(decl tbz (BranchTarget BranchTarget Reg u8) SideEffectNoResult) 5136(rule (tbz taken not_taken rn bit) 5137 (test_branch (TestBitAndBranchKind.Z) taken not_taken rn bit)) 5138 5139;; Helper for emitting `MInst.MovToNZCV` instructions. 5140(decl mov_to_nzcv (Reg) ProducesFlags) 5141(rule (mov_to_nzcv rn) 5142 (ProducesFlags.ProducesFlagsSideEffect 5143 (MInst.MovToNZCV rn))) 5144 5145;; Helper for emitting `MInst.EmitIsland` instructions. 5146(decl emit_island (CodeOffset) SideEffectNoResult) 5147(rule (emit_island needed_space) 5148 (SideEffectNoResult.Inst 5149 (MInst.EmitIsland needed_space))) 5150 5151;; Helper for emitting `br_table` sequences. 5152(decl br_table_impl (u64 Reg MachLabel BoxVecMachLabel) Unit) 5153(rule (br_table_impl (imm12_from_u64 jt_size) ridx default targets) 5154 (emit_side_effect (with_flags_side_effect 5155 (cmp_imm (OperandSize.Size32) ridx jt_size) 5156 (jt_sequence ridx default targets)))) 5157(rule -1 (br_table_impl jt_size ridx default targets) 5158 (let ((jt_size Reg (imm $I64 (ImmExtend.Zero) jt_size))) 5159 (emit_side_effect (with_flags_side_effect 5160 (cmp (OperandSize.Size32) ridx jt_size) 5161 (jt_sequence ridx default targets))))) 5162 5163;; Helper for emitting the `uzp1` instruction 5164(decl vec_uzp1 (Reg Reg VectorSize) Reg) 5165(rule (vec_uzp1 rn rm size) (vec_rrr (VecALUOp.Uzp1) rn rm size)) 5166 5167;; Helper for emitting the `uzp2` instruction 5168(decl vec_uzp2 (Reg Reg VectorSize) Reg) 5169(rule (vec_uzp2 rn rm size) (vec_rrr (VecALUOp.Uzp2) rn rm size)) 5170 5171;; Helper for emitting the `zip1` instruction 5172(decl vec_zip1 (Reg Reg VectorSize) Reg) 5173(rule (vec_zip1 rn rm size) (vec_rrr (VecALUOp.Zip1) rn rm size)) 5174 5175;; Helper for emitting the `zip2` instruction 5176(decl vec_zip2 (Reg Reg VectorSize) Reg) 5177(rule (vec_zip2 rn rm size) (vec_rrr (VecALUOp.Zip2) rn rm size)) 5178 5179;; Helper for emitting the `trn1` instruction 5180(decl vec_trn1 (Reg Reg VectorSize) Reg) 5181(rule (vec_trn1 rn rm size) (vec_rrr (VecALUOp.Trn1) rn rm size)) 5182 5183;; Helper for emitting the `trn2` instruction 5184(decl vec_trn2 (Reg Reg VectorSize) Reg) 5185(rule (vec_trn2 rn rm size) (vec_rrr (VecALUOp.Trn2) rn rm size)) 5186 5187;; Helper for creating a zero value `ASIMDMovModImm` immediate. 5188(decl asimd_mov_mod_imm_zero (ScalarSize) ASIMDMovModImm) 5189(extern constructor asimd_mov_mod_imm_zero asimd_mov_mod_imm_zero) 5190 5191;; Helper for fallibly creating an `ASIMDMovModImm` immediate from its parts. 5192(decl pure partial asimd_mov_mod_imm_from_u64 (u64 ScalarSize) ASIMDMovModImm) 5193(extern constructor asimd_mov_mod_imm_from_u64 asimd_mov_mod_imm_from_u64) 5194 5195;; Helper for fallibly creating an `ASIMDFPModImm` immediate from its parts. 5196(decl pure partial asimd_fp_mod_imm_from_u64 (u64 ScalarSize) ASIMDFPModImm) 5197(extern constructor asimd_fp_mod_imm_from_u64 asimd_fp_mod_imm_from_u64) 5198 5199;; Helper for creating a `VecDupFPImm` instruction 5200(decl vec_dup_fp_imm (ASIMDFPModImm VectorSize) Reg) 5201(rule (vec_dup_fp_imm imm size) 5202 (let ((dst WritableReg (temp_writable_reg $I8X16)) 5203 (_ Unit (emit (MInst.VecDupFPImm dst imm size)))) 5204 dst)) 5205 5206;; Helper for creating a `FpuLoad64` instruction 5207(decl fpu_load64 (AMode MemFlags) Reg) 5208(rule (fpu_load64 amode flags) 5209 (let ((dst WritableReg (temp_writable_reg $I8X16)) 5210 (_ Unit (emit (MInst.FpuLoad64 dst amode flags)))) 5211 dst)) 5212 5213;; Helper for creating a `FpuLoad128` instruction 5214(decl fpu_load128 (AMode MemFlags) Reg) 5215(rule (fpu_load128 amode flags) 5216 (let ((dst WritableReg (temp_writable_reg $I8X16)) 5217 (_ Unit (emit (MInst.FpuLoad128 dst amode flags)))) 5218 dst)) 5219 5220;; Helper for creating an `LabelAddress` instruction. 5221(decl a64_label_address (MachLabel) Reg) 5222(rule (a64_label_address label) 5223 (let ((dst WritableReg (temp_writable_reg $I64)) 5224 (_ Unit (emit (MInst.LabelAddress dst label)))) 5225 dst)) 5226 5227;; Helper for creating a `SequencePoint` instruction. 5228(decl a64_sequence_point () SideEffectNoResult) 5229(rule (a64_sequence_point) 5230 (SideEffectNoResult.Inst (MInst.SequencePoint))) 5231