From 875a6ac09a2a4ae2d83dfe262a81d6eb33c24022 Mon Sep 17 00:00:00 2001 From: Evan Cheng Date: Fri, 12 Nov 2010 22:42:47 +0000 Subject: [PATCH] Add conditional mvn instructions. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@118935 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/ARM/ARMISelDAGToDAG.cpp | 36 ++++++++++++++--- lib/Target/ARM/ARMInstrInfo.td | 22 ++++++++++- lib/Target/ARM/ARMInstrThumb2.td | 19 +++++++-- test/CodeGen/ARM/select_xform.ll | 62 +++++++++++++++++++++++++----- 4 files changed, 120 insertions(+), 19 deletions(-) diff --git a/lib/Target/ARM/ARMISelDAGToDAG.cpp b/lib/Target/ARM/ARMISelDAGToDAG.cpp index ee3ffef0e5f..965ec6e4d1c 100644 --- a/lib/Target/ARM/ARMISelDAGToDAG.cpp +++ b/lib/Target/ARM/ARMISelDAGToDAG.cpp @@ -142,14 +142,30 @@ public: bool SelectT2AddrModeSoReg(SDValue N, SDValue &Base, SDValue &OffReg, SDValue &ShImm); + inline bool is_so_imm(unsigned Imm) const { + return ARM_AM::getSOImmVal(Imm) != -1; + } + + inline bool is_so_imm_not(unsigned Imm) const { + return ARM_AM::getSOImmVal(~Imm) != -1; + } + + inline bool is_t2_so_imm(unsigned Imm) const { + return ARM_AM::getT2SOImmVal(Imm) != -1; + } + + inline bool is_t2_so_imm_not(unsigned Imm) const { + return ARM_AM::getT2SOImmVal(~Imm) != -1; + } + inline bool Pred_so_imm(SDNode *inN) const { ConstantSDNode *N = cast(inN); - return ARM_AM::getSOImmVal(N->getZExtValue()) != -1; + return is_so_imm(N->getZExtValue()); } inline bool Pred_t2_so_imm(SDNode *inN) const { ConstantSDNode *N = cast(inN); - return ARM_AM::getT2SOImmVal(N->getZExtValue()) != -1; + return is_t2_so_imm(N->getZExtValue()); } // Include the pieces autogenerated from the target description. @@ -1767,13 +1783,18 @@ SelectT2CMOVImmOp(SDNode *N, SDValue FalseVal, SDValue TrueVal, return 0; unsigned TrueImm = T->getZExtValue(); - bool isSoImm = Pred_t2_so_imm(TrueVal.getNode()); + bool isSoImm = is_t2_so_imm(TrueImm); if (isSoImm || TrueImm <= 0xffff) { - SDValue True = CurDAG->getTargetConstant(T->getZExtValue(), MVT::i32); + SDValue True = CurDAG->getTargetConstant(TrueImm, MVT::i32); SDValue CC = CurDAG->getTargetConstant(CCVal, MVT::i32); SDValue Ops[] = { FalseVal, True, CC, CCR, InFlag }; return CurDAG->SelectNodeTo(N, (isSoImm ? ARM::t2MOVCCi : ARM::t2MOVCCi16), MVT::i32, Ops, 5); + } else if (is_t2_so_imm_not(TrueImm)) { + SDValue True = CurDAG->getTargetConstant(TrueImm, MVT::i32); + SDValue CC = CurDAG->getTargetConstant(CCVal, MVT::i32); + SDValue Ops[] = { FalseVal, True, CC, CCR, InFlag }; + return CurDAG->SelectNodeTo(N, ARM::t2MVNCCi, MVT::i32, Ops, 5); } return 0; } @@ -1786,13 +1807,18 @@ SelectARMCMOVImmOp(SDNode *N, SDValue FalseVal, SDValue TrueVal, return 0; unsigned TrueImm = T->getZExtValue(); - bool isSoImm = Pred_so_imm(TrueVal.getNode()); + bool isSoImm = is_so_imm(TrueImm); if (isSoImm || (Subtarget->hasV6T2Ops() && TrueImm <= 0xffff)) { SDValue True = CurDAG->getTargetConstant(TrueImm, MVT::i32); SDValue CC = CurDAG->getTargetConstant(CCVal, MVT::i32); SDValue Ops[] = { FalseVal, True, CC, CCR, InFlag }; return CurDAG->SelectNodeTo(N, (isSoImm ? ARM::MOVCCi : ARM::MOVCCi16), MVT::i32, Ops, 5); + } else if (is_so_imm_not(TrueImm)) { + SDValue True = CurDAG->getTargetConstant(~TrueImm, MVT::i32); + SDValue CC = CurDAG->getTargetConstant(CCVal, MVT::i32); + SDValue Ops[] = { FalseVal, True, CC, CCR, InFlag }; + return CurDAG->SelectNodeTo(N, ARM::MVNCCi, MVT::i32, Ops, 5); } return 0; } diff --git a/lib/Target/ARM/ARMInstrInfo.td b/lib/Target/ARM/ARMInstrInfo.td index 6926bf0e72a..849bda8f0cf 100644 --- a/lib/Target/ARM/ARMInstrInfo.td +++ b/lib/Target/ARM/ARMInstrInfo.td @@ -212,12 +212,12 @@ def imm16_31 : PatLeaf<(i32 imm), [{ def so_imm_neg : PatLeaf<(imm), [{ - return ARM_AM::getSOImmVal(-(int)N->getZExtValue()) != -1; + return ARM_AM::getSOImmVal(-(uint32_t)N->getZExtValue()) != -1; }], so_imm_neg_XFORM>; def so_imm_not : PatLeaf<(imm), [{ - return ARM_AM::getSOImmVal(~(int)N->getZExtValue()) != -1; + return ARM_AM::getSOImmVal(~(uint32_t)N->getZExtValue()) != -1; }], so_imm_not_XFORM>; // sext_16_node predicate - True if the SDNode is sign-extended 16 or more bits. @@ -2875,6 +2875,7 @@ def BCCZi64 : PseudoInst<(outs), // the normal MOV instructions. That would fix the dependency on // special casing them in tblgen. let neverHasSideEffects = 1 in { +let isAsCheapAsAMove = 1 in def MOVCCr : AI1<0b1101, (outs GPR:$Rd), (ins GPR:$false, GPR:$Rm), DPFrm, IIC_iCMOVr, "mov", "\t$Rd, $Rm", [/*(set GPR:$Rd, (ARMcmov GPR:$false, GPR:$Rm, imm:$cc, CCR:$ccr))*/]>, @@ -2903,6 +2904,7 @@ def MOVCCs : AI1<0b1101, (outs GPR:$Rd), let Inst{11-0} = shift; } +let isAsCheapAsAMove = 1 in def MOVCCi16 : AI1<0b1000, (outs GPR:$Rd), (ins GPR:$false, i32imm:$imm), DPFrm, IIC_iMOVi, "movw", "\t$Rd, $imm", @@ -2918,6 +2920,7 @@ def MOVCCi16 : AI1<0b1000, (outs GPR:$Rd), (ins GPR:$false, i32imm:$imm), let Inst{11-0} = imm{11-0}; } +let isAsCheapAsAMove = 1 in def MOVCCi : AI1<0b1101, (outs GPR:$Rd), (ins GPR:$false, so_imm:$imm), DPFrm, IIC_iCMOVi, "mov", "\t$Rd, $imm", @@ -2931,6 +2934,21 @@ def MOVCCi : AI1<0b1101, (outs GPR:$Rd), let Inst{15-12} = Rd; let Inst{11-0} = imm; } + +let isAsCheapAsAMove = 1 in +def MVNCCi : AI1<0b1111, (outs GPR:$Rd), + (ins GPR:$false, so_imm:$imm), DPFrm, IIC_iCMOVi, + "mvn", "\t$Rd, $imm", + [/*(set GPR:$Rd, (ARMcmov GPR:$false, so_imm_not:$imm, imm:$cc, CCR:$ccr))*/]>, + RegConstraint<"$false = $Rd">, UnaryDP { + bits<4> Rd; + bits<12> imm; + let Inst{25} = 1; + let Inst{20} = 0; + let Inst{19-16} = 0b0000; + let Inst{15-12} = Rd; + let Inst{11-0} = imm; +} } // neverHasSideEffects //===----------------------------------------------------------------------===// diff --git a/lib/Target/ARM/ARMInstrThumb2.td b/lib/Target/ARM/ARMInstrThumb2.td index 3854b683184..66f2259dbf3 100644 --- a/lib/Target/ARM/ARMInstrThumb2.td +++ b/lib/Target/ARM/ARMInstrThumb2.td @@ -66,7 +66,7 @@ def t2_so_imm_not : Operand, // t2_so_imm_neg - Match an immediate that is a negation of a t2_so_imm. def t2_so_imm_neg : Operand, PatLeaf<(imm), [{ - return ARM_AM::getT2SOImmVal(-((int)N->getZExtValue())) != -1; + return ARM_AM::getT2SOImmVal(-((uint32_t)N->getZExtValue())) != -1; }], t2_so_imm_neg_XFORM>; // Break t2_so_imm's up into two pieces. This handles immediates with up to 16 @@ -2243,7 +2243,7 @@ defm t2TEQ : T2I_cmp_irs<0b0100, "teq", // Conditional moves // FIXME: should be able to write a pattern for ARMcmov, but can't use // a two-value operand where a dag node expects two operands. :( -let neverHasSideEffects = 1 in { +let neverHasSideEffects = 1, isAsCheapAsAMove = 1 in { def t2MOVCCr : T2I<(outs rGPR:$dst), (ins rGPR:$false, rGPR:$true), IIC_iCMOVr, "mov", ".w\t$dst, $true", [/*(set rGPR:$dst, (ARMcmov rGPR:$false, rGPR:$true, imm:$cc, CCR:$ccr))*/]>, @@ -2270,7 +2270,7 @@ def t2MOVCCi : T2I<(outs rGPR:$dst), (ins rGPR:$false, t2_so_imm:$true), } def t2MOVCCi16 : T2I<(outs rGPR:$dst), (ins rGPR:$false, i32imm:$src), - IIC_iMOVi, + IIC_iCMOVi, "movw", "\t$dst, $src", []>, RegConstraint<"$false = $dst"> { let Inst{31-27} = 0b11110; @@ -2280,6 +2280,19 @@ def t2MOVCCi16 : T2I<(outs rGPR:$dst), (ins rGPR:$false, i32imm:$src), let Inst{15} = 0; } +def t2MVNCCi : T2I<(outs rGPR:$dst), (ins rGPR:$false, t2_so_imm:$true), + IIC_iCMOVi, "mvn", ".w\t$dst, $true", +[/*(set rGPR:$dst,(ARMcmov rGPR:$false,t2_so_imm_not:$true, + imm:$cc, CCR:$ccr))*/]>, + RegConstraint<"$false = $dst"> { + let Inst{31-27} = 0b11110; + let Inst{25} = 0; + let Inst{24-21} = 0b0011; + let Inst{20} = 0; // The S bit. + let Inst{19-16} = 0b1111; // Rn + let Inst{15} = 0; +} + class T2I_movcc_sh opcod, dag oops, dag iops, InstrItinClass itin, string opc, string asm, list pattern> : T2I { diff --git a/test/CodeGen/ARM/select_xform.ll b/test/CodeGen/ARM/select_xform.ll index 7fd91ceea5a..21bc5fa8279 100644 --- a/test/CodeGen/ARM/select_xform.ll +++ b/test/CodeGen/ARM/select_xform.ll @@ -1,15 +1,59 @@ -; RUN: llc < %s -march=arm | grep mov | count 2 +; RUN: llc < %s -mtriple=arm-apple-darwin -mcpu=cortex-a8 | FileCheck %s -check-prefix=ARM +; RUN: llc < %s -mtriple=thumb-apple-darwin -mcpu=cortex-a8 | FileCheck %s -check-prefix=T2 +; rdar://8662825 define i32 @t1(i32 %a, i32 %b, i32 %c) nounwind { - %tmp1 = icmp sgt i32 %c, 10 - %tmp2 = select i1 %tmp1, i32 0, i32 2147483647 - %tmp3 = add i32 %tmp2, %b - ret i32 %tmp3 +; ARM: t1: +; ARM: sub r0, r1, #6, 2 +; ARM: movgt r0, r1 + +; T2: t1: +; T2: sub.w r0, r1, #-2147483648 +; T2: movgt r0, r1 + %tmp1 = icmp sgt i32 %c, 10 + %tmp2 = select i1 %tmp1, i32 0, i32 2147483647 + %tmp3 = add i32 %tmp2, %b + ret i32 %tmp3 } define i32 @t2(i32 %a, i32 %b, i32 %c, i32 %d) nounwind { - %tmp1 = icmp sgt i32 %c, 10 - %tmp2 = select i1 %tmp1, i32 0, i32 10 - %tmp3 = sub i32 %b, %tmp2 - ret i32 %tmp3 +; ARM: t2: +; ARM: sub r0, r1, #10 +; ARM: movgt r0, r1 + +; T2: t2: +; T2: sub.w r0, r1, #10 +; T2: movgt r0, r1 + %tmp1 = icmp sgt i32 %c, 10 + %tmp2 = select i1 %tmp1, i32 0, i32 10 + %tmp3 = sub i32 %b, %tmp2 + ret i32 %tmp3 +} + +define i32 @t3(i32 %a, i32 %b, i32 %x, i32 %y) nounwind { +; ARM: t3: +; ARM: mvnlt r2, #0 +; ARM: and r0, r2, r3 + +; T2: t3: +; T2: movlt.w r2, #-1 +; T2: and.w r0, r2, r3 + %cond = icmp slt i32 %a, %b + %z = select i1 %cond, i32 -1, i32 %x + %s = and i32 %z, %y + ret i32 %s +} + +define i32 @t4(i32 %a, i32 %b, i32 %x, i32 %y) nounwind { +; ARM: t4: +; ARM: movlt r2, #0 +; ARM: orr r0, r2, r3 + +; T2: t4: +; T2: movlt r2, #0 +; T2: orr.w r0, r2, r3 + %cond = icmp slt i32 %a, %b + %z = select i1 %cond, i32 0, i32 %x + %s = or i32 %z, %y + ret i32 %s }