[SCEV] Directly form add recurrences for simple pointer IVs. - #222915
[SCEV] Directly form add recurrences for simple pointer IVs.#222915fhahn wants to merge 2 commits into
Conversation
Add support for PN = PHI(Start, gep Self, LoopInvariant) to createSimpleAffineAddRec. This allows to handle simple pointer IVs without going through the more expensive createAddRecFromPHI machinery in many cases. This is not completely NFC: previously we created SCEVUnknown for a trivial AddRec with step 0, now we return the start value. This gives a modest geomean compile-time decrease * stage1-O3: -0.05% * stage1-ReleaseThinLTO: -0.06% * stage1-ReleaseLTO-g: -0.06% * stage1-aarch64-O3: -0.07% * stage2-O3: -0.05% * clang build: -0.08% With larger decreases for more SCEV-heavy workloads. https://llvm-compile-time-tracker.com/compare.php?from=c1b661fde124399f0484c4b39501b37613cc4757&to=5cd19e23596c86eae9607286efe86b7a3e885a86&stat=instructions:u
|
@llvm/pr-subscribers-llvm-analysis Author: Florian Hahn (fhahn) ChangesAdd support for PN = PHI(Start, gep Self, LoopInvariant) to This allows to handle simple pointer IVs without going through the more This is not completely NFC: previously we created SCEVUnknown for a This gives a modest geomean compile-time decrease
With larger decreases for more SCEV-heavy workloads. Patch is 22.35 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/222915.diff 2 Files Affected:
diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index 06f350fd2179b..810fc9573e310 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -5693,6 +5693,24 @@ bool PredicatedScalarEvolution::areAddRecsEqualWithPreds(
return true;
}
+static SCEV::NoWrapFlags
+getNoWrapFlagsForGEP(GEPOperator *GEP, const SCEV *Accum, ScalarEvolution &SE) {
+ SCEV::NoWrapFlags Flags = SCEV::FlagAnyWrap;
+ GEPNoWrapFlags NW = GEP->getNoWrapFlags();
+ // If the increment has any nowrap flags, then we know the address
+ // space cannot be wrapped around.
+ if (NW != GEPNoWrapFlags::none())
+ Flags = ScalarEvolution::setFlags(Flags, SCEV::FlagNW);
+ // If the GEP is nuw or nusw with non-negative offset, we know that
+ // no unsigned wrap occurs. We cannot set the nsw flag as only the
+ // offset is treated as signed, while the base is unsigned.
+ if (NW.hasNoUnsignedWrap() ||
+ (NW.hasNoUnsignedSignedWrap() && SE.isKnownNonNegative(Accum)))
+ Flags = ScalarEvolution::setFlags(Flags, SCEV::FlagNUW);
+
+ return Flags;
+}
+
/// A helper function for createAddRecFromPHI to handle simple cases.
///
/// This function tries to find an AddRec expression for the simplest (yet most
@@ -5706,27 +5724,39 @@ const SCEV *ScalarEvolution::createSimpleAffineAddRec(PHINode *PN,
assert(L && L->getHeader() == PN->getParent());
assert(BEValueV && StartValueV);
- auto BO = MatchBinaryOp(BEValueV, getDataLayout(), AC, DT, PN);
- if (!BO)
- return nullptr;
+ const SCEV *Accum = nullptr;
+ SCEV::NoWrapFlags Flags = SCEV::FlagAnyWrap;
+ if (auto BO = MatchBinaryOp(BEValueV, getDataLayout(), AC, DT, PN)) {
+ if (BO->Opcode != Instruction::Add)
+ return nullptr;
- if (BO->Opcode != Instruction::Add)
- return nullptr;
+ if (BO->LHS == PN && L->isLoopInvariant(BO->RHS))
+ Accum = getSCEV(BO->RHS);
+ else if (BO->RHS == PN && L->isLoopInvariant(BO->LHS))
+ Accum = getSCEV(BO->LHS);
- const SCEV *Accum = nullptr;
- if (BO->LHS == PN && L->isLoopInvariant(BO->RHS))
- Accum = getSCEV(BO->RHS);
- else if (BO->RHS == PN && L->isLoopInvariant(BO->LHS))
- Accum = getSCEV(BO->LHS);
+ if (!Accum)
+ return nullptr;
- if (!Accum)
- return nullptr;
+ if (BO->IsNUW)
+ Flags = setFlags(Flags, SCEV::FlagNUW);
+ if (BO->IsNSW)
+ Flags = setFlags(Flags, SCEV::FlagNSW);
+ } else {
+ // Handle pointer induction variable: PN = PHI(Start, gep PN,
+ // LoopInvariant).
+ auto *GEP = dyn_cast<GEPOperator>(BEValueV);
+ if (!GEP || GEP->getPointerOperand() != PN || GEP->getNumIndices() != 1)
+ return nullptr;
+ Value *Idx = *GEP->idx_begin();
+ if (!L->isLoopInvariant(Idx))
+ return nullptr;
- SCEV::NoWrapFlags Flags = SCEV::FlagAnyWrap;
- if (BO->IsNUW)
- Flags = setFlags(Flags, SCEV::FlagNUW);
- if (BO->IsNSW)
- Flags = setFlags(Flags, SCEV::FlagNSW);
+ Type *IntIdxTy = getEffectiveSCEVType(GEP->getType());
+ Accum = getMulExpr(getTruncateOrSignExtend(getSCEV(Idx), IntIdxTy),
+ getSizeOfExpr(IntIdxTy, GEP->getSourceElementType()));
+ Flags = getNoWrapFlagsForGEP(GEP, Accum, *this);
+ }
const SCEV *StartVal = getSCEV(StartValueV);
const SCEV *PHISCEV = getAddRecExpr(StartVal, Accum, L, Flags);
@@ -5832,19 +5862,8 @@ const SCEV *ScalarEvolution::createAddRecFromPHI(PHINode *PN) {
Flags = setFlags(Flags, SCEV::FlagNSW);
}
} else if (GEPOperator *GEP = dyn_cast<GEPOperator>(BEValueV)) {
- if (GEP->getOperand(0) == PN) {
- GEPNoWrapFlags NW = GEP->getNoWrapFlags();
- // If the increment has any nowrap flags, then we know the address
- // space cannot be wrapped around.
- if (NW != GEPNoWrapFlags::none())
- Flags = setFlags(Flags, SCEV::FlagNW);
- // If the GEP is nuw or nusw with non-negative offset, we know that
- // no unsigned wrap occurs. We cannot set the nsw flag as only the
- // offset is treated as signed, while the base is unsigned.
- if (NW.hasNoUnsignedWrap() ||
- (NW.hasNoUnsignedSignedWrap() && isKnownNonNegative(Accum)))
- Flags = setFlags(Flags, SCEV::FlagNUW);
- }
+ if (GEP->getOperand(0) == PN)
+ Flags = getNoWrapFlagsForGEP(GEP, Accum, *this);
// We cannot transfer nuw and nsw flags from subtraction
// operations -- sub nuw X, Y is not the same as add nuw X, -Y
diff --git a/llvm/test/Analysis/ScalarEvolution/pointer-iv-addrec.ll b/llvm/test/Analysis/ScalarEvolution/pointer-iv-addrec.ll
new file mode 100644
index 0000000000000..348260df97839
--- /dev/null
+++ b/llvm/test/Analysis/ScalarEvolution/pointer-iv-addrec.ll
@@ -0,0 +1,343 @@
+; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -passes='print<scalar-evolution>' -disable-output %s 2>&1 | FileCheck %s
+
+target datalayout = "e-m:e-p:64:64-p1:32:32-i64:64-n32:64"
+
+%struct.S = type { i32, i64 }
+
+define void @gep_iv_constant_step(ptr %p, i64 %n) {
+; CHECK-LABEL: 'gep_iv_constant_step'
+; CHECK-NEXT: Classifying expressions for: @gep_iv_constant_step
+; CHECK-NEXT: %iv = phi ptr [ %p, %entry ], [ %iv.next, %loop ]
+; CHECK-NEXT: --> {%p,+,4}<nuw><%loop> U: full-set S: full-set Exits: (-4 + (4 * %n) + %p) LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: %i = phi i64 [ 0, %entry ], [ %i.next, %loop ]
+; CHECK-NEXT: --> {0,+,1}<nuw><nsw><%loop> U: [0,-9223372036854775808) S: [0,-9223372036854775808) Exits: (-1 + %n) LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: %iv.next = getelementptr inbounds i32, ptr %iv, i64 1
+; CHECK-NEXT: --> {(4 + %p),+,4}<nw><%loop> U: full-set S: full-set Exits: ((4 * %n) + %p) LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: %i.next = add nuw nsw i64 %i, 1
+; CHECK-NEXT: --> {1,+,1}<nuw><nsw><%loop> U: [1,-9223372036854775808) S: [1,-9223372036854775808) Exits: %n LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: Determining loop execution counts for: @gep_iv_constant_step
+; CHECK-NEXT: Loop %loop: backedge-taken count is (-1 + %n)
+; CHECK-NEXT: Loop %loop: constant max backedge-taken count is i64 -1
+; CHECK-NEXT: Loop %loop: symbolic max backedge-taken count is (-1 + %n)
+; CHECK-NEXT: Loop %loop: Trip multiple is 1
+;
+entry:
+ br label %loop
+
+loop:
+ %iv = phi ptr [ %p, %entry ], [ %iv.next, %loop ]
+ %i = phi i64 [ 0, %entry ], [ %i.next, %loop ]
+ %iv.next = getelementptr inbounds i32, ptr %iv, i64 1
+ %i.next = add nuw nsw i64 %i, 1
+ store i32 0, ptr %iv, align 4
+ %ec = icmp eq i64 %i.next, %n
+ br i1 %ec, label %exit, label %loop
+
+exit:
+ ret void
+}
+
+define void @gep_iv_invariant_step(ptr %p, i64 %step, i64 %n) {
+; CHECK-LABEL: 'gep_iv_invariant_step'
+; CHECK-NEXT: Classifying expressions for: @gep_iv_invariant_step
+; CHECK-NEXT: %iv = phi ptr [ %p, %entry ], [ %iv.next, %loop ]
+; CHECK-NEXT: --> {%p,+,%step}<%loop> U: full-set S: full-set Exits: (((-1 + %n) * %step) + %p) LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: %i = phi i64 [ 0, %entry ], [ %i.next, %loop ]
+; CHECK-NEXT: --> {0,+,1}<nuw><nsw><%loop> U: [0,-9223372036854775808) S: [0,-9223372036854775808) Exits: (-1 + %n) LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: %iv.next = getelementptr i8, ptr %iv, i64 %step
+; CHECK-NEXT: --> {(%step + %p),+,%step}<%loop> U: full-set S: full-set Exits: ((%step * %n) + %p) LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: %i.next = add nuw nsw i64 %i, 1
+; CHECK-NEXT: --> {1,+,1}<nuw><nsw><%loop> U: [1,-9223372036854775808) S: [1,-9223372036854775808) Exits: %n LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: Determining loop execution counts for: @gep_iv_invariant_step
+; CHECK-NEXT: Loop %loop: backedge-taken count is (-1 + %n)
+; CHECK-NEXT: Loop %loop: constant max backedge-taken count is i64 -1
+; CHECK-NEXT: Loop %loop: symbolic max backedge-taken count is (-1 + %n)
+; CHECK-NEXT: Loop %loop: Trip multiple is 1
+;
+entry:
+ br label %loop
+
+loop:
+ %iv = phi ptr [ %p, %entry ], [ %iv.next, %loop ]
+ %i = phi i64 [ 0, %entry ], [ %i.next, %loop ]
+ %iv.next = getelementptr i8, ptr %iv, i64 %step
+ %i.next = add nuw nsw i64 %i, 1
+ store i32 0, ptr %iv, align 4
+ %ec = icmp eq i64 %i.next, %n
+ br i1 %ec, label %exit, label %loop
+
+exit:
+ ret void
+}
+
+; The offset may be negative, so only nw can be derived from nusw.
+define void @gep_iv_nusw_negative_step(ptr %p, i64 %n) {
+; CHECK-LABEL: 'gep_iv_nusw_negative_step'
+; CHECK-NEXT: Classifying expressions for: @gep_iv_nusw_negative_step
+; CHECK-NEXT: %iv = phi ptr [ %p, %entry ], [ %iv.next, %loop ]
+; CHECK-NEXT: --> {%p,+,-4}<nw><%loop> U: full-set S: full-set Exits: (4 + (-4 * %n) + %p) LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: %i = phi i64 [ 0, %entry ], [ %i.next, %loop ]
+; CHECK-NEXT: --> {0,+,1}<nuw><nsw><%loop> U: [0,-9223372036854775808) S: [0,-9223372036854775808) Exits: (-1 + %n) LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: %iv.next = getelementptr nusw i32, ptr %iv, i64 -1
+; CHECK-NEXT: --> {(-4 + %p),+,-4}<nw><%loop> U: full-set S: full-set Exits: ((-4 * %n) + %p) LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: %i.next = add nuw nsw i64 %i, 1
+; CHECK-NEXT: --> {1,+,1}<nuw><nsw><%loop> U: [1,-9223372036854775808) S: [1,-9223372036854775808) Exits: %n LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: Determining loop execution counts for: @gep_iv_nusw_negative_step
+; CHECK-NEXT: Loop %loop: backedge-taken count is (-1 + %n)
+; CHECK-NEXT: Loop %loop: constant max backedge-taken count is i64 -1
+; CHECK-NEXT: Loop %loop: symbolic max backedge-taken count is (-1 + %n)
+; CHECK-NEXT: Loop %loop: Trip multiple is 1
+;
+entry:
+ br label %loop
+
+loop:
+ %iv = phi ptr [ %p, %entry ], [ %iv.next, %loop ]
+ %i = phi i64 [ 0, %entry ], [ %i.next, %loop ]
+ %iv.next = getelementptr nusw i32, ptr %iv, i64 -1
+ %i.next = add nuw nsw i64 %i, 1
+ store i32 0, ptr %iv, align 4
+ %ec = icmp eq i64 %i.next, %n
+ br i1 %ec, label %exit, label %loop
+
+exit:
+ ret void
+}
+
+; The index is wider than the index type of the address space, so it is
+; truncated before scaling.
+define void @gep_iv_narrow_index_type(ptr addrspace(1) %p, i64 %step, i64 %n) {
+; CHECK-LABEL: 'gep_iv_narrow_index_type'
+; CHECK-NEXT: Classifying expressions for: @gep_iv_narrow_index_type
+; CHECK-NEXT: %iv = phi ptr addrspace(1) [ %p, %entry ], [ %iv.next, %loop ]
+; CHECK-NEXT: --> {%p,+,(4 * (trunc i64 %step to i32))}<nw><%loop> U: full-set S: full-set Exits: ((4 * (trunc i64 %step to i32) * (-1 + (trunc i64 %n to i32))) + %p) LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: %i = phi i64 [ 0, %entry ], [ %i.next, %loop ]
+; CHECK-NEXT: --> {0,+,1}<nuw><nsw><%loop> U: [0,-9223372036854775808) S: [0,-9223372036854775808) Exits: (-1 + %n) LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: %iv.next = getelementptr inbounds i32, ptr addrspace(1) %iv, i64 %step
+; CHECK-NEXT: --> {((4 * (trunc i64 %step to i32)) + %p),+,(4 * (trunc i64 %step to i32))}<nw><%loop> U: full-set S: full-set Exits: ((4 * (trunc i64 %step to i32) * (trunc i64 %n to i32)) + %p) LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: %i.next = add nuw nsw i64 %i, 1
+; CHECK-NEXT: --> {1,+,1}<nuw><nsw><%loop> U: [1,-9223372036854775808) S: [1,-9223372036854775808) Exits: %n LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: Determining loop execution counts for: @gep_iv_narrow_index_type
+; CHECK-NEXT: Loop %loop: backedge-taken count is (-1 + %n)
+; CHECK-NEXT: Loop %loop: constant max backedge-taken count is i64 -1
+; CHECK-NEXT: Loop %loop: symbolic max backedge-taken count is (-1 + %n)
+; CHECK-NEXT: Loop %loop: Trip multiple is 1
+;
+entry:
+ br label %loop
+
+loop:
+ %iv = phi ptr addrspace(1) [ %p, %entry ], [ %iv.next, %loop ]
+ %i = phi i64 [ 0, %entry ], [ %i.next, %loop ]
+ %iv.next = getelementptr inbounds i32, ptr addrspace(1) %iv, i64 %step
+ %i.next = add nuw nsw i64 %i, 1
+ store i32 0, ptr addrspace(1) %iv, align 4
+ %ec = icmp eq i64 %i.next, %n
+ br i1 %ec, label %exit, label %loop
+
+exit:
+ ret void
+}
+
+define void @gep_iv_scalable(ptr %p, i64 %n) {
+; CHECK-LABEL: 'gep_iv_scalable'
+; CHECK-NEXT: Classifying expressions for: @gep_iv_scalable
+; CHECK-NEXT: %iv = phi ptr [ %p, %entry ], [ %iv.next, %loop ]
+; CHECK-NEXT: --> {%p,+,(16 * vscale)}<%loop> U: full-set S: full-set Exits: ((16 * vscale * (-1 + %n)) + %p) LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: %i = phi i64 [ 0, %entry ], [ %i.next, %loop ]
+; CHECK-NEXT: --> {0,+,1}<nuw><nsw><%loop> U: [0,-9223372036854775808) S: [0,-9223372036854775808) Exits: (-1 + %n) LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: %iv.next = getelementptr <vscale x 4 x i32>, ptr %iv, i64 1
+; CHECK-NEXT: --> {((16 * vscale) + %p),+,(16 * vscale)}<%loop> U: full-set S: full-set Exits: ((16 * vscale * %n) + %p) LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: %i.next = add nuw nsw i64 %i, 1
+; CHECK-NEXT: --> {1,+,1}<nuw><nsw><%loop> U: [1,-9223372036854775808) S: [1,-9223372036854775808) Exits: %n LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: Determining loop execution counts for: @gep_iv_scalable
+; CHECK-NEXT: Loop %loop: backedge-taken count is (-1 + %n)
+; CHECK-NEXT: Loop %loop: constant max backedge-taken count is i64 -1
+; CHECK-NEXT: Loop %loop: symbolic max backedge-taken count is (-1 + %n)
+; CHECK-NEXT: Loop %loop: Trip multiple is 1
+;
+entry:
+ br label %loop
+
+loop:
+ %iv = phi ptr [ %p, %entry ], [ %iv.next, %loop ]
+ %i = phi i64 [ 0, %entry ], [ %i.next, %loop ]
+ %iv.next = getelementptr <vscale x 4 x i32>, ptr %iv, i64 1
+ %i.next = add nuw nsw i64 %i, 1
+ store i32 0, ptr %iv, align 4
+ %ec = icmp eq i64 %i.next, %n
+ br i1 %ec, label %exit, label %loop
+
+exit:
+ ret void
+}
+
+define void @gep_iv_struct_single_index(ptr %p, i64 %n) {
+; CHECK-LABEL: 'gep_iv_struct_single_index'
+; CHECK-NEXT: Classifying expressions for: @gep_iv_struct_single_index
+; CHECK-NEXT: %iv = phi ptr [ %p, %entry ], [ %iv.next, %loop ]
+; CHECK-NEXT: --> {%p,+,16}<nuw><%loop> U: full-set S: full-set Exits: (-16 + (16 * %n) + %p) LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: %i = phi i64 [ 0, %entry ], [ %i.next, %loop ]
+; CHECK-NEXT: --> {0,+,1}<nuw><nsw><%loop> U: [0,-9223372036854775808) S: [0,-9223372036854775808) Exits: (-1 + %n) LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: %iv.next = getelementptr inbounds %struct.S, ptr %iv, i64 1
+; CHECK-NEXT: --> {(16 + %p),+,16}<nw><%loop> U: full-set S: full-set Exits: ((16 * %n) + %p) LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: %i.next = add nuw nsw i64 %i, 1
+; CHECK-NEXT: --> {1,+,1}<nuw><nsw><%loop> U: [1,-9223372036854775808) S: [1,-9223372036854775808) Exits: %n LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: Determining loop execution counts for: @gep_iv_struct_single_index
+; CHECK-NEXT: Loop %loop: backedge-taken count is (-1 + %n)
+; CHECK-NEXT: Loop %loop: constant max backedge-taken count is i64 -1
+; CHECK-NEXT: Loop %loop: symbolic max backedge-taken count is (-1 + %n)
+; CHECK-NEXT: Loop %loop: Trip multiple is 1
+;
+entry:
+ br label %loop
+
+loop:
+ %iv = phi ptr [ %p, %entry ], [ %iv.next, %loop ]
+ %i = phi i64 [ 0, %entry ], [ %i.next, %loop ]
+ %iv.next = getelementptr inbounds %struct.S, ptr %iv, i64 1
+ %i.next = add nuw nsw i64 %i, 1
+ store i32 0, ptr %iv, align 4
+ %ec = icmp eq i64 %i.next, %n
+ br i1 %ec, label %exit, label %loop
+
+exit:
+ ret void
+}
+
+; The step is zero, so the PHI is loop-invariant. This is more precise than the
+; general route, which cannot form an add recurrence here.
+define void @gep_iv_zero_step(ptr %p, i64 %n) {
+; CHECK-LABEL: 'gep_iv_zero_step'
+; CHECK-NEXT: Classifying expressions for: @gep_iv_zero_step
+; CHECK-NEXT: %iv = phi ptr [ %p, %entry ], [ %iv.next, %loop ]
+; CHECK-NEXT: --> %p U: full-set S: full-set Exits: %p LoopDispositions: { %loop: Invariant }
+; CHECK-NEXT: %i = phi i64 [ 0, %entry ], [ %i.next, %loop ]
+; CHECK-NEXT: --> {0,+,1}<nuw><nsw><%loop> U: [0,-9223372036854775808) S: [0,-9223372036854775808) Exits: (-1 + %n) LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: %iv.next = getelementptr inbounds i32, ptr %iv, i64 0
+; CHECK-NEXT: --> %p U: full-set S: full-set Exits: %p LoopDispositions: { %loop: Invariant }
+; CHECK-NEXT: %i.next = add nuw nsw i64 %i, 1
+; CHECK-NEXT: --> {1,+,1}<nuw><nsw><%loop> U: [1,-9223372036854775808) S: [1,-9223372036854775808) Exits: %n LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: Determining loop execution counts for: @gep_iv_zero_step
+; CHECK-NEXT: Loop %loop: backedge-taken count is (-1 + %n)
+; CHECK-NEXT: Loop %loop: constant max backedge-taken count is i64 -1
+; CHECK-NEXT: Loop %loop: symbolic max backedge-taken count is (-1 + %n)
+; CHECK-NEXT: Loop %loop: Trip multiple is 1
+;
+entry:
+ br label %loop
+
+loop:
+ %iv = phi ptr [ %p, %entry ], [ %iv.next, %loop ]
+ %i = phi i64 [ 0, %entry ], [ %i.next, %loop ]
+ %iv.next = getelementptr inbounds i32, ptr %iv, i64 0
+ %i.next = add nuw nsw i64 %i, 1
+ store i32 0, ptr %iv, align 4
+ %ec = icmp eq i64 %i.next, %n
+ br i1 %ec, label %exit, label %loop
+
+exit:
+ ret void
+}
+
+; More than one index.
+define void @gep_iv_struct_two_indices(ptr %p, i64 %n) {
+; CHECK-LABEL: 'gep_iv_struct_two_indices'
+; CHECK-NEXT: Classifying expressions for: @gep_iv_struct_two_indices
+; CHECK-NEXT: %iv = phi ptr [ %p, %entry ], [ %iv.next, %loop ]
+; CHECK-NEXT: --> {%p,+,16}<nuw><%loop> U: full-set S: full-set Exits: (-16 + (16 * %n) + %p) LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: %i = phi i64 [ 0, %entry ], [ %i.next, %loop ]
+; CHECK-NEXT: --> {0,+,1}<nuw><nsw><%loop> U: [0,-9223372036854775808) S: [0,-9223372036854775808) Exits: (-1 + %n) LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: %iv.next = getelementptr inbounds %struct.S, ptr %iv, i64 1, i32 0
+; CHECK-NEXT: --> {(16 + %p),+,16}<nw><%loop> U: full-set S: full-set Exits: ((16 * %n) + %p) LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: %i.next = add nuw nsw i64 %i, 1
+; CHECK-NEXT: --> {1,+,1}<nuw><nsw><%loop> U: [1,-9223372036854775808) S: [1,-9223372036854775808) Exits: %n LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: Determining loop execution counts for: @gep_iv_struct_two_indices
+; CHECK-NEXT: Loop %loop: backedge-taken count is (-1 + %n)
+; CHECK-NEXT: Loop %loop: constant max backedge-taken count is i64 -1
+; CHECK-NEXT: Loop %loop: symbolic max backedge-taken count is (-1 + %n)
+; CHECK-NEXT: Loop %loop: Trip multiple is 1
+;
+entry:
+ br label %loop
+
+loop:
+ %iv = phi ptr [ %p, %entry ], [ %iv.next, %loop ]
+ %i = phi i64 [ 0, %entry ], [ %i.next, %loop ]
+ %iv.next = getelementptr inbounds %struct.S, ptr %iv, i64 1, i32 0
+ %i.next = add nuw nsw i64 %i, 1
+ store i32 0, ptr %iv, align 4
+ %ec = icmp eq i64 %i.next, %n
+ br i1 %ec, label %exit, label %loop
+
+exit:
+ ret void
+}
+
+; The index is not loop-invariant.
+define void @gep_iv_variant_step(ptr %p, i64 %n) {
+; CHECK-LABEL: 'gep_iv_variant_step'
+; CHECK-NEXT: Classifying expressions for: @gep_iv_variant_step
+; CHECK-NEXT: %iv = phi ptr [ %p, %entry ], [ %iv.next, %loop ]
+; CHECK-NEXT: --> {%p,+,0,+,1}<%loop> U: full-set S: full-set Exits: ((trunc i65 (((zext i64 (-2 + %n) to i65) * (zext i64 (-1 + %n) to i65)) /u 2) to i64) + %p) LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: %i = phi i64 [ 0, %entry ], [ %i.next, %loop ]
+; CHECK-NEXT: --> {0,+,1}<nuw><nsw><%loop> U: [0,-9223372036854775808) S: [0,-9223372036854775808) Exits: (-1 + %n) LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: %iv.next = getelementptr i8, ptr %iv, i64 %i
+; CHECK-NEXT: --> {%p,+,1,+,1}<%loop> U: full-set S: full-set Exits: (-1 + (trunc i65 (((zext i64 (-2 + %n) to i65) * (zext i64 (-1 + %n) to i65)) /u 2) to i64) + %n + %p) LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: %i.next = add nuw nsw i64 %i, 1
+; CHECK-NEXT: --> {1,+,1}<nuw><nsw><%loop> U: [1,-922...
[truncated]
|
Add support for PN = PHI(Start, gep Self, LoopInvariant) to
createSimpleAffineAddRec.
This allows to handle simple pointer IVs without going through the more
expensive createAddRecFromPHI machinery in many cases.
This is not completely NFC: previously we created SCEVUnknown for a
trivial AddRec with step 0, now we return the start value.
This gives a modest geomean compile-time decrease
With larger decreases for more SCEV-heavy workloads.
https://llvm-compile-time-tracker.com/compare.php?from=c1b661fde124399f0484c4b39501b37613cc4757&to=5cd19e23596c86eae9607286efe86b7a3e885a86&stat=instructions:u