mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-02-27 02:31:09 +00:00
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
This commit is contained in:
parent
c42a0b75a4
commit
8d1ffbd1ad
@ -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);
|
||||
|
@ -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);
|
||||
|
116
test/CodeGen/MSP430/setcc.ll
Normal file
116
test/CodeGen/MSP430/setcc.ll
Normal file
@ -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
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user