diff options
| author | Luke Lau <luke@igalia.com> | 2024-05-15 11:44:32 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-05-15 11:44:32 +0800 |
| commit | 1a58e88690c1a48d1082b4ee6b759f5dc49a7144 (patch) | |
| tree | 5b6fb1f1a262f63981aff7ac56b15ec27875053b /llvm/lib | |
| parent | 72b2c37de6a4bbc2b2d2cda49293684b7cc71508 (diff) | |
| download | llvm-1a58e88690c1a48d1082b4ee6b759f5dc49a7144.zip llvm-1a58e88690c1a48d1082b4ee6b759f5dc49a7144.tar.gz llvm-1a58e88690c1a48d1082b4ee6b759f5dc49a7144.tar.bz2 | |
[RISCV] Move RISCVInsertVSETVLI to after phi elimination (#91440)
Split off from #70549, this patch moves RISCVInsertVSETVLI to after phi
elimination where we exit SSA and need to move to LiveVariables.
The motivation for splitting this off is to avoid the large scheduling
diffs from moving completely to after regalloc, and instead focus on
converting the pass to work on LiveIntervals.
The two main changes required are updating VSETVLIInfo to store VNInfos
instead of MachineInstrs, which allows us to still check for PHI defs in
needVSETVLIPHI, and fixing up the live intervals of any AVL operands
after inserting new instructions.
On O3 the pass is inserted after the register coalescer, otherwise we
end up with a bunch of COPYs around eliminated PHIs that trip up
needVSETVLIPHI.
Co-authored-by: Piyou Chen <piyou.chen@sifive.com>
Diffstat (limited to 'llvm/lib')
| -rw-r--r-- | llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp | 262 | ||||
| -rw-r--r-- | llvm/lib/Target/RISCV/RISCVTargetMachine.cpp | 9 |
2 files changed, 174 insertions, 97 deletions
diff --git a/llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp b/llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp index 7a8ff84..1c81542 100644 --- a/llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp +++ b/llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp @@ -47,6 +47,18 @@ static cl::opt<bool> DisableInsertVSETVLPHIOpt( namespace { +/// Given a virtual register \p Reg, return the corresponding VNInfo for it. +/// This should never return nullptr. +static VNInfo *getVNInfoFromReg(Register Reg, const MachineInstr &MI, + const LiveIntervals *LIS) { + assert(Reg.isVirtual()); + auto &LI = LIS->getInterval(Reg); + SlotIndex SI = LIS->getSlotIndexes()->getInstructionIndex(MI); + VNInfo *VNI = LI.getVNInfoBefore(SI); + assert(VNI); + return VNI; +} + static unsigned getVLOpNum(const MachineInstr &MI) { return RISCVII::getVLOpNum(MI.getDesc()); } @@ -426,7 +438,8 @@ DemandedFields getDemanded(const MachineInstr &MI, const RISCVSubtarget *ST) { /// values of the VL and VTYPE registers after insertion. class VSETVLIInfo { struct AVLDef { - const MachineInstr *DefMI; + // Every AVLDef should have a VNInfo. + const VNInfo *ValNo; Register DefReg; }; union { @@ -465,9 +478,9 @@ public: void setUnknown() { State = Unknown; } bool isUnknown() const { return State == Unknown; } - void setAVLRegDef(const MachineInstr *DefMI, Register AVLReg) { - assert(DefMI && AVLReg.isVirtual()); - AVLRegDef.DefMI = DefMI; + void setAVLRegDef(const VNInfo *VNInfo, Register AVLReg) { + assert(VNInfo && AVLReg.isVirtual()); + AVLRegDef.ValNo = VNInfo; AVLRegDef.DefReg = AVLReg; State = AVLIsReg; } @@ -493,9 +506,18 @@ public: assert(hasAVLImm()); return AVLImm; } - const MachineInstr &getAVLDefMI() const { - assert(hasAVLReg() && AVLRegDef.DefMI); - return *AVLRegDef.DefMI; + const VNInfo *getAVLVNInfo() const { + assert(hasAVLReg()); + return AVLRegDef.ValNo; + } + // Most AVLIsReg infos will have a single defining MachineInstr, unless it was + // a PHI node. In that case getAVLVNInfo()->def will point to the block + // boundary slot. + const MachineInstr *getAVLDefMI(const LiveIntervals *LIS) const { + assert(hasAVLReg()); + auto *MI = LIS->getInstructionFromIndex(getAVLVNInfo()->def); + assert(!(getAVLVNInfo()->isPHIDef() && MI)); + return MI; } void setAVL(VSETVLIInfo Info) { @@ -503,7 +525,7 @@ public: if (Info.isUnknown()) setUnknown(); else if (Info.hasAVLReg()) - setAVLRegDef(&Info.getAVLDefMI(), Info.getAVLReg()); + setAVLRegDef(Info.getAVLVNInfo(), Info.getAVLReg()); else if (Info.hasAVLVLMAX()) setAVLVLMAX(); else if (Info.hasAVLIgnored()) @@ -519,11 +541,13 @@ public: bool getTailAgnostic() const { return TailAgnostic; } bool getMaskAgnostic() const { return MaskAgnostic; } - bool hasNonZeroAVL() const { + bool hasNonZeroAVL(const LiveIntervals *LIS) const { if (hasAVLImm()) return getAVLImm() > 0; - if (hasAVLReg()) - return isNonZeroLoadImmediate(getAVLDefMI()); + if (hasAVLReg()) { + if (auto *DefMI = getAVLDefMI(LIS)) + return isNonZeroLoadImmediate(*DefMI); + } if (hasAVLVLMAX()) return true; if (hasAVLIgnored()) @@ -531,16 +555,17 @@ public: return false; } - bool hasEquallyZeroAVL(const VSETVLIInfo &Other) const { + bool hasEquallyZeroAVL(const VSETVLIInfo &Other, + const LiveIntervals *LIS) const { if (hasSameAVL(Other)) return true; - return (hasNonZeroAVL() && Other.hasNonZeroAVL()); + return (hasNonZeroAVL(LIS) && Other.hasNonZeroAVL(LIS)); } bool hasSameAVL(const VSETVLIInfo &Other) const { if (hasAVLReg() && Other.hasAVLReg()) - return AVLRegDef.DefMI == Other.AVLRegDef.DefMI && - AVLRegDef.DefReg == Other.AVLRegDef.DefReg; + return getAVLVNInfo()->id == Other.getAVLVNInfo()->id && + getAVLReg() == Other.getAVLReg(); if (hasAVLImm() && Other.hasAVLImm()) return getAVLImm() == Other.getAVLImm(); @@ -620,7 +645,7 @@ public: // Require are compatible with the previous vsetvli instruction represented // by this. MI is the instruction whose requirements we're considering. bool isCompatible(const DemandedFields &Used, const VSETVLIInfo &Require, - const MachineRegisterInfo &MRI) const { + const LiveIntervals *LIS) const { assert(isValid() && Require.isValid() && "Can't compare invalid VSETVLIInfos"); assert(!Require.SEWLMULRatioOnly && @@ -636,7 +661,7 @@ public: if (Used.VLAny && !(hasSameAVL(Require) && hasSameVLMAX(Require))) return false; - if (Used.VLZeroness && !hasEquallyZeroAVL(Require)) + if (Used.VLZeroness && !hasEquallyZeroAVL(Require, LIS)) return false; return hasCompatibleVTYPE(Used, Require); @@ -765,6 +790,7 @@ class RISCVInsertVSETVLI : public MachineFunctionPass { const RISCVSubtarget *ST; const TargetInstrInfo *TII; MachineRegisterInfo *MRI; + LiveIntervals *LIS; std::vector<BlockData> BlockInfo; std::queue<const MachineBasicBlock *> WorkList; @@ -777,6 +803,14 @@ public: void getAnalysisUsage(AnalysisUsage &AU) const override { AU.setPreservesCFG(); + + AU.addRequired<LiveIntervals>(); + AU.addPreserved<LiveIntervals>(); + AU.addRequired<SlotIndexes>(); + AU.addPreserved<SlotIndexes>(); + AU.addPreserved<LiveDebugVariables>(); + AU.addPreserved<LiveStacks>(); + MachineFunctionPass::getAnalysisUsage(AU); } @@ -848,7 +882,7 @@ INITIALIZE_PASS(RISCVCoalesceVSETVLI, "riscv-coalesce-vsetvli", // Return a VSETVLIInfo representing the changes made by this VSETVLI or // VSETIVLI instruction. static VSETVLIInfo getInfoForVSETVLI(const MachineInstr &MI, - const MachineRegisterInfo &MRI) { + const LiveIntervals *LIS) { VSETVLIInfo NewInfo; if (MI.getOpcode() == RISCV::PseudoVSETIVLI) { NewInfo.setAVLImm(MI.getOperand(1).getImm()); @@ -861,7 +895,7 @@ static VSETVLIInfo getInfoForVSETVLI(const MachineInstr &MI, if (AVLReg == RISCV::X0) NewInfo.setAVLVLMAX(); else - NewInfo.setAVLRegDef(MRI.getUniqueVRegDef(AVLReg), AVLReg); + NewInfo.setAVLRegDef(getVNInfoFromReg(AVLReg, MI, LIS), AVLReg); } NewInfo.setVTYPE(MI.getOperand(2).getImm()); @@ -880,7 +914,7 @@ static unsigned computeVLMAX(unsigned VLEN, unsigned SEW, static VSETVLIInfo computeInfoForInstr(const MachineInstr &MI, uint64_t TSFlags, const RISCVSubtarget &ST, - const MachineRegisterInfo *MRI) { + const LiveIntervals *LIS) { VSETVLIInfo InstrInfo; bool TailAgnostic = true; @@ -933,7 +967,7 @@ static VSETVLIInfo computeInfoForInstr(const MachineInstr &MI, uint64_t TSFlags, else InstrInfo.setAVLImm(Imm); } else { - InstrInfo.setAVLRegDef(MRI->getUniqueVRegDef(VLOp.getReg()), + InstrInfo.setAVLRegDef(getVNInfoFromReg(VLOp.getReg(), MI, LIS), VLOp.getReg()); } } else { @@ -955,9 +989,9 @@ static VSETVLIInfo computeInfoForInstr(const MachineInstr &MI, uint64_t TSFlags, // register AVLs to avoid extending live ranges without being sure we can // kill the original source reg entirely. if (InstrInfo.hasAVLReg()) { - const MachineInstr &DefMI = InstrInfo.getAVLDefMI(); - if (isVectorConfigInstr(DefMI)) { - VSETVLIInfo DefInstrInfo = getInfoForVSETVLI(DefMI, *MRI); + if (const MachineInstr *DefMI = InstrInfo.getAVLDefMI(LIS); + DefMI && isVectorConfigInstr(*DefMI)) { + VSETVLIInfo DefInstrInfo = getInfoForVSETVLI(*DefMI, LIS); if (DefInstrInfo.hasSameVLMAX(InstrInfo) && (DefInstrInfo.hasAVLImm() || DefInstrInfo.hasAVLVLMAX())) InstrInfo.setAVL(DefInstrInfo); @@ -983,11 +1017,12 @@ void RISCVInsertVSETVLI::insertVSETVLI(MachineBasicBlock &MBB, // Use X0, X0 form if the AVL is the same and the SEW+LMUL gives the same // VLMAX. if (Info.hasSameAVL(PrevInfo) && Info.hasSameVLMAX(PrevInfo)) { - BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETVLIX0)) - .addReg(RISCV::X0, RegState::Define | RegState::Dead) - .addReg(RISCV::X0, RegState::Kill) - .addImm(Info.encodeVTYPE()) - .addReg(RISCV::VL, RegState::Implicit); + auto MI = BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETVLIX0)) + .addReg(RISCV::X0, RegState::Define | RegState::Dead) + .addReg(RISCV::X0, RegState::Kill) + .addImm(Info.encodeVTYPE()) + .addReg(RISCV::VL, RegState::Implicit); + LIS->InsertMachineInstrInMaps(*MI); return; } @@ -995,15 +1030,16 @@ void RISCVInsertVSETVLI::insertVSETVLI(MachineBasicBlock &MBB, // it has the same VLMAX we want and the last VL/VTYPE we observed is the // same, we can use the X0, X0 form. if (Info.hasSameVLMAX(PrevInfo) && Info.hasAVLReg()) { - const MachineInstr &DefMI = Info.getAVLDefMI(); - if (isVectorConfigInstr(DefMI)) { - VSETVLIInfo DefInfo = getInfoForVSETVLI(DefMI, *MRI); + if (const MachineInstr *DefMI = Info.getAVLDefMI(LIS); + DefMI && isVectorConfigInstr(*DefMI)) { + VSETVLIInfo DefInfo = getInfoForVSETVLI(*DefMI, LIS); if (DefInfo.hasSameAVL(PrevInfo) && DefInfo.hasSameVLMAX(PrevInfo)) { - BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETVLIX0)) - .addReg(RISCV::X0, RegState::Define | RegState::Dead) - .addReg(RISCV::X0, RegState::Kill) - .addImm(Info.encodeVTYPE()) - .addReg(RISCV::VL, RegState::Implicit); + auto MI = BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETVLIX0)) + .addReg(RISCV::X0, RegState::Define | RegState::Dead) + .addReg(RISCV::X0, RegState::Kill) + .addImm(Info.encodeVTYPE()) + .addReg(RISCV::VL, RegState::Implicit); + LIS->InsertMachineInstrInMaps(*MI); return; } } @@ -1011,10 +1047,11 @@ void RISCVInsertVSETVLI::insertVSETVLI(MachineBasicBlock &MBB, } if (Info.hasAVLImm()) { - BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETIVLI)) - .addReg(RISCV::X0, RegState::Define | RegState::Dead) - .addImm(Info.getAVLImm()) - .addImm(Info.encodeVTYPE()); + auto MI = BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETIVLI)) + .addReg(RISCV::X0, RegState::Define | RegState::Dead) + .addImm(Info.getAVLImm()) + .addImm(Info.encodeVTYPE()); + LIS->InsertMachineInstrInMaps(*MI); return; } @@ -1023,36 +1060,46 @@ void RISCVInsertVSETVLI::insertVSETVLI(MachineBasicBlock &MBB, // the previous vl to become invalid. if (PrevInfo.isValid() && !PrevInfo.isUnknown() && Info.hasSameVLMAX(PrevInfo)) { - BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETVLIX0)) - .addReg(RISCV::X0, RegState::Define | RegState::Dead) - .addReg(RISCV::X0, RegState::Kill) - .addImm(Info.encodeVTYPE()) - .addReg(RISCV::VL, RegState::Implicit); + auto MI = BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETVLIX0)) + .addReg(RISCV::X0, RegState::Define | RegState::Dead) + .addReg(RISCV::X0, RegState::Kill) + .addImm(Info.encodeVTYPE()) + .addReg(RISCV::VL, RegState::Implicit); + LIS->InsertMachineInstrInMaps(*MI); return; } // Otherwise use an AVL of 1 to avoid depending on previous vl. - BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETIVLI)) - .addReg(RISCV::X0, RegState::Define | RegState::Dead) - .addImm(1) - .addImm(Info.encodeVTYPE()); + auto MI = BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETIVLI)) + .addReg(RISCV::X0, RegState::Define | RegState::Dead) + .addImm(1) + .addImm(Info.encodeVTYPE()); + LIS->InsertMachineInstrInMaps(*MI); return; } if (Info.hasAVLVLMAX()) { Register DestReg = MRI->createVirtualRegister(&RISCV::GPRRegClass); - BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETVLIX0)) - .addReg(DestReg, RegState::Define | RegState::Dead) - .addReg(RISCV::X0, RegState::Kill) - .addImm(Info.encodeVTYPE()); + auto MI = BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETVLIX0)) + .addReg(DestReg, RegState::Define | RegState::Dead) + .addReg(RISCV::X0, RegState::Kill) + .addImm(Info.encodeVTYPE()); + LIS->InsertMachineInstrInMaps(*MI); + LIS->createAndComputeVirtRegInterval(DestReg); return; } Register AVLReg = Info.getAVLReg(); MRI->constrainRegClass(AVLReg, &RISCV::GPRNoX0RegClass); - BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETVLI)) - .addReg(RISCV::X0, RegState::Define | RegState::Dead) - .addReg(AVLReg) - .addImm(Info.encodeVTYPE()); + auto MI = BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETVLI)) + .addReg(RISCV::X0, RegState::Define | RegState::Dead) + .addReg(AVLReg) + .addImm(Info.encodeVTYPE()); + LIS->InsertMachineInstrInMaps(*MI); + // Normally the AVL's live range will already extend past the inserted vsetvli + // because the pseudos below will already use the AVL. But this isn't always + // the case, e.g. PseudoVMV_X_S doesn't have an AVL operand. + LIS->getInterval(AVLReg).extendInBlock( + LIS->getMBBStartIdx(&MBB), LIS->getInstructionIndex(*MI).getRegSlot()); } static bool isLMUL1OrSmaller(RISCVII::VLMUL LMUL) { @@ -1065,7 +1112,7 @@ static bool isLMUL1OrSmaller(RISCVII::VLMUL LMUL) { bool RISCVInsertVSETVLI::needVSETVLI(const MachineInstr &MI, const VSETVLIInfo &Require, const VSETVLIInfo &CurInfo) const { - assert(Require == computeInfoForInstr(MI, MI.getDesc().TSFlags, *ST, MRI)); + assert(Require == computeInfoForInstr(MI, MI.getDesc().TSFlags, *ST, LIS)); if (!CurInfo.isValid() || CurInfo.isUnknown() || CurInfo.hasSEWLMULRatioOnly()) return true; @@ -1106,7 +1153,7 @@ bool RISCVInsertVSETVLI::needVSETVLI(const MachineInstr &MI, Used.TailPolicy = false; } - if (CurInfo.isCompatible(Used, Require, *MRI)) + if (CurInfo.isCompatible(Used, Require, LIS)) return false; // We didn't find a compatible value. If our AVL is a virtual register, @@ -1114,9 +1161,9 @@ bool RISCVInsertVSETVLI::needVSETVLI(const MachineInstr &MI, // and the last VL/VTYPE we observed is the same, we don't need a // VSETVLI here. if (Require.hasAVLReg() && CurInfo.hasCompatibleVTYPE(Used, Require)) { - const MachineInstr &DefMI = Require.getAVLDefMI(); - if (isVectorConfigInstr(DefMI)) { - VSETVLIInfo DefInfo = getInfoForVSETVLI(DefMI, *MRI); + if (const MachineInstr *DefMI = Require.getAVLDefMI(LIS); + DefMI && isVectorConfigInstr(*DefMI)) { + VSETVLIInfo DefInfo = getInfoForVSETVLI(*DefMI, LIS); if (DefInfo.hasSameAVL(CurInfo) && DefInfo.hasSameVLMAX(CurInfo)) return false; } @@ -1152,7 +1199,7 @@ void RISCVInsertVSETVLI::transferBefore(VSETVLIInfo &Info, if (!RISCVII::hasSEWOp(TSFlags)) return; - const VSETVLIInfo NewInfo = computeInfoForInstr(MI, TSFlags, *ST, MRI); + const VSETVLIInfo NewInfo = computeInfoForInstr(MI, TSFlags, *ST, LIS); assert(NewInfo.isValid() && !NewInfo.isUnknown()); if (Info.isValid() && !needVSETVLI(MI, NewInfo, Info)) return; @@ -1171,7 +1218,7 @@ void RISCVInsertVSETVLI::transferBefore(VSETVLIInfo &Info, // variant, so we avoid the transform to prevent extending live range of an // avl register operand. // TODO: We can probably relax this for immediates. - bool EquallyZero = IncomingInfo.hasEquallyZeroAVL(PrevInfo) && + bool EquallyZero = IncomingInfo.hasEquallyZeroAVL(PrevInfo, LIS) && IncomingInfo.hasSameVLMAX(PrevInfo); if (Demanded.VLAny || (Demanded.VLZeroness && !EquallyZero)) Info.setAVL(IncomingInfo); @@ -1202,14 +1249,17 @@ void RISCVInsertVSETVLI::transferBefore(VSETVLIInfo &Info, void RISCVInsertVSETVLI::transferAfter(VSETVLIInfo &Info, const MachineInstr &MI) const { if (isVectorConfigInstr(MI)) { - Info = getInfoForVSETVLI(MI, *MRI); + Info = getInfoForVSETVLI(MI, LIS); return; } if (RISCV::isFaultFirstLoad(MI)) { // Update AVL to vl-output of the fault first load. - Info.setAVLRegDef(MRI->getUniqueVRegDef(MI.getOperand(1).getReg()), - MI.getOperand(1).getReg()); + assert(MI.getOperand(1).getReg().isVirtual()); + auto &LI = LIS->getInterval(MI.getOperand(1).getReg()); + SlotIndex SI = LIS->getSlotIndexes()->getInstructionIndex(MI).getRegSlot(); + VNInfo *VNI = LI.getVNInfoAt(SI); + Info.setAVLRegDef(VNI, MI.getOperand(1).getReg()); return; } @@ -1293,7 +1343,7 @@ void RISCVInsertVSETVLI::computeIncomingVLVTYPE(const MachineBasicBlock &MBB) { } // If we weren't able to prove a vsetvli was directly unneeded, it might still -// be unneeded if the AVL is a phi node where all incoming values are VL +// be unneeded if the AVL was a phi node where all incoming values are VL // outputs from the last VSETVLI in their respective basic blocks. bool RISCVInsertVSETVLI::needVSETVLIPHI(const VSETVLIInfo &Require, const MachineBasicBlock &MBB) const { @@ -1303,26 +1353,27 @@ bool RISCVInsertVSETVLI::needVSETVLIPHI(const VSETVLIInfo &Require, if (!Require.hasAVLReg()) return true; - // We need the AVL to be produce by a PHI node in this basic block. - const MachineInstr *PHI = &Require.getAVLDefMI(); - if (PHI->getOpcode() != RISCV::PHI || PHI->getParent() != &MBB) + // We need the AVL to have been produced by a PHI node in this basic block. + const VNInfo *Valno = Require.getAVLVNInfo(); + if (!Valno->isPHIDef() || LIS->getMBBFromIndex(Valno->def) != &MBB) return true; - for (unsigned PHIOp = 1, NumOps = PHI->getNumOperands(); PHIOp != NumOps; - PHIOp += 2) { - Register InReg = PHI->getOperand(PHIOp).getReg(); - MachineBasicBlock *PBB = PHI->getOperand(PHIOp + 1).getMBB(); + const LiveRange &LR = LIS->getInterval(Require.getAVLReg()); + + for (auto *PBB : MBB.predecessors()) { const VSETVLIInfo &PBBExit = BlockInfo[PBB->getNumber()].Exit; // We need the PHI input to the be the output of a VSET(I)VLI. - MachineInstr *DefMI = MRI->getUniqueVRegDef(InReg); - assert(DefMI); - if (!isVectorConfigInstr(*DefMI)) + const VNInfo *Value = LR.getVNInfoBefore(LIS->getMBBEndIdx(PBB)); + if (!Value) + return true; + MachineInstr *DefMI = LIS->getInstructionFromIndex(Value->def); + if (!DefMI || !isVectorConfigInstr(*DefMI)) return true; // We found a VSET(I)VLI make sure it matches the output of the // predecessor block. - VSETVLIInfo DefInfo = getInfoForVSETVLI(*DefMI, *MRI); + VSETVLIInfo DefInfo = getInfoForVSETVLI(*DefMI, LIS); if (DefInfo != PBBExit) return true; @@ -1377,19 +1428,28 @@ void RISCVInsertVSETVLI::emitVSETVLIs(MachineBasicBlock &MBB) { MachineOperand &VLOp = MI.getOperand(getVLOpNum(MI)); if (VLOp.isReg()) { Register Reg = VLOp.getReg(); - MachineInstr *VLOpDef = MRI->getUniqueVRegDef(Reg); - assert(VLOpDef); + LiveInterval &LI = LIS->getInterval(Reg); // Erase the AVL operand from the instruction. VLOp.setReg(RISCV::NoRegister); VLOp.setIsKill(false); + SmallVector<MachineInstr *> DeadMIs; + LIS->shrinkToUses(&LI, &DeadMIs); + // We might have separate components that need split due to + // needVSETVLIPHI causing us to skip inserting a new VL def. + SmallVector<LiveInterval *> SplitLIs; + LIS->splitSeparateComponents(LI, SplitLIs); // If the AVL was an immediate > 31, then it would have been emitted // as an ADDI. However, the ADDI might not have been used in the // vsetvli, or a vsetvli might not have been emitted, so it may be // dead now. - if (TII->isAddImmediate(*VLOpDef, Reg) && MRI->use_nodbg_empty(Reg)) - VLOpDef->eraseFromParent(); + for (MachineInstr *DeadMI : DeadMIs) { + if (!TII->isAddImmediate(*DeadMI, Reg)) + continue; + LIS->RemoveMachineInstrFromMaps(*DeadMI); + DeadMI->eraseFromParent(); + } } MI.addOperand(MachineOperand::CreateReg(RISCV::VL, /*isDef*/ false, /*isImp*/ true)); @@ -1458,14 +1518,14 @@ void RISCVInsertVSETVLI::doPRE(MachineBasicBlock &MBB) { // we need to prove the value is available at the point we're going // to insert the vsetvli at. if (AvailableInfo.hasAVLReg()) { - const MachineInstr *AVLDefMI = &AvailableInfo.getAVLDefMI(); + SlotIndex SI = AvailableInfo.getAVLVNInfo()->def; // This is an inline dominance check which covers the case of // UnavailablePred being the preheader of a loop. - if (AVLDefMI->getParent() != UnavailablePred) + if (LIS->getMBBFromIndex(SI) != UnavailablePred) + return; + if (!UnavailablePred->terminators().empty() && + SI >= LIS->getInstructionIndex(*UnavailablePred->getFirstTerminator())) return; - for (auto &TermMI : UnavailablePred->terminators()) - if (&TermMI == AVLDefMI) - return; } // If the AVL isn't used in its predecessors then bail, since we have no AVL @@ -1526,7 +1586,8 @@ void RISCVInsertVSETVLI::doPRE(MachineBasicBlock &MBB) { static bool canMutatePriorConfig(const MachineInstr &PrevMI, const MachineInstr &MI, const DemandedFields &Used, - const MachineRegisterInfo &MRI) { + const MachineRegisterInfo &MRI, + const LiveIntervals *LIS) { // If the VL values aren't equal, return false if either a) the former is // demanded, or b) we can't rewrite the former to be the later for // implementation reasons. @@ -1537,8 +1598,8 @@ static bool canMutatePriorConfig(const MachineInstr &PrevMI, if (Used.VLZeroness) { if (isVLPreservingConfig(PrevMI)) return false; - if (!getInfoForVSETVLI(PrevMI, MRI) - .hasEquallyZeroAVL(getInfoForVSETVLI(MI, MRI))) + if (!getInfoForVSETVLI(PrevMI, LIS) + .hasEquallyZeroAVL(getInfoForVSETVLI(MI, LIS), LIS)) return false; } @@ -1588,7 +1649,7 @@ bool RISCVCoalesceVSETVLI::coalesceVSETVLIs(MachineBasicBlock &MBB) { continue; } - if (canMutatePriorConfig(MI, *NextMI, Used, *MRI)) { + if (canMutatePriorConfig(MI, *NextMI, Used, *MRI, LIS)) { if (!isVLPreservingConfig(*NextMI)) { Register DefReg = NextMI->getOperand(0).getReg(); @@ -1661,9 +1722,17 @@ void RISCVInsertVSETVLI::insertReadVL(MachineBasicBlock &MBB) { if (RISCV::isFaultFirstLoad(MI)) { Register VLOutput = MI.getOperand(1).getReg(); assert(VLOutput.isVirtual()); - if (!MRI->use_nodbg_empty(VLOutput)) - BuildMI(MBB, I, MI.getDebugLoc(), TII->get(RISCV::PseudoReadVL), - VLOutput); + if (!MI.getOperand(1).isDead()) { + auto ReadVLMI = BuildMI(MBB, I, MI.getDebugLoc(), + TII->get(RISCV::PseudoReadVL), VLOutput); + // Move the LiveInterval's definition down to PseudoReadVL. + SlotIndex NewDefSI = + LIS->InsertMachineInstrInMaps(*ReadVLMI).getRegSlot(); + LiveInterval &DefLI = LIS->getInterval(VLOutput); + VNInfo *DefVNI = DefLI.getVNInfoAt(DefLI.beginIndex()); + DefLI.removeSegment(DefLI.beginIndex(), NewDefSI); + DefVNI->def = NewDefSI; + } // We don't use the vl output of the VLEFF/VLSEGFF anymore. MI.getOperand(1).setReg(RISCV::X0); } @@ -1680,6 +1749,7 @@ bool RISCVInsertVSETVLI::runOnMachineFunction(MachineFunction &MF) { TII = ST->getInstrInfo(); MRI = &MF.getRegInfo(); + LIS = &getAnalysis<LiveIntervals>(); assert(BlockInfo.empty() && "Expect empty block infos"); BlockInfo.resize(MF.getNumBlockIDs()); diff --git a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp index 7b2dcad..5d598a2 100644 --- a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp +++ b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp @@ -541,9 +541,16 @@ void RISCVPassConfig::addPreRegAlloc() { addPass(createRISCVPreRAExpandPseudoPass()); if (TM->getOptLevel() != CodeGenOptLevel::None) addPass(createRISCVMergeBaseOffsetOptPass()); + addPass(createRISCVInsertReadWriteCSRPass()); addPass(createRISCVInsertWriteVXRMPass()); - addPass(createRISCVInsertVSETVLIPass()); + + // Run RISCVInsertVSETVLI after PHI elimination. On O1 and above do it after + // register coalescing so needVSETVLIPHI doesn't need to look through COPYs. + if (TM->getOptLevel() == CodeGenOptLevel::None) + insertPass(&PHIEliminationID, createRISCVInsertVSETVLIPass()); + else + insertPass(&RegisterCoalescerID, createRISCVInsertVSETVLIPass()); } void RISCVPassConfig::addFastRegAlloc() { |
