Skip to content

Commit b37419e

Browse files
author
Max Kazantsev
committed
[SCEV] Prohibit SCEV transformations for huge SCEVs
Currently SCEV attempts to limit transformations so that they do not work with big SCEVs (that may take almost infinite compile time). But for this, it uses heuristics such as recursion depth and number of operands, which do not give us a guarantee that we don't actually have big SCEVs. This situation is still possible, though it is not likely to happen. However, the bug PR33494 showed a bunch of simple corner case tests where we still produce huge SCEVs, even not reaching big recursion depth etc. This patch introduces a concept of 'huge' SCEVs. A SCEV is huge if its expression size (intoduced in D35989) exceeds some threshold value. We prohibit optimizing transformations if any of SCEVs we are dealing with is huge. This gives us a reliable check that we don't spend too much time working with them. As the next step, we can possibly get rid of old limiting mechanisms, such as recursion depth thresholds. Differential Revision: https://reviews.llvm.org/D35990 Reviewed By: reames llvm-svn: 352728
1 parent 108b892 commit b37419e

File tree

3 files changed

+62
-4
lines changed

3 files changed

+62
-4
lines changed

llvm/lib/Analysis/ScalarEvolution.cpp

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,11 @@ static cl::opt<unsigned>
211211
cl::desc("Max coefficients in AddRec during evolving"),
212212
cl::init(8));
213213

214+
static cl::opt<unsigned>
215+
HugeExprThreshold("scalar-evolution-huge-expr-threshold", cl::Hidden,
216+
cl::desc("Size of the expression which is considered huge"),
217+
cl::init(4096));
218+
214219
//===----------------------------------------------------------------------===//
215220
// SCEV class definitions
216221
//===----------------------------------------------------------------------===//
@@ -845,6 +850,17 @@ static inline int sizeOfSCEV(const SCEV *S) {
845850
return F.Size;
846851
}
847852

853+
/// Returns true if the subtree of \p S contains at least HugeExprThreshold
854+
/// nodes.
855+
static bool isHugeExpression(const SCEV *S) {
856+
return S->getExpressionSize() >= HugeExprThreshold;
857+
}
858+
859+
/// Returns true of \p Ops contains a huge SCEV (see definition above).
860+
static bool hasHugeExpression(ArrayRef<const SCEV *> Ops) {
861+
return any_of(Ops, isHugeExpression);
862+
}
863+
848864
namespace {
849865

850866
struct SCEVDivision : public SCEVVisitor<SCEVDivision, void> {
@@ -2404,7 +2420,7 @@ const SCEV *ScalarEvolution::getAddExpr(SmallVectorImpl<const SCEV *> &Ops,
24042420
}
24052421

24062422
// Limit recursion calls depth.
2407-
if (Depth > MaxArithDepth)
2423+
if (Depth > MaxArithDepth || hasHugeExpression(Ops))
24082424
return getOrCreateAddExpr(Ops, Flags);
24092425

24102426
// Okay, check to see if the same value occurs in the operand list more than
@@ -2883,7 +2899,7 @@ const SCEV *ScalarEvolution::getMulExpr(SmallVectorImpl<const SCEV *> &Ops,
28832899
Flags = StrengthenNoWrapFlags(this, scMulExpr, Ops, Flags);
28842900

28852901
// Limit recursion calls depth.
2886-
if (Depth > MaxArithDepth)
2902+
if (Depth > MaxArithDepth || hasHugeExpression(Ops))
28872903
return getOrCreateMulExpr(Ops, Flags);
28882904

28892905
// If there are any constants, fold them together.
@@ -3056,7 +3072,8 @@ const SCEV *ScalarEvolution::getMulExpr(SmallVectorImpl<const SCEV *> &Ops,
30563072
// Limit max number of arguments to avoid creation of unreasonably big
30573073
// SCEVAddRecs with very complex operands.
30583074
if (AddRec->getNumOperands() + OtherAddRec->getNumOperands() - 1 >
3059-
MaxAddRecSize)
3075+
MaxAddRecSize || isHugeExpression(AddRec) ||
3076+
isHugeExpression(OtherAddRec))
30603077
continue;
30613078

30623079
bool Overflow = false;
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py
2+
; RUN: opt < %s -analyze -scalar-evolution -scalar-evolution-huge-expr-threshold=1 | FileCheck %s
3+
4+
define void @test(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f) {
5+
; CHECK-LABEL: 'test'
6+
; CHECK-NEXT: Classifying expressions for: @test
7+
; CHECK-NEXT: %add1 = add i32 %a, %b
8+
; CHECK-NEXT: --> (%a + %b) U: full-set S: full-set
9+
; CHECK-NEXT: %add2 = add i32 %add1, %c
10+
; CHECK-NEXT: --> ((%a + %b) + %c) U: full-set S: full-set
11+
; CHECK-NEXT: %add3 = add i32 %add2, %d
12+
; CHECK-NEXT: --> (((%a + %b) + %c) + %d) U: full-set S: full-set
13+
; CHECK-NEXT: %add4 = add i32 %add3, %e
14+
; CHECK-NEXT: --> ((((%a + %b) + %c) + %d) + %e) U: full-set S: full-set
15+
; CHECK-NEXT: %add5 = add i32 %add4, %f
16+
; CHECK-NEXT: --> (((((%a + %b) + %c) + %d) + %e) + %f) U: full-set S: full-set
17+
; CHECK-NEXT: %mul1 = mul i32 %a, %b
18+
; CHECK-NEXT: --> (%a * %b) U: full-set S: full-set
19+
; CHECK-NEXT: %mul2 = mul i32 %mul1, %c
20+
; CHECK-NEXT: --> ((%a * %b) * %c) U: full-set S: full-set
21+
; CHECK-NEXT: %mul3 = mul i32 %mul2, %d
22+
; CHECK-NEXT: --> (((%a * %b) * %c) * %d) U: full-set S: full-set
23+
; CHECK-NEXT: %mul4 = mul i32 %mul3, %e
24+
; CHECK-NEXT: --> ((((%a * %b) * %c) * %d) * %e) U: full-set S: full-set
25+
; CHECK-NEXT: %mul5 = mul i32 %mul4, %f
26+
; CHECK-NEXT: --> (((((%a * %b) * %c) * %d) * %e) * %f) U: full-set S: full-set
27+
; CHECK-NEXT: Determining loop execution counts for: @test
28+
;
29+
%add1 = add i32 %a, %b
30+
%add2 = add i32 %add1, %c
31+
%add3 = add i32 %add2, %d
32+
%add4 = add i32 %add3, %e
33+
%add5 = add i32 %add4, %f
34+
35+
%mul1 = mul i32 %a, %b
36+
%mul2 = mul i32 %mul1, %c
37+
%mul3 = mul i32 %mul2, %d
38+
%mul4 = mul i32 %mul3, %e
39+
%mul5 = mul i32 %mul4, %f
40+
ret void
41+
}

llvm/test/Transforms/LoopStrengthReduce/X86/bin_power.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
; RUN: opt < %s -loop-reduce -S | FileCheck %s
1+
; RUN: opt < %s -scalar-evolution-huge-expr-threshold=1000000 -loop-reduce -S | FileCheck %s
22

33
target datalayout = "e-m:e-i32:64-f80:128-n8:16:32:64-S128"
44
target triple = "x86_64-unknown-linux-gnu"

0 commit comments

Comments
 (0)