diff --git a/lib/Target/ARM/ARMISelLowering.cpp b/lib/Target/ARM/ARMISelLowering.cpp index bb715cb3ca4..8f3457a0452 100644 --- a/lib/Target/ARM/ARMISelLowering.cpp +++ b/lib/Target/ARM/ARMISelLowering.cpp @@ -266,6 +266,7 @@ const char *ARMTargetLowering::getTargetNodeName(unsigned Opcode) const { case ARMISD::RET_FLAG: return "ARMISD::RET_FLAG"; case ARMISD::PIC_ADD: return "ARMISD::PIC_ADD"; case ARMISD::CMP: return "ARMISD::CMP"; + case ARMISD::CMPNZ: return "ARMISD::CMPNZ"; case ARMISD::CMPFP: return "ARMISD::CMPFP"; case ARMISD::CMPFPw0: return "ARMISD::CMPFPw0"; case ARMISD::FMSTAT: return "ARMISD::FMSTAT"; @@ -946,8 +947,21 @@ static SDOperand getARMCmp(SDOperand LHS, SDOperand RHS, ISD::CondCode CC, } ARMCC::CondCodes CondCode = IntCCToARMCC(CC); + ARMISD::NodeType CompareType; + switch (CondCode) { + default: + CompareType = ARMISD::CMP; + break; + case ARMCC::EQ: + case ARMCC::NE: + case ARMCC::MI: + case ARMCC::PL: + // Uses only N and Z Flags + CompareType = ARMISD::CMPNZ; + break; + } ARMCC = DAG.getConstant(CondCode, MVT::i32); - return DAG.getNode(ARMISD::CMP, MVT::Flag, LHS, RHS); + return DAG.getNode(CompareType, MVT::Flag, LHS, RHS); } /// Returns a appropriate VFP CMP (fcmp{s|d}+fmstat) for the given operands. diff --git a/lib/Target/ARM/ARMISelLowering.h b/lib/Target/ARM/ARMISelLowering.h index 8846decd9bf..9842b9248bd 100644 --- a/lib/Target/ARM/ARMISelLowering.h +++ b/lib/Target/ARM/ARMISelLowering.h @@ -43,6 +43,7 @@ namespace llvm { PIC_ADD, // Add with a PC operand and a PIC label. CMP, // ARM compare instructions. + CMPNZ, // ARM compare that uses only N or Z flags. CMPFP, // ARM VFP compare instruction, sets FPSCR. CMPFPw0, // ARM VFP compare against zero instruction, sets FPSCR. FMSTAT, // ARM fmstat instruction. diff --git a/lib/Target/ARM/ARMInstrInfo.td b/lib/Target/ARM/ARMInstrInfo.td index 36d2e4a0460..1c3e34bd304 100644 --- a/lib/Target/ARM/ARMInstrInfo.td +++ b/lib/Target/ARM/ARMInstrInfo.td @@ -70,6 +70,9 @@ def ARMbrjt : SDNode<"ARMISD::BR_JT", SDT_ARMBrJT, def ARMcmp : SDNode<"ARMISD::CMP", SDT_ARMCmp, [SDNPOutFlag]>; +def ARMcmpNZ : SDNode<"ARMISD::CMPNZ", SDT_ARMCmp, + [SDNPOutFlag]>; + def ARMpic_add : SDNode<"ARMISD::PIC_ADD", SDT_ARMPICAdd>; def ARMsrl_flag : SDNode<"ARMISD::SRL_FLAG", SDTIntUnaryOp, [SDNPOutFlag]>; @@ -1023,10 +1026,15 @@ def : ARMPat<(ARMcmp GPR:$src, so_imm_neg:$imm), (CMNri GPR:$src, so_imm_neg:$imm)>; // Note that TST/TEQ don't set all the same flags that CMP does! -def TSTrr : AI1<(ops GPR:$a, so_reg:$b), "tst $a, $b", []>; -def TSTri : AI1<(ops GPR:$a, so_imm:$b), "tst $a, $b", []>; -def TEQrr : AI1<(ops GPR:$a, so_reg:$b), "teq $a, $b", []>; -def TEQri : AI1<(ops GPR:$a, so_imm:$b), "teq $a, $b", []>; +defm TST : AI1_bin0_irs<"tst", BinOpFrag<(ARMcmpNZ (and node:$LHS, node:$RHS), 0)>>; +defm TEQ : AI1_bin0_irs<"teq", BinOpFrag<(ARMcmpNZ (xor node:$LHS, node:$RHS), 0)>>; + +defm CMPnz : AI1_bin0_irs<"cmp", BinOpFrag<(ARMcmpNZ node:$LHS, node:$RHS)>>; +defm CMNnz : AI1_bin0_irs<"cmn", BinOpFrag<(ARMcmpNZ node:$LHS,(ineg node:$RHS))>>; + +def : ARMPat<(ARMcmpNZ GPR:$src, so_imm_neg:$imm), + (CMNri GPR:$src, so_imm_neg:$imm)>; + // Conditional moves def MOVCCr : AI<(ops GPR:$dst, GPR:$false, GPR:$true, CCOp:$cc), diff --git a/lib/Target/ARM/ARMInstrThumb.td b/lib/Target/ARM/ARMInstrThumb.td index ad8a88f2077..48196369add 100644 --- a/lib/Target/ARM/ARMInstrThumb.td +++ b/lib/Target/ARM/ARMInstrThumb.td @@ -356,7 +356,23 @@ def tCMPi8 : TI<(ops GPR:$lhs, i32imm:$rhs), def tCMPr : TI<(ops GPR:$lhs, GPR:$rhs), "cmp $lhs, $rhs", [(ARMcmp GPR:$lhs, GPR:$rhs)]>; - + +def tTST : TI<(ops GPR:$lhs, GPR:$rhs), + "tst $lhs, $rhs", + [(ARMcmpNZ (and GPR:$lhs, GPR:$rhs), 0)]>; + +def tCMNNZ : TI<(ops GPR:$lhs, GPR:$rhs), + "cmn $lhs, $rhs", + [(ARMcmpNZ GPR:$lhs, (ineg GPR:$rhs))]>; + +def tCMPNZi8 : TI<(ops GPR:$lhs, i32imm:$rhs), + "cmp $lhs, $rhs", + [(ARMcmpNZ GPR:$lhs, imm0_255:$rhs)]>; + +def tCMPNZr : TI<(ops GPR:$lhs, GPR:$rhs), + "cmp $lhs, $rhs", + [(ARMcmpNZ GPR:$lhs, GPR:$rhs)]>; + // TODO: A7-37: CMP(3) - cmp hi regs def tEOR : TIt<(ops GPR:$dst, GPR:$lhs, GPR:$rhs), @@ -472,7 +488,6 @@ def tSXTH : TI<(ops GPR:$dst, GPR:$src), [(set GPR:$dst, (sext_inreg GPR:$src, i16))]>, Requires<[IsThumb, HasV6]>; -// TODO: A7-122: TST - test. def tUXTB : TI<(ops GPR:$dst, GPR:$src), "uxtb $dst, $src", diff --git a/test/CodeGen/ARM/tst_teq.ll b/test/CodeGen/ARM/tst_teq.ll new file mode 100644 index 00000000000..fb2f73be14e --- /dev/null +++ b/test/CodeGen/ARM/tst_teq.ll @@ -0,0 +1,21 @@ +; RUN: llvm-as < %s | llc -march=arm && +; RUN: llvm-as < %s | llc -march=thumb && +; RUN: llvm-as < %s | llc -march=arm | grep "tst" && +; RUN: llvm-as < %s | llc -march=arm | grep "teq" && +; RUN: llvm-as < %s | llc -march=thumb | grep "tst" + +define i32 @f(i32 %a) { +entry: + %tmp2 = and i32 %a, 255 ; [#uses=1] + icmp eq i32 %tmp2, 0 ; :0 [#uses=1] + %retval = select i1 %0, i32 20, i32 10 ; [#uses=1] + ret i32 %retval +} + +define i32 @g(i32 %a) { +entry: + %tmp2 = xor i32 %a, 255 + icmp eq i32 %tmp2, 0 ; :0 [#uses=1] + %retval = select i1 %0, i32 20, i32 10 ; [#uses=1] + ret i32 %retval +}