]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/lib/Analysis/CFLAndersAliasAnalysis.cpp
Import mandoc 1.4.1rc2
[FreeBSD/FreeBSD.git] / contrib / llvm / lib / Analysis / CFLAndersAliasAnalysis.cpp
1 //- CFLAndersAliasAnalysis.cpp - Unification-based Alias Analysis ---*- C++-*-//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file implements a CFL-based, summary-based alias analysis algorithm. It
11 // differs from CFLSteensAliasAnalysis in its inclusion-based nature while
12 // CFLSteensAliasAnalysis is unification-based. This pass has worse performance
13 // than CFLSteensAliasAnalysis (the worst case complexity of
14 // CFLAndersAliasAnalysis is cubic, while the worst case complexity of
15 // CFLSteensAliasAnalysis is almost linear), but it is able to yield more
16 // precise analysis result. The precision of this analysis is roughly the same
17 // as that of an one level context-sensitive Andersen's algorithm.
18 //
19 // The algorithm used here is based on recursive state machine matching scheme
20 // proposed in "Demand-driven alias analysis for C" by Xin Zheng and Radu
21 // Rugina. The general idea is to extend the tranditional transitive closure
22 // algorithm to perform CFL matching along the way: instead of recording
23 // "whether X is reachable from Y", we keep track of "whether X is reachable
24 // from Y at state Z", where the "state" field indicates where we are in the CFL
25 // matching process. To understand the matching better, it is advisable to have
26 // the state machine shown in Figure 3 of the paper available when reading the
27 // codes: all we do here is to selectively expand the transitive closure by
28 // discarding edges that are not recognized by the state machine.
29 //
30 // There is one difference between our current implementation and the one
31 // described in the paper: out algorithm eagerly computes all alias pairs after
32 // the CFLGraph is built, while in the paper the authors did the computation in
33 // a demand-driven fashion. We did not implement the demand-driven algorithm due
34 // to the additional coding complexity and higher memory profile, but if we
35 // found it necessary we may switch to it eventually.
36 //
37 //===----------------------------------------------------------------------===//
38
39 // N.B. AliasAnalysis as a whole is phrased as a FunctionPass at the moment, and
40 // CFLAndersAA is interprocedural. This is *technically* A Bad Thing, because
41 // FunctionPasses are only allowed to inspect the Function that they're being
42 // run on. Realistically, this likely isn't a problem until we allow
43 // FunctionPasses to run concurrently.
44
45 #include "llvm/Analysis/CFLAndersAliasAnalysis.h"
46 #include "CFLGraph.h"
47 #include "llvm/ADT/DenseSet.h"
48 #include "llvm/Pass.h"
49
50 using namespace llvm;
51 using namespace llvm::cflaa;
52
53 #define DEBUG_TYPE "cfl-anders-aa"
54
55 CFLAndersAAResult::CFLAndersAAResult(const TargetLibraryInfo &TLI) : TLI(TLI) {}
56 CFLAndersAAResult::CFLAndersAAResult(CFLAndersAAResult &&RHS)
57     : AAResultBase(std::move(RHS)), TLI(RHS.TLI) {}
58 CFLAndersAAResult::~CFLAndersAAResult() {}
59
60 static const Function *parentFunctionOfValue(const Value *Val) {
61   if (auto *Inst = dyn_cast<Instruction>(Val)) {
62     auto *Bb = Inst->getParent();
63     return Bb->getParent();
64   }
65
66   if (auto *Arg = dyn_cast<Argument>(Val))
67     return Arg->getParent();
68   return nullptr;
69 }
70
71 namespace {
72
73 enum class MatchState : uint8_t {
74   FlowFrom = 0,     // S1 in the paper
75   FlowFromMemAlias, // S2 in the paper
76   FlowTo,           // S3 in the paper
77   FlowToMemAlias    // S4 in the paper
78 };
79
80 // We use ReachabilitySet to keep track of value aliases (The nonterminal "V" in
81 // the paper) during the analysis.
82 class ReachabilitySet {
83   typedef std::bitset<4> StateSet;
84   typedef DenseMap<InstantiatedValue, StateSet> ValueStateMap;
85   typedef DenseMap<InstantiatedValue, ValueStateMap> ValueReachMap;
86   ValueReachMap ReachMap;
87
88 public:
89   typedef ValueStateMap::const_iterator const_valuestate_iterator;
90   typedef ValueReachMap::const_iterator const_value_iterator;
91
92   // Insert edge 'From->To' at state 'State'
93   bool insert(InstantiatedValue From, InstantiatedValue To, MatchState State) {
94     auto &States = ReachMap[To][From];
95     auto Idx = static_cast<size_t>(State);
96     if (!States.test(Idx)) {
97       States.set(Idx);
98       return true;
99     }
100     return false;
101   }
102
103   // Return the set of all ('From', 'State') pair for a given node 'To'
104   iterator_range<const_valuestate_iterator>
105   reachableValueAliases(InstantiatedValue V) const {
106     auto Itr = ReachMap.find(V);
107     if (Itr == ReachMap.end())
108       return make_range<const_valuestate_iterator>(const_valuestate_iterator(),
109                                                    const_valuestate_iterator());
110     return make_range<const_valuestate_iterator>(Itr->second.begin(),
111                                                  Itr->second.end());
112   }
113
114   iterator_range<const_value_iterator> value_mappings() const {
115     return make_range<const_value_iterator>(ReachMap.begin(), ReachMap.end());
116   }
117 };
118
119 // We use AliasMemSet to keep track of all memory aliases (the nonterminal "M"
120 // in the paper) during the analysis.
121 class AliasMemSet {
122   typedef DenseSet<InstantiatedValue> MemSet;
123   typedef DenseMap<InstantiatedValue, MemSet> MemMapType;
124   MemMapType MemMap;
125
126 public:
127   typedef MemSet::const_iterator const_mem_iterator;
128
129   bool insert(InstantiatedValue LHS, InstantiatedValue RHS) {
130     // Top-level values can never be memory aliases because one cannot take the
131     // addresses of them
132     assert(LHS.DerefLevel > 0 && RHS.DerefLevel > 0);
133     return MemMap[LHS].insert(RHS).second;
134   }
135
136   const MemSet *getMemoryAliases(InstantiatedValue V) const {
137     auto Itr = MemMap.find(V);
138     if (Itr == MemMap.end())
139       return nullptr;
140     return &Itr->second;
141   }
142 };
143
144 // We use AliasAttrMap to keep track of the AliasAttr of each node.
145 class AliasAttrMap {
146   typedef DenseMap<InstantiatedValue, AliasAttrs> MapType;
147   MapType AttrMap;
148
149 public:
150   typedef MapType::const_iterator const_iterator;
151
152   bool add(InstantiatedValue V, AliasAttrs Attr) {
153     if (Attr.none())
154       return false;
155     auto &OldAttr = AttrMap[V];
156     auto NewAttr = OldAttr | Attr;
157     if (OldAttr == NewAttr)
158       return false;
159     OldAttr = NewAttr;
160     return true;
161   }
162
163   AliasAttrs getAttrs(InstantiatedValue V) const {
164     AliasAttrs Attr;
165     auto Itr = AttrMap.find(V);
166     if (Itr != AttrMap.end())
167       Attr = Itr->second;
168     return Attr;
169   }
170
171   iterator_range<const_iterator> mappings() const {
172     return make_range<const_iterator>(AttrMap.begin(), AttrMap.end());
173   }
174 };
175
176 struct WorkListItem {
177   InstantiatedValue From;
178   InstantiatedValue To;
179   MatchState State;
180 };
181 }
182
183 class CFLAndersAAResult::FunctionInfo {
184   /// Map a value to other values that may alias it
185   /// Since the alias relation is symmetric, to save some space we assume values
186   /// are properly ordered: if a and b alias each other, and a < b, then b is in
187   /// AliasMap[a] but not vice versa.
188   DenseMap<const Value *, std::vector<const Value *>> AliasMap;
189
190   /// Map a value to its corresponding AliasAttrs
191   DenseMap<const Value *, AliasAttrs> AttrMap;
192
193   /// Summary of externally visible effects.
194   AliasSummary Summary;
195
196   AliasAttrs getAttrs(const Value *) const;
197
198 public:
199   FunctionInfo(const ReachabilitySet &, AliasAttrMap);
200
201   bool mayAlias(const Value *LHS, const Value *RHS) const;
202   const AliasSummary &getAliasSummary() const { return Summary; }
203 };
204
205 CFLAndersAAResult::FunctionInfo::FunctionInfo(const ReachabilitySet &ReachSet,
206                                               AliasAttrMap AMap) {
207   // Populate AttrMap
208   for (const auto &Mapping : AMap.mappings()) {
209     auto IVal = Mapping.first;
210
211     // AttrMap only cares about top-level values
212     if (IVal.DerefLevel == 0)
213       AttrMap[IVal.Val] = Mapping.second;
214   }
215
216   // Populate AliasMap
217   for (const auto &OuterMapping : ReachSet.value_mappings()) {
218     // AliasMap only cares about top-level values
219     if (OuterMapping.first.DerefLevel > 0)
220       continue;
221
222     auto Val = OuterMapping.first.Val;
223     auto &AliasList = AliasMap[Val];
224     for (const auto &InnerMapping : OuterMapping.second) {
225       // Again, AliasMap only cares about top-level values
226       if (InnerMapping.first.DerefLevel == 0)
227         AliasList.push_back(InnerMapping.first.Val);
228     }
229
230     // Sort AliasList for faster lookup
231     std::sort(AliasList.begin(), AliasList.end(), std::less<const Value *>());
232   }
233
234   // TODO: Populate function summary here
235 }
236
237 AliasAttrs CFLAndersAAResult::FunctionInfo::getAttrs(const Value *V) const {
238   assert(V != nullptr);
239
240   AliasAttrs Attr;
241   auto Itr = AttrMap.find(V);
242   if (Itr != AttrMap.end())
243     Attr = Itr->second;
244   return Attr;
245 }
246
247 bool CFLAndersAAResult::FunctionInfo::mayAlias(const Value *LHS,
248                                                const Value *RHS) const {
249   assert(LHS && RHS);
250
251   auto Itr = AliasMap.find(LHS);
252   if (Itr != AliasMap.end()) {
253     if (std::binary_search(Itr->second.begin(), Itr->second.end(), RHS,
254                            std::less<const Value *>()))
255       return true;
256   }
257
258   // Even if LHS and RHS are not reachable, they may still alias due to their
259   // AliasAttrs
260   auto AttrsA = getAttrs(LHS);
261   auto AttrsB = getAttrs(RHS);
262
263   if (AttrsA.none() || AttrsB.none())
264     return false;
265   if (hasUnknownOrCallerAttr(AttrsA) || hasUnknownOrCallerAttr(AttrsB))
266     return true;
267   if (isGlobalOrArgAttr(AttrsA) && isGlobalOrArgAttr(AttrsB))
268     return true;
269   return false;
270 }
271
272 static void propagate(InstantiatedValue From, InstantiatedValue To,
273                       MatchState State, ReachabilitySet &ReachSet,
274                       std::vector<WorkListItem> &WorkList) {
275   if (From == To)
276     return;
277   if (ReachSet.insert(From, To, State))
278     WorkList.push_back(WorkListItem{From, To, State});
279 }
280
281 static void initializeWorkList(std::vector<WorkListItem> &WorkList,
282                                ReachabilitySet &ReachSet,
283                                const CFLGraph &Graph) {
284   for (const auto &Mapping : Graph.value_mappings()) {
285     auto Val = Mapping.first;
286     auto &ValueInfo = Mapping.second;
287     assert(ValueInfo.getNumLevels() > 0);
288
289     // Insert all immediate assignment neighbors to the worklist
290     for (unsigned I = 0, E = ValueInfo.getNumLevels(); I < E; ++I) {
291       auto Src = InstantiatedValue{Val, I};
292       // If there's an assignment edge from X to Y, it means Y is reachable from
293       // X at S2 and X is reachable from Y at S1
294       for (auto &Edge : ValueInfo.getNodeInfoAtLevel(I).Edges) {
295         propagate(Edge.Other, Src, MatchState::FlowFrom, ReachSet, WorkList);
296         propagate(Src, Edge.Other, MatchState::FlowTo, ReachSet, WorkList);
297       }
298     }
299   }
300 }
301
302 static Optional<InstantiatedValue> getNodeBelow(const CFLGraph &Graph,
303                                                 InstantiatedValue V) {
304   auto NodeBelow = InstantiatedValue{V.Val, V.DerefLevel + 1};
305   if (Graph.getNode(NodeBelow))
306     return NodeBelow;
307   return None;
308 }
309
310 static void processWorkListItem(const WorkListItem &Item, const CFLGraph &Graph,
311                                 ReachabilitySet &ReachSet, AliasMemSet &MemSet,
312                                 std::vector<WorkListItem> &WorkList) {
313   auto FromNode = Item.From;
314   auto ToNode = Item.To;
315
316   auto NodeInfo = Graph.getNode(ToNode);
317   assert(NodeInfo != nullptr);
318
319   // TODO: propagate field offsets
320
321   // FIXME: Here is a neat trick we can do: since both ReachSet and MemSet holds
322   // relations that are symmetric, we could actually cut the storage by half by
323   // sorting FromNode and ToNode before insertion happens.
324
325   // The newly added value alias pair may pontentially generate more memory
326   // alias pairs. Check for them here.
327   auto FromNodeBelow = getNodeBelow(Graph, FromNode);
328   auto ToNodeBelow = getNodeBelow(Graph, ToNode);
329   if (FromNodeBelow && ToNodeBelow &&
330       MemSet.insert(*FromNodeBelow, *ToNodeBelow)) {
331     propagate(*FromNodeBelow, *ToNodeBelow, MatchState::FlowFromMemAlias,
332               ReachSet, WorkList);
333     for (const auto &Mapping : ReachSet.reachableValueAliases(*FromNodeBelow)) {
334       auto Src = Mapping.first;
335       if (Mapping.second.test(static_cast<size_t>(MatchState::FlowFrom)))
336         propagate(Src, *ToNodeBelow, MatchState::FlowFromMemAlias, ReachSet,
337                   WorkList);
338       if (Mapping.second.test(static_cast<size_t>(MatchState::FlowTo)))
339         propagate(Src, *ToNodeBelow, MatchState::FlowToMemAlias, ReachSet,
340                   WorkList);
341     }
342   }
343
344   // This is the core of the state machine walking algorithm. We expand ReachSet
345   // based on which state we are at (which in turn dictates what edges we
346   // should examine)
347   // From a high-level point of view, the state machine here guarantees two
348   // properties:
349   // - If *X and *Y are memory aliases, then X and Y are value aliases
350   // - If Y is an alias of X, then reverse assignment edges (if there is any)
351   // should precede any assignment edges on the path from X to Y.
352   switch (Item.State) {
353   case MatchState::FlowFrom: {
354     for (const auto &RevAssignEdge : NodeInfo->ReverseEdges)
355       propagate(FromNode, RevAssignEdge.Other, MatchState::FlowFrom, ReachSet,
356                 WorkList);
357     for (const auto &AssignEdge : NodeInfo->Edges)
358       propagate(FromNode, AssignEdge.Other, MatchState::FlowTo, ReachSet,
359                 WorkList);
360     if (auto AliasSet = MemSet.getMemoryAliases(ToNode)) {
361       for (const auto &MemAlias : *AliasSet)
362         propagate(FromNode, MemAlias, MatchState::FlowFromMemAlias, ReachSet,
363                   WorkList);
364     }
365     break;
366   }
367   case MatchState::FlowFromMemAlias: {
368     for (const auto &RevAssignEdge : NodeInfo->ReverseEdges)
369       propagate(FromNode, RevAssignEdge.Other, MatchState::FlowFrom, ReachSet,
370                 WorkList);
371     for (const auto &AssignEdge : NodeInfo->Edges)
372       propagate(FromNode, AssignEdge.Other, MatchState::FlowTo, ReachSet,
373                 WorkList);
374     break;
375   }
376   case MatchState::FlowTo: {
377     for (const auto &AssignEdge : NodeInfo->Edges)
378       propagate(FromNode, AssignEdge.Other, MatchState::FlowTo, ReachSet,
379                 WorkList);
380     if (auto AliasSet = MemSet.getMemoryAliases(ToNode)) {
381       for (const auto &MemAlias : *AliasSet)
382         propagate(FromNode, MemAlias, MatchState::FlowToMemAlias, ReachSet,
383                   WorkList);
384     }
385     break;
386   }
387   case MatchState::FlowToMemAlias: {
388     for (const auto &AssignEdge : NodeInfo->Edges)
389       propagate(FromNode, AssignEdge.Other, MatchState::FlowTo, ReachSet,
390                 WorkList);
391     break;
392   }
393   }
394 }
395
396 static AliasAttrMap buildAttrMap(const CFLGraph &Graph,
397                                  const ReachabilitySet &ReachSet) {
398   AliasAttrMap AttrMap;
399   std::vector<InstantiatedValue> WorkList, NextList;
400
401   // Initialize each node with its original AliasAttrs in CFLGraph
402   for (const auto &Mapping : Graph.value_mappings()) {
403     auto Val = Mapping.first;
404     auto &ValueInfo = Mapping.second;
405     for (unsigned I = 0, E = ValueInfo.getNumLevels(); I < E; ++I) {
406       auto Node = InstantiatedValue{Val, I};
407       AttrMap.add(Node, ValueInfo.getNodeInfoAtLevel(I).Attr);
408       WorkList.push_back(Node);
409     }
410   }
411
412   while (!WorkList.empty()) {
413     for (const auto &Dst : WorkList) {
414       auto DstAttr = AttrMap.getAttrs(Dst);
415       if (DstAttr.none())
416         continue;
417
418       // Propagate attr on the same level
419       for (const auto &Mapping : ReachSet.reachableValueAliases(Dst)) {
420         auto Src = Mapping.first;
421         if (AttrMap.add(Src, DstAttr))
422           NextList.push_back(Src);
423       }
424
425       // Propagate attr to the levels below
426       auto DstBelow = getNodeBelow(Graph, Dst);
427       while (DstBelow) {
428         if (AttrMap.add(*DstBelow, DstAttr)) {
429           NextList.push_back(*DstBelow);
430           break;
431         }
432         DstBelow = getNodeBelow(Graph, *DstBelow);
433       }
434     }
435     WorkList.swap(NextList);
436     NextList.clear();
437   }
438
439   return AttrMap;
440 }
441
442 CFLAndersAAResult::FunctionInfo
443 CFLAndersAAResult::buildInfoFrom(const Function &Fn) {
444   CFLGraphBuilder<CFLAndersAAResult> GraphBuilder(
445       *this, TLI,
446       // Cast away the constness here due to GraphBuilder's API requirement
447       const_cast<Function &>(Fn));
448   auto &Graph = GraphBuilder.getCFLGraph();
449
450   ReachabilitySet ReachSet;
451   AliasMemSet MemSet;
452
453   std::vector<WorkListItem> WorkList, NextList;
454   initializeWorkList(WorkList, ReachSet, Graph);
455   // TODO: make sure we don't stop before the fix point is reached
456   while (!WorkList.empty()) {
457     for (const auto &Item : WorkList)
458       processWorkListItem(Item, Graph, ReachSet, MemSet, NextList);
459
460     NextList.swap(WorkList);
461     NextList.clear();
462   }
463
464   // Now that we have all the reachability info, propagate AliasAttrs according
465   // to it
466   auto IValueAttrMap = buildAttrMap(Graph, ReachSet);
467
468   return FunctionInfo(ReachSet, std::move(IValueAttrMap));
469 }
470
471 void CFLAndersAAResult::scan(const Function &Fn) {
472   auto InsertPair = Cache.insert(std::make_pair(&Fn, Optional<FunctionInfo>()));
473   (void)InsertPair;
474   assert(InsertPair.second &&
475          "Trying to scan a function that has already been cached");
476
477   // Note that we can't do Cache[Fn] = buildSetsFrom(Fn) here: the function call
478   // may get evaluated after operator[], potentially triggering a DenseMap
479   // resize and invalidating the reference returned by operator[]
480   auto FunInfo = buildInfoFrom(Fn);
481   Cache[&Fn] = std::move(FunInfo);
482   Handles.push_front(FunctionHandle(const_cast<Function *>(&Fn), this));
483 }
484
485 void CFLAndersAAResult::evict(const Function &Fn) { Cache.erase(&Fn); }
486
487 const Optional<CFLAndersAAResult::FunctionInfo> &
488 CFLAndersAAResult::ensureCached(const Function &Fn) {
489   auto Iter = Cache.find(&Fn);
490   if (Iter == Cache.end()) {
491     scan(Fn);
492     Iter = Cache.find(&Fn);
493     assert(Iter != Cache.end());
494     assert(Iter->second.hasValue());
495   }
496   return Iter->second;
497 }
498
499 const AliasSummary *CFLAndersAAResult::getAliasSummary(const Function &Fn) {
500   auto &FunInfo = ensureCached(Fn);
501   if (FunInfo.hasValue())
502     return &FunInfo->getAliasSummary();
503   else
504     return nullptr;
505 }
506
507 AliasResult CFLAndersAAResult::query(const MemoryLocation &LocA,
508                                      const MemoryLocation &LocB) {
509   auto *ValA = LocA.Ptr;
510   auto *ValB = LocB.Ptr;
511
512   if (!ValA->getType()->isPointerTy() || !ValB->getType()->isPointerTy())
513     return NoAlias;
514
515   auto *Fn = parentFunctionOfValue(ValA);
516   if (!Fn) {
517     Fn = parentFunctionOfValue(ValB);
518     if (!Fn) {
519       // The only times this is known to happen are when globals + InlineAsm are
520       // involved
521       DEBUG(dbgs()
522             << "CFLAndersAA: could not extract parent function information.\n");
523       return MayAlias;
524     }
525   } else {
526     assert(!parentFunctionOfValue(ValB) || parentFunctionOfValue(ValB) == Fn);
527   }
528
529   assert(Fn != nullptr);
530   auto &FunInfo = ensureCached(*Fn);
531
532   // AliasMap lookup
533   if (FunInfo->mayAlias(ValA, ValB))
534     return MayAlias;
535   return NoAlias;
536 }
537
538 AliasResult CFLAndersAAResult::alias(const MemoryLocation &LocA,
539                                      const MemoryLocation &LocB) {
540   if (LocA.Ptr == LocB.Ptr)
541     return LocA.Size == LocB.Size ? MustAlias : PartialAlias;
542
543   // Comparisons between global variables and other constants should be
544   // handled by BasicAA.
545   // CFLAndersAA may report NoAlias when comparing a GlobalValue and
546   // ConstantExpr, but every query needs to have at least one Value tied to a
547   // Function, and neither GlobalValues nor ConstantExprs are.
548   if (isa<Constant>(LocA.Ptr) && isa<Constant>(LocB.Ptr))
549     return AAResultBase::alias(LocA, LocB);
550
551   AliasResult QueryResult = query(LocA, LocB);
552   if (QueryResult == MayAlias)
553     return AAResultBase::alias(LocA, LocB);
554
555   return QueryResult;
556 }
557
558 char CFLAndersAA::PassID;
559
560 CFLAndersAAResult CFLAndersAA::run(Function &F, AnalysisManager<Function> &AM) {
561   return CFLAndersAAResult(AM.getResult<TargetLibraryAnalysis>(F));
562 }
563
564 char CFLAndersAAWrapperPass::ID = 0;
565 INITIALIZE_PASS(CFLAndersAAWrapperPass, "cfl-anders-aa",
566                 "Inclusion-Based CFL Alias Analysis", false, true)
567
568 ImmutablePass *llvm::createCFLAndersAAWrapperPass() {
569   return new CFLAndersAAWrapperPass();
570 }
571
572 CFLAndersAAWrapperPass::CFLAndersAAWrapperPass() : ImmutablePass(ID) {
573   initializeCFLAndersAAWrapperPassPass(*PassRegistry::getPassRegistry());
574 }
575
576 void CFLAndersAAWrapperPass::initializePass() {
577   auto &TLIWP = getAnalysis<TargetLibraryInfoWrapperPass>();
578   Result.reset(new CFLAndersAAResult(TLIWP.getTLI()));
579 }
580
581 void CFLAndersAAWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
582   AU.setPreservesAll();
583   AU.addRequired<TargetLibraryInfoWrapperPass>();
584 }