[llvm] [RISCV] Preserve independent VTYPE facts across CFG joins (PR #228735)

via llvm-commits llvm-commits at lists.llvm.org
Sat Oct 3 09:21:24 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-risc-v

Author: tinfengyu

<details>
<summary>Changes</summary>

RISCVInsertVSETVLI can lose independently useful VTYPE information across CFG joins when incoming paths disagree on AVL/VL. This can lead to redundant vector configuration instructions even when the required VTYPE is already known.

Add a bounded side analysis that tracks VTYPE facts independently of VL/AVL information. Forward dataflow computes VTYPE facts that hold on all incoming paths, while backward dataflow determines whether the VTYPE established by a candidate configuration is needed before it is overwritten or observed. The analysis deliberately does not infer a common VL from a common VTYPE.

The optimization remains conservative around unsupported or potentially observable operations. Candidate instructions are collected before mutation and removed separately, after which physical VL/VTYPE liveness and analysis state are repaired.

Tests cover independent VTYPE facts across CFG joins, differing AVL provenance, cases where a common VTYPE must not be treated as a common VL, and existing RVV cases affected by the generated-code changes. The focused and affected RISC-V tests pass with the final patch.

AI tool usage: AI tools assisted with the implementation and tests. I reviewed and validated the implementation, tests, and generated changes and take responsibility for the contribution.

---

Patch is 99.11 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/228735.diff


5 Files Affected:

- (modified) llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp (+557) 
- (modified) llvm/test/CodeGen/RISCV/rvv/fixed-vectors-masked-gather.ll (+136-136) 
- (modified) llvm/test/CodeGen/RISCV/rvv/vp-vector-interleaved-access.ll (+2-3) 
- (added) llvm/test/CodeGen/RISCV/rvv/vsetvli-independent-type-facts.ll (+390) 
- (added) llvm/test/CodeGen/RISCV/rvv/vsetvli-independent-type-facts.mir (+1243) 


``````````diff
diff --git a/llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp b/llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp
index 1087737e2d96c..b67c01ae174e4 100644
--- a/llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp
+++ b/llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp
@@ -27,12 +27,15 @@
 #include "RISCV.h"
 #include "RISCVSubtarget.h"
 #include "RISCVVSETVLIInfoAnalysis.h"
+#include "llvm/ADT/BitVector.h"
 #include "llvm/ADT/PostOrderIterator.h"
+#include "llvm/ADT/SmallSet.h"
 #include "llvm/ADT/Statistic.h"
 #include "llvm/CodeGen/LiveDebugVariables.h"
 #include "llvm/CodeGen/LiveIntervals.h"
 #include "llvm/CodeGen/LiveStacks.h"
 #include "llvm/CodeGen/MachineFunctionPass.h"
+#include <optional>
 #include <queue>
 using namespace llvm;
 using namespace RISCV;
@@ -43,6 +46,21 @@ using namespace RISCV;
 STATISTIC(NumInsertedVSETVL, "Number of VSETVL inst inserted");
 STATISTIC(NumCoalescedVSETVL, "Number of VSETVL inst coalesced");
 
+STATISTIC(NumIndependentVTYPECandidates, "Number of optional type-only setups");
+STATISTIC(NumIndependentVTYPEBlocks, "Number of blocks in type-fact cleanup");
+STATISTIC(NumIndependentVTYPEForwardVisits,
+          "Number of forward type-fact worklist visits");
+STATISTIC(NumIndependentVTYPEBackwardVisits,
+          "Number of backward type-safety worklist visits");
+STATISTIC(NumIndependentVTYPEInstructionScans,
+          "Number of instructions scanned by type-fact worklists");
+STATISTIC(NumIndependentVTYPEDeleted,
+          "Number of independently redundant type-only setups deleted");
+
+static cl::opt<bool> EnableIndependentVTYPEFacts(
+    DEBUG_TYPE "-independent-type-facts", cl::Hidden, cl::init(true),
+    cl::desc("Remove redundant vector setups using independent type facts"));
+
 static cl::opt<bool> EnsureWholeVectorRegisterMoveValidVTYPE(
     DEBUG_TYPE "-whole-vector-register-move-valid-vtype", cl::Hidden,
     cl::desc("Insert vsetvlis before vmvNr.vs to ensure vtype is valid and "
@@ -88,6 +106,531 @@ enum TKTMMode {
   VSETTM = 1,
 };
 
+// Common type facts describe fixed, final MIR. They intentionally say nothing
+// about AVL, the selected VL, or whether VL is zero.
+struct IndependentVTYPEFact {
+  enum Kind { NotReached, Exact, Clear, Unknown } K = NotReached;
+  unsigned Encoding = 0;
+
+  bool operator==(const IndependentVTYPEFact &Other) const {
+    return K == Other.K && (K != Exact || Encoding == Other.Encoding);
+  }
+
+  IndependentVTYPEFact merge(IndependentVTYPEFact Other) const {
+    if (K == NotReached)
+      return Other;
+    if (Other.K == NotReached || *this == Other)
+      return *this;
+    if (K == Unknown || Other.K == Unknown)
+      return {Unknown};
+    return {Clear};
+  }
+};
+
+// This deliberately excludes explicit architectural-state manipulation. Check
+// both the original stream (before configs are inserted) and the final stream.
+static bool hasIndependentVTYPEFactScope(const MachineFunction &MF,
+                                         const RISCVSubtarget &ST,
+                                         bool BeforeInsertion) {
+  if (ST.hasVendorXSfmmbase())
+    return false;
+  for (const MachineBasicBlock &MBB : MF)
+    for (const MachineInstr &MI : MBB) {
+      if (MI.isBundled() || MI.isCall() || MI.isInlineAsm() ||
+          RISCVInstrInfo::isFaultOnlyFirstLoad(MI) ||
+          RISCVInstrInfo::isXSfmmVectorConfigInstr(MI) ||
+          (MI.hasUnmodeledSideEffects() && !MI.isMetaInstruction() &&
+           MI.getOpcode() != RISCV::PseudoRET && !MI.isBranch()))
+        return false;
+      switch (MI.getOpcode()) {
+      case RISCV::CSRRW:
+      case RISCV::CSRRS:
+      case RISCV::CSRRC:
+      case RISCV::CSRRWI:
+      case RISCV::CSRRSI:
+      case RISCV::CSRRCI:
+      case RISCV::ECALL:
+      case RISCV::EBREAK:
+      case RISCV::VSETVLI:
+      case RISCV::VSETIVLI:
+      case RISCV::VSETVL:
+      case RISCV::PseudoReadVL:
+      case RISCV::PseudoReadVLENBViaVSETVLIX0:
+        return false;
+      }
+      bool Config = RISCVInstrInfo::isVectorConfigInstr(MI);
+      if (BeforeInsertion && Config)
+        return false;
+      uint64_t Flags = MI.getDesc().TSFlags;
+      if (RISCVII::hasTWidenOp(Flags) ||
+          RISCVII::getAltFmtType(Flags) == RISCVII::AltFmtType::AltFmt)
+        return false;
+      for (const MachineOperand &MO : MI.operands()) {
+        if (MO.isRegMask())
+          return false;
+        if (!MO.isReg() ||
+            (MO.getReg() != RISCV::VL && MO.getReg() != RISCV::VTYPE))
+          continue;
+        if (!MO.isImplicit() || MO.getSubReg())
+          return false;
+        if (Config)
+          continue; // Config operand shapes are checked by the decoder.
+        if (MO.isDef())
+          return false;
+        if (!RISCVII::hasSEWOp(Flags) &&
+            !RISCV::isVectorCopy(ST.getRegisterInfo(), MI))
+          return false;
+        if (MO.getReg() == RISCV::VL && !RISCVII::hasVLOp(Flags))
+          return false;
+      }
+    }
+  return true;
+}
+
+class IndependentVTYPECleanup {
+  MachineFunction &MF;
+  const RISCVSubtarget &ST;
+  const TargetRegisterInfo &TRI;
+  MachineRegisterInfo &MRI;
+  LiveIntervals *LIS;
+  SmallPtrSet<const MachineInstr *, 32> Optional;
+  SmallPtrSet<const MachineInstr *, 32> WholeCopies;
+
+  bool isLegalType(int64_t Encoding) const {
+    if (Encoding < 0 || (Encoding & ~0xff) ||
+        RISCVVType::getVLMUL(Encoding) != RISCVVType::LMUL_1)
+      return false;
+    unsigned SEW = RISCVVType::getSEW(Encoding);
+    return SEW == 8 || SEW == 16 || SEW == 32 ||
+           (SEW == 64 && ST.hasVInstructionsI64());
+  }
+
+  // Require the ordinary independent overwrite shape, including exactly its
+  // two architectural state defs. x0,x0 is deliberately not an overwrite.
+  std::optional<unsigned> decodeConfig(const MachineInstr &MI) const {
+    unsigned Opcode = MI.getOpcode();
+    if (Opcode != RISCV::PseudoVSETIVLI && Opcode != RISCV::PseudoVSETVLI &&
+        Opcode != RISCV::PseudoVSETVLIX0)
+      return std::nullopt;
+    if (MI.getNumOperands() != 5 || MI.getNumExplicitOperands() != 3 ||
+        !MI.getOperand(0).isReg() || !MI.getOperand(0).isDef() ||
+        MI.getOperand(0).getSubReg() || !isGPR(MI.getOperand(0).getReg()) ||
+        !MI.getOperand(2).isImm() || !isLegalType(MI.getOperand(2).getImm()))
+      return std::nullopt;
+    const MachineOperand &AVL = MI.getOperand(1);
+    if (Opcode == RISCV::PseudoVSETIVLI) {
+      if (!AVL.isImm() || AVL.getImm() < 0 || AVL.getImm() > 31)
+        return std::nullopt;
+    } else if (!AVL.isReg() || !AVL.isUse() || AVL.getSubReg() ||
+               (Opcode == RISCV::PseudoVSETVLIX0
+                    ? AVL.getReg() != RISCV::X0
+                    : !isGPR(AVL.getReg()) || AVL.getReg() == RISCV::X0)) {
+      return std::nullopt;
+    }
+    bool VLDef = false, VTypeDef = false;
+    for (const MachineOperand &MO : MI.implicit_operands()) {
+      if (!MO.isReg() || !MO.isDef() || MO.getSubReg())
+        return std::nullopt;
+      if (MO.getReg() == RISCV::VL && !VLDef)
+        VLDef = true;
+      else if (MO.getReg() == RISCV::VTYPE && !VTypeDef)
+        VTypeDef = true;
+      else
+        return std::nullopt;
+    }
+    if (!VLDef || !VTypeDef)
+      return std::nullopt;
+    return MI.getOperand(2).getImm();
+  }
+
+  bool isGPR(Register Reg) const {
+    if (!Reg)
+      return false;
+    if (Reg.isPhysical())
+      return RISCV::GPRRegClass.contains(Reg);
+    return RISCV::GPRRegClass.hasSubClassEq(MRI.getRegClass(Reg));
+  }
+
+  bool hasWholeCopyShape(const MachineInstr &MI) const {
+    if (!RISCV::isVectorCopy(&TRI, MI) || MI.getNumExplicitOperands() != 2 ||
+        MI.getNumOperands() != 3)
+      return false;
+    for (unsigned I = 0; I != 2; ++I) {
+      const MachineOperand &MO = MI.getOperand(I);
+      if (!MO.isReg() || !MO.getReg().isPhysical() || MO.getSubReg() ||
+          MO.isDef() != (I == 0))
+        return false;
+    }
+    const MachineOperand &State = MI.getOperand(2);
+    if (!State.isReg() || !State.isImplicit() || !State.isUse() ||
+        State.getReg() != RISCV::VTYPE || State.getSubReg())
+      return false;
+    return true;
+  }
+
+  bool isWholeCopy(const MachineInstr &MI) const {
+    return WholeCopies.contains(&MI);
+  }
+
+  bool isExtract(const MachineInstr &MI) const {
+    if (MI.getOpcode() != RISCV::PseudoVMV_X_S ||
+        MI.getNumExplicitOperands() != 3 || MI.getNumOperands() != 4)
+      return false;
+    const MachineOperand &Use = MI.getOperand(3);
+    return Use.isReg() && Use.isImplicit() && Use.isUse() &&
+           Use.getReg() == RISCV::VTYPE && !Use.getSubReg();
+  }
+
+  // Requirements of every suffix path before a retained overwrite or return.
+  enum class Demand {
+    None,
+    LegalOnly,
+    Unsafe,
+    SEW8 = 8,
+    SEW16 = 16,
+    SEW32 = 32,
+    SEW64 = 64
+  };
+
+  static Demand mergeDemand(Demand A, Demand B) {
+    if (A == B || B == Demand::None)
+      return A;
+    if (A == Demand::None)
+      return B;
+    if (A == Demand::Unsafe || B == Demand::Unsafe)
+      return Demand::Unsafe;
+    if (A == Demand::LegalOnly)
+      return B;
+    if (B == Demand::LegalOnly)
+      return A;
+    return Demand::Unsafe; // Distinct exact SEW requirements cannot both hold.
+  }
+
+  static bool accepts(Demand Required, IndependentVTYPEFact Fact) {
+    if (Fact.K != IndependentVTYPEFact::Exact &&
+        Fact.K != IndependentVTYPEFact::Clear)
+      return false;
+    if (Required == Demand::None || Required == Demand::LegalOnly)
+      return true;
+    if (Required == Demand::Unsafe)
+      return false;
+    return Fact.K == IndependentVTYPEFact::Exact &&
+           RISCVVType::getSEW(Fact.Encoding) == static_cast<unsigned>(Required);
+  }
+
+  bool isNeutral(const MachineInstr &MI) const {
+    if (MI.isMetaInstruction())
+      return true;
+    if (MI.hasUnmodeledSideEffects() || MI.mayLoadOrStore())
+      return false;
+    switch (MI.getOpcode()) {
+    case TargetOpcode::COPY:
+    case RISCV::ADD:
+    case RISCV::ADDI:
+    case RISCV::ADDW:
+    case RISCV::ADDIW:
+    case RISCV::SUB:
+    case RISCV::SUBW:
+    case RISCV::AND:
+    case RISCV::ANDI:
+    case RISCV::OR:
+    case RISCV::ORI:
+    case RISCV::XOR:
+    case RISCV::XORI:
+    case RISCV::SLL:
+    case RISCV::SLLI:
+    case RISCV::SRL:
+    case RISCV::SRLI:
+    case RISCV::SRA:
+    case RISCV::SRAI:
+    case RISCV::SLT:
+    case RISCV::SLTI:
+    case RISCV::SLTU:
+    case RISCV::SLTIU:
+    case RISCV::LUI:
+    case RISCV::BEQ:
+    case RISCV::BNE:
+    case RISCV::BLT:
+    case RISCV::BGE:
+    case RISCV::BLTU:
+    case RISCV::BGEU:
+    case RISCV::PseudoBR:
+      break;
+    default:
+      return false;
+    }
+    for (const MachineOperand &MO : MI.operands())
+      if (MO.isRegMask() || (MO.isReg() && !isGPR(MO.getReg())))
+        return false;
+    return true;
+  }
+
+  Demand demandBefore(const MachineInstr &MI, Demand After) const {
+    if (Optional.contains(&MI))
+      return After; // Optional overwrites must never shield an observer.
+    if (decodeConfig(MI))
+      return Demand::None;
+    DemandedFields Used = getDemanded(MI, &ST);
+    if (Used.usedVL())
+      return Demand::Unsafe;
+    if (MI.getOpcode() == RISCV::PseudoRET) {
+      if (Used.usedVTYPE() || !MI.getParent()->succ_empty() ||
+          MI.getNumExplicitOperands())
+        return Demand::Unsafe;
+      for (const MachineOperand &MO : MI.operands()) {
+        if (!MO.isReg() || !MO.isImplicit() || !MO.isUse() ||
+            !MO.getReg().isPhysical() || MO.getSubReg())
+          return Demand::Unsafe;
+        Register Reg = MO.getReg();
+        if (!RISCV::GPRRegClass.contains(Reg) &&
+            !RISCV::FPR16RegClass.contains(Reg) &&
+            !RISCV::FPR32RegClass.contains(Reg) &&
+            !RISCV::FPR64RegClass.contains(Reg) &&
+            !RISCV::VRRegClass.contains(Reg) &&
+            !RISCV::VRM2RegClass.contains(Reg) &&
+            !RISCV::VRM4RegClass.contains(Reg) &&
+            !RISCV::VRM8RegClass.contains(Reg))
+          return Demand::Unsafe;
+      }
+      return Demand::None;
+    }
+    if (isWholeCopy(MI) && !Used.SEW && !Used.LMUL && !Used.SEWLMULRatio &&
+        !Used.TailPolicy && !Used.MaskPolicy && !Used.AltFmt && !Used.TWiden)
+      return mergeDemand(Demand::LegalOnly, After);
+    if (isExtract(MI)) {
+      // Keep the required-type support certificate and explicitly check the
+      // integer extraction contract before summarizing compatibility as SEW.
+      if (Used.SEW != DemandedFields::SEWEqual ||
+          Used.LMUL != DemandedFields::LMULNone || Used.SEWLMULRatio ||
+          Used.TailPolicy || Used.MaskPolicy || Used.AltFmt || Used.TWiden)
+        return Demand::Unsafe;
+      RISCVVSETVLIInfoAnalysis Requirements(&ST, nullptr);
+      unsigned Required = Requirements.computeInfoForInstr(MI).encodeVTYPE();
+      if (!isLegalType(Required))
+        return Demand::Unsafe;
+      return mergeDemand(static_cast<Demand>(RISCVVType::getSEW(Required)),
+                         After);
+    }
+    return !Used.usedVTYPE() && isNeutral(MI) ? After : Demand::Unsafe;
+  }
+
+  IndependentVTYPEFact transfer(const MachineInstr &MI,
+                                IndependentVTYPEFact Fact) const {
+    if (Fact.K == IndependentVTYPEFact::NotReached)
+      return Fact;
+    if (Optional.contains(&MI))
+      return {IndependentVTYPEFact::Unknown};
+    if (auto Encoding = decodeConfig(MI))
+      return {IndependentVTYPEFact::Exact, *Encoding};
+    if (RISCVInstrInfo::isVectorConfigInstr(MI) ||
+        MI.modifiesRegister(RISCV::VTYPE, &TRI))
+      return {IndependentVTYPEFact::Unknown};
+    return Fact;
+  }
+
+public:
+  IndependentVTYPECleanup(MachineFunction &MF, const RISCVSubtarget &ST,
+                          LiveIntervals *LIS)
+      : MF(MF), ST(ST), TRI(*ST.getRegisterInfo()), MRI(MF.getRegInfo()),
+        LIS(LIS) {}
+
+  void run(SlotIndexes *Indexes) {
+    // The downstream COPY converter searches for an explicit local producer.
+    // Track physical defs once per block; this check is bounded by the number
+    // of target registers, rather than rescanning a prefix for every COPY.
+    for (MachineBasicBlock &MBB : MF) {
+      SmallSet<Register, 32> Defined;
+      for (MachineInstr &MI : MBB) {
+        if (MI.isMetaInstruction())
+          continue;
+        if (hasWholeCopyShape(MI)) {
+          Register Source = MI.getOperand(1).getReg();
+          if (llvm::none_of(Defined, [&](Register Def) {
+                return TRI.regsOverlap(Def, Source);
+              }))
+            WholeCopies.insert(&MI);
+        }
+        for (const MachineOperand &MO : MI.explicit_operands())
+          if (MO.isReg() && MO.isDef() && MO.getReg().isPhysical())
+            Defined.insert(MO.getReg());
+      }
+    }
+    // Freeze this set before either analysis. Even a retained Optional kills
+    // forward facts and is transparent to backward safety.
+    for (MachineBasicBlock &MBB : MF)
+      for (MachineInstr &MI : MBB) {
+        if (MI.getOpcode() != RISCV::PseudoVSETIVLI || !decodeConfig(MI) ||
+            MI.getOperand(0).getReg() != RISCV::X0 ||
+            !MI.getOperand(0).isDead() || MI.getOperand(1).getImm() != 1)
+          continue;
+        auto Next = std::next(MI.getIterator());
+        while (Next != MBB.end() && Next->isMetaInstruction())
+          ++Next;
+        if (Next != MBB.end() && (isExtract(*Next) || isWholeCopy(*Next)))
+          Optional.insert(&MI);
+      }
+    if (Optional.empty())
+      return;
+    NumIndependentVTYPECandidates += Optional.size();
+    NumIndependentVTYPEBlocks += MF.size();
+
+    unsigned N = MF.getNumBlockIDs();
+    SmallVector<IndependentVTYPEFact> Entries(N), Exits(N);
+    SmallVector<MachineBasicBlock *> Queue;
+    BitVector Queued(N);
+    auto Enqueue = [&](MachineBasicBlock *MBB) {
+      if (!Queued.test(MBB->getNumber())) {
+        Queued.set(MBB->getNumber());
+        Queue.push_back(MBB);
+      }
+    };
+    Enqueue(&MF.front());
+    while (!Queue.empty()) {
+      MachineBasicBlock &MBB = *Queue.pop_back_val();
+      Queued.reset(MBB.getNumber());
+      ++NumIndependentVTYPEForwardVisits;
+      IndependentVTYPEFact Entry;
+      if (&MBB == &MF.front())
+        Entry.K = IndependentVTYPEFact::Unknown;
+      for (MachineBasicBlock *Pred : MBB.predecessors())
+        Entry = Entry.merge(Exits[Pred->getNumber()]);
+      Entries[MBB.getNumber()] = Entry;
+      IndependentVTYPEFact Exit = Entry;
+      for (const MachineInstr &MI : MBB) {
+        ++NumIndependentVTYPEInstructionScans;
+        Exit = transfer(MI, Exit);
+      }
+      if (Exit == Exits[MBB.getNumber()])
+        continue;
+      Exits[MBB.getNumber()] = Exit;
+      for (MachineBasicBlock *Succ : MBB.successors())
+        Enqueue(Succ);
+    }
+
+    // Least fixed point: closed neutral cycles require nothing; observers
+    // strengthen demands and a bad observer on any path propagates Unsafe.
+    SmallVector<Demand> DemandEntry(N, Demand::None),
+        DemandExit(N, Demand::None);
+    Queue.clear();
+    Queued.reset();
+    for (MachineBasicBlock &MBB : MF)
+      Enqueue(&MBB);
+    while (!Queue.empty()) {
+      MachineBasicBlock &MBB = *Queue.pop_back_val();
+      Queued.reset(MBB.getNumber());
+      ++NumIndependentVTYPEBackwardVisits;
+      Demand Required = MBB.succ_empty() ? Demand::Unsafe : Demand::None;
+      for (MachineBasicBlock *Succ : MBB.successors())
+        Required = mergeDemand(Required, DemandEntry[Succ->getNumber()]);
+      DemandExit[MBB.getNumber()] = Required;
+      for (const MachineInstr &MI : llvm::reverse(MBB)) {
+        ++NumIndependentVTYPEInstructionScans;
+        Required = demandBefore(MI, Required);
+      }
+      if (Required == DemandEntry[MBB.getNumber()])
+        continue;
+      DemandEntry[MBB.getNumber()] = Required;
+      for (MachineBasicBlock *Pred : MBB.predecessors())
+        Enqueue(Pred);
+    }
+
+    // Pair each candidate's suffix demand AFTER the Optional with the forward
+    // fact BEFORE it. Both analyses use the immutable original instruction set.
+    DenseMap<const MachineInstr *, Demand> SuffixDemand;
+    for (MachineBasicBlock &MBB : MF) {
+      Demand Required = DemandExit[MBB.getNumber()];
+      for (const MachineInstr &MI : llvm::reverse(MBB)) {
+        if (Optional.contains(&MI))
+          SuffixDemand[&MI] = Required;
+        Required = demandBefore(MI, Required);
+      }
+    }
+    SmallVector<MachineInstr *> Remove;
+    for (MachineBasicBlock &MBB : MF) {
+      IndependentVTYPEFact Fact = Entries[MBB.getNumber()];
+      for (MachineInstr &MI : MBB) {
+        auto It = SuffixDemand.find(&MI);
+        if (It != SuffixDemand.end() && accepts(It->second, Fact))
+          Remove.push_back(&MI);
+        Fact = transfer(MI, Fact);
+      }
+    }
+
+    // No mutations until every proof has been selected. A deletion never
+    // creates facts for another deletion in this invocation.
+    if (Remove.empty())
+      return;
+    for (MachineInstr *MI : Remove) {
+      if (LIS)
+        LIS->RemoveMachineInstrFromMaps(*MI);
+      else if (Indexes)
+        Indexes->removeMachineInstrFromMaps(*MI);
+      MI->eraseFromParent();
+      ++NumIndependentVTYPEDeleted;
+    }
+    // Recompute just the two affected physical live-in sets. Deleted defs can
+    // expose uses across joins and through otherwise transparent blocks.
+    SmallVector<unsigned> LiveIn(N, 0);
+    Queue.clear();
+    Queued.reset();
+    for (MachineBasicBlock &MBB : MF)
+      Enqueue(&MBB);
+    while (!Queue.empty()) {
+      MachineBasicBlock &MBB = *Queue.pop_back_val();
+      Queued.reset(MBB.getNumber());
+      unsigned Live = 0;
+      for (MachineBasicBlock *Succ : MBB.successors())
+        Live |= LiveIn[Succ->getNumber()];
+      for (const MachineInstr &MI : llvm::reverse(MBB)) {
+        for (const MachineOperand &MO : MI.operands()) {
+          if (!MO.isReg() || !MO.isDef())
+            continue;
+          if (MO.getReg() == RISCV::VL)
+            Live &= ~1U;
+          if (MO.getReg() == RISCV::VTYPE)
+            Live &= ~2U;
+        }
+        for (const MachineOperand &MO : MI.operands()) {
+          if (!MO.isReg() || !MO.isUse() || MO.isUndef())
+            continue;
+          if (MO.getReg() == RISCV::VL)
+            Live |= 1;
+   ...
[truncated]

``````````

</details>


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


More information about the llvm-commits mailing list