| //===----------------------------------------------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file contains one of the four passes that expand pseudo instructions |
| // into target instructions. This pass is run very late, but before atomic |
| // instructions are expanded. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "RISCV.h" |
| #include "RISCVExpandPseudoBase.h" |
| #include "RISCVInstrInfo.h" |
| #include "RISCVSubtarget.h" |
| #include "llvm/CodeGen/LivePhysRegs.h" |
| #include "llvm/CodeGen/MachineFunctionPass.h" |
| #include "llvm/CodeGen/MachineInstrBuilder.h" |
| |
| using namespace llvm; |
| |
| #define RISCV_EXPAND_PSEUDO_PRE_EMIT_NAME \ |
| "RISC-V Pseudo Instruction Expansion - Pre-Emit" |
| |
| namespace { |
| |
| class RISCVExpandPseudoPreEmitImpl final : public RISCVExpandPseudoImplBase { |
| bool expandMI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, |
| MachineBasicBlock::iterator &NextMBBI) const override; |
| |
| bool expandCCOp(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, |
| MachineBasicBlock::iterator &NextMBBI) const; |
| |
| bool expandCCOpToCMov(MachineBasicBlock &MBB, |
| MachineBasicBlock::iterator MBBI) const; |
| |
| bool expandVMSET_VMCLR(MachineBasicBlock &MBB, |
| MachineBasicBlock::iterator MBBI, |
| unsigned Opcode) const; |
| |
| bool expandMV_FPR16INX(MachineBasicBlock &MBB, |
| MachineBasicBlock::iterator MBBI) const; |
| |
| bool expandMV_FPR32INX(MachineBasicBlock &MBB, |
| MachineBasicBlock::iterator MBBI) const; |
| |
| bool expandRV32ZdinxStore(MachineBasicBlock &MBB, |
| MachineBasicBlock::iterator MBBI) const; |
| |
| bool expandRV32ZdinxLoad(MachineBasicBlock &MBB, |
| MachineBasicBlock::iterator MBBI) const; |
| |
| bool |
| expandPseudoReadVLENBViaVSETVLIX0(MachineBasicBlock &MBB, |
| MachineBasicBlock::iterator MBBI) const; |
| |
| bool expandPseudoClearFPR64(MachineBasicBlock &MBB, |
| MachineBasicBlock::iterator MBBI) const; |
| }; |
| |
| class RISCVExpandPseudoPreEmitLegacy : public MachineFunctionPass { |
| public: |
| static char ID; |
| |
| RISCVExpandPseudoPreEmitLegacy() : MachineFunctionPass(ID) {} |
| |
| bool runOnMachineFunction(MachineFunction &MF) override { |
| return RISCVExpandPseudoPreEmitImpl().run(MF); |
| } |
| |
| StringRef getPassName() const override { |
| return RISCV_EXPAND_PSEUDO_PRE_EMIT_NAME; |
| } |
| }; |
| |
| } // anonymous namespace |
| |
| bool RISCVExpandPseudoPreEmitImpl::expandMI( |
| MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, |
| MachineBasicBlock::iterator &NextMBBI) const { |
| // RISCVInstrInfo::getInstSizeInBytes expects that the total size of the |
| // expanded instructions for each pseudo is correct in the Size field of the |
| // tablegen definition for the pseudo. |
| switch (MBBI->getOpcode()) { |
| case RISCV::PseudoMV_FPR16INX: |
| return expandMV_FPR16INX(MBB, MBBI); |
| case RISCV::PseudoMV_FPR32INX: |
| return expandMV_FPR32INX(MBB, MBBI); |
| case RISCV::PseudoRV32ZdinxSD: |
| return expandRV32ZdinxStore(MBB, MBBI); |
| case RISCV::PseudoRV32ZdinxLD: |
| return expandRV32ZdinxLoad(MBB, MBBI); |
| case RISCV::PseudoCCMOVGPRNoX0: |
| case RISCV::PseudoCCMOVGPR: |
| case RISCV::PseudoCCADD: |
| case RISCV::PseudoCCSUB: |
| case RISCV::PseudoCCAND: |
| case RISCV::PseudoCCOR: |
| case RISCV::PseudoCCXOR: |
| case RISCV::PseudoCCMAX: |
| case RISCV::PseudoCCMAXU: |
| case RISCV::PseudoCCMIN: |
| case RISCV::PseudoCCMINU: |
| case RISCV::PseudoCCMUL: |
| case RISCV::PseudoCCLUI: |
| case RISCV::PseudoCCQC_E_LB: |
| case RISCV::PseudoCCQC_E_LH: |
| case RISCV::PseudoCCQC_E_LW: |
| case RISCV::PseudoCCQC_E_LHU: |
| case RISCV::PseudoCCQC_E_LBU: |
| case RISCV::PseudoCCLB: |
| case RISCV::PseudoCCLH: |
| case RISCV::PseudoCCLW: |
| case RISCV::PseudoCCLHU: |
| case RISCV::PseudoCCLBU: |
| case RISCV::PseudoCCLWU: |
| case RISCV::PseudoCCLD: |
| case RISCV::PseudoCCQC_LI: |
| case RISCV::PseudoCCQC_E_LI: |
| case RISCV::PseudoCCADDW: |
| case RISCV::PseudoCCSUBW: |
| case RISCV::PseudoCCSLL: |
| case RISCV::PseudoCCSRL: |
| case RISCV::PseudoCCSRA: |
| case RISCV::PseudoCCADDI: |
| case RISCV::PseudoCCSLLI: |
| case RISCV::PseudoCCSRLI: |
| case RISCV::PseudoCCSRAI: |
| case RISCV::PseudoCCANDI: |
| case RISCV::PseudoCCORI: |
| case RISCV::PseudoCCXORI: |
| case RISCV::PseudoCCSLLW: |
| case RISCV::PseudoCCSRLW: |
| case RISCV::PseudoCCSRAW: |
| case RISCV::PseudoCCADDIW: |
| case RISCV::PseudoCCSLLIW: |
| case RISCV::PseudoCCSRLIW: |
| case RISCV::PseudoCCSRAIW: |
| case RISCV::PseudoCCANDN: |
| case RISCV::PseudoCCORN: |
| case RISCV::PseudoCCXNOR: |
| case RISCV::PseudoCCNDS_BFOS: |
| case RISCV::PseudoCCNDS_BFOZ: |
| return expandCCOp(MBB, MBBI, NextMBBI); |
| case RISCV::PseudoVMCLR_M_B1: |
| case RISCV::PseudoVMCLR_M_B2: |
| case RISCV::PseudoVMCLR_M_B4: |
| case RISCV::PseudoVMCLR_M_B8: |
| case RISCV::PseudoVMCLR_M_B16: |
| case RISCV::PseudoVMCLR_M_B32: |
| case RISCV::PseudoVMCLR_M_B64: |
| // vmclr.m vd => vmxor.mm vd, vd, vd |
| return expandVMSET_VMCLR(MBB, MBBI, RISCV::VMXOR_MM); |
| case RISCV::PseudoVMSET_M_B1: |
| case RISCV::PseudoVMSET_M_B2: |
| case RISCV::PseudoVMSET_M_B4: |
| case RISCV::PseudoVMSET_M_B8: |
| case RISCV::PseudoVMSET_M_B16: |
| case RISCV::PseudoVMSET_M_B32: |
| case RISCV::PseudoVMSET_M_B64: |
| // vmset.m vd => vmxnor.mm vd, vd, vd |
| return expandVMSET_VMCLR(MBB, MBBI, RISCV::VMXNOR_MM); |
| case RISCV::PseudoReadVLENBViaVSETVLIX0: |
| return expandPseudoReadVLENBViaVSETVLIX0(MBB, MBBI); |
| case RISCV::PseudoClearFPR64: |
| return expandPseudoClearFPR64(MBB, MBBI); |
| } |
| |
| return false; |
| } |
| |
| bool RISCVExpandPseudoPreEmitImpl::expandCCOp( |
| MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, |
| MachineBasicBlock::iterator &NextMBBI) const { |
| // First try expanding to a Conditional Move rather than a branch+mv |
| if (expandCCOpToCMov(MBB, MBBI)) |
| return true; |
| |
| MachineFunction *MF = MBB.getParent(); |
| MachineInstr &MI = *MBBI; |
| DebugLoc DL = MI.getDebugLoc(); |
| |
| MachineBasicBlock *TrueBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock()); |
| MachineBasicBlock *MergeBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock()); |
| |
| MF->insert(++MBB.getIterator(), TrueBB); |
| MF->insert(++TrueBB->getIterator(), MergeBB); |
| |
| // We want to copy the "true" value only when the branch is executed. |
| // The SDNodeXform is responsible for the inversion. |
| unsigned BranchOpCode = |
| MI.getOperand(MI.getNumExplicitOperands() - 3).getImm(); |
| |
| // Insert branch instruction. |
| BuildMI(MBB, MBBI, DL, TII->get(BranchOpCode)) |
| .add(MI.getOperand(MI.getNumExplicitOperands() - 2)) |
| .add(MI.getOperand(MI.getNumExplicitOperands() - 1)) |
| .addMBB(MergeBB); |
| |
| Register DestReg = MI.getOperand(0).getReg(); |
| assert(MI.getOperand(1).getReg() == DestReg); |
| |
| if (MI.getOpcode() == RISCV::PseudoCCMOVGPR || |
| MI.getOpcode() == RISCV::PseudoCCMOVGPRNoX0) { |
| // Add MV. |
| BuildMI(TrueBB, DL, TII->get(RISCV::ADDI), DestReg) |
| .add(MI.getOperand(2)) |
| .addImm(0); |
| } else { |
| unsigned NewOpc; |
| // clang-format off |
| switch (MI.getOpcode()) { |
| default: |
| llvm_unreachable("Unexpected opcode!"); |
| case RISCV::PseudoCCADD: NewOpc = RISCV::ADD; break; |
| case RISCV::PseudoCCSUB: NewOpc = RISCV::SUB; break; |
| case RISCV::PseudoCCSLL: NewOpc = RISCV::SLL; break; |
| case RISCV::PseudoCCSRL: NewOpc = RISCV::SRL; break; |
| case RISCV::PseudoCCSRA: NewOpc = RISCV::SRA; break; |
| case RISCV::PseudoCCAND: NewOpc = RISCV::AND; break; |
| case RISCV::PseudoCCOR: NewOpc = RISCV::OR; break; |
| case RISCV::PseudoCCXOR: NewOpc = RISCV::XOR; break; |
| case RISCV::PseudoCCMAX: NewOpc = RISCV::MAX; break; |
| case RISCV::PseudoCCMIN: NewOpc = RISCV::MIN; break; |
| case RISCV::PseudoCCMAXU: NewOpc = RISCV::MAXU; break; |
| case RISCV::PseudoCCMINU: NewOpc = RISCV::MINU; break; |
| case RISCV::PseudoCCMUL: NewOpc = RISCV::MUL; break; |
| case RISCV::PseudoCCLUI: NewOpc = RISCV::LUI; break; |
| case RISCV::PseudoCCQC_E_LB: NewOpc = RISCV::QC_E_LB; break; |
| case RISCV::PseudoCCQC_E_LH: NewOpc = RISCV::QC_E_LH; break; |
| case RISCV::PseudoCCQC_E_LW: NewOpc = RISCV::QC_E_LW; break; |
| case RISCV::PseudoCCQC_E_LHU: NewOpc = RISCV::QC_E_LHU; break; |
| case RISCV::PseudoCCQC_E_LBU: NewOpc = RISCV::QC_E_LBU; break; |
| case RISCV::PseudoCCLB: NewOpc = RISCV::LB; break; |
| case RISCV::PseudoCCLH: NewOpc = RISCV::LH; break; |
| case RISCV::PseudoCCLW: NewOpc = RISCV::LW; break; |
| case RISCV::PseudoCCLHU: NewOpc = RISCV::LHU; break; |
| case RISCV::PseudoCCLBU: NewOpc = RISCV::LBU; break; |
| case RISCV::PseudoCCLWU: NewOpc = RISCV::LWU; break; |
| case RISCV::PseudoCCLD: NewOpc = RISCV::LD; break; |
| case RISCV::PseudoCCQC_LI: NewOpc = RISCV::QC_LI; break; |
| case RISCV::PseudoCCQC_E_LI: NewOpc = RISCV::QC_E_LI; break; |
| case RISCV::PseudoCCADDI: NewOpc = RISCV::ADDI; break; |
| case RISCV::PseudoCCSLLI: NewOpc = RISCV::SLLI; break; |
| case RISCV::PseudoCCSRLI: NewOpc = RISCV::SRLI; break; |
| case RISCV::PseudoCCSRAI: NewOpc = RISCV::SRAI; break; |
| case RISCV::PseudoCCANDI: NewOpc = RISCV::ANDI; break; |
| case RISCV::PseudoCCORI: NewOpc = RISCV::ORI; break; |
| case RISCV::PseudoCCXORI: NewOpc = RISCV::XORI; break; |
| case RISCV::PseudoCCADDW: NewOpc = RISCV::ADDW; break; |
| case RISCV::PseudoCCSUBW: NewOpc = RISCV::SUBW; break; |
| case RISCV::PseudoCCSLLW: NewOpc = RISCV::SLLW; break; |
| case RISCV::PseudoCCSRLW: NewOpc = RISCV::SRLW; break; |
| case RISCV::PseudoCCSRAW: NewOpc = RISCV::SRAW; break; |
| case RISCV::PseudoCCADDIW: NewOpc = RISCV::ADDIW; break; |
| case RISCV::PseudoCCSLLIW: NewOpc = RISCV::SLLIW; break; |
| case RISCV::PseudoCCSRLIW: NewOpc = RISCV::SRLIW; break; |
| case RISCV::PseudoCCSRAIW: NewOpc = RISCV::SRAIW; break; |
| case RISCV::PseudoCCANDN: NewOpc = RISCV::ANDN; break; |
| case RISCV::PseudoCCORN: NewOpc = RISCV::ORN; break; |
| case RISCV::PseudoCCXNOR: NewOpc = RISCV::XNOR; break; |
| case RISCV::PseudoCCNDS_BFOS: NewOpc = RISCV::NDS_BFOS; break; |
| case RISCV::PseudoCCNDS_BFOZ: NewOpc = RISCV::NDS_BFOZ; break; |
| } |
| // clang-format on |
| |
| if (NewOpc == RISCV::NDS_BFOZ || NewOpc == RISCV::NDS_BFOS) { |
| BuildMI(TrueBB, DL, TII->get(NewOpc), DestReg) |
| .add(MI.getOperand(2)) |
| .add(MI.getOperand(3)) |
| .add(MI.getOperand(4)); |
| } else if (NewOpc == RISCV::LUI || NewOpc == RISCV::QC_LI || |
| NewOpc == RISCV::QC_E_LI) { |
| BuildMI(TrueBB, DL, TII->get(NewOpc), DestReg).add(MI.getOperand(2)); |
| } else { |
| BuildMI(TrueBB, DL, TII->get(NewOpc), DestReg) |
| .add(MI.getOperand(2)) |
| .add(MI.getOperand(3)); |
| } |
| } |
| |
| TrueBB->addSuccessor(MergeBB); |
| |
| MergeBB->splice(MergeBB->end(), &MBB, MI, MBB.end()); |
| MergeBB->transferSuccessors(&MBB); |
| |
| MBB.addSuccessor(TrueBB); |
| MBB.addSuccessor(MergeBB); |
| |
| NextMBBI = MBB.end(); |
| MI.eraseFromParent(); |
| |
| // Make sure live-ins are correctly attached to this new basic block. |
| LivePhysRegs LiveRegs; |
| computeAndAddLiveIns(LiveRegs, *TrueBB); |
| computeAndAddLiveIns(LiveRegs, *MergeBB); |
| |
| return true; |
| } |
| |
| bool RISCVExpandPseudoPreEmitImpl::expandCCOpToCMov( |
| MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI) const { |
| MachineInstr &MI = *MBBI; |
| DebugLoc DL = MI.getDebugLoc(); |
| |
| if (MI.getOpcode() != RISCV::PseudoCCMOVGPR && |
| MI.getOpcode() != RISCV::PseudoCCMOVGPRNoX0) |
| return false; |
| |
| if (!STI->hasVendorXqcicm()) |
| return false; |
| |
| MachineOperand &LHS = MI.getOperand(MI.getNumExplicitOperands() - 2); |
| MachineOperand &RHS = MI.getOperand(MI.getNumExplicitOperands() - 1); |
| |
| // FIXME: Would be wonderful to support LHS=X0, but not very easy. |
| if (LHS.getReg() == RISCV::X0 || MI.getOperand(1).getReg() == RISCV::X0 || |
| MI.getOperand(2).getReg() == RISCV::X0) |
| return false; |
| |
| // Use branch opcode to select appropriate Xqcicm instruction |
| unsigned BCC = MI.getOperand(MI.getNumExplicitOperands() - 3).getImm(); |
| std::optional<unsigned> CMovRegOpcode; |
| bool IsSigned = true; |
| unsigned CMovImmOpcode; |
| switch (BCC) { |
| default: |
| return false; // Unhandled branch opcodes |
| case RISCV::BNE: |
| CMovRegOpcode = RISCV::QC_MVEQ; |
| CMovImmOpcode = RISCV::QC_MVEQI; |
| break; |
| case RISCV::BEQ: |
| CMovRegOpcode = RISCV::QC_MVNE; |
| CMovImmOpcode = RISCV::QC_MVNEI; |
| break; |
| case RISCV::BGE: |
| CMovRegOpcode = RISCV::QC_MVLT; |
| CMovImmOpcode = RISCV::QC_MVLTI; |
| break; |
| case RISCV::BLT: |
| CMovRegOpcode = RISCV::QC_MVGE; |
| CMovImmOpcode = RISCV::QC_MVGEI; |
| break; |
| case RISCV::BGEU: |
| CMovRegOpcode = RISCV::QC_MVLTU; |
| CMovImmOpcode = RISCV::QC_MVLTUI; |
| break; |
| case RISCV::BLTU: |
| CMovRegOpcode = RISCV::QC_MVGEU; |
| CMovImmOpcode = RISCV::QC_MVGEUI; |
| break; |
| case RISCV::QC_BEQI: |
| CMovImmOpcode = RISCV::QC_MVNEI; |
| break; |
| case RISCV::QC_BNEI: |
| CMovImmOpcode = RISCV::QC_MVEQI; |
| break; |
| case RISCV::QC_BLTI: |
| CMovImmOpcode = RISCV::QC_MVGEI; |
| break; |
| case RISCV::QC_BGEI: |
| CMovImmOpcode = RISCV::QC_MVLTI; |
| break; |
| case RISCV::QC_BLTUI: |
| CMovImmOpcode = RISCV::QC_MVGEUI; |
| IsSigned = false; |
| break; |
| case RISCV::QC_BGEUI: |
| CMovImmOpcode = RISCV::QC_MVLTUI; |
| IsSigned = false; |
| break; |
| } |
| |
| if (RHS.isImm()) { |
| if ((!isInt<5>(RHS.getImm()) || !IsSigned) && |
| (!isUInt<5>(RHS.getImm()) || IsSigned)) |
| return false; |
| |
| // $dst = PseudoCCMOVGPR $falsev(=$dst), $truev, $opcode, $lhs, $rhs_imm |
| // $dst = PseudoCCMOVGPRNoX0 $falsev(=$dst), $truev, $opcode, $lhs, $rhs_imm |
| // => |
| // $dst = QC_MVccI $falsev (=$dst), $lhs, $rhs_imm, $truev |
| BuildMI(MBB, MBBI, DL, TII->get(CMovImmOpcode)) |
| .addDef(MI.getOperand(0).getReg()) |
| .addReg(MI.getOperand(1).getReg()) |
| .addReg(LHS.getReg()) |
| .add(RHS) |
| .addReg(MI.getOperand(2).getReg()); |
| |
| MI.eraseFromParent(); |
| return true; |
| } |
| |
| if (RHS.getReg() == RISCV::X0) { |
| // $dst = PseudoCCMOVGPR $falsev (=$dst), $truev, $opcode, $lhs, X0 |
| // $dst = PseudoCCMOVGPRNoX0 $falsev (=$dst), $truev, $opcode, $lhs, X0 |
| // => |
| // $dst = QC_MVccI $falsev (=$dst), $lhs, 0, $truev |
| BuildMI(MBB, MBBI, DL, TII->get(CMovImmOpcode)) |
| .addDef(MI.getOperand(0).getReg()) |
| .addReg(MI.getOperand(1).getReg()) |
| .addReg(LHS.getReg()) |
| .addImm(0) |
| .addReg(MI.getOperand(2).getReg()); |
| |
| MI.eraseFromParent(); |
| return true; |
| } |
| |
| if (!CMovRegOpcode) |
| return false; |
| |
| // $dst = PseudoCCMOVGPR $falsev (=$dst), $truev, $opcode, $lhs, $rhs |
| // $dst = PseudoCCMOVGPRNoX0 $falsev (=$dst), $truev, $opcode, $lhs, $rhs |
| // => |
| // $dst = QC_MVcc $falsev (=$dst), $lhs, $rhs, $truev |
| BuildMI(MBB, MBBI, DL, TII->get(*CMovRegOpcode)) |
| .addDef(MI.getOperand(0).getReg()) |
| .addReg(MI.getOperand(1).getReg()) |
| .addReg(LHS.getReg()) |
| .addReg(RHS.getReg()) |
| .addReg(MI.getOperand(2).getReg()); |
| MI.eraseFromParent(); |
| return true; |
| } |
| |
| bool RISCVExpandPseudoPreEmitImpl::expandVMSET_VMCLR( |
| MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, |
| unsigned Opcode) const { |
| DebugLoc DL = MBBI->getDebugLoc(); |
| Register DstReg = MBBI->getOperand(0).getReg(); |
| const MCInstrDesc &Desc = TII->get(Opcode); |
| BuildMI(MBB, MBBI, DL, Desc, DstReg) |
| .addReg(DstReg, RegState::Undef) |
| .addReg(DstReg, RegState::Undef); |
| MBBI->eraseFromParent(); // The pseudo instruction is gone now. |
| return true; |
| } |
| |
| bool RISCVExpandPseudoPreEmitImpl::expandMV_FPR16INX( |
| MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI) const { |
| DebugLoc DL = MBBI->getDebugLoc(); |
| const TargetRegisterInfo *TRI = STI->getRegisterInfo(); |
| Register DstReg = TRI->getMatchingSuperReg( |
| MBBI->getOperand(0).getReg(), RISCV::sub_16, &RISCV::GPRRegClass); |
| Register SrcReg = TRI->getMatchingSuperReg( |
| MBBI->getOperand(1).getReg(), RISCV::sub_16, &RISCV::GPRRegClass); |
| |
| BuildMI(MBB, MBBI, DL, TII->get(RISCV::ADDI), DstReg) |
| .addReg(SrcReg, getKillRegState(MBBI->getOperand(1).isKill())) |
| .addImm(0); |
| |
| MBBI->eraseFromParent(); // The pseudo instruction is gone now. |
| return true; |
| } |
| |
| bool RISCVExpandPseudoPreEmitImpl::expandMV_FPR32INX( |
| MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI) const { |
| DebugLoc DL = MBBI->getDebugLoc(); |
| const TargetRegisterInfo *TRI = STI->getRegisterInfo(); |
| Register DstReg = TRI->getMatchingSuperReg( |
| MBBI->getOperand(0).getReg(), RISCV::sub_32, &RISCV::GPRRegClass); |
| Register SrcReg = TRI->getMatchingSuperReg( |
| MBBI->getOperand(1).getReg(), RISCV::sub_32, &RISCV::GPRRegClass); |
| |
| BuildMI(MBB, MBBI, DL, TII->get(RISCV::ADDI), DstReg) |
| .addReg(SrcReg, getKillRegState(MBBI->getOperand(1).isKill())) |
| .addImm(0); |
| |
| MBBI->eraseFromParent(); // The pseudo instruction is gone now. |
| return true; |
| } |
| |
| // This function expands the PseudoRV32ZdinxSD for storing a double-precision |
| // floating-point value into memory by generating an equivalent instruction |
| // sequence for RV32. |
| bool RISCVExpandPseudoPreEmitImpl::expandRV32ZdinxStore( |
| MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI) const { |
| DebugLoc DL = MBBI->getDebugLoc(); |
| const TargetRegisterInfo *TRI = STI->getRegisterInfo(); |
| Register Lo = |
| TRI->getSubReg(MBBI->getOperand(0).getReg(), RISCV::sub_gpr_even); |
| Register Hi = |
| TRI->getSubReg(MBBI->getOperand(0).getReg(), RISCV::sub_gpr_odd); |
| if (Hi == RISCV::DUMMY_REG_PAIR_WITH_X0) |
| Hi = RISCV::X0; |
| |
| auto MIBLo = BuildMI(MBB, MBBI, DL, TII->get(RISCV::SW)) |
| .addReg(Lo, getKillRegState(MBBI->getOperand(0).isKill())) |
| .addReg(MBBI->getOperand(1).getReg()) |
| .add(MBBI->getOperand(2)); |
| |
| MachineInstrBuilder MIBHi; |
| if (MBBI->getOperand(2).isGlobal() || MBBI->getOperand(2).isCPI()) { |
| assert(MBBI->getOperand(2).getOffset() % 8 == 0); |
| MBBI->getOperand(2).setOffset(MBBI->getOperand(2).getOffset() + 4); |
| MIBHi = BuildMI(MBB, MBBI, DL, TII->get(RISCV::SW)) |
| .addReg(Hi, getKillRegState(MBBI->getOperand(0).isKill())) |
| .add(MBBI->getOperand(1)) |
| .add(MBBI->getOperand(2)); |
| } else { |
| assert(isInt<12>(MBBI->getOperand(2).getImm() + 4)); |
| MIBHi = BuildMI(MBB, MBBI, DL, TII->get(RISCV::SW)) |
| .addReg(Hi, getKillRegState(MBBI->getOperand(0).isKill())) |
| .add(MBBI->getOperand(1)) |
| .addImm(MBBI->getOperand(2).getImm() + 4); |
| } |
| |
| MachineFunction *MF = MBB.getParent(); |
| SmallVector<MachineMemOperand *> NewLoMMOs; |
| SmallVector<MachineMemOperand *> NewHiMMOs; |
| for (const MachineMemOperand *MMO : MBBI->memoperands()) { |
| NewLoMMOs.push_back(MF->getMachineMemOperand(MMO, 0, 4)); |
| NewHiMMOs.push_back(MF->getMachineMemOperand(MMO, 4, 4)); |
| } |
| MIBLo.setMemRefs(NewLoMMOs); |
| MIBHi.setMemRefs(NewHiMMOs); |
| |
| MBBI->eraseFromParent(); |
| return true; |
| } |
| |
| // This function expands PseudoRV32ZdinxLoad for loading a double-precision |
| // floating-point value from memory into an equivalent instruction sequence for |
| // RV32. |
| bool RISCVExpandPseudoPreEmitImpl::expandRV32ZdinxLoad( |
| MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI) const { |
| DebugLoc DL = MBBI->getDebugLoc(); |
| const TargetRegisterInfo *TRI = STI->getRegisterInfo(); |
| Register Lo = |
| TRI->getSubReg(MBBI->getOperand(0).getReg(), RISCV::sub_gpr_even); |
| Register Hi = |
| TRI->getSubReg(MBBI->getOperand(0).getReg(), RISCV::sub_gpr_odd); |
| assert(Hi != RISCV::DUMMY_REG_PAIR_WITH_X0 && "Cannot write to X0_Pair"); |
| |
| MachineInstrBuilder MIBLo, MIBHi; |
| |
| // If the register of operand 1 is equal to the Lo register, then swap the |
| // order of loading the Lo and Hi statements. |
| bool IsOp1EqualToLo = Lo == MBBI->getOperand(1).getReg(); |
| // Order: Lo, Hi |
| if (!IsOp1EqualToLo) { |
| MIBLo = BuildMI(MBB, MBBI, DL, TII->get(RISCV::LW), Lo) |
| .addReg(MBBI->getOperand(1).getReg()) |
| .add(MBBI->getOperand(2)); |
| } |
| |
| if (MBBI->getOperand(2).isGlobal() || MBBI->getOperand(2).isCPI()) { |
| auto Offset = MBBI->getOperand(2).getOffset(); |
| assert(Offset % 8 == 0); |
| MBBI->getOperand(2).setOffset(Offset + 4); |
| MIBHi = BuildMI(MBB, MBBI, DL, TII->get(RISCV::LW), Hi) |
| .addReg(MBBI->getOperand(1).getReg()) |
| .add(MBBI->getOperand(2)); |
| MBBI->getOperand(2).setOffset(Offset); |
| } else { |
| assert(isInt<12>(MBBI->getOperand(2).getImm() + 4)); |
| MIBHi = BuildMI(MBB, MBBI, DL, TII->get(RISCV::LW), Hi) |
| .addReg(MBBI->getOperand(1).getReg()) |
| .addImm(MBBI->getOperand(2).getImm() + 4); |
| } |
| |
| // Order: Hi, Lo |
| if (IsOp1EqualToLo) { |
| MIBLo = BuildMI(MBB, MBBI, DL, TII->get(RISCV::LW), Lo) |
| .addReg(MBBI->getOperand(1).getReg()) |
| .add(MBBI->getOperand(2)); |
| } |
| |
| MachineFunction *MF = MBB.getParent(); |
| SmallVector<MachineMemOperand *> NewLoMMOs; |
| SmallVector<MachineMemOperand *> NewHiMMOs; |
| for (const MachineMemOperand *MMO : MBBI->memoperands()) { |
| NewLoMMOs.push_back(MF->getMachineMemOperand(MMO, 0, 4)); |
| NewHiMMOs.push_back(MF->getMachineMemOperand(MMO, 4, 4)); |
| } |
| MIBLo.setMemRefs(NewLoMMOs); |
| MIBHi.setMemRefs(NewHiMMOs); |
| |
| MBBI->eraseFromParent(); |
| return true; |
| } |
| |
| bool RISCVExpandPseudoPreEmitImpl::expandPseudoReadVLENBViaVSETVLIX0( |
| MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI) const { |
| DebugLoc DL = MBBI->getDebugLoc(); |
| Register Dst = MBBI->getOperand(0).getReg(); |
| unsigned Mul = MBBI->getOperand(1).getImm(); |
| RISCVVType::VLMUL VLMUL = RISCVVType::encodeLMUL(Mul, /*Fractional=*/false); |
| unsigned VTypeImm = RISCVVType::encodeVTYPE( |
| VLMUL, /*SEW=*/8, /*TailAgnostic=*/true, /*MaskAgnostic=*/true); |
| |
| BuildMI(MBB, MBBI, DL, TII->get(RISCV::PseudoVSETVLIX0)) |
| .addReg(Dst, RegState::Define) |
| .addReg(RISCV::X0, RegState::Kill) |
| .addImm(VTypeImm); |
| |
| MBBI->eraseFromParent(); |
| return true; |
| } |
| |
| bool RISCVExpandPseudoPreEmitImpl::expandPseudoClearFPR64( |
| MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI) const { |
| const DebugLoc &DL = MBBI->getDebugLoc(); |
| Register Dst = MBBI->getOperand(0).getReg(); |
| |
| if (STI->is64Bit()) { |
| BuildMI(MBB, MBBI, DL, TII->get(RISCV::FMV_D_X), Dst).addReg(RISCV::X0); |
| } else { |
| BuildMI(MBB, MBBI, DL, TII->get(RISCV::FCVT_D_W), Dst) |
| .addReg(RISCV::X0) |
| .addImm(RISCVFPRndMode::RNE); |
| } |
| |
| MBBI->eraseFromParent(); |
| return true; |
| } |
| |
| char RISCVExpandPseudoPreEmitLegacy::ID = 0; |
| |
| INITIALIZE_PASS(RISCVExpandPseudoPreEmitLegacy, "riscv-expand-pseudo-pre-emit", |
| RISCV_EXPAND_PSEUDO_PRE_EMIT_NAME, false, false) |
| |
| FunctionPass *llvm::createRISCVExpandPseudoPreEmitLegacyPass() { |
| return new RISCVExpandPseudoPreEmitLegacy(); |
| } |
| |
| PreservedAnalyses |
| RISCVExpandPseudoPreEmitPass::run(MachineFunction &MF, |
| MachineFunctionAnalysisManager &MFAM) { |
| bool Changed = RISCVExpandPseudoPreEmitImpl().run(MF); |
| if (!Changed) |
| return PreservedAnalyses::all(); |
| return getMachineFunctionPassPreservedAnalyses(); |
| } |