summaryrefslogtreecommitdiffstats
path: root/llvm/lib
diff options
context:
space:
mode:
authorVitaly Buka <vitalybuka@google.com>2018-11-26 23:05:58 +0000
committerVitaly Buka <vitalybuka@google.com>2018-11-26 23:05:58 +0000
commit42b050673e91141af74470b03fce85fa8a3bf3c5 (patch)
tree4ebc892c0ad9e1d2797a6d2a0d37aceae464bc74 /llvm/lib
parentb8e6fa66387aabe2c3ac8c952a8c151e040370d2 (diff)
downloadbcm5719-llvm-42b050673e91141af74470b03fce85fa8a3bf3c5.tar.gz
bcm5719-llvm-42b050673e91141af74470b03fce85fa8a3bf3c5.zip
[stack-safety] Inter-Procedural Analysis implementation
Summary: IPA is implemented as module pass which produce map from Function or Alias to StackSafetyInfo for a single function. From prototype by Evgenii Stepanov and Vlad Tsyrklevich. Reviewers: eugenis, vlad.tsyrklevich, pcc, glider Subscribers: hiraditya, mgrang, llvm-commits Differential Revision: https://reviews.llvm.org/D54543 llvm-svn: 347611
Diffstat (limited to 'llvm/lib')
-rw-r--r--llvm/lib/Analysis/StackSafetyAnalysis.cpp207
1 files changed, 203 insertions, 4 deletions
diff --git a/llvm/lib/Analysis/StackSafetyAnalysis.cpp b/llvm/lib/Analysis/StackSafetyAnalysis.cpp
index 008d2b7647c..11411175f20 100644
--- a/llvm/lib/Analysis/StackSafetyAnalysis.cpp
+++ b/llvm/lib/Analysis/StackSafetyAnalysis.cpp
@@ -10,7 +10,6 @@
//===----------------------------------------------------------------------===//
#include "llvm/Analysis/StackSafetyAnalysis.h"
-#include "llvm/ADT/StringExtras.h"
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
#include "llvm/IR/CallSite.h"
#include "llvm/IR/InstIterator.h"
@@ -21,6 +20,9 @@ using namespace llvm;
#define DEBUG_TYPE "stack-safety"
+static cl::opt<int> StackSafetyMaxIterations("stack-safety-max-iterations",
+ cl::init(20), cl::Hidden);
+
namespace {
/// Rewrite an SCEV expression for a memory access address to an expression that
@@ -150,9 +152,14 @@ struct StackSafetyInfo::FunctionInfo {
SmallVector<ParamInfo, 4> Params;
// TODO: describe return value as depending on one or more of its arguments.
+ // StackSafetyDataFlowAnalysis counter stored here for faster access.
+ int UpdateCount = 0;
+
FunctionInfo(const StackSafetyInfo &SSI) : FunctionInfo(*SSI.Info) {}
explicit FunctionInfo(const Function *F) : GV(F){};
+ // Creates FunctionInfo that forwards all the parameters to the aliasee.
+ explicit FunctionInfo(const GlobalAlias *A);
FunctionInfo(FunctionInfo &&) = default;
@@ -163,6 +170,8 @@ struct StackSafetyInfo::FunctionInfo {
StringRef getName() const { return GV->getName(); }
void print(raw_ostream &O) const {
+ // TODO: Consider different printout format after
+ // StackSafetyDataFlowAnalysis. Calls and parameters are irrelevant then.
O << " @" << getName() << (IsDSOLocal() ? "" : " dso_preemptable")
<< (IsInterposable() ? " interposable" : "") << "\n";
O << " args uses:\n";
@@ -177,6 +186,18 @@ private:
FunctionInfo(const FunctionInfo &) = default;
};
+StackSafetyInfo::FunctionInfo::FunctionInfo(const GlobalAlias *A) : GV(A) {
+ unsigned PointerSize = A->getParent()->getDataLayout().getPointerSizeInBits();
+ const GlobalObject *Aliasee = A->getBaseObject();
+ const FunctionType *Type = cast<FunctionType>(Aliasee->getValueType());
+ // 'Forward' all parameters to this alias to the aliasee
+ for (unsigned ArgNo = 0; ArgNo < Type->getNumParams(); ArgNo++) {
+ Params.emplace_back(PointerSize, nullptr);
+ UseInfo &US = Params.back().Use;
+ US.Calls.emplace_back(Aliasee, ArgNo, ConstantRange(APInt(PointerSize, 0)));
+ }
+}
+
namespace {
class StackSafetyLocalAnalysis {
@@ -373,8 +394,172 @@ StackSafetyInfo StackSafetyLocalAnalysis::run() {
return StackSafetyInfo(std::move(Info));
}
+class StackSafetyDataFlowAnalysis {
+ using FunctionMap =
+ std::map<const GlobalValue *, StackSafetyInfo::FunctionInfo>;
+
+ FunctionMap Functions;
+ // Callee-to-Caller multimap.
+ DenseMap<const GlobalValue *, SmallVector<const GlobalValue *, 4>> Callers;
+ SetVector<const GlobalValue *> WorkList;
+
+ unsigned PointerSize = 0;
+ const ConstantRange UnknownRange;
+
+ ConstantRange getArgumentAccessRange(const GlobalValue *Callee,
+ unsigned ParamNo) const;
+ bool updateOneUse(UseInfo &US, bool UpdateToFullSet);
+ void updateOneNode(const GlobalValue *Callee,
+ StackSafetyInfo::FunctionInfo &FS);
+ void updateOneNode(const GlobalValue *Callee) {
+ updateOneNode(Callee, Functions.find(Callee)->second);
+ }
+ void updateAllNodes() {
+ for (auto &F : Functions)
+ updateOneNode(F.first, F.second);
+ }
+ void runDataFlow();
+ void verifyFixedPoint();
+
+public:
+ StackSafetyDataFlowAnalysis(
+ Module &M, std::function<const StackSafetyInfo &(Function &)> FI);
+ StackSafetyGlobalInfo run();
+};
+
+StackSafetyDataFlowAnalysis::StackSafetyDataFlowAnalysis(
+ Module &M, std::function<const StackSafetyInfo &(Function &)> FI)
+ : PointerSize(M.getDataLayout().getPointerSizeInBits()),
+ UnknownRange(PointerSize, true) {
+ // Without ThinLTO, run the local analysis for every function in the TU and
+ // then run the DFA and annotate allocas
+ for (auto &F : M.functions())
+ if (!F.isDeclaration())
+ Functions.emplace(&F, FI(F));
+ for (auto &A : M.aliases())
+ if (isa<Function>(A.getBaseObject()))
+ Functions.emplace(&A, &A);
+}
+
+ConstantRange
+StackSafetyDataFlowAnalysis::getArgumentAccessRange(const GlobalValue *Callee,
+ unsigned ParamNo) const {
+ auto IT = Functions.find(Callee);
+ // Unknown callee (outside of LTO domain or an indirect call).
+ if (IT == Functions.end())
+ return UnknownRange;
+ const StackSafetyInfo::FunctionInfo &FS = IT->second;
+ // The definition of this symbol may not be the definition in this linkage
+ // unit.
+ if (!FS.IsDSOLocal() || FS.IsInterposable())
+ return UnknownRange;
+ if (ParamNo >= FS.Params.size()) // possibly vararg
+ return UnknownRange;
+ return FS.Params[ParamNo].Use.Range;
+}
+
+bool StackSafetyDataFlowAnalysis::updateOneUse(UseInfo &US,
+ bool UpdateToFullSet) {
+ bool Changed = false;
+ for (auto &CS : US.Calls) {
+ assert(!CS.Range.isEmptySet() &&
+ "Param range can't be empty-set, invalid access range");
+
+ ConstantRange CalleeRange = getArgumentAccessRange(CS.Callee, CS.ParamNo);
+ CalleeRange = CalleeRange.add(CS.Offset);
+ if (!US.Range.contains(CalleeRange)) {
+ Changed = true;
+ if (UpdateToFullSet)
+ US.Range = UnknownRange;
+ else
+ US.Range = US.Range.unionWith(CalleeRange);
+ }
+ }
+ return Changed;
+}
+
+void StackSafetyDataFlowAnalysis::updateOneNode(
+ const GlobalValue *Callee, StackSafetyInfo::FunctionInfo &FS) {
+ bool UpdateToFullSet = FS.UpdateCount > StackSafetyMaxIterations;
+ bool Changed = false;
+ for (auto &AS : FS.Allocas)
+ Changed |= updateOneUse(AS.Use, UpdateToFullSet);
+ for (auto &PS : FS.Params)
+ Changed |= updateOneUse(PS.Use, UpdateToFullSet);
+
+ if (Changed) {
+ LLVM_DEBUG(dbgs() << "=== update [" << FS.UpdateCount
+ << (UpdateToFullSet ? ", full-set" : "") << "] "
+ << FS.getName() << "\n");
+ // Callers of this function may need updating.
+ for (auto &CallerID : Callers[Callee])
+ WorkList.insert(CallerID);
+
+ ++FS.UpdateCount;
+ }
+}
+
+void StackSafetyDataFlowAnalysis::runDataFlow() {
+ Callers.clear();
+ WorkList.clear();
+
+ SmallVector<const GlobalValue *, 16> Callees;
+ for (auto &F : Functions) {
+ Callees.clear();
+ StackSafetyInfo::FunctionInfo &FS = F.second;
+ for (auto &AS : FS.Allocas)
+ for (auto &CS : AS.Use.Calls)
+ Callees.push_back(CS.Callee);
+ for (auto &PS : FS.Params)
+ for (auto &CS : PS.Use.Calls)
+ Callees.push_back(CS.Callee);
+
+ llvm::sort(Callees);
+ Callees.erase(std::unique(Callees.begin(), Callees.end()), Callees.end());
+
+ for (auto &Callee : Callees)
+ Callers[Callee].push_back(F.first);
+ }
+
+ updateAllNodes();
+
+ while (!WorkList.empty()) {
+ const GlobalValue *Callee = WorkList.back();
+ WorkList.pop_back();
+ updateOneNode(Callee);
+ }
+}
+
+void StackSafetyDataFlowAnalysis::verifyFixedPoint() {
+ WorkList.clear();
+ updateAllNodes();
+ assert(WorkList.empty());
+}
+
+StackSafetyGlobalInfo StackSafetyDataFlowAnalysis::run() {
+ runDataFlow();
+ LLVM_DEBUG(verifyFixedPoint());
+
+ StackSafetyGlobalInfo SSI;
+ for (auto &F : Functions)
+ SSI.emplace(F.first, std::move(F.second));
+ return SSI;
+}
+
void print(const StackSafetyGlobalInfo &SSI, raw_ostream &O, const Module &M) {
- O << "Not Implemented\n";
+ size_t Count = 0;
+ for (auto &F : M.functions())
+ if (!F.isDeclaration()) {
+ SSI.find(&F)->second.print(O);
+ O << "\n";
+ ++Count;
+ }
+ for (auto &A : M.aliases()) {
+ SSI.find(&A)->second.print(O);
+ O << "\n";
+ ++Count;
+ }
+ assert(Count == SSI.size() && "Unexpected functions in the result");
}
} // end anonymous namespace
@@ -431,7 +616,14 @@ AnalysisKey StackSafetyGlobalAnalysis::Key;
StackSafetyGlobalInfo
StackSafetyGlobalAnalysis::run(Module &M, ModuleAnalysisManager &AM) {
- return {};
+ FunctionAnalysisManager &FAM =
+ AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
+
+ StackSafetyDataFlowAnalysis SSDFA(
+ M, [&FAM](Function &F) -> const StackSafetyInfo & {
+ return FAM.getResult<StackSafetyAnalysis>(F);
+ });
+ return SSDFA.run();
}
PreservedAnalyses StackSafetyGlobalPrinterPass::run(Module &M,
@@ -459,7 +651,14 @@ void StackSafetyGlobalInfoWrapperPass::getAnalysisUsage(
AU.addRequired<StackSafetyInfoWrapperPass>();
}
-bool StackSafetyGlobalInfoWrapperPass::runOnModule(Module &M) { return false; }
+bool StackSafetyGlobalInfoWrapperPass::runOnModule(Module &M) {
+ StackSafetyDataFlowAnalysis SSDFA(
+ M, [this](Function &F) -> const StackSafetyInfo & {
+ return getAnalysis<StackSafetyInfoWrapperPass>(F).getResult();
+ });
+ SSI = SSDFA.run();
+ return false;
+}
static const char LocalPassArg[] = "stack-safety-local";
static const char LocalPassName[] = "Stack Safety Local Analysis";
OpenPOWER on IntegriCloud