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; 62*04eeddc0SDimitry 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), 68*04eeddc0SDimitry 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 } 100*04eeddc0SDimitry Andric bool hasZeroAVL() const { 101*04eeddc0SDimitry Andric if (hasAVLImm()) 102*04eeddc0SDimitry Andric return getAVLImm() == 0; 103*04eeddc0SDimitry Andric return false; 104*04eeddc0SDimitry Andric } 105*04eeddc0SDimitry Andric bool hasNonZeroAVL() const { 106*04eeddc0SDimitry Andric if (hasAVLImm()) 107*04eeddc0SDimitry Andric return getAVLImm() > 0; 108*04eeddc0SDimitry Andric if (hasAVLReg()) 109*04eeddc0SDimitry Andric return getAVLReg() == RISCV::X0; 110*04eeddc0SDimitry Andric return false; 111*04eeddc0SDimitry 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, 136*04eeddc0SDimitry 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; 145*04eeddc0SDimitry 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 156*04eeddc0SDimitry Andric bool hasSameSEW(const VSETVLIInfo &Other) const { 157*04eeddc0SDimitry Andric assert(isValid() && Other.isValid() && 158*04eeddc0SDimitry Andric "Can't compare invalid VSETVLIInfos"); 159*04eeddc0SDimitry Andric assert(!isUnknown() && !Other.isUnknown() && 160*04eeddc0SDimitry Andric "Can't compare VTYPE in unknown state"); 161*04eeddc0SDimitry Andric assert(!SEWLMULRatioOnly && !Other.SEWLMULRatioOnly && 162*04eeddc0SDimitry Andric "Can't compare when only LMUL/SEW ratio is valid."); 163*04eeddc0SDimitry Andric return SEW == Other.SEW; 164*04eeddc0SDimitry Andric } 165*04eeddc0SDimitry 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 205*04eeddc0SDimitry Andric bool hasSamePolicy(const VSETVLIInfo &Other) const { 206*04eeddc0SDimitry Andric assert(isValid() && Other.isValid() && 207*04eeddc0SDimitry Andric "Can't compare invalid VSETVLIInfos"); 208*04eeddc0SDimitry Andric assert(!isUnknown() && !Other.isUnknown() && 209*04eeddc0SDimitry Andric "Can't compare VTYPE in unknown state"); 210*04eeddc0SDimitry Andric return TailAgnostic == Other.TailAgnostic && 211*04eeddc0SDimitry Andric MaskAgnostic == Other.MaskAgnostic; 212*04eeddc0SDimitry Andric } 213*04eeddc0SDimitry 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 258*04eeddc0SDimitry Andric // For vmv.s.x and vfmv.s.f, there is only two behaviors, VL = 0 and VL > 0. 259*04eeddc0SDimitry Andric // So it's compatible when we could make sure that both VL be the same 260*04eeddc0SDimitry Andric // situation. 261*04eeddc0SDimitry Andric if (!Strict && InstrInfo.ScalarMovOp && InstrInfo.hasAVLImm() && 262*04eeddc0SDimitry Andric ((hasNonZeroAVL() && InstrInfo.hasNonZeroAVL()) || 263*04eeddc0SDimitry Andric (hasZeroAVL() && InstrInfo.hasZeroAVL())) && 264*04eeddc0SDimitry Andric hasSameSEW(InstrInfo) && hasSamePolicy(InstrInfo)) 265*04eeddc0SDimitry Andric return true; 266*04eeddc0SDimitry 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 337fe6060f1SDimitry Andric // Calculate the VSETVLIInfo visible to a block assuming this and Other are 338fe6060f1SDimitry Andric // both predecessors. 339fe6060f1SDimitry Andric VSETVLIInfo intersect(const VSETVLIInfo &Other) const { 340fe6060f1SDimitry Andric // If the new value isn't valid, ignore it. 341fe6060f1SDimitry Andric if (!Other.isValid()) 342fe6060f1SDimitry Andric return *this; 343fe6060f1SDimitry Andric 344fe6060f1SDimitry Andric // If this value isn't valid, this must be the first predecessor, use it. 345fe6060f1SDimitry Andric if (!isValid()) 346fe6060f1SDimitry Andric return Other; 347fe6060f1SDimitry Andric 348fe6060f1SDimitry Andric // If either is unknown, the result is unknown. 349fe6060f1SDimitry Andric if (isUnknown() || Other.isUnknown()) 350fe6060f1SDimitry Andric return VSETVLIInfo::getUnknown(); 351fe6060f1SDimitry Andric 352fe6060f1SDimitry Andric // If we have an exact, match return this. 353fe6060f1SDimitry Andric if (*this == Other) 354fe6060f1SDimitry Andric return *this; 355fe6060f1SDimitry Andric 356fe6060f1SDimitry Andric // Not an exact match, but maybe the AVL and VLMAX are the same. If so, 357fe6060f1SDimitry Andric // return an SEW/LMUL ratio only value. 358fe6060f1SDimitry Andric if (hasSameAVL(Other) && hasSameVLMAX(Other)) { 359fe6060f1SDimitry Andric VSETVLIInfo MergeInfo = *this; 360fe6060f1SDimitry Andric MergeInfo.SEWLMULRatioOnly = true; 361fe6060f1SDimitry Andric return MergeInfo; 362fe6060f1SDimitry Andric } 363fe6060f1SDimitry Andric 364fe6060f1SDimitry Andric // Otherwise the result is unknown. 365fe6060f1SDimitry Andric return VSETVLIInfo::getUnknown(); 366fe6060f1SDimitry Andric } 367fe6060f1SDimitry Andric 368fe6060f1SDimitry Andric // Calculate the VSETVLIInfo visible at the end of the block assuming this 369fe6060f1SDimitry Andric // is the predecessor value, and Other is change for this block. 370fe6060f1SDimitry Andric VSETVLIInfo merge(const VSETVLIInfo &Other) const { 371fe6060f1SDimitry Andric assert(isValid() && "Can only merge with a valid VSETVLInfo"); 372fe6060f1SDimitry Andric 373fe6060f1SDimitry Andric // Nothing changed from the predecessor, keep it. 374fe6060f1SDimitry Andric if (!Other.isValid()) 375fe6060f1SDimitry Andric return *this; 376fe6060f1SDimitry Andric 377fe6060f1SDimitry Andric // If the change is compatible with the input, we won't create a VSETVLI 378fe6060f1SDimitry Andric // and should keep the predecessor. 379349cc55cSDimitry Andric if (isCompatible(Other, /*Strict*/ true)) 380fe6060f1SDimitry Andric return *this; 381fe6060f1SDimitry Andric 382fe6060f1SDimitry Andric // Otherwise just use whatever is in this block. 383fe6060f1SDimitry Andric return Other; 384fe6060f1SDimitry Andric } 385fe6060f1SDimitry Andric }; 386fe6060f1SDimitry Andric 387fe6060f1SDimitry Andric struct BlockData { 388fe6060f1SDimitry Andric // The VSETVLIInfo that represents the net changes to the VL/VTYPE registers 389fe6060f1SDimitry Andric // made by this block. Calculated in Phase 1. 390fe6060f1SDimitry Andric VSETVLIInfo Change; 391fe6060f1SDimitry Andric 392fe6060f1SDimitry Andric // The VSETVLIInfo that represents the VL/VTYPE settings on exit from this 393fe6060f1SDimitry Andric // block. Calculated in Phase 2. 394fe6060f1SDimitry Andric VSETVLIInfo Exit; 395fe6060f1SDimitry Andric 396fe6060f1SDimitry Andric // The VSETVLIInfo that represents the VL/VTYPE settings from all predecessor 397fe6060f1SDimitry Andric // blocks. Calculated in Phase 2, and used by Phase 3. 398fe6060f1SDimitry Andric VSETVLIInfo Pred; 399fe6060f1SDimitry Andric 400fe6060f1SDimitry Andric // Keeps track of whether the block is already in the queue. 401fe6060f1SDimitry Andric bool InQueue = false; 402fe6060f1SDimitry Andric 403fe6060f1SDimitry Andric BlockData() {} 404fe6060f1SDimitry Andric }; 405fe6060f1SDimitry Andric 406fe6060f1SDimitry Andric class RISCVInsertVSETVLI : public MachineFunctionPass { 407fe6060f1SDimitry Andric const TargetInstrInfo *TII; 408fe6060f1SDimitry Andric MachineRegisterInfo *MRI; 409fe6060f1SDimitry Andric 410fe6060f1SDimitry Andric std::vector<BlockData> BlockInfo; 411fe6060f1SDimitry Andric std::queue<const MachineBasicBlock *> WorkList; 412fe6060f1SDimitry Andric 413fe6060f1SDimitry Andric public: 414fe6060f1SDimitry Andric static char ID; 415fe6060f1SDimitry Andric 416fe6060f1SDimitry Andric RISCVInsertVSETVLI() : MachineFunctionPass(ID) { 417fe6060f1SDimitry Andric initializeRISCVInsertVSETVLIPass(*PassRegistry::getPassRegistry()); 418fe6060f1SDimitry Andric } 419fe6060f1SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 420fe6060f1SDimitry Andric 421fe6060f1SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 422fe6060f1SDimitry Andric AU.setPreservesCFG(); 423fe6060f1SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 424fe6060f1SDimitry Andric } 425fe6060f1SDimitry Andric 426fe6060f1SDimitry Andric StringRef getPassName() const override { return RISCV_INSERT_VSETVLI_NAME; } 427fe6060f1SDimitry Andric 428fe6060f1SDimitry Andric private: 429fe6060f1SDimitry Andric bool needVSETVLI(const VSETVLIInfo &Require, const VSETVLIInfo &CurInfo); 430fe6060f1SDimitry Andric bool needVSETVLIPHI(const VSETVLIInfo &Require, const MachineBasicBlock &MBB); 431fe6060f1SDimitry Andric void insertVSETVLI(MachineBasicBlock &MBB, MachineInstr &MI, 432fe6060f1SDimitry Andric const VSETVLIInfo &Info, const VSETVLIInfo &PrevInfo); 433fe6060f1SDimitry Andric 434fe6060f1SDimitry Andric bool computeVLVTYPEChanges(const MachineBasicBlock &MBB); 435fe6060f1SDimitry Andric void computeIncomingVLVTYPE(const MachineBasicBlock &MBB); 436fe6060f1SDimitry Andric void emitVSETVLIs(MachineBasicBlock &MBB); 437fe6060f1SDimitry Andric }; 438fe6060f1SDimitry Andric 439fe6060f1SDimitry Andric } // end anonymous namespace 440fe6060f1SDimitry Andric 441fe6060f1SDimitry Andric char RISCVInsertVSETVLI::ID = 0; 442fe6060f1SDimitry Andric 443fe6060f1SDimitry Andric INITIALIZE_PASS(RISCVInsertVSETVLI, DEBUG_TYPE, RISCV_INSERT_VSETVLI_NAME, 444fe6060f1SDimitry Andric false, false) 445fe6060f1SDimitry Andric 446fe6060f1SDimitry Andric static MachineInstr *elideCopies(MachineInstr *MI, 447fe6060f1SDimitry Andric const MachineRegisterInfo *MRI) { 448fe6060f1SDimitry Andric while (true) { 449fe6060f1SDimitry Andric if (!MI->isFullCopy()) 450fe6060f1SDimitry Andric return MI; 451fe6060f1SDimitry Andric if (!Register::isVirtualRegister(MI->getOperand(1).getReg())) 452fe6060f1SDimitry Andric return nullptr; 453fe6060f1SDimitry Andric MI = MRI->getVRegDef(MI->getOperand(1).getReg()); 454fe6060f1SDimitry Andric if (!MI) 455fe6060f1SDimitry Andric return nullptr; 456fe6060f1SDimitry Andric } 457fe6060f1SDimitry Andric } 458fe6060f1SDimitry Andric 459*04eeddc0SDimitry Andric static bool isScalarMoveInstr(const MachineInstr &MI) { 460*04eeddc0SDimitry Andric switch (MI.getOpcode()) { 461*04eeddc0SDimitry Andric default: 462*04eeddc0SDimitry Andric return false; 463*04eeddc0SDimitry Andric case RISCV::PseudoVMV_S_X_M1: 464*04eeddc0SDimitry Andric case RISCV::PseudoVMV_S_X_M2: 465*04eeddc0SDimitry Andric case RISCV::PseudoVMV_S_X_M4: 466*04eeddc0SDimitry Andric case RISCV::PseudoVMV_S_X_M8: 467*04eeddc0SDimitry Andric case RISCV::PseudoVMV_S_X_MF2: 468*04eeddc0SDimitry Andric case RISCV::PseudoVMV_S_X_MF4: 469*04eeddc0SDimitry Andric case RISCV::PseudoVMV_S_X_MF8: 470*04eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F16_M1: 471*04eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F16_M2: 472*04eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F16_M4: 473*04eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F16_M8: 474*04eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F16_MF2: 475*04eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F16_MF4: 476*04eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F32_M1: 477*04eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F32_M2: 478*04eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F32_M4: 479*04eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F32_M8: 480*04eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F32_MF2: 481*04eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F64_M1: 482*04eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F64_M2: 483*04eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F64_M4: 484*04eeddc0SDimitry Andric case RISCV::PseudoVFMV_S_F64_M8: 485*04eeddc0SDimitry Andric return true; 486*04eeddc0SDimitry Andric } 487*04eeddc0SDimitry Andric } 488*04eeddc0SDimitry Andric 489fe6060f1SDimitry Andric static VSETVLIInfo computeInfoForInstr(const MachineInstr &MI, uint64_t TSFlags, 490fe6060f1SDimitry Andric const MachineRegisterInfo *MRI) { 491fe6060f1SDimitry Andric VSETVLIInfo InstrInfo; 492fe6060f1SDimitry Andric unsigned NumOperands = MI.getNumExplicitOperands(); 493349cc55cSDimitry Andric bool HasPolicy = RISCVII::hasVecPolicyOp(TSFlags); 494fe6060f1SDimitry Andric 495fe6060f1SDimitry Andric // Default to tail agnostic unless the destination is tied to a source. 496fe6060f1SDimitry Andric // Unless the source is undef. In that case the user would have some control 497fe6060f1SDimitry Andric // over the tail values. Some pseudo instructions force a tail agnostic policy 498fe6060f1SDimitry Andric // despite having a tied def. 499fe6060f1SDimitry Andric bool ForceTailAgnostic = RISCVII::doesForceTailAgnostic(TSFlags); 500fe6060f1SDimitry Andric bool TailAgnostic = true; 501349cc55cSDimitry Andric // If the instruction has policy argument, use the argument. 502349cc55cSDimitry Andric if (HasPolicy) { 503349cc55cSDimitry Andric const MachineOperand &Op = MI.getOperand(MI.getNumExplicitOperands() - 1); 504349cc55cSDimitry Andric TailAgnostic = Op.getImm() & 0x1; 505349cc55cSDimitry Andric } 506349cc55cSDimitry Andric 507fe6060f1SDimitry Andric unsigned UseOpIdx; 508349cc55cSDimitry Andric if (!(ForceTailAgnostic || (HasPolicy && TailAgnostic)) && 509349cc55cSDimitry Andric MI.isRegTiedToUseOperand(0, &UseOpIdx)) { 510fe6060f1SDimitry Andric TailAgnostic = false; 511fe6060f1SDimitry Andric // If the tied operand is an IMPLICIT_DEF we can keep TailAgnostic. 512fe6060f1SDimitry Andric const MachineOperand &UseMO = MI.getOperand(UseOpIdx); 513fe6060f1SDimitry Andric MachineInstr *UseMI = MRI->getVRegDef(UseMO.getReg()); 514fe6060f1SDimitry Andric if (UseMI) { 515fe6060f1SDimitry Andric UseMI = elideCopies(UseMI, MRI); 516fe6060f1SDimitry Andric if (UseMI && UseMI->isImplicitDef()) 517fe6060f1SDimitry Andric TailAgnostic = true; 518fe6060f1SDimitry Andric } 519fe6060f1SDimitry Andric } 520fe6060f1SDimitry Andric 521349cc55cSDimitry Andric // Remove the tail policy so we can find the SEW and VL. 522349cc55cSDimitry Andric if (HasPolicy) 523349cc55cSDimitry Andric --NumOperands; 524349cc55cSDimitry Andric 525349cc55cSDimitry Andric RISCVII::VLMUL VLMul = RISCVII::getLMul(TSFlags); 526349cc55cSDimitry Andric 527349cc55cSDimitry Andric unsigned Log2SEW = MI.getOperand(NumOperands - 1).getImm(); 528349cc55cSDimitry Andric // A Log2SEW of 0 is an operation on mask registers only. 529349cc55cSDimitry Andric bool MaskRegOp = Log2SEW == 0; 530349cc55cSDimitry Andric unsigned SEW = Log2SEW ? 1 << Log2SEW : 8; 531349cc55cSDimitry Andric assert(RISCVVType::isValidSEW(SEW) && "Unexpected SEW"); 532349cc55cSDimitry Andric 533349cc55cSDimitry Andric // If there are no explicit defs, this is a store instruction which can 534349cc55cSDimitry Andric // ignore the tail and mask policies. 535349cc55cSDimitry Andric bool StoreOp = MI.getNumExplicitDefs() == 0; 536*04eeddc0SDimitry Andric bool ScalarMovOp = isScalarMoveInstr(MI); 537349cc55cSDimitry Andric 538fe6060f1SDimitry Andric if (RISCVII::hasVLOp(TSFlags)) { 539349cc55cSDimitry Andric const MachineOperand &VLOp = MI.getOperand(NumOperands - 2); 540349cc55cSDimitry Andric if (VLOp.isImm()) { 541349cc55cSDimitry Andric int64_t Imm = VLOp.getImm(); 542349cc55cSDimitry Andric // Conver the VLMax sentintel to X0 register. 543349cc55cSDimitry Andric if (Imm == RISCV::VLMaxSentinel) 544349cc55cSDimitry Andric InstrInfo.setAVLReg(RISCV::X0); 545fe6060f1SDimitry Andric else 546349cc55cSDimitry Andric InstrInfo.setAVLImm(Imm); 547349cc55cSDimitry Andric } else { 548fe6060f1SDimitry Andric InstrInfo.setAVLReg(VLOp.getReg()); 549349cc55cSDimitry Andric } 550fe6060f1SDimitry Andric } else 551fe6060f1SDimitry Andric InstrInfo.setAVLReg(RISCV::NoRegister); 552fe6060f1SDimitry Andric InstrInfo.setVTYPE(VLMul, SEW, /*TailAgnostic*/ TailAgnostic, 553*04eeddc0SDimitry Andric /*MaskAgnostic*/ false, MaskRegOp, StoreOp, ScalarMovOp); 554fe6060f1SDimitry Andric 555fe6060f1SDimitry Andric return InstrInfo; 556fe6060f1SDimitry Andric } 557fe6060f1SDimitry Andric 558fe6060f1SDimitry Andric void RISCVInsertVSETVLI::insertVSETVLI(MachineBasicBlock &MBB, MachineInstr &MI, 559fe6060f1SDimitry Andric const VSETVLIInfo &Info, 560fe6060f1SDimitry Andric const VSETVLIInfo &PrevInfo) { 561fe6060f1SDimitry Andric DebugLoc DL = MI.getDebugLoc(); 562fe6060f1SDimitry Andric 563fe6060f1SDimitry Andric // Use X0, X0 form if the AVL is the same and the SEW+LMUL gives the same 564fe6060f1SDimitry Andric // VLMAX. 565fe6060f1SDimitry Andric if (PrevInfo.isValid() && !PrevInfo.isUnknown() && 566fe6060f1SDimitry Andric Info.hasSameAVL(PrevInfo) && Info.hasSameVLMAX(PrevInfo)) { 567349cc55cSDimitry Andric BuildMI(MBB, MI, DL, TII->get(RISCV::PseudoVSETVLIX0)) 568fe6060f1SDimitry Andric .addReg(RISCV::X0, RegState::Define | RegState::Dead) 569fe6060f1SDimitry Andric .addReg(RISCV::X0, RegState::Kill) 570fe6060f1SDimitry Andric .addImm(Info.encodeVTYPE()) 571fe6060f1SDimitry Andric .addReg(RISCV::VL, RegState::Implicit); 572fe6060f1SDimitry Andric return; 573fe6060f1SDimitry Andric } 574fe6060f1SDimitry Andric 575fe6060f1SDimitry Andric if (Info.hasAVLImm()) { 576fe6060f1SDimitry Andric BuildMI(MBB, MI, DL, TII->get(RISCV::PseudoVSETIVLI)) 577fe6060f1SDimitry Andric .addReg(RISCV::X0, RegState::Define | RegState::Dead) 578fe6060f1SDimitry Andric .addImm(Info.getAVLImm()) 579fe6060f1SDimitry Andric .addImm(Info.encodeVTYPE()); 580fe6060f1SDimitry Andric return; 581fe6060f1SDimitry Andric } 582fe6060f1SDimitry Andric 583fe6060f1SDimitry Andric Register AVLReg = Info.getAVLReg(); 584fe6060f1SDimitry Andric if (AVLReg == RISCV::NoRegister) { 585fe6060f1SDimitry Andric // We can only use x0, x0 if there's no chance of the vtype change causing 586fe6060f1SDimitry Andric // the previous vl to become invalid. 587fe6060f1SDimitry Andric if (PrevInfo.isValid() && !PrevInfo.isUnknown() && 588fe6060f1SDimitry Andric Info.hasSameVLMAX(PrevInfo)) { 589349cc55cSDimitry Andric BuildMI(MBB, MI, DL, TII->get(RISCV::PseudoVSETVLIX0)) 590fe6060f1SDimitry Andric .addReg(RISCV::X0, RegState::Define | RegState::Dead) 591fe6060f1SDimitry Andric .addReg(RISCV::X0, RegState::Kill) 592fe6060f1SDimitry Andric .addImm(Info.encodeVTYPE()) 593fe6060f1SDimitry Andric .addReg(RISCV::VL, RegState::Implicit); 594fe6060f1SDimitry Andric return; 595fe6060f1SDimitry Andric } 596fe6060f1SDimitry Andric // Otherwise use an AVL of 0 to avoid depending on previous vl. 597fe6060f1SDimitry Andric BuildMI(MBB, MI, DL, TII->get(RISCV::PseudoVSETIVLI)) 598fe6060f1SDimitry Andric .addReg(RISCV::X0, RegState::Define | RegState::Dead) 599fe6060f1SDimitry Andric .addImm(0) 600fe6060f1SDimitry Andric .addImm(Info.encodeVTYPE()); 601fe6060f1SDimitry Andric return; 602fe6060f1SDimitry Andric } 603fe6060f1SDimitry Andric 604349cc55cSDimitry Andric if (AVLReg.isVirtual()) 605349cc55cSDimitry Andric MRI->constrainRegClass(AVLReg, &RISCV::GPRNoX0RegClass); 606349cc55cSDimitry Andric 607349cc55cSDimitry Andric // Use X0 as the DestReg unless AVLReg is X0. We also need to change the 608349cc55cSDimitry Andric // opcode if the AVLReg is X0 as they have different register classes for 609349cc55cSDimitry Andric // the AVL operand. 610fe6060f1SDimitry Andric Register DestReg = RISCV::X0; 611349cc55cSDimitry Andric unsigned Opcode = RISCV::PseudoVSETVLI; 612349cc55cSDimitry Andric if (AVLReg == RISCV::X0) { 613fe6060f1SDimitry Andric DestReg = MRI->createVirtualRegister(&RISCV::GPRRegClass); 614349cc55cSDimitry Andric Opcode = RISCV::PseudoVSETVLIX0; 615349cc55cSDimitry Andric } 616349cc55cSDimitry Andric BuildMI(MBB, MI, DL, TII->get(Opcode)) 617fe6060f1SDimitry Andric .addReg(DestReg, RegState::Define | RegState::Dead) 618fe6060f1SDimitry Andric .addReg(AVLReg) 619fe6060f1SDimitry Andric .addImm(Info.encodeVTYPE()); 620fe6060f1SDimitry Andric } 621fe6060f1SDimitry Andric 622fe6060f1SDimitry Andric // Return a VSETVLIInfo representing the changes made by this VSETVLI or 623fe6060f1SDimitry Andric // VSETIVLI instruction. 624fe6060f1SDimitry Andric static VSETVLIInfo getInfoForVSETVLI(const MachineInstr &MI) { 625fe6060f1SDimitry Andric VSETVLIInfo NewInfo; 626349cc55cSDimitry Andric if (MI.getOpcode() == RISCV::PseudoVSETIVLI) { 627349cc55cSDimitry Andric NewInfo.setAVLImm(MI.getOperand(1).getImm()); 628349cc55cSDimitry Andric } else { 629349cc55cSDimitry Andric assert(MI.getOpcode() == RISCV::PseudoVSETVLI || 630349cc55cSDimitry Andric MI.getOpcode() == RISCV::PseudoVSETVLIX0); 631fe6060f1SDimitry Andric Register AVLReg = MI.getOperand(1).getReg(); 632fe6060f1SDimitry Andric assert((AVLReg != RISCV::X0 || MI.getOperand(0).getReg() != RISCV::X0) && 633fe6060f1SDimitry Andric "Can't handle X0, X0 vsetvli yet"); 634fe6060f1SDimitry Andric NewInfo.setAVLReg(AVLReg); 635fe6060f1SDimitry Andric } 636fe6060f1SDimitry Andric NewInfo.setVTYPE(MI.getOperand(2).getImm()); 637fe6060f1SDimitry Andric 638fe6060f1SDimitry Andric return NewInfo; 639fe6060f1SDimitry Andric } 640fe6060f1SDimitry Andric 641fe6060f1SDimitry Andric bool RISCVInsertVSETVLI::needVSETVLI(const VSETVLIInfo &Require, 642fe6060f1SDimitry Andric const VSETVLIInfo &CurInfo) { 643349cc55cSDimitry Andric if (CurInfo.isCompatible(Require, /*Strict*/ false)) 644fe6060f1SDimitry Andric return false; 645fe6060f1SDimitry Andric 646fe6060f1SDimitry Andric // We didn't find a compatible value. If our AVL is a virtual register, 647fe6060f1SDimitry Andric // it might be defined by a VSET(I)VLI. If it has the same VTYPE we need 648fe6060f1SDimitry Andric // and the last VL/VTYPE we observed is the same, we don't need a 649fe6060f1SDimitry Andric // VSETVLI here. 650fe6060f1SDimitry Andric if (!CurInfo.isUnknown() && Require.hasAVLReg() && 651fe6060f1SDimitry Andric Require.getAVLReg().isVirtual() && !CurInfo.hasSEWLMULRatioOnly() && 652349cc55cSDimitry Andric CurInfo.hasCompatibleVTYPE(Require, /*Strict*/ false)) { 653fe6060f1SDimitry Andric if (MachineInstr *DefMI = MRI->getVRegDef(Require.getAVLReg())) { 654fe6060f1SDimitry Andric if (DefMI->getOpcode() == RISCV::PseudoVSETVLI || 655349cc55cSDimitry Andric DefMI->getOpcode() == RISCV::PseudoVSETVLIX0 || 656fe6060f1SDimitry Andric DefMI->getOpcode() == RISCV::PseudoVSETIVLI) { 657fe6060f1SDimitry Andric VSETVLIInfo DefInfo = getInfoForVSETVLI(*DefMI); 658fe6060f1SDimitry Andric if (DefInfo.hasSameAVL(CurInfo) && DefInfo.hasSameVTYPE(CurInfo)) 659fe6060f1SDimitry Andric return false; 660fe6060f1SDimitry Andric } 661fe6060f1SDimitry Andric } 662fe6060f1SDimitry Andric } 663fe6060f1SDimitry Andric 664fe6060f1SDimitry Andric return true; 665fe6060f1SDimitry Andric } 666fe6060f1SDimitry Andric 667349cc55cSDimitry Andric bool canSkipVSETVLIForLoadStore(const MachineInstr &MI, 668349cc55cSDimitry Andric const VSETVLIInfo &Require, 669349cc55cSDimitry Andric const VSETVLIInfo &CurInfo) { 670349cc55cSDimitry Andric unsigned EEW; 671349cc55cSDimitry Andric switch (MI.getOpcode()) { 672349cc55cSDimitry Andric default: 673349cc55cSDimitry Andric return false; 674349cc55cSDimitry Andric case RISCV::PseudoVLE8_V_M1: 675349cc55cSDimitry Andric case RISCV::PseudoVLE8_V_M1_MASK: 676349cc55cSDimitry Andric case RISCV::PseudoVLE8_V_M2: 677349cc55cSDimitry Andric case RISCV::PseudoVLE8_V_M2_MASK: 678349cc55cSDimitry Andric case RISCV::PseudoVLE8_V_M4: 679349cc55cSDimitry Andric case RISCV::PseudoVLE8_V_M4_MASK: 680349cc55cSDimitry Andric case RISCV::PseudoVLE8_V_M8: 681349cc55cSDimitry Andric case RISCV::PseudoVLE8_V_M8_MASK: 682349cc55cSDimitry Andric case RISCV::PseudoVLE8_V_MF2: 683349cc55cSDimitry Andric case RISCV::PseudoVLE8_V_MF2_MASK: 684349cc55cSDimitry Andric case RISCV::PseudoVLE8_V_MF4: 685349cc55cSDimitry Andric case RISCV::PseudoVLE8_V_MF4_MASK: 686349cc55cSDimitry Andric case RISCV::PseudoVLE8_V_MF8: 687349cc55cSDimitry Andric case RISCV::PseudoVLE8_V_MF8_MASK: 688349cc55cSDimitry Andric case RISCV::PseudoVLSE8_V_M1: 689349cc55cSDimitry Andric case RISCV::PseudoVLSE8_V_M1_MASK: 690349cc55cSDimitry Andric case RISCV::PseudoVLSE8_V_M2: 691349cc55cSDimitry Andric case RISCV::PseudoVLSE8_V_M2_MASK: 692349cc55cSDimitry Andric case RISCV::PseudoVLSE8_V_M4: 693349cc55cSDimitry Andric case RISCV::PseudoVLSE8_V_M4_MASK: 694349cc55cSDimitry Andric case RISCV::PseudoVLSE8_V_M8: 695349cc55cSDimitry Andric case RISCV::PseudoVLSE8_V_M8_MASK: 696349cc55cSDimitry Andric case RISCV::PseudoVLSE8_V_MF2: 697349cc55cSDimitry Andric case RISCV::PseudoVLSE8_V_MF2_MASK: 698349cc55cSDimitry Andric case RISCV::PseudoVLSE8_V_MF4: 699349cc55cSDimitry Andric case RISCV::PseudoVLSE8_V_MF4_MASK: 700349cc55cSDimitry Andric case RISCV::PseudoVLSE8_V_MF8: 701349cc55cSDimitry Andric case RISCV::PseudoVLSE8_V_MF8_MASK: 702349cc55cSDimitry Andric case RISCV::PseudoVSE8_V_M1: 703349cc55cSDimitry Andric case RISCV::PseudoVSE8_V_M1_MASK: 704349cc55cSDimitry Andric case RISCV::PseudoVSE8_V_M2: 705349cc55cSDimitry Andric case RISCV::PseudoVSE8_V_M2_MASK: 706349cc55cSDimitry Andric case RISCV::PseudoVSE8_V_M4: 707349cc55cSDimitry Andric case RISCV::PseudoVSE8_V_M4_MASK: 708349cc55cSDimitry Andric case RISCV::PseudoVSE8_V_M8: 709349cc55cSDimitry Andric case RISCV::PseudoVSE8_V_M8_MASK: 710349cc55cSDimitry Andric case RISCV::PseudoVSE8_V_MF2: 711349cc55cSDimitry Andric case RISCV::PseudoVSE8_V_MF2_MASK: 712349cc55cSDimitry Andric case RISCV::PseudoVSE8_V_MF4: 713349cc55cSDimitry Andric case RISCV::PseudoVSE8_V_MF4_MASK: 714349cc55cSDimitry Andric case RISCV::PseudoVSE8_V_MF8: 715349cc55cSDimitry Andric case RISCV::PseudoVSE8_V_MF8_MASK: 716349cc55cSDimitry Andric case RISCV::PseudoVSSE8_V_M1: 717349cc55cSDimitry Andric case RISCV::PseudoVSSE8_V_M1_MASK: 718349cc55cSDimitry Andric case RISCV::PseudoVSSE8_V_M2: 719349cc55cSDimitry Andric case RISCV::PseudoVSSE8_V_M2_MASK: 720349cc55cSDimitry Andric case RISCV::PseudoVSSE8_V_M4: 721349cc55cSDimitry Andric case RISCV::PseudoVSSE8_V_M4_MASK: 722349cc55cSDimitry Andric case RISCV::PseudoVSSE8_V_M8: 723349cc55cSDimitry Andric case RISCV::PseudoVSSE8_V_M8_MASK: 724349cc55cSDimitry Andric case RISCV::PseudoVSSE8_V_MF2: 725349cc55cSDimitry Andric case RISCV::PseudoVSSE8_V_MF2_MASK: 726349cc55cSDimitry Andric case RISCV::PseudoVSSE8_V_MF4: 727349cc55cSDimitry Andric case RISCV::PseudoVSSE8_V_MF4_MASK: 728349cc55cSDimitry Andric case RISCV::PseudoVSSE8_V_MF8: 729349cc55cSDimitry Andric case RISCV::PseudoVSSE8_V_MF8_MASK: 730349cc55cSDimitry Andric EEW = 8; 731349cc55cSDimitry Andric break; 732349cc55cSDimitry Andric case RISCV::PseudoVLE16_V_M1: 733349cc55cSDimitry Andric case RISCV::PseudoVLE16_V_M1_MASK: 734349cc55cSDimitry Andric case RISCV::PseudoVLE16_V_M2: 735349cc55cSDimitry Andric case RISCV::PseudoVLE16_V_M2_MASK: 736349cc55cSDimitry Andric case RISCV::PseudoVLE16_V_M4: 737349cc55cSDimitry Andric case RISCV::PseudoVLE16_V_M4_MASK: 738349cc55cSDimitry Andric case RISCV::PseudoVLE16_V_M8: 739349cc55cSDimitry Andric case RISCV::PseudoVLE16_V_M8_MASK: 740349cc55cSDimitry Andric case RISCV::PseudoVLE16_V_MF2: 741349cc55cSDimitry Andric case RISCV::PseudoVLE16_V_MF2_MASK: 742349cc55cSDimitry Andric case RISCV::PseudoVLE16_V_MF4: 743349cc55cSDimitry Andric case RISCV::PseudoVLE16_V_MF4_MASK: 744349cc55cSDimitry Andric case RISCV::PseudoVLSE16_V_M1: 745349cc55cSDimitry Andric case RISCV::PseudoVLSE16_V_M1_MASK: 746349cc55cSDimitry Andric case RISCV::PseudoVLSE16_V_M2: 747349cc55cSDimitry Andric case RISCV::PseudoVLSE16_V_M2_MASK: 748349cc55cSDimitry Andric case RISCV::PseudoVLSE16_V_M4: 749349cc55cSDimitry Andric case RISCV::PseudoVLSE16_V_M4_MASK: 750349cc55cSDimitry Andric case RISCV::PseudoVLSE16_V_M8: 751349cc55cSDimitry Andric case RISCV::PseudoVLSE16_V_M8_MASK: 752349cc55cSDimitry Andric case RISCV::PseudoVLSE16_V_MF2: 753349cc55cSDimitry Andric case RISCV::PseudoVLSE16_V_MF2_MASK: 754349cc55cSDimitry Andric case RISCV::PseudoVLSE16_V_MF4: 755349cc55cSDimitry Andric case RISCV::PseudoVLSE16_V_MF4_MASK: 756349cc55cSDimitry Andric case RISCV::PseudoVSE16_V_M1: 757349cc55cSDimitry Andric case RISCV::PseudoVSE16_V_M1_MASK: 758349cc55cSDimitry Andric case RISCV::PseudoVSE16_V_M2: 759349cc55cSDimitry Andric case RISCV::PseudoVSE16_V_M2_MASK: 760349cc55cSDimitry Andric case RISCV::PseudoVSE16_V_M4: 761349cc55cSDimitry Andric case RISCV::PseudoVSE16_V_M4_MASK: 762349cc55cSDimitry Andric case RISCV::PseudoVSE16_V_M8: 763349cc55cSDimitry Andric case RISCV::PseudoVSE16_V_M8_MASK: 764349cc55cSDimitry Andric case RISCV::PseudoVSE16_V_MF2: 765349cc55cSDimitry Andric case RISCV::PseudoVSE16_V_MF2_MASK: 766349cc55cSDimitry Andric case RISCV::PseudoVSE16_V_MF4: 767349cc55cSDimitry Andric case RISCV::PseudoVSE16_V_MF4_MASK: 768349cc55cSDimitry Andric case RISCV::PseudoVSSE16_V_M1: 769349cc55cSDimitry Andric case RISCV::PseudoVSSE16_V_M1_MASK: 770349cc55cSDimitry Andric case RISCV::PseudoVSSE16_V_M2: 771349cc55cSDimitry Andric case RISCV::PseudoVSSE16_V_M2_MASK: 772349cc55cSDimitry Andric case RISCV::PseudoVSSE16_V_M4: 773349cc55cSDimitry Andric case RISCV::PseudoVSSE16_V_M4_MASK: 774349cc55cSDimitry Andric case RISCV::PseudoVSSE16_V_M8: 775349cc55cSDimitry Andric case RISCV::PseudoVSSE16_V_M8_MASK: 776349cc55cSDimitry Andric case RISCV::PseudoVSSE16_V_MF2: 777349cc55cSDimitry Andric case RISCV::PseudoVSSE16_V_MF2_MASK: 778349cc55cSDimitry Andric case RISCV::PseudoVSSE16_V_MF4: 779349cc55cSDimitry Andric case RISCV::PseudoVSSE16_V_MF4_MASK: 780349cc55cSDimitry Andric EEW = 16; 781349cc55cSDimitry Andric break; 782349cc55cSDimitry Andric case RISCV::PseudoVLE32_V_M1: 783349cc55cSDimitry Andric case RISCV::PseudoVLE32_V_M1_MASK: 784349cc55cSDimitry Andric case RISCV::PseudoVLE32_V_M2: 785349cc55cSDimitry Andric case RISCV::PseudoVLE32_V_M2_MASK: 786349cc55cSDimitry Andric case RISCV::PseudoVLE32_V_M4: 787349cc55cSDimitry Andric case RISCV::PseudoVLE32_V_M4_MASK: 788349cc55cSDimitry Andric case RISCV::PseudoVLE32_V_M8: 789349cc55cSDimitry Andric case RISCV::PseudoVLE32_V_M8_MASK: 790349cc55cSDimitry Andric case RISCV::PseudoVLE32_V_MF2: 791349cc55cSDimitry Andric case RISCV::PseudoVLE32_V_MF2_MASK: 792349cc55cSDimitry Andric case RISCV::PseudoVLSE32_V_M1: 793349cc55cSDimitry Andric case RISCV::PseudoVLSE32_V_M1_MASK: 794349cc55cSDimitry Andric case RISCV::PseudoVLSE32_V_M2: 795349cc55cSDimitry Andric case RISCV::PseudoVLSE32_V_M2_MASK: 796349cc55cSDimitry Andric case RISCV::PseudoVLSE32_V_M4: 797349cc55cSDimitry Andric case RISCV::PseudoVLSE32_V_M4_MASK: 798349cc55cSDimitry Andric case RISCV::PseudoVLSE32_V_M8: 799349cc55cSDimitry Andric case RISCV::PseudoVLSE32_V_M8_MASK: 800349cc55cSDimitry Andric case RISCV::PseudoVLSE32_V_MF2: 801349cc55cSDimitry Andric case RISCV::PseudoVLSE32_V_MF2_MASK: 802349cc55cSDimitry Andric case RISCV::PseudoVSE32_V_M1: 803349cc55cSDimitry Andric case RISCV::PseudoVSE32_V_M1_MASK: 804349cc55cSDimitry Andric case RISCV::PseudoVSE32_V_M2: 805349cc55cSDimitry Andric case RISCV::PseudoVSE32_V_M2_MASK: 806349cc55cSDimitry Andric case RISCV::PseudoVSE32_V_M4: 807349cc55cSDimitry Andric case RISCV::PseudoVSE32_V_M4_MASK: 808349cc55cSDimitry Andric case RISCV::PseudoVSE32_V_M8: 809349cc55cSDimitry Andric case RISCV::PseudoVSE32_V_M8_MASK: 810349cc55cSDimitry Andric case RISCV::PseudoVSE32_V_MF2: 811349cc55cSDimitry Andric case RISCV::PseudoVSE32_V_MF2_MASK: 812349cc55cSDimitry Andric case RISCV::PseudoVSSE32_V_M1: 813349cc55cSDimitry Andric case RISCV::PseudoVSSE32_V_M1_MASK: 814349cc55cSDimitry Andric case RISCV::PseudoVSSE32_V_M2: 815349cc55cSDimitry Andric case RISCV::PseudoVSSE32_V_M2_MASK: 816349cc55cSDimitry Andric case RISCV::PseudoVSSE32_V_M4: 817349cc55cSDimitry Andric case RISCV::PseudoVSSE32_V_M4_MASK: 818349cc55cSDimitry Andric case RISCV::PseudoVSSE32_V_M8: 819349cc55cSDimitry Andric case RISCV::PseudoVSSE32_V_M8_MASK: 820349cc55cSDimitry Andric case RISCV::PseudoVSSE32_V_MF2: 821349cc55cSDimitry Andric case RISCV::PseudoVSSE32_V_MF2_MASK: 822349cc55cSDimitry Andric EEW = 32; 823349cc55cSDimitry Andric break; 824349cc55cSDimitry Andric case RISCV::PseudoVLE64_V_M1: 825349cc55cSDimitry Andric case RISCV::PseudoVLE64_V_M1_MASK: 826349cc55cSDimitry Andric case RISCV::PseudoVLE64_V_M2: 827349cc55cSDimitry Andric case RISCV::PseudoVLE64_V_M2_MASK: 828349cc55cSDimitry Andric case RISCV::PseudoVLE64_V_M4: 829349cc55cSDimitry Andric case RISCV::PseudoVLE64_V_M4_MASK: 830349cc55cSDimitry Andric case RISCV::PseudoVLE64_V_M8: 831349cc55cSDimitry Andric case RISCV::PseudoVLE64_V_M8_MASK: 832349cc55cSDimitry Andric case RISCV::PseudoVLSE64_V_M1: 833349cc55cSDimitry Andric case RISCV::PseudoVLSE64_V_M1_MASK: 834349cc55cSDimitry Andric case RISCV::PseudoVLSE64_V_M2: 835349cc55cSDimitry Andric case RISCV::PseudoVLSE64_V_M2_MASK: 836349cc55cSDimitry Andric case RISCV::PseudoVLSE64_V_M4: 837349cc55cSDimitry Andric case RISCV::PseudoVLSE64_V_M4_MASK: 838349cc55cSDimitry Andric case RISCV::PseudoVLSE64_V_M8: 839349cc55cSDimitry Andric case RISCV::PseudoVLSE64_V_M8_MASK: 840349cc55cSDimitry Andric case RISCV::PseudoVSE64_V_M1: 841349cc55cSDimitry Andric case RISCV::PseudoVSE64_V_M1_MASK: 842349cc55cSDimitry Andric case RISCV::PseudoVSE64_V_M2: 843349cc55cSDimitry Andric case RISCV::PseudoVSE64_V_M2_MASK: 844349cc55cSDimitry Andric case RISCV::PseudoVSE64_V_M4: 845349cc55cSDimitry Andric case RISCV::PseudoVSE64_V_M4_MASK: 846349cc55cSDimitry Andric case RISCV::PseudoVSE64_V_M8: 847349cc55cSDimitry Andric case RISCV::PseudoVSE64_V_M8_MASK: 848349cc55cSDimitry Andric case RISCV::PseudoVSSE64_V_M1: 849349cc55cSDimitry Andric case RISCV::PseudoVSSE64_V_M1_MASK: 850349cc55cSDimitry Andric case RISCV::PseudoVSSE64_V_M2: 851349cc55cSDimitry Andric case RISCV::PseudoVSSE64_V_M2_MASK: 852349cc55cSDimitry Andric case RISCV::PseudoVSSE64_V_M4: 853349cc55cSDimitry Andric case RISCV::PseudoVSSE64_V_M4_MASK: 854349cc55cSDimitry Andric case RISCV::PseudoVSSE64_V_M8: 855349cc55cSDimitry Andric case RISCV::PseudoVSSE64_V_M8_MASK: 856349cc55cSDimitry Andric EEW = 64; 857349cc55cSDimitry Andric break; 858349cc55cSDimitry Andric } 859349cc55cSDimitry Andric 860349cc55cSDimitry Andric return CurInfo.isCompatibleWithLoadStoreEEW(EEW, Require); 861349cc55cSDimitry Andric } 862349cc55cSDimitry Andric 863fe6060f1SDimitry Andric bool RISCVInsertVSETVLI::computeVLVTYPEChanges(const MachineBasicBlock &MBB) { 864fe6060f1SDimitry Andric bool HadVectorOp = false; 865fe6060f1SDimitry Andric 866fe6060f1SDimitry Andric BlockData &BBInfo = BlockInfo[MBB.getNumber()]; 867fe6060f1SDimitry Andric for (const MachineInstr &MI : MBB) { 868fe6060f1SDimitry Andric // If this is an explicit VSETVLI or VSETIVLI, update our state. 869fe6060f1SDimitry Andric if (MI.getOpcode() == RISCV::PseudoVSETVLI || 870349cc55cSDimitry Andric MI.getOpcode() == RISCV::PseudoVSETVLIX0 || 871fe6060f1SDimitry Andric MI.getOpcode() == RISCV::PseudoVSETIVLI) { 872fe6060f1SDimitry Andric HadVectorOp = true; 873fe6060f1SDimitry Andric BBInfo.Change = getInfoForVSETVLI(MI); 874fe6060f1SDimitry Andric continue; 875fe6060f1SDimitry Andric } 876fe6060f1SDimitry Andric 877fe6060f1SDimitry Andric uint64_t TSFlags = MI.getDesc().TSFlags; 878fe6060f1SDimitry Andric if (RISCVII::hasSEWOp(TSFlags)) { 879fe6060f1SDimitry Andric HadVectorOp = true; 880fe6060f1SDimitry Andric 881fe6060f1SDimitry Andric VSETVLIInfo NewInfo = computeInfoForInstr(MI, TSFlags, MRI); 882fe6060f1SDimitry Andric 883fe6060f1SDimitry Andric if (!BBInfo.Change.isValid()) { 884fe6060f1SDimitry Andric BBInfo.Change = NewInfo; 885fe6060f1SDimitry Andric } else { 886fe6060f1SDimitry Andric // If this instruction isn't compatible with the previous VL/VTYPE 887fe6060f1SDimitry Andric // we need to insert a VSETVLI. 888349cc55cSDimitry Andric // If this is a unit-stride or strided load/store, we may be able to use 889349cc55cSDimitry Andric // the EMUL=(EEW/SEW)*LMUL relationship to avoid changing vtype. 890349cc55cSDimitry Andric // NOTE: We only do this if the vtype we're comparing against was 891349cc55cSDimitry Andric // created in this block. We need the first and third phase to treat 892349cc55cSDimitry Andric // the store the same way. 893349cc55cSDimitry Andric if (!canSkipVSETVLIForLoadStore(MI, NewInfo, BBInfo.Change) && 894349cc55cSDimitry Andric needVSETVLI(NewInfo, BBInfo.Change)) 895fe6060f1SDimitry Andric BBInfo.Change = NewInfo; 896fe6060f1SDimitry Andric } 897fe6060f1SDimitry Andric } 898fe6060f1SDimitry Andric 899fe6060f1SDimitry Andric // If this is something that updates VL/VTYPE that we don't know about, set 900fe6060f1SDimitry Andric // the state to unknown. 901fe6060f1SDimitry Andric if (MI.isCall() || MI.isInlineAsm() || MI.modifiesRegister(RISCV::VL) || 902fe6060f1SDimitry Andric MI.modifiesRegister(RISCV::VTYPE)) { 903fe6060f1SDimitry Andric BBInfo.Change = VSETVLIInfo::getUnknown(); 904fe6060f1SDimitry Andric } 905fe6060f1SDimitry Andric } 906fe6060f1SDimitry Andric 907fe6060f1SDimitry Andric // Initial exit state is whatever change we found in the block. 908fe6060f1SDimitry Andric BBInfo.Exit = BBInfo.Change; 909fe6060f1SDimitry Andric 910fe6060f1SDimitry Andric return HadVectorOp; 911fe6060f1SDimitry Andric } 912fe6060f1SDimitry Andric 913fe6060f1SDimitry Andric void RISCVInsertVSETVLI::computeIncomingVLVTYPE(const MachineBasicBlock &MBB) { 914fe6060f1SDimitry Andric BlockData &BBInfo = BlockInfo[MBB.getNumber()]; 915fe6060f1SDimitry Andric 916fe6060f1SDimitry Andric BBInfo.InQueue = false; 917fe6060f1SDimitry Andric 918fe6060f1SDimitry Andric VSETVLIInfo InInfo; 919fe6060f1SDimitry Andric if (MBB.pred_empty()) { 920fe6060f1SDimitry Andric // There are no predecessors, so use the default starting status. 921fe6060f1SDimitry Andric InInfo.setUnknown(); 922fe6060f1SDimitry Andric } else { 923fe6060f1SDimitry Andric for (MachineBasicBlock *P : MBB.predecessors()) 924fe6060f1SDimitry Andric InInfo = InInfo.intersect(BlockInfo[P->getNumber()].Exit); 925fe6060f1SDimitry Andric } 926fe6060f1SDimitry Andric 927fe6060f1SDimitry Andric // If we don't have any valid predecessor value, wait until we do. 928fe6060f1SDimitry Andric if (!InInfo.isValid()) 929fe6060f1SDimitry Andric return; 930fe6060f1SDimitry Andric 931fe6060f1SDimitry Andric BBInfo.Pred = InInfo; 932fe6060f1SDimitry Andric 933fe6060f1SDimitry Andric VSETVLIInfo TmpStatus = BBInfo.Pred.merge(BBInfo.Change); 934fe6060f1SDimitry Andric 935fe6060f1SDimitry Andric // If the new exit value matches the old exit value, we don't need to revisit 936fe6060f1SDimitry Andric // any blocks. 937fe6060f1SDimitry Andric if (BBInfo.Exit == TmpStatus) 938fe6060f1SDimitry Andric return; 939fe6060f1SDimitry Andric 940fe6060f1SDimitry Andric BBInfo.Exit = TmpStatus; 941fe6060f1SDimitry Andric 942fe6060f1SDimitry Andric // Add the successors to the work list so we can propagate the changed exit 943fe6060f1SDimitry Andric // status. 944fe6060f1SDimitry Andric for (MachineBasicBlock *S : MBB.successors()) 945fe6060f1SDimitry Andric if (!BlockInfo[S->getNumber()].InQueue) 946fe6060f1SDimitry Andric WorkList.push(S); 947fe6060f1SDimitry Andric } 948fe6060f1SDimitry Andric 949fe6060f1SDimitry Andric // If we weren't able to prove a vsetvli was directly unneeded, it might still 950fe6060f1SDimitry Andric // be/ unneeded if the AVL is a phi node where all incoming values are VL 951fe6060f1SDimitry Andric // outputs from the last VSETVLI in their respective basic blocks. 952fe6060f1SDimitry Andric bool RISCVInsertVSETVLI::needVSETVLIPHI(const VSETVLIInfo &Require, 953fe6060f1SDimitry Andric const MachineBasicBlock &MBB) { 954fe6060f1SDimitry Andric if (DisableInsertVSETVLPHIOpt) 955fe6060f1SDimitry Andric return true; 956fe6060f1SDimitry Andric 957fe6060f1SDimitry Andric if (!Require.hasAVLReg()) 958fe6060f1SDimitry Andric return true; 959fe6060f1SDimitry Andric 960fe6060f1SDimitry Andric Register AVLReg = Require.getAVLReg(); 961fe6060f1SDimitry Andric if (!AVLReg.isVirtual()) 962fe6060f1SDimitry Andric return true; 963fe6060f1SDimitry Andric 964fe6060f1SDimitry Andric // We need the AVL to be produce by a PHI node in this basic block. 965fe6060f1SDimitry Andric MachineInstr *PHI = MRI->getVRegDef(AVLReg); 966fe6060f1SDimitry Andric if (!PHI || PHI->getOpcode() != RISCV::PHI || PHI->getParent() != &MBB) 967fe6060f1SDimitry Andric return true; 968fe6060f1SDimitry Andric 969fe6060f1SDimitry Andric for (unsigned PHIOp = 1, NumOps = PHI->getNumOperands(); PHIOp != NumOps; 970fe6060f1SDimitry Andric PHIOp += 2) { 971fe6060f1SDimitry Andric Register InReg = PHI->getOperand(PHIOp).getReg(); 972fe6060f1SDimitry Andric MachineBasicBlock *PBB = PHI->getOperand(PHIOp + 1).getMBB(); 973fe6060f1SDimitry Andric const BlockData &PBBInfo = BlockInfo[PBB->getNumber()]; 974fe6060f1SDimitry Andric // If the exit from the predecessor has the VTYPE we are looking for 975fe6060f1SDimitry Andric // we might be able to avoid a VSETVLI. 976349cc55cSDimitry Andric if (PBBInfo.Exit.isUnknown() || 977349cc55cSDimitry Andric !PBBInfo.Exit.hasCompatibleVTYPE(Require, /*Strict*/ false)) 978fe6060f1SDimitry Andric return true; 979fe6060f1SDimitry Andric 980fe6060f1SDimitry Andric // We need the PHI input to the be the output of a VSET(I)VLI. 981fe6060f1SDimitry Andric MachineInstr *DefMI = MRI->getVRegDef(InReg); 982fe6060f1SDimitry Andric if (!DefMI || (DefMI->getOpcode() != RISCV::PseudoVSETVLI && 983349cc55cSDimitry Andric DefMI->getOpcode() != RISCV::PseudoVSETVLIX0 && 984fe6060f1SDimitry Andric DefMI->getOpcode() != RISCV::PseudoVSETIVLI)) 985fe6060f1SDimitry Andric return true; 986fe6060f1SDimitry Andric 987fe6060f1SDimitry Andric // We found a VSET(I)VLI make sure it matches the output of the 988fe6060f1SDimitry Andric // predecessor block. 989fe6060f1SDimitry Andric VSETVLIInfo DefInfo = getInfoForVSETVLI(*DefMI); 990fe6060f1SDimitry Andric if (!DefInfo.hasSameAVL(PBBInfo.Exit) || 991fe6060f1SDimitry Andric !DefInfo.hasSameVTYPE(PBBInfo.Exit)) 992fe6060f1SDimitry Andric return true; 993fe6060f1SDimitry Andric } 994fe6060f1SDimitry Andric 995fe6060f1SDimitry Andric // If all the incoming values to the PHI checked out, we don't need 996fe6060f1SDimitry Andric // to insert a VSETVLI. 997fe6060f1SDimitry Andric return false; 998fe6060f1SDimitry Andric } 999fe6060f1SDimitry Andric 1000fe6060f1SDimitry Andric void RISCVInsertVSETVLI::emitVSETVLIs(MachineBasicBlock &MBB) { 1001fe6060f1SDimitry Andric VSETVLIInfo CurInfo; 1002349cc55cSDimitry Andric // Only be set if current VSETVLIInfo is from an explicit VSET(I)VLI. 1003349cc55cSDimitry Andric MachineInstr *PrevVSETVLIMI = nullptr; 1004fe6060f1SDimitry Andric 1005fe6060f1SDimitry Andric for (MachineInstr &MI : MBB) { 1006fe6060f1SDimitry Andric // If this is an explicit VSETVLI or VSETIVLI, update our state. 1007fe6060f1SDimitry Andric if (MI.getOpcode() == RISCV::PseudoVSETVLI || 1008349cc55cSDimitry Andric MI.getOpcode() == RISCV::PseudoVSETVLIX0 || 1009fe6060f1SDimitry Andric MI.getOpcode() == RISCV::PseudoVSETIVLI) { 1010fe6060f1SDimitry Andric // Conservatively, mark the VL and VTYPE as live. 1011fe6060f1SDimitry Andric assert(MI.getOperand(3).getReg() == RISCV::VL && 1012fe6060f1SDimitry Andric MI.getOperand(4).getReg() == RISCV::VTYPE && 1013fe6060f1SDimitry Andric "Unexpected operands where VL and VTYPE should be"); 1014fe6060f1SDimitry Andric MI.getOperand(3).setIsDead(false); 1015fe6060f1SDimitry Andric MI.getOperand(4).setIsDead(false); 1016fe6060f1SDimitry Andric CurInfo = getInfoForVSETVLI(MI); 1017349cc55cSDimitry Andric PrevVSETVLIMI = &MI; 1018fe6060f1SDimitry Andric continue; 1019fe6060f1SDimitry Andric } 1020fe6060f1SDimitry Andric 1021fe6060f1SDimitry Andric uint64_t TSFlags = MI.getDesc().TSFlags; 1022fe6060f1SDimitry Andric if (RISCVII::hasSEWOp(TSFlags)) { 1023fe6060f1SDimitry Andric VSETVLIInfo NewInfo = computeInfoForInstr(MI, TSFlags, MRI); 1024fe6060f1SDimitry Andric if (RISCVII::hasVLOp(TSFlags)) { 1025349cc55cSDimitry Andric unsigned Offset = 2; 1026349cc55cSDimitry Andric if (RISCVII::hasVecPolicyOp(TSFlags)) 1027349cc55cSDimitry Andric Offset = 3; 1028349cc55cSDimitry Andric MachineOperand &VLOp = 1029349cc55cSDimitry Andric MI.getOperand(MI.getNumExplicitOperands() - Offset); 1030fe6060f1SDimitry Andric if (VLOp.isReg()) { 1031fe6060f1SDimitry Andric // Erase the AVL operand from the instruction. 1032fe6060f1SDimitry Andric VLOp.setReg(RISCV::NoRegister); 1033fe6060f1SDimitry Andric VLOp.setIsKill(false); 1034fe6060f1SDimitry Andric } 1035fe6060f1SDimitry Andric MI.addOperand(MachineOperand::CreateReg(RISCV::VL, /*isDef*/ false, 1036fe6060f1SDimitry Andric /*isImp*/ true)); 1037fe6060f1SDimitry Andric } 1038fe6060f1SDimitry Andric MI.addOperand(MachineOperand::CreateReg(RISCV::VTYPE, /*isDef*/ false, 1039fe6060f1SDimitry Andric /*isImp*/ true)); 1040fe6060f1SDimitry Andric 1041fe6060f1SDimitry Andric if (!CurInfo.isValid()) { 1042fe6060f1SDimitry Andric // We haven't found any vector instructions or VL/VTYPE changes yet, 1043fe6060f1SDimitry Andric // use the predecessor information. 1044fe6060f1SDimitry Andric assert(BlockInfo[MBB.getNumber()].Pred.isValid() && 1045fe6060f1SDimitry Andric "Expected a valid predecessor state."); 1046fe6060f1SDimitry Andric if (needVSETVLI(NewInfo, BlockInfo[MBB.getNumber()].Pred) && 1047fe6060f1SDimitry Andric needVSETVLIPHI(NewInfo, MBB)) { 1048fe6060f1SDimitry Andric insertVSETVLI(MBB, MI, NewInfo, BlockInfo[MBB.getNumber()].Pred); 1049fe6060f1SDimitry Andric CurInfo = NewInfo; 1050fe6060f1SDimitry Andric } 1051fe6060f1SDimitry Andric } else { 1052fe6060f1SDimitry Andric // If this instruction isn't compatible with the previous VL/VTYPE 1053fe6060f1SDimitry Andric // we need to insert a VSETVLI. 1054349cc55cSDimitry Andric // If this is a unit-stride or strided load/store, we may be able to use 1055349cc55cSDimitry Andric // the EMUL=(EEW/SEW)*LMUL relationship to avoid changing vtype. 1056349cc55cSDimitry Andric // NOTE: We can't use predecessor information for the store. We must 1057349cc55cSDimitry Andric // treat it the same as the first phase so that we produce the correct 1058349cc55cSDimitry Andric // vl/vtype for succesor blocks. 1059349cc55cSDimitry Andric if (!canSkipVSETVLIForLoadStore(MI, NewInfo, CurInfo) && 1060349cc55cSDimitry Andric needVSETVLI(NewInfo, CurInfo)) { 1061349cc55cSDimitry Andric // If the previous VL/VTYPE is set by VSETVLI and do not use, Merge it 1062349cc55cSDimitry Andric // with current VL/VTYPE. 1063349cc55cSDimitry Andric bool NeedInsertVSETVLI = true; 1064349cc55cSDimitry Andric if (PrevVSETVLIMI) { 1065349cc55cSDimitry Andric bool HasSameAVL = 1066349cc55cSDimitry Andric CurInfo.hasSameAVL(NewInfo) || 1067349cc55cSDimitry Andric (NewInfo.hasAVLReg() && NewInfo.getAVLReg().isVirtual() && 1068349cc55cSDimitry Andric NewInfo.getAVLReg() == PrevVSETVLIMI->getOperand(0).getReg()); 1069349cc55cSDimitry Andric // If these two VSETVLI have the same AVL and the same VLMAX, 1070349cc55cSDimitry Andric // we could merge these two VSETVLI. 1071349cc55cSDimitry Andric if (HasSameAVL && 1072349cc55cSDimitry Andric CurInfo.getSEWLMULRatio() == NewInfo.getSEWLMULRatio()) { 1073349cc55cSDimitry Andric PrevVSETVLIMI->getOperand(2).setImm(NewInfo.encodeVTYPE()); 1074349cc55cSDimitry Andric NeedInsertVSETVLI = false; 1075349cc55cSDimitry Andric } 1076*04eeddc0SDimitry Andric if (isScalarMoveInstr(MI) && 1077*04eeddc0SDimitry Andric ((CurInfo.hasNonZeroAVL() && NewInfo.hasNonZeroAVL()) || 1078*04eeddc0SDimitry Andric (CurInfo.hasZeroAVL() && NewInfo.hasZeroAVL())) && 1079*04eeddc0SDimitry Andric NewInfo.hasSameVLMAX(CurInfo)) { 1080*04eeddc0SDimitry Andric PrevVSETVLIMI->getOperand(2).setImm(NewInfo.encodeVTYPE()); 1081*04eeddc0SDimitry Andric NeedInsertVSETVLI = false; 1082*04eeddc0SDimitry Andric } 1083349cc55cSDimitry Andric } 1084349cc55cSDimitry Andric if (NeedInsertVSETVLI) 1085fe6060f1SDimitry Andric insertVSETVLI(MBB, MI, NewInfo, CurInfo); 1086fe6060f1SDimitry Andric CurInfo = NewInfo; 1087fe6060f1SDimitry Andric } 1088fe6060f1SDimitry Andric } 1089349cc55cSDimitry Andric PrevVSETVLIMI = nullptr; 1090fe6060f1SDimitry Andric } 1091fe6060f1SDimitry Andric 1092fe6060f1SDimitry Andric // If this is something updates VL/VTYPE that we don't know about, set 1093fe6060f1SDimitry Andric // the state to unknown. 1094fe6060f1SDimitry Andric if (MI.isCall() || MI.isInlineAsm() || MI.modifiesRegister(RISCV::VL) || 1095fe6060f1SDimitry Andric MI.modifiesRegister(RISCV::VTYPE)) { 1096fe6060f1SDimitry Andric CurInfo = VSETVLIInfo::getUnknown(); 1097349cc55cSDimitry Andric PrevVSETVLIMI = nullptr; 1098fe6060f1SDimitry Andric } 1099fe6060f1SDimitry Andric } 1100fe6060f1SDimitry Andric } 1101fe6060f1SDimitry Andric 1102fe6060f1SDimitry Andric bool RISCVInsertVSETVLI::runOnMachineFunction(MachineFunction &MF) { 1103fe6060f1SDimitry Andric // Skip if the vector extension is not enabled. 1104fe6060f1SDimitry Andric const RISCVSubtarget &ST = MF.getSubtarget<RISCVSubtarget>(); 1105349cc55cSDimitry Andric if (!ST.hasVInstructions()) 1106fe6060f1SDimitry Andric return false; 1107fe6060f1SDimitry Andric 1108fe6060f1SDimitry Andric TII = ST.getInstrInfo(); 1109fe6060f1SDimitry Andric MRI = &MF.getRegInfo(); 1110fe6060f1SDimitry Andric 1111fe6060f1SDimitry Andric assert(BlockInfo.empty() && "Expect empty block infos"); 1112fe6060f1SDimitry Andric BlockInfo.resize(MF.getNumBlockIDs()); 1113fe6060f1SDimitry Andric 1114fe6060f1SDimitry Andric bool HaveVectorOp = false; 1115fe6060f1SDimitry Andric 1116fe6060f1SDimitry Andric // Phase 1 - determine how VL/VTYPE are affected by the each block. 1117fe6060f1SDimitry Andric for (const MachineBasicBlock &MBB : MF) 1118fe6060f1SDimitry Andric HaveVectorOp |= computeVLVTYPEChanges(MBB); 1119fe6060f1SDimitry Andric 1120fe6060f1SDimitry Andric // If we didn't find any instructions that need VSETVLI, we're done. 1121fe6060f1SDimitry Andric if (HaveVectorOp) { 1122fe6060f1SDimitry Andric // Phase 2 - determine the exit VL/VTYPE from each block. We add all 1123fe6060f1SDimitry Andric // blocks to the list here, but will also add any that need to be revisited 1124fe6060f1SDimitry Andric // during Phase 2 processing. 1125fe6060f1SDimitry Andric for (const MachineBasicBlock &MBB : MF) { 1126fe6060f1SDimitry Andric WorkList.push(&MBB); 1127fe6060f1SDimitry Andric BlockInfo[MBB.getNumber()].InQueue = true; 1128fe6060f1SDimitry Andric } 1129fe6060f1SDimitry Andric while (!WorkList.empty()) { 1130fe6060f1SDimitry Andric const MachineBasicBlock &MBB = *WorkList.front(); 1131fe6060f1SDimitry Andric WorkList.pop(); 1132fe6060f1SDimitry Andric computeIncomingVLVTYPE(MBB); 1133fe6060f1SDimitry Andric } 1134fe6060f1SDimitry Andric 1135fe6060f1SDimitry Andric // Phase 3 - add any vsetvli instructions needed in the block. Use the 1136fe6060f1SDimitry Andric // Phase 2 information to avoid adding vsetvlis before the first vector 1137fe6060f1SDimitry Andric // instruction in the block if the VL/VTYPE is satisfied by its 1138fe6060f1SDimitry Andric // predecessors. 1139fe6060f1SDimitry Andric for (MachineBasicBlock &MBB : MF) 1140fe6060f1SDimitry Andric emitVSETVLIs(MBB); 1141fe6060f1SDimitry Andric } 1142fe6060f1SDimitry Andric 1143fe6060f1SDimitry Andric BlockInfo.clear(); 1144fe6060f1SDimitry Andric 1145fe6060f1SDimitry Andric return HaveVectorOp; 1146fe6060f1SDimitry Andric } 1147fe6060f1SDimitry Andric 1148fe6060f1SDimitry Andric /// Returns an instance of the Insert VSETVLI pass. 1149fe6060f1SDimitry Andric FunctionPass *llvm::createRISCVInsertVSETVLIPass() { 1150fe6060f1SDimitry Andric return new RISCVInsertVSETVLI(); 1151fe6060f1SDimitry Andric } 1152