Skip to content

Commit 16217ce

Browse files
committed
RPO Leader
1 parent b5657d6 commit 16217ce

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.
@@ -731,7 +742,19 @@ class NewGVN {
731742

732743
// Congruence class handling.
733744
CongruenceClass *createCongruenceClass(Value *Leader, const Expression *E) {
734-
auto *result = new CongruenceClass(NextCongruenceNum++, Leader, E);
745+
// Set RPO to 0 for values that are always available (constants and function
746+
// args). These should always be made leader.
747+
unsigned LeaderDFS = 0;
748+
749+
// If Leader is not specified, either we have a memory class or the leader
750+
// will be set later. Otherwise, if Leader is an Instruction, set LeaderDFS
751+
// to its RPO number.
752+
if (!Leader)
753+
LeaderDFS = ~0;
754+
else if (auto *I = dyn_cast<Instruction>(Leader))
755+
LeaderDFS = InstrToDFSNum(I);
756+
auto *result =
757+
new CongruenceClass(NextCongruenceNum++, {Leader, LeaderDFS}, E);
735758
CongruenceClasses.emplace_back(result);
736759
return result;
737760
}
@@ -2244,8 +2267,13 @@ void NewGVN::moveValueToNewCongruenceClass(Instruction *I, const Expression *E,
22442267
OldClass->erase(I);
22452268
NewClass->insert(I);
22462269

2247-
if (NewClass->getLeader() != I)
2248-
NewClass->addPossibleNextLeader({I, InstrToDFSNum(I)});
2270+
// Ensure that the leader has the lowest RPO. If the leader changed notify all
2271+
// members of the class.
2272+
if (NewClass->getLeader() != I &&
2273+
NewClass->addPossibleLeader({I, InstrToDFSNum(I)})) {
2274+
markValueLeaderChangeTouched(NewClass);
2275+
}
2276+
22492277
// Handle our special casing of stores.
22502278
if (auto *SI = dyn_cast<StoreInst>(I)) {
22512279
OldClass->decStoreCount();
@@ -2269,7 +2297,7 @@ void NewGVN::moveValueToNewCongruenceClass(Instruction *I, const Expression *E,
22692297
<< " because store joined class\n");
22702298
// If we changed the leader, we have to mark it changed because we don't
22712299
// know what it will do to symbolic evaluation.
2272-
NewClass->setLeader(SI);
2300+
NewClass->setLeader({SI, InstrToDFSNum(SI)});
22732301
}
22742302
// We rely on the code below handling the MemoryAccess change.
22752303
}
@@ -2315,7 +2343,8 @@ void NewGVN::moveValueToNewCongruenceClass(Instruction *I, const Expression *E,
23152343
if (OldClass->getStoredValue())
23162344
OldClass->setStoredValue(nullptr);
23172345
}
2318-
OldClass->setLeader(getNextValueLeader(OldClass));
2346+
OldClass->setLeader({getNextValueLeader(OldClass),
2347+
InstrToDFSNum(getNextValueLeader(OldClass))});
23192348
OldClass->resetNextLeader();
23202349
markValueLeaderChangeTouched(OldClass);
23212350
}
@@ -2354,15 +2383,15 @@ void NewGVN::performCongruenceFinding(Instruction *I, const Expression *E) {
23542383

23552384
// Constants and variables should always be made the leader.
23562385
if (const auto *CE = dyn_cast<ConstantExpression>(E)) {
2357-
NewClass->setLeader(CE->getConstantValue());
2386+
NewClass->setLeader({CE->getConstantValue(), 0});
23582387
} else if (const auto *SE = dyn_cast<StoreExpression>(E)) {
23592388
StoreInst *SI = SE->getStoreInst();
2360-
NewClass->setLeader(SI);
2389+
NewClass->setLeader({SI, InstrToDFSNum(SI)});
23612390
NewClass->setStoredValue(SE->getStoredValue());
23622391
// The RepMemoryAccess field will be filled in properly by the
23632392
// moveValueToNewCongruenceClass call.
23642393
} else {
2365-
NewClass->setLeader(I);
2394+
NewClass->setLeader({I, InstrToDFSNum(I)});
23662395
}
23672396
assert(!isa<VariableExpression>(E) &&
23682397
"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)