Lower setcc branchless, if this is profitable.
authorAnton Korobeynikov <asl@math.spbu.ru>
Fri, 11 Dec 2009 23:01:29 +0000 (23:01 +0000)
committerAnton Korobeynikov <asl@math.spbu.ru>
Fri, 11 Dec 2009 23:01:29 +0000 (23:01 +0000)
Based on the patch by Brian Lucas!

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@91175 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/MSP430/MSP430ISelLowering.cpp
lib/Target/MSP430/MSP430ISelLowering.h
test/CodeGen/MSP430/setcc.ll [new file with mode: 0644]

index 5012791d38032bd779b48fcdd6435495bcea7f92..4bd6006964f25288eb29325b66804d97b9442679 100644 (file)
@@ -115,8 +115,8 @@ MSP430TargetLowering::MSP430TargetLowering(MSP430TargetMachine &tm) :
   setOperationAction(ISD::BR_CC,            MVT::i8,    Custom);
   setOperationAction(ISD::BR_CC,            MVT::i16,   Custom);
   setOperationAction(ISD::BRCOND,           MVT::Other, Expand);
-  setOperationAction(ISD::SETCC,            MVT::i8,    Expand);
-  setOperationAction(ISD::SETCC,            MVT::i16,   Expand);
+  setOperationAction(ISD::SETCC,            MVT::i8,    Custom);
+  setOperationAction(ISD::SETCC,            MVT::i16,   Custom);
   setOperationAction(ISD::SELECT,           MVT::i8,    Expand);
   setOperationAction(ISD::SELECT,           MVT::i16,   Expand);
   setOperationAction(ISD::SELECT_CC,        MVT::i8,    Custom);
@@ -183,6 +183,7 @@ SDValue MSP430TargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) {
   case ISD::SRA:              return LowerShifts(Op, DAG);
   case ISD::GlobalAddress:    return LowerGlobalAddress(Op, DAG);
   case ISD::ExternalSymbol:   return LowerExternalSymbol(Op, DAG);
+  case ISD::SETCC:            return LowerSETCC(Op, DAG);
   case ISD::BR_CC:            return LowerBR_CC(Op, DAG);
   case ISD::SELECT_CC:        return LowerSELECT_CC(Op, DAG);
   case ISD::SIGN_EXTEND:      return LowerSIGN_EXTEND(Op, DAG);
@@ -701,6 +702,88 @@ SDValue MSP430TargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) {
                      Chain, Dest, TargetCC, Flag);
 }
 
