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" 35fe6060f1SDimitry Andric #define RISCV_INSERT_VSETVLI_NAME "RISCV 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 55*bdd1243dSDimitry Andric static bool isVectorConfigInstr(const MachineInstr &MI) { 56*bdd1243dSDimitry Andric return MI.getOpcode() == RISCV::PseudoVSETVLI || 57*bdd1243dSDimitry Andric MI.getOpcode() == RISCV::PseudoVSETVLIX0 || 58*bdd1243dSDimitry Andric MI.getOpcode() == RISCV::PseudoVSETIVLI; 59*bdd1243dSDimitry Andric } 60*bdd1243dSDimitry Andric 61*bdd1243dSDimitry Andric /// Return true if this is 'vsetvli x0, x0, vtype' which preserves 62*bdd1243dSDimitry Andric /// VL and only sets VTYPE. 63*bdd1243dSDimitry Andric static bool isVLPreservingConfig(const MachineInstr &MI) { 64*bdd1243dSDimitry Andric if (MI.getOpcode() != RISCV::PseudoVSETVLIX0) 65*bdd1243dSDimitry Andric return false; 66*bdd1243dSDimitry Andric assert(RISCV::X0 == MI.getOperand(1).getReg()); 67*bdd1243dSDimitry Andric return RISCV::X0 == MI.getOperand(0).getReg(); 68*bdd1243dSDimitry Andric } 69*bdd1243dSDimitry Andric 70*bdd1243dSDimitry Andric static uint16_t getRVVMCOpcode(uint16_t RVVPseudoOpcode) { 71*bdd1243dSDimitry Andric const RISCVVPseudosTable::PseudoInfo *RVV = 72*bdd1243dSDimitry Andric RISCVVPseudosTable::getPseudoInfo(RVVPseudoOpcode); 73*bdd1243dSDimitry Andric if (!RVV) 74*bdd1243dSDimitry Andric return 0; 75*bdd1243dSDimitry Andric return RVV->BaseInstr; 76*bdd1243dSDimitry Andric } 77*bdd1243dSDimitry Andric 7804eeddc0SDimitry Andric static bool isScalarMoveInstr(const MachineInstr &MI) { 79*bdd1243dSDimitry Andric switch (getRVVMCOpcode(MI.getOpcode())) { 8004eeddc0SDimitry Andric default: 8104eeddc0SDimitry Andric return false; 82*bdd1243dSDimitry Andric case RISCV::VMV_S_X: 83*bdd1243dSDimitry Andric case RISCV::VFMV_S_F: 8404eeddc0SDimitry Andric return true; 8504eeddc0SDimitry Andric } 8604eeddc0SDimitry Andric } 8704eeddc0SDimitry Andric 88*bdd1243dSDimitry Andric /// Get the EEW for a load or store instruction. Return std::nullopt if MI is 89*bdd1243dSDimitry Andric /// not a load or store which ignores SEW. 90*bdd1243dSDimitry Andric static std::optional<unsigned> getEEWForLoadStore(const MachineInstr &MI) { 91*bdd1243dSDimitry Andric switch (getRVVMCOpcode(MI.getOpcode())) { 92349cc55cSDimitry Andric default: 93*bdd1243dSDimitry Andric return std::nullopt; 94*bdd1243dSDimitry Andric case RISCV::VLE8_V: 95*bdd1243dSDimitry Andric case RISCV::VLSE8_V: 96*bdd1243dSDimitry Andric case RISCV::VSE8_V: 97*bdd1243dSDimitry Andric case RISCV::VSSE8_V: 9881ad6265SDimitry Andric return 8; 99*bdd1243dSDimitry Andric case RISCV::VLE16_V: 100*bdd1243dSDimitry Andric case RISCV::VLSE16_V: 101*bdd1243dSDimitry Andric case RISCV::VSE16_V: 102*bdd1243dSDimitry Andric case RISCV::VSSE16_V: 10381ad6265SDimitry Andric return 16; 104*bdd1243dSDimitry Andric case RISCV::VLE32_V: 105*bdd1243dSDimitry Andric case RISCV::VLSE32_V: 106*bdd1243dSDimitry Andric case RISCV::VSE32_V: 107*bdd1243dSDimitry Andric case RISCV::VSSE32_V: 10881ad6265SDimitry Andric return 32; 109*bdd1243dSDimitry Andric case RISCV::VLE64_V: 110*bdd1243dSDimitry Andric case RISCV::VLSE64_V: 111*bdd1243dSDimitry Andric case RISCV::VSE64_V: 112*bdd1243dSDimitry Andric case RISCV::VSSE64_V: 11381ad6265SDimitry Andric return 64; 11481ad6265SDimitry Andric } 115349cc55cSDimitry Andric } 116349cc55cSDimitry Andric 11781ad6265SDimitry Andric /// Return true if this is an operation on mask registers. Note that 11881ad6265SDimitry Andric /// this includes both arithmetic/logical ops and load/store (vlm/vsm). 11981ad6265SDimitry Andric static bool isMaskRegOp(const MachineInstr &MI) { 120*bdd1243dSDimitry Andric if (!RISCVII::hasSEWOp(MI.getDesc().TSFlags)) 121*bdd1243dSDimitry Andric return false; 12281ad6265SDimitry Andric const unsigned Log2SEW = MI.getOperand(getSEWOpNum(MI)).getImm(); 12381ad6265SDimitry Andric // A Log2SEW of 0 is an operation on mask registers only. 12481ad6265SDimitry Andric return Log2SEW == 0; 12581ad6265SDimitry Andric } 12681ad6265SDimitry Andric 12781ad6265SDimitry Andric /// Which subfields of VL or VTYPE have values we need to preserve? 12881ad6265SDimitry Andric struct DemandedFields { 129*bdd1243dSDimitry Andric // Some unknown property of VL is used. If demanded, must preserve entire 130*bdd1243dSDimitry Andric // value. 131*bdd1243dSDimitry Andric bool VLAny = false; 132*bdd1243dSDimitry Andric // Only zero vs non-zero is used. If demanded, can change non-zero values. 133*bdd1243dSDimitry Andric bool VLZeroness = false; 13481ad6265SDimitry Andric bool SEW = false; 13581ad6265SDimitry Andric bool LMUL = false; 13681ad6265SDimitry Andric bool SEWLMULRatio = false; 13781ad6265SDimitry Andric bool TailPolicy = false; 13881ad6265SDimitry Andric bool MaskPolicy = false; 13981ad6265SDimitry Andric 14081ad6265SDimitry Andric // Return true if any part of VTYPE was used 141*bdd1243dSDimitry Andric bool usedVTYPE() const { 14281ad6265SDimitry Andric return SEW || LMUL || SEWLMULRatio || TailPolicy || MaskPolicy; 14381ad6265SDimitry Andric } 14481ad6265SDimitry Andric 145*bdd1243dSDimitry Andric // Return true if any property of VL was used 146*bdd1243dSDimitry Andric bool usedVL() { 147*bdd1243dSDimitry Andric return VLAny || VLZeroness; 148*bdd1243dSDimitry Andric } 149*bdd1243dSDimitry Andric 15081ad6265SDimitry Andric // Mark all VTYPE subfields and properties as demanded 15181ad6265SDimitry Andric void demandVTYPE() { 15281ad6265SDimitry Andric SEW = true; 15381ad6265SDimitry Andric LMUL = true; 15481ad6265SDimitry Andric SEWLMULRatio = true; 15581ad6265SDimitry Andric TailPolicy = true; 15681ad6265SDimitry Andric MaskPolicy = true; 15781ad6265SDimitry Andric } 158*bdd1243dSDimitry Andric 159*bdd1243dSDimitry Andric // Mark all VL properties as demanded 160*bdd1243dSDimitry Andric void demandVL() { 161*bdd1243dSDimitry Andric VLAny = true; 162*bdd1243dSDimitry Andric VLZeroness = true; 163*bdd1243dSDimitry Andric } 164*bdd1243dSDimitry Andric 165*bdd1243dSDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 166*bdd1243dSDimitry Andric /// Support for debugging, callable in GDB: V->dump() 167*bdd1243dSDimitry Andric LLVM_DUMP_METHOD void dump() const { 168*bdd1243dSDimitry Andric print(dbgs()); 169*bdd1243dSDimitry Andric dbgs() << "\n"; 170*bdd1243dSDimitry Andric } 171*bdd1243dSDimitry Andric 172*bdd1243dSDimitry Andric /// Implement operator<<. 173*bdd1243dSDimitry Andric void print(raw_ostream &OS) const { 174*bdd1243dSDimitry Andric OS << "{"; 175*bdd1243dSDimitry Andric OS << "VLAny=" << VLAny << ", "; 176*bdd1243dSDimitry Andric OS << "VLZeroness=" << VLZeroness << ", "; 177*bdd1243dSDimitry Andric OS << "SEW=" << SEW << ", "; 178*bdd1243dSDimitry Andric OS << "LMUL=" << LMUL << ", "; 179*bdd1243dSDimitry Andric OS << "SEWLMULRatio=" << SEWLMULRatio << ", "; 180*bdd1243dSDimitry Andric OS << "TailPolicy=" << TailPolicy << ", "; 181*bdd1243dSDimitry Andric OS << "MaskPolicy=" << MaskPolicy; 182*bdd1243dSDimitry Andric OS << "}"; 183*bdd1243dSDimitry Andric } 184*bdd1243dSDimitry Andric #endif 18581ad6265SDimitry Andric }; 18681ad6265SDimitry Andric 187*bdd1243dSDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 188*bdd1243dSDimitry Andric LLVM_ATTRIBUTE_USED 189*bdd1243dSDimitry Andric inline raw_ostream &operator<<(raw_ostream &OS, const DemandedFields &DF) { 190*bdd1243dSDimitry Andric DF.print(OS); 191*bdd1243dSDimitry Andric return OS; 192*bdd1243dSDimitry Andric } 193*bdd1243dSDimitry Andric #endif 194*bdd1243dSDimitry Andric 195*bdd1243dSDimitry Andric 19681ad6265SDimitry Andric /// Return true if the two values of the VTYPE register provided are 19781ad6265SDimitry Andric /// indistinguishable from the perspective of an instruction (or set of 19881ad6265SDimitry Andric /// instructions) which use only the Used subfields and properties. 19981ad6265SDimitry Andric static bool areCompatibleVTYPEs(uint64_t VType1, 20081ad6265SDimitry Andric uint64_t VType2, 20181ad6265SDimitry Andric const DemandedFields &Used) { 20281ad6265SDimitry Andric if (Used.SEW && 20381ad6265SDimitry Andric RISCVVType::getSEW(VType1) != RISCVVType::getSEW(VType2)) 20481ad6265SDimitry Andric return false; 20581ad6265SDimitry Andric 20681ad6265SDimitry Andric if (Used.LMUL && 20781ad6265SDimitry Andric RISCVVType::getVLMUL(VType1) != RISCVVType::getVLMUL(VType2)) 20881ad6265SDimitry Andric return false; 20981ad6265SDimitry Andric 21081ad6265SDimitry Andric if (Used.SEWLMULRatio) { 211*bdd1243dSDimitry Andric auto Ratio1 = RISCVVType::getSEWLMULRatio(RISCVVType::getSEW(VType1), 21281ad6265SDimitry Andric RISCVVType::getVLMUL(VType1)); 213*bdd1243dSDimitry Andric auto Ratio2 = RISCVVType::getSEWLMULRatio(RISCVVType::getSEW(VType2), 21481ad6265SDimitry Andric RISCVVType::getVLMUL(VType2)); 21581ad6265SDimitry Andric if (Ratio1 != Ratio2) 21681ad6265SDimitry Andric return false; 21781ad6265SDimitry Andric } 21881ad6265SDimitry Andric 21981ad6265SDimitry Andric if (Used.TailPolicy && 22081ad6265SDimitry Andric RISCVVType::isTailAgnostic(VType1) != RISCVVType::isTailAgnostic(VType2)) 22181ad6265SDimitry Andric return false; 22281ad6265SDimitry Andric if (Used.MaskPolicy && 22381ad6265SDimitry Andric RISCVVType::isMaskAgnostic(VType1) != RISCVVType::isMaskAgnostic(VType2)) 22481ad6265SDimitry Andric return false; 22581ad6265SDimitry Andric return true; 22681ad6265SDimitry Andric } 22781ad6265SDimitry Andric 22881ad6265SDimitry Andric /// Return the fields and properties demanded by the provided instruction. 22981ad6265SDimitry Andric static DemandedFields getDemanded(const MachineInstr &MI) { 23081ad6265SDimitry Andric // Warning: This function has to work on both the lowered (i.e. post 23181ad6265SDimitry Andric // emitVSETVLIs) and pre-lowering forms. The main implication of this is 23281ad6265SDimitry Andric // that it can't use the value of a SEW, VL, or Policy operand as they might 23381ad6265SDimitry Andric // be stale after lowering. 23481ad6265SDimitry Andric 23581ad6265SDimitry Andric // Most instructions don't use any of these subfeilds. 23681ad6265SDimitry Andric DemandedFields Res; 23781ad6265SDimitry Andric // Start conservative if registers are used 23881ad6265SDimitry Andric if (MI.isCall() || MI.isInlineAsm() || MI.readsRegister(RISCV::VL)) 239*bdd1243dSDimitry Andric Res.demandVL();; 24081ad6265SDimitry Andric if (MI.isCall() || MI.isInlineAsm() || MI.readsRegister(RISCV::VTYPE)) 24181ad6265SDimitry Andric Res.demandVTYPE(); 24281ad6265SDimitry Andric // Start conservative on the unlowered form too 24381ad6265SDimitry Andric uint64_t TSFlags = MI.getDesc().TSFlags; 24481ad6265SDimitry Andric if (RISCVII::hasSEWOp(TSFlags)) { 24581ad6265SDimitry Andric Res.demandVTYPE(); 24681ad6265SDimitry Andric if (RISCVII::hasVLOp(TSFlags)) 247*bdd1243dSDimitry Andric Res.demandVL(); 248*bdd1243dSDimitry Andric 249*bdd1243dSDimitry Andric // Behavior is independent of mask policy. 250*bdd1243dSDimitry Andric if (!RISCVII::usesMaskPolicy(TSFlags)) 251*bdd1243dSDimitry Andric Res.MaskPolicy = false; 25281ad6265SDimitry Andric } 25381ad6265SDimitry Andric 25481ad6265SDimitry Andric // Loads and stores with implicit EEW do not demand SEW or LMUL directly. 25581ad6265SDimitry Andric // They instead demand the ratio of the two which is used in computing 25681ad6265SDimitry Andric // EMUL, but which allows us the flexibility to change SEW and LMUL 25781ad6265SDimitry Andric // provided we don't change the ratio. 25881ad6265SDimitry Andric // Note: We assume that the instructions initial SEW is the EEW encoded 25981ad6265SDimitry Andric // in the opcode. This is asserted when constructing the VSETVLIInfo. 26081ad6265SDimitry Andric if (getEEWForLoadStore(MI)) { 26181ad6265SDimitry Andric Res.SEW = false; 26281ad6265SDimitry Andric Res.LMUL = false; 26381ad6265SDimitry Andric } 26481ad6265SDimitry Andric 26581ad6265SDimitry Andric // Store instructions don't use the policy fields. 26681ad6265SDimitry Andric if (RISCVII::hasSEWOp(TSFlags) && MI.getNumExplicitDefs() == 0) { 26781ad6265SDimitry Andric Res.TailPolicy = false; 26881ad6265SDimitry Andric Res.MaskPolicy = false; 26981ad6265SDimitry Andric } 27081ad6265SDimitry Andric 27181ad6265SDimitry Andric // If this is a mask reg operation, it only cares about VLMAX. 27281ad6265SDimitry Andric // TODO: Possible extensions to this logic 27381ad6265SDimitry Andric // * Probably ok if available VLMax is larger than demanded 27481ad6265SDimitry Andric // * The policy bits can probably be ignored.. 27581ad6265SDimitry Andric if (isMaskRegOp(MI)) { 27681ad6265SDimitry Andric Res.SEW = false; 27781ad6265SDimitry Andric Res.LMUL = false; 27881ad6265SDimitry Andric } 27981ad6265SDimitry Andric 280*bdd1243dSDimitry Andric // For vmv.s.x and vfmv.s.f, there are only two behaviors, VL = 0 and VL > 0. 281*bdd1243dSDimitry Andric if (isScalarMoveInstr(MI)) { 282*bdd1243dSDimitry Andric Res.LMUL = false; 283*bdd1243dSDimitry Andric Res.SEWLMULRatio = false; 284*bdd1243dSDimitry Andric Res.VLAny = false; 285*bdd1243dSDimitry Andric } 286*bdd1243dSDimitry Andric 28781ad6265SDimitry Andric return Res; 28881ad6265SDimitry Andric } 28981ad6265SDimitry Andric 29081ad6265SDimitry Andric /// Defines the abstract state with which the forward dataflow models the 29181ad6265SDimitry Andric /// values of the VL and VTYPE registers after insertion. 29281ad6265SDimitry Andric class VSETVLIInfo { 29381ad6265SDimitry Andric union { 29481ad6265SDimitry Andric Register AVLReg; 29581ad6265SDimitry Andric unsigned AVLImm; 29681ad6265SDimitry Andric }; 29781ad6265SDimitry Andric 29881ad6265SDimitry Andric enum : uint8_t { 29981ad6265SDimitry Andric Uninitialized, 30081ad6265SDimitry Andric AVLIsReg, 30181ad6265SDimitry Andric AVLIsImm, 30281ad6265SDimitry Andric Unknown, 30381ad6265SDimitry Andric } State = Uninitialized; 30481ad6265SDimitry Andric 30581ad6265SDimitry Andric // Fields from VTYPE. 30681ad6265SDimitry Andric RISCVII::VLMUL VLMul = RISCVII::LMUL_1; 30781ad6265SDimitry Andric uint8_t SEW = 0; 30881ad6265SDimitry Andric uint8_t TailAgnostic : 1; 30981ad6265SDimitry Andric uint8_t MaskAgnostic : 1; 31081ad6265SDimitry Andric uint8_t SEWLMULRatioOnly : 1; 31181ad6265SDimitry Andric 31281ad6265SDimitry Andric public: 31381ad6265SDimitry Andric VSETVLIInfo() 31481ad6265SDimitry Andric : AVLImm(0), TailAgnostic(false), MaskAgnostic(false), 31581ad6265SDimitry Andric SEWLMULRatioOnly(false) {} 31681ad6265SDimitry Andric 31781ad6265SDimitry Andric static VSETVLIInfo getUnknown() { 31881ad6265SDimitry Andric VSETVLIInfo Info; 31981ad6265SDimitry Andric Info.setUnknown(); 32081ad6265SDimitry Andric return Info; 32181ad6265SDimitry Andric } 32281ad6265SDimitry Andric 32381ad6265SDimitry Andric bool isValid() const { return State != Uninitialized; } 32481ad6265SDimitry Andric void setUnknown() { State = Unknown; } 32581ad6265SDimitry Andric bool isUnknown() const { return State == Unknown; } 32681ad6265SDimitry Andric 32781ad6265SDimitry Andric void setAVLReg(Register Reg) { 32881ad6265SDimitry Andric AVLReg = Reg; 32981ad6265SDimitry Andric State = AVLIsReg; 33081ad6265SDimitry Andric } 33181ad6265SDimitry Andric 33281ad6265SDimitry Andric void setAVLImm(unsigned Imm) { 33381ad6265SDimitry Andric AVLImm = Imm; 33481ad6265SDimitry Andric State = AVLIsImm; 33581ad6265SDimitry Andric } 33681ad6265SDimitry Andric 33781ad6265SDimitry Andric bool hasAVLImm() const { return State == AVLIsImm; } 33881ad6265SDimitry Andric bool hasAVLReg() const { return State == AVLIsReg; } 33981ad6265SDimitry Andric Register getAVLReg() const { 34081ad6265SDimitry Andric assert(hasAVLReg()); 34181ad6265SDimitry Andric return AVLReg; 34281ad6265SDimitry Andric } 34381ad6265SDimitry Andric unsigned getAVLImm() const { 34481ad6265SDimitry Andric assert(hasAVLImm()); 34581ad6265SDimitry Andric return AVLImm; 34681ad6265SDimitry Andric } 34781ad6265SDimitry Andric 34881ad6265SDimitry Andric unsigned getSEW() const { return SEW; } 34981ad6265SDimitry Andric RISCVII::VLMUL getVLMUL() const { return VLMul; } 35081ad6265SDimitry Andric 35181ad6265SDimitry Andric bool hasNonZeroAVL() const { 35281ad6265SDimitry Andric if (hasAVLImm()) 35381ad6265SDimitry Andric return getAVLImm() > 0; 35481ad6265SDimitry Andric if (hasAVLReg()) 35581ad6265SDimitry Andric return getAVLReg() == RISCV::X0; 35681ad6265SDimitry Andric return false; 35781ad6265SDimitry Andric } 35881ad6265SDimitry Andric 359*bdd1243dSDimitry Andric bool hasEquallyZeroAVL(const VSETVLIInfo &Other) const { 360*bdd1243dSDimitry Andric if (hasSameAVL(Other)) 361*bdd1243dSDimitry Andric return true; 362*bdd1243dSDimitry Andric return (hasNonZeroAVL() && Other.hasNonZeroAVL()); 363*bdd1243dSDimitry Andric } 364*bdd1243dSDimitry Andric 36581ad6265SDimitry Andric bool hasSameAVL(const VSETVLIInfo &Other) const { 36681ad6265SDimitry Andric if (hasAVLReg() && Other.hasAVLReg()) 36781ad6265SDimitry Andric return getAVLReg() == Other.getAVLReg(); 36881ad6265SDimitry Andric 36981ad6265SDimitry Andric if (hasAVLImm() && Other.hasAVLImm()) 37081ad6265SDimitry Andric return getAVLImm() == Other.getAVLImm(); 37181ad6265SDimitry Andric 37281ad6265SDimitry Andric return false; 37381ad6265SDimitry Andric } 37481ad6265SDimitry Andric 37581ad6265SDimitry Andric void setVTYPE(unsigned VType) { 37681ad6265SDimitry Andric assert(isValid() && !isUnknown() && 37781ad6265SDimitry Andric "Can't set VTYPE for uninitialized or unknown"); 37881ad6265SDimitry Andric VLMul = RISCVVType::getVLMUL(VType); 37981ad6265SDimitry Andric SEW = RISCVVType::getSEW(VType); 38081ad6265SDimitry Andric TailAgnostic = RISCVVType::isTailAgnostic(VType); 38181ad6265SDimitry Andric MaskAgnostic = RISCVVType::isMaskAgnostic(VType); 38281ad6265SDimitry Andric } 38381ad6265SDimitry Andric void setVTYPE(RISCVII::VLMUL L, unsigned S, bool TA, bool MA) { 38481ad6265SDimitry Andric assert(isValid() && !isUnknown() && 38581ad6265SDimitry Andric "Can't set VTYPE for uninitialized or unknown"); 38681ad6265SDimitry Andric VLMul = L; 38781ad6265SDimitry Andric SEW = S; 38881ad6265SDimitry Andric TailAgnostic = TA; 38981ad6265SDimitry Andric MaskAgnostic = MA; 39081ad6265SDimitry Andric } 39181ad6265SDimitry Andric 39281ad6265SDimitry Andric unsigned encodeVTYPE() const { 39381ad6265SDimitry Andric assert(isValid() && !isUnknown() && !SEWLMULRatioOnly && 39481ad6265SDimitry Andric "Can't encode VTYPE for uninitialized or unknown"); 39581ad6265SDimitry Andric return RISCVVType::encodeVTYPE(VLMul, SEW, TailAgnostic, MaskAgnostic); 39681ad6265SDimitry Andric } 39781ad6265SDimitry Andric 39881ad6265SDimitry Andric bool hasSEWLMULRatioOnly() const { return SEWLMULRatioOnly; } 39981ad6265SDimitry Andric 40081ad6265SDimitry Andric bool hasSameVTYPE(const VSETVLIInfo &Other) const { 40181ad6265SDimitry Andric assert(isValid() && Other.isValid() && 40281ad6265SDimitry Andric "Can't compare invalid VSETVLIInfos"); 40381ad6265SDimitry Andric assert(!isUnknown() && !Other.isUnknown() && 40481ad6265SDimitry Andric "Can't compare VTYPE in unknown state"); 40581ad6265SDimitry Andric assert(!SEWLMULRatioOnly && !Other.SEWLMULRatioOnly && 40681ad6265SDimitry Andric "Can't compare when only LMUL/SEW ratio is valid."); 40781ad6265SDimitry Andric return std::tie(VLMul, SEW, TailAgnostic, MaskAgnostic) == 40881ad6265SDimitry Andric std::tie(Other.VLMul, Other.SEW, Other.TailAgnostic, 40981ad6265SDimitry Andric Other.MaskAgnostic); 41081ad6265SDimitry Andric } 41181ad6265SDimitry Andric 41281ad6265SDimitry Andric unsigned getSEWLMULRatio() const { 41381ad6265SDimitry Andric assert(isValid() && !isUnknown() && 41481ad6265SDimitry Andric "Can't use VTYPE for uninitialized or unknown"); 415*bdd1243dSDimitry Andric return RISCVVType::getSEWLMULRatio(SEW, VLMul); 41681ad6265SDimitry Andric } 41781ad6265SDimitry Andric 41881ad6265SDimitry Andric // Check if the VTYPE for these two VSETVLIInfos produce the same VLMAX. 41981ad6265SDimitry Andric // Note that having the same VLMAX ensures that both share the same 42081ad6265SDimitry Andric // function from AVL to VL; that is, they must produce the same VL value 42181ad6265SDimitry Andric // for any given AVL value. 42281ad6265SDimitry Andric bool hasSameVLMAX(const VSETVLIInfo &Other) const { 42381ad6265SDimitry Andric assert(isValid() && Other.isValid() && 42481ad6265SDimitry Andric "Can't compare invalid VSETVLIInfos"); 42581ad6265SDimitry Andric assert(!isUnknown() && !Other.isUnknown() && 42681ad6265SDimitry Andric "Can't compare VTYPE in unknown state"); 42781ad6265SDimitry Andric return getSEWLMULRatio() == Other.getSEWLMULRatio(); 42881ad6265SDimitry Andric } 42981ad6265SDimitry Andric 430*bdd1243dSDimitry Andric bool hasCompatibleVTYPE(const DemandedFields &Used, 43181ad6265SDimitry Andric const VSETVLIInfo &Require) const { 43281ad6265SDimitry Andric return areCompatibleVTYPEs(encodeVTYPE(), Require.encodeVTYPE(), Used); 43381ad6265SDimitry Andric } 43481ad6265SDimitry Andric 43581ad6265SDimitry Andric // Determine whether the vector instructions requirements represented by 43681ad6265SDimitry Andric // Require are compatible with the previous vsetvli instruction represented 43781ad6265SDimitry Andric // by this. MI is the instruction whose requirements we're considering. 438*bdd1243dSDimitry Andric bool isCompatible(const DemandedFields &Used, const VSETVLIInfo &Require) const { 43981ad6265SDimitry Andric assert(isValid() && Require.isValid() && 44081ad6265SDimitry Andric "Can't compare invalid VSETVLIInfos"); 44181ad6265SDimitry Andric assert(!Require.SEWLMULRatioOnly && 44281ad6265SDimitry Andric "Expected a valid VTYPE for instruction!"); 44381ad6265SDimitry Andric // Nothing is compatible with Unknown. 44481ad6265SDimitry Andric if (isUnknown() || Require.isUnknown()) 44581ad6265SDimitry Andric return false; 44681ad6265SDimitry Andric 44781ad6265SDimitry Andric // If only our VLMAX ratio is valid, then this isn't compatible. 44881ad6265SDimitry Andric if (SEWLMULRatioOnly) 44981ad6265SDimitry Andric return false; 45081ad6265SDimitry Andric 45181ad6265SDimitry Andric // If the instruction doesn't need an AVLReg and the SEW matches, consider 45281ad6265SDimitry Andric // it compatible. 45381ad6265SDimitry Andric if (Require.hasAVLReg() && Require.AVLReg == RISCV::NoRegister) 45481ad6265SDimitry Andric if (SEW == Require.SEW) 45581ad6265SDimitry Andric return true; 45681ad6265SDimitry Andric 457*bdd1243dSDimitry Andric if (Used.VLAny && !hasSameAVL(Require)) 458*bdd1243dSDimitry Andric return false; 459*bdd1243dSDimitry Andric 460*bdd1243dSDimitry Andric if (Used.VLZeroness && !hasEquallyZeroAVL(Require)) 461*bdd1243dSDimitry Andric return false; 462*bdd1243dSDimitry Andric 463*bdd1243dSDimitry Andric return areCompatibleVTYPEs(encodeVTYPE(), Require.encodeVTYPE(), Used); 46481ad6265SDimitry Andric } 46581ad6265SDimitry Andric 46681ad6265SDimitry Andric bool operator==(const VSETVLIInfo &Other) const { 46781ad6265SDimitry Andric // Uninitialized is only equal to another Uninitialized. 46881ad6265SDimitry Andric if (!isValid()) 46981ad6265SDimitry Andric return !Other.isValid(); 47081ad6265SDimitry Andric if (!Other.isValid()) 47181ad6265SDimitry Andric return !isValid(); 47281ad6265SDimitry Andric 47381ad6265SDimitry Andric // Unknown is only equal to another Unknown. 47481ad6265SDimitry Andric if (isUnknown()) 47581ad6265SDimitry Andric return Other.isUnknown(); 47681ad6265SDimitry Andric if (Other.isUnknown()) 47781ad6265SDimitry Andric return isUnknown(); 47881ad6265SDimitry Andric 47981ad6265SDimitry Andric if (!hasSameAVL(Other)) 48081ad6265SDimitry Andric return false; 48181ad6265SDimitry Andric 48281ad6265SDimitry Andric // If the SEWLMULRatioOnly bits are different, then they aren't equal. 48381ad6265SDimitry Andric if (SEWLMULRatioOnly != Other.SEWLMULRatioOnly) 48481ad6265SDimitry Andric return false; 48581ad6265SDimitry Andric 48681ad6265SDimitry Andric // If only the VLMAX is valid, check that it is the same. 48781ad6265SDimitry Andric if (SEWLMULRatioOnly) 48881ad6265SDimitry Andric return hasSameVLMAX(Other); 48981ad6265SDimitry Andric 49081ad6265SDimitry Andric // If the full VTYPE is valid, check that it is the same. 49181ad6265SDimitry Andric return hasSameVTYPE(Other); 49281ad6265SDimitry Andric } 49381ad6265SDimitry Andric 49481ad6265SDimitry Andric bool operator!=(const VSETVLIInfo &Other) const { 49581ad6265SDimitry Andric return !(*this == Other); 49681ad6265SDimitry Andric } 49781ad6265SDimitry Andric 49881ad6265SDimitry Andric // Calculate the VSETVLIInfo visible to a block assuming this and Other are 49981ad6265SDimitry Andric // both predecessors. 50081ad6265SDimitry Andric VSETVLIInfo intersect(const VSETVLIInfo &Other) const { 50181ad6265SDimitry Andric // If the new value isn't valid, ignore it. 50281ad6265SDimitry Andric if (!Other.isValid()) 50381ad6265SDimitry Andric return *this; 50481ad6265SDimitry Andric 50581ad6265SDimitry Andric // If this value isn't valid, this must be the first predecessor, use it. 50681ad6265SDimitry Andric if (!isValid()) 50781ad6265SDimitry Andric return Other; 50881ad6265SDimitry Andric 50981ad6265SDimitry Andric // If either is unknown, the result is unknown. 51081ad6265SDimitry Andric if (isUnknown() || Other.isUnknown()) 51181ad6265SDimitry Andric return VSETVLIInfo::getUnknown(); 51281ad6265SDimitry Andric 51381ad6265SDimitry Andric // If we have an exact, match return this. 51481ad6265SDimitry Andric if (*this == Other) 51581ad6265SDimitry Andric return *this; 51681ad6265SDimitry Andric 51781ad6265SDimitry Andric // Not an exact match, but maybe the AVL and VLMAX are the same. If so, 51881ad6265SDimitry Andric // return an SEW/LMUL ratio only value. 51981ad6265SDimitry Andric if (hasSameAVL(Other) && hasSameVLMAX(Other)) { 52081ad6265SDimitry Andric VSETVLIInfo MergeInfo = *this; 52181ad6265SDimitry Andric MergeInfo.SEWLMULRatioOnly = true; 52281ad6265SDimitry Andric return MergeInfo; 52381ad6265SDimitry Andric } 52481ad6265SDimitry Andric 52581ad6265SDimitry Andric // Otherwise the result is unknown. 52681ad6265SDimitry Andric return VSETVLIInfo::getUnknown(); 52781ad6265SDimitry Andric } 52881ad6265SDimitry Andric 52981ad6265SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 53081ad6265SDimitry Andric /// Support for debugging, callable in GDB: V->dump() 53181ad6265SDimitry Andric LLVM_DUMP_METHOD void dump() const { 53281ad6265SDimitry Andric print(dbgs()); 53381ad6265SDimitry Andric dbgs() << "\n"; 53481ad6265SDimitry Andric } 53581ad6265SDimitry Andric 53681ad6265SDimitry Andric /// Implement operator<<. 53781ad6265SDimitry Andric /// @{ 53881ad6265SDimitry Andric void print(raw_ostream &OS) const { 53981ad6265SDimitry Andric OS << "{"; 54081ad6265SDimitry Andric if (!isValid()) 54181ad6265SDimitry Andric OS << "Uninitialized"; 54281ad6265SDimitry Andric if (isUnknown()) 54381ad6265SDimitry Andric OS << "unknown"; 54481ad6265SDimitry Andric if (hasAVLReg()) 54581ad6265SDimitry Andric OS << "AVLReg=" << (unsigned)AVLReg; 54681ad6265SDimitry Andric if (hasAVLImm()) 54781ad6265SDimitry Andric OS << "AVLImm=" << (unsigned)AVLImm; 54881ad6265SDimitry Andric OS << ", " 54981ad6265SDimitry Andric << "VLMul=" << (unsigned)VLMul << ", " 55081ad6265SDimitry Andric << "SEW=" << (unsigned)SEW << ", " 55181ad6265SDimitry Andric << "TailAgnostic=" << (bool)TailAgnostic << ", " 55281ad6265SDimitry Andric << "MaskAgnostic=" << (bool)MaskAgnostic << ", " 55381ad6265SDimitry Andric << "SEWLMULRatioOnly=" << (bool)SEWLMULRatioOnly << "}"; 55481ad6265SDimitry Andric } 55581ad6265SDimitry Andric #endif 55681ad6265SDimitry Andric }; 55781ad6265SDimitry Andric 55881ad6265SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 55981ad6265SDimitry Andric LLVM_ATTRIBUTE_USED 56081ad6265SDimitry Andric inline raw_ostream &operator<<(raw_ostream &OS, const VSETVLIInfo &V) { 56181ad6265SDimitry Andric V.print(OS); 56281ad6265SDimitry Andric return OS; 56381ad6265SDimitry Andric } 56481ad6265SDimitry Andric #endif 56581ad6265SDimitry Andric 56681ad6265SDimitry Andric struct BlockData { 56781ad6265SDimitry Andric // The VSETVLIInfo that represents the net changes to the VL/VTYPE registers 56881ad6265SDimitry Andric // made by this block. Calculated in Phase 1. 56981ad6265SDimitry Andric VSETVLIInfo Change; 57081ad6265SDimitry Andric 57181ad6265SDimitry Andric // The VSETVLIInfo that represents the VL/VTYPE settings on exit from this 57281ad6265SDimitry Andric // block. Calculated in Phase 2. 57381ad6265SDimitry Andric VSETVLIInfo Exit; 57481ad6265SDimitry Andric 57581ad6265SDimitry Andric // The VSETVLIInfo that represents the VL/VTYPE settings from all predecessor 57681ad6265SDimitry Andric // blocks. Calculated in Phase 2, and used by Phase 3. 57781ad6265SDimitry Andric VSETVLIInfo Pred; 57881ad6265SDimitry Andric 57981ad6265SDimitry Andric // Keeps track of whether the block is already in the queue. 58081ad6265SDimitry Andric bool InQueue = false; 58181ad6265SDimitry Andric 58281ad6265SDimitry Andric BlockData() = default; 58381ad6265SDimitry Andric }; 58481ad6265SDimitry Andric 58581ad6265SDimitry Andric class RISCVInsertVSETVLI : public MachineFunctionPass { 58681ad6265SDimitry Andric const TargetInstrInfo *TII; 58781ad6265SDimitry Andric MachineRegisterInfo *MRI; 58881ad6265SDimitry Andric 58981ad6265SDimitry Andric std::vector<BlockData> BlockInfo; 59081ad6265SDimitry Andric std::queue<const MachineBasicBlock *> WorkList; 59181ad6265SDimitry Andric 59281ad6265SDimitry Andric public: 59381ad6265SDimitry Andric static char ID; 59481ad6265SDimitry Andric 59581ad6265SDimitry Andric RISCVInsertVSETVLI() : MachineFunctionPass(ID) { 59681ad6265SDimitry Andric initializeRISCVInsertVSETVLIPass(*PassRegistry::getPassRegistry()); 59781ad6265SDimitry Andric } 59881ad6265SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 59981ad6265SDimitry Andric 60081ad6265SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 60181ad6265SDimitry Andric AU.setPreservesCFG(); 60281ad6265SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 60381ad6265SDimitry Andric } 60481ad6265SDimitry Andric 60581ad6265SDimitry Andric StringRef getPassName() const override { return RISCV_INSERT_VSETVLI_NAME; } 60681ad6265SDimitry Andric 60781ad6265SDimitry Andric private: 60881ad6265SDimitry Andric bool needVSETVLI(const MachineInstr &MI, const VSETVLIInfo &Require, 60981ad6265SDimitry Andric const VSETVLIInfo &CurInfo) const; 61081ad6265SDimitry Andric bool needVSETVLIPHI(const VSETVLIInfo &Require, 61181ad6265SDimitry Andric const MachineBasicBlock &MBB) const; 61281ad6265SDimitry Andric void insertVSETVLI(MachineBasicBlock &MBB, MachineInstr &MI, 61381ad6265SDimitry Andric const VSETVLIInfo &Info, const VSETVLIInfo &PrevInfo); 61481ad6265SDimitry Andric void insertVSETVLI(MachineBasicBlock &MBB, 61581ad6265SDimitry Andric MachineBasicBlock::iterator InsertPt, DebugLoc DL, 61681ad6265SDimitry Andric const VSETVLIInfo &Info, const VSETVLIInfo &PrevInfo); 61781ad6265SDimitry Andric 61881ad6265SDimitry Andric void transferBefore(VSETVLIInfo &Info, const MachineInstr &MI); 61981ad6265SDimitry Andric void transferAfter(VSETVLIInfo &Info, const MachineInstr &MI); 62081ad6265SDimitry Andric bool computeVLVTYPEChanges(const MachineBasicBlock &MBB); 62181ad6265SDimitry Andric void computeIncomingVLVTYPE(const MachineBasicBlock &MBB); 62281ad6265SDimitry Andric void emitVSETVLIs(MachineBasicBlock &MBB); 62381ad6265SDimitry Andric void doLocalPostpass(MachineBasicBlock &MBB); 62481ad6265SDimitry Andric void doPRE(MachineBasicBlock &MBB); 62581ad6265SDimitry Andric void insertReadVL(MachineBasicBlock &MBB); 62681ad6265SDimitry Andric }; 62781ad6265SDimitry Andric 62881ad6265SDimitry Andric } // end anonymous namespace 62981ad6265SDimitry Andric 63081ad6265SDimitry Andric char RISCVInsertVSETVLI::ID = 0; 63181ad6265SDimitry Andric 63281ad6265SDimitry Andric INITIALIZE_PASS(RISCVInsertVSETVLI, DEBUG_TYPE, RISCV_INSERT_VSETVLI_NAME, 63381ad6265SDimitry Andric false, false) 63481ad6265SDimitry Andric 63581ad6265SDimitry Andric static VSETVLIInfo computeInfoForInstr(const MachineInstr &MI, uint64_t TSFlags, 63681ad6265SDimitry Andric const MachineRegisterInfo *MRI) { 63781ad6265SDimitry Andric VSETVLIInfo InstrInfo; 63881ad6265SDimitry Andric 639*bdd1243dSDimitry Andric bool TailAgnostic, MaskAgnostic; 64081ad6265SDimitry Andric unsigned UseOpIdx; 641*bdd1243dSDimitry Andric if (MI.isRegTiedToUseOperand(0, &UseOpIdx)) { 642*bdd1243dSDimitry Andric // Start with undisturbed. 643*bdd1243dSDimitry Andric TailAgnostic = false; 644*bdd1243dSDimitry Andric MaskAgnostic = false; 645*bdd1243dSDimitry Andric 646*bdd1243dSDimitry Andric // If there is a policy operand, use it. 64781ad6265SDimitry Andric if (RISCVII::hasVecPolicyOp(TSFlags)) { 64881ad6265SDimitry Andric const MachineOperand &Op = MI.getOperand(MI.getNumExplicitOperands() - 1); 64981ad6265SDimitry Andric uint64_t Policy = Op.getImm(); 65081ad6265SDimitry Andric assert(Policy <= (RISCVII::TAIL_AGNOSTIC | RISCVII::MASK_AGNOSTIC) && 65181ad6265SDimitry Andric "Invalid Policy Value"); 65281ad6265SDimitry Andric TailAgnostic = Policy & RISCVII::TAIL_AGNOSTIC; 65381ad6265SDimitry Andric MaskAgnostic = Policy & RISCVII::MASK_AGNOSTIC; 654*bdd1243dSDimitry Andric } 655*bdd1243dSDimitry Andric 656*bdd1243dSDimitry Andric // If the tied operand is an IMPLICIT_DEF we can use TailAgnostic and 657*bdd1243dSDimitry Andric // MaskAgnostic. 65881ad6265SDimitry Andric const MachineOperand &UseMO = MI.getOperand(UseOpIdx); 65981ad6265SDimitry Andric MachineInstr *UseMI = MRI->getVRegDef(UseMO.getReg()); 66081ad6265SDimitry Andric if (UseMI && UseMI->isImplicitDef()) { 66181ad6265SDimitry Andric TailAgnostic = true; 66281ad6265SDimitry Andric MaskAgnostic = true; 66381ad6265SDimitry Andric } 66481ad6265SDimitry Andric // Some pseudo instructions force a tail agnostic policy despite having a 66581ad6265SDimitry Andric // tied def. 66681ad6265SDimitry Andric if (RISCVII::doesForceTailAgnostic(TSFlags)) 66781ad6265SDimitry Andric TailAgnostic = true; 668*bdd1243dSDimitry Andric 669*bdd1243dSDimitry Andric if (!RISCVII::usesMaskPolicy(TSFlags)) 670*bdd1243dSDimitry Andric MaskAgnostic = true; 671*bdd1243dSDimitry Andric } else { 672*bdd1243dSDimitry Andric // If there is no tied operand,, there shouldn't be a policy operand. 673*bdd1243dSDimitry Andric assert(!RISCVII::hasVecPolicyOp(TSFlags) && "Unexpected policy operand"); 674*bdd1243dSDimitry Andric // No tied operand use agnostic policies. 675*bdd1243dSDimitry Andric TailAgnostic = true; 676*bdd1243dSDimitry Andric MaskAgnostic = true; 67781ad6265SDimitry Andric } 67881ad6265SDimitry Andric 67981ad6265SDimitry Andric RISCVII::VLMUL VLMul = RISCVII::getLMul(TSFlags); 68081ad6265SDimitry Andric 68181ad6265SDimitry Andric unsigned Log2SEW = MI.getOperand(getSEWOpNum(MI)).getImm(); 68281ad6265SDimitry Andric // A Log2SEW of 0 is an operation on mask registers only. 68381ad6265SDimitry Andric unsigned SEW = Log2SEW ? 1 << Log2SEW : 8; 68481ad6265SDimitry Andric assert(RISCVVType::isValidSEW(SEW) && "Unexpected SEW"); 68581ad6265SDimitry Andric 68681ad6265SDimitry Andric if (RISCVII::hasVLOp(TSFlags)) { 68781ad6265SDimitry Andric const MachineOperand &VLOp = MI.getOperand(getVLOpNum(MI)); 68881ad6265SDimitry Andric if (VLOp.isImm()) { 68981ad6265SDimitry Andric int64_t Imm = VLOp.getImm(); 69081ad6265SDimitry Andric // Conver the VLMax sentintel to X0 register. 69181ad6265SDimitry Andric if (Imm == RISCV::VLMaxSentinel) 69281ad6265SDimitry Andric InstrInfo.setAVLReg(RISCV::X0); 69381ad6265SDimitry Andric else 69481ad6265SDimitry Andric InstrInfo.setAVLImm(Imm); 69581ad6265SDimitry Andric } else { 69681ad6265SDimitry Andric InstrInfo.setAVLReg(VLOp.getReg()); 69781ad6265SDimitry Andric } 69881ad6265SDimitry Andric } else { 69981ad6265SDimitry Andric InstrInfo.setAVLReg(RISCV::NoRegister); 70081ad6265SDimitry Andric } 70181ad6265SDimitry Andric #ifndef NDEBUG 702*bdd1243dSDimitry Andric if (std::optional<unsigned> EEW = getEEWForLoadStore(MI)) { 70381ad6265SDimitry Andric assert(SEW == EEW && "Initial SEW doesn't match expected EEW"); 70481ad6265SDimitry Andric } 70581ad6265SDimitry Andric #endif 70681ad6265SDimitry Andric InstrInfo.setVTYPE(VLMul, SEW, TailAgnostic, MaskAgnostic); 70781ad6265SDimitry Andric 70881ad6265SDimitry Andric return InstrInfo; 70981ad6265SDimitry Andric } 71081ad6265SDimitry Andric 71181ad6265SDimitry Andric void RISCVInsertVSETVLI::insertVSETVLI(MachineBasicBlock &MBB, MachineInstr &MI, 71281ad6265SDimitry Andric const VSETVLIInfo &Info, 71381ad6265SDimitry Andric const VSETVLIInfo &PrevInfo) { 71481ad6265SDimitry Andric DebugLoc DL = MI.getDebugLoc(); 71581ad6265SDimitry Andric insertVSETVLI(MBB, MachineBasicBlock::iterator(&MI), DL, Info, PrevInfo); 71681ad6265SDimitry Andric } 71781ad6265SDimitry Andric 71881ad6265SDimitry Andric void RISCVInsertVSETVLI::insertVSETVLI(MachineBasicBlock &MBB, 71981ad6265SDimitry Andric MachineBasicBlock::iterator InsertPt, DebugLoc DL, 72081ad6265SDimitry Andric const VSETVLIInfo &Info, const VSETVLIInfo &PrevInfo) { 72181ad6265SDimitry Andric 72281ad6265SDimitry Andric // Use X0, X0 form if the AVL is the same and the SEW+LMUL gives the same 72381ad6265SDimitry Andric // VLMAX. 72481ad6265SDimitry Andric if (PrevInfo.isValid() && !PrevInfo.isUnknown() && 72581ad6265SDimitry Andric Info.hasSameAVL(PrevInfo) && Info.hasSameVLMAX(PrevInfo)) { 72681ad6265SDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETVLIX0)) 72781ad6265SDimitry Andric .addReg(RISCV::X0, RegState::Define | RegState::Dead) 72881ad6265SDimitry Andric .addReg(RISCV::X0, RegState::Kill) 72981ad6265SDimitry Andric .addImm(Info.encodeVTYPE()) 73081ad6265SDimitry Andric .addReg(RISCV::VL, RegState::Implicit); 73181ad6265SDimitry Andric return; 73281ad6265SDimitry Andric } 73381ad6265SDimitry Andric 73481ad6265SDimitry Andric if (Info.hasAVLImm()) { 73581ad6265SDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETIVLI)) 73681ad6265SDimitry Andric .addReg(RISCV::X0, RegState::Define | RegState::Dead) 73781ad6265SDimitry Andric .addImm(Info.getAVLImm()) 73881ad6265SDimitry Andric .addImm(Info.encodeVTYPE()); 73981ad6265SDimitry Andric return; 74081ad6265SDimitry Andric } 74181ad6265SDimitry Andric 74281ad6265SDimitry Andric Register AVLReg = Info.getAVLReg(); 74381ad6265SDimitry Andric if (AVLReg == RISCV::NoRegister) { 74481ad6265SDimitry Andric // We can only use x0, x0 if there's no chance of the vtype change causing 74581ad6265SDimitry Andric // the previous vl to become invalid. 74681ad6265SDimitry Andric if (PrevInfo.isValid() && !PrevInfo.isUnknown() && 74781ad6265SDimitry Andric Info.hasSameVLMAX(PrevInfo)) { 74881ad6265SDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETVLIX0)) 74981ad6265SDimitry Andric .addReg(RISCV::X0, RegState::Define | RegState::Dead) 75081ad6265SDimitry Andric .addReg(RISCV::X0, RegState::Kill) 75181ad6265SDimitry Andric .addImm(Info.encodeVTYPE()) 75281ad6265SDimitry Andric .addReg(RISCV::VL, RegState::Implicit); 75381ad6265SDimitry Andric return; 75481ad6265SDimitry Andric } 75581ad6265SDimitry Andric // Otherwise use an AVL of 0 to avoid depending on previous vl. 75681ad6265SDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETIVLI)) 75781ad6265SDimitry Andric .addReg(RISCV::X0, RegState::Define | RegState::Dead) 75881ad6265SDimitry Andric .addImm(0) 75981ad6265SDimitry Andric .addImm(Info.encodeVTYPE()); 76081ad6265SDimitry Andric return; 76181ad6265SDimitry Andric } 76281ad6265SDimitry Andric 76381ad6265SDimitry Andric if (AVLReg.isVirtual()) 76481ad6265SDimitry Andric MRI->constrainRegClass(AVLReg, &RISCV::GPRNoX0RegClass); 76581ad6265SDimitry Andric 76681ad6265SDimitry Andric // Use X0 as the DestReg unless AVLReg is X0. We also need to change the 76781ad6265SDimitry Andric // opcode if the AVLReg is X0 as they have different register classes for 76881ad6265SDimitry Andric // the AVL operand. 76981ad6265SDimitry Andric Register DestReg = RISCV::X0; 77081ad6265SDimitry Andric unsigned Opcode = RISCV::PseudoVSETVLI; 77181ad6265SDimitry Andric if (AVLReg == RISCV::X0) { 77281ad6265SDimitry Andric DestReg = MRI->createVirtualRegister(&RISCV::GPRRegClass); 77381ad6265SDimitry Andric Opcode = RISCV::PseudoVSETVLIX0; 77481ad6265SDimitry Andric } 77581ad6265SDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(Opcode)) 77681ad6265SDimitry Andric .addReg(DestReg, RegState::Define | RegState::Dead) 77781ad6265SDimitry Andric .addReg(AVLReg) 77881ad6265SDimitry Andric .addImm(Info.encodeVTYPE()); 77981ad6265SDimitry Andric } 78081ad6265SDimitry Andric 78181ad6265SDimitry Andric // Return a VSETVLIInfo representing the changes made by this VSETVLI or 78281ad6265SDimitry Andric // VSETIVLI instruction. 78381ad6265SDimitry Andric static VSETVLIInfo getInfoForVSETVLI(const MachineInstr &MI) { 78481ad6265SDimitry Andric VSETVLIInfo NewInfo; 78581ad6265SDimitry Andric if (MI.getOpcode() == RISCV::PseudoVSETIVLI) { 78681ad6265SDimitry Andric NewInfo.setAVLImm(MI.getOperand(1).getImm()); 78781ad6265SDimitry Andric } else { 78881ad6265SDimitry Andric assert(MI.getOpcode() == RISCV::PseudoVSETVLI || 78981ad6265SDimitry Andric MI.getOpcode() == RISCV::PseudoVSETVLIX0); 79081ad6265SDimitry Andric Register AVLReg = MI.getOperand(1).getReg(); 79181ad6265SDimitry Andric assert((AVLReg != RISCV::X0 || MI.getOperand(0).getReg() != RISCV::X0) && 79281ad6265SDimitry Andric "Can't handle X0, X0 vsetvli yet"); 79381ad6265SDimitry Andric NewInfo.setAVLReg(AVLReg); 79481ad6265SDimitry Andric } 79581ad6265SDimitry Andric NewInfo.setVTYPE(MI.getOperand(2).getImm()); 79681ad6265SDimitry Andric 79781ad6265SDimitry Andric return NewInfo; 79881ad6265SDimitry Andric } 79981ad6265SDimitry Andric 80081ad6265SDimitry Andric /// Return true if a VSETVLI is required to transition from CurInfo to Require 80181ad6265SDimitry Andric /// before MI. 80281ad6265SDimitry Andric bool RISCVInsertVSETVLI::needVSETVLI(const MachineInstr &MI, 80381ad6265SDimitry Andric const VSETVLIInfo &Require, 80481ad6265SDimitry Andric const VSETVLIInfo &CurInfo) const { 80581ad6265SDimitry Andric assert(Require == computeInfoForInstr(MI, MI.getDesc().TSFlags, MRI)); 80681ad6265SDimitry Andric 80781ad6265SDimitry Andric if (!CurInfo.isValid() || CurInfo.isUnknown() || CurInfo.hasSEWLMULRatioOnly()) 80881ad6265SDimitry Andric return true; 80981ad6265SDimitry Andric 810*bdd1243dSDimitry Andric DemandedFields Used = getDemanded(MI); 811*bdd1243dSDimitry Andric 812*bdd1243dSDimitry Andric if (isScalarMoveInstr(MI)) { 813*bdd1243dSDimitry Andric // For vmv.s.x and vfmv.s.f, if writing to an implicit_def operand, we don't 814*bdd1243dSDimitry Andric // need to preserve any other bits and are thus compatible with any larger, 815*bdd1243dSDimitry Andric // etype and can disregard policy bits. Warning: It's tempting to try doing 816*bdd1243dSDimitry Andric // this for any tail agnostic operation, but we can't as TA requires 817*bdd1243dSDimitry Andric // tail lanes to either be the original value or -1. We are writing 818*bdd1243dSDimitry Andric // unknown bits to the lanes here. 81981ad6265SDimitry Andric auto *VRegDef = MRI->getVRegDef(MI.getOperand(1).getReg()); 82081ad6265SDimitry Andric if (VRegDef && VRegDef->isImplicitDef() && 821*bdd1243dSDimitry Andric CurInfo.getSEW() >= Require.getSEW()) { 822*bdd1243dSDimitry Andric Used.SEW = false; 823*bdd1243dSDimitry Andric Used.TailPolicy = false; 82481ad6265SDimitry Andric } 825*bdd1243dSDimitry Andric } 826*bdd1243dSDimitry Andric 827*bdd1243dSDimitry Andric if (CurInfo.isCompatible(Used, Require)) 828*bdd1243dSDimitry Andric return false; 82981ad6265SDimitry Andric 83081ad6265SDimitry Andric // We didn't find a compatible value. If our AVL is a virtual register, 83181ad6265SDimitry Andric // it might be defined by a VSET(I)VLI. If it has the same VLMAX we need 83281ad6265SDimitry Andric // and the last VL/VTYPE we observed is the same, we don't need a 83381ad6265SDimitry Andric // VSETVLI here. 83481ad6265SDimitry Andric if (Require.hasAVLReg() && Require.getAVLReg().isVirtual() && 835*bdd1243dSDimitry Andric CurInfo.hasCompatibleVTYPE(Used, Require)) { 83681ad6265SDimitry Andric if (MachineInstr *DefMI = MRI->getVRegDef(Require.getAVLReg())) { 83781ad6265SDimitry Andric if (isVectorConfigInstr(*DefMI)) { 83881ad6265SDimitry Andric VSETVLIInfo DefInfo = getInfoForVSETVLI(*DefMI); 83981ad6265SDimitry Andric if (DefInfo.hasSameAVL(CurInfo) && DefInfo.hasSameVLMAX(CurInfo)) 84081ad6265SDimitry Andric return false; 84181ad6265SDimitry Andric } 84281ad6265SDimitry Andric } 84381ad6265SDimitry Andric } 84481ad6265SDimitry Andric 84581ad6265SDimitry Andric return true; 84681ad6265SDimitry Andric } 84781ad6265SDimitry Andric 84881ad6265SDimitry Andric // Given an incoming state reaching MI, modifies that state so that it is minimally 84981ad6265SDimitry Andric // compatible with MI. The resulting state is guaranteed to be semantically legal 85081ad6265SDimitry Andric // for MI, but may not be the state requested by MI. 85181ad6265SDimitry Andric void RISCVInsertVSETVLI::transferBefore(VSETVLIInfo &Info, const MachineInstr &MI) { 85281ad6265SDimitry Andric uint64_t TSFlags = MI.getDesc().TSFlags; 85381ad6265SDimitry Andric if (!RISCVII::hasSEWOp(TSFlags)) 85481ad6265SDimitry Andric return; 85581ad6265SDimitry Andric 85681ad6265SDimitry Andric const VSETVLIInfo NewInfo = computeInfoForInstr(MI, TSFlags, MRI); 85781ad6265SDimitry Andric if (Info.isValid() && !needVSETVLI(MI, NewInfo, Info)) 85881ad6265SDimitry Andric return; 85981ad6265SDimitry Andric 86081ad6265SDimitry Andric const VSETVLIInfo PrevInfo = Info; 86181ad6265SDimitry Andric Info = NewInfo; 86281ad6265SDimitry Andric 86381ad6265SDimitry Andric if (!RISCVII::hasVLOp(TSFlags)) 86481ad6265SDimitry Andric return; 86581ad6265SDimitry Andric 86681ad6265SDimitry Andric // For vmv.s.x and vfmv.s.f, there are only two behaviors, VL = 0 and 86781ad6265SDimitry Andric // VL > 0. We can discard the user requested AVL and just use the last 86881ad6265SDimitry Andric // one if we can prove it equally zero. This removes a vsetvli entirely 86981ad6265SDimitry Andric // if the types match or allows use of cheaper avl preserving variant 87081ad6265SDimitry Andric // if VLMAX doesn't change. If VLMAX might change, we couldn't use 87181ad6265SDimitry Andric // the 'vsetvli x0, x0, vtype" variant, so we avoid the transform to 87281ad6265SDimitry Andric // prevent extending live range of an avl register operand. 87381ad6265SDimitry Andric // TODO: We can probably relax this for immediates. 87481ad6265SDimitry Andric if (isScalarMoveInstr(MI) && PrevInfo.isValid() && 875*bdd1243dSDimitry Andric PrevInfo.hasEquallyZeroAVL(Info) && 87681ad6265SDimitry Andric Info.hasSameVLMAX(PrevInfo)) { 87781ad6265SDimitry Andric if (PrevInfo.hasAVLImm()) 87881ad6265SDimitry Andric Info.setAVLImm(PrevInfo.getAVLImm()); 87981ad6265SDimitry Andric else 88081ad6265SDimitry Andric Info.setAVLReg(PrevInfo.getAVLReg()); 88181ad6265SDimitry Andric return; 88281ad6265SDimitry Andric } 88381ad6265SDimitry Andric 88461cfbce3SDimitry Andric // If AVL is defined by a vsetvli with the same VLMAX, we can 88581ad6265SDimitry Andric // replace the AVL operand with the AVL of the defining vsetvli. 88681ad6265SDimitry Andric // We avoid general register AVLs to avoid extending live ranges 88781ad6265SDimitry Andric // without being sure we can kill the original source reg entirely. 88881ad6265SDimitry Andric if (!Info.hasAVLReg() || !Info.getAVLReg().isVirtual()) 88981ad6265SDimitry Andric return; 89081ad6265SDimitry Andric MachineInstr *DefMI = MRI->getVRegDef(Info.getAVLReg()); 89181ad6265SDimitry Andric if (!DefMI || !isVectorConfigInstr(*DefMI)) 89281ad6265SDimitry Andric return; 89381ad6265SDimitry Andric 89481ad6265SDimitry Andric VSETVLIInfo DefInfo = getInfoForVSETVLI(*DefMI); 89581ad6265SDimitry Andric if (DefInfo.hasSameVLMAX(Info) && 89681ad6265SDimitry Andric (DefInfo.hasAVLImm() || DefInfo.getAVLReg() == RISCV::X0)) { 89781ad6265SDimitry Andric if (DefInfo.hasAVLImm()) 89881ad6265SDimitry Andric Info.setAVLImm(DefInfo.getAVLImm()); 89981ad6265SDimitry Andric else 90081ad6265SDimitry Andric Info.setAVLReg(DefInfo.getAVLReg()); 90181ad6265SDimitry Andric return; 90281ad6265SDimitry Andric } 90381ad6265SDimitry Andric } 90481ad6265SDimitry Andric 90581ad6265SDimitry Andric // Given a state with which we evaluated MI (see transferBefore above for why 90681ad6265SDimitry Andric // this might be different that the state MI requested), modify the state to 90781ad6265SDimitry Andric // reflect the changes MI might make. 90881ad6265SDimitry Andric void RISCVInsertVSETVLI::transferAfter(VSETVLIInfo &Info, const MachineInstr &MI) { 90981ad6265SDimitry Andric if (isVectorConfigInstr(MI)) { 91081ad6265SDimitry Andric Info = getInfoForVSETVLI(MI); 91181ad6265SDimitry Andric return; 91281ad6265SDimitry Andric } 91381ad6265SDimitry Andric 91481ad6265SDimitry Andric if (RISCV::isFaultFirstLoad(MI)) { 91581ad6265SDimitry Andric // Update AVL to vl-output of the fault first load. 91681ad6265SDimitry Andric Info.setAVLReg(MI.getOperand(1).getReg()); 91781ad6265SDimitry Andric return; 91881ad6265SDimitry Andric } 91981ad6265SDimitry Andric 92081ad6265SDimitry Andric // If this is something that updates VL/VTYPE that we don't know about, set 92181ad6265SDimitry Andric // the state to unknown. 92281ad6265SDimitry Andric if (MI.isCall() || MI.isInlineAsm() || MI.modifiesRegister(RISCV::VL) || 92381ad6265SDimitry Andric MI.modifiesRegister(RISCV::VTYPE)) 92481ad6265SDimitry Andric Info = VSETVLIInfo::getUnknown(); 925349cc55cSDimitry Andric } 926349cc55cSDimitry Andric 927fe6060f1SDimitry Andric bool RISCVInsertVSETVLI::computeVLVTYPEChanges(const MachineBasicBlock &MBB) { 928fe6060f1SDimitry Andric bool HadVectorOp = false; 929fe6060f1SDimitry Andric 930fe6060f1SDimitry Andric BlockData &BBInfo = BlockInfo[MBB.getNumber()]; 93181ad6265SDimitry Andric BBInfo.Change = BBInfo.Pred; 932fe6060f1SDimitry Andric for (const MachineInstr &MI : MBB) { 93381ad6265SDimitry Andric transferBefore(BBInfo.Change, MI); 934fe6060f1SDimitry Andric 93581ad6265SDimitry Andric if (isVectorConfigInstr(MI) || RISCVII::hasSEWOp(MI.getDesc().TSFlags)) 936fe6060f1SDimitry Andric HadVectorOp = true; 937fe6060f1SDimitry Andric 93881ad6265SDimitry Andric transferAfter(BBInfo.Change, MI); 939fe6060f1SDimitry Andric } 940fe6060f1SDimitry Andric 941fe6060f1SDimitry Andric return HadVectorOp; 942fe6060f1SDimitry Andric } 943fe6060f1SDimitry Andric 944fe6060f1SDimitry Andric void RISCVInsertVSETVLI::computeIncomingVLVTYPE(const MachineBasicBlock &MBB) { 94581ad6265SDimitry Andric 946fe6060f1SDimitry Andric BlockData &BBInfo = BlockInfo[MBB.getNumber()]; 947fe6060f1SDimitry Andric 948fe6060f1SDimitry Andric BBInfo.InQueue = false; 949fe6060f1SDimitry Andric 950*bdd1243dSDimitry Andric // Start with the previous entry so that we keep the most conservative state 951*bdd1243dSDimitry Andric // we have ever found. 952*bdd1243dSDimitry Andric VSETVLIInfo InInfo = BBInfo.Pred; 953fe6060f1SDimitry Andric if (MBB.pred_empty()) { 954fe6060f1SDimitry Andric // There are no predecessors, so use the default starting status. 955fe6060f1SDimitry Andric InInfo.setUnknown(); 956fe6060f1SDimitry Andric } else { 957fe6060f1SDimitry Andric for (MachineBasicBlock *P : MBB.predecessors()) 958fe6060f1SDimitry Andric InInfo = InInfo.intersect(BlockInfo[P->getNumber()].Exit); 959fe6060f1SDimitry Andric } 960fe6060f1SDimitry Andric 961fe6060f1SDimitry Andric // If we don't have any valid predecessor value, wait until we do. 962fe6060f1SDimitry Andric if (!InInfo.isValid()) 963fe6060f1SDimitry Andric return; 964fe6060f1SDimitry Andric 96581ad6265SDimitry Andric // If no change, no need to rerun block 96681ad6265SDimitry Andric if (InInfo == BBInfo.Pred) 96781ad6265SDimitry Andric return; 968fe6060f1SDimitry Andric 96981ad6265SDimitry Andric BBInfo.Pred = InInfo; 97081ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "Entry state of " << printMBBReference(MBB) 97181ad6265SDimitry Andric << " changed to " << BBInfo.Pred << "\n"); 97281ad6265SDimitry Andric 97381ad6265SDimitry Andric // Note: It's tempting to cache the state changes here, but due to the 97481ad6265SDimitry Andric // compatibility checks performed a blocks output state can change based on 97581ad6265SDimitry Andric // the input state. To cache, we'd have to add logic for finding 97681ad6265SDimitry Andric // never-compatible state changes. 97781ad6265SDimitry Andric computeVLVTYPEChanges(MBB); 97881ad6265SDimitry Andric VSETVLIInfo TmpStatus = BBInfo.Change; 979fe6060f1SDimitry Andric 980fe6060f1SDimitry Andric // If the new exit value matches the old exit value, we don't need to revisit 981fe6060f1SDimitry Andric // any blocks. 982fe6060f1SDimitry Andric if (BBInfo.Exit == TmpStatus) 983fe6060f1SDimitry Andric return; 984fe6060f1SDimitry Andric 985fe6060f1SDimitry Andric BBInfo.Exit = TmpStatus; 98681ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "Exit state of " << printMBBReference(MBB) 98781ad6265SDimitry Andric << " changed to " << BBInfo.Exit << "\n"); 988fe6060f1SDimitry Andric 989fe6060f1SDimitry Andric // Add the successors to the work list so we can propagate the changed exit 990fe6060f1SDimitry Andric // status. 991fe6060f1SDimitry Andric for (MachineBasicBlock *S : MBB.successors()) 992*bdd1243dSDimitry Andric if (!BlockInfo[S->getNumber()].InQueue) { 993*bdd1243dSDimitry Andric BlockInfo[S->getNumber()].InQueue = true; 994fe6060f1SDimitry Andric WorkList.push(S); 995fe6060f1SDimitry Andric } 996*bdd1243dSDimitry Andric } 997fe6060f1SDimitry Andric 998fe6060f1SDimitry Andric // If we weren't able to prove a vsetvli was directly unneeded, it might still 99981ad6265SDimitry Andric // be unneeded if the AVL is a phi node where all incoming values are VL 1000fe6060f1SDimitry Andric // outputs from the last VSETVLI in their respective basic blocks. 1001fe6060f1SDimitry Andric bool RISCVInsertVSETVLI::needVSETVLIPHI(const VSETVLIInfo &Require, 100281ad6265SDimitry Andric const MachineBasicBlock &MBB) const { 1003fe6060f1SDimitry Andric if (DisableInsertVSETVLPHIOpt) 1004fe6060f1SDimitry Andric return true; 1005fe6060f1SDimitry Andric 1006fe6060f1SDimitry Andric if (!Require.hasAVLReg()) 1007fe6060f1SDimitry Andric return true; 1008fe6060f1SDimitry Andric 1009fe6060f1SDimitry Andric Register AVLReg = Require.getAVLReg(); 1010fe6060f1SDimitry Andric if (!AVLReg.isVirtual()) 1011fe6060f1SDimitry Andric return true; 1012fe6060f1SDimitry Andric 1013fe6060f1SDimitry Andric // We need the AVL to be produce by a PHI node in this basic block. 1014fe6060f1SDimitry Andric MachineInstr *PHI = MRI->getVRegDef(AVLReg); 1015fe6060f1SDimitry Andric if (!PHI || PHI->getOpcode() != RISCV::PHI || PHI->getParent() != &MBB) 1016fe6060f1SDimitry Andric return true; 1017fe6060f1SDimitry Andric 1018fe6060f1SDimitry Andric for (unsigned PHIOp = 1, NumOps = PHI->getNumOperands(); PHIOp != NumOps; 1019fe6060f1SDimitry Andric PHIOp += 2) { 1020fe6060f1SDimitry Andric Register InReg = PHI->getOperand(PHIOp).getReg(); 1021fe6060f1SDimitry Andric MachineBasicBlock *PBB = PHI->getOperand(PHIOp + 1).getMBB(); 1022fe6060f1SDimitry Andric const BlockData &PBBInfo = BlockInfo[PBB->getNumber()]; 1023fe6060f1SDimitry Andric // If the exit from the predecessor has the VTYPE we are looking for 1024fe6060f1SDimitry Andric // we might be able to avoid a VSETVLI. 102581ad6265SDimitry Andric if (PBBInfo.Exit.isUnknown() || !PBBInfo.Exit.hasSameVTYPE(Require)) 1026fe6060f1SDimitry Andric return true; 1027fe6060f1SDimitry Andric 1028fe6060f1SDimitry Andric // We need the PHI input to the be the output of a VSET(I)VLI. 1029fe6060f1SDimitry Andric MachineInstr *DefMI = MRI->getVRegDef(InReg); 103081ad6265SDimitry Andric if (!DefMI || !isVectorConfigInstr(*DefMI)) 1031fe6060f1SDimitry Andric return true; 1032fe6060f1SDimitry Andric 1033fe6060f1SDimitry Andric // We found a VSET(I)VLI make sure it matches the output of the 1034fe6060f1SDimitry Andric // predecessor block. 1035fe6060f1SDimitry Andric VSETVLIInfo DefInfo = getInfoForVSETVLI(*DefMI); 1036fe6060f1SDimitry Andric if (!DefInfo.hasSameAVL(PBBInfo.Exit) || 1037fe6060f1SDimitry Andric !DefInfo.hasSameVTYPE(PBBInfo.Exit)) 1038fe6060f1SDimitry Andric return true; 1039fe6060f1SDimitry Andric } 1040fe6060f1SDimitry Andric 1041fe6060f1SDimitry Andric // If all the incoming values to the PHI checked out, we don't need 1042fe6060f1SDimitry Andric // to insert a VSETVLI. 1043fe6060f1SDimitry Andric return false; 1044fe6060f1SDimitry Andric } 1045fe6060f1SDimitry Andric 1046fe6060f1SDimitry Andric void RISCVInsertVSETVLI::emitVSETVLIs(MachineBasicBlock &MBB) { 104781ad6265SDimitry Andric VSETVLIInfo CurInfo = BlockInfo[MBB.getNumber()].Pred; 104881ad6265SDimitry Andric // Track whether the prefix of the block we've scanned is transparent 104981ad6265SDimitry Andric // (meaning has not yet changed the abstract state). 105081ad6265SDimitry Andric bool PrefixTransparent = true; 1051fe6060f1SDimitry Andric for (MachineInstr &MI : MBB) { 105281ad6265SDimitry Andric const VSETVLIInfo PrevInfo = CurInfo; 105381ad6265SDimitry Andric transferBefore(CurInfo, MI); 105481ad6265SDimitry Andric 1055fe6060f1SDimitry Andric // If this is an explicit VSETVLI or VSETIVLI, update our state. 105681ad6265SDimitry Andric if (isVectorConfigInstr(MI)) { 1057fe6060f1SDimitry Andric // Conservatively, mark the VL and VTYPE as live. 1058fe6060f1SDimitry Andric assert(MI.getOperand(3).getReg() == RISCV::VL && 1059fe6060f1SDimitry Andric MI.getOperand(4).getReg() == RISCV::VTYPE && 1060fe6060f1SDimitry Andric "Unexpected operands where VL and VTYPE should be"); 1061fe6060f1SDimitry Andric MI.getOperand(3).setIsDead(false); 1062fe6060f1SDimitry Andric MI.getOperand(4).setIsDead(false); 106381ad6265SDimitry Andric PrefixTransparent = false; 1064fe6060f1SDimitry Andric } 1065fe6060f1SDimitry Andric 1066fe6060f1SDimitry Andric uint64_t TSFlags = MI.getDesc().TSFlags; 1067fe6060f1SDimitry Andric if (RISCVII::hasSEWOp(TSFlags)) { 106881ad6265SDimitry Andric if (PrevInfo != CurInfo) { 106981ad6265SDimitry Andric // If this is the first implicit state change, and the state change 107081ad6265SDimitry Andric // requested can be proven to produce the same register contents, we 107181ad6265SDimitry Andric // can skip emitting the actual state change and continue as if we 107281ad6265SDimitry Andric // had since we know the GPR result of the implicit state change 107381ad6265SDimitry Andric // wouldn't be used and VL/VTYPE registers are correct. Note that 107481ad6265SDimitry Andric // we *do* need to model the state as if it changed as while the 107581ad6265SDimitry Andric // register contents are unchanged, the abstract model can change. 107681ad6265SDimitry Andric if (!PrefixTransparent || needVSETVLIPHI(CurInfo, MBB)) 107781ad6265SDimitry Andric insertVSETVLI(MBB, MI, CurInfo, PrevInfo); 107881ad6265SDimitry Andric PrefixTransparent = false; 107981ad6265SDimitry Andric } 108081ad6265SDimitry Andric 1081fe6060f1SDimitry Andric if (RISCVII::hasVLOp(TSFlags)) { 108281ad6265SDimitry Andric MachineOperand &VLOp = MI.getOperand(getVLOpNum(MI)); 1083fe6060f1SDimitry Andric if (VLOp.isReg()) { 1084fe6060f1SDimitry Andric // Erase the AVL operand from the instruction. 1085fe6060f1SDimitry Andric VLOp.setReg(RISCV::NoRegister); 1086fe6060f1SDimitry Andric VLOp.setIsKill(false); 1087fe6060f1SDimitry Andric } 1088fe6060f1SDimitry Andric MI.addOperand(MachineOperand::CreateReg(RISCV::VL, /*isDef*/ false, 1089fe6060f1SDimitry Andric /*isImp*/ true)); 1090fe6060f1SDimitry Andric } 1091fe6060f1SDimitry Andric MI.addOperand(MachineOperand::CreateReg(RISCV::VTYPE, /*isDef*/ false, 1092fe6060f1SDimitry Andric /*isImp*/ true)); 1093fe6060f1SDimitry Andric } 1094fe6060f1SDimitry Andric 1095fe6060f1SDimitry Andric if (MI.isCall() || MI.isInlineAsm() || MI.modifiesRegister(RISCV::VL) || 109681ad6265SDimitry Andric MI.modifiesRegister(RISCV::VTYPE)) 109781ad6265SDimitry Andric PrefixTransparent = false; 109881ad6265SDimitry Andric 109981ad6265SDimitry Andric transferAfter(CurInfo, MI); 1100fe6060f1SDimitry Andric } 1101d56accc7SDimitry Andric 1102d56accc7SDimitry Andric // If we reach the end of the block and our current info doesn't match the 1103d56accc7SDimitry Andric // expected info, insert a vsetvli to correct. 110481ad6265SDimitry Andric if (!UseStrictAsserts) { 1105d56accc7SDimitry Andric const VSETVLIInfo &ExitInfo = BlockInfo[MBB.getNumber()].Exit; 1106d56accc7SDimitry Andric if (CurInfo.isValid() && ExitInfo.isValid() && !ExitInfo.isUnknown() && 1107d56accc7SDimitry Andric CurInfo != ExitInfo) { 110881ad6265SDimitry Andric // Note there's an implicit assumption here that terminators never use 110981ad6265SDimitry Andric // or modify VL or VTYPE. Also, fallthrough will return end(). 111081ad6265SDimitry Andric auto InsertPt = MBB.getFirstInstrTerminator(); 111181ad6265SDimitry Andric insertVSETVLI(MBB, InsertPt, MBB.findDebugLoc(InsertPt), ExitInfo, 111281ad6265SDimitry Andric CurInfo); 1113d56accc7SDimitry Andric CurInfo = ExitInfo; 1114d56accc7SDimitry Andric } 1115d56accc7SDimitry Andric } 111681ad6265SDimitry Andric 111781ad6265SDimitry Andric if (UseStrictAsserts && CurInfo.isValid()) { 111881ad6265SDimitry Andric const auto &Info = BlockInfo[MBB.getNumber()]; 111981ad6265SDimitry Andric if (CurInfo != Info.Exit) { 112081ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "in block " << printMBBReference(MBB) << "\n"); 112181ad6265SDimitry Andric LLVM_DEBUG(dbgs() << " begin state: " << Info.Pred << "\n"); 112281ad6265SDimitry Andric LLVM_DEBUG(dbgs() << " expected end state: " << Info.Exit << "\n"); 112381ad6265SDimitry Andric LLVM_DEBUG(dbgs() << " actual end state: " << CurInfo << "\n"); 112481ad6265SDimitry Andric } 112581ad6265SDimitry Andric assert(CurInfo == Info.Exit && 112681ad6265SDimitry Andric "InsertVSETVLI dataflow invariant violated"); 112781ad6265SDimitry Andric } 112881ad6265SDimitry Andric } 112981ad6265SDimitry Andric 113081ad6265SDimitry Andric /// Return true if the VL value configured must be equal to the requested one. 113181ad6265SDimitry Andric static bool hasFixedResult(const VSETVLIInfo &Info, const RISCVSubtarget &ST) { 113281ad6265SDimitry Andric if (!Info.hasAVLImm()) 113381ad6265SDimitry Andric // VLMAX is always the same value. 113481ad6265SDimitry Andric // TODO: Could extend to other registers by looking at the associated vreg 113581ad6265SDimitry Andric // def placement. 113681ad6265SDimitry Andric return RISCV::X0 == Info.getAVLReg(); 113781ad6265SDimitry Andric 113881ad6265SDimitry Andric unsigned AVL = Info.getAVLImm(); 113981ad6265SDimitry Andric unsigned SEW = Info.getSEW(); 114081ad6265SDimitry Andric unsigned AVLInBits = AVL * SEW; 114181ad6265SDimitry Andric 114281ad6265SDimitry Andric unsigned LMul; 114381ad6265SDimitry Andric bool Fractional; 114481ad6265SDimitry Andric std::tie(LMul, Fractional) = RISCVVType::decodeVLMUL(Info.getVLMUL()); 114581ad6265SDimitry Andric 114681ad6265SDimitry Andric if (Fractional) 114781ad6265SDimitry Andric return ST.getRealMinVLen() / LMul >= AVLInBits; 114881ad6265SDimitry Andric return ST.getRealMinVLen() * LMul >= AVLInBits; 114981ad6265SDimitry Andric } 115081ad6265SDimitry Andric 115181ad6265SDimitry Andric /// Perform simple partial redundancy elimination of the VSETVLI instructions 115281ad6265SDimitry Andric /// we're about to insert by looking for cases where we can PRE from the 115381ad6265SDimitry Andric /// beginning of one block to the end of one of its predecessors. Specifically, 115481ad6265SDimitry Andric /// this is geared to catch the common case of a fixed length vsetvl in a single 115581ad6265SDimitry Andric /// block loop when it could execute once in the preheader instead. 115681ad6265SDimitry Andric void RISCVInsertVSETVLI::doPRE(MachineBasicBlock &MBB) { 115781ad6265SDimitry Andric const MachineFunction &MF = *MBB.getParent(); 115881ad6265SDimitry Andric const RISCVSubtarget &ST = MF.getSubtarget<RISCVSubtarget>(); 115981ad6265SDimitry Andric 116081ad6265SDimitry Andric if (!BlockInfo[MBB.getNumber()].Pred.isUnknown()) 116181ad6265SDimitry Andric return; 116281ad6265SDimitry Andric 116381ad6265SDimitry Andric MachineBasicBlock *UnavailablePred = nullptr; 116481ad6265SDimitry Andric VSETVLIInfo AvailableInfo; 116581ad6265SDimitry Andric for (MachineBasicBlock *P : MBB.predecessors()) { 116681ad6265SDimitry Andric const VSETVLIInfo &PredInfo = BlockInfo[P->getNumber()].Exit; 116781ad6265SDimitry Andric if (PredInfo.isUnknown()) { 116881ad6265SDimitry Andric if (UnavailablePred) 116981ad6265SDimitry Andric return; 117081ad6265SDimitry Andric UnavailablePred = P; 117181ad6265SDimitry Andric } else if (!AvailableInfo.isValid()) { 117281ad6265SDimitry Andric AvailableInfo = PredInfo; 117381ad6265SDimitry Andric } else if (AvailableInfo != PredInfo) { 117481ad6265SDimitry Andric return; 117581ad6265SDimitry Andric } 117681ad6265SDimitry Andric } 117781ad6265SDimitry Andric 117881ad6265SDimitry Andric // Unreachable, single pred, or full redundancy. Note that FRE is handled by 117981ad6265SDimitry Andric // phase 3. 118081ad6265SDimitry Andric if (!UnavailablePred || !AvailableInfo.isValid()) 118181ad6265SDimitry Andric return; 118281ad6265SDimitry Andric 118381ad6265SDimitry Andric // Critical edge - TODO: consider splitting? 118481ad6265SDimitry Andric if (UnavailablePred->succ_size() != 1) 118581ad6265SDimitry Andric return; 118681ad6265SDimitry Andric 118781ad6265SDimitry Andric // If VL can be less than AVL, then we can't reduce the frequency of exec. 118881ad6265SDimitry Andric if (!hasFixedResult(AvailableInfo, ST)) 118981ad6265SDimitry Andric return; 119081ad6265SDimitry Andric 119181ad6265SDimitry Andric // Does it actually let us remove an implicit transition in MBB? 119281ad6265SDimitry Andric bool Found = false; 119381ad6265SDimitry Andric for (auto &MI : MBB) { 119481ad6265SDimitry Andric if (isVectorConfigInstr(MI)) 119581ad6265SDimitry Andric return; 119681ad6265SDimitry Andric 119781ad6265SDimitry Andric const uint64_t TSFlags = MI.getDesc().TSFlags; 119881ad6265SDimitry Andric if (RISCVII::hasSEWOp(TSFlags)) { 119981ad6265SDimitry Andric if (AvailableInfo != computeInfoForInstr(MI, TSFlags, MRI)) 120081ad6265SDimitry Andric return; 120181ad6265SDimitry Andric Found = true; 120281ad6265SDimitry Andric break; 120381ad6265SDimitry Andric } 120481ad6265SDimitry Andric } 120581ad6265SDimitry Andric if (!Found) 120681ad6265SDimitry Andric return; 120781ad6265SDimitry Andric 120881ad6265SDimitry Andric // Finally, update both data flow state and insert the actual vsetvli. 120981ad6265SDimitry Andric // Doing both keeps the code in sync with the dataflow results, which 121081ad6265SDimitry Andric // is critical for correctness of phase 3. 121181ad6265SDimitry Andric auto OldInfo = BlockInfo[UnavailablePred->getNumber()].Exit; 121281ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "PRE VSETVLI from " << MBB.getName() << " to " 121381ad6265SDimitry Andric << UnavailablePred->getName() << " with state " 121481ad6265SDimitry Andric << AvailableInfo << "\n"); 121581ad6265SDimitry Andric BlockInfo[UnavailablePred->getNumber()].Exit = AvailableInfo; 121681ad6265SDimitry Andric BlockInfo[MBB.getNumber()].Pred = AvailableInfo; 121781ad6265SDimitry Andric 121881ad6265SDimitry Andric // Note there's an implicit assumption here that terminators never use 121981ad6265SDimitry Andric // or modify VL or VTYPE. Also, fallthrough will return end(). 122081ad6265SDimitry Andric auto InsertPt = UnavailablePred->getFirstInstrTerminator(); 122181ad6265SDimitry Andric insertVSETVLI(*UnavailablePred, InsertPt, 122281ad6265SDimitry Andric UnavailablePred->findDebugLoc(InsertPt), 122381ad6265SDimitry Andric AvailableInfo, OldInfo); 122481ad6265SDimitry Andric } 122581ad6265SDimitry Andric 122681ad6265SDimitry Andric static void doUnion(DemandedFields &A, DemandedFields B) { 1227*bdd1243dSDimitry Andric A.VLAny |= B.VLAny; 1228*bdd1243dSDimitry Andric A.VLZeroness |= B.VLZeroness; 122981ad6265SDimitry Andric A.SEW |= B.SEW; 123081ad6265SDimitry Andric A.LMUL |= B.LMUL; 123181ad6265SDimitry Andric A.SEWLMULRatio |= B.SEWLMULRatio; 123281ad6265SDimitry Andric A.TailPolicy |= B.TailPolicy; 123381ad6265SDimitry Andric A.MaskPolicy |= B.MaskPolicy; 123481ad6265SDimitry Andric } 123581ad6265SDimitry Andric 1236*bdd1243dSDimitry Andric static bool isNonZeroAVL(const MachineOperand &MO) { 1237*bdd1243dSDimitry Andric if (MO.isReg()) 1238*bdd1243dSDimitry Andric return RISCV::X0 == MO.getReg(); 1239*bdd1243dSDimitry Andric assert(MO.isImm()); 1240*bdd1243dSDimitry Andric return 0 != MO.getImm(); 1241*bdd1243dSDimitry Andric } 1242*bdd1243dSDimitry Andric 1243*bdd1243dSDimitry Andric // Return true if we can mutate PrevMI to match MI without changing any the 1244*bdd1243dSDimitry Andric // fields which would be observed. 124581ad6265SDimitry Andric static bool canMutatePriorConfig(const MachineInstr &PrevMI, 124681ad6265SDimitry Andric const MachineInstr &MI, 124781ad6265SDimitry Andric const DemandedFields &Used) { 1248*bdd1243dSDimitry Andric // If the VL values aren't equal, return false if either a) the former is 1249*bdd1243dSDimitry Andric // demanded, or b) we can't rewrite the former to be the later for 1250*bdd1243dSDimitry Andric // implementation reasons. 1251*bdd1243dSDimitry Andric if (!isVLPreservingConfig(MI)) { 1252*bdd1243dSDimitry Andric if (Used.VLAny) 125381ad6265SDimitry Andric return false; 125481ad6265SDimitry Andric 1255*bdd1243dSDimitry Andric // TODO: Requires more care in the mutation... 1256*bdd1243dSDimitry Andric if (isVLPreservingConfig(PrevMI)) 1257*bdd1243dSDimitry Andric return false; 1258*bdd1243dSDimitry Andric 1259*bdd1243dSDimitry Andric // We don't bother to handle the equally zero case here as it's largely 1260*bdd1243dSDimitry Andric // uninteresting. 1261*bdd1243dSDimitry Andric if (Used.VLZeroness && 1262*bdd1243dSDimitry Andric (!isNonZeroAVL(MI.getOperand(1)) || 1263*bdd1243dSDimitry Andric !isNonZeroAVL(PrevMI.getOperand(1)))) 1264*bdd1243dSDimitry Andric return false; 1265*bdd1243dSDimitry Andric 1266*bdd1243dSDimitry Andric // TODO: Track whether the register is defined between 1267*bdd1243dSDimitry Andric // PrevMI and MI. 1268*bdd1243dSDimitry Andric if (MI.getOperand(1).isReg() && 1269*bdd1243dSDimitry Andric RISCV::X0 != MI.getOperand(1).getReg()) 1270*bdd1243dSDimitry Andric return false; 1271*bdd1243dSDimitry Andric 1272*bdd1243dSDimitry Andric // TODO: We need to change the result register to allow this rewrite 1273*bdd1243dSDimitry Andric // without the result forming a vl preserving vsetvli which is not 1274*bdd1243dSDimitry Andric // a correct state merge. 1275*bdd1243dSDimitry Andric if (PrevMI.getOperand(0).getReg() == RISCV::X0 && 1276*bdd1243dSDimitry Andric MI.getOperand(1).isReg()) 1277*bdd1243dSDimitry Andric return false; 1278*bdd1243dSDimitry Andric } 1279*bdd1243dSDimitry Andric 128081ad6265SDimitry Andric if (!PrevMI.getOperand(2).isImm() || !MI.getOperand(2).isImm()) 128181ad6265SDimitry Andric return false; 128281ad6265SDimitry Andric 128381ad6265SDimitry Andric auto PriorVType = PrevMI.getOperand(2).getImm(); 128481ad6265SDimitry Andric auto VType = MI.getOperand(2).getImm(); 128581ad6265SDimitry Andric return areCompatibleVTYPEs(PriorVType, VType, Used); 128681ad6265SDimitry Andric } 128781ad6265SDimitry Andric 128881ad6265SDimitry Andric void RISCVInsertVSETVLI::doLocalPostpass(MachineBasicBlock &MBB) { 1289*bdd1243dSDimitry Andric MachineInstr *NextMI = nullptr; 1290*bdd1243dSDimitry Andric // We can have arbitrary code in successors, so VL and VTYPE 1291*bdd1243dSDimitry Andric // must be considered demanded. 129281ad6265SDimitry Andric DemandedFields Used; 1293*bdd1243dSDimitry Andric Used.demandVL(); 1294*bdd1243dSDimitry Andric Used.demandVTYPE(); 129581ad6265SDimitry Andric SmallVector<MachineInstr*> ToDelete; 1296*bdd1243dSDimitry Andric for (MachineInstr &MI : make_range(MBB.rbegin(), MBB.rend())) { 1297*bdd1243dSDimitry Andric 1298*bdd1243dSDimitry Andric if (!isVectorConfigInstr(MI)) { 129981ad6265SDimitry Andric doUnion(Used, getDemanded(MI)); 130081ad6265SDimitry Andric continue; 130181ad6265SDimitry Andric } 1302*bdd1243dSDimitry Andric 130381ad6265SDimitry Andric Register VRegDef = MI.getOperand(0).getReg(); 130481ad6265SDimitry Andric if (VRegDef != RISCV::X0 && 130581ad6265SDimitry Andric !(VRegDef.isVirtual() && MRI->use_nodbg_empty(VRegDef))) 1306*bdd1243dSDimitry Andric Used.demandVL(); 1307*bdd1243dSDimitry Andric 1308*bdd1243dSDimitry Andric if (NextMI) { 1309*bdd1243dSDimitry Andric if (!Used.usedVL() && !Used.usedVTYPE()) { 1310*bdd1243dSDimitry Andric ToDelete.push_back(&MI); 1311*bdd1243dSDimitry Andric // Leave NextMI unchanged 1312*bdd1243dSDimitry Andric continue; 1313*bdd1243dSDimitry Andric } else if (canMutatePriorConfig(MI, *NextMI, Used)) { 1314*bdd1243dSDimitry Andric if (!isVLPreservingConfig(*NextMI)) { 1315*bdd1243dSDimitry Andric if (NextMI->getOperand(1).isImm()) 1316*bdd1243dSDimitry Andric MI.getOperand(1).ChangeToImmediate(NextMI->getOperand(1).getImm()); 1317*bdd1243dSDimitry Andric else 1318*bdd1243dSDimitry Andric MI.getOperand(1).ChangeToRegister(NextMI->getOperand(1).getReg(), false); 1319*bdd1243dSDimitry Andric MI.setDesc(NextMI->getDesc()); 1320*bdd1243dSDimitry Andric } 1321*bdd1243dSDimitry Andric MI.getOperand(2).setImm(NextMI->getOperand(2).getImm()); 1322*bdd1243dSDimitry Andric ToDelete.push_back(NextMI); 1323*bdd1243dSDimitry Andric // fallthrough 1324*bdd1243dSDimitry Andric } 1325*bdd1243dSDimitry Andric } 1326*bdd1243dSDimitry Andric NextMI = &MI; 1327*bdd1243dSDimitry Andric Used = getDemanded(MI); 132881ad6265SDimitry Andric } 132981ad6265SDimitry Andric 133081ad6265SDimitry Andric for (auto *MI : ToDelete) 133181ad6265SDimitry Andric MI->eraseFromParent(); 133281ad6265SDimitry Andric } 133381ad6265SDimitry Andric 133481ad6265SDimitry Andric void RISCVInsertVSETVLI::insertReadVL(MachineBasicBlock &MBB) { 133581ad6265SDimitry Andric for (auto I = MBB.begin(), E = MBB.end(); I != E;) { 133681ad6265SDimitry Andric MachineInstr &MI = *I++; 133781ad6265SDimitry Andric if (RISCV::isFaultFirstLoad(MI)) { 133881ad6265SDimitry Andric Register VLOutput = MI.getOperand(1).getReg(); 133981ad6265SDimitry Andric if (!MRI->use_nodbg_empty(VLOutput)) 134081ad6265SDimitry Andric BuildMI(MBB, I, MI.getDebugLoc(), TII->get(RISCV::PseudoReadVL), 134181ad6265SDimitry Andric VLOutput); 134281ad6265SDimitry Andric // We don't use the vl output of the VLEFF/VLSEGFF anymore. 134381ad6265SDimitry Andric MI.getOperand(1).setReg(RISCV::X0); 134481ad6265SDimitry Andric } 1345fe6060f1SDimitry Andric } 1346fe6060f1SDimitry Andric } 1347fe6060f1SDimitry Andric 1348fe6060f1SDimitry Andric bool RISCVInsertVSETVLI::runOnMachineFunction(MachineFunction &MF) { 1349fe6060f1SDimitry Andric // Skip if the vector extension is not enabled. 1350fe6060f1SDimitry Andric const RISCVSubtarget &ST = MF.getSubtarget<RISCVSubtarget>(); 1351349cc55cSDimitry Andric if (!ST.hasVInstructions()) 1352fe6060f1SDimitry Andric return false; 1353fe6060f1SDimitry Andric 135481ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "Entering InsertVSETVLI for " << MF.getName() << "\n"); 135581ad6265SDimitry Andric 1356fe6060f1SDimitry Andric TII = ST.getInstrInfo(); 1357fe6060f1SDimitry Andric MRI = &MF.getRegInfo(); 1358fe6060f1SDimitry Andric 1359fe6060f1SDimitry Andric assert(BlockInfo.empty() && "Expect empty block infos"); 1360fe6060f1SDimitry Andric BlockInfo.resize(MF.getNumBlockIDs()); 1361fe6060f1SDimitry Andric 1362fe6060f1SDimitry Andric bool HaveVectorOp = false; 1363fe6060f1SDimitry Andric 1364fe6060f1SDimitry Andric // Phase 1 - determine how VL/VTYPE are affected by the each block. 136581ad6265SDimitry Andric for (const MachineBasicBlock &MBB : MF) { 1366fe6060f1SDimitry Andric HaveVectorOp |= computeVLVTYPEChanges(MBB); 136781ad6265SDimitry Andric // Initial exit state is whatever change we found in the block. 136881ad6265SDimitry Andric BlockData &BBInfo = BlockInfo[MBB.getNumber()]; 136981ad6265SDimitry Andric BBInfo.Exit = BBInfo.Change; 137081ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "Initial exit state of " << printMBBReference(MBB) 137181ad6265SDimitry Andric << " is " << BBInfo.Exit << "\n"); 137281ad6265SDimitry Andric 137381ad6265SDimitry Andric } 1374fe6060f1SDimitry Andric 1375fe6060f1SDimitry Andric // If we didn't find any instructions that need VSETVLI, we're done. 137681ad6265SDimitry Andric if (!HaveVectorOp) { 137781ad6265SDimitry Andric BlockInfo.clear(); 137881ad6265SDimitry Andric return false; 137981ad6265SDimitry Andric } 138081ad6265SDimitry Andric 1381fe6060f1SDimitry Andric // Phase 2 - determine the exit VL/VTYPE from each block. We add all 1382fe6060f1SDimitry Andric // blocks to the list here, but will also add any that need to be revisited 1383fe6060f1SDimitry Andric // during Phase 2 processing. 1384fe6060f1SDimitry Andric for (const MachineBasicBlock &MBB : MF) { 1385fe6060f1SDimitry Andric WorkList.push(&MBB); 1386fe6060f1SDimitry Andric BlockInfo[MBB.getNumber()].InQueue = true; 1387fe6060f1SDimitry Andric } 1388fe6060f1SDimitry Andric while (!WorkList.empty()) { 1389fe6060f1SDimitry Andric const MachineBasicBlock &MBB = *WorkList.front(); 1390fe6060f1SDimitry Andric WorkList.pop(); 1391fe6060f1SDimitry Andric computeIncomingVLVTYPE(MBB); 1392fe6060f1SDimitry Andric } 1393fe6060f1SDimitry Andric 139481ad6265SDimitry Andric // Perform partial redundancy elimination of vsetvli transitions. 139581ad6265SDimitry Andric for (MachineBasicBlock &MBB : MF) 139681ad6265SDimitry Andric doPRE(MBB); 139781ad6265SDimitry Andric 1398fe6060f1SDimitry Andric // Phase 3 - add any vsetvli instructions needed in the block. Use the 1399fe6060f1SDimitry Andric // Phase 2 information to avoid adding vsetvlis before the first vector 1400fe6060f1SDimitry Andric // instruction in the block if the VL/VTYPE is satisfied by its 1401fe6060f1SDimitry Andric // predecessors. 1402fe6060f1SDimitry Andric for (MachineBasicBlock &MBB : MF) 1403fe6060f1SDimitry Andric emitVSETVLIs(MBB); 140481ad6265SDimitry Andric 140581ad6265SDimitry Andric // Now that all vsetvlis are explicit, go through and do block local 140681ad6265SDimitry Andric // DSE and peephole based demanded fields based transforms. Note that 140781ad6265SDimitry Andric // this *must* be done outside the main dataflow so long as we allow 140881ad6265SDimitry Andric // any cross block analysis within the dataflow. We can't have both 140981ad6265SDimitry Andric // demanded fields based mutation and non-local analysis in the 141081ad6265SDimitry Andric // dataflow at the same time without introducing inconsistencies. 141181ad6265SDimitry Andric for (MachineBasicBlock &MBB : MF) 141281ad6265SDimitry Andric doLocalPostpass(MBB); 141381ad6265SDimitry Andric 141481ad6265SDimitry Andric // Once we're fully done rewriting all the instructions, do a final pass 141581ad6265SDimitry Andric // through to check for VSETVLIs which write to an unused destination. 141681ad6265SDimitry Andric // For the non X0, X0 variant, we can replace the destination register 141781ad6265SDimitry Andric // with X0 to reduce register pressure. This is really a generic 141881ad6265SDimitry Andric // optimization which can be applied to any dead def (TODO: generalize). 141981ad6265SDimitry Andric for (MachineBasicBlock &MBB : MF) { 142081ad6265SDimitry Andric for (MachineInstr &MI : MBB) { 142181ad6265SDimitry Andric if (MI.getOpcode() == RISCV::PseudoVSETVLI || 142281ad6265SDimitry Andric MI.getOpcode() == RISCV::PseudoVSETIVLI) { 142381ad6265SDimitry Andric Register VRegDef = MI.getOperand(0).getReg(); 142481ad6265SDimitry Andric if (VRegDef != RISCV::X0 && MRI->use_nodbg_empty(VRegDef)) 142581ad6265SDimitry Andric MI.getOperand(0).setReg(RISCV::X0); 142681ad6265SDimitry Andric } 142781ad6265SDimitry Andric } 1428fe6060f1SDimitry Andric } 1429fe6060f1SDimitry Andric 143081ad6265SDimitry Andric // Insert PseudoReadVL after VLEFF/VLSEGFF and replace it with the vl output 143181ad6265SDimitry Andric // of VLEFF/VLSEGFF. 143281ad6265SDimitry Andric for (MachineBasicBlock &MBB : MF) 143381ad6265SDimitry Andric insertReadVL(MBB); 1434fe6060f1SDimitry Andric 143581ad6265SDimitry Andric BlockInfo.clear(); 1436fe6060f1SDimitry Andric return HaveVectorOp; 1437fe6060f1SDimitry Andric } 1438fe6060f1SDimitry Andric 1439fe6060f1SDimitry Andric /// Returns an instance of the Insert VSETVLI pass. 1440fe6060f1SDimitry Andric FunctionPass *llvm::createRISCVInsertVSETVLIPass() { 1441fe6060f1SDimitry Andric return new RISCVInsertVSETVLI(); 1442fe6060f1SDimitry Andric } 1443