[llvm-branch-commits] [MISched] Add loop-carried WAR renaming for aggressive breaking (PR #231791)

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Wed Oct 14 00:55:46 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

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

Author: Pengcheng Wang (wangpc-pp)

<details>
<summary>Changes</summary>

Teach AggressiveAntiDepBreaker to break single-block loop-carried
write-after-read hazards. It finds a physical register whose live range
crosses the loop backedge and rewrites it to an otherwise unused
register, then runs the renaming from ScheduleDAGMI::finishBlock when
the aggressive breaker is selected.

Cover the single-block GPR, FPR, and vector cases plus the conservative
bailouts (single def, live-in use, non-renamable operands, multi-block
loops, missing uses, tied uses, no free register, and bundles) with a
RISC-V test. The bailout cases share one CHECK prefix because the
ANTIDEP and NO-ANTIDEP runs match; only the renamed cases differ.

Assisted-by: TRAE CLI (GPT-5.6)


---

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


4 Files Affected:

- (modified) llvm/lib/CodeGen/AggressiveAntiDepBreaker.cpp (+210) 
- (modified) llvm/lib/CodeGen/AggressiveAntiDepBreaker.h (+4) 
- (modified) llvm/lib/CodeGen/MachineScheduler.cpp (+6-1) 
- (added) llvm/test/CodeGen/RISCV/postmisched-antidep-loop.mir (+573) 


``````````diff
diff --git a/llvm/lib/CodeGen/AggressiveAntiDepBreaker.cpp b/llvm/lib/CodeGen/AggressiveAntiDepBreaker.cpp
index a425864921416..3ab29cd90588a 100644
--- a/llvm/lib/CodeGen/AggressiveAntiDepBreaker.cpp
+++ b/llvm/lib/CodeGen/AggressiveAntiDepBreaker.cpp
@@ -21,6 +21,7 @@
 #include "llvm/CodeGen/MachineFrameInfo.h"
 #include "llvm/CodeGen/MachineFunction.h"
 #include "llvm/CodeGen/MachineInstr.h"
+#include "llvm/CodeGen/MachineLoopInfo.h"
 #include "llvm/CodeGen/MachineOperand.h"
 #include "llvm/CodeGen/MachineRegisterInfo.h"
 #include "llvm/CodeGen/RegisterClassInfo.h"
@@ -34,6 +35,7 @@
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/raw_ostream.h"
 #include <cassert>
+#include <optional>
 
 using namespace llvm;
 
@@ -184,6 +186,214 @@ void AggressiveAntiDepBreaker::FinishBlock() {
   State = nullptr;
 }
 
+namespace {
+
+struct LoopCarriedRename {
+  SmallVector<MachineOperand *, 8> Refs;
+  BitVector Candidates;
+};
+
+static bool overlapsReg(const MachineOperand &MO, MCRegister Reg,
+                        const TargetRegisterInfo &TRI) {
+  return MO.isReg() && MO.getReg().isPhysical() &&
+         TRI.regsOverlap(MO.getReg(), Reg);
+}
+
+static std::optional<LoopCarriedRename>
+findLoopCarriedRename(MachineBasicBlock &MBB, MCRegister Reg,
+                      const TargetInstrInfo &TII,
+                      const TargetRegisterInfo &TRI) {
+  LoopCarriedRename Rename{{}, BitVector(TRI.getNumRegs(), true)};
+  enum class ScanPhase { BeforeFirstDef, RenameRange, AfterSecondDef };
+  ScanPhase Phase = ScanPhase::BeforeFirstDef;
+  bool FoundUseInRenameRange = false;
+  bool FoundUseAfterSecondDef = false;
+
+  auto AddRenameRef = [&](MachineOperand &MO) {
+    if (!MO.isDebug()) {
+      const TargetRegisterClass *RC =
+          MO.getParent()->getRegClassConstraint(MO.getOperandNo(), &TII, &TRI);
+      if (!RC)
+        return false;
+      Rename.Candidates &= TRI.getAllocatableSet(*MBB.getParent(), RC);
+    }
+    Rename.Refs.push_back(&MO);
+    return true;
+  };
+
+  for (MachineInstr &MI : MBB) {
+    if (MI.isBundle())
+      return std::nullopt;
+    if (MI.isDebugInstr()) {
+      if (Phase == ScanPhase::RenameRange) {
+        for (MachineOperand &MO : MI.operands()) {
+          if (!overlapsReg(MO, Reg, TRI))
+            continue;
+          if (MI.isDebugPHI())
+            continue;
+          if (MO.getReg() != Reg)
+            return std::nullopt;
+          if (!AddRenameRef(MO))
+            return std::nullopt;
+        }
+      }
+      continue;
+    }
+    if (MI.isCall() || MI.isInlineAsm() || TII.isPredicated(MI))
+      return std::nullopt;
+    for (const MachineOperand &MO : MI.operands())
+      if (MO.isRegMask())
+        return std::nullopt;
+
+    bool HasFullDef = false;
+    for (MachineOperand &MO : MI.operands()) {
+      if (!overlapsReg(MO, Reg, TRI))
+        continue;
+      if (MO.getReg() != Reg || MO.getSubReg())
+        return std::nullopt;
+      if (MO.isDef() && !MO.isImplicit())
+        HasFullDef = true;
+    }
+
+    if (Phase == ScanPhase::BeforeFirstDef) {
+      for (MachineOperand &MO : MI.operands())
+        if (overlapsReg(MO, Reg, TRI) && MO.readsReg())
+          return std::nullopt;
+      if (!HasFullDef)
+        continue;
+
+      Phase = ScanPhase::RenameRange;
+      for (MachineOperand &MO : MI.operands()) {
+        if (!overlapsReg(MO, Reg, TRI))
+          continue;
+        if (MO.readsReg() || MO.isImplicit() || !MO.isRenamable())
+          return std::nullopt;
+        if (!AddRenameRef(MO))
+          return std::nullopt;
+      }
+      continue;
+    }
+
+    if (Phase == ScanPhase::RenameRange) {
+      if (HasFullDef) {
+        Phase = ScanPhase::AfterSecondDef;
+        for (MachineOperand &MO : MI.operands()) {
+          if (!overlapsReg(MO, Reg, TRI))
+            continue;
+          if (MO.getReg() != Reg || MO.getSubReg() || MO.isImplicit())
+            return std::nullopt;
+          if (MO.isDef()) {
+            if (MO.isEarlyClobber())
+              return std::nullopt;
+            continue;
+          }
+          if (MO.readsReg()) {
+            if (MO.isTied() || !MO.isRenamable())
+              return std::nullopt;
+            if (!AddRenameRef(MO))
+              return std::nullopt;
+            FoundUseInRenameRange = true;
+          }
+        }
+        continue;
+      }
+
+      for (MachineOperand &MO : MI.operands()) {
+        if (!overlapsReg(MO, Reg, TRI))
+          continue;
+        if (MO.getReg() != Reg || MO.getSubReg() || MO.isDef() ||
+            MO.isImplicit() || !MO.readsReg() || !MO.isRenamable())
+          return std::nullopt;
+        if (!AddRenameRef(MO))
+          return std::nullopt;
+        FoundUseInRenameRange = true;
+      }
+      continue;
+    }
+
+    for (MachineOperand &MO : MI.operands())
+      if (overlapsReg(MO, Reg, TRI) && MO.readsReg())
+        FoundUseAfterSecondDef = true;
+  }
+
+  if (Phase != ScanPhase::AfterSecondDef || !FoundUseInRenameRange ||
+      !FoundUseAfterSecondDef)
+    return std::nullopt;
+
+  return Rename;
+}
+
+} // namespace
+
+void AggressiveAntiDepBreaker::BreakLoopCarriedAntiDependencies(
+    MachineBasicBlock &MBB, const MachineLoopInfo &MLI) {
+  const MachineLoop *Loop = MLI.getLoopFor(&MBB);
+  if (!Loop || Loop->getHeader() != &MBB || Loop->getNumBlocks() != 1 ||
+      !MBB.isSuccessor(&MBB))
+    return;
+
+  // Track every register unit referenced or clobbered anywhere in the block.
+  LiveRegUnits UnavailableUnits(*TRI);
+  // Preserve the conservative whole-register treatment of boundary liveness.
+  for (const auto &LI : MBB.liveins())
+    UnavailableUnits.addReg(LI.PhysReg);
+  for (const MachineBasicBlock *Succ : MBB.successors())
+    for (const auto &LI : Succ->liveins())
+      UnavailableUnits.addReg(LI.PhysReg);
+  const BitVector Pristine =
+      MBB.getParent()->getFrameInfo().getPristineRegs(*MBB.getParent());
+  for (unsigned Reg : Pristine.set_bits())
+    UnavailableUnits.addReg(MCRegister(Reg));
+
+  SmallVector<MCRegister, 8> DefRegs;
+  BitVector Seen(TRI->getNumRegs());
+  for (MachineInstr &MI : MBB) {
+    if (MI.isBundle())
+      return;
+    UnavailableUnits.accumulate(MI);
+    // Keep the whole-block-unused policy for physical register operands that
+    // accumulate() ignores, such as undef uses.
+    for (const MachineOperand &MO : MI.operands())
+      if (MO.isReg() && MO.getReg() && MO.getReg().isPhysical() &&
+          !MO.isDef() && !MO.readsReg())
+        UnavailableUnits.addReg(MO.getReg().asMCReg());
+    if (MI.isDebugOrPseudoInstr())
+      continue;
+    for (MachineOperand &MO : MI.operands()) {
+      if (!MO.isReg() || !MO.isDef() || MO.isImplicit() ||
+          !MO.getReg().isPhysical() || !MO.getReg() || MO.getSubReg())
+        continue;
+      MCRegister Reg = MO.getReg().asMCReg();
+      if (!Seen.test(Reg.id())) {
+        Seen.set(Reg.id());
+        DefRegs.push_back(Reg);
+      }
+    }
+  }
+
+  for (MCRegister Reg : DefRegs) {
+    std::optional<LoopCarriedRename> Rename =
+        findLoopCarriedRename(MBB, Reg, *TII, *TRI);
+    if (!Rename)
+      continue;
+
+    const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg);
+    for (MCRegister NewReg : RegClassInfo.getOrder(RC)) {
+      if (NewReg == Reg || !Rename->Candidates.test(NewReg.id()) ||
+          !MRI.isAllocatable(NewReg) || !UnavailableUnits.available(NewReg))
+        continue;
+
+      LLVM_DEBUG(dbgs() << "Breaking loop-carried anti-dependence on "
+                        << printReg(Reg, TRI) << " using "
+                        << printReg(NewReg, TRI) << '\n');
+      for (MachineOperand *MO : Rename->Refs)
+        MO->setReg(NewReg);
+      UnavailableUnits.addReg(NewReg);
+      break;
+    }
+  }
+}
+
 void AggressiveAntiDepBreaker::Observe(MachineInstr &MI, unsigned Count,
                                        unsigned InsertPosIndex) {
   assert(Count < InsertPosIndex && "Instruction index out of expected range!");
diff --git a/llvm/lib/CodeGen/AggressiveAntiDepBreaker.h b/llvm/lib/CodeGen/AggressiveAntiDepBreaker.h
index 4f474ebb6b89e..687a3fe999183 100644
--- a/llvm/lib/CodeGen/AggressiveAntiDepBreaker.h
+++ b/llvm/lib/CodeGen/AggressiveAntiDepBreaker.h
@@ -29,6 +29,7 @@ namespace llvm {
 class MachineBasicBlock;
 class MachineFunction;
 class MachineInstr;
+class MachineLoopInfo;
 class MachineOperand;
 class MachineRegisterInfo;
 class RegisterClassInfo;
@@ -150,6 +151,9 @@ class LLVM_LIBRARY_VISIBILITY AggressiveAntiDepState {
                                    unsigned InsertPosIndex,
                                    DbgValueVector &DbgValues) override;
 
+    void BreakLoopCarriedAntiDependencies(MachineBasicBlock &MBB,
+                                          const MachineLoopInfo &MLI);
+
     /// Update liveness information to account for the current
     /// instruction, which will not be scheduled.
     void Observe(MachineInstr &MI, unsigned Count,
diff --git a/llvm/lib/CodeGen/MachineScheduler.cpp b/llvm/lib/CodeGen/MachineScheduler.cpp
index 34770352a3fc3..e195f2df00915 100644
--- a/llvm/lib/CodeGen/MachineScheduler.cpp
+++ b/llvm/lib/CodeGen/MachineScheduler.cpp
@@ -1123,6 +1123,7 @@ LLVM_DUMP_METHOD void ReadyQueue::dump() const {
 // Provide a vtable anchor.
 struct ScheduleDAGMI::AntiDepState {
   std::unique_ptr<AntiDepBreaker> Breaker;
+  AggressiveAntiDepBreaker *Aggressive = nullptr;
   unsigned EndIndex = 0;
   MachineBasicBlock::iterator ScanPos;
   bool RegionProcessed = false;
@@ -1146,8 +1147,10 @@ ScheduleDAGMI::ScheduleDAGMI(MachineSchedContext *C,
     SmallVector<const TargetRegisterClass *, 4> CriticalPathRCs;
     C->MF->getSubtarget().getCriticalPathRCs(CriticalPathRCs);
     AntiDep = std::make_unique<AntiDepState>();
-    AntiDep->Breaker = std::make_unique<AggressiveAntiDepBreaker>(
+    auto Breaker = std::make_unique<AggressiveAntiDepBreaker>(
         *C->MF, *C->RegClassInfo, CriticalPathRCs);
+    AntiDep->Aggressive = Breaker.get();
+    AntiDep->Breaker = std::move(Breaker);
   } else if (AntiDepMode == TargetSubtargetInfo::ANTIDEP_CRITICAL) {
     AntiDep = std::make_unique<AntiDepState>();
     AntiDep->Breaker.reset(
@@ -1239,6 +1242,8 @@ void ScheduleDAGMI::startBlock(MachineBasicBlock *bb) {
 
 void ScheduleDAGMI::finishBlock() {
   SchedImpl->leaveMBB();
+  if (AntiDep && AntiDep->Aggressive)
+    AntiDep->Aggressive->BreakLoopCarriedAntiDependencies(*BB, *MLI);
   if (AntiDep)
     AntiDep->Breaker->FinishBlock();
   ScheduleDAGInstrs::finishBlock();
diff --git a/llvm/test/CodeGen/RISCV/postmisched-antidep-loop.mir b/llvm/test/CodeGen/RISCV/postmisched-antidep-loop.mir
new file mode 100644
index 0000000000000..da8ab60a33a8b
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/postmisched-antidep-loop.mir
@@ -0,0 +1,573 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+# RUN: llc -mtriple=riscv64 -mcpu=sifive-x280 -run-pass=postmisched \
+# RUN:   -enable-post-misched -misched-postra-antidep=all \
+# RUN:   -verify-machineinstrs -o - %s | FileCheck %s --check-prefixes=CHECK,ANTIDEP
+# RUN: llc -mtriple=riscv64 -mcpu=sifive-x280 -run-pass=postmisched \
+# RUN:   -enable-post-misched -misched-postra-antidep=none \
+# RUN:   -verify-machineinstrs -o - %s | FileCheck %s --check-prefixes=CHECK,NO-ANTIDEP
+
+---
+name:            gpr_loop_carried_war
+tracksRegLiveness: true
+body:             |
+  ; ANTIDEP-LABEL: name: gpr_loop_carried_war
+  ; ANTIDEP: bb.0:
+  ; ANTIDEP-NEXT:   successors: %bb.1(0x80000000)
+  ; ANTIDEP-NEXT: {{  $}}
+  ; ANTIDEP-NEXT:   PseudoBR %bb.1
+  ; ANTIDEP-NEXT: {{  $}}
+  ; ANTIDEP-NEXT: bb.1:
+  ; ANTIDEP-NEXT:   successors: %bb.1(0x7c000000), %bb.2(0x04000000)
+  ; ANTIDEP-NEXT:   liveins: $x10, $x11, $x12, $x13
+  ; ANTIDEP-NEXT: {{  $}}
+  ; ANTIDEP-NEXT:   $x14 = LD renamable $x10, 0 :: (load (s64))
+  ; ANTIDEP-NEXT:   renamable $x15 = ADD killed $x14, renamable $x11
+  ; ANTIDEP-NEXT:   SD killed renamable $x15, renamable $x12, 0 :: (store (s64))
+  ; ANTIDEP-NEXT:   BNE renamable $x13, $x0, %bb.1
+  ; ANTIDEP-NEXT: {{  $}}
+  ; ANTIDEP-NEXT: bb.2:
+  ; ANTIDEP-NEXT:   PseudoRET
+  ;
+  ; NO-ANTIDEP-LABEL: name: gpr_loop_carried_war
+  ; NO-ANTIDEP: bb.0:
+  ; NO-ANTIDEP-NEXT:   successors: %bb.1(0x80000000)
+  ; NO-ANTIDEP-NEXT: {{  $}}
+  ; NO-ANTIDEP-NEXT:   PseudoBR %bb.1
+  ; NO-ANTIDEP-NEXT: {{  $}}
+  ; NO-ANTIDEP-NEXT: bb.1:
+  ; NO-ANTIDEP-NEXT:   successors: %bb.1(0x7c000000), %bb.2(0x04000000)
+  ; NO-ANTIDEP-NEXT:   liveins: $x10, $x11, $x12, $x13
+  ; NO-ANTIDEP-NEXT: {{  $}}
+  ; NO-ANTIDEP-NEXT:   renamable $x15 = LD renamable $x10, 0 :: (load (s64))
+  ; NO-ANTIDEP-NEXT:   renamable $x15 = ADD killed renamable $x15, renamable $x11
+  ; NO-ANTIDEP-NEXT:   SD killed renamable $x15, renamable $x12, 0 :: (store (s64))
+  ; NO-ANTIDEP-NEXT:   BNE renamable $x13, $x0, %bb.1
+  ; NO-ANTIDEP-NEXT: {{  $}}
+  ; NO-ANTIDEP-NEXT: bb.2:
+  ; NO-ANTIDEP-NEXT:   PseudoRET
+  bb.0:
+    successors: %bb.1(0x80000000)
+
+    PseudoBR %bb.1
+
+  bb.1:
+    successors: %bb.1(0x7c000000), %bb.2(0x04000000)
+    liveins: $x10, $x11, $x12, $x13
+
+    renamable $x15 = LD renamable $x10, 0 :: (load (s64))
+    renamable $x15 = ADD killed renamable $x15, renamable $x11
+    SD renamable $x15, renamable $x12, 0 :: (store (s64))
+    BNE renamable $x13, $x0, %bb.1
+
+  bb.2:
+    PseudoRET
+...
+
+---
+name:            fpr_loop_carried_war
+tracksRegLiveness: true
+body:             |
+  ; ANTIDEP-LABEL: name: fpr_loop_carried_war
+  ; ANTIDEP: bb.0:
+  ; ANTIDEP-NEXT:   successors: %bb.1(0x80000000)
+  ; ANTIDEP-NEXT: {{  $}}
+  ; ANTIDEP-NEXT:   PseudoBR %bb.1
+  ; ANTIDEP-NEXT: {{  $}}
+  ; ANTIDEP-NEXT: bb.1:
+  ; ANTIDEP-NEXT:   successors: %bb.1(0x7c000000), %bb.2(0x04000000)
+  ; ANTIDEP-NEXT:   liveins: $x10, $x11, $x12, $f11_d
+  ; ANTIDEP-NEXT: {{  $}}
+  ; ANTIDEP-NEXT:   $f15_d = FLD renamable $x10, 0 :: (load (s64))
+  ; ANTIDEP-NEXT:   renamable $f10_d = nofpexcept FADD_D killed $f15_d, renamable $f11_d, 7, implicit $frm
+  ; ANTIDEP-NEXT:   FSD killed renamable $f10_d, renamable $x11, 0 :: (store (s64))
+  ; ANTIDEP-NEXT:   BNE renamable $x12, $x0, %bb.1
+  ; ANTIDEP-NEXT: {{  $}}
+  ; ANTIDEP-NEXT: bb.2:
+  ; ANTIDEP-NEXT:   PseudoRET
+  ;
+  ; NO-ANTIDEP-LABEL: name: fpr_loop_carried_war
+  ; NO-ANTIDEP: bb.0:
+  ; NO-ANTIDEP-NEXT:   successors: %bb.1(0x80000000)
+  ; NO-ANTIDEP-NEXT: {{  $}}
+  ; NO-ANTIDEP-NEXT:   PseudoBR %bb.1
+  ; NO-ANTIDEP-NEXT: {{  $}}
+  ; NO-ANTIDEP-NEXT: bb.1:
+  ; NO-ANTIDEP-NEXT:   successors: %bb.1(0x7c000000), %bb.2(0x04000000)
+  ; NO-ANTIDEP-NEXT:   liveins: $x10, $x11, $x12, $f11_d
+  ; NO-ANTIDEP-NEXT: {{  $}}
+  ; NO-ANTIDEP-NEXT:   renamable $f10_d = FLD renamable $x10, 0 :: (load (s64))
+  ; NO-ANTIDEP-NEXT:   renamable $f10_d = nofpexcept FADD_D killed renamable $f10_d, renamable $f11_d, 7, implicit $frm
+  ; NO-ANTIDEP-NEXT:   FSD killed renamable $f10_d, renamable $x11, 0 :: (store (s64))
+  ; NO-ANTIDEP-NEXT:   BNE renamable $x12, $x0, %bb.1
+  ; NO-ANTIDEP-NEXT: {{  $}}
+  ; NO-ANTIDEP-NEXT: bb.2:
+  ; NO-ANTIDEP-NEXT:   PseudoRET
+  bb.0:
+    successors: %bb.1(0x80000000)
+
+    PseudoBR %bb.1
+
+  bb.1:
+    successors: %bb.1(0x7c000000), %bb.2(0x04000000)
+    liveins: $x10, $x11, $x12, $f11_d
+
+    renamable $f10_d = FLD renamable $x10, 0 :: (load (s64))
+    renamable $f10_d = nofpexcept FADD_D killed renamable $f10_d, renamable $f11_d, 7, implicit $frm
+    FSD renamable $f10_d, renamable $x11, 0 :: (store (s64))
+    BNE renamable $x12, $x0, %bb.1
+
+  bb.2:
+    PseudoRET
+...
+
+---
+name:            rvv_loop_carried_war
+tracksRegLiveness: true
+body:             |
+  ; ANTIDEP-LABEL: name: rvv_loop_carried_war
+  ; ANTIDEP: bb.0:
+  ; ANTIDEP-NEXT:   successors: %bb.1(0x80000000)
+  ; ANTIDEP-NEXT: {{  $}}
+  ; ANTIDEP-NEXT:   PseudoBR %bb.1
+  ; ANTIDEP-NEXT: {{  $}}
+  ; ANTIDEP-NEXT: bb.1:
+  ; ANTIDEP-NEXT:   successors: %bb.1(0x7c000000), %bb.2(0x04000000)
+  ; ANTIDEP-NEXT:   liveins: $x10, $x11, $x12, $v16m8
+  ; ANTIDEP-NEXT: {{  $}}
+  ; ANTIDEP-NEXT:   dead $x0 = PseudoVSETIVLI 0, 211 /* e32, m8, ta, ma */, implicit-def $vl, implicit-def $vtype
+  ; ANTIDEP-NEXT:   $v24m8 = PseudoVLE32_V_M8 undef $v24m8, renamable $x10, $noreg /* vl */, 5 /* e32 */, 2 /* tu, ma */, implicit $vl, implicit $vtype :: (load unknown-size, align 4)
+  ; ANTIDEP-NEXT:   renamable $v8m8 = nofpexcept PseudoVFADD_VV_M8_E32 undef renamable $v8m8, killed $v24m8, renamable $v16m8, 7 /* frm=dyn */, $noreg /* vl */, 5 /* e32 */, 0 /* tu, mu */, implicit $frm, implicit $vl, implicit $vtype
+  ; ANTIDEP-NEXT:   PseudoVSE32_V_M8 killed renamable $v8m8, renamable $x11, $noreg /* vl */, 5 /* e32 */, implicit $vl, implicit $vtype :: (store unknown-size, align 4)
+  ; ANTIDEP-NEXT:   BNE renamable $x12, $x0, %bb.1
+  ; ANTIDEP-NEXT: {{  $}}
+  ; ANTIDEP-NEXT: bb.2:
+  ; ANTIDEP-NEXT:   PseudoRET
+  ;
+  ; NO-ANTIDEP-LABEL: name: rvv_loop_carried_war
+  ; NO-ANTIDEP: bb.0:
+  ; NO-ANTIDEP-NEXT:   successors: %bb.1(0x80000000)
+  ; NO-ANTIDEP-NEXT: {{  $}}
+  ; NO-ANTIDEP-NEXT:   PseudoBR %bb.1
+  ; NO-ANTIDEP-NEXT: {{  $}}
+  ; NO-ANTIDEP-NEXT: bb.1:
+  ; NO-ANTIDEP-NEXT:   successors: %bb.1(0x7c000000), %bb.2(0x04000000)
+  ; NO-ANTIDEP-NEXT:   liveins: $x10, $x11, $x12, $v16m8
+  ; NO-ANTIDEP-NEXT: {{  $}}
+  ; NO-ANTIDEP-NEXT:   dead $x0 = PseudoVSETIVLI 0, 211 /* e32, m8, ta, ma */, implicit-def $vl, implicit-def $vtype
+  ; NO-ANTIDEP-NEXT:   renamable $v8m8 = PseudoVLE32_V_M8 undef renamable $v8m8, renamable $x10, $noreg /* vl */, 5 /* e32 */, 2 /* tu, ma */, implicit $vl, implicit $vtype :: (load unknown-size, align 4)
+  ; NO-ANTIDEP-NEXT:   renamable $v8m8 = nofpexcept PseudoVFADD_VV_M8_E32 undef renamable $v8m8, killed renamable $v8m8, renamable $v16m8, 7 /* frm=dyn */, $noreg /* vl */, 5 /* e32 */, 0 /* tu, mu */, implicit $frm, implicit $vl, implicit $vtype
+  ; NO-ANTIDEP-NEXT:   PseudoVSE32_V_M8 killed renamable $v8m8, renamable $x11, $noreg /* vl */, 5 /* e32 */, implicit $vl, implicit $vtype :: (store unknown-size, align 4)
+  ; NO-ANTIDEP-NEXT:   BNE renamable $x12, $x0, %bb.1
+  ; NO-ANTIDEP-NEXT: {{  $}}
+  ; NO-ANTIDEP-NEXT: bb.2:
+  ; NO-ANTIDEP-NEXT:   PseudoRET
+  bb.0:
+    successors: %bb.1(0x80000000)
+
+    PseudoBR %bb.1
+
+  bb.1:
+    successors: %bb.1(0x7c000000), %bb.2(0x04000000)
+    liveins: $x10, $x11, $x12, $v16m8
+
+    dead $x0 = PseudoVSETIVLI 0, 211 /* e32, m8, ta, ma */, implicit-def $vl, implicit-def $vtype
+    renamable $v8m8 = PseudoVLE32_V_M8 undef renamable $v8m8, renamable $x10, $noreg /* vl */, 5 /* e32 */, 2 /* tu, ma */, implicit $vl, implicit $vtype :: (load unknown-size, align 4)
+    renamable $v8m8 = nofpexcept PseudoVFADD_VV_M8_E32 undef renamable $v8m8, killed renamable $v8m8, renamable $v16m8, 7 /* frm=dyn */, $noreg /* vl */, 5 /* e32 */, 0 /* tu, mu */, implicit $frm, implicit $vl, implicit $vtype
+    PseudoVSE32_V_M8 killed renamable $v8m8, renamable $x11, $noreg /* vl */, 5 /* e32 */, implicit $vl, implicit $vtype :: (store unknown-size, align 4)
+    BNE renamable $x12, $x0, %bb.1
+
+  bb.2:
+    PseudoRET
+...
+
+# Negative tests
+
+# Renaming a loop with only one definition would only move the same backedge
+# WAR to another register, so a second complete definition is required.
+---
+name:            single_def_loop_carried_war
+tracksRegLiveness: true
+body:             |
+  ; CHECK-LABEL: name: single_def_loop_carried_war
+  ; CHECK: bb.0:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   PseudoBR %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1:
+  ; CHECK-NEXT:   successors: %bb.1(0x7c000000), %bb.2(0x04000000)
+  ; CHECK-NEXT:   liveins: $x10, $x11, $x12
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   renamable $x15 = LD renamable $x10, 0 :: (load (s64))
+  ; CHECK-NEXT:   SD killed renamable $x15, renamable $x11, 0 :: (store (s64))
+  ; CHECK-NEXT:   BNE renamable $x12, $x0, %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2:
+  ; CHECK-NEXT:   PseudoRET
+  bb.0:
+    successors: %bb.1(0x80000000)
+
+    PseudoBR %bb.1
+
+  bb.1:
+    successors: %bb.1(0x7c000000), %bb.2(0x04000000)
+    liveins: $x10, $x11, $x12
+
+    renamable $x15 = LD renamable $x10, 0 :: (load (s64))
+    SD renamable $x15, renamable $x11, 0 :: (store (s64))
+    BNE renamable $x12, $x0, %bb.1
+
+  bb.2:
+    PseudoRET
+...
+
+# A use before the first definition means ...
[truncated]

``````````

</details>


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


More information about the llvm-branch-commits mailing list