Skip to content

Commit d3f13a0

Browse files
[GVN] MemorySSA for GVN: embed the memory state in symbolic expressions (#123218)
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. Co-authored-by: Momchil Velikov <[email protected]>
1 parent 71f72f4 commit d3f13a0

File tree

2 files changed

+104
-6
lines changed
  • llvm
    • include/llvm/Transforms/Scalar
    • lib/Transforms/Scalar

2 files changed

+104
-6
lines changed

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

Lines changed: 20 additions & 1 deletion
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;
@@ -170,13 +172,20 @@ class GVNPass : public PassInfoMixin<GVNPass> {
170172
// Value number to PHINode mapping. Used for phi-translate in scalarpre.
171173
DenseMap<uint32_t, PHINode *> NumberingPhi;
172174

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

178184
AAResults *AA = nullptr;
179185
MemoryDependenceResults *MD = nullptr;
186+
bool IsMDEnabled = false;
187+
MemorySSA *MSSA = nullptr;
188+
bool IsMSSAEnabled = false;
180189
DominatorTree *DT = nullptr;
181190

182191
uint32_t NextValueNumber = 1;
@@ -187,12 +196,14 @@ class GVNPass : public PassInfoMixin<GVNPass> {
187196
Expression createExtractvalueExpr(ExtractValueInst *EI);
188197
Expression createGEPExpr(GetElementPtrInst *GEP);
189198
uint32_t lookupOrAddCall(CallInst *C);
199+
uint32_t computeLoadStoreVN(Instruction *I);
190200
uint32_t phiTranslateImpl(const BasicBlock *BB, const BasicBlock *PhiBlock,
191201
uint32_t Num, GVNPass &GVN);
192202
bool areCallValsEqual(uint32_t Num, uint32_t NewNum, const BasicBlock *Pred,
193203
const BasicBlock *PhiBlock, GVNPass &GVN);
194204
std::pair<uint32_t, bool> assignExpNewValueNum(Expression &Exp);
195205
bool areAllValsInBB(uint32_t Num, const BasicBlock *BB, GVNPass &GVN);
206+
void addMemoryStateToExp(Instruction *I, Expression &Exp);
196207

197208
public:
198209
LLVM_ABI ValueTable();
@@ -201,6 +212,7 @@ class GVNPass : public PassInfoMixin<GVNPass> {
201212
LLVM_ABI ~ValueTable();
202213
LLVM_ABI ValueTable &operator=(const ValueTable &Arg);
203214

215+
LLVM_ABI uint32_t lookupOrAdd(MemoryAccess *MA);
204216
LLVM_ABI uint32_t lookupOrAdd(Value *V);
205217
LLVM_ABI uint32_t lookup(Value *V, bool Verify = true) const;
206218
LLVM_ABI uint32_t lookupOrAddCmp(unsigned Opcode, CmpInst::Predicate Pred,
@@ -216,7 +228,14 @@ class GVNPass : public PassInfoMixin<GVNPass> {
216228
LLVM_ABI void erase(Value *V);
217229
void setAliasAnalysis(AAResults *A) { AA = A; }
218230
AAResults *getAliasAnalysis() const { return AA; }
219-
void setMemDep(MemoryDependenceResults *M) { MD = M; }
231+
void setMemDep(MemoryDependenceResults *M, bool MDEnabled = true) {
232+
MD = M;
233+
IsMDEnabled = MDEnabled;
234+
}
235+
void setMemorySSA(MemorySSA *M, bool MSSAEnabled = false) {
236+
MSSA = M;
237+
IsMSSAEnabled = MSSAEnabled;
238+
}
220239
void setDomTree(DominatorTree *D) { DT = D; }
221240
uint32_t getNextUnusedValueNumber() { return NextValueNumber; }
222241
LLVM_ABI 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
@@ -474,6 +474,19 @@ void GVNPass::ValueTable::add(Value *V, uint32_t Num) {
474474
NumberingPhi[Num] = PN;
475475
}
476476

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

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

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

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

@@ -672,6 +720,9 @@ uint32_t GVNPass::ValueTable::lookupOrAdd(Value *V) {
672720
ValueNumbering[V] = NextValueNumber;
673721
NumberingPhi[NextValueNumber] = cast<PHINode>(V);
674722
return NextValueNumber++;
723+
case Instruction::Load:
724+
case Instruction::Store:
725+
return computeLoadStoreVN(I);
675726
default:
676727
ValueNumbering[V] = NextValueNumber;
677728
return NextValueNumber++;
@@ -709,6 +760,7 @@ void GVNPass::ValueTable::clear() {
709760
ValueNumbering.clear();
710761
ExpressionNumbering.clear();
711762
NumberingPhi.clear();
763+
NumberingBB.clear();
712764
PhiTranslateTable.clear();
713765
NextValueNumber = 1;
714766
Expressions.clear();
@@ -723,6 +775,8 @@ void GVNPass::ValueTable::erase(Value *V) {
723775
// If V is PHINode, V <--> value number is an one-to-one mapping.
724776
if (isa<PHINode>(V))
725777
NumberingPhi.erase(Num);
778+
else if (isa<BasicBlock>(V))
779+
NumberingBB.erase(Num);
726780
}
727781

728782
/// verifyRemoved - Verify that the value is removed from all internal data
@@ -2310,15 +2364,39 @@ bool GVNPass::ValueTable::areCallValsEqual(uint32_t Num, uint32_t NewNum,
23102364
uint32_t GVNPass::ValueTable::phiTranslateImpl(const BasicBlock *Pred,
23112365
const BasicBlock *PhiBlock,
23122366
uint32_t Num, GVNPass &GVN) {
2367+
// See if we can refine the value number by looking at the PN incoming value
2368+
// for the given predecessor.
23132369
if (PHINode *PN = NumberingPhi[Num]) {
2314-
for (unsigned I = 0; I != PN->getNumIncomingValues(); ++I) {
2315-
if (PN->getParent() == PhiBlock && PN->getIncomingBlock(I) == Pred)
2316-
if (uint32_t TransVal = lookup(PN->getIncomingValue(I), false))
2317-
return TransVal;
2318-
}
2370+
if (PN->getParent() == PhiBlock)
2371+
for (unsigned I = 0; I != PN->getNumIncomingValues(); ++I)
2372+
if (PN->getIncomingBlock(I) == Pred)
2373+
if (uint32_t TransVal = lookup(PN->getIncomingValue(I), false))
2374+
return TransVal;
23192375
return Num;
23202376
}
23212377

2378+
if (BasicBlock *BB = NumberingBB[Num]) {
2379+
assert(MSSA && "NumberingBB is non-empty only when using MemorySSA");
2380+
// Value numbers of basic blocks are used to represent memory state in
2381+
// load/store instructions and read-only function calls when said state is
2382+
// set by a MemoryPhi.
2383+
if (BB != PhiBlock)
2384+
return Num;
2385+
MemoryPhi *MPhi = MSSA->getMemoryAccess(BB);
2386+
for (unsigned i = 0, N = MPhi->getNumIncomingValues(); i != N; ++i) {
2387+
if (MPhi->getIncomingBlock(i) != Pred)
2388+
continue;
2389+
MemoryAccess *MA = MPhi->getIncomingValue(i);
2390+
if (auto *PredPhi = dyn_cast<MemoryPhi>(MA))
2391+
return lookupOrAdd(PredPhi->getBlock());
2392+
if (MSSA->isLiveOnEntryDef(MA))
2393+
return lookupOrAdd(&BB->getParent()->getEntryBlock());
2394+
return lookupOrAdd(cast<MemoryUseOrDef>(MA)->getMemoryInst());
2395+
}
2396+
llvm_unreachable(
2397+
"CFG/MemorySSA mismatch: predecessor not found among incoming blocks");
2398+
}
2399+
23222400
// If there is any value related with Num is defined in a BB other than
23232401
// PhiBlock, it cannot depend on a phi in PhiBlock without going through
23242402
// a backedge. We can do an early exit in that case to save compile time.
@@ -2761,6 +2839,7 @@ bool GVNPass::runImpl(Function &F, AssumptionCache &RunAC, DominatorTree &RunDT,
27612839
ICF = &ImplicitCFT;
27622840
this->LI = &LI;
27632841
VN.setMemDep(MD);
2842+
VN.setMemorySSA(MSSA);
27642843
ORE = RunORE;
27652844
InvalidBlockRPONumbers = true;
27662845
MemorySSAUpdater Updater(MSSA);

0 commit comments

Comments
 (0)