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 10fe6060f1SDimitry Andric // needed. 11fe6060f1SDimitry Andric // 12fe6060f1SDimitry Andric // This pass consists of 3 phases: 13fe6060f1SDimitry Andric // 14fe6060f1SDimitry Andric // Phase 1 collects how each basic block affects VL/VTYPE. 15fe6060f1SDimitry Andric // 16fe6060f1SDimitry Andric // Phase 2 uses the information from phase 1 to do a data flow analysis to 17fe6060f1SDimitry Andric // propagate the VL/VTYPE changes through the function. This gives us the 18fe6060f1SDimitry Andric // VL/VTYPE at the start of each basic block. 19fe6060f1SDimitry Andric // 20fe6060f1SDimitry Andric // Phase 3 inserts VSETVLI instructions in each basic block. Information from 21fe6060f1SDimitry Andric // phase 2 is used to prevent inserting a VSETVLI before the first vector 22fe6060f1SDimitry Andric // instruction in the block if possible. 23fe6060f1SDimitry Andric // 24fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 25fe6060f1SDimitry Andric 26fe6060f1SDimitry Andric #include "RISCV.h" 27fe6060f1SDimitry Andric #include "RISCVSubtarget.h" 28fe6060f1SDimitry Andric #include "llvm/CodeGen/LiveIntervals.h" 29fe6060f1SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 30fe6060f1SDimitry Andric #include <queue> 31fe6060f1SDimitry Andric using namespace llvm; 32fe6060f1SDimitry Andric 33fe6060f1SDimitry Andric #define DEBUG_TYPE "riscv-insert-vsetvli" 34fe6060f1SDimitry Andric #define RISCV_INSERT_VSETVLI_NAME "RISCV Insert VSETVLI pass" 35fe6060f1SDimitry Andric 36fe6060f1SDimitry Andric static cl::opt<bool> DisableInsertVSETVLPHIOpt( 37fe6060f1SDimitry Andric "riscv-disable-insert-vsetvl-phi-opt", cl::init(false), cl::Hidden, 38fe6060f1SDimitry Andric cl::desc("Disable looking through phis when inserting vsetvlis.")); 39fe6060f1SDimitry Andric 40fe6060f1SDimitry Andric namespace { 41fe6060f1SDimitry Andric 42fe6060f1SDimitry Andric class VSETVLIInfo { 43fe6060f1SDimitry Andric union { 44fe6060f1SDimitry Andric Register AVLReg; 45fe6060f1SDimitry Andric unsigned AVLImm; 46fe6060f1SDimitry Andric }; 47fe6060f1SDimitry Andric 48fe6060f1SDimitry Andric enum : uint8_t { 49fe6060f1SDimitry Andric Uninitialized, 50fe6060f1SDimitry Andric AVLIsReg, 51fe6060f1SDimitry Andric AVLIsImm, 52fe6060f1SDimitry Andric Unknown, 53fe6060f1SDimitry Andric } State = Uninitialized; 54fe6060f1SDimitry Andric 55fe6060f1SDimitry Andric // Fields from VTYPE. 56fe6060f1SDimitry Andric RISCVII::VLMUL VLMul = RISCVII::LMUL_1; 57fe6060f1SDimitry Andric uint8_t SEW = 0; 58fe6060f1SDimitry Andric uint8_t TailAgnostic : 1; 59fe6060f1SDimitry Andric uint8_t MaskAgnostic : 1; 60fe6060f1SDimitry Andric uint8_t MaskRegOp : 1; 61349cc55cSDimitry Andric uint8_t StoreOp : 1; 6204eeddc0SDimitry Andric uint8_t ScalarMovOp : 1; 63fe6060f1SDimitry Andric uint8_t SEWLMULRatioOnly : 1; 64fe6060f1SDimitry Andric 65fe6060f1SDimitry Andric public: 66fe6060f1SDimitry Andric VSETVLIInfo() 67fe6060f1SDimitry Andric : AVLImm(0), TailAgnostic(false), MaskAgnostic(false), MaskRegOp(false), 6804eeddc0SDimitry Andric StoreOp(false), ScalarMovOp(false), SEWLMULRatioOnly(false) {} 69fe6060f1SDimitry Andric 70fe6060f1SDimitry Andric static VSETVLIInfo getUnknown() { 71fe6060f1SDimitry Andric VSETVLIInfo Info; 72fe6060f1SDimitry Andric Info.setUnknown(); 73fe6060f1SDimitry Andric return Info; 74fe6060f1SDimitry Andric } 75fe6060f1SDimitry Andric 76fe6060f1SDimitry Andric bool isValid() const { return State != Uninitialized; } 77fe6060f1SDimitry Andric void setUnknown() { State = Unknown; } 78fe6060f1SDimitry Andric bool isUnknown() const { return State == Unknown; } 79fe6060f1SDimitry Andric 80fe6060f1SDimitry Andric void setAVLReg(Register Reg) { 81fe6060f1SDimitry Andric AVLReg = Reg; 82fe6060f1SDimitry Andric State = AVLIsReg; 83fe6060f1SDimitry Andric } 84fe6060f1SDimitry Andric 85fe6060f1SDimitry Andric void setAVLImm(unsigned Imm) { 86fe6060f1SDimitry Andric AVLImm = Imm; 87fe6060f1SDimitry Andric State = AVLIsImm; 88fe6060f1SDimitry Andric } 89fe6060f1SDimitry Andric 90fe6060f1SDimitry Andric bool hasAVLImm() const { return State == AVLIsImm; } 91fe6060f1SDimitry Andric bool hasAVLReg() const { return State == AVLIsReg; } 92fe6060f1SDimitry Andric Register getAVLReg() const { 93fe6060f1SDimitry Andric assert(hasAVLReg()); 94fe6060f1SDimitry Andric return AVLReg; 95fe6060f1SDimitry Andric } 96fe6060f1SDimitry Andric unsigned getAVLImm() const { 97fe6060f1SDimitry Andric assert(hasAVLImm()); 98fe6060f1SDimitry Andric return AVLImm; 99fe6060f1SDimitry Andric } 10004eeddc0SDimitry Andric bool hasZeroAVL() const { 10104eeddc0SDimitry Andric if (hasAVLImm()) 10204eeddc0SDimitry Andric return getAVLImm() == 0; 10304eeddc0SDimitry Andric return false; 10404eeddc0SDimitry Andric } 10504eeddc0SDimitry Andric bool hasNonZeroAVL() const { 10604eeddc0SDimitry Andric if (hasAVLImm()) 10704eeddc0SDimitry Andric return getAVLImm() > 0; 10804eeddc0SDimitry Andric if (hasAVLReg()) 10904eeddc0SDimitry Andric return getAVLReg() == RISCV::X0; 11004eeddc0SDimitry Andric return false; 11104eeddc0SDimitry Andric } 112fe6060f1SDimitry Andric 113fe6060f1SDimitry Andric bool hasSameAVL(const VSETVLIInfo &Other) const { 114fe6060f1SDimitry Andric assert(isValid() && Other.isValid() && 115fe6060f1SDimitry Andric "Can't compare invalid VSETVLIInfos"); 116fe6060f1SDimitry Andric assert(!isUnknown() && !Other.isUnknown() && 117fe6060f1SDimitry Andric "Can't compare AVL in unknown state"); 118fe6060f1SDimitry Andric if (hasAVLReg() && Other.hasAVLReg()) 119fe6060f1SDimitry Andric return getAVLReg() == Other.getAVLReg(); 120fe6060f1SDimitry Andric 121fe6060f1SDimitry Andric if (hasAVLImm() && Other.hasAVLImm()) 122fe6060f1SDimitry Andric return getAVLImm() == Other.getAVLImm(); 123fe6060f1SDimitry Andric 124fe6060f1SDimitry Andric return false; 125fe6060f1SDimitry Andric } 126fe6060f1SDimitry Andric 127fe6060f1SDimitry Andric void setVTYPE(unsigned VType) { 128fe6060f1SDimitry Andric assert(isValid() && !isUnknown() && 129fe6060f1SDimitry Andric "Can't set VTYPE for uninitialized or unknown"); 130fe6060f1SDimitry Andric VLMul = RISCVVType::getVLMUL(VType); 131fe6060f1SDimitry Andric SEW = RISCVVType::getSEW(VType); 132fe6060f1SDimitry Andric TailAgnostic = RISCVVType::isTailAgnostic(VType); 133fe6060f1SDimitry Andric MaskAgnostic = RISCVVType::isMaskAgnostic(VType); 134fe6060f1SDimitry Andric } 135349cc55cSDimitry Andric void setVTYPE(RISCVII::VLMUL L, unsigned S, bool TA, bool MA, bool MRO, 13604eeddc0SDimitry Andric bool IsStore, bool IsScalarMovOp) { 137fe6060f1SDimitry Andric assert(isValid() && !isUnknown() && 138fe6060f1SDimitry Andric "Can't set VTYPE for uninitialized or unknown"); 139fe6060f1SDimitry Andric VLMul = L; 140fe6060f1SDimitry Andric SEW = S; 141fe6060f1SDimitry Andric TailAgnostic = TA; 142fe6060f1SDimitry Andric MaskAgnostic = MA; 143fe6060f1SDimitry Andric MaskRegOp = MRO; 144349cc55cSDimitry Andric StoreOp = IsStore; 14504eeddc0SDimitry Andric ScalarMovOp = IsScalarMovOp; 146fe6060f1SDimitry Andric } 147fe6060f1SDimitry Andric 148fe6060f1SDimitry Andric unsigned encodeVTYPE() const { 149fe6060f1SDimitry Andric assert(isValid() && !isUnknown() && !SEWLMULRatioOnly && 150fe6060f1SDimitry Andric "Can't encode VTYPE for uninitialized or unknown"); 151fe6060f1SDimitry Andric return RISCVVType::encodeVTYPE(VLMul, SEW, TailAgnostic, MaskAgnostic); 152fe6060f1SDimitry Andric } 153fe6060f1SDimitry Andric 154fe6060f1SDimitry Andric bool hasSEWLMULRatioOnly() const { return SEWLMULRatioOnly; } 155fe6060f1SDimitry Andric 15604eeddc0SDimitry Andric bool hasSameSEW(const VSETVLIInfo &Other) const { 15704eeddc0SDimitry Andric assert(isValid() && Other.isValid() && 15804eeddc0SDimitry Andric "Can't compare invalid VSETVLIInfos"); 15904eeddc0SDimitry Andric assert(!isUnknown() && !Other.isUnknown() && 16004eeddc0SDimitry Andric "Can't compare VTYPE in unknown state"); 16104eeddc0SDimitry Andric assert(!SEWLMULRatioOnly && !Other.SEWLMULRatioOnly && 16204eeddc0SDimitry Andric "Can't compare when only LMUL/SEW ratio is valid."); 16304eeddc0SDimitry Andric return SEW == Other.SEW; 16404eeddc0SDimitry Andric } 16504eeddc0SDimitry Andric 166fe6060f1SDimitry Andric bool hasSameVTYPE(const VSETVLIInfo &Other) const { 167fe6060f1SDimitry Andric assert(isValid() && Other.isValid() && 168fe6060f1SDimitry Andric "Can't compare invalid VSETVLIInfos"); 169fe6060f1SDimitry Andric assert(!isUnknown() && !Other.isUnknown() && 170fe6060f1SDimitry Andric "Can't compare VTYPE in unknown state"); 171fe6060f1SDimitry Andric assert(!SEWLMULRatioOnly && !Other.SEWLMULRatioOnly && 172fe6060f1SDimitry Andric "Can't compare when only LMUL/SEW ratio is valid."); 173fe6060f1SDimitry Andric return std::tie(VLMul, SEW, TailAgnostic, MaskAgnostic) == 174fe6060f1SDimitry Andric std::tie(Other.VLMul, Other.SEW, Other.TailAgnostic, 175fe6060f1SDimitry Andric Other.MaskAgnostic); 176fe6060f1SDimitry Andric } 177fe6060f1SDimitry Andric 178349cc55cSDimitry Andric static unsigned getSEWLMULRatio(unsigned SEW, RISCVII::VLMUL VLMul) { 179fe6060f1SDimitry Andric unsigned LMul; 180fe6060f1SDimitry Andric bool Fractional; 181fe6060f1SDimitry Andric std::tie(LMul, Fractional) = RISCVVType::decodeVLMUL(VLMul); 182fe6060f1SDimitry Andric 183fe6060f1SDimitry Andric // Convert LMul to a fixed point value with 3 fractional bits. 184fe6060f1SDimitry Andric LMul = Fractional ? (8 / LMul) : (LMul * 8); 185fe6060f1SDimitry Andric 186fe6060f1SDimitry Andric assert(SEW >= 8 && "Unexpected SEW value"); 187fe6060f1SDimitry Andric return (SEW * 8) / LMul; 188fe6060f1SDimitry Andric } 189fe6060f1SDimitry Andric 190349cc55cSDimitry Andric unsigned getSEWLMULRatio() const { 191349cc55cSDimitry Andric assert(isValid() && !isUnknown() && 192349cc55cSDimitry Andric "Can't use VTYPE for uninitialized or unknown"); 193349cc55cSDimitry Andric return getSEWLMULRatio(SEW, VLMul); 194349cc55cSDimitry Andric } 195349cc55cSDimitry Andric 196fe6060f1SDimitry Andric // Check if the VTYPE for these two VSETVLIInfos produce the same VLMAX. 197fe6060f1SDimitry Andric bool hasSameVLMAX(const VSETVLIInfo &Other) const { 198fe6060f1SDimitry Andric assert(isValid() && Other.isValid() && 199fe6060f1SDimitry Andric "Can't compare invalid VSETVLIInfos"); 200fe6060f1SDimitry Andric assert(!isUnknown() && !Other.isUnknown() && 201fe6060f1SDimitry Andric "Can't compare VTYPE in unknown state"); 202fe6060f1SDimitry Andric return getSEWLMULRatio() == Other.getSEWLMULRatio(); 203fe6060f1SDimitry Andric } 204fe6060f1SDimitry Andric 20504eeddc0SDimitry Andric bool hasSamePolicy(const VSETVLIInfo &Other) const { 20604eeddc0SDimitry Andric assert(isValid() && Other.isValid() && 20704eeddc0SDimitry Andric "Can't compare invalid VSETVLIInfos"); 20804eeddc0SDimitry Andric assert(!isUnknown() && !Other.isUnknown() && 20904eeddc0SDimitry Andric "Can't compare VTYPE in unknown state"); 21004eeddc0SDimitry Andric return TailAgnostic == Other.TailAgnostic && 21104eeddc0SDimitry Andric MaskAgnostic == Other.MaskAgnostic; 21204eeddc0SDimitry Andric } 21304eeddc0SDimitry Andric 214349cc55cSDimitry Andric bool hasCompatibleVTYPE(const VSETVLIInfo &InstrInfo, bool Strict) const { 215349cc55cSDimitry Andric // Simple case, see if full VTYPE matches. 216349cc55cSDimitry Andric if (hasSameVTYPE(InstrInfo)) 217349cc55cSDimitry Andric return true; 218349cc55cSDimitry Andric 219349cc55cSDimitry Andric if (Strict) 220349cc55cSDimitry Andric return false; 221349cc55cSDimitry Andric 222349cc55cSDimitry Andric // If this is a mask reg operation, it only cares about VLMAX. 223349cc55cSDimitry Andric // FIXME: Mask reg operations are probably ok if "this" VLMAX is larger 224349cc55cSDimitry Andric // than "InstrInfo". 225349cc55cSDimitry Andric // FIXME: The policy bits can probably be ignored for mask reg operations. 226349cc55cSDimitry Andric if (InstrInfo.MaskRegOp && hasSameVLMAX(InstrInfo) && 227349cc55cSDimitry Andric TailAgnostic == InstrInfo.TailAgnostic && 228349cc55cSDimitry Andric MaskAgnostic == InstrInfo.MaskAgnostic) 229349cc55cSDimitry Andric return true; 230349cc55cSDimitry Andric 231349cc55cSDimitry Andric return false; 232349cc55cSDimitry Andric } 233349cc55cSDimitry Andric 234fe6060f1SDimitry Andric // Determine whether the vector instructions requirements represented by 235fe6060f1SDimitry Andric // InstrInfo are compatible with the previous vsetvli instruction represented 236fe6060f1SDimitry Andric // by this. 237349cc55cSDimitry Andric bool isCompatible(const VSETVLIInfo &InstrInfo, bool Strict) const { 238fe6060f1SDimitry Andric assert(isValid() && InstrInfo.isValid() && 239fe6060f1SDimitry Andric "Can't compare invalid VSETVLIInfos"); 240fe6060f1SDimitry Andric assert(!InstrInfo.SEWLMULRatioOnly && 241fe6060f1SDimitry Andric "Expected a valid VTYPE for instruction!"); 242fe6060f1SDimitry Andric // Nothing is compatible with Unknown. 243fe6060f1SDimitry Andric if (isUnknown() || InstrInfo.isUnknown()) 244fe6060f1SDimitry Andric return false; 245fe6060f1SDimitry Andric 246fe6060f1SDimitry Andric // If only our VLMAX ratio is valid, then this isn't compatible. 247fe6060f1SDimitry Andric if (SEWLMULRatioOnly) 248fe6060f1SDimitry Andric return false; 249fe6060f1SDimitry Andric 250fe6060f1SDimitry Andric // If the instruction doesn't need an AVLReg and the SEW matches, consider 251fe6060f1SDimitry Andric // it compatible. 252349cc55cSDimitry Andric if (!Strict && InstrInfo.hasAVLReg() && 253349cc55cSDimitry Andric InstrInfo.AVLReg == RISCV::NoRegister) { 254fe6060f1SDimitry Andric if (SEW == InstrInfo.SEW) 255fe6060f1SDimitry Andric return true; 256fe6060f1SDimitry Andric } 257fe6060f1SDimitry Andric 25804eeddc0SDimitry Andric // For vmv.s.x and vfmv.s.f, there is only two behaviors, VL = 0 and VL > 0. 25904eeddc0SDimitry Andric // So it's compatible when we could make sure that both VL be the same 26004eeddc0SDimitry Andric // situation. 26104eeddc0SDimitry Andric if (!Strict && InstrInfo.ScalarMovOp && InstrInfo.hasAVLImm() && 26204eeddc0SDimitry Andric ((hasNonZeroAVL() && InstrInfo.hasNonZeroAVL()) || 26304eeddc0SDimitry Andric (hasZeroAVL() && InstrInfo.hasZeroAVL())) && 26404eeddc0SDimitry Andric hasSameSEW(InstrInfo) && hasSamePolicy(InstrInfo)) 26504eeddc0SDimitry Andric return true; 26604eeddc0SDimitry Andric 267349cc55cSDimitry Andric // The AVL must match. 268349cc55cSDimitry Andric if (!hasSameAVL(InstrInfo)) 269fe6060f1SDimitry Andric return false; 270fe6060f1SDimitry Andric 271349cc55cSDimitry Andric if (hasCompatibleVTYPE(InstrInfo, Strict)) 272349cc55cSDimitry Andric return true; 273349cc55cSDimitry Andric 274349cc55cSDimitry Andric // Strict matches must ensure a full VTYPE match. 275349cc55cSDimitry Andric if (Strict) 276349cc55cSDimitry Andric return false; 277349cc55cSDimitry Andric 278349cc55cSDimitry Andric // Store instructions don't use the policy fields. 279349cc55cSDimitry Andric // TODO: Move into hasCompatibleVTYPE? 280349cc55cSDimitry Andric if (InstrInfo.StoreOp && VLMul == InstrInfo.VLMul && SEW == InstrInfo.SEW) 281349cc55cSDimitry Andric return true; 282349cc55cSDimitry Andric 283349cc55cSDimitry Andric // Anything else is not compatible. 284349cc55cSDimitry Andric return false; 285349cc55cSDimitry Andric } 286349cc55cSDimitry Andric 287349cc55cSDimitry Andric bool isCompatibleWithLoadStoreEEW(unsigned EEW, 288349cc55cSDimitry Andric const VSETVLIInfo &InstrInfo) const { 289349cc55cSDimitry Andric assert(isValid() && InstrInfo.isValid() && 290349cc55cSDimitry Andric "Can't compare invalid VSETVLIInfos"); 291349cc55cSDimitry Andric assert(!InstrInfo.SEWLMULRatioOnly && 292349cc55cSDimitry Andric "Expected a valid VTYPE for instruction!"); 293349cc55cSDimitry Andric assert(EEW == InstrInfo.SEW && "Mismatched EEW/SEW for store"); 294349cc55cSDimitry Andric 295349cc55cSDimitry Andric if (isUnknown() || hasSEWLMULRatioOnly()) 296349cc55cSDimitry Andric return false; 297349cc55cSDimitry Andric 298349cc55cSDimitry Andric if (!hasSameAVL(InstrInfo)) 299349cc55cSDimitry Andric return false; 300349cc55cSDimitry Andric 301349cc55cSDimitry Andric // Stores can ignore the tail and mask policies. 302349cc55cSDimitry Andric if (!InstrInfo.StoreOp && (TailAgnostic != InstrInfo.TailAgnostic || 303349cc55cSDimitry Andric MaskAgnostic != InstrInfo.MaskAgnostic)) 304349cc55cSDimitry Andric return false; 305349cc55cSDimitry Andric 306349cc55cSDimitry Andric return getSEWLMULRatio() == getSEWLMULRatio(EEW, InstrInfo.VLMul); 307fe6060f1SDimitry Andric } 308fe6060f1SDimitry Andric 309fe6060f1SDimitry Andric bool operator==(const VSETVLIInfo &Other) const { 310fe6060f1SDimitry Andric // Uninitialized is only equal to another Uninitialized. 311fe6060f1SDimitry Andric if (!isValid()) 312fe6060f1SDimitry Andric return !Other.isValid(); 313fe6060f1SDimitry Andric if (!Other.isValid()) 314fe6060f1SDimitry Andric return !isValid(); 315fe6060f1SDimitry Andric 316fe6060f1SDimitry Andric // Unknown is only equal to another Unknown. 317fe6060f1SDimitry Andric if (isUnknown()) 318fe6060f1SDimitry Andric return Other.isUnknown(); 319fe6060f1SDimitry Andric if (Other.isUnknown()) 320fe6060f1SDimitry Andric return isUnknown(); 321fe6060f1SDimitry Andric 322fe6060f1SDimitry Andric if (!hasSameAVL(Other)) 323fe6060f1SDimitry Andric return false; 324fe6060f1SDimitry Andric 325fe6060f1SDimitry Andric // If only the VLMAX is valid, check that it is the same. 326fe6060f1SDimitry Andric if (SEWLMULRatioOnly && Other.SEWLMULRatioOnly) 327fe6060f1SDimitry Andric return hasSameVLMAX(Other); 328fe6060f1SDimitry Andric 329fe6060f1SDimitry Andric // If the full VTYPE is valid, check that it is the same. 330fe6060f1SDimitry Andric if (!SEWLMULRatioOnly && !Other.SEWLMULRatioOnly) 331fe6060f1SDimitry Andric return hasSameVTYPE(Other); 332fe6060f1SDimitry Andric 333fe6060f1SDimitry Andric // If the SEWLMULRatioOnly bits are different, then they aren't equal. 334fe6060f1SDimitry Andric return false; 335fe6060f1SDimitry Andric } 336fe6060f1SDimitry Andric 337*d56accc7SDimitry Andric bool operator!=(const VSETVLIInfo &Other) const { 338*d56accc7SDimitry Andric return !(*this == Other); 339*d56accc7SDimitry Andric } 340*d56accc7SDimitry Andric 341fe6060f1SDimitry Andric // Calculate the VSETVLIInfo visible to a block assuming this and Other are 342fe6060f1SDimitry Andric // both predecessors. 343fe6060f1SDimitry Andric VSETVLIInfo intersect(const VSETVLIInfo &Other) const { 344fe6060f1SDimitry Andric // If the new value isn't valid, ignore it. 345fe6060f1SDimitry Andric if (!Other.isValid()) 346fe6060f1SDimitry Andric return *this; 347fe6060f1SDimitry Andric 348fe6060f1SDimitry Andric // If this value isn't valid, this must be the first predecessor, use it. 349fe6060f1SDimitry Andric if (!isValid()) 350fe6060f1SDimitry Andric return Other; 351fe6060f1SDimitry Andric 352fe6060f1SDimitry Andric // If either is unknown, the result is unknown. 353fe6060f1SDimitry Andric if (isUnknown() || Other.isUnknown()) 354fe6060f1SDimitry Andric return VSETVLIInfo::getUnknown(); 355fe6060f1SDimitry Andric 356fe6060f1SDimitry Andric // If we have an exact, match return this. 357fe6060f1SDimitry Andric if (*this == Other) 358fe6060f1SDimitry Andric return *this; 359fe6060f1SDimitry Andric 360fe6060f1SDimitry Andric // Not an exact match, but maybe the AVL and VLMAX are the same. If so, 361fe6060f1SDimitry Andric // return an SEW/LMUL ratio only value. 362fe6060f1SDimitry Andric if (hasSameAVL(Other) && hasSameVLMAX(Other)) { 363fe6060f1SDimitry Andric VSETVLIInfo MergeInfo = *this; 364fe6060f1SDimitry Andric MergeInfo.SEWLMULRatioOnly = true; 365fe6060f1SDimitry Andric return MergeInfo; 366fe6060f1SDimitry Andric } 367fe6060f1SDimitry Andric 368fe6060f1SDimitry Andric // Otherwise the result is unknown. 369fe6060f1SDimitry Andric return VSETVLIInfo::getUnknown(); 370fe6060f1SDimitry Andric } 371fe6060f1SDimitry Andric 372fe6060f1SDimitry Andric // Calculate the VSETVLIInfo visible at the end of the block assuming this 373fe6060f1SDimitry Andric // is the predecessor value, and Other is change for this block. 374fe6060f1SDimitry Andric VSETVLIInfo merge(const VSETVLIInfo &Other) const { 375fe6060f1SDimitry Andric assert(isValid() && "Can only merge with a valid VSETVLInfo"); 376fe6060f1SDimitry Andric 377fe6060f1SDimitry Andric // Nothing changed from the predecessor, keep it. 378fe6060f1SDimitry Andric if (!Other.isValid()) 379fe6060f1SDimitry Andric return *this; 380fe6060f1SDimitry Andric 381fe6060f1SDimitry Andric // If the change is compatible with the input, we won't create a VSETVLI 382fe6060f1SDimitry Andric // and should keep the predecessor. 383349cc55cSDimitry Andric if (isCompatible(Other, /*Strict*/ true)) 384fe6060f1SDimitry Andric return *this; 385fe6060f1SDimitry Andric 386fe6060f1SDimitry Andric // Otherwise just use whatever is in this block. 387fe6060f1SDimitry Andric return Other; 388fe6060f1SDimitry Andric } 389fe6060f1SDimitry Andric }; 390fe6060f1SDimitry Andric 391fe6060f1SDimitry Andric struct BlockData { 392fe6060f1SDimitry Andric // The VSETVLIInfo that represents the net changes to the VL/VTYPE registers 393fe6060f1SDimitry Andric // made by this block. Calculated in Phase 1. 394fe6060f1SDimitry Andric VSETVLIInfo Change; 395fe6060f1SDimitry Andric 396fe6060f1SDimitry Andric // The VSETVLIInfo that represents the VL/VTYPE settings on exit from this 397fe6060f1SDimitry Andric // block. Calculated in Phase 2. 398fe6060f1SDimitry Andric VSETVLIInfo Exit; 399fe6060f1SDimitry Andric 400fe6060f1SDimitry Andric // The VSETVLIInfo that represents the VL/VTYPE settings from all predecessor 401fe6060f1SDimitry Andric // blocks. Calculated in Phase 2, and used by Phase 3. 402fe6060f1SDimitry Andric VSETVLIInfo Pred; 403fe6060f1SDimitry Andric 404fe6060f1SDimitry Andric // Keeps track of whether the block is already in the queue. 405fe6060f1SDimitry Andric bool InQueue = false; 406fe6060f1SDimitry Andric 407fe6060f1SDimitry Andric BlockData() {} 408fe6060f1SDimitry Andric }; 409fe6060f1SDimitry Andric 410fe6060f1SDimitry Andric class RISCVInsertVSETVLI : public MachineFunctionPass { 411fe6060f1SDimitry Andric const TargetInstrInfo *TII; 412fe6060f1SDimitry Andric MachineRegisterInfo *MRI; 413fe6060f1SDimitry Andric 414fe6060f1SDimitry Andric std::vector<BlockData> BlockInfo; 415fe6060f1SDimitry Andric std::queue<const MachineBasicBlock *> WorkList; 416fe6060f1SDimitry Andric 417fe6060f1SDimitry Andric public: 418fe6060f1SDimitry Andric static char ID; 419fe6060f1SDimitry Andric 420fe6060f1SDimitry Andric RISCVInsertVSETVLI() : MachineFunctionPass(ID) { 421fe6060f1SDimitry Andric initializeRISCVInsertVSETVLIPass(*PassRegistry::getPassRegistry()); 422fe6060f1SDimitry Andric } 423fe6060f1SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 424fe6060f1SDimitry Andric 425fe6060f1SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 426fe6060f1SDimitry Andric AU.setPreservesCFG(); 427fe6060f1SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 428fe6060f1SDimitry Andric } 429fe6060f1SDimitry Andric 430fe6060f1SDimitry Andric StringRef getPassName() const override { return RISCV_INSERT_VSETVLI_NAME; } 431fe6060f1SDimitry Andric 432fe6060f1SDimitry Andric private: 433fe6060f1SDimitry Andric bool needVSETVLI(const VSETVLIInfo &Require, const VSETVLIInfo &CurInfo); 434fe6060f1SDimitry Andric bool needVSETVLIPHI(const VSETVLIInfo &Require, const MachineBasicBlock &MBB); 435fe6060f1SDimitry Andric void insertVSETVLI(MachineBasicBlock &MBB, MachineInstr &MI, 436fe6060f1SDimitry Andric const VSETVLIInfo &Info, const VSETVLIInfo &PrevInfo); 437fe6060f1SDimitry Andric 438fe6060f1SDimitry Andric bool computeVLVTYPEChanges(const MachineBasicBlock &MBB); 439fe6060f1SDimitry Andric void computeIncomingVLVTYPE(const MachineBasicBlock &MBB); 440fe6060f1SDimitry Andric void emitVSETVLIs(MachineBasicBlock &MBB); 441fe6060f1SDimitry Andric }; 442fe6060f1SDimitry Andric 443fe6060f1SDimitry Andric } // end anonymous namespace 444fe6060f1SDimitry Andric 445fe6060f1SDimitry Andric char RISCVInsertVSETVLI::ID = 0; 446fe6060f1SDimitry Andric 447fe6060f1SDimitry Andric INITIALIZE_PASS(RISCVInsertVSETVLI, DEBUG_TYPE, RISCV_INSERT_VSETVLI_NAME, 448fe6060f1SDimitry Andric false, false) 449fe6060f1SDimitry Andric 450fe6060f1SDimitry Andric static MachineInstr *elideCopies(MachineInstr *MI, 451fe6060f1SDimitry Andric const MachineRegisterInfo *MRI) { 452fe6060f1SDimitry Andric while (true) { 453fe6060f1SDimitry Andric if (!MI->isFullCopy()) 454fe6060f1SDimitry Andric return MI; 455fe6060f1SDimitry Andric if (!Register::isVirtualRegister(MI->getOperand(1).getReg())) 456fe6060f1SDimitry Andric return nullptr; 457fe6060f1SDimitry Andric MI = MRI->getVRegDef(MI->getOperand(1).getReg()); 458fe6060f1SDimitry Andric if (!MI) 459fe6060f1SDimitry Andric return nullptr; 460fe6060f1SDimitry Andric } 461fe6060f1SDimitry Andric } 462fe6060f1SDimitry Andric 46304eeddc0SDimitry Andric static bool isScalarMoveInstr(const MachineInstr &MI) { 46404eeddc0SDimitry Andric switch (MI.getOpcode()) { 46504eeddc0SDimitry Andric default: 46604eeddc0SDimitry Andric return false; 46704eeddc0SDimitry Andric case RISCV::PseudoVMV_S_X_M1: 46804eeddc0SDimitry Andric case RISCV::PseudoVMV_S_X_M2: 46904eeddc0SDimitry Andric case RISCV::PseudoVMV_S_X_M4: 47004eeddc0SDimitry Andric case RISCV::PseudoVMV_S_X_M8: 47104eeddc0SDimitry Andric case RISCV::PseudoVMV_S_X_MF2: 47204eeddc0SDimitry Andric case RISCV::PseudoVMV_S_X_MF4: 47304eeddc0SDimitry Andric case RISCV::PseudoVMV_S_X_MF8: 47404eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F16_M1: 47504eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F16_M2: 47604eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F16_M4: 47704eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F16_M8: 47804eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F16_MF2: 47904eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F16_MF4: 48004eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F32_M1: 48104eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F32_M2: 48204eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F32_M4: 48304eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F32_M8: 48404eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F32_MF2: 48504eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F64_M1: 48604eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F64_M2: 48704eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F64_M4: 48804eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F64_M8: 48904eeddc0SDimitry Andric return true; 49004eeddc0SDimitry Andric } 49104eeddc0SDimitry Andric } 49204eeddc0SDimitry Andric 493fe6060f1SDimitry Andric static VSETVLIInfo computeInfoForInstr(const MachineInstr &MI, uint64_t TSFlags, 494fe6060f1SDimitry Andric const MachineRegisterInfo *MRI) { 495fe6060f1SDimitry Andric VSETVLIInfo InstrInfo; 496fe6060f1SDimitry Andric unsigned NumOperands = MI.getNumExplicitOperands(); 497349cc55cSDimitry Andric bool HasPolicy = RISCVII::hasVecPolicyOp(TSFlags); 498fe6060f1SDimitry Andric 499fe6060f1SDimitry Andric // Default to tail agnostic unless the destination is tied to a source. 500fe6060f1SDimitry Andric // Unless the source is undef. In that case the user would have some control 501fe6060f1SDimitry Andric // over the tail values. Some pseudo instructions force a tail agnostic policy 502fe6060f1SDimitry Andric // despite having a tied def. 503fe6060f1SDimitry Andric bool ForceTailAgnostic = RISCVII::doesForceTailAgnostic(TSFlags); 504fe6060f1SDimitry Andric bool TailAgnostic = true; 505349cc55cSDimitry Andric // If the instruction has policy argument, use the argument. 506349cc55cSDimitry Andric if (HasPolicy) { 507349cc55cSDimitry Andric const MachineOperand &Op = MI.getOperand(MI.getNumExplicitOperands() - 1); 508349cc55cSDimitry Andric TailAgnostic = Op.getImm() & 0x1; 509349cc55cSDimitry Andric } 510349cc55cSDimitry Andric 511fe6060f1SDimitry Andric unsigned UseOpIdx; 512349cc55cSDimitry Andric if (!(ForceTailAgnostic || (HasPolicy && TailAgnostic)) && 513349cc55cSDimitry Andric MI.isRegTiedToUseOperand(0, &UseOpIdx)) { 514fe6060f1SDimitry Andric TailAgnostic = false; 515fe6060f1SDimitry Andric // If the tied operand is an IMPLICIT_DEF we can keep TailAgnostic. 516fe6060f1SDimitry Andric const MachineOperand &UseMO = MI.getOperand(UseOpIdx); 517fe6060f1SDimitry Andric MachineInstr *UseMI = MRI->getVRegDef(UseMO.getReg()); 518fe6060f1SDimitry Andric if (UseMI) { 519fe6060f1SDimitry Andric UseMI = elideCopies(UseMI, MRI); 520fe6060f1SDimitry Andric if (UseMI && UseMI->isImplicitDef()) 521fe6060f1SDimitry Andric TailAgnostic = true; 522fe6060f1SDimitry Andric } 523fe6060f1SDimitry Andric } 524fe6060f1SDimitry Andric 525349cc55cSDimitry Andric // Remove the tail policy so we can find the SEW and VL. 526349cc55cSDimitry Andric if (HasPolicy) 527349cc55cSDimitry Andric --NumOperands; 528349cc55cSDimitry Andric 529349cc55cSDimitry Andric RISCVII::VLMUL VLMul = RISCVII::getLMul(TSFlags); 530349cc55cSDimitry Andric 531349cc55cSDimitry Andric unsigned Log2SEW = MI.getOperand(NumOperands - 1).getImm(); 532349cc55cSDimitry Andric // A Log2SEW of 0 is an operation on mask registers only. 533349cc55cSDimitry Andric bool MaskRegOp = Log2SEW == 0; 534349cc55cSDimitry Andric unsigned SEW = Log2SEW ? 1 << Log2SEW : 8; 535349cc55cSDimitry Andric assert(RISCVVType::isValidSEW(SEW) && "Unexpected SEW"); 536349cc55cSDimitry Andric 537349cc55cSDimitry Andric // If there are no explicit defs, this is a store instruction which can 538349cc55cSDimitry Andric // ignore the tail and mask policies. 539349cc55cSDimitry Andric bool StoreOp = MI.getNumExplicitDefs() == 0; 54004eeddc0SDimitry Andric bool ScalarMovOp = isScalarMoveInstr(MI); 541349cc55cSDimitry Andric 542fe6060f1SDimitry Andric if (RISCVII::hasVLOp(TSFlags)) { 543349cc55cSDimitry Andric const MachineOperand &VLOp = MI.getOperand(NumOperands - 2); 544349cc55cSDimitry Andric if (VLOp.isImm()) { 545349cc55cSDimitry Andric int64_t Imm = VLOp.getImm(); 546349cc55cSDimitry Andric // Conver the VLMax sentintel to X0 register. 547349cc55cSDimitry Andric if (Imm == RISCV::VLMaxSentinel) 548349cc55cSDimitry Andric InstrInfo.setAVLReg(RISCV::X0); 549fe6060f1SDimitry Andric else 550349cc55cSDimitry Andric InstrInfo.setAVLImm(Imm); 551349cc55cSDimitry Andric } else { 552fe6060f1SDimitry Andric InstrInfo.setAVLReg(VLOp.getReg()); 553349cc55cSDimitry Andric } 554fe6060f1SDimitry Andric } else 555fe6060f1SDimitry Andric InstrInfo.setAVLReg(RISCV::NoRegister); 556fe6060f1SDimitry Andric InstrInfo.setVTYPE(VLMul, SEW, /*TailAgnostic*/ TailAgnostic, 55704eeddc0SDimitry Andric /*MaskAgnostic*/ false, MaskRegOp, StoreOp, ScalarMovOp); 558fe6060f1SDimitry Andric 559fe6060f1SDimitry Andric return InstrInfo; 560fe6060f1SDimitry Andric } 561fe6060f1SDimitry Andric 562fe6060f1SDimitry Andric void RISCVInsertVSETVLI::insertVSETVLI(MachineBasicBlock &MBB, MachineInstr &MI, 563fe6060f1SDimitry Andric const VSETVLIInfo &Info, 564fe6060f1SDimitry Andric const VSETVLIInfo &PrevInfo) { 565fe6060f1SDimitry Andric DebugLoc DL = MI.getDebugLoc(); 566fe6060f1SDimitry Andric 567fe6060f1SDimitry Andric // Use X0, X0 form if the AVL is the same and the SEW+LMUL gives the same 568fe6060f1SDimitry Andric // VLMAX. 569fe6060f1SDimitry Andric if (PrevInfo.isValid() && !PrevInfo.isUnknown() && 570fe6060f1SDimitry Andric Info.hasSameAVL(PrevInfo) && Info.hasSameVLMAX(PrevInfo)) { 571349cc55cSDimitry Andric BuildMI(MBB, MI, DL, TII->get(RISCV::PseudoVSETVLIX0)) 572fe6060f1SDimitry Andric .addReg(RISCV::X0, RegState::Define | RegState::Dead) 573fe6060f1SDimitry Andric .addReg(RISCV::X0, RegState::Kill) 574fe6060f1SDimitry Andric .addImm(Info.encodeVTYPE()) 575fe6060f1SDimitry Andric .addReg(RISCV::VL, RegState::Implicit); 576fe6060f1SDimitry Andric return; 577fe6060f1SDimitry Andric } 578fe6060f1SDimitry Andric 579fe6060f1SDimitry Andric if (Info.hasAVLImm()) { 580fe6060f1SDimitry Andric BuildMI(MBB, MI, DL, TII->get(RISCV::PseudoVSETIVLI)) 581fe6060f1SDimitry Andric .addReg(RISCV::X0, RegState::Define | RegState::Dead) 582fe6060f1SDimitry Andric .addImm(Info.getAVLImm()) 583fe6060f1SDimitry Andric .addImm(Info.encodeVTYPE()); 584fe6060f1SDimitry Andric return; 585fe6060f1SDimitry Andric } 586fe6060f1SDimitry Andric 587fe6060f1SDimitry Andric Register AVLReg = Info.getAVLReg(); 588fe6060f1SDimitry Andric if (AVLReg == RISCV::NoRegister) { 589fe6060f1SDimitry Andric // We can only use x0, x0 if there's no chance of the vtype change causing 590fe6060f1SDimitry Andric // the previous vl to become invalid. 591fe6060f1SDimitry Andric if (PrevInfo.isValid() && !PrevInfo.isUnknown() && 592fe6060f1SDimitry Andric Info.hasSameVLMAX(PrevInfo)) { 593349cc55cSDimitry Andric BuildMI(MBB, MI, DL, TII->get(RISCV::PseudoVSETVLIX0)) 594fe6060f1SDimitry Andric .addReg(RISCV::X0, RegState::Define | RegState::Dead) 595fe6060f1SDimitry Andric .addReg(RISCV::X0, RegState::Kill) 596fe6060f1SDimitry Andric .addImm(Info.encodeVTYPE()) 597fe6060f1SDimitry Andric .addReg(RISCV::VL, RegState::Implicit); 598fe6060f1SDimitry Andric return; 599fe6060f1SDimitry Andric } 600fe6060f1SDimitry Andric // Otherwise use an AVL of 0 to avoid depending on previous vl. 601fe6060f1SDimitry Andric BuildMI(MBB, MI, DL, TII->get(RISCV::PseudoVSETIVLI)) 602fe6060f1SDimitry Andric .addReg(RISCV::X0, RegState::Define | RegState::Dead) 603fe6060f1SDimitry Andric .addImm(0) 604fe6060f1SDimitry Andric .addImm(Info.encodeVTYPE()); 605fe6060f1SDimitry Andric return; 606fe6060f1SDimitry Andric } 607fe6060f1SDimitry Andric 608349cc55cSDimitry Andric if (AVLReg.isVirtual()) 609349cc55cSDimitry Andric MRI->constrainRegClass(AVLReg, &RISCV::GPRNoX0RegClass); 610349cc55cSDimitry Andric 611349cc55cSDimitry Andric // Use X0 as the DestReg unless AVLReg is X0. We also need to change the 612349cc55cSDimitry Andric // opcode if the AVLReg is X0 as they have different register classes for 613349cc55cSDimitry Andric // the AVL operand. 614fe6060f1SDimitry Andric Register DestReg = RISCV::X0; 615349cc55cSDimitry Andric unsigned Opcode = RISCV::PseudoVSETVLI; 616349cc55cSDimitry Andric if (AVLReg == RISCV::X0) { 617fe6060f1SDimitry Andric DestReg = MRI->createVirtualRegister(&RISCV::GPRRegClass); 618349cc55cSDimitry Andric Opcode = RISCV::PseudoVSETVLIX0; 619349cc55cSDimitry Andric } 620349cc55cSDimitry Andric BuildMI(MBB, MI, DL, TII->get(Opcode)) 621fe6060f1SDimitry Andric .addReg(DestReg, RegState::Define | RegState::Dead) 622fe6060f1SDimitry Andric .addReg(AVLReg) 623fe6060f1SDimitry Andric .addImm(Info.encodeVTYPE()); 624fe6060f1SDimitry Andric } 625fe6060f1SDimitry Andric 626fe6060f1SDimitry Andric // Return a VSETVLIInfo representing the changes made by this VSETVLI or 627fe6060f1SDimitry Andric // VSETIVLI instruction. 628fe6060f1SDimitry Andric static VSETVLIInfo getInfoForVSETVLI(const MachineInstr &MI) { 629fe6060f1SDimitry Andric VSETVLIInfo NewInfo; 630349cc55cSDimitry Andric if (MI.getOpcode() == RISCV::PseudoVSETIVLI) { 631349cc55cSDimitry Andric NewInfo.setAVLImm(MI.getOperand(1).getImm()); 632349cc55cSDimitry Andric } else { 633349cc55cSDimitry Andric assert(MI.getOpcode() == RISCV::PseudoVSETVLI || 634349cc55cSDimitry Andric MI.getOpcode() == RISCV::PseudoVSETVLIX0); 635fe6060f1SDimitry Andric Register AVLReg = MI.getOperand(1).getReg(); 636fe6060f1SDimitry Andric assert((AVLReg != RISCV::X0 || MI.getOperand(0).getReg() != RISCV::X0) && 637fe6060f1SDimitry Andric "Can't handle X0, X0 vsetvli yet"); 638fe6060f1SDimitry Andric NewInfo.setAVLReg(AVLReg); 639fe6060f1SDimitry Andric } 640fe6060f1SDimitry Andric NewInfo.setVTYPE(MI.getOperand(2).getImm()); 641fe6060f1SDimitry Andric 642fe6060f1SDimitry Andric return NewInfo; 643fe6060f1SDimitry Andric } 644fe6060f1SDimitry Andric 645fe6060f1SDimitry Andric bool RISCVInsertVSETVLI::needVSETVLI(const VSETVLIInfo &Require, 646fe6060f1SDimitry Andric const VSETVLIInfo &CurInfo) { 647349cc55cSDimitry Andric if (CurInfo.isCompatible(Require, /*Strict*/ false)) 648fe6060f1SDimitry Andric return false; 649fe6060f1SDimitry Andric 650fe6060f1SDimitry Andric // We didn't find a compatible value. If our AVL is a virtual register, 651fe6060f1SDimitry Andric // it might be defined by a VSET(I)VLI. If it has the same VTYPE we need 652fe6060f1SDimitry Andric // and the last VL/VTYPE we observed is the same, we don't need a 653fe6060f1SDimitry Andric // VSETVLI here. 654fe6060f1SDimitry Andric if (!CurInfo.isUnknown() && Require.hasAVLReg() && 655fe6060f1SDimitry Andric Require.getAVLReg().isVirtual() && !CurInfo.hasSEWLMULRatioOnly() && 656349cc55cSDimitry Andric CurInfo.hasCompatibleVTYPE(Require, /*Strict*/ false)) { 657fe6060f1SDimitry Andric if (MachineInstr *DefMI = MRI->getVRegDef(Require.getAVLReg())) { 658fe6060f1SDimitry Andric if (DefMI->getOpcode() == RISCV::PseudoVSETVLI || 659349cc55cSDimitry Andric DefMI->getOpcode() == RISCV::PseudoVSETVLIX0 || 660fe6060f1SDimitry Andric DefMI->getOpcode() == RISCV::PseudoVSETIVLI) { 661fe6060f1SDimitry Andric VSETVLIInfo DefInfo = getInfoForVSETVLI(*DefMI); 662fe6060f1SDimitry Andric if (DefInfo.hasSameAVL(CurInfo) && DefInfo.hasSameVTYPE(CurInfo)) 663fe6060f1SDimitry Andric return false; 664fe6060f1SDimitry Andric } 665fe6060f1SDimitry Andric } 666fe6060f1SDimitry Andric } 667fe6060f1SDimitry Andric 668fe6060f1SDimitry Andric return true; 669fe6060f1SDimitry Andric } 670fe6060f1SDimitry Andric 671349cc55cSDimitry Andric bool canSkipVSETVLIForLoadStore(const MachineInstr &MI, 672349cc55cSDimitry Andric const VSETVLIInfo &Require, 673349cc55cSDimitry Andric const VSETVLIInfo &CurInfo) { 674349cc55cSDimitry Andric unsigned EEW; 675349cc55cSDimitry Andric switch (MI.getOpcode()) { 676349cc55cSDimitry Andric default: 677349cc55cSDimitry Andric return false; 678349cc55cSDimitry Andric case RISCV::PseudoVLE8_V_M1: 679349cc55cSDimitry Andric case RISCV::PseudoVLE8_V_M1_MASK: 680349cc55cSDimitry Andric case RISCV::PseudoVLE8_V_M2: 681349cc55cSDimitry Andric case RISCV::PseudoVLE8_V_M2_MASK: 682349cc55cSDimitry Andric case RISCV::PseudoVLE8_V_M4: 683349cc55cSDimitry Andric case RISCV::PseudoVLE8_V_M4_MASK: 684349cc55cSDimitry Andric case RISCV::PseudoVLE8_V_M8: 685349cc55cSDimitry Andric case RISCV::PseudoVLE8_V_M8_MASK: 686349cc55cSDimitry Andric case RISCV::PseudoVLE8_V_MF2: 687349cc55cSDimitry Andric case RISCV::PseudoVLE8_V_MF2_MASK: 688349cc55cSDimitry Andric case RISCV::PseudoVLE8_V_MF4: 689349cc55cSDimitry Andric case RISCV::PseudoVLE8_V_MF4_MASK: 690349cc55cSDimitry Andric case RISCV::PseudoVLE8_V_MF8: 691349cc55cSDimitry Andric case RISCV::PseudoVLE8_V_MF8_MASK: 692349cc55cSDimitry Andric case RISCV::PseudoVLSE8_V_M1: 693349cc55cSDimitry Andric case RISCV::PseudoVLSE8_V_M1_MASK: 694349cc55cSDimitry Andric case RISCV::PseudoVLSE8_V_M2: 695349cc55cSDimitry Andric case RISCV::PseudoVLSE8_V_M2_MASK: 696349cc55cSDimitry Andric case RISCV::PseudoVLSE8_V_M4: 697349cc55cSDimitry Andric case RISCV::PseudoVLSE8_V_M4_MASK: 698349cc55cSDimitry Andric case RISCV::PseudoVLSE8_V_M8: 699349cc55cSDimitry Andric case RISCV::PseudoVLSE8_V_M8_MASK: 700349cc55cSDimitry Andric case RISCV::PseudoVLSE8_V_MF2: 701349cc55cSDimitry Andric case RISCV::PseudoVLSE8_V_MF2_MASK: 702349cc55cSDimitry Andric case RISCV::PseudoVLSE8_V_MF4: 703349cc55cSDimitry Andric case RISCV::PseudoVLSE8_V_MF4_MASK: 704349cc55cSDimitry Andric case RISCV::PseudoVLSE8_V_MF8: 705349cc55cSDimitry Andric case RISCV::PseudoVLSE8_V_MF8_MASK: 706349cc55cSDimitry Andric case RISCV::PseudoVSE8_V_M1: 707349cc55cSDimitry Andric case RISCV::PseudoVSE8_V_M1_MASK: 708349cc55cSDimitry Andric case RISCV::PseudoVSE8_V_M2: 709349cc55cSDimitry Andric case RISCV::PseudoVSE8_V_M2_MASK: 710349cc55cSDimitry Andric case RISCV::PseudoVSE8_V_M4: 711349cc55cSDimitry Andric case RISCV::PseudoVSE8_V_M4_MASK: 712349cc55cSDimitry Andric case RISCV::PseudoVSE8_V_M8: 713349cc55cSDimitry Andric case RISCV::PseudoVSE8_V_M8_MASK: 714349cc55cSDimitry Andric case RISCV::PseudoVSE8_V_MF2: 715349cc55cSDimitry Andric case RISCV::PseudoVSE8_V_MF2_MASK: 716349cc55cSDimitry Andric case RISCV::PseudoVSE8_V_MF4: 717349cc55cSDimitry Andric case RISCV::PseudoVSE8_V_MF4_MASK: 718349cc55cSDimitry Andric case RISCV::PseudoVSE8_V_MF8: 719349cc55cSDimitry Andric case RISCV::PseudoVSE8_V_MF8_MASK: 720349cc55cSDimitry Andric case RISCV::PseudoVSSE8_V_M1: 721349cc55cSDimitry Andric case RISCV::PseudoVSSE8_V_M1_MASK: 722349cc55cSDimitry Andric case RISCV::PseudoVSSE8_V_M2: 723349cc55cSDimitry Andric case RISCV::PseudoVSSE8_V_M2_MASK: 724349cc55cSDimitry Andric case RISCV::PseudoVSSE8_V_M4: 725349cc55cSDimitry Andric case RISCV::PseudoVSSE8_V_M4_MASK: 726349cc55cSDimitry Andric case RISCV::PseudoVSSE8_V_M8: 727349cc55cSDimitry Andric case RISCV::PseudoVSSE8_V_M8_MASK: 728349cc55cSDimitry Andric case RISCV::PseudoVSSE8_V_MF2: 729349cc55cSDimitry Andric case RISCV::PseudoVSSE8_V_MF2_MASK: 730349cc55cSDimitry Andric case RISCV::PseudoVSSE8_V_MF4: 731349cc55cSDimitry Andric case RISCV::PseudoVSSE8_V_MF4_MASK: 732349cc55cSDimitry Andric case RISCV::PseudoVSSE8_V_MF8: 733349cc55cSDimitry Andric case RISCV::PseudoVSSE8_V_MF8_MASK: 734349cc55cSDimitry Andric EEW = 8; 735349cc55cSDimitry Andric break; 736349cc55cSDimitry Andric case RISCV::PseudoVLE16_V_M1: 737349cc55cSDimitry Andric case RISCV::PseudoVLE16_V_M1_MASK: 738349cc55cSDimitry Andric case RISCV::PseudoVLE16_V_M2: 739349cc55cSDimitry Andric case RISCV::PseudoVLE16_V_M2_MASK: 740349cc55cSDimitry Andric case RISCV::PseudoVLE16_V_M4: 741349cc55cSDimitry Andric case RISCV::PseudoVLE16_V_M4_MASK: 742349cc55cSDimitry Andric case RISCV::PseudoVLE16_V_M8: 743349cc55cSDimitry Andric case RISCV::PseudoVLE16_V_M8_MASK: 744349cc55cSDimitry Andric case RISCV::PseudoVLE16_V_MF2: 745349cc55cSDimitry Andric case RISCV::PseudoVLE16_V_MF2_MASK: 746349cc55cSDimitry Andric case RISCV::PseudoVLE16_V_MF4: 747349cc55cSDimitry Andric case RISCV::PseudoVLE16_V_MF4_MASK: 748349cc55cSDimitry Andric case RISCV::PseudoVLSE16_V_M1: 749349cc55cSDimitry Andric case RISCV::PseudoVLSE16_V_M1_MASK: 750349cc55cSDimitry Andric case RISCV::PseudoVLSE16_V_M2: 751349cc55cSDimitry Andric case RISCV::PseudoVLSE16_V_M2_MASK: 752349cc55cSDimitry Andric case RISCV::PseudoVLSE16_V_M4: 753349cc55cSDimitry Andric case RISCV::PseudoVLSE16_V_M4_MASK: 754349cc55cSDimitry Andric case RISCV::PseudoVLSE16_V_M8: 755349cc55cSDimitry Andric case RISCV::PseudoVLSE16_V_M8_MASK: 756349cc55cSDimitry Andric case RISCV::PseudoVLSE16_V_MF2: 757349cc55cSDimitry Andric case RISCV::PseudoVLSE16_V_MF2_MASK: 758349cc55cSDimitry Andric case RISCV::PseudoVLSE16_V_MF4: 759349cc55cSDimitry Andric case RISCV::PseudoVLSE16_V_MF4_MASK: 760349cc55cSDimitry Andric case RISCV::PseudoVSE16_V_M1: 761349cc55cSDimitry Andric case RISCV::PseudoVSE16_V_M1_MASK: 762349cc55cSDimitry Andric case RISCV::PseudoVSE16_V_M2: 763349cc55cSDimitry Andric case RISCV::PseudoVSE16_V_M2_MASK: 764349cc55cSDimitry Andric case RISCV::PseudoVSE16_V_M4: 765349cc55cSDimitry Andric case RISCV::PseudoVSE16_V_M4_MASK: 766349cc55cSDimitry Andric case RISCV::PseudoVSE16_V_M8: 767349cc55cSDimitry Andric case RISCV::PseudoVSE16_V_M8_MASK: 768349cc55cSDimitry Andric case RISCV::PseudoVSE16_V_MF2: 769349cc55cSDimitry Andric case RISCV::PseudoVSE16_V_MF2_MASK: 770349cc55cSDimitry Andric case RISCV::PseudoVSE16_V_MF4: 771349cc55cSDimitry Andric case RISCV::PseudoVSE16_V_MF4_MASK: 772349cc55cSDimitry Andric case RISCV::PseudoVSSE16_V_M1: 773349cc55cSDimitry Andric case RISCV::PseudoVSSE16_V_M1_MASK: 774349cc55cSDimitry Andric case RISCV::PseudoVSSE16_V_M2: 775349cc55cSDimitry Andric case RISCV::PseudoVSSE16_V_M2_MASK: 776349cc55cSDimitry Andric case RISCV::PseudoVSSE16_V_M4: 777349cc55cSDimitry Andric case RISCV::PseudoVSSE16_V_M4_MASK: 778349cc55cSDimitry Andric case RISCV::PseudoVSSE16_V_M8: 779349cc55cSDimitry Andric case RISCV::PseudoVSSE16_V_M8_MASK: 780349cc55cSDimitry Andric case RISCV::PseudoVSSE16_V_MF2: 781349cc55cSDimitry Andric case RISCV::PseudoVSSE16_V_MF2_MASK: 782349cc55cSDimitry Andric case RISCV::PseudoVSSE16_V_MF4: 783349cc55cSDimitry Andric case RISCV::PseudoVSSE16_V_MF4_MASK: 784349cc55cSDimitry Andric EEW = 16; 785349cc55cSDimitry Andric break; 786349cc55cSDimitry Andric case RISCV::PseudoVLE32_V_M1: 787349cc55cSDimitry Andric case RISCV::PseudoVLE32_V_M1_MASK: 788349cc55cSDimitry Andric case RISCV::PseudoVLE32_V_M2: 789349cc55cSDimitry Andric case RISCV::PseudoVLE32_V_M2_MASK: 790349cc55cSDimitry Andric case RISCV::PseudoVLE32_V_M4: 791349cc55cSDimitry Andric case RISCV::PseudoVLE32_V_M4_MASK: 792349cc55cSDimitry Andric case RISCV::PseudoVLE32_V_M8: 793349cc55cSDimitry Andric case RISCV::PseudoVLE32_V_M8_MASK: 794349cc55cSDimitry Andric case RISCV::PseudoVLE32_V_MF2: 795349cc55cSDimitry Andric case RISCV::PseudoVLE32_V_MF2_MASK: 796349cc55cSDimitry Andric case RISCV::PseudoVLSE32_V_M1: 797349cc55cSDimitry Andric case RISCV::PseudoVLSE32_V_M1_MASK: 798349cc55cSDimitry Andric case RISCV::PseudoVLSE32_V_M2: 799349cc55cSDimitry Andric case RISCV::PseudoVLSE32_V_M2_MASK: 800349cc55cSDimitry Andric case RISCV::PseudoVLSE32_V_M4: 801349cc55cSDimitry Andric case RISCV::PseudoVLSE32_V_M4_MASK: 802349cc55cSDimitry Andric case RISCV::PseudoVLSE32_V_M8: 803349cc55cSDimitry Andric case RISCV::PseudoVLSE32_V_M8_MASK: 804349cc55cSDimitry Andric case RISCV::PseudoVLSE32_V_MF2: 805349cc55cSDimitry Andric case RISCV::PseudoVLSE32_V_MF2_MASK: 806349cc55cSDimitry Andric case RISCV::PseudoVSE32_V_M1: 807349cc55cSDimitry Andric case RISCV::PseudoVSE32_V_M1_MASK: 808349cc55cSDimitry Andric case RISCV::PseudoVSE32_V_M2: 809349cc55cSDimitry Andric case RISCV::PseudoVSE32_V_M2_MASK: 810349cc55cSDimitry Andric case RISCV::PseudoVSE32_V_M4: 811349cc55cSDimitry Andric case RISCV::PseudoVSE32_V_M4_MASK: 812349cc55cSDimitry Andric case RISCV::PseudoVSE32_V_M8: 813349cc55cSDimitry Andric case RISCV::PseudoVSE32_V_M8_MASK: 814349cc55cSDimitry Andric case RISCV::PseudoVSE32_V_MF2: 815349cc55cSDimitry Andric case RISCV::PseudoVSE32_V_MF2_MASK: 816349cc55cSDimitry Andric case RISCV::PseudoVSSE32_V_M1: 817349cc55cSDimitry Andric case RISCV::PseudoVSSE32_V_M1_MASK: 818349cc55cSDimitry Andric case RISCV::PseudoVSSE32_V_M2: 819349cc55cSDimitry Andric case RISCV::PseudoVSSE32_V_M2_MASK: 820349cc55cSDimitry Andric case RISCV::PseudoVSSE32_V_M4: 821349cc55cSDimitry Andric case RISCV::PseudoVSSE32_V_M4_MASK: 822349cc55cSDimitry Andric case RISCV::PseudoVSSE32_V_M8: 823349cc55cSDimitry Andric case RISCV::PseudoVSSE32_V_M8_MASK: 824349cc55cSDimitry Andric case RISCV::PseudoVSSE32_V_MF2: 825349cc55cSDimitry Andric case RISCV::PseudoVSSE32_V_MF2_MASK: 826349cc55cSDimitry Andric EEW = 32; 827349cc55cSDimitry Andric break; 828349cc55cSDimitry Andric case RISCV::PseudoVLE64_V_M1: 829349cc55cSDimitry Andric case RISCV::PseudoVLE64_V_M1_MASK: 830349cc55cSDimitry Andric case RISCV::PseudoVLE64_V_M2: 831349cc55cSDimitry Andric case RISCV::PseudoVLE64_V_M2_MASK: 832349cc55cSDimitry Andric case RISCV::PseudoVLE64_V_M4: 833349cc55cSDimitry Andric case RISCV::PseudoVLE64_V_M4_MASK: 834349cc55cSDimitry Andric case RISCV::PseudoVLE64_V_M8: 835349cc55cSDimitry Andric case RISCV::PseudoVLE64_V_M8_MASK: 836349cc55cSDimitry Andric case RISCV::PseudoVLSE64_V_M1: 837349cc55cSDimitry Andric case RISCV::PseudoVLSE64_V_M1_MASK: 838349cc55cSDimitry Andric case RISCV::PseudoVLSE64_V_M2: 839349cc55cSDimitry Andric case RISCV::PseudoVLSE64_V_M2_MASK: 840349cc55cSDimitry Andric case RISCV::PseudoVLSE64_V_M4: 841349cc55cSDimitry Andric case RISCV::PseudoVLSE64_V_M4_MASK: 842349cc55cSDimitry Andric case RISCV::PseudoVLSE64_V_M8: 843349cc55cSDimitry Andric case RISCV::PseudoVLSE64_V_M8_MASK: 844349cc55cSDimitry Andric case RISCV::PseudoVSE64_V_M1: 845349cc55cSDimitry Andric case RISCV::PseudoVSE64_V_M1_MASK: 846349cc55cSDimitry Andric case RISCV::PseudoVSE64_V_M2: 847349cc55cSDimitry Andric case RISCV::PseudoVSE64_V_M2_MASK: 848349cc55cSDimitry Andric case RISCV::PseudoVSE64_V_M4: 849349cc55cSDimitry Andric case RISCV::PseudoVSE64_V_M4_MASK: 850349cc55cSDimitry Andric case RISCV::PseudoVSE64_V_M8: 851349cc55cSDimitry Andric case RISCV::PseudoVSE64_V_M8_MASK: 852349cc55cSDimitry Andric case RISCV::PseudoVSSE64_V_M1: 853349cc55cSDimitry Andric case RISCV::PseudoVSSE64_V_M1_MASK: 854349cc55cSDimitry Andric case RISCV::PseudoVSSE64_V_M2: 855349cc55cSDimitry Andric case RISCV::PseudoVSSE64_V_M2_MASK: 856349cc55cSDimitry Andric case RISCV::PseudoVSSE64_V_M4: 857349cc55cSDimitry Andric case RISCV::PseudoVSSE64_V_M4_MASK: 858349cc55cSDimitry Andric case RISCV::PseudoVSSE64_V_M8: 859349cc55cSDimitry Andric case RISCV::PseudoVSSE64_V_M8_MASK: 860349cc55cSDimitry Andric EEW = 64; 861349cc55cSDimitry Andric break; 862349cc55cSDimitry Andric } 863349cc55cSDimitry Andric 864349cc55cSDimitry Andric return CurInfo.isCompatibleWithLoadStoreEEW(EEW, Require); 865349cc55cSDimitry Andric } 866349cc55cSDimitry Andric 867fe6060f1SDimitry Andric bool RISCVInsertVSETVLI::computeVLVTYPEChanges(const MachineBasicBlock &MBB) { 868fe6060f1SDimitry Andric bool HadVectorOp = false; 869fe6060f1SDimitry Andric 870fe6060f1SDimitry Andric BlockData &BBInfo = BlockInfo[MBB.getNumber()]; 871fe6060f1SDimitry Andric for (const MachineInstr &MI : MBB) { 872fe6060f1SDimitry Andric // If this is an explicit VSETVLI or VSETIVLI, update our state. 873fe6060f1SDimitry Andric if (MI.getOpcode() == RISCV::PseudoVSETVLI || 874349cc55cSDimitry Andric MI.getOpcode() == RISCV::PseudoVSETVLIX0 || 875fe6060f1SDimitry Andric MI.getOpcode() == RISCV::PseudoVSETIVLI) { 876fe6060f1SDimitry Andric HadVectorOp = true; 877fe6060f1SDimitry Andric BBInfo.Change = getInfoForVSETVLI(MI); 878fe6060f1SDimitry Andric continue; 879fe6060f1SDimitry Andric } 880fe6060f1SDimitry Andric 881fe6060f1SDimitry Andric uint64_t TSFlags = MI.getDesc().TSFlags; 882fe6060f1SDimitry Andric if (RISCVII::hasSEWOp(TSFlags)) { 883fe6060f1SDimitry Andric HadVectorOp = true; 884fe6060f1SDimitry Andric 885fe6060f1SDimitry Andric VSETVLIInfo NewInfo = computeInfoForInstr(MI, TSFlags, MRI); 886fe6060f1SDimitry Andric 887fe6060f1SDimitry Andric if (!BBInfo.Change.isValid()) { 888fe6060f1SDimitry Andric BBInfo.Change = NewInfo; 889fe6060f1SDimitry Andric } else { 890fe6060f1SDimitry Andric // If this instruction isn't compatible with the previous VL/VTYPE 891fe6060f1SDimitry Andric // we need to insert a VSETVLI. 892349cc55cSDimitry Andric // If this is a unit-stride or strided load/store, we may be able to use 893349cc55cSDimitry Andric // the EMUL=(EEW/SEW)*LMUL relationship to avoid changing vtype. 894349cc55cSDimitry Andric // NOTE: We only do this if the vtype we're comparing against was 895349cc55cSDimitry Andric // created in this block. We need the first and third phase to treat 896349cc55cSDimitry Andric // the store the same way. 897349cc55cSDimitry Andric if (!canSkipVSETVLIForLoadStore(MI, NewInfo, BBInfo.Change) && 898349cc55cSDimitry Andric needVSETVLI(NewInfo, BBInfo.Change)) 899fe6060f1SDimitry Andric BBInfo.Change = NewInfo; 900fe6060f1SDimitry Andric } 901fe6060f1SDimitry Andric } 902fe6060f1SDimitry Andric 903fe6060f1SDimitry Andric // If this is something that updates VL/VTYPE that we don't know about, set 904fe6060f1SDimitry Andric // the state to unknown. 905fe6060f1SDimitry Andric if (MI.isCall() || MI.isInlineAsm() || MI.modifiesRegister(RISCV::VL) || 906fe6060f1SDimitry Andric MI.modifiesRegister(RISCV::VTYPE)) { 907fe6060f1SDimitry Andric BBInfo.Change = VSETVLIInfo::getUnknown(); 908fe6060f1SDimitry Andric } 909fe6060f1SDimitry Andric } 910fe6060f1SDimitry Andric 911fe6060f1SDimitry Andric // Initial exit state is whatever change we found in the block. 912fe6060f1SDimitry Andric BBInfo.Exit = BBInfo.Change; 913fe6060f1SDimitry Andric 914fe6060f1SDimitry Andric return HadVectorOp; 915fe6060f1SDimitry Andric } 916fe6060f1SDimitry Andric 917fe6060f1SDimitry Andric void RISCVInsertVSETVLI::computeIncomingVLVTYPE(const MachineBasicBlock &MBB) { 918fe6060f1SDimitry Andric BlockData &BBInfo = BlockInfo[MBB.getNumber()]; 919fe6060f1SDimitry Andric 920fe6060f1SDimitry Andric BBInfo.InQueue = false; 921fe6060f1SDimitry Andric 922fe6060f1SDimitry Andric VSETVLIInfo InInfo; 923fe6060f1SDimitry Andric if (MBB.pred_empty()) { 924fe6060f1SDimitry Andric // There are no predecessors, so use the default starting status. 925fe6060f1SDimitry Andric InInfo.setUnknown(); 926fe6060f1SDimitry Andric } else { 927fe6060f1SDimitry Andric for (MachineBasicBlock *P : MBB.predecessors()) 928fe6060f1SDimitry Andric InInfo = InInfo.intersect(BlockInfo[P->getNumber()].Exit); 929fe6060f1SDimitry Andric } 930fe6060f1SDimitry Andric 931fe6060f1SDimitry Andric // If we don't have any valid predecessor value, wait until we do. 932fe6060f1SDimitry Andric if (!InInfo.isValid()) 933fe6060f1SDimitry Andric return; 934fe6060f1SDimitry Andric 935fe6060f1SDimitry Andric BBInfo.Pred = InInfo; 936fe6060f1SDimitry Andric 937fe6060f1SDimitry Andric VSETVLIInfo TmpStatus = BBInfo.Pred.merge(BBInfo.Change); 938fe6060f1SDimitry Andric 939fe6060f1SDimitry Andric // If the new exit value matches the old exit value, we don't need to revisit 940fe6060f1SDimitry Andric // any blocks. 941fe6060f1SDimitry Andric if (BBInfo.Exit == TmpStatus) 942fe6060f1SDimitry Andric return; 943fe6060f1SDimitry Andric 944fe6060f1SDimitry Andric BBInfo.Exit = TmpStatus; 945fe6060f1SDimitry Andric 946fe6060f1SDimitry Andric // Add the successors to the work list so we can propagate the changed exit 947fe6060f1SDimitry Andric // status. 948fe6060f1SDimitry Andric for (MachineBasicBlock *S : MBB.successors()) 949fe6060f1SDimitry Andric if (!BlockInfo[S->getNumber()].InQueue) 950fe6060f1SDimitry Andric WorkList.push(S); 951fe6060f1SDimitry Andric } 952fe6060f1SDimitry Andric 953fe6060f1SDimitry Andric // If we weren't able to prove a vsetvli was directly unneeded, it might still 954fe6060f1SDimitry Andric // be/ unneeded if the AVL is a phi node where all incoming values are VL 955fe6060f1SDimitry Andric // outputs from the last VSETVLI in their respective basic blocks. 956fe6060f1SDimitry Andric bool RISCVInsertVSETVLI::needVSETVLIPHI(const VSETVLIInfo &Require, 957fe6060f1SDimitry Andric const MachineBasicBlock &MBB) { 958fe6060f1SDimitry Andric if (DisableInsertVSETVLPHIOpt) 959fe6060f1SDimitry Andric return true; 960fe6060f1SDimitry Andric 961fe6060f1SDimitry Andric if (!Require.hasAVLReg()) 962fe6060f1SDimitry Andric return true; 963fe6060f1SDimitry Andric 964fe6060f1SDimitry Andric Register AVLReg = Require.getAVLReg(); 965fe6060f1SDimitry Andric if (!AVLReg.isVirtual()) 966fe6060f1SDimitry Andric return true; 967fe6060f1SDimitry Andric 968fe6060f1SDimitry Andric // We need the AVL to be produce by a PHI node in this basic block. 969fe6060f1SDimitry Andric MachineInstr *PHI = MRI->getVRegDef(AVLReg); 970fe6060f1SDimitry Andric if (!PHI || PHI->getOpcode() != RISCV::PHI || PHI->getParent() != &MBB) 971fe6060f1SDimitry Andric return true; 972fe6060f1SDimitry Andric 973fe6060f1SDimitry Andric for (unsigned PHIOp = 1, NumOps = PHI->getNumOperands(); PHIOp != NumOps; 974fe6060f1SDimitry Andric PHIOp += 2) { 975fe6060f1SDimitry Andric Register InReg = PHI->getOperand(PHIOp).getReg(); 976fe6060f1SDimitry Andric MachineBasicBlock *PBB = PHI->getOperand(PHIOp + 1).getMBB(); 977fe6060f1SDimitry Andric const BlockData &PBBInfo = BlockInfo[PBB->getNumber()]; 978fe6060f1SDimitry Andric // If the exit from the predecessor has the VTYPE we are looking for 979fe6060f1SDimitry Andric // we might be able to avoid a VSETVLI. 980349cc55cSDimitry Andric if (PBBInfo.Exit.isUnknown() || 981349cc55cSDimitry Andric !PBBInfo.Exit.hasCompatibleVTYPE(Require, /*Strict*/ false)) 982fe6060f1SDimitry Andric return true; 983fe6060f1SDimitry Andric 984fe6060f1SDimitry Andric // We need the PHI input to the be the output of a VSET(I)VLI. 985fe6060f1SDimitry Andric MachineInstr *DefMI = MRI->getVRegDef(InReg); 986fe6060f1SDimitry Andric if (!DefMI || (DefMI->getOpcode() != RISCV::PseudoVSETVLI && 987349cc55cSDimitry Andric DefMI->getOpcode() != RISCV::PseudoVSETVLIX0 && 988fe6060f1SDimitry Andric DefMI->getOpcode() != RISCV::PseudoVSETIVLI)) 989fe6060f1SDimitry Andric return true; 990fe6060f1SDimitry Andric 991fe6060f1SDimitry Andric // We found a VSET(I)VLI make sure it matches the output of the 992fe6060f1SDimitry Andric // predecessor block. 993fe6060f1SDimitry Andric VSETVLIInfo DefInfo = getInfoForVSETVLI(*DefMI); 994fe6060f1SDimitry Andric if (!DefInfo.hasSameAVL(PBBInfo.Exit) || 995fe6060f1SDimitry Andric !DefInfo.hasSameVTYPE(PBBInfo.Exit)) 996fe6060f1SDimitry Andric return true; 997fe6060f1SDimitry Andric } 998fe6060f1SDimitry Andric 999fe6060f1SDimitry Andric // If all the incoming values to the PHI checked out, we don't need 1000fe6060f1SDimitry Andric // to insert a VSETVLI. 1001fe6060f1SDimitry Andric return false; 1002fe6060f1SDimitry Andric } 1003fe6060f1SDimitry Andric 1004fe6060f1SDimitry Andric void RISCVInsertVSETVLI::emitVSETVLIs(MachineBasicBlock &MBB) { 1005fe6060f1SDimitry Andric VSETVLIInfo CurInfo; 1006349cc55cSDimitry Andric // Only be set if current VSETVLIInfo is from an explicit VSET(I)VLI. 1007349cc55cSDimitry Andric MachineInstr *PrevVSETVLIMI = nullptr; 1008fe6060f1SDimitry Andric 1009fe6060f1SDimitry Andric for (MachineInstr &MI : MBB) { 1010fe6060f1SDimitry Andric // If this is an explicit VSETVLI or VSETIVLI, update our state. 1011fe6060f1SDimitry Andric if (MI.getOpcode() == RISCV::PseudoVSETVLI || 1012349cc55cSDimitry Andric MI.getOpcode() == RISCV::PseudoVSETVLIX0 || 1013fe6060f1SDimitry Andric MI.getOpcode() == RISCV::PseudoVSETIVLI) { 1014fe6060f1SDimitry Andric // Conservatively, mark the VL and VTYPE as live. 1015fe6060f1SDimitry Andric assert(MI.getOperand(3).getReg() == RISCV::VL && 1016fe6060f1SDimitry Andric MI.getOperand(4).getReg() == RISCV::VTYPE && 1017fe6060f1SDimitry Andric "Unexpected operands where VL and VTYPE should be"); 1018fe6060f1SDimitry Andric MI.getOperand(3).setIsDead(false); 1019fe6060f1SDimitry Andric MI.getOperand(4).setIsDead(false); 1020fe6060f1SDimitry Andric CurInfo = getInfoForVSETVLI(MI); 1021349cc55cSDimitry Andric PrevVSETVLIMI = &MI; 1022fe6060f1SDimitry Andric continue; 1023fe6060f1SDimitry Andric } 1024fe6060f1SDimitry Andric 1025fe6060f1SDimitry Andric uint64_t TSFlags = MI.getDesc().TSFlags; 1026fe6060f1SDimitry Andric if (RISCVII::hasSEWOp(TSFlags)) { 1027fe6060f1SDimitry Andric VSETVLIInfo NewInfo = computeInfoForInstr(MI, TSFlags, MRI); 1028fe6060f1SDimitry Andric if (RISCVII::hasVLOp(TSFlags)) { 1029349cc55cSDimitry Andric unsigned Offset = 2; 1030349cc55cSDimitry Andric if (RISCVII::hasVecPolicyOp(TSFlags)) 1031349cc55cSDimitry Andric Offset = 3; 1032349cc55cSDimitry Andric MachineOperand &VLOp = 1033349cc55cSDimitry Andric MI.getOperand(MI.getNumExplicitOperands() - Offset); 1034fe6060f1SDimitry Andric if (VLOp.isReg()) { 1035fe6060f1SDimitry Andric // Erase the AVL operand from the instruction. 1036fe6060f1SDimitry Andric VLOp.setReg(RISCV::NoRegister); 1037fe6060f1SDimitry Andric VLOp.setIsKill(false); 1038fe6060f1SDimitry Andric } 1039fe6060f1SDimitry Andric MI.addOperand(MachineOperand::CreateReg(RISCV::VL, /*isDef*/ false, 1040fe6060f1SDimitry Andric /*isImp*/ true)); 1041fe6060f1SDimitry Andric } 1042fe6060f1SDimitry Andric MI.addOperand(MachineOperand::CreateReg(RISCV::VTYPE, /*isDef*/ false, 1043fe6060f1SDimitry Andric /*isImp*/ true)); 1044fe6060f1SDimitry Andric 1045fe6060f1SDimitry Andric if (!CurInfo.isValid()) { 1046fe6060f1SDimitry Andric // We haven't found any vector instructions or VL/VTYPE changes yet, 1047fe6060f1SDimitry Andric // use the predecessor information. 1048fe6060f1SDimitry Andric assert(BlockInfo[MBB.getNumber()].Pred.isValid() && 1049fe6060f1SDimitry Andric "Expected a valid predecessor state."); 1050*d56accc7SDimitry Andric if (needVSETVLI(NewInfo, BlockInfo[MBB.getNumber()].Pred) && 1051fe6060f1SDimitry Andric needVSETVLIPHI(NewInfo, MBB)) { 1052fe6060f1SDimitry Andric insertVSETVLI(MBB, MI, NewInfo, BlockInfo[MBB.getNumber()].Pred); 1053fe6060f1SDimitry Andric CurInfo = NewInfo; 1054fe6060f1SDimitry Andric } 1055fe6060f1SDimitry Andric } else { 1056fe6060f1SDimitry Andric // If this instruction isn't compatible with the previous VL/VTYPE 1057fe6060f1SDimitry Andric // we need to insert a VSETVLI. 1058349cc55cSDimitry Andric // If this is a unit-stride or strided load/store, we may be able to use 1059349cc55cSDimitry Andric // the EMUL=(EEW/SEW)*LMUL relationship to avoid changing vtype. 1060349cc55cSDimitry Andric // NOTE: We can't use predecessor information for the store. We must 1061349cc55cSDimitry Andric // treat it the same as the first phase so that we produce the correct 1062349cc55cSDimitry Andric // vl/vtype for succesor blocks. 1063349cc55cSDimitry Andric if (!canSkipVSETVLIForLoadStore(MI, NewInfo, CurInfo) && 1064349cc55cSDimitry Andric needVSETVLI(NewInfo, CurInfo)) { 1065349cc55cSDimitry Andric // If the previous VL/VTYPE is set by VSETVLI and do not use, Merge it 1066349cc55cSDimitry Andric // with current VL/VTYPE. 1067349cc55cSDimitry Andric bool NeedInsertVSETVLI = true; 1068349cc55cSDimitry Andric if (PrevVSETVLIMI) { 1069349cc55cSDimitry Andric bool HasSameAVL = 1070349cc55cSDimitry Andric CurInfo.hasSameAVL(NewInfo) || 1071349cc55cSDimitry Andric (NewInfo.hasAVLReg() && NewInfo.getAVLReg().isVirtual() && 1072349cc55cSDimitry Andric NewInfo.getAVLReg() == PrevVSETVLIMI->getOperand(0).getReg()); 1073349cc55cSDimitry Andric // If these two VSETVLI have the same AVL and the same VLMAX, 1074349cc55cSDimitry Andric // we could merge these two VSETVLI. 1075349cc55cSDimitry Andric if (HasSameAVL && 1076349cc55cSDimitry Andric CurInfo.getSEWLMULRatio() == NewInfo.getSEWLMULRatio()) { 1077349cc55cSDimitry Andric PrevVSETVLIMI->getOperand(2).setImm(NewInfo.encodeVTYPE()); 1078349cc55cSDimitry Andric NeedInsertVSETVLI = false; 1079349cc55cSDimitry Andric } 108004eeddc0SDimitry Andric if (isScalarMoveInstr(MI) && 108104eeddc0SDimitry Andric ((CurInfo.hasNonZeroAVL() && NewInfo.hasNonZeroAVL()) || 108204eeddc0SDimitry Andric (CurInfo.hasZeroAVL() && NewInfo.hasZeroAVL())) && 108304eeddc0SDimitry Andric NewInfo.hasSameVLMAX(CurInfo)) { 108404eeddc0SDimitry Andric PrevVSETVLIMI->getOperand(2).setImm(NewInfo.encodeVTYPE()); 108504eeddc0SDimitry Andric NeedInsertVSETVLI = false; 108604eeddc0SDimitry Andric } 1087349cc55cSDimitry Andric } 1088349cc55cSDimitry Andric if (NeedInsertVSETVLI) 1089fe6060f1SDimitry Andric insertVSETVLI(MBB, MI, NewInfo, CurInfo); 1090fe6060f1SDimitry Andric CurInfo = NewInfo; 1091fe6060f1SDimitry Andric } 1092fe6060f1SDimitry Andric } 1093349cc55cSDimitry Andric PrevVSETVLIMI = nullptr; 1094fe6060f1SDimitry Andric } 1095fe6060f1SDimitry Andric 1096fe6060f1SDimitry Andric // If this is something updates VL/VTYPE that we don't know about, set 1097fe6060f1SDimitry Andric // the state to unknown. 1098fe6060f1SDimitry Andric if (MI.isCall() || MI.isInlineAsm() || MI.modifiesRegister(RISCV::VL) || 1099fe6060f1SDimitry Andric MI.modifiesRegister(RISCV::VTYPE)) { 1100fe6060f1SDimitry Andric CurInfo = VSETVLIInfo::getUnknown(); 1101349cc55cSDimitry Andric PrevVSETVLIMI = nullptr; 1102fe6060f1SDimitry Andric } 1103*d56accc7SDimitry Andric 1104*d56accc7SDimitry Andric // If we reach the end of the block and our current info doesn't match the 1105*d56accc7SDimitry Andric // expected info, insert a vsetvli to correct. 1106*d56accc7SDimitry Andric if (MI.isTerminator()) { 1107*d56accc7SDimitry Andric const VSETVLIInfo &ExitInfo = BlockInfo[MBB.getNumber()].Exit; 1108*d56accc7SDimitry Andric if (CurInfo.isValid() && ExitInfo.isValid() && !ExitInfo.isUnknown() && 1109*d56accc7SDimitry Andric CurInfo != ExitInfo) { 1110*d56accc7SDimitry Andric insertVSETVLI(MBB, MI, ExitInfo, CurInfo); 1111*d56accc7SDimitry Andric CurInfo = ExitInfo; 1112*d56accc7SDimitry Andric } 1113*d56accc7SDimitry Andric } 1114fe6060f1SDimitry Andric } 1115fe6060f1SDimitry Andric } 1116fe6060f1SDimitry Andric 1117fe6060f1SDimitry Andric bool RISCVInsertVSETVLI::runOnMachineFunction(MachineFunction &MF) { 1118fe6060f1SDimitry Andric // Skip if the vector extension is not enabled. 1119fe6060f1SDimitry Andric const RISCVSubtarget &ST = MF.getSubtarget<RISCVSubtarget>(); 1120349cc55cSDimitry Andric if (!ST.hasVInstructions()) 1121fe6060f1SDimitry Andric return false; 1122fe6060f1SDimitry Andric 1123fe6060f1SDimitry Andric TII = ST.getInstrInfo(); 1124fe6060f1SDimitry Andric MRI = &MF.getRegInfo(); 1125fe6060f1SDimitry Andric 1126fe6060f1SDimitry Andric assert(BlockInfo.empty() && "Expect empty block infos"); 1127fe6060f1SDimitry Andric BlockInfo.resize(MF.getNumBlockIDs()); 1128fe6060f1SDimitry Andric 1129fe6060f1SDimitry Andric bool HaveVectorOp = false; 1130fe6060f1SDimitry Andric 1131fe6060f1SDimitry Andric // Phase 1 - determine how VL/VTYPE are affected by the each block. 1132fe6060f1SDimitry Andric for (const MachineBasicBlock &MBB : MF) 1133fe6060f1SDimitry Andric HaveVectorOp |= computeVLVTYPEChanges(MBB); 1134fe6060f1SDimitry Andric 1135fe6060f1SDimitry Andric // If we didn't find any instructions that need VSETVLI, we're done. 1136fe6060f1SDimitry Andric if (HaveVectorOp) { 1137fe6060f1SDimitry Andric // Phase 2 - determine the exit VL/VTYPE from each block. We add all 1138fe6060f1SDimitry Andric // blocks to the list here, but will also add any that need to be revisited 1139fe6060f1SDimitry Andric // during Phase 2 processing. 1140fe6060f1SDimitry Andric for (const MachineBasicBlock &MBB : MF) { 1141fe6060f1SDimitry Andric WorkList.push(&MBB); 1142fe6060f1SDimitry Andric BlockInfo[MBB.getNumber()].InQueue = true; 1143fe6060f1SDimitry Andric } 1144fe6060f1SDimitry Andric while (!WorkList.empty()) { 1145fe6060f1SDimitry Andric const MachineBasicBlock &MBB = *WorkList.front(); 1146fe6060f1SDimitry Andric WorkList.pop(); 1147fe6060f1SDimitry Andric computeIncomingVLVTYPE(MBB); 1148fe6060f1SDimitry Andric } 1149fe6060f1SDimitry Andric 1150fe6060f1SDimitry Andric // Phase 3 - add any vsetvli instructions needed in the block. Use the 1151fe6060f1SDimitry Andric // Phase 2 information to avoid adding vsetvlis before the first vector 1152fe6060f1SDimitry Andric // instruction in the block if the VL/VTYPE is satisfied by its 1153fe6060f1SDimitry Andric // predecessors. 1154fe6060f1SDimitry Andric for (MachineBasicBlock &MBB : MF) 1155fe6060f1SDimitry Andric emitVSETVLIs(MBB); 1156fe6060f1SDimitry Andric } 1157fe6060f1SDimitry Andric 1158fe6060f1SDimitry Andric BlockInfo.clear(); 1159fe6060f1SDimitry Andric 1160fe6060f1SDimitry Andric return HaveVectorOp; 1161fe6060f1SDimitry Andric } 1162fe6060f1SDimitry Andric 1163fe6060f1SDimitry Andric /// Returns an instance of the Insert VSETVLI pass. 1164fe6060f1SDimitry Andric FunctionPass *llvm::createRISCVInsertVSETVLIPass() { 1165fe6060f1SDimitry Andric return new RISCVInsertVSETVLI(); 1166fe6060f1SDimitry Andric } 1167