xref: /netbsd-src/external/apache2/llvm/dist/llvm/lib/Target/RISCV/RISCVCleanupVSETVLI.cpp (revision 82d56013d7b633d116a93943de88e08335357a7c)
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