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