llvm.org GIT mirror llvm / de62d73
[SCEV] Fix exponential time complexity by caching git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@301149 91177308-0d34-0410-b5e6-96231b3b80d8 Sanjoy Das 2 years ago
3 changed file(s) with 161 addition(s) and 19 deletion(s). Raw diff Collapse all Expand all
876876 bool ControlsExit,
877877 bool AllowPredicates = false);
878878
879 // Helper functions for computeExitLimitFromCond to avoid exponential time
880 // complexity.
881
882 class ExitLimitCache {
883 // It may look like we need key on the whole (L, TBB, FBB, ControlsExit,
884 // AllowPredicates) tuple, but recursive calls to
885 // computeExitLimitFromCondCached from computeExitLimitFromCondImpl only
886 // vary the in \c ExitCond and \c ControlsExit parameters. We remember the
887 // initial values of the other values to assert our assumption.
888 SmallDenseMap, ExitLimit> TripCountMap;
889
890 const Loop *L;
891 BasicBlock *TBB;
892 BasicBlock *FBB;
893 bool AllowPredicates;
894
895 public:
896 ExitLimitCache(const Loop *L, BasicBlock *TBB, BasicBlock *FBB,
897 bool AllowPredicates)
898 : L(L), TBB(TBB), FBB(FBB), AllowPredicates(AllowPredicates) {}
899
900 Optional find(const Loop *L, Value *ExitCond, BasicBlock *TBB,
901 BasicBlock *FBB, bool ControlsExit,
902 bool AllowPredicates);
903
904 void insert(const Loop *L, Value *ExitCond, BasicBlock *TBB,
905 BasicBlock *FBB, bool ControlsExit, bool AllowPredicates,
906 const ExitLimit &EL);
907 };
908
909 typedef ExitLimitCache ExitLimitCacheTy;
910 ExitLimit computeExitLimitFromCondCached(ExitLimitCacheTy &Cache,
911 const Loop *L, Value *ExitCond,
912 BasicBlock *TBB, BasicBlock *FBB,
913 bool ControlsExit,
914 bool AllowPredicates);
915 ExitLimit computeExitLimitFromCondImpl(ExitLimitCacheTy &Cache, const Loop *L,
916 Value *ExitCond, BasicBlock *TBB,
917 BasicBlock *FBB, bool ControlsExit,
918 bool AllowPredicates);
919
879920 /// Compute the number of times the backedge of the specified loop will
880921 /// execute if its exit condition were a conditional branch of the ICmpInst
881922 /// ExitCond, TBB, and FBB. If AllowPredicates is set, this call will try
60786078 return getCouldNotCompute();
60796079 }
60806080
6081 ScalarEvolution::ExitLimit
6082 ScalarEvolution::computeExitLimitFromCond(const Loop *L,
6083 Value *ExitCond,
6084 BasicBlock *TBB,
6085 BasicBlock *FBB,
6086 bool ControlsExit,
6087 bool AllowPredicates) {
6081 ScalarEvolution::ExitLimit ScalarEvolution::computeExitLimitFromCond(
6082 const Loop *L, Value *ExitCond, BasicBlock *TBB, BasicBlock *FBB,
6083 bool ControlsExit, bool AllowPredicates) {
6084 ScalarEvolution::ExitLimitCacheTy Cache(L, TBB, FBB, AllowPredicates);
6085 return computeExitLimitFromCondCached(Cache, L, ExitCond, TBB, FBB,
6086 ControlsExit, AllowPredicates);
6087 }
6088
6089 Optional
6090 ScalarEvolution::ExitLimitCache::find(const Loop *L, Value *ExitCond,
6091 BasicBlock *TBB, BasicBlock *FBB,
6092 bool ControlsExit, bool AllowPredicates) {
6093 assert(this->L == L && this->TBB == TBB && this->FBB == FBB &&
6094 this->AllowPredicates == AllowPredicates &&
6095 "Variance in assumed invariant key components!");
6096 auto Itr = TripCountMap.find({ExitCond, ControlsExit});
6097 if (Itr == TripCountMap.end())
6098 return None;
6099 return Itr->second;
6100 }
6101
6102 void ScalarEvolution::ExitLimitCache::insert(const Loop *L, Value *ExitCond,
6103 BasicBlock *TBB, BasicBlock *FBB,
6104 bool ControlsExit,
6105 bool AllowPredicates,
6106 const ExitLimit &EL) {
6107 assert(this->L == L && this->TBB == TBB && this->FBB == FBB &&
6108 this->AllowPredicates == AllowPredicates &&
6109 "Variance in assumed invariant key components!");
6110
6111 auto InsertResult = TripCountMap.insert({{ExitCond, ControlsExit}, EL});
6112 assert(InsertResult.second && "Expected successful insertion!");
6113 }
6114
6115 ScalarEvolution::ExitLimit ScalarEvolution::computeExitLimitFromCondCached(
6116 ExitLimitCacheTy &Cache, const Loop *L, Value *ExitCond, BasicBlock *TBB,
6117 BasicBlock *FBB, bool ControlsExit, bool AllowPredicates) {
6118
6119 if (auto MaybeEL =
6120 Cache.find(L, ExitCond, TBB, FBB, ControlsExit, AllowPredicates))
6121 return *MaybeEL;
6122
6123 ExitLimit EL = computeExitLimitFromCondImpl(Cache, L, ExitCond, TBB, FBB,
6124 ControlsExit, AllowPredicates);
6125 Cache.insert(L, ExitCond, TBB, FBB, ControlsExit, AllowPredicates, EL);
6126 return EL;
6127 }
6128
6129 ScalarEvolution::ExitLimit ScalarEvolution::computeExitLimitFromCondImpl(
6130 ExitLimitCacheTy &Cache, const Loop *L, Value *ExitCond, BasicBlock *TBB,
6131 BasicBlock *FBB, bool ControlsExit, bool AllowPredicates) {
60886132 // Check if the controlling expression for this loop is an And or Or.
60896133 if (BinaryOperator *BO = dyn_cast(ExitCond)) {
60906134 if (BO->getOpcode() == Instruction::And) {
60916135 // Recurse on the operands of the and.
60926136 bool EitherMayExit = L->contains(TBB);
6093 ExitLimit EL0 = computeExitLimitFromCond(L, BO->getOperand(0), TBB, FBB,
6094 ControlsExit && !EitherMayExit,
6095 AllowPredicates);
6096 ExitLimit EL1 = computeExitLimitFromCond(L, BO->getOperand(1), TBB, FBB,
6097 ControlsExit && !EitherMayExit,
6098 AllowPredicates);
6137 ExitLimit EL0 = computeExitLimitFromCondCached(
6138 Cache, L, BO->getOperand(0), TBB, FBB, ControlsExit && !EitherMayExit,
6139 AllowPredicates);
6140 ExitLimit EL1 = computeExitLimitFromCondCached(
6141 Cache, L, BO->getOperand(1), TBB, FBB, ControlsExit && !EitherMayExit,
6142 AllowPredicates);
60996143 const SCEV *BECount = getCouldNotCompute();
61006144 const SCEV *MaxBECount = getCouldNotCompute();
61016145 if (EitherMayExit) {
61396183 if (BO->getOpcode() == Instruction::Or) {
61406184 // Recurse on the operands of the or.
61416185 bool EitherMayExit = L->contains(FBB);
6142 ExitLimit EL0 = computeExitLimitFromCond(L, BO->getOperand(0), TBB, FBB,
6143 ControlsExit && !EitherMayExit,
6144 AllowPredicates);
6145 ExitLimit EL1 = computeExitLimitFromCond(L, BO->getOperand(1), TBB, FBB,
6146 ControlsExit && !EitherMayExit,
6147 AllowPredicates);
6186 ExitLimit EL0 = computeExitLimitFromCondCached(
6187 Cache, L, BO->getOperand(0), TBB, FBB, ControlsExit && !EitherMayExit,
6188 AllowPredicates);
6189 ExitLimit EL1 = computeExitLimitFromCondCached(
6190 Cache, L, BO->getOperand(1), TBB, FBB, ControlsExit && !EitherMayExit,
6191 AllowPredicates);
61486192 const SCEV *BECount = getCouldNotCompute();
61496193 const SCEV *MaxBECount = getCouldNotCompute();
61506194 if (EitherMayExit) {
0 ; RUN: opt -analyze -scalar-evolution < %s | FileCheck %s
1
2 ; CHECK: Printing analysis 'Scalar Evolution Analysis' for function 'f':
3
4 ; CHECK: Loop %loop: Unpredictable backedge-taken count.
5 ; CHECK: Loop %loop: max backedge-taken count is 0
6 ; CHECK: Loop %loop: Unpredictable predicated backedge-taken count.
7
8
9 define void @f(i32 %n, i32* %ptr) {
10 entry:
11 br label %loop
12
13 loop:
14 %iv = phi i32 [ 0, %entry ], [ %iv.inc, %be ]
15 %iv.inc = add i32 %iv, 1
16 %unswitch_cond_root = icmp ne i32 %iv.inc, 42
17 %us.0 = and i1 %unswitch_cond_root, %unswitch_cond_root
18 %us.1 = and i1 %us.0, %us.0
19 %us.2 = and i1 %us.1, %us.1
20 %us.3 = and i1 %us.2, %us.2
21 %us.4 = and i1 %us.3, %us.3
22 %us.5 = and i1 %us.4, %us.4
23 %us.6 = and i1 %us.5, %us.5
24 %us.7 = and i1 %us.6, %us.6
25 %us.8 = and i1 %us.7, %us.7
26 %us.9 = and i1 %us.8, %us.8
27 %us.10 = and i1 %us.9, %us.9
28 %us.11 = and i1 %us.10, %us.10
29 %us.12 = and i1 %us.11, %us.11
30 %us.13 = and i1 %us.12, %us.12
31 %us.14 = and i1 %us.13, %us.13
32 %us.15 = and i1 %us.14, %us.14
33 %us.16 = and i1 %us.15, %us.15
34 %us.17 = and i1 %us.16, %us.16
35 %us.18 = and i1 %us.17, %us.17
36 %us.19 = and i1 %us.18, %us.18
37 %us.20 = and i1 %us.19, %us.19
38 %us.21 = and i1 %us.20, %us.20
39 %us.22 = and i1 %us.21, %us.21
40 %us.23 = and i1 %us.22, %us.22
41 %us.24 = and i1 %us.23, %us.23
42 %us.25 = and i1 %us.24, %us.24
43 %us.26 = and i1 %us.25, %us.25
44 %us.27 = and i1 %us.26, %us.26
45 %us.28 = and i1 %us.27, %us.27
46 %us.29 = and i1 %us.28, %us.28
47 br i1 %us.29, label %leave, label %be
48
49 be:
50 store volatile i32 0, i32* %ptr
51 %becond = icmp ult i32 %iv.inc, %n
52 br i1 %becond, label %leave, label %loop
53
54 leave:
55 ret void
56 }