Add DAG combine for ladd / lsub.
authorRichard Osborne <richard@xmos.com>
Tue, 9 Mar 2010 16:07:47 +0000 (16:07 +0000)
committerRichard Osborne <richard@xmos.com>
Tue, 9 Mar 2010 16:07:47 +0000 (16:07 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@98057 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/XCore/XCoreISelLowering.cpp
lib/Target/XCore/XCoreISelLowering.h
test/CodeGen/XCore/ladd_lsub_combine.ll [new file with mode: 0644]

index e6515d821b861aabba1ef4399770dc9a37adb0dd..e59b18cd2a30af68f392f9b489fb578aea5a11bc 100644 (file)
@@ -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<ConstantSDNode>(N0);
+    ConstantSDNode *N1C = dyn_cast<ConstantSDNode>(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<ConstantSDNode>(N0);
+    ConstantSDNode *N1C = dyn_cast<ConstantSDNode>(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<StoreSDNode>(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
 //===----------------------------------------------------------------------===//
index 0c638aff48fedb1044c8995095d1d71526b6b19a..f44c3243ee757fccb806626ae11a167a28b12bf8 100644 (file)
@@ -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 (file)
index 0000000..ea9a3b7
--- /dev/null
@@ -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         ; <i64> [#uses=1]
+       %1 = zext i32 %y to i64         ; <i64> [#uses=1]
+       %2 = add i64 %1, %0             ; <i64> [#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         ; <i64> [#uses=1]
+       %1 = zext i32 %y to i64         ; <i64> [#uses=1]
+       %2 = sub i64 %1, %0             ; <i64> [#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