[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