[llvm-commits] [llvm] r112664 - in /llvm/trunk: lib/Target/ARM/ARMISelDAGToDAG.cpp lib/Target/ARM/ARMInstrInfo.td lib/Target/ARM/ARMInstrThumb2.td test/CodeGen/ARM/mvncc.ll test/CodeGen/Thumb2/thumb2-mvncc.ll
Evan Cheng
evan.cheng at apple.com
Tue Sep 7 23:02:44 PDT 2010
Hi Bill,
Thanks for doing this but I have some questions.
On Aug 31, 2010, at 3:41 PM, Bill Wendling <isanbard at gmail.com> wrote:
> Author: void
> Date: Tue Aug 31 17:41:22 2010
> New Revision: 112664
>
> URL: http://llvm.org/viewvc/llvm-project?rev=112664&view=rev
> Log:
> We have a chance for an optimization. Consider this code:
>
> int x(int t) {
> if (t & 256)
> return -26;
> return 0;
> }
>
> We generate this:
>
> tst.w r0, #256
> mvn r0, #25
> it eq
> moveq r0, #0
>
> while gcc generates this:
>
> ands r0, r0, #256
> it ne
> mvnne r0, #25
> bx lr
Is it possible to generate the "and" and comparison at isel time and let the peephole pass get rid of the compare later? I'd prefer to avoid having these instructions like ARM::ANDS.
Evan
>
> Scandalous really!
>
> During ISel time, we can look for this particular pattern. One where we have a
> "MOVCC" that uses the flag off of a CMPZ that itself is comparing an AND
> instruction to 0. Something like this (greatly simplified):
>
> %r0 = ISD::AND ...
> ARMISD::CMPZ %r0, 0 @ sets [CPSR]
> %r0 = ARMISD::MOVCC 0, -26 @ reads [CPSR]
>
> All we have to do is convert the "ISD::AND" into an "ARM::ANDS" that sets [CPSR]
> when it's zero. The zero value will all ready be in the %r0 register and we only
> need to change it if the AND wasn't zero. Easy!
>
> Added:
> llvm/trunk/test/CodeGen/ARM/mvncc.ll
> llvm/trunk/test/CodeGen/Thumb2/thumb2-mvncc.ll
> Modified:
> llvm/trunk/lib/Target/ARM/ARMISelDAGToDAG.cpp
> llvm/trunk/lib/Target/ARM/ARMInstrInfo.td
> llvm/trunk/lib/Target/ARM/ARMInstrThumb2.td
>
> Modified: llvm/trunk/lib/Target/ARM/ARMISelDAGToDAG.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMISelDAGToDAG.cpp?rev=112664&r1=112663&r2=112664&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Target/ARM/ARMISelDAGToDAG.cpp (original)
> +++ llvm/trunk/lib/Target/ARM/ARMISelDAGToDAG.cpp Tue Aug 31 17:41:22 2010
> @@ -180,6 +180,9 @@
> SDNode *SelectARMCMOVSoImmOp(SDNode *N, SDValue FalseVal, SDValue TrueVal,
> ARMCC::CondCodes CCVal, SDValue CCR,
> SDValue InFlag);
> + SDNode *OptimizeCMOVSoImmOp(SDNode *N, SDValue FalseVal, SDValue TrueVal,
> + ARMCC::CondCodes CCVal, SDValue CCR,
> + SDValue InFlag, bool IsThumb2);
>
> SDNode *SelectConcatVector(SDNode *N);
>
> @@ -1641,6 +1644,92 @@
> return 0;
> }
>
> +/// OptimizeCMOVSoImmOp - It's possible to save an instruction or two be
> +/// recognizing that the TST and AND instructions perform the same function
> +/// (they "and" the two values). See inside for more details.
> +SDNode *ARMDAGToDAGISel::
> +OptimizeCMOVSoImmOp(SDNode *N, SDValue FalseVal, SDValue TrueVal,
> + ARMCC::CondCodes CCVal, SDValue CCR, SDValue InFlag,
> + bool IsThumb2) {
> + // Convert:
> + //
> + // tst.w r0, #256
> + // mvn r0, #25
> + // it eq
> + // moveq r0, #0
> + //
> + // into:
> + //
> + // ands.w r0, r0, #256
> + // it ne
> + // mvnne.w r0, #25
> + //
> + if (InFlag.getOpcode() != ARMISD::CMPZ ||
> + InFlag.getOperand(0).getOpcode() != ISD::AND)
> + return 0;
> +
> + // The true value needs to be zero, as that's the result of the AND
> + // instruction.
> + ConstantSDNode *True = dyn_cast<ConstantSDNode>(TrueVal);
> + if (!True || True->getZExtValue() != 0)
> + return 0;
> +
> + // Bail if the false value isn't an immediate.
> + ConstantSDNode *False = dyn_cast<ConstantSDNode>(FalseVal);
> + if (!False)
> + return 0;
> +
> + bool UseMVN = false;
> + if ((IsThumb2 && !Pred_t2_so_imm(FalseVal.getNode())) ||
> + (!IsThumb2 && !Pred_so_imm(FalseVal.getNode()))) {
> + // The false value isn't a proper immediate. Check to see if we can use the
> + // bitwise NOT version.
> + if ((IsThumb2 && ARM_AM::getT2SOImmVal(~False->getZExtValue()) != -1) ||
> + (!IsThumb2 && ARM_AM::getSOImmVal(~False->getZExtValue()) != -1)) {
> + UseMVN = true;
> + FalseVal = CurDAG->getTargetConstant(~False->getZExtValue(), MVT::i32);
> + } else {
> + return 0;
> + }
> + } else {
> + FalseVal = CurDAG->getTargetConstant(False->getZExtValue(), MVT::i32);
> + }
> +
> + // A comparison against zero corresponds with the flag AND sets if the result
> + // is zero.
> + ConstantSDNode *CmpVal = dyn_cast<ConstantSDNode>(InFlag.getOperand(1));
> + if (!CmpVal || CmpVal->getZExtValue() != 0)
> + return 0;
> +
> + ARMCC::CondCodes NegCC = ARMCC::getOppositeCondition(CCVal);
> + SDValue OrigAnd = InFlag.getOperand(0);
> + SDValue NewAnd =
> + CurDAG->getNode(ARMISD::AND, N->getDebugLoc(),
> + CurDAG->getVTList(OrigAnd.getValueType(), MVT::Flag),
> + OrigAnd->getOperand(0), OrigAnd->getOperand(1));
> +
> + unsigned Opcode = !UseMVN ?
> + (IsThumb2 ? ARM::t2MOVCCi : ARM::MOVCCi) :
> + (IsThumb2 ? ARM::t2MVNCCi : ARM::MVNCCi);
> +
> + SDValue Ops[] = {
> + NewAnd.getValue(0),
> + FalseVal,
> + CurDAG->getTargetConstant(NegCC, MVT::i32),
> + CCR, NewAnd.getValue(1)
> + };
> + SDNode *ResNode = CurDAG->SelectNodeTo(N, Opcode, MVT::i32, Ops, 5);
> +
> + // Manually run "Select" on the newly created "ARMISD::AND" node to make
> + // sure that it's converted properly.
> + SDNode *AndNode = Select(NewAnd.getNode());
> + if (AndNode && NewAnd.getNode() != AndNode &&
> + NewAnd.getNode()->getOpcode() != ISD::DELETED_NODE)
> + ReplaceUses(NewAnd.getNode(), AndNode);
> +
> + return ResNode;
> +}
> +
> SDNode *ARMDAGToDAGISel::
> SelectT2CMOVSoImmOp(SDNode *N, SDValue FalseVal, SDValue TrueVal,
> ARMCC::CondCodes CCVal, SDValue CCR, SDValue InFlag) {
> @@ -1649,6 +1738,10 @@
> return 0;
>
> if (Pred_t2_so_imm(TrueVal.getNode())) {
> + SDNode *ResNode = OptimizeCMOVSoImmOp(N, FalseVal, TrueVal, CCVal, CCR,
> + InFlag, true);
> + if (ResNode) return ResNode;
> +
> SDValue True = CurDAG->getTargetConstant(T->getZExtValue(), MVT::i32);
> SDValue CC = CurDAG->getTargetConstant(CCVal, MVT::i32);
> SDValue Ops[] = { FalseVal, True, CC, CCR, InFlag };
> @@ -1666,6 +1759,10 @@
> return 0;
>
> if (Pred_so_imm(TrueVal.getNode())) {
> + SDNode *ResNode = OptimizeCMOVSoImmOp(N, FalseVal, TrueVal, CCVal, CCR,
> + InFlag, false);
> + if (ResNode) return ResNode;
> +
> SDValue True = CurDAG->getTargetConstant(T->getZExtValue(), MVT::i32);
> SDValue CC = CurDAG->getTargetConstant(CCVal, MVT::i32);
> SDValue Ops[] = { FalseVal, True, CC, CCR, InFlag };
>
> Modified: llvm/trunk/lib/Target/ARM/ARMInstrInfo.td
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstrInfo.td?rev=112664&r1=112663&r2=112664&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Target/ARM/ARMInstrInfo.td (original)
> +++ llvm/trunk/lib/Target/ARM/ARMInstrInfo.td Tue Aug 31 17:41:22 2010
> @@ -2419,6 +2419,14 @@
> RegConstraint<"$false = $dst">, UnaryDP {
> let Inst{25} = 1;
> }
> +
> +def MVNCCi : AI1<0b1111, (outs GPR:$dst),
> + (ins GPR:$false, so_imm:$true), DPFrm, IIC_iCMOVi,
> + "mvn", "\t$dst, $true",
> + [/*(set GPR:$dst, (ARMcmov GPR:$false,so_imm_not:$true,imm:$cc,CCR:$ccr))*/]>,
> + RegConstraint<"$false = $dst">, UnaryDP {
> + let Inst{25} = 0;
> +}
> } // neverHasSideEffects
>
> //===----------------------------------------------------------------------===//
>
> Modified: llvm/trunk/lib/Target/ARM/ARMInstrThumb2.td
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstrThumb2.td?rev=112664&r1=112663&r2=112664&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Target/ARM/ARMInstrThumb2.td (original)
> +++ llvm/trunk/lib/Target/ARM/ARMInstrThumb2.td Tue Aug 31 17:41:22 2010
> @@ -2195,6 +2195,18 @@
> 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<bits<2> opcod, dag oops, dag iops, InstrItinClass itin,
> string opc, string asm, list<dag> pattern>
> : T2I<oops, iops, itin, opc, asm, pattern> {
>
> Added: llvm/trunk/test/CodeGen/ARM/mvncc.ll
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/mvncc.ll?rev=112664&view=auto
> ==============================================================================
> --- llvm/trunk/test/CodeGen/ARM/mvncc.ll (added)
> +++ llvm/trunk/test/CodeGen/ARM/mvncc.ll Tue Aug 31 17:41:22 2010
> @@ -0,0 +1,12 @@
> +; RUN: llc < %s -mtriple=arm-apple-darwin | FileCheck %s
> +
> +define i32 @f1(i32 %t) nounwind {
> +; CHECK: f1
> +; CHECK-NOT: tst
> +; CHECK: and
> +; CHECK: mvnne
> + %and = and i32 %t, 256
> + %tobool = icmp eq i32 %and, 0
> + %retval.0 = select i1 %tobool, i32 0, i32 -26
> + ret i32 %retval.0
> +}
>
> Added: llvm/trunk/test/CodeGen/Thumb2/thumb2-mvncc.ll
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/thumb2-mvncc.ll?rev=112664&view=auto
> ==============================================================================
> --- llvm/trunk/test/CodeGen/Thumb2/thumb2-mvncc.ll (added)
> +++ llvm/trunk/test/CodeGen/Thumb2/thumb2-mvncc.ll Tue Aug 31 17:41:22 2010
> @@ -0,0 +1,13 @@
> +; RUN: llc < %s -mtriple=thumbv7-apple-darwin | FileCheck %s
> +
> +define i32 @f1(i32 %t) nounwind {
> +; CHECK: f1
> +; CHECK-NOT: tst
> +; CHECK: ands
> +; CHECK: it ne
> +; CHECK: mvnne
> + %and = and i32 %t, 256
> + %tobool = icmp eq i32 %and, 0
> + %retval.0 = select i1 %tobool, i32 0, i32 -26
> + ret i32 %retval.0
> +}
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
More information about the llvm-commits
mailing list