Skip to content

Commit dec6f01

Browse files
committed
RPO Leader
1 parent 69fecaa commit dec6f01

File tree

3 files changed

+51
-22
lines changed

3 files changed

+51
-22
lines changed

llvm/lib/Transforms/Scalar/NewGVN.cpp

Lines changed: 46 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,8 @@ class CongruenceClass {
297297
using MemoryMemberSet = SmallPtrSet<const MemoryMemberType *, 2>;
298298

299299
explicit CongruenceClass(unsigned ID) : ID(ID) {}
300-
CongruenceClass(unsigned ID, Value *Leader, const Expression *E)
300+
CongruenceClass(unsigned ID, std::pair<Value *, unsigned int> Leader,
301+
const Expression *E)
301302
: ID(ID), RepLeader(Leader), DefiningExpr(E) {}
302303

303304
unsigned getID() const { return ID; }
@@ -311,15 +312,23 @@ class CongruenceClass {
311312
}
312313

313314
// Leader functions
314-
Value *getLeader() const { return RepLeader; }
315-
void setLeader(Value *Leader) { RepLeader = Leader; }
315+
Value *getLeader() const { return RepLeader.first; }
316+
void setLeader(std::pair<Value *, unsigned int> Leader) {
317+
RepLeader = Leader;
318+
}
316319
const std::pair<Value *, unsigned int> &getNextLeader() const {
317320
return NextLeader;
318321
}
319322
void resetNextLeader() { NextLeader = {nullptr, ~0}; }
320-
void addPossibleNextLeader(std::pair<Value *, unsigned int> LeaderPair) {
321-
if (LeaderPair.second < NextLeader.second)
323+
bool addPossibleLeader(std::pair<Value *, unsigned int> LeaderPair) {
324+
if (LeaderPair.second < RepLeader.second) {
325+
NextLeader = RepLeader;
326+
RepLeader = LeaderPair;
327+
return true;
328+
} else if (LeaderPair.second < NextLeader.second) {
322329
NextLeader = LeaderPair;
330+
}
331+
return false;
323332
}
324333

325334
Value *getStoredValue() const { return RepStoredValue; }
@@ -392,11 +401,13 @@ class CongruenceClass {
392401
private:
393402
unsigned ID;
394403

395-
// Representative leader.
396-
Value *RepLeader = nullptr;
404+
// Representative leader and its corresponding RPO number.
405+
// The leader must have the lowest RPO number.
406+
std::pair<Value *, unsigned int> RepLeader = {nullptr, ~0U};
397407

398-
// The most dominating leader after our current leader, because the member set
399-
// is not sorted and is expensive to keep sorted all the time.
408+
// The most dominating leader after our current leader (given by the RPO
409+
// number), because the member set is not sorted and is expensive to keep
410+
// sorted all the time.
400411
std::pair<Value *, unsigned int> NextLeader = {nullptr, ~0U};
401412

402413
// If this is represented by a store, the value of the store.
@@ -735,7 +746,19 @@ class NewGVN {
735746

736747
// Congruence class handling.
737748
CongruenceClass *createCongruenceClass(Value *Leader, const Expression *E) {
738-
auto *result = new CongruenceClass(NextCongruenceNum++, Leader, E);
749+
// Set RPO to 0 for values that are always available (constants and function
750+
// args). These should always be made leader.
751+
unsigned LeaderDFS = 0;
752+
753+
// If Leader is not specified, either we have a memory class or the leader
754+
// will be set later. Otherwise, if Leader is an Instruction, set LeaderDFS
755+
// to its RPO number.
756+
if (!Leader)
757+
LeaderDFS = ~0;
758+
else if (auto *I = dyn_cast<Instruction>(Leader))
759+
LeaderDFS = InstrToDFSNum(I);
760+
auto *result =
761+
new CongruenceClass(NextCongruenceNum++, {Leader, LeaderDFS}, E);
739762
CongruenceClasses.emplace_back(result);
740763
return result;
741764
}
@@ -2248,8 +2271,13 @@ void NewGVN::moveValueToNewCongruenceClass(Instruction *I, const Expression *E,
22482271
OldClass->erase(I);
22492272
NewClass->insert(I);
22502273

2251-
if (NewClass->getLeader() != I)
2252-
NewClass->addPossibleNextLeader({I, InstrToDFSNum(I)});
2274+
// Ensure that the leader has the lowest RPO. If the leader changed notify all
2275+
// members of the class.
2276+
if (NewClass->getLeader() != I &&
2277+
NewClass->addPossibleLeader({I, InstrToDFSNum(I)})) {
2278+
markValueLeaderChangeTouched(NewClass);
2279+
}
2280+
22532281
// Handle our special casing of stores.
22542282
if (auto *SI = dyn_cast<StoreInst>(I)) {
22552283
OldClass->decStoreCount();
@@ -2273,7 +2301,7 @@ void NewGVN::moveValueToNewCongruenceClass(Instruction *I, const Expression *E,
22732301
<< " because store joined class\n");
22742302
// If we changed the leader, we have to mark it changed because we don't
22752303
// know what it will do to symbolic evaluation.
2276-
NewClass->setLeader(SI);
2304+
NewClass->setLeader({SI, InstrToDFSNum(SI)});
22772305
}
22782306
// We rely on the code below handling the MemoryAccess change.
22792307
}
@@ -2319,7 +2347,8 @@ void NewGVN::moveValueToNewCongruenceClass(Instruction *I, const Expression *E,
23192347
if (OldClass->getStoredValue())
23202348
OldClass->setStoredValue(nullptr);
23212349
}
2322-
OldClass->setLeader(getNextValueLeader(OldClass));
2350+
OldClass->setLeader({getNextValueLeader(OldClass),
2351+
InstrToDFSNum(getNextValueLeader(OldClass))});
23232352
OldClass->resetNextLeader();
23242353
markValueLeaderChangeTouched(OldClass);
23252354
}
@@ -2358,15 +2387,15 @@ void NewGVN::performCongruenceFinding(Instruction *I, const Expression *E) {
23582387

23592388
// Constants and variables should always be made the leader.
23602389
if (const auto *CE = dyn_cast<ConstantExpression>(E)) {
2361-
NewClass->setLeader(CE->getConstantValue());
2390+
NewClass->setLeader({CE->getConstantValue(), 0});
23622391
} else if (const auto *SE = dyn_cast<StoreExpression>(E)) {
23632392
StoreInst *SI = SE->getStoreInst();
2364-
NewClass->setLeader(SI);
2393+
NewClass->setLeader({SI, InstrToDFSNum(SI)});
23652394
NewClass->setStoredValue(SE->getStoredValue());
23662395
// The RepMemoryAccess field will be filled in properly by the
23672396
// moveValueToNewCongruenceClass call.
23682397
} else {
2369-
NewClass->setLeader(I);
2398+
NewClass->setLeader({I, InstrToDFSNum(I)});
23702399
}
23712400
assert(!isa<VariableExpression>(E) &&
23722401
"VariableExpression should have been handled already");
@@ -3253,7 +3282,6 @@ void NewGVN::verifyMemoryCongruency() const {
32533282
return ReachableEdges.count(
32543283
{FirstMP->getIncomingBlock(U), FirstMP->getBlock()}) &&
32553284
isa<MemoryDef>(U);
3256-
32573285
};
32583286
// All arguments should in the same class, ignoring unreachable arguments
32593287
auto FilteredPhiArgs =

llvm/test/Transforms/NewGVN/todo-pr36335-phi-undef.ll renamed to llvm/test/Transforms/NewGVN/pr36335-phi-undef.ll

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
22
; RUN: opt -passes=newgvn -S %s | FileCheck %s
33

4-
; TODO: NewGVN currently miscomiles the function below. PR36335.
5-
64
declare void @foo(i32)
75

86
define void @main(i1 %c1, i1 %c2, i32 %x) {
@@ -11,7 +9,8 @@ define void @main(i1 %c1, i1 %c2, i32 %x) {
119
; CHECK-NEXT: br i1 [[C1:%.*]], label [[L:%.*]], label [[END:%.*]]
1210
; CHECK: L:
1311
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X:%.*]], -1
14-
; CHECK-NEXT: call void @foo(i32 [[XOR]])
12+
; CHECK-NEXT: [[NEG:%.*]] = xor i32 [[XOR]], -1
13+
; CHECK-NEXT: call void @foo(i32 [[NEG]])
1514
; CHECK-NEXT: br label [[L]]
1615
; CHECK: end:
1716
; CHECK-NEXT: ret void

llvm/test/Transforms/NewGVN/simp-to-self.ll

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@ define void @fn1(i1 %bc) {
1212
; CHECK-NEXT: [[LV:%.*]] = load i32, ptr @a, align 4
1313
; CHECK-NEXT: [[BF_CLEAR:%.*]] = and i32 [[LV]], -131072
1414
; CHECK-NEXT: [[BF_SET:%.*]] = or i32 1, [[BF_CLEAR]]
15+
; CHECK-NEXT: [[BF_CLEAR_1:%.*]] = and i32 [[BF_SET]], -131072
16+
; CHECK-NEXT: [[BF_SET_1:%.*]] = or i32 1, [[BF_CLEAR_1]]
1517
; CHECK-NEXT: br i1 [[BC]], label [[FOR_COND]], label [[EXIT:%.*]]
1618
; CHECK: exit:
17-
; CHECK-NEXT: store i32 [[BF_SET]], ptr @a, align 4
19+
; CHECK-NEXT: store i32 [[BF_SET_1]], ptr @a, align 4
1820
; CHECK-NEXT: ret void
1921
;
2022
entry:

0 commit comments

Comments
 (0)