mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 12:12:47 +01:00
[SimplifyCFG] Revise common code sinking
- Fix the case where more than 1 common instructions derived from the same operand cannot be sunk. When a pair of value has more than 1 derived values in both branches, only 1 derived value could be sunk. - Replace BB1 -> (BB2, PN) map with joint value map, i.e. map of (BB1, BB2) -> PN, which is more accurate to track common ops. llvm-svn: 224757
This commit is contained in:
parent
9dee8a54d7
commit
e7760832e1
@ -1244,14 +1244,13 @@ static bool SinkThenElseCodeToEnd(BranchInst *BI1) {
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Gather the PHI nodes in BBEnd.
|
// Gather the PHI nodes in BBEnd.
|
||||||
std::map<Value*, std::pair<Value*, PHINode*> > MapValueFromBB1ToBB2;
|
SmallDenseMap<std::pair<Value *, Value *>, PHINode *> JointValueMap;
|
||||||
Instruction *FirstNonPhiInBBEnd = nullptr;
|
Instruction *FirstNonPhiInBBEnd = nullptr;
|
||||||
for (BasicBlock::iterator I = BBEnd->begin(), E = BBEnd->end();
|
for (BasicBlock::iterator I = BBEnd->begin(), E = BBEnd->end(); I != E; ++I) {
|
||||||
I != E; ++I) {
|
|
||||||
if (PHINode *PN = dyn_cast<PHINode>(I)) {
|
if (PHINode *PN = dyn_cast<PHINode>(I)) {
|
||||||
Value *BB1V = PN->getIncomingValueForBlock(BB1);
|
Value *BB1V = PN->getIncomingValueForBlock(BB1);
|
||||||
Value *BB2V = PN->getIncomingValueForBlock(BB2);
|
Value *BB2V = PN->getIncomingValueForBlock(BB2);
|
||||||
MapValueFromBB1ToBB2[BB1V] = std::make_pair(BB2V, PN);
|
JointValueMap[std::make_pair(BB1V, BB2V)] = PN;
|
||||||
} else {
|
} else {
|
||||||
FirstNonPhiInBBEnd = &*I;
|
FirstNonPhiInBBEnd = &*I;
|
||||||
break;
|
break;
|
||||||
@ -1260,12 +1259,12 @@ static bool SinkThenElseCodeToEnd(BranchInst *BI1) {
|
|||||||
if (!FirstNonPhiInBBEnd)
|
if (!FirstNonPhiInBBEnd)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
||||||
// This does very trivial matching, with limited scanning, to find identical
|
// This does very trivial matching, with limited scanning, to find identical
|
||||||
// instructions in the two blocks. We scan backward for obviously identical
|
// instructions in the two blocks. We scan backward for obviously identical
|
||||||
// instructions in an identical order.
|
// instructions in an identical order.
|
||||||
BasicBlock::InstListType::reverse_iterator RI1 = BB1->getInstList().rbegin(),
|
BasicBlock::InstListType::reverse_iterator RI1 = BB1->getInstList().rbegin(),
|
||||||
RE1 = BB1->getInstList().rend(), RI2 = BB2->getInstList().rbegin(),
|
RE1 = BB1->getInstList().rend(),
|
||||||
|
RI2 = BB2->getInstList().rbegin(),
|
||||||
RE2 = BB2->getInstList().rend();
|
RE2 = BB2->getInstList().rend();
|
||||||
// Skip debug info.
|
// Skip debug info.
|
||||||
while (RI1 != RE1 && isa<DbgInfoIntrinsic>(&*RI1)) ++RI1;
|
while (RI1 != RE1 && isa<DbgInfoIntrinsic>(&*RI1)) ++RI1;
|
||||||
@ -1289,6 +1288,7 @@ static bool SinkThenElseCodeToEnd(BranchInst *BI1) {
|
|||||||
return Changed;
|
return Changed;
|
||||||
|
|
||||||
Instruction *I1 = &*RI1, *I2 = &*RI2;
|
Instruction *I1 = &*RI1, *I2 = &*RI2;
|
||||||
|
auto InstPair = std::make_pair(I1, I2);
|
||||||
// I1 and I2 should have a single use in the same PHI node, and they
|
// I1 and I2 should have a single use in the same PHI node, and they
|
||||||
// perform the same operation.
|
// perform the same operation.
|
||||||
// Cannot move control-flow-involving, volatile loads, vaarg, etc.
|
// Cannot move control-flow-involving, volatile loads, vaarg, etc.
|
||||||
@ -1299,11 +1299,11 @@ static bool SinkThenElseCodeToEnd(BranchInst *BI1) {
|
|||||||
I1->mayHaveSideEffects() || I2->mayHaveSideEffects() ||
|
I1->mayHaveSideEffects() || I2->mayHaveSideEffects() ||
|
||||||
I1->mayReadOrWriteMemory() || I2->mayReadOrWriteMemory() ||
|
I1->mayReadOrWriteMemory() || I2->mayReadOrWriteMemory() ||
|
||||||
!I1->hasOneUse() || !I2->hasOneUse() ||
|
!I1->hasOneUse() || !I2->hasOneUse() ||
|
||||||
MapValueFromBB1ToBB2.find(I1) == MapValueFromBB1ToBB2.end() ||
|
!JointValueMap.count(InstPair))
|
||||||
MapValueFromBB1ToBB2[I1].first != I2)
|
|
||||||
return Changed;
|
return Changed;
|
||||||
|
|
||||||
// Check whether we should swap the operands of ICmpInst.
|
// Check whether we should swap the operands of ICmpInst.
|
||||||
|
// TODO: Add support of communativity.
|
||||||
ICmpInst *ICmp1 = dyn_cast<ICmpInst>(I1), *ICmp2 = dyn_cast<ICmpInst>(I2);
|
ICmpInst *ICmp1 = dyn_cast<ICmpInst>(I1), *ICmp2 = dyn_cast<ICmpInst>(I2);
|
||||||
bool SwapOpnds = false;
|
bool SwapOpnds = false;
|
||||||
if (ICmp1 && ICmp2 &&
|
if (ICmp1 && ICmp2 &&
|
||||||
@ -1324,16 +1324,13 @@ static bool SinkThenElseCodeToEnd(BranchInst *BI1) {
|
|||||||
// with a PHI node after sinking. We only handle the case where there is
|
// with a PHI node after sinking. We only handle the case where there is
|
||||||
// a single pair of different operands.
|
// a single pair of different operands.
|
||||||
Value *DifferentOp1 = nullptr, *DifferentOp2 = nullptr;
|
Value *DifferentOp1 = nullptr, *DifferentOp2 = nullptr;
|
||||||
unsigned Op1Idx = 0;
|
unsigned Op1Idx = ~0U;
|
||||||
for (unsigned I = 0, E = I1->getNumOperands(); I != E; ++I) {
|
for (unsigned I = 0, E = I1->getNumOperands(); I != E; ++I) {
|
||||||
if (I1->getOperand(I) == I2->getOperand(I))
|
if (I1->getOperand(I) == I2->getOperand(I))
|
||||||
continue;
|
continue;
|
||||||
// Early exit if we have more-than one pair of different operands or
|
// Early exit if we have more-than one pair of different operands or if
|
||||||
// the different operand is already in MapValueFromBB1ToBB2.
|
// we need a PHI node to replace a constant.
|
||||||
// Early exit if we need a PHI node to replace a constant.
|
if (Op1Idx != ~0U ||
|
||||||
if (DifferentOp1 ||
|
|
||||||
MapValueFromBB1ToBB2.find(I1->getOperand(I)) !=
|
|
||||||
MapValueFromBB1ToBB2.end() ||
|
|
||||||
isa<Constant>(I1->getOperand(I)) ||
|
isa<Constant>(I1->getOperand(I)) ||
|
||||||
isa<Constant>(I2->getOperand(I))) {
|
isa<Constant>(I2->getOperand(I))) {
|
||||||
// If we can't sink the instructions, undo the swapping.
|
// If we can't sink the instructions, undo the swapping.
|
||||||
@ -1346,24 +1343,27 @@ static bool SinkThenElseCodeToEnd(BranchInst *BI1) {
|
|||||||
DifferentOp2 = I2->getOperand(I);
|
DifferentOp2 = I2->getOperand(I);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We insert the pair of different operands to MapValueFromBB1ToBB2 and
|
DEBUG(dbgs() << "SINK common instructions " << *I1 << "\n");
|
||||||
// remove (I1, I2) from MapValueFromBB1ToBB2.
|
DEBUG(dbgs() << " " << *I2 << "\n");
|
||||||
if (DifferentOp1) {
|
|
||||||
PHINode *NewPN = PHINode::Create(DifferentOp1->getType(), 2,
|
// We insert the pair of different operands to JointValueMap and
|
||||||
DifferentOp1->getName() + ".sink",
|
// remove (I1, I2) from JointValueMap.
|
||||||
BBEnd->begin());
|
if (Op1Idx != ~0U) {
|
||||||
MapValueFromBB1ToBB2[DifferentOp1] = std::make_pair(DifferentOp2, NewPN);
|
auto &NewPN = JointValueMap[std::make_pair(DifferentOp1, DifferentOp2)];
|
||||||
// I1 should use NewPN instead of DifferentOp1.
|
if (!NewPN) {
|
||||||
I1->setOperand(Op1Idx, NewPN);
|
NewPN =
|
||||||
|
PHINode::Create(DifferentOp1->getType(), 2,
|
||||||
|
DifferentOp1->getName() + ".sink", BBEnd->begin());
|
||||||
NewPN->addIncoming(DifferentOp1, BB1);
|
NewPN->addIncoming(DifferentOp1, BB1);
|
||||||
NewPN->addIncoming(DifferentOp2, BB2);
|
NewPN->addIncoming(DifferentOp2, BB2);
|
||||||
DEBUG(dbgs() << "Create PHI node " << *NewPN << "\n";);
|
DEBUG(dbgs() << "Create PHI node " << *NewPN << "\n";);
|
||||||
}
|
}
|
||||||
PHINode *OldPN = MapValueFromBB1ToBB2[I1].second;
|
// I1 should use NewPN instead of DifferentOp1.
|
||||||
MapValueFromBB1ToBB2.erase(I1);
|
I1->setOperand(Op1Idx, NewPN);
|
||||||
|
}
|
||||||
|
PHINode *OldPN = JointValueMap[InstPair];
|
||||||
|
JointValueMap.erase(InstPair);
|
||||||
|
|
||||||
DEBUG(dbgs() << "SINK common instructions " << *I1 << "\n";);
|
|
||||||
DEBUG(dbgs() << " " << *I2 << "\n";);
|
|
||||||
// We need to update RE1 and RE2 if we are going to sink the first
|
// We need to update RE1 and RE2 if we are going to sink the first
|
||||||
// instruction in the basic block down.
|
// instruction in the basic block down.
|
||||||
bool UpdateRE1 = (I1 == BB1->begin()), UpdateRE2 = (I2 == BB2->begin());
|
bool UpdateRE1 = (I1 == BB1->begin()), UpdateRE2 = (I2 == BB2->begin());
|
||||||
|
@ -4,7 +4,7 @@ define zeroext i1 @test1(i1 zeroext %flag, i32 %blksA, i32 %blksB, i32 %nblks) {
|
|||||||
entry:
|
entry:
|
||||||
br i1 %flag, label %if.then, label %if.else
|
br i1 %flag, label %if.then, label %if.else
|
||||||
|
|
||||||
; CHECK: test1
|
; CHECK-LABEL: test1
|
||||||
; CHECK: add
|
; CHECK: add
|
||||||
; CHECK: select
|
; CHECK: select
|
||||||
; CHECK: icmp
|
; CHECK: icmp
|
||||||
@ -30,7 +30,7 @@ define zeroext i1 @test2(i1 zeroext %flag, i32 %blksA, i32 %blksB, i32 %nblks) {
|
|||||||
entry:
|
entry:
|
||||||
br i1 %flag, label %if.then, label %if.else
|
br i1 %flag, label %if.then, label %if.else
|
||||||
|
|
||||||
; CHECK: test2
|
; CHECK-LABEL: test2
|
||||||
; CHECK: add
|
; CHECK: add
|
||||||
; CHECK: select
|
; CHECK: select
|
||||||
; CHECK: icmp
|
; CHECK: icmp
|
||||||
@ -51,3 +51,33 @@ if.end:
|
|||||||
%tobool4 = icmp ne i8 %obeys.0, 0
|
%tobool4 = icmp ne i8 %obeys.0, 0
|
||||||
ret i1 %tobool4
|
ret i1 %tobool4
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare i32 @foo(i32, i32) nounwind readnone
|
||||||
|
|
||||||
|
define i32 @test3(i1 zeroext %flag, i32 %x, i32 %y) {
|
||||||
|
entry:
|
||||||
|
br i1 %flag, label %if.then, label %if.else
|
||||||
|
|
||||||
|
if.then:
|
||||||
|
%x0 = call i32 @foo(i32 %x, i32 0) nounwind readnone
|
||||||
|
%y0 = call i32 @foo(i32 %x, i32 1) nounwind readnone
|
||||||
|
br label %if.end
|
||||||
|
|
||||||
|
if.else:
|
||||||
|
%x1 = call i32 @foo(i32 %y, i32 0) nounwind readnone
|
||||||
|
%y1 = call i32 @foo(i32 %y, i32 1) nounwind readnone
|
||||||
|
br label %if.end
|
||||||
|
|
||||||
|
if.end:
|
||||||
|
%xx = phi i32 [ %x0, %if.then ], [ %x1, %if.else ]
|
||||||
|
%yy = phi i32 [ %y0, %if.then ], [ %y1, %if.else ]
|
||||||
|
%ret = add i32 %xx, %yy
|
||||||
|
ret i32 %ret
|
||||||
|
}
|
||||||
|
|
||||||
|
; CHECK-LABEL: test3
|
||||||
|
; CHECK: select
|
||||||
|
; CHECK: call
|
||||||
|
; CHECK: call
|
||||||
|
; CHECK: add
|
||||||
|
; CHECK-NOT: br
|
||||||
|
Loading…
Reference in New Issue
Block a user