1
0
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:
Michael Liao 2014-12-23 08:26:55 +00:00
parent 9dee8a54d7
commit e7760832e1
2 changed files with 62 additions and 32 deletions

View File

@ -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());

View File

@ -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