+
+SDValue MSP430TargetLowering::LowerSETCC(SDValue Op, SelectionDAG &DAG) {
+  SDValue LHS   = Op.getOperand(0);
+  SDValue RHS   = Op.getOperand(1);
+  DebugLoc dl   = Op.getDebugLoc();
+
+  // If we are doing an AND and testing against zero, then the CMP
+  // will not be generated.  The AND (or BIT) will generate the condition codes,
+  // but they are different from CMP.
+  bool andCC = false;
+  if (ConstantSDNode *RHSC = dyn_cast<ConstantSDNode>(RHS)) {
+    if (RHSC->isNullValue() && LHS.hasOneUse() &&
+        (LHS.getOpcode() == ISD::AND ||
+         (LHS.getOpcode() == ISD::TRUNCATE &&
+          LHS.getOperand(0).getOpcode() == ISD::AND))) {
+      andCC = true;
+    }
+  }
+  ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(2))->get();
+  SDValue TargetCC;
+  SDValue Flag = EmitCMP(LHS, RHS, TargetCC, CC, dl, DAG);
+
+  // Get the condition codes directly from the status register, if its easy.
+  // Otherwise a branch will be generated.  Note that the AND and BIT
+  // instructions generate different flags than CMP, the carry bit can be used
+  // for NE/EQ.
+  bool Invert = false;
+  bool Shift = false;
+  bool Convert = true;
+  switch (cast<ConstantSDNode>(TargetCC)->getZExtValue()) {
+   default:
+    Convert = false;
+    break;
+   case MSP430CC::COND_HS:
+     // Res = SRW & 1, no processing is required
+     break;
+    case MSP430CC::COND_LO:
+     // Res = ~(SRW & 1)
+     Invert = true;
+     break;
+    case MSP430CC::COND_NE:
+     if (andCC) {
+       // C = ~Z, thus Res = SRW & 1, no processing is required
+     } else {
+       // Res = (SRW >> 1) & 1
+       Shift = true;
+     }
+     break;
+    case MSP430CC::COND_E:
+     if (andCC) {
+       // C = ~Z, thus Res = ~(SRW & 1)
+     } else {
+       // Res = ~((SRW >> 1) & 1)
+       Shift = true;
+     }
+     Invert = true;
+     break;
+  }
+  EVT VT = Op.getValueType();
+  SDValue One  = DAG.getConstant(1, VT);
+  if (Convert) {
+    SDValue SR = DAG.getCopyFromReg(DAG.getEntryNode(), dl, MSP430::SRW,
+                                     MVT::i16, Flag);
+    if (Shift)
+      // FIXME: somewhere this is turned into a SRL, lower it MSP specific?
+      SR = DAG.getNode(ISD::SRA, dl, MVT::i16, SR, One);
+    SR = DAG.getNode(ISD::AND, dl, MVT::i16, SR, One);
+    if (Invert)
+      SR = DAG.getNode(ISD::XOR, dl, MVT::i16, SR, One);
+    return SR;
+  } else {
+    SDValue Zero = DAG.getConstant(0, VT);
+    SDVTList VTs = DAG.getVTList(Op.getValueType(), MVT::Flag);
+    SmallVector<SDValue, 4> Ops;
+    Ops.push_back(One);
+    Ops.push_back(Zero);
+    Ops.push_back(TargetCC);
+    Ops.push_back(Flag);
+    return DAG.getNode(MSP430ISD::SELECT_CC, dl, VTs, &Ops[0], Ops.size());
+  }
+}
+
 SDValue MSP430TargetLowering::LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) {
   SDValue LHS    = Op.getOperand(0);
   SDValue RHS    = Op.getOperand(1);
index 0eac0938338c5ba6a3db1f7ab41963ffccd94ea9..b126d8e431f6ac2dbea9a3667f36cae939709090 100644 (file)
@@ -84,6 +84,7 @@ namespace llvm {
     SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG);
     SDValue LowerExternalSymbol(SDValue Op, SelectionDAG &DAG);
     SDValue LowerBR_CC(SDValue Op, SelectionDAG &DAG);
+    SDValue LowerSETCC(SDValue Op, SelectionDAG &DAG);
     SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG);
     SDValue LowerSIGN_EXTEND(SDValue Op, SelectionDAG &DAG);
     SDValue LowerRETURNADDR(SDValue Op, SelectionDAG &DAG);
