From fa87f4d35423aff6598b3bef63dfeb161630260b Mon Sep 17 00:00:00 2001 From: Ryotaro Kasuga Date: Wed, 25 Jun 2025 13:13:13 +0000 Subject: [PATCH 1/3] [MachinePipeliner] Add missed loop-carried memory deps for validation --- llvm/include/llvm/CodeGen/MachinePipeliner.h | 38 ++-- llvm/lib/CodeGen/MachinePipeliner.cpp | 194 ++++++++++++++---- .../Hexagon/swp-loop-carried-order-dep1.mir | 14 +- .../Hexagon/swp-loop-carried-order-dep2.mir | 8 +- .../Hexagon/swp-loop-carried-order-dep3.mir | 8 +- .../Hexagon/swp-loop-carried-order-dep4.mir | 6 +- .../Hexagon/swp-loop-carried-order-dep5.mir | 22 +- 7 files changed, 204 insertions(+), 86 deletions(-) diff --git a/llvm/include/llvm/CodeGen/MachinePipeliner.h b/llvm/include/llvm/CodeGen/MachinePipeliner.h index e4e794c434adb..3a3b1fc353146 100644 --- a/llvm/include/llvm/CodeGen/MachinePipeliner.h +++ b/llvm/include/llvm/CodeGen/MachinePipeliner.h @@ -120,14 +120,17 @@ class SwingSchedulerDDGEdge { SUnit *Dst = nullptr; SDep Pred; unsigned Distance = 0; + bool IsValidationOnly = false; public: /// Creates an edge corresponding to an edge represented by \p PredOrSucc and /// \p Dep in the original DAG. This pair has no information about the /// direction of the edge, so we need to pass an additional argument \p /// IsSucc. - SwingSchedulerDDGEdge(SUnit *PredOrSucc, const SDep &Dep, bool IsSucc) - : Dst(PredOrSucc), Pred(Dep), Distance(0u) { + SwingSchedulerDDGEdge(SUnit *PredOrSucc, const SDep &Dep, bool IsSucc, + bool IsValidationOnly) + : Dst(PredOrSucc), Pred(Dep), Distance(0u), + IsValidationOnly(IsValidationOnly) { SUnit *Src = Dep.getSUnit(); if (IsSucc) { @@ -188,6 +191,10 @@ class SwingSchedulerDDGEdge { /// functions. We ignore the back-edge recurrence in order to avoid unbounded /// recursion in the calculation of the ASAP, ALAP, etc functions. bool ignoreDependence(bool IgnoreAnti) const; + + /// Returns true if this edge is intended to be used only for validating the + /// schedule. + bool isValidationOnly() const { return IsValidationOnly; } }; /// Represents loop-carried dependencies. Because SwingSchedulerDAG doesn't @@ -208,25 +215,21 @@ struct LoopCarriedEdges { return &Ite->second; } - /// Retruns true if the edge from \p From to \p To is a back-edge that should - /// be used when scheduling. - bool shouldUseWhenScheduling(const SUnit *From, const SUnit *To) const; - /// Adds some edges to the original DAG that correspond to loop-carried /// dependencies. Historically, loop-carried edges are represented by using /// non-loop-carried edges in the original DAG. This function appends such /// edges to preserve the previous behavior. - void modifySUnits(std::vector &SUnits); + void modifySUnits(std::vector &SUnits, const TargetInstrInfo *TII); void dump(SUnit *SU, const TargetRegisterInfo *TRI, const MachineRegisterInfo *MRI) const; }; -/// Represents dependencies between instructions. This class is a wrapper of -/// `SUnits` and its dependencies to manipulate back-edges in a natural way. -/// Currently it only supports back-edges via PHI, which are expressed as -/// anti-dependencies in the original DAG. -/// FIXME: Support any other loop-carried dependencies +/// This class provides APIs to retrieve edges from/to an SUnit node, with a +/// particular focus on loop-carried dependencies. Since SUnit is not designed +/// to represent such edges, handling them directly using its APIs has required +/// non-trivial logic in the past. This class serves as a wrapper around SUnit, +/// offering a simpler interface for managing these dependencies. class SwingSchedulerDDG { using EdgesType = SmallVector; @@ -244,17 +247,26 @@ class SwingSchedulerDDG { SwingSchedulerDDGEdges EntrySUEdges; SwingSchedulerDDGEdges ExitSUEdges; + /// Edges that are used only when validating the schedule. These edges are + /// not considered to drive the optimization heuristics. + SmallVector ValidationOnlyEdges; + + /// Adds a NON-validation-only edge to the DDG. Assumes to be called only by + /// the cotr. void addEdge(const SUnit *SU, const SwingSchedulerDDGEdge &Edge); SwingSchedulerDDGEdges &getEdges(const SUnit *SU); const SwingSchedulerDDGEdges &getEdges(const SUnit *SU) const; public: - SwingSchedulerDDG(std::vector &SUnits, SUnit *EntrySU, SUnit *ExitSU); + SwingSchedulerDDG(std::vector &SUnits, SUnit *EntrySU, SUnit *ExitSU, + const LoopCarriedEdges &LCE); const EdgesType &getInEdges(const SUnit *SU) const; const EdgesType &getOutEdges(const SUnit *SU) const; + + bool isValidSchedule(const SMSchedule &Schedule) const; }; /// This class builds the dependence graph for the instructions in a loop, diff --git a/llvm/lib/CodeGen/MachinePipeliner.cpp b/llvm/lib/CodeGen/MachinePipeliner.cpp index d2c79f64afe64..c224654c062c5 100644 --- a/llvm/lib/CodeGen/MachinePipeliner.cpp +++ b/llvm/lib/CodeGen/MachinePipeliner.cpp @@ -338,6 +338,17 @@ class LoopCarriedOrderDepsTracker { void addLoopCarriedDepenenciesForChunks(const LoadStoreChunk &From, const LoadStoreChunk &To); + /// Add a loop-carried order dependency between \p Src and \p Dst if we + /// cannot prove tye are independent. When \p PerformCheapCheck is true, a + /// lightweight dependency test (referred to as "cheap check" below) is + /// performed at first. Note that the cheap check is retained to maintain the + /// existing behavior and not expected to be used anymore. + /// + /// TODO: Remove \p PerformCheapCheck and the corresponding cheap check. + void addDependenciesBetweenSUs(const SUnitWithMemInfo &Src, + const SUnitWithMemInfo &Dst, + bool PerformCheapCheck = false); + void computeDependenciesAux(); }; @@ -673,7 +684,7 @@ void SwingSchedulerDAG::schedule() { Topo.InitDAGTopologicalSorting(); changeDependences(); postProcessDAG(); - DDG = std::make_unique(SUnits, &EntrySU, &ExitSU); + DDG = std::make_unique(SUnits, &EntrySU, &ExitSU, LCE); LLVM_DEBUG({ dump(); dbgs() << "===== Loop Carried Edges Begin =====\n"; @@ -958,11 +969,11 @@ bool SUnitWithMemInfo::getUnderlyingObjects() { /// 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) { +static bool +hasLoopCarriedMemDep(const SUnitWithMemInfo &Src, const SUnitWithMemInfo &Dst, + BatchAAResults &BAA, const TargetInstrInfo *TII, + const TargetRegisterInfo *TRI, + const SwingSchedulerDAG *SSD, bool PerformCheapCheck) { if (Src.isTriviallyDisjoint(Dst)) return false; if (isSuccOrder(Src.SU, Dst.SU)) @@ -970,24 +981,32 @@ static bool hasLoopCarriedMemDep(const SUnitWithMemInfo &Src, 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; + if (PerformCheapCheck) { + // 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. + // + // TODO: This check will be removed. + 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; + } } } + if (!SSD->mayOverlapInLaterIter(&SrcMI, &DstMI)) + return false; + // 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. @@ -1056,20 +1075,34 @@ LoopCarriedOrderDepsTracker::getInstrTag(SUnit *SU) const { return std::nullopt; } +void LoopCarriedOrderDepsTracker::addDependenciesBetweenSUs( + const SUnitWithMemInfo &Src, const SUnitWithMemInfo &Dst, + bool PerformCheapCheck) { + // Avoid self-dependencies. + if (Src.SU == Dst.SU) + return; + + if (hasLoopCarriedMemDep(Src, Dst, *BAA, TII, TRI, DAG, PerformCheapCheck)) + LoopCarried[Src.SU->NodeNum].set(Dst.SU->NodeNum); +} + void LoopCarriedOrderDepsTracker::addLoopCarriedDepenenciesForChunks( const LoadStoreChunk &From, const LoadStoreChunk &To) { - // Add dependencies for load-to-store (WAR) from top to bottom. + // Add load-to-store dependencies (WAR). for (const SUnitWithMemInfo &Src : From.Loads) for (const SUnitWithMemInfo &Dst : To.Stores) - if (Src.SU->NodeNum < Dst.SU->NodeNum && - hasLoopCarriedMemDep(Src, Dst, *BAA, TII, TRI)) - LoopCarried[Src.SU->NodeNum].set(Dst.SU->NodeNum); + // Perform a cheap check first if this is a forward dependency. + addDependenciesBetweenSUs(Src, Dst, Src.SU->NodeNum < Dst.SU->NodeNum); - // TODO: The following dependencies are missed. - // - // - Dependencies for load-to-store from bottom to top. - // - Dependencies for store-to-load (RAW). - // - Dependencies for store-to-store (WAW). + // Add store-to-load dependencies (RAW). + for (const SUnitWithMemInfo &Src : From.Stores) + for (const SUnitWithMemInfo &Dst : To.Loads) + addDependenciesBetweenSUs(Src, Dst); + + // Add store-to-store dependencies (WAW). + for (const SUnitWithMemInfo &Src : From.Stores) + for (const SUnitWithMemInfo &Dst : To.Stores) + addDependenciesBetweenSUs(Src, Dst); } void LoopCarriedOrderDepsTracker::computeDependenciesAux() { @@ -1116,7 +1149,7 @@ LoopCarriedEdges SwingSchedulerDAG::addLoopCarriedDependences() { for (const int Succ : LCODTracker.getLoopCarried(I).set_bits()) LCE.OrderDeps[&SUnits[I]].insert(&SUnits[Succ]); - LCE.modifySUnits(SUnits); + LCE.modifySUnits(SUnits, TII); return LCE; } @@ -2676,6 +2709,11 @@ bool SwingSchedulerDAG::schedulePipeline(SMSchedule &Schedule) { }); } while (++NI != NE && scheduleFound); + // If a schedule is found, validate it against the validation-only + // dependencies. + if (scheduleFound) + scheduleFound = DDG->isValidSchedule(Schedule); + // If a schedule is found, ensure non-pipelined instructions are in stage 0 if (scheduleFound) scheduleFound = @@ -4118,6 +4156,8 @@ SwingSchedulerDDG::getEdges(const SUnit *SU) const { void SwingSchedulerDDG::addEdge(const SUnit *SU, const SwingSchedulerDDGEdge &Edge) { + assert(!Edge.isValidationOnly() && + "Validation-only edges are not expected here."); auto &Edges = getEdges(SU); if (Edge.getSrc() == SU) Edges.Succs.push_back(Edge); @@ -4127,25 +4167,43 @@ void SwingSchedulerDDG::addEdge(const SUnit *SU, void SwingSchedulerDDG::initEdges(SUnit *SU) { for (const auto &PI : SU->Preds) { - SwingSchedulerDDGEdge Edge(SU, PI, false); + SwingSchedulerDDGEdge Edge(SU, PI, /*IsSucc=*/false, + /*IsValidationOnly=*/false); addEdge(SU, Edge); } for (const auto &SI : SU->Succs) { - SwingSchedulerDDGEdge Edge(SU, SI, true); + SwingSchedulerDDGEdge Edge(SU, SI, /*IsSucc=*/true, + /*IsValidationOnly=*/false); addEdge(SU, Edge); } } SwingSchedulerDDG::SwingSchedulerDDG(std::vector &SUnits, SUnit *EntrySU, - SUnit *ExitSU) + SUnit *ExitSU, const LoopCarriedEdges &LCE) : EntrySU(EntrySU), ExitSU(ExitSU) { EdgesVec.resize(SUnits.size()); + // Add non-loop-carried edges based on the DAG. initEdges(EntrySU); initEdges(ExitSU); for (auto &SU : SUnits) initEdges(&SU); + + // Add loop-carried edges, which are not represented in the DAG. + for (SUnit &SU : SUnits) { + SUnit *Src = &SU; + if (const LoopCarriedEdges::OrderDep *OD = LCE.getOrderDepOrNull(Src)) { + SDep Base(Src, SDep::Barrier); + Base.setLatency(1); + for (SUnit *Dst : *OD) { + SwingSchedulerDDGEdge Edge(Dst, Base, /*IsSucc=*/false, + /*IsValidationOnly=*/true); + Edge.setDistance(1); + ValidationOnlyEdges.push_back(Edge); + } + } + } } const SwingSchedulerDDG::EdgesType & @@ -4158,17 +4216,73 @@ SwingSchedulerDDG::getOutEdges(const SUnit *SU) const { return getEdges(SU).Succs; } -void LoopCarriedEdges::modifySUnits(std::vector &SUnits) { - // Currently this function simply adds all dependencies represented by this - // object. After we properly handle missed dependencies, the logic here will - // be more complex, as currently missed edges should not be added to the DAG. +/// Check if \p Schedule doesn't violate the validation-only dependencies. +bool SwingSchedulerDDG::isValidSchedule(const SMSchedule &Schedule) const { + unsigned II = Schedule.getInitiationInterval(); + + auto ExpandCycle = [&](SUnit *SU) { + int Stage = Schedule.stageScheduled(SU); + int Cycle = Schedule.cycleScheduled(SU); + return Cycle + (Stage * II); + }; + + for (const SwingSchedulerDDGEdge &Edge : ValidationOnlyEdges) { + SUnit *Src = Edge.getSrc(); + SUnit *Dst = Edge.getDst(); + if (!Src->isInstr() || !Dst->isInstr()) + continue; + int CycleSrc = ExpandCycle(Src); + int CycleDst = ExpandCycle(Dst); + int MaxLateStart = CycleDst + Edge.getDistance() * II - Edge.getLatency(); + if (CycleSrc > MaxLateStart) { + LLVM_DEBUG({ + dbgs() << "Validation failed for edge from " << Src->NodeNum << " to " + << Dst->NodeNum << "\n"; + }); + return false; + } + } + return true; +} + +void LoopCarriedEdges::modifySUnits(std::vector &SUnits, + const TargetInstrInfo *TII) { for (SUnit &SU : SUnits) { SUnit *Src = &SU; if (auto *OrderDep = getOrderDepOrNull(Src)) { SDep Dep(Src, SDep::Barrier); Dep.setLatency(1); - for (SUnit *Dst : *OrderDep) - Dst->addPred(Dep); + for (SUnit *Dst : *OrderDep) { + SUnit *From = Src; + SUnit *To = Dst; + if (From->NodeNum > To->NodeNum) + std::swap(From, To); + + // Add a forward edge if the following conditions are met: + // + // - The instruction of the source node (FromMI) may read memory. + // - The instruction of the target node (ToMI) may modify memory, but + // does not read it. + // - Neither instruction is a global barrier. + // - The load appears before the store in the original basic block. + // - There are no barrier or store instructions between the two nodes. + // - The target node is unreachable from the source node in the current + // DAG. + // + // TODO: These conditions are inherited from a previous implementation, + // and some may no longer be necessary. For now, we conservatively + // retain all of them to avoid regressions, but the logic could + // potentially be simplified + MachineInstr *FromMI = From->getInstr(); + MachineInstr *ToMI = To->getInstr(); + if (FromMI->mayLoad() && !ToMI->mayLoad() && ToMI->mayStore() && + !TII->isGlobalMemoryObject(FromMI) && + !TII->isGlobalMemoryObject(ToMI) && !isSuccOrder(From, To)) { + SDep Pred = Dep; + Pred.setSUnit(Src); + Dst->addPred(Pred); + } + } } } } diff --git a/llvm/test/CodeGen/Hexagon/swp-loop-carried-order-dep1.mir b/llvm/test/CodeGen/Hexagon/swp-loop-carried-order-dep1.mir index 17ee07f49324a..7182e0a112560 100644 --- a/llvm/test/CodeGen/Hexagon/swp-loop-carried-order-dep1.mir +++ b/llvm/test/CodeGen/Hexagon/swp-loop-carried-order-dep1.mir @@ -14,16 +14,14 @@ # ``` # # Loop-carried dependencies exist from store for a[i+1] to load/store for a[i], but not vice versa. -# FIXME: Currently the following dependencies are missed. -# -# Loop carried edges from SU(6) -# Order -# SU(4) -# Loop carried edges from SU(8) -# Order -# SU(4) # CHECK: ===== Loop Carried Edges Begin ===== +# CHECK-NEXT: Loop carried edges from SU(6) +# CHECK-NEXT: Order +# CHECK-NEXT: SU(4) +# CHECK-NEXT: Loop carried edges from SU(8) +# CHECK-NEXT: Order +# CHECK-NEXT: SU(4) # CHECK-NEXT: ===== Loop Carried Edges End ===== --- | diff --git a/llvm/test/CodeGen/Hexagon/swp-loop-carried-order-dep2.mir b/llvm/test/CodeGen/Hexagon/swp-loop-carried-order-dep2.mir index 850e602c9146f..56485e04ad35c 100644 --- a/llvm/test/CodeGen/Hexagon/swp-loop-carried-order-dep2.mir +++ b/llvm/test/CodeGen/Hexagon/swp-loop-carried-order-dep2.mir @@ -14,16 +14,14 @@ # ``` # # Loop-carried dependencies exist from load/store for a[i] to store for a[i-1], but not vice versa. -# FIXME: Currently the following dependencies are missed. -# -# Loop carried edges from SU(5) -# Order -# SU(7) # CHECK: ===== Loop Carried Edges Begin ===== # CHECK-NEXT: Loop carried edges from SU(3) # CHECK-NEXT: Order # CHECK-NEXT: SU(7) +# CHECK-NEXT: Loop carried edges from SU(5) +# CHECK-NEXT: Order +# CHECK-NEXT: SU(7) # CHECK-NEXT: ===== Loop Carried Edges End ===== --- | diff --git a/llvm/test/CodeGen/Hexagon/swp-loop-carried-order-dep3.mir b/llvm/test/CodeGen/Hexagon/swp-loop-carried-order-dep3.mir index ca59b97dd11e9..69f56fa7934f2 100644 --- a/llvm/test/CodeGen/Hexagon/swp-loop-carried-order-dep3.mir +++ b/llvm/test/CodeGen/Hexagon/swp-loop-carried-order-dep3.mir @@ -14,13 +14,11 @@ # ``` # # Loop-carried dependencies exist from load for a[i+1] to store for a[i]. -# FIXME: Currently the following dependencies are missed. -# -# Loop carried edges from SU(7) -# Order -# SU(5) # CHECK: ===== Loop Carried Edges Begin ===== +# CHECK-NEXT: Loop carried edges from SU(7) +# CHECK-NEXT: Order +# CHECK-NEXT: SU(5) # CHECK-NEXT: ===== Loop Carried Edges End ===== --- | diff --git a/llvm/test/CodeGen/Hexagon/swp-loop-carried-order-dep4.mir b/llvm/test/CodeGen/Hexagon/swp-loop-carried-order-dep4.mir index 4bc4b48735947..cc4e9e1d67c5c 100644 --- a/llvm/test/CodeGen/Hexagon/swp-loop-carried-order-dep4.mir +++ b/llvm/test/CodeGen/Hexagon/swp-loop-carried-order-dep4.mir @@ -20,15 +20,15 @@ # # FIXME: Currently the following dependencies are missed. # -# Loop carried edges from SU(4) -# Order -# SU(3) # CHECK: ===== Loop Carried Edges Begin ===== # CHECK-NEXT: Loop carried edges from SU(2) # CHECK-NEXT: Order # CHECK-NEXT: SU(3) # CHECK-NEXT: SU(4) +# CHECK-NEXT: Loop carried edges from SU(4) +# CHECK-NEXT: Order +# CHECK-NEXT: SU(3) # CHECK-NEXT: ===== Loop Carried Edges End ===== --- | diff --git a/llvm/test/CodeGen/Hexagon/swp-loop-carried-order-dep5.mir b/llvm/test/CodeGen/Hexagon/swp-loop-carried-order-dep5.mir index 77c3d569db181..3c2e0c40680c8 100644 --- a/llvm/test/CodeGen/Hexagon/swp-loop-carried-order-dep5.mir +++ b/llvm/test/CodeGen/Hexagon/swp-loop-carried-order-dep5.mir @@ -23,20 +23,18 @@ # Note that if there is already a dependency between two instructions, we don't # add loop-carried on between them since non-loop-carried one imposes stronger # constraint than loop-carried one. -# -# FIXME: Currently the following dependencies are missed. -# Loop carried edges from SU(5) -# Order -# SU(2) -# Loop carried edges from SU(6) -# Order -# SU(5) -# Loop carried edges from SU(8) -# Order -# SU(3) -# SU(5) # CHECK: ===== Loop Carried Edges Begin ===== +# CHECK-NEXT: Loop carried edges from SU(5) +# CHECK-NEXT: Order +# CHECK-NEXT: SU(2) +# CHECK-NEXT: Loop carried edges from SU(6) +# CHECK-NEXT: Order +# CHECK-NEXT: SU(5) +# CHECK-NEXT: Loop carried edges from SU(8) +# CHECK-NEXT: Order +# CHECK-NEXT: SU(3) +# CHECK-NEXT: SU(5) # CHECK-NEXT: ===== Loop Carried Edges End ===== --- | From 46c21dd8869842d5f12392c1c292ef41804c8b21 Mon Sep 17 00:00:00 2001 From: Ryotaro Kasuga Date: Thu, 10 Jul 2025 19:23:41 +0900 Subject: [PATCH 2/3] Update llvm/lib/CodeGen/MachinePipeliner.cpp Co-authored-by: aankit-ca --- llvm/lib/CodeGen/MachinePipeliner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/lib/CodeGen/MachinePipeliner.cpp b/llvm/lib/CodeGen/MachinePipeliner.cpp index c224654c062c5..b38a4d1c55af9 100644 --- a/llvm/lib/CodeGen/MachinePipeliner.cpp +++ b/llvm/lib/CodeGen/MachinePipeliner.cpp @@ -339,7 +339,7 @@ class LoopCarriedOrderDepsTracker { const LoadStoreChunk &To); /// Add a loop-carried order dependency between \p Src and \p Dst if we - /// cannot prove tye are independent. When \p PerformCheapCheck is true, a + /// cannot prove they are independent. When \p PerformCheapCheck is true, a /// lightweight dependency test (referred to as "cheap check" below) is /// performed at first. Note that the cheap check is retained to maintain the /// existing behavior and not expected to be used anymore. From b5348d7a34d0eb93ab1a4ccdb4a43a092d8b8ed1 Mon Sep 17 00:00:00 2001 From: Ryotaro Kasuga Date: Thu, 10 Jul 2025 19:26:36 +0900 Subject: [PATCH 3/3] Fix typo --- llvm/include/llvm/CodeGen/MachinePipeliner.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/include/llvm/CodeGen/MachinePipeliner.h b/llvm/include/llvm/CodeGen/MachinePipeliner.h index 3a3b1fc353146..e50443d25cc60 100644 --- a/llvm/include/llvm/CodeGen/MachinePipeliner.h +++ b/llvm/include/llvm/CodeGen/MachinePipeliner.h @@ -252,7 +252,7 @@ class SwingSchedulerDDG { SmallVector ValidationOnlyEdges; /// Adds a NON-validation-only edge to the DDG. Assumes to be called only by - /// the cotr. + /// the ctor. void addEdge(const SUnit *SU, const SwingSchedulerDDGEdge &Edge); SwingSchedulerDDGEdges &getEdges(const SUnit *SU);