|
|
|
@ -23,13 +23,12 @@
|
|
|
|
|
///
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
|
|
#include "llvm/Transforms/Scalar.h"
|
|
|
|
|
#include "llvm/Transforms/Scalar/SROA.h"
|
|
|
|
|
#include "llvm/ADT/STLExtras.h"
|
|
|
|
|
#include "llvm/ADT/SetVector.h"
|
|
|
|
|
#include "llvm/ADT/SmallVector.h"
|
|
|
|
|
#include "llvm/ADT/Statistic.h"
|
|
|
|
|
#include "llvm/Analysis/GlobalsModRef.h"
|
|
|
|
|
#include "llvm/Analysis/AssumptionCache.h"
|
|
|
|
|
#include "llvm/Analysis/GlobalsModRef.h"
|
|
|
|
|
#include "llvm/Analysis/Loads.h"
|
|
|
|
|
#include "llvm/Analysis/PtrUseVisitor.h"
|
|
|
|
|
#include "llvm/Analysis/ValueTracking.h"
|
|
|
|
@ -38,8 +37,6 @@
|
|
|
|
|
#include "llvm/IR/DataLayout.h"
|
|
|
|
|
#include "llvm/IR/DebugInfo.h"
|
|
|
|
|
#include "llvm/IR/DerivedTypes.h"
|
|
|
|
|
#include "llvm/IR/Dominators.h"
|
|
|
|
|
#include "llvm/IR/Function.h"
|
|
|
|
|
#include "llvm/IR/IRBuilder.h"
|
|
|
|
|
#include "llvm/IR/InstVisitor.h"
|
|
|
|
|
#include "llvm/IR/Instructions.h"
|
|
|
|
@ -54,6 +51,7 @@
|
|
|
|
|
#include "llvm/Support/MathExtras.h"
|
|
|
|
|
#include "llvm/Support/TimeValue.h"
|
|
|
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
|
#include "llvm/Transforms/Scalar.h"
|
|
|
|
|
#include "llvm/Transforms/Utils/Local.h"
|
|
|
|
|
#include "llvm/Transforms/Utils/PromoteMemToReg.h"
|
|
|
|
|
|
|
|
|
@ -63,6 +61,7 @@
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
|
using namespace llvm::sroa;
|
|
|
|
|
|
|
|
|
|
#define DEBUG_TYPE "sroa"
|
|
|
|
|
|
|
|
|
@ -200,7 +199,6 @@ template <typename T> struct isPodLike;
|
|
|
|
|
template <> struct isPodLike<Slice> { static const bool value = true; };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
/// \brief Representation of the alloca slices.
|
|
|
|
|
///
|
|
|
|
|
/// This class represents the slices of an alloca which are formed by its
|
|
|
|
@ -208,7 +206,7 @@ namespace {
|
|
|
|
|
/// for the slices used and we reflect that in this structure. The uses are
|
|
|
|
|
/// stored, sorted by increasing beginning offset and with unsplittable slices
|
|
|
|
|
/// starting at a particular offset before splittable slices.
|
|
|
|
|
class AllocaSlices {
|
|
|
|
|
class llvm::sroa::AllocaSlices {
|
|
|
|
|
public:
|
|
|
|
|
/// \brief Construct the slices of a particular alloca.
|
|
|
|
|
AllocaSlices(const DataLayout &DL, AllocaInst &AI);
|
|
|
|
@ -248,8 +246,77 @@ public:
|
|
|
|
|
std::inplace_merge(Slices.begin(), SliceI, Slices.end());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Forward declare an iterator to befriend it.
|
|
|
|
|
// Forward declare the iterator and range accessor for walking the
|
|
|
|
|
// partitions.
|
|
|
|
|
class partition_iterator;
|
|
|
|
|
iterator_range<partition_iterator> partitions();
|
|
|
|
|
|
|
|
|
|
/// \brief Access the dead users for this alloca.
|
|
|
|
|
ArrayRef<Instruction *> getDeadUsers() const { return DeadUsers; }
|
|
|
|
|
|
|
|
|
|
/// \brief Access the dead operands referring to this alloca.
|
|
|
|
|
///
|
|
|
|
|
/// These are operands which have cannot actually be used to refer to the
|
|
|
|
|
/// alloca as they are outside its range and the user doesn't correct for
|
|
|
|
|
/// that. These mostly consist of PHI node inputs and the like which we just
|
|
|
|
|
/// need to replace with undef.
|
|
|
|
|
ArrayRef<Use *> getDeadOperands() const { return DeadOperands; }
|
|
|
|
|
|
|
|
|
|
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
|
|
|
|
void print(raw_ostream &OS, const_iterator I, StringRef Indent = " ") const;
|
|
|
|
|
void printSlice(raw_ostream &OS, const_iterator I,
|
|
|
|
|
StringRef Indent = " ") const;
|
|
|
|
|
void printUse(raw_ostream &OS, const_iterator I,
|
|
|
|
|
StringRef Indent = " ") const;
|
|
|
|
|
void print(raw_ostream &OS) const;
|
|
|
|
|
void dump(const_iterator I) const;
|
|
|
|
|
void dump() const;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
template <typename DerivedT, typename RetT = void> class BuilderBase;
|
|
|
|
|
class SliceBuilder;
|
|
|
|
|
friend class AllocaSlices::SliceBuilder;
|
|
|
|
|
|
|
|
|
|
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
|
|
|
|
/// \brief Handle to alloca instruction to simplify method interfaces.
|
|
|
|
|
AllocaInst &AI;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/// \brief The instruction responsible for this alloca not having a known set
|
|
|
|
|
/// of slices.
|
|
|
|
|
///
|
|
|
|
|
/// When an instruction (potentially) escapes the pointer to the alloca, we
|
|
|
|
|
/// store a pointer to that here and abort trying to form slices of the
|
|
|
|
|
/// alloca. This will be null if the alloca slices are analyzed successfully.
|
|
|
|
|
Instruction *PointerEscapingInstr;
|
|
|
|
|
|
|
|
|
|
/// \brief The slices of the alloca.
|
|
|
|
|
///
|
|
|
|
|
/// We store a vector of the slices formed by uses of the alloca here. This
|
|
|
|
|
/// vector is sorted by increasing begin offset, and then the unsplittable
|
|
|
|
|
/// slices before the splittable ones. See the Slice inner class for more
|
|
|
|
|
/// details.
|
|
|
|
|
SmallVector<Slice, 8> Slices;
|
|
|
|
|
|
|
|
|
|
/// \brief Instructions which will become dead if we rewrite the alloca.
|
|
|
|
|
///
|
|
|
|
|
/// Note that these are not separated by slice. This is because we expect an
|
|
|
|
|
/// alloca to be completely rewritten or not rewritten at all. If rewritten,
|
|
|
|
|
/// all these instructions can simply be removed and replaced with undef as
|
|
|
|
|
/// they come from outside of the allocated space.
|
|
|
|
|
SmallVector<Instruction *, 8> DeadUsers;
|
|
|
|
|
|
|
|
|
|
/// \brief Operands which will become dead if we rewrite the alloca.
|
|
|
|
|
///
|
|
|
|
|
/// These are operands that in their particular use can be replaced with
|
|
|
|
|
/// undef when we rewrite the alloca. These show up in out-of-bounds inputs
|
|
|
|
|
/// to PHI nodes and the like. They aren't entirely dead (there might be
|
|
|
|
|
/// a GEP back into the bounds using it elsewhere) and nor is the PHI, but we
|
|
|
|
|
/// want to swap this particular input for undef to simplify the use lists of
|
|
|
|
|
/// the alloca.
|
|
|
|
|
SmallVector<Use *, 8> DeadOperands;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/// \brief A partition of the slices.
|
|
|
|
|
///
|
|
|
|
@ -260,11 +327,13 @@ public:
|
|
|
|
|
///
|
|
|
|
|
/// Objects of this type are produced by traversing the alloca's slices, but
|
|
|
|
|
/// are only ephemeral and not persistent.
|
|
|
|
|
class Partition {
|
|
|
|
|
class llvm::sroa::Partition {
|
|
|
|
|
private:
|
|
|
|
|
friend class AllocaSlices;
|
|
|
|
|
friend class AllocaSlices::partition_iterator;
|
|
|
|
|
|
|
|
|
|
typedef AllocaSlices::iterator iterator;
|
|
|
|
|
|
|
|
|
|
/// \brief The beginning and ending offsets of the alloca for this
|
|
|
|
|
/// partition.
|
|
|
|
|
uint64_t BeginOffset, EndOffset;
|
|
|
|
@ -332,9 +401,9 @@ public:
|
|
|
|
|
///
|
|
|
|
|
/// It is templated on the slice iterator type to use so that it can operate
|
|
|
|
|
/// with either const or non-const slice iterators.
|
|
|
|
|
class partition_iterator
|
|
|
|
|
: public iterator_facade_base<partition_iterator,
|
|
|
|
|
std::forward_iterator_tag, Partition> {
|
|
|
|
|
class AllocaSlices::partition_iterator
|
|
|
|
|
: public iterator_facade_base<partition_iterator, std::forward_iterator_tag,
|
|
|
|
|
Partition> {
|
|
|
|
|
friend class AllocaSlices;
|
|
|
|
|
|
|
|
|
|
/// \brief Most of the state for walking the partitions is held in a class
|
|
|
|
@ -493,8 +562,7 @@ public:
|
|
|
|
|
// P.SI == SE, as the end iterator will additionally have an empty split
|
|
|
|
|
// slices list, but the prior may have the same P.SI and a tail of split
|
|
|
|
|
// slices.
|
|
|
|
|
if (P.SI == RHS.P.SI &&
|
|
|
|
|
P.SplitTails.empty() == RHS.P.SplitTails.empty()) {
|
|
|
|
|
if (P.SI == RHS.P.SI && P.SplitTails.empty() == RHS.P.SplitTails.empty()) {
|
|
|
|
|
assert(P.SJ == RHS.P.SJ &&
|
|
|
|
|
"Same set of slices formed two different sized partitions!");
|
|
|
|
|
assert(P.SplitTails.size() == RHS.P.SplitTails.size() &&
|
|
|
|
@ -520,79 +588,11 @@ public:
|
|
|
|
|
/// offsets of the slices and the ability to split them. It will visit "empty"
|
|
|
|
|
/// partitions to cover regions of the alloca only accessed via split
|
|
|
|
|
/// slices.
|
|
|
|
|
iterator_range<partition_iterator> partitions() {
|
|
|
|
|
iterator_range<AllocaSlices::partition_iterator> AllocaSlices::partitions() {
|
|
|
|
|
return make_range(partition_iterator(begin(), end()),
|
|
|
|
|
partition_iterator(end(), end()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// \brief Access the dead users for this alloca.
|
|
|
|
|
ArrayRef<Instruction *> getDeadUsers() const { return DeadUsers; }
|
|
|
|
|
|
|
|
|
|
/// \brief Access the dead operands referring to this alloca.
|
|
|
|
|
///
|
|
|
|
|
/// These are operands which have cannot actually be used to refer to the
|
|
|
|
|
/// alloca as they are outside its range and the user doesn't correct for
|
|
|
|
|
/// that. These mostly consist of PHI node inputs and the like which we just
|
|
|
|
|
/// need to replace with undef.
|
|
|
|
|
ArrayRef<Use *> getDeadOperands() const { return DeadOperands; }
|
|
|
|
|
|
|
|
|
|
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
|
|
|
|
void print(raw_ostream &OS, const_iterator I, StringRef Indent = " ") const;
|
|
|
|
|
void printSlice(raw_ostream &OS, const_iterator I,
|
|
|
|
|
StringRef Indent = " ") const;
|
|
|
|
|
void printUse(raw_ostream &OS, const_iterator I,
|
|
|
|
|
StringRef Indent = " ") const;
|
|
|
|
|
void print(raw_ostream &OS) const;
|
|
|
|
|
void dump(const_iterator I) const;
|
|
|
|
|
void dump() const;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
template <typename DerivedT, typename RetT = void> class BuilderBase;
|
|
|
|
|
class SliceBuilder;
|
|
|
|
|
friend class AllocaSlices::SliceBuilder;
|
|
|
|
|
|
|
|
|
|
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
|
|
|
|
/// \brief Handle to alloca instruction to simplify method interfaces.
|
|
|
|
|
AllocaInst &AI;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/// \brief The instruction responsible for this alloca not having a known set
|
|
|
|
|
/// of slices.
|
|
|
|
|
///
|
|
|
|
|
/// When an instruction (potentially) escapes the pointer to the alloca, we
|
|
|
|
|
/// store a pointer to that here and abort trying to form slices of the
|
|
|
|
|
/// alloca. This will be null if the alloca slices are analyzed successfully.
|
|
|
|
|
Instruction *PointerEscapingInstr;
|
|
|
|
|
|
|
|
|
|
/// \brief The slices of the alloca.
|
|
|
|
|
///
|
|
|
|
|
/// We store a vector of the slices formed by uses of the alloca here. This
|
|
|
|
|
/// vector is sorted by increasing begin offset, and then the unsplittable
|
|
|
|
|
/// slices before the splittable ones. See the Slice inner class for more
|
|
|
|
|
/// details.
|
|
|
|
|
SmallVector<Slice, 8> Slices;
|
|
|
|
|
|
|
|
|
|
/// \brief Instructions which will become dead if we rewrite the alloca.
|
|
|
|
|
///
|
|
|
|
|
/// Note that these are not separated by slice. This is because we expect an
|
|
|
|
|
/// alloca to be completely rewritten or not rewritten at all. If rewritten,
|
|
|
|
|
/// all these instructions can simply be removed and replaced with undef as
|
|
|
|
|
/// they come from outside of the allocated space.
|
|
|
|
|
SmallVector<Instruction *, 8> DeadUsers;
|
|
|
|
|
|
|
|
|
|
/// \brief Operands which will become dead if we rewrite the alloca.
|
|
|
|
|
///
|
|
|
|
|
/// These are operands that in their particular use can be replaced with
|
|
|
|
|
/// undef when we rewrite the alloca. These show up in out-of-bounds inputs
|
|
|
|
|
/// to PHI nodes and the like. They aren't entirely dead (there might be
|
|
|
|
|
/// a GEP back into the bounds using it elsewhere) and nor is the PHI, but we
|
|
|
|
|
/// want to swap this particular input for undef to simplify the use lists of
|
|
|
|
|
/// the alloca.
|
|
|
|
|
SmallVector<Use *, 8> DeadOperands;
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static Value *foldSelectInst(SelectInst &SI) {
|
|
|
|
|
// If the condition being selected on is a constant or the same value is
|
|
|
|
|
// being selected between, fold the select. Yes this does (rarely) happen
|
|
|
|
@ -1068,110 +1068,6 @@ LLVM_DUMP_METHOD void AllocaSlices::dump() const { print(dbgs()); }
|
|
|
|
|
|
|
|
|
|
#endif // !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
/// \brief An optimization pass providing Scalar Replacement of Aggregates.
|
|
|
|
|
///
|
|
|
|
|
/// This pass takes allocations which can be completely analyzed (that is, they
|
|
|
|
|
/// don't escape) and tries to turn them into scalar SSA values. There are
|
|
|
|
|
/// a few steps to this process.
|
|
|
|
|
///
|
|
|
|
|
/// 1) It takes allocations of aggregates and analyzes the ways in which they
|
|
|
|
|
/// are used to try to split them into smaller allocations, ideally of
|
|
|
|
|
/// a single scalar data type. It will split up memcpy and memset accesses
|
|
|
|
|
/// as necessary and try to isolate individual scalar accesses.
|
|
|
|
|
/// 2) It will transform accesses into forms which are suitable for SSA value
|
|
|
|
|
/// promotion. This can be replacing a memset with a scalar store of an
|
|
|
|
|
/// integer value, or it can involve speculating operations on a PHI or
|
|
|
|
|
/// select to be a PHI or select of the results.
|
|
|
|
|
/// 3) Finally, this will try to detect a pattern of accesses which map cleanly
|
|
|
|
|
/// onto insert and extract operations on a vector value, and convert them to
|
|
|
|
|
/// this form. By doing so, it will enable promotion of vector aggregates to
|
|
|
|
|
/// SSA vector values.
|
|
|
|
|
class SROA : public FunctionPass {
|
|
|
|
|
LLVMContext *C;
|
|
|
|
|
DominatorTree *DT;
|
|
|
|
|
AssumptionCache *AC;
|
|
|
|
|
|
|
|
|
|
/// \brief Worklist of alloca instructions to simplify.
|
|
|
|
|
///
|
|
|
|
|
/// Each alloca in the function is added to this. Each new alloca formed gets
|
|
|
|
|
/// added to it as well to recursively simplify unless that alloca can be
|
|
|
|
|
/// directly promoted. Finally, each time we rewrite a use of an alloca other
|
|
|
|
|
/// the one being actively rewritten, we add it back onto the list if not
|
|
|
|
|
/// already present to ensure it is re-visited.
|
|
|
|
|
SetVector<AllocaInst *, SmallVector<AllocaInst *, 16>> Worklist;
|
|
|
|
|
|
|
|
|
|
/// \brief A collection of instructions to delete.
|
|
|
|
|
/// We try to batch deletions to simplify code and make things a bit more
|
|
|
|
|
/// efficient.
|
|
|
|
|
SetVector<Instruction *, SmallVector<Instruction *, 8>> DeadInsts;
|
|
|
|
|
|
|
|
|
|
/// \brief Post-promotion worklist.
|
|
|
|
|
///
|
|
|
|
|
/// Sometimes we discover an alloca which has a high probability of becoming
|
|
|
|
|
/// viable for SROA after a round of promotion takes place. In those cases,
|
|
|
|
|
/// the alloca is enqueued here for re-processing.
|
|
|
|
|
///
|
|
|
|
|
/// Note that we have to be very careful to clear allocas out of this list in
|
|
|
|
|
/// the event they are deleted.
|
|
|
|
|
SetVector<AllocaInst *, SmallVector<AllocaInst *, 16>> PostPromotionWorklist;
|
|
|
|
|
|
|
|
|
|
/// \brief A collection of alloca instructions we can directly promote.
|
|
|
|
|
std::vector<AllocaInst *> PromotableAllocas;
|
|
|
|
|
|
|
|
|
|
/// \brief A worklist of PHIs to speculate prior to promoting allocas.
|
|
|
|
|
///
|
|
|
|
|
/// All of these PHIs have been checked for the safety of speculation and by
|
|
|
|
|
/// being speculated will allow promoting allocas currently in the promotable
|
|
|
|
|
/// queue.
|
|
|
|
|
SetVector<PHINode *, SmallVector<PHINode *, 2>> SpeculatablePHIs;
|
|
|
|
|
|
|
|
|
|
/// \brief A worklist of select instructions to speculate prior to promoting
|
|
|
|
|
/// allocas.
|
|
|
|
|
///
|
|
|
|
|
/// All of these select instructions have been checked for the safety of
|
|
|
|
|
/// speculation and by being speculated will allow promoting allocas
|
|
|
|
|
/// currently in the promotable queue.
|
|
|
|
|
SetVector<SelectInst *, SmallVector<SelectInst *, 2>> SpeculatableSelects;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
SROA() : FunctionPass(ID), C(nullptr), DT(nullptr) {
|
|
|
|
|
initializeSROAPass(*PassRegistry::getPassRegistry());
|
|
|
|
|
}
|
|
|
|
|
bool runOnFunction(Function &F) override;
|
|
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
|
|
|
|
|
|
|
|
|
const char *getPassName() const override { return "SROA"; }
|
|
|
|
|
static char ID;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
friend class PHIOrSelectSpeculator;
|
|
|
|
|
friend class AllocaSliceRewriter;
|
|
|
|
|
|
|
|
|
|
bool presplitLoadsAndStores(AllocaInst &AI, AllocaSlices &AS);
|
|
|
|
|
AllocaInst *rewritePartition(AllocaInst &AI, AllocaSlices &AS,
|
|
|
|
|
AllocaSlices::Partition &P);
|
|
|
|
|
bool splitAlloca(AllocaInst &AI, AllocaSlices &AS);
|
|
|
|
|
bool runOnAlloca(AllocaInst &AI);
|
|
|
|
|
void clobberUse(Use &U);
|
|
|
|
|
void deleteDeadInstructions(SmallPtrSetImpl<AllocaInst *> &DeletedAllocas);
|
|
|
|
|
bool promoteAllocas(Function &F);
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char SROA::ID = 0;
|
|
|
|
|
|
|
|
|
|
FunctionPass *llvm::createSROAPass() {
|
|
|
|
|
return new SROA();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
INITIALIZE_PASS_BEGIN(SROA, "sroa", "Scalar Replacement Of Aggregates", false,
|
|
|
|
|
false)
|
|
|
|
|
INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
|
|
|
|
|
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
|
|
|
|
|
INITIALIZE_PASS_END(SROA, "sroa", "Scalar Replacement Of Aggregates", false,
|
|
|
|
|
false)
|
|
|
|
|
|
|
|
|
|
/// Walk the range of a partitioning looking for a common type to cover this
|
|
|
|
|
/// sequence of slices.
|
|
|
|
|
static Type *findCommonType(AllocaSlices::const_iterator B,
|
|
|
|
@ -1825,8 +1721,8 @@ static Value *convertValue(const DataLayout &DL, IRBuilderTy &IRB, Value *V,
|
|
|
|
|
///
|
|
|
|
|
/// This function is called to test each entry in a partition which is slated
|
|
|
|
|
/// for a single slice.
|
|
|
|
|
static bool isVectorPromotionViableForSlice(AllocaSlices::Partition &P,
|
|
|
|
|
const Slice &S, VectorType *Ty,
|
|
|
|
|
static bool isVectorPromotionViableForSlice(Partition &P, const Slice &S,
|
|
|
|
|
VectorType *Ty,
|
|
|
|
|
uint64_t ElementSize,
|
|
|
|
|
const DataLayout &DL) {
|
|
|
|
|
// First validate the slice offsets.
|
|
|
|
@ -1901,8 +1797,7 @@ static bool isVectorPromotionViableForSlice(AllocaSlices::Partition &P,
|
|
|
|
|
/// SSA value. We only can ensure this for a limited set of operations, and we
|
|
|
|
|
/// don't want to do the rewrites unless we are confident that the result will
|
|
|
|
|
/// be promotable, so we have an early test here.
|
|
|
|
|
static VectorType *isVectorPromotionViable(AllocaSlices::Partition &P,
|
|
|
|
|
const DataLayout &DL) {
|
|
|
|
|
static VectorType *isVectorPromotionViable(Partition &P, const DataLayout &DL) {
|
|
|
|
|
// Collect the candidate types for vector-based promotion. Also track whether
|
|
|
|
|
// we have different element types.
|
|
|
|
|
SmallVector<VectorType *, 4> CandidateTys;
|
|
|
|
@ -2088,7 +1983,7 @@ static bool isIntegerWideningViableForSlice(const Slice &S,
|
|
|
|
|
/// This is a quick test to check whether we can rewrite the integer loads and
|
|
|
|
|
/// stores to a particular alloca into wider loads and stores and be able to
|
|
|
|
|
/// promote the resulting alloca.
|
|
|
|
|
static bool isIntegerWideningViable(AllocaSlices::Partition &P, Type *AllocaTy,
|
|
|
|
|
static bool isIntegerWideningViable(Partition &P, Type *AllocaTy,
|
|
|
|
|
const DataLayout &DL) {
|
|
|
|
|
uint64_t SizeInBits = DL.getTypeSizeInBits(AllocaTy);
|
|
|
|
|
// Don't create integer types larger than the maximum bitwidth.
|
|
|
|
@ -2257,14 +2152,14 @@ static Value *insertVector(IRBuilderTy &IRB, Value *Old, Value *V,
|
|
|
|
|
return V;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
/// \brief Visitor to rewrite instructions using p particular slice of an alloca
|
|
|
|
|
/// to use a new alloca.
|
|
|
|
|
///
|
|
|
|
|
/// Also implements the rewriting to vector-based accesses when the partition
|
|
|
|
|
/// passes the isVectorPromotionViable predicate. Most of the rewriting logic
|
|
|
|
|
/// lives here.
|
|
|
|
|
class AllocaSliceRewriter : public InstVisitor<AllocaSliceRewriter, bool> {
|
|
|
|
|
class llvm::sroa::AllocaSliceRewriter
|
|
|
|
|
: public InstVisitor<AllocaSliceRewriter, bool> {
|
|
|
|
|
// Befriend the base class so it can delegate to private visit methods.
|
|
|
|
|
friend class llvm::InstVisitor<AllocaSliceRewriter, bool>;
|
|
|
|
|
typedef llvm::InstVisitor<AllocaSliceRewriter, bool> Base;
|
|
|
|
@ -3068,7 +2963,6 @@ private:
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
/// \brief Visitor to rewrite aggregate loads and stores as scalar.
|
|
|
|
@ -3923,7 +3817,7 @@ bool SROA::presplitLoadsAndStores(AllocaInst &AI, AllocaSlices &AS) {
|
|
|
|
|
/// at enabling promotion and if it was successful queues the alloca to be
|
|
|
|
|
/// promoted.
|
|
|
|
|
AllocaInst *SROA::rewritePartition(AllocaInst &AI, AllocaSlices &AS,
|
|
|
|
|
AllocaSlices::Partition &P) {
|
|
|
|
|
Partition &P) {
|
|
|
|
|
// Try to compute a friendly type for this partition of the alloca. This
|
|
|
|
|
// won't always succeed, in which case we fall back to a legal integer type
|
|
|
|
|
// or an i8 array of an appropriate size.
|
|
|
|
@ -4304,14 +4198,12 @@ bool SROA::promoteAllocas(Function &F) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool SROA::runOnFunction(Function &F) {
|
|
|
|
|
if (skipOptnoneFunction(F))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
PreservedAnalyses SROA::runImpl(Function &F, DominatorTree &RunDT,
|
|
|
|
|
AssumptionCache &RunAC) {
|
|
|
|
|
DEBUG(dbgs() << "SROA function: " << F.getName() << "\n");
|
|
|
|
|
C = &F.getContext();
|
|
|
|
|
DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
|
|
|
|
|
AC = &getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F);
|
|
|
|
|
DT = &RunDT;
|
|
|
|
|
AC = &RunAC;
|
|
|
|
|
|
|
|
|
|
BasicBlock &EntryBB = F.getEntryBlock();
|
|
|
|
|
for (BasicBlock::iterator I = EntryBB.begin(), E = std::prev(EntryBB.end());
|
|
|
|
@ -4350,12 +4242,55 @@ bool SROA::runOnFunction(Function &F) {
|
|
|
|
|
PostPromotionWorklist.clear();
|
|
|
|
|
} while (!Worklist.empty());
|
|
|
|
|
|
|
|
|
|
return Changed;
|
|
|
|
|
// FIXME: Even when promoting allocas we should preserve some abstract set of
|
|
|
|
|
// CFG-specific analyses.
|
|
|
|
|
return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SROA::getAnalysisUsage(AnalysisUsage &AU) const {
|
|
|
|
|
PreservedAnalyses SROA::run(Function &F, AnalysisManager<Function> *AM) {
|
|
|
|
|
return runImpl(F, AM->getResult<DominatorTreeAnalysis>(F),
|
|
|
|
|
AM->getResult<AssumptionAnalysis>(F));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// A legacy pass for the legacy pass manager that wraps the \c SROA pass.
|
|
|
|
|
///
|
|
|
|
|
/// This is in the llvm namespace purely to allow it to be a friend of the \c
|
|
|
|
|
/// SROA pass.
|
|
|
|
|
class llvm::sroa::SROALegacyPass : public FunctionPass {
|
|
|
|
|
/// The SROA implementation.
|
|
|
|
|
SROA Impl;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
SROALegacyPass() : FunctionPass(ID) {
|
|
|
|
|
initializeSROALegacyPassPass(*PassRegistry::getPassRegistry());
|
|
|
|
|
}
|
|
|
|
|
bool runOnFunction(Function &F) override {
|
|
|
|
|
if (skipOptnoneFunction(F))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
auto PA = Impl.runImpl(
|
|
|
|
|
F, getAnalysis<DominatorTreeWrapperPass>().getDomTree(),
|
|
|
|
|
getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F));
|
|
|
|
|
return !PA.areAllPreserved();
|
|
|
|
|
}
|
|
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
|
|
|
|
AU.addRequired<AssumptionCacheTracker>();
|
|
|
|
|
AU.addRequired<DominatorTreeWrapperPass>();
|
|
|
|
|
AU.addPreserved<GlobalsAAWrapperPass>();
|
|
|
|
|
AU.setPreservesCFG();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *getPassName() const override { return "SROA"; }
|
|
|
|
|
static char ID;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
char SROALegacyPass::ID = 0;
|
|
|
|
|
|
|
|
|
|
FunctionPass *llvm::createSROAPass() { return new SROALegacyPass(); }
|
|
|
|
|
|
|
|
|
|
INITIALIZE_PASS_BEGIN(SROALegacyPass, "sroa",
|
|
|
|
|
"Scalar Replacement Of Aggregates", false, false)
|
|
|
|
|
INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
|
|
|
|
|
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
|
|
|
|
|
INITIALIZE_PASS_END(SROALegacyPass, "sroa", "Scalar Replacement Of Aggregates",
|
|
|
|
|
false, false)
|
|
|
|
|