mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-08-09 11:25:55 +00:00
Teach GVN to reason about edges dominating uses. This allows it to handle cases
where some fact lake a=b dominates a use in a phi, but doesn't dominate the basic block itself. This feature could also be implemented by splitting critical edges, but at least with the current algorithm reasoning about the dominance directly is faster. The time for running "opt -O2" in the testcase in pr10584 is 1.003 times slower and on gcc as a single file it is 1.0007 times faster. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@162023 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -705,7 +705,20 @@ DominatorTreeBase<NodeT>::properlyDominates(const NodeT *A, const NodeT *B) {
|
|||||||
|
|
||||||
EXTERN_TEMPLATE_INSTANTIATION(class DominatorTreeBase<BasicBlock>);
|
EXTERN_TEMPLATE_INSTANTIATION(class DominatorTreeBase<BasicBlock>);
|
||||||
|
|
||||||
class BasicBlockEdge;
|
class BasicBlockEdge {
|
||||||
|
const BasicBlock *Start;
|
||||||
|
const BasicBlock *End;
|
||||||
|
public:
|
||||||
|
BasicBlockEdge(const BasicBlock *Start_, const BasicBlock *End_) :
|
||||||
|
Start(Start_), End(End_) { }
|
||||||
|
const BasicBlock *getStart() const {
|
||||||
|
return Start;
|
||||||
|
}
|
||||||
|
const BasicBlock *getEnd() const {
|
||||||
|
return End;
|
||||||
|
}
|
||||||
|
bool isSingleEdge() const;
|
||||||
|
};
|
||||||
|
|
||||||
//===-------------------------------------
|
//===-------------------------------------
|
||||||
/// DominatorTree Class - Concrete subclass of DominatorTreeBase that is used to
|
/// DominatorTree Class - Concrete subclass of DominatorTreeBase that is used to
|
||||||
|
@@ -613,8 +613,8 @@ namespace {
|
|||||||
void verifyRemoved(const Instruction *I) const;
|
void verifyRemoved(const Instruction *I) const;
|
||||||
bool splitCriticalEdges();
|
bool splitCriticalEdges();
|
||||||
unsigned replaceAllDominatedUsesWith(Value *From, Value *To,
|
unsigned replaceAllDominatedUsesWith(Value *From, Value *To,
|
||||||
const BasicBlock *Root);
|
const BasicBlockEdge &Root);
|
||||||
bool propagateEquality(Value *LHS, Value *RHS, const BasicBlock *Root);
|
bool propagateEquality(Value *LHS, Value *RHS, const BasicBlockEdge &Root);
|
||||||
};
|
};
|
||||||
|
|
||||||
char GVN::ID = 0;
|
char GVN::ID = 0;
|
||||||
@@ -2004,22 +2004,13 @@ Value *GVN::findLeader(const BasicBlock *BB, uint32_t num) {
|
|||||||
/// use is dominated by the given basic block. Returns the number of uses that
|
/// use is dominated by the given basic block. Returns the number of uses that
|
||||||
/// were replaced.
|
/// were replaced.
|
||||||
unsigned GVN::replaceAllDominatedUsesWith(Value *From, Value *To,
|
unsigned GVN::replaceAllDominatedUsesWith(Value *From, Value *To,
|
||||||
const BasicBlock *Root) {
|
const BasicBlockEdge &Root) {
|
||||||
unsigned Count = 0;
|
unsigned Count = 0;
|
||||||
for (Value::use_iterator UI = From->use_begin(), UE = From->use_end();
|
for (Value::use_iterator UI = From->use_begin(), UE = From->use_end();
|
||||||
UI != UE; ) {
|
UI != UE; ) {
|
||||||
Use &U = (UI++).getUse();
|
Use &U = (UI++).getUse();
|
||||||
|
|
||||||
// If From occurs as a phi node operand then the use implicitly lives in the
|
if (DT->dominates(Root, U)) {
|
||||||
// corresponding incoming block. Otherwise it is the block containing the
|
|
||||||
// user that must be dominated by Root.
|
|
||||||
BasicBlock *UsingBlock;
|
|
||||||
if (PHINode *PN = dyn_cast<PHINode>(U.getUser()))
|
|
||||||
UsingBlock = PN->getIncomingBlock(U);
|
|
||||||
else
|
|
||||||
UsingBlock = cast<Instruction>(U.getUser())->getParent();
|
|
||||||
|
|
||||||
if (DT->dominates(Root, UsingBlock)) {
|
|
||||||
U.set(To);
|
U.set(To);
|
||||||
++Count;
|
++Count;
|
||||||
}
|
}
|
||||||
@@ -2027,13 +2018,34 @@ unsigned GVN::replaceAllDominatedUsesWith(Value *From, Value *To,
|
|||||||
return Count;
|
return Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// isOnlyReachableViaThisEdge - There is an edge from 'Src' to 'Dst'. Return
|
||||||
|
/// true if every path from the entry block to 'Dst' passes via this edge. In
|
||||||
|
/// particular 'Dst' must not be reachable via another edge from 'Src'.
|
||||||
|
static bool isOnlyReachableViaThisEdge(const BasicBlockEdge &E,
|
||||||
|
DominatorTree *DT) {
|
||||||
|
// While in theory it is interesting to consider the case in which Dst has
|
||||||
|
// more than one predecessor, because Dst might be part of a loop which is
|
||||||
|
// only reachable from Src, in practice it is pointless since at the time
|
||||||
|
// GVN runs all such loops have preheaders, which means that Dst will have
|
||||||
|
// been changed to have only one predecessor, namely Src.
|
||||||
|
const BasicBlock *Pred = E.getEnd()->getSinglePredecessor();
|
||||||
|
const BasicBlock *Src = E.getStart();
|
||||||
|
assert((!Pred || Pred == Src) && "No edge between these basic blocks!");
|
||||||
|
(void)Src;
|
||||||
|
return Pred != 0;
|
||||||
|
}
|
||||||
|
|
||||||
/// propagateEquality - The given values are known to be equal in every block
|
/// propagateEquality - The given values are known to be equal in every block
|
||||||
/// dominated by 'Root'. Exploit this, for example by replacing 'LHS' with
|
/// dominated by 'Root'. Exploit this, for example by replacing 'LHS' with
|
||||||
/// 'RHS' everywhere in the scope. Returns whether a change was made.
|
/// 'RHS' everywhere in the scope. Returns whether a change was made.
|
||||||
bool GVN::propagateEquality(Value *LHS, Value *RHS, const BasicBlock *Root) {
|
bool GVN::propagateEquality(Value *LHS, Value *RHS,
|
||||||
|
const BasicBlockEdge &Root) {
|
||||||
SmallVector<std::pair<Value*, Value*>, 4> Worklist;
|
SmallVector<std::pair<Value*, Value*>, 4> Worklist;
|
||||||
Worklist.push_back(std::make_pair(LHS, RHS));
|
Worklist.push_back(std::make_pair(LHS, RHS));
|
||||||
bool Changed = false;
|
bool Changed = false;
|
||||||
|
// For speed, compute a conservative fast approximation to
|
||||||
|
// DT->dominates(Root, Root.getEnd());
|
||||||
|
bool RootDominatesEnd = isOnlyReachableViaThisEdge(Root, DT);
|
||||||
|
|
||||||
while (!Worklist.empty()) {
|
while (!Worklist.empty()) {
|
||||||
std::pair<Value*, Value*> Item = Worklist.pop_back_val();
|
std::pair<Value*, Value*> Item = Worklist.pop_back_val();
|
||||||
@@ -2065,9 +2077,6 @@ bool GVN::propagateEquality(Value *LHS, Value *RHS, const BasicBlock *Root) {
|
|||||||
LVN = RVN;
|
LVN = RVN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert((!isa<Instruction>(RHS) ||
|
|
||||||
DT->properlyDominates(cast<Instruction>(RHS)->getParent(), Root)) &&
|
|
||||||
"Instruction doesn't dominate scope!");
|
|
||||||
|
|
||||||
// If value numbering later sees that an instruction in the scope is equal
|
// If value numbering later sees that an instruction in the scope is equal
|
||||||
// to 'LHS' then ensure it will be turned into 'RHS'. In order to preserve
|
// to 'LHS' then ensure it will be turned into 'RHS'. In order to preserve
|
||||||
@@ -2076,8 +2085,10 @@ bool GVN::propagateEquality(Value *LHS, Value *RHS, const BasicBlock *Root) {
|
|||||||
// if RHS is an instruction (if an instruction in the scope is morphed into
|
// if RHS is an instruction (if an instruction in the scope is morphed into
|
||||||
// LHS then it will be turned into RHS by the next GVN iteration anyway, so
|
// LHS then it will be turned into RHS by the next GVN iteration anyway, so
|
||||||
// using the leader table is about compiling faster, not optimizing better).
|
// using the leader table is about compiling faster, not optimizing better).
|
||||||
if (!isa<Instruction>(RHS))
|
// The leader table only tracks basic blocks, not edges. Only add to if we
|
||||||
addToLeaderTable(LVN, RHS, Root);
|
// have the simple case where the edge dominates the end.
|
||||||
|
if (RootDominatesEnd && !isa<Instruction>(RHS))
|
||||||
|
addToLeaderTable(LVN, RHS, Root.getEnd());
|
||||||
|
|
||||||
// Replace all occurrences of 'LHS' with 'RHS' everywhere in the scope. As
|
// Replace all occurrences of 'LHS' with 'RHS' everywhere in the scope. As
|
||||||
// LHS always has at least one use that is not dominated by Root, this will
|
// LHS always has at least one use that is not dominated by Root, this will
|
||||||
@@ -2136,7 +2147,7 @@ bool GVN::propagateEquality(Value *LHS, Value *RHS, const BasicBlock *Root) {
|
|||||||
// If the number we were assigned was brand new then there is no point in
|
// If the number we were assigned was brand new then there is no point in
|
||||||
// looking for an instruction realizing it: there cannot be one!
|
// looking for an instruction realizing it: there cannot be one!
|
||||||
if (Num < NextNum) {
|
if (Num < NextNum) {
|
||||||
Value *NotCmp = findLeader(Root, Num);
|
Value *NotCmp = findLeader(Root.getEnd(), Num);
|
||||||
if (NotCmp && isa<Instruction>(NotCmp)) {
|
if (NotCmp && isa<Instruction>(NotCmp)) {
|
||||||
unsigned NumReplacements =
|
unsigned NumReplacements =
|
||||||
replaceAllDominatedUsesWith(NotCmp, NotVal, Root);
|
replaceAllDominatedUsesWith(NotCmp, NotVal, Root);
|
||||||
@@ -2146,7 +2157,10 @@ bool GVN::propagateEquality(Value *LHS, Value *RHS, const BasicBlock *Root) {
|
|||||||
}
|
}
|
||||||
// Ensure that any instruction in scope that gets the "A < B" value number
|
// Ensure that any instruction in scope that gets the "A < B" value number
|
||||||
// is replaced with false.
|
// is replaced with false.
|
||||||
addToLeaderTable(Num, NotVal, Root);
|
// The leader table only tracks basic blocks, not edges. Only add to if we
|
||||||
|
// have the simple case where the edge dominates the end.
|
||||||
|
if (RootDominatesEnd)
|
||||||
|
addToLeaderTable(Num, NotVal, Root.getEnd());
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -2155,22 +2169,6 @@ bool GVN::propagateEquality(Value *LHS, Value *RHS, const BasicBlock *Root) {
|
|||||||
return Changed;
|
return Changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// isOnlyReachableViaThisEdge - There is an edge from 'Src' to 'Dst'. Return
|
|
||||||
/// true if every path from the entry block to 'Dst' passes via this edge. In
|
|
||||||
/// particular 'Dst' must not be reachable via another edge from 'Src'.
|
|
||||||
static bool isOnlyReachableViaThisEdge(BasicBlock *Src, BasicBlock *Dst,
|
|
||||||
DominatorTree *DT) {
|
|
||||||
// While in theory it is interesting to consider the case in which Dst has
|
|
||||||
// more than one predecessor, because Dst might be part of a loop which is
|
|
||||||
// only reachable from Src, in practice it is pointless since at the time
|
|
||||||
// GVN runs all such loops have preheaders, which means that Dst will have
|
|
||||||
// been changed to have only one predecessor, namely Src.
|
|
||||||
BasicBlock *Pred = Dst->getSinglePredecessor();
|
|
||||||
assert((!Pred || Pred == Src) && "No edge between these basic blocks!");
|
|
||||||
(void)Src;
|
|
||||||
return Pred != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// processInstruction - When calculating availability, handle an instruction
|
/// processInstruction - When calculating availability, handle an instruction
|
||||||
/// by inserting it into the appropriate sets
|
/// by inserting it into the appropriate sets
|
||||||
bool GVN::processInstruction(Instruction *I) {
|
bool GVN::processInstruction(Instruction *I) {
|
||||||
@@ -2210,18 +2208,20 @@ bool GVN::processInstruction(Instruction *I) {
|
|||||||
|
|
||||||
BasicBlock *TrueSucc = BI->getSuccessor(0);
|
BasicBlock *TrueSucc = BI->getSuccessor(0);
|
||||||
BasicBlock *FalseSucc = BI->getSuccessor(1);
|
BasicBlock *FalseSucc = BI->getSuccessor(1);
|
||||||
|
// Avoid multiple edges early.
|
||||||
|
if (TrueSucc == FalseSucc)
|
||||||
|
return false;
|
||||||
|
|
||||||
BasicBlock *Parent = BI->getParent();
|
BasicBlock *Parent = BI->getParent();
|
||||||
bool Changed = false;
|
bool Changed = false;
|
||||||
|
|
||||||
if (isOnlyReachableViaThisEdge(Parent, TrueSucc, DT))
|
Value *TrueVal = ConstantInt::getTrue(TrueSucc->getContext());
|
||||||
Changed |= propagateEquality(BranchCond,
|
BasicBlockEdge TrueE(Parent, TrueSucc);
|
||||||
ConstantInt::getTrue(TrueSucc->getContext()),
|
Changed |= propagateEquality(BranchCond, TrueVal, TrueE);
|
||||||
TrueSucc);
|
|
||||||
|
|
||||||
if (isOnlyReachableViaThisEdge(Parent, FalseSucc, DT))
|
Value *FalseVal = ConstantInt::getFalse(FalseSucc->getContext());
|
||||||
Changed |= propagateEquality(BranchCond,
|
BasicBlockEdge FalseE(Parent, FalseSucc);
|
||||||
ConstantInt::getFalse(FalseSucc->getContext()),
|
Changed |= propagateEquality(BranchCond, FalseVal, FalseE);
|
||||||
FalseSucc);
|
|
||||||
|
|
||||||
return Changed;
|
return Changed;
|
||||||
}
|
}
|
||||||
@@ -2234,8 +2234,9 @@ bool GVN::processInstruction(Instruction *I) {
|
|||||||
for (SwitchInst::CaseIt i = SI->case_begin(), e = SI->case_end();
|
for (SwitchInst::CaseIt i = SI->case_begin(), e = SI->case_end();
|
||||||
i != e; ++i) {
|
i != e; ++i) {
|
||||||
BasicBlock *Dst = i.getCaseSuccessor();
|
BasicBlock *Dst = i.getCaseSuccessor();
|
||||||
if (isOnlyReachableViaThisEdge(Parent, Dst, DT))
|
BasicBlockEdge E(Parent, Dst);
|
||||||
Changed |= propagateEquality(SwitchCond, i.getCaseValue(), Dst);
|
if (E.isSingleEdge())
|
||||||
|
Changed |= propagateEquality(SwitchCond, i.getCaseValue(), E);
|
||||||
}
|
}
|
||||||
return Changed;
|
return Changed;
|
||||||
}
|
}
|
||||||
|
@@ -39,20 +39,17 @@ static cl::opt<bool,true>
|
|||||||
VerifyDomInfoX("verify-dom-info", cl::location(VerifyDomInfo),
|
VerifyDomInfoX("verify-dom-info", cl::location(VerifyDomInfo),
|
||||||
cl::desc("Verify dominator info (time consuming)"));
|
cl::desc("Verify dominator info (time consuming)"));
|
||||||
|
|
||||||
namespace llvm {
|
bool BasicBlockEdge::isSingleEdge() const {
|
||||||
class BasicBlockEdge {
|
const TerminatorInst *TI = Start->getTerminator();
|
||||||
const BasicBlock *Start;
|
unsigned NumEdgesToEnd = 0;
|
||||||
const BasicBlock *End;
|
for (unsigned int i = 0, n = TI->getNumSuccessors(); i < n; ++i) {
|
||||||
public:
|
if (TI->getSuccessor(i) == End)
|
||||||
BasicBlockEdge(const BasicBlock *Start_, const BasicBlock *End_) :
|
++NumEdgesToEnd;
|
||||||
Start(Start_), End(End_) { }
|
if (NumEdgesToEnd >= 2)
|
||||||
const BasicBlock *getStart() const {
|
return false;
|
||||||
return Start;
|
}
|
||||||
}
|
assert(NumEdgesToEnd == 1);
|
||||||
const BasicBlock *getEnd() const {
|
return true;
|
||||||
return End;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
60
test/Transforms/GVN/edge.ll
Normal file
60
test/Transforms/GVN/edge.ll
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
; RUN: opt %s -gvn -S -o - | FileCheck %s
|
||||||
|
|
||||||
|
define i32 @f1(i32 %x) {
|
||||||
|
; CHECK: define i32 @f1(
|
||||||
|
bb0:
|
||||||
|
%cmp = icmp eq i32 %x, 0
|
||||||
|
br i1 %cmp, label %bb2, label %bb1
|
||||||
|
bb1:
|
||||||
|
br label %bb2
|
||||||
|
bb2:
|
||||||
|
%cond = phi i32 [ %x, %bb0 ], [ 0, %bb1 ]
|
||||||
|
%foo = add i32 %cond, %x
|
||||||
|
ret i32 %foo
|
||||||
|
; CHECK: bb2:
|
||||||
|
; CHECK: ret i32 %x
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32 @f2(i32 %x) {
|
||||||
|
; CHECK: define i32 @f2(
|
||||||
|
bb0:
|
||||||
|
%cmp = icmp ne i32 %x, 0
|
||||||
|
br i1 %cmp, label %bb1, label %bb2
|
||||||
|
bb1:
|
||||||
|
br label %bb2
|
||||||
|
bb2:
|
||||||
|
%cond = phi i32 [ %x, %bb0 ], [ 0, %bb1 ]
|
||||||
|
%foo = add i32 %cond, %x
|
||||||
|
ret i32 %foo
|
||||||
|
; CHECK: bb2:
|
||||||
|
; CHECK: ret i32 %x
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32 @f3(i32 %x) {
|
||||||
|
; CHECK: define i32 @f3(
|
||||||
|
bb0:
|
||||||
|
switch i32 %x, label %bb1 [ i32 0, label %bb2]
|
||||||
|
bb1:
|
||||||
|
br label %bb2
|
||||||
|
bb2:
|
||||||
|
%cond = phi i32 [ %x, %bb0 ], [ 0, %bb1 ]
|
||||||
|
%foo = add i32 %cond, %x
|
||||||
|
ret i32 %foo
|
||||||
|
; CHECK: bb2:
|
||||||
|
; CHECK: ret i32 %x
|
||||||
|
}
|
||||||
|
|
||||||
|
declare void @g(i1)
|
||||||
|
define void @f4(i8 * %x) {
|
||||||
|
; CHECK: define void @f4(
|
||||||
|
bb0:
|
||||||
|
%y = icmp eq i8* null, %x
|
||||||
|
br i1 %y, label %bb2, label %bb1
|
||||||
|
bb1:
|
||||||
|
br label %bb2
|
||||||
|
bb2:
|
||||||
|
%zed = icmp eq i8* null, %x
|
||||||
|
call void @g(i1 %zed)
|
||||||
|
; CHECK: call void @g(i1 %y)
|
||||||
|
ret void
|
||||||
|
}
|
Reference in New Issue
Block a user