llvm.org GIT mirror llvm / 43a6c5e
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 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! git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@112664 91177308-0d34-0410-b5e6-96231b3b80d8 Bill Wendling 10 years ago
5 changed file(s) with 142 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
179179 SDNode *SelectARMCMOVSoImmOp(SDNode *N, SDValue FalseVal, SDValue TrueVal,
180180 ARMCC::CondCodes CCVal, SDValue CCR,
181181 SDValue InFlag);
182 SDNode *OptimizeCMOVSoImmOp(SDNode *N, SDValue FalseVal, SDValue TrueVal,
183 ARMCC::CondCodes CCVal, SDValue CCR,
184 SDValue InFlag, bool IsThumb2);
182185
183186 SDNode *SelectConcatVector(SDNode *N);
184187
16401643 return 0;
16411644 }
16421645
1646 /// OptimizeCMOVSoImmOp - It's possible to save an instruction or two be
1647 /// recognizing that the TST and AND instructions perform the same function
1648 /// (they "and" the two values). See inside for more details.
1649 SDNode *ARMDAGToDAGISel::
1650 OptimizeCMOVSoImmOp(SDNode *N, SDValue FalseVal, SDValue TrueVal,
1651 ARMCC::CondCodes CCVal, SDValue CCR, SDValue InFlag,
1652 bool IsThumb2) {
1653 // Convert:
1654 //
1655 // tst.w r0, #256
1656 // mvn r0, #25
1657 // it eq
1658 // moveq r0, #0
1659 //
1660 // into:
1661 //
1662 // ands.w r0, r0, #256
1663 // it ne
1664 // mvnne.w r0, #25
1665 //
1666 if (InFlag.getOpcode() != ARMISD::CMPZ ||
1667 InFlag.getOperand(0).getOpcode() != ISD::AND)
1668 return 0;
1669
1670 // The true value needs to be zero, as that's the result of the AND
1671 // instruction.
1672 ConstantSDNode *True = dyn_cast(TrueVal);
1673 if (!True || True->getZExtValue() != 0)
1674 return 0;
1675
1676 // Bail if the false value isn't an immediate.
1677 ConstantSDNode *False = dyn_cast(FalseVal);
1678 if (!False)
1679 return 0;
1680
1681 bool UseMVN = false;
1682 if ((IsThumb2 && !Pred_t2_so_imm(FalseVal.getNode())) ||
1683 (!IsThumb2 && !Pred_so_imm(FalseVal.getNode()))) {
1684 // The false value isn't a proper immediate. Check to see if we can use the
1685 // bitwise NOT version.
1686 if ((IsThumb2 && ARM_AM::getT2SOImmVal(~False->getZExtValue()) != -1) ||
1687 (!IsThumb2 && ARM_AM::getSOImmVal(~False->getZExtValue()) != -1)) {
1688 UseMVN = true;
1689 FalseVal = CurDAG->getTargetConstant(~False->getZExtValue(), MVT::i32);
1690 } else {
1691 return 0;
1692 }
1693 } else {
1694 FalseVal = CurDAG->getTargetConstant(False->getZExtValue(), MVT::i32);
1695 }
1696
1697 // A comparison against zero corresponds with the flag AND sets if the result
1698 // is zero.
1699 ConstantSDNode *CmpVal = dyn_cast(InFlag.getOperand(1));
1700 if (!CmpVal || CmpVal->getZExtValue() != 0)
1701 return 0;
1702
1703 ARMCC::CondCodes NegCC = ARMCC::getOppositeCondition(CCVal);
1704 SDValue OrigAnd = InFlag.getOperand(0);
1705 SDValue NewAnd =
1706 CurDAG->getNode(ARMISD::AND, N->getDebugLoc(),
1707 CurDAG->getVTList(OrigAnd.getValueType(), MVT::Flag),
1708 OrigAnd->getOperand(0), OrigAnd->getOperand(1));
1709
1710 unsigned Opcode = !UseMVN ?
1711 (IsThumb2 ? ARM::t2MOVCCi : ARM::MOVCCi) :
1712 (IsThumb2 ? ARM::t2MVNCCi : ARM::MVNCCi);
1713
1714 SDValue Ops[] = {
1715 NewAnd.getValue(0),
1716 FalseVal,
1717 CurDAG->getTargetConstant(NegCC, MVT::i32),
1718 CCR, NewAnd.getValue(1)
1719 };
1720 SDNode *ResNode = CurDAG->SelectNodeTo(N, Opcode, MVT::i32, Ops, 5);
1721
1722 // Manually run "Select" on the newly created "ARMISD::AND" node to make
1723 // sure that it's converted properly.
1724 SDNode *AndNode = Select(NewAnd.getNode());
1725 if (AndNode && NewAnd.getNode() != AndNode &&
1726 NewAnd.getNode()->getOpcode() != ISD::DELETED_NODE)
1727 ReplaceUses(NewAnd.getNode(), AndNode);
1728
1729 return ResNode;
1730 }
1731
16431732 SDNode *ARMDAGToDAGISel::
16441733 SelectT2CMOVSoImmOp(SDNode *N, SDValue FalseVal, SDValue TrueVal,
16451734 ARMCC::CondCodes CCVal, SDValue CCR, SDValue InFlag) {
16481737 return 0;
16491738
16501739 if (Pred_t2_so_imm(TrueVal.getNode())) {
1740 SDNode *ResNode = OptimizeCMOVSoImmOp(N, FalseVal, TrueVal, CCVal, CCR,
1741 InFlag, true);
1742 if (ResNode) return ResNode;
1743
16511744 SDValue True = CurDAG->getTargetConstant(T->getZExtValue(), MVT::i32);
16521745 SDValue CC = CurDAG->getTargetConstant(CCVal, MVT::i32);
16531746 SDValue Ops[] = { FalseVal, True, CC, CCR, InFlag };
16651758 return 0;
16661759
16671760 if (Pred_so_imm(TrueVal.getNode())) {
1761 SDNode *ResNode = OptimizeCMOVSoImmOp(N, FalseVal, TrueVal, CCVal, CCR,
1762 InFlag, false);
1763 if (ResNode) return ResNode;
1764
16681765 SDValue True = CurDAG->getTargetConstant(T->getZExtValue(), MVT::i32);
16691766 SDValue CC = CurDAG->getTargetConstant(CCVal, MVT::i32);
16701767 SDValue Ops[] = { FalseVal, True, CC, CCR, InFlag };
24172417 [/*(set GPR:$dst, (ARMcmov GPR:$false, so_imm:$true, imm:$cc, CCR:$ccr))*/]>,
24182418 RegConstraint<"$false = $dst">, UnaryDP {
24192419 let Inst{25} = 1;
2420 }
2421
2422 def MVNCCi : AI1<0b1111, (outs GPR:$dst),
2423 (ins GPR:$false, so_imm:$true), DPFrm, IIC_iCMOVi,
2424 "mvn", "\t$dst, $true",
2425 [/*(set GPR:$dst, (ARMcmov GPR:$false,so_imm_not:$true,imm:$cc,CCR:$ccr))*/]>,
2426 RegConstraint<"$false = $dst">, UnaryDP {
2427 let Inst{25} = 0;
24202428 }
24212429 } // neverHasSideEffects
24222430
21892189 let Inst{31-27} = 0b11110;
21902190 let Inst{25} = 0;
21912191 let Inst{24-21} = 0b0010;
2192 let Inst{20} = 0; // The S bit.
2193 let Inst{19-16} = 0b1111; // Rn
2194 let Inst{15} = 0;
2195 }
2196
2197 def t2MVNCCi : T2I<(outs rGPR:$dst), (ins rGPR:$false, t2_so_imm:$true),
2198 IIC_iCMOVi, "mvn", ".w\t$dst, $true",
2199 [/*(set rGPR:$dst,(ARMcmov rGPR:$false,t2_so_imm_not:$true,imm:$cc,CCR:$ccr))*/]>,
2200 RegConstraint<"$false = $dst"> {
2201 let Inst{31-27} = 0b11110;
2202 let Inst{25} = 0;
2203 let Inst{24-21} = 0b0011;
21922204 let Inst{20} = 0; // The S bit.
21932205 let Inst{19-16} = 0b1111; // Rn
21942206 let Inst{15} = 0;
0 ; RUN: llc < %s -mtriple=arm-apple-darwin | FileCheck %s
1
2 define i32 @f1(i32 %t) nounwind {
3 ; CHECK: f1
4 ; CHECK-NOT: tst
5 ; CHECK: and
6 ; CHECK: mvnne
7 %and = and i32 %t, 256
8 %tobool = icmp eq i32 %and, 0
9 %retval.0 = select i1 %tobool, i32 0, i32 -26
10 ret i32 %retval.0
11 }
0 ; RUN: llc < %s -mtriple=thumbv7-apple-darwin | FileCheck %s
1
2 define i32 @f1(i32 %t) nounwind {
3 ; CHECK: f1
4 ; CHECK-NOT: tst
5 ; CHECK: ands
6 ; CHECK: it ne
7 ; CHECK: mvnne
8 %and = and i32 %t, 256
9 %tobool = icmp eq i32 %and, 0
10 %retval.0 = select i1 %tobool, i32 0, i32 -26
11 ret i32 %retval.0
12 }