1 //===- RISCVCleanupVSETVLI.cpp - Cleanup unneeded VSETVLI instructions ----===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file implements a function pass that removes duplicate vsetvli
10 // instructions within a basic block.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "RISCV.h"
15 #include "RISCVSubtarget.h"
16 #include "llvm/CodeGen/MachineFunctionPass.h"
17 using namespace llvm;
18
19 #define DEBUG_TYPE "riscv-cleanup-vsetvli"
20 #define RISCV_CLEANUP_VSETVLI_NAME "RISCV Cleanup VSETVLI pass"
21
22 namespace {
23
24 class RISCVCleanupVSETVLI : public MachineFunctionPass {
25 public:
26 static char ID;
27
RISCVCleanupVSETVLI()28 RISCVCleanupVSETVLI() : MachineFunctionPass(ID) {
29 initializeRISCVCleanupVSETVLIPass(*PassRegistry::getPassRegistry());
30 }
31 bool runOnMachineFunction(MachineFunction &MF) override;
32 bool runOnMachineBasicBlock(MachineBasicBlock &MBB);
33
getRequiredProperties() const34 MachineFunctionProperties getRequiredProperties() const override {
35 return MachineFunctionProperties().set(
36 MachineFunctionProperties::Property::IsSSA);
37 }
38
39 // This pass modifies the program, but does not modify the CFG
getAnalysisUsage(AnalysisUsage & AU) const40 void getAnalysisUsage(AnalysisUsage &AU) const override {
41 AU.setPreservesCFG();
42 MachineFunctionPass::getAnalysisUsage(AU);
43 }
44
getPassName() const45 StringRef getPassName() const override { return RISCV_CLEANUP_VSETVLI_NAME; }
46 };
47
48 } // end anonymous namespace
49
50 char RISCVCleanupVSETVLI::ID = 0;
51
INITIALIZE_PASS(RISCVCleanupVSETVLI,DEBUG_TYPE,RISCV_CLEANUP_VSETVLI_NAME,false,false)52 INITIALIZE_PASS(RISCVCleanupVSETVLI, DEBUG_TYPE,
53 RISCV_CLEANUP_VSETVLI_NAME, false, false)
54
55 static bool isRedundantVSETVLI(MachineInstr &MI, MachineInstr *PrevVSETVLI) {
56 // If we don't have a previous VSET{I}VLI or the VL output isn't dead, we
57 // can't remove this VSETVLI.
58 if (!PrevVSETVLI || !MI.getOperand(0).isDead())
59 return false;
60
61 // Does this VSET{I}VLI use the same VTYPE immediate.
62 int64_t PrevVTYPEImm = PrevVSETVLI->getOperand(2).getImm();
63 int64_t VTYPEImm = MI.getOperand(2).getImm();
64 if (PrevVTYPEImm != VTYPEImm)
65 return false;
66
67 if (MI.getOpcode() == RISCV::PseudoVSETIVLI) {
68 // If the previous opcode wasn't vsetivli we can't compare them.
69 if (PrevVSETVLI->getOpcode() != RISCV::PseudoVSETIVLI)
70 return false;
71
72 // For VSETIVLI, we can just compare the immediates.
73 return PrevVSETVLI->getOperand(1).getImm() == MI.getOperand(1).getImm();
74 }
75
76 assert(MI.getOpcode() == RISCV::PseudoVSETVLI);
77 Register AVLReg = MI.getOperand(1).getReg();
78 Register PrevOutVL = PrevVSETVLI->getOperand(0).getReg();
79
80 // If this VSETVLI isn't changing VL, it is redundant.
81 if (AVLReg == RISCV::X0 && MI.getOperand(0).getReg() == RISCV::X0)
82 return true;
83
84 // If the previous VSET{I}VLI's output (which isn't X0) is fed into this
85 // VSETVLI, this one isn't changing VL so is redundant.
86 // Only perform this on virtual registers to avoid the complexity of having
87 // to work out if the physical register was clobbered somewhere in between.
88 if (AVLReg.isVirtual() && AVLReg == PrevOutVL)
89 return true;
90
91 // If the previous opcode isn't vsetvli we can't do any more comparison.
92 if (PrevVSETVLI->getOpcode() != RISCV::PseudoVSETVLI)
93 return false;
94
95 // Does this VSETVLI use the same AVL register?
96 if (AVLReg != PrevVSETVLI->getOperand(1).getReg())
97 return false;
98
99 // If the AVLReg is X0 we must be setting VL to VLMAX. Keeping VL unchanged
100 // was handled above.
101 if (AVLReg == RISCV::X0) {
102 // This instruction is setting VL to VLMAX, this is redundant if the
103 // previous VSETVLI was also setting VL to VLMAX. But it is not redundant
104 // if they were setting it to any other value or leaving VL unchanged.
105 return PrevOutVL != RISCV::X0;
106 }
107
108 // This vsetvli is redundant.
109 return true;
110 }
111
runOnMachineBasicBlock(MachineBasicBlock & MBB)112 bool RISCVCleanupVSETVLI::runOnMachineBasicBlock(MachineBasicBlock &MBB) {
113 bool Changed = false;
114 MachineInstr *PrevVSETVLI = nullptr;
115
116 for (auto MII = MBB.begin(), MIE = MBB.end(); MII != MIE;) {
117 MachineInstr &MI = *MII++;
118
119 if (MI.getOpcode() != RISCV::PseudoVSETVLI &&
120 MI.getOpcode() != RISCV::PseudoVSETIVLI) {
121 if (PrevVSETVLI &&
122 (MI.isCall() || MI.modifiesRegister(RISCV::VL) ||
123 MI.modifiesRegister(RISCV::VTYPE))) {
124 // Old VL/VTYPE is overwritten.
125 PrevVSETVLI = nullptr;
126 }
127 continue;
128 }
129
130 if (isRedundantVSETVLI(MI, PrevVSETVLI)) {
131 // This VSETVLI is redundant, remove it.
132 MI.eraseFromParent();
133 Changed = true;
134 } else {
135 // Otherwise update VSET{I}VLI for the next iteration.
136 PrevVSETVLI = &MI;
137 }
138 }
139
140 return Changed;
141 }
142
runOnMachineFunction(MachineFunction & MF)143 bool RISCVCleanupVSETVLI::runOnMachineFunction(MachineFunction &MF) {
144 if (skipFunction(MF.getFunction()))
145 return false;
146
147 // Skip if the vector extension is not enabled.
148 const RISCVSubtarget &ST = MF.getSubtarget<RISCVSubtarget>();
149 if (!ST.hasStdExtV())
150 return false;
151
152 bool Changed = false;
153
154 for (MachineBasicBlock &MBB : MF)
155 Changed |= runOnMachineBasicBlock(MBB);
156
157 return Changed;
158 }
159
160 /// Returns an instance of the Cleanup VSETVLI pass.
createRISCVCleanupVSETVLIPass()161 FunctionPass *llvm::createRISCVCleanupVSETVLIPass() {
162 return new RISCVCleanupVSETVLI();
163 }
164