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.
getVNInfoFromReg(Register Reg,const MachineInstr & MI,const LiveIntervals * LIS)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
getVLOpNum(const MachineInstr & MI)5981ad6265SDimitry Andric static unsigned getVLOpNum(const MachineInstr &MI) {
6081ad6265SDimitry Andric return RISCVII::getVLOpNum(MI.getDesc());
61fe6060f1SDimitry Andric }
62fe6060f1SDimitry Andric
getSEWOpNum(const MachineInstr & MI)6381ad6265SDimitry Andric static unsigned getSEWOpNum(const MachineInstr &MI) {
6481ad6265SDimitry Andric return RISCVII::getSEWOpNum(MI.getDesc());
65fe6060f1SDimitry Andric }
66fe6060f1SDimitry Andric
isVectorConfigInstr(const MachineInstr & MI)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.
isVLPreservingConfig(const MachineInstr & MI)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
isFloatScalarMoveOrScalarSplatInstr(const MachineInstr & MI)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
isScalarExtractInstr(const MachineInstr & MI)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
isScalarInsertInstr(const MachineInstr & MI)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
isScalarSplatInstr(const MachineInstr & MI)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
isVSlideInstr(const MachineInstr & MI)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.
getEEWForLoadStore(const MachineInstr & MI)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
isNonZeroLoadImmediate(const MachineInstr & MI)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).
isMaskRegOp(const MachineInstr & MI)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.
hasUndefinedMergeOp(const MachineInstr & MI)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
usedVTYPE__anoncddf45c50111::DemandedFields227bdd1243dSDimitry 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
usedVL__anoncddf45c50111::DemandedFields232bdd1243dSDimitry Andric bool usedVL() {
233bdd1243dSDimitry Andric return VLAny || VLZeroness;
234bdd1243dSDimitry Andric }
235bdd1243dSDimitry Andric
23681ad6265SDimitry Andric // Mark all VTYPE subfields and properties as demanded
demandVTYPE__anoncddf45c50111::DemandedFields23781ad6265SDimitry 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
demandVL__anoncddf45c50111::DemandedFields246bdd1243dSDimitry Andric void demandVL() {
247bdd1243dSDimitry Andric VLAny = true;
248bdd1243dSDimitry Andric VLZeroness = true;
249bdd1243dSDimitry Andric }
250bdd1243dSDimitry Andric
all__anoncddf45c50111::DemandedFields251*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.
doUnion__anoncddf45c50111::DemandedFields259*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()
dump__anoncddf45c50111::DemandedFields271bdd1243dSDimitry Andric LLVM_DUMP_METHOD void dump() const {
272bdd1243dSDimitry Andric print(dbgs());
273bdd1243dSDimitry Andric dbgs() << "\n";
274bdd1243dSDimitry Andric }
275bdd1243dSDimitry Andric
276bdd1243dSDimitry Andric /// Implement operator<<.
print__anoncddf45c50111::DemandedFields277bdd1243dSDimitry 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
operator <<(raw_ostream & OS,const DemandedFields & DF)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
isLMUL1OrSmaller(RISCVII::VLMUL LMUL)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.
areCompatibleVTYPEs(uint64_t CurVType,uint64_t NewVType,const DemandedFields & Used)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.
getDemanded(const MachineInstr & MI,const RISCVSubtarget * ST)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:
VSETVLIInfo()54081ad6265SDimitry Andric VSETVLIInfo()
54181ad6265SDimitry Andric : AVLImm(0), TailAgnostic(false), MaskAgnostic(false),
54281ad6265SDimitry Andric SEWLMULRatioOnly(false) {}
54381ad6265SDimitry Andric
getUnknown()54481ad6265SDimitry Andric static VSETVLIInfo getUnknown() {
54581ad6265SDimitry Andric VSETVLIInfo Info;
54681ad6265SDimitry Andric Info.setUnknown();
54781ad6265SDimitry Andric return Info;
54881ad6265SDimitry Andric }
54981ad6265SDimitry Andric
isValid() const55081ad6265SDimitry Andric bool isValid() const { return State != Uninitialized; }
setUnknown()55181ad6265SDimitry Andric void setUnknown() { State = Unknown; }
isUnknown() const55281ad6265SDimitry Andric bool isUnknown() const { return State == Unknown; }
55381ad6265SDimitry Andric
setAVLRegDef(const VNInfo * VNInfo,Register AVLReg)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
setAVLImm(unsigned Imm)56181ad6265SDimitry Andric void setAVLImm(unsigned Imm) {
56281ad6265SDimitry Andric AVLImm = Imm;
56381ad6265SDimitry Andric State = AVLIsImm;
56481ad6265SDimitry Andric }
56581ad6265SDimitry Andric
setAVLVLMAX()566*0fca6ea1SDimitry Andric void setAVLVLMAX() { State = AVLIsVLMAX; }
567*0fca6ea1SDimitry Andric
hasAVLImm() const56881ad6265SDimitry Andric bool hasAVLImm() const { return State == AVLIsImm; }
hasAVLReg() const56981ad6265SDimitry Andric bool hasAVLReg() const { return State == AVLIsReg; }
hasAVLVLMAX() const570*0fca6ea1SDimitry Andric bool hasAVLVLMAX() const { return State == AVLIsVLMAX; }
getAVLReg() const57181ad6265SDimitry Andric Register getAVLReg() const {
572*0fca6ea1SDimitry Andric assert(hasAVLReg() && AVLRegDef.DefReg.isVirtual());
573*0fca6ea1SDimitry Andric return AVLRegDef.DefReg;
57481ad6265SDimitry Andric }
getAVLImm() const57581ad6265SDimitry Andric unsigned getAVLImm() const {
57681ad6265SDimitry Andric assert(hasAVLImm());
57781ad6265SDimitry Andric return AVLImm;
57881ad6265SDimitry Andric }
getAVLVNInfo() const579*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.
getAVLDefMI(const LiveIntervals * LIS) const587*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
setAVL(VSETVLIInfo Info)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
getSEW() const61081ad6265SDimitry Andric unsigned getSEW() const { return SEW; }
getVLMUL() const61181ad6265SDimitry Andric RISCVII::VLMUL getVLMUL() const { return VLMul; }
getTailAgnostic() const6125f757f3fSDimitry Andric bool getTailAgnostic() const { return TailAgnostic; }
getMaskAgnostic() const6135f757f3fSDimitry Andric bool getMaskAgnostic() const { return MaskAgnostic; }
61481ad6265SDimitry Andric
hasNonZeroAVL(const LiveIntervals * LIS) const615*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
hasEquallyZeroAVL(const VSETVLIInfo & Other,const LiveIntervals * LIS) const62706c3fb27SDimitry 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
hasSameAVLLatticeValue(const VSETVLIInfo & Other) const634*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.
hasSameAVL(const VSETVLIInfo & Other) const655*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
setVTYPE(unsigned VType)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 }
setVTYPE(RISCVII::VLMUL L,unsigned S,bool TA,bool MA)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
setVLMul(RISCVII::VLMUL VLMul)6855f757f3fSDimitry Andric void setVLMul(RISCVII::VLMUL VLMul) { this->VLMul = VLMul; }
6865f757f3fSDimitry Andric
encodeVTYPE() const68781ad6265SDimitry 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
hasSEWLMULRatioOnly() const69381ad6265SDimitry Andric bool hasSEWLMULRatioOnly() const { return SEWLMULRatioOnly; }
69481ad6265SDimitry Andric
hasSameVTYPE(const VSETVLIInfo & Other) const69581ad6265SDimitry 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
getSEWLMULRatio() const70781ad6265SDimitry 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.
hasSameVLMAX(const VSETVLIInfo & Other) const71781ad6265SDimitry 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
hasCompatibleVTYPE(const DemandedFields & Used,const VSETVLIInfo & Require) const725bdd1243dSDimitry 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.
isCompatible(const DemandedFields & Used,const VSETVLIInfo & Require,const LiveIntervals * LIS) const73306c3fb27SDimitry 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
operator ==(const VSETVLIInfo & Other) const75481ad6265SDimitry 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
operator !=(const VSETVLIInfo & Other) const78281ad6265SDimitry 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.
intersect(const VSETVLIInfo & Other) const78881ad6265SDimitry 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()
dump() const81981ad6265SDimitry 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 /// @{
print(raw_ostream & OS) const82681ad6265SDimitry 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
operator <<(raw_ostream & OS,const VSETVLIInfo & V)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
RISCVInsertVSETVLI()8845f757f3fSDimitry Andric RISCVInsertVSETVLI() : MachineFunctionPass(ID) {}
88581ad6265SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override;
88681ad6265SDimitry Andric
getAnalysisUsage(AnalysisUsage & AU) const88781ad6265SDimitry 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
getPassName() const89981ad6265SDimitry 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
INITIALIZE_PASS(RISCVInsertVSETVLI,DEBUG_TYPE,RISCV_INSERT_VSETVLI_NAME,false,false)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
getInfoForVSETVLI(const MachineInstr & MI) const959*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
computeVLMAX(unsigned VLEN,unsigned SEW,RISCVII::VLMUL VLMul)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
computeInfoForInstr(const MachineInstr & MI) const997*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
insertVSETVLI(MachineBasicBlock & MBB,MachineBasicBlock::iterator InsertPt,DebugLoc DL,const VSETVLIInfo & Info,const VSETVLIInfo & PrevInfo)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.
needVSETVLI(const DemandedFields & Used,const VSETVLIInfo & Require,const VSETVLIInfo & CurInfo) const1177*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.
adjustIncoming(VSETVLIInfo PrevInfo,VSETVLIInfo NewInfo,DemandedFields & Demanded)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.
transferBefore(VSETVLIInfo & Info,const MachineInstr & MI) const12105f757f3fSDimitry 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.
transferAfter(VSETVLIInfo & Info,const MachineInstr & MI) const12635f757f3fSDimitry 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
computeVLVTYPEChanges(const MachineBasicBlock & MBB,VSETVLIInfo & Info) const12925f757f3fSDimitry 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
computeIncomingVLVTYPE(const MachineBasicBlock & MBB)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.
needVSETVLIPHI(const VSETVLIInfo & Require,const MachineBasicBlock & MBB) const1366fe6060f1SDimitry 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
emitVSETVLIs(MachineBasicBlock & MBB)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.
doPRE(MachineBasicBlock & MBB)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.
canMutatePriorConfig(const MachineInstr & PrevMI,const MachineInstr & MI,const DemandedFields & Used) const1604*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
coalesceVSETVLIs(MachineBasicBlock & MBB) const1639*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
insertReadVL(MachineBasicBlock & MBB)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
runOnMachineFunction(MachineFunction & MF)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.
createRISCVInsertVSETVLIPass()1848fe6060f1SDimitry Andric FunctionPass *llvm::createRISCVInsertVSETVLIPass() {
1849fe6060f1SDimitry Andric return new RISCVInsertVSETVLI();
1850fe6060f1SDimitry Andric }
1851