aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/llvm/Target/TargetLowering.h4
-rw-r--r--lib/CodeGen/SelectionDAG/DAGCombiner.cpp158
-rw-r--r--lib/Target/X86/X86ISelLowering.cpp10
-rw-r--r--lib/Target/X86/X86ISelLowering.h1
-rw-r--r--test/CodeGen/X86/2007-10-29-ExtendSetCC.ll17
5 files changed, 166 insertions, 24 deletions
diff --git a/include/llvm/Target/TargetLowering.h b/include/llvm/Target/TargetLowering.h
index e092145..9d7a1ec 100644
--- a/include/llvm/Target/TargetLowering.h
+++ b/include/llvm/Target/TargetLowering.h
@@ -1000,6 +1000,10 @@ public:
virtual bool isTruncateFree(const Type *Ty1, const Type *Ty2) const {
return false;
}
+
+ virtual bool isTruncateFree(MVT::ValueType VT1, MVT::ValueType VT2) const {
+ return false;
+ }
//===--------------------------------------------------------------------===//
// Div utility functions
diff --git a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index d3b8b00..b4299f4 100644
--- a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -2497,6 +2497,74 @@ SDOperand DAGCombiner::visitSETCC(SDNode *N) {
cast<CondCodeSDNode>(N->getOperand(2))->get());
}
+// ExtendUsesToFormExtLoad - Trying to extend uses of a load to enable this:
+// "fold ({s|z}ext (load x)) -> ({s|z}ext (truncate ({s|z}extload x)))"
+// transformation. Returns true if extension are possible and the above
+// mentioned transformation is profitable.
+static bool ExtendUsesToFormExtLoad(SDNode *N, SDOperand N0,
+ unsigned ExtOpc,
+ SmallVector<SDNode*, 4> &ExtendNodes,
+ TargetLowering &TLI) {
+ bool HasCopyToRegUses = false;
+ bool isTruncFree = TLI.isTruncateFree(N->getValueType(0), N0.getValueType());
+ for (SDNode::use_iterator UI = N0.Val->use_begin(), UE = N0.Val->use_end();
+ UI != UE; ++UI) {
+ SDNode *User = *UI;
+ if (User == N)
+ continue;
+ // FIXME: Only extend SETCC N, N and SETCC N, c for now.
+ if (User->getOpcode() == ISD::SETCC) {
+ ISD::CondCode CC = cast<CondCodeSDNode>(User->getOperand(2))->get();
+ if (ExtOpc == ISD::ZERO_EXTEND && ISD::isSignedIntSetCC(CC))
+ // Sign bits will be lost after a zext.
+ return false;
+ bool Add = false;
+ for (unsigned i = 0; i != 2; ++i) {
+ SDOperand UseOp = User->getOperand(i);
+ if (UseOp == N0)
+ continue;
+ if (!isa<ConstantSDNode>(UseOp))
+ return false;
+ Add = true;
+ }
+ if (Add)
+ ExtendNodes.push_back(User);
+ } else {
+ for (unsigned i = 0, e = User->getNumOperands(); i != e; ++i) {
+ SDOperand UseOp = User->getOperand(i);
+ if (UseOp == N0) {
+ // If truncate from extended type to original load type is free
+ // on this target, then it's ok to extend a CopyToReg.
+ if (isTruncFree && User->getOpcode() == ISD::CopyToReg)
+ HasCopyToRegUses = true;
+ else
+ return false;
+ }
+ }
+ }
+ }
+
+ if (HasCopyToRegUses) {
+ bool BothLiveOut = false;
+ for (SDNode::use_iterator UI = N->use_begin(), UE = N->use_end();
+ UI != UE; ++UI) {
+ SDNode *User = *UI;
+ for (unsigned i = 0, e = User->getNumOperands(); i != e; ++i) {
+ SDOperand UseOp = User->getOperand(i);
+ if (UseOp.Val == N && UseOp.ResNo == 0) {
+ BothLiveOut = true;
+ break;
+ }
+ }
+ }
+ if (BothLiveOut)
+ // Both unextended and extended values are live out. There had better be
+ // good a reason for the transformation.
+ return ExtendNodes.size();
+ }
+ return true;
+}
+
SDOperand DAGCombiner::visitSIGN_EXTEND(SDNode *N) {
SDOperand N0 = N->getOperand(0);
MVT::ValueType VT = N->getValueType(0);
@@ -2560,19 +2628,40 @@ SDOperand DAGCombiner::visitSIGN_EXTEND(SDNode *N) {
}
// fold (sext (load x)) -> (sext (truncate (sextload x)))
- if (ISD::isNON_EXTLoad(N0.Val) && N0.hasOneUse() &&
+ if (ISD::isNON_EXTLoad(N0.Val) &&
(!AfterLegalize||TLI.isLoadXLegal(ISD::SEXTLOAD, N0.getValueType()))){
- LoadSDNode *LN0 = cast<LoadSDNode>(N0);
- SDOperand ExtLoad = DAG.getExtLoad(ISD::SEXTLOAD, VT, LN0->getChain(),
- LN0->getBasePtr(), LN0->getSrcValue(),
- LN0->getSrcValueOffset(),
- N0.getValueType(),
- LN0->isVolatile(),
- LN0->getAlignment());
- CombineTo(N, ExtLoad);
- CombineTo(N0.Val, DAG.getNode(ISD::TRUNCATE, N0.getValueType(), ExtLoad),
- ExtLoad.getValue(1));
- return SDOperand(N, 0); // Return N so it doesn't get rechecked!
+ bool DoXform = true;
+ SmallVector<SDNode*, 4> SetCCs;
+ if (!N0.hasOneUse())
+ DoXform = ExtendUsesToFormExtLoad(N, N0, ISD::SIGN_EXTEND, SetCCs, TLI);
+ if (DoXform) {
+ LoadSDNode *LN0 = cast<LoadSDNode>(N0);
+ SDOperand ExtLoad = DAG.getExtLoad(ISD::SEXTLOAD, VT, LN0->getChain(),
+ LN0->getBasePtr(), LN0->getSrcValue(),
+ LN0->getSrcValueOffset(),
+ N0.getValueType(),
+ LN0->isVolatile(),
+ LN0->getAlignment());
+ CombineTo(N, ExtLoad);
+ SDOperand Trunc = DAG.getNode(ISD::TRUNCATE, N0.getValueType(), ExtLoad);
+ CombineTo(N0.Val, Trunc, ExtLoad.getValue(1));
+ // Extend SetCC uses if necessary.
+ for (unsigned i = 0, e = SetCCs.size(); i != e; ++i) {
+ SDNode *SetCC = SetCCs[i];
+ SmallVector<SDOperand, 4> Ops;
+ for (unsigned j = 0; j != 2; ++j) {
+ SDOperand SOp = SetCC->getOperand(j);
+ if (SOp == Trunc)
+ Ops.push_back(ExtLoad);
+ else
+ Ops.push_back(DAG.getNode(ISD::SIGN_EXTEND, VT, SOp));
+ }
+ Ops.push_back(SetCC->getOperand(2));
+ CombineTo(SetCC, DAG.getNode(ISD::SETCC, SetCC->getValueType(0),
+ &Ops[0], Ops.size()));
+ }
+ return SDOperand(N, 0); // Return N so it doesn't get rechecked!
+ }
}
// fold (sext (sextload x)) -> (sext (truncate (sextload x)))
@@ -2656,19 +2745,40 @@ SDOperand DAGCombiner::visitZERO_EXTEND(SDNode *N) {
}
// fold (zext (load x)) -> (zext (truncate (zextload x)))
- if (ISD::isNON_EXTLoad(N0.Val) && N0.hasOneUse() &&
+ if (ISD::isNON_EXTLoad(N0.Val) &&
(!AfterLegalize||TLI.isLoadXLegal(ISD::ZEXTLOAD, N0.getValueType()))) {
- LoadSDNode *LN0 = cast<LoadSDNode>(N0);
- SDOperand ExtLoad = DAG.getExtLoad(ISD::ZEXTLOAD, VT, LN0->getChain(),
- LN0->getBasePtr(), LN0->getSrcValue(),
- LN0->getSrcValueOffset(),
- N0.getValueType(),
- LN0->isVolatile(),
- LN0->getAlignment());
- CombineTo(N, ExtLoad);
- CombineTo(N0.Val, DAG.getNode(ISD::TRUNCATE, N0.getValueType(), ExtLoad),
- ExtLoad.getValue(1));
- return SDOperand(N, 0); // Return N so it doesn't get rechecked!
+ bool DoXform = true;
+ SmallVector<SDNode*, 4> SetCCs;
+ if (!N0.hasOneUse())
+ DoXform = ExtendUsesToFormExtLoad(N, N0, ISD::ZERO_EXTEND, SetCCs, TLI);
+ if (DoXform) {
+ LoadSDNode *LN0 = cast<LoadSDNode>(N0);
+ SDOperand ExtLoad = DAG.getExtLoad(ISD::ZEXTLOAD, VT, LN0->getChain(),
+ LN0->getBasePtr(), LN0->getSrcValue(),
+ LN0->getSrcValueOffset(),
+ N0.getValueType(),
+ LN0->isVolatile(),
+ LN0->getAlignment());
+ CombineTo(N, ExtLoad);
+ SDOperand Trunc = DAG.getNode(ISD::TRUNCATE, N0.getValueType(), ExtLoad);
+ CombineTo(N0.Val, Trunc, ExtLoad.getValue(1));
+ // Extend SetCC uses if necessary.
+ for (unsigned i = 0, e = SetCCs.size(); i != e; ++i) {
+ SDNode *SetCC = SetCCs[i];
+ SmallVector<SDOperand, 4> Ops;
+ for (unsigned j = 0; j != 2; ++j) {
+ SDOperand SOp = SetCC->getOperand(j);
+ if (SOp == Trunc)
+ Ops.push_back(ExtLoad);
+ else
+ Ops.push_back(DAG.getNode(ISD::SIGN_EXTEND, VT, SOp));
+ }
+ Ops.push_back(SetCC->getOperand(2));
+ CombineTo(SetCC, DAG.getNode(ISD::SETCC, SetCC->getValueType(0),
+ &Ops[0], Ops.size()));
+ }
+ return SDOperand(N, 0); // Return N so it doesn't get rechecked!
+ }
}
// fold (zext (zextload x)) -> (zext (truncate (zextload x)))
diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp
index 5decef2..27685a8 100644
--- a/lib/Target/X86/X86ISelLowering.cpp
+++ b/lib/Target/X86/X86ISelLowering.cpp
@@ -5132,6 +5132,16 @@ bool X86TargetLowering::isTruncateFree(const Type *Ty1, const Type *Ty2) const {
return Subtarget->is64Bit() || NumBits1 < 64;
}
+bool X86TargetLowering::isTruncateFree(MVT::ValueType VT1,
+ MVT::ValueType VT2) const {
+ if (!MVT::isInteger(VT1) || !MVT::isInteger(VT2))
+ return false;
+ unsigned NumBits1 = MVT::getSizeInBits(VT1);
+ unsigned NumBits2 = MVT::getSizeInBits(VT2);
+ if (NumBits1 <= NumBits2)
+ return false;
+ return Subtarget->is64Bit() || NumBits1 < 64;
+}
/// isShuffleMaskLegal - Targets can use this to indicate that they only
/// support *some* VECTOR_SHUFFLE operations, those with specific masks.
diff --git a/lib/Target/X86/X86ISelLowering.h b/lib/Target/X86/X86ISelLowering.h
index b68de5a..2330f98 100644
--- a/lib/Target/X86/X86ISelLowering.h
+++ b/lib/Target/X86/X86ISelLowering.h
@@ -363,6 +363,7 @@ namespace llvm {
/// type Ty1 to type Ty2. e.g. On x86 it's free to truncate a i32 value in
/// register EAX to i16 by referencing its sub-register AX.
virtual bool isTruncateFree(const Type *Ty1, const Type *Ty2) const;
+ virtual bool isTruncateFree(MVT::ValueType VT1, MVT::ValueType VT2) const;
/// isShuffleMaskLegal - Targets can use this to indicate that they only
/// support *some* VECTOR_SHUFFLE operations, those with specific masks.
diff --git a/test/CodeGen/X86/2007-10-29-ExtendSetCC.ll b/test/CodeGen/X86/2007-10-29-ExtendSetCC.ll
new file mode 100644
index 0000000..9013e90
--- /dev/null
+++ b/test/CodeGen/X86/2007-10-29-ExtendSetCC.ll
@@ -0,0 +1,17 @@
+; RUN: llvm-as < %s | llc -march=x86 | grep mov | count 1
+
+define i16 @t() signext {
+entry:
+ %tmp180 = load i16* null, align 2 ; <i16> [#uses=3]
+ %tmp180181 = sext i16 %tmp180 to i32 ; <i32> [#uses=1]
+ %tmp185 = icmp slt i16 %tmp180, 0 ; <i1> [#uses=1]
+ br i1 %tmp185, label %cond_true188, label %cond_next245
+
+cond_true188: ; preds = %entry
+ %tmp195196 = trunc i16 %tmp180 to i8 ; <i8> [#uses=0]
+ ret i16 0
+
+cond_next245: ; preds = %entry
+ %tmp256 = and i32 %tmp180181, 15 ; <i32> [#uses=0]
+ ret i16 0
+}