Skip to content

Commit ab90d29

Browse files
krystian-andrzejewskiigcbot
authored andcommitted
Extend support for creating SCEVs iteratively
This change is to avoid stack overflow issues related to creating scalar evolution expressions. The previous solution can lead to unintended scenarios when building an expression chain requires to use a recursive approach extensively. Moreover, there is an improvement in the quality of these expressions because of creating a final expression of the phi instruction only in the recursive function.
1 parent b81c88a commit ab90d29

File tree

2 files changed

+238
-95
lines changed

2 files changed

+238
-95
lines changed
Lines changed: 147 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*========================== begin_copyright_notice ============================
22

3-
Copyright (C) 2023 Intel Corporation
3+
Copyright (C) 2023-2024 Intel Corporation
44

55
SPDX-License-Identifier: MIT
66

@@ -14,84 +14,175 @@ SPDX-License-Identifier: Apache-2.0 with LLVM-exception
1414

1515
============================= end_copyright_notice ===========================*/
1616

17-
# TODO: Once upstreamed, update with LLORG revision & adjust per community review
18-
19-
diff -Naur "a/llvm/include/llvm/Analysis/ScalarEvolution.h" "b/llvm/include/llvm/Analysis/ScalarEvolution.h"
20-
--- "a/llvm/include/llvm/Analysis/ScalarEvolution.h" 2023-09-27 19:27:08.174510600 +0200
21-
+++ "b/llvm/include/llvm/Analysis/ScalarEvolution.h" 2023-09-27 18:41:11.301171800 +0200
22-
@@ -1292,6 +1292,9 @@
23-
/// Mark predicate values currently being processed by isImpliedCond.
24-
SmallPtrSet<const Value *, 6> PendingLoopPredicates;
25-
26-
+ /// Set of Phis processed in createSCEVIter.
27-
+ SmallPtrSet<const PHINode*, 6> PendingPhiSCEVIter;
17+
diff --git a/llvm/include/llvm/Analysis/ScalarEvolution.h b/llvm/include/llvm/Analysis/ScalarEvolution.h
18+
index 51558a37b..a2069980a 100644
19+
--- a/llvm/include/llvm/Analysis/ScalarEvolution.h
20+
+++ b/llvm/include/llvm/Analysis/ScalarEvolution.h
21+
@@ -1613,6 +1613,9 @@ private:
22+
/// Provide the special handling we need to analyze PHI SCEVs.
23+
const SCEV *createNodeForPHI(PHINode *PN);
24+
25+
+ /// Helper function to get a single start and back edge value from a phi node.
26+
+ std::pair<Value*, Value*> getStartAndBackEdgeValues(PHINode *PN);
2827
+
29-
/// Mark SCEVUnknown Phis currently being processed by getRangeRef.
30-
SmallPtrSet<const PHINode *, 6> PendingPhiRanges;
28+
/// Helper function called from createNodeForPHI.
29+
const SCEV *createAddRecFromPHI(PHINode *PN);
30+
31+
diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
32+
index fc9517ebb..facfe1c7d 100644
33+
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
34+
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
35+
@@ -5529,10 +5529,11 @@ const SCEV *ScalarEvolution::createSimpleAffineAddRec(PHINode *PN,
36+
return PHISCEV;
37+
}
38+
39+
-const SCEV *ScalarEvolution::createAddRecFromPHI(PHINode *PN) {
40+
+std::pair<Value *, Value *>
41+
+ScalarEvolution::getStartAndBackEdgeValues(PHINode *PN) {
42+
const Loop *L = LI.getLoopFor(PN->getParent());
43+
if (!L || L->getHeader() != PN->getParent())
44+
- return nullptr;
45+
+ return {};
46+
47+
// The loop may have multiple entrances or multiple exits; we can analyze
48+
// this phi as an addrec if it has a unique entry value and a unique
49+
@@ -5555,10 +5556,18 @@ const SCEV *ScalarEvolution::createAddRecFromPHI(PHINode *PN) {
50+
}
51+
}
52+
if (!BEValueV || !StartValueV)
53+
- return nullptr;
54+
+ return {};
55+
+ return {StartValueV, BEValueV};
56+
+}
3157

