[llvm] r274958 - [CFLAA] Move the graph builder out from CFLSteens. NFC.
George Burgess IV via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 8 19:54:43 PDT 2016
Author: gbiv
Date: Fri Jul 8 21:54:42 2016
New Revision: 274958
URL: http://llvm.org/viewvc/llvm-project?rev=274958&view=rev
Log:
[CFLAA] Move the graph builder out from CFLSteens. NFC.
Patch by Jia Chen.
Differential Revision: http://reviews.llvm.org/D22022
Modified:
llvm/trunk/include/llvm/Analysis/CFLAndersAliasAnalysis.h
llvm/trunk/include/llvm/Analysis/CFLSteensAliasAnalysis.h
llvm/trunk/lib/Analysis/AliasAnalysisSummary.h
llvm/trunk/lib/Analysis/CFLGraph.h
llvm/trunk/lib/Analysis/CFLSteensAliasAnalysis.cpp
Modified: llvm/trunk/include/llvm/Analysis/CFLAndersAliasAnalysis.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/CFLAndersAliasAnalysis.h?rev=274958&r1=274957&r2=274958&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Analysis/CFLAndersAliasAnalysis.h (original)
+++ llvm/trunk/include/llvm/Analysis/CFLAndersAliasAnalysis.h Fri Jul 8 21:54:42 2016
@@ -21,12 +21,23 @@
namespace llvm {
+namespace cflaa {
+struct AliasSummary;
+}
+
class CFLAndersAAResult : public AAResultBase<CFLAndersAAResult> {
friend AAResultBase<CFLAndersAAResult>;
public:
explicit CFLAndersAAResult();
+ /// \brief Get the alias summary for the given function
+ /// Return nullptr if the summary is not found or not available
+ const cflaa::AliasSummary *getAliasSummary(Function &Fn) {
+ // Dummy implementation
+ return nullptr;
+ }
+
AliasResult alias(const MemoryLocation &LocA, const MemoryLocation &LocB) {
// Dummy implementation
return AAResultBase::alias(LocA, LocB);
Modified: llvm/trunk/include/llvm/Analysis/CFLSteensAliasAnalysis.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/CFLSteensAliasAnalysis.h?rev=274958&r1=274957&r2=274958&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Analysis/CFLSteensAliasAnalysis.h (original)
+++ llvm/trunk/include/llvm/Analysis/CFLSteensAliasAnalysis.h Fri Jul 8 21:54:42 2016
@@ -29,6 +29,10 @@ namespace llvm {
class TargetLibraryInfo;
+namespace cflaa {
+struct AliasSummary;
+}
+
class CFLSteensAAResult : public AAResultBase<CFLSteensAAResult> {
friend AAResultBase<CFLSteensAAResult>;
class FunctionInfo;
@@ -52,6 +56,10 @@ public:
/// Returns the appropriate entry from the cache.
const Optional<FunctionInfo> &ensureCached(Function *Fn);
+ /// \brief Get the alias summary for the given function
+ /// Return nullptr if the summary is not found or not available
+ const cflaa::AliasSummary *getAliasSummary(Function &Fn);
+
AliasResult query(const MemoryLocation &LocA, const MemoryLocation &LocB);
AliasResult alias(const MemoryLocation &LocA, const MemoryLocation &LocB) {
Modified: llvm/trunk/lib/Analysis/AliasAnalysisSummary.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/AliasAnalysisSummary.h?rev=274958&r1=274957&r2=274958&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/AliasAnalysisSummary.h (original)
+++ llvm/trunk/lib/Analysis/AliasAnalysisSummary.h Fri Jul 8 21:54:42 2016
@@ -36,6 +36,7 @@
#define LLVM_ANALYSIS_ALIASANALYSISSUMMARY_H
#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/IR/CallSite.h"
#include <bitset>
@@ -96,6 +97,9 @@ AliasAttrs getExternallyVisibleAttrs(Ali
// Function summary related stuffs
//===----------------------------------------------------------------------===//
+/// The maximum number of arguments we can put into a summary.
+static unsigned MaxSupportedArgsInSummary = 50;
+
/// We use InterfaceValue to describe parameters/return value, as well as
/// potential memory locations that are pointed to by parameters/return value,
/// of a function.
@@ -129,6 +133,15 @@ struct ExternalAttribute {
AliasAttrs Attr;
};
+/// AliasSummary is just a collection of ExternalRelation and ExternalAttribute
+struct AliasSummary {
+ // RetParamRelations is a collection of ExternalRelations.
+ SmallVector<ExternalRelation, 8> RetParamRelations;
+
+ // RetParamAttributes is a collection of ExternalAttributes.
+ SmallVector<ExternalAttribute, 8> RetParamAttributes;
+};
+
/// This is the result of instantiating InterfaceValue at a particular callsite
struct InstantiatedValue {
Value *Val;
Modified: llvm/trunk/lib/Analysis/CFLGraph.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/CFLGraph.h?rev=274958&r1=274957&r2=274958&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/CFLGraph.h (original)
+++ llvm/trunk/lib/Analysis/CFLGraph.h Fri Jul 8 21:54:42 2016
@@ -17,6 +17,9 @@
#include "AliasAnalysisSummary.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/Analysis/MemoryBuiltins.h"
+#include "llvm/IR/InstVisitor.h"
+#include "llvm/IR/Instructions.h"
namespace llvm {
namespace cflaa {
@@ -144,6 +147,412 @@ public:
bool empty() const { return NodeImpls.empty(); }
std::size_t size() const { return NodeImpls.size(); }
};
+
+///\brief A builder class used to create CFLGraph instance from a given function
+/// The CFL-AA that uses this builder must provide its own type as a template
+/// argument. This is necessary for interprocedural processing: CFLGraphBuilder
+/// needs a way of obtaining the summary of other functions when callinsts are
+/// encountered.
+/// As a result, we expect the said CFL-AA to expose a getAliasSummary() public
+/// member function that takes a Function& and returns the corresponding summary
+/// as a const AliasSummary*.
+template <typename CFLAA> class CFLGraphBuilder {
+ // Input of the builder
+ CFLAA &Analysis;
+ const TargetLibraryInfo &TLI;
+
+ // Output of the builder
+ CFLGraph Graph;
+ SmallVector<Value *, 4> ReturnedValues;
+
+ // Auxiliary structures used by the builder
+ SmallVector<InstantiatedRelation, 8> InstantiatedRelations;
+ SmallVector<InstantiatedAttr, 8> InstantiatedAttrs;
+
+ // Helper class
+ /// Gets the edges our graph should have, based on an Instruction*
+ class GetEdgesVisitor : public InstVisitor<GetEdgesVisitor, void> {
+ CFLAA &AA;
+ const TargetLibraryInfo &TLI;
+
+ CFLGraph &Graph;
+ SmallVectorImpl<Value *> &ReturnValues;
+ SmallVectorImpl<InstantiatedRelation> &InstantiatedRelations;
+ SmallVectorImpl<InstantiatedAttr> &InstantiatedAttrs;
+
+ static bool hasUsefulEdges(ConstantExpr *CE) {
+ // ConstantExpr doesn't have terminators, invokes, or fences, so only
+ // needs
+ // to check for compares.
+ return CE->getOpcode() != Instruction::ICmp &&
+ CE->getOpcode() != Instruction::FCmp;
+ }
+
+ // Returns possible functions called by CS into the given SmallVectorImpl.
+ // Returns true if targets found, false otherwise.
+ static bool getPossibleTargets(CallSite CS,
+ SmallVectorImpl<Function *> &Output) {
+ if (auto *Fn = CS.getCalledFunction()) {
+ Output.push_back(Fn);
+ return true;
+ }
+
+ // TODO: If the call is indirect, we might be able to enumerate all
+ // potential
+ // targets of the call and return them, rather than just failing.
+ return false;
+ }
+
+ void addNode(Value *Val) {
+ assert(Val != nullptr);
+ if (!Graph.addNode(Val))
+ return;
+
+ if (isa<GlobalValue>(Val)) {
+ Graph.addAttr(Val, getGlobalOrArgAttrFromValue(*Val));
+ // Currently we do not attempt to be smart on globals
+ InstantiatedAttrs.push_back(
+ InstantiatedAttr{InstantiatedValue{Val, 1}, getAttrUnknown()});
+ } else if (auto CExpr = dyn_cast<ConstantExpr>(Val))
+ if (hasUsefulEdges(CExpr))
+ visitConstantExpr(CExpr);
+ }
+
+ void addNodeWithAttr(Value *Val, AliasAttrs Attr) {
+ addNode(Val);
+ Graph.addAttr(Val, Attr);
+ }
+
+ void addEdge(Value *From, Value *To, EdgeType Type) {
+ assert(From != nullptr && To != nullptr);
+ if (!From->getType()->isPointerTy() || !To->getType()->isPointerTy())
+ return;
+ addNode(From);
+ if (To != From)
+ addNode(To);
+ Graph.addEdge(From, To, Type);
+ }
+
+ public:
+ GetEdgesVisitor(CFLGraphBuilder &Builder)
+ : AA(Builder.Analysis), TLI(Builder.TLI), Graph(Builder.Graph),
+ ReturnValues(Builder.ReturnedValues),
+ InstantiatedRelations(Builder.InstantiatedRelations),
+ InstantiatedAttrs(Builder.InstantiatedAttrs) {}
+
+ void visitInstruction(Instruction &) {
+ llvm_unreachable("Unsupported instruction encountered");
+ }
+
+ void visitReturnInst(ReturnInst &Inst) {
+ if (auto RetVal = Inst.getReturnValue()) {
+ if (RetVal->getType()->isPointerTy()) {
+ addNode(RetVal);
+ ReturnValues.push_back(RetVal);
+ }
+ }
+ }
+
+ void visitPtrToIntInst(PtrToIntInst &Inst) {
+ auto *Ptr = Inst.getOperand(0);
+ addNodeWithAttr(Ptr, getAttrEscaped());
+ }
+
+ void visitIntToPtrInst(IntToPtrInst &Inst) {
+ auto *Ptr = &Inst;
+ addNodeWithAttr(Ptr, getAttrUnknown());
+ }
+
+ void visitCastInst(CastInst &Inst) {
+ auto *Src = Inst.getOperand(0);
+ addEdge(Src, &Inst, EdgeType::Assign);
+ }
+
+ void visitBinaryOperator(BinaryOperator &Inst) {
+ auto *Op1 = Inst.getOperand(0);
+ auto *Op2 = Inst.getOperand(1);
+ addEdge(Op1, &Inst, EdgeType::Assign);
+ addEdge(Op2, &Inst, EdgeType::Assign);
+ }
+
+ void visitAtomicCmpXchgInst(AtomicCmpXchgInst &Inst) {
+ auto *Ptr = Inst.getPointerOperand();
+ auto *Val = Inst.getNewValOperand();
+ addEdge(Ptr, Val, EdgeType::Dereference);
+ }
+
+ void visitAtomicRMWInst(AtomicRMWInst &Inst) {
+ auto *Ptr = Inst.getPointerOperand();
+ auto *Val = Inst.getValOperand();
+ addEdge(Ptr, Val, EdgeType::Dereference);
+ }
+
+ void visitPHINode(PHINode &Inst) {
+ for (Value *Val : Inst.incoming_values())
+ addEdge(Val, &Inst, EdgeType::Assign);
+ }
+
+ void visitGetElementPtrInst(GetElementPtrInst &Inst) {
+ auto *Op = Inst.getPointerOperand();
+ addEdge(Op, &Inst, EdgeType::Assign);
+ }
+
+ void visitSelectInst(SelectInst &Inst) {
+ // Condition is not processed here (The actual statement producing
+ // the condition result is processed elsewhere). For select, the
+ // condition is evaluated, but not loaded, stored, or assigned
+ // simply as a result of being the condition of a select.
+
+ auto *TrueVal = Inst.getTrueValue();
+ auto *FalseVal = Inst.getFalseValue();
+ addEdge(TrueVal, &Inst, EdgeType::Assign);
+ addEdge(FalseVal, &Inst, EdgeType::Assign);
+ }
+
+ void visitAllocaInst(AllocaInst &Inst) { Graph.addNode(&Inst); }
+
+ void visitLoadInst(LoadInst &Inst) {
+ auto *Ptr = Inst.getPointerOperand();
+ auto *Val = &Inst;
+ addEdge(Val, Ptr, EdgeType::Reference);
+ }
+
+ void visitStoreInst(StoreInst &Inst) {
+ auto *Ptr = Inst.getPointerOperand();
+ auto *Val = Inst.getValueOperand();
+ addEdge(Ptr, Val, EdgeType::Dereference);
+ }
+
+ void visitVAArgInst(VAArgInst &Inst) {
+ // We can't fully model va_arg here. For *Ptr = Inst.getOperand(0), it
+ // does
+ // two things:
+ // 1. Loads a value from *((T*)*Ptr).
+ // 2. Increments (stores to) *Ptr by some target-specific amount.
+ // For now, we'll handle this like a landingpad instruction (by placing
+ // the
+ // result in its own group, and having that group alias externals).
+ addNodeWithAttr(&Inst, getAttrUnknown());
+ }
+
+ static bool isFunctionExternal(Function *Fn) {
+ return !Fn->hasExactDefinition();
+ }
+
+ bool tryInterproceduralAnalysis(CallSite CS,
+ const SmallVectorImpl<Function *> &Fns) {
+ assert(Fns.size() > 0);
+
+ if (CS.arg_size() > MaxSupportedArgsInSummary)
+ return false;
+
+ // Exit early if we'll fail anyway
+ for (auto *Fn : Fns) {
+ if (isFunctionExternal(Fn) || Fn->isVarArg())
+ return false;
+ // Fail if the caller does not provide enough arguments
+ assert(Fn->arg_size() <= CS.arg_size());
+ if (!AA.getAliasSummary(*Fn))
+ return false;
+ }
+
+ for (auto *Fn : Fns) {
+ auto Summary = AA.getAliasSummary(*Fn);
+ assert(Summary != nullptr);
+
+ auto &RetParamRelations = Summary->RetParamRelations;
+ for (auto &Relation : RetParamRelations) {
+ auto IRelation = instantiateExternalRelation(Relation, CS);
+ if (IRelation.hasValue())
+ InstantiatedRelations.push_back(*IRelation);
+ }
+
+ auto &RetParamAttributes = Summary->RetParamAttributes;
+ for (auto &Attribute : RetParamAttributes) {
+ auto IAttr = instantiateExternalAttribute(Attribute, CS);
+ if (IAttr.hasValue())
+ InstantiatedAttrs.push_back(*IAttr);
+ }
+ }
+
+ return true;
+ }
+
+ void visitCallSite(CallSite CS) {
+ auto Inst = CS.getInstruction();
+
+ // Make sure all arguments and return value are added to the graph first
+ for (Value *V : CS.args())
+ addNode(V);
+ if (Inst->getType()->isPointerTy())
+ addNode(Inst);
+
+ // Check if Inst is a call to a library function that
+ // allocates/deallocates
+ // on the heap. Those kinds of functions do not introduce any aliases.
+ // TODO: address other common library functions such as realloc(),
+ // strdup(),
+ // etc.
+ if (isMallocLikeFn(Inst, &TLI) || isCallocLikeFn(Inst, &TLI) ||
+ isFreeCall(Inst, &TLI))
+ return;
+
+ // TODO: Add support for noalias args/all the other fun function
+ // attributes
+ // that we can tack on.
+ SmallVector<Function *, 4> Targets;
+ if (getPossibleTargets(CS, Targets))
+ if (tryInterproceduralAnalysis(CS, Targets))
+ return;
+
+ // Because the function is opaque, we need to note that anything
+ // could have happened to the arguments (unless the function is marked
+ // readonly or readnone), and that the result could alias just about
+ // anything, too (unless the result is marked noalias).
+ if (!CS.onlyReadsMemory())
+ for (Value *V : CS.args()) {
+ if (V->getType()->isPointerTy()) {
+ // The argument itself escapes.
+ addNodeWithAttr(V, getAttrEscaped());
+ // The fate of argument memory is unknown. Note that since
+ // AliasAttrs
+ // is transitive with respect to dereference, we only need to
+ // specify
+ // it for the first-level memory.
+ InstantiatedAttrs.push_back(
+ InstantiatedAttr{InstantiatedValue{V, 1}, getAttrUnknown()});
+ }
+ }
+
+ if (Inst->getType()->isPointerTy()) {
+ auto *Fn = CS.getCalledFunction();
+ if (Fn == nullptr || !Fn->doesNotAlias(0))
+ // No need to call addNodeWithAttr() since we've added Inst at the
+ // beginning of this function and we know it is not a global.
+ Graph.addAttr(Inst, getAttrUnknown());
+ }
+ }
+
+ /// Because vectors/aggregates are immutable and unaddressable, there's
+ /// nothing we can do to coax a value out of them, other than calling
+ /// Extract{Element,Value}. We can effectively treat them as pointers to
+ /// arbitrary memory locations we can store in and load from.
+ void visitExtractElementInst(ExtractElementInst &Inst) {
+ auto *Ptr = Inst.getVectorOperand();
+ auto *Val = &Inst;
+ addEdge(Val, Ptr, EdgeType::Reference);
+ }
+
+ void visitInsertElementInst(InsertElementInst &Inst) {
+ auto *Vec = Inst.getOperand(0);
+ auto *Val = Inst.getOperand(1);
+ addEdge(Vec, &Inst, EdgeType::Assign);
+ addEdge(&Inst, Val, EdgeType::Dereference);
+ }
+
+ void visitLandingPadInst(LandingPadInst &Inst) {
+ // Exceptions come from "nowhere", from our analysis' perspective.
+ // So we place the instruction its own group, noting that said group may
+ // alias externals
+ addNodeWithAttr(&Inst, getAttrUnknown());
+ }
+
+ void visitInsertValueInst(InsertValueInst &Inst) {
+ auto *Agg = Inst.getOperand(0);
+ auto *Val = Inst.getOperand(1);
+ addEdge(Agg, &Inst, EdgeType::Assign);
+ addEdge(&Inst, Val, EdgeType::Dereference);
+ }
+
+ void visitExtractValueInst(ExtractValueInst &Inst) {
+ auto *Ptr = Inst.getAggregateOperand();
+ addEdge(&Inst, Ptr, EdgeType::Reference);
+ }
+
+ void visitShuffleVectorInst(ShuffleVectorInst &Inst) {
+ auto *From1 = Inst.getOperand(0);
+ auto *From2 = Inst.getOperand(1);
+ addEdge(From1, &Inst, EdgeType::Assign);
+ addEdge(From2, &Inst, EdgeType::Assign);
+ }
+
+ void visitConstantExpr(ConstantExpr *CE) {
+ switch (CE->getOpcode()) {
+ default:
+ llvm_unreachable("Unknown instruction type encountered!");
+// Build the switch statement using the Instruction.def file.
+#define HANDLE_INST(NUM, OPCODE, CLASS) \
+ case Instruction::OPCODE: \
+ this->visit##OPCODE(*(CLASS *)CE); \
+ break;
+#include "llvm/IR/Instruction.def"
+ }
+ }
+ };
+
+ // Helper functions
+
+ // Determines whether or not we an instruction is useless to us (e.g.
+ // FenceInst)
+ static bool hasUsefulEdges(Instruction *Inst) {
+ bool IsNonInvokeRetTerminator = isa<TerminatorInst>(Inst) &&
+ !isa<InvokeInst>(Inst) &&
+ !isa<ReturnInst>(Inst);
+ return !isa<CmpInst>(Inst) && !isa<FenceInst>(Inst) &&
+ !IsNonInvokeRetTerminator;
+ }
+
+ void addArgumentToGraph(Argument &Arg) {
+ if (Arg.getType()->isPointerTy()) {
+ Graph.addNode(&Arg);
+ Graph.addAttr(&Arg, getGlobalOrArgAttrFromValue(Arg));
+ // Pointees of a formal parameter is known to the caller
+ InstantiatedAttrs.push_back(
+ InstantiatedAttr{InstantiatedValue{&Arg, 1}, getAttrCaller()});
+ }
+ }
+
+ // Given an Instruction, this will add it to the graph, along with any
+ // Instructions that are potentially only available from said Instruction
+ // For example, given the following line:
+ // %0 = load i16* getelementptr ([1 x i16]* @a, 0, 0), align 2
+ // addInstructionToGraph would add both the `load` and `getelementptr`
+ // instructions to the graph appropriately.
+ void addInstructionToGraph(Instruction &Inst) {
+ if (!hasUsefulEdges(&Inst))
+ return;
+
+ GetEdgesVisitor(*this).visit(Inst);
+ }
+
+ // Builds the graph needed for constructing the StratifiedSets for the given
+ // function
+ void buildGraphFrom(Function &Fn) {
+ for (auto &Bb : Fn.getBasicBlockList())
+ for (auto &Inst : Bb.getInstList())
+ addInstructionToGraph(Inst);
+
+ for (auto &Arg : Fn.args())
+ addArgumentToGraph(Arg);
+ }
+
+public:
+ CFLGraphBuilder(CFLAA &Analysis, const TargetLibraryInfo &TLI, Function &Fn)
+ : Analysis(Analysis), TLI(TLI) {
+ buildGraphFrom(Fn);
+ }
+
+ const CFLGraph &getCFLGraph() const { return Graph; }
+ const SmallVector<Value *, 4> &getReturnValues() const {
+ return ReturnedValues;
+ }
+ const SmallVector<InstantiatedRelation, 8> &getInstantiatedRelations() const {
+ return InstantiatedRelations;
+ }
+ const SmallVector<InstantiatedAttr, 8> &getInstantiatedAttrs() const {
+ return InstantiatedAttrs;
+ }
+};
}
}
Modified: llvm/trunk/lib/Analysis/CFLSteensAliasAnalysis.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/CFLSteensAliasAnalysis.cpp?rev=274958&r1=274957&r2=274958&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/CFLSteensAliasAnalysis.cpp (original)
+++ llvm/trunk/lib/Analysis/CFLSteensAliasAnalysis.cpp Fri Jul 8 21:54:42 2016
@@ -41,12 +41,9 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/None.h"
#include "llvm/ADT/Optional.h"
-#include "llvm/Analysis/MemoryBuiltins.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
-#include "llvm/IR/InstVisitor.h"
-#include "llvm/IR/Instructions.h"
#include "llvm/Pass.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
@@ -71,425 +68,27 @@ CFLSteensAAResult::~CFLSteensAAResult()
/// Information we have about a function and would like to keep around.
class CFLSteensAAResult::FunctionInfo {
StratifiedSets<Value *> Sets;
-
- // RetParamRelations is a collection of ExternalRelations.
- SmallVector<ExternalRelation, 8> RetParamRelations;
-
- // RetParamAttributes is a collection of ExternalAttributes.
- SmallVector<ExternalAttribute, 8> RetParamAttributes;
+ AliasSummary Summary;
public:
FunctionInfo(Function &Fn, const SmallVectorImpl<Value *> &RetVals,
StratifiedSets<Value *> S);
const StratifiedSets<Value *> &getStratifiedSets() const { return Sets; }
- const SmallVectorImpl<ExternalRelation> &getRetParamRelations() const {
- return RetParamRelations;
- }
- const SmallVectorImpl<ExternalAttribute> &getRetParamAttributes() const {
- return RetParamAttributes;
- }
+ const AliasSummary &getAliasSummary() const { return Summary; }
};
/// Try to go from a Value* to a Function*. Never returns nullptr.
static Optional<Function *> parentFunctionOfValue(Value *);
-/// Returns possible functions called by the Inst* into the given
-/// SmallVectorImpl. Returns true if targets found, false otherwise. This is
-/// templated so we can use it with CallInsts and InvokeInsts.
-static bool getPossibleTargets(CallSite, SmallVectorImpl<Function *> &);
-
const StratifiedIndex StratifiedLink::SetSentinel =
std::numeric_limits<StratifiedIndex>::max();
namespace {
-/// The maximum number of arguments we can put into a summary.
-LLVM_CONSTEXPR unsigned MaxSupportedArgsInSummary = 50;
-
/// StratifiedSets call for knowledge of "direction", so this is how we
/// represent that locally.
enum class Level { Same, Above, Below };
-
-/// Gets the edges our graph should have, based on an Instruction*
-class GetEdgesVisitor : public InstVisitor<GetEdgesVisitor, void> {
- CFLSteensAAResult &AA;
- const TargetLibraryInfo &TLI;
-
- CFLGraph &Graph;
- SmallVectorImpl<Value *> &ReturnValues;
- SmallVectorImpl<InstantiatedRelation> &InstantiatedRelations;
- SmallVectorImpl<InstantiatedAttr> &InstantiatedAttrs;
-
- static bool hasUsefulEdges(ConstantExpr *CE) {
- // ConstantExpr doesn't have terminators, invokes, or fences, so only needs
- // to check for compares.
- return CE->getOpcode() != Instruction::ICmp &&
- CE->getOpcode() != Instruction::FCmp;
- }
-
- void addNode(Value *Val) {
- assert(Val != nullptr);
- if (!Graph.addNode(Val))
- return;
-
- if (isa<GlobalValue>(Val)) {
- Graph.addAttr(Val, getGlobalOrArgAttrFromValue(*Val));
- // Currently we do not attempt to be smart on globals
- InstantiatedAttrs.push_back(
- InstantiatedAttr{InstantiatedValue{Val, 1}, getAttrUnknown()});
- } else if (auto CExpr = dyn_cast<ConstantExpr>(Val))
- if (hasUsefulEdges(CExpr))
- visitConstantExpr(CExpr);
- }
-
- void addNodeWithAttr(Value *Val, AliasAttrs Attr) {
- addNode(Val);
- Graph.addAttr(Val, Attr);
- }
-
- void addEdge(Value *From, Value *To, EdgeType Type) {
- assert(From != nullptr && To != nullptr);
- if (!From->getType()->isPointerTy() || !To->getType()->isPointerTy())
- return;
- addNode(From);
- if (To != From)
- addNode(To);
- Graph.addEdge(From, To, Type);
- }
-
-public:
- GetEdgesVisitor(CFLSteensAAResult &AA, const TargetLibraryInfo &TLI,
- CFLGraph &Graph, SmallVectorImpl<Value *> &ReturnValues,
- SmallVectorImpl<InstantiatedRelation> &InstantiatedRelations,
- SmallVectorImpl<InstantiatedAttr> &InstantiatedAttrs)
- : AA(AA), TLI(TLI), Graph(Graph), ReturnValues(ReturnValues),
- InstantiatedRelations(InstantiatedRelations),
- InstantiatedAttrs(InstantiatedAttrs) {}
-
- void visitInstruction(Instruction &) {
- llvm_unreachable("Unsupported instruction encountered");
- }
-
- void visitReturnInst(ReturnInst &Inst) {
- if (auto RetVal = Inst.getReturnValue()) {
- if (RetVal->getType()->isPointerTy()) {
- addNode(RetVal);
- ReturnValues.push_back(RetVal);
- }
- }
- }
-
- void visitPtrToIntInst(PtrToIntInst &Inst) {
- auto *Ptr = Inst.getOperand(0);
- addNodeWithAttr(Ptr, getAttrEscaped());
- }
-
- void visitIntToPtrInst(IntToPtrInst &Inst) {
- auto *Ptr = &Inst;
- addNodeWithAttr(Ptr, getAttrUnknown());
- }
-
- void visitCastInst(CastInst &Inst) {
- auto *Src = Inst.getOperand(0);
- addEdge(Src, &Inst, EdgeType::Assign);
- }
-
- void visitBinaryOperator(BinaryOperator &Inst) {
- auto *Op1 = Inst.getOperand(0);
- auto *Op2 = Inst.getOperand(1);
- addEdge(Op1, &Inst, EdgeType::Assign);
- addEdge(Op2, &Inst, EdgeType::Assign);
- }
-
- void visitAtomicCmpXchgInst(AtomicCmpXchgInst &Inst) {
- auto *Ptr = Inst.getPointerOperand();
- auto *Val = Inst.getNewValOperand();
- addEdge(Ptr, Val, EdgeType::Dereference);
- }
-
- void visitAtomicRMWInst(AtomicRMWInst &Inst) {
- auto *Ptr = Inst.getPointerOperand();
- auto *Val = Inst.getValOperand();
- addEdge(Ptr, Val, EdgeType::Dereference);
- }
-
- void visitPHINode(PHINode &Inst) {
- for (Value *Val : Inst.incoming_values())
- addEdge(Val, &Inst, EdgeType::Assign);
- }
-
- void visitGetElementPtrInst(GetElementPtrInst &Inst) {
- auto *Op = Inst.getPointerOperand();
- addEdge(Op, &Inst, EdgeType::Assign);
- }
-
- void visitSelectInst(SelectInst &Inst) {
- // Condition is not processed here (The actual statement producing
- // the condition result is processed elsewhere). For select, the
- // condition is evaluated, but not loaded, stored, or assigned
- // simply as a result of being the condition of a select.
-
- auto *TrueVal = Inst.getTrueValue();
- auto *FalseVal = Inst.getFalseValue();
- addEdge(TrueVal, &Inst, EdgeType::Assign);
- addEdge(FalseVal, &Inst, EdgeType::Assign);
- }
-
- void visitAllocaInst(AllocaInst &Inst) { Graph.addNode(&Inst); }
-
- void visitLoadInst(LoadInst &Inst) {
- auto *Ptr = Inst.getPointerOperand();
- auto *Val = &Inst;
- addEdge(Val, Ptr, EdgeType::Reference);
- }
-
- void visitStoreInst(StoreInst &Inst) {
- auto *Ptr = Inst.getPointerOperand();
- auto *Val = Inst.getValueOperand();
- addEdge(Ptr, Val, EdgeType::Dereference);
- }
-
- void visitVAArgInst(VAArgInst &Inst) {
- // We can't fully model va_arg here. For *Ptr = Inst.getOperand(0), it does
- // two things:
- // 1. Loads a value from *((T*)*Ptr).
- // 2. Increments (stores to) *Ptr by some target-specific amount.
- // For now, we'll handle this like a landingpad instruction (by placing the
- // result in its own group, and having that group alias externals).
- addNodeWithAttr(&Inst, getAttrUnknown());
- }
-
- static bool isFunctionExternal(Function *Fn) {
- return !Fn->hasExactDefinition();
- }
-
- bool tryInterproceduralAnalysis(CallSite CS,
- const SmallVectorImpl<Function *> &Fns) {
- assert(Fns.size() > 0);
-
- if (CS.arg_size() > MaxSupportedArgsInSummary)
- return false;
-
- // Exit early if we'll fail anyway
- for (auto *Fn : Fns) {
- if (isFunctionExternal(Fn) || Fn->isVarArg())
- return false;
- // Fail if the caller does not provide enough arguments
- assert(Fn->arg_size() <= CS.arg_size());
- auto &MaybeInfo = AA.ensureCached(Fn);
- if (!MaybeInfo.hasValue())
- return false;
- }
-
- for (auto *Fn : Fns) {
- auto &FnInfo = AA.ensureCached(Fn);
- assert(FnInfo.hasValue());
-
- auto &RetParamRelations = FnInfo->getRetParamRelations();
- for (auto &Relation : RetParamRelations) {
- auto IRelation = instantiateExternalRelation(Relation, CS);
- if (IRelation.hasValue())
- InstantiatedRelations.push_back(*IRelation);
- }
-
- auto &RetParamAttributes = FnInfo->getRetParamAttributes();
- for (auto &Attribute : RetParamAttributes) {
- auto IAttr = instantiateExternalAttribute(Attribute, CS);
- if (IAttr.hasValue())
- InstantiatedAttrs.push_back(*IAttr);
- }
- }
-
- return true;
- }
-
- void visitCallSite(CallSite CS) {
- auto Inst = CS.getInstruction();
-
- // Make sure all arguments and return value are added to the graph first
- for (Value *V : CS.args())
- addNode(V);
- if (Inst->getType()->isPointerTy())
- addNode(Inst);
-
- // Check if Inst is a call to a library function that allocates/deallocates
- // on the heap. Those kinds of functions do not introduce any aliases.
- // TODO: address other common library functions such as realloc(), strdup(),
- // etc.
- if (isMallocLikeFn(Inst, &TLI) || isCallocLikeFn(Inst, &TLI) ||
- isFreeCall(Inst, &TLI))
- return;
-
- // TODO: Add support for noalias args/all the other fun function attributes
- // that we can tack on.
- SmallVector<Function *, 4> Targets;
- if (getPossibleTargets(CS, Targets))
- if (tryInterproceduralAnalysis(CS, Targets))
- return;
-
- // Because the function is opaque, we need to note that anything
- // could have happened to the arguments (unless the function is marked
- // readonly or readnone), and that the result could alias just about
- // anything, too (unless the result is marked noalias).
- if (!CS.onlyReadsMemory())
- for (Value *V : CS.args()) {
- if (V->getType()->isPointerTy()) {
- // The argument itself escapes.
- addNodeWithAttr(V, getAttrEscaped());
- // The fate of argument memory is unknown. Note that since AliasAttrs
- // is transitive with respect to dereference, we only need to specify
- // it for the first-level memory.
- InstantiatedAttrs.push_back(
- InstantiatedAttr{InstantiatedValue{V, 1}, getAttrUnknown()});
- }
- }
-
- if (Inst->getType()->isPointerTy()) {
- auto *Fn = CS.getCalledFunction();
- if (Fn == nullptr || !Fn->doesNotAlias(0))
- // No need to call addNodeWithAttr() since we've added Inst at the
- // beginning of this function and we know it is not a global.
- Graph.addAttr(Inst, getAttrUnknown());
- }
- }
-
- /// Because vectors/aggregates are immutable and unaddressable, there's
- /// nothing we can do to coax a value out of them, other than calling
- /// Extract{Element,Value}. We can effectively treat them as pointers to
- /// arbitrary memory locations we can store in and load from.
- void visitExtractElementInst(ExtractElementInst &Inst) {
- auto *Ptr = Inst.getVectorOperand();
- auto *Val = &Inst;
- addEdge(Val, Ptr, EdgeType::Reference);
- }
-
- void visitInsertElementInst(InsertElementInst &Inst) {
- auto *Vec = Inst.getOperand(0);
- auto *Val = Inst.getOperand(1);
- addEdge(Vec, &Inst, EdgeType::Assign);
- addEdge(&Inst, Val, EdgeType::Dereference);
- }
-
- void visitLandingPadInst(LandingPadInst &Inst) {
- // Exceptions come from "nowhere", from our analysis' perspective.
- // So we place the instruction its own group, noting that said group may
- // alias externals
- addNodeWithAttr(&Inst, getAttrUnknown());
- }
-
- void visitInsertValueInst(InsertValueInst &Inst) {
- auto *Agg = Inst.getOperand(0);
- auto *Val = Inst.getOperand(1);
- addEdge(Agg, &Inst, EdgeType::Assign);
- addEdge(&Inst, Val, EdgeType::Dereference);
- }
-
- void visitExtractValueInst(ExtractValueInst &Inst) {
- auto *Ptr = Inst.getAggregateOperand();
- addEdge(&Inst, Ptr, EdgeType::Reference);
- }
-
- void visitShuffleVectorInst(ShuffleVectorInst &Inst) {
- auto *From1 = Inst.getOperand(0);
- auto *From2 = Inst.getOperand(1);
- addEdge(From1, &Inst, EdgeType::Assign);
- addEdge(From2, &Inst, EdgeType::Assign);
- }
-
- void visitConstantExpr(ConstantExpr *CE) {
- switch (CE->getOpcode()) {
- default:
- llvm_unreachable("Unknown instruction type encountered!");
-// Build the switch statement using the Instruction.def file.
-#define HANDLE_INST(NUM, OPCODE, CLASS) \
- case Instruction::OPCODE: \
- visit##OPCODE(*(CLASS *)CE); \
- break;
-#include "llvm/IR/Instruction.def"
- }
- }
-};
-
-class CFLGraphBuilder {
- // Input of the builder
- CFLSteensAAResult &Analysis;
- const TargetLibraryInfo &TLI;
-
- // Output of the builder
- CFLGraph Graph;
- SmallVector<Value *, 4> ReturnedValues;
-
- // Auxiliary structures used by the builder
- SmallVector<InstantiatedRelation, 8> InstantiatedRelations;
- SmallVector<InstantiatedAttr, 8> InstantiatedAttrs;
-
- // Helper functions
-
- // Determines whether or not we an instruction is useless to us (e.g.
- // FenceInst)
- static bool hasUsefulEdges(Instruction *Inst) {
- bool IsNonInvokeRetTerminator = isa<TerminatorInst>(Inst) &&
- !isa<InvokeInst>(Inst) &&
- !isa<ReturnInst>(Inst);
- return !isa<CmpInst>(Inst) && !isa<FenceInst>(Inst) &&
- !IsNonInvokeRetTerminator;
- }
-
- void addArgumentToGraph(Argument &Arg) {
- if (Arg.getType()->isPointerTy()) {
- Graph.addNode(&Arg);
- Graph.addAttr(&Arg, getGlobalOrArgAttrFromValue(Arg));
- // Pointees of a formal parameter is known to the caller
- InstantiatedAttrs.push_back(
- InstantiatedAttr{InstantiatedValue{&Arg, 1}, getAttrCaller()});
- }
- }
-
- // Given an Instruction, this will add it to the graph, along with any
- // Instructions that are potentially only available from said Instruction
- // For example, given the following line:
- // %0 = load i16* getelementptr ([1 x i16]* @a, 0, 0), align 2
- // addInstructionToGraph would add both the `load` and `getelementptr`
- // instructions to the graph appropriately.
- void addInstructionToGraph(Instruction &Inst) {
- if (!hasUsefulEdges(&Inst))
- return;
-
- GetEdgesVisitor(Analysis, TLI, Graph, ReturnedValues, InstantiatedRelations,
- InstantiatedAttrs)
- .visit(Inst);
- }
-
- // Builds the graph needed for constructing the StratifiedSets for the given
- // function
- void buildGraphFrom(Function &Fn) {
- for (auto &Bb : Fn.getBasicBlockList())
- for (auto &Inst : Bb.getInstList())
- addInstructionToGraph(Inst);
-
- for (auto &Arg : Fn.args())
- addArgumentToGraph(Arg);
- }
-
-public:
- CFLGraphBuilder(CFLSteensAAResult &Analysis, const TargetLibraryInfo &TLI,
- Function &Fn)
- : Analysis(Analysis), TLI(TLI) {
- buildGraphFrom(Fn);
- }
-
- const CFLGraph &getCFLGraph() const { return Graph; }
- const SmallVector<Value *, 4> &getReturnValues() const {
- return ReturnedValues;
- }
- const SmallVector<InstantiatedRelation, 8> &getInstantiatedRelations() const {
- return InstantiatedRelations;
- }
- const SmallVector<InstantiatedAttr, 8> &getInstantiatedAttrs() const {
- return InstantiatedAttrs;
- }
-};
}
//===----------------------------------------------------------------------===//
@@ -514,18 +113,6 @@ static Optional<Function *> parentFuncti
return None;
}
-static bool getPossibleTargets(CallSite CS,
- SmallVectorImpl<Function *> &Output) {
- if (auto *Fn = CS.getCalledFunction()) {
- Output.push_back(Fn);
- return true;
- }
-
- // TODO: If the call is indirect, we might be able to enumerate all potential
- // targets of the call and return them, rather than just failing.
- return false;
-}
-
static Level directionOfEdgeType(EdgeType Weight) {
switch (Weight) {
case EdgeType::Reference:
@@ -586,7 +173,8 @@ CFLSteensAAResult::FunctionInfo::Functio
auto Itr = InterfaceMap.find(SetIndex);
if (Itr != InterfaceMap.end()) {
if (CurrValue != Itr->second)
- RetParamRelations.push_back(ExternalRelation{CurrValue, Itr->second});
+ Summary.RetParamRelations.push_back(
+ ExternalRelation{CurrValue, Itr->second});
break;
}
@@ -594,7 +182,7 @@ CFLSteensAAResult::FunctionInfo::Functio
InterfaceMap.insert(std::make_pair(SetIndex, CurrValue));
auto ExternalAttrs = getExternallyVisibleAttrs(Link.Attrs);
if (ExternalAttrs.any())
- RetParamAttributes.push_back(
+ Summary.RetParamAttributes.push_back(
ExternalAttribute{CurrValue, ExternalAttrs});
if (!Link.hasBelow())
@@ -628,7 +216,7 @@ CFLSteensAAResult::FunctionInfo::Functio
// Builds the graph + StratifiedSets for a function.
CFLSteensAAResult::FunctionInfo CFLSteensAAResult::buildSetsFrom(Function *Fn) {
- CFLGraphBuilder GraphBuilder(*this, TLI, *Fn);
+ CFLGraphBuilder<CFLSteensAAResult> GraphBuilder(*this, TLI, *Fn);
StratifiedSetsBuilder<Value *> SetBuilder;
auto &Graph = GraphBuilder.getCFLGraph();
@@ -721,6 +309,14 @@ CFLSteensAAResult::ensureCached(Function
return Iter->second;
}
+const AliasSummary *CFLSteensAAResult::getAliasSummary(Function &Fn) {
+ auto &FunInfo = ensureCached(&Fn);
+ if (FunInfo.hasValue())
+ return &FunInfo->getAliasSummary();
+ else
+ return nullptr;
+}
+
AliasResult CFLSteensAAResult::query(const MemoryLocation &LocA,
const MemoryLocation &LocB) {
auto *ValA = const_cast<Value *>(LocA.Ptr);
@@ -793,8 +389,8 @@ ModRefInfo CFLSteensAAResult::getArgModR
auto &MaybeInfo = ensureCached(const_cast<Function *>(CalledFunc));
if (!MaybeInfo.hasValue())
return MRI_ModRef;
- auto &RetParamAttributes = MaybeInfo->getRetParamAttributes();
- auto &RetParamRelations = MaybeInfo->getRetParamRelations();
+ auto &RetParamAttributes = MaybeInfo->getAliasSummary().RetParamAttributes;
+ auto &RetParamRelations = MaybeInfo->getAliasSummary().RetParamRelations;
bool ArgAttributeIsWritten =
std::any_of(RetParamAttributes.begin(), RetParamAttributes.end(),
@@ -832,8 +428,8 @@ FunctionModRefBehavior CFLSteensAAResult
auto &MaybeInfo = ensureCached(const_cast<Function *>(F));
if (!MaybeInfo.hasValue())
return FMRB_UnknownModRefBehavior;
- auto &RetParamAttributes = MaybeInfo->getRetParamAttributes();
- auto &RetParamRelations = MaybeInfo->getRetParamRelations();
+ auto &RetParamAttributes = MaybeInfo->getAliasSummary().RetParamAttributes;
+ auto &RetParamRelations = MaybeInfo->getAliasSummary().RetParamRelations;
// First, if any argument is marked Escpaed, Unknown or Global, anything may
// happen to them and thus we can't draw any conclusion.
More information about the llvm-commits
mailing list