Index: llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp =================================================================== --- llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp +++ llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp @@ -500,6 +500,16 @@ MI.getOpcode() == RISCV::PseudoVSETIVLI; } +/// Return true if this is 'vsetvli x0, x0, vtype' which preserves +/// VL and only sets VTYPE. +static bool isVTYPEConfig(const MachineInstr &MI) { + if (MI.getOpcode() != RISCV::PseudoVSETVLIX0) + return false; + Register DestReg = MI.getOperand(0).getReg(); + Register AVLReg = MI.getOperand(1).getReg(); + return DestReg == RISCV::X0 && AVLReg == RISCV::X0; +} + static MachineInstr *elideCopies(MachineInstr *MI, const MachineRegisterInfo *MRI) { while (true) { @@ -1096,9 +1106,6 @@ void RISCVInsertVSETVLI::emitVSETVLIs(MachineBasicBlock &MBB) { VSETVLIInfo CurInfo; - // Only be set if current VSETVLIInfo is from an explicit VSET(I)VLI. - MachineInstr *PrevVSETVLIMI = nullptr; - for (MachineInstr &MI : MBB) { // If this is an explicit VSETVLI or VSETIVLI, update our state. if (isVectorConfigInstr(MI)) { @@ -1109,7 +1116,6 @@ MI.getOperand(3).setIsDead(false); MI.getOperand(4).setIsDead(false); CurInfo = getInfoForVSETVLI(MI); - PrevVSETVLIMI = &MI; continue; } @@ -1156,29 +1162,10 @@ // vl/vtype for succesor blocks. if (!canSkipVSETVLIForLoadStore(MI, NewInfo, CurInfo) && needVSETVLI(NewInfo, CurInfo)) { - // If the previous VL/VTYPE is set by VSETVLI and do not use, Merge it - // with current VL/VTYPE. - bool NeedInsertVSETVLI = true; - if (PrevVSETVLIMI) { - // If these two VSETVLI have the same AVL and the same VLMAX, - // we could merge these two VSETVLI. - // TODO: If we remove this, we get a `vsetvli x0, x0, vtype' - // here. We could simply let this be emitted, then remove - // the unused vsetvlis in a post-pass. - if (CurInfo.hasSameAVL(NewInfo) && CurInfo.hasSameVLMAX(NewInfo)) { - // WARNING: For correctness, it is essential the contents of VL - // and VTYPE stay the same after this instruction. This - // greatly limits the mutation we can legally do here. - PrevVSETVLIMI->getOperand(2).setImm(NewInfo.encodeVTYPE()); - NeedInsertVSETVLI = false; - } - } - if (NeedInsertVSETVLI) - insertVSETVLI(MBB, MI, NewInfo, CurInfo); + insertVSETVLI(MBB, MI, NewInfo, CurInfo); CurInfo = NewInfo; } } - PrevVSETVLIMI = nullptr; } // If this is something that updates VL/VTYPE that we don't know about, set @@ -1186,7 +1173,6 @@ if (MI.isCall() || MI.isInlineAsm() || MI.modifiesRegister(RISCV::VL) || MI.modifiesRegister(RISCV::VTYPE)) { CurInfo = VSETVLIInfo::getUnknown(); - PrevVSETVLIMI = nullptr; } // If we reach the end of the block and our current info doesn't match the @@ -1342,6 +1328,54 @@ for (MachineBasicBlock &MBB : MF) emitVSETVLIs(MBB); + // Now that all vsetvlis are explicit, go through and do block local + // DSE and peephole based demanded fields based transforms. + MachineInstr *PrevMI = nullptr; + bool UsedVL = false, UsedVTYPE = false; + SmallVector ToDelete; + for (MachineBasicBlock &MBB : MF) { + for (MachineInstr &MI : MBB) { + // Note: Must be *before* vsetvli handling to account for config cases + // which only change some subfields. + if (MI.isCall() || MI.isInlineAsm() || MI.readsRegister(RISCV::VL)) + UsedVL = true; + if (MI.isCall() || MI.isInlineAsm() || MI.readsRegister(RISCV::VTYPE)) + UsedVTYPE = true; + + if (!isVectorConfigInstr(MI)) + continue; + + if (PrevMI) { + if (!UsedVL && !UsedVTYPE) { + LLVM_DEBUG(dbgs() << "Queue delete (dead): " << PrevMI << "\n"); + ToDelete.push_back(PrevMI); + // fallthrough + } else if (!UsedVTYPE && isVTYPEConfig(MI)) { + // Note: `vsetvli x0, x0, vtype' is the canonical instruction + // for this case. If you find yourself wanting to add other forms + // to this "unused VTYPE" case, we're probably missing a + // canonicalization earlier. + PrevMI->getOperand(2).setImm(MI.getOperand(2).getImm()); + ToDelete.push_back(&MI); + // Leave PrevMI unchanged + continue; + } + } + PrevMI = &MI; + UsedVL = false; + UsedVTYPE = false; + Register VRegDef = MI.getOperand(0).getReg(); + if (VRegDef != RISCV::X0 && + !(VRegDef.isVirtual() && MRI->use_nodbg_empty(VRegDef))) + UsedVL = true; + } + } + + for (auto *MI : ToDelete) + MI->eraseFromParent(); + + + // Once we're fully done rewriting all the instructions, do a final pass // through to check for VSETVLIs which write to an unused destination. // For the non X0, X0 variant, we can replace the destination register Index: llvm/test/CodeGen/RISCV/rvv/vsetvli-insert.ll =================================================================== --- llvm/test/CodeGen/RISCV/rvv/vsetvli-insert.ll +++ llvm/test/CodeGen/RISCV/rvv/vsetvli-insert.ll @@ -328,8 +328,7 @@ define double @test17(i64 %avl, %a, %b) nounwind { ; CHECK-LABEL: test17: ; CHECK: # %bb.0: # %entry -; CHECK-NEXT: vsetvli a0, a0, e32, mf2, ta, mu -; CHECK-NEXT: vsetvli zero, zero, e64, m1, ta, mu +; CHECK-NEXT: vsetvli a0, a0, e64, m1, ta, mu ; CHECK-NEXT: vfmv.f.s ft0, v8 ; CHECK-NEXT: vsetvli zero, a0, e64, m1, ta, mu ; CHECK-NEXT: vfadd.vv v8, v8, v9