diff --git a/test/CodeGen/MSP430/setcc.ll b/test/CodeGen/MSP430/setcc.ll
new file mode 100644 (file)
index 0000000..971d1b5
--- /dev/null
@@ -0,0 +1,116 @@
+; RUN: llc -march=msp430 < %s | FileCheck %s
+target datalayout = "e-p:16:16:16-i1:8:8-i8:8:8-i16:16:16-i32:16:32"
+target triple = "msp430-generic-generic"
+
+define i16 @sccweqand(i16 %a, i16 %b) nounwind {
+       %t1 = and i16 %a, %b
+       %t2 = icmp eq i16 %t1, 0
+       %t3 = zext i1 %t2 to i16
+       ret i16 %t3
+}
+; CHECK: sccweqand:
+; CHECK:       bit.w   r14, r15
+; CHECK-NEXT:  mov.w   r2, r15
+; CHECK-NEXT:  and.w   #1, r15
+; CHECK-NEXT:  xor.w   #1, r15
+
+define i16 @sccwneand(i16 %a, i16 %b) nounwind {
+       %t1 = and i16 %a, %b
+       %t2 = icmp ne i16 %t1, 0
+       %t3 = zext i1 %t2 to i16
+       ret i16 %t3
+}
+; CHECK: sccwneand:
+; CHECK:       bit.w   r14, r15
+; CHECK-NEXT:  mov.w   r2, r15
+; CHECK-NEXT:  and.w   #1, r15
+
+define i16 @sccwne(i16 %a, i16 %b) nounwind {
+       %t1 = icmp ne i16 %a, %b
+       %t2 = zext i1 %t1 to i16
+       ret i16 %t2
+}
+; CHECK:sccwne:
+; CHECK:       cmp.w   r15, r14
+; CHECK-NEXT:  mov.w   r2, r15
+; CHECK-NEXT:  rra.w   r15
+; CHECK-NEXT:  and.w   #1, r15
+
+define i16 @sccweq(i16 %a, i16 %b) nounwind {
+       %t1 = icmp eq i16 %a, %b
+       %t2 = zext i1 %t1 to i16
+       ret i16 %t2
+}
+; CHECK:sccweq:
+; CHECK:       cmp.w   r15, r14
+; CHECK-NEXT:  mov.w   r2, r15
+; CHECK-NEXT:  rra.w   r15
+; CHECK-NEXT:  and.w   #1, r15
+; CHECK-NEXT:  xor.w   #1, r15
+
+define i16 @sccwugt(i16 %a, i16 %b) nounwind {
+       %t1 = icmp ugt i16 %a, %b
+       %t2 = zext i1 %t1 to i16
+       ret i16 %t2
+}
+; CHECK:sccwugt:
+; CHECK:       cmp.w   r14, r15
+; CHECK-NEXT:  mov.w   r2, r15
+; CHECK-NEXT:  and.w   #1, r15
+; CHECK-NEXT:  xor.w   #1, r15
+
+define i16 @sccwuge(i16 %a, i16 %b) nounwind {
+       %t1 = icmp uge i16 %a, %b
+       %t2 = zext i1 %t1 to i16
+       ret i16 %t2
+}
+; CHECK:sccwuge:
+; CHECK:       cmp.w   r15, r14
+; CHECK-NEXT:  mov.w   r2, r15
+; CHECK-NEXT:  and.w   #1, r15
+
+define i16 @sccwult(i16 %a, i16 %b) nounwind {
+       %t1 = icmp ult i16 %a, %b
+       %t2 = zext i1 %t1 to i16
+       ret i16 %t2
+}
+; CHECK:sccwult:
+; CHECK:       cmp.w   r15, r14
+; CHECK-NEXT:  mov.w   r2, r15
+; CHECK-NEXT:  and.w   #1, r15
+; CHECK-NEXT:  xor.w   #1, r15
+
+define i16 @sccwule(i16 %a, i16 %b) nounwind {
+       %t1 = icmp ule i16 %a, %b
+       %t2 = zext i1 %t1 to i16
+       ret i16 %t2
+}
+; CHECK:sccwule:
+; CHECK:       cmp.w   r14, r15
+; CHECK-NEXT:  mov.w   r2, r15
+; CHECK-NEXT:  and.w   #1, r15
+
+define i16 @sccwsgt(i16 %a, i16 %b) nounwind {
+       %t1 = icmp sgt i16 %a, %b
+       %t2 = zext i1 %t1 to i16
+       ret i16 %t2
+}
+
+define i16 @sccwsge(i16 %a, i16 %b) nounwind {
+       %t1 = icmp sge i16 %a, %b
+       %t2 = zext i1 %t1 to i16
+       ret i16 %t2
+}
+
+define i16 @sccwslt(i16 %a, i16 %b) nounwind {
+       %t1 = icmp slt i16 %a, %b
+       %t2 = zext i1 %t1 to i16
+       ret i16 %t2
+}
+
+define i16 @sccwsle(i16 %a, i16 %b) nounwind {
+       %t1 = icmp sle i16 %a, %b
+       %t2 = zext i1 %t1 to i16
+       ret i16 %t2
+}
+