CFLSteensAliasAnalysis.cpp revision 303231
1303231Sdim//- CFLSteensAliasAnalysis.cpp - Unification-based Alias Analysis ---*- C++-*-//
2303231Sdim//
3303231Sdim//                     The LLVM Compiler Infrastructure
4303231Sdim//
5303231Sdim// This file is distributed under the University of Illinois Open Source
6303231Sdim// License. See LICENSE.TXT for details.
7303231Sdim//
8303231Sdim//===----------------------------------------------------------------------===//
9303231Sdim//
10303231Sdim// This file implements a CFL-base, summary-based alias analysis algorithm. It
11303231Sdim// does not depend on types. The algorithm is a mixture of the one described in
12303231Sdim// "Demand-driven alias analysis for C" by Xin Zheng and Radu Rugina, and "Fast
13303231Sdim// algorithms for Dyck-CFL-reachability with applications to Alias Analysis" by
14303231Sdim// Zhang Q, Lyu M R, Yuan H, and Su Z. -- to summarize the papers, we build a
15303231Sdim// graph of the uses of a variable, where each node is a memory location, and
16303231Sdim// each edge is an action that happened on that memory location.  The "actions"
17303231Sdim// can be one of Dereference, Reference, or Assign. The precision of this
18303231Sdim// analysis is roughly the same as that of an one level context-sensitive
19303231Sdim// Steensgaard's algorithm.
20303231Sdim//
21303231Sdim// Two variables are considered as aliasing iff you can reach one value's node
22303231Sdim// from the other value's node and the language formed by concatenating all of
23303231Sdim// the edge labels (actions) conforms to a context-free grammar.
24303231Sdim//
25303231Sdim// Because this algorithm requires a graph search on each query, we execute the
26303231Sdim// algorithm outlined in "Fast algorithms..." (mentioned above)
27303231Sdim// in order to transform the graph into sets of variables that may alias in
28303231Sdim// ~nlogn time (n = number of variables), which makes queries take constant
29303231Sdim// time.
30303231Sdim//===----------------------------------------------------------------------===//
31303231Sdim
32303231Sdim// N.B. AliasAnalysis as a whole is phrased as a FunctionPass at the moment, and
33303231Sdim// CFLSteensAA is interprocedural. This is *technically* A Bad Thing, because
34303231Sdim// FunctionPasses are only allowed to inspect the Function that they're being
35303231Sdim// run on. Realistically, this likely isn't a problem until we allow
36303231Sdim// FunctionPasses to run concurrently.
37303231Sdim
38303231Sdim#include "llvm/Analysis/CFLSteensAliasAnalysis.h"
39303231Sdim#include "CFLGraph.h"
40303231Sdim#include "StratifiedSets.h"
41303231Sdim#include "llvm/ADT/DenseMap.h"
42303231Sdim#include "llvm/ADT/None.h"
43303231Sdim#include "llvm/ADT/Optional.h"
44303231Sdim#include "llvm/Analysis/TargetLibraryInfo.h"
45303231Sdim#include "llvm/IR/Constants.h"
46303231Sdim#include "llvm/IR/Function.h"
47303231Sdim#include "llvm/Pass.h"
48303231Sdim#include "llvm/Support/Compiler.h"
49303231Sdim#include "llvm/Support/Debug.h"
50303231Sdim#include "llvm/Support/ErrorHandling.h"
51303231Sdim#include "llvm/Support/raw_ostream.h"
52303231Sdim#include <algorithm>
53303231Sdim#include <cassert>
54303231Sdim#include <memory>
55303231Sdim#include <tuple>
56303231Sdim
57303231Sdimusing namespace llvm;
58303231Sdimusing namespace llvm::cflaa;
59303231Sdim
60303231Sdim#define DEBUG_TYPE "cfl-steens-aa"
61303231Sdim
62303231SdimCFLSteensAAResult::CFLSteensAAResult(const TargetLibraryInfo &TLI)
63303231Sdim    : AAResultBase(), TLI(TLI) {}
64303231SdimCFLSteensAAResult::CFLSteensAAResult(CFLSteensAAResult &&Arg)
65303231Sdim    : AAResultBase(std::move(Arg)), TLI(Arg.TLI) {}
66303231SdimCFLSteensAAResult::~CFLSteensAAResult() {}
67303231Sdim
68303231Sdim/// Information we have about a function and would like to keep around.
69303231Sdimclass CFLSteensAAResult::FunctionInfo {
70303231Sdim  StratifiedSets<InstantiatedValue> Sets;
71303231Sdim  AliasSummary Summary;
72303231Sdim
73303231Sdimpublic:
74303231Sdim  FunctionInfo(Function &Fn, const SmallVectorImpl<Value *> &RetVals,
75303231Sdim               StratifiedSets<InstantiatedValue> S);
76303231Sdim
77303231Sdim  const StratifiedSets<InstantiatedValue> &getStratifiedSets() const {
78303231Sdim    return Sets;
79303231Sdim  }
80303231Sdim  const AliasSummary &getAliasSummary() const { return Summary; }
81303231Sdim};
82303231Sdim
83303231Sdim/// Try to go from a Value* to a Function*. Never returns nullptr.
84303231Sdimstatic Optional<Function *> parentFunctionOfValue(Value *);
85303231Sdim
86303231Sdimconst StratifiedIndex StratifiedLink::SetSentinel =
87303231Sdim    std::numeric_limits<StratifiedIndex>::max();
88303231Sdim
89303231Sdim//===----------------------------------------------------------------------===//
90303231Sdim// Function declarations that require types defined in the namespace above
91303231Sdim//===----------------------------------------------------------------------===//
92303231Sdim
93303231Sdim/// Determines whether it would be pointless to add the given Value to our sets.
94303231Sdimstatic bool canSkipAddingToSets(Value *Val);
95303231Sdim
96303231Sdimstatic Optional<Function *> parentFunctionOfValue(Value *Val) {
97303231Sdim  if (auto *Inst = dyn_cast<Instruction>(Val)) {
98303231Sdim    auto *Bb = Inst->getParent();
99303231Sdim    return Bb->getParent();
100303231Sdim  }
101303231Sdim
102303231Sdim  if (auto *Arg = dyn_cast<Argument>(Val))
103303231Sdim    return Arg->getParent();
104303231Sdim  return None;
105303231Sdim}
106303231Sdim
107303231Sdimstatic bool canSkipAddingToSets(Value *Val) {
108303231Sdim  // Constants can share instances, which may falsely unify multiple
109303231Sdim  // sets, e.g. in
110303231Sdim  // store i32* null, i32** %ptr1
111303231Sdim  // store i32* null, i32** %ptr2
112303231Sdim  // clearly ptr1 and ptr2 should not be unified into the same set, so
113303231Sdim  // we should filter out the (potentially shared) instance to
114303231Sdim  // i32* null.
115303231Sdim  if (isa<Constant>(Val)) {
116303231Sdim    // TODO: Because all of these things are constant, we can determine whether
117303231Sdim    // the data is *actually* mutable at graph building time. This will probably
118303231Sdim    // come for free/cheap with offset awareness.
119303231Sdim    bool CanStoreMutableData = isa<GlobalValue>(Val) ||
120303231Sdim                               isa<ConstantExpr>(Val) ||
121303231Sdim                               isa<ConstantAggregate>(Val);
122303231Sdim    return !CanStoreMutableData;
123303231Sdim  }
124303231Sdim
125303231Sdim  return false;
126303231Sdim}
127303231Sdim
128303231SdimCFLSteensAAResult::FunctionInfo::FunctionInfo(
129303231Sdim    Function &Fn, const SmallVectorImpl<Value *> &RetVals,
130303231Sdim    StratifiedSets<InstantiatedValue> S)
131303231Sdim    : Sets(std::move(S)) {
132303231Sdim  // Historically, an arbitrary upper-bound of 50 args was selected. We may want
133303231Sdim  // to remove this if it doesn't really matter in practice.
134303231Sdim  if (Fn.arg_size() > MaxSupportedArgsInSummary)
135303231Sdim    return;
136303231Sdim
137303231Sdim  DenseMap<StratifiedIndex, InterfaceValue> InterfaceMap;
138303231Sdim
139303231Sdim  // Our intention here is to record all InterfaceValues that share the same
140303231Sdim  // StratifiedIndex in RetParamRelations. For each valid InterfaceValue, we
141303231Sdim  // have its StratifiedIndex scanned here and check if the index is presented
142303231Sdim  // in InterfaceMap: if it is not, we add the correspondence to the map;
143303231Sdim  // otherwise, an aliasing relation is found and we add it to
144303231Sdim  // RetParamRelations.
145303231Sdim
146303231Sdim  auto AddToRetParamRelations = [&](unsigned InterfaceIndex,
147303231Sdim                                    StratifiedIndex SetIndex) {
148303231Sdim    unsigned Level = 0;
149303231Sdim    while (true) {
150303231Sdim      InterfaceValue CurrValue{InterfaceIndex, Level};
151303231Sdim
152303231Sdim      auto Itr = InterfaceMap.find(SetIndex);
153303231Sdim      if (Itr != InterfaceMap.end()) {
154303231Sdim        if (CurrValue != Itr->second)
155303231Sdim          Summary.RetParamRelations.push_back(
156303231Sdim              ExternalRelation{CurrValue, Itr->second});
157303231Sdim        break;
158303231Sdim      }
159303231Sdim
160303231Sdim      auto &Link = Sets.getLink(SetIndex);
161303231Sdim      InterfaceMap.insert(std::make_pair(SetIndex, CurrValue));
162303231Sdim      auto ExternalAttrs = getExternallyVisibleAttrs(Link.Attrs);
163303231Sdim      if (ExternalAttrs.any())
164303231Sdim        Summary.RetParamAttributes.push_back(
165303231Sdim            ExternalAttribute{CurrValue, ExternalAttrs});
166303231Sdim
167303231Sdim      if (!Link.hasBelow())
168303231Sdim        break;
169303231Sdim
170303231Sdim      ++Level;
171303231Sdim      SetIndex = Link.Below;
172303231Sdim    }
173303231Sdim  };
174303231Sdim
175303231Sdim  // Populate RetParamRelations for return values
176303231Sdim  for (auto *RetVal : RetVals) {
177303231Sdim    assert(RetVal != nullptr);
178303231Sdim    assert(RetVal->getType()->isPointerTy());
179303231Sdim    auto RetInfo = Sets.find(InstantiatedValue{RetVal, 0});
180303231Sdim    if (RetInfo.hasValue())
181303231Sdim      AddToRetParamRelations(0, RetInfo->Index);
182303231Sdim  }
183303231Sdim
184303231Sdim  // Populate RetParamRelations for parameters
185303231Sdim  unsigned I = 0;
186303231Sdim  for (auto &Param : Fn.args()) {
187303231Sdim    if (Param.getType()->isPointerTy()) {
188303231Sdim      auto ParamInfo = Sets.find(InstantiatedValue{&Param, 0});
189303231Sdim      if (ParamInfo.hasValue())
190303231Sdim        AddToRetParamRelations(I + 1, ParamInfo->Index);
191303231Sdim    }
192303231Sdim    ++I;
193303231Sdim  }
194303231Sdim}
195303231Sdim
196303231Sdim// Builds the graph + StratifiedSets for a function.
197303231SdimCFLSteensAAResult::FunctionInfo CFLSteensAAResult::buildSetsFrom(Function *Fn) {
198303231Sdim  CFLGraphBuilder<CFLSteensAAResult> GraphBuilder(*this, TLI, *Fn);
199303231Sdim  StratifiedSetsBuilder<InstantiatedValue> SetBuilder;
200303231Sdim
201303231Sdim  // Add all CFLGraph nodes and all Dereference edges to StratifiedSets
202303231Sdim  auto &Graph = GraphBuilder.getCFLGraph();
203303231Sdim  for (const auto &Mapping : Graph.value_mappings()) {
204303231Sdim    auto Val = Mapping.first;
205303231Sdim    if (canSkipAddingToSets(Val))
206303231Sdim      continue;
207303231Sdim    auto &ValueInfo = Mapping.second;
208303231Sdim
209303231Sdim    assert(ValueInfo.getNumLevels() > 0);
210303231Sdim    SetBuilder.add(InstantiatedValue{Val, 0});
211303231Sdim    SetBuilder.noteAttributes(InstantiatedValue{Val, 0},
212303231Sdim                              ValueInfo.getNodeInfoAtLevel(0).Attr);
213303231Sdim    for (unsigned I = 0, E = ValueInfo.getNumLevels() - 1; I < E; ++I) {
214303231Sdim      SetBuilder.add(InstantiatedValue{Val, I + 1});
215303231Sdim      SetBuilder.noteAttributes(InstantiatedValue{Val, I + 1},
216303231Sdim                                ValueInfo.getNodeInfoAtLevel(I + 1).Attr);
217303231Sdim      SetBuilder.addBelow(InstantiatedValue{Val, I},
218303231Sdim                          InstantiatedValue{Val, I + 1});
219303231Sdim    }
220303231Sdim  }
221303231Sdim
222303231Sdim  // Add all assign edges to StratifiedSets
223303231Sdim  for (const auto &Mapping : Graph.value_mappings()) {
224303231Sdim    auto Val = Mapping.first;
225303231Sdim    if (canSkipAddingToSets(Val))
226303231Sdim      continue;
227303231Sdim    auto &ValueInfo = Mapping.second;
228303231Sdim
229303231Sdim    for (unsigned I = 0, E = ValueInfo.getNumLevels(); I < E; ++I) {
230303231Sdim      auto Src = InstantiatedValue{Val, I};
231303231Sdim      for (auto &Edge : ValueInfo.getNodeInfoAtLevel(I).Edges)
232303231Sdim        SetBuilder.addWith(Src, Edge.Other);
233303231Sdim    }
234303231Sdim  }
235303231Sdim
236303231Sdim  return FunctionInfo(*Fn, GraphBuilder.getReturnValues(), SetBuilder.build());
237303231Sdim}
238303231Sdim
239303231Sdimvoid CFLSteensAAResult::scan(Function *Fn) {
240303231Sdim  auto InsertPair = Cache.insert(std::make_pair(Fn, Optional<FunctionInfo>()));
241303231Sdim  (void)InsertPair;
242303231Sdim  assert(InsertPair.second &&
243303231Sdim         "Trying to scan a function that has already been cached");
244303231Sdim
245303231Sdim  // Note that we can't do Cache[Fn] = buildSetsFrom(Fn) here: the function call
246303231Sdim  // may get evaluated after operator[], potentially triggering a DenseMap
247303231Sdim  // resize and invalidating the reference returned by operator[]
248303231Sdim  auto FunInfo = buildSetsFrom(Fn);
249303231Sdim  Cache[Fn] = std::move(FunInfo);
250303231Sdim
251303231Sdim  Handles.push_front(FunctionHandle(Fn, this));
252303231Sdim}
253303231Sdim
254303231Sdimvoid CFLSteensAAResult::evict(Function *Fn) { Cache.erase(Fn); }
255303231Sdim
256303231Sdim/// Ensures that the given function is available in the cache, and returns the
257303231Sdim/// entry.
258303231Sdimconst Optional<CFLSteensAAResult::FunctionInfo> &
259303231SdimCFLSteensAAResult::ensureCached(Function *Fn) {
260303231Sdim  auto Iter = Cache.find(Fn);
261303231Sdim  if (Iter == Cache.end()) {
262303231Sdim    scan(Fn);
263303231Sdim    Iter = Cache.find(Fn);
264303231Sdim    assert(Iter != Cache.end());
265303231Sdim    assert(Iter->second.hasValue());
266303231Sdim  }
267303231Sdim  return Iter->second;
268303231Sdim}
269303231Sdim
270303231Sdimconst AliasSummary *CFLSteensAAResult::getAliasSummary(Function &Fn) {
271303231Sdim  auto &FunInfo = ensureCached(&Fn);
272303231Sdim  if (FunInfo.hasValue())
273303231Sdim    return &FunInfo->getAliasSummary();
274303231Sdim  else
275303231Sdim    return nullptr;
276303231Sdim}
277303231Sdim
278303231SdimAliasResult CFLSteensAAResult::query(const MemoryLocation &LocA,
279303231Sdim                                     const MemoryLocation &LocB) {
280303231Sdim  auto *ValA = const_cast<Value *>(LocA.Ptr);
281303231Sdim  auto *ValB = const_cast<Value *>(LocB.Ptr);
282303231Sdim
283303231Sdim  if (!ValA->getType()->isPointerTy() || !ValB->getType()->isPointerTy())
284303231Sdim    return NoAlias;
285303231Sdim
286303231Sdim  Function *Fn = nullptr;
287303231Sdim  auto MaybeFnA = parentFunctionOfValue(ValA);
288303231Sdim  auto MaybeFnB = parentFunctionOfValue(ValB);
289303231Sdim  if (!MaybeFnA.hasValue() && !MaybeFnB.hasValue()) {
290303231Sdim    // The only times this is known to happen are when globals + InlineAsm are
291303231Sdim    // involved
292303231Sdim    DEBUG(dbgs()
293303231Sdim          << "CFLSteensAA: could not extract parent function information.\n");
294303231Sdim    return MayAlias;
295303231Sdim  }
296303231Sdim
297303231Sdim  if (MaybeFnA.hasValue()) {
298303231Sdim    Fn = *MaybeFnA;
299303231Sdim    assert((!MaybeFnB.hasValue() || *MaybeFnB == *MaybeFnA) &&
300303231Sdim           "Interprocedural queries not supported");
301303231Sdim  } else {
302303231Sdim    Fn = *MaybeFnB;
303303231Sdim  }
304303231Sdim
305303231Sdim  assert(Fn != nullptr);
306303231Sdim  auto &MaybeInfo = ensureCached(Fn);
307303231Sdim  assert(MaybeInfo.hasValue());
308303231Sdim
309303231Sdim  auto &Sets = MaybeInfo->getStratifiedSets();
310303231Sdim  auto MaybeA = Sets.find(InstantiatedValue{ValA, 0});
311303231Sdim  if (!MaybeA.hasValue())
312303231Sdim    return MayAlias;
313303231Sdim
314303231Sdim  auto MaybeB = Sets.find(InstantiatedValue{ValB, 0});
315303231Sdim  if (!MaybeB.hasValue())
316303231Sdim    return MayAlias;
317303231Sdim
318303231Sdim  auto SetA = *MaybeA;
319303231Sdim  auto SetB = *MaybeB;
320303231Sdim  auto AttrsA = Sets.getLink(SetA.Index).Attrs;
321303231Sdim  auto AttrsB = Sets.getLink(SetB.Index).Attrs;
322303231Sdim
323303231Sdim  // If both values are local (meaning the corresponding set has attribute
324303231Sdim  // AttrNone or AttrEscaped), then we know that CFLSteensAA fully models them:
325303231Sdim  // they may-alias each other if and only if they are in the same set.
326303231Sdim  // If at least one value is non-local (meaning it either is global/argument or
327303231Sdim  // it comes from unknown sources like integer cast), the situation becomes a
328303231Sdim  // bit more interesting. We follow three general rules described below:
329303231Sdim  // - Non-local values may alias each other
330303231Sdim  // - AttrNone values do not alias any non-local values
331303231Sdim  // - AttrEscaped do not alias globals/arguments, but they may alias
332303231Sdim  // AttrUnknown values
333303231Sdim  if (SetA.Index == SetB.Index)
334303231Sdim    return MayAlias;
335303231Sdim  if (AttrsA.none() || AttrsB.none())
336303231Sdim    return NoAlias;
337303231Sdim  if (hasUnknownOrCallerAttr(AttrsA) || hasUnknownOrCallerAttr(AttrsB))
338303231Sdim    return MayAlias;
339303231Sdim  if (isGlobalOrArgAttr(AttrsA) && isGlobalOrArgAttr(AttrsB))
340303231Sdim    return MayAlias;
341303231Sdim  return NoAlias;
342303231Sdim}
343303231Sdim
344303231SdimModRefInfo CFLSteensAAResult::getArgModRefInfo(ImmutableCallSite CS,
345303231Sdim                                               unsigned ArgIdx) {
346303231Sdim  if (auto CalledFunc = CS.getCalledFunction()) {
347303231Sdim    auto &MaybeInfo = ensureCached(const_cast<Function *>(CalledFunc));
348303231Sdim    if (!MaybeInfo.hasValue())
349303231Sdim      return MRI_ModRef;
350303231Sdim    auto &RetParamAttributes = MaybeInfo->getAliasSummary().RetParamAttributes;
351303231Sdim    auto &RetParamRelations = MaybeInfo->getAliasSummary().RetParamRelations;
352303231Sdim
353303231Sdim    bool ArgAttributeIsWritten =
354303231Sdim        std::any_of(RetParamAttributes.begin(), RetParamAttributes.end(),
355303231Sdim                    [ArgIdx](const ExternalAttribute &ExtAttr) {
356303231Sdim                      return ExtAttr.IValue.Index == ArgIdx + 1;
357303231Sdim                    });
358303231Sdim    bool ArgIsAccessed =
359303231Sdim        std::any_of(RetParamRelations.begin(), RetParamRelations.end(),
360303231Sdim                    [ArgIdx](const ExternalRelation &ExtRelation) {
361303231Sdim                      return ExtRelation.To.Index == ArgIdx + 1 ||
362303231Sdim                             ExtRelation.From.Index == ArgIdx + 1;
363303231Sdim                    });
364303231Sdim
365303231Sdim    return (!ArgIsAccessed && !ArgAttributeIsWritten) ? MRI_NoModRef
366303231Sdim                                                      : MRI_ModRef;
367303231Sdim  }
368303231Sdim
369303231Sdim  return MRI_ModRef;
370303231Sdim}
371303231Sdim
372303231SdimFunctionModRefBehavior
373303231SdimCFLSteensAAResult::getModRefBehavior(ImmutableCallSite CS) {
374303231Sdim  // If we know the callee, try analyzing it
375303231Sdim  if (auto CalledFunc = CS.getCalledFunction())
376303231Sdim    return getModRefBehavior(CalledFunc);
377303231Sdim
378303231Sdim  // Otherwise, be conservative
379303231Sdim  return FMRB_UnknownModRefBehavior;
380303231Sdim}
381303231Sdim
382303231SdimFunctionModRefBehavior CFLSteensAAResult::getModRefBehavior(const Function *F) {
383303231Sdim  assert(F != nullptr);
384303231Sdim
385303231Sdim  // TODO: Remove the const_cast
386303231Sdim  auto &MaybeInfo = ensureCached(const_cast<Function *>(F));
387303231Sdim  if (!MaybeInfo.hasValue())
388303231Sdim    return FMRB_UnknownModRefBehavior;
389303231Sdim  auto &RetParamAttributes = MaybeInfo->getAliasSummary().RetParamAttributes;
390303231Sdim  auto &RetParamRelations = MaybeInfo->getAliasSummary().RetParamRelations;
391303231Sdim
392303231Sdim  // First, if any argument is marked Escpaed, Unknown or Global, anything may
393303231Sdim  // happen to them and thus we can't draw any conclusion.
394303231Sdim  if (!RetParamAttributes.empty())
395303231Sdim    return FMRB_UnknownModRefBehavior;
396303231Sdim
397303231Sdim  // Currently we don't (and can't) distinguish reads from writes in
398303231Sdim  // RetParamRelations. All we can say is whether there may be memory access or
399303231Sdim  // not.
400303231Sdim  if (RetParamRelations.empty())
401303231Sdim    return FMRB_DoesNotAccessMemory;
402303231Sdim
403303231Sdim  // Check if something beyond argmem gets touched.
404303231Sdim  bool AccessArgMemoryOnly =
405303231Sdim      std::all_of(RetParamRelations.begin(), RetParamRelations.end(),
406303231Sdim                  [](const ExternalRelation &ExtRelation) {
407303231Sdim                    // Both DerefLevels has to be 0, since we don't know which
408303231Sdim                    // one is a read and which is a write.
409303231Sdim                    return ExtRelation.From.DerefLevel == 0 &&
410303231Sdim                           ExtRelation.To.DerefLevel == 0;
411303231Sdim                  });
412303231Sdim  return AccessArgMemoryOnly ? FMRB_OnlyAccessesArgumentPointees
413303231Sdim                             : FMRB_UnknownModRefBehavior;
414303231Sdim}
415303231Sdim
416303231Sdimchar CFLSteensAA::PassID;
417303231Sdim
418303231SdimCFLSteensAAResult CFLSteensAA::run(Function &F, AnalysisManager<Function> &AM) {
419303231Sdim  return CFLSteensAAResult(AM.getResult<TargetLibraryAnalysis>(F));
420303231Sdim}
421303231Sdim
422303231Sdimchar CFLSteensAAWrapperPass::ID = 0;
423303231SdimINITIALIZE_PASS(CFLSteensAAWrapperPass, "cfl-steens-aa",
424303231Sdim                "Unification-Based CFL Alias Analysis", false, true)
425303231Sdim
426303231SdimImmutablePass *llvm::createCFLSteensAAWrapperPass() {
427303231Sdim  return new CFLSteensAAWrapperPass();
428303231Sdim}
429303231Sdim
430303231SdimCFLSteensAAWrapperPass::CFLSteensAAWrapperPass() : ImmutablePass(ID) {
431303231Sdim  initializeCFLSteensAAWrapperPassPass(*PassRegistry::getPassRegistry());
432303231Sdim}
433303231Sdim
434303231Sdimvoid CFLSteensAAWrapperPass::initializePass() {
435303231Sdim  auto &TLIWP = getAnalysis<TargetLibraryInfoWrapperPass>();
436303231Sdim  Result.reset(new CFLSteensAAResult(TLIWP.getTLI()));
437303231Sdim}
438303231Sdim
439303231Sdimvoid CFLSteensAAWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
440303231Sdim  AU.setPreservesAll();
441303231Sdim  AU.addRequired<TargetLibraryInfoWrapperPass>();
442303231Sdim}
443