LLVM  4.0.0
CFLAndersAliasAnalysis.cpp
Go to the documentation of this file.
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 are two differences between our current implementation and the one
31 // described in the paper:
32 // - Our algorithm eagerly computes all alias pairs after the CFLGraph is built,
33 // while in the paper the authors did the computation in a demand-driven
34 // fashion. We did not implement the demand-driven algorithm due to the
35 // additional coding complexity and higher memory profile, but if we found it
36 // necessary we may switch to it eventually.
37 // - In the paper the authors use a state machine that does not distinguish
38 // value reads from value writes. For example, if Y is reachable from X at state
39 // S3, it may be the case that X is written into Y, or it may be the case that
40 // there's a third value Z that writes into both X and Y. To make that
41 // distinction (which is crucial in building function summary as well as
42 // retrieving mod-ref info), we choose to duplicate some of the states in the
43 // paper's proposed state machine. The duplication does not change the set the
44 // machine accepts. Given a pair of reachable values, it only provides more
45 // detailed information on which value is being written into and which is being
46 // read from.
47 //
48 //===----------------------------------------------------------------------===//
49 
50 // N.B. AliasAnalysis as a whole is phrased as a FunctionPass at the moment, and
51 // CFLAndersAA is interprocedural. This is *technically* A Bad Thing, because
52 // FunctionPasses are only allowed to inspect the Function that they're being
53 // run on. Realistically, this likely isn't a problem until we allow
54 // FunctionPasses to run concurrently.
55 
57 #include "CFLGraph.h"
58 #include "llvm/ADT/DenseSet.h"
59 #include "llvm/Pass.h"
60 
61 using namespace llvm;
62 using namespace llvm::cflaa;
63 
64 #define DEBUG_TYPE "cfl-anders-aa"
65 
68  : AAResultBase(std::move(RHS)), TLI(RHS.TLI) {}
70 
71 static const Function *parentFunctionOfValue(const Value *Val) {
72  if (auto *Inst = dyn_cast<Instruction>(Val)) {
73  auto *Bb = Inst->getParent();
74  return Bb->getParent();
75  }
76 
77  if (auto *Arg = dyn_cast<Argument>(Val))
78  return Arg->getParent();
79  return nullptr;
80 }
81 
82 namespace {
83 
84 enum class MatchState : uint8_t {
85  // The following state represents S1 in the paper.
86  FlowFromReadOnly = 0,
87  // The following two states together represent S2 in the paper.
88  // The 'NoReadWrite' suffix indicates that there exists an alias path that
89  // does not contain assignment and reverse assignment edges.
90  // The 'ReadOnly' suffix indicates that there exists an alias path that
91  // contains reverse assignment edges only.
92  FlowFromMemAliasNoReadWrite,
93  FlowFromMemAliasReadOnly,
94  // The following two states together represent S3 in the paper.
95  // The 'WriteOnly' suffix indicates that there exists an alias path that
96  // contains assignment edges only.
97  // The 'ReadWrite' suffix indicates that there exists an alias path that
98  // contains both assignment and reverse assignment edges. Note that if X and Y
99  // are reachable at 'ReadWrite' state, it does NOT mean X is both read from
100  // and written to Y. Instead, it means that a third value Z is written to both
101  // X and Y.
102  FlowToWriteOnly,
103  FlowToReadWrite,
104  // The following two states together represent S4 in the paper.
105  FlowToMemAliasWriteOnly,
106  FlowToMemAliasReadWrite,
107 };
108 
109 typedef std::bitset<7> StateSet;
110 const unsigned ReadOnlyStateMask =
111  (1U << static_cast<uint8_t>(MatchState::FlowFromReadOnly)) |
112  (1U << static_cast<uint8_t>(MatchState::FlowFromMemAliasReadOnly));
113 const unsigned WriteOnlyStateMask =
114  (1U << static_cast<uint8_t>(MatchState::FlowToWriteOnly)) |
115  (1U << static_cast<uint8_t>(MatchState::FlowToMemAliasWriteOnly));
116 
117 // A pair that consists of a value and an offset
118 struct OffsetValue {
119  const Value *Val;
120  int64_t Offset;
121 };
122 
123 bool operator==(OffsetValue LHS, OffsetValue RHS) {
124  return LHS.Val == RHS.Val && LHS.Offset == RHS.Offset;
125 }
126 bool operator<(OffsetValue LHS, OffsetValue RHS) {
127  return std::less<const Value *>()(LHS.Val, RHS.Val) ||
128  (LHS.Val == RHS.Val && LHS.Offset < RHS.Offset);
129 }
130 
131 // A pair that consists of an InstantiatedValue and an offset
132 struct OffsetInstantiatedValue {
133  InstantiatedValue IVal;
134  int64_t Offset;
135 };
136 
137 bool operator==(OffsetInstantiatedValue LHS, OffsetInstantiatedValue RHS) {
138  return LHS.IVal == RHS.IVal && LHS.Offset == RHS.Offset;
139 }
140 
141 // We use ReachabilitySet to keep track of value aliases (The nonterminal "V" in
142 // the paper) during the analysis.
143 class ReachabilitySet {
144  typedef DenseMap<InstantiatedValue, StateSet> ValueStateMap;
145  typedef DenseMap<InstantiatedValue, ValueStateMap> ValueReachMap;
146  ValueReachMap ReachMap;
147 
148 public:
149  typedef ValueStateMap::const_iterator const_valuestate_iterator;
150  typedef ValueReachMap::const_iterator const_value_iterator;
151 
152  // Insert edge 'From->To' at state 'State'
153  bool insert(InstantiatedValue From, InstantiatedValue To, MatchState State) {
154  assert(From != To);
155  auto &States = ReachMap[To][From];
156  auto Idx = static_cast<size_t>(State);
157  if (!States.test(Idx)) {
158  States.set(Idx);
159  return true;
160  }
161  return false;
162  }
163 
164  // Return the set of all ('From', 'State') pair for a given node 'To'
166  reachableValueAliases(InstantiatedValue V) const {
167  auto Itr = ReachMap.find(V);
168  if (Itr == ReachMap.end())
169  return make_range<const_valuestate_iterator>(const_valuestate_iterator(),
170  const_valuestate_iterator());
171  return make_range<const_valuestate_iterator>(Itr->second.begin(),
172  Itr->second.end());
173  }
174 
175  iterator_range<const_value_iterator> value_mappings() const {
176  return make_range<const_value_iterator>(ReachMap.begin(), ReachMap.end());
177  }
178 };
179 
180 // We use AliasMemSet to keep track of all memory aliases (the nonterminal "M"
181 // in the paper) during the analysis.
182 class AliasMemSet {
183  typedef DenseSet<InstantiatedValue> MemSet;
184  typedef DenseMap<InstantiatedValue, MemSet> MemMapType;
185  MemMapType MemMap;
186 
187 public:
188  typedef MemSet::const_iterator const_mem_iterator;
189 
190  bool insert(InstantiatedValue LHS, InstantiatedValue RHS) {
191  // Top-level values can never be memory aliases because one cannot take the
192  // addresses of them
193  assert(LHS.DerefLevel > 0 && RHS.DerefLevel > 0);
194  return MemMap[LHS].insert(RHS).second;
195  }
196 
197  const MemSet *getMemoryAliases(InstantiatedValue V) const {
198  auto Itr = MemMap.find(V);
199  if (Itr == MemMap.end())
200  return nullptr;
201  return &Itr->second;
202  }
203 };
204 
205 // We use AliasAttrMap to keep track of the AliasAttr of each node.
206 class AliasAttrMap {
208  MapType AttrMap;
209 
210 public:
211  typedef MapType::const_iterator const_iterator;
212 
213  bool add(InstantiatedValue V, AliasAttrs Attr) {
214  auto &OldAttr = AttrMap[V];
215  auto NewAttr = OldAttr | Attr;
216  if (OldAttr == NewAttr)
217  return false;
218  OldAttr = NewAttr;
219  return true;
220  }
221 
222  AliasAttrs getAttrs(InstantiatedValue V) const {
223  AliasAttrs Attr;
224  auto Itr = AttrMap.find(V);
225  if (Itr != AttrMap.end())
226  Attr = Itr->second;
227  return Attr;
228  }
229 
230  iterator_range<const_iterator> mappings() const {
231  return make_range<const_iterator>(AttrMap.begin(), AttrMap.end());
232  }
233 };
234 
235 struct WorkListItem {
236  InstantiatedValue From;
238  MatchState State;
239 };
240 
241 struct ValueSummary {
242  struct Record {
243  InterfaceValue IValue;
244  unsigned DerefLevel;
245  };
246  SmallVector<Record, 4> FromRecords, ToRecords;
247 };
248 }
249 
250 namespace llvm {
251 // Specialize DenseMapInfo for OffsetValue.
252 template <> struct DenseMapInfo<OffsetValue> {
253  static OffsetValue getEmptyKey() {
254  return OffsetValue{DenseMapInfo<const Value *>::getEmptyKey(),
256  }
257  static OffsetValue getTombstoneKey() {
260  }
261  static unsigned getHashValue(const OffsetValue &OVal) {
263  std::make_pair(OVal.Val, OVal.Offset));
264  }
265  static bool isEqual(const OffsetValue &LHS, const OffsetValue &RHS) {
266  return LHS == RHS;
267  }
268 };
269 
270 // Specialize DenseMapInfo for OffsetInstantiatedValue.
271 template <> struct DenseMapInfo<OffsetInstantiatedValue> {
272  static OffsetInstantiatedValue getEmptyKey() {
273  return OffsetInstantiatedValue{
276  }
277  static OffsetInstantiatedValue getTombstoneKey() {
278  return OffsetInstantiatedValue{
281  }
282  static unsigned getHashValue(const OffsetInstantiatedValue &OVal) {
284  std::make_pair(OVal.IVal, OVal.Offset));
285  }
286  static bool isEqual(const OffsetInstantiatedValue &LHS,
287  const OffsetInstantiatedValue &RHS) {
288  return LHS == RHS;
289  }
290 };
291 }
292 
294  /// Map a value to other values that may alias it
295  /// Since the alias relation is symmetric, to save some space we assume values
296  /// are properly ordered: if a and b alias each other, and a < b, then b is in
297  /// AliasMap[a] but not vice versa.
299 
300  /// Map a value to its corresponding AliasAttrs
302 
303  /// Summary of externally visible effects.
304  AliasSummary Summary;
305 
306  Optional<AliasAttrs> getAttrs(const Value *) const;
307 
308 public:
310  const ReachabilitySet &, AliasAttrMap);
311 
312  bool mayAlias(const Value *, uint64_t, const Value *, uint64_t) const;
313  const AliasSummary &getAliasSummary() const { return Summary; }
314 };
315 
316 static bool hasReadOnlyState(StateSet Set) {
317  return (Set & StateSet(ReadOnlyStateMask)).any();
318 }
319 
320 static bool hasWriteOnlyState(StateSet Set) {
321  return (Set & StateSet(WriteOnlyStateMask)).any();
322 }
323 
326  const SmallVectorImpl<Value *> &RetVals) {
327  auto Val = IValue.Val;
328 
329  Optional<unsigned> Index;
330  if (auto Arg = dyn_cast<Argument>(Val))
331  Index = Arg->getArgNo() + 1;
332  else if (is_contained(RetVals, Val))
333  Index = 0;
334 
335  if (Index)
336  return InterfaceValue{*Index, IValue.DerefLevel};
337  return None;
338 }
339 
341  const AliasAttrMap &AMap) {
342  for (const auto &Mapping : AMap.mappings()) {
343  auto IVal = Mapping.first;
344 
345  // Insert IVal into the map
346  auto &Attr = AttrMap[IVal.Val];
347  // AttrMap only cares about top-level values
348  if (IVal.DerefLevel == 0)
349  Attr |= Mapping.second;
350  }
351 }
352 
353 static void
354 populateAliasMap(DenseMap<const Value *, std::vector<OffsetValue>> &AliasMap,
355  const ReachabilitySet &ReachSet) {
356  for (const auto &OuterMapping : ReachSet.value_mappings()) {
357  // AliasMap only cares about top-level values
358  if (OuterMapping.first.DerefLevel > 0)
359  continue;
360 
361  auto Val = OuterMapping.first.Val;
362  auto &AliasList = AliasMap[Val];
363  for (const auto &InnerMapping : OuterMapping.second) {
364  // Again, AliasMap only cares about top-level values
365  if (InnerMapping.first.DerefLevel == 0)
366  AliasList.push_back(OffsetValue{InnerMapping.first.Val, UnknownOffset});
367  }
368 
369  // Sort AliasList for faster lookup
370  std::sort(AliasList.begin(), AliasList.end());
371  }
372 }
373 
375  SmallVectorImpl<ExternalRelation> &ExtRelations, const Function &Fn,
376  const SmallVectorImpl<Value *> &RetVals, const ReachabilitySet &ReachSet) {
377  // If a function only returns one of its argument X, then X will be both an
378  // argument and a return value at the same time. This is an edge case that
379  // needs special handling here.
380  for (const auto &Arg : Fn.args()) {
381  if (is_contained(RetVals, &Arg)) {
382  auto ArgVal = InterfaceValue{Arg.getArgNo() + 1, 0};
383  auto RetVal = InterfaceValue{0, 0};
384  ExtRelations.push_back(ExternalRelation{ArgVal, RetVal, 0});
385  }
386  }
387 
388  // Below is the core summary construction logic.
389  // A naive solution of adding only the value aliases that are parameters or
390  // return values in ReachSet to the summary won't work: It is possible that a
391  // parameter P is written into an intermediate value I, and the function
392  // subsequently returns *I. In that case, *I is does not value alias anything
393  // in ReachSet, and the naive solution will miss a summary edge from (P, 1) to
394  // (I, 1).
395  // To account for the aforementioned case, we need to check each non-parameter
396  // and non-return value for the possibility of acting as an intermediate.
397  // 'ValueMap' here records, for each value, which InterfaceValues read from or
398  // write into it. If both the read list and the write list of a given value
399  // are non-empty, we know that a particular value is an intermidate and we
400  // need to add summary edges from the writes to the reads.
402  for (const auto &OuterMapping : ReachSet.value_mappings()) {
403  if (auto Dst = getInterfaceValue(OuterMapping.first, RetVals)) {
404  for (const auto &InnerMapping : OuterMapping.second) {
405  // If Src is a param/return value, we get a same-level assignment.
406  if (auto Src = getInterfaceValue(InnerMapping.first, RetVals)) {
407  // This may happen if both Dst and Src are return values
408  if (*Dst == *Src)
409  continue;
410 
411  if (hasReadOnlyState(InnerMapping.second))
412  ExtRelations.push_back(ExternalRelation{*Dst, *Src, UnknownOffset});
413  // No need to check for WriteOnly state, since ReachSet is symmetric
414  } else {
415  // If Src is not a param/return, add it to ValueMap
416  auto SrcIVal = InnerMapping.first;
417  if (hasReadOnlyState(InnerMapping.second))
418  ValueMap[SrcIVal.Val].FromRecords.push_back(
419  ValueSummary::Record{*Dst, SrcIVal.DerefLevel});
420  if (hasWriteOnlyState(InnerMapping.second))
421  ValueMap[SrcIVal.Val].ToRecords.push_back(
422  ValueSummary::Record{*Dst, SrcIVal.DerefLevel});
423  }
424  }
425  }
426  }
427 
428  for (const auto &Mapping : ValueMap) {
429  for (const auto &FromRecord : Mapping.second.FromRecords) {
430  for (const auto &ToRecord : Mapping.second.ToRecords) {
431  auto ToLevel = ToRecord.DerefLevel;
432  auto FromLevel = FromRecord.DerefLevel;
433  // Same-level assignments should have already been processed by now
434  if (ToLevel == FromLevel)
435  continue;
436 
437  auto SrcIndex = FromRecord.IValue.Index;
438  auto SrcLevel = FromRecord.IValue.DerefLevel;
439  auto DstIndex = ToRecord.IValue.Index;
440  auto DstLevel = ToRecord.IValue.DerefLevel;
441  if (ToLevel > FromLevel)
442  SrcLevel += ToLevel - FromLevel;
443  else
444  DstLevel += FromLevel - ToLevel;
445 
446  ExtRelations.push_back(ExternalRelation{
447  InterfaceValue{SrcIndex, SrcLevel},
448  InterfaceValue{DstIndex, DstLevel}, UnknownOffset});
449  }
450  }
451  }
452 
453  // Remove duplicates in ExtRelations
454  std::sort(ExtRelations.begin(), ExtRelations.end());
455  ExtRelations.erase(std::unique(ExtRelations.begin(), ExtRelations.end()),
456  ExtRelations.end());
457 }
458 
460  SmallVectorImpl<ExternalAttribute> &ExtAttributes, const Function &Fn,
461  const SmallVectorImpl<Value *> &RetVals, const AliasAttrMap &AMap) {
462  for (const auto &Mapping : AMap.mappings()) {
463  if (auto IVal = getInterfaceValue(Mapping.first, RetVals)) {
464  auto Attr = getExternallyVisibleAttrs(Mapping.second);
465  if (Attr.any())
466  ExtAttributes.push_back(ExternalAttribute{*IVal, Attr});
467  }
468  }
469 }
470 
472  const Function &Fn, const SmallVectorImpl<Value *> &RetVals,
473  const ReachabilitySet &ReachSet, AliasAttrMap AMap) {
474  populateAttrMap(AttrMap, AMap);
475  populateExternalAttributes(Summary.RetParamAttributes, Fn, RetVals, AMap);
476  populateAliasMap(AliasMap, ReachSet);
477  populateExternalRelations(Summary.RetParamRelations, Fn, RetVals, ReachSet);
478 }
479 
481 CFLAndersAAResult::FunctionInfo::getAttrs(const Value *V) const {
482  assert(V != nullptr);
483 
484  auto Itr = AttrMap.find(V);
485  if (Itr != AttrMap.end())
486  return Itr->second;
487  return None;
488 }
489 
491  uint64_t LHSSize,
492  const Value *RHS,
493  uint64_t RHSSize) const {
494  assert(LHS && RHS);
495 
496  // Check if we've seen LHS and RHS before. Sometimes LHS or RHS can be created
497  // after the analysis gets executed, and we want to be conservative in those
498  // cases.
499  auto MaybeAttrsA = getAttrs(LHS);
500  auto MaybeAttrsB = getAttrs(RHS);
501  if (!MaybeAttrsA || !MaybeAttrsB)
502  return true;
503 
504  // Check AliasAttrs before AliasMap lookup since it's cheaper
505  auto AttrsA = *MaybeAttrsA;
506  auto AttrsB = *MaybeAttrsB;
507  if (hasUnknownOrCallerAttr(AttrsA))
508  return AttrsB.any();
509  if (hasUnknownOrCallerAttr(AttrsB))
510  return AttrsA.any();
511  if (isGlobalOrArgAttr(AttrsA))
512  return isGlobalOrArgAttr(AttrsB);
513  if (isGlobalOrArgAttr(AttrsB))
514  return isGlobalOrArgAttr(AttrsA);
515 
516  // At this point both LHS and RHS should point to locally allocated objects
517 
518  auto Itr = AliasMap.find(LHS);
519  if (Itr != AliasMap.end()) {
520 
521  // Find out all (X, Offset) where X == RHS
522  auto Comparator = [](OffsetValue LHS, OffsetValue RHS) {
523  return std::less<const Value *>()(LHS.Val, RHS.Val);
524  };
525 #ifdef EXPENSIVE_CHECKS
526  assert(std::is_sorted(Itr->second.begin(), Itr->second.end(), Comparator));
527 #endif
528  auto RangePair = std::equal_range(Itr->second.begin(), Itr->second.end(),
529  OffsetValue{RHS, 0}, Comparator);
530 
531  if (RangePair.first != RangePair.second) {
532  // Be conservative about UnknownSize
533  if (LHSSize == MemoryLocation::UnknownSize ||
534  RHSSize == MemoryLocation::UnknownSize)
535  return true;
536 
537  for (const auto &OVal : make_range(RangePair)) {
538  // Be conservative about UnknownOffset
539  if (OVal.Offset == UnknownOffset)
540  return true;
541 
542  // We know that LHS aliases (RHS + OVal.Offset) if the control flow
543  // reaches here. The may-alias query essentially becomes integer
544  // range-overlap queries over two ranges [OVal.Offset, OVal.Offset +
545  // LHSSize) and [0, RHSSize).
546 
547  // Try to be conservative on super large offsets
548  if (LLVM_UNLIKELY(LHSSize > INT64_MAX || RHSSize > INT64_MAX))
549  return true;
550 
551  auto LHSStart = OVal.Offset;
552  // FIXME: Do we need to guard against integer overflow?
553  auto LHSEnd = OVal.Offset + static_cast<int64_t>(LHSSize);
554  auto RHSStart = 0;
555  auto RHSEnd = static_cast<int64_t>(RHSSize);
556  if (LHSEnd > RHSStart && LHSStart < RHSEnd)
557  return true;
558  }
559  }
560  }
561 
562  return false;
563 }
564 
566  MatchState State, ReachabilitySet &ReachSet,
567  std::vector<WorkListItem> &WorkList) {
568  if (From == To)
569  return;
570  if (ReachSet.insert(From, To, State))
571  WorkList.push_back(WorkListItem{From, To, State});
572 }
573 
574 static void initializeWorkList(std::vector<WorkListItem> &WorkList,
575  ReachabilitySet &ReachSet,
576  const CFLGraph &Graph) {
577  for (const auto &Mapping : Graph.value_mappings()) {
578  auto Val = Mapping.first;
579  auto &ValueInfo = Mapping.second;
580  assert(ValueInfo.getNumLevels() > 0);
581 
582  // Insert all immediate assignment neighbors to the worklist
583  for (unsigned I = 0, E = ValueInfo.getNumLevels(); I < E; ++I) {
584  auto Src = InstantiatedValue{Val, I};
585  // If there's an assignment edge from X to Y, it means Y is reachable from
586  // X at S2 and X is reachable from Y at S1
587  for (auto &Edge : ValueInfo.getNodeInfoAtLevel(I).Edges) {
588  propagate(Edge.Other, Src, MatchState::FlowFromReadOnly, ReachSet,
589  WorkList);
590  propagate(Src, Edge.Other, MatchState::FlowToWriteOnly, ReachSet,
591  WorkList);
592  }
593  }
594  }
595 }
596 
598  InstantiatedValue V) {
599  auto NodeBelow = InstantiatedValue{V.Val, V.DerefLevel + 1};
600  if (Graph.getNode(NodeBelow))
601  return NodeBelow;
602  return None;
603 }
604 
605 static void processWorkListItem(const WorkListItem &Item, const CFLGraph &Graph,
606  ReachabilitySet &ReachSet, AliasMemSet &MemSet,
607  std::vector<WorkListItem> &WorkList) {
608  auto FromNode = Item.From;
609  auto ToNode = Item.To;
610 
611  auto NodeInfo = Graph.getNode(ToNode);
612  assert(NodeInfo != nullptr);
613 
614  // TODO: propagate field offsets
615 
616  // FIXME: Here is a neat trick we can do: since both ReachSet and MemSet holds
617  // relations that are symmetric, we could actually cut the storage by half by
618  // sorting FromNode and ToNode before insertion happens.
619 
620  // The newly added value alias pair may pontentially generate more memory
621  // alias pairs. Check for them here.
622  auto FromNodeBelow = getNodeBelow(Graph, FromNode);
623  auto ToNodeBelow = getNodeBelow(Graph, ToNode);
624  if (FromNodeBelow && ToNodeBelow &&
625  MemSet.insert(*FromNodeBelow, *ToNodeBelow)) {
626  propagate(*FromNodeBelow, *ToNodeBelow,
627  MatchState::FlowFromMemAliasNoReadWrite, ReachSet, WorkList);
628  for (const auto &Mapping : ReachSet.reachableValueAliases(*FromNodeBelow)) {
629  auto Src = Mapping.first;
630  auto MemAliasPropagate = [&](MatchState FromState, MatchState ToState) {
631  if (Mapping.second.test(static_cast<size_t>(FromState)))
632  propagate(Src, *ToNodeBelow, ToState, ReachSet, WorkList);
633  };
634 
635  MemAliasPropagate(MatchState::FlowFromReadOnly,
636  MatchState::FlowFromMemAliasReadOnly);
637  MemAliasPropagate(MatchState::FlowToWriteOnly,
638  MatchState::FlowToMemAliasWriteOnly);
639  MemAliasPropagate(MatchState::FlowToReadWrite,
640  MatchState::FlowToMemAliasReadWrite);
641  }
642  }
643 
644  // This is the core of the state machine walking algorithm. We expand ReachSet
645  // based on which state we are at (which in turn dictates what edges we
646  // should examine)
647  // From a high-level point of view, the state machine here guarantees two
648  // properties:
649  // - If *X and *Y are memory aliases, then X and Y are value aliases
650  // - If Y is an alias of X, then reverse assignment edges (if there is any)
651  // should precede any assignment edges on the path from X to Y.
652  auto NextAssignState = [&](MatchState State) {
653  for (const auto &AssignEdge : NodeInfo->Edges)
654  propagate(FromNode, AssignEdge.Other, State, ReachSet, WorkList);
655  };
656  auto NextRevAssignState = [&](MatchState State) {
657  for (const auto &RevAssignEdge : NodeInfo->ReverseEdges)
658  propagate(FromNode, RevAssignEdge.Other, State, ReachSet, WorkList);
659  };
660  auto NextMemState = [&](MatchState State) {
661  if (auto AliasSet = MemSet.getMemoryAliases(ToNode)) {
662  for (const auto &MemAlias : *AliasSet)
663  propagate(FromNode, MemAlias, State, ReachSet, WorkList);
664  }
665  };
666 
667  switch (Item.State) {
668  case MatchState::FlowFromReadOnly: {
669  NextRevAssignState(MatchState::FlowFromReadOnly);
670  NextAssignState(MatchState::FlowToReadWrite);
671  NextMemState(MatchState::FlowFromMemAliasReadOnly);
672  break;
673  }
674  case MatchState::FlowFromMemAliasNoReadWrite: {
675  NextRevAssignState(MatchState::FlowFromReadOnly);
676  NextAssignState(MatchState::FlowToWriteOnly);
677  break;
678  }
679  case MatchState::FlowFromMemAliasReadOnly: {
680  NextRevAssignState(MatchState::FlowFromReadOnly);
681  NextAssignState(MatchState::FlowToReadWrite);
682  break;
683  }
684  case MatchState::FlowToWriteOnly: {
685  NextAssignState(MatchState::FlowToWriteOnly);
686  NextMemState(MatchState::FlowToMemAliasWriteOnly);
687  break;
688  }
689  case MatchState::FlowToReadWrite: {
690  NextAssignState(MatchState::FlowToReadWrite);
691  NextMemState(MatchState::FlowToMemAliasReadWrite);
692  break;
693  }
694  case MatchState::FlowToMemAliasWriteOnly: {
695  NextAssignState(MatchState::FlowToWriteOnly);
696  break;
697  }
698  case MatchState::FlowToMemAliasReadWrite: {
699  NextAssignState(MatchState::FlowToReadWrite);
700  break;
701  }
702  }
703 }
704 
705 static AliasAttrMap buildAttrMap(const CFLGraph &Graph,
706  const ReachabilitySet &ReachSet) {
707  AliasAttrMap AttrMap;
708  std::vector<InstantiatedValue> WorkList, NextList;
709 
710  // Initialize each node with its original AliasAttrs in CFLGraph
711  for (const auto &Mapping : Graph.value_mappings()) {
712  auto Val = Mapping.first;
713  auto &ValueInfo = Mapping.second;
714  for (unsigned I = 0, E = ValueInfo.getNumLevels(); I < E; ++I) {
715  auto Node = InstantiatedValue{Val, I};
716  AttrMap.add(Node, ValueInfo.getNodeInfoAtLevel(I).Attr);
717  WorkList.push_back(Node);
718  }
719  }
720 
721  while (!WorkList.empty()) {
722  for (const auto &Dst : WorkList) {
723  auto DstAttr = AttrMap.getAttrs(Dst);
724  if (DstAttr.none())
725  continue;
726 
727  // Propagate attr on the same level
728  for (const auto &Mapping : ReachSet.reachableValueAliases(Dst)) {
729  auto Src = Mapping.first;
730  if (AttrMap.add(Src, DstAttr))
731  NextList.push_back(Src);
732  }
733 
734  // Propagate attr to the levels below
735  auto DstBelow = getNodeBelow(Graph, Dst);
736  while (DstBelow) {
737  if (AttrMap.add(*DstBelow, DstAttr)) {
738  NextList.push_back(*DstBelow);
739  break;
740  }
741  DstBelow = getNodeBelow(Graph, *DstBelow);
742  }
743  }
744  WorkList.swap(NextList);
745  NextList.clear();
746  }
747 
748  return AttrMap;
749 }
750 
752 CFLAndersAAResult::buildInfoFrom(const Function &Fn) {
754  *this, TLI,
755  // Cast away the constness here due to GraphBuilder's API requirement
756  const_cast<Function &>(Fn));
757  auto &Graph = GraphBuilder.getCFLGraph();
758 
759  ReachabilitySet ReachSet;
760  AliasMemSet MemSet;
761 
762  std::vector<WorkListItem> WorkList, NextList;
763  initializeWorkList(WorkList, ReachSet, Graph);
764  // TODO: make sure we don't stop before the fix point is reached
765  while (!WorkList.empty()) {
766  for (const auto &Item : WorkList)
767  processWorkListItem(Item, Graph, ReachSet, MemSet, NextList);
768 
769  NextList.swap(WorkList);
770  NextList.clear();
771  }
772 
773  // Now that we have all the reachability info, propagate AliasAttrs according
774  // to it
775  auto IValueAttrMap = buildAttrMap(Graph, ReachSet);
776 
777  return FunctionInfo(Fn, GraphBuilder.getReturnValues(), ReachSet,
778  std::move(IValueAttrMap));
779 }
780 
781 void CFLAndersAAResult::scan(const Function &Fn) {
782  auto InsertPair = Cache.insert(std::make_pair(&Fn, Optional<FunctionInfo>()));
783  (void)InsertPair;
784  assert(InsertPair.second &&
785  "Trying to scan a function that has already been cached");
786 
787  // Note that we can't do Cache[Fn] = buildSetsFrom(Fn) here: the function call
788  // may get evaluated after operator[], potentially triggering a DenseMap
789  // resize and invalidating the reference returned by operator[]
790  auto FunInfo = buildInfoFrom(Fn);
791  Cache[&Fn] = std::move(FunInfo);
792  Handles.push_front(FunctionHandle(const_cast<Function *>(&Fn), this));
793 }
794 
795 void CFLAndersAAResult::evict(const Function &Fn) { Cache.erase(&Fn); }
796 
798 CFLAndersAAResult::ensureCached(const Function &Fn) {
799  auto Iter = Cache.find(&Fn);
800  if (Iter == Cache.end()) {
801  scan(Fn);
802  Iter = Cache.find(&Fn);
803  assert(Iter != Cache.end());
804  assert(Iter->second.hasValue());
805  }
806  return Iter->second;
807 }
808 
809 const AliasSummary *CFLAndersAAResult::getAliasSummary(const Function &Fn) {
810  auto &FunInfo = ensureCached(Fn);
811  if (FunInfo.hasValue())
812  return &FunInfo->getAliasSummary();
813  else
814  return nullptr;
815 }
816 
817 AliasResult CFLAndersAAResult::query(const MemoryLocation &LocA,
818  const MemoryLocation &LocB) {
819  auto *ValA = LocA.Ptr;
820  auto *ValB = LocB.Ptr;
821 
822  if (!ValA->getType()->isPointerTy() || !ValB->getType()->isPointerTy())
823  return NoAlias;
824 
825  auto *Fn = parentFunctionOfValue(ValA);
826  if (!Fn) {
827  Fn = parentFunctionOfValue(ValB);
828  if (!Fn) {
829  // The only times this is known to happen are when globals + InlineAsm are
830  // involved
831  DEBUG(dbgs()
832  << "CFLAndersAA: could not extract parent function information.\n");
833  return MayAlias;
834  }
835  } else {
836  assert(!parentFunctionOfValue(ValB) || parentFunctionOfValue(ValB) == Fn);
837  }
838 
839  assert(Fn != nullptr);
840  auto &FunInfo = ensureCached(*Fn);
841 
842  // AliasMap lookup
843  if (FunInfo->mayAlias(ValA, LocA.Size, ValB, LocB.Size))
844  return MayAlias;
845  return NoAlias;
846 }
847 
848 AliasResult CFLAndersAAResult::alias(const MemoryLocation &LocA,
849  const MemoryLocation &LocB) {
850  if (LocA.Ptr == LocB.Ptr)
851  return LocA.Size == LocB.Size ? MustAlias : PartialAlias;
852 
853  // Comparisons between global variables and other constants should be
854  // handled by BasicAA.
855  // CFLAndersAA may report NoAlias when comparing a GlobalValue and
856  // ConstantExpr, but every query needs to have at least one Value tied to a
857  // Function, and neither GlobalValues nor ConstantExprs are.
858  if (isa<Constant>(LocA.Ptr) && isa<Constant>(LocB.Ptr))
859  return AAResultBase::alias(LocA, LocB);
860 
861  AliasResult QueryResult = query(LocA, LocB);
862  if (QueryResult == MayAlias)
863  return AAResultBase::alias(LocA, LocB);
864 
865  return QueryResult;
866 }
867 
868 AnalysisKey CFLAndersAA::Key;
869 
872 }
873 
876  "Inclusion-Based CFL Alias Analysis", false, true)
877 
879  return new CFLAndersAAWrapperPass();
880 }
881 
882 CFLAndersAAWrapperPass::CFLAndersAAWrapperPass() : ImmutablePass(ID) {
884 }
885 
887  auto &TLIWP = getAnalysis<TargetLibraryInfoWrapperPass>();
888  Result.reset(new CFLAndersAAResult(TLIWP.getTLI()));
889 }
890 
892  AU.setPreservesAll();
894 }
const NoneType None
Definition: None.h:23
The two locations precisely alias each other.
Definition: AliasAnalysis.h:85
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
This is the interface for LLVM's inclusion-based alias analysis implemented with CFL graph reachabili...
CFLAndersAAResult(const TargetLibraryInfo &)
We use ExternalRelation to describe an externally visible aliasing relations between parameters/retur...
static void populateAliasMap(DenseMap< const Value *, std::vector< OffsetValue >> &AliasMap, const ReachabilitySet &ReachSet)
#define LLVM_UNLIKELY(EXPR)
Definition: Compiler.h:182
Implements a dense probed hash-table based set.
Definition: DenseSet.h:202
The two locations alias, but only due to a partial overlap.
Definition: AliasAnalysis.h:83
This is the result of instantiating InterfaceValue at a particular callsite.
void initializeCFLAndersAAWrapperPassPass(PassRegistry &)
void initializePass() override
initializePass - This method may be overriden by immutable passes to allow them to perform various in...
The Program Expression Graph (PEG) of CFL analysis CFLGraph is auxiliary data structure used by CFL-b...
Definition: CFLGraph.h:37
The two locations do not alias at all.
Definition: AliasAnalysis.h:79
iterator_range< const_value_iterator > value_mappings() const
Definition: CFLGraph.h:128
The two locations may or may not alias. This is the least precise result.
Definition: AliasAnalysis.h:81
static void populateAttrMap(DenseMap< const Value *, AliasAttrs > &AttrMap, const AliasAttrMap &AMap)
We use ExternalAttribute to describe an externally visible AliasAttrs for parameters/return value...
We use InterfaceValue to describe parameters/return value, as well as potential memory locations that...
AnalysisUsage & addRequired()
const AliasSummary & getAliasSummary() const
static AliasAttrMap buildAttrMap(const CFLGraph &Graph, const ReachabilitySet &ReachSet)
INITIALIZE_PASS(CFLAndersAAWrapperPass,"cfl-anders-aa","Inclusion-Based CFL Alias Analysis", false, true) ImmutablePass *llvm
static bool isEqual(const OffsetValue &LHS, const OffsetValue &RHS)
static Optional< InterfaceValue > getInterfaceValue(InstantiatedValue IValue, const SmallVectorImpl< Value * > &RetVals)
A CRTP-driven "mixin" base class to help implement the function alias analysis results concept...
static void populateExternalAttributes(SmallVectorImpl< ExternalAttribute > &ExtAttributes, const Function &Fn, const SmallVectorImpl< Value * > &RetVals, const AliasAttrMap &AMap)
#define F(x, y, z)
Definition: MD5.cpp:51
static bool add(uint64_t *dest, const uint64_t *x, const uint64_t *y, unsigned len)
This function adds the integer array x to the integer array Y and places the result in dest...
Definition: APInt.cpp:239
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
static bool isEqual(const OffsetInstantiatedValue &LHS, const OffsetInstantiatedValue &RHS)
static const Function * parentFunctionOfValue(const Value *Val)
static GCRegistry::Add< CoreCLRGC > E("coreclr","CoreCLR-compatible GC")
static unsigned getHashValue(const OffsetInstantiatedValue &OVal)
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs...ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Definition: PassManager.h:653
static bool hasWriteOnlyState(StateSet Set)
Legacy wrapper pass to provide the CFLAndersAAResult object.
AliasResult
The possible results of an alias query.
Definition: AliasAnalysis.h:73
Represent the analysis usage information of a pass.
FunctionInfo(const Function &, const SmallVectorImpl< Value * > &, const ReachabilitySet &, AliasAttrMap)
uint32_t Offset
bool isGlobalOrArgAttr(AliasAttrs Attr)
bool mayAlias(const Value *, uint64_t, const Value *, uint64_t) const
Struct to hold value either by GUID or GlobalValue*.
const Value * Ptr
The address of the start of the location.
Representation for a specific memory location.
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
See the file comment.
Definition: ValueMap.h:87
ImmutablePass class - This class is used to provide information that does not need to be run...
Definition: Pass.h:266
static void initializeWorkList(std::vector< WorkListItem > &WorkList, ReachabilitySet &ReachSet, const CFLGraph &Graph)
AliasAttrs getExternallyVisibleAttrs(AliasAttrs Attr)
Given an AliasAttrs, return a new AliasAttrs that only contains attributes meaningful to the caller...
A builder class used to create CFLGraph instance from a given function The CFL-AA that uses this buil...
Definition: CFLGraph.h:142
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small...
Definition: SmallVector.h:843
Provides information about what library functions are available for the current target.
Alias summary information.
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:132
A range adaptor for a pair of iterators.
void setPreservesAll()
Set by analyses that do not transform their input at all.
This file defines CFLGraph, an auxiliary data structure used by CFL-based alias analysis.
static void propagate(InstantiatedValue From, InstantiatedValue To, MatchState State, ReachabilitySet &ReachSet, std::vector< WorkListItem > &WorkList)
static const int64_t UnknownOffset
#define I(x, y, z)
Definition: MD5.cpp:54
static Optional< InstantiatedValue > getNodeBelow(const CFLGraph &Graph, InstantiatedValue V)
static void processWorkListItem(const WorkListItem &Item, const CFLGraph &Graph, ReachabilitySet &ReachSet, AliasMemSet &MemSet, std::vector< WorkListItem > &WorkList)
bool hasUnknownOrCallerAttr(AliasAttrs Attr)
std::bitset< NumAliasAttrs > AliasAttrs
These are attributes that an alias analysis can use to mark certain special properties of a given poi...
static bool hasReadOnlyState(StateSet Set)
Analysis pass providing the TargetLibraryInfo.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
bool operator<(int64_t V1, const APSInt &V2)
Definition: APSInt.h:326
Module * getParent()
Get the module that this global value is contained inside of...
Definition: GlobalValue.h:537
LLVM Value Representation.
Definition: Value.h:71
#define DEBUG(X)
Definition: Debug.h:100
A container for analyses that lazily runs them and caches their results.
static void populateExternalRelations(SmallVectorImpl< ExternalRelation > &ExtRelations, const Function &Fn, const SmallVectorImpl< Value * > &RetVals, const ReachabilitySet &ReachSet)
bool operator==(uint64_t V1, const APInt &V2)
Definition: APInt.h:1722
ImmutablePass * createCFLAndersAAWrapperPass()
static unsigned getHashValue(const OffsetValue &OVal)
A special type used by analysis passes to provide an address that identifies that particular analysis...
Definition: PassManager.h:64
static Expected< BitVector > scan(StringRef &S, StringRef Original)
Definition: GlobPattern.cpp:64
iterator_range< arg_iterator > args()
Definition: Function.h:568
uint64_t Size
The maximum size of the location, in address-units, or UnknownSize if the size is not known...
bool is_contained(R &&Range, const E &Element)
Wrapper function around std::find to detect if an element exists in a container.
Definition: STLExtras.h:783