Changeset View
Changeset View
Standalone View
Standalone View
llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
Show First 20 Lines • Show All 770 Lines • ▼ Show 20 Lines | struct DSEState { | ||||
/// Keep track of instructions (partly) overlapping with killing MemoryDefs per | /// Keep track of instructions (partly) overlapping with killing MemoryDefs per | ||||
/// basic block. | /// basic block. | ||||
MapVector<BasicBlock *, InstOverlapIntervalsTy> IOLs; | MapVector<BasicBlock *, InstOverlapIntervalsTy> IOLs; | ||||
// Check if there are root nodes that are terminated by UnreachableInst. | // Check if there are root nodes that are terminated by UnreachableInst. | ||||
// Those roots pessimize post-dominance queries. If there are such roots, | // Those roots pessimize post-dominance queries. If there are such roots, | ||||
// fall back to CFG scan starting from all non-unreachable roots. | // fall back to CFG scan starting from all non-unreachable roots. | ||||
bool AnyUnreachableExit; | bool AnyUnreachableExit; | ||||
// Whether or not we should iterate on removing dead stores at the end of the | |||||
// function due to removing a store causing a previously captured pointer to | |||||
// no longer be captured. | |||||
bool ShouldIterateEndOfFunctionDSE; | |||||
// Class contains self-reference, make sure it's not copied/moved. | // Class contains self-reference, make sure it's not copied/moved. | ||||
DSEState(const DSEState &) = delete; | DSEState(const DSEState &) = delete; | ||||
DSEState &operator=(const DSEState &) = delete; | DSEState &operator=(const DSEState &) = delete; | ||||
DSEState(Function &F, AliasAnalysis &AA, MemorySSA &MSSA, DominatorTree &DT, | DSEState(Function &F, AliasAnalysis &AA, MemorySSA &MSSA, DominatorTree &DT, | ||||
PostDominatorTree &PDT, AssumptionCache &AC, | PostDominatorTree &PDT, AssumptionCache &AC, | ||||
const TargetLibraryInfo &TLI, const LoopInfo &LI) | const TargetLibraryInfo &TLI, const LoopInfo &LI) | ||||
: F(F), AA(AA), EI(DT, LI, EphValues), BatchAA(AA, &EI), MSSA(MSSA), | : F(F), AA(AA), EI(DT, LI, EphValues), BatchAA(AA, &EI), MSSA(MSSA), | ||||
▲ Show 20 Lines • Show All 806 Lines • ▼ Show 20 Lines | while (!NowDeadInsts.empty()) { | ||||
// Try to preserve debug information attached to the dead instruction. | // Try to preserve debug information attached to the dead instruction. | ||||
salvageDebugInfo(*DeadInst); | salvageDebugInfo(*DeadInst); | ||||
salvageKnowledge(DeadInst); | salvageKnowledge(DeadInst); | ||||
// Remove the Instruction from MSSA. | // Remove the Instruction from MSSA. | ||||
if (MemoryAccess *MA = MSSA.getMemoryAccess(DeadInst)) { | if (MemoryAccess *MA = MSSA.getMemoryAccess(DeadInst)) { | ||||
if (MemoryDef *MD = dyn_cast<MemoryDef>(MA)) { | if (MemoryDef *MD = dyn_cast<MemoryDef>(MA)) { | ||||
SkipStores.insert(MD); | SkipStores.insert(MD); | ||||
if (auto *SI = dyn_cast<StoreInst>(MD->getMemoryInst())) { | |||||
if (SI->getValueOperand()->getType()->isPointerTy()) { | |||||
const Value *UO = getUnderlyingObject(SI->getValueOperand()); | |||||
if (CapturedBeforeReturn.erase(UO)) | |||||
ShouldIterateEndOfFunctionDSE = true; | |||||
InvisibleToCallerAfterRet.erase(UO); | |||||
} | |||||
} | |||||
} | } | ||||
Updater.removeMemoryAccess(MA); | Updater.removeMemoryAccess(MA); | ||||
} | } | ||||
auto I = IOLs.find(DeadInst->getParent()); | auto I = IOLs.find(DeadInst->getParent()); | ||||
if (I != IOLs.end()) | if (I != IOLs.end()) | ||||
I->second.erase(DeadInst); | I->second.erase(DeadInst); | ||||
▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | struct DSEState { | ||||
/// Eliminate writes to objects that are not visible in the caller and are not | /// Eliminate writes to objects that are not visible in the caller and are not | ||||
/// accessed before returning from the function. | /// accessed before returning from the function. | ||||
bool eliminateDeadWritesAtEndOfFunction() { | bool eliminateDeadWritesAtEndOfFunction() { | ||||
bool MadeChange = false; | bool MadeChange = false; | ||||
LLVM_DEBUG( | LLVM_DEBUG( | ||||
dbgs() | dbgs() | ||||
<< "Trying to eliminate MemoryDefs at the end of the function\n"); | << "Trying to eliminate MemoryDefs at the end of the function\n"); | ||||
do { | |||||
ShouldIterateEndOfFunctionDSE = false; | |||||
for (MemoryDef *Def : llvm::reverse(MemDefs)) { | for (MemoryDef *Def : llvm::reverse(MemDefs)) { | ||||
if (SkipStores.contains(Def)) | if (SkipStores.contains(Def)) | ||||
continue; | continue; | ||||
Instruction *DefI = Def->getMemoryInst(); | Instruction *DefI = Def->getMemoryInst(); | ||||
auto DefLoc = getLocForWrite(DefI); | auto DefLoc = getLocForWrite(DefI); | ||||
if (!DefLoc || !isRemovable(DefI)) | if (!DefLoc || !isRemovable(DefI)) | ||||
continue; | continue; | ||||
// NOTE: Currently eliminating writes at the end of a function is limited | // NOTE: Currently eliminating writes at the end of a function is | ||||
// to MemoryDefs with a single underlying object, to save compile-time. In | // limited to MemoryDefs with a single underlying object, to save | ||||
// practice it appears the case with multiple underlying objects is very | // compile-time. In practice it appears the case with multiple | ||||
// uncommon. If it turns out to be important, we can use | // underlying objects is very uncommon. If it turns out to be important, | ||||
// getUnderlyingObjects here instead. | // we can use getUnderlyingObjects here instead. | ||||
const Value *UO = getUnderlyingObject(DefLoc->Ptr); | const Value *UO = getUnderlyingObject(DefLoc->Ptr); | ||||
if (!isInvisibleToCallerAfterRet(UO)) | if (!isInvisibleToCallerAfterRet(UO)) | ||||
continue; | continue; | ||||
if (isWriteAtEndOfFunction(Def)) { | if (isWriteAtEndOfFunction(Def)) { | ||||
// See through pointer-to-pointer bitcasts | // See through pointer-to-pointer bitcasts | ||||
LLVM_DEBUG(dbgs() << " ... MemoryDef is not accessed until the end " | LLVM_DEBUG(dbgs() << " ... MemoryDef is not accessed until the end " | ||||
"of the function\n"); | "of the function\n"); | ||||
deleteDeadInstruction(DefI); | deleteDeadInstruction(DefI); | ||||
++NumFastStores; | ++NumFastStores; | ||||
MadeChange = true; | MadeChange = true; | ||||
} | } | ||||
} | } | ||||
} while (ShouldIterateEndOfFunctionDSE); | |||||
return MadeChange; | return MadeChange; | ||||
} | } | ||||
/// If we have a zero initializing memset following a call to malloc, | /// If we have a zero initializing memset following a call to malloc, | ||||
/// try folding it into a call to calloc. | /// try folding it into a call to calloc. | ||||
bool tryFoldIntoCalloc(MemoryDef *Def, const Value *DefUO) { | bool tryFoldIntoCalloc(MemoryDef *Def, const Value *DefUO) { | ||||
Instruction *DefI = Def->getMemoryInst(); | Instruction *DefI = Def->getMemoryInst(); | ||||
MemSetInst *MemSet = dyn_cast<MemSetInst>(DefI); | MemSetInst *MemSet = dyn_cast<MemSetInst>(DefI); | ||||
▲ Show 20 Lines • Show All 512 Lines • Show Last 20 Lines |