32-
diff -Naur "a/llvm/lib/Analysis/ScalarEvolution.cpp" "b/llvm/lib/Analysis/ScalarEvolution.cpp"
33-
--- "a/llvm/lib/Analysis/ScalarEvolution.cpp" 2023-09-27 19:27:08.189098000 +0200
34-
+++ "b/llvm/lib/Analysis/ScalarEvolution.cpp" 2023-09-27 19:05:40.601713600 +0200
35-
@@ -7004,6 +7004,13 @@
58+
- assert(ValueExprMap.find_as(PN) == ValueExprMap.end() &&
59+
- "PHI node already processed?");
60+
+const SCEV *ScalarEvolution::createAddRecFromPHI(PHINode *PN) {
61+
+ // The loop may have multiple entrances or multiple exits; we can analyze
62+
+ // this phi as an addrec if it has a unique entry value and a unique
63+
+ // backedge value.
64+
+ std::pair<Value *, Value *> StartAndBEValueV = getStartAndBackEdgeValues(PN);
65+
+ Value *BEValueV = StartAndBEValueV.second, *StartValueV = StartAndBEValueV.first;
66+
+ if (!BEValueV || !StartValueV)
67+
+ return nullptr;
68+
69+
// First, try to find AddRec expression without creating a fictituos symbolic
70+
// value for PN.
71+
@@ -5572,6 +5581,7 @@ const SCEV *ScalarEvolution::createAddRecFromPHI(PHINode *PN) {
72+
// Using this symbolic name for the PHI, analyze the value coming around
73+
// the back-edge.
74+
const SCEV *BEValue = getSCEV(BEValueV);
75+
+ const Loop *L = LI.getLoopFor(PN->getParent());
76+
77+
// NOTE: If BEValue is loop invariant, we know that the PHI node just
78+
// has a special value for the first iteration of the loop.
79+
@@ -5772,8 +5782,15 @@ static bool IsAvailableOnEntry(const Loop *L, DominatorTree &DT, const SCEV *S,
80+
// Try to match a control flow sequence that branches out at BI and merges back
81+
// at Merge into a "C ? LHS : RHS" select pattern. Return true on a successful
82+
// match.
83+
-static bool BrPHIToSelect(DominatorTree &DT, BranchInst *BI, PHINode *Merge,
84+
- Value *&C, Value *&LHS, Value *&RHS) {
85+
+static bool BrPHIToSelect(DominatorTree &DT, PHINode *Merge, Value *&C,
86+
+ Value *&LHS, Value *&RHS) {
87+
+
88+
+ BasicBlock *IDom = DT[Merge->getParent()]->getIDom()->getBlock();
89+
+ assert(IDom && "At least the entry block should dominate PN");
90+
+
91+
+ auto *BI = dyn_cast<BranchInst>(IDom->getTerminator());
92+
+ if (!BI || !BI->isConditional())
93+
+ return false;
94+
C = BI->getCondition();
95+
96+
BasicBlockEdge LeftEdge(BI->getParent(), BI->getSuccessor(0));
97+
@@ -5802,6 +5819,11 @@ static bool BrPHIToSelect(DominatorTree &DT, BranchInst *BI, PHINode *Merge,
98+
return false;
99+
}
100+
101+
+static bool BrPHIToSelect(DominatorTree& DT, PHINode* Merge) {
102+
+ Value *Cond = nullptr, *LHS = nullptr, *RHS = nullptr;
103+
+ return BrPHIToSelect(DT, Merge, Cond, LHS, RHS);
104+
+}
105+
+
106+
const SCEV *ScalarEvolution::createNodeFromSelectLikePHI(PHINode *PN) {
107+
auto IsReachable =
108+
[&](BasicBlock *BB) { return DT.isReachableFromEntry(BB); };
109+
@@ -5824,18 +5846,16 @@ const SCEV *ScalarEvolution::createNodeFromSelectLikePHI(PHINode *PN) {
110+
// V = phi [ %x, %left ], [ %y, %right ]
111+
//
112+
// as "select %cond, %x, %y"
113+
-
114+
- BasicBlock *IDom = DT[PN->getParent()]->getIDom()->getBlock();
115+
- assert(IDom && "At least the entry block should dominate PN");
116+
-
117+
- auto *BI = dyn_cast<BranchInst>(IDom->getTerminator());
118+
Value *Cond = nullptr, *LHS = nullptr, *RHS = nullptr;
119+
120+
- if (BI && BI->isConditional() &&
121+
- BrPHIToSelect(DT, BI, PN, Cond, LHS, RHS) &&
122+
+ // do not run over cycled PHIs while processing createNodeFromSelectLikePHI
123+
+ const SCEV* S = nullptr;
124+
+ if (BrPHIToSelect(DT, PN, Cond, LHS, RHS) &&
125+
IsAvailableOnEntry(L, DT, getSCEV(LHS), PN->getParent()) &&
126+
- IsAvailableOnEntry(L, DT, getSCEV(RHS), PN->getParent()))
127+
- return createNodeForSelectOrPHI(PN, Cond, LHS, RHS);
128+
+ IsAvailableOnEntry(L, DT, getSCEV(RHS), PN->getParent())) {
129+
+ S = createNodeForSelectOrPHI(PN, Cond, LHS, RHS);
130+
+ }
131+
+ return S;
132+
}
133+
134+
return nullptr;
135+
@@ -7004,6 +7024,7 @@ const SCEV *ScalarEvolution::createSCEVIter(Value *V) {
36136

37137
Stack.emplace_back(V, true);
38138
Stack.emplace_back(V, false);
39-
+
40-
+ if (isa<PHINode>(V) &&
41-
+ !PendingPhiSCEVIter.insert(cast<PHINode>(V)).second) {
42-
+ // cycled back to createSCEVIter while processing this Phi, bail
43-
+ return getUnknown(V);
44-
+ }
45139
+
46140
while (!Stack.empty()) {
47141
auto E = Stack.pop_back_val();
48142
Value *CurV = E.getPointer();
49-
@@ -7016,6 +7023,10 @@
50-
// If all operands have been visited already, create the SCEV.
51-
if (E.getInt()) {
52-
CreatedSCEV = createSCEV(CurV);
53-
+ } else if (isa<PHINode>(CurV) &&
54-
+ PendingPhiSCEVIter.count(cast<PHINode>(CurV)) > 0) {
55-
+ // cycled Phi, try to get its SCEV
56-
+ CreatedSCEV = createSCEV(CurV);
57-
} else {
58-
// Otherwise get the operands we need to create SCEV's for before creating
59-
// the SCEV for CurV. If the SCEV for CurV can be constructed trivially,
60-
@@ -7025,12 +7036,17 @@
61-
62-
if (CreatedSCEV) {
143+
@@ -7023,14 +7044,15 @@ const SCEV *ScalarEvolution::createSCEVIter(Value *V) {
144+
CreatedSCEV = getOperandsToCreate(CurV, Ops);
145+
}
146+
147+
- if (CreatedSCEV) {
148+
+ if (CreatedSCEV)
63149
insertValueToMap(CurV, CreatedSCEV);
64-
+ if (isa<PHINode>(CurV))
65-
+ PendingPhiSCEVIter.erase(cast<PHINode>(CurV));
66-
} else {
150+
- } else {
151+
+ else {
67152
// Queue CurV for SCEV creation, followed by its's operands which need to
68153
// be constructed first.
69154
Stack.emplace_back(CurV, true);
70155
- for (Value *Op : Ops)
71-
+ if (isa<PHINode>(CurV))
72-
+ PendingPhiSCEVIter.insert(cast<PHINode>(CurV));
73156
+ for (Value *Op : Ops) {
74157
Stack.emplace_back(Op, false);
75158
+ }
76159
}
77160
}
78161

79-
@@ -7153,7 +7169,8 @@
162+
@@ -7152,9 +7174,24 @@ ScalarEvolution::getOperandsToCreate(Value *V, SmallVectorImpl<Value *> &Ops) {
163+
case Instruction::IntToPtr:
80164
return getUnknown(V);
81165

82-
case Instruction::PHI:
166+
- case Instruction::PHI:
83167
- // Keep constructing SCEVs' for phis recursively for now.
84-
+ for (auto& Op : cast<PHINode>(U)->operands())
85-
+ Ops.push_back(Op);
168+
+ case Instruction::PHI: {
169+
+ PHINode *PN = cast<PHINode>(U);
170+
+
171+
+ if (PN->getNumIncomingValues() == 2) {
172+
+ std::pair<Value *, Value *> StartAndBEValueV =
173+
+ getStartAndBackEdgeValues(PN);
174+
+ if (StartAndBEValueV.first && StartAndBEValueV.second)
175+
+ // resolve recursively - may create cycles
176+
+ return nullptr;
177+
+ else if (BrPHIToSelect(DT, PN))
178+
+ // resolve iteratively - does not create cycles
179+
+ for (auto &Op : PN->operands())
180+
+ Ops.push_back(Op);
181+
+ }
182+
+
183+
+ // resolve iteratively - does not create SCEV cycles (trivially resolved)
86184
return nullptr;
185+
+ }
87186

88187
case Instruction::Select: {
89-
@@ -13405,6 +13422,8 @@
90-
auto ValueIt = ValueExprMap.find_as(ValueAndOffset.first);
91-
if (ValueIt != ValueExprMap.end())
92-
ValueExprMap.erase(ValueIt);
93-
+ if (isa<PHINode>(ValueAndOffset.first))
94-
+ PendingPhiSCEVIter.erase(cast<PHINode>(ValueAndOffset.first));
95-
}
96-
}
97-
ExprValueMap.erase(ExprIt);
188+
// Check if U is a select that can be simplified to a SCEVUnknown.
Lines changed: 91 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*========================== begin_copyright_notice ============================
22

3-
Copyright (C) 2023 Intel Corporation
3+
Copyright (C) 2023-2024 Intel Corporation
44

55
SPDX-License-Identifier: MIT
66

@@ -16,43 +16,95 @@ SPDX-License-Identifier: Apache-2.0 with LLVM-exception
1616

1717
# TODO: Once upstreamed, update with LLORG revision & adjust per community review
1818

19-
diff -Naur "a/llvm/include/llvm/Analysis/ScalarEvolution.h" "b/llvm/include/llvm/Analysis/ScalarEvolution.h"
20-
--- "a/llvm/include/llvm/Analysis/ScalarEvolution.h" 2023-12-19 12:51:55.043965800 +0100
21-
+++ "b/llvm/include/llvm/Analysis/ScalarEvolution.h" 2023-12-19 12:28:39.120139600 +0100
22-
@@ -1295,6 +1295,9 @@
23-
/// Set of Phis processed in createSCEVIter.
24-
SmallPtrSet<const PHINode*, 6> PendingPhiSCEVIter;
25-
26-
+ /// Set of Phis processed in createPhiNodeFromSelectLikePHI.
27-
+ SmallPtrSet<const PHINode*, 6> PendingPhiNodeFromSelectLikePHI;
28-
+
29-
/// Mark SCEVUnknown Phis currently being processed by getRangeRef.
30-
SmallPtrSet<const PHINode *, 6> PendingPhiRanges;
31-
32-
diff -Naur "a/llvm/lib/Analysis/ScalarEvolution.cpp" "b/llvm/lib/Analysis/ScalarEvolution.cpp"
33-
--- "a/llvm/lib/Analysis/ScalarEvolution.cpp" 2023-12-19 12:52:55.207074600 +0100
34-
+++ "b/llvm/lib/Analysis/ScalarEvolution.cpp" 2023-12-19 12:37:39.188525900 +0100
35-
@@ -5836,11 +5836,18 @@
36-
auto *BI = dyn_cast<BranchInst>(IDom->getTerminator());
37-
Value *Cond = nullptr, *LHS = nullptr, *RHS = nullptr;
38-
39-
- if (BI && BI->isConditional() &&
40-
- BrPHIToSelect(DT, BI, PN, Cond, LHS, RHS) &&
41-
- IsAvailableOnEntry(L, DT, getSCEV(LHS), PN->getParent()) &&
42-
- IsAvailableOnEntry(L, DT, getSCEV(RHS), PN->getParent()))
43-
- return createNodeForSelectOrPHI(PN, Cond, LHS, RHS);
44-
+ // do not run over cycled PHIs while processing createNodeFromSelectLikePHI
45-
+ if (PendingPhiNodeFromSelectLikePHI.insert(PN).second) {
46-
+ const SCEV* S = nullptr;
47-
+ if (BI && BI->isConditional() &&
48-
+ BrPHIToSelect(DT, BI, PN, Cond, LHS, RHS) &&
49-
+ IsAvailableOnEntry(L, DT, getSCEV(LHS), PN->getParent()) &&
50-
+ IsAvailableOnEntry(L, DT, getSCEV(RHS), PN->getParent())) {
51-
+ S = createNodeForSelectOrPHI(PN, Cond, LHS, RHS);
52-
+ }
53-
+ PendingPhiNodeFromSelectLikePHI.erase(PN);
54-
+ return S;
55-
+ }
19+
diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
20+
index e765a4d54..518683c29 100644
21+
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
22+
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
23+
@@ -5576,12 +5576,14 @@ const SCEV *ScalarEvolution::createAddRecFromPHI(PHINode *PN) {
24+
25+
// First, try to find AddRec expression without creating a fictituos symbolic
26+
// value for PN.
27+
- if (auto *S = createSimpleAffineAddRec(PN, BEValueV, StartValueV))
28+
- return S;
29+
+ // if (auto *S = createSimpleAffineAddRec(PN, BEValueV, StartValueV))
30+
+ // return S;
31+
32+
// Handle PHI node value symbolically.
33+
- const SCEV *SymbolicName = getUnknown(PN);
34+
- insertValueToMap(PN, SymbolicName);
35+
+ // const SCEV *SymbolicName = getUnknown(PN);
36+
+ // insertValueToMap(PN, SymbolicName);
37+
+ const SCEV *SymbolicName = getExistingSCEV(PN);
38+
+ assert(SymbolicName);
39+
40+
// Using this symbolic name for the PHI, analyze the value coming around
41+
// the back-edge.
42+
@@ -5789,6 +5791,8 @@ static bool IsAvailableOnEntry(const Loop *L, DominatorTree &DT, const SCEV *S,
43+
// match.
44+
static bool BrPHIToSelect(DominatorTree &DT, PHINode *Merge, Value *&C,
45+
Value *&LHS, Value *&RHS) {
46+
+ if (Merge->getNumIncomingValues() != 2)
47+
+ return false;
48+
49+
BasicBlock *IDom = DT[Merge->getParent()]->getIDom()->getBlock();
50+
assert(IDom && "At least the entry block should dominate PN");
51+
@@ -7094,14 +7098,13 @@ const SCEV *ScalarEvolution::createSCEVIter(Value *V) {
52+
using PointerTy = PointerIntPair<Value *, 1, bool>;
53+
SmallVector<PointerTy> Stack;
54+
55+
- Stack.emplace_back(V, true);
56+
Stack.emplace_back(V, false);
57+
58+
while (!Stack.empty()) {
59+
auto E = Stack.pop_back_val();
60+
Value *CurV = E.getPointer();
61+
62+
- if (getExistingSCEV(CurV))
63+
+ if (getExistingSCEV(CurV) && !E.getInt())
64+
continue;
65+
66+
SmallVector<Value *> Ops;
67+
@@ -7118,7 +7121,7 @@ const SCEV *ScalarEvolution::createSCEVIter(Value *V) {
68+
69+
if (CreatedSCEV)
70+
insertValueToMap(CurV, CreatedSCEV);
71+
- else {
72+
+ if (!Ops.empty() || !CreatedSCEV) {
73+
// Queue CurV for SCEV creation, followed by its's operands which need to
74+
// be constructed first.
75+
Stack.emplace_back(CurV, true);
76+
@@ -7248,21 +7251,19 @@ ScalarEvolution::getOperandsToCreate(Value *V, SmallVectorImpl<Value *> &Ops) {
77+
78+
case Instruction::PHI: {
79+
PHINode *PN = cast<PHINode>(U);
80+
-
81+
- if (PN->getNumIncomingValues() == 2) {
82+
- std::pair<Value *, Value *> StartAndBEValueV =
83+
- getStartAndBackEdgeValues(PN);
84+
- if (StartAndBEValueV.first && StartAndBEValueV.second)
85+
- // resolve recursively - may create cycles
86+
- return nullptr;
87+
- else if (BrPHIToSelect(DT, PN))
88+
- // resolve iteratively - does not create cycles
89+
- for (auto &Op : PN->operands())
90+
- Ops.push_back(Op);
91+
- }
92+
-
93+
- // resolve iteratively - does not create SCEV cycles (trivially resolved)
94+
- return nullptr;
95+
+ // This phi's operands must be attached due to range computations even if it is redundant
96+
+ // to determine its SCEV expression.
97+
+ for (auto &Op : PN->operands())
98+
+ Ops.push_back(Op);
99+
+ if (BrPHIToSelect(DT, PN))
100+
+ // This phi instruction might be classified as a phi-like-select expression.
101+
+ // Any initial definition cannot be applied since this pattern doesn't support
102+
+ // such a path as dedicated to addrec expressions.
103+
+ return nullptr;
104+
+ // This phi instruction is initially defined as undefined and can be replaced
105+
+ // with an addrec expression if it meets requirements. Otherwise,
106+
+ // this will be preserved.
107+
+ return getUnknown(V);
56108
}
57109

58-
return nullptr;
110+
case Instruction::Select: {

0 commit comments

Comments
 (0)