Skip to content

Commit b4e2bbc

Browse files
momchil-velikovantoniofrighetto
authored andcommitted
[GVN] MemorySSA for GVN: embed the memory state in symbolic expressions
While migrating towards MemorySSA, account for the memory state modeled by MemorySSA by hashing it, when computing the symbolic expressions for the memory operations. Likewise, when phi-translating while walking the CFG for PRE possibilities, see if the value number of an operand may be refined with one of the value from the incoming edges of the MemoryPhi associated to the current phi.
1 parent d7afafd commit b4e2bbc

File tree

2 files changed

+95
-5
lines changed
  • llvm
    • include/llvm/Transforms/Scalar
    • lib/Transforms/Scalar

2 files changed

+95
-5
lines changed

llvm/include/llvm/Transforms/Scalar/GVN.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,9 @@ class ImplicitControlFlowTracking;
4646
class LoadInst;
4747
class LoopInfo;
4848
class MemDepResult;
49+
class MemoryAccess;
4950
class MemoryDependenceResults;
51+
class MemoryLocation;
5052
class MemorySSA;
5153
class MemorySSAUpdater;
5254
class NonLocalDepResult;
@@ -172,13 +174,18 @@ class GVNPass : public PassInfoMixin<GVNPass> {
172174
// Value number to PHINode mapping. Used for phi-translate in scalarpre.
173175
DenseMap<uint32_t, PHINode *> NumberingPhi;
174176

177+
// Value number to BasicBlock mapping. Used for phi-translate across
178+
// MemoryPhis.
179+
DenseMap<uint32_t, BasicBlock *> NumberingBB;
180+
175181
// Cache for phi-translate in scalarpre.
176182
using PhiTranslateMap =
177183
DenseMap<std::pair<uint32_t, const BasicBlock *>, uint32_t>;
178184
PhiTranslateMap PhiTranslateTable;
179185

180186
AAResults *AA = nullptr;
181187
MemoryDependenceResults *MD = nullptr;
188+
MemorySSA *MSSA = nullptr;
182189
DominatorTree *DT = nullptr;
183190

184191
uint32_t NextValueNumber = 1;
@@ -189,12 +196,14 @@ class GVNPass : public PassInfoMixin<GVNPass> {
189196
Expression createExtractvalueExpr(ExtractValueInst *EI);
190197
Expression createGEPExpr(GetElementPtrInst *GEP);
191198
uint32_t lookupOrAddCall(CallInst *C);
199+
uint32_t lookupOrAddLoadStore(Instruction *I);
192200
uint32_t phiTranslateImpl(const BasicBlock *BB, const BasicBlock *PhiBlock,
193201
uint32_t Num, GVNPass &GVN);
194202
bool areCallValsEqual(uint32_t Num, uint32_t NewNum, const BasicBlock *Pred,
195203
const BasicBlock *PhiBlock, GVNPass &GVN);
196204
std::pair<uint32_t, bool> assignExpNewValueNum(Expression &Exp);
197205
bool areAllValsInBB(uint32_t Num, const BasicBlock *BB, GVNPass &GVN);
206+
void addMemoryStateToExp(Instruction *I, Expression &Exp);
198207

199208
public:
200209
ValueTable();
@@ -203,6 +212,7 @@ class GVNPass : public PassInfoMixin<GVNPass> {
203212
~ValueTable();
204213
ValueTable &operator=(const ValueTable &Arg);
205214

215+
uint32_t lookupOrAdd(MemoryAccess *MA);
206216
uint32_t lookupOrAdd(Value *V);
207217
uint32_t lookup(Value *V, bool Verify = true) const;
208218
uint32_t lookupOrAddCmp(unsigned Opcode, CmpInst::Predicate Pred,
@@ -217,6 +227,7 @@ class GVNPass : public PassInfoMixin<GVNPass> {
217227
void setAliasAnalysis(AAResults *A) { AA = A; }
218228
AAResults *getAliasAnalysis() const { return AA; }
219229
void setMemDep(MemoryDependenceResults *M) { MD = M; }
230+
void setMemorySSA(MemorySSA *M) { MSSA = M; }
220231
void setDomTree(DominatorTree *D) { DT = D; }
221232
uint32_t getNextUnusedValueNumber() { return NextValueNumber; }
222233
void verifyRemoved(const Value *) const;

llvm/lib/Transforms/Scalar/GVN.cpp

Lines changed: 84 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,19 @@ void GVNPass::ValueTable::add(Value *V, uint32_t Num) {
475475
NumberingPhi[Num] = PN;
476476
}
477477

478+
// Include the incoming memory state into the hash of the expression for the
479+
// given instruction. If the incoming memory state is:
480+
// * LiveOnEntry, add the value number of the entry block,
481+
// * a MemoryPhi, add the value number of the basic block corresponding to that
482+
// MemoryPhi,
483+
// * a MemoryDef, add the value number of the memory setting instruction.
484+
void GVNPass::ValueTable::addMemoryStateToExp(Instruction *I, Expression &Exp) {
485+
assert(MSSA && "addMemoryStateToExp should not be called without MemorySSA");
486+
assert(MSSA->getMemoryAccess(I) && "Instruction does not access memory");
487+
MemoryAccess *MA = MSSA->getSkipSelfWalker()->getClobberingMemoryAccess(I);
488+
Exp.VarArgs.push_back(lookupOrAdd(MA));
489+
}
490+
478491
uint32_t GVNPass::ValueTable::lookupOrAddCall(CallInst *C) {
479492
// FIXME: Currently the calls which may access the thread id may
480493
// be considered as not accessing the memory. But this is
@@ -595,15 +608,48 @@ uint32_t GVNPass::ValueTable::lookupOrAddCall(CallInst *C) {
595608
return V;
596609
}
597610

611+
if (MSSA && AA->onlyReadsMemory(C)) {
612+
Expression Exp = createExpr(C);
613+
addMemoryStateToExp(C, Exp);
614+
auto [V, _] = assignExpNewValueNum(Exp);
615+
ValueNumbering[C] = V;
616+
return V;
617+
}
618+
598619
ValueNumbering[C] = NextValueNumber;
599620
return NextValueNumber++;
600621
}
601622

623+
/// Returns the value number for the specified load or store instruction.
624+
uint32_t GVNPass::ValueTable::lookupOrAddLoadStore(Instruction *I) {
625+
if (!MSSA) {
626+
ValueNumbering[I] = NextValueNumber;
627+
return NextValueNumber++;
628+
}
629+
630+
Expression Exp;
631+
Exp.Ty = I->getType();
632+
Exp.Opcode = I->getOpcode();
633+
for (Use &Op : I->operands())
634+
Exp.VarArgs.push_back(lookupOrAdd(Op));
635+
addMemoryStateToExp(I, Exp);
636+
637+
auto [V, _] = assignExpNewValueNum(Exp);
638+
ValueNumbering[I] = V;
639+
return V;
640+
}
641+
602642
/// Returns true if a value number exists for the specified value.
603643
bool GVNPass::ValueTable::exists(Value *V) const {
604644
return ValueNumbering.contains(V);
605645
}
606646

647+
uint32_t GVNPass::ValueTable::lookupOrAdd(MemoryAccess *MA) {
648+
return MSSA->isLiveOnEntryDef(MA) || isa<MemoryPhi>(MA)
649+
? lookupOrAdd(MA->getBlock())
650+
: lookupOrAdd(cast<MemoryUseOrDef>(MA)->getMemoryInst());
651+
}
652+
607653
/// lookupOrAdd - Returns the value number for the specified value, assigning
608654
/// it a new number if it did not have one before.
609655
uint32_t GVNPass::ValueTable::lookupOrAdd(Value *V) {
@@ -614,6 +660,8 @@ uint32_t GVNPass::ValueTable::lookupOrAdd(Value *V) {
614660
auto *I = dyn_cast<Instruction>(V);
615661
if (!I) {
616662
ValueNumbering[V] = NextValueNumber;
663+
if (isa<BasicBlock>(V))
664+
NumberingBB[NextValueNumber] = cast<BasicBlock>(V);
617665
return NextValueNumber++;
618666
}
619667

@@ -673,6 +721,9 @@ uint32_t GVNPass::ValueTable::lookupOrAdd(Value *V) {
673721
ValueNumbering[V] = NextValueNumber;
674722
NumberingPhi[NextValueNumber] = cast<PHINode>(V);
675723
return NextValueNumber++;
724+
case Instruction::Load:
725+
case Instruction::Store:
726+
return lookupOrAddLoadStore(I);
676727
default:
677728
ValueNumbering[V] = NextValueNumber;
678729
return NextValueNumber++;
@@ -710,6 +761,7 @@ void GVNPass::ValueTable::clear() {
710761
ValueNumbering.clear();
711762
ExpressionNumbering.clear();
712763
NumberingPhi.clear();
764+
NumberingBB.clear();
713765
PhiTranslateTable.clear();
714766
NextValueNumber = 1;
715767
Expressions.clear();
@@ -724,6 +776,8 @@ void GVNPass::ValueTable::erase(Value *V) {
724776
// If V is PHINode, V <--> value number is an one-to-one mapping.
725777
if (isa<PHINode>(V))
726778
NumberingPhi.erase(Num);
779+
else if (isa<BasicBlock>(V))
780+
NumberingBB.erase(Num);
727781
}
728782

729783
/// verifyRemoved - Verify that the value is removed from all internal data
@@ -2295,15 +2349,39 @@ bool GVNPass::ValueTable::areCallValsEqual(uint32_t Num, uint32_t NewNum,
22952349
uint32_t GVNPass::ValueTable::phiTranslateImpl(const BasicBlock *Pred,
22962350
const BasicBlock *PhiBlock,
22972351
uint32_t Num, GVNPass &GVN) {
2352+
// See if we can refine the value number by looking at the PN incoming value
2353+
// for the given predecessor.
22982354
if (PHINode *PN = NumberingPhi[Num]) {
2299-
for (unsigned I = 0; I != PN->getNumIncomingValues(); ++I) {
2300-
if (PN->getParent() == PhiBlock && PN->getIncomingBlock(I) == Pred)
2301-
if (uint32_t TransVal = lookup(PN->getIncomingValue(I), false))
2302-
return TransVal;
2303-
}
2355+
if (PN->getParent() == PhiBlock)
2356+
for (unsigned I = 0; I != PN->getNumIncomingValues(); ++I)
2357+
if (PN->getIncomingBlock(I) == Pred)
2358+
if (uint32_t TransVal = lookup(PN->getIncomingValue(I), false))
2359+
return TransVal;
23042360
return Num;
23052361
}
23062362

2363+
if (BasicBlock *BB = NumberingBB[Num]) {
2364+
assert(MSSA && "NumberingBB is non-empty only when using MemorySSA");
2365+
// Value numbers of basic blocks are used to represent memory state in
2366+
// load/store instructions and read-only function calls when said state is
2367+
// set by a MemoryPhi.
2368+
if (BB != PhiBlock)
2369+
return Num;
2370+
MemoryPhi *MPhi = MSSA->getMemoryAccess(BB);
2371+
for (unsigned i = 0, N = MPhi->getNumIncomingValues(); i != N; ++i) {
2372+
if (MPhi->getIncomingBlock(i) != Pred)
2373+
continue;
2374+
MemoryAccess *MA = MPhi->getIncomingValue(i);
2375+
if (auto *PredPhi = dyn_cast<MemoryPhi>(MA))
2376+
return lookupOrAdd(PredPhi->getBlock());
2377+
if (MSSA->isLiveOnEntryDef(MA))
2378+
return lookupOrAdd(&BB->getParent()->getEntryBlock());
2379+
return lookupOrAdd(cast<MemoryUseOrDef>(MA)->getMemoryInst());
2380+
}
2381+
llvm_unreachable(
2382+
"CFG/MemorySSA mismatch: predecessor not found among incoming blocks");
2383+
}
2384+
23072385
// If there is any value related with Num is defined in a BB other than
23082386
// PhiBlock, it cannot depend on a phi in PhiBlock without going through
23092387
// a backedge. We can do an early exit in that case to save compile time.
@@ -2738,6 +2816,7 @@ bool GVNPass::runImpl(Function &F, AssumptionCache &RunAC, DominatorTree &RunDT,
27382816
ICF = &ImplicitCFT;
27392817
this->LI = &LI;
27402818
VN.setMemDep(MD);
2819+
VN.setMemorySSA(MSSA);
27412820
ORE = RunORE;
27422821
InvalidBlockRPONumbers = true;
27432822
MemorySSAUpdater Updater(MSSA);

0 commit comments

Comments
 (0)