@@ -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.
@@ -735,7 +746,19 @@ class NewGVN {
735
746
736
747
// Congruence class handling.
737
748
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);
739
762
CongruenceClasses.emplace_back (result);
740
763
return result;
741
764
}
@@ -2248,8 +2271,13 @@ void NewGVN::moveValueToNewCongruenceClass(Instruction *I, const Expression *E,
2248
2271
OldClass->erase (I);
2249
2272
NewClass->insert (I);
2250
2273
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
+
2253
2281
// Handle our special casing of stores.
2254
2282
if (auto *SI = dyn_cast<StoreInst>(I)) {
2255
2283
OldClass->decStoreCount ();
@@ -2273,7 +2301,7 @@ void NewGVN::moveValueToNewCongruenceClass(Instruction *I, const Expression *E,
2273
2301
<< " because store joined class\n " );
2274
2302
// If we changed the leader, we have to mark it changed because we don't
2275
2303
// know what it will do to symbolic evaluation.
2276
- NewClass->setLeader (SI );
2304
+ NewClass->setLeader ({SI, InstrToDFSNum (SI)} );
2277
2305
}
2278
2306
// We rely on the code below handling the MemoryAccess change.
2279
2307
}
@@ -2319,7 +2347,8 @@ void NewGVN::moveValueToNewCongruenceClass(Instruction *I, const Expression *E,
2319
2347
if (OldClass->getStoredValue ())
2320
2348
OldClass->setStoredValue (nullptr );
2321
2349
}
2322
- OldClass->setLeader (getNextValueLeader (OldClass));
2350
+ OldClass->setLeader ({getNextValueLeader (OldClass),
2351
+ InstrToDFSNum (getNextValueLeader (OldClass))});
2323
2352
OldClass->resetNextLeader ();
2324
2353
markValueLeaderChangeTouched (OldClass);
2325
2354
}
@@ -2358,15 +2387,15 @@ void NewGVN::performCongruenceFinding(Instruction *I, const Expression *E) {
2358
2387
2359
2388
// Constants and variables should always be made the leader.
2360
2389
if (const auto *CE = dyn_cast<ConstantExpression>(E)) {
2361
- NewClass->setLeader (CE->getConstantValue ());
2390
+ NewClass->setLeader ({ CE->getConstantValue (), 0 } );
2362
2391
} else if (const auto *SE = dyn_cast<StoreExpression>(E)) {
2363
2392
StoreInst *SI = SE->getStoreInst ();
2364
- NewClass->setLeader (SI );
2393
+ NewClass->setLeader ({SI, InstrToDFSNum (SI)} );
2365
2394
NewClass->setStoredValue (SE->getStoredValue ());
2366
2395
// The RepMemoryAccess field will be filled in properly by the
2367
2396
// moveValueToNewCongruenceClass call.
2368
2397
} else {
2369
- NewClass->setLeader (I );
2398
+ NewClass->setLeader ({I, InstrToDFSNum (I)} );
2370
2399
}
2371
2400
assert (!isa<VariableExpression>(E) &&
2372
2401
" 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