1;; Instruction formats. 2(type MInst 3 (enum 4 ;; A no-op of zero size. 5 (Nop0) 6 (Nop4) 7 8 ;; load immediate 9 (Lui 10 (rd WritableReg) 11 (imm Imm20)) 12 13 (LoadInlineConst 14 (rd WritableReg) 15 (ty Type) 16 (imm u64)) 17 18 (Auipc 19 (rd WritableReg) 20 (imm Imm20)) 21 22 (Fli 23 (width FpuOPWidth) 24 (imm FliConstant) 25 (rd WritableReg)) 26 27 ;; An ALU operation with one register sources and a register destination. 28 (FpuRR 29 (alu_op FpuOPRR) 30 (width FpuOPWidth) 31 (frm FRM) 32 (rd WritableReg) 33 (rs Reg)) 34 35 36 ;; An ALU operation with two register sources and a register destination. 37 (AluRRR 38 (alu_op AluOPRRR) 39 (rd WritableReg) 40 (rs1 Reg) 41 (rs2 Reg)) 42 43 ;; An ALU operation with two register sources and a register destination. 44 (FpuRRR 45 (alu_op FpuOPRRR) 46 (width FpuOPWidth) 47 (frm FRM) 48 (rd WritableReg) 49 (rs1 Reg) 50 (rs2 Reg)) 51 52 ;; An ALU operation with three register sources and a register destination. 53 (FpuRRRR 54 (alu_op FpuOPRRRR) 55 (width FpuOPWidth) 56 (frm FRM) 57 (rd WritableReg) 58 (rs1 Reg) 59 (rs2 Reg) 60 (rs3 Reg)) 61 62 ;; An ALU operation with a register source and an immediate-12 source, and a register 63 ;; destination. 64 (AluRRImm12 65 (alu_op AluOPRRI) 66 (rd WritableReg) 67 (rs Reg) 68 (imm12 Imm12)) 69 70 ;; A CSR Reading or Writing instruction with a register source and a register destination. 71 (CsrReg 72 (op CsrRegOP) 73 (rd WritableReg) 74 (rs Reg) 75 (csr CSR)) 76 77 ;; A CSR Writing instruction with an immediate source and a register destination. 78 (CsrImm 79 (op CsrImmOP) 80 (rd WritableReg) 81 (imm UImm5) 82 (csr CSR)) 83 84 ;; An load 85 (Load 86 (rd WritableReg) 87 (op LoadOP) 88 (flags MemFlags) 89 (from AMode)) 90 ;; An Store 91 (Store 92 (to AMode) 93 (op StoreOP) 94 (flags MemFlags) 95 (src Reg)) 96 97 ;; A pseudo-instruction that captures register arguments in vregs. 98 (Args 99 (args VecArgPair)) 100 101 ;; A pseudo-instruction that moves vregs to return registers. 102 (Rets 103 (rets VecRetPair)) 104 105 (Ret) 106 107 (Extend 108 (rd WritableReg) 109 (rn Reg) 110 (signed bool) 111 (from_bits u8) 112 (to_bits u8)) 113 114 ;; A machine direct-call instruction. 115 (Call (info BoxCallInfo)) 116 117 ;; A machine indirect-call instruction. 118 (CallInd (info BoxCallIndInfo)) 119 120 ;; A direct return-call macro instruction. 121 (ReturnCall (info BoxReturnCallInfo)) 122 123 ;; An indirect return-call macro instruction. 124 (ReturnCallInd (info BoxReturnCallIndInfo)) 125 126 ;; Emits a trap with the given trap code if the comparison succeeds 127 (TrapIf 128 (rs1 Reg) 129 (rs2 Reg) 130 (cc IntCC) 131 (trap_code TrapCode)) 132 133 (Jal 134 ;; (rd WritableReg) don't use 135 (label MachLabel)) 136 137 (CondBr 138 (taken CondBrTarget) 139 (not_taken CondBrTarget) 140 (kind IntegerCompare)) 141 142 ;; Load an inline symbol reference. 143 (LoadExtNameGot 144 (rd WritableReg) 145 (name BoxExternalName)) 146 (LoadExtNameNear 147 (rd WritableReg) 148 (name BoxExternalName) 149 (offset i64)) 150 (LoadExtNameFar 151 (rd WritableReg) 152 (name BoxExternalName) 153 (offset i64)) 154 155 ;; Load a TLS symbol address 156 (ElfTlsGetAddr 157 (rd WritableReg) 158 (name BoxExternalName)) 159 160 ;; Load address referenced by `mem` into `rd`. 161 (LoadAddr 162 (rd WritableReg) 163 (mem AMode)) 164 165 ;; A MOV instruction. These are encoded as OrR's (AluRRR form) but we 166 ;; keep them separate at the `Inst` level for better pretty-printing 167 ;; and faster `is_move()` logic. 168 (Mov 169 (rd WritableReg) 170 (rm Reg) 171 (ty Type)) 172 173 ;; A MOV instruction, but where the source register is a non-allocatable 174 ;; PReg. It's important that the register be non-allocatable, as regalloc2 175 ;; will not see it as used. 176 (MovFromPReg 177 (rd WritableReg) 178 (rm PReg)) 179 180 (Fence 181 (pred FenceReq) 182 (succ FenceReq)) 183 184 (EBreak) 185 186 ;; An instruction guaranteed to always be undefined and to trigger an illegal instruction at 187 ;; runtime. 188 (Udf 189 (trap_code TrapCode)) 190 ;; a jump and link register operation 191 (Jalr 192 ;;Plain unconditional jumps (assembler pseudo-op J) are encoded as a JAL with rd=x0. 193 (rd WritableReg) 194 (base Reg) 195 (offset Imm12)) 196 197 ;; atomic operations. 198 (Atomic 199 (op AtomicOP) 200 (rd WritableReg) 201 (addr Reg) 202 (src Reg) 203 (amo AMO)) 204 ;; an atomic store 205 (AtomicStore 206 (src Reg) 207 (ty Type) 208 (p Reg)) 209 ;; an atomic load. 210 (AtomicLoad 211 (rd WritableReg) 212 (ty Type) 213 (p Reg)) 214 215 ;; an atomic nand need using loop to implement. 216 (AtomicRmwLoop 217 (offset Reg) 218 (op AtomicRmwOp) 219 (dst WritableReg) 220 (ty Type) 221 (p Reg) 222 (x Reg) 223 (t0 WritableReg)) 224 225 ;; select x or y base on condition 226 (Select 227 (dst WritableValueRegs) 228 (condition IntegerCompare) 229 (x ValueRegs) 230 (y ValueRegs)) 231 232 (BrTable 233 (index Reg) 234 (tmp1 WritableReg) 235 (tmp2 WritableReg) 236 (targets VecMachLabel)) 237 238 ;; atomic compare and set operation 239 (AtomicCas 240 (offset Reg) 241 (t0 WritableReg) 242 (dst WritableReg) 243 (e Reg) 244 (addr Reg) 245 (v Reg) 246 (ty Type)) 247 248 (RawData (data VecU8)) 249 250 ;; An unwind pseudo-instruction. 251 (Unwind 252 (inst UnwindInst)) 253 254 ;; A dummy use, useful to keep a value alive. 255 (DummyUse 256 (reg Reg)) 257 258 ;; A pseudoinstruction that loads the address of a label. 259 (LabelAddress (dst WritableReg) 260 (label MachLabel)) 261 262 ;; popcnt if target doesn't support extension B 263 ;; use iteration to implement. 264 (Popcnt 265 (sum WritableReg) 266 (step WritableReg) 267 (tmp WritableReg) 268 (rs Reg) 269 (ty Type)) 270 271 ;;; counting leading or trailing zeros. 272 (Cltz 273 ;; leading or trailing. 274 (leading bool) 275 (sum WritableReg) 276 (step WritableReg) 277 (tmp WritableReg) 278 (rs Reg) 279 (ty Type)) 280 281 (Brev8 282 (rs Reg) 283 (ty Type) 284 (step WritableReg) 285 (tmp WritableReg) 286 (tmp2 WritableReg) 287 (rd WritableReg)) 288 (StackProbeLoop 289 (guard_size u32) 290 (probe_count u32) 291 (tmp WritableReg)) 292 293 (VecAluRRRR 294 (op VecAluOpRRRR) 295 (vd WritableReg) 296 (vd_src Reg) 297 (vs2 Reg) 298 (vs1 Reg) 299 (mask VecOpMasking) 300 (vstate VState)) 301 302 (VecAluRRRImm5 303 (op VecAluOpRRRImm5) 304 (vd WritableReg) 305 (vd_src Reg) 306 (vs2 Reg) 307 (imm Imm5) 308 (mask VecOpMasking) 309 (vstate VState)) 310 311 (VecAluRRR 312 (op VecAluOpRRR) 313 (vd WritableReg) 314 (vs2 Reg) 315 (vs1 Reg) 316 (mask VecOpMasking) 317 (vstate VState)) 318 319 (VecAluRRImm5 320 (op VecAluOpRRImm5) 321 (vd WritableReg) 322 (vs2 Reg) 323 (imm Imm5) 324 (mask VecOpMasking) 325 (vstate VState)) 326 327 (VecAluRR 328 (op VecAluOpRR) 329 (vd WritableReg) 330 (vs Reg) 331 (mask VecOpMasking) 332 (vstate VState)) 333 334 (VecAluRImm5 335 (op VecAluOpRImm5) 336 (vd WritableReg) 337 (imm Imm5) 338 (mask VecOpMasking) 339 (vstate VState)) 340 341 (VecSetState 342 (rd WritableReg) 343 (vstate VState)) 344 345 (VecLoad 346 (eew VecElementWidth) 347 (to WritableReg) 348 (from VecAMode) 349 (flags MemFlags) 350 (mask VecOpMasking) 351 (vstate VState)) 352 353 (VecStore 354 (eew VecElementWidth) 355 (to VecAMode) 356 (from Reg) 357 (flags MemFlags) 358 (mask VecOpMasking) 359 (vstate VState)) 360 361 (EmitIsland 362 ;; The needed space before the next deadline. 363 (needed_space u32)) 364 365 ;; A pseudoinstruction that serves as a sequence point. 366 (SequencePoint) 367)) 368 369(type AtomicOP (enum 370 (LrW) 371 (ScW) 372 (AmoswapW) 373 (AmoaddW) 374 (AmoxorW) 375 (AmoandW) 376 (AmoorW) 377 (AmominW) 378 (AmomaxW) 379 (AmominuW) 380 (AmomaxuW) 381 (LrD) 382 (ScD) 383 (AmoswapD) 384 (AmoaddD) 385 (AmoxorD) 386 (AmoandD) 387 (AmoorD) 388 (AmominD) 389 (AmomaxD) 390 (AmominuD) 391 (AmomaxuD) 392)) 393 394(type FpuOPRRRR (enum 395 (Fmadd) 396 (Fmsub) 397 (Fnmsub) 398 (Fnmadd) 399)) 400 401(type FClassResult (enum 402 ;;0 rs1 is −∞. 403 (NegInfinite) 404 ;; 1 rs1 is a negative normal number. 405 (NegNormal) 406 ;; 2 rs1 is a negative subnormal number. 407 (NegSubNormal) 408 ;; 3 rs1 is −0. 409 (NegZero) 410 ;; 4 rs1 is +0. 411 (PosZero) 412 ;; 5 rs1 is a positive subnormal number. 413 (PosSubNormal) 414 ;; 6 rs1 is a positive normal number. 415 (PosNormal) 416 ;; 7 rs1 is +∞. 417 (PosInfinite) 418 ;; 8 rs1 is a signaling NaN. 419 (SNaN) 420 ;; 9 rs1 is a quiet NaN. 421 (QNaN) 422)) 423 424(type FliConstant (primitive FliConstant)) 425 426(type FpuOPWidth (enum 427 (S) 428 (D) 429 (H) 430 (Q) 431)) 432 433(decl pure fpu_op_width_from_ty (Type) FpuOPWidth) 434(extern constructor fpu_op_width_from_ty fpu_op_width_from_ty) 435(convert Type FpuOPWidth fpu_op_width_from_ty) 436 437(type FpuOPRR (enum 438 (Fsqrt) ;; fsqrt.{fmt} 439 (Fclass) ;; fclass.{fmt} 440 (FcvtWFmt) ;; fcvt.w.{fmt} 441 (FcvtWuFmt) ;; fcvt.wu.{fmt} 442 (FcvtLFmt) ;; fcvt.l.{fmt} 443 (FcvtLuFmt) ;; fcvt.lu.{fmt} 444 (FcvtFmtW) ;; fcvt.{fmt}.w 445 (FcvtFmtWu) ;; fcvt.{fmt}.wu 446 (FcvtFmtL) ;; fcvt.{fmt}.l 447 (FcvtFmtLu) ;; fcvt.{fmt}.lu 448 (FmvXFmt) ;; fmv.x.{fmt} 449 (FmvFmtX) ;; fmv.{fmt}.x 450 (FcvtSD) ;; fcvt.s.d 451 (FcvtDS) ;; fcvt.d.s 452 453 ;; Zfa Extension 454 (Fround) ;; fround.{fmt} 455)) 456 457(type LoadOP (enum 458 (Lb) 459 (Lh) 460 (Lw) 461 (Lbu) 462 (Lhu) 463 (Lwu) 464 (Ld) 465 (Flh) 466 (Flw) 467 (Fld) 468)) 469 470(type StoreOP (enum 471 (Sb) 472 (Sh) 473 (Sw) 474 (Sd) 475 (Fsh) 476 (Fsw) 477 (Fsd) 478)) 479 480(type AluOPRRR (enum 481 ;; base set 482 (Add) 483 (Sub) 484 (Sll) 485 (Slt) 486 (SltU) 487 (Sgt) 488 (Sgtu) 489 (Xor) 490 (Srl) 491 (Sra) 492 (Or) 493 (And) 494 495 ;; RV64I Base Instruction Set (in addition to RV32I) 496 (Addw) 497 (Subw) 498 (Sllw) 499 (Srlw) 500 (Sraw) 501 502 503 ;;RV32M Standard Extension 504 (Mul) 505 (Mulh) 506 (Mulhsu) 507 (Mulhu) 508 (Div) 509 (DivU) 510 (Rem) 511 (RemU) 512 513 ;; RV64M Standard Extension (in addition to RV32M) 514 (Mulw) 515 (Divw) 516 (Divuw) 517 (Remw) 518 (Remuw) 519 520 ;; Zba: Address Generation Instructions 521 (Adduw) 522 (Sh1add) 523 (Sh1adduw) 524 (Sh2add) 525 (Sh2adduw) 526 (Sh3add) 527 (Sh3adduw) 528 529 ;; Zbb: Bit Manipulation Instructions 530 (Andn) 531 (Orn) 532 (Xnor) 533 (Max) 534 (Maxu) 535 (Min) 536 (Minu) 537 (Rol) 538 (Rolw) 539 (Ror) 540 (Rorw) 541 542 ;; Zbs: Single-bit instructions 543 (Bclr) 544 (Bext) 545 (Binv) 546 (Bset) 547 548 ;; Zbc: Carry-less multiplication 549 (Clmul) 550 (Clmulh) 551 (Clmulr) 552 553 ;; Zbkb: Bit-manipulation for Cryptography 554 (Pack) 555 (Packw) 556 (Packh) 557 558 ;; ZiCond: Integer Conditional Operations 559 (CzeroEqz) 560 (CzeroNez) 561)) 562 563 564(type FpuOPRRR (enum 565 (Fadd) 566 (Fsub) 567 (Fmul) 568 (Fdiv) 569 (Fsgnj) 570 (Fsgnjn) 571 (Fsgnjx) 572 (Fmin) 573 (Fmax) 574 (Feq) 575 (Flt) 576 (Fle) 577 578 ;; Zfa Extension 579 (Fminm) 580 (Fmaxm) 581)) 582 583 584 585(type AluOPRRI (enum 586 ;; Base ISA 587 (Addi) 588 (Slti) 589 (SltiU) 590 (Xori) 591 (Ori) 592 (Andi) 593 (Slli) 594 (Srli) 595 (Srai) 596 (Addiw) 597 (Slliw) 598 (SrliW) 599 (Sraiw) 600 601 ;; Zba: Address Generation Instructions 602 (SlliUw) 603 604 ;; Zbb: Bit Manipulation Instructions 605 (Clz) 606 (Clzw) 607 (Ctz) 608 (Ctzw) 609 (Cpop) 610 (Cpopw) 611 (Sextb) 612 (Sexth) 613 (Zexth) 614 (Rori) 615 (Roriw) 616 (Rev8) 617 (Brev8) 618 (Orcb) 619 620 ;; Zbs: Single-bit instructions 621 (Bclri) 622 (Bexti) 623 (Binvi) 624 (Bseti) 625)) 626 627(type COpcodeSpace (enum 628 (C0) 629 (C1) 630 (C2) 631)) 632 633;; Opcodes for the CR compressed instruction format 634(type CrOp (enum 635 (CMv) 636 (CAdd) 637 (CJr) 638 (CJalr) 639 ;; c.ebreak technically isn't a CR format instruction, but it's encoding 640 ;; lines up with this format. 641 (CEbreak) 642)) 643 644;; Opcodes for the CA compressed instruction format 645(type CaOp (enum 646 (CAnd) 647 (COr) 648 (CXor) 649 (CSub) 650 (CAddw) 651 (CSubw) 652 (CMul) 653)) 654 655;; Opcodes for the CJ compressed instruction format 656(type CjOp (enum 657 (CJ) 658)) 659 660;; Opcodes for the CI compressed instruction format 661(type CiOp (enum 662 (CAddi) 663 (CAddiw) 664 (CAddi16sp) 665 (CSlli) 666 (CLi) 667 (CLui) 668 (CLwsp) 669 (CLdsp) 670 (CFldsp) 671)) 672 673;; Opcodes for the CIW compressed instruction format 674(type CiwOp (enum 675 (CAddi4spn) 676)) 677 678;; Opcodes for the CB compressed instruction format 679(type CbOp (enum 680 (CSrli) 681 (CSrai) 682 (CAndi) 683)) 684 685;; Opcodes for the CSS compressed instruction format 686(type CssOp (enum 687 (CSwsp) 688 (CSdsp) 689 (CFsdsp) 690)) 691 692;; Opcodes for the CS compressed instruction format 693(type CsOp (enum 694 (CSw) 695 (CSd) 696 (CFsd) 697)) 698 699;; Opcodes for the CL compressed instruction format 700(type ClOp (enum 701 (CLw) 702 (CLd) 703 (CFld) 704)) 705 706;; Opcodes for the CSZN compressed instruction format 707(type CsznOp (enum 708 (CNot) 709 (CZextb) 710 (CZexth) 711 (CZextw) 712 (CSextb) 713 (CSexth) 714)) 715 716;; This is a mix of all Zcb memory addressing instructions 717;; 718;; Technically they are split across 4 different formats. 719;; But they are all very similar, so we just group them all together. 720(type ZcbMemOp (enum 721 (CLbu) 722 (CLhu) 723 (CLh) 724 (CSb) 725 (CSh) 726)) 727 728 729(type CsrRegOP (enum 730 ;; Atomic Read/Write CSR 731 (CsrRW) 732 ;; Atomic Read and Set Bits in CSR 733 (CsrRS) 734 ;; Atomic Read and Clear Bits in CSR 735 (CsrRC) 736)) 737 738(type CsrImmOP (enum 739 ;; Atomic Read/Write CSR (Immediate Source) 740 (CsrRWI) 741 ;; Atomic Read and Set Bits in CSR (Immediate Source) 742 (CsrRSI) 743 ;; Atomic Read and Clear Bits in CSR (Immediate Source) 744 (CsrRCI) 745)) 746 747;; Enum of the known CSR registers 748(type CSR (enum 749 ;; Floating-Point Dynamic Rounding Mode 750 (Frm) 751)) 752 753 754(type FRM (enum 755 ;; Round to Nearest, ties to Even 756 (RNE) 757 ;; Round towards Zero 758 (RTZ) 759 ;; Round Down (towards −∞) 760 (RDN) 761 ;; Round Up (towards +∞) 762 (RUP) 763 ;; Round to Nearest, ties to Max Magnitude 764 (RMM) 765 ;; In instruction’s rm field, selects dynamic rounding mode; 766 ;;In Rounding Mode register, Invalid. 767 (Fcsr) 768)) 769 770(decl pure frm_bits (FRM) UImm5) 771(extern constructor frm_bits frm_bits) 772(convert FRM UImm5 frm_bits) 773 774(type FFlagsException (enum 775 ;; Invalid Operation 776 (NV) 777 ;; Divide by Zero 778 (DZ) 779 ;; Overflow 780 (OF) 781 ;; Underflow 782 (UF) 783 ;; Inexact 784 (NX) 785)) 786 787;;;; input output read write 788;;;; SI SO SR SW 789;;;; PI PO PR PW 790;;;; lowest four bit are used. 791(type FenceReq (primitive u8)) 792 793(type BoxCallInfo (primitive BoxCallInfo)) 794(type BoxCallIndInfo (primitive BoxCallIndInfo)) 795(type BoxReturnCallInfo (primitive BoxReturnCallInfo)) 796(type BoxReturnCallIndInfo (primitive BoxReturnCallIndInfo)) 797(type IntegerCompare (primitive IntegerCompare)) 798(type AMode (primitive AMode)) 799(type OptionReg (primitive OptionReg)) 800(type OptionImm12 (primitive OptionImm12)) 801(type OptionUimm5 (primitive OptionUimm5)) 802(type Imm12 (primitive Imm12)) 803(type UImm5 (primitive UImm5)) 804(type Imm5 (primitive Imm5)) 805(type Imm20 (primitive Imm20)) 806(type Imm3 (primitive Imm3)) 807(type CondBrTarget (primitive CondBrTarget)) 808(type VecU8 (primitive VecU8)) 809(type AMO (primitive AMO)) 810(type VecMachLabel extern (enum)) 811 812 813;;;; Newtypes for Different Register Classes ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 814 815(type XReg (primitive XReg)) 816(type WritableXReg (primitive WritableXReg)) 817(type FReg (primitive FReg)) 818(type WritableFReg (primitive WritableFReg)) 819(type VReg (primitive VReg)) 820(type WritableVReg (primitive WritableVReg)) 821 822;; Construct a new `XReg` from a `Reg`. 823;; 824;; Asserts that the register has a Integer RegClass. 825(decl xreg_new (Reg) XReg) 826(extern constructor xreg_new xreg_new) 827(convert Reg XReg xreg_new) 828 829;; Construct a new `WritableXReg` from a `WritableReg`. 830;; 831;; Asserts that the register has a Integer RegClass. 832(decl writable_xreg_new (WritableReg) WritableXReg) 833(extern constructor writable_xreg_new writable_xreg_new) 834(convert WritableReg WritableXReg writable_xreg_new) 835 836;; Put a value into a XReg. 837;; 838;; Asserts that the value goes into a XReg. 839(decl put_in_xreg (Value) XReg) 840(rule (put_in_xreg val) (xreg_new (put_in_reg val))) 841(convert Value XReg put_in_xreg) 842 843;; Construct an `InstOutput` out of a single XReg register. 844(decl output_xreg (XReg) InstOutput) 845(rule (output_xreg x) (output_reg x)) 846(convert XReg InstOutput output_xreg) 847 848;; Convert a `WritableXReg` to an `XReg`. 849(decl pure writable_xreg_to_xreg (WritableXReg) XReg) 850(extern constructor writable_xreg_to_xreg writable_xreg_to_xreg) 851(convert WritableXReg XReg writable_xreg_to_xreg) 852 853;; Convert a `WritableXReg` to an `WritableReg`. 854(decl pure writable_xreg_to_writable_reg (WritableXReg) WritableReg) 855(extern constructor writable_xreg_to_writable_reg writable_xreg_to_writable_reg) 856(convert WritableXReg WritableReg writable_xreg_to_writable_reg) 857 858;; Convert a `WritableXReg` to an `Reg`. 859(decl pure writable_xreg_to_reg (WritableXReg) Reg) 860(rule (writable_xreg_to_reg x) (writable_xreg_to_writable_reg x)) 861(convert WritableXReg Reg writable_xreg_to_reg) 862 863;; Convert an `XReg` to a `Reg`. 864(decl pure xreg_to_reg (XReg) Reg) 865(extern constructor xreg_to_reg xreg_to_reg) 866(convert XReg Reg xreg_to_reg) 867 868;; Convert a `XReg` to a `ValueRegs`. 869(decl xreg_to_value_regs (XReg) ValueRegs) 870(rule (xreg_to_value_regs x) (value_reg x)) 871(convert XReg ValueRegs xreg_to_reg) 872 873;; Convert a `WritableXReg` to a `ValueRegs`. 874(decl writable_xreg_to_value_regs (WritableXReg) ValueRegs) 875(rule (writable_xreg_to_value_regs x) (value_reg x)) 876(convert WritableXReg ValueRegs writable_xreg_to_value_regs) 877 878;; Allocates a new `WritableXReg`. 879(decl temp_writable_xreg () WritableXReg) 880(rule (temp_writable_xreg) (temp_writable_reg $I64)) 881 882 883;; Construct a new `FReg` from a `Reg`. 884;; 885;; Asserts that the register has a Float RegClass. 886(decl freg_new (Reg) FReg) 887(extern constructor freg_new freg_new) 888(convert Reg FReg freg_new) 889 890;; Construct a new `WritableFReg` from a `WritableReg`. 891;; 892;; Asserts that the register has a Float RegClass. 893(decl writable_freg_new (WritableReg) WritableFReg) 894(extern constructor writable_freg_new writable_freg_new) 895(convert WritableReg WritableFReg writable_freg_new) 896 897;; Put a value into a FReg. 898;; 899;; Asserts that the value goes into a FReg. 900(decl put_in_freg (Value) FReg) 901(rule (put_in_freg val) (freg_new (put_in_reg val))) 902(convert Value FReg put_in_freg) 903 904;; Construct an `InstOutput` out of a single FReg register. 905(decl output_freg (FReg) InstOutput) 906(rule (output_freg x) (output_reg x)) 907(convert FReg InstOutput output_freg) 908 909;; Convert a `WritableFReg` to an `FReg`. 910(decl pure writable_freg_to_freg (WritableFReg) FReg) 911(extern constructor writable_freg_to_freg writable_freg_to_freg) 912(convert WritableFReg FReg writable_freg_to_freg) 913 914;; Convert a `WritableFReg` to an `WritableReg`. 915(decl pure writable_freg_to_writable_reg (WritableFReg) WritableReg) 916(extern constructor writable_freg_to_writable_reg writable_freg_to_writable_reg) 917(convert WritableFReg WritableReg writable_freg_to_writable_reg) 918 919;; Convert a `WritableFReg` to an `Reg`. 920(decl pure writable_freg_to_reg (WritableFReg) Reg) 921(rule (writable_freg_to_reg x) (writable_freg_to_writable_reg x)) 922(convert WritableFReg Reg writable_freg_to_reg) 923 924;; Convert an `FReg` to a `Reg`. 925(decl pure freg_to_reg (FReg) Reg) 926(extern constructor freg_to_reg freg_to_reg) 927(convert FReg Reg freg_to_reg) 928 929;; Convert a `FReg` to a `ValueRegs`. 930(decl freg_to_value_regs (FReg) ValueRegs) 931(rule (freg_to_value_regs x) (value_reg x)) 932(convert FReg ValueRegs xreg_to_reg) 933 934;; Convert a `WritableFReg` to a `ValueRegs`. 935(decl writable_freg_to_value_regs (WritableFReg) ValueRegs) 936(rule (writable_freg_to_value_regs x) (value_reg x)) 937(convert WritableFReg ValueRegs writable_freg_to_value_regs) 938 939;; Allocates a new `WritableFReg`. 940(decl temp_writable_freg () WritableFReg) 941(rule (temp_writable_freg) (temp_writable_reg $F64)) 942 943 944 945;; Construct a new `VReg` from a `Reg`. 946;; 947;; Asserts that the register has a Vector RegClass. 948(decl vreg_new (Reg) VReg) 949(extern constructor vreg_new vreg_new) 950(convert Reg VReg vreg_new) 951 952;; Construct a new `WritableVReg` from a `WritableReg`. 953;; 954;; Asserts that the register has a Vector RegClass. 955(decl writable_vreg_new (WritableReg) WritableVReg) 956(extern constructor writable_vreg_new writable_vreg_new) 957(convert WritableReg WritableVReg writable_vreg_new) 958 959;; Put a value into a VReg. 960;; 961;; Asserts that the value goes into a VReg. 962(decl put_in_vreg (Value) VReg) 963(rule (put_in_vreg val) (vreg_new (put_in_reg val))) 964(convert Value VReg put_in_vreg) 965 966;; Construct an `InstOutput` out of a single VReg register. 967(decl output_vreg (VReg) InstOutput) 968(rule (output_vreg x) (output_reg x)) 969(convert VReg InstOutput output_vreg) 970 971;; Convert a `WritableVReg` to an `VReg`. 972(decl pure writable_vreg_to_vreg (WritableVReg) VReg) 973(extern constructor writable_vreg_to_vreg writable_vreg_to_vreg) 974(convert WritableVReg VReg writable_vreg_to_vreg) 975 976;; Convert a `WritableVReg` to an `WritableReg`. 977(decl pure writable_vreg_to_writable_reg (WritableVReg) WritableReg) 978(extern constructor writable_vreg_to_writable_reg writable_vreg_to_writable_reg) 979(convert WritableVReg WritableReg writable_vreg_to_writable_reg) 980 981;; Convert a `WritableVReg` to an `Reg`. 982(decl pure writable_vreg_to_reg (WritableVReg) Reg) 983(rule (writable_vreg_to_reg x) (writable_vreg_to_writable_reg x)) 984(convert WritableVReg Reg writable_vreg_to_reg) 985 986;; Convert an `VReg` to a `Reg`. 987(decl pure vreg_to_reg (VReg) Reg) 988(extern constructor vreg_to_reg vreg_to_reg) 989(convert VReg Reg vreg_to_reg) 990 991;; Convert a `VReg` to a `ValueRegs`. 992(decl vreg_to_value_regs (VReg) ValueRegs) 993(rule (vreg_to_value_regs x) (value_reg x)) 994(convert VReg ValueRegs xreg_to_reg) 995 996;; Convert a `WritableVReg` to a `ValueRegs`. 997(decl writable_vreg_to_value_regs (WritableVReg) ValueRegs) 998(rule (writable_vreg_to_value_regs x) (value_reg x)) 999(convert WritableVReg ValueRegs writable_vreg_to_value_regs) 1000 1001;; Allocates a new `WritableVReg`. 1002(decl temp_writable_vreg () WritableVReg) 1003(rule (temp_writable_vreg) (temp_writable_reg $I8X16)) 1004 1005 1006;; ISA Extension helpers 1007 1008(decl pure has_m () bool) 1009(extern constructor has_m has_m) 1010 1011(decl pure has_v () bool) 1012(extern constructor has_v has_v) 1013 1014(decl pure has_zfa () bool) 1015(extern constructor has_zfa has_zfa) 1016 1017(decl pure has_zfhmin () bool) 1018(extern constructor has_zfhmin has_zfhmin) 1019 1020(decl pure has_zfh () bool) 1021(extern constructor has_zfh has_zfh) 1022 1023(decl pure has_zvfh () bool) 1024(extern constructor has_zvfh has_zvfh) 1025 1026(decl pure has_zbkb () bool) 1027(extern constructor has_zbkb has_zbkb) 1028 1029(decl pure has_zba () bool) 1030(extern constructor has_zba has_zba) 1031 1032(decl pure has_zbb () bool) 1033(extern constructor has_zbb has_zbb) 1034 1035(decl pure has_zbc () bool) 1036(extern constructor has_zbc has_zbc) 1037 1038(decl pure has_zbs () bool) 1039(extern constructor has_zbs has_zbs) 1040 1041(decl pure has_zicond () bool) 1042(extern constructor has_zicond has_zicond) 1043 1044 1045;;;; Type Helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1046 1047;; Helper that matches any supported type. This extractor checks the ISA flags 1048;; to determine if the type is supported. 1049(decl ty_supported (Type) Type) 1050(extern extractor ty_supported ty_supported) 1051 1052;; Helper that matches any scalar floating point type 1053 1054;; Floating point registers are large enough to hold the type 1055(decl ty_supported_float_size (Type) Type) 1056(extern extractor ty_supported_float_size ty_supported_float_size) 1057 1058;; At least basic floating point instructions like load/store are supported (e.g. Zfhmin) 1059(decl ty_supported_float_min (Type) Type) 1060(extern extractor ty_supported_float_min ty_supported_float_min) 1061 1062;; All floating point instructions are supported (e.g. Zfh) 1063(decl ty_supported_float_full (Type) Type) 1064(extern extractor ty_supported_float_full ty_supported_float_full) 1065 1066;; Helper that matches any supported vector type 1067(decl ty_supported_vec (Type) Type) 1068(extern extractor ty_supported_vec ty_supported_vec) 1069 1070;; Helper that matches types which are stored in a pair of integer registers (I128 and F128) 1071(decl ty_reg_pair (Type) Type) 1072(extern extractor ty_reg_pair ty_reg_pair) 1073 1074 1075;;;; Instruction Helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1076 1077;; RV32I Base Integer Instruction Set 1078 1079;; Helper for emitting the `add` instruction. 1080;; rd ← rs1 + rs2 1081(decl rv_add (XReg XReg) XReg) 1082(rule (rv_add rs1 rs2) 1083 (alu_rrr (AluOPRRR.Add) rs1 rs2)) 1084 1085;; Helper for emitting the `addi` ("Add Immediate") instruction. 1086;; rd ← rs1 + sext(imm) 1087(decl rv_addi (XReg Imm12) XReg) 1088(rule (rv_addi rs1 imm) 1089 (alu_rr_imm12 (AluOPRRI.Addi) rs1 imm)) 1090 1091;; Helper for emitting the `sub` instruction. 1092;; rd ← rs1 - rs2 1093(decl rv_sub (XReg XReg) XReg) 1094(rule (rv_sub rs1 rs2) 1095 (alu_rrr (AluOPRRR.Sub) rs1 rs2)) 1096 1097;; Helper for emitting the `neg` instruction. 1098;; This instruction is a mnemonic for `sub rd, zero, rs1`. 1099(decl rv_neg (XReg) XReg) 1100(rule (rv_neg rs1) 1101 (alu_rrr (AluOPRRR.Sub) (zero_reg) rs1)) 1102 1103;; Helper for emitting the `sll` ("Shift Left Logical") instruction. 1104;; rd ← rs1 << rs2 1105(decl rv_sll (XReg XReg) XReg) 1106(rule (rv_sll rs1 rs2) 1107 (alu_rrr (AluOPRRR.Sll) rs1 rs2)) 1108 1109;; Helper for emitting the `slli` ("Shift Left Logical Immediate") instruction. 1110;; rd ← rs1 << uext(imm) 1111(decl rv_slli (XReg Imm12) XReg) 1112(rule (rv_slli rs1 imm) 1113 (alu_rr_imm12 (AluOPRRI.Slli) rs1 imm)) 1114 1115;; Helper for emitting the `srl` ("Shift Right Logical") instruction. 1116;; rd ← rs1 >> rs2 1117(decl rv_srl (XReg XReg) XReg) 1118(rule (rv_srl rs1 rs2) 1119 (alu_rrr (AluOPRRR.Srl) rs1 rs2)) 1120 1121;; Helper for emitting the `srli` ("Shift Right Logical Immediate") instruction. 1122;; rd ← rs1 >> uext(imm) 1123(decl rv_srli (XReg Imm12) XReg) 1124(rule (rv_srli rs1 imm) 1125 (alu_rr_imm12 (AluOPRRI.Srli) rs1 imm)) 1126 1127;; Helper for emitting the `sra` ("Shift Right Arithmetic") instruction. 1128;; rd ← rs1 >> rs2 1129(decl rv_sra (XReg XReg) XReg) 1130(rule (rv_sra rs1 rs2) 1131 (alu_rrr (AluOPRRR.Sra) rs1 rs2)) 1132 1133;; Helper for emitting the `srai` ("Shift Right Arithmetic Immediate") instruction. 1134;; rd ← rs1 >> uext(imm) 1135(decl rv_srai (XReg Imm12) XReg) 1136(rule (rv_srai rs1 imm) 1137 (alu_rr_imm12 (AluOPRRI.Srai) rs1 imm)) 1138 1139;; Helper for emitting the `or` instruction. 1140;; rd ← rs1 ∨ rs2 1141(decl rv_or (XReg XReg) XReg) 1142(rule (rv_or rs1 rs2) 1143 (alu_rrr (AluOPRRR.Or) rs1 rs2)) 1144 1145;; Helper for emitting the `ori` ("Or Immediate") instruction. 1146;; rd ← rs1 ∨ uext(imm) 1147(decl rv_ori (XReg Imm12) XReg) 1148(rule (rv_ori rs1 imm) 1149 (alu_rr_imm12 (AluOPRRI.Ori) rs1 imm)) 1150 1151;; Helper for emitting the `xor` instruction. 1152;; rd ← rs1 ⊕ rs2 1153(decl rv_xor (XReg XReg) XReg) 1154(rule (rv_xor rs1 rs2) 1155 (alu_rrr (AluOPRRR.Xor) rs1 rs2)) 1156 1157;; Helper for emitting the `xori` ("Exclusive Or Immediate") instruction. 1158;; rd ← rs1 ⊕ uext(imm) 1159(decl rv_xori (XReg Imm12) XReg) 1160(rule (rv_xori rs1 imm) 1161 (alu_rr_imm12 (AluOPRRI.Xori) rs1 imm)) 1162 1163;; Helper for emitting the `not` instruction. 1164;; This instruction is a mnemonic for `xori rd, rs1, -1`. 1165(decl rv_not (XReg) XReg) 1166(rule (rv_not rs1) 1167 (rv_xori rs1 (imm12_const -1))) 1168 1169;; Helper for emitting the `and` instruction. 1170;; rd ← rs1 ∧ rs2 1171(decl rv_and (XReg XReg) XReg) 1172(rule (rv_and rs1 rs2) 1173 (alu_rrr (AluOPRRR.And) rs1 rs2)) 1174 1175;; Helper for emitting the `andi` ("And Immediate") instruction. 1176;; rd ← rs1 ∧ uext(imm) 1177(decl rv_andi (XReg Imm12) XReg) 1178(rule (rv_andi rs1 imm) 1179 (alu_rr_imm12 (AluOPRRI.Andi) rs1 imm)) 1180 1181;; Helper for emitting the `slt` ("Set Less Than") instruction. 1182;; rd ← rs1 < rs2 1183(decl rv_slt (XReg XReg) XReg) 1184(rule (rv_slt rs1 rs2) 1185 (alu_rrr (AluOPRRR.Slt) rs1 rs2)) 1186 1187;; Helper for emitting the `sltu` ("Set Less Than Unsigned") instruction. 1188;; rd ← rs1 < rs2 1189(decl rv_sltu (XReg XReg) XReg) 1190(rule (rv_sltu rs1 rs2) 1191 (alu_rrr (AluOPRRR.SltU) rs1 rs2)) 1192 1193;; Helper for emitting the `snez` instruction. 1194;; This instruction is a mnemonic for `sltu rd, zero, rs`. 1195(decl rv_snez (XReg) XReg) 1196(rule (rv_snez rs1) 1197 (rv_sltu (zero_reg) rs1)) 1198 1199;; Helper for emitting the `slti` ("Set Less Than Immediate") instruction. 1200;; rd ← rs1 < imm 1201(decl rv_slti (XReg Imm12) XReg) 1202(rule (rv_slti rs1 imm) 1203 (alu_rr_imm12 (AluOPRRI.Slti) rs1 imm)) 1204 1205;; Helper for emitting the `sltiu` ("Set Less Than Immediate Unsigned") instruction. 1206;; rd ← rs1 < imm 1207(decl rv_sltiu (XReg Imm12) XReg) 1208(rule (rv_sltiu rs1 imm) 1209 (alu_rr_imm12 (AluOPRRI.SltiU) rs1 imm)) 1210 1211;; Helper for emitting the `seqz` instruction. 1212;; This instruction is a mnemonic for `sltiu rd, rs, 1`. 1213(decl rv_seqz (XReg) XReg) 1214(rule (rv_seqz rs1) 1215 (rv_sltiu rs1 (imm12_const 1))) 1216 1217 1218;; RV64I Base Integer Instruction Set 1219;; Unlike RV32I instructions these are only present in the 64bit ISA 1220 1221;; Helper for emitting the `addw` ("Add Word") instruction. 1222;; rd ← sext32(rs1) + sext32(rs2) 1223(decl rv_addw (XReg XReg) XReg) 1224(rule (rv_addw rs1 rs2) 1225 (alu_rrr (AluOPRRR.Addw) rs1 rs2)) 1226 1227;; Helper for emitting the `addiw` ("Add Word Immediate") instruction. 1228;; rd ← sext32(rs1) + imm 1229(decl rv_addiw (XReg Imm12) XReg) 1230(rule (rv_addiw rs1 imm) 1231 (alu_rr_imm12 (AluOPRRI.Addiw) rs1 imm)) 1232 1233;; Helper for emitting the `sext.w` ("Sign Extend Word") instruction. 1234;; This instruction is a mnemonic for `addiw rd, rs, zero`. 1235(decl rv_sextw (XReg) XReg) 1236(rule (rv_sextw rs1) 1237 (rv_addiw rs1 (imm12_const 0))) 1238 1239;; Helper for emitting the `subw` ("Subtract Word") instruction. 1240;; rd ← sext32(rs1) - sext32(rs2) 1241(decl rv_subw (XReg XReg) XReg) 1242(rule (rv_subw rs1 rs2) 1243 (alu_rrr (AluOPRRR.Subw) rs1 rs2)) 1244 1245;; Helper for emitting the `sllw` ("Shift Left Logical Word") instruction. 1246;; rd ← sext32(uext32(rs1) << rs2) 1247(decl rv_sllw (XReg XReg) XReg) 1248(rule (rv_sllw rs1 rs2) 1249 (alu_rrr (AluOPRRR.Sllw) rs1 rs2)) 1250 1251;; Helper for emitting the `slliw` ("Shift Left Logical Immediate Word") instruction. 1252;; rd ← sext32(uext32(rs1) << imm) 1253(decl rv_slliw (XReg Imm12) XReg) 1254(rule (rv_slliw rs1 imm) 1255 (alu_rr_imm12 (AluOPRRI.Slliw) rs1 imm)) 1256 1257;; Helper for emitting the `srlw` ("Shift Right Logical Word") instruction. 1258;; rd ← sext32(uext32(rs1) >> rs2) 1259(decl rv_srlw (XReg XReg) XReg) 1260(rule (rv_srlw rs1 rs2) 1261 (alu_rrr (AluOPRRR.Srlw) rs1 rs2)) 1262 1263;; Helper for emitting the `srliw` ("Shift Right Logical Immediate Word") instruction. 1264;; rd ← sext32(uext32(rs1) >> imm) 1265(decl rv_srliw (XReg Imm12) XReg) 1266(rule (rv_srliw rs1 imm) 1267 (alu_rr_imm12 (AluOPRRI.SrliW) rs1 imm)) 1268 1269;; Helper for emitting the `sraw` ("Shift Right Arithmetic Word") instruction. 1270;; rd ← sext32(rs1 >> rs2) 1271(decl rv_sraw (XReg XReg) XReg) 1272(rule (rv_sraw rs1 rs2) 1273 (alu_rrr (AluOPRRR.Sraw) rs1 rs2)) 1274 1275;; Helper for emitting the `sraiw` ("Shift Right Arithmetic Immediate Word") instruction. 1276;; rd ← sext32(rs1 >> imm) 1277(decl rv_sraiw (XReg Imm12) XReg) 1278(rule (rv_sraiw rs1 imm) 1279 (alu_rr_imm12 (AluOPRRI.Sraiw) rs1 imm)) 1280 1281 1282;; RV32M Extension 1283;; TODO: Enable these instructions only when we have the M extension 1284 1285;; Helper for emitting the `mul` instruction. 1286;; rd ← rs1 × rs2 1287(decl rv_mul (XReg XReg) XReg) 1288(rule (rv_mul rs1 rs2) 1289 (alu_rrr (AluOPRRR.Mul) rs1 rs2)) 1290 1291;; Helper for emitting the `mulh` ("Multiply High Signed Signed") instruction. 1292;; rd ← (sext(rs1) × sext(rs2)) » xlen 1293(decl rv_mulh (XReg XReg) XReg) 1294(rule (rv_mulh rs1 rs2) 1295 (alu_rrr (AluOPRRR.Mulh) rs1 rs2)) 1296 1297;; Helper for emitting the `mulhu` ("Multiply High Unsigned Unsigned") instruction. 1298;; rd ← (uext(rs1) × uext(rs2)) » xlen 1299(decl rv_mulhu (XReg XReg) XReg) 1300(rule (rv_mulhu rs1 rs2) 1301 (alu_rrr (AluOPRRR.Mulhu) rs1 rs2)) 1302 1303;; Helper for emitting the `div` instruction. 1304;; rd ← rs1 ÷ rs2 1305(decl rv_div (XReg XReg) XReg) 1306(rule (rv_div rs1 rs2) 1307 (alu_rrr (AluOPRRR.Div) rs1 rs2)) 1308 1309;; Helper for emitting the `divu` ("Divide Unsigned") instruction. 1310;; rd ← rs1 ÷ rs2 1311(decl rv_divu (XReg XReg) XReg) 1312(rule (rv_divu rs1 rs2) 1313 (alu_rrr (AluOPRRR.DivU) rs1 rs2)) 1314 1315;; Helper for emitting the `rem` instruction. 1316;; rd ← rs1 mod rs2 1317(decl rv_rem (XReg XReg) XReg) 1318(rule (rv_rem rs1 rs2) 1319 (alu_rrr (AluOPRRR.Rem) rs1 rs2)) 1320 1321;; Helper for emitting the `remu` ("Remainder Unsigned") instruction. 1322;; rd ← rs1 mod rs2 1323(decl rv_remu (XReg XReg) XReg) 1324(rule (rv_remu rs1 rs2) 1325 (alu_rrr (AluOPRRR.RemU) rs1 rs2)) 1326 1327;; RV64M Extension 1328;; TODO: Enable these instructions only when we have the M extension 1329 1330;; Helper for emitting the `mulw` ("Multiply Word") instruction. 1331;; rd ← uext32(rs1) × uext32(rs2) 1332(decl rv_mulw (XReg XReg) XReg) 1333(rule (rv_mulw rs1 rs2) 1334 (alu_rrr (AluOPRRR.Mulw) rs1 rs2)) 1335 1336;; Helper for emitting the `divw` ("Divide Word") instruction. 1337;; rd ← sext32(rs1) ÷ sext32(rs2) 1338(decl rv_divw (XReg XReg) XReg) 1339(rule (rv_divw rs1 rs2) 1340 (alu_rrr (AluOPRRR.Divw) rs1 rs2)) 1341 1342;; Helper for emitting the `divuw` ("Divide Unsigned Word") instruction. 1343;; rd ← uext32(rs1) ÷ uext32(rs2) 1344(decl rv_divuw (XReg XReg) XReg) 1345(rule (rv_divuw rs1 rs2) 1346 (alu_rrr (AluOPRRR.Divuw) rs1 rs2)) 1347 1348;; Helper for emitting the `remw` ("Remainder Word") instruction. 1349;; rd ← sext32(rs1) mod sext32(rs2) 1350(decl rv_remw (XReg XReg) XReg) 1351(rule (rv_remw rs1 rs2) 1352 (alu_rrr (AluOPRRR.Remw) rs1 rs2)) 1353 1354;; Helper for emitting the `remuw` ("Remainder Unsigned Word") instruction. 1355;; rd ← uext32(rs1) mod uext32(rs2) 1356(decl rv_remuw (XReg XReg) XReg) 1357(rule (rv_remuw rs1 rs2) 1358 (alu_rrr (AluOPRRR.Remuw) rs1 rs2)) 1359 1360 1361;; F and D Extensions 1362;; TODO: Enable these instructions only when we have the F or D extensions 1363 1364;; Helper for emitting the `fadd` instruction. 1365(decl rv_fadd (Type FRM FReg FReg) FReg) 1366(rule (rv_fadd ty frm rs1 rs2) (fpu_rrr (FpuOPRRR.Fadd) ty frm rs1 rs2)) 1367 1368;; Helper for emitting the `fsub` instruction. 1369(decl rv_fsub (Type FRM FReg FReg) FReg) 1370(rule (rv_fsub ty frm rs1 rs2) (fpu_rrr (FpuOPRRR.Fsub) ty frm rs1 rs2)) 1371 1372;; Helper for emitting the `fmul` instruction. 1373(decl rv_fmul (Type FRM FReg FReg) FReg) 1374(rule (rv_fmul ty frm rs1 rs2) (fpu_rrr (FpuOPRRR.Fmul) ty frm rs1 rs2)) 1375 1376;; Helper for emitting the `fdiv` instruction. 1377(decl rv_fdiv (Type FRM FReg FReg) FReg) 1378(rule (rv_fdiv ty frm rs1 rs2) (fpu_rrr (FpuOPRRR.Fdiv) ty frm rs1 rs2)) 1379 1380;; Helper for emitting the `fsqrt` instruction. 1381(decl rv_fsqrt (Type FRM FReg) FReg) 1382(rule (rv_fsqrt ty frm rs1) (fpu_rr (FpuOPRR.Fsqrt) ty frm rs1)) 1383 1384;; Helper for emitting the `fmadd` instruction. 1385(decl rv_fmadd (Type FRM FReg FReg FReg) FReg) 1386(rule (rv_fmadd ty frm rs1 rs2 rs3) (fpu_rrrr (FpuOPRRRR.Fmadd) ty frm rs1 rs2 rs3)) 1387 1388;; Helper for emitting the `fmsub` instruction. 1389(decl rv_fmsub (Type FRM FReg FReg FReg) FReg) 1390(rule (rv_fmsub ty frm rs1 rs2 rs3) (fpu_rrrr (FpuOPRRRR.Fmsub) ty frm rs1 rs2 rs3)) 1391 1392;; Helper for emitting the `fnmadd` instruction. 1393(decl rv_fnmadd (Type FRM FReg FReg FReg) FReg) 1394(rule (rv_fnmadd ty frm rs1 rs2 rs3) (fpu_rrrr (FpuOPRRRR.Fnmadd) ty frm rs1 rs2 rs3)) 1395 1396;; Helper for emitting the `fnmsub` instruction. 1397(decl rv_fnmsub (Type FRM FReg FReg FReg) FReg) 1398(rule (rv_fnmsub ty frm rs1 rs2 rs3) (fpu_rrrr (FpuOPRRRR.Fnmsub) ty frm rs1 rs2 rs3)) 1399 1400;; Helper for emitting the `fmv.x.h` instruction. 1401(decl rv_fmvxh (FReg) XReg) 1402(rule (rv_fmvxh r) (fpu_rr_int (FpuOPRR.FmvXFmt) $F16 (FRM.RNE) r)) 1403 1404;; Helper for emitting the `fmv.x.w` instruction. 1405(decl rv_fmvxw (FReg) XReg) 1406(rule (rv_fmvxw r) (fpu_rr_int (FpuOPRR.FmvXFmt) $F32 (FRM.RNE) r)) 1407 1408;; Helper for emitting the `fmv.x.d` instruction. 1409(decl rv_fmvxd (FReg) XReg) 1410(rule (rv_fmvxd r) (fpu_rr_int (FpuOPRR.FmvXFmt) $F64 (FRM.RNE) r)) 1411 1412;; Helper for emitting the `fmv.h.x` instruction. 1413(decl rv_fmvhx (XReg) FReg) 1414(rule (rv_fmvhx r) (fpu_rr (FpuOPRR.FmvFmtX) $F16 (FRM.RNE) r)) 1415 1416;; Helper for emitting the `fmv.w.x` instruction. 1417(decl rv_fmvwx (XReg) FReg) 1418(rule (rv_fmvwx r) (fpu_rr (FpuOPRR.FmvFmtX) $F32 (FRM.RNE) r)) 1419 1420;; Helper for emitting the `fmv.d.x` instruction. 1421(decl rv_fmvdx (XReg) FReg) 1422(rule (rv_fmvdx r) (fpu_rr (FpuOPRR.FmvFmtX) $F64 (FRM.RNE) r)) 1423 1424;; Helper for emitting the `fcvt.d.s` ("Float Convert Double to Single") instruction. 1425(decl rv_fcvtds (FReg) FReg) 1426(rule (rv_fcvtds rs1) (fpu_rr (FpuOPRR.FcvtDS) $F64 (FRM.RNE) rs1)) 1427 1428;; Helper for emitting the `fcvt.s.d` ("Float Convert Single to Double") instruction. 1429(decl rv_fcvtsd (FRM FReg) FReg) 1430(rule (rv_fcvtsd frm rs1) (fpu_rr (FpuOPRR.FcvtSD) $F32 frm rs1)) 1431 1432;; Helper for emitting the `fcvt.s.w` instruction. 1433(decl rv_fcvtsw (FRM XReg) FReg) 1434(rule (rv_fcvtsw frm rs1) (fpu_rr (FpuOPRR.FcvtFmtW) $F32 frm rs1)) 1435 1436;; Helper for emitting the `fcvt.s.wu` instruction. 1437(decl rv_fcvtswu (FRM XReg) FReg) 1438(rule (rv_fcvtswu frm rs1) (fpu_rr (FpuOPRR.FcvtFmtWu) $F32 frm rs1)) 1439 1440;; Helper for emitting the `fcvt.d.w` instruction. 1441(decl rv_fcvtdw (XReg) FReg) 1442(rule (rv_fcvtdw rs1) (fpu_rr (FpuOPRR.FcvtFmtW) $F64 (FRM.RNE) rs1)) 1443 1444;; Helper for emitting the `fcvt.d.wu` instruction. 1445(decl rv_fcvtdwu (XReg) FReg) 1446(rule (rv_fcvtdwu rs1) (fpu_rr (FpuOPRR.FcvtFmtWu) $F64 (FRM.RNE) rs1)) 1447 1448;; Helper for emitting the `fcvt.s.l` instruction. 1449(decl rv_fcvtsl (FRM XReg) FReg) 1450(rule (rv_fcvtsl frm rs1) (fpu_rr (FpuOPRR.FcvtFmtL) $F32 frm rs1)) 1451 1452;; Helper for emitting the `fcvt.s.lu` instruction. 1453(decl rv_fcvtslu (FRM XReg) FReg) 1454(rule (rv_fcvtslu frm rs1) (fpu_rr (FpuOPRR.FcvtFmtLu) $F32 frm rs1)) 1455 1456;; Helper for emitting the `fcvt.d.l` instruction. 1457(decl rv_fcvtdl (FRM XReg) FReg) 1458(rule (rv_fcvtdl frm rs1) (fpu_rr (FpuOPRR.FcvtFmtL) $F64 frm rs1)) 1459 1460;; Helper for emitting the `fcvt.d.lu` instruction. 1461(decl rv_fcvtdlu (FRM XReg) FReg) 1462(rule (rv_fcvtdlu frm rs1) (fpu_rr (FpuOPRR.FcvtFmtLu) $F64 frm rs1)) 1463 1464;; Helper for emitting the `fcvt.w.s` instruction. 1465(decl rv_fcvtws (FRM FReg) XReg) 1466(rule (rv_fcvtws frm rs1) (fpu_rr_int (FpuOPRR.FcvtWFmt) $F32 frm rs1)) 1467 1468;; Helper for emitting the `fcvt.l.s` instruction. 1469(decl rv_fcvtls (FRM FReg) XReg) 1470(rule (rv_fcvtls frm rs1) (fpu_rr_int (FpuOPRR.FcvtLFmt) $F32 frm rs1)) 1471 1472;; Helper for emitting the `fcvt.wu.s` instruction. 1473(decl rv_fcvtwus (FRM FReg) XReg) 1474(rule (rv_fcvtwus frm rs1) (fpu_rr_int (FpuOPRR.FcvtWuFmt) $F32 frm rs1)) 1475 1476;; Helper for emitting the `fcvt.lu.s` instruction. 1477(decl rv_fcvtlus (FRM FReg) XReg) 1478(rule (rv_fcvtlus frm rs1) (fpu_rr_int (FpuOPRR.FcvtLuFmt) $F32 frm rs1)) 1479 1480;; Helper for emitting the `fcvt.w.d` instruction. 1481(decl rv_fcvtwd (FRM FReg) XReg) 1482(rule (rv_fcvtwd frm rs1) (fpu_rr_int (FpuOPRR.FcvtWFmt) $F64 frm rs1)) 1483 1484;; Helper for emitting the `fcvt.l.d` instruction. 1485(decl rv_fcvtld (FRM FReg) XReg) 1486(rule (rv_fcvtld frm rs1) (fpu_rr_int (FpuOPRR.FcvtLFmt) $F64 frm rs1)) 1487 1488;; Helper for emitting the `fcvt.wu.d` instruction. 1489(decl rv_fcvtwud (FRM FReg) XReg) 1490(rule (rv_fcvtwud frm rs1) (fpu_rr_int (FpuOPRR.FcvtWuFmt) $F64 frm rs1)) 1491 1492;; Helper for emitting the `fcvt.lu.d` instruction. 1493(decl rv_fcvtlud (FRM FReg) XReg) 1494(rule (rv_fcvtlud frm rs1) (fpu_rr_int (FpuOPRR.FcvtLuFmt) $F64 frm rs1)) 1495 1496;; Helper for emitting the `fcvt.w.*` instructions. 1497(decl rv_fcvtw (Type FRM FReg) XReg) 1498(rule (rv_fcvtw $F32 frm rs1) (rv_fcvtws frm rs1)) 1499(rule (rv_fcvtw $F64 frm rs1) (rv_fcvtwd frm rs1)) 1500 1501;; Helper for emitting the `fcvt.l.*` instructions. 1502(decl rv_fcvtl (Type FRM FReg) XReg) 1503(rule (rv_fcvtl $F32 frm rs1) (rv_fcvtls frm rs1)) 1504(rule (rv_fcvtl $F64 frm rs1) (rv_fcvtld frm rs1)) 1505 1506;; Helper for emitting the `fcvt.wu.*` instructions. 1507(decl rv_fcvtwu (Type FRM FReg) XReg) 1508(rule (rv_fcvtwu $F32 frm rs1) (rv_fcvtwus frm rs1)) 1509(rule (rv_fcvtwu $F64 frm rs1) (rv_fcvtwud frm rs1)) 1510 1511;; Helper for emitting the `fcvt.lu.*` instructions. 1512(decl rv_fcvtlu (Type FRM FReg) XReg) 1513(rule (rv_fcvtlu $F32 frm rs1) (rv_fcvtlus frm rs1)) 1514(rule (rv_fcvtlu $F64 frm rs1) (rv_fcvtlud frm rs1)) 1515 1516;; Helper for emitting the `fsgnj` ("Floating Point Sign Injection") instruction. 1517;; The output of this instruction is `rs1` with the sign bit from `rs2` 1518;; This implements the `copysign` operation 1519(decl rv_fsgnj (Type FReg FReg) FReg) 1520(rule (rv_fsgnj ty rs1 rs2) (fpu_rrr (FpuOPRRR.Fsgnj) ty (FRM.RNE) rs1 rs2)) 1521 1522;; Helper for emitting the `fsgnjn` ("Floating Point Sign Injection Negated") instruction. 1523;; The output of this instruction is `rs1` with the negated sign bit from `rs2` 1524;; When `rs1 == rs2` this implements the `neg` operation 1525(decl rv_fsgnjn (Type FReg FReg) FReg) 1526(rule (rv_fsgnjn ty rs1 rs2) (fpu_rrr (FpuOPRRR.Fsgnjn) ty (FRM.RTZ) rs1 rs2)) 1527 1528;; Helper for emitting the `fneg` ("Floating Point Negate") instruction. 1529;; This instruction is a mnemonic for `fsgnjn rd, rs1, rs1` 1530(decl rv_fneg (Type FReg) FReg) 1531(rule (rv_fneg ty rs1) (rv_fsgnjn ty rs1 rs1)) 1532 1533;; Helper for emitting the `fsgnjx` ("Floating Point Sign Injection Exclusive") instruction. 1534;; The output of this instruction is `rs1` with the XOR of the sign bits from `rs1` and `rs2`. 1535;; When `rs1 == rs2` this implements `fabs` 1536(decl rv_fsgnjx (Type FReg FReg) FReg) 1537(rule (rv_fsgnjx ty rs1 rs2) (fpu_rrr (FpuOPRRR.Fsgnjx) ty (FRM.RDN) rs1 rs2)) 1538 1539;; Helper for emitting the `fabs` ("Floating Point Absolute") instruction. 1540;; This instruction is a mnemonic for `fsgnjx rd, rs1, rs1` 1541(decl rv_fabs (Type FReg) FReg) 1542(rule (rv_fabs ty rs1) (rv_fsgnjx ty rs1 rs1)) 1543 1544;; Helper for emitting the `feq` ("Float Equal") instruction. 1545(decl rv_feq (Type FReg FReg) XReg) 1546(rule (rv_feq ty rs1 rs2) (fpu_rrr_int (FpuOPRRR.Feq) ty (FRM.RDN) rs1 rs2)) 1547 1548;; Helper for emitting the `flt` ("Float Less Than") instruction. 1549(decl rv_flt (Type FReg FReg) XReg) 1550(rule (rv_flt ty rs1 rs2) (fpu_rrr_int (FpuOPRRR.Flt) ty (FRM.RTZ) rs1 rs2)) 1551 1552;; Helper for emitting the `fle` ("Float Less Than or Equal") instruction. 1553(decl rv_fle (Type FReg FReg) XReg) 1554(rule (rv_fle ty rs1 rs2) (fpu_rrr_int (FpuOPRRR.Fle) ty (FRM.RNE) rs1 rs2)) 1555 1556;; Helper for emitting the `fgt` ("Float Greater Than") instruction. 1557;; Note: The arguments are reversed 1558(decl rv_fgt (Type FReg FReg) XReg) 1559(rule (rv_fgt ty rs1 rs2) (rv_flt ty rs2 rs1)) 1560 1561;; Helper for emitting the `fge` ("Float Greater Than or Equal") instruction. 1562;; Note: The arguments are reversed 1563(decl rv_fge (Type FReg FReg) XReg) 1564(rule (rv_fge ty rs1 rs2) (rv_fle ty rs2 rs1)) 1565 1566;; Helper for emitting the `fmin` instruction. 1567(decl rv_fmin (Type FReg FReg) FReg) 1568(rule (rv_fmin ty rs1 rs2) (fpu_rrr (FpuOPRRR.Fmin) ty (FRM.RNE) rs1 rs2)) 1569 1570;; Helper for emitting the `fmax` instruction. 1571(decl rv_fmax (Type FReg FReg) FReg) 1572(rule (rv_fmax ty rs1 rs2) (fpu_rrr (FpuOPRRR.Fmax) ty (FRM.RTZ) rs1 rs2)) 1573 1574;; `Zfa` Extension Instructions 1575 1576;; Helper for emitting the `fminm` instruction. 1577(decl rv_fminm (Type FReg FReg) FReg) 1578(rule (rv_fminm ty rs1 rs2) (fpu_rrr (FpuOPRRR.Fminm) ty (FRM.RDN) rs1 rs2)) 1579 1580;; Helper for emitting the `fmaxm` instruction. 1581(decl rv_fmaxm (Type FReg FReg) FReg) 1582(rule (rv_fmaxm ty rs1 rs2) (fpu_rrr (FpuOPRRR.Fmaxm) ty (FRM.RUP) rs1 rs2)) 1583 1584;; Helper for emitting the `fround` instruction. 1585(decl rv_fround (Type FRM FReg) FReg) 1586(rule (rv_fround ty frm rs) (fpu_rr (FpuOPRR.Fround) ty frm rs)) 1587 1588;; Helper for emitting the `fli` instruction. 1589(decl rv_fli (Type FliConstant) FReg) 1590(rule (rv_fli ty imm) 1591 (let ((dst WritableFReg (temp_writable_freg)) 1592 (_ Unit (emit (MInst.Fli ty 1593 imm 1594 dst)))) 1595 dst)) 1596 1597;; `Zba` Extension Instructions 1598 1599;; Helper for emitting the `adduw` ("Add Unsigned Word") instruction. 1600;; rd ← uext32(rs1) + uext32(rs2) 1601(decl rv_adduw (XReg XReg) XReg) 1602(rule (rv_adduw rs1 rs2) 1603 (alu_rrr (AluOPRRR.Adduw) rs1 rs2)) 1604 1605;; Helper for emitting the `zext.w` ("Zero Extend Word") instruction. 1606;; This instruction is a mnemonic for `adduw rd, rs1, zero`. 1607;; rd ← uext32(rs1) 1608(decl rv_zextw (XReg) XReg) 1609(rule (rv_zextw rs1) 1610 (rv_adduw rs1 (zero_reg))) 1611 1612;; Helper for emitting the `slli.uw` ("Shift Left Logical Immediate Unsigned Word") instruction. 1613;; rd ← uext32(rs1) << imm 1614(decl rv_slliuw (XReg Imm12) XReg) 1615(rule (rv_slliuw rs1 imm) 1616 (alu_rr_imm12 (AluOPRRI.SlliUw) rs1 imm)) 1617 1618 1619;; `Zbb` Extension Instructions 1620 1621;; Helper for emitting the `andn` ("And Negated") instruction. 1622;; rd ← rs1 ∧ ~(rs2) 1623(decl rv_andn (XReg XReg) XReg) 1624(rule (rv_andn rs1 rs2) 1625 (if-let true (has_zbb)) 1626 (alu_rrr (AluOPRRR.Andn) rs1 rs2)) 1627(rule (rv_andn rs1 rs2) 1628 (if-let false (has_zbb)) 1629 (rv_and rs1 (rv_not rs2))) 1630 1631;; Helper for emitting the `orn` ("Or Negated") instruction. 1632;; rd ← rs1 ∨ ~(rs2) 1633(decl rv_orn (XReg XReg) XReg) 1634(rule (rv_orn rs1 rs2) 1635 (alu_rrr (AluOPRRR.Orn) rs1 rs2)) 1636 1637;; Helper for emitting the `xnor` ("Exclusive NOR") instruction. 1638;; rd ← ~(rs1 ^ rs2) 1639(decl rv_xnor (XReg XReg) XReg) 1640(rule (rv_xnor rs1 rs2) 1641 (alu_rrr (AluOPRRR.Xnor) rs1 rs2)) 1642 1643;; Helper for emitting the `clz` ("Count Leading Zero Bits") instruction. 1644(decl rv_clz (XReg) XReg) 1645(rule (rv_clz rs1) 1646 (alu_rr_funct12 (AluOPRRI.Clz) rs1)) 1647 1648;; Helper for emitting the `clzw` ("Count Leading Zero Bits in Word") instruction. 1649(decl rv_clzw (XReg) XReg) 1650(rule (rv_clzw rs1) 1651 (alu_rr_funct12 (AluOPRRI.Clzw) rs1)) 1652 1653;; Helper for emitting the `ctz` ("Count Trailing Zero Bits") instruction. 1654(decl rv_ctz (XReg) XReg) 1655(rule (rv_ctz rs1) 1656 (alu_rr_funct12 (AluOPRRI.Ctz) rs1)) 1657 1658;; Helper for emitting the `ctzw` ("Count Trailing Zero Bits in Word") instruction. 1659(decl rv_ctzw (XReg) XReg) 1660(rule (rv_ctzw rs1) 1661 (alu_rr_funct12 (AluOPRRI.Ctzw) rs1)) 1662 1663;; Helper for emitting the `cpop` ("Count Population") instruction. 1664(decl rv_cpop (XReg) XReg) 1665(rule (rv_cpop rs1) 1666 (alu_rr_funct12 (AluOPRRI.Cpop) rs1)) 1667 1668;; Helper for emitting the `cpopw` ("Count Population") instruction. 1669(decl rv_cpopw (XReg) XReg) 1670(rule (rv_cpopw rs1) 1671 (alu_rr_funct12 (AluOPRRI.Cpopw) rs1)) 1672 1673;; Helper for emitting the `max` instruction. 1674(decl rv_max (XReg XReg) XReg) 1675(rule (rv_max rs1 rs2) 1676 (alu_rrr (AluOPRRR.Max) rs1 rs2)) 1677 1678;; Helper for emitting the `maxu` instruction. 1679(decl rv_maxu (XReg XReg) XReg) 1680(rule (rv_maxu rs1 rs2) 1681 (alu_rrr (AluOPRRR.Maxu) rs1 rs2)) 1682 1683;; Helper for emitting the `min` instruction. 1684(decl rv_min (XReg XReg) XReg) 1685(rule (rv_min rs1 rs2) 1686 (alu_rrr (AluOPRRR.Min) rs1 rs2)) 1687 1688;; Helper for emitting the `minu` instruction. 1689(decl rv_minu (XReg XReg) XReg) 1690(rule (rv_minu rs1 rs2) 1691 (alu_rrr (AluOPRRR.Minu) rs1 rs2)) 1692 1693;; Helper for emitting the `sext.b` instruction. 1694(decl rv_sextb (XReg) XReg) 1695(rule (rv_sextb rs1) 1696 (alu_rr_imm12 (AluOPRRI.Sextb) rs1 (imm12_const 0))) 1697 1698;; Helper for emitting the `sext.h` instruction. 1699(decl rv_sexth (XReg) XReg) 1700(rule (rv_sexth rs1) 1701 (alu_rr_imm12 (AluOPRRI.Sexth) rs1 (imm12_const 0))) 1702 1703;; Helper for emitting the `zext.h` instruction. 1704(decl rv_zexth (XReg) XReg) 1705(rule (rv_zexth rs1) 1706 (alu_rr_imm12 (AluOPRRI.Zexth) rs1 (imm12_const 0))) 1707 1708;; Helper for emitting the `rol` ("Rotate Left") instruction. 1709(decl rv_rol (XReg XReg) XReg) 1710(rule (rv_rol rs1 rs2) 1711 (alu_rrr (AluOPRRR.Rol) rs1 rs2)) 1712 1713;; Helper for emitting the `rolw` ("Rotate Left Word") instruction. 1714(decl rv_rolw (XReg XReg) XReg) 1715(rule (rv_rolw rs1 rs2) 1716 (alu_rrr (AluOPRRR.Rolw) rs1 rs2)) 1717 1718;; Helper for emitting the `ror` ("Rotate Right") instruction. 1719(decl rv_ror (XReg XReg) XReg) 1720(rule (rv_ror rs1 rs2) 1721 (alu_rrr (AluOPRRR.Ror) rs1 rs2)) 1722 1723;; Helper for emitting the `rorw` ("Rotate Right Word") instruction. 1724(decl rv_rorw (XReg XReg) XReg) 1725(rule (rv_rorw rs1 rs2) 1726 (alu_rrr (AluOPRRR.Rorw) rs1 rs2)) 1727 1728;; Helper for emitting the `rori` ("Rotate Right") instruction. 1729(decl rv_rori (XReg Imm12) XReg) 1730(rule (rv_rori rs1 rs2) 1731 (alu_rr_imm12 (AluOPRRI.Rori) rs1 rs2)) 1732 1733;; Helper for emitting the `roriw` ("Rotate Right Word") instruction. 1734(decl rv_roriw (XReg Imm12) XReg) 1735(rule (rv_roriw rs1 rs2) 1736 (alu_rr_imm12 (AluOPRRI.Roriw) rs1 rs2)) 1737 1738;; Helper for emitting the `rev8` ("Byte Reverse") instruction. 1739(decl rv_rev8 (XReg) XReg) 1740(rule (rv_rev8 rs1) 1741 (alu_rr_funct12 (AluOPRRI.Rev8) rs1)) 1742 1743;; Helper for emitting the `brev8` ("Bit Reverse Inside Bytes") instruction. 1744;; TODO: This instruction is mentioned in some older versions of the 1745;; spec, but has since disappeared, we should follow up on this. 1746;; It probably was renamed to `rev.b` which seems to be the closest match. 1747(decl rv_brev8 (XReg) XReg) 1748(rule (rv_brev8 rs1) 1749 (alu_rr_funct12 (AluOPRRI.Brev8) rs1)) 1750 1751;; `Zbs` Extension Instructions 1752 1753(decl rv_bclr (XReg XReg) XReg) 1754(rule (rv_bclr rs1 rs2) 1755 (alu_rrr (AluOPRRR.Bclr) rs1 rs2)) 1756 1757(decl rv_bclri (XReg Imm12) XReg) 1758(rule (rv_bclri rs1 imm) 1759 (alu_rr_imm12 (AluOPRRI.Bclri) rs1 imm)) 1760 1761(decl rv_bext (XReg XReg) XReg) 1762(rule (rv_bext rs1 rs2) 1763 (alu_rrr (AluOPRRR.Bext) rs1 rs2)) 1764 1765(decl rv_bexti (XReg Imm12) XReg) 1766(rule (rv_bexti rs1 imm) 1767 (alu_rr_imm12 (AluOPRRI.Bexti) rs1 imm)) 1768 1769(decl rv_binv (XReg XReg) XReg) 1770(rule (rv_binv rs1 rs2) 1771 (alu_rrr (AluOPRRR.Binv) rs1 rs2)) 1772 1773(decl rv_binvi (XReg Imm12) XReg) 1774(rule (rv_binvi rs1 imm) 1775 (alu_rr_imm12 (AluOPRRI.Binvi) rs1 imm)) 1776 1777(decl rv_bset (XReg XReg) XReg) 1778(rule (rv_bset rs1 rs2) 1779 (alu_rrr (AluOPRRR.Bset) rs1 rs2)) 1780 1781;; Helper for emitting the `bseti` ("Single-Bit Set Immediate") instruction. 1782(decl rv_bseti (XReg Imm12) XReg) 1783(rule (rv_bseti rs1 imm) 1784 (alu_rr_imm12 (AluOPRRI.Bseti) rs1 imm)) 1785 1786;; `Zbkb` Extension Instructions 1787 1788;; Helper for emitting the `pack` ("Pack low halves of registers") instruction. 1789(decl rv_pack (XReg XReg) XReg) 1790(rule (rv_pack rs1 rs2) 1791 (alu_rrr (AluOPRRR.Pack) rs1 rs2)) 1792 1793;; Helper for emitting the `packw` ("Pack low 16-bits of registers") instruction. 1794(decl rv_packw (XReg XReg) XReg) 1795(rule (rv_packw rs1 rs2) 1796 (alu_rrr (AluOPRRR.Packw) rs1 rs2)) 1797 1798;; `ZiCond` Extension Instructions 1799 1800;; Helper for emitting the `czero.eqz` ("Conditional zero, if condition is equal to zero") instruction. 1801;; RS1 is the data source 1802;; RS2 is the condition 1803;; 1804;; rd = (rs2 == 0) ? 0 : rs1 1805(decl rv_czero_eqz (XReg XReg) XReg) 1806(rule (rv_czero_eqz rs1 rs2) 1807 (alu_rrr (AluOPRRR.CzeroEqz) rs1 rs2)) 1808 1809;; Helper for emitting the `czero.nez` ("Conditional zero, if condition is nonzero") instruction. 1810;; RS1 is the data source 1811;; RS2 is the condition 1812;; 1813;; rd = (rs2 != 0) ? 0 : rs1 1814(decl rv_czero_nez (XReg XReg) XReg) 1815(rule (rv_czero_nez rs1 rs2) 1816 (alu_rrr (AluOPRRR.CzeroNez) rs1 rs2)) 1817 1818 1819;; `Zicsr` Extension Instructions 1820 1821;; Helper for emitting the `csrrwi` instruction. 1822(decl rv_csrrwi (CSR UImm5) XReg) 1823(rule (rv_csrrwi csr imm) 1824 (csr_imm (CsrImmOP.CsrRWI) csr imm)) 1825 1826;; This is a special case of `csrrwi` when the CSR is the `frm` CSR. 1827(decl rv_fsrmi (FRM) XReg) 1828(rule (rv_fsrmi frm) (rv_csrrwi (CSR.Frm) frm)) 1829 1830 1831;; Helper for emitting the `csrw` instruction. This is a special case of 1832;; `csrrw` where the destination register is always `x0`. 1833(decl rv_csrw (CSR XReg) Unit) 1834(rule (rv_csrw csr rs) 1835 (csr_reg_dst_zero (CsrRegOP.CsrRW) csr rs)) 1836 1837;; This is a special case of `csrw` when the CSR is the `frm` CSR. 1838(decl rv_fsrm (XReg) Unit) 1839(rule (rv_fsrm rs) (rv_csrw (CSR.Frm) rs)) 1840 1841 1842 1843 1844 1845 1846;; Helper for generating a FliConstant from a u64 constant 1847(decl pure partial fli_constant_from_u64 (Type u64) FliConstant) 1848(extern constructor fli_constant_from_u64 fli_constant_from_u64) 1849 1850;; Helper for generating a FliConstant from a u64 negated constant 1851(decl pure partial fli_constant_from_negated_u64 (Type u64) FliConstant) 1852(extern constructor fli_constant_from_negated_u64 fli_constant_from_negated_u64) 1853 1854;; Helper for generating a i64 from a pair of Imm20 and Imm12 constants 1855(decl i64_generate_imm (Imm20 Imm12) i64) 1856(extern extractor i64_generate_imm i64_generate_imm) 1857 1858;; Helper for generating a i64 from a shift of a Imm20 constant with LUI 1859(decl i64_shift_for_lui (u64 Imm12) i64) 1860(extern extractor i64_shift_for_lui i64_shift_for_lui) 1861 1862;; Helper for generating a i64 from a shift of a Imm20 constant 1863(decl i64_shift (i64 Imm12) i64) 1864(extern extractor i64_shift i64_shift) 1865 1866(decl pure has_fli_for_type (Type) bool) 1867(rule 2 (has_fli_for_type $F16) (if-let true (has_zfh)) (has_zfa)) 1868(rule 1 (has_fli_for_type $F16) (if-let true (has_zvfh)) (has_zfa)) 1869(rule (has_fli_for_type $F16) false) 1870(rule (has_fli_for_type $F32) (has_zfa)) 1871(rule (has_fli_for_type $F64) (has_zfa)) 1872 1873;; Immediate Loading rules 1874;; TODO: Loading the zero reg directly causes a bunch of regalloc errors, we should look into it. 1875;; TODO: Load floats using `fld` instead of `ld` 1876;; 1877;; Recursion: bounded since either float cases are reduced to integers, or the 1878;; shift case reduces to a smaller constant. 1879(decl rec imm (Type u64) Reg) 1880 1881;; Special-case 0.0 for floats to use the `(zero_reg)` directly. 1882;; See #7162 for why this doesn't fall out of the rules below. 1883(rule 9 (imm (ty_supported_float_min ty) 0) (gen_bitcast (zero_reg) (float_int_of_same_size ty) ty)) 1884 1885;; If Zfa is enabled, we can load certain constants with the `fli` instruction. 1886(rule 8 (imm (ty_supported_float_size ty) imm) 1887 (if-let true (has_fli_for_type ty)) 1888 (if-let const (fli_constant_from_u64 ty imm)) 1889 (rv_fli ty const)) 1890 1891;; It is beneficial to load the negated constant with `fli` and then negate it 1892;; in a register. 1893;; 1894;; For f64's this saves one instruction, and for f32's it avoids 1895;; having to allocate an integer register, reducing integer register pressure. 1896(rule 7 (imm (ty_supported_float_full ty) imm) 1897 (if-let true (has_fli_for_type ty)) 1898 (if-let const (fli_constant_from_negated_u64 ty imm)) 1899 (rv_fneg ty (rv_fli ty const))) 1900 1901;; Otherwise floats get loaded as integers and then moved into an F register. 1902(rule 6 (imm (ty_supported_float_min ty) c) (gen_bitcast (imm (float_int_of_same_size ty) c) (float_int_of_same_size ty) ty)) 1903;; NaN-box the constant when 16-bit `fmv` is unavailable. 1904(rule 5 (imm (ty_supported_float_size $F16) c) (gen_bitcast (imm $I32 (u64_or c 0xffff0000)) $I32 $F32)) 1905 1906;; Try to match just an imm12 1907(rule 4 (imm (ty_int ty) c) 1908 (if-let (i64_generate_imm (imm20_is_zero) imm12) (i64_sextend_u64 ty c)) 1909 (rv_addi (zero_reg) imm12)) 1910 1911;; We can also try to load using a single LUI. 1912;; LUI takes a 20 bit immediate, places it on bits 13 to 32 of the register. 1913;; In RV64 this value is then sign extended to 64bits. 1914(rule 3 (imm (ty_int ty) c) 1915 (if-let (i64_generate_imm imm20 (imm12_is_zero)) (i64_sextend_u64 ty c)) 1916 (rv_lui imm20)) 1917 1918;; We can combo addi + lui to represent all 32-bit immediates 1919;; And some 64-bit immediates as well. 1920(rule 2 (imm (ty_int ty) c) 1921 (if-let (i64_generate_imm imm20 imm12) (i64_sextend_u64 ty c)) 1922 (rv_addi (rv_lui imm20) imm12)) 1923 1924;; If the non-zero bits of the immediate fit in 20 bits, we can use LUI + shift 1925(rule 1 (imm (ty_int ty) c) 1926 (if-let (i64_shift_for_lui (imm20_from_u64 base) shift) (i64_sextend_u64 ty c)) 1927 (rv_slli (rv_lui base) shift)) 1928 1929;; Combine one of the above rules with a shift-left if possible, This chops off 1930;; all trailing zeros from the input constant and then attempts if the resulting 1931;; constant can itself use one of the above rules via the `i64_generate_imm` 1932;; matcher. This will then recurse on the above rules to materialize a smaller 1933;; constant which is then shifted left to create the desired constant. 1934(rule 0 (imm (ty_int ty) c) 1935 (if-let (i64_shift c_shifted shift) (i64_sextend_u64 ty c)) ;; constant to make 1936 (if-let (i64_generate_imm _ _) c_shifted) ;; can the smaller constant be made? 1937 (rv_slli (imm ty (i64_cast_unsigned c_shifted)) shift)) 1938 1939;; Otherwise we fall back to loading the immediate from the constant pool. 1940(rule -1 (imm (ty_int ty) c) 1941 (gen_load 1942 (gen_const_amode (emit_u64_le_const c)) 1943 (LoadOP.Ld) 1944 (mem_flags_trusted))) 1945 1946;; Imm12 Rules 1947 1948(decl pure imm12_zero () Imm12) 1949(rule (imm12_zero) (imm12_const 0)) 1950 1951(decl pure imm12_const (i32) Imm12) 1952(extern constructor imm12_const imm12_const) 1953 1954(decl load_imm12 (i32) Reg) 1955(rule 1956 (load_imm12 x) 1957 (rv_addi (zero_reg) (imm12_const x))) 1958 1959;; for load immediate 1960(decl imm_from_bits (u64) Imm12) 1961(extern constructor imm_from_bits imm_from_bits) 1962 1963(decl imm_from_neg_bits (i64) Imm12) 1964(extern constructor imm_from_neg_bits imm_from_neg_bits) 1965 1966(decl imm12_const_add (i32 i32) Imm12) 1967(extern constructor imm12_const_add imm12_const_add) 1968 1969;; Performs a fallible add of the `Imm12` value and the 32-bit value provided. 1970(decl pure partial imm12_add (Imm12 i32) Imm12) 1971(extern constructor imm12_add imm12_add) 1972 1973(decl imm12_and (Imm12 u64) Imm12) 1974(extern constructor imm12_and imm12_and) 1975 1976;; Imm12 Extractors 1977 1978;; Helper to go directly from a `Value`, when it's an `iconst`, to an `Imm12`. 1979(decl imm12_from_value (Imm12) Value) 1980(extractor (imm12_from_value n) (i64_from_iconst (imm12_from_i64 n))) 1981 1982;; Conceptually the same as `imm12_from_value`, but tries negating the constant 1983;; value (first sign-extending to handle narrow widths). 1984(decl pure partial imm12_from_negated_value (Value) Imm12) 1985(rule 1986 (imm12_from_negated_value (has_type ty (iconst _ n))) 1987 (if-let (imm12_from_u64 imm) (i64_cast_unsigned (i64_wrapping_neg (i64_sextend_imm64 ty n)))) 1988 imm) 1989 1990(decl imm12_from_u64 (Imm12) u64) 1991(extern extractor imm12_from_u64 imm12_from_u64) 1992 1993(decl imm12_from_i64 (Imm12) i64) 1994(extern extractor imm12_from_i64 imm12_from_i64) 1995 1996(decl pure partial u64_to_imm12 (u64) Imm12) 1997(rule (u64_to_imm12 (imm12_from_u64 n)) n) 1998 1999(decl pure imm12_is_zero () Imm12) 2000(extern extractor imm12_is_zero imm12_is_zero) 2001 2002;; Imm20 2003 2004;; Extractor that matches if a Imm20 is zero 2005(decl pure imm20_is_zero () Imm20) 2006(extern extractor imm20_is_zero imm20_is_zero) 2007 2008(decl imm20_from_u64 (Imm20) u64) 2009(extern extractor imm20_from_u64 imm20_from_u64) 2010 2011(decl imm20_from_i64 (Imm20) i64) 2012(extern extractor imm20_from_i64 imm20_from_i64) 2013 2014 2015;; Imm5 Extractors 2016 2017(decl imm5_from_u64 (Imm5) u64) 2018(extern extractor imm5_from_u64 imm5_from_u64) 2019 2020(decl imm5_from_i64 (Imm5) i64) 2021(extern extractor imm5_from_i64 imm5_from_i64) 2022 2023;; Construct a Imm5 from an i8 2024(decl pure partial i8_to_imm5 (i8) Imm5) 2025(extern constructor i8_to_imm5 i8_to_imm5) 2026 2027;; Helper to go directly from a `Value` to an `Imm5`. 2028(decl imm5_from_value (Imm5) Value) 2029(extractor (imm5_from_value n) (i64_from_iconst (imm5_from_i64 n))) 2030 2031;; Like imm5_from_value, but first negates the `Value`. 2032(decl pure partial imm5_from_negated_value (Value) Imm5) 2033(rule (imm5_from_negated_value (has_type ty (iconst _ n))) 2034 (if-let (imm5_from_i64 imm) (i64_wrapping_neg (i64_sextend_imm64 ty n))) 2035 imm) 2036 2037;; Constructor that matches a `Value` equivalent to a replicated Imm5 on all lanes. 2038(decl pure partial replicated_imm5 (Value) Imm5) 2039(rule (replicated_imm5 (splat _ (imm5_from_value n))) n) 2040(rule (replicated_imm5 (vconst _ (u128_from_constant n128))) 2041 (if-let (u128_replicated_u64 n64) n128) 2042 (if-let (u64_replicated_u32 n32) n64) 2043 (if-let (u32_replicated_u16 n16) n32) 2044 (if-let (u16_replicated_u8 n8) n16) 2045 (if-let n (i8_to_imm5 (u8_cast_signed n8))) 2046 n) 2047 2048;; Like replicated_imm5, but first negates the `Value`. 2049(decl pure partial negated_replicated_imm5 (Value) Imm5) 2050(rule (negated_replicated_imm5 (splat _ n)) 2051 (if-let imm5 (imm5_from_negated_value n)) 2052 imm5) 2053(rule (negated_replicated_imm5 (vconst _ (u128_from_constant n128))) 2054 (if-let (u128_replicated_u64 n64) n128) 2055 (if-let (u64_replicated_u32 n32) n64) 2056 (if-let (u32_replicated_u16 n16) n32) 2057 (if-let (u16_replicated_u8 n8) n16) 2058 (if-let n (i8_to_imm5 (i8_wrapping_neg (u8_cast_signed n8)))) 2059 n) 2060 2061;; UImm5 Helpers 2062 2063;; Constructor that matches a `Value` equivalent to a replicated UImm5 on all lanes. 2064(decl pure partial replicated_uimm5 (Value) UImm5) 2065(rule (replicated_uimm5 (splat _ (uimm5_from_value n))) n) 2066(rule 1 (replicated_uimm5 (vconst _ (u128_from_constant n128))) 2067 (if-let (u128_replicated_u64 n64) n128) 2068 (if-let (u64_replicated_u32 n32) n64) 2069 (if-let (u32_replicated_u16 n16) n32) 2070 (if-let (u16_replicated_u8 n8) n16) 2071 (if-let (uimm5_from_u8 n) n8) 2072 n) 2073 2074;; Helper to go directly from a `Value`, when it's an `iconst`, to an `UImm5`. 2075(decl uimm5_from_value (UImm5) Value) 2076(extractor (uimm5_from_value n) 2077 (iconst _ (u64_from_imm64 (uimm5_from_u64 n)))) 2078 2079;; Extract a `UImm5` from an `u8`. 2080(decl pure partial uimm5_from_u8 (UImm5) u8) 2081(extern extractor uimm5_from_u8 uimm5_from_u8) 2082 2083;; Extract a `UImm5` from an `u64`. 2084(decl pure partial uimm5_from_u64 (UImm5) u64) 2085(extern extractor uimm5_from_u64 uimm5_from_u64) 2086 2087;; Convert a `u64` into an `UImm5` 2088(decl pure partial u64_to_uimm5 (u64) UImm5) 2089(rule (u64_to_uimm5 (uimm5_from_u64 n)) n) 2090 2091(decl uimm5_bitcast_to_imm5 (UImm5) Imm5) 2092(extern constructor uimm5_bitcast_to_imm5 uimm5_bitcast_to_imm5) 2093 2094;; Float Helpers 2095 2096;; Returns the bitpattern of the Canonical NaN for the given type. 2097(decl pure canonical_nan_u64 (Type) u64) 2098(rule (canonical_nan_u64 $F32) 0x7fc00000) 2099(rule (canonical_nan_u64 $F64) 0x7ff8000000000000) 2100 2101;; Helper for emitting `MInst.FpuRR` instructions. 2102(decl fpu_rr (FpuOPRR Type FRM Reg) FReg) 2103(rule (fpu_rr op ty frm src) 2104 (let ((dst WritableFReg (temp_writable_freg)) 2105 (_ Unit (emit (MInst.FpuRR op ty frm dst src)))) 2106 dst)) 2107 2108;; Similar to fpu_rr but with an integer destination register 2109(decl fpu_rr_int (FpuOPRR Type FRM Reg) XReg) 2110(rule (fpu_rr_int op ty frm src) 2111 (let ((dst WritableXReg (temp_writable_xreg)) 2112 (_ Unit (emit (MInst.FpuRR op ty frm dst src)))) 2113 dst)) 2114 2115;; Helper for emitting `MInst.AluRRR` instructions. 2116(decl alu_rrr (AluOPRRR Reg Reg) Reg) 2117(rule (alu_rrr op src1 src2) 2118 (let ((dst WritableXReg (temp_writable_xreg)) 2119 (_ Unit (emit (MInst.AluRRR op dst src1 src2)))) 2120 dst)) 2121 2122;; Helper for emitting `MInst.FpuRRR` instructions. 2123(decl fpu_rrr (FpuOPRRR Type FRM Reg Reg) FReg) 2124(rule (fpu_rrr op ty frm src1 src2) 2125 (let ((dst WritableFReg (temp_writable_freg)) 2126 (_ Unit (emit (MInst.FpuRRR op ty frm dst src1 src2)))) 2127 dst)) 2128 2129;; Similar to fpu_rrr but with an integer destination register 2130(decl fpu_rrr_int (FpuOPRRR Type FRM Reg Reg) XReg) 2131(rule (fpu_rrr_int op ty frm src1 src2) 2132 (let ((dst WritableXReg (temp_writable_xreg)) 2133 (_ Unit (emit (MInst.FpuRRR op ty frm dst src1 src2)))) 2134 dst)) 2135 2136;; Helper for emitting `MInst.FpuRRRR` instructions. 2137(decl fpu_rrrr (FpuOPRRRR Type FRM Reg Reg Reg) FReg) 2138(rule (fpu_rrrr op ty frm src1 src2 src3) 2139 (let ((dst WritableFReg (temp_writable_freg)) 2140 (_ Unit (emit (MInst.FpuRRRR op ty frm dst src1 src2 src3)))) 2141 dst)) 2142 2143 2144;; Helper for emitting `MInst.AluRRImm12` instructions. 2145(decl alu_rr_imm12 (AluOPRRI Reg Imm12) Reg) 2146(rule (alu_rr_imm12 op src imm) 2147 (let ((dst WritableXReg (temp_writable_xreg)) 2148 (_ Unit (emit (MInst.AluRRImm12 op dst src imm)))) 2149 dst)) 2150 2151;; some instruction use imm12 as funct12. 2152;; so we don't need the imm12 parameter. 2153(decl alu_rr_funct12 (AluOPRRI Reg) Reg) 2154(rule (alu_rr_funct12 op src) 2155 (let ((dst WritableXReg (temp_writable_xreg)) 2156 (_ Unit (emit (MInst.AluRRImm12 op dst src (imm12_zero))))) 2157 dst)) 2158 2159;; Helper for emitting the `Lui` instruction. 2160;; TODO: This should be something like `emit_u_type`. And should share the 2161;; `MInst` with `auipc` since these instructions share the U-Type format. 2162(decl rv_lui (Imm20) XReg) 2163(rule (rv_lui imm) 2164 (let ((dst WritableXReg (temp_writable_xreg)) 2165 (_ Unit (emit (MInst.Lui dst imm)))) 2166 dst)) 2167 2168;; Helper for emitting `MInst.CsrImm` instructions. 2169(decl csr_imm (CsrImmOP CSR UImm5) XReg) 2170(rule (csr_imm op csr imm) 2171 (let ((dst WritableXReg (temp_writable_xreg)) 2172 (_ Unit (emit (MInst.CsrImm op dst imm csr)))) 2173 dst)) 2174 2175;; Helper for emitting a `MInst.CsrReg` instruction that writes the result to x0. 2176(decl csr_reg_dst_zero (CsrRegOP CSR XReg) Unit) 2177(rule (csr_reg_dst_zero op csr rs) 2178 (emit (MInst.CsrReg op (writable_zero_reg) rs csr))) 2179 2180 2181 2182(decl select_addi (Type) AluOPRRI) 2183(rule 1 (select_addi (fits_in_32 ty)) (AluOPRRI.Addiw)) 2184(rule (select_addi (fits_in_64 ty)) (AluOPRRI.Addi)) 2185 2186 2187(decl gen_andi (XReg u64) XReg) 2188(rule 1 (gen_andi x (imm12_from_u64 y)) 2189 (rv_andi x y)) 2190 2191(rule 0 (gen_andi x y) 2192 (rv_and x (imm $I64 y))) 2193 2194 2195(decl gen_or (Type ValueRegs ValueRegs) ValueRegs) 2196(rule 1 (gen_or $I128 x y) 2197 (value_regs 2198 (rv_or (value_regs_get x 0) (value_regs_get y 0)) 2199 (rv_or (value_regs_get x 1) (value_regs_get y 1)))) 2200 2201(rule 0 (gen_or (fits_in_64 _) x y) 2202 (rv_or (value_regs_get x 0) (value_regs_get y 0))) 2203 2204 2205(decl lower_ctz (Type Reg) Reg) 2206(rule (lower_ctz ty x) 2207 (gen_cltz false x ty)) 2208 2209(rule 1 (lower_ctz (fits_in_16 ty) x) 2210 (if-let true (has_zbb)) 2211 (let ((tmp Reg (gen_bseti x (ty_bits ty)))) 2212 (rv_ctzw tmp))) 2213 2214(rule 2 (lower_ctz $I32 x) 2215 (if-let true (has_zbb)) 2216 (rv_ctzw x)) 2217 2218(rule 2 (lower_ctz $I64 x) 2219 (if-let true (has_zbb)) 2220 (rv_ctz x)) 2221 2222;; Count leading zeros from a i128 bit value. 2223;; We count both halves separately and conditionally add them if it makes sense. 2224 2225(decl gen_cltz (bool XReg Type) XReg) 2226(rule (gen_cltz leading rs ty) 2227 (let ((tmp WritableXReg (temp_writable_xreg)) 2228 (step WritableXReg (temp_writable_xreg)) 2229 (sum WritableXReg (temp_writable_xreg)) 2230 (_ Unit (emit (MInst.Cltz leading sum step tmp rs ty)))) 2231 sum)) 2232 2233;; Performs a zero extension of the given value 2234(decl zext (Value) XReg) 2235 2236;; In the most generic case, we shift left and then shift right. 2237(rule 0 (zext val @ (value_type (fits_in_32 ty))) 2238 (let ((shift Imm12 (imm_from_bits (u64_wrapping_sub 64 (ty_bits ty))))) 2239 (rv_srli (rv_slli val shift) shift))) 2240 2241;; If we are zero extending a U8 we can use a `andi` instruction. 2242(rule 1 (zext val @ (value_type $I8)) 2243 (rv_andi val (imm12_const 0xff))) 2244 2245;; No point in trying to use `packh` here to zero extend 8 bit values 2246;; since we can just use `andi` instead which is part of the base ISA. 2247 2248;; If we have the `zbkb` extension `packw` can be used to zero extend 16 bit values 2249(rule 1 (zext val @ (value_type $I16)) 2250 (if-let true (has_zbkb)) 2251 (rv_packw val (zero_reg))) 2252 2253;; If we have the `zbkb` extension `pack` can be used to zero extend 32 bit registers 2254(rule 1 (zext val @ (value_type $I32)) 2255 (if-let true (has_zbkb)) 2256 (rv_pack val (zero_reg))) 2257 2258;; If we have the `zbb` extension we can use the dedicated `zext.h` instruction. 2259(rule 2 (zext val @ (value_type $I16)) 2260 (if-let true (has_zbb)) 2261 (rv_zexth val)) 2262 2263;; With `zba` we have a `zext.w` instruction 2264(rule 2 (zext val @ (value_type $I32)) 2265 (if-let true (has_zba)) 2266 (rv_zextw val)) 2267 2268;; Ignore sign extensions for values whose representation is already the full 2269;; register width. 2270(rule 3 (zext val) 2271 (if (val_already_extended (ExtendOp.Zero) val)) 2272 val) 2273 2274;; Performs a signed extension of the given value 2275(decl sext (Value) XReg) 2276 2277;; Same base case as `zext`, shift left-then-right. 2278(rule 0 (sext val @ (value_type (fits_in_32 ty))) 2279 (let ((shift Imm12 (imm_from_bits (u64_wrapping_sub 64 (ty_bits ty))))) 2280 (rv_srai (rv_slli val shift) shift))) 2281 2282;; If we have the `zbb` extension we can use the dedicated `sext.b` instruction. 2283(rule 1 (sext val @ (value_type $I8)) 2284 (if-let true (has_zbb)) 2285 (rv_sextb val)) 2286 2287;; If we have the `zbb` extension we can use the dedicated `sext.h` instruction. 2288(rule 1 (sext val @ (value_type $I16)) 2289 (if-let true (has_zbb)) 2290 (rv_sexth val)) 2291 2292;; When signed extending from 32 to 64 bits we can use a 2293;; `addiw val 0`. Also known as a `sext.w` 2294(rule 1 (sext val @ (value_type $I32)) 2295 (rv_sextw val)) 2296 2297;; Ignore sign extensions for values whose representation is already the full 2298;; register width. 2299(rule 2 (sext val) 2300 (if (val_already_extended (ExtendOp.Signed) val)) 2301 val) 2302 2303;; Helper matcher for when a value's representation is already sign or zero 2304;; extended to the full 64-bit register representation. This is used by `zext` 2305;; and `sext` above to skip the extension instruction entirely in some 2306;; circumstances. 2307(decl pure partial val_already_extended (ExtendOp Value) bool) 2308(rule 0 (val_already_extended _ v @ (value_type $I64)) true) 2309 2310;; When extending our backend always extends to the full register width, so 2311;; there's no need to extend-an-extend. 2312(rule 1 (val_already_extended (ExtendOp.Zero) (uextend _ _)) true) 2313(rule 1 (val_already_extended (ExtendOp.Signed) (sextend _ _)) true) 2314 2315;; The result of `icmp`/`fcmp` is zero or one, meaning that it's already sign 2316;; extended to the full register width. 2317(rule 1 (val_already_extended _ (icmp _ _ _ _)) true) 2318(rule 1 (val_already_extended _ (fcmp _ _ _ _)) true) 2319 2320;; The lowering for these operations always sign-extend their results due to the 2321;; use of the `*w` instructions in RV64I. Note that this requires that the 2322;; extension is from 32 to 64, 16/8-bit operations are explicitly excluded here. 2323;; There are no native instructions for the 16/8 bit operations so they must 2324;; fall through to actual sign extension above. 2325(rule 1 (val_already_extended (ExtendOp.Signed) (has_type $I32 (ishl _ _ _))) true) 2326(rule 1 (val_already_extended (ExtendOp.Signed) (has_type $I32 (ushr _ _ _))) true) 2327(rule 1 (val_already_extended (ExtendOp.Signed) (has_type $I32 (sshr _ _ _))) true) 2328(rule 1 (val_already_extended (ExtendOp.Signed) (has_type $I32 (iadd _ _ _))) true) 2329(rule 1 (val_already_extended (ExtendOp.Signed) (has_type $I32 (isub _ _ _))) true) 2330 2331(type ExtendOp 2332 (enum 2333 (Zero) 2334 (Signed))) 2335 2336(decl lower_b128_binary (AluOPRRR ValueRegs ValueRegs) ValueRegs) 2337(rule 2338 (lower_b128_binary op a b) 2339 (let 2340 ( ;; low part. 2341 (low XReg (alu_rrr op (value_regs_get a 0) (value_regs_get b 0))) 2342 ;; high part. 2343 (high XReg (alu_rrr op (value_regs_get a 1) (value_regs_get b 1)))) 2344 (value_regs low high))) 2345 2346(decl lower_smlhi (Type XReg XReg) XReg) 2347(rule 1 2348 (lower_smlhi $I64 rs1 rs2) 2349 (rv_mulh rs1 rs2)) 2350 2351(rule 2352 (lower_smlhi ty rs1 rs2) 2353 (let 2354 ((tmp XReg (rv_mul rs1 rs2))) 2355 (rv_srli tmp (imm12_const (ty_bits ty))))) 2356 2357;;;; construct shift amount.rotl on i128 will use shift to implement. So can call this function. 2358;;;; this will return shift amount and (ty_bits - "shift amount") 2359;;;; if ty_bits is greater than 64 like i128, then shmat will fallback to 64.because We are 64 bit platform. 2360(decl gen_shamt (Type XReg) ValueRegs) 2361(extern constructor gen_shamt gen_shamt) 2362 2363;; bseti: Set a single bit in a register, indexed by a constant. 2364(decl gen_bseti (Reg u64) Reg) 2365(rule (gen_bseti val bit) 2366 (if-let false (has_zbs)) 2367 (if-let false (u64_lt_eq bit 12)) 2368 (let ((const XReg (imm $I64 (u64_wrapping_shl 1 (u64_unwrap_into_u32 bit))))) 2369 (rv_or val const))) 2370 2371(rule (gen_bseti val bit) 2372 (if-let false (has_zbs)) 2373 (if-let true (u64_lt_eq bit 12)) 2374 (rv_ori val (imm12_const (u32_cast_signed (u32_wrapping_shl 1 (u64_unwrap_into_u32 bit)))))) 2375 2376(rule (gen_bseti val bit) 2377 (if-let true (has_zbs)) 2378 (rv_bseti val (imm12_const (u32_cast_signed (u64_unwrap_into_u32 bit))))) 2379 2380 2381(decl gen_popcnt (XReg) Reg) 2382(rule (gen_popcnt rs) 2383 (let 2384 ((tmp WritableXReg (temp_writable_xreg)) 2385 (step WritableXReg (temp_writable_xreg)) 2386 (sum WritableXReg (temp_writable_xreg)) 2387 (_ Unit (emit (MInst.Popcnt sum step tmp rs $I64)))) 2388 (writable_reg_to_reg sum))) 2389 2390;; Generates a AMode that points to a register plus an offset. 2391(decl gen_reg_offset_amode (Reg i64) AMode) 2392(extern constructor gen_reg_offset_amode gen_reg_offset_amode) 2393 2394;; Generates a AMode that an offset from the stack pointer. 2395(decl gen_sp_offset_amode (i64) AMode) 2396(extern constructor gen_sp_offset_amode gen_sp_offset_amode) 2397 2398;; Generates a AMode that an offset from the frame pointer. 2399(decl gen_fp_offset_amode (i64) AMode) 2400(extern constructor gen_fp_offset_amode gen_fp_offset_amode) 2401 2402;; Generates an AMode that points to a stack slot + offset. 2403(decl gen_stack_slot_amode (StackSlot i64) AMode) 2404(extern constructor gen_stack_slot_amode gen_stack_slot_amode) 2405 2406;; Generates a AMode that points to a constant in the constant pool. 2407(decl gen_const_amode (VCodeConstant) AMode) 2408(extern constructor gen_const_amode gen_const_amode) 2409 2410 2411 2412;; Tries to match a Value + Offset into an AMode 2413(decl amode (Value i32) AMode) 2414(rule 0 (amode addr offset) (amode_inner addr offset)) 2415 2416;; If we are adding a constant offset with an iadd we can instead make that 2417;; offset part of the amode offset. 2418;; 2419;; We can't recurse into `amode` again since that could cause stack overflows. 2420;; See: https://github.com/bytecodealliance/wasmtime/pull/6968 2421(rule 1 (amode (iadd _ addr (i32_from_iconst y)) offset) 2422 (if-let new_offset (i32_checked_add y offset)) 2423 (amode_inner addr new_offset)) 2424(rule 2 (amode (iadd _ (i32_from_iconst x) addr) offset) 2425 (if-let new_offset (i32_checked_add x offset)) 2426 (amode_inner addr new_offset)) 2427 2428 2429;; These are the normal rules for generating an AMode. 2430(decl amode_inner (Value i32) AMode) 2431 2432;; In the simplest case we just lower into a Reg+Offset 2433(rule 0 (amode_inner r @ (value_type (ty_addr64 _)) offset) 2434 (gen_reg_offset_amode r offset)) 2435 2436;; If the value is a `get_frame_pointer`, we can just use the offset from that. 2437(rule 1 (amode_inner (get_frame_pointer _) offset) 2438 (gen_fp_offset_amode offset)) 2439 2440;; If the value is a `get_stack_pointer`, we can just use the offset from that. 2441(rule 1 (amode_inner (get_stack_pointer _) offset) 2442 (gen_sp_offset_amode offset)) 2443 2444;; Similarly if the value is a `stack_addr` we can also turn that into an sp offset. 2445(rule 1 (amode_inner (stack_addr _ ss ss_offset) amode_offset) 2446 (if-let combined_offset (i32_checked_add ss_offset amode_offset)) 2447 (gen_stack_slot_amode ss combined_offset)) 2448 2449 2450;; Helpers for sinkable loads ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2451 2452;; RISC-V doesen't really have sinkable loads. But the regular load instructions 2453;; sign / zero extend their results to 64 bits. So we can pretend they are 2454;; an extend instruction with a sinkable load. This allows us to have better 2455;; lowerings on these cases. 2456 2457;; Extract a sinkable instruction from a value operand. 2458(decl sinkable_inst (Inst) Value) 2459(extern extractor sinkable_inst sinkable_inst) 2460 2461;; Matches a sinkable load. 2462(decl sinkable_load (Inst Type MemFlags Value Offset32) Value) 2463(extractor (sinkable_load inst ty flags addr offset) 2464 (and 2465 (load _ (little_or_native_endian flags) addr offset) 2466 (sinkable_inst (has_type ty inst)))) 2467 2468;; Returns a canonical type for a LoadOP. We only return I64 or F64. 2469(decl load_op_reg_type (LoadOP) Type) 2470(rule 1 (load_op_reg_type (LoadOP.Fld)) $F64) 2471(rule 1 (load_op_reg_type (LoadOP.Flw)) $F64) 2472(rule 1 (load_op_reg_type (LoadOP.Flh)) $F64) 2473(rule 0 (load_op_reg_type _) $I64) 2474 2475;; Helper constructor to build a load instruction. 2476;; 2477;; Recursion: recursive rule can only match once, since it matches on 2478;; `LoadOP.Flh` and emits `LoadOP.Lh`. 2479(decl rec gen_load (AMode LoadOP MemFlags) Reg) 2480(rule (gen_load amode op flags) 2481 (let ((dst WritableReg (temp_writable_reg (load_op_reg_type op))) 2482 (_ Unit (emit (MInst.Load dst op flags amode)))) 2483 dst)) 2484(rule 1 (gen_load amode (LoadOP.Flh) flags) 2485 (if-let false (has_zfhmin)) 2486 (gen_bitcast (gen_load amode (LoadOP.Lh) flags) $I16 $F16)) 2487 2488;; Similar to `gen_load` but marks `Inst` as sunk at the current point. 2489;; 2490;; This is only useful for load op's that perform some additional computation 2491;; such as extending the loaded value. 2492(decl gen_sunk_load (Inst AMode LoadOP MemFlags) Reg) 2493(rule (gen_sunk_load inst amode op flags) 2494 (let ((_ Unit (sink_inst inst))) 2495 (gen_load amode op flags))) 2496 2497 2498;; Helper constructor to build a store instruction. 2499;; 2500;; This helper contains a special-case for zero constants stored to memory to 2501;; directly store the `zero` register to memory. See #7162 for some discussion 2502;; on why this doesn't just fall out. 2503(decl gen_store (AMode MemFlags Value) InstOutput) 2504(rule 2 (gen_store amode flags val @ (value_type $F16)) 2505 (if-let false (has_zfhmin)) 2506 (rv_store amode (StoreOP.Sh) flags (gen_bitcast val $F16 $I16))) 2507(rule 1 (gen_store amode flags val @ (value_type ty)) 2508 (if-let (u64_from_iconst 0) val) 2509 (rv_store amode (store_op ty) flags (zero_reg))) 2510(rule 0 (gen_store amode flags val @ (value_type ty)) 2511 (rv_store amode (store_op ty) flags val)) 2512 2513;; Emit a raw instruction to store a register into memory. 2514;; 2515;; Note that the `src` operand must have the correct type for the `op` 2516;; specified. 2517(decl rv_store (AMode StoreOP MemFlags Reg) InstOutput) 2518(rule (rv_store amode op flags src) 2519 (side_effect (SideEffectNoResult.Inst (MInst.Store amode op flags src)))) 2520 2521 2522 2523 2524(decl valid_atomic_transaction (Type) Type) 2525(extern extractor valid_atomic_transaction valid_atomic_transaction) 2526 2527;;helper function. 2528;;construct an atomic instruction. 2529(decl gen_atomic (AtomicOP Reg Reg AMO) Reg) 2530(rule 2531 (gen_atomic op addr src amo) 2532 (let 2533 ((tmp WritableXReg (temp_writable_xreg)) 2534 (_ Unit (emit (MInst.Atomic op tmp addr src amo)))) 2535 tmp)) 2536 2537;; helper function 2538(decl get_atomic_rmw_op (Type AtomicRmwOp) AtomicOP) 2539(rule 2540 (get_atomic_rmw_op $I32 (AtomicRmwOp.Add)) 2541 (AtomicOP.AmoaddW)) 2542(rule 2543 (get_atomic_rmw_op $I64 (AtomicRmwOp.Add)) 2544 (AtomicOP.AmoaddD)) 2545 2546(rule 2547 (get_atomic_rmw_op $I32 (AtomicRmwOp.And)) 2548 (AtomicOP.AmoandW)) 2549 2550(rule 2551 (get_atomic_rmw_op $I64 (AtomicRmwOp.And)) 2552 (AtomicOP.AmoandD)) 2553 2554(rule 2555 (get_atomic_rmw_op $I32 (AtomicRmwOp.Or)) 2556 (AtomicOP.AmoorW)) 2557 2558(rule 2559 (get_atomic_rmw_op $I64 (AtomicRmwOp.Or)) 2560 (AtomicOP.AmoorD)) 2561 2562(rule 2563 (get_atomic_rmw_op $I32 (AtomicRmwOp.Smax)) 2564 (AtomicOP.AmomaxW)) 2565 2566(rule 2567 (get_atomic_rmw_op $I64 (AtomicRmwOp.Smax)) 2568 (AtomicOP.AmomaxD)) 2569 2570(rule 2571 (get_atomic_rmw_op $I32 (AtomicRmwOp.Smin)) 2572 (AtomicOP.AmominW)) 2573 2574(rule 2575 (get_atomic_rmw_op $I64 (AtomicRmwOp.Smin)) 2576 (AtomicOP.AmominD)) 2577 2578(rule 2579 (get_atomic_rmw_op $I32 (AtomicRmwOp.Umax)) 2580 (AtomicOP.AmomaxuW) 2581) 2582 2583(rule 2584 (get_atomic_rmw_op $I64 (AtomicRmwOp.Umax)) 2585 (AtomicOP.AmomaxuD)) 2586 2587(rule 2588 (get_atomic_rmw_op $I32 (AtomicRmwOp.Umin)) 2589 (AtomicOP.AmominuW)) 2590 2591(rule 2592 (get_atomic_rmw_op $I64 (AtomicRmwOp.Umin)) 2593 (AtomicOP.AmominuD)) 2594 2595(rule 2596 (get_atomic_rmw_op $I32 (AtomicRmwOp.Xchg)) 2597 (AtomicOP.AmoswapW)) 2598 2599(rule 2600 (get_atomic_rmw_op $I64 (AtomicRmwOp.Xchg)) 2601 (AtomicOP.AmoswapD)) 2602 2603(rule 2604 (get_atomic_rmw_op $I32 (AtomicRmwOp.Xor)) 2605 (AtomicOP.AmoxorW)) 2606 2607(rule 2608 (get_atomic_rmw_op $I64 (AtomicRmwOp.Xor)) 2609 (AtomicOP.AmoxorD)) 2610 2611(decl atomic_amo () AMO) 2612(extern constructor atomic_amo atomic_amo) 2613 2614 2615(decl gen_atomic_load (Reg Type) Reg) 2616(rule 2617 (gen_atomic_load p ty) 2618 (let 2619 ((tmp WritableXReg (temp_writable_xreg)) 2620 (_ Unit (emit (MInst.AtomicLoad tmp ty p)))) 2621 (writable_reg_to_reg tmp))) 2622 2623;;; 2624(decl gen_atomic_store (Reg Type Reg) InstOutput) 2625(rule 2626 (gen_atomic_store p ty src) 2627 (side_effect (SideEffectNoResult.Inst (MInst.AtomicStore src ty p))) 2628) 2629 2630 2631;; Rounds a FReg by converting the value into an integer and back with a specified 2632;; float rounding mode. 2633(decl float_round_fcvt (Type FRM FReg) FReg) 2634(rule (float_round_fcvt $F32 frm rs) (rv_fcvtsw frm (rv_fcvtws frm rs))) 2635(rule (float_round_fcvt $F64 frm rs) (rv_fcvtdl frm (rv_fcvtld frm rs))) 2636 2637(decl gen_float_round (FRM FReg Type) FReg) 2638(rule 0 (gen_float_round frm rs ty) 2639 (let ( 2640 ;; if rs is NaN/+-Infinity/+-Zero or if the exponent is larger than # of bits 2641 ;; in mantissa, the result is the same as src, check for these cases first. 2642 (max FReg (imm ty (float_int_max ty))) 2643 (abs FReg (rv_fabs ty rs)) 2644 (exact XReg (rv_flt ty abs max)) 2645 2646 ;; Manually round the value using the fcvt instructions 2647 ;; to move the value to an integer register and back. 2648 (fcvt FReg (float_round_fcvt ty frm rs)) 2649 ;; Restore the sign bit from the initial value. 2650 (rounded FReg (rv_fsgnj ty fcvt rs)) 2651 2652 ;; We want to return a arithmetic nan if the input is a canonical nan. 2653 ;; Convert them by adding 0.0 to the input. 2654 (float_zero FReg (gen_bitcast (zero_reg) (float_int_of_same_size ty) ty)) 2655 (corrected_nan FReg (rv_fadd ty (FRM.RNE) rs float_zero))) 2656 2657 ;; Check if the value cannot be rounded exactly and return the source input if so 2658 (gen_select_freg (cmp_eqz exact) corrected_nan rounded))) 2659 2660;; With Zfa we can use the dedicated `fround` instruction. 2661(rule 1 (gen_float_round frm rs ty) 2662 (if-let true (has_zfa)) 2663 (rv_fround ty frm rs)) 2664 2665 2666 2667(decl gen_stack_addr (StackSlot Offset32) Reg) 2668(extern constructor gen_stack_addr gen_stack_addr) 2669 2670; Recursion: bounded by only matching when one of the inputs is a zero register, 2671; but not both. 2672(decl rec gen_select_xreg (IntegerCompare XReg XReg) XReg) 2673 2674(rule 6 (gen_select_xreg (int_compare_decompose cc x y) x y) 2675 (if-let (IntCC.UnsignedLessThan) (intcc_without_eq cc)) 2676 (if-let true (has_zbb)) 2677 (rv_minu x y)) 2678 2679(rule 6 (gen_select_xreg (int_compare_decompose cc x y) x y) 2680 (if-let (IntCC.SignedLessThan) (intcc_without_eq cc)) 2681 (if-let true (has_zbb)) 2682 (rv_min x y)) 2683 2684(rule 6 (gen_select_xreg (int_compare_decompose cc x y) x y) 2685 (if-let (IntCC.UnsignedGreaterThan) (intcc_without_eq cc)) 2686 (if-let true (has_zbb)) 2687 (rv_maxu x y)) 2688 2689(rule 6 (gen_select_xreg (int_compare_decompose cc x y) x y) 2690 (if-let (IntCC.SignedGreaterThan) (intcc_without_eq cc)) 2691 (if-let true (has_zbb)) 2692 (rv_max x y)) 2693 2694;; Rotate Zero Reg to the right. This allows us to write fewer rules 2695;; below when matching the zero register 2696;; 2697;; Additionally prevent this rule from recursing infinitely by only 2698;; matching when one of the inputs is the zero register, but not both. 2699 2700(rule 5 (gen_select_xreg (int_compare_decompose cc a @ (zero_reg) b @ (non_zero_reg)) x y) 2701 (if-let true (has_zicond)) 2702 (gen_select_xreg (int_compare (intcc_swap_args cc) b a) x y)) 2703 2704(rule 4 (gen_select_xreg c @ (int_compare_decompose cc a b) x @ (zero_reg) y @ (non_zero_reg)) 2705 (if-let true (has_zicond)) 2706 (gen_select_xreg (int_compare (intcc_complement cc) a b) y x)) 2707 2708(rule 3 (gen_select_xreg (int_compare_decompose (IntCC.Equal) c (zero_reg)) x (zero_reg)) 2709 (if-let true (has_zicond)) 2710 (rv_czero_nez x c)) 2711 2712(rule 3 (gen_select_xreg (int_compare_decompose (IntCC.NotEqual) c (zero_reg)) x (zero_reg)) 2713 (if-let true (has_zicond)) 2714 (rv_czero_eqz x c)) 2715 2716(rule 2 (gen_select_xreg (int_compare_decompose (IntCC.Equal) c (zero_reg)) x y) 2717 (if-let true (has_zicond)) 2718 (rv_or 2719 (rv_czero_nez x c) 2720 (rv_czero_eqz y c))) 2721 2722(rule 2 (gen_select_xreg (int_compare_decompose (IntCC.NotEqual) c (zero_reg)) x y) 2723 (if-let true (has_zicond)) 2724 (rv_or 2725 (rv_czero_eqz x c) 2726 (rv_czero_nez y c))) 2727 2728;; It is still beneficial to emit the full compare instruction, and then the 3 instruction 2729;; select using zicond, so do that here as a last resort. 2730(rule 1 (gen_select_xreg compare x y) 2731 (if-let true (has_zicond)) 2732 (gen_select_xreg (cmp_nez (lower_int_compare compare)) x y)) 2733 2734;; In the base case we emit a conditional branch and a few moves. 2735 2736(rule 0 (gen_select_xreg c x y) 2737 (let 2738 ((dst WritableReg (temp_writable_xreg)) 2739 (_ Unit (emit (MInst.Select dst c x y)))) 2740 (writable_reg_to_reg dst))) 2741 2742 2743(decl gen_select_vreg (IntegerCompare VReg VReg) VReg) 2744(rule (gen_select_vreg c x y) 2745 (let 2746 ((dst WritableReg (temp_writable_vreg)) 2747 (_ Unit (emit (MInst.Select dst c (vreg_to_reg x) (vreg_to_reg y))))) 2748 (writable_reg_to_reg dst))) 2749(decl gen_select_freg (IntegerCompare FReg FReg) FReg) 2750(rule (gen_select_freg c x y) 2751 (let 2752 ((dst WritableReg (temp_writable_freg)) 2753 (_ Unit (emit (MInst.Select dst c (freg_to_reg x) (freg_to_reg y))))) 2754 (writable_reg_to_reg dst))) 2755(decl gen_select_regs (IntegerCompare ValueRegs ValueRegs) ValueRegs) 2756(rule (gen_select_regs c x y) 2757 (let 2758 ((dst1 WritableReg (temp_writable_xreg)) 2759 (dst2 WritableReg (temp_writable_xreg)) 2760 (_ Unit (emit (MInst.Select (writable_value_regs dst1 dst2) c x y)))) 2761 (value_regs dst1 dst2))) 2762 2763(decl udf (TrapCode) InstOutput) 2764(rule 2765 (udf code) 2766 (side_effect (SideEffectNoResult.Inst (MInst.Udf code)))) 2767 2768(decl load_op (Type) LoadOP) 2769(extern constructor load_op load_op) 2770 2771(decl store_op (Type) StoreOP) 2772(extern constructor store_op store_op) 2773 2774 2775;;;; load extern name 2776(decl load_ext_name (ExternalName i64 RelocDistance) Reg) 2777(rule (load_ext_name name offset _dist) 2778 (if-let true (is_pic)) 2779 (rv_add (load_ext_name_got name) (imm $I64 (i64_cast_unsigned offset)))) 2780(rule 1 (load_ext_name name 0 _dist) 2781 (if-let true (is_pic)) 2782 (load_ext_name_got name)) 2783(rule (load_ext_name name offset (RelocDistance.Near)) 2784 (if-let false (is_pic)) 2785 (load_ext_name_near name offset)) 2786(rule (load_ext_name name offset (RelocDistance.Far)) 2787 (if-let false (is_pic)) 2788 (load_ext_name_far name offset)) 2789 2790(decl pure is_pic () bool) 2791(extern constructor is_pic is_pic) 2792 2793;; Helper for emitting `MInst.LoadExtNameGot` instructions. 2794(decl load_ext_name_got (BoxExternalName) Reg) 2795(rule (load_ext_name_got extname) 2796 (let ((dst WritableReg (temp_writable_reg $I64)) 2797 (_ Unit (emit (MInst.LoadExtNameGot dst extname)))) 2798 dst)) 2799 2800;; Helper for emitting `MInst.LoadExtNameNear` instructions. 2801(decl load_ext_name_near (BoxExternalName i64) Reg) 2802(rule (load_ext_name_near extname offset) 2803 (let ((dst WritableReg (temp_writable_reg $I64)) 2804 (_ Unit (emit (MInst.LoadExtNameNear dst extname offset)))) 2805 dst)) 2806 2807;; Helper for emitting `MInst.LoadExtNameFar` instructions. 2808(decl load_ext_name_far (BoxExternalName i64) Reg) 2809(rule (load_ext_name_far extname offset) 2810 (let ((dst WritableReg (temp_writable_reg $I64)) 2811 (_ Unit (emit (MInst.LoadExtNameFar dst extname offset)))) 2812 dst)) 2813 2814(decl elf_tls_get_addr (ExternalName) Reg) 2815(rule (elf_tls_get_addr name) 2816 (let ((dst WritableReg (temp_writable_reg $I64)) 2817 (_ Unit (emit (MInst.ElfTlsGetAddr dst name)))) 2818 dst)) 2819 2820;;; some float binary operation 2821;;; 1. need move into x register. 2822;;; 2. do the operation. 2823;;; 3. move back. 2824(decl lower_float_binary (AluOPRRR FReg FReg Type) FReg) 2825(rule 2826 (lower_float_binary op rs1 rs2 ty) 2827 (let ((x_rs1 XReg (move_f_to_x rs1 ty)) 2828 (x_rs2 XReg (move_f_to_x rs2 ty)) 2829 (tmp XReg (alu_rrr op x_rs1 x_rs2))) 2830 (move_x_to_f tmp ty))) 2831 2832 2833(decl sub_i128 (ValueRegs ValueRegs) ValueRegs) 2834(rule 2835 (sub_i128 x y ) 2836 (let ( 2837 ;; low part. 2838 (low XReg (rv_sub (value_regs_get x 0) (value_regs_get y 0))) 2839 ;; compute borrow. 2840 (borrow XReg (rv_sltu (value_regs_get x 0) low)) 2841 ;; 2842 (high_tmp XReg (rv_sub (value_regs_get x 1) (value_regs_get y 1))) 2843 ;; 2844 (high XReg (rv_sub high_tmp borrow))) 2845 (value_regs low high))) 2846 2847;; Consume a CmpResult, producing a branch on its result. 2848(decl cond_br (IntegerCompare CondBrTarget CondBrTarget) SideEffectNoResult) 2849(rule (cond_br cmp then else) 2850 (SideEffectNoResult.Inst 2851 (MInst.CondBr then else cmp))) 2852 2853;; Helper for emitting the `j` mnemonic, an unconditional jump to label. 2854(decl rv_j (MachLabel) SideEffectNoResult) 2855(rule (rv_j label) 2856 (SideEffectNoResult.Inst (MInst.Jal label))) 2857 2858;; Construct an IntegerCompare value. 2859(decl int_compare (IntCC XReg XReg) IntegerCompare) 2860(extern constructor int_compare int_compare) 2861 2862;; Extract the components of an `IntegerCompare` 2863(decl int_compare_decompose (IntCC XReg XReg) IntegerCompare) 2864(extern extractor infallible int_compare_decompose int_compare_decompose) 2865 2866(decl label_to_br_target (MachLabel) CondBrTarget) 2867(extern constructor label_to_br_target label_to_br_target) 2868(convert MachLabel CondBrTarget label_to_br_target) 2869 2870(decl cmp_eqz (XReg) IntegerCompare) 2871(rule (cmp_eqz r) (int_compare (IntCC.Equal) r (zero_reg))) 2872 2873(decl cmp_nez (XReg) IntegerCompare) 2874(rule (cmp_nez r) (int_compare (IntCC.NotEqual) r (zero_reg))) 2875 2876(decl cmp_eq (XReg XReg) IntegerCompare) 2877(rule (cmp_eq rs1 rs2) (int_compare (IntCC.Equal) rs1 rs2)) 2878 2879(decl cmp_ne (XReg XReg) IntegerCompare) 2880(rule (cmp_ne rs1 rs2) (int_compare (IntCC.NotEqual) rs1 rs2)) 2881 2882(decl cmp_lt (XReg XReg) IntegerCompare) 2883(rule (cmp_lt rs1 rs2) (int_compare (IntCC.SignedLessThan) rs1 rs2)) 2884 2885(decl cmp_ltz (XReg) IntegerCompare) 2886(rule (cmp_ltz rs) (int_compare (IntCC.SignedLessThan) rs (zero_reg))) 2887 2888(decl cmp_gt (XReg XReg) IntegerCompare) 2889(rule (cmp_gt rs1 rs2) (int_compare (IntCC.SignedGreaterThan) rs1 rs2)) 2890 2891(decl cmp_ge (XReg XReg) IntegerCompare) 2892(rule (cmp_ge rs1 rs2) (int_compare (IntCC.SignedGreaterThanOrEqual) rs1 rs2)) 2893 2894(decl cmp_le (XReg XReg) IntegerCompare) 2895(rule (cmp_le rs1 rs2) (int_compare (IntCC.SignedLessThanOrEqual) rs1 rs2)) 2896 2897(decl cmp_gtu (XReg XReg) IntegerCompare) 2898(rule (cmp_gtu rs1 rs2) (int_compare (IntCC.UnsignedGreaterThan) rs1 rs2)) 2899 2900(decl cmp_geu (XReg XReg) IntegerCompare) 2901(rule (cmp_geu rs1 rs2) (int_compare (IntCC.UnsignedGreaterThanOrEqual) rs1 rs2)) 2902 2903(decl cmp_ltu (XReg XReg) IntegerCompare) 2904(rule (cmp_ltu rs1 rs2) (int_compare (IntCC.UnsignedLessThan) rs1 rs2)) 2905 2906(decl cmp_leu (XReg XReg) IntegerCompare) 2907(rule (cmp_leu rs1 rs2) (int_compare (IntCC.UnsignedLessThanOrEqual) rs1 rs2)) 2908 2909;; Helper to generate an `IntegerCompare` which represents the "truthy" value of 2910;; the input provided. 2911;; 2912;; This is used in `Select` and `brif` for example to generate conditional 2913;; branches. The returned comparison, when taken, represents that `Value` is 2914;; nonzero. When not taken the input `Value` is zero. 2915(decl is_nonzero_cmp (Value) IntegerCompare) 2916 2917;; Base case - convert to a "truthy" value and compare it against zero. 2918;; 2919;; Note that non-64-bit types need to be extended since the upper bits from 2920;; Cranelift's point of view are undefined. Favor a zero extension for 8-bit 2921;; types because that's a single `andi` instruction, but favor sign-extension 2922;; for 16 and 32-bit types because many RISC-V which operate on the low 32-bits. 2923;; Additionally the base 64-bit ISA has a single instruction for sign-extending 2924;; from 32 to 64-bits which makes that a bit cheaper if used. 2925;; of registers sign-extend the results. 2926(rule 0 (is_nonzero_cmp val @ (value_type (fits_in_64 _))) 2927 (cmp_nez (sext val))) 2928(rule 1 (is_nonzero_cmp val @ (value_type $I8)) 2929 (cmp_nez (zext val))) 2930(rule 1 (is_nonzero_cmp val @ (value_type $I128)) 2931 (cmp_nez (rv_or (value_regs_get val 0) (value_regs_get val 1)))) 2932 2933;; If the input value is itself an `icmp` or `fcmp` we can avoid generating the 2934;; result of the comparison and instead move the comparison directly into the 2935;; `IntegerCompare` that's returned. 2936(rule 2 (is_nonzero_cmp (maybe_uextend (icmp _ cc a b @ (value_type (fits_in_64 _))))) 2937 (icmp_to_int_compare cc a b)) 2938(rule 2 (is_nonzero_cmp (maybe_uextend (fcmp _ cc a @ (value_type ty) b))) 2939 (fcmp_to_float_compare cc ty a b)) 2940 2941;; Creates an `IntegerCompare` from an `icmp` node's parts. This will extend 2942;; values as necessary to their full register width to perform the 2943;; comparison. The returned `IntegerCompare` is suitable to use in conditional 2944;; branches for example. 2945;; 2946;; Note that this should ideally only be used when the `IntegerCompare` returned 2947;; is fed into a branch. If `IntegerCompare` is materialized this will miss out 2948;; on optimizations to compare against constants using some native instructions. 2949(decl icmp_to_int_compare (IntCC Value Value) IntegerCompare) 2950(rule 0 (icmp_to_int_compare cc a b @ (value_type (fits_in_64 in_ty))) 2951 (int_compare cc (put_value_in_reg_for_icmp cc a) (put_value_in_reg_for_icmp cc b))) 2952(rule 1 (icmp_to_int_compare cc a b @ (value_type $I128)) 2953 (cmp_nez (lower_icmp_i128 cc a b))) 2954 2955;; Places a `Value` into a full register width to prepare for a comparison 2956;; using `IntCC`. 2957;; 2958;; This is largely a glorified means of choosing sign-extension or 2959;; zero-extension for the `Value` input. 2960(decl put_value_in_reg_for_icmp (IntCC Value) XReg) 2961 2962;; Base cases, use the `cc` to determine whether to zero or sign extend. 2963(rule 0 (put_value_in_reg_for_icmp cc val) 2964 (zext val)) 2965(rule 1 (put_value_in_reg_for_icmp cc val) 2966 (if (signed_cond_code cc)) 2967 (sext val)) 2968 2969;; For equality and inequality favor sign extension since it's generally 2970;; easier to perform sign extension on RV64 via native instructions. For 8-bit 2971;; types though use zero-extension since that's a single instruction `and`. 2972(rule 2 (put_value_in_reg_for_icmp (IntCC.Equal) val @ (value_type (fits_in_64 _))) 2973 (sext val)) 2974(rule 2 (put_value_in_reg_for_icmp (IntCC.NotEqual) val @ (value_type (fits_in_64 _))) 2975 (sext val)) 2976(rule 3 (put_value_in_reg_for_icmp (IntCC.Equal) val @ (value_type $I8)) 2977 (zext val)) 2978(rule 3 (put_value_in_reg_for_icmp (IntCC.NotEqual) val @ (value_type $I8)) 2979 (zext val)) 2980 2981;; As a special case use `x0` directly if a constant is 0. 2982(rule 4 (put_value_in_reg_for_icmp _ (i64_from_iconst 0)) 2983 (zero_reg)) 2984 2985 2986(decl partial lower_branch (Inst MachLabelSlice) Unit) 2987(rule (lower_branch (jump _) (single_target label)) 2988 (emit_side_effect (rv_j label))) 2989 2990(rule (lower_branch (brif v _ _) (two_targets then else)) 2991 (emit_side_effect (cond_br (is_nonzero_cmp v) then else))) 2992 2993(decl lower_br_table (Reg MachLabelSlice) Unit) 2994(extern constructor lower_br_table lower_br_table) 2995 2996(rule (lower_branch (br_table index _) targets) 2997 (lower_br_table index targets)) 2998 2999(decl load_ra () Reg) 3000(extern constructor load_ra load_ra) 3001 3002 3003;; Generates a bitcast instruction. 3004;; Args are: src, src_ty, dst_ty 3005;; 3006;; Recursion: only recursive rule matches on vec-to-float, and emits vec-to-int 3007;; and int-to-float bitcasts, so this can only recurse once. 3008(decl rec gen_bitcast (Reg Type Type) Reg) 3009 3010(rule 9 (gen_bitcast r (ty_supported_float_size $F16) (ty_supported_vec _)) (if-let false (has_zvfh)) (rv_vfmv_sf r (vstate_from_type $F32))) 3011(rule 8 (gen_bitcast r (ty_supported_vec ty) (ty_supported_float_size $F16)) (if-let false (has_zvfh)) (gen_bitcast (gen_bitcast r ty $I16) $I16 $F16)) 3012(rule 7 (gen_bitcast r (ty_supported_float_min src_ty) (ty_supported_vec _)) (rv_vfmv_sf r src_ty)) 3013(rule 6 (gen_bitcast r (ty_supported_vec _) (ty_supported_float_min dst_ty)) (rv_vfmv_fs r dst_ty)) 3014 3015(rule 5 (gen_bitcast r (ty_int_ref_scalar_64 src_ty) (ty_supported_vec _)) (rv_vmv_sx r src_ty)) 3016(rule 4 (gen_bitcast r (ty_supported_vec _) (ty_int_ref_scalar_64 dst_ty)) (rv_vmv_xs r dst_ty)) 3017(rule 3 (gen_bitcast r (ty_supported_float_min $F16) $I16) (rv_fmvxh r)) 3018(rule 2 (gen_bitcast r (ty_supported_float_size $F16) $I16) (rv_fmvxw r)) 3019(rule 2 (gen_bitcast r (ty_supported_float_size $F32) $I32) (rv_fmvxw r)) 3020(rule 2 (gen_bitcast r (ty_supported_float_size $F64) $I64) (rv_fmvxd r)) 3021(rule 1 (gen_bitcast r $I16 (ty_supported_float_min $F16)) (rv_fmvhx r)) 3022;; Smaller float types are NaN-boxed inside of larger floating point types on RISC-V, meaning the 3023;; smaller float is stored in the lower bits of the larger float and all the other bits are set to 1. 3024;; This is done automatically by the correctly-sized `fmv` instructions but needs to be done manually 3025;; here when using a 32-bit `fmv` for a 16-bit float. 3026(rule 0 (gen_bitcast r $I16 (ty_supported_float_size $F16)) (rv_fmvwx (rv_or r (imm $I32 0xffff0000)))) 3027(rule 0 (gen_bitcast r $I32 (ty_supported_float_size $F32)) (rv_fmvwx r)) 3028(rule 0 (gen_bitcast r $I64 (ty_supported_float_size $F64)) (rv_fmvdx r)) 3029(rule -1 (gen_bitcast r (ty_supported_float_size _) (ty_supported_float_size _)) r) 3030(rule -2 (gen_bitcast r (ty_int_ref_scalar_64 _) (ty_int_ref_scalar_64 _)) r) 3031(rule -3 (gen_bitcast r (ty_supported_vec _) (ty_supported_vec _)) r) 3032 3033(decl move_f_to_x (FReg Type) XReg) 3034(rule (move_f_to_x r ty) (gen_bitcast r ty (float_int_of_same_size ty))) 3035 3036(decl move_x_to_f (XReg Type) FReg) 3037(rule (move_x_to_f r ty) (gen_bitcast r (float_int_of_same_size ty) ty)) 3038 3039(decl float_int_of_same_size (Type) Type) 3040(rule (float_int_of_same_size $F16) $I16) 3041(rule (float_int_of_same_size $F32) $I32) 3042(rule (float_int_of_same_size $F64) $I64) 3043 3044 3045(decl gen_brev8 (Reg Type) Reg) 3046(rule 1 3047 (gen_brev8 rs _) 3048 (if-let true (has_zbkb)) 3049 (rv_brev8 rs)) 3050(rule 3051 (gen_brev8 rs ty) 3052 (if-let false (has_zbkb)) 3053 (let 3054 ((tmp WritableXReg (temp_writable_xreg)) 3055 (tmp2 WritableXReg (temp_writable_xreg)) 3056 (step WritableXReg (temp_writable_xreg)) 3057 (rd WritableXReg (temp_writable_xreg)) 3058 (_ Unit (emit (MInst.Brev8 rs ty step tmp tmp2 rd)))) 3059 (writable_reg_to_reg rd))) 3060 3061;; Negates x 3062;; Equivalent to 0 - x 3063(decl neg (Type ValueRegs) ValueRegs) 3064(rule 1 (neg (fits_in_64 (ty_int ty)) val) 3065 (value_reg 3066 (rv_neg (value_regs_get val 0)))) 3067 3068(rule 2 (neg $I128 val) 3069 (sub_i128 (value_regs_zero) val)) 3070 3071 3072;; Builds an instruction sequence that traps if the comparison succeeds. 3073(decl gen_trapif (IntCC XReg XReg TrapCode) InstOutput) 3074(rule (gen_trapif cc a b trap_code) 3075 (side_effect (SideEffectNoResult.Inst (MInst.TrapIf a b cc trap_code)))) 3076 3077;; Builds an instruction sequence that traps if the input is non-zero. 3078(decl gen_trapnz (XReg TrapCode) InstOutput) 3079(rule (gen_trapnz test trap_code) 3080 (gen_trapif (IntCC.NotEqual) test (zero_reg) trap_code)) 3081 3082;; Builds an instruction sequence that traps if the input is zero. 3083(decl gen_trapz (XReg TrapCode) InstOutput) 3084(rule (gen_trapz test trap_code) 3085 (gen_trapif (IntCC.Equal) test (zero_reg) trap_code)) 3086 3087;; Converts bool to the corresponding {in,}equality condition 3088(type ZeroCond 3089 (enum 3090 Zero 3091 NonZero)) 3092 3093(decl zero_cond_to_cc (ZeroCond) IntCC) 3094(rule (zero_cond_to_cc (ZeroCond.Zero)) (IntCC.Equal)) 3095(rule (zero_cond_to_cc (ZeroCond.NonZero)) (IntCC.NotEqual)) 3096 3097;; Builds an instruction sequence for wide trapz/nz 3098(decl gen_trapif_val_i128 (ZeroCond ValueRegs TrapCode) InstOutput) 3099(rule (gen_trapif_val_i128 zero_cond value trap_code) 3100 (let ((lo XReg (value_regs_get value 0)) 3101 (hi XReg (value_regs_get value 1)) 3102 (test XReg (rv_or hi lo))) 3103 (gen_trapif (zero_cond_to_cc zero_cond) test (zero_reg) trap_code))) 3104 3105;;;; Helpers for Emitting Calls ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 3106 3107(decl gen_call_info (Sig ExternalName CallArgList CallRetList OptionTryCallInfo bool) BoxCallInfo) 3108(extern constructor gen_call_info gen_call_info) 3109 3110(decl gen_call_ind_info (Sig Reg CallArgList CallRetList OptionTryCallInfo) BoxCallIndInfo) 3111(extern constructor gen_call_ind_info gen_call_ind_info) 3112 3113(decl gen_return_call_info (Sig ExternalName CallArgList) BoxReturnCallInfo) 3114(extern constructor gen_return_call_info gen_return_call_info) 3115 3116(decl gen_return_call_ind_info (Sig Reg CallArgList) BoxReturnCallIndInfo) 3117(extern constructor gen_return_call_ind_info gen_return_call_ind_info) 3118 3119;; Helper for creating `MInst.Call` instructions. 3120(decl call_impl (BoxCallInfo) SideEffectNoResult) 3121(rule (call_impl info) 3122 (SideEffectNoResult.Inst (MInst.Call info))) 3123 3124;; Helper for creating `MInst.CallInd` instructions. 3125(decl call_ind_impl (BoxCallIndInfo) SideEffectNoResult) 3126(rule (call_ind_impl info) 3127 (SideEffectNoResult.Inst (MInst.CallInd info))) 3128 3129;; Helper for creating `MInst.ReturnCall` instructions. 3130(decl return_call_impl (BoxReturnCallInfo) SideEffectNoResult) 3131(rule (return_call_impl info) 3132 (SideEffectNoResult.Inst (MInst.ReturnCall info))) 3133 3134;; Helper for creating `MInst.ReturnCallInd` instructions. 3135(decl return_call_ind_impl (BoxReturnCallIndInfo) SideEffectNoResult) 3136(rule (return_call_ind_impl info) 3137 (SideEffectNoResult.Inst (MInst.ReturnCallInd info))) 3138 3139 3140;;; this is trying to imitate aarch64 `madd` instruction. 3141(decl madd (XReg XReg XReg) XReg) 3142(rule 3143 (madd n m a) 3144 (let 3145 ((t XReg (rv_mul n m))) 3146 (rv_add t a))) 3147 3148;;;; Helpers for bmask ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 3149 3150;; Generates either 0 if `Value` is zero or -1 otherwise. 3151(decl gen_bmask (Value) XReg) 3152 3153;; Base cases: use `snez` after a sign extension to ensure that the entire 3154;; register is defined. For i128 we test both the upper and lower half. 3155(rule 0 (gen_bmask val @ (value_type (fits_in_64 _))) 3156 (let ((non_zero XReg (rv_snez (sext val)))) 3157 (rv_neg non_zero))) 3158(rule 1 (gen_bmask val @ (value_type $I128)) 3159 (let ((non_zero XReg (rv_snez (rv_or (value_regs_get val 0) (value_regs_get val 1))))) 3160 (rv_neg non_zero))) 3161 3162;; If the input value is an `icmp` or an `fcmp` directly then the `snez` can 3163;; be omitted because the result of the icmp or fcmp is a 0 or 1 directly. This 3164;; means we can go straight to the `neg` instruction to produce the final 3165;; result. 3166(rule 2 (gen_bmask val @ (maybe_uextend (icmp _ _ _ _))) (rv_neg val)) 3167(rule 2 (gen_bmask val @ (maybe_uextend (fcmp _ _ _ _))) (rv_neg val)) 3168 3169(decl lower_bmask (Value Type) ValueRegs) 3170(rule 0 (lower_bmask val (fits_in_64 _)) 3171 (value_reg (gen_bmask val))) 3172(rule 1 (lower_bmask val $I128) 3173 (let ((bits XReg (gen_bmask val))) 3174 (value_regs bits bits))) 3175 3176;;;; Helpers for physical registers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 3177 3178(decl gen_mov_from_preg (PReg) Reg) 3179 3180(rule 3181 (gen_mov_from_preg rm) 3182 (let ((rd WritableXReg (temp_writable_xreg)) 3183 (_ Unit (emit (MInst.MovFromPReg rd rm)))) 3184 rd)) 3185 3186(decl fp_reg () PReg) 3187(extern constructor fp_reg fp_reg) 3188 3189(decl sp_reg () PReg) 3190(extern constructor sp_reg sp_reg) 3191 3192;; Extractor that matches all registers, except the zero register 3193(decl non_zero_reg () XReg) 3194(extern extractor non_zero_reg is_non_zero_reg) 3195 3196;; Helper for creating the zero register. 3197(decl zero_reg () XReg) 3198(extern constructor zero_reg zero_reg) 3199(extern extractor zero_reg is_zero_reg) 3200 3201(decl value_regs_zero () ValueRegs) 3202(rule (value_regs_zero) 3203 (value_regs (imm $I64 0) (imm $I64 0))) 3204 3205(decl writable_zero_reg () WritableReg) 3206(extern constructor writable_zero_reg writable_zero_reg) 3207 3208 3209;;;; Helpers for floating point comparisons ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 3210 3211(type FloatCompare (enum 3212 ;; The comparison succeeded if `r` is one 3213 (One (r XReg)) 3214 ;; The comparison succeeded if `r` is zero 3215 (Zero (r XReg)) 3216)) 3217 3218(decl float_compare_invert (FloatCompare) FloatCompare) 3219(rule (float_compare_invert (FloatCompare.One r)) (FloatCompare.Zero r)) 3220(rule (float_compare_invert (FloatCompare.Zero r)) (FloatCompare.One r)) 3221 3222(decl float_to_int_compare (FloatCompare) IntegerCompare) 3223(rule (float_to_int_compare (FloatCompare.One r)) (cmp_nez r)) 3224(rule (float_to_int_compare (FloatCompare.Zero r)) (cmp_eqz r)) 3225(convert FloatCompare IntegerCompare float_to_int_compare) 3226 3227;; Compare two floating point numbers and return a zero/non-zero result. 3228;; 3229;; Recursion: at most once to convert unordered comparisons into ordered comparisons. 3230(decl rec fcmp_to_float_compare (FloatCC Type FReg FReg) FloatCompare) 3231 3232;; Direct codegen for unordered comparisons is not that efficient, so invert 3233;; the comparison to get an ordered comparison and generate that. Then invert 3234;; the result to produce the final fcmp result. 3235(rule 0 (fcmp_to_float_compare cc ty a b) 3236 (if-let true (floatcc_unordered cc)) 3237 (float_compare_invert (fcmp_to_float_compare (floatcc_complement cc) ty a b))) 3238 3239;; a is not nan && b is not nan 3240(rule 1 (fcmp_to_float_compare (FloatCC.Ordered) ty a b) 3241 (FloatCompare.One (rv_and (is_not_nan ty a) (is_not_nan ty b)))) 3242 3243(decl is_not_nan (Type FReg) XReg) 3244(rule (is_not_nan ty a) (rv_feq ty a a)) 3245 3246;; a == b 3247(rule 1 (fcmp_to_float_compare (FloatCC.Equal) ty a b) 3248 (FloatCompare.One (rv_feq ty a b))) 3249 3250;; a != b 3251;; == !(a == b) 3252(rule 1 (fcmp_to_float_compare (FloatCC.NotEqual) ty a b) 3253 (FloatCompare.Zero (rv_feq ty a b))) 3254 3255;; a < b || a > b 3256(rule 1 (fcmp_to_float_compare (FloatCC.OrderedNotEqual) ty a b) 3257 (FloatCompare.One (rv_or (rv_flt ty a b) (rv_fgt ty a b)))) 3258 3259;; a < b 3260(rule 1 (fcmp_to_float_compare (FloatCC.LessThan) ty a b) 3261 (FloatCompare.One (rv_flt ty a b))) 3262 3263;; a <= b 3264(rule 1 (fcmp_to_float_compare (FloatCC.LessThanOrEqual) ty a b) 3265 (FloatCompare.One (rv_fle ty a b))) 3266 3267;; a > b 3268(rule 1 (fcmp_to_float_compare (FloatCC.GreaterThan) ty a b) 3269 (FloatCompare.One (rv_fgt ty a b))) 3270 3271;; a >= b 3272(rule 1 (fcmp_to_float_compare (FloatCC.GreaterThanOrEqual) ty a b) 3273 (FloatCompare.One (rv_fge ty a b))) 3274 3275 3276;; Helper for creating an `LabelAddress` instruction. 3277(decl rv64_label_address (MachLabel) Reg) 3278(rule (rv64_label_address label) 3279 (let ((dst WritableReg (temp_writable_reg $I64)) 3280 (_ Unit (emit (MInst.LabelAddress dst label)))) 3281 dst)) 3282 3283;; Helper for creating a `SequencePoint` instruction. 3284(decl rv64_sequence_point () SideEffectNoResult) 3285(rule (rv64_sequence_point) 3286 (SideEffectNoResult.Inst (MInst.SequencePoint))) 3287