Index: llvm/lib/Target/ARM/ARMISelLowering.h =================================================================== --- llvm/lib/Target/ARM/ARMISelLowering.h +++ llvm/lib/Target/ARM/ARMISelLowering.h @@ -514,6 +514,9 @@ const SelectionDAG &DAG, unsigned Depth) const override; + bool isMulAddWithConstProfitable(const SDValue &AddNode, + const SDValue &ConstNode) const override; + bool targetShrinkDemandedConstant(SDValue Op, const APInt &DemandedBits, const APInt &DemandedElts, TargetLoweringOpt &TLO) const override; Index: llvm/lib/Target/ARM/ARMISelLowering.cpp =================================================================== --- llvm/lib/Target/ARM/ARMISelLowering.cpp +++ llvm/lib/Target/ARM/ARMISelLowering.cpp @@ -18738,6 +18738,39 @@ return AbsImm >= 0 && AbsImm <= 255; } +// Return false to prevent folding +// (mul (add r, c0), c1) -> (add (mul r, c1), c0*c1) in DAGCombine, +// if the folding leads to worse code. +bool ARMTargetLowering::isMulAddWithConstProfitable( + const SDValue &AddNode, const SDValue &ConstNode) const { + // TODO: Implement this hook for thumb. + if (Subtarget->isThumb()) + return true; + + // Let the DAGCombiner decide for vector types and large types. + const EVT VT = AddNode.getValueType(); + if (VT.isVector() || VT.getScalarSizeInBits() > 32) + return true; + + // It is worse if c0 is legal add immediate, while c1*c0 is not, + // and has to be composed by at least two instructions. That means c0*c1 + // can not be obtained via a single MOV/MVN, and can not be + // obtained via a single MOVW (on ARMv6t2 and above). + const ConstantSDNode *C0Node = cast(AddNode.getOperand(1)); + const ConstantSDNode *C1Node = cast(ConstNode); + const int64_t C0 = C0Node->getSExtValue(); + const int64_t C1 = C1Node->getSExtValue(); + if (isLegalAddImmediate(C0) && !isLegalAddImmediate(C0 * C1) && + !isLegalAddImmediate(~std::abs(C0 * C1))) { + // TODO: Check for subtargets without movw/movt. + if (Subtarget->useMovt() && std::abs(C0 * C1) > 0xffff) + return false; + } + + // Default to true and let the DAGCombiner decide. + return true; +} + static bool getARMIndexedAddressParts(SDNode *Ptr, EVT VT, bool isSEXTLoad, SDValue &Base, SDValue &Offset, bool &isInc, Index: llvm/test/CodeGen/ARM/addimm-mulimm.ll =================================================================== --- llvm/test/CodeGen/ARM/addimm-mulimm.ll +++ llvm/test/CodeGen/ARM/addimm-mulimm.ll @@ -137,10 +137,9 @@ ; ; CHECK-7-LABEL: fold_addimm_mulimm_i: ; CHECK-7: @ %bb.0: -; CHECK-7-NEXT: movw r1, #23067 -; CHECK-7-NEXT: movw r2, #353 -; CHECK-7-NEXT: movt r1, #1 -; CHECK-7-NEXT: mla r0, r0, r2, r1 +; CHECK-7-NEXT: add r0, r0, #251 +; CHECK-7-NEXT: movw r1, #353 +; CHECK-7-NEXT: mul r0, r0, r1 ; CHECK-7-NEXT: bx lr %b = add i32 %a, 251 %c = mul i32 %b, 353 @@ -162,10 +161,9 @@ ; ; CHECK-7-LABEL: fold_addimm_mulimm_j: ; CHECK-7: @ %bb.0: -; CHECK-7-NEXT: movw r1, #42469 -; CHECK-7-NEXT: movw r2, #353 -; CHECK-7-NEXT: movt r1, #65534 -; CHECK-7-NEXT: mla r0, r0, r2, r1 +; CHECK-7-NEXT: sub r0, r0, #251 +; CHECK-7-NEXT: movw r1, #353 +; CHECK-7-NEXT: mul r0, r0, r1 ; CHECK-7-NEXT: bx lr %b = add i32 %a, -251 %c = mul i32 %b, 353