diff options
author | Anton Korobeynikov <asl@math.spbu.ru> | 2009-12-11 23:01:29 +0000 |
---|---|---|
committer | Anton Korobeynikov <asl@math.spbu.ru> | 2009-12-11 23:01:29 +0000 |
commit | 8d1ffbd1adad453fe330be4951400bfd25fab666 (patch) | |
tree | 0c0cb92016b625c72049185348bc48380ac68703 | |
parent | c42a0b75a41144be86d40872b57850ab578969ea (diff) |
Lower setcc branchless, if this is profitable.
Based on the patch by Brian Lucas!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@91175 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/Target/MSP430/MSP430ISelLowering.cpp | 87 | ||||
-rw-r--r-- | lib/Target/MSP430/MSP430ISelLowering.h | 1 | ||||
-rw-r--r-- | test/CodeGen/MSP430/setcc.ll | 116 |
3 files changed, 202 insertions, 2 deletions
diff --git a/lib/Target/MSP430/MSP430ISelLowering.cpp b/lib/Target/MSP430/MSP430ISelLowering.cpp index 5012791d38..4bd6006964 100644 --- a/lib/Target/MSP430/MSP430ISelLowering.cpp +++ b/lib/Target/MSP430/MSP430ISelLowering.cpp @@ -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); diff --git a/lib/Target/MSP430/MSP430ISelLowering.h b/lib/Target/MSP430/MSP430ISelLowering.h index 0eac093833..b126d8e431 100644 --- a/lib/Target/MSP430/MSP430ISelLowering.h +++ b/lib/Target/MSP430/MSP430ISelLowering.h @@ -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 index 0000000000..971d1b5be8 --- /dev/null +++ b/test/CodeGen/MSP430/setcc.ll @@ -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 +} + |