1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 18:54:02 +01:00

[NFC] Disambiguate LI in GVN

Name GVN uses name 'LI' for two different unrelated things:
LoadInst and LoopInfo. This patch relates the variables with
former meaning into 'Load' to disambiguate the code.
This commit is contained in:
Max Kazantsev 2021-04-01 12:31:57 +07:00
parent 1c951bda95
commit 467293274d
2 changed files with 125 additions and 123 deletions

View File

@ -314,17 +314,17 @@ private:
/// Given a local dependency (Def or Clobber) determine if a value is
/// available for the load. Returns true if an value is known to be
/// available and populates Res. Returns false otherwise.
bool AnalyzeLoadAvailability(LoadInst *LI, MemDepResult DepInfo,
bool AnalyzeLoadAvailability(LoadInst *Load, MemDepResult DepInfo,
Value *Address, gvn::AvailableValue &Res);
/// Given a list of non-local dependencies, determine if a value is
/// available for the load in each specified block. If it is, add it to
/// ValuesPerBlock. If not, add it to UnavailableBlocks.
void AnalyzeLoadAvailability(LoadInst *LI, LoadDepVect &Deps,
void AnalyzeLoadAvailability(LoadInst *Load, LoadDepVect &Deps,
AvailValInBlkVect &ValuesPerBlock,
UnavailBlkVect &UnavailableBlocks);
bool PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock,
bool PerformLoadPRE(LoadInst *Load, AvailValInBlkVect &ValuesPerBlock,
UnavailBlkVect &UnavailableBlocks);
// Other helper routines

View File

@ -208,9 +208,9 @@ struct llvm::gvn::AvailableValue {
return Res;
}
static AvailableValue getLoad(LoadInst *LI, unsigned Offset = 0) {
static AvailableValue getLoad(LoadInst *Load, unsigned Offset = 0) {
AvailableValue Res;
Res.Val.setPointer(LI);
Res.Val.setPointer(Load);
Res.Val.setInt(LoadVal);
Res.Offset = Offset;
return Res;
@ -246,7 +246,7 @@ struct llvm::gvn::AvailableValue {
/// Emit code at the specified insertion point to adjust the value defined
/// here to the specified type. This handles various coercion cases.
Value *MaterializeAdjustedValue(LoadInst *LI, Instruction *InsertPt,
Value *MaterializeAdjustedValue(LoadInst *Load, Instruction *InsertPt,
GVN &gvn) const;
};
@ -277,8 +277,8 @@ struct llvm::gvn::AvailableValueInBlock {
/// Emit code at the end of this block to adjust the value defined here to
/// the specified type. This handles various coercion cases.
Value *MaterializeAdjustedValue(LoadInst *LI, GVN &gvn) const {
return AV.MaterializeAdjustedValue(LI, BB->getTerminator(), gvn);
Value *MaterializeAdjustedValue(LoadInst *Load, GVN &gvn) const {
return AV.MaterializeAdjustedValue(Load, BB->getTerminator(), gvn);
}
};
@ -670,10 +670,10 @@ PreservedAnalyses GVN::run(Function &F, FunctionAnalysisManager &AM) {
auto &AA = AM.getResult<AAManager>(F);
auto *MemDep =
isMemDepEnabled() ? &AM.getResult<MemoryDependenceAnalysis>(F) : nullptr;
auto *LI = AM.getCachedResult<LoopAnalysis>(F);
auto *Load = AM.getCachedResult<LoopAnalysis>(F);
auto *MSSA = AM.getCachedResult<MemorySSAAnalysis>(F);
auto &ORE = AM.getResult<OptimizationRemarkEmitterAnalysis>(F);
bool Changed = runImpl(F, AC, DT, TLI, AA, MemDep, LI, &ORE,
bool Changed = runImpl(F, AC, DT, TLI, AA, MemDep, Load, &ORE,
MSSA ? &MSSA->getMSSA() : nullptr);
if (!Changed)
return PreservedAnalyses::all();
@ -683,7 +683,7 @@ PreservedAnalyses GVN::run(Function &F, FunctionAnalysisManager &AM) {
PA.preserve<TargetLibraryAnalysis>();
if (MSSA)
PA.preserve<MemorySSAAnalysis>();
if (LI)
if (Load)
PA.preserve<LoopAnalysis>();
return PA;
}
@ -736,7 +736,7 @@ static bool IsValueFullyAvailableInBlock(
Worklist.emplace_back(BB);
while (!Worklist.empty()) {
BasicBlock *CurrBB = Worklist.pop_back_val(); // LIFO - depth-first!
BasicBlock *CurrBB = Worklist.pop_back_val(); // LoadFO - depth-first!
// Optimistically assume that the block is Speculatively Available and check
// to see if we already know about this block in one lookup.
std::pair<DenseMap<BasicBlock *, AvailabilityState>::iterator, bool> IV =
@ -834,25 +834,26 @@ static bool IsValueFullyAvailableInBlock(
}
/// Given a set of loads specified by ValuesPerBlock,
/// construct SSA form, allowing us to eliminate LI. This returns the value
/// that should be used at LI's definition site.
static Value *ConstructSSAForLoadSet(LoadInst *LI,
SmallVectorImpl<AvailableValueInBlock> &ValuesPerBlock,
GVN &gvn) {
/// construct SSA form, allowing us to eliminate Load. This returns the value
/// that should be used at Load's definition site.
static Value *
ConstructSSAForLoadSet(LoadInst *Load,
SmallVectorImpl<AvailableValueInBlock> &ValuesPerBlock,
GVN &gvn) {
// Check for the fully redundant, dominating load case. In this case, we can
// just use the dominating value directly.
if (ValuesPerBlock.size() == 1 &&
gvn.getDominatorTree().properlyDominates(ValuesPerBlock[0].BB,
LI->getParent())) {
Load->getParent())) {
assert(!ValuesPerBlock[0].AV.isUndefValue() &&
"Dead BB dominate this block");
return ValuesPerBlock[0].MaterializeAdjustedValue(LI, gvn);
return ValuesPerBlock[0].MaterializeAdjustedValue(Load, gvn);
}
// Otherwise, we have to construct SSA form.
SmallVector<PHINode*, 8> NewPHIs;
SSAUpdater SSAUpdate(&NewPHIs);
SSAUpdate.Initialize(LI->getType(), LI->getName());
SSAUpdate.Initialize(Load->getType(), Load->getName());
for (const AvailableValueInBlock &AV : ValuesPerBlock) {
BasicBlock *BB = AV.BB;
@ -867,24 +868,24 @@ static Value *ConstructSSAForLoadSet(LoadInst *LI,
// available in is the block that the load is in, then don't add it as
// SSAUpdater will resolve the value to the relevant phi which may let it
// avoid phi construction entirely if there's actually only one value.
if (BB == LI->getParent() &&
((AV.AV.isSimpleValue() && AV.AV.getSimpleValue() == LI) ||
(AV.AV.isCoercedLoadValue() && AV.AV.getCoercedLoadValue() == LI)))
if (BB == Load->getParent() &&
((AV.AV.isSimpleValue() && AV.AV.getSimpleValue() == Load) ||
(AV.AV.isCoercedLoadValue() && AV.AV.getCoercedLoadValue() == Load)))
continue;
SSAUpdate.AddAvailableValue(BB, AV.MaterializeAdjustedValue(LI, gvn));
SSAUpdate.AddAvailableValue(BB, AV.MaterializeAdjustedValue(Load, gvn));
}
// Perform PHI construction.
return SSAUpdate.GetValueInMiddleOfBlock(LI->getParent());
return SSAUpdate.GetValueInMiddleOfBlock(Load->getParent());
}
Value *AvailableValue::MaterializeAdjustedValue(LoadInst *LI,
Value *AvailableValue::MaterializeAdjustedValue(LoadInst *Load,
Instruction *InsertPt,
GVN &gvn) const {
Value *Res;
Type *LoadTy = LI->getType();
const DataLayout &DL = LI->getModule()->getDataLayout();
Type *LoadTy = Load->getType();
const DataLayout &DL = Load->getModule()->getDataLayout();
if (isSimpleValue()) {
Res = getSimpleValue();
if (Res->getType() != LoadTy) {
@ -934,20 +935,20 @@ static bool isLifetimeStart(const Instruction *Inst) {
/// Try to locate the three instruction involved in a missed
/// load-elimination case that is due to an intervening store.
static void reportMayClobberedLoad(LoadInst *LI, MemDepResult DepInfo,
static void reportMayClobberedLoad(LoadInst *Load, MemDepResult DepInfo,
DominatorTree *DT,
OptimizationRemarkEmitter *ORE) {
using namespace ore;
User *OtherAccess = nullptr;
OptimizationRemarkMissed R(DEBUG_TYPE, "LoadClobbered", LI);
R << "load of type " << NV("Type", LI->getType()) << " not eliminated"
OptimizationRemarkMissed R(DEBUG_TYPE, "LoadClobbered", Load);
R << "load of type " << NV("Type", Load->getType()) << " not eliminated"
<< setExtraArgs();
for (auto *U : LI->getPointerOperand()->users())
if (U != LI && (isa<LoadInst>(U) || isa<StoreInst>(U)) &&
DT->dominates(cast<Instruction>(U), LI)) {
for (auto *U : Load->getPointerOperand()->users())
if (U != Load && (isa<LoadInst>(U) || isa<StoreInst>(U)) &&
DT->dominates(cast<Instruction>(U), Load)) {
// FIXME: for now give up if there are multiple memory accesses that
// dominate the load. We need further analysis to decide which one is
// that we're forwarding from.
@ -965,13 +966,13 @@ static void reportMayClobberedLoad(LoadInst *LI, MemDepResult DepInfo,
ORE->emit(R);
}
bool GVN::AnalyzeLoadAvailability(LoadInst *LI, MemDepResult DepInfo,
bool GVN::AnalyzeLoadAvailability(LoadInst *Load, MemDepResult DepInfo,
Value *Address, AvailableValue &Res) {
assert((DepInfo.isDef() || DepInfo.isClobber()) &&
"expected a local dependence");
assert(LI->isUnordered() && "rules below are incorrect for ordered access");
assert(Load->isUnordered() && "rules below are incorrect for ordered access");
const DataLayout &DL = LI->getModule()->getDataLayout();
const DataLayout &DL = Load->getModule()->getDataLayout();
Instruction *DepInst = DepInfo.getInst();
if (DepInfo.isClobber()) {
@ -980,9 +981,9 @@ bool GVN::AnalyzeLoadAvailability(LoadInst *LI, MemDepResult DepInfo,
// stored value.
if (StoreInst *DepSI = dyn_cast<StoreInst>(DepInst)) {
// Can't forward from non-atomic to atomic without violating memory model.
if (Address && LI->isAtomic() <= DepSI->isAtomic()) {
if (Address && Load->isAtomic() <= DepSI->isAtomic()) {
int Offset =
analyzeLoadFromClobberingStore(LI->getType(), Address, DepSI, DL);
analyzeLoadFromClobberingStore(Load->getType(), Address, DepSI, DL);
if (Offset != -1) {
Res = AvailableValue::get(DepSI->getValueOperand(), Offset);
return true;
@ -994,16 +995,17 @@ bool GVN::AnalyzeLoadAvailability(LoadInst *LI, MemDepResult DepInfo,
// load i32* P
// load i8* (P+1)
// if we have this, replace the later with an extraction from the former.
if (LoadInst *DepLI = dyn_cast<LoadInst>(DepInst)) {
if (LoadInst *DepLoad = dyn_cast<LoadInst>(DepInst)) {
// If this is a clobber and L is the first instruction in its block, then
// we have the first instruction in the entry block.
// Can't forward from non-atomic to atomic without violating memory model.
if (DepLI != LI && Address && LI->isAtomic() <= DepLI->isAtomic()) {
int Offset =
analyzeLoadFromClobberingLoad(LI->getType(), Address, DepLI, DL);
if (DepLoad != Load && Address &&
Load->isAtomic() <= DepLoad->isAtomic()) {
int Offset = analyzeLoadFromClobberingLoad(Load->getType(), Address,
DepLoad, DL);
if (Offset != -1) {
Res = AvailableValue::getLoad(DepLI, Offset);
Res = AvailableValue::getLoad(DepLoad, Offset);
return true;
}
}
@ -1012,8 +1014,8 @@ bool GVN::AnalyzeLoadAvailability(LoadInst *LI, MemDepResult DepInfo,
// If the clobbering value is a memset/memcpy/memmove, see if we can
// forward a value on from it.
if (MemIntrinsic *DepMI = dyn_cast<MemIntrinsic>(DepInst)) {
if (Address && !LI->isAtomic()) {
int Offset = analyzeLoadFromClobberingMemInst(LI->getType(), Address,
if (Address && !Load->isAtomic()) {
int Offset = analyzeLoadFromClobberingMemInst(Load->getType(), Address,
DepMI, DL);
if (Offset != -1) {
Res = AvailableValue::getMI(DepMI, Offset);
@ -1024,10 +1026,10 @@ bool GVN::AnalyzeLoadAvailability(LoadInst *LI, MemDepResult DepInfo,
// Nothing known about this clobber, have to be conservative
LLVM_DEBUG(
// fast print dep, using operator<< on instruction is too slow.
dbgs() << "GVN: load "; LI->printAsOperand(dbgs());
dbgs() << "GVN: load "; Load->printAsOperand(dbgs());
dbgs() << " is clobbered by " << *DepInst << '\n';);
if (ORE->allowExtraAnalysis(DEBUG_TYPE))
reportMayClobberedLoad(LI, DepInfo, DT, ORE);
reportMayClobberedLoad(Load, DepInfo, DT, ORE);
return false;
}
@ -1038,13 +1040,13 @@ bool GVN::AnalyzeLoadAvailability(LoadInst *LI, MemDepResult DepInfo,
isAlignedAllocLikeFn(DepInst, TLI) ||
// Loading immediately after lifetime begin -> undef.
isLifetimeStart(DepInst)) {
Res = AvailableValue::get(UndefValue::get(LI->getType()));
Res = AvailableValue::get(UndefValue::get(Load->getType()));
return true;
}
// Loading from calloc (which zero initializes memory) -> zero
if (isCallocLikeFn(DepInst, TLI)) {
Res = AvailableValue::get(Constant::getNullValue(LI->getType()));
Res = AvailableValue::get(Constant::getNullValue(Load->getType()));
return true;
}
@ -1052,12 +1054,12 @@ bool GVN::AnalyzeLoadAvailability(LoadInst *LI, MemDepResult DepInfo,
// Reject loads and stores that are to the same address but are of
// different types if we have to. If the stored value is convertable to
// the loaded value, we can reuse it.
if (!canCoerceMustAliasedValueToLoad(S->getValueOperand(), LI->getType(),
if (!canCoerceMustAliasedValueToLoad(S->getValueOperand(), Load->getType(),
DL))
return false;
// Can't forward from non-atomic to atomic without violating memory model.
if (S->isAtomic() < LI->isAtomic())
if (S->isAtomic() < Load->isAtomic())
return false;
Res = AvailableValue::get(S->getValueOperand());
@ -1068,11 +1070,11 @@ bool GVN::AnalyzeLoadAvailability(LoadInst *LI, MemDepResult DepInfo,
// If the types mismatch and we can't handle it, reject reuse of the load.
// If the stored value is larger or equal to the loaded value, we can reuse
// it.
if (!canCoerceMustAliasedValueToLoad(LD, LI->getType(), DL))
if (!canCoerceMustAliasedValueToLoad(LD, Load->getType(), DL))
return false;
// Can't forward from non-atomic to atomic without violating memory model.
if (LD->isAtomic() < LI->isAtomic())
if (LD->isAtomic() < Load->isAtomic())
return false;
Res = AvailableValue::getLoad(LD);
@ -1082,12 +1084,12 @@ bool GVN::AnalyzeLoadAvailability(LoadInst *LI, MemDepResult DepInfo,
// Unknown def - must be conservative
LLVM_DEBUG(
// fast print dep, using operator<< on instruction is too slow.
dbgs() << "GVN: load "; LI->printAsOperand(dbgs());
dbgs() << "GVN: load "; Load->printAsOperand(dbgs());
dbgs() << " has unknown def " << *DepInst << '\n';);
return false;
}
void GVN::AnalyzeLoadAvailability(LoadInst *LI, LoadDepVect &Deps,
void GVN::AnalyzeLoadAvailability(LoadInst *Load, LoadDepVect &Deps,
AvailValInBlkVect &ValuesPerBlock,
UnavailBlkVect &UnavailableBlocks) {
// Filter out useless results (non-locals, etc). Keep track of the blocks
@ -1117,7 +1119,7 @@ void GVN::AnalyzeLoadAvailability(LoadInst *LI, LoadDepVect &Deps,
Value *Address = Deps[i].getAddress();
AvailableValue AV;
if (AnalyzeLoadAvailability(LI, DepInfo, Address, AV)) {
if (AnalyzeLoadAvailability(Load, DepInfo, Address, AV)) {
// subtlety: because we know this was a non-local dependency, we know
// it's safe to materialize anywhere between the instruction within
// DepInfo and the end of it's block.
@ -1132,7 +1134,7 @@ void GVN::AnalyzeLoadAvailability(LoadInst *LI, LoadDepVect &Deps,
"post condition violation");
}
bool GVN::PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock,
bool GVN::PerformLoadPRE(LoadInst *Load, AvailValInBlkVect &ValuesPerBlock,
UnavailBlkVect &UnavailableBlocks) {
// Okay, we have *some* definitions of the value. This means that the value
// is available in some of our (transitive) predecessors. Lets think about
@ -1147,7 +1149,7 @@ bool GVN::PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock,
// Let's find the first basic block with more than one predecessor. Walk
// backwards through predecessors if needed.
BasicBlock *LoadBB = LI->getParent();
BasicBlock *LoadBB = Load->getParent();
BasicBlock *TmpBB = LoadBB;
// Check that there is no implicit control flow instructions above our load in
@ -1166,7 +1168,7 @@ bool GVN::PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock,
// access the array.
// Check that there is no guard in this block above our instruction.
bool MustEnsureSafetyOfSpeculativeExecution =
ICF->isDominatedByICFIFromSameBlock(LI);
ICF->isDominatedByICFIFromSameBlock(Load);
while (TmpBB->getSinglePredecessor()) {
TmpBB = TmpBB->getSinglePredecessor();
@ -1207,7 +1209,7 @@ bool GVN::PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock,
if (Pred->getTerminator()->isEHPad()) {
LLVM_DEBUG(
dbgs() << "COULD NOT PRE LOAD BECAUSE OF AN EH PAD PREDECESSOR '"
<< Pred->getName() << "': " << *LI << '\n');
<< Pred->getName() << "': " << *Load << '\n');
return false;
}
@ -1219,7 +1221,7 @@ bool GVN::PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock,
if (isa<IndirectBrInst>(Pred->getTerminator())) {
LLVM_DEBUG(
dbgs() << "COULD NOT PRE LOAD BECAUSE OF INDBR CRITICAL EDGE '"
<< Pred->getName() << "': " << *LI << '\n');
<< Pred->getName() << "': " << *Load << '\n');
return false;
}
@ -1227,14 +1229,14 @@ bool GVN::PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock,
if (isa<CallBrInst>(Pred->getTerminator())) {
LLVM_DEBUG(
dbgs() << "COULD NOT PRE LOAD BECAUSE OF CALLBR CRITICAL EDGE '"
<< Pred->getName() << "': " << *LI << '\n');
<< Pred->getName() << "': " << *Load << '\n');
return false;
}
if (LoadBB->isEHPad()) {
LLVM_DEBUG(
dbgs() << "COULD NOT PRE LOAD BECAUSE OF AN EH PAD CRITICAL EDGE '"
<< Pred->getName() << "': " << *LI << '\n');
<< Pred->getName() << "': " << *Load << '\n');
return false;
}
@ -1244,7 +1246,7 @@ bool GVN::PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock,
LLVM_DEBUG(
dbgs()
<< "COULD NOT PRE LOAD BECAUSE OF A BACKEDGE CRITICAL EDGE '"
<< Pred->getName() << "': " << *LI << '\n');
<< Pred->getName() << "': " << *Load << '\n');
return false;
}
@ -1262,7 +1264,7 @@ bool GVN::PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock,
// If this load is unavailable in multiple predecessors, reject it.
// FIXME: If we could restructure the CFG, we could make a common pred with
// all the preds that don't have an available LI and insert a new load into
// all the preds that don't have an available Load and insert a new load into
// that one block.
if (NumUnavailablePreds != 1)
return false;
@ -1271,10 +1273,10 @@ bool GVN::PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock,
// to speculatively execute the load at that points.
if (MustEnsureSafetyOfSpeculativeExecution) {
if (CriticalEdgePred.size())
if (!isSafeToSpeculativelyExecute(LI, LoadBB->getFirstNonPHI(), DT))
if (!isSafeToSpeculativelyExecute(Load, LoadBB->getFirstNonPHI(), DT))
return false;
for (auto &PL : PredLoads)
if (!isSafeToSpeculativelyExecute(LI, PL.first->getTerminator(), DT))
if (!isSafeToSpeculativelyExecute(Load, PL.first->getTerminator(), DT))
return false;
}
@ -1289,21 +1291,21 @@ bool GVN::PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock,
// Check if the load can safely be moved to all the unavailable predecessors.
bool CanDoPRE = true;
const DataLayout &DL = LI->getModule()->getDataLayout();
const DataLayout &DL = Load->getModule()->getDataLayout();
SmallVector<Instruction*, 8> NewInsts;
for (auto &PredLoad : PredLoads) {
BasicBlock *UnavailablePred = PredLoad.first;
// Do PHI translation to get its value in the predecessor if necessary. The
// returned pointer (if non-null) is guaranteed to dominate UnavailablePred.
// We do the translation for each edge we skipped by going from LI's block
// We do the translation for each edge we skipped by going from Load's block
// to LoadBB, otherwise we might miss pieces needing translation.
// If all preds have a single successor, then we know it is safe to insert
// the load on the pred (?!?), so we can insert code to materialize the
// pointer if it is not available.
Value *LoadPtr = LI->getPointerOperand();
BasicBlock *Cur = LI->getParent();
Value *LoadPtr = Load->getPointerOperand();
BasicBlock *Cur = Load->getParent();
while (Cur != LoadBB) {
PHITransAddr Address(LoadPtr, DL, AC);
LoadPtr = Address.PHITranslateWithInsertion(
@ -1324,7 +1326,7 @@ bool GVN::PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock,
// we fail PRE.
if (!LoadPtr) {
LLVM_DEBUG(dbgs() << "COULDN'T INSERT PHI TRANSLATED VALUE OF: "
<< *LI->getPointerOperand() << "\n");
<< *Load->getPointerOperand() << "\n");
CanDoPRE = false;
break;
}
@ -1349,7 +1351,7 @@ bool GVN::PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock,
// Okay, we can eliminate this load by inserting a reload in the predecessor
// and using PHI construction to get the value in the other predecessors, do
// it.
LLVM_DEBUG(dbgs() << "GVN REMOVING PRE LOAD: " << *LI << '\n');
LLVM_DEBUG(dbgs() << "GVN REMOVING PRE LOAD: " << *Load << '\n');
LLVM_DEBUG(if (!NewInsts.empty()) dbgs()
<< "INSERTED " << NewInsts.size() << " INSTS: " << *NewInsts.back()
<< '\n');
@ -1372,19 +1374,19 @@ bool GVN::PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock,
BasicBlock *UnavailablePred = PredLoad.first;
Value *LoadPtr = PredLoad.second;
auto *NewLoad = new LoadInst(
LI->getType(), LoadPtr, LI->getName() + ".pre", LI->isVolatile(),
LI->getAlign(), LI->getOrdering(), LI->getSyncScopeID(),
UnavailablePred->getTerminator());
NewLoad->setDebugLoc(LI->getDebugLoc());
auto *NewLoad =
new LoadInst(Load->getType(), LoadPtr, Load->getName() + ".pre",
Load->isVolatile(), Load->getAlign(), Load->getOrdering(),
Load->getSyncScopeID(), UnavailablePred->getTerminator());
NewLoad->setDebugLoc(Load->getDebugLoc());
if (MSSAU) {
auto *MSSA = MSSAU->getMemorySSA();
// Get the defining access of the original load or use the load if it is a
// MemoryDef (e.g. because it is volatile). The inserted loads are
// guaranteed to load from the same definition.
auto *LIAcc = MSSA->getMemoryAccess(LI);
auto *LoadAcc = MSSA->getMemoryAccess(Load);
auto *DefiningAcc =
isa<MemoryDef>(LIAcc) ? LIAcc : LIAcc->getDefiningAccess();
isa<MemoryDef>(LoadAcc) ? LoadAcc : LoadAcc->getDefiningAccess();
auto *NewAccess = MSSAU->createMemoryAccessInBB(
NewLoad, DefiningAcc, NewLoad->getParent(),
MemorySSA::BeforeTerminator);
@ -1396,19 +1398,19 @@ bool GVN::PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock,
// Transfer the old load's AA tags to the new load.
AAMDNodes Tags;
LI->getAAMetadata(Tags);
Load->getAAMetadata(Tags);
if (Tags)
NewLoad->setAAMetadata(Tags);
if (auto *MD = LI->getMetadata(LLVMContext::MD_invariant_load))
if (auto *MD = Load->getMetadata(LLVMContext::MD_invariant_load))
NewLoad->setMetadata(LLVMContext::MD_invariant_load, MD);
if (auto *InvGroupMD = LI->getMetadata(LLVMContext::MD_invariant_group))
if (auto *InvGroupMD = Load->getMetadata(LLVMContext::MD_invariant_group))
NewLoad->setMetadata(LLVMContext::MD_invariant_group, InvGroupMD);
if (auto *RangeMD = LI->getMetadata(LLVMContext::MD_range))
if (auto *RangeMD = Load->getMetadata(LLVMContext::MD_range))
NewLoad->setMetadata(LLVMContext::MD_range, RangeMD);
if (auto *AccessMD = LI->getMetadata(LLVMContext::MD_access_group))
if (this->LI && this->LI->getLoopFor(LI->getParent()) ==
this->LI->getLoopFor(UnavailablePred))
if (auto *AccessMD = Load->getMetadata(LLVMContext::MD_access_group))
if (LI &&
LI->getLoopFor(Load->getParent()) == LI->getLoopFor(UnavailablePred))
NewLoad->setMetadata(LLVMContext::MD_access_group, AccessMD);
// We do not propagate the old load's debug location, because the new
@ -1425,30 +1427,30 @@ bool GVN::PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock,
}
// Perform PHI construction.
Value *V = ConstructSSAForLoadSet(LI, ValuesPerBlock, *this);
LI->replaceAllUsesWith(V);
Value *V = ConstructSSAForLoadSet(Load, ValuesPerBlock, *this);
Load->replaceAllUsesWith(V);
if (isa<PHINode>(V))
V->takeName(LI);
V->takeName(Load);
if (Instruction *I = dyn_cast<Instruction>(V))
I->setDebugLoc(LI->getDebugLoc());
I->setDebugLoc(Load->getDebugLoc());
if (V->getType()->isPtrOrPtrVectorTy())
MD->invalidateCachedPointerInfo(V);
markInstructionForDeletion(LI);
markInstructionForDeletion(Load);
ORE->emit([&]() {
return OptimizationRemark(DEBUG_TYPE, "LoadPRE", LI)
return OptimizationRemark(DEBUG_TYPE, "LoadPRE", Load)
<< "load eliminated by PRE";
});
++NumPRELoad;
return true;
}
static void reportLoadElim(LoadInst *LI, Value *AvailableValue,
static void reportLoadElim(LoadInst *Load, Value *AvailableValue,
OptimizationRemarkEmitter *ORE) {
using namespace ore;
ORE->emit([&]() {
return OptimizationRemark(DEBUG_TYPE, "LoadElim", LI)
<< "load of type " << NV("Type", LI->getType()) << " eliminated"
return OptimizationRemark(DEBUG_TYPE, "LoadElim", Load)
<< "load of type " << NV("Type", Load->getType()) << " eliminated"
<< setExtraArgs() << " in favor of "
<< NV("InfavorOfValue", AvailableValue);
});
@ -1456,17 +1458,17 @@ static void reportLoadElim(LoadInst *LI, Value *AvailableValue,
/// Attempt to eliminate a load whose dependencies are
/// non-local by performing PHI construction.
bool GVN::processNonLocalLoad(LoadInst *LI) {
bool GVN::processNonLocalLoad(LoadInst *Load) {
// non-local speculations are not allowed under asan.
if (LI->getParent()->getParent()->hasFnAttribute(
if (Load->getParent()->getParent()->hasFnAttribute(
Attribute::SanitizeAddress) ||
LI->getParent()->getParent()->hasFnAttribute(
Load->getParent()->getParent()->hasFnAttribute(
Attribute::SanitizeHWAddress))
return false;
// Step 1: Find the non-local dependencies of the load.
LoadDepVect Deps;
MD->getNonLocalPointerDependency(LI, Deps);
MD->getNonLocalPointerDependency(Load, Deps);
// If we had to process more than one hundred blocks to find the
// dependencies, this load isn't worth worrying about. Optimizing
@ -1479,14 +1481,15 @@ bool GVN::processNonLocalLoad(LoadInst *LI) {
// clobber in the current block. Reject this early.
if (NumDeps == 1 &&
!Deps[0].getResult().isDef() && !Deps[0].getResult().isClobber()) {
LLVM_DEBUG(dbgs() << "GVN: non-local load "; LI->printAsOperand(dbgs());
LLVM_DEBUG(dbgs() << "GVN: non-local load "; Load->printAsOperand(dbgs());
dbgs() << " has unknown dependencies\n";);
return false;
}
bool Changed = false;
// If this load follows a GEP, see if we can PRE the indices before analyzing.
if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(LI->getOperand(0))) {
if (GetElementPtrInst *GEP =
dyn_cast<GetElementPtrInst>(Load->getOperand(0))) {
for (GetElementPtrInst::op_iterator OI = GEP->idx_begin(),
OE = GEP->idx_end();
OI != OE; ++OI)
@ -1497,7 +1500,7 @@ bool GVN::processNonLocalLoad(LoadInst *LI) {
// Step 2: Analyze the availability of the load
AvailValInBlkVect ValuesPerBlock;
UnavailBlkVect UnavailableBlocks;
AnalyzeLoadAvailability(LI, Deps, ValuesPerBlock, UnavailableBlocks);
AnalyzeLoadAvailability(Load, Deps, ValuesPerBlock, UnavailableBlocks);
// If we have no predecessors that produce a known value for this load, exit
// early.
@ -1510,36 +1513,35 @@ bool GVN::processNonLocalLoad(LoadInst *LI) {
// load, then it is fully redundant and we can use PHI insertion to compute
// its value. Insert PHIs and remove the fully redundant value now.
if (UnavailableBlocks.empty()) {
LLVM_DEBUG(dbgs() << "GVN REMOVING NONLOCAL LOAD: " << *LI << '\n');
LLVM_DEBUG(dbgs() << "GVN REMOVING NONLOCAL LOAD: " << *Load << '\n');
// Perform PHI construction.
Value *V = ConstructSSAForLoadSet(LI, ValuesPerBlock, *this);
LI->replaceAllUsesWith(V);
Value *V = ConstructSSAForLoadSet(Load, ValuesPerBlock, *this);
Load->replaceAllUsesWith(V);
if (isa<PHINode>(V))
V->takeName(LI);
V->takeName(Load);
if (Instruction *I = dyn_cast<Instruction>(V))
// If instruction I has debug info, then we should not update it.
// Also, if I has a null DebugLoc, then it is still potentially incorrect
// to propagate LI's DebugLoc because LI may not post-dominate I.
if (LI->getDebugLoc() && LI->getParent() == I->getParent())
I->setDebugLoc(LI->getDebugLoc());
// to propagate Load's DebugLoc because Load may not post-dominate I.
if (Load->getDebugLoc() && Load->getParent() == I->getParent())
I->setDebugLoc(Load->getDebugLoc());
if (V->getType()->isPtrOrPtrVectorTy())
MD->invalidateCachedPointerInfo(V);
markInstructionForDeletion(LI);
markInstructionForDeletion(Load);
++NumGVNLoad;
reportLoadElim(LI, V, ORE);
reportLoadElim(Load, V, ORE);
return true;
}
// Step 4: Eliminate partial redundancy.
if (!isPREEnabled() || !isLoadPREEnabled())
return Changed;
if (!isLoadInLoopPREEnabled() && this->LI &&
this->LI->getLoopFor(LI->getParent()))
if (!isLoadInLoopPREEnabled() && LI && LI->getLoopFor(Load->getParent()))
return Changed;
return Changed || PerformLoadPRE(LI, ValuesPerBlock, UnavailableBlocks);
return Changed || PerformLoadPRE(Load, ValuesPerBlock, UnavailableBlocks);
}
static bool impliesEquivalanceIfTrue(CmpInst* Cmp) {
@ -2190,12 +2192,12 @@ bool GVN::processInstruction(Instruction *I) {
if (IntrinsicI->getIntrinsicID() == Intrinsic::assume)
return processAssumeIntrinsic(IntrinsicI);
if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
if (processLoad(LI))
if (LoadInst *Load = dyn_cast<LoadInst>(I)) {
if (processLoad(Load))
return true;
unsigned Num = VN.lookupOrAdd(LI);
addToLeaderTable(Num, LI, LI->getParent());
unsigned Num = VN.lookupOrAdd(Load);
addToLeaderTable(Num, Load, Load->getParent());
return false;
}
@ -2299,7 +2301,7 @@ bool GVN::processInstruction(Instruction *I) {
/// runOnFunction - This is the main transformation entry point for a function.
bool GVN::runImpl(Function &F, AssumptionCache &RunAC, DominatorTree &RunDT,
const TargetLibraryInfo &RunTLI, AAResults &RunAA,
MemoryDependenceResults *RunMD, LoopInfo *LI,
MemoryDependenceResults *RunMD, LoopInfo *Load,
OptimizationRemarkEmitter *RunORE, MemorySSA *MSSA) {
AC = &RunAC;
DT = &RunDT;
@ -2309,7 +2311,7 @@ bool GVN::runImpl(Function &F, AssumptionCache &RunAC, DominatorTree &RunDT,
MD = RunMD;
ImplicitControlFlowTracking ImplicitCFT;
ICF = &ImplicitCFT;
this->LI = LI;
this->LI = Load;
VN.setMemDep(MD);
ORE = RunORE;
InvalidBlockRPONumbers = true;
@ -2325,7 +2327,7 @@ bool GVN::runImpl(Function &F, AssumptionCache &RunAC, DominatorTree &RunDT,
for (Function::iterator FI = F.begin(), FE = F.end(); FI != FE; ) {
BasicBlock *BB = &*FI++;
bool removedBlock = MergeBlockIntoPredecessor(BB, &DTU, LI, MSSAU, MD);
bool removedBlock = MergeBlockIntoPredecessor(BB, &DTU, Load, MSSAU, MD);
if (removedBlock)
++NumGVNBlocks;