xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
1fe6060f1SDimitry Andric //===- RISCVInsertVSETVLI.cpp - Insert VSETVLI instructions ---------------===//
2fe6060f1SDimitry Andric //
3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fe6060f1SDimitry Andric //
7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
8fe6060f1SDimitry Andric //
9fe6060f1SDimitry Andric // This file implements a function pass that inserts VSETVLI instructions where
1081ad6265SDimitry Andric // needed and expands the vl outputs of VLEFF/VLSEGFF to PseudoReadVL
1181ad6265SDimitry Andric // instructions.
12fe6060f1SDimitry Andric //
13fe6060f1SDimitry Andric // This pass consists of 3 phases:
14fe6060f1SDimitry Andric //
15fe6060f1SDimitry Andric // Phase 1 collects how each basic block affects VL/VTYPE.
16fe6060f1SDimitry Andric //
17fe6060f1SDimitry Andric // Phase 2 uses the information from phase 1 to do a data flow analysis to
18fe6060f1SDimitry Andric // propagate the VL/VTYPE changes through the function. This gives us the
19fe6060f1SDimitry Andric // VL/VTYPE at the start of each basic block.
20fe6060f1SDimitry Andric //
21fe6060f1SDimitry Andric // Phase 3 inserts VSETVLI instructions in each basic block. Information from
22fe6060f1SDimitry Andric // phase 2 is used to prevent inserting a VSETVLI before the first vector
23fe6060f1SDimitry Andric // instruction in the block if possible.
24fe6060f1SDimitry Andric //
25fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
26fe6060f1SDimitry Andric 
27fe6060f1SDimitry Andric #include "RISCV.h"
28fe6060f1SDimitry Andric #include "RISCVSubtarget.h"
29fe6060f1SDimitry Andric #include "llvm/CodeGen/LiveIntervals.h"
30fe6060f1SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
31fe6060f1SDimitry Andric #include <queue>
32fe6060f1SDimitry Andric using namespace llvm;
33fe6060f1SDimitry Andric 
34fe6060f1SDimitry Andric #define DEBUG_TYPE "riscv-insert-vsetvli"
35*06c3fb27SDimitry Andric #define RISCV_INSERT_VSETVLI_NAME "RISC-V Insert VSETVLI pass"
36fe6060f1SDimitry Andric 
37fe6060f1SDimitry Andric static cl::opt<bool> DisableInsertVSETVLPHIOpt(
38fe6060f1SDimitry Andric     "riscv-disable-insert-vsetvl-phi-opt", cl::init(false), cl::Hidden,
39fe6060f1SDimitry Andric     cl::desc("Disable looking through phis when inserting vsetvlis."));
40fe6060f1SDimitry Andric 
4181ad6265SDimitry Andric static cl::opt<bool> UseStrictAsserts(
4281ad6265SDimitry Andric     "riscv-insert-vsetvl-strict-asserts", cl::init(true), cl::Hidden,
4381ad6265SDimitry Andric     cl::desc("Enable strict assertion checking for the dataflow algorithm"));
4481ad6265SDimitry Andric 
45fe6060f1SDimitry Andric namespace {
46fe6060f1SDimitry Andric 
4781ad6265SDimitry Andric static unsigned getVLOpNum(const MachineInstr &MI) {
4881ad6265SDimitry Andric   return RISCVII::getVLOpNum(MI.getDesc());
49fe6060f1SDimitry Andric }
50fe6060f1SDimitry Andric 
5181ad6265SDimitry Andric static unsigned getSEWOpNum(const MachineInstr &MI) {
5281ad6265SDimitry Andric   return RISCVII::getSEWOpNum(MI.getDesc());
53fe6060f1SDimitry Andric }
54fe6060f1SDimitry Andric 
55bdd1243dSDimitry Andric static bool isVectorConfigInstr(const MachineInstr &MI) {
56bdd1243dSDimitry Andric   return MI.getOpcode() == RISCV::PseudoVSETVLI ||
57bdd1243dSDimitry Andric          MI.getOpcode() == RISCV::PseudoVSETVLIX0 ||
58bdd1243dSDimitry Andric          MI.getOpcode() == RISCV::PseudoVSETIVLI;
59bdd1243dSDimitry Andric }
60bdd1243dSDimitry Andric 
61bdd1243dSDimitry Andric /// Return true if this is 'vsetvli x0, x0, vtype' which preserves
62bdd1243dSDimitry Andric /// VL and only sets VTYPE.
63bdd1243dSDimitry Andric static bool isVLPreservingConfig(const MachineInstr &MI) {
64bdd1243dSDimitry Andric   if (MI.getOpcode() != RISCV::PseudoVSETVLIX0)
65bdd1243dSDimitry Andric     return false;
66bdd1243dSDimitry Andric   assert(RISCV::X0 == MI.getOperand(1).getReg());
67bdd1243dSDimitry Andric   return RISCV::X0 == MI.getOperand(0).getReg();
68bdd1243dSDimitry Andric }
69bdd1243dSDimitry Andric 
70bdd1243dSDimitry Andric static uint16_t getRVVMCOpcode(uint16_t RVVPseudoOpcode) {
71bdd1243dSDimitry Andric   const RISCVVPseudosTable::PseudoInfo *RVV =
72bdd1243dSDimitry Andric       RISCVVPseudosTable::getPseudoInfo(RVVPseudoOpcode);
73bdd1243dSDimitry Andric   if (!RVV)
74bdd1243dSDimitry Andric     return 0;
75bdd1243dSDimitry Andric   return RVV->BaseInstr;
76bdd1243dSDimitry Andric }
77bdd1243dSDimitry Andric 
7804eeddc0SDimitry Andric static bool isScalarMoveInstr(const MachineInstr &MI) {
79bdd1243dSDimitry Andric   switch (getRVVMCOpcode(MI.getOpcode())) {
8004eeddc0SDimitry Andric   default:
8104eeddc0SDimitry Andric     return false;
82bdd1243dSDimitry Andric   case RISCV::VMV_S_X:
83bdd1243dSDimitry Andric   case RISCV::VFMV_S_F:
8404eeddc0SDimitry Andric     return true;
8504eeddc0SDimitry Andric   }
8604eeddc0SDimitry Andric }
8704eeddc0SDimitry Andric 
88*06c3fb27SDimitry Andric static bool isScalarSplatInstr(const MachineInstr &MI) {
89*06c3fb27SDimitry Andric   switch (getRVVMCOpcode(MI.getOpcode())) {
90*06c3fb27SDimitry Andric   default:
91*06c3fb27SDimitry Andric     return false;
92*06c3fb27SDimitry Andric   case RISCV::VMV_V_I:
93*06c3fb27SDimitry Andric   case RISCV::VMV_V_X:
94*06c3fb27SDimitry Andric   case RISCV::VFMV_V_F:
95*06c3fb27SDimitry Andric     return true;
96*06c3fb27SDimitry Andric   }
97*06c3fb27SDimitry Andric }
98*06c3fb27SDimitry Andric 
99*06c3fb27SDimitry Andric static bool isVSlideInstr(const MachineInstr &MI) {
100*06c3fb27SDimitry Andric   switch (getRVVMCOpcode(MI.getOpcode())) {
101*06c3fb27SDimitry Andric   default:
102*06c3fb27SDimitry Andric     return false;
103*06c3fb27SDimitry Andric   case RISCV::VSLIDEDOWN_VX:
104*06c3fb27SDimitry Andric   case RISCV::VSLIDEDOWN_VI:
105*06c3fb27SDimitry Andric   case RISCV::VSLIDEUP_VX:
106*06c3fb27SDimitry Andric   case RISCV::VSLIDEUP_VI:
107*06c3fb27SDimitry Andric     return true;
108*06c3fb27SDimitry Andric   }
109*06c3fb27SDimitry Andric }
110*06c3fb27SDimitry Andric 
111bdd1243dSDimitry Andric /// Get the EEW for a load or store instruction.  Return std::nullopt if MI is
112bdd1243dSDimitry Andric /// not a load or store which ignores SEW.
113bdd1243dSDimitry Andric static std::optional<unsigned> getEEWForLoadStore(const MachineInstr &MI) {
114bdd1243dSDimitry Andric   switch (getRVVMCOpcode(MI.getOpcode())) {
115349cc55cSDimitry Andric   default:
116bdd1243dSDimitry Andric     return std::nullopt;
117bdd1243dSDimitry Andric   case RISCV::VLE8_V:
118bdd1243dSDimitry Andric   case RISCV::VLSE8_V:
119bdd1243dSDimitry Andric   case RISCV::VSE8_V:
120bdd1243dSDimitry Andric   case RISCV::VSSE8_V:
12181ad6265SDimitry Andric     return 8;
122bdd1243dSDimitry Andric   case RISCV::VLE16_V:
123bdd1243dSDimitry Andric   case RISCV::VLSE16_V:
124bdd1243dSDimitry Andric   case RISCV::VSE16_V:
125bdd1243dSDimitry Andric   case RISCV::VSSE16_V:
12681ad6265SDimitry Andric     return 16;
127bdd1243dSDimitry Andric   case RISCV::VLE32_V:
128bdd1243dSDimitry Andric   case RISCV::VLSE32_V:
129bdd1243dSDimitry Andric   case RISCV::VSE32_V:
130bdd1243dSDimitry Andric   case RISCV::VSSE32_V:
13181ad6265SDimitry Andric     return 32;
132bdd1243dSDimitry Andric   case RISCV::VLE64_V:
133bdd1243dSDimitry Andric   case RISCV::VLSE64_V:
134bdd1243dSDimitry Andric   case RISCV::VSE64_V:
135bdd1243dSDimitry Andric   case RISCV::VSSE64_V:
13681ad6265SDimitry Andric     return 64;
13781ad6265SDimitry Andric   }
138349cc55cSDimitry Andric }
139349cc55cSDimitry Andric 
14081ad6265SDimitry Andric /// Return true if this is an operation on mask registers.  Note that
14181ad6265SDimitry Andric /// this includes both arithmetic/logical ops and load/store (vlm/vsm).
14281ad6265SDimitry Andric static bool isMaskRegOp(const MachineInstr &MI) {
143bdd1243dSDimitry Andric   if (!RISCVII::hasSEWOp(MI.getDesc().TSFlags))
144bdd1243dSDimitry Andric     return false;
14581ad6265SDimitry Andric   const unsigned Log2SEW = MI.getOperand(getSEWOpNum(MI)).getImm();
14681ad6265SDimitry Andric   // A Log2SEW of 0 is an operation on mask registers only.
14781ad6265SDimitry Andric   return Log2SEW == 0;
14881ad6265SDimitry Andric }
14981ad6265SDimitry Andric 
150*06c3fb27SDimitry Andric /// Return true if the inactive elements in the result are entirely undefined.
151*06c3fb27SDimitry Andric /// Note that this is different from "agnostic" as defined by the vector
152*06c3fb27SDimitry Andric /// specification.  Agnostic requires each lane to either be undisturbed, or
153*06c3fb27SDimitry Andric /// take the value -1; no other value is allowed.
154*06c3fb27SDimitry Andric static bool hasUndefinedMergeOp(const MachineInstr &MI,
155*06c3fb27SDimitry Andric                                 const MachineRegisterInfo &MRI) {
156*06c3fb27SDimitry Andric 
157*06c3fb27SDimitry Andric   unsigned UseOpIdx;
158*06c3fb27SDimitry Andric   if (!MI.isRegTiedToUseOperand(0, &UseOpIdx))
159*06c3fb27SDimitry Andric     // If there is no passthrough operand, then the pass through
160*06c3fb27SDimitry Andric     // lanes are undefined.
161*06c3fb27SDimitry Andric     return true;
162*06c3fb27SDimitry Andric 
163*06c3fb27SDimitry Andric   // If the tied operand is an IMPLICIT_DEF (or a REG_SEQUENCE whose operands
164*06c3fb27SDimitry Andric   // are solely IMPLICIT_DEFS), the pass through lanes are undefined.
165*06c3fb27SDimitry Andric   const MachineOperand &UseMO = MI.getOperand(UseOpIdx);
166*06c3fb27SDimitry Andric   if (MachineInstr *UseMI = MRI.getVRegDef(UseMO.getReg())) {
167*06c3fb27SDimitry Andric     if (UseMI->isImplicitDef())
168*06c3fb27SDimitry Andric       return true;
169*06c3fb27SDimitry Andric 
170*06c3fb27SDimitry Andric     if (UseMI->isRegSequence()) {
171*06c3fb27SDimitry Andric       for (unsigned i = 1, e = UseMI->getNumOperands(); i < e; i += 2) {
172*06c3fb27SDimitry Andric         MachineInstr *SourceMI = MRI.getVRegDef(UseMI->getOperand(i).getReg());
173*06c3fb27SDimitry Andric         if (!SourceMI || !SourceMI->isImplicitDef())
174*06c3fb27SDimitry Andric           return false;
175*06c3fb27SDimitry Andric       }
176*06c3fb27SDimitry Andric       return true;
177*06c3fb27SDimitry Andric     }
178*06c3fb27SDimitry Andric   }
179*06c3fb27SDimitry Andric   return false;
180*06c3fb27SDimitry Andric }
181*06c3fb27SDimitry Andric 
18281ad6265SDimitry Andric /// Which subfields of VL or VTYPE have values we need to preserve?
18381ad6265SDimitry Andric struct DemandedFields {
184bdd1243dSDimitry Andric   // Some unknown property of VL is used.  If demanded, must preserve entire
185bdd1243dSDimitry Andric   // value.
186bdd1243dSDimitry Andric   bool VLAny = false;
187bdd1243dSDimitry Andric   // Only zero vs non-zero is used. If demanded, can change non-zero values.
188bdd1243dSDimitry Andric   bool VLZeroness = false;
189*06c3fb27SDimitry Andric   // What properties of SEW we need to preserve.
190*06c3fb27SDimitry Andric   enum : uint8_t {
191*06c3fb27SDimitry Andric     SEWEqual = 2,              // The exact value of SEW needs to be preserved.
192*06c3fb27SDimitry Andric     SEWGreaterThanOrEqual = 1, // SEW can be changed as long as it's greater
193*06c3fb27SDimitry Andric                                // than or equal to the original value.
194*06c3fb27SDimitry Andric     SEWNone = 0                // We don't need to preserve SEW at all.
195*06c3fb27SDimitry Andric   } SEW = SEWNone;
19681ad6265SDimitry Andric   bool LMUL = false;
19781ad6265SDimitry Andric   bool SEWLMULRatio = false;
19881ad6265SDimitry Andric   bool TailPolicy = false;
19981ad6265SDimitry Andric   bool MaskPolicy = false;
20081ad6265SDimitry Andric 
20181ad6265SDimitry Andric   // Return true if any part of VTYPE was used
202bdd1243dSDimitry Andric   bool usedVTYPE() const {
20381ad6265SDimitry Andric     return SEW || LMUL || SEWLMULRatio || TailPolicy || MaskPolicy;
20481ad6265SDimitry Andric   }
20581ad6265SDimitry Andric 
206bdd1243dSDimitry Andric   // Return true if any property of VL was used
207bdd1243dSDimitry Andric   bool usedVL() {
208bdd1243dSDimitry Andric     return VLAny || VLZeroness;
209bdd1243dSDimitry Andric   }
210bdd1243dSDimitry Andric 
21181ad6265SDimitry Andric   // Mark all VTYPE subfields and properties as demanded
21281ad6265SDimitry Andric   void demandVTYPE() {
213*06c3fb27SDimitry Andric     SEW = SEWEqual;
21481ad6265SDimitry Andric     LMUL = true;
21581ad6265SDimitry Andric     SEWLMULRatio = true;
21681ad6265SDimitry Andric     TailPolicy = true;
21781ad6265SDimitry Andric     MaskPolicy = true;
21881ad6265SDimitry Andric   }
219bdd1243dSDimitry Andric 
220bdd1243dSDimitry Andric   // Mark all VL properties as demanded
221bdd1243dSDimitry Andric   void demandVL() {
222bdd1243dSDimitry Andric     VLAny = true;
223bdd1243dSDimitry Andric     VLZeroness = true;
224bdd1243dSDimitry Andric   }
225bdd1243dSDimitry Andric 
226bdd1243dSDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
227bdd1243dSDimitry Andric   /// Support for debugging, callable in GDB: V->dump()
228bdd1243dSDimitry Andric   LLVM_DUMP_METHOD void dump() const {
229bdd1243dSDimitry Andric     print(dbgs());
230bdd1243dSDimitry Andric     dbgs() << "\n";
231bdd1243dSDimitry Andric   }
232bdd1243dSDimitry Andric 
233bdd1243dSDimitry Andric   /// Implement operator<<.
234bdd1243dSDimitry Andric   void print(raw_ostream &OS) const {
235bdd1243dSDimitry Andric     OS << "{";
236bdd1243dSDimitry Andric     OS << "VLAny=" << VLAny << ", ";
237bdd1243dSDimitry Andric     OS << "VLZeroness=" << VLZeroness << ", ";
238*06c3fb27SDimitry Andric     OS << "SEW=";
239*06c3fb27SDimitry Andric     switch (SEW) {
240*06c3fb27SDimitry Andric     case SEWEqual:
241*06c3fb27SDimitry Andric       OS << "SEWEqual";
242*06c3fb27SDimitry Andric       break;
243*06c3fb27SDimitry Andric     case SEWGreaterThanOrEqual:
244*06c3fb27SDimitry Andric       OS << "SEWGreaterThanOrEqual";
245*06c3fb27SDimitry Andric       break;
246*06c3fb27SDimitry Andric     case SEWNone:
247*06c3fb27SDimitry Andric       OS << "SEWNone";
248*06c3fb27SDimitry Andric       break;
249*06c3fb27SDimitry Andric     };
250*06c3fb27SDimitry Andric     OS << ", ";
251bdd1243dSDimitry Andric     OS << "LMUL=" << LMUL << ", ";
252bdd1243dSDimitry Andric     OS << "SEWLMULRatio=" << SEWLMULRatio << ", ";
253bdd1243dSDimitry Andric     OS << "TailPolicy=" << TailPolicy << ", ";
254bdd1243dSDimitry Andric     OS << "MaskPolicy=" << MaskPolicy;
255bdd1243dSDimitry Andric     OS << "}";
256bdd1243dSDimitry Andric   }
257bdd1243dSDimitry Andric #endif
25881ad6265SDimitry Andric };
25981ad6265SDimitry Andric 
260bdd1243dSDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
261bdd1243dSDimitry Andric LLVM_ATTRIBUTE_USED
262bdd1243dSDimitry Andric inline raw_ostream &operator<<(raw_ostream &OS, const DemandedFields &DF) {
263bdd1243dSDimitry Andric   DF.print(OS);
264bdd1243dSDimitry Andric   return OS;
265bdd1243dSDimitry Andric }
266bdd1243dSDimitry Andric #endif
267bdd1243dSDimitry Andric 
268*06c3fb27SDimitry Andric /// Return true if moving from CurVType to NewVType is
269*06c3fb27SDimitry Andric /// indistinguishable from the perspective of an instruction (or set
270*06c3fb27SDimitry Andric /// of instructions) which use only the Used subfields and properties.
271*06c3fb27SDimitry Andric static bool areCompatibleVTYPEs(uint64_t CurVType, uint64_t NewVType,
27281ad6265SDimitry Andric                                 const DemandedFields &Used) {
273*06c3fb27SDimitry Andric   if (Used.SEW == DemandedFields::SEWEqual &&
274*06c3fb27SDimitry Andric       RISCVVType::getSEW(CurVType) != RISCVVType::getSEW(NewVType))
275*06c3fb27SDimitry Andric     return false;
276*06c3fb27SDimitry Andric 
277*06c3fb27SDimitry Andric   if (Used.SEW == DemandedFields::SEWGreaterThanOrEqual &&
278*06c3fb27SDimitry Andric       RISCVVType::getSEW(NewVType) < RISCVVType::getSEW(CurVType))
27981ad6265SDimitry Andric     return false;
28081ad6265SDimitry Andric 
28181ad6265SDimitry Andric   if (Used.LMUL &&
282*06c3fb27SDimitry Andric       RISCVVType::getVLMUL(CurVType) != RISCVVType::getVLMUL(NewVType))
28381ad6265SDimitry Andric     return false;
28481ad6265SDimitry Andric 
28581ad6265SDimitry Andric   if (Used.SEWLMULRatio) {
286*06c3fb27SDimitry Andric     auto Ratio1 = RISCVVType::getSEWLMULRatio(RISCVVType::getSEW(CurVType),
287*06c3fb27SDimitry Andric                                               RISCVVType::getVLMUL(CurVType));
288*06c3fb27SDimitry Andric     auto Ratio2 = RISCVVType::getSEWLMULRatio(RISCVVType::getSEW(NewVType),
289*06c3fb27SDimitry Andric                                               RISCVVType::getVLMUL(NewVType));
29081ad6265SDimitry Andric     if (Ratio1 != Ratio2)
29181ad6265SDimitry Andric       return false;
29281ad6265SDimitry Andric   }
29381ad6265SDimitry Andric 
294*06c3fb27SDimitry Andric   if (Used.TailPolicy && RISCVVType::isTailAgnostic(CurVType) !=
295*06c3fb27SDimitry Andric                              RISCVVType::isTailAgnostic(NewVType))
29681ad6265SDimitry Andric     return false;
297*06c3fb27SDimitry Andric   if (Used.MaskPolicy && RISCVVType::isMaskAgnostic(CurVType) !=
298*06c3fb27SDimitry Andric                              RISCVVType::isMaskAgnostic(NewVType))
29981ad6265SDimitry Andric     return false;
30081ad6265SDimitry Andric   return true;
30181ad6265SDimitry Andric }
30281ad6265SDimitry Andric 
30381ad6265SDimitry Andric /// Return the fields and properties demanded by the provided instruction.
304*06c3fb27SDimitry Andric DemandedFields getDemanded(const MachineInstr &MI,
305*06c3fb27SDimitry Andric                            const MachineRegisterInfo *MRI) {
30681ad6265SDimitry Andric   // Warning: This function has to work on both the lowered (i.e. post
30781ad6265SDimitry Andric   // emitVSETVLIs) and pre-lowering forms.  The main implication of this is
30881ad6265SDimitry Andric   // that it can't use the value of a SEW, VL, or Policy operand as they might
30981ad6265SDimitry Andric   // be stale after lowering.
31081ad6265SDimitry Andric 
31181ad6265SDimitry Andric   // Most instructions don't use any of these subfeilds.
31281ad6265SDimitry Andric   DemandedFields Res;
31381ad6265SDimitry Andric   // Start conservative if registers are used
31481ad6265SDimitry Andric   if (MI.isCall() || MI.isInlineAsm() || MI.readsRegister(RISCV::VL))
315*06c3fb27SDimitry Andric     Res.demandVL();
31681ad6265SDimitry Andric   if (MI.isCall() || MI.isInlineAsm() || MI.readsRegister(RISCV::VTYPE))
31781ad6265SDimitry Andric     Res.demandVTYPE();
31881ad6265SDimitry Andric   // Start conservative on the unlowered form too
31981ad6265SDimitry Andric   uint64_t TSFlags = MI.getDesc().TSFlags;
32081ad6265SDimitry Andric   if (RISCVII::hasSEWOp(TSFlags)) {
32181ad6265SDimitry Andric     Res.demandVTYPE();
32281ad6265SDimitry Andric     if (RISCVII::hasVLOp(TSFlags))
323bdd1243dSDimitry Andric       Res.demandVL();
324bdd1243dSDimitry Andric 
325bdd1243dSDimitry Andric     // Behavior is independent of mask policy.
326bdd1243dSDimitry Andric     if (!RISCVII::usesMaskPolicy(TSFlags))
327bdd1243dSDimitry Andric       Res.MaskPolicy = false;
32881ad6265SDimitry Andric   }
32981ad6265SDimitry Andric 
33081ad6265SDimitry Andric   // Loads and stores with implicit EEW do not demand SEW or LMUL directly.
33181ad6265SDimitry Andric   // They instead demand the ratio of the two which is used in computing
33281ad6265SDimitry Andric   // EMUL, but which allows us the flexibility to change SEW and LMUL
33381ad6265SDimitry Andric   // provided we don't change the ratio.
33481ad6265SDimitry Andric   // Note: We assume that the instructions initial SEW is the EEW encoded
33581ad6265SDimitry Andric   // in the opcode.  This is asserted when constructing the VSETVLIInfo.
33681ad6265SDimitry Andric   if (getEEWForLoadStore(MI)) {
337*06c3fb27SDimitry Andric     Res.SEW = DemandedFields::SEWNone;
33881ad6265SDimitry Andric     Res.LMUL = false;
33981ad6265SDimitry Andric   }
34081ad6265SDimitry Andric 
34181ad6265SDimitry Andric   // Store instructions don't use the policy fields.
34281ad6265SDimitry Andric   if (RISCVII::hasSEWOp(TSFlags) && MI.getNumExplicitDefs() == 0) {
34381ad6265SDimitry Andric     Res.TailPolicy = false;
34481ad6265SDimitry Andric     Res.MaskPolicy = false;
34581ad6265SDimitry Andric   }
34681ad6265SDimitry Andric 
34781ad6265SDimitry Andric   // If this is a mask reg operation, it only cares about VLMAX.
34881ad6265SDimitry Andric   // TODO: Possible extensions to this logic
34981ad6265SDimitry Andric   // * Probably ok if available VLMax is larger than demanded
35081ad6265SDimitry Andric   // * The policy bits can probably be ignored..
35181ad6265SDimitry Andric   if (isMaskRegOp(MI)) {
352*06c3fb27SDimitry Andric     Res.SEW = DemandedFields::SEWNone;
35381ad6265SDimitry Andric     Res.LMUL = false;
35481ad6265SDimitry Andric   }
35581ad6265SDimitry Andric 
356bdd1243dSDimitry Andric   // For vmv.s.x and vfmv.s.f, there are only two behaviors, VL = 0 and VL > 0.
357bdd1243dSDimitry Andric   if (isScalarMoveInstr(MI)) {
358bdd1243dSDimitry Andric     Res.LMUL = false;
359bdd1243dSDimitry Andric     Res.SEWLMULRatio = false;
360bdd1243dSDimitry Andric     Res.VLAny = false;
361*06c3fb27SDimitry Andric     // For vmv.s.x and vfmv.s.f, if the merge operand is *undefined*, we don't
362*06c3fb27SDimitry Andric     // need to preserve any other bits and are thus compatible with any larger,
363*06c3fb27SDimitry Andric     // etype and can disregard policy bits.  Warning: It's tempting to try doing
364*06c3fb27SDimitry Andric     // this for any tail agnostic operation, but we can't as TA requires
365*06c3fb27SDimitry Andric     // tail lanes to either be the original value or -1.  We are writing
366*06c3fb27SDimitry Andric     // unknown bits to the lanes here.
367*06c3fb27SDimitry Andric     if (hasUndefinedMergeOp(MI, *MRI)) {
368*06c3fb27SDimitry Andric       Res.SEW = DemandedFields::SEWGreaterThanOrEqual;
369*06c3fb27SDimitry Andric       Res.TailPolicy = false;
370*06c3fb27SDimitry Andric     }
371bdd1243dSDimitry Andric   }
372bdd1243dSDimitry Andric 
37381ad6265SDimitry Andric   return Res;
37481ad6265SDimitry Andric }
37581ad6265SDimitry Andric 
37681ad6265SDimitry Andric /// Defines the abstract state with which the forward dataflow models the
37781ad6265SDimitry Andric /// values of the VL and VTYPE registers after insertion.
37881ad6265SDimitry Andric class VSETVLIInfo {
37981ad6265SDimitry Andric   union {
38081ad6265SDimitry Andric     Register AVLReg;
38181ad6265SDimitry Andric     unsigned AVLImm;
38281ad6265SDimitry Andric   };
38381ad6265SDimitry Andric 
38481ad6265SDimitry Andric   enum : uint8_t {
38581ad6265SDimitry Andric     Uninitialized,
38681ad6265SDimitry Andric     AVLIsReg,
38781ad6265SDimitry Andric     AVLIsImm,
38881ad6265SDimitry Andric     Unknown,
38981ad6265SDimitry Andric   } State = Uninitialized;
39081ad6265SDimitry Andric 
39181ad6265SDimitry Andric   // Fields from VTYPE.
39281ad6265SDimitry Andric   RISCVII::VLMUL VLMul = RISCVII::LMUL_1;
39381ad6265SDimitry Andric   uint8_t SEW = 0;
39481ad6265SDimitry Andric   uint8_t TailAgnostic : 1;
39581ad6265SDimitry Andric   uint8_t MaskAgnostic : 1;
39681ad6265SDimitry Andric   uint8_t SEWLMULRatioOnly : 1;
39781ad6265SDimitry Andric 
39881ad6265SDimitry Andric public:
39981ad6265SDimitry Andric   VSETVLIInfo()
40081ad6265SDimitry Andric       : AVLImm(0), TailAgnostic(false), MaskAgnostic(false),
40181ad6265SDimitry Andric         SEWLMULRatioOnly(false) {}
40281ad6265SDimitry Andric 
40381ad6265SDimitry Andric   static VSETVLIInfo getUnknown() {
40481ad6265SDimitry Andric     VSETVLIInfo Info;
40581ad6265SDimitry Andric     Info.setUnknown();
40681ad6265SDimitry Andric     return Info;
40781ad6265SDimitry Andric   }
40881ad6265SDimitry Andric 
40981ad6265SDimitry Andric   bool isValid() const { return State != Uninitialized; }
41081ad6265SDimitry Andric   void setUnknown() { State = Unknown; }
41181ad6265SDimitry Andric   bool isUnknown() const { return State == Unknown; }
41281ad6265SDimitry Andric 
41381ad6265SDimitry Andric   void setAVLReg(Register Reg) {
41481ad6265SDimitry Andric     AVLReg = Reg;
41581ad6265SDimitry Andric     State = AVLIsReg;
41681ad6265SDimitry Andric   }
41781ad6265SDimitry Andric 
41881ad6265SDimitry Andric   void setAVLImm(unsigned Imm) {
41981ad6265SDimitry Andric     AVLImm = Imm;
42081ad6265SDimitry Andric     State = AVLIsImm;
42181ad6265SDimitry Andric   }
42281ad6265SDimitry Andric 
42381ad6265SDimitry Andric   bool hasAVLImm() const { return State == AVLIsImm; }
42481ad6265SDimitry Andric   bool hasAVLReg() const { return State == AVLIsReg; }
42581ad6265SDimitry Andric   Register getAVLReg() const {
42681ad6265SDimitry Andric     assert(hasAVLReg());
42781ad6265SDimitry Andric     return AVLReg;
42881ad6265SDimitry Andric   }
42981ad6265SDimitry Andric   unsigned getAVLImm() const {
43081ad6265SDimitry Andric     assert(hasAVLImm());
43181ad6265SDimitry Andric     return AVLImm;
43281ad6265SDimitry Andric   }
43381ad6265SDimitry Andric 
43481ad6265SDimitry Andric   unsigned getSEW() const { return SEW; }
43581ad6265SDimitry Andric   RISCVII::VLMUL getVLMUL() const { return VLMul; }
43681ad6265SDimitry Andric 
437*06c3fb27SDimitry Andric   bool hasNonZeroAVL(const MachineRegisterInfo &MRI) const {
43881ad6265SDimitry Andric     if (hasAVLImm())
43981ad6265SDimitry Andric       return getAVLImm() > 0;
440*06c3fb27SDimitry Andric     if (hasAVLReg()) {
441*06c3fb27SDimitry Andric       if (getAVLReg() == RISCV::X0)
442*06c3fb27SDimitry Andric         return true;
443*06c3fb27SDimitry Andric       if (MachineInstr *MI = MRI.getVRegDef(getAVLReg());
444*06c3fb27SDimitry Andric           MI && MI->getOpcode() == RISCV::ADDI &&
445*06c3fb27SDimitry Andric           MI->getOperand(1).isReg() && MI->getOperand(2).isImm() &&
446*06c3fb27SDimitry Andric           MI->getOperand(1).getReg() == RISCV::X0 &&
447*06c3fb27SDimitry Andric           MI->getOperand(2).getImm() != 0)
448*06c3fb27SDimitry Andric         return true;
449*06c3fb27SDimitry Andric       return false;
450*06c3fb27SDimitry Andric     }
45181ad6265SDimitry Andric     return false;
45281ad6265SDimitry Andric   }
45381ad6265SDimitry Andric 
454*06c3fb27SDimitry Andric   bool hasEquallyZeroAVL(const VSETVLIInfo &Other,
455*06c3fb27SDimitry Andric                          const MachineRegisterInfo &MRI) const {
456bdd1243dSDimitry Andric     if (hasSameAVL(Other))
457bdd1243dSDimitry Andric       return true;
458*06c3fb27SDimitry Andric     return (hasNonZeroAVL(MRI) && Other.hasNonZeroAVL(MRI));
459bdd1243dSDimitry Andric   }
460bdd1243dSDimitry Andric 
46181ad6265SDimitry Andric   bool hasSameAVL(const VSETVLIInfo &Other) const {
46281ad6265SDimitry Andric     if (hasAVLReg() && Other.hasAVLReg())
46381ad6265SDimitry Andric       return getAVLReg() == Other.getAVLReg();
46481ad6265SDimitry Andric 
46581ad6265SDimitry Andric     if (hasAVLImm() && Other.hasAVLImm())
46681ad6265SDimitry Andric       return getAVLImm() == Other.getAVLImm();
46781ad6265SDimitry Andric 
46881ad6265SDimitry Andric     return false;
46981ad6265SDimitry Andric   }
47081ad6265SDimitry Andric 
47181ad6265SDimitry Andric   void setVTYPE(unsigned VType) {
47281ad6265SDimitry Andric     assert(isValid() && !isUnknown() &&
47381ad6265SDimitry Andric            "Can't set VTYPE for uninitialized or unknown");
47481ad6265SDimitry Andric     VLMul = RISCVVType::getVLMUL(VType);
47581ad6265SDimitry Andric     SEW = RISCVVType::getSEW(VType);
47681ad6265SDimitry Andric     TailAgnostic = RISCVVType::isTailAgnostic(VType);
47781ad6265SDimitry Andric     MaskAgnostic = RISCVVType::isMaskAgnostic(VType);
47881ad6265SDimitry Andric   }
47981ad6265SDimitry Andric   void setVTYPE(RISCVII::VLMUL L, unsigned S, bool TA, bool MA) {
48081ad6265SDimitry Andric     assert(isValid() && !isUnknown() &&
48181ad6265SDimitry Andric            "Can't set VTYPE for uninitialized or unknown");
48281ad6265SDimitry Andric     VLMul = L;
48381ad6265SDimitry Andric     SEW = S;
48481ad6265SDimitry Andric     TailAgnostic = TA;
48581ad6265SDimitry Andric     MaskAgnostic = MA;
48681ad6265SDimitry Andric   }
48781ad6265SDimitry Andric 
48881ad6265SDimitry Andric   unsigned encodeVTYPE() const {
48981ad6265SDimitry Andric     assert(isValid() && !isUnknown() && !SEWLMULRatioOnly &&
49081ad6265SDimitry Andric            "Can't encode VTYPE for uninitialized or unknown");
49181ad6265SDimitry Andric     return RISCVVType::encodeVTYPE(VLMul, SEW, TailAgnostic, MaskAgnostic);
49281ad6265SDimitry Andric   }
49381ad6265SDimitry Andric 
49481ad6265SDimitry Andric   bool hasSEWLMULRatioOnly() const { return SEWLMULRatioOnly; }
49581ad6265SDimitry Andric 
49681ad6265SDimitry Andric   bool hasSameVTYPE(const VSETVLIInfo &Other) const {
49781ad6265SDimitry Andric     assert(isValid() && Other.isValid() &&
49881ad6265SDimitry Andric            "Can't compare invalid VSETVLIInfos");
49981ad6265SDimitry Andric     assert(!isUnknown() && !Other.isUnknown() &&
50081ad6265SDimitry Andric            "Can't compare VTYPE in unknown state");
50181ad6265SDimitry Andric     assert(!SEWLMULRatioOnly && !Other.SEWLMULRatioOnly &&
50281ad6265SDimitry Andric            "Can't compare when only LMUL/SEW ratio is valid.");
50381ad6265SDimitry Andric     return std::tie(VLMul, SEW, TailAgnostic, MaskAgnostic) ==
50481ad6265SDimitry Andric            std::tie(Other.VLMul, Other.SEW, Other.TailAgnostic,
50581ad6265SDimitry Andric                     Other.MaskAgnostic);
50681ad6265SDimitry Andric   }
50781ad6265SDimitry Andric 
50881ad6265SDimitry Andric   unsigned getSEWLMULRatio() const {
50981ad6265SDimitry Andric     assert(isValid() && !isUnknown() &&
51081ad6265SDimitry Andric            "Can't use VTYPE for uninitialized or unknown");
511bdd1243dSDimitry Andric     return RISCVVType::getSEWLMULRatio(SEW, VLMul);
51281ad6265SDimitry Andric   }
51381ad6265SDimitry Andric 
51481ad6265SDimitry Andric   // Check if the VTYPE for these two VSETVLIInfos produce the same VLMAX.
51581ad6265SDimitry Andric   // Note that having the same VLMAX ensures that both share the same
51681ad6265SDimitry Andric   // function from AVL to VL; that is, they must produce the same VL value
51781ad6265SDimitry Andric   // for any given AVL value.
51881ad6265SDimitry Andric   bool hasSameVLMAX(const VSETVLIInfo &Other) const {
51981ad6265SDimitry Andric     assert(isValid() && Other.isValid() &&
52081ad6265SDimitry Andric            "Can't compare invalid VSETVLIInfos");
52181ad6265SDimitry Andric     assert(!isUnknown() && !Other.isUnknown() &&
52281ad6265SDimitry Andric            "Can't compare VTYPE in unknown state");
52381ad6265SDimitry Andric     return getSEWLMULRatio() == Other.getSEWLMULRatio();
52481ad6265SDimitry Andric   }
52581ad6265SDimitry Andric 
526bdd1243dSDimitry Andric   bool hasCompatibleVTYPE(const DemandedFields &Used,
52781ad6265SDimitry Andric                           const VSETVLIInfo &Require) const {
528*06c3fb27SDimitry Andric     return areCompatibleVTYPEs(Require.encodeVTYPE(), encodeVTYPE(), Used);
52981ad6265SDimitry Andric   }
53081ad6265SDimitry Andric 
53181ad6265SDimitry Andric   // Determine whether the vector instructions requirements represented by
53281ad6265SDimitry Andric   // Require are compatible with the previous vsetvli instruction represented
53381ad6265SDimitry Andric   // by this.  MI is the instruction whose requirements we're considering.
534*06c3fb27SDimitry Andric   bool isCompatible(const DemandedFields &Used, const VSETVLIInfo &Require,
535*06c3fb27SDimitry Andric                     const MachineRegisterInfo &MRI) const {
53681ad6265SDimitry Andric     assert(isValid() && Require.isValid() &&
53781ad6265SDimitry Andric            "Can't compare invalid VSETVLIInfos");
53881ad6265SDimitry Andric     assert(!Require.SEWLMULRatioOnly &&
53981ad6265SDimitry Andric            "Expected a valid VTYPE for instruction!");
54081ad6265SDimitry Andric     // Nothing is compatible with Unknown.
54181ad6265SDimitry Andric     if (isUnknown() || Require.isUnknown())
54281ad6265SDimitry Andric       return false;
54381ad6265SDimitry Andric 
54481ad6265SDimitry Andric     // If only our VLMAX ratio is valid, then this isn't compatible.
54581ad6265SDimitry Andric     if (SEWLMULRatioOnly)
54681ad6265SDimitry Andric       return false;
54781ad6265SDimitry Andric 
54881ad6265SDimitry Andric     // If the instruction doesn't need an AVLReg and the SEW matches, consider
54981ad6265SDimitry Andric     // it compatible.
55081ad6265SDimitry Andric     if (Require.hasAVLReg() && Require.AVLReg == RISCV::NoRegister)
55181ad6265SDimitry Andric       if (SEW == Require.SEW)
55281ad6265SDimitry Andric         return true;
55381ad6265SDimitry Andric 
554bdd1243dSDimitry Andric     if (Used.VLAny && !hasSameAVL(Require))
555bdd1243dSDimitry Andric       return false;
556bdd1243dSDimitry Andric 
557*06c3fb27SDimitry Andric     if (Used.VLZeroness && !hasEquallyZeroAVL(Require, MRI))
558bdd1243dSDimitry Andric       return false;
559bdd1243dSDimitry Andric 
560*06c3fb27SDimitry Andric     return hasCompatibleVTYPE(Used, Require);
56181ad6265SDimitry Andric   }
56281ad6265SDimitry Andric 
56381ad6265SDimitry Andric   bool operator==(const VSETVLIInfo &Other) const {
56481ad6265SDimitry Andric     // Uninitialized is only equal to another Uninitialized.
56581ad6265SDimitry Andric     if (!isValid())
56681ad6265SDimitry Andric       return !Other.isValid();
56781ad6265SDimitry Andric     if (!Other.isValid())
56881ad6265SDimitry Andric       return !isValid();
56981ad6265SDimitry Andric 
57081ad6265SDimitry Andric     // Unknown is only equal to another Unknown.
57181ad6265SDimitry Andric     if (isUnknown())
57281ad6265SDimitry Andric       return Other.isUnknown();
57381ad6265SDimitry Andric     if (Other.isUnknown())
57481ad6265SDimitry Andric       return isUnknown();
57581ad6265SDimitry Andric 
57681ad6265SDimitry Andric     if (!hasSameAVL(Other))
57781ad6265SDimitry Andric       return false;
57881ad6265SDimitry Andric 
57981ad6265SDimitry Andric     // If the SEWLMULRatioOnly bits are different, then they aren't equal.
58081ad6265SDimitry Andric     if (SEWLMULRatioOnly != Other.SEWLMULRatioOnly)
58181ad6265SDimitry Andric       return false;
58281ad6265SDimitry Andric 
58381ad6265SDimitry Andric     // If only the VLMAX is valid, check that it is the same.
58481ad6265SDimitry Andric     if (SEWLMULRatioOnly)
58581ad6265SDimitry Andric       return hasSameVLMAX(Other);
58681ad6265SDimitry Andric 
58781ad6265SDimitry Andric     // If the full VTYPE is valid, check that it is the same.
58881ad6265SDimitry Andric     return hasSameVTYPE(Other);
58981ad6265SDimitry Andric   }
59081ad6265SDimitry Andric 
59181ad6265SDimitry Andric   bool operator!=(const VSETVLIInfo &Other) const {
59281ad6265SDimitry Andric     return !(*this == Other);
59381ad6265SDimitry Andric   }
59481ad6265SDimitry Andric 
59581ad6265SDimitry Andric   // Calculate the VSETVLIInfo visible to a block assuming this and Other are
59681ad6265SDimitry Andric   // both predecessors.
59781ad6265SDimitry Andric   VSETVLIInfo intersect(const VSETVLIInfo &Other) const {
59881ad6265SDimitry Andric     // If the new value isn't valid, ignore it.
59981ad6265SDimitry Andric     if (!Other.isValid())
60081ad6265SDimitry Andric       return *this;
60181ad6265SDimitry Andric 
60281ad6265SDimitry Andric     // If this value isn't valid, this must be the first predecessor, use it.
60381ad6265SDimitry Andric     if (!isValid())
60481ad6265SDimitry Andric       return Other;
60581ad6265SDimitry Andric 
60681ad6265SDimitry Andric     // If either is unknown, the result is unknown.
60781ad6265SDimitry Andric     if (isUnknown() || Other.isUnknown())
60881ad6265SDimitry Andric       return VSETVLIInfo::getUnknown();
60981ad6265SDimitry Andric 
61081ad6265SDimitry Andric     // If we have an exact, match return this.
61181ad6265SDimitry Andric     if (*this == Other)
61281ad6265SDimitry Andric       return *this;
61381ad6265SDimitry Andric 
61481ad6265SDimitry Andric     // Not an exact match, but maybe the AVL and VLMAX are the same. If so,
61581ad6265SDimitry Andric     // return an SEW/LMUL ratio only value.
61681ad6265SDimitry Andric     if (hasSameAVL(Other) && hasSameVLMAX(Other)) {
61781ad6265SDimitry Andric       VSETVLIInfo MergeInfo = *this;
61881ad6265SDimitry Andric       MergeInfo.SEWLMULRatioOnly = true;
61981ad6265SDimitry Andric       return MergeInfo;
62081ad6265SDimitry Andric     }
62181ad6265SDimitry Andric 
62281ad6265SDimitry Andric     // Otherwise the result is unknown.
62381ad6265SDimitry Andric     return VSETVLIInfo::getUnknown();
62481ad6265SDimitry Andric   }
62581ad6265SDimitry Andric 
62681ad6265SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
62781ad6265SDimitry Andric   /// Support for debugging, callable in GDB: V->dump()
62881ad6265SDimitry Andric   LLVM_DUMP_METHOD void dump() const {
62981ad6265SDimitry Andric     print(dbgs());
63081ad6265SDimitry Andric     dbgs() << "\n";
63181ad6265SDimitry Andric   }
63281ad6265SDimitry Andric 
63381ad6265SDimitry Andric   /// Implement operator<<.
63481ad6265SDimitry Andric   /// @{
63581ad6265SDimitry Andric   void print(raw_ostream &OS) const {
63681ad6265SDimitry Andric     OS << "{";
63781ad6265SDimitry Andric     if (!isValid())
63881ad6265SDimitry Andric       OS << "Uninitialized";
63981ad6265SDimitry Andric     if (isUnknown())
64081ad6265SDimitry Andric       OS << "unknown";
64181ad6265SDimitry Andric     if (hasAVLReg())
64281ad6265SDimitry Andric       OS << "AVLReg=" << (unsigned)AVLReg;
64381ad6265SDimitry Andric     if (hasAVLImm())
64481ad6265SDimitry Andric       OS << "AVLImm=" << (unsigned)AVLImm;
64581ad6265SDimitry Andric     OS << ", "
64681ad6265SDimitry Andric        << "VLMul=" << (unsigned)VLMul << ", "
64781ad6265SDimitry Andric        << "SEW=" << (unsigned)SEW << ", "
64881ad6265SDimitry Andric        << "TailAgnostic=" << (bool)TailAgnostic << ", "
64981ad6265SDimitry Andric        << "MaskAgnostic=" << (bool)MaskAgnostic << ", "
65081ad6265SDimitry Andric        << "SEWLMULRatioOnly=" << (bool)SEWLMULRatioOnly << "}";
65181ad6265SDimitry Andric   }
65281ad6265SDimitry Andric #endif
65381ad6265SDimitry Andric };
65481ad6265SDimitry Andric 
65581ad6265SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
65681ad6265SDimitry Andric LLVM_ATTRIBUTE_USED
65781ad6265SDimitry Andric inline raw_ostream &operator<<(raw_ostream &OS, const VSETVLIInfo &V) {
65881ad6265SDimitry Andric   V.print(OS);
65981ad6265SDimitry Andric   return OS;
66081ad6265SDimitry Andric }
66181ad6265SDimitry Andric #endif
66281ad6265SDimitry Andric 
66381ad6265SDimitry Andric struct BlockData {
66481ad6265SDimitry Andric   // The VSETVLIInfo that represents the net changes to the VL/VTYPE registers
66581ad6265SDimitry Andric   // made by this block. Calculated in Phase 1.
66681ad6265SDimitry Andric   VSETVLIInfo Change;
66781ad6265SDimitry Andric 
66881ad6265SDimitry Andric   // The VSETVLIInfo that represents the VL/VTYPE settings on exit from this
66981ad6265SDimitry Andric   // block. Calculated in Phase 2.
67081ad6265SDimitry Andric   VSETVLIInfo Exit;
67181ad6265SDimitry Andric 
67281ad6265SDimitry Andric   // The VSETVLIInfo that represents the VL/VTYPE settings from all predecessor
67381ad6265SDimitry Andric   // blocks. Calculated in Phase 2, and used by Phase 3.
67481ad6265SDimitry Andric   VSETVLIInfo Pred;
67581ad6265SDimitry Andric 
67681ad6265SDimitry Andric   // Keeps track of whether the block is already in the queue.
67781ad6265SDimitry Andric   bool InQueue = false;
67881ad6265SDimitry Andric 
67981ad6265SDimitry Andric   BlockData() = default;
68081ad6265SDimitry Andric };
68181ad6265SDimitry Andric 
68281ad6265SDimitry Andric class RISCVInsertVSETVLI : public MachineFunctionPass {
68381ad6265SDimitry Andric   const TargetInstrInfo *TII;
68481ad6265SDimitry Andric   MachineRegisterInfo *MRI;
68581ad6265SDimitry Andric 
68681ad6265SDimitry Andric   std::vector<BlockData> BlockInfo;
68781ad6265SDimitry Andric   std::queue<const MachineBasicBlock *> WorkList;
68881ad6265SDimitry Andric 
68981ad6265SDimitry Andric public:
69081ad6265SDimitry Andric   static char ID;
69181ad6265SDimitry Andric 
69281ad6265SDimitry Andric   RISCVInsertVSETVLI() : MachineFunctionPass(ID) {
69381ad6265SDimitry Andric     initializeRISCVInsertVSETVLIPass(*PassRegistry::getPassRegistry());
69481ad6265SDimitry Andric   }
69581ad6265SDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
69681ad6265SDimitry Andric 
69781ad6265SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
69881ad6265SDimitry Andric     AU.setPreservesCFG();
69981ad6265SDimitry Andric     MachineFunctionPass::getAnalysisUsage(AU);
70081ad6265SDimitry Andric   }
70181ad6265SDimitry Andric 
70281ad6265SDimitry Andric   StringRef getPassName() const override { return RISCV_INSERT_VSETVLI_NAME; }
70381ad6265SDimitry Andric 
70481ad6265SDimitry Andric private:
70581ad6265SDimitry Andric   bool needVSETVLI(const MachineInstr &MI, const VSETVLIInfo &Require,
70681ad6265SDimitry Andric                    const VSETVLIInfo &CurInfo) const;
70781ad6265SDimitry Andric   bool needVSETVLIPHI(const VSETVLIInfo &Require,
70881ad6265SDimitry Andric                       const MachineBasicBlock &MBB) const;
70981ad6265SDimitry Andric   void insertVSETVLI(MachineBasicBlock &MBB, MachineInstr &MI,
71081ad6265SDimitry Andric                      const VSETVLIInfo &Info, const VSETVLIInfo &PrevInfo);
71181ad6265SDimitry Andric   void insertVSETVLI(MachineBasicBlock &MBB,
71281ad6265SDimitry Andric                      MachineBasicBlock::iterator InsertPt, DebugLoc DL,
71381ad6265SDimitry Andric                      const VSETVLIInfo &Info, const VSETVLIInfo &PrevInfo);
71481ad6265SDimitry Andric 
71581ad6265SDimitry Andric   void transferBefore(VSETVLIInfo &Info, const MachineInstr &MI);
71681ad6265SDimitry Andric   void transferAfter(VSETVLIInfo &Info, const MachineInstr &MI);
71781ad6265SDimitry Andric   bool computeVLVTYPEChanges(const MachineBasicBlock &MBB);
71881ad6265SDimitry Andric   void computeIncomingVLVTYPE(const MachineBasicBlock &MBB);
71981ad6265SDimitry Andric   void emitVSETVLIs(MachineBasicBlock &MBB);
72081ad6265SDimitry Andric   void doLocalPostpass(MachineBasicBlock &MBB);
72181ad6265SDimitry Andric   void doPRE(MachineBasicBlock &MBB);
72281ad6265SDimitry Andric   void insertReadVL(MachineBasicBlock &MBB);
72381ad6265SDimitry Andric };
72481ad6265SDimitry Andric 
72581ad6265SDimitry Andric } // end anonymous namespace
72681ad6265SDimitry Andric 
72781ad6265SDimitry Andric char RISCVInsertVSETVLI::ID = 0;
72881ad6265SDimitry Andric 
72981ad6265SDimitry Andric INITIALIZE_PASS(RISCVInsertVSETVLI, DEBUG_TYPE, RISCV_INSERT_VSETVLI_NAME,
73081ad6265SDimitry Andric                 false, false)
73181ad6265SDimitry Andric 
73281ad6265SDimitry Andric static VSETVLIInfo computeInfoForInstr(const MachineInstr &MI, uint64_t TSFlags,
73381ad6265SDimitry Andric                                        const MachineRegisterInfo *MRI) {
73481ad6265SDimitry Andric   VSETVLIInfo InstrInfo;
73581ad6265SDimitry Andric 
736*06c3fb27SDimitry Andric   bool TailAgnostic = true;
737*06c3fb27SDimitry Andric   bool MaskAgnostic = true;
738*06c3fb27SDimitry Andric   if (!hasUndefinedMergeOp(MI, *MRI)) {
739bdd1243dSDimitry Andric     // Start with undisturbed.
740bdd1243dSDimitry Andric     TailAgnostic = false;
741bdd1243dSDimitry Andric     MaskAgnostic = false;
742bdd1243dSDimitry Andric 
743bdd1243dSDimitry Andric     // If there is a policy operand, use it.
74481ad6265SDimitry Andric     if (RISCVII::hasVecPolicyOp(TSFlags)) {
74581ad6265SDimitry Andric       const MachineOperand &Op = MI.getOperand(MI.getNumExplicitOperands() - 1);
74681ad6265SDimitry Andric       uint64_t Policy = Op.getImm();
74781ad6265SDimitry Andric       assert(Policy <= (RISCVII::TAIL_AGNOSTIC | RISCVII::MASK_AGNOSTIC) &&
74881ad6265SDimitry Andric              "Invalid Policy Value");
74981ad6265SDimitry Andric       TailAgnostic = Policy & RISCVII::TAIL_AGNOSTIC;
75081ad6265SDimitry Andric       MaskAgnostic = Policy & RISCVII::MASK_AGNOSTIC;
751bdd1243dSDimitry Andric     }
752bdd1243dSDimitry Andric 
75381ad6265SDimitry Andric     // Some pseudo instructions force a tail agnostic policy despite having a
75481ad6265SDimitry Andric     // tied def.
75581ad6265SDimitry Andric     if (RISCVII::doesForceTailAgnostic(TSFlags))
75681ad6265SDimitry Andric       TailAgnostic = true;
757bdd1243dSDimitry Andric 
758bdd1243dSDimitry Andric     if (!RISCVII::usesMaskPolicy(TSFlags))
759bdd1243dSDimitry Andric       MaskAgnostic = true;
76081ad6265SDimitry Andric   }
76181ad6265SDimitry Andric 
76281ad6265SDimitry Andric   RISCVII::VLMUL VLMul = RISCVII::getLMul(TSFlags);
76381ad6265SDimitry Andric 
76481ad6265SDimitry Andric   unsigned Log2SEW = MI.getOperand(getSEWOpNum(MI)).getImm();
76581ad6265SDimitry Andric   // A Log2SEW of 0 is an operation on mask registers only.
76681ad6265SDimitry Andric   unsigned SEW = Log2SEW ? 1 << Log2SEW : 8;
76781ad6265SDimitry Andric   assert(RISCVVType::isValidSEW(SEW) && "Unexpected SEW");
76881ad6265SDimitry Andric 
76981ad6265SDimitry Andric   if (RISCVII::hasVLOp(TSFlags)) {
77081ad6265SDimitry Andric     const MachineOperand &VLOp = MI.getOperand(getVLOpNum(MI));
77181ad6265SDimitry Andric     if (VLOp.isImm()) {
77281ad6265SDimitry Andric       int64_t Imm = VLOp.getImm();
77381ad6265SDimitry Andric       // Conver the VLMax sentintel to X0 register.
77481ad6265SDimitry Andric       if (Imm == RISCV::VLMaxSentinel)
77581ad6265SDimitry Andric         InstrInfo.setAVLReg(RISCV::X0);
77681ad6265SDimitry Andric       else
77781ad6265SDimitry Andric         InstrInfo.setAVLImm(Imm);
77881ad6265SDimitry Andric     } else {
77981ad6265SDimitry Andric       InstrInfo.setAVLReg(VLOp.getReg());
78081ad6265SDimitry Andric     }
78181ad6265SDimitry Andric   } else {
78281ad6265SDimitry Andric     InstrInfo.setAVLReg(RISCV::NoRegister);
78381ad6265SDimitry Andric   }
78481ad6265SDimitry Andric #ifndef NDEBUG
785bdd1243dSDimitry Andric   if (std::optional<unsigned> EEW = getEEWForLoadStore(MI)) {
78681ad6265SDimitry Andric     assert(SEW == EEW && "Initial SEW doesn't match expected EEW");
78781ad6265SDimitry Andric   }
78881ad6265SDimitry Andric #endif
78981ad6265SDimitry Andric   InstrInfo.setVTYPE(VLMul, SEW, TailAgnostic, MaskAgnostic);
79081ad6265SDimitry Andric 
79181ad6265SDimitry Andric   return InstrInfo;
79281ad6265SDimitry Andric }
79381ad6265SDimitry Andric 
79481ad6265SDimitry Andric void RISCVInsertVSETVLI::insertVSETVLI(MachineBasicBlock &MBB, MachineInstr &MI,
79581ad6265SDimitry Andric                                        const VSETVLIInfo &Info,
79681ad6265SDimitry Andric                                        const VSETVLIInfo &PrevInfo) {
79781ad6265SDimitry Andric   DebugLoc DL = MI.getDebugLoc();
79881ad6265SDimitry Andric   insertVSETVLI(MBB, MachineBasicBlock::iterator(&MI), DL, Info, PrevInfo);
79981ad6265SDimitry Andric }
80081ad6265SDimitry Andric 
801*06c3fb27SDimitry Andric // Return a VSETVLIInfo representing the changes made by this VSETVLI or
802*06c3fb27SDimitry Andric // VSETIVLI instruction.
803*06c3fb27SDimitry Andric static VSETVLIInfo getInfoForVSETVLI(const MachineInstr &MI) {
804*06c3fb27SDimitry Andric   VSETVLIInfo NewInfo;
805*06c3fb27SDimitry Andric   if (MI.getOpcode() == RISCV::PseudoVSETIVLI) {
806*06c3fb27SDimitry Andric     NewInfo.setAVLImm(MI.getOperand(1).getImm());
807*06c3fb27SDimitry Andric   } else {
808*06c3fb27SDimitry Andric     assert(MI.getOpcode() == RISCV::PseudoVSETVLI ||
809*06c3fb27SDimitry Andric            MI.getOpcode() == RISCV::PseudoVSETVLIX0);
810*06c3fb27SDimitry Andric     Register AVLReg = MI.getOperand(1).getReg();
811*06c3fb27SDimitry Andric     assert((AVLReg != RISCV::X0 || MI.getOperand(0).getReg() != RISCV::X0) &&
812*06c3fb27SDimitry Andric            "Can't handle X0, X0 vsetvli yet");
813*06c3fb27SDimitry Andric     NewInfo.setAVLReg(AVLReg);
814*06c3fb27SDimitry Andric   }
815*06c3fb27SDimitry Andric   NewInfo.setVTYPE(MI.getOperand(2).getImm());
816*06c3fb27SDimitry Andric 
817*06c3fb27SDimitry Andric   return NewInfo;
818*06c3fb27SDimitry Andric }
819*06c3fb27SDimitry Andric 
82081ad6265SDimitry Andric void RISCVInsertVSETVLI::insertVSETVLI(MachineBasicBlock &MBB,
82181ad6265SDimitry Andric                      MachineBasicBlock::iterator InsertPt, DebugLoc DL,
82281ad6265SDimitry Andric                      const VSETVLIInfo &Info, const VSETVLIInfo &PrevInfo) {
82381ad6265SDimitry Andric 
824*06c3fb27SDimitry Andric   if (PrevInfo.isValid() && !PrevInfo.isUnknown()) {
82581ad6265SDimitry Andric     // Use X0, X0 form if the AVL is the same and the SEW+LMUL gives the same
82681ad6265SDimitry Andric     // VLMAX.
827*06c3fb27SDimitry Andric     if (Info.hasSameAVL(PrevInfo) && Info.hasSameVLMAX(PrevInfo)) {
82881ad6265SDimitry Andric       BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETVLIX0))
82981ad6265SDimitry Andric           .addReg(RISCV::X0, RegState::Define | RegState::Dead)
83081ad6265SDimitry Andric           .addReg(RISCV::X0, RegState::Kill)
83181ad6265SDimitry Andric           .addImm(Info.encodeVTYPE())
83281ad6265SDimitry Andric           .addReg(RISCV::VL, RegState::Implicit);
83381ad6265SDimitry Andric       return;
83481ad6265SDimitry Andric     }
83581ad6265SDimitry Andric 
836*06c3fb27SDimitry Andric     // If our AVL is a virtual register, it might be defined by a VSET(I)VLI. If
837*06c3fb27SDimitry Andric     // it has the same VLMAX we want and the last VL/VTYPE we observed is the
838*06c3fb27SDimitry Andric     // same, we can use the X0, X0 form.
839*06c3fb27SDimitry Andric     if (Info.hasSameVLMAX(PrevInfo) && Info.hasAVLReg() &&
840*06c3fb27SDimitry Andric         Info.getAVLReg().isVirtual()) {
841*06c3fb27SDimitry Andric       if (MachineInstr *DefMI = MRI->getVRegDef(Info.getAVLReg())) {
842*06c3fb27SDimitry Andric         if (isVectorConfigInstr(*DefMI)) {
843*06c3fb27SDimitry Andric           VSETVLIInfo DefInfo = getInfoForVSETVLI(*DefMI);
844*06c3fb27SDimitry Andric           if (DefInfo.hasSameAVL(PrevInfo) && DefInfo.hasSameVLMAX(PrevInfo)) {
845*06c3fb27SDimitry Andric             BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETVLIX0))
846*06c3fb27SDimitry Andric                 .addReg(RISCV::X0, RegState::Define | RegState::Dead)
847*06c3fb27SDimitry Andric                 .addReg(RISCV::X0, RegState::Kill)
848*06c3fb27SDimitry Andric                 .addImm(Info.encodeVTYPE())
849*06c3fb27SDimitry Andric                 .addReg(RISCV::VL, RegState::Implicit);
850*06c3fb27SDimitry Andric             return;
851*06c3fb27SDimitry Andric           }
852*06c3fb27SDimitry Andric         }
853*06c3fb27SDimitry Andric       }
854*06c3fb27SDimitry Andric     }
855*06c3fb27SDimitry Andric   }
856*06c3fb27SDimitry Andric 
85781ad6265SDimitry Andric   if (Info.hasAVLImm()) {
85881ad6265SDimitry Andric     BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETIVLI))
85981ad6265SDimitry Andric         .addReg(RISCV::X0, RegState::Define | RegState::Dead)
86081ad6265SDimitry Andric         .addImm(Info.getAVLImm())
86181ad6265SDimitry Andric         .addImm(Info.encodeVTYPE());
86281ad6265SDimitry Andric     return;
86381ad6265SDimitry Andric   }
86481ad6265SDimitry Andric 
86581ad6265SDimitry Andric   Register AVLReg = Info.getAVLReg();
86681ad6265SDimitry Andric   if (AVLReg == RISCV::NoRegister) {
86781ad6265SDimitry Andric     // We can only use x0, x0 if there's no chance of the vtype change causing
86881ad6265SDimitry Andric     // the previous vl to become invalid.
86981ad6265SDimitry Andric     if (PrevInfo.isValid() && !PrevInfo.isUnknown() &&
87081ad6265SDimitry Andric         Info.hasSameVLMAX(PrevInfo)) {
87181ad6265SDimitry Andric       BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETVLIX0))
87281ad6265SDimitry Andric           .addReg(RISCV::X0, RegState::Define | RegState::Dead)
87381ad6265SDimitry Andric           .addReg(RISCV::X0, RegState::Kill)
87481ad6265SDimitry Andric           .addImm(Info.encodeVTYPE())
87581ad6265SDimitry Andric           .addReg(RISCV::VL, RegState::Implicit);
87681ad6265SDimitry Andric       return;
87781ad6265SDimitry Andric     }
87881ad6265SDimitry Andric     // Otherwise use an AVL of 0 to avoid depending on previous vl.
87981ad6265SDimitry Andric     BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETIVLI))
88081ad6265SDimitry Andric         .addReg(RISCV::X0, RegState::Define | RegState::Dead)
88181ad6265SDimitry Andric         .addImm(0)
88281ad6265SDimitry Andric         .addImm(Info.encodeVTYPE());
88381ad6265SDimitry Andric     return;
88481ad6265SDimitry Andric   }
88581ad6265SDimitry Andric 
88681ad6265SDimitry Andric   if (AVLReg.isVirtual())
88781ad6265SDimitry Andric     MRI->constrainRegClass(AVLReg, &RISCV::GPRNoX0RegClass);
88881ad6265SDimitry Andric 
88981ad6265SDimitry Andric   // Use X0 as the DestReg unless AVLReg is X0. We also need to change the
89081ad6265SDimitry Andric   // opcode if the AVLReg is X0 as they have different register classes for
89181ad6265SDimitry Andric   // the AVL operand.
89281ad6265SDimitry Andric   Register DestReg = RISCV::X0;
89381ad6265SDimitry Andric   unsigned Opcode = RISCV::PseudoVSETVLI;
89481ad6265SDimitry Andric   if (AVLReg == RISCV::X0) {
89581ad6265SDimitry Andric     DestReg = MRI->createVirtualRegister(&RISCV::GPRRegClass);
89681ad6265SDimitry Andric     Opcode = RISCV::PseudoVSETVLIX0;
89781ad6265SDimitry Andric   }
89881ad6265SDimitry Andric   BuildMI(MBB, InsertPt, DL, TII->get(Opcode))
89981ad6265SDimitry Andric       .addReg(DestReg, RegState::Define | RegState::Dead)
90081ad6265SDimitry Andric       .addReg(AVLReg)
90181ad6265SDimitry Andric       .addImm(Info.encodeVTYPE());
90281ad6265SDimitry Andric }
90381ad6265SDimitry Andric 
904*06c3fb27SDimitry Andric static bool isLMUL1OrSmaller(RISCVII::VLMUL LMUL) {
905*06c3fb27SDimitry Andric   auto [LMul, Fractional] = RISCVVType::decodeVLMUL(LMUL);
906*06c3fb27SDimitry Andric   return Fractional || LMul == 1;
90781ad6265SDimitry Andric }
90881ad6265SDimitry Andric 
90981ad6265SDimitry Andric /// Return true if a VSETVLI is required to transition from CurInfo to Require
91081ad6265SDimitry Andric /// before MI.
91181ad6265SDimitry Andric bool RISCVInsertVSETVLI::needVSETVLI(const MachineInstr &MI,
91281ad6265SDimitry Andric                                      const VSETVLIInfo &Require,
91381ad6265SDimitry Andric                                      const VSETVLIInfo &CurInfo) const {
91481ad6265SDimitry Andric   assert(Require == computeInfoForInstr(MI, MI.getDesc().TSFlags, MRI));
91581ad6265SDimitry Andric 
91681ad6265SDimitry Andric   if (!CurInfo.isValid() || CurInfo.isUnknown() || CurInfo.hasSEWLMULRatioOnly())
91781ad6265SDimitry Andric     return true;
91881ad6265SDimitry Andric 
919*06c3fb27SDimitry Andric   DemandedFields Used = getDemanded(MI, MRI);
920bdd1243dSDimitry Andric 
921*06c3fb27SDimitry Andric   // A slidedown/slideup with an *undefined* merge op can freely clobber
922*06c3fb27SDimitry Andric   // elements not copied from the source vector (e.g. masked off, tail, or
923*06c3fb27SDimitry Andric   // slideup's prefix). Notes:
924*06c3fb27SDimitry Andric   // * We can't modify SEW here since the slide amount is in units of SEW.
925*06c3fb27SDimitry Andric   // * VL=1 is special only because we have existing support for zero vs
926*06c3fb27SDimitry Andric   //   non-zero VL.  We could generalize this if we had a VL > C predicate.
927*06c3fb27SDimitry Andric   // * The LMUL1 restriction is for machines whose latency may depend on VL.
928*06c3fb27SDimitry Andric   // * As above, this is only legal for tail "undefined" not "agnostic".
929*06c3fb27SDimitry Andric   if (isVSlideInstr(MI) && Require.hasAVLImm() && Require.getAVLImm() == 1 &&
930*06c3fb27SDimitry Andric       isLMUL1OrSmaller(CurInfo.getVLMUL()) && hasUndefinedMergeOp(MI, *MRI)) {
931*06c3fb27SDimitry Andric     Used.VLAny = false;
932*06c3fb27SDimitry Andric     Used.VLZeroness = true;
933*06c3fb27SDimitry Andric     Used.LMUL = false;
934bdd1243dSDimitry Andric     Used.TailPolicy = false;
93581ad6265SDimitry Andric   }
936*06c3fb27SDimitry Andric 
937*06c3fb27SDimitry Andric   // A tail undefined vmv.v.i/x or vfmv.v.f with VL=1 can be treated in the same
938*06c3fb27SDimitry Andric   // semantically as vmv.s.x.  This is particularly useful since we don't have an
939*06c3fb27SDimitry Andric   // immediate form of vmv.s.x, and thus frequently use vmv.v.i in it's place.
940*06c3fb27SDimitry Andric   // Since a splat is non-constant time in LMUL, we do need to be careful to not
941*06c3fb27SDimitry Andric   // increase the number of active vector registers (unlike for vmv.s.x.)
942*06c3fb27SDimitry Andric   if (isScalarSplatInstr(MI) && Require.hasAVLImm() && Require.getAVLImm() == 1 &&
943*06c3fb27SDimitry Andric       isLMUL1OrSmaller(CurInfo.getVLMUL()) && hasUndefinedMergeOp(MI, *MRI)) {
944*06c3fb27SDimitry Andric     Used.LMUL = false;
945*06c3fb27SDimitry Andric     Used.SEWLMULRatio = false;
946*06c3fb27SDimitry Andric     Used.VLAny = false;
947*06c3fb27SDimitry Andric     Used.SEW = DemandedFields::SEWGreaterThanOrEqual;
948*06c3fb27SDimitry Andric     Used.TailPolicy = false;
949bdd1243dSDimitry Andric   }
950bdd1243dSDimitry Andric 
951*06c3fb27SDimitry Andric   if (CurInfo.isCompatible(Used, Require, *MRI))
952bdd1243dSDimitry Andric     return false;
95381ad6265SDimitry Andric 
95481ad6265SDimitry Andric   // We didn't find a compatible value. If our AVL is a virtual register,
95581ad6265SDimitry Andric   // it might be defined by a VSET(I)VLI. If it has the same VLMAX we need
95681ad6265SDimitry Andric   // and the last VL/VTYPE we observed is the same, we don't need a
95781ad6265SDimitry Andric   // VSETVLI here.
95881ad6265SDimitry Andric   if (Require.hasAVLReg() && Require.getAVLReg().isVirtual() &&
959bdd1243dSDimitry Andric       CurInfo.hasCompatibleVTYPE(Used, Require)) {
96081ad6265SDimitry Andric     if (MachineInstr *DefMI = MRI->getVRegDef(Require.getAVLReg())) {
96181ad6265SDimitry Andric       if (isVectorConfigInstr(*DefMI)) {
96281ad6265SDimitry Andric         VSETVLIInfo DefInfo = getInfoForVSETVLI(*DefMI);
96381ad6265SDimitry Andric         if (DefInfo.hasSameAVL(CurInfo) && DefInfo.hasSameVLMAX(CurInfo))
96481ad6265SDimitry Andric           return false;
96581ad6265SDimitry Andric       }
96681ad6265SDimitry Andric     }
96781ad6265SDimitry Andric   }
96881ad6265SDimitry Andric 
96981ad6265SDimitry Andric   return true;
97081ad6265SDimitry Andric }
97181ad6265SDimitry Andric 
97281ad6265SDimitry Andric // Given an incoming state reaching MI, modifies that state so that it is minimally
97381ad6265SDimitry Andric // compatible with MI.  The resulting state is guaranteed to be semantically legal
97481ad6265SDimitry Andric // for MI, but may not be the state requested by MI.
97581ad6265SDimitry Andric void RISCVInsertVSETVLI::transferBefore(VSETVLIInfo &Info, const MachineInstr &MI) {
97681ad6265SDimitry Andric   uint64_t TSFlags = MI.getDesc().TSFlags;
97781ad6265SDimitry Andric   if (!RISCVII::hasSEWOp(TSFlags))
97881ad6265SDimitry Andric     return;
97981ad6265SDimitry Andric 
98081ad6265SDimitry Andric   const VSETVLIInfo NewInfo = computeInfoForInstr(MI, TSFlags, MRI);
98181ad6265SDimitry Andric   if (Info.isValid() && !needVSETVLI(MI, NewInfo, Info))
98281ad6265SDimitry Andric     return;
98381ad6265SDimitry Andric 
98481ad6265SDimitry Andric   const VSETVLIInfo PrevInfo = Info;
98581ad6265SDimitry Andric   Info = NewInfo;
98681ad6265SDimitry Andric 
98781ad6265SDimitry Andric   if (!RISCVII::hasVLOp(TSFlags))
98881ad6265SDimitry Andric     return;
98981ad6265SDimitry Andric 
99081ad6265SDimitry Andric   // For vmv.s.x and vfmv.s.f, there are only two behaviors, VL = 0 and
99181ad6265SDimitry Andric   // VL > 0. We can discard the user requested AVL and just use the last
99281ad6265SDimitry Andric   // one if we can prove it equally zero.  This removes a vsetvli entirely
99381ad6265SDimitry Andric   // if the types match or allows use of cheaper avl preserving variant
99481ad6265SDimitry Andric   // if VLMAX doesn't change.  If VLMAX might change, we couldn't use
99581ad6265SDimitry Andric   // the 'vsetvli x0, x0, vtype" variant, so we avoid the transform to
99681ad6265SDimitry Andric   // prevent extending live range of an avl register operand.
99781ad6265SDimitry Andric   // TODO: We can probably relax this for immediates.
99881ad6265SDimitry Andric   if (isScalarMoveInstr(MI) && PrevInfo.isValid() &&
999*06c3fb27SDimitry Andric       PrevInfo.hasEquallyZeroAVL(Info, *MRI) &&
100081ad6265SDimitry Andric       Info.hasSameVLMAX(PrevInfo)) {
100181ad6265SDimitry Andric     if (PrevInfo.hasAVLImm())
100281ad6265SDimitry Andric       Info.setAVLImm(PrevInfo.getAVLImm());
100381ad6265SDimitry Andric     else
100481ad6265SDimitry Andric       Info.setAVLReg(PrevInfo.getAVLReg());
100581ad6265SDimitry Andric     return;
100681ad6265SDimitry Andric   }
100781ad6265SDimitry Andric 
100861cfbce3SDimitry Andric   // If AVL is defined by a vsetvli with the same VLMAX, we can
100981ad6265SDimitry Andric   // replace the AVL operand with the AVL of the defining vsetvli.
101081ad6265SDimitry Andric   // We avoid general register AVLs to avoid extending live ranges
101181ad6265SDimitry Andric   // without being sure we can kill the original source reg entirely.
101281ad6265SDimitry Andric   if (!Info.hasAVLReg() || !Info.getAVLReg().isVirtual())
101381ad6265SDimitry Andric     return;
101481ad6265SDimitry Andric   MachineInstr *DefMI = MRI->getVRegDef(Info.getAVLReg());
101581ad6265SDimitry Andric   if (!DefMI || !isVectorConfigInstr(*DefMI))
101681ad6265SDimitry Andric     return;
101781ad6265SDimitry Andric 
101881ad6265SDimitry Andric   VSETVLIInfo DefInfo = getInfoForVSETVLI(*DefMI);
101981ad6265SDimitry Andric   if (DefInfo.hasSameVLMAX(Info) &&
102081ad6265SDimitry Andric       (DefInfo.hasAVLImm() || DefInfo.getAVLReg() == RISCV::X0)) {
102181ad6265SDimitry Andric     if (DefInfo.hasAVLImm())
102281ad6265SDimitry Andric       Info.setAVLImm(DefInfo.getAVLImm());
102381ad6265SDimitry Andric     else
102481ad6265SDimitry Andric       Info.setAVLReg(DefInfo.getAVLReg());
102581ad6265SDimitry Andric     return;
102681ad6265SDimitry Andric   }
102781ad6265SDimitry Andric }
102881ad6265SDimitry Andric 
102981ad6265SDimitry Andric // Given a state with which we evaluated MI (see transferBefore above for why
103081ad6265SDimitry Andric // this might be different that the state MI requested), modify the state to
103181ad6265SDimitry Andric // reflect the changes MI might make.
103281ad6265SDimitry Andric void RISCVInsertVSETVLI::transferAfter(VSETVLIInfo &Info, const MachineInstr &MI) {
103381ad6265SDimitry Andric   if (isVectorConfigInstr(MI)) {
103481ad6265SDimitry Andric     Info = getInfoForVSETVLI(MI);
103581ad6265SDimitry Andric     return;
103681ad6265SDimitry Andric   }
103781ad6265SDimitry Andric 
103881ad6265SDimitry Andric   if (RISCV::isFaultFirstLoad(MI)) {
103981ad6265SDimitry Andric     // Update AVL to vl-output of the fault first load.
104081ad6265SDimitry Andric     Info.setAVLReg(MI.getOperand(1).getReg());
104181ad6265SDimitry Andric     return;
104281ad6265SDimitry Andric   }
104381ad6265SDimitry Andric 
104481ad6265SDimitry Andric   // If this is something that updates VL/VTYPE that we don't know about, set
104581ad6265SDimitry Andric   // the state to unknown.
104681ad6265SDimitry Andric   if (MI.isCall() || MI.isInlineAsm() || MI.modifiesRegister(RISCV::VL) ||
104781ad6265SDimitry Andric       MI.modifiesRegister(RISCV::VTYPE))
104881ad6265SDimitry Andric     Info = VSETVLIInfo::getUnknown();
1049349cc55cSDimitry Andric }
1050349cc55cSDimitry Andric 
1051fe6060f1SDimitry Andric bool RISCVInsertVSETVLI::computeVLVTYPEChanges(const MachineBasicBlock &MBB) {
1052fe6060f1SDimitry Andric   bool HadVectorOp = false;
1053fe6060f1SDimitry Andric 
1054fe6060f1SDimitry Andric   BlockData &BBInfo = BlockInfo[MBB.getNumber()];
105581ad6265SDimitry Andric   BBInfo.Change = BBInfo.Pred;
1056fe6060f1SDimitry Andric   for (const MachineInstr &MI : MBB) {
105781ad6265SDimitry Andric     transferBefore(BBInfo.Change, MI);
1058fe6060f1SDimitry Andric 
105981ad6265SDimitry Andric     if (isVectorConfigInstr(MI) || RISCVII::hasSEWOp(MI.getDesc().TSFlags))
1060fe6060f1SDimitry Andric       HadVectorOp = true;
1061fe6060f1SDimitry Andric 
106281ad6265SDimitry Andric     transferAfter(BBInfo.Change, MI);
1063fe6060f1SDimitry Andric   }
1064fe6060f1SDimitry Andric 
1065fe6060f1SDimitry Andric   return HadVectorOp;
1066fe6060f1SDimitry Andric }
1067fe6060f1SDimitry Andric 
1068fe6060f1SDimitry Andric void RISCVInsertVSETVLI::computeIncomingVLVTYPE(const MachineBasicBlock &MBB) {
106981ad6265SDimitry Andric 
1070fe6060f1SDimitry Andric   BlockData &BBInfo = BlockInfo[MBB.getNumber()];
1071fe6060f1SDimitry Andric 
1072fe6060f1SDimitry Andric   BBInfo.InQueue = false;
1073fe6060f1SDimitry Andric 
1074bdd1243dSDimitry Andric   // Start with the previous entry so that we keep the most conservative state
1075bdd1243dSDimitry Andric   // we have ever found.
1076bdd1243dSDimitry Andric   VSETVLIInfo InInfo = BBInfo.Pred;
1077fe6060f1SDimitry Andric   if (MBB.pred_empty()) {
1078fe6060f1SDimitry Andric     // There are no predecessors, so use the default starting status.
1079fe6060f1SDimitry Andric     InInfo.setUnknown();
1080fe6060f1SDimitry Andric   } else {
1081fe6060f1SDimitry Andric     for (MachineBasicBlock *P : MBB.predecessors())
1082fe6060f1SDimitry Andric       InInfo = InInfo.intersect(BlockInfo[P->getNumber()].Exit);
1083fe6060f1SDimitry Andric   }
1084fe6060f1SDimitry Andric 
1085fe6060f1SDimitry Andric   // If we don't have any valid predecessor value, wait until we do.
1086fe6060f1SDimitry Andric   if (!InInfo.isValid())
1087fe6060f1SDimitry Andric     return;
1088fe6060f1SDimitry Andric 
108981ad6265SDimitry Andric   // If no change, no need to rerun block
109081ad6265SDimitry Andric   if (InInfo == BBInfo.Pred)
109181ad6265SDimitry Andric     return;
1092fe6060f1SDimitry Andric 
109381ad6265SDimitry Andric   BBInfo.Pred = InInfo;
109481ad6265SDimitry Andric   LLVM_DEBUG(dbgs() << "Entry state of " << printMBBReference(MBB)
109581ad6265SDimitry Andric                     << " changed to " << BBInfo.Pred << "\n");
109681ad6265SDimitry Andric 
109781ad6265SDimitry Andric   // Note: It's tempting to cache the state changes here, but due to the
109881ad6265SDimitry Andric   // compatibility checks performed a blocks output state can change based on
109981ad6265SDimitry Andric   // the input state.  To cache, we'd have to add logic for finding
110081ad6265SDimitry Andric   // never-compatible state changes.
110181ad6265SDimitry Andric   computeVLVTYPEChanges(MBB);
110281ad6265SDimitry Andric   VSETVLIInfo TmpStatus = BBInfo.Change;
1103fe6060f1SDimitry Andric 
1104fe6060f1SDimitry Andric   // If the new exit value matches the old exit value, we don't need to revisit
1105fe6060f1SDimitry Andric   // any blocks.
1106fe6060f1SDimitry Andric   if (BBInfo.Exit == TmpStatus)
1107fe6060f1SDimitry Andric     return;
1108fe6060f1SDimitry Andric 
1109fe6060f1SDimitry Andric   BBInfo.Exit = TmpStatus;
111081ad6265SDimitry Andric   LLVM_DEBUG(dbgs() << "Exit state of " << printMBBReference(MBB)
111181ad6265SDimitry Andric                     << " changed to " << BBInfo.Exit << "\n");
1112fe6060f1SDimitry Andric 
1113fe6060f1SDimitry Andric   // Add the successors to the work list so we can propagate the changed exit
1114fe6060f1SDimitry Andric   // status.
1115fe6060f1SDimitry Andric   for (MachineBasicBlock *S : MBB.successors())
1116bdd1243dSDimitry Andric     if (!BlockInfo[S->getNumber()].InQueue) {
1117bdd1243dSDimitry Andric       BlockInfo[S->getNumber()].InQueue = true;
1118fe6060f1SDimitry Andric       WorkList.push(S);
1119fe6060f1SDimitry Andric     }
1120bdd1243dSDimitry Andric }
1121fe6060f1SDimitry Andric 
1122fe6060f1SDimitry Andric // If we weren't able to prove a vsetvli was directly unneeded, it might still
112381ad6265SDimitry Andric // be unneeded if the AVL is a phi node where all incoming values are VL
1124fe6060f1SDimitry Andric // outputs from the last VSETVLI in their respective basic blocks.
1125fe6060f1SDimitry Andric bool RISCVInsertVSETVLI::needVSETVLIPHI(const VSETVLIInfo &Require,
112681ad6265SDimitry Andric                                         const MachineBasicBlock &MBB) const {
1127fe6060f1SDimitry Andric   if (DisableInsertVSETVLPHIOpt)
1128fe6060f1SDimitry Andric     return true;
1129fe6060f1SDimitry Andric 
1130fe6060f1SDimitry Andric   if (!Require.hasAVLReg())
1131fe6060f1SDimitry Andric     return true;
1132fe6060f1SDimitry Andric 
1133fe6060f1SDimitry Andric   Register AVLReg = Require.getAVLReg();
1134fe6060f1SDimitry Andric   if (!AVLReg.isVirtual())
1135fe6060f1SDimitry Andric     return true;
1136fe6060f1SDimitry Andric 
1137fe6060f1SDimitry Andric   // We need the AVL to be produce by a PHI node in this basic block.
1138fe6060f1SDimitry Andric   MachineInstr *PHI = MRI->getVRegDef(AVLReg);
1139fe6060f1SDimitry Andric   if (!PHI || PHI->getOpcode() != RISCV::PHI || PHI->getParent() != &MBB)
1140fe6060f1SDimitry Andric     return true;
1141fe6060f1SDimitry Andric 
1142fe6060f1SDimitry Andric   for (unsigned PHIOp = 1, NumOps = PHI->getNumOperands(); PHIOp != NumOps;
1143fe6060f1SDimitry Andric        PHIOp += 2) {
1144fe6060f1SDimitry Andric     Register InReg = PHI->getOperand(PHIOp).getReg();
1145fe6060f1SDimitry Andric     MachineBasicBlock *PBB = PHI->getOperand(PHIOp + 1).getMBB();
1146fe6060f1SDimitry Andric     const BlockData &PBBInfo = BlockInfo[PBB->getNumber()];
1147fe6060f1SDimitry Andric     // If the exit from the predecessor has the VTYPE we are looking for
1148fe6060f1SDimitry Andric     // we might be able to avoid a VSETVLI.
114981ad6265SDimitry Andric     if (PBBInfo.Exit.isUnknown() || !PBBInfo.Exit.hasSameVTYPE(Require))
1150fe6060f1SDimitry Andric       return true;
1151fe6060f1SDimitry Andric 
1152fe6060f1SDimitry Andric     // We need the PHI input to the be the output of a VSET(I)VLI.
1153fe6060f1SDimitry Andric     MachineInstr *DefMI = MRI->getVRegDef(InReg);
115481ad6265SDimitry Andric     if (!DefMI || !isVectorConfigInstr(*DefMI))
1155fe6060f1SDimitry Andric       return true;
1156fe6060f1SDimitry Andric 
1157fe6060f1SDimitry Andric     // We found a VSET(I)VLI make sure it matches the output of the
1158fe6060f1SDimitry Andric     // predecessor block.
1159fe6060f1SDimitry Andric     VSETVLIInfo DefInfo = getInfoForVSETVLI(*DefMI);
1160fe6060f1SDimitry Andric     if (!DefInfo.hasSameAVL(PBBInfo.Exit) ||
1161fe6060f1SDimitry Andric         !DefInfo.hasSameVTYPE(PBBInfo.Exit))
1162fe6060f1SDimitry Andric       return true;
1163fe6060f1SDimitry Andric   }
1164fe6060f1SDimitry Andric 
1165fe6060f1SDimitry Andric   // If all the incoming values to the PHI checked out, we don't need
1166fe6060f1SDimitry Andric   // to insert a VSETVLI.
1167fe6060f1SDimitry Andric   return false;
1168fe6060f1SDimitry Andric }
1169fe6060f1SDimitry Andric 
1170fe6060f1SDimitry Andric void RISCVInsertVSETVLI::emitVSETVLIs(MachineBasicBlock &MBB) {
117181ad6265SDimitry Andric   VSETVLIInfo CurInfo = BlockInfo[MBB.getNumber()].Pred;
117281ad6265SDimitry Andric   // Track whether the prefix of the block we've scanned is transparent
117381ad6265SDimitry Andric   // (meaning has not yet changed the abstract state).
117481ad6265SDimitry Andric   bool PrefixTransparent = true;
1175fe6060f1SDimitry Andric   for (MachineInstr &MI : MBB) {
117681ad6265SDimitry Andric     const VSETVLIInfo PrevInfo = CurInfo;
117781ad6265SDimitry Andric     transferBefore(CurInfo, MI);
117881ad6265SDimitry Andric 
1179fe6060f1SDimitry Andric     // If this is an explicit VSETVLI or VSETIVLI, update our state.
118081ad6265SDimitry Andric     if (isVectorConfigInstr(MI)) {
1181fe6060f1SDimitry Andric       // Conservatively, mark the VL and VTYPE as live.
1182fe6060f1SDimitry Andric       assert(MI.getOperand(3).getReg() == RISCV::VL &&
1183fe6060f1SDimitry Andric              MI.getOperand(4).getReg() == RISCV::VTYPE &&
1184fe6060f1SDimitry Andric              "Unexpected operands where VL and VTYPE should be");
1185fe6060f1SDimitry Andric       MI.getOperand(3).setIsDead(false);
1186fe6060f1SDimitry Andric       MI.getOperand(4).setIsDead(false);
118781ad6265SDimitry Andric       PrefixTransparent = false;
1188fe6060f1SDimitry Andric     }
1189fe6060f1SDimitry Andric 
1190fe6060f1SDimitry Andric     uint64_t TSFlags = MI.getDesc().TSFlags;
1191fe6060f1SDimitry Andric     if (RISCVII::hasSEWOp(TSFlags)) {
119281ad6265SDimitry Andric       if (PrevInfo != CurInfo) {
119381ad6265SDimitry Andric         // If this is the first implicit state change, and the state change
119481ad6265SDimitry Andric         // requested can be proven to produce the same register contents, we
119581ad6265SDimitry Andric         // can skip emitting the actual state change and continue as if we
119681ad6265SDimitry Andric         // had since we know the GPR result of the implicit state change
119781ad6265SDimitry Andric         // wouldn't be used and VL/VTYPE registers are correct.  Note that
119881ad6265SDimitry Andric         // we *do* need to model the state as if it changed as while the
119981ad6265SDimitry Andric         // register contents are unchanged, the abstract model can change.
120081ad6265SDimitry Andric         if (!PrefixTransparent || needVSETVLIPHI(CurInfo, MBB))
120181ad6265SDimitry Andric           insertVSETVLI(MBB, MI, CurInfo, PrevInfo);
120281ad6265SDimitry Andric         PrefixTransparent = false;
120381ad6265SDimitry Andric       }
120481ad6265SDimitry Andric 
1205fe6060f1SDimitry Andric       if (RISCVII::hasVLOp(TSFlags)) {
120681ad6265SDimitry Andric         MachineOperand &VLOp = MI.getOperand(getVLOpNum(MI));
1207fe6060f1SDimitry Andric         if (VLOp.isReg()) {
1208fe6060f1SDimitry Andric           // Erase the AVL operand from the instruction.
1209fe6060f1SDimitry Andric           VLOp.setReg(RISCV::NoRegister);
1210fe6060f1SDimitry Andric           VLOp.setIsKill(false);
1211fe6060f1SDimitry Andric         }
1212fe6060f1SDimitry Andric         MI.addOperand(MachineOperand::CreateReg(RISCV::VL, /*isDef*/ false,
1213fe6060f1SDimitry Andric                                                 /*isImp*/ true));
1214fe6060f1SDimitry Andric       }
1215fe6060f1SDimitry Andric       MI.addOperand(MachineOperand::CreateReg(RISCV::VTYPE, /*isDef*/ false,
1216fe6060f1SDimitry Andric                                               /*isImp*/ true));
1217fe6060f1SDimitry Andric     }
1218fe6060f1SDimitry Andric 
1219fe6060f1SDimitry Andric     if (MI.isCall() || MI.isInlineAsm() || MI.modifiesRegister(RISCV::VL) ||
122081ad6265SDimitry Andric         MI.modifiesRegister(RISCV::VTYPE))
122181ad6265SDimitry Andric       PrefixTransparent = false;
122281ad6265SDimitry Andric 
122381ad6265SDimitry Andric     transferAfter(CurInfo, MI);
1224fe6060f1SDimitry Andric   }
1225d56accc7SDimitry Andric 
1226d56accc7SDimitry Andric   // If we reach the end of the block and our current info doesn't match the
1227d56accc7SDimitry Andric   // expected info, insert a vsetvli to correct.
122881ad6265SDimitry Andric   if (!UseStrictAsserts) {
1229d56accc7SDimitry Andric     const VSETVLIInfo &ExitInfo = BlockInfo[MBB.getNumber()].Exit;
1230d56accc7SDimitry Andric     if (CurInfo.isValid() && ExitInfo.isValid() && !ExitInfo.isUnknown() &&
1231d56accc7SDimitry Andric         CurInfo != ExitInfo) {
123281ad6265SDimitry Andric       // Note there's an implicit assumption here that terminators never use
123381ad6265SDimitry Andric       // or modify VL or VTYPE.  Also, fallthrough will return end().
123481ad6265SDimitry Andric       auto InsertPt = MBB.getFirstInstrTerminator();
123581ad6265SDimitry Andric       insertVSETVLI(MBB, InsertPt, MBB.findDebugLoc(InsertPt), ExitInfo,
123681ad6265SDimitry Andric                     CurInfo);
1237d56accc7SDimitry Andric       CurInfo = ExitInfo;
1238d56accc7SDimitry Andric     }
1239d56accc7SDimitry Andric   }
124081ad6265SDimitry Andric 
124181ad6265SDimitry Andric   if (UseStrictAsserts && CurInfo.isValid()) {
124281ad6265SDimitry Andric     const auto &Info = BlockInfo[MBB.getNumber()];
124381ad6265SDimitry Andric     if (CurInfo != Info.Exit) {
124481ad6265SDimitry Andric       LLVM_DEBUG(dbgs() << "in block " << printMBBReference(MBB) << "\n");
124581ad6265SDimitry Andric       LLVM_DEBUG(dbgs() << "  begin        state: " << Info.Pred << "\n");
124681ad6265SDimitry Andric       LLVM_DEBUG(dbgs() << "  expected end state: " << Info.Exit << "\n");
124781ad6265SDimitry Andric       LLVM_DEBUG(dbgs() << "  actual   end state: " << CurInfo << "\n");
124881ad6265SDimitry Andric     }
124981ad6265SDimitry Andric     assert(CurInfo == Info.Exit &&
125081ad6265SDimitry Andric            "InsertVSETVLI dataflow invariant violated");
125181ad6265SDimitry Andric   }
125281ad6265SDimitry Andric }
125381ad6265SDimitry Andric 
125481ad6265SDimitry Andric /// Return true if the VL value configured must be equal to the requested one.
125581ad6265SDimitry Andric static bool hasFixedResult(const VSETVLIInfo &Info, const RISCVSubtarget &ST) {
125681ad6265SDimitry Andric   if (!Info.hasAVLImm())
125781ad6265SDimitry Andric     // VLMAX is always the same value.
125881ad6265SDimitry Andric     // TODO: Could extend to other registers by looking at the associated vreg
125981ad6265SDimitry Andric     // def placement.
126081ad6265SDimitry Andric     return RISCV::X0 == Info.getAVLReg();
126181ad6265SDimitry Andric 
126281ad6265SDimitry Andric   unsigned AVL = Info.getAVLImm();
126381ad6265SDimitry Andric   unsigned SEW = Info.getSEW();
126481ad6265SDimitry Andric   unsigned AVLInBits = AVL * SEW;
126581ad6265SDimitry Andric 
126681ad6265SDimitry Andric   unsigned LMul;
126781ad6265SDimitry Andric   bool Fractional;
126881ad6265SDimitry Andric   std::tie(LMul, Fractional) = RISCVVType::decodeVLMUL(Info.getVLMUL());
126981ad6265SDimitry Andric 
127081ad6265SDimitry Andric   if (Fractional)
127181ad6265SDimitry Andric     return ST.getRealMinVLen() / LMul >= AVLInBits;
127281ad6265SDimitry Andric   return ST.getRealMinVLen() * LMul >= AVLInBits;
127381ad6265SDimitry Andric }
127481ad6265SDimitry Andric 
127581ad6265SDimitry Andric /// Perform simple partial redundancy elimination of the VSETVLI instructions
127681ad6265SDimitry Andric /// we're about to insert by looking for cases where we can PRE from the
127781ad6265SDimitry Andric /// beginning of one block to the end of one of its predecessors.  Specifically,
127881ad6265SDimitry Andric /// this is geared to catch the common case of a fixed length vsetvl in a single
127981ad6265SDimitry Andric /// block loop when it could execute once in the preheader instead.
128081ad6265SDimitry Andric void RISCVInsertVSETVLI::doPRE(MachineBasicBlock &MBB) {
128181ad6265SDimitry Andric   const MachineFunction &MF = *MBB.getParent();
128281ad6265SDimitry Andric   const RISCVSubtarget &ST = MF.getSubtarget<RISCVSubtarget>();
128381ad6265SDimitry Andric 
128481ad6265SDimitry Andric   if (!BlockInfo[MBB.getNumber()].Pred.isUnknown())
128581ad6265SDimitry Andric     return;
128681ad6265SDimitry Andric 
128781ad6265SDimitry Andric   MachineBasicBlock *UnavailablePred = nullptr;
128881ad6265SDimitry Andric   VSETVLIInfo AvailableInfo;
128981ad6265SDimitry Andric   for (MachineBasicBlock *P : MBB.predecessors()) {
129081ad6265SDimitry Andric     const VSETVLIInfo &PredInfo = BlockInfo[P->getNumber()].Exit;
129181ad6265SDimitry Andric     if (PredInfo.isUnknown()) {
129281ad6265SDimitry Andric       if (UnavailablePred)
129381ad6265SDimitry Andric         return;
129481ad6265SDimitry Andric       UnavailablePred = P;
129581ad6265SDimitry Andric     } else if (!AvailableInfo.isValid()) {
129681ad6265SDimitry Andric       AvailableInfo = PredInfo;
129781ad6265SDimitry Andric     } else if (AvailableInfo != PredInfo) {
129881ad6265SDimitry Andric       return;
129981ad6265SDimitry Andric     }
130081ad6265SDimitry Andric   }
130181ad6265SDimitry Andric 
130281ad6265SDimitry Andric   // Unreachable, single pred, or full redundancy. Note that FRE is handled by
130381ad6265SDimitry Andric   // phase 3.
130481ad6265SDimitry Andric   if (!UnavailablePred || !AvailableInfo.isValid())
130581ad6265SDimitry Andric     return;
130681ad6265SDimitry Andric 
130781ad6265SDimitry Andric   // Critical edge - TODO: consider splitting?
130881ad6265SDimitry Andric   if (UnavailablePred->succ_size() != 1)
130981ad6265SDimitry Andric     return;
131081ad6265SDimitry Andric 
131181ad6265SDimitry Andric   // If VL can be less than AVL, then we can't reduce the frequency of exec.
131281ad6265SDimitry Andric   if (!hasFixedResult(AvailableInfo, ST))
131381ad6265SDimitry Andric     return;
131481ad6265SDimitry Andric 
1315*06c3fb27SDimitry Andric   // Model the effect of changing the input state of the block MBB to
1316*06c3fb27SDimitry Andric   // AvailableInfo.  We're looking for two issues here; one legality,
1317*06c3fb27SDimitry Andric   // one profitability.
1318*06c3fb27SDimitry Andric   // 1) If the block doesn't use some of the fields from VL or VTYPE, we
1319*06c3fb27SDimitry Andric   //    may hit the end of the block with a different end state.  We can
1320*06c3fb27SDimitry Andric   //    not make this change without reflowing later blocks as well.
1321*06c3fb27SDimitry Andric   // 2) If we don't actually remove a transition, inserting a vsetvli
1322*06c3fb27SDimitry Andric   //    into the predecessor block would be correct, but unprofitable.
1323*06c3fb27SDimitry Andric   VSETVLIInfo OldInfo = BlockInfo[MBB.getNumber()].Pred;
1324*06c3fb27SDimitry Andric   VSETVLIInfo CurInfo = AvailableInfo;
1325*06c3fb27SDimitry Andric   int TransitionsRemoved = 0;
1326*06c3fb27SDimitry Andric   for (const MachineInstr &MI : MBB) {
1327*06c3fb27SDimitry Andric     const VSETVLIInfo LastInfo = CurInfo;
1328*06c3fb27SDimitry Andric     const VSETVLIInfo LastOldInfo = OldInfo;
1329*06c3fb27SDimitry Andric     transferBefore(CurInfo, MI);
1330*06c3fb27SDimitry Andric     transferBefore(OldInfo, MI);
1331*06c3fb27SDimitry Andric     if (CurInfo == LastInfo)
1332*06c3fb27SDimitry Andric       TransitionsRemoved++;
1333*06c3fb27SDimitry Andric     if (LastOldInfo == OldInfo)
1334*06c3fb27SDimitry Andric       TransitionsRemoved--;
1335*06c3fb27SDimitry Andric     transferAfter(CurInfo, MI);
1336*06c3fb27SDimitry Andric     transferAfter(OldInfo, MI);
1337*06c3fb27SDimitry Andric     if (CurInfo == OldInfo)
1338*06c3fb27SDimitry Andric       // Convergence.  All transitions after this must match by construction.
133981ad6265SDimitry Andric       break;
134081ad6265SDimitry Andric   }
1341*06c3fb27SDimitry Andric   if (CurInfo != OldInfo || TransitionsRemoved <= 0)
1342*06c3fb27SDimitry Andric     // Issues 1 and 2 above
134381ad6265SDimitry Andric     return;
134481ad6265SDimitry Andric 
134581ad6265SDimitry Andric   // Finally, update both data flow state and insert the actual vsetvli.
134681ad6265SDimitry Andric   // Doing both keeps the code in sync with the dataflow results, which
134781ad6265SDimitry Andric   // is critical for correctness of phase 3.
1348*06c3fb27SDimitry Andric   auto OldExit = BlockInfo[UnavailablePred->getNumber()].Exit;
134981ad6265SDimitry Andric   LLVM_DEBUG(dbgs() << "PRE VSETVLI from " << MBB.getName() << " to "
135081ad6265SDimitry Andric                     << UnavailablePred->getName() << " with state "
135181ad6265SDimitry Andric                     << AvailableInfo << "\n");
135281ad6265SDimitry Andric   BlockInfo[UnavailablePred->getNumber()].Exit = AvailableInfo;
135381ad6265SDimitry Andric   BlockInfo[MBB.getNumber()].Pred = AvailableInfo;
135481ad6265SDimitry Andric 
135581ad6265SDimitry Andric   // Note there's an implicit assumption here that terminators never use
135681ad6265SDimitry Andric   // or modify VL or VTYPE.  Also, fallthrough will return end().
135781ad6265SDimitry Andric   auto InsertPt = UnavailablePred->getFirstInstrTerminator();
135881ad6265SDimitry Andric   insertVSETVLI(*UnavailablePred, InsertPt,
135981ad6265SDimitry Andric                 UnavailablePred->findDebugLoc(InsertPt),
1360*06c3fb27SDimitry Andric                 AvailableInfo, OldExit);
136181ad6265SDimitry Andric }
136281ad6265SDimitry Andric 
136381ad6265SDimitry Andric static void doUnion(DemandedFields &A, DemandedFields B) {
1364bdd1243dSDimitry Andric   A.VLAny |= B.VLAny;
1365bdd1243dSDimitry Andric   A.VLZeroness |= B.VLZeroness;
1366*06c3fb27SDimitry Andric   A.SEW = std::max(A.SEW, B.SEW);
136781ad6265SDimitry Andric   A.LMUL |= B.LMUL;
136881ad6265SDimitry Andric   A.SEWLMULRatio |= B.SEWLMULRatio;
136981ad6265SDimitry Andric   A.TailPolicy |= B.TailPolicy;
137081ad6265SDimitry Andric   A.MaskPolicy |= B.MaskPolicy;
137181ad6265SDimitry Andric }
137281ad6265SDimitry Andric 
1373bdd1243dSDimitry Andric static bool isNonZeroAVL(const MachineOperand &MO) {
1374bdd1243dSDimitry Andric   if (MO.isReg())
1375bdd1243dSDimitry Andric     return RISCV::X0 == MO.getReg();
1376bdd1243dSDimitry Andric   assert(MO.isImm());
1377bdd1243dSDimitry Andric   return 0 != MO.getImm();
1378bdd1243dSDimitry Andric }
1379bdd1243dSDimitry Andric 
1380bdd1243dSDimitry Andric // Return true if we can mutate PrevMI to match MI without changing any the
1381bdd1243dSDimitry Andric // fields which would be observed.
138281ad6265SDimitry Andric static bool canMutatePriorConfig(const MachineInstr &PrevMI,
138381ad6265SDimitry Andric                                  const MachineInstr &MI,
138481ad6265SDimitry Andric                                  const DemandedFields &Used) {
1385bdd1243dSDimitry Andric   // If the VL values aren't equal, return false if either a) the former is
1386bdd1243dSDimitry Andric   // demanded, or b) we can't rewrite the former to be the later for
1387bdd1243dSDimitry Andric   // implementation reasons.
1388bdd1243dSDimitry Andric   if (!isVLPreservingConfig(MI)) {
1389bdd1243dSDimitry Andric     if (Used.VLAny)
139081ad6265SDimitry Andric       return false;
139181ad6265SDimitry Andric 
1392bdd1243dSDimitry Andric     // TODO: Requires more care in the mutation...
1393bdd1243dSDimitry Andric     if (isVLPreservingConfig(PrevMI))
1394bdd1243dSDimitry Andric       return false;
1395bdd1243dSDimitry Andric 
1396bdd1243dSDimitry Andric     // We don't bother to handle the equally zero case here as it's largely
1397bdd1243dSDimitry Andric     // uninteresting.
1398bdd1243dSDimitry Andric     if (Used.VLZeroness &&
1399bdd1243dSDimitry Andric         (!isNonZeroAVL(MI.getOperand(1)) ||
1400bdd1243dSDimitry Andric          !isNonZeroAVL(PrevMI.getOperand(1))))
1401bdd1243dSDimitry Andric       return false;
1402bdd1243dSDimitry Andric 
1403bdd1243dSDimitry Andric     // TODO: Track whether the register is defined between
1404bdd1243dSDimitry Andric     // PrevMI and MI.
1405bdd1243dSDimitry Andric     if (MI.getOperand(1).isReg() &&
1406bdd1243dSDimitry Andric         RISCV::X0 != MI.getOperand(1).getReg())
1407bdd1243dSDimitry Andric       return false;
1408bdd1243dSDimitry Andric 
1409bdd1243dSDimitry Andric     // TODO: We need to change the result register to allow this rewrite
1410bdd1243dSDimitry Andric     // without the result forming a vl preserving vsetvli which is not
1411bdd1243dSDimitry Andric     // a correct state merge.
1412bdd1243dSDimitry Andric     if (PrevMI.getOperand(0).getReg() == RISCV::X0 &&
1413bdd1243dSDimitry Andric         MI.getOperand(1).isReg())
1414bdd1243dSDimitry Andric       return false;
1415bdd1243dSDimitry Andric   }
1416bdd1243dSDimitry Andric 
141781ad6265SDimitry Andric   if (!PrevMI.getOperand(2).isImm() || !MI.getOperand(2).isImm())
141881ad6265SDimitry Andric     return false;
141981ad6265SDimitry Andric 
142081ad6265SDimitry Andric   auto PriorVType = PrevMI.getOperand(2).getImm();
142181ad6265SDimitry Andric   auto VType = MI.getOperand(2).getImm();
142281ad6265SDimitry Andric   return areCompatibleVTYPEs(PriorVType, VType, Used);
142381ad6265SDimitry Andric }
142481ad6265SDimitry Andric 
142581ad6265SDimitry Andric void RISCVInsertVSETVLI::doLocalPostpass(MachineBasicBlock &MBB) {
1426bdd1243dSDimitry Andric   MachineInstr *NextMI = nullptr;
1427bdd1243dSDimitry Andric   // We can have arbitrary code in successors, so VL and VTYPE
1428bdd1243dSDimitry Andric   // must be considered demanded.
142981ad6265SDimitry Andric   DemandedFields Used;
1430bdd1243dSDimitry Andric   Used.demandVL();
1431bdd1243dSDimitry Andric   Used.demandVTYPE();
143281ad6265SDimitry Andric   SmallVector<MachineInstr*> ToDelete;
1433bdd1243dSDimitry Andric   for (MachineInstr &MI : make_range(MBB.rbegin(), MBB.rend())) {
1434bdd1243dSDimitry Andric 
1435bdd1243dSDimitry Andric     if (!isVectorConfigInstr(MI)) {
1436*06c3fb27SDimitry Andric       doUnion(Used, getDemanded(MI, MRI));
143781ad6265SDimitry Andric       continue;
143881ad6265SDimitry Andric     }
1439bdd1243dSDimitry Andric 
144081ad6265SDimitry Andric     Register VRegDef = MI.getOperand(0).getReg();
144181ad6265SDimitry Andric     if (VRegDef != RISCV::X0 &&
144281ad6265SDimitry Andric         !(VRegDef.isVirtual() && MRI->use_nodbg_empty(VRegDef)))
1443bdd1243dSDimitry Andric       Used.demandVL();
1444bdd1243dSDimitry Andric 
1445bdd1243dSDimitry Andric     if (NextMI) {
1446bdd1243dSDimitry Andric       if (!Used.usedVL() && !Used.usedVTYPE()) {
1447bdd1243dSDimitry Andric         ToDelete.push_back(&MI);
1448bdd1243dSDimitry Andric         // Leave NextMI unchanged
1449bdd1243dSDimitry Andric         continue;
1450bdd1243dSDimitry Andric       } else if (canMutatePriorConfig(MI, *NextMI, Used)) {
1451bdd1243dSDimitry Andric         if (!isVLPreservingConfig(*NextMI)) {
1452bdd1243dSDimitry Andric           if (NextMI->getOperand(1).isImm())
1453bdd1243dSDimitry Andric             MI.getOperand(1).ChangeToImmediate(NextMI->getOperand(1).getImm());
1454bdd1243dSDimitry Andric           else
1455bdd1243dSDimitry Andric             MI.getOperand(1).ChangeToRegister(NextMI->getOperand(1).getReg(), false);
1456bdd1243dSDimitry Andric           MI.setDesc(NextMI->getDesc());
1457bdd1243dSDimitry Andric         }
1458bdd1243dSDimitry Andric         MI.getOperand(2).setImm(NextMI->getOperand(2).getImm());
1459*06c3fb27SDimitry Andric         // Don't delete a vsetvli if its result might be used.
1460*06c3fb27SDimitry Andric         Register NextVRefDef = NextMI->getOperand(0).getReg();
1461*06c3fb27SDimitry Andric         if (NextVRefDef == RISCV::X0 ||
1462*06c3fb27SDimitry Andric             (NextVRefDef.isVirtual() && MRI->use_nodbg_empty(NextVRefDef)))
1463bdd1243dSDimitry Andric           ToDelete.push_back(NextMI);
1464bdd1243dSDimitry Andric         // fallthrough
1465bdd1243dSDimitry Andric       }
1466bdd1243dSDimitry Andric     }
1467bdd1243dSDimitry Andric     NextMI = &MI;
1468*06c3fb27SDimitry Andric     Used = getDemanded(MI, MRI);
146981ad6265SDimitry Andric   }
147081ad6265SDimitry Andric 
147181ad6265SDimitry Andric   for (auto *MI : ToDelete)
147281ad6265SDimitry Andric     MI->eraseFromParent();
147381ad6265SDimitry Andric }
147481ad6265SDimitry Andric 
147581ad6265SDimitry Andric void RISCVInsertVSETVLI::insertReadVL(MachineBasicBlock &MBB) {
147681ad6265SDimitry Andric   for (auto I = MBB.begin(), E = MBB.end(); I != E;) {
147781ad6265SDimitry Andric     MachineInstr &MI = *I++;
147881ad6265SDimitry Andric     if (RISCV::isFaultFirstLoad(MI)) {
147981ad6265SDimitry Andric       Register VLOutput = MI.getOperand(1).getReg();
148081ad6265SDimitry Andric       if (!MRI->use_nodbg_empty(VLOutput))
148181ad6265SDimitry Andric         BuildMI(MBB, I, MI.getDebugLoc(), TII->get(RISCV::PseudoReadVL),
148281ad6265SDimitry Andric                 VLOutput);
148381ad6265SDimitry Andric       // We don't use the vl output of the VLEFF/VLSEGFF anymore.
148481ad6265SDimitry Andric       MI.getOperand(1).setReg(RISCV::X0);
148581ad6265SDimitry Andric     }
1486fe6060f1SDimitry Andric   }
1487fe6060f1SDimitry Andric }
1488fe6060f1SDimitry Andric 
1489fe6060f1SDimitry Andric bool RISCVInsertVSETVLI::runOnMachineFunction(MachineFunction &MF) {
1490fe6060f1SDimitry Andric   // Skip if the vector extension is not enabled.
1491fe6060f1SDimitry Andric   const RISCVSubtarget &ST = MF.getSubtarget<RISCVSubtarget>();
1492349cc55cSDimitry Andric   if (!ST.hasVInstructions())
1493fe6060f1SDimitry Andric     return false;
1494fe6060f1SDimitry Andric 
149581ad6265SDimitry Andric   LLVM_DEBUG(dbgs() << "Entering InsertVSETVLI for " << MF.getName() << "\n");
149681ad6265SDimitry Andric 
1497fe6060f1SDimitry Andric   TII = ST.getInstrInfo();
1498fe6060f1SDimitry Andric   MRI = &MF.getRegInfo();
1499fe6060f1SDimitry Andric 
1500fe6060f1SDimitry Andric   assert(BlockInfo.empty() && "Expect empty block infos");
1501fe6060f1SDimitry Andric   BlockInfo.resize(MF.getNumBlockIDs());
1502fe6060f1SDimitry Andric 
1503fe6060f1SDimitry Andric   bool HaveVectorOp = false;
1504fe6060f1SDimitry Andric 
1505fe6060f1SDimitry Andric   // Phase 1 - determine how VL/VTYPE are affected by the each block.
150681ad6265SDimitry Andric   for (const MachineBasicBlock &MBB : MF) {
1507fe6060f1SDimitry Andric     HaveVectorOp |= computeVLVTYPEChanges(MBB);
150881ad6265SDimitry Andric     // Initial exit state is whatever change we found in the block.
150981ad6265SDimitry Andric     BlockData &BBInfo = BlockInfo[MBB.getNumber()];
151081ad6265SDimitry Andric     BBInfo.Exit = BBInfo.Change;
151181ad6265SDimitry Andric     LLVM_DEBUG(dbgs() << "Initial exit state of " << printMBBReference(MBB)
151281ad6265SDimitry Andric                       << " is " << BBInfo.Exit << "\n");
151381ad6265SDimitry Andric 
151481ad6265SDimitry Andric   }
1515fe6060f1SDimitry Andric 
1516fe6060f1SDimitry Andric   // If we didn't find any instructions that need VSETVLI, we're done.
151781ad6265SDimitry Andric   if (!HaveVectorOp) {
151881ad6265SDimitry Andric     BlockInfo.clear();
151981ad6265SDimitry Andric     return false;
152081ad6265SDimitry Andric   }
152181ad6265SDimitry Andric 
1522fe6060f1SDimitry Andric   // Phase 2 - determine the exit VL/VTYPE from each block. We add all
1523fe6060f1SDimitry Andric   // blocks to the list here, but will also add any that need to be revisited
1524fe6060f1SDimitry Andric   // during Phase 2 processing.
1525fe6060f1SDimitry Andric   for (const MachineBasicBlock &MBB : MF) {
1526fe6060f1SDimitry Andric     WorkList.push(&MBB);
1527fe6060f1SDimitry Andric     BlockInfo[MBB.getNumber()].InQueue = true;
1528fe6060f1SDimitry Andric   }
1529fe6060f1SDimitry Andric   while (!WorkList.empty()) {
1530fe6060f1SDimitry Andric     const MachineBasicBlock &MBB = *WorkList.front();
1531fe6060f1SDimitry Andric     WorkList.pop();
1532fe6060f1SDimitry Andric     computeIncomingVLVTYPE(MBB);
1533fe6060f1SDimitry Andric   }
1534fe6060f1SDimitry Andric 
153581ad6265SDimitry Andric   // Perform partial redundancy elimination of vsetvli transitions.
153681ad6265SDimitry Andric   for (MachineBasicBlock &MBB : MF)
153781ad6265SDimitry Andric     doPRE(MBB);
153881ad6265SDimitry Andric 
1539fe6060f1SDimitry Andric   // Phase 3 - add any vsetvli instructions needed in the block. Use the
1540fe6060f1SDimitry Andric   // Phase 2 information to avoid adding vsetvlis before the first vector
1541fe6060f1SDimitry Andric   // instruction in the block if the VL/VTYPE is satisfied by its
1542fe6060f1SDimitry Andric   // predecessors.
1543fe6060f1SDimitry Andric   for (MachineBasicBlock &MBB : MF)
1544fe6060f1SDimitry Andric     emitVSETVLIs(MBB);
154581ad6265SDimitry Andric 
154681ad6265SDimitry Andric   // Now that all vsetvlis are explicit, go through and do block local
154781ad6265SDimitry Andric   // DSE and peephole based demanded fields based transforms.  Note that
154881ad6265SDimitry Andric   // this *must* be done outside the main dataflow so long as we allow
154981ad6265SDimitry Andric   // any cross block analysis within the dataflow.  We can't have both
155081ad6265SDimitry Andric   // demanded fields based mutation and non-local analysis in the
155181ad6265SDimitry Andric   // dataflow at the same time without introducing inconsistencies.
155281ad6265SDimitry Andric   for (MachineBasicBlock &MBB : MF)
155381ad6265SDimitry Andric     doLocalPostpass(MBB);
155481ad6265SDimitry Andric 
155581ad6265SDimitry Andric   // Once we're fully done rewriting all the instructions, do a final pass
155681ad6265SDimitry Andric   // through to check for VSETVLIs which write to an unused destination.
155781ad6265SDimitry Andric   // For the non X0, X0 variant, we can replace the destination register
155881ad6265SDimitry Andric   // with X0 to reduce register pressure.  This is really a generic
155981ad6265SDimitry Andric   // optimization which can be applied to any dead def (TODO: generalize).
156081ad6265SDimitry Andric   for (MachineBasicBlock &MBB : MF) {
156181ad6265SDimitry Andric     for (MachineInstr &MI : MBB) {
156281ad6265SDimitry Andric       if (MI.getOpcode() == RISCV::PseudoVSETVLI ||
156381ad6265SDimitry Andric           MI.getOpcode() == RISCV::PseudoVSETIVLI) {
156481ad6265SDimitry Andric         Register VRegDef = MI.getOperand(0).getReg();
156581ad6265SDimitry Andric         if (VRegDef != RISCV::X0 && MRI->use_nodbg_empty(VRegDef))
156681ad6265SDimitry Andric           MI.getOperand(0).setReg(RISCV::X0);
156781ad6265SDimitry Andric       }
156881ad6265SDimitry Andric     }
1569fe6060f1SDimitry Andric   }
1570fe6060f1SDimitry Andric 
157181ad6265SDimitry Andric   // Insert PseudoReadVL after VLEFF/VLSEGFF and replace it with the vl output
157281ad6265SDimitry Andric   // of VLEFF/VLSEGFF.
157381ad6265SDimitry Andric   for (MachineBasicBlock &MBB : MF)
157481ad6265SDimitry Andric     insertReadVL(MBB);
1575fe6060f1SDimitry Andric 
157681ad6265SDimitry Andric   BlockInfo.clear();
1577fe6060f1SDimitry Andric   return HaveVectorOp;
1578fe6060f1SDimitry Andric }
1579fe6060f1SDimitry Andric 
1580fe6060f1SDimitry Andric /// Returns an instance of the Insert VSETVLI pass.
1581fe6060f1SDimitry Andric FunctionPass *llvm::createRISCVInsertVSETVLIPass() {
1582fe6060f1SDimitry Andric   return new RISCVInsertVSETVLI();
1583fe6060f1SDimitry Andric }
1584