Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

[MachinePipeliner] Extract some process into a separate function #137662

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 14, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 59 additions & 66 deletions 125 llvm/lib/CodeGen/MachinePipeliner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -884,6 +884,63 @@ bool SUnitWithMemInfo::getUnderlyingObjects() {
return true;
}

/// Returns true if there is a loop-carried order dependency from \p Src to \p
/// Dst.
static bool hasLoopCarriedMemDep(const SUnitWithMemInfo &Src,
const SUnitWithMemInfo &Dst,
BatchAAResults &BAA,
const TargetInstrInfo *TII,
const TargetRegisterInfo *TRI) {
if (Src.isTriviallyDisjoint(Dst))
return false;
if (isSuccOrder(Src.SU, Dst.SU))
return false;

MachineInstr &SrcMI = *Src.SU->getInstr();
MachineInstr &DstMI = *Dst.SU->getInstr();
// First, perform the cheaper check that compares the base register.
// If they are the same and the load offset is less than the store
// offset, then mark the dependence as loop carried potentially.
const MachineOperand *BaseOp1, *BaseOp2;
int64_t Offset1, Offset2;
bool Offset1IsScalable, Offset2IsScalable;
if (TII->getMemOperandWithOffset(SrcMI, BaseOp1, Offset1, Offset1IsScalable,
TRI) &&
TII->getMemOperandWithOffset(DstMI, BaseOp2, Offset2, Offset2IsScalable,
TRI)) {
if (BaseOp1->isIdenticalTo(*BaseOp2) &&
Offset1IsScalable == Offset2IsScalable && (int)Offset1 < (int)Offset2) {
assert(TII->areMemAccessesTriviallyDisjoint(SrcMI, DstMI) &&
"What happened to the chain edge?");
return true;
}
}

// Second, the more expensive check that uses alias analysis on the
// base registers. If they alias, and the load offset is less than
// the store offset, the mark the dependence as loop carried.
if (Src.isUnknown() || Dst.isUnknown())
return true;
if (Src.MemOpValue == Dst.MemOpValue && Src.MemOpOffset <= Dst.MemOpOffset)
return true;

if (BAA.isNoAlias(
MemoryLocation::getBeforeOrAfter(Src.MemOpValue, Src.AATags),
MemoryLocation::getBeforeOrAfter(Dst.MemOpValue, Dst.AATags)))
return false;

// AliasAnalysis sometimes gives up on following the underlying
// object. In such a case, separate checks for underlying objects may
// prove that there are no aliases between two accesses.
for (const Value *SrcObj : Src.UnderlyingObjs)
for (const Value *DstObj : Dst.UnderlyingObjs)
if (!BAA.isNoAlias(MemoryLocation::getBeforeOrAfter(SrcObj, Src.AATags),
MemoryLocation::getBeforeOrAfter(DstObj, Dst.AATags)))
return true;

return false;
}

/// Add a chain edge between a load and store if the store can be an
/// alias of the load on a subsequent iteration, i.e., a loop carried
/// dependence. This code is very similar to the code in ScheduleDAGInstrs
Expand All @@ -898,76 +955,12 @@ void SwingSchedulerDAG::addLoopCarriedDependences() {
PendingLoads.emplace_back(&SU);
} else if (MI.mayStore()) {
SUnitWithMemInfo Store(&SU);
for (const SUnitWithMemInfo &Load : PendingLoads) {
if (Load.isTriviallyDisjoint(Store))
continue;
if (isSuccOrder(Load.SU, Store.SU))
continue;
MachineInstr &LdMI = *Load.SU->getInstr();
// First, perform the cheaper check that compares the base register.
// If they are the same and the load offset is less than the store
// offset, then mark the dependence as loop carried potentially.
const MachineOperand *BaseOp1, *BaseOp2;
int64_t Offset1, Offset2;
bool Offset1IsScalable, Offset2IsScalable;
if (TII->getMemOperandWithOffset(LdMI, BaseOp1, Offset1,
Offset1IsScalable, TRI) &&
TII->getMemOperandWithOffset(MI, BaseOp2, Offset2,
Offset2IsScalable, TRI)) {
if (BaseOp1->isIdenticalTo(*BaseOp2) &&
Offset1IsScalable == Offset2IsScalable &&
(int)Offset1 < (int)Offset2) {
assert(TII->areMemAccessesTriviallyDisjoint(LdMI, MI) &&
"What happened to the chain edge?");
SDep Dep(Load.SU, SDep::Barrier);
Dep.setLatency(1);
SU.addPred(Dep);
continue;
}
}
// Second, the more expensive check that uses alias analysis on the
// base registers. If they alias, and the load offset is less than
// the store offset, the mark the dependence as loop carried.
if (Load.isUnknown() || Store.isUnknown()) {
SDep Dep(Load.SU, SDep::Barrier);
Dep.setLatency(1);
SU.addPred(Dep);
continue;
}
if (Load.MemOpValue == Store.MemOpValue &&
Load.MemOpOffset <= Store.MemOpOffset) {
SDep Dep(Load.SU, SDep::Barrier);
Dep.setLatency(1);
SU.addPred(Dep);
continue;
}

bool IsNoAlias = [&] {
if (BAA.isNoAlias(MemoryLocation::getBeforeOrAfter(Load.MemOpValue,
Load.AATags),
MemoryLocation::getBeforeOrAfter(Store.MemOpValue,
Store.AATags)))
return true;

// AliasAnalysis sometimes gives up on following the underlying
// object. In such a case, separate checks for underlying objects may
// prove that there are no aliases between two accesses.
for (const Value *LoadObj : Load.UnderlyingObjs)
for (const Value *StoreObj : Store.UnderlyingObjs)
if (!BAA.isNoAlias(
MemoryLocation::getBeforeOrAfter(LoadObj, Load.AATags),
MemoryLocation::getBeforeOrAfter(StoreObj, Store.AATags)))
return false;

return true;
}();

if (!IsNoAlias) {
for (const SUnitWithMemInfo &Load : PendingLoads)
if (hasLoopCarriedMemDep(Load, Store, BAA, TII, TRI)) {
SDep Dep(Load.SU, SDep::Barrier);
Dep.setLatency(1);
SU.addPred(Dep);
}
}
}
}
}
Expand Down
Loading
Morty Proxy This is a proxified and sanitized view of the page, visit original site.