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" 29*7a6dacacSDimitry Andric #include "llvm/ADT/Statistic.h" 30fe6060f1SDimitry Andric #include "llvm/CodeGen/LiveIntervals.h" 31fe6060f1SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 32fe6060f1SDimitry Andric #include <queue> 33fe6060f1SDimitry Andric using namespace llvm; 34fe6060f1SDimitry Andric 35fe6060f1SDimitry Andric #define DEBUG_TYPE "riscv-insert-vsetvli" 3606c3fb27SDimitry Andric #define RISCV_INSERT_VSETVLI_NAME "RISC-V Insert VSETVLI pass" 37fe6060f1SDimitry Andric 38*7a6dacacSDimitry Andric STATISTIC(NumInsertedVSETVL, "Number of VSETVL inst inserted"); 39*7a6dacacSDimitry Andric STATISTIC(NumRemovedVSETVL, "Number of VSETVL inst removed"); 40*7a6dacacSDimitry Andric 41fe6060f1SDimitry Andric static cl::opt<bool> DisableInsertVSETVLPHIOpt( 42fe6060f1SDimitry Andric "riscv-disable-insert-vsetvl-phi-opt", cl::init(false), cl::Hidden, 43fe6060f1SDimitry Andric cl::desc("Disable looking through phis when inserting vsetvlis.")); 44fe6060f1SDimitry Andric 4581ad6265SDimitry Andric static cl::opt<bool> UseStrictAsserts( 4681ad6265SDimitry Andric "riscv-insert-vsetvl-strict-asserts", cl::init(true), cl::Hidden, 4781ad6265SDimitry Andric cl::desc("Enable strict assertion checking for the dataflow algorithm")); 4881ad6265SDimitry Andric 49fe6060f1SDimitry Andric namespace { 50fe6060f1SDimitry Andric 5181ad6265SDimitry Andric static unsigned getVLOpNum(const MachineInstr &MI) { 5281ad6265SDimitry Andric return RISCVII::getVLOpNum(MI.getDesc()); 53fe6060f1SDimitry Andric } 54fe6060f1SDimitry Andric 5581ad6265SDimitry Andric static unsigned getSEWOpNum(const MachineInstr &MI) { 5681ad6265SDimitry Andric return RISCVII::getSEWOpNum(MI.getDesc()); 57fe6060f1SDimitry Andric } 58fe6060f1SDimitry Andric 59bdd1243dSDimitry Andric static bool isVectorConfigInstr(const MachineInstr &MI) { 60bdd1243dSDimitry Andric return MI.getOpcode() == RISCV::PseudoVSETVLI || 61bdd1243dSDimitry Andric MI.getOpcode() == RISCV::PseudoVSETVLIX0 || 62bdd1243dSDimitry Andric MI.getOpcode() == RISCV::PseudoVSETIVLI; 63bdd1243dSDimitry Andric } 64bdd1243dSDimitry Andric 65bdd1243dSDimitry Andric /// Return true if this is 'vsetvli x0, x0, vtype' which preserves 66bdd1243dSDimitry Andric /// VL and only sets VTYPE. 67bdd1243dSDimitry Andric static bool isVLPreservingConfig(const MachineInstr &MI) { 68bdd1243dSDimitry Andric if (MI.getOpcode() != RISCV::PseudoVSETVLIX0) 69bdd1243dSDimitry Andric return false; 70bdd1243dSDimitry Andric assert(RISCV::X0 == MI.getOperand(1).getReg()); 71bdd1243dSDimitry Andric return RISCV::X0 == MI.getOperand(0).getReg(); 72bdd1243dSDimitry Andric } 73bdd1243dSDimitry Andric 745f757f3fSDimitry Andric static bool isFloatScalarMoveOrScalarSplatInstr(const MachineInstr &MI) { 755f757f3fSDimitry Andric switch (RISCV::getRVVMCOpcode(MI.getOpcode())) { 765f757f3fSDimitry Andric default: 775f757f3fSDimitry Andric return false; 785f757f3fSDimitry Andric case RISCV::VFMV_S_F: 795f757f3fSDimitry Andric case RISCV::VFMV_V_F: 805f757f3fSDimitry Andric return true; 815f757f3fSDimitry Andric } 82bdd1243dSDimitry Andric } 83bdd1243dSDimitry Andric 845f757f3fSDimitry Andric static bool isScalarExtractInstr(const MachineInstr &MI) { 855f757f3fSDimitry Andric switch (RISCV::getRVVMCOpcode(MI.getOpcode())) { 865f757f3fSDimitry Andric default: 875f757f3fSDimitry Andric return false; 885f757f3fSDimitry Andric case RISCV::VMV_X_S: 895f757f3fSDimitry Andric case RISCV::VFMV_F_S: 905f757f3fSDimitry Andric return true; 915f757f3fSDimitry Andric } 925f757f3fSDimitry Andric } 935f757f3fSDimitry Andric 945f757f3fSDimitry Andric static bool isScalarInsertInstr(const MachineInstr &MI) { 955f757f3fSDimitry Andric switch (RISCV::getRVVMCOpcode(MI.getOpcode())) { 9604eeddc0SDimitry Andric default: 9704eeddc0SDimitry Andric return false; 98bdd1243dSDimitry Andric case RISCV::VMV_S_X: 99bdd1243dSDimitry Andric case RISCV::VFMV_S_F: 10004eeddc0SDimitry Andric return true; 10104eeddc0SDimitry Andric } 10204eeddc0SDimitry Andric } 10304eeddc0SDimitry Andric 10406c3fb27SDimitry Andric static bool isScalarSplatInstr(const MachineInstr &MI) { 1055f757f3fSDimitry Andric switch (RISCV::getRVVMCOpcode(MI.getOpcode())) { 10606c3fb27SDimitry Andric default: 10706c3fb27SDimitry Andric return false; 10806c3fb27SDimitry Andric case RISCV::VMV_V_I: 10906c3fb27SDimitry Andric case RISCV::VMV_V_X: 11006c3fb27SDimitry Andric case RISCV::VFMV_V_F: 11106c3fb27SDimitry Andric return true; 11206c3fb27SDimitry Andric } 11306c3fb27SDimitry Andric } 11406c3fb27SDimitry Andric 11506c3fb27SDimitry Andric static bool isVSlideInstr(const MachineInstr &MI) { 1165f757f3fSDimitry Andric switch (RISCV::getRVVMCOpcode(MI.getOpcode())) { 11706c3fb27SDimitry Andric default: 11806c3fb27SDimitry Andric return false; 11906c3fb27SDimitry Andric case RISCV::VSLIDEDOWN_VX: 12006c3fb27SDimitry Andric case RISCV::VSLIDEDOWN_VI: 12106c3fb27SDimitry Andric case RISCV::VSLIDEUP_VX: 12206c3fb27SDimitry Andric case RISCV::VSLIDEUP_VI: 12306c3fb27SDimitry Andric return true; 12406c3fb27SDimitry Andric } 12506c3fb27SDimitry Andric } 12606c3fb27SDimitry Andric 127bdd1243dSDimitry Andric /// Get the EEW for a load or store instruction. Return std::nullopt if MI is 128bdd1243dSDimitry Andric /// not a load or store which ignores SEW. 129bdd1243dSDimitry Andric static std::optional<unsigned> getEEWForLoadStore(const MachineInstr &MI) { 1305f757f3fSDimitry Andric switch (RISCV::getRVVMCOpcode(MI.getOpcode())) { 131349cc55cSDimitry Andric default: 132bdd1243dSDimitry Andric return std::nullopt; 133bdd1243dSDimitry Andric case RISCV::VLE8_V: 134bdd1243dSDimitry Andric case RISCV::VLSE8_V: 135bdd1243dSDimitry Andric case RISCV::VSE8_V: 136bdd1243dSDimitry Andric case RISCV::VSSE8_V: 13781ad6265SDimitry Andric return 8; 138bdd1243dSDimitry Andric case RISCV::VLE16_V: 139bdd1243dSDimitry Andric case RISCV::VLSE16_V: 140bdd1243dSDimitry Andric case RISCV::VSE16_V: 141bdd1243dSDimitry Andric case RISCV::VSSE16_V: 14281ad6265SDimitry Andric return 16; 143bdd1243dSDimitry Andric case RISCV::VLE32_V: 144bdd1243dSDimitry Andric case RISCV::VLSE32_V: 145bdd1243dSDimitry Andric case RISCV::VSE32_V: 146bdd1243dSDimitry Andric case RISCV::VSSE32_V: 14781ad6265SDimitry Andric return 32; 148bdd1243dSDimitry Andric case RISCV::VLE64_V: 149bdd1243dSDimitry Andric case RISCV::VLSE64_V: 150bdd1243dSDimitry Andric case RISCV::VSE64_V: 151bdd1243dSDimitry Andric case RISCV::VSSE64_V: 15281ad6265SDimitry Andric return 64; 15381ad6265SDimitry Andric } 154349cc55cSDimitry Andric } 155349cc55cSDimitry Andric 1565f757f3fSDimitry Andric static bool isNonZeroLoadImmediate(MachineInstr &MI) { 1575f757f3fSDimitry Andric return MI.getOpcode() == RISCV::ADDI && 1585f757f3fSDimitry Andric MI.getOperand(1).isReg() && MI.getOperand(2).isImm() && 1595f757f3fSDimitry Andric MI.getOperand(1).getReg() == RISCV::X0 && 1605f757f3fSDimitry Andric MI.getOperand(2).getImm() != 0; 1615f757f3fSDimitry Andric } 1625f757f3fSDimitry Andric 16381ad6265SDimitry Andric /// Return true if this is an operation on mask registers. Note that 16481ad6265SDimitry Andric /// this includes both arithmetic/logical ops and load/store (vlm/vsm). 16581ad6265SDimitry Andric static bool isMaskRegOp(const MachineInstr &MI) { 166bdd1243dSDimitry Andric if (!RISCVII::hasSEWOp(MI.getDesc().TSFlags)) 167bdd1243dSDimitry Andric return false; 16881ad6265SDimitry Andric const unsigned Log2SEW = MI.getOperand(getSEWOpNum(MI)).getImm(); 16981ad6265SDimitry Andric // A Log2SEW of 0 is an operation on mask registers only. 17081ad6265SDimitry Andric return Log2SEW == 0; 17181ad6265SDimitry Andric } 17281ad6265SDimitry Andric 17306c3fb27SDimitry Andric /// Return true if the inactive elements in the result are entirely undefined. 17406c3fb27SDimitry Andric /// Note that this is different from "agnostic" as defined by the vector 17506c3fb27SDimitry Andric /// specification. Agnostic requires each lane to either be undisturbed, or 17606c3fb27SDimitry Andric /// take the value -1; no other value is allowed. 17706c3fb27SDimitry Andric static bool hasUndefinedMergeOp(const MachineInstr &MI, 17806c3fb27SDimitry Andric const MachineRegisterInfo &MRI) { 17906c3fb27SDimitry Andric 18006c3fb27SDimitry Andric unsigned UseOpIdx; 18106c3fb27SDimitry Andric if (!MI.isRegTiedToUseOperand(0, &UseOpIdx)) 18206c3fb27SDimitry Andric // If there is no passthrough operand, then the pass through 18306c3fb27SDimitry Andric // lanes are undefined. 18406c3fb27SDimitry Andric return true; 18506c3fb27SDimitry Andric 1865f757f3fSDimitry Andric // If the tied operand is NoReg, an IMPLICIT_DEF, or a REG_SEQEUENCE whose 1875f757f3fSDimitry Andric // operands are solely IMPLICIT_DEFS, then the pass through lanes are 1885f757f3fSDimitry Andric // undefined. 18906c3fb27SDimitry Andric const MachineOperand &UseMO = MI.getOperand(UseOpIdx); 1905f757f3fSDimitry Andric if (UseMO.getReg() == RISCV::NoRegister) 1915f757f3fSDimitry Andric return true; 1925f757f3fSDimitry Andric 19306c3fb27SDimitry Andric if (MachineInstr *UseMI = MRI.getVRegDef(UseMO.getReg())) { 19406c3fb27SDimitry Andric if (UseMI->isImplicitDef()) 19506c3fb27SDimitry Andric return true; 19606c3fb27SDimitry Andric 19706c3fb27SDimitry Andric if (UseMI->isRegSequence()) { 19806c3fb27SDimitry Andric for (unsigned i = 1, e = UseMI->getNumOperands(); i < e; i += 2) { 19906c3fb27SDimitry Andric MachineInstr *SourceMI = MRI.getVRegDef(UseMI->getOperand(i).getReg()); 20006c3fb27SDimitry Andric if (!SourceMI || !SourceMI->isImplicitDef()) 20106c3fb27SDimitry Andric return false; 20206c3fb27SDimitry Andric } 20306c3fb27SDimitry Andric return true; 20406c3fb27SDimitry Andric } 20506c3fb27SDimitry Andric } 20606c3fb27SDimitry Andric return false; 20706c3fb27SDimitry Andric } 20806c3fb27SDimitry Andric 20981ad6265SDimitry Andric /// Which subfields of VL or VTYPE have values we need to preserve? 21081ad6265SDimitry Andric struct DemandedFields { 211bdd1243dSDimitry Andric // Some unknown property of VL is used. If demanded, must preserve entire 212bdd1243dSDimitry Andric // value. 213bdd1243dSDimitry Andric bool VLAny = false; 214bdd1243dSDimitry Andric // Only zero vs non-zero is used. If demanded, can change non-zero values. 215bdd1243dSDimitry Andric bool VLZeroness = false; 21606c3fb27SDimitry Andric // What properties of SEW we need to preserve. 21706c3fb27SDimitry Andric enum : uint8_t { 2185f757f3fSDimitry Andric SEWEqual = 3, // The exact value of SEW needs to be preserved. 2195f757f3fSDimitry Andric SEWGreaterThanOrEqual = 2, // SEW can be changed as long as it's greater 22006c3fb27SDimitry Andric // than or equal to the original value. 2215f757f3fSDimitry Andric SEWGreaterThanOrEqualAndLessThan64 = 2225f757f3fSDimitry Andric 1, // SEW can be changed as long as it's greater 2235f757f3fSDimitry Andric // than or equal to the original value, but must be less 2245f757f3fSDimitry Andric // than 64. 22506c3fb27SDimitry Andric SEWNone = 0 // We don't need to preserve SEW at all. 22606c3fb27SDimitry Andric } SEW = SEWNone; 22781ad6265SDimitry Andric bool LMUL = false; 22881ad6265SDimitry Andric bool SEWLMULRatio = false; 22981ad6265SDimitry Andric bool TailPolicy = false; 23081ad6265SDimitry Andric bool MaskPolicy = false; 23181ad6265SDimitry Andric 23281ad6265SDimitry Andric // Return true if any part of VTYPE was used 233bdd1243dSDimitry Andric bool usedVTYPE() const { 23481ad6265SDimitry Andric return SEW || LMUL || SEWLMULRatio || TailPolicy || MaskPolicy; 23581ad6265SDimitry Andric } 23681ad6265SDimitry Andric 237bdd1243dSDimitry Andric // Return true if any property of VL was used 238bdd1243dSDimitry Andric bool usedVL() { 239bdd1243dSDimitry Andric return VLAny || VLZeroness; 240bdd1243dSDimitry Andric } 241bdd1243dSDimitry Andric 24281ad6265SDimitry Andric // Mark all VTYPE subfields and properties as demanded 24381ad6265SDimitry Andric void demandVTYPE() { 24406c3fb27SDimitry Andric SEW = SEWEqual; 24581ad6265SDimitry Andric LMUL = true; 24681ad6265SDimitry Andric SEWLMULRatio = true; 24781ad6265SDimitry Andric TailPolicy = true; 24881ad6265SDimitry Andric MaskPolicy = true; 24981ad6265SDimitry Andric } 250bdd1243dSDimitry Andric 251bdd1243dSDimitry Andric // Mark all VL properties as demanded 252bdd1243dSDimitry Andric void demandVL() { 253bdd1243dSDimitry Andric VLAny = true; 254bdd1243dSDimitry Andric VLZeroness = true; 255bdd1243dSDimitry Andric } 256bdd1243dSDimitry Andric 257bdd1243dSDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 258bdd1243dSDimitry Andric /// Support for debugging, callable in GDB: V->dump() 259bdd1243dSDimitry Andric LLVM_DUMP_METHOD void dump() const { 260bdd1243dSDimitry Andric print(dbgs()); 261bdd1243dSDimitry Andric dbgs() << "\n"; 262bdd1243dSDimitry Andric } 263bdd1243dSDimitry Andric 264bdd1243dSDimitry Andric /// Implement operator<<. 265bdd1243dSDimitry Andric void print(raw_ostream &OS) const { 266bdd1243dSDimitry Andric OS << "{"; 267bdd1243dSDimitry Andric OS << "VLAny=" << VLAny << ", "; 268bdd1243dSDimitry Andric OS << "VLZeroness=" << VLZeroness << ", "; 26906c3fb27SDimitry Andric OS << "SEW="; 27006c3fb27SDimitry Andric switch (SEW) { 27106c3fb27SDimitry Andric case SEWEqual: 27206c3fb27SDimitry Andric OS << "SEWEqual"; 27306c3fb27SDimitry Andric break; 27406c3fb27SDimitry Andric case SEWGreaterThanOrEqual: 27506c3fb27SDimitry Andric OS << "SEWGreaterThanOrEqual"; 27606c3fb27SDimitry Andric break; 2775f757f3fSDimitry Andric case SEWGreaterThanOrEqualAndLessThan64: 2785f757f3fSDimitry Andric OS << "SEWGreaterThanOrEqualAndLessThan64"; 2795f757f3fSDimitry Andric break; 28006c3fb27SDimitry Andric case SEWNone: 28106c3fb27SDimitry Andric OS << "SEWNone"; 28206c3fb27SDimitry Andric break; 28306c3fb27SDimitry Andric }; 28406c3fb27SDimitry Andric OS << ", "; 285bdd1243dSDimitry Andric OS << "LMUL=" << LMUL << ", "; 286bdd1243dSDimitry Andric OS << "SEWLMULRatio=" << SEWLMULRatio << ", "; 287bdd1243dSDimitry Andric OS << "TailPolicy=" << TailPolicy << ", "; 288bdd1243dSDimitry Andric OS << "MaskPolicy=" << MaskPolicy; 289bdd1243dSDimitry Andric OS << "}"; 290bdd1243dSDimitry Andric } 291bdd1243dSDimitry Andric #endif 29281ad6265SDimitry Andric }; 29381ad6265SDimitry Andric 294bdd1243dSDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 295bdd1243dSDimitry Andric LLVM_ATTRIBUTE_USED 296bdd1243dSDimitry Andric inline raw_ostream &operator<<(raw_ostream &OS, const DemandedFields &DF) { 297bdd1243dSDimitry Andric DF.print(OS); 298bdd1243dSDimitry Andric return OS; 299bdd1243dSDimitry Andric } 300bdd1243dSDimitry Andric #endif 301bdd1243dSDimitry Andric 30206c3fb27SDimitry Andric /// Return true if moving from CurVType to NewVType is 30306c3fb27SDimitry Andric /// indistinguishable from the perspective of an instruction (or set 30406c3fb27SDimitry Andric /// of instructions) which use only the Used subfields and properties. 30506c3fb27SDimitry Andric static bool areCompatibleVTYPEs(uint64_t CurVType, uint64_t NewVType, 30681ad6265SDimitry Andric const DemandedFields &Used) { 3075f757f3fSDimitry Andric switch (Used.SEW) { 3085f757f3fSDimitry Andric case DemandedFields::SEWNone: 3095f757f3fSDimitry Andric break; 3105f757f3fSDimitry Andric case DemandedFields::SEWEqual: 3115f757f3fSDimitry Andric if (RISCVVType::getSEW(CurVType) != RISCVVType::getSEW(NewVType)) 31206c3fb27SDimitry Andric return false; 3135f757f3fSDimitry Andric break; 3145f757f3fSDimitry Andric case DemandedFields::SEWGreaterThanOrEqual: 3155f757f3fSDimitry Andric if (RISCVVType::getSEW(NewVType) < RISCVVType::getSEW(CurVType)) 31681ad6265SDimitry Andric return false; 3175f757f3fSDimitry Andric break; 3185f757f3fSDimitry Andric case DemandedFields::SEWGreaterThanOrEqualAndLessThan64: 3195f757f3fSDimitry Andric if (RISCVVType::getSEW(NewVType) < RISCVVType::getSEW(CurVType) || 3205f757f3fSDimitry Andric RISCVVType::getSEW(NewVType) >= 64) 3215f757f3fSDimitry Andric return false; 3225f757f3fSDimitry Andric break; 3235f757f3fSDimitry Andric } 32481ad6265SDimitry Andric 32581ad6265SDimitry Andric if (Used.LMUL && 32606c3fb27SDimitry Andric RISCVVType::getVLMUL(CurVType) != RISCVVType::getVLMUL(NewVType)) 32781ad6265SDimitry Andric return false; 32881ad6265SDimitry Andric 32981ad6265SDimitry Andric if (Used.SEWLMULRatio) { 33006c3fb27SDimitry Andric auto Ratio1 = RISCVVType::getSEWLMULRatio(RISCVVType::getSEW(CurVType), 33106c3fb27SDimitry Andric RISCVVType::getVLMUL(CurVType)); 33206c3fb27SDimitry Andric auto Ratio2 = RISCVVType::getSEWLMULRatio(RISCVVType::getSEW(NewVType), 33306c3fb27SDimitry Andric RISCVVType::getVLMUL(NewVType)); 33481ad6265SDimitry Andric if (Ratio1 != Ratio2) 33581ad6265SDimitry Andric return false; 33681ad6265SDimitry Andric } 33781ad6265SDimitry Andric 33806c3fb27SDimitry Andric if (Used.TailPolicy && RISCVVType::isTailAgnostic(CurVType) != 33906c3fb27SDimitry Andric RISCVVType::isTailAgnostic(NewVType)) 34081ad6265SDimitry Andric return false; 34106c3fb27SDimitry Andric if (Used.MaskPolicy && RISCVVType::isMaskAgnostic(CurVType) != 34206c3fb27SDimitry Andric RISCVVType::isMaskAgnostic(NewVType)) 34381ad6265SDimitry Andric return false; 34481ad6265SDimitry Andric return true; 34581ad6265SDimitry Andric } 34681ad6265SDimitry Andric 34781ad6265SDimitry Andric /// Return the fields and properties demanded by the provided instruction. 34806c3fb27SDimitry Andric DemandedFields getDemanded(const MachineInstr &MI, 3495f757f3fSDimitry Andric const MachineRegisterInfo *MRI, 3505f757f3fSDimitry Andric const RISCVSubtarget *ST) { 35181ad6265SDimitry Andric // Warning: This function has to work on both the lowered (i.e. post 35281ad6265SDimitry Andric // emitVSETVLIs) and pre-lowering forms. The main implication of this is 35381ad6265SDimitry Andric // that it can't use the value of a SEW, VL, or Policy operand as they might 35481ad6265SDimitry Andric // be stale after lowering. 35581ad6265SDimitry Andric 35681ad6265SDimitry Andric // Most instructions don't use any of these subfeilds. 35781ad6265SDimitry Andric DemandedFields Res; 35881ad6265SDimitry Andric // Start conservative if registers are used 35981ad6265SDimitry Andric if (MI.isCall() || MI.isInlineAsm() || MI.readsRegister(RISCV::VL)) 36006c3fb27SDimitry Andric Res.demandVL(); 36181ad6265SDimitry Andric if (MI.isCall() || MI.isInlineAsm() || MI.readsRegister(RISCV::VTYPE)) 36281ad6265SDimitry Andric Res.demandVTYPE(); 36381ad6265SDimitry Andric // Start conservative on the unlowered form too 36481ad6265SDimitry Andric uint64_t TSFlags = MI.getDesc().TSFlags; 36581ad6265SDimitry Andric if (RISCVII::hasSEWOp(TSFlags)) { 36681ad6265SDimitry Andric Res.demandVTYPE(); 36781ad6265SDimitry Andric if (RISCVII::hasVLOp(TSFlags)) 368bdd1243dSDimitry Andric Res.demandVL(); 369bdd1243dSDimitry Andric 370bdd1243dSDimitry Andric // Behavior is independent of mask policy. 371bdd1243dSDimitry Andric if (!RISCVII::usesMaskPolicy(TSFlags)) 372bdd1243dSDimitry Andric Res.MaskPolicy = false; 37381ad6265SDimitry Andric } 37481ad6265SDimitry Andric 37581ad6265SDimitry Andric // Loads and stores with implicit EEW do not demand SEW or LMUL directly. 37681ad6265SDimitry Andric // They instead demand the ratio of the two which is used in computing 37781ad6265SDimitry Andric // EMUL, but which allows us the flexibility to change SEW and LMUL 37881ad6265SDimitry Andric // provided we don't change the ratio. 37981ad6265SDimitry Andric // Note: We assume that the instructions initial SEW is the EEW encoded 38081ad6265SDimitry Andric // in the opcode. This is asserted when constructing the VSETVLIInfo. 38181ad6265SDimitry Andric if (getEEWForLoadStore(MI)) { 38206c3fb27SDimitry Andric Res.SEW = DemandedFields::SEWNone; 38381ad6265SDimitry Andric Res.LMUL = false; 38481ad6265SDimitry Andric } 38581ad6265SDimitry Andric 38681ad6265SDimitry Andric // Store instructions don't use the policy fields. 38781ad6265SDimitry Andric if (RISCVII::hasSEWOp(TSFlags) && MI.getNumExplicitDefs() == 0) { 38881ad6265SDimitry Andric Res.TailPolicy = false; 38981ad6265SDimitry Andric Res.MaskPolicy = false; 39081ad6265SDimitry Andric } 39181ad6265SDimitry Andric 39281ad6265SDimitry Andric // If this is a mask reg operation, it only cares about VLMAX. 39381ad6265SDimitry Andric // TODO: Possible extensions to this logic 39481ad6265SDimitry Andric // * Probably ok if available VLMax is larger than demanded 39581ad6265SDimitry Andric // * The policy bits can probably be ignored.. 39681ad6265SDimitry Andric if (isMaskRegOp(MI)) { 39706c3fb27SDimitry Andric Res.SEW = DemandedFields::SEWNone; 39881ad6265SDimitry Andric Res.LMUL = false; 39981ad6265SDimitry Andric } 40081ad6265SDimitry Andric 401bdd1243dSDimitry Andric // For vmv.s.x and vfmv.s.f, there are only two behaviors, VL = 0 and VL > 0. 4025f757f3fSDimitry Andric if (isScalarInsertInstr(MI)) { 403bdd1243dSDimitry Andric Res.LMUL = false; 404bdd1243dSDimitry Andric Res.SEWLMULRatio = false; 405bdd1243dSDimitry Andric Res.VLAny = false; 40606c3fb27SDimitry Andric // For vmv.s.x and vfmv.s.f, if the merge operand is *undefined*, we don't 40706c3fb27SDimitry Andric // need to preserve any other bits and are thus compatible with any larger, 40806c3fb27SDimitry Andric // etype and can disregard policy bits. Warning: It's tempting to try doing 40906c3fb27SDimitry Andric // this for any tail agnostic operation, but we can't as TA requires 41006c3fb27SDimitry Andric // tail lanes to either be the original value or -1. We are writing 41106c3fb27SDimitry Andric // unknown bits to the lanes here. 41206c3fb27SDimitry Andric if (hasUndefinedMergeOp(MI, *MRI)) { 4135f757f3fSDimitry Andric if (isFloatScalarMoveOrScalarSplatInstr(MI) && !ST->hasVInstructionsF64()) 4145f757f3fSDimitry Andric Res.SEW = DemandedFields::SEWGreaterThanOrEqualAndLessThan64; 4155f757f3fSDimitry Andric else 41606c3fb27SDimitry Andric Res.SEW = DemandedFields::SEWGreaterThanOrEqual; 41706c3fb27SDimitry Andric Res.TailPolicy = false; 41806c3fb27SDimitry Andric } 419bdd1243dSDimitry Andric } 420bdd1243dSDimitry Andric 4215f757f3fSDimitry Andric // vmv.x.s, and vmv.f.s are unconditional and ignore everything except SEW. 4225f757f3fSDimitry Andric if (isScalarExtractInstr(MI)) { 4235f757f3fSDimitry Andric assert(!RISCVII::hasVLOp(TSFlags)); 4245f757f3fSDimitry Andric Res.LMUL = false; 4255f757f3fSDimitry Andric Res.SEWLMULRatio = false; 4265f757f3fSDimitry Andric Res.TailPolicy = false; 4275f757f3fSDimitry Andric Res.MaskPolicy = false; 4285f757f3fSDimitry Andric } 4295f757f3fSDimitry Andric 43081ad6265SDimitry Andric return Res; 43181ad6265SDimitry Andric } 43281ad6265SDimitry Andric 43381ad6265SDimitry Andric /// Defines the abstract state with which the forward dataflow models the 43481ad6265SDimitry Andric /// values of the VL and VTYPE registers after insertion. 43581ad6265SDimitry Andric class VSETVLIInfo { 43681ad6265SDimitry Andric union { 43781ad6265SDimitry Andric Register AVLReg; 43881ad6265SDimitry Andric unsigned AVLImm; 43981ad6265SDimitry Andric }; 44081ad6265SDimitry Andric 44181ad6265SDimitry Andric enum : uint8_t { 44281ad6265SDimitry Andric Uninitialized, 44381ad6265SDimitry Andric AVLIsReg, 44481ad6265SDimitry Andric AVLIsImm, 44581ad6265SDimitry Andric Unknown, 44681ad6265SDimitry Andric } State = Uninitialized; 44781ad6265SDimitry Andric 44881ad6265SDimitry Andric // Fields from VTYPE. 44981ad6265SDimitry Andric RISCVII::VLMUL VLMul = RISCVII::LMUL_1; 45081ad6265SDimitry Andric uint8_t SEW = 0; 45181ad6265SDimitry Andric uint8_t TailAgnostic : 1; 45281ad6265SDimitry Andric uint8_t MaskAgnostic : 1; 45381ad6265SDimitry Andric uint8_t SEWLMULRatioOnly : 1; 45481ad6265SDimitry Andric 45581ad6265SDimitry Andric public: 45681ad6265SDimitry Andric VSETVLIInfo() 45781ad6265SDimitry Andric : AVLImm(0), TailAgnostic(false), MaskAgnostic(false), 45881ad6265SDimitry Andric SEWLMULRatioOnly(false) {} 45981ad6265SDimitry Andric 46081ad6265SDimitry Andric static VSETVLIInfo getUnknown() { 46181ad6265SDimitry Andric VSETVLIInfo Info; 46281ad6265SDimitry Andric Info.setUnknown(); 46381ad6265SDimitry Andric return Info; 46481ad6265SDimitry Andric } 46581ad6265SDimitry Andric 46681ad6265SDimitry Andric bool isValid() const { return State != Uninitialized; } 46781ad6265SDimitry Andric void setUnknown() { State = Unknown; } 46881ad6265SDimitry Andric bool isUnknown() const { return State == Unknown; } 46981ad6265SDimitry Andric 47081ad6265SDimitry Andric void setAVLReg(Register Reg) { 47181ad6265SDimitry Andric AVLReg = Reg; 47281ad6265SDimitry Andric State = AVLIsReg; 47381ad6265SDimitry Andric } 47481ad6265SDimitry Andric 47581ad6265SDimitry Andric void setAVLImm(unsigned Imm) { 47681ad6265SDimitry Andric AVLImm = Imm; 47781ad6265SDimitry Andric State = AVLIsImm; 47881ad6265SDimitry Andric } 47981ad6265SDimitry Andric 48081ad6265SDimitry Andric bool hasAVLImm() const { return State == AVLIsImm; } 48181ad6265SDimitry Andric bool hasAVLReg() const { return State == AVLIsReg; } 48281ad6265SDimitry Andric Register getAVLReg() const { 48381ad6265SDimitry Andric assert(hasAVLReg()); 48481ad6265SDimitry Andric return AVLReg; 48581ad6265SDimitry Andric } 48681ad6265SDimitry Andric unsigned getAVLImm() const { 48781ad6265SDimitry Andric assert(hasAVLImm()); 48881ad6265SDimitry Andric return AVLImm; 48981ad6265SDimitry Andric } 49081ad6265SDimitry Andric 4915f757f3fSDimitry Andric void setAVL(VSETVLIInfo Info) { 4925f757f3fSDimitry Andric assert(Info.isValid()); 4935f757f3fSDimitry Andric if (Info.isUnknown()) 4945f757f3fSDimitry Andric setUnknown(); 4955f757f3fSDimitry Andric else if (Info.hasAVLReg()) 4965f757f3fSDimitry Andric setAVLReg(Info.getAVLReg()); 4975f757f3fSDimitry Andric else { 4985f757f3fSDimitry Andric assert(Info.hasAVLImm()); 4995f757f3fSDimitry Andric setAVLImm(Info.getAVLImm()); 5005f757f3fSDimitry Andric } 5015f757f3fSDimitry Andric } 5025f757f3fSDimitry Andric 50381ad6265SDimitry Andric unsigned getSEW() const { return SEW; } 50481ad6265SDimitry Andric RISCVII::VLMUL getVLMUL() const { return VLMul; } 5055f757f3fSDimitry Andric bool getTailAgnostic() const { return TailAgnostic; } 5065f757f3fSDimitry Andric bool getMaskAgnostic() const { return MaskAgnostic; } 50781ad6265SDimitry Andric 50806c3fb27SDimitry Andric bool hasNonZeroAVL(const MachineRegisterInfo &MRI) const { 50981ad6265SDimitry Andric if (hasAVLImm()) 51081ad6265SDimitry Andric return getAVLImm() > 0; 51106c3fb27SDimitry Andric if (hasAVLReg()) { 51206c3fb27SDimitry Andric if (getAVLReg() == RISCV::X0) 51306c3fb27SDimitry Andric return true; 51406c3fb27SDimitry Andric if (MachineInstr *MI = MRI.getVRegDef(getAVLReg()); 5155f757f3fSDimitry Andric MI && isNonZeroLoadImmediate(*MI)) 51606c3fb27SDimitry Andric return true; 51706c3fb27SDimitry Andric return false; 51806c3fb27SDimitry Andric } 51981ad6265SDimitry Andric return false; 52081ad6265SDimitry Andric } 52181ad6265SDimitry Andric 52206c3fb27SDimitry Andric bool hasEquallyZeroAVL(const VSETVLIInfo &Other, 52306c3fb27SDimitry Andric const MachineRegisterInfo &MRI) const { 524bdd1243dSDimitry Andric if (hasSameAVL(Other)) 525bdd1243dSDimitry Andric return true; 52606c3fb27SDimitry Andric return (hasNonZeroAVL(MRI) && Other.hasNonZeroAVL(MRI)); 527bdd1243dSDimitry Andric } 528bdd1243dSDimitry Andric 52981ad6265SDimitry Andric bool hasSameAVL(const VSETVLIInfo &Other) const { 53081ad6265SDimitry Andric if (hasAVLReg() && Other.hasAVLReg()) 53181ad6265SDimitry Andric return getAVLReg() == Other.getAVLReg(); 53281ad6265SDimitry Andric 53381ad6265SDimitry Andric if (hasAVLImm() && Other.hasAVLImm()) 53481ad6265SDimitry Andric return getAVLImm() == Other.getAVLImm(); 53581ad6265SDimitry Andric 53681ad6265SDimitry Andric return false; 53781ad6265SDimitry Andric } 53881ad6265SDimitry Andric 53981ad6265SDimitry Andric void setVTYPE(unsigned VType) { 54081ad6265SDimitry Andric assert(isValid() && !isUnknown() && 54181ad6265SDimitry Andric "Can't set VTYPE for uninitialized or unknown"); 54281ad6265SDimitry Andric VLMul = RISCVVType::getVLMUL(VType); 54381ad6265SDimitry Andric SEW = RISCVVType::getSEW(VType); 54481ad6265SDimitry Andric TailAgnostic = RISCVVType::isTailAgnostic(VType); 54581ad6265SDimitry Andric MaskAgnostic = RISCVVType::isMaskAgnostic(VType); 54681ad6265SDimitry Andric } 54781ad6265SDimitry Andric void setVTYPE(RISCVII::VLMUL L, unsigned S, bool TA, bool MA) { 54881ad6265SDimitry Andric assert(isValid() && !isUnknown() && 54981ad6265SDimitry Andric "Can't set VTYPE for uninitialized or unknown"); 55081ad6265SDimitry Andric VLMul = L; 55181ad6265SDimitry Andric SEW = S; 55281ad6265SDimitry Andric TailAgnostic = TA; 55381ad6265SDimitry Andric MaskAgnostic = MA; 55481ad6265SDimitry Andric } 55581ad6265SDimitry Andric 5565f757f3fSDimitry Andric void setVLMul(RISCVII::VLMUL VLMul) { this->VLMul = VLMul; } 5575f757f3fSDimitry Andric 55881ad6265SDimitry Andric unsigned encodeVTYPE() const { 55981ad6265SDimitry Andric assert(isValid() && !isUnknown() && !SEWLMULRatioOnly && 56081ad6265SDimitry Andric "Can't encode VTYPE for uninitialized or unknown"); 56181ad6265SDimitry Andric return RISCVVType::encodeVTYPE(VLMul, SEW, TailAgnostic, MaskAgnostic); 56281ad6265SDimitry Andric } 56381ad6265SDimitry Andric 56481ad6265SDimitry Andric bool hasSEWLMULRatioOnly() const { return SEWLMULRatioOnly; } 56581ad6265SDimitry Andric 56681ad6265SDimitry Andric bool hasSameVTYPE(const VSETVLIInfo &Other) const { 56781ad6265SDimitry Andric assert(isValid() && Other.isValid() && 56881ad6265SDimitry Andric "Can't compare invalid VSETVLIInfos"); 56981ad6265SDimitry Andric assert(!isUnknown() && !Other.isUnknown() && 57081ad6265SDimitry Andric "Can't compare VTYPE in unknown state"); 57181ad6265SDimitry Andric assert(!SEWLMULRatioOnly && !Other.SEWLMULRatioOnly && 57281ad6265SDimitry Andric "Can't compare when only LMUL/SEW ratio is valid."); 57381ad6265SDimitry Andric return std::tie(VLMul, SEW, TailAgnostic, MaskAgnostic) == 57481ad6265SDimitry Andric std::tie(Other.VLMul, Other.SEW, Other.TailAgnostic, 57581ad6265SDimitry Andric Other.MaskAgnostic); 57681ad6265SDimitry Andric } 57781ad6265SDimitry Andric 57881ad6265SDimitry Andric unsigned getSEWLMULRatio() const { 57981ad6265SDimitry Andric assert(isValid() && !isUnknown() && 58081ad6265SDimitry Andric "Can't use VTYPE for uninitialized or unknown"); 581bdd1243dSDimitry Andric return RISCVVType::getSEWLMULRatio(SEW, VLMul); 58281ad6265SDimitry Andric } 58381ad6265SDimitry Andric 58481ad6265SDimitry Andric // Check if the VTYPE for these two VSETVLIInfos produce the same VLMAX. 58581ad6265SDimitry Andric // Note that having the same VLMAX ensures that both share the same 58681ad6265SDimitry Andric // function from AVL to VL; that is, they must produce the same VL value 58781ad6265SDimitry Andric // for any given AVL value. 58881ad6265SDimitry Andric bool hasSameVLMAX(const VSETVLIInfo &Other) const { 58981ad6265SDimitry Andric assert(isValid() && Other.isValid() && 59081ad6265SDimitry Andric "Can't compare invalid VSETVLIInfos"); 59181ad6265SDimitry Andric assert(!isUnknown() && !Other.isUnknown() && 59281ad6265SDimitry Andric "Can't compare VTYPE in unknown state"); 59381ad6265SDimitry Andric return getSEWLMULRatio() == Other.getSEWLMULRatio(); 59481ad6265SDimitry Andric } 59581ad6265SDimitry Andric 596bdd1243dSDimitry Andric bool hasCompatibleVTYPE(const DemandedFields &Used, 59781ad6265SDimitry Andric const VSETVLIInfo &Require) const { 59806c3fb27SDimitry Andric return areCompatibleVTYPEs(Require.encodeVTYPE(), encodeVTYPE(), Used); 59981ad6265SDimitry Andric } 60081ad6265SDimitry Andric 60181ad6265SDimitry Andric // Determine whether the vector instructions requirements represented by 60281ad6265SDimitry Andric // Require are compatible with the previous vsetvli instruction represented 60381ad6265SDimitry Andric // by this. MI is the instruction whose requirements we're considering. 60406c3fb27SDimitry Andric bool isCompatible(const DemandedFields &Used, const VSETVLIInfo &Require, 60506c3fb27SDimitry Andric const MachineRegisterInfo &MRI) const { 60681ad6265SDimitry Andric assert(isValid() && Require.isValid() && 60781ad6265SDimitry Andric "Can't compare invalid VSETVLIInfos"); 60881ad6265SDimitry Andric assert(!Require.SEWLMULRatioOnly && 60981ad6265SDimitry Andric "Expected a valid VTYPE for instruction!"); 61081ad6265SDimitry Andric // Nothing is compatible with Unknown. 61181ad6265SDimitry Andric if (isUnknown() || Require.isUnknown()) 61281ad6265SDimitry Andric return false; 61381ad6265SDimitry Andric 61481ad6265SDimitry Andric // If only our VLMAX ratio is valid, then this isn't compatible. 61581ad6265SDimitry Andric if (SEWLMULRatioOnly) 61681ad6265SDimitry Andric return false; 61781ad6265SDimitry Andric 618bdd1243dSDimitry Andric if (Used.VLAny && !hasSameAVL(Require)) 619bdd1243dSDimitry Andric return false; 620bdd1243dSDimitry Andric 62106c3fb27SDimitry Andric if (Used.VLZeroness && !hasEquallyZeroAVL(Require, MRI)) 622bdd1243dSDimitry Andric return false; 623bdd1243dSDimitry Andric 62406c3fb27SDimitry Andric return hasCompatibleVTYPE(Used, Require); 62581ad6265SDimitry Andric } 62681ad6265SDimitry Andric 62781ad6265SDimitry Andric bool operator==(const VSETVLIInfo &Other) const { 62881ad6265SDimitry Andric // Uninitialized is only equal to another Uninitialized. 62981ad6265SDimitry Andric if (!isValid()) 63081ad6265SDimitry Andric return !Other.isValid(); 63181ad6265SDimitry Andric if (!Other.isValid()) 63281ad6265SDimitry Andric return !isValid(); 63381ad6265SDimitry Andric 63481ad6265SDimitry Andric // Unknown is only equal to another Unknown. 63581ad6265SDimitry Andric if (isUnknown()) 63681ad6265SDimitry Andric return Other.isUnknown(); 63781ad6265SDimitry Andric if (Other.isUnknown()) 63881ad6265SDimitry Andric return isUnknown(); 63981ad6265SDimitry Andric 64081ad6265SDimitry Andric if (!hasSameAVL(Other)) 64181ad6265SDimitry Andric return false; 64281ad6265SDimitry Andric 64381ad6265SDimitry Andric // If the SEWLMULRatioOnly bits are different, then they aren't equal. 64481ad6265SDimitry Andric if (SEWLMULRatioOnly != Other.SEWLMULRatioOnly) 64581ad6265SDimitry Andric return false; 64681ad6265SDimitry Andric 64781ad6265SDimitry Andric // If only the VLMAX is valid, check that it is the same. 64881ad6265SDimitry Andric if (SEWLMULRatioOnly) 64981ad6265SDimitry Andric return hasSameVLMAX(Other); 65081ad6265SDimitry Andric 65181ad6265SDimitry Andric // If the full VTYPE is valid, check that it is the same. 65281ad6265SDimitry Andric return hasSameVTYPE(Other); 65381ad6265SDimitry Andric } 65481ad6265SDimitry Andric 65581ad6265SDimitry Andric bool operator!=(const VSETVLIInfo &Other) const { 65681ad6265SDimitry Andric return !(*this == Other); 65781ad6265SDimitry Andric } 65881ad6265SDimitry Andric 65981ad6265SDimitry Andric // Calculate the VSETVLIInfo visible to a block assuming this and Other are 66081ad6265SDimitry Andric // both predecessors. 66181ad6265SDimitry Andric VSETVLIInfo intersect(const VSETVLIInfo &Other) const { 66281ad6265SDimitry Andric // If the new value isn't valid, ignore it. 66381ad6265SDimitry Andric if (!Other.isValid()) 66481ad6265SDimitry Andric return *this; 66581ad6265SDimitry Andric 66681ad6265SDimitry Andric // If this value isn't valid, this must be the first predecessor, use it. 66781ad6265SDimitry Andric if (!isValid()) 66881ad6265SDimitry Andric return Other; 66981ad6265SDimitry Andric 67081ad6265SDimitry Andric // If either is unknown, the result is unknown. 67181ad6265SDimitry Andric if (isUnknown() || Other.isUnknown()) 67281ad6265SDimitry Andric return VSETVLIInfo::getUnknown(); 67381ad6265SDimitry Andric 67481ad6265SDimitry Andric // If we have an exact, match return this. 67581ad6265SDimitry Andric if (*this == Other) 67681ad6265SDimitry Andric return *this; 67781ad6265SDimitry Andric 67881ad6265SDimitry Andric // Not an exact match, but maybe the AVL and VLMAX are the same. If so, 67981ad6265SDimitry Andric // return an SEW/LMUL ratio only value. 68081ad6265SDimitry Andric if (hasSameAVL(Other) && hasSameVLMAX(Other)) { 68181ad6265SDimitry Andric VSETVLIInfo MergeInfo = *this; 68281ad6265SDimitry Andric MergeInfo.SEWLMULRatioOnly = true; 68381ad6265SDimitry Andric return MergeInfo; 68481ad6265SDimitry Andric } 68581ad6265SDimitry Andric 68681ad6265SDimitry Andric // Otherwise the result is unknown. 68781ad6265SDimitry Andric return VSETVLIInfo::getUnknown(); 68881ad6265SDimitry Andric } 68981ad6265SDimitry Andric 69081ad6265SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 69181ad6265SDimitry Andric /// Support for debugging, callable in GDB: V->dump() 69281ad6265SDimitry Andric LLVM_DUMP_METHOD void dump() const { 69381ad6265SDimitry Andric print(dbgs()); 69481ad6265SDimitry Andric dbgs() << "\n"; 69581ad6265SDimitry Andric } 69681ad6265SDimitry Andric 69781ad6265SDimitry Andric /// Implement operator<<. 69881ad6265SDimitry Andric /// @{ 69981ad6265SDimitry Andric void print(raw_ostream &OS) const { 70081ad6265SDimitry Andric OS << "{"; 70181ad6265SDimitry Andric if (!isValid()) 70281ad6265SDimitry Andric OS << "Uninitialized"; 70381ad6265SDimitry Andric if (isUnknown()) 70481ad6265SDimitry Andric OS << "unknown"; 70581ad6265SDimitry Andric if (hasAVLReg()) 70681ad6265SDimitry Andric OS << "AVLReg=" << (unsigned)AVLReg; 70781ad6265SDimitry Andric if (hasAVLImm()) 70881ad6265SDimitry Andric OS << "AVLImm=" << (unsigned)AVLImm; 70981ad6265SDimitry Andric OS << ", " 71081ad6265SDimitry Andric << "VLMul=" << (unsigned)VLMul << ", " 71181ad6265SDimitry Andric << "SEW=" << (unsigned)SEW << ", " 71281ad6265SDimitry Andric << "TailAgnostic=" << (bool)TailAgnostic << ", " 71381ad6265SDimitry Andric << "MaskAgnostic=" << (bool)MaskAgnostic << ", " 71481ad6265SDimitry Andric << "SEWLMULRatioOnly=" << (bool)SEWLMULRatioOnly << "}"; 71581ad6265SDimitry Andric } 71681ad6265SDimitry Andric #endif 71781ad6265SDimitry Andric }; 71881ad6265SDimitry Andric 71981ad6265SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 72081ad6265SDimitry Andric LLVM_ATTRIBUTE_USED 72181ad6265SDimitry Andric inline raw_ostream &operator<<(raw_ostream &OS, const VSETVLIInfo &V) { 72281ad6265SDimitry Andric V.print(OS); 72381ad6265SDimitry Andric return OS; 72481ad6265SDimitry Andric } 72581ad6265SDimitry Andric #endif 72681ad6265SDimitry Andric 72781ad6265SDimitry Andric struct BlockData { 72881ad6265SDimitry Andric // The VSETVLIInfo that represents the VL/VTYPE settings on exit from this 72981ad6265SDimitry Andric // block. Calculated in Phase 2. 73081ad6265SDimitry Andric VSETVLIInfo Exit; 73181ad6265SDimitry Andric 73281ad6265SDimitry Andric // The VSETVLIInfo that represents the VL/VTYPE settings from all predecessor 73381ad6265SDimitry Andric // blocks. Calculated in Phase 2, and used by Phase 3. 73481ad6265SDimitry Andric VSETVLIInfo Pred; 73581ad6265SDimitry Andric 73681ad6265SDimitry Andric // Keeps track of whether the block is already in the queue. 73781ad6265SDimitry Andric bool InQueue = false; 73881ad6265SDimitry Andric 73981ad6265SDimitry Andric BlockData() = default; 74081ad6265SDimitry Andric }; 74181ad6265SDimitry Andric 74281ad6265SDimitry Andric class RISCVInsertVSETVLI : public MachineFunctionPass { 7435f757f3fSDimitry Andric const RISCVSubtarget *ST; 74481ad6265SDimitry Andric const TargetInstrInfo *TII; 74581ad6265SDimitry Andric MachineRegisterInfo *MRI; 74681ad6265SDimitry Andric 74781ad6265SDimitry Andric std::vector<BlockData> BlockInfo; 74881ad6265SDimitry Andric std::queue<const MachineBasicBlock *> WorkList; 74981ad6265SDimitry Andric 75081ad6265SDimitry Andric public: 75181ad6265SDimitry Andric static char ID; 75281ad6265SDimitry Andric 7535f757f3fSDimitry Andric RISCVInsertVSETVLI() : MachineFunctionPass(ID) {} 75481ad6265SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 75581ad6265SDimitry Andric 75681ad6265SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 75781ad6265SDimitry Andric AU.setPreservesCFG(); 75881ad6265SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 75981ad6265SDimitry Andric } 76081ad6265SDimitry Andric 76181ad6265SDimitry Andric StringRef getPassName() const override { return RISCV_INSERT_VSETVLI_NAME; } 76281ad6265SDimitry Andric 76381ad6265SDimitry Andric private: 76481ad6265SDimitry Andric bool needVSETVLI(const MachineInstr &MI, const VSETVLIInfo &Require, 76581ad6265SDimitry Andric const VSETVLIInfo &CurInfo) const; 76681ad6265SDimitry Andric bool needVSETVLIPHI(const VSETVLIInfo &Require, 76781ad6265SDimitry Andric const MachineBasicBlock &MBB) const; 76881ad6265SDimitry Andric void insertVSETVLI(MachineBasicBlock &MBB, MachineInstr &MI, 76981ad6265SDimitry Andric const VSETVLIInfo &Info, const VSETVLIInfo &PrevInfo); 77081ad6265SDimitry Andric void insertVSETVLI(MachineBasicBlock &MBB, 77181ad6265SDimitry Andric MachineBasicBlock::iterator InsertPt, DebugLoc DL, 77281ad6265SDimitry Andric const VSETVLIInfo &Info, const VSETVLIInfo &PrevInfo); 77381ad6265SDimitry Andric 7745f757f3fSDimitry Andric void transferBefore(VSETVLIInfo &Info, const MachineInstr &MI) const; 7755f757f3fSDimitry Andric void transferAfter(VSETVLIInfo &Info, const MachineInstr &MI) const; 7765f757f3fSDimitry Andric bool computeVLVTYPEChanges(const MachineBasicBlock &MBB, 7775f757f3fSDimitry Andric VSETVLIInfo &Info) const; 77881ad6265SDimitry Andric void computeIncomingVLVTYPE(const MachineBasicBlock &MBB); 77981ad6265SDimitry Andric void emitVSETVLIs(MachineBasicBlock &MBB); 78081ad6265SDimitry Andric void doLocalPostpass(MachineBasicBlock &MBB); 78181ad6265SDimitry Andric void doPRE(MachineBasicBlock &MBB); 78281ad6265SDimitry Andric void insertReadVL(MachineBasicBlock &MBB); 78381ad6265SDimitry Andric }; 78481ad6265SDimitry Andric 78581ad6265SDimitry Andric } // end anonymous namespace 78681ad6265SDimitry Andric 78781ad6265SDimitry Andric char RISCVInsertVSETVLI::ID = 0; 78881ad6265SDimitry Andric 78981ad6265SDimitry Andric INITIALIZE_PASS(RISCVInsertVSETVLI, DEBUG_TYPE, RISCV_INSERT_VSETVLI_NAME, 79081ad6265SDimitry Andric false, false) 79181ad6265SDimitry Andric 7925f757f3fSDimitry Andric // Return a VSETVLIInfo representing the changes made by this VSETVLI or 7935f757f3fSDimitry Andric // VSETIVLI instruction. 7945f757f3fSDimitry Andric static VSETVLIInfo getInfoForVSETVLI(const MachineInstr &MI) { 7955f757f3fSDimitry Andric VSETVLIInfo NewInfo; 7965f757f3fSDimitry Andric if (MI.getOpcode() == RISCV::PseudoVSETIVLI) { 7975f757f3fSDimitry Andric NewInfo.setAVLImm(MI.getOperand(1).getImm()); 7985f757f3fSDimitry Andric } else { 7995f757f3fSDimitry Andric assert(MI.getOpcode() == RISCV::PseudoVSETVLI || 8005f757f3fSDimitry Andric MI.getOpcode() == RISCV::PseudoVSETVLIX0); 8015f757f3fSDimitry Andric Register AVLReg = MI.getOperand(1).getReg(); 8025f757f3fSDimitry Andric assert((AVLReg != RISCV::X0 || MI.getOperand(0).getReg() != RISCV::X0) && 8035f757f3fSDimitry Andric "Can't handle X0, X0 vsetvli yet"); 8045f757f3fSDimitry Andric NewInfo.setAVLReg(AVLReg); 8055f757f3fSDimitry Andric } 8065f757f3fSDimitry Andric NewInfo.setVTYPE(MI.getOperand(2).getImm()); 8075f757f3fSDimitry Andric 8085f757f3fSDimitry Andric return NewInfo; 8095f757f3fSDimitry Andric } 8105f757f3fSDimitry Andric 811*7a6dacacSDimitry Andric static unsigned computeVLMAX(unsigned VLEN, unsigned SEW, 812*7a6dacacSDimitry Andric RISCVII::VLMUL VLMul) { 813*7a6dacacSDimitry Andric auto [LMul, Fractional] = RISCVVType::decodeVLMUL(VLMul); 814*7a6dacacSDimitry Andric if (Fractional) 815*7a6dacacSDimitry Andric VLEN = VLEN / LMul; 816*7a6dacacSDimitry Andric else 817*7a6dacacSDimitry Andric VLEN = VLEN * LMul; 818*7a6dacacSDimitry Andric return VLEN/SEW; 819*7a6dacacSDimitry Andric } 820*7a6dacacSDimitry Andric 82181ad6265SDimitry Andric static VSETVLIInfo computeInfoForInstr(const MachineInstr &MI, uint64_t TSFlags, 822*7a6dacacSDimitry Andric const RISCVSubtarget &ST, 82381ad6265SDimitry Andric const MachineRegisterInfo *MRI) { 82481ad6265SDimitry Andric VSETVLIInfo InstrInfo; 82581ad6265SDimitry Andric 82606c3fb27SDimitry Andric bool TailAgnostic = true; 82706c3fb27SDimitry Andric bool MaskAgnostic = true; 82806c3fb27SDimitry Andric if (!hasUndefinedMergeOp(MI, *MRI)) { 829bdd1243dSDimitry Andric // Start with undisturbed. 830bdd1243dSDimitry Andric TailAgnostic = false; 831bdd1243dSDimitry Andric MaskAgnostic = false; 832bdd1243dSDimitry Andric 833bdd1243dSDimitry Andric // If there is a policy operand, use it. 83481ad6265SDimitry Andric if (RISCVII::hasVecPolicyOp(TSFlags)) { 83581ad6265SDimitry Andric const MachineOperand &Op = MI.getOperand(MI.getNumExplicitOperands() - 1); 83681ad6265SDimitry Andric uint64_t Policy = Op.getImm(); 83781ad6265SDimitry Andric assert(Policy <= (RISCVII::TAIL_AGNOSTIC | RISCVII::MASK_AGNOSTIC) && 83881ad6265SDimitry Andric "Invalid Policy Value"); 83981ad6265SDimitry Andric TailAgnostic = Policy & RISCVII::TAIL_AGNOSTIC; 84081ad6265SDimitry Andric MaskAgnostic = Policy & RISCVII::MASK_AGNOSTIC; 841bdd1243dSDimitry Andric } 842bdd1243dSDimitry Andric 84381ad6265SDimitry Andric // Some pseudo instructions force a tail agnostic policy despite having a 84481ad6265SDimitry Andric // tied def. 84581ad6265SDimitry Andric if (RISCVII::doesForceTailAgnostic(TSFlags)) 84681ad6265SDimitry Andric TailAgnostic = true; 847bdd1243dSDimitry Andric 848bdd1243dSDimitry Andric if (!RISCVII::usesMaskPolicy(TSFlags)) 849bdd1243dSDimitry Andric MaskAgnostic = true; 85081ad6265SDimitry Andric } 85181ad6265SDimitry Andric 85281ad6265SDimitry Andric RISCVII::VLMUL VLMul = RISCVII::getLMul(TSFlags); 85381ad6265SDimitry Andric 85481ad6265SDimitry Andric unsigned Log2SEW = MI.getOperand(getSEWOpNum(MI)).getImm(); 85581ad6265SDimitry Andric // A Log2SEW of 0 is an operation on mask registers only. 85681ad6265SDimitry Andric unsigned SEW = Log2SEW ? 1 << Log2SEW : 8; 85781ad6265SDimitry Andric assert(RISCVVType::isValidSEW(SEW) && "Unexpected SEW"); 85881ad6265SDimitry Andric 85981ad6265SDimitry Andric if (RISCVII::hasVLOp(TSFlags)) { 86081ad6265SDimitry Andric const MachineOperand &VLOp = MI.getOperand(getVLOpNum(MI)); 86181ad6265SDimitry Andric if (VLOp.isImm()) { 86281ad6265SDimitry Andric int64_t Imm = VLOp.getImm(); 86381ad6265SDimitry Andric // Conver the VLMax sentintel to X0 register. 864*7a6dacacSDimitry Andric if (Imm == RISCV::VLMaxSentinel) { 865*7a6dacacSDimitry Andric // If we know the exact VLEN, see if we can use the constant encoding 866*7a6dacacSDimitry Andric // for the VLMAX instead. This reduces register pressure slightly. 867*7a6dacacSDimitry Andric const unsigned VLMAX = computeVLMAX(ST.getRealMaxVLen(), SEW, VLMul); 868*7a6dacacSDimitry Andric if (ST.getRealMinVLen() == ST.getRealMaxVLen() && VLMAX <= 31) 869*7a6dacacSDimitry Andric InstrInfo.setAVLImm(VLMAX); 870*7a6dacacSDimitry Andric else 87181ad6265SDimitry Andric InstrInfo.setAVLReg(RISCV::X0); 872*7a6dacacSDimitry Andric } 87381ad6265SDimitry Andric else 87481ad6265SDimitry Andric InstrInfo.setAVLImm(Imm); 87581ad6265SDimitry Andric } else { 87681ad6265SDimitry Andric InstrInfo.setAVLReg(VLOp.getReg()); 87781ad6265SDimitry Andric } 87881ad6265SDimitry Andric } else { 8795f757f3fSDimitry Andric assert(isScalarExtractInstr(MI)); 88081ad6265SDimitry Andric InstrInfo.setAVLReg(RISCV::NoRegister); 88181ad6265SDimitry Andric } 88281ad6265SDimitry Andric #ifndef NDEBUG 883bdd1243dSDimitry Andric if (std::optional<unsigned> EEW = getEEWForLoadStore(MI)) { 88481ad6265SDimitry Andric assert(SEW == EEW && "Initial SEW doesn't match expected EEW"); 88581ad6265SDimitry Andric } 88681ad6265SDimitry Andric #endif 88781ad6265SDimitry Andric InstrInfo.setVTYPE(VLMul, SEW, TailAgnostic, MaskAgnostic); 88881ad6265SDimitry Andric 8895f757f3fSDimitry Andric // If AVL is defined by a vsetvli with the same VLMAX, we can replace the 8905f757f3fSDimitry Andric // AVL operand with the AVL of the defining vsetvli. We avoid general 8915f757f3fSDimitry Andric // register AVLs to avoid extending live ranges without being sure we can 8925f757f3fSDimitry Andric // kill the original source reg entirely. 8935f757f3fSDimitry Andric if (InstrInfo.hasAVLReg() && InstrInfo.getAVLReg().isVirtual()) { 8945f757f3fSDimitry Andric MachineInstr *DefMI = MRI->getVRegDef(InstrInfo.getAVLReg()); 8955f757f3fSDimitry Andric if (DefMI && isVectorConfigInstr(*DefMI)) { 8965f757f3fSDimitry Andric VSETVLIInfo DefInstrInfo = getInfoForVSETVLI(*DefMI); 8975f757f3fSDimitry Andric if (DefInstrInfo.hasSameVLMAX(InstrInfo) && 8985f757f3fSDimitry Andric (DefInstrInfo.hasAVLImm() || DefInstrInfo.getAVLReg() == RISCV::X0)) { 8995f757f3fSDimitry Andric InstrInfo.setAVL(DefInstrInfo); 9005f757f3fSDimitry Andric } 9015f757f3fSDimitry Andric } 9025f757f3fSDimitry Andric } 9035f757f3fSDimitry Andric 90481ad6265SDimitry Andric return InstrInfo; 90581ad6265SDimitry Andric } 90681ad6265SDimitry Andric 90781ad6265SDimitry Andric void RISCVInsertVSETVLI::insertVSETVLI(MachineBasicBlock &MBB, MachineInstr &MI, 90881ad6265SDimitry Andric const VSETVLIInfo &Info, 90981ad6265SDimitry Andric const VSETVLIInfo &PrevInfo) { 91081ad6265SDimitry Andric DebugLoc DL = MI.getDebugLoc(); 91181ad6265SDimitry Andric insertVSETVLI(MBB, MachineBasicBlock::iterator(&MI), DL, Info, PrevInfo); 91281ad6265SDimitry Andric } 91381ad6265SDimitry Andric 91481ad6265SDimitry Andric void RISCVInsertVSETVLI::insertVSETVLI(MachineBasicBlock &MBB, 91581ad6265SDimitry Andric MachineBasicBlock::iterator InsertPt, DebugLoc DL, 91681ad6265SDimitry Andric const VSETVLIInfo &Info, const VSETVLIInfo &PrevInfo) { 91781ad6265SDimitry Andric 918*7a6dacacSDimitry Andric ++NumInsertedVSETVL; 91906c3fb27SDimitry Andric if (PrevInfo.isValid() && !PrevInfo.isUnknown()) { 92081ad6265SDimitry Andric // Use X0, X0 form if the AVL is the same and the SEW+LMUL gives the same 92181ad6265SDimitry Andric // VLMAX. 92206c3fb27SDimitry Andric if (Info.hasSameAVL(PrevInfo) && Info.hasSameVLMAX(PrevInfo)) { 92381ad6265SDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETVLIX0)) 92481ad6265SDimitry Andric .addReg(RISCV::X0, RegState::Define | RegState::Dead) 92581ad6265SDimitry Andric .addReg(RISCV::X0, RegState::Kill) 92681ad6265SDimitry Andric .addImm(Info.encodeVTYPE()) 92781ad6265SDimitry Andric .addReg(RISCV::VL, RegState::Implicit); 92881ad6265SDimitry Andric return; 92981ad6265SDimitry Andric } 93081ad6265SDimitry Andric 93106c3fb27SDimitry Andric // If our AVL is a virtual register, it might be defined by a VSET(I)VLI. If 93206c3fb27SDimitry Andric // it has the same VLMAX we want and the last VL/VTYPE we observed is the 93306c3fb27SDimitry Andric // same, we can use the X0, X0 form. 93406c3fb27SDimitry Andric if (Info.hasSameVLMAX(PrevInfo) && Info.hasAVLReg() && 93506c3fb27SDimitry Andric Info.getAVLReg().isVirtual()) { 93606c3fb27SDimitry Andric if (MachineInstr *DefMI = MRI->getVRegDef(Info.getAVLReg())) { 93706c3fb27SDimitry Andric if (isVectorConfigInstr(*DefMI)) { 93806c3fb27SDimitry Andric VSETVLIInfo DefInfo = getInfoForVSETVLI(*DefMI); 93906c3fb27SDimitry Andric if (DefInfo.hasSameAVL(PrevInfo) && DefInfo.hasSameVLMAX(PrevInfo)) { 94006c3fb27SDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETVLIX0)) 94106c3fb27SDimitry Andric .addReg(RISCV::X0, RegState::Define | RegState::Dead) 94206c3fb27SDimitry Andric .addReg(RISCV::X0, RegState::Kill) 94306c3fb27SDimitry Andric .addImm(Info.encodeVTYPE()) 94406c3fb27SDimitry Andric .addReg(RISCV::VL, RegState::Implicit); 94506c3fb27SDimitry Andric return; 94606c3fb27SDimitry Andric } 94706c3fb27SDimitry Andric } 94806c3fb27SDimitry Andric } 94906c3fb27SDimitry Andric } 95006c3fb27SDimitry Andric } 95106c3fb27SDimitry Andric 95281ad6265SDimitry Andric if (Info.hasAVLImm()) { 95381ad6265SDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETIVLI)) 95481ad6265SDimitry Andric .addReg(RISCV::X0, RegState::Define | RegState::Dead) 95581ad6265SDimitry Andric .addImm(Info.getAVLImm()) 95681ad6265SDimitry Andric .addImm(Info.encodeVTYPE()); 95781ad6265SDimitry Andric return; 95881ad6265SDimitry Andric } 95981ad6265SDimitry Andric 96081ad6265SDimitry Andric Register AVLReg = Info.getAVLReg(); 96181ad6265SDimitry Andric if (AVLReg == RISCV::NoRegister) { 96281ad6265SDimitry Andric // We can only use x0, x0 if there's no chance of the vtype change causing 96381ad6265SDimitry Andric // the previous vl to become invalid. 96481ad6265SDimitry Andric if (PrevInfo.isValid() && !PrevInfo.isUnknown() && 96581ad6265SDimitry Andric Info.hasSameVLMAX(PrevInfo)) { 96681ad6265SDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETVLIX0)) 96781ad6265SDimitry Andric .addReg(RISCV::X0, RegState::Define | RegState::Dead) 96881ad6265SDimitry Andric .addReg(RISCV::X0, RegState::Kill) 96981ad6265SDimitry Andric .addImm(Info.encodeVTYPE()) 97081ad6265SDimitry Andric .addReg(RISCV::VL, RegState::Implicit); 97181ad6265SDimitry Andric return; 97281ad6265SDimitry Andric } 9735f757f3fSDimitry Andric // Otherwise use an AVL of 1 to avoid depending on previous vl. 97481ad6265SDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETIVLI)) 97581ad6265SDimitry Andric .addReg(RISCV::X0, RegState::Define | RegState::Dead) 9765f757f3fSDimitry Andric .addImm(1) 97781ad6265SDimitry Andric .addImm(Info.encodeVTYPE()); 97881ad6265SDimitry Andric return; 97981ad6265SDimitry Andric } 98081ad6265SDimitry Andric 98181ad6265SDimitry Andric if (AVLReg.isVirtual()) 98281ad6265SDimitry Andric MRI->constrainRegClass(AVLReg, &RISCV::GPRNoX0RegClass); 98381ad6265SDimitry Andric 98481ad6265SDimitry Andric // Use X0 as the DestReg unless AVLReg is X0. We also need to change the 98581ad6265SDimitry Andric // opcode if the AVLReg is X0 as they have different register classes for 98681ad6265SDimitry Andric // the AVL operand. 98781ad6265SDimitry Andric Register DestReg = RISCV::X0; 98881ad6265SDimitry Andric unsigned Opcode = RISCV::PseudoVSETVLI; 98981ad6265SDimitry Andric if (AVLReg == RISCV::X0) { 99081ad6265SDimitry Andric DestReg = MRI->createVirtualRegister(&RISCV::GPRRegClass); 99181ad6265SDimitry Andric Opcode = RISCV::PseudoVSETVLIX0; 99281ad6265SDimitry Andric } 99381ad6265SDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(Opcode)) 99481ad6265SDimitry Andric .addReg(DestReg, RegState::Define | RegState::Dead) 99581ad6265SDimitry Andric .addReg(AVLReg) 99681ad6265SDimitry Andric .addImm(Info.encodeVTYPE()); 99781ad6265SDimitry Andric } 99881ad6265SDimitry Andric 99906c3fb27SDimitry Andric static bool isLMUL1OrSmaller(RISCVII::VLMUL LMUL) { 100006c3fb27SDimitry Andric auto [LMul, Fractional] = RISCVVType::decodeVLMUL(LMUL); 100106c3fb27SDimitry Andric return Fractional || LMul == 1; 100281ad6265SDimitry Andric } 100381ad6265SDimitry Andric 100481ad6265SDimitry Andric /// Return true if a VSETVLI is required to transition from CurInfo to Require 100581ad6265SDimitry Andric /// before MI. 100681ad6265SDimitry Andric bool RISCVInsertVSETVLI::needVSETVLI(const MachineInstr &MI, 100781ad6265SDimitry Andric const VSETVLIInfo &Require, 100881ad6265SDimitry Andric const VSETVLIInfo &CurInfo) const { 1009*7a6dacacSDimitry Andric assert(Require == computeInfoForInstr(MI, MI.getDesc().TSFlags, *ST, MRI)); 101081ad6265SDimitry Andric 101181ad6265SDimitry Andric if (!CurInfo.isValid() || CurInfo.isUnknown() || CurInfo.hasSEWLMULRatioOnly()) 101281ad6265SDimitry Andric return true; 101381ad6265SDimitry Andric 10145f757f3fSDimitry Andric DemandedFields Used = getDemanded(MI, MRI, ST); 1015bdd1243dSDimitry Andric 101606c3fb27SDimitry Andric // A slidedown/slideup with an *undefined* merge op can freely clobber 101706c3fb27SDimitry Andric // elements not copied from the source vector (e.g. masked off, tail, or 101806c3fb27SDimitry Andric // slideup's prefix). Notes: 101906c3fb27SDimitry Andric // * We can't modify SEW here since the slide amount is in units of SEW. 102006c3fb27SDimitry Andric // * VL=1 is special only because we have existing support for zero vs 102106c3fb27SDimitry Andric // non-zero VL. We could generalize this if we had a VL > C predicate. 102206c3fb27SDimitry Andric // * The LMUL1 restriction is for machines whose latency may depend on VL. 102306c3fb27SDimitry Andric // * As above, this is only legal for tail "undefined" not "agnostic". 102406c3fb27SDimitry Andric if (isVSlideInstr(MI) && Require.hasAVLImm() && Require.getAVLImm() == 1 && 102506c3fb27SDimitry Andric isLMUL1OrSmaller(CurInfo.getVLMUL()) && hasUndefinedMergeOp(MI, *MRI)) { 102606c3fb27SDimitry Andric Used.VLAny = false; 102706c3fb27SDimitry Andric Used.VLZeroness = true; 102806c3fb27SDimitry Andric Used.LMUL = false; 1029bdd1243dSDimitry Andric Used.TailPolicy = false; 103081ad6265SDimitry Andric } 103106c3fb27SDimitry Andric 103206c3fb27SDimitry Andric // A tail undefined vmv.v.i/x or vfmv.v.f with VL=1 can be treated in the same 103306c3fb27SDimitry Andric // semantically as vmv.s.x. This is particularly useful since we don't have an 103406c3fb27SDimitry Andric // immediate form of vmv.s.x, and thus frequently use vmv.v.i in it's place. 103506c3fb27SDimitry Andric // Since a splat is non-constant time in LMUL, we do need to be careful to not 103606c3fb27SDimitry Andric // increase the number of active vector registers (unlike for vmv.s.x.) 103706c3fb27SDimitry Andric if (isScalarSplatInstr(MI) && Require.hasAVLImm() && Require.getAVLImm() == 1 && 103806c3fb27SDimitry Andric isLMUL1OrSmaller(CurInfo.getVLMUL()) && hasUndefinedMergeOp(MI, *MRI)) { 103906c3fb27SDimitry Andric Used.LMUL = false; 104006c3fb27SDimitry Andric Used.SEWLMULRatio = false; 104106c3fb27SDimitry Andric Used.VLAny = false; 10425f757f3fSDimitry Andric if (isFloatScalarMoveOrScalarSplatInstr(MI) && !ST->hasVInstructionsF64()) 10435f757f3fSDimitry Andric Used.SEW = DemandedFields::SEWGreaterThanOrEqualAndLessThan64; 10445f757f3fSDimitry Andric else 104506c3fb27SDimitry Andric Used.SEW = DemandedFields::SEWGreaterThanOrEqual; 104606c3fb27SDimitry Andric Used.TailPolicy = false; 1047bdd1243dSDimitry Andric } 1048bdd1243dSDimitry Andric 104906c3fb27SDimitry Andric if (CurInfo.isCompatible(Used, Require, *MRI)) 1050bdd1243dSDimitry Andric return false; 105181ad6265SDimitry Andric 105281ad6265SDimitry Andric // We didn't find a compatible value. If our AVL is a virtual register, 105381ad6265SDimitry Andric // it might be defined by a VSET(I)VLI. If it has the same VLMAX we need 105481ad6265SDimitry Andric // and the last VL/VTYPE we observed is the same, we don't need a 105581ad6265SDimitry Andric // VSETVLI here. 105681ad6265SDimitry Andric if (Require.hasAVLReg() && Require.getAVLReg().isVirtual() && 1057bdd1243dSDimitry Andric CurInfo.hasCompatibleVTYPE(Used, Require)) { 105881ad6265SDimitry Andric if (MachineInstr *DefMI = MRI->getVRegDef(Require.getAVLReg())) { 105981ad6265SDimitry Andric if (isVectorConfigInstr(*DefMI)) { 106081ad6265SDimitry Andric VSETVLIInfo DefInfo = getInfoForVSETVLI(*DefMI); 106181ad6265SDimitry Andric if (DefInfo.hasSameAVL(CurInfo) && DefInfo.hasSameVLMAX(CurInfo)) 106281ad6265SDimitry Andric return false; 106381ad6265SDimitry Andric } 106481ad6265SDimitry Andric } 106581ad6265SDimitry Andric } 106681ad6265SDimitry Andric 106781ad6265SDimitry Andric return true; 106881ad6265SDimitry Andric } 106981ad6265SDimitry Andric 10705f757f3fSDimitry Andric // If we don't use LMUL or the SEW/LMUL ratio, then adjust LMUL so that we 10715f757f3fSDimitry Andric // maintain the SEW/LMUL ratio. This allows us to eliminate VL toggles in more 10725f757f3fSDimitry Andric // places. 10735f757f3fSDimitry Andric static VSETVLIInfo adjustIncoming(VSETVLIInfo PrevInfo, VSETVLIInfo NewInfo, 10745f757f3fSDimitry Andric DemandedFields &Demanded) { 10755f757f3fSDimitry Andric VSETVLIInfo Info = NewInfo; 10765f757f3fSDimitry Andric 10775f757f3fSDimitry Andric if (!Demanded.LMUL && !Demanded.SEWLMULRatio && PrevInfo.isValid() && 10785f757f3fSDimitry Andric !PrevInfo.isUnknown()) { 10795f757f3fSDimitry Andric if (auto NewVLMul = RISCVVType::getSameRatioLMUL( 10805f757f3fSDimitry Andric PrevInfo.getSEW(), PrevInfo.getVLMUL(), Info.getSEW())) 10815f757f3fSDimitry Andric Info.setVLMul(*NewVLMul); 10825f757f3fSDimitry Andric Demanded.LMUL = true; 10835f757f3fSDimitry Andric } 10845f757f3fSDimitry Andric 10855f757f3fSDimitry Andric return Info; 10865f757f3fSDimitry Andric } 10875f757f3fSDimitry Andric 10885f757f3fSDimitry Andric // Given an incoming state reaching MI, minimally modifies that state so that it 10895f757f3fSDimitry Andric // is compatible with MI. The resulting state is guaranteed to be semantically 10905f757f3fSDimitry Andric // legal for MI, but may not be the state requested by MI. 10915f757f3fSDimitry Andric void RISCVInsertVSETVLI::transferBefore(VSETVLIInfo &Info, 10925f757f3fSDimitry Andric const MachineInstr &MI) const { 109381ad6265SDimitry Andric uint64_t TSFlags = MI.getDesc().TSFlags; 109481ad6265SDimitry Andric if (!RISCVII::hasSEWOp(TSFlags)) 109581ad6265SDimitry Andric return; 109681ad6265SDimitry Andric 1097*7a6dacacSDimitry Andric const VSETVLIInfo NewInfo = computeInfoForInstr(MI, TSFlags, *ST, MRI); 10985f757f3fSDimitry Andric assert(NewInfo.isValid() && !NewInfo.isUnknown()); 109981ad6265SDimitry Andric if (Info.isValid() && !needVSETVLI(MI, NewInfo, Info)) 110081ad6265SDimitry Andric return; 110181ad6265SDimitry Andric 110281ad6265SDimitry Andric const VSETVLIInfo PrevInfo = Info; 11035f757f3fSDimitry Andric if (!Info.isValid() || Info.isUnknown()) 110481ad6265SDimitry Andric Info = NewInfo; 110581ad6265SDimitry Andric 11065f757f3fSDimitry Andric DemandedFields Demanded = getDemanded(MI, MRI, ST); 11075f757f3fSDimitry Andric const VSETVLIInfo IncomingInfo = adjustIncoming(PrevInfo, NewInfo, Demanded); 110881ad6265SDimitry Andric 11095f757f3fSDimitry Andric // If MI only demands that VL has the same zeroness, we only need to set the 11105f757f3fSDimitry Andric // AVL if the zeroness differs. This removes a vsetvli entirely if the types 11115f757f3fSDimitry Andric // match or allows use of cheaper avl preserving variant if VLMAX doesn't 11125f757f3fSDimitry Andric // change. If VLMAX might change, we couldn't use the 'vsetvli x0, x0, vtype" 11135f757f3fSDimitry Andric // variant, so we avoid the transform to prevent extending live range of an 11145f757f3fSDimitry Andric // avl register operand. 111581ad6265SDimitry Andric // TODO: We can probably relax this for immediates. 11165f757f3fSDimitry Andric bool EquallyZero = IncomingInfo.hasEquallyZeroAVL(PrevInfo, *MRI) && 11175f757f3fSDimitry Andric IncomingInfo.hasSameVLMAX(PrevInfo); 11185f757f3fSDimitry Andric if (Demanded.VLAny || (Demanded.VLZeroness && !EquallyZero)) 11195f757f3fSDimitry Andric Info.setAVL(IncomingInfo); 112081ad6265SDimitry Andric 11215f757f3fSDimitry Andric Info.setVTYPE( 11225f757f3fSDimitry Andric ((Demanded.LMUL || Demanded.SEWLMULRatio) ? IncomingInfo : Info) 11235f757f3fSDimitry Andric .getVLMUL(), 11245f757f3fSDimitry Andric ((Demanded.SEW || Demanded.SEWLMULRatio) ? IncomingInfo : Info).getSEW(), 11255f757f3fSDimitry Andric // Prefer tail/mask agnostic since it can be relaxed to undisturbed later 11265f757f3fSDimitry Andric // if needed. 11275f757f3fSDimitry Andric (Demanded.TailPolicy ? IncomingInfo : Info).getTailAgnostic() || 11285f757f3fSDimitry Andric IncomingInfo.getTailAgnostic(), 11295f757f3fSDimitry Andric (Demanded.MaskPolicy ? IncomingInfo : Info).getMaskAgnostic() || 11305f757f3fSDimitry Andric IncomingInfo.getMaskAgnostic()); 113181ad6265SDimitry Andric 11325f757f3fSDimitry Andric // If we only knew the sew/lmul ratio previously, replace the VTYPE but keep 11335f757f3fSDimitry Andric // the AVL. 11345f757f3fSDimitry Andric if (Info.hasSEWLMULRatioOnly()) { 11355f757f3fSDimitry Andric VSETVLIInfo RatiolessInfo = IncomingInfo; 11365f757f3fSDimitry Andric RatiolessInfo.setAVL(Info); 11375f757f3fSDimitry Andric Info = RatiolessInfo; 113881ad6265SDimitry Andric } 113981ad6265SDimitry Andric } 114081ad6265SDimitry Andric 114181ad6265SDimitry Andric // Given a state with which we evaluated MI (see transferBefore above for why 114281ad6265SDimitry Andric // this might be different that the state MI requested), modify the state to 114381ad6265SDimitry Andric // reflect the changes MI might make. 11445f757f3fSDimitry Andric void RISCVInsertVSETVLI::transferAfter(VSETVLIInfo &Info, 11455f757f3fSDimitry Andric const MachineInstr &MI) const { 114681ad6265SDimitry Andric if (isVectorConfigInstr(MI)) { 114781ad6265SDimitry Andric Info = getInfoForVSETVLI(MI); 114881ad6265SDimitry Andric return; 114981ad6265SDimitry Andric } 115081ad6265SDimitry Andric 115181ad6265SDimitry Andric if (RISCV::isFaultFirstLoad(MI)) { 115281ad6265SDimitry Andric // Update AVL to vl-output of the fault first load. 115381ad6265SDimitry Andric Info.setAVLReg(MI.getOperand(1).getReg()); 115481ad6265SDimitry Andric return; 115581ad6265SDimitry Andric } 115681ad6265SDimitry Andric 115781ad6265SDimitry Andric // If this is something that updates VL/VTYPE that we don't know about, set 115881ad6265SDimitry Andric // the state to unknown. 115981ad6265SDimitry Andric if (MI.isCall() || MI.isInlineAsm() || MI.modifiesRegister(RISCV::VL) || 116081ad6265SDimitry Andric MI.modifiesRegister(RISCV::VTYPE)) 116181ad6265SDimitry Andric Info = VSETVLIInfo::getUnknown(); 1162349cc55cSDimitry Andric } 1163349cc55cSDimitry Andric 11645f757f3fSDimitry Andric bool RISCVInsertVSETVLI::computeVLVTYPEChanges(const MachineBasicBlock &MBB, 11655f757f3fSDimitry Andric VSETVLIInfo &Info) const { 1166fe6060f1SDimitry Andric bool HadVectorOp = false; 1167fe6060f1SDimitry Andric 11685f757f3fSDimitry Andric Info = BlockInfo[MBB.getNumber()].Pred; 1169fe6060f1SDimitry Andric for (const MachineInstr &MI : MBB) { 11705f757f3fSDimitry Andric transferBefore(Info, MI); 1171fe6060f1SDimitry Andric 117281ad6265SDimitry Andric if (isVectorConfigInstr(MI) || RISCVII::hasSEWOp(MI.getDesc().TSFlags)) 1173fe6060f1SDimitry Andric HadVectorOp = true; 1174fe6060f1SDimitry Andric 11755f757f3fSDimitry Andric transferAfter(Info, MI); 1176fe6060f1SDimitry Andric } 1177fe6060f1SDimitry Andric 1178fe6060f1SDimitry Andric return HadVectorOp; 1179fe6060f1SDimitry Andric } 1180fe6060f1SDimitry Andric 1181fe6060f1SDimitry Andric void RISCVInsertVSETVLI::computeIncomingVLVTYPE(const MachineBasicBlock &MBB) { 118281ad6265SDimitry Andric 1183fe6060f1SDimitry Andric BlockData &BBInfo = BlockInfo[MBB.getNumber()]; 1184fe6060f1SDimitry Andric 1185fe6060f1SDimitry Andric BBInfo.InQueue = false; 1186fe6060f1SDimitry Andric 1187bdd1243dSDimitry Andric // Start with the previous entry so that we keep the most conservative state 1188bdd1243dSDimitry Andric // we have ever found. 1189bdd1243dSDimitry Andric VSETVLIInfo InInfo = BBInfo.Pred; 1190fe6060f1SDimitry Andric if (MBB.pred_empty()) { 1191fe6060f1SDimitry Andric // There are no predecessors, so use the default starting status. 1192fe6060f1SDimitry Andric InInfo.setUnknown(); 1193fe6060f1SDimitry Andric } else { 1194fe6060f1SDimitry Andric for (MachineBasicBlock *P : MBB.predecessors()) 1195fe6060f1SDimitry Andric InInfo = InInfo.intersect(BlockInfo[P->getNumber()].Exit); 1196fe6060f1SDimitry Andric } 1197fe6060f1SDimitry Andric 1198fe6060f1SDimitry Andric // If we don't have any valid predecessor value, wait until we do. 1199fe6060f1SDimitry Andric if (!InInfo.isValid()) 1200fe6060f1SDimitry Andric return; 1201fe6060f1SDimitry Andric 120281ad6265SDimitry Andric // If no change, no need to rerun block 120381ad6265SDimitry Andric if (InInfo == BBInfo.Pred) 120481ad6265SDimitry Andric return; 1205fe6060f1SDimitry Andric 120681ad6265SDimitry Andric BBInfo.Pred = InInfo; 120781ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "Entry state of " << printMBBReference(MBB) 120881ad6265SDimitry Andric << " changed to " << BBInfo.Pred << "\n"); 120981ad6265SDimitry Andric 121081ad6265SDimitry Andric // Note: It's tempting to cache the state changes here, but due to the 121181ad6265SDimitry Andric // compatibility checks performed a blocks output state can change based on 121281ad6265SDimitry Andric // the input state. To cache, we'd have to add logic for finding 121381ad6265SDimitry Andric // never-compatible state changes. 12145f757f3fSDimitry Andric VSETVLIInfo TmpStatus; 12155f757f3fSDimitry Andric computeVLVTYPEChanges(MBB, TmpStatus); 1216fe6060f1SDimitry Andric 1217fe6060f1SDimitry Andric // If the new exit value matches the old exit value, we don't need to revisit 1218fe6060f1SDimitry Andric // any blocks. 1219fe6060f1SDimitry Andric if (BBInfo.Exit == TmpStatus) 1220fe6060f1SDimitry Andric return; 1221fe6060f1SDimitry Andric 1222fe6060f1SDimitry Andric BBInfo.Exit = TmpStatus; 122381ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "Exit state of " << printMBBReference(MBB) 122481ad6265SDimitry Andric << " changed to " << BBInfo.Exit << "\n"); 1225fe6060f1SDimitry Andric 1226fe6060f1SDimitry Andric // Add the successors to the work list so we can propagate the changed exit 1227fe6060f1SDimitry Andric // status. 1228fe6060f1SDimitry Andric for (MachineBasicBlock *S : MBB.successors()) 1229bdd1243dSDimitry Andric if (!BlockInfo[S->getNumber()].InQueue) { 1230bdd1243dSDimitry Andric BlockInfo[S->getNumber()].InQueue = true; 1231fe6060f1SDimitry Andric WorkList.push(S); 1232fe6060f1SDimitry Andric } 1233bdd1243dSDimitry Andric } 1234fe6060f1SDimitry Andric 1235fe6060f1SDimitry Andric // If we weren't able to prove a vsetvli was directly unneeded, it might still 123681ad6265SDimitry Andric // be unneeded if the AVL is a phi node where all incoming values are VL 1237fe6060f1SDimitry Andric // outputs from the last VSETVLI in their respective basic blocks. 1238fe6060f1SDimitry Andric bool RISCVInsertVSETVLI::needVSETVLIPHI(const VSETVLIInfo &Require, 123981ad6265SDimitry Andric const MachineBasicBlock &MBB) const { 1240fe6060f1SDimitry Andric if (DisableInsertVSETVLPHIOpt) 1241fe6060f1SDimitry Andric return true; 1242fe6060f1SDimitry Andric 1243fe6060f1SDimitry Andric if (!Require.hasAVLReg()) 1244fe6060f1SDimitry Andric return true; 1245fe6060f1SDimitry Andric 1246fe6060f1SDimitry Andric Register AVLReg = Require.getAVLReg(); 1247fe6060f1SDimitry Andric if (!AVLReg.isVirtual()) 1248fe6060f1SDimitry Andric return true; 1249fe6060f1SDimitry Andric 1250fe6060f1SDimitry Andric // We need the AVL to be produce by a PHI node in this basic block. 1251fe6060f1SDimitry Andric MachineInstr *PHI = MRI->getVRegDef(AVLReg); 1252fe6060f1SDimitry Andric if (!PHI || PHI->getOpcode() != RISCV::PHI || PHI->getParent() != &MBB) 1253fe6060f1SDimitry Andric return true; 1254fe6060f1SDimitry Andric 1255fe6060f1SDimitry Andric for (unsigned PHIOp = 1, NumOps = PHI->getNumOperands(); PHIOp != NumOps; 1256fe6060f1SDimitry Andric PHIOp += 2) { 1257fe6060f1SDimitry Andric Register InReg = PHI->getOperand(PHIOp).getReg(); 1258fe6060f1SDimitry Andric MachineBasicBlock *PBB = PHI->getOperand(PHIOp + 1).getMBB(); 1259fe6060f1SDimitry Andric const BlockData &PBBInfo = BlockInfo[PBB->getNumber()]; 1260fe6060f1SDimitry Andric // If the exit from the predecessor has the VTYPE we are looking for 1261fe6060f1SDimitry Andric // we might be able to avoid a VSETVLI. 126281ad6265SDimitry Andric if (PBBInfo.Exit.isUnknown() || !PBBInfo.Exit.hasSameVTYPE(Require)) 1263fe6060f1SDimitry Andric return true; 1264fe6060f1SDimitry Andric 1265fe6060f1SDimitry Andric // We need the PHI input to the be the output of a VSET(I)VLI. 1266fe6060f1SDimitry Andric MachineInstr *DefMI = MRI->getVRegDef(InReg); 126781ad6265SDimitry Andric if (!DefMI || !isVectorConfigInstr(*DefMI)) 1268fe6060f1SDimitry Andric return true; 1269fe6060f1SDimitry Andric 1270fe6060f1SDimitry Andric // We found a VSET(I)VLI make sure it matches the output of the 1271fe6060f1SDimitry Andric // predecessor block. 1272fe6060f1SDimitry Andric VSETVLIInfo DefInfo = getInfoForVSETVLI(*DefMI); 1273fe6060f1SDimitry Andric if (!DefInfo.hasSameAVL(PBBInfo.Exit) || 1274fe6060f1SDimitry Andric !DefInfo.hasSameVTYPE(PBBInfo.Exit)) 1275fe6060f1SDimitry Andric return true; 1276fe6060f1SDimitry Andric } 1277fe6060f1SDimitry Andric 1278fe6060f1SDimitry Andric // If all the incoming values to the PHI checked out, we don't need 1279fe6060f1SDimitry Andric // to insert a VSETVLI. 1280fe6060f1SDimitry Andric return false; 1281fe6060f1SDimitry Andric } 1282fe6060f1SDimitry Andric 1283fe6060f1SDimitry Andric void RISCVInsertVSETVLI::emitVSETVLIs(MachineBasicBlock &MBB) { 128481ad6265SDimitry Andric VSETVLIInfo CurInfo = BlockInfo[MBB.getNumber()].Pred; 128581ad6265SDimitry Andric // Track whether the prefix of the block we've scanned is transparent 128681ad6265SDimitry Andric // (meaning has not yet changed the abstract state). 128781ad6265SDimitry Andric bool PrefixTransparent = true; 1288fe6060f1SDimitry Andric for (MachineInstr &MI : MBB) { 128981ad6265SDimitry Andric const VSETVLIInfo PrevInfo = CurInfo; 129081ad6265SDimitry Andric transferBefore(CurInfo, MI); 129181ad6265SDimitry Andric 1292fe6060f1SDimitry Andric // If this is an explicit VSETVLI or VSETIVLI, update our state. 129381ad6265SDimitry Andric if (isVectorConfigInstr(MI)) { 1294fe6060f1SDimitry Andric // Conservatively, mark the VL and VTYPE as live. 1295fe6060f1SDimitry Andric assert(MI.getOperand(3).getReg() == RISCV::VL && 1296fe6060f1SDimitry Andric MI.getOperand(4).getReg() == RISCV::VTYPE && 1297fe6060f1SDimitry Andric "Unexpected operands where VL and VTYPE should be"); 1298fe6060f1SDimitry Andric MI.getOperand(3).setIsDead(false); 1299fe6060f1SDimitry Andric MI.getOperand(4).setIsDead(false); 130081ad6265SDimitry Andric PrefixTransparent = false; 1301fe6060f1SDimitry Andric } 1302fe6060f1SDimitry Andric 1303fe6060f1SDimitry Andric uint64_t TSFlags = MI.getDesc().TSFlags; 1304fe6060f1SDimitry Andric if (RISCVII::hasSEWOp(TSFlags)) { 130581ad6265SDimitry Andric if (PrevInfo != CurInfo) { 130681ad6265SDimitry Andric // If this is the first implicit state change, and the state change 130781ad6265SDimitry Andric // requested can be proven to produce the same register contents, we 130881ad6265SDimitry Andric // can skip emitting the actual state change and continue as if we 130981ad6265SDimitry Andric // had since we know the GPR result of the implicit state change 131081ad6265SDimitry Andric // wouldn't be used and VL/VTYPE registers are correct. Note that 131181ad6265SDimitry Andric // we *do* need to model the state as if it changed as while the 131281ad6265SDimitry Andric // register contents are unchanged, the abstract model can change. 131381ad6265SDimitry Andric if (!PrefixTransparent || needVSETVLIPHI(CurInfo, MBB)) 131481ad6265SDimitry Andric insertVSETVLI(MBB, MI, CurInfo, PrevInfo); 131581ad6265SDimitry Andric PrefixTransparent = false; 131681ad6265SDimitry Andric } 131781ad6265SDimitry Andric 1318fe6060f1SDimitry Andric if (RISCVII::hasVLOp(TSFlags)) { 131981ad6265SDimitry Andric MachineOperand &VLOp = MI.getOperand(getVLOpNum(MI)); 1320fe6060f1SDimitry Andric if (VLOp.isReg()) { 13215f757f3fSDimitry Andric Register Reg = VLOp.getReg(); 13225f757f3fSDimitry Andric MachineInstr *VLOpDef = MRI->getVRegDef(Reg); 13235f757f3fSDimitry Andric 1324fe6060f1SDimitry Andric // Erase the AVL operand from the instruction. 1325fe6060f1SDimitry Andric VLOp.setReg(RISCV::NoRegister); 1326fe6060f1SDimitry Andric VLOp.setIsKill(false); 13275f757f3fSDimitry Andric 13285f757f3fSDimitry Andric // If the AVL was an immediate > 31, then it would have been emitted 13295f757f3fSDimitry Andric // as an ADDI. However, the ADDI might not have been used in the 13305f757f3fSDimitry Andric // vsetvli, or a vsetvli might not have been emitted, so it may be 13315f757f3fSDimitry Andric // dead now. 13325f757f3fSDimitry Andric if (VLOpDef && TII->isAddImmediate(*VLOpDef, Reg) && 13335f757f3fSDimitry Andric MRI->use_nodbg_empty(Reg)) 13345f757f3fSDimitry Andric VLOpDef->eraseFromParent(); 1335fe6060f1SDimitry Andric } 1336fe6060f1SDimitry Andric MI.addOperand(MachineOperand::CreateReg(RISCV::VL, /*isDef*/ false, 1337fe6060f1SDimitry Andric /*isImp*/ true)); 1338fe6060f1SDimitry Andric } 1339fe6060f1SDimitry Andric MI.addOperand(MachineOperand::CreateReg(RISCV::VTYPE, /*isDef*/ false, 1340fe6060f1SDimitry Andric /*isImp*/ true)); 1341fe6060f1SDimitry Andric } 1342fe6060f1SDimitry Andric 1343fe6060f1SDimitry Andric if (MI.isCall() || MI.isInlineAsm() || MI.modifiesRegister(RISCV::VL) || 134481ad6265SDimitry Andric MI.modifiesRegister(RISCV::VTYPE)) 134581ad6265SDimitry Andric PrefixTransparent = false; 134681ad6265SDimitry Andric 134781ad6265SDimitry Andric transferAfter(CurInfo, MI); 1348fe6060f1SDimitry Andric } 1349d56accc7SDimitry Andric 1350d56accc7SDimitry Andric // If we reach the end of the block and our current info doesn't match the 1351d56accc7SDimitry Andric // expected info, insert a vsetvli to correct. 135281ad6265SDimitry Andric if (!UseStrictAsserts) { 1353d56accc7SDimitry Andric const VSETVLIInfo &ExitInfo = BlockInfo[MBB.getNumber()].Exit; 1354d56accc7SDimitry Andric if (CurInfo.isValid() && ExitInfo.isValid() && !ExitInfo.isUnknown() && 1355d56accc7SDimitry Andric CurInfo != ExitInfo) { 135681ad6265SDimitry Andric // Note there's an implicit assumption here that terminators never use 135781ad6265SDimitry Andric // or modify VL or VTYPE. Also, fallthrough will return end(). 135881ad6265SDimitry Andric auto InsertPt = MBB.getFirstInstrTerminator(); 135981ad6265SDimitry Andric insertVSETVLI(MBB, InsertPt, MBB.findDebugLoc(InsertPt), ExitInfo, 136081ad6265SDimitry Andric CurInfo); 1361d56accc7SDimitry Andric CurInfo = ExitInfo; 1362d56accc7SDimitry Andric } 1363d56accc7SDimitry Andric } 136481ad6265SDimitry Andric 136581ad6265SDimitry Andric if (UseStrictAsserts && CurInfo.isValid()) { 136681ad6265SDimitry Andric const auto &Info = BlockInfo[MBB.getNumber()]; 136781ad6265SDimitry Andric if (CurInfo != Info.Exit) { 136881ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "in block " << printMBBReference(MBB) << "\n"); 136981ad6265SDimitry Andric LLVM_DEBUG(dbgs() << " begin state: " << Info.Pred << "\n"); 137081ad6265SDimitry Andric LLVM_DEBUG(dbgs() << " expected end state: " << Info.Exit << "\n"); 137181ad6265SDimitry Andric LLVM_DEBUG(dbgs() << " actual end state: " << CurInfo << "\n"); 137281ad6265SDimitry Andric } 137381ad6265SDimitry Andric assert(CurInfo == Info.Exit && 137481ad6265SDimitry Andric "InsertVSETVLI dataflow invariant violated"); 137581ad6265SDimitry Andric } 137681ad6265SDimitry Andric } 137781ad6265SDimitry Andric 137881ad6265SDimitry Andric /// Perform simple partial redundancy elimination of the VSETVLI instructions 137981ad6265SDimitry Andric /// we're about to insert by looking for cases where we can PRE from the 138081ad6265SDimitry Andric /// beginning of one block to the end of one of its predecessors. Specifically, 138181ad6265SDimitry Andric /// this is geared to catch the common case of a fixed length vsetvl in a single 138281ad6265SDimitry Andric /// block loop when it could execute once in the preheader instead. 138381ad6265SDimitry Andric void RISCVInsertVSETVLI::doPRE(MachineBasicBlock &MBB) { 138481ad6265SDimitry Andric if (!BlockInfo[MBB.getNumber()].Pred.isUnknown()) 138581ad6265SDimitry Andric return; 138681ad6265SDimitry Andric 138781ad6265SDimitry Andric MachineBasicBlock *UnavailablePred = nullptr; 138881ad6265SDimitry Andric VSETVLIInfo AvailableInfo; 138981ad6265SDimitry Andric for (MachineBasicBlock *P : MBB.predecessors()) { 139081ad6265SDimitry Andric const VSETVLIInfo &PredInfo = BlockInfo[P->getNumber()].Exit; 139181ad6265SDimitry Andric if (PredInfo.isUnknown()) { 139281ad6265SDimitry Andric if (UnavailablePred) 139381ad6265SDimitry Andric return; 139481ad6265SDimitry Andric UnavailablePred = P; 139581ad6265SDimitry Andric } else if (!AvailableInfo.isValid()) { 139681ad6265SDimitry Andric AvailableInfo = PredInfo; 139781ad6265SDimitry Andric } else if (AvailableInfo != PredInfo) { 139881ad6265SDimitry Andric return; 139981ad6265SDimitry Andric } 140081ad6265SDimitry Andric } 140181ad6265SDimitry Andric 140281ad6265SDimitry Andric // Unreachable, single pred, or full redundancy. Note that FRE is handled by 140381ad6265SDimitry Andric // phase 3. 140481ad6265SDimitry Andric if (!UnavailablePred || !AvailableInfo.isValid()) 140581ad6265SDimitry Andric return; 140681ad6265SDimitry Andric 14071db9f3b2SDimitry Andric // If we don't know the exact VTYPE, we can't copy the vsetvli to the exit of 14081db9f3b2SDimitry Andric // the unavailable pred. 14091db9f3b2SDimitry Andric if (AvailableInfo.hasSEWLMULRatioOnly()) 14101db9f3b2SDimitry Andric return; 14111db9f3b2SDimitry Andric 141281ad6265SDimitry Andric // Critical edge - TODO: consider splitting? 141381ad6265SDimitry Andric if (UnavailablePred->succ_size() != 1) 141481ad6265SDimitry Andric return; 141581ad6265SDimitry Andric 14165f757f3fSDimitry Andric // If the AVL value is a register (other than our VLMAX sentinel), 14175f757f3fSDimitry Andric // we need to prove the value is available at the point we're going 14185f757f3fSDimitry Andric // to insert the vsetvli at. 14195f757f3fSDimitry Andric if (AvailableInfo.hasAVLReg() && RISCV::X0 != AvailableInfo.getAVLReg()) { 14205f757f3fSDimitry Andric MachineInstr *AVLDefMI = MRI->getVRegDef(AvailableInfo.getAVLReg()); 14215f757f3fSDimitry Andric if (!AVLDefMI) 142281ad6265SDimitry Andric return; 14235f757f3fSDimitry Andric // This is an inline dominance check which covers the case of 14245f757f3fSDimitry Andric // UnavailablePred being the preheader of a loop. 14255f757f3fSDimitry Andric if (AVLDefMI->getParent() != UnavailablePred) 14265f757f3fSDimitry Andric return; 14275f757f3fSDimitry Andric for (auto &TermMI : UnavailablePred->terminators()) 14285f757f3fSDimitry Andric if (&TermMI == AVLDefMI) 14295f757f3fSDimitry Andric return; 14305f757f3fSDimitry Andric } 143181ad6265SDimitry Andric 143206c3fb27SDimitry Andric // Model the effect of changing the input state of the block MBB to 143306c3fb27SDimitry Andric // AvailableInfo. We're looking for two issues here; one legality, 143406c3fb27SDimitry Andric // one profitability. 143506c3fb27SDimitry Andric // 1) If the block doesn't use some of the fields from VL or VTYPE, we 143606c3fb27SDimitry Andric // may hit the end of the block with a different end state. We can 143706c3fb27SDimitry Andric // not make this change without reflowing later blocks as well. 143806c3fb27SDimitry Andric // 2) If we don't actually remove a transition, inserting a vsetvli 143906c3fb27SDimitry Andric // into the predecessor block would be correct, but unprofitable. 144006c3fb27SDimitry Andric VSETVLIInfo OldInfo = BlockInfo[MBB.getNumber()].Pred; 144106c3fb27SDimitry Andric VSETVLIInfo CurInfo = AvailableInfo; 144206c3fb27SDimitry Andric int TransitionsRemoved = 0; 144306c3fb27SDimitry Andric for (const MachineInstr &MI : MBB) { 144406c3fb27SDimitry Andric const VSETVLIInfo LastInfo = CurInfo; 144506c3fb27SDimitry Andric const VSETVLIInfo LastOldInfo = OldInfo; 144606c3fb27SDimitry Andric transferBefore(CurInfo, MI); 144706c3fb27SDimitry Andric transferBefore(OldInfo, MI); 144806c3fb27SDimitry Andric if (CurInfo == LastInfo) 144906c3fb27SDimitry Andric TransitionsRemoved++; 145006c3fb27SDimitry Andric if (LastOldInfo == OldInfo) 145106c3fb27SDimitry Andric TransitionsRemoved--; 145206c3fb27SDimitry Andric transferAfter(CurInfo, MI); 145306c3fb27SDimitry Andric transferAfter(OldInfo, MI); 145406c3fb27SDimitry Andric if (CurInfo == OldInfo) 145506c3fb27SDimitry Andric // Convergence. All transitions after this must match by construction. 145681ad6265SDimitry Andric break; 145781ad6265SDimitry Andric } 145806c3fb27SDimitry Andric if (CurInfo != OldInfo || TransitionsRemoved <= 0) 145906c3fb27SDimitry Andric // Issues 1 and 2 above 146081ad6265SDimitry Andric return; 146181ad6265SDimitry Andric 146281ad6265SDimitry Andric // Finally, update both data flow state and insert the actual vsetvli. 146381ad6265SDimitry Andric // Doing both keeps the code in sync with the dataflow results, which 146481ad6265SDimitry Andric // is critical for correctness of phase 3. 146506c3fb27SDimitry Andric auto OldExit = BlockInfo[UnavailablePred->getNumber()].Exit; 146681ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "PRE VSETVLI from " << MBB.getName() << " to " 146781ad6265SDimitry Andric << UnavailablePred->getName() << " with state " 146881ad6265SDimitry Andric << AvailableInfo << "\n"); 146981ad6265SDimitry Andric BlockInfo[UnavailablePred->getNumber()].Exit = AvailableInfo; 147081ad6265SDimitry Andric BlockInfo[MBB.getNumber()].Pred = AvailableInfo; 147181ad6265SDimitry Andric 147281ad6265SDimitry Andric // Note there's an implicit assumption here that terminators never use 147381ad6265SDimitry Andric // or modify VL or VTYPE. Also, fallthrough will return end(). 147481ad6265SDimitry Andric auto InsertPt = UnavailablePred->getFirstInstrTerminator(); 147581ad6265SDimitry Andric insertVSETVLI(*UnavailablePred, InsertPt, 147681ad6265SDimitry Andric UnavailablePred->findDebugLoc(InsertPt), 147706c3fb27SDimitry Andric AvailableInfo, OldExit); 147881ad6265SDimitry Andric } 147981ad6265SDimitry Andric 148081ad6265SDimitry Andric static void doUnion(DemandedFields &A, DemandedFields B) { 1481bdd1243dSDimitry Andric A.VLAny |= B.VLAny; 1482bdd1243dSDimitry Andric A.VLZeroness |= B.VLZeroness; 148306c3fb27SDimitry Andric A.SEW = std::max(A.SEW, B.SEW); 148481ad6265SDimitry Andric A.LMUL |= B.LMUL; 148581ad6265SDimitry Andric A.SEWLMULRatio |= B.SEWLMULRatio; 148681ad6265SDimitry Andric A.TailPolicy |= B.TailPolicy; 148781ad6265SDimitry Andric A.MaskPolicy |= B.MaskPolicy; 148881ad6265SDimitry Andric } 148981ad6265SDimitry Andric 1490bdd1243dSDimitry Andric // Return true if we can mutate PrevMI to match MI without changing any the 1491bdd1243dSDimitry Andric // fields which would be observed. 149281ad6265SDimitry Andric static bool canMutatePriorConfig(const MachineInstr &PrevMI, 149381ad6265SDimitry Andric const MachineInstr &MI, 14945f757f3fSDimitry Andric const DemandedFields &Used, 14955f757f3fSDimitry Andric const MachineRegisterInfo &MRI) { 1496bdd1243dSDimitry Andric // If the VL values aren't equal, return false if either a) the former is 1497bdd1243dSDimitry Andric // demanded, or b) we can't rewrite the former to be the later for 1498bdd1243dSDimitry Andric // implementation reasons. 1499bdd1243dSDimitry Andric if (!isVLPreservingConfig(MI)) { 1500bdd1243dSDimitry Andric if (Used.VLAny) 150181ad6265SDimitry Andric return false; 150281ad6265SDimitry Andric 15035f757f3fSDimitry Andric if (Used.VLZeroness) { 15045f757f3fSDimitry Andric if (isVLPreservingConfig(PrevMI)) 1505bdd1243dSDimitry Andric return false; 1506297eecfbSDimitry Andric if (!getInfoForVSETVLI(PrevMI).hasEquallyZeroAVL(getInfoForVSETVLI(MI), 1507297eecfbSDimitry Andric MRI)) 15085f757f3fSDimitry Andric return false; 15095f757f3fSDimitry Andric } 1510bdd1243dSDimitry Andric 1511297eecfbSDimitry Andric auto &AVL = MI.getOperand(1); 1512297eecfbSDimitry Andric auto &PrevAVL = PrevMI.getOperand(1); 1513297eecfbSDimitry Andric assert(MRI.isSSA()); 1514297eecfbSDimitry Andric 1515297eecfbSDimitry Andric // If the AVL is a register, we need to make sure MI's AVL dominates PrevMI. 1516297eecfbSDimitry Andric // For now just check that PrevMI uses the same virtual register. 1517297eecfbSDimitry Andric if (AVL.isReg() && AVL.getReg() != RISCV::X0) { 1518297eecfbSDimitry Andric if (AVL.getReg().isPhysical()) 1519bdd1243dSDimitry Andric return false; 1520297eecfbSDimitry Andric if (!PrevAVL.isReg() || PrevAVL.getReg() != AVL.getReg()) 1521297eecfbSDimitry Andric return false; 1522297eecfbSDimitry Andric } 1523bdd1243dSDimitry Andric } 1524bdd1243dSDimitry Andric 152581ad6265SDimitry Andric if (!PrevMI.getOperand(2).isImm() || !MI.getOperand(2).isImm()) 152681ad6265SDimitry Andric return false; 152781ad6265SDimitry Andric 152881ad6265SDimitry Andric auto PriorVType = PrevMI.getOperand(2).getImm(); 152981ad6265SDimitry Andric auto VType = MI.getOperand(2).getImm(); 153081ad6265SDimitry Andric return areCompatibleVTYPEs(PriorVType, VType, Used); 153181ad6265SDimitry Andric } 153281ad6265SDimitry Andric 153381ad6265SDimitry Andric void RISCVInsertVSETVLI::doLocalPostpass(MachineBasicBlock &MBB) { 1534bdd1243dSDimitry Andric MachineInstr *NextMI = nullptr; 1535bdd1243dSDimitry Andric // We can have arbitrary code in successors, so VL and VTYPE 1536bdd1243dSDimitry Andric // must be considered demanded. 153781ad6265SDimitry Andric DemandedFields Used; 1538bdd1243dSDimitry Andric Used.demandVL(); 1539bdd1243dSDimitry Andric Used.demandVTYPE(); 154081ad6265SDimitry Andric SmallVector<MachineInstr*> ToDelete; 1541bdd1243dSDimitry Andric for (MachineInstr &MI : make_range(MBB.rbegin(), MBB.rend())) { 1542bdd1243dSDimitry Andric 1543bdd1243dSDimitry Andric if (!isVectorConfigInstr(MI)) { 15445f757f3fSDimitry Andric doUnion(Used, getDemanded(MI, MRI, ST)); 154581ad6265SDimitry Andric continue; 154681ad6265SDimitry Andric } 1547bdd1243dSDimitry Andric 154881ad6265SDimitry Andric Register VRegDef = MI.getOperand(0).getReg(); 154981ad6265SDimitry Andric if (VRegDef != RISCV::X0 && 155081ad6265SDimitry Andric !(VRegDef.isVirtual() && MRI->use_nodbg_empty(VRegDef))) 1551bdd1243dSDimitry Andric Used.demandVL(); 1552bdd1243dSDimitry Andric 1553bdd1243dSDimitry Andric if (NextMI) { 1554bdd1243dSDimitry Andric if (!Used.usedVL() && !Used.usedVTYPE()) { 1555bdd1243dSDimitry Andric ToDelete.push_back(&MI); 1556bdd1243dSDimitry Andric // Leave NextMI unchanged 1557bdd1243dSDimitry Andric continue; 15585f757f3fSDimitry Andric } else if (canMutatePriorConfig(MI, *NextMI, Used, *MRI)) { 1559bdd1243dSDimitry Andric if (!isVLPreservingConfig(*NextMI)) { 15605f757f3fSDimitry Andric MI.getOperand(0).setReg(NextMI->getOperand(0).getReg()); 15615f757f3fSDimitry Andric MI.getOperand(0).setIsDead(false); 15625f757f3fSDimitry Andric Register OldVLReg; 15635f757f3fSDimitry Andric if (MI.getOperand(1).isReg()) 15645f757f3fSDimitry Andric OldVLReg = MI.getOperand(1).getReg(); 1565bdd1243dSDimitry Andric if (NextMI->getOperand(1).isImm()) 1566bdd1243dSDimitry Andric MI.getOperand(1).ChangeToImmediate(NextMI->getOperand(1).getImm()); 1567bdd1243dSDimitry Andric else 1568bdd1243dSDimitry Andric MI.getOperand(1).ChangeToRegister(NextMI->getOperand(1).getReg(), false); 15695f757f3fSDimitry Andric if (OldVLReg) { 15705f757f3fSDimitry Andric MachineInstr *VLOpDef = MRI->getUniqueVRegDef(OldVLReg); 15715f757f3fSDimitry Andric if (VLOpDef && TII->isAddImmediate(*VLOpDef, OldVLReg) && 15725f757f3fSDimitry Andric MRI->use_nodbg_empty(OldVLReg)) 15735f757f3fSDimitry Andric VLOpDef->eraseFromParent(); 15745f757f3fSDimitry Andric } 1575bdd1243dSDimitry Andric MI.setDesc(NextMI->getDesc()); 1576bdd1243dSDimitry Andric } 1577bdd1243dSDimitry Andric MI.getOperand(2).setImm(NextMI->getOperand(2).getImm()); 1578bdd1243dSDimitry Andric ToDelete.push_back(NextMI); 1579bdd1243dSDimitry Andric // fallthrough 1580bdd1243dSDimitry Andric } 1581bdd1243dSDimitry Andric } 1582bdd1243dSDimitry Andric NextMI = &MI; 15835f757f3fSDimitry Andric Used = getDemanded(MI, MRI, ST); 158481ad6265SDimitry Andric } 158581ad6265SDimitry Andric 1586*7a6dacacSDimitry Andric NumRemovedVSETVL += ToDelete.size(); 158781ad6265SDimitry Andric for (auto *MI : ToDelete) 158881ad6265SDimitry Andric MI->eraseFromParent(); 158981ad6265SDimitry Andric } 159081ad6265SDimitry Andric 159181ad6265SDimitry Andric void RISCVInsertVSETVLI::insertReadVL(MachineBasicBlock &MBB) { 159281ad6265SDimitry Andric for (auto I = MBB.begin(), E = MBB.end(); I != E;) { 159381ad6265SDimitry Andric MachineInstr &MI = *I++; 159481ad6265SDimitry Andric if (RISCV::isFaultFirstLoad(MI)) { 159581ad6265SDimitry Andric Register VLOutput = MI.getOperand(1).getReg(); 159681ad6265SDimitry Andric if (!MRI->use_nodbg_empty(VLOutput)) 159781ad6265SDimitry Andric BuildMI(MBB, I, MI.getDebugLoc(), TII->get(RISCV::PseudoReadVL), 159881ad6265SDimitry Andric VLOutput); 159981ad6265SDimitry Andric // We don't use the vl output of the VLEFF/VLSEGFF anymore. 160081ad6265SDimitry Andric MI.getOperand(1).setReg(RISCV::X0); 160181ad6265SDimitry Andric } 1602fe6060f1SDimitry Andric } 1603fe6060f1SDimitry Andric } 1604fe6060f1SDimitry Andric 1605fe6060f1SDimitry Andric bool RISCVInsertVSETVLI::runOnMachineFunction(MachineFunction &MF) { 1606fe6060f1SDimitry Andric // Skip if the vector extension is not enabled. 16075f757f3fSDimitry Andric ST = &MF.getSubtarget<RISCVSubtarget>(); 16085f757f3fSDimitry Andric if (!ST->hasVInstructions()) 1609fe6060f1SDimitry Andric return false; 1610fe6060f1SDimitry Andric 161181ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "Entering InsertVSETVLI for " << MF.getName() << "\n"); 161281ad6265SDimitry Andric 16135f757f3fSDimitry Andric TII = ST->getInstrInfo(); 1614fe6060f1SDimitry Andric MRI = &MF.getRegInfo(); 1615fe6060f1SDimitry Andric 1616fe6060f1SDimitry Andric assert(BlockInfo.empty() && "Expect empty block infos"); 1617fe6060f1SDimitry Andric BlockInfo.resize(MF.getNumBlockIDs()); 1618fe6060f1SDimitry Andric 1619fe6060f1SDimitry Andric bool HaveVectorOp = false; 1620fe6060f1SDimitry Andric 1621fe6060f1SDimitry Andric // Phase 1 - determine how VL/VTYPE are affected by the each block. 162281ad6265SDimitry Andric for (const MachineBasicBlock &MBB : MF) { 16235f757f3fSDimitry Andric VSETVLIInfo TmpStatus; 16245f757f3fSDimitry Andric HaveVectorOp |= computeVLVTYPEChanges(MBB, TmpStatus); 162581ad6265SDimitry Andric // Initial exit state is whatever change we found in the block. 162681ad6265SDimitry Andric BlockData &BBInfo = BlockInfo[MBB.getNumber()]; 16275f757f3fSDimitry Andric BBInfo.Exit = TmpStatus; 162881ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "Initial exit state of " << printMBBReference(MBB) 162981ad6265SDimitry Andric << " is " << BBInfo.Exit << "\n"); 163081ad6265SDimitry Andric 163181ad6265SDimitry Andric } 1632fe6060f1SDimitry Andric 1633fe6060f1SDimitry Andric // If we didn't find any instructions that need VSETVLI, we're done. 163481ad6265SDimitry Andric if (!HaveVectorOp) { 163581ad6265SDimitry Andric BlockInfo.clear(); 163681ad6265SDimitry Andric return false; 163781ad6265SDimitry Andric } 163881ad6265SDimitry Andric 1639fe6060f1SDimitry Andric // Phase 2 - determine the exit VL/VTYPE from each block. We add all 1640fe6060f1SDimitry Andric // blocks to the list here, but will also add any that need to be revisited 1641fe6060f1SDimitry Andric // during Phase 2 processing. 1642fe6060f1SDimitry Andric for (const MachineBasicBlock &MBB : MF) { 1643fe6060f1SDimitry Andric WorkList.push(&MBB); 1644fe6060f1SDimitry Andric BlockInfo[MBB.getNumber()].InQueue = true; 1645fe6060f1SDimitry Andric } 1646fe6060f1SDimitry Andric while (!WorkList.empty()) { 1647fe6060f1SDimitry Andric const MachineBasicBlock &MBB = *WorkList.front(); 1648fe6060f1SDimitry Andric WorkList.pop(); 1649fe6060f1SDimitry Andric computeIncomingVLVTYPE(MBB); 1650fe6060f1SDimitry Andric } 1651fe6060f1SDimitry Andric 165281ad6265SDimitry Andric // Perform partial redundancy elimination of vsetvli transitions. 165381ad6265SDimitry Andric for (MachineBasicBlock &MBB : MF) 165481ad6265SDimitry Andric doPRE(MBB); 165581ad6265SDimitry Andric 1656fe6060f1SDimitry Andric // Phase 3 - add any vsetvli instructions needed in the block. Use the 1657fe6060f1SDimitry Andric // Phase 2 information to avoid adding vsetvlis before the first vector 1658fe6060f1SDimitry Andric // instruction in the block if the VL/VTYPE is satisfied by its 1659fe6060f1SDimitry Andric // predecessors. 1660fe6060f1SDimitry Andric for (MachineBasicBlock &MBB : MF) 1661fe6060f1SDimitry Andric emitVSETVLIs(MBB); 166281ad6265SDimitry Andric 166381ad6265SDimitry Andric // Now that all vsetvlis are explicit, go through and do block local 166481ad6265SDimitry Andric // DSE and peephole based demanded fields based transforms. Note that 166581ad6265SDimitry Andric // this *must* be done outside the main dataflow so long as we allow 166681ad6265SDimitry Andric // any cross block analysis within the dataflow. We can't have both 166781ad6265SDimitry Andric // demanded fields based mutation and non-local analysis in the 166881ad6265SDimitry Andric // dataflow at the same time without introducing inconsistencies. 166981ad6265SDimitry Andric for (MachineBasicBlock &MBB : MF) 167081ad6265SDimitry Andric doLocalPostpass(MBB); 167181ad6265SDimitry Andric 167281ad6265SDimitry Andric // Insert PseudoReadVL after VLEFF/VLSEGFF and replace it with the vl output 167381ad6265SDimitry Andric // of VLEFF/VLSEGFF. 167481ad6265SDimitry Andric for (MachineBasicBlock &MBB : MF) 167581ad6265SDimitry Andric insertReadVL(MBB); 1676fe6060f1SDimitry Andric 167781ad6265SDimitry Andric BlockInfo.clear(); 1678fe6060f1SDimitry Andric return HaveVectorOp; 1679fe6060f1SDimitry Andric } 1680fe6060f1SDimitry Andric 1681fe6060f1SDimitry Andric /// Returns an instance of the Insert VSETVLI pass. 1682fe6060f1SDimitry Andric FunctionPass *llvm::createRISCVInsertVSETVLIPass() { 1683fe6060f1SDimitry Andric return new RISCVInsertVSETVLI(); 1684fe6060f1SDimitry Andric } 1685