Skip to content

Commit dfc0ba6

Browse files
committed
add_EliminateNewDuplicatePHINodes
1 parent c66ce08 commit dfc0ba6

File tree

3 files changed

+370
-49
lines changed

3 files changed

+370
-49
lines changed

llvm/include/llvm/Transforms/Utils/Local.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,22 @@ bool EliminateDuplicatePHINodes(BasicBlock *BB);
175175
bool EliminateDuplicatePHINodes(BasicBlock *BB,
176176
SmallPtrSetImpl<PHINode *> &ToRemove);
177177

178+
/// Check for and eliminate duplicate PHI nodes in the block. This function is
179+
/// specifically designed for scenarios where new PHI nodes are inserted into
180+
/// the beginning of the block, such when SSAUpdaterBulk::RewriteAllUses. It
181+
/// compares the newly inserted PHI nodes against the existing ones and if a
182+
/// new PHI node is found to be a duplicate of an existing one, the new node is
183+
/// removed. Existing PHI nodes are left unmodified, even if they are
184+
/// duplicates. New nodes are also deleted if they are duplicates of each other.
185+
/// Similar to EliminateDuplicatePHINodes, this function assumes a consistent
186+
/// order for all incoming values across PHI nodes in the block. FirstExistingPN
187+
/// Points to the first existing PHI node in the block. Newly inserted PHI nodes
188+
/// should not reference one another. However, they may reference themselves or
189+
/// existing PHI nodes, and existing PHI nodes may reference the newly inserted
190+
/// PHI nodes.
191+
bool EliminateNewDuplicatePHINodes(BasicBlock *BB,
192+
BasicBlock::phi_iterator FirstExistingPN);
193+
178194
/// This function is used to do simplification of a CFG. For example, it
179195
/// adjusts branches to branches to eliminate the extra hop, it eliminates
180196
/// unreachable basic blocks, and does other peephole optimization of the CFG.

llvm/lib/Transforms/Utils/Local.cpp

Lines changed: 154 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1420,65 +1420,65 @@ EliminateDuplicatePHINodesNaiveImpl(BasicBlock *BB,
14201420
return Changed;
14211421
}
14221422

