Skip to content

Commit a7cae25

Browse files
committed
[DeadStoreElimination] Optimize tautological assignments
If a store is immediately dominated by a condition that ensures that the value being stored in a memory location is already present at that memory location, consider the store a noop. Fixes #63419
1 parent 0871c4b commit a7cae25

File tree

2 files changed

+413
-0
lines changed

2 files changed

+413
-0
lines changed

llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1901,6 +1901,57 @@ struct DSEState {
19011901
return true;
19021902
}
19031903

1904+
// Check if there is a dominating condition, that implies that the value
1905+
// being stored in a ptr is already present in the ptr.
1906+
bool dominatingConditionImpliesValue(MemoryDef *Def) {
1907+
auto *StoreI = cast<StoreInst>(Def->getMemoryInst());
1908+
BasicBlock *StoreBB = StoreI->getParent();
1909+
Value *StorePtr = StoreI->getPointerOperand();
1910+
Value *StoreVal = StoreI->getValueOperand();
1911+
1912+
DomTreeNode *IDom = DT.getNode(StoreBB)->getIDom();
1913+
if (!IDom)
1914+
return false;
1915+
1916+
auto *BI = dyn_cast<BranchInst>(IDom->getBlock()->getTerminator());
1917+
if (!BI || !BI->isConditional())
1918+
return false;
1919+
1920+
// In case both blocks are the same, it is not possible to determine
1921+
// if optimization is possible. (We would not want to optimize a store
1922+
// in the FalseBB if condition is true and vice versa.)
1923+
if (BI->getSuccessor(0) == BI->getSuccessor(1))
1924+
return false;
1925+
1926+
Instruction *ICmpL;
1927+
ICmpInst::Predicate Pred;
1928+
if (!match(BI->getCondition(),
1929+
m_c_ICmp(Pred,
1930+
m_CombineAnd(m_Load(m_Specific(StorePtr)),
1931+
m_Instruction(ICmpL)),
1932+
m_Specific(StoreVal))) ||
1933+
!ICmpInst::isEquality(Pred))
1934+
return false;
1935+
1936+
// In case the else blocks also branches to the if block or the other way
1937+
// around it is not possible to determine if the optimization is possible.
1938+
if (Pred == ICmpInst::ICMP_EQ &&
1939+
!DT.dominates(BasicBlockEdge(BI->getParent(), BI->getSuccessor(0)),
1940+
StoreBB))
1941+
return false;
1942+
1943+
if (Pred == ICmpInst::ICMP_NE &&
1944+
!DT.dominates(BasicBlockEdge(BI->getParent(), BI->getSuccessor(1)),
1945+
StoreBB))
1946+
return false;
1947+
1948+
MemoryAccess *LoadAcc = MSSA.getMemoryAccess(ICmpL);
1949+
MemoryAccess *ClobAcc =
1950+
MSSA.getSkipSelfWalker()->getClobberingMemoryAccess(Def, BatchAA);
1951+
1952+
return MSSA.dominates(ClobAcc, LoadAcc);
1953+
}
1954+
19041955
/// \returns true if \p Def is a no-op store, either because it
19051956
/// directly stores back a loaded value or stores zero to a calloced object.
19061957
bool storeIsNoop(MemoryDef *Def, const Value *DefUO) {
@@ -1931,6 +1982,9 @@ struct DSEState {
19311982
if (!Store)
19321983
return false;
19331984

1985+
if (dominatingConditionImpliesValue(Def))
1986+
return true;
1987+
19341988
if (auto *LoadI = dyn_cast<LoadInst>(Store->getOperand(0))) {
19351989
if (LoadI->getPointerOperand() == Store->getOperand(1)) {
19361990
// Get the defining access for the load.

0 commit comments

Comments
 (0)