mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-08-08 19:25:47 +00:00
Add a DAGCombine for (ext (binop (load x), cst)).
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@133124 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -138,6 +138,10 @@ namespace {
|
|||||||
SDValue PromoteExtend(SDValue Op);
|
SDValue PromoteExtend(SDValue Op);
|
||||||
bool PromoteLoad(SDValue Op);
|
bool PromoteLoad(SDValue Op);
|
||||||
|
|
||||||
|
void ExtendSetCCUses(SmallVector<SDNode*, 4> SetCCs,
|
||||||
|
SDValue Trunc, SDValue ExtLoad, DebugLoc DL,
|
||||||
|
ISD::NodeType ExtType);
|
||||||
|
|
||||||
/// combine - call the node-specific routine that knows how to fold each
|
/// combine - call the node-specific routine that knows how to fold each
|
||||||
/// particular type of node. If that doesn't do anything, try the
|
/// particular type of node. If that doesn't do anything, try the
|
||||||
/// target-specific DAG combines.
|
/// target-specific DAG combines.
|
||||||
@@ -3699,6 +3703,28 @@ static bool ExtendUsesToFormExtLoad(SDNode *N, SDValue N0,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DAGCombiner::ExtendSetCCUses(SmallVector<SDNode*, 4> SetCCs,
|
||||||
|
SDValue Trunc, SDValue ExtLoad, DebugLoc DL,
|
||||||
|
ISD::NodeType ExtType) {
|
||||||
|
// Extend SetCC uses if necessary.
|
||||||
|
for (unsigned i = 0, e = SetCCs.size(); i != e; ++i) {
|
||||||
|
SDNode *SetCC = SetCCs[i];
|
||||||
|
SmallVector<SDValue, 4> Ops;
|
||||||
|
|
||||||
|
for (unsigned j = 0; j != 2; ++j) {
|
||||||
|
SDValue SOp = SetCC->getOperand(j);
|
||||||
|
if (SOp == Trunc)
|
||||||
|
Ops.push_back(ExtLoad);
|
||||||
|
else
|
||||||
|
Ops.push_back(DAG.getNode(ExtType, DL, ExtLoad->getValueType(0), SOp));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ops.push_back(SetCC->getOperand(2));
|
||||||
|
CombineTo(SetCC, DAG.getNode(ISD::SETCC, DL, SetCC->getValueType(0),
|
||||||
|
&Ops[0], Ops.size()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SDValue DAGCombiner::visitSIGN_EXTEND(SDNode *N) {
|
SDValue DAGCombiner::visitSIGN_EXTEND(SDNode *N) {
|
||||||
SDValue N0 = N->getOperand(0);
|
SDValue N0 = N->getOperand(0);
|
||||||
EVT VT = N->getValueType(0);
|
EVT VT = N->getValueType(0);
|
||||||
@@ -3787,27 +3813,8 @@ SDValue DAGCombiner::visitSIGN_EXTEND(SDNode *N) {
|
|||||||
SDValue Trunc = DAG.getNode(ISD::TRUNCATE, N0.getDebugLoc(),
|
SDValue Trunc = DAG.getNode(ISD::TRUNCATE, N0.getDebugLoc(),
|
||||||
N0.getValueType(), ExtLoad);
|
N0.getValueType(), ExtLoad);
|
||||||
CombineTo(N0.getNode(), Trunc, ExtLoad.getValue(1));
|
CombineTo(N0.getNode(), Trunc, ExtLoad.getValue(1));
|
||||||
|
ExtendSetCCUses(SetCCs, Trunc, ExtLoad, N->getDebugLoc(),
|
||||||
// Extend SetCC uses if necessary.
|
ISD::SIGN_EXTEND);
|
||||||
for (unsigned i = 0, e = SetCCs.size(); i != e; ++i) {
|
|
||||||
SDNode *SetCC = SetCCs[i];
|
|
||||||
SmallVector<SDValue, 4> Ops;
|
|
||||||
|
|
||||||
for (unsigned j = 0; j != 2; ++j) {
|
|
||||||
SDValue SOp = SetCC->getOperand(j);
|
|
||||||
if (SOp == Trunc)
|
|
||||||
Ops.push_back(ExtLoad);
|
|
||||||
else
|
|
||||||
Ops.push_back(DAG.getNode(ISD::SIGN_EXTEND,
|
|
||||||
N->getDebugLoc(), VT, SOp));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ops.push_back(SetCC->getOperand(2));
|
|
||||||
CombineTo(SetCC, DAG.getNode(ISD::SETCC, N->getDebugLoc(),
|
|
||||||
SetCC->getValueType(0),
|
|
||||||
&Ops[0], Ops.size()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return SDValue(N, 0); // Return N so it doesn't get rechecked!
|
return SDValue(N, 0); // Return N so it doesn't get rechecked!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3835,6 +3842,45 @@ SDValue DAGCombiner::visitSIGN_EXTEND(SDNode *N) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fold (sext (and/or/xor (load x), cst)) ->
|
||||||
|
// (and/or/xor (sextload x), (sext cst))
|
||||||
|
if ((N0.getOpcode() == ISD::AND || N0.getOpcode() == ISD::OR ||
|
||||||
|
N0.getOpcode() == ISD::XOR) &&
|
||||||
|
isa<LoadSDNode>(N0.getOperand(0)) &&
|
||||||
|
N0.getOperand(1).getOpcode() == ISD::Constant &&
|
||||||
|
TLI.isLoadExtLegal(ISD::SEXTLOAD, N0.getValueType()) &&
|
||||||
|
(!LegalOperations && TLI.isOperationLegal(N0.getOpcode(), VT))) {
|
||||||
|
LoadSDNode *LN0 = cast<LoadSDNode>(N0.getOperand(0));
|
||||||
|
if (LN0->getExtensionType() != ISD::ZEXTLOAD) {
|
||||||
|
bool DoXform = true;
|
||||||
|
SmallVector<SDNode*, 4> SetCCs;
|
||||||
|
if (!N0.hasOneUse())
|
||||||
|
DoXform = ExtendUsesToFormExtLoad(N, N0.getOperand(0), ISD::SIGN_EXTEND,
|
||||||
|
SetCCs, TLI);
|
||||||
|
if (DoXform) {
|
||||||
|
SDValue ExtLoad = DAG.getExtLoad(ISD::SEXTLOAD, LN0->getDebugLoc(), VT,
|
||||||
|
LN0->getChain(), LN0->getBasePtr(),
|
||||||
|
LN0->getPointerInfo(),
|
||||||
|
LN0->getMemoryVT(),
|
||||||
|
LN0->isVolatile(),
|
||||||
|
LN0->isNonTemporal(),
|
||||||
|
LN0->getAlignment());
|
||||||
|
APInt Mask = cast<ConstantSDNode>(N0.getOperand(1))->getAPIntValue();
|
||||||
|
Mask = Mask.sext(VT.getSizeInBits());
|
||||||
|
SDValue And = DAG.getNode(N0.getOpcode(), N->getDebugLoc(), VT,
|
||||||
|
ExtLoad, DAG.getConstant(Mask, VT));
|
||||||
|
SDValue Trunc = DAG.getNode(ISD::TRUNCATE,
|
||||||
|
N0.getOperand(0).getDebugLoc(),
|
||||||
|
N0.getOperand(0).getValueType(), ExtLoad);
|
||||||
|
CombineTo(N, And);
|
||||||
|
CombineTo(N0.getOperand(0).getNode(), Trunc, ExtLoad.getValue(1));
|
||||||
|
ExtendSetCCUses(SetCCs, Trunc, ExtLoad, N->getDebugLoc(),
|
||||||
|
ISD::SIGN_EXTEND);
|
||||||
|
return SDValue(N, 0); // Return N so it doesn't get rechecked!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (N0.getOpcode() == ISD::SETCC) {
|
if (N0.getOpcode() == ISD::SETCC) {
|
||||||
// sext(setcc) -> sext_in_reg(vsetcc) for vectors.
|
// sext(setcc) -> sext_in_reg(vsetcc) for vectors.
|
||||||
// Only do this before legalize for now.
|
// Only do this before legalize for now.
|
||||||
@@ -3993,30 +4039,51 @@ SDValue DAGCombiner::visitZERO_EXTEND(SDNode *N) {
|
|||||||
N0.getValueType(), ExtLoad);
|
N0.getValueType(), ExtLoad);
|
||||||
CombineTo(N0.getNode(), Trunc, ExtLoad.getValue(1));
|
CombineTo(N0.getNode(), Trunc, ExtLoad.getValue(1));
|
||||||
|
|
||||||
// Extend SetCC uses if necessary.
|
ExtendSetCCUses(SetCCs, Trunc, ExtLoad, N->getDebugLoc(),
|
||||||
for (unsigned i = 0, e = SetCCs.size(); i != e; ++i) {
|
ISD::ZERO_EXTEND);
|
||||||
SDNode *SetCC = SetCCs[i];
|
|
||||||
SmallVector<SDValue, 4> Ops;
|
|
||||||
|
|
||||||
for (unsigned j = 0; j != 2; ++j) {
|
|
||||||
SDValue SOp = SetCC->getOperand(j);
|
|
||||||
if (SOp == Trunc)
|
|
||||||
Ops.push_back(ExtLoad);
|
|
||||||
else
|
|
||||||
Ops.push_back(DAG.getNode(ISD::ZERO_EXTEND,
|
|
||||||
N->getDebugLoc(), VT, SOp));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ops.push_back(SetCC->getOperand(2));
|
|
||||||
CombineTo(SetCC, DAG.getNode(ISD::SETCC, N->getDebugLoc(),
|
|
||||||
SetCC->getValueType(0),
|
|
||||||
&Ops[0], Ops.size()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return SDValue(N, 0); // Return N so it doesn't get rechecked!
|
return SDValue(N, 0); // Return N so it doesn't get rechecked!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fold (zext (and/or/xor (load x), cst)) ->
|
||||||
|
// (and/or/xor (zextload x), (zext cst))
|
||||||
|
if ((N0.getOpcode() == ISD::AND || N0.getOpcode() == ISD::OR ||
|
||||||
|
N0.getOpcode() == ISD::XOR) &&
|
||||||
|
isa<LoadSDNode>(N0.getOperand(0)) &&
|
||||||
|
N0.getOperand(1).getOpcode() == ISD::Constant &&
|
||||||
|
TLI.isLoadExtLegal(ISD::ZEXTLOAD, N0.getValueType()) &&
|
||||||
|
(!LegalOperations && TLI.isOperationLegal(N0.getOpcode(), VT))) {
|
||||||
|
LoadSDNode *LN0 = cast<LoadSDNode>(N0.getOperand(0));
|
||||||
|
if (LN0->getExtensionType() != ISD::SEXTLOAD) {
|
||||||
|
bool DoXform = true;
|
||||||
|
SmallVector<SDNode*, 4> SetCCs;
|
||||||
|
if (!N0.hasOneUse())
|
||||||
|
DoXform = ExtendUsesToFormExtLoad(N, N0.getOperand(0), ISD::ZERO_EXTEND,
|
||||||
|
SetCCs, TLI);
|
||||||
|
if (DoXform) {
|
||||||
|
SDValue ExtLoad = DAG.getExtLoad(ISD::ZEXTLOAD, LN0->getDebugLoc(), VT,
|
||||||
|
LN0->getChain(), LN0->getBasePtr(),
|
||||||
|
LN0->getPointerInfo(),
|
||||||
|
LN0->getMemoryVT(),
|
||||||
|
LN0->isVolatile(),
|
||||||
|
LN0->isNonTemporal(),
|
||||||
|
LN0->getAlignment());
|
||||||
|
APInt Mask = cast<ConstantSDNode>(N0.getOperand(1))->getAPIntValue();
|
||||||
|
Mask = Mask.zext(VT.getSizeInBits());
|
||||||
|
SDValue And = DAG.getNode(N0.getOpcode(), N->getDebugLoc(), VT,
|
||||||
|
ExtLoad, DAG.getConstant(Mask, VT));
|
||||||
|
SDValue Trunc = DAG.getNode(ISD::TRUNCATE,
|
||||||
|
N0.getOperand(0).getDebugLoc(),
|
||||||
|
N0.getOperand(0).getValueType(), ExtLoad);
|
||||||
|
CombineTo(N, And);
|
||||||
|
CombineTo(N0.getOperand(0).getNode(), Trunc, ExtLoad.getValue(1));
|
||||||
|
ExtendSetCCUses(SetCCs, Trunc, ExtLoad, N->getDebugLoc(),
|
||||||
|
ISD::ZERO_EXTEND);
|
||||||
|
return SDValue(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)))
|
||||||
if ((ISD::isZEXTLoad(N0.getNode()) || ISD::isEXTLoad(N0.getNode())) &&
|
if ((ISD::isZEXTLoad(N0.getNode()) || ISD::isEXTLoad(N0.getNode())) &&
|
||||||
@@ -4201,27 +4268,8 @@ SDValue DAGCombiner::visitANY_EXTEND(SDNode *N) {
|
|||||||
SDValue Trunc = DAG.getNode(ISD::TRUNCATE, N0.getDebugLoc(),
|
SDValue Trunc = DAG.getNode(ISD::TRUNCATE, N0.getDebugLoc(),
|
||||||
N0.getValueType(), ExtLoad);
|
N0.getValueType(), ExtLoad);
|
||||||
CombineTo(N0.getNode(), Trunc, ExtLoad.getValue(1));
|
CombineTo(N0.getNode(), Trunc, ExtLoad.getValue(1));
|
||||||
|
ExtendSetCCUses(SetCCs, Trunc, ExtLoad, N->getDebugLoc(),
|
||||||
// Extend SetCC uses if necessary.
|
ISD::ANY_EXTEND);
|
||||||
for (unsigned i = 0, e = SetCCs.size(); i != e; ++i) {
|
|
||||||
SDNode *SetCC = SetCCs[i];
|
|
||||||
SmallVector<SDValue, 4> Ops;
|
|
||||||
|
|
||||||
for (unsigned j = 0; j != 2; ++j) {
|
|
||||||
SDValue SOp = SetCC->getOperand(j);
|
|
||||||
if (SOp == Trunc)
|
|
||||||
Ops.push_back(ExtLoad);
|
|
||||||
else
|
|
||||||
Ops.push_back(DAG.getNode(ISD::ANY_EXTEND,
|
|
||||||
N->getDebugLoc(), VT, SOp));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ops.push_back(SetCC->getOperand(2));
|
|
||||||
CombineTo(SetCC, DAG.getNode(ISD::SETCC, N->getDebugLoc(),
|
|
||||||
SetCC->getValueType(0),
|
|
||||||
&Ops[0], Ops.size()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return SDValue(N, 0); // Return N so it doesn't get rechecked!
|
return SDValue(N, 0); // Return N so it doesn't get rechecked!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,9 +3,19 @@
|
|||||||
define signext i16 @foo(i16 signext %x) nounwind {
|
define signext i16 @foo(i16 signext %x) nounwind {
|
||||||
entry:
|
entry:
|
||||||
; CHECK: foo:
|
; CHECK: foo:
|
||||||
; CHECK: movzwl 4(%esp), %eax
|
; CHECK-NOT: movzwl
|
||||||
; CHECK: xorl $21998, %eax
|
|
||||||
; CHECK: movswl %ax, %eax
|
; CHECK: movswl %ax, %eax
|
||||||
|
; CHECK: xorl $21998, %eax
|
||||||
%0 = xor i16 %x, 21998
|
%0 = xor i16 %x, 21998
|
||||||
ret i16 %0
|
ret i16 %0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
define signext i16 @bar(i16 signext %x) nounwind {
|
||||||
|
entry:
|
||||||
|
; CHECK: bar:
|
||||||
|
; CHECK-NOT: movzwl
|
||||||
|
; CHECK: movswl %ax, %eax
|
||||||
|
; CHECK: xorl $-10770, %eax
|
||||||
|
%0 = xor i16 %x, 54766
|
||||||
|
ret i16 %0
|
||||||
|
}
|
||||||
|
36
test/CodeGen/X86/zext-fold.ll
Normal file
36
test/CodeGen/X86/zext-fold.ll
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
; RUN: llc < %s -march=x86 | FileCheck %s
|
||||||
|
|
||||||
|
;; Simple case
|
||||||
|
define i32 @test1(i8 %x) nounwind readnone {
|
||||||
|
%A = and i8 %x, -32
|
||||||
|
%B = zext i8 %A to i32
|
||||||
|
ret i32 %B
|
||||||
|
}
|
||||||
|
; CHECK: test1
|
||||||
|
; CHECK: movzbl
|
||||||
|
; CHECK-NEXT: andl {{.*}}224
|
||||||
|
|
||||||
|
;; Multiple uses of %x but easily extensible.
|
||||||
|
define i32 @test2(i8 %x) nounwind readnone {
|
||||||
|
%A = and i8 %x, -32
|
||||||
|
%B = zext i8 %A to i32
|
||||||
|
%C = or i8 %x, 63
|
||||||
|
%D = zext i8 %C to i32
|
||||||
|
%E = add i32 %B, %D
|
||||||
|
ret i32 %E
|
||||||
|
}
|
||||||
|
; CHECK: test2
|
||||||
|
; CHECK: movzbl
|
||||||
|
; CHECK-NEXT: orl {{.*}}63
|
||||||
|
; CHECK-NEXT: andl {{.*}}224
|
||||||
|
|
||||||
|
declare void @use(i32, i8)
|
||||||
|
|
||||||
|
;; Multiple uses of %x where we shouldn't extend the load.
|
||||||
|
define void @test3(i8 %x) nounwind readnone {
|
||||||
|
%A = and i8 %x, -32
|
||||||
|
%B = zext i8 %A to i32
|
||||||
|
call void @use(i32 %B, i8 %x)
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
; CHECK: test3
|
Reference in New Issue
Block a user