[llvm] 67601a4 - [RISCV][NFC] Add RISCVVSETVLIInfoAnalysis

via llvm-commits llvm-commits at lists.llvm.org
Sun Jan 11 20:00:59 PST 2026


Author: Pengcheng Wang
Date: 2026-01-12T12:00:55+08:00
New Revision: 67601a43b57a2df9c9b51463b84b3610878556ab

URL: https://github.com/llvm/llvm-project/commit/67601a43b57a2df9c9b51463b84b3610878556ab
DIFF: https://github.com/llvm/llvm-project/commit/67601a43b57a2df9c9b51463b84b3610878556ab.diff

LOG: [RISCV][NFC] Add RISCVVSETVLIInfoAnalysis

This can be reused by #95924.

Reviewers: BeMg, topperc, lukel97, preames, mshockwave

Reviewed By: mshockwave, topperc

Pull Request: https://github.com/llvm/llvm-project/pull/172615

Added: 
    llvm/lib/Target/RISCV/RISCVVSETVLIInfoAnalysis.cpp
    llvm/lib/Target/RISCV/RISCVVSETVLIInfoAnalysis.h

Modified: 
    llvm/lib/Target/RISCV/CMakeLists.txt
    llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp
    llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
    llvm/lib/Target/RISCV/RISCVInstrInfo.h

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/RISCV/CMakeLists.txt b/llvm/lib/Target/RISCV/CMakeLists.txt
index 768c6c4ae3171..3b529c1471d54 100644
--- a/llvm/lib/Target/RISCV/CMakeLists.txt
+++ b/llvm/lib/Target/RISCV/CMakeLists.txt
@@ -72,6 +72,7 @@ add_llvm_target(RISCVCodeGen
   RISCVVectorPeephole.cpp
   RISCVVLOptimizer.cpp
   RISCVVMV0Elimination.cpp
+  RISCVVSETVLIInfoAnalysis.cpp
   RISCVZacasABIFix.cpp
   RISCVZilsdOptimizer.cpp
   GISel/RISCVCallLowering.cpp

diff  --git a/llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp b/llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp
index 1a043936383f8..8ba00c815fa0e 100644
--- a/llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp
+++ b/llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp
@@ -26,6 +26,7 @@
 
 #include "RISCV.h"
 #include "RISCVSubtarget.h"
+#include "RISCVVSETVLIInfoAnalysis.h"
 #include "llvm/ADT/PostOrderIterator.h"
 #include "llvm/ADT/Statistic.h"
 #include "llvm/CodeGen/LiveDebugVariables.h"
@@ -34,6 +35,7 @@
 #include "llvm/CodeGen/MachineFunctionPass.h"
 #include <queue>
 using namespace llvm;
+using namespace RISCV;
 
 #define DEBUG_TYPE "riscv-insert-vsetvli"
 #define RISCV_INSERT_VSETVLI_NAME "RISC-V Insert VSETVLI pass"
@@ -66,851 +68,6 @@ static unsigned getVLOpNum(const MachineInstr &MI) {
   return RISCVII::getVLOpNum(MI.getDesc());
 }
 
-static unsigned getSEWOpNum(const MachineInstr &MI) {
-  return RISCVII::getSEWOpNum(MI.getDesc());
-}
-
-static unsigned getVecPolicyOpNum(const MachineInstr &MI) {
-  return RISCVII::getVecPolicyOpNum(MI.getDesc());
-}
-
-/// Get the EEW for a load or store instruction.  Return std::nullopt if MI is
-/// not a load or store which ignores SEW.
-static std::optional<unsigned> getEEWForLoadStore(const MachineInstr &MI) {
-  switch (RISCV::getRVVMCOpcode(MI.getOpcode())) {
-  default:
-    return std::nullopt;
-  case RISCV::VLE8_V:
-  case RISCV::VLSE8_V:
-  case RISCV::VSE8_V:
-  case RISCV::VSSE8_V:
-    return 8;
-  case RISCV::VLE16_V:
-  case RISCV::VLSE16_V:
-  case RISCV::VSE16_V:
-  case RISCV::VSSE16_V:
-    return 16;
-  case RISCV::VLE32_V:
-  case RISCV::VLSE32_V:
-  case RISCV::VSE32_V:
-  case RISCV::VSSE32_V:
-    return 32;
-  case RISCV::VLE64_V:
-  case RISCV::VLSE64_V:
-  case RISCV::VSE64_V:
-  case RISCV::VSSE64_V:
-    return 64;
-  }
-}
-
-/// Return true if this is an operation on mask registers.  Note that
-/// this includes both arithmetic/logical ops and load/store (vlm/vsm).
-static bool isMaskRegOp(const MachineInstr &MI) {
-  if (!RISCVII::hasSEWOp(MI.getDesc().TSFlags))
-    return false;
-  const unsigned Log2SEW = MI.getOperand(getSEWOpNum(MI)).getImm();
-  // A Log2SEW of 0 is an operation on mask registers only.
-  return Log2SEW == 0;
-}
-
-/// Return true if the inactive elements in the result are entirely undefined.
-/// Note that this is 
diff erent from "agnostic" as defined by the vector
-/// specification.  Agnostic requires each lane to either be undisturbed, or
-/// take the value -1; no other value is allowed.
-static bool hasUndefinedPassthru(const MachineInstr &MI) {
-
-  unsigned UseOpIdx;
-  if (!MI.isRegTiedToUseOperand(0, &UseOpIdx))
-    // If there is no passthrough operand, then the pass through
-    // lanes are undefined.
-    return true;
-
-  // All undefined passthrus should be $noreg: see
-  // RISCVDAGToDAGISel::doPeepholeNoRegPassThru
-  const MachineOperand &UseMO = MI.getOperand(UseOpIdx);
-  return !UseMO.getReg().isValid() || UseMO.isUndef();
-}
-
-/// Return true if \p MI is a copy that will be lowered to one or more vmvNr.vs.
-static bool isVectorCopy(const TargetRegisterInfo *TRI,
-                         const MachineInstr &MI) {
-  return MI.isCopy() && MI.getOperand(0).getReg().isPhysical() &&
-         RISCVRegisterInfo::isRVVRegClass(
-             TRI->getMinimalPhysRegClass(MI.getOperand(0).getReg()));
-}
-
-/// Which subfields of VL or VTYPE have values we need to preserve?
-struct DemandedFields {
-  // Some unknown property of VL is used.  If demanded, must preserve entire
-  // value.
-  bool VLAny = false;
-  // Only zero vs non-zero is used. If demanded, can change non-zero values.
-  bool VLZeroness = false;
-  // What properties of SEW we need to preserve.
-  enum : uint8_t {
-    SEWEqual = 3, // The exact value of SEW needs to be preserved.
-    SEWGreaterThanOrEqualAndLessThan64 =
-        2, // SEW can be changed as long as it's greater
-           // than or equal to the original value, but must be less
-           // than 64.
-    SEWGreaterThanOrEqual = 1, // SEW can be changed as long as it's greater
-                               // than or equal to the original value.
-    SEWNone = 0                // We don't need to preserve SEW at all.
-  } SEW = SEWNone;
-  enum : uint8_t {
-    LMULEqual = 2, // The exact value of LMUL needs to be preserved.
-    LMULLessThanOrEqualToM1 = 1, // We can use any LMUL <= M1.
-    LMULNone = 0                 // We don't need to preserve LMUL at all.
-  } LMUL = LMULNone;
-  bool SEWLMULRatio = false;
-  bool TailPolicy = false;
-  bool MaskPolicy = false;
-  // If this is true, we demand that VTYPE is set to some legal state, i.e. that
-  // vill is unset.
-  bool VILL = false;
-  bool TWiden = false;
-  bool AltFmt = false;
-
-  // Return true if any part of VTYPE was used
-  bool usedVTYPE() const {
-    return SEW || LMUL || SEWLMULRatio || TailPolicy || MaskPolicy || VILL ||
-           TWiden || AltFmt;
-  }
-
-  // Return true if any property of VL was used
-  bool usedVL() {
-    return VLAny || VLZeroness;
-  }
-
-  // Mark all VTYPE subfields and properties as demanded
-  void demandVTYPE() {
-    SEW = SEWEqual;
-    LMUL = LMULEqual;
-    SEWLMULRatio = true;
-    TailPolicy = true;
-    MaskPolicy = true;
-    VILL = true;
-    TWiden = true;
-    AltFmt = true;
-  }
-
-  // Mark all VL properties as demanded
-  void demandVL() {
-    VLAny = true;
-    VLZeroness = true;
-  }
-
-  static DemandedFields all() {
-    DemandedFields DF;
-    DF.demandVTYPE();
-    DF.demandVL();
-    return DF;
-  }
-
-  // Make this the result of demanding both the fields in this and B.
-  void doUnion(const DemandedFields &B) {
-    VLAny |= B.VLAny;
-    VLZeroness |= B.VLZeroness;
-    SEW = std::max(SEW, B.SEW);
-    LMUL = std::max(LMUL, B.LMUL);
-    SEWLMULRatio |= B.SEWLMULRatio;
-    TailPolicy |= B.TailPolicy;
-    MaskPolicy |= B.MaskPolicy;
-    VILL |= B.VILL;
-    AltFmt |= B.AltFmt;
-    TWiden |= B.TWiden;
-  }
-
-#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
-  /// Support for debugging, callable in GDB: V->dump()
-  LLVM_DUMP_METHOD void dump() const {
-    print(dbgs());
-    dbgs() << "\n";
-  }
-
-  /// Implement operator<<.
-  void print(raw_ostream &OS) const {
-    OS << "{";
-    OS << "VLAny=" << VLAny << ", ";
-    OS << "VLZeroness=" << VLZeroness << ", ";
-    OS << "SEW=";
-    switch (SEW) {
-    case SEWEqual:
-      OS << "SEWEqual";
-      break;
-    case SEWGreaterThanOrEqual:
-      OS << "SEWGreaterThanOrEqual";
-      break;
-    case SEWGreaterThanOrEqualAndLessThan64:
-      OS << "SEWGreaterThanOrEqualAndLessThan64";
-      break;
-    case SEWNone:
-      OS << "SEWNone";
-      break;
-    };
-    OS << ", ";
-    OS << "LMUL=";
-    switch (LMUL) {
-    case LMULEqual:
-      OS << "LMULEqual";
-      break;
-    case LMULLessThanOrEqualToM1:
-      OS << "LMULLessThanOrEqualToM1";
-      break;
-    case LMULNone:
-      OS << "LMULNone";
-      break;
-    };
-    OS << ", ";
-    OS << "SEWLMULRatio=" << SEWLMULRatio << ", ";
-    OS << "TailPolicy=" << TailPolicy << ", ";
-    OS << "MaskPolicy=" << MaskPolicy << ", ";
-    OS << "VILL=" << VILL << ", ";
-    OS << "AltFmt=" << AltFmt << ", ";
-    OS << "TWiden=" << TWiden;
-    OS << "}";
-  }
-#endif
-};
-
-#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
-LLVM_ATTRIBUTE_USED
-inline raw_ostream &operator<<(raw_ostream &OS, const DemandedFields &DF) {
-  DF.print(OS);
-  return OS;
-}
-#endif
-
-static bool isLMUL1OrSmaller(RISCVVType::VLMUL LMUL) {
-  auto [LMul, Fractional] = RISCVVType::decodeVLMUL(LMUL);
-  return Fractional || LMul == 1;
-}
-
-/// Return true if moving from CurVType to NewVType is
-/// indistinguishable from the perspective of an instruction (or set
-/// of instructions) which use only the Used subfields and properties.
-static bool areCompatibleVTYPEs(uint64_t CurVType, uint64_t NewVType,
-                                const DemandedFields &Used) {
-  switch (Used.SEW) {
-  case DemandedFields::SEWNone:
-    break;
-  case DemandedFields::SEWEqual:
-    if (RISCVVType::getSEW(CurVType) != RISCVVType::getSEW(NewVType))
-      return false;
-    break;
-  case DemandedFields::SEWGreaterThanOrEqual:
-    if (RISCVVType::getSEW(NewVType) < RISCVVType::getSEW(CurVType))
-      return false;
-    break;
-  case DemandedFields::SEWGreaterThanOrEqualAndLessThan64:
-    if (RISCVVType::getSEW(NewVType) < RISCVVType::getSEW(CurVType) ||
-        RISCVVType::getSEW(NewVType) >= 64)
-      return false;
-    break;
-  }
-
-  switch (Used.LMUL) {
-  case DemandedFields::LMULNone:
-    break;
-  case DemandedFields::LMULEqual:
-    if (RISCVVType::getVLMUL(CurVType) != RISCVVType::getVLMUL(NewVType))
-      return false;
-    break;
-  case DemandedFields::LMULLessThanOrEqualToM1:
-    if (!isLMUL1OrSmaller(RISCVVType::getVLMUL(NewVType)))
-      return false;
-    break;
-  }
-
-  if (Used.SEWLMULRatio) {
-    auto Ratio1 = RISCVVType::getSEWLMULRatio(RISCVVType::getSEW(CurVType),
-                                              RISCVVType::getVLMUL(CurVType));
-    auto Ratio2 = RISCVVType::getSEWLMULRatio(RISCVVType::getSEW(NewVType),
-                                              RISCVVType::getVLMUL(NewVType));
-    if (Ratio1 != Ratio2)
-      return false;
-  }
-
-  if (Used.TailPolicy && RISCVVType::isTailAgnostic(CurVType) !=
-                             RISCVVType::isTailAgnostic(NewVType))
-    return false;
-  if (Used.MaskPolicy && RISCVVType::isMaskAgnostic(CurVType) !=
-                             RISCVVType::isMaskAgnostic(NewVType))
-    return false;
-  if (Used.TWiden && (RISCVVType::hasXSfmmWiden(CurVType) !=
-                          RISCVVType::hasXSfmmWiden(NewVType) ||
-                      (RISCVVType::hasXSfmmWiden(CurVType) &&
-                       RISCVVType::getXSfmmWiden(CurVType) !=
-                           RISCVVType::getXSfmmWiden(NewVType))))
-    return false;
-  if (Used.AltFmt &&
-      RISCVVType::isAltFmt(CurVType) != RISCVVType::isAltFmt(NewVType))
-    return false;
-  return true;
-}
-
-/// Return the fields and properties demanded by the provided instruction.
-DemandedFields getDemanded(const MachineInstr &MI, const RISCVSubtarget *ST) {
-  // This function works in coalesceVSETVLI too. We can still use the value of a
-  // SEW, VL, or Policy operand even though it might not be the exact value in
-  // the VL or VTYPE, since we only care about what the instruction originally
-  // demanded.
-
-  // Most instructions don't use any of these subfeilds.
-  DemandedFields Res;
-  // Start conservative if registers are used
-  if (MI.isCall() || MI.isInlineAsm() ||
-      MI.readsRegister(RISCV::VL, /*TRI=*/nullptr))
-    Res.demandVL();
-  if (MI.isCall() || MI.isInlineAsm() ||
-      MI.readsRegister(RISCV::VTYPE, /*TRI=*/nullptr))
-    Res.demandVTYPE();
-  // Start conservative on the unlowered form too
-  uint64_t TSFlags = MI.getDesc().TSFlags;
-  if (RISCVII::hasSEWOp(TSFlags)) {
-    Res.demandVTYPE();
-    if (RISCVII::hasVLOp(TSFlags))
-      if (const MachineOperand &VLOp = MI.getOperand(getVLOpNum(MI));
-          !VLOp.isReg() || !VLOp.isUndef())
-        Res.demandVL();
-
-    // Behavior is independent of mask policy.
-    if (!RISCVII::usesMaskPolicy(TSFlags))
-      Res.MaskPolicy = false;
-  }
-
-  // Loads and stores with implicit EEW do not demand SEW or LMUL directly.
-  // They instead demand the ratio of the two which is used in computing
-  // EMUL, but which allows us the flexibility to change SEW and LMUL
-  // provided we don't change the ratio.
-  // Note: We assume that the instructions initial SEW is the EEW encoded
-  // in the opcode.  This is asserted when constructing the VSETVLIInfo.
-  if (getEEWForLoadStore(MI)) {
-    Res.SEW = DemandedFields::SEWNone;
-    Res.LMUL = DemandedFields::LMULNone;
-  }
-
-  // Store instructions don't use the policy fields.
-  if (RISCVII::hasSEWOp(TSFlags) && MI.getNumExplicitDefs() == 0) {
-    Res.TailPolicy = false;
-    Res.MaskPolicy = false;
-  }
-
-  // If this is a mask reg operation, it only cares about VLMAX.
-  // TODO: Possible extensions to this logic
-  // * Probably ok if available VLMax is larger than demanded
-  // * The policy bits can probably be ignored..
-  if (isMaskRegOp(MI)) {
-    Res.SEW = DemandedFields::SEWNone;
-    Res.LMUL = DemandedFields::LMULNone;
-  }
-
-  // For vmv.s.x and vfmv.s.f, there are only two behaviors, VL = 0 and VL > 0.
-  if (RISCVInstrInfo::isScalarInsertInstr(MI)) {
-    Res.LMUL = DemandedFields::LMULNone;
-    Res.SEWLMULRatio = false;
-    Res.VLAny = false;
-    // For vmv.s.x and vfmv.s.f, if the passthru is *undefined*, we don't
-    // need to preserve any other bits and are thus compatible with any larger,
-    // etype and can disregard policy bits.  Warning: It's tempting to try doing
-    // this for any tail agnostic operation, but we can't as TA requires
-    // tail lanes to either be the original value or -1.  We are writing
-    // unknown bits to the lanes here.
-    if (hasUndefinedPassthru(MI)) {
-      if (RISCVInstrInfo::isFloatScalarMoveOrScalarSplatInstr(MI) &&
-          !ST->hasVInstructionsF64())
-        Res.SEW = DemandedFields::SEWGreaterThanOrEqualAndLessThan64;
-      else
-        Res.SEW = DemandedFields::SEWGreaterThanOrEqual;
-      Res.TailPolicy = false;
-    }
-  }
-
-  // vmv.x.s, and vfmv.f.s are unconditional and ignore everything except SEW.
-  if (RISCVInstrInfo::isScalarExtractInstr(MI)) {
-    assert(!RISCVII::hasVLOp(TSFlags));
-    Res.LMUL = DemandedFields::LMULNone;
-    Res.SEWLMULRatio = false;
-    Res.TailPolicy = false;
-    Res.MaskPolicy = false;
-  }
-
-  if (RISCVII::hasVLOp(MI.getDesc().TSFlags)) {
-    const MachineOperand &VLOp = MI.getOperand(getVLOpNum(MI));
-    // A slidedown/slideup with an *undefined* passthru can freely clobber
-    // elements not copied from the source vector (e.g. masked off, tail, or
-    // slideup's prefix). Notes:
-    // * We can't modify SEW here since the slide amount is in units of SEW.
-    // * VL=1 is special only because we have existing support for zero vs
-    //   non-zero VL.  We could generalize this if we had a VL > C predicate.
-    // * The LMUL1 restriction is for machines whose latency may depend on LMUL.
-    // * As above, this is only legal for tail "undefined" not "agnostic".
-    // * We avoid increasing vl if the subtarget has +vl-dependent-latency
-    if (RISCVInstrInfo::isVSlideInstr(MI) && VLOp.isImm() &&
-        VLOp.getImm() == 1 && hasUndefinedPassthru(MI) &&
-        !ST->hasVLDependentLatency()) {
-      Res.VLAny = false;
-      Res.VLZeroness = true;
-      Res.LMUL = DemandedFields::LMULLessThanOrEqualToM1;
-      Res.TailPolicy = false;
-    }
-
-    // A tail undefined vmv.v.i/x or vfmv.v.f with VL=1 can be treated in the
-    // same semantically as vmv.s.x.  This is particularly useful since we don't
-    // have an immediate form of vmv.s.x, and thus frequently use vmv.v.i in
-    // it's place. Since a splat is non-constant time in LMUL, we do need to be
-    // careful to not increase the number of active vector registers (unlike for
-    // vmv.s.x.)
-    if (RISCVInstrInfo::isScalarSplatInstr(MI) && VLOp.isImm() &&
-        VLOp.getImm() == 1 && hasUndefinedPassthru(MI) &&
-        !ST->hasVLDependentLatency()) {
-      Res.LMUL = DemandedFields::LMULLessThanOrEqualToM1;
-      Res.SEWLMULRatio = false;
-      Res.VLAny = false;
-      if (RISCVInstrInfo::isFloatScalarMoveOrScalarSplatInstr(MI) &&
-          !ST->hasVInstructionsF64())
-        Res.SEW = DemandedFields::SEWGreaterThanOrEqualAndLessThan64;
-      else
-        Res.SEW = DemandedFields::SEWGreaterThanOrEqual;
-      Res.TailPolicy = false;
-    }
-  }
-
-  // In §32.16.6, whole vector register moves have a dependency on SEW. At the
-  // MIR level though we don't encode the element type, and it gives the same
-  // result whatever the SEW may be.
-  //
-  // However it does need valid SEW, i.e. vill must be cleared. The entry to a
-  // function, calls and inline assembly may all set it, so make sure we clear
-  // it for whole register copies. Do this by leaving VILL demanded.
-  if (isVectorCopy(ST->getRegisterInfo(), MI)) {
-    Res.LMUL = DemandedFields::LMULNone;
-    Res.SEW = DemandedFields::SEWNone;
-    Res.SEWLMULRatio = false;
-    Res.TailPolicy = false;
-    Res.MaskPolicy = false;
-  }
-
-  if (RISCVInstrInfo::isVExtractInstr(MI)) {
-    assert(!RISCVII::hasVLOp(TSFlags));
-    // TODO: LMUL can be any larger value (without cost)
-    Res.TailPolicy = false;
-  }
-
-  Res.AltFmt = RISCVII::getAltFmtType(MI.getDesc().TSFlags) !=
-               RISCVII::AltFmtType::DontCare;
-  Res.TWiden = RISCVII::hasTWidenOp(MI.getDesc().TSFlags) ||
-               RISCVInstrInfo::isXSfmmVectorConfigInstr(MI);
-
-  return Res;
-}
-
-/// Defines the abstract state with which the forward dataflow models the
-/// values of the VL and VTYPE registers after insertion.
-class VSETVLIInfo {
-  struct AVLDef {
-    // Every AVLDef should have a VNInfo, unless we're running without
-    // LiveIntervals in which case this will be nullptr.
-    const VNInfo *ValNo;
-    Register DefReg;
-  };
-  union {
-    AVLDef AVLRegDef;
-    unsigned AVLImm;
-  };
-
-  enum class AVLState : uint8_t {
-    Uninitialized,
-    AVLIsReg,
-    AVLIsImm,
-    AVLIsVLMAX,
-    Unknown, // AVL and VTYPE are fully unknown
-  } State = AVLState::Uninitialized;
-
-  // Fields from VTYPE.
-  RISCVVType::VLMUL VLMul = RISCVVType::LMUL_1;
-  uint8_t SEW = 0;
-  uint8_t TailAgnostic : 1;
-  uint8_t MaskAgnostic : 1;
-  uint8_t SEWLMULRatioOnly : 1;
-  uint8_t AltFmt : 1;
-  uint8_t TWiden : 3;
-
-public:
-  VSETVLIInfo()
-      : AVLImm(0), TailAgnostic(false), MaskAgnostic(false),
-        SEWLMULRatioOnly(false), AltFmt(false), TWiden(0) {}
-
-  static VSETVLIInfo getUnknown() {
-    VSETVLIInfo Info;
-    Info.setUnknown();
-    return Info;
-  }
-
-  bool isValid() const { return State != AVLState::Uninitialized; }
-  void setUnknown() { State = AVLState::Unknown; }
-  bool isUnknown() const { return State == AVLState::Unknown; }
-
-  void setAVLRegDef(const VNInfo *VNInfo, Register AVLReg) {
-    assert(AVLReg.isVirtual());
-    AVLRegDef.ValNo = VNInfo;
-    AVLRegDef.DefReg = AVLReg;
-    State = AVLState::AVLIsReg;
-  }
-
-  void setAVLImm(unsigned Imm) {
-    AVLImm = Imm;
-    State = AVLState::AVLIsImm;
-  }
-
-  void setAVLVLMAX() { State = AVLState::AVLIsVLMAX; }
-
-  bool hasAVLImm() const { return State == AVLState::AVLIsImm; }
-  bool hasAVLReg() const { return State == AVLState::AVLIsReg; }
-  bool hasAVLVLMAX() const { return State == AVLState::AVLIsVLMAX; }
-  Register getAVLReg() const {
-    assert(hasAVLReg() && AVLRegDef.DefReg.isVirtual());
-    return AVLRegDef.DefReg;
-  }
-  unsigned getAVLImm() const {
-    assert(hasAVLImm());
-    return AVLImm;
-  }
-  const VNInfo *getAVLVNInfo() const {
-    assert(hasAVLReg());
-    return AVLRegDef.ValNo;
-  }
-  // Most AVLIsReg infos will have a single defining MachineInstr, unless it was
-  // a PHI node. In that case getAVLVNInfo()->def will point to the block
-  // boundary slot and this will return nullptr.  If LiveIntervals isn't
-  // available, nullptr is also returned.
-  const MachineInstr *getAVLDefMI(const LiveIntervals *LIS) const {
-    assert(hasAVLReg());
-    if (!LIS || getAVLVNInfo()->isPHIDef())
-      return nullptr;
-    auto *MI = LIS->getInstructionFromIndex(getAVLVNInfo()->def);
-    assert(MI);
-    return MI;
-  }
-
-  void setAVL(const VSETVLIInfo &Info) {
-    assert(Info.isValid());
-    if (Info.isUnknown())
-      setUnknown();
-    else if (Info.hasAVLReg())
-      setAVLRegDef(Info.getAVLVNInfo(), Info.getAVLReg());
-    else if (Info.hasAVLVLMAX())
-      setAVLVLMAX();
-    else {
-      assert(Info.hasAVLImm());
-      setAVLImm(Info.getAVLImm());
-    }
-  }
-
-  bool hasSEWLMULRatioOnly() const { return SEWLMULRatioOnly; }
-
-  unsigned getSEW() const {
-    assert(isValid() && !isUnknown() && !hasSEWLMULRatioOnly() &&
-           "Can't use VTYPE for uninitialized or unknown");
-    return SEW;
-  }
-  RISCVVType::VLMUL getVLMUL() const {
-    assert(isValid() && !isUnknown() && !hasSEWLMULRatioOnly() &&
-           "Can't use VTYPE for uninitialized or unknown");
-    return VLMul;
-  }
-  bool getTailAgnostic() const {
-    assert(isValid() && !isUnknown() &&
-           "Can't use VTYPE for uninitialized or unknown");
-    return TailAgnostic;
-  }
-  bool getMaskAgnostic() const {
-    assert(isValid() && !isUnknown() &&
-           "Can't use VTYPE for uninitialized or unknown");
-    return MaskAgnostic;
-  }
-  bool getAltFmt() const {
-    assert(isValid() && !isUnknown() &&
-           "Can't use VTYPE for uninitialized or unknown");
-    return AltFmt;
-  }
-  unsigned getTWiden() const {
-    assert(isValid() && !isUnknown() &&
-           "Can't use VTYPE for uninitialized or unknown");
-    return TWiden;
-  }
-
-  bool hasNonZeroAVL(const LiveIntervals *LIS) const {
-    if (hasAVLImm())
-      return getAVLImm() > 0;
-    if (hasAVLReg()) {
-      if (auto *DefMI = getAVLDefMI(LIS))
-        return RISCVInstrInfo::isNonZeroLoadImmediate(*DefMI);
-    }
-    if (hasAVLVLMAX())
-      return true;
-    return false;
-  }
-
-  bool hasEquallyZeroAVL(const VSETVLIInfo &Other,
-                         const LiveIntervals *LIS) const {
-    if (hasSameAVL(Other))
-      return true;
-    return (hasNonZeroAVL(LIS) && Other.hasNonZeroAVL(LIS));
-  }
-
-  bool hasSameAVLLatticeValue(const VSETVLIInfo &Other) const {
-    if (hasAVLReg() && Other.hasAVLReg()) {
-      assert(!getAVLVNInfo() == !Other.getAVLVNInfo() &&
-             "we either have intervals or we don't");
-      if (!getAVLVNInfo())
-        return getAVLReg() == Other.getAVLReg();
-      return getAVLVNInfo()->id == Other.getAVLVNInfo()->id &&
-             getAVLReg() == Other.getAVLReg();
-    }
-
-    if (hasAVLImm() && Other.hasAVLImm())
-      return getAVLImm() == Other.getAVLImm();
-
-    if (hasAVLVLMAX())
-      return Other.hasAVLVLMAX() && hasSameVLMAX(Other);
-
-    return false;
-  }
-
-  // Return true if the two lattice values are guaranteed to have
-  // the same AVL value at runtime.
-  bool hasSameAVL(const VSETVLIInfo &Other) const {
-    // Without LiveIntervals, we don't know which instruction defines a
-    // register.  Since a register may be redefined, this means all AVLIsReg
-    // states must be treated as possibly distinct.
-    if (hasAVLReg() && Other.hasAVLReg()) {
-      assert(!getAVLVNInfo() == !Other.getAVLVNInfo() &&
-             "we either have intervals or we don't");
-      if (!getAVLVNInfo())
-        return false;
-    }
-    return hasSameAVLLatticeValue(Other);
-  }
-
-  void setVTYPE(unsigned VType) {
-    assert(isValid() && !isUnknown() &&
-           "Can't set VTYPE for uninitialized or unknown");
-    VLMul = RISCVVType::getVLMUL(VType);
-    SEW = RISCVVType::getSEW(VType);
-    TailAgnostic = RISCVVType::isTailAgnostic(VType);
-    MaskAgnostic = RISCVVType::isMaskAgnostic(VType);
-    AltFmt = RISCVVType::isAltFmt(VType);
-    TWiden =
-        RISCVVType::hasXSfmmWiden(VType) ? RISCVVType::getXSfmmWiden(VType) : 0;
-  }
-  void setVTYPE(RISCVVType::VLMUL L, unsigned S, bool TA, bool MA, bool Altfmt,
-                unsigned W) {
-    assert(isValid() && !isUnknown() &&
-           "Can't set VTYPE for uninitialized or unknown");
-    VLMul = L;
-    SEW = S;
-    TailAgnostic = TA;
-    MaskAgnostic = MA;
-    AltFmt = Altfmt;
-    TWiden = W;
-  }
-
-  void setAltFmt(bool AF) { AltFmt = AF; }
-
-  void setVLMul(RISCVVType::VLMUL VLMul) { this->VLMul = VLMul; }
-
-  unsigned encodeVTYPE() const {
-    assert(isValid() && !isUnknown() && !SEWLMULRatioOnly &&
-           "Can't encode VTYPE for uninitialized or unknown");
-    if (TWiden != 0)
-      return RISCVVType::encodeXSfmmVType(SEW, TWiden, AltFmt);
-    return RISCVVType::encodeVTYPE(VLMul, SEW, TailAgnostic, MaskAgnostic,
-                                   AltFmt);
-  }
-
-  bool hasSameVTYPE(const VSETVLIInfo &Other) const {
-    assert(isValid() && Other.isValid() &&
-           "Can't compare invalid VSETVLIInfos");
-    assert(!isUnknown() && !Other.isUnknown() &&
-           "Can't compare VTYPE in unknown state");
-    assert(!SEWLMULRatioOnly && !Other.SEWLMULRatioOnly &&
-           "Can't compare when only LMUL/SEW ratio is valid.");
-    return std::tie(VLMul, SEW, TailAgnostic, MaskAgnostic, AltFmt, TWiden) ==
-           std::tie(Other.VLMul, Other.SEW, Other.TailAgnostic,
-                    Other.MaskAgnostic, Other.AltFmt, Other.TWiden);
-  }
-
-  unsigned getSEWLMULRatio() const {
-    assert(isValid() && !isUnknown() &&
-           "Can't use VTYPE for uninitialized or unknown");
-    return RISCVVType::getSEWLMULRatio(SEW, VLMul);
-  }
-
-  // Check if the VTYPE for these two VSETVLIInfos produce the same VLMAX.
-  // Note that having the same VLMAX ensures that both share the same
-  // function from AVL to VL; that is, they must produce the same VL value
-  // for any given AVL value.
-  bool hasSameVLMAX(const VSETVLIInfo &Other) const {
-    assert(isValid() && Other.isValid() &&
-           "Can't compare invalid VSETVLIInfos");
-    assert(!isUnknown() && !Other.isUnknown() &&
-           "Can't compare VTYPE in unknown state");
-    return getSEWLMULRatio() == Other.getSEWLMULRatio();
-  }
-
-  bool hasCompatibleVTYPE(const DemandedFields &Used,
-                          const VSETVLIInfo &Require) const {
-    return areCompatibleVTYPEs(Require.encodeVTYPE(), encodeVTYPE(), Used);
-  }
-
-  // Determine whether the vector instructions requirements represented by
-  // Require are compatible with the previous vsetvli instruction represented
-  // by this.  MI is the instruction whose requirements we're considering.
-  bool isCompatible(const DemandedFields &Used, const VSETVLIInfo &Require,
-                    const LiveIntervals *LIS) const {
-    assert(isValid() && Require.isValid() &&
-           "Can't compare invalid VSETVLIInfos");
-    // Nothing is compatible with Unknown.
-    if (isUnknown() || Require.isUnknown())
-      return false;
-
-    // If only our VLMAX ratio is valid, then this isn't compatible.
-    if (SEWLMULRatioOnly || Require.SEWLMULRatioOnly)
-      return false;
-
-    if (Used.VLAny && !(hasSameAVL(Require) && hasSameVLMAX(Require)))
-      return false;
-
-    if (Used.VLZeroness && !hasEquallyZeroAVL(Require, LIS))
-      return false;
-
-    return hasCompatibleVTYPE(Used, Require);
-  }
-
-  bool operator==(const VSETVLIInfo &Other) const {
-    // Uninitialized is only equal to another Uninitialized.
-    if (!isValid())
-      return !Other.isValid();
-    if (!Other.isValid())
-      return !isValid();
-
-    // Unknown is only equal to another Unknown.
-    if (isUnknown())
-      return Other.isUnknown();
-    if (Other.isUnknown())
-      return isUnknown();
-
-    if (!hasSameAVLLatticeValue(Other))
-      return false;
-
-    // If the SEWLMULRatioOnly bits are 
diff erent, then they aren't equal.
-    if (SEWLMULRatioOnly != Other.SEWLMULRatioOnly)
-      return false;
-
-    // If only the VLMAX is valid, check that it is the same.
-    if (SEWLMULRatioOnly)
-      return hasSameVLMAX(Other);
-
-    // If the full VTYPE is valid, check that it is the same.
-    return hasSameVTYPE(Other);
-  }
-
-  bool operator!=(const VSETVLIInfo &Other) const {
-    return !(*this == Other);
-  }
-
-  // Calculate the VSETVLIInfo visible to a block assuming this and Other are
-  // both predecessors.
-  VSETVLIInfo intersect(const VSETVLIInfo &Other) const {
-    // If the new value isn't valid, ignore it.
-    if (!Other.isValid())
-      return *this;
-
-    // If this value isn't valid, this must be the first predecessor, use it.
-    if (!isValid())
-      return Other;
-
-    // If either is unknown, the result is unknown.
-    if (isUnknown() || Other.isUnknown())
-      return VSETVLIInfo::getUnknown();
-
-    // If we have an exact, match return this.
-    if (*this == Other)
-      return *this;
-
-    // Not an exact match, but maybe the AVL and VLMAX are the same. If so,
-    // return an SEW/LMUL ratio only value.
-    if (hasSameAVL(Other) && hasSameVLMAX(Other)) {
-      VSETVLIInfo MergeInfo = *this;
-      MergeInfo.SEWLMULRatioOnly = true;
-      return MergeInfo;
-    }
-
-    // Otherwise the result is unknown.
-    return VSETVLIInfo::getUnknown();
-  }
-
-#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
-  /// Support for debugging, callable in GDB: V->dump()
-  LLVM_DUMP_METHOD void dump() const {
-    print(dbgs());
-    dbgs() << "\n";
-  }
-
-  /// Implement operator<<.
-  /// @{
-  void print(raw_ostream &OS) const {
-    OS << '{';
-    switch (State) {
-    case AVLState::Uninitialized:
-      OS << "Uninitialized";
-      break;
-    case AVLState::Unknown:
-      OS << "unknown";
-      break;
-    case AVLState::AVLIsReg:
-      OS << "AVLReg=" << llvm::printReg(getAVLReg());
-      break;
-    case AVLState::AVLIsImm:
-      OS << "AVLImm=" << (unsigned)AVLImm;
-      break;
-    case AVLState::AVLIsVLMAX:
-      OS << "AVLVLMAX";
-      break;
-    }
-    if (isValid() && !isUnknown()) {
-      OS << ", ";
-
-      unsigned LMul;
-      bool Fractional;
-      std::tie(LMul, Fractional) = decodeVLMUL(VLMul);
-
-      OS << "VLMul=m";
-      if (Fractional)
-        OS << 'f';
-      OS << LMul << ", "
-         << "SEW=e" << (unsigned)SEW << ", "
-         << "TailAgnostic=" << (bool)TailAgnostic << ", "
-         << "MaskAgnostic=" << (bool)MaskAgnostic << ", "
-         << "SEWLMULRatioOnly=" << (bool)SEWLMULRatioOnly << ", "
-         << "TWiden=" << (unsigned)TWiden << ", "
-         << "AltFmt=" << (bool)AltFmt;
-    }
-
-    OS << '}';
-  }
-#endif
-};
-
-#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
-LLVM_ATTRIBUTE_USED
-inline raw_ostream &operator<<(raw_ostream &OS, const VSETVLIInfo &V) {
-  V.print(OS);
-  return OS;
-}
-#endif
-
 struct BlockData {
   // The VSETVLIInfo that represents the VL/VTYPE settings on exit from this
   // block. Calculated in Phase 2.
@@ -937,6 +94,7 @@ class RISCVInsertVSETVLI : public MachineFunctionPass {
   MachineRegisterInfo *MRI;
   // Possibly null!
   LiveIntervals *LIS;
+  RISCVVSETVLIInfoAnalysis VIA;
 
   std::vector<BlockData> BlockInfo;
   std::queue<const MachineBasicBlock *> WorkList;
@@ -982,10 +140,6 @@ class RISCVInsertVSETVLI : public MachineFunctionPass {
   bool canMutatePriorConfig(const MachineInstr &PrevMI, const MachineInstr &MI,
                             const DemandedFields &Used) const;
   void coalesceVSETVLIs(MachineBasicBlock &MBB) const;
-
-  VSETVLIInfo getInfoForVSETVLI(const MachineInstr &MI) const;
-  VSETVLIInfo computeInfoForInstr(const MachineInstr &MI) const;
-  void forwardVSETVLIAVL(VSETVLIInfo &Info) const;
   bool insertVSETMTK(MachineBasicBlock &MBB, TKTMMode Mode) const;
 };
 
@@ -997,177 +151,6 @@ char &llvm::RISCVInsertVSETVLIID = RISCVInsertVSETVLI::ID;
 INITIALIZE_PASS(RISCVInsertVSETVLI, DEBUG_TYPE, RISCV_INSERT_VSETVLI_NAME,
                 false, false)
 
-// If the AVL is defined by a vsetvli's output vl with the same VLMAX, we can
-// replace the AVL operand with the AVL of the defining vsetvli. E.g.
-//
-// %vl = PseudoVSETVLI %avl:gpr, SEW=32, LMUL=M1
-// $x0 = PseudoVSETVLI %vl:gpr, SEW=32, LMUL=M1
-// ->
-// %vl = PseudoVSETVLI %avl:gpr, SEW=32, LMUL=M1
-// $x0 = PseudoVSETVLI %avl:gpr, SEW=32, LMUL=M1
-void RISCVInsertVSETVLI::forwardVSETVLIAVL(VSETVLIInfo &Info) const {
-  if (!Info.hasAVLReg())
-    return;
-  const MachineInstr *DefMI = Info.getAVLDefMI(LIS);
-  if (!DefMI || !RISCVInstrInfo::isVectorConfigInstr(*DefMI))
-    return;
-  VSETVLIInfo DefInstrInfo = getInfoForVSETVLI(*DefMI);
-  if (!DefInstrInfo.hasSameVLMAX(Info))
-    return;
-  Info.setAVL(DefInstrInfo);
-}
-
-// Return a VSETVLIInfo representing the changes made by this VSETVLI or
-// VSETIVLI instruction.
-VSETVLIInfo
-RISCVInsertVSETVLI::getInfoForVSETVLI(const MachineInstr &MI) const {
-  VSETVLIInfo NewInfo;
-  if (MI.getOpcode() == RISCV::PseudoVSETIVLI) {
-    NewInfo.setAVLImm(MI.getOperand(1).getImm());
-  } else if (RISCVInstrInfo::isXSfmmVectorConfigTNInstr(MI)) {
-    assert(MI.getOpcode() == RISCV::PseudoSF_VSETTNT ||
-           MI.getOpcode() == RISCV::PseudoSF_VSETTNTX0);
-    switch (MI.getOpcode()) {
-    case RISCV::PseudoSF_VSETTNTX0:
-      NewInfo.setAVLVLMAX();
-      break;
-    case RISCV::PseudoSF_VSETTNT:
-      Register ATNReg = MI.getOperand(1).getReg();
-      NewInfo.setAVLRegDef(getVNInfoFromReg(ATNReg, MI, LIS), ATNReg);
-      break;
-    }
-  } else {
-    assert(MI.getOpcode() == RISCV::PseudoVSETVLI ||
-           MI.getOpcode() == RISCV::PseudoVSETVLIX0);
-    if (MI.getOpcode() == RISCV::PseudoVSETVLIX0)
-      NewInfo.setAVLVLMAX();
-    else if (MI.getOperand(1).isUndef())
-      // Otherwise use an AVL of 1 to avoid depending on previous vl.
-      NewInfo.setAVLImm(1);
-    else {
-      Register AVLReg = MI.getOperand(1).getReg();
-      VNInfo *VNI = getVNInfoFromReg(AVLReg, MI, LIS);
-      NewInfo.setAVLRegDef(VNI, AVLReg);
-    }
-  }
-  NewInfo.setVTYPE(MI.getOperand(2).getImm());
-
-  forwardVSETVLIAVL(NewInfo);
-
-  return NewInfo;
-}
-
-static unsigned computeVLMAX(unsigned VLEN, unsigned SEW,
-                             RISCVVType::VLMUL VLMul) {
-  auto [LMul, Fractional] = RISCVVType::decodeVLMUL(VLMul);
-  if (Fractional)
-    VLEN = VLEN / LMul;
-  else
-    VLEN = VLEN * LMul;
-  return VLEN/SEW;
-}
-
-VSETVLIInfo
-RISCVInsertVSETVLI::computeInfoForInstr(const MachineInstr &MI) const {
-  VSETVLIInfo InstrInfo;
-  const uint64_t TSFlags = MI.getDesc().TSFlags;
-
-  bool TailAgnostic = true;
-  bool MaskAgnostic = true;
-  if (!hasUndefinedPassthru(MI)) {
-    // Start with undisturbed.
-    TailAgnostic = false;
-    MaskAgnostic = false;
-
-    // If there is a policy operand, use it.
-    if (RISCVII::hasVecPolicyOp(TSFlags)) {
-      const MachineOperand &Op = MI.getOperand(getVecPolicyOpNum(MI));
-      uint64_t Policy = Op.getImm();
-      assert(Policy <=
-                 (RISCVVType::TAIL_AGNOSTIC | RISCVVType::MASK_AGNOSTIC) &&
-             "Invalid Policy Value");
-      TailAgnostic = Policy & RISCVVType::TAIL_AGNOSTIC;
-      MaskAgnostic = Policy & RISCVVType::MASK_AGNOSTIC;
-    }
-
-    if (!RISCVII::usesMaskPolicy(TSFlags))
-      MaskAgnostic = true;
-  }
-
-  RISCVVType::VLMUL VLMul = RISCVII::getLMul(TSFlags);
-
-  bool AltFmt = RISCVII::getAltFmtType(TSFlags) == RISCVII::AltFmtType::AltFmt;
-  InstrInfo.setAltFmt(AltFmt);
-
-  unsigned Log2SEW = MI.getOperand(getSEWOpNum(MI)).getImm();
-  // A Log2SEW of 0 is an operation on mask registers only.
-  unsigned SEW = Log2SEW ? 1 << Log2SEW : 8;
-  assert(RISCVVType::isValidSEW(SEW) && "Unexpected SEW");
-
-  if (RISCVII::hasTWidenOp(TSFlags)) {
-    const MachineOperand &TWidenOp =
-        MI.getOperand(MI.getNumExplicitOperands() - 1);
-    unsigned TWiden = TWidenOp.getImm();
-
-    InstrInfo.setAVLVLMAX();
-    if (RISCVII::hasVLOp(TSFlags)) {
-      const MachineOperand &TNOp =
-          MI.getOperand(RISCVII::getTNOpNum(MI.getDesc()));
-
-      if (TNOp.getReg().isVirtual())
-        InstrInfo.setAVLRegDef(getVNInfoFromReg(TNOp.getReg(), MI, LIS),
-                               TNOp.getReg());
-    }
-
-    InstrInfo.setVTYPE(VLMul, SEW, TailAgnostic, MaskAgnostic, AltFmt, TWiden);
-
-    return InstrInfo;
-  }
-
-  if (RISCVII::hasVLOp(TSFlags)) {
-    const MachineOperand &VLOp = MI.getOperand(getVLOpNum(MI));
-    if (VLOp.isImm()) {
-      int64_t Imm = VLOp.getImm();
-      // Convert the VLMax sentintel to X0 register.
-      if (Imm == RISCV::VLMaxSentinel) {
-        // If we know the exact VLEN, see if we can use the constant encoding
-        // for the VLMAX instead.  This reduces register pressure slightly.
-        const unsigned VLMAX = computeVLMAX(ST->getRealMaxVLen(), SEW, VLMul);
-        if (ST->getRealMinVLen() == ST->getRealMaxVLen() && VLMAX <= 31)
-          InstrInfo.setAVLImm(VLMAX);
-        else
-          InstrInfo.setAVLVLMAX();
-      }
-      else
-        InstrInfo.setAVLImm(Imm);
-    } else if (VLOp.isUndef()) {
-      // Otherwise use an AVL of 1 to avoid depending on previous vl.
-      InstrInfo.setAVLImm(1);
-    } else {
-      VNInfo *VNI = getVNInfoFromReg(VLOp.getReg(), MI, LIS);
-      InstrInfo.setAVLRegDef(VNI, VLOp.getReg());
-    }
-  } else {
-    assert(RISCVInstrInfo::isScalarExtractInstr(MI) ||
-           RISCVInstrInfo::isVExtractInstr(MI));
-    // Pick a random value for state tracking purposes, will be ignored via
-    // the demanded fields mechanism
-    InstrInfo.setAVLImm(1);
-  }
-#ifndef NDEBUG
-  if (std::optional<unsigned> EEW = getEEWForLoadStore(MI)) {
-    assert(SEW == EEW && "Initial SEW doesn't match expected EEW");
-  }
-#endif
-  // TODO: Propagate the twiden from previous vtype for potential reuse.
-  InstrInfo.setVTYPE(VLMul, SEW, TailAgnostic, MaskAgnostic, AltFmt,
-                     /*TWiden*/ 0);
-
-  forwardVSETVLIAVL(InstrInfo);
-
-  return InstrInfo;
-}
-
 void RISCVInsertVSETVLI::insertVSETVLI(MachineBasicBlock &MBB,
                                        MachineBasicBlock::iterator InsertPt,
                                        DebugLoc DL, const VSETVLIInfo &Info,
@@ -1216,7 +199,7 @@ void RISCVInsertVSETVLI::insertVSETVLI(MachineBasicBlock &MBB,
     if (Info.hasSameVLMAX(PrevInfo) && Info.hasAVLReg()) {
       if (const MachineInstr *DefMI = Info.getAVLDefMI(LIS);
           DefMI && RISCVInstrInfo::isVectorConfigInstr(*DefMI)) {
-        VSETVLIInfo DefInfo = getInfoForVSETVLI(*DefMI);
+        VSETVLIInfo DefInfo = VIA.getInfoForVSETVLI(*DefMI);
         if (DefInfo.hasSameAVL(PrevInfo) && DefInfo.hasSameVLMAX(PrevInfo)) {
           auto MI =
               BuildMI(MBB, InsertPt, DL, TII->get(RISCV::PseudoVSETVLIX0X0))
@@ -1331,7 +314,7 @@ static VSETVLIInfo adjustIncoming(const VSETVLIInfo &PrevInfo,
 // legal for MI, but may not be the state requested by MI.
 void RISCVInsertVSETVLI::transferBefore(VSETVLIInfo &Info,
                                         const MachineInstr &MI) const {
-  if (isVectorCopy(ST->getRegisterInfo(), MI) &&
+  if (RISCV::isVectorCopy(ST->getRegisterInfo(), MI) &&
       (Info.isUnknown() || !Info.isValid() || Info.hasSEWLMULRatioOnly())) {
     // Use an arbitrary but valid AVL and VTYPE so vill will be cleared. It may
     // be coalesced into another vsetvli since we won't demand any fields.
@@ -1348,7 +331,7 @@ void RISCVInsertVSETVLI::transferBefore(VSETVLIInfo &Info,
 
   DemandedFields Demanded = getDemanded(MI, ST);
 
-  const VSETVLIInfo NewInfo = computeInfoForInstr(MI);
+  const VSETVLIInfo NewInfo = VIA.computeInfoForInstr(MI);
   assert(NewInfo.isValid() && !NewInfo.isUnknown());
   if (Info.isValid() && !needVSETVLI(Demanded, NewInfo, Info))
     return;
@@ -1399,7 +382,7 @@ void RISCVInsertVSETVLI::transferBefore(VSETVLIInfo &Info,
 void RISCVInsertVSETVLI::transferAfter(VSETVLIInfo &Info,
                                        const MachineInstr &MI) const {
   if (RISCVInstrInfo::isVectorConfigInstr(MI)) {
-    Info = getInfoForVSETVLI(MI);
+    Info = VIA.getInfoForVSETVLI(MI);
     return;
   }
 
@@ -1435,7 +418,7 @@ bool RISCVInsertVSETVLI::computeVLVTYPEChanges(const MachineBasicBlock &MBB,
 
     if (RISCVInstrInfo::isVectorConfigInstr(MI) ||
         RISCVII::hasSEWOp(MI.getDesc().TSFlags) ||
-        isVectorCopy(ST->getRegisterInfo(), MI) ||
+        RISCV::isVectorCopy(ST->getRegisterInfo(), MI) ||
         RISCVInstrInfo::isXSfmmVectorConfigInstr(MI))
       HadVectorOp = true;
 
@@ -1530,7 +513,7 @@ bool RISCVInsertVSETVLI::needVSETVLIPHI(const VSETVLIInfo &Require,
 
     // We found a VSET(I)VLI make sure it matches the output of the
     // predecessor block.
-    VSETVLIInfo DefInfo = getInfoForVSETVLI(*DefMI);
+    VSETVLIInfo DefInfo = VIA.getInfoForVSETVLI(*DefMI);
     if (DefInfo != PBBExit)
       return true;
 
@@ -1567,7 +550,7 @@ void RISCVInsertVSETVLI::emitVSETVLIs(MachineBasicBlock &MBB) {
     }
 
     if (EnsureWholeVectorRegisterMoveValidVTYPE &&
-        isVectorCopy(ST->getRegisterInfo(), MI)) {
+        RISCV::isVectorCopy(ST->getRegisterInfo(), MI)) {
       if (!PrevInfo.isCompatible(DemandedFields::all(), CurInfo, LIS)) {
         insertVSETVLI(MBB, MI, MI.getDebugLoc(), CurInfo, PrevInfo);
         PrefixTransparent = false;
@@ -1773,8 +756,8 @@ bool RISCVInsertVSETVLI::canMutatePriorConfig(
     if (Used.VLZeroness) {
       if (RISCVInstrInfo::isVLPreservingConfig(PrevMI))
         return false;
-      if (!getInfoForVSETVLI(PrevMI).hasEquallyZeroAVL(getInfoForVSETVLI(MI),
-                                                       LIS))
+      if (!VIA.getInfoForVSETVLI(PrevMI).hasEquallyZeroAVL(
+              VIA.getInfoForVSETVLI(MI), LIS))
         return false;
     }
 
@@ -1962,7 +945,7 @@ bool RISCVInsertVSETVLI::insertVSETMTK(MachineBasicBlock &MBB,
         !RISCVII::hasSEWOp(TSFlags) || !RISCVII::hasTWidenOp(TSFlags))
       continue;
 
-    VSETVLIInfo CurrInfo = computeInfoForInstr(MI);
+    VSETVLIInfo CurrInfo = VIA.computeInfoForInstr(MI);
 
     if (Mode == VSETTK && !RISCVII::hasTKOp(TSFlags))
       continue;
@@ -2023,6 +1006,7 @@ bool RISCVInsertVSETVLI::runOnMachineFunction(MachineFunction &MF) {
   MRI = &MF.getRegInfo();
   auto *LISWrapper = getAnalysisIfAvailable<LiveIntervalsWrapperPass>();
   LIS = LISWrapper ? &LISWrapper->getLIS() : nullptr;
+  VIA = RISCVVSETVLIInfoAnalysis(ST, LIS);
 
   assert(BlockInfo.empty() && "Expect empty block infos");
   BlockInfo.resize(MF.getNumBlockIDs());

diff  --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
index 400b680a3ff12..5a717654e385c 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
@@ -4917,6 +4917,14 @@ bool RISCV::isRVVSpill(const MachineInstr &MI) {
   return true;
 }
 
+/// Return true if \p MI is a copy that will be lowered to one or more vmvNr.vs.
+bool RISCV::isVectorCopy(const TargetRegisterInfo *TRI,
+                         const MachineInstr &MI) {
+  return MI.isCopy() && MI.getOperand(0).getReg().isPhysical() &&
+         RISCVRegisterInfo::isRVVRegClass(
+             TRI->getMinimalPhysRegClass(MI.getOperand(0).getReg()));
+}
+
 std::optional<std::pair<unsigned, unsigned>>
 RISCV::isRVVSpillForZvlsseg(unsigned Opcode) {
   switch (Opcode) {

diff  --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.h b/llvm/lib/Target/RISCV/RISCVInstrInfo.h
index 93c9c7fc3edb1..741a514d82bdd 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.h
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.h
@@ -372,6 +372,9 @@ namespace RISCV {
 // expect to see a FrameIndex operand.
 bool isRVVSpill(const MachineInstr &MI);
 
+/// Return true if \p MI is a copy that will be lowered to one or more vmvNr.vs.
+bool isVectorCopy(const TargetRegisterInfo *TRI, const MachineInstr &MI);
+
 std::optional<std::pair<unsigned, unsigned>>
 isRVVSpillForZvlsseg(unsigned Opcode);
 

diff  --git a/llvm/lib/Target/RISCV/RISCVVSETVLIInfoAnalysis.cpp b/llvm/lib/Target/RISCV/RISCVVSETVLIInfoAnalysis.cpp
new file mode 100644
index 0000000000000..3fa9baea6de14
--- /dev/null
+++ b/llvm/lib/Target/RISCV/RISCVVSETVLIInfoAnalysis.cpp
@@ -0,0 +1,501 @@
+//===- RISCVVSETVLIInfoAnalysis.cpp - VSETVLI Info Analysis ---------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements an analysis of the vtype/vl information that is needed
+// by RISCVInsertVSETVLI pass and others.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RISCVVSETVLIInfoAnalysis.h"
+#include "RISCVSubtarget.h"
+#include "llvm/CodeGen/LiveIntervals.h"
+
+namespace llvm {
+namespace RISCV {
+
+/// Given a virtual register \p Reg, return the corresponding VNInfo for it.
+/// This will return nullptr if the virtual register is an implicit_def or
+/// if LiveIntervals is not available.
+static VNInfo *getVNInfoFromReg(Register Reg, const MachineInstr &MI,
+                                const LiveIntervals *LIS) {
+  assert(Reg.isVirtual());
+  if (!LIS)
+    return nullptr;
+  auto &LI = LIS->getInterval(Reg);
+  SlotIndex SI = LIS->getSlotIndexes()->getInstructionIndex(MI);
+  return LI.getVNInfoBefore(SI);
+}
+
+static unsigned getVLOpNum(const MachineInstr &MI) {
+  return RISCVII::getVLOpNum(MI.getDesc());
+}
+
+static unsigned getSEWOpNum(const MachineInstr &MI) {
+  return RISCVII::getSEWOpNum(MI.getDesc());
+}
+
+static unsigned getVecPolicyOpNum(const MachineInstr &MI) {
+  return RISCVII::getVecPolicyOpNum(MI.getDesc());
+}
+
+/// Get the EEW for a load or store instruction.  Return std::nullopt if MI is
+/// not a load or store which ignores SEW.
+static std::optional<unsigned> getEEWForLoadStore(const MachineInstr &MI) {
+  switch (RISCV::getRVVMCOpcode(MI.getOpcode())) {
+  default:
+    return std::nullopt;
+  case RISCV::VLE8_V:
+  case RISCV::VLSE8_V:
+  case RISCV::VSE8_V:
+  case RISCV::VSSE8_V:
+    return 8;
+  case RISCV::VLE16_V:
+  case RISCV::VLSE16_V:
+  case RISCV::VSE16_V:
+  case RISCV::VSSE16_V:
+    return 16;
+  case RISCV::VLE32_V:
+  case RISCV::VLSE32_V:
+  case RISCV::VSE32_V:
+  case RISCV::VSSE32_V:
+    return 32;
+  case RISCV::VLE64_V:
+  case RISCV::VLSE64_V:
+  case RISCV::VSE64_V:
+  case RISCV::VSSE64_V:
+    return 64;
+  }
+}
+
+/// Return true if this is an operation on mask registers.  Note that
+/// this includes both arithmetic/logical ops and load/store (vlm/vsm).
+static bool isMaskRegOp(const MachineInstr &MI) {
+  if (!RISCVII::hasSEWOp(MI.getDesc().TSFlags))
+    return false;
+  const unsigned Log2SEW = MI.getOperand(getSEWOpNum(MI)).getImm();
+  // A Log2SEW of 0 is an operation on mask registers only.
+  return Log2SEW == 0;
+}
+
+/// Return true if the inactive elements in the result are entirely undefined.
+/// Note that this is 
diff erent from "agnostic" as defined by the vector
+/// specification.  Agnostic requires each lane to either be undisturbed, or
+/// take the value -1; no other value is allowed.
+static bool hasUndefinedPassthru(const MachineInstr &MI) {
+  unsigned UseOpIdx;
+  if (!MI.isRegTiedToUseOperand(0, &UseOpIdx))
+    // If there is no passthrough operand, then the pass through
+    // lanes are undefined.
+    return true;
+
+  // All undefined passthrus should be $noreg: see
+  // RISCVDAGToDAGISel::doPeepholeNoRegPassThru
+  const MachineOperand &UseMO = MI.getOperand(UseOpIdx);
+  return !UseMO.getReg().isValid() || UseMO.isUndef();
+}
+
+static bool isLMUL1OrSmaller(RISCVVType::VLMUL LMUL) {
+  auto [LMul, Fractional] = RISCVVType::decodeVLMUL(LMUL);
+  return Fractional || LMul == 1;
+}
+
+/// Return true if moving from CurVType to NewVType is
+/// indistinguishable from the perspective of an instruction (or set
+/// of instructions) which use only the Used subfields and properties.
+bool areCompatibleVTYPEs(uint64_t CurVType, uint64_t NewVType,
+                         const DemandedFields &Used) {
+  switch (Used.SEW) {
+  case DemandedFields::SEWNone:
+    break;
+  case DemandedFields::SEWEqual:
+    if (RISCVVType::getSEW(CurVType) != RISCVVType::getSEW(NewVType))
+      return false;
+    break;
+  case DemandedFields::SEWGreaterThanOrEqual:
+    if (RISCVVType::getSEW(NewVType) < RISCVVType::getSEW(CurVType))
+      return false;
+    break;
+  case DemandedFields::SEWGreaterThanOrEqualAndLessThan64:
+    if (RISCVVType::getSEW(NewVType) < RISCVVType::getSEW(CurVType) ||
+        RISCVVType::getSEW(NewVType) >= 64)
+      return false;
+    break;
+  }
+
+  switch (Used.LMUL) {
+  case DemandedFields::LMULNone:
+    break;
+  case DemandedFields::LMULEqual:
+    if (RISCVVType::getVLMUL(CurVType) != RISCVVType::getVLMUL(NewVType))
+      return false;
+    break;
+  case DemandedFields::LMULLessThanOrEqualToM1:
+    if (!isLMUL1OrSmaller(RISCVVType::getVLMUL(NewVType)))
+      return false;
+    break;
+  }
+
+  if (Used.SEWLMULRatio) {
+    auto Ratio1 = RISCVVType::getSEWLMULRatio(RISCVVType::getSEW(CurVType),
+                                              RISCVVType::getVLMUL(CurVType));
+    auto Ratio2 = RISCVVType::getSEWLMULRatio(RISCVVType::getSEW(NewVType),
+                                              RISCVVType::getVLMUL(NewVType));
+    if (Ratio1 != Ratio2)
+      return false;
+  }
+
+  if (Used.TailPolicy && RISCVVType::isTailAgnostic(CurVType) !=
+                             RISCVVType::isTailAgnostic(NewVType))
+    return false;
+  if (Used.MaskPolicy && RISCVVType::isMaskAgnostic(CurVType) !=
+                             RISCVVType::isMaskAgnostic(NewVType))
+    return false;
+  if (Used.TWiden && (RISCVVType::hasXSfmmWiden(CurVType) !=
+                          RISCVVType::hasXSfmmWiden(NewVType) ||
+                      (RISCVVType::hasXSfmmWiden(CurVType) &&
+                       RISCVVType::getXSfmmWiden(CurVType) !=
+                           RISCVVType::getXSfmmWiden(NewVType))))
+    return false;
+  if (Used.AltFmt &&
+      RISCVVType::isAltFmt(CurVType) != RISCVVType::isAltFmt(NewVType))
+    return false;
+  return true;
+}
+
+/// Return the fields and properties demanded by the provided instruction.
+DemandedFields getDemanded(const MachineInstr &MI, const RISCVSubtarget *ST) {
+  // This function works in coalesceVSETVLI too. We can still use the value of a
+  // SEW, VL, or Policy operand even though it might not be the exact value in
+  // the VL or VTYPE, since we only care about what the instruction originally
+  // demanded.
+
+  // Most instructions don't use any of these subfeilds.
+  DemandedFields Res;
+  // Start conservative if registers are used
+  if (MI.isCall() || MI.isInlineAsm() ||
+      MI.readsRegister(RISCV::VL, /*TRI=*/nullptr))
+    Res.demandVL();
+  if (MI.isCall() || MI.isInlineAsm() ||
+      MI.readsRegister(RISCV::VTYPE, /*TRI=*/nullptr))
+    Res.demandVTYPE();
+  // Start conservative on the unlowered form too
+  uint64_t TSFlags = MI.getDesc().TSFlags;
+  if (RISCVII::hasSEWOp(TSFlags)) {
+    Res.demandVTYPE();
+    if (RISCVII::hasVLOp(TSFlags))
+      if (const MachineOperand &VLOp = MI.getOperand(getVLOpNum(MI));
+          !VLOp.isReg() || !VLOp.isUndef())
+        Res.demandVL();
+
+    // Behavior is independent of mask policy.
+    if (!RISCVII::usesMaskPolicy(TSFlags))
+      Res.MaskPolicy = false;
+  }
+
+  // Loads and stores with implicit EEW do not demand SEW or LMUL directly.
+  // They instead demand the ratio of the two which is used in computing
+  // EMUL, but which allows us the flexibility to change SEW and LMUL
+  // provided we don't change the ratio.
+  // Note: We assume that the instructions initial SEW is the EEW encoded
+  // in the opcode.  This is asserted when constructing the VSETVLIInfo.
+  if (RISCV::getEEWForLoadStore(MI)) {
+    Res.SEW = DemandedFields::SEWNone;
+    Res.LMUL = DemandedFields::LMULNone;
+  }
+
+  // Store instructions don't use the policy fields.
+  if (RISCVII::hasSEWOp(TSFlags) && MI.getNumExplicitDefs() == 0) {
+    Res.TailPolicy = false;
+    Res.MaskPolicy = false;
+  }
+
+  // If this is a mask reg operation, it only cares about VLMAX.
+  // TODO: Possible extensions to this logic
+  // * Probably ok if available VLMax is larger than demanded
+  // * The policy bits can probably be ignored..
+  if (isMaskRegOp(MI)) {
+    Res.SEW = DemandedFields::SEWNone;
+    Res.LMUL = DemandedFields::LMULNone;
+  }
+
+  // For vmv.s.x and vfmv.s.f, there are only two behaviors, VL = 0 and VL > 0.
+  if (RISCVInstrInfo::isScalarInsertInstr(MI)) {
+    Res.LMUL = DemandedFields::LMULNone;
+    Res.SEWLMULRatio = false;
+    Res.VLAny = false;
+    // For vmv.s.x and vfmv.s.f, if the passthru is *undefined*, we don't
+    // need to preserve any other bits and are thus compatible with any larger,
+    // etype and can disregard policy bits.  Warning: It's tempting to try doing
+    // this for any tail agnostic operation, but we can't as TA requires
+    // tail lanes to either be the original value or -1.  We are writing
+    // unknown bits to the lanes here.
+    if (RISCV::hasUndefinedPassthru(MI)) {
+      if (RISCVInstrInfo::isFloatScalarMoveOrScalarSplatInstr(MI) &&
+          !ST->hasVInstructionsF64())
+        Res.SEW = DemandedFields::SEWGreaterThanOrEqualAndLessThan64;
+      else
+        Res.SEW = DemandedFields::SEWGreaterThanOrEqual;
+      Res.TailPolicy = false;
+    }
+  }
+
+  // vmv.x.s, and vfmv.f.s are unconditional and ignore everything except SEW.
+  if (RISCVInstrInfo::isScalarExtractInstr(MI)) {
+    assert(!RISCVII::hasVLOp(TSFlags));
+    Res.LMUL = DemandedFields::LMULNone;
+    Res.SEWLMULRatio = false;
+    Res.TailPolicy = false;
+    Res.MaskPolicy = false;
+  }
+
+  if (RISCVII::hasVLOp(MI.getDesc().TSFlags)) {
+    const MachineOperand &VLOp = MI.getOperand(getVLOpNum(MI));
+    // A slidedown/slideup with an *undefined* passthru can freely clobber
+    // elements not copied from the source vector (e.g. masked off, tail, or
+    // slideup's prefix). Notes:
+    // * We can't modify SEW here since the slide amount is in units of SEW.
+    // * VL=1 is special only because we have existing support for zero vs
+    //   non-zero VL.  We could generalize this if we had a VL > C predicate.
+    // * The LMUL1 restriction is for machines whose latency may depend on LMUL.
+    // * As above, this is only legal for tail "undefined" not "agnostic".
+    // * We avoid increasing vl if the subtarget has +vl-dependent-latency
+    if (RISCVInstrInfo::isVSlideInstr(MI) && VLOp.isImm() &&
+        VLOp.getImm() == 1 && RISCV::hasUndefinedPassthru(MI) &&
+        !ST->hasVLDependentLatency()) {
+      Res.VLAny = false;
+      Res.VLZeroness = true;
+      Res.LMUL = DemandedFields::LMULLessThanOrEqualToM1;
+      Res.TailPolicy = false;
+    }
+
+    // A tail undefined vmv.v.i/x or vfmv.v.f with VL=1 can be treated in the
+    // same semantically as vmv.s.x.  This is particularly useful since we don't
+    // have an immediate form of vmv.s.x, and thus frequently use vmv.v.i in
+    // it's place. Since a splat is non-constant time in LMUL, we do need to be
+    // careful to not increase the number of active vector registers (unlike for
+    // vmv.s.x.)
+    if (RISCVInstrInfo::isScalarSplatInstr(MI) && VLOp.isImm() &&
+        VLOp.getImm() == 1 && RISCV::hasUndefinedPassthru(MI) &&
+        !ST->hasVLDependentLatency()) {
+      Res.LMUL = DemandedFields::LMULLessThanOrEqualToM1;
+      Res.SEWLMULRatio = false;
+      Res.VLAny = false;
+      if (RISCVInstrInfo::isFloatScalarMoveOrScalarSplatInstr(MI) &&
+          !ST->hasVInstructionsF64())
+        Res.SEW = DemandedFields::SEWGreaterThanOrEqualAndLessThan64;
+      else
+        Res.SEW = DemandedFields::SEWGreaterThanOrEqual;
+      Res.TailPolicy = false;
+    }
+  }
+
+  // In §32.16.6, whole vector register moves have a dependency on SEW. At the
+  // MIR level though we don't encode the element type, and it gives the same
+  // result whatever the SEW may be.
+  //
+  // However it does need valid SEW, i.e. vill must be cleared. The entry to a
+  // function, calls and inline assembly may all set it, so make sure we clear
+  // it for whole register copies. Do this by leaving VILL demanded.
+  if (RISCV::isVectorCopy(ST->getRegisterInfo(), MI)) {
+    Res.LMUL = DemandedFields::LMULNone;
+    Res.SEW = DemandedFields::SEWNone;
+    Res.SEWLMULRatio = false;
+    Res.TailPolicy = false;
+    Res.MaskPolicy = false;
+  }
+
+  if (RISCVInstrInfo::isVExtractInstr(MI)) {
+    assert(!RISCVII::hasVLOp(TSFlags));
+    // TODO: LMUL can be any larger value (without cost)
+    Res.TailPolicy = false;
+  }
+
+  Res.AltFmt = RISCVII::getAltFmtType(MI.getDesc().TSFlags) !=
+               RISCVII::AltFmtType::DontCare;
+  Res.TWiden = RISCVII::hasTWidenOp(MI.getDesc().TSFlags) ||
+               RISCVInstrInfo::isXSfmmVectorConfigInstr(MI);
+
+  return Res;
+}
+
+bool VSETVLIInfo::hasCompatibleVTYPE(const DemandedFields &Used,
+                                     const VSETVLIInfo &Require) const {
+  return areCompatibleVTYPEs(Require.encodeVTYPE(), encodeVTYPE(), Used);
+}
+
+// If the AVL is defined by a vsetvli's output vl with the same VLMAX, we can
+// replace the AVL operand with the AVL of the defining vsetvli. E.g.
+//
+// %vl = PseudoVSETVLI %avl:gpr, SEW=32, LMUL=M1
+// $x0 = PseudoVSETVLI %vl:gpr, SEW=32, LMUL=M1
+// ->
+// %vl = PseudoVSETVLI %avl:gpr, SEW=32, LMUL=M1
+// $x0 = PseudoVSETVLI %avl:gpr, SEW=32, LMUL=M1
+void RISCVVSETVLIInfoAnalysis::forwardVSETVLIAVL(VSETVLIInfo &Info) const {
+  if (!Info.hasAVLReg())
+    return;
+  const MachineInstr *DefMI = Info.getAVLDefMI(LIS);
+  if (!DefMI || !RISCVInstrInfo::isVectorConfigInstr(*DefMI))
+    return;
+  VSETVLIInfo DefInstrInfo = getInfoForVSETVLI(*DefMI);
+  if (!DefInstrInfo.hasSameVLMAX(Info))
+    return;
+  Info.setAVL(DefInstrInfo);
+}
+
+// Return a VSETVLIInfo representing the changes made by this VSETVLI or
+// VSETIVLI instruction.
+VSETVLIInfo
+RISCVVSETVLIInfoAnalysis::getInfoForVSETVLI(const MachineInstr &MI) const {
+  VSETVLIInfo NewInfo;
+  if (MI.getOpcode() == RISCV::PseudoVSETIVLI) {
+    NewInfo.setAVLImm(MI.getOperand(1).getImm());
+  } else if (RISCVInstrInfo::isXSfmmVectorConfigTNInstr(MI)) {
+    assert(MI.getOpcode() == RISCV::PseudoSF_VSETTNT ||
+           MI.getOpcode() == RISCV::PseudoSF_VSETTNTX0);
+    switch (MI.getOpcode()) {
+    case RISCV::PseudoSF_VSETTNTX0:
+      NewInfo.setAVLVLMAX();
+      break;
+    case RISCV::PseudoSF_VSETTNT:
+      Register ATNReg = MI.getOperand(1).getReg();
+      NewInfo.setAVLRegDef(getVNInfoFromReg(ATNReg, MI, LIS), ATNReg);
+      break;
+    }
+  } else {
+    assert(MI.getOpcode() == RISCV::PseudoVSETVLI ||
+           MI.getOpcode() == RISCV::PseudoVSETVLIX0);
+    if (MI.getOpcode() == RISCV::PseudoVSETVLIX0)
+      NewInfo.setAVLVLMAX();
+    else if (MI.getOperand(1).isUndef())
+      // Otherwise use an AVL of 1 to avoid depending on previous vl.
+      NewInfo.setAVLImm(1);
+    else {
+      Register AVLReg = MI.getOperand(1).getReg();
+      VNInfo *VNI = getVNInfoFromReg(AVLReg, MI, LIS);
+      NewInfo.setAVLRegDef(VNI, AVLReg);
+    }
+  }
+  NewInfo.setVTYPE(MI.getOperand(2).getImm());
+
+  forwardVSETVLIAVL(NewInfo);
+
+  return NewInfo;
+}
+
+static unsigned computeVLMAX(unsigned VLEN, unsigned SEW,
+                             RISCVVType::VLMUL VLMul) {
+  auto [LMul, Fractional] = RISCVVType::decodeVLMUL(VLMul);
+  if (Fractional)
+    VLEN = VLEN / LMul;
+  else
+    VLEN = VLEN * LMul;
+  return VLEN / SEW;
+}
+
+VSETVLIInfo
+RISCVVSETVLIInfoAnalysis::computeInfoForInstr(const MachineInstr &MI) const {
+  VSETVLIInfo InstrInfo;
+  const uint64_t TSFlags = MI.getDesc().TSFlags;
+
+  bool TailAgnostic = true;
+  bool MaskAgnostic = true;
+  if (!RISCV::hasUndefinedPassthru(MI)) {
+    // Start with undisturbed.
+    TailAgnostic = false;
+    MaskAgnostic = false;
+
+    // If there is a policy operand, use it.
+    if (RISCVII::hasVecPolicyOp(TSFlags)) {
+      const MachineOperand &Op = MI.getOperand(getVecPolicyOpNum(MI));
+      uint64_t Policy = Op.getImm();
+      assert(Policy <=
+                 (RISCVVType::TAIL_AGNOSTIC | RISCVVType::MASK_AGNOSTIC) &&
+             "Invalid Policy Value");
+      TailAgnostic = Policy & RISCVVType::TAIL_AGNOSTIC;
+      MaskAgnostic = Policy & RISCVVType::MASK_AGNOSTIC;
+    }
+
+    if (!RISCVII::usesMaskPolicy(TSFlags))
+      MaskAgnostic = true;
+  }
+
+  RISCVVType::VLMUL VLMul = RISCVII::getLMul(TSFlags);
+
+  bool AltFmt = RISCVII::getAltFmtType(TSFlags) == RISCVII::AltFmtType::AltFmt;
+  InstrInfo.setAltFmt(AltFmt);
+
+  unsigned Log2SEW = MI.getOperand(getSEWOpNum(MI)).getImm();
+  // A Log2SEW of 0 is an operation on mask registers only.
+  unsigned SEW = Log2SEW ? 1 << Log2SEW : 8;
+  assert(RISCVVType::isValidSEW(SEW) && "Unexpected SEW");
+
+  if (RISCVII::hasTWidenOp(TSFlags)) {
+    const MachineOperand &TWidenOp =
+        MI.getOperand(MI.getNumExplicitOperands() - 1);
+    unsigned TWiden = TWidenOp.getImm();
+
+    InstrInfo.setAVLVLMAX();
+    if (RISCVII::hasVLOp(TSFlags)) {
+      const MachineOperand &TNOp =
+          MI.getOperand(RISCVII::getTNOpNum(MI.getDesc()));
+
+      if (TNOp.getReg().isVirtual())
+        InstrInfo.setAVLRegDef(getVNInfoFromReg(TNOp.getReg(), MI, LIS),
+                               TNOp.getReg());
+    }
+
+    InstrInfo.setVTYPE(VLMul, SEW, TailAgnostic, MaskAgnostic, AltFmt, TWiden);
+
+    return InstrInfo;
+  }
+
+  if (RISCVII::hasVLOp(TSFlags)) {
+    const MachineOperand &VLOp = MI.getOperand(getVLOpNum(MI));
+    if (VLOp.isImm()) {
+      int64_t Imm = VLOp.getImm();
+      // Convert the VLMax sentintel to X0 register.
+      if (Imm == RISCV::VLMaxSentinel) {
+        // If we know the exact VLEN, see if we can use the constant encoding
+        // for the VLMAX instead.  This reduces register pressure slightly.
+        const unsigned VLMAX = computeVLMAX(ST->getRealMaxVLen(), SEW, VLMul);
+        if (ST->getRealMinVLen() == ST->getRealMaxVLen() && VLMAX <= 31)
+          InstrInfo.setAVLImm(VLMAX);
+        else
+          InstrInfo.setAVLVLMAX();
+      } else
+        InstrInfo.setAVLImm(Imm);
+    } else if (VLOp.isUndef()) {
+      // Otherwise use an AVL of 1 to avoid depending on previous vl.
+      InstrInfo.setAVLImm(1);
+    } else {
+      VNInfo *VNI = getVNInfoFromReg(VLOp.getReg(), MI, LIS);
+      InstrInfo.setAVLRegDef(VNI, VLOp.getReg());
+    }
+  } else {
+    assert(RISCVInstrInfo::isScalarExtractInstr(MI) ||
+           RISCVInstrInfo::isVExtractInstr(MI));
+    // Pick a random value for state tracking purposes, will be ignored via
+    // the demanded fields mechanism
+    InstrInfo.setAVLImm(1);
+  }
+#ifndef NDEBUG
+  if (std::optional<unsigned> EEW = RISCV::getEEWForLoadStore(MI)) {
+    assert(SEW == EEW && "Initial SEW doesn't match expected EEW");
+  }
+#endif
+  // TODO: Propagate the twiden from previous vtype for potential reuse.
+  InstrInfo.setVTYPE(VLMul, SEW, TailAgnostic, MaskAgnostic, AltFmt,
+                     /*TWiden*/ 0);
+
+  forwardVSETVLIAVL(InstrInfo);
+
+  return InstrInfo;
+}
+} // namespace RISCV
+} // namespace llvm

diff  --git a/llvm/lib/Target/RISCV/RISCVVSETVLIInfoAnalysis.h b/llvm/lib/Target/RISCV/RISCVVSETVLIInfoAnalysis.h
new file mode 100644
index 0000000000000..ec8b8c3fc9812
--- /dev/null
+++ b/llvm/lib/Target/RISCV/RISCVVSETVLIInfoAnalysis.h
@@ -0,0 +1,589 @@
+//===- RISCVVSETVLIInfoAnalysis.h - VSETVLI Info Analysis -----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements an analysis of the vtype/vl information that is needed
+// by RISCVInsertVSETVLI pass and others.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RISCV.h"
+#include "RISCVSubtarget.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/CodeGen/LiveDebugVariables.h"
+#include "llvm/CodeGen/LiveIntervals.h"
+#include "llvm/CodeGen/LiveStacks.h"
+
+namespace llvm {
+namespace RISCV {
+/// Which subfields of VL or VTYPE have values we need to preserve?
+struct DemandedFields {
+  // Some unknown property of VL is used.  If demanded, must preserve entire
+  // value.
+  bool VLAny = false;
+  // Only zero vs non-zero is used. If demanded, can change non-zero values.
+  bool VLZeroness = false;
+  // What properties of SEW we need to preserve.
+  enum : uint8_t {
+    SEWEqual = 3, // The exact value of SEW needs to be preserved.
+    SEWGreaterThanOrEqualAndLessThan64 =
+        2, // SEW can be changed as long as it's greater
+           // than or equal to the original value, but must be less
+           // than 64.
+    SEWGreaterThanOrEqual = 1, // SEW can be changed as long as it's greater
+                               // than or equal to the original value.
+    SEWNone = 0                // We don't need to preserve SEW at all.
+  } SEW = SEWNone;
+  enum : uint8_t {
+    LMULEqual = 2, // The exact value of LMUL needs to be preserved.
+    LMULLessThanOrEqualToM1 = 1, // We can use any LMUL <= M1.
+    LMULNone = 0                 // We don't need to preserve LMUL at all.
+  } LMUL = LMULNone;
+  bool SEWLMULRatio = false;
+  bool TailPolicy = false;
+  bool MaskPolicy = false;
+  // If this is true, we demand that VTYPE is set to some legal state, i.e. that
+  // vill is unset.
+  bool VILL = false;
+  bool TWiden = false;
+  bool AltFmt = false;
+
+  // Return true if any part of VTYPE was used
+  bool usedVTYPE() const {
+    return SEW || LMUL || SEWLMULRatio || TailPolicy || MaskPolicy || VILL ||
+           TWiden || AltFmt;
+  }
+
+  // Return true if any property of VL was used
+  bool usedVL() { return VLAny || VLZeroness; }
+
+  // Mark all VTYPE subfields and properties as demanded
+  void demandVTYPE() {
+    SEW = SEWEqual;
+    LMUL = LMULEqual;
+    SEWLMULRatio = true;
+    TailPolicy = true;
+    MaskPolicy = true;
+    VILL = true;
+    TWiden = true;
+    AltFmt = true;
+  }
+
+  // Mark all VL properties as demanded
+  void demandVL() {
+    VLAny = true;
+    VLZeroness = true;
+  }
+
+  static DemandedFields all() {
+    DemandedFields DF;
+    DF.demandVTYPE();
+    DF.demandVL();
+    return DF;
+  }
+
+  // Make this the result of demanding both the fields in this and B.
+  void doUnion(const DemandedFields &B) {
+    VLAny |= B.VLAny;
+    VLZeroness |= B.VLZeroness;
+    SEW = std::max(SEW, B.SEW);
+    LMUL = std::max(LMUL, B.LMUL);
+    SEWLMULRatio |= B.SEWLMULRatio;
+    TailPolicy |= B.TailPolicy;
+    MaskPolicy |= B.MaskPolicy;
+    VILL |= B.VILL;
+    AltFmt |= B.AltFmt;
+    TWiden |= B.TWiden;
+  }
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+  /// Support for debugging, callable in GDB: V->dump()
+  LLVM_DUMP_METHOD void dump() const {
+    print(dbgs());
+    dbgs() << "\n";
+  }
+
+  /// Implement operator<<.
+  void print(raw_ostream &OS) const {
+    OS << "{";
+    OS << "VLAny=" << VLAny << ", ";
+    OS << "VLZeroness=" << VLZeroness << ", ";
+    OS << "SEW=";
+    switch (SEW) {
+    case SEWEqual:
+      OS << "SEWEqual";
+      break;
+    case SEWGreaterThanOrEqual:
+      OS << "SEWGreaterThanOrEqual";
+      break;
+    case SEWGreaterThanOrEqualAndLessThan64:
+      OS << "SEWGreaterThanOrEqualAndLessThan64";
+      break;
+    case SEWNone:
+      OS << "SEWNone";
+      break;
+    };
+    OS << ", ";
+    OS << "LMUL=";
+    switch (LMUL) {
+    case LMULEqual:
+      OS << "LMULEqual";
+      break;
+    case LMULLessThanOrEqualToM1:
+      OS << "LMULLessThanOrEqualToM1";
+      break;
+    case LMULNone:
+      OS << "LMULNone";
+      break;
+    };
+    OS << ", ";
+    OS << "SEWLMULRatio=" << SEWLMULRatio << ", ";
+    OS << "TailPolicy=" << TailPolicy << ", ";
+    OS << "MaskPolicy=" << MaskPolicy << ", ";
+    OS << "VILL=" << VILL << ", ";
+    OS << "AltFmt=" << AltFmt << ", ";
+    OS << "TWiden=" << TWiden;
+    OS << "}";
+  }
+#endif
+};
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+LLVM_ATTRIBUTE_USED
+inline raw_ostream &operator<<(raw_ostream &OS, const DemandedFields &DF) {
+  DF.print(OS);
+  return OS;
+}
+#endif
+
+bool areCompatibleVTYPEs(uint64_t CurVType, uint64_t NewVType,
+                         const DemandedFields &Used);
+
+/// Return the fields and properties demanded by the provided instruction.
+DemandedFields getDemanded(const MachineInstr &MI, const RISCVSubtarget *ST);
+
+/// Defines the abstract state with which the forward dataflow models the
+/// values of the VL and VTYPE registers after insertion.
+class VSETVLIInfo {
+  struct AVLDef {
+    // Every AVLDef should have a VNInfo, unless we're running without
+    // LiveIntervals in which case this will be nullptr.
+    const VNInfo *ValNo;
+    Register DefReg;
+  };
+  union {
+    AVLDef AVLRegDef;
+    unsigned AVLImm;
+  };
+
+  enum class AVLState : uint8_t {
+    Uninitialized,
+    AVLIsReg,
+    AVLIsImm,
+    AVLIsVLMAX,
+    Unknown, // AVL and VTYPE are fully unknown
+  } State = AVLState::Uninitialized;
+
+  // Fields from VTYPE.
+  RISCVVType::VLMUL VLMul = RISCVVType::LMUL_1;
+  uint8_t SEW = 0;
+  uint8_t TailAgnostic : 1;
+  uint8_t MaskAgnostic : 1;
+  uint8_t SEWLMULRatioOnly : 1;
+  uint8_t AltFmt : 1;
+  uint8_t TWiden : 3;
+
+public:
+  VSETVLIInfo()
+      : AVLImm(0), TailAgnostic(false), MaskAgnostic(false),
+        SEWLMULRatioOnly(false), AltFmt(false), TWiden(0) {}
+
+  static VSETVLIInfo getUnknown() {
+    VSETVLIInfo Info;
+    Info.setUnknown();
+    return Info;
+  }
+
+  bool isValid() const { return State != AVLState::Uninitialized; }
+  void setUnknown() { State = AVLState::Unknown; }
+  bool isUnknown() const { return State == AVLState::Unknown; }
+
+  void setAVLRegDef(const VNInfo *VNInfo, Register AVLReg) {
+    assert(AVLReg.isVirtual());
+    AVLRegDef.ValNo = VNInfo;
+    AVLRegDef.DefReg = AVLReg;
+    State = AVLState::AVLIsReg;
+  }
+
+  void setAVLImm(unsigned Imm) {
+    AVLImm = Imm;
+    State = AVLState::AVLIsImm;
+  }
+
+  void setAVLVLMAX() { State = AVLState::AVLIsVLMAX; }
+
+  bool hasAVLImm() const { return State == AVLState::AVLIsImm; }
+  bool hasAVLReg() const { return State == AVLState::AVLIsReg; }
+  bool hasAVLVLMAX() const { return State == AVLState::AVLIsVLMAX; }
+  Register getAVLReg() const {
+    assert(hasAVLReg() && AVLRegDef.DefReg.isVirtual());
+    return AVLRegDef.DefReg;
+  }
+  unsigned getAVLImm() const {
+    assert(hasAVLImm());
+    return AVLImm;
+  }
+  const VNInfo *getAVLVNInfo() const {
+    assert(hasAVLReg());
+    return AVLRegDef.ValNo;
+  }
+  // Most AVLIsReg infos will have a single defining MachineInstr, unless it was
+  // a PHI node. In that case getAVLVNInfo()->def will point to the block
+  // boundary slot and this will return nullptr.  If LiveIntervals isn't
+  // available, nullptr is also returned.
+  const MachineInstr *getAVLDefMI(const LiveIntervals *LIS) const {
+    assert(hasAVLReg());
+    if (!LIS || getAVLVNInfo()->isPHIDef())
+      return nullptr;
+    auto *MI = LIS->getInstructionFromIndex(getAVLVNInfo()->def);
+    assert(MI);
+    return MI;
+  }
+
+  void setAVL(const VSETVLIInfo &Info) {
+    assert(Info.isValid());
+    if (Info.isUnknown())
+      setUnknown();
+    else if (Info.hasAVLReg())
+      setAVLRegDef(Info.getAVLVNInfo(), Info.getAVLReg());
+    else if (Info.hasAVLVLMAX())
+      setAVLVLMAX();
+    else {
+      assert(Info.hasAVLImm());
+      setAVLImm(Info.getAVLImm());
+    }
+  }
+
+  bool hasSEWLMULRatioOnly() const { return SEWLMULRatioOnly; }
+
+  unsigned getSEW() const {
+    assert(isValid() && !isUnknown() && !hasSEWLMULRatioOnly() &&
+           "Can't use VTYPE for uninitialized or unknown");
+    return SEW;
+  }
+  RISCVVType::VLMUL getVLMUL() const {
+    assert(isValid() && !isUnknown() && !hasSEWLMULRatioOnly() &&
+           "Can't use VTYPE for uninitialized or unknown");
+    return VLMul;
+  }
+  bool getTailAgnostic() const {
+    assert(isValid() && !isUnknown() &&
+           "Can't use VTYPE for uninitialized or unknown");
+    return TailAgnostic;
+  }
+  bool getMaskAgnostic() const {
+    assert(isValid() && !isUnknown() &&
+           "Can't use VTYPE for uninitialized or unknown");
+    return MaskAgnostic;
+  }
+  bool getAltFmt() const {
+    assert(isValid() && !isUnknown() &&
+           "Can't use VTYPE for uninitialized or unknown");
+    return AltFmt;
+  }
+  unsigned getTWiden() const {
+    assert(isValid() && !isUnknown() &&
+           "Can't use VTYPE for uninitialized or unknown");
+    return TWiden;
+  }
+
+  bool hasNonZeroAVL(const LiveIntervals *LIS) const {
+    if (hasAVLImm())
+      return getAVLImm() > 0;
+    if (hasAVLReg()) {
+      if (auto *DefMI = getAVLDefMI(LIS))
+        return RISCVInstrInfo::isNonZeroLoadImmediate(*DefMI);
+    }
+    if (hasAVLVLMAX())
+      return true;
+    return false;
+  }
+
+  bool hasEquallyZeroAVL(const VSETVLIInfo &Other,
+                         const LiveIntervals *LIS) const {
+    if (hasSameAVL(Other))
+      return true;
+    return (hasNonZeroAVL(LIS) && Other.hasNonZeroAVL(LIS));
+  }
+
+  bool hasSameAVLLatticeValue(const VSETVLIInfo &Other) const {
+    if (hasAVLReg() && Other.hasAVLReg()) {
+      assert(!getAVLVNInfo() == !Other.getAVLVNInfo() &&
+             "we either have intervals or we don't");
+      if (!getAVLVNInfo())
+        return getAVLReg() == Other.getAVLReg();
+      return getAVLVNInfo()->id == Other.getAVLVNInfo()->id &&
+             getAVLReg() == Other.getAVLReg();
+    }
+
+    if (hasAVLImm() && Other.hasAVLImm())
+      return getAVLImm() == Other.getAVLImm();
+
+    if (hasAVLVLMAX())
+      return Other.hasAVLVLMAX() && hasSameVLMAX(Other);
+
+    return false;
+  }
+
+  // Return true if the two lattice values are guaranteed to have
+  // the same AVL value at runtime.
+  bool hasSameAVL(const VSETVLIInfo &Other) const {
+    // Without LiveIntervals, we don't know which instruction defines a
+    // register.  Since a register may be redefined, this means all AVLIsReg
+    // states must be treated as possibly distinct.
+    if (hasAVLReg() && Other.hasAVLReg()) {
+      assert(!getAVLVNInfo() == !Other.getAVLVNInfo() &&
+             "we either have intervals or we don't");
+      if (!getAVLVNInfo())
+        return false;
+    }
+    return hasSameAVLLatticeValue(Other);
+  }
+
+  void setVTYPE(unsigned VType) {
+    assert(isValid() && !isUnknown() &&
+           "Can't set VTYPE for uninitialized or unknown");
+    VLMul = RISCVVType::getVLMUL(VType);
+    SEW = RISCVVType::getSEW(VType);
+    TailAgnostic = RISCVVType::isTailAgnostic(VType);
+    MaskAgnostic = RISCVVType::isMaskAgnostic(VType);
+    AltFmt = RISCVVType::isAltFmt(VType);
+    TWiden =
+        RISCVVType::hasXSfmmWiden(VType) ? RISCVVType::getXSfmmWiden(VType) : 0;
+  }
+  void setVTYPE(RISCVVType::VLMUL L, unsigned S, bool TA, bool MA, bool Altfmt,
+                unsigned W) {
+    assert(isValid() && !isUnknown() &&
+           "Can't set VTYPE for uninitialized or unknown");
+    VLMul = L;
+    SEW = S;
+    TailAgnostic = TA;
+    MaskAgnostic = MA;
+    AltFmt = Altfmt;
+    TWiden = W;
+  }
+
+  void setAltFmt(bool AF) { AltFmt = AF; }
+
+  void setVLMul(RISCVVType::VLMUL VLMul) { this->VLMul = VLMul; }
+
+  unsigned encodeVTYPE() const {
+    assert(isValid() && !isUnknown() && !SEWLMULRatioOnly &&
+           "Can't encode VTYPE for uninitialized or unknown");
+    if (TWiden != 0)
+      return RISCVVType::encodeXSfmmVType(SEW, TWiden, AltFmt);
+    return RISCVVType::encodeVTYPE(VLMul, SEW, TailAgnostic, MaskAgnostic,
+                                   AltFmt);
+  }
+
+  bool hasSameVTYPE(const VSETVLIInfo &Other) const {
+    assert(isValid() && Other.isValid() &&
+           "Can't compare invalid VSETVLIInfos");
+    assert(!isUnknown() && !Other.isUnknown() &&
+           "Can't compare VTYPE in unknown state");
+    assert(!SEWLMULRatioOnly && !Other.SEWLMULRatioOnly &&
+           "Can't compare when only LMUL/SEW ratio is valid.");
+    return std::tie(VLMul, SEW, TailAgnostic, MaskAgnostic, AltFmt, TWiden) ==
+           std::tie(Other.VLMul, Other.SEW, Other.TailAgnostic,
+                    Other.MaskAgnostic, Other.AltFmt, Other.TWiden);
+  }
+
+  unsigned getSEWLMULRatio() const {
+    assert(isValid() && !isUnknown() &&
+           "Can't use VTYPE for uninitialized or unknown");
+    return RISCVVType::getSEWLMULRatio(SEW, VLMul);
+  }
+
+  // Check if the VTYPE for these two VSETVLIInfos produce the same VLMAX.
+  // Note that having the same VLMAX ensures that both share the same
+  // function from AVL to VL; that is, they must produce the same VL value
+  // for any given AVL value.
+  bool hasSameVLMAX(const VSETVLIInfo &Other) const {
+    assert(isValid() && Other.isValid() &&
+           "Can't compare invalid VSETVLIInfos");
+    assert(!isUnknown() && !Other.isUnknown() &&
+           "Can't compare VTYPE in unknown state");
+    return getSEWLMULRatio() == Other.getSEWLMULRatio();
+  }
+
+  bool hasCompatibleVTYPE(const DemandedFields &Used,
+                          const VSETVLIInfo &Require) const;
+
+  // Determine whether the vector instructions requirements represented by
+  // Require are compatible with the previous vsetvli instruction represented
+  // by this.  MI is the instruction whose requirements we're considering.
+  bool isCompatible(const DemandedFields &Used, const VSETVLIInfo &Require,
+                    const LiveIntervals *LIS) const {
+    assert(isValid() && Require.isValid() &&
+           "Can't compare invalid VSETVLIInfos");
+    // Nothing is compatible with Unknown.
+    if (isUnknown() || Require.isUnknown())
+      return false;
+
+    // If only our VLMAX ratio is valid, then this isn't compatible.
+    if (SEWLMULRatioOnly || Require.SEWLMULRatioOnly)
+      return false;
+
+    if (Used.VLAny && !(hasSameAVL(Require) && hasSameVLMAX(Require)))
+      return false;
+
+    if (Used.VLZeroness && !hasEquallyZeroAVL(Require, LIS))
+      return false;
+
+    return hasCompatibleVTYPE(Used, Require);
+  }
+
+  bool operator==(const VSETVLIInfo &Other) const {
+    // Uninitialized is only equal to another Uninitialized.
+    if (!isValid())
+      return !Other.isValid();
+    if (!Other.isValid())
+      return !isValid();
+
+    // Unknown is only equal to another Unknown.
+    if (isUnknown())
+      return Other.isUnknown();
+    if (Other.isUnknown())
+      return isUnknown();
+
+    if (!hasSameAVLLatticeValue(Other))
+      return false;
+
+    // If the SEWLMULRatioOnly bits are 
diff erent, then they aren't equal.
+    if (SEWLMULRatioOnly != Other.SEWLMULRatioOnly)
+      return false;
+
+    // If only the VLMAX is valid, check that it is the same.
+    if (SEWLMULRatioOnly)
+      return hasSameVLMAX(Other);
+
+    // If the full VTYPE is valid, check that it is the same.
+    return hasSameVTYPE(Other);
+  }
+
+  bool operator!=(const VSETVLIInfo &Other) const { return !(*this == Other); }
+
+  // Calculate the VSETVLIInfo visible to a block assuming this and Other are
+  // both predecessors.
+  VSETVLIInfo intersect(const VSETVLIInfo &Other) const {
+    // If the new value isn't valid, ignore it.
+    if (!Other.isValid())
+      return *this;
+
+    // If this value isn't valid, this must be the first predecessor, use it.
+    if (!isValid())
+      return Other;
+
+    // If either is unknown, the result is unknown.
+    if (isUnknown() || Other.isUnknown())
+      return VSETVLIInfo::getUnknown();
+
+    // If we have an exact, match return this.
+    if (*this == Other)
+      return *this;
+
+    // Not an exact match, but maybe the AVL and VLMAX are the same. If so,
+    // return an SEW/LMUL ratio only value.
+    if (hasSameAVL(Other) && hasSameVLMAX(Other)) {
+      VSETVLIInfo MergeInfo = *this;
+      MergeInfo.SEWLMULRatioOnly = true;
+      return MergeInfo;
+    }
+
+    // Otherwise the result is unknown.
+    return VSETVLIInfo::getUnknown();
+  }
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+  /// Support for debugging, callable in GDB: V->dump()
+  LLVM_DUMP_METHOD void dump() const {
+    print(dbgs());
+    dbgs() << "\n";
+  }
+
+  /// Implement operator<<.
+  /// @{
+  void print(raw_ostream &OS) const {
+    OS << '{';
+    switch (State) {
+    case AVLState::Uninitialized:
+      OS << "Uninitialized";
+      break;
+    case AVLState::Unknown:
+      OS << "unknown";
+      break;
+    case AVLState::AVLIsReg:
+      OS << "AVLReg=" << llvm::printReg(getAVLReg());
+      break;
+    case AVLState::AVLIsImm:
+      OS << "AVLImm=" << (unsigned)AVLImm;
+      break;
+    case AVLState::AVLIsVLMAX:
+      OS << "AVLVLMAX";
+      break;
+    }
+    if (isValid() && !isUnknown()) {
+      OS << ", ";
+
+      unsigned LMul;
+      bool Fractional;
+      std::tie(LMul, Fractional) = decodeVLMUL(VLMul);
+
+      OS << "VLMul=m";
+      if (Fractional)
+        OS << 'f';
+      OS << LMul << ", "
+         << "SEW=e" << (unsigned)SEW << ", "
+         << "TailAgnostic=" << (bool)TailAgnostic << ", "
+         << "MaskAgnostic=" << (bool)MaskAgnostic << ", "
+         << "SEWLMULRatioOnly=" << (bool)SEWLMULRatioOnly << ", "
+         << "TWiden=" << (unsigned)TWiden << ", "
+         << "AltFmt=" << (bool)AltFmt;
+    }
+
+    OS << '}';
+  }
+#endif
+};
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+LLVM_ATTRIBUTE_USED
+inline raw_ostream &operator<<(raw_ostream &OS, const VSETVLIInfo &V) {
+  V.print(OS);
+  return OS;
+}
+#endif
+
+class RISCVVSETVLIInfoAnalysis {
+  const RISCVSubtarget *ST;
+  // Possibly null!
+  LiveIntervals *LIS;
+
+public:
+  RISCVVSETVLIInfoAnalysis() = default;
+  RISCVVSETVLIInfoAnalysis(const RISCVSubtarget *ST, LiveIntervals *LIS)
+      : ST(ST), LIS(LIS) {}
+
+  VSETVLIInfo getInfoForVSETVLI(const MachineInstr &MI) const;
+  VSETVLIInfo computeInfoForInstr(const MachineInstr &MI) const;
+
+private:
+  void forwardVSETVLIAVL(VSETVLIInfo &Info) const;
+};
+
+} // namespace RISCV
+} // namespace llvm


        


More information about the llvm-commits mailing list