Enable more fold (sext (load x)) -> (sext (truncate (sextload x)))
transformation. Previously, it's restricted by ensuring the number of load uses is one. Now the restriction is loosened up by allowing setcc uses to be "extended" (e.g. setcc x, c, eq -> setcc sext(x), sext(c), eq). llvm-svn: 43465
This commit is contained in:
parent
1961c28d46
commit
e106e2f142
|
@ -1001,6 +1001,10 @@ public:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual bool isTruncateFree(MVT::ValueType VT1, MVT::ValueType VT2) const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
//===--------------------------------------------------------------------===//
|
//===--------------------------------------------------------------------===//
|
||||||
// Div utility functions
|
// Div utility functions
|
||||||
//
|
//
|
||||||
|
|
|
@ -2497,6 +2497,74 @@ SDOperand DAGCombiner::visitSETCC(SDNode *N) {
|
||||||
cast<CondCodeSDNode>(N->getOperand(2))->get());
|
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 DAGCombiner::visitSIGN_EXTEND(SDNode *N) {
|
||||||
SDOperand N0 = N->getOperand(0);
|
SDOperand N0 = N->getOperand(0);
|
||||||
MVT::ValueType VT = N->getValueType(0);
|
MVT::ValueType VT = N->getValueType(0);
|
||||||
|
@ -2560,8 +2628,13 @@ SDOperand DAGCombiner::visitSIGN_EXTEND(SDNode *N) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// fold (sext (load x)) -> (sext (truncate (sextload x)))
|
// 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()))){
|
(!AfterLegalize||TLI.isLoadXLegal(ISD::SEXTLOAD, N0.getValueType()))){
|
||||||
|
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);
|
LoadSDNode *LN0 = cast<LoadSDNode>(N0);
|
||||||
SDOperand ExtLoad = DAG.getExtLoad(ISD::SEXTLOAD, VT, LN0->getChain(),
|
SDOperand ExtLoad = DAG.getExtLoad(ISD::SEXTLOAD, VT, LN0->getChain(),
|
||||||
LN0->getBasePtr(), LN0->getSrcValue(),
|
LN0->getBasePtr(), LN0->getSrcValue(),
|
||||||
|
@ -2570,10 +2643,26 @@ SDOperand DAGCombiner::visitSIGN_EXTEND(SDNode *N) {
|
||||||
LN0->isVolatile(),
|
LN0->isVolatile(),
|
||||||
LN0->getAlignment());
|
LN0->getAlignment());
|
||||||
CombineTo(N, ExtLoad);
|
CombineTo(N, ExtLoad);
|
||||||
CombineTo(N0.Val, DAG.getNode(ISD::TRUNCATE, N0.getValueType(), ExtLoad),
|
SDOperand Trunc = DAG.getNode(ISD::TRUNCATE, N0.getValueType(), ExtLoad);
|
||||||
ExtLoad.getValue(1));
|
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!
|
return SDOperand(N, 0); // Return N so it doesn't get rechecked!
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// fold (sext (sextload x)) -> (sext (truncate (sextload x)))
|
// fold (sext (sextload x)) -> (sext (truncate (sextload x)))
|
||||||
// fold (sext ( extload x)) -> (sext (truncate (sextload x)))
|
// fold (sext ( extload x)) -> (sext (truncate (sextload x)))
|
||||||
|
@ -2656,8 +2745,13 @@ SDOperand DAGCombiner::visitZERO_EXTEND(SDNode *N) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// fold (zext (load x)) -> (zext (truncate (zextload x)))
|
// 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()))) {
|
(!AfterLegalize||TLI.isLoadXLegal(ISD::ZEXTLOAD, N0.getValueType()))) {
|
||||||
|
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);
|
LoadSDNode *LN0 = cast<LoadSDNode>(N0);
|
||||||
SDOperand ExtLoad = DAG.getExtLoad(ISD::ZEXTLOAD, VT, LN0->getChain(),
|
SDOperand ExtLoad = DAG.getExtLoad(ISD::ZEXTLOAD, VT, LN0->getChain(),
|
||||||
LN0->getBasePtr(), LN0->getSrcValue(),
|
LN0->getBasePtr(), LN0->getSrcValue(),
|
||||||
|
@ -2666,10 +2760,26 @@ SDOperand DAGCombiner::visitZERO_EXTEND(SDNode *N) {
|
||||||
LN0->isVolatile(),
|
LN0->isVolatile(),
|
||||||
LN0->getAlignment());
|
LN0->getAlignment());
|
||||||
CombineTo(N, ExtLoad);
|
CombineTo(N, ExtLoad);
|
||||||
CombineTo(N0.Val, DAG.getNode(ISD::TRUNCATE, N0.getValueType(), ExtLoad),
|
SDOperand Trunc = DAG.getNode(ISD::TRUNCATE, N0.getValueType(), ExtLoad);
|
||||||
ExtLoad.getValue(1));
|
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!
|
return SDOperand(N, 0); // Return N so it doesn't get rechecked!
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// fold (zext (zextload x)) -> (zext (truncate (zextload x)))
|
// fold (zext (zextload x)) -> (zext (truncate (zextload x)))
|
||||||
// fold (zext ( extload x)) -> (zext (truncate (zextload x)))
|
// fold (zext ( extload x)) -> (zext (truncate (zextload x)))
|
||||||
|
|
|
@ -5132,6 +5132,16 @@ bool X86TargetLowering::isTruncateFree(const Type *Ty1, const Type *Ty2) const {
|
||||||
return Subtarget->is64Bit() || NumBits1 < 64;
|
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
|
/// isShuffleMaskLegal - Targets can use this to indicate that they only
|
||||||
/// support *some* VECTOR_SHUFFLE operations, those with specific masks.
|
/// support *some* VECTOR_SHUFFLE operations, those with specific masks.
|
||||||
|
|
|
@ -363,6 +363,7 @@ namespace llvm {
|
||||||
/// type Ty1 to type Ty2. e.g. On x86 it's free to truncate a i32 value in
|
/// 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.
|
/// register EAX to i16 by referencing its sub-register AX.
|
||||||
virtual bool isTruncateFree(const Type *Ty1, const Type *Ty2) const;
|
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
|
/// isShuffleMaskLegal - Targets can use this to indicate that they only
|
||||||
/// support *some* VECTOR_SHUFFLE operations, those with specific masks.
|
/// support *some* VECTOR_SHUFFLE operations, those with specific masks.
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
Loading…
Reference in New Issue