From 0fa5aac292b8e1bafb00b55233c78466b06bc323 Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Thu, 27 May 2021 15:20:02 -0700 Subject: [PATCH] [RISCV] Teach VSETVLI insertion to look through PHIs to prove we don't need to insert a vsetvli. If an instruction's AVL operand is a PHI node in the same block, we may be able to peek through the PHI to find vsetvli instructions that produce the AVL in other basic blocks. If we can prove those vsetvli instructions have the same VTYPE and were the last vsetvli in their respective blocks, then we don't need to insert a vsetvli for this pseudo instruction. Reviewed By: rogfer01 Differential Revision: https://reviews.llvm.org/D103277 --- llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp | 57 +++++++++++++++++++++- .../CodeGen/RISCV/rvv/vsetvli-insert-crossbb.ll | 12 ++--- 2 files changed, 59 insertions(+), 10 deletions(-) diff --git a/llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp b/llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp index 1b1f58d..e1c7cb3 100644 --- a/llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp +++ b/llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp @@ -33,6 +33,10 @@ using namespace llvm; #define DEBUG_TYPE "riscv-insert-vsetvli" #define RISCV_INSERT_VSETVLI_NAME "RISCV Insert VSETVLI pass" +static cl::opt DisableInsertVSETVLPHIOpt( + "riscv-disable-insert-vsetvl-phi-opt", cl::init(false), cl::Hidden, + cl::desc("Disable looking through phis when inserting vsetvlis.")); + namespace { class VSETVLIInfo { @@ -285,6 +289,7 @@ public: private: bool needVSETVLI(const VSETVLIInfo &Require, const VSETVLIInfo &CurInfo); + bool needVSETVLIPHI(const VSETVLIInfo &Require, const MachineBasicBlock &MBB); void insertVSETVLI(MachineBasicBlock &MBB, MachineInstr &MI, const VSETVLIInfo &Info, const VSETVLIInfo &PrevInfo); @@ -526,6 +531,55 @@ void RISCVInsertVSETVLI::computeIncomingVLVTYPE(const MachineBasicBlock &MBB) { WorkList.push(S); } +// 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 +// outputs from the last VSETVLI in their respective basic blocks. +bool RISCVInsertVSETVLI::needVSETVLIPHI(const VSETVLIInfo &Require, + const MachineBasicBlock &MBB) { + if (DisableInsertVSETVLPHIOpt) + return true; + + if (!Require.hasAVLReg()) + return true; + + Register AVLReg = Require.getAVLReg(); + if (!AVLReg.isVirtual()) + return true; + + // We need the AVL to be produce by a PHI node in this basic block. + MachineInstr *PHI = MRI->getVRegDef(AVLReg); + if (!PHI || PHI->getOpcode() != RISCV::PHI || PHI->getParent() != &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 BlockData &PBBInfo = BlockInfo[PBB->getNumber()]; + // If the exit from the predecessor has the VTYPE we are looking for + // we might be able to avoid a VSETVLI. + if (PBBInfo.Exit.isUnknown() || !PBBInfo.Exit.hasSameVTYPE(Require)) + return true; + + // We need the PHI input to the be the output of a VSET(I)VLI. + MachineInstr *DefMI = MRI->getVRegDef(InReg); + if (!DefMI || (DefMI->getOpcode() != RISCV::PseudoVSETVLI && + DefMI->getOpcode() != RISCV::PseudoVSETIVLI)) + return true; + + // We found a VSET(I)VLI make sure it matches the output of the + // predecessor block. + VSETVLIInfo DefInfo = getInfoForVSETVLI(*DefMI); + if (!DefInfo.hasSameAVL(PBBInfo.Exit) || + !DefInfo.hasSameVTYPE(PBBInfo.Exit)) + return true; + } + + // If all the incoming values to the PHI checked out, we don't need + // to insert a VSETVLI. + return false; +} + void RISCVInsertVSETVLI::emitVSETVLIs(MachineBasicBlock &MBB) { VSETVLIInfo CurInfo; @@ -564,7 +618,8 @@ void RISCVInsertVSETVLI::emitVSETVLIs(MachineBasicBlock &MBB) { // use the predecessor information. assert(BlockInfo[MBB.getNumber()].Pred.isValid() && "Expected a valid predecessor state."); - if (needVSETVLI(NewInfo, BlockInfo[MBB.getNumber()].Pred)) { + if (needVSETVLI(NewInfo, BlockInfo[MBB.getNumber()].Pred) && + needVSETVLIPHI(NewInfo, MBB)) { insertVSETVLI(MBB, MI, NewInfo, BlockInfo[MBB.getNumber()].Pred); CurInfo = NewInfo; } diff --git a/llvm/test/CodeGen/RISCV/rvv/vsetvli-insert-crossbb.ll b/llvm/test/CodeGen/RISCV/rvv/vsetvli-insert-crossbb.ll index 3300de6..e529dc0 100644 --- a/llvm/test/CodeGen/RISCV/rvv/vsetvli-insert-crossbb.ll +++ b/llvm/test/CodeGen/RISCV/rvv/vsetvli-insert-crossbb.ll @@ -83,8 +83,6 @@ if.end: ; preds = %if.else, %if.then ret %3 } -; FIXME: The last vsetvli is redundant, but we need to look through a phi to -; prove it. define @test3(i64 %avl, i8 zeroext %cond, %a, %b) nounwind { ; CHECK-LABEL: test3: ; CHECK: # %bb.0: # %entry @@ -92,12 +90,11 @@ define @test3(i64 %avl, i8 zeroext %cond, %3 } -; FIXME: The vsetvli in for.body can be removed, it's redundant by its -; predecessors, but we need to look through a PHI to prove it. define void @saxpy_vec(i64 %n, float %a, float* nocapture readonly %x, float* nocapture %y) { ; CHECK-LABEL: saxpy_vec: ; CHECK: # %bb.0: # %entry @@ -456,12 +451,11 @@ define void @saxpy_vec(i64 %n, float %a, float* nocapture readonly %x, float* no ; CHECK-NEXT: fmv.w.x ft0, a1 ; CHECK-NEXT: .LBB8_2: # %for.body ; CHECK-NEXT: # =>This Inner Loop Header: Depth=1 -; CHECK-NEXT: vsetvli zero, a4, e32,m8,ta,mu ; CHECK-NEXT: vle32.v v8, (a2) ; CHECK-NEXT: vle32.v v16, (a3) ; CHECK-NEXT: slli a1, a4, 2 ; CHECK-NEXT: add a2, a2, a1 -; CHECK-NEXT: vsetvli zero, zero, e32,m8,tu,mu +; CHECK-NEXT: vsetvli zero, a4, e32,m8,tu,mu ; CHECK-NEXT: vfmacc.vf v16, ft0, v8 ; CHECK-NEXT: vsetvli zero, zero, e32,m8,ta,mu ; CHECK-NEXT: vse32.v v16, (a3) -- 2.7.4