LLVM  4.0.0
CFLSteensAliasAnalysis.cpp
Go to the documentation of this file.
1 //- CFLSteensAliasAnalysis.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-base, summary-based alias analysis algorithm. It
11 // does not depend on types. The algorithm is a mixture of the one described in
12 // "Demand-driven alias analysis for C" by Xin Zheng and Radu Rugina, and "Fast
13 // algorithms for Dyck-CFL-reachability with applications to Alias Analysis" by
14 // Zhang Q, Lyu M R, Yuan H, and Su Z. -- to summarize the papers, we build a
15 // graph of the uses of a variable, where each node is a memory location, and
16 // each edge is an action that happened on that memory location. The "actions"
17 // can be one of Dereference, Reference, or Assign. The precision of this
18 // analysis is roughly the same as that of an one level context-sensitive
19 // Steensgaard's algorithm.
20 //
21 // Two variables are considered as aliasing iff you can reach one value's node
22 // from the other value's node and the language formed by concatenating all of
23 // the edge labels (actions) conforms to a context-free grammar.
24 //
25 // Because this algorithm requires a graph search on each query, we execute the
26 // algorithm outlined in "Fast algorithms..." (mentioned above)
27 // in order to transform the graph into sets of variables that may alias in
28 // ~nlogn time (n = number of variables), which makes queries take constant
29 // time.
30 //===----------------------------------------------------------------------===//
31 
32 // N.B. AliasAnalysis as a whole is phrased as a FunctionPass at the moment, and
33 // CFLSteensAA is interprocedural. This is *technically* A Bad Thing, because
34 // FunctionPasses are only allowed to inspect the Function that they're being
35 // run on. Realistically, this likely isn't a problem until we allow
36 // FunctionPasses to run concurrently.
37 
39 #include "CFLGraph.h"
40 #include "StratifiedSets.h"
41 #include "llvm/ADT/DenseMap.h"
42 #include "llvm/ADT/None.h"
43 #include "llvm/ADT/Optional.h"
45 #include "llvm/IR/Constants.h"
46 #include "llvm/IR/Function.h"
47 #include "llvm/Pass.h"
48 #include "llvm/Support/Compiler.h"
49 #include "llvm/Support/Debug.h"
52 #include <algorithm>
53 #include <cassert>
54 #include <memory>
55 #include <tuple>
56 
57 using namespace llvm;
58 using namespace llvm::cflaa;
59 
60 #define DEBUG_TYPE "cfl-steens-aa"
61 
63  : AAResultBase(), TLI(TLI) {}
65  : AAResultBase(std::move(Arg)), TLI(Arg.TLI) {}
67 
68 /// Information we have about a function and would like to keep around.
71  AliasSummary Summary;
72 
73 public:
76 
78  return Sets;
79  }
80  const AliasSummary &getAliasSummary() const { return Summary; }
81 };
82 
83 /// Try to go from a Value* to a Function*. Never returns nullptr.
85 
86 const StratifiedIndex StratifiedLink::SetSentinel =
87  std::numeric_limits<StratifiedIndex>::max();
88 
89 //===----------------------------------------------------------------------===//
90 // Function declarations that require types defined in the namespace above
91 //===----------------------------------------------------------------------===//
92 
93 /// Determines whether it would be pointless to add the given Value to our sets.
94 static bool canSkipAddingToSets(Value *Val);
95 
97  if (auto *Inst = dyn_cast<Instruction>(Val)) {
98  auto *Bb = Inst->getParent();
99  return Bb->getParent();
100  }
101 
102  if (auto *Arg = dyn_cast<Argument>(Val))
103  return Arg->getParent();
104  return None;
105 }
106 
107 static bool canSkipAddingToSets(Value *Val) {
108  // Constants can share instances, which may falsely unify multiple
109  // sets, e.g. in
110  // store i32* null, i32** %ptr1
111  // store i32* null, i32** %ptr2
112  // clearly ptr1 and ptr2 should not be unified into the same set, so
113  // we should filter out the (potentially shared) instance to
114  // i32* null.
115  if (isa<Constant>(Val)) {
116  // TODO: Because all of these things are constant, we can determine whether
117  // the data is *actually* mutable at graph building time. This will probably
118  // come for free/cheap with offset awareness.
119  bool CanStoreMutableData = isa<GlobalValue>(Val) ||
120  isa<ConstantExpr>(Val) ||
121  isa<ConstantAggregate>(Val);
122  return !CanStoreMutableData;
123  }
124 
125  return false;
126 }
127 
129  Function &Fn, const SmallVectorImpl<Value *> &RetVals,
131  : Sets(std::move(S)) {
132  // Historically, an arbitrary upper-bound of 50 args was selected. We may want
133  // to remove this if it doesn't really matter in practice.
135  return;
136 
138 
139  // Our intention here is to record all InterfaceValues that share the same
140  // StratifiedIndex in RetParamRelations. For each valid InterfaceValue, we
141  // have its StratifiedIndex scanned here and check if the index is presented
142  // in InterfaceMap: if it is not, we add the correspondence to the map;
143  // otherwise, an aliasing relation is found and we add it to
144  // RetParamRelations.
145 
146  auto AddToRetParamRelations = [&](unsigned InterfaceIndex,
147  StratifiedIndex SetIndex) {
148  unsigned Level = 0;
149  while (true) {
150  InterfaceValue CurrValue{InterfaceIndex, Level};
151 
152  auto Itr = InterfaceMap.find(SetIndex);
153  if (Itr != InterfaceMap.end()) {
154  if (CurrValue != Itr->second)
155  Summary.RetParamRelations.push_back(
156  ExternalRelation{CurrValue, Itr->second, UnknownOffset});
157  break;
158  }
159 
160  auto &Link = Sets.getLink(SetIndex);
161  InterfaceMap.insert(std::make_pair(SetIndex, CurrValue));
162  auto ExternalAttrs = getExternallyVisibleAttrs(Link.Attrs);
163  if (ExternalAttrs.any())
164  Summary.RetParamAttributes.push_back(
165  ExternalAttribute{CurrValue, ExternalAttrs});
166 
167  if (!Link.hasBelow())
168  break;
169 
170  ++Level;
171  SetIndex = Link.Below;
172  }
173  };
174 
175  // Populate RetParamRelations for return values
176  for (auto *RetVal : RetVals) {
177  assert(RetVal != nullptr);
178  assert(RetVal->getType()->isPointerTy());
179  auto RetInfo = Sets.find(InstantiatedValue{RetVal, 0});
180  if (RetInfo.hasValue())
181  AddToRetParamRelations(0, RetInfo->Index);
182  }
183 
184  // Populate RetParamRelations for parameters
185  unsigned I = 0;
186  for (auto &Param : Fn.args()) {
187  if (Param.getType()->isPointerTy()) {
188  auto ParamInfo = Sets.find(InstantiatedValue{&Param, 0});
189  if (ParamInfo.hasValue())
190  AddToRetParamRelations(I + 1, ParamInfo->Index);
191  }
192  ++I;
193  }
194 }
195 
196 // Builds the graph + StratifiedSets for a function.
197 CFLSteensAAResult::FunctionInfo CFLSteensAAResult::buildSetsFrom(Function *Fn) {
198  CFLGraphBuilder<CFLSteensAAResult> GraphBuilder(*this, TLI, *Fn);
200 
201  // Add all CFLGraph nodes and all Dereference edges to StratifiedSets
202  auto &Graph = GraphBuilder.getCFLGraph();
203  for (const auto &Mapping : Graph.value_mappings()) {
204  auto Val = Mapping.first;
205  if (canSkipAddingToSets(Val))
206  continue;
207  auto &ValueInfo = Mapping.second;
208 
209  assert(ValueInfo.getNumLevels() > 0);
210  SetBuilder.add(InstantiatedValue{Val, 0});
211  SetBuilder.noteAttributes(InstantiatedValue{Val, 0},
212  ValueInfo.getNodeInfoAtLevel(0).Attr);
213  for (unsigned I = 0, E = ValueInfo.getNumLevels() - 1; I < E; ++I) {
214  SetBuilder.add(InstantiatedValue{Val, I + 1});
215  SetBuilder.noteAttributes(InstantiatedValue{Val, I + 1},
216  ValueInfo.getNodeInfoAtLevel(I + 1).Attr);
217  SetBuilder.addBelow(InstantiatedValue{Val, I},
218  InstantiatedValue{Val, I + 1});
219  }
220  }
221 
222  // Add all assign edges to StratifiedSets
223  for (const auto &Mapping : Graph.value_mappings()) {
224  auto Val = Mapping.first;
225  if (canSkipAddingToSets(Val))
226  continue;
227  auto &ValueInfo = Mapping.second;
228 
229  for (unsigned I = 0, E = ValueInfo.getNumLevels(); I < E; ++I) {
230  auto Src = InstantiatedValue{Val, I};
231  for (auto &Edge : ValueInfo.getNodeInfoAtLevel(I).Edges)
232  SetBuilder.addWith(Src, Edge.Other);
233  }
234  }
235 
236  return FunctionInfo(*Fn, GraphBuilder.getReturnValues(), SetBuilder.build());
237 }
238 
240  auto InsertPair = Cache.insert(std::make_pair(Fn, Optional<FunctionInfo>()));
241  (void)InsertPair;
242  assert(InsertPair.second &&
243  "Trying to scan a function that has already been cached");
244 
245  // Note that we can't do Cache[Fn] = buildSetsFrom(Fn) here: the function call
246  // may get evaluated after operator[], potentially triggering a DenseMap
247  // resize and invalidating the reference returned by operator[]
248  auto FunInfo = buildSetsFrom(Fn);
249  Cache[Fn] = std::move(FunInfo);
250 
251  Handles.push_front(FunctionHandle(Fn, this));
252 }
253 
254 void CFLSteensAAResult::evict(Function *Fn) { Cache.erase(Fn); }
255 
256 /// Ensures that the given function is available in the cache, and returns the
257 /// entry.
260  auto Iter = Cache.find(Fn);
261  if (Iter == Cache.end()) {
262  scan(Fn);
263  Iter = Cache.find(Fn);
264  assert(Iter != Cache.end());
265  assert(Iter->second.hasValue());
266  }
267  return Iter->second;
268 }
269 
271  auto &FunInfo = ensureCached(&Fn);
272  if (FunInfo.hasValue())
273  return &FunInfo->getAliasSummary();
274  else
275  return nullptr;
276 }
277 
279  const MemoryLocation &LocB) {
280  auto *ValA = const_cast<Value *>(LocA.Ptr);
281  auto *ValB = const_cast<Value *>(LocB.Ptr);
282 
283  if (!ValA->getType()->isPointerTy() || !ValB->getType()->isPointerTy())
284  return NoAlias;
285 
286  Function *Fn = nullptr;
287  auto MaybeFnA = parentFunctionOfValue(ValA);
288  auto MaybeFnB = parentFunctionOfValue(ValB);
289  if (!MaybeFnA.hasValue() && !MaybeFnB.hasValue()) {
290  // The only times this is known to happen are when globals + InlineAsm are
291  // involved
292  DEBUG(dbgs()
293  << "CFLSteensAA: could not extract parent function information.\n");
294  return MayAlias;
295  }
296 
297  if (MaybeFnA.hasValue()) {
298  Fn = *MaybeFnA;
299  assert((!MaybeFnB.hasValue() || *MaybeFnB == *MaybeFnA) &&
300  "Interprocedural queries not supported");
301  } else {
302  Fn = *MaybeFnB;
303  }
304 
305  assert(Fn != nullptr);
306  auto &MaybeInfo = ensureCached(Fn);
307  assert(MaybeInfo.hasValue());
308 
309  auto &Sets = MaybeInfo->getStratifiedSets();
310  auto MaybeA = Sets.find(InstantiatedValue{ValA, 0});
311  if (!MaybeA.hasValue())
312  return MayAlias;
313 
314  auto MaybeB = Sets.find(InstantiatedValue{ValB, 0});
315  if (!MaybeB.hasValue())
316  return MayAlias;
317 
318  auto SetA = *MaybeA;
319  auto SetB = *MaybeB;
320  auto AttrsA = Sets.getLink(SetA.Index).Attrs;
321  auto AttrsB = Sets.getLink(SetB.Index).Attrs;
322 
323  // If both values are local (meaning the corresponding set has attribute
324  // AttrNone or AttrEscaped), then we know that CFLSteensAA fully models them:
325  // they may-alias each other if and only if they are in the same set.
326  // If at least one value is non-local (meaning it either is global/argument or
327  // it comes from unknown sources like integer cast), the situation becomes a
328  // bit more interesting. We follow three general rules described below:
329  // - Non-local values may alias each other
330  // - AttrNone values do not alias any non-local values
331  // - AttrEscaped do not alias globals/arguments, but they may alias
332  // AttrUnknown values
333  if (SetA.Index == SetB.Index)
334  return MayAlias;
335  if (AttrsA.none() || AttrsB.none())
336  return NoAlias;
337  if (hasUnknownOrCallerAttr(AttrsA) || hasUnknownOrCallerAttr(AttrsB))
338  return MayAlias;
339  if (isGlobalOrArgAttr(AttrsA) && isGlobalOrArgAttr(AttrsB))
340  return MayAlias;
341  return NoAlias;
342 }
343 
344 AnalysisKey CFLSteensAA::Key;
345 
348 }
349 
352  "Unification-Based CFL Alias Analysis", false, true)
353 
355  return new CFLSteensAAWrapperPass();
356 }
357 
360 }
361 
363  auto &TLIWP = getAnalysis<TargetLibraryInfoWrapperPass>();
364  Result.reset(new CFLSteensAAResult(TLIWP.getTLI()));
365 }
366 
368  AU.setPreservesAll();
370 }
const NoneType None
Definition: None.h:23
const cflaa::AliasSummary * getAliasSummary(Function &Fn)
Get the alias summary for the given function Return nullptr if the summary is not found or not availa...
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
const AliasSummary & getAliasSummary() const
We use ExternalRelation to describe an externally visible aliasing relations between parameters/retur...
StratifiedSets< T > build()
Builds a StratifiedSet from the information we've been given since either construction or the prior b...
This is the result of instantiating InterfaceValue at a particular callsite.
const Optional< FunctionInfo > & ensureCached(Function *Fn)
Ensures that the given function is available in the cache.
The two locations do not alias at all.
Definition: AliasAnalysis.h:79
FunctionInfo(Function &Fn, const SmallVectorImpl< Value * > &RetVals, StratifiedSets< InstantiatedValue > S)
The two locations may or may not alias. This is the least precise result.
Definition: AliasAnalysis.h:81
We use ExternalAttribute to describe an externally visible AliasAttrs for parameters/return value...
size_t arg_size() const
Definition: Function.cpp:327
We use InterfaceValue to describe parameters/return value, as well as potential memory locations that...
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Definition: DenseMap.h:172
AnalysisUsage & addRequired()
const StratifiedSets< InstantiatedValue > & getStratifiedSets() const
CFLSteensAAResult run(Function &F, FunctionAnalysisManager &AM)
bool addWith(const T &Main, const T &ToAdd)
A CRTP-driven "mixin" base class to help implement the function alias analysis results concept...
CFLSteensAAResult(const TargetLibraryInfo &)
#define F(x, y, z)
Definition: MD5.cpp:51
Legacy wrapper pass to provide the CFLSteensAAResult object.
void scan(Function *Fn)
Inserts the given Function into the cache.
static GCRegistry::Add< CoreCLRGC > E("coreclr","CoreCLR-compatible GC")
This is the interface for LLVM's unification-based alias analysis implemented with CFL graph reachabi...
void initializePass() override
initializePass - This method may be overriden by immutable passes to allow them to perform various in...
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs...ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Definition: PassManager.h:653
This file contains the declarations for the subclasses of Constant, which represent the different fla...
AliasResult
The possible results of an alias query.
Definition: AliasAnalysis.h:73
Represent the analysis usage information of a pass.
bool isGlobalOrArgAttr(AliasAttrs Attr)
AliasResult query(const MemoryLocation &LocA, const MemoryLocation &LocB)
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.
ImmutablePass class - This class is used to provide information that does not need to be run...
Definition: Pass.h:266
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
Provides information about what library functions are available for the current target.
static bool canSkipAddingToSets(Value *Val)
Determines whether it would be pointless to add the given Value to our sets.
bool addBelow(const T &Main, const T &ToAdd)
Restructures the stratified sets as necessary to make "ToAdd" in a set below "Main".
const StratifiedLink & getLink(StratifiedIndex Index) const
Alias summary information.
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:132
Information we have about a function and would like to keep around.
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 const int64_t UnknownOffset
INITIALIZE_PASS(CFLSteensAAWrapperPass,"cfl-steens-aa","Unification-Based CFL Alias Analysis", false, true) ImmutablePass *llvm
#define I(x, y, z)
Definition: MD5.cpp:54
bool hasUnknownOrCallerAttr(AliasAttrs Attr)
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
ImmutablePass * createCFLSteensAAWrapperPass()
Analysis pass providing the TargetLibraryInfo.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
void initializeCFLSteensAAWrapperPassPass(PassRegistry &)
Generic Builder class that produces StratifiedSets instances.
LLVM Value Representation.
Definition: Value.h:71
static const unsigned MaxSupportedArgsInSummary
The maximum number of arguments we can put into a summary.
#define DEBUG(X)
Definition: Debug.h:100
A container for analyses that lazily runs them and caches their results.
A special type used by analysis passes to provide an address that identifies that particular analysis...
Definition: PassManager.h:64
void noteAttributes(const T &Main, AliasAttrs NewAttrs)
static Optional< Function * > parentFunctionOfValue(Value *)
Try to go from a Value* to a Function*. Never returns nullptr.