@@ -297,7 +297,8 @@ class CongruenceClass {
297
297
using MemoryMemberSet = SmallPtrSet<const MemoryMemberType *, 2 >;
298
298
299
299
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)
301
302
: ID(ID), RepLeader(Leader), DefiningExpr(E) {}
302
303
303
304
unsigned getID () const { return ID; }
@@ -311,15 +312,23 @@ class CongruenceClass {
311
312
}
312
313
313
314
// 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
+ }
316
319
const std::pair<Value *, unsigned int > &getNextLeader () const {
317
320
return NextLeader;
318
321
}
319
322
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 ) {
322
329
NextLeader = LeaderPair;
330
+ }
331
+ return false ;
323
332
}
324
333
325
334
Value *getStoredValue () const { return RepStoredValue; }
@@ -392,11 +401,13 @@ class CongruenceClass {
392
401
private:
393
402
unsigned ID;
394
403
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 };
397
407
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.
400
411
std::pair<Value *, unsigned int > NextLeader = {nullptr , ~0U };
401
412
402
413
// If this is represented by a store, the value of the store.
@@ -731,7 +742,19 @@ class NewGVN {
731
742
732
743
// Congruence class handling.
733
744
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);
735
758
CongruenceClasses.emplace_back (result);
736
759
return result;
737
760
}
@@ -2244,8 +2267,13 @@ void NewGVN::moveValueToNewCongruenceClass(Instruction *I, const Expression *E,
2244
2267
OldClass->erase (I);
2245
2268
NewClass->insert (I);
2246
2269
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
+
2249
2277
// Handle our special casing of stores.
2250
2278
if (auto *SI = dyn_cast<StoreInst>(I)) {
2251
2279
OldClass->decStoreCount ();
@@ -2269,7 +2297,7 @@ void NewGVN::moveValueToNewCongruenceClass(Instruction *I, const Expression *E,
2269
2297
<< " because store joined class\n " );
2270
2298
// If we changed the leader, we have to mark it changed because we don't
2271
2299
// know what it will do to symbolic evaluation.
2272
- NewClass->setLeader (SI );
2300
+ NewClass->setLeader ({SI, InstrToDFSNum (SI)} );
2273
2301
}
2274
2302
// We rely on the code below handling the MemoryAccess change.
2275
2303
}
@@ -2315,7 +2343,8 @@ void NewGVN::moveValueToNewCongruenceClass(Instruction *I, const Expression *E,
2315
2343
if (OldClass->getStoredValue ())
2316
2344
OldClass->setStoredValue (nullptr );
2317
2345
}
2318
- OldClass->setLeader (getNextValueLeader (OldClass));
2346
+ OldClass->setLeader ({getNextValueLeader (OldClass),
2347
+ InstrToDFSNum (getNextValueLeader (OldClass))});
2319
2348
OldClass->resetNextLeader ();
2320
2349
markValueLeaderChangeTouched (OldClass);
2321
2350
}
@@ -2354,15 +2383,15 @@ void NewGVN::performCongruenceFinding(Instruction *I, const Expression *E) {
2354
2383
2355
2384
// Constants and variables should always be made the leader.
2356
2385
if (const auto *CE = dyn_cast<ConstantExpression>(E)) {
2357
- NewClass->setLeader (CE->getConstantValue ());
2386
+ NewClass->setLeader ({ CE->getConstantValue (), 0 } );
2358
2387
} else if (const auto *SE = dyn_cast<StoreExpression>(E)) {
2359
2388
StoreInst *SI = SE->getStoreInst ();
2360
- NewClass->setLeader (SI );
2389
+ NewClass->setLeader ({SI, InstrToDFSNum (SI)} );
2361
2390
NewClass->setStoredValue (SE->getStoredValue ());
2362
2391
// The RepMemoryAccess field will be filled in properly by the
2363
2392
// moveValueToNewCongruenceClass call.
2364
2393
} else {
2365
- NewClass->setLeader (I );
2394
+ NewClass->setLeader ({I, InstrToDFSNum (I)} );
2366
2395
}
2367
2396
assert (!isa<VariableExpression>(E) &&
2368
2397
" VariableExpression should have been handled already" );
@@ -3253,7 +3282,6 @@ void NewGVN::verifyMemoryCongruency() const {
3253
3282
return ReachableEdges.count (
3254
3283
{FirstMP->getIncomingBlock (U), FirstMP->getBlock ()}) &&
3255
3284
isa<MemoryDef>(U);
3256
-
3257
3285
};
3258
3286
// All arguments should in the same class, ignoring unreachable arguments
3259
3287
auto FilteredPhiArgs =
0 commit comments