1fe6060f1SDimitry Andric //===- RISCVInsertVSETVLI.cpp - Insert VSETVLI instructions ---------------===// 2fe6060f1SDimitry Andric // 3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6fe6060f1SDimitry Andric // 7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 8fe6060f1SDimitry Andric // 9fe6060f1SDimitry Andric // This file implements a function pass that inserts VSETVLI instructions where 1081ad6265SDimitry Andric // needed and expands the vl outputs of VLEFF/VLSEGFF to PseudoReadVL 1181ad6265SDimitry Andric // instructions. 12fe6060f1SDimitry Andric // 13fe6060f1SDimitry Andric // This pass consists of 3 phases: 14fe6060f1SDimitry Andric // 15fe6060f1SDimitry Andric // Phase 1 collects how each basic block affects VL/VTYPE. 16fe6060f1SDimitry Andric // 17fe6060f1SDimitry Andric // Phase 2 uses the information from phase 1 to do a data flow analysis to 18fe6060f1SDimitry Andric // propagate the VL/VTYPE changes through the function. This gives us the 19fe6060f1SDimitry Andric // VL/VTYPE at the start of each basic block. 20fe6060f1SDimitry Andric // 21fe6060f1SDimitry Andric // Phase 3 inserts VSETVLI instructions in each basic block. Information from 22fe6060f1SDimitry Andric // phase 2 is used to prevent inserting a VSETVLI before the first vector 23fe6060f1SDimitry Andric // instruction in the block if possible. 24fe6060f1SDimitry Andric // 25fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 26fe6060f1SDimitry Andric 27fe6060f1SDimitry Andric #include "RISCV.h" 28fe6060f1SDimitry Andric #include "RISCVSubtarget.h" 29fe6060f1SDimitry Andric #include "llvm/CodeGen/LiveIntervals.h" 30fe6060f1SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 31fe6060f1SDimitry Andric #include <queue> 32fe6060f1SDimitry Andric using namespace llvm; 33fe6060f1SDimitry Andric 34fe6060f1SDimitry Andric #define DEBUG_TYPE "riscv-insert-vsetvli" 3506c3fb27SDimitry Andric #define RISCV_INSERT_VSETVLI_NAME "RISC-V Insert VSETVLI pass" 36fe6060f1SDimitry Andric 37fe6060f1SDimitry Andric static cl::opt<bool> DisableInsertVSETVLPHIOpt( 38fe6060f1SDimitry Andric "riscv-disable-insert-vsetvl-phi-opt", cl::init(false), cl::Hidden, 39fe6060f1SDimitry Andric cl::desc("Disable looking through phis when inserting vsetvlis.")); 40fe6060f1SDimitry Andric 4181ad6265SDimitry Andric static cl::opt<bool> UseStrictAsserts( 4281ad6265SDimitry Andric "riscv-insert-vsetvl-strict-asserts", cl::init(true), cl::Hidden, 4381ad6265SDimitry Andric cl::desc("Enable strict assertion checking for the dataflow algorithm")); 4481ad6265SDimitry Andric 45fe6060f1SDimitry Andric namespace { 46fe6060f1SDimitry Andric 4781ad6265SDimitry Andric static unsigned getVLOpNum(const MachineInstr &MI) { 4881ad6265SDimitry Andric return RISCVII::getVLOpNum(MI.getDesc()); 49fe6060f1SDimitry Andric } 50fe6060f1SDimitry Andric 5181ad6265SDimitry Andric static unsigned getSEWOpNum(const MachineInstr &MI) { 5281ad6265SDimitry Andric return RISCVII::getSEWOpNum(MI.getDesc()); 53fe6060f1SDimitry Andric } 54fe6060f1SDimitry Andric 55bdd1243dSDimitry Andric static bool isVectorConfigInstr(const MachineInstr &MI) { 56bdd1243dSDimitry Andric return MI.getOpcode() == RISCV::PseudoVSETVLI || 57bdd1243dSDimitry Andric MI.getOpcode() == RISCV::PseudoVSETVLIX0 || 58bdd1243dSDimitry Andric MI.getOpcode() == RISCV::PseudoVSETIVLI; 59bdd1243dSDimitry Andric } 60bdd1243dSDimitry Andric 61bdd1243dSDimitry Andric /// Return true if this is 'vsetvli x0, x0, vtype' which preserves 62bdd1243dSDimitry Andric /// VL and only sets VTYPE. 63bdd1243dSDimitry Andric static bool isVLPreservingConfig(const MachineInstr &MI) { 64bdd1243dSDimitry Andric if (MI.getOpcode() != RISCV::PseudoVSETVLIX0) 65bdd1243dSDimitry Andric return false; 66bdd1243dSDimitry Andric assert(RISCV::X0 == MI.getOperand(1).getReg()); 67bdd1243dSDimitry Andric return RISCV::X0 == MI.getOperand(0).getReg(); 68bdd1243dSDimitry Andric } 69bdd1243dSDimitry Andric 705f757f3fSDimitry Andric static bool isFloatScalarMoveOrScalarSplatInstr(const MachineInstr &MI) { 715f757f3fSDimitry Andric switch (RISCV::getRVVMCOpcode(MI.getOpcode())) { 725f757f3fSDimitry Andric default: 735f757f3fSDimitry Andric return false; 745f757f3fSDimitry Andric case RISCV::VFMV_S_F: 755f757f3fSDimitry Andric case RISCV::VFMV_V_F: 765f757f3fSDimitry Andric return true; 775f757f3fSDimitry Andric } 78bdd1243dSDimitry Andric } 79bdd1243dSDimitry Andric 805f757f3fSDimitry Andric static bool isScalarExtractInstr(const MachineInstr &MI) { 815f757f3fSDimitry Andric switch (RISCV::getRVVMCOpcode(MI.getOpcode())) { 825f757f3fSDimitry Andric default: 835f757f3fSDimitry Andric return false; 845f757f3fSDimitry Andric case RISCV::VMV_X_S: 855f757f3fSDimitry Andric case RISCV::VFMV_F_S: 865f757f3fSDimitry Andric return true; 875f757f3fSDimitry Andric } 885f757f3fSDimitry Andric } 895f757f3fSDimitry Andric 905f757f3fSDimitry Andric static bool isScalarInsertInstr(const MachineInstr &MI) { 915f757f3fSDimitry Andric switch (RISCV::getRVVMCOpcode(MI.getOpcode())) { 9204eeddc0SDimitry Andric default: 9304eeddc0SDimitry Andric return false; 94bdd1243dSDimitry Andric case RISCV::VMV_S_X: 95bdd1243dSDimitry Andric case RISCV::VFMV_S_F: 9604eeddc0SDimitry Andric return true; 9704eeddc0SDimitry Andric } 9804eeddc0SDimitry Andric } 9904eeddc0SDimitry Andric 10006c3fb27SDimitry Andric static bool isScalarSplatInstr(const MachineInstr &MI) { 1015f757f3fSDimitry Andric switch (RISCV::getRVVMCOpcode(MI.getOpcode())) { 10206c3fb27SDimitry Andric default: 10306c3fb27SDimitry Andric return false; 10406c3fb27SDimitry Andric case RISCV::VMV_V_I: 10506c3fb27SDimitry Andric case RISCV::VMV_V_X: 10606c3fb27SDimitry Andric case RISCV::VFMV_V_F: 10706c3fb27SDimitry Andric return true; 10806c3fb27SDimitry Andric } 10906c3fb27SDimitry Andric } 11006c3fb27SDimitry Andric 11106c3fb27SDimitry Andric static bool isVSlideInstr(const MachineInstr &MI) { 1125f757f3fSDimitry Andric switch (RISCV::getRVVMCOpcode(MI.getOpcode())) { 11306c3fb27SDimitry Andric default: 11406c3fb27SDimitry Andric return false; 11506c3fb27SDimitry Andric case RISCV::VSLIDEDOWN_VX: 11606c3fb27SDimitry Andric case RISCV::VSLIDEDOWN_VI: 11706c3fb27SDimitry Andric case RISCV::VSLIDEUP_VX: 11806c3fb27SDimitry Andric case RISCV::VSLIDEUP_VI: 11906c3fb27SDimitry Andric return true; 12006c3fb27SDimitry Andric } 12106c3fb27SDimitry Andric } 12206c3fb27SDimitry Andric 123bdd1243dSDimitry Andric /// Get the EEW for a load or store instruction. Return std::nullopt if MI is 124bdd1243dSDimitry Andric /// not a load or store which ignores SEW. 125bdd1243dSDimitry Andric static std::optional<unsigned> getEEWForLoadStore(const MachineInstr &MI) { 1265f757f3fSDimitry Andric switch (RISCV::getRVVMCOpcode(MI.getOpcode())) { 127349cc55cSDimitry Andric default: 128bdd1243dSDimitry Andric return std::nullopt; 129bdd1243dSDimitry Andric case RISCV::VLE8_V: 130bdd1243dSDimitry Andric case RISCV::VLSE8_V: 131bdd1243dSDimitry Andric case RISCV::VSE8_V: 132bdd1243dSDimitry Andric case RISCV::VSSE8_V: 13381ad6265SDimitry Andric return 8; 134bdd1243dSDimitry Andric case RISCV::VLE16_V: 135bdd1243dSDimitry Andric case RISCV::VLSE16_V: 136bdd1243dSDimitry Andric case RISCV::VSE16_V: 137bdd1243dSDimitry Andric case RISCV::VSSE16_V: 13881ad6265SDimitry Andric return 16; 139bdd1243dSDimitry Andric case RISCV::VLE32_V: 140bdd1243dSDimitry Andric case RISCV::VLSE32_V: 141bdd1243dSDimitry Andric case RISCV::VSE32_V: 142bdd1243dSDimitry Andric case RISCV::VSSE32_V: 14381ad6265SDimitry Andric return 32; 144bdd1243dSDimitry Andric case RISCV::VLE64_V: 145bdd1243dSDimitry Andric case RISCV::VLSE64_V: 146bdd1243dSDimitry Andric case RISCV::VSE64_V: 147bdd1243dSDimitry Andric case RISCV::VSSE64_V: 14881ad6265SDimitry Andric return 64; 14981ad6265SDimitry Andric } 150349cc55cSDimitry Andric } 151349cc55cSDimitry Andric 1525f757f3fSDimitry Andric static bool isNonZeroLoadImmediate(MachineInstr &MI) { 1535f757f3fSDimitry Andric return MI.getOpcode() == RISCV::ADDI && 1545f757f3fSDimitry Andric MI.getOperand(1).isReg() && MI.getOperand(2).isImm() && 1555f757f3fSDimitry Andric MI.getOperand(1).getReg() == RISCV::X0 && 1565f757f3fSDimitry Andric MI.getOperand(2).getImm() != 0; 1575f757f3fSDimitry Andric } 1585f757f3fSDimitry Andric 15981ad6265SDimitry Andric /// Return true if this is an operation on mask registers. Note that 16081ad6265SDimitry Andric /// this includes both arithmetic/logical ops and load/store (vlm/vsm). 16181ad6265SDimitry Andric static bool isMaskRegOp(const MachineInstr &MI) { 162bdd1243dSDimitry Andric if (!RISCVII::hasSEWOp(MI.getDesc().TSFlags)) 163bdd1243dSDimitry Andric return false; 16481ad6265SDimitry Andric const unsigned Log2SEW = MI.getOperand(getSEWOpNum(MI)).getImm(); 16581ad6265SDimitry Andric // A Log2SEW of 0 is an operation on mask registers only. 16681ad6265SDimitry Andric return Log2SEW == 0; 16781ad6265SDimitry Andric } 16881ad6265SDimitry Andric 16906c3fb27SDimitry Andric /// Return true if the inactive elements in the result are entirely undefined. 17006c3fb27SDimitry Andric /// Note that this is different from "agnostic" as defined by the vector 17106c3fb27SDimitry Andric /// specification. Agnostic requires each lane to either be undisturbed, or 17206c3fb27SDimitry Andric /// take the value -1; no other value is allowed. 17306c3fb27SDimitry Andric static bool hasUndefinedMergeOp(const MachineInstr &MI, 17406c3fb27SDimitry Andric const MachineRegisterInfo &MRI) { 17506c3fb27SDimitry Andric 17606c3fb27SDimitry Andric unsigned UseOpIdx; 17706c3fb27SDimitry Andric if (!MI.isRegTiedToUseOperand(0, &UseOpIdx)) 17806c3fb27SDimitry Andric // If there is no passthrough operand, then the pass through 17906c3fb27SDimitry Andric // lanes are undefined. 18006c3fb27SDimitry Andric return true; 18106c3fb27SDimitry Andric 1825f757f3fSDimitry Andric // If the tied operand is NoReg, an IMPLICIT_DEF, or a REG_SEQEUENCE whose 1835f757f3fSDimitry Andric // operands are solely IMPLICIT_DEFS, then the pass through lanes are 1845f757f3fSDimitry Andric // undefined. 18506c3fb27SDimitry Andric const MachineOperand &UseMO = MI.getOperand(UseOpIdx); 1865f757f3fSDimitry Andric if (UseMO.getReg() == RISCV::NoRegister) 1875f757f3fSDimitry Andric return true; 1885f757f3fSDimitry Andric 18906c3fb27SDimitry Andric if (MachineInstr *UseMI = MRI.getVRegDef(UseMO.getReg())) { 19006c3fb27SDimitry Andric if (UseMI->isImplicitDef()) 19106c3fb27SDimitry Andric return true; 19206c3fb27SDimitry Andric 19306c3fb27SDimitry Andric if (UseMI->isRegSequence()) { 19406c3fb27SDimitry Andric for (unsigned i = 1, e = UseMI->getNumOperands(); i < e; i += 2) { 19506c3fb27SDimitry Andric MachineInstr *SourceMI = MRI.getVRegDef(UseMI->getOperand(i).getReg()); 19606c3fb27SDimitry Andric if (!SourceMI || !SourceMI->isImplicitDef()) 19706c3fb27SDimitry Andric return false; 19806c3fb27SDimitry Andric } 19906c3fb27SDimitry Andric return true; 20006c3fb27SDimitry Andric } 20106c3fb27SDimitry Andric } 20206c3fb27SDimitry Andric return false; 20306c3fb27SDimitry Andric } 20406c3fb27SDimitry Andric 20581ad6265SDimitry Andric /// Which subfields of VL or VTYPE have values we need to preserve? 20681ad6265SDimitry Andric struct DemandedFields { 207bdd1243dSDimitry Andric // Some unknown property of VL is used. If demanded, must preserve entire 208bdd1243dSDimitry Andric // value. 209bdd1243dSDimitry Andric bool VLAny = false; 210bdd1243dSDimitry Andric // Only zero vs non-zero is used. If demanded, can change non-zero values. 211bdd1243dSDimitry Andric bool VLZeroness = false; 21206c3fb27SDimitry Andric // What properties of SEW we need to preserve. 21306c3fb27SDimitry Andric enum : uint8_t { 2145f757f3fSDimitry Andric SEWEqual = 3, // The exact value of SEW needs to be preserved. 2155f757f3fSDimitry Andric SEWGreaterThanOrEqual = 2, // SEW can be changed as long as it's greater 21606c3fb27SDimitry Andric // than or equal to the original value. 2175f757f3fSDimitry Andric SEWGreaterThanOrEqualAndLessThan64 = 2185f757f3fSDimitry Andric 1, // SEW can be changed as long as it's greater 2195f757f3fSDimitry Andric // than or equal to the original value, but must be less 2205f757f3fSDimitry Andric // than 64. 22106c3fb27SDimitry Andric SEWNone = 0 // We don't need to preserve SEW at all. 22206c3fb27SDimitry Andric } SEW = SEWNone; 22381ad6265SDimitry Andric bool LMUL = false; 22481ad6265SDimitry Andric bool SEWLMULRatio = false; 22581ad6265SDimitry Andric bool TailPolicy = false; 22681ad6265SDimitry Andric bool MaskPolicy = false; 22781ad6265SDimitry Andric 22881ad6265SDimitry Andric // Return true if any part of VTYPE was used 229bdd1243dSDimitry Andric bool usedVTYPE() const { 23081ad6265SDimitry Andric return SEW || LMUL || SEWLMULRatio || TailPolicy || MaskPolicy; 23181ad6265SDimitry Andric } 23281ad6265SDimitry Andric 233bdd1243dSDimitry Andric // Return true if any property of VL was used 234bdd1243dSDimitry Andric bool usedVL() { 235bdd1243dSDimitry Andric return VLAny || VLZeroness; 236bdd1243dSDimitry Andric } 237bdd1243dSDimitry Andric 23881ad6265SDimitry Andric // Mark all VTYPE subfields and properties as demanded 23981ad6265SDimitry Andric void demandVTYPE() { 24006c3fb27SDimitry Andric SEW = SEWEqual; 24181ad6265SDimitry Andric LMUL = true; 24281ad6265SDimitry Andric SEWLMULRatio = true; 24381ad6265SDimitry Andric TailPolicy = true; 24481ad6265SDimitry Andric MaskPolicy = true; 24581ad6265SDimitry Andric } 246bdd1243dSDimitry Andric 247bdd1243dSDimitry Andric // Mark all VL properties as demanded 248bdd1243dSDimitry Andric void demandVL() { 249bdd1243dSDimitry Andric VLAny = true; 250bdd1243dSDimitry Andric VLZeroness = true; 251bdd1243dSDimitry Andric } 252bdd1243dSDimitry Andric 253bdd1243dSDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 254bdd1243dSDimitry Andric /// Support for debugging, callable in GDB: V->dump() 255bdd1243dSDimitry Andric LLVM_DUMP_METHOD void dump() const { 256bdd1243dSDimitry Andric print(dbgs()); 257bdd1243dSDimitry Andric dbgs() << "\n"; 258bdd1243dSDimitry Andric } 259bdd1243dSDimitry Andric 260bdd1243dSDimitry Andric /// Implement operator<<. 261bdd1243dSDimitry Andric void print(raw_ostream &OS) const { 262bdd1243dSDimitry Andric OS << "{"; 263bdd1243dSDimitry Andric OS << "VLAny=" << VLAny << ", "; 264bdd1243dSDimitry Andric OS << "VLZeroness=" << VLZeroness << ", "; 26506c3fb27SDimitry Andric OS << "SEW="; 26606c3fb27SDimitry Andric switch (SEW) { 26706c3fb27SDimitry Andric case SEWEqual: 26806c3fb27SDimitry Andric OS << "SEWEqual"; 26906c3fb27SDimitry Andric break; 27006c3fb27SDimitry Andric case SEWGreaterThanOrEqual: 27106c3fb27SDimitry Andric OS << "SEWGreaterThanOrEqual"; 27206c3fb27SDimitry Andric break; 2735f757f3fSDimitry Andric case SEWGreaterThanOrEqualAndLessThan64: 2745f757f3fSDimitry Andric OS << "SEWGreaterThanOrEqualAndLessThan64"; 2755f757f3fSDimitry Andric break; 27606c3fb27SDimitry Andric case SEWNone: 27706c3fb27SDimitry Andric OS << "SEWNone"; 27806c3fb27SDimitry Andric break; 27906c3fb27SDimitry Andric }; 28006c3fb27SDimitry Andric OS << ", "; 281bdd1243dSDimitry Andric OS << "LMUL=" << LMUL << ", "; 282bdd1243dSDimitry Andric OS << "SEWLMULRatio=" << SEWLMULRatio << ", "; 283bdd1243dSDimitry Andric OS << "TailPolicy=" << TailPolicy << ", "; 284bdd1243dSDimitry Andric OS << "MaskPolicy=" << MaskPolicy; 285bdd1243dSDimitry Andric OS << "}"; 286bdd1243dSDimitry Andric } 287bdd1243dSDimitry Andric #endif 28881ad6265SDimitry Andric }; 28981ad6265SDimitry Andric 290bdd1243dSDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 291bdd1243dSDimitry Andric LLVM_ATTRIBUTE_USED 292bdd1243dSDimitry Andric inline raw_ostream &operator<<(raw_ostream &OS, const DemandedFields &DF) { 293bdd1243dSDimitry Andric DF.print(OS); 294bdd1243dSDimitry Andric return OS; 295bdd1243dSDimitry Andric } 296bdd1243dSDimitry Andric #endif 297bdd1243dSDimitry Andric 29806c3fb27SDimitry Andric /// Return true if moving from CurVType to NewVType is 29906c3fb27SDimitry Andric /// indistinguishable from the perspective of an instruction (or set 30006c3fb27SDimitry Andric /// of instructions) which use only the Used subfields and properties. 30106c3fb27SDimitry Andric static bool areCompatibleVTYPEs(uint64_t CurVType, uint64_t NewVType, 30281ad6265SDimitry Andric const DemandedFields &Used) { 3035f757f3fSDimitry Andric switch (Used.SEW) { 3045f757f3fSDimitry Andric case DemandedFields::SEWNone: 3055f757f3fSDimitry Andric break; 3065f757f3fSDimitry Andric case DemandedFields::SEWEqual: 3075f757f3fSDimitry Andric if (RISCVVType::getSEW(CurVType) != RISCVVType::getSEW(NewVType)) 30806c3fb27SDimitry Andric return false; 3095f757f3fSDimitry Andric break; 3105f757f3fSDimitry Andric case DemandedFields::SEWGreaterThanOrEqual: 3115f757f3fSDimitry Andric if (RISCVVType::getSEW(NewVType) < RISCVVType::getSEW(CurVType)) 31281ad6265SDimitry Andric return false; 3135f757f3fSDimitry Andric break; 3145f757f3fSDimitry Andric case DemandedFields::SEWGreaterThanOrEqualAndLessThan64: 3155f757f3fSDimitry Andric if (RISCVVType::getSEW(NewVType) < RISCVVType::getSEW(CurVType) || 3165f757f3fSDimitry Andric RISCVVType::getSEW(NewVType) >= 64) 3175f757f3fSDimitry Andric return false; 3185f757f3fSDimitry Andric break; 3195f757f3fSDimitry Andric } 32081ad6265SDimitry Andric 32181ad6265SDimitry Andric if (Used.LMUL && 32206c3fb27SDimitry Andric RISCVVType::getVLMUL(CurVType) != RISCVVType::getVLMUL(NewVType)) 32381ad6265SDimitry Andric return false; 32481ad6265SDimitry Andric 32581ad6265SDimitry Andric if (Used.SEWLMULRatio) { 32606c3fb27SDimitry Andric auto Ratio1 = RISCVVType::getSEWLMULRatio(RISCVVType::getSEW(CurVType), 32706c3fb27SDimitry Andric RISCVVType::getVLMUL(CurVType)); 32806c3fb27SDimitry Andric auto Ratio2 = RISCVVType::getSEWLMULRatio(RISCVVType::getSEW(NewVType), 32906c3fb27SDimitry Andric RISCVVType::getVLMUL(NewVType)); 33081ad6265SDimitry Andric if (Ratio1 != Ratio2) 33181ad6265SDimitry Andric return false; 33281ad6265SDimitry Andric } 33381ad6265SDimitry Andric 33406c3fb27SDimitry Andric if (Used.TailPolicy && RISCVVType::isTailAgnostic(CurVType) != 33506c3fb27SDimitry Andric RISCVVType::isTailAgnostic(NewVType)) 33681ad6265SDimitry Andric return false; 33706c3fb27SDimitry Andric if (Used.MaskPolicy && RISCVVType::isMaskAgnostic(CurVType) != 33806c3fb27SDimitry Andric RISCVVType::isMaskAgnostic(NewVType)) 33981ad6265SDimitry Andric return false; 34081ad6265SDimitry Andric return true; 34181ad6265SDimitry Andric } 34281ad6265SDimitry Andric 34381ad6265SDimitry Andric /// Return the fields and properties demanded by the provided instruction. 34406c3fb27SDimitry Andric DemandedFields getDemanded(const MachineInstr &MI, 3455f757f3fSDimitry Andric const MachineRegisterInfo *MRI, 3465f757f3fSDimitry Andric const RISCVSubtarget *ST) { 34781ad6265SDimitry Andric // Warning: This function has to work on both the lowered (i.e. post 34881ad6265SDimitry Andric // emitVSETVLIs) and pre-lowering forms. The main implication of this is 34981ad6265SDimitry Andric // that it can't use the value of a SEW, VL, or Policy operand as they might 35081ad6265SDimitry Andric // be stale after lowering. 35181ad6265SDimitry Andric 35281ad6265SDimitry Andric // Most instructions don't use any of these subfeilds. 35381ad6265SDimitry Andric DemandedFields Res; 35481ad6265SDimitry Andric // Start conservative if registers are used 35581ad6265SDimitry Andric if (MI.isCall() || MI.isInlineAsm() || MI.readsRegister(RISCV::VL)) 35606c3fb27SDimitry Andric Res.demandVL(); 35781ad6265SDimitry Andric if (MI.isCall() || MI.isInlineAsm() || MI.readsRegister(RISCV::VTYPE)) 35881ad6265SDimitry Andric Res.demandVTYPE(); 35981ad6265SDimitry Andric // Start conservative on the unlowered form too 36081ad6265SDimitry Andric uint64_t TSFlags = MI.getDesc().TSFlags; 36181ad6265SDimitry Andric if (RISCVII::hasSEWOp(TSFlags)) { 36281ad6265SDimitry Andric Res.demandVTYPE(); 36381ad6265SDimitry Andric if (RISCVII::hasVLOp(TSFlags)) 364bdd1243dSDimitry Andric Res.demandVL(); 365bdd1243dSDimitry Andric 366bdd1243dSDimitry Andric // Behavior is independent of mask policy. 367bdd1243dSDimitry Andric if (!RISCVII::usesMaskPolicy(TSFlags)) 368bdd1243dSDimitry Andric Res.MaskPolicy = false; 36981ad6265SDimitry Andric } 37081ad6265SDimitry Andric 37181ad6265SDimitry Andric // Loads and stores with implicit EEW do not demand SEW or LMUL directly. 37281ad6265SDimitry Andric // They instead demand the ratio of the two which is used in computing 37381ad6265SDimitry Andric // EMUL, but which allows us the flexibility to change SEW and LMUL 37481ad6265SDimitry Andric // provided we don't change the ratio. 37581ad6265SDimitry Andric // Note: We assume that the instructions initial SEW is the EEW encoded 37681ad6265SDimitry Andric // in the opcode. This is asserted when constructing the VSETVLIInfo. 37781ad6265SDimitry Andric if (getEEWForLoadStore(MI)) { 37806c3fb27SDimitry Andric Res.SEW = DemandedFields::SEWNone; 37981ad6265SDimitry Andric Res.LMUL = false; 38081ad6265SDimitry Andric } 38181ad6265SDimitry Andric 38281ad6265SDimitry Andric // Store instructions don't use the policy fields. 38381ad6265SDimitry Andric if (RISCVII::hasSEWOp(TSFlags) && MI.getNumExplicitDefs() == 0) { 38481ad6265SDimitry Andric Res.TailPolicy = false; 38581ad6265SDimitry Andric Res.MaskPolicy = false; 38681ad6265SDimitry Andric } 38781ad6265SDimitry Andric 38881ad6265SDimitry Andric // If this is a mask reg operation, it only cares about VLMAX. 38981ad6265SDimitry Andric // TODO: Possible extensions to this logic 39081ad6265SDimitry Andric // * Probably ok if available VLMax is larger than demanded 39181ad6265SDimitry Andric // * The policy bits can probably be ignored.. 39281ad6265SDimitry Andric if (isMaskRegOp(MI)) { 39306c3fb27SDimitry Andric Res.SEW = DemandedFields::SEWNone; 39481ad6265SDimitry Andric Res.LMUL = false; 39581ad6265SDimitry Andric } 39681ad6265SDimitry Andric 397bdd1243dSDimitry Andric // For vmv.s.x and vfmv.s.f, there are only two behaviors, VL = 0 and VL > 0. 3985f757f3fSDimitry Andric if (isScalarInsertInstr(MI)) { 399bdd1243dSDimitry Andric Res.LMUL = false; 400bdd1243dSDimitry Andric Res.SEWLMULRatio = false; 401bdd1243dSDimitry Andric Res.VLAny = false; 40206c3fb27SDimitry Andric // For vmv.s.x and vfmv.s.f, if the merge operand is *undefined*, we don't 40306c3fb27SDimitry Andric // need to preserve any other bits and are thus compatible with any larger, 40406c3fb27SDimitry Andric // etype and can disregard policy bits. Warning: It's tempting to try doing 40506c3fb27SDimitry Andric // this for any tail agnostic operation, but we can't as TA requires 40606c3fb27SDimitry Andric // tail lanes to either be the original value or -1. We are writing 40706c3fb27SDimitry Andric // unknown bits to the lanes here. 40806c3fb27SDimitry Andric if (hasUndefinedMergeOp(MI, *MRI)) { 4095f757f3fSDimitry Andric if (isFloatScalarMoveOrScalarSplatInstr(MI) && !ST->hasVInstructionsF64()) 4105f757f3fSDimitry Andric Res.SEW = DemandedFields::SEWGreaterThanOrEqualAndLessThan64; 4115f757f3fSDimitry Andric else 41206c3fb27SDimitry Andric Res.SEW = DemandedFields::SEWGreaterThanOrEqual; 41306c3fb27SDimitry Andric Res.TailPolicy = false; 41406c3fb27SDimitry Andric } 415bdd1243dSDimitry Andric } 416bdd1243dSDimitry Andric 4175f757f3fSDimitry Andric // vmv.x.s, and vmv.f.s are unconditional and ignore everything except SEW. 4185f757f3fSDimitry Andric if (isScalarExtractInstr(MI)) { 4195f757f3fSDimitry Andric assert(!RISCVII::hasVLOp(TSFlags)); 4205f757f3fSDimitry Andric Res.LMUL = false; 4215f757f3fSDimitry Andric Res.SEWLMULRatio = false; 4225f757f3fSDimitry Andric Res.TailPolicy = false; 4235f757f3fSDimitry Andric Res.MaskPolicy = false; 4245f757f3fSDimitry Andric } 4255f757f3fSDimitry Andric 42681ad6265SDimitry Andric return Res; 42781ad6265SDimitry Andric } 42881ad6265SDimitry Andric 42981ad6265SDimitry Andric /// Defines the abstract state with which the forward dataflow models the 43081ad6265SDimitry Andric /// values of the VL and VTYPE registers after insertion. 43181ad6265SDimitry Andric class VSETVLIInfo { 43281ad6265SDimitry Andric union { 43381ad6265SDimitry Andric Register AVLReg; 43481ad6265SDimitry Andric unsigned AVLImm; 43581ad6265SDimitry Andric }; 43681ad6265SDimitry Andric 43781ad6265SDimitry Andric enum : uint8_t { 43881ad6265SDimitry Andric Uninitialized, 43981ad6265SDimitry Andric AVLIsReg, 44081ad6265SDimitry Andric AVLIsImm, 44181ad6265SDimitry Andric Unknown, 44281ad6265SDimitry Andric } State = Uninitialized; 44381ad6265SDimitry Andric 44481ad6265SDimitry Andric // Fields from VTYPE. 44581ad6265SDimitry Andric RISCVII::VLMUL VLMul = RISCVII::LMUL_1; 44681ad6265SDimitry Andric uint8_t SEW = 0; 44781ad6265SDimitry Andric uint8_t TailAgnostic : 1; 44881ad6265SDimitry Andric uint8_t MaskAgnostic : 1; 44981ad6265SDimitry Andric uint8_t SEWLMULRatioOnly : 1; 45081ad6265SDimitry Andric 45181ad6265SDimitry Andric public: 45281ad6265SDimitry Andric VSETVLIInfo() 45381ad6265SDimitry Andric : AVLImm(0), TailAgnostic(false), MaskAgnostic(false), 45481ad6265SDimitry Andric SEWLMULRatioOnly(false) {} 45581ad6265SDimitry Andric 45681ad6265SDimitry Andric static VSETVLIInfo getUnknown() { 45781ad6265SDimitry Andric VSETVLIInfo Info; 45881ad6265SDimitry Andric Info.setUnknown(); 45981ad6265SDimitry Andric return Info; 46081ad6265SDimitry Andric } 46181ad6265SDimitry Andric 46281ad6265SDimitry Andric bool isValid() const { return State != Uninitialized; } 46381ad6265SDimitry Andric void setUnknown() { State = Unknown; } 46481ad6265SDimitry Andric bool isUnknown() const { return State == Unknown; } 46581ad6265SDimitry Andric 46681ad6265SDimitry Andric void setAVLReg(Register Reg) { 46781ad6265SDimitry Andric AVLReg = Reg; 46881ad6265SDimitry Andric State = AVLIsReg; 46981ad6265SDimitry Andric } 47081ad6265SDimitry Andric 47181ad6265SDimitry Andric void setAVLImm(unsigned Imm) { 47281ad6265SDimitry Andric AVLImm = Imm; 47381ad6265SDimitry Andric State = AVLIsImm; 47481ad6265SDimitry Andric } 47581ad6265SDimitry Andric 47681ad6265SDimitry Andric bool hasAVLImm() const { return State == AVLIsImm; } 47781ad6265SDimitry Andric bool hasAVLReg() const { return State == AVLIsReg; } 47881ad6265SDimitry Andric Register getAVLReg() const { 47981ad6265SDimitry Andric assert(hasAVLReg()); 48081ad6265SDimitry Andric return AVLReg; 48181ad6265SDimitry Andric } 48281ad6265SDimitry Andric unsigned getAVLImm() const { 48381ad6265SDimitry Andric assert(hasAVLImm()); 48481ad6265SDimitry Andric return AVLImm; 48581ad6265SDimitry Andric } 48681ad6265SDimitry Andric 4875f757f3fSDimitry Andric void setAVL(VSETVLIInfo Info) { 4885f757f3fSDimitry Andric assert(Info.isValid()); 4895f757f3fSDimitry Andric if (Info.isUnknown()) 4905f757f3fSDimitry Andric setUnknown(); 4915f757f3fSDimitry Andric else if (Info.hasAVLReg()) 4925f757f3fSDimitry Andric setAVLReg(Info.getAVLReg()); 4935f757f3fSDimitry Andric else { 4945f757f3fSDimitry Andric assert(Info.hasAVLImm()); 4955f757f3fSDimitry Andric setAVLImm(Info.getAVLImm()); 4965f757f3fSDimitry Andric } 4975f757f3fSDimitry Andric } 4985f757f3fSDimitry Andric 49981ad6265SDimitry Andric unsigned getSEW() const { return SEW; } 50081ad6265SDimitry Andric RISCVII::VLMUL getVLMUL() const { return VLMul; } 5015f757f3fSDimitry Andric bool getTailAgnostic() const { return TailAgnostic; } 5025f757f3fSDimitry Andric bool getMaskAgnostic() const { return MaskAgnostic; } 50381ad6265SDimitry Andric 50406c3fb27SDimitry Andric bool hasNonZeroAVL(const MachineRegisterInfo &MRI) const { 50581ad6265SDimitry Andric if (hasAVLImm()) 50681ad6265SDimitry Andric return getAVLImm() > 0; 50706c3fb27SDimitry Andric if (hasAVLReg()) { 50806c3fb27SDimitry Andric if (getAVLReg() == RISCV::X0) 50906c3fb27SDimitry Andric return true; 51006c3fb27SDimitry Andric if (MachineInstr *MI = MRI.getVRegDef(getAVLReg()); 5115f757f3fSDimitry Andric MI && isNonZeroLoadImmediate(*MI)) 51206c3fb27SDimitry Andric return true; 51306c3fb27SDimitry Andric return false; 51406c3fb27SDimitry Andric } 51581ad6265SDimitry Andric return false; 51681ad6265SDimitry Andric } 51781ad6265SDimitry Andric 51806c3fb27SDimitry Andric bool hasEquallyZeroAVL(const VSETVLIInfo &Other, 51906c3fb27SDimitry Andric const MachineRegisterInfo &MRI) const { 520bdd1243dSDimitry Andric if (hasSameAVL(Other)) 521bdd1243dSDimitry Andric return true; 52206c3fb27SDimitry Andric return (hasNonZeroAVL(MRI) && Other.hasNonZeroAVL(MRI)); 523bdd1243dSDimitry Andric } 524bdd1243dSDimitry Andric 52581ad6265SDimitry Andric bool hasSameAVL(const VSETVLIInfo &Other) const { 52681ad6265SDimitry Andric if (hasAVLReg() && Other.hasAVLReg()) 52781ad6265SDimitry Andric return getAVLReg() == Other.getAVLReg(); 52881ad6265SDimitry Andric 52981ad6265SDimitry Andric if (hasAVLImm() && Other.hasAVLImm()) 53081ad6265SDimitry Andric return getAVLImm() == Other.getAVLImm(); 53181ad6265SDimitry Andric 53281ad6265SDimitry Andric return false; 53381ad6265SDimitry Andric } 53481ad6265SDimitry Andric 53581ad6265SDimitry Andric void setVTYPE(unsigned VType) { 53681ad6265SDimitry Andric assert(isValid() && !isUnknown() && 53781ad6265SDimitry Andric "Can't set VTYPE for uninitialized or unknown"); 53881ad6265SDimitry Andric VLMul = RISCVVType::getVLMUL(VType); 53981ad6265SDimitry Andric SEW = RISCVVType::getSEW(VType); 54081ad6265SDimitry Andric TailAgnostic = RISCVVType::isTailAgnostic(VType); 54181ad6265SDimitry Andric MaskAgnostic = RISCVVType::isMaskAgnostic(VType); 54281ad6265SDimitry Andric } 54381ad6265SDimitry Andric void setVTYPE(RISCVII::VLMUL L, unsigned S, bool TA, bool MA) { 54481ad6265SDimitry Andric assert(isValid() && !isUnknown() && 54581ad6265SDimitry Andric "Can't set VTYPE for uninitialized or unknown"); 54681ad6265SDimitry Andric VLMul = L; 54781ad6265SDimitry Andric SEW = S; 54881ad6265SDimitry Andric TailAgnostic = TA; 54981ad6265SDimitry Andric MaskAgnostic = MA; 55081ad6265SDimitry Andric } 55181ad6265SDimitry Andric 5525f757f3fSDimitry Andric void setVLMul(RISCVII::VLMUL VLMul) { this->VLMul = VLMul; } 5535f757f3fSDimitry Andric 55481ad6265SDimitry Andric unsigned encodeVTYPE() const { 55581ad6265SDimitry Andric assert(isValid() && !isUnknown() && !SEWLMULRatioOnly && 55681ad6265SDimitry Andric "Can't encode VTYPE for uninitialized or unknown"); 55781ad6265SDimitry Andric return RISCVVType::encodeVTYPE(VLMul, SEW, TailAgnostic, MaskAgnostic); 55881ad6265SDimitry Andric } 55981ad6265SDimitry Andric 56081ad6265SDimitry Andric bool hasSEWLMULRatioOnly() const { return SEWLMULRatioOnly; } 56181ad6265SDimitry Andric 56281ad6265SDimitry Andric bool hasSameVTYPE(const VSETVLIInfo &Other) const { 56381ad6265SDimitry Andric assert(isValid() && Other.isValid() && 56481ad6265SDimitry Andric "Can't compare invalid VSETVLIInfos"); 56581ad6265SDimitry Andric assert(!isUnknown() && !Other.isUnknown() && 56681ad6265SDimitry Andric "Can't compare VTYPE in unknown state"); 56781ad6265SDimitry Andric assert(!SEWLMULRatioOnly && !Other.SEWLMULRatioOnly && 56881ad6265SDimitry Andric "Can't compare when only LMUL/SEW ratio is valid."); 56981ad6265SDimitry Andric return std::tie(VLMul, SEW, TailAgnostic, MaskAgnostic) == 57081ad6265SDimitry Andric std::tie(Other.VLMul, Other.SEW, Other.TailAgnostic, 57181ad6265SDimitry Andric Other.MaskAgnostic); 57281ad6265SDimitry Andric } 57381ad6265SDimitry Andric 57481ad6265SDimitry Andric unsigned getSEWLMULRatio() const { 57581ad6265SDimitry Andric assert(isValid() && !isUnknown() && 57681ad6265SDimitry Andric "Can't use VTYPE for uninitialized or unknown"); 577bdd1243dSDimitry Andric return RISCVVType::getSEWLMULRatio(SEW, VLMul); 57881ad6265SDimitry Andric } 57981ad6265SDimitry Andric 58081ad6265SDimitry Andric // Check if the VTYPE for these two VSETVLIInfos produce the same VLMAX. 58181ad6265SDimitry Andric // Note that having the same VLMAX ensures that both share the same 58281ad6265SDimitry Andric // function from AVL to VL; that is, they must produce the same VL value 58381ad6265SDimitry Andric // for any given AVL value. 58481ad6265SDimitry Andric bool hasSameVLMAX(const VSETVLIInfo &Other) const { 58581ad6265SDimitry Andric assert(isValid() && Other.isValid() && 58681ad6265SDimitry Andric "Can't compare invalid VSETVLIInfos"); 58781ad6265SDimitry Andric assert(!isUnknown() && !Other.isUnknown() && 58881ad6265SDimitry Andric "Can't compare VTYPE in unknown state"); 58981ad6265SDimitry Andric return getSEWLMULRatio() == Other.getSEWLMULRatio(); 59081ad6265SDimitry Andric } 59181ad6265SDimitry Andric 592bdd1243dSDimitry Andric bool hasCompatibleVTYPE(const DemandedFields &Used, 59381ad6265SDimitry Andric const VSETVLIInfo &Require) const { 59406c3fb27SDimitry Andric return areCompatibleVTYPEs(Require.encodeVTYPE(), encodeVTYPE(), Used); 59581ad6265SDimitry Andric } 59681ad6265SDimitry Andric 59781ad6265SDimitry Andric // Determine whether the vector instructions requirements represented by 59881ad6265SDimitry Andric // Require are compatible with the previous vsetvli instruction represented 59981ad6265SDimitry Andric // by this. MI is the instruction whose requirements we're considering. 60006c3fb27SDimitry Andric bool isCompatible(const DemandedFields &Used, const VSETVLIInfo &Require, 60106c3fb27SDimitry Andric const MachineRegisterInfo &MRI) const { 60281ad6265SDimitry Andric assert(isValid() && Require.isValid() && 60381ad6265SDimitry Andric "Can't compare invalid VSETVLIInfos"); 60481ad6265SDimitry Andric assert(!Require.SEWLMULRatioOnly && 60581ad6265SDimitry Andric "Expected a valid VTYPE for instruction!"); 60681ad6265SDimitry Andric // Nothing is compatible with Unknown. 60781ad6265SDimitry Andric if (isUnknown() || Require.isUnknown()) 60881ad6265SDimitry Andric return false; 60981ad6265SDimitry Andric 61081ad6265SDimitry Andric // If only our VLMAX ratio is valid, then this isn't compatible. 61181ad6265SDimitry Andric if (SEWLMULRatioOnly) 61281ad6265SDimitry Andric return false; 61381ad6265SDimitry Andric 614bdd1243dSDimitry Andric if (Used.VLAny && !hasSameAVL(Require)) 615bdd1243dSDimitry Andric return false; 616bdd1243dSDimitry Andric 61706c3fb27SDimitry Andric if (Used.VLZeroness && !hasEquallyZeroAVL(Require, MRI)) 618bdd1243dSDimitry Andric return false; 619bdd1243dSDimitry Andric 62006c3fb27SDimitry Andric return hasCompatibleVTYPE(Used, Require); 62181ad6265SDimitry Andric } 62281ad6265SDimitry Andric 62381ad6265SDimitry Andric bool operator==(const VSETVLIInfo &Other) const { 62481ad6265SDimitry Andric // Uninitialized is only equal to another Uninitialized. 62581ad6265SDimitry Andric if (!isValid()) 62681ad6265SDimitry Andric return !Other.isValid(); 62781ad6265SDimitry Andric if (!Other.isValid()) 62881ad6265SDimitry Andric return !isValid(); 62981ad6265SDimitry Andric 63081ad6265SDimitry Andric // Unknown is only equal to another Unknown. 63181ad6265SDimitry Andric if (isUnknown()) 63281ad6265SDimitry Andric return Other.isUnknown(); 63381ad6265SDimitry Andric if (Other.isUnknown()) 63481ad6265SDimitry Andric return isUnknown(); 63581ad6265SDimitry Andric 63681ad6265SDimitry Andric if (!hasSameAVL(Other)) 63781ad6265SDimitry Andric return false; 63881ad6265SDimitry Andric 63981ad6265SDimitry Andric // If the SEWLMULRatioOnly bits are different, then they aren't equal. 64081ad6265SDimitry Andric if (SEWLMULRatioOnly != Other.SEWLMULRatioOnly) 64181ad6265SDimitry Andric return false; 64281ad6265SDimitry Andric 64381ad6265SDimitry Andric // If only the VLMAX is valid, check that it is the same. 64481ad6265SDimitry Andric if (SEWLMULRatioOnly) 64581ad6265SDimitry Andric return hasSameVLMAX(Other); 64681ad6265SDimitry Andric 64781ad6265SDimitry Andric // If the full VTYPE is valid, check that it is the same. 64881ad6265SDimitry Andric return hasSameVTYPE(Other); 64981ad6265SDimitry Andric } 65081ad6265SDimitry Andric 65181ad6265SDimitry Andric bool operator!=(const VSETVLIInfo &Other) const { 65281ad6265SDimitry Andric return !(*this == Other); 65381ad6265SDimitry Andric } 65481ad6265SDimitry Andric 65581ad6265SDimitry Andric // Calculate the VSETVLIInfo visible to a block assuming this and Other are 65681ad6265SDimitry Andric // both predecessors. 65781ad6265SDimitry Andric VSETVLIInfo intersect(const VSETVLIInfo &Other) const { 65881ad6265SDimitry Andric // If the new value isn't valid, ignore it. 65981ad6265SDimitry Andric if (!Other.isValid()) 66081ad6265SDimitry Andric return *this; 66181ad6265SDimitry Andric 66281ad6265SDimitry Andric // If this value isn't valid, this must be the first predecessor, use it. 66381ad6265SDimitry Andric if (!isValid()) 66481ad6265SDimitry Andric return Other; 66581ad6265SDimitry Andric 66681ad6265SDimitry Andric // If either is unknown, the result is unknown. 66781ad6265SDimitry Andric if (isUnknown() || Other.isUnknown()) 66881ad6265SDimitry Andric return VSETVLIInfo::getUnknown(); 66981ad6265SDimitry Andric 67081ad6265SDimitry Andric // If we have an exact, match return this. 67181ad6265SDimitry Andric if (*this == Other) 67281ad6265SDimitry Andric return *this; 67381ad6265SDimitry Andric 67481ad6265SDimitry Andric // Not an exact match, but maybe the AVL and VLMAX are the same. If so, 67581ad6265SDimitry Andric // return an SEW/LMUL ratio only value. 67681ad6265SDimitry Andric if (hasSameAVL(Other) && hasSameVLMAX(Other)) { 67781ad6265SDimitry Andric VSETVLIInfo MergeInfo = *this; 67881ad6265SDimitry Andric MergeInfo.SEWLMULRatioOnly = true; 67981ad6265SDimitry Andric return MergeInfo; 68081ad6265SDimitry Andric } 68181ad6265SDimitry Andric 68281ad6265SDimitry Andric // Otherwise the result is unknown. 68381ad6265SDimitry Andric return VSETVLIInfo::getUnknown(); 68481ad6265SDimitry Andric } 68581ad6265SDimitry Andric 68681ad6265SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 68781ad6265SDimitry Andric /// Support for debugging, callable in GDB: V->dump() 68881ad6265SDimitry Andric LLVM_DUMP_METHOD void dump() const { 68981ad6265SDimitry Andric print(dbgs()); 69081ad6265SDimitry Andric dbgs() << "\n"; 69181ad6265SDimitry Andric } 69281ad6265SDimitry Andric 69381ad6265SDimitry Andric /// Implement operator<<. 69481ad6265SDimitry Andric /// @{ 69581ad6265SDimitry Andric void print(raw_ostream &OS) const { 69681ad6265SDimitry Andric OS << "{"; 69781ad6265SDimitry Andric if (!isValid()) 69881ad6265SDimitry Andric OS << "Uninitialized"; 69981ad6265SDimitry Andric if (isUnknown()) 70081ad6265SDimitry Andric OS << "unknown"; 70181ad6265SDimitry Andric if (hasAVLReg()) 70281ad6265SDimitry Andric OS << "AVLReg=" << (unsigned)AVLReg; 70381ad6265SDimitry Andric if (hasAVLImm()) 70481ad6265SDimitry Andric OS << "AVLImm=" << (unsigned)AVLImm; 70581ad6265SDimitry Andric OS << ", " 70681ad6265SDimitry Andric << "VLMul=" << (unsigned)VLMul << ", " 70781ad6265SDimitry Andric << "SEW=" << (unsigned)SEW << ", " 70881ad6265SDimitry Andric << "TailAgnostic=" << (bool)TailAgnostic << ", " 70981ad6265SDimitry Andric << "MaskAgnostic=" << (bool)MaskAgnostic << ", " 71081ad6265SDimitry Andric << "SEWLMULRatioOnly=" << (bool)SEWLMULRatioOnly << "}"; 71181ad6265SDimitry Andric } 71281ad6265SDimitry Andric #endif 71381ad6265SDimitry Andric }; 71481ad6265SDimitry Andric 71581ad6265SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 71681ad6265SDimitry Andric LLVM_ATTRIBUTE_USED 71781ad6265SDimitry Andric inline raw_ostream &operator<<(raw_ostream &OS, const VSETVLIInfo &V) { 71881ad6265SDimitry Andric V.print(OS); 71981ad6265SDimitry Andric return OS; 72081ad6265SDimitry Andric } 72181ad6265SDimitry Andric #endif 72281ad6265SDimitry Andric 72381ad6265SDimitry Andric struct BlockData { 72481ad6265SDimitry Andric // The VSETVLIInfo that represents the VL/VTYPE settings on exit from this 72581ad6265SDimitry Andric // block. Calculated in Phase 2. 72681ad6265SDimitry Andric VSETVLIInfo Exit; 72781ad6265SDimitry Andric 72881ad6265SDimitry Andric // The VSETVLIInfo that represents the VL/VTYPE settings from all predecessor 72981ad6265SDimitry Andric // blocks. Calculated in Phase 2, and used by Phase 3. 73081ad6265SDimitry Andric VSETVLIInfo Pred; 73181ad6265SDimitry Andric 73281ad6265SDimitry Andric // Keeps track of whether the block is already in the queue. 73381ad6265SDimitry Andric bool InQueue = false; 73481ad6265SDimitry Andric 73581ad6265SDimitry Andric BlockData() = default; 73681ad6265SDimitry Andric }; 73781ad6265SDimitry Andric 73881ad6265SDimitry Andric class RISCVInsertVSETVLI : public MachineFunctionPass { 7395f757f3fSDimitry Andric const RISCVSubtarget *ST; 74081ad6265SDimitry Andric const TargetInstrInfo *TII; 74181ad6265SDimitry Andric MachineRegisterInfo *MRI; 74281ad6265SDimitry Andric 74381ad6265SDimitry Andric std::vector<BlockData> BlockInfo; 74481ad6265SDimitry Andric std::queue<const MachineBasicBlock *> WorkList; 74581ad6265SDimitry Andric 74681ad6265SDimitry Andric public: 74781ad6265SDimitry Andric static char ID; 74881ad6265SDimitry Andric 7495f757f3fSDimitry Andric RISCVInsertVSETVLI() : MachineFunctionPass(ID) {} 75081ad6265SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 75181ad6265SDimitry Andric 75281ad6265SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 75381ad6265SDimitry Andric AU.setPreservesCFG(); 75481ad6265SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 75581ad6265SDimitry Andric } 75681ad6265SDimitry Andric 75781ad6265SDimitry Andric StringRef getPassName() const override { return RISCV_INSERT_VSETVLI_NAME; } 75881ad6265SDimitry Andric 75981ad6265SDimitry Andric private: 76081ad6265SDimitry Andric bool needVSETVLI(const MachineInstr &MI, const VSETVLIInfo &Require, 76181ad6265SDimitry Andric const VSETVLIInfo &CurInfo) const; 76281ad6265SDimitry Andric bool needVSETVLIPHI(const VSETVLIInfo &Require, 76381ad6265SDimitry Andric const MachineBasicBlock &MBB) const; 76481ad6265SDimitry Andric void insertVSETVLI(MachineBasicBlock &MBB, MachineInstr &MI, 76581ad6265SDimitry Andric const VSETVLIInfo &Info, const VSETVLIInfo &PrevInfo); 76681ad6265SDimitry Andric void insertVSETVLI(MachineBasicBlock &MBB, 76781ad6265SDimitry Andric MachineBasicBlock::iterator InsertPt, DebugLoc DL, 76881ad6265SDimitry Andric const VSETVLIInfo &Info, const VSETVLIInfo &PrevInfo); 76981ad6265SDimitry Andric 7705f757f3fSDimitry Andric void transferBefore(VSETVLIInfo &Info, const MachineInstr &MI) const; 7715f757f3fSDimitry Andric void transferAfter(VSETVLIInfo &Info, const MachineInstr &MI) const; 7725f757f3fSDimitry Andric bool computeVLVTYPEChanges(const MachineBasicBlock &MBB, 7735f757f3fSDimitry Andric VSETVLIInfo &Info) const; 77481ad6265SDimitry Andric void computeIncomingVLVTYPE(const MachineBasicBlock &MBB); 77581ad6265SDimitry Andric void emitVSETVLIs(MachineBasicBlock &MBB); 77681ad6265SDimitry Andric void doLocalPostpass(MachineBasicBlock &MBB); 77781ad6265SDimitry Andric void doPRE(MachineBasicBlock &MBB); 77881ad6265SDimitry Andric void insertReadVL(MachineBasicBlock &MBB); 77981ad6265SDimitry Andric }; 78081ad6265SDimitry Andric 78181ad6265SDimitry Andric } // end anonymous namespace 78281ad6265SDimitry Andric 78381ad6265SDimitry Andric char RISCVInsertVSETVLI::ID = 0; 78481ad6265SDimitry Andric 78581ad6265SDimitry Andric INITIALIZE_PASS(RISCVInsertVSETVLI, DEBUG_TYPE, RISCV_INSERT_VSETVLI_NAME, 78681ad6265SDimitry Andric false, false) 78781ad6265SDimitry Andric 7885f757f3fSDimitry Andric // Return a VSETVLIInfo representing the changes made by this VSETVLI or 7895f757f3fSDimitry Andric // VSETIVLI instruction. 7905f757f3fSDimitry Andric static VSETVLIInfo getInfoForVSETVLI(const MachineInstr &MI) { 7915f757f3fSDimitry Andric VSETVLIInfo NewInfo; 7925f757f3fSDimitry Andric if (MI.getOpcode() == RISCV::PseudoVSETIVLI) { 7935f757f3fSDimitry Andric NewInfo.setAVLImm(MI.getOperand(1).getImm()); 7945f757f3fSDimitry Andric } else { 7955f757f3fSDimitry Andric assert(MI.getOpcode() == RISCV::PseudoVSETVLI || 7965f757f3fSDimitry Andric MI.getOpcode() == RISCV::PseudoVSETVLIX0); 7975f757f3fSDimitry Andric Register AVLReg = MI.getOperand(1).getReg(); 7985f757f3fSDimitry Andric assert((AVLReg != RISCV::X0 || MI.getOperand(0).getReg() != RISCV::X0) && 7995f757f3fSDimitry Andric "Can't handle X0, X0 vsetvli yet"); 8005f757f3fSDimitry Andric NewInfo.setAVLReg(AVLReg); 8015f757f3fSDimitry Andric } 8025f757f3fSDimitry Andric NewInfo.setVTYPE(MI.getOperand(2).getImm()); 8035f757f3fSDimitry Andric 8045f757f3fSDimitry Andric return NewInfo; 8055f757f3fSDimitry Andric } 8065f757f3fSDimitry Andric 80781ad6265SDimitry Andric static VSETVLIInfo computeInfoForInstr(const MachineInstr &MI, uint64_t TSFlags, 80881ad6265SDimitry Andric const MachineRegisterInfo *MRI) { 80981ad6265SDimitry Andric VSETVLIInfo InstrInfo; 81081ad6265SDimitry Andric 81106c3fb27SDimitry Andric bool TailAgnostic = true; 81206c3fb27SDimitry Andric bool MaskAgnostic = true; 81306c3fb27SDimitry Andric if (!hasUndefinedMergeOp(MI, *MRI)) { 814bdd1243dSDimitry Andric // Start with undisturbed. 815bdd1243dSDimitry Andric TailAgnostic = false; 816bdd1243dSDimitry Andric MaskAgnostic = false; 817bdd1243dSDimitry Andric 818bdd1243dSDimitry Andric // If there is a policy operand, use it. 81981ad6265SDimitry Andric if (RISCVII::hasVecPolicyOp(TSFlags)) { 82081ad6265SDimitry Andric const MachineOperand &Op = MI.getOperand(MI.getNumExplicitOperands() - 1); 82181ad6265SDimitry Andric uint64_t Policy = Op.getImm(); 82281ad6265SDimitry Andric assert(Policy <= (RISCVII::TAIL_AGNOSTIC | RISCVII::MASK_AGNOSTIC) && 82381ad6265SDimitry Andric "Invalid Policy Value"); 82481ad6265SDimitry Andric TailAgnostic = Policy & RISCVII::TAIL_AGNOSTIC; 82581ad6265SDimitry Andric MaskAgnostic = Policy & RISCVII::MASK_AGNOSTIC; 826bdd1243dSDimitry Andric } 827bdd1243dSDimitry Andric 82881ad6265SDimitry Andric // Some pseudo instructions force a tail agnostic policy despite having a 82981ad6265SDimitry Andric // tied def. 83081ad6265SDimitry Andric if (RISCVII::doesForceTailAgnostic(TSFlags)) 83181ad6265SDimitry Andric TailAgnostic = true; 832bdd1243dSDimitry Andric 833bdd1243dSDimitry Andric if (!RISCVII::usesMaskPolicy(TSFlags)) 834bdd1243dSDimitry Andric MaskAgnostic = true; 83581ad6265SDimitry Andric } 83681ad6265SDimitry Andric 83781ad6265SDimitry Andric RISCVII::VLMUL VLMul = RISCVII::getLMul(TSFlags); 83881ad6265SDimitry Andric 83981ad6265SDimitry Andric unsigned Log2SEW = MI.getOperand(getSEWOpNum(MI)).getImm(); 84081ad6265SDimitry Andric // A Log2SEW of 0 is an operation on mask registers only. 84181ad6265SDimitry Andric unsigned SEW = Log2SEW ? 1 << Log2SEW : 8; 84281ad6265SDimitry Andric assert(RISCVVType::isValidSEW(SEW) && "Unexpected SEW"); 84381ad6265SDimitry Andric 84481ad6265SDimitry Andric if (RISCVII::hasVLOp(TSFlags)) { 84581ad6265SDimitry Andric const MachineOperand &VLOp = MI.getOperand(getVLOpNum(MI)); 84681ad6265SDimitry Andric if (VLOp.isImm()) { 84781ad6265SDimitry Andric int64_t Imm = VLOp.getImm(); 84881ad6265SDimitry Andric // Conver the VLMax sentintel to X0 register. 84981ad6265SDimitry Andric if (Imm == RISCV::VLMaxSentinel) 85081ad6265SDimitry Andric InstrInfo.setAVLReg(RISCV::X0); 85181ad6265SDimitry Andric else 85281ad6265SDimitry Andric InstrInfo.setAVLImm(Imm); 85381ad6265SDimitry Andric } else { 85481ad6265SDimitry Andric InstrInfo.setAVLReg(VLOp.getReg()); 85581ad6265SDimitry Andric } 85681ad6265SDimitry Andric } else { 8575f757f3fSDimitry Andric assert(isScalarExtractInstr(MI)); 85881ad6265SDimitry Andric InstrInfo.setAVLReg(RISCV::NoRegister); 85981ad6265SDimitry Andric } 86081ad6265SDimitry Andric #ifndef NDEBUG 861bdd1243dSDimitry Andric if (std::optional<unsigned> EEW = getEEWForLoadStore(MI)) { 86281ad6265SDimitry Andric assert(SEW == EEW && "Initial SEW doesn't match expected EEW"); 86381ad6265SDimitry Andric } 86481ad6265SDimitry Andric #endif 86581ad6265SDimitry Andric InstrInfo.setVTYPE(VLMul, SEW, TailAgnostic, MaskAgnostic); 86681ad6265SDimitry Andric 8675f757f3fSDimitry Andric // If AVL is defined by a vsetvli with the same VLMAX, we can replace the 8685f757f3fSDimitry Andric // AVL operand with the AVL of the defining vsetvli. We avoid general 8695f757f3fSDimitry Andric // register AVLs to avoid extending live ranges without being sure we can 8705f757f3fSDimitry Andric // kill the original source reg entirely. 8715f757f3fSDimitry Andric if (InstrInfo.hasAVLReg() && InstrInfo.getAVLReg().isVirtual()) { 8725f757f3fSDimitry Andric MachineInstr *DefMI = MRI->getVRegDef(InstrInfo.getAVLReg()); 8735f757f3fSDimitry Andric if (DefMI && isVectorConfigInstr(*DefMI)) { 8745f757f3fSDimitry Andric VSETVLIInfo DefInstrInfo = getInfoForVSETVLI(*DefMI); 8755f757f3fSDimitry Andric if (DefInstrInfo.hasSameVLMAX(InstrInfo) && 8765f757f3fSDimitry Andric (DefInstrInfo.hasAVLImm() || DefInstrInfo.getAVLReg() == RISCV::X0)) { 8775f757f3fSDimitry Andric InstrInfo.setAVL(DefInstrInfo); 8785f757f3fSDimitry Andric } 8795f757f3fSDimitry Andric } 8805f757f3fSDimitry Andric } 8815f757f3fSDimitry Andric 88281ad6265SDimitry Andric return InstrInfo; 88381ad6265SDimitry Andric } 88481ad6265SDimitry Andric 88581ad6265SDimitry Andric void RISCVInsertVSETVLI::insertVSETVLI(MachineBasicBlock &MBB, MachineInstr &MI, 88681ad6265SDimitry Andric const VSETVLIInfo &Info, 88781ad6265SDimitry Andric const VSETVLIInfo &PrevInfo) { 88881ad6265SDimitry Andric DebugLoc DL = MI.getDebugLoc(); 88981ad6265SDimitry Andric insertVSETVLI(MBB, MachineBasicBlock::iterator(&MI), DL, Info, PrevInfo); 89081ad6265SDimitry Andric } 89181ad6265SDimitry Andric 89281ad6265SDimitry Andric void RISCVInsertVSETVLI::insertVSETVLI(MachineBasicBlock &MBB, 89381ad6265SDimitry Andric MachineBasicBlock::iterator InsertPt, DebugLoc DL, 89481ad6265SDimitry Andric const VSETVLIInfo &Info, const VSETVLIInfo &PrevInfo) { 89581ad6265SDimitry Andric 89606c3fb27SDimitry Andric if (PrevInfo.isValid() && !PrevInfo.isUnknown()) { 89781ad6265SDimitry Andric // Use X0, X0 form if the AVL is the same and the SEW+LMUL gives the same 89881ad6265SDimitry Andric // VLMAX. 89906c3fb27SDimitry Andric if (Info.hasSameAVL(PrevInfo) && Info.hasSameVLMAX(PrevInfo)) { 90081ad6265SDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETVLIX0)) 90181ad6265SDimitry Andric .addReg(RISCV::X0, RegState::Define | RegState::Dead) 90281ad6265SDimitry Andric .addReg(RISCV::X0, RegState::Kill) 90381ad6265SDimitry Andric .addImm(Info.encodeVTYPE()) 90481ad6265SDimitry Andric .addReg(RISCV::VL, RegState::Implicit); 90581ad6265SDimitry Andric return; 90681ad6265SDimitry Andric } 90781ad6265SDimitry Andric 90806c3fb27SDimitry Andric // If our AVL is a virtual register, it might be defined by a VSET(I)VLI. If 90906c3fb27SDimitry Andric // it has the same VLMAX we want and the last VL/VTYPE we observed is the 91006c3fb27SDimitry Andric // same, we can use the X0, X0 form. 91106c3fb27SDimitry Andric if (Info.hasSameVLMAX(PrevInfo) && Info.hasAVLReg() && 91206c3fb27SDimitry Andric Info.getAVLReg().isVirtual()) { 91306c3fb27SDimitry Andric if (MachineInstr *DefMI = MRI->getVRegDef(Info.getAVLReg())) { 91406c3fb27SDimitry Andric if (isVectorConfigInstr(*DefMI)) { 91506c3fb27SDimitry Andric VSETVLIInfo DefInfo = getInfoForVSETVLI(*DefMI); 91606c3fb27SDimitry Andric if (DefInfo.hasSameAVL(PrevInfo) && DefInfo.hasSameVLMAX(PrevInfo)) { 91706c3fb27SDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETVLIX0)) 91806c3fb27SDimitry Andric .addReg(RISCV::X0, RegState::Define | RegState::Dead) 91906c3fb27SDimitry Andric .addReg(RISCV::X0, RegState::Kill) 92006c3fb27SDimitry Andric .addImm(Info.encodeVTYPE()) 92106c3fb27SDimitry Andric .addReg(RISCV::VL, RegState::Implicit); 92206c3fb27SDimitry Andric return; 92306c3fb27SDimitry Andric } 92406c3fb27SDimitry Andric } 92506c3fb27SDimitry Andric } 92606c3fb27SDimitry Andric } 92706c3fb27SDimitry Andric } 92806c3fb27SDimitry Andric 92981ad6265SDimitry Andric if (Info.hasAVLImm()) { 93081ad6265SDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETIVLI)) 93181ad6265SDimitry Andric .addReg(RISCV::X0, RegState::Define | RegState::Dead) 93281ad6265SDimitry Andric .addImm(Info.getAVLImm()) 93381ad6265SDimitry Andric .addImm(Info.encodeVTYPE()); 93481ad6265SDimitry Andric return; 93581ad6265SDimitry Andric } 93681ad6265SDimitry Andric 93781ad6265SDimitry Andric Register AVLReg = Info.getAVLReg(); 93881ad6265SDimitry Andric if (AVLReg == RISCV::NoRegister) { 93981ad6265SDimitry Andric // We can only use x0, x0 if there's no chance of the vtype change causing 94081ad6265SDimitry Andric // the previous vl to become invalid. 94181ad6265SDimitry Andric if (PrevInfo.isValid() && !PrevInfo.isUnknown() && 94281ad6265SDimitry Andric Info.hasSameVLMAX(PrevInfo)) { 94381ad6265SDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETVLIX0)) 94481ad6265SDimitry Andric .addReg(RISCV::X0, RegState::Define | RegState::Dead) 94581ad6265SDimitry Andric .addReg(RISCV::X0, RegState::Kill) 94681ad6265SDimitry Andric .addImm(Info.encodeVTYPE()) 94781ad6265SDimitry Andric .addReg(RISCV::VL, RegState::Implicit); 94881ad6265SDimitry Andric return; 94981ad6265SDimitry Andric } 9505f757f3fSDimitry Andric // Otherwise use an AVL of 1 to avoid depending on previous vl. 95181ad6265SDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETIVLI)) 95281ad6265SDimitry Andric .addReg(RISCV::X0, RegState::Define | RegState::Dead) 9535f757f3fSDimitry Andric .addImm(1) 95481ad6265SDimitry Andric .addImm(Info.encodeVTYPE()); 95581ad6265SDimitry Andric return; 95681ad6265SDimitry Andric } 95781ad6265SDimitry Andric 95881ad6265SDimitry Andric if (AVLReg.isVirtual()) 95981ad6265SDimitry Andric MRI->constrainRegClass(AVLReg, &RISCV::GPRNoX0RegClass); 96081ad6265SDimitry Andric 96181ad6265SDimitry Andric // Use X0 as the DestReg unless AVLReg is X0. We also need to change the 96281ad6265SDimitry Andric // opcode if the AVLReg is X0 as they have different register classes for 96381ad6265SDimitry Andric // the AVL operand. 96481ad6265SDimitry Andric Register DestReg = RISCV::X0; 96581ad6265SDimitry Andric unsigned Opcode = RISCV::PseudoVSETVLI; 96681ad6265SDimitry Andric if (AVLReg == RISCV::X0) { 96781ad6265SDimitry Andric DestReg = MRI->createVirtualRegister(&RISCV::GPRRegClass); 96881ad6265SDimitry Andric Opcode = RISCV::PseudoVSETVLIX0; 96981ad6265SDimitry Andric } 97081ad6265SDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(Opcode)) 97181ad6265SDimitry Andric .addReg(DestReg, RegState::Define | RegState::Dead) 97281ad6265SDimitry Andric .addReg(AVLReg) 97381ad6265SDimitry Andric .addImm(Info.encodeVTYPE()); 97481ad6265SDimitry Andric } 97581ad6265SDimitry Andric 97606c3fb27SDimitry Andric static bool isLMUL1OrSmaller(RISCVII::VLMUL LMUL) { 97706c3fb27SDimitry Andric auto [LMul, Fractional] = RISCVVType::decodeVLMUL(LMUL); 97806c3fb27SDimitry Andric return Fractional || LMul == 1; 97981ad6265SDimitry Andric } 98081ad6265SDimitry Andric 98181ad6265SDimitry Andric /// Return true if a VSETVLI is required to transition from CurInfo to Require 98281ad6265SDimitry Andric /// before MI. 98381ad6265SDimitry Andric bool RISCVInsertVSETVLI::needVSETVLI(const MachineInstr &MI, 98481ad6265SDimitry Andric const VSETVLIInfo &Require, 98581ad6265SDimitry Andric const VSETVLIInfo &CurInfo) const { 98681ad6265SDimitry Andric assert(Require == computeInfoForInstr(MI, MI.getDesc().TSFlags, MRI)); 98781ad6265SDimitry Andric 98881ad6265SDimitry Andric if (!CurInfo.isValid() || CurInfo.isUnknown() || CurInfo.hasSEWLMULRatioOnly()) 98981ad6265SDimitry Andric return true; 99081ad6265SDimitry Andric 9915f757f3fSDimitry Andric DemandedFields Used = getDemanded(MI, MRI, ST); 992bdd1243dSDimitry Andric 99306c3fb27SDimitry Andric // A slidedown/slideup with an *undefined* merge op can freely clobber 99406c3fb27SDimitry Andric // elements not copied from the source vector (e.g. masked off, tail, or 99506c3fb27SDimitry Andric // slideup's prefix). Notes: 99606c3fb27SDimitry Andric // * We can't modify SEW here since the slide amount is in units of SEW. 99706c3fb27SDimitry Andric // * VL=1 is special only because we have existing support for zero vs 99806c3fb27SDimitry Andric // non-zero VL. We could generalize this if we had a VL > C predicate. 99906c3fb27SDimitry Andric // * The LMUL1 restriction is for machines whose latency may depend on VL. 100006c3fb27SDimitry Andric // * As above, this is only legal for tail "undefined" not "agnostic". 100106c3fb27SDimitry Andric if (isVSlideInstr(MI) && Require.hasAVLImm() && Require.getAVLImm() == 1 && 100206c3fb27SDimitry Andric isLMUL1OrSmaller(CurInfo.getVLMUL()) && hasUndefinedMergeOp(MI, *MRI)) { 100306c3fb27SDimitry Andric Used.VLAny = false; 100406c3fb27SDimitry Andric Used.VLZeroness = true; 100506c3fb27SDimitry Andric Used.LMUL = false; 1006bdd1243dSDimitry Andric Used.TailPolicy = false; 100781ad6265SDimitry Andric } 100806c3fb27SDimitry Andric 100906c3fb27SDimitry Andric // A tail undefined vmv.v.i/x or vfmv.v.f with VL=1 can be treated in the same 101006c3fb27SDimitry Andric // semantically as vmv.s.x. This is particularly useful since we don't have an 101106c3fb27SDimitry Andric // immediate form of vmv.s.x, and thus frequently use vmv.v.i in it's place. 101206c3fb27SDimitry Andric // Since a splat is non-constant time in LMUL, we do need to be careful to not 101306c3fb27SDimitry Andric // increase the number of active vector registers (unlike for vmv.s.x.) 101406c3fb27SDimitry Andric if (isScalarSplatInstr(MI) && Require.hasAVLImm() && Require.getAVLImm() == 1 && 101506c3fb27SDimitry Andric isLMUL1OrSmaller(CurInfo.getVLMUL()) && hasUndefinedMergeOp(MI, *MRI)) { 101606c3fb27SDimitry Andric Used.LMUL = false; 101706c3fb27SDimitry Andric Used.SEWLMULRatio = false; 101806c3fb27SDimitry Andric Used.VLAny = false; 10195f757f3fSDimitry Andric if (isFloatScalarMoveOrScalarSplatInstr(MI) && !ST->hasVInstructionsF64()) 10205f757f3fSDimitry Andric Used.SEW = DemandedFields::SEWGreaterThanOrEqualAndLessThan64; 10215f757f3fSDimitry Andric else 102206c3fb27SDimitry Andric Used.SEW = DemandedFields::SEWGreaterThanOrEqual; 102306c3fb27SDimitry Andric Used.TailPolicy = false; 1024bdd1243dSDimitry Andric } 1025bdd1243dSDimitry Andric 102606c3fb27SDimitry Andric if (CurInfo.isCompatible(Used, Require, *MRI)) 1027bdd1243dSDimitry Andric return false; 102881ad6265SDimitry Andric 102981ad6265SDimitry Andric // We didn't find a compatible value. If our AVL is a virtual register, 103081ad6265SDimitry Andric // it might be defined by a VSET(I)VLI. If it has the same VLMAX we need 103181ad6265SDimitry Andric // and the last VL/VTYPE we observed is the same, we don't need a 103281ad6265SDimitry Andric // VSETVLI here. 103381ad6265SDimitry Andric if (Require.hasAVLReg() && Require.getAVLReg().isVirtual() && 1034bdd1243dSDimitry Andric CurInfo.hasCompatibleVTYPE(Used, Require)) { 103581ad6265SDimitry Andric if (MachineInstr *DefMI = MRI->getVRegDef(Require.getAVLReg())) { 103681ad6265SDimitry Andric if (isVectorConfigInstr(*DefMI)) { 103781ad6265SDimitry Andric VSETVLIInfo DefInfo = getInfoForVSETVLI(*DefMI); 103881ad6265SDimitry Andric if (DefInfo.hasSameAVL(CurInfo) && DefInfo.hasSameVLMAX(CurInfo)) 103981ad6265SDimitry Andric return false; 104081ad6265SDimitry Andric } 104181ad6265SDimitry Andric } 104281ad6265SDimitry Andric } 104381ad6265SDimitry Andric 104481ad6265SDimitry Andric return true; 104581ad6265SDimitry Andric } 104681ad6265SDimitry Andric 10475f757f3fSDimitry Andric // If we don't use LMUL or the SEW/LMUL ratio, then adjust LMUL so that we 10485f757f3fSDimitry Andric // maintain the SEW/LMUL ratio. This allows us to eliminate VL toggles in more 10495f757f3fSDimitry Andric // places. 10505f757f3fSDimitry Andric static VSETVLIInfo adjustIncoming(VSETVLIInfo PrevInfo, VSETVLIInfo NewInfo, 10515f757f3fSDimitry Andric DemandedFields &Demanded) { 10525f757f3fSDimitry Andric VSETVLIInfo Info = NewInfo; 10535f757f3fSDimitry Andric 10545f757f3fSDimitry Andric if (!Demanded.LMUL && !Demanded.SEWLMULRatio && PrevInfo.isValid() && 10555f757f3fSDimitry Andric !PrevInfo.isUnknown()) { 10565f757f3fSDimitry Andric if (auto NewVLMul = RISCVVType::getSameRatioLMUL( 10575f757f3fSDimitry Andric PrevInfo.getSEW(), PrevInfo.getVLMUL(), Info.getSEW())) 10585f757f3fSDimitry Andric Info.setVLMul(*NewVLMul); 10595f757f3fSDimitry Andric Demanded.LMUL = true; 10605f757f3fSDimitry Andric } 10615f757f3fSDimitry Andric 10625f757f3fSDimitry Andric return Info; 10635f757f3fSDimitry Andric } 10645f757f3fSDimitry Andric 10655f757f3fSDimitry Andric // Given an incoming state reaching MI, minimally modifies that state so that it 10665f757f3fSDimitry Andric // is compatible with MI. The resulting state is guaranteed to be semantically 10675f757f3fSDimitry Andric // legal for MI, but may not be the state requested by MI. 10685f757f3fSDimitry Andric void RISCVInsertVSETVLI::transferBefore(VSETVLIInfo &Info, 10695f757f3fSDimitry Andric const MachineInstr &MI) const { 107081ad6265SDimitry Andric uint64_t TSFlags = MI.getDesc().TSFlags; 107181ad6265SDimitry Andric if (!RISCVII::hasSEWOp(TSFlags)) 107281ad6265SDimitry Andric return; 107381ad6265SDimitry Andric 107481ad6265SDimitry Andric const VSETVLIInfo NewInfo = computeInfoForInstr(MI, TSFlags, MRI); 10755f757f3fSDimitry Andric assert(NewInfo.isValid() && !NewInfo.isUnknown()); 107681ad6265SDimitry Andric if (Info.isValid() && !needVSETVLI(MI, NewInfo, Info)) 107781ad6265SDimitry Andric return; 107881ad6265SDimitry Andric 107981ad6265SDimitry Andric const VSETVLIInfo PrevInfo = Info; 10805f757f3fSDimitry Andric if (!Info.isValid() || Info.isUnknown()) 108181ad6265SDimitry Andric Info = NewInfo; 108281ad6265SDimitry Andric 10835f757f3fSDimitry Andric DemandedFields Demanded = getDemanded(MI, MRI, ST); 10845f757f3fSDimitry Andric const VSETVLIInfo IncomingInfo = adjustIncoming(PrevInfo, NewInfo, Demanded); 108581ad6265SDimitry Andric 10865f757f3fSDimitry Andric // If MI only demands that VL has the same zeroness, we only need to set the 10875f757f3fSDimitry Andric // AVL if the zeroness differs. This removes a vsetvli entirely if the types 10885f757f3fSDimitry Andric // match or allows use of cheaper avl preserving variant if VLMAX doesn't 10895f757f3fSDimitry Andric // change. If VLMAX might change, we couldn't use the 'vsetvli x0, x0, vtype" 10905f757f3fSDimitry Andric // variant, so we avoid the transform to prevent extending live range of an 10915f757f3fSDimitry Andric // avl register operand. 109281ad6265SDimitry Andric // TODO: We can probably relax this for immediates. 10935f757f3fSDimitry Andric bool EquallyZero = IncomingInfo.hasEquallyZeroAVL(PrevInfo, *MRI) && 10945f757f3fSDimitry Andric IncomingInfo.hasSameVLMAX(PrevInfo); 10955f757f3fSDimitry Andric if (Demanded.VLAny || (Demanded.VLZeroness && !EquallyZero)) 10965f757f3fSDimitry Andric Info.setAVL(IncomingInfo); 109781ad6265SDimitry Andric 10985f757f3fSDimitry Andric Info.setVTYPE( 10995f757f3fSDimitry Andric ((Demanded.LMUL || Demanded.SEWLMULRatio) ? IncomingInfo : Info) 11005f757f3fSDimitry Andric .getVLMUL(), 11015f757f3fSDimitry Andric ((Demanded.SEW || Demanded.SEWLMULRatio) ? IncomingInfo : Info).getSEW(), 11025f757f3fSDimitry Andric // Prefer tail/mask agnostic since it can be relaxed to undisturbed later 11035f757f3fSDimitry Andric // if needed. 11045f757f3fSDimitry Andric (Demanded.TailPolicy ? IncomingInfo : Info).getTailAgnostic() || 11055f757f3fSDimitry Andric IncomingInfo.getTailAgnostic(), 11065f757f3fSDimitry Andric (Demanded.MaskPolicy ? IncomingInfo : Info).getMaskAgnostic() || 11075f757f3fSDimitry Andric IncomingInfo.getMaskAgnostic()); 110881ad6265SDimitry Andric 11095f757f3fSDimitry Andric // If we only knew the sew/lmul ratio previously, replace the VTYPE but keep 11105f757f3fSDimitry Andric // the AVL. 11115f757f3fSDimitry Andric if (Info.hasSEWLMULRatioOnly()) { 11125f757f3fSDimitry Andric VSETVLIInfo RatiolessInfo = IncomingInfo; 11135f757f3fSDimitry Andric RatiolessInfo.setAVL(Info); 11145f757f3fSDimitry Andric Info = RatiolessInfo; 111581ad6265SDimitry Andric } 111681ad6265SDimitry Andric } 111781ad6265SDimitry Andric 111881ad6265SDimitry Andric // Given a state with which we evaluated MI (see transferBefore above for why 111981ad6265SDimitry Andric // this might be different that the state MI requested), modify the state to 112081ad6265SDimitry Andric // reflect the changes MI might make. 11215f757f3fSDimitry Andric void RISCVInsertVSETVLI::transferAfter(VSETVLIInfo &Info, 11225f757f3fSDimitry Andric const MachineInstr &MI) const { 112381ad6265SDimitry Andric if (isVectorConfigInstr(MI)) { 112481ad6265SDimitry Andric Info = getInfoForVSETVLI(MI); 112581ad6265SDimitry Andric return; 112681ad6265SDimitry Andric } 112781ad6265SDimitry Andric 112881ad6265SDimitry Andric if (RISCV::isFaultFirstLoad(MI)) { 112981ad6265SDimitry Andric // Update AVL to vl-output of the fault first load. 113081ad6265SDimitry Andric Info.setAVLReg(MI.getOperand(1).getReg()); 113181ad6265SDimitry Andric return; 113281ad6265SDimitry Andric } 113381ad6265SDimitry Andric 113481ad6265SDimitry Andric // If this is something that updates VL/VTYPE that we don't know about, set 113581ad6265SDimitry Andric // the state to unknown. 113681ad6265SDimitry Andric if (MI.isCall() || MI.isInlineAsm() || MI.modifiesRegister(RISCV::VL) || 113781ad6265SDimitry Andric MI.modifiesRegister(RISCV::VTYPE)) 113881ad6265SDimitry Andric Info = VSETVLIInfo::getUnknown(); 1139349cc55cSDimitry Andric } 1140349cc55cSDimitry Andric 11415f757f3fSDimitry Andric bool RISCVInsertVSETVLI::computeVLVTYPEChanges(const MachineBasicBlock &MBB, 11425f757f3fSDimitry Andric VSETVLIInfo &Info) const { 1143fe6060f1SDimitry Andric bool HadVectorOp = false; 1144fe6060f1SDimitry Andric 11455f757f3fSDimitry Andric Info = BlockInfo[MBB.getNumber()].Pred; 1146fe6060f1SDimitry Andric for (const MachineInstr &MI : MBB) { 11475f757f3fSDimitry Andric transferBefore(Info, MI); 1148fe6060f1SDimitry Andric 114981ad6265SDimitry Andric if (isVectorConfigInstr(MI) || RISCVII::hasSEWOp(MI.getDesc().TSFlags)) 1150fe6060f1SDimitry Andric HadVectorOp = true; 1151fe6060f1SDimitry Andric 11525f757f3fSDimitry Andric transferAfter(Info, MI); 1153fe6060f1SDimitry Andric } 1154fe6060f1SDimitry Andric 1155fe6060f1SDimitry Andric return HadVectorOp; 1156fe6060f1SDimitry Andric } 1157fe6060f1SDimitry Andric 1158fe6060f1SDimitry Andric void RISCVInsertVSETVLI::computeIncomingVLVTYPE(const MachineBasicBlock &MBB) { 115981ad6265SDimitry Andric 1160fe6060f1SDimitry Andric BlockData &BBInfo = BlockInfo[MBB.getNumber()]; 1161fe6060f1SDimitry Andric 1162fe6060f1SDimitry Andric BBInfo.InQueue = false; 1163fe6060f1SDimitry Andric 1164bdd1243dSDimitry Andric // Start with the previous entry so that we keep the most conservative state 1165bdd1243dSDimitry Andric // we have ever found. 1166bdd1243dSDimitry Andric VSETVLIInfo InInfo = BBInfo.Pred; 1167fe6060f1SDimitry Andric if (MBB.pred_empty()) { 1168fe6060f1SDimitry Andric // There are no predecessors, so use the default starting status. 1169fe6060f1SDimitry Andric InInfo.setUnknown(); 1170fe6060f1SDimitry Andric } else { 1171fe6060f1SDimitry Andric for (MachineBasicBlock *P : MBB.predecessors()) 1172fe6060f1SDimitry Andric InInfo = InInfo.intersect(BlockInfo[P->getNumber()].Exit); 1173fe6060f1SDimitry Andric } 1174fe6060f1SDimitry Andric 1175fe6060f1SDimitry Andric // If we don't have any valid predecessor value, wait until we do. 1176fe6060f1SDimitry Andric if (!InInfo.isValid()) 1177fe6060f1SDimitry Andric return; 1178fe6060f1SDimitry Andric 117981ad6265SDimitry Andric // If no change, no need to rerun block 118081ad6265SDimitry Andric if (InInfo == BBInfo.Pred) 118181ad6265SDimitry Andric return; 1182fe6060f1SDimitry Andric 118381ad6265SDimitry Andric BBInfo.Pred = InInfo; 118481ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "Entry state of " << printMBBReference(MBB) 118581ad6265SDimitry Andric << " changed to " << BBInfo.Pred << "\n"); 118681ad6265SDimitry Andric 118781ad6265SDimitry Andric // Note: It's tempting to cache the state changes here, but due to the 118881ad6265SDimitry Andric // compatibility checks performed a blocks output state can change based on 118981ad6265SDimitry Andric // the input state. To cache, we'd have to add logic for finding 119081ad6265SDimitry Andric // never-compatible state changes. 11915f757f3fSDimitry Andric VSETVLIInfo TmpStatus; 11925f757f3fSDimitry Andric computeVLVTYPEChanges(MBB, TmpStatus); 1193fe6060f1SDimitry Andric 1194fe6060f1SDimitry Andric // If the new exit value matches the old exit value, we don't need to revisit 1195fe6060f1SDimitry Andric // any blocks. 1196fe6060f1SDimitry Andric if (BBInfo.Exit == TmpStatus) 1197fe6060f1SDimitry Andric return; 1198fe6060f1SDimitry Andric 1199fe6060f1SDimitry Andric BBInfo.Exit = TmpStatus; 120081ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "Exit state of " << printMBBReference(MBB) 120181ad6265SDimitry Andric << " changed to " << BBInfo.Exit << "\n"); 1202fe6060f1SDimitry Andric 1203fe6060f1SDimitry Andric // Add the successors to the work list so we can propagate the changed exit 1204fe6060f1SDimitry Andric // status. 1205fe6060f1SDimitry Andric for (MachineBasicBlock *S : MBB.successors()) 1206bdd1243dSDimitry Andric if (!BlockInfo[S->getNumber()].InQueue) { 1207bdd1243dSDimitry Andric BlockInfo[S->getNumber()].InQueue = true; 1208fe6060f1SDimitry Andric WorkList.push(S); 1209fe6060f1SDimitry Andric } 1210bdd1243dSDimitry Andric } 1211fe6060f1SDimitry Andric 1212fe6060f1SDimitry Andric // If we weren't able to prove a vsetvli was directly unneeded, it might still 121381ad6265SDimitry Andric // be unneeded if the AVL is a phi node where all incoming values are VL 1214fe6060f1SDimitry Andric // outputs from the last VSETVLI in their respective basic blocks. 1215fe6060f1SDimitry Andric bool RISCVInsertVSETVLI::needVSETVLIPHI(const VSETVLIInfo &Require, 121681ad6265SDimitry Andric const MachineBasicBlock &MBB) const { 1217fe6060f1SDimitry Andric if (DisableInsertVSETVLPHIOpt) 1218fe6060f1SDimitry Andric return true; 1219fe6060f1SDimitry Andric 1220fe6060f1SDimitry Andric if (!Require.hasAVLReg()) 1221fe6060f1SDimitry Andric return true; 1222fe6060f1SDimitry Andric 1223fe6060f1SDimitry Andric Register AVLReg = Require.getAVLReg(); 1224fe6060f1SDimitry Andric if (!AVLReg.isVirtual()) 1225fe6060f1SDimitry Andric return true; 1226fe6060f1SDimitry Andric 1227fe6060f1SDimitry Andric // We need the AVL to be produce by a PHI node in this basic block. 1228fe6060f1SDimitry Andric MachineInstr *PHI = MRI->getVRegDef(AVLReg); 1229fe6060f1SDimitry Andric if (!PHI || PHI->getOpcode() != RISCV::PHI || PHI->getParent() != &MBB) 1230fe6060f1SDimitry Andric return true; 1231fe6060f1SDimitry Andric 1232fe6060f1SDimitry Andric for (unsigned PHIOp = 1, NumOps = PHI->getNumOperands(); PHIOp != NumOps; 1233fe6060f1SDimitry Andric PHIOp += 2) { 1234fe6060f1SDimitry Andric Register InReg = PHI->getOperand(PHIOp).getReg(); 1235fe6060f1SDimitry Andric MachineBasicBlock *PBB = PHI->getOperand(PHIOp + 1).getMBB(); 1236fe6060f1SDimitry Andric const BlockData &PBBInfo = BlockInfo[PBB->getNumber()]; 1237fe6060f1SDimitry Andric // If the exit from the predecessor has the VTYPE we are looking for 1238fe6060f1SDimitry Andric // we might be able to avoid a VSETVLI. 123981ad6265SDimitry Andric if (PBBInfo.Exit.isUnknown() || !PBBInfo.Exit.hasSameVTYPE(Require)) 1240fe6060f1SDimitry Andric return true; 1241fe6060f1SDimitry Andric 1242fe6060f1SDimitry Andric // We need the PHI input to the be the output of a VSET(I)VLI. 1243fe6060f1SDimitry Andric MachineInstr *DefMI = MRI->getVRegDef(InReg); 124481ad6265SDimitry Andric if (!DefMI || !isVectorConfigInstr(*DefMI)) 1245fe6060f1SDimitry Andric return true; 1246fe6060f1SDimitry Andric 1247fe6060f1SDimitry Andric // We found a VSET(I)VLI make sure it matches the output of the 1248fe6060f1SDimitry Andric // predecessor block. 1249fe6060f1SDimitry Andric VSETVLIInfo DefInfo = getInfoForVSETVLI(*DefMI); 1250fe6060f1SDimitry Andric if (!DefInfo.hasSameAVL(PBBInfo.Exit) || 1251fe6060f1SDimitry Andric !DefInfo.hasSameVTYPE(PBBInfo.Exit)) 1252fe6060f1SDimitry Andric return true; 1253fe6060f1SDimitry Andric } 1254fe6060f1SDimitry Andric 1255fe6060f1SDimitry Andric // If all the incoming values to the PHI checked out, we don't need 1256fe6060f1SDimitry Andric // to insert a VSETVLI. 1257fe6060f1SDimitry Andric return false; 1258fe6060f1SDimitry Andric } 1259fe6060f1SDimitry Andric 1260fe6060f1SDimitry Andric void RISCVInsertVSETVLI::emitVSETVLIs(MachineBasicBlock &MBB) { 126181ad6265SDimitry Andric VSETVLIInfo CurInfo = BlockInfo[MBB.getNumber()].Pred; 126281ad6265SDimitry Andric // Track whether the prefix of the block we've scanned is transparent 126381ad6265SDimitry Andric // (meaning has not yet changed the abstract state). 126481ad6265SDimitry Andric bool PrefixTransparent = true; 1265fe6060f1SDimitry Andric for (MachineInstr &MI : MBB) { 126681ad6265SDimitry Andric const VSETVLIInfo PrevInfo = CurInfo; 126781ad6265SDimitry Andric transferBefore(CurInfo, MI); 126881ad6265SDimitry Andric 1269fe6060f1SDimitry Andric // If this is an explicit VSETVLI or VSETIVLI, update our state. 127081ad6265SDimitry Andric if (isVectorConfigInstr(MI)) { 1271fe6060f1SDimitry Andric // Conservatively, mark the VL and VTYPE as live. 1272fe6060f1SDimitry Andric assert(MI.getOperand(3).getReg() == RISCV::VL && 1273fe6060f1SDimitry Andric MI.getOperand(4).getReg() == RISCV::VTYPE && 1274fe6060f1SDimitry Andric "Unexpected operands where VL and VTYPE should be"); 1275fe6060f1SDimitry Andric MI.getOperand(3).setIsDead(false); 1276fe6060f1SDimitry Andric MI.getOperand(4).setIsDead(false); 127781ad6265SDimitry Andric PrefixTransparent = false; 1278fe6060f1SDimitry Andric } 1279fe6060f1SDimitry Andric 1280fe6060f1SDimitry Andric uint64_t TSFlags = MI.getDesc().TSFlags; 1281fe6060f1SDimitry Andric if (RISCVII::hasSEWOp(TSFlags)) { 128281ad6265SDimitry Andric if (PrevInfo != CurInfo) { 128381ad6265SDimitry Andric // If this is the first implicit state change, and the state change 128481ad6265SDimitry Andric // requested can be proven to produce the same register contents, we 128581ad6265SDimitry Andric // can skip emitting the actual state change and continue as if we 128681ad6265SDimitry Andric // had since we know the GPR result of the implicit state change 128781ad6265SDimitry Andric // wouldn't be used and VL/VTYPE registers are correct. Note that 128881ad6265SDimitry Andric // we *do* need to model the state as if it changed as while the 128981ad6265SDimitry Andric // register contents are unchanged, the abstract model can change. 129081ad6265SDimitry Andric if (!PrefixTransparent || needVSETVLIPHI(CurInfo, MBB)) 129181ad6265SDimitry Andric insertVSETVLI(MBB, MI, CurInfo, PrevInfo); 129281ad6265SDimitry Andric PrefixTransparent = false; 129381ad6265SDimitry Andric } 129481ad6265SDimitry Andric 1295fe6060f1SDimitry Andric if (RISCVII::hasVLOp(TSFlags)) { 129681ad6265SDimitry Andric MachineOperand &VLOp = MI.getOperand(getVLOpNum(MI)); 1297fe6060f1SDimitry Andric if (VLOp.isReg()) { 12985f757f3fSDimitry Andric Register Reg = VLOp.getReg(); 12995f757f3fSDimitry Andric MachineInstr *VLOpDef = MRI->getVRegDef(Reg); 13005f757f3fSDimitry Andric 1301fe6060f1SDimitry Andric // Erase the AVL operand from the instruction. 1302fe6060f1SDimitry Andric VLOp.setReg(RISCV::NoRegister); 1303fe6060f1SDimitry Andric VLOp.setIsKill(false); 13045f757f3fSDimitry Andric 13055f757f3fSDimitry Andric // If the AVL was an immediate > 31, then it would have been emitted 13065f757f3fSDimitry Andric // as an ADDI. However, the ADDI might not have been used in the 13075f757f3fSDimitry Andric // vsetvli, or a vsetvli might not have been emitted, so it may be 13085f757f3fSDimitry Andric // dead now. 13095f757f3fSDimitry Andric if (VLOpDef && TII->isAddImmediate(*VLOpDef, Reg) && 13105f757f3fSDimitry Andric MRI->use_nodbg_empty(Reg)) 13115f757f3fSDimitry Andric VLOpDef->eraseFromParent(); 1312fe6060f1SDimitry Andric } 1313fe6060f1SDimitry Andric MI.addOperand(MachineOperand::CreateReg(RISCV::VL, /*isDef*/ false, 1314fe6060f1SDimitry Andric /*isImp*/ true)); 1315fe6060f1SDimitry Andric } 1316fe6060f1SDimitry Andric MI.addOperand(MachineOperand::CreateReg(RISCV::VTYPE, /*isDef*/ false, 1317fe6060f1SDimitry Andric /*isImp*/ true)); 1318fe6060f1SDimitry Andric } 1319fe6060f1SDimitry Andric 1320fe6060f1SDimitry Andric if (MI.isCall() || MI.isInlineAsm() || MI.modifiesRegister(RISCV::VL) || 132181ad6265SDimitry Andric MI.modifiesRegister(RISCV::VTYPE)) 132281ad6265SDimitry Andric PrefixTransparent = false; 132381ad6265SDimitry Andric 132481ad6265SDimitry Andric transferAfter(CurInfo, MI); 1325fe6060f1SDimitry Andric } 1326d56accc7SDimitry Andric 1327d56accc7SDimitry Andric // If we reach the end of the block and our current info doesn't match the 1328d56accc7SDimitry Andric // expected info, insert a vsetvli to correct. 132981ad6265SDimitry Andric if (!UseStrictAsserts) { 1330d56accc7SDimitry Andric const VSETVLIInfo &ExitInfo = BlockInfo[MBB.getNumber()].Exit; 1331d56accc7SDimitry Andric if (CurInfo.isValid() && ExitInfo.isValid() && !ExitInfo.isUnknown() && 1332d56accc7SDimitry Andric CurInfo != ExitInfo) { 133381ad6265SDimitry Andric // Note there's an implicit assumption here that terminators never use 133481ad6265SDimitry Andric // or modify VL or VTYPE. Also, fallthrough will return end(). 133581ad6265SDimitry Andric auto InsertPt = MBB.getFirstInstrTerminator(); 133681ad6265SDimitry Andric insertVSETVLI(MBB, InsertPt, MBB.findDebugLoc(InsertPt), ExitInfo, 133781ad6265SDimitry Andric CurInfo); 1338d56accc7SDimitry Andric CurInfo = ExitInfo; 1339d56accc7SDimitry Andric } 1340d56accc7SDimitry Andric } 134181ad6265SDimitry Andric 134281ad6265SDimitry Andric if (UseStrictAsserts && CurInfo.isValid()) { 134381ad6265SDimitry Andric const auto &Info = BlockInfo[MBB.getNumber()]; 134481ad6265SDimitry Andric if (CurInfo != Info.Exit) { 134581ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "in block " << printMBBReference(MBB) << "\n"); 134681ad6265SDimitry Andric LLVM_DEBUG(dbgs() << " begin state: " << Info.Pred << "\n"); 134781ad6265SDimitry Andric LLVM_DEBUG(dbgs() << " expected end state: " << Info.Exit << "\n"); 134881ad6265SDimitry Andric LLVM_DEBUG(dbgs() << " actual end state: " << CurInfo << "\n"); 134981ad6265SDimitry Andric } 135081ad6265SDimitry Andric assert(CurInfo == Info.Exit && 135181ad6265SDimitry Andric "InsertVSETVLI dataflow invariant violated"); 135281ad6265SDimitry Andric } 135381ad6265SDimitry Andric } 135481ad6265SDimitry Andric 135581ad6265SDimitry Andric /// Perform simple partial redundancy elimination of the VSETVLI instructions 135681ad6265SDimitry Andric /// we're about to insert by looking for cases where we can PRE from the 135781ad6265SDimitry Andric /// beginning of one block to the end of one of its predecessors. Specifically, 135881ad6265SDimitry Andric /// this is geared to catch the common case of a fixed length vsetvl in a single 135981ad6265SDimitry Andric /// block loop when it could execute once in the preheader instead. 136081ad6265SDimitry Andric void RISCVInsertVSETVLI::doPRE(MachineBasicBlock &MBB) { 136181ad6265SDimitry Andric if (!BlockInfo[MBB.getNumber()].Pred.isUnknown()) 136281ad6265SDimitry Andric return; 136381ad6265SDimitry Andric 136481ad6265SDimitry Andric MachineBasicBlock *UnavailablePred = nullptr; 136581ad6265SDimitry Andric VSETVLIInfo AvailableInfo; 136681ad6265SDimitry Andric for (MachineBasicBlock *P : MBB.predecessors()) { 136781ad6265SDimitry Andric const VSETVLIInfo &PredInfo = BlockInfo[P->getNumber()].Exit; 136881ad6265SDimitry Andric if (PredInfo.isUnknown()) { 136981ad6265SDimitry Andric if (UnavailablePred) 137081ad6265SDimitry Andric return; 137181ad6265SDimitry Andric UnavailablePred = P; 137281ad6265SDimitry Andric } else if (!AvailableInfo.isValid()) { 137381ad6265SDimitry Andric AvailableInfo = PredInfo; 137481ad6265SDimitry Andric } else if (AvailableInfo != PredInfo) { 137581ad6265SDimitry Andric return; 137681ad6265SDimitry Andric } 137781ad6265SDimitry Andric } 137881ad6265SDimitry Andric 137981ad6265SDimitry Andric // Unreachable, single pred, or full redundancy. Note that FRE is handled by 138081ad6265SDimitry Andric // phase 3. 138181ad6265SDimitry Andric if (!UnavailablePred || !AvailableInfo.isValid()) 138281ad6265SDimitry Andric return; 138381ad6265SDimitry Andric 1384*1db9f3b2SDimitry Andric // If we don't know the exact VTYPE, we can't copy the vsetvli to the exit of 1385*1db9f3b2SDimitry Andric // the unavailable pred. 1386*1db9f3b2SDimitry Andric if (AvailableInfo.hasSEWLMULRatioOnly()) 1387*1db9f3b2SDimitry Andric return; 1388*1db9f3b2SDimitry Andric 138981ad6265SDimitry Andric // Critical edge - TODO: consider splitting? 139081ad6265SDimitry Andric if (UnavailablePred->succ_size() != 1) 139181ad6265SDimitry Andric return; 139281ad6265SDimitry Andric 13935f757f3fSDimitry Andric // If the AVL value is a register (other than our VLMAX sentinel), 13945f757f3fSDimitry Andric // we need to prove the value is available at the point we're going 13955f757f3fSDimitry Andric // to insert the vsetvli at. 13965f757f3fSDimitry Andric if (AvailableInfo.hasAVLReg() && RISCV::X0 != AvailableInfo.getAVLReg()) { 13975f757f3fSDimitry Andric MachineInstr *AVLDefMI = MRI->getVRegDef(AvailableInfo.getAVLReg()); 13985f757f3fSDimitry Andric if (!AVLDefMI) 139981ad6265SDimitry Andric return; 14005f757f3fSDimitry Andric // This is an inline dominance check which covers the case of 14015f757f3fSDimitry Andric // UnavailablePred being the preheader of a loop. 14025f757f3fSDimitry Andric if (AVLDefMI->getParent() != UnavailablePred) 14035f757f3fSDimitry Andric return; 14045f757f3fSDimitry Andric for (auto &TermMI : UnavailablePred->terminators()) 14055f757f3fSDimitry Andric if (&TermMI == AVLDefMI) 14065f757f3fSDimitry Andric return; 14075f757f3fSDimitry Andric } 140881ad6265SDimitry Andric 140906c3fb27SDimitry Andric // Model the effect of changing the input state of the block MBB to 141006c3fb27SDimitry Andric // AvailableInfo. We're looking for two issues here; one legality, 141106c3fb27SDimitry Andric // one profitability. 141206c3fb27SDimitry Andric // 1) If the block doesn't use some of the fields from VL or VTYPE, we 141306c3fb27SDimitry Andric // may hit the end of the block with a different end state. We can 141406c3fb27SDimitry Andric // not make this change without reflowing later blocks as well. 141506c3fb27SDimitry Andric // 2) If we don't actually remove a transition, inserting a vsetvli 141606c3fb27SDimitry Andric // into the predecessor block would be correct, but unprofitable. 141706c3fb27SDimitry Andric VSETVLIInfo OldInfo = BlockInfo[MBB.getNumber()].Pred; 141806c3fb27SDimitry Andric VSETVLIInfo CurInfo = AvailableInfo; 141906c3fb27SDimitry Andric int TransitionsRemoved = 0; 142006c3fb27SDimitry Andric for (const MachineInstr &MI : MBB) { 142106c3fb27SDimitry Andric const VSETVLIInfo LastInfo = CurInfo; 142206c3fb27SDimitry Andric const VSETVLIInfo LastOldInfo = OldInfo; 142306c3fb27SDimitry Andric transferBefore(CurInfo, MI); 142406c3fb27SDimitry Andric transferBefore(OldInfo, MI); 142506c3fb27SDimitry Andric if (CurInfo == LastInfo) 142606c3fb27SDimitry Andric TransitionsRemoved++; 142706c3fb27SDimitry Andric if (LastOldInfo == OldInfo) 142806c3fb27SDimitry Andric TransitionsRemoved--; 142906c3fb27SDimitry Andric transferAfter(CurInfo, MI); 143006c3fb27SDimitry Andric transferAfter(OldInfo, MI); 143106c3fb27SDimitry Andric if (CurInfo == OldInfo) 143206c3fb27SDimitry Andric // Convergence. All transitions after this must match by construction. 143381ad6265SDimitry Andric break; 143481ad6265SDimitry Andric } 143506c3fb27SDimitry Andric if (CurInfo != OldInfo || TransitionsRemoved <= 0) 143606c3fb27SDimitry Andric // Issues 1 and 2 above 143781ad6265SDimitry Andric return; 143881ad6265SDimitry Andric 143981ad6265SDimitry Andric // Finally, update both data flow state and insert the actual vsetvli. 144081ad6265SDimitry Andric // Doing both keeps the code in sync with the dataflow results, which 144181ad6265SDimitry Andric // is critical for correctness of phase 3. 144206c3fb27SDimitry Andric auto OldExit = BlockInfo[UnavailablePred->getNumber()].Exit; 144381ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "PRE VSETVLI from " << MBB.getName() << " to " 144481ad6265SDimitry Andric << UnavailablePred->getName() << " with state " 144581ad6265SDimitry Andric << AvailableInfo << "\n"); 144681ad6265SDimitry Andric BlockInfo[UnavailablePred->getNumber()].Exit = AvailableInfo; 144781ad6265SDimitry Andric BlockInfo[MBB.getNumber()].Pred = AvailableInfo; 144881ad6265SDimitry Andric 144981ad6265SDimitry Andric // Note there's an implicit assumption here that terminators never use 145081ad6265SDimitry Andric // or modify VL or VTYPE. Also, fallthrough will return end(). 145181ad6265SDimitry Andric auto InsertPt = UnavailablePred->getFirstInstrTerminator(); 145281ad6265SDimitry Andric insertVSETVLI(*UnavailablePred, InsertPt, 145381ad6265SDimitry Andric UnavailablePred->findDebugLoc(InsertPt), 145406c3fb27SDimitry Andric AvailableInfo, OldExit); 145581ad6265SDimitry Andric } 145681ad6265SDimitry Andric 145781ad6265SDimitry Andric static void doUnion(DemandedFields &A, DemandedFields B) { 1458bdd1243dSDimitry Andric A.VLAny |= B.VLAny; 1459bdd1243dSDimitry Andric A.VLZeroness |= B.VLZeroness; 146006c3fb27SDimitry Andric A.SEW = std::max(A.SEW, B.SEW); 146181ad6265SDimitry Andric A.LMUL |= B.LMUL; 146281ad6265SDimitry Andric A.SEWLMULRatio |= B.SEWLMULRatio; 146381ad6265SDimitry Andric A.TailPolicy |= B.TailPolicy; 146481ad6265SDimitry Andric A.MaskPolicy |= B.MaskPolicy; 146581ad6265SDimitry Andric } 146681ad6265SDimitry Andric 14675f757f3fSDimitry Andric static bool isNonZeroAVL(const MachineOperand &MO, 14685f757f3fSDimitry Andric const MachineRegisterInfo &MRI) { 14695f757f3fSDimitry Andric if (MO.isReg()) { 14705f757f3fSDimitry Andric if (MO.getReg() == RISCV::X0) 14715f757f3fSDimitry Andric return true; 14725f757f3fSDimitry Andric if (MachineInstr *MI = MRI.getVRegDef(MO.getReg()); 14735f757f3fSDimitry Andric MI && isNonZeroLoadImmediate(*MI)) 14745f757f3fSDimitry Andric return true; 14755f757f3fSDimitry Andric return false; 14765f757f3fSDimitry Andric } 1477bdd1243dSDimitry Andric assert(MO.isImm()); 1478bdd1243dSDimitry Andric return 0 != MO.getImm(); 1479bdd1243dSDimitry Andric } 1480bdd1243dSDimitry Andric 1481bdd1243dSDimitry Andric // Return true if we can mutate PrevMI to match MI without changing any the 1482bdd1243dSDimitry Andric // fields which would be observed. 148381ad6265SDimitry Andric static bool canMutatePriorConfig(const MachineInstr &PrevMI, 148481ad6265SDimitry Andric const MachineInstr &MI, 14855f757f3fSDimitry Andric const DemandedFields &Used, 14865f757f3fSDimitry Andric const MachineRegisterInfo &MRI) { 1487bdd1243dSDimitry Andric // If the VL values aren't equal, return false if either a) the former is 1488bdd1243dSDimitry Andric // demanded, or b) we can't rewrite the former to be the later for 1489bdd1243dSDimitry Andric // implementation reasons. 1490bdd1243dSDimitry Andric if (!isVLPreservingConfig(MI)) { 1491bdd1243dSDimitry Andric if (Used.VLAny) 149281ad6265SDimitry Andric return false; 149381ad6265SDimitry Andric 1494bdd1243dSDimitry Andric // We don't bother to handle the equally zero case here as it's largely 1495bdd1243dSDimitry Andric // uninteresting. 14965f757f3fSDimitry Andric if (Used.VLZeroness) { 14975f757f3fSDimitry Andric if (isVLPreservingConfig(PrevMI)) 1498bdd1243dSDimitry Andric return false; 14995f757f3fSDimitry Andric if (!isNonZeroAVL(MI.getOperand(1), MRI) || 15005f757f3fSDimitry Andric !isNonZeroAVL(PrevMI.getOperand(1), MRI)) 15015f757f3fSDimitry Andric return false; 15025f757f3fSDimitry Andric } 1503bdd1243dSDimitry Andric 1504bdd1243dSDimitry Andric // TODO: Track whether the register is defined between 1505bdd1243dSDimitry Andric // PrevMI and MI. 1506bdd1243dSDimitry Andric if (MI.getOperand(1).isReg() && 1507bdd1243dSDimitry Andric RISCV::X0 != MI.getOperand(1).getReg()) 1508bdd1243dSDimitry Andric return false; 1509bdd1243dSDimitry Andric } 1510bdd1243dSDimitry Andric 151181ad6265SDimitry Andric if (!PrevMI.getOperand(2).isImm() || !MI.getOperand(2).isImm()) 151281ad6265SDimitry Andric return false; 151381ad6265SDimitry Andric 151481ad6265SDimitry Andric auto PriorVType = PrevMI.getOperand(2).getImm(); 151581ad6265SDimitry Andric auto VType = MI.getOperand(2).getImm(); 151681ad6265SDimitry Andric return areCompatibleVTYPEs(PriorVType, VType, Used); 151781ad6265SDimitry Andric } 151881ad6265SDimitry Andric 151981ad6265SDimitry Andric void RISCVInsertVSETVLI::doLocalPostpass(MachineBasicBlock &MBB) { 1520bdd1243dSDimitry Andric MachineInstr *NextMI = nullptr; 1521bdd1243dSDimitry Andric // We can have arbitrary code in successors, so VL and VTYPE 1522bdd1243dSDimitry Andric // must be considered demanded. 152381ad6265SDimitry Andric DemandedFields Used; 1524bdd1243dSDimitry Andric Used.demandVL(); 1525bdd1243dSDimitry Andric Used.demandVTYPE(); 152681ad6265SDimitry Andric SmallVector<MachineInstr*> ToDelete; 1527bdd1243dSDimitry Andric for (MachineInstr &MI : make_range(MBB.rbegin(), MBB.rend())) { 1528bdd1243dSDimitry Andric 1529bdd1243dSDimitry Andric if (!isVectorConfigInstr(MI)) { 15305f757f3fSDimitry Andric doUnion(Used, getDemanded(MI, MRI, ST)); 153181ad6265SDimitry Andric continue; 153281ad6265SDimitry Andric } 1533bdd1243dSDimitry Andric 153481ad6265SDimitry Andric Register VRegDef = MI.getOperand(0).getReg(); 153581ad6265SDimitry Andric if (VRegDef != RISCV::X0 && 153681ad6265SDimitry Andric !(VRegDef.isVirtual() && MRI->use_nodbg_empty(VRegDef))) 1537bdd1243dSDimitry Andric Used.demandVL(); 1538bdd1243dSDimitry Andric 1539bdd1243dSDimitry Andric if (NextMI) { 1540bdd1243dSDimitry Andric if (!Used.usedVL() && !Used.usedVTYPE()) { 1541bdd1243dSDimitry Andric ToDelete.push_back(&MI); 1542bdd1243dSDimitry Andric // Leave NextMI unchanged 1543bdd1243dSDimitry Andric continue; 15445f757f3fSDimitry Andric } else if (canMutatePriorConfig(MI, *NextMI, Used, *MRI)) { 1545bdd1243dSDimitry Andric if (!isVLPreservingConfig(*NextMI)) { 15465f757f3fSDimitry Andric MI.getOperand(0).setReg(NextMI->getOperand(0).getReg()); 15475f757f3fSDimitry Andric MI.getOperand(0).setIsDead(false); 15485f757f3fSDimitry Andric Register OldVLReg; 15495f757f3fSDimitry Andric if (MI.getOperand(1).isReg()) 15505f757f3fSDimitry Andric OldVLReg = MI.getOperand(1).getReg(); 1551bdd1243dSDimitry Andric if (NextMI->getOperand(1).isImm()) 1552bdd1243dSDimitry Andric MI.getOperand(1).ChangeToImmediate(NextMI->getOperand(1).getImm()); 1553bdd1243dSDimitry Andric else 1554bdd1243dSDimitry Andric MI.getOperand(1).ChangeToRegister(NextMI->getOperand(1).getReg(), false); 15555f757f3fSDimitry Andric if (OldVLReg) { 15565f757f3fSDimitry Andric MachineInstr *VLOpDef = MRI->getUniqueVRegDef(OldVLReg); 15575f757f3fSDimitry Andric if (VLOpDef && TII->isAddImmediate(*VLOpDef, OldVLReg) && 15585f757f3fSDimitry Andric MRI->use_nodbg_empty(OldVLReg)) 15595f757f3fSDimitry Andric VLOpDef->eraseFromParent(); 15605f757f3fSDimitry Andric } 1561bdd1243dSDimitry Andric MI.setDesc(NextMI->getDesc()); 1562bdd1243dSDimitry Andric } 1563bdd1243dSDimitry Andric MI.getOperand(2).setImm(NextMI->getOperand(2).getImm()); 1564bdd1243dSDimitry Andric ToDelete.push_back(NextMI); 1565bdd1243dSDimitry Andric // fallthrough 1566bdd1243dSDimitry Andric } 1567bdd1243dSDimitry Andric } 1568bdd1243dSDimitry Andric NextMI = &MI; 15695f757f3fSDimitry Andric Used = getDemanded(MI, MRI, ST); 157081ad6265SDimitry Andric } 157181ad6265SDimitry Andric 157281ad6265SDimitry Andric for (auto *MI : ToDelete) 157381ad6265SDimitry Andric MI->eraseFromParent(); 157481ad6265SDimitry Andric } 157581ad6265SDimitry Andric 157681ad6265SDimitry Andric void RISCVInsertVSETVLI::insertReadVL(MachineBasicBlock &MBB) { 157781ad6265SDimitry Andric for (auto I = MBB.begin(), E = MBB.end(); I != E;) { 157881ad6265SDimitry Andric MachineInstr &MI = *I++; 157981ad6265SDimitry Andric if (RISCV::isFaultFirstLoad(MI)) { 158081ad6265SDimitry Andric Register VLOutput = MI.getOperand(1).getReg(); 158181ad6265SDimitry Andric if (!MRI->use_nodbg_empty(VLOutput)) 158281ad6265SDimitry Andric BuildMI(MBB, I, MI.getDebugLoc(), TII->get(RISCV::PseudoReadVL), 158381ad6265SDimitry Andric VLOutput); 158481ad6265SDimitry Andric // We don't use the vl output of the VLEFF/VLSEGFF anymore. 158581ad6265SDimitry Andric MI.getOperand(1).setReg(RISCV::X0); 158681ad6265SDimitry Andric } 1587fe6060f1SDimitry Andric } 1588fe6060f1SDimitry Andric } 1589fe6060f1SDimitry Andric 1590fe6060f1SDimitry Andric bool RISCVInsertVSETVLI::runOnMachineFunction(MachineFunction &MF) { 1591fe6060f1SDimitry Andric // Skip if the vector extension is not enabled. 15925f757f3fSDimitry Andric ST = &MF.getSubtarget<RISCVSubtarget>(); 15935f757f3fSDimitry Andric if (!ST->hasVInstructions()) 1594fe6060f1SDimitry Andric return false; 1595fe6060f1SDimitry Andric 159681ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "Entering InsertVSETVLI for " << MF.getName() << "\n"); 159781ad6265SDimitry Andric 15985f757f3fSDimitry Andric TII = ST->getInstrInfo(); 1599fe6060f1SDimitry Andric MRI = &MF.getRegInfo(); 1600fe6060f1SDimitry Andric 1601fe6060f1SDimitry Andric assert(BlockInfo.empty() && "Expect empty block infos"); 1602fe6060f1SDimitry Andric BlockInfo.resize(MF.getNumBlockIDs()); 1603fe6060f1SDimitry Andric 1604fe6060f1SDimitry Andric bool HaveVectorOp = false; 1605fe6060f1SDimitry Andric 1606fe6060f1SDimitry Andric // Phase 1 - determine how VL/VTYPE are affected by the each block. 160781ad6265SDimitry Andric for (const MachineBasicBlock &MBB : MF) { 16085f757f3fSDimitry Andric VSETVLIInfo TmpStatus; 16095f757f3fSDimitry Andric HaveVectorOp |= computeVLVTYPEChanges(MBB, TmpStatus); 161081ad6265SDimitry Andric // Initial exit state is whatever change we found in the block. 161181ad6265SDimitry Andric BlockData &BBInfo = BlockInfo[MBB.getNumber()]; 16125f757f3fSDimitry Andric BBInfo.Exit = TmpStatus; 161381ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "Initial exit state of " << printMBBReference(MBB) 161481ad6265SDimitry Andric << " is " << BBInfo.Exit << "\n"); 161581ad6265SDimitry Andric 161681ad6265SDimitry Andric } 1617fe6060f1SDimitry Andric 1618fe6060f1SDimitry Andric // If we didn't find any instructions that need VSETVLI, we're done. 161981ad6265SDimitry Andric if (!HaveVectorOp) { 162081ad6265SDimitry Andric BlockInfo.clear(); 162181ad6265SDimitry Andric return false; 162281ad6265SDimitry Andric } 162381ad6265SDimitry Andric 1624fe6060f1SDimitry Andric // Phase 2 - determine the exit VL/VTYPE from each block. We add all 1625fe6060f1SDimitry Andric // blocks to the list here, but will also add any that need to be revisited 1626fe6060f1SDimitry Andric // during Phase 2 processing. 1627fe6060f1SDimitry Andric for (const MachineBasicBlock &MBB : MF) { 1628fe6060f1SDimitry Andric WorkList.push(&MBB); 1629fe6060f1SDimitry Andric BlockInfo[MBB.getNumber()].InQueue = true; 1630fe6060f1SDimitry Andric } 1631fe6060f1SDimitry Andric while (!WorkList.empty()) { 1632fe6060f1SDimitry Andric const MachineBasicBlock &MBB = *WorkList.front(); 1633fe6060f1SDimitry Andric WorkList.pop(); 1634fe6060f1SDimitry Andric computeIncomingVLVTYPE(MBB); 1635fe6060f1SDimitry Andric } 1636fe6060f1SDimitry Andric 163781ad6265SDimitry Andric // Perform partial redundancy elimination of vsetvli transitions. 163881ad6265SDimitry Andric for (MachineBasicBlock &MBB : MF) 163981ad6265SDimitry Andric doPRE(MBB); 164081ad6265SDimitry Andric 1641fe6060f1SDimitry Andric // Phase 3 - add any vsetvli instructions needed in the block. Use the 1642fe6060f1SDimitry Andric // Phase 2 information to avoid adding vsetvlis before the first vector 1643fe6060f1SDimitry Andric // instruction in the block if the VL/VTYPE is satisfied by its 1644fe6060f1SDimitry Andric // predecessors. 1645fe6060f1SDimitry Andric for (MachineBasicBlock &MBB : MF) 1646fe6060f1SDimitry Andric emitVSETVLIs(MBB); 164781ad6265SDimitry Andric 164881ad6265SDimitry Andric // Now that all vsetvlis are explicit, go through and do block local 164981ad6265SDimitry Andric // DSE and peephole based demanded fields based transforms. Note that 165081ad6265SDimitry Andric // this *must* be done outside the main dataflow so long as we allow 165181ad6265SDimitry Andric // any cross block analysis within the dataflow. We can't have both 165281ad6265SDimitry Andric // demanded fields based mutation and non-local analysis in the 165381ad6265SDimitry Andric // dataflow at the same time without introducing inconsistencies. 165481ad6265SDimitry Andric for (MachineBasicBlock &MBB : MF) 165581ad6265SDimitry Andric doLocalPostpass(MBB); 165681ad6265SDimitry Andric 165781ad6265SDimitry Andric // Insert PseudoReadVL after VLEFF/VLSEGFF and replace it with the vl output 165881ad6265SDimitry Andric // of VLEFF/VLSEGFF. 165981ad6265SDimitry Andric for (MachineBasicBlock &MBB : MF) 166081ad6265SDimitry Andric insertReadVL(MBB); 1661fe6060f1SDimitry Andric 166281ad6265SDimitry Andric BlockInfo.clear(); 1663fe6060f1SDimitry Andric return HaveVectorOp; 1664fe6060f1SDimitry Andric } 1665fe6060f1SDimitry Andric 1666fe6060f1SDimitry Andric /// Returns an instance of the Insert VSETVLI pass. 1667fe6060f1SDimitry Andric FunctionPass *llvm::createRISCVInsertVSETVLIPass() { 1668fe6060f1SDimitry Andric return new RISCVInsertVSETVLI(); 1669fe6060f1SDimitry Andric } 1670