mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-02 07:32:52 +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:
parent
e0b5cfcae8
commit
c06b5bf340
@ -138,6 +138,10 @@ namespace {
|
||||
SDValue PromoteExtend(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
|
||||
/// particular type of node. If that doesn't do anything, try the
|
||||
/// target-specific DAG combines.
|
||||
@ -3699,6 +3703,28 @@ static bool ExtendUsesToFormExtLoad(SDNode *N, SDValue N0,
|
||||
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 N0 = N->getOperand(0);
|
||||
EVT VT = N->getValueType(0);
|
||||
@ -3787,27 +3813,8 @@ SDValue DAGCombiner::visitSIGN_EXTEND(SDNode *N) {
|
||||
SDValue Trunc = DAG.getNode(ISD::TRUNCATE, N0.getDebugLoc(),
|
||||
N0.getValueType(), ExtLoad);
|
||||
CombineTo(N0.getNode(), Trunc, ExtLoad.getValue(1));
|
||||
|
||||
// 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(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()));
|
||||
}
|
||||
|
||||
ExtendSetCCUses(SetCCs, Trunc, ExtLoad, N->getDebugLoc(),
|
||||
ISD::SIGN_EXTEND);
|
||||
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) {
|
||||
// sext(setcc) -> sext_in_reg(vsetcc) for vectors.
|
||||
// Only do this before legalize for now.
|
||||
@ -3993,30 +4039,51 @@ SDValue DAGCombiner::visitZERO_EXTEND(SDNode *N) {
|
||||
N0.getValueType(), ExtLoad);
|
||||
CombineTo(N0.getNode(), Trunc, ExtLoad.getValue(1));
|
||||
|
||||
// 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(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()));
|
||||
}
|
||||
|
||||
ExtendSetCCUses(SetCCs, Trunc, ExtLoad, N->getDebugLoc(),
|
||||
ISD::ZERO_EXTEND);
|
||||
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 ( extload x)) -> (zext (truncate (zextload x)))
|
||||
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(),
|
||||
N0.getValueType(), ExtLoad);
|
||||
CombineTo(N0.getNode(), Trunc, ExtLoad.getValue(1));
|
||||
|
||||
// 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(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()));
|
||||
}
|
||||
|
||||
ExtendSetCCUses(SetCCs, Trunc, ExtLoad, N->getDebugLoc(),
|
||||
ISD::ANY_EXTEND);
|
||||
return SDValue(N, 0); // Return N so it doesn't get rechecked!
|
||||
}
|
||||
}
|
||||
|
@ -3,9 +3,19 @@
|
||||
define signext i16 @foo(i16 signext %x) nounwind {
|
||||
entry:
|
||||
; CHECK: foo:
|
||||
; CHECK: movzwl 4(%esp), %eax
|
||||
; CHECK: xorl $21998, %eax
|
||||
; CHECK-NOT: movzwl
|
||||
; CHECK: movswl %ax, %eax
|
||||
; CHECK: xorl $21998, %eax
|
||||
%0 = xor i16 %x, 21998
|
||||
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
|
Loading…
Reference in New Issue
Block a user