Skip to content

Commit 6d00400

Browse files
committed
[GVN] Share equality propagation for assume and condition
GVN currently has two different implementation of equality propagation. One of them is used for branch conditions (dominating an edge), which performs replacements across multiple blocks. This is also used for assumes to handle uses outside the current block. However, uses inside the block are handled using a completely separate implementation, which involves populating a replacement map and then checking it for individual instructions during normal GVN. While this approach generally makes sense, it is kind of pointless if we already do a use walk to handle the cross-block case anyway. This PR generalizes propagateEquality() to accept either a BasicBlockEdge or an Instruction* and replace dominated users. This removes the need for special handling of uses in the same block for assumes, as they're covered by instruction dominance.
1 parent db39ef9 commit 6d00400

File tree

5 files changed

+92
-153
lines changed

5 files changed

+92
-153
lines changed

llvm/include/llvm/Transforms/Scalar/GVN.h

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include <cstdint>
2929
#include <optional>
3030
#include <utility>
31+
#include <variant>
3132
#include <vector>
3233

3334
namespace llvm {
@@ -321,11 +322,6 @@ class GVNPass : public PassInfoMixin<GVNPass> {
321322
};
322323
LeaderMap LeaderTable;
323324

324-
// Block-local map of equivalent values to their leader, does not
325-
// propagate to any successors. Entries added mid-block are applied
326-
// to the remaining instructions in the block.
327-
SmallMapVector<Value *, Value *, 4> ReplaceOperandsWithMap;
328-
329325
// Map the block to reversed postorder traversal number. It is used to
330326
// find back edge easily.
331327
DenseMap<AssertingVH<BasicBlock>, uint32_t> BlockRPONumber;
@@ -400,9 +396,9 @@ class GVNPass : public PassInfoMixin<GVNPass> {
400396
void verifyRemoved(const Instruction *I) const;
401397
bool splitCriticalEdges();
402398
BasicBlock *splitCriticalEdges(BasicBlock *Pred, BasicBlock *Succ);
403-
bool replaceOperandsForInBlockEquality(Instruction *I) const;
404-
bool propagateEquality(Value *LHS, Value *RHS, const BasicBlockEdge &Root,
405-
bool DominatesByEdge);
399+
bool
400+
propagateEquality(Value *LHS, Value *RHS,
401+
const std::variant<BasicBlockEdge, Instruction *> &Root);
406402
bool processFoldableCondBr(BranchInst *BI);
407403
void addDeadBlock(BasicBlock *BB);
408404
void assignValNumForDeadCode();

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,9 @@ LLVM_ABI unsigned replaceDominatedUsesWith(Value *From, Value *To,
452452
LLVM_ABI unsigned replaceDominatedUsesWith(Value *From, Value *To,
453453
DominatorTree &DT,
454454
const BasicBlock *BB);
455+
LLVM_ABI unsigned replaceDominatedUsesWith(Value *From, Value *To,
456+
DominatorTree &DT,
457+
const Instruction *I);
455458
/// Replace each use of 'From' with 'To' if that use is dominated by
456459
/// the given edge and the callback ShouldReplace returns true. Returns the
457460
/// number of replacements made.
@@ -465,6 +468,10 @@ LLVM_ABI unsigned replaceDominatedUsesWithIf(
465468
Value *From, Value *To, DominatorTree &DT, const BasicBlock *BB,
466469
function_ref<bool(const Use &U, const Value *To)> ShouldReplace);
467470

471+
LLVM_ABI unsigned replaceDominatedUsesWithIf(
472+
Value *From, Value *To, DominatorTree &DT, const Instruction *I,
473+
function_ref<bool(const Use &U, const Value *To)> ShouldReplace);
474+
468475
/// Return true if this call calls a gc leaf function.
469476
///
470477
/// A leaf function is a function that does not safepoint the thread during its

llvm/lib/Transforms/Scalar/GVN.cpp

Lines changed: 64 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -2083,13 +2083,6 @@ bool GVNPass::processNonLocalLoad(LoadInst *Load) {
20832083
return Changed;
20842084
}
20852085

2086-
static bool hasUsersIn(Value *V, BasicBlock *BB) {
2087-
return any_of(V->users(), [BB](User *U) {
2088-
auto *I = dyn_cast<Instruction>(U);
2089-
return I && I->getParent() == BB;
2090-
});
2091-
}
2092-
20932086
bool GVNPass::processAssumeIntrinsic(AssumeInst *IntrinsicI) {
20942087
Value *V = IntrinsicI->getArgOperand(0);
20952088

@@ -2148,85 +2141,7 @@ bool GVNPass::processAssumeIntrinsic(AssumeInst *IntrinsicI) {
21482141
}
21492142

21502143
Constant *True = ConstantInt::getTrue(V->getContext());
2151-
bool Changed = false;
2152-
2153-
for (BasicBlock *Successor : successors(IntrinsicI->getParent())) {
2154-
BasicBlockEdge Edge(IntrinsicI->getParent(), Successor);
2155-
2156-
// This property is only true in dominated successors, propagateEquality
2157-
// will check dominance for us.
2158-
Changed |= propagateEquality(V, True, Edge, false);
2159-
}
2160-
2161-
// We can replace assume value with true, which covers cases like this:
2162-
// call void @llvm.assume(i1 %cmp)
2163-
// br i1 %cmp, label %bb1, label %bb2 ; will change %cmp to true
2164-
ReplaceOperandsWithMap[V] = True;
2165-
2166-
// Similarly, after assume(!NotV) we know that NotV == false.
2167-
Value *NotV;
2168-
if (match(V, m_Not(m_Value(NotV))))
2169-
ReplaceOperandsWithMap[NotV] = ConstantInt::getFalse(V->getContext());
2170-
2171-
// If we find an equality fact, canonicalize all dominated uses in this block
2172-
// to one of the two values. We heuristically choice the "oldest" of the
2173-
// two where age is determined by value number. (Note that propagateEquality
2174-
// above handles the cross block case.)
2175-
//
2176-
// Key case to cover are:
2177-
// 1)
2178-
// %cmp = fcmp oeq float 3.000000e+00, %0 ; const on lhs could happen
2179-
// call void @llvm.assume(i1 %cmp)
2180-
// ret float %0 ; will change it to ret float 3.000000e+00
2181-
// 2)
2182-
// %load = load float, float* %addr
2183-
// %cmp = fcmp oeq float %load, %0
2184-
// call void @llvm.assume(i1 %cmp)
2185-
// ret float %load ; will change it to ret float %0
2186-
if (auto *CmpI = dyn_cast<CmpInst>(V)) {
2187-
if (CmpI->isEquivalence()) {
2188-
Value *CmpLHS = CmpI->getOperand(0);
2189-
Value *CmpRHS = CmpI->getOperand(1);
2190-
// Heuristically pick the better replacement -- the choice of heuristic
2191-
// isn't terribly important here, but the fact we canonicalize on some
2192-
// replacement is for exposing other simplifications.
2193-
// TODO: pull this out as a helper function and reuse w/ existing
2194-
// (slightly different) logic.
2195-
if (isa<Constant>(CmpLHS) && !isa<Constant>(CmpRHS))
2196-
std::swap(CmpLHS, CmpRHS);
2197-
if (!isa<Instruction>(CmpLHS) && isa<Instruction>(CmpRHS))
2198-
std::swap(CmpLHS, CmpRHS);
2199-
if ((isa<Argument>(CmpLHS) && isa<Argument>(CmpRHS)) ||
2200-
(isa<Instruction>(CmpLHS) && isa<Instruction>(CmpRHS))) {
2201-
// Move the 'oldest' value to the right-hand side, using the value
2202-
// number as a proxy for age.
2203-
uint32_t LVN = VN.lookupOrAdd(CmpLHS);
2204-
uint32_t RVN = VN.lookupOrAdd(CmpRHS);
2205-
if (LVN < RVN)
2206-
std::swap(CmpLHS, CmpRHS);
2207-
}
2208-
2209-
// Handle degenerate case where we either haven't pruned a dead path or a
2210-
// removed a trivial assume yet.
2211-
if (isa<Constant>(CmpLHS) && isa<Constant>(CmpRHS))
2212-
return Changed;
2213-
2214-
LLVM_DEBUG(dbgs() << "Replacing dominated uses of "
2215-
<< *CmpLHS << " with "
2216-
<< *CmpRHS << " in block "
2217-
<< IntrinsicI->getParent()->getName() << "\n");
2218-
2219-
// Setup the replacement map - this handles uses within the same block.
2220-
if (hasUsersIn(CmpLHS, IntrinsicI->getParent()))
2221-
ReplaceOperandsWithMap[CmpLHS] = CmpRHS;
2222-
2223-
// NOTE: The non-block local cases are handled by the call to
2224-
// propagateEquality above; this block is just about handling the block
2225-
// local cases. TODO: There's a bunch of logic in propagateEqualiy which
2226-
// isn't duplicated for the block local case, can we share it somehow?
2227-
}
2228-
}
2229-
return Changed;
2144+
return propagateEquality(V, True, IntrinsicI);
22302145
}
22312146

22322147
static void patchAndReplaceAllUsesWith(Instruction *I, Value *Repl) {
@@ -2496,39 +2411,28 @@ void GVNPass::assignBlockRPONumber(Function &F) {
24962411
InvalidBlockRPONumbers = false;
24972412
}
24982413

2499-
bool GVNPass::replaceOperandsForInBlockEquality(Instruction *Instr) const {
2500-
bool Changed = false;
2501-
for (unsigned OpNum = 0; OpNum < Instr->getNumOperands(); ++OpNum) {
2502-
Use &Operand = Instr->getOperandUse(OpNum);
2503-
auto It = ReplaceOperandsWithMap.find(Operand.get());
2504-
if (It != ReplaceOperandsWithMap.end()) {
2505-
const DataLayout &DL = Instr->getDataLayout();
2506-
if (!canReplacePointersInUseIfEqual(Operand, It->second, DL))
2507-
continue;
2508-
2509-
LLVM_DEBUG(dbgs() << "GVN replacing: " << *Operand << " with "
2510-
<< *It->second << " in instruction " << *Instr << '\n');
2511-
Instr->setOperand(OpNum, It->second);
2512-
Changed = true;
2513-
}
2514-
}
2515-
return Changed;
2516-
}
2517-
2518-
/// The given values are known to be equal in every block
2414+
/// The given values are known to be equal in every use
25192415
/// dominated by 'Root'. Exploit this, for example by replacing 'LHS' with
25202416
/// 'RHS' everywhere in the scope. Returns whether a change was made.
25212417
/// If DominatesByEdge is false, then it means that we will propagate the RHS
25222418
/// value starting from the end of Root.Start.
2523-
bool GVNPass::propagateEquality(Value *LHS, Value *RHS,
2524-
const BasicBlockEdge &Root,
2525-
bool DominatesByEdge) {
2419+
bool GVNPass::propagateEquality(
2420+
Value *LHS, Value *RHS,
2421+
const std::variant<BasicBlockEdge, Instruction *> &Root) {
25262422
SmallVector<std::pair<Value*, Value*>, 4> Worklist;
25272423
Worklist.push_back(std::make_pair(LHS, RHS));
25282424
bool Changed = false;
2529-
// For speed, compute a conservative fast approximation to
2530-
// DT->dominates(Root, Root.getEnd());
2531-
const bool RootDominatesEnd = isOnlyReachableViaThisEdge(Root, DT);
2425+
SmallVector<const BasicBlock *> DominatedBlocks;
2426+
if (const BasicBlockEdge *Edge = std::get_if<BasicBlockEdge>(&Root)) {
2427+
// For speed, compute a conservative fast approximation to
2428+
// DT->dominates(Root, Root.getEnd());
2429+
if (isOnlyReachableViaThisEdge(*Edge, DT))
2430+
DominatedBlocks.push_back(Edge->getEnd());
2431+
} else {
2432+
Instruction *I = std::get<Instruction *>(Root);
2433+
for (const auto *Node : DT->getNode(I->getParent())->children())
2434+
DominatedBlocks.push_back(Node->getBlock());
2435+
}
25322436

25332437
while (!Worklist.empty()) {
25342438
std::pair<Value*, Value*> Item = Worklist.pop_back_val();
@@ -2576,9 +2480,9 @@ bool GVNPass::propagateEquality(Value *LHS, Value *RHS,
25762480
// using the leader table is about compiling faster, not optimizing better).
25772481
// The leader table only tracks basic blocks, not edges. Only add to if we
25782482
// have the simple case where the edge dominates the end.
2579-
if (RootDominatesEnd && !isa<Instruction>(RHS) &&
2580-
canReplacePointersIfEqual(LHS, RHS, DL))
2581-
LeaderTable.insert(LVN, RHS, Root.getEnd());
2483+
if (!isa<Instruction>(RHS) && canReplacePointersIfEqual(LHS, RHS, DL))
2484+
for (const BasicBlock *BB : DominatedBlocks)
2485+
LeaderTable.insert(LVN, RHS, BB);
25822486

25832487
// Replace all occurrences of 'LHS' with 'RHS' everywhere in the scope. As
25842488
// LHS always has at least one use that is not dominated by Root, this will
@@ -2588,12 +2492,14 @@ bool GVNPass::propagateEquality(Value *LHS, Value *RHS,
25882492
auto CanReplacePointersCallBack = [&DL](const Use &U, const Value *To) {
25892493
return canReplacePointersInUseIfEqual(U, To, DL);
25902494
};
2591-
unsigned NumReplacements =
2592-
DominatesByEdge
2593-
? replaceDominatedUsesWithIf(LHS, RHS, *DT, Root,
2594-
CanReplacePointersCallBack)
2595-
: replaceDominatedUsesWithIf(LHS, RHS, *DT, Root.getStart(),
2596-
CanReplacePointersCallBack);
2495+
unsigned NumReplacements;
2496+
if (const BasicBlockEdge *Edge = std::get_if<BasicBlockEdge>(&Root))
2497+
NumReplacements = replaceDominatedUsesWithIf(
2498+
LHS, RHS, *DT, *Edge, CanReplacePointersCallBack);
2499+
else
2500+
NumReplacements = replaceDominatedUsesWithIf(
2501+
LHS, RHS, *DT, std::get<Instruction *>(Root),
2502+
CanReplacePointersCallBack);
25972503

25982504
if (NumReplacements > 0) {
25992505
Changed = true;
@@ -2652,26 +2558,45 @@ bool GVNPass::propagateEquality(Value *LHS, Value *RHS,
26522558
// If the number we were assigned was brand new then there is no point in
26532559
// looking for an instruction realizing it: there cannot be one!
26542560
if (Num < NextNum) {
2655-
Value *NotCmp = findLeader(Root.getEnd(), Num);
2656-
if (NotCmp && isa<Instruction>(NotCmp)) {
2657-
unsigned NumReplacements =
2658-
DominatesByEdge
2659-
? replaceDominatedUsesWith(NotCmp, NotVal, *DT, Root)
2660-
: replaceDominatedUsesWith(NotCmp, NotVal, *DT,
2661-
Root.getStart());
2662-
Changed |= NumReplacements > 0;
2663-
NumGVNEqProp += NumReplacements;
2664-
// Cached information for anything that uses NotCmp will be invalid.
2665-
if (MD)
2666-
MD->invalidateCachedPointerInfo(NotCmp);
2561+
for (const auto &Entry : LeaderTable.getLeaders(Num)) {
2562+
// Only look at leaders that either dominate the start of the edge,
2563+
// or are dominated by the end. This check is not necessary for
2564+
// correctness, it only discards cases for which the following
2565+
// use replacement will not work anyway.
2566+
if (const BasicBlockEdge *Edge = std::get_if<BasicBlockEdge>(&Root)) {
2567+
if (!DT->dominates(Entry.BB, Edge->getStart()) &&
2568+
!DT->dominates(Edge->getEnd(), Entry.BB))
2569+
continue;
2570+
} else {
2571+
auto *InstBB = std::get<Instruction *>(Root)->getParent();
2572+
if (!DT->dominates(Entry.BB, InstBB) &&
2573+
!DT->dominates(InstBB, Entry.BB))
2574+
continue;
2575+
}
2576+
2577+
Value *NotCmp = Entry.Val;
2578+
if (NotCmp && isa<Instruction>(NotCmp)) {
2579+
unsigned NumReplacements;
2580+
if (const BasicBlockEdge *Edge = std::get_if<BasicBlockEdge>(&Root))
2581+
NumReplacements =
2582+
replaceDominatedUsesWith(NotCmp, NotVal, *DT, *Edge);
2583+
else
2584+
NumReplacements = replaceDominatedUsesWith(
2585+
NotCmp, NotVal, *DT, std::get<Instruction *>(Root));
2586+
Changed |= NumReplacements > 0;
2587+
NumGVNEqProp += NumReplacements;
2588+
// Cached information for anything that uses NotCmp will be invalid.
2589+
if (MD)
2590+
MD->invalidateCachedPointerInfo(NotCmp);
2591+
}
26672592
}
26682593
}
26692594
// Ensure that any instruction in scope that gets the "A < B" value number
26702595
// is replaced with false.
26712596
// The leader table only tracks basic blocks, not edges. Only add to if we
26722597
// have the simple case where the edge dominates the end.
2673-
if (RootDominatesEnd)
2674-
LeaderTable.insert(Num, NotVal, Root.getEnd());
2598+
for (const BasicBlock *BB : DominatedBlocks)
2599+
LeaderTable.insert(Num, NotVal, BB);
26752600

26762601
continue;
26772602
}
@@ -2755,11 +2680,11 @@ bool GVNPass::processInstruction(Instruction *I) {
27552680

27562681
Value *TrueVal = ConstantInt::getTrue(TrueSucc->getContext());
27572682
BasicBlockEdge TrueE(Parent, TrueSucc);
2758-
Changed |= propagateEquality(BranchCond, TrueVal, TrueE, true);
2683+
Changed |= propagateEquality(BranchCond, TrueVal, TrueE);
27592684

27602685
Value *FalseVal = ConstantInt::getFalse(FalseSucc->getContext());
27612686
BasicBlockEdge FalseE(Parent, FalseSucc);
2762-
Changed |= propagateEquality(BranchCond, FalseVal, FalseE, true);
2687+
Changed |= propagateEquality(BranchCond, FalseVal, FalseE);
27632688

27642689
return Changed;
27652690
}
@@ -2780,7 +2705,7 @@ bool GVNPass::processInstruction(Instruction *I) {
27802705
// If there is only a single edge, propagate the case value into it.
27812706
if (SwitchEdges.lookup(Dst) == 1) {
27822707
BasicBlockEdge E(Parent, Dst);
2783-
Changed |= propagateEquality(SwitchCond, Case.getCaseValue(), E, true);
2708+
Changed |= propagateEquality(SwitchCond, Case.getCaseValue(), E);
27842709
}
27852710
}
27862711
return Changed;
@@ -2908,8 +2833,6 @@ bool GVNPass::processBlock(BasicBlock *BB) {
29082833
if (DeadBlocks.count(BB))
29092834
return false;
29102835

2911-
// Clearing map before every BB because it can be used only for single BB.
2912-
ReplaceOperandsWithMap.clear();
29132836
bool ChangedFunction = false;
29142837

29152838
// Since we may not have visited the input blocks of the phis, we can't
@@ -2921,11 +2844,8 @@ bool GVNPass::processBlock(BasicBlock *BB) {
29212844
for (PHINode *PN : PHINodesToRemove) {
29222845
removeInstruction(PN);
29232846
}
2924-
for (Instruction &Inst : make_early_inc_range(*BB)) {
2925-
if (!ReplaceOperandsWithMap.empty())
2926-
ChangedFunction |= replaceOperandsForInBlockEquality(&Inst);
2847+
for (Instruction &Inst : make_early_inc_range(*BB))
29272848
ChangedFunction |= processInstruction(&Inst);
2928-
}
29292849
return ChangedFunction;
29302850
}
29312851

llvm/lib/Transforms/Utils/Local.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3239,6 +3239,13 @@ unsigned llvm::replaceDominatedUsesWith(Value *From, Value *To,
32393239
return ::replaceDominatedUsesWith(From, To, Dominates);
32403240
}
32413241

3242+
unsigned llvm::replaceDominatedUsesWith(Value *From, Value *To,
3243+
DominatorTree &DT,
3244+
const Instruction *I) {
3245+
auto Dominates = [&](const Use &U) { return DT.dominates(I, U); };
3246+
return ::replaceDominatedUsesWith(From, To, Dominates);
3247+
}
3248+
32423249
unsigned llvm::replaceDominatedUsesWithIf(
32433250
Value *From, Value *To, DominatorTree &DT, const BasicBlockEdge &Root,
32443251
function_ref<bool(const Use &U, const Value *To)> ShouldReplace) {
@@ -3257,6 +3264,15 @@ unsigned llvm::replaceDominatedUsesWithIf(
32573264
return ::replaceDominatedUsesWith(From, To, DominatesAndShouldReplace);
32583265
}
32593266

3267+
unsigned llvm::replaceDominatedUsesWithIf(
3268+
Value *From, Value *To, DominatorTree &DT, const Instruction *I,
3269+
function_ref<bool(const Use &U, const Value *To)> ShouldReplace) {
3270+
auto DominatesAndShouldReplace = [&](const Use &U) {
3271+
return DT.dominates(I, U) && ShouldReplace(U, To);
3272+
};
3273+
return ::replaceDominatedUsesWith(From, To, DominatesAndShouldReplace);
3274+
}
3275+
32603276
bool llvm::callsGCLeafFunction(const CallBase *Call,
32613277
const TargetLibraryInfo &TLI) {
32623278
// Check if the function is specifically marked as a gc leaf function.

llvm/test/Transforms/GVN/condprop.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ define i1 @test6_phi2(i1 %c, i32 %x, i32 %y) {
360360
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X]], [[Y]]
361361
; CHECK-NEXT: br i1 [[CMP]], label [[BB2]], label [[BB3:%.*]]
362362
; CHECK: bb2:
363-
; CHECK-NEXT: [[PHI:%.*]] = phi i1 [ [[CMP_NOT]], [[BB1]] ], [ true, [[ENTRY:%.*]] ]
363+
; CHECK-NEXT: [[PHI:%.*]] = phi i1 [ false, [[BB1]] ], [ true, [[ENTRY:%.*]] ]
364364
; CHECK-NEXT: ret i1 [[PHI]]
365365
; CHECK: bb3:
366366
; CHECK-NEXT: ret i1 false

0 commit comments

Comments
 (0)