You've already forked linux-packaging-mono
Imported Upstream version 5.18.0.207
Former-commit-id: 3b152f462918d427ce18620a2cbe4f8b79650449
This commit is contained in:
parent
8e12397d70
commit
eb85e2fc17
155
external/llvm/lib/Transforms/IPO/AlwaysInliner.cpp
vendored
155
external/llvm/lib/Transforms/IPO/AlwaysInliner.cpp
vendored
@ -1,155 +0,0 @@
|
||||
//===- InlineAlways.cpp - Code to inline always_inline functions ----------===//
|
||||
//
|
||||
// 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 custom inliner that handles only functions that
|
||||
// are marked as "always inline".
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Transforms/IPO/AlwaysInliner.h"
|
||||
#include "llvm/ADT/SetVector.h"
|
||||
#include "llvm/Analysis/AssumptionCache.h"
|
||||
#include "llvm/Analysis/InlineCost.h"
|
||||
#include "llvm/Analysis/TargetLibraryInfo.h"
|
||||
#include "llvm/IR/CallSite.h"
|
||||
#include "llvm/IR/CallingConv.h"
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/IR/Type.h"
|
||||
#include "llvm/Transforms/IPO.h"
|
||||
#include "llvm/Transforms/IPO/Inliner.h"
|
||||
#include "llvm/Transforms/Utils/Cloning.h"
|
||||
#include "llvm/Transforms/Utils/ModuleUtils.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
#define DEBUG_TYPE "inline"
|
||||
|
||||
PreservedAnalyses AlwaysInlinerPass::run(Module &M, ModuleAnalysisManager &) {
|
||||
InlineFunctionInfo IFI;
|
||||
SmallSetVector<CallSite, 16> Calls;
|
||||
bool Changed = false;
|
||||
SmallVector<Function *, 16> InlinedFunctions;
|
||||
for (Function &F : M)
|
||||
if (!F.isDeclaration() && F.hasFnAttribute(Attribute::AlwaysInline) &&
|
||||
isInlineViable(F)) {
|
||||
Calls.clear();
|
||||
|
||||
for (User *U : F.users())
|
||||
if (auto CS = CallSite(U))
|
||||
if (CS.getCalledFunction() == &F)
|
||||
Calls.insert(CS);
|
||||
|
||||
for (CallSite CS : Calls)
|
||||
// FIXME: We really shouldn't be able to fail to inline at this point!
|
||||
// We should do something to log or check the inline failures here.
|
||||
Changed |= InlineFunction(CS, IFI);
|
||||
|
||||
// Remember to try and delete this function afterward. This both avoids
|
||||
// re-walking the rest of the module and avoids dealing with any iterator
|
||||
// invalidation issues while deleting functions.
|
||||
InlinedFunctions.push_back(&F);
|
||||
}
|
||||
|
||||
// Remove any live functions.
|
||||
erase_if(InlinedFunctions, [&](Function *F) {
|
||||
F->removeDeadConstantUsers();
|
||||
return !F->isDefTriviallyDead();
|
||||
});
|
||||
|
||||
// Delete the non-comdat ones from the module and also from our vector.
|
||||
auto NonComdatBegin = partition(
|
||||
InlinedFunctions, [&](Function *F) { return F->hasComdat(); });
|
||||
for (Function *F : make_range(NonComdatBegin, InlinedFunctions.end()))
|
||||
M.getFunctionList().erase(F);
|
||||
InlinedFunctions.erase(NonComdatBegin, InlinedFunctions.end());
|
||||
|
||||
if (!InlinedFunctions.empty()) {
|
||||
// Now we just have the comdat functions. Filter out the ones whose comdats
|
||||
// are not actually dead.
|
||||
filterDeadComdatFunctions(M, InlinedFunctions);
|
||||
// The remaining functions are actually dead.
|
||||
for (Function *F : InlinedFunctions)
|
||||
M.getFunctionList().erase(F);
|
||||
}
|
||||
|
||||
return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
/// Inliner pass which only handles "always inline" functions.
|
||||
///
|
||||
/// Unlike the \c AlwaysInlinerPass, this uses the more heavyweight \c Inliner
|
||||
/// base class to provide several facilities such as array alloca merging.
|
||||
class AlwaysInlinerLegacyPass : public LegacyInlinerBase {
|
||||
|
||||
public:
|
||||
AlwaysInlinerLegacyPass() : LegacyInlinerBase(ID, /*InsertLifetime*/ true) {
|
||||
initializeAlwaysInlinerLegacyPassPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
AlwaysInlinerLegacyPass(bool InsertLifetime)
|
||||
: LegacyInlinerBase(ID, InsertLifetime) {
|
||||
initializeAlwaysInlinerLegacyPassPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
/// Main run interface method. We override here to avoid calling skipSCC().
|
||||
bool runOnSCC(CallGraphSCC &SCC) override { return inlineCalls(SCC); }
|
||||
|
||||
static char ID; // Pass identification, replacement for typeid
|
||||
|
||||
InlineCost getInlineCost(CallSite CS) override;
|
||||
|
||||
using llvm::Pass::doFinalization;
|
||||
bool doFinalization(CallGraph &CG) override {
|
||||
return removeDeadFunctions(CG, /*AlwaysInlineOnly=*/true);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
char AlwaysInlinerLegacyPass::ID = 0;
|
||||
INITIALIZE_PASS_BEGIN(AlwaysInlinerLegacyPass, "always-inline",
|
||||
"Inliner for always_inline functions", false, false)
|
||||
INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
|
||||
INITIALIZE_PASS_DEPENDENCY(CallGraphWrapperPass)
|
||||
INITIALIZE_PASS_DEPENDENCY(ProfileSummaryInfoWrapperPass)
|
||||
INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
|
||||
INITIALIZE_PASS_END(AlwaysInlinerLegacyPass, "always-inline",
|
||||
"Inliner for always_inline functions", false, false)
|
||||
|
||||
Pass *llvm::createAlwaysInlinerLegacyPass(bool InsertLifetime) {
|
||||
return new AlwaysInlinerLegacyPass(InsertLifetime);
|
||||
}
|
||||
|
||||
/// \brief Get the inline cost for the always-inliner.
|
||||
///
|
||||
/// The always inliner *only* handles functions which are marked with the
|
||||
/// attribute to force inlining. As such, it is dramatically simpler and avoids
|
||||
/// using the powerful (but expensive) inline cost analysis. Instead it uses
|
||||
/// a very simple and boring direct walk of the instructions looking for
|
||||
/// impossible-to-inline constructs.
|
||||
///
|
||||
/// Note, it would be possible to go to some lengths to cache the information
|
||||
/// computed here, but as we only expect to do this for relatively few and
|
||||
/// small functions which have the explicit attribute to force inlining, it is
|
||||
/// likely not worth it in practice.
|
||||
InlineCost AlwaysInlinerLegacyPass::getInlineCost(CallSite CS) {
|
||||
Function *Callee = CS.getCalledFunction();
|
||||
|
||||
// Only inline direct calls to functions with always-inline attributes
|
||||
// that are viable for inlining. FIXME: We shouldn't even get here for
|
||||
// declarations.
|
||||
if (Callee && !Callee->isDeclaration() &&
|
||||
CS.hasFnAttr(Attribute::AlwaysInline) && isInlineViable(*Callee))
|
||||
return InlineCost::getAlways();
|
||||
|
||||
return InlineCost::getNever();
|
||||
}
|
1100
external/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp
vendored
1100
external/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp
vendored
File diff suppressed because it is too large
Load Diff
@ -1,47 +0,0 @@
|
||||
//===- BarrierNoopPass.cpp - A barrier pass for the pass manager ----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// NOTE: DO NOT USE THIS IF AVOIDABLE
|
||||
//
|
||||
// This pass is a nonce pass intended to allow manipulation of the implicitly
|
||||
// nesting pass manager. For example, it can be used to cause a CGSCC pass
|
||||
// manager to be closed prior to running a new collection of function passes.
|
||||
//
|
||||
// FIXME: This is a huge HACK. This should be removed when the pass manager's
|
||||
// nesting is made explicit instead of implicit.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Transforms/IPO.h"
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
/// \brief A nonce module pass used to place a barrier in a pass manager.
|
||||
///
|
||||
/// There is no mechanism for ending a CGSCC pass manager once one is started.
|
||||
/// This prevents extension points from having clear deterministic ordering
|
||||
/// when they are phrased as non-module passes.
|
||||
class BarrierNoop : public ModulePass {
|
||||
public:
|
||||
static char ID; // Pass identification.
|
||||
|
||||
BarrierNoop() : ModulePass(ID) {
|
||||
initializeBarrierNoopPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
bool runOnModule(Module &M) override { return false; }
|
||||
};
|
||||
}
|
||||
|
||||
ModulePass *llvm::createBarrierNoopPass() { return new BarrierNoop(); }
|
||||
|
||||
char BarrierNoop::ID = 0;
|
||||
INITIALIZE_PASS(BarrierNoop, "barrier", "A No-Op Barrier Pass",
|
||||
false, false)
|
41
external/llvm/lib/Transforms/IPO/CMakeLists.txt
vendored
41
external/llvm/lib/Transforms/IPO/CMakeLists.txt
vendored
@ -1,41 +0,0 @@
|
||||
add_llvm_library(LLVMipo
|
||||
AlwaysInliner.cpp
|
||||
ArgumentPromotion.cpp
|
||||
BarrierNoopPass.cpp
|
||||
CalledValuePropagation.cpp
|
||||
ConstantMerge.cpp
|
||||
CrossDSOCFI.cpp
|
||||
DeadArgumentElimination.cpp
|
||||
ElimAvailExtern.cpp
|
||||
ExtractGV.cpp
|
||||
ForceFunctionAttrs.cpp
|
||||
FunctionAttrs.cpp
|
||||
FunctionImport.cpp
|
||||
GlobalDCE.cpp
|
||||
GlobalOpt.cpp
|
||||
GlobalSplit.cpp
|
||||
IPConstantPropagation.cpp
|
||||
IPO.cpp
|
||||
InferFunctionAttrs.cpp
|
||||
InlineSimple.cpp
|
||||
Inliner.cpp
|
||||
Internalize.cpp
|
||||
LoopExtractor.cpp
|
||||
LowerTypeTests.cpp
|
||||
MergeFunctions.cpp
|
||||
PartialInlining.cpp
|
||||
PassManagerBuilder.cpp
|
||||
PruneEH.cpp
|
||||
SampleProfile.cpp
|
||||
StripDeadPrototypes.cpp
|
||||
StripSymbols.cpp
|
||||
ThinLTOBitcodeWriter.cpp
|
||||
WholeProgramDevirt.cpp
|
||||
|
||||
ADDITIONAL_HEADER_DIRS
|
||||
${LLVM_MAIN_INCLUDE_DIR}/llvm/Transforms
|
||||
${LLVM_MAIN_INCLUDE_DIR}/llvm/Transforms/IPO
|
||||
|
||||
DEPENDS
|
||||
intrinsics_gen
|
||||
)
|
@ -1,423 +0,0 @@
|
||||
//===- CalledValuePropagation.cpp - Propagate called values -----*- C++ -*-===//
|
||||
//
|
||||
// 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 transformation that attaches !callees metadata to
|
||||
// indirect call sites. For a given call site, the metadata, if present,
|
||||
// indicates the set of functions the call site could possibly target at
|
||||
// run-time. This metadata is added to indirect call sites when the set of
|
||||
// possible targets can be determined by analysis and is known to be small. The
|
||||
// analysis driving the transformation is similar to constant propagation and
|
||||
// makes uses of the generic sparse propagation solver.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Transforms/IPO/CalledValuePropagation.h"
|
||||
#include "llvm/Analysis/SparsePropagation.h"
|
||||
#include "llvm/Analysis/ValueLatticeUtils.h"
|
||||
#include "llvm/IR/InstVisitor.h"
|
||||
#include "llvm/IR/MDBuilder.h"
|
||||
#include "llvm/Transforms/IPO.h"
|
||||
using namespace llvm;
|
||||
|
||||
#define DEBUG_TYPE "called-value-propagation"
|
||||
|
||||
/// The maximum number of functions to track per lattice value. Once the number
|
||||
/// of functions a call site can possibly target exceeds this threshold, it's
|
||||
/// lattice value becomes overdefined. The number of possible lattice values is
|
||||
/// bounded by Ch(F, M), where F is the number of functions in the module and M
|
||||
/// is MaxFunctionsPerValue. As such, this value should be kept very small. We
|
||||
/// likely can't do anything useful for call sites with a large number of
|
||||
/// possible targets, anyway.
|
||||
static cl::opt<unsigned> MaxFunctionsPerValue(
|
||||
"cvp-max-functions-per-value", cl::Hidden, cl::init(4),
|
||||
cl::desc("The maximum number of functions to track per lattice value"));
|
||||
|
||||
namespace {
|
||||
/// To enable interprocedural analysis, we assign LLVM values to the following
|
||||
/// groups. The register group represents SSA registers, the return group
|
||||
/// represents the return values of functions, and the memory group represents
|
||||
/// in-memory values. An LLVM Value can technically be in more than one group.
|
||||
/// It's necessary to distinguish these groups so we can, for example, track a
|
||||
/// global variable separately from the value stored at its location.
|
||||
enum class IPOGrouping { Register, Return, Memory };
|
||||
|
||||
/// Our LatticeKeys are PointerIntPairs composed of LLVM values and groupings.
|
||||
using CVPLatticeKey = PointerIntPair<Value *, 2, IPOGrouping>;
|
||||
|
||||
/// The lattice value type used by our custom lattice function. It holds the
|
||||
/// lattice state, and a set of functions.
|
||||
class CVPLatticeVal {
|
||||
public:
|
||||
/// The states of the lattice values. Only the FunctionSet state is
|
||||
/// interesting. It indicates the set of functions to which an LLVM value may
|
||||
/// refer.
|
||||
enum CVPLatticeStateTy { Undefined, FunctionSet, Overdefined, Untracked };
|
||||
|
||||
/// Comparator for sorting the functions set. We want to keep the order
|
||||
/// deterministic for testing, etc.
|
||||
struct Compare {
|
||||
bool operator()(const Function *LHS, const Function *RHS) const {
|
||||
return LHS->getName() < RHS->getName();
|
||||
}
|
||||
};
|
||||
|
||||
CVPLatticeVal() : LatticeState(Undefined) {}
|
||||
CVPLatticeVal(CVPLatticeStateTy LatticeState) : LatticeState(LatticeState) {}
|
||||
CVPLatticeVal(std::set<Function *, Compare> &&Functions)
|
||||
: LatticeState(FunctionSet), Functions(Functions) {}
|
||||
|
||||
/// Get a reference to the functions held by this lattice value. The number
|
||||
/// of functions will be zero for states other than FunctionSet.
|
||||
const std::set<Function *, Compare> &getFunctions() const {
|
||||
return Functions;
|
||||
}
|
||||
|
||||
/// Returns true if the lattice value is in the FunctionSet state.
|
||||
bool isFunctionSet() const { return LatticeState == FunctionSet; }
|
||||
|
||||
bool operator==(const CVPLatticeVal &RHS) const {
|
||||
return LatticeState == RHS.LatticeState && Functions == RHS.Functions;
|
||||
}
|
||||
|
||||
bool operator!=(const CVPLatticeVal &RHS) const {
|
||||
return LatticeState != RHS.LatticeState || Functions != RHS.Functions;
|
||||
}
|
||||
|
||||
private:
|
||||
/// Holds the state this lattice value is in.
|
||||
CVPLatticeStateTy LatticeState;
|
||||
|
||||
/// Holds functions indicating the possible targets of call sites. This set
|
||||
/// is empty for lattice values in the undefined, overdefined, and untracked
|
||||
/// states. The maximum size of the set is controlled by
|
||||
/// MaxFunctionsPerValue. Since most LLVM values are expected to be in
|
||||
/// uninteresting states (i.e., overdefined), CVPLatticeVal objects should be
|
||||
/// small and efficiently copyable.
|
||||
std::set<Function *, Compare> Functions;
|
||||
};
|
||||
|
||||
/// The custom lattice function used by the generic sparse propagation solver.
|
||||
/// It handles merging lattice values and computing new lattice values for
|
||||
/// constants, arguments, values returned from trackable functions, and values
|
||||
/// located in trackable global variables. It also computes the lattice values
|
||||
/// that change as a result of executing instructions.
|
||||
class CVPLatticeFunc
|
||||
: public AbstractLatticeFunction<CVPLatticeKey, CVPLatticeVal> {
|
||||
public:
|
||||
CVPLatticeFunc()
|
||||
: AbstractLatticeFunction(CVPLatticeVal(CVPLatticeVal::Undefined),
|
||||
CVPLatticeVal(CVPLatticeVal::Overdefined),
|
||||
CVPLatticeVal(CVPLatticeVal::Untracked)) {}
|
||||
|
||||
/// Compute and return a CVPLatticeVal for the given CVPLatticeKey.
|
||||
CVPLatticeVal ComputeLatticeVal(CVPLatticeKey Key) override {
|
||||
switch (Key.getInt()) {
|
||||
case IPOGrouping::Register:
|
||||
if (isa<Instruction>(Key.getPointer())) {
|
||||
return getUndefVal();
|
||||
} else if (auto *A = dyn_cast<Argument>(Key.getPointer())) {
|
||||
if (canTrackArgumentsInterprocedurally(A->getParent()))
|
||||
return getUndefVal();
|
||||
} else if (auto *C = dyn_cast<Constant>(Key.getPointer())) {
|
||||
return computeConstant(C);
|
||||
}
|
||||
return getOverdefinedVal();
|
||||
case IPOGrouping::Memory:
|
||||
case IPOGrouping::Return:
|
||||
if (auto *GV = dyn_cast<GlobalVariable>(Key.getPointer())) {
|
||||
if (canTrackGlobalVariableInterprocedurally(GV))
|
||||
return computeConstant(GV->getInitializer());
|
||||
} else if (auto *F = cast<Function>(Key.getPointer()))
|
||||
if (canTrackReturnsInterprocedurally(F))
|
||||
return getUndefVal();
|
||||
}
|
||||
return getOverdefinedVal();
|
||||
}
|
||||
|
||||
/// Merge the two given lattice values. The interesting cases are merging two
|
||||
/// FunctionSet values and a FunctionSet value with an Undefined value. For
|
||||
/// these cases, we simply union the function sets. If the size of the union
|
||||
/// is greater than the maximum functions we track, the merged value is
|
||||
/// overdefined.
|
||||
CVPLatticeVal MergeValues(CVPLatticeVal X, CVPLatticeVal Y) override {
|
||||
if (X == getOverdefinedVal() || Y == getOverdefinedVal())
|
||||
return getOverdefinedVal();
|
||||
if (X == getUndefVal() && Y == getUndefVal())
|
||||
return getUndefVal();
|
||||
std::set<Function *, CVPLatticeVal::Compare> Union;
|
||||
std::set_union(X.getFunctions().begin(), X.getFunctions().end(),
|
||||
Y.getFunctions().begin(), Y.getFunctions().end(),
|
||||
std::inserter(Union, Union.begin()),
|
||||
CVPLatticeVal::Compare{});
|
||||
if (Union.size() > MaxFunctionsPerValue)
|
||||
return getOverdefinedVal();
|
||||
return CVPLatticeVal(std::move(Union));
|
||||
}
|
||||
|
||||
/// Compute the lattice values that change as a result of executing the given
|
||||
/// instruction. The changed values are stored in \p ChangedValues. We handle
|
||||
/// just a few kinds of instructions since we're only propagating values that
|
||||
/// can be called.
|
||||
void ComputeInstructionState(
|
||||
Instruction &I, DenseMap<CVPLatticeKey, CVPLatticeVal> &ChangedValues,
|
||||
SparseSolver<CVPLatticeKey, CVPLatticeVal> &SS) override {
|
||||
switch (I.getOpcode()) {
|
||||
case Instruction::Call:
|
||||
return visitCallSite(cast<CallInst>(&I), ChangedValues, SS);
|
||||
case Instruction::Invoke:
|
||||
return visitCallSite(cast<InvokeInst>(&I), ChangedValues, SS);
|
||||
case Instruction::Load:
|
||||
return visitLoad(*cast<LoadInst>(&I), ChangedValues, SS);
|
||||
case Instruction::Ret:
|
||||
return visitReturn(*cast<ReturnInst>(&I), ChangedValues, SS);
|
||||
case Instruction::Select:
|
||||
return visitSelect(*cast<SelectInst>(&I), ChangedValues, SS);
|
||||
case Instruction::Store:
|
||||
return visitStore(*cast<StoreInst>(&I), ChangedValues, SS);
|
||||
default:
|
||||
return visitInst(I, ChangedValues, SS);
|
||||
}
|
||||
}
|
||||
|
||||
/// Print the given CVPLatticeVal to the specified stream.
|
||||
void PrintLatticeVal(CVPLatticeVal LV, raw_ostream &OS) override {
|
||||
if (LV == getUndefVal())
|
||||
OS << "Undefined ";
|
||||
else if (LV == getOverdefinedVal())
|
||||
OS << "Overdefined";
|
||||
else if (LV == getUntrackedVal())
|
||||
OS << "Untracked ";
|
||||
else
|
||||
OS << "FunctionSet";
|
||||
}
|
||||
|
||||
/// Print the given CVPLatticeKey to the specified stream.
|
||||
void PrintLatticeKey(CVPLatticeKey Key, raw_ostream &OS) override {
|
||||
if (Key.getInt() == IPOGrouping::Register)
|
||||
OS << "<reg> ";
|
||||
else if (Key.getInt() == IPOGrouping::Memory)
|
||||
OS << "<mem> ";
|
||||
else if (Key.getInt() == IPOGrouping::Return)
|
||||
OS << "<ret> ";
|
||||
if (isa<Function>(Key.getPointer()))
|
||||
OS << Key.getPointer()->getName();
|
||||
else
|
||||
OS << *Key.getPointer();
|
||||
}
|
||||
|
||||
/// We collect a set of indirect calls when visiting call sites. This method
|
||||
/// returns a reference to that set.
|
||||
SmallPtrSetImpl<Instruction *> &getIndirectCalls() { return IndirectCalls; }
|
||||
|
||||
private:
|
||||
/// Holds the indirect calls we encounter during the analysis. We will attach
|
||||
/// metadata to these calls after the analysis indicating the functions the
|
||||
/// calls can possibly target.
|
||||
SmallPtrSet<Instruction *, 32> IndirectCalls;
|
||||
|
||||
/// Compute a new lattice value for the given constant. The constant, after
|
||||
/// stripping any pointer casts, should be a Function. We ignore null
|
||||
/// pointers as an optimization, since calling these values is undefined
|
||||
/// behavior.
|
||||
CVPLatticeVal computeConstant(Constant *C) {
|
||||
if (isa<ConstantPointerNull>(C))
|
||||
return CVPLatticeVal(CVPLatticeVal::FunctionSet);
|
||||
if (auto *F = dyn_cast<Function>(C->stripPointerCasts()))
|
||||
return CVPLatticeVal({F});
|
||||
return getOverdefinedVal();
|
||||
}
|
||||
|
||||
/// Handle return instructions. The function's return state is the merge of
|
||||
/// the returned value state and the function's return state.
|
||||
void visitReturn(ReturnInst &I,
|
||||
DenseMap<CVPLatticeKey, CVPLatticeVal> &ChangedValues,
|
||||
SparseSolver<CVPLatticeKey, CVPLatticeVal> &SS) {
|
||||
Function *F = I.getParent()->getParent();
|
||||
if (F->getReturnType()->isVoidTy())
|
||||
return;
|
||||
auto RegI = CVPLatticeKey(I.getReturnValue(), IPOGrouping::Register);
|
||||
auto RetF = CVPLatticeKey(F, IPOGrouping::Return);
|
||||
ChangedValues[RetF] =
|
||||
MergeValues(SS.getValueState(RegI), SS.getValueState(RetF));
|
||||
}
|
||||
|
||||
/// Handle call sites. The state of a called function's formal arguments is
|
||||
/// the merge of the argument state with the call sites corresponding actual
|
||||
/// argument state. The call site state is the merge of the call site state
|
||||
/// with the returned value state of the called function.
|
||||
void visitCallSite(CallSite CS,
|
||||
DenseMap<CVPLatticeKey, CVPLatticeVal> &ChangedValues,
|
||||
SparseSolver<CVPLatticeKey, CVPLatticeVal> &SS) {
|
||||
Function *F = CS.getCalledFunction();
|
||||
Instruction *I = CS.getInstruction();
|
||||
auto RegI = CVPLatticeKey(I, IPOGrouping::Register);
|
||||
|
||||
// If this is an indirect call, save it so we can quickly revisit it when
|
||||
// attaching metadata.
|
||||
if (!F)
|
||||
IndirectCalls.insert(I);
|
||||
|
||||
// If we can't track the function's return values, there's nothing to do.
|
||||
if (!F || !canTrackReturnsInterprocedurally(F)) {
|
||||
ChangedValues[RegI] = getOverdefinedVal();
|
||||
return;
|
||||
}
|
||||
|
||||
// Inform the solver that the called function is executable, and perform
|
||||
// the merges for the arguments and return value.
|
||||
SS.MarkBlockExecutable(&F->front());
|
||||
auto RetF = CVPLatticeKey(F, IPOGrouping::Return);
|
||||
for (Argument &A : F->args()) {
|
||||
auto RegFormal = CVPLatticeKey(&A, IPOGrouping::Register);
|
||||
auto RegActual =
|
||||
CVPLatticeKey(CS.getArgument(A.getArgNo()), IPOGrouping::Register);
|
||||
ChangedValues[RegFormal] =
|
||||
MergeValues(SS.getValueState(RegFormal), SS.getValueState(RegActual));
|
||||
}
|
||||
ChangedValues[RegI] =
|
||||
MergeValues(SS.getValueState(RegI), SS.getValueState(RetF));
|
||||
}
|
||||
|
||||
/// Handle select instructions. The select instruction state is the merge the
|
||||
/// true and false value states.
|
||||
void visitSelect(SelectInst &I,
|
||||
DenseMap<CVPLatticeKey, CVPLatticeVal> &ChangedValues,
|
||||
SparseSolver<CVPLatticeKey, CVPLatticeVal> &SS) {
|
||||
auto RegI = CVPLatticeKey(&I, IPOGrouping::Register);
|
||||
auto RegT = CVPLatticeKey(I.getTrueValue(), IPOGrouping::Register);
|
||||
auto RegF = CVPLatticeKey(I.getFalseValue(), IPOGrouping::Register);
|
||||
ChangedValues[RegI] =
|
||||
MergeValues(SS.getValueState(RegT), SS.getValueState(RegF));
|
||||
}
|
||||
|
||||
/// Handle load instructions. If the pointer operand of the load is a global
|
||||
/// variable, we attempt to track the value. The loaded value state is the
|
||||
/// merge of the loaded value state with the global variable state.
|
||||
void visitLoad(LoadInst &I,
|
||||
DenseMap<CVPLatticeKey, CVPLatticeVal> &ChangedValues,
|
||||
SparseSolver<CVPLatticeKey, CVPLatticeVal> &SS) {
|
||||
auto RegI = CVPLatticeKey(&I, IPOGrouping::Register);
|
||||
if (auto *GV = dyn_cast<GlobalVariable>(I.getPointerOperand())) {
|
||||
auto MemGV = CVPLatticeKey(GV, IPOGrouping::Memory);
|
||||
ChangedValues[RegI] =
|
||||
MergeValues(SS.getValueState(RegI), SS.getValueState(MemGV));
|
||||
} else {
|
||||
ChangedValues[RegI] = getOverdefinedVal();
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle store instructions. If the pointer operand of the store is a
|
||||
/// global variable, we attempt to track the value. The global variable state
|
||||
/// is the merge of the stored value state with the global variable state.
|
||||
void visitStore(StoreInst &I,
|
||||
DenseMap<CVPLatticeKey, CVPLatticeVal> &ChangedValues,
|
||||
SparseSolver<CVPLatticeKey, CVPLatticeVal> &SS) {
|
||||
auto *GV = dyn_cast<GlobalVariable>(I.getPointerOperand());
|
||||
if (!GV)
|
||||
return;
|
||||
auto RegI = CVPLatticeKey(I.getValueOperand(), IPOGrouping::Register);
|
||||
auto MemGV = CVPLatticeKey(GV, IPOGrouping::Memory);
|
||||
ChangedValues[MemGV] =
|
||||
MergeValues(SS.getValueState(RegI), SS.getValueState(MemGV));
|
||||
}
|
||||
|
||||
/// Handle all other instructions. All other instructions are marked
|
||||
/// overdefined.
|
||||
void visitInst(Instruction &I,
|
||||
DenseMap<CVPLatticeKey, CVPLatticeVal> &ChangedValues,
|
||||
SparseSolver<CVPLatticeKey, CVPLatticeVal> &SS) {
|
||||
auto RegI = CVPLatticeKey(&I, IPOGrouping::Register);
|
||||
ChangedValues[RegI] = getOverdefinedVal();
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace llvm {
|
||||
/// A specialization of LatticeKeyInfo for CVPLatticeKeys. The generic solver
|
||||
/// must translate between LatticeKeys and LLVM Values when adding Values to
|
||||
/// its work list and inspecting the state of control-flow related values.
|
||||
template <> struct LatticeKeyInfo<CVPLatticeKey> {
|
||||
static inline Value *getValueFromLatticeKey(CVPLatticeKey Key) {
|
||||
return Key.getPointer();
|
||||
}
|
||||
static inline CVPLatticeKey getLatticeKeyFromValue(Value *V) {
|
||||
return CVPLatticeKey(V, IPOGrouping::Register);
|
||||
}
|
||||
};
|
||||
} // namespace llvm
|
||||
|
||||
static bool runCVP(Module &M) {
|
||||
// Our custom lattice function and generic sparse propagation solver.
|
||||
CVPLatticeFunc Lattice;
|
||||
SparseSolver<CVPLatticeKey, CVPLatticeVal> Solver(&Lattice);
|
||||
|
||||
// For each function in the module, if we can't track its arguments, let the
|
||||
// generic solver assume it is executable.
|
||||
for (Function &F : M)
|
||||
if (!F.isDeclaration() && !canTrackArgumentsInterprocedurally(&F))
|
||||
Solver.MarkBlockExecutable(&F.front());
|
||||
|
||||
// Solver our custom lattice. In doing so, we will also build a set of
|
||||
// indirect call sites.
|
||||
Solver.Solve();
|
||||
|
||||
// Attach metadata to the indirect call sites that were collected indicating
|
||||
// the set of functions they can possibly target.
|
||||
bool Changed = false;
|
||||
MDBuilder MDB(M.getContext());
|
||||
for (Instruction *C : Lattice.getIndirectCalls()) {
|
||||
CallSite CS(C);
|
||||
auto RegI = CVPLatticeKey(CS.getCalledValue(), IPOGrouping::Register);
|
||||
CVPLatticeVal LV = Solver.getExistingValueState(RegI);
|
||||
if (!LV.isFunctionSet() || LV.getFunctions().empty())
|
||||
continue;
|
||||
MDNode *Callees = MDB.createCallees(SmallVector<Function *, 4>(
|
||||
LV.getFunctions().begin(), LV.getFunctions().end()));
|
||||
C->setMetadata(LLVMContext::MD_callees, Callees);
|
||||
Changed = true;
|
||||
}
|
||||
|
||||
return Changed;
|
||||
}
|
||||
|
||||
PreservedAnalyses CalledValuePropagationPass::run(Module &M,
|
||||
ModuleAnalysisManager &) {
|
||||
runCVP(M);
|
||||
return PreservedAnalyses::all();
|
||||
}
|
||||
|
||||
namespace {
|
||||
class CalledValuePropagationLegacyPass : public ModulePass {
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
||||
AU.setPreservesAll();
|
||||
}
|
||||
|
||||
CalledValuePropagationLegacyPass() : ModulePass(ID) {
|
||||
initializeCalledValuePropagationLegacyPassPass(
|
||||
*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
bool runOnModule(Module &M) override {
|
||||
if (skipModule(M))
|
||||
return false;
|
||||
return runCVP(M);
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
char CalledValuePropagationLegacyPass::ID = 0;
|
||||
INITIALIZE_PASS(CalledValuePropagationLegacyPass, "called-value-propagation",
|
||||
"Called Value Propagation", false, false)
|
||||
|
||||
ModulePass *llvm::createCalledValuePropagationPass() {
|
||||
return new CalledValuePropagationLegacyPass();
|
||||
}
|
260
external/llvm/lib/Transforms/IPO/ConstantMerge.cpp
vendored
260
external/llvm/lib/Transforms/IPO/ConstantMerge.cpp
vendored
@ -1,260 +0,0 @@
|
||||
//===- ConstantMerge.cpp - Merge duplicate global constants ---------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the interface to a pass that merges duplicate global
|
||||
// constants together into a single constant that is shared. This is useful
|
||||
// because some passes (ie TraceValues) insert a lot of string constants into
|
||||
// the program, regardless of whether or not an existing string is available.
|
||||
//
|
||||
// Algorithm: ConstantMerge is designed to build up a map of available constants
|
||||
// and eliminate duplicates when it is initialized.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Transforms/IPO/ConstantMerge.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
#include "llvm/IR/DerivedTypes.h"
|
||||
#include "llvm/IR/GlobalValue.h"
|
||||
#include "llvm/IR/GlobalVariable.h"
|
||||
#include "llvm/IR/LLVMContext.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Transforms/IPO.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <utility>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
#define DEBUG_TYPE "constmerge"
|
||||
|
||||
STATISTIC(NumMerged, "Number of global constants merged");
|
||||
|
||||
/// Find values that are marked as llvm.used.
|
||||
static void FindUsedValues(GlobalVariable *LLVMUsed,
|
||||
SmallPtrSetImpl<const GlobalValue*> &UsedValues) {
|
||||
if (!LLVMUsed) return;
|
||||
ConstantArray *Inits = cast<ConstantArray>(LLVMUsed->getInitializer());
|
||||
|
||||
for (unsigned i = 0, e = Inits->getNumOperands(); i != e; ++i) {
|
||||
Value *Operand = Inits->getOperand(i)->stripPointerCastsNoFollowAliases();
|
||||
GlobalValue *GV = cast<GlobalValue>(Operand);
|
||||
UsedValues.insert(GV);
|
||||
}
|
||||
}
|
||||
|
||||
// True if A is better than B.
|
||||
static bool IsBetterCanonical(const GlobalVariable &A,
|
||||
const GlobalVariable &B) {
|
||||
if (!A.hasLocalLinkage() && B.hasLocalLinkage())
|
||||
return true;
|
||||
|
||||
if (A.hasLocalLinkage() && !B.hasLocalLinkage())
|
||||
return false;
|
||||
|
||||
return A.hasGlobalUnnamedAddr();
|
||||
}
|
||||
|
||||
static bool hasMetadataOtherThanDebugLoc(const GlobalVariable *GV) {
|
||||
SmallVector<std::pair<unsigned, MDNode *>, 4> MDs;
|
||||
GV->getAllMetadata(MDs);
|
||||
for (const auto &V : MDs)
|
||||
if (V.first != LLVMContext::MD_dbg)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static void copyDebugLocMetadata(const GlobalVariable *From,
|
||||
GlobalVariable *To) {
|
||||
SmallVector<DIGlobalVariableExpression *, 1> MDs;
|
||||
From->getDebugInfo(MDs);
|
||||
for (auto MD : MDs)
|
||||
To->addDebugInfo(MD);
|
||||
}
|
||||
|
||||
static unsigned getAlignment(GlobalVariable *GV) {
|
||||
unsigned Align = GV->getAlignment();
|
||||
if (Align)
|
||||
return Align;
|
||||
return GV->getParent()->getDataLayout().getPreferredAlignment(GV);
|
||||
}
|
||||
|
||||
static bool mergeConstants(Module &M) {
|
||||
// Find all the globals that are marked "used". These cannot be merged.
|
||||
SmallPtrSet<const GlobalValue*, 8> UsedGlobals;
|
||||
FindUsedValues(M.getGlobalVariable("llvm.used"), UsedGlobals);
|
||||
FindUsedValues(M.getGlobalVariable("llvm.compiler.used"), UsedGlobals);
|
||||
|
||||
// Map unique constants to globals.
|
||||
DenseMap<Constant *, GlobalVariable *> CMap;
|
||||
|
||||
// Replacements - This vector contains a list of replacements to perform.
|
||||
SmallVector<std::pair<GlobalVariable*, GlobalVariable*>, 32> Replacements;
|
||||
|
||||
bool MadeChange = false;
|
||||
|
||||
// Iterate constant merging while we are still making progress. Merging two
|
||||
// constants together may allow us to merge other constants together if the
|
||||
// second level constants have initializers which point to the globals that
|
||||
// were just merged.
|
||||
while (true) {
|
||||
// First: Find the canonical constants others will be merged with.
|
||||
for (Module::global_iterator GVI = M.global_begin(), E = M.global_end();
|
||||
GVI != E; ) {
|
||||
GlobalVariable *GV = &*GVI++;
|
||||
|
||||
// If this GV is dead, remove it.
|
||||
GV->removeDeadConstantUsers();
|
||||
if (GV->use_empty() && GV->hasLocalLinkage()) {
|
||||
GV->eraseFromParent();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Only process constants with initializers in the default address space.
|
||||
if (!GV->isConstant() || !GV->hasDefinitiveInitializer() ||
|
||||
GV->getType()->getAddressSpace() != 0 || GV->hasSection() ||
|
||||
// Don't touch values marked with attribute(used).
|
||||
UsedGlobals.count(GV))
|
||||
continue;
|
||||
|
||||
// This transformation is legal for weak ODR globals in the sense it
|
||||
// doesn't change semantics, but we really don't want to perform it
|
||||
// anyway; it's likely to pessimize code generation, and some tools
|
||||
// (like the Darwin linker in cases involving CFString) don't expect it.
|
||||
if (GV->isWeakForLinker())
|
||||
continue;
|
||||
|
||||
// Don't touch globals with metadata other then !dbg.
|
||||
if (hasMetadataOtherThanDebugLoc(GV))
|
||||
continue;
|
||||
|
||||
Constant *Init = GV->getInitializer();
|
||||
|
||||
// Check to see if the initializer is already known.
|
||||
GlobalVariable *&Slot = CMap[Init];
|
||||
|
||||
// If this is the first constant we find or if the old one is local,
|
||||
// replace with the current one. If the current is externally visible
|
||||
// it cannot be replace, but can be the canonical constant we merge with.
|
||||
if (!Slot || IsBetterCanonical(*GV, *Slot))
|
||||
Slot = GV;
|
||||
}
|
||||
|
||||
// Second: identify all globals that can be merged together, filling in
|
||||
// the Replacements vector. We cannot do the replacement in this pass
|
||||
// because doing so may cause initializers of other globals to be rewritten,
|
||||
// invalidating the Constant* pointers in CMap.
|
||||
for (Module::global_iterator GVI = M.global_begin(), E = M.global_end();
|
||||
GVI != E; ) {
|
||||
GlobalVariable *GV = &*GVI++;
|
||||
|
||||
// Only process constants with initializers in the default address space.
|
||||
if (!GV->isConstant() || !GV->hasDefinitiveInitializer() ||
|
||||
GV->getType()->getAddressSpace() != 0 || GV->hasSection() ||
|
||||
// Don't touch values marked with attribute(used).
|
||||
UsedGlobals.count(GV))
|
||||
continue;
|
||||
|
||||
// We can only replace constant with local linkage.
|
||||
if (!GV->hasLocalLinkage())
|
||||
continue;
|
||||
|
||||
Constant *Init = GV->getInitializer();
|
||||
|
||||
// Check to see if the initializer is already known.
|
||||
GlobalVariable *Slot = CMap[Init];
|
||||
|
||||
if (!Slot || Slot == GV)
|
||||
continue;
|
||||
|
||||
if (!Slot->hasGlobalUnnamedAddr() && !GV->hasGlobalUnnamedAddr())
|
||||
continue;
|
||||
|
||||
if (hasMetadataOtherThanDebugLoc(GV))
|
||||
continue;
|
||||
|
||||
if (!GV->hasGlobalUnnamedAddr())
|
||||
Slot->setUnnamedAddr(GlobalValue::UnnamedAddr::None);
|
||||
|
||||
// Make all uses of the duplicate constant use the canonical version.
|
||||
Replacements.push_back(std::make_pair(GV, Slot));
|
||||
}
|
||||
|
||||
if (Replacements.empty())
|
||||
return MadeChange;
|
||||
CMap.clear();
|
||||
|
||||
// Now that we have figured out which replacements must be made, do them all
|
||||
// now. This avoid invalidating the pointers in CMap, which are unneeded
|
||||
// now.
|
||||
for (unsigned i = 0, e = Replacements.size(); i != e; ++i) {
|
||||
// Bump the alignment if necessary.
|
||||
if (Replacements[i].first->getAlignment() ||
|
||||
Replacements[i].second->getAlignment()) {
|
||||
Replacements[i].second->setAlignment(
|
||||
std::max(getAlignment(Replacements[i].first),
|
||||
getAlignment(Replacements[i].second)));
|
||||
}
|
||||
|
||||
copyDebugLocMetadata(Replacements[i].first, Replacements[i].second);
|
||||
|
||||
// Eliminate any uses of the dead global.
|
||||
Replacements[i].first->replaceAllUsesWith(Replacements[i].second);
|
||||
|
||||
// Delete the global value from the module.
|
||||
assert(Replacements[i].first->hasLocalLinkage() &&
|
||||
"Refusing to delete an externally visible global variable.");
|
||||
Replacements[i].first->eraseFromParent();
|
||||
}
|
||||
|
||||
NumMerged += Replacements.size();
|
||||
Replacements.clear();
|
||||
}
|
||||
}
|
||||
|
||||
PreservedAnalyses ConstantMergePass::run(Module &M, ModuleAnalysisManager &) {
|
||||
if (!mergeConstants(M))
|
||||
return PreservedAnalyses::all();
|
||||
return PreservedAnalyses::none();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct ConstantMergeLegacyPass : public ModulePass {
|
||||
static char ID; // Pass identification, replacement for typeid
|
||||
|
||||
ConstantMergeLegacyPass() : ModulePass(ID) {
|
||||
initializeConstantMergeLegacyPassPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
// For this pass, process all of the globals in the module, eliminating
|
||||
// duplicate constants.
|
||||
bool runOnModule(Module &M) override {
|
||||
if (skipModule(M))
|
||||
return false;
|
||||
return mergeConstants(M);
|
||||
}
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
char ConstantMergeLegacyPass::ID = 0;
|
||||
|
||||
INITIALIZE_PASS(ConstantMergeLegacyPass, "constmerge",
|
||||
"Merge Duplicate Global Constants", false, false)
|
||||
|
||||
ModulePass *llvm::createConstantMergePass() {
|
||||
return new ConstantMergeLegacyPass();
|
||||
}
|
182
external/llvm/lib/Transforms/IPO/CrossDSOCFI.cpp
vendored
182
external/llvm/lib/Transforms/IPO/CrossDSOCFI.cpp
vendored
@ -1,182 +0,0 @@
|
||||
//===-- CrossDSOCFI.cpp - Externalize this module's CFI checks ------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This pass exports all llvm.bitset's found in the module in the form of a
|
||||
// __cfi_check function, which can be used to verify cross-DSO call targets.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Transforms/IPO/CrossDSOCFI.h"
|
||||
#include "llvm/ADT/SetVector.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/IR/Constant.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/GlobalObject.h"
|
||||
#include "llvm/IR/GlobalVariable.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/IR/Intrinsics.h"
|
||||
#include "llvm/IR/MDBuilder.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/IR/Operator.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Transforms/IPO.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
#define DEBUG_TYPE "cross-dso-cfi"
|
||||
|
||||
STATISTIC(NumTypeIds, "Number of unique type identifiers");
|
||||
|
||||
namespace {
|
||||
|
||||
struct CrossDSOCFI : public ModulePass {
|
||||
static char ID;
|
||||
CrossDSOCFI() : ModulePass(ID) {
|
||||
initializeCrossDSOCFIPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
MDNode *VeryLikelyWeights;
|
||||
|
||||
ConstantInt *extractNumericTypeId(MDNode *MD);
|
||||
void buildCFICheck(Module &M);
|
||||
bool runOnModule(Module &M) override;
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
INITIALIZE_PASS_BEGIN(CrossDSOCFI, "cross-dso-cfi", "Cross-DSO CFI", false,
|
||||
false)
|
||||
INITIALIZE_PASS_END(CrossDSOCFI, "cross-dso-cfi", "Cross-DSO CFI", false, false)
|
||||
char CrossDSOCFI::ID = 0;
|
||||
|
||||
ModulePass *llvm::createCrossDSOCFIPass() { return new CrossDSOCFI; }
|
||||
|
||||
/// Extracts a numeric type identifier from an MDNode containing type metadata.
|
||||
ConstantInt *CrossDSOCFI::extractNumericTypeId(MDNode *MD) {
|
||||
// This check excludes vtables for classes inside anonymous namespaces.
|
||||
auto TM = dyn_cast<ValueAsMetadata>(MD->getOperand(1));
|
||||
if (!TM)
|
||||
return nullptr;
|
||||
auto C = dyn_cast_or_null<ConstantInt>(TM->getValue());
|
||||
if (!C) return nullptr;
|
||||
// We are looking for i64 constants.
|
||||
if (C->getBitWidth() != 64) return nullptr;
|
||||
|
||||
return C;
|
||||
}
|
||||
|
||||
/// buildCFICheck - emits __cfi_check for the current module.
|
||||
void CrossDSOCFI::buildCFICheck(Module &M) {
|
||||
// FIXME: verify that __cfi_check ends up near the end of the code section,
|
||||
// but before the jump slots created in LowerTypeTests.
|
||||
SetVector<uint64_t> TypeIds;
|
||||
SmallVector<MDNode *, 2> Types;
|
||||
for (GlobalObject &GO : M.global_objects()) {
|
||||
Types.clear();
|
||||
GO.getMetadata(LLVMContext::MD_type, Types);
|
||||
for (MDNode *Type : Types) {
|
||||
// Sanity check. GO must not be a function declaration.
|
||||
assert(!isa<Function>(&GO) || !cast<Function>(&GO)->isDeclaration());
|
||||
|
||||
if (ConstantInt *TypeId = extractNumericTypeId(Type))
|
||||
TypeIds.insert(TypeId->getZExtValue());
|
||||
}
|
||||
}
|
||||
|
||||
NamedMDNode *CfiFunctionsMD = M.getNamedMetadata("cfi.functions");
|
||||
if (CfiFunctionsMD) {
|
||||
for (auto Func : CfiFunctionsMD->operands()) {
|
||||
assert(Func->getNumOperands() >= 2);
|
||||
for (unsigned I = 2; I < Func->getNumOperands(); ++I)
|
||||
if (ConstantInt *TypeId =
|
||||
extractNumericTypeId(cast<MDNode>(Func->getOperand(I).get())))
|
||||
TypeIds.insert(TypeId->getZExtValue());
|
||||
}
|
||||
}
|
||||
|
||||
LLVMContext &Ctx = M.getContext();
|
||||
Constant *C = M.getOrInsertFunction(
|
||||
"__cfi_check", Type::getVoidTy(Ctx), Type::getInt64Ty(Ctx),
|
||||
Type::getInt8PtrTy(Ctx), Type::getInt8PtrTy(Ctx));
|
||||
Function *F = dyn_cast<Function>(C);
|
||||
// Take over the existing function. The frontend emits a weak stub so that the
|
||||
// linker knows about the symbol; this pass replaces the function body.
|
||||
F->deleteBody();
|
||||
F->setAlignment(4096);
|
||||
|
||||
Triple T(M.getTargetTriple());
|
||||
if (T.isARM() || T.isThumb())
|
||||
F->addFnAttr("target-features", "+thumb-mode");
|
||||
|
||||
auto args = F->arg_begin();
|
||||
Value &CallSiteTypeId = *(args++);
|
||||
CallSiteTypeId.setName("CallSiteTypeId");
|
||||
Value &Addr = *(args++);
|
||||
Addr.setName("Addr");
|
||||
Value &CFICheckFailData = *(args++);
|
||||
CFICheckFailData.setName("CFICheckFailData");
|
||||
assert(args == F->arg_end());
|
||||
|
||||
BasicBlock *BB = BasicBlock::Create(Ctx, "entry", F);
|
||||
BasicBlock *ExitBB = BasicBlock::Create(Ctx, "exit", F);
|
||||
|
||||
BasicBlock *TrapBB = BasicBlock::Create(Ctx, "fail", F);
|
||||
IRBuilder<> IRBFail(TrapBB);
|
||||
Constant *CFICheckFailFn = M.getOrInsertFunction(
|
||||
"__cfi_check_fail", Type::getVoidTy(Ctx), Type::getInt8PtrTy(Ctx),
|
||||
Type::getInt8PtrTy(Ctx));
|
||||
IRBFail.CreateCall(CFICheckFailFn, {&CFICheckFailData, &Addr});
|
||||
IRBFail.CreateBr(ExitBB);
|
||||
|
||||
IRBuilder<> IRBExit(ExitBB);
|
||||
IRBExit.CreateRetVoid();
|
||||
|
||||
IRBuilder<> IRB(BB);
|
||||
SwitchInst *SI = IRB.CreateSwitch(&CallSiteTypeId, TrapBB, TypeIds.size());
|
||||
for (uint64_t TypeId : TypeIds) {
|
||||
ConstantInt *CaseTypeId = ConstantInt::get(Type::getInt64Ty(Ctx), TypeId);
|
||||
BasicBlock *TestBB = BasicBlock::Create(Ctx, "test", F);
|
||||
IRBuilder<> IRBTest(TestBB);
|
||||
Function *BitsetTestFn = Intrinsic::getDeclaration(&M, Intrinsic::type_test);
|
||||
|
||||
Value *Test = IRBTest.CreateCall(
|
||||
BitsetTestFn, {&Addr, MetadataAsValue::get(
|
||||
Ctx, ConstantAsMetadata::get(CaseTypeId))});
|
||||
BranchInst *BI = IRBTest.CreateCondBr(Test, ExitBB, TrapBB);
|
||||
BI->setMetadata(LLVMContext::MD_prof, VeryLikelyWeights);
|
||||
|
||||
SI->addCase(CaseTypeId, TestBB);
|
||||
++NumTypeIds;
|
||||
}
|
||||
}
|
||||
|
||||
bool CrossDSOCFI::runOnModule(Module &M) {
|
||||
if (skipModule(M))
|
||||
return false;
|
||||
|
||||
VeryLikelyWeights =
|
||||
MDBuilder(M.getContext()).createBranchWeights((1U << 20) - 1, 1);
|
||||
if (M.getModuleFlag("Cross-DSO CFI") == nullptr)
|
||||
return false;
|
||||
buildCFICheck(M);
|
||||
return true;
|
||||
}
|
||||
|
||||
PreservedAnalyses CrossDSOCFIPass::run(Module &M, ModuleAnalysisManager &AM) {
|
||||
CrossDSOCFI Impl;
|
||||
bool Changed = Impl.runOnModule(M);
|
||||
if (!Changed)
|
||||
return PreservedAnalyses::all();
|
||||
return PreservedAnalyses::none();
|
||||
}
|
File diff suppressed because it is too large
Load Diff
102
external/llvm/lib/Transforms/IPO/ElimAvailExtern.cpp
vendored
102
external/llvm/lib/Transforms/IPO/ElimAvailExtern.cpp
vendored
@ -1,102 +0,0 @@
|
||||
//===- ElimAvailExtern.cpp - DCE unreachable internal functions -----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This transform is designed to eliminate available external global
|
||||
// definitions from the program, turning them into declarations.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Transforms/IPO/ElimAvailExtern.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/IR/Constant.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/GlobalValue.h"
|
||||
#include "llvm/IR/GlobalVariable.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Transforms/IPO.h"
|
||||
#include "llvm/Transforms/Utils/GlobalStatus.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
#define DEBUG_TYPE "elim-avail-extern"
|
||||
|
||||
STATISTIC(NumFunctions, "Number of functions removed");
|
||||
STATISTIC(NumVariables, "Number of global variables removed");
|
||||
|
||||
static bool eliminateAvailableExternally(Module &M) {
|
||||
bool Changed = false;
|
||||
|
||||
// Drop initializers of available externally global variables.
|
||||
for (GlobalVariable &GV : M.globals()) {
|
||||
if (!GV.hasAvailableExternallyLinkage())
|
||||
continue;
|
||||
if (GV.hasInitializer()) {
|
||||
Constant *Init = GV.getInitializer();
|
||||
GV.setInitializer(nullptr);
|
||||
if (isSafeToDestroyConstant(Init))
|
||||
Init->destroyConstant();
|
||||
}
|
||||
GV.removeDeadConstantUsers();
|
||||
GV.setLinkage(GlobalValue::ExternalLinkage);
|
||||
NumVariables++;
|
||||
Changed = true;
|
||||
}
|
||||
|
||||
// Drop the bodies of available externally functions.
|
||||
for (Function &F : M) {
|
||||
if (!F.hasAvailableExternallyLinkage())
|
||||
continue;
|
||||
if (!F.isDeclaration())
|
||||
// This will set the linkage to external
|
||||
F.deleteBody();
|
||||
F.removeDeadConstantUsers();
|
||||
NumFunctions++;
|
||||
Changed = true;
|
||||
}
|
||||
|
||||
return Changed;
|
||||
}
|
||||
|
||||
PreservedAnalyses
|
||||
EliminateAvailableExternallyPass::run(Module &M, ModuleAnalysisManager &) {
|
||||
if (!eliminateAvailableExternally(M))
|
||||
return PreservedAnalyses::all();
|
||||
return PreservedAnalyses::none();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct EliminateAvailableExternallyLegacyPass : public ModulePass {
|
||||
static char ID; // Pass identification, replacement for typeid
|
||||
|
||||
EliminateAvailableExternallyLegacyPass() : ModulePass(ID) {
|
||||
initializeEliminateAvailableExternallyLegacyPassPass(
|
||||
*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
// run - Do the EliminateAvailableExternally pass on the specified module,
|
||||
// optionally updating the specified callgraph to reflect the changes.
|
||||
bool runOnModule(Module &M) override {
|
||||
if (skipModule(M))
|
||||
return false;
|
||||
return eliminateAvailableExternally(M);
|
||||
}
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
char EliminateAvailableExternallyLegacyPass::ID = 0;
|
||||
|
||||
INITIALIZE_PASS(EliminateAvailableExternallyLegacyPass, "elim-avail-extern",
|
||||
"Eliminate Available Externally Globals", false, false)
|
||||
|
||||
ModulePass *llvm::createEliminateAvailableExternallyPass() {
|
||||
return new EliminateAvailableExternallyLegacyPass();
|
||||
}
|
161
external/llvm/lib/Transforms/IPO/ExtractGV.cpp
vendored
161
external/llvm/lib/Transforms/IPO/ExtractGV.cpp
vendored
@ -1,161 +0,0 @@
|
||||
//===-- ExtractGV.cpp - Global Value extraction pass ----------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This pass extracts global values
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/ADT/SetVector.h"
|
||||
#include "llvm/IR/LLVMContext.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Transforms/IPO.h"
|
||||
#include <algorithm>
|
||||
using namespace llvm;
|
||||
|
||||
/// Make sure GV is visible from both modules. Delete is true if it is
|
||||
/// being deleted from this module.
|
||||
/// This also makes sure GV cannot be dropped so that references from
|
||||
/// the split module remain valid.
|
||||
static void makeVisible(GlobalValue &GV, bool Delete) {
|
||||
bool Local = GV.hasLocalLinkage();
|
||||
if (Local || Delete) {
|
||||
GV.setLinkage(GlobalValue::ExternalLinkage);
|
||||
if (Local)
|
||||
GV.setVisibility(GlobalValue::HiddenVisibility);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!GV.hasLinkOnceLinkage()) {
|
||||
assert(!GV.isDiscardableIfUnused());
|
||||
return;
|
||||
}
|
||||
|
||||
// Map linkonce* to weak* so that llvm doesn't drop this GV.
|
||||
switch(GV.getLinkage()) {
|
||||
default:
|
||||
llvm_unreachable("Unexpected linkage");
|
||||
case GlobalValue::LinkOnceAnyLinkage:
|
||||
GV.setLinkage(GlobalValue::WeakAnyLinkage);
|
||||
return;
|
||||
case GlobalValue::LinkOnceODRLinkage:
|
||||
GV.setLinkage(GlobalValue::WeakODRLinkage);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
/// @brief A pass to extract specific global values and their dependencies.
|
||||
class GVExtractorPass : public ModulePass {
|
||||
SetVector<GlobalValue *> Named;
|
||||
bool deleteStuff;
|
||||
public:
|
||||
static char ID; // Pass identification, replacement for typeid
|
||||
|
||||
/// If deleteS is true, this pass deletes the specified global values.
|
||||
/// Otherwise, it deletes as much of the module as possible, except for the
|
||||
/// global values specified.
|
||||
explicit GVExtractorPass(std::vector<GlobalValue*> &GVs,
|
||||
bool deleteS = true)
|
||||
: ModulePass(ID), Named(GVs.begin(), GVs.end()), deleteStuff(deleteS) {}
|
||||
|
||||
bool runOnModule(Module &M) override {
|
||||
if (skipModule(M))
|
||||
return false;
|
||||
|
||||
// Visit the global inline asm.
|
||||
if (!deleteStuff)
|
||||
M.setModuleInlineAsm("");
|
||||
|
||||
// For simplicity, just give all GlobalValues ExternalLinkage. A trickier
|
||||
// implementation could figure out which GlobalValues are actually
|
||||
// referenced by the Named set, and which GlobalValues in the rest of
|
||||
// the module are referenced by the NamedSet, and get away with leaving
|
||||
// more internal and private things internal and private. But for now,
|
||||
// be conservative and simple.
|
||||
|
||||
// Visit the GlobalVariables.
|
||||
for (Module::global_iterator I = M.global_begin(), E = M.global_end();
|
||||
I != E; ++I) {
|
||||
bool Delete =
|
||||
deleteStuff == (bool)Named.count(&*I) && !I->isDeclaration();
|
||||
if (!Delete) {
|
||||
if (I->hasAvailableExternallyLinkage())
|
||||
continue;
|
||||
if (I->getName() == "llvm.global_ctors")
|
||||
continue;
|
||||
}
|
||||
|
||||
makeVisible(*I, Delete);
|
||||
|
||||
if (Delete) {
|
||||
// Make this a declaration and drop it's comdat.
|
||||
I->setInitializer(nullptr);
|
||||
I->setComdat(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
// Visit the Functions.
|
||||
for (Function &F : M) {
|
||||
bool Delete =
|
||||
deleteStuff == (bool)Named.count(&F) && !F.isDeclaration();
|
||||
if (!Delete) {
|
||||
if (F.hasAvailableExternallyLinkage())
|
||||
continue;
|
||||
}
|
||||
|
||||
makeVisible(F, Delete);
|
||||
|
||||
if (Delete) {
|
||||
// Make this a declaration and drop it's comdat.
|
||||
F.deleteBody();
|
||||
F.setComdat(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
// Visit the Aliases.
|
||||
for (Module::alias_iterator I = M.alias_begin(), E = M.alias_end();
|
||||
I != E;) {
|
||||
Module::alias_iterator CurI = I;
|
||||
++I;
|
||||
|
||||
bool Delete = deleteStuff == (bool)Named.count(&*CurI);
|
||||
makeVisible(*CurI, Delete);
|
||||
|
||||
if (Delete) {
|
||||
Type *Ty = CurI->getValueType();
|
||||
|
||||
CurI->removeFromParent();
|
||||
llvm::Value *Declaration;
|
||||
if (FunctionType *FTy = dyn_cast<FunctionType>(Ty)) {
|
||||
Declaration = Function::Create(FTy, GlobalValue::ExternalLinkage,
|
||||
CurI->getName(), &M);
|
||||
|
||||
} else {
|
||||
Declaration =
|
||||
new GlobalVariable(M, Ty, false, GlobalValue::ExternalLinkage,
|
||||
nullptr, CurI->getName());
|
||||
|
||||
}
|
||||
CurI->replaceAllUsesWith(Declaration);
|
||||
delete &*CurI;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
char GVExtractorPass::ID = 0;
|
||||
}
|
||||
|
||||
ModulePass *llvm::createGVExtractionPass(std::vector<GlobalValue *> &GVs,
|
||||
bool deleteFn) {
|
||||
return new GVExtractorPass(GVs, deleteFn);
|
||||
}
|
@ -1,124 +0,0 @@
|
||||
//===- ForceFunctionAttrs.cpp - Force function attrs for debugging --------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Transforms/IPO/ForceFunctionAttrs.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/LLVMContext.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
using namespace llvm;
|
||||
|
||||
#define DEBUG_TYPE "forceattrs"
|
||||
|
||||
static cl::list<std::string>
|
||||
ForceAttributes("force-attribute", cl::Hidden,
|
||||
cl::desc("Add an attribute to a function. This should be a "
|
||||
"pair of 'function-name:attribute-name', for "
|
||||
"example -force-attribute=foo:noinline. This "
|
||||
"option can be specified multiple times."));
|
||||
|
||||
static Attribute::AttrKind parseAttrKind(StringRef Kind) {
|
||||
return StringSwitch<Attribute::AttrKind>(Kind)
|
||||
.Case("alwaysinline", Attribute::AlwaysInline)
|
||||
.Case("builtin", Attribute::Builtin)
|
||||
.Case("cold", Attribute::Cold)
|
||||
.Case("convergent", Attribute::Convergent)
|
||||
.Case("inlinehint", Attribute::InlineHint)
|
||||
.Case("jumptable", Attribute::JumpTable)
|
||||
.Case("minsize", Attribute::MinSize)
|
||||
.Case("naked", Attribute::Naked)
|
||||
.Case("nobuiltin", Attribute::NoBuiltin)
|
||||
.Case("noduplicate", Attribute::NoDuplicate)
|
||||
.Case("noimplicitfloat", Attribute::NoImplicitFloat)
|
||||
.Case("noinline", Attribute::NoInline)
|
||||
.Case("nonlazybind", Attribute::NonLazyBind)
|
||||
.Case("noredzone", Attribute::NoRedZone)
|
||||
.Case("noreturn", Attribute::NoReturn)
|
||||
.Case("norecurse", Attribute::NoRecurse)
|
||||
.Case("nounwind", Attribute::NoUnwind)
|
||||
.Case("optnone", Attribute::OptimizeNone)
|
||||
.Case("optsize", Attribute::OptimizeForSize)
|
||||
.Case("readnone", Attribute::ReadNone)
|
||||
.Case("readonly", Attribute::ReadOnly)
|
||||
.Case("argmemonly", Attribute::ArgMemOnly)
|
||||
.Case("returns_twice", Attribute::ReturnsTwice)
|
||||
.Case("safestack", Attribute::SafeStack)
|
||||
.Case("sanitize_address", Attribute::SanitizeAddress)
|
||||
.Case("sanitize_hwaddress", Attribute::SanitizeHWAddress)
|
||||
.Case("sanitize_memory", Attribute::SanitizeMemory)
|
||||
.Case("sanitize_thread", Attribute::SanitizeThread)
|
||||
.Case("ssp", Attribute::StackProtect)
|
||||
.Case("sspreq", Attribute::StackProtectReq)
|
||||
.Case("sspstrong", Attribute::StackProtectStrong)
|
||||
.Case("strictfp", Attribute::StrictFP)
|
||||
.Case("uwtable", Attribute::UWTable)
|
||||
.Default(Attribute::None);
|
||||
}
|
||||
|
||||
/// If F has any forced attributes given on the command line, add them.
|
||||
static void addForcedAttributes(Function &F) {
|
||||
for (auto &S : ForceAttributes) {
|
||||
auto KV = StringRef(S).split(':');
|
||||
if (KV.first != F.getName())
|
||||
continue;
|
||||
|
||||
auto Kind = parseAttrKind(KV.second);
|
||||
if (Kind == Attribute::None) {
|
||||
DEBUG(dbgs() << "ForcedAttribute: " << KV.second
|
||||
<< " unknown or not handled!\n");
|
||||
continue;
|
||||
}
|
||||
if (F.hasFnAttribute(Kind))
|
||||
continue;
|
||||
F.addFnAttr(Kind);
|
||||
}
|
||||
}
|
||||
|
||||
PreservedAnalyses ForceFunctionAttrsPass::run(Module &M,
|
||||
ModuleAnalysisManager &) {
|
||||
if (ForceAttributes.empty())
|
||||
return PreservedAnalyses::all();
|
||||
|
||||
for (Function &F : M.functions())
|
||||
addForcedAttributes(F);
|
||||
|
||||
// Just conservatively invalidate analyses, this isn't likely to be important.
|
||||
return PreservedAnalyses::none();
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct ForceFunctionAttrsLegacyPass : public ModulePass {
|
||||
static char ID; // Pass identification, replacement for typeid
|
||||
ForceFunctionAttrsLegacyPass() : ModulePass(ID) {
|
||||
initializeForceFunctionAttrsLegacyPassPass(
|
||||
*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
bool runOnModule(Module &M) override {
|
||||
if (ForceAttributes.empty())
|
||||
return false;
|
||||
|
||||
for (Function &F : M.functions())
|
||||
addForcedAttributes(F);
|
||||
|
||||
// Conservatively assume we changed something.
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
char ForceFunctionAttrsLegacyPass::ID = 0;
|
||||
INITIALIZE_PASS(ForceFunctionAttrsLegacyPass, "forceattrs",
|
||||
"Force set function attributes", false, false)
|
||||
|
||||
Pass *llvm::createForceFunctionAttrsLegacyPass() {
|
||||
return new ForceFunctionAttrsLegacyPass();
|
||||
}
|
1368
external/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
vendored
1368
external/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
vendored
File diff suppressed because it is too large
Load Diff
961
external/llvm/lib/Transforms/IPO/FunctionImport.cpp
vendored
961
external/llvm/lib/Transforms/IPO/FunctionImport.cpp
vendored
File diff suppressed because it is too large
Load Diff
293
external/llvm/lib/Transforms/IPO/GlobalDCE.cpp
vendored
293
external/llvm/lib/Transforms/IPO/GlobalDCE.cpp
vendored
@ -1,293 +0,0 @@
|
||||
//===-- GlobalDCE.cpp - DCE unreachable internal functions ----------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This transform is designed to eliminate unreachable internal globals from the
|
||||
// program. It uses an aggressive algorithm, searching out globals that are
|
||||
// known to be alive. After it finds all of the globals which are needed, it
|
||||
// deletes whatever is left over. This allows it to delete recursive chunks of
|
||||
// the program which are unreachable.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Transforms/IPO/GlobalDCE.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Transforms/IPO.h"
|
||||
#include "llvm/Transforms/Utils/CtorUtils.h"
|
||||
#include "llvm/Transforms/Utils/GlobalStatus.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
#define DEBUG_TYPE "globaldce"
|
||||
|
||||
STATISTIC(NumAliases , "Number of global aliases removed");
|
||||
STATISTIC(NumFunctions, "Number of functions removed");
|
||||
STATISTIC(NumIFuncs, "Number of indirect functions removed");
|
||||
STATISTIC(NumVariables, "Number of global variables removed");
|
||||
|
||||
namespace {
|
||||
class GlobalDCELegacyPass : public ModulePass {
|
||||
public:
|
||||
static char ID; // Pass identification, replacement for typeid
|
||||
GlobalDCELegacyPass() : ModulePass(ID) {
|
||||
initializeGlobalDCELegacyPassPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
// run - Do the GlobalDCE pass on the specified module, optionally updating
|
||||
// the specified callgraph to reflect the changes.
|
||||
//
|
||||
bool runOnModule(Module &M) override {
|
||||
if (skipModule(M))
|
||||
return false;
|
||||
|
||||
// We need a minimally functional dummy module analysis manager. It needs
|
||||
// to at least know about the possibility of proxying a function analysis
|
||||
// manager.
|
||||
FunctionAnalysisManager DummyFAM;
|
||||
ModuleAnalysisManager DummyMAM;
|
||||
DummyMAM.registerPass(
|
||||
[&] { return FunctionAnalysisManagerModuleProxy(DummyFAM); });
|
||||
|
||||
auto PA = Impl.run(M, DummyMAM);
|
||||
return !PA.areAllPreserved();
|
||||
}
|
||||
|
||||
private:
|
||||
GlobalDCEPass Impl;
|
||||
};
|
||||
}
|
||||
|
||||
char GlobalDCELegacyPass::ID = 0;
|
||||
INITIALIZE_PASS(GlobalDCELegacyPass, "globaldce",
|
||||
"Dead Global Elimination", false, false)
|
||||
|
||||
// Public interface to the GlobalDCEPass.
|
||||
ModulePass *llvm::createGlobalDCEPass() {
|
||||
return new GlobalDCELegacyPass();
|
||||
}
|
||||
|
||||
/// Returns true if F contains only a single "ret" instruction.
|
||||
static bool isEmptyFunction(Function *F) {
|
||||
BasicBlock &Entry = F->getEntryBlock();
|
||||
if (Entry.size() != 1 || !isa<ReturnInst>(Entry.front()))
|
||||
return false;
|
||||
ReturnInst &RI = cast<ReturnInst>(Entry.front());
|
||||
return RI.getReturnValue() == nullptr;
|
||||
}
|
||||
|
||||
/// Compute the set of GlobalValue that depends from V.
|
||||
/// The recursion stops as soon as a GlobalValue is met.
|
||||
void GlobalDCEPass::ComputeDependencies(Value *V,
|
||||
SmallPtrSetImpl<GlobalValue *> &Deps) {
|
||||
if (auto *I = dyn_cast<Instruction>(V)) {
|
||||
Function *Parent = I->getParent()->getParent();
|
||||
Deps.insert(Parent);
|
||||
} else if (auto *GV = dyn_cast<GlobalValue>(V)) {
|
||||
Deps.insert(GV);
|
||||
} else if (auto *CE = dyn_cast<Constant>(V)) {
|
||||
// Avoid walking the whole tree of a big ConstantExprs multiple times.
|
||||
auto Where = ConstantDependenciesCache.find(CE);
|
||||
if (Where != ConstantDependenciesCache.end()) {
|
||||
auto const &K = Where->second;
|
||||
Deps.insert(K.begin(), K.end());
|
||||
} else {
|
||||
SmallPtrSetImpl<GlobalValue *> &LocalDeps = ConstantDependenciesCache[CE];
|
||||
for (User *CEUser : CE->users())
|
||||
ComputeDependencies(CEUser, LocalDeps);
|
||||
Deps.insert(LocalDeps.begin(), LocalDeps.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GlobalDCEPass::UpdateGVDependencies(GlobalValue &GV) {
|
||||
SmallPtrSet<GlobalValue *, 8> Deps;
|
||||
for (User *User : GV.users())
|
||||
ComputeDependencies(User, Deps);
|
||||
Deps.erase(&GV); // Remove self-reference.
|
||||
for (GlobalValue *GVU : Deps) {
|
||||
GVDependencies[GVU].insert(&GV);
|
||||
}
|
||||
}
|
||||
|
||||
/// Mark Global value as Live
|
||||
void GlobalDCEPass::MarkLive(GlobalValue &GV,
|
||||
SmallVectorImpl<GlobalValue *> *Updates) {
|
||||
auto const Ret = AliveGlobals.insert(&GV);
|
||||
if (!Ret.second)
|
||||
return;
|
||||
|
||||
if (Updates)
|
||||
Updates->push_back(&GV);
|
||||
if (Comdat *C = GV.getComdat()) {
|
||||
for (auto &&CM : make_range(ComdatMembers.equal_range(C)))
|
||||
MarkLive(*CM.second, Updates); // Recursion depth is only two because only
|
||||
// globals in the same comdat are visited.
|
||||
}
|
||||
}
|
||||
|
||||
PreservedAnalyses GlobalDCEPass::run(Module &M, ModuleAnalysisManager &MAM) {
|
||||
bool Changed = false;
|
||||
|
||||
// The algorithm first computes the set L of global variables that are
|
||||
// trivially live. Then it walks the initialization of these variables to
|
||||
// compute the globals used to initialize them, which effectively builds a
|
||||
// directed graph where nodes are global variables, and an edge from A to B
|
||||
// means B is used to initialize A. Finally, it propagates the liveness
|
||||
// information through the graph starting from the nodes in L. Nodes note
|
||||
// marked as alive are discarded.
|
||||
|
||||
// Remove empty functions from the global ctors list.
|
||||
Changed |= optimizeGlobalCtorsList(M, isEmptyFunction);
|
||||
|
||||
// Collect the set of members for each comdat.
|
||||
for (Function &F : M)
|
||||
if (Comdat *C = F.getComdat())
|
||||
ComdatMembers.insert(std::make_pair(C, &F));
|
||||
for (GlobalVariable &GV : M.globals())
|
||||
if (Comdat *C = GV.getComdat())
|
||||
ComdatMembers.insert(std::make_pair(C, &GV));
|
||||
for (GlobalAlias &GA : M.aliases())
|
||||
if (Comdat *C = GA.getComdat())
|
||||
ComdatMembers.insert(std::make_pair(C, &GA));
|
||||
|
||||
// Loop over the module, adding globals which are obviously necessary.
|
||||
for (GlobalObject &GO : M.global_objects()) {
|
||||
Changed |= RemoveUnusedGlobalValue(GO);
|
||||
// Functions with external linkage are needed if they have a body.
|
||||
// Externally visible & appending globals are needed, if they have an
|
||||
// initializer.
|
||||
if (!GO.isDeclaration() && !GO.hasAvailableExternallyLinkage())
|
||||
if (!GO.isDiscardableIfUnused())
|
||||
MarkLive(GO);
|
||||
|
||||
UpdateGVDependencies(GO);
|
||||
}
|
||||
|
||||
// Compute direct dependencies of aliases.
|
||||
for (GlobalAlias &GA : M.aliases()) {
|
||||
Changed |= RemoveUnusedGlobalValue(GA);
|
||||
// Externally visible aliases are needed.
|
||||
if (!GA.isDiscardableIfUnused())
|
||||
MarkLive(GA);
|
||||
|
||||
UpdateGVDependencies(GA);
|
||||
}
|
||||
|
||||
// Compute direct dependencies of ifuncs.
|
||||
for (GlobalIFunc &GIF : M.ifuncs()) {
|
||||
Changed |= RemoveUnusedGlobalValue(GIF);
|
||||
// Externally visible ifuncs are needed.
|
||||
if (!GIF.isDiscardableIfUnused())
|
||||
MarkLive(GIF);
|
||||
|
||||
UpdateGVDependencies(GIF);
|
||||
}
|
||||
|
||||
// Propagate liveness from collected Global Values through the computed
|
||||
// dependencies.
|
||||
SmallVector<GlobalValue *, 8> NewLiveGVs{AliveGlobals.begin(),
|
||||
AliveGlobals.end()};
|
||||
while (!NewLiveGVs.empty()) {
|
||||
GlobalValue *LGV = NewLiveGVs.pop_back_val();
|
||||
for (auto *GVD : GVDependencies[LGV])
|
||||
MarkLive(*GVD, &NewLiveGVs);
|
||||
}
|
||||
|
||||
// Now that all globals which are needed are in the AliveGlobals set, we loop
|
||||
// through the program, deleting those which are not alive.
|
||||
//
|
||||
|
||||
// The first pass is to drop initializers of global variables which are dead.
|
||||
std::vector<GlobalVariable *> DeadGlobalVars; // Keep track of dead globals
|
||||
for (GlobalVariable &GV : M.globals())
|
||||
if (!AliveGlobals.count(&GV)) {
|
||||
DeadGlobalVars.push_back(&GV); // Keep track of dead globals
|
||||
if (GV.hasInitializer()) {
|
||||
Constant *Init = GV.getInitializer();
|
||||
GV.setInitializer(nullptr);
|
||||
if (isSafeToDestroyConstant(Init))
|
||||
Init->destroyConstant();
|
||||
}
|
||||
}
|
||||
|
||||
// The second pass drops the bodies of functions which are dead...
|
||||
std::vector<Function *> DeadFunctions;
|
||||
for (Function &F : M)
|
||||
if (!AliveGlobals.count(&F)) {
|
||||
DeadFunctions.push_back(&F); // Keep track of dead globals
|
||||
if (!F.isDeclaration())
|
||||
F.deleteBody();
|
||||
}
|
||||
|
||||
// The third pass drops targets of aliases which are dead...
|
||||
std::vector<GlobalAlias*> DeadAliases;
|
||||
for (GlobalAlias &GA : M.aliases())
|
||||
if (!AliveGlobals.count(&GA)) {
|
||||
DeadAliases.push_back(&GA);
|
||||
GA.setAliasee(nullptr);
|
||||
}
|
||||
|
||||
// The fourth pass drops targets of ifuncs which are dead...
|
||||
std::vector<GlobalIFunc*> DeadIFuncs;
|
||||
for (GlobalIFunc &GIF : M.ifuncs())
|
||||
if (!AliveGlobals.count(&GIF)) {
|
||||
DeadIFuncs.push_back(&GIF);
|
||||
GIF.setResolver(nullptr);
|
||||
}
|
||||
|
||||
// Now that all interferences have been dropped, delete the actual objects
|
||||
// themselves.
|
||||
auto EraseUnusedGlobalValue = [&](GlobalValue *GV) {
|
||||
RemoveUnusedGlobalValue(*GV);
|
||||
GV->eraseFromParent();
|
||||
Changed = true;
|
||||
};
|
||||
|
||||
NumFunctions += DeadFunctions.size();
|
||||
for (Function *F : DeadFunctions)
|
||||
EraseUnusedGlobalValue(F);
|
||||
|
||||
NumVariables += DeadGlobalVars.size();
|
||||
for (GlobalVariable *GV : DeadGlobalVars)
|
||||
EraseUnusedGlobalValue(GV);
|
||||
|
||||
NumAliases += DeadAliases.size();
|
||||
for (GlobalAlias *GA : DeadAliases)
|
||||
EraseUnusedGlobalValue(GA);
|
||||
|
||||
NumIFuncs += DeadIFuncs.size();
|
||||
for (GlobalIFunc *GIF : DeadIFuncs)
|
||||
EraseUnusedGlobalValue(GIF);
|
||||
|
||||
// Make sure that all memory is released
|
||||
AliveGlobals.clear();
|
||||
ConstantDependenciesCache.clear();
|
||||
GVDependencies.clear();
|
||||
ComdatMembers.clear();
|
||||
|
||||
if (Changed)
|
||||
return PreservedAnalyses::none();
|
||||
return PreservedAnalyses::all();
|
||||
}
|
||||
|
||||
// RemoveUnusedGlobalValue - Loop over all of the uses of the specified
|
||||
// GlobalValue, looking for the constant pointer ref that may be pointing to it.
|
||||
// If found, check to see if the constant pointer ref is safe to destroy, and if
|
||||
// so, nuke it. This will reduce the reference count on the global value, which
|
||||
// might make it deader.
|
||||
//
|
||||
bool GlobalDCEPass::RemoveUnusedGlobalValue(GlobalValue &GV) {
|
||||
if (GV.use_empty())
|
||||
return false;
|
||||
GV.removeDeadConstantUsers();
|
||||
return GV.use_empty();
|
||||
}
|
@ -1 +0,0 @@
|
||||
e0bbf45d316aaf0b6cca9720829810e0970d8e86
|
193
external/llvm/lib/Transforms/IPO/GlobalSplit.cpp
vendored
193
external/llvm/lib/Transforms/IPO/GlobalSplit.cpp
vendored
@ -1,193 +0,0 @@
|
||||
//===- GlobalSplit.cpp - global variable splitter -------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This pass uses inrange annotations on GEP indices to split globals where
|
||||
// beneficial. Clang currently attaches these annotations to references to
|
||||
// virtual table globals under the Itanium ABI for the benefit of the
|
||||
// whole-program virtual call optimization and control flow integrity passes.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Transforms/IPO/GlobalSplit.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/IR/Constant.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/GlobalValue.h"
|
||||
#include "llvm/IR/GlobalVariable.h"
|
||||
#include "llvm/IR/Intrinsics.h"
|
||||
#include "llvm/IR/LLVMContext.h"
|
||||
#include "llvm/IR/Metadata.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/IR/Operator.h"
|
||||
#include "llvm/IR/Type.h"
|
||||
#include "llvm/IR/User.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Transforms/IPO.h"
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
static bool splitGlobal(GlobalVariable &GV) {
|
||||
// If the address of the global is taken outside of the module, we cannot
|
||||
// apply this transformation.
|
||||
if (!GV.hasLocalLinkage())
|
||||
return false;
|
||||
|
||||
// We currently only know how to split ConstantStructs.
|
||||
auto *Init = dyn_cast_or_null<ConstantStruct>(GV.getInitializer());
|
||||
if (!Init)
|
||||
return false;
|
||||
|
||||
// Verify that each user of the global is an inrange getelementptr constant.
|
||||
// From this it follows that any loads from or stores to that global must use
|
||||
// a pointer derived from an inrange getelementptr constant, which is
|
||||
// sufficient to allow us to apply the splitting transform.
|
||||
for (User *U : GV.users()) {
|
||||
if (!isa<Constant>(U))
|
||||
return false;
|
||||
|
||||
auto *GEP = dyn_cast<GEPOperator>(U);
|
||||
if (!GEP || !GEP->getInRangeIndex() || *GEP->getInRangeIndex() != 1 ||
|
||||
!isa<ConstantInt>(GEP->getOperand(1)) ||
|
||||
!cast<ConstantInt>(GEP->getOperand(1))->isZero() ||
|
||||
!isa<ConstantInt>(GEP->getOperand(2)))
|
||||
return false;
|
||||
}
|
||||
|
||||
SmallVector<MDNode *, 2> Types;
|
||||
GV.getMetadata(LLVMContext::MD_type, Types);
|
||||
|
||||
const DataLayout &DL = GV.getParent()->getDataLayout();
|
||||
const StructLayout *SL = DL.getStructLayout(Init->getType());
|
||||
|
||||
IntegerType *Int32Ty = Type::getInt32Ty(GV.getContext());
|
||||
|
||||
std::vector<GlobalVariable *> SplitGlobals(Init->getNumOperands());
|
||||
for (unsigned I = 0; I != Init->getNumOperands(); ++I) {
|
||||
// Build a global representing this split piece.
|
||||
auto *SplitGV =
|
||||
new GlobalVariable(*GV.getParent(), Init->getOperand(I)->getType(),
|
||||
GV.isConstant(), GlobalValue::PrivateLinkage,
|
||||
Init->getOperand(I), GV.getName() + "." + utostr(I));
|
||||
SplitGlobals[I] = SplitGV;
|
||||
|
||||
unsigned SplitBegin = SL->getElementOffset(I);
|
||||
unsigned SplitEnd = (I == Init->getNumOperands() - 1)
|
||||
? SL->getSizeInBytes()
|
||||
: SL->getElementOffset(I + 1);
|
||||
|
||||
// Rebuild type metadata, adjusting by the split offset.
|
||||
// FIXME: See if we can use DW_OP_piece to preserve debug metadata here.
|
||||
for (MDNode *Type : Types) {
|
||||
uint64_t ByteOffset = cast<ConstantInt>(
|
||||
cast<ConstantAsMetadata>(Type->getOperand(0))->getValue())
|
||||
->getZExtValue();
|
||||
// Type metadata may be attached one byte after the end of the vtable, for
|
||||
// classes without virtual methods in Itanium ABI. AFAIK, it is never
|
||||
// attached to the first byte of a vtable. Subtract one to get the right
|
||||
// slice.
|
||||
// This is making an assumption that vtable groups are the only kinds of
|
||||
// global variables that !type metadata can be attached to, and that they
|
||||
// are either Itanium ABI vtable groups or contain a single vtable (i.e.
|
||||
// Microsoft ABI vtables).
|
||||
uint64_t AttachedTo = (ByteOffset == 0) ? ByteOffset : ByteOffset - 1;
|
||||
if (AttachedTo < SplitBegin || AttachedTo >= SplitEnd)
|
||||
continue;
|
||||
SplitGV->addMetadata(
|
||||
LLVMContext::MD_type,
|
||||
*MDNode::get(GV.getContext(),
|
||||
{ConstantAsMetadata::get(
|
||||
ConstantInt::get(Int32Ty, ByteOffset - SplitBegin)),
|
||||
Type->getOperand(1)}));
|
||||
}
|
||||
}
|
||||
|
||||
for (User *U : GV.users()) {
|
||||
auto *GEP = cast<GEPOperator>(U);
|
||||
unsigned I = cast<ConstantInt>(GEP->getOperand(2))->getZExtValue();
|
||||
if (I >= SplitGlobals.size())
|
||||
continue;
|
||||
|
||||
SmallVector<Value *, 4> Ops;
|
||||
Ops.push_back(ConstantInt::get(Int32Ty, 0));
|
||||
for (unsigned I = 3; I != GEP->getNumOperands(); ++I)
|
||||
Ops.push_back(GEP->getOperand(I));
|
||||
|
||||
auto *NewGEP = ConstantExpr::getGetElementPtr(
|
||||
SplitGlobals[I]->getInitializer()->getType(), SplitGlobals[I], Ops,
|
||||
GEP->isInBounds());
|
||||
GEP->replaceAllUsesWith(NewGEP);
|
||||
}
|
||||
|
||||
// Finally, remove the original global. Any remaining uses refer to invalid
|
||||
// elements of the global, so replace with undef.
|
||||
if (!GV.use_empty())
|
||||
GV.replaceAllUsesWith(UndefValue::get(GV.getType()));
|
||||
GV.eraseFromParent();
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool splitGlobals(Module &M) {
|
||||
// First, see if the module uses either of the llvm.type.test or
|
||||
// llvm.type.checked.load intrinsics, which indicates that splitting globals
|
||||
// may be beneficial.
|
||||
Function *TypeTestFunc =
|
||||
M.getFunction(Intrinsic::getName(Intrinsic::type_test));
|
||||
Function *TypeCheckedLoadFunc =
|
||||
M.getFunction(Intrinsic::getName(Intrinsic::type_checked_load));
|
||||
if ((!TypeTestFunc || TypeTestFunc->use_empty()) &&
|
||||
(!TypeCheckedLoadFunc || TypeCheckedLoadFunc->use_empty()))
|
||||
return false;
|
||||
|
||||
bool Changed = false;
|
||||
for (auto I = M.global_begin(); I != M.global_end();) {
|
||||
GlobalVariable &GV = *I;
|
||||
++I;
|
||||
Changed |= splitGlobal(GV);
|
||||
}
|
||||
return Changed;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct GlobalSplit : public ModulePass {
|
||||
static char ID;
|
||||
|
||||
GlobalSplit() : ModulePass(ID) {
|
||||
initializeGlobalSplitPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
bool runOnModule(Module &M) override {
|
||||
if (skipModule(M))
|
||||
return false;
|
||||
|
||||
return splitGlobals(M);
|
||||
}
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
char GlobalSplit::ID = 0;
|
||||
|
||||
INITIALIZE_PASS(GlobalSplit, "globalsplit", "Global splitter", false, false)
|
||||
|
||||
ModulePass *llvm::createGlobalSplitPass() {
|
||||
return new GlobalSplit;
|
||||
}
|
||||
|
||||
PreservedAnalyses GlobalSplitPass::run(Module &M, ModuleAnalysisManager &AM) {
|
||||
if (!splitGlobals(M))
|
||||
return PreservedAnalyses::all();
|
||||
return PreservedAnalyses::none();
|
||||
}
|
@ -1,286 +0,0 @@
|
||||
//===-- IPConstantPropagation.cpp - Propagate constants through calls -----===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This pass implements an _extremely_ simple interprocedural constant
|
||||
// propagation pass. It could certainly be improved in many different ways,
|
||||
// like using a worklist. This pass makes arguments dead, but does not remove
|
||||
// them. The existing dead argument elimination pass should be run after this
|
||||
// to clean up the mess.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/Analysis/ValueTracking.h"
|
||||
#include "llvm/IR/CallSite.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Transforms/IPO.h"
|
||||
using namespace llvm;
|
||||
|
||||
#define DEBUG_TYPE "ipconstprop"
|
||||
|
||||
STATISTIC(NumArgumentsProped, "Number of args turned into constants");
|
||||
STATISTIC(NumReturnValProped, "Number of return values turned into constants");
|
||||
|
||||
namespace {
|
||||
/// IPCP - The interprocedural constant propagation pass
|
||||
///
|
||||
struct IPCP : public ModulePass {
|
||||
static char ID; // Pass identification, replacement for typeid
|
||||
IPCP() : ModulePass(ID) {
|
||||
initializeIPCPPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
bool runOnModule(Module &M) override;
|
||||
};
|
||||
}
|
||||
|
||||
/// PropagateConstantsIntoArguments - Look at all uses of the specified
|
||||
/// function. If all uses are direct call sites, and all pass a particular
|
||||
/// constant in for an argument, propagate that constant in as the argument.
|
||||
///
|
||||
static bool PropagateConstantsIntoArguments(Function &F) {
|
||||
if (F.arg_empty() || F.use_empty()) return false; // No arguments? Early exit.
|
||||
|
||||
// For each argument, keep track of its constant value and whether it is a
|
||||
// constant or not. The bool is driven to true when found to be non-constant.
|
||||
SmallVector<std::pair<Constant*, bool>, 16> ArgumentConstants;
|
||||
ArgumentConstants.resize(F.arg_size());
|
||||
|
||||
unsigned NumNonconstant = 0;
|
||||
for (Use &U : F.uses()) {
|
||||
User *UR = U.getUser();
|
||||
// Ignore blockaddress uses.
|
||||
if (isa<BlockAddress>(UR)) continue;
|
||||
|
||||
// Used by a non-instruction, or not the callee of a function, do not
|
||||
// transform.
|
||||
if (!isa<CallInst>(UR) && !isa<InvokeInst>(UR))
|
||||
return false;
|
||||
|
||||
CallSite CS(cast<Instruction>(UR));
|
||||
if (!CS.isCallee(&U))
|
||||
return false;
|
||||
|
||||
// Check out all of the potentially constant arguments. Note that we don't
|
||||
// inspect varargs here.
|
||||
CallSite::arg_iterator AI = CS.arg_begin();
|
||||
Function::arg_iterator Arg = F.arg_begin();
|
||||
for (unsigned i = 0, e = ArgumentConstants.size(); i != e;
|
||||
++i, ++AI, ++Arg) {
|
||||
|
||||
// If this argument is known non-constant, ignore it.
|
||||
if (ArgumentConstants[i].second)
|
||||
continue;
|
||||
|
||||
Constant *C = dyn_cast<Constant>(*AI);
|
||||
if (C && ArgumentConstants[i].first == nullptr) {
|
||||
ArgumentConstants[i].first = C; // First constant seen.
|
||||
} else if (C && ArgumentConstants[i].first == C) {
|
||||
// Still the constant value we think it is.
|
||||
} else if (*AI == &*Arg) {
|
||||
// Ignore recursive calls passing argument down.
|
||||
} else {
|
||||
// Argument became non-constant. If all arguments are non-constant now,
|
||||
// give up on this function.
|
||||
if (++NumNonconstant == ArgumentConstants.size())
|
||||
return false;
|
||||
ArgumentConstants[i].second = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we got to this point, there is a constant argument!
|
||||
assert(NumNonconstant != ArgumentConstants.size());
|
||||
bool MadeChange = false;
|
||||
Function::arg_iterator AI = F.arg_begin();
|
||||
for (unsigned i = 0, e = ArgumentConstants.size(); i != e; ++i, ++AI) {
|
||||
// Do we have a constant argument?
|
||||
if (ArgumentConstants[i].second || AI->use_empty() ||
|
||||
AI->hasInAllocaAttr() || (AI->hasByValAttr() && !F.onlyReadsMemory()))
|
||||
continue;
|
||||
|
||||
Value *V = ArgumentConstants[i].first;
|
||||
if (!V) V = UndefValue::get(AI->getType());
|
||||
AI->replaceAllUsesWith(V);
|
||||
++NumArgumentsProped;
|
||||
MadeChange = true;
|
||||
}
|
||||
return MadeChange;
|
||||
}
|
||||
|
||||
|
||||
// Check to see if this function returns one or more constants. If so, replace
|
||||
// all callers that use those return values with the constant value. This will
|
||||
// leave in the actual return values and instructions, but deadargelim will
|
||||
// clean that up.
|
||||
//
|
||||
// Additionally if a function always returns one of its arguments directly,
|
||||
// callers will be updated to use the value they pass in directly instead of
|
||||
// using the return value.
|
||||
static bool PropagateConstantReturn(Function &F) {
|
||||
if (F.getReturnType()->isVoidTy())
|
||||
return false; // No return value.
|
||||
|
||||
// We can infer and propagate the return value only when we know that the
|
||||
// definition we'll get at link time is *exactly* the definition we see now.
|
||||
// For more details, see GlobalValue::mayBeDerefined.
|
||||
if (!F.isDefinitionExact())
|
||||
return false;
|
||||
|
||||
// Don't touch naked functions. The may contain asm returning
|
||||
// value we don't see, so we may end up interprocedurally propagating
|
||||
// the return value incorrectly.
|
||||
if (F.hasFnAttribute(Attribute::Naked))
|
||||
return false;
|
||||
|
||||
// Check to see if this function returns a constant.
|
||||
SmallVector<Value *,4> RetVals;
|
||||
StructType *STy = dyn_cast<StructType>(F.getReturnType());
|
||||
if (STy)
|
||||
for (unsigned i = 0, e = STy->getNumElements(); i < e; ++i)
|
||||
RetVals.push_back(UndefValue::get(STy->getElementType(i)));
|
||||
else
|
||||
RetVals.push_back(UndefValue::get(F.getReturnType()));
|
||||
|
||||
unsigned NumNonConstant = 0;
|
||||
for (BasicBlock &BB : F)
|
||||
if (ReturnInst *RI = dyn_cast<ReturnInst>(BB.getTerminator())) {
|
||||
for (unsigned i = 0, e = RetVals.size(); i != e; ++i) {
|
||||
// Already found conflicting return values?
|
||||
Value *RV = RetVals[i];
|
||||
if (!RV)
|
||||
continue;
|
||||
|
||||
// Find the returned value
|
||||
Value *V;
|
||||
if (!STy)
|
||||
V = RI->getOperand(0);
|
||||
else
|
||||
V = FindInsertedValue(RI->getOperand(0), i);
|
||||
|
||||
if (V) {
|
||||
// Ignore undefs, we can change them into anything
|
||||
if (isa<UndefValue>(V))
|
||||
continue;
|
||||
|
||||
// Try to see if all the rets return the same constant or argument.
|
||||
if (isa<Constant>(V) || isa<Argument>(V)) {
|
||||
if (isa<UndefValue>(RV)) {
|
||||
// No value found yet? Try the current one.
|
||||
RetVals[i] = V;
|
||||
continue;
|
||||
}
|
||||
// Returning the same value? Good.
|
||||
if (RV == V)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// Different or no known return value? Don't propagate this return
|
||||
// value.
|
||||
RetVals[i] = nullptr;
|
||||
// All values non-constant? Stop looking.
|
||||
if (++NumNonConstant == RetVals.size())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// If we got here, the function returns at least one constant value. Loop
|
||||
// over all users, replacing any uses of the return value with the returned
|
||||
// constant.
|
||||
bool MadeChange = false;
|
||||
for (Use &U : F.uses()) {
|
||||
CallSite CS(U.getUser());
|
||||
Instruction* Call = CS.getInstruction();
|
||||
|
||||
// Not a call instruction or a call instruction that's not calling F
|
||||
// directly?
|
||||
if (!Call || !CS.isCallee(&U))
|
||||
continue;
|
||||
|
||||
// Call result not used?
|
||||
if (Call->use_empty())
|
||||
continue;
|
||||
|
||||
MadeChange = true;
|
||||
|
||||
if (!STy) {
|
||||
Value* New = RetVals[0];
|
||||
if (Argument *A = dyn_cast<Argument>(New))
|
||||
// Was an argument returned? Then find the corresponding argument in
|
||||
// the call instruction and use that.
|
||||
New = CS.getArgument(A->getArgNo());
|
||||
Call->replaceAllUsesWith(New);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto I = Call->user_begin(), E = Call->user_end(); I != E;) {
|
||||
Instruction *Ins = cast<Instruction>(*I);
|
||||
|
||||
// Increment now, so we can remove the use
|
||||
++I;
|
||||
|
||||
// Find the index of the retval to replace with
|
||||
int index = -1;
|
||||
if (ExtractValueInst *EV = dyn_cast<ExtractValueInst>(Ins))
|
||||
if (EV->hasIndices())
|
||||
index = *EV->idx_begin();
|
||||
|
||||
// If this use uses a specific return value, and we have a replacement,
|
||||
// replace it.
|
||||
if (index != -1) {
|
||||
Value *New = RetVals[index];
|
||||
if (New) {
|
||||
if (Argument *A = dyn_cast<Argument>(New))
|
||||
// Was an argument returned? Then find the corresponding argument in
|
||||
// the call instruction and use that.
|
||||
New = CS.getArgument(A->getArgNo());
|
||||
Ins->replaceAllUsesWith(New);
|
||||
Ins->eraseFromParent();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (MadeChange) ++NumReturnValProped;
|
||||
return MadeChange;
|
||||
}
|
||||
|
||||
char IPCP::ID = 0;
|
||||
INITIALIZE_PASS(IPCP, "ipconstprop",
|
||||
"Interprocedural constant propagation", false, false)
|
||||
|
||||
ModulePass *llvm::createIPConstantPropagationPass() { return new IPCP(); }
|
||||
|
||||
bool IPCP::runOnModule(Module &M) {
|
||||
if (skipModule(M))
|
||||
return false;
|
||||
|
||||
bool Changed = false;
|
||||
bool LocalChange = true;
|
||||
|
||||
// FIXME: instead of using smart algorithms, we just iterate until we stop
|
||||
// making changes.
|
||||
while (LocalChange) {
|
||||
LocalChange = false;
|
||||
for (Function &F : M)
|
||||
if (!F.isDeclaration()) {
|
||||
// Delete any klingons.
|
||||
F.removeDeadConstantUsers();
|
||||
if (F.hasLocalLinkage())
|
||||
LocalChange |= PropagateConstantsIntoArguments(F);
|
||||
Changed |= PropagateConstantReturn(F);
|
||||
}
|
||||
Changed |= LocalChange;
|
||||
}
|
||||
return Changed;
|
||||
}
|
128
external/llvm/lib/Transforms/IPO/IPO.cpp
vendored
128
external/llvm/lib/Transforms/IPO/IPO.cpp
vendored
@ -1,128 +0,0 @@
|
||||
//===-- IPO.cpp -----------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the common infrastructure (including C bindings) for
|
||||
// libLLVMIPO.a, which implements several transformations over the LLVM
|
||||
// intermediate representation.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm-c/Transforms/IPO.h"
|
||||
#include "llvm-c/Initialization.h"
|
||||
#include "llvm/IR/LegacyPassManager.h"
|
||||
#include "llvm/InitializePasses.h"
|
||||
#include "llvm/Transforms/IPO.h"
|
||||
#include "llvm/Transforms/IPO/AlwaysInliner.h"
|
||||
#include "llvm/Transforms/IPO/FunctionAttrs.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
void llvm::initializeIPO(PassRegistry &Registry) {
|
||||
initializeArgPromotionPass(Registry);
|
||||
initializeCalledValuePropagationLegacyPassPass(Registry);
|
||||
initializeConstantMergeLegacyPassPass(Registry);
|
||||
initializeCrossDSOCFIPass(Registry);
|
||||
initializeDAEPass(Registry);
|
||||
initializeDAHPass(Registry);
|
||||
initializeForceFunctionAttrsLegacyPassPass(Registry);
|
||||
initializeGlobalDCELegacyPassPass(Registry);
|
||||
initializeGlobalOptLegacyPassPass(Registry);
|
||||
initializeGlobalSplitPass(Registry);
|
||||
initializeIPCPPass(Registry);
|
||||
initializeAlwaysInlinerLegacyPassPass(Registry);
|
||||
initializeSimpleInlinerPass(Registry);
|
||||
initializeInferFunctionAttrsLegacyPassPass(Registry);
|
||||
initializeInternalizeLegacyPassPass(Registry);
|
||||
initializeLoopExtractorPass(Registry);
|
||||
initializeBlockExtractorPassPass(Registry);
|
||||
initializeSingleLoopExtractorPass(Registry);
|
||||
initializeLowerTypeTestsPass(Registry);
|
||||
initializeMergeFunctionsPass(Registry);
|
||||
initializePartialInlinerLegacyPassPass(Registry);
|
||||
initializePostOrderFunctionAttrsLegacyPassPass(Registry);
|
||||
initializeReversePostOrderFunctionAttrsLegacyPassPass(Registry);
|
||||
initializePruneEHPass(Registry);
|
||||
initializeStripDeadPrototypesLegacyPassPass(Registry);
|
||||
initializeStripSymbolsPass(Registry);
|
||||
initializeStripDebugDeclarePass(Registry);
|
||||
initializeStripDeadDebugInfoPass(Registry);
|
||||
initializeStripNonDebugSymbolsPass(Registry);
|
||||
initializeBarrierNoopPass(Registry);
|
||||
initializeEliminateAvailableExternallyLegacyPassPass(Registry);
|
||||
initializeSampleProfileLoaderLegacyPassPass(Registry);
|
||||
initializeFunctionImportLegacyPassPass(Registry);
|
||||
initializeWholeProgramDevirtPass(Registry);
|
||||
}
|
||||
|
||||
void LLVMInitializeIPO(LLVMPassRegistryRef R) {
|
||||
initializeIPO(*unwrap(R));
|
||||
}
|
||||
|
||||
void LLVMAddArgumentPromotionPass(LLVMPassManagerRef PM) {
|
||||
unwrap(PM)->add(createArgumentPromotionPass());
|
||||
}
|
||||
|
||||
void LLVMAddCalledValuePropagationPass(LLVMPassManagerRef PM) {
|
||||
unwrap(PM)->add(createCalledValuePropagationPass());
|
||||
}
|
||||
|
||||
void LLVMAddConstantMergePass(LLVMPassManagerRef PM) {
|
||||
unwrap(PM)->add(createConstantMergePass());
|
||||
}
|
||||
|
||||
void LLVMAddDeadArgEliminationPass(LLVMPassManagerRef PM) {
|
||||
unwrap(PM)->add(createDeadArgEliminationPass());
|
||||
}
|
||||
|
||||
void LLVMAddFunctionAttrsPass(LLVMPassManagerRef PM) {
|
||||
unwrap(PM)->add(createPostOrderFunctionAttrsLegacyPass());
|
||||
}
|
||||
|
||||
void LLVMAddFunctionInliningPass(LLVMPassManagerRef PM) {
|
||||
unwrap(PM)->add(createFunctionInliningPass());
|
||||
}
|
||||
|
||||
void LLVMAddAlwaysInlinerPass(LLVMPassManagerRef PM) {
|
||||
unwrap(PM)->add(llvm::createAlwaysInlinerLegacyPass());
|
||||
}
|
||||
|
||||
void LLVMAddGlobalDCEPass(LLVMPassManagerRef PM) {
|
||||
unwrap(PM)->add(createGlobalDCEPass());
|
||||
}
|
||||
|
||||
void LLVMAddGlobalOptimizerPass(LLVMPassManagerRef PM) {
|
||||
unwrap(PM)->add(createGlobalOptimizerPass());
|
||||
}
|
||||
|
||||
void LLVMAddIPConstantPropagationPass(LLVMPassManagerRef PM) {
|
||||
unwrap(PM)->add(createIPConstantPropagationPass());
|
||||
}
|
||||
|
||||
void LLVMAddPruneEHPass(LLVMPassManagerRef PM) {
|
||||
unwrap(PM)->add(createPruneEHPass());
|
||||
}
|
||||
|
||||
void LLVMAddIPSCCPPass(LLVMPassManagerRef PM) {
|
||||
unwrap(PM)->add(createIPSCCPPass());
|
||||
}
|
||||
|
||||
void LLVMAddInternalizePass(LLVMPassManagerRef PM, unsigned AllButMain) {
|
||||
auto PreserveMain = [=](const GlobalValue &GV) {
|
||||
return AllButMain && GV.getName() == "main";
|
||||
};
|
||||
unwrap(PM)->add(createInternalizePass(PreserveMain));
|
||||
}
|
||||
|
||||
void LLVMAddStripDeadPrototypesPass(LLVMPassManagerRef PM) {
|
||||
unwrap(PM)->add(createStripDeadPrototypesPass());
|
||||
}
|
||||
|
||||
void LLVMAddStripSymbolsPass(LLVMPassManagerRef PM) {
|
||||
unwrap(PM)->add(createStripSymbolsPass());
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
//===- InferFunctionAttrs.cpp - Infer implicit function attributes --------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Transforms/IPO/InferFunctionAttrs.h"
|
||||
#include "llvm/Analysis/TargetLibraryInfo.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/LLVMContext.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Transforms/Utils/BuildLibCalls.h"
|
||||
using namespace llvm;
|
||||
|
||||
#define DEBUG_TYPE "inferattrs"
|
||||
|
||||
static bool inferAllPrototypeAttributes(Module &M,
|
||||
const TargetLibraryInfo &TLI) {
|
||||
bool Changed = false;
|
||||
|
||||
for (Function &F : M.functions())
|
||||
// We only infer things using the prototype and the name; we don't need
|
||||
// definitions.
|
||||
if (F.isDeclaration() && !F.hasFnAttribute((Attribute::OptimizeNone)))
|
||||
Changed |= inferLibFuncAttributes(F, TLI);
|
||||
|
||||
return Changed;
|
||||
}
|
||||
|
||||
PreservedAnalyses InferFunctionAttrsPass::run(Module &M,
|
||||
ModuleAnalysisManager &AM) {
|
||||
auto &TLI = AM.getResult<TargetLibraryAnalysis>(M);
|
||||
|
||||
if (!inferAllPrototypeAttributes(M, TLI))
|
||||
// If we didn't infer anything, preserve all analyses.
|
||||
return PreservedAnalyses::all();
|
||||
|
||||
// Otherwise, we may have changed fundamental function attributes, so clear
|
||||
// out all the passes.
|
||||
return PreservedAnalyses::none();
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct InferFunctionAttrsLegacyPass : public ModulePass {
|
||||
static char ID; // Pass identification, replacement for typeid
|
||||
InferFunctionAttrsLegacyPass() : ModulePass(ID) {
|
||||
initializeInferFunctionAttrsLegacyPassPass(
|
||||
*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
||||
AU.addRequired<TargetLibraryInfoWrapperPass>();
|
||||
}
|
||||
|
||||
bool runOnModule(Module &M) override {
|
||||
if (skipModule(M))
|
||||
return false;
|
||||
|
||||
auto &TLI = getAnalysis<TargetLibraryInfoWrapperPass>().getTLI();
|
||||
return inferAllPrototypeAttributes(M, TLI);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
char InferFunctionAttrsLegacyPass::ID = 0;
|
||||
INITIALIZE_PASS_BEGIN(InferFunctionAttrsLegacyPass, "inferattrs",
|
||||
"Infer set function attributes", false, false)
|
||||
INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
|
||||
INITIALIZE_PASS_END(InferFunctionAttrsLegacyPass, "inferattrs",
|
||||
"Infer set function attributes", false, false)
|
||||
|
||||
Pass *llvm::createInferFunctionAttrsLegacyPass() {
|
||||
return new InferFunctionAttrsLegacyPass();
|
||||
}
|
125
external/llvm/lib/Transforms/IPO/InlineSimple.cpp
vendored
125
external/llvm/lib/Transforms/IPO/InlineSimple.cpp
vendored
@ -1,125 +0,0 @@
|
||||
//===- InlineSimple.cpp - Code to perform simple function inlining --------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements bottom-up inlining of functions into callees.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Analysis/AssumptionCache.h"
|
||||
#include "llvm/Analysis/InlineCost.h"
|
||||
#include "llvm/Analysis/ProfileSummaryInfo.h"
|
||||
#include "llvm/Analysis/TargetLibraryInfo.h"
|
||||
#include "llvm/Analysis/TargetTransformInfo.h"
|
||||
#include "llvm/IR/CallSite.h"
|
||||
#include "llvm/IR/CallingConv.h"
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/IR/Type.h"
|
||||
#include "llvm/Transforms/IPO.h"
|
||||
#include "llvm/Transforms/IPO/Inliner.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
#define DEBUG_TYPE "inline"
|
||||
|
||||
namespace {
|
||||
|
||||
/// \brief Actual inliner pass implementation.
|
||||
///
|
||||
/// The common implementation of the inlining logic is shared between this
|
||||
/// inliner pass and the always inliner pass. The two passes use different cost
|
||||
/// analyses to determine when to inline.
|
||||
class SimpleInliner : public LegacyInlinerBase {
|
||||
|
||||
InlineParams Params;
|
||||
|
||||
public:
|
||||
SimpleInliner() : LegacyInlinerBase(ID), Params(llvm::getInlineParams()) {
|
||||
initializeSimpleInlinerPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
explicit SimpleInliner(InlineParams Params)
|
||||
: LegacyInlinerBase(ID), Params(std::move(Params)) {
|
||||
initializeSimpleInlinerPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
static char ID; // Pass identification, replacement for typeid
|
||||
|
||||
InlineCost getInlineCost(CallSite CS) override {
|
||||
Function *Callee = CS.getCalledFunction();
|
||||
TargetTransformInfo &TTI = TTIWP->getTTI(*Callee);
|
||||
|
||||
bool RemarksEnabled = false;
|
||||
const auto &BBs = CS.getCaller()->getBasicBlockList();
|
||||
if (!BBs.empty()) {
|
||||
auto DI = OptimizationRemark(DEBUG_TYPE, "", DebugLoc(), &BBs.front());
|
||||
if (DI.isEnabled())
|
||||
RemarksEnabled = true;
|
||||
}
|
||||
OptimizationRemarkEmitter ORE(CS.getCaller());
|
||||
|
||||
std::function<AssumptionCache &(Function &)> GetAssumptionCache =
|
||||
[&](Function &F) -> AssumptionCache & {
|
||||
return ACT->getAssumptionCache(F);
|
||||
};
|
||||
return llvm::getInlineCost(CS, Params, TTI, GetAssumptionCache,
|
||||
/*GetBFI=*/None, PSI,
|
||||
RemarksEnabled ? &ORE : nullptr);
|
||||
}
|
||||
|
||||
bool runOnSCC(CallGraphSCC &SCC) override;
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
|
||||
private:
|
||||
TargetTransformInfoWrapperPass *TTIWP;
|
||||
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
char SimpleInliner::ID = 0;
|
||||
INITIALIZE_PASS_BEGIN(SimpleInliner, "inline", "Function Integration/Inlining",
|
||||
false, false)
|
||||
INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
|
||||
INITIALIZE_PASS_DEPENDENCY(CallGraphWrapperPass)
|
||||
INITIALIZE_PASS_DEPENDENCY(ProfileSummaryInfoWrapperPass)
|
||||
INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)
|
||||
INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
|
||||
INITIALIZE_PASS_END(SimpleInliner, "inline", "Function Integration/Inlining",
|
||||
false, false)
|
||||
|
||||
Pass *llvm::createFunctionInliningPass() { return new SimpleInliner(); }
|
||||
|
||||
Pass *llvm::createFunctionInliningPass(int Threshold) {
|
||||
return new SimpleInliner(llvm::getInlineParams(Threshold));
|
||||
}
|
||||
|
||||
Pass *llvm::createFunctionInliningPass(unsigned OptLevel,
|
||||
unsigned SizeOptLevel,
|
||||
bool DisableInlineHotCallSite) {
|
||||
auto Param = llvm::getInlineParams(OptLevel, SizeOptLevel);
|
||||
if (DisableInlineHotCallSite)
|
||||
Param.HotCallSiteThreshold = 0;
|
||||
return new SimpleInliner(Param);
|
||||
}
|
||||
|
||||
Pass *llvm::createFunctionInliningPass(InlineParams &Params) {
|
||||
return new SimpleInliner(Params);
|
||||
}
|
||||
|
||||
bool SimpleInliner::runOnSCC(CallGraphSCC &SCC) {
|
||||
TTIWP = &getAnalysis<TargetTransformInfoWrapperPass>();
|
||||
return LegacyInlinerBase::runOnSCC(SCC);
|
||||
}
|
||||
|
||||
void SimpleInliner::getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.addRequired<TargetTransformInfoWrapperPass>();
|
||||
LegacyInlinerBase::getAnalysisUsage(AU);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user