xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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"
297a6dacacSDimitry Andric #include "llvm/ADT/Statistic.h"
30*0fca6ea1SDimitry Andric #include "llvm/CodeGen/LiveDebugVariables.h"
31fe6060f1SDimitry Andric #include "llvm/CodeGen/LiveIntervals.h"
32*0fca6ea1SDimitry Andric #include "llvm/CodeGen/LiveStacks.h"
33fe6060f1SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
34fe6060f1SDimitry Andric #include <queue>
35fe6060f1SDimitry Andric using namespace llvm;
36fe6060f1SDimitry Andric 
37fe6060f1SDimitry Andric #define DEBUG_TYPE "riscv-insert-vsetvli"
3806c3fb27SDimitry Andric #define RISCV_INSERT_VSETVLI_NAME "RISC-V Insert VSETVLI pass"
39*0fca6ea1SDimitry Andric #define RISCV_COALESCE_VSETVLI_NAME "RISC-V Coalesce VSETVLI pass"
40fe6060f1SDimitry Andric 
417a6dacacSDimitry Andric STATISTIC(NumInsertedVSETVL, "Number of VSETVL inst inserted");
42*0fca6ea1SDimitry Andric STATISTIC(NumCoalescedVSETVL, "Number of VSETVL inst coalesced");
4381ad6265SDimitry Andric 
44fe6060f1SDimitry Andric namespace {
45fe6060f1SDimitry Andric 
46*0fca6ea1SDimitry Andric /// Given a virtual register \p Reg, return the corresponding VNInfo for it.
47*0fca6ea1SDimitry Andric /// This will return nullptr if the virtual register is an implicit_def or
48*0fca6ea1SDimitry Andric /// if LiveIntervals is not available.
49*0fca6ea1SDimitry Andric static VNInfo *getVNInfoFromReg(Register Reg, const MachineInstr &MI,
50*0fca6ea1SDimitry Andric                                 const LiveIntervals *LIS) {
51*0fca6ea1SDimitry Andric   assert(Reg.isVirtual());
52*0fca6ea1SDimitry Andric   if (!LIS)
53*0fca6ea1SDimitry Andric     return nullptr;
54*0fca6ea1SDimitry Andric   auto &LI = LIS->getInterval(Reg);
55*0fca6ea1SDimitry Andric   SlotIndex SI = LIS->getSlotIndexes()->getInstructionIndex(MI);
56*0fca6ea1SDimitry Andric   return LI.getVNInfoBefore(SI);
57*0fca6ea1SDimitry Andric }
58*0fca6ea1SDimitry Andric 
5981ad6265SDimitry Andric static unsigned getVLOpNum(const MachineInstr &MI) {
6081ad6265SDimitry Andric   return RISCVII::getVLOpNum(MI.getDesc());
61fe6060f1SDimitry Andric }
62fe6060f1SDimitry Andric 
6381ad6265SDimitry Andric static unsigned getSEWOpNum(const MachineInstr &MI) {
6481ad6265SDimitry Andric   return RISCVII::getSEWOpNum(MI.getDesc());
65fe6060f1SDimitry Andric }
66fe6060f1SDimitry Andric 
67bdd1243dSDimitry Andric static bool isVectorConfigInstr(const MachineInstr &MI) {
68bdd1243dSDimitry Andric   return MI.getOpcode() == RISCV::PseudoVSETVLI ||
69bdd1243dSDimitry Andric          MI.getOpcode() == RISCV::PseudoVSETVLIX0 ||
70bdd1243dSDimitry Andric          MI.getOpcode() == RISCV::PseudoVSETIVLI;
71bdd1243dSDimitry Andric }
72bdd1243dSDimitry Andric 
73bdd1243dSDimitry Andric /// Return true if this is 'vsetvli x0, x0, vtype' which preserves
74bdd1243dSDimitry Andric /// VL and only sets VTYPE.
75bdd1243dSDimitry Andric static bool isVLPreservingConfig(const MachineInstr &MI) {
76bdd1243dSDimitry Andric   if (MI.getOpcode() != RISCV::PseudoVSETVLIX0)
77bdd1243dSDimitry Andric     return false;
78bdd1243dSDimitry Andric   assert(RISCV::X0 == MI.getOperand(1).getReg());
79bdd1243dSDimitry Andric   return RISCV::X0 == MI.getOperand(0).getReg();
80bdd1243dSDimitry Andric }
81bdd1243dSDimitry Andric 
825f757f3fSDimitry Andric static bool isFloatScalarMoveOrScalarSplatInstr(const MachineInstr &MI) {
835f757f3fSDimitry Andric   switch (RISCV::getRVVMCOpcode(MI.getOpcode())) {
845f757f3fSDimitry Andric   default:
855f757f3fSDimitry Andric     return false;
865f757f3fSDimitry Andric   case RISCV::VFMV_S_F:
875f757f3fSDimitry Andric   case RISCV::VFMV_V_F:
885f757f3fSDimitry Andric     return true;
895f757f3fSDimitry Andric   }
90bdd1243dSDimitry Andric }
91bdd1243dSDimitry Andric 
925f757f3fSDimitry Andric static bool isScalarExtractInstr(const MachineInstr &MI) {
935f757f3fSDimitry Andric   switch (RISCV::getRVVMCOpcode(MI.getOpcode())) {
945f757f3fSDimitry Andric   default:
955f757f3fSDimitry Andric     return false;
965f757f3fSDimitry Andric   case RISCV::VMV_X_S:
975f757f3fSDimitry Andric   case RISCV::VFMV_F_S:
985f757f3fSDimitry Andric     return true;
995f757f3fSDimitry Andric   }
1005f757f3fSDimitry Andric }
1015f757f3fSDimitry Andric 
1025f757f3fSDimitry Andric static bool isScalarInsertInstr(const MachineInstr &MI) {
1035f757f3fSDimitry Andric   switch (RISCV::getRVVMCOpcode(MI.getOpcode())) {
10404eeddc0SDimitry Andric   default:
10504eeddc0SDimitry Andric     return false;
106bdd1243dSDimitry Andric   case RISCV::VMV_S_X:
107bdd1243dSDimitry Andric   case RISCV::VFMV_S_F:
10804eeddc0SDimitry Andric     return true;
10904eeddc0SDimitry Andric   }
11004eeddc0SDimitry Andric }
11104eeddc0SDimitry Andric 
11206c3fb27SDimitry Andric static bool isScalarSplatInstr(const MachineInstr &MI) {
1135f757f3fSDimitry Andric   switch (RISCV::getRVVMCOpcode(MI.getOpcode())) {
11406c3fb27SDimitry Andric   default:
11506c3fb27SDimitry Andric     return false;
11606c3fb27SDimitry Andric   case RISCV::VMV_V_I:
11706c3fb27SDimitry Andric   case RISCV::VMV_V_X:
11806c3fb27SDimitry Andric   case RISCV::VFMV_V_F:
11906c3fb27SDimitry Andric     return true;
12006c3fb27SDimitry Andric   }
12106c3fb27SDimitry Andric }
12206c3fb27SDimitry Andric 
12306c3fb27SDimitry Andric static bool isVSlideInstr(const MachineInstr &MI) {
1245f757f3fSDimitry Andric   switch (RISCV::getRVVMCOpcode(MI.getOpcode())) {
12506c3fb27SDimitry Andric   default:
12606c3fb27SDimitry Andric     return false;
12706c3fb27SDimitry Andric   case RISCV::VSLIDEDOWN_VX:
12806c3fb27SDimitry Andric   case RISCV::VSLIDEDOWN_VI:
12906c3fb27SDimitry Andric   case RISCV::VSLIDEUP_VX:
13006c3fb27SDimitry Andric   case RISCV::VSLIDEUP_VI:
13106c3fb27SDimitry Andric     return true;
13206c3fb27SDimitry Andric   }
13306c3fb27SDimitry Andric }
13406c3fb27SDimitry Andric 
135bdd1243dSDimitry Andric /// Get the EEW for a load or store instruction.  Return std::nullopt if MI is
136bdd1243dSDimitry Andric /// not a load or store which ignores SEW.
137bdd1243dSDimitry Andric static std::optional<unsigned> getEEWForLoadStore(const MachineInstr &MI) {
1385f757f3fSDimitry Andric   switch (RISCV::getRVVMCOpcode(MI.getOpcode())) {
139349cc55cSDimitry Andric   default:
140bdd1243dSDimitry Andric     return std::nullopt;
141bdd1243dSDimitry Andric   case RISCV::VLE8_V:
142bdd1243dSDimitry Andric   case RISCV::VLSE8_V:
143bdd1243dSDimitry Andric   case RISCV::VSE8_V:
144bdd1243dSDimitry Andric   case RISCV::VSSE8_V:
14581ad6265SDimitry Andric     return 8;
146bdd1243dSDimitry Andric   case RISCV::VLE16_V:
147bdd1243dSDimitry Andric   case RISCV::VLSE16_V:
148bdd1243dSDimitry Andric   case RISCV::VSE16_V:
149bdd1243dSDimitry Andric   case RISCV::VSSE16_V:
15081ad6265SDimitry Andric     return 16;
151bdd1243dSDimitry Andric   case RISCV::VLE32_V:
152bdd1243dSDimitry Andric   case RISCV::VLSE32_V:
153bdd1243dSDimitry Andric   case RISCV::VSE32_V:
154bdd1243dSDimitry Andric   case RISCV::VSSE32_V:
15581ad6265SDimitry Andric     return 32;
156bdd1243dSDimitry Andric   case RISCV::VLE64_V:
157bdd1243dSDimitry Andric   case RISCV::VLSE64_V:
158bdd1243dSDimitry Andric   case RISCV::VSE64_V:
159bdd1243dSDimitry Andric   case RISCV::VSSE64_V:
16081ad6265SDimitry Andric     return 64;
16181ad6265SDimitry Andric   }
162349cc55cSDimitry Andric }
163349cc55cSDimitry Andric 
164*0fca6ea1SDimitry Andric static bool isNonZeroLoadImmediate(const MachineInstr &MI) {
1655f757f3fSDimitry Andric   return MI.getOpcode() == RISCV::ADDI &&
1665f757f3fSDimitry Andric     MI.getOperand(1).isReg() && MI.getOperand(2).isImm() &&
1675f757f3fSDimitry Andric     MI.getOperand(1).getReg() == RISCV::X0 &&
1685f757f3fSDimitry Andric     MI.getOperand(2).getImm() != 0;
1695f757f3fSDimitry Andric }
1705f757f3fSDimitry Andric 
17181ad6265SDimitry Andric /// Return true if this is an operation on mask registers.  Note that
17281ad6265SDimitry Andric /// this includes both arithmetic/logical ops and load/store (vlm/vsm).
17381ad6265SDimitry Andric static bool isMaskRegOp(const MachineInstr &MI) {
174bdd1243dSDimitry Andric   if (!RISCVII::hasSEWOp(MI.getDesc().TSFlags))
175bdd1243dSDimitry Andric     return false;
17681ad6265SDimitry Andric   const unsigned Log2SEW = MI.getOperand(getSEWOpNum(MI)).getImm();
17781ad6265SDimitry Andric   // A Log2SEW of 0 is an operation on mask registers only.
17881ad6265SDimitry Andric   return Log2SEW == 0;
17981ad6265SDimitry Andric }
18081ad6265SDimitry Andric 
18106c3fb27SDimitry Andric /// Return true if the inactive elements in the result are entirely undefined.
18206c3fb27SDimitry Andric /// Note that this is different from "agnostic" as defined by the vector
18306c3fb27SDimitry Andric /// specification.  Agnostic requires each lane to either be undisturbed, or
18406c3fb27SDimitry Andric /// take the value -1; no other value is allowed.
185*0fca6ea1SDimitry Andric static bool hasUndefinedMergeOp(const MachineInstr &MI) {
18606c3fb27SDimitry Andric 
18706c3fb27SDimitry Andric   unsigned UseOpIdx;
18806c3fb27SDimitry Andric   if (!MI.isRegTiedToUseOperand(0, &UseOpIdx))
18906c3fb27SDimitry Andric     // If there is no passthrough operand, then the pass through
19006c3fb27SDimitry Andric     // lanes are undefined.
19106c3fb27SDimitry Andric     return true;
19206c3fb27SDimitry Andric 
193*0fca6ea1SDimitry Andric   // All undefined passthrus should be $noreg: see
194*0fca6ea1SDimitry Andric   // RISCVDAGToDAGISel::doPeepholeNoRegPassThru
19506c3fb27SDimitry Andric   const MachineOperand &UseMO = MI.getOperand(UseOpIdx);
196*0fca6ea1SDimitry Andric   return UseMO.getReg() == RISCV::NoRegister || UseMO.isUndef();
19706c3fb27SDimitry Andric }
19806c3fb27SDimitry Andric 
19981ad6265SDimitry Andric /// Which subfields of VL or VTYPE have values we need to preserve?
20081ad6265SDimitry Andric struct DemandedFields {
201bdd1243dSDimitry Andric   // Some unknown property of VL is used.  If demanded, must preserve entire
202bdd1243dSDimitry Andric   // value.
203bdd1243dSDimitry Andric   bool VLAny = false;
204bdd1243dSDimitry Andric   // Only zero vs non-zero is used. If demanded, can change non-zero values.
205bdd1243dSDimitry Andric   bool VLZeroness = false;
20606c3fb27SDimitry Andric   // What properties of SEW we need to preserve.
20706c3fb27SDimitry Andric   enum : uint8_t {
2085f757f3fSDimitry Andric     SEWEqual = 3,              // The exact value of SEW needs to be preserved.
2095f757f3fSDimitry Andric     SEWGreaterThanOrEqual = 2, // SEW can be changed as long as it's greater
21006c3fb27SDimitry Andric                                // than or equal to the original value.
2115f757f3fSDimitry Andric     SEWGreaterThanOrEqualAndLessThan64 =
2125f757f3fSDimitry Andric         1,      // SEW can be changed as long as it's greater
2135f757f3fSDimitry Andric                 // than or equal to the original value, but must be less
2145f757f3fSDimitry Andric                 // than 64.
21506c3fb27SDimitry Andric     SEWNone = 0 // We don't need to preserve SEW at all.
21606c3fb27SDimitry Andric   } SEW = SEWNone;
217*0fca6ea1SDimitry Andric   enum : uint8_t {
218*0fca6ea1SDimitry Andric     LMULEqual = 2, // The exact value of LMUL needs to be preserved.
219*0fca6ea1SDimitry Andric     LMULLessThanOrEqualToM1 = 1, // We can use any LMUL <= M1.
220*0fca6ea1SDimitry Andric     LMULNone = 0                 // We don't need to preserve LMUL at all.
221*0fca6ea1SDimitry Andric   } LMUL = LMULNone;
22281ad6265SDimitry Andric   bool SEWLMULRatio = false;
22381ad6265SDimitry Andric   bool TailPolicy = false;
22481ad6265SDimitry Andric   bool MaskPolicy = false;
22581ad6265SDimitry Andric 
22681ad6265SDimitry Andric   // Return true if any part of VTYPE was used
227bdd1243dSDimitry Andric   bool usedVTYPE() const {
22881ad6265SDimitry Andric     return SEW || LMUL || SEWLMULRatio || TailPolicy || MaskPolicy;
22981ad6265SDimitry Andric   }
23081ad6265SDimitry Andric 
231bdd1243dSDimitry Andric   // Return true if any property of VL was used
232bdd1243dSDimitry Andric   bool usedVL() {
233bdd1243dSDimitry Andric     return VLAny || VLZeroness;
234bdd1243dSDimitry Andric   }
235bdd1243dSDimitry Andric 
23681ad6265SDimitry Andric   // Mark all VTYPE subfields and properties as demanded
23781ad6265SDimitry Andric   void demandVTYPE() {
23806c3fb27SDimitry Andric     SEW = SEWEqual;
239*0fca6ea1SDimitry Andric     LMUL = LMULEqual;
24081ad6265SDimitry Andric     SEWLMULRatio = true;
24181ad6265SDimitry Andric     TailPolicy = true;
24281ad6265SDimitry Andric     MaskPolicy = true;
24381ad6265SDimitry Andric   }
244bdd1243dSDimitry Andric 
245bdd1243dSDimitry Andric   // Mark all VL properties as demanded
246bdd1243dSDimitry Andric   void demandVL() {
247bdd1243dSDimitry Andric     VLAny = true;
248bdd1243dSDimitry Andric     VLZeroness = true;
249bdd1243dSDimitry Andric   }
250bdd1243dSDimitry Andric 
251*0fca6ea1SDimitry Andric   static DemandedFields all() {
252*0fca6ea1SDimitry Andric     DemandedFields DF;
253*0fca6ea1SDimitry Andric     DF.demandVTYPE();
254*0fca6ea1SDimitry Andric     DF.demandVL();
255*0fca6ea1SDimitry Andric     return DF;
256*0fca6ea1SDimitry Andric   }
257*0fca6ea1SDimitry Andric 
258*0fca6ea1SDimitry Andric   // Make this the result of demanding both the fields in this and B.
259*0fca6ea1SDimitry Andric   void doUnion(const DemandedFields &B) {
260*0fca6ea1SDimitry Andric     VLAny |= B.VLAny;
261*0fca6ea1SDimitry Andric     VLZeroness |= B.VLZeroness;
262*0fca6ea1SDimitry Andric     SEW = std::max(SEW, B.SEW);
263*0fca6ea1SDimitry Andric     LMUL = std::max(LMUL, B.LMUL);
264*0fca6ea1SDimitry Andric     SEWLMULRatio |= B.SEWLMULRatio;
265*0fca6ea1SDimitry Andric     TailPolicy |= B.TailPolicy;
266*0fca6ea1SDimitry Andric     MaskPolicy |= B.MaskPolicy;
267*0fca6ea1SDimitry Andric   }
268*0fca6ea1SDimitry Andric 
269bdd1243dSDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
270bdd1243dSDimitry Andric   /// Support for debugging, callable in GDB: V->dump()
271bdd1243dSDimitry Andric   LLVM_DUMP_METHOD void dump() const {
272bdd1243dSDimitry Andric     print(dbgs());
273bdd1243dSDimitry Andric     dbgs() << "\n";
274bdd1243dSDimitry Andric   }
275bdd1243dSDimitry Andric 
276bdd1243dSDimitry Andric   /// Implement operator<<.
277bdd1243dSDimitry Andric   void print(raw_ostream &OS) const {
278bdd1243dSDimitry Andric     OS << "{";
279bdd1243dSDimitry Andric     OS << "VLAny=" << VLAny << ", ";
280bdd1243dSDimitry Andric     OS << "VLZeroness=" << VLZeroness << ", ";
28106c3fb27SDimitry Andric     OS << "SEW=";
28206c3fb27SDimitry Andric     switch (SEW) {
28306c3fb27SDimitry Andric     case SEWEqual:
28406c3fb27SDimitry Andric       OS << "SEWEqual";
28506c3fb27SDimitry Andric       break;
28606c3fb27SDimitry Andric     case SEWGreaterThanOrEqual:
28706c3fb27SDimitry Andric       OS << "SEWGreaterThanOrEqual";
28806c3fb27SDimitry Andric       break;
2895f757f3fSDimitry Andric     case SEWGreaterThanOrEqualAndLessThan64:
2905f757f3fSDimitry Andric       OS << "SEWGreaterThanOrEqualAndLessThan64";
2915f757f3fSDimitry Andric       break;
29206c3fb27SDimitry Andric     case SEWNone:
29306c3fb27SDimitry Andric       OS << "SEWNone";
29406c3fb27SDimitry Andric       break;
29506c3fb27SDimitry Andric     };
29606c3fb27SDimitry Andric     OS << ", ";
297*0fca6ea1SDimitry Andric     OS << "LMUL=";
298*0fca6ea1SDimitry Andric     switch (LMUL) {
299*0fca6ea1SDimitry Andric     case LMULEqual:
300*0fca6ea1SDimitry Andric       OS << "LMULEqual";
301*0fca6ea1SDimitry Andric       break;
302*0fca6ea1SDimitry Andric     case LMULLessThanOrEqualToM1:
303*0fca6ea1SDimitry Andric       OS << "LMULLessThanOrEqualToM1";
304*0fca6ea1SDimitry Andric       break;
305*0fca6ea1SDimitry Andric     case LMULNone:
306*0fca6ea1SDimitry Andric       OS << "LMULNone";
307*0fca6ea1SDimitry Andric       break;
308*0fca6ea1SDimitry Andric     };
309*0fca6ea1SDimitry Andric     OS << ", ";
310bdd1243dSDimitry Andric     OS << "SEWLMULRatio=" << SEWLMULRatio << ", ";
311bdd1243dSDimitry Andric     OS << "TailPolicy=" << TailPolicy << ", ";
312bdd1243dSDimitry Andric     OS << "MaskPolicy=" << MaskPolicy;
313bdd1243dSDimitry Andric     OS << "}";
314bdd1243dSDimitry Andric   }
315bdd1243dSDimitry Andric #endif
31681ad6265SDimitry Andric };
31781ad6265SDimitry Andric 
318bdd1243dSDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
319bdd1243dSDimitry Andric LLVM_ATTRIBUTE_USED
320bdd1243dSDimitry Andric inline raw_ostream &operator<<(raw_ostream &OS, const DemandedFields &DF) {
321bdd1243dSDimitry Andric   DF.print(OS);
322bdd1243dSDimitry Andric   return OS;
323bdd1243dSDimitry Andric }
324bdd1243dSDimitry Andric #endif
325bdd1243dSDimitry Andric 
326*0fca6ea1SDimitry Andric static bool isLMUL1OrSmaller(RISCVII::VLMUL LMUL) {
327*0fca6ea1SDimitry Andric   auto [LMul, Fractional] = RISCVVType::decodeVLMUL(LMUL);
328*0fca6ea1SDimitry Andric   return Fractional || LMul == 1;
329*0fca6ea1SDimitry Andric }
330*0fca6ea1SDimitry Andric 
33106c3fb27SDimitry Andric /// Return true if moving from CurVType to NewVType is
33206c3fb27SDimitry Andric /// indistinguishable from the perspective of an instruction (or set
33306c3fb27SDimitry Andric /// of instructions) which use only the Used subfields and properties.
33406c3fb27SDimitry Andric static bool areCompatibleVTYPEs(uint64_t CurVType, uint64_t NewVType,
33581ad6265SDimitry Andric                                 const DemandedFields &Used) {
3365f757f3fSDimitry Andric   switch (Used.SEW) {
3375f757f3fSDimitry Andric   case DemandedFields::SEWNone:
3385f757f3fSDimitry Andric     break;
3395f757f3fSDimitry Andric   case DemandedFields::SEWEqual:
3405f757f3fSDimitry Andric     if (RISCVVType::getSEW(CurVType) != RISCVVType::getSEW(NewVType))
34106c3fb27SDimitry Andric       return false;
3425f757f3fSDimitry Andric     break;
3435f757f3fSDimitry Andric   case DemandedFields::SEWGreaterThanOrEqual:
3445f757f3fSDimitry Andric     if (RISCVVType::getSEW(NewVType) < RISCVVType::getSEW(CurVType))
34581ad6265SDimitry Andric       return false;
3465f757f3fSDimitry Andric     break;
3475f757f3fSDimitry Andric   case DemandedFields::SEWGreaterThanOrEqualAndLessThan64:
3485f757f3fSDimitry Andric     if (RISCVVType::getSEW(NewVType) < RISCVVType::getSEW(CurVType) ||
3495f757f3fSDimitry Andric         RISCVVType::getSEW(NewVType) >= 64)
3505f757f3fSDimitry Andric       return false;
3515f757f3fSDimitry Andric     break;
3525f757f3fSDimitry Andric   }
35381ad6265SDimitry Andric 
354*0fca6ea1SDimitry Andric   switch (Used.LMUL) {
355*0fca6ea1SDimitry Andric   case DemandedFields::LMULNone:
356*0fca6ea1SDimitry Andric     break;
357*0fca6ea1SDimitry Andric   case DemandedFields::LMULEqual:
358*0fca6ea1SDimitry Andric     if (RISCVVType::getVLMUL(CurVType) != RISCVVType::getVLMUL(NewVType))
35981ad6265SDimitry Andric       return false;
360*0fca6ea1SDimitry Andric     break;
361*0fca6ea1SDimitry Andric   case DemandedFields::LMULLessThanOrEqualToM1:
362*0fca6ea1SDimitry Andric     if (!isLMUL1OrSmaller(RISCVVType::getVLMUL(NewVType)))
363*0fca6ea1SDimitry Andric       return false;
364*0fca6ea1SDimitry Andric     break;
365*0fca6ea1SDimitry Andric   }
36681ad6265SDimitry Andric 
36781ad6265SDimitry Andric   if (Used.SEWLMULRatio) {
36806c3fb27SDimitry Andric     auto Ratio1 = RISCVVType::getSEWLMULRatio(RISCVVType::getSEW(CurVType),
36906c3fb27SDimitry Andric                                               RISCVVType::getVLMUL(CurVType));
37006c3fb27SDimitry Andric     auto Ratio2 = RISCVVType::getSEWLMULRatio(RISCVVType::getSEW(NewVType),
37106c3fb27SDimitry Andric                                               RISCVVType::getVLMUL(NewVType));
37281ad6265SDimitry Andric     if (Ratio1 != Ratio2)
37381ad6265SDimitry Andric       return false;
37481ad6265SDimitry Andric   }
37581ad6265SDimitry Andric 
37606c3fb27SDimitry Andric   if (Used.TailPolicy && RISCVVType::isTailAgnostic(CurVType) !=
37706c3fb27SDimitry Andric                              RISCVVType::isTailAgnostic(NewVType))
37881ad6265SDimitry Andric     return false;
37906c3fb27SDimitry Andric   if (Used.MaskPolicy && RISCVVType::isMaskAgnostic(CurVType) !=
38006c3fb27SDimitry Andric                              RISCVVType::isMaskAgnostic(NewVType))
38181ad6265SDimitry Andric     return false;
38281ad6265SDimitry Andric   return true;
38381ad6265SDimitry Andric }
38481ad6265SDimitry Andric 
38581ad6265SDimitry Andric /// Return the fields and properties demanded by the provided instruction.
386*0fca6ea1SDimitry Andric DemandedFields getDemanded(const MachineInstr &MI, const RISCVSubtarget *ST) {
387*0fca6ea1SDimitry Andric   // This function works in coalesceVSETVLI too. We can still use the value of a
388*0fca6ea1SDimitry Andric   // SEW, VL, or Policy operand even though it might not be the exact value in
389*0fca6ea1SDimitry Andric   // the VL or VTYPE, since we only care about what the instruction originally
390*0fca6ea1SDimitry Andric   // demanded.
39181ad6265SDimitry Andric 
39281ad6265SDimitry Andric   // Most instructions don't use any of these subfeilds.
39381ad6265SDimitry Andric   DemandedFields Res;
39481ad6265SDimitry Andric   // Start conservative if registers are used
395*0fca6ea1SDimitry Andric   if (MI.isCall() || MI.isInlineAsm() ||
396*0fca6ea1SDimitry Andric       MI.readsRegister(RISCV::VL, /*TRI=*/nullptr))
39706c3fb27SDimitry Andric     Res.demandVL();
398*0fca6ea1SDimitry Andric   if (MI.isCall() || MI.isInlineAsm() ||
399*0fca6ea1SDimitry Andric       MI.readsRegister(RISCV::VTYPE, /*TRI=*/nullptr))
40081ad6265SDimitry Andric     Res.demandVTYPE();
40181ad6265SDimitry Andric   // Start conservative on the unlowered form too
40281ad6265SDimitry Andric   uint64_t TSFlags = MI.getDesc().TSFlags;
40381ad6265SDimitry Andric   if (RISCVII::hasSEWOp(TSFlags)) {
40481ad6265SDimitry Andric     Res.demandVTYPE();
40581ad6265SDimitry Andric     if (RISCVII::hasVLOp(TSFlags))
406*0fca6ea1SDimitry Andric       if (const MachineOperand &VLOp = MI.getOperand(getVLOpNum(MI));
407*0fca6ea1SDimitry Andric           !VLOp.isReg() || !VLOp.isUndef())
408bdd1243dSDimitry Andric         Res.demandVL();
409bdd1243dSDimitry Andric 
410bdd1243dSDimitry Andric     // Behavior is independent of mask policy.
411bdd1243dSDimitry Andric     if (!RISCVII::usesMaskPolicy(TSFlags))
412bdd1243dSDimitry Andric       Res.MaskPolicy = false;
41381ad6265SDimitry Andric   }
41481ad6265SDimitry Andric 
41581ad6265SDimitry Andric   // Loads and stores with implicit EEW do not demand SEW or LMUL directly.
41681ad6265SDimitry Andric   // They instead demand the ratio of the two which is used in computing
41781ad6265SDimitry Andric   // EMUL, but which allows us the flexibility to change SEW and LMUL
41881ad6265SDimitry Andric   // provided we don't change the ratio.
41981ad6265SDimitry Andric   // Note: We assume that the instructions initial SEW is the EEW encoded
42081ad6265SDimitry Andric   // in the opcode.  This is asserted when constructing the VSETVLIInfo.
42181ad6265SDimitry Andric   if (getEEWForLoadStore(MI)) {
42206c3fb27SDimitry Andric     Res.SEW = DemandedFields::SEWNone;
423*0fca6ea1SDimitry Andric     Res.LMUL = DemandedFields::LMULNone;
42481ad6265SDimitry Andric   }
42581ad6265SDimitry Andric 
42681ad6265SDimitry Andric   // Store instructions don't use the policy fields.
42781ad6265SDimitry Andric   if (RISCVII::hasSEWOp(TSFlags) && MI.getNumExplicitDefs() == 0) {
42881ad6265SDimitry Andric     Res.TailPolicy = false;
42981ad6265SDimitry Andric     Res.MaskPolicy = false;
43081ad6265SDimitry Andric   }
43181ad6265SDimitry Andric 
43281ad6265SDimitry Andric   // If this is a mask reg operation, it only cares about VLMAX.
43381ad6265SDimitry Andric   // TODO: Possible extensions to this logic
43481ad6265SDimitry Andric   // * Probably ok if available VLMax is larger than demanded
43581ad6265SDimitry Andric   // * The policy bits can probably be ignored..
43681ad6265SDimitry Andric   if (isMaskRegOp(MI)) {
43706c3fb27SDimitry Andric     Res.SEW = DemandedFields::SEWNone;
438*0fca6ea1SDimitry Andric     Res.LMUL = DemandedFields::LMULNone;
43981ad6265SDimitry Andric   }
44081ad6265SDimitry Andric 
441bdd1243dSDimitry Andric   // For vmv.s.x and vfmv.s.f, there are only two behaviors, VL = 0 and VL > 0.
4425f757f3fSDimitry Andric   if (isScalarInsertInstr(MI)) {
443*0fca6ea1SDimitry Andric     Res.LMUL = DemandedFields::LMULNone;
444bdd1243dSDimitry Andric     Res.SEWLMULRatio = false;
445bdd1243dSDimitry Andric     Res.VLAny = false;
44606c3fb27SDimitry Andric     // For vmv.s.x and vfmv.s.f, if the merge operand is *undefined*, we don't
44706c3fb27SDimitry Andric     // need to preserve any other bits and are thus compatible with any larger,
44806c3fb27SDimitry Andric     // etype and can disregard policy bits.  Warning: It's tempting to try doing
44906c3fb27SDimitry Andric     // this for any tail agnostic operation, but we can't as TA requires
45006c3fb27SDimitry Andric     // tail lanes to either be the original value or -1.  We are writing
45106c3fb27SDimitry Andric     // unknown bits to the lanes here.
452*0fca6ea1SDimitry Andric     if (hasUndefinedMergeOp(MI)) {
4535f757f3fSDimitry Andric       if (isFloatScalarMoveOrScalarSplatInstr(MI) && !ST->hasVInstructionsF64())
4545f757f3fSDimitry Andric         Res.SEW = DemandedFields::SEWGreaterThanOrEqualAndLessThan64;
4555f757f3fSDimitry Andric       else
45606c3fb27SDimitry Andric         Res.SEW = DemandedFields::SEWGreaterThanOrEqual;
45706c3fb27SDimitry Andric       Res.TailPolicy = false;
45806c3fb27SDimitry Andric     }
459bdd1243dSDimitry Andric   }
460bdd1243dSDimitry Andric 
4615f757f3fSDimitry Andric   // vmv.x.s, and vmv.f.s are unconditional and ignore everything except SEW.
4625f757f3fSDimitry Andric   if (isScalarExtractInstr(MI)) {
4635f757f3fSDimitry Andric     assert(!RISCVII::hasVLOp(TSFlags));
464*0fca6ea1SDimitry Andric     Res.LMUL = DemandedFields::LMULNone;
4655f757f3fSDimitry Andric     Res.SEWLMULRatio = false;
4665f757f3fSDimitry Andric     Res.TailPolicy = false;
4675f757f3fSDimitry Andric     Res.MaskPolicy = false;
4685f757f3fSDimitry Andric   }
4695f757f3fSDimitry Andric 
470*0fca6ea1SDimitry Andric   if (RISCVII::hasVLOp(MI.getDesc().TSFlags)) {
471*0fca6ea1SDimitry Andric     const MachineOperand &VLOp = MI.getOperand(getVLOpNum(MI));
472*0fca6ea1SDimitry Andric     // A slidedown/slideup with an *undefined* merge op can freely clobber
473*0fca6ea1SDimitry Andric     // elements not copied from the source vector (e.g. masked off, tail, or
474*0fca6ea1SDimitry Andric     // slideup's prefix). Notes:
475*0fca6ea1SDimitry Andric     // * We can't modify SEW here since the slide amount is in units of SEW.
476*0fca6ea1SDimitry Andric     // * VL=1 is special only because we have existing support for zero vs
477*0fca6ea1SDimitry Andric     //   non-zero VL.  We could generalize this if we had a VL > C predicate.
478*0fca6ea1SDimitry Andric     // * The LMUL1 restriction is for machines whose latency may depend on VL.
479*0fca6ea1SDimitry Andric     // * As above, this is only legal for tail "undefined" not "agnostic".
480*0fca6ea1SDimitry Andric     if (isVSlideInstr(MI) && VLOp.isImm() && VLOp.getImm() == 1 &&
481*0fca6ea1SDimitry Andric         hasUndefinedMergeOp(MI)) {
482*0fca6ea1SDimitry Andric       Res.VLAny = false;
483*0fca6ea1SDimitry Andric       Res.VLZeroness = true;
484*0fca6ea1SDimitry Andric       Res.LMUL = DemandedFields::LMULLessThanOrEqualToM1;
485*0fca6ea1SDimitry Andric       Res.TailPolicy = false;
486*0fca6ea1SDimitry Andric     }
487*0fca6ea1SDimitry Andric 
488*0fca6ea1SDimitry Andric     // A tail undefined vmv.v.i/x or vfmv.v.f with VL=1 can be treated in the
489*0fca6ea1SDimitry Andric     // same semantically as vmv.s.x.  This is particularly useful since we don't
490*0fca6ea1SDimitry Andric     // have an immediate form of vmv.s.x, and thus frequently use vmv.v.i in
491*0fca6ea1SDimitry Andric     // it's place. Since a splat is non-constant time in LMUL, we do need to be
492*0fca6ea1SDimitry Andric     // careful to not increase the number of active vector registers (unlike for
493*0fca6ea1SDimitry Andric     // vmv.s.x.)
494*0fca6ea1SDimitry Andric     if (isScalarSplatInstr(MI) && VLOp.isImm() && VLOp.getImm() == 1 &&
495*0fca6ea1SDimitry Andric         hasUndefinedMergeOp(MI)) {
496*0fca6ea1SDimitry Andric       Res.LMUL = DemandedFields::LMULLessThanOrEqualToM1;
497*0fca6ea1SDimitry Andric       Res.SEWLMULRatio = false;
498*0fca6ea1SDimitry Andric       Res.VLAny = false;
499*0fca6ea1SDimitry Andric       if (isFloatScalarMoveOrScalarSplatInstr(MI) && !ST->hasVInstructionsF64())
500*0fca6ea1SDimitry Andric         Res.SEW = DemandedFields::SEWGreaterThanOrEqualAndLessThan64;
501*0fca6ea1SDimitry Andric       else
502*0fca6ea1SDimitry Andric         Res.SEW = DemandedFields::SEWGreaterThanOrEqual;
503*0fca6ea1SDimitry Andric       Res.TailPolicy = false;
504*0fca6ea1SDimitry Andric     }
505*0fca6ea1SDimitry Andric   }
506*0fca6ea1SDimitry Andric 
50781ad6265SDimitry Andric   return Res;
50881ad6265SDimitry Andric }
50981ad6265SDimitry Andric 
51081ad6265SDimitry Andric /// Defines the abstract state with which the forward dataflow models the
51181ad6265SDimitry Andric /// values of the VL and VTYPE registers after insertion.
51281ad6265SDimitry Andric class VSETVLIInfo {
513*0fca6ea1SDimitry Andric   struct AVLDef {
514*0fca6ea1SDimitry Andric     // Every AVLDef should have a VNInfo, unless we're running without
515*0fca6ea1SDimitry Andric     // LiveIntervals in which case this will be nullptr.
516*0fca6ea1SDimitry Andric     const VNInfo *ValNo;
517*0fca6ea1SDimitry Andric     Register DefReg;
518*0fca6ea1SDimitry Andric   };
51981ad6265SDimitry Andric   union {
520*0fca6ea1SDimitry Andric     AVLDef AVLRegDef;
52181ad6265SDimitry Andric     unsigned AVLImm;
52281ad6265SDimitry Andric   };
52381ad6265SDimitry Andric 
52481ad6265SDimitry Andric   enum : uint8_t {
52581ad6265SDimitry Andric     Uninitialized,
52681ad6265SDimitry Andric     AVLIsReg,
52781ad6265SDimitry Andric     AVLIsImm,
528*0fca6ea1SDimitry Andric     AVLIsVLMAX,
529*0fca6ea1SDimitry Andric     Unknown, // AVL and VTYPE are fully unknown
53081ad6265SDimitry Andric   } State = Uninitialized;
53181ad6265SDimitry Andric 
53281ad6265SDimitry Andric   // Fields from VTYPE.
53381ad6265SDimitry Andric   RISCVII::VLMUL VLMul = RISCVII::LMUL_1;
53481ad6265SDimitry Andric   uint8_t SEW = 0;
53581ad6265SDimitry Andric   uint8_t TailAgnostic : 1;
53681ad6265SDimitry Andric   uint8_t MaskAgnostic : 1;
53781ad6265SDimitry Andric   uint8_t SEWLMULRatioOnly : 1;
53881ad6265SDimitry Andric 
53981ad6265SDimitry Andric public:
54081ad6265SDimitry Andric   VSETVLIInfo()
54181ad6265SDimitry Andric       : AVLImm(0), TailAgnostic(false), MaskAgnostic(false),
54281ad6265SDimitry Andric         SEWLMULRatioOnly(false) {}
54381ad6265SDimitry Andric 
54481ad6265SDimitry Andric   static VSETVLIInfo getUnknown() {
54581ad6265SDimitry Andric     VSETVLIInfo Info;
54681ad6265SDimitry Andric     Info.setUnknown();
54781ad6265SDimitry Andric     return Info;
54881ad6265SDimitry Andric   }
54981ad6265SDimitry Andric 
55081ad6265SDimitry Andric   bool isValid() const { return State != Uninitialized; }
55181ad6265SDimitry Andric   void setUnknown() { State = Unknown; }
55281ad6265SDimitry Andric   bool isUnknown() const { return State == Unknown; }
55381ad6265SDimitry Andric 
554*0fca6ea1SDimitry Andric   void setAVLRegDef(const VNInfo *VNInfo, Register AVLReg) {
555*0fca6ea1SDimitry Andric     assert(AVLReg.isVirtual());
556*0fca6ea1SDimitry Andric     AVLRegDef.ValNo = VNInfo;
557*0fca6ea1SDimitry Andric     AVLRegDef.DefReg = AVLReg;
55881ad6265SDimitry Andric     State = AVLIsReg;
55981ad6265SDimitry Andric   }
56081ad6265SDimitry Andric 
56181ad6265SDimitry Andric   void setAVLImm(unsigned Imm) {
56281ad6265SDimitry Andric     AVLImm = Imm;
56381ad6265SDimitry Andric     State = AVLIsImm;
56481ad6265SDimitry Andric   }
56581ad6265SDimitry Andric 
566*0fca6ea1SDimitry Andric   void setAVLVLMAX() { State = AVLIsVLMAX; }
567*0fca6ea1SDimitry Andric 
56881ad6265SDimitry Andric   bool hasAVLImm() const { return State == AVLIsImm; }
56981ad6265SDimitry Andric   bool hasAVLReg() const { return State == AVLIsReg; }
570*0fca6ea1SDimitry Andric   bool hasAVLVLMAX() const { return State == AVLIsVLMAX; }
57181ad6265SDimitry Andric   Register getAVLReg() const {
572*0fca6ea1SDimitry Andric     assert(hasAVLReg() && AVLRegDef.DefReg.isVirtual());
573*0fca6ea1SDimitry Andric     return AVLRegDef.DefReg;
57481ad6265SDimitry Andric   }
57581ad6265SDimitry Andric   unsigned getAVLImm() const {
57681ad6265SDimitry Andric     assert(hasAVLImm());
57781ad6265SDimitry Andric     return AVLImm;
57881ad6265SDimitry Andric   }
579*0fca6ea1SDimitry Andric   const VNInfo *getAVLVNInfo() const {
580*0fca6ea1SDimitry Andric     assert(hasAVLReg());
581*0fca6ea1SDimitry Andric     return AVLRegDef.ValNo;
582*0fca6ea1SDimitry Andric   }
583*0fca6ea1SDimitry Andric   // Most AVLIsReg infos will have a single defining MachineInstr, unless it was
584*0fca6ea1SDimitry Andric   // a PHI node. In that case getAVLVNInfo()->def will point to the block
585*0fca6ea1SDimitry Andric   // boundary slot and this will return nullptr.  If LiveIntervals isn't
586*0fca6ea1SDimitry Andric   // available, nullptr is also returned.
587*0fca6ea1SDimitry Andric   const MachineInstr *getAVLDefMI(const LiveIntervals *LIS) const {
588*0fca6ea1SDimitry Andric     assert(hasAVLReg());
589*0fca6ea1SDimitry Andric     if (!LIS || getAVLVNInfo()->isPHIDef())
590*0fca6ea1SDimitry Andric       return nullptr;
591*0fca6ea1SDimitry Andric     auto *MI = LIS->getInstructionFromIndex(getAVLVNInfo()->def);
592*0fca6ea1SDimitry Andric     assert(MI);
593*0fca6ea1SDimitry Andric     return MI;
594*0fca6ea1SDimitry Andric   }
59581ad6265SDimitry Andric 
5965f757f3fSDimitry Andric   void setAVL(VSETVLIInfo Info) {
5975f757f3fSDimitry Andric     assert(Info.isValid());
5985f757f3fSDimitry Andric     if (Info.isUnknown())
5995f757f3fSDimitry Andric       setUnknown();
6005f757f3fSDimitry Andric     else if (Info.hasAVLReg())
601*0fca6ea1SDimitry Andric       setAVLRegDef(Info.getAVLVNInfo(), Info.getAVLReg());
602*0fca6ea1SDimitry Andric     else if (Info.hasAVLVLMAX())
603*0fca6ea1SDimitry Andric       setAVLVLMAX();
6045f757f3fSDimitry Andric     else {
6055f757f3fSDimitry Andric       assert(Info.hasAVLImm());
6065f757f3fSDimitry Andric       setAVLImm(Info.getAVLImm());
6075f757f3fSDimitry Andric     }
6085f757f3fSDimitry Andric   }
6095f757f3fSDimitry Andric 
61081ad6265SDimitry Andric   unsigned getSEW() const { return SEW; }
61181ad6265SDimitry Andric   RISCVII::VLMUL getVLMUL() const { return VLMul; }
6125f757f3fSDimitry Andric   bool getTailAgnostic() const { return TailAgnostic; }
6135f757f3fSDimitry Andric   bool getMaskAgnostic() const { return MaskAgnostic; }
61481ad6265SDimitry Andric 
615*0fca6ea1SDimitry Andric   bool hasNonZeroAVL(const LiveIntervals *LIS) const {
61681ad6265SDimitry Andric     if (hasAVLImm())
61781ad6265SDimitry Andric       return getAVLImm() > 0;
61806c3fb27SDimitry Andric     if (hasAVLReg()) {
619*0fca6ea1SDimitry Andric       if (auto *DefMI = getAVLDefMI(LIS))
620*0fca6ea1SDimitry Andric         return isNonZeroLoadImmediate(*DefMI);
62106c3fb27SDimitry Andric     }
622*0fca6ea1SDimitry Andric     if (hasAVLVLMAX())
623*0fca6ea1SDimitry Andric       return true;
62481ad6265SDimitry Andric     return false;
62581ad6265SDimitry Andric   }
62681ad6265SDimitry Andric 
62706c3fb27SDimitry Andric   bool hasEquallyZeroAVL(const VSETVLIInfo &Other,
628*0fca6ea1SDimitry Andric                          const LiveIntervals *LIS) const {
629bdd1243dSDimitry Andric     if (hasSameAVL(Other))
630bdd1243dSDimitry Andric       return true;
631*0fca6ea1SDimitry Andric     return (hasNonZeroAVL(LIS) && Other.hasNonZeroAVL(LIS));
632bdd1243dSDimitry Andric   }
633bdd1243dSDimitry Andric 
634*0fca6ea1SDimitry Andric   bool hasSameAVLLatticeValue(const VSETVLIInfo &Other) const {
635*0fca6ea1SDimitry Andric     if (hasAVLReg() && Other.hasAVLReg()) {
636*0fca6ea1SDimitry Andric       assert(!getAVLVNInfo() == !Other.getAVLVNInfo() &&
637*0fca6ea1SDimitry Andric              "we either have intervals or we don't");
638*0fca6ea1SDimitry Andric       if (!getAVLVNInfo())
63981ad6265SDimitry Andric         return getAVLReg() == Other.getAVLReg();
640*0fca6ea1SDimitry Andric       return getAVLVNInfo()->id == Other.getAVLVNInfo()->id &&
641*0fca6ea1SDimitry Andric              getAVLReg() == Other.getAVLReg();
642*0fca6ea1SDimitry Andric     }
64381ad6265SDimitry Andric 
64481ad6265SDimitry Andric     if (hasAVLImm() && Other.hasAVLImm())
64581ad6265SDimitry Andric       return getAVLImm() == Other.getAVLImm();
64681ad6265SDimitry Andric 
647*0fca6ea1SDimitry Andric     if (hasAVLVLMAX())
648*0fca6ea1SDimitry Andric       return Other.hasAVLVLMAX() && hasSameVLMAX(Other);
649*0fca6ea1SDimitry Andric 
65081ad6265SDimitry Andric     return false;
65181ad6265SDimitry Andric   }
65281ad6265SDimitry Andric 
653*0fca6ea1SDimitry Andric   // Return true if the two lattice values are guaranteed to have
654*0fca6ea1SDimitry Andric   // the same AVL value at runtime.
655*0fca6ea1SDimitry Andric   bool hasSameAVL(const VSETVLIInfo &Other) const {
656*0fca6ea1SDimitry Andric     // Without LiveIntervals, we don't know which instruction defines a
657*0fca6ea1SDimitry Andric     // register.  Since a register may be redefined, this means all AVLIsReg
658*0fca6ea1SDimitry Andric     // states must be treated as possibly distinct.
659*0fca6ea1SDimitry Andric     if (hasAVLReg() && Other.hasAVLReg()) {
660*0fca6ea1SDimitry Andric       assert(!getAVLVNInfo() == !Other.getAVLVNInfo() &&
661*0fca6ea1SDimitry Andric              "we either have intervals or we don't");
662*0fca6ea1SDimitry Andric       if (!getAVLVNInfo())
663*0fca6ea1SDimitry Andric         return false;
664*0fca6ea1SDimitry Andric     }
665*0fca6ea1SDimitry Andric     return hasSameAVLLatticeValue(Other);
666*0fca6ea1SDimitry Andric   }
667*0fca6ea1SDimitry Andric 
66881ad6265SDimitry Andric   void setVTYPE(unsigned VType) {
66981ad6265SDimitry Andric     assert(isValid() && !isUnknown() &&
67081ad6265SDimitry Andric            "Can't set VTYPE for uninitialized or unknown");
67181ad6265SDimitry Andric     VLMul = RISCVVType::getVLMUL(VType);
67281ad6265SDimitry Andric     SEW = RISCVVType::getSEW(VType);
67381ad6265SDimitry Andric     TailAgnostic = RISCVVType::isTailAgnostic(VType);
67481ad6265SDimitry Andric     MaskAgnostic = RISCVVType::isMaskAgnostic(VType);
67581ad6265SDimitry Andric   }
67681ad6265SDimitry Andric   void setVTYPE(RISCVII::VLMUL L, unsigned S, bool TA, bool MA) {
67781ad6265SDimitry Andric     assert(isValid() && !isUnknown() &&
67881ad6265SDimitry Andric            "Can't set VTYPE for uninitialized or unknown");
67981ad6265SDimitry Andric     VLMul = L;
68081ad6265SDimitry Andric     SEW = S;
68181ad6265SDimitry Andric     TailAgnostic = TA;
68281ad6265SDimitry Andric     MaskAgnostic = MA;
68381ad6265SDimitry Andric   }
68481ad6265SDimitry Andric 
6855f757f3fSDimitry Andric   void setVLMul(RISCVII::VLMUL VLMul) { this->VLMul = VLMul; }
6865f757f3fSDimitry Andric 
68781ad6265SDimitry Andric   unsigned encodeVTYPE() const {
68881ad6265SDimitry Andric     assert(isValid() && !isUnknown() && !SEWLMULRatioOnly &&
68981ad6265SDimitry Andric            "Can't encode VTYPE for uninitialized or unknown");
69081ad6265SDimitry Andric     return RISCVVType::encodeVTYPE(VLMul, SEW, TailAgnostic, MaskAgnostic);
69181ad6265SDimitry Andric   }
69281ad6265SDimitry Andric 
69381ad6265SDimitry Andric   bool hasSEWLMULRatioOnly() const { return SEWLMULRatioOnly; }
69481ad6265SDimitry Andric 
69581ad6265SDimitry Andric   bool hasSameVTYPE(const VSETVLIInfo &Other) const {
69681ad6265SDimitry Andric     assert(isValid() && Other.isValid() &&
69781ad6265SDimitry Andric            "Can't compare invalid VSETVLIInfos");
69881ad6265SDimitry Andric     assert(!isUnknown() && !Other.isUnknown() &&
69981ad6265SDimitry Andric            "Can't compare VTYPE in unknown state");
70081ad6265SDimitry Andric     assert(!SEWLMULRatioOnly && !Other.SEWLMULRatioOnly &&
70181ad6265SDimitry Andric            "Can't compare when only LMUL/SEW ratio is valid.");
70281ad6265SDimitry Andric     return std::tie(VLMul, SEW, TailAgnostic, MaskAgnostic) ==
70381ad6265SDimitry Andric            std::tie(Other.VLMul, Other.SEW, Other.TailAgnostic,
70481ad6265SDimitry Andric                     Other.MaskAgnostic);
70581ad6265SDimitry Andric   }
70681ad6265SDimitry Andric 
70781ad6265SDimitry Andric   unsigned getSEWLMULRatio() const {
70881ad6265SDimitry Andric     assert(isValid() && !isUnknown() &&
70981ad6265SDimitry Andric            "Can't use VTYPE for uninitialized or unknown");
710bdd1243dSDimitry Andric     return RISCVVType::getSEWLMULRatio(SEW, VLMul);
71181ad6265SDimitry Andric   }
71281ad6265SDimitry Andric 
71381ad6265SDimitry Andric   // Check if the VTYPE for these two VSETVLIInfos produce the same VLMAX.
71481ad6265SDimitry Andric   // Note that having the same VLMAX ensures that both share the same
71581ad6265SDimitry Andric   // function from AVL to VL; that is, they must produce the same VL value
71681ad6265SDimitry Andric   // for any given AVL value.
71781ad6265SDimitry Andric   bool hasSameVLMAX(const VSETVLIInfo &Other) const {
71881ad6265SDimitry Andric     assert(isValid() && Other.isValid() &&
71981ad6265SDimitry Andric            "Can't compare invalid VSETVLIInfos");
72081ad6265SDimitry Andric     assert(!isUnknown() && !Other.isUnknown() &&
72181ad6265SDimitry Andric            "Can't compare VTYPE in unknown state");
72281ad6265SDimitry Andric     return getSEWLMULRatio() == Other.getSEWLMULRatio();
72381ad6265SDimitry Andric   }
72481ad6265SDimitry Andric 
725bdd1243dSDimitry Andric   bool hasCompatibleVTYPE(const DemandedFields &Used,
72681ad6265SDimitry Andric                           const VSETVLIInfo &Require) const {
72706c3fb27SDimitry Andric     return areCompatibleVTYPEs(Require.encodeVTYPE(), encodeVTYPE(), Used);
72881ad6265SDimitry Andric   }
72981ad6265SDimitry Andric 
73081ad6265SDimitry Andric   // Determine whether the vector instructions requirements represented by
73181ad6265SDimitry Andric   // Require are compatible with the previous vsetvli instruction represented
73281ad6265SDimitry Andric   // by this.  MI is the instruction whose requirements we're considering.
73306c3fb27SDimitry Andric   bool isCompatible(const DemandedFields &Used, const VSETVLIInfo &Require,
734*0fca6ea1SDimitry Andric                     const LiveIntervals *LIS) const {
73581ad6265SDimitry Andric     assert(isValid() && Require.isValid() &&
73681ad6265SDimitry Andric            "Can't compare invalid VSETVLIInfos");
73781ad6265SDimitry Andric     // Nothing is compatible with Unknown.
73881ad6265SDimitry Andric     if (isUnknown() || Require.isUnknown())
73981ad6265SDimitry Andric       return false;
74081ad6265SDimitry Andric 
74181ad6265SDimitry Andric     // If only our VLMAX ratio is valid, then this isn't compatible.
742*0fca6ea1SDimitry Andric     if (SEWLMULRatioOnly || Require.SEWLMULRatioOnly)
74381ad6265SDimitry Andric       return false;
74481ad6265SDimitry Andric 
745*0fca6ea1SDimitry Andric     if (Used.VLAny && !(hasSameAVL(Require) && hasSameVLMAX(Require)))
746bdd1243dSDimitry Andric       return false;
747bdd1243dSDimitry Andric 
748*0fca6ea1SDimitry Andric     if (Used.VLZeroness && !hasEquallyZeroAVL(Require, LIS))
749bdd1243dSDimitry Andric       return false;
750bdd1243dSDimitry Andric 
75106c3fb27SDimitry Andric     return hasCompatibleVTYPE(Used, Require);
75281ad6265SDimitry Andric   }
75381ad6265SDimitry Andric 
75481ad6265SDimitry Andric   bool operator==(const VSETVLIInfo &Other) const {
75581ad6265SDimitry Andric     // Uninitialized is only equal to another Uninitialized.
75681ad6265SDimitry Andric     if (!isValid())
75781ad6265SDimitry Andric       return !Other.isValid();
75881ad6265SDimitry Andric     if (!Other.isValid())
75981ad6265SDimitry Andric       return !isValid();
76081ad6265SDimitry Andric 
76181ad6265SDimitry Andric     // Unknown is only equal to another Unknown.
76281ad6265SDimitry Andric     if (isUnknown())
76381ad6265SDimitry Andric       return Other.isUnknown();
76481ad6265SDimitry Andric     if (Other.isUnknown())
76581ad6265SDimitry Andric       return isUnknown();
76681ad6265SDimitry Andric 
767*0fca6ea1SDimitry Andric     if (!hasSameAVLLatticeValue(Other))
76881ad6265SDimitry Andric       return false;
76981ad6265SDimitry Andric 
77081ad6265SDimitry Andric     // If the SEWLMULRatioOnly bits are different, then they aren't equal.
77181ad6265SDimitry Andric     if (SEWLMULRatioOnly != Other.SEWLMULRatioOnly)
77281ad6265SDimitry Andric       return false;
77381ad6265SDimitry Andric 
77481ad6265SDimitry Andric     // If only the VLMAX is valid, check that it is the same.
77581ad6265SDimitry Andric     if (SEWLMULRatioOnly)
77681ad6265SDimitry Andric       return hasSameVLMAX(Other);
77781ad6265SDimitry Andric 
77881ad6265SDimitry Andric     // If the full VTYPE is valid, check that it is the same.
77981ad6265SDimitry Andric     return hasSameVTYPE(Other);
78081ad6265SDimitry Andric   }
78181ad6265SDimitry Andric 
78281ad6265SDimitry Andric   bool operator!=(const VSETVLIInfo &Other) const {
78381ad6265SDimitry Andric     return !(*this == Other);
78481ad6265SDimitry Andric   }
78581ad6265SDimitry Andric 
78681ad6265SDimitry Andric   // Calculate the VSETVLIInfo visible to a block assuming this and Other are
78781ad6265SDimitry Andric   // both predecessors.
78881ad6265SDimitry Andric   VSETVLIInfo intersect(const VSETVLIInfo &Other) const {
78981ad6265SDimitry Andric     // If the new value isn't valid, ignore it.
79081ad6265SDimitry Andric     if (!Other.isValid())
79181ad6265SDimitry Andric       return *this;
79281ad6265SDimitry Andric 
79381ad6265SDimitry Andric     // If this value isn't valid, this must be the first predecessor, use it.
79481ad6265SDimitry Andric     if (!isValid())
79581ad6265SDimitry Andric       return Other;
79681ad6265SDimitry Andric 
79781ad6265SDimitry Andric     // If either is unknown, the result is unknown.
79881ad6265SDimitry Andric     if (isUnknown() || Other.isUnknown())
79981ad6265SDimitry Andric       return VSETVLIInfo::getUnknown();
80081ad6265SDimitry Andric 
80181ad6265SDimitry Andric     // If we have an exact, match return this.
80281ad6265SDimitry Andric     if (*this == Other)
80381ad6265SDimitry Andric       return *this;
80481ad6265SDimitry Andric 
80581ad6265SDimitry Andric     // Not an exact match, but maybe the AVL and VLMAX are the same. If so,
80681ad6265SDimitry Andric     // return an SEW/LMUL ratio only value.
80781ad6265SDimitry Andric     if (hasSameAVL(Other) && hasSameVLMAX(Other)) {
80881ad6265SDimitry Andric       VSETVLIInfo MergeInfo = *this;
80981ad6265SDimitry Andric       MergeInfo.SEWLMULRatioOnly = true;
81081ad6265SDimitry Andric       return MergeInfo;
81181ad6265SDimitry Andric     }
81281ad6265SDimitry Andric 
81381ad6265SDimitry Andric     // Otherwise the result is unknown.
81481ad6265SDimitry Andric     return VSETVLIInfo::getUnknown();
81581ad6265SDimitry Andric   }
81681ad6265SDimitry Andric 
81781ad6265SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
81881ad6265SDimitry Andric   /// Support for debugging, callable in GDB: V->dump()
81981ad6265SDimitry Andric   LLVM_DUMP_METHOD void dump() const {
82081ad6265SDimitry Andric     print(dbgs());
82181ad6265SDimitry Andric     dbgs() << "\n";
82281ad6265SDimitry Andric   }
82381ad6265SDimitry Andric 
82481ad6265SDimitry Andric   /// Implement operator<<.
82581ad6265SDimitry Andric   /// @{
82681ad6265SDimitry Andric   void print(raw_ostream &OS) const {
82781ad6265SDimitry Andric     OS << "{";
82881ad6265SDimitry Andric     if (!isValid())
82981ad6265SDimitry Andric       OS << "Uninitialized";
83081ad6265SDimitry Andric     if (isUnknown())
83181ad6265SDimitry Andric       OS << "unknown";
83281ad6265SDimitry Andric     if (hasAVLReg())
833*0fca6ea1SDimitry Andric       OS << "AVLReg=" << llvm::printReg(getAVLReg());
83481ad6265SDimitry Andric     if (hasAVLImm())
83581ad6265SDimitry Andric       OS << "AVLImm=" << (unsigned)AVLImm;
836*0fca6ea1SDimitry Andric     if (hasAVLVLMAX())
837*0fca6ea1SDimitry Andric       OS << "AVLVLMAX";
83881ad6265SDimitry Andric     OS << ", "
83981ad6265SDimitry Andric        << "VLMul=" << (unsigned)VLMul << ", "
84081ad6265SDimitry Andric        << "SEW=" << (unsigned)SEW << ", "
84181ad6265SDimitry Andric        << "TailAgnostic=" << (bool)TailAgnostic << ", "
84281ad6265SDimitry Andric        << "MaskAgnostic=" << (bool)MaskAgnostic << ", "
84381ad6265SDimitry Andric        << "SEWLMULRatioOnly=" << (bool)SEWLMULRatioOnly << "}";
84481ad6265SDimitry Andric   }
84581ad6265SDimitry Andric #endif
84681ad6265SDimitry Andric };
84781ad6265SDimitry Andric 
84881ad6265SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
84981ad6265SDimitry Andric LLVM_ATTRIBUTE_USED
85081ad6265SDimitry Andric inline raw_ostream &operator<<(raw_ostream &OS, const VSETVLIInfo &V) {
85181ad6265SDimitry Andric   V.print(OS);
85281ad6265SDimitry Andric   return OS;
85381ad6265SDimitry Andric }
85481ad6265SDimitry Andric #endif
85581ad6265SDimitry Andric 
85681ad6265SDimitry Andric struct BlockData {
85781ad6265SDimitry Andric   // The VSETVLIInfo that represents the VL/VTYPE settings on exit from this
85881ad6265SDimitry Andric   // block. Calculated in Phase 2.
85981ad6265SDimitry Andric   VSETVLIInfo Exit;
86081ad6265SDimitry Andric 
86181ad6265SDimitry Andric   // The VSETVLIInfo that represents the VL/VTYPE settings from all predecessor
86281ad6265SDimitry Andric   // blocks. Calculated in Phase 2, and used by Phase 3.
86381ad6265SDimitry Andric   VSETVLIInfo Pred;
86481ad6265SDimitry Andric 
86581ad6265SDimitry Andric   // Keeps track of whether the block is already in the queue.
86681ad6265SDimitry Andric   bool InQueue = false;
86781ad6265SDimitry Andric 
86881ad6265SDimitry Andric   BlockData() = default;
86981ad6265SDimitry Andric };
87081ad6265SDimitry Andric 
87181ad6265SDimitry Andric class RISCVInsertVSETVLI : public MachineFunctionPass {
8725f757f3fSDimitry Andric   const RISCVSubtarget *ST;
87381ad6265SDimitry Andric   const TargetInstrInfo *TII;
87481ad6265SDimitry Andric   MachineRegisterInfo *MRI;
875*0fca6ea1SDimitry Andric   // Possibly null!
876*0fca6ea1SDimitry Andric   LiveIntervals *LIS;
87781ad6265SDimitry Andric 
87881ad6265SDimitry Andric   std::vector<BlockData> BlockInfo;
87981ad6265SDimitry Andric   std::queue<const MachineBasicBlock *> WorkList;
88081ad6265SDimitry Andric 
88181ad6265SDimitry Andric public:
88281ad6265SDimitry Andric   static char ID;
88381ad6265SDimitry Andric 
8845f757f3fSDimitry Andric   RISCVInsertVSETVLI() : MachineFunctionPass(ID) {}
88581ad6265SDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
88681ad6265SDimitry Andric 
88781ad6265SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
88881ad6265SDimitry Andric     AU.setPreservesCFG();
889*0fca6ea1SDimitry Andric 
890*0fca6ea1SDimitry Andric     AU.addUsedIfAvailable<LiveIntervalsWrapperPass>();
891*0fca6ea1SDimitry Andric     AU.addPreserved<LiveIntervalsWrapperPass>();
892*0fca6ea1SDimitry Andric     AU.addPreserved<SlotIndexesWrapperPass>();
893*0fca6ea1SDimitry Andric     AU.addPreserved<LiveDebugVariables>();
894*0fca6ea1SDimitry Andric     AU.addPreserved<LiveStacks>();
895*0fca6ea1SDimitry Andric 
89681ad6265SDimitry Andric     MachineFunctionPass::getAnalysisUsage(AU);
89781ad6265SDimitry Andric   }
89881ad6265SDimitry Andric 
89981ad6265SDimitry Andric   StringRef getPassName() const override { return RISCV_INSERT_VSETVLI_NAME; }
90081ad6265SDimitry Andric 
90181ad6265SDimitry Andric private:
902*0fca6ea1SDimitry Andric   bool needVSETVLI(const DemandedFields &Used, const VSETVLIInfo &Require,
90381ad6265SDimitry Andric                    const VSETVLIInfo &CurInfo) const;
90481ad6265SDimitry Andric   bool needVSETVLIPHI(const VSETVLIInfo &Require,
90581ad6265SDimitry Andric                       const MachineBasicBlock &MBB) const;
90681ad6265SDimitry Andric   void insertVSETVLI(MachineBasicBlock &MBB,
90781ad6265SDimitry Andric                      MachineBasicBlock::iterator InsertPt, DebugLoc DL,
90881ad6265SDimitry Andric                      const VSETVLIInfo &Info, const VSETVLIInfo &PrevInfo);
90981ad6265SDimitry Andric 
9105f757f3fSDimitry Andric   void transferBefore(VSETVLIInfo &Info, const MachineInstr &MI) const;
9115f757f3fSDimitry Andric   void transferAfter(VSETVLIInfo &Info, const MachineInstr &MI) const;
9125f757f3fSDimitry Andric   bool computeVLVTYPEChanges(const MachineBasicBlock &MBB,
9135f757f3fSDimitry Andric                              VSETVLIInfo &Info) const;
91481ad6265SDimitry Andric   void computeIncomingVLVTYPE(const MachineBasicBlock &MBB);
91581ad6265SDimitry Andric   void emitVSETVLIs(MachineBasicBlock &MBB);
91681ad6265SDimitry Andric   void doPRE(MachineBasicBlock &MBB);
91781ad6265SDimitry Andric   void insertReadVL(MachineBasicBlock &MBB);
918*0fca6ea1SDimitry Andric 
919*0fca6ea1SDimitry Andric   bool canMutatePriorConfig(const MachineInstr &PrevMI, const MachineInstr &MI,
920*0fca6ea1SDimitry Andric                             const DemandedFields &Used) const;
921*0fca6ea1SDimitry Andric   void coalesceVSETVLIs(MachineBasicBlock &MBB) const;
922*0fca6ea1SDimitry Andric 
923*0fca6ea1SDimitry Andric   VSETVLIInfo getInfoForVSETVLI(const MachineInstr &MI) const;
924*0fca6ea1SDimitry Andric   VSETVLIInfo computeInfoForInstr(const MachineInstr &MI) const;
925*0fca6ea1SDimitry Andric   void forwardVSETVLIAVL(VSETVLIInfo &Info) const;
92681ad6265SDimitry Andric };
92781ad6265SDimitry Andric 
92881ad6265SDimitry Andric } // end anonymous namespace
92981ad6265SDimitry Andric 
93081ad6265SDimitry Andric char RISCVInsertVSETVLI::ID = 0;
931*0fca6ea1SDimitry Andric char &llvm::RISCVInsertVSETVLIID = RISCVInsertVSETVLI::ID;
93281ad6265SDimitry Andric 
93381ad6265SDimitry Andric INITIALIZE_PASS(RISCVInsertVSETVLI, DEBUG_TYPE, RISCV_INSERT_VSETVLI_NAME,
93481ad6265SDimitry Andric                 false, false)
93581ad6265SDimitry Andric 
936*0fca6ea1SDimitry Andric // If the AVL is defined by a vsetvli's output vl with the same VLMAX, we can
937*0fca6ea1SDimitry Andric // replace the AVL operand with the AVL of the defining vsetvli. E.g.
938*0fca6ea1SDimitry Andric //
939*0fca6ea1SDimitry Andric // %vl = PseudoVSETVLI %avl:gpr, SEW=32, LMUL=M1
940*0fca6ea1SDimitry Andric // $x0 = PseudoVSETVLI %vl:gpr, SEW=32, LMUL=M1
941*0fca6ea1SDimitry Andric // ->
942*0fca6ea1SDimitry Andric // %vl = PseudoVSETVLI %avl:gpr, SEW=32, LMUL=M1
943*0fca6ea1SDimitry Andric // $x0 = PseudoVSETVLI %avl:gpr, SEW=32, LMUL=M1
944*0fca6ea1SDimitry Andric void RISCVInsertVSETVLI::forwardVSETVLIAVL(VSETVLIInfo &Info) const {
945*0fca6ea1SDimitry Andric   if (!Info.hasAVLReg())
946*0fca6ea1SDimitry Andric     return;
947*0fca6ea1SDimitry Andric   const MachineInstr *DefMI = Info.getAVLDefMI(LIS);
948*0fca6ea1SDimitry Andric   if (!DefMI || !isVectorConfigInstr(*DefMI))
949*0fca6ea1SDimitry Andric     return;
950*0fca6ea1SDimitry Andric   VSETVLIInfo DefInstrInfo = getInfoForVSETVLI(*DefMI);
951*0fca6ea1SDimitry Andric   if (!DefInstrInfo.hasSameVLMAX(Info))
952*0fca6ea1SDimitry Andric     return;
953*0fca6ea1SDimitry Andric   Info.setAVL(DefInstrInfo);
954*0fca6ea1SDimitry Andric }
955*0fca6ea1SDimitry Andric 
9565f757f3fSDimitry Andric // Return a VSETVLIInfo representing the changes made by this VSETVLI or
9575f757f3fSDimitry Andric // VSETIVLI instruction.
958*0fca6ea1SDimitry Andric VSETVLIInfo
959*0fca6ea1SDimitry Andric RISCVInsertVSETVLI::getInfoForVSETVLI(const MachineInstr &MI) const {
9605f757f3fSDimitry Andric   VSETVLIInfo NewInfo;
9615f757f3fSDimitry Andric   if (MI.getOpcode() == RISCV::PseudoVSETIVLI) {
9625f757f3fSDimitry Andric     NewInfo.setAVLImm(MI.getOperand(1).getImm());
9635f757f3fSDimitry Andric   } else {
9645f757f3fSDimitry Andric     assert(MI.getOpcode() == RISCV::PseudoVSETVLI ||
9655f757f3fSDimitry Andric            MI.getOpcode() == RISCV::PseudoVSETVLIX0);
9665f757f3fSDimitry Andric     Register AVLReg = MI.getOperand(1).getReg();
9675f757f3fSDimitry Andric     assert((AVLReg != RISCV::X0 || MI.getOperand(0).getReg() != RISCV::X0) &&
9685f757f3fSDimitry Andric            "Can't handle X0, X0 vsetvli yet");
969*0fca6ea1SDimitry Andric     if (AVLReg == RISCV::X0)
970*0fca6ea1SDimitry Andric       NewInfo.setAVLVLMAX();
971*0fca6ea1SDimitry Andric     else if (MI.getOperand(1).isUndef())
972*0fca6ea1SDimitry Andric       // Otherwise use an AVL of 1 to avoid depending on previous vl.
973*0fca6ea1SDimitry Andric       NewInfo.setAVLImm(1);
974*0fca6ea1SDimitry Andric     else {
975*0fca6ea1SDimitry Andric       VNInfo *VNI = getVNInfoFromReg(AVLReg, MI, LIS);
976*0fca6ea1SDimitry Andric       NewInfo.setAVLRegDef(VNI, AVLReg);
977*0fca6ea1SDimitry Andric     }
9785f757f3fSDimitry Andric   }
9795f757f3fSDimitry Andric   NewInfo.setVTYPE(MI.getOperand(2).getImm());
9805f757f3fSDimitry Andric 
981*0fca6ea1SDimitry Andric   forwardVSETVLIAVL(NewInfo);
982*0fca6ea1SDimitry Andric 
9835f757f3fSDimitry Andric   return NewInfo;
9845f757f3fSDimitry Andric }
9855f757f3fSDimitry Andric 
9867a6dacacSDimitry Andric static unsigned computeVLMAX(unsigned VLEN, unsigned SEW,
9877a6dacacSDimitry Andric                              RISCVII::VLMUL VLMul) {
9887a6dacacSDimitry Andric   auto [LMul, Fractional] = RISCVVType::decodeVLMUL(VLMul);
9897a6dacacSDimitry Andric   if (Fractional)
9907a6dacacSDimitry Andric     VLEN = VLEN / LMul;
9917a6dacacSDimitry Andric   else
9927a6dacacSDimitry Andric     VLEN = VLEN * LMul;
9937a6dacacSDimitry Andric   return VLEN/SEW;
9947a6dacacSDimitry Andric }
9957a6dacacSDimitry Andric 
996*0fca6ea1SDimitry Andric VSETVLIInfo
997*0fca6ea1SDimitry Andric RISCVInsertVSETVLI::computeInfoForInstr(const MachineInstr &MI) const {
99881ad6265SDimitry Andric   VSETVLIInfo InstrInfo;
999*0fca6ea1SDimitry Andric   const uint64_t TSFlags = MI.getDesc().TSFlags;
100081ad6265SDimitry Andric 
100106c3fb27SDimitry Andric   bool TailAgnostic = true;
100206c3fb27SDimitry Andric   bool MaskAgnostic = true;
1003*0fca6ea1SDimitry Andric   if (!hasUndefinedMergeOp(MI)) {
1004bdd1243dSDimitry Andric     // Start with undisturbed.
1005bdd1243dSDimitry Andric     TailAgnostic = false;
1006bdd1243dSDimitry Andric     MaskAgnostic = false;
1007bdd1243dSDimitry Andric 
1008bdd1243dSDimitry Andric     // If there is a policy operand, use it.
100981ad6265SDimitry Andric     if (RISCVII::hasVecPolicyOp(TSFlags)) {
101081ad6265SDimitry Andric       const MachineOperand &Op = MI.getOperand(MI.getNumExplicitOperands() - 1);
101181ad6265SDimitry Andric       uint64_t Policy = Op.getImm();
101281ad6265SDimitry Andric       assert(Policy <= (RISCVII::TAIL_AGNOSTIC | RISCVII::MASK_AGNOSTIC) &&
101381ad6265SDimitry Andric              "Invalid Policy Value");
101481ad6265SDimitry Andric       TailAgnostic = Policy & RISCVII::TAIL_AGNOSTIC;
101581ad6265SDimitry Andric       MaskAgnostic = Policy & RISCVII::MASK_AGNOSTIC;
1016bdd1243dSDimitry Andric     }
1017bdd1243dSDimitry Andric 
101881ad6265SDimitry Andric     // Some pseudo instructions force a tail agnostic policy despite having a
101981ad6265SDimitry Andric     // tied def.
102081ad6265SDimitry Andric     if (RISCVII::doesForceTailAgnostic(TSFlags))
102181ad6265SDimitry Andric       TailAgnostic = true;
1022bdd1243dSDimitry Andric 
1023bdd1243dSDimitry Andric     if (!RISCVII::usesMaskPolicy(TSFlags))
1024bdd1243dSDimitry Andric       MaskAgnostic = true;
102581ad6265SDimitry Andric   }
102681ad6265SDimitry Andric 
102781ad6265SDimitry Andric   RISCVII::VLMUL VLMul = RISCVII::getLMul(TSFlags);
102881ad6265SDimitry Andric 
102981ad6265SDimitry Andric   unsigned Log2SEW = MI.getOperand(getSEWOpNum(MI)).getImm();
103081ad6265SDimitry Andric   // A Log2SEW of 0 is an operation on mask registers only.
103181ad6265SDimitry Andric   unsigned SEW = Log2SEW ? 1 << Log2SEW : 8;
103281ad6265SDimitry Andric   assert(RISCVVType::isValidSEW(SEW) && "Unexpected SEW");
103381ad6265SDimitry Andric 
103481ad6265SDimitry Andric   if (RISCVII::hasVLOp(TSFlags)) {
103581ad6265SDimitry Andric     const MachineOperand &VLOp = MI.getOperand(getVLOpNum(MI));
103681ad6265SDimitry Andric     if (VLOp.isImm()) {
103781ad6265SDimitry Andric       int64_t Imm = VLOp.getImm();
103881ad6265SDimitry Andric       // Conver the VLMax sentintel to X0 register.
10397a6dacacSDimitry Andric       if (Imm == RISCV::VLMaxSentinel) {
10407a6dacacSDimitry Andric         // If we know the exact VLEN, see if we can use the constant encoding
10417a6dacacSDimitry Andric         // for the VLMAX instead.  This reduces register pressure slightly.
1042*0fca6ea1SDimitry Andric         const unsigned VLMAX = computeVLMAX(ST->getRealMaxVLen(), SEW, VLMul);
1043*0fca6ea1SDimitry Andric         if (ST->getRealMinVLen() == ST->getRealMaxVLen() && VLMAX <= 31)
10447a6dacacSDimitry Andric           InstrInfo.setAVLImm(VLMAX);
10457a6dacacSDimitry Andric         else
1046*0fca6ea1SDimitry Andric           InstrInfo.setAVLVLMAX();
10477a6dacacSDimitry Andric       }
104881ad6265SDimitry Andric       else
104981ad6265SDimitry Andric         InstrInfo.setAVLImm(Imm);
1050*0fca6ea1SDimitry Andric     } else if (VLOp.isUndef()) {
1051*0fca6ea1SDimitry Andric       // Otherwise use an AVL of 1 to avoid depending on previous vl.
1052*0fca6ea1SDimitry Andric       InstrInfo.setAVLImm(1);
105381ad6265SDimitry Andric     } else {
1054*0fca6ea1SDimitry Andric       VNInfo *VNI = getVNInfoFromReg(VLOp.getReg(), MI, LIS);
1055*0fca6ea1SDimitry Andric       InstrInfo.setAVLRegDef(VNI, VLOp.getReg());
105681ad6265SDimitry Andric     }
105781ad6265SDimitry Andric   } else {
10585f757f3fSDimitry Andric     assert(isScalarExtractInstr(MI));
1059*0fca6ea1SDimitry Andric     // Pick a random value for state tracking purposes, will be ignored via
1060*0fca6ea1SDimitry Andric     // the demanded fields mechanism
1061*0fca6ea1SDimitry Andric     InstrInfo.setAVLImm(1);
106281ad6265SDimitry Andric   }
106381ad6265SDimitry Andric #ifndef NDEBUG
1064bdd1243dSDimitry Andric   if (std::optional<unsigned> EEW = getEEWForLoadStore(MI)) {
106581ad6265SDimitry Andric     assert(SEW == EEW && "Initial SEW doesn't match expected EEW");
106681ad6265SDimitry Andric   }
106781ad6265SDimitry Andric #endif
106881ad6265SDimitry Andric   InstrInfo.setVTYPE(VLMul, SEW, TailAgnostic, MaskAgnostic);
106981ad6265SDimitry Andric 
1070*0fca6ea1SDimitry Andric   forwardVSETVLIAVL(InstrInfo);
10715f757f3fSDimitry Andric 
107281ad6265SDimitry Andric   return InstrInfo;
107381ad6265SDimitry Andric }
107481ad6265SDimitry Andric 
107581ad6265SDimitry Andric void RISCVInsertVSETVLI::insertVSETVLI(MachineBasicBlock &MBB,
107681ad6265SDimitry Andric                      MachineBasicBlock::iterator InsertPt, DebugLoc DL,
107781ad6265SDimitry Andric                      const VSETVLIInfo &Info, const VSETVLIInfo &PrevInfo) {
107881ad6265SDimitry Andric 
10797a6dacacSDimitry Andric   ++NumInsertedVSETVL;
108006c3fb27SDimitry Andric   if (PrevInfo.isValid() && !PrevInfo.isUnknown()) {
108181ad6265SDimitry Andric     // Use X0, X0 form if the AVL is the same and the SEW+LMUL gives the same
108281ad6265SDimitry Andric     // VLMAX.
108306c3fb27SDimitry Andric     if (Info.hasSameAVL(PrevInfo) && Info.hasSameVLMAX(PrevInfo)) {
1084*0fca6ea1SDimitry Andric       auto MI = BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETVLIX0))
108581ad6265SDimitry Andric                     .addReg(RISCV::X0, RegState::Define | RegState::Dead)
108681ad6265SDimitry Andric                     .addReg(RISCV::X0, RegState::Kill)
108781ad6265SDimitry Andric                     .addImm(Info.encodeVTYPE())
108881ad6265SDimitry Andric                     .addReg(RISCV::VL, RegState::Implicit);
1089*0fca6ea1SDimitry Andric       if (LIS)
1090*0fca6ea1SDimitry Andric         LIS->InsertMachineInstrInMaps(*MI);
109181ad6265SDimitry Andric       return;
109281ad6265SDimitry Andric     }
109381ad6265SDimitry Andric 
109406c3fb27SDimitry Andric     // If our AVL is a virtual register, it might be defined by a VSET(I)VLI. If
109506c3fb27SDimitry Andric     // it has the same VLMAX we want and the last VL/VTYPE we observed is the
109606c3fb27SDimitry Andric     // same, we can use the X0, X0 form.
1097*0fca6ea1SDimitry Andric     if (Info.hasSameVLMAX(PrevInfo) && Info.hasAVLReg()) {
1098*0fca6ea1SDimitry Andric       if (const MachineInstr *DefMI = Info.getAVLDefMI(LIS);
1099*0fca6ea1SDimitry Andric           DefMI && isVectorConfigInstr(*DefMI)) {
110006c3fb27SDimitry Andric         VSETVLIInfo DefInfo = getInfoForVSETVLI(*DefMI);
110106c3fb27SDimitry Andric         if (DefInfo.hasSameAVL(PrevInfo) && DefInfo.hasSameVLMAX(PrevInfo)) {
1102*0fca6ea1SDimitry Andric           auto MI = BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETVLIX0))
110306c3fb27SDimitry Andric                         .addReg(RISCV::X0, RegState::Define | RegState::Dead)
110406c3fb27SDimitry Andric                         .addReg(RISCV::X0, RegState::Kill)
110506c3fb27SDimitry Andric                         .addImm(Info.encodeVTYPE())
110606c3fb27SDimitry Andric                         .addReg(RISCV::VL, RegState::Implicit);
1107*0fca6ea1SDimitry Andric           if (LIS)
1108*0fca6ea1SDimitry Andric             LIS->InsertMachineInstrInMaps(*MI);
110906c3fb27SDimitry Andric           return;
111006c3fb27SDimitry Andric         }
111106c3fb27SDimitry Andric       }
111206c3fb27SDimitry Andric     }
111306c3fb27SDimitry Andric   }
111406c3fb27SDimitry Andric 
111581ad6265SDimitry Andric   if (Info.hasAVLImm()) {
1116*0fca6ea1SDimitry Andric     auto MI = BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETIVLI))
111781ad6265SDimitry Andric                   .addReg(RISCV::X0, RegState::Define | RegState::Dead)
111881ad6265SDimitry Andric                   .addImm(Info.getAVLImm())
111981ad6265SDimitry Andric                   .addImm(Info.encodeVTYPE());
1120*0fca6ea1SDimitry Andric     if (LIS)
1121*0fca6ea1SDimitry Andric       LIS->InsertMachineInstrInMaps(*MI);
1122*0fca6ea1SDimitry Andric     return;
1123*0fca6ea1SDimitry Andric   }
1124*0fca6ea1SDimitry Andric 
1125*0fca6ea1SDimitry Andric   if (Info.hasAVLVLMAX()) {
1126*0fca6ea1SDimitry Andric     Register DestReg = MRI->createVirtualRegister(&RISCV::GPRRegClass);
1127*0fca6ea1SDimitry Andric     auto MI = BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETVLIX0))
1128*0fca6ea1SDimitry Andric                   .addReg(DestReg, RegState::Define | RegState::Dead)
1129*0fca6ea1SDimitry Andric                   .addReg(RISCV::X0, RegState::Kill)
1130*0fca6ea1SDimitry Andric                   .addImm(Info.encodeVTYPE());
1131*0fca6ea1SDimitry Andric     if (LIS) {
1132*0fca6ea1SDimitry Andric       LIS->InsertMachineInstrInMaps(*MI);
1133*0fca6ea1SDimitry Andric       LIS->createAndComputeVirtRegInterval(DestReg);
1134*0fca6ea1SDimitry Andric     }
113581ad6265SDimitry Andric     return;
113681ad6265SDimitry Andric   }
113781ad6265SDimitry Andric 
113881ad6265SDimitry Andric   Register AVLReg = Info.getAVLReg();
113981ad6265SDimitry Andric   MRI->constrainRegClass(AVLReg, &RISCV::GPRNoX0RegClass);
1140*0fca6ea1SDimitry Andric   auto MI = BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETVLI))
1141*0fca6ea1SDimitry Andric                 .addReg(RISCV::X0, RegState::Define | RegState::Dead)
114281ad6265SDimitry Andric                 .addReg(AVLReg)
114381ad6265SDimitry Andric                 .addImm(Info.encodeVTYPE());
1144*0fca6ea1SDimitry Andric   if (LIS) {
1145*0fca6ea1SDimitry Andric     LIS->InsertMachineInstrInMaps(*MI);
1146*0fca6ea1SDimitry Andric     LiveInterval &LI = LIS->getInterval(AVLReg);
1147*0fca6ea1SDimitry Andric     SlotIndex SI = LIS->getInstructionIndex(*MI).getRegSlot();
1148*0fca6ea1SDimitry Andric     // If the AVL value isn't live at MI, do a quick check to see if it's easily
1149*0fca6ea1SDimitry Andric     // extendable. Otherwise, we need to copy it.
1150*0fca6ea1SDimitry Andric     if (LI.getVNInfoBefore(SI) != Info.getAVLVNInfo()) {
1151*0fca6ea1SDimitry Andric       if (!LI.liveAt(SI) && LI.containsOneValue())
1152*0fca6ea1SDimitry Andric         LIS->extendToIndices(LI, SI);
1153*0fca6ea1SDimitry Andric       else {
1154*0fca6ea1SDimitry Andric         Register AVLCopyReg =
1155*0fca6ea1SDimitry Andric             MRI->createVirtualRegister(&RISCV::GPRNoX0RegClass);
1156*0fca6ea1SDimitry Andric         MachineBasicBlock::iterator II;
1157*0fca6ea1SDimitry Andric         if (Info.getAVLVNInfo()->isPHIDef())
1158*0fca6ea1SDimitry Andric           II = LIS->getMBBFromIndex(Info.getAVLVNInfo()->def)->getFirstNonPHI();
1159*0fca6ea1SDimitry Andric         else {
1160*0fca6ea1SDimitry Andric           II = LIS->getInstructionFromIndex(Info.getAVLVNInfo()->def);
1161*0fca6ea1SDimitry Andric           II = std::next(II);
116281ad6265SDimitry Andric         }
1163*0fca6ea1SDimitry Andric         assert(II.isValid());
1164*0fca6ea1SDimitry Andric         auto AVLCopy =
1165*0fca6ea1SDimitry Andric             BuildMI(*II->getParent(), II, DL, TII->get(RISCV::COPY), AVLCopyReg)
1166*0fca6ea1SDimitry Andric                 .addReg(AVLReg);
1167*0fca6ea1SDimitry Andric         LIS->InsertMachineInstrInMaps(*AVLCopy);
1168*0fca6ea1SDimitry Andric         MI->getOperand(1).setReg(AVLCopyReg);
1169*0fca6ea1SDimitry Andric         LIS->createAndComputeVirtRegInterval(AVLCopyReg);
1170*0fca6ea1SDimitry Andric       }
1171*0fca6ea1SDimitry Andric     }
1172*0fca6ea1SDimitry Andric   }
117381ad6265SDimitry Andric }
117481ad6265SDimitry Andric 
117581ad6265SDimitry Andric /// Return true if a VSETVLI is required to transition from CurInfo to Require
1176*0fca6ea1SDimitry Andric /// given a set of DemandedFields \p Used.
1177*0fca6ea1SDimitry Andric bool RISCVInsertVSETVLI::needVSETVLI(const DemandedFields &Used,
117881ad6265SDimitry Andric                                      const VSETVLIInfo &Require,
117981ad6265SDimitry Andric                                      const VSETVLIInfo &CurInfo) const {
118081ad6265SDimitry Andric   if (!CurInfo.isValid() || CurInfo.isUnknown() || CurInfo.hasSEWLMULRatioOnly())
118181ad6265SDimitry Andric     return true;
118281ad6265SDimitry Andric 
1183*0fca6ea1SDimitry Andric   if (CurInfo.isCompatible(Used, Require, LIS))
1184bdd1243dSDimitry Andric     return false;
118581ad6265SDimitry Andric 
118681ad6265SDimitry Andric   return true;
118781ad6265SDimitry Andric }
118881ad6265SDimitry Andric 
11895f757f3fSDimitry Andric // If we don't use LMUL or the SEW/LMUL ratio, then adjust LMUL so that we
11905f757f3fSDimitry Andric // maintain the SEW/LMUL ratio. This allows us to eliminate VL toggles in more
11915f757f3fSDimitry Andric // places.
11925f757f3fSDimitry Andric static VSETVLIInfo adjustIncoming(VSETVLIInfo PrevInfo, VSETVLIInfo NewInfo,
11935f757f3fSDimitry Andric                                   DemandedFields &Demanded) {
11945f757f3fSDimitry Andric   VSETVLIInfo Info = NewInfo;
11955f757f3fSDimitry Andric 
11965f757f3fSDimitry Andric   if (!Demanded.LMUL && !Demanded.SEWLMULRatio && PrevInfo.isValid() &&
11975f757f3fSDimitry Andric       !PrevInfo.isUnknown()) {
11985f757f3fSDimitry Andric     if (auto NewVLMul = RISCVVType::getSameRatioLMUL(
11995f757f3fSDimitry Andric             PrevInfo.getSEW(), PrevInfo.getVLMUL(), Info.getSEW()))
12005f757f3fSDimitry Andric       Info.setVLMul(*NewVLMul);
1201*0fca6ea1SDimitry Andric     Demanded.LMUL = DemandedFields::LMULEqual;
12025f757f3fSDimitry Andric   }
12035f757f3fSDimitry Andric 
12045f757f3fSDimitry Andric   return Info;
12055f757f3fSDimitry Andric }
12065f757f3fSDimitry Andric 
12075f757f3fSDimitry Andric // Given an incoming state reaching MI, minimally modifies that state so that it
12085f757f3fSDimitry Andric // is compatible with MI. The resulting state is guaranteed to be semantically
12095f757f3fSDimitry Andric // legal for MI, but may not be the state requested by MI.
12105f757f3fSDimitry Andric void RISCVInsertVSETVLI::transferBefore(VSETVLIInfo &Info,
12115f757f3fSDimitry Andric                                         const MachineInstr &MI) const {
1212*0fca6ea1SDimitry Andric   if (!RISCVII::hasSEWOp(MI.getDesc().TSFlags))
121381ad6265SDimitry Andric     return;
121481ad6265SDimitry Andric 
1215*0fca6ea1SDimitry Andric   DemandedFields Demanded = getDemanded(MI, ST);
1216*0fca6ea1SDimitry Andric 
1217*0fca6ea1SDimitry Andric   const VSETVLIInfo NewInfo = computeInfoForInstr(MI);
12185f757f3fSDimitry Andric   assert(NewInfo.isValid() && !NewInfo.isUnknown());
1219*0fca6ea1SDimitry Andric   if (Info.isValid() && !needVSETVLI(Demanded, NewInfo, Info))
122081ad6265SDimitry Andric     return;
122181ad6265SDimitry Andric 
122281ad6265SDimitry Andric   const VSETVLIInfo PrevInfo = Info;
12235f757f3fSDimitry Andric   if (!Info.isValid() || Info.isUnknown())
122481ad6265SDimitry Andric     Info = NewInfo;
122581ad6265SDimitry Andric 
12265f757f3fSDimitry Andric   const VSETVLIInfo IncomingInfo = adjustIncoming(PrevInfo, NewInfo, Demanded);
122781ad6265SDimitry Andric 
12285f757f3fSDimitry Andric   // If MI only demands that VL has the same zeroness, we only need to set the
12295f757f3fSDimitry Andric   // AVL if the zeroness differs.  This removes a vsetvli entirely if the types
12305f757f3fSDimitry Andric   // match or allows use of cheaper avl preserving variant if VLMAX doesn't
12315f757f3fSDimitry Andric   // change. If VLMAX might change, we couldn't use the 'vsetvli x0, x0, vtype"
12325f757f3fSDimitry Andric   // variant, so we avoid the transform to prevent extending live range of an
12335f757f3fSDimitry Andric   // avl register operand.
123481ad6265SDimitry Andric   // TODO: We can probably relax this for immediates.
1235*0fca6ea1SDimitry Andric   bool EquallyZero = IncomingInfo.hasEquallyZeroAVL(PrevInfo, LIS) &&
12365f757f3fSDimitry Andric                      IncomingInfo.hasSameVLMAX(PrevInfo);
12375f757f3fSDimitry Andric   if (Demanded.VLAny || (Demanded.VLZeroness && !EquallyZero))
12385f757f3fSDimitry Andric     Info.setAVL(IncomingInfo);
123981ad6265SDimitry Andric 
12405f757f3fSDimitry Andric   Info.setVTYPE(
12415f757f3fSDimitry Andric       ((Demanded.LMUL || Demanded.SEWLMULRatio) ? IncomingInfo : Info)
12425f757f3fSDimitry Andric           .getVLMUL(),
12435f757f3fSDimitry Andric       ((Demanded.SEW || Demanded.SEWLMULRatio) ? IncomingInfo : Info).getSEW(),
12445f757f3fSDimitry Andric       // Prefer tail/mask agnostic since it can be relaxed to undisturbed later
12455f757f3fSDimitry Andric       // if needed.
12465f757f3fSDimitry Andric       (Demanded.TailPolicy ? IncomingInfo : Info).getTailAgnostic() ||
12475f757f3fSDimitry Andric           IncomingInfo.getTailAgnostic(),
12485f757f3fSDimitry Andric       (Demanded.MaskPolicy ? IncomingInfo : Info).getMaskAgnostic() ||
12495f757f3fSDimitry Andric           IncomingInfo.getMaskAgnostic());
125081ad6265SDimitry Andric 
12515f757f3fSDimitry Andric   // If we only knew the sew/lmul ratio previously, replace the VTYPE but keep
12525f757f3fSDimitry Andric   // the AVL.
12535f757f3fSDimitry Andric   if (Info.hasSEWLMULRatioOnly()) {
12545f757f3fSDimitry Andric     VSETVLIInfo RatiolessInfo = IncomingInfo;
12555f757f3fSDimitry Andric     RatiolessInfo.setAVL(Info);
12565f757f3fSDimitry Andric     Info = RatiolessInfo;
125781ad6265SDimitry Andric   }
125881ad6265SDimitry Andric }
125981ad6265SDimitry Andric 
126081ad6265SDimitry Andric // Given a state with which we evaluated MI (see transferBefore above for why
126181ad6265SDimitry Andric // this might be different that the state MI requested), modify the state to
126281ad6265SDimitry Andric // reflect the changes MI might make.
12635f757f3fSDimitry Andric void RISCVInsertVSETVLI::transferAfter(VSETVLIInfo &Info,
12645f757f3fSDimitry Andric                                        const MachineInstr &MI) const {
126581ad6265SDimitry Andric   if (isVectorConfigInstr(MI)) {
126681ad6265SDimitry Andric     Info = getInfoForVSETVLI(MI);
126781ad6265SDimitry Andric     return;
126881ad6265SDimitry Andric   }
126981ad6265SDimitry Andric 
127081ad6265SDimitry Andric   if (RISCV::isFaultFirstLoad(MI)) {
127181ad6265SDimitry Andric     // Update AVL to vl-output of the fault first load.
1272*0fca6ea1SDimitry Andric     assert(MI.getOperand(1).getReg().isVirtual());
1273*0fca6ea1SDimitry Andric     if (LIS) {
1274*0fca6ea1SDimitry Andric       auto &LI = LIS->getInterval(MI.getOperand(1).getReg());
1275*0fca6ea1SDimitry Andric       SlotIndex SI =
1276*0fca6ea1SDimitry Andric           LIS->getSlotIndexes()->getInstructionIndex(MI).getRegSlot();
1277*0fca6ea1SDimitry Andric       VNInfo *VNI = LI.getVNInfoAt(SI);
1278*0fca6ea1SDimitry Andric       Info.setAVLRegDef(VNI, MI.getOperand(1).getReg());
1279*0fca6ea1SDimitry Andric     } else
1280*0fca6ea1SDimitry Andric       Info.setAVLRegDef(nullptr, MI.getOperand(1).getReg());
128181ad6265SDimitry Andric     return;
128281ad6265SDimitry Andric   }
128381ad6265SDimitry Andric 
128481ad6265SDimitry Andric   // If this is something that updates VL/VTYPE that we don't know about, set
128581ad6265SDimitry Andric   // the state to unknown.
1286*0fca6ea1SDimitry Andric   if (MI.isCall() || MI.isInlineAsm() ||
1287*0fca6ea1SDimitry Andric       MI.modifiesRegister(RISCV::VL, /*TRI=*/nullptr) ||
1288*0fca6ea1SDimitry Andric       MI.modifiesRegister(RISCV::VTYPE, /*TRI=*/nullptr))
128981ad6265SDimitry Andric     Info = VSETVLIInfo::getUnknown();
1290349cc55cSDimitry Andric }
1291349cc55cSDimitry Andric 
12925f757f3fSDimitry Andric bool RISCVInsertVSETVLI::computeVLVTYPEChanges(const MachineBasicBlock &MBB,
12935f757f3fSDimitry Andric                                                VSETVLIInfo &Info) const {
1294fe6060f1SDimitry Andric   bool HadVectorOp = false;
1295fe6060f1SDimitry Andric 
12965f757f3fSDimitry Andric   Info = BlockInfo[MBB.getNumber()].Pred;
1297fe6060f1SDimitry Andric   for (const MachineInstr &MI : MBB) {
12985f757f3fSDimitry Andric     transferBefore(Info, MI);
1299fe6060f1SDimitry Andric 
130081ad6265SDimitry Andric     if (isVectorConfigInstr(MI) || RISCVII::hasSEWOp(MI.getDesc().TSFlags))
1301fe6060f1SDimitry Andric       HadVectorOp = true;
1302fe6060f1SDimitry Andric 
13035f757f3fSDimitry Andric     transferAfter(Info, MI);
1304fe6060f1SDimitry Andric   }
1305fe6060f1SDimitry Andric 
1306fe6060f1SDimitry Andric   return HadVectorOp;
1307fe6060f1SDimitry Andric }
1308fe6060f1SDimitry Andric 
1309fe6060f1SDimitry Andric void RISCVInsertVSETVLI::computeIncomingVLVTYPE(const MachineBasicBlock &MBB) {
131081ad6265SDimitry Andric 
1311fe6060f1SDimitry Andric   BlockData &BBInfo = BlockInfo[MBB.getNumber()];
1312fe6060f1SDimitry Andric 
1313fe6060f1SDimitry Andric   BBInfo.InQueue = false;
1314fe6060f1SDimitry Andric 
1315bdd1243dSDimitry Andric   // Start with the previous entry so that we keep the most conservative state
1316bdd1243dSDimitry Andric   // we have ever found.
1317bdd1243dSDimitry Andric   VSETVLIInfo InInfo = BBInfo.Pred;
1318fe6060f1SDimitry Andric   if (MBB.pred_empty()) {
1319fe6060f1SDimitry Andric     // There are no predecessors, so use the default starting status.
1320fe6060f1SDimitry Andric     InInfo.setUnknown();
1321fe6060f1SDimitry Andric   } else {
1322fe6060f1SDimitry Andric     for (MachineBasicBlock *P : MBB.predecessors())
1323fe6060f1SDimitry Andric       InInfo = InInfo.intersect(BlockInfo[P->getNumber()].Exit);
1324fe6060f1SDimitry Andric   }
1325fe6060f1SDimitry Andric 
1326fe6060f1SDimitry Andric   // If we don't have any valid predecessor value, wait until we do.
1327fe6060f1SDimitry Andric   if (!InInfo.isValid())
1328fe6060f1SDimitry Andric     return;
1329fe6060f1SDimitry Andric 
133081ad6265SDimitry Andric   // If no change, no need to rerun block
133181ad6265SDimitry Andric   if (InInfo == BBInfo.Pred)
133281ad6265SDimitry Andric     return;
1333fe6060f1SDimitry Andric 
133481ad6265SDimitry Andric   BBInfo.Pred = InInfo;
133581ad6265SDimitry Andric   LLVM_DEBUG(dbgs() << "Entry state of " << printMBBReference(MBB)
133681ad6265SDimitry Andric                     << " changed to " << BBInfo.Pred << "\n");
133781ad6265SDimitry Andric 
133881ad6265SDimitry Andric   // Note: It's tempting to cache the state changes here, but due to the
133981ad6265SDimitry Andric   // compatibility checks performed a blocks output state can change based on
134081ad6265SDimitry Andric   // the input state.  To cache, we'd have to add logic for finding
134181ad6265SDimitry Andric   // never-compatible state changes.
13425f757f3fSDimitry Andric   VSETVLIInfo TmpStatus;
13435f757f3fSDimitry Andric   computeVLVTYPEChanges(MBB, TmpStatus);
1344fe6060f1SDimitry Andric 
1345fe6060f1SDimitry Andric   // If the new exit value matches the old exit value, we don't need to revisit
1346fe6060f1SDimitry Andric   // any blocks.
1347fe6060f1SDimitry Andric   if (BBInfo.Exit == TmpStatus)
1348fe6060f1SDimitry Andric     return;
1349fe6060f1SDimitry Andric 
1350fe6060f1SDimitry Andric   BBInfo.Exit = TmpStatus;
135181ad6265SDimitry Andric   LLVM_DEBUG(dbgs() << "Exit state of " << printMBBReference(MBB)
135281ad6265SDimitry Andric                     << " changed to " << BBInfo.Exit << "\n");
1353fe6060f1SDimitry Andric 
1354fe6060f1SDimitry Andric   // Add the successors to the work list so we can propagate the changed exit
1355fe6060f1SDimitry Andric   // status.
1356fe6060f1SDimitry Andric   for (MachineBasicBlock *S : MBB.successors())
1357bdd1243dSDimitry Andric     if (!BlockInfo[S->getNumber()].InQueue) {
1358bdd1243dSDimitry Andric       BlockInfo[S->getNumber()].InQueue = true;
1359fe6060f1SDimitry Andric       WorkList.push(S);
1360fe6060f1SDimitry Andric     }
1361bdd1243dSDimitry Andric }
1362fe6060f1SDimitry Andric 
1363fe6060f1SDimitry Andric // If we weren't able to prove a vsetvli was directly unneeded, it might still
1364*0fca6ea1SDimitry Andric // be unneeded if the AVL was a phi node where all incoming values are VL
1365fe6060f1SDimitry Andric // outputs from the last VSETVLI in their respective basic blocks.
1366fe6060f1SDimitry Andric bool RISCVInsertVSETVLI::needVSETVLIPHI(const VSETVLIInfo &Require,
136781ad6265SDimitry Andric                                         const MachineBasicBlock &MBB) const {
1368fe6060f1SDimitry Andric   if (!Require.hasAVLReg())
1369fe6060f1SDimitry Andric     return true;
1370fe6060f1SDimitry Andric 
1371*0fca6ea1SDimitry Andric   if (!LIS)
1372fe6060f1SDimitry Andric     return true;
1373fe6060f1SDimitry Andric 
1374*0fca6ea1SDimitry Andric   // We need the AVL to have been produced by a PHI node in this basic block.
1375*0fca6ea1SDimitry Andric   const VNInfo *Valno = Require.getAVLVNInfo();
1376*0fca6ea1SDimitry Andric   if (!Valno->isPHIDef() || LIS->getMBBFromIndex(Valno->def) != &MBB)
1377fe6060f1SDimitry Andric     return true;
1378fe6060f1SDimitry Andric 
1379*0fca6ea1SDimitry Andric   const LiveRange &LR = LIS->getInterval(Require.getAVLReg());
1380*0fca6ea1SDimitry Andric 
1381*0fca6ea1SDimitry Andric   for (auto *PBB : MBB.predecessors()) {
1382*0fca6ea1SDimitry Andric     const VSETVLIInfo &PBBExit = BlockInfo[PBB->getNumber()].Exit;
1383fe6060f1SDimitry Andric 
1384fe6060f1SDimitry Andric     // We need the PHI input to the be the output of a VSET(I)VLI.
1385*0fca6ea1SDimitry Andric     const VNInfo *Value = LR.getVNInfoBefore(LIS->getMBBEndIdx(PBB));
1386*0fca6ea1SDimitry Andric     if (!Value)
1387*0fca6ea1SDimitry Andric       return true;
1388*0fca6ea1SDimitry Andric     MachineInstr *DefMI = LIS->getInstructionFromIndex(Value->def);
138981ad6265SDimitry Andric     if (!DefMI || !isVectorConfigInstr(*DefMI))
1390fe6060f1SDimitry Andric       return true;
1391fe6060f1SDimitry Andric 
1392fe6060f1SDimitry Andric     // We found a VSET(I)VLI make sure it matches the output of the
1393fe6060f1SDimitry Andric     // predecessor block.
1394fe6060f1SDimitry Andric     VSETVLIInfo DefInfo = getInfoForVSETVLI(*DefMI);
1395*0fca6ea1SDimitry Andric     if (DefInfo != PBBExit)
1396*0fca6ea1SDimitry Andric       return true;
1397*0fca6ea1SDimitry Andric 
1398*0fca6ea1SDimitry Andric     // Require has the same VL as PBBExit, so if the exit from the
1399*0fca6ea1SDimitry Andric     // predecessor has the VTYPE we are looking for we might be able
1400*0fca6ea1SDimitry Andric     // to avoid a VSETVLI.
1401*0fca6ea1SDimitry Andric     if (PBBExit.isUnknown() || !PBBExit.hasSameVTYPE(Require))
1402fe6060f1SDimitry Andric       return true;
1403fe6060f1SDimitry Andric   }
1404fe6060f1SDimitry Andric 
1405fe6060f1SDimitry Andric   // If all the incoming values to the PHI checked out, we don't need
1406fe6060f1SDimitry Andric   // to insert a VSETVLI.
1407fe6060f1SDimitry Andric   return false;
1408fe6060f1SDimitry Andric }
1409fe6060f1SDimitry Andric 
1410fe6060f1SDimitry Andric void RISCVInsertVSETVLI::emitVSETVLIs(MachineBasicBlock &MBB) {
141181ad6265SDimitry Andric   VSETVLIInfo CurInfo = BlockInfo[MBB.getNumber()].Pred;
141281ad6265SDimitry Andric   // Track whether the prefix of the block we've scanned is transparent
141381ad6265SDimitry Andric   // (meaning has not yet changed the abstract state).
141481ad6265SDimitry Andric   bool PrefixTransparent = true;
1415fe6060f1SDimitry Andric   for (MachineInstr &MI : MBB) {
141681ad6265SDimitry Andric     const VSETVLIInfo PrevInfo = CurInfo;
141781ad6265SDimitry Andric     transferBefore(CurInfo, MI);
141881ad6265SDimitry Andric 
1419fe6060f1SDimitry Andric     // If this is an explicit VSETVLI or VSETIVLI, update our state.
142081ad6265SDimitry Andric     if (isVectorConfigInstr(MI)) {
1421fe6060f1SDimitry Andric       // Conservatively, mark the VL and VTYPE as live.
1422fe6060f1SDimitry Andric       assert(MI.getOperand(3).getReg() == RISCV::VL &&
1423fe6060f1SDimitry Andric              MI.getOperand(4).getReg() == RISCV::VTYPE &&
1424fe6060f1SDimitry Andric              "Unexpected operands where VL and VTYPE should be");
1425fe6060f1SDimitry Andric       MI.getOperand(3).setIsDead(false);
1426fe6060f1SDimitry Andric       MI.getOperand(4).setIsDead(false);
142781ad6265SDimitry Andric       PrefixTransparent = false;
1428fe6060f1SDimitry Andric     }
1429fe6060f1SDimitry Andric 
1430fe6060f1SDimitry Andric     uint64_t TSFlags = MI.getDesc().TSFlags;
1431fe6060f1SDimitry Andric     if (RISCVII::hasSEWOp(TSFlags)) {
1432*0fca6ea1SDimitry Andric       if (!PrevInfo.isCompatible(DemandedFields::all(), CurInfo, LIS)) {
143381ad6265SDimitry Andric         // If this is the first implicit state change, and the state change
143481ad6265SDimitry Andric         // requested can be proven to produce the same register contents, we
143581ad6265SDimitry Andric         // can skip emitting the actual state change and continue as if we
143681ad6265SDimitry Andric         // had since we know the GPR result of the implicit state change
143781ad6265SDimitry Andric         // wouldn't be used and VL/VTYPE registers are correct.  Note that
143881ad6265SDimitry Andric         // we *do* need to model the state as if it changed as while the
143981ad6265SDimitry Andric         // register contents are unchanged, the abstract model can change.
144081ad6265SDimitry Andric         if (!PrefixTransparent || needVSETVLIPHI(CurInfo, MBB))
1441*0fca6ea1SDimitry Andric           insertVSETVLI(MBB, MI, MI.getDebugLoc(), CurInfo, PrevInfo);
144281ad6265SDimitry Andric         PrefixTransparent = false;
144381ad6265SDimitry Andric       }
144481ad6265SDimitry Andric 
1445fe6060f1SDimitry Andric       if (RISCVII::hasVLOp(TSFlags)) {
144681ad6265SDimitry Andric         MachineOperand &VLOp = MI.getOperand(getVLOpNum(MI));
1447fe6060f1SDimitry Andric         if (VLOp.isReg()) {
14485f757f3fSDimitry Andric           Register Reg = VLOp.getReg();
14495f757f3fSDimitry Andric 
1450fe6060f1SDimitry Andric           // Erase the AVL operand from the instruction.
1451fe6060f1SDimitry Andric           VLOp.setReg(RISCV::NoRegister);
1452fe6060f1SDimitry Andric           VLOp.setIsKill(false);
1453*0fca6ea1SDimitry Andric           if (LIS) {
1454*0fca6ea1SDimitry Andric             LiveInterval &LI = LIS->getInterval(Reg);
1455*0fca6ea1SDimitry Andric             SmallVector<MachineInstr *> DeadMIs;
1456*0fca6ea1SDimitry Andric             LIS->shrinkToUses(&LI, &DeadMIs);
1457*0fca6ea1SDimitry Andric             // We might have separate components that need split due to
1458*0fca6ea1SDimitry Andric             // needVSETVLIPHI causing us to skip inserting a new VL def.
1459*0fca6ea1SDimitry Andric             SmallVector<LiveInterval *> SplitLIs;
1460*0fca6ea1SDimitry Andric             LIS->splitSeparateComponents(LI, SplitLIs);
14615f757f3fSDimitry Andric 
14625f757f3fSDimitry Andric             // If the AVL was an immediate > 31, then it would have been emitted
14635f757f3fSDimitry Andric             // as an ADDI. However, the ADDI might not have been used in the
14645f757f3fSDimitry Andric             // vsetvli, or a vsetvli might not have been emitted, so it may be
14655f757f3fSDimitry Andric             // dead now.
1466*0fca6ea1SDimitry Andric             for (MachineInstr *DeadMI : DeadMIs) {
1467*0fca6ea1SDimitry Andric               if (!TII->isAddImmediate(*DeadMI, Reg))
1468*0fca6ea1SDimitry Andric                 continue;
1469*0fca6ea1SDimitry Andric               LIS->RemoveMachineInstrFromMaps(*DeadMI);
1470*0fca6ea1SDimitry Andric               DeadMI->eraseFromParent();
1471*0fca6ea1SDimitry Andric             }
1472*0fca6ea1SDimitry Andric           }
1473fe6060f1SDimitry Andric         }
1474fe6060f1SDimitry Andric         MI.addOperand(MachineOperand::CreateReg(RISCV::VL, /*isDef*/ false,
1475fe6060f1SDimitry Andric                                                 /*isImp*/ true));
1476fe6060f1SDimitry Andric       }
1477fe6060f1SDimitry Andric       MI.addOperand(MachineOperand::CreateReg(RISCV::VTYPE, /*isDef*/ false,
1478fe6060f1SDimitry Andric                                               /*isImp*/ true));
1479fe6060f1SDimitry Andric     }
1480fe6060f1SDimitry Andric 
1481*0fca6ea1SDimitry Andric     if (MI.isCall() || MI.isInlineAsm() ||
1482*0fca6ea1SDimitry Andric         MI.modifiesRegister(RISCV::VL, /*TRI=*/nullptr) ||
1483*0fca6ea1SDimitry Andric         MI.modifiesRegister(RISCV::VTYPE, /*TRI=*/nullptr))
148481ad6265SDimitry Andric       PrefixTransparent = false;
148581ad6265SDimitry Andric 
148681ad6265SDimitry Andric     transferAfter(CurInfo, MI);
1487fe6060f1SDimitry Andric   }
1488d56accc7SDimitry Andric 
148981ad6265SDimitry Andric   const auto &Info = BlockInfo[MBB.getNumber()];
149081ad6265SDimitry Andric   if (CurInfo != Info.Exit) {
149181ad6265SDimitry Andric     LLVM_DEBUG(dbgs() << "in block " << printMBBReference(MBB) << "\n");
149281ad6265SDimitry Andric     LLVM_DEBUG(dbgs() << "  begin        state: " << Info.Pred << "\n");
149381ad6265SDimitry Andric     LLVM_DEBUG(dbgs() << "  expected end state: " << Info.Exit << "\n");
149481ad6265SDimitry Andric     LLVM_DEBUG(dbgs() << "  actual   end state: " << CurInfo << "\n");
149581ad6265SDimitry Andric   }
1496*0fca6ea1SDimitry Andric   assert(CurInfo == Info.Exit && "InsertVSETVLI dataflow invariant violated");
149781ad6265SDimitry Andric }
149881ad6265SDimitry Andric 
149981ad6265SDimitry Andric /// Perform simple partial redundancy elimination of the VSETVLI instructions
150081ad6265SDimitry Andric /// we're about to insert by looking for cases where we can PRE from the
150181ad6265SDimitry Andric /// beginning of one block to the end of one of its predecessors.  Specifically,
150281ad6265SDimitry Andric /// this is geared to catch the common case of a fixed length vsetvl in a single
150381ad6265SDimitry Andric /// block loop when it could execute once in the preheader instead.
150481ad6265SDimitry Andric void RISCVInsertVSETVLI::doPRE(MachineBasicBlock &MBB) {
150581ad6265SDimitry Andric   if (!BlockInfo[MBB.getNumber()].Pred.isUnknown())
150681ad6265SDimitry Andric     return;
150781ad6265SDimitry Andric 
150881ad6265SDimitry Andric   MachineBasicBlock *UnavailablePred = nullptr;
150981ad6265SDimitry Andric   VSETVLIInfo AvailableInfo;
151081ad6265SDimitry Andric   for (MachineBasicBlock *P : MBB.predecessors()) {
151181ad6265SDimitry Andric     const VSETVLIInfo &PredInfo = BlockInfo[P->getNumber()].Exit;
151281ad6265SDimitry Andric     if (PredInfo.isUnknown()) {
151381ad6265SDimitry Andric       if (UnavailablePred)
151481ad6265SDimitry Andric         return;
151581ad6265SDimitry Andric       UnavailablePred = P;
151681ad6265SDimitry Andric     } else if (!AvailableInfo.isValid()) {
151781ad6265SDimitry Andric       AvailableInfo = PredInfo;
151881ad6265SDimitry Andric     } else if (AvailableInfo != PredInfo) {
151981ad6265SDimitry Andric       return;
152081ad6265SDimitry Andric     }
152181ad6265SDimitry Andric   }
152281ad6265SDimitry Andric 
152381ad6265SDimitry Andric   // Unreachable, single pred, or full redundancy. Note that FRE is handled by
152481ad6265SDimitry Andric   // phase 3.
152581ad6265SDimitry Andric   if (!UnavailablePred || !AvailableInfo.isValid())
152681ad6265SDimitry Andric     return;
152781ad6265SDimitry Andric 
1528*0fca6ea1SDimitry Andric   if (!LIS)
1529*0fca6ea1SDimitry Andric     return;
1530*0fca6ea1SDimitry Andric 
15311db9f3b2SDimitry Andric   // If we don't know the exact VTYPE, we can't copy the vsetvli to the exit of
15321db9f3b2SDimitry Andric   // the unavailable pred.
15331db9f3b2SDimitry Andric   if (AvailableInfo.hasSEWLMULRatioOnly())
15341db9f3b2SDimitry Andric     return;
15351db9f3b2SDimitry Andric 
153681ad6265SDimitry Andric   // Critical edge - TODO: consider splitting?
153781ad6265SDimitry Andric   if (UnavailablePred->succ_size() != 1)
153881ad6265SDimitry Andric     return;
153981ad6265SDimitry Andric 
15405f757f3fSDimitry Andric   // If the AVL value is a register (other than our VLMAX sentinel),
15415f757f3fSDimitry Andric   // we need to prove the value is available at the point we're going
15425f757f3fSDimitry Andric   // to insert the vsetvli at.
1543*0fca6ea1SDimitry Andric   if (AvailableInfo.hasAVLReg()) {
1544*0fca6ea1SDimitry Andric     SlotIndex SI = AvailableInfo.getAVLVNInfo()->def;
15455f757f3fSDimitry Andric     // This is an inline dominance check which covers the case of
15465f757f3fSDimitry Andric     // UnavailablePred being the preheader of a loop.
1547*0fca6ea1SDimitry Andric     if (LIS->getMBBFromIndex(SI) != UnavailablePred)
15485f757f3fSDimitry Andric       return;
1549*0fca6ea1SDimitry Andric     if (!UnavailablePred->terminators().empty() &&
1550*0fca6ea1SDimitry Andric         SI >= LIS->getInstructionIndex(*UnavailablePred->getFirstTerminator()))
15515f757f3fSDimitry Andric       return;
15525f757f3fSDimitry Andric   }
155381ad6265SDimitry Andric 
155406c3fb27SDimitry Andric   // Model the effect of changing the input state of the block MBB to
155506c3fb27SDimitry Andric   // AvailableInfo.  We're looking for two issues here; one legality,
155606c3fb27SDimitry Andric   // one profitability.
155706c3fb27SDimitry Andric   // 1) If the block doesn't use some of the fields from VL or VTYPE, we
155806c3fb27SDimitry Andric   //    may hit the end of the block with a different end state.  We can
155906c3fb27SDimitry Andric   //    not make this change without reflowing later blocks as well.
156006c3fb27SDimitry Andric   // 2) If we don't actually remove a transition, inserting a vsetvli
156106c3fb27SDimitry Andric   //    into the predecessor block would be correct, but unprofitable.
156206c3fb27SDimitry Andric   VSETVLIInfo OldInfo = BlockInfo[MBB.getNumber()].Pred;
156306c3fb27SDimitry Andric   VSETVLIInfo CurInfo = AvailableInfo;
156406c3fb27SDimitry Andric   int TransitionsRemoved = 0;
156506c3fb27SDimitry Andric   for (const MachineInstr &MI : MBB) {
156606c3fb27SDimitry Andric     const VSETVLIInfo LastInfo = CurInfo;
156706c3fb27SDimitry Andric     const VSETVLIInfo LastOldInfo = OldInfo;
156806c3fb27SDimitry Andric     transferBefore(CurInfo, MI);
156906c3fb27SDimitry Andric     transferBefore(OldInfo, MI);
157006c3fb27SDimitry Andric     if (CurInfo == LastInfo)
157106c3fb27SDimitry Andric       TransitionsRemoved++;
157206c3fb27SDimitry Andric     if (LastOldInfo == OldInfo)
157306c3fb27SDimitry Andric       TransitionsRemoved--;
157406c3fb27SDimitry Andric     transferAfter(CurInfo, MI);
157506c3fb27SDimitry Andric     transferAfter(OldInfo, MI);
157606c3fb27SDimitry Andric     if (CurInfo == OldInfo)
157706c3fb27SDimitry Andric       // Convergence.  All transitions after this must match by construction.
157881ad6265SDimitry Andric       break;
157981ad6265SDimitry Andric   }
158006c3fb27SDimitry Andric   if (CurInfo != OldInfo || TransitionsRemoved <= 0)
158106c3fb27SDimitry Andric     // Issues 1 and 2 above
158281ad6265SDimitry Andric     return;
158381ad6265SDimitry Andric 
158481ad6265SDimitry Andric   // Finally, update both data flow state and insert the actual vsetvli.
158581ad6265SDimitry Andric   // Doing both keeps the code in sync with the dataflow results, which
158681ad6265SDimitry Andric   // is critical for correctness of phase 3.
158706c3fb27SDimitry Andric   auto OldExit = BlockInfo[UnavailablePred->getNumber()].Exit;
158881ad6265SDimitry Andric   LLVM_DEBUG(dbgs() << "PRE VSETVLI from " << MBB.getName() << " to "
158981ad6265SDimitry Andric                     << UnavailablePred->getName() << " with state "
159081ad6265SDimitry Andric                     << AvailableInfo << "\n");
159181ad6265SDimitry Andric   BlockInfo[UnavailablePred->getNumber()].Exit = AvailableInfo;
159281ad6265SDimitry Andric   BlockInfo[MBB.getNumber()].Pred = AvailableInfo;
159381ad6265SDimitry Andric 
159481ad6265SDimitry Andric   // Note there's an implicit assumption here that terminators never use
159581ad6265SDimitry Andric   // or modify VL or VTYPE.  Also, fallthrough will return end().
159681ad6265SDimitry Andric   auto InsertPt = UnavailablePred->getFirstInstrTerminator();
159781ad6265SDimitry Andric   insertVSETVLI(*UnavailablePred, InsertPt,
159881ad6265SDimitry Andric                 UnavailablePred->findDebugLoc(InsertPt),
159906c3fb27SDimitry Andric                 AvailableInfo, OldExit);
160081ad6265SDimitry Andric }
160181ad6265SDimitry Andric 
1602bdd1243dSDimitry Andric // Return true if we can mutate PrevMI to match MI without changing any the
1603bdd1243dSDimitry Andric // fields which would be observed.
1604*0fca6ea1SDimitry Andric bool RISCVInsertVSETVLI::canMutatePriorConfig(
1605*0fca6ea1SDimitry Andric     const MachineInstr &PrevMI, const MachineInstr &MI,
1606*0fca6ea1SDimitry Andric     const DemandedFields &Used) const {
1607bdd1243dSDimitry Andric   // If the VL values aren't equal, return false if either a) the former is
1608bdd1243dSDimitry Andric   // demanded, or b) we can't rewrite the former to be the later for
1609bdd1243dSDimitry Andric   // implementation reasons.
1610bdd1243dSDimitry Andric   if (!isVLPreservingConfig(MI)) {
1611bdd1243dSDimitry Andric     if (Used.VLAny)
161281ad6265SDimitry Andric       return false;
161381ad6265SDimitry Andric 
16145f757f3fSDimitry Andric     if (Used.VLZeroness) {
16155f757f3fSDimitry Andric       if (isVLPreservingConfig(PrevMI))
1616bdd1243dSDimitry Andric         return false;
1617297eecfbSDimitry Andric       if (!getInfoForVSETVLI(PrevMI).hasEquallyZeroAVL(getInfoForVSETVLI(MI),
1618*0fca6ea1SDimitry Andric                                                        LIS))
16195f757f3fSDimitry Andric         return false;
16205f757f3fSDimitry Andric     }
1621bdd1243dSDimitry Andric 
1622297eecfbSDimitry Andric     auto &AVL = MI.getOperand(1);
1623297eecfbSDimitry Andric     auto &PrevAVL = PrevMI.getOperand(1);
1624297eecfbSDimitry Andric 
1625297eecfbSDimitry Andric     // If the AVL is a register, we need to make sure MI's AVL dominates PrevMI.
1626297eecfbSDimitry Andric     // For now just check that PrevMI uses the same virtual register.
1627*0fca6ea1SDimitry Andric     if (AVL.isReg() && AVL.getReg() != RISCV::X0 &&
1628*0fca6ea1SDimitry Andric         (!MRI->hasOneDef(AVL.getReg()) || !PrevAVL.isReg() ||
1629*0fca6ea1SDimitry Andric          PrevAVL.getReg() != AVL.getReg()))
1630297eecfbSDimitry Andric       return false;
1631297eecfbSDimitry Andric   }
1632bdd1243dSDimitry Andric 
1633*0fca6ea1SDimitry Andric   assert(PrevMI.getOperand(2).isImm() && MI.getOperand(2).isImm());
163481ad6265SDimitry Andric   auto PriorVType = PrevMI.getOperand(2).getImm();
163581ad6265SDimitry Andric   auto VType = MI.getOperand(2).getImm();
163681ad6265SDimitry Andric   return areCompatibleVTYPEs(PriorVType, VType, Used);
163781ad6265SDimitry Andric }
163881ad6265SDimitry Andric 
1639*0fca6ea1SDimitry Andric void RISCVInsertVSETVLI::coalesceVSETVLIs(MachineBasicBlock &MBB) const {
1640bdd1243dSDimitry Andric   MachineInstr *NextMI = nullptr;
1641bdd1243dSDimitry Andric   // We can have arbitrary code in successors, so VL and VTYPE
1642bdd1243dSDimitry Andric   // must be considered demanded.
164381ad6265SDimitry Andric   DemandedFields Used;
1644bdd1243dSDimitry Andric   Used.demandVL();
1645bdd1243dSDimitry Andric   Used.demandVTYPE();
164681ad6265SDimitry Andric   SmallVector<MachineInstr*> ToDelete;
1647*0fca6ea1SDimitry Andric 
1648*0fca6ea1SDimitry Andric   // Update LIS and cleanup dead AVLs given a value which has
1649*0fca6ea1SDimitry Andric   // has had one use (as an AVL) removed.
1650*0fca6ea1SDimitry Andric   auto afterDroppedAVLUse = [&](Register OldVLReg) {
1651*0fca6ea1SDimitry Andric     if (LIS)
1652*0fca6ea1SDimitry Andric       LIS->shrinkToUses(&LIS->getInterval(OldVLReg));
1653*0fca6ea1SDimitry Andric 
1654*0fca6ea1SDimitry Andric     MachineInstr *VLOpDef = MRI->getUniqueVRegDef(OldVLReg);
1655*0fca6ea1SDimitry Andric     if (VLOpDef && TII->isAddImmediate(*VLOpDef, OldVLReg) &&
1656*0fca6ea1SDimitry Andric         MRI->use_nodbg_empty(OldVLReg)) {
1657*0fca6ea1SDimitry Andric       if (LIS) {
1658*0fca6ea1SDimitry Andric         LIS->removeInterval(OldVLReg);
1659*0fca6ea1SDimitry Andric         LIS->RemoveMachineInstrFromMaps(*VLOpDef);
1660*0fca6ea1SDimitry Andric       }
1661*0fca6ea1SDimitry Andric       VLOpDef->eraseFromParent();
1662*0fca6ea1SDimitry Andric     }
1663*0fca6ea1SDimitry Andric   };
1664*0fca6ea1SDimitry Andric 
1665bdd1243dSDimitry Andric   for (MachineInstr &MI : make_range(MBB.rbegin(), MBB.rend())) {
1666bdd1243dSDimitry Andric 
1667bdd1243dSDimitry Andric     if (!isVectorConfigInstr(MI)) {
1668*0fca6ea1SDimitry Andric       Used.doUnion(getDemanded(MI, ST));
1669*0fca6ea1SDimitry Andric       if (MI.isCall() || MI.isInlineAsm() ||
1670*0fca6ea1SDimitry Andric           MI.modifiesRegister(RISCV::VL, /*TRI=*/nullptr) ||
1671*0fca6ea1SDimitry Andric           MI.modifiesRegister(RISCV::VTYPE, /*TRI=*/nullptr))
1672*0fca6ea1SDimitry Andric         NextMI = nullptr;
167381ad6265SDimitry Andric       continue;
167481ad6265SDimitry Andric     }
1675bdd1243dSDimitry Andric 
1676*0fca6ea1SDimitry Andric     if (!MI.getOperand(0).isDead())
1677bdd1243dSDimitry Andric       Used.demandVL();
1678bdd1243dSDimitry Andric 
1679bdd1243dSDimitry Andric     if (NextMI) {
1680bdd1243dSDimitry Andric       if (!Used.usedVL() && !Used.usedVTYPE()) {
1681bdd1243dSDimitry Andric         ToDelete.push_back(&MI);
1682bdd1243dSDimitry Andric         // Leave NextMI unchanged
1683bdd1243dSDimitry Andric         continue;
1684*0fca6ea1SDimitry Andric       }
1685*0fca6ea1SDimitry Andric 
1686*0fca6ea1SDimitry Andric       if (canMutatePriorConfig(MI, *NextMI, Used)) {
1687bdd1243dSDimitry Andric         if (!isVLPreservingConfig(*NextMI)) {
1688*0fca6ea1SDimitry Andric           Register DefReg = NextMI->getOperand(0).getReg();
1689*0fca6ea1SDimitry Andric 
1690*0fca6ea1SDimitry Andric           MI.getOperand(0).setReg(DefReg);
16915f757f3fSDimitry Andric           MI.getOperand(0).setIsDead(false);
1692*0fca6ea1SDimitry Andric 
1693*0fca6ea1SDimitry Andric           // The def of DefReg moved to MI, so extend the LiveInterval up to
1694*0fca6ea1SDimitry Andric           // it.
1695*0fca6ea1SDimitry Andric           if (DefReg.isVirtual() && LIS) {
1696*0fca6ea1SDimitry Andric             LiveInterval &DefLI = LIS->getInterval(DefReg);
1697*0fca6ea1SDimitry Andric             SlotIndex MISlot = LIS->getInstructionIndex(MI).getRegSlot();
1698*0fca6ea1SDimitry Andric             VNInfo *DefVNI = DefLI.getVNInfoAt(DefLI.beginIndex());
1699*0fca6ea1SDimitry Andric             LiveInterval::Segment S(MISlot, DefLI.beginIndex(), DefVNI);
1700*0fca6ea1SDimitry Andric             DefLI.addSegment(S);
1701*0fca6ea1SDimitry Andric             DefVNI->def = MISlot;
1702*0fca6ea1SDimitry Andric             // Mark DefLI as spillable if it was previously unspillable
1703*0fca6ea1SDimitry Andric             DefLI.setWeight(0);
1704*0fca6ea1SDimitry Andric 
1705*0fca6ea1SDimitry Andric             // DefReg may have had no uses, in which case we need to shrink
1706*0fca6ea1SDimitry Andric             // the LiveInterval up to MI.
1707*0fca6ea1SDimitry Andric             LIS->shrinkToUses(&DefLI);
1708*0fca6ea1SDimitry Andric           }
1709*0fca6ea1SDimitry Andric 
17105f757f3fSDimitry Andric           Register OldVLReg;
17115f757f3fSDimitry Andric           if (MI.getOperand(1).isReg())
17125f757f3fSDimitry Andric             OldVLReg = MI.getOperand(1).getReg();
1713bdd1243dSDimitry Andric           if (NextMI->getOperand(1).isImm())
1714bdd1243dSDimitry Andric             MI.getOperand(1).ChangeToImmediate(NextMI->getOperand(1).getImm());
1715bdd1243dSDimitry Andric           else
1716bdd1243dSDimitry Andric             MI.getOperand(1).ChangeToRegister(NextMI->getOperand(1).getReg(), false);
1717*0fca6ea1SDimitry Andric           if (OldVLReg && OldVLReg.isVirtual())
1718*0fca6ea1SDimitry Andric             afterDroppedAVLUse(OldVLReg);
1719*0fca6ea1SDimitry Andric 
1720bdd1243dSDimitry Andric           MI.setDesc(NextMI->getDesc());
1721bdd1243dSDimitry Andric         }
1722bdd1243dSDimitry Andric         MI.getOperand(2).setImm(NextMI->getOperand(2).getImm());
1723bdd1243dSDimitry Andric         ToDelete.push_back(NextMI);
1724bdd1243dSDimitry Andric         // fallthrough
1725bdd1243dSDimitry Andric       }
1726bdd1243dSDimitry Andric     }
1727bdd1243dSDimitry Andric     NextMI = &MI;
1728*0fca6ea1SDimitry Andric     Used = getDemanded(MI, ST);
172981ad6265SDimitry Andric   }
173081ad6265SDimitry Andric 
1731*0fca6ea1SDimitry Andric   NumCoalescedVSETVL += ToDelete.size();
1732*0fca6ea1SDimitry Andric   for (auto *MI : ToDelete) {
1733*0fca6ea1SDimitry Andric     if (LIS)
1734*0fca6ea1SDimitry Andric       LIS->RemoveMachineInstrFromMaps(*MI);
1735*0fca6ea1SDimitry Andric     Register OldAVLReg;
1736*0fca6ea1SDimitry Andric     if (MI->getOperand(1).isReg())
1737*0fca6ea1SDimitry Andric       OldAVLReg = MI->getOperand(1).getReg();
173881ad6265SDimitry Andric     MI->eraseFromParent();
1739*0fca6ea1SDimitry Andric     if (OldAVLReg && OldAVLReg.isVirtual())
1740*0fca6ea1SDimitry Andric       afterDroppedAVLUse(OldAVLReg);
1741*0fca6ea1SDimitry Andric   }
174281ad6265SDimitry Andric }
174381ad6265SDimitry Andric 
174481ad6265SDimitry Andric void RISCVInsertVSETVLI::insertReadVL(MachineBasicBlock &MBB) {
174581ad6265SDimitry Andric   for (auto I = MBB.begin(), E = MBB.end(); I != E;) {
174681ad6265SDimitry Andric     MachineInstr &MI = *I++;
174781ad6265SDimitry Andric     if (RISCV::isFaultFirstLoad(MI)) {
174881ad6265SDimitry Andric       Register VLOutput = MI.getOperand(1).getReg();
1749*0fca6ea1SDimitry Andric       assert(VLOutput.isVirtual());
1750*0fca6ea1SDimitry Andric       if (!MI.getOperand(1).isDead()) {
1751*0fca6ea1SDimitry Andric         auto ReadVLMI = BuildMI(MBB, I, MI.getDebugLoc(),
1752*0fca6ea1SDimitry Andric                                 TII->get(RISCV::PseudoReadVL), VLOutput);
1753*0fca6ea1SDimitry Andric         // Move the LiveInterval's definition down to PseudoReadVL.
1754*0fca6ea1SDimitry Andric         if (LIS) {
1755*0fca6ea1SDimitry Andric           SlotIndex NewDefSI =
1756*0fca6ea1SDimitry Andric               LIS->InsertMachineInstrInMaps(*ReadVLMI).getRegSlot();
1757*0fca6ea1SDimitry Andric           LiveInterval &DefLI = LIS->getInterval(VLOutput);
1758*0fca6ea1SDimitry Andric           VNInfo *DefVNI = DefLI.getVNInfoAt(DefLI.beginIndex());
1759*0fca6ea1SDimitry Andric           DefLI.removeSegment(DefLI.beginIndex(), NewDefSI);
1760*0fca6ea1SDimitry Andric           DefVNI->def = NewDefSI;
1761*0fca6ea1SDimitry Andric         }
1762*0fca6ea1SDimitry Andric       }
176381ad6265SDimitry Andric       // We don't use the vl output of the VLEFF/VLSEGFF anymore.
176481ad6265SDimitry Andric       MI.getOperand(1).setReg(RISCV::X0);
176581ad6265SDimitry Andric     }
1766fe6060f1SDimitry Andric   }
1767fe6060f1SDimitry Andric }
1768fe6060f1SDimitry Andric 
1769fe6060f1SDimitry Andric bool RISCVInsertVSETVLI::runOnMachineFunction(MachineFunction &MF) {
1770fe6060f1SDimitry Andric   // Skip if the vector extension is not enabled.
17715f757f3fSDimitry Andric   ST = &MF.getSubtarget<RISCVSubtarget>();
17725f757f3fSDimitry Andric   if (!ST->hasVInstructions())
1773fe6060f1SDimitry Andric     return false;
1774fe6060f1SDimitry Andric 
177581ad6265SDimitry Andric   LLVM_DEBUG(dbgs() << "Entering InsertVSETVLI for " << MF.getName() << "\n");
177681ad6265SDimitry Andric 
17775f757f3fSDimitry Andric   TII = ST->getInstrInfo();
1778fe6060f1SDimitry Andric   MRI = &MF.getRegInfo();
1779*0fca6ea1SDimitry Andric   auto *LISWrapper = getAnalysisIfAvailable<LiveIntervalsWrapperPass>();
1780*0fca6ea1SDimitry Andric   LIS = LISWrapper ? &LISWrapper->getLIS() : nullptr;
1781fe6060f1SDimitry Andric 
1782fe6060f1SDimitry Andric   assert(BlockInfo.empty() && "Expect empty block infos");
1783fe6060f1SDimitry Andric   BlockInfo.resize(MF.getNumBlockIDs());
1784fe6060f1SDimitry Andric 
1785fe6060f1SDimitry Andric   bool HaveVectorOp = false;
1786fe6060f1SDimitry Andric 
1787fe6060f1SDimitry Andric   // Phase 1 - determine how VL/VTYPE are affected by the each block.
178881ad6265SDimitry Andric   for (const MachineBasicBlock &MBB : MF) {
17895f757f3fSDimitry Andric     VSETVLIInfo TmpStatus;
17905f757f3fSDimitry Andric     HaveVectorOp |= computeVLVTYPEChanges(MBB, TmpStatus);
179181ad6265SDimitry Andric     // Initial exit state is whatever change we found in the block.
179281ad6265SDimitry Andric     BlockData &BBInfo = BlockInfo[MBB.getNumber()];
17935f757f3fSDimitry Andric     BBInfo.Exit = TmpStatus;
179481ad6265SDimitry Andric     LLVM_DEBUG(dbgs() << "Initial exit state of " << printMBBReference(MBB)
179581ad6265SDimitry Andric                       << " is " << BBInfo.Exit << "\n");
179681ad6265SDimitry Andric 
179781ad6265SDimitry Andric   }
1798fe6060f1SDimitry Andric 
1799fe6060f1SDimitry Andric   // If we didn't find any instructions that need VSETVLI, we're done.
180081ad6265SDimitry Andric   if (!HaveVectorOp) {
180181ad6265SDimitry Andric     BlockInfo.clear();
180281ad6265SDimitry Andric     return false;
180381ad6265SDimitry Andric   }
180481ad6265SDimitry Andric 
1805fe6060f1SDimitry Andric   // Phase 2 - determine the exit VL/VTYPE from each block. We add all
1806fe6060f1SDimitry Andric   // blocks to the list here, but will also add any that need to be revisited
1807fe6060f1SDimitry Andric   // during Phase 2 processing.
1808fe6060f1SDimitry Andric   for (const MachineBasicBlock &MBB : MF) {
1809fe6060f1SDimitry Andric     WorkList.push(&MBB);
1810fe6060f1SDimitry Andric     BlockInfo[MBB.getNumber()].InQueue = true;
1811fe6060f1SDimitry Andric   }
1812fe6060f1SDimitry Andric   while (!WorkList.empty()) {
1813fe6060f1SDimitry Andric     const MachineBasicBlock &MBB = *WorkList.front();
1814fe6060f1SDimitry Andric     WorkList.pop();
1815fe6060f1SDimitry Andric     computeIncomingVLVTYPE(MBB);
1816fe6060f1SDimitry Andric   }
1817fe6060f1SDimitry Andric 
181881ad6265SDimitry Andric   // Perform partial redundancy elimination of vsetvli transitions.
181981ad6265SDimitry Andric   for (MachineBasicBlock &MBB : MF)
182081ad6265SDimitry Andric     doPRE(MBB);
182181ad6265SDimitry Andric 
1822fe6060f1SDimitry Andric   // Phase 3 - add any vsetvli instructions needed in the block. Use the
1823fe6060f1SDimitry Andric   // Phase 2 information to avoid adding vsetvlis before the first vector
1824fe6060f1SDimitry Andric   // instruction in the block if the VL/VTYPE is satisfied by its
1825fe6060f1SDimitry Andric   // predecessors.
1826fe6060f1SDimitry Andric   for (MachineBasicBlock &MBB : MF)
1827fe6060f1SDimitry Andric     emitVSETVLIs(MBB);
182881ad6265SDimitry Andric 
182981ad6265SDimitry Andric   // Now that all vsetvlis are explicit, go through and do block local
183081ad6265SDimitry Andric   // DSE and peephole based demanded fields based transforms.  Note that
183181ad6265SDimitry Andric   // this *must* be done outside the main dataflow so long as we allow
183281ad6265SDimitry Andric   // any cross block analysis within the dataflow.  We can't have both
183381ad6265SDimitry Andric   // demanded fields based mutation and non-local analysis in the
183481ad6265SDimitry Andric   // dataflow at the same time without introducing inconsistencies.
183581ad6265SDimitry Andric   for (MachineBasicBlock &MBB : MF)
1836*0fca6ea1SDimitry Andric     coalesceVSETVLIs(MBB);
183781ad6265SDimitry Andric 
183881ad6265SDimitry Andric   // Insert PseudoReadVL after VLEFF/VLSEGFF and replace it with the vl output
183981ad6265SDimitry Andric   // of VLEFF/VLSEGFF.
184081ad6265SDimitry Andric   for (MachineBasicBlock &MBB : MF)
184181ad6265SDimitry Andric     insertReadVL(MBB);
1842fe6060f1SDimitry Andric 
184381ad6265SDimitry Andric   BlockInfo.clear();
1844fe6060f1SDimitry Andric   return HaveVectorOp;
1845fe6060f1SDimitry Andric }
1846fe6060f1SDimitry Andric 
1847fe6060f1SDimitry Andric /// Returns an instance of the Insert VSETVLI pass.
1848fe6060f1SDimitry Andric FunctionPass *llvm::createRISCVInsertVSETVLIPass() {
1849fe6060f1SDimitry Andric   return new RISCVInsertVSETVLI();
1850fe6060f1SDimitry Andric }
1851