[llvm-commits] CVS: llvm/lib/Target/X86/X86ISelPattern.cpp
Chris Lattner
lattner at cs.uiuc.edu
Sun Jan 16 22:27:11 PST 2005
Changes in directory llvm/lib/Target/X86:
X86ISelPattern.cpp updated: 1.60 -> 1.61
---
Log message:
Fix test/Regression/CodeGen/X86/2005-01-17-CycleInDAG.ll and 132.ijpeg.
Do not fold a load into an operation if it will induce a cycle in the DAG.
Repeat after me: dAg.
---
Diffs of the changes: (+62 -17)
Index: llvm/lib/Target/X86/X86ISelPattern.cpp
diff -u llvm/lib/Target/X86/X86ISelPattern.cpp:1.60 llvm/lib/Target/X86/X86ISelPattern.cpp:1.61
--- llvm/lib/Target/X86/X86ISelPattern.cpp:1.60 Sun Jan 16 19:34:14 2005
+++ llvm/lib/Target/X86/X86ISelPattern.cpp Mon Jan 17 00:26:58 2005
@@ -343,7 +343,7 @@
/// SelectionDAGISel when it has created a SelectionDAG for us to codegen.
virtual void InstructionSelectBasicBlock(SelectionDAG &DAG);
- bool isFoldableLoad(SDOperand Op);
+ bool isFoldableLoad(SDOperand Op, SDOperand OtherOp);
void EmitFoldedLoad(SDOperand Op, X86AddressMode &AM);
@@ -920,7 +920,7 @@
unsigned Opc;
if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(RHS)) {
Opc = 0;
- if (HasOneUse && isFoldableLoad(LHS)) {
+ if (HasOneUse && isFoldableLoad(LHS, RHS)) {
switch (RHS.getValueType()) {
default: break;
case MVT::i1:
@@ -959,7 +959,7 @@
}
Opc = 0;
- if (HasOneUse && isFoldableLoad(LHS)) {
+ if (HasOneUse && isFoldableLoad(LHS, RHS)) {
switch (RHS.getValueType()) {
default: break;
case MVT::i1:
@@ -996,9 +996,30 @@
BuildMI(BB, Opc, 2).addReg(Tmp1).addReg(Tmp2);
}
+/// NodeTransitivelyUsesValue - Return true if N or any of its uses uses Op.
+/// The DAG cannot have cycles in it, by definition, so the visited set is not
+/// needed to prevent infinite loops. The DAG CAN, however, have unbounded
+/// reuse, so it prevents exponential cases.
+///
+static bool NodeTransitivelyUsesValue(SDOperand N, SDOperand Op,
+ std::set<SDNode*> &Visited) {
+ if (N == Op) return true; // Found it.
+ SDNode *Node = N.Val;
+ if (Node->getNumOperands() == 0) return false; // Leaf?
+ if (!Visited.insert(Node).second) return false; // Already visited?
+
+ // Recurse for the first N-1 operands.
+ for (unsigned i = 1, e = Node->getNumOperands(); i != e; ++i)
+ if (NodeTransitivelyUsesValue(Node->getOperand(i), Op, Visited))
+ return true;
+
+ // Tail recurse for the last operand.
+ return NodeTransitivelyUsesValue(Node->getOperand(0), Op, Visited);
+}
+
/// isFoldableLoad - Return true if this is a load instruction that can safely
/// be folded into an operation that uses it.
-bool ISel::isFoldableLoad(SDOperand Op) {
+bool ISel::isFoldableLoad(SDOperand Op, SDOperand OtherOp) {
if (Op.getOpcode() != ISD::LOAD ||
// FIXME: currently can't fold constant pool indexes.
isa<ConstantPoolSDNode>(Op.getOperand(1)))
@@ -1011,10 +1032,22 @@
assert(!LoweredTokens.count(Op.getValue(1)) &&
"Token lowered but value not in map?");
- // Finally, there can only be one use of its value.
- return Op.Val->hasNUsesOfValue(1, 0);
+ // If there is not just one use of its value, we cannot fold.
+ if (!Op.Val->hasNUsesOfValue(1, 0)) return false;
+
+ // Finally, we cannot fold the load into the operation if this would induce a
+ // cycle into the resultant dag. To check for this, see if OtherOp (the other
+ // operand of the operation we are folding the load into) can possible use the
+ // chain node defined by the load.
+ if (OtherOp.Val && !Op.Val->hasNUsesOfValue(0, 1)) { // Has uses of chain?
+ std::set<SDNode*> Visited;
+ if (NodeTransitivelyUsesValue(OtherOp, Op.getValue(1), Visited))
+ return false;
+ }
+ return true;
}
+
/// EmitFoldedLoad - Ensure that the arguments of the load are code generated,
/// and compute the address being loaded into AM.
void ISel::EmitFoldedLoad(SDOperand Op, X86AddressMode &AM) {
@@ -1136,7 +1169,7 @@
return Result;
}
- if (isFoldableLoad(N.getOperand(0))) {
+ if (isFoldableLoad(N.getOperand(0), SDOperand())) {
static const unsigned Opc[3] = {
X86::MOVZX32rm8, X86::MOVZX32rm16, X86::MOVZX16rm8
};
@@ -1163,7 +1196,7 @@
assert(N.getOperand(0).getValueType() != MVT::i1 &&
"Sign extend from bool not implemented!");
- if (isFoldableLoad(N.getOperand(0))) {
+ if (isFoldableLoad(N.getOperand(0), SDOperand())) {
static const unsigned Opc[3] = {
X86::MOVSX32rm8, X86::MOVSX32rm16, X86::MOVSX16rm8
};
@@ -1183,7 +1216,7 @@
}
case ISD::TRUNCATE:
// Fold TRUNCATE (LOAD P) into a smaller load from P.
- if (isFoldableLoad(N.getOperand(0))) {
+ if (isFoldableLoad(N.getOperand(0), SDOperand())) {
switch (N.getValueType()) {
default: assert(0 && "Unknown truncate!");
case MVT::i1:
@@ -1442,10 +1475,13 @@
Op0 = N.getOperand(0);
Op1 = N.getOperand(1);
- if (isFoldableLoad(Op0))
+ if (isFoldableLoad(Op0, Op1)) {
std::swap(Op0, Op1);
+ goto FoldAdd;
+ }
- if (isFoldableLoad(Op1)) {
+ if (isFoldableLoad(Op1, Op0)) {
+ FoldAdd:
switch (N.getValueType()) {
default: assert(0 && "Cannot add this type!");
case MVT::i1:
@@ -1622,9 +1658,10 @@
}
}
- if (isFoldableLoad(Op0))
+ if (isFoldableLoad(Op0, Op1))
if (Node->getOpcode() != ISD::SUB) {
std::swap(Op0, Op1);
+ goto FoldOps;
} else {
// Emit 'reverse' subract, with a memory operand.
switch (N.getValueType()) {
@@ -1641,7 +1678,8 @@
}
}
- if (isFoldableLoad(Op1)) {
+ if (isFoldableLoad(Op1, Op0)) {
+ FoldOps:
switch (N.getValueType()) {
default: assert(0 && "Cannot operate on this type!");
case MVT::i1:
@@ -2433,16 +2471,17 @@
// Check to see if this is a load/op/store combination.
if (N.getOperand(1).Val->hasOneUse() &&
- isFoldableLoad(N.getOperand(0).getValue(0)) &&
- !MVT::isFloatingPoint(N.getOperand(0).getValue(0).getValueType())) {
+ N.getOperand(1).Val->getNumOperands() == 2 &&
+ !MVT::isFloatingPoint(N.getOperand(0).getValue(0).getValueType()) &&
+ isFoldableLoad(N.getOperand(0).getValue(0),
+ N.getOperand(0).getValue(1))) {
SDOperand TheLoad = N.getOperand(0).getValue(0);
// Check to see if we are loading the same pointer that we're storing to.
if (TheLoad.getOperand(1) == N.getOperand(2)) {
// See if the stored value is a simple binary operator that uses the
// load as one of its operands.
SDOperand Op = N.getOperand(1);
- if (Op.Val->getNumOperands() == 2 &&
- (Op.getOperand(0) == TheLoad || Op.getOperand(1) == TheLoad)) {
+ if ((Op.getOperand(0) == TheLoad || Op.getOperand(1) == TheLoad)) {
// Finally, check to see if this is one of the ops we can handle!
static const unsigned ADDTAB[] = {
X86::ADD8mi, X86::ADD16mi, X86::ADD32mi,
@@ -2480,6 +2519,12 @@
const unsigned *TabPtr = 0;
switch (Op.getOpcode()) {
default: std::cerr << "CANNOT [mem] op= val: "; Op.Val->dump(); std::cerr << "\n"; break;
+ case ISD::MUL:
+ case ISD::SDIV:
+ case ISD::UDIV:
+ case ISD::SREM:
+ case ISD::UREM: break;
+
case ISD::ADD: TabPtr = ADDTAB; break;
case ISD::SUB: TabPtr = SUBTAB; break;
case ISD::AND: TabPtr = ANDTAB; break;
More information about the llvm-commits
mailing list