You've already forked linux-packaging-mono
Imported Upstream version 5.18.0.167
Former-commit-id: 289509151e0fee68a1b591a20c9f109c3c789d3a
This commit is contained in:
parent
e19d552987
commit
b084638f15
816
external/llvm/lib/Analysis/AliasAnalysis.cpp
vendored
816
external/llvm/lib/Analysis/AliasAnalysis.cpp
vendored
File diff suppressed because it is too large
Load Diff
@ -1,444 +0,0 @@
|
||||
//===- AliasAnalysisEvaluator.cpp - Alias Analysis Accuracy Evaluator -----===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Analysis/AliasAnalysisEvaluator.h"
|
||||
#include "llvm/ADT/SetVector.h"
|
||||
#include "llvm/Analysis/AliasAnalysis.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
#include "llvm/IR/DerivedTypes.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/InstIterator.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
using namespace llvm;
|
||||
|
||||
static cl::opt<bool> PrintAll("print-all-alias-modref-info", cl::ReallyHidden);
|
||||
|
||||
static cl::opt<bool> PrintNoAlias("print-no-aliases", cl::ReallyHidden);
|
||||
static cl::opt<bool> PrintMayAlias("print-may-aliases", cl::ReallyHidden);
|
||||
static cl::opt<bool> PrintPartialAlias("print-partial-aliases", cl::ReallyHidden);
|
||||
static cl::opt<bool> PrintMustAlias("print-must-aliases", cl::ReallyHidden);
|
||||
|
||||
static cl::opt<bool> PrintNoModRef("print-no-modref", cl::ReallyHidden);
|
||||
static cl::opt<bool> PrintRef("print-ref", cl::ReallyHidden);
|
||||
static cl::opt<bool> PrintMod("print-mod", cl::ReallyHidden);
|
||||
static cl::opt<bool> PrintModRef("print-modref", cl::ReallyHidden);
|
||||
static cl::opt<bool> PrintMust("print-must", cl::ReallyHidden);
|
||||
static cl::opt<bool> PrintMustRef("print-mustref", cl::ReallyHidden);
|
||||
static cl::opt<bool> PrintMustMod("print-mustmod", cl::ReallyHidden);
|
||||
static cl::opt<bool> PrintMustModRef("print-mustmodref", cl::ReallyHidden);
|
||||
|
||||
static cl::opt<bool> EvalAAMD("evaluate-aa-metadata", cl::ReallyHidden);
|
||||
|
||||
static void PrintResults(const char *Msg, bool P, const Value *V1,
|
||||
const Value *V2, const Module *M) {
|
||||
if (PrintAll || P) {
|
||||
std::string o1, o2;
|
||||
{
|
||||
raw_string_ostream os1(o1), os2(o2);
|
||||
V1->printAsOperand(os1, true, M);
|
||||
V2->printAsOperand(os2, true, M);
|
||||
}
|
||||
|
||||
if (o2 < o1)
|
||||
std::swap(o1, o2);
|
||||
errs() << " " << Msg << ":\t"
|
||||
<< o1 << ", "
|
||||
<< o2 << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
PrintModRefResults(const char *Msg, bool P, Instruction *I, Value *Ptr,
|
||||
Module *M) {
|
||||
if (PrintAll || P) {
|
||||
errs() << " " << Msg << ": Ptr: ";
|
||||
Ptr->printAsOperand(errs(), true, M);
|
||||
errs() << "\t<->" << *I << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
PrintModRefResults(const char *Msg, bool P, CallSite CSA, CallSite CSB,
|
||||
Module *M) {
|
||||
if (PrintAll || P) {
|
||||
errs() << " " << Msg << ": " << *CSA.getInstruction()
|
||||
<< " <-> " << *CSB.getInstruction() << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
PrintLoadStoreResults(const char *Msg, bool P, const Value *V1,
|
||||
const Value *V2, const Module *M) {
|
||||
if (PrintAll || P) {
|
||||
errs() << " " << Msg << ": " << *V1
|
||||
<< " <-> " << *V2 << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool isInterestingPointer(Value *V) {
|
||||
return V->getType()->isPointerTy()
|
||||
&& !isa<ConstantPointerNull>(V);
|
||||
}
|
||||
|
||||
PreservedAnalyses AAEvaluator::run(Function &F, FunctionAnalysisManager &AM) {
|
||||
runInternal(F, AM.getResult<AAManager>(F));
|
||||
return PreservedAnalyses::all();
|
||||
}
|
||||
|
||||
void AAEvaluator::runInternal(Function &F, AAResults &AA) {
|
||||
const DataLayout &DL = F.getParent()->getDataLayout();
|
||||
|
||||
++FunctionCount;
|
||||
|
||||
SetVector<Value *> Pointers;
|
||||
SmallSetVector<CallSite, 16> CallSites;
|
||||
SetVector<Value *> Loads;
|
||||
SetVector<Value *> Stores;
|
||||
|
||||
for (auto &I : F.args())
|
||||
if (I.getType()->isPointerTy()) // Add all pointer arguments.
|
||||
Pointers.insert(&I);
|
||||
|
||||
for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) {
|
||||
if (I->getType()->isPointerTy()) // Add all pointer instructions.
|
||||
Pointers.insert(&*I);
|
||||
if (EvalAAMD && isa<LoadInst>(&*I))
|
||||
Loads.insert(&*I);
|
||||
if (EvalAAMD && isa<StoreInst>(&*I))
|
||||
Stores.insert(&*I);
|
||||
Instruction &Inst = *I;
|
||||
if (auto CS = CallSite(&Inst)) {
|
||||
Value *Callee = CS.getCalledValue();
|
||||
// Skip actual functions for direct function calls.
|
||||
if (!isa<Function>(Callee) && isInterestingPointer(Callee))
|
||||
Pointers.insert(Callee);
|
||||
// Consider formals.
|
||||
for (Use &DataOp : CS.data_ops())
|
||||
if (isInterestingPointer(DataOp))
|
||||
Pointers.insert(DataOp);
|
||||
CallSites.insert(CS);
|
||||
} else {
|
||||
// Consider all operands.
|
||||
for (Instruction::op_iterator OI = Inst.op_begin(), OE = Inst.op_end();
|
||||
OI != OE; ++OI)
|
||||
if (isInterestingPointer(*OI))
|
||||
Pointers.insert(*OI);
|
||||
}
|
||||
}
|
||||
|
||||
if (PrintAll || PrintNoAlias || PrintMayAlias || PrintPartialAlias ||
|
||||
PrintMustAlias || PrintNoModRef || PrintMod || PrintRef || PrintModRef)
|
||||
errs() << "Function: " << F.getName() << ": " << Pointers.size()
|
||||
<< " pointers, " << CallSites.size() << " call sites\n";
|
||||
|
||||
// iterate over the worklist, and run the full (n^2)/2 disambiguations
|
||||
for (SetVector<Value *>::iterator I1 = Pointers.begin(), E = Pointers.end();
|
||||
I1 != E; ++I1) {
|
||||
uint64_t I1Size = MemoryLocation::UnknownSize;
|
||||
Type *I1ElTy = cast<PointerType>((*I1)->getType())->getElementType();
|
||||
if (I1ElTy->isSized()) I1Size = DL.getTypeStoreSize(I1ElTy);
|
||||
|
||||
for (SetVector<Value *>::iterator I2 = Pointers.begin(); I2 != I1; ++I2) {
|
||||
uint64_t I2Size = MemoryLocation::UnknownSize;
|
||||
Type *I2ElTy =cast<PointerType>((*I2)->getType())->getElementType();
|
||||
if (I2ElTy->isSized()) I2Size = DL.getTypeStoreSize(I2ElTy);
|
||||
|
||||
switch (AA.alias(*I1, I1Size, *I2, I2Size)) {
|
||||
case NoAlias:
|
||||
PrintResults("NoAlias", PrintNoAlias, *I1, *I2, F.getParent());
|
||||
++NoAliasCount;
|
||||
break;
|
||||
case MayAlias:
|
||||
PrintResults("MayAlias", PrintMayAlias, *I1, *I2, F.getParent());
|
||||
++MayAliasCount;
|
||||
break;
|
||||
case PartialAlias:
|
||||
PrintResults("PartialAlias", PrintPartialAlias, *I1, *I2,
|
||||
F.getParent());
|
||||
++PartialAliasCount;
|
||||
break;
|
||||
case MustAlias:
|
||||
PrintResults("MustAlias", PrintMustAlias, *I1, *I2, F.getParent());
|
||||
++MustAliasCount;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (EvalAAMD) {
|
||||
// iterate over all pairs of load, store
|
||||
for (Value *Load : Loads) {
|
||||
for (Value *Store : Stores) {
|
||||
switch (AA.alias(MemoryLocation::get(cast<LoadInst>(Load)),
|
||||
MemoryLocation::get(cast<StoreInst>(Store)))) {
|
||||
case NoAlias:
|
||||
PrintLoadStoreResults("NoAlias", PrintNoAlias, Load, Store,
|
||||
F.getParent());
|
||||
++NoAliasCount;
|
||||
break;
|
||||
case MayAlias:
|
||||
PrintLoadStoreResults("MayAlias", PrintMayAlias, Load, Store,
|
||||
F.getParent());
|
||||
++MayAliasCount;
|
||||
break;
|
||||
case PartialAlias:
|
||||
PrintLoadStoreResults("PartialAlias", PrintPartialAlias, Load, Store,
|
||||
F.getParent());
|
||||
++PartialAliasCount;
|
||||
break;
|
||||
case MustAlias:
|
||||
PrintLoadStoreResults("MustAlias", PrintMustAlias, Load, Store,
|
||||
F.getParent());
|
||||
++MustAliasCount;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// iterate over all pairs of store, store
|
||||
for (SetVector<Value *>::iterator I1 = Stores.begin(), E = Stores.end();
|
||||
I1 != E; ++I1) {
|
||||
for (SetVector<Value *>::iterator I2 = Stores.begin(); I2 != I1; ++I2) {
|
||||
switch (AA.alias(MemoryLocation::get(cast<StoreInst>(*I1)),
|
||||
MemoryLocation::get(cast<StoreInst>(*I2)))) {
|
||||
case NoAlias:
|
||||
PrintLoadStoreResults("NoAlias", PrintNoAlias, *I1, *I2,
|
||||
F.getParent());
|
||||
++NoAliasCount;
|
||||
break;
|
||||
case MayAlias:
|
||||
PrintLoadStoreResults("MayAlias", PrintMayAlias, *I1, *I2,
|
||||
F.getParent());
|
||||
++MayAliasCount;
|
||||
break;
|
||||
case PartialAlias:
|
||||
PrintLoadStoreResults("PartialAlias", PrintPartialAlias, *I1, *I2,
|
||||
F.getParent());
|
||||
++PartialAliasCount;
|
||||
break;
|
||||
case MustAlias:
|
||||
PrintLoadStoreResults("MustAlias", PrintMustAlias, *I1, *I2,
|
||||
F.getParent());
|
||||
++MustAliasCount;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mod/ref alias analysis: compare all pairs of calls and values
|
||||
for (CallSite C : CallSites) {
|
||||
Instruction *I = C.getInstruction();
|
||||
|
||||
for (auto Pointer : Pointers) {
|
||||
uint64_t Size = MemoryLocation::UnknownSize;
|
||||
Type *ElTy = cast<PointerType>(Pointer->getType())->getElementType();
|
||||
if (ElTy->isSized()) Size = DL.getTypeStoreSize(ElTy);
|
||||
|
||||
switch (AA.getModRefInfo(C, Pointer, Size)) {
|
||||
case ModRefInfo::NoModRef:
|
||||
PrintModRefResults("NoModRef", PrintNoModRef, I, Pointer,
|
||||
F.getParent());
|
||||
++NoModRefCount;
|
||||
break;
|
||||
case ModRefInfo::Mod:
|
||||
PrintModRefResults("Just Mod", PrintMod, I, Pointer, F.getParent());
|
||||
++ModCount;
|
||||
break;
|
||||
case ModRefInfo::Ref:
|
||||
PrintModRefResults("Just Ref", PrintRef, I, Pointer, F.getParent());
|
||||
++RefCount;
|
||||
break;
|
||||
case ModRefInfo::ModRef:
|
||||
PrintModRefResults("Both ModRef", PrintModRef, I, Pointer,
|
||||
F.getParent());
|
||||
++ModRefCount;
|
||||
break;
|
||||
case ModRefInfo::Must:
|
||||
PrintModRefResults("Must", PrintMust, I, Pointer, F.getParent());
|
||||
++MustCount;
|
||||
break;
|
||||
case ModRefInfo::MustMod:
|
||||
PrintModRefResults("Just Mod (MustAlias)", PrintMustMod, I, Pointer,
|
||||
F.getParent());
|
||||
++MustModCount;
|
||||
break;
|
||||
case ModRefInfo::MustRef:
|
||||
PrintModRefResults("Just Ref (MustAlias)", PrintMustRef, I, Pointer,
|
||||
F.getParent());
|
||||
++MustRefCount;
|
||||
break;
|
||||
case ModRefInfo::MustModRef:
|
||||
PrintModRefResults("Both ModRef (MustAlias)", PrintMustModRef, I,
|
||||
Pointer, F.getParent());
|
||||
++MustModRefCount;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mod/ref alias analysis: compare all pairs of calls
|
||||
for (auto C = CallSites.begin(), Ce = CallSites.end(); C != Ce; ++C) {
|
||||
for (auto D = CallSites.begin(); D != Ce; ++D) {
|
||||
if (D == C)
|
||||
continue;
|
||||
switch (AA.getModRefInfo(*C, *D)) {
|
||||
case ModRefInfo::NoModRef:
|
||||
PrintModRefResults("NoModRef", PrintNoModRef, *C, *D, F.getParent());
|
||||
++NoModRefCount;
|
||||
break;
|
||||
case ModRefInfo::Mod:
|
||||
PrintModRefResults("Just Mod", PrintMod, *C, *D, F.getParent());
|
||||
++ModCount;
|
||||
break;
|
||||
case ModRefInfo::Ref:
|
||||
PrintModRefResults("Just Ref", PrintRef, *C, *D, F.getParent());
|
||||
++RefCount;
|
||||
break;
|
||||
case ModRefInfo::ModRef:
|
||||
PrintModRefResults("Both ModRef", PrintModRef, *C, *D, F.getParent());
|
||||
++ModRefCount;
|
||||
break;
|
||||
case ModRefInfo::Must:
|
||||
PrintModRefResults("Must", PrintMust, *C, *D, F.getParent());
|
||||
++MustCount;
|
||||
break;
|
||||
case ModRefInfo::MustMod:
|
||||
PrintModRefResults("Just Mod (MustAlias)", PrintMustMod, *C, *D,
|
||||
F.getParent());
|
||||
++MustModCount;
|
||||
break;
|
||||
case ModRefInfo::MustRef:
|
||||
PrintModRefResults("Just Ref (MustAlias)", PrintMustRef, *C, *D,
|
||||
F.getParent());
|
||||
++MustRefCount;
|
||||
break;
|
||||
case ModRefInfo::MustModRef:
|
||||
PrintModRefResults("Both ModRef (MustAlias)", PrintMustModRef, *C, *D,
|
||||
F.getParent());
|
||||
++MustModRefCount;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void PrintPercent(int64_t Num, int64_t Sum) {
|
||||
errs() << "(" << Num * 100LL / Sum << "." << ((Num * 1000LL / Sum) % 10)
|
||||
<< "%)\n";
|
||||
}
|
||||
|
||||
AAEvaluator::~AAEvaluator() {
|
||||
if (FunctionCount == 0)
|
||||
return;
|
||||
|
||||
int64_t AliasSum =
|
||||
NoAliasCount + MayAliasCount + PartialAliasCount + MustAliasCount;
|
||||
errs() << "===== Alias Analysis Evaluator Report =====\n";
|
||||
if (AliasSum == 0) {
|
||||
errs() << " Alias Analysis Evaluator Summary: No pointers!\n";
|
||||
} else {
|
||||
errs() << " " << AliasSum << " Total Alias Queries Performed\n";
|
||||
errs() << " " << NoAliasCount << " no alias responses ";
|
||||
PrintPercent(NoAliasCount, AliasSum);
|
||||
errs() << " " << MayAliasCount << " may alias responses ";
|
||||
PrintPercent(MayAliasCount, AliasSum);
|
||||
errs() << " " << PartialAliasCount << " partial alias responses ";
|
||||
PrintPercent(PartialAliasCount, AliasSum);
|
||||
errs() << " " << MustAliasCount << " must alias responses ";
|
||||
PrintPercent(MustAliasCount, AliasSum);
|
||||
errs() << " Alias Analysis Evaluator Pointer Alias Summary: "
|
||||
<< NoAliasCount * 100 / AliasSum << "%/"
|
||||
<< MayAliasCount * 100 / AliasSum << "%/"
|
||||
<< PartialAliasCount * 100 / AliasSum << "%/"
|
||||
<< MustAliasCount * 100 / AliasSum << "%\n";
|
||||
}
|
||||
|
||||
// Display the summary for mod/ref analysis
|
||||
int64_t ModRefSum = NoModRefCount + RefCount + ModCount + ModRefCount +
|
||||
MustCount + MustRefCount + MustModCount + MustModRefCount;
|
||||
if (ModRefSum == 0) {
|
||||
errs() << " Alias Analysis Mod/Ref Evaluator Summary: no "
|
||||
"mod/ref!\n";
|
||||
} else {
|
||||
errs() << " " << ModRefSum << " Total ModRef Queries Performed\n";
|
||||
errs() << " " << NoModRefCount << " no mod/ref responses ";
|
||||
PrintPercent(NoModRefCount, ModRefSum);
|
||||
errs() << " " << ModCount << " mod responses ";
|
||||
PrintPercent(ModCount, ModRefSum);
|
||||
errs() << " " << RefCount << " ref responses ";
|
||||
PrintPercent(RefCount, ModRefSum);
|
||||
errs() << " " << ModRefCount << " mod & ref responses ";
|
||||
PrintPercent(ModRefCount, ModRefSum);
|
||||
errs() << " " << MustCount << " must responses ";
|
||||
PrintPercent(MustCount, ModRefSum);
|
||||
errs() << " " << MustModCount << " must mod responses ";
|
||||
PrintPercent(MustModCount, ModRefSum);
|
||||
errs() << " " << MustRefCount << " must ref responses ";
|
||||
PrintPercent(MustRefCount, ModRefSum);
|
||||
errs() << " " << MustModRefCount << " must mod & ref responses ";
|
||||
PrintPercent(MustModRefCount, ModRefSum);
|
||||
errs() << " Alias Analysis Evaluator Mod/Ref Summary: "
|
||||
<< NoModRefCount * 100 / ModRefSum << "%/"
|
||||
<< ModCount * 100 / ModRefSum << "%/" << RefCount * 100 / ModRefSum
|
||||
<< "%/" << ModRefCount * 100 / ModRefSum << "%/"
|
||||
<< MustCount * 100 / ModRefSum << "%/"
|
||||
<< MustRefCount * 100 / ModRefSum << "%/"
|
||||
<< MustModCount * 100 / ModRefSum << "%/"
|
||||
<< MustModRefCount * 100 / ModRefSum << "%\n";
|
||||
}
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
class AAEvalLegacyPass : public FunctionPass {
|
||||
std::unique_ptr<AAEvaluator> P;
|
||||
|
||||
public:
|
||||
static char ID; // Pass identification, replacement for typeid
|
||||
AAEvalLegacyPass() : FunctionPass(ID) {
|
||||
initializeAAEvalLegacyPassPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
||||
AU.addRequired<AAResultsWrapperPass>();
|
||||
AU.setPreservesAll();
|
||||
}
|
||||
|
||||
bool doInitialization(Module &M) override {
|
||||
P.reset(new AAEvaluator());
|
||||
return false;
|
||||
}
|
||||
|
||||
bool runOnFunction(Function &F) override {
|
||||
P->runInternal(F, getAnalysis<AAResultsWrapperPass>().getAAResults());
|
||||
return false;
|
||||
}
|
||||
bool doFinalization(Module &M) override {
|
||||
P.reset();
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
char AAEvalLegacyPass::ID = 0;
|
||||
INITIALIZE_PASS_BEGIN(AAEvalLegacyPass, "aa-eval",
|
||||
"Exhaustive Alias Analysis Precision Evaluator", false,
|
||||
true)
|
||||
INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass)
|
||||
INITIALIZE_PASS_END(AAEvalLegacyPass, "aa-eval",
|
||||
"Exhaustive Alias Analysis Precision Evaluator", false,
|
||||
true)
|
||||
|
||||
FunctionPass *llvm::createAAEvalPass() { return new AAEvalLegacyPass(); }
|
103
external/llvm/lib/Analysis/AliasAnalysisSummary.cpp
vendored
103
external/llvm/lib/Analysis/AliasAnalysisSummary.cpp
vendored
@ -1,103 +0,0 @@
|
||||
#include "AliasAnalysisSummary.h"
|
||||
#include "llvm/IR/Argument.h"
|
||||
#include "llvm/IR/Type.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace cflaa {
|
||||
|
||||
namespace {
|
||||
const unsigned AttrEscapedIndex = 0;
|
||||
const unsigned AttrUnknownIndex = 1;
|
||||
const unsigned AttrGlobalIndex = 2;
|
||||
const unsigned AttrCallerIndex = 3;
|
||||
const unsigned AttrFirstArgIndex = 4;
|
||||
const unsigned AttrLastArgIndex = NumAliasAttrs;
|
||||
const unsigned AttrMaxNumArgs = AttrLastArgIndex - AttrFirstArgIndex;
|
||||
|
||||
// It would be *slightly* prettier if we changed these to AliasAttrs, but it
|
||||
// seems that both GCC and MSVC emit dynamic initializers for const bitsets.
|
||||
using AliasAttr = unsigned;
|
||||
const AliasAttr AttrNone = 0;
|
||||
const AliasAttr AttrEscaped = 1 << AttrEscapedIndex;
|
||||
const AliasAttr AttrUnknown = 1 << AttrUnknownIndex;
|
||||
const AliasAttr AttrGlobal = 1 << AttrGlobalIndex;
|
||||
const AliasAttr AttrCaller = 1 << AttrCallerIndex;
|
||||
const AliasAttr ExternalAttrMask = AttrEscaped | AttrUnknown | AttrGlobal;
|
||||
}
|
||||
|
||||
AliasAttrs getAttrNone() { return AttrNone; }
|
||||
|
||||
AliasAttrs getAttrUnknown() { return AttrUnknown; }
|
||||
bool hasUnknownAttr(AliasAttrs Attr) { return Attr.test(AttrUnknownIndex); }
|
||||
|
||||
AliasAttrs getAttrCaller() { return AttrCaller; }
|
||||
bool hasCallerAttr(AliasAttrs Attr) { return Attr.test(AttrCaller); }
|
||||
bool hasUnknownOrCallerAttr(AliasAttrs Attr) {
|
||||
return Attr.test(AttrUnknownIndex) || Attr.test(AttrCallerIndex);
|
||||
}
|
||||
|
||||
AliasAttrs getAttrEscaped() { return AttrEscaped; }
|
||||
bool hasEscapedAttr(AliasAttrs Attr) { return Attr.test(AttrEscapedIndex); }
|
||||
|
||||
static AliasAttr argNumberToAttr(unsigned ArgNum) {
|
||||
if (ArgNum >= AttrMaxNumArgs)
|
||||
return AttrUnknown;
|
||||
// N.B. MSVC complains if we use `1U` here, since AliasAttr' ctor takes
|
||||
// an unsigned long long.
|
||||
return AliasAttr(1ULL << (ArgNum + AttrFirstArgIndex));
|
||||
}
|
||||
|
||||
AliasAttrs getGlobalOrArgAttrFromValue(const Value &Val) {
|
||||
if (isa<GlobalValue>(Val))
|
||||
return AttrGlobal;
|
||||
|
||||
if (auto *Arg = dyn_cast<Argument>(&Val))
|
||||
// Only pointer arguments should have the argument attribute,
|
||||
// because things can't escape through scalars without us seeing a
|
||||
// cast, and thus, interaction with them doesn't matter.
|
||||
if (!Arg->hasNoAliasAttr() && Arg->getType()->isPointerTy())
|
||||
return argNumberToAttr(Arg->getArgNo());
|
||||
return AttrNone;
|
||||
}
|
||||
|
||||
bool isGlobalOrArgAttr(AliasAttrs Attr) {
|
||||
return Attr.reset(AttrEscapedIndex)
|
||||
.reset(AttrUnknownIndex)
|
||||
.reset(AttrCallerIndex)
|
||||
.any();
|
||||
}
|
||||
|
||||
AliasAttrs getExternallyVisibleAttrs(AliasAttrs Attr) {
|
||||
return Attr & AliasAttrs(ExternalAttrMask);
|
||||
}
|
||||
|
||||
Optional<InstantiatedValue> instantiateInterfaceValue(InterfaceValue IValue,
|
||||
CallSite CS) {
|
||||
auto Index = IValue.Index;
|
||||
auto Value = (Index == 0) ? CS.getInstruction() : CS.getArgument(Index - 1);
|
||||
if (Value->getType()->isPointerTy())
|
||||
return InstantiatedValue{Value, IValue.DerefLevel};
|
||||
return None;
|
||||
}
|
||||
|
||||
Optional<InstantiatedRelation>
|
||||
instantiateExternalRelation(ExternalRelation ERelation, CallSite CS) {
|
||||
auto From = instantiateInterfaceValue(ERelation.From, CS);
|
||||
if (!From)
|
||||
return None;
|
||||
auto To = instantiateInterfaceValue(ERelation.To, CS);
|
||||
if (!To)
|
||||
return None;
|
||||
return InstantiatedRelation{*From, *To, ERelation.Offset};
|
||||
}
|
||||
|
||||
Optional<InstantiatedAttr> instantiateExternalAttribute(ExternalAttribute EAttr,
|
||||
CallSite CS) {
|
||||
auto Value = instantiateInterfaceValue(EAttr.IValue, CS);
|
||||
if (!Value)
|
||||
return None;
|
||||
return InstantiatedAttr{*Value, EAttr.Attr};
|
||||
}
|
||||
}
|
||||
}
|
265
external/llvm/lib/Analysis/AliasAnalysisSummary.h
vendored
265
external/llvm/lib/Analysis/AliasAnalysisSummary.h
vendored
@ -1,265 +0,0 @@
|
||||
//=====- CFLSummary.h - Abstract stratified sets implementation. --------=====//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// \file
|
||||
/// This file defines various utility types and functions useful to
|
||||
/// summary-based alias analysis.
|
||||
///
|
||||
/// Summary-based analysis, also known as bottom-up analysis, is a style of
|
||||
/// interprocedrual static analysis that tries to analyze the callees before the
|
||||
/// callers get analyzed. The key idea of summary-based analysis is to first
|
||||
/// process each function indepedently, outline its behavior in a condensed
|
||||
/// summary, and then instantiate the summary at the callsite when the said
|
||||
/// function is called elsewhere. This is often in contrast to another style
|
||||
/// called top-down analysis, in which callers are always analyzed first before
|
||||
/// the callees.
|
||||
///
|
||||
/// In a summary-based analysis, functions must be examined independently and
|
||||
/// out-of-context. We have no information on the state of the memory, the
|
||||
/// arguments, the global values, and anything else external to the function. To
|
||||
/// carry out the analysis conservative assumptions have to be made about those
|
||||
/// external states. In exchange for the potential loss of precision, the
|
||||
/// summary we obtain this way is highly reusable, which makes the analysis
|
||||
/// easier to scale to large programs even if carried out context-sensitively.
|
||||
///
|
||||
/// Currently, all CFL-based alias analyses adopt the summary-based approach
|
||||
/// and therefore heavily rely on this header.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_ALIASANALYSISSUMMARY_H
|
||||
#define LLVM_ANALYSIS_ALIASANALYSISSUMMARY_H
|
||||
|
||||
#include "llvm/ADT/DenseMapInfo.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/IR/CallSite.h"
|
||||
#include <bitset>
|
||||
|
||||
namespace llvm {
|
||||
namespace cflaa {
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// AliasAttr related stuffs
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// The number of attributes that AliasAttr should contain. Attributes are
|
||||
/// described below, and 32 was an arbitrary choice because it fits nicely in 32
|
||||
/// bits (because we use a bitset for AliasAttr).
|
||||
static const unsigned NumAliasAttrs = 32;
|
||||
|
||||
/// These are attributes that an alias analysis can use to mark certain special
|
||||
/// properties of a given pointer. Refer to the related functions below to see
|
||||
/// what kinds of attributes are currently defined.
|
||||
typedef std::bitset<NumAliasAttrs> AliasAttrs;
|
||||
|
||||
/// Attr represent whether the said pointer comes from an unknown source
|
||||
/// (such as opaque memory or an integer cast).
|
||||
AliasAttrs getAttrNone();
|
||||
|
||||
/// AttrUnknown represent whether the said pointer comes from a source not known
|
||||
/// to alias analyses (such as opaque memory or an integer cast).
|
||||
AliasAttrs getAttrUnknown();
|
||||
bool hasUnknownAttr(AliasAttrs);
|
||||
|
||||
/// AttrCaller represent whether the said pointer comes from a source not known
|
||||
/// to the current function but known to the caller. Values pointed to by the
|
||||
/// arguments of the current function have this attribute set
|
||||
AliasAttrs getAttrCaller();
|
||||
bool hasCallerAttr(AliasAttrs);
|
||||
bool hasUnknownOrCallerAttr(AliasAttrs);
|
||||
|
||||
/// AttrEscaped represent whether the said pointer comes from a known source but
|
||||
/// escapes to the unknown world (e.g. casted to an integer, or passed as an
|
||||
/// argument to opaque function). Unlike non-escaped pointers, escaped ones may
|
||||
/// alias pointers coming from unknown sources.
|
||||
AliasAttrs getAttrEscaped();
|
||||
bool hasEscapedAttr(AliasAttrs);
|
||||
|
||||
/// AttrGlobal represent whether the said pointer is a global value.
|
||||
/// AttrArg represent whether the said pointer is an argument, and if so, what
|
||||
/// index the argument has.
|
||||
AliasAttrs getGlobalOrArgAttrFromValue(const Value &);
|
||||
bool isGlobalOrArgAttr(AliasAttrs);
|
||||
|
||||
/// Given an AliasAttrs, return a new AliasAttrs that only contains attributes
|
||||
/// meaningful to the caller. This function is primarily used for
|
||||
/// interprocedural analysis
|
||||
/// Currently, externally visible AliasAttrs include AttrUnknown, AttrGlobal,
|
||||
/// and AttrEscaped
|
||||
AliasAttrs getExternallyVisibleAttrs(AliasAttrs);
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Function summary related stuffs
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// The maximum number of arguments we can put into a summary.
|
||||
static const 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.
|
||||
/// Index is an integer which represents a single parameter or a return value.
|
||||
/// When the index is 0, it refers to the return value. Non-zero index i refers
|
||||
/// to the i-th parameter.
|
||||
/// DerefLevel indicates the number of dereferences one must perform on the
|
||||
/// parameter/return value to get this InterfaceValue.
|
||||
struct InterfaceValue {
|
||||
unsigned Index;
|
||||
unsigned DerefLevel;
|
||||
};
|
||||
|
||||
inline bool operator==(InterfaceValue LHS, InterfaceValue RHS) {
|
||||
return LHS.Index == RHS.Index && LHS.DerefLevel == RHS.DerefLevel;
|
||||
}
|
||||
inline bool operator!=(InterfaceValue LHS, InterfaceValue RHS) {
|
||||
return !(LHS == RHS);
|
||||
}
|
||||
inline bool operator<(InterfaceValue LHS, InterfaceValue RHS) {
|
||||
return LHS.Index < RHS.Index ||
|
||||
(LHS.Index == RHS.Index && LHS.DerefLevel < RHS.DerefLevel);
|
||||
}
|
||||
inline bool operator>(InterfaceValue LHS, InterfaceValue RHS) {
|
||||
return RHS < LHS;
|
||||
}
|
||||
inline bool operator<=(InterfaceValue LHS, InterfaceValue RHS) {
|
||||
return !(RHS < LHS);
|
||||
}
|
||||
inline bool operator>=(InterfaceValue LHS, InterfaceValue RHS) {
|
||||
return !(LHS < RHS);
|
||||
}
|
||||
|
||||
// We use UnknownOffset to represent pointer offsets that cannot be determined
|
||||
// at compile time. Note that MemoryLocation::UnknownSize cannot be used here
|
||||
// because we require a signed value.
|
||||
static const int64_t UnknownOffset = INT64_MAX;
|
||||
|
||||
inline int64_t addOffset(int64_t LHS, int64_t RHS) {
|
||||
if (LHS == UnknownOffset || RHS == UnknownOffset)
|
||||
return UnknownOffset;
|
||||
// FIXME: Do we need to guard against integer overflow here?
|
||||
return LHS + RHS;
|
||||
}
|
||||
|
||||
/// We use ExternalRelation to describe an externally visible aliasing relations
|
||||
/// between parameters/return value of a function.
|
||||
struct ExternalRelation {
|
||||
InterfaceValue From, To;
|
||||
int64_t Offset;
|
||||
};
|
||||
|
||||
inline bool operator==(ExternalRelation LHS, ExternalRelation RHS) {
|
||||
return LHS.From == RHS.From && LHS.To == RHS.To && LHS.Offset == RHS.Offset;
|
||||
}
|
||||
inline bool operator!=(ExternalRelation LHS, ExternalRelation RHS) {
|
||||
return !(LHS == RHS);
|
||||
}
|
||||
inline bool operator<(ExternalRelation LHS, ExternalRelation RHS) {
|
||||
if (LHS.From < RHS.From)
|
||||
return true;
|
||||
if (LHS.From > RHS.From)
|
||||
return false;
|
||||
if (LHS.To < RHS.To)
|
||||
return true;
|
||||
if (LHS.To > RHS.To)
|
||||
return false;
|
||||
return LHS.Offset < RHS.Offset;
|
||||
}
|
||||
inline bool operator>(ExternalRelation LHS, ExternalRelation RHS) {
|
||||
return RHS < LHS;
|
||||
}
|
||||
inline bool operator<=(ExternalRelation LHS, ExternalRelation RHS) {
|
||||
return !(RHS < LHS);
|
||||
}
|
||||
inline bool operator>=(ExternalRelation LHS, ExternalRelation RHS) {
|
||||
return !(LHS < RHS);
|
||||
}
|
||||
|
||||
/// We use ExternalAttribute to describe an externally visible AliasAttrs
|
||||
/// for parameters/return value.
|
||||
struct ExternalAttribute {
|
||||
InterfaceValue IValue;
|
||||
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;
|
||||
unsigned DerefLevel;
|
||||
};
|
||||
Optional<InstantiatedValue> instantiateInterfaceValue(InterfaceValue, CallSite);
|
||||
|
||||
inline bool operator==(InstantiatedValue LHS, InstantiatedValue RHS) {
|
||||
return LHS.Val == RHS.Val && LHS.DerefLevel == RHS.DerefLevel;
|
||||
}
|
||||
inline bool operator!=(InstantiatedValue LHS, InstantiatedValue RHS) {
|
||||
return !(LHS == RHS);
|
||||
}
|
||||
inline bool operator<(InstantiatedValue LHS, InstantiatedValue RHS) {
|
||||
return std::less<Value *>()(LHS.Val, RHS.Val) ||
|
||||
(LHS.Val == RHS.Val && LHS.DerefLevel < RHS.DerefLevel);
|
||||
}
|
||||
inline bool operator>(InstantiatedValue LHS, InstantiatedValue RHS) {
|
||||
return RHS < LHS;
|
||||
}
|
||||
inline bool operator<=(InstantiatedValue LHS, InstantiatedValue RHS) {
|
||||
return !(RHS < LHS);
|
||||
}
|
||||
inline bool operator>=(InstantiatedValue LHS, InstantiatedValue RHS) {
|
||||
return !(LHS < RHS);
|
||||
}
|
||||
|
||||
/// This is the result of instantiating ExternalRelation at a particular
|
||||
/// callsite
|
||||
struct InstantiatedRelation {
|
||||
InstantiatedValue From, To;
|
||||
int64_t Offset;
|
||||
};
|
||||
Optional<InstantiatedRelation> instantiateExternalRelation(ExternalRelation,
|
||||
CallSite);
|
||||
|
||||
/// This is the result of instantiating ExternalAttribute at a particular
|
||||
/// callsite
|
||||
struct InstantiatedAttr {
|
||||
InstantiatedValue IValue;
|
||||
AliasAttrs Attr;
|
||||
};
|
||||
Optional<InstantiatedAttr> instantiateExternalAttribute(ExternalAttribute,
|
||||
CallSite);
|
||||
}
|
||||
|
||||
template <> struct DenseMapInfo<cflaa::InstantiatedValue> {
|
||||
static inline cflaa::InstantiatedValue getEmptyKey() {
|
||||
return cflaa::InstantiatedValue{DenseMapInfo<Value *>::getEmptyKey(),
|
||||
DenseMapInfo<unsigned>::getEmptyKey()};
|
||||
}
|
||||
static inline cflaa::InstantiatedValue getTombstoneKey() {
|
||||
return cflaa::InstantiatedValue{DenseMapInfo<Value *>::getTombstoneKey(),
|
||||
DenseMapInfo<unsigned>::getTombstoneKey()};
|
||||
}
|
||||
static unsigned getHashValue(const cflaa::InstantiatedValue &IV) {
|
||||
return DenseMapInfo<std::pair<Value *, unsigned>>::getHashValue(
|
||||
std::make_pair(IV.Val, IV.DerefLevel));
|
||||
}
|
||||
static bool isEqual(const cflaa::InstantiatedValue &LHS,
|
||||
const cflaa::InstantiatedValue &RHS) {
|
||||
return LHS.Val == RHS.Val && LHS.DerefLevel == RHS.DerefLevel;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
719
external/llvm/lib/Analysis/AliasSetTracker.cpp
vendored
719
external/llvm/lib/Analysis/AliasSetTracker.cpp
vendored
File diff suppressed because it is too large
Load Diff
134
external/llvm/lib/Analysis/Analysis.cpp
vendored
134
external/llvm/lib/Analysis/Analysis.cpp
vendored
@ -1,134 +0,0 @@
|
||||
//===-- Analysis.cpp ------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm-c/Analysis.h"
|
||||
#include "llvm-c/Initialization.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/IR/Verifier.h"
|
||||
#include "llvm/InitializePasses.h"
|
||||
#include "llvm/PassRegistry.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <cstring>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
/// initializeAnalysis - Initialize all passes linked into the Analysis library.
|
||||
void llvm::initializeAnalysis(PassRegistry &Registry) {
|
||||
initializeAAEvalLegacyPassPass(Registry);
|
||||
initializeAliasSetPrinterPass(Registry);
|
||||
initializeBasicAAWrapperPassPass(Registry);
|
||||
initializeBlockFrequencyInfoWrapperPassPass(Registry);
|
||||
initializeBranchProbabilityInfoWrapperPassPass(Registry);
|
||||
initializeCallGraphWrapperPassPass(Registry);
|
||||
initializeCallGraphDOTPrinterPass(Registry);
|
||||
initializeCallGraphPrinterLegacyPassPass(Registry);
|
||||
initializeCallGraphViewerPass(Registry);
|
||||
initializeCostModelAnalysisPass(Registry);
|
||||
initializeCFGViewerLegacyPassPass(Registry);
|
||||
initializeCFGPrinterLegacyPassPass(Registry);
|
||||
initializeCFGOnlyViewerLegacyPassPass(Registry);
|
||||
initializeCFGOnlyPrinterLegacyPassPass(Registry);
|
||||
initializeCFLAndersAAWrapperPassPass(Registry);
|
||||
initializeCFLSteensAAWrapperPassPass(Registry);
|
||||
initializeDependenceAnalysisWrapperPassPass(Registry);
|
||||
initializeDelinearizationPass(Registry);
|
||||
initializeDemandedBitsWrapperPassPass(Registry);
|
||||
initializeDivergenceAnalysisPass(Registry);
|
||||
initializeDominanceFrontierWrapperPassPass(Registry);
|
||||
initializeDomViewerPass(Registry);
|
||||
initializeDomPrinterPass(Registry);
|
||||
initializeDomOnlyViewerPass(Registry);
|
||||
initializePostDomViewerPass(Registry);
|
||||
initializeDomOnlyPrinterPass(Registry);
|
||||
initializePostDomPrinterPass(Registry);
|
||||
initializePostDomOnlyViewerPass(Registry);
|
||||
initializePostDomOnlyPrinterPass(Registry);
|
||||
initializeAAResultsWrapperPassPass(Registry);
|
||||
initializeGlobalsAAWrapperPassPass(Registry);
|
||||
initializeIVUsersWrapperPassPass(Registry);
|
||||
initializeInstCountPass(Registry);
|
||||
initializeIntervalPartitionPass(Registry);
|
||||
initializeLazyBranchProbabilityInfoPassPass(Registry);
|
||||
initializeLazyBlockFrequencyInfoPassPass(Registry);
|
||||
initializeLazyValueInfoWrapperPassPass(Registry);
|
||||
initializeLazyValueInfoPrinterPass(Registry);
|
||||
initializeLintPass(Registry);
|
||||
initializeLoopInfoWrapperPassPass(Registry);
|
||||
initializeMemDepPrinterPass(Registry);
|
||||
initializeMemDerefPrinterPass(Registry);
|
||||
initializeMemoryDependenceWrapperPassPass(Registry);
|
||||
initializeModuleDebugInfoPrinterPass(Registry);
|
||||
initializeModuleSummaryIndexWrapperPassPass(Registry);
|
||||
initializeObjCARCAAWrapperPassPass(Registry);
|
||||
initializeOptimizationRemarkEmitterWrapperPassPass(Registry);
|
||||
initializePostDominatorTreeWrapperPassPass(Registry);
|
||||
initializeRegionInfoPassPass(Registry);
|
||||
initializeRegionViewerPass(Registry);
|
||||
initializeRegionPrinterPass(Registry);
|
||||
initializeRegionOnlyViewerPass(Registry);
|
||||
initializeRegionOnlyPrinterPass(Registry);
|
||||
initializeSCEVAAWrapperPassPass(Registry);
|
||||
initializeScalarEvolutionWrapperPassPass(Registry);
|
||||
initializeTargetTransformInfoWrapperPassPass(Registry);
|
||||
initializeTypeBasedAAWrapperPassPass(Registry);
|
||||
initializeScopedNoAliasAAWrapperPassPass(Registry);
|
||||
initializeLCSSAVerificationPassPass(Registry);
|
||||
initializeMemorySSAWrapperPassPass(Registry);
|
||||
initializeMemorySSAPrinterLegacyPassPass(Registry);
|
||||
}
|
||||
|
||||
void LLVMInitializeAnalysis(LLVMPassRegistryRef R) {
|
||||
initializeAnalysis(*unwrap(R));
|
||||
}
|
||||
|
||||
void LLVMInitializeIPA(LLVMPassRegistryRef R) {
|
||||
initializeAnalysis(*unwrap(R));
|
||||
}
|
||||
|
||||
LLVMBool LLVMVerifyModule(LLVMModuleRef M, LLVMVerifierFailureAction Action,
|
||||
char **OutMessages) {
|
||||
raw_ostream *DebugOS = Action != LLVMReturnStatusAction ? &errs() : nullptr;
|
||||
std::string Messages;
|
||||
raw_string_ostream MsgsOS(Messages);
|
||||
|
||||
LLVMBool Result = verifyModule(*unwrap(M), OutMessages ? &MsgsOS : DebugOS);
|
||||
|
||||
// Duplicate the output to stderr.
|
||||
if (DebugOS && OutMessages)
|
||||
*DebugOS << MsgsOS.str();
|
||||
|
||||
if (Action == LLVMAbortProcessAction && Result)
|
||||
report_fatal_error("Broken module found, compilation aborted!");
|
||||
|
||||
if (OutMessages)
|
||||
*OutMessages = strdup(MsgsOS.str().c_str());
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
LLVMBool LLVMVerifyFunction(LLVMValueRef Fn, LLVMVerifierFailureAction Action) {
|
||||
LLVMBool Result = verifyFunction(
|
||||
*unwrap<Function>(Fn), Action != LLVMReturnStatusAction ? &errs()
|
||||
: nullptr);
|
||||
|
||||
if (Action == LLVMAbortProcessAction && Result)
|
||||
report_fatal_error("Broken function found, compilation aborted!");
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
void LLVMViewFunctionCFG(LLVMValueRef Fn) {
|
||||
Function *F = unwrap<Function>(Fn);
|
||||
F->viewCFG();
|
||||
}
|
||||
|
||||
void LLVMViewFunctionCFGOnly(LLVMValueRef Fn) {
|
||||
Function *F = unwrap<Function>(Fn);
|
||||
F->viewCFGOnly();
|
||||
}
|
275
external/llvm/lib/Analysis/AssumptionCache.cpp
vendored
275
external/llvm/lib/Analysis/AssumptionCache.cpp
vendored
@ -1,275 +0,0 @@
|
||||
//===- AssumptionCache.cpp - Cache finding @llvm.assume calls -------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains a pass that keeps track of @llvm.assume intrinsics in
|
||||
// the functions of a module.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Analysis/AssumptionCache.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/IR/BasicBlock.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/InstrTypes.h"
|
||||
#include "llvm/IR/Instruction.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/IR/Intrinsics.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#include "llvm/IR/PatternMatch.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <utility>
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::PatternMatch;
|
||||
|
||||
static cl::opt<bool>
|
||||
VerifyAssumptionCache("verify-assumption-cache", cl::Hidden,
|
||||
cl::desc("Enable verification of assumption cache"),
|
||||
cl::init(false));
|
||||
|
||||
SmallVector<WeakTrackingVH, 1> &
|
||||
AssumptionCache::getOrInsertAffectedValues(Value *V) {
|
||||
// Try using find_as first to avoid creating extra value handles just for the
|
||||
// purpose of doing the lookup.
|
||||
auto AVI = AffectedValues.find_as(V);
|
||||
if (AVI != AffectedValues.end())
|
||||
return AVI->second;
|
||||
|
||||
auto AVIP = AffectedValues.insert(
|
||||
{AffectedValueCallbackVH(V, this), SmallVector<WeakTrackingVH, 1>()});
|
||||
return AVIP.first->second;
|
||||
}
|
||||
|
||||
void AssumptionCache::updateAffectedValues(CallInst *CI) {
|
||||
// Note: This code must be kept in-sync with the code in
|
||||
// computeKnownBitsFromAssume in ValueTracking.
|
||||
|
||||
SmallVector<Value *, 16> Affected;
|
||||
auto AddAffected = [&Affected](Value *V) {
|
||||
if (isa<Argument>(V)) {
|
||||
Affected.push_back(V);
|
||||
} else if (auto *I = dyn_cast<Instruction>(V)) {
|
||||
Affected.push_back(I);
|
||||
|
||||
// Peek through unary operators to find the source of the condition.
|
||||
Value *Op;
|
||||
if (match(I, m_BitCast(m_Value(Op))) ||
|
||||
match(I, m_PtrToInt(m_Value(Op))) ||
|
||||
match(I, m_Not(m_Value(Op)))) {
|
||||
if (isa<Instruction>(Op) || isa<Argument>(Op))
|
||||
Affected.push_back(Op);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Value *Cond = CI->getArgOperand(0), *A, *B;
|
||||
AddAffected(Cond);
|
||||
|
||||
CmpInst::Predicate Pred;
|
||||
if (match(Cond, m_ICmp(Pred, m_Value(A), m_Value(B)))) {
|
||||
AddAffected(A);
|
||||
AddAffected(B);
|
||||
|
||||
if (Pred == ICmpInst::ICMP_EQ) {
|
||||
// For equality comparisons, we handle the case of bit inversion.
|
||||
auto AddAffectedFromEq = [&AddAffected](Value *V) {
|
||||
Value *A;
|
||||
if (match(V, m_Not(m_Value(A)))) {
|
||||
AddAffected(A);
|
||||
V = A;
|
||||
}
|
||||
|
||||
Value *B;
|
||||
ConstantInt *C;
|
||||
// (A & B) or (A | B) or (A ^ B).
|
||||
if (match(V, m_BitwiseLogic(m_Value(A), m_Value(B)))) {
|
||||
AddAffected(A);
|
||||
AddAffected(B);
|
||||
// (A << C) or (A >>_s C) or (A >>_u C) where C is some constant.
|
||||
} else if (match(V, m_Shift(m_Value(A), m_ConstantInt(C)))) {
|
||||
AddAffected(A);
|
||||
}
|
||||
};
|
||||
|
||||
AddAffectedFromEq(A);
|
||||
AddAffectedFromEq(B);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &AV : Affected) {
|
||||
auto &AVV = getOrInsertAffectedValues(AV);
|
||||
if (std::find(AVV.begin(), AVV.end(), CI) == AVV.end())
|
||||
AVV.push_back(CI);
|
||||
}
|
||||
}
|
||||
|
||||
void AssumptionCache::AffectedValueCallbackVH::deleted() {
|
||||
auto AVI = AC->AffectedValues.find(getValPtr());
|
||||
if (AVI != AC->AffectedValues.end())
|
||||
AC->AffectedValues.erase(AVI);
|
||||
// 'this' now dangles!
|
||||
}
|
||||
|
||||
void AssumptionCache::copyAffectedValuesInCache(Value *OV, Value *NV) {
|
||||
auto &NAVV = getOrInsertAffectedValues(NV);
|
||||
auto AVI = AffectedValues.find(OV);
|
||||
if (AVI == AffectedValues.end())
|
||||
return;
|
||||
|
||||
for (auto &A : AVI->second)
|
||||
if (std::find(NAVV.begin(), NAVV.end(), A) == NAVV.end())
|
||||
NAVV.push_back(A);
|
||||
}
|
||||
|
||||
void AssumptionCache::AffectedValueCallbackVH::allUsesReplacedWith(Value *NV) {
|
||||
if (!isa<Instruction>(NV) && !isa<Argument>(NV))
|
||||
return;
|
||||
|
||||
// Any assumptions that affected this value now affect the new value.
|
||||
|
||||
AC->copyAffectedValuesInCache(getValPtr(), NV);
|
||||
// 'this' now might dangle! If the AffectedValues map was resized to add an
|
||||
// entry for NV then this object might have been destroyed in favor of some
|
||||
// copy in the grown map.
|
||||
}
|
||||
|
||||
void AssumptionCache::scanFunction() {
|
||||
assert(!Scanned && "Tried to scan the function twice!");
|
||||
assert(AssumeHandles.empty() && "Already have assumes when scanning!");
|
||||
|
||||
// Go through all instructions in all blocks, add all calls to @llvm.assume
|
||||
// to this cache.
|
||||
for (BasicBlock &B : F)
|
||||
for (Instruction &II : B)
|
||||
if (match(&II, m_Intrinsic<Intrinsic::assume>()))
|
||||
AssumeHandles.push_back(&II);
|
||||
|
||||
// Mark the scan as complete.
|
||||
Scanned = true;
|
||||
|
||||
// Update affected values.
|
||||
for (auto &A : AssumeHandles)
|
||||
updateAffectedValues(cast<CallInst>(A));
|
||||
}
|
||||
|
||||
void AssumptionCache::registerAssumption(CallInst *CI) {
|
||||
assert(match(CI, m_Intrinsic<Intrinsic::assume>()) &&
|
||||
"Registered call does not call @llvm.assume");
|
||||
|
||||
// If we haven't scanned the function yet, just drop this assumption. It will
|
||||
// be found when we scan later.
|
||||
if (!Scanned)
|
||||
return;
|
||||
|
||||
AssumeHandles.push_back(CI);
|
||||
|
||||
#ifndef NDEBUG
|
||||
assert(CI->getParent() &&
|
||||
"Cannot register @llvm.assume call not in a basic block");
|
||||
assert(&F == CI->getParent()->getParent() &&
|
||||
"Cannot register @llvm.assume call not in this function");
|
||||
|
||||
// We expect the number of assumptions to be small, so in an asserts build
|
||||
// check that we don't accumulate duplicates and that all assumptions point
|
||||
// to the same function.
|
||||
SmallPtrSet<Value *, 16> AssumptionSet;
|
||||
for (auto &VH : AssumeHandles) {
|
||||
if (!VH)
|
||||
continue;
|
||||
|
||||
assert(&F == cast<Instruction>(VH)->getParent()->getParent() &&
|
||||
"Cached assumption not inside this function!");
|
||||
assert(match(cast<CallInst>(VH), m_Intrinsic<Intrinsic::assume>()) &&
|
||||
"Cached something other than a call to @llvm.assume!");
|
||||
assert(AssumptionSet.insert(VH).second &&
|
||||
"Cache contains multiple copies of a call!");
|
||||
}
|
||||
#endif
|
||||
|
||||
updateAffectedValues(CI);
|
||||
}
|
||||
|
||||
AnalysisKey AssumptionAnalysis::Key;
|
||||
|
||||
PreservedAnalyses AssumptionPrinterPass::run(Function &F,
|
||||
FunctionAnalysisManager &AM) {
|
||||
AssumptionCache &AC = AM.getResult<AssumptionAnalysis>(F);
|
||||
|
||||
OS << "Cached assumptions for function: " << F.getName() << "\n";
|
||||
for (auto &VH : AC.assumptions())
|
||||
if (VH)
|
||||
OS << " " << *cast<CallInst>(VH)->getArgOperand(0) << "\n";
|
||||
|
||||
return PreservedAnalyses::all();
|
||||
}
|
||||
|
||||
void AssumptionCacheTracker::FunctionCallbackVH::deleted() {
|
||||
auto I = ACT->AssumptionCaches.find_as(cast<Function>(getValPtr()));
|
||||
if (I != ACT->AssumptionCaches.end())
|
||||
ACT->AssumptionCaches.erase(I);
|
||||
// 'this' now dangles!
|
||||
}
|
||||
|
||||
AssumptionCache &AssumptionCacheTracker::getAssumptionCache(Function &F) {
|
||||
// We probe the function map twice to try and avoid creating a value handle
|
||||
// around the function in common cases. This makes insertion a bit slower,
|
||||
// but if we have to insert we're going to scan the whole function so that
|
||||
// shouldn't matter.
|
||||
auto I = AssumptionCaches.find_as(&F);
|
||||
if (I != AssumptionCaches.end())
|
||||
return *I->second;
|
||||
|
||||
// Ok, build a new cache by scanning the function, insert it and the value
|
||||
// handle into our map, and return the newly populated cache.
|
||||
auto IP = AssumptionCaches.insert(std::make_pair(
|
||||
FunctionCallbackVH(&F, this), llvm::make_unique<AssumptionCache>(F)));
|
||||
assert(IP.second && "Scanning function already in the map?");
|
||||
return *IP.first->second;
|
||||
}
|
||||
|
||||
void AssumptionCacheTracker::verifyAnalysis() const {
|
||||
// FIXME: In the long term the verifier should not be controllable with a
|
||||
// flag. We should either fix all passes to correctly update the assumption
|
||||
// cache and enable the verifier unconditionally or somehow arrange for the
|
||||
// assumption list to be updated automatically by passes.
|
||||
if (!VerifyAssumptionCache)
|
||||
return;
|
||||
|
||||
SmallPtrSet<const CallInst *, 4> AssumptionSet;
|
||||
for (const auto &I : AssumptionCaches) {
|
||||
for (auto &VH : I.second->assumptions())
|
||||
if (VH)
|
||||
AssumptionSet.insert(cast<CallInst>(VH));
|
||||
|
||||
for (const BasicBlock &B : cast<Function>(*I.first))
|
||||
for (const Instruction &II : B)
|
||||
if (match(&II, m_Intrinsic<Intrinsic::assume>()) &&
|
||||
!AssumptionSet.count(cast<CallInst>(&II)))
|
||||
report_fatal_error("Assumption in scanned function not in cache");
|
||||
}
|
||||
}
|
||||
|
||||
AssumptionCacheTracker::AssumptionCacheTracker() : ImmutablePass(ID) {
|
||||
initializeAssumptionCacheTrackerPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
AssumptionCacheTracker::~AssumptionCacheTracker() = default;
|
||||
|
||||
char AssumptionCacheTracker::ID = 0;
|
||||
|
||||
INITIALIZE_PASS(AssumptionCacheTracker, "assumption-cache-tracker",
|
||||
"Assumption Cache Tracker", false, true)
|
1886
external/llvm/lib/Analysis/BasicAliasAnalysis.cpp
vendored
1886
external/llvm/lib/Analysis/BasicAliasAnalysis.cpp
vendored
File diff suppressed because it is too large
Load Diff
342
external/llvm/lib/Analysis/BlockFrequencyInfo.cpp
vendored
342
external/llvm/lib/Analysis/BlockFrequencyInfo.cpp
vendored
@ -1,342 +0,0 @@
|
||||
//===- BlockFrequencyInfo.cpp - Block Frequency Analysis ------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Loops should be simplified before this analysis.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Analysis/BlockFrequencyInfo.h"
|
||||
#include "llvm/ADT/APInt.h"
|
||||
#include "llvm/ADT/None.h"
|
||||
#include "llvm/ADT/iterator.h"
|
||||
#include "llvm/Analysis/BlockFrequencyInfoImpl.h"
|
||||
#include "llvm/Analysis/BranchProbabilityInfo.h"
|
||||
#include "llvm/Analysis/LoopInfo.h"
|
||||
#include "llvm/IR/CFG.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/GraphWriter.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
#define DEBUG_TYPE "block-freq"
|
||||
|
||||
static cl::opt<GVDAGType> ViewBlockFreqPropagationDAG(
|
||||
"view-block-freq-propagation-dags", cl::Hidden,
|
||||
cl::desc("Pop up a window to show a dag displaying how block "
|
||||
"frequencies propagation through the CFG."),
|
||||
cl::values(clEnumValN(GVDT_None, "none", "do not display graphs."),
|
||||
clEnumValN(GVDT_Fraction, "fraction",
|
||||
"display a graph using the "
|
||||
"fractional block frequency representation."),
|
||||
clEnumValN(GVDT_Integer, "integer",
|
||||
"display a graph using the raw "
|
||||
"integer fractional block frequency representation."),
|
||||
clEnumValN(GVDT_Count, "count", "display a graph using the real "
|
||||
"profile count if available.")));
|
||||
|
||||
cl::opt<std::string>
|
||||
ViewBlockFreqFuncName("view-bfi-func-name", cl::Hidden,
|
||||
cl::desc("The option to specify "
|
||||
"the name of the function "
|
||||
"whose CFG will be displayed."));
|
||||
|
||||
cl::opt<unsigned>
|
||||
ViewHotFreqPercent("view-hot-freq-percent", cl::init(10), cl::Hidden,
|
||||
cl::desc("An integer in percent used to specify "
|
||||
"the hot blocks/edges to be displayed "
|
||||
"in red: a block or edge whose frequency "
|
||||
"is no less than the max frequency of the "
|
||||
"function multiplied by this percent."));
|
||||
|
||||
// Command line option to turn on CFG dot or text dump after profile annotation.
|
||||
cl::opt<PGOViewCountsType> PGOViewCounts(
|
||||
"pgo-view-counts", cl::Hidden,
|
||||
cl::desc("A boolean option to show CFG dag or text with "
|
||||
"block profile counts and branch probabilities "
|
||||
"right after PGO profile annotation step. The "
|
||||
"profile counts are computed using branch "
|
||||
"probabilities from the runtime profile data and "
|
||||
"block frequency propagation algorithm. To view "
|
||||
"the raw counts from the profile, use option "
|
||||
"-pgo-view-raw-counts instead. To limit graph "
|
||||
"display to only one function, use filtering option "
|
||||
"-view-bfi-func-name."),
|
||||
cl::values(clEnumValN(PGOVCT_None, "none", "do not show."),
|
||||
clEnumValN(PGOVCT_Graph, "graph", "show a graph."),
|
||||
clEnumValN(PGOVCT_Text, "text", "show in text.")));
|
||||
|
||||
static cl::opt<bool> PrintBlockFreq(
|
||||
"print-bfi", cl::init(false), cl::Hidden,
|
||||
cl::desc("Print the block frequency info."));
|
||||
|
||||
cl::opt<std::string> PrintBlockFreqFuncName(
|
||||
"print-bfi-func-name", cl::Hidden,
|
||||
cl::desc("The option to specify the name of the function "
|
||||
"whose block frequency info is printed."));
|
||||
|
||||
namespace llvm {
|
||||
|
||||
static GVDAGType getGVDT() {
|
||||
if (PGOViewCounts == PGOVCT_Graph)
|
||||
return GVDT_Count;
|
||||
return ViewBlockFreqPropagationDAG;
|
||||
}
|
||||
|
||||
template <>
|
||||
struct GraphTraits<BlockFrequencyInfo *> {
|
||||
using NodeRef = const BasicBlock *;
|
||||
using ChildIteratorType = succ_const_iterator;
|
||||
using nodes_iterator = pointer_iterator<Function::const_iterator>;
|
||||
|
||||
static NodeRef getEntryNode(const BlockFrequencyInfo *G) {
|
||||
return &G->getFunction()->front();
|
||||
}
|
||||
|
||||
static ChildIteratorType child_begin(const NodeRef N) {
|
||||
return succ_begin(N);
|
||||
}
|
||||
|
||||
static ChildIteratorType child_end(const NodeRef N) { return succ_end(N); }
|
||||
|
||||
static nodes_iterator nodes_begin(const BlockFrequencyInfo *G) {
|
||||
return nodes_iterator(G->getFunction()->begin());
|
||||
}
|
||||
|
||||
static nodes_iterator nodes_end(const BlockFrequencyInfo *G) {
|
||||
return nodes_iterator(G->getFunction()->end());
|
||||
}
|
||||
};
|
||||
|
||||
using BFIDOTGTraitsBase =
|
||||
BFIDOTGraphTraitsBase<BlockFrequencyInfo, BranchProbabilityInfo>;
|
||||
|
||||
template <>
|
||||
struct DOTGraphTraits<BlockFrequencyInfo *> : public BFIDOTGTraitsBase {
|
||||
explicit DOTGraphTraits(bool isSimple = false)
|
||||
: BFIDOTGTraitsBase(isSimple) {}
|
||||
|
||||
std::string getNodeLabel(const BasicBlock *Node,
|
||||
const BlockFrequencyInfo *Graph) {
|
||||
|
||||
return BFIDOTGTraitsBase::getNodeLabel(Node, Graph, getGVDT());
|
||||
}
|
||||
|
||||
std::string getNodeAttributes(const BasicBlock *Node,
|
||||
const BlockFrequencyInfo *Graph) {
|
||||
return BFIDOTGTraitsBase::getNodeAttributes(Node, Graph,
|
||||
ViewHotFreqPercent);
|
||||
}
|
||||
|
||||
std::string getEdgeAttributes(const BasicBlock *Node, EdgeIter EI,
|
||||
const BlockFrequencyInfo *BFI) {
|
||||
return BFIDOTGTraitsBase::getEdgeAttributes(Node, EI, BFI, BFI->getBPI(),
|
||||
ViewHotFreqPercent);
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
BlockFrequencyInfo::BlockFrequencyInfo() = default;
|
||||
|
||||
BlockFrequencyInfo::BlockFrequencyInfo(const Function &F,
|
||||
const BranchProbabilityInfo &BPI,
|
||||
const LoopInfo &LI) {
|
||||
calculate(F, BPI, LI);
|
||||
}
|
||||
|
||||
BlockFrequencyInfo::BlockFrequencyInfo(BlockFrequencyInfo &&Arg)
|
||||
: BFI(std::move(Arg.BFI)) {}
|
||||
|
||||
BlockFrequencyInfo &BlockFrequencyInfo::operator=(BlockFrequencyInfo &&RHS) {
|
||||
releaseMemory();
|
||||
BFI = std::move(RHS.BFI);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Explicitly define the default constructor otherwise it would be implicitly
|
||||
// defined at the first ODR-use which is the BFI member in the
|
||||
// LazyBlockFrequencyInfo header. The dtor needs the BlockFrequencyInfoImpl
|
||||
// template instantiated which is not available in the header.
|
||||
BlockFrequencyInfo::~BlockFrequencyInfo() = default;
|
||||
|
||||
bool BlockFrequencyInfo::invalidate(Function &F, const PreservedAnalyses &PA,
|
||||
FunctionAnalysisManager::Invalidator &) {
|
||||
// Check whether the analysis, all analyses on functions, or the function's
|
||||
// CFG have been preserved.
|
||||
auto PAC = PA.getChecker<BlockFrequencyAnalysis>();
|
||||
return !(PAC.preserved() || PAC.preservedSet<AllAnalysesOn<Function>>() ||
|
||||
PAC.preservedSet<CFGAnalyses>());
|
||||
}
|
||||
|
||||
void BlockFrequencyInfo::calculate(const Function &F,
|
||||
const BranchProbabilityInfo &BPI,
|
||||
const LoopInfo &LI) {
|
||||
if (!BFI)
|
||||
BFI.reset(new ImplType);
|
||||
BFI->calculate(F, BPI, LI);
|
||||
if (ViewBlockFreqPropagationDAG != GVDT_None &&
|
||||
(ViewBlockFreqFuncName.empty() ||
|
||||
F.getName().equals(ViewBlockFreqFuncName))) {
|
||||
view();
|
||||
}
|
||||
if (PrintBlockFreq &&
|
||||
(PrintBlockFreqFuncName.empty() ||
|
||||
F.getName().equals(PrintBlockFreqFuncName))) {
|
||||
print(dbgs());
|
||||
}
|
||||
}
|
||||
|
||||
BlockFrequency BlockFrequencyInfo::getBlockFreq(const BasicBlock *BB) const {
|
||||
return BFI ? BFI->getBlockFreq(BB) : 0;
|
||||
}
|
||||
|
||||
Optional<uint64_t>
|
||||
BlockFrequencyInfo::getBlockProfileCount(const BasicBlock *BB) const {
|
||||
if (!BFI)
|
||||
return None;
|
||||
|
||||
return BFI->getBlockProfileCount(*getFunction(), BB);
|
||||
}
|
||||
|
||||
Optional<uint64_t>
|
||||
BlockFrequencyInfo::getProfileCountFromFreq(uint64_t Freq) const {
|
||||
if (!BFI)
|
||||
return None;
|
||||
return BFI->getProfileCountFromFreq(*getFunction(), Freq);
|
||||
}
|
||||
|
||||
bool BlockFrequencyInfo::isIrrLoopHeader(const BasicBlock *BB) {
|
||||
assert(BFI && "Expected analysis to be available");
|
||||
return BFI->isIrrLoopHeader(BB);
|
||||
}
|
||||
|
||||
void BlockFrequencyInfo::setBlockFreq(const BasicBlock *BB, uint64_t Freq) {
|
||||
assert(BFI && "Expected analysis to be available");
|
||||
BFI->setBlockFreq(BB, Freq);
|
||||
}
|
||||
|
||||
void BlockFrequencyInfo::setBlockFreqAndScale(
|
||||
const BasicBlock *ReferenceBB, uint64_t Freq,
|
||||
SmallPtrSetImpl<BasicBlock *> &BlocksToScale) {
|
||||
assert(BFI && "Expected analysis to be available");
|
||||
// Use 128 bits APInt to avoid overflow.
|
||||
APInt NewFreq(128, Freq);
|
||||
APInt OldFreq(128, BFI->getBlockFreq(ReferenceBB).getFrequency());
|
||||
APInt BBFreq(128, 0);
|
||||
for (auto *BB : BlocksToScale) {
|
||||
BBFreq = BFI->getBlockFreq(BB).getFrequency();
|
||||
// Multiply first by NewFreq and then divide by OldFreq
|
||||
// to minimize loss of precision.
|
||||
BBFreq *= NewFreq;
|
||||
// udiv is an expensive operation in the general case. If this ends up being
|
||||
// a hot spot, one of the options proposed in
|
||||
// https://reviews.llvm.org/D28535#650071 could be used to avoid this.
|
||||
BBFreq = BBFreq.udiv(OldFreq);
|
||||
BFI->setBlockFreq(BB, BBFreq.getLimitedValue());
|
||||
}
|
||||
BFI->setBlockFreq(ReferenceBB, Freq);
|
||||
}
|
||||
|
||||
/// Pop up a ghostview window with the current block frequency propagation
|
||||
/// rendered using dot.
|
||||
void BlockFrequencyInfo::view() const {
|
||||
ViewGraph(const_cast<BlockFrequencyInfo *>(this), "BlockFrequencyDAGs");
|
||||
}
|
||||
|
||||
const Function *BlockFrequencyInfo::getFunction() const {
|
||||
return BFI ? BFI->getFunction() : nullptr;
|
||||
}
|
||||
|
||||
const BranchProbabilityInfo *BlockFrequencyInfo::getBPI() const {
|
||||
return BFI ? &BFI->getBPI() : nullptr;
|
||||
}
|
||||
|
||||
raw_ostream &BlockFrequencyInfo::
|
||||
printBlockFreq(raw_ostream &OS, const BlockFrequency Freq) const {
|
||||
return BFI ? BFI->printBlockFreq(OS, Freq) : OS;
|
||||
}
|
||||
|
||||
raw_ostream &
|
||||
BlockFrequencyInfo::printBlockFreq(raw_ostream &OS,
|
||||
const BasicBlock *BB) const {
|
||||
return BFI ? BFI->printBlockFreq(OS, BB) : OS;
|
||||
}
|
||||
|
||||
uint64_t BlockFrequencyInfo::getEntryFreq() const {
|
||||
return BFI ? BFI->getEntryFreq() : 0;
|
||||
}
|
||||
|
||||
void BlockFrequencyInfo::releaseMemory() { BFI.reset(); }
|
||||
|
||||
void BlockFrequencyInfo::print(raw_ostream &OS) const {
|
||||
if (BFI)
|
||||
BFI->print(OS);
|
||||
}
|
||||
|
||||
INITIALIZE_PASS_BEGIN(BlockFrequencyInfoWrapperPass, "block-freq",
|
||||
"Block Frequency Analysis", true, true)
|
||||
INITIALIZE_PASS_DEPENDENCY(BranchProbabilityInfoWrapperPass)
|
||||
INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass)
|
||||
INITIALIZE_PASS_END(BlockFrequencyInfoWrapperPass, "block-freq",
|
||||
"Block Frequency Analysis", true, true)
|
||||
|
||||
char BlockFrequencyInfoWrapperPass::ID = 0;
|
||||
|
||||
BlockFrequencyInfoWrapperPass::BlockFrequencyInfoWrapperPass()
|
||||
: FunctionPass(ID) {
|
||||
initializeBlockFrequencyInfoWrapperPassPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
BlockFrequencyInfoWrapperPass::~BlockFrequencyInfoWrapperPass() = default;
|
||||
|
||||
void BlockFrequencyInfoWrapperPass::print(raw_ostream &OS,
|
||||
const Module *) const {
|
||||
BFI.print(OS);
|
||||
}
|
||||
|
||||
void BlockFrequencyInfoWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.addRequired<BranchProbabilityInfoWrapperPass>();
|
||||
AU.addRequired<LoopInfoWrapperPass>();
|
||||
AU.setPreservesAll();
|
||||
}
|
||||
|
||||
void BlockFrequencyInfoWrapperPass::releaseMemory() { BFI.releaseMemory(); }
|
||||
|
||||
bool BlockFrequencyInfoWrapperPass::runOnFunction(Function &F) {
|
||||
BranchProbabilityInfo &BPI =
|
||||
getAnalysis<BranchProbabilityInfoWrapperPass>().getBPI();
|
||||
LoopInfo &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
|
||||
BFI.calculate(F, BPI, LI);
|
||||
return false;
|
||||
}
|
||||
|
||||
AnalysisKey BlockFrequencyAnalysis::Key;
|
||||
BlockFrequencyInfo BlockFrequencyAnalysis::run(Function &F,
|
||||
FunctionAnalysisManager &AM) {
|
||||
BlockFrequencyInfo BFI;
|
||||
BFI.calculate(F, AM.getResult<BranchProbabilityAnalysis>(F),
|
||||
AM.getResult<LoopAnalysis>(F));
|
||||
return BFI;
|
||||
}
|
||||
|
||||
PreservedAnalyses
|
||||
BlockFrequencyPrinterPass::run(Function &F, FunctionAnalysisManager &AM) {
|
||||
OS << "Printing analysis results of BFI for function "
|
||||
<< "'" << F.getName() << "':"
|
||||
<< "\n";
|
||||
AM.getResult<BlockFrequencyAnalysis>(F).print(OS);
|
||||
return PreservedAnalyses::all();
|
||||
}
|
File diff suppressed because it is too large
Load Diff
916
external/llvm/lib/Analysis/BranchProbabilityInfo.cpp
vendored
916
external/llvm/lib/Analysis/BranchProbabilityInfo.cpp
vendored
File diff suppressed because it is too large
Load Diff
236
external/llvm/lib/Analysis/CFG.cpp
vendored
236
external/llvm/lib/Analysis/CFG.cpp
vendored
@ -1,236 +0,0 @@
|
||||
//===-- CFG.cpp - BasicBlock analysis --------------------------------------==//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This family of functions performs analyses on basic blocks, and instructions
|
||||
// contained within basic blocks.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Analysis/CFG.h"
|
||||
#include "llvm/ADT/SmallSet.h"
|
||||
#include "llvm/Analysis/LoopInfo.h"
|
||||
#include "llvm/IR/Dominators.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
/// FindFunctionBackedges - Analyze the specified function to find all of the
|
||||
/// loop backedges in the function and return them. This is a relatively cheap
|
||||
/// (compared to computing dominators and loop info) analysis.
|
||||
///
|
||||
/// The output is added to Result, as pairs of <from,to> edge info.
|
||||
void llvm::FindFunctionBackedges(const Function &F,
|
||||
SmallVectorImpl<std::pair<const BasicBlock*,const BasicBlock*> > &Result) {
|
||||
const BasicBlock *BB = &F.getEntryBlock();
|
||||
if (succ_empty(BB))
|
||||
return;
|
||||
|
||||
SmallPtrSet<const BasicBlock*, 8> Visited;
|
||||
SmallVector<std::pair<const BasicBlock*, succ_const_iterator>, 8> VisitStack;
|
||||
SmallPtrSet<const BasicBlock*, 8> InStack;
|
||||
|
||||
Visited.insert(BB);
|
||||
VisitStack.push_back(std::make_pair(BB, succ_begin(BB)));
|
||||
InStack.insert(BB);
|
||||
do {
|
||||
std::pair<const BasicBlock*, succ_const_iterator> &Top = VisitStack.back();
|
||||
const BasicBlock *ParentBB = Top.first;
|
||||
succ_const_iterator &I = Top.second;
|
||||
|
||||
bool FoundNew = false;
|
||||
while (I != succ_end(ParentBB)) {
|
||||
BB = *I++;
|
||||
if (Visited.insert(BB).second) {
|
||||
FoundNew = true;
|
||||
break;
|
||||
}
|
||||
// Successor is in VisitStack, it's a back edge.
|
||||
if (InStack.count(BB))
|
||||
Result.push_back(std::make_pair(ParentBB, BB));
|
||||
}
|
||||
|
||||
if (FoundNew) {
|
||||
// Go down one level if there is a unvisited successor.
|
||||
InStack.insert(BB);
|
||||
VisitStack.push_back(std::make_pair(BB, succ_begin(BB)));
|
||||
} else {
|
||||
// Go up one level.
|
||||
InStack.erase(VisitStack.pop_back_val().first);
|
||||
}
|
||||
} while (!VisitStack.empty());
|
||||
}
|
||||
|
||||
/// GetSuccessorNumber - Search for the specified successor of basic block BB
|
||||
/// and return its position in the terminator instruction's list of
|
||||
/// successors. It is an error to call this with a block that is not a
|
||||
/// successor.
|
||||
unsigned llvm::GetSuccessorNumber(const BasicBlock *BB,
|
||||
const BasicBlock *Succ) {
|
||||
const TerminatorInst *Term = BB->getTerminator();
|
||||
#ifndef NDEBUG
|
||||
unsigned e = Term->getNumSuccessors();
|
||||
#endif
|
||||
for (unsigned i = 0; ; ++i) {
|
||||
assert(i != e && "Didn't find edge?");
|
||||
if (Term->getSuccessor(i) == Succ)
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
/// isCriticalEdge - Return true if the specified edge is a critical edge.
|
||||
/// Critical edges are edges from a block with multiple successors to a block
|
||||
/// with multiple predecessors.
|
||||
bool llvm::isCriticalEdge(const TerminatorInst *TI, unsigned SuccNum,
|
||||
bool AllowIdenticalEdges) {
|
||||
assert(SuccNum < TI->getNumSuccessors() && "Illegal edge specification!");
|
||||
if (TI->getNumSuccessors() == 1) return false;
|
||||
|
||||
const BasicBlock *Dest = TI->getSuccessor(SuccNum);
|
||||
const_pred_iterator I = pred_begin(Dest), E = pred_end(Dest);
|
||||
|
||||
// If there is more than one predecessor, this is a critical edge...
|
||||
assert(I != E && "No preds, but we have an edge to the block?");
|
||||
const BasicBlock *FirstPred = *I;
|
||||
++I; // Skip one edge due to the incoming arc from TI.
|
||||
if (!AllowIdenticalEdges)
|
||||
return I != E;
|
||||
|
||||
// If AllowIdenticalEdges is true, then we allow this edge to be considered
|
||||
// non-critical iff all preds come from TI's block.
|
||||
for (; I != E; ++I)
|
||||
if (*I != FirstPred)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// LoopInfo contains a mapping from basic block to the innermost loop. Find
|
||||
// the outermost loop in the loop nest that contains BB.
|
||||
static const Loop *getOutermostLoop(const LoopInfo *LI, const BasicBlock *BB) {
|
||||
const Loop *L = LI->getLoopFor(BB);
|
||||
if (L) {
|
||||
while (const Loop *Parent = L->getParentLoop())
|
||||
L = Parent;
|
||||
}
|
||||
return L;
|
||||
}
|
||||
|
||||
// True if there is a loop which contains both BB1 and BB2.
|
||||
static bool loopContainsBoth(const LoopInfo *LI,
|
||||
const BasicBlock *BB1, const BasicBlock *BB2) {
|
||||
const Loop *L1 = getOutermostLoop(LI, BB1);
|
||||
const Loop *L2 = getOutermostLoop(LI, BB2);
|
||||
return L1 != nullptr && L1 == L2;
|
||||
}
|
||||
|
||||
bool llvm::isPotentiallyReachableFromMany(
|
||||
SmallVectorImpl<BasicBlock *> &Worklist, BasicBlock *StopBB,
|
||||
const DominatorTree *DT, const LoopInfo *LI) {
|
||||
// When the stop block is unreachable, it's dominated from everywhere,
|
||||
// regardless of whether there's a path between the two blocks.
|
||||
if (DT && !DT->isReachableFromEntry(StopBB))
|
||||
DT = nullptr;
|
||||
|
||||
// Limit the number of blocks we visit. The goal is to avoid run-away compile
|
||||
// times on large CFGs without hampering sensible code. Arbitrarily chosen.
|
||||
unsigned Limit = 32;
|
||||
SmallPtrSet<const BasicBlock*, 32> Visited;
|
||||
do {
|
||||
BasicBlock *BB = Worklist.pop_back_val();
|
||||
if (!Visited.insert(BB).second)
|
||||
continue;
|
||||
if (BB == StopBB)
|
||||
return true;
|
||||
if (DT && DT->dominates(BB, StopBB))
|
||||
return true;
|
||||
if (LI && loopContainsBoth(LI, BB, StopBB))
|
||||
return true;
|
||||
|
||||
if (!--Limit) {
|
||||
// We haven't been able to prove it one way or the other. Conservatively
|
||||
// answer true -- that there is potentially a path.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (const Loop *Outer = LI ? getOutermostLoop(LI, BB) : nullptr) {
|
||||
// All blocks in a single loop are reachable from all other blocks. From
|
||||
// any of these blocks, we can skip directly to the exits of the loop,
|
||||
// ignoring any other blocks inside the loop body.
|
||||
Outer->getExitBlocks(Worklist);
|
||||
} else {
|
||||
Worklist.append(succ_begin(BB), succ_end(BB));
|
||||
}
|
||||
} while (!Worklist.empty());
|
||||
|
||||
// We have exhausted all possible paths and are certain that 'To' can not be
|
||||
// reached from 'From'.
|
||||
return false;
|
||||
}
|
||||
|
||||
bool llvm::isPotentiallyReachable(const BasicBlock *A, const BasicBlock *B,
|
||||
const DominatorTree *DT, const LoopInfo *LI) {
|
||||
assert(A->getParent() == B->getParent() &&
|
||||
"This analysis is function-local!");
|
||||
|
||||
SmallVector<BasicBlock*, 32> Worklist;
|
||||
Worklist.push_back(const_cast<BasicBlock*>(A));
|
||||
|
||||
return isPotentiallyReachableFromMany(Worklist, const_cast<BasicBlock *>(B),
|
||||
DT, LI);
|
||||
}
|
||||
|
||||
bool llvm::isPotentiallyReachable(const Instruction *A, const Instruction *B,
|
||||
const DominatorTree *DT, const LoopInfo *LI) {
|
||||
assert(A->getParent()->getParent() == B->getParent()->getParent() &&
|
||||
"This analysis is function-local!");
|
||||
|
||||
SmallVector<BasicBlock*, 32> Worklist;
|
||||
|
||||
if (A->getParent() == B->getParent()) {
|
||||
// The same block case is special because it's the only time we're looking
|
||||
// within a single block to see which instruction comes first. Once we
|
||||
// start looking at multiple blocks, the first instruction of the block is
|
||||
// reachable, so we only need to determine reachability between whole
|
||||
// blocks.
|
||||
BasicBlock *BB = const_cast<BasicBlock *>(A->getParent());
|
||||
|
||||
// If the block is in a loop then we can reach any instruction in the block
|
||||
// from any other instruction in the block by going around a backedge.
|
||||
if (LI && LI->getLoopFor(BB) != nullptr)
|
||||
return true;
|
||||
|
||||
// Linear scan, start at 'A', see whether we hit 'B' or the end first.
|
||||
for (BasicBlock::const_iterator I = A->getIterator(), E = BB->end(); I != E;
|
||||
++I) {
|
||||
if (&*I == B)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Can't be in a loop if it's the entry block -- the entry block may not
|
||||
// have predecessors.
|
||||
if (BB == &BB->getParent()->getEntryBlock())
|
||||
return false;
|
||||
|
||||
// Otherwise, continue doing the normal per-BB CFG walk.
|
||||
Worklist.append(succ_begin(BB), succ_end(BB));
|
||||
|
||||
if (Worklist.empty()) {
|
||||
// We've proven that there's no path!
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
Worklist.push_back(const_cast<BasicBlock*>(A->getParent()));
|
||||
}
|
||||
|
||||
if (A->getParent() == &A->getParent()->getParent()->getEntryBlock())
|
||||
return true;
|
||||
if (B->getParent() == &A->getParent()->getParent()->getEntryBlock())
|
||||
return false;
|
||||
|
||||
return isPotentiallyReachableFromMany(
|
||||
Worklist, const_cast<BasicBlock *>(B->getParent()), DT, LI);
|
||||
}
|
184
external/llvm/lib/Analysis/CFGPrinter.cpp
vendored
184
external/llvm/lib/Analysis/CFGPrinter.cpp
vendored
@ -1,184 +0,0 @@
|
||||
//===- CFGPrinter.cpp - DOT printer for the control flow graph ------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines a '-dot-cfg' analysis pass, which emits the
|
||||
// cfg.<fnname>.dot file for each function in the program, with a graph of the
|
||||
// CFG for that function.
|
||||
//
|
||||
// The other main feature of this file is that it implements the
|
||||
// Function::viewCFG method, which is useful for debugging passes which operate
|
||||
// on the CFG.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Analysis/CFGPrinter.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
struct CFGViewerLegacyPass : public FunctionPass {
|
||||
static char ID; // Pass identifcation, replacement for typeid
|
||||
CFGViewerLegacyPass() : FunctionPass(ID) {
|
||||
initializeCFGViewerLegacyPassPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
bool runOnFunction(Function &F) override {
|
||||
F.viewCFG();
|
||||
return false;
|
||||
}
|
||||
|
||||
void print(raw_ostream &OS, const Module* = nullptr) const override {}
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
||||
AU.setPreservesAll();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
char CFGViewerLegacyPass::ID = 0;
|
||||
INITIALIZE_PASS(CFGViewerLegacyPass, "view-cfg", "View CFG of function", false, true)
|
||||
|
||||
PreservedAnalyses CFGViewerPass::run(Function &F,
|
||||
FunctionAnalysisManager &AM) {
|
||||
F.viewCFG();
|
||||
return PreservedAnalyses::all();
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
struct CFGOnlyViewerLegacyPass : public FunctionPass {
|
||||
static char ID; // Pass identifcation, replacement for typeid
|
||||
CFGOnlyViewerLegacyPass() : FunctionPass(ID) {
|
||||
initializeCFGOnlyViewerLegacyPassPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
bool runOnFunction(Function &F) override {
|
||||
F.viewCFGOnly();
|
||||
return false;
|
||||
}
|
||||
|
||||
void print(raw_ostream &OS, const Module* = nullptr) const override {}
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
||||
AU.setPreservesAll();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
char CFGOnlyViewerLegacyPass::ID = 0;
|
||||
INITIALIZE_PASS(CFGOnlyViewerLegacyPass, "view-cfg-only",
|
||||
"View CFG of function (with no function bodies)", false, true)
|
||||
|
||||
PreservedAnalyses CFGOnlyViewerPass::run(Function &F,
|
||||
FunctionAnalysisManager &AM) {
|
||||
F.viewCFGOnly();
|
||||
return PreservedAnalyses::all();
|
||||
}
|
||||
|
||||
static void writeCFGToDotFile(Function &F, bool CFGOnly = false) {
|
||||
std::string Filename = ("cfg." + F.getName() + ".dot").str();
|
||||
errs() << "Writing '" << Filename << "'...";
|
||||
|
||||
std::error_code EC;
|
||||
raw_fd_ostream File(Filename, EC, sys::fs::F_Text);
|
||||
|
||||
if (!EC)
|
||||
WriteGraph(File, (const Function*)&F, CFGOnly);
|
||||
else
|
||||
errs() << " error opening file for writing!";
|
||||
errs() << "\n";
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct CFGPrinterLegacyPass : public FunctionPass {
|
||||
static char ID; // Pass identification, replacement for typeid
|
||||
CFGPrinterLegacyPass() : FunctionPass(ID) {
|
||||
initializeCFGPrinterLegacyPassPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
bool runOnFunction(Function &F) override {
|
||||
writeCFGToDotFile(F);
|
||||
return false;
|
||||
}
|
||||
|
||||
void print(raw_ostream &OS, const Module* = nullptr) const override {}
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
||||
AU.setPreservesAll();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
char CFGPrinterLegacyPass::ID = 0;
|
||||
INITIALIZE_PASS(CFGPrinterLegacyPass, "dot-cfg", "Print CFG of function to 'dot' file",
|
||||
false, true)
|
||||
|
||||
PreservedAnalyses CFGPrinterPass::run(Function &F,
|
||||
FunctionAnalysisManager &AM) {
|
||||
writeCFGToDotFile(F);
|
||||
return PreservedAnalyses::all();
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct CFGOnlyPrinterLegacyPass : public FunctionPass {
|
||||
static char ID; // Pass identification, replacement for typeid
|
||||
CFGOnlyPrinterLegacyPass() : FunctionPass(ID) {
|
||||
initializeCFGOnlyPrinterLegacyPassPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
bool runOnFunction(Function &F) override {
|
||||
writeCFGToDotFile(F, /*CFGOnly=*/true);
|
||||
return false;
|
||||
}
|
||||
void print(raw_ostream &OS, const Module* = nullptr) const override {}
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
||||
AU.setPreservesAll();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
char CFGOnlyPrinterLegacyPass::ID = 0;
|
||||
INITIALIZE_PASS(CFGOnlyPrinterLegacyPass, "dot-cfg-only",
|
||||
"Print CFG of function to 'dot' file (with no function bodies)",
|
||||
false, true)
|
||||
|
||||
PreservedAnalyses CFGOnlyPrinterPass::run(Function &F,
|
||||
FunctionAnalysisManager &AM) {
|
||||
writeCFGToDotFile(F, /*CFGOnly=*/true);
|
||||
return PreservedAnalyses::all();
|
||||
}
|
||||
|
||||
/// viewCFG - This function is meant for use from the debugger. You can just
|
||||
/// say 'call F->viewCFG()' and a ghostview window should pop up from the
|
||||
/// program, displaying the CFG of the current function. This depends on there
|
||||
/// being a 'dot' and 'gv' program in your path.
|
||||
///
|
||||
void Function::viewCFG() const {
|
||||
ViewGraph(this, "cfg" + getName());
|
||||
}
|
||||
|
||||
/// viewCFGOnly - This function is meant for use from the debugger. It works
|
||||
/// just like viewCFG, but it does not include the contents of basic blocks
|
||||
/// into the nodes, just the label. If you are only interested in the CFG
|
||||
/// this can make the graph smaller.
|
||||
///
|
||||
void Function::viewCFGOnly() const {
|
||||
ViewGraph(this, "cfg" + getName(), true);
|
||||
}
|
||||
|
||||
FunctionPass *llvm::createCFGPrinterLegacyPassPass () {
|
||||
return new CFGPrinterLegacyPass();
|
||||
}
|
||||
|
||||
FunctionPass *llvm::createCFGOnlyPrinterLegacyPassPass () {
|
||||
return new CFGOnlyPrinterLegacyPass();
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
671
external/llvm/lib/Analysis/CFLGraph.h
vendored
671
external/llvm/lib/Analysis/CFLGraph.h
vendored
File diff suppressed because it is too large
Load Diff
@ -1,357 +0,0 @@
|
||||
//===- CFLSteensAliasAnalysis.cpp - Unification-based Alias Analysis ------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements a CFL-base, summary-based alias analysis algorithm. It
|
||||
// does not depend on types. The algorithm is a mixture of the one described in
|
||||
// "Demand-driven alias analysis for C" by Xin Zheng and Radu Rugina, and "Fast
|
||||
// algorithms for Dyck-CFL-reachability with applications to Alias Analysis" by
|
||||
// Zhang Q, Lyu M R, Yuan H, and Su Z. -- to summarize the papers, we build a
|
||||
// graph of the uses of a variable, where each node is a memory location, and
|
||||
// each edge is an action that happened on that memory location. The "actions"
|
||||
// can be one of Dereference, Reference, or Assign. The precision of this
|
||||
// analysis is roughly the same as that of an one level context-sensitive
|
||||
// Steensgaard's algorithm.
|
||||
//
|
||||
// Two variables are considered as aliasing iff you can reach one value's node
|
||||
// from the other value's node and the language formed by concatenating all of
|
||||
// the edge labels (actions) conforms to a context-free grammar.
|
||||
//
|
||||
// Because this algorithm requires a graph search on each query, we execute the
|
||||
// algorithm outlined in "Fast algorithms..." (mentioned above)
|
||||
// in order to transform the graph into sets of variables that may alias in
|
||||
// ~nlogn time (n = number of variables), which makes queries take constant
|
||||
// time.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// N.B. AliasAnalysis as a whole is phrased as a FunctionPass at the moment, and
|
||||
// CFLSteensAA is interprocedural. This is *technically* A Bad Thing, because
|
||||
// FunctionPasses are only allowed to inspect the Function that they're being
|
||||
// run on. Realistically, this likely isn't a problem until we allow
|
||||
// FunctionPasses to run concurrently.
|
||||
|
||||
#include "llvm/Analysis/CFLSteensAliasAnalysis.h"
|
||||
#include "AliasAnalysisSummary.h"
|
||||
#include "CFLGraph.h"
|
||||
#include "StratifiedSets.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Analysis/TargetLibraryInfo.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/Type.h"
|
||||
#include "llvm/IR/Value.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::cflaa;
|
||||
|
||||
#define DEBUG_TYPE "cfl-steens-aa"
|
||||
|
||||
CFLSteensAAResult::CFLSteensAAResult(const TargetLibraryInfo &TLI)
|
||||
: AAResultBase(), TLI(TLI) {}
|
||||
CFLSteensAAResult::CFLSteensAAResult(CFLSteensAAResult &&Arg)
|
||||
: AAResultBase(std::move(Arg)), TLI(Arg.TLI) {}
|
||||
CFLSteensAAResult::~CFLSteensAAResult() = default;
|
||||
|
||||
/// Information we have about a function and would like to keep around.
|
||||
class CFLSteensAAResult::FunctionInfo {
|
||||
StratifiedSets<InstantiatedValue> Sets;
|
||||
AliasSummary Summary;
|
||||
|
||||
public:
|
||||
FunctionInfo(Function &Fn, const SmallVectorImpl<Value *> &RetVals,
|
||||
StratifiedSets<InstantiatedValue> S);
|
||||
|
||||
const StratifiedSets<InstantiatedValue> &getStratifiedSets() const {
|
||||
return Sets;
|
||||
}
|
||||
|
||||
const AliasSummary &getAliasSummary() const { return Summary; }
|
||||
};
|
||||
|
||||
const StratifiedIndex StratifiedLink::SetSentinel =
|
||||
std::numeric_limits<StratifiedIndex>::max();
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Function declarations that require types defined in the namespace above
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// Determines whether it would be pointless to add the given Value to our sets.
|
||||
static bool canSkipAddingToSets(Value *Val) {
|
||||
// Constants can share instances, which may falsely unify multiple
|
||||
// sets, e.g. in
|
||||
// store i32* null, i32** %ptr1
|
||||
// store i32* null, i32** %ptr2
|
||||
// clearly ptr1 and ptr2 should not be unified into the same set, so
|
||||
// we should filter out the (potentially shared) instance to
|
||||
// i32* null.
|
||||
if (isa<Constant>(Val)) {
|
||||
// TODO: Because all of these things are constant, we can determine whether
|
||||
// the data is *actually* mutable at graph building time. This will probably
|
||||
// come for free/cheap with offset awareness.
|
||||
bool CanStoreMutableData = isa<GlobalValue>(Val) ||
|
||||
isa<ConstantExpr>(Val) ||
|
||||
isa<ConstantAggregate>(Val);
|
||||
return !CanStoreMutableData;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
CFLSteensAAResult::FunctionInfo::FunctionInfo(
|
||||
Function &Fn, const SmallVectorImpl<Value *> &RetVals,
|
||||
StratifiedSets<InstantiatedValue> S)
|
||||
: Sets(std::move(S)) {
|
||||
// Historically, an arbitrary upper-bound of 50 args was selected. We may want
|
||||
// to remove this if it doesn't really matter in practice.
|
||||
if (Fn.arg_size() > MaxSupportedArgsInSummary)
|
||||
return;
|
||||
|
||||
DenseMap<StratifiedIndex, InterfaceValue> InterfaceMap;
|
||||
|
||||
// Our intention here is to record all InterfaceValues that share the same
|
||||
// StratifiedIndex in RetParamRelations. For each valid InterfaceValue, we
|
||||
// have its StratifiedIndex scanned here and check if the index is presented
|
||||
// in InterfaceMap: if it is not, we add the correspondence to the map;
|
||||
// otherwise, an aliasing relation is found and we add it to
|
||||
// RetParamRelations.
|
||||
|
||||
auto AddToRetParamRelations = [&](unsigned InterfaceIndex,
|
||||
StratifiedIndex SetIndex) {
|
||||
unsigned Level = 0;
|
||||
while (true) {
|
||||
InterfaceValue CurrValue{InterfaceIndex, Level};
|
||||
|
||||
auto Itr = InterfaceMap.find(SetIndex);
|
||||
if (Itr != InterfaceMap.end()) {
|
||||
if (CurrValue != Itr->second)
|
||||
Summary.RetParamRelations.push_back(
|
||||
ExternalRelation{CurrValue, Itr->second, UnknownOffset});
|
||||
break;
|
||||
}
|
||||
|
||||
auto &Link = Sets.getLink(SetIndex);
|
||||
InterfaceMap.insert(std::make_pair(SetIndex, CurrValue));
|
||||
auto ExternalAttrs = getExternallyVisibleAttrs(Link.Attrs);
|
||||
if (ExternalAttrs.any())
|
||||
Summary.RetParamAttributes.push_back(
|
||||
ExternalAttribute{CurrValue, ExternalAttrs});
|
||||
|
||||
if (!Link.hasBelow())
|
||||
break;
|
||||
|
||||
++Level;
|
||||
SetIndex = Link.Below;
|
||||
}
|
||||
};
|
||||
|
||||
// Populate RetParamRelations for return values
|
||||
for (auto *RetVal : RetVals) {
|
||||
assert(RetVal != nullptr);
|
||||
assert(RetVal->getType()->isPointerTy());
|
||||
auto RetInfo = Sets.find(InstantiatedValue{RetVal, 0});
|
||||
if (RetInfo.hasValue())
|
||||
AddToRetParamRelations(0, RetInfo->Index);
|
||||
}
|
||||
|
||||
// Populate RetParamRelations for parameters
|
||||
unsigned I = 0;
|
||||
for (auto &Param : Fn.args()) {
|
||||
if (Param.getType()->isPointerTy()) {
|
||||
auto ParamInfo = Sets.find(InstantiatedValue{&Param, 0});
|
||||
if (ParamInfo.hasValue())
|
||||
AddToRetParamRelations(I + 1, ParamInfo->Index);
|
||||
}
|
||||
++I;
|
||||
}
|
||||
}
|
||||
|
||||
// Builds the graph + StratifiedSets for a function.
|
||||
CFLSteensAAResult::FunctionInfo CFLSteensAAResult::buildSetsFrom(Function *Fn) {
|
||||
CFLGraphBuilder<CFLSteensAAResult> GraphBuilder(*this, TLI, *Fn);
|
||||
StratifiedSetsBuilder<InstantiatedValue> SetBuilder;
|
||||
|
||||
// Add all CFLGraph nodes and all Dereference edges to StratifiedSets
|
||||
auto &Graph = GraphBuilder.getCFLGraph();
|
||||
for (const auto &Mapping : Graph.value_mappings()) {
|
||||
auto Val = Mapping.first;
|
||||
if (canSkipAddingToSets(Val))
|
||||
continue;
|
||||
auto &ValueInfo = Mapping.second;
|
||||
|
||||
assert(ValueInfo.getNumLevels() > 0);
|
||||
SetBuilder.add(InstantiatedValue{Val, 0});
|
||||
SetBuilder.noteAttributes(InstantiatedValue{Val, 0},
|
||||
ValueInfo.getNodeInfoAtLevel(0).Attr);
|
||||
for (unsigned I = 0, E = ValueInfo.getNumLevels() - 1; I < E; ++I) {
|
||||
SetBuilder.add(InstantiatedValue{Val, I + 1});
|
||||
SetBuilder.noteAttributes(InstantiatedValue{Val, I + 1},
|
||||
ValueInfo.getNodeInfoAtLevel(I + 1).Attr);
|
||||
SetBuilder.addBelow(InstantiatedValue{Val, I},
|
||||
InstantiatedValue{Val, I + 1});
|
||||
}
|
||||
}
|
||||
|
||||
// Add all assign edges to StratifiedSets
|
||||
for (const auto &Mapping : Graph.value_mappings()) {
|
||||
auto Val = Mapping.first;
|
||||
if (canSkipAddingToSets(Val))
|
||||
continue;
|
||||
auto &ValueInfo = Mapping.second;
|
||||
|
||||
for (unsigned I = 0, E = ValueInfo.getNumLevels(); I < E; ++I) {
|
||||
auto Src = InstantiatedValue{Val, I};
|
||||
for (auto &Edge : ValueInfo.getNodeInfoAtLevel(I).Edges)
|
||||
SetBuilder.addWith(Src, Edge.Other);
|
||||
}
|
||||
}
|
||||
|
||||
return FunctionInfo(*Fn, GraphBuilder.getReturnValues(), SetBuilder.build());
|
||||
}
|
||||
|
||||
void CFLSteensAAResult::scan(Function *Fn) {
|
||||
auto InsertPair = Cache.insert(std::make_pair(Fn, Optional<FunctionInfo>()));
|
||||
(void)InsertPair;
|
||||
assert(InsertPair.second &&
|
||||
"Trying to scan a function that has already been cached");
|
||||
|
||||
// Note that we can't do Cache[Fn] = buildSetsFrom(Fn) here: the function call
|
||||
// may get evaluated after operator[], potentially triggering a DenseMap
|
||||
// resize and invalidating the reference returned by operator[]
|
||||
auto FunInfo = buildSetsFrom(Fn);
|
||||
Cache[Fn] = std::move(FunInfo);
|
||||
|
||||
Handles.emplace_front(Fn, this);
|
||||
}
|
||||
|
||||
void CFLSteensAAResult::evict(Function *Fn) { Cache.erase(Fn); }
|
||||
|
||||
/// Ensures that the given function is available in the cache, and returns the
|
||||
/// entry.
|
||||
const Optional<CFLSteensAAResult::FunctionInfo> &
|
||||
CFLSteensAAResult::ensureCached(Function *Fn) {
|
||||
auto Iter = Cache.find(Fn);
|
||||
if (Iter == Cache.end()) {
|
||||
scan(Fn);
|
||||
Iter = Cache.find(Fn);
|
||||
assert(Iter != Cache.end());
|
||||
assert(Iter->second.hasValue());
|
||||
}
|
||||
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);
|
||||
auto *ValB = const_cast<Value *>(LocB.Ptr);
|
||||
|
||||
if (!ValA->getType()->isPointerTy() || !ValB->getType()->isPointerTy())
|
||||
return NoAlias;
|
||||
|
||||
Function *Fn = nullptr;
|
||||
Function *MaybeFnA = const_cast<Function *>(parentFunctionOfValue(ValA));
|
||||
Function *MaybeFnB = const_cast<Function *>(parentFunctionOfValue(ValB));
|
||||
if (!MaybeFnA && !MaybeFnB) {
|
||||
// The only times this is known to happen are when globals + InlineAsm are
|
||||
// involved
|
||||
DEBUG(dbgs()
|
||||
<< "CFLSteensAA: could not extract parent function information.\n");
|
||||
return MayAlias;
|
||||
}
|
||||
|
||||
if (MaybeFnA) {
|
||||
Fn = MaybeFnA;
|
||||
assert((!MaybeFnB || MaybeFnB == MaybeFnA) &&
|
||||
"Interprocedural queries not supported");
|
||||
} else {
|
||||
Fn = MaybeFnB;
|
||||
}
|
||||
|
||||
assert(Fn != nullptr);
|
||||
auto &MaybeInfo = ensureCached(Fn);
|
||||
assert(MaybeInfo.hasValue());
|
||||
|
||||
auto &Sets = MaybeInfo->getStratifiedSets();
|
||||
auto MaybeA = Sets.find(InstantiatedValue{ValA, 0});
|
||||
if (!MaybeA.hasValue())
|
||||
return MayAlias;
|
||||
|
||||
auto MaybeB = Sets.find(InstantiatedValue{ValB, 0});
|
||||
if (!MaybeB.hasValue())
|
||||
return MayAlias;
|
||||
|
||||
auto SetA = *MaybeA;
|
||||
auto SetB = *MaybeB;
|
||||
auto AttrsA = Sets.getLink(SetA.Index).Attrs;
|
||||
auto AttrsB = Sets.getLink(SetB.Index).Attrs;
|
||||
|
||||
// If both values are local (meaning the corresponding set has attribute
|
||||
// AttrNone or AttrEscaped), then we know that CFLSteensAA fully models them:
|
||||
// they may-alias each other if and only if they are in the same set.
|
||||
// If at least one value is non-local (meaning it either is global/argument or
|
||||
// it comes from unknown sources like integer cast), the situation becomes a
|
||||
// bit more interesting. We follow three general rules described below:
|
||||
// - Non-local values may alias each other
|
||||
// - AttrNone values do not alias any non-local values
|
||||
// - AttrEscaped do not alias globals/arguments, but they may alias
|
||||
// AttrUnknown values
|
||||
if (SetA.Index == SetB.Index)
|
||||
return MayAlias;
|
||||
if (AttrsA.none() || AttrsB.none())
|
||||
return NoAlias;
|
||||
if (hasUnknownOrCallerAttr(AttrsA) || hasUnknownOrCallerAttr(AttrsB))
|
||||
return MayAlias;
|
||||
if (isGlobalOrArgAttr(AttrsA) && isGlobalOrArgAttr(AttrsB))
|
||||
return MayAlias;
|
||||
return NoAlias;
|
||||
}
|
||||
|
||||
AnalysisKey CFLSteensAA::Key;
|
||||
|
||||
CFLSteensAAResult CFLSteensAA::run(Function &F, FunctionAnalysisManager &AM) {
|
||||
return CFLSteensAAResult(AM.getResult<TargetLibraryAnalysis>(F));
|
||||
}
|
||||
|
||||
char CFLSteensAAWrapperPass::ID = 0;
|
||||
INITIALIZE_PASS(CFLSteensAAWrapperPass, "cfl-steens-aa",
|
||||
"Unification-Based CFL Alias Analysis", false, true)
|
||||
|
||||
ImmutablePass *llvm::createCFLSteensAAWrapperPass() {
|
||||
return new CFLSteensAAWrapperPass();
|
||||
}
|
||||
|
||||
CFLSteensAAWrapperPass::CFLSteensAAWrapperPass() : ImmutablePass(ID) {
|
||||
initializeCFLSteensAAWrapperPassPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
void CFLSteensAAWrapperPass::initializePass() {
|
||||
auto &TLIWP = getAnalysis<TargetLibraryInfoWrapperPass>();
|
||||
Result.reset(new CFLSteensAAResult(TLIWP.getTLI()));
|
||||
}
|
||||
|
||||
void CFLSteensAAWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.setPreservesAll();
|
||||
AU.addRequired<TargetLibraryInfoWrapperPass>();
|
||||
}
|
688
external/llvm/lib/Analysis/CGSCCPassManager.cpp
vendored
688
external/llvm/lib/Analysis/CGSCCPassManager.cpp
vendored
File diff suppressed because it is too large
Load Diff
93
external/llvm/lib/Analysis/CMakeLists.txt
vendored
93
external/llvm/lib/Analysis/CMakeLists.txt
vendored
@ -1,93 +0,0 @@
|
||||
add_llvm_library(LLVMAnalysis
|
||||
AliasAnalysis.cpp
|
||||
AliasAnalysisEvaluator.cpp
|
||||
AliasAnalysisSummary.cpp
|
||||
AliasSetTracker.cpp
|
||||
Analysis.cpp
|
||||
AssumptionCache.cpp
|
||||
BasicAliasAnalysis.cpp
|
||||
BlockFrequencyInfo.cpp
|
||||
BlockFrequencyInfoImpl.cpp
|
||||
BranchProbabilityInfo.cpp
|
||||
CFG.cpp
|
||||
CFGPrinter.cpp
|
||||
CFLAndersAliasAnalysis.cpp
|
||||
CFLSteensAliasAnalysis.cpp
|
||||
CGSCCPassManager.cpp
|
||||
CallGraph.cpp
|
||||
CallGraphSCCPass.cpp
|
||||
CallPrinter.cpp
|
||||
CaptureTracking.cpp
|
||||
CmpInstAnalysis.cpp
|
||||
CostModel.cpp
|
||||
CodeMetrics.cpp
|
||||
ConstantFolding.cpp
|
||||
Delinearization.cpp
|
||||
DemandedBits.cpp
|
||||
DependenceAnalysis.cpp
|
||||
DivergenceAnalysis.cpp
|
||||
DomPrinter.cpp
|
||||
DominanceFrontier.cpp
|
||||
EHPersonalities.cpp
|
||||
GlobalsModRef.cpp
|
||||
IVUsers.cpp
|
||||
IndirectCallPromotionAnalysis.cpp
|
||||
InlineCost.cpp
|
||||
InstCount.cpp
|
||||
InstructionSimplify.cpp
|
||||
Interval.cpp
|
||||
IntervalPartition.cpp
|
||||
IteratedDominanceFrontier.cpp
|
||||
LazyBranchProbabilityInfo.cpp
|
||||
LazyBlockFrequencyInfo.cpp
|
||||
LazyCallGraph.cpp
|
||||
LazyValueInfo.cpp
|
||||
Lint.cpp
|
||||
Loads.cpp
|
||||
LoopAccessAnalysis.cpp
|
||||
LoopAnalysisManager.cpp
|
||||
LoopUnrollAnalyzer.cpp
|
||||
LoopInfo.cpp
|
||||
LoopPass.cpp
|
||||
MemDepPrinter.cpp
|
||||
MemDerefPrinter.cpp
|
||||
MemoryBuiltins.cpp
|
||||
MemoryDependenceAnalysis.cpp
|
||||
MemoryLocation.cpp
|
||||
MemorySSA.cpp
|
||||
MemorySSAUpdater.cpp
|
||||
ModuleDebugInfoPrinter.cpp
|
||||
ModuleSummaryAnalysis.cpp
|
||||
ObjCARCAliasAnalysis.cpp
|
||||
ObjCARCAnalysisUtils.cpp
|
||||
ObjCARCInstKind.cpp
|
||||
OptimizationRemarkEmitter.cpp
|
||||
OrderedBasicBlock.cpp
|
||||
PHITransAddr.cpp
|
||||
PostDominators.cpp
|
||||
ProfileSummaryInfo.cpp
|
||||
PtrUseVisitor.cpp
|
||||
RegionInfo.cpp
|
||||
RegionPass.cpp
|
||||
RegionPrinter.cpp
|
||||
ScalarEvolution.cpp
|
||||
ScalarEvolutionAliasAnalysis.cpp
|
||||
ScalarEvolutionExpander.cpp
|
||||
ScalarEvolutionNormalization.cpp
|
||||
TargetLibraryInfo.cpp
|
||||
TargetTransformInfo.cpp
|
||||
Trace.cpp
|
||||
TypeBasedAliasAnalysis.cpp
|
||||
TypeMetadataUtils.cpp
|
||||
ScopedNoAliasAA.cpp
|
||||
ValueLattice.cpp
|
||||
ValueLatticeUtils.cpp
|
||||
ValueTracking.cpp
|
||||
VectorUtils.cpp
|
||||
|
||||
ADDITIONAL_HEADER_DIRS
|
||||
${LLVM_MAIN_INCLUDE_DIR}/llvm/Analysis
|
||||
|
||||
DEPENDS
|
||||
intrinsics_gen
|
||||
)
|
328
external/llvm/lib/Analysis/CallGraph.cpp
vendored
328
external/llvm/lib/Analysis/CallGraph.cpp
vendored
@ -1,328 +0,0 @@
|
||||
//===- CallGraph.cpp - Build a Module's call graph ------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Analysis/CallGraph.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/IR/CallSite.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/Intrinsics.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Implementations of the CallGraph class methods.
|
||||
//
|
||||
|
||||
CallGraph::CallGraph(Module &M)
|
||||
: M(M), ExternalCallingNode(getOrInsertFunction(nullptr)),
|
||||
CallsExternalNode(llvm::make_unique<CallGraphNode>(nullptr)) {
|
||||
// Add every function to the call graph.
|
||||
for (Function &F : M)
|
||||
addToCallGraph(&F);
|
||||
}
|
||||
|
||||
CallGraph::CallGraph(CallGraph &&Arg)
|
||||
: M(Arg.M), FunctionMap(std::move(Arg.FunctionMap)),
|
||||
ExternalCallingNode(Arg.ExternalCallingNode),
|
||||
CallsExternalNode(std::move(Arg.CallsExternalNode)) {
|
||||
Arg.FunctionMap.clear();
|
||||
Arg.ExternalCallingNode = nullptr;
|
||||
}
|
||||
|
||||
CallGraph::~CallGraph() {
|
||||
// CallsExternalNode is not in the function map, delete it explicitly.
|
||||
if (CallsExternalNode)
|
||||
CallsExternalNode->allReferencesDropped();
|
||||
|
||||
// Reset all node's use counts to zero before deleting them to prevent an
|
||||
// assertion from firing.
|
||||
#ifndef NDEBUG
|
||||
for (auto &I : FunctionMap)
|
||||
I.second->allReferencesDropped();
|
||||
#endif
|
||||
}
|
||||
|
||||
void CallGraph::addToCallGraph(Function *F) {
|
||||
CallGraphNode *Node = getOrInsertFunction(F);
|
||||
|
||||
// If this function has external linkage or has its address taken, anything
|
||||
// could call it.
|
||||
if (!F->hasLocalLinkage() || F->hasAddressTaken())
|
||||
ExternalCallingNode->addCalledFunction(CallSite(), Node);
|
||||
|
||||
// If this function is not defined in this translation unit, it could call
|
||||
// anything.
|
||||
if (F->isDeclaration() && !F->isIntrinsic())
|
||||
Node->addCalledFunction(CallSite(), CallsExternalNode.get());
|
||||
|
||||
// Look for calls by this function.
|
||||
for (BasicBlock &BB : *F)
|
||||
for (Instruction &I : BB) {
|
||||
if (auto CS = CallSite(&I)) {
|
||||
const Function *Callee = CS.getCalledFunction();
|
||||
if (!Callee || !Intrinsic::isLeaf(Callee->getIntrinsicID()))
|
||||
// Indirect calls of intrinsics are not allowed so no need to check.
|
||||
// We can be more precise here by using TargetArg returned by
|
||||
// Intrinsic::isLeaf.
|
||||
Node->addCalledFunction(CS, CallsExternalNode.get());
|
||||
else if (!Callee->isIntrinsic())
|
||||
Node->addCalledFunction(CS, getOrInsertFunction(Callee));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CallGraph::print(raw_ostream &OS) const {
|
||||
// Print in a deterministic order by sorting CallGraphNodes by name. We do
|
||||
// this here to avoid slowing down the non-printing fast path.
|
||||
|
||||
SmallVector<CallGraphNode *, 16> Nodes;
|
||||
Nodes.reserve(FunctionMap.size());
|
||||
|
||||
for (const auto &I : *this)
|
||||
Nodes.push_back(I.second.get());
|
||||
|
||||
std::sort(Nodes.begin(), Nodes.end(),
|
||||
[](CallGraphNode *LHS, CallGraphNode *RHS) {
|
||||
if (Function *LF = LHS->getFunction())
|
||||
if (Function *RF = RHS->getFunction())
|
||||
return LF->getName() < RF->getName();
|
||||
|
||||
return RHS->getFunction() != nullptr;
|
||||
});
|
||||
|
||||
for (CallGraphNode *CN : Nodes)
|
||||
CN->print(OS);
|
||||
}
|
||||
|
||||
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||
LLVM_DUMP_METHOD void CallGraph::dump() const { print(dbgs()); }
|
||||
#endif
|
||||
|
||||
// removeFunctionFromModule - Unlink the function from this module, returning
|
||||
// it. Because this removes the function from the module, the call graph node
|
||||
// is destroyed. This is only valid if the function does not call any other
|
||||
// functions (ie, there are no edges in it's CGN). The easiest way to do this
|
||||
// is to dropAllReferences before calling this.
|
||||
//
|
||||
Function *CallGraph::removeFunctionFromModule(CallGraphNode *CGN) {
|
||||
assert(CGN->empty() && "Cannot remove function from call "
|
||||
"graph if it references other functions!");
|
||||
Function *F = CGN->getFunction(); // Get the function for the call graph node
|
||||
FunctionMap.erase(F); // Remove the call graph node from the map
|
||||
|
||||
M.getFunctionList().remove(F);
|
||||
return F;
|
||||
}
|
||||
|
||||
/// spliceFunction - Replace the function represented by this node by another.
|
||||
/// This does not rescan the body of the function, so it is suitable when
|
||||
/// splicing the body of the old function to the new while also updating all
|
||||
/// callers from old to new.
|
||||
void CallGraph::spliceFunction(const Function *From, const Function *To) {
|
||||
assert(FunctionMap.count(From) && "No CallGraphNode for function!");
|
||||
assert(!FunctionMap.count(To) &&
|
||||
"Pointing CallGraphNode at a function that already exists");
|
||||
FunctionMapTy::iterator I = FunctionMap.find(From);
|
||||
I->second->F = const_cast<Function*>(To);
|
||||
FunctionMap[To] = std::move(I->second);
|
||||
FunctionMap.erase(I);
|
||||
}
|
||||
|
||||
// getOrInsertFunction - This method is identical to calling operator[], but
|
||||
// it will insert a new CallGraphNode for the specified function if one does
|
||||
// not already exist.
|
||||
CallGraphNode *CallGraph::getOrInsertFunction(const Function *F) {
|
||||
auto &CGN = FunctionMap[F];
|
||||
if (CGN)
|
||||
return CGN.get();
|
||||
|
||||
assert((!F || F->getParent() == &M) && "Function not in current module!");
|
||||
CGN = llvm::make_unique<CallGraphNode>(const_cast<Function *>(F));
|
||||
return CGN.get();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Implementations of the CallGraphNode class methods.
|
||||
//
|
||||
|
||||
void CallGraphNode::print(raw_ostream &OS) const {
|
||||
if (Function *F = getFunction())
|
||||
OS << "Call graph node for function: '" << F->getName() << "'";
|
||||
else
|
||||
OS << "Call graph node <<null function>>";
|
||||
|
||||
OS << "<<" << this << ">> #uses=" << getNumReferences() << '\n';
|
||||
|
||||
for (const auto &I : *this) {
|
||||
OS << " CS<" << I.first << "> calls ";
|
||||
if (Function *FI = I.second->getFunction())
|
||||
OS << "function '" << FI->getName() <<"'\n";
|
||||
else
|
||||
OS << "external node\n";
|
||||
}
|
||||
OS << '\n';
|
||||
}
|
||||
|
||||
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||
LLVM_DUMP_METHOD void CallGraphNode::dump() const { print(dbgs()); }
|
||||
#endif
|
||||
|
||||
/// removeCallEdgeFor - This method removes the edge in the node for the
|
||||
/// specified call site. Note that this method takes linear time, so it
|
||||
/// should be used sparingly.
|
||||
void CallGraphNode::removeCallEdgeFor(CallSite CS) {
|
||||
for (CalledFunctionsVector::iterator I = CalledFunctions.begin(); ; ++I) {
|
||||
assert(I != CalledFunctions.end() && "Cannot find callsite to remove!");
|
||||
if (I->first == CS.getInstruction()) {
|
||||
I->second->DropRef();
|
||||
*I = CalledFunctions.back();
|
||||
CalledFunctions.pop_back();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// removeAnyCallEdgeTo - This method removes any call edges from this node to
|
||||
// the specified callee function. This takes more time to execute than
|
||||
// removeCallEdgeTo, so it should not be used unless necessary.
|
||||
void CallGraphNode::removeAnyCallEdgeTo(CallGraphNode *Callee) {
|
||||
for (unsigned i = 0, e = CalledFunctions.size(); i != e; ++i)
|
||||
if (CalledFunctions[i].second == Callee) {
|
||||
Callee->DropRef();
|
||||
CalledFunctions[i] = CalledFunctions.back();
|
||||
CalledFunctions.pop_back();
|
||||
--i; --e;
|
||||
}
|
||||
}
|
||||
|
||||
/// removeOneAbstractEdgeTo - Remove one edge associated with a null callsite
|
||||
/// from this node to the specified callee function.
|
||||
void CallGraphNode::removeOneAbstractEdgeTo(CallGraphNode *Callee) {
|
||||
for (CalledFunctionsVector::iterator I = CalledFunctions.begin(); ; ++I) {
|
||||
assert(I != CalledFunctions.end() && "Cannot find callee to remove!");
|
||||
CallRecord &CR = *I;
|
||||
if (CR.second == Callee && CR.first == nullptr) {
|
||||
Callee->DropRef();
|
||||
*I = CalledFunctions.back();
|
||||
CalledFunctions.pop_back();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// replaceCallEdge - This method replaces the edge in the node for the
|
||||
/// specified call site with a new one. Note that this method takes linear
|
||||
/// time, so it should be used sparingly.
|
||||
void CallGraphNode::replaceCallEdge(CallSite CS,
|
||||
CallSite NewCS, CallGraphNode *NewNode){
|
||||
for (CalledFunctionsVector::iterator I = CalledFunctions.begin(); ; ++I) {
|
||||
assert(I != CalledFunctions.end() && "Cannot find callsite to remove!");
|
||||
if (I->first == CS.getInstruction()) {
|
||||
I->second->DropRef();
|
||||
I->first = NewCS.getInstruction();
|
||||
I->second = NewNode;
|
||||
NewNode->AddRef();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Provide an explicit template instantiation for the static ID.
|
||||
AnalysisKey CallGraphAnalysis::Key;
|
||||
|
||||
PreservedAnalyses CallGraphPrinterPass::run(Module &M,
|
||||
ModuleAnalysisManager &AM) {
|
||||
AM.getResult<CallGraphAnalysis>(M).print(OS);
|
||||
return PreservedAnalyses::all();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Out-of-line definitions of CallGraphAnalysis class members.
|
||||
//
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Implementations of the CallGraphWrapperPass class methods.
|
||||
//
|
||||
|
||||
CallGraphWrapperPass::CallGraphWrapperPass() : ModulePass(ID) {
|
||||
initializeCallGraphWrapperPassPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
CallGraphWrapperPass::~CallGraphWrapperPass() = default;
|
||||
|
||||
void CallGraphWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.setPreservesAll();
|
||||
}
|
||||
|
||||
bool CallGraphWrapperPass::runOnModule(Module &M) {
|
||||
// All the real work is done in the constructor for the CallGraph.
|
||||
G.reset(new CallGraph(M));
|
||||
return false;
|
||||
}
|
||||
|
||||
INITIALIZE_PASS(CallGraphWrapperPass, "basiccg", "CallGraph Construction",
|
||||
false, true)
|
||||
|
||||
char CallGraphWrapperPass::ID = 0;
|
||||
|
||||
void CallGraphWrapperPass::releaseMemory() { G.reset(); }
|
||||
|
||||
void CallGraphWrapperPass::print(raw_ostream &OS, const Module *) const {
|
||||
if (!G) {
|
||||
OS << "No call graph has been built!\n";
|
||||
return;
|
||||
}
|
||||
|
||||
// Just delegate.
|
||||
G->print(OS);
|
||||
}
|
||||
|
||||
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||
LLVM_DUMP_METHOD
|
||||
void CallGraphWrapperPass::dump() const { print(dbgs(), nullptr); }
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
struct CallGraphPrinterLegacyPass : public ModulePass {
|
||||
static char ID; // Pass ID, replacement for typeid
|
||||
|
||||
CallGraphPrinterLegacyPass() : ModulePass(ID) {
|
||||
initializeCallGraphPrinterLegacyPassPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
||||
AU.setPreservesAll();
|
||||
AU.addRequiredTransitive<CallGraphWrapperPass>();
|
||||
}
|
||||
|
||||
bool runOnModule(Module &M) override {
|
||||
getAnalysis<CallGraphWrapperPass>().print(errs(), &M);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
char CallGraphPrinterLegacyPass::ID = 0;
|
||||
|
||||
INITIALIZE_PASS_BEGIN(CallGraphPrinterLegacyPass, "print-callgraph",
|
||||
"Print a call graph", true, true)
|
||||
INITIALIZE_PASS_DEPENDENCY(CallGraphWrapperPass)
|
||||
INITIALIZE_PASS_END(CallGraphPrinterLegacyPass, "print-callgraph",
|
||||
"Print a call graph", true, true)
|
658
external/llvm/lib/Analysis/CallGraphSCCPass.cpp
vendored
658
external/llvm/lib/Analysis/CallGraphSCCPass.cpp
vendored
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user