Skip to content

Commit 2f4e71a

Browse files
committed
add_EliminateNewDuplicatePHINodes
1 parent 4244a91 commit 2f4e71a

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. FirstExistedPN
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 FirstExistedPN);
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
@@ -1419,65 +1419,65 @@ EliminateDuplicatePHINodesNaiveImpl(BasicBlock *BB,
14191419
return Changed;
14201420
}
14211421

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

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

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

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

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

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

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

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

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

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

0 commit comments

Comments
 (0)