[llvm] [LoopSplitUtils] Revert, removing from tree (PR #214577)

via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 10 02:37:58 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-transforms

Author: Ramkumar Ramachandra (artagnon)

<details>
<summary>Changes</summary>

This reverts commits:

- 2354dce21 ([Transforms][Utils] Add LoopSplitUtils for iteration-space loop splitting, #<!-- -->205995)
- 8f1efc26 ([Transforms][Utils] Preserve branch weights in LoopSplitUtils, #<!-- -->213626)
- 49ace5ab ([Transforms][Utils] Test for branch weight preservation in LoopSplitUtils, #<!-- -->213647)

Removing LoopSplitUtils from the tree completely, as several crashes were uncovered after it was added. A highly reduced initial version with much better test coverage is proposed for the re-land.

---

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


19 Files Affected:

- (modified) llvm/include/llvm/IR/ValueMap.h (-11) 
- (removed) llvm/include/llvm/Transforms/Utils/LoopSplitUtils.h (-154) 
- (removed) llvm/include/llvm/Transforms/Utils/LoopSplitUtilsPass.h (-30) 
- (modified) llvm/lib/Passes/PassBuilder.cpp (-1) 
- (modified) llvm/lib/Passes/PassRegistry.def (-1) 
- (modified) llvm/lib/Transforms/Utils/CMakeLists.txt (-2) 
- (removed) llvm/lib/Transforms/Utils/LoopSplitUtils.cpp (-630) 
- (removed) llvm/lib/Transforms/Utils/LoopSplitUtilsPass.cpp (-148) 
- (removed) llvm/test/Transforms/LoopSplit/basic.ll (-61) 
- (removed) llvm/test/Transforms/LoopSplit/branch-weights.ll (-67) 
- (removed) llvm/test/Transforms/LoopSplit/constant-trip-count.ll (-89) 
- (removed) llvm/test/Transforms/LoopSplit/descending.ll (-60) 
- (removed) llvm/test/Transforms/LoopSplit/empty-leading-partition.ll (-71) 
- (removed) llvm/test/Transforms/LoopSplit/four-partitions.ll (-88) 
- (removed) llvm/test/Transforms/LoopSplit/multiple-partitions.ll (-75) 
- (removed) llvm/test/Transforms/LoopSplit/nested-loop.ll (-88) 
- (removed) llvm/test/Transforms/LoopSplit/optional-guard.ll (-70) 
- (removed) llvm/test/Transforms/LoopSplit/partition-value-map.ll (-44) 
- (removed) llvm/test/Transforms/LoopSplit/reduction.ll (-71) 


``````````diff
diff --git a/llvm/include/llvm/IR/ValueMap.h b/llvm/include/llvm/IR/ValueMap.h
index 1b9ade90293d8..435347be3f3c1 100644
--- a/llvm/include/llvm/IR/ValueMap.h
+++ b/llvm/include/llvm/IR/ValueMap.h
@@ -169,17 +169,6 @@ class ValueMap {
     return I != Map.end() ? I->second : ValueT();
   }
 
-  /// Return the entry for the specified key, or \p Default. This variant is
-  /// useful, because `lookup` cannot be used with non-default-constructible
-  /// values.
-  template <typename U = std::remove_cv_t<ValueT>>
-  ValueT lookup_or(const KeyT &Val, U &&Default) const {
-    typename MapT::const_iterator I = Map.find_as(Val);
-    if (I != Map.end())
-      return I->second;
-    return std::forward<U>(Default);
-  }
-
   // Inserts key,value pair into the map if the key isn't already in the map.
   // If the key is already in the map, it returns false and doesn't update the
   // value.
diff --git a/llvm/include/llvm/Transforms/Utils/LoopSplitUtils.h b/llvm/include/llvm/Transforms/Utils/LoopSplitUtils.h
deleted file mode 100644
index f01a8c5d74662..0000000000000
--- a/llvm/include/llvm/Transforms/Utils/LoopSplitUtils.h
+++ /dev/null
@@ -1,154 +0,0 @@
-//===- LoopSplitUtils.h - Split a loop's iteration space --------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// Splits a counted loop's iteration space into a chain of per-partition
-// sub-loops. See LoopSplitUtils.cpp for the structure produced.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_TRANSFORMS_UTILS_LOOPSPLITUTILS_H
-#define LLVM_TRANSFORMS_UTILS_LOOPSPLITUTILS_H
-
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/Analysis/LoopInfo.h"
-#include "llvm/Support/Compiler.h"
-#include "llvm/Transforms/Utils/ValueMapper.h"
-#include <memory>
-
-namespace llvm {
-
-class DominatorTree;
-class SCEV;
-class SCEVExpander;
-class ScalarEvolution;
-
-/// Splits a counted loop into a chain of per-partition sub-loops.
-///
-/// Usage:
-/// \code
-///   LoopSplitUtils LSU(L, LI, SE, DT);
-///   if (!LSU.isLegal())
-///     return false;
-///   LSU.addPartition(S0, E0);   // one call per partition, in order
-///   LSU.addPartition(S1, E1);
-///   LSU.split();
-/// \endcode
-class LoopSplitUtils {
-public:
-  LLVM_ABI LoopSplitUtils(Loop *L, LoopInfo *LI, ScalarEvolution *SE,
-                          DominatorTree *DT)
-      : L(L), LI(LI), SE(SE), DT(DT) {}
-
-  /// Analyze \p L and return true if it is a counted loop this utility can
-  /// split: a bottom-tested single-exit loop in LCSSA form with a unique
-  /// unit-step integer induction and a computable trip count. Must succeed
-  /// before split().
-  LLVM_ABI bool isLegal();
-
-  /// Return the loop's induction variable. Valid only after isLegal() succeeds.
-  LLVM_ABI PHINode *getInductionVariable() const {
-    return L->getInductionVariable(*SE);
-  }
-
-  /// Append an inclusive partition range [Start, End] in iteration order.
-  /// Partitions must tile the whole space: first Start = induction start, each
-  /// later Start = previous End +/- step, last End = induction end (desc: S >=
-  /// E).
-  ///
-  /// Bounds must be loop-invariant and representable in the induction type
-  /// without wrapping: a Start +/- offset that wraps past TYPE_MAX/MIN/0 looks
-  /// in-range and silently miscompiles. See LoopSplitUtils.cpp for the
-  /// rationale.
-  ///
-  /// Every partition is guarded by default; use avoidPartitionGuard() to opt
-  /// out.
-  LLVM_ABI void addPartition(const SCEV *Start, const SCEV *End);
-
-  /// Suppress the entry guard for partition \p PartitionIndex (already added).
-  /// Use only for a partition the caller can prove runs at least once; for a
-  /// runtime- empty partition this is incorrect and yields one spurious
-  /// iteration.
-  LLVM_ABI void avoidPartitionGuard(unsigned PartitionIndex);
-
-  LLVM_ABI unsigned getNumPartitions() const { return Partitions.size(); }
-
-  /// Perform the split. Requires a successful isLegal() and at least two
-  /// partitions. Returns true if the loop was rewritten.
-  LLVM_ABI bool split();
-
-  /// Return the counterpart of original-loop value \p V in partition
-  /// \p PartitionIndex (0-based). Partition 0 maps values to themselves; a
-  /// later partition returns the clone, or null if not cloned. Valid only after
-  /// split().
-  LLVM_ABI Value *getPartitionValue(Value *V, unsigned PartitionIndex) const;
-
-  /// Return the original-to-clone value map for the partition at
-  /// \p PartitionIndex, for callers that want to remap many values. Null for
-  /// partition 0 (identity) and for any partition that was not cloned.
-  LLVM_ABI const ValueToValueMapTy *
-  getPartitionValueMap(unsigned PartitionIndex) const;
-
-private:
-  /// Everything known about one partition: the caller-supplied range plus the
-  /// state split() derives. Indexed by partition number in \c Partitions.
-  struct PartitionInfo {
-    PartitionInfo() = default;
-    PartitionInfo(const SCEV *StartExpr, const SCEV *EndExpr)
-        : StartExpr(StartExpr), EndExpr(EndExpr) {}
-
-    // Set by addPartition() / avoidPartitionGuard() before split():
-    const SCEV *StartExpr = nullptr; // inclusive iteration range [Start, End].
-    const SCEV *EndExpr = nullptr;
-    bool Guarded = true; // emit an entry guard?
-
-    // Filled in by split():
-    std::unique_ptr<ValueToValueMapTy> VMap; // null for partition 0 (identity).
-    Value *StartVal = nullptr;               // expanded start.
-    Value *SelEnd = nullptr;                 // clamped end min(End, indEnd).
-    bool Empty = false;                      // provably zero-iteration.
-    BasicBlock *GuardBlock = nullptr;
-    BasicBlock *Preheader = nullptr;
-    BasicBlock *Exit = nullptr;
-    Loop *SubLoop = nullptr;
-    Value *LatchIndOp = nullptr; // induction operand of the latch compare.
-  };
-
-  /// Per-split() scratch threaded through the phase helpers (the escaping
-  /// values, new blocks, etc.). A pure transform internal, so it is defined in
-  /// the implementation file.
-  struct SplitState;
-
-  Loop *L;
-  LoopInfo *LI;
-  ScalarEvolution *SE;
-  DominatorTree *DT;
-
-  // Induction analysis, populated by isLegal().
-  Value *LatchIndOperand = nullptr; // induction operand of the latch compare.
-  bool InductionIsSigned = false;   // iteration ordering signedness.
-  const SCEV *InductionEnd = nullptr;
-
-  /// One record per partition, in add order.
-  SmallVector<PartitionInfo, 4> Partitions;
-
-  // split() phase helpers, run in order; each is documented at its definition.
-  /// Collect loop-carried and live-out values and split off the final exit.
-  void collectEscapingValues(SplitState &S);
-  /// Expand each partition's start and clamped end into the entry guard.
-  void expandPartitionBounds(SplitState &S, SCEVExpander &Expander);
-  /// Pass 1: clone each later partition's sub-loop and create its guard/exit.
-  void clonePartitions(SplitState &S);
-  /// Pass 2: emit each guard, clamp each latch, and chain the partitions.
-  void chainPartitions(SplitState &S);
-  /// Rebuild SSA for every escaping value with a per-value SSAUpdater.
-  void reconstructSSA(SplitState &S);
-};
-
-} // namespace llvm
-
-#endif // LLVM_TRANSFORMS_UTILS_LOOPSPLITUTILS_H
diff --git a/llvm/include/llvm/Transforms/Utils/LoopSplitUtilsPass.h b/llvm/include/llvm/Transforms/Utils/LoopSplitUtilsPass.h
deleted file mode 100644
index 4a744d5fb7a22..0000000000000
--- a/llvm/include/llvm/Transforms/Utils/LoopSplitUtilsPass.h
+++ /dev/null
@@ -1,30 +0,0 @@
-//===- LoopSplitUtilsPass.h - Test driver for LoopSplitUtils ----*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// A command-line driven pass used to exercise the LoopSplitUtils utility from
-// `opt`. The split points are provided via the -loop-split-points option as
-// iteration offsets relative to the induction start.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_TRANSFORMS_UTILS_LOOPSPLITUTILSPASS_H
-#define LLVM_TRANSFORMS_UTILS_LOOPSPLITUTILSPASS_H
-
-#include "llvm/IR/PassManager.h"
-#include "llvm/Support/Compiler.h"
-
-namespace llvm {
-
-class LoopSplitUtilsPass : public PassInfoMixin<LoopSplitUtilsPass> {
-public:
-  LLVM_ABI PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
-};
-
-} // namespace llvm
-
-#endif // LLVM_TRANSFORMS_UTILS_LOOPSPLITUTILSPASS_H
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index db4b92811f57e..6abaa77f9065f 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -379,7 +379,6 @@
 #include "llvm/Transforms/Utils/InstructionNamer.h"
 #include "llvm/Transforms/Utils/LibCallsShrinkWrap.h"
 #include "llvm/Transforms/Utils/LoopSimplify.h"
-#include "llvm/Transforms/Utils/LoopSplitUtilsPass.h"
 #include "llvm/Transforms/Utils/LoopVersioning.h"
 #include "llvm/Transforms/Utils/LowerCommentStringPass.h"
 #include "llvm/Transforms/Utils/LowerGlobalDtors.h"
diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
index 5e592945d0de7..177d8ecd3508d 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -478,7 +478,6 @@ FUNCTION_PASS("loop-fusion", LoopFusePass())
 FUNCTION_PASS("loop-load-elim", LoopLoadEliminationPass())
 FUNCTION_PASS("loop-simplify", LoopSimplifyPass())
 FUNCTION_PASS("loop-sink", LoopSinkPass())
-FUNCTION_PASS("loop-split-utils", LoopSplitUtilsPass())
 FUNCTION_PASS("loop-versioning", LoopVersioningPass())
 FUNCTION_PASS("lower-atomic", LowerAtomicPass())
 FUNCTION_PASS("lower-constant-intrinsics", LowerConstantIntrinsicsPass())
diff --git a/llvm/lib/Transforms/Utils/CMakeLists.txt b/llvm/lib/Transforms/Utils/CMakeLists.txt
index 8858582506329..68f48b757eb6d 100644
--- a/llvm/lib/Transforms/Utils/CMakeLists.txt
+++ b/llvm/lib/Transforms/Utils/CMakeLists.txt
@@ -49,8 +49,6 @@ add_llvm_component_library(LLVMTransformUtils
   LoopPeel.cpp
   LoopRotationUtils.cpp
   LoopSimplify.cpp
-  LoopSplitUtils.cpp
-  LoopSplitUtilsPass.cpp
   LoopUnroll.cpp
   LoopUnrollAndJam.cpp
   LoopUnrollRuntime.cpp
diff --git a/llvm/lib/Transforms/Utils/LoopSplitUtils.cpp b/llvm/lib/Transforms/Utils/LoopSplitUtils.cpp
deleted file mode 100644
index db07e3f571f66..0000000000000
--- a/llvm/lib/Transforms/Utils/LoopSplitUtils.cpp
+++ /dev/null
@@ -1,630 +0,0 @@
-//===- LoopSplitUtils.cpp - Split a loop's iteration space ----------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// Splits a counted loop's iteration space into a chain of per-partition
-// sub-loops. See LoopSplitUtils.h for the high-level usage guidelines.
-//
-// Structure produced for partitions [S0,E0], [S1,E1], ... where E is the loop's
-// last iteration and each clamped end sel_i = min(E_i, E):
-//
-//   guard0:                            ; every S_i and sel_i is computed here
-//     if (S0 <= sel0) goto preheader0 else goto guard1   ; default guard check
-//   loop0: ...                         ; latch stops at sel0
-//   exit0 -> guard1
-//   guard1:
-//     if (S1 <= sel1) goto preheader1 else goto guard2   ; default guard check
-//   loop1: ...                         ; latch stops at sel1
-//   exit1 -> guard2
-//     ...
-//   final.exit:                        ; merges every partition's live-outs
-//
-// Each guard holds the "S_i <= sel_i" check and skips an empty partition by
-// falling through to the next guard. The check is replaced by an unconditional
-// branch when a partition is proven empty (to the next guard) or the caller
-// exempts it via avoidPartitionGuard() (to its preheader). All S_i/sel_i are
-// materialized once in guard0; the end clamp keeps the "runs at least once"
-// iteration in the right partition; live-outs are rebuilt one SSAUpdater each.
-//
-// A descending (step -1) loop uses the same structure mirrored: partitions run
-// high-to-low and the empty test, clamp, and predicates flip (>=/>).
-//
-// Usage guidelines:
-//  - Caller bounds must not wrap the induction type. The clamp absorbs a bound
-//    past the runtime trip count, but a Start +/- offset that overshoots the
-//    type extreme wraps in the bound arithmetic and cannot be repaired here.
-//  - Bounds must be loop-invariant: they are expanded in guard0 (the
-//  preheader),
-//    so a bound depending on a value defined inside the loop cannot be placed.
-//  - The partitions must tile the original iteration space exactly -- same
-//    iterations, same order -- so the split preserves program behaviour.
-//  - A caller that drops a guard via avoidPartitionGuard() must itself ensure
-//    that partition runs at least once, or the result is a spurious iteration.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Transforms/Utils/LoopSplitUtils.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/Analysis/LoopInfo.h"
-#include "llvm/Analysis/ScalarEvolution.h"
-#include "llvm/Analysis/ScalarEvolutionExpressions.h"
-#include "llvm/Analysis/ScalarEvolutionPatternMatch.h"
-#include "llvm/IR/BasicBlock.h"
-#include "llvm/IR/CFG.h"
-#include "llvm/IR/Constants.h"
-#include "llvm/IR/Dominators.h"
-#include "llvm/IR/Function.h"
-#include "llvm/IR/IRBuilder.h"
-#include "llvm/IR/Instructions.h"
-#include "llvm/IR/ProfDataUtils.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Transforms/Utils/BasicBlockUtils.h"
-#include "llvm/Transforms/Utils/Cloning.h"
-#include "llvm/Transforms/Utils/LoopUtils.h"
-#include "llvm/Transforms/Utils/SSAUpdater.h"
-#include "llvm/Transforms/Utils/ScalarEvolutionExpander.h"
-#include "llvm/Transforms/Utils/ValueMapper.h"
-#include <optional>
-
-using namespace llvm;
-using namespace llvm::SCEVPatternMatch;
-
-#define DEBUG_TYPE "loop-split-utils"
-
-//===----------------------------------------------------------------------===//
-// LoopSplitUtils - construction, partition list, induction analysis
-//===----------------------------------------------------------------------===//
-
-/// Per-split() scratch shared by the phase helpers; lives for one split() call.
-struct LoopSplitUtils::SplitState {
-  // Partition 0 reuses the original loop's preheader, exit, and entry guard;
-  // those blocks live in Partitions[0] rather than being duplicated here.
-  BasicBlock *FinalExit = nullptr; // where live-outs merge.
-  Loop *OuterLoop = nullptr;       // parent of the new blocks, if any.
-  PHINode *Induction = nullptr;    // the loop's induction variable.
-  bool Descending = false;         // step is negative (loop counts down).
-  bool LatchComparesPHI = false;   // latch compares the PHI, not the step.
-
-  /// A value that must be reconstructed after cloning because it is
-  /// loop-carried (feeds a later partition), live-out (used after the loop), or
-  /// both.
-  struct EscapingValue {
-    EscapingValue() = default;
-    EscapingValue(Value *Def) : Def(Def) {}
-
-    /// The value as it exists in partition 0 (the original).
-    Value *Def = nullptr;
-    /// The carried header PHI in partition 0, or null if \c Def needs no
-    /// per-partition start value seeded.
-    PHINode *CarriedHeaderPHI = nullptr;
-    /// True if \c Def is used outside the loop and must be merged at the final
-    /// exit.
-    bool EscapesOutside = false;
-    /// \c Def and \c CarriedHeaderPHI cloned into each partition (index 0 is
-    /// the original; \c PerPartitionPHI[0] is unused).
-    SmallVector<Value *, 4> PerPartitionDef;
-    SmallVector<PHINode *, 4> PerPartitionPHI;
-  };
-
-  /// Values that must survive across partitions (carried and/or live-out).
-  SmallVector<EscapingValue, 8> Escaping;
-
-  EscapingValue &addEscaping(Value *Def) { return Escaping.emplace_back(Def); }
-};
-
-// Record a new partition with the given inclusive iteration range.
-void LoopSplitUtils::addPartition(const SCEV *Start, const SCEV *End) {
-  Partitions.emplace_back(Start, End);
-}
-
-// Mark a partition so split() emits no entry guard for it.
-void LoopSplitUtils::avoidPartitionGuard(unsigned PartitionIndex) {
-  assert(PartitionIndex < Partitions.size() &&
-         "avoidPartitionGuard() called for an unknown partition");
-  Partitions[PartitionIndex].Guarded = false;
-}
-
-// Return a partition's original-to-clone map, or null if it has none.
-const ValueToValueMapTy *
-LoopSplitUtils::getPartitionValueMap(unsigned PartitionIndex) const {
-  if (PartitionIndex >= Partitions.size())
-    return nullptr;
-  return Partitions[PartitionIndex].VMap.get();
-}
-
-// Look up the counterpart of an original value in a given partition.
-Value *LoopSplitUtils::getPartitionValue(Value *V,
-                                         unsigned PartitionIndex) const {
-  assert(PartitionIndex < getNumPartitions() && "partition index out of range");
-  // Partition 0 reuses the original loop: every value maps to itself.
-  if (PartitionIndex == 0)
-    return V;
-  const ValueToValueMapTy *VMap = getPartitionValueMap(PartitionIndex);
-  if (!VMap)
-    return nullptr;
-  return VMap->lookup(V);
-}
-
-// Find the induction variable and the latch operand it is compared against;
-// returns the induction's add-recurrence, or null if the loop is unsuitable.
-// On success \p LatchIndOperand is set to the compared induction operand.
-static const SCEVAddRecExpr *analyzeInduction(Loop *L, ScalarEvolution *SE,
-                                              Value *&LatchIndOperand) {
-  ICmpInst *LatchCmp = L->getLatchCmpInst();
-
-  // SCEV's induction variable, restricted to a unit-step affine recurrence.
-  PHINode *Induction = L->getInductionVariable(*SE);
-  if (!Induction)
-    return nullptr;
-  const SCEV *IndSCEV = SE->getSCEV(Induction);
-  // Match an affine add-recurrence and capture its constant step; accept a unit
-  // step in either direction: +1 (ascending) or -1 (descending).
-  const APInt *Step;
-  if (!match(IndSCEV, m_scev_AffineAddRec(m_SCEV(), m_scev_APInt(Step))))
-    return nullptr;
-  if (!Step->isOne() && !Step->isAllOnes())
-    return nullptr;
-  const auto *AR = cast<SCEVAddRecExpr>(IndSCEV);
-
-  // The induction's "next" value (i + 1), produced in the latch.
-  auto *StepInst = dyn_cast<Instruction>(
-      Induction->getIncomingValueForBlock(L->getLoopLatch()));
-  if (!StepInst)
-    return nullptr;
-
-  // Select the compare operand that is the induction (PHI or its step).
-  if (LatchCmp->getOperand(0) == Induction ||
-      LatchCmp->getOperand(0) == StepInst)
-    LatchIndOperand = LatchCmp->getOperand(0);
-  else if (LatchCmp->getOperand(1) == Induction ||
-           LatchCmp->getOperand(1) == StepInst)
-    LatchIndOperand = LatchCmp->getOperand(1);
-  else
-    return nullptr;
-  return AR;
-}
-
-// Decide whether the iteration ordering is signed or unsigned; returns the
-// signedness, or nullopt if it cannot be proven.
-static std::optional<bool> computeSignedness(Loop *L,
-                                             const SCEVAddRecExpr *IndAR) {
-  ICmpInst::Predicate P = L->getLatchCmpInst()->getPredicate();
-  // A relational predicate gives the ordering directly; for eq/ne fall back to
-  // the recurrence's no-wrap flags.
-  if (ICmpInst::isRelational(P))
-    return ICmpInst::isSigned(P);
-  if (IndAR->hasNoSignedWrap())
-    return true;
-  if (IndAR->hasNoUnsignedWrap())
-    return false;
-  LLVM_DEBUG(dbgs() << DEBUG_TYPE
-             ": cannot prove iteration ordering signedness\n");
-  return std::nullopt;
-}
-
-// Check every structural precondition and record the induction analysis.
-bool LoopSplitUtils::isLegal() {
-  // Require a bottom-tested single-exit loop in LCSSA form with a preheader.
-  if (!L->getLoopPreheader() ...
[truncated]

``````````

</details>


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


More information about the llvm-commits mailing list