From lattner at cs.uiuc.edu Mon Sep 19 00:23:55 2005
From: lattner at cs.uiuc.edu (Chris Lattner)
Date: Mon, 19 Sep 2005 00:23:55 -0500
Subject: [llvm-commits] CVS: llvm/lib/Target/X86/X86RegisterInfo.cpp
X86RegisterInfo.h
Message-ID: <200509190523.AAA00430@zion.cs.uiuc.edu>
Changes in directory llvm/lib/Target/X86:
X86RegisterInfo.cpp updated: 1.108 -> 1.109
X86RegisterInfo.h updated: 1.30 -> 1.31
---
Log message:
Implement the isLoadFromStackSlot interface
---
Diffs of the changes: (+28 -0)
X86RegisterInfo.cpp | 25 +++++++++++++++++++++++++
X86RegisterInfo.h | 3 +++
2 files changed, 28 insertions(+)
Index: llvm/lib/Target/X86/X86RegisterInfo.cpp
diff -u llvm/lib/Target/X86/X86RegisterInfo.cpp:1.108 llvm/lib/Target/X86/X86RegisterInfo.cpp:1.109
--- llvm/lib/Target/X86/X86RegisterInfo.cpp:1.108 Fri Aug 19 13:32:03 2005
+++ llvm/lib/Target/X86/X86RegisterInfo.cpp Mon Sep 19 00:23:44 2005
@@ -92,6 +92,31 @@
BuildMI(MBB, MI, Opc, 1, DestReg).addReg(SrcReg);
}
+unsigned X86RegisterInfo::isLoadFromStackSlot(MachineInstr *MI,
+ int &FrameIndex) const {
+ switch (MI->getOpcode()) {
+ default: break;
+ case X86::MOV8rm:
+ case X86::MOV16rm:
+ case X86::MOV32rm:
+ case X86::FLD64m:
+ case X86::FLD80m:
+ case X86::MOVAPDrm:
+ case X86::MOVSDrm:
+ if (MI->getOperand(1).isFrameIndex() && MI->getOperand(2).isImmediate() &&
+ MI->getOperand(3).isRegister() && MI->getOperand(4).isImmediate() &&
+ MI->getOperand(2).getImmedValue() == 1 &&
+ MI->getOperand(3).getReg() == 0 &&
+ MI->getOperand(4).getImmedValue() == 0) {
+ FrameIndex = MI->getOperand(1).getFrameIndex();
+ return MI->getOperand(0).getReg();
+ }
+ break;
+ }
+ return 0;
+}
+
+
static MachineInstr *MakeMInst(unsigned Opcode, unsigned FrameIndex,
MachineInstr *MI) {
return addFrameReference(BuildMI(Opcode, 4), FrameIndex);
Index: llvm/lib/Target/X86/X86RegisterInfo.h
diff -u llvm/lib/Target/X86/X86RegisterInfo.h:1.30 llvm/lib/Target/X86/X86RegisterInfo.h:1.31
--- llvm/lib/Target/X86/X86RegisterInfo.h:1.30 Fri Aug 19 13:32:03 2005
+++ llvm/lib/Target/X86/X86RegisterInfo.h Mon Sep 19 00:23:44 2005
@@ -39,6 +39,9 @@
unsigned DestReg, unsigned SrcReg,
const TargetRegisterClass *RC) const;
+ unsigned isLoadFromStackSlot(MachineInstr *MI, int &FrameIndex) const;
+
+
/// foldMemoryOperand - If this target supports it, fold a load or store of
/// the specified stack slot into the specified machine instruction for the
/// specified operand. If this is possible, the target should perform the
From lattner at cs.uiuc.edu Mon Sep 19 01:56:33 2005
From: lattner at cs.uiuc.edu (Chris Lattner)
Date: Mon, 19 Sep 2005 01:56:33 -0500
Subject: [llvm-commits] CVS: llvm/lib/CodeGen/VirtRegMap.cpp
Message-ID: <200509190656.BAA10993@zion.cs.uiuc.edu>
Changes in directory llvm/lib/CodeGen:
VirtRegMap.cpp updated: 1.38 -> 1.39
---
Log message:
Teach the local spiller to turn stack slot loads into register-register copies
when possible, avoiding the load (and avoiding the copy if the value is already
in the right register).
This patch came about when I noticed code like the following being generated:
store R17 -> [SS1]
...blah...
R4 = load [SS1]
This was causing an LSU reject on the G5. This problem was due to the register
allocator folding spill code into a reg-reg copy (producing the load), which
prevented the spiller from being able to rewrite the load into a copy, despite
the fact that the value was already available in a register. In the case
above, we now rip out the R4 load and replace it with a R4 = R17 copy.
This speeds up several programs on X86 (which spills a lot :) ), e.g.
smg2k from 22.39->20.60s, povray from 12.93->12.66s, 168.wupwise from
68.54->53.83s (!), 197.parser from 7.33->6.62s (!), etc. This may have a larger
impact in some cases on the G5 (by avoiding LSU rejects), though it probably
won't trigger as often (less spilling in general).
Targets that implement folding of loads/stores into copies should implement
the isLoadFromStackSlot hook to get this.
---
Diffs of the changes: (+52 -26)
VirtRegMap.cpp | 78 ++++++++++++++++++++++++++++++++++++++-------------------
1 files changed, 52 insertions(+), 26 deletions(-)
Index: llvm/lib/CodeGen/VirtRegMap.cpp
diff -u llvm/lib/CodeGen/VirtRegMap.cpp:1.38 llvm/lib/CodeGen/VirtRegMap.cpp:1.39
--- llvm/lib/CodeGen/VirtRegMap.cpp:1.38 Fri Sep 9 15:29:51 2005
+++ llvm/lib/CodeGen/VirtRegMap.cpp Mon Sep 19 01:56:21 2005
@@ -466,36 +466,61 @@
<< I->second.second);
unsigned VirtReg = I->second.first;
VirtRegMap::ModRef MR = I->second.second;
- if (VRM.hasStackSlot(VirtReg)) {
- int SS = VRM.getStackSlot(VirtReg);
- DEBUG(std::cerr << " - StackSlot: " << SS << "\n");
-
- // If this reference is not a use, any previous store is now dead.
- // Otherwise, the store to this stack slot is not dead anymore.
- std::map::iterator MDSI = MaybeDeadStores.find(SS);
- if (MDSI != MaybeDeadStores.end()) {
- if (MR & VirtRegMap::isRef) // Previous store is not dead.
- MaybeDeadStores.erase(MDSI);
- else {
- // If we get here, the store is dead, nuke it now.
- assert(MR == VirtRegMap::isMod && "Can't be modref!");
- MBB.erase(MDSI->second);
- MaybeDeadStores.erase(MDSI);
- ++NumDSE;
+ if (!VRM.hasStackSlot(VirtReg)) {
+ DEBUG(std::cerr << ": No stack slot!\n");
+ continue;
+ }
+ int SS = VRM.getStackSlot(VirtReg);
+ DEBUG(std::cerr << " - StackSlot: " << SS << "\n");
+
+ // If this folded instruction is just a use, check to see if it's a
+ // straight load from the virt reg slot.
+ if ((MR & VirtRegMap::isRef) && !(MR & VirtRegMap::isMod)) {
+ int FrameIdx;
+ if (unsigned DestReg = MRI->isLoadFromStackSlot(&MI, FrameIdx)) {
+ // If this spill slot is available, insert a copy for it!
+ std::map::iterator It = SpillSlotsAvailable.find(SS);
+ if (FrameIdx == SS && It != SpillSlotsAvailable.end()) {
+ DEBUG(std::cerr << "Promoted Load To Copy: " << MI);
+ MachineFunction &MF = *MBB.getParent();
+ if (DestReg != It->second) {
+ MRI->copyRegToReg(MBB, &MI, DestReg, It->second,
+ MF.getSSARegMap()->getRegClass(VirtReg));
+ // Revisit the copy if the destination is a vreg.
+ if (MRegisterInfo::isVirtualRegister(DestReg)) {
+ NextMII = &MI;
+ --NextMII; // backtrack to the copy.
+ }
+ }
+ MBB.erase(&MI);
+ goto ProcessNextInst;
}
}
+ }
+
+ // If this reference is not a use, any previous store is now dead.
+ // Otherwise, the store to this stack slot is not dead anymore.
+ std::map::iterator MDSI = MaybeDeadStores.find(SS);
+ if (MDSI != MaybeDeadStores.end()) {
+ if (MR & VirtRegMap::isRef) // Previous store is not dead.
+ MaybeDeadStores.erase(MDSI);
+ else {
+ // If we get here, the store is dead, nuke it now.
+ assert(MR == VirtRegMap::isMod && "Can't be modref!");
+ MBB.erase(MDSI->second);
+ MaybeDeadStores.erase(MDSI);
+ ++NumDSE;
+ }
+ }
- // If the spill slot value is available, and this is a new definition of
- // the value, the value is not available anymore.
- if (MR & VirtRegMap::isMod) {
- std::map::iterator It = SpillSlotsAvailable.find(SS);
- if (It != SpillSlotsAvailable.end()) {
- PhysRegsAvailable.erase(It->second);
- SpillSlotsAvailable.erase(It);
- }
+ // If the spill slot value is available, and this is a new definition of
+ // the value, the value is not available anymore.
+ if (MR & VirtRegMap::isMod) {
+ std::map::iterator It = SpillSlotsAvailable.find(SS);
+ if (It != SpillSlotsAvailable.end()) {
+ PhysRegsAvailable.erase(It->second);
+ SpillSlotsAvailable.erase(It);
}
- } else {
- DEBUG(std::cerr << ": No stack slot!\n");
}
}
@@ -575,6 +600,7 @@
}
}
}
+ ProcessNextInst:
MII = NextMII;
}
}
From natebegeman at mac.com Mon Sep 19 17:34:12 2005
From: natebegeman at mac.com (Nate Begeman)
Date: Mon, 19 Sep 2005 17:34:12 -0500
Subject: [llvm-commits] CVS: llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
Message-ID: <200509192234.RAA00686@zion.cs.uiuc.edu>
Changes in directory llvm/lib/CodeGen/SelectionDAG:
DAGCombiner.cpp updated: 1.12 -> 1.13
---
Log message:
Stub out the rest of the DAG Combiner. Just need to fill in the
select_cc bits and then wrap it in a convenience function for use with
regular select.
---
Diffs of the changes: (+105 -9)
DAGCombiner.cpp | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++-----
1 files changed, 105 insertions(+), 9 deletions(-)
Index: llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
diff -u llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp:1.12 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp:1.13
--- llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp:1.12 Thu Sep 15 19:54:12 2005
+++ llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp Mon Sep 19 17:34:01 2005
@@ -20,6 +20,14 @@
// ZERO_EXTEND/SIGN_EXTEND by converting them to an ANY_EXTEND node which
// we don't have yet.
//
+// FIXME: select C, 16, 0 -> shr C, 4
+// FIXME: select C, pow2, pow2 -> something smart
+// FIXME: trunc(select X, Y, Z) -> select X, trunc(Y), trunc(Z)
+// FIXME: (select C, load A, load B) -> load (select C, A, B)
+// FIXME: store -> load -> forward substitute
+// FIXME: Dead stores -> nuke
+// FIXME: shr X, (and Y,31) -> shr X, Y
+// FIXME: TRUNC (LOAD) -> EXT_LOAD/LOAD(smaller)
// FIXME: mul (x, const) -> shifts + adds
// FIXME: undef values
// FIXME: zero extend when top bits are 0 -> drop it ?
@@ -117,10 +125,13 @@
SDOperand visitFNEG(SDNode *N);
SDOperand visitFABS(SDNode *N);
SDOperand visitBRCOND(SDNode *N);
- // brcondtwoway
- // br_cc
- // brtwoway_cc
-
+ SDOperand visitBRCONDTWOWAY(SDNode *N);
+ SDOperand visitBR_CC(SDNode *N);
+ SDOperand visitBRTWOWAY_CC(SDNode *N);
+
+ SDOperand SimplifySelect(SDOperand N0, SDOperand N1, SDOperand N2);
+ SDOperand SimplifySelectCC(SDOperand N0, SDOperand N1, SDOperand N2,
+ SDOperand N3, ISD::CondCode CC);
SDOperand SimplifySetCC(MVT::ValueType VT, SDOperand N0, SDOperand N1,
ISD::CondCode Cond);
public:
@@ -339,6 +350,10 @@
case ISD::FP_EXTEND: return visitFP_EXTEND(N);
case ISD::FNEG: return visitFNEG(N);
case ISD::FABS: return visitFABS(N);
+ case ISD::BRCOND: return visitBRCOND(N);
+ case ISD::BRCONDTWOWAY: return visitBRCONDTWOWAY(N);
+ case ISD::BR_CC: return visitBR_CC(N);
+ case ISD::BRTWOWAY_CC: return visitBRTWOWAY_CC(N);
}
return SDOperand();
}
@@ -1029,7 +1044,7 @@
ConstantSDNode *N1C = dyn_cast(N1);
ConstantSDNode *N2C = dyn_cast(N2);
MVT::ValueType VT = N->getValueType(0);
-
+
// fold select C, X, X -> X
if (N1 == N2)
return N1;
@@ -1040,7 +1055,7 @@
if (N0C && N0C->isNullValue())
return N2;
// fold select C, 1, X -> C | X
- if (MVT::i1 == VT && N1C && !N1C->isNullValue())
+ if (MVT::i1 == VT && N1C && N1C->getValue() == 1)
return DAG.getNode(ISD::OR, VT, N0, N2);
// fold select C, 0, X -> ~C & X
// FIXME: this should check for C type == X type, not i1?
@@ -1050,7 +1065,7 @@
return DAG.getNode(ISD::AND, VT, XORNode, N2);
}
// fold select C, X, 1 -> ~C | X
- if (MVT::i1 == VT && N2C && !N2C->isNullValue()) {
+ if (MVT::i1 == VT && N2C && N2C->getValue() == 1) {
SDOperand XORNode = DAG.getNode(ISD::XOR, VT, N0, DAG.getConstant(1, VT));
WorkList.push_back(XORNode.Val);
return DAG.getNode(ISD::OR, VT, XORNode, N1);
@@ -1065,12 +1080,40 @@
// fold X ? Y : X --> X ? Y : 0 --> X & Y
if (MVT::i1 == VT && N0 == N2)
return DAG.getNode(ISD::AND, VT, N0, N1);
-
+ // fold selects based on a setcc into other things, such as min/max/abs
+ if (N0.getOpcode() == ISD::SETCC)
+ return SimplifySelect(N0, N1, N2);
return SDOperand();
}
SDOperand DAGCombiner::visitSELECT_CC(SDNode *N) {
- return SDOperand();
+ SDOperand N0 = N->getOperand(0);
+ SDOperand N1 = N->getOperand(1);
+ SDOperand N2 = N->getOperand(2);
+ SDOperand N3 = N->getOperand(3);
+ SDOperand N4 = N->getOperand(4);
+ ConstantSDNode *N0C = dyn_cast(N0);
+ ConstantSDNode *N1C = dyn_cast(N1);
+ ConstantSDNode *N2C = dyn_cast(N2);
+ ISD::CondCode CC = cast(N4)->get();
+
+ // Determine if the condition we're dealing with is constant
+ SDOperand SCC = SimplifySetCC(TLI.getSetCCResultTy(), N0, N1, CC);
+ ConstantSDNode *SCCC = dyn_cast(SCC);
+ bool constTrue = SCCC && SCCC->getValue() == 1;
+ bool constFalse = SCCC && SCCC->isNullValue();
+
+ // fold select_cc lhs, rhs, x, x, cc -> x
+ if (N2 == N3)
+ return N2;
+ // fold select_cc true, x, y -> x
+ if (constTrue)
+ return N2;
+ // fold select_cc false, x, y -> y
+ if (constFalse)
+ return N3;
+ // fold select_cc into other things, such as min/max/abs
+ return SimplifySelectCC(N0, N1, N2, N3, CC);
}
SDOperand DAGCombiner::visitSETCC(SDNode *N) {
@@ -1290,6 +1333,59 @@
return SDOperand();
}
+SDOperand DAGCombiner::visitBRCOND(SDNode *N) {
+ SDOperand Chain = N->getOperand(0);
+ SDOperand N1 = N->getOperand(1);
+ SDOperand N2 = N->getOperand(2);
+ ConstantSDNode *N1C = dyn_cast(N1);
+
+ // never taken branch, fold to chain
+ if (N1C && N1C->isNullValue())
+ return Chain;
+ // unconditional branch
+ if (N1C && !N1C->isNullValue())
+ return DAG.getNode(ISD::BR, MVT::Other, Chain, N2);
+ return SDOperand();
+}
+
+SDOperand DAGCombiner::visitBRCONDTWOWAY(SDNode *N) {
+ SDOperand Chain = N->getOperand(0);
+ SDOperand N1 = N->getOperand(1);
+ SDOperand N2 = N->getOperand(2);
+ SDOperand N3 = N->getOperand(3);
+ ConstantSDNode *N1C = dyn_cast(N1);
+
+ // unconditional branch to true mbb
+ if (N1C && N1C->getValue() == 1)
+ return DAG.getNode(ISD::BR, MVT::Other, Chain, N2);
+ // unconditional branch to false mbb
+ if (N1C && N1C->isNullValue())
+ return DAG.getNode(ISD::BR, MVT::Other, Chain, N3);
+ return SDOperand();
+}
+
+SDOperand DAGCombiner::visitBR_CC(SDNode *N) {
+ // FIXME: come up with a common way between br_cc, brtwoway_cc, and select_cc
+ // to canonicalize the condition without calling getnode a bazillion times.
+ return SDOperand();
+}
+
+SDOperand DAGCombiner::visitBRTWOWAY_CC(SDNode *N) {
+ // FIXME: come up with a common way between br_cc, brtwoway_cc, and select_cc
+ // to canonicalize the condition without calling getnode a bazillion times.
+ return SDOperand();
+}
+
+SDOperand DAGCombiner::SimplifySelect(SDOperand N0, SDOperand N1, SDOperand N2){
+ return SDOperand();
+}
+
+SDOperand DAGCombiner::SimplifySelectCC(SDOperand N0, SDOperand N1,
+ SDOperand N2, SDOperand N3,
+ ISD::CondCode CC) {
+ return SDOperand();
+}
+
SDOperand DAGCombiner::SimplifySetCC(MVT::ValueType VT, SDOperand N0,
SDOperand N1, ISD::CondCode Cond) {
// These setcc operations always fold.
From lattner at cs.uiuc.edu Mon Sep 19 18:48:15 2005
From: lattner at cs.uiuc.edu (Chris Lattner)
Date: Mon, 19 Sep 2005 18:48:15 -0500
Subject: [llvm-commits]
CVS: llvm/test/Regression/Transforms/SimplifyCFG/branch-phi-thread.ll
Message-ID: <200509192348.SAA01088@zion.cs.uiuc.edu>
Changes in directory llvm/test/Regression/Transforms/SimplifyCFG:
branch-phi-thread.ll added (r1.1)
---
Log message:
new testcase.
---
Diffs of the changes: (+26 -0)
branch-phi-thread.ll | 26 ++++++++++++++++++++++++++
1 files changed, 26 insertions(+)
Index: llvm/test/Regression/Transforms/SimplifyCFG/branch-phi-thread.ll
diff -c /dev/null llvm/test/Regression/Transforms/SimplifyCFG/branch-phi-thread.ll:1.1
*** /dev/null Mon Sep 19 18:48:14 2005
--- llvm/test/Regression/Transforms/SimplifyCFG/branch-phi-thread.ll Mon Sep 19 18:48:04 2005
***************
*** 0 ****
--- 1,26 ----
+ ; RUN: llvm-as < %s | opt -simplifycfg -adce | llvm-dis | not grep 'call void %f1'
+ declare void %f1()
+ declare void %f2()
+ declare void %f3()
+ declare void %f4()
+
+ implementation
+
+ int %test2(int %X, bool %D) {
+ E:
+ %C = seteq int %X, 0
+ br bool %C, label %T, label %F
+ T:
+ %P = phi bool [true, %E], [%C, %A]
+ br bool %P, label %B, label %A
+ A:
+ call void %f1()
+ br bool %D, label %T, label %F
+ B:
+ call void %f2()
+ ret int 345
+ F:
+ call void %f3()
+ ret int 123
+ }
+
From lattner at cs.uiuc.edu Mon Sep 19 18:49:48 2005
From: lattner at cs.uiuc.edu (Chris Lattner)
Date: Mon, 19 Sep 2005 18:49:48 -0500
Subject: [llvm-commits] CVS: llvm/lib/Transforms/Utils/SimplifyCFG.cpp
Message-ID: <200509192349.SAA01125@zion.cs.uiuc.edu>
Changes in directory llvm/lib/Transforms/Utils:
SimplifyCFG.cpp updated: 1.82 -> 1.83
---
Log message:
Implement SimplifyCFG/branch-phi-thread.ll, the most trivial case of threading
control across branches with determined outcomes. More generality to follow.
This triggers a couple thousand times in specint.
---
Diffs of the changes: (+73 -0)
SimplifyCFG.cpp | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 73 insertions(+)
Index: llvm/lib/Transforms/Utils/SimplifyCFG.cpp
diff -u llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.82 llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.83
--- llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.82 Wed Aug 3 12:59:45 2005
+++ llvm/lib/Transforms/Utils/SimplifyCFG.cpp Mon Sep 19 18:49:37 2005
@@ -18,6 +18,7 @@
#include "llvm/Type.h"
#include "llvm/Support/CFG.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include
#include
#include
@@ -889,6 +890,70 @@
return true;
}
+/// FoldCondBranchOnPHI - If we have a conditional branch on a PHI node value
+/// that is defined in the same block as the branch and if any PHI entries are
+/// constants, thread edges corresponding to that entry to be branches to their
+/// ultimate destination.
+static bool FoldCondBranchOnPHI(BranchInst *BI) {
+ BasicBlock *BB = BI->getParent();
+ PHINode *PN = dyn_cast(BI->getCondition());
+ if (!PN || PN->getParent() != BB) return false;
+
+ // Degenerate case of a single entry PHI.
+ if (PN->getNumIncomingValues() == 1) {
+ if (PN->getIncomingValue(0) != PN)
+ PN->replaceAllUsesWith(PN->getIncomingValue(0));
+ else
+ PN->replaceAllUsesWith(UndefValue::get(PN->getType()));
+ PN->eraseFromParent();
+ return true;
+ }
+
+ // Now we know that this block has multiple preds and two succs.
+
+ // If this basic block contains anything other than the PHI and branch, bail
+ // out. FIXME: improve this in the future.
+ BasicBlock::iterator BBI = BB->begin();
+ if (&*BBI != PN || &*++BBI != BI)
+ return false;
+
+ // Okay, this is a simple enough basic block. See if any phi values are
+ // constants.
+ for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i)
+ if (ConstantBool *CB = dyn_cast(PN->getIncomingValue(i))) {
+ // Okay, we now know that all edges from PredBB should be revectored to
+ // branch to RealDest.
+ BasicBlock *PredBB = PN->getIncomingBlock(i);
+ BasicBlock *RealDest = BI->getSuccessor(!CB->getValue());
+
+ // If there are PHI nodes in the destination block, we have to add an
+ // entry for PredBB. Instead of being smart about this, just split the
+ // critical edge, which will eliminate the PHI-ness.
+ if (isa(RealDest->begin())) {
+ SplitCriticalEdge(BI, !CB->getValue());
+ RealDest = BI->getSuccessor(!CB->getValue());
+ }
+ assert(!isa(RealDest->begin()) && "Crit edge split failure!");
+
+ // Loop over all of the edges from PredBB to BB, changing them to branch
+ // to RealDest instead.
+ TerminatorInst *PredBBTI = PredBB->getTerminator();
+ for (unsigned i = 0, e = PredBBTI->getNumSuccessors(); i != e; ++i)
+ if (PredBBTI->getSuccessor(i) == BB) {
+ BB->removePredecessor(PredBB);
+ PredBBTI->setSuccessor(i, RealDest);
+ }
+
+ std::cerr << *BB;
+
+ // Recurse, simplifying any other constants.
+ return FoldCondBranchOnPHI(BI) | true;
+ }
+
+ return false;
+}
+
+
namespace {
/// ConstantIntOrdering - This class implements a stable ordering of constant
/// integers that does not depend on their address. This is important for
@@ -1144,6 +1209,14 @@
if (FoldValueComparisonIntoPredecessors(BI))
return SimplifyCFG(BB) | true;
}
+
+ // If this is a branch on a phi node in the current block, thread control
+ // through this block if any PHI node entries are constants.
+ if (PHINode *PN = dyn_cast(BI->getCondition()))
+ if (PN->getParent() == BI->getParent())
+ if (FoldCondBranchOnPHI(BI))
+ return SimplifyCFG(BB) | true;
+
// If this basic block is ONLY a setcc and a branch, and if a predecessor
// branches to us and one of our successors, fold the setcc into the
From lattner at cs.uiuc.edu Mon Sep 19 18:50:26 2005
From: lattner at cs.uiuc.edu (Chris Lattner)
Date: Mon, 19 Sep 2005 18:50:26 -0500
Subject: [llvm-commits] CVS: llvm/lib/Transforms/Utils/SimplifyCFG.cpp
Message-ID: <200509192350.SAA01193@zion.cs.uiuc.edu>
Changes in directory llvm/lib/Transforms/Utils:
SimplifyCFG.cpp updated: 1.83 -> 1.84
---
Log message:
remove debugging code :-/
---
Diffs of the changes: (+0 -2)
SimplifyCFG.cpp | 2 --
1 files changed, 2 deletions(-)
Index: llvm/lib/Transforms/Utils/SimplifyCFG.cpp
diff -u llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.83 llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.84
--- llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.83 Mon Sep 19 18:49:37 2005
+++ llvm/lib/Transforms/Utils/SimplifyCFG.cpp Mon Sep 19 18:50:15 2005
@@ -944,8 +944,6 @@
PredBBTI->setSuccessor(i, RealDest);
}
- std::cerr << *BB;
-
// Recurse, simplifying any other constants.
return FoldCondBranchOnPHI(BI) | true;
}
From lattner at cs.uiuc.edu Mon Sep 19 18:57:16 2005
From: lattner at cs.uiuc.edu (Chris Lattner)
Date: Mon, 19 Sep 2005 18:57:16 -0500
Subject: [llvm-commits] CVS: llvm/lib/Transforms/Utils/SimplifyCFG.cpp
Message-ID: <200509192357.SAA01269@zion.cs.uiuc.edu>
Changes in directory llvm/lib/Transforms/Utils:
SimplifyCFG.cpp updated: 1.84 -> 1.85
---
Log message:
Reject a case we don't handle yet
---
Diffs of the changes: (+3 -1)
SimplifyCFG.cpp | 4 +++-
1 files changed, 3 insertions(+), 1 deletion(-)
Index: llvm/lib/Transforms/Utils/SimplifyCFG.cpp
diff -u llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.84 llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.85
--- llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.84 Mon Sep 19 18:50:15 2005
+++ llvm/lib/Transforms/Utils/SimplifyCFG.cpp Mon Sep 19 18:57:04 2005
@@ -897,7 +897,9 @@
static bool FoldCondBranchOnPHI(BranchInst *BI) {
BasicBlock *BB = BI->getParent();
PHINode *PN = dyn_cast(BI->getCondition());
- if (!PN || PN->getParent() != BB) return false;
+ // NOTE: we currently cannot transform this case if the PHI node is used
+ // outside of the block.
+ if (!PN || PN->getParent() != BB || !PN->hasOneUse()) return false;
// Degenerate case of a single entry PHI.
if (PN->getNumIncomingValues() == 1) {
From lattner at cs.uiuc.edu Mon Sep 19 19:42:06 2005
From: lattner at cs.uiuc.edu (Chris Lattner)
Date: Mon, 19 Sep 2005 19:42:06 -0500
Subject: [llvm-commits]
CVS: llvm/test/Regression/Transforms/SimplifyCFG/branch-phi-thread.ll
Message-ID: <200509200042.TAA01480@zion.cs.uiuc.edu>
Changes in directory llvm/test/Regression/Transforms/SimplifyCFG:
branch-phi-thread.ll updated: 1.1 -> 1.2
---
Log message:
new testcase
---
Diffs of the changes: (+19 -1)
branch-phi-thread.ll | 20 +++++++++++++++++++-
1 files changed, 19 insertions(+), 1 deletion(-)
Index: llvm/test/Regression/Transforms/SimplifyCFG/branch-phi-thread.ll
diff -u llvm/test/Regression/Transforms/SimplifyCFG/branch-phi-thread.ll:1.1 llvm/test/Regression/Transforms/SimplifyCFG/branch-phi-thread.ll:1.2
--- llvm/test/Regression/Transforms/SimplifyCFG/branch-phi-thread.ll:1.1 Mon Sep 19 18:48:04 2005
+++ llvm/test/Regression/Transforms/SimplifyCFG/branch-phi-thread.ll Mon Sep 19 19:41:55 2005
@@ -1,4 +1,5 @@
-; RUN: llvm-as < %s | opt -simplifycfg -adce | llvm-dis | not grep 'call void %f1'
+; RUN: llvm-as < %s | opt -simplifycfg -adce | llvm-dis | not grep 'call void %f1' &&
+; RUN: llvm-as < %s | opt -simplifycfg -adce -disable-output
declare void %f1()
declare void %f2()
declare void %f3()
@@ -6,6 +7,23 @@
implementation
+int %test1(int %X, bool %D) {
+E:
+ %C = seteq int %X, 0
+ br bool %C, label %T, label %F
+T:
+ br bool %C, label %B, label %A
+A:
+ call void %f1()
+ br bool %D, label %T, label %F
+B:
+ call void %f2()
+ ret int 345
+F:
+ call void %f3()
+ ret int 123
+}
+
int %test2(int %X, bool %D) {
E:
%C = seteq int %X, 0
From lattner at cs.uiuc.edu Mon Sep 19 19:43:28 2005
From: lattner at cs.uiuc.edu (Chris Lattner)
Date: Mon, 19 Sep 2005 19:43:28 -0500
Subject: [llvm-commits] CVS: llvm/lib/Transforms/Utils/SimplifyCFG.cpp
Message-ID: <200509200043.TAA01546@zion.cs.uiuc.edu>
Changes in directory llvm/lib/Transforms/Utils:
SimplifyCFG.cpp updated: 1.85 -> 1.86
---
Log message:
Implement merging of blocks with the same condition if the block has multiple
predecessors. This implements branch-phi-thread.ll::test1
---
Diffs of the changes: (+59 -21)
SimplifyCFG.cpp | 80 +++++++++++++++++++++++++++++++++++++++++---------------
1 files changed, 59 insertions(+), 21 deletions(-)
Index: llvm/lib/Transforms/Utils/SimplifyCFG.cpp
diff -u llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.85 llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.86
--- llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.85 Mon Sep 19 18:57:04 2005
+++ llvm/lib/Transforms/Utils/SimplifyCFG.cpp Mon Sep 19 19:43:16 2005
@@ -890,6 +890,26 @@
return true;
}
+/// BlockIsSimpleEnoughToThreadThrough - Return true if we can thread a branch
+/// across this block.
+static bool BlockIsSimpleEnoughToThreadThrough(BasicBlock *BB) {
+ BranchInst *BI = cast(BB->getTerminator());
+ Value *Cond = BI->getCondition();
+
+ // If this basic block contains anything other than a PHI (which controls the
+ // branch) and branch itself, bail out. FIXME: improve this in the future.
+ for (BasicBlock::iterator BBI = BB->begin(); &*BBI != BI; ++BBI) {
+ if (!isa(BBI)) return false;
+
+ if (&*BBI != Cond || !Cond->hasOneUse())
+ return false;
+
+ // Looks ok, continue checking.
+ }
+
+ return true;
+}
+
/// FoldCondBranchOnPHI - If we have a conditional branch on a PHI node value
/// that is defined in the same block as the branch and if any PHI entries are
/// constants, thread edges corresponding to that entry to be branches to their
@@ -899,7 +919,8 @@
PHINode *PN = dyn_cast(BI->getCondition());
// NOTE: we currently cannot transform this case if the PHI node is used
// outside of the block.
- if (!PN || PN->getParent() != BB || !PN->hasOneUse()) return false;
+ if (!PN || PN->getParent() != BB || !PN->hasOneUse())
+ return false;
// Degenerate case of a single entry PHI.
if (PN->getNumIncomingValues() == 1) {
@@ -912,12 +933,7 @@
}
// Now we know that this block has multiple preds and two succs.
-
- // If this basic block contains anything other than the PHI and branch, bail
- // out. FIXME: improve this in the future.
- BasicBlock::iterator BBI = BB->begin();
- if (&*BBI != PN || &*++BBI != BI)
- return false;
+ if (!BlockIsSimpleEnoughToThreadThrough(BB)) return false;
// Okay, this is a simple enough basic block. See if any phi values are
// constants.
@@ -1272,22 +1288,44 @@
}
}
- // If this block ends with a branch instruction, and if there is one
- // predecessor, see if the previous block ended with a branch on the same
- // condition, which makes this conditional branch redundant.
- if (BasicBlock *OnlyPred = BB->getSinglePredecessor())
- if (BranchInst *PBI = dyn_cast(OnlyPred->getTerminator()))
- if (PBI->isConditional() &&
+ // If this block ends with a branch instruction, and if there is a
+ // predecessor that ends on a branch of the same condition, make this
+ // conditional branch redundant.
+ for (pred_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI)
+ if (BranchInst *PBI = dyn_cast((*PI)->getTerminator()))
+ if (PBI != BI && PBI->isConditional() &&
PBI->getCondition() == BI->getCondition() &&
- (PBI->getSuccessor(0) != BB || PBI->getSuccessor(1) != BB)) {
+ PBI->getSuccessor(0) != PBI->getSuccessor(1)) {
// Okay, the outcome of this conditional branch is statically
- // knowable. Delete the outgoing CFG edge that is impossible to
- // execute.
- bool CondIsTrue = PBI->getSuccessor(0) == BB;
- BI->getSuccessor(CondIsTrue)->removePredecessor(BB);
- new BranchInst(BI->getSuccessor(!CondIsTrue), BB);
- BB->getInstList().erase(BI);
- return SimplifyCFG(BB) | true;
+ // knowable. If this block had a single pred, handle specially.
+ if (BB->getSinglePredecessor()) {
+ // Turn this into a branch on constant.
+ bool CondIsTrue = PBI->getSuccessor(0) == BB;
+ BI->setCondition(ConstantBool::get(CondIsTrue));
+ return SimplifyCFG(BB); // Nuke the branch on constant.
+ }
+
+ // Otherwise, if there are multiple predecessors, insert a PHI that
+ // merges in the constant and simplify the block result.
+ if (BlockIsSimpleEnoughToThreadThrough(BB)) {
+ PHINode *NewPN = new PHINode(Type::BoolTy,
+ BI->getCondition()->getName()+".pr",
+ BB->begin());
+ for (PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI)
+ if ((PBI = dyn_cast((*PI)->getTerminator())) &&
+ PBI != BI && PBI->isConditional() &&
+ PBI->getCondition() == BI->getCondition() &&
+ PBI->getSuccessor(0) != PBI->getSuccessor(1)) {
+ bool CondIsTrue = PBI->getSuccessor(0) == BB;
+ NewPN->addIncoming(ConstantBool::get(CondIsTrue), *PI);
+ } else {
+ NewPN->addIncoming(BI->getCondition(), *PI);
+ }
+
+ BI->setCondition(NewPN);
+ // This will thread the branch.
+ return SimplifyCFG(BB) | true;
+ }
}
}
} else if (isa(BB->getTerminator())) {
From lattner at cs.uiuc.edu Mon Sep 19 20:43:52 2005
From: lattner at cs.uiuc.edu (Chris Lattner)
Date: Mon, 19 Sep 2005 20:43:52 -0500
Subject: [llvm-commits]
CVS: llvm/test/Regression/Transforms/SimplifyCFG/branch-phi-thread.ll
Message-ID: <200509200143.UAA01928@zion.cs.uiuc.edu>
Changes in directory llvm/test/Regression/Transforms/SimplifyCFG:
branch-phi-thread.ll updated: 1.2 -> 1.3
---
Log message:
make this test harder: add a case where instructions are in the bb to be
threaded over
---
Diffs of the changes: (+19 -0)
branch-phi-thread.ll | 19 +++++++++++++++++++
1 files changed, 19 insertions(+)
Index: llvm/test/Regression/Transforms/SimplifyCFG/branch-phi-thread.ll
diff -u llvm/test/Regression/Transforms/SimplifyCFG/branch-phi-thread.ll:1.2 llvm/test/Regression/Transforms/SimplifyCFG/branch-phi-thread.ll:1.3
--- llvm/test/Regression/Transforms/SimplifyCFG/branch-phi-thread.ll:1.2 Mon Sep 19 19:41:55 2005
+++ llvm/test/Regression/Transforms/SimplifyCFG/branch-phi-thread.ll Mon Sep 19 20:43:41 2005
@@ -42,3 +42,22 @@
ret int 123
}
+int %test3(int %X, bool %D, int* %AP, int* %BP) {
+E:
+ %C = seteq int %X, 0
+ br bool %C, label %T, label %F
+T:
+ call void %f3() ;; Inst in block.
+ %XX = load int* %AP
+ store int %XX, int* %BP
+ br bool %C, label %B, label %A
+A:
+ call void %f1()
+ br bool %D, label %T, label %F
+B:
+ call void %f2()
+ ret int 345
+F:
+ call void %f3()
+ ret int 123
+}
From lattner at cs.uiuc.edu Mon Sep 19 20:48:51 2005
From: lattner at cs.uiuc.edu (Chris Lattner)
Date: Mon, 19 Sep 2005 20:48:51 -0500
Subject: [llvm-commits] CVS: llvm/lib/Transforms/Utils/SimplifyCFG.cpp
Message-ID: <200509200148.UAA02081@zion.cs.uiuc.edu>
Changes in directory llvm/lib/Transforms/Utils:
SimplifyCFG.cpp updated: 1.86 -> 1.87
---
Log message:
Start threading across blocks with code in them, so long as the code does
not define a value that is used outside of it's block. This catches many
more simplifications, e.g. 854 in 176.gcc, 137 in vpr, etc.
This implements branch-phi-thread.ll:test3.ll
---
Diffs of the changes: (+64 -15)
SimplifyCFG.cpp | 79 +++++++++++++++++++++++++++++++++++++++++++++-----------
1 files changed, 64 insertions(+), 15 deletions(-)
Index: llvm/lib/Transforms/Utils/SimplifyCFG.cpp
diff -u llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.86 llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.87
--- llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.86 Mon Sep 19 19:43:16 2005
+++ llvm/lib/Transforms/Utils/SimplifyCFG.cpp Mon Sep 19 20:48:40 2005
@@ -896,17 +896,24 @@
BranchInst *BI = cast(BB->getTerminator());
Value *Cond = BI->getCondition();
+ unsigned Size = 0;
+
// If this basic block contains anything other than a PHI (which controls the
// branch) and branch itself, bail out. FIXME: improve this in the future.
- for (BasicBlock::iterator BBI = BB->begin(); &*BBI != BI; ++BBI) {
- if (!isa(BBI)) return false;
+ for (BasicBlock::iterator BBI = BB->begin(); &*BBI != BI; ++BBI, ++Size) {
+ if (Size > 10) return false; // Don't clone large BB's.
- if (&*BBI != Cond || !Cond->hasOneUse())
- return false;
+ // We can only support instructions that are do not define values that are
+ // live outside of the current basic block.
+ for (Value::use_iterator UI = BBI->use_begin(), E = BBI->use_end();
+ UI != E; ++UI) {
+ Instruction *U = cast(*UI);
+ if (U->getParent() != BB || isa(U)) return false;
+ }
// Looks ok, continue checking.
}
-
+
return true;
}
@@ -944,22 +951,64 @@
BasicBlock *PredBB = PN->getIncomingBlock(i);
BasicBlock *RealDest = BI->getSuccessor(!CB->getValue());
- // If there are PHI nodes in the destination block, we have to add an
- // entry for PredBB. Instead of being smart about this, just split the
- // critical edge, which will eliminate the PHI-ness.
- if (isa(RealDest->begin())) {
- SplitCriticalEdge(BI, !CB->getValue());
- RealDest = BI->getSuccessor(!CB->getValue());
- }
- assert(!isa(RealDest->begin()) && "Crit edge split failure!");
+ if (RealDest == BB) continue; // Skip self loops.
+ // The dest block might have PHI nodes, other predecessors and other
+ // difficult cases. Instead of being smart about this, just insert a new
+ // block that jumps to the destination block, effectively splitting
+ // the edge we are about to create.
+ BasicBlock *EdgeBB = new BasicBlock(RealDest->getName()+".critedge",
+ RealDest->getParent(), RealDest);
+ new BranchInst(RealDest, EdgeBB);
+ PHINode *PN;
+ for (BasicBlock::iterator BBI = RealDest->begin();
+ (PN = dyn_cast(BBI)); ++BBI) {
+ Value *V = PN->getIncomingValueForBlock(BB);
+ PN->addIncoming(V, EdgeBB);
+ }
+
+ // BB may have instructions that are being threaded over. Clone these
+ // instructions into EdgeBB. We know that there will be no uses of the
+ // cloned instructions outside of EdgeBB.
+ BasicBlock::iterator InsertPt = EdgeBB->begin();
+ std::map TranslateMap; // Track translated values.
+ for (BasicBlock::iterator BBI = BB->begin(); &*BBI != BI; ++BBI) {
+ if (PHINode *PN = dyn_cast(BBI)) {
+ TranslateMap[PN] = PN->getIncomingValueForBlock(PredBB);
+ } else {
+ // Clone the instruction.
+ Instruction *N = BBI->clone();
+ if (BBI->hasName()) N->setName(BBI->getName()+".c");
+
+ // Update operands due to translation.
+ for (unsigned i = 0, e = N->getNumOperands(); i != e; ++i) {
+ std::map::iterator PI =
+ TranslateMap.find(N->getOperand(i));
+ if (PI != TranslateMap.end())
+ N->setOperand(i, PI->second);
+ }
+
+ // Check for trivial simplification.
+ if (Constant *C = ConstantFoldInstruction(N)) {
+ std::cerr << "FOLDED: " << *N;
+ TranslateMap[BBI] = C;
+ delete N; // Constant folded away, don't need actual inst
+ } else {
+ // Insert the new instruction into its new home.
+ EdgeBB->getInstList().insert(InsertPt, N);
+ if (!BBI->use_empty())
+ TranslateMap[BBI] = N;
+ }
+ }
+ }
+
// Loop over all of the edges from PredBB to BB, changing them to branch
- // to RealDest instead.
+ // to EdgeBB instead.
TerminatorInst *PredBBTI = PredBB->getTerminator();
for (unsigned i = 0, e = PredBBTI->getNumSuccessors(); i != e; ++i)
if (PredBBTI->getSuccessor(i) == BB) {
BB->removePredecessor(PredBB);
- PredBBTI->setSuccessor(i, RealDest);
+ PredBBTI->setSuccessor(i, EdgeBB);
}
// Recurse, simplifying any other constants.
From lattner at cs.uiuc.edu Tue Sep 20 22:56:38 2005
From: lattner at cs.uiuc.edu (Chris Lattner)
Date: Tue, 20 Sep 2005 22:56:38 -0500
Subject: [llvm-commits] CVS: llvm/docs/CFEBuildInstrs.html
Message-ID: <200509210356.WAA26115@zion.cs.uiuc.edu>
Changes in directory llvm/docs:
CFEBuildInstrs.html updated: 1.52 -> 1.53
---
Log message:
Recommend what I actually test
---
Diffs of the changes: (+3 -2)
CFEBuildInstrs.html | 5 +++--
1 files changed, 3 insertions(+), 2 deletions(-)
Index: llvm/docs/CFEBuildInstrs.html
diff -u llvm/docs/CFEBuildInstrs.html:1.52 llvm/docs/CFEBuildInstrs.html:1.53
--- llvm/docs/CFEBuildInstrs.html:1.52 Tue Jun 14 02:29:50 2005
+++ llvm/docs/CFEBuildInstrs.html Tue Sep 20 22:56:26 2005
@@ -103,7 +103,8 @@
Configure and build the LLVM libraries and tools. There are two ways to
do this: either with objdir == srcdir or
objdir != srcdir. It is recommended
-that srcdir not be the same as objdir:
+that srcdir be the same as objdir for your LLVM tree (but note
+that you should always use srcdir != objdir for llvm-gcc):