xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp (revision d56accc7c3dcc897489b6a07834763a03b9f3d68)
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
10fe6060f1SDimitry Andric // needed.
11fe6060f1SDimitry Andric //
12fe6060f1SDimitry Andric // This pass consists of 3 phases:
13fe6060f1SDimitry Andric //
14fe6060f1SDimitry Andric // Phase 1 collects how each basic block affects VL/VTYPE.
15fe6060f1SDimitry Andric //
16fe6060f1SDimitry Andric // Phase 2 uses the information from phase 1 to do a data flow analysis to
17fe6060f1SDimitry Andric // propagate the VL/VTYPE changes through the function. This gives us the
18fe6060f1SDimitry Andric // VL/VTYPE at the start of each basic block.
19fe6060f1SDimitry Andric //
20fe6060f1SDimitry Andric // Phase 3 inserts VSETVLI instructions in each basic block. Information from
21fe6060f1SDimitry Andric // phase 2 is used to prevent inserting a VSETVLI before the first vector
22fe6060f1SDimitry Andric // instruction in the block if possible.
23fe6060f1SDimitry Andric //
24fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
25fe6060f1SDimitry Andric 
26fe6060f1SDimitry Andric #include "RISCV.h"
27fe6060f1SDimitry Andric #include "RISCVSubtarget.h"
28fe6060f1SDimitry Andric #include "llvm/CodeGen/LiveIntervals.h"
29fe6060f1SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
30fe6060f1SDimitry Andric #include <queue>
31fe6060f1SDimitry Andric using namespace llvm;
32fe6060f1SDimitry Andric 
33fe6060f1SDimitry Andric #define DEBUG_TYPE "riscv-insert-vsetvli"
34fe6060f1SDimitry Andric #define RISCV_INSERT_VSETVLI_NAME "RISCV Insert VSETVLI pass"
35fe6060f1SDimitry Andric 
36fe6060f1SDimitry Andric static cl::opt<bool> DisableInsertVSETVLPHIOpt(
37fe6060f1SDimitry Andric     "riscv-disable-insert-vsetvl-phi-opt", cl::init(false), cl::Hidden,
38fe6060f1SDimitry Andric     cl::desc("Disable looking through phis when inserting vsetvlis."));
39fe6060f1SDimitry Andric 
40fe6060f1SDimitry Andric namespace {
41fe6060f1SDimitry Andric 
42fe6060f1SDimitry Andric class VSETVLIInfo {
43fe6060f1SDimitry Andric   union {
44fe6060f1SDimitry Andric     Register AVLReg;
45fe6060f1SDimitry Andric     unsigned AVLImm;
46fe6060f1SDimitry Andric   };
47fe6060f1SDimitry Andric 
48fe6060f1SDimitry Andric   enum : uint8_t {
49fe6060f1SDimitry Andric     Uninitialized,
50fe6060f1SDimitry Andric     AVLIsReg,
51fe6060f1SDimitry Andric     AVLIsImm,
52fe6060f1SDimitry Andric     Unknown,
53fe6060f1SDimitry Andric   } State = Uninitialized;
54fe6060f1SDimitry Andric 
55fe6060f1SDimitry Andric   // Fields from VTYPE.
56fe6060f1SDimitry Andric   RISCVII::VLMUL VLMul = RISCVII::LMUL_1;
57fe6060f1SDimitry Andric   uint8_t SEW = 0;
58fe6060f1SDimitry Andric   uint8_t TailAgnostic : 1;
59fe6060f1SDimitry Andric   uint8_t MaskAgnostic : 1;
60fe6060f1SDimitry Andric   uint8_t MaskRegOp : 1;
61349cc55cSDimitry Andric   uint8_t StoreOp : 1;
6204eeddc0SDimitry Andric   uint8_t ScalarMovOp : 1;
63fe6060f1SDimitry Andric   uint8_t SEWLMULRatioOnly : 1;
64fe6060f1SDimitry Andric 
65fe6060f1SDimitry Andric public:
66fe6060f1SDimitry Andric   VSETVLIInfo()
67fe6060f1SDimitry Andric       : AVLImm(0), TailAgnostic(false), MaskAgnostic(false), MaskRegOp(false),
6804eeddc0SDimitry Andric         StoreOp(false), ScalarMovOp(false), SEWLMULRatioOnly(false) {}
69fe6060f1SDimitry Andric 
70fe6060f1SDimitry Andric   static VSETVLIInfo getUnknown() {
71fe6060f1SDimitry Andric     VSETVLIInfo Info;
72fe6060f1SDimitry Andric     Info.setUnknown();
73fe6060f1SDimitry Andric     return Info;
74fe6060f1SDimitry Andric   }
75fe6060f1SDimitry Andric 
76fe6060f1SDimitry Andric   bool isValid() const { return State != Uninitialized; }
77fe6060f1SDimitry Andric   void setUnknown() { State = Unknown; }
78fe6060f1SDimitry Andric   bool isUnknown() const { return State == Unknown; }
79fe6060f1SDimitry Andric 
80fe6060f1SDimitry Andric   void setAVLReg(Register Reg) {
81fe6060f1SDimitry Andric     AVLReg = Reg;
82fe6060f1SDimitry Andric     State = AVLIsReg;
83fe6060f1SDimitry Andric   }
84fe6060f1SDimitry Andric 
85fe6060f1SDimitry Andric   void setAVLImm(unsigned Imm) {
86fe6060f1SDimitry Andric     AVLImm = Imm;
87fe6060f1SDimitry Andric     State = AVLIsImm;
88fe6060f1SDimitry Andric   }
89fe6060f1SDimitry Andric 
90fe6060f1SDimitry Andric   bool hasAVLImm() const { return State == AVLIsImm; }
91fe6060f1SDimitry Andric   bool hasAVLReg() const { return State == AVLIsReg; }
92fe6060f1SDimitry Andric   Register getAVLReg() const {
93fe6060f1SDimitry Andric     assert(hasAVLReg());
94fe6060f1SDimitry Andric     return AVLReg;
95fe6060f1SDimitry Andric   }
96fe6060f1SDimitry Andric   unsigned getAVLImm() const {
97fe6060f1SDimitry Andric     assert(hasAVLImm());
98fe6060f1SDimitry Andric     return AVLImm;
99fe6060f1SDimitry Andric   }
10004eeddc0SDimitry Andric   bool hasZeroAVL() const {
10104eeddc0SDimitry Andric     if (hasAVLImm())
10204eeddc0SDimitry Andric       return getAVLImm() == 0;
10304eeddc0SDimitry Andric     return false;
10404eeddc0SDimitry Andric   }
10504eeddc0SDimitry Andric   bool hasNonZeroAVL() const {
10604eeddc0SDimitry Andric     if (hasAVLImm())
10704eeddc0SDimitry Andric       return getAVLImm() > 0;
10804eeddc0SDimitry Andric     if (hasAVLReg())
10904eeddc0SDimitry Andric       return getAVLReg() == RISCV::X0;
11004eeddc0SDimitry Andric     return false;
11104eeddc0SDimitry Andric   }
112fe6060f1SDimitry Andric 
113fe6060f1SDimitry Andric   bool hasSameAVL(const VSETVLIInfo &Other) const {
114fe6060f1SDimitry Andric     assert(isValid() && Other.isValid() &&
115fe6060f1SDimitry Andric            "Can't compare invalid VSETVLIInfos");
116fe6060f1SDimitry Andric     assert(!isUnknown() && !Other.isUnknown() &&
117fe6060f1SDimitry Andric            "Can't compare AVL in unknown state");
118fe6060f1SDimitry Andric     if (hasAVLReg() && Other.hasAVLReg())
119fe6060f1SDimitry Andric       return getAVLReg() == Other.getAVLReg();
120fe6060f1SDimitry Andric 
121fe6060f1SDimitry Andric     if (hasAVLImm() && Other.hasAVLImm())
122fe6060f1SDimitry Andric       return getAVLImm() == Other.getAVLImm();
123fe6060f1SDimitry Andric 
124fe6060f1SDimitry Andric     return false;
125fe6060f1SDimitry Andric   }
126fe6060f1SDimitry Andric 
127fe6060f1SDimitry Andric   void setVTYPE(unsigned VType) {
128fe6060f1SDimitry Andric     assert(isValid() && !isUnknown() &&
129fe6060f1SDimitry Andric            "Can't set VTYPE for uninitialized or unknown");
130fe6060f1SDimitry Andric     VLMul = RISCVVType::getVLMUL(VType);
131fe6060f1SDimitry Andric     SEW = RISCVVType::getSEW(VType);
132fe6060f1SDimitry Andric     TailAgnostic = RISCVVType::isTailAgnostic(VType);
133fe6060f1SDimitry Andric     MaskAgnostic = RISCVVType::isMaskAgnostic(VType);
134fe6060f1SDimitry Andric   }
135349cc55cSDimitry Andric   void setVTYPE(RISCVII::VLMUL L, unsigned S, bool TA, bool MA, bool MRO,
13604eeddc0SDimitry Andric                 bool IsStore, bool IsScalarMovOp) {
137fe6060f1SDimitry Andric     assert(isValid() && !isUnknown() &&
138fe6060f1SDimitry Andric            "Can't set VTYPE for uninitialized or unknown");
139fe6060f1SDimitry Andric     VLMul = L;
140fe6060f1SDimitry Andric     SEW = S;
141fe6060f1SDimitry Andric     TailAgnostic = TA;
142fe6060f1SDimitry Andric     MaskAgnostic = MA;
143fe6060f1SDimitry Andric     MaskRegOp = MRO;
144349cc55cSDimitry Andric     StoreOp = IsStore;
14504eeddc0SDimitry Andric     ScalarMovOp = IsScalarMovOp;
146fe6060f1SDimitry Andric   }
147fe6060f1SDimitry Andric 
148fe6060f1SDimitry Andric   unsigned encodeVTYPE() const {
149fe6060f1SDimitry Andric     assert(isValid() && !isUnknown() && !SEWLMULRatioOnly &&
150fe6060f1SDimitry Andric            "Can't encode VTYPE for uninitialized or unknown");
151fe6060f1SDimitry Andric     return RISCVVType::encodeVTYPE(VLMul, SEW, TailAgnostic, MaskAgnostic);
152fe6060f1SDimitry Andric   }
153fe6060f1SDimitry Andric 
154fe6060f1SDimitry Andric   bool hasSEWLMULRatioOnly() const { return SEWLMULRatioOnly; }
155fe6060f1SDimitry Andric 
15604eeddc0SDimitry Andric   bool hasSameSEW(const VSETVLIInfo &Other) const {
15704eeddc0SDimitry Andric     assert(isValid() && Other.isValid() &&
15804eeddc0SDimitry Andric            "Can't compare invalid VSETVLIInfos");
15904eeddc0SDimitry Andric     assert(!isUnknown() && !Other.isUnknown() &&
16004eeddc0SDimitry Andric            "Can't compare VTYPE in unknown state");
16104eeddc0SDimitry Andric     assert(!SEWLMULRatioOnly && !Other.SEWLMULRatioOnly &&
16204eeddc0SDimitry Andric            "Can't compare when only LMUL/SEW ratio is valid.");
16304eeddc0SDimitry Andric     return SEW == Other.SEW;
16404eeddc0SDimitry Andric   }
16504eeddc0SDimitry Andric 
166fe6060f1SDimitry Andric   bool hasSameVTYPE(const VSETVLIInfo &Other) const {
167fe6060f1SDimitry Andric     assert(isValid() && Other.isValid() &&
168fe6060f1SDimitry Andric            "Can't compare invalid VSETVLIInfos");
169fe6060f1SDimitry Andric     assert(!isUnknown() && !Other.isUnknown() &&
170fe6060f1SDimitry Andric            "Can't compare VTYPE in unknown state");
171fe6060f1SDimitry Andric     assert(!SEWLMULRatioOnly && !Other.SEWLMULRatioOnly &&
172fe6060f1SDimitry Andric            "Can't compare when only LMUL/SEW ratio is valid.");
173fe6060f1SDimitry Andric     return std::tie(VLMul, SEW, TailAgnostic, MaskAgnostic) ==
174fe6060f1SDimitry Andric            std::tie(Other.VLMul, Other.SEW, Other.TailAgnostic,
175fe6060f1SDimitry Andric                     Other.MaskAgnostic);
176fe6060f1SDimitry Andric   }
177fe6060f1SDimitry Andric 
178349cc55cSDimitry Andric   static unsigned getSEWLMULRatio(unsigned SEW, RISCVII::VLMUL VLMul) {
179fe6060f1SDimitry Andric     unsigned LMul;
180fe6060f1SDimitry Andric     bool Fractional;
181fe6060f1SDimitry Andric     std::tie(LMul, Fractional) = RISCVVType::decodeVLMUL(VLMul);
182fe6060f1SDimitry Andric 
183fe6060f1SDimitry Andric     // Convert LMul to a fixed point value with 3 fractional bits.
184fe6060f1SDimitry Andric     LMul = Fractional ? (8 / LMul) : (LMul * 8);
185fe6060f1SDimitry Andric 
186fe6060f1SDimitry Andric     assert(SEW >= 8 && "Unexpected SEW value");
187fe6060f1SDimitry Andric     return (SEW * 8) / LMul;
188fe6060f1SDimitry Andric   }
189fe6060f1SDimitry Andric 
190349cc55cSDimitry Andric   unsigned getSEWLMULRatio() const {
191349cc55cSDimitry Andric     assert(isValid() && !isUnknown() &&
192349cc55cSDimitry Andric            "Can't use VTYPE for uninitialized or unknown");
193349cc55cSDimitry Andric     return getSEWLMULRatio(SEW, VLMul);
194349cc55cSDimitry Andric   }
195349cc55cSDimitry Andric 
196fe6060f1SDimitry Andric   // Check if the VTYPE for these two VSETVLIInfos produce the same VLMAX.
197fe6060f1SDimitry Andric   bool hasSameVLMAX(const VSETVLIInfo &Other) const {
198fe6060f1SDimitry Andric     assert(isValid() && Other.isValid() &&
199fe6060f1SDimitry Andric            "Can't compare invalid VSETVLIInfos");
200fe6060f1SDimitry Andric     assert(!isUnknown() && !Other.isUnknown() &&
201fe6060f1SDimitry Andric            "Can't compare VTYPE in unknown state");
202fe6060f1SDimitry Andric     return getSEWLMULRatio() == Other.getSEWLMULRatio();
203fe6060f1SDimitry Andric   }
204fe6060f1SDimitry Andric 
20504eeddc0SDimitry Andric   bool hasSamePolicy(const VSETVLIInfo &Other) const {
20604eeddc0SDimitry Andric     assert(isValid() && Other.isValid() &&
20704eeddc0SDimitry Andric            "Can't compare invalid VSETVLIInfos");
20804eeddc0SDimitry Andric     assert(!isUnknown() && !Other.isUnknown() &&
20904eeddc0SDimitry Andric            "Can't compare VTYPE in unknown state");
21004eeddc0SDimitry Andric     return TailAgnostic == Other.TailAgnostic &&
21104eeddc0SDimitry Andric            MaskAgnostic == Other.MaskAgnostic;
21204eeddc0SDimitry Andric   }
21304eeddc0SDimitry Andric 
214349cc55cSDimitry Andric   bool hasCompatibleVTYPE(const VSETVLIInfo &InstrInfo, bool Strict) const {
215349cc55cSDimitry Andric     // Simple case, see if full VTYPE matches.
216349cc55cSDimitry Andric     if (hasSameVTYPE(InstrInfo))
217349cc55cSDimitry Andric       return true;
218349cc55cSDimitry Andric 
219349cc55cSDimitry Andric     if (Strict)
220349cc55cSDimitry Andric       return false;
221349cc55cSDimitry Andric 
222349cc55cSDimitry Andric     // If this is a mask reg operation, it only cares about VLMAX.
223349cc55cSDimitry Andric     // FIXME: Mask reg operations are probably ok if "this" VLMAX is larger
224349cc55cSDimitry Andric     // than "InstrInfo".
225349cc55cSDimitry Andric     // FIXME: The policy bits can probably be ignored for mask reg operations.
226349cc55cSDimitry Andric     if (InstrInfo.MaskRegOp && hasSameVLMAX(InstrInfo) &&
227349cc55cSDimitry Andric         TailAgnostic == InstrInfo.TailAgnostic &&
228349cc55cSDimitry Andric         MaskAgnostic == InstrInfo.MaskAgnostic)
229349cc55cSDimitry Andric       return true;
230349cc55cSDimitry Andric 
231349cc55cSDimitry Andric     return false;
232349cc55cSDimitry Andric   }
233349cc55cSDimitry Andric 
234fe6060f1SDimitry Andric   // Determine whether the vector instructions requirements represented by
235fe6060f1SDimitry Andric   // InstrInfo are compatible with the previous vsetvli instruction represented
236fe6060f1SDimitry Andric   // by this.
237349cc55cSDimitry Andric   bool isCompatible(const VSETVLIInfo &InstrInfo, bool Strict) const {
238fe6060f1SDimitry Andric     assert(isValid() && InstrInfo.isValid() &&
239fe6060f1SDimitry Andric            "Can't compare invalid VSETVLIInfos");
240fe6060f1SDimitry Andric     assert(!InstrInfo.SEWLMULRatioOnly &&
241fe6060f1SDimitry Andric            "Expected a valid VTYPE for instruction!");
242fe6060f1SDimitry Andric     // Nothing is compatible with Unknown.
243fe6060f1SDimitry Andric     if (isUnknown() || InstrInfo.isUnknown())
244fe6060f1SDimitry Andric       return false;
245fe6060f1SDimitry Andric 
246fe6060f1SDimitry Andric     // If only our VLMAX ratio is valid, then this isn't compatible.
247fe6060f1SDimitry Andric     if (SEWLMULRatioOnly)
248fe6060f1SDimitry Andric       return false;
249fe6060f1SDimitry Andric 
250fe6060f1SDimitry Andric     // If the instruction doesn't need an AVLReg and the SEW matches, consider
251fe6060f1SDimitry Andric     // it compatible.
252349cc55cSDimitry Andric     if (!Strict && InstrInfo.hasAVLReg() &&
253349cc55cSDimitry Andric         InstrInfo.AVLReg == RISCV::NoRegister) {
254fe6060f1SDimitry Andric       if (SEW == InstrInfo.SEW)
255fe6060f1SDimitry Andric         return true;
256fe6060f1SDimitry Andric     }
257fe6060f1SDimitry Andric 
25804eeddc0SDimitry Andric     // For vmv.s.x and vfmv.s.f, there is only two behaviors, VL = 0 and VL > 0.
25904eeddc0SDimitry Andric     // So it's compatible when we could make sure that both VL be the same
26004eeddc0SDimitry Andric     // situation.
26104eeddc0SDimitry Andric     if (!Strict && InstrInfo.ScalarMovOp && InstrInfo.hasAVLImm() &&
26204eeddc0SDimitry Andric         ((hasNonZeroAVL() && InstrInfo.hasNonZeroAVL()) ||
26304eeddc0SDimitry Andric          (hasZeroAVL() && InstrInfo.hasZeroAVL())) &&
26404eeddc0SDimitry Andric         hasSameSEW(InstrInfo) && hasSamePolicy(InstrInfo))
26504eeddc0SDimitry Andric       return true;
26604eeddc0SDimitry Andric 
267349cc55cSDimitry Andric     // The AVL must match.
268349cc55cSDimitry Andric     if (!hasSameAVL(InstrInfo))
269fe6060f1SDimitry Andric       return false;
270fe6060f1SDimitry Andric 
271349cc55cSDimitry Andric     if (hasCompatibleVTYPE(InstrInfo, Strict))
272349cc55cSDimitry Andric       return true;
273349cc55cSDimitry Andric 
274349cc55cSDimitry Andric     // Strict matches must ensure a full VTYPE match.
275349cc55cSDimitry Andric     if (Strict)
276349cc55cSDimitry Andric       return false;
277349cc55cSDimitry Andric 
278349cc55cSDimitry Andric     // Store instructions don't use the policy fields.
279349cc55cSDimitry Andric     // TODO: Move into hasCompatibleVTYPE?
280349cc55cSDimitry Andric     if (InstrInfo.StoreOp && VLMul == InstrInfo.VLMul && SEW == InstrInfo.SEW)
281349cc55cSDimitry Andric       return true;
282349cc55cSDimitry Andric 
283349cc55cSDimitry Andric     // Anything else is not compatible.
284349cc55cSDimitry Andric     return false;
285349cc55cSDimitry Andric   }
286349cc55cSDimitry Andric 
287349cc55cSDimitry Andric   bool isCompatibleWithLoadStoreEEW(unsigned EEW,
288349cc55cSDimitry Andric                                     const VSETVLIInfo &InstrInfo) const {
289349cc55cSDimitry Andric     assert(isValid() && InstrInfo.isValid() &&
290349cc55cSDimitry Andric            "Can't compare invalid VSETVLIInfos");
291349cc55cSDimitry Andric     assert(!InstrInfo.SEWLMULRatioOnly &&
292349cc55cSDimitry Andric            "Expected a valid VTYPE for instruction!");
293349cc55cSDimitry Andric     assert(EEW == InstrInfo.SEW && "Mismatched EEW/SEW for store");
294349cc55cSDimitry Andric 
295349cc55cSDimitry Andric     if (isUnknown() || hasSEWLMULRatioOnly())
296349cc55cSDimitry Andric       return false;
297349cc55cSDimitry Andric 
298349cc55cSDimitry Andric     if (!hasSameAVL(InstrInfo))
299349cc55cSDimitry Andric       return false;
300349cc55cSDimitry Andric 
301349cc55cSDimitry Andric     // Stores can ignore the tail and mask policies.
302349cc55cSDimitry Andric     if (!InstrInfo.StoreOp && (TailAgnostic != InstrInfo.TailAgnostic ||
303349cc55cSDimitry Andric                                MaskAgnostic != InstrInfo.MaskAgnostic))
304349cc55cSDimitry Andric       return false;
305349cc55cSDimitry Andric 
306349cc55cSDimitry Andric     return getSEWLMULRatio() == getSEWLMULRatio(EEW, InstrInfo.VLMul);
307fe6060f1SDimitry Andric   }
308fe6060f1SDimitry Andric 
309fe6060f1SDimitry Andric   bool operator==(const VSETVLIInfo &Other) const {
310fe6060f1SDimitry Andric     // Uninitialized is only equal to another Uninitialized.
311fe6060f1SDimitry Andric     if (!isValid())
312fe6060f1SDimitry Andric       return !Other.isValid();
313fe6060f1SDimitry Andric     if (!Other.isValid())
314fe6060f1SDimitry Andric       return !isValid();
315fe6060f1SDimitry Andric 
316fe6060f1SDimitry Andric     // Unknown is only equal to another Unknown.
317fe6060f1SDimitry Andric     if (isUnknown())
318fe6060f1SDimitry Andric       return Other.isUnknown();
319fe6060f1SDimitry Andric     if (Other.isUnknown())
320fe6060f1SDimitry Andric       return isUnknown();
321fe6060f1SDimitry Andric 
322fe6060f1SDimitry Andric     if (!hasSameAVL(Other))
323fe6060f1SDimitry Andric       return false;
324fe6060f1SDimitry Andric 
325fe6060f1SDimitry Andric     // If only the VLMAX is valid, check that it is the same.
326fe6060f1SDimitry Andric     if (SEWLMULRatioOnly && Other.SEWLMULRatioOnly)
327fe6060f1SDimitry Andric       return hasSameVLMAX(Other);
328fe6060f1SDimitry Andric 
329fe6060f1SDimitry Andric     // If the full VTYPE is valid, check that it is the same.
330fe6060f1SDimitry Andric     if (!SEWLMULRatioOnly && !Other.SEWLMULRatioOnly)
331fe6060f1SDimitry Andric       return hasSameVTYPE(Other);
332fe6060f1SDimitry Andric 
333fe6060f1SDimitry Andric     // If the SEWLMULRatioOnly bits are different, then they aren't equal.
334fe6060f1SDimitry Andric     return false;
335fe6060f1SDimitry Andric   }
336fe6060f1SDimitry Andric 
337*d56accc7SDimitry Andric   bool operator!=(const VSETVLIInfo &Other) const {
338*d56accc7SDimitry Andric     return !(*this == Other);
339*d56accc7SDimitry Andric   }
340*d56accc7SDimitry Andric 
341fe6060f1SDimitry Andric   // Calculate the VSETVLIInfo visible to a block assuming this and Other are
342fe6060f1SDimitry Andric   // both predecessors.
343fe6060f1SDimitry Andric   VSETVLIInfo intersect(const VSETVLIInfo &Other) const {
344fe6060f1SDimitry Andric     // If the new value isn't valid, ignore it.
345fe6060f1SDimitry Andric     if (!Other.isValid())
346fe6060f1SDimitry Andric       return *this;
347fe6060f1SDimitry Andric 
348fe6060f1SDimitry Andric     // If this value isn't valid, this must be the first predecessor, use it.
349fe6060f1SDimitry Andric     if (!isValid())
350fe6060f1SDimitry Andric       return Other;
351fe6060f1SDimitry Andric 
352fe6060f1SDimitry Andric     // If either is unknown, the result is unknown.
353fe6060f1SDimitry Andric     if (isUnknown() || Other.isUnknown())
354fe6060f1SDimitry Andric       return VSETVLIInfo::getUnknown();
355fe6060f1SDimitry Andric 
356fe6060f1SDimitry Andric     // If we have an exact, match return this.
357fe6060f1SDimitry Andric     if (*this == Other)
358fe6060f1SDimitry Andric       return *this;
359fe6060f1SDimitry Andric 
360fe6060f1SDimitry Andric     // Not an exact match, but maybe the AVL and VLMAX are the same. If so,
361fe6060f1SDimitry Andric     // return an SEW/LMUL ratio only value.
362fe6060f1SDimitry Andric     if (hasSameAVL(Other) && hasSameVLMAX(Other)) {
363fe6060f1SDimitry Andric       VSETVLIInfo MergeInfo = *this;
364fe6060f1SDimitry Andric       MergeInfo.SEWLMULRatioOnly = true;
365fe6060f1SDimitry Andric       return MergeInfo;
366fe6060f1SDimitry Andric     }
367fe6060f1SDimitry Andric 
368fe6060f1SDimitry Andric     // Otherwise the result is unknown.
369fe6060f1SDimitry Andric     return VSETVLIInfo::getUnknown();
370fe6060f1SDimitry Andric   }
371fe6060f1SDimitry Andric 
372fe6060f1SDimitry Andric   // Calculate the VSETVLIInfo visible at the end of the block assuming this
373fe6060f1SDimitry Andric   // is the predecessor value, and Other is change for this block.
374fe6060f1SDimitry Andric   VSETVLIInfo merge(const VSETVLIInfo &Other) const {
375fe6060f1SDimitry Andric     assert(isValid() && "Can only merge with a valid VSETVLInfo");
376fe6060f1SDimitry Andric 
377fe6060f1SDimitry Andric     // Nothing changed from the predecessor, keep it.
378fe6060f1SDimitry Andric     if (!Other.isValid())
379fe6060f1SDimitry Andric       return *this;
380fe6060f1SDimitry Andric 
381fe6060f1SDimitry Andric     // If the change is compatible with the input, we won't create a VSETVLI
382fe6060f1SDimitry Andric     // and should keep the predecessor.
383349cc55cSDimitry Andric     if (isCompatible(Other, /*Strict*/ true))
384fe6060f1SDimitry Andric       return *this;
385fe6060f1SDimitry Andric 
386fe6060f1SDimitry Andric     // Otherwise just use whatever is in this block.
387fe6060f1SDimitry Andric     return Other;
388fe6060f1SDimitry Andric   }
389fe6060f1SDimitry Andric };
390fe6060f1SDimitry Andric 
391fe6060f1SDimitry Andric struct BlockData {
392fe6060f1SDimitry Andric   // The VSETVLIInfo that represents the net changes to the VL/VTYPE registers
393fe6060f1SDimitry Andric   // made by this block. Calculated in Phase 1.
394fe6060f1SDimitry Andric   VSETVLIInfo Change;
395fe6060f1SDimitry Andric 
396fe6060f1SDimitry Andric   // The VSETVLIInfo that represents the VL/VTYPE settings on exit from this
397fe6060f1SDimitry Andric   // block. Calculated in Phase 2.
398fe6060f1SDimitry Andric   VSETVLIInfo Exit;
399fe6060f1SDimitry Andric 
400fe6060f1SDimitry Andric   // The VSETVLIInfo that represents the VL/VTYPE settings from all predecessor
401fe6060f1SDimitry Andric   // blocks. Calculated in Phase 2, and used by Phase 3.
402fe6060f1SDimitry Andric   VSETVLIInfo Pred;
403fe6060f1SDimitry Andric 
404fe6060f1SDimitry Andric   // Keeps track of whether the block is already in the queue.
405fe6060f1SDimitry Andric   bool InQueue = false;
406fe6060f1SDimitry Andric 
407fe6060f1SDimitry Andric   BlockData() {}
408fe6060f1SDimitry Andric };
409fe6060f1SDimitry Andric 
410fe6060f1SDimitry Andric class RISCVInsertVSETVLI : public MachineFunctionPass {
411fe6060f1SDimitry Andric   const TargetInstrInfo *TII;
412fe6060f1SDimitry Andric   MachineRegisterInfo *MRI;
413fe6060f1SDimitry Andric 
414fe6060f1SDimitry Andric   std::vector<BlockData> BlockInfo;
415fe6060f1SDimitry Andric   std::queue<const MachineBasicBlock *> WorkList;
416fe6060f1SDimitry Andric 
417fe6060f1SDimitry Andric public:
418fe6060f1SDimitry Andric   static char ID;
419fe6060f1SDimitry Andric 
420fe6060f1SDimitry Andric   RISCVInsertVSETVLI() : MachineFunctionPass(ID) {
421fe6060f1SDimitry Andric     initializeRISCVInsertVSETVLIPass(*PassRegistry::getPassRegistry());
422fe6060f1SDimitry Andric   }
423fe6060f1SDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
424fe6060f1SDimitry Andric 
425fe6060f1SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
426fe6060f1SDimitry Andric     AU.setPreservesCFG();
427fe6060f1SDimitry Andric     MachineFunctionPass::getAnalysisUsage(AU);
428fe6060f1SDimitry Andric   }
429fe6060f1SDimitry Andric 
430fe6060f1SDimitry Andric   StringRef getPassName() const override { return RISCV_INSERT_VSETVLI_NAME; }
431fe6060f1SDimitry Andric 
432fe6060f1SDimitry Andric private:
433fe6060f1SDimitry Andric   bool needVSETVLI(const VSETVLIInfo &Require, const VSETVLIInfo &CurInfo);
434fe6060f1SDimitry Andric   bool needVSETVLIPHI(const VSETVLIInfo &Require, const MachineBasicBlock &MBB);
435fe6060f1SDimitry Andric   void insertVSETVLI(MachineBasicBlock &MBB, MachineInstr &MI,
436fe6060f1SDimitry Andric                      const VSETVLIInfo &Info, const VSETVLIInfo &PrevInfo);
437fe6060f1SDimitry Andric 
438fe6060f1SDimitry Andric   bool computeVLVTYPEChanges(const MachineBasicBlock &MBB);
439fe6060f1SDimitry Andric   void computeIncomingVLVTYPE(const MachineBasicBlock &MBB);
440fe6060f1SDimitry Andric   void emitVSETVLIs(MachineBasicBlock &MBB);
441fe6060f1SDimitry Andric };
442fe6060f1SDimitry Andric 
443fe6060f1SDimitry Andric } // end anonymous namespace
444fe6060f1SDimitry Andric 
445fe6060f1SDimitry Andric char RISCVInsertVSETVLI::ID = 0;
446fe6060f1SDimitry Andric 
447fe6060f1SDimitry Andric INITIALIZE_PASS(RISCVInsertVSETVLI, DEBUG_TYPE, RISCV_INSERT_VSETVLI_NAME,
448fe6060f1SDimitry Andric                 false, false)
449fe6060f1SDimitry Andric 
450fe6060f1SDimitry Andric static MachineInstr *elideCopies(MachineInstr *MI,
451fe6060f1SDimitry Andric                                  const MachineRegisterInfo *MRI) {
452fe6060f1SDimitry Andric   while (true) {
453fe6060f1SDimitry Andric     if (!MI->isFullCopy())
454fe6060f1SDimitry Andric       return MI;
455fe6060f1SDimitry Andric     if (!Register::isVirtualRegister(MI->getOperand(1).getReg()))
456fe6060f1SDimitry Andric       return nullptr;
457fe6060f1SDimitry Andric     MI = MRI->getVRegDef(MI->getOperand(1).getReg());
458fe6060f1SDimitry Andric     if (!MI)
459fe6060f1SDimitry Andric       return nullptr;
460fe6060f1SDimitry Andric   }
461fe6060f1SDimitry Andric }
462fe6060f1SDimitry Andric 
46304eeddc0SDimitry Andric static bool isScalarMoveInstr(const MachineInstr &MI) {
46404eeddc0SDimitry Andric   switch (MI.getOpcode()) {
46504eeddc0SDimitry Andric   default:
46604eeddc0SDimitry Andric     return false;
46704eeddc0SDimitry Andric   case RISCV::PseudoVMV_S_X_M1:
46804eeddc0SDimitry Andric   case RISCV::PseudoVMV_S_X_M2:
46904eeddc0SDimitry Andric   case RISCV::PseudoVMV_S_X_M4:
47004eeddc0SDimitry Andric   case RISCV::PseudoVMV_S_X_M8:
47104eeddc0SDimitry Andric   case RISCV::PseudoVMV_S_X_MF2:
47204eeddc0SDimitry Andric   case RISCV::PseudoVMV_S_X_MF4:
47304eeddc0SDimitry Andric   case RISCV::PseudoVMV_S_X_MF8:
47404eeddc0SDimitry Andric   case RISCV::PseudoVFMV_S_F16_M1:
47504eeddc0SDimitry Andric   case RISCV::PseudoVFMV_S_F16_M2:
47604eeddc0SDimitry Andric   case RISCV::PseudoVFMV_S_F16_M4:
47704eeddc0SDimitry Andric   case RISCV::PseudoVFMV_S_F16_M8:
47804eeddc0SDimitry Andric   case RISCV::PseudoVFMV_S_F16_MF2:
47904eeddc0SDimitry Andric   case RISCV::PseudoVFMV_S_F16_MF4:
48004eeddc0SDimitry Andric   case RISCV::PseudoVFMV_S_F32_M1:
48104eeddc0SDimitry Andric   case RISCV::PseudoVFMV_S_F32_M2:
48204eeddc0SDimitry Andric   case RISCV::PseudoVFMV_S_F32_M4:
48304eeddc0SDimitry Andric   case RISCV::PseudoVFMV_S_F32_M8:
48404eeddc0SDimitry Andric   case RISCV::PseudoVFMV_S_F32_MF2:
48504eeddc0SDimitry Andric   case RISCV::PseudoVFMV_S_F64_M1:
48604eeddc0SDimitry Andric   case RISCV::PseudoVFMV_S_F64_M2:
48704eeddc0SDimitry Andric   case RISCV::PseudoVFMV_S_F64_M4:
48804eeddc0SDimitry Andric   case RISCV::PseudoVFMV_S_F64_M8:
48904eeddc0SDimitry Andric     return true;
49004eeddc0SDimitry Andric   }
49104eeddc0SDimitry Andric }
49204eeddc0SDimitry Andric 
493fe6060f1SDimitry Andric static VSETVLIInfo computeInfoForInstr(const MachineInstr &MI, uint64_t TSFlags,
494fe6060f1SDimitry Andric                                        const MachineRegisterInfo *MRI) {
495fe6060f1SDimitry Andric   VSETVLIInfo InstrInfo;
496fe6060f1SDimitry Andric   unsigned NumOperands = MI.getNumExplicitOperands();
497349cc55cSDimitry Andric   bool HasPolicy = RISCVII::hasVecPolicyOp(TSFlags);
498fe6060f1SDimitry Andric 
499fe6060f1SDimitry Andric   // Default to tail agnostic unless the destination is tied to a source.
500fe6060f1SDimitry Andric   // Unless the source is undef. In that case the user would have some control
501fe6060f1SDimitry Andric   // over the tail values. Some pseudo instructions force a tail agnostic policy
502fe6060f1SDimitry Andric   // despite having a tied def.
503fe6060f1SDimitry Andric   bool ForceTailAgnostic = RISCVII::doesForceTailAgnostic(TSFlags);
504fe6060f1SDimitry Andric   bool TailAgnostic = true;
505349cc55cSDimitry Andric   // If the instruction has policy argument, use the argument.
506349cc55cSDimitry Andric   if (HasPolicy) {
507349cc55cSDimitry Andric     const MachineOperand &Op = MI.getOperand(MI.getNumExplicitOperands() - 1);
508349cc55cSDimitry Andric     TailAgnostic = Op.getImm() & 0x1;
509349cc55cSDimitry Andric   }
510349cc55cSDimitry Andric 
511fe6060f1SDimitry Andric   unsigned UseOpIdx;
512349cc55cSDimitry Andric   if (!(ForceTailAgnostic || (HasPolicy && TailAgnostic)) &&
513349cc55cSDimitry Andric       MI.isRegTiedToUseOperand(0, &UseOpIdx)) {
514fe6060f1SDimitry Andric     TailAgnostic = false;
515fe6060f1SDimitry Andric     // If the tied operand is an IMPLICIT_DEF we can keep TailAgnostic.
516fe6060f1SDimitry Andric     const MachineOperand &UseMO = MI.getOperand(UseOpIdx);
517fe6060f1SDimitry Andric     MachineInstr *UseMI = MRI->getVRegDef(UseMO.getReg());
518fe6060f1SDimitry Andric     if (UseMI) {
519fe6060f1SDimitry Andric       UseMI = elideCopies(UseMI, MRI);
520fe6060f1SDimitry Andric       if (UseMI && UseMI->isImplicitDef())
521fe6060f1SDimitry Andric         TailAgnostic = true;
522fe6060f1SDimitry Andric     }
523fe6060f1SDimitry Andric   }
524fe6060f1SDimitry Andric 
525349cc55cSDimitry Andric   // Remove the tail policy so we can find the SEW and VL.
526349cc55cSDimitry Andric   if (HasPolicy)
527349cc55cSDimitry Andric     --NumOperands;
528349cc55cSDimitry Andric 
529349cc55cSDimitry Andric   RISCVII::VLMUL VLMul = RISCVII::getLMul(TSFlags);
530349cc55cSDimitry Andric 
531349cc55cSDimitry Andric   unsigned Log2SEW = MI.getOperand(NumOperands - 1).getImm();
532349cc55cSDimitry Andric   // A Log2SEW of 0 is an operation on mask registers only.
533349cc55cSDimitry Andric   bool MaskRegOp = Log2SEW == 0;
534349cc55cSDimitry Andric   unsigned SEW = Log2SEW ? 1 << Log2SEW : 8;
535349cc55cSDimitry Andric   assert(RISCVVType::isValidSEW(SEW) && "Unexpected SEW");
536349cc55cSDimitry Andric 
537349cc55cSDimitry Andric   // If there are no explicit defs, this is a store instruction which can
538349cc55cSDimitry Andric   // ignore the tail and mask policies.
539349cc55cSDimitry Andric   bool StoreOp = MI.getNumExplicitDefs() == 0;
54004eeddc0SDimitry Andric   bool ScalarMovOp = isScalarMoveInstr(MI);
541349cc55cSDimitry Andric 
542fe6060f1SDimitry Andric   if (RISCVII::hasVLOp(TSFlags)) {
543349cc55cSDimitry Andric     const MachineOperand &VLOp = MI.getOperand(NumOperands - 2);
544349cc55cSDimitry Andric     if (VLOp.isImm()) {
545349cc55cSDimitry Andric       int64_t Imm = VLOp.getImm();
546349cc55cSDimitry Andric       // Conver the VLMax sentintel to X0 register.
547349cc55cSDimitry Andric       if (Imm == RISCV::VLMaxSentinel)
548349cc55cSDimitry Andric         InstrInfo.setAVLReg(RISCV::X0);
549fe6060f1SDimitry Andric       else
550349cc55cSDimitry Andric         InstrInfo.setAVLImm(Imm);
551349cc55cSDimitry Andric     } else {
552fe6060f1SDimitry Andric       InstrInfo.setAVLReg(VLOp.getReg());
553349cc55cSDimitry Andric     }
554fe6060f1SDimitry Andric   } else
555fe6060f1SDimitry Andric     InstrInfo.setAVLReg(RISCV::NoRegister);
556fe6060f1SDimitry Andric   InstrInfo.setVTYPE(VLMul, SEW, /*TailAgnostic*/ TailAgnostic,
55704eeddc0SDimitry Andric                      /*MaskAgnostic*/ false, MaskRegOp, StoreOp, ScalarMovOp);
558fe6060f1SDimitry Andric 
559fe6060f1SDimitry Andric   return InstrInfo;
560fe6060f1SDimitry Andric }
561fe6060f1SDimitry Andric 
562fe6060f1SDimitry Andric void RISCVInsertVSETVLI::insertVSETVLI(MachineBasicBlock &MBB, MachineInstr &MI,
563fe6060f1SDimitry Andric                                        const VSETVLIInfo &Info,
564fe6060f1SDimitry Andric                                        const VSETVLIInfo &PrevInfo) {
565fe6060f1SDimitry Andric   DebugLoc DL = MI.getDebugLoc();
566fe6060f1SDimitry Andric 
567fe6060f1SDimitry Andric   // Use X0, X0 form if the AVL is the same and the SEW+LMUL gives the same
568fe6060f1SDimitry Andric   // VLMAX.
569fe6060f1SDimitry Andric   if (PrevInfo.isValid() && !PrevInfo.isUnknown() &&
570fe6060f1SDimitry Andric       Info.hasSameAVL(PrevInfo) && Info.hasSameVLMAX(PrevInfo)) {
571349cc55cSDimitry Andric     BuildMI(MBB, MI, DL, TII->get(RISCV::PseudoVSETVLIX0))
572fe6060f1SDimitry Andric         .addReg(RISCV::X0, RegState::Define | RegState::Dead)
573fe6060f1SDimitry Andric         .addReg(RISCV::X0, RegState::Kill)
574fe6060f1SDimitry Andric         .addImm(Info.encodeVTYPE())
575fe6060f1SDimitry Andric         .addReg(RISCV::VL, RegState::Implicit);
576fe6060f1SDimitry Andric     return;
577fe6060f1SDimitry Andric   }
578fe6060f1SDimitry Andric 
579fe6060f1SDimitry Andric   if (Info.hasAVLImm()) {
580fe6060f1SDimitry Andric     BuildMI(MBB, MI, DL, TII->get(RISCV::PseudoVSETIVLI))
581fe6060f1SDimitry Andric         .addReg(RISCV::X0, RegState::Define | RegState::Dead)
582fe6060f1SDimitry Andric         .addImm(Info.getAVLImm())
583fe6060f1SDimitry Andric         .addImm(Info.encodeVTYPE());
584fe6060f1SDimitry Andric     return;
585fe6060f1SDimitry Andric   }
586fe6060f1SDimitry Andric 
587fe6060f1SDimitry Andric   Register AVLReg = Info.getAVLReg();
588fe6060f1SDimitry Andric   if (AVLReg == RISCV::NoRegister) {
589fe6060f1SDimitry Andric     // We can only use x0, x0 if there's no chance of the vtype change causing
590fe6060f1SDimitry Andric     // the previous vl to become invalid.
591fe6060f1SDimitry Andric     if (PrevInfo.isValid() && !PrevInfo.isUnknown() &&
592fe6060f1SDimitry Andric         Info.hasSameVLMAX(PrevInfo)) {
593349cc55cSDimitry Andric       BuildMI(MBB, MI, DL, TII->get(RISCV::PseudoVSETVLIX0))
594fe6060f1SDimitry Andric           .addReg(RISCV::X0, RegState::Define | RegState::Dead)
595fe6060f1SDimitry Andric           .addReg(RISCV::X0, RegState::Kill)
596fe6060f1SDimitry Andric           .addImm(Info.encodeVTYPE())
597fe6060f1SDimitry Andric           .addReg(RISCV::VL, RegState::Implicit);
598fe6060f1SDimitry Andric       return;
599fe6060f1SDimitry Andric     }
600fe6060f1SDimitry Andric     // Otherwise use an AVL of 0 to avoid depending on previous vl.
601fe6060f1SDimitry Andric     BuildMI(MBB, MI, DL, TII->get(RISCV::PseudoVSETIVLI))
602fe6060f1SDimitry Andric         .addReg(RISCV::X0, RegState::Define | RegState::Dead)
603fe6060f1SDimitry Andric         .addImm(0)
604fe6060f1SDimitry Andric         .addImm(Info.encodeVTYPE());
605fe6060f1SDimitry Andric     return;
606fe6060f1SDimitry Andric   }
607fe6060f1SDimitry Andric 
608349cc55cSDimitry Andric   if (AVLReg.isVirtual())
609349cc55cSDimitry Andric     MRI->constrainRegClass(AVLReg, &RISCV::GPRNoX0RegClass);
610349cc55cSDimitry Andric 
611349cc55cSDimitry Andric   // Use X0 as the DestReg unless AVLReg is X0. We also need to change the
612349cc55cSDimitry Andric   // opcode if the AVLReg is X0 as they have different register classes for
613349cc55cSDimitry Andric   // the AVL operand.
614fe6060f1SDimitry Andric   Register DestReg = RISCV::X0;
615349cc55cSDimitry Andric   unsigned Opcode = RISCV::PseudoVSETVLI;
616349cc55cSDimitry Andric   if (AVLReg == RISCV::X0) {
617fe6060f1SDimitry Andric     DestReg = MRI->createVirtualRegister(&RISCV::GPRRegClass);
618349cc55cSDimitry Andric     Opcode = RISCV::PseudoVSETVLIX0;
619349cc55cSDimitry Andric   }
620349cc55cSDimitry Andric   BuildMI(MBB, MI, DL, TII->get(Opcode))
621fe6060f1SDimitry Andric       .addReg(DestReg, RegState::Define | RegState::Dead)
622fe6060f1SDimitry Andric       .addReg(AVLReg)
623fe6060f1SDimitry Andric       .addImm(Info.encodeVTYPE());
624fe6060f1SDimitry Andric }
625fe6060f1SDimitry Andric 
626fe6060f1SDimitry Andric // Return a VSETVLIInfo representing the changes made by this VSETVLI or
627fe6060f1SDimitry Andric // VSETIVLI instruction.
628fe6060f1SDimitry Andric static VSETVLIInfo getInfoForVSETVLI(const MachineInstr &MI) {
629fe6060f1SDimitry Andric   VSETVLIInfo NewInfo;
630349cc55cSDimitry Andric   if (MI.getOpcode() == RISCV::PseudoVSETIVLI) {
631349cc55cSDimitry Andric     NewInfo.setAVLImm(MI.getOperand(1).getImm());
632349cc55cSDimitry Andric   } else {
633349cc55cSDimitry Andric     assert(MI.getOpcode() == RISCV::PseudoVSETVLI ||
634349cc55cSDimitry Andric            MI.getOpcode() == RISCV::PseudoVSETVLIX0);
635fe6060f1SDimitry Andric     Register AVLReg = MI.getOperand(1).getReg();
636fe6060f1SDimitry Andric     assert((AVLReg != RISCV::X0 || MI.getOperand(0).getReg() != RISCV::X0) &&
637fe6060f1SDimitry Andric            "Can't handle X0, X0 vsetvli yet");
638fe6060f1SDimitry Andric     NewInfo.setAVLReg(AVLReg);
639fe6060f1SDimitry Andric   }
640fe6060f1SDimitry Andric   NewInfo.setVTYPE(MI.getOperand(2).getImm());
641fe6060f1SDimitry Andric 
642fe6060f1SDimitry Andric   return NewInfo;
643fe6060f1SDimitry Andric }
644fe6060f1SDimitry Andric 
645fe6060f1SDimitry Andric bool RISCVInsertVSETVLI::needVSETVLI(const VSETVLIInfo &Require,
646fe6060f1SDimitry Andric                                      const VSETVLIInfo &CurInfo) {
647349cc55cSDimitry Andric   if (CurInfo.isCompatible(Require, /*Strict*/ false))
648fe6060f1SDimitry Andric     return false;
649fe6060f1SDimitry Andric 
650fe6060f1SDimitry Andric   // We didn't find a compatible value. If our AVL is a virtual register,
651fe6060f1SDimitry Andric   // it might be defined by a VSET(I)VLI. If it has the same VTYPE we need
652fe6060f1SDimitry Andric   // and the last VL/VTYPE we observed is the same, we don't need a
653fe6060f1SDimitry Andric   // VSETVLI here.
654fe6060f1SDimitry Andric   if (!CurInfo.isUnknown() && Require.hasAVLReg() &&
655fe6060f1SDimitry Andric       Require.getAVLReg().isVirtual() && !CurInfo.hasSEWLMULRatioOnly() &&
656349cc55cSDimitry Andric       CurInfo.hasCompatibleVTYPE(Require, /*Strict*/ false)) {
657fe6060f1SDimitry Andric     if (MachineInstr *DefMI = MRI->getVRegDef(Require.getAVLReg())) {
658fe6060f1SDimitry Andric       if (DefMI->getOpcode() == RISCV::PseudoVSETVLI ||
659349cc55cSDimitry Andric           DefMI->getOpcode() == RISCV::PseudoVSETVLIX0 ||
660fe6060f1SDimitry Andric           DefMI->getOpcode() == RISCV::PseudoVSETIVLI) {
661fe6060f1SDimitry Andric         VSETVLIInfo DefInfo = getInfoForVSETVLI(*DefMI);
662fe6060f1SDimitry Andric         if (DefInfo.hasSameAVL(CurInfo) && DefInfo.hasSameVTYPE(CurInfo))
663fe6060f1SDimitry Andric           return false;
664fe6060f1SDimitry Andric       }
665fe6060f1SDimitry Andric     }
666fe6060f1SDimitry Andric   }
667fe6060f1SDimitry Andric 
668fe6060f1SDimitry Andric   return true;
669fe6060f1SDimitry Andric }
670fe6060f1SDimitry Andric 
671349cc55cSDimitry Andric bool canSkipVSETVLIForLoadStore(const MachineInstr &MI,
672349cc55cSDimitry Andric                                 const VSETVLIInfo &Require,
673349cc55cSDimitry Andric                                 const VSETVLIInfo &CurInfo) {
674349cc55cSDimitry Andric   unsigned EEW;
675349cc55cSDimitry Andric   switch (MI.getOpcode()) {
676349cc55cSDimitry Andric   default:
677349cc55cSDimitry Andric     return false;
678349cc55cSDimitry Andric   case RISCV::PseudoVLE8_V_M1:
679349cc55cSDimitry Andric   case RISCV::PseudoVLE8_V_M1_MASK:
680349cc55cSDimitry Andric   case RISCV::PseudoVLE8_V_M2:
681349cc55cSDimitry Andric   case RISCV::PseudoVLE8_V_M2_MASK:
682349cc55cSDimitry Andric   case RISCV::PseudoVLE8_V_M4:
683349cc55cSDimitry Andric   case RISCV::PseudoVLE8_V_M4_MASK:
684349cc55cSDimitry Andric   case RISCV::PseudoVLE8_V_M8:
685349cc55cSDimitry Andric   case RISCV::PseudoVLE8_V_M8_MASK:
686349cc55cSDimitry Andric   case RISCV::PseudoVLE8_V_MF2:
687349cc55cSDimitry Andric   case RISCV::PseudoVLE8_V_MF2_MASK:
688349cc55cSDimitry Andric   case RISCV::PseudoVLE8_V_MF4:
689349cc55cSDimitry Andric   case RISCV::PseudoVLE8_V_MF4_MASK:
690349cc55cSDimitry Andric   case RISCV::PseudoVLE8_V_MF8:
691349cc55cSDimitry Andric   case RISCV::PseudoVLE8_V_MF8_MASK:
692349cc55cSDimitry Andric   case RISCV::PseudoVLSE8_V_M1:
693349cc55cSDimitry Andric   case RISCV::PseudoVLSE8_V_M1_MASK:
694349cc55cSDimitry Andric   case RISCV::PseudoVLSE8_V_M2:
695349cc55cSDimitry Andric   case RISCV::PseudoVLSE8_V_M2_MASK:
696349cc55cSDimitry Andric   case RISCV::PseudoVLSE8_V_M4:
697349cc55cSDimitry Andric   case RISCV::PseudoVLSE8_V_M4_MASK:
698349cc55cSDimitry Andric   case RISCV::PseudoVLSE8_V_M8:
699349cc55cSDimitry Andric   case RISCV::PseudoVLSE8_V_M8_MASK:
700349cc55cSDimitry Andric   case RISCV::PseudoVLSE8_V_MF2:
701349cc55cSDimitry Andric   case RISCV::PseudoVLSE8_V_MF2_MASK:
702349cc55cSDimitry Andric   case RISCV::PseudoVLSE8_V_MF4:
703349cc55cSDimitry Andric   case RISCV::PseudoVLSE8_V_MF4_MASK:
704349cc55cSDimitry Andric   case RISCV::PseudoVLSE8_V_MF8:
705349cc55cSDimitry Andric   case RISCV::PseudoVLSE8_V_MF8_MASK:
706349cc55cSDimitry Andric   case RISCV::PseudoVSE8_V_M1:
707349cc55cSDimitry Andric   case RISCV::PseudoVSE8_V_M1_MASK:
708349cc55cSDimitry Andric   case RISCV::PseudoVSE8_V_M2:
709349cc55cSDimitry Andric   case RISCV::PseudoVSE8_V_M2_MASK:
710349cc55cSDimitry Andric   case RISCV::PseudoVSE8_V_M4:
711349cc55cSDimitry Andric   case RISCV::PseudoVSE8_V_M4_MASK:
712349cc55cSDimitry Andric   case RISCV::PseudoVSE8_V_M8:
713349cc55cSDimitry Andric   case RISCV::PseudoVSE8_V_M8_MASK:
714349cc55cSDimitry Andric   case RISCV::PseudoVSE8_V_MF2:
715349cc55cSDimitry Andric   case RISCV::PseudoVSE8_V_MF2_MASK:
716349cc55cSDimitry Andric   case RISCV::PseudoVSE8_V_MF4:
717349cc55cSDimitry Andric   case RISCV::PseudoVSE8_V_MF4_MASK:
718349cc55cSDimitry Andric   case RISCV::PseudoVSE8_V_MF8:
719349cc55cSDimitry Andric   case RISCV::PseudoVSE8_V_MF8_MASK:
720349cc55cSDimitry Andric   case RISCV::PseudoVSSE8_V_M1:
721349cc55cSDimitry Andric   case RISCV::PseudoVSSE8_V_M1_MASK:
722349cc55cSDimitry Andric   case RISCV::PseudoVSSE8_V_M2:
723349cc55cSDimitry Andric   case RISCV::PseudoVSSE8_V_M2_MASK:
724349cc55cSDimitry Andric   case RISCV::PseudoVSSE8_V_M4:
725349cc55cSDimitry Andric   case RISCV::PseudoVSSE8_V_M4_MASK:
726349cc55cSDimitry Andric   case RISCV::PseudoVSSE8_V_M8:
727349cc55cSDimitry Andric   case RISCV::PseudoVSSE8_V_M8_MASK:
728349cc55cSDimitry Andric   case RISCV::PseudoVSSE8_V_MF2:
729349cc55cSDimitry Andric   case RISCV::PseudoVSSE8_V_MF2_MASK:
730349cc55cSDimitry Andric   case RISCV::PseudoVSSE8_V_MF4:
731349cc55cSDimitry Andric   case RISCV::PseudoVSSE8_V_MF4_MASK:
732349cc55cSDimitry Andric   case RISCV::PseudoVSSE8_V_MF8:
733349cc55cSDimitry Andric   case RISCV::PseudoVSSE8_V_MF8_MASK:
734349cc55cSDimitry Andric     EEW = 8;
735349cc55cSDimitry Andric     break;
736349cc55cSDimitry Andric   case RISCV::PseudoVLE16_V_M1:
737349cc55cSDimitry Andric   case RISCV::PseudoVLE16_V_M1_MASK:
738349cc55cSDimitry Andric   case RISCV::PseudoVLE16_V_M2:
739349cc55cSDimitry Andric   case RISCV::PseudoVLE16_V_M2_MASK:
740349cc55cSDimitry Andric   case RISCV::PseudoVLE16_V_M4:
741349cc55cSDimitry Andric   case RISCV::PseudoVLE16_V_M4_MASK:
742349cc55cSDimitry Andric   case RISCV::PseudoVLE16_V_M8:
743349cc55cSDimitry Andric   case RISCV::PseudoVLE16_V_M8_MASK:
744349cc55cSDimitry Andric   case RISCV::PseudoVLE16_V_MF2:
745349cc55cSDimitry Andric   case RISCV::PseudoVLE16_V_MF2_MASK:
746349cc55cSDimitry Andric   case RISCV::PseudoVLE16_V_MF4:
747349cc55cSDimitry Andric   case RISCV::PseudoVLE16_V_MF4_MASK:
748349cc55cSDimitry Andric   case RISCV::PseudoVLSE16_V_M1:
749349cc55cSDimitry Andric   case RISCV::PseudoVLSE16_V_M1_MASK:
750349cc55cSDimitry Andric   case RISCV::PseudoVLSE16_V_M2:
751349cc55cSDimitry Andric   case RISCV::PseudoVLSE16_V_M2_MASK:
752349cc55cSDimitry Andric   case RISCV::PseudoVLSE16_V_M4:
753349cc55cSDimitry Andric   case RISCV::PseudoVLSE16_V_M4_MASK:
754349cc55cSDimitry Andric   case RISCV::PseudoVLSE16_V_M8:
755349cc55cSDimitry Andric   case RISCV::PseudoVLSE16_V_M8_MASK:
756349cc55cSDimitry Andric   case RISCV::PseudoVLSE16_V_MF2:
757349cc55cSDimitry Andric   case RISCV::PseudoVLSE16_V_MF2_MASK:
758349cc55cSDimitry Andric   case RISCV::PseudoVLSE16_V_MF4:
759349cc55cSDimitry Andric   case RISCV::PseudoVLSE16_V_MF4_MASK:
760349cc55cSDimitry Andric   case RISCV::PseudoVSE16_V_M1:
761349cc55cSDimitry Andric   case RISCV::PseudoVSE16_V_M1_MASK:
762349cc55cSDimitry Andric   case RISCV::PseudoVSE16_V_M2:
763349cc55cSDimitry Andric   case RISCV::PseudoVSE16_V_M2_MASK:
764349cc55cSDimitry Andric   case RISCV::PseudoVSE16_V_M4:
765349cc55cSDimitry Andric   case RISCV::PseudoVSE16_V_M4_MASK:
766349cc55cSDimitry Andric   case RISCV::PseudoVSE16_V_M8:
767349cc55cSDimitry Andric   case RISCV::PseudoVSE16_V_M8_MASK:
768349cc55cSDimitry Andric   case RISCV::PseudoVSE16_V_MF2:
769349cc55cSDimitry Andric   case RISCV::PseudoVSE16_V_MF2_MASK:
770349cc55cSDimitry Andric   case RISCV::PseudoVSE16_V_MF4:
771349cc55cSDimitry Andric   case RISCV::PseudoVSE16_V_MF4_MASK:
772349cc55cSDimitry Andric   case RISCV::PseudoVSSE16_V_M1:
773349cc55cSDimitry Andric   case RISCV::PseudoVSSE16_V_M1_MASK:
774349cc55cSDimitry Andric   case RISCV::PseudoVSSE16_V_M2:
775349cc55cSDimitry Andric   case RISCV::PseudoVSSE16_V_M2_MASK:
776349cc55cSDimitry Andric   case RISCV::PseudoVSSE16_V_M4:
777349cc55cSDimitry Andric   case RISCV::PseudoVSSE16_V_M4_MASK:
778349cc55cSDimitry Andric   case RISCV::PseudoVSSE16_V_M8:
779349cc55cSDimitry Andric   case RISCV::PseudoVSSE16_V_M8_MASK:
780349cc55cSDimitry Andric   case RISCV::PseudoVSSE16_V_MF2:
781349cc55cSDimitry Andric   case RISCV::PseudoVSSE16_V_MF2_MASK:
782349cc55cSDimitry Andric   case RISCV::PseudoVSSE16_V_MF4:
783349cc55cSDimitry Andric   case RISCV::PseudoVSSE16_V_MF4_MASK:
784349cc55cSDimitry Andric     EEW = 16;
785349cc55cSDimitry Andric     break;
786349cc55cSDimitry Andric   case RISCV::PseudoVLE32_V_M1:
787349cc55cSDimitry Andric   case RISCV::PseudoVLE32_V_M1_MASK:
788349cc55cSDimitry Andric   case RISCV::PseudoVLE32_V_M2:
789349cc55cSDimitry Andric   case RISCV::PseudoVLE32_V_M2_MASK:
790349cc55cSDimitry Andric   case RISCV::PseudoVLE32_V_M4:
791349cc55cSDimitry Andric   case RISCV::PseudoVLE32_V_M4_MASK:
792349cc55cSDimitry Andric   case RISCV::PseudoVLE32_V_M8:
793349cc55cSDimitry Andric   case RISCV::PseudoVLE32_V_M8_MASK:
794349cc55cSDimitry Andric   case RISCV::PseudoVLE32_V_MF2:
795349cc55cSDimitry Andric   case RISCV::PseudoVLE32_V_MF2_MASK:
796349cc55cSDimitry Andric   case RISCV::PseudoVLSE32_V_M1:
797349cc55cSDimitry Andric   case RISCV::PseudoVLSE32_V_M1_MASK:
798349cc55cSDimitry Andric   case RISCV::PseudoVLSE32_V_M2:
799349cc55cSDimitry Andric   case RISCV::PseudoVLSE32_V_M2_MASK:
800349cc55cSDimitry Andric   case RISCV::PseudoVLSE32_V_M4:
801349cc55cSDimitry Andric   case RISCV::PseudoVLSE32_V_M4_MASK:
802349cc55cSDimitry Andric   case RISCV::PseudoVLSE32_V_M8:
803349cc55cSDimitry Andric   case RISCV::PseudoVLSE32_V_M8_MASK:
804349cc55cSDimitry Andric   case RISCV::PseudoVLSE32_V_MF2:
805349cc55cSDimitry Andric   case RISCV::PseudoVLSE32_V_MF2_MASK:
806349cc55cSDimitry Andric   case RISCV::PseudoVSE32_V_M1:
807349cc55cSDimitry Andric   case RISCV::PseudoVSE32_V_M1_MASK:
808349cc55cSDimitry Andric   case RISCV::PseudoVSE32_V_M2:
809349cc55cSDimitry Andric   case RISCV::PseudoVSE32_V_M2_MASK:
810349cc55cSDimitry Andric   case RISCV::PseudoVSE32_V_M4:
811349cc55cSDimitry Andric   case RISCV::PseudoVSE32_V_M4_MASK:
812349cc55cSDimitry Andric   case RISCV::PseudoVSE32_V_M8:
813349cc55cSDimitry Andric   case RISCV::PseudoVSE32_V_M8_MASK:
814349cc55cSDimitry Andric   case RISCV::PseudoVSE32_V_MF2:
815349cc55cSDimitry Andric   case RISCV::PseudoVSE32_V_MF2_MASK:
816349cc55cSDimitry Andric   case RISCV::PseudoVSSE32_V_M1:
817349cc55cSDimitry Andric   case RISCV::PseudoVSSE32_V_M1_MASK:
818349cc55cSDimitry Andric   case RISCV::PseudoVSSE32_V_M2:
819349cc55cSDimitry Andric   case RISCV::PseudoVSSE32_V_M2_MASK:
820349cc55cSDimitry Andric   case RISCV::PseudoVSSE32_V_M4:
821349cc55cSDimitry Andric   case RISCV::PseudoVSSE32_V_M4_MASK:
822349cc55cSDimitry Andric   case RISCV::PseudoVSSE32_V_M8:
823349cc55cSDimitry Andric   case RISCV::PseudoVSSE32_V_M8_MASK:
824349cc55cSDimitry Andric   case RISCV::PseudoVSSE32_V_MF2:
825349cc55cSDimitry Andric   case RISCV::PseudoVSSE32_V_MF2_MASK:
826349cc55cSDimitry Andric     EEW = 32;
827349cc55cSDimitry Andric     break;
828349cc55cSDimitry Andric   case RISCV::PseudoVLE64_V_M1:
829349cc55cSDimitry Andric   case RISCV::PseudoVLE64_V_M1_MASK:
830349cc55cSDimitry Andric   case RISCV::PseudoVLE64_V_M2:
831349cc55cSDimitry Andric   case RISCV::PseudoVLE64_V_M2_MASK:
832349cc55cSDimitry Andric   case RISCV::PseudoVLE64_V_M4:
833349cc55cSDimitry Andric   case RISCV::PseudoVLE64_V_M4_MASK:
834349cc55cSDimitry Andric   case RISCV::PseudoVLE64_V_M8:
835349cc55cSDimitry Andric   case RISCV::PseudoVLE64_V_M8_MASK:
836349cc55cSDimitry Andric   case RISCV::PseudoVLSE64_V_M1:
837349cc55cSDimitry Andric   case RISCV::PseudoVLSE64_V_M1_MASK:
838349cc55cSDimitry Andric   case RISCV::PseudoVLSE64_V_M2:
839349cc55cSDimitry Andric   case RISCV::PseudoVLSE64_V_M2_MASK:
840349cc55cSDimitry Andric   case RISCV::PseudoVLSE64_V_M4:
841349cc55cSDimitry Andric   case RISCV::PseudoVLSE64_V_M4_MASK:
842349cc55cSDimitry Andric   case RISCV::PseudoVLSE64_V_M8:
843349cc55cSDimitry Andric   case RISCV::PseudoVLSE64_V_M8_MASK:
844349cc55cSDimitry Andric   case RISCV::PseudoVSE64_V_M1:
845349cc55cSDimitry Andric   case RISCV::PseudoVSE64_V_M1_MASK:
846349cc55cSDimitry Andric   case RISCV::PseudoVSE64_V_M2:
847349cc55cSDimitry Andric   case RISCV::PseudoVSE64_V_M2_MASK:
848349cc55cSDimitry Andric   case RISCV::PseudoVSE64_V_M4:
849349cc55cSDimitry Andric   case RISCV::PseudoVSE64_V_M4_MASK:
850349cc55cSDimitry Andric   case RISCV::PseudoVSE64_V_M8:
851349cc55cSDimitry Andric   case RISCV::PseudoVSE64_V_M8_MASK:
852349cc55cSDimitry Andric   case RISCV::PseudoVSSE64_V_M1:
853349cc55cSDimitry Andric   case RISCV::PseudoVSSE64_V_M1_MASK:
854349cc55cSDimitry Andric   case RISCV::PseudoVSSE64_V_M2:
855349cc55cSDimitry Andric   case RISCV::PseudoVSSE64_V_M2_MASK:
856349cc55cSDimitry Andric   case RISCV::PseudoVSSE64_V_M4:
857349cc55cSDimitry Andric   case RISCV::PseudoVSSE64_V_M4_MASK:
858349cc55cSDimitry Andric   case RISCV::PseudoVSSE64_V_M8:
859349cc55cSDimitry Andric   case RISCV::PseudoVSSE64_V_M8_MASK:
860349cc55cSDimitry Andric     EEW = 64;
861349cc55cSDimitry Andric     break;
862349cc55cSDimitry Andric   }
863349cc55cSDimitry Andric 
864349cc55cSDimitry Andric   return CurInfo.isCompatibleWithLoadStoreEEW(EEW, Require);
865349cc55cSDimitry Andric }
866349cc55cSDimitry Andric 
867fe6060f1SDimitry Andric bool RISCVInsertVSETVLI::computeVLVTYPEChanges(const MachineBasicBlock &MBB) {
868fe6060f1SDimitry Andric   bool HadVectorOp = false;
869fe6060f1SDimitry Andric 
870fe6060f1SDimitry Andric   BlockData &BBInfo = BlockInfo[MBB.getNumber()];
871fe6060f1SDimitry Andric   for (const MachineInstr &MI : MBB) {
872fe6060f1SDimitry Andric     // If this is an explicit VSETVLI or VSETIVLI, update our state.
873fe6060f1SDimitry Andric     if (MI.getOpcode() == RISCV::PseudoVSETVLI ||
874349cc55cSDimitry Andric         MI.getOpcode() == RISCV::PseudoVSETVLIX0 ||
875fe6060f1SDimitry Andric         MI.getOpcode() == RISCV::PseudoVSETIVLI) {
876fe6060f1SDimitry Andric       HadVectorOp = true;
877fe6060f1SDimitry Andric       BBInfo.Change = getInfoForVSETVLI(MI);
878fe6060f1SDimitry Andric       continue;
879fe6060f1SDimitry Andric     }
880fe6060f1SDimitry Andric 
881fe6060f1SDimitry Andric     uint64_t TSFlags = MI.getDesc().TSFlags;
882fe6060f1SDimitry Andric     if (RISCVII::hasSEWOp(TSFlags)) {
883fe6060f1SDimitry Andric       HadVectorOp = true;
884fe6060f1SDimitry Andric 
885fe6060f1SDimitry Andric       VSETVLIInfo NewInfo = computeInfoForInstr(MI, TSFlags, MRI);
886fe6060f1SDimitry Andric 
887fe6060f1SDimitry Andric       if (!BBInfo.Change.isValid()) {
888fe6060f1SDimitry Andric         BBInfo.Change = NewInfo;
889fe6060f1SDimitry Andric       } else {
890fe6060f1SDimitry Andric         // If this instruction isn't compatible with the previous VL/VTYPE
891fe6060f1SDimitry Andric         // we need to insert a VSETVLI.
892349cc55cSDimitry Andric         // If this is a unit-stride or strided load/store, we may be able to use
893349cc55cSDimitry Andric         // the EMUL=(EEW/SEW)*LMUL relationship to avoid changing vtype.
894349cc55cSDimitry Andric         // NOTE: We only do this if the vtype we're comparing against was
895349cc55cSDimitry Andric         // created in this block. We need the first and third phase to treat
896349cc55cSDimitry Andric         // the store the same way.
897349cc55cSDimitry Andric         if (!canSkipVSETVLIForLoadStore(MI, NewInfo, BBInfo.Change) &&
898349cc55cSDimitry Andric             needVSETVLI(NewInfo, BBInfo.Change))
899fe6060f1SDimitry Andric           BBInfo.Change = NewInfo;
900fe6060f1SDimitry Andric       }
901fe6060f1SDimitry Andric     }
902fe6060f1SDimitry Andric 
903fe6060f1SDimitry Andric     // If this is something that updates VL/VTYPE that we don't know about, set
904fe6060f1SDimitry Andric     // the state to unknown.
905fe6060f1SDimitry Andric     if (MI.isCall() || MI.isInlineAsm() || MI.modifiesRegister(RISCV::VL) ||
906fe6060f1SDimitry Andric         MI.modifiesRegister(RISCV::VTYPE)) {
907fe6060f1SDimitry Andric       BBInfo.Change = VSETVLIInfo::getUnknown();
908fe6060f1SDimitry Andric     }
909fe6060f1SDimitry Andric   }
910fe6060f1SDimitry Andric 
911fe6060f1SDimitry Andric   // Initial exit state is whatever change we found in the block.
912fe6060f1SDimitry Andric   BBInfo.Exit = BBInfo.Change;
913fe6060f1SDimitry Andric 
914fe6060f1SDimitry Andric   return HadVectorOp;
915fe6060f1SDimitry Andric }
916fe6060f1SDimitry Andric 
917fe6060f1SDimitry Andric void RISCVInsertVSETVLI::computeIncomingVLVTYPE(const MachineBasicBlock &MBB) {
918fe6060f1SDimitry Andric   BlockData &BBInfo = BlockInfo[MBB.getNumber()];
919fe6060f1SDimitry Andric 
920fe6060f1SDimitry Andric   BBInfo.InQueue = false;
921fe6060f1SDimitry Andric 
922fe6060f1SDimitry Andric   VSETVLIInfo InInfo;
923fe6060f1SDimitry Andric   if (MBB.pred_empty()) {
924fe6060f1SDimitry Andric     // There are no predecessors, so use the default starting status.
925fe6060f1SDimitry Andric     InInfo.setUnknown();
926fe6060f1SDimitry Andric   } else {
927fe6060f1SDimitry Andric     for (MachineBasicBlock *P : MBB.predecessors())
928fe6060f1SDimitry Andric       InInfo = InInfo.intersect(BlockInfo[P->getNumber()].Exit);
929fe6060f1SDimitry Andric   }
930fe6060f1SDimitry Andric 
931fe6060f1SDimitry Andric   // If we don't have any valid predecessor value, wait until we do.
932fe6060f1SDimitry Andric   if (!InInfo.isValid())
933fe6060f1SDimitry Andric     return;
934fe6060f1SDimitry Andric 
935fe6060f1SDimitry Andric   BBInfo.Pred = InInfo;
936fe6060f1SDimitry Andric 
937fe6060f1SDimitry Andric   VSETVLIInfo TmpStatus = BBInfo.Pred.merge(BBInfo.Change);
938fe6060f1SDimitry Andric 
939fe6060f1SDimitry Andric   // If the new exit value matches the old exit value, we don't need to revisit
940fe6060f1SDimitry Andric   // any blocks.
941fe6060f1SDimitry Andric   if (BBInfo.Exit == TmpStatus)
942fe6060f1SDimitry Andric     return;
943fe6060f1SDimitry Andric 
944fe6060f1SDimitry Andric   BBInfo.Exit = TmpStatus;
945fe6060f1SDimitry Andric 
946fe6060f1SDimitry Andric   // Add the successors to the work list so we can propagate the changed exit
947fe6060f1SDimitry Andric   // status.
948fe6060f1SDimitry Andric   for (MachineBasicBlock *S : MBB.successors())
949fe6060f1SDimitry Andric     if (!BlockInfo[S->getNumber()].InQueue)
950fe6060f1SDimitry Andric       WorkList.push(S);
951fe6060f1SDimitry Andric }
952fe6060f1SDimitry Andric 
953fe6060f1SDimitry Andric // If we weren't able to prove a vsetvli was directly unneeded, it might still
954fe6060f1SDimitry Andric // be/ unneeded if the AVL is a phi node where all incoming values are VL
955fe6060f1SDimitry Andric // outputs from the last VSETVLI in their respective basic blocks.
956fe6060f1SDimitry Andric bool RISCVInsertVSETVLI::needVSETVLIPHI(const VSETVLIInfo &Require,
957fe6060f1SDimitry Andric                                         const MachineBasicBlock &MBB) {
958fe6060f1SDimitry Andric   if (DisableInsertVSETVLPHIOpt)
959fe6060f1SDimitry Andric     return true;
960fe6060f1SDimitry Andric 
961fe6060f1SDimitry Andric   if (!Require.hasAVLReg())
962fe6060f1SDimitry Andric     return true;
963fe6060f1SDimitry Andric 
964fe6060f1SDimitry Andric   Register AVLReg = Require.getAVLReg();
965fe6060f1SDimitry Andric   if (!AVLReg.isVirtual())
966fe6060f1SDimitry Andric     return true;
967fe6060f1SDimitry Andric 
968fe6060f1SDimitry Andric   // We need the AVL to be produce by a PHI node in this basic block.
969fe6060f1SDimitry Andric   MachineInstr *PHI = MRI->getVRegDef(AVLReg);
970fe6060f1SDimitry Andric   if (!PHI || PHI->getOpcode() != RISCV::PHI || PHI->getParent() != &MBB)
971fe6060f1SDimitry Andric     return true;
972fe6060f1SDimitry Andric 
973fe6060f1SDimitry Andric   for (unsigned PHIOp = 1, NumOps = PHI->getNumOperands(); PHIOp != NumOps;
974fe6060f1SDimitry Andric        PHIOp += 2) {
975fe6060f1SDimitry Andric     Register InReg = PHI->getOperand(PHIOp).getReg();
976fe6060f1SDimitry Andric     MachineBasicBlock *PBB = PHI->getOperand(PHIOp + 1).getMBB();
977fe6060f1SDimitry Andric     const BlockData &PBBInfo = BlockInfo[PBB->getNumber()];
978fe6060f1SDimitry Andric     // If the exit from the predecessor has the VTYPE we are looking for
979fe6060f1SDimitry Andric     // we might be able to avoid a VSETVLI.
980349cc55cSDimitry Andric     if (PBBInfo.Exit.isUnknown() ||
981349cc55cSDimitry Andric         !PBBInfo.Exit.hasCompatibleVTYPE(Require, /*Strict*/ false))
982fe6060f1SDimitry Andric       return true;
983fe6060f1SDimitry Andric 
984fe6060f1SDimitry Andric     // We need the PHI input to the be the output of a VSET(I)VLI.
985fe6060f1SDimitry Andric     MachineInstr *DefMI = MRI->getVRegDef(InReg);
986fe6060f1SDimitry Andric     if (!DefMI || (DefMI->getOpcode() != RISCV::PseudoVSETVLI &&
987349cc55cSDimitry Andric                    DefMI->getOpcode() != RISCV::PseudoVSETVLIX0 &&
988fe6060f1SDimitry Andric                    DefMI->getOpcode() != RISCV::PseudoVSETIVLI))
989fe6060f1SDimitry Andric       return true;
990fe6060f1SDimitry Andric 
991fe6060f1SDimitry Andric     // We found a VSET(I)VLI make sure it matches the output of the
992fe6060f1SDimitry Andric     // predecessor block.
993fe6060f1SDimitry Andric     VSETVLIInfo DefInfo = getInfoForVSETVLI(*DefMI);
994fe6060f1SDimitry Andric     if (!DefInfo.hasSameAVL(PBBInfo.Exit) ||
995fe6060f1SDimitry Andric         !DefInfo.hasSameVTYPE(PBBInfo.Exit))
996fe6060f1SDimitry Andric       return true;
997fe6060f1SDimitry Andric   }
998fe6060f1SDimitry Andric 
999fe6060f1SDimitry Andric   // If all the incoming values to the PHI checked out, we don't need
1000fe6060f1SDimitry Andric   // to insert a VSETVLI.
1001fe6060f1SDimitry Andric   return false;
1002fe6060f1SDimitry Andric }
1003fe6060f1SDimitry Andric 
1004fe6060f1SDimitry Andric void RISCVInsertVSETVLI::emitVSETVLIs(MachineBasicBlock &MBB) {
1005fe6060f1SDimitry Andric   VSETVLIInfo CurInfo;
1006349cc55cSDimitry Andric   // Only be set if current VSETVLIInfo is from an explicit VSET(I)VLI.
1007349cc55cSDimitry Andric   MachineInstr *PrevVSETVLIMI = nullptr;
1008fe6060f1SDimitry Andric 
1009fe6060f1SDimitry Andric   for (MachineInstr &MI : MBB) {
1010fe6060f1SDimitry Andric     // If this is an explicit VSETVLI or VSETIVLI, update our state.
1011fe6060f1SDimitry Andric     if (MI.getOpcode() == RISCV::PseudoVSETVLI ||
1012349cc55cSDimitry Andric         MI.getOpcode() == RISCV::PseudoVSETVLIX0 ||
1013fe6060f1SDimitry Andric         MI.getOpcode() == RISCV::PseudoVSETIVLI) {
1014fe6060f1SDimitry Andric       // Conservatively, mark the VL and VTYPE as live.
1015fe6060f1SDimitry Andric       assert(MI.getOperand(3).getReg() == RISCV::VL &&
1016fe6060f1SDimitry Andric              MI.getOperand(4).getReg() == RISCV::VTYPE &&
1017fe6060f1SDimitry Andric              "Unexpected operands where VL and VTYPE should be");
1018fe6060f1SDimitry Andric       MI.getOperand(3).setIsDead(false);
1019fe6060f1SDimitry Andric       MI.getOperand(4).setIsDead(false);
1020fe6060f1SDimitry Andric       CurInfo = getInfoForVSETVLI(MI);
1021349cc55cSDimitry Andric       PrevVSETVLIMI = &MI;
1022fe6060f1SDimitry Andric       continue;
1023fe6060f1SDimitry Andric     }
1024fe6060f1SDimitry Andric 
1025fe6060f1SDimitry Andric     uint64_t TSFlags = MI.getDesc().TSFlags;
1026fe6060f1SDimitry Andric     if (RISCVII::hasSEWOp(TSFlags)) {
1027fe6060f1SDimitry Andric       VSETVLIInfo NewInfo = computeInfoForInstr(MI, TSFlags, MRI);
1028fe6060f1SDimitry Andric       if (RISCVII::hasVLOp(TSFlags)) {
1029349cc55cSDimitry Andric         unsigned Offset = 2;
1030349cc55cSDimitry Andric         if (RISCVII::hasVecPolicyOp(TSFlags))
1031349cc55cSDimitry Andric           Offset = 3;
1032349cc55cSDimitry Andric         MachineOperand &VLOp =
1033349cc55cSDimitry Andric             MI.getOperand(MI.getNumExplicitOperands() - Offset);
1034fe6060f1SDimitry Andric         if (VLOp.isReg()) {
1035fe6060f1SDimitry Andric           // Erase the AVL operand from the instruction.
1036fe6060f1SDimitry Andric           VLOp.setReg(RISCV::NoRegister);
1037fe6060f1SDimitry Andric           VLOp.setIsKill(false);
1038fe6060f1SDimitry Andric         }
1039fe6060f1SDimitry Andric         MI.addOperand(MachineOperand::CreateReg(RISCV::VL, /*isDef*/ false,
1040fe6060f1SDimitry Andric                                                 /*isImp*/ true));
1041fe6060f1SDimitry Andric       }
1042fe6060f1SDimitry Andric       MI.addOperand(MachineOperand::CreateReg(RISCV::VTYPE, /*isDef*/ false,
1043fe6060f1SDimitry Andric                                               /*isImp*/ true));
1044fe6060f1SDimitry Andric 
1045fe6060f1SDimitry Andric       if (!CurInfo.isValid()) {
1046fe6060f1SDimitry Andric         // We haven't found any vector instructions or VL/VTYPE changes yet,
1047fe6060f1SDimitry Andric         // use the predecessor information.
1048fe6060f1SDimitry Andric         assert(BlockInfo[MBB.getNumber()].Pred.isValid() &&
1049fe6060f1SDimitry Andric                "Expected a valid predecessor state.");
1050*d56accc7SDimitry Andric         if (needVSETVLI(NewInfo, BlockInfo[MBB.getNumber()].Pred) &&
1051fe6060f1SDimitry Andric             needVSETVLIPHI(NewInfo, MBB)) {
1052fe6060f1SDimitry Andric           insertVSETVLI(MBB, MI, NewInfo, BlockInfo[MBB.getNumber()].Pred);
1053fe6060f1SDimitry Andric           CurInfo = NewInfo;
1054fe6060f1SDimitry Andric         }
1055fe6060f1SDimitry Andric       } else {
1056fe6060f1SDimitry Andric         // If this instruction isn't compatible with the previous VL/VTYPE
1057fe6060f1SDimitry Andric         // we need to insert a VSETVLI.
1058349cc55cSDimitry Andric         // If this is a unit-stride or strided load/store, we may be able to use
1059349cc55cSDimitry Andric         // the EMUL=(EEW/SEW)*LMUL relationship to avoid changing vtype.
1060349cc55cSDimitry Andric         // NOTE: We can't use predecessor information for the store. We must
1061349cc55cSDimitry Andric         // treat it the same as the first phase so that we produce the correct
1062349cc55cSDimitry Andric         // vl/vtype for succesor blocks.
1063349cc55cSDimitry Andric         if (!canSkipVSETVLIForLoadStore(MI, NewInfo, CurInfo) &&
1064349cc55cSDimitry Andric             needVSETVLI(NewInfo, CurInfo)) {
1065349cc55cSDimitry Andric           // If the previous VL/VTYPE is set by VSETVLI and do not use, Merge it
1066349cc55cSDimitry Andric           // with current VL/VTYPE.
1067349cc55cSDimitry Andric           bool NeedInsertVSETVLI = true;
1068349cc55cSDimitry Andric           if (PrevVSETVLIMI) {
1069349cc55cSDimitry Andric             bool HasSameAVL =
1070349cc55cSDimitry Andric                 CurInfo.hasSameAVL(NewInfo) ||
1071349cc55cSDimitry Andric                 (NewInfo.hasAVLReg() && NewInfo.getAVLReg().isVirtual() &&
1072349cc55cSDimitry Andric                  NewInfo.getAVLReg() == PrevVSETVLIMI->getOperand(0).getReg());
1073349cc55cSDimitry Andric             // If these two VSETVLI have the same AVL and the same VLMAX,
1074349cc55cSDimitry Andric             // we could merge these two VSETVLI.
1075349cc55cSDimitry Andric             if (HasSameAVL &&
1076349cc55cSDimitry Andric                 CurInfo.getSEWLMULRatio() == NewInfo.getSEWLMULRatio()) {
1077349cc55cSDimitry Andric               PrevVSETVLIMI->getOperand(2).setImm(NewInfo.encodeVTYPE());
1078349cc55cSDimitry Andric               NeedInsertVSETVLI = false;
1079349cc55cSDimitry Andric             }
108004eeddc0SDimitry Andric             if (isScalarMoveInstr(MI) &&
108104eeddc0SDimitry Andric                 ((CurInfo.hasNonZeroAVL() && NewInfo.hasNonZeroAVL()) ||
108204eeddc0SDimitry Andric                  (CurInfo.hasZeroAVL() && NewInfo.hasZeroAVL())) &&
108304eeddc0SDimitry Andric                 NewInfo.hasSameVLMAX(CurInfo)) {
108404eeddc0SDimitry Andric               PrevVSETVLIMI->getOperand(2).setImm(NewInfo.encodeVTYPE());
108504eeddc0SDimitry Andric               NeedInsertVSETVLI = false;
108604eeddc0SDimitry Andric             }
1087349cc55cSDimitry Andric           }
1088349cc55cSDimitry Andric           if (NeedInsertVSETVLI)
1089fe6060f1SDimitry Andric             insertVSETVLI(MBB, MI, NewInfo, CurInfo);
1090fe6060f1SDimitry Andric           CurInfo = NewInfo;
1091fe6060f1SDimitry Andric         }
1092fe6060f1SDimitry Andric       }
1093349cc55cSDimitry Andric       PrevVSETVLIMI = nullptr;
1094fe6060f1SDimitry Andric     }
1095fe6060f1SDimitry Andric 
1096fe6060f1SDimitry Andric     // If this is something updates VL/VTYPE that we don't know about, set
1097fe6060f1SDimitry Andric     // the state to unknown.
1098fe6060f1SDimitry Andric     if (MI.isCall() || MI.isInlineAsm() || MI.modifiesRegister(RISCV::VL) ||
1099fe6060f1SDimitry Andric         MI.modifiesRegister(RISCV::VTYPE)) {
1100fe6060f1SDimitry Andric       CurInfo = VSETVLIInfo::getUnknown();
1101349cc55cSDimitry Andric       PrevVSETVLIMI = nullptr;
1102fe6060f1SDimitry Andric     }
1103*d56accc7SDimitry Andric 
1104*d56accc7SDimitry Andric     // If we reach the end of the block and our current info doesn't match the
1105*d56accc7SDimitry Andric     // expected info, insert a vsetvli to correct.
1106*d56accc7SDimitry Andric     if (MI.isTerminator()) {
1107*d56accc7SDimitry Andric       const VSETVLIInfo &ExitInfo = BlockInfo[MBB.getNumber()].Exit;
1108*d56accc7SDimitry Andric       if (CurInfo.isValid() && ExitInfo.isValid() && !ExitInfo.isUnknown() &&
1109*d56accc7SDimitry Andric           CurInfo != ExitInfo) {
1110*d56accc7SDimitry Andric         insertVSETVLI(MBB, MI, ExitInfo, CurInfo);
1111*d56accc7SDimitry Andric         CurInfo = ExitInfo;
1112*d56accc7SDimitry Andric       }
1113*d56accc7SDimitry Andric     }
1114fe6060f1SDimitry Andric   }
1115fe6060f1SDimitry Andric }
1116fe6060f1SDimitry Andric 
1117fe6060f1SDimitry Andric bool RISCVInsertVSETVLI::runOnMachineFunction(MachineFunction &MF) {
1118fe6060f1SDimitry Andric   // Skip if the vector extension is not enabled.
1119fe6060f1SDimitry Andric   const RISCVSubtarget &ST = MF.getSubtarget<RISCVSubtarget>();
1120349cc55cSDimitry Andric   if (!ST.hasVInstructions())
1121fe6060f1SDimitry Andric     return false;
1122fe6060f1SDimitry Andric 
1123fe6060f1SDimitry Andric   TII = ST.getInstrInfo();
1124fe6060f1SDimitry Andric   MRI = &MF.getRegInfo();
1125fe6060f1SDimitry Andric 
1126fe6060f1SDimitry Andric   assert(BlockInfo.empty() && "Expect empty block infos");
1127fe6060f1SDimitry Andric   BlockInfo.resize(MF.getNumBlockIDs());
1128fe6060f1SDimitry Andric 
1129fe6060f1SDimitry Andric   bool HaveVectorOp = false;
1130fe6060f1SDimitry Andric 
1131fe6060f1SDimitry Andric   // Phase 1 - determine how VL/VTYPE are affected by the each block.
1132fe6060f1SDimitry Andric   for (const MachineBasicBlock &MBB : MF)
1133fe6060f1SDimitry Andric     HaveVectorOp |= computeVLVTYPEChanges(MBB);
1134fe6060f1SDimitry Andric 
1135fe6060f1SDimitry Andric   // If we didn't find any instructions that need VSETVLI, we're done.
1136fe6060f1SDimitry Andric   if (HaveVectorOp) {
1137fe6060f1SDimitry Andric     // Phase 2 - determine the exit VL/VTYPE from each block. We add all
1138fe6060f1SDimitry Andric     // blocks to the list here, but will also add any that need to be revisited
1139fe6060f1SDimitry Andric     // during Phase 2 processing.
1140fe6060f1SDimitry Andric     for (const MachineBasicBlock &MBB : MF) {
1141fe6060f1SDimitry Andric       WorkList.push(&MBB);
1142fe6060f1SDimitry Andric       BlockInfo[MBB.getNumber()].InQueue = true;
1143fe6060f1SDimitry Andric     }
1144fe6060f1SDimitry Andric     while (!WorkList.empty()) {
1145fe6060f1SDimitry Andric       const MachineBasicBlock &MBB = *WorkList.front();
1146fe6060f1SDimitry Andric       WorkList.pop();
1147fe6060f1SDimitry Andric       computeIncomingVLVTYPE(MBB);
1148fe6060f1SDimitry Andric     }
1149fe6060f1SDimitry Andric 
1150fe6060f1SDimitry Andric     // Phase 3 - add any vsetvli instructions needed in the block. Use the
1151fe6060f1SDimitry Andric     // Phase 2 information to avoid adding vsetvlis before the first vector
1152fe6060f1SDimitry Andric     // instruction in the block if the VL/VTYPE is satisfied by its
1153fe6060f1SDimitry Andric     // predecessors.
1154fe6060f1SDimitry Andric     for (MachineBasicBlock &MBB : MF)
1155fe6060f1SDimitry Andric       emitVSETVLIs(MBB);
1156fe6060f1SDimitry Andric   }
1157fe6060f1SDimitry Andric 
1158fe6060f1SDimitry Andric   BlockInfo.clear();
1159fe6060f1SDimitry Andric 
1160fe6060f1SDimitry Andric   return HaveVectorOp;
1161fe6060f1SDimitry Andric }
1162fe6060f1SDimitry Andric 
1163fe6060f1SDimitry Andric /// Returns an instance of the Insert VSETVLI pass.
1164fe6060f1SDimitry Andric FunctionPass *llvm::createRISCVInsertVSETVLIPass() {
1165fe6060f1SDimitry Andric   return new RISCVInsertVSETVLI();
1166fe6060f1SDimitry Andric }
1167