[llvm] [RISCV] Introduce VLOptimizer pass (PR #108640)

Philip Reames via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 17 10:41:57 PDT 2024


================
@@ -0,0 +1,1589 @@
+//===-------------- RISCVVLOptimizer.cpp - VL Optimizer -------------------===//
+//
+// 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 pass reduces the VL where possible at the MI level, before VSETVLI
+// instructions are inserted.
+//
+// The purpose of this optimization is to make the VL argument, for instructions
+// that have a VL argument, as small as possible. This is implemented by
+// visiting each instruction in reverse order and checking that if it has a VL
+// argument, whether the VL can be reduced.
+//
+//===---------------------------------------------------------------------===//
+
+#include "RISCV.h"
+#include "RISCVMachineFunctionInfo.h"
+#include "RISCVSubtarget.h"
+#include "llvm/ADT/SetVector.h"
+#include "llvm/CodeGen/MachineDominators.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/InitializePasses.h"
+
+#include <algorithm>
+
+using namespace llvm;
+
+#define DEBUG_TYPE "riscv-vl-optimizer"
+#define PASS_NAME "RISC-V VL Optimizer"
+
+namespace {
+
+class RISCVVLOptimizer : public MachineFunctionPass {
+  const MachineRegisterInfo *MRI;
+  const MachineDominatorTree *MDT;
+
+public:
+  static char ID;
+
+  RISCVVLOptimizer() : MachineFunctionPass(ID) {}
+
+  bool runOnMachineFunction(MachineFunction &MF) override;
+
+  void getAnalysisUsage(AnalysisUsage &AU) const override {
+    AU.setPreservesCFG();
+    AU.addRequired<MachineDominatorTreeWrapperPass>();
+    MachineFunctionPass::getAnalysisUsage(AU);
+  }
+
+  StringRef getPassName() const override { return PASS_NAME; }
+
+private:
+  bool tryReduceVL(MachineInstr &MI);
+  bool isCandidate(const MachineInstr &MI) const;
+};
+
+} // end anonymous namespace
+
+char RISCVVLOptimizer::ID = 0;
+INITIALIZE_PASS_BEGIN(RISCVVLOptimizer, DEBUG_TYPE, PASS_NAME, false, false)
+INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass)
+INITIALIZE_PASS_END(RISCVVLOptimizer, DEBUG_TYPE, PASS_NAME, false, false)
+
+FunctionPass *llvm::createRISCVVLOptimizerPass() {
+  return new RISCVVLOptimizer();
+}
+
+/// Return true if R is a physical or virtual vector register, false otherwise.
+static bool isVectorRegClass(Register R, const MachineRegisterInfo *MRI) {
+  if (R.isPhysical())
+    return RISCV::VRRegClass.contains(R);
+  const TargetRegisterClass *RC = MRI->getRegClass(R);
+  return RISCVRI::isVRegClass(RC->TSFlags);
+}
+
+/// Represents the EMUL and EEW of a MachineOperand.
+struct OperandInfo {
+  enum class State {
+    Unknown,
+    Known,
+  } S;
+
+  // Represent as 1,2,4,8, ... and fractional indicator. This is because
+  // EMUL can take on values that don't map to RISCVII::VLMUL values exactly.
+  // For example, a mask operand can have an EMUL less than MF8.
+  std::pair<unsigned, bool> EMUL;
+
+  unsigned Log2EEW;
+
+  OperandInfo(RISCVII::VLMUL EMUL, unsigned Log2EEW)
+      : S(State::Known), EMUL(RISCVVType::decodeVLMUL(EMUL)), Log2EEW(Log2EEW) {
+  }
+
+  OperandInfo(std::pair<unsigned, bool> EMUL, unsigned Log2EEW)
+      : S(State::Known), EMUL(EMUL), Log2EEW(Log2EEW) {}
+
+  OperandInfo(State S) : S(S) {
+    assert(S != State::Known &&
+           "This constructor may only be used to construct "
+           "an Unknown OperandInfo");
+  }
+
+  bool isUnknown() const { return S == State::Unknown; }
+  bool isKnown() const { return S == State::Known; }
+
+  static bool EMULAndEEWAreEqual(const OperandInfo &A, const OperandInfo &B) {
+    assert(A.isKnown() && B.isKnown() && "Both operands must be known");
+    return A.Log2EEW == B.Log2EEW && A.EMUL.first == B.EMUL.first &&
+           A.EMUL.second == B.EMUL.second;
+  }
+
+  void print(raw_ostream &OS) const {
+    if (isUnknown()) {
+      OS << "Unknown";
+      return;
+    }
+    OS << "EMUL: ";
+    if (EMUL.second)
+      OS << "m";
+    OS << "f" << EMUL.first;
+    OS << ", EEW: " << (1 << Log2EEW);
+  }
+};
+
+static raw_ostream &operator<<(raw_ostream &OS, const OperandInfo &OI) {
+  OI.print(OS);
+  return OS;
+}
+
+namespace llvm {
+namespace RISCVVType {
+/// Return the RISCVII::VLMUL that is two times VLMul.
+/// Precondition: VLMul is not LMUL_RESERVED or LMUL_8.
+static RISCVII::VLMUL twoTimesVLMUL(RISCVII::VLMUL VLMul) {
+  switch (VLMul) {
+  case RISCVII::VLMUL::LMUL_F8:
+    return RISCVII::VLMUL::LMUL_F4;
+  case RISCVII::VLMUL::LMUL_F4:
+    return RISCVII::VLMUL::LMUL_F2;
+  case RISCVII::VLMUL::LMUL_F2:
+    return RISCVII::VLMUL::LMUL_1;
+  case RISCVII::VLMUL::LMUL_1:
+    return RISCVII::VLMUL::LMUL_2;
+  case RISCVII::VLMUL::LMUL_2:
+    return RISCVII::VLMUL::LMUL_4;
+  case RISCVII::VLMUL::LMUL_4:
+    return RISCVII::VLMUL::LMUL_8;
+  case RISCVII::VLMUL::LMUL_8:
+  default:
+    llvm_unreachable("Could not multiply VLMul by 2");
+  }
+}
+
+/// Return the RISCVII::VLMUL that is VLMul / 2.
+/// Precondition: VLMul is not LMUL_RESERVED or LMUL_MF8.
+static RISCVII::VLMUL halfVLMUL(RISCVII::VLMUL VLMul) {
+  switch (VLMul) {
+  case RISCVII::VLMUL::LMUL_F4:
+    return RISCVII::VLMUL::LMUL_F8;
+  case RISCVII::VLMUL::LMUL_F2:
+    return RISCVII::VLMUL::LMUL_F4;
+  case RISCVII::VLMUL::LMUL_1:
+    return RISCVII::VLMUL::LMUL_F2;
+  case RISCVII::VLMUL::LMUL_2:
+    return RISCVII::VLMUL::LMUL_1;
+  case RISCVII::VLMUL::LMUL_4:
+    return RISCVII::VLMUL::LMUL_2;
+  case RISCVII::VLMUL::LMUL_8:
+    return RISCVII::VLMUL::LMUL_4;
+  case RISCVII::VLMUL::LMUL_F8:
+  default:
+    llvm_unreachable("Could not divide VLMul by 2");
+  }
+}
+
+/// Return EMUL = (EEW / SEW) * LMUL where EEW comes from Log2EEW and LMUL and
+/// SEW are from the TSFlags of MI.
+static std::pair<unsigned, bool>
+getEMULEqualsEEWDivSEWTimesLMUL(unsigned Log2EEW, const MachineInstr &MI) {
+  RISCVII::VLMUL MIVLMUL = RISCVII::getLMul(MI.getDesc().TSFlags);
+  auto [MILMUL, MILMULIsFractional] = RISCVVType::decodeVLMUL(MIVLMUL);
+  unsigned MILog2SEW =
+      MI.getOperand(RISCVII::getSEWOpNum(MI.getDesc())).getImm();
+  unsigned MISEW = 1 << MILog2SEW;
+
+  unsigned EEW = 1 << Log2EEW;
+  // Calculate (EEW/SEW)*LMUL preserving fractions less than 1. Use GCD
+  // to put fraction in simplest form.
+  unsigned Num = EEW, Denom = MISEW;
+  int GCD = MILMULIsFractional ? std::gcd(Num, Denom * MILMUL)
+                               : std::gcd(Num * MILMUL, Denom);
+  Num = MILMULIsFractional ? Num / GCD : Num * MILMUL / GCD;
+  Denom = MILMULIsFractional ? Denom * MILMUL / GCD : Denom / GCD;
+  return std::make_pair(Num > Denom ? Num : Denom, Denom > Num);
+}
+} // end namespace RISCVVType
+} // end namespace llvm
+
+static bool isOpN(const MachineOperand &MO, unsigned OpN) {
+  const MachineInstr &MI = *MO.getParent();
+  bool HasPassthru = RISCVII::isFirstDefTiedToFirstUse(MI.getDesc());
+
+  if (HasPassthru)
+    return MO.getOperandNo() == OpN + 1;
+
+  return MO.getOperandNo() == OpN;
+}
+
+/// An index segment load or store operand has the form v.*seg<nf>ei<eeew>.v.
+/// Data has EEW=SEW, EMUL=LMUL. Index has EEW=<eew>, EMUL=(EEW/SEW)*LMUL. LMUL
+/// and SEW comes from TSFlags of MI.
+static OperandInfo getIndexSegmentLoadStoreOperandInfo(unsigned Log2EEW,
+                                                       const MachineInstr &MI,
+                                                       const MachineOperand &MO,
+                                                       bool IsLoad) {
+  // Operand 0 is data register
+  // Data vector register group has EEW=SEW, EMUL=LMUL.
+  if (MO.getOperandNo() == 0) {
+    RISCVII::VLMUL MIVLMul = RISCVII::getLMul(MI.getDesc().TSFlags);
+    unsigned MILog2SEW =
+        MI.getOperand(RISCVII::getSEWOpNum(MI.getDesc())).getImm();
+    return OperandInfo(MIVLMul, MILog2SEW);
+  }
+
+  // Operand 2 is index vector register
+  // v.*seg<nf>ei<eeew>.v
+  // Index vector register group has EEW=<eew>, EMUL=(EEW/SEW)*LMUL.
+  if (isOpN(MO, 2))
+    return OperandInfo(RISCVVType::getEMULEqualsEEWDivSEWTimesLMUL(Log2EEW, MI),
+                       Log2EEW);
+
+  llvm_unreachable("Could not get OperandInfo for non-vector register of an "
+                   "indexed segment load or store instruction");
+}
+
+/// Dest has EEW=SEW and EMUL=LMUL. Source EEW=SEW/Factor (i.e. F2 => EEW/2).
+/// Source has EMUL=(EEW/SEW)*LMUL. LMUL and SEW comes from TSFlags of MI.
+static OperandInfo getIntegerExtensionOperandInfo(unsigned Factor,
+                                                  const MachineInstr &MI,
+                                                  const MachineOperand &MO) {
+  RISCVII::VLMUL MIVLMul = RISCVII::getLMul(MI.getDesc().TSFlags);
+  unsigned MILog2SEW =
+      MI.getOperand(RISCVII::getSEWOpNum(MI.getDesc())).getImm();
+
+  if (MO.getOperandNo() == 0)
+    return OperandInfo(MIVLMul, MILog2SEW);
+
+  unsigned MISEW = 1 << MILog2SEW;
+  unsigned EEW = MISEW / Factor;
+  unsigned Log2EEW = Log2_32(EEW);
+
+  return OperandInfo(RISCVVType::getEMULEqualsEEWDivSEWTimesLMUL(Log2EEW, MI),
+                     Log2EEW);
+}
+
+/// Check whether MO is a mask operand of MI.
+static bool isMaskOperand(const MachineInstr &MI, const MachineOperand &MO,
+                          const MachineRegisterInfo *MRI) {
+
+  if (!MO.isReg() || !isVectorRegClass(MO.getReg(), MRI))
+    return false;
+
+  const MCInstrDesc &Desc = MI.getDesc();
+  return Desc.operands()[MO.getOperandNo()].RegClass == RISCV::VMV0RegClassID;
+}
+
+/// Return the OperandInfo for MO, which is an operand of MI.
+static OperandInfo getOperandInfo(const MachineInstr &MI,
+                                  const MachineOperand &MO,
+                                  const MachineRegisterInfo *MRI) {
+  const RISCVVPseudosTable::PseudoInfo *RVV =
+      RISCVVPseudosTable::getPseudoInfo(MI.getOpcode());
+  assert(RVV && "Could not find MI in PseudoTable");
+
+  // MI has a VLMUL and SEW associated with it. The RVV specification defines
+  // the LMUL and SEW of each operand and definition in relation to MI.VLMUL and
+  // MI.SEW.
+  RISCVII::VLMUL MIVLMul = RISCVII::getLMul(MI.getDesc().TSFlags);
+  unsigned MILog2SEW =
+      MI.getOperand(RISCVII::getSEWOpNum(MI.getDesc())).getImm();
+
+  const bool HasPassthru = RISCVII::isFirstDefTiedToFirstUse(MI.getDesc());
+
+  // We bail out early for instructions that have passthru with non NoRegister,
+  // which means they are using TU policy. We are not interested in these
+  // since they must preserve the entire register content.
+  if (HasPassthru && MO.getOperandNo() == MI.getNumExplicitDefs() &&
+      (MO.getReg() != RISCV::NoRegister))
+    return OperandInfo(OperandInfo::State::Unknown);
+
+  bool IsMODef = MO.getOperandNo() == 0;
+  bool IsOp1 = isOpN(MO, 1);
+  bool IsOp2 = isOpN(MO, 2);
+  bool IsOp3 = isOpN(MO, 3);
+
+  // All mask operands have EEW=1, EMUL=(EEW/SEW)*LMUL
+  if (isMaskOperand(MI, MO, MRI))
+    return OperandInfo(RISCVVType::getEMULEqualsEEWDivSEWTimesLMUL(0, MI), 0);
+
+  // switch against BaseInstr to reduce number of cases that need to be
+  // considered.
+  switch (RVV->BaseInstr) {
+
+  // 6. Configuration-Setting Instructions
+  // Configuration setting instructions do not read or write vector registers
+  case RISCV::VSETIVLI:
+  case RISCV::VSETVL:
+  case RISCV::VSETVLI:
+    llvm_unreachable("Configuration setting instructions do not read or write "
+                     "vector registers");
+
+  // 7. Vector Loads and Stores
+  // 7.4. Vector Unit-Stride Instructions
+  // 7.5. Vector Strided Instructions
+  // 7.7. Unit-stride Fault-Only-First Loads
+  /// Dest EEW encoded in the instruction and EMUL=(EEW/SEW)*LMUL
+  case RISCV::VLE8_V:
+  case RISCV::VSE8_V:
+  case RISCV::VLM_V:
+  case RISCV::VSM_V:
+  case RISCV::VLSE8_V:
+  case RISCV::VSSE8_V:
+  case RISCV::VLE8FF_V:
+    return OperandInfo(RISCVVType::getEMULEqualsEEWDivSEWTimesLMUL(3, MI), 3);
+  case RISCV::VLE16_V:
+  case RISCV::VSE16_V:
+  case RISCV::VLSE16_V:
+  case RISCV::VSSE16_V:
+  case RISCV::VLE16FF_V:
+    return OperandInfo(RISCVVType::getEMULEqualsEEWDivSEWTimesLMUL(4, MI), 4);
+  case RISCV::VLE32_V:
+  case RISCV::VSE32_V:
+  case RISCV::VLSE32_V:
+  case RISCV::VSSE32_V:
+  case RISCV::VLE32FF_V:
+    return OperandInfo(RISCVVType::getEMULEqualsEEWDivSEWTimesLMUL(5, MI), 5);
+  case RISCV::VLE64_V:
+  case RISCV::VSE64_V:
+  case RISCV::VLSE64_V:
+  case RISCV::VSSE64_V:
+  case RISCV::VLE64FF_V:
+    return OperandInfo(RISCVVType::getEMULEqualsEEWDivSEWTimesLMUL(6, MI), 6);
+
+  // 7.6. Vector Indexed Instructions
+  // Data EEW=SEW, EMUL=LMUL. Index EEW=<eew> and EMUL=(EEW/SEW)*LMUL
+  case RISCV::VLUXEI8_V:
+  case RISCV::VLOXEI8_V:
+  case RISCV::VSUXEI8_V:
+  case RISCV::VSOXEI8_V:
+    if (MO.getOperandNo() == 0)
+      return OperandInfo(MIVLMul, MILog2SEW);
+    return OperandInfo(RISCVVType::getEMULEqualsEEWDivSEWTimesLMUL(3, MI), 3);
+  case RISCV::VLUXEI16_V:
+  case RISCV::VLOXEI16_V:
+  case RISCV::VSUXEI16_V:
+  case RISCV::VSOXEI16_V:
+    if (MO.getOperandNo() == 0)
+      return OperandInfo(MIVLMul, MILog2SEW);
+    return OperandInfo(RISCVVType::getEMULEqualsEEWDivSEWTimesLMUL(4, MI), 4);
+  case RISCV::VLUXEI32_V:
+  case RISCV::VLOXEI32_V:
+  case RISCV::VSUXEI32_V:
+  case RISCV::VSOXEI32_V:
+    if (MO.getOperandNo() == 0)
+      return OperandInfo(MIVLMul, MILog2SEW);
+    return OperandInfo(RISCVVType::getEMULEqualsEEWDivSEWTimesLMUL(5, MI), 5);
+  case RISCV::VLUXEI64_V:
+  case RISCV::VLOXEI64_V:
+  case RISCV::VSUXEI64_V:
+  case RISCV::VSOXEI64_V:
+    if (MO.getOperandNo() == 0)
+      return OperandInfo(MIVLMul, MILog2SEW);
+    return OperandInfo(RISCVVType::getEMULEqualsEEWDivSEWTimesLMUL(6, MI), 6);
+
+  // 7.8. Vector Load/Store Segment Instructions
+  // 7.8.1. Vector Unit-Stride Segment Loads and Stores
+  // v.*seg<nf>e<eew>.*
+  // EEW=eew, EMUL=LMUL
+  case RISCV::VLSEG2E8_V:
+  case RISCV::VLSEG2E8FF_V:
+  case RISCV::VLSEG3E8_V:
+  case RISCV::VLSEG3E8FF_V:
+  case RISCV::VLSEG4E8_V:
+  case RISCV::VLSEG4E8FF_V:
+  case RISCV::VLSEG5E8_V:
+  case RISCV::VLSEG5E8FF_V:
+  case RISCV::VLSEG6E8_V:
+  case RISCV::VLSEG6E8FF_V:
+  case RISCV::VLSEG7E8_V:
+  case RISCV::VLSEG7E8FF_V:
+  case RISCV::VLSEG8E8_V:
+  case RISCV::VLSEG8E8FF_V:
+  case RISCV::VSSEG2E8_V:
+  case RISCV::VSSEG3E8_V:
+  case RISCV::VSSEG4E8_V:
+  case RISCV::VSSEG5E8_V:
+  case RISCV::VSSEG6E8_V:
+  case RISCV::VSSEG7E8_V:
+  case RISCV::VSSEG8E8_V:
+    return OperandInfo(MIVLMul, 3);
+  case RISCV::VLSEG2E16_V:
+  case RISCV::VLSEG2E16FF_V:
+  case RISCV::VLSEG3E16_V:
+  case RISCV::VLSEG3E16FF_V:
+  case RISCV::VLSEG4E16_V:
+  case RISCV::VLSEG4E16FF_V:
+  case RISCV::VLSEG5E16_V:
+  case RISCV::VLSEG5E16FF_V:
+  case RISCV::VLSEG6E16_V:
+  case RISCV::VLSEG6E16FF_V:
+  case RISCV::VLSEG7E16_V:
+  case RISCV::VLSEG7E16FF_V:
+  case RISCV::VLSEG8E16_V:
+  case RISCV::VLSEG8E16FF_V:
+  case RISCV::VSSEG2E16_V:
+  case RISCV::VSSEG3E16_V:
+  case RISCV::VSSEG4E16_V:
+  case RISCV::VSSEG5E16_V:
+  case RISCV::VSSEG6E16_V:
+  case RISCV::VSSEG7E16_V:
+  case RISCV::VSSEG8E16_V:
+    return OperandInfo(MIVLMul, 4);
+  case RISCV::VLSEG2E32_V:
+  case RISCV::VLSEG2E32FF_V:
+  case RISCV::VLSEG3E32_V:
+  case RISCV::VLSEG3E32FF_V:
+  case RISCV::VLSEG4E32_V:
+  case RISCV::VLSEG4E32FF_V:
+  case RISCV::VLSEG5E32_V:
+  case RISCV::VLSEG5E32FF_V:
+  case RISCV::VLSEG6E32_V:
+  case RISCV::VLSEG6E32FF_V:
+  case RISCV::VLSEG7E32_V:
+  case RISCV::VLSEG7E32FF_V:
+  case RISCV::VLSEG8E32_V:
+  case RISCV::VLSEG8E32FF_V:
+  case RISCV::VSSEG2E32_V:
+  case RISCV::VSSEG3E32_V:
+  case RISCV::VSSEG4E32_V:
+  case RISCV::VSSEG5E32_V:
+  case RISCV::VSSEG6E32_V:
+  case RISCV::VSSEG7E32_V:
+  case RISCV::VSSEG8E32_V:
+    return OperandInfo(MIVLMul, 5);
+  case RISCV::VLSEG2E64_V:
+  case RISCV::VLSEG2E64FF_V:
+  case RISCV::VLSEG3E64_V:
+  case RISCV::VLSEG3E64FF_V:
+  case RISCV::VLSEG4E64_V:
+  case RISCV::VLSEG4E64FF_V:
+  case RISCV::VLSEG5E64_V:
+  case RISCV::VLSEG5E64FF_V:
+  case RISCV::VLSEG6E64_V:
+  case RISCV::VLSEG6E64FF_V:
+  case RISCV::VLSEG7E64_V:
+  case RISCV::VLSEG7E64FF_V:
+  case RISCV::VLSEG8E64_V:
+  case RISCV::VLSEG8E64FF_V:
+  case RISCV::VSSEG2E64_V:
+  case RISCV::VSSEG3E64_V:
+  case RISCV::VSSEG4E64_V:
+  case RISCV::VSSEG5E64_V:
+  case RISCV::VSSEG6E64_V:
+  case RISCV::VSSEG7E64_V:
+  case RISCV::VSSEG8E64_V:
+    return OperandInfo(MIVLMul, 6);
+
+  // 7.8.2. Vector Strided Segment Loads and Stores
+  case RISCV::VLSSEG2E8_V:
+  case RISCV::VLSSEG3E8_V:
+  case RISCV::VLSSEG4E8_V:
+  case RISCV::VLSSEG5E8_V:
+  case RISCV::VLSSEG6E8_V:
+  case RISCV::VLSSEG7E8_V:
+  case RISCV::VLSSEG8E8_V:
+  case RISCV::VSSSEG2E8_V:
+  case RISCV::VSSSEG3E8_V:
+  case RISCV::VSSSEG4E8_V:
+  case RISCV::VSSSEG5E8_V:
+  case RISCV::VSSSEG6E8_V:
+  case RISCV::VSSSEG7E8_V:
+  case RISCV::VSSSEG8E8_V:
+    return OperandInfo(MIVLMul, 3);
+  case RISCV::VLSSEG2E16_V:
+  case RISCV::VLSSEG3E16_V:
+  case RISCV::VLSSEG4E16_V:
+  case RISCV::VLSSEG5E16_V:
+  case RISCV::VLSSEG6E16_V:
+  case RISCV::VLSSEG7E16_V:
+  case RISCV::VLSSEG8E16_V:
+  case RISCV::VSSSEG2E16_V:
+  case RISCV::VSSSEG3E16_V:
+  case RISCV::VSSSEG4E16_V:
+  case RISCV::VSSSEG5E16_V:
+  case RISCV::VSSSEG6E16_V:
+  case RISCV::VSSSEG7E16_V:
+  case RISCV::VSSSEG8E16_V:
+    return OperandInfo(MIVLMul, 4);
+  case RISCV::VLSSEG2E32_V:
+  case RISCV::VLSSEG3E32_V:
+  case RISCV::VLSSEG4E32_V:
+  case RISCV::VLSSEG5E32_V:
+  case RISCV::VLSSEG6E32_V:
+  case RISCV::VLSSEG7E32_V:
+  case RISCV::VLSSEG8E32_V:
+  case RISCV::VSSSEG2E32_V:
+  case RISCV::VSSSEG3E32_V:
+  case RISCV::VSSSEG4E32_V:
+  case RISCV::VSSSEG5E32_V:
+  case RISCV::VSSSEG6E32_V:
+  case RISCV::VSSSEG7E32_V:
+  case RISCV::VSSSEG8E32_V:
+    return OperandInfo(MIVLMul, 5);
+  case RISCV::VLSSEG2E64_V:
+  case RISCV::VLSSEG3E64_V:
+  case RISCV::VLSSEG4E64_V:
+  case RISCV::VLSSEG5E64_V:
+  case RISCV::VLSSEG6E64_V:
+  case RISCV::VLSSEG7E64_V:
+  case RISCV::VLSSEG8E64_V:
+  case RISCV::VSSSEG2E64_V:
+  case RISCV::VSSSEG3E64_V:
+  case RISCV::VSSSEG4E64_V:
+  case RISCV::VSSSEG5E64_V:
+  case RISCV::VSSSEG6E64_V:
+  case RISCV::VSSSEG7E64_V:
+  case RISCV::VSSSEG8E64_V:
+    return OperandInfo(MIVLMul, 6);
+
+  // 7.8.3. Vector Indexed Segment Loads and Stores
+  case RISCV::VLUXSEG2EI8_V:
+  case RISCV::VLUXSEG3EI8_V:
+  case RISCV::VLUXSEG4EI8_V:
+  case RISCV::VLUXSEG5EI8_V:
+  case RISCV::VLUXSEG6EI8_V:
+  case RISCV::VLUXSEG7EI8_V:
+  case RISCV::VLUXSEG8EI8_V:
+  case RISCV::VLOXSEG2EI8_V:
+  case RISCV::VLOXSEG3EI8_V:
+  case RISCV::VLOXSEG4EI8_V:
+  case RISCV::VLOXSEG5EI8_V:
+  case RISCV::VLOXSEG6EI8_V:
+  case RISCV::VLOXSEG7EI8_V:
+  case RISCV::VLOXSEG8EI8_V:
+    return getIndexSegmentLoadStoreOperandInfo(3, MI, MO, /* IsLoad */ true);
+  case RISCV::VSUXSEG2EI8_V:
+  case RISCV::VSUXSEG3EI8_V:
+  case RISCV::VSUXSEG4EI8_V:
+  case RISCV::VSUXSEG5EI8_V:
+  case RISCV::VSUXSEG6EI8_V:
+  case RISCV::VSUXSEG7EI8_V:
+  case RISCV::VSUXSEG8EI8_V:
+  case RISCV::VSOXSEG2EI8_V:
+  case RISCV::VSOXSEG3EI8_V:
+  case RISCV::VSOXSEG4EI8_V:
+  case RISCV::VSOXSEG5EI8_V:
+  case RISCV::VSOXSEG6EI8_V:
+  case RISCV::VSOXSEG7EI8_V:
+  case RISCV::VSOXSEG8EI8_V:
+    return getIndexSegmentLoadStoreOperandInfo(3, MI, MO, /* IsLoad */ false);
+  case RISCV::VLUXSEG2EI16_V:
+  case RISCV::VLUXSEG3EI16_V:
+  case RISCV::VLUXSEG4EI16_V:
+  case RISCV::VLUXSEG5EI16_V:
+  case RISCV::VLUXSEG6EI16_V:
+  case RISCV::VLUXSEG7EI16_V:
+  case RISCV::VLUXSEG8EI16_V:
+  case RISCV::VLOXSEG2EI16_V:
+  case RISCV::VLOXSEG3EI16_V:
+  case RISCV::VLOXSEG4EI16_V:
+  case RISCV::VLOXSEG5EI16_V:
+  case RISCV::VLOXSEG6EI16_V:
+  case RISCV::VLOXSEG7EI16_V:
+  case RISCV::VLOXSEG8EI16_V:
+    return getIndexSegmentLoadStoreOperandInfo(4, MI, MO, /* IsLoad */ true);
+  case RISCV::VSUXSEG2EI16_V:
+  case RISCV::VSUXSEG3EI16_V:
+  case RISCV::VSUXSEG4EI16_V:
+  case RISCV::VSUXSEG5EI16_V:
+  case RISCV::VSUXSEG6EI16_V:
+  case RISCV::VSUXSEG7EI16_V:
+  case RISCV::VSUXSEG8EI16_V:
+  case RISCV::VSOXSEG2EI16_V:
+  case RISCV::VSOXSEG3EI16_V:
+  case RISCV::VSOXSEG4EI16_V:
+  case RISCV::VSOXSEG5EI16_V:
+  case RISCV::VSOXSEG6EI16_V:
+  case RISCV::VSOXSEG7EI16_V:
+  case RISCV::VSOXSEG8EI16_V:
+    return getIndexSegmentLoadStoreOperandInfo(4, MI, MO, /* IsLoad */ false);
+  case RISCV::VLUXSEG2EI32_V:
+  case RISCV::VLUXSEG3EI32_V:
+  case RISCV::VLUXSEG4EI32_V:
+  case RISCV::VLUXSEG5EI32_V:
+  case RISCV::VLUXSEG6EI32_V:
+  case RISCV::VLUXSEG7EI32_V:
+  case RISCV::VLUXSEG8EI32_V:
+  case RISCV::VLOXSEG2EI32_V:
+  case RISCV::VLOXSEG3EI32_V:
+  case RISCV::VLOXSEG4EI32_V:
+  case RISCV::VLOXSEG5EI32_V:
+  case RISCV::VLOXSEG6EI32_V:
+  case RISCV::VLOXSEG7EI32_V:
+  case RISCV::VLOXSEG8EI32_V:
+    return getIndexSegmentLoadStoreOperandInfo(5, MI, MO, /* IsLoad */ true);
+  case RISCV::VSUXSEG2EI32_V:
+  case RISCV::VSUXSEG3EI32_V:
+  case RISCV::VSUXSEG4EI32_V:
+  case RISCV::VSUXSEG5EI32_V:
+  case RISCV::VSUXSEG6EI32_V:
+  case RISCV::VSUXSEG7EI32_V:
+  case RISCV::VSUXSEG8EI32_V:
+  case RISCV::VSOXSEG2EI32_V:
+  case RISCV::VSOXSEG3EI32_V:
+  case RISCV::VSOXSEG4EI32_V:
+  case RISCV::VSOXSEG5EI32_V:
+  case RISCV::VSOXSEG6EI32_V:
+  case RISCV::VSOXSEG7EI32_V:
+  case RISCV::VSOXSEG8EI32_V:
+    return getIndexSegmentLoadStoreOperandInfo(5, MI, MO, /* IsLoad */ false);
+  case RISCV::VLUXSEG2EI64_V:
+  case RISCV::VLUXSEG3EI64_V:
+  case RISCV::VLUXSEG4EI64_V:
+  case RISCV::VLUXSEG5EI64_V:
+  case RISCV::VLUXSEG6EI64_V:
+  case RISCV::VLUXSEG7EI64_V:
+  case RISCV::VLUXSEG8EI64_V:
+  case RISCV::VLOXSEG2EI64_V:
+  case RISCV::VLOXSEG3EI64_V:
+  case RISCV::VLOXSEG4EI64_V:
+  case RISCV::VLOXSEG5EI64_V:
+  case RISCV::VLOXSEG6EI64_V:
+  case RISCV::VLOXSEG7EI64_V:
+  case RISCV::VLOXSEG8EI64_V:
+    return getIndexSegmentLoadStoreOperandInfo(6, MI, MO, /* IsLoad */ true);
+  case RISCV::VSUXSEG2EI64_V:
+  case RISCV::VSUXSEG3EI64_V:
+  case RISCV::VSUXSEG4EI64_V:
+  case RISCV::VSUXSEG5EI64_V:
+  case RISCV::VSUXSEG6EI64_V:
+  case RISCV::VSUXSEG7EI64_V:
+  case RISCV::VSUXSEG8EI64_V:
+  case RISCV::VSOXSEG2EI64_V:
+  case RISCV::VSOXSEG3EI64_V:
+  case RISCV::VSOXSEG4EI64_V:
+  case RISCV::VSOXSEG5EI64_V:
+  case RISCV::VSOXSEG6EI64_V:
+  case RISCV::VSOXSEG7EI64_V:
+  case RISCV::VSOXSEG8EI64_V:
+    return getIndexSegmentLoadStoreOperandInfo(6, MI, MO, /* IsLoad */ false);
+
+  // 7.9. Vector Load/Store Whole Register Instructions
+  // EMUL=nr. EEW=eew. Since in-register byte layouts are idential to in-memory
+  // byte layouts, the same data is writen to destination register regardless
+  // of EEW. eew is just a hint to the hardware and has not functional impact.
+  // Therefore, it is be okay if we ignore eew and always use the same EEW to
+  // create more optimization opportunities.
+  // FIXME: Instead of using any SEW, we really ought to return the SEW in the
+  // instruction and add a field to OperandInfo that says the SEW is just a hint
+  // so that this optimization can use any sew to construct a ratio.
+  case RISCV::VL1RE8_V:
+  case RISCV::VL1RE16_V:
+  case RISCV::VL1RE32_V:
+  case RISCV::VL1RE64_V:
+  case RISCV::VS1R_V:
+    return OperandInfo(RISCVII::VLMUL::LMUL_1, 0);
+  case RISCV::VL2RE8_V:
+  case RISCV::VL2RE16_V:
+  case RISCV::VL2RE32_V:
+  case RISCV::VL2RE64_V:
+  case RISCV::VS2R_V:
+    return OperandInfo(RISCVII::VLMUL::LMUL_2, 0);
+  case RISCV::VL4RE8_V:
+  case RISCV::VL4RE16_V:
+  case RISCV::VL4RE32_V:
+  case RISCV::VL4RE64_V:
+  case RISCV::VS4R_V:
+    return OperandInfo(RISCVII::VLMUL::LMUL_4, 0);
+  case RISCV::VL8RE8_V:
+  case RISCV::VL8RE16_V:
+  case RISCV::VL8RE32_V:
+  case RISCV::VL8RE64_V:
+  case RISCV::VS8R_V:
+    return OperandInfo(RISCVII::VLMUL::LMUL_8, 0);
+
+  // 11. Vector Integer Arithmetic Instructions
+  // 11.1. Vector Single-Width Integer Add and Subtract
+  case RISCV::VADD_VI:
+  case RISCV::VADD_VV:
+  case RISCV::VADD_VX:
+  case RISCV::VSUB_VV:
+  case RISCV::VSUB_VX:
+  case RISCV::VRSUB_VI:
+  case RISCV::VRSUB_VX:
+    return OperandInfo(MIVLMul, MILog2SEW);
+
+  // 11.2. Vector Widening Integer Add/Subtract
+  // Def uses EEW=2*SEW and EMUL=2*LMUL. Operands use EEW=SEW and EMUL=LMUL.
+  case RISCV::VWADDU_VV:
+  case RISCV::VWADDU_VX:
+  case RISCV::VWSUBU_VV:
+  case RISCV::VWSUBU_VX:
+  case RISCV::VWADD_VV:
+  case RISCV::VWADD_VX:
+  case RISCV::VWSUB_VV:
+  case RISCV::VWSUB_VX:
+  case RISCV::VWSLL_VI: {
+    unsigned Log2EEW = IsMODef ? MILog2SEW + 1 : MILog2SEW;
+    RISCVII::VLMUL EMUL =
+        IsMODef ? RISCVVType::twoTimesVLMUL(MIVLMul) : MIVLMul;
+    return OperandInfo(EMUL, Log2EEW);
+  }
+  // Def and Op1 uses EEW=2*SEW and EMUL=2*LMUL. Op2 uses EEW=SEW and EMUL=LMUL
+  case RISCV::VWADDU_WV:
+  case RISCV::VWADDU_WX:
+  case RISCV::VWSUBU_WV:
+  case RISCV::VWSUBU_WX:
+  case RISCV::VWADD_WV:
+  case RISCV::VWADD_WX:
+  case RISCV::VWSUB_WV:
+  case RISCV::VWSUB_WX: {
+    bool TwoTimes = IsMODef || IsOp1;
+    unsigned Log2EEW = TwoTimes ? MILog2SEW + 1 : MILog2SEW;
+    RISCVII::VLMUL EMUL =
+        TwoTimes ? RISCVVType::twoTimesVLMUL(MIVLMul) : MIVLMul;
+    return OperandInfo(EMUL, Log2EEW);
+  }
+  // 11.3. Vector Integer Extension
+  case RISCV::VZEXT_VF2:
+  case RISCV::VSEXT_VF2:
+    return getIntegerExtensionOperandInfo(2, MI, MO);
+  case RISCV::VZEXT_VF4:
+  case RISCV::VSEXT_VF4:
+    return getIntegerExtensionOperandInfo(4, MI, MO);
+  case RISCV::VZEXT_VF8:
+  case RISCV::VSEXT_VF8:
+    return getIntegerExtensionOperandInfo(8, MI, MO);
+
+  // 11.4. Vector Integer Add-with-Carry / Subtract-with-Borrow Instructions
+  // EEW=SEW and EMUL=LMUL. Mask Operand EEW=1 and EMUL=(EEW/SEW)*LMUL
+  case RISCV::VADC_VIM:
+  case RISCV::VADC_VVM:
+  case RISCV::VADC_VXM:
+  case RISCV::VSBC_VVM:
+  case RISCV::VSBC_VXM:
+    return MO.getOperandNo() == 3
+               ? OperandInfo(RISCVVType::getEMULEqualsEEWDivSEWTimesLMUL(0, MI),
+                             0)
+               : OperandInfo(MIVLMul, MILog2SEW);
+  // Dest EEW=1 and EMUL=(EEW/SEW)*LMUL. Source EEW=SEW and EMUL=LMUL. Mask
+  // operand EEW=1 and EMUL=(EEW/SEW)*LMUL
+  case RISCV::VMADC_VIM:
+  case RISCV::VMADC_VVM:
+  case RISCV::VMADC_VXM:
+  case RISCV::VMSBC_VVM:
+  case RISCV::VMSBC_VXM:
+    return IsMODef || MO.getOperandNo() == 3
+               ? OperandInfo(RISCVVType::getEMULEqualsEEWDivSEWTimesLMUL(0, MI),
+                             0)
+               : OperandInfo(MIVLMul, MILog2SEW);
+  // Dest EEW=1 and EMUL=(EEW/SEW)*LMUL. Source EEW=SEW and EMUL=LMUL.
+  case RISCV::VMADC_VV:
+  case RISCV::VMADC_VI:
+  case RISCV::VMADC_VX:
+  case RISCV::VMSBC_VV:
+  case RISCV::VMSBC_VX:
+    return IsMODef ? OperandInfo(
+                         RISCVVType::getEMULEqualsEEWDivSEWTimesLMUL(0, MI), 0)
+                   : OperandInfo(MIVLMul, MILog2SEW);
+
+  // 11.5. Vector Bitwise Logical Instructions
+  // 11.6. Vector Single-Width Shift Instructions
+  // EEW=SEW. EMUL=LMUL.
+  case RISCV::VAND_VI:
+  case RISCV::VAND_VV:
+  case RISCV::VAND_VX:
+  case RISCV::VOR_VI:
+  case RISCV::VOR_VV:
+  case RISCV::VOR_VX:
+  case RISCV::VXOR_VI:
+  case RISCV::VXOR_VV:
+  case RISCV::VXOR_VX:
+  case RISCV::VSLL_VI:
+  case RISCV::VSLL_VV:
+  case RISCV::VSLL_VX:
+  case RISCV::VSRL_VI:
+  case RISCV::VSRL_VV:
+  case RISCV::VSRL_VX:
+  case RISCV::VSRA_VI:
+  case RISCV::VSRA_VV:
+  case RISCV::VSRA_VX:
+    return OperandInfo(MIVLMul, MILog2SEW);
+
+  // 11.7. Vector Narrowing Integer Right Shift Instructions
+  // Destination EEW=SEW and EMUL=LMUL, Op 1 has EEW=2*SEW EMUL=2*LMUL. Op2 has
+  // EEW=SEW EMUL=LMUL.
+  case RISCV::VNSRL_WX:
+  case RISCV::VNSRL_WI:
+  case RISCV::VNSRL_WV:
+  case RISCV::VNSRA_WI:
+  case RISCV::VNSRA_WV:
+  case RISCV::VNSRA_WX: {
+    bool TwoTimes = IsOp1;
+    unsigned Log2EEW = TwoTimes ? MILog2SEW + 1 : MILog2SEW;
+    RISCVII::VLMUL EMUL =
+        TwoTimes ? RISCVVType::twoTimesVLMUL(MIVLMul) : MIVLMul;
+    return OperandInfo(EMUL, Log2EEW);
+  }
+  // 11.8. Vector Integer Compare Instructions
+  // Dest EEW=1 and EMUL=(EEW/SEW)*LMUL. Source EEW=SEW and EMUL=LMUL.
+  case RISCV::VMSEQ_VI:
+  case RISCV::VMSEQ_VV:
+  case RISCV::VMSEQ_VX:
+  case RISCV::VMSNE_VI:
+  case RISCV::VMSNE_VV:
+  case RISCV::VMSNE_VX:
+  case RISCV::VMSLTU_VV:
+  case RISCV::VMSLTU_VX:
+  case RISCV::VMSLT_VV:
+  case RISCV::VMSLT_VX:
+  case RISCV::VMSLEU_VV:
+  case RISCV::VMSLEU_VI:
+  case RISCV::VMSLEU_VX:
+  case RISCV::VMSLE_VV:
+  case RISCV::VMSLE_VI:
+  case RISCV::VMSLE_VX:
+  case RISCV::VMSGTU_VI:
+  case RISCV::VMSGTU_VX:
+  case RISCV::VMSGT_VI:
+  case RISCV::VMSGT_VX:
+    if (IsMODef)
+      return OperandInfo(RISCVVType::getEMULEqualsEEWDivSEWTimesLMUL(0, MI), 0);
+    return OperandInfo(MIVLMul, MILog2SEW);
+
+  // 11.9. Vector Integer Min/Max Instructions
+  // EEW=SEW. EMUL=LMUL.
+  case RISCV::VMINU_VV:
+  case RISCV::VMINU_VX:
+  case RISCV::VMIN_VV:
+  case RISCV::VMIN_VX:
+  case RISCV::VMAXU_VV:
+  case RISCV::VMAXU_VX:
+  case RISCV::VMAX_VV:
+  case RISCV::VMAX_VX:
+    return OperandInfo(MIVLMul, MILog2SEW);
+
+  // 11.10. Vector Single-Width Integer Multiply Instructions
+  // Source and Dest EEW=SEW and EMUL=LMUL.
+  case RISCV::VMUL_VV:
+  case RISCV::VMUL_VX:
+  case RISCV::VMULH_VV:
+  case RISCV::VMULH_VX:
+  case RISCV::VMULHU_VV:
+  case RISCV::VMULHU_VX:
+  case RISCV::VMULHSU_VV:
+  case RISCV::VMULHSU_VX: {
+    return OperandInfo(MIVLMul, MILog2SEW);
+  }
+  // 11.11. Vector Integer Divide Instructions
+  // EEW=SEW. EMUL=LMUL.
+  case RISCV::VDIVU_VV:
+  case RISCV::VDIVU_VX:
+  case RISCV::VDIV_VV:
+  case RISCV::VDIV_VX:
+  case RISCV::VREMU_VV:
+  case RISCV::VREMU_VX:
+  case RISCV::VREM_VV:
+  case RISCV::VREM_VX:
+    return OperandInfo(MIVLMul, MILog2SEW);
+
+  // 11.12. Vector Widening Integer Multiply Instructions
+  // Source and Destination EMUL=LMUL. Destination EEW=2*SEW. Source EEW=SEW.
+  case RISCV::VWMUL_VV:
+  case RISCV::VWMUL_VX:
+  case RISCV::VWMULSU_VV:
+  case RISCV::VWMULSU_VX:
+  case RISCV::VWMULU_VV:
+  case RISCV::VWMULU_VX: {
+    unsigned Log2EEW = IsMODef ? MILog2SEW + 1 : MILog2SEW;
+    RISCVII::VLMUL EMUL =
+        IsMODef ? RISCVVType::twoTimesVLMUL(MIVLMul) : MIVLMul;
+    return OperandInfo(EMUL, Log2EEW);
+  }
+  // 11.13. Vector Single-Width Integer Multiply-Add Instructions
+  // EEW=SEW. EMUL=LMUL.
+  case RISCV::VMACC_VV:
+  case RISCV::VMACC_VX:
+  case RISCV::VNMSAC_VV:
+  case RISCV::VNMSAC_VX:
+  case RISCV::VMADD_VV:
+  case RISCV::VMADD_VX:
+  case RISCV::VNMSUB_VV:
+  case RISCV::VNMSUB_VX:
+    return OperandInfo(MIVLMul, MILog2SEW);
+
+  // 11.14. Vector Widening Integer Multiply-Add Instructions
+  // Destination EEW=2*SEW and EMUL=2*LMUL. Source EEW=SEW and EMUL=LMUL.
+  // Even though the add is a 2*SEW addition, the operands of the add are the
+  // Dest which is 2*SEW and the result of the multiply which is 2*SEW.
+  case RISCV::VWMACCU_VV:
+  case RISCV::VWMACCU_VX:
+  case RISCV::VWMACC_VV:
+  case RISCV::VWMACC_VX:
+  case RISCV::VWMACCSU_VV:
+  case RISCV::VWMACCSU_VX:
+  case RISCV::VWMACCUS_VX: {
+    // Operand 0 is destination as a def and Operand 1 is destination as a use
+    // due to SSA.
+    bool TwoTimes = IsMODef || IsOp1;
+    unsigned Log2EEW = TwoTimes ? MILog2SEW + 1 : MILog2SEW;
+    RISCVII::VLMUL EMUL =
+        TwoTimes ? RISCVVType::twoTimesVLMUL(MIVLMul) : MIVLMul;
+    return OperandInfo(EMUL, Log2EEW);
+  }
+  // 11.15. Vector Integer Merge Instructions
+  // EEW=SEW and EMUL=LMUL, except the mask operand has EEW=1 and EMUL=
+  // (EEW/SEW)*LMUL.
+  case RISCV::VMERGE_VIM:
+  case RISCV::VMERGE_VVM:
+  case RISCV::VMERGE_VXM:
+    if (MO.getOperandNo() == 3)
+      return OperandInfo(RISCVVType::getEMULEqualsEEWDivSEWTimesLMUL(0, MI), 0);
+    return OperandInfo(MIVLMul, MILog2SEW);
+
+  // 11.16. Vector Integer Move Instructions
+  // 12. Vector Fixed-Point Arithmetic Instructions
+  // 12.1. Vector Single-Width Saturating Add and Subtract
+  // 12.2. Vector Single-Width Averaging Add and Subtract
+  // EEW=SEW. EMUL=LMUL.
+  case RISCV::VMV_V_I:
+  case RISCV::VMV_V_V:
+  case RISCV::VMV_V_X:
+  case RISCV::VSADDU_VI:
+  case RISCV::VSADDU_VV:
+  case RISCV::VSADDU_VX:
+  case RISCV::VSADD_VI:
+  case RISCV::VSADD_VV:
+  case RISCV::VSADD_VX:
+  case RISCV::VSSUBU_VV:
+  case RISCV::VSSUBU_VX:
+  case RISCV::VSSUB_VV:
+  case RISCV::VSSUB_VX:
+  case RISCV::VAADDU_VV:
+  case RISCV::VAADDU_VX:
+  case RISCV::VAADD_VV:
+  case RISCV::VAADD_VX:
+  case RISCV::VASUBU_VV:
+  case RISCV::VASUBU_VX:
+  case RISCV::VASUB_VV:
+  case RISCV::VASUB_VX:
+    return OperandInfo(MIVLMul, MILog2SEW);
+
+  // 12.3. Vector Single-Width Fractional Multiply with Rounding and Saturation
+  // Destination EEW=2*SEW and EMUL=2*EMUL. Source EEW=SEW and EMUL=LMUL.
+  case RISCV::VSMUL_VV:
+  case RISCV::VSMUL_VX: {
+    unsigned Log2EEW = IsMODef ? MILog2SEW + 1 : MILog2SEW;
+    RISCVII::VLMUL EMUL =
+        IsMODef ? RISCVVType::twoTimesVLMUL(MIVLMul) : MIVLMul;
+    return OperandInfo(EMUL, Log2EEW);
+  }
+  // 12.4. Vector Single-Width Scaling Shift Instructions
+  // EEW=SEW. EMUL=LMUL.
+  case RISCV::VSSRL_VI:
+  case RISCV::VSSRL_VV:
+  case RISCV::VSSRL_VX:
+  case RISCV::VSSRA_VI:
+  case RISCV::VSSRA_VV:
+  case RISCV::VSSRA_VX:
+    return OperandInfo(MIVLMul, MILog2SEW);
+
+  // 12.5. Vector Narrowing Fixed-Point Clip Instructions
+  // Destination and Op1 EEW=SEW and EMUL=LMUL. Op2 EEW=2*SEW and EMUL=2*LMUL
+  case RISCV::VNCLIPU_WI:
+  case RISCV::VNCLIPU_WV:
+  case RISCV::VNCLIPU_WX:
+  case RISCV::VNCLIP_WI:
+  case RISCV::VNCLIP_WV:
+  case RISCV::VNCLIP_WX: {
+    bool TwoTimes = !IsMODef && IsOp1;
+    unsigned Log2EEW = TwoTimes ? MILog2SEW + 1 : MILog2SEW;
+    RISCVII::VLMUL EMUL =
+        TwoTimes ? RISCVVType::twoTimesVLMUL(MIVLMul) : MIVLMul;
+    return OperandInfo(EMUL, Log2EEW);
+  }
+  // 13. Vector Floating-Point Instructions
+  // 13.2. Vector Single-Width Floating-Point Add/Subtract Instructions
+  // EEW=SEW. EMUL=LMUL.
+  case RISCV::VFADD_VF:
+  case RISCV::VFADD_VV:
+  case RISCV::VFSUB_VF:
+  case RISCV::VFSUB_VV:
+  case RISCV::VFRSUB_VF:
+    return OperandInfo(MIVLMul, MILog2SEW);
+
+  // 13.3. Vector Widening Floating-Point Add/Subtract Instructions
+  // Dest EEW=2*SEW and EMUL=2*LMUL. Source EEW=SEW and EMUL=LMUL.
+  case RISCV::VFWADD_VV:
+  case RISCV::VFWADD_VF:
+  case RISCV::VFWSUB_VV:
+  case RISCV::VFWSUB_VF: {
+    unsigned Log2EEW = IsMODef ? MILog2SEW + 1 : MILog2SEW;
+    RISCVII::VLMUL EMUL =
+        IsMODef ? RISCVVType::twoTimesVLMUL(MIVLMul) : MIVLMul;
+    return OperandInfo(EMUL, Log2EEW);
+  }
+  // Dest and Op1 EEW=2*SEW and EMUL=2*LMUL. Op2 EEW=SEW and EMUL=LMUL.
+  case RISCV::VFWADD_WF:
+  case RISCV::VFWADD_WV:
+  case RISCV::VFWSUB_WF:
+  case RISCV::VFWSUB_WV: {
+    bool TwoTimes = IsMODef || IsOp1;
+    unsigned Log2EEW = TwoTimes ? MILog2SEW + 1 : MILog2SEW;
+    RISCVII::VLMUL EMUL =
+        TwoTimes ? RISCVVType::twoTimesVLMUL(MIVLMul) : MIVLMul;
+    return OperandInfo(EMUL, Log2EEW);
+  }
+  // 13.4. Vector Single-Width Floating-Point Multiply/Divide Instructions
+  // EEW=SEW. EMUL=LMUL.
+  case RISCV::VFMUL_VF:
+  case RISCV::VFMUL_VV:
+  case RISCV::VFDIV_VF:
+  case RISCV::VFDIV_VV:
+  case RISCV::VFRDIV_VF:
+    return OperandInfo(MIVLMul, MILog2SEW);
+
+  // 13.5. Vector Widening Floating-Point Multiply
+  case RISCV::VFWMUL_VF:
+  case RISCV::VFWMUL_VV:
+    return OperandInfo(MIVLMul, MILog2SEW);
+
+  // 13.6. Vector Single-Width Floating-Point Fused Multiply-Add Instructions
+  // EEW=SEW. EMUL=LMUL.
+  // TODO: FMA instructions reads 3 registers but MC layer only reads 2
+  // registers since its missing that the output operand should be part of the
+  // input operand list.
+  case RISCV::VFMACC_VF:
+  case RISCV::VFMACC_VV:
+  case RISCV::VFNMACC_VF:
+  case RISCV::VFNMACC_VV:
+  case RISCV::VFMSAC_VF:
+  case RISCV::VFMSAC_VV:
+  case RISCV::VFNMSAC_VF:
+  case RISCV::VFNMSAC_VV:
+  case RISCV::VFMADD_VF:
+  case RISCV::VFMADD_VV:
+  case RISCV::VFNMADD_VF:
+  case RISCV::VFNMADD_VV:
+  case RISCV::VFMSUB_VF:
+  case RISCV::VFMSUB_VV:
+  case RISCV::VFNMSUB_VF:
+  case RISCV::VFNMSUB_VV:
+    return OperandInfo(OperandInfo::State::Unknown);
+
+  // 13.7. Vector Widening Floating-Point Fused Multiply-Add Instructions
+  // Dest EEW=2*SEW and EMUL=2*LMUL. Source EEW=SEW EMUL=LMUL.
+  case RISCV::VFWMACC_VF:
+  case RISCV::VFWMACC_VV:
+  case RISCV::VFWNMACC_VF:
+  case RISCV::VFWNMACC_VV:
+  case RISCV::VFWMSAC_VF:
+  case RISCV::VFWMSAC_VV:
+  case RISCV::VFWNMSAC_VF:
+  case RISCV::VFWNMSAC_VV: {
+    // Operand 0 is destination as a def and Operand 1 is destination as a use
+    // due to SSA.
+    bool TwoTimes = IsMODef || IsOp1;
+    unsigned Log2EEW = TwoTimes ? MILog2SEW + 1 : MILog2SEW;
+    RISCVII::VLMUL EMUL =
+        TwoTimes ? RISCVVType::twoTimesVLMUL(MIVLMul) : MIVLMul;
+    return OperandInfo(EMUL, Log2EEW);
+  }
+  // 13.8. Vector Floating-Point Square-Root Instruction
+  // 13.9. Vector Floating-Point Reciprocal Square-Root Estimate Instruction
+  // 13.10. Vector Floating-Point Reciprocal Estimate Instruction
+  // 13.11. Vector Floating-Point MIN/MAX Instructions
+  // 13.12. Vector Floating-Point Sign-Injection Instructions
+  // 13.14. Vector Floating-Point Classify Instruction
+  // 13.16. Vector Floating-Point Move Instruction
+  // 13.17. Single-Width Floating-Point/Integer Type-Convert Instructions
+  // EEW=SEW. EMUL=LMUL.
+  case RISCV::VFSQRT_V:
+  case RISCV::VFRSQRT7_V:
+  case RISCV::VFREC7_V:
+  case RISCV::VFMIN_VF:
+  case RISCV::VFMIN_VV:
+  case RISCV::VFMAX_VF:
+  case RISCV::VFMAX_VV:
+  case RISCV::VFSGNJ_VF:
+  case RISCV::VFSGNJ_VV:
+  case RISCV::VFSGNJN_VV:
+  case RISCV::VFSGNJN_VF:
+  case RISCV::VFSGNJX_VF:
+  case RISCV::VFSGNJX_VV:
+  case RISCV::VFCLASS_V:
+  case RISCV::VFMV_V_F:
+  case RISCV::VFCVT_XU_F_V:
+  case RISCV::VFCVT_X_F_V:
+  case RISCV::VFCVT_RTZ_XU_F_V:
+  case RISCV::VFCVT_RTZ_X_F_V:
+  case RISCV::VFCVT_F_XU_V:
+  case RISCV::VFCVT_F_X_V:
+    return OperandInfo(MIVLMul, MILog2SEW);
+
+  // 13.13. Vector Floating-Point Compare Instructions
+  // Dest EEW=1 and EMUL=(EEW/SEW)*LMUL. Source EEW=SEW EMUL=LMUL.
+  case RISCV::VMFEQ_VF:
+  case RISCV::VMFEQ_VV:
+  case RISCV::VMFNE_VF:
+  case RISCV::VMFNE_VV:
+  case RISCV::VMFLT_VF:
+  case RISCV::VMFLT_VV:
+  case RISCV::VMFLE_VF:
+  case RISCV::VMFLE_VV:
+  case RISCV::VMFGT_VF:
+  case RISCV::VMFGE_VF:
+    if (IsMODef)
+      return OperandInfo(RISCVVType::getEMULEqualsEEWDivSEWTimesLMUL(0, MI), 0);
+    return OperandInfo(MIVLMul, MILog2SEW);
+
+  // 13.15. Vector Floating-Point Merge Instruction
+  // EEW=SEW and EMUL=LMUL, except the mask operand has EEW=1 and EMUL=
+  // (EEW/SEW)*LMUL.
+  case RISCV::VFMERGE_VFM:
+    if (IsOp3)
+      return OperandInfo(RISCVVType::getEMULEqualsEEWDivSEWTimesLMUL(0, MI), 0);
+    return OperandInfo(MIVLMul, MILog2SEW);
+
+  // 13.18. Widening Floating-Point/Integer Type-Convert Instructions
+  // Dest EEW=2*SEW and EMUL=2*LMUL. Source EEW=SEW and EMUL=LMUL.
+  case RISCV::VFWCVT_XU_F_V:
+  case RISCV::VFWCVT_X_F_V:
+  case RISCV::VFWCVT_RTZ_XU_F_V:
+  case RISCV::VFWCVT_RTZ_X_F_V:
+  case RISCV::VFWCVT_F_XU_V:
+  case RISCV::VFWCVT_F_X_V:
+  case RISCV::VFWCVT_F_F_V: {
+    unsigned Log2EEW = IsMODef ? MILog2SEW + 1 : MILog2SEW;
+    RISCVII::VLMUL EMUL =
+        IsMODef ? RISCVVType::twoTimesVLMUL(MIVLMul) : MIVLMul;
+    return OperandInfo(EMUL, Log2EEW);
+  }
+  // 13.19. Narrowing Floating-Point/Integer Type-Convert Instructions
+  // EMUL=LMUL. Dest EEW=SEW/2. Source EEW=SEW EMUL=LMUL.
+  case RISCV::VFNCVT_XU_F_W:
+  case RISCV::VFNCVT_X_F_W:
+  case RISCV::VFNCVT_RTZ_XU_F_W:
+  case RISCV::VFNCVT_RTZ_X_F_W:
+  case RISCV::VFNCVT_F_XU_W:
+  case RISCV::VFNCVT_F_X_W:
+  case RISCV::VFNCVT_F_F_W:
+  case RISCV::VFNCVT_ROD_F_F_W: {
+    unsigned Log2EEW = IsMODef ? MILog2SEW - 1 : MILog2SEW;
+    RISCVII::VLMUL EMUL = IsMODef ? RISCVVType::halfVLMUL(MIVLMul) : MIVLMul;
+    return OperandInfo(EMUL, Log2EEW);
+  }
+  // 14. Vector Reduction Operations
+  // 14.1. Vector Single-Width Integer Reduction Instructions
+  // We need to return Unknown since only element 0 of reduction is valid but it
+  // was generated by reducing over all of the input elements. There are 3
+  // vector sources for reductions. One for scalar, one for tail value, and one
+  // for the elements to reduce over. Only the one with the elements to reduce
+  // over obeys VL. The other two only read element 0 from the register.
+  case RISCV::VREDAND_VS:
+  case RISCV::VREDMAX_VS:
+  case RISCV::VREDMAXU_VS:
+  case RISCV::VREDMIN_VS:
+  case RISCV::VREDMINU_VS:
+  case RISCV::VREDOR_VS:
+  case RISCV::VREDSUM_VS:
+  case RISCV::VREDXOR_VS:
+    return OperandInfo(OperandInfo::State::Unknown);
+
+  // 14.2. Vector Widening Integer Reduction Instructions
+  // Dest EEW=2*SEW and EMUL=2*LMUL. Source EEW=SEW EMUL=LMUL. Source is zero
+  // extended to 2*SEW in order to generate 2*SEW Dest.
+  case RISCV::VWREDSUM_VS:
+  case RISCV::VWREDSUMU_VS: {
+    unsigned Log2EEW = IsMODef ? MILog2SEW + 1 : MILog2SEW;
+    RISCVII::VLMUL EMUL =
+        IsMODef ? RISCVVType::twoTimesVLMUL(MIVLMul) : MIVLMul;
+    return OperandInfo(EMUL, Log2EEW);
+  }
+  // 14.3. Vector Single-Width Floating-Point Reduction Instructions
+  // EMUL=LMUL. EEW=SEW.
+  case RISCV::VFREDMAX_VS:
+  case RISCV::VFREDMIN_VS:
+  case RISCV::VFREDOSUM_VS:
+  case RISCV::VFREDUSUM_VS:
+    return OperandInfo(MIVLMul, MILog2SEW);
+
+  // 14.4. Vector Widening Floating-Point Reduction Instructions
+  // Source EEW=SEW and EMUL=LMUL. Dest EEW=2*SEW and EMUL=2*LMUL.
+  case RISCV::VFWREDOSUM_VS:
+  case RISCV::VFWREDUSUM_VS: {
+    unsigned Log2EEW = IsMODef ? MILog2SEW + 1 : MILog2SEW;
+    RISCVII::VLMUL EMUL =
+        IsMODef ? RISCVVType::twoTimesVLMUL(MIVLMul) : MIVLMul;
+    return OperandInfo(EMUL, Log2EEW);
+  }
+
+  // 15. Vector Mask Instructions
+  // 15.2. Vector count population in mask vcpop.m
+  // 15.3. vfirst find-first-set mask bit
+  // 15.4. vmsbf.m set-before-first mask bit
+  // 15.6. vmsof.m set-only-first mask bit
+  // EEW=1 and EMUL= (EEW/SEW)*LMUL
+  case RISCV::VMAND_MM:
+  case RISCV::VMNAND_MM:
+  case RISCV::VMANDN_MM:
+  case RISCV::VMXOR_MM:
+  case RISCV::VMOR_MM:
+  case RISCV::VMNOR_MM:
+  case RISCV::VMORN_MM:
+  case RISCV::VMXNOR_MM:
+  case RISCV::VCPOP_M:
+  case RISCV::VFIRST_M:
+  case RISCV::VMSBF_M:
+  case RISCV::VMSIF_M:
+  case RISCV::VMSOF_M: {
+    return OperandInfo(RISCVVType::getEMULEqualsEEWDivSEWTimesLMUL(0, MI), 0);
+  }
+  // 15.8. Vector Iota Instruction
+  // Dest and Op1 EEW=SEW and EMUL=LMUL. Op2 EEW=1 and EMUL(EEW/SEW)*LMUL.
+  case RISCV::VIOTA_M: {
+    bool IsDefOrOp1 = IsMODef || IsOp1;
+    unsigned Log2EEW = IsDefOrOp1 ? 0 : MILog2SEW;
+    if (IsDefOrOp1)
+      return OperandInfo(MIVLMul, Log2EEW);
+    return OperandInfo(
+        RISCVVType::getEMULEqualsEEWDivSEWTimesLMUL(MILog2SEW, MI), Log2EEW);
+  }
+  // 15.9. Vector Element Index Instruction
+  // Dest EEW=SEW EMUL=LMUL. Mask Operand EEW=1 and EMUL(EEW/SEW)*LMUL.
+  case RISCV::VID_V: {
+    unsigned Log2EEW = IsMODef ? MILog2SEW : 0;
+    if (IsMODef)
+      return OperandInfo(MIVLMul, Log2EEW);
+    return OperandInfo(RISCVVType::getEMULEqualsEEWDivSEWTimesLMUL(Log2EEW, MI),
+                       Log2EEW);
+  }
+  // 16. Vector Permutation Instructions
+  // 16.1. Integer Scalar Move Instructions
+  // 16.2. Floating-Point Scalar Move Instructions
+  // EMUL=LMUL. EEW=SEW.
+  case RISCV::VMV_X_S:
+  case RISCV::VMV_S_X:
+  case RISCV::VFMV_F_S:
+  case RISCV::VFMV_S_F:
+    return OperandInfo(MIVLMul, MILog2SEW);
+
+  // 16.3. Vector Slide Instructions
+  // EMUL=LMUL. EEW=SEW.
+  case RISCV::VSLIDEUP_VI:
+  case RISCV::VSLIDEUP_VX:
+  case RISCV::VSLIDEDOWN_VI:
+  case RISCV::VSLIDEDOWN_VX:
+  case RISCV::VSLIDE1UP_VX:
+  case RISCV::VFSLIDE1UP_VF:
+  case RISCV::VSLIDE1DOWN_VX:
+  case RISCV::VFSLIDE1DOWN_VF:
+    return OperandInfo(MIVLMul, MILog2SEW);
+
+  // 16.4. Vector Register Gather Instructions
+  // EMUL=LMUL. EEW=SEW. For mask operand, EMUL=1 and EEW=1.
+  case RISCV::VRGATHER_VI:
+  case RISCV::VRGATHER_VV:
+  case RISCV::VRGATHER_VX:
+    return OperandInfo(MIVLMul, MILog2SEW);
+  // Destination EMUL=LMUL and EEW=SEW. Op2 EEW=SEW and EMUL=LMUL. Op1 EEW=16
+  // and EMUL=(16/SEW)*LMUL.
+  case RISCV::VRGATHEREI16_VV: {
+    if (IsMODef || IsOp2)
+      return OperandInfo(MIVLMul, MILog2SEW);
+    return OperandInfo(RISCVVType::getEMULEqualsEEWDivSEWTimesLMUL(4, MI), 4);
+  }
+  // 16.5. Vector Compress Instruction
+  // EMUL=LMUL. EEW=SEW.
+  case RISCV::VCOMPRESS_VM:
+    return OperandInfo(MIVLMul, MILog2SEW);
+
+  // 16.6. Whole Vector Register Move
+  case RISCV::VMV1R_V:
+  case RISCV::VMV2R_V:
+  case RISCV::VMV4R_V:
+  case RISCV::VMV8R_V:
+    llvm_unreachable("These instructions don't have pseudo versions so they "
+                     "don't have an SEW operand.");
+
+  default:
+    return OperandInfo(OperandInfo::State::Unknown);
+  }
+}
+
+/// Return true if this optimization should consider MI for VL reduction. This
+/// white-list approach simplifies this optimization for instructions that may
+/// have more complex semantics with relation to how it uses VL.
+static bool isSupportedInstr(const MachineInstr &MI) {
+  const RISCVVPseudosTable::PseudoInfo *RVV =
+      RISCVVPseudosTable::getPseudoInfo(MI.getOpcode());
+
+  if (!RVV)
+    return false;
+
+  switch (RVV->BaseInstr) {
+  case RISCV::VADD_VI:
+  case RISCV::VADD_VV:
+  case RISCV::VADD_VX:
+  case RISCV::VMUL_VV:
+  case RISCV::VMUL_VX:
+  case RISCV::VSLL_VI:
+  case RISCV::VSEXT_VF2:
+  case RISCV::VSEXT_VF4:
+  case RISCV::VSEXT_VF8:
+  case RISCV::VZEXT_VF2:
+  case RISCV::VZEXT_VF4:
+  case RISCV::VZEXT_VF8:
+  case RISCV::VMV_V_I:
+  case RISCV::VMV_V_X:
+  case RISCV::VNSRL_WI:
+  case RISCV::VWADD_VV:
+  case RISCV::VWADDU_VV:
+  case RISCV::VWMACC_VX:
+  case RISCV::VWMACCU_VX:
+  case RISCV::VWSLL_VI:
+    return true;
+  }
+
+  return false;
+}
+
+/// Return true if MO is a vector operand but is used as a scalar operand.
+static bool isVectorOpUsedAsScalarOp(MachineOperand &MO) {
+  MachineInstr *MI = MO.getParent();
+  const RISCVVPseudosTable::PseudoInfo *RVV =
+      RISCVVPseudosTable::getPseudoInfo(MI->getOpcode());
+
+  if (!RVV)
+    return false;
+
+  switch (RVV->BaseInstr) {
+  // Reductions only use vs1[0] of vs1
+  case RISCV::VREDAND_VS:
+  case RISCV::VREDMAX_VS:
+  case RISCV::VREDMAXU_VS:
+  case RISCV::VREDMIN_VS:
+  case RISCV::VREDMINU_VS:
+  case RISCV::VREDOR_VS:
+  case RISCV::VREDSUM_VS:
+  case RISCV::VREDXOR_VS:
+  case RISCV::VWREDSUM_VS:
+  case RISCV::VWREDSUMU_VS:
+  case RISCV::VFREDMAX_VS:
+  case RISCV::VFREDMIN_VS:
+  case RISCV::VFREDOSUM_VS:
+  case RISCV::VFREDUSUM_VS:
+  case RISCV::VFWREDOSUM_VS:
+  case RISCV::VFWREDUSUM_VS: {
+    return isOpN(MO, 2);
+  }
+  default:
+    return false;
+  }
+}
+
+static bool safeToPropgateVL(const MachineInstr &MI) {
+  const RISCVVPseudosTable::PseudoInfo *RVV =
+      RISCVVPseudosTable::getPseudoInfo(MI.getOpcode());
+  if (!RVV)
+    return false;
+
+  switch (RVV->BaseInstr) {
+  // vslidedown instructions may use the higher part of the input operand beyond
+  // the VL.
+  case RISCV::VSLIDEDOWN_VI:
+  case RISCV::VSLIDEDOWN_VX:
+  case RISCV::VSLIDE1DOWN_VX:
+  case RISCV::VFSLIDE1DOWN_VF:
+
+  // vrgather instructions may index beyond the VL.
+  case RISCV::VRGATHER_VI:
+  case RISCV::VRGATHER_VV:
+  case RISCV::VRGATHER_VX:
+  case RISCV::VRGATHEREI16_VV:
+    return false;
+
+  default:
+    return true;
+  }
+}
+
+bool RISCVVLOptimizer::isCandidate(const MachineInstr &MI) const {
+
+  LLVM_DEBUG(
+      dbgs() << "Check whether the instruction is a candidate for reducing VL:"
+             << MI << "\n");
+
+  const MCInstrDesc &Desc = MI.getDesc();
+  if (!RISCVII::hasVLOp(Desc.TSFlags) || !RISCVII::hasSEWOp(Desc.TSFlags)) {
+    LLVM_DEBUG(dbgs() << "  Not a candidate due to lack of vl op or sew op\n");
+    return false;
+  }
+
+  if (MI.getNumDefs() != 1) {
+    LLVM_DEBUG(dbgs() << " Not a candidate due to it def more than one\n");
+    return false;
+  }
+  unsigned VLOpNum = RISCVII::getVLOpNum(Desc);
+  const MachineOperand &VLOp = MI.getOperand(VLOpNum);
+  if (!VLOp.isImm() || VLOp.getImm() != RISCV::VLMaxSentinel) {
+    LLVM_DEBUG(dbgs() << "  Not a candidate due to VL is not VLMAX\n");
+    return false;
+  }
+
+  // Some instructions that produce vectors have semantics that make it more
+  // difficult to determine whether the VL can be reduced. For example, some
+  // instructions, such as reductions, may write lanes past VL to a scalar
+  // register. Other instructions, such as some loads or stores, may write
+  // lower lanes using data from higher lanes. There may be other complex
+  // semantics not mentioned here that make it hard to determine whether
+  // the VL can be optimized. As a result, a white-list of supported
+  // instructions is used. Over time, more instructions cam be supported
+  // upon careful examination of their semantics under the logic in this
+  // optimization.
+  // TODO: Use a better approach than a white-list, such as adding
+  // properties to instructions using something like TSFlags.
+  if (!isSupportedInstr(MI)) {
+    LLVM_DEBUG(dbgs() << "  Not a candidate due to unsupported instruction\n");
+    return false;
+  }
+
+  return true;
+}
+
+bool RISCVVLOptimizer::tryReduceVL(MachineInstr &OrigMI) {
+  SetVector<MachineInstr *> Worklist;
+  Worklist.insert(&OrigMI);
+
+  bool MadeChange = false;
+  while (!Worklist.empty()) {
+    MachineInstr &MI = *Worklist.pop_back_val();
+    LLVM_DEBUG(dbgs() << "Try reduce VL for " << MI << "\n");
+    std::optional<Register> CommonVL;
+    bool CanReduceVL = true;
+    for (auto &UserOp : MRI->use_operands(MI.getOperand(0).getReg())) {
+      const MachineInstr &UserMI = *UserOp.getParent();
+      LLVM_DEBUG(dbgs() << "  Check user: " << UserMI << "\n");
+
+      // Instructions like reductions may use a vector register as a scalar
+      // register. In this case, we should treat it like a scalar register which
+      // does not impact the decision on whether to optimize VL.
+      if (isVectorOpUsedAsScalarOp(UserOp)) {
+        [[maybe_unused]] Register R = UserOp.getReg();
+        [[maybe_unused]] const TargetRegisterClass *RC = MRI->getRegClass(R);
+        assert(RISCV::VRRegClass.hasSubClassEq(RC) &&
+               "Expect LMUL 1 register class for vector as scalar operands!");
+        LLVM_DEBUG(dbgs() << "    Use this operand as a scalar operand\n");
+        continue;
+      }
+
+      if (!safeToPropgateVL(UserMI)) {
+        LLVM_DEBUG(dbgs() << "    Abort due to used by unsafe instruction\n");
+        CanReduceVL = false;
+        break;
+      }
+
+      // Tied operands might pass through.
+      if (UserOp.isTied()) {
+        LLVM_DEBUG(dbgs() << "    Abort due to user use it as tied operand\n");
+        CanReduceVL = false;
+        break;
+      }
+
+      const MCInstrDesc &Desc = UserMI.getDesc();
+      if (!RISCVII::hasVLOp(Desc.TSFlags) || !RISCVII::hasSEWOp(Desc.TSFlags)) {
+        LLVM_DEBUG(dbgs() << "    Abort due to lack of VL or SEW, assume that"
+                             " use VLMAX.\n");
+        CanReduceVL = false;
+        break;
+      }
+
+      unsigned VLOpNum = RISCVII::getVLOpNum(Desc);
+      const MachineOperand &VLOp = UserMI.getOperand(VLOpNum);
+      // Looking for a register VL that isn't X0.
+      if (!VLOp.isReg() || VLOp.getReg() == RISCV::X0) {
+        LLVM_DEBUG(dbgs() << "    Abort due to user use X0 as VL.\n");
+        CanReduceVL = false;
+        break;
+      }
+
+      if (!CommonVL) {
+        CommonVL = VLOp.getReg();
+      } else if (*CommonVL != VLOp.getReg()) {
+        LLVM_DEBUG(dbgs() << "    Abort due to users have different VL!\n");
+        CanReduceVL = false;
+        break;
+      }
+
+      // The SEW and LMUL of destination and source registers need to match.
+
+      // If the produced Dest is not a vector register, then it has no EEW or
+      // EMUL, so there is no need to check that producer and consumer LMUL and
+      // SEW match. We've already checked above that UserOp is a vector
+      // register.
+      if (!isVectorRegClass(MI.getOperand(0).getReg(), MRI)) {
----------------
preames wrote:

This can be hoisted out of the loop right?  Though actually, how does such a thing end up on the visit list at all?  This maybe implies a missing guard somewhere.

https://github.com/llvm/llvm-project/pull/108640


More information about the llvm-commits mailing list