1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-19 11:02:59 +02:00

[DSE,MemorySSA] Use BatchAA for AA queries.

We can use BatchAA to avoid some repeated AA queries. We only remove
stores, so I think we will get away with using a single BatchAA instance
for the complete run.

The changes in AliasAnalysis.h mirror the changes in D85583.

The change improves compile-time by roughly 1%.
http://llvm-compile-time-tracker.com/compare.php?from=67ad786353dfcc7633c65de11601d7823746378e&to=10529e5b43809808e8c198f88fffd8f756554e45&stat=instructions

This is part of the patches to bring down compile-time to the level
referenced in
http://lists.llvm.org/pipermail/llvm-dev/2020-August/144417.html

Reviewed By: asbirlea

Differential Revision: https://reviews.llvm.org/D86275
This commit is contained in:
Florian Hahn 2020-08-22 08:36:35 +01:00
parent 2248051c0d
commit 384a619d03
2 changed files with 46 additions and 31 deletions

View File

@ -847,6 +847,13 @@ public:
FunctionModRefBehavior getModRefBehavior(const CallBase *Call) {
return AA.getModRefBehavior(Call);
}
bool isMustAlias(const MemoryLocation &LocA, const MemoryLocation &LocB) {
return alias(LocA, LocB) == MustAlias;
}
bool isMustAlias(const Value *V1, const Value *V2) {
return alias(MemoryLocation(V1, LocationSize::precise(1)),
MemoryLocation(V2, LocationSize::precise(1))) == MustAlias;
}
};
/// Temporary typedef for legacy code that uses a generic \c AliasAnalysis

View File

@ -383,12 +383,12 @@ enum OverwriteResult {
/// write to the same underlying object. In that case, use isPartialOverwrite to
/// check if \p Later partially overwrites \p Earlier. Returns 'OW_Unknown' if
/// nothing can be determined.
static OverwriteResult isOverwrite(const MemoryLocation &Later,
const MemoryLocation &Earlier,
const DataLayout &DL,
const TargetLibraryInfo &TLI,
int64_t &EarlierOff, int64_t &LaterOff,
AliasAnalysis &AA, const Function *F) {
template <typename AATy>
static OverwriteResult
isOverwrite(const MemoryLocation &Later, const MemoryLocation &Earlier,
const DataLayout &DL, const TargetLibraryInfo &TLI,
int64_t &EarlierOff, int64_t &LaterOff, AATy &AA,
const Function *F) {
// FIXME: Vet that this works for size upper-bounds. Seems unlikely that we'll
// get imprecise values here, though (except for unknown sizes).
if (!Later.Size.isPrecise() || !Earlier.Size.isPrecise())
@ -643,11 +643,10 @@ static bool isPossibleSelfRead(Instruction *Inst,
/// modified between the first and the second instruction.
/// Precondition: Second instruction must be dominated by the first
/// instruction.
static bool memoryIsNotModifiedBetween(Instruction *FirstI,
Instruction *SecondI,
AliasAnalysis *AA,
const DataLayout &DL,
DominatorTree *DT) {
template <typename AATy>
static bool
memoryIsNotModifiedBetween(Instruction *FirstI, Instruction *SecondI, AATy &AA,
const DataLayout &DL, DominatorTree *DT) {
// Do a backwards scan through the CFG from SecondI to FirstI. Look for
// instructions which can modify the memory location accessed by SecondI.
//
@ -696,7 +695,7 @@ static bool memoryIsNotModifiedBetween(Instruction *FirstI,
for (; BI != EI; ++BI) {
Instruction *I = &*BI;
if (I->mayWriteToMemory() && I != SecondI)
if (isModSet(AA->getModRefInfo(I, MemLoc.getWithNewPtr(Ptr))))
if (isModSet(AA.getModRefInfo(I, MemLoc.getWithNewPtr(Ptr))))
return false;
}
if (B != FirstBB) {
@ -1132,7 +1131,7 @@ static bool eliminateNoopStore(Instruction *Inst, BasicBlock::iterator &BBI,
if (LoadInst *DepLoad = dyn_cast<LoadInst>(SI->getValueOperand())) {
if (SI->getPointerOperand() == DepLoad->getPointerOperand() &&
isRemovable(SI) &&
memoryIsNotModifiedBetween(DepLoad, SI, AA, DL, DT)) {
memoryIsNotModifiedBetween(DepLoad, SI, *AA, DL, DT)) {
LLVM_DEBUG(
dbgs() << "DSE: Remove Store Of Load from same pointer:\n LOAD: "
@ -1151,7 +1150,7 @@ static bool eliminateNoopStore(Instruction *Inst, BasicBlock::iterator &BBI,
dyn_cast<Instruction>(getUnderlyingObject(SI->getPointerOperand()));
if (UnderlyingPointer && isCallocLikeFn(UnderlyingPointer, TLI) &&
memoryIsNotModifiedBetween(UnderlyingPointer, SI, AA, DL, DT)) {
memoryIsNotModifiedBetween(UnderlyingPointer, SI, *AA, DL, DT)) {
LLVM_DEBUG(
dbgs() << "DSE: Remove null store to the calloc'ed object:\n DEAD: "
<< *Inst << "\n OBJECT: " << *UnderlyingPointer << '\n');
@ -1164,11 +1163,10 @@ static bool eliminateNoopStore(Instruction *Inst, BasicBlock::iterator &BBI,
return false;
}
static Constant *
tryToMergePartialOverlappingStores(StoreInst *Earlier, StoreInst *Later,
int64_t InstWriteOffset,
int64_t DepWriteOffset, const DataLayout &DL,
AliasAnalysis *AA, DominatorTree *DT) {
template <typename AATy>
static Constant *tryToMergePartialOverlappingStores(
StoreInst *Earlier, StoreInst *Later, int64_t InstWriteOffset,
int64_t DepWriteOffset, const DataLayout &DL, AATy &AA, DominatorTree *DT) {
if (Earlier && isa<ConstantInt>(Earlier->getValueOperand()) &&
DL.typeSizeEqualsStoreSize(Earlier->getValueOperand()->getType()) &&
@ -1361,7 +1359,7 @@ static bool eliminateDeadStores(BasicBlock &BB, AliasAnalysis *AA,
auto *Earlier = dyn_cast<StoreInst>(DepWrite);
auto *Later = dyn_cast<StoreInst>(Inst);
if (Constant *C = tryToMergePartialOverlappingStores(
Earlier, Later, InstWriteOffset, DepWriteOffset, DL, AA,
Earlier, Later, InstWriteOffset, DepWriteOffset, DL, *AA,
DT)) {
auto *SI = new StoreInst(
C, Earlier->getPointerOperand(), false, Earlier->getAlign(),
@ -1507,6 +1505,16 @@ bool canSkipDef(MemoryDef *D, bool DefVisibleToCaller) {
struct DSEState {
Function &F;
AliasAnalysis &AA;
/// The single BatchAA instance that is used to cache AA queries. It will
/// not be invalidated over the whole run. This is safe, because:
/// 1. Only memory writes are removed, so the alias cache for memory
/// locations remains valid.
/// 2. No new instructions are added (only instructions removed), so cached
/// information for a deleted value cannot be accessed by a re-used new
/// value pointer.
BatchAAResults BatchAA;
MemorySSA &MSSA;
DominatorTree &DT;
PostDominatorTree &PDT;
@ -1534,7 +1542,7 @@ struct DSEState {
DSEState(Function &F, AliasAnalysis &AA, MemorySSA &MSSA, DominatorTree &DT,
PostDominatorTree &PDT, const TargetLibraryInfo &TLI)
: F(F), AA(AA), MSSA(MSSA), DT(DT), PDT(PDT), TLI(TLI) {}
: F(F), AA(AA), BatchAA(AA), MSSA(MSSA), DT(DT), PDT(PDT), TLI(TLI) {}
static DSEState get(Function &F, AliasAnalysis &AA, MemorySSA &MSSA,
DominatorTree &DT, PostDominatorTree &PDT,
@ -1623,7 +1631,7 @@ struct DSEState {
}
/// Returns true if \p Use completely overwrites \p DefLoc.
bool isCompleteOverwrite(MemoryLocation DefLoc, Instruction *UseInst) const {
bool isCompleteOverwrite(MemoryLocation DefLoc, Instruction *UseInst) {
// UseInst has a MemoryDef associated in MemorySSA. It's possible for a
// MemoryDef to not write to memory, e.g. a volatile load is modeled as a
// MemoryDef.
@ -1638,7 +1646,7 @@ struct DSEState {
auto CC = getLocForWriteEx(UseInst);
const DataLayout &DL = F.getParent()->getDataLayout();
return CC && isOverwrite(*CC, DefLoc, DL, TLI, DepWriteOffset,
InstWriteOffset, AA, &F) == OW_Complete;
InstWriteOffset, BatchAA, &F) == OW_Complete;
}
/// Returns true if \p Def is not read before returning from the function.
@ -1717,7 +1725,7 @@ struct DSEState {
/// Returns true if \p MaybeTerm is a memory terminator for the same
/// underlying object as \p DefLoc.
bool isMemTerminator(MemoryLocation DefLoc, Instruction *MaybeTerm) const {
bool isMemTerminator(MemoryLocation DefLoc, Instruction *MaybeTerm) {
Optional<std::pair<MemoryLocation, bool>> MaybeTermLoc =
getLocForTerminator(MaybeTerm);
@ -1730,11 +1738,11 @@ struct DSEState {
DataLayout DL = MaybeTerm->getParent()->getModule()->getDataLayout();
DefLoc = MemoryLocation(getUnderlyingObject(DefLoc.Ptr));
}
return AA.isMustAlias(MaybeTermLoc->first, DefLoc);
return BatchAA.isMustAlias(MaybeTermLoc->first, DefLoc);
}
// Returns true if \p Use may read from \p DefLoc.
bool isReadClobber(MemoryLocation DefLoc, Instruction *UseInst) const {
bool isReadClobber(MemoryLocation DefLoc, Instruction *UseInst) {
if (!UseInst->mayReadFromMemory())
return false;
@ -1742,7 +1750,7 @@ struct DSEState {
if (CB->onlyAccessesInaccessibleMemory())
return false;
ModRefInfo MR = AA.getModRefInfo(UseInst, DefLoc);
ModRefInfo MR = BatchAA.getModRefInfo(UseInst, DefLoc);
// If necessary, perform additional analysis.
if (isRefSet(MR))
MR = AA.callCapturesBefore(UseInst, DefLoc, &DT);
@ -1758,7 +1766,7 @@ struct DSEState {
Optional<MemoryAccess *>
getDomMemoryDef(MemoryDef *KillingDef, MemoryAccess *Current,
MemoryLocation DefLoc, bool DefVisibleToCallerBeforeRet,
bool DefVisibleToCallerAfterRet, unsigned &ScanLimit) const {
bool DefVisibleToCallerAfterRet, unsigned &ScanLimit) {
if (ScanLimit == 0) {
LLVM_DEBUG(dbgs() << "\n ... hit scan limit\n");
return None;
@ -2285,7 +2293,7 @@ bool eliminateDeadStoresMemorySSA(Function &F, AliasAnalysis &AA,
// Check if NI overwrites SI.
int64_t InstWriteOffset, DepWriteOffset;
OverwriteResult OR = isOverwrite(SILoc, NILoc, DL, TLI, DepWriteOffset,
InstWriteOffset, State.AA, &F);
InstWriteOffset, State.BatchAA, &F);
if (OR == OW_MaybePartial) {
auto Iter = State.IOLs.insert(
std::make_pair<BasicBlock *, InstOverlapIntervalsTy>(
@ -2303,8 +2311,8 @@ bool eliminateDeadStoresMemorySSA(Function &F, AliasAnalysis &AA,
// TODO: implement tryToMergeParialOverlappingStores using MemorySSA.
if (Earlier && Later && DT.dominates(Earlier, Later)) {
if (Constant *Merged = tryToMergePartialOverlappingStores(
Earlier, Later, InstWriteOffset, DepWriteOffset, DL, &AA,
&DT)) {
Earlier, Later, InstWriteOffset, DepWriteOffset, DL,
State.BatchAA, &DT)) {
// Update stored value of earlier store to merged constant.
Earlier->setOperand(0, Merged);