@@ -59,6 +59,11 @@ INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
5959INITIALIZE_PASS_END(LazyValueInfoWrapperPass, " lazy-value-info" ,
6060 " Lazy Value Information Analysis" , false , true )
6161
62+ static cl::opt<bool> PerPredRanges(
63+ " lvi-per-pred-ranges" , cl::Hidden, cl::init(false ),
64+ cl::desc(" Enable tracking of ranges for a value in a block for"
65+ " each block predecessor (default = false)" ));
66+
6267namespace llvm {
6368FunctionPass *createLazyValueInfoPass () {
6469 return new LazyValueInfoWrapperPass ();
@@ -103,6 +108,10 @@ namespace {
103108
104109namespace {
105110using NonNullPointerSet = SmallDenseSet<AssertingVH<Value>, 2 >;
111+ using BBLatticeElementMap =
112+ SmallDenseMap<PoisoningVH<BasicBlock>, ValueLatticeElement, 4 >;
113+ using PredecessorValueLatticeMap =
114+ SmallDenseMap<AssertingVH<Value>, BBLatticeElementMap, 2 >;
106115
107116// / This is the cache kept by LazyValueInfo which
108117// / maintains information about queries across the clients' queries.
@@ -117,6 +126,10 @@ class LazyValueInfoCache {
117126 // std::nullopt indicates that the nonnull pointers for this basic block
118127 // block have not been computed yet.
119128 std::optional<NonNullPointerSet> NonNullPointers;
129+ // This is an extension of the above LatticeElements, caching, for each
130+ // Value, a ValueLatticeElement, for each predecessor of the BB tracked by
131+ // this entry.
132+ std::optional<PredecessorValueLatticeMap> PredecessorLatticeElements;
120133 };
121134
122135 // / Cached information per basic block.
@@ -134,8 +147,14 @@ class LazyValueInfoCache {
134147
135148 BlockCacheEntry *getOrCreateBlockEntry (BasicBlock *BB) {
136149 auto It = BlockCache.find_as (BB);
137- if (It == BlockCache.end ())
138- It = BlockCache.insert ({BB, std::make_unique<BlockCacheEntry>()}).first ;
150+ if (It == BlockCache.end ()) {
151+ std::unique_ptr<BlockCacheEntry> BCE =
152+ std::make_unique<BlockCacheEntry>();
153+ if (PerPredRanges)
154+ BCE->PredecessorLatticeElements =
155+ std::make_optional<PredecessorValueLatticeMap>();
156+ It = BlockCache.insert ({BB, std::move (BCE)}).first ;
157+ }
139158
140159 return It->second .get ();
141160 }
@@ -161,6 +180,28 @@ class LazyValueInfoCache {
161180 addValueHandle (Val);
162181 }
163182
183+ void insertPredecessorResults (Value *Val, BasicBlock *BB,
184+ BBLatticeElementMap &PredLatticeElements) {
185+ BlockCacheEntry *Entry = getOrCreateBlockEntry (BB);
186+
187+ Entry->PredecessorLatticeElements ->insert ({Val, PredLatticeElements});
188+
189+ addValueHandle (Val);
190+ }
191+
192+ std::optional<BBLatticeElementMap>
193+ getCachedPredecessorInfo (Value *V, BasicBlock *BB) const {
194+ const BlockCacheEntry *Entry = getBlockEntry (BB);
195+ if (!Entry)
196+ return std::nullopt ;
197+
198+ auto LatticeIt = Entry->PredecessorLatticeElements ->find_as (V);
199+ if (LatticeIt == Entry->PredecessorLatticeElements ->end ())
200+ return std::nullopt ;
201+
202+ return LatticeIt->second ;
203+ }
204+
164205 std::optional<ValueLatticeElement> getCachedValueInfo (Value *V,
165206 BasicBlock *BB) const {
166207 const BlockCacheEntry *Entry = getBlockEntry (BB);
@@ -216,6 +257,8 @@ void LazyValueInfoCache::eraseValue(Value *V) {
216257 Pair.second ->OverDefined .erase (V);
217258 if (Pair.second ->NonNullPointers )
218259 Pair.second ->NonNullPointers ->erase (V);
260+ if (PerPredRanges)
261+ Pair.second ->PredecessorLatticeElements ->erase (V);
219262 }
220263
221264 auto HandleIt = ValueHandles.find_as (V);
@@ -230,6 +273,10 @@ void LVIValueHandle::deleted() {
230273}
231274
232275void LazyValueInfoCache::eraseBlock (BasicBlock *BB) {
276+ // Clear all when a BB is removed.
277+ if (PerPredRanges)
278+ for (auto &Pair : BlockCache)
279+ Pair.second ->PredecessorLatticeElements ->clear ();
233280 BlockCache.erase (BB);
234281}
235282
@@ -691,6 +738,9 @@ LazyValueInfoImpl::solveBlockValueNonLocal(Value *Val, BasicBlock *BB) {
691738 // find a path to function entry. TODO: We should consider explicitly
692739 // canonicalizing to make this true rather than relying on this happy
693740 // accident.
741+ std::optional<BBLatticeElementMap> PredLatticeElements;
742+ if (PerPredRanges)
743+ PredLatticeElements = std::make_optional<BBLatticeElementMap>();
694744 for (BasicBlock *Pred : predecessors (BB)) {
695745 // Skip self loops.
696746 if (Pred == BB)
@@ -710,8 +760,13 @@ LazyValueInfoImpl::solveBlockValueNonLocal(Value *Val, BasicBlock *BB) {
710760 << Pred->getName () << " ' (non local).\n " );
711761 return Result;
712762 }
763+ if (PerPredRanges)
764+ PredLatticeElements->insert ({Pred, *EdgeResult});
713765 }
714766
767+ if (PerPredRanges)
768+ TheCache.insertPredecessorResults (Val, BB, *PredLatticeElements);
769+
715770 // Return the merged value, which is more precise than 'overdefined'.
716771 assert (!Result.isOverdefined ());
717772 return Result;
@@ -724,6 +779,9 @@ LazyValueInfoImpl::solveBlockValuePHINode(PHINode *PN, BasicBlock *BB) {
724779 // Loop over all of our predecessors, merging what we know from them into
725780 // result. See the comment about the chosen traversal order in
726781 // solveBlockValueNonLocal; the same reasoning applies here.
782+ std::optional<BBLatticeElementMap> PredLatticeElements;
783+ if (PerPredRanges)
784+ PredLatticeElements = std::make_optional<BBLatticeElementMap>();
727785 for (unsigned i = 0 , e = PN->getNumIncomingValues (); i != e; ++i) {
728786 BasicBlock *PhiBB = PN->getIncomingBlock (i);
729787 Value *PhiVal = PN->getIncomingValue (i);
@@ -746,8 +804,14 @@ LazyValueInfoImpl::solveBlockValuePHINode(PHINode *PN, BasicBlock *BB) {
746804
747805 return Result;
748806 }
807+
808+ if (PerPredRanges)
809+ PredLatticeElements->insert ({PhiBB, *EdgeResult});
749810 }
750811
812+ if (PerPredRanges)
813+ TheCache.insertPredecessorResults (PN, BB, *PredLatticeElements);
814+
751815 // Return the merged value, which is more precise than 'overdefined'.
752816 assert (!Result.isOverdefined () && " Possible PHI in entry block?" );
753817 return Result;
@@ -1002,7 +1066,77 @@ LazyValueInfoImpl::solveBlockValueBinaryOpImpl(
10021066
10031067 const ConstantRange &LHSRange = *LHSRes;
10041068 const ConstantRange &RHSRange = *RHSRes;
1005- return ValueLatticeElement::getRange (OpFn (LHSRange, RHSRange));
1069+
1070+ std::optional<ValueLatticeElement> MergedResult =
1071+ ValueLatticeElement::getRange (OpFn (LHSRange, RHSRange));
1072+
1073+ if (!PerPredRanges)
1074+ return MergedResult;
1075+
1076+ std::optional<BBLatticeElementMap> PredLHS =
1077+ TheCache.getCachedPredecessorInfo (LHS, BB);
1078+ if (!PredLHS)
1079+ return MergedResult;
1080+ std::optional<BBLatticeElementMap> PredRHS =
1081+ TheCache.getCachedPredecessorInfo (RHS, BB);
1082+ if (!PredRHS)
1083+ return MergedResult;
1084+
1085+ const BBLatticeElementMap &LHSPredMap = *PredLHS;
1086+ const BBLatticeElementMap &RHSPredMap = *PredRHS;
1087+
1088+ BBLatticeElementMap PredLatticeElements;
1089+ ValueLatticeElement OverallPredResult;
1090+ for (auto *Pred : predecessors (BB)) {
1091+ auto LHSIt = LHSPredMap.find_as (Pred);
1092+ if (LHSIt == LHSPredMap.end ())
1093+ return MergedResult;
1094+ const ValueLatticeElement &LHSFromPred = LHSIt->second ;
1095+ std::optional<ConstantRange> LHSFromPredRes =
1096+ LHSFromPred.asConstantRange (LHS->getType ());
1097+ if (!LHSFromPredRes)
1098+ return MergedResult;
1099+
1100+ auto RHSIt = RHSPredMap.find_as (Pred);
1101+ if (RHSIt == RHSPredMap.end ())
1102+ return MergedResult;
1103+ const ValueLatticeElement &RHSFromPred = RHSIt->second ;
1104+ std::optional<ConstantRange> RHSFromPredRes =
1105+ RHSFromPred.asConstantRange (RHS->getType ());
1106+ if (!RHSFromPredRes)
1107+ return MergedResult;
1108+
1109+ const ConstantRange &LHSFromPredRange = *LHSFromPredRes;
1110+ const ConstantRange &RHSFromPredRange = *RHSFromPredRes;
1111+ std::optional<ValueLatticeElement> PredResult =
1112+ ValueLatticeElement::getRange (OpFn (LHSFromPredRange, RHSFromPredRange));
1113+ if (!PredResult)
1114+ return MergedResult;
1115+ if (PredResult->isOverdefined ()) {
1116+ LLVM_DEBUG (
1117+ dbgs () << " pred BB '" << Pred->getName () << " ' for BB '"
1118+ << BB->getName ()
1119+ << " ' overdefined. Discarding all predecessor intervals.\n " );
1120+ return MergedResult;
1121+ }
1122+ PredLatticeElements.insert ({Pred, *PredResult});
1123+ OverallPredResult.mergeIn (*PredResult);
1124+ }
1125+
1126+ // If this point is reached, all predecessors for both LHS and RHS have
1127+ // constant ranges previously computed. Can cache result and use the
1128+ // OverallPredResult;
1129+ TheCache.insertPredecessorResults (I, BB, PredLatticeElements);
1130+
1131+ LLVM_DEBUG (dbgs () << " Using predecessor intervals, evaluated " << *I
1132+ << " to: " << OverallPredResult << " .\n " );
1133+
1134+ if (!MergedResult)
1135+ return OverallPredResult;
1136+
1137+ LLVM_DEBUG (dbgs () << " Intersecting intervals for " << *I << " : "
1138+ << OverallPredResult << " and " << MergedResult << " .\n " );
1139+ return MergedResult->intersect (OverallPredResult);
10061140}
10071141
10081142std::optional<ValueLatticeElement>
0 commit comments