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" 35*06c3fb27SDimitry 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 70bdd1243dSDimitry Andric static uint16_t getRVVMCOpcode(uint16_t RVVPseudoOpcode) { 71bdd1243dSDimitry Andric const RISCVVPseudosTable::PseudoInfo *RVV = 72bdd1243dSDimitry Andric RISCVVPseudosTable::getPseudoInfo(RVVPseudoOpcode); 73bdd1243dSDimitry Andric if (!RVV) 74bdd1243dSDimitry Andric return 0; 75bdd1243dSDimitry Andric return RVV->BaseInstr; 76bdd1243dSDimitry Andric } 77bdd1243dSDimitry Andric 7804eeddc0SDimitry Andric static bool isScalarMoveInstr(const MachineInstr &MI) { 79bdd1243dSDimitry Andric switch (getRVVMCOpcode(MI.getOpcode())) { 8004eeddc0SDimitry Andric default: 8104eeddc0SDimitry Andric return false; 82bdd1243dSDimitry Andric case RISCV::VMV_S_X: 83bdd1243dSDimitry Andric case RISCV::VFMV_S_F: 8404eeddc0SDimitry Andric return true; 8504eeddc0SDimitry Andric } 8604eeddc0SDimitry Andric } 8704eeddc0SDimitry Andric 88*06c3fb27SDimitry Andric static bool isScalarSplatInstr(const MachineInstr &MI) { 89*06c3fb27SDimitry Andric switch (getRVVMCOpcode(MI.getOpcode())) { 90*06c3fb27SDimitry Andric default: 91*06c3fb27SDimitry Andric return false; 92*06c3fb27SDimitry Andric case RISCV::VMV_V_I: 93*06c3fb27SDimitry Andric case RISCV::VMV_V_X: 94*06c3fb27SDimitry Andric case RISCV::VFMV_V_F: 95*06c3fb27SDimitry Andric return true; 96*06c3fb27SDimitry Andric } 97*06c3fb27SDimitry Andric } 98*06c3fb27SDimitry Andric 99*06c3fb27SDimitry Andric static bool isVSlideInstr(const MachineInstr &MI) { 100*06c3fb27SDimitry Andric switch (getRVVMCOpcode(MI.getOpcode())) { 101*06c3fb27SDimitry Andric default: 102*06c3fb27SDimitry Andric return false; 103*06c3fb27SDimitry Andric case RISCV::VSLIDEDOWN_VX: 104*06c3fb27SDimitry Andric case RISCV::VSLIDEDOWN_VI: 105*06c3fb27SDimitry Andric case RISCV::VSLIDEUP_VX: 106*06c3fb27SDimitry Andric case RISCV::VSLIDEUP_VI: 107*06c3fb27SDimitry Andric return true; 108*06c3fb27SDimitry Andric } 109*06c3fb27SDimitry Andric } 110*06c3fb27SDimitry Andric 111bdd1243dSDimitry Andric /// Get the EEW for a load or store instruction. Return std::nullopt if MI is 112bdd1243dSDimitry Andric /// not a load or store which ignores SEW. 113bdd1243dSDimitry Andric static std::optional<unsigned> getEEWForLoadStore(const MachineInstr &MI) { 114bdd1243dSDimitry Andric switch (getRVVMCOpcode(MI.getOpcode())) { 115349cc55cSDimitry Andric default: 116bdd1243dSDimitry Andric return std::nullopt; 117bdd1243dSDimitry Andric case RISCV::VLE8_V: 118bdd1243dSDimitry Andric case RISCV::VLSE8_V: 119bdd1243dSDimitry Andric case RISCV::VSE8_V: 120bdd1243dSDimitry Andric case RISCV::VSSE8_V: 12181ad6265SDimitry Andric return 8; 122bdd1243dSDimitry Andric case RISCV::VLE16_V: 123bdd1243dSDimitry Andric case RISCV::VLSE16_V: 124bdd1243dSDimitry Andric case RISCV::VSE16_V: 125bdd1243dSDimitry Andric case RISCV::VSSE16_V: 12681ad6265SDimitry Andric return 16; 127bdd1243dSDimitry Andric case RISCV::VLE32_V: 128bdd1243dSDimitry Andric case RISCV::VLSE32_V: 129bdd1243dSDimitry Andric case RISCV::VSE32_V: 130bdd1243dSDimitry Andric case RISCV::VSSE32_V: 13181ad6265SDimitry Andric return 32; 132bdd1243dSDimitry Andric case RISCV::VLE64_V: 133bdd1243dSDimitry Andric case RISCV::VLSE64_V: 134bdd1243dSDimitry Andric case RISCV::VSE64_V: 135bdd1243dSDimitry Andric case RISCV::VSSE64_V: 13681ad6265SDimitry Andric return 64; 13781ad6265SDimitry Andric } 138349cc55cSDimitry Andric } 139349cc55cSDimitry Andric 14081ad6265SDimitry Andric /// Return true if this is an operation on mask registers. Note that 14181ad6265SDimitry Andric /// this includes both arithmetic/logical ops and load/store (vlm/vsm). 14281ad6265SDimitry Andric static bool isMaskRegOp(const MachineInstr &MI) { 143bdd1243dSDimitry Andric if (!RISCVII::hasSEWOp(MI.getDesc().TSFlags)) 144bdd1243dSDimitry Andric return false; 14581ad6265SDimitry Andric const unsigned Log2SEW = MI.getOperand(getSEWOpNum(MI)).getImm(); 14681ad6265SDimitry Andric // A Log2SEW of 0 is an operation on mask registers only. 14781ad6265SDimitry Andric return Log2SEW == 0; 14881ad6265SDimitry Andric } 14981ad6265SDimitry Andric 150*06c3fb27SDimitry Andric /// Return true if the inactive elements in the result are entirely undefined. 151*06c3fb27SDimitry Andric /// Note that this is different from "agnostic" as defined by the vector 152*06c3fb27SDimitry Andric /// specification. Agnostic requires each lane to either be undisturbed, or 153*06c3fb27SDimitry Andric /// take the value -1; no other value is allowed. 154*06c3fb27SDimitry Andric static bool hasUndefinedMergeOp(const MachineInstr &MI, 155*06c3fb27SDimitry Andric const MachineRegisterInfo &MRI) { 156*06c3fb27SDimitry Andric 157*06c3fb27SDimitry Andric unsigned UseOpIdx; 158*06c3fb27SDimitry Andric if (!MI.isRegTiedToUseOperand(0, &UseOpIdx)) 159*06c3fb27SDimitry Andric // If there is no passthrough operand, then the pass through 160*06c3fb27SDimitry Andric // lanes are undefined. 161*06c3fb27SDimitry Andric return true; 162*06c3fb27SDimitry Andric 163*06c3fb27SDimitry Andric // If the tied operand is an IMPLICIT_DEF (or a REG_SEQUENCE whose operands 164*06c3fb27SDimitry Andric // are solely IMPLICIT_DEFS), the pass through lanes are undefined. 165*06c3fb27SDimitry Andric const MachineOperand &UseMO = MI.getOperand(UseOpIdx); 166*06c3fb27SDimitry Andric if (MachineInstr *UseMI = MRI.getVRegDef(UseMO.getReg())) { 167*06c3fb27SDimitry Andric if (UseMI->isImplicitDef()) 168*06c3fb27SDimitry Andric return true; 169*06c3fb27SDimitry Andric 170*06c3fb27SDimitry Andric if (UseMI->isRegSequence()) { 171*06c3fb27SDimitry Andric for (unsigned i = 1, e = UseMI->getNumOperands(); i < e; i += 2) { 172*06c3fb27SDimitry Andric MachineInstr *SourceMI = MRI.getVRegDef(UseMI->getOperand(i).getReg()); 173*06c3fb27SDimitry Andric if (!SourceMI || !SourceMI->isImplicitDef()) 174*06c3fb27SDimitry Andric return false; 175*06c3fb27SDimitry Andric } 176*06c3fb27SDimitry Andric return true; 177*06c3fb27SDimitry Andric } 178*06c3fb27SDimitry Andric } 179*06c3fb27SDimitry Andric return false; 180*06c3fb27SDimitry Andric } 181*06c3fb27SDimitry Andric 18281ad6265SDimitry Andric /// Which subfields of VL or VTYPE have values we need to preserve? 18381ad6265SDimitry Andric struct DemandedFields { 184bdd1243dSDimitry Andric // Some unknown property of VL is used. If demanded, must preserve entire 185bdd1243dSDimitry Andric // value. 186bdd1243dSDimitry Andric bool VLAny = false; 187bdd1243dSDimitry Andric // Only zero vs non-zero is used. If demanded, can change non-zero values. 188bdd1243dSDimitry Andric bool VLZeroness = false; 189*06c3fb27SDimitry Andric // What properties of SEW we need to preserve. 190*06c3fb27SDimitry Andric enum : uint8_t { 191*06c3fb27SDimitry Andric SEWEqual = 2, // The exact value of SEW needs to be preserved. 192*06c3fb27SDimitry Andric SEWGreaterThanOrEqual = 1, // SEW can be changed as long as it's greater 193*06c3fb27SDimitry Andric // than or equal to the original value. 194*06c3fb27SDimitry Andric SEWNone = 0 // We don't need to preserve SEW at all. 195*06c3fb27SDimitry Andric } SEW = SEWNone; 19681ad6265SDimitry Andric bool LMUL = false; 19781ad6265SDimitry Andric bool SEWLMULRatio = false; 19881ad6265SDimitry Andric bool TailPolicy = false; 19981ad6265SDimitry Andric bool MaskPolicy = false; 20081ad6265SDimitry Andric 20181ad6265SDimitry Andric // Return true if any part of VTYPE was used 202bdd1243dSDimitry Andric bool usedVTYPE() const { 20381ad6265SDimitry Andric return SEW || LMUL || SEWLMULRatio || TailPolicy || MaskPolicy; 20481ad6265SDimitry Andric } 20581ad6265SDimitry Andric 206bdd1243dSDimitry Andric // Return true if any property of VL was used 207bdd1243dSDimitry Andric bool usedVL() { 208bdd1243dSDimitry Andric return VLAny || VLZeroness; 209bdd1243dSDimitry Andric } 210bdd1243dSDimitry Andric 21181ad6265SDimitry Andric // Mark all VTYPE subfields and properties as demanded 21281ad6265SDimitry Andric void demandVTYPE() { 213*06c3fb27SDimitry Andric SEW = SEWEqual; 21481ad6265SDimitry Andric LMUL = true; 21581ad6265SDimitry Andric SEWLMULRatio = true; 21681ad6265SDimitry Andric TailPolicy = true; 21781ad6265SDimitry Andric MaskPolicy = true; 21881ad6265SDimitry Andric } 219bdd1243dSDimitry Andric 220bdd1243dSDimitry Andric // Mark all VL properties as demanded 221bdd1243dSDimitry Andric void demandVL() { 222bdd1243dSDimitry Andric VLAny = true; 223bdd1243dSDimitry Andric VLZeroness = true; 224bdd1243dSDimitry Andric } 225bdd1243dSDimitry Andric 226bdd1243dSDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 227bdd1243dSDimitry Andric /// Support for debugging, callable in GDB: V->dump() 228bdd1243dSDimitry Andric LLVM_DUMP_METHOD void dump() const { 229bdd1243dSDimitry Andric print(dbgs()); 230bdd1243dSDimitry Andric dbgs() << "\n"; 231bdd1243dSDimitry Andric } 232bdd1243dSDimitry Andric 233bdd1243dSDimitry Andric /// Implement operator<<. 234bdd1243dSDimitry Andric void print(raw_ostream &OS) const { 235bdd1243dSDimitry Andric OS << "{"; 236bdd1243dSDimitry Andric OS << "VLAny=" << VLAny << ", "; 237bdd1243dSDimitry Andric OS << "VLZeroness=" << VLZeroness << ", "; 238*06c3fb27SDimitry Andric OS << "SEW="; 239*06c3fb27SDimitry Andric switch (SEW) { 240*06c3fb27SDimitry Andric case SEWEqual: 241*06c3fb27SDimitry Andric OS << "SEWEqual"; 242*06c3fb27SDimitry Andric break; 243*06c3fb27SDimitry Andric case SEWGreaterThanOrEqual: 244*06c3fb27SDimitry Andric OS << "SEWGreaterThanOrEqual"; 245*06c3fb27SDimitry Andric break; 246*06c3fb27SDimitry Andric case SEWNone: 247*06c3fb27SDimitry Andric OS << "SEWNone"; 248*06c3fb27SDimitry Andric break; 249*06c3fb27SDimitry Andric }; 250*06c3fb27SDimitry Andric OS << ", "; 251bdd1243dSDimitry Andric OS << "LMUL=" << LMUL << ", "; 252bdd1243dSDimitry Andric OS << "SEWLMULRatio=" << SEWLMULRatio << ", "; 253bdd1243dSDimitry Andric OS << "TailPolicy=" << TailPolicy << ", "; 254bdd1243dSDimitry Andric OS << "MaskPolicy=" << MaskPolicy; 255bdd1243dSDimitry Andric OS << "}"; 256bdd1243dSDimitry Andric } 257bdd1243dSDimitry Andric #endif 25881ad6265SDimitry Andric }; 25981ad6265SDimitry Andric 260bdd1243dSDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 261bdd1243dSDimitry Andric LLVM_ATTRIBUTE_USED 262bdd1243dSDimitry Andric inline raw_ostream &operator<<(raw_ostream &OS, const DemandedFields &DF) { 263bdd1243dSDimitry Andric DF.print(OS); 264bdd1243dSDimitry Andric return OS; 265bdd1243dSDimitry Andric } 266bdd1243dSDimitry Andric #endif 267bdd1243dSDimitry Andric 268*06c3fb27SDimitry Andric /// Return true if moving from CurVType to NewVType is 269*06c3fb27SDimitry Andric /// indistinguishable from the perspective of an instruction (or set 270*06c3fb27SDimitry Andric /// of instructions) which use only the Used subfields and properties. 271*06c3fb27SDimitry Andric static bool areCompatibleVTYPEs(uint64_t CurVType, uint64_t NewVType, 27281ad6265SDimitry Andric const DemandedFields &Used) { 273*06c3fb27SDimitry Andric if (Used.SEW == DemandedFields::SEWEqual && 274*06c3fb27SDimitry Andric RISCVVType::getSEW(CurVType) != RISCVVType::getSEW(NewVType)) 275*06c3fb27SDimitry Andric return false; 276*06c3fb27SDimitry Andric 277*06c3fb27SDimitry Andric if (Used.SEW == DemandedFields::SEWGreaterThanOrEqual && 278*06c3fb27SDimitry Andric RISCVVType::getSEW(NewVType) < RISCVVType::getSEW(CurVType)) 27981ad6265SDimitry Andric return false; 28081ad6265SDimitry Andric 28181ad6265SDimitry Andric if (Used.LMUL && 282*06c3fb27SDimitry Andric RISCVVType::getVLMUL(CurVType) != RISCVVType::getVLMUL(NewVType)) 28381ad6265SDimitry Andric return false; 28481ad6265SDimitry Andric 28581ad6265SDimitry Andric if (Used.SEWLMULRatio) { 286*06c3fb27SDimitry Andric auto Ratio1 = RISCVVType::getSEWLMULRatio(RISCVVType::getSEW(CurVType), 287*06c3fb27SDimitry Andric RISCVVType::getVLMUL(CurVType)); 288*06c3fb27SDimitry Andric auto Ratio2 = RISCVVType::getSEWLMULRatio(RISCVVType::getSEW(NewVType), 289*06c3fb27SDimitry Andric RISCVVType::getVLMUL(NewVType)); 29081ad6265SDimitry Andric if (Ratio1 != Ratio2) 29181ad6265SDimitry Andric return false; 29281ad6265SDimitry Andric } 29381ad6265SDimitry Andric 294*06c3fb27SDimitry Andric if (Used.TailPolicy && RISCVVType::isTailAgnostic(CurVType) != 295*06c3fb27SDimitry Andric RISCVVType::isTailAgnostic(NewVType)) 29681ad6265SDimitry Andric return false; 297*06c3fb27SDimitry Andric if (Used.MaskPolicy && RISCVVType::isMaskAgnostic(CurVType) != 298*06c3fb27SDimitry Andric RISCVVType::isMaskAgnostic(NewVType)) 29981ad6265SDimitry Andric return false; 30081ad6265SDimitry Andric return true; 30181ad6265SDimitry Andric } 30281ad6265SDimitry Andric 30381ad6265SDimitry Andric /// Return the fields and properties demanded by the provided instruction. 304*06c3fb27SDimitry Andric DemandedFields getDemanded(const MachineInstr &MI, 305*06c3fb27SDimitry Andric const MachineRegisterInfo *MRI) { 30681ad6265SDimitry Andric // Warning: This function has to work on both the lowered (i.e. post 30781ad6265SDimitry Andric // emitVSETVLIs) and pre-lowering forms. The main implication of this is 30881ad6265SDimitry Andric // that it can't use the value of a SEW, VL, or Policy operand as they might 30981ad6265SDimitry Andric // be stale after lowering. 31081ad6265SDimitry Andric 31181ad6265SDimitry Andric // Most instructions don't use any of these subfeilds. 31281ad6265SDimitry Andric DemandedFields Res; 31381ad6265SDimitry Andric // Start conservative if registers are used 31481ad6265SDimitry Andric if (MI.isCall() || MI.isInlineAsm() || MI.readsRegister(RISCV::VL)) 315*06c3fb27SDimitry Andric Res.demandVL(); 31681ad6265SDimitry Andric if (MI.isCall() || MI.isInlineAsm() || MI.readsRegister(RISCV::VTYPE)) 31781ad6265SDimitry Andric Res.demandVTYPE(); 31881ad6265SDimitry Andric // Start conservative on the unlowered form too 31981ad6265SDimitry Andric uint64_t TSFlags = MI.getDesc().TSFlags; 32081ad6265SDimitry Andric if (RISCVII::hasSEWOp(TSFlags)) { 32181ad6265SDimitry Andric Res.demandVTYPE(); 32281ad6265SDimitry Andric if (RISCVII::hasVLOp(TSFlags)) 323bdd1243dSDimitry Andric Res.demandVL(); 324bdd1243dSDimitry Andric 325bdd1243dSDimitry Andric // Behavior is independent of mask policy. 326bdd1243dSDimitry Andric if (!RISCVII::usesMaskPolicy(TSFlags)) 327bdd1243dSDimitry Andric Res.MaskPolicy = false; 32881ad6265SDimitry Andric } 32981ad6265SDimitry Andric 33081ad6265SDimitry Andric // Loads and stores with implicit EEW do not demand SEW or LMUL directly. 33181ad6265SDimitry Andric // They instead demand the ratio of the two which is used in computing 33281ad6265SDimitry Andric // EMUL, but which allows us the flexibility to change SEW and LMUL 33381ad6265SDimitry Andric // provided we don't change the ratio. 33481ad6265SDimitry Andric // Note: We assume that the instructions initial SEW is the EEW encoded 33581ad6265SDimitry Andric // in the opcode. This is asserted when constructing the VSETVLIInfo. 33681ad6265SDimitry Andric if (getEEWForLoadStore(MI)) { 337*06c3fb27SDimitry Andric Res.SEW = DemandedFields::SEWNone; 33881ad6265SDimitry Andric Res.LMUL = false; 33981ad6265SDimitry Andric } 34081ad6265SDimitry Andric 34181ad6265SDimitry Andric // Store instructions don't use the policy fields. 34281ad6265SDimitry Andric if (RISCVII::hasSEWOp(TSFlags) && MI.getNumExplicitDefs() == 0) { 34381ad6265SDimitry Andric Res.TailPolicy = false; 34481ad6265SDimitry Andric Res.MaskPolicy = false; 34581ad6265SDimitry Andric } 34681ad6265SDimitry Andric 34781ad6265SDimitry Andric // If this is a mask reg operation, it only cares about VLMAX. 34881ad6265SDimitry Andric // TODO: Possible extensions to this logic 34981ad6265SDimitry Andric // * Probably ok if available VLMax is larger than demanded 35081ad6265SDimitry Andric // * The policy bits can probably be ignored.. 35181ad6265SDimitry Andric if (isMaskRegOp(MI)) { 352*06c3fb27SDimitry Andric Res.SEW = DemandedFields::SEWNone; 35381ad6265SDimitry Andric Res.LMUL = false; 35481ad6265SDimitry Andric } 35581ad6265SDimitry Andric 356bdd1243dSDimitry Andric // For vmv.s.x and vfmv.s.f, there are only two behaviors, VL = 0 and VL > 0. 357bdd1243dSDimitry Andric if (isScalarMoveInstr(MI)) { 358bdd1243dSDimitry Andric Res.LMUL = false; 359bdd1243dSDimitry Andric Res.SEWLMULRatio = false; 360bdd1243dSDimitry Andric Res.VLAny = false; 361*06c3fb27SDimitry Andric // For vmv.s.x and vfmv.s.f, if the merge operand is *undefined*, we don't 362*06c3fb27SDimitry Andric // need to preserve any other bits and are thus compatible with any larger, 363*06c3fb27SDimitry Andric // etype and can disregard policy bits. Warning: It's tempting to try doing 364*06c3fb27SDimitry Andric // this for any tail agnostic operation, but we can't as TA requires 365*06c3fb27SDimitry Andric // tail lanes to either be the original value or -1. We are writing 366*06c3fb27SDimitry Andric // unknown bits to the lanes here. 367*06c3fb27SDimitry Andric if (hasUndefinedMergeOp(MI, *MRI)) { 368*06c3fb27SDimitry Andric Res.SEW = DemandedFields::SEWGreaterThanOrEqual; 369*06c3fb27SDimitry Andric Res.TailPolicy = false; 370*06c3fb27SDimitry Andric } 371bdd1243dSDimitry Andric } 372bdd1243dSDimitry Andric 37381ad6265SDimitry Andric return Res; 37481ad6265SDimitry Andric } 37581ad6265SDimitry Andric 37681ad6265SDimitry Andric /// Defines the abstract state with which the forward dataflow models the 37781ad6265SDimitry Andric /// values of the VL and VTYPE registers after insertion. 37881ad6265SDimitry Andric class VSETVLIInfo { 37981ad6265SDimitry Andric union { 38081ad6265SDimitry Andric Register AVLReg; 38181ad6265SDimitry Andric unsigned AVLImm; 38281ad6265SDimitry Andric }; 38381ad6265SDimitry Andric 38481ad6265SDimitry Andric enum : uint8_t { 38581ad6265SDimitry Andric Uninitialized, 38681ad6265SDimitry Andric AVLIsReg, 38781ad6265SDimitry Andric AVLIsImm, 38881ad6265SDimitry Andric Unknown, 38981ad6265SDimitry Andric } State = Uninitialized; 39081ad6265SDimitry Andric 39181ad6265SDimitry Andric // Fields from VTYPE. 39281ad6265SDimitry Andric RISCVII::VLMUL VLMul = RISCVII::LMUL_1; 39381ad6265SDimitry Andric uint8_t SEW = 0; 39481ad6265SDimitry Andric uint8_t TailAgnostic : 1; 39581ad6265SDimitry Andric uint8_t MaskAgnostic : 1; 39681ad6265SDimitry Andric uint8_t SEWLMULRatioOnly : 1; 39781ad6265SDimitry Andric 39881ad6265SDimitry Andric public: 39981ad6265SDimitry Andric VSETVLIInfo() 40081ad6265SDimitry Andric : AVLImm(0), TailAgnostic(false), MaskAgnostic(false), 40181ad6265SDimitry Andric SEWLMULRatioOnly(false) {} 40281ad6265SDimitry Andric 40381ad6265SDimitry Andric static VSETVLIInfo getUnknown() { 40481ad6265SDimitry Andric VSETVLIInfo Info; 40581ad6265SDimitry Andric Info.setUnknown(); 40681ad6265SDimitry Andric return Info; 40781ad6265SDimitry Andric } 40881ad6265SDimitry Andric 40981ad6265SDimitry Andric bool isValid() const { return State != Uninitialized; } 41081ad6265SDimitry Andric void setUnknown() { State = Unknown; } 41181ad6265SDimitry Andric bool isUnknown() const { return State == Unknown; } 41281ad6265SDimitry Andric 41381ad6265SDimitry Andric void setAVLReg(Register Reg) { 41481ad6265SDimitry Andric AVLReg = Reg; 41581ad6265SDimitry Andric State = AVLIsReg; 41681ad6265SDimitry Andric } 41781ad6265SDimitry Andric 41881ad6265SDimitry Andric void setAVLImm(unsigned Imm) { 41981ad6265SDimitry Andric AVLImm = Imm; 42081ad6265SDimitry Andric State = AVLIsImm; 42181ad6265SDimitry Andric } 42281ad6265SDimitry Andric 42381ad6265SDimitry Andric bool hasAVLImm() const { return State == AVLIsImm; } 42481ad6265SDimitry Andric bool hasAVLReg() const { return State == AVLIsReg; } 42581ad6265SDimitry Andric Register getAVLReg() const { 42681ad6265SDimitry Andric assert(hasAVLReg()); 42781ad6265SDimitry Andric return AVLReg; 42881ad6265SDimitry Andric } 42981ad6265SDimitry Andric unsigned getAVLImm() const { 43081ad6265SDimitry Andric assert(hasAVLImm()); 43181ad6265SDimitry Andric return AVLImm; 43281ad6265SDimitry Andric } 43381ad6265SDimitry Andric 43481ad6265SDimitry Andric unsigned getSEW() const { return SEW; } 43581ad6265SDimitry Andric RISCVII::VLMUL getVLMUL() const { return VLMul; } 43681ad6265SDimitry Andric 437*06c3fb27SDimitry Andric bool hasNonZeroAVL(const MachineRegisterInfo &MRI) const { 43881ad6265SDimitry Andric if (hasAVLImm()) 43981ad6265SDimitry Andric return getAVLImm() > 0; 440*06c3fb27SDimitry Andric if (hasAVLReg()) { 441*06c3fb27SDimitry Andric if (getAVLReg() == RISCV::X0) 442*06c3fb27SDimitry Andric return true; 443*06c3fb27SDimitry Andric if (MachineInstr *MI = MRI.getVRegDef(getAVLReg()); 444*06c3fb27SDimitry Andric MI && MI->getOpcode() == RISCV::ADDI && 445*06c3fb27SDimitry Andric MI->getOperand(1).isReg() && MI->getOperand(2).isImm() && 446*06c3fb27SDimitry Andric MI->getOperand(1).getReg() == RISCV::X0 && 447*06c3fb27SDimitry Andric MI->getOperand(2).getImm() != 0) 448*06c3fb27SDimitry Andric return true; 449*06c3fb27SDimitry Andric return false; 450*06c3fb27SDimitry Andric } 45181ad6265SDimitry Andric return false; 45281ad6265SDimitry Andric } 45381ad6265SDimitry Andric 454*06c3fb27SDimitry Andric bool hasEquallyZeroAVL(const VSETVLIInfo &Other, 455*06c3fb27SDimitry Andric const MachineRegisterInfo &MRI) const { 456bdd1243dSDimitry Andric if (hasSameAVL(Other)) 457bdd1243dSDimitry Andric return true; 458*06c3fb27SDimitry Andric return (hasNonZeroAVL(MRI) && Other.hasNonZeroAVL(MRI)); 459bdd1243dSDimitry Andric } 460bdd1243dSDimitry Andric 46181ad6265SDimitry Andric bool hasSameAVL(const VSETVLIInfo &Other) const { 46281ad6265SDimitry Andric if (hasAVLReg() && Other.hasAVLReg()) 46381ad6265SDimitry Andric return getAVLReg() == Other.getAVLReg(); 46481ad6265SDimitry Andric 46581ad6265SDimitry Andric if (hasAVLImm() && Other.hasAVLImm()) 46681ad6265SDimitry Andric return getAVLImm() == Other.getAVLImm(); 46781ad6265SDimitry Andric 46881ad6265SDimitry Andric return false; 46981ad6265SDimitry Andric } 47081ad6265SDimitry Andric 47181ad6265SDimitry Andric void setVTYPE(unsigned VType) { 47281ad6265SDimitry Andric assert(isValid() && !isUnknown() && 47381ad6265SDimitry Andric "Can't set VTYPE for uninitialized or unknown"); 47481ad6265SDimitry Andric VLMul = RISCVVType::getVLMUL(VType); 47581ad6265SDimitry Andric SEW = RISCVVType::getSEW(VType); 47681ad6265SDimitry Andric TailAgnostic = RISCVVType::isTailAgnostic(VType); 47781ad6265SDimitry Andric MaskAgnostic = RISCVVType::isMaskAgnostic(VType); 47881ad6265SDimitry Andric } 47981ad6265SDimitry Andric void setVTYPE(RISCVII::VLMUL L, unsigned S, bool TA, bool MA) { 48081ad6265SDimitry Andric assert(isValid() && !isUnknown() && 48181ad6265SDimitry Andric "Can't set VTYPE for uninitialized or unknown"); 48281ad6265SDimitry Andric VLMul = L; 48381ad6265SDimitry Andric SEW = S; 48481ad6265SDimitry Andric TailAgnostic = TA; 48581ad6265SDimitry Andric MaskAgnostic = MA; 48681ad6265SDimitry Andric } 48781ad6265SDimitry Andric 48881ad6265SDimitry Andric unsigned encodeVTYPE() const { 48981ad6265SDimitry Andric assert(isValid() && !isUnknown() && !SEWLMULRatioOnly && 49081ad6265SDimitry Andric "Can't encode VTYPE for uninitialized or unknown"); 49181ad6265SDimitry Andric return RISCVVType::encodeVTYPE(VLMul, SEW, TailAgnostic, MaskAgnostic); 49281ad6265SDimitry Andric } 49381ad6265SDimitry Andric 49481ad6265SDimitry Andric bool hasSEWLMULRatioOnly() const { return SEWLMULRatioOnly; } 49581ad6265SDimitry Andric 49681ad6265SDimitry Andric bool hasSameVTYPE(const VSETVLIInfo &Other) const { 49781ad6265SDimitry Andric assert(isValid() && Other.isValid() && 49881ad6265SDimitry Andric "Can't compare invalid VSETVLIInfos"); 49981ad6265SDimitry Andric assert(!isUnknown() && !Other.isUnknown() && 50081ad6265SDimitry Andric "Can't compare VTYPE in unknown state"); 50181ad6265SDimitry Andric assert(!SEWLMULRatioOnly && !Other.SEWLMULRatioOnly && 50281ad6265SDimitry Andric "Can't compare when only LMUL/SEW ratio is valid."); 50381ad6265SDimitry Andric return std::tie(VLMul, SEW, TailAgnostic, MaskAgnostic) == 50481ad6265SDimitry Andric std::tie(Other.VLMul, Other.SEW, Other.TailAgnostic, 50581ad6265SDimitry Andric Other.MaskAgnostic); 50681ad6265SDimitry Andric } 50781ad6265SDimitry Andric 50881ad6265SDimitry Andric unsigned getSEWLMULRatio() const { 50981ad6265SDimitry Andric assert(isValid() && !isUnknown() && 51081ad6265SDimitry Andric "Can't use VTYPE for uninitialized or unknown"); 511bdd1243dSDimitry Andric return RISCVVType::getSEWLMULRatio(SEW, VLMul); 51281ad6265SDimitry Andric } 51381ad6265SDimitry Andric 51481ad6265SDimitry Andric // Check if the VTYPE for these two VSETVLIInfos produce the same VLMAX. 51581ad6265SDimitry Andric // Note that having the same VLMAX ensures that both share the same 51681ad6265SDimitry Andric // function from AVL to VL; that is, they must produce the same VL value 51781ad6265SDimitry Andric // for any given AVL value. 51881ad6265SDimitry Andric bool hasSameVLMAX(const VSETVLIInfo &Other) const { 51981ad6265SDimitry Andric assert(isValid() && Other.isValid() && 52081ad6265SDimitry Andric "Can't compare invalid VSETVLIInfos"); 52181ad6265SDimitry Andric assert(!isUnknown() && !Other.isUnknown() && 52281ad6265SDimitry Andric "Can't compare VTYPE in unknown state"); 52381ad6265SDimitry Andric return getSEWLMULRatio() == Other.getSEWLMULRatio(); 52481ad6265SDimitry Andric } 52581ad6265SDimitry Andric 526bdd1243dSDimitry Andric bool hasCompatibleVTYPE(const DemandedFields &Used, 52781ad6265SDimitry Andric const VSETVLIInfo &Require) const { 528*06c3fb27SDimitry Andric return areCompatibleVTYPEs(Require.encodeVTYPE(), encodeVTYPE(), Used); 52981ad6265SDimitry Andric } 53081ad6265SDimitry Andric 53181ad6265SDimitry Andric // Determine whether the vector instructions requirements represented by 53281ad6265SDimitry Andric // Require are compatible with the previous vsetvli instruction represented 53381ad6265SDimitry Andric // by this. MI is the instruction whose requirements we're considering. 534*06c3fb27SDimitry Andric bool isCompatible(const DemandedFields &Used, const VSETVLIInfo &Require, 535*06c3fb27SDimitry Andric const MachineRegisterInfo &MRI) const { 53681ad6265SDimitry Andric assert(isValid() && Require.isValid() && 53781ad6265SDimitry Andric "Can't compare invalid VSETVLIInfos"); 53881ad6265SDimitry Andric assert(!Require.SEWLMULRatioOnly && 53981ad6265SDimitry Andric "Expected a valid VTYPE for instruction!"); 54081ad6265SDimitry Andric // Nothing is compatible with Unknown. 54181ad6265SDimitry Andric if (isUnknown() || Require.isUnknown()) 54281ad6265SDimitry Andric return false; 54381ad6265SDimitry Andric 54481ad6265SDimitry Andric // If only our VLMAX ratio is valid, then this isn't compatible. 54581ad6265SDimitry Andric if (SEWLMULRatioOnly) 54681ad6265SDimitry Andric return false; 54781ad6265SDimitry Andric 54881ad6265SDimitry Andric // If the instruction doesn't need an AVLReg and the SEW matches, consider 54981ad6265SDimitry Andric // it compatible. 55081ad6265SDimitry Andric if (Require.hasAVLReg() && Require.AVLReg == RISCV::NoRegister) 55181ad6265SDimitry Andric if (SEW == Require.SEW) 55281ad6265SDimitry Andric return true; 55381ad6265SDimitry Andric 554bdd1243dSDimitry Andric if (Used.VLAny && !hasSameAVL(Require)) 555bdd1243dSDimitry Andric return false; 556bdd1243dSDimitry Andric 557*06c3fb27SDimitry Andric if (Used.VLZeroness && !hasEquallyZeroAVL(Require, MRI)) 558bdd1243dSDimitry Andric return false; 559bdd1243dSDimitry Andric 560*06c3fb27SDimitry Andric return hasCompatibleVTYPE(Used, Require); 56181ad6265SDimitry Andric } 56281ad6265SDimitry Andric 56381ad6265SDimitry Andric bool operator==(const VSETVLIInfo &Other) const { 56481ad6265SDimitry Andric // Uninitialized is only equal to another Uninitialized. 56581ad6265SDimitry Andric if (!isValid()) 56681ad6265SDimitry Andric return !Other.isValid(); 56781ad6265SDimitry Andric if (!Other.isValid()) 56881ad6265SDimitry Andric return !isValid(); 56981ad6265SDimitry Andric 57081ad6265SDimitry Andric // Unknown is only equal to another Unknown. 57181ad6265SDimitry Andric if (isUnknown()) 57281ad6265SDimitry Andric return Other.isUnknown(); 57381ad6265SDimitry Andric if (Other.isUnknown()) 57481ad6265SDimitry Andric return isUnknown(); 57581ad6265SDimitry Andric 57681ad6265SDimitry Andric if (!hasSameAVL(Other)) 57781ad6265SDimitry Andric return false; 57881ad6265SDimitry Andric 57981ad6265SDimitry Andric // If the SEWLMULRatioOnly bits are different, then they aren't equal. 58081ad6265SDimitry Andric if (SEWLMULRatioOnly != Other.SEWLMULRatioOnly) 58181ad6265SDimitry Andric return false; 58281ad6265SDimitry Andric 58381ad6265SDimitry Andric // If only the VLMAX is valid, check that it is the same. 58481ad6265SDimitry Andric if (SEWLMULRatioOnly) 58581ad6265SDimitry Andric return hasSameVLMAX(Other); 58681ad6265SDimitry Andric 58781ad6265SDimitry Andric // If the full VTYPE is valid, check that it is the same. 58881ad6265SDimitry Andric return hasSameVTYPE(Other); 58981ad6265SDimitry Andric } 59081ad6265SDimitry Andric 59181ad6265SDimitry Andric bool operator!=(const VSETVLIInfo &Other) const { 59281ad6265SDimitry Andric return !(*this == Other); 59381ad6265SDimitry Andric } 59481ad6265SDimitry Andric 59581ad6265SDimitry Andric // Calculate the VSETVLIInfo visible to a block assuming this and Other are 59681ad6265SDimitry Andric // both predecessors. 59781ad6265SDimitry Andric VSETVLIInfo intersect(const VSETVLIInfo &Other) const { 59881ad6265SDimitry Andric // If the new value isn't valid, ignore it. 59981ad6265SDimitry Andric if (!Other.isValid()) 60081ad6265SDimitry Andric return *this; 60181ad6265SDimitry Andric 60281ad6265SDimitry Andric // If this value isn't valid, this must be the first predecessor, use it. 60381ad6265SDimitry Andric if (!isValid()) 60481ad6265SDimitry Andric return Other; 60581ad6265SDimitry Andric 60681ad6265SDimitry Andric // If either is unknown, the result is unknown. 60781ad6265SDimitry Andric if (isUnknown() || Other.isUnknown()) 60881ad6265SDimitry Andric return VSETVLIInfo::getUnknown(); 60981ad6265SDimitry Andric 61081ad6265SDimitry Andric // If we have an exact, match return this. 61181ad6265SDimitry Andric if (*this == Other) 61281ad6265SDimitry Andric return *this; 61381ad6265SDimitry Andric 61481ad6265SDimitry Andric // Not an exact match, but maybe the AVL and VLMAX are the same. If so, 61581ad6265SDimitry Andric // return an SEW/LMUL ratio only value. 61681ad6265SDimitry Andric if (hasSameAVL(Other) && hasSameVLMAX(Other)) { 61781ad6265SDimitry Andric VSETVLIInfo MergeInfo = *this; 61881ad6265SDimitry Andric MergeInfo.SEWLMULRatioOnly = true; 61981ad6265SDimitry Andric return MergeInfo; 62081ad6265SDimitry Andric } 62181ad6265SDimitry Andric 62281ad6265SDimitry Andric // Otherwise the result is unknown. 62381ad6265SDimitry Andric return VSETVLIInfo::getUnknown(); 62481ad6265SDimitry Andric } 62581ad6265SDimitry Andric 62681ad6265SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 62781ad6265SDimitry Andric /// Support for debugging, callable in GDB: V->dump() 62881ad6265SDimitry Andric LLVM_DUMP_METHOD void dump() const { 62981ad6265SDimitry Andric print(dbgs()); 63081ad6265SDimitry Andric dbgs() << "\n"; 63181ad6265SDimitry Andric } 63281ad6265SDimitry Andric 63381ad6265SDimitry Andric /// Implement operator<<. 63481ad6265SDimitry Andric /// @{ 63581ad6265SDimitry Andric void print(raw_ostream &OS) const { 63681ad6265SDimitry Andric OS << "{"; 63781ad6265SDimitry Andric if (!isValid()) 63881ad6265SDimitry Andric OS << "Uninitialized"; 63981ad6265SDimitry Andric if (isUnknown()) 64081ad6265SDimitry Andric OS << "unknown"; 64181ad6265SDimitry Andric if (hasAVLReg()) 64281ad6265SDimitry Andric OS << "AVLReg=" << (unsigned)AVLReg; 64381ad6265SDimitry Andric if (hasAVLImm()) 64481ad6265SDimitry Andric OS << "AVLImm=" << (unsigned)AVLImm; 64581ad6265SDimitry Andric OS << ", " 64681ad6265SDimitry Andric << "VLMul=" << (unsigned)VLMul << ", " 64781ad6265SDimitry Andric << "SEW=" << (unsigned)SEW << ", " 64881ad6265SDimitry Andric << "TailAgnostic=" << (bool)TailAgnostic << ", " 64981ad6265SDimitry Andric << "MaskAgnostic=" << (bool)MaskAgnostic << ", " 65081ad6265SDimitry Andric << "SEWLMULRatioOnly=" << (bool)SEWLMULRatioOnly << "}"; 65181ad6265SDimitry Andric } 65281ad6265SDimitry Andric #endif 65381ad6265SDimitry Andric }; 65481ad6265SDimitry Andric 65581ad6265SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 65681ad6265SDimitry Andric LLVM_ATTRIBUTE_USED 65781ad6265SDimitry Andric inline raw_ostream &operator<<(raw_ostream &OS, const VSETVLIInfo &V) { 65881ad6265SDimitry Andric V.print(OS); 65981ad6265SDimitry Andric return OS; 66081ad6265SDimitry Andric } 66181ad6265SDimitry Andric #endif 66281ad6265SDimitry Andric 66381ad6265SDimitry Andric struct BlockData { 66481ad6265SDimitry Andric // The VSETVLIInfo that represents the net changes to the VL/VTYPE registers 66581ad6265SDimitry Andric // made by this block. Calculated in Phase 1. 66681ad6265SDimitry Andric VSETVLIInfo Change; 66781ad6265SDimitry Andric 66881ad6265SDimitry Andric // The VSETVLIInfo that represents the VL/VTYPE settings on exit from this 66981ad6265SDimitry Andric // block. Calculated in Phase 2. 67081ad6265SDimitry Andric VSETVLIInfo Exit; 67181ad6265SDimitry Andric 67281ad6265SDimitry Andric // The VSETVLIInfo that represents the VL/VTYPE settings from all predecessor 67381ad6265SDimitry Andric // blocks. Calculated in Phase 2, and used by Phase 3. 67481ad6265SDimitry Andric VSETVLIInfo Pred; 67581ad6265SDimitry Andric 67681ad6265SDimitry Andric // Keeps track of whether the block is already in the queue. 67781ad6265SDimitry Andric bool InQueue = false; 67881ad6265SDimitry Andric 67981ad6265SDimitry Andric BlockData() = default; 68081ad6265SDimitry Andric }; 68181ad6265SDimitry Andric 68281ad6265SDimitry Andric class RISCVInsertVSETVLI : public MachineFunctionPass { 68381ad6265SDimitry Andric const TargetInstrInfo *TII; 68481ad6265SDimitry Andric MachineRegisterInfo *MRI; 68581ad6265SDimitry Andric 68681ad6265SDimitry Andric std::vector<BlockData> BlockInfo; 68781ad6265SDimitry Andric std::queue<const MachineBasicBlock *> WorkList; 68881ad6265SDimitry Andric 68981ad6265SDimitry Andric public: 69081ad6265SDimitry Andric static char ID; 69181ad6265SDimitry Andric 69281ad6265SDimitry Andric RISCVInsertVSETVLI() : MachineFunctionPass(ID) { 69381ad6265SDimitry Andric initializeRISCVInsertVSETVLIPass(*PassRegistry::getPassRegistry()); 69481ad6265SDimitry Andric } 69581ad6265SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 69681ad6265SDimitry Andric 69781ad6265SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 69881ad6265SDimitry Andric AU.setPreservesCFG(); 69981ad6265SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 70081ad6265SDimitry Andric } 70181ad6265SDimitry Andric 70281ad6265SDimitry Andric StringRef getPassName() const override { return RISCV_INSERT_VSETVLI_NAME; } 70381ad6265SDimitry Andric 70481ad6265SDimitry Andric private: 70581ad6265SDimitry Andric bool needVSETVLI(const MachineInstr &MI, const VSETVLIInfo &Require, 70681ad6265SDimitry Andric const VSETVLIInfo &CurInfo) const; 70781ad6265SDimitry Andric bool needVSETVLIPHI(const VSETVLIInfo &Require, 70881ad6265SDimitry Andric const MachineBasicBlock &MBB) const; 70981ad6265SDimitry Andric void insertVSETVLI(MachineBasicBlock &MBB, MachineInstr &MI, 71081ad6265SDimitry Andric const VSETVLIInfo &Info, const VSETVLIInfo &PrevInfo); 71181ad6265SDimitry Andric void insertVSETVLI(MachineBasicBlock &MBB, 71281ad6265SDimitry Andric MachineBasicBlock::iterator InsertPt, DebugLoc DL, 71381ad6265SDimitry Andric const VSETVLIInfo &Info, const VSETVLIInfo &PrevInfo); 71481ad6265SDimitry Andric 71581ad6265SDimitry Andric void transferBefore(VSETVLIInfo &Info, const MachineInstr &MI); 71681ad6265SDimitry Andric void transferAfter(VSETVLIInfo &Info, const MachineInstr &MI); 71781ad6265SDimitry Andric bool computeVLVTYPEChanges(const MachineBasicBlock &MBB); 71881ad6265SDimitry Andric void computeIncomingVLVTYPE(const MachineBasicBlock &MBB); 71981ad6265SDimitry Andric void emitVSETVLIs(MachineBasicBlock &MBB); 72081ad6265SDimitry Andric void doLocalPostpass(MachineBasicBlock &MBB); 72181ad6265SDimitry Andric void doPRE(MachineBasicBlock &MBB); 72281ad6265SDimitry Andric void insertReadVL(MachineBasicBlock &MBB); 72381ad6265SDimitry Andric }; 72481ad6265SDimitry Andric 72581ad6265SDimitry Andric } // end anonymous namespace 72681ad6265SDimitry Andric 72781ad6265SDimitry Andric char RISCVInsertVSETVLI::ID = 0; 72881ad6265SDimitry Andric 72981ad6265SDimitry Andric INITIALIZE_PASS(RISCVInsertVSETVLI, DEBUG_TYPE, RISCV_INSERT_VSETVLI_NAME, 73081ad6265SDimitry Andric false, false) 73181ad6265SDimitry Andric 73281ad6265SDimitry Andric static VSETVLIInfo computeInfoForInstr(const MachineInstr &MI, uint64_t TSFlags, 73381ad6265SDimitry Andric const MachineRegisterInfo *MRI) { 73481ad6265SDimitry Andric VSETVLIInfo InstrInfo; 73581ad6265SDimitry Andric 736*06c3fb27SDimitry Andric bool TailAgnostic = true; 737*06c3fb27SDimitry Andric bool MaskAgnostic = true; 738*06c3fb27SDimitry Andric if (!hasUndefinedMergeOp(MI, *MRI)) { 739bdd1243dSDimitry Andric // Start with undisturbed. 740bdd1243dSDimitry Andric TailAgnostic = false; 741bdd1243dSDimitry Andric MaskAgnostic = false; 742bdd1243dSDimitry Andric 743bdd1243dSDimitry Andric // If there is a policy operand, use it. 74481ad6265SDimitry Andric if (RISCVII::hasVecPolicyOp(TSFlags)) { 74581ad6265SDimitry Andric const MachineOperand &Op = MI.getOperand(MI.getNumExplicitOperands() - 1); 74681ad6265SDimitry Andric uint64_t Policy = Op.getImm(); 74781ad6265SDimitry Andric assert(Policy <= (RISCVII::TAIL_AGNOSTIC | RISCVII::MASK_AGNOSTIC) && 74881ad6265SDimitry Andric "Invalid Policy Value"); 74981ad6265SDimitry Andric TailAgnostic = Policy & RISCVII::TAIL_AGNOSTIC; 75081ad6265SDimitry Andric MaskAgnostic = Policy & RISCVII::MASK_AGNOSTIC; 751bdd1243dSDimitry Andric } 752bdd1243dSDimitry Andric 75381ad6265SDimitry Andric // Some pseudo instructions force a tail agnostic policy despite having a 75481ad6265SDimitry Andric // tied def. 75581ad6265SDimitry Andric if (RISCVII::doesForceTailAgnostic(TSFlags)) 75681ad6265SDimitry Andric TailAgnostic = true; 757bdd1243dSDimitry Andric 758bdd1243dSDimitry Andric if (!RISCVII::usesMaskPolicy(TSFlags)) 759bdd1243dSDimitry Andric MaskAgnostic = true; 76081ad6265SDimitry Andric } 76181ad6265SDimitry Andric 76281ad6265SDimitry Andric RISCVII::VLMUL VLMul = RISCVII::getLMul(TSFlags); 76381ad6265SDimitry Andric 76481ad6265SDimitry Andric unsigned Log2SEW = MI.getOperand(getSEWOpNum(MI)).getImm(); 76581ad6265SDimitry Andric // A Log2SEW of 0 is an operation on mask registers only. 76681ad6265SDimitry Andric unsigned SEW = Log2SEW ? 1 << Log2SEW : 8; 76781ad6265SDimitry Andric assert(RISCVVType::isValidSEW(SEW) && "Unexpected SEW"); 76881ad6265SDimitry Andric 76981ad6265SDimitry Andric if (RISCVII::hasVLOp(TSFlags)) { 77081ad6265SDimitry Andric const MachineOperand &VLOp = MI.getOperand(getVLOpNum(MI)); 77181ad6265SDimitry Andric if (VLOp.isImm()) { 77281ad6265SDimitry Andric int64_t Imm = VLOp.getImm(); 77381ad6265SDimitry Andric // Conver the VLMax sentintel to X0 register. 77481ad6265SDimitry Andric if (Imm == RISCV::VLMaxSentinel) 77581ad6265SDimitry Andric InstrInfo.setAVLReg(RISCV::X0); 77681ad6265SDimitry Andric else 77781ad6265SDimitry Andric InstrInfo.setAVLImm(Imm); 77881ad6265SDimitry Andric } else { 77981ad6265SDimitry Andric InstrInfo.setAVLReg(VLOp.getReg()); 78081ad6265SDimitry Andric } 78181ad6265SDimitry Andric } else { 78281ad6265SDimitry Andric InstrInfo.setAVLReg(RISCV::NoRegister); 78381ad6265SDimitry Andric } 78481ad6265SDimitry Andric #ifndef NDEBUG 785bdd1243dSDimitry Andric if (std::optional<unsigned> EEW = getEEWForLoadStore(MI)) { 78681ad6265SDimitry Andric assert(SEW == EEW && "Initial SEW doesn't match expected EEW"); 78781ad6265SDimitry Andric } 78881ad6265SDimitry Andric #endif 78981ad6265SDimitry Andric InstrInfo.setVTYPE(VLMul, SEW, TailAgnostic, MaskAgnostic); 79081ad6265SDimitry Andric 79181ad6265SDimitry Andric return InstrInfo; 79281ad6265SDimitry Andric } 79381ad6265SDimitry Andric 79481ad6265SDimitry Andric void RISCVInsertVSETVLI::insertVSETVLI(MachineBasicBlock &MBB, MachineInstr &MI, 79581ad6265SDimitry Andric const VSETVLIInfo &Info, 79681ad6265SDimitry Andric const VSETVLIInfo &PrevInfo) { 79781ad6265SDimitry Andric DebugLoc DL = MI.getDebugLoc(); 79881ad6265SDimitry Andric insertVSETVLI(MBB, MachineBasicBlock::iterator(&MI), DL, Info, PrevInfo); 79981ad6265SDimitry Andric } 80081ad6265SDimitry Andric 801*06c3fb27SDimitry Andric // Return a VSETVLIInfo representing the changes made by this VSETVLI or 802*06c3fb27SDimitry Andric // VSETIVLI instruction. 803*06c3fb27SDimitry Andric static VSETVLIInfo getInfoForVSETVLI(const MachineInstr &MI) { 804*06c3fb27SDimitry Andric VSETVLIInfo NewInfo; 805*06c3fb27SDimitry Andric if (MI.getOpcode() == RISCV::PseudoVSETIVLI) { 806*06c3fb27SDimitry Andric NewInfo.setAVLImm(MI.getOperand(1).getImm()); 807*06c3fb27SDimitry Andric } else { 808*06c3fb27SDimitry Andric assert(MI.getOpcode() == RISCV::PseudoVSETVLI || 809*06c3fb27SDimitry Andric MI.getOpcode() == RISCV::PseudoVSETVLIX0); 810*06c3fb27SDimitry Andric Register AVLReg = MI.getOperand(1).getReg(); 811*06c3fb27SDimitry Andric assert((AVLReg != RISCV::X0 || MI.getOperand(0).getReg() != RISCV::X0) && 812*06c3fb27SDimitry Andric "Can't handle X0, X0 vsetvli yet"); 813*06c3fb27SDimitry Andric NewInfo.setAVLReg(AVLReg); 814*06c3fb27SDimitry Andric } 815*06c3fb27SDimitry Andric NewInfo.setVTYPE(MI.getOperand(2).getImm()); 816*06c3fb27SDimitry Andric 817*06c3fb27SDimitry Andric return NewInfo; 818*06c3fb27SDimitry Andric } 819*06c3fb27SDimitry Andric 82081ad6265SDimitry Andric void RISCVInsertVSETVLI::insertVSETVLI(MachineBasicBlock &MBB, 82181ad6265SDimitry Andric MachineBasicBlock::iterator InsertPt, DebugLoc DL, 82281ad6265SDimitry Andric const VSETVLIInfo &Info, const VSETVLIInfo &PrevInfo) { 82381ad6265SDimitry Andric 824*06c3fb27SDimitry Andric if (PrevInfo.isValid() && !PrevInfo.isUnknown()) { 82581ad6265SDimitry Andric // Use X0, X0 form if the AVL is the same and the SEW+LMUL gives the same 82681ad6265SDimitry Andric // VLMAX. 827*06c3fb27SDimitry Andric if (Info.hasSameAVL(PrevInfo) && Info.hasSameVLMAX(PrevInfo)) { 82881ad6265SDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETVLIX0)) 82981ad6265SDimitry Andric .addReg(RISCV::X0, RegState::Define | RegState::Dead) 83081ad6265SDimitry Andric .addReg(RISCV::X0, RegState::Kill) 83181ad6265SDimitry Andric .addImm(Info.encodeVTYPE()) 83281ad6265SDimitry Andric .addReg(RISCV::VL, RegState::Implicit); 83381ad6265SDimitry Andric return; 83481ad6265SDimitry Andric } 83581ad6265SDimitry Andric 836*06c3fb27SDimitry Andric // If our AVL is a virtual register, it might be defined by a VSET(I)VLI. If 837*06c3fb27SDimitry Andric // it has the same VLMAX we want and the last VL/VTYPE we observed is the 838*06c3fb27SDimitry Andric // same, we can use the X0, X0 form. 839*06c3fb27SDimitry Andric if (Info.hasSameVLMAX(PrevInfo) && Info.hasAVLReg() && 840*06c3fb27SDimitry Andric Info.getAVLReg().isVirtual()) { 841*06c3fb27SDimitry Andric if (MachineInstr *DefMI = MRI->getVRegDef(Info.getAVLReg())) { 842*06c3fb27SDimitry Andric if (isVectorConfigInstr(*DefMI)) { 843*06c3fb27SDimitry Andric VSETVLIInfo DefInfo = getInfoForVSETVLI(*DefMI); 844*06c3fb27SDimitry Andric if (DefInfo.hasSameAVL(PrevInfo) && DefInfo.hasSameVLMAX(PrevInfo)) { 845*06c3fb27SDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETVLIX0)) 846*06c3fb27SDimitry Andric .addReg(RISCV::X0, RegState::Define | RegState::Dead) 847*06c3fb27SDimitry Andric .addReg(RISCV::X0, RegState::Kill) 848*06c3fb27SDimitry Andric .addImm(Info.encodeVTYPE()) 849*06c3fb27SDimitry Andric .addReg(RISCV::VL, RegState::Implicit); 850*06c3fb27SDimitry Andric return; 851*06c3fb27SDimitry Andric } 852*06c3fb27SDimitry Andric } 853*06c3fb27SDimitry Andric } 854*06c3fb27SDimitry Andric } 855*06c3fb27SDimitry Andric } 856*06c3fb27SDimitry Andric 85781ad6265SDimitry Andric if (Info.hasAVLImm()) { 85881ad6265SDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETIVLI)) 85981ad6265SDimitry Andric .addReg(RISCV::X0, RegState::Define | RegState::Dead) 86081ad6265SDimitry Andric .addImm(Info.getAVLImm()) 86181ad6265SDimitry Andric .addImm(Info.encodeVTYPE()); 86281ad6265SDimitry Andric return; 86381ad6265SDimitry Andric } 86481ad6265SDimitry Andric 86581ad6265SDimitry Andric Register AVLReg = Info.getAVLReg(); 86681ad6265SDimitry Andric if (AVLReg == RISCV::NoRegister) { 86781ad6265SDimitry Andric // We can only use x0, x0 if there's no chance of the vtype change causing 86881ad6265SDimitry Andric // the previous vl to become invalid. 86981ad6265SDimitry Andric if (PrevInfo.isValid() && !PrevInfo.isUnknown() && 87081ad6265SDimitry Andric Info.hasSameVLMAX(PrevInfo)) { 87181ad6265SDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETVLIX0)) 87281ad6265SDimitry Andric .addReg(RISCV::X0, RegState::Define | RegState::Dead) 87381ad6265SDimitry Andric .addReg(RISCV::X0, RegState::Kill) 87481ad6265SDimitry Andric .addImm(Info.encodeVTYPE()) 87581ad6265SDimitry Andric .addReg(RISCV::VL, RegState::Implicit); 87681ad6265SDimitry Andric return; 87781ad6265SDimitry Andric } 87881ad6265SDimitry Andric // Otherwise use an AVL of 0 to avoid depending on previous vl. 87981ad6265SDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETIVLI)) 88081ad6265SDimitry Andric .addReg(RISCV::X0, RegState::Define | RegState::Dead) 88181ad6265SDimitry Andric .addImm(0) 88281ad6265SDimitry Andric .addImm(Info.encodeVTYPE()); 88381ad6265SDimitry Andric return; 88481ad6265SDimitry Andric } 88581ad6265SDimitry Andric 88681ad6265SDimitry Andric if (AVLReg.isVirtual()) 88781ad6265SDimitry Andric MRI->constrainRegClass(AVLReg, &RISCV::GPRNoX0RegClass); 88881ad6265SDimitry Andric 88981ad6265SDimitry Andric // Use X0 as the DestReg unless AVLReg is X0. We also need to change the 89081ad6265SDimitry Andric // opcode if the AVLReg is X0 as they have different register classes for 89181ad6265SDimitry Andric // the AVL operand. 89281ad6265SDimitry Andric Register DestReg = RISCV::X0; 89381ad6265SDimitry Andric unsigned Opcode = RISCV::PseudoVSETVLI; 89481ad6265SDimitry Andric if (AVLReg == RISCV::X0) { 89581ad6265SDimitry Andric DestReg = MRI->createVirtualRegister(&RISCV::GPRRegClass); 89681ad6265SDimitry Andric Opcode = RISCV::PseudoVSETVLIX0; 89781ad6265SDimitry Andric } 89881ad6265SDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(Opcode)) 89981ad6265SDimitry Andric .addReg(DestReg, RegState::Define | RegState::Dead) 90081ad6265SDimitry Andric .addReg(AVLReg) 90181ad6265SDimitry Andric .addImm(Info.encodeVTYPE()); 90281ad6265SDimitry Andric } 90381ad6265SDimitry Andric 904*06c3fb27SDimitry Andric static bool isLMUL1OrSmaller(RISCVII::VLMUL LMUL) { 905*06c3fb27SDimitry Andric auto [LMul, Fractional] = RISCVVType::decodeVLMUL(LMUL); 906*06c3fb27SDimitry Andric return Fractional || LMul == 1; 90781ad6265SDimitry Andric } 90881ad6265SDimitry Andric 90981ad6265SDimitry Andric /// Return true if a VSETVLI is required to transition from CurInfo to Require 91081ad6265SDimitry Andric /// before MI. 91181ad6265SDimitry Andric bool RISCVInsertVSETVLI::needVSETVLI(const MachineInstr &MI, 91281ad6265SDimitry Andric const VSETVLIInfo &Require, 91381ad6265SDimitry Andric const VSETVLIInfo &CurInfo) const { 91481ad6265SDimitry Andric assert(Require == computeInfoForInstr(MI, MI.getDesc().TSFlags, MRI)); 91581ad6265SDimitry Andric 91681ad6265SDimitry Andric if (!CurInfo.isValid() || CurInfo.isUnknown() || CurInfo.hasSEWLMULRatioOnly()) 91781ad6265SDimitry Andric return true; 91881ad6265SDimitry Andric 919*06c3fb27SDimitry Andric DemandedFields Used = getDemanded(MI, MRI); 920bdd1243dSDimitry Andric 921*06c3fb27SDimitry Andric // A slidedown/slideup with an *undefined* merge op can freely clobber 922*06c3fb27SDimitry Andric // elements not copied from the source vector (e.g. masked off, tail, or 923*06c3fb27SDimitry Andric // slideup's prefix). Notes: 924*06c3fb27SDimitry Andric // * We can't modify SEW here since the slide amount is in units of SEW. 925*06c3fb27SDimitry Andric // * VL=1 is special only because we have existing support for zero vs 926*06c3fb27SDimitry Andric // non-zero VL. We could generalize this if we had a VL > C predicate. 927*06c3fb27SDimitry Andric // * The LMUL1 restriction is for machines whose latency may depend on VL. 928*06c3fb27SDimitry Andric // * As above, this is only legal for tail "undefined" not "agnostic". 929*06c3fb27SDimitry Andric if (isVSlideInstr(MI) && Require.hasAVLImm() && Require.getAVLImm() == 1 && 930*06c3fb27SDimitry Andric isLMUL1OrSmaller(CurInfo.getVLMUL()) && hasUndefinedMergeOp(MI, *MRI)) { 931*06c3fb27SDimitry Andric Used.VLAny = false; 932*06c3fb27SDimitry Andric Used.VLZeroness = true; 933*06c3fb27SDimitry Andric Used.LMUL = false; 934bdd1243dSDimitry Andric Used.TailPolicy = false; 93581ad6265SDimitry Andric } 936*06c3fb27SDimitry Andric 937*06c3fb27SDimitry Andric // A tail undefined vmv.v.i/x or vfmv.v.f with VL=1 can be treated in the same 938*06c3fb27SDimitry Andric // semantically as vmv.s.x. This is particularly useful since we don't have an 939*06c3fb27SDimitry Andric // immediate form of vmv.s.x, and thus frequently use vmv.v.i in it's place. 940*06c3fb27SDimitry Andric // Since a splat is non-constant time in LMUL, we do need to be careful to not 941*06c3fb27SDimitry Andric // increase the number of active vector registers (unlike for vmv.s.x.) 942*06c3fb27SDimitry Andric if (isScalarSplatInstr(MI) && Require.hasAVLImm() && Require.getAVLImm() == 1 && 943*06c3fb27SDimitry Andric isLMUL1OrSmaller(CurInfo.getVLMUL()) && hasUndefinedMergeOp(MI, *MRI)) { 944*06c3fb27SDimitry Andric Used.LMUL = false; 945*06c3fb27SDimitry Andric Used.SEWLMULRatio = false; 946*06c3fb27SDimitry Andric Used.VLAny = false; 947*06c3fb27SDimitry Andric Used.SEW = DemandedFields::SEWGreaterThanOrEqual; 948*06c3fb27SDimitry Andric Used.TailPolicy = false; 949bdd1243dSDimitry Andric } 950bdd1243dSDimitry Andric 951*06c3fb27SDimitry Andric if (CurInfo.isCompatible(Used, Require, *MRI)) 952bdd1243dSDimitry Andric return false; 95381ad6265SDimitry Andric 95481ad6265SDimitry Andric // We didn't find a compatible value. If our AVL is a virtual register, 95581ad6265SDimitry Andric // it might be defined by a VSET(I)VLI. If it has the same VLMAX we need 95681ad6265SDimitry Andric // and the last VL/VTYPE we observed is the same, we don't need a 95781ad6265SDimitry Andric // VSETVLI here. 95881ad6265SDimitry Andric if (Require.hasAVLReg() && Require.getAVLReg().isVirtual() && 959bdd1243dSDimitry Andric CurInfo.hasCompatibleVTYPE(Used, Require)) { 96081ad6265SDimitry Andric if (MachineInstr *DefMI = MRI->getVRegDef(Require.getAVLReg())) { 96181ad6265SDimitry Andric if (isVectorConfigInstr(*DefMI)) { 96281ad6265SDimitry Andric VSETVLIInfo DefInfo = getInfoForVSETVLI(*DefMI); 96381ad6265SDimitry Andric if (DefInfo.hasSameAVL(CurInfo) && DefInfo.hasSameVLMAX(CurInfo)) 96481ad6265SDimitry Andric return false; 96581ad6265SDimitry Andric } 96681ad6265SDimitry Andric } 96781ad6265SDimitry Andric } 96881ad6265SDimitry Andric 96981ad6265SDimitry Andric return true; 97081ad6265SDimitry Andric } 97181ad6265SDimitry Andric 97281ad6265SDimitry Andric // Given an incoming state reaching MI, modifies that state so that it is minimally 97381ad6265SDimitry Andric // compatible with MI. The resulting state is guaranteed to be semantically legal 97481ad6265SDimitry Andric // for MI, but may not be the state requested by MI. 97581ad6265SDimitry Andric void RISCVInsertVSETVLI::transferBefore(VSETVLIInfo &Info, const MachineInstr &MI) { 97681ad6265SDimitry Andric uint64_t TSFlags = MI.getDesc().TSFlags; 97781ad6265SDimitry Andric if (!RISCVII::hasSEWOp(TSFlags)) 97881ad6265SDimitry Andric return; 97981ad6265SDimitry Andric 98081ad6265SDimitry Andric const VSETVLIInfo NewInfo = computeInfoForInstr(MI, TSFlags, MRI); 98181ad6265SDimitry Andric if (Info.isValid() && !needVSETVLI(MI, NewInfo, Info)) 98281ad6265SDimitry Andric return; 98381ad6265SDimitry Andric 98481ad6265SDimitry Andric const VSETVLIInfo PrevInfo = Info; 98581ad6265SDimitry Andric Info = NewInfo; 98681ad6265SDimitry Andric 98781ad6265SDimitry Andric if (!RISCVII::hasVLOp(TSFlags)) 98881ad6265SDimitry Andric return; 98981ad6265SDimitry Andric 99081ad6265SDimitry Andric // For vmv.s.x and vfmv.s.f, there are only two behaviors, VL = 0 and 99181ad6265SDimitry Andric // VL > 0. We can discard the user requested AVL and just use the last 99281ad6265SDimitry Andric // one if we can prove it equally zero. This removes a vsetvli entirely 99381ad6265SDimitry Andric // if the types match or allows use of cheaper avl preserving variant 99481ad6265SDimitry Andric // if VLMAX doesn't change. If VLMAX might change, we couldn't use 99581ad6265SDimitry Andric // the 'vsetvli x0, x0, vtype" variant, so we avoid the transform to 99681ad6265SDimitry Andric // prevent extending live range of an avl register operand. 99781ad6265SDimitry Andric // TODO: We can probably relax this for immediates. 99881ad6265SDimitry Andric if (isScalarMoveInstr(MI) && PrevInfo.isValid() && 999*06c3fb27SDimitry Andric PrevInfo.hasEquallyZeroAVL(Info, *MRI) && 100081ad6265SDimitry Andric Info.hasSameVLMAX(PrevInfo)) { 100181ad6265SDimitry Andric if (PrevInfo.hasAVLImm()) 100281ad6265SDimitry Andric Info.setAVLImm(PrevInfo.getAVLImm()); 100381ad6265SDimitry Andric else 100481ad6265SDimitry Andric Info.setAVLReg(PrevInfo.getAVLReg()); 100581ad6265SDimitry Andric return; 100681ad6265SDimitry Andric } 100781ad6265SDimitry Andric 100861cfbce3SDimitry Andric // If AVL is defined by a vsetvli with the same VLMAX, we can 100981ad6265SDimitry Andric // replace the AVL operand with the AVL of the defining vsetvli. 101081ad6265SDimitry Andric // We avoid general register AVLs to avoid extending live ranges 101181ad6265SDimitry Andric // without being sure we can kill the original source reg entirely. 101281ad6265SDimitry Andric if (!Info.hasAVLReg() || !Info.getAVLReg().isVirtual()) 101381ad6265SDimitry Andric return; 101481ad6265SDimitry Andric MachineInstr *DefMI = MRI->getVRegDef(Info.getAVLReg()); 101581ad6265SDimitry Andric if (!DefMI || !isVectorConfigInstr(*DefMI)) 101681ad6265SDimitry Andric return; 101781ad6265SDimitry Andric 101881ad6265SDimitry Andric VSETVLIInfo DefInfo = getInfoForVSETVLI(*DefMI); 101981ad6265SDimitry Andric if (DefInfo.hasSameVLMAX(Info) && 102081ad6265SDimitry Andric (DefInfo.hasAVLImm() || DefInfo.getAVLReg() == RISCV::X0)) { 102181ad6265SDimitry Andric if (DefInfo.hasAVLImm()) 102281ad6265SDimitry Andric Info.setAVLImm(DefInfo.getAVLImm()); 102381ad6265SDimitry Andric else 102481ad6265SDimitry Andric Info.setAVLReg(DefInfo.getAVLReg()); 102581ad6265SDimitry Andric return; 102681ad6265SDimitry Andric } 102781ad6265SDimitry Andric } 102881ad6265SDimitry Andric 102981ad6265SDimitry Andric // Given a state with which we evaluated MI (see transferBefore above for why 103081ad6265SDimitry Andric // this might be different that the state MI requested), modify the state to 103181ad6265SDimitry Andric // reflect the changes MI might make. 103281ad6265SDimitry Andric void RISCVInsertVSETVLI::transferAfter(VSETVLIInfo &Info, const MachineInstr &MI) { 103381ad6265SDimitry Andric if (isVectorConfigInstr(MI)) { 103481ad6265SDimitry Andric Info = getInfoForVSETVLI(MI); 103581ad6265SDimitry Andric return; 103681ad6265SDimitry Andric } 103781ad6265SDimitry Andric 103881ad6265SDimitry Andric if (RISCV::isFaultFirstLoad(MI)) { 103981ad6265SDimitry Andric // Update AVL to vl-output of the fault first load. 104081ad6265SDimitry Andric Info.setAVLReg(MI.getOperand(1).getReg()); 104181ad6265SDimitry Andric return; 104281ad6265SDimitry Andric } 104381ad6265SDimitry Andric 104481ad6265SDimitry Andric // If this is something that updates VL/VTYPE that we don't know about, set 104581ad6265SDimitry Andric // the state to unknown. 104681ad6265SDimitry Andric if (MI.isCall() || MI.isInlineAsm() || MI.modifiesRegister(RISCV::VL) || 104781ad6265SDimitry Andric MI.modifiesRegister(RISCV::VTYPE)) 104881ad6265SDimitry Andric Info = VSETVLIInfo::getUnknown(); 1049349cc55cSDimitry Andric } 1050349cc55cSDimitry Andric 1051fe6060f1SDimitry Andric bool RISCVInsertVSETVLI::computeVLVTYPEChanges(const MachineBasicBlock &MBB) { 1052fe6060f1SDimitry Andric bool HadVectorOp = false; 1053fe6060f1SDimitry Andric 1054fe6060f1SDimitry Andric BlockData &BBInfo = BlockInfo[MBB.getNumber()]; 105581ad6265SDimitry Andric BBInfo.Change = BBInfo.Pred; 1056fe6060f1SDimitry Andric for (const MachineInstr &MI : MBB) { 105781ad6265SDimitry Andric transferBefore(BBInfo.Change, MI); 1058fe6060f1SDimitry Andric 105981ad6265SDimitry Andric if (isVectorConfigInstr(MI) || RISCVII::hasSEWOp(MI.getDesc().TSFlags)) 1060fe6060f1SDimitry Andric HadVectorOp = true; 1061fe6060f1SDimitry Andric 106281ad6265SDimitry Andric transferAfter(BBInfo.Change, MI); 1063fe6060f1SDimitry Andric } 1064fe6060f1SDimitry Andric 1065fe6060f1SDimitry Andric return HadVectorOp; 1066fe6060f1SDimitry Andric } 1067fe6060f1SDimitry Andric 1068fe6060f1SDimitry Andric void RISCVInsertVSETVLI::computeIncomingVLVTYPE(const MachineBasicBlock &MBB) { 106981ad6265SDimitry Andric 1070fe6060f1SDimitry Andric BlockData &BBInfo = BlockInfo[MBB.getNumber()]; 1071fe6060f1SDimitry Andric 1072fe6060f1SDimitry Andric BBInfo.InQueue = false; 1073fe6060f1SDimitry Andric 1074bdd1243dSDimitry Andric // Start with the previous entry so that we keep the most conservative state 1075bdd1243dSDimitry Andric // we have ever found. 1076bdd1243dSDimitry Andric VSETVLIInfo InInfo = BBInfo.Pred; 1077fe6060f1SDimitry Andric if (MBB.pred_empty()) { 1078fe6060f1SDimitry Andric // There are no predecessors, so use the default starting status. 1079fe6060f1SDimitry Andric InInfo.setUnknown(); 1080fe6060f1SDimitry Andric } else { 1081fe6060f1SDimitry Andric for (MachineBasicBlock *P : MBB.predecessors()) 1082fe6060f1SDimitry Andric InInfo = InInfo.intersect(BlockInfo[P->getNumber()].Exit); 1083fe6060f1SDimitry Andric } 1084fe6060f1SDimitry Andric 1085fe6060f1SDimitry Andric // If we don't have any valid predecessor value, wait until we do. 1086fe6060f1SDimitry Andric if (!InInfo.isValid()) 1087fe6060f1SDimitry Andric return; 1088fe6060f1SDimitry Andric 108981ad6265SDimitry Andric // If no change, no need to rerun block 109081ad6265SDimitry Andric if (InInfo == BBInfo.Pred) 109181ad6265SDimitry Andric return; 1092fe6060f1SDimitry Andric 109381ad6265SDimitry Andric BBInfo.Pred = InInfo; 109481ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "Entry state of " << printMBBReference(MBB) 109581ad6265SDimitry Andric << " changed to " << BBInfo.Pred << "\n"); 109681ad6265SDimitry Andric 109781ad6265SDimitry Andric // Note: It's tempting to cache the state changes here, but due to the 109881ad6265SDimitry Andric // compatibility checks performed a blocks output state can change based on 109981ad6265SDimitry Andric // the input state. To cache, we'd have to add logic for finding 110081ad6265SDimitry Andric // never-compatible state changes. 110181ad6265SDimitry Andric computeVLVTYPEChanges(MBB); 110281ad6265SDimitry Andric VSETVLIInfo TmpStatus = BBInfo.Change; 1103fe6060f1SDimitry Andric 1104fe6060f1SDimitry Andric // If the new exit value matches the old exit value, we don't need to revisit 1105fe6060f1SDimitry Andric // any blocks. 1106fe6060f1SDimitry Andric if (BBInfo.Exit == TmpStatus) 1107fe6060f1SDimitry Andric return; 1108fe6060f1SDimitry Andric 1109fe6060f1SDimitry Andric BBInfo.Exit = TmpStatus; 111081ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "Exit state of " << printMBBReference(MBB) 111181ad6265SDimitry Andric << " changed to " << BBInfo.Exit << "\n"); 1112fe6060f1SDimitry Andric 1113fe6060f1SDimitry Andric // Add the successors to the work list so we can propagate the changed exit 1114fe6060f1SDimitry Andric // status. 1115fe6060f1SDimitry Andric for (MachineBasicBlock *S : MBB.successors()) 1116bdd1243dSDimitry Andric if (!BlockInfo[S->getNumber()].InQueue) { 1117bdd1243dSDimitry Andric BlockInfo[S->getNumber()].InQueue = true; 1118fe6060f1SDimitry Andric WorkList.push(S); 1119fe6060f1SDimitry Andric } 1120bdd1243dSDimitry Andric } 1121fe6060f1SDimitry Andric 1122fe6060f1SDimitry Andric // If we weren't able to prove a vsetvli was directly unneeded, it might still 112381ad6265SDimitry Andric // be unneeded if the AVL is a phi node where all incoming values are VL 1124fe6060f1SDimitry Andric // outputs from the last VSETVLI in their respective basic blocks. 1125fe6060f1SDimitry Andric bool RISCVInsertVSETVLI::needVSETVLIPHI(const VSETVLIInfo &Require, 112681ad6265SDimitry Andric const MachineBasicBlock &MBB) const { 1127fe6060f1SDimitry Andric if (DisableInsertVSETVLPHIOpt) 1128fe6060f1SDimitry Andric return true; 1129fe6060f1SDimitry Andric 1130fe6060f1SDimitry Andric if (!Require.hasAVLReg()) 1131fe6060f1SDimitry Andric return true; 1132fe6060f1SDimitry Andric 1133fe6060f1SDimitry Andric Register AVLReg = Require.getAVLReg(); 1134fe6060f1SDimitry Andric if (!AVLReg.isVirtual()) 1135fe6060f1SDimitry Andric return true; 1136fe6060f1SDimitry Andric 1137fe6060f1SDimitry Andric // We need the AVL to be produce by a PHI node in this basic block. 1138fe6060f1SDimitry Andric MachineInstr *PHI = MRI->getVRegDef(AVLReg); 1139fe6060f1SDimitry Andric if (!PHI || PHI->getOpcode() != RISCV::PHI || PHI->getParent() != &MBB) 1140fe6060f1SDimitry Andric return true; 1141fe6060f1SDimitry Andric 1142fe6060f1SDimitry Andric for (unsigned PHIOp = 1, NumOps = PHI->getNumOperands(); PHIOp != NumOps; 1143fe6060f1SDimitry Andric PHIOp += 2) { 1144fe6060f1SDimitry Andric Register InReg = PHI->getOperand(PHIOp).getReg(); 1145fe6060f1SDimitry Andric MachineBasicBlock *PBB = PHI->getOperand(PHIOp + 1).getMBB(); 1146fe6060f1SDimitry Andric const BlockData &PBBInfo = BlockInfo[PBB->getNumber()]; 1147fe6060f1SDimitry Andric // If the exit from the predecessor has the VTYPE we are looking for 1148fe6060f1SDimitry Andric // we might be able to avoid a VSETVLI. 114981ad6265SDimitry Andric if (PBBInfo.Exit.isUnknown() || !PBBInfo.Exit.hasSameVTYPE(Require)) 1150fe6060f1SDimitry Andric return true; 1151fe6060f1SDimitry Andric 1152fe6060f1SDimitry Andric // We need the PHI input to the be the output of a VSET(I)VLI. 1153fe6060f1SDimitry Andric MachineInstr *DefMI = MRI->getVRegDef(InReg); 115481ad6265SDimitry Andric if (!DefMI || !isVectorConfigInstr(*DefMI)) 1155fe6060f1SDimitry Andric return true; 1156fe6060f1SDimitry Andric 1157fe6060f1SDimitry Andric // We found a VSET(I)VLI make sure it matches the output of the 1158fe6060f1SDimitry Andric // predecessor block. 1159fe6060f1SDimitry Andric VSETVLIInfo DefInfo = getInfoForVSETVLI(*DefMI); 1160fe6060f1SDimitry Andric if (!DefInfo.hasSameAVL(PBBInfo.Exit) || 1161fe6060f1SDimitry Andric !DefInfo.hasSameVTYPE(PBBInfo.Exit)) 1162fe6060f1SDimitry Andric return true; 1163fe6060f1SDimitry Andric } 1164fe6060f1SDimitry Andric 1165fe6060f1SDimitry Andric // If all the incoming values to the PHI checked out, we don't need 1166fe6060f1SDimitry Andric // to insert a VSETVLI. 1167fe6060f1SDimitry Andric return false; 1168fe6060f1SDimitry Andric } 1169fe6060f1SDimitry Andric 1170fe6060f1SDimitry Andric void RISCVInsertVSETVLI::emitVSETVLIs(MachineBasicBlock &MBB) { 117181ad6265SDimitry Andric VSETVLIInfo CurInfo = BlockInfo[MBB.getNumber()].Pred; 117281ad6265SDimitry Andric // Track whether the prefix of the block we've scanned is transparent 117381ad6265SDimitry Andric // (meaning has not yet changed the abstract state). 117481ad6265SDimitry Andric bool PrefixTransparent = true; 1175fe6060f1SDimitry Andric for (MachineInstr &MI : MBB) { 117681ad6265SDimitry Andric const VSETVLIInfo PrevInfo = CurInfo; 117781ad6265SDimitry Andric transferBefore(CurInfo, MI); 117881ad6265SDimitry Andric 1179fe6060f1SDimitry Andric // If this is an explicit VSETVLI or VSETIVLI, update our state. 118081ad6265SDimitry Andric if (isVectorConfigInstr(MI)) { 1181fe6060f1SDimitry Andric // Conservatively, mark the VL and VTYPE as live. 1182fe6060f1SDimitry Andric assert(MI.getOperand(3).getReg() == RISCV::VL && 1183fe6060f1SDimitry Andric MI.getOperand(4).getReg() == RISCV::VTYPE && 1184fe6060f1SDimitry Andric "Unexpected operands where VL and VTYPE should be"); 1185fe6060f1SDimitry Andric MI.getOperand(3).setIsDead(false); 1186fe6060f1SDimitry Andric MI.getOperand(4).setIsDead(false); 118781ad6265SDimitry Andric PrefixTransparent = false; 1188fe6060f1SDimitry Andric } 1189fe6060f1SDimitry Andric 1190fe6060f1SDimitry Andric uint64_t TSFlags = MI.getDesc().TSFlags; 1191fe6060f1SDimitry Andric if (RISCVII::hasSEWOp(TSFlags)) { 119281ad6265SDimitry Andric if (PrevInfo != CurInfo) { 119381ad6265SDimitry Andric // If this is the first implicit state change, and the state change 119481ad6265SDimitry Andric // requested can be proven to produce the same register contents, we 119581ad6265SDimitry Andric // can skip emitting the actual state change and continue as if we 119681ad6265SDimitry Andric // had since we know the GPR result of the implicit state change 119781ad6265SDimitry Andric // wouldn't be used and VL/VTYPE registers are correct. Note that 119881ad6265SDimitry Andric // we *do* need to model the state as if it changed as while the 119981ad6265SDimitry Andric // register contents are unchanged, the abstract model can change. 120081ad6265SDimitry Andric if (!PrefixTransparent || needVSETVLIPHI(CurInfo, MBB)) 120181ad6265SDimitry Andric insertVSETVLI(MBB, MI, CurInfo, PrevInfo); 120281ad6265SDimitry Andric PrefixTransparent = false; 120381ad6265SDimitry Andric } 120481ad6265SDimitry Andric 1205fe6060f1SDimitry Andric if (RISCVII::hasVLOp(TSFlags)) { 120681ad6265SDimitry Andric MachineOperand &VLOp = MI.getOperand(getVLOpNum(MI)); 1207fe6060f1SDimitry Andric if (VLOp.isReg()) { 1208fe6060f1SDimitry Andric // Erase the AVL operand from the instruction. 1209fe6060f1SDimitry Andric VLOp.setReg(RISCV::NoRegister); 1210fe6060f1SDimitry Andric VLOp.setIsKill(false); 1211fe6060f1SDimitry Andric } 1212fe6060f1SDimitry Andric MI.addOperand(MachineOperand::CreateReg(RISCV::VL, /*isDef*/ false, 1213fe6060f1SDimitry Andric /*isImp*/ true)); 1214fe6060f1SDimitry Andric } 1215fe6060f1SDimitry Andric MI.addOperand(MachineOperand::CreateReg(RISCV::VTYPE, /*isDef*/ false, 1216fe6060f1SDimitry Andric /*isImp*/ true)); 1217fe6060f1SDimitry Andric } 1218fe6060f1SDimitry Andric 1219fe6060f1SDimitry Andric if (MI.isCall() || MI.isInlineAsm() || MI.modifiesRegister(RISCV::VL) || 122081ad6265SDimitry Andric MI.modifiesRegister(RISCV::VTYPE)) 122181ad6265SDimitry Andric PrefixTransparent = false; 122281ad6265SDimitry Andric 122381ad6265SDimitry Andric transferAfter(CurInfo, MI); 1224fe6060f1SDimitry Andric } 1225d56accc7SDimitry Andric 1226d56accc7SDimitry Andric // If we reach the end of the block and our current info doesn't match the 1227d56accc7SDimitry Andric // expected info, insert a vsetvli to correct. 122881ad6265SDimitry Andric if (!UseStrictAsserts) { 1229d56accc7SDimitry Andric const VSETVLIInfo &ExitInfo = BlockInfo[MBB.getNumber()].Exit; 1230d56accc7SDimitry Andric if (CurInfo.isValid() && ExitInfo.isValid() && !ExitInfo.isUnknown() && 1231d56accc7SDimitry Andric CurInfo != ExitInfo) { 123281ad6265SDimitry Andric // Note there's an implicit assumption here that terminators never use 123381ad6265SDimitry Andric // or modify VL or VTYPE. Also, fallthrough will return end(). 123481ad6265SDimitry Andric auto InsertPt = MBB.getFirstInstrTerminator(); 123581ad6265SDimitry Andric insertVSETVLI(MBB, InsertPt, MBB.findDebugLoc(InsertPt), ExitInfo, 123681ad6265SDimitry Andric CurInfo); 1237d56accc7SDimitry Andric CurInfo = ExitInfo; 1238d56accc7SDimitry Andric } 1239d56accc7SDimitry Andric } 124081ad6265SDimitry Andric 124181ad6265SDimitry Andric if (UseStrictAsserts && CurInfo.isValid()) { 124281ad6265SDimitry Andric const auto &Info = BlockInfo[MBB.getNumber()]; 124381ad6265SDimitry Andric if (CurInfo != Info.Exit) { 124481ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "in block " << printMBBReference(MBB) << "\n"); 124581ad6265SDimitry Andric LLVM_DEBUG(dbgs() << " begin state: " << Info.Pred << "\n"); 124681ad6265SDimitry Andric LLVM_DEBUG(dbgs() << " expected end state: " << Info.Exit << "\n"); 124781ad6265SDimitry Andric LLVM_DEBUG(dbgs() << " actual end state: " << CurInfo << "\n"); 124881ad6265SDimitry Andric } 124981ad6265SDimitry Andric assert(CurInfo == Info.Exit && 125081ad6265SDimitry Andric "InsertVSETVLI dataflow invariant violated"); 125181ad6265SDimitry Andric } 125281ad6265SDimitry Andric } 125381ad6265SDimitry Andric 125481ad6265SDimitry Andric /// Return true if the VL value configured must be equal to the requested one. 125581ad6265SDimitry Andric static bool hasFixedResult(const VSETVLIInfo &Info, const RISCVSubtarget &ST) { 125681ad6265SDimitry Andric if (!Info.hasAVLImm()) 125781ad6265SDimitry Andric // VLMAX is always the same value. 125881ad6265SDimitry Andric // TODO: Could extend to other registers by looking at the associated vreg 125981ad6265SDimitry Andric // def placement. 126081ad6265SDimitry Andric return RISCV::X0 == Info.getAVLReg(); 126181ad6265SDimitry Andric 126281ad6265SDimitry Andric unsigned AVL = Info.getAVLImm(); 126381ad6265SDimitry Andric unsigned SEW = Info.getSEW(); 126481ad6265SDimitry Andric unsigned AVLInBits = AVL * SEW; 126581ad6265SDimitry Andric 126681ad6265SDimitry Andric unsigned LMul; 126781ad6265SDimitry Andric bool Fractional; 126881ad6265SDimitry Andric std::tie(LMul, Fractional) = RISCVVType::decodeVLMUL(Info.getVLMUL()); 126981ad6265SDimitry Andric 127081ad6265SDimitry Andric if (Fractional) 127181ad6265SDimitry Andric return ST.getRealMinVLen() / LMul >= AVLInBits; 127281ad6265SDimitry Andric return ST.getRealMinVLen() * LMul >= AVLInBits; 127381ad6265SDimitry Andric } 127481ad6265SDimitry Andric 127581ad6265SDimitry Andric /// Perform simple partial redundancy elimination of the VSETVLI instructions 127681ad6265SDimitry Andric /// we're about to insert by looking for cases where we can PRE from the 127781ad6265SDimitry Andric /// beginning of one block to the end of one of its predecessors. Specifically, 127881ad6265SDimitry Andric /// this is geared to catch the common case of a fixed length vsetvl in a single 127981ad6265SDimitry Andric /// block loop when it could execute once in the preheader instead. 128081ad6265SDimitry Andric void RISCVInsertVSETVLI::doPRE(MachineBasicBlock &MBB) { 128181ad6265SDimitry Andric const MachineFunction &MF = *MBB.getParent(); 128281ad6265SDimitry Andric const RISCVSubtarget &ST = MF.getSubtarget<RISCVSubtarget>(); 128381ad6265SDimitry Andric 128481ad6265SDimitry Andric if (!BlockInfo[MBB.getNumber()].Pred.isUnknown()) 128581ad6265SDimitry Andric return; 128681ad6265SDimitry Andric 128781ad6265SDimitry Andric MachineBasicBlock *UnavailablePred = nullptr; 128881ad6265SDimitry Andric VSETVLIInfo AvailableInfo; 128981ad6265SDimitry Andric for (MachineBasicBlock *P : MBB.predecessors()) { 129081ad6265SDimitry Andric const VSETVLIInfo &PredInfo = BlockInfo[P->getNumber()].Exit; 129181ad6265SDimitry Andric if (PredInfo.isUnknown()) { 129281ad6265SDimitry Andric if (UnavailablePred) 129381ad6265SDimitry Andric return; 129481ad6265SDimitry Andric UnavailablePred = P; 129581ad6265SDimitry Andric } else if (!AvailableInfo.isValid()) { 129681ad6265SDimitry Andric AvailableInfo = PredInfo; 129781ad6265SDimitry Andric } else if (AvailableInfo != PredInfo) { 129881ad6265SDimitry Andric return; 129981ad6265SDimitry Andric } 130081ad6265SDimitry Andric } 130181ad6265SDimitry Andric 130281ad6265SDimitry Andric // Unreachable, single pred, or full redundancy. Note that FRE is handled by 130381ad6265SDimitry Andric // phase 3. 130481ad6265SDimitry Andric if (!UnavailablePred || !AvailableInfo.isValid()) 130581ad6265SDimitry Andric return; 130681ad6265SDimitry Andric 130781ad6265SDimitry Andric // Critical edge - TODO: consider splitting? 130881ad6265SDimitry Andric if (UnavailablePred->succ_size() != 1) 130981ad6265SDimitry Andric return; 131081ad6265SDimitry Andric 131181ad6265SDimitry Andric // If VL can be less than AVL, then we can't reduce the frequency of exec. 131281ad6265SDimitry Andric if (!hasFixedResult(AvailableInfo, ST)) 131381ad6265SDimitry Andric return; 131481ad6265SDimitry Andric 1315*06c3fb27SDimitry Andric // Model the effect of changing the input state of the block MBB to 1316*06c3fb27SDimitry Andric // AvailableInfo. We're looking for two issues here; one legality, 1317*06c3fb27SDimitry Andric // one profitability. 1318*06c3fb27SDimitry Andric // 1) If the block doesn't use some of the fields from VL or VTYPE, we 1319*06c3fb27SDimitry Andric // may hit the end of the block with a different end state. We can 1320*06c3fb27SDimitry Andric // not make this change without reflowing later blocks as well. 1321*06c3fb27SDimitry Andric // 2) If we don't actually remove a transition, inserting a vsetvli 1322*06c3fb27SDimitry Andric // into the predecessor block would be correct, but unprofitable. 1323*06c3fb27SDimitry Andric VSETVLIInfo OldInfo = BlockInfo[MBB.getNumber()].Pred; 1324*06c3fb27SDimitry Andric VSETVLIInfo CurInfo = AvailableInfo; 1325*06c3fb27SDimitry Andric int TransitionsRemoved = 0; 1326*06c3fb27SDimitry Andric for (const MachineInstr &MI : MBB) { 1327*06c3fb27SDimitry Andric const VSETVLIInfo LastInfo = CurInfo; 1328*06c3fb27SDimitry Andric const VSETVLIInfo LastOldInfo = OldInfo; 1329*06c3fb27SDimitry Andric transferBefore(CurInfo, MI); 1330*06c3fb27SDimitry Andric transferBefore(OldInfo, MI); 1331*06c3fb27SDimitry Andric if (CurInfo == LastInfo) 1332*06c3fb27SDimitry Andric TransitionsRemoved++; 1333*06c3fb27SDimitry Andric if (LastOldInfo == OldInfo) 1334*06c3fb27SDimitry Andric TransitionsRemoved--; 1335*06c3fb27SDimitry Andric transferAfter(CurInfo, MI); 1336*06c3fb27SDimitry Andric transferAfter(OldInfo, MI); 1337*06c3fb27SDimitry Andric if (CurInfo == OldInfo) 1338*06c3fb27SDimitry Andric // Convergence. All transitions after this must match by construction. 133981ad6265SDimitry Andric break; 134081ad6265SDimitry Andric } 1341*06c3fb27SDimitry Andric if (CurInfo != OldInfo || TransitionsRemoved <= 0) 1342*06c3fb27SDimitry Andric // Issues 1 and 2 above 134381ad6265SDimitry Andric return; 134481ad6265SDimitry Andric 134581ad6265SDimitry Andric // Finally, update both data flow state and insert the actual vsetvli. 134681ad6265SDimitry Andric // Doing both keeps the code in sync with the dataflow results, which 134781ad6265SDimitry Andric // is critical for correctness of phase 3. 1348*06c3fb27SDimitry Andric auto OldExit = BlockInfo[UnavailablePred->getNumber()].Exit; 134981ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "PRE VSETVLI from " << MBB.getName() << " to " 135081ad6265SDimitry Andric << UnavailablePred->getName() << " with state " 135181ad6265SDimitry Andric << AvailableInfo << "\n"); 135281ad6265SDimitry Andric BlockInfo[UnavailablePred->getNumber()].Exit = AvailableInfo; 135381ad6265SDimitry Andric BlockInfo[MBB.getNumber()].Pred = AvailableInfo; 135481ad6265SDimitry Andric 135581ad6265SDimitry Andric // Note there's an implicit assumption here that terminators never use 135681ad6265SDimitry Andric // or modify VL or VTYPE. Also, fallthrough will return end(). 135781ad6265SDimitry Andric auto InsertPt = UnavailablePred->getFirstInstrTerminator(); 135881ad6265SDimitry Andric insertVSETVLI(*UnavailablePred, InsertPt, 135981ad6265SDimitry Andric UnavailablePred->findDebugLoc(InsertPt), 1360*06c3fb27SDimitry Andric AvailableInfo, OldExit); 136181ad6265SDimitry Andric } 136281ad6265SDimitry Andric 136381ad6265SDimitry Andric static void doUnion(DemandedFields &A, DemandedFields B) { 1364bdd1243dSDimitry Andric A.VLAny |= B.VLAny; 1365bdd1243dSDimitry Andric A.VLZeroness |= B.VLZeroness; 1366*06c3fb27SDimitry Andric A.SEW = std::max(A.SEW, B.SEW); 136781ad6265SDimitry Andric A.LMUL |= B.LMUL; 136881ad6265SDimitry Andric A.SEWLMULRatio |= B.SEWLMULRatio; 136981ad6265SDimitry Andric A.TailPolicy |= B.TailPolicy; 137081ad6265SDimitry Andric A.MaskPolicy |= B.MaskPolicy; 137181ad6265SDimitry Andric } 137281ad6265SDimitry Andric 1373bdd1243dSDimitry Andric static bool isNonZeroAVL(const MachineOperand &MO) { 1374bdd1243dSDimitry Andric if (MO.isReg()) 1375bdd1243dSDimitry Andric return RISCV::X0 == MO.getReg(); 1376bdd1243dSDimitry Andric assert(MO.isImm()); 1377bdd1243dSDimitry Andric return 0 != MO.getImm(); 1378bdd1243dSDimitry Andric } 1379bdd1243dSDimitry Andric 1380bdd1243dSDimitry Andric // Return true if we can mutate PrevMI to match MI without changing any the 1381bdd1243dSDimitry Andric // fields which would be observed. 138281ad6265SDimitry Andric static bool canMutatePriorConfig(const MachineInstr &PrevMI, 138381ad6265SDimitry Andric const MachineInstr &MI, 138481ad6265SDimitry Andric const DemandedFields &Used) { 1385bdd1243dSDimitry Andric // If the VL values aren't equal, return false if either a) the former is 1386bdd1243dSDimitry Andric // demanded, or b) we can't rewrite the former to be the later for 1387bdd1243dSDimitry Andric // implementation reasons. 1388bdd1243dSDimitry Andric if (!isVLPreservingConfig(MI)) { 1389bdd1243dSDimitry Andric if (Used.VLAny) 139081ad6265SDimitry Andric return false; 139181ad6265SDimitry Andric 1392bdd1243dSDimitry Andric // TODO: Requires more care in the mutation... 1393bdd1243dSDimitry Andric if (isVLPreservingConfig(PrevMI)) 1394bdd1243dSDimitry Andric return false; 1395bdd1243dSDimitry Andric 1396bdd1243dSDimitry Andric // We don't bother to handle the equally zero case here as it's largely 1397bdd1243dSDimitry Andric // uninteresting. 1398bdd1243dSDimitry Andric if (Used.VLZeroness && 1399bdd1243dSDimitry Andric (!isNonZeroAVL(MI.getOperand(1)) || 1400bdd1243dSDimitry Andric !isNonZeroAVL(PrevMI.getOperand(1)))) 1401bdd1243dSDimitry Andric return false; 1402bdd1243dSDimitry Andric 1403bdd1243dSDimitry Andric // TODO: Track whether the register is defined between 1404bdd1243dSDimitry Andric // PrevMI and MI. 1405bdd1243dSDimitry Andric if (MI.getOperand(1).isReg() && 1406bdd1243dSDimitry Andric RISCV::X0 != MI.getOperand(1).getReg()) 1407bdd1243dSDimitry Andric return false; 1408bdd1243dSDimitry Andric 1409bdd1243dSDimitry Andric // TODO: We need to change the result register to allow this rewrite 1410bdd1243dSDimitry Andric // without the result forming a vl preserving vsetvli which is not 1411bdd1243dSDimitry Andric // a correct state merge. 1412bdd1243dSDimitry Andric if (PrevMI.getOperand(0).getReg() == RISCV::X0 && 1413bdd1243dSDimitry Andric MI.getOperand(1).isReg()) 1414bdd1243dSDimitry Andric return false; 1415bdd1243dSDimitry Andric } 1416bdd1243dSDimitry Andric 141781ad6265SDimitry Andric if (!PrevMI.getOperand(2).isImm() || !MI.getOperand(2).isImm()) 141881ad6265SDimitry Andric return false; 141981ad6265SDimitry Andric 142081ad6265SDimitry Andric auto PriorVType = PrevMI.getOperand(2).getImm(); 142181ad6265SDimitry Andric auto VType = MI.getOperand(2).getImm(); 142281ad6265SDimitry Andric return areCompatibleVTYPEs(PriorVType, VType, Used); 142381ad6265SDimitry Andric } 142481ad6265SDimitry Andric 142581ad6265SDimitry Andric void RISCVInsertVSETVLI::doLocalPostpass(MachineBasicBlock &MBB) { 1426bdd1243dSDimitry Andric MachineInstr *NextMI = nullptr; 1427bdd1243dSDimitry Andric // We can have arbitrary code in successors, so VL and VTYPE 1428bdd1243dSDimitry Andric // must be considered demanded. 142981ad6265SDimitry Andric DemandedFields Used; 1430bdd1243dSDimitry Andric Used.demandVL(); 1431bdd1243dSDimitry Andric Used.demandVTYPE(); 143281ad6265SDimitry Andric SmallVector<MachineInstr*> ToDelete; 1433bdd1243dSDimitry Andric for (MachineInstr &MI : make_range(MBB.rbegin(), MBB.rend())) { 1434bdd1243dSDimitry Andric 1435bdd1243dSDimitry Andric if (!isVectorConfigInstr(MI)) { 1436*06c3fb27SDimitry Andric doUnion(Used, getDemanded(MI, MRI)); 143781ad6265SDimitry Andric continue; 143881ad6265SDimitry Andric } 1439bdd1243dSDimitry Andric 144081ad6265SDimitry Andric Register VRegDef = MI.getOperand(0).getReg(); 144181ad6265SDimitry Andric if (VRegDef != RISCV::X0 && 144281ad6265SDimitry Andric !(VRegDef.isVirtual() && MRI->use_nodbg_empty(VRegDef))) 1443bdd1243dSDimitry Andric Used.demandVL(); 1444bdd1243dSDimitry Andric 1445bdd1243dSDimitry Andric if (NextMI) { 1446bdd1243dSDimitry Andric if (!Used.usedVL() && !Used.usedVTYPE()) { 1447bdd1243dSDimitry Andric ToDelete.push_back(&MI); 1448bdd1243dSDimitry Andric // Leave NextMI unchanged 1449bdd1243dSDimitry Andric continue; 1450bdd1243dSDimitry Andric } else if (canMutatePriorConfig(MI, *NextMI, Used)) { 1451bdd1243dSDimitry Andric if (!isVLPreservingConfig(*NextMI)) { 1452bdd1243dSDimitry Andric if (NextMI->getOperand(1).isImm()) 1453bdd1243dSDimitry Andric MI.getOperand(1).ChangeToImmediate(NextMI->getOperand(1).getImm()); 1454bdd1243dSDimitry Andric else 1455bdd1243dSDimitry Andric MI.getOperand(1).ChangeToRegister(NextMI->getOperand(1).getReg(), false); 1456bdd1243dSDimitry Andric MI.setDesc(NextMI->getDesc()); 1457bdd1243dSDimitry Andric } 1458bdd1243dSDimitry Andric MI.getOperand(2).setImm(NextMI->getOperand(2).getImm()); 1459*06c3fb27SDimitry Andric // Don't delete a vsetvli if its result might be used. 1460*06c3fb27SDimitry Andric Register NextVRefDef = NextMI->getOperand(0).getReg(); 1461*06c3fb27SDimitry Andric if (NextVRefDef == RISCV::X0 || 1462*06c3fb27SDimitry Andric (NextVRefDef.isVirtual() && MRI->use_nodbg_empty(NextVRefDef))) 1463bdd1243dSDimitry Andric ToDelete.push_back(NextMI); 1464bdd1243dSDimitry Andric // fallthrough 1465bdd1243dSDimitry Andric } 1466bdd1243dSDimitry Andric } 1467bdd1243dSDimitry Andric NextMI = &MI; 1468*06c3fb27SDimitry Andric Used = getDemanded(MI, MRI); 146981ad6265SDimitry Andric } 147081ad6265SDimitry Andric 147181ad6265SDimitry Andric for (auto *MI : ToDelete) 147281ad6265SDimitry Andric MI->eraseFromParent(); 147381ad6265SDimitry Andric } 147481ad6265SDimitry Andric 147581ad6265SDimitry Andric void RISCVInsertVSETVLI::insertReadVL(MachineBasicBlock &MBB) { 147681ad6265SDimitry Andric for (auto I = MBB.begin(), E = MBB.end(); I != E;) { 147781ad6265SDimitry Andric MachineInstr &MI = *I++; 147881ad6265SDimitry Andric if (RISCV::isFaultFirstLoad(MI)) { 147981ad6265SDimitry Andric Register VLOutput = MI.getOperand(1).getReg(); 148081ad6265SDimitry Andric if (!MRI->use_nodbg_empty(VLOutput)) 148181ad6265SDimitry Andric BuildMI(MBB, I, MI.getDebugLoc(), TII->get(RISCV::PseudoReadVL), 148281ad6265SDimitry Andric VLOutput); 148381ad6265SDimitry Andric // We don't use the vl output of the VLEFF/VLSEGFF anymore. 148481ad6265SDimitry Andric MI.getOperand(1).setReg(RISCV::X0); 148581ad6265SDimitry Andric } 1486fe6060f1SDimitry Andric } 1487fe6060f1SDimitry Andric } 1488fe6060f1SDimitry Andric 1489fe6060f1SDimitry Andric bool RISCVInsertVSETVLI::runOnMachineFunction(MachineFunction &MF) { 1490fe6060f1SDimitry Andric // Skip if the vector extension is not enabled. 1491fe6060f1SDimitry Andric const RISCVSubtarget &ST = MF.getSubtarget<RISCVSubtarget>(); 1492349cc55cSDimitry Andric if (!ST.hasVInstructions()) 1493fe6060f1SDimitry Andric return false; 1494fe6060f1SDimitry Andric 149581ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "Entering InsertVSETVLI for " << MF.getName() << "\n"); 149681ad6265SDimitry Andric 1497fe6060f1SDimitry Andric TII = ST.getInstrInfo(); 1498fe6060f1SDimitry Andric MRI = &MF.getRegInfo(); 1499fe6060f1SDimitry Andric 1500fe6060f1SDimitry Andric assert(BlockInfo.empty() && "Expect empty block infos"); 1501fe6060f1SDimitry Andric BlockInfo.resize(MF.getNumBlockIDs()); 1502fe6060f1SDimitry Andric 1503fe6060f1SDimitry Andric bool HaveVectorOp = false; 1504fe6060f1SDimitry Andric 1505fe6060f1SDimitry Andric // Phase 1 - determine how VL/VTYPE are affected by the each block. 150681ad6265SDimitry Andric for (const MachineBasicBlock &MBB : MF) { 1507fe6060f1SDimitry Andric HaveVectorOp |= computeVLVTYPEChanges(MBB); 150881ad6265SDimitry Andric // Initial exit state is whatever change we found in the block. 150981ad6265SDimitry Andric BlockData &BBInfo = BlockInfo[MBB.getNumber()]; 151081ad6265SDimitry Andric BBInfo.Exit = BBInfo.Change; 151181ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "Initial exit state of " << printMBBReference(MBB) 151281ad6265SDimitry Andric << " is " << BBInfo.Exit << "\n"); 151381ad6265SDimitry Andric 151481ad6265SDimitry Andric } 1515fe6060f1SDimitry Andric 1516fe6060f1SDimitry Andric // If we didn't find any instructions that need VSETVLI, we're done. 151781ad6265SDimitry Andric if (!HaveVectorOp) { 151881ad6265SDimitry Andric BlockInfo.clear(); 151981ad6265SDimitry Andric return false; 152081ad6265SDimitry Andric } 152181ad6265SDimitry Andric 1522fe6060f1SDimitry Andric // Phase 2 - determine the exit VL/VTYPE from each block. We add all 1523fe6060f1SDimitry Andric // blocks to the list here, but will also add any that need to be revisited 1524fe6060f1SDimitry Andric // during Phase 2 processing. 1525fe6060f1SDimitry Andric for (const MachineBasicBlock &MBB : MF) { 1526fe6060f1SDimitry Andric WorkList.push(&MBB); 1527fe6060f1SDimitry Andric BlockInfo[MBB.getNumber()].InQueue = true; 1528fe6060f1SDimitry Andric } 1529fe6060f1SDimitry Andric while (!WorkList.empty()) { 1530fe6060f1SDimitry Andric const MachineBasicBlock &MBB = *WorkList.front(); 1531fe6060f1SDimitry Andric WorkList.pop(); 1532fe6060f1SDimitry Andric computeIncomingVLVTYPE(MBB); 1533fe6060f1SDimitry Andric } 1534fe6060f1SDimitry Andric 153581ad6265SDimitry Andric // Perform partial redundancy elimination of vsetvli transitions. 153681ad6265SDimitry Andric for (MachineBasicBlock &MBB : MF) 153781ad6265SDimitry Andric doPRE(MBB); 153881ad6265SDimitry Andric 1539fe6060f1SDimitry Andric // Phase 3 - add any vsetvli instructions needed in the block. Use the 1540fe6060f1SDimitry Andric // Phase 2 information to avoid adding vsetvlis before the first vector 1541fe6060f1SDimitry Andric // instruction in the block if the VL/VTYPE is satisfied by its 1542fe6060f1SDimitry Andric // predecessors. 1543fe6060f1SDimitry Andric for (MachineBasicBlock &MBB : MF) 1544fe6060f1SDimitry Andric emitVSETVLIs(MBB); 154581ad6265SDimitry Andric 154681ad6265SDimitry Andric // Now that all vsetvlis are explicit, go through and do block local 154781ad6265SDimitry Andric // DSE and peephole based demanded fields based transforms. Note that 154881ad6265SDimitry Andric // this *must* be done outside the main dataflow so long as we allow 154981ad6265SDimitry Andric // any cross block analysis within the dataflow. We can't have both 155081ad6265SDimitry Andric // demanded fields based mutation and non-local analysis in the 155181ad6265SDimitry Andric // dataflow at the same time without introducing inconsistencies. 155281ad6265SDimitry Andric for (MachineBasicBlock &MBB : MF) 155381ad6265SDimitry Andric doLocalPostpass(MBB); 155481ad6265SDimitry Andric 155581ad6265SDimitry Andric // Once we're fully done rewriting all the instructions, do a final pass 155681ad6265SDimitry Andric // through to check for VSETVLIs which write to an unused destination. 155781ad6265SDimitry Andric // For the non X0, X0 variant, we can replace the destination register 155881ad6265SDimitry Andric // with X0 to reduce register pressure. This is really a generic 155981ad6265SDimitry Andric // optimization which can be applied to any dead def (TODO: generalize). 156081ad6265SDimitry Andric for (MachineBasicBlock &MBB : MF) { 156181ad6265SDimitry Andric for (MachineInstr &MI : MBB) { 156281ad6265SDimitry Andric if (MI.getOpcode() == RISCV::PseudoVSETVLI || 156381ad6265SDimitry Andric MI.getOpcode() == RISCV::PseudoVSETIVLI) { 156481ad6265SDimitry Andric Register VRegDef = MI.getOperand(0).getReg(); 156581ad6265SDimitry Andric if (VRegDef != RISCV::X0 && MRI->use_nodbg_empty(VRegDef)) 156681ad6265SDimitry Andric MI.getOperand(0).setReg(RISCV::X0); 156781ad6265SDimitry Andric } 156881ad6265SDimitry Andric } 1569fe6060f1SDimitry Andric } 1570fe6060f1SDimitry Andric 157181ad6265SDimitry Andric // Insert PseudoReadVL after VLEFF/VLSEGFF and replace it with the vl output 157281ad6265SDimitry Andric // of VLEFF/VLSEGFF. 157381ad6265SDimitry Andric for (MachineBasicBlock &MBB : MF) 157481ad6265SDimitry Andric insertReadVL(MBB); 1575fe6060f1SDimitry Andric 157681ad6265SDimitry Andric BlockInfo.clear(); 1577fe6060f1SDimitry Andric return HaveVectorOp; 1578fe6060f1SDimitry Andric } 1579fe6060f1SDimitry Andric 1580fe6060f1SDimitry Andric /// Returns an instance of the Insert VSETVLI pass. 1581fe6060f1SDimitry Andric FunctionPass *llvm::createRISCVInsertVSETVLIPass() { 1582fe6060f1SDimitry Andric return new RISCVInsertVSETVLI(); 1583fe6060f1SDimitry Andric } 1584