From 7b871b3464a5f84f8984786c665f70f5384fb0d6 Mon Sep 17 00:00:00 2001 From: Richard Osborne Date: Tue, 9 Mar 2010 16:07:47 +0000 Subject: [PATCH] Add DAG combine for ladd / lsub. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@98057 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/XCore/XCoreISelLowering.cpp | 63 +++++++++++++++++++++++++ lib/Target/XCore/XCoreISelLowering.h | 7 +++ test/CodeGen/XCore/ladd_lsub_combine.ll | 28 +++++++++++ 3 files changed, 98 insertions(+) create mode 100644 test/CodeGen/XCore/ladd_lsub_combine.ll diff --git a/lib/Target/XCore/XCoreISelLowering.cpp b/lib/Target/XCore/XCoreISelLowering.cpp index e6515d821b8..e59b18cd2a3 100644 --- a/lib/Target/XCore/XCoreISelLowering.cpp +++ b/lib/Target/XCore/XCoreISelLowering.cpp @@ -1097,6 +1097,48 @@ SDValue XCoreTargetLowering::PerformDAGCombine(SDNode *N, DebugLoc dl = N->getDebugLoc(); switch (N->getOpcode()) { default: break; + case XCoreISD::LADD: { + SDValue N0 = N->getOperand(0); + SDValue N1 = N->getOperand(1); + SDValue N2 = N->getOperand(2); + ConstantSDNode *N0C = dyn_cast(N0); + ConstantSDNode *N1C = dyn_cast(N1); + EVT VT = N0.getValueType(); + + // fold (ladd 0, 0, x) -> 0, x & 1 + if (N0C && N0C->isNullValue() && N1C && N1C->isNullValue()) { + SDValue Carry = DAG.getConstant(0, VT); + SDValue Result = DAG.getNode(ISD::AND, dl, VT, N2, + DAG.getConstant(1, VT)); + SDValue Ops [] = { Carry, Result }; + return DAG.getMergeValues(Ops, 2, dl); + } + } + break; + case XCoreISD::LSUB: { + SDValue N0 = N->getOperand(0); + SDValue N1 = N->getOperand(1); + SDValue N2 = N->getOperand(2); + ConstantSDNode *N0C = dyn_cast(N0); + ConstantSDNode *N1C = dyn_cast(N1); + EVT VT = N0.getValueType(); + + // fold (lsub 0, 0, x) -> x, -x iff x has only the low bit set + if (N0C && N0C->isNullValue() && N1C && N1C->isNullValue()) { + APInt KnownZero, KnownOne; + APInt Mask = APInt::getHighBitsSet(VT.getSizeInBits(), + VT.getSizeInBits() - 1); + DAG.ComputeMaskedBits(N2, Mask, KnownZero, KnownOne); + if (KnownZero == Mask) { + SDValue Borrow = N2; + SDValue Result = DAG.getNode(ISD::SUB, dl, VT, + DAG.getConstant(0, VT), N2); + SDValue Ops [] = { Borrow, Result }; + return DAG.getMergeValues(Ops, 2, dl); + } + } + } + break; case ISD::STORE: { // Replace unaligned store of unaligned load with memmove. StoreSDNode *ST = cast(N); @@ -1137,6 +1179,27 @@ SDValue XCoreTargetLowering::PerformDAGCombine(SDNode *N, return SDValue(); } +void XCoreTargetLowering::computeMaskedBitsForTargetNode(const SDValue Op, + const APInt &Mask, + APInt &KnownZero, + APInt &KnownOne, + const SelectionDAG &DAG, + unsigned Depth) const { + KnownZero = KnownOne = APInt(Mask.getBitWidth(), 0); + switch (Op.getOpcode()) { + default: break; + case XCoreISD::LADD: + case XCoreISD::LSUB: + if (Op.getResNo() == 0) { + // Top bits of carry / borrow are clear. + KnownZero = APInt::getHighBitsSet(Mask.getBitWidth(), + Mask.getBitWidth() - 1); + KnownZero &= Mask; + } + break; + } +} + //===----------------------------------------------------------------------===// // Addressing mode description hooks //===----------------------------------------------------------------------===// diff --git a/lib/Target/XCore/XCoreISelLowering.h b/lib/Target/XCore/XCoreISelLowering.h index 0c638aff48f..f44c3243ee7 100644 --- a/lib/Target/XCore/XCoreISelLowering.h +++ b/lib/Target/XCore/XCoreISelLowering.h @@ -144,6 +144,13 @@ namespace llvm { virtual SDValue PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const; + virtual void computeMaskedBitsForTargetNode(const SDValue Op, + const APInt &Mask, + APInt &KnownZero, + APInt &KnownOne, + const SelectionDAG &DAG, + unsigned Depth = 0) const; + virtual SDValue LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv, diff --git a/test/CodeGen/XCore/ladd_lsub_combine.ll b/test/CodeGen/XCore/ladd_lsub_combine.ll new file mode 100644 index 00000000000..ea9a3b78f2f --- /dev/null +++ b/test/CodeGen/XCore/ladd_lsub_combine.ll @@ -0,0 +1,28 @@ +; RUN: llvm-as < %s | llc -march=xcore | FileCheck %s + +; Only needs one ladd +define i64 @f1(i32 %x, i32 %y) nounwind { +entry: + %0 = zext i32 %x to i64 ; [#uses=1] + %1 = zext i32 %y to i64 ; [#uses=1] + %2 = add i64 %1, %0 ; [#uses=1] + ret i64 %2 +} +; CHECK: f1: +; CHECK: ldc r2, 0 +; CHECK-NEXT: ladd r1, r0, r1, r0, r2 +; CHECK-NEXT: retsp 0 + +; Only needs one lsub and one neg +define i64 @f2(i32 %x, i32 %y) nounwind { +entry: + %0 = zext i32 %x to i64 ; [#uses=1] + %1 = zext i32 %y to i64 ; [#uses=1] + %2 = sub i64 %1, %0 ; [#uses=1] + ret i64 %2 +} +; CHECK: f2: +; CHECK: ldc r2, 0 +; CHECK-NEXT: lsub r1, r0, r1, r0, r2 +; CHECK-NEXT: neg r1, r1 +; CHECK-NEXT: retsp 0 -- 2.34.1