1423-
static bool
1424-
EliminateDuplicatePHINodesSetBasedImpl(BasicBlock *BB,
1425-
SmallPtrSetImpl<PHINode *> &ToRemove) {
1426-
// This implementation doesn't currently consider undef operands
1427-
// specially. Theoretically, two phis which are identical except for
1428-
// one having an undef where the other doesn't could be collapsed.
1423+
// This implementation doesn't currently consider undef operands
1424+
// specially. Theoretically, two phis which are identical except for
1425+
// one having an undef where the other doesn't could be collapsed.
14291426

1430-
struct PHIDenseMapInfo {
1431-
static PHINode *getEmptyKey() {
1432-
return DenseMapInfo<PHINode *>::getEmptyKey();
1433-
}
1427+
struct PHIDenseMapInfo {
1428+
static PHINode *getEmptyKey() {
1429+
return DenseMapInfo<PHINode *>::getEmptyKey();
1430+
}
14341431

1435-
static PHINode *getTombstoneKey() {
1436-
return DenseMapInfo<PHINode *>::getTombstoneKey();
1437-
}
1432+
static PHINode *getTombstoneKey() {
1433+
return DenseMapInfo<PHINode *>::getTombstoneKey();
1434+
}
14381435

1439-
static bool isSentinel(PHINode *PN) {
1440-
return PN == getEmptyKey() || PN == getTombstoneKey();
1441-
}
1436+
static bool isSentinel(const PHINode *PN) {
1437+
return PN == getEmptyKey() || PN == getTombstoneKey();
1438+
}
14421439

1443-
// WARNING: this logic must be kept in sync with
1444-
// Instruction::isIdenticalToWhenDefined()!
1445-
static unsigned getHashValueImpl(PHINode *PN) {
1446-
// Compute a hash value on the operands. Instcombine will likely have
1447-
// sorted them, which helps expose duplicates, but we have to check all
1448-
// the operands to be safe in case instcombine hasn't run.
1449-
return static_cast<unsigned>(
1450-
hash_combine(hash_combine_range(PN->operand_values()),
1451-
hash_combine_range(PN->blocks())));
1452-
}
1440+
// WARNING: this logic must be kept in sync with
1441+
// Instruction::isIdenticalToWhenDefined()!
1442+
static unsigned getHashValueImpl(const PHINode *PN) {
1443+
// Compute a hash value on the operands. Instcombine will likely have
1444+
// sorted them, which helps expose duplicates, but we have to check all
1445+
// the operands to be safe in case instcombine hasn't run.
1446+
return static_cast<unsigned>(
1447+
hash_combine(hash_combine_range(PN->operand_values()),
1448+
hash_combine_range(PN->blocks())));
1449+
}
14531450

1454-
static unsigned getHashValue(PHINode *PN) {
1451+
static unsigned getHashValue(const PHINode *PN) {
14551452
#ifndef NDEBUG
1456-
// If -phicse-debug-hash was specified, return a constant -- this
1457-
// will force all hashing to collide, so we'll exhaustively search
1458-
// the table for a match, and the assertion in isEqual will fire if
1459-
// there's a bug causing equal keys to hash differently.
1460-
if (PHICSEDebugHash)
1461-
return 0;
1453+
// If -phicse-debug-hash was specified, return a constant -- this
1454+
// will force all hashing to collide, so we'll exhaustively search
1455+
// the table for a match, and the assertion in isEqual will fire if
1456+
// there's a bug causing equal keys to hash differently.
1457+
if (PHICSEDebugHash)
1458+
return 0;
14621459
#endif
1463-
return getHashValueImpl(PN);
1464-
}
1460+
return getHashValueImpl(PN);
1461+
}
14651462

1466-
static bool isEqualImpl(PHINode *LHS, PHINode *RHS) {
1467-
if (isSentinel(LHS) || isSentinel(RHS))
1468-
return LHS == RHS;
1469-
return LHS->isIdenticalTo(RHS);
1470-
}
1463+
static bool isEqualImpl(const PHINode *LHS, const PHINode *RHS) {
1464+
if (isSentinel(LHS) || isSentinel(RHS))
1465+
return LHS == RHS;
1466+
return LHS->isIdenticalTo(RHS);
1467+
}
14711468

1472-
static bool isEqual(PHINode *LHS, PHINode *RHS) {
1473-
// These comparisons are nontrivial, so assert that equality implies
1474-
// hash equality (DenseMap demands this as an invariant).
1475-
bool Result = isEqualImpl(LHS, RHS);
1476-
assert(!Result || (isSentinel(LHS) && LHS == RHS) ||
1477-
getHashValueImpl(LHS) == getHashValueImpl(RHS));
1478-
return Result;
1479-
}
1480-
};
1469+
static bool isEqual(const PHINode *LHS, const PHINode *RHS) {
1470+
// These comparisons are nontrivial, so assert that equality implies
1471+
// hash equality (DenseMap demands this as an invariant).
1472+
bool Result = isEqualImpl(LHS, RHS);
1473+
assert(!Result || (isSentinel(LHS) && LHS == RHS) ||
1474+
getHashValueImpl(LHS) == getHashValueImpl(RHS));
1475+
return Result;
1476+
}
1477+
};
14811478

1479+
static bool
1480+
EliminateDuplicatePHINodesSetBasedImpl(BasicBlock *BB,
1481+
SmallPtrSetImpl<PHINode *> &ToRemove) {
14821482
// Set of unique PHINodes.
14831483
DenseSet<PHINode *, PHIDenseMapInfo> PHISet;
14841484
PHISet.reserve(4 * PHICSENumPHISmallSize);
@@ -1525,6 +1525,111 @@ bool llvm::EliminateDuplicatePHINodes(BasicBlock *BB) {
15251525
return Changed;
15261526
}
15271527

1528+
#ifndef NDEBUG // Should this be under EXPENSIVE_CHECKS?
1529+
// New PHI nodes should not reference one another but they may reference
1530+
// themselves or existing PHI nodes, and existing PHI nodes may reference new
1531+
// PHI nodes.
1532+
static bool
1533+
PHIAreRefEachOther(const iterator_range<BasicBlock::phi_iterator> &NewPHIs) {
1534+
SmallPtrSet<PHINode *, 8> NewPHISet;
1535+
for (PHINode &PN : NewPHIs)
1536+
NewPHISet.insert(&PN);
1537+
for (PHINode &PHI : NewPHIs) {
1538+
for (Value *V : PHI.incoming_values()) {
1539+
PHINode *IncPHI = dyn_cast<PHINode>(V);
1540+
if (IncPHI && IncPHI != &PHI && NewPHISet.contains(IncPHI))
1541+
return true;
1542+
}
1543+
}
1544+
return false;
1545+
}
1546+
#endif
1547+
1548+
bool EliminateNewDuplicatePHINodesN2(BasicBlock *BB,
1549+
BasicBlock::phi_iterator FirstExistingPN) {
1550+
auto ReplaceIfIdentical = [](PHINode &PHI, PHINode &ReplPHI) {
1551+
if (!PHI.isIdenticalToWhenDefined(&ReplPHI))
1552+
return false;
1553+
PHI.replaceAllUsesWith(&ReplPHI);
1554+
PHI.eraseFromParent();
1555+
return true;
1556+
};
1557+
1558+
// Deduplicate new PHIs first to reduce the number of comparisons on the
1559+
// following new -> existing pass.
1560+
bool Changed = false;
1561+
for (auto I = BB->phis().begin(); I != FirstExistingPN; ++I) {
1562+
for (auto J = std::next(I); J != FirstExistingPN;) {
1563+
Changed |= ReplaceIfIdentical(*J++, *I);
1564+
}
1565+
}
1566+
1567+
// Iterate over existing PHIs and replace identical new PHIs.
1568+
for (PHINode &ExistingPHI : make_range(FirstExistingPN, BB->phis().end())) {
1569+
auto I = BB->phis().begin();
1570+
assert(I != FirstExistingPN); // Should be at least one new PHI.
1571+
do {
1572+
Changed |= ReplaceIfIdentical(*I++, ExistingPHI);
1573+
} while (I != FirstExistingPN);
1574+
if (BB->phis().begin() == FirstExistingPN)
1575+
return Changed;
1576+
}
1577+
return Changed;
1578+
}
1579+
1580+
bool EliminateNewDuplicatePHINodesSet(
1581+
BasicBlock *BB, BasicBlock::phi_iterator FirstExistingPN) {
1582+
auto Replace = [](PHINode &PHI, PHINode &ReplPHI) {
1583+
PHI.replaceAllUsesWith(&ReplPHI);
1584+
PHI.eraseFromParent();
1585+
return true;
1586+
};
1587+
1588+
DenseSet<PHINode *, PHIDenseMapInfo> NewPHISet;
1589+
NewPHISet.reserve(4 * PHICSENumPHISmallSize);
1590+
1591+
// Deduplicate new PHIs, note that NewPHISet remains consistent because new
1592+
// PHIs are not reference each other.
1593+
bool Changed = false;
1594+
for (PHINode &NewPHI :
1595+
make_early_inc_range(make_range(BB->phis().begin(), FirstExistingPN))) {
1596+
auto [I, Inserted] = NewPHISet.insert(&NewPHI);
1597+
if (!Inserted)
1598+
Changed |= Replace(NewPHI, **I);
1599+
}
1600+
1601+
// Iterate over existing PHIs and replace matching new PHIs.
1602+
for (PHINode &ExistingPHI : make_range(FirstExistingPN, BB->phis().end())) {
1603+
assert(!NewPHISet.empty()); // Should be at least one new PHI.
1604+
auto I = NewPHISet.find(&ExistingPHI);
1605+
if (I == NewPHISet.end())
1606+
continue;
1607+
Changed |= Replace(**I, ExistingPHI);
1608+
NewPHISet.erase(I);
1609+
if (NewPHISet.empty())
1610+
return Changed;
1611+
}
1612+
return Changed;
1613+
}
1614+
1615+
bool llvm::EliminateNewDuplicatePHINodes(
1616+
BasicBlock *BB, BasicBlock::phi_iterator FirstExistingPN) {
1617+
1618+
if (hasNItemsOrLess(BB->phis(), 1))
1619+
return false;
1620+
1621+
auto NewPHIs = make_range(BB->phis().begin(), FirstExistingPN);
1622+
assert(!PHIAreRefEachOther(NewPHIs));
1623+
1624+
// Both functions perform identical pass over existing PHIs and differ in time
1625+
// spent on new PHI duplicate check which depends on the number of new PHIs.
1626+
// Therefore make a choice based on the number of new PHIs and not the total
1627+
// number of PHIs in the block.
1628+
return hasNItemsOrLess(NewPHIs, PHICSENumPHISmallSize)
1629+
? EliminateNewDuplicatePHINodesN2(BB, FirstExistingPN)
1630+
: EliminateNewDuplicatePHINodesSet(BB, FirstExistingPN);
1631+
}
1632+
15281633
Align llvm::tryEnforceAlignment(Value *V, Align PrefAlign,
15291634
const DataLayout &DL) {
15301635
V = V->stripPointerCasts();

0 commit comments

Comments
 (0)