[llvm] Multiplication swap (PR #195494)
via llvm-commits
llvm-commits at lists.llvm.org
Sat May 2 17:38:40 PDT 2026
https://github.com/LumioseSil created https://github.com/llvm/llvm-project/pull/195494
None
>From 4bbcfb456b6370f17c006fd589d80d8eca8e5900 Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
Date: Thu, 30 Apr 2026 21:56:54 -0400
Subject: [PATCH 1/6] [ARM] Have SelectionDAG optimize muls, not ISelDAGtoDAG
I had to swap so shifts would be on the right side for better folding.
Made that change in AArch64 too for parity.
---
.../Target/AArch64/AArch64ISelLowering.cpp | 20 +-
llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp | 46 ---
llvm/lib/Target/ARM/ARMISelLowering.cpp | 269 +++++++++++++-----
llvm/test/CodeGen/AArch64/load-insert-zero.ll | 4 +-
.../AArch64/sme2-intrinsics-int-dots.ll | 28 +-
.../CodeGen/AArch64/sme2-intrinsics-vdot.ll | 16 +-
.../ARM/2013-05-07-ByteLoadSameAddress.ll | 2 +-
llvm/test/CodeGen/ARM/addimm-mulimm.ll | 224 +++++++++------
llvm/test/CodeGen/ARM/funnel-shift.ll | 20 +-
llvm/test/CodeGen/ARM/memset-inline.ll | 189 +++++++++---
llvm/test/CodeGen/ARM/mul_const.ll | 8 +-
llvm/test/CodeGen/ARM/popcnt.ll | 59 ++--
llvm/test/CodeGen/ARM/select-imm.ll | 17 +-
.../CodeGen/ARM/srem-seteq-illegal-types.ll | 26 +-
.../CodeGen/ARM/urem-seteq-illegal-types.ll | 26 +-
.../Thumb2/mve-gather-scatter-optimisation.ll | 48 ++--
llvm/test/CodeGen/Thumb2/mve-memtp-branch.ll | 27 +-
llvm/test/CodeGen/Thumb2/mve-postinc-dct.ll | 110 +++----
.../Thumb2/urem-seteq-illegal-types.ll | 4 +-
19 files changed, 700 insertions(+), 443 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index e3c12b9ebd3ed..b80ce556c0cac 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -20520,13 +20520,13 @@ static SDValue performMulCombine(SDNode *N, SelectionDAG &DAG,
};
if (ConstValue.isNonNegative()) {
- // (mul x, (2^N + 1) * 2^M) => (shl (add (shl x, N), x), M)
+ // (mul x, (2^N + 1) * 2^M) => (shl (add x, (shl x, N)), M)
// (mul x, 2^N - 1) => (sub (shl x, N), x)
// (mul x, (2^(N-M) - 1) * 2^M) => (sub (shl x, N), (shl x, M))
// (mul x, (2^M + 1) * (2^N + 1))
- // => MV = (add (shl x, M), x); (add (shl MV, N), MV)
+ // => MV = (add x, (shl x, M)); (add MV, (shl MV, N))
// (mul x, (2^M + 1) * 2^N + 1))
- // => MV = add (shl x, M), x); add (shl MV, N), x)
+ // => MV = (add x, (shl x, M)); (add x, (shl MV, N)))
// (mul x, 1 - (1 - 2^M) * 2^N))
// => MV = sub (x - (shl x, M)); sub (x - (shl MV, N))
APInt SCVMinus1 = ShiftedConstValue - 1;
@@ -20535,7 +20535,7 @@ static SDValue performMulCombine(SDNode *N, SelectionDAG &DAG,
APInt CVM, CVN;
if (SCVMinus1.isPowerOf2()) {
ShiftAmt = SCVMinus1.logBase2();
- return Shl(Add(Shl(N0, ShiftAmt), N0), TrailingZeroes);
+ return Shl(Add(N0, Shl(N0, ShiftAmt)), TrailingZeroes);
} else if (CVPlus1.isPowerOf2()) {
ShiftAmt = CVPlus1.logBase2();
return Sub(Shl(N0, ShiftAmt), N0);
@@ -20551,8 +20551,8 @@ static SDValue performMulCombine(SDNode *N, SelectionDAG &DAG,
unsigned ShiftN1 = CVNMinus1.logBase2();
// ALULSLFast implicate that Shifts <= 4 places are fast
if (ShiftM1 <= 4 && ShiftN1 <= 4) {
- SDValue MVal = Add(Shl(N0, ShiftM1), N0);
- return Add(Shl(MVal, ShiftN1), MVal);
+ SDValue MVal = Add(N0, Shl(N0, ShiftM1));
+ return Add(MVal, Shl(MVal, ShiftN1));
}
}
if (Subtarget->hasALULSLFast() &&
@@ -20561,8 +20561,8 @@ static SDValue performMulCombine(SDNode *N, SelectionDAG &DAG,
unsigned ShiftN = CVN.getZExtValue();
// ALULSLFast implicate that Shifts <= 4 places are fast
if (ShiftM <= 4 && ShiftN <= 4) {
- SDValue MVal = Add(Shl(N0, CVM.getZExtValue()), N0);
- return Add(Shl(MVal, CVN.getZExtValue()), N0);
+ SDValue MVal = Add(N0, Shl(N0, CVM.getZExtValue()));
+ return Add(N0, Shl(MVal, CVN.getZExtValue()));
}
}
@@ -20578,7 +20578,7 @@ static SDValue performMulCombine(SDNode *N, SelectionDAG &DAG,
}
} else {
// (mul x, -(2^N - 1)) => (sub x, (shl x, N))
- // (mul x, -(2^N + 1)) => - (add (shl x, N), x)
+ // (mul x, -(2^N + 1)) => - (add x, (shl x, N)))
// (mul x, -(2^(N-M) - 1) * 2^M) => (sub (shl x, M), (shl x, N))
APInt SCVPlus1 = -ShiftedConstValue + 1;
APInt CVNegPlus1 = -ConstValue + 1;
@@ -20588,7 +20588,7 @@ static SDValue performMulCombine(SDNode *N, SelectionDAG &DAG,
return Sub(N0, Shl(N0, ShiftAmt));
} else if (CVNegMinus1.isPowerOf2()) {
ShiftAmt = CVNegMinus1.logBase2();
- return Negate(Add(Shl(N0, ShiftAmt), N0));
+ return Negate(Add(N0, Shl(N0, ShiftAmt)));
} else if (SCVPlus1.isPowerOf2()) {
ShiftAmt = SCVPlus1.logBase2() + TrailingZeroes;
return Sub(Shl(N0, TrailingZeroes), Shl(N0, ShiftAmt));
diff --git a/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp b/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp
index 61b679d55fb47..6d8a0276354cd 100644
--- a/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp
+++ b/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp
@@ -3839,52 +3839,6 @@ void ARMDAGToDAGISel::Select(SDNode *N) {
if (tryFMULFixed(N, dl))
return;
break;
- case ISD::MUL:
- if (Subtarget->isThumb1Only())
- break;
- if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(N->getOperand(1))) {
- unsigned RHSV = C->getZExtValue();
- if (!RHSV) break;
- if (isPowerOf2_32(RHSV-1)) { // 2^n+1?
- unsigned ShImm = Log2_32(RHSV-1);
- if (ShImm >= 32)
- break;
- SDValue V = N->getOperand(0);
- ShImm = ARM_AM::getSORegOpc(ARM_AM::lsl, ShImm);
- SDValue ShImmOp = CurDAG->getTargetConstant(ShImm, dl, MVT::i32);
- SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
- if (Subtarget->isThumb()) {
- SDValue Ops[] = { V, V, ShImmOp, getAL(CurDAG, dl), Reg0, Reg0 };
- CurDAG->SelectNodeTo(N, ARM::t2ADDrs, MVT::i32, Ops);
- return;
- } else {
- SDValue Ops[] = { V, V, Reg0, ShImmOp, getAL(CurDAG, dl), Reg0,
- Reg0 };
- CurDAG->SelectNodeTo(N, ARM::ADDrsi, MVT::i32, Ops);
- return;
- }
- }
- if (isPowerOf2_32(RHSV+1)) { // 2^n-1?
- unsigned ShImm = Log2_32(RHSV+1);
- if (ShImm >= 32)
- break;
- SDValue V = N->getOperand(0);
- ShImm = ARM_AM::getSORegOpc(ARM_AM::lsl, ShImm);
- SDValue ShImmOp = CurDAG->getTargetConstant(ShImm, dl, MVT::i32);
- SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
- if (Subtarget->isThumb()) {
- SDValue Ops[] = { V, V, ShImmOp, getAL(CurDAG, dl), Reg0, Reg0 };
- CurDAG->SelectNodeTo(N, ARM::t2RSBrs, MVT::i32, Ops);
- return;
- } else {
- SDValue Ops[] = { V, V, Reg0, ShImmOp, getAL(CurDAG, dl), Reg0,
- Reg0 };
- CurDAG->SelectNodeTo(N, ARM::RSBrsi, MVT::i32, Ops);
- return;
- }
- }
- }
- break;
case ISD::AND: {
// Check for unsigned bitfield extract
if (tryV6T2BitfieldExtractOp(N, false))
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp
index cbff40f697b9b..6524f3f2d7a84 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp
@@ -14071,7 +14071,10 @@ static SDValue PerformSUBCombine(SDNode *N,
static SDValue PerformVMULCombine(SDNode *N,
TargetLowering::DAGCombinerInfo &DCI,
const ARMSubtarget *Subtarget) {
- if (!Subtarget->hasVMLxForwarding())
+
+ EVT VT = N->getValueType(0);
+ if (!Subtarget->hasVMLxForwarding() ||
+ (!VT.is64BitVector() && !VT.is128BitVector()))
return SDValue();
SelectionDAG &DAG = DCI.DAG;
@@ -14090,7 +14093,6 @@ static SDValue PerformVMULCombine(SDNode *N,
if (N0 == N1)
return SDValue();
- EVT VT = N->getValueType(0);
SDLoc DL(N);
SDValue N00 = N0->getOperand(0);
SDValue N01 = N0->getOperand(1);
@@ -14102,7 +14104,7 @@ static SDValue PerformVMULCombine(SDNode *N,
static SDValue PerformMVEVMULLCombine(SDNode *N, SelectionDAG &DAG,
const ARMSubtarget *Subtarget) {
EVT VT = N->getValueType(0);
- if (VT != MVT::v2i64)
+ if (!Subtarget->hasMVEIntegerOps() || VT != MVT::v2i64)
return SDValue();
SDValue N0 = N->getOperand(0);
@@ -14164,14 +14166,12 @@ static SDValue PerformMVEVMULLCombine(SDNode *N, SelectionDAG &DAG,
return SDValue();
}
-static SDValue PerformMULCombine(SDNode *N,
+static SDValue PerformMULCombine(SDNode *N, SelectionDAG &DAG,
TargetLowering::DAGCombinerInfo &DCI,
const ARMSubtarget *Subtarget) {
- SelectionDAG &DAG = DCI.DAG;
- EVT VT = N->getValueType(0);
- if (Subtarget->hasMVEIntegerOps() && VT == MVT::v2i64)
- return PerformMVEVMULLCombine(N, DAG, Subtarget);
+ if (SDValue Val = PerformMVEVMULLCombine(N, DAG, Subtarget))
+ return Val;
if (Subtarget->isThumb1Only())
return SDValue();
@@ -14179,74 +14179,208 @@ static SDValue PerformMULCombine(SDNode *N,
if (DCI.isBeforeLegalize() || DCI.isCalledByLegalizer())
return SDValue();
- if (VT.is64BitVector() || VT.is128BitVector())
- return PerformVMULCombine(N, DCI, Subtarget);
- if (VT != MVT::i32)
- return SDValue();
+ if (SDValue Val = PerformVMULCombine(N, DCI, Subtarget))
+ return Val;
- ConstantSDNode *C = dyn_cast<ConstantSDNode>(N->getOperand(1));
+ SDLoc DL(N);
+ EVT VT = N->getValueType(0);
+ SDValue N0 = N->getOperand(0);
+ SDValue N1 = N->getOperand(1);
+ SDValue MulOper;
+ unsigned AddSubOpc;
+
+ if (!Subtarget->isThumb()) {
+ auto IsAddSubWith1 = [&](SDValue V) -> bool {
+ AddSubOpc = V->getOpcode();
+ if ((AddSubOpc == ISD::ADD || AddSubOpc == ISD::SUB) && V->hasOneUse()) {
+ SDValue Opnd = V->getOperand(1);
+ MulOper = V->getOperand(0);
+ if (AddSubOpc == ISD::SUB)
+ std::swap(Opnd, MulOper);
+ if (auto C = dyn_cast<ConstantSDNode>(Opnd))
+ return C->isOne();
+ }
+ return false;
+ };
+
+ if (IsAddSubWith1(N0)) {
+ SDValue MulVal = DAG.getNode(ISD::MUL, DL, VT, N1, MulOper);
+ return DAG.getNode(AddSubOpc, DL, VT, N1, MulVal);
+ }
+
+ if (IsAddSubWith1(N1)) {
+ SDValue MulVal = DAG.getNode(ISD::MUL, DL, VT, N0, MulOper);
+ return DAG.getNode(AddSubOpc, DL, VT, N0, MulVal);
+ }
+ }
+
+ // The below optimizations require a constant RHS.
+ ConstantSDNode *C = dyn_cast<ConstantSDNode>(N1);
if (!C)
return SDValue();
- int64_t MulAmt = C->getSExtValue();
- unsigned ShiftAmt = llvm::countr_zero<uint64_t>(MulAmt);
-
- ShiftAmt = ShiftAmt & (32 - 1);
- SDValue V = N->getOperand(0);
- SDLoc DL(N);
+ const APInt &ConstValue = C->getAPIntValue();
- SDValue Res;
- MulAmt >>= ShiftAmt;
-
- if (MulAmt >= 0) {
- if (llvm::has_single_bit<uint32_t>(MulAmt - 1)) {
- // (mul x, 2^N + 1) => (add (shl x, N), x)
- Res = DAG.getNode(ISD::ADD, DL, VT,
- V,
- DAG.getNode(ISD::SHL, DL, VT,
- V,
- DAG.getConstant(Log2_32(MulAmt - 1), DL,
- MVT::i32)));
- } else if (llvm::has_single_bit<uint32_t>(MulAmt + 1)) {
- // (mul x, 2^N - 1) => (sub (shl x, N), x)
- Res = DAG.getNode(ISD::SUB, DL, VT,
- DAG.getNode(ISD::SHL, DL, VT,
- V,
- DAG.getConstant(Log2_32(MulAmt + 1), DL,
- MVT::i32)),
- V);
- } else
+ unsigned TrailingZeroes = ConstValue.countr_zero();
+ if (TrailingZeroes && !Subtarget->isThumb()) {
+ // Conservatively do not lower to shift+add+shift if the mul might be
+ // folded into smul or umul.
+ if (N0->hasOneUse() && (isSignExtended(N0.getNode(), DAG) ||
+ isZeroExtended(N0.getNode(), DAG)))
return SDValue();
- } else {
- uint64_t MulAmtAbs = -MulAmt;
- if (llvm::has_single_bit<uint32_t>(MulAmtAbs + 1)) {
- // (mul x, -(2^N - 1)) => (sub x, (shl x, N))
- Res = DAG.getNode(ISD::SUB, DL, VT,
- V,
- DAG.getNode(ISD::SHL, DL, VT,
- V,
- DAG.getConstant(Log2_32(MulAmtAbs + 1), DL,
- MVT::i32)));
- } else if (llvm::has_single_bit<uint32_t>(MulAmtAbs - 1)) {
- // (mul x, -(2^N + 1)) => - (add (shl x, N), x)
- Res = DAG.getNode(ISD::ADD, DL, VT,
- V,
- DAG.getNode(ISD::SHL, DL, VT,
- V,
- DAG.getConstant(Log2_32(MulAmtAbs - 1), DL,
- MVT::i32)));
- Res = DAG.getNode(ISD::SUB, DL, VT,
- DAG.getConstant(0, DL, MVT::i32), Res);
- } else
+ // Conservatively do not lower to shift+add+shift if the mul might be
+ // folded into madd or msub.
+ if (N->hasOneUse() && (N->user_begin()->getOpcode() == ISD::ADD ||
+ N->user_begin()->getOpcode() == ISD::SUB))
return SDValue();
}
- if (ShiftAmt != 0)
- Res = DAG.getNode(ISD::SHL, DL, VT,
- Res, DAG.getConstant(ShiftAmt, DL, MVT::i32));
+ // Use ShiftedConstValue instead of ConstValue to support both shift+add/sub
+ // and shift+add+shift.
+ APInt ShiftedConstValue = ConstValue.ashr(TrailingZeroes);
+ unsigned ShiftAmt;
+
+ auto Shl = [&](SDValue N0, unsigned N1) {
+ if (!N0.getNode())
+ return SDValue();
+ // If shift causes overflow, ignore this combine.
+ if (N1 >= N0.getValueSizeInBits())
+ return SDValue();
+ SDValue RHS = DAG.getConstant(N1, DL, MVT::i32);
+ return DAG.getNode(ISD::SHL, DL, VT, N0, RHS);
+ };
+ auto Add = [&](SDValue N0, SDValue N1) {
+ if (!N0.getNode() || !N1.getNode())
+ return SDValue();
+ return DAG.getNode(ISD::ADD, DL, VT, N0, N1);
+ };
+ auto Sub = [&](SDValue N0, SDValue N1) {
+ if (!N0.getNode() || !N1.getNode())
+ return SDValue();
+ return DAG.getNode(ISD::SUB, DL, VT, N0, N1);
+ };
+ auto Negate = [&](SDValue N) {
+ if (!N0.getNode())
+ return SDValue();
+ SDValue Zero = DAG.getConstant(0, DL, VT);
+ return DAG.getNode(ISD::SUB, DL, VT, Zero, N);
+ };
+
+ // Can the const C be decomposed into (1+2^M1)*(1+2^N1), eg:
+ // C = 45 is equal to (1+4)*(1+8), we don't decompose it into (1+2)*(16-1) as
+ // the (2^N - 1) can't be execused via a single instruction.
+ auto isPowPlusPlusConst = [](APInt C, APInt &M, APInt &N) {
+ unsigned BitWidth = C.getBitWidth();
+ for (unsigned i = 1; i < BitWidth / 2; i++) {
+ APInt Rem;
+ APInt X(BitWidth, (1 << i) + 1);
+ APInt::sdivrem(C, X, N, Rem);
+ APInt NVMinus1 = N - 1;
+ if (Rem == 0 && NVMinus1.isPowerOf2()) {
+ M = X;
+ return true;
+ }
+ }
+ return false;
+ };
+
+ // Can the const C be decomposed into (2^M + 1) * 2^N + 1), eg:
+ // C = 11 is equal to (1+4)*2+1, we don't decompose it into (1+2)*4-1 as
+ // the (2^N - 1) can't be execused via a single instruction.
+ auto isPowPlusPlusOneConst = [](APInt C, APInt &M, APInt &N) {
+ APInt CVMinus1 = C - 1;
+ if (CVMinus1.isNegative())
+ return false;
+ unsigned TrailingZeroes = CVMinus1.countr_zero();
+ APInt SCVMinus1 = CVMinus1.ashr(TrailingZeroes) - 1;
+ if (SCVMinus1.isPowerOf2()) {
+ unsigned BitWidth = SCVMinus1.getBitWidth();
+ M = APInt(BitWidth, SCVMinus1.logBase2());
+ N = APInt(BitWidth, TrailingZeroes);
+ return true;
+ }
+ return false;
+ };
+
+ // Can the const C be decomposed into (1 - (1 - 2^M) * 2^N), eg:
+ // C = 29 is equal to 1 - (1 - 2^3) * 2^2.
+ auto isPowMinusMinusOneConst = [](APInt C, APInt &M, APInt &N) {
+ APInt CVMinus1 = C - 1;
+ if (CVMinus1.isNegative())
+ return false;
+ unsigned TrailingZeroes = CVMinus1.countr_zero();
+ APInt CVPlus1 = CVMinus1.ashr(TrailingZeroes) + 1;
+ if (CVPlus1.isPowerOf2()) {
+ unsigned BitWidth = CVPlus1.getBitWidth();
+ M = APInt(BitWidth, CVPlus1.logBase2());
+ N = APInt(BitWidth, TrailingZeroes);
+ return true;
+ }
+ return false;
+ };
+
+ if (ConstValue.isNonNegative()) {
+ // (mul x, (2^N + 1) * 2^M) => (shl (add x, (shl x, N)), M)
+ // (mul x, 2^N - 1) => (sub (shl x, N), x)
+ // (mul x, (2^(N-M) - 1) * 2^M) => (sub (shl x, N), (shl x, M))
+ // (mul x, (2^M + 1) * (2^N + 1))
+ // => MV = (add x, (shl x, M)); (add MV, (shl MV, N))
+ // (mul x, (2^M + 1) * 2^N + 1))
+ // => MV = (add x, (shl x, M)); (add x, (shl MV, N)))
+ // (mul x, 1 - (1 - 2^M) * 2^N))
+ // => MV = sub (x - (shl x, M)); sub (x - (shl MV, N))
+ APInt SCVMinus1 = ShiftedConstValue - 1;
+ APInt SCVPlus1 = ShiftedConstValue + 1;
+ APInt CVPlus1 = ConstValue + 1;
+ APInt CVM, CVN;
+ if (SCVMinus1.isPowerOf2()) {
+ ShiftAmt = SCVMinus1.logBase2();
+ return Shl(Add(N0, Shl(N0, ShiftAmt)), TrailingZeroes);
+ } else if (CVPlus1.isPowerOf2()) {
+ ShiftAmt = CVPlus1.logBase2();
+ return Sub(Shl(N0, ShiftAmt), N0);
+ } else if (SCVPlus1.isPowerOf2()) {
+ ShiftAmt = SCVPlus1.logBase2() + TrailingZeroes;
+ return Sub(Shl(N0, ShiftAmt), Shl(N0, TrailingZeroes));
+ }
+ if (isPowPlusPlusConst(ConstValue, CVM, CVN)) {
+ APInt CVMMinus1 = CVM - 1;
+ APInt CVNMinus1 = CVN - 1;
+ unsigned ShiftM1 = CVMMinus1.logBase2();
+ unsigned ShiftN1 = CVNMinus1.logBase2();
+
+ SDValue MVal = Add(N0, Shl(N0, ShiftM1));
+ return Add(MVal, Shl(MVal, ShiftN1));
+ }
+ if (isPowPlusPlusOneConst(ConstValue, CVM, CVN)) {
+
+ SDValue MVal = Add(N0, Shl(N0, CVM.getZExtValue()));
+ return Add(N0, Shl(MVal, CVN.getZExtValue()));
+ }
+
+ if (isPowMinusMinusOneConst(ConstValue, CVM, CVN)) {
+ SDValue MVal = Sub(N0, Shl(N0, CVM.getZExtValue()));
+ return Sub(N0, Shl(MVal, CVN.getZExtValue()));
+ }
+ } else {
+ // (mul x, -(2^N - 1)) => (sub x, (shl x, N))
+ // (mul x, -(2^N + 1)) => - (add x, (shl x, N)))
+ // (mul x, -(2^(N-M) - 1) * 2^M) => (sub (shl x, M), (shl x, N))
+ APInt SCVPlus1 = -ShiftedConstValue + 1;
+ APInt CVNegPlus1 = -ConstValue + 1;
+ APInt CVNegMinus1 = -ConstValue - 1;
+ if (CVNegPlus1.isPowerOf2()) {
+ ShiftAmt = CVNegPlus1.logBase2();
+ return Sub(N0, Shl(N0, ShiftAmt));
+ } else if (CVNegMinus1.isPowerOf2()) {
+ ShiftAmt = CVNegMinus1.logBase2();
+ return Negate(Add(N0, Shl(N0, ShiftAmt)));
+ } else if (SCVPlus1.isPowerOf2()) {
+ ShiftAmt = SCVPlus1.logBase2() + TrailingZeroes;
+ return Sub(Shl(N0, TrailingZeroes), Shl(N0, ShiftAmt));
+ }
+ }
- // Do not add new nodes to DAG combiner worklist.
- DCI.CombineTo(N, Res, false);
return SDValue();
}
@@ -18961,7 +19095,8 @@ SDValue ARMTargetLowering::PerformDAGCombine(SDNode *N,
case ARMISD::UMLAL: return PerformUMLALCombine(N, DCI.DAG, Subtarget);
case ISD::ADD: return PerformADDCombine(N, DCI, Subtarget);
case ISD::SUB: return PerformSUBCombine(N, DCI, Subtarget);
- case ISD::MUL: return PerformMULCombine(N, DCI, Subtarget);
+ case ISD::MUL:
+ return PerformMULCombine(N, DCI.DAG, DCI, Subtarget);
case ISD::OR: return PerformORCombine(N, DCI, Subtarget);
case ISD::XOR: return PerformXORCombine(N, DCI, Subtarget);
case ISD::AND: return PerformANDCombine(N, DCI, Subtarget);
diff --git a/llvm/test/CodeGen/AArch64/load-insert-zero.ll b/llvm/test/CodeGen/AArch64/load-insert-zero.ll
index d6150b6dc4585..cbb2d6081acae 100644
--- a/llvm/test/CodeGen/AArch64/load-insert-zero.ll
+++ b/llvm/test/CodeGen/AArch64/load-insert-zero.ll
@@ -793,7 +793,7 @@ define void @predictor_4x4_neon(ptr nocapture noundef writeonly %0, i64 noundef
; CHECK-NEXT: ext v2.8b, v2.8b, v0.8b, #1
; CHECK-NEXT: ext v1.8b, v3.8b, v0.8b, #1
; CHECK-NEXT: str s2, [x0, x8]
-; CHECK-NEXT: add x8, x8, x1
+; CHECK-NEXT: add x8, x1, x8
; CHECK-NEXT: str s1, [x0, x8]
; CHECK-NEXT: ret
%5 = load i32, ptr %2, align 4
@@ -856,7 +856,7 @@ define void @predictor_4x4_neon_new(ptr nocapture noundef writeonly %0, i64 noun
; CHECK-NEXT: ldur s3, [x2, #3]
; CHECK-NEXT: uaddl v4.8h, v1.8b, v0.8b
; CHECK-NEXT: urhadd v0.8b, v0.8b, v1.8b
-; CHECK-NEXT: add x9, x8, x1
+; CHECK-NEXT: add x9, x1, x8
; CHECK-NEXT: uaddl v5.8h, v2.8b, v1.8b
; CHECK-NEXT: uaddl v3.8h, v3.8b, v2.8b
; CHECK-NEXT: urhadd v1.8b, v1.8b, v2.8b
diff --git a/llvm/test/CodeGen/AArch64/sme2-intrinsics-int-dots.ll b/llvm/test/CodeGen/AArch64/sme2-intrinsics-int-dots.ll
index 111b3fde29a37..33b5a8f5eac53 100644
--- a/llvm/test/CodeGen/AArch64/sme2-intrinsics-int-dots.ll
+++ b/llvm/test/CodeGen/AArch64/sme2-intrinsics-int-dots.ll
@@ -77,7 +77,7 @@ define void @udot_multi_za32_u16_vg1x4_tuple(i64 %stride, ptr %ptr) #1 {
; CHECK-NEXT: mov w8, wzr
; CHECK-NEXT: ld1b { z16.b, z20.b, z24.b, z28.b }, pn8/z, [x1]
; CHECK-NEXT: ld1b { z17.b, z21.b, z25.b, z29.b }, pn8/z, [x1, x0]
-; CHECK-NEXT: add x10, x9, x0
+; CHECK-NEXT: add x10, x0, x9
; CHECK-NEXT: ld1b { z18.b, z22.b, z26.b, z30.b }, pn8/z, [x1, x9]
; CHECK-NEXT: ld1b { z19.b, z23.b, z27.b, z31.b }, pn8/z, [x1, x10]
; CHECK-NEXT: udot za.s[w8, 0, vgx4], { z16.b - z19.b }, { z20.b - z23.b }
@@ -270,7 +270,7 @@ define void @usdot_multi_za32_u16_vg1x4_tuple(i64 %stride, ptr %ptr) #1 {
; CHECK-NEXT: mov w8, wzr
; CHECK-NEXT: ld1b { z16.b, z20.b, z24.b, z28.b }, pn8/z, [x1]
; CHECK-NEXT: ld1b { z17.b, z21.b, z25.b, z29.b }, pn8/z, [x1, x0]
-; CHECK-NEXT: add x10, x9, x0
+; CHECK-NEXT: add x10, x0, x9
; CHECK-NEXT: ld1b { z18.b, z22.b, z26.b, z30.b }, pn8/z, [x1, x9]
; CHECK-NEXT: ld1b { z19.b, z23.b, z27.b, z31.b }, pn8/z, [x1, x10]
; CHECK-NEXT: usdot za.s[w8, 0, vgx4], { z16.b - z19.b }, { z20.b - z23.b }
@@ -383,7 +383,7 @@ define void @sdot_multi_za32_u16_vg1x4_tuple(i64 %stride, ptr %ptr) #0 {
; CHECK-NEXT: mov w8, wzr
; CHECK-NEXT: ld1b { z16.b, z20.b, z24.b, z28.b }, pn8/z, [x1]
; CHECK-NEXT: ld1b { z17.b, z21.b, z25.b, z29.b }, pn8/z, [x1, x0]
-; CHECK-NEXT: add x10, x9, x0
+; CHECK-NEXT: add x10, x0, x9
; CHECK-NEXT: ld1b { z18.b, z22.b, z26.b, z30.b }, pn8/z, [x1, x9]
; CHECK-NEXT: ld1b { z19.b, z23.b, z27.b, z31.b }, pn8/z, [x1, x10]
; CHECK-NEXT: sdot za.s[w8, 0, vgx4], { z16.b - z19.b }, { z20.b - z23.b }
@@ -883,7 +883,7 @@ define void @usdot_single_za32_u16_vg1x4_tuple(ptr %ptr, i64 %stride, <vscale x
; CHECK-NEXT: str z23, [sp, #1, mul vl] // 16-byte Folded Spill
; CHECK-NEXT: mov w8, wzr
; CHECK-NEXT: str z22, [sp, #2, mul vl] // 16-byte Folded Spill
-; CHECK-NEXT: add x10, x9, x1
+; CHECK-NEXT: add x10, x1, x9
; CHECK-NEXT: str z21, [sp, #3, mul vl] // 16-byte Folded Spill
; CHECK-NEXT: str z20, [sp, #4, mul vl] // 16-byte Folded Spill
; CHECK-NEXT: str z19, [sp, #5, mul vl] // 16-byte Folded Spill
@@ -1203,7 +1203,7 @@ define void @sudot_single_za32_u16_vg1x4_tuple(ptr %ptr, i64 %stride, <vscale x
; CHECK-NEXT: str z23, [sp, #1, mul vl] // 16-byte Folded Spill
; CHECK-NEXT: mov w8, wzr
; CHECK-NEXT: str z22, [sp, #2, mul vl] // 16-byte Folded Spill
-; CHECK-NEXT: add x10, x9, x1
+; CHECK-NEXT: add x10, x1, x9
; CHECK-NEXT: str z21, [sp, #3, mul vl] // 16-byte Folded Spill
; CHECK-NEXT: str z20, [sp, #4, mul vl] // 16-byte Folded Spill
; CHECK-NEXT: str z19, [sp, #5, mul vl] // 16-byte Folded Spill
@@ -1398,7 +1398,7 @@ define void @udot_form_4x_tuple(ptr %ptr, i64 %stride) #0 {
; CHECK-NEXT: mov w8, wzr
; CHECK-NEXT: ld1b { z16.b, z20.b, z24.b, z28.b }, pn8/z, [x0]
; CHECK-NEXT: ld1b { z17.b, z21.b, z25.b, z29.b }, pn8/z, [x0, x1]
-; CHECK-NEXT: add x10, x9, x1
+; CHECK-NEXT: add x10, x1, x9
; CHECK-NEXT: ld1b { z18.b, z22.b, z26.b, z30.b }, pn8/z, [x0, x9]
; CHECK-NEXT: ld1b { z19.b, z23.b, z27.b, z31.b }, pn8/z, [x0, x10]
; CHECK-NEXT: udot za.s[w8, 0, vgx4], { z16.b - z19.b }, z0.b[0]
@@ -1451,7 +1451,7 @@ define void @udot_form_4x_tuple_svecc(ptr %ptr, i64 %stride, <vscale x 16 x i8>
; CHECK-NEXT: str z23, [sp, #1, mul vl] // 16-byte Folded Spill
; CHECK-NEXT: mov w8, wzr
; CHECK-NEXT: str z22, [sp, #2, mul vl] // 16-byte Folded Spill
-; CHECK-NEXT: add x10, x9, x1
+; CHECK-NEXT: add x10, x1, x9
; CHECK-NEXT: str z21, [sp, #3, mul vl] // 16-byte Folded Spill
; CHECK-NEXT: str z20, [sp, #4, mul vl] // 16-byte Folded Spill
; CHECK-NEXT: str z19, [sp, #5, mul vl] // 16-byte Folded Spill
@@ -1526,7 +1526,7 @@ define void @udot_single_za32_u16_vg1x4_x2load_x4tuple(ptr %ptr, i64 %stride, <v
; CHECK-NEXT: st1b { z10.b, z11.b }, pn8, [sp, #2, mul vl] // 32-byte Folded Spill
; CHECK-NEXT: ptrue pn8.b
; CHECK-NEXT: str z9, [sp, #4, mul vl] // 16-byte Folded Spill
-; CHECK-NEXT: add x10, x9, x1
+; CHECK-NEXT: add x10, x1, x9
; CHECK-NEXT: mov w8, wzr
; CHECK-NEXT: ld1b { z1.b, z9.b }, pn8/z, [x0]
; CHECK-NEXT: ld1b { z2.b, z10.b }, pn8/z, [x0, x1]
@@ -1702,7 +1702,7 @@ define void @usdot_form_4x_tuple(ptr %ptr, i64 %stride) #0 {
; CHECK-NEXT: mov w8, wzr
; CHECK-NEXT: ld1b { z16.b, z20.b, z24.b, z28.b }, pn8/z, [x0]
; CHECK-NEXT: ld1b { z17.b, z21.b, z25.b, z29.b }, pn8/z, [x0, x1]
-; CHECK-NEXT: add x10, x9, x1
+; CHECK-NEXT: add x10, x1, x9
; CHECK-NEXT: ld1b { z18.b, z22.b, z26.b, z30.b }, pn8/z, [x0, x9]
; CHECK-NEXT: ld1b { z19.b, z23.b, z27.b, z31.b }, pn8/z, [x0, x10]
; CHECK-NEXT: usdot za.s[w8, 0, vgx4], { z16.b - z19.b }, z0.b[0]
@@ -1755,7 +1755,7 @@ define void @usdot_form_4x_tuple_svecc(ptr %ptr, i64 %stride, <vscale x 16 x i8>
; CHECK-NEXT: str z23, [sp, #1, mul vl] // 16-byte Folded Spill
; CHECK-NEXT: mov w8, wzr
; CHECK-NEXT: str z22, [sp, #2, mul vl] // 16-byte Folded Spill
-; CHECK-NEXT: add x10, x9, x1
+; CHECK-NEXT: add x10, x1, x9
; CHECK-NEXT: str z21, [sp, #3, mul vl] // 16-byte Folded Spill
; CHECK-NEXT: str z20, [sp, #4, mul vl] // 16-byte Folded Spill
; CHECK-NEXT: str z19, [sp, #5, mul vl] // 16-byte Folded Spill
@@ -1956,7 +1956,7 @@ define void @sdot_form_4x_tuple(ptr %ptr, i64 %stride) #0 {
; CHECK-NEXT: mov w8, wzr
; CHECK-NEXT: ld1b { z16.b, z20.b, z24.b, z28.b }, pn8/z, [x0]
; CHECK-NEXT: ld1b { z17.b, z21.b, z25.b, z29.b }, pn8/z, [x0, x1]
-; CHECK-NEXT: add x10, x9, x1
+; CHECK-NEXT: add x10, x1, x9
; CHECK-NEXT: ld1b { z18.b, z22.b, z26.b, z30.b }, pn8/z, [x0, x9]
; CHECK-NEXT: ld1b { z19.b, z23.b, z27.b, z31.b }, pn8/z, [x0, x10]
; CHECK-NEXT: sdot za.s[w8, 0, vgx4], { z16.b - z19.b }, z0.b[0]
@@ -2009,7 +2009,7 @@ define void @sdot_form_4x_tuple_svecc(ptr %ptr, i64 %stride, <vscale x 16 x i8>
; CHECK-NEXT: str z23, [sp, #1, mul vl] // 16-byte Folded Spill
; CHECK-NEXT: mov w8, wzr
; CHECK-NEXT: str z22, [sp, #2, mul vl] // 16-byte Folded Spill
-; CHECK-NEXT: add x10, x9, x1
+; CHECK-NEXT: add x10, x1, x9
; CHECK-NEXT: str z21, [sp, #3, mul vl] // 16-byte Folded Spill
; CHECK-NEXT: str z20, [sp, #4, mul vl] // 16-byte Folded Spill
; CHECK-NEXT: str z19, [sp, #5, mul vl] // 16-byte Folded Spill
@@ -2210,7 +2210,7 @@ define void @sudot_form_4x_tuple(ptr %ptr, i64 %stride) #0 {
; CHECK-NEXT: mov w8, wzr
; CHECK-NEXT: ld1b { z16.b, z20.b, z24.b, z28.b }, pn8/z, [x0]
; CHECK-NEXT: ld1b { z17.b, z21.b, z25.b, z29.b }, pn8/z, [x0, x1]
-; CHECK-NEXT: add x10, x9, x1
+; CHECK-NEXT: add x10, x1, x9
; CHECK-NEXT: ld1b { z18.b, z22.b, z26.b, z30.b }, pn8/z, [x0, x9]
; CHECK-NEXT: ld1b { z19.b, z23.b, z27.b, z31.b }, pn8/z, [x0, x10]
; CHECK-NEXT: sudot za.s[w8, 0, vgx4], { z16.b - z19.b }, z0.b[0]
@@ -2263,7 +2263,7 @@ define void @sudot_form_4x_tuple_svecc(ptr %ptr, i64 %stride, <vscale x 16 x i8>
; CHECK-NEXT: str z23, [sp, #1, mul vl] // 16-byte Folded Spill
; CHECK-NEXT: mov w8, wzr
; CHECK-NEXT: str z22, [sp, #2, mul vl] // 16-byte Folded Spill
-; CHECK-NEXT: add x10, x9, x1
+; CHECK-NEXT: add x10, x1, x9
; CHECK-NEXT: str z21, [sp, #3, mul vl] // 16-byte Folded Spill
; CHECK-NEXT: str z20, [sp, #4, mul vl] // 16-byte Folded Spill
; CHECK-NEXT: str z19, [sp, #5, mul vl] // 16-byte Folded Spill
diff --git a/llvm/test/CodeGen/AArch64/sme2-intrinsics-vdot.ll b/llvm/test/CodeGen/AArch64/sme2-intrinsics-vdot.ll
index 31ea2833bb8cf..27263b1f38fb6 100644
--- a/llvm/test/CodeGen/AArch64/sme2-intrinsics-vdot.ll
+++ b/llvm/test/CodeGen/AArch64/sme2-intrinsics-vdot.ll
@@ -144,7 +144,7 @@ define void @svdot_form_4x_tuple(ptr %ptr, i64 %stride) #0 {
; CHECK-NEXT: mov w8, wzr
; CHECK-NEXT: ld1b { z16.b, z20.b, z24.b, z28.b }, pn8/z, [x0]
; CHECK-NEXT: ld1b { z17.b, z21.b, z25.b, z29.b }, pn8/z, [x0, x1]
-; CHECK-NEXT: add x10, x9, x1
+; CHECK-NEXT: add x10, x1, x9
; CHECK-NEXT: ld1b { z18.b, z22.b, z26.b, z30.b }, pn8/z, [x0, x9]
; CHECK-NEXT: ld1b { z19.b, z23.b, z27.b, z31.b }, pn8/z, [x0, x10]
; CHECK-NEXT: svdot za.s[w8, 0, vgx4], { z16.b - z19.b }, z0.b[0]
@@ -197,7 +197,7 @@ define void @svdot_form_4x_tuple_svecc(ptr %ptr, i64 %stride, <vscale x 8 x i16>
; CHECK-NEXT: str z23, [sp, #1, mul vl] // 16-byte Folded Spill
; CHECK-NEXT: mov w8, wzr
; CHECK-NEXT: str z22, [sp, #2, mul vl] // 16-byte Folded Spill
-; CHECK-NEXT: add x10, x9, x1
+; CHECK-NEXT: add x10, x1, x9
; CHECK-NEXT: str z21, [sp, #3, mul vl] // 16-byte Folded Spill
; CHECK-NEXT: str z20, [sp, #4, mul vl] // 16-byte Folded Spill
; CHECK-NEXT: str z19, [sp, #5, mul vl] // 16-byte Folded Spill
@@ -371,7 +371,7 @@ define void @uvdot_form_4x_tuple(ptr %ptr, i64 %stride) #0 {
; CHECK-NEXT: mov w8, wzr
; CHECK-NEXT: ld1b { z16.b, z20.b, z24.b, z28.b }, pn8/z, [x0]
; CHECK-NEXT: ld1b { z17.b, z21.b, z25.b, z29.b }, pn8/z, [x0, x1]
-; CHECK-NEXT: add x10, x9, x1
+; CHECK-NEXT: add x10, x1, x9
; CHECK-NEXT: ld1b { z18.b, z22.b, z26.b, z30.b }, pn8/z, [x0, x9]
; CHECK-NEXT: ld1b { z19.b, z23.b, z27.b, z31.b }, pn8/z, [x0, x10]
; CHECK-NEXT: uvdot za.s[w8, 0, vgx4], { z16.b - z19.b }, z0.b[0]
@@ -424,7 +424,7 @@ define void @uvdot_form_4x_tuple_svecc(ptr %ptr, i64 %stride, <vscale x 8 x i16>
; CHECK-NEXT: str z23, [sp, #1, mul vl] // 16-byte Folded Spill
; CHECK-NEXT: mov w8, wzr
; CHECK-NEXT: str z22, [sp, #2, mul vl] // 16-byte Folded Spill
-; CHECK-NEXT: add x10, x9, x1
+; CHECK-NEXT: add x10, x1, x9
; CHECK-NEXT: str z21, [sp, #3, mul vl] // 16-byte Folded Spill
; CHECK-NEXT: str z20, [sp, #4, mul vl] // 16-byte Folded Spill
; CHECK-NEXT: str z19, [sp, #5, mul vl] // 16-byte Folded Spill
@@ -510,7 +510,7 @@ define void @suvdot_form_4x_tuple(ptr %ptr, i64 %stride) #0 {
; CHECK-NEXT: mov w8, wzr
; CHECK-NEXT: ld1b { z16.b, z20.b, z24.b, z28.b }, pn8/z, [x0]
; CHECK-NEXT: ld1b { z17.b, z21.b, z25.b, z29.b }, pn8/z, [x0, x1]
-; CHECK-NEXT: add x10, x9, x1
+; CHECK-NEXT: add x10, x1, x9
; CHECK-NEXT: ld1b { z18.b, z22.b, z26.b, z30.b }, pn8/z, [x0, x9]
; CHECK-NEXT: ld1b { z19.b, z23.b, z27.b, z31.b }, pn8/z, [x0, x10]
; CHECK-NEXT: suvdot za.s[w8, 0, vgx4], { z16.b - z19.b }, z0.b[0]
@@ -563,7 +563,7 @@ define void @suvdot_form_4x_tuple_svecc(ptr %ptr, i64 %stride, <vscale x 8 x i16
; CHECK-NEXT: str z23, [sp, #1, mul vl] // 16-byte Folded Spill
; CHECK-NEXT: mov w8, wzr
; CHECK-NEXT: str z22, [sp, #2, mul vl] // 16-byte Folded Spill
-; CHECK-NEXT: add x10, x9, x1
+; CHECK-NEXT: add x10, x1, x9
; CHECK-NEXT: str z21, [sp, #3, mul vl] // 16-byte Folded Spill
; CHECK-NEXT: str z20, [sp, #4, mul vl] // 16-byte Folded Spill
; CHECK-NEXT: str z19, [sp, #5, mul vl] // 16-byte Folded Spill
@@ -649,7 +649,7 @@ define void @usvdot_form_4x_tuple(ptr %ptr, i64 %stride) #0 {
; CHECK-NEXT: mov w8, wzr
; CHECK-NEXT: ld1b { z16.b, z20.b, z24.b, z28.b }, pn8/z, [x0]
; CHECK-NEXT: ld1b { z17.b, z21.b, z25.b, z29.b }, pn8/z, [x0, x1]
-; CHECK-NEXT: add x10, x9, x1
+; CHECK-NEXT: add x10, x1, x9
; CHECK-NEXT: ld1b { z18.b, z22.b, z26.b, z30.b }, pn8/z, [x0, x9]
; CHECK-NEXT: ld1b { z19.b, z23.b, z27.b, z31.b }, pn8/z, [x0, x10]
; CHECK-NEXT: usvdot za.s[w8, 0, vgx4], { z16.b - z19.b }, z0.b[0]
@@ -702,7 +702,7 @@ define void @usvdot_form_4x_tuple_svecc(ptr %ptr, i64 %stride, <vscale x 8 x i16
; CHECK-NEXT: str z23, [sp, #1, mul vl] // 16-byte Folded Spill
; CHECK-NEXT: mov w8, wzr
; CHECK-NEXT: str z22, [sp, #2, mul vl] // 16-byte Folded Spill
-; CHECK-NEXT: add x10, x9, x1
+; CHECK-NEXT: add x10, x1, x9
; CHECK-NEXT: str z21, [sp, #3, mul vl] // 16-byte Folded Spill
; CHECK-NEXT: str z20, [sp, #4, mul vl] // 16-byte Folded Spill
; CHECK-NEXT: str z19, [sp, #5, mul vl] // 16-byte Folded Spill
diff --git a/llvm/test/CodeGen/ARM/2013-05-07-ByteLoadSameAddress.ll b/llvm/test/CodeGen/ARM/2013-05-07-ByteLoadSameAddress.ll
index f7500bd5bda48..61d2a9f446698 100644
--- a/llvm/test/CodeGen/ARM/2013-05-07-ByteLoadSameAddress.ll
+++ b/llvm/test/CodeGen/ARM/2013-05-07-ByteLoadSameAddress.ll
@@ -49,7 +49,7 @@ entry:
%8 = load i8, ptr %arrayidx62, align 1
%conv63 = zext i8 %8 to i32
; CHECK: ldrb r{{[0-9]*}}, [r{{[0-9]*}}, #-1]
-; CHECK-NEXT: ldrb{{[.w]*}} r{{[0-9]*}}, [r{{[0-9]*}}, #1]
+; CHECK: ldrb{{[.w]*}} r{{[0-9]*}}, [r{{[0-9]*}}, #1]
%tmp = add i32 %add34191, %conv46
%tmp193 = add i32 %tmp, %conv52
%tmp194 = add i32 %tmp193, %conv57
diff --git a/llvm/test/CodeGen/ARM/addimm-mulimm.ll b/llvm/test/CodeGen/ARM/addimm-mulimm.ll
index d5c6bbfd3cffd..5a201b2f3c438 100644
--- a/llvm/test/CodeGen/ARM/addimm-mulimm.ll
+++ b/llvm/test/CodeGen/ARM/addimm-mulimm.ll
@@ -7,17 +7,24 @@
define i32 @fold_add19_mul11_i32(i32 %a) {
; CHECK-ARM-LABEL: fold_add19_mul11_i32:
; CHECK-ARM: @ %bb.0:
-; CHECK-ARM-NEXT: mov r1, #11
-; CHECK-ARM-NEXT: mul r0, r0, r1
+; CHECK-ARM-NEXT: add r1, r0, r0, lsl #2
+; CHECK-ARM-NEXT: add r0, r0, r1, lsl #1
; CHECK-ARM-NEXT: add r0, r0, #209
; CHECK-ARM-NEXT: bx lr
;
-; CHECK-THUMB-LABEL: fold_add19_mul11_i32:
-; CHECK-THUMB: @ %bb.0:
-; CHECK-THUMB-NEXT: movs r1, #11
-; CHECK-THUMB-NEXT: muls r0, r1, r0
-; CHECK-THUMB-NEXT: adds r0, #209
-; CHECK-THUMB-NEXT: bx lr
+; CHECK-THUMBV6M-LABEL: fold_add19_mul11_i32:
+; CHECK-THUMBV6M: @ %bb.0:
+; CHECK-THUMBV6M-NEXT: movs r1, #11
+; CHECK-THUMBV6M-NEXT: muls r0, r1, r0
+; CHECK-THUMBV6M-NEXT: adds r0, #209
+; CHECK-THUMBV6M-NEXT: bx lr
+;
+; CHECK-THUMBV7M-LABEL: fold_add19_mul11_i32:
+; CHECK-THUMBV7M: @ %bb.0:
+; CHECK-THUMBV7M-NEXT: add.w r1, r0, r0, lsl #2
+; CHECK-THUMBV7M-NEXT: add.w r0, r0, r1, lsl #1
+; CHECK-THUMBV7M-NEXT: adds r0, #209
+; CHECK-THUMBV7M-NEXT: bx lr
%b = add i32 %a, 19
%c = mul i32 %b, 11
ret i32 %c
@@ -26,17 +33,24 @@ define i32 @fold_add19_mul11_i32(i32 %a) {
define i16 @fold_add19_mul11_i16(i16 %a) {
; CHECK-ARM-LABEL: fold_add19_mul11_i16:
; CHECK-ARM: @ %bb.0:
-; CHECK-ARM-NEXT: mov r1, #11
-; CHECK-ARM-NEXT: mul r0, r0, r1
+; CHECK-ARM-NEXT: add r1, r0, r0, lsl #2
+; CHECK-ARM-NEXT: add r0, r0, r1, lsl #1
; CHECK-ARM-NEXT: add r0, r0, #209
; CHECK-ARM-NEXT: bx lr
;
-; CHECK-THUMB-LABEL: fold_add19_mul11_i16:
-; CHECK-THUMB: @ %bb.0:
-; CHECK-THUMB-NEXT: movs r1, #11
-; CHECK-THUMB-NEXT: muls r0, r1, r0
-; CHECK-THUMB-NEXT: adds r0, #209
-; CHECK-THUMB-NEXT: bx lr
+; CHECK-THUMBV6M-LABEL: fold_add19_mul11_i16:
+; CHECK-THUMBV6M: @ %bb.0:
+; CHECK-THUMBV6M-NEXT: movs r1, #11
+; CHECK-THUMBV6M-NEXT: muls r0, r1, r0
+; CHECK-THUMBV6M-NEXT: adds r0, #209
+; CHECK-THUMBV6M-NEXT: bx lr
+;
+; CHECK-THUMBV7M-LABEL: fold_add19_mul11_i16:
+; CHECK-THUMBV7M: @ %bb.0:
+; CHECK-THUMBV7M-NEXT: add.w r1, r0, r0, lsl #2
+; CHECK-THUMBV7M-NEXT: add.w r0, r0, r1, lsl #1
+; CHECK-THUMBV7M-NEXT: adds r0, #209
+; CHECK-THUMBV7M-NEXT: bx lr
%b = add i16 %a, 19
%c = mul i16 %b, 11
ret i16 %c
@@ -45,17 +59,24 @@ define i16 @fold_add19_mul11_i16(i16 %a) {
define i32 @fold_sub19_mul11_i32(i32 %a) {
; CHECK-ARM-LABEL: fold_sub19_mul11_i32:
; CHECK-ARM: @ %bb.0:
-; CHECK-ARM-NEXT: mov r1, #11
-; CHECK-ARM-NEXT: mul r0, r0, r1
+; CHECK-ARM-NEXT: add r1, r0, r0, lsl #2
+; CHECK-ARM-NEXT: add r0, r0, r1, lsl #1
; CHECK-ARM-NEXT: sub r0, r0, #209
; CHECK-ARM-NEXT: bx lr
;
-; CHECK-THUMB-LABEL: fold_sub19_mul11_i32:
-; CHECK-THUMB: @ %bb.0:
-; CHECK-THUMB-NEXT: movs r1, #11
-; CHECK-THUMB-NEXT: muls r0, r1, r0
-; CHECK-THUMB-NEXT: subs r0, #209
-; CHECK-THUMB-NEXT: bx lr
+; CHECK-THUMBV6M-LABEL: fold_sub19_mul11_i32:
+; CHECK-THUMBV6M: @ %bb.0:
+; CHECK-THUMBV6M-NEXT: movs r1, #11
+; CHECK-THUMBV6M-NEXT: muls r0, r1, r0
+; CHECK-THUMBV6M-NEXT: subs r0, #209
+; CHECK-THUMBV6M-NEXT: bx lr
+;
+; CHECK-THUMBV7M-LABEL: fold_sub19_mul11_i32:
+; CHECK-THUMBV7M: @ %bb.0:
+; CHECK-THUMBV7M-NEXT: add.w r1, r0, r0, lsl #2
+; CHECK-THUMBV7M-NEXT: add.w r0, r0, r1, lsl #1
+; CHECK-THUMBV7M-NEXT: subs r0, #209
+; CHECK-THUMBV7M-NEXT: bx lr
%b = add i32 %a, -19
%c = mul i32 %b, 11
ret i32 %c
@@ -64,17 +85,24 @@ define i32 @fold_sub19_mul11_i32(i32 %a) {
define i16 @fold_sub19_mul11_i16(i16 %a) {
; CHECK-ARM-LABEL: fold_sub19_mul11_i16:
; CHECK-ARM: @ %bb.0:
-; CHECK-ARM-NEXT: mov r1, #11
-; CHECK-ARM-NEXT: mul r0, r0, r1
+; CHECK-ARM-NEXT: add r1, r0, r0, lsl #2
+; CHECK-ARM-NEXT: add r0, r0, r1, lsl #1
; CHECK-ARM-NEXT: sub r0, r0, #209
; CHECK-ARM-NEXT: bx lr
;
-; CHECK-THUMB-LABEL: fold_sub19_mul11_i16:
-; CHECK-THUMB: @ %bb.0:
-; CHECK-THUMB-NEXT: movs r1, #11
-; CHECK-THUMB-NEXT: muls r0, r1, r0
-; CHECK-THUMB-NEXT: subs r0, #209
-; CHECK-THUMB-NEXT: bx lr
+; CHECK-THUMBV6M-LABEL: fold_sub19_mul11_i16:
+; CHECK-THUMBV6M: @ %bb.0:
+; CHECK-THUMBV6M-NEXT: movs r1, #11
+; CHECK-THUMBV6M-NEXT: muls r0, r1, r0
+; CHECK-THUMBV6M-NEXT: subs r0, #209
+; CHECK-THUMBV6M-NEXT: bx lr
+;
+; CHECK-THUMBV7M-LABEL: fold_sub19_mul11_i16:
+; CHECK-THUMBV7M: @ %bb.0:
+; CHECK-THUMBV7M-NEXT: add.w r1, r0, r0, lsl #2
+; CHECK-THUMBV7M-NEXT: add.w r0, r0, r1, lsl #1
+; CHECK-THUMBV7M-NEXT: subs r0, #209
+; CHECK-THUMBV7M-NEXT: bx lr
%b = add i16 %a, -19
%c = mul i16 %b, 11
ret i16 %c
@@ -83,17 +111,18 @@ define i16 @fold_sub19_mul11_i16(i16 %a) {
define i32 @fold_add301_mul19_i32(i32 %a) {
; CHECK-ARMV6-LABEL: fold_add301_mul19_i32:
; CHECK-ARMV6: @ %bb.0:
-; CHECK-ARMV6-NEXT: mov r1, #87
-; CHECK-ARMV6-NEXT: mov r2, #19
-; CHECK-ARMV6-NEXT: orr r1, r1, #5632
-; CHECK-ARMV6-NEXT: mla r0, r0, r2, r1
+; CHECK-ARMV6-NEXT: add r1, r0, r0, lsl #3
+; CHECK-ARMV6-NEXT: add r0, r0, r1, lsl #1
+; CHECK-ARMV6-NEXT: add r0, r0, #87
+; CHECK-ARMV6-NEXT: add r0, r0, #5632
; CHECK-ARMV6-NEXT: bx lr
;
; CHECK-ARMV7-LABEL: fold_add301_mul19_i32:
; CHECK-ARMV7: @ %bb.0:
+; CHECK-ARMV7-NEXT: add r1, r0, r0, lsl #3
+; CHECK-ARMV7-NEXT: add r0, r0, r1, lsl #1
; CHECK-ARMV7-NEXT: movw r1, #5719
-; CHECK-ARMV7-NEXT: mov r2, #19
-; CHECK-ARMV7-NEXT: mla r0, r0, r2, r1
+; CHECK-ARMV7-NEXT: add r0, r0, r1
; CHECK-ARMV7-NEXT: bx lr
;
; CHECK-THUMBV6M-LABEL: fold_add301_mul19_i32:
@@ -110,9 +139,10 @@ define i32 @fold_add301_mul19_i32(i32 %a) {
;
; CHECK-THUMBV7M-LABEL: fold_add301_mul19_i32:
; CHECK-THUMBV7M: @ %bb.0:
+; CHECK-THUMBV7M-NEXT: add.w r1, r0, r0, lsl #3
+; CHECK-THUMBV7M-NEXT: add.w r0, r0, r1, lsl #1
; CHECK-THUMBV7M-NEXT: movw r1, #5719
-; CHECK-THUMBV7M-NEXT: movs r2, #19
-; CHECK-THUMBV7M-NEXT: mla r0, r0, r2, r1
+; CHECK-THUMBV7M-NEXT: add r0, r1
; CHECK-THUMBV7M-NEXT: bx lr
%b = add i32 %a, 301
%c = mul i32 %b, 19
@@ -122,17 +152,18 @@ define i32 @fold_add301_mul19_i32(i32 %a) {
define i16 @fold_add301_mul19_i16(i16 %a) {
; CHECK-ARMV6-LABEL: fold_add301_mul19_i16:
; CHECK-ARMV6: @ %bb.0:
-; CHECK-ARMV6-NEXT: mov r1, #87
-; CHECK-ARMV6-NEXT: mov r2, #19
-; CHECK-ARMV6-NEXT: orr r1, r1, #5632
-; CHECK-ARMV6-NEXT: mla r0, r0, r2, r1
+; CHECK-ARMV6-NEXT: add r1, r0, r0, lsl #3
+; CHECK-ARMV6-NEXT: add r0, r0, r1, lsl #1
+; CHECK-ARMV6-NEXT: add r0, r0, #87
+; CHECK-ARMV6-NEXT: add r0, r0, #5632
; CHECK-ARMV6-NEXT: bx lr
;
; CHECK-ARMV7-LABEL: fold_add301_mul19_i16:
; CHECK-ARMV7: @ %bb.0:
+; CHECK-ARMV7-NEXT: add r1, r0, r0, lsl #3
+; CHECK-ARMV7-NEXT: add r0, r0, r1, lsl #1
; CHECK-ARMV7-NEXT: movw r1, #5719
-; CHECK-ARMV7-NEXT: mov r2, #19
-; CHECK-ARMV7-NEXT: mla r0, r0, r2, r1
+; CHECK-ARMV7-NEXT: add r0, r0, r1
; CHECK-ARMV7-NEXT: bx lr
;
; CHECK-THUMBV6M-LABEL: fold_add301_mul19_i16:
@@ -149,9 +180,10 @@ define i16 @fold_add301_mul19_i16(i16 %a) {
;
; CHECK-THUMBV7M-LABEL: fold_add301_mul19_i16:
; CHECK-THUMBV7M: @ %bb.0:
+; CHECK-THUMBV7M-NEXT: add.w r1, r0, r0, lsl #3
+; CHECK-THUMBV7M-NEXT: add.w r0, r0, r1, lsl #1
; CHECK-THUMBV7M-NEXT: movw r1, #5719
-; CHECK-THUMBV7M-NEXT: movs r2, #19
-; CHECK-THUMBV7M-NEXT: mla r0, r0, r2, r1
+; CHECK-THUMBV7M-NEXT: add r0, r1
; CHECK-THUMBV7M-NEXT: bx lr
%b = add i16 %a, 301
%c = mul i16 %b, 19
@@ -161,16 +193,16 @@ define i16 @fold_add301_mul19_i16(i16 %a) {
define i32 @fold_sub301_mul19_i32(i32 %a) {
; CHECK-ARMV6-LABEL: fold_sub301_mul19_i32:
; CHECK-ARMV6: @ %bb.0:
-; CHECK-ARMV6-NEXT: mvn r1, #86
-; CHECK-ARMV6-NEXT: mov r2, #19
-; CHECK-ARMV6-NEXT: sub r1, r1, #5632
-; CHECK-ARMV6-NEXT: mla r0, r0, r2, r1
+; CHECK-ARMV6-NEXT: add r1, r0, r0, lsl #3
+; CHECK-ARMV6-NEXT: add r0, r0, r1, lsl #1
+; CHECK-ARMV6-NEXT: sub r0, r0, #87
+; CHECK-ARMV6-NEXT: sub r0, r0, #5632
; CHECK-ARMV6-NEXT: bx lr
;
; CHECK-ARMV7-LABEL: fold_sub301_mul19_i32:
; CHECK-ARMV7: @ %bb.0:
-; CHECK-ARMV7-NEXT: mov r1, #19
-; CHECK-ARMV7-NEXT: mul r0, r0, r1
+; CHECK-ARMV7-NEXT: add r1, r0, r0, lsl #3
+; CHECK-ARMV7-NEXT: add r0, r0, r1, lsl #1
; CHECK-ARMV7-NEXT: movw r1, #5719
; CHECK-ARMV7-NEXT: sub r0, r0, r1
; CHECK-ARMV7-NEXT: bx lr
@@ -189,8 +221,8 @@ define i32 @fold_sub301_mul19_i32(i32 %a) {
;
; CHECK-THUMBV7M-LABEL: fold_sub301_mul19_i32:
; CHECK-THUMBV7M: @ %bb.0:
-; CHECK-THUMBV7M-NEXT: movs r1, #19
-; CHECK-THUMBV7M-NEXT: muls r0, r1, r0
+; CHECK-THUMBV7M-NEXT: add.w r1, r0, r0, lsl #3
+; CHECK-THUMBV7M-NEXT: add.w r0, r0, r1, lsl #1
; CHECK-THUMBV7M-NEXT: movw r1, #5719
; CHECK-THUMBV7M-NEXT: subs r0, r0, r1
; CHECK-THUMBV7M-NEXT: bx lr
@@ -202,16 +234,16 @@ define i32 @fold_sub301_mul19_i32(i32 %a) {
define i16 @fold_sub301_mul19_i16(i16 %a) {
; CHECK-ARMV6-LABEL: fold_sub301_mul19_i16:
; CHECK-ARMV6: @ %bb.0:
-; CHECK-ARMV6-NEXT: mvn r1, #86
-; CHECK-ARMV6-NEXT: mov r2, #19
-; CHECK-ARMV6-NEXT: sub r1, r1, #5632
-; CHECK-ARMV6-NEXT: mla r0, r0, r2, r1
+; CHECK-ARMV6-NEXT: add r1, r0, r0, lsl #3
+; CHECK-ARMV6-NEXT: add r0, r0, r1, lsl #1
+; CHECK-ARMV6-NEXT: sub r0, r0, #87
+; CHECK-ARMV6-NEXT: sub r0, r0, #5632
; CHECK-ARMV6-NEXT: bx lr
;
; CHECK-ARMV7-LABEL: fold_sub301_mul19_i16:
; CHECK-ARMV7: @ %bb.0:
-; CHECK-ARMV7-NEXT: mov r1, #19
-; CHECK-ARMV7-NEXT: mul r0, r0, r1
+; CHECK-ARMV7-NEXT: add r1, r0, r0, lsl #3
+; CHECK-ARMV7-NEXT: add r0, r0, r1, lsl #1
; CHECK-ARMV7-NEXT: movw r1, #5719
; CHECK-ARMV7-NEXT: sub r0, r0, r1
; CHECK-ARMV7-NEXT: bx lr
@@ -230,8 +262,8 @@ define i16 @fold_sub301_mul19_i16(i16 %a) {
;
; CHECK-THUMBV7M-LABEL: fold_sub301_mul19_i16:
; CHECK-THUMBV7M: @ %bb.0:
-; CHECK-THUMBV7M-NEXT: movs r1, #19
-; CHECK-THUMBV7M-NEXT: muls r0, r1, r0
+; CHECK-THUMBV7M-NEXT: add.w r1, r0, r0, lsl #3
+; CHECK-THUMBV7M-NEXT: add.w r0, r0, r1, lsl #1
; CHECK-THUMBV7M-NEXT: movw r1, #5719
; CHECK-THUMBV7M-NEXT: subs r0, r0, r1
; CHECK-THUMBV7M-NEXT: bx lr
@@ -244,15 +276,16 @@ define i32 @fold_add251_mul253_i32(i32 %a) {
; CHECK-ARMV6-LABEL: fold_add251_mul253_i32:
; CHECK-ARMV6: @ %bb.0:
; CHECK-ARMV6-NEXT: add r0, r0, #251
-; CHECK-ARMV6-NEXT: mov r1, #253
-; CHECK-ARMV6-NEXT: mul r0, r0, r1
+; CHECK-ARMV6-NEXT: sub r1, r0, r0, lsl #6
+; CHECK-ARMV6-NEXT: sub r0, r0, r1, lsl #2
; CHECK-ARMV6-NEXT: bx lr
;
; CHECK-ARMV7-LABEL: fold_add251_mul253_i32:
; CHECK-ARMV7: @ %bb.0:
+; CHECK-ARMV7-NEXT: sub r1, r0, r0, lsl #6
+; CHECK-ARMV7-NEXT: sub r0, r0, r1, lsl #2
; CHECK-ARMV7-NEXT: movw r1, #63503
-; CHECK-ARMV7-NEXT: mov r2, #253
-; CHECK-ARMV7-NEXT: mla r0, r0, r2, r1
+; CHECK-ARMV7-NEXT: add r0, r0, r1
; CHECK-ARMV7-NEXT: bx lr
;
; CHECK-THUMBV6M-LABEL: fold_add251_mul253_i32:
@@ -264,9 +297,10 @@ define i32 @fold_add251_mul253_i32(i32 %a) {
;
; CHECK-THUMBV7M-LABEL: fold_add251_mul253_i32:
; CHECK-THUMBV7M: @ %bb.0:
+; CHECK-THUMBV7M-NEXT: sub.w r1, r0, r0, lsl #6
+; CHECK-THUMBV7M-NEXT: sub.w r0, r0, r1, lsl #2
; CHECK-THUMBV7M-NEXT: movw r1, #63503
-; CHECK-THUMBV7M-NEXT: movs r2, #253
-; CHECK-THUMBV7M-NEXT: mla r0, r0, r2, r1
+; CHECK-THUMBV7M-NEXT: add r0, r1
; CHECK-THUMBV7M-NEXT: bx lr
%b = add i32 %a, 251
%c = mul i32 %b, 253
@@ -277,14 +311,14 @@ define i16 @fold_add251_mul253_i16(i16 %a) {
; CHECK-ARMV6-LABEL: fold_add251_mul253_i16:
; CHECK-ARMV6: @ %bb.0:
; CHECK-ARMV6-NEXT: add r0, r0, #251
-; CHECK-ARMV6-NEXT: mov r1, #253
-; CHECK-ARMV6-NEXT: mul r0, r0, r1
+; CHECK-ARMV6-NEXT: sub r1, r0, r0, lsl #6
+; CHECK-ARMV6-NEXT: sub r0, r0, r1, lsl #2
; CHECK-ARMV6-NEXT: bx lr
;
; CHECK-ARMV7-LABEL: fold_add251_mul253_i16:
; CHECK-ARMV7: @ %bb.0:
-; CHECK-ARMV7-NEXT: mov r1, #253
-; CHECK-ARMV7-NEXT: mul r0, r0, r1
+; CHECK-ARMV7-NEXT: sub r1, r0, r0, lsl #6
+; CHECK-ARMV7-NEXT: sub r0, r0, r1, lsl #2
; CHECK-ARMV7-NEXT: movw r1, #2033
; CHECK-ARMV7-NEXT: sub r0, r0, r1
; CHECK-ARMV7-NEXT: bx lr
@@ -298,8 +332,8 @@ define i16 @fold_add251_mul253_i16(i16 %a) {
;
; CHECK-THUMBV7M-LABEL: fold_add251_mul253_i16:
; CHECK-THUMBV7M: @ %bb.0:
-; CHECK-THUMBV7M-NEXT: movs r1, #253
-; CHECK-THUMBV7M-NEXT: muls r0, r1, r0
+; CHECK-THUMBV7M-NEXT: sub.w r1, r0, r0, lsl #6
+; CHECK-THUMBV7M-NEXT: sub.w r0, r0, r1, lsl #2
; CHECK-THUMBV7M-NEXT: subw r0, r0, #2033
; CHECK-THUMBV7M-NEXT: bx lr
%b = add i16 %a, 251
@@ -311,16 +345,23 @@ define i32 @fold_sub251_mul253_i32(i32 %a) {
; CHECK-ARM-LABEL: fold_sub251_mul253_i32:
; CHECK-ARM: @ %bb.0:
; CHECK-ARM-NEXT: sub r0, r0, #251
-; CHECK-ARM-NEXT: mov r1, #253
-; CHECK-ARM-NEXT: mul r0, r0, r1
+; CHECK-ARM-NEXT: sub r1, r0, r0, lsl #6
+; CHECK-ARM-NEXT: sub r0, r0, r1, lsl #2
; CHECK-ARM-NEXT: bx lr
;
-; CHECK-THUMB-LABEL: fold_sub251_mul253_i32:
-; CHECK-THUMB: @ %bb.0:
-; CHECK-THUMB-NEXT: subs r0, #251
-; CHECK-THUMB-NEXT: movs r1, #253
-; CHECK-THUMB-NEXT: muls r0, r1, r0
-; CHECK-THUMB-NEXT: bx lr
+; CHECK-THUMBV6M-LABEL: fold_sub251_mul253_i32:
+; CHECK-THUMBV6M: @ %bb.0:
+; CHECK-THUMBV6M-NEXT: subs r0, #251
+; CHECK-THUMBV6M-NEXT: movs r1, #253
+; CHECK-THUMBV6M-NEXT: muls r0, r1, r0
+; CHECK-THUMBV6M-NEXT: bx lr
+;
+; CHECK-THUMBV7M-LABEL: fold_sub251_mul253_i32:
+; CHECK-THUMBV7M: @ %bb.0:
+; CHECK-THUMBV7M-NEXT: subs r0, #251
+; CHECK-THUMBV7M-NEXT: sub.w r1, r0, r0, lsl #6
+; CHECK-THUMBV7M-NEXT: sub.w r0, r0, r1, lsl #2
+; CHECK-THUMBV7M-NEXT: bx lr
%b = add i32 %a, -251
%c = mul i32 %b, 253
ret i32 %c
@@ -330,15 +371,16 @@ define i16 @fold_sub251_mul253_i16(i16 %a) {
; CHECK-ARMV6-LABEL: fold_sub251_mul253_i16:
; CHECK-ARMV6: @ %bb.0:
; CHECK-ARMV6-NEXT: sub r0, r0, #251
-; CHECK-ARMV6-NEXT: mov r1, #253
-; CHECK-ARMV6-NEXT: mul r0, r0, r1
+; CHECK-ARMV6-NEXT: sub r1, r0, r0, lsl #6
+; CHECK-ARMV6-NEXT: sub r0, r0, r1, lsl #2
; CHECK-ARMV6-NEXT: bx lr
;
; CHECK-ARMV7-LABEL: fold_sub251_mul253_i16:
; CHECK-ARMV7: @ %bb.0:
+; CHECK-ARMV7-NEXT: sub r1, r0, r0, lsl #6
+; CHECK-ARMV7-NEXT: sub r0, r0, r1, lsl #2
; CHECK-ARMV7-NEXT: movw r1, #2033
-; CHECK-ARMV7-NEXT: mov r2, #253
-; CHECK-ARMV7-NEXT: mla r0, r0, r2, r1
+; CHECK-ARMV7-NEXT: add r0, r0, r1
; CHECK-ARMV7-NEXT: bx lr
;
; CHECK-THUMBV6M-LABEL: fold_sub251_mul253_i16:
@@ -350,8 +392,8 @@ define i16 @fold_sub251_mul253_i16(i16 %a) {
;
; CHECK-THUMBV7M-LABEL: fold_sub251_mul253_i16:
; CHECK-THUMBV7M: @ %bb.0:
-; CHECK-THUMBV7M-NEXT: movs r1, #253
-; CHECK-THUMBV7M-NEXT: muls r0, r1, r0
+; CHECK-THUMBV7M-NEXT: sub.w r1, r0, r0, lsl #6
+; CHECK-THUMBV7M-NEXT: sub.w r0, r0, r1, lsl #2
; CHECK-THUMBV7M-NEXT: addw r0, r0, #2033
; CHECK-THUMBV7M-NEXT: bx lr
%b = add i16 %a, -251
@@ -500,3 +542,5 @@ define i16 @fold_sub251_mul353_i16(i16 %a) {
%c = mul i16 %b, 353
ret i16 %c
}
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-THUMB: {{.*}}
diff --git a/llvm/test/CodeGen/ARM/funnel-shift.ll b/llvm/test/CodeGen/ARM/funnel-shift.ll
index 77fc7095ab0f2..2a8bdf5a7c964 100644
--- a/llvm/test/CodeGen/ARM/funnel-shift.ll
+++ b/llvm/test/CodeGen/ARM/funnel-shift.ll
@@ -69,8 +69,9 @@ define i37 @fshl_i37(i37 %x, i37 %y, i37 %z) {
; SCALAR-NEXT: sub r4, r5, r12
; SCALAR-NEXT: add r4, r12, r4, lsr #1
; SCALAR-NEXT: lsr r12, r4, #5
-; SCALAR-NEXT: mov r4, #37
-; SCALAR-NEXT: mls r5, r12, r4, r5
+; SCALAR-NEXT: add r4, r12, r12, lsl #3
+; SCALAR-NEXT: add r4, r12, r4, lsl #2
+; SCALAR-NEXT: sub r5, r5, r4
; SCALAR-NEXT: mov r4, r0
; SCALAR-NEXT: tst r5, #32
; SCALAR-NEXT: and r12, r5, #31
@@ -111,8 +112,9 @@ define i37 @fshl_i37(i37 %x, i37 %y, i37 %z) {
; NEON-NEXT: sub r4, r12, lr
; NEON-NEXT: add r4, lr, r4, lsr #1
; NEON-NEXT: lsr lr, r4, #5
-; NEON-NEXT: mov r4, #37
-; NEON-NEXT: mls r12, lr, r4, r12
+; NEON-NEXT: add r4, lr, lr, lsl #3
+; NEON-NEXT: add r4, lr, r4, lsl #2
+; NEON-NEXT: sub r12, r12, r4
; NEON-NEXT: mov r4, r0
; NEON-NEXT: tst r12, #32
; NEON-NEXT: and lr, r12, #31
@@ -276,8 +278,9 @@ define i37 @fshr_i37(i37 %x, i37 %y, i37 %z) {
; SCALAR-NEXT: sub r4, r5, r12
; SCALAR-NEXT: add r4, r12, r4, lsr #1
; SCALAR-NEXT: lsr r12, r4, #5
-; SCALAR-NEXT: mov r4, #37
-; SCALAR-NEXT: mls r5, r12, r4, r5
+; SCALAR-NEXT: add r4, r12, r12, lsl #3
+; SCALAR-NEXT: add r4, r12, r4, lsl #2
+; SCALAR-NEXT: sub r5, r5, r4
; SCALAR-NEXT: mov r4, #31
; SCALAR-NEXT: add lr, r5, #27
; SCALAR-NEXT: bic r12, r4, lr
@@ -319,8 +322,9 @@ define i37 @fshr_i37(i37 %x, i37 %y, i37 %z) {
; NEON-NEXT: sub r4, r12, lr
; NEON-NEXT: add r4, lr, r4, lsr #1
; NEON-NEXT: lsr lr, r4, #5
-; NEON-NEXT: mov r4, #37
-; NEON-NEXT: mls r4, lr, r4, r12
+; NEON-NEXT: add r4, lr, lr, lsl #3
+; NEON-NEXT: add r4, lr, r4, lsl #2
+; NEON-NEXT: sub r4, r12, r4
; NEON-NEXT: add r12, r4, #27
; NEON-NEXT: mov r4, #31
; NEON-NEXT: bic lr, r4, r12
diff --git a/llvm/test/CodeGen/ARM/memset-inline.ll b/llvm/test/CodeGen/ARM/memset-inline.ll
index 09469b4128f47..e1000ef444ed8 100644
--- a/llvm/test/CodeGen/ARM/memset-inline.ll
+++ b/llvm/test/CodeGen/ARM/memset-inline.ll
@@ -1,36 +1,97 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
; RUN: llc < %s -mtriple=thumbv7-apple-ios -mcpu=cortex-a8 -pre-RA-sched=source -disable-post-ra | FileCheck %s -check-prefix=CHECK-7A
; RUN: llc < %s -mtriple=thumbv6m -pre-RA-sched=source -disable-post-ra -mattr=+strict-align | FileCheck %s -check-prefix=CHECK-6M
define void @t1(ptr nocapture %c) nounwind optsize {
-entry:
; CHECK-7A-LABEL: t1:
-; CHECK-7A: movs r1, #0
-; CHECK-7A: strd r1, r1, [r0]
-; CHECK-7A: str r1, [r0, #8]
+; CHECK-7A: @ %bb.0: @ %entry
+; CHECK-7A-NEXT: movs r1, #0
+; CHECK-7A-NEXT: strd r1, r1, [r0]
+; CHECK-7A-NEXT: str r1, [r0, #8]
+; CHECK-7A-NEXT: bx lr
+;
; CHECK-6M-LABEL: t1:
-; CHECK-6M: movs r1, #0
-; CHECK-6M: str r1, [r0]
-; CHECK-6M: str r1, [r0, #4]
-; CHECK-6M: str r1, [r0, #8]
+; CHECK-6M: @ %bb.0: @ %entry
+; CHECK-6M-NEXT: movs r1, #0
+; CHECK-6M-NEXT: str r1, [r0]
+; CHECK-6M-NEXT: str r1, [r0, #4]
+; CHECK-6M-NEXT: str r1, [r0, #8]
+; CHECK-6M-NEXT: bx lr
+entry:
call void @llvm.memset.p0.i64(ptr align 8 %c, i8 0, i64 12, i1 false)
ret void
}
define void @t2() nounwind ssp {
-entry:
; CHECK-7A-LABEL: t2:
-; CHECK-7A: vmov.i32 {{q[0-9]+}}, #0x0
-; CHECK-7A: movs r1, #10
-; CHECK-7A: vst1.64 {d{{[0-9]+}}, d{{[0-9]+}}}, [r2], r1
-; CHECK-7A: vst1.16 {d{{[0-9]+}}, d{{[0-9]+}}}, [r2]
+; CHECK-7A: @ %bb.0: @ %entry
+; CHECK-7A-NEXT: push {r4, r7, lr}
+; CHECK-7A-NEXT: add r7, sp, #4
+; CHECK-7A-NEXT: sub sp, #36
+; CHECK-7A-NEXT: mov r4, sp
+; CHECK-7A-NEXT: bfc r4, #0, #3
+; CHECK-7A-NEXT: mov sp, r4
+; CHECK-7A-NEXT: movw r0, :lower16:(L___stack_chk_guard$non_lazy_ptr-(LPC1_0+4))
+; CHECK-7A-NEXT: movt r0, :upper16:(L___stack_chk_guard$non_lazy_ptr-(LPC1_0+4))
+; CHECK-7A-NEXT: LPC1_0:
+; CHECK-7A-NEXT: add r0, pc
+; CHECK-7A-NEXT: ldr r0, [r0]
+; CHECK-7A-NEXT: ldr r0, [r0]
+; CHECK-7A-NEXT: str r0, [sp, #32]
+; CHECK-7A-NEXT: vmov.i32 q8, #0x0
+; CHECK-7A-NEXT: movs r1, #10
+; CHECK-7A-NEXT: mov r0, sp
+; CHECK-7A-NEXT: mov r2, r0
+; CHECK-7A-NEXT: vst1.64 {d16, d17}, [r2], r1
+; CHECK-7A-NEXT: vst1.16 {d16, d17}, [r2]
+; CHECK-7A-NEXT: bl _something
+; CHECK-7A-NEXT: ldr r0, [sp, #32]
+; CHECK-7A-NEXT: movw r1, :lower16:(L___stack_chk_guard$non_lazy_ptr-(LPC1_1+4))
+; CHECK-7A-NEXT: movt r1, :upper16:(L___stack_chk_guard$non_lazy_ptr-(LPC1_1+4))
+; CHECK-7A-NEXT: LPC1_1:
+; CHECK-7A-NEXT: add r1, pc
+; CHECK-7A-NEXT: ldr r1, [r1]
+; CHECK-7A-NEXT: ldr r1, [r1]
+; CHECK-7A-NEXT: cmp r1, r0
+; CHECK-7A-NEXT: ittt eq
+; CHECK-7A-NEXT: subeq r4, r7, #4
+; CHECK-7A-NEXT: moveq sp, r4
+; CHECK-7A-NEXT: popeq {r4, r7, pc}
+; CHECK-7A-NEXT: LBB1_1: @ %entry
+; CHECK-7A-NEXT: bl ___stack_chk_fail
+;
; CHECK-6M-LABEL: t2:
-; CHECK-6M: movs [[REG:r[0-9]+]], #0
-; CHECK-6M-DAG: str [[REG]], [sp, #20]
-; CHECK-6M-DAG: str [[REG]], [sp, #16]
-; CHECK-6M-DAG: str [[REG]], [sp, #12]
-; CHECK-6M-DAG: str [[REG]], [sp, #8]
-; CHECK-6M-DAG: str [[REG]], [sp, #4]
-; CHECK-6M-DAG: str [[REG]], [sp]
+; CHECK-6M: @ %bb.0: @ %entry
+; CHECK-6M-NEXT: push {r7, lr}
+; CHECK-6M-NEXT: sub sp, #32
+; CHECK-6M-NEXT: ldr r0, .LCPI1_0
+; CHECK-6M-NEXT: ldr r0, [r0]
+; CHECK-6M-NEXT: str r0, [sp, #28]
+; CHECK-6M-NEXT: mov r0, sp
+; CHECK-6M-NEXT: movs r1, #0
+; CHECK-6M-NEXT: strh r1, [r0, #24]
+; CHECK-6M-NEXT: str r1, [sp]
+; CHECK-6M-NEXT: str r1, [sp, #4]
+; CHECK-6M-NEXT: str r1, [sp, #8]
+; CHECK-6M-NEXT: str r1, [sp, #12]
+; CHECK-6M-NEXT: str r1, [sp, #16]
+; CHECK-6M-NEXT: str r1, [sp, #20]
+; CHECK-6M-NEXT: bl something
+; CHECK-6M-NEXT: ldr r0, [sp, #28]
+; CHECK-6M-NEXT: ldr r1, .LCPI1_0
+; CHECK-6M-NEXT: ldr r1, [r1]
+; CHECK-6M-NEXT: cmp r1, r0
+; CHECK-6M-NEXT: bne .LBB1_2
+; CHECK-6M-NEXT: @ %bb.1: @ %entry
+; CHECK-6M-NEXT: add sp, #32
+; CHECK-6M-NEXT: pop {r7, pc}
+; CHECK-6M-NEXT: .LBB1_2: @ %entry
+; CHECK-6M-NEXT: bl __stack_chk_fail
+; CHECK-6M-NEXT: .p2align 2
+; CHECK-6M-NEXT: @ %bb.3:
+; CHECK-6M-NEXT: .LCPI1_0:
+; CHECK-6M-NEXT: .long __stack_chk_guard
+entry:
%buf = alloca [26 x i8], align 1
call void @llvm.memset.p0.i32(ptr %buf, i8 0, i32 26, i1 false)
call void @something(ptr %buf) nounwind
@@ -38,16 +99,44 @@ entry:
}
define void @t3(ptr %p) {
-entry:
; CHECK-7A-LABEL: t3:
-; CHECK-7A: muls [[REG:r[0-9]+]],
-; CHECK-7A: str [[REG]],
+; CHECK-7A: @ %bb.0: @ %entry
+; CHECK-7A-NEXT: push {r4, r5, lr}
+; CHECK-7A-NEXT: mov r4, r0
+; CHECK-7A-NEXT: movs r5, #0
+; CHECK-7A-NEXT: LBB2_1: @ %for.body
+; CHECK-7A-NEXT: @ =>This Inner Loop Header: Depth=1
+; CHECK-7A-NEXT: uxtb r0, r5
+; CHECK-7A-NEXT: orr.w r0, r0, r0, lsl #8
+; CHECK-7A-NEXT: orr.w r0, r0, r0, lsl #16
+; CHECK-7A-NEXT: str r0, [r4]
+; CHECK-7A-NEXT: mov r0, r4
+; CHECK-7A-NEXT: bl _something
+; CHECK-7A-NEXT: adds r5, #1
+; CHECK-7A-NEXT: cmp r5, #255
+; CHECK-7A-NEXT: bne LBB2_1
+; CHECK-7A-NEXT: @ %bb.2: @ %for.end
+; CHECK-7A-NEXT: pop {r4, r5, pc}
+;
; CHECK-6M-LABEL: t3:
-; CHECK-6M-NOT: muls
-; CHECK-6M: strb [[REG:r[0-9]+]],
-; CHECK-6M: strb [[REG]],
-; CHECK-6M: strb [[REG]],
-; CHECK-6M: strb [[REG]],
+; CHECK-6M: @ %bb.0: @ %entry
+; CHECK-6M-NEXT: push {r4, r5, r7, lr}
+; CHECK-6M-NEXT: mov r4, r0
+; CHECK-6M-NEXT: movs r5, #0
+; CHECK-6M-NEXT: .LBB2_1: @ %for.body
+; CHECK-6M-NEXT: @ =>This Inner Loop Header: Depth=1
+; CHECK-6M-NEXT: strb r5, [r4, #3]
+; CHECK-6M-NEXT: strb r5, [r4, #2]
+; CHECK-6M-NEXT: strb r5, [r4, #1]
+; CHECK-6M-NEXT: strb r5, [r4]
+; CHECK-6M-NEXT: mov r0, r4
+; CHECK-6M-NEXT: bl something
+; CHECK-6M-NEXT: adds r5, r5, #1
+; CHECK-6M-NEXT: cmp r5, #255
+; CHECK-6M-NEXT: bne .LBB2_1
+; CHECK-6M-NEXT: @ %bb.2: @ %for.end
+; CHECK-6M-NEXT: pop {r4, r5, r7, pc}
+entry:
br label %for.body
for.body:
@@ -64,14 +153,46 @@ for.end:
}
define void @t4(ptr %p) {
-entry:
; CHECK-7A-LABEL: t4:
-; CHECK-7A: muls [[REG:r[0-9]+]],
-; CHECK-7A: str [[REG]],
+; CHECK-7A: @ %bb.0: @ %entry
+; CHECK-7A-NEXT: push {r4, r5, lr}
+; CHECK-7A-NEXT: mov r4, r0
+; CHECK-7A-NEXT: movs r5, #0
+; CHECK-7A-NEXT: LBB3_1: @ %for.body
+; CHECK-7A-NEXT: @ =>This Inner Loop Header: Depth=1
+; CHECK-7A-NEXT: uxtb r0, r5
+; CHECK-7A-NEXT: orr.w r0, r0, r0, lsl #8
+; CHECK-7A-NEXT: orr.w r0, r0, r0, lsl #16
+; CHECK-7A-NEXT: str r0, [r4]
+; CHECK-7A-NEXT: mov r0, r4
+; CHECK-7A-NEXT: bl _something
+; CHECK-7A-NEXT: adds r5, #1
+; CHECK-7A-NEXT: cmp r5, #255
+; CHECK-7A-NEXT: bne LBB3_1
+; CHECK-7A-NEXT: @ %bb.2: @ %for.end
+; CHECK-7A-NEXT: pop {r4, r5, pc}
+;
; CHECK-6M-LABEL: t4:
-; CHECK-6M: muls [[REG:r[0-9]+]],
-; CHECK-6M: strh [[REG]],
-; CHECK-6M: strh [[REG]],
+; CHECK-6M: @ %bb.0: @ %entry
+; CHECK-6M-NEXT: push {r4, r5, r7, lr}
+; CHECK-6M-NEXT: mov r4, r0
+; CHECK-6M-NEXT: movs r5, #0
+; CHECK-6M-NEXT: .LBB3_1: @ %for.body
+; CHECK-6M-NEXT: @ =>This Inner Loop Header: Depth=1
+; CHECK-6M-NEXT: uxtb r0, r5
+; CHECK-6M-NEXT: movs r1, #255
+; CHECK-6M-NEXT: adds r1, #2
+; CHECK-6M-NEXT: muls r1, r0, r1
+; CHECK-6M-NEXT: strh r1, [r4, #2]
+; CHECK-6M-NEXT: strh r1, [r4]
+; CHECK-6M-NEXT: mov r0, r4
+; CHECK-6M-NEXT: bl something
+; CHECK-6M-NEXT: adds r5, r5, #1
+; CHECK-6M-NEXT: cmp r5, #255
+; CHECK-6M-NEXT: bne .LBB3_1
+; CHECK-6M-NEXT: @ %bb.2: @ %for.end
+; CHECK-6M-NEXT: pop {r4, r5, r7, pc}
+entry:
br label %for.body
for.body:
diff --git a/llvm/test/CodeGen/ARM/mul_const.ll b/llvm/test/CodeGen/ARM/mul_const.ll
index adb615af2ab42..a7c31871e6588 100644
--- a/llvm/test/CodeGen/ARM/mul_const.ll
+++ b/llvm/test/CodeGen/ARM/mul_const.ll
@@ -208,14 +208,14 @@ entry:
define i32 @tn12288(i32 %v) nounwind readnone {
; ARM-LABEL: tn12288:
; ARM: @ %bb.0: @ %entry
-; ARM-NEXT: sub r0, r0, r0, lsl #2
-; ARM-NEXT: lsl r0, r0, #12
+; ARM-NEXT: lsl r1, r0, #12
+; ARM-NEXT: sub r0, r1, r0, lsl #14
; ARM-NEXT: mov pc, lr
;
; THUMB2-LABEL: tn12288:
; THUMB2: @ %bb.0: @ %entry
-; THUMB2-NEXT: sub.w r0, r0, r0, lsl #2
-; THUMB2-NEXT: lsls r0, r0, #12
+; THUMB2-NEXT: lsls r1, r0, #12
+; THUMB2-NEXT: sub.w r0, r1, r0, lsl #14
; THUMB2-NEXT: bx lr
;
; THUMB-LABEL: tn12288:
diff --git a/llvm/test/CodeGen/ARM/popcnt.ll b/llvm/test/CodeGen/ARM/popcnt.ll
index a70fdc580ca9b..22b42b296c6eb 100644
--- a/llvm/test/CodeGen/ARM/popcnt.ll
+++ b/llvm/test/CodeGen/ARM/popcnt.ll
@@ -325,18 +325,18 @@ define i32 @ctpop32(i32 %x) nounwind readnone {
; CHECK-LABEL: ctpop32:
; CHECK: @ %bb.0:
; CHECK-NEXT: ldr r1, .LCPI22_0
-; CHECK-NEXT: ldr r2, .LCPI22_3
+; CHECK-NEXT: ldr r3, .LCPI22_2
; CHECK-NEXT: and r1, r1, r0, lsr #1
-; CHECK-NEXT: ldr r12, .LCPI22_1
+; CHECK-NEXT: ldr r2, .LCPI22_1
; CHECK-NEXT: sub r0, r0, r1
-; CHECK-NEXT: ldr r3, .LCPI22_2
-; CHECK-NEXT: and r1, r0, r2
-; CHECK-NEXT: and r0, r2, r0, lsr #2
+; CHECK-NEXT: and r1, r0, r3
+; CHECK-NEXT: and r0, r3, r0, lsr #2
; CHECK-NEXT: add r0, r1, r0
; CHECK-NEXT: add r0, r0, r0, lsr #4
-; CHECK-NEXT: and r0, r0, r12
-; CHECK-NEXT: mul r1, r0, r3
-; CHECK-NEXT: lsr r0, r1, #24
+; CHECK-NEXT: and r0, r0, r2
+; CHECK-NEXT: add r0, r0, r0, lsl #8
+; CHECK-NEXT: add r0, r0, r0, lsl #16
+; CHECK-NEXT: lsr r0, r0, #24
; CHECK-NEXT: mov pc, lr
; CHECK-NEXT: .p2align 2
; CHECK-NEXT: @ %bb.1:
@@ -345,8 +345,6 @@ define i32 @ctpop32(i32 %x) nounwind readnone {
; CHECK-NEXT: .LCPI22_1:
; CHECK-NEXT: .long 252645135 @ 0xf0f0f0f
; CHECK-NEXT: .LCPI22_2:
-; CHECK-NEXT: .long 16843009 @ 0x1010101
-; CHECK-NEXT: .LCPI22_3:
; CHECK-NEXT: .long 858993459 @ 0x33333333
%count = tail call i32 @llvm.ctpop.i32(i32 %x)
ret i32 %count
@@ -355,32 +353,33 @@ define i32 @ctpop32(i32 %x) nounwind readnone {
define i64 @ctpop64(i64 %x) nounwind readnone {
; CHECK-LABEL: ctpop64:
; CHECK: @ %bb.0:
-; CHECK-NEXT: .save {r4, lr}
-; CHECK-NEXT: push {r4, lr}
-; CHECK-NEXT: ldr r2, .LCPI23_0
-; CHECK-NEXT: ldr r3, .LCPI23_3
-; CHECK-NEXT: and r4, r2, r0, lsr #1
-; CHECK-NEXT: and r2, r2, r1, lsr #1
-; CHECK-NEXT: sub r0, r0, r4
+; CHECK-NEXT: .save {r11, lr}
+; CHECK-NEXT: push {r11, lr}
+; CHECK-NEXT: ldr lr, .LCPI23_0
+; CHECK-NEXT: ldr r3, .LCPI23_2
+; CHECK-NEXT: and r2, lr, r1, lsr #1
+; CHECK-NEXT: ldr r12, .LCPI23_1
; CHECK-NEXT: sub r1, r1, r2
-; CHECK-NEXT: and r4, r0, r3
; CHECK-NEXT: and r2, r1, r3
-; CHECK-NEXT: and r0, r3, r0, lsr #2
; CHECK-NEXT: and r1, r3, r1, lsr #2
-; CHECK-NEXT: add r0, r4, r0
-; CHECK-NEXT: ldr lr, .LCPI23_1
; CHECK-NEXT: add r1, r2, r1
-; CHECK-NEXT: ldr r12, .LCPI23_2
-; CHECK-NEXT: add r0, r0, r0, lsr #4
-; CHECK-NEXT: and r0, r0, lr
+; CHECK-NEXT: and r2, lr, r0, lsr #1
+; CHECK-NEXT: sub r0, r0, r2
+; CHECK-NEXT: and r2, r0, r3
; CHECK-NEXT: add r1, r1, r1, lsr #4
-; CHECK-NEXT: mul r2, r0, r12
-; CHECK-NEXT: and r0, r1, lr
-; CHECK-NEXT: mul r1, r0, r12
-; CHECK-NEXT: lsr r0, r2, #24
+; CHECK-NEXT: and r0, r3, r0, lsr #2
+; CHECK-NEXT: and r1, r1, r12
+; CHECK-NEXT: add r0, r2, r0
+; CHECK-NEXT: add r1, r1, r1, lsl #8
+; CHECK-NEXT: add r0, r0, r0, lsr #4
+; CHECK-NEXT: and r0, r0, r12
+; CHECK-NEXT: add r1, r1, r1, lsl #16
+; CHECK-NEXT: add r0, r0, r0, lsl #8
+; CHECK-NEXT: add r0, r0, r0, lsl #16
+; CHECK-NEXT: lsr r0, r0, #24
; CHECK-NEXT: add r0, r0, r1, lsr #24
; CHECK-NEXT: mov r1, #0
-; CHECK-NEXT: pop {r4, lr}
+; CHECK-NEXT: pop {r11, lr}
; CHECK-NEXT: mov pc, lr
; CHECK-NEXT: .p2align 2
; CHECK-NEXT: @ %bb.1:
@@ -389,8 +388,6 @@ define i64 @ctpop64(i64 %x) nounwind readnone {
; CHECK-NEXT: .LCPI23_1:
; CHECK-NEXT: .long 252645135 @ 0xf0f0f0f
; CHECK-NEXT: .LCPI23_2:
-; CHECK-NEXT: .long 16843009 @ 0x1010101
-; CHECK-NEXT: .LCPI23_3:
; CHECK-NEXT: .long 858993459 @ 0x33333333
%count = tail call i64 @llvm.ctpop.i64(i64 %x)
ret i64 %count
diff --git a/llvm/test/CodeGen/ARM/select-imm.ll b/llvm/test/CodeGen/ARM/select-imm.ll
index 186276b50ceeb..2c9b72f6ba512 100644
--- a/llvm/test/CodeGen/ARM/select-imm.ll
+++ b/llvm/test/CodeGen/ARM/select-imm.ll
@@ -698,16 +698,15 @@ define i1 @t11() {
; ARMT2-NEXT: sub sp, sp, #4
; ARMT2-NEXT: ldr r1, [sp]
; ARMT2-NEXT: mov r0, #33
-; ARMT2-NEXT: movw r2, #39322
-; ARMT2-NEXT: movt r2, #6553
+; ARMT2-NEXT: mov r12, #10
+; ARMT2-NEXT: movw r3, #39322
; ARMT2-NEXT: bfi r1, r0, #0, #12
-; ARMT2-NEXT: mov r0, #10
-; ARMT2-NEXT: bfi r1, r0, #12, #13
-; ARMT2-NEXT: mov r0, r1
-; ARMT2-NEXT: bfc r0, #12, #20
-; ARMT2-NEXT: umull r2, r3, r0, r2
-; ARMT2-NEXT: add r2, r3, r3, lsl #2
-; ARMT2-NEXT: sub r0, r0, r2, lsl #1
+; ARMT2-NEXT: movt r3, #6553
+; ARMT2-NEXT: bfi r1, r12, #12, #13
+; ARMT2-NEXT: mov r2, r1
+; ARMT2-NEXT: bfc r2, #12, #20
+; ARMT2-NEXT: umull r3, r0, r2, r3
+; ARMT2-NEXT: mls r0, r0, r12, r2
; ARMT2-NEXT: movw r2, #40960
; ARMT2-NEXT: movt r2, #65024
; ARMT2-NEXT: and r1, r1, r2
diff --git a/llvm/test/CodeGen/ARM/srem-seteq-illegal-types.ll b/llvm/test/CodeGen/ARM/srem-seteq-illegal-types.ll
index 973362462f735..4600a6c141e02 100644
--- a/llvm/test/CodeGen/ARM/srem-seteq-illegal-types.ll
+++ b/llvm/test/CodeGen/ARM/srem-seteq-illegal-types.ll
@@ -119,8 +119,9 @@ define i1 @test_srem_even(i4 %X) nounwind {
; ARM5-NEXT: add r1, r1, r1, lsl #1
; ARM5-NEXT: lsr r2, r1, #4
; ARM5-NEXT: add r1, r2, r1, lsr #31
-; ARM5-NEXT: add r1, r1, r1, lsl #1
-; ARM5-NEXT: sub r0, r0, r1, lsl #1
+; ARM5-NEXT: mov r2, #6
+; ARM5-NEXT: mul r3, r1, r2
+; ARM5-NEXT: sub r0, r0, r3
; ARM5-NEXT: and r0, r0, #15
; ARM5-NEXT: sub r0, r0, #1
; ARM5-NEXT: clz r0, r0
@@ -134,8 +135,9 @@ define i1 @test_srem_even(i4 %X) nounwind {
; ARM6-NEXT: add r1, r1, r1, lsl #1
; ARM6-NEXT: lsr r2, r1, #4
; ARM6-NEXT: add r1, r2, r1, lsr #31
-; ARM6-NEXT: add r1, r1, r1, lsl #1
-; ARM6-NEXT: sub r0, r0, r1, lsl #1
+; ARM6-NEXT: mov r2, #6
+; ARM6-NEXT: mul r1, r1, r2
+; ARM6-NEXT: sub r0, r0, r1
; ARM6-NEXT: and r0, r0, #15
; ARM6-NEXT: sub r0, r0, #1
; ARM6-NEXT: clz r0, r0
@@ -148,8 +150,8 @@ define i1 @test_srem_even(i4 %X) nounwind {
; ARM7-NEXT: add r1, r1, r1, lsl #1
; ARM7-NEXT: lsr r2, r1, #4
; ARM7-NEXT: add r1, r2, r1, lsr #31
-; ARM7-NEXT: add r1, r1, r1, lsl #1
-; ARM7-NEXT: sub r0, r0, r1, lsl #1
+; ARM7-NEXT: mov r2, #6
+; ARM7-NEXT: mls r0, r1, r2, r0
; ARM7-NEXT: and r0, r0, #15
; ARM7-NEXT: sub r0, r0, #1
; ARM7-NEXT: clz r0, r0
@@ -162,8 +164,8 @@ define i1 @test_srem_even(i4 %X) nounwind {
; ARM8-NEXT: add r1, r1, r1, lsl #1
; ARM8-NEXT: lsr r2, r1, #4
; ARM8-NEXT: add r1, r2, r1, lsr #31
-; ARM8-NEXT: add r1, r1, r1, lsl #1
-; ARM8-NEXT: sub r0, r0, r1, lsl #1
+; ARM8-NEXT: mov r2, #6
+; ARM8-NEXT: mls r0, r1, r2, r0
; ARM8-NEXT: and r0, r0, #15
; ARM8-NEXT: sub r0, r0, #1
; ARM8-NEXT: clz r0, r0
@@ -176,8 +178,8 @@ define i1 @test_srem_even(i4 %X) nounwind {
; NEON7-NEXT: add r1, r1, r1, lsl #1
; NEON7-NEXT: lsr r2, r1, #4
; NEON7-NEXT: add r1, r2, r1, lsr #31
-; NEON7-NEXT: add r1, r1, r1, lsl #1
-; NEON7-NEXT: sub r0, r0, r1, lsl #1
+; NEON7-NEXT: mov r2, #6
+; NEON7-NEXT: mls r0, r1, r2, r0
; NEON7-NEXT: and r0, r0, #15
; NEON7-NEXT: sub r0, r0, #1
; NEON7-NEXT: clz r0, r0
@@ -190,8 +192,8 @@ define i1 @test_srem_even(i4 %X) nounwind {
; NEON8-NEXT: add r1, r1, r1, lsl #1
; NEON8-NEXT: lsr r2, r1, #4
; NEON8-NEXT: add r1, r2, r1, lsr #31
-; NEON8-NEXT: add r1, r1, r1, lsl #1
-; NEON8-NEXT: sub r0, r0, r1, lsl #1
+; NEON8-NEXT: mov r2, #6
+; NEON8-NEXT: mls r0, r1, r2, r0
; NEON8-NEXT: and r0, r0, #15
; NEON8-NEXT: sub r0, r0, #1
; NEON8-NEXT: clz r0, r0
diff --git a/llvm/test/CodeGen/ARM/urem-seteq-illegal-types.ll b/llvm/test/CodeGen/ARM/urem-seteq-illegal-types.ll
index 9f703567f122f..919a209d9946d 100644
--- a/llvm/test/CodeGen/ARM/urem-seteq-illegal-types.ll
+++ b/llvm/test/CodeGen/ARM/urem-seteq-illegal-types.ll
@@ -193,18 +193,18 @@ define i1 @test_urem_even(i27 %X) nounwind {
define i1 @test_urem_odd_setne(i4 %X) nounwind {
; ARM5-LABEL: test_urem_odd_setne:
; ARM5: @ %bb.0:
-; ARM5-NEXT: mov r1, #13
-; ARM5-NEXT: mul r2, r0, r1
+; ARM5-NEXT: add r1, r0, r0, lsl #1
+; ARM5-NEXT: add r0, r0, r1, lsl #2
+; ARM5-NEXT: and r1, r0, #15
; ARM5-NEXT: mov r0, #0
-; ARM5-NEXT: and r1, r2, #15
; ARM5-NEXT: cmp r1, #3
; ARM5-NEXT: movhi r0, #1
; ARM5-NEXT: bx lr
;
; ARM6-LABEL: test_urem_odd_setne:
; ARM6: @ %bb.0:
-; ARM6-NEXT: mov r1, #13
-; ARM6-NEXT: mul r0, r0, r1
+; ARM6-NEXT: add r1, r0, r0, lsl #1
+; ARM6-NEXT: add r0, r0, r1, lsl #2
; ARM6-NEXT: and r1, r0, #15
; ARM6-NEXT: mov r0, #0
; ARM6-NEXT: cmp r1, #3
@@ -213,8 +213,8 @@ define i1 @test_urem_odd_setne(i4 %X) nounwind {
;
; ARM7-LABEL: test_urem_odd_setne:
; ARM7: @ %bb.0:
-; ARM7-NEXT: mov r1, #13
-; ARM7-NEXT: mul r0, r0, r1
+; ARM7-NEXT: add r1, r0, r0, lsl #1
+; ARM7-NEXT: add r0, r0, r1, lsl #2
; ARM7-NEXT: and r1, r0, #15
; ARM7-NEXT: mov r0, #0
; ARM7-NEXT: cmp r1, #3
@@ -223,8 +223,8 @@ define i1 @test_urem_odd_setne(i4 %X) nounwind {
;
; ARM8-LABEL: test_urem_odd_setne:
; ARM8: @ %bb.0:
-; ARM8-NEXT: mov r1, #13
-; ARM8-NEXT: mul r0, r0, r1
+; ARM8-NEXT: add r1, r0, r0, lsl #1
+; ARM8-NEXT: add r0, r0, r1, lsl #2
; ARM8-NEXT: and r1, r0, #15
; ARM8-NEXT: mov r0, #0
; ARM8-NEXT: cmp r1, #3
@@ -233,8 +233,8 @@ define i1 @test_urem_odd_setne(i4 %X) nounwind {
;
; NEON7-LABEL: test_urem_odd_setne:
; NEON7: @ %bb.0:
-; NEON7-NEXT: mov r1, #13
-; NEON7-NEXT: mul r0, r0, r1
+; NEON7-NEXT: add r1, r0, r0, lsl #1
+; NEON7-NEXT: add r0, r0, r1, lsl #2
; NEON7-NEXT: and r1, r0, #15
; NEON7-NEXT: mov r0, #0
; NEON7-NEXT: cmp r1, #3
@@ -243,8 +243,8 @@ define i1 @test_urem_odd_setne(i4 %X) nounwind {
;
; NEON8-LABEL: test_urem_odd_setne:
; NEON8: @ %bb.0:
-; NEON8-NEXT: mov r1, #13
-; NEON8-NEXT: mul r0, r0, r1
+; NEON8-NEXT: add r1, r0, r0, lsl #1
+; NEON8-NEXT: add r0, r0, r1, lsl #2
; NEON8-NEXT: and r1, r0, #15
; NEON8-NEXT: mov r0, #0
; NEON8-NEXT: cmp r1, #3
diff --git a/llvm/test/CodeGen/Thumb2/mve-gather-scatter-optimisation.ll b/llvm/test/CodeGen/Thumb2/mve-gather-scatter-optimisation.ll
index eedca2cd4a5d3..3f63e6daf6e1b 100644
--- a/llvm/test/CodeGen/Thumb2/mve-gather-scatter-optimisation.ll
+++ b/llvm/test/CodeGen/Thumb2/mve-gather-scatter-optimisation.ll
@@ -864,16 +864,15 @@ define hidden arm_aapcs_vfpcc i32 @arm_depthwise_conv_s8(ptr nocapture readonly
; CHECK-NEXT: .pad #24
; CHECK-NEXT: sub sp, #24
; CHECK-NEXT: ldrd r2, r7, [sp, #136]
-; CHECK-NEXT: add.w r8, r7, #10
+; CHECK-NEXT: add.w r12, r7, #10
; CHECK-NEXT: adr r7, .LCPI11_0
; CHECK-NEXT: ldr r1, [sp, #128]
; CHECK-NEXT: vdup.32 q0, r2
; CHECK-NEXT: vldrw.u32 q1, [r7]
-; CHECK-NEXT: movs r4, #0
+; CHECK-NEXT: mov.w r11, #0
; CHECK-NEXT: mov.w r10, #6
-; CHECK-NEXT: movs r6, #11
; CHECK-NEXT: vshl.i32 q0, q0, #2
-; CHECK-NEXT: movs r5, #0
+; CHECK-NEXT: movs r6, #0
; CHECK-NEXT: .LBB11_1: @ %for.body10.i
; CHECK-NEXT: @ =>This Loop Header: Depth=1
; CHECK-NEXT: @ Child Loop BB11_2 Depth 2
@@ -881,14 +880,14 @@ define hidden arm_aapcs_vfpcc i32 @arm_depthwise_conv_s8(ptr nocapture readonly
; CHECK-NEXT: @ Child Loop BB11_4 Depth 4
; CHECK-NEXT: @ Child Loop BB11_5 Depth 5
; CHECK-NEXT: mov.w r9, #0
-; CHECK-NEXT: str r5, [sp, #4] @ 4-byte Spill
+; CHECK-NEXT: str r6, [sp, #4] @ 4-byte Spill
; CHECK-NEXT: .LBB11_2: @ %for.cond22.preheader.i
; CHECK-NEXT: @ Parent Loop BB11_1 Depth=1
; CHECK-NEXT: @ => This Loop Header: Depth=2
; CHECK-NEXT: @ Child Loop BB11_3 Depth 3
; CHECK-NEXT: @ Child Loop BB11_4 Depth 4
; CHECK-NEXT: @ Child Loop BB11_5 Depth 5
-; CHECK-NEXT: movs r7, #0
+; CHECK-NEXT: movs r6, #0
; CHECK-NEXT: vdup.32 q2, r9
; CHECK-NEXT: vstrw.32 q2, [sp, #8] @ 16-byte Spill
; CHECK-NEXT: .LBB11_3: @ %for.body27.i
@@ -898,23 +897,24 @@ define hidden arm_aapcs_vfpcc i32 @arm_depthwise_conv_s8(ptr nocapture readonly
; CHECK-NEXT: @ Child Loop BB11_4 Depth 4
; CHECK-NEXT: @ Child Loop BB11_5 Depth 5
; CHECK-NEXT: dls lr, r10
-; CHECK-NEXT: mov.w r12, #0
-; CHECK-NEXT: mov.w r11, #4
-; CHECK-NEXT: vdup.32 q3, r7
+; CHECK-NEXT: movs r4, #0
+; CHECK-NEXT: movs r5, #4
+; CHECK-NEXT: vdup.32 q3, r6
; CHECK-NEXT: .LBB11_4: @ %for.body78.us.i
; CHECK-NEXT: @ Parent Loop BB11_1 Depth=1
; CHECK-NEXT: @ Parent Loop BB11_2 Depth=2
; CHECK-NEXT: @ Parent Loop BB11_3 Depth=3
; CHECK-NEXT: @ => This Loop Header: Depth=4
; CHECK-NEXT: @ Child Loop BB11_5 Depth 5
-; CHECK-NEXT: mul r5, r11, r6
+; CHECK-NEXT: add.w r7, r5, r5, lsl #2
; CHECK-NEXT: vmov q4, q3
-; CHECK-NEXT: vadd.i32 q5, q1, r5
+; CHECK-NEXT: add.w r7, r5, r7, lsl #1
+; CHECK-NEXT: vadd.i32 q5, q1, r7
+; CHECK-NEXT: add.w r8, r7, #113
; CHECK-NEXT: vmla.i32 q4, q5, r2
; CHECK-NEXT: vldrw.u32 q5, [sp, #8] @ 16-byte Reload
-; CHECK-NEXT: adds r5, #113
-; CHECK-NEXT: vadd.i32 q6, q1, r5
-; CHECK-NEXT: mov r5, r8
+; CHECK-NEXT: vadd.i32 q6, q1, r8
+; CHECK-NEXT: mov r7, r12
; CHECK-NEXT: vmla.i32 q5, q6, r2
; CHECK-NEXT: .LBB11_5: @ %vector.body
; CHECK-NEXT: @ Parent Loop BB11_1 Depth=1
@@ -927,20 +927,20 @@ define hidden arm_aapcs_vfpcc i32 @arm_depthwise_conv_s8(ptr nocapture readonly
; CHECK-NEXT: vldrb.s32 q5, [r1, q4]
; CHECK-NEXT: vadd.i32 q6, q4, q0
; CHECK-NEXT: vadd.i32 q2, q2, r2
-; CHECK-NEXT: subs r5, #4
-; CHECK-NEXT: vmlava.u32 r12, q2, q5
+; CHECK-NEXT: subs r7, #4
+; CHECK-NEXT: vmlava.u32 r4, q2, q5
; CHECK-NEXT: vmov q5, q7
; CHECK-NEXT: vmov q4, q6
; CHECK-NEXT: bne .LBB11_5
; CHECK-NEXT: @ %bb.6: @ %middle.block
; CHECK-NEXT: @ in Loop: Header=BB11_4 Depth=4
-; CHECK-NEXT: add.w r11, r11, #1
+; CHECK-NEXT: adds r5, #1
; CHECK-NEXT: le lr, .LBB11_4
; CHECK-NEXT: @ %bb.7: @ %for.cond.cleanup77.i
; CHECK-NEXT: @ in Loop: Header=BB11_3 Depth=3
-; CHECK-NEXT: adds r7, #1
-; CHECK-NEXT: adds r4, #1
-; CHECK-NEXT: cmp r7, r2
+; CHECK-NEXT: adds r6, #1
+; CHECK-NEXT: add.w r11, r11, #1
+; CHECK-NEXT: cmp r6, r2
; CHECK-NEXT: bne .LBB11_3
; CHECK-NEXT: @ %bb.8: @ %for.cond.cleanup26.i
; CHECK-NEXT: @ in Loop: Header=BB11_2 Depth=2
@@ -949,12 +949,12 @@ define hidden arm_aapcs_vfpcc i32 @arm_depthwise_conv_s8(ptr nocapture readonly
; CHECK-NEXT: bne .LBB11_2
; CHECK-NEXT: @ %bb.9: @ %for.cond.cleanup20.i
; CHECK-NEXT: @ in Loop: Header=BB11_1 Depth=1
-; CHECK-NEXT: ldr r5, [sp, #4] @ 4-byte Reload
+; CHECK-NEXT: ldr r6, [sp, #4] @ 4-byte Reload
; CHECK-NEXT: ldr r7, [sp, #180]
-; CHECK-NEXT: adds r5, #1
-; CHECK-NEXT: cmp r5, r7
+; CHECK-NEXT: adds r6, #1
+; CHECK-NEXT: cmp r6, r7
; CHECK-NEXT: it eq
-; CHECK-NEXT: moveq r5, #0
+; CHECK-NEXT: moveq r6, #0
; CHECK-NEXT: b .LBB11_1
; CHECK-NEXT: .p2align 4
; CHECK-NEXT: @ %bb.10:
diff --git a/llvm/test/CodeGen/Thumb2/mve-memtp-branch.ll b/llvm/test/CodeGen/Thumb2/mve-memtp-branch.ll
index b5c9b903e1841..cc4ce97d5798b 100644
--- a/llvm/test/CodeGen/Thumb2/mve-memtp-branch.ll
+++ b/llvm/test/CodeGen/Thumb2/mve-memtp-branch.ll
@@ -14,10 +14,9 @@ define i32 @a(i8 zeroext %b, ptr nocapture readonly %c, ptr nocapture readonly %
; CHECK-NEXT: cmp r0, #2
; CHECK-NEXT: bls.w .LBB0_12
; CHECK-NEXT: @ %bb.1: @ %for.body.us.preheader
-; CHECK-NEXT: movw r5, :lower16:arr_183
+; CHECK-NEXT: movw r12, :lower16:arr_183
; CHECK-NEXT: movs r3, #0
-; CHECK-NEXT: movt r5, :upper16:arr_183
-; CHECK-NEXT: mov.w r12, #19
+; CHECK-NEXT: movt r12, :upper16:arr_183
; CHECK-NEXT: vmov.i32 q0, #0x0
; CHECK-NEXT: vmov.i32 q1, #0x0
; CHECK-NEXT: vmov.i32 q2, #0x0
@@ -33,11 +32,13 @@ define i32 @a(i8 zeroext %b, ptr nocapture readonly %c, ptr nocapture readonly %
; CHECK-NEXT: @ Child Loop BB0_8 Depth 2
; CHECK-NEXT: @ Child Loop BB0_11 Depth 2
; CHECK-NEXT: ldr.w r0, [r2, r3, lsl #2]
+; CHECK-NEXT: add.w r4, r3, r3, lsl #3
; CHECK-NEXT: cmp r0, #0
; CHECK-NEXT: ite ne
; CHECK-NEXT: ldrbne r0, [r1, r3]
; CHECK-NEXT: moveq r0, #0
-; CHECK-NEXT: mla r3, r3, r12, r5
+; CHECK-NEXT: add.w r3, r3, r4, lsl #1
+; CHECK-NEXT: add r3, r12
; CHECK-NEXT: add r3, r0
; CHECK-NEXT: rsb.w r0, r0, #108
; CHECK-NEXT: wlstp.8 lr, r0, .LBB0_5
@@ -52,7 +53,7 @@ define i32 @a(i8 zeroext %b, ptr nocapture readonly %c, ptr nocapture readonly %
; CHECK-NEXT: ite ne
; CHECK-NEXT: ldrbne r0, [r1, #1]
; CHECK-NEXT: moveq r0, #0
-; CHECK-NEXT: adds r3, r5, r0
+; CHECK-NEXT: add.w r3, r12, r0
; CHECK-NEXT: rsb.w r0, r0, #108
; CHECK-NEXT: adds r3, #19
; CHECK-NEXT: wlstp.8 lr, r0, .LBB0_7
@@ -67,7 +68,7 @@ define i32 @a(i8 zeroext %b, ptr nocapture readonly %c, ptr nocapture readonly %
; CHECK-NEXT: ite ne
; CHECK-NEXT: ldrbne r0, [r1, #1]
; CHECK-NEXT: moveq r0, #0
-; CHECK-NEXT: adds r3, r5, r0
+; CHECK-NEXT: add.w r3, r12, r0
; CHECK-NEXT: rsb.w r0, r0, #108
; CHECK-NEXT: adds r3, #19
; CHECK-NEXT: wlstp.8 lr, r0, .LBB0_9
@@ -82,12 +83,12 @@ define i32 @a(i8 zeroext %b, ptr nocapture readonly %c, ptr nocapture readonly %
; CHECK-NEXT: ite ne
; CHECK-NEXT: ldrbne r0, [r1, #1]
; CHECK-NEXT: moveq r0, #0
-; CHECK-NEXT: adds r3, r5, r0
+; CHECK-NEXT: add.w r3, r12, r0
; CHECK-NEXT: rsb.w r0, r0, #108
-; CHECK-NEXT: add.w r4, r0, #15
+; CHECK-NEXT: add.w r5, r0, #15
; CHECK-NEXT: adds r3, #19
-; CHECK-NEXT: lsrs r4, r4, #4
-; CHECK-NEXT: cmp.w r4, #0
+; CHECK-NEXT: lsrs r5, r5, #4
+; CHECK-NEXT: cmp.w r5, #0
; CHECK-NEXT: beq .LBB0_2
; CHECK-NEXT: @ %bb.10: @ %land.end.us.2
; CHECK-NEXT: @ in Loop: Header=BB0_3 Depth=1
@@ -132,13 +133,13 @@ define i32 @a(i8 zeroext %b, ptr nocapture readonly %c, ptr nocapture readonly %
; CHECK-NEXT: ite ne
; CHECK-NEXT: ldrbne r3, [r1, #1]
; CHECK-NEXT: moveq r3, #0
-; CHECK-NEXT: add.w r5, r12, r3
+; CHECK-NEXT: add.w r4, r12, r3
; CHECK-NEXT: rsb.w r3, r3, #108
-; CHECK-NEXT: add.w r4, r5, #19
+; CHECK-NEXT: add.w r5, r4, #19
; CHECK-NEXT: wlstp.8 lr, r3, .LBB0_17
; CHECK-NEXT: .LBB0_16: @ Parent Loop BB0_14 Depth=1
; CHECK-NEXT: @ => This Inner Loop Header: Depth=2
-; CHECK-NEXT: vstrb.8 q0, [r4], #16
+; CHECK-NEXT: vstrb.8 q0, [r5], #16
; CHECK-NEXT: letp lr, .LBB0_16
; CHECK-NEXT: .LBB0_17: @ %for.cond.backedge
; CHECK-NEXT: @ in Loop: Header=BB0_14 Depth=1
diff --git a/llvm/test/CodeGen/Thumb2/mve-postinc-dct.ll b/llvm/test/CodeGen/Thumb2/mve-postinc-dct.ll
index 2587a0bb6e00b..6f51b3887afcc 100644
--- a/llvm/test/CodeGen/Thumb2/mve-postinc-dct.ll
+++ b/llvm/test/CodeGen/Thumb2/mve-postinc-dct.ll
@@ -1013,54 +1013,53 @@ define void @DCT_mve7(ptr nocapture readonly %S, ptr nocapture readonly %pIn, pt
; CHECK-NEXT: cmp r1, #2
; CHECK-NEXT: blo.w .LBB6_5
; CHECK-NEXT: @ %bb.1: @ %for.body.preheader
-; CHECK-NEXT: ldr.w r10, [r0, #8]
+; CHECK-NEXT: ldr.w r9, [r0, #8]
+; CHECK-NEXT: movs r4, #1
; CHECK-NEXT: ldr r1, [r0]
-; CHECK-NEXT: add.w r0, r10, #3
+; CHECK-NEXT: lsl.w r0, r9, #5
+; CHECK-NEXT: add.w r8, r1, r9, lsl #2
+; CHECK-NEXT: sub.w r0, r0, r9, lsl #2
+; CHECK-NEXT: str r0, [sp, #4] @ 4-byte Spill
+; CHECK-NEXT: add.w r0, r9, #3
+; CHECK-NEXT: lsl.w r6, r9, #2
; CHECK-NEXT: bic r0, r0, #3
-; CHECK-NEXT: add.w r9, r1, r10, lsl #2
-; CHECK-NEXT: subs r1, r0, #4
-; CHECK-NEXT: movs r0, #1
-; CHECK-NEXT: lsl.w r5, r10, #2
-; CHECK-NEXT: add.w r1, r0, r1, lsr #2
-; CHECK-NEXT: str r1, [sp, #4] @ 4-byte Spill
-; CHECK-NEXT: rsb r1, r10, r10, lsl #3
-; CHECK-NEXT: lsls r1, r1, #2
-; CHECK-NEXT: str r1, [sp] @ 4-byte Spill
+; CHECK-NEXT: subs r0, #4
+; CHECK-NEXT: add.w r0, r4, r0, lsr #2
+; CHECK-NEXT: str r0, [sp] @ 4-byte Spill
; CHECK-NEXT: .LBB6_2: @ %for.body
; CHECK-NEXT: @ =>This Loop Header: Depth=1
; CHECK-NEXT: @ Child Loop BB6_3 Depth 2
; CHECK-NEXT: ldr r1, [sp, #12] @ 4-byte Reload
-; CHECK-NEXT: adds r4, r0, #2
-; CHECK-NEXT: add.w r8, r0, #1
-; CHECK-NEXT: ldr r7, [sp, #4] @ 4-byte Reload
+; CHECK-NEXT: add.w r12, r4, #1
+; CHECK-NEXT: ldr r7, [sp] @ 4-byte Reload
; CHECK-NEXT: vmov.i32 q0, #0x0
; CHECK-NEXT: vmov.i32 q2, #0x0
-; CHECK-NEXT: mov r3, r9
+; CHECK-NEXT: mov r3, r8
; CHECK-NEXT: vmov.i32 q4, #0x0
; CHECK-NEXT: vmov.i32 q5, #0x0
; CHECK-NEXT: vmov.i32 q3, #0x0
; CHECK-NEXT: vmov.i32 q6, #0x0
; CHECK-NEXT: vmov.i32 q1, #0x0
-; CHECK-NEXT: mov r12, r10
+; CHECK-NEXT: mov r0, r9
; CHECK-NEXT: vstrw.32 q0, [sp, #32] @ 16-byte Spill
; CHECK-NEXT: dls lr, r7
; CHECK-NEXT: .LBB6_3: @ %vector.body
; CHECK-NEXT: @ Parent Loop BB6_2 Depth=1
; CHECK-NEXT: @ => This Inner Loop Header: Depth=2
-; CHECK-NEXT: vctp.32 r12
-; CHECK-NEXT: add.w r11, r3, r5
+; CHECK-NEXT: vctp.32 r0
+; CHECK-NEXT: add.w r10, r3, r6
; CHECK-NEXT: vpstt
; CHECK-NEXT: vldrwt.u32 q7, [r1], #16
; CHECK-NEXT: vldrwt.u32 q0, [r3], #16
-; CHECK-NEXT: add.w r6, r11, r5
-; CHECK-NEXT: sub.w r12, r12, #4
+; CHECK-NEXT: add.w r11, r10, r6
+; CHECK-NEXT: subs r0, #4
; CHECK-NEXT: vpstt
; CHECK-NEXT: vfmat.f32 q5, q0, q7
-; CHECK-NEXT: vldrwt.u32 q0, [r11]
-; CHECK-NEXT: adds r7, r6, r5
+; CHECK-NEXT: vldrwt.u32 q0, [r10]
+; CHECK-NEXT: add.w r5, r11, r6
; CHECK-NEXT: vpstt
; CHECK-NEXT: vfmat.f32 q6, q0, q7
-; CHECK-NEXT: vldrwt.u32 q0, [r6]
+; CHECK-NEXT: vldrwt.u32 q0, [r11]
; CHECK-NEXT: vstrw.32 q6, [sp, #16] @ 16-byte Spill
; CHECK-NEXT: vmov q6, q5
; CHECK-NEXT: vpst
@@ -1069,24 +1068,24 @@ define void @DCT_mve7(ptr nocapture readonly %S, ptr nocapture readonly %pIn, pt
; CHECK-NEXT: vmov q4, q3
; CHECK-NEXT: vmov q3, q1
; CHECK-NEXT: vpst
-; CHECK-NEXT: vldrwt.u32 q0, [r7]
+; CHECK-NEXT: vldrwt.u32 q0, [r5]
; CHECK-NEXT: vldrw.u32 q1, [sp, #32] @ 16-byte Reload
-; CHECK-NEXT: adds r6, r7, r5
+; CHECK-NEXT: adds r7, r5, r6
; CHECK-NEXT: vpstt
; CHECK-NEXT: vfmat.f32 q1, q0, q7
-; CHECK-NEXT: vldrwt.u32 q0, [r6]
-; CHECK-NEXT: adds r7, r6, r5
+; CHECK-NEXT: vldrwt.u32 q0, [r7]
+; CHECK-NEXT: adds r5, r7, r6
; CHECK-NEXT: vstrw.32 q1, [sp, #32] @ 16-byte Spill
; CHECK-NEXT: vmov q1, q3
; CHECK-NEXT: vmov q3, q4
; CHECK-NEXT: vpstt
; CHECK-NEXT: vfmat.f32 q3, q0, q7
-; CHECK-NEXT: vldrwt.u32 q0, [r7]
+; CHECK-NEXT: vldrwt.u32 q0, [r5]
; CHECK-NEXT: vmov q4, q5
-; CHECK-NEXT: adds r6, r7, r5
+; CHECK-NEXT: adds r7, r5, r6
; CHECK-NEXT: vpstt
; CHECK-NEXT: vfmat.f32 q4, q0, q7
-; CHECK-NEXT: vldrwt.u32 q0, [r6]
+; CHECK-NEXT: vldrwt.u32 q0, [r7]
; CHECK-NEXT: vmov q5, q6
; CHECK-NEXT: vldrw.u32 q6, [sp, #16] @ 16-byte Reload
; CHECK-NEXT: vpst
@@ -1095,7 +1094,7 @@ define void @DCT_mve7(ptr nocapture readonly %S, ptr nocapture readonly %pIn, pt
; CHECK-NEXT: @ %bb.4: @ %middle.block
; CHECK-NEXT: @ in Loop: Header=BB6_2 Depth=1
; CHECK-NEXT: vadd.f32 s0, s26, s27
-; CHECK-NEXT: add.w r1, r2, r8, lsl #2
+; CHECK-NEXT: add.w r0, r2, r12, lsl #2
; CHECK-NEXT: vadd.f32 s2, s24, s25
; CHECK-NEXT: vadd.f32 s1, s22, s23
; CHECK-NEXT: vadd.f32 s3, s20, s21
@@ -1103,42 +1102,43 @@ define void @DCT_mve7(ptr nocapture readonly %S, ptr nocapture readonly %pIn, pt
; CHECK-NEXT: vadd.f32 s4, s4, s5
; CHECK-NEXT: vadd.f32 s10, s10, s11
; CHECK-NEXT: vadd.f32 s8, s8, s9
+; CHECK-NEXT: vadd.f32 s0, s2, s0
; CHECK-NEXT: vadd.f32 s9, s18, s19
; CHECK-NEXT: vadd.f32 s11, s16, s17
; CHECK-NEXT: vldrw.u32 q4, [sp, #32] @ 16-byte Reload
-; CHECK-NEXT: vadd.f32 s0, s2, s0
+; CHECK-NEXT: vadd.f32 s2, s3, s1
; CHECK-NEXT: vadd.f32 s5, s18, s19
; CHECK-NEXT: vadd.f32 s7, s16, s17
-; CHECK-NEXT: vadd.f32 s2, s3, s1
; CHECK-NEXT: vadd.f32 s4, s4, s6
+; CHECK-NEXT: vstr s0, [r0]
+; CHECK-NEXT: add.w r0, r2, r4, lsl #2
; CHECK-NEXT: vadd.f32 s14, s14, s15
; CHECK-NEXT: vadd.f32 s12, s12, s13
-; CHECK-NEXT: vstr s0, [r1]
-; CHECK-NEXT: add.w r1, r2, r0, lsl #2
+; CHECK-NEXT: vstr s2, [r0]
+; CHECK-NEXT: adds r0, r4, #2
; CHECK-NEXT: vadd.f32 s8, s8, s10
; CHECK-NEXT: vadd.f32 s6, s7, s5
-; CHECK-NEXT: vstr s2, [r1]
-; CHECK-NEXT: add.w r1, r2, r4, lsl #2
+; CHECK-NEXT: add.w r0, r2, r0, lsl #2
; CHECK-NEXT: vadd.f32 s10, s11, s9
-; CHECK-NEXT: vstr s4, [r1]
-; CHECK-NEXT: adds r1, r0, #3
+; CHECK-NEXT: vstr s4, [r0]
+; CHECK-NEXT: adds r0, r4, #3
; CHECK-NEXT: vadd.f32 s12, s12, s14
-; CHECK-NEXT: add.w r1, r2, r1, lsl #2
-; CHECK-NEXT: vstr s6, [r1]
-; CHECK-NEXT: adds r1, r0, #4
-; CHECK-NEXT: add.w r1, r2, r1, lsl #2
-; CHECK-NEXT: vstr s12, [r1]
-; CHECK-NEXT: adds r1, r0, #5
-; CHECK-NEXT: add.w r1, r2, r1, lsl #2
-; CHECK-NEXT: vstr s10, [r1]
-; CHECK-NEXT: adds r1, r0, #6
-; CHECK-NEXT: adds r0, #7
-; CHECK-NEXT: add.w r1, r2, r1, lsl #2
-; CHECK-NEXT: vstr s8, [r1]
-; CHECK-NEXT: ldr r1, [sp] @ 4-byte Reload
-; CHECK-NEXT: add r9, r1
-; CHECK-NEXT: ldr r1, [sp, #8] @ 4-byte Reload
-; CHECK-NEXT: cmp r0, r1
+; CHECK-NEXT: add.w r0, r2, r0, lsl #2
+; CHECK-NEXT: vstr s6, [r0]
+; CHECK-NEXT: adds r0, r4, #4
+; CHECK-NEXT: add.w r0, r2, r0, lsl #2
+; CHECK-NEXT: vstr s12, [r0]
+; CHECK-NEXT: adds r0, r4, #5
+; CHECK-NEXT: add.w r0, r2, r0, lsl #2
+; CHECK-NEXT: vstr s10, [r0]
+; CHECK-NEXT: adds r0, r4, #6
+; CHECK-NEXT: adds r4, #7
+; CHECK-NEXT: add.w r0, r2, r0, lsl #2
+; CHECK-NEXT: vstr s8, [r0]
+; CHECK-NEXT: ldr r0, [sp, #4] @ 4-byte Reload
+; CHECK-NEXT: add r8, r0
+; CHECK-NEXT: ldr r0, [sp, #8] @ 4-byte Reload
+; CHECK-NEXT: cmp r4, r0
; CHECK-NEXT: blo.w .LBB6_2
; CHECK-NEXT: .LBB6_5: @ %for.cond.cleanup
; CHECK-NEXT: add sp, #48
diff --git a/llvm/test/CodeGen/Thumb2/urem-seteq-illegal-types.ll b/llvm/test/CodeGen/Thumb2/urem-seteq-illegal-types.ll
index e5350409cd6ba..5fe867fb7b67e 100644
--- a/llvm/test/CodeGen/Thumb2/urem-seteq-illegal-types.ll
+++ b/llvm/test/CodeGen/Thumb2/urem-seteq-illegal-types.ll
@@ -42,8 +42,8 @@ define i1 @test_urem_even(i27 %X) nounwind {
define i1 @test_urem_odd_setne(i4 %X) nounwind {
; CHECK-LABEL: test_urem_odd_setne:
; CHECK: @ %bb.0:
-; CHECK-NEXT: movs r1, #13
-; CHECK-NEXT: muls r0, r1, r0
+; CHECK-NEXT: add.w r1, r0, r0, lsl #1
+; CHECK-NEXT: add.w r0, r0, r1, lsl #2
; CHECK-NEXT: and r1, r0, #15
; CHECK-NEXT: movs r0, #0
; CHECK-NEXT: cmp r1, #3
>From 8fa3ca754139175563b392237f22548097548be0 Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
Date: Wed, 17 Sep 2025 15:36:39 -0400
Subject: [PATCH 2/6] [ARM] Enable machine combiner pass
No custom combiners yet, but that will come later.
t2ADDrr is not added because it will throw an assert due to t2ADDrr having special rules in regards to SP even though this doesn't apply in reassociation.
---
llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp | 52 +++++++++++++++--
llvm/lib/Target/ARM/ARMBaseInstrInfo.h | 5 ++
llvm/lib/Target/ARM/ARMTargetMachine.cpp | 6 ++
llvm/test/CodeGen/ARM/O3-pipeline.ll | 3 +
llvm/test/CodeGen/ARM/bfi.ll | 14 ++---
llvm/test/CodeGen/ARM/combine-bitreverse.ll | 2 +-
.../ARM/cortex-a57-misched-ldm-wrback.ll | 2 +-
llvm/test/CodeGen/ARM/shift-combine.ll | 2 +-
llvm/test/CodeGen/ARM/swift-return.ll | 8 +--
.../ARM/umulo-128-legalisation-lowering.ll | 4 +-
.../CodeGen/Thumb2/mve-fptosi-sat-vector.ll | 48 ++++++++--------
.../CodeGen/Thumb2/mve-fptoui-sat-vector.ll | 56 +++++++++----------
llvm/test/CodeGen/Thumb2/mve-vcreate.ll | 42 +++++++-------
.../Thumb2/umulo-128-legalisation-lowering.ll | 2 +-
14 files changed, 151 insertions(+), 95 deletions(-)
diff --git a/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp b/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
index eb8ff794ad8a6..90a2325cd93a6 100644
--- a/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
+++ b/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
@@ -2601,6 +2601,49 @@ bool llvm::rewriteARMFrameIndex(MachineInstr &MI, unsigned FrameRegIdx,
return Offset == 0;
}
+// ARM supports MachineCombiner.
+bool ARMBaseInstrInfo::useMachineCombiner() const { return true; }
+
+/// Return true when Inst is associative and commutative so that it can be
+/// reassociated. If Invert is true, then the inverse of Inst operation must
+/// be checked.
+// TODO: There are many more machine instruction opcodes to match:
+// 1. Other data types (integer, vectors)
+// 2. Other math / logic operations (xor, or)
+// 3. Other forms of the same operation (intrinsics and other variants)
+bool ARMBaseInstrInfo::isAssociativeAndCommutative(const MachineInstr &Inst,
+ bool Invert) const {
+ if (Invert)
+ return false;
+
+ // Don't reassociate if CPSR is defined and not dead
+ if (isCPSRDefined(Inst))
+ return false;
+
+ switch (Inst.getOpcode()) {
+ case ARM::ADDrr:
+ case ARM::tADDrr:
+ // FIXME: Unable to reassociate t2ADDrr because it expects a rGPR register,
+ // but gets a GPRnopc register in reassociation. Fixing this requires
+ // splitting t2ADDrr because it has different rules depending on SP case.
+ case ARM::ANDrr:
+ case ARM::tAND:
+ case ARM::t2ANDrr:
+ case ARM::ORRrr:
+ case ARM::tORR:
+ case ARM::t2ORRrr:
+ case ARM::EORrr:
+ case ARM::tEOR:
+ case ARM::t2EORrr:
+ case ARM::MUL:
+ case ARM::t2MUL:
+ case ARM::tMUL:
+ return true;
+ default:
+ return false;
+ }
+}
+
/// analyzeCompare - For a comparison instruction, return the source registers
/// in SrcReg and SrcReg2 if having two register operands, and the value it
/// compares against in CmpValue. Return true if the comparison instruction
@@ -3263,11 +3306,10 @@ bool ARMBaseInstrInfo::foldImmediate(MachineInstr &UseMI, MachineInstr &DefMI,
UseMI.getOperand(1).setIsKill();
UseMI.getOperand(2).ChangeToImmediate(SOImmValV2);
DefMI.eraseFromParent();
- // FIXME: t2ADDrr should be split, as different rulles apply when writing to SP.
- // Just as t2ADDri, that was split to [t2ADDri, t2ADDspImm].
- // Then the below code will not be needed, as the input/output register
- // classes will be rgpr or gprSP.
- // For now, we fix the UseMI operand explicitly here:
+ // FIXME: t2ADDrr should be split, as different rules apply when writing to
+ // SP. Just as t2ADDri, that was split to [t2ADDri, t2ADDspImm]. Then the
+ // below code will not be needed, as the input/output register classes will be
+ // rgpr or gprSP. For now, we fix the UseMI operand explicitly here:
switch(NewUseOpc){
case ARM::t2ADDspImm:
case ARM::t2SUBspImm:
diff --git a/llvm/lib/Target/ARM/ARMBaseInstrInfo.h b/llvm/lib/Target/ARM/ARMBaseInstrInfo.h
index 94595ab2b338b..728c40a410dfc 100644
--- a/llvm/lib/Target/ARM/ARMBaseInstrInfo.h
+++ b/llvm/lib/Target/ARM/ARMBaseInstrInfo.h
@@ -186,6 +186,11 @@ class ARMBaseInstrInfo : public ARMGenInstrInfo {
bool isPredicable(const MachineInstr &MI) const override;
+ bool isAssociativeAndCommutative(const MachineInstr &Inst,
+ bool Invert) const override;
+
+ bool useMachineCombiner() const override;
+
// CPSR defined in instruction
static bool isCPSRDefined(const MachineInstr &MI);
diff --git a/llvm/lib/Target/ARM/ARMTargetMachine.cpp b/llvm/lib/Target/ARM/ARMTargetMachine.cpp
index 0de6f3d16eff4..a36742b610ef3 100644
--- a/llvm/lib/Target/ARM/ARMTargetMachine.cpp
+++ b/llvm/lib/Target/ARM/ARMTargetMachine.cpp
@@ -312,6 +312,7 @@ class ARMPassConfig : public TargetPassConfig {
bool addPreISel() override;
bool addInstSelector() override;
bool addIRTranslator() override;
+ bool addILPOpts() override;
bool addLegalizeMachineIR() override;
bool addRegBankSelect() override;
bool addGlobalInstructionSelect() override;
@@ -481,6 +482,11 @@ void ARMPassConfig::addPreRegAlloc() {
}
}
+bool ARMPassConfig::addILPOpts() {
+ addPass(&MachineCombinerID);
+ return true;
+}
+
void ARMPassConfig::addPreSched2() {
if (getOptLevel() != CodeGenOptLevel::None) {
if (EnableARMLoadStoreOpt)
diff --git a/llvm/test/CodeGen/ARM/O3-pipeline.ll b/llvm/test/CodeGen/ARM/O3-pipeline.ll
index 9f4d70531a3f7..f42509c35efff 100644
--- a/llvm/test/CodeGen/ARM/O3-pipeline.ll
+++ b/llvm/test/CodeGen/ARM/O3-pipeline.ll
@@ -90,6 +90,9 @@
; CHECK-NEXT: Remove dead machine instructions
; CHECK-NEXT: MachineDominator Tree Construction
; CHECK-NEXT: Machine Natural Loop Construction
+; CHECK-NEXT: Machine Trace Metrics
+; CHECK-NEXT: Lazy Machine Block Frequency Analysis
+; CHECK-NEXT: Machine InstCombiner
; CHECK-NEXT: Machine Block Frequency Analysis
; CHECK-NEXT: Early Machine Loop Invariant Code Motion
; CHECK-NEXT: MachineDominator Tree Construction
diff --git a/llvm/test/CodeGen/ARM/bfi.ll b/llvm/test/CodeGen/ARM/bfi.ll
index 5aeb99695a5fe..1811b5765efab 100644
--- a/llvm/test/CodeGen/ARM/bfi.ll
+++ b/llvm/test/CodeGen/ARM/bfi.ll
@@ -225,8 +225,8 @@ define i32 @bfi1(i32 %a, i32 %b) {
; CHECK-NEXT: bic r1, r1, #19
; CHECK-NEXT: orr r1, r1, r2
; CHECK-NEXT: and r2, r0, #16
-; CHECK-NEXT: orr r1, r1, r2
; CHECK-NEXT: and r0, r0, #2
+; CHECK-NEXT: orr r0, r2, r0
; CHECK-NEXT: orr r0, r1, r0
; CHECK-NEXT: bx lr
%x1 = and i32 %a, 1
@@ -274,15 +274,15 @@ define i32 @bfi2(i32 %a, i32 %b) {
; CHECK-LABEL: bfi2:
; CHECK: @ %bb.0:
; CHECK-NEXT: movw r2, #65148
+; CHECK-NEXT: and r3, r0, #2
; CHECK-NEXT: movt r2, #65535
; CHECK-NEXT: and r1, r1, r2
; CHECK-NEXT: and r2, r0, #1
-; CHECK-NEXT: orr r1, r1, r2
-; CHECK-NEXT: and r2, r0, #2
+; CHECK-NEXT: orr r2, r2, r3
; CHECK-NEXT: orr r1, r1, r2
; CHECK-NEXT: and r2, r0, #128
-; CHECK-NEXT: orr r1, r1, r2
; CHECK-NEXT: and r0, r0, #256
+; CHECK-NEXT: orr r0, r2, r0
; CHECK-NEXT: orr r0, r1, r0
; CHECK-NEXT: bx lr
%x1 = and i32 %a, 1
@@ -335,15 +335,15 @@ define i32 @bfi3(i32 %a, i32 %b) {
; CHECK-LABEL: bfi3:
; CHECK: @ %bb.0:
; CHECK-NEXT: movw r2, #65148
+; CHECK-NEXT: and r3, r0, #128
; CHECK-NEXT: movt r2, #65535
; CHECK-NEXT: and r1, r1, r2
; CHECK-NEXT: and r2, r0, #1
-; CHECK-NEXT: orr r1, r1, r2
-; CHECK-NEXT: and r2, r0, #128
+; CHECK-NEXT: orr r2, r2, r3
; CHECK-NEXT: orr r1, r1, r2
; CHECK-NEXT: and r2, r0, #2
-; CHECK-NEXT: orr r1, r1, r2
; CHECK-NEXT: and r0, r0, #256
+; CHECK-NEXT: orr r0, r2, r0
; CHECK-NEXT: orr r0, r1, r0
; CHECK-NEXT: bx lr
%x1 = and i32 %a, 1
diff --git a/llvm/test/CodeGen/ARM/combine-bitreverse.ll b/llvm/test/CodeGen/ARM/combine-bitreverse.ll
index 93fd77cb5fe15..e8126b483a758 100644
--- a/llvm/test/CodeGen/ARM/combine-bitreverse.ll
+++ b/llvm/test/CodeGen/ARM/combine-bitreverse.ll
@@ -50,9 +50,9 @@ define i32 @brev_and_all_operand_multiuse(i32 %a, i32 %b) #0 {
; CHECK-NEXT: rbit r1, r1
; CHECK-NEXT: rbit r0, r0
; CHECK-NEXT: and.w r2, r0, r1
+; CHECK-NEXT: muls r0, r1, r0
; CHECK-NEXT: rbit r2, r2
; CHECK-NEXT: muls r0, r2, r0
-; CHECK-NEXT: muls r0, r1, r0
; CHECK-NEXT: bx lr
%1 = tail call i32 @llvm.bitreverse.i32(i32 %a)
%2 = tail call i32 @llvm.bitreverse.i32(i32 %b)
diff --git a/llvm/test/CodeGen/ARM/cortex-a57-misched-ldm-wrback.ll b/llvm/test/CodeGen/ARM/cortex-a57-misched-ldm-wrback.ll
index 0e49a334e5a5b..9fdc5546e3fab 100644
--- a/llvm/test/CodeGen/ARM/cortex-a57-misched-ldm-wrback.ll
+++ b/llvm/test/CodeGen/ARM/cortex-a57-misched-ldm-wrback.ll
@@ -15,7 +15,7 @@
; CHECK: Successors:
; CHECK: Data
; CHECK-SAME: Latency=1
-; CHECK-NEXT: Data
+; CHECK: Data
; CHECK-SAME: Latency=3
; CHECK-NEXT: Data
; CHECK-SAME: Latency=0
diff --git a/llvm/test/CodeGen/ARM/shift-combine.ll b/llvm/test/CodeGen/ARM/shift-combine.ll
index 6566707b23b7a..5ec8fbeb01f56 100644
--- a/llvm/test/CodeGen/ARM/shift-combine.ll
+++ b/llvm/test/CodeGen/ARM/shift-combine.ll
@@ -1108,9 +1108,9 @@ define i32 @logic_tree_with_shifts_var_i32(i32 %a, i32 %b, i32 %c, i32 %d, i32 %
; CHECK-ALIGN: @ %bb.0:
; CHECK-ALIGN-NEXT: orrs r0, r2
; CHECK-ALIGN-NEXT: ldr r2, [sp]
+; CHECK-ALIGN-NEXT: orrs r1, r3
; CHECK-ALIGN-NEXT: lsls r0, r2
; CHECK-ALIGN-NEXT: orrs r0, r1
-; CHECK-ALIGN-NEXT: orrs r0, r3
; CHECK-ALIGN-NEXT: bx lr
;
; CHECK-V6M-LABEL: logic_tree_with_shifts_var_i32:
diff --git a/llvm/test/CodeGen/ARM/swift-return.ll b/llvm/test/CodeGen/ARM/swift-return.ll
index 3695cfa5b029d..67c478f385519 100644
--- a/llvm/test/CodeGen/ARM/swift-return.ll
+++ b/llvm/test/CodeGen/ARM/swift-return.ll
@@ -105,8 +105,8 @@ define swiftcc { i32, i32, i32, i32, i32 } @gen2(i32 %key) {
; CHECK-LABEL: test3:
; CHECK: bl {{.*}}gen3
; CHECK: add r0, r0, r1
-; CHECK: add r0, r0, r2
-; CHECK: add r0, r0, r3
+; CHECK: add r1, r2, r3
+; CHECK: add r0, r0, r1
; CHECK-O0-LABEL: test3:
; CHECK-O0: bl {{.*}}gen3
; CHECK-O0: add r0, r0, r1
@@ -191,8 +191,8 @@ declare swiftcc { double, double, double, double } @gen5()
; CHECK: bl _gen6
; CHECK-DAG: vadd.f64 [[TMP:d.*]], d0, d1
; CHECK-DAG: add r0, r0, r1
-; CHECK-DAG: add r0, r0, r2
-; CHECK-DAG: add r0, r0, r3
+; CHECK-DAG: add r1, r2, r3
+; CHECK-DAG: add r0, r0, r1
; CHECK-DAG: vadd.f64 [[TMP]], [[TMP]], d2
; CHECK-DAG: vadd.f64 d0, [[TMP]], d3
define swiftcc { double, i32 } @test6() #0 {
diff --git a/llvm/test/CodeGen/ARM/umulo-128-legalisation-lowering.ll b/llvm/test/CodeGen/ARM/umulo-128-legalisation-lowering.ll
index 4eb82c80e2bff..d3a4dae6cefc9 100644
--- a/llvm/test/CodeGen/ARM/umulo-128-legalisation-lowering.ll
+++ b/llvm/test/CodeGen/ARM/umulo-128-legalisation-lowering.ll
@@ -79,12 +79,12 @@ define { i128, i8 } @muloti_test(i128 %l, i128 %r) unnamed_addr #0 {
; ARMV6-NEXT: and r1, r5, r1
; ARMV6-NEXT: ldr r6, [sp, #16] @ 4-byte Reload
; ARMV6-NEXT: orr r1, r1, r9
-; ARMV6-NEXT: orr r1, r1, r11
; ARMV6-NEXT: and r0, r10, r0
+; ARMV6-NEXT: orr r1, r1, r11
; ARMV6-NEXT: adcs r6, r12, r6
; ARMV6-NEXT: str r6, [r2, #12]
; ARMV6-NEXT: ldr r6, [sp, #24] @ 4-byte Reload
-; ARMV6-NEXT: orr r1, r1, r6
+; ARMV6-NEXT: orr r0, r0, r6
; ARMV6-NEXT: orr r0, r0, r1
; ARMV6-NEXT: and r1, r4, r3
; ARMV6-NEXT: orr r1, r1, r7
diff --git a/llvm/test/CodeGen/Thumb2/mve-fptosi-sat-vector.ll b/llvm/test/CodeGen/Thumb2/mve-fptosi-sat-vector.ll
index 77548b49d77f2..d1698062f9ac3 100644
--- a/llvm/test/CodeGen/Thumb2/mve-fptosi-sat-vector.ll
+++ b/llvm/test/CodeGen/Thumb2/mve-fptosi-sat-vector.ll
@@ -4109,8 +4109,8 @@ define arm_aapcs_vfpcc <8 x i16> @test_signed_v8f16_v8i16(<8 x half> %f) {
define arm_aapcs_vfpcc <8 x i19> @test_signed_v8f16_v8i19(<8 x half> %f) {
; CHECK-LABEL: test_signed_v8f16_v8i19:
; CHECK: @ %bb.0:
-; CHECK-NEXT: .save {r4, r5, r7, r9, r11, lr}
-; CHECK-NEXT: push.w {r4, r5, r7, r9, r11, lr}
+; CHECK-NEXT: .save {r4, r5, r6, r7, r9, r11, lr}
+; CHECK-NEXT: push.w {r4, r5, r6, r7, r9, r11, lr}
; CHECK-NEXT: vldr s6, .LCPI46_1
; CHECK-NEXT: vcvtb.f32.f16 s12, s0
; CHECK-NEXT: vcvtt.f32.f16 s0, s0
@@ -4146,60 +4146,60 @@ define arm_aapcs_vfpcc <8 x i19> @test_signed_v8f16_v8i19(<8 x half> %f) {
; CHECK-NEXT: vmrs APSR_nzcv, fpscr
; CHECK-NEXT: lsll r2, r7, #19
; CHECK-NEXT: bfc r1, #19, #13
-; CHECK-NEXT: vmov r12, s10
+; CHECK-NEXT: vmov lr, s10
; CHECK-NEXT: vcmp.f32 s1, s1
; CHECK-NEXT: vmaxnm.f32 s8, s0, s6
; CHECK-NEXT: orr.w r1, r1, r2
; CHECK-NEXT: str r1, [r0]
; CHECK-NEXT: it vs
-; CHECK-NEXT: movvs.w r12, #0
+; CHECK-NEXT: movvs.w lr, #0
; CHECK-NEXT: vmrs APSR_nzcv, fpscr
; CHECK-NEXT: vcmp.f32 s0, s0
; CHECK-NEXT: vcvtt.f32.f16 s0, s2
; CHECK-NEXT: vmaxnm.f32 s2, s0, s6
-; CHECK-NEXT: vminnm.f32 s8, s8, s4
-; CHECK-NEXT: vminnm.f32 s2, s2, s4
; CHECK-NEXT: vmov r3, s7
+; CHECK-NEXT: vminnm.f32 s2, s2, s4
+; CHECK-NEXT: vminnm.f32 s8, s8, s4
; CHECK-NEXT: vcvt.s32.f32 s2, s2
; CHECK-NEXT: it vs
; CHECK-NEXT: movvs r3, #0
; CHECK-NEXT: vcvt.s32.f32 s8, s8
; CHECK-NEXT: bfc r3, #19, #13
-; CHECK-NEXT: mov r2, r12
+; CHECK-NEXT: mov r2, lr
; CHECK-NEXT: movs r1, #0
; CHECK-NEXT: bfc r2, #19, #13
; CHECK-NEXT: mov r4, r3
; CHECK-NEXT: mov.w r9, #0
; CHECK-NEXT: lsrl r2, r1, #7
+; CHECK-NEXT: lsrl r4, r9, #26
; CHECK-NEXT: vmrs APSR_nzcv, fpscr
; CHECK-NEXT: vcmp.f32 s0, s0
-; CHECK-NEXT: lsrl r4, r9, #26
; CHECK-NEXT: vcvtt.f32.f16 s0, s3
-; CHECK-NEXT: mov lr, r1
-; CHECK-NEXT: orr.w r1, r4, r2
-; CHECK-NEXT: vmov r4, s2
+; CHECK-NEXT: orr.w r12, r4, r2
+; CHECK-NEXT: vmov r2, s2
; CHECK-NEXT: vmaxnm.f32 s2, s0, s6
-; CHECK-NEXT: vmov r2, s8
+; CHECK-NEXT: vmov r4, s8
; CHECK-NEXT: vminnm.f32 s2, s2, s4
; CHECK-NEXT: it vs
-; CHECK-NEXT: movvs r2, #0
+; CHECK-NEXT: movvs r4, #0
; CHECK-NEXT: vcvt.s32.f32 s2, s2
-; CHECK-NEXT: bfc r2, #19, #13
-; CHECK-NEXT: movs r5, #0
-; CHECK-NEXT: lsll r2, r5, #12
; CHECK-NEXT: vmrs APSR_nzcv, fpscr
; CHECK-NEXT: it vs
-; CHECK-NEXT: movvs r4, #0
-; CHECK-NEXT: orrs r2, r1
+; CHECK-NEXT: movvs r2, #0
+; CHECK-NEXT: mov r6, r1
; CHECK-NEXT: bfc r4, #19, #13
+; CHECK-NEXT: movs r5, #0
+; CHECK-NEXT: bfc r2, #19, #13
; CHECK-NEXT: movs r1, #0
-; CHECK-NEXT: lsll r4, r1, #31
-; CHECK-NEXT: vcmp.f32 s0, s0
+; CHECK-NEXT: lsll r4, r5, #12
+; CHECK-NEXT: lsll r2, r1, #31
; CHECK-NEXT: orrs r2, r4
+; CHECK-NEXT: vcmp.f32 s0, s0
+; CHECK-NEXT: orr.w r2, r2, r12
; CHECK-NEXT: str r2, [r0, #8]
; CHECK-NEXT: orr.w r2, r7, r3, lsl #6
; CHECK-NEXT: vcvtb.f32.f16 s0, s3
-; CHECK-NEXT: orr.w r3, r2, r12, lsl #25
+; CHECK-NEXT: orr.w r3, r2, lr, lsl #25
; CHECK-NEXT: vmov r2, s2
; CHECK-NEXT: vmaxnm.f32 s2, s0, s6
; CHECK-NEXT: vmrs APSR_nzcv, fpscr
@@ -4213,6 +4213,7 @@ define arm_aapcs_vfpcc <8 x i19> @test_signed_v8f16_v8i19(<8 x half> %f) {
; CHECK-NEXT: lsll r2, r7, #5
; CHECK-NEXT: vmrs APSR_nzcv, fpscr
; CHECK-NEXT: mov.w r11, #0
+; CHECK-NEXT: orr.w r1, r1, r5
; CHECK-NEXT: vmov r7, s2
; CHECK-NEXT: it vs
; CHECK-NEXT: movvs r7, #0
@@ -4224,12 +4225,11 @@ define arm_aapcs_vfpcc <8 x i19> @test_signed_v8f16_v8i19(<8 x half> %f) {
; CHECK-NEXT: str r3, [r0, #4]
; CHECK-NEXT: lsrs r2, r2, #16
; CHECK-NEXT: strb r2, [r0, #18]
-; CHECK-NEXT: orr.w r2, r9, lr
-; CHECK-NEXT: orrs r2, r5
+; CHECK-NEXT: orr.w r2, r9, r6
; CHECK-NEXT: orrs r1, r2
; CHECK-NEXT: orr.w r1, r1, r7, lsl #18
; CHECK-NEXT: str r1, [r0, #12]
-; CHECK-NEXT: pop.w {r4, r5, r7, r9, r11, pc}
+; CHECK-NEXT: pop.w {r4, r5, r6, r7, r9, r11, pc}
; CHECK-NEXT: .p2align 2
; CHECK-NEXT: @ %bb.1:
; CHECK-NEXT: .LCPI46_0:
diff --git a/llvm/test/CodeGen/Thumb2/mve-fptoui-sat-vector.ll b/llvm/test/CodeGen/Thumb2/mve-fptoui-sat-vector.ll
index 1a22270ea0ebe..4ce0086fc076a 100644
--- a/llvm/test/CodeGen/Thumb2/mve-fptoui-sat-vector.ll
+++ b/llvm/test/CodeGen/Thumb2/mve-fptoui-sat-vector.ll
@@ -3427,8 +3427,8 @@ define arm_aapcs_vfpcc <8 x i16> @test_unsigned_v8f16_v8i16(<8 x half> %f) {
define arm_aapcs_vfpcc <8 x i19> @test_unsigned_v8f16_v8i19(<8 x half> %f) {
; CHECK-LABEL: test_unsigned_v8f16_v8i19:
; CHECK: @ %bb.0:
-; CHECK-NEXT: .save {r4, r5, r7, r9, r11, lr}
-; CHECK-NEXT: push.w {r4, r5, r7, r9, r11, lr}
+; CHECK-NEXT: .save {r4, r5, r6, r7, r9, r11, lr}
+; CHECK-NEXT: push.w {r4, r5, r6, r7, r9, r11, lr}
; CHECK-NEXT: vldr s6, .LCPI46_1
; CHECK-NEXT: vcvtb.f32.f16 s12, s0
; CHECK-NEXT: vcvtt.f32.f16 s0, s0
@@ -3444,13 +3444,13 @@ define arm_aapcs_vfpcc <8 x i19> @test_unsigned_v8f16_v8i19(<8 x half> %f) {
; CHECK-NEXT: vcvt.u32.f32 s14, s14
; CHECK-NEXT: vcvtt.f32.f16 s1, s1
; CHECK-NEXT: vcvt.u32.f32 s10, s10
-; CHECK-NEXT: vmaxnm.f32 s7, s1, s6
-; CHECK-NEXT: vcmp.f32 s0, s0
; CHECK-NEXT: movs r5, #0
+; CHECK-NEXT: vcmp.f32 s0, s0
+; CHECK-NEXT: vmaxnm.f32 s7, s1, s6
; CHECK-NEXT: vmrs APSR_nzcv, fpscr
; CHECK-NEXT: vcmp.f32 s12, s12
-; CHECK-NEXT: vminnm.f32 s7, s7, s4
; CHECK-NEXT: vcvtb.f32.f16 s0, s2
+; CHECK-NEXT: vminnm.f32 s7, s7, s4
; CHECK-NEXT: vcvt.u32.f32 s7, s7
; CHECK-NEXT: mov.w r11, #0
; CHECK-NEXT: vmov r2, s5
@@ -3484,34 +3484,35 @@ define arm_aapcs_vfpcc <8 x i19> @test_unsigned_v8f16_v8i19(<8 x half> %f) {
; CHECK-NEXT: lsrl r4, r9, #26
; CHECK-NEXT: it vs
; CHECK-NEXT: movvs.w r12, #0
-; CHECK-NEXT: mov r2, r12
-; CHECK-NEXT: lsrl r2, r11, #7
; CHECK-NEXT: vmrs APSR_nzcv, fpscr
; CHECK-NEXT: vcmp.f32 s0, s0
; CHECK-NEXT: vcvtb.f32.f16 s0, s3
-; CHECK-NEXT: orr.w r1, r4, r2
+; CHECK-NEXT: mov r2, r12
; CHECK-NEXT: mov.w r7, #0
+; CHECK-NEXT: lsrl r2, r11, #7
+; CHECK-NEXT: mov.w r1, #0
+; CHECK-NEXT: orr.w r4, r4, r2
; CHECK-NEXT: vmov r2, s8
-; CHECK-NEXT: vmov r4, s2
+; CHECK-NEXT: vmov r6, s2
; CHECK-NEXT: vmaxnm.f32 s2, s0, s6
; CHECK-NEXT: vminnm.f32 s2, s2, s4
; CHECK-NEXT: it vs
; CHECK-NEXT: movvs r2, #0
; CHECK-NEXT: vcvt.u32.f32 s2, s2
-; CHECK-NEXT: lsll r2, r7, #12
; CHECK-NEXT: vmrs APSR_nzcv, fpscr
-; CHECK-NEXT: orr.w r2, r2, r1
; CHECK-NEXT: it vs
-; CHECK-NEXT: movvs r4, #0
-; CHECK-NEXT: movs r1, #0
-; CHECK-NEXT: lsll r4, r1, #31
+; CHECK-NEXT: movvs r6, #0
+; CHECK-NEXT: lsll r2, r7, #12
+; CHECK-NEXT: lsll r6, r1, #31
; CHECK-NEXT: vcmp.f32 s0, s0
-; CHECK-NEXT: orrs r2, r4
+; CHECK-NEXT: orrs r2, r6
; CHECK-NEXT: vcvtt.f32.f16 s0, s3
+; CHECK-NEXT: orrs r2, r4
; CHECK-NEXT: str r2, [r0, #8]
; CHECK-NEXT: orr.w r2, r5, r3, lsl #6
; CHECK-NEXT: vmrs APSR_nzcv, fpscr
; CHECK-NEXT: vcmp.f32 s0, s0
+; CHECK-NEXT: mov.w r5, #0
; CHECK-NEXT: vmov r3, s2
; CHECK-NEXT: vmaxnm.f32 s2, s0, s6
; CHECK-NEXT: vminnm.f32 s2, s2, s4
@@ -3519,26 +3520,25 @@ define arm_aapcs_vfpcc <8 x i19> @test_unsigned_v8f16_v8i19(<8 x half> %f) {
; CHECK-NEXT: movvs r3, #0
; CHECK-NEXT: vcvt.u32.f32 s2, s2
; CHECK-NEXT: vmrs APSR_nzcv, fpscr
-; CHECK-NEXT: mov.w r5, #0
-; CHECK-NEXT: orr.w r12, r2, r12, lsl #25
-; CHECK-NEXT: mov r2, r3
-; CHECK-NEXT: vmov r4, s2
+; CHECK-NEXT: mov r4, r3
+; CHECK-NEXT: orr.w r2, r2, r12, lsl #25
+; CHECK-NEXT: orr.w r1, r1, r7
+; CHECK-NEXT: vmov r6, s2
; CHECK-NEXT: it vs
-; CHECK-NEXT: movvs r4, #0
-; CHECK-NEXT: lsll r4, r5, #5
+; CHECK-NEXT: movvs r6, #0
+; CHECK-NEXT: lsll r6, r5, #5
; CHECK-NEXT: movs r5, #0
-; CHECK-NEXT: lsrl r2, r5, #14
-; CHECK-NEXT: orrs r2, r4
-; CHECK-NEXT: strh r2, [r0, #16]
-; CHECK-NEXT: str.w r12, [r0, #4]
-; CHECK-NEXT: lsrs r2, r2, #16
+; CHECK-NEXT: lsrl r4, r5, #14
+; CHECK-NEXT: orrs r6, r4
+; CHECK-NEXT: strh r6, [r0, #16]
+; CHECK-NEXT: str r2, [r0, #4]
+; CHECK-NEXT: lsrs r2, r6, #16
; CHECK-NEXT: strb r2, [r0, #18]
; CHECK-NEXT: orr.w r2, r9, r11
-; CHECK-NEXT: orrs r2, r7
; CHECK-NEXT: orrs r1, r2
; CHECK-NEXT: orr.w r1, r1, r3, lsl #18
; CHECK-NEXT: str r1, [r0, #12]
-; CHECK-NEXT: pop.w {r4, r5, r7, r9, r11, pc}
+; CHECK-NEXT: pop.w {r4, r5, r6, r7, r9, r11, pc}
; CHECK-NEXT: .p2align 2
; CHECK-NEXT: @ %bb.1:
; CHECK-NEXT: .LCPI46_0:
diff --git a/llvm/test/CodeGen/Thumb2/mve-vcreate.ll b/llvm/test/CodeGen/Thumb2/mve-vcreate.ll
index 7e68cea23e949..16f7163b8589e 100644
--- a/llvm/test/CodeGen/Thumb2/mve-vcreate.ll
+++ b/llvm/test/CodeGen/Thumb2/mve-vcreate.ll
@@ -310,52 +310,52 @@ define hidden <16 x i8> @create_i8(i8 zeroext %a1, i8 zeroext %b1, i8 zeroext %c
; CHECK-NEXT: ldr r4, [sp, #40]
; CHECK-NEXT: mov.w r11, #0
; CHECK-NEXT: ldr r6, [sp, #36]
-; CHECK-NEXT: movs r7, #0
+; CHECK-NEXT: movs r5, #0
; CHECK-NEXT: lsll r4, r11, #16
; CHECK-NEXT: mov r10, r1
-; CHECK-NEXT: lsll r6, r7, #24
+; CHECK-NEXT: lsll r6, r5, #24
; CHECK-NEXT: mov r8, r3
; CHECK-NEXT: orr.w r1, r6, r4
; CHECK-NEXT: ldr r6, [sp, #44]
; CHECK-NEXT: movs r3, #0
-; CHECK-NEXT: ldr r4, [sp, #72]
+; CHECK-NEXT: ldr r7, [sp, #48]
; CHECK-NEXT: lsll r6, r3, #8
-; CHECK-NEXT: movs r5, #0
-; CHECK-NEXT: orrs r1, r6
-; CHECK-NEXT: ldr r6, [sp, #48]
-; CHECK-NEXT: lsll r4, r5, #16
-; CHECK-NEXT: mov.w r9, #0
-; CHECK-NEXT: orr.w r12, r1, r6
+; CHECK-NEXT: ldr r4, [sp, #72]
+; CHECK-NEXT: orrs r7, r6
; CHECK-NEXT: ldr r6, [sp, #68]
+; CHECK-NEXT: orr.w r12, r1, r7
+; CHECK-NEXT: movs r7, #0
; CHECK-NEXT: movs r1, #0
+; CHECK-NEXT: lsll r4, r7, #16
; CHECK-NEXT: lsll r6, r1, #24
-; CHECK-NEXT: orrs r6, r4
+; CHECK-NEXT: mov.w r9, #0
+; CHECK-NEXT: orr.w lr, r6, r4
; CHECK-NEXT: ldr r4, [sp, #76]
+; CHECK-NEXT: ldr r6, [sp, #80]
+; CHECK-NEXT: orrs r1, r7
; CHECK-NEXT: lsll r4, r9, #8
-; CHECK-NEXT: orrs r6, r4
-; CHECK-NEXT: ldr r4, [sp, #80]
-; CHECK-NEXT: orr.w lr, r6, r4
+; CHECK-NEXT: orrs r4, r6
+; CHECK-NEXT: orr.w r1, r1, r9
+; CHECK-NEXT: orr.w lr, lr, r4
; CHECK-NEXT: lsl.w r4, r10, #16
; CHECK-NEXT: orr.w r0, r4, r0, lsl #22
; CHECK-NEXT: orr.w r0, r0, r2, lsl #8
+; CHECK-NEXT: orr.w r2, r11, r3
; CHECK-NEXT: add r0, r8
-; CHECK-NEXT: orrs r0, r7
-; CHECK-NEXT: orr.w r0, r0, r11
-; CHECK-NEXT: orr.w r2, r0, r3
-; CHECK-NEXT: ldr r0, [sp, #56]
; CHECK-NEXT: ldr r3, [sp, #52]
+; CHECK-NEXT: orrs r0, r5
+; CHECK-NEXT: orrs r2, r0
+; CHECK-NEXT: ldr r0, [sp, #56]
; CHECK-NEXT: lsls r0, r0, #16
; CHECK-NEXT: orr.w r0, r0, r3, lsl #22
; CHECK-NEXT: ldr r3, [sp, #60]
; CHECK-NEXT: orr.w r0, r0, r3, lsl #8
; CHECK-NEXT: ldr r3, [sp, #64]
; CHECK-NEXT: add r0, r3
-; CHECK-NEXT: orrs r0, r1
+; CHECK-NEXT: orr.w r3, r0, r1
; CHECK-NEXT: mov r1, r2
-; CHECK-NEXT: orrs r0, r5
-; CHECK-NEXT: mov r2, lr
-; CHECK-NEXT: orr.w r3, r0, r9
; CHECK-NEXT: mov r0, r12
+; CHECK-NEXT: mov r2, lr
; CHECK-NEXT: pop.w {r4, r5, r6, r7, r8, r9, r10, r11, pc}
entry:
%conv = zext i8 %a1 to i64
diff --git a/llvm/test/CodeGen/Thumb2/umulo-128-legalisation-lowering.ll b/llvm/test/CodeGen/Thumb2/umulo-128-legalisation-lowering.ll
index fe1d06cb39e16..a32b7b86e0634 100644
--- a/llvm/test/CodeGen/Thumb2/umulo-128-legalisation-lowering.ll
+++ b/llvm/test/CodeGen/Thumb2/umulo-128-legalisation-lowering.ll
@@ -88,7 +88,7 @@ define { i128, i8 } @muloti_test(i128 %l, i128 %r) unnamed_addr #0 {
; THUMBV7-NEXT: adds r1, r1, r6
; THUMBV7-NEXT: umlal r2, r7, r3, r8
; THUMBV7-NEXT: adc r4, r4, #0
-; THUMBV7-NEXT: orrs r0, r4
+; THUMBV7-NEXT: orrs r5, r4
; THUMBV7-NEXT: orrs r0, r5
; THUMBV7-NEXT: ldrd r5, r4, [sp, #36] @ 8-byte Folded Reload
; THUMBV7-NEXT: adds r5, r5, r4
>From 237098aabbb0da771fe0a964d477e4bd72056c9c Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
Date: Sat, 2 May 2026 20:03:21 -0400
Subject: [PATCH 3/6] Move MLA handling to Machine Combiner
---
llvm/include/llvm/CodeGen/TargetInstrInfo.h | 2 +-
llvm/lib/CodeGen/TargetInstrInfo.cpp | 5 -
llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp | 285 ++++++++++++++++++++
llvm/lib/Target/ARM/ARMBaseInstrInfo.h | 27 ++
llvm/lib/Target/ARM/ARMISelLowering.cpp | 4 +-
5 files changed, 316 insertions(+), 7 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/TargetInstrInfo.h b/llvm/include/llvm/CodeGen/TargetInstrInfo.h
index 30dc643bfed2f..a05bf8ff357df 100644
--- a/llvm/include/llvm/CodeGen/TargetInstrInfo.h
+++ b/llvm/include/llvm/CodeGen/TargetInstrInfo.h
@@ -1307,7 +1307,7 @@ class LLVM_ABI TargetInstrInfo : public MCInstrInfo {
/// Return true when a code sequence can improve throughput. It
/// should be called only for instructions in loops.
/// \param Pattern - combiner pattern
- virtual bool isThroughputPattern(unsigned Pattern) const;
+ virtual bool isThroughputPattern(unsigned Pattern) const { return false; }
/// Return the objective of a combiner pattern.
/// \param Pattern - combiner pattern
diff --git a/llvm/lib/CodeGen/TargetInstrInfo.cpp b/llvm/lib/CodeGen/TargetInstrInfo.cpp
index bc930df5a9bc1..d46e7d49d7126 100644
--- a/llvm/lib/CodeGen/TargetInstrInfo.cpp
+++ b/llvm/lib/CodeGen/TargetInstrInfo.cpp
@@ -1183,11 +1183,6 @@ bool TargetInstrInfo::getMachineCombinerPatterns(
return false;
}
-/// Return true when a code sequence can improve loop throughput.
-bool TargetInstrInfo::isThroughputPattern(unsigned Pattern) const {
- return false;
-}
-
CombinerObjective
TargetInstrInfo::getCombinerObjective(unsigned Pattern) const {
switch (Pattern) {
diff --git a/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp b/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
index 90a2325cd93a6..6047c1dbb4a1e 100644
--- a/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
+++ b/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
@@ -600,6 +600,291 @@ template <> bool IsCPSRDead<MachineInstr>(const MachineInstr *MI) {
} // end namespace llvm
+//
+// Utility routine that checks if \param MO is defined by an
+// \param CombineOpc instruction in the basic block \param MBB.
+// ARM GPR \p MUL does not use AArch64-style MADD-with-zero; require \p MUL.
+static bool canCombine(MachineBasicBlock &MBB, MachineOperand &MO,
+ unsigned CombineOpc) {
+ MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();
+ MachineInstr *MI = nullptr;
+
+ if (MO.isReg() && MO.getReg().isVirtual())
+ MI = MRI.getUniqueVRegDef(MO.getReg());
+ // And it needs to be in the trace (otherwise, it won't have a depth).
+ if (!MI || MI->getParent() != &MBB || MI->getOpcode() != CombineOpc)
+ return false;
+ // Must only used by the user we combine with.
+ if (!MRI.hasOneNonDBGUse(MI->getOperand(0).getReg()))
+ return false;
+
+ return llvm::IsCPSRDead(MI);
+}
+
+//
+// Is \param MO defined by an integer multiply and can be combined?
+static bool canCombineWithMUL(MachineBasicBlock &MBB, MachineOperand &MO,
+ unsigned MulOpc) {
+ return canCombine(MBB, MO, MulOpc);
+}
+
+// GPR register/register add/sub roots that can fuse with ARM-mode \p MUL.
+static bool isCombineInstrCandidate(unsigned Opc) {
+ switch (Opc) {
+ case ARM::ADDrr:
+ case ARM::SUBrr:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/// Append predicate / cc operands from \p Root onto \p MIB so they match \p
+/// NewDesc's trailing operands (MLS has predicate only; MLA matches Root).
+static void armAppendConditionOperands(MachineInstrBuilder &MIB,
+ const MachineInstr &Root,
+ const MCInstrDesc &NewDesc) {
+ int RP = Root.findFirstPredOperandIdx();
+ int NP = NewDesc.findFirstPredOperandIdx();
+ assert(RP >= 0 && NP >= 0 && "Expected predicate operands");
+ unsigned NTailNew = NewDesc.getNumOperands() - NP;
+ assert(RP + NTailNew <= Root.getNumOperands() &&
+ "Root does not supply enough predicate/cc operands");
+ for (unsigned i = 0; i < NTailNew; ++i)
+ MIB.add(Root.getOperand(RP + i));
+}
+
+/// Emit MLA merging ARM-mode \p Root with ARM::MUL feeding operand \p IdxMulOpd.
+static MachineInstr *genArmGPRMLA(MachineFunction &MF,
+ MachineRegisterInfo &MRI,
+ const TargetInstrInfo *TII, MachineInstr &Root,
+ SmallVectorImpl<MachineInstr *> &InsInstrs,
+ unsigned IdxMulOpd,
+ const TargetRegisterClass *RC) {
+ assert(IdxMulOpd == 1 || IdxMulOpd == 2);
+ MachineInstr *Mul =
+ MRI.getUniqueVRegDef(Root.getOperand(IdxMulOpd).getReg());
+ assert(Mul->getOpcode() == ARM::MUL && "Expected ARM-mode MUL");
+
+ Register Dst = Root.getOperand(0).getReg();
+ Register MulRn = Mul->getOperand(1).getReg();
+ bool MulRnKill = Mul->getOperand(1).isKill();
+ Register MulRm = Mul->getOperand(2).getReg();
+ bool MulRmKill = Mul->getOperand(2).isKill();
+ unsigned IdxOther = IdxMulOpd == 1 ? 2 : 1;
+ Register Other = Root.getOperand(IdxOther).getReg();
+ bool OtherKill = Root.getOperand(IdxOther).isKill();
+
+ if (Dst.isVirtual())
+ MRI.constrainRegClass(Dst, RC);
+ if (MulRn.isVirtual())
+ MRI.constrainRegClass(MulRn, RC);
+ if (MulRm.isVirtual())
+ MRI.constrainRegClass(MulRm, RC);
+ if (Other.isVirtual())
+ MRI.constrainRegClass(Other, RC);
+
+ MachineInstrBuilder MIB =
+ BuildMI(MF, MIMetadata(Root), TII->get(ARM::MLA), Dst)
+ .addReg(MulRn, getKillRegState(MulRnKill))
+ .addReg(MulRm, getKillRegState(MulRmKill))
+ .addReg(Other, getKillRegState(OtherKill));
+ armAppendConditionOperands(MIB, Root, TII->get(ARM::MLA));
+ InsInstrs.push_back(MIB);
+ return Mul;
+}
+
+/// Emit MLS Rd = Ra - Rn*Rm for SUBrr where \p IdxMulOpd points at the product.
+static MachineInstr *genArmGPRMLS(MachineFunction &MF,
+ MachineRegisterInfo &MRI,
+ const TargetInstrInfo *TII, MachineInstr &Root,
+ SmallVectorImpl<MachineInstr *> &InsInstrs,
+ unsigned IdxMulOpd,
+ const TargetRegisterClass *RC) {
+ assert(IdxMulOpd == 2 &&
+ "MLS fusion only matches SUB when multiply uses subtract operand");
+ MachineInstr *Mul =
+ MRI.getUniqueVRegDef(Root.getOperand(IdxMulOpd).getReg());
+ assert(Mul->getOpcode() == ARM::MUL && "Expected ARM-mode MUL");
+
+ Register Dst = Root.getOperand(0).getReg();
+ Register MulRn = Mul->getOperand(1).getReg();
+ bool MulRnKill = Mul->getOperand(1).isKill();
+ Register MulRm = Mul->getOperand(2).getReg();
+ bool MulRmKill = Mul->getOperand(2).isKill();
+ Register Ra = Root.getOperand(1).getReg();
+ bool RaKill = Root.getOperand(1).isKill();
+
+ if (Dst.isVirtual())
+ MRI.constrainRegClass(Dst, RC);
+ if (MulRn.isVirtual())
+ MRI.constrainRegClass(MulRn, RC);
+ if (MulRm.isVirtual())
+ MRI.constrainRegClass(MulRm, RC);
+ if (Ra.isVirtual())
+ MRI.constrainRegClass(Ra, RC);
+
+ MachineInstrBuilder MIB =
+ BuildMI(MF, MIMetadata(Root), TII->get(ARM::MLS), Dst)
+ .addReg(MulRn, getKillRegState(MulRnKill))
+ .addReg(MulRm, getKillRegState(MulRmKill))
+ .addReg(Ra, getKillRegState(RaKill));
+ armAppendConditionOperands(MIB, Root, TII->get(ARM::MLS));
+ InsInstrs.push_back(MIB);
+ return Mul;
+}
+
+/// SUBrr with mul on operand 1: emit RSB + MLA like AArch64 SUB+0 + MADD.
+static MachineInstr *genArmGPRMLASubMulOp1(
+ MachineFunction &MF, MachineRegisterInfo &MRI, const TargetInstrInfo *TII,
+ MachineInstr &Root, SmallVectorImpl<MachineInstr *> &InsInstrs,
+ DenseMap<Register, unsigned> &InstrIdxForVirtReg) {
+ MachineInstr *Mul =
+ MRI.getUniqueVRegDef(Root.getOperand(1).getReg());
+ assert(Mul->getOpcode() == ARM::MUL && "Expected ARM-mode MUL");
+
+ Register Dst = Root.getOperand(0).getReg();
+ Register Other = Root.getOperand(2).getReg();
+ bool OtherKill = Root.getOperand(2).isKill();
+ Register MulRn = Mul->getOperand(1).getReg();
+ bool MulRnKill = Mul->getOperand(1).isKill();
+ Register MulRm = Mul->getOperand(2).getReg();
+ bool MulRmKill = Mul->getOperand(2).isKill();
+
+ const TargetRegisterClass *MLARc = &ARM::GPRnopcRegClass;
+ Register NegVr = MRI.createVirtualRegister(MLARc);
+ MachineInstrBuilder RsbMIB =
+ BuildMI(MF, MIMetadata(Root), TII->get(ARM::RSBri), NegVr)
+ .addReg(Other, getKillRegState(OtherKill))
+ .addImm(0);
+ armAppendConditionOperands(RsbMIB, Root, TII->get(ARM::RSBri));
+ InsInstrs.push_back(RsbMIB);
+ InstrIdxForVirtReg.insert(std::make_pair(NegVr, 0));
+
+ if (Dst.isVirtual())
+ MRI.constrainRegClass(Dst, MLARc);
+ if (MulRn.isVirtual())
+ MRI.constrainRegClass(MulRn, MLARc);
+ if (MulRm.isVirtual())
+ MRI.constrainRegClass(MulRm, MLARc);
+
+ MachineInstrBuilder MlaMIB =
+ BuildMI(MF, MIMetadata(Root), TII->get(ARM::MLA), Dst)
+ .addReg(MulRn, getKillRegState(MulRnKill))
+ .addReg(MulRm, getKillRegState(MulRmKill))
+ .addReg(NegVr, RegState::Kill);
+ armAppendConditionOperands(MlaMIB, Root, TII->get(ARM::MLA));
+ InsInstrs.push_back(MlaMIB);
+ return Mul;
+}
+
+/// Find instructions that can be turned into MLA / MLS (ARM-state GPR).
+static bool getMaddPatterns(const ARMSubtarget &Subtarget, MachineInstr &Root,
+ SmallVectorImpl<unsigned> &Patterns) {
+ unsigned Opc = Root.getOpcode();
+ MachineBasicBlock &MBB = *Root.getParent();
+ bool Found = false;
+
+ if (!isCombineInstrCandidate(Opc))
+ return false;
+
+ // Do not fuse if this root defines live CPSR (mla/mls handling must preserve
+ // flags semantics separately).
+ if (!llvm::IsCPSRDead(&Root))
+ return false;
+
+ const bool CanMLS = Subtarget.hasV6T2Ops();
+
+ auto setFound = [&](unsigned OperandIdx, unsigned Pattern) {
+ if (!Root.getOperand(OperandIdx).isReg())
+ return;
+ if (canCombineWithMUL(MBB, Root.getOperand(OperandIdx), ARM::MUL)) {
+ Patterns.push_back(Pattern);
+ Found = true;
+ }
+ };
+
+ typedef ARMMachineCombinerPattern MCP;
+
+ switch (Opc) {
+ default:
+ break;
+ case ARM::ADDrr:
+
+ assert(Root.getOperand(1).isReg() && Root.getOperand(2).isReg() &&
+ "ADDrr must use register operands");
+ setFound(1, MCP::MULADD_OP1);
+ setFound(2, MCP::MULADD_OP2);
+ break;
+ case ARM::SUBrr:
+ if (CanMLS)
+ setFound(2, MCP::MULSUB_OP2);
+ setFound(1, MCP::MULSUB_OP1);
+ break;
+ }
+ return Found;
+}
+
+bool ARMBaseInstrInfo::getMachineCombinerPatterns(
+ MachineInstr &Root, SmallVectorImpl<unsigned> &Patterns,
+ bool DoRegPressureReduce) const {
+
+ if (!Subtarget.isThumb()) {
+ if (getMaddPatterns(Subtarget, Root, Patterns))
+ return true;
+ }
+
+ return TargetInstrInfo::getMachineCombinerPatterns(Root, Patterns,
+ DoRegPressureReduce);
+}
+
+void ARMBaseInstrInfo::genAlternativeCodeSequence(
+ MachineInstr &Root, unsigned Pattern,
+ SmallVectorImpl<MachineInstr *> &InsInstrs,
+ SmallVectorImpl<MachineInstr *> &DelInstrs,
+ DenseMap<Register, unsigned> &InstrIdxForVirtReg) const {
+ MachineBasicBlock &MBB = *Root.getParent();
+ MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();
+ MachineFunction &MF = *MBB.getParent();
+ const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
+
+ MachineInstr *MulToDelete = nullptr;
+ typedef ARMMachineCombinerPattern MCP;
+
+ switch (Pattern) {
+ default:
+ TargetInstrInfo::genAlternativeCodeSequence(Root, Pattern, InsInstrs,
+ DelInstrs, InstrIdxForVirtReg);
+ return;
+ case MCP::MULADD_OP1:
+ MulToDelete =
+ genArmGPRMLA(MF, MRI, TII, Root, InsInstrs, 1, &ARM::GPRnopcRegClass);
+ break;
+ case MCP::MULADD_OP2:
+ MulToDelete =
+ genArmGPRMLA(MF, MRI, TII, Root, InsInstrs, 2, &ARM::GPRnopcRegClass);
+ break;
+ case MCP::MULSUB_OP1:
+ MulToDelete = genArmGPRMLASubMulOp1(MF, MRI, TII, Root, InsInstrs,
+ InstrIdxForVirtReg);
+ break;
+ case MCP::MULSUB_OP2:
+ MulToDelete =
+ genArmGPRMLS(MF, MRI, TII, Root, InsInstrs, 2, &ARM::GPRRegClass);
+ break;
+ }
+
+ if (MulToDelete)
+ DelInstrs.push_back(MulToDelete);
+ DelInstrs.push_back(&Root);
+
+ uint32_t Flags = Root.getFlags();
+ if (MulToDelete)
+ Flags = Root.mergeFlagsWith(*MulToDelete);
+ for (MachineInstr *MI : InsInstrs)
+ MI->setFlags(Flags);
+}
+
/// GetInstSize - Return the size of the specified MachineInstr.
///
unsigned ARMBaseInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
diff --git a/llvm/lib/Target/ARM/ARMBaseInstrInfo.h b/llvm/lib/Target/ARM/ARMBaseInstrInfo.h
index 728c40a410dfc..7eb7fd0a383d1 100644
--- a/llvm/lib/Target/ARM/ARMBaseInstrInfo.h
+++ b/llvm/lib/Target/ARM/ARMBaseInstrInfo.h
@@ -39,6 +39,20 @@ namespace llvm {
class ARMBaseRegisterInfo;
class ARMSubtarget;
+
+// ARM MachineCombiner patterns
+enum ARMMachineCombinerPattern : unsigned {
+ // These are patterns used to reduce the length of dependence chain.
+ SUBADD_OP1 = MachineCombinerPattern::TARGET_PATTERN_START,
+ SUBADD_OP2,
+
+ // These are multiply-add patterns matched by the ARM machine combiner.
+ MULADD_OP1,
+ MULADD_OP2,
+ MULSUB_OP1,
+ MULSUB_OP2
+};
+
class ARMBaseInstrInfo : public ARMGenInstrInfo {
const ARMSubtarget &Subtarget;
@@ -186,6 +200,19 @@ class ARMBaseInstrInfo : public ARMGenInstrInfo {
bool isPredicable(const MachineInstr &MI) const override;
+ /// Return true when there is potentially a faster code sequence
+ /// for an instruction chain ending in ``Root``. All potential patterns are
+ /// listed in the ``Patterns`` array.
+ bool getMachineCombinerPatterns(MachineInstr &Root,
+ SmallVectorImpl<unsigned> &Patterns,
+ bool DoRegPressureReduce) const override;
+
+ void genAlternativeCodeSequence(
+ MachineInstr &Root, unsigned Pattern,
+ SmallVectorImpl<MachineInstr *> &InsInstrs,
+ SmallVectorImpl<MachineInstr *> &DelInstrs,
+ DenseMap<Register, unsigned> &InstrIdxForVirtReg) const override;
+
bool isAssociativeAndCommutative(const MachineInstr &Inst,
bool Invert) const override;
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp
index 6524f3f2d7a84..b94f646f78df6 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp
@@ -14192,7 +14192,9 @@ static SDValue PerformMULCombine(SDNode *N, SelectionDAG &DAG,
if (!Subtarget->isThumb()) {
auto IsAddSubWith1 = [&](SDValue V) -> bool {
AddSubOpc = V->getOpcode();
- if ((AddSubOpc == ISD::ADD || AddSubOpc == ISD::SUB) && V->hasOneUse()) {
+ if ((AddSubOpc == ISD::ADD ||
+ (AddSubOpc == ISD::SUB && Subtarget->hasV6T2Ops())) &&
+ V->hasOneUse()) {
SDValue Opnd = V->getOperand(1);
MulOper = V->getOperand(0);
if (AddSubOpc == ISD::SUB)
>From 65f12bd98f72007646b32a41a88ee66215ddb556 Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
Date: Sat, 2 May 2026 20:21:52 -0400
Subject: [PATCH 4/6] a
---
llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp | 26 ++++++++++++----
llvm/lib/Target/ARM/ARMISelLowering.cpp | 39 +++++++++++++++---------
llvm/test/CodeGen/ARM/addimm-mulimm.ll | 6 ++--
llvm/test/CodeGen/ARM/uadd_sat_plus.ll | 7 +++--
4 files changed, 52 insertions(+), 26 deletions(-)
diff --git a/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp b/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
index 6047c1dbb4a1e..b796a686026b2 100644
--- a/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
+++ b/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
@@ -788,12 +788,24 @@ static bool getMaddPatterns(const ARMSubtarget &Subtarget, MachineInstr &Root,
if (!isCombineInstrCandidate(Opc))
return false;
- // Do not fuse if this root defines live CPSR (mla/mls handling must preserve
- // flags semantics separately).
- if (!llvm::IsCPSRDead(&Root))
+ // MLA/MLS do not provide ADD/SUB-with-S-bit flag semantics. Do not fuse when
+ // the root defines CPSR: conditional ARM instructions depend on flags without
+ // necessarily listing an explicit CPSR use, so IsCPSRDead(&Root) is unreliable.
+ //
+ // Contrast AArch64 getMaddPatterns: ADDS/SUBS use separate opcodes and may be
+ // converted to non-flag ADD/SUB for fusion when an NZCV def operand exists.
+ // ARM keeps one ADDrr/SUBrr opcode with optional cc_out (explicit CPSR def
+ // when the S bit is used). If this root has any explicit CPSR def operand,
+ // do not fuse. (AArch64 passes isDead=true there to match only dead NZCV
+ // defs before ADDS→ADD conversion; ARM must not fuse on any CPSR-def add.)
+ if (Root.findRegisterDefOperandIdx(ARM::CPSR, /*TRI=*/nullptr, false) != -1)
return false;
- const bool CanMLS = Subtarget.hasV6T2Ops();
+ // Match TableGen Requires on MLA / MLS (ARMInstrInfo.td).
+ const bool CanMLA =
+ Subtarget.useMulOps() && Subtarget.hasV6Ops() && Subtarget.hasARMOps();
+ const bool CanMLS =
+ Subtarget.useMulOps() && Subtarget.hasV6T2Ops() && Subtarget.hasARMOps();
auto setFound = [&](unsigned OperandIdx, unsigned Pattern) {
if (!Root.getOperand(OperandIdx).isReg())
@@ -810,7 +822,8 @@ static bool getMaddPatterns(const ARMSubtarget &Subtarget, MachineInstr &Root,
default:
break;
case ARM::ADDrr:
-
+ if (!CanMLA)
+ break;
assert(Root.getOperand(1).isReg() && Root.getOperand(2).isReg() &&
"ADDrr must use register operands");
setFound(1, MCP::MULADD_OP1);
@@ -819,7 +832,8 @@ static bool getMaddPatterns(const ARMSubtarget &Subtarget, MachineInstr &Root,
case ARM::SUBrr:
if (CanMLS)
setFound(2, MCP::MULSUB_OP2);
- setFound(1, MCP::MULSUB_OP1);
+ if (CanMLA)
+ setFound(1, MCP::MULSUB_OP1);
break;
}
return Found;
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp
index b94f646f78df6..628fe58c42801 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp
@@ -14192,16 +14192,22 @@ static SDValue PerformMULCombine(SDNode *N, SelectionDAG &DAG,
if (!Subtarget->isThumb()) {
auto IsAddSubWith1 = [&](SDValue V) -> bool {
AddSubOpc = V->getOpcode();
- if ((AddSubOpc == ISD::ADD ||
- (AddSubOpc == ISD::SUB && Subtarget->hasV6T2Ops())) &&
- V->hasOneUse()) {
- SDValue Opnd = V->getOperand(1);
- MulOper = V->getOperand(0);
- if (AddSubOpc == ISD::SUB)
- std::swap(Opnd, MulOper);
- if (auto C = dyn_cast<ConstantSDNode>(Opnd))
- return C->isOne();
- }
+ if (AddSubOpc == ISD::ADD) {
+ if (!(Subtarget->hasV6Ops() && Subtarget->useMulOps()))
+ return false;
+ } else if (AddSubOpc == ISD::SUB) {
+ if (!(Subtarget->hasV6T2Ops() && Subtarget->useMulOps()))
+ return false;
+ } else
+ return false;
+ if (!V->hasOneUse())
+ return false;
+ SDValue Opnd = V->getOperand(1);
+ MulOper = V->getOperand(0);
+ if (AddSubOpc == ISD::SUB)
+ std::swap(Opnd, MulOper);
+ if (auto C = dyn_cast<ConstantSDNode>(Opnd))
+ return C->isOne();
return false;
};
@@ -14231,10 +14237,15 @@ static SDValue PerformMULCombine(SDNode *N, SelectionDAG &DAG,
isZeroExtended(N0.getNode(), DAG)))
return SDValue();
// Conservatively do not lower to shift+add+shift if the mul might be
- // folded into madd or msub.
- if (N->hasOneUse() && (N->user_begin()->getOpcode() == ISD::ADD ||
- N->user_begin()->getOpcode() == ISD::SUB))
- return SDValue();
+ // folded into MLA / MLS on ARM-mode GPR paths (same gates as the machine
+ // combiner and IsAddSubWith1 above).
+ if (N->hasOneUse() && Subtarget->hasARMOps() && Subtarget->useMulOps()) {
+ unsigned UOpc = N->user_begin()->getOpcode();
+ if (UOpc == ISD::ADD && Subtarget->hasV6Ops())
+ return SDValue();
+ if (UOpc == ISD::SUB && Subtarget->hasV6T2Ops())
+ return SDValue();
+ }
}
// Use ShiftedConstValue instead of ConstValue to support both shift+add/sub
diff --git a/llvm/test/CodeGen/ARM/addimm-mulimm.ll b/llvm/test/CodeGen/ARM/addimm-mulimm.ll
index 5a201b2f3c438..ae9fc901bb4f2 100644
--- a/llvm/test/CodeGen/ARM/addimm-mulimm.ll
+++ b/llvm/test/CodeGen/ARM/addimm-mulimm.ll
@@ -517,10 +517,10 @@ define i16 @fold_sub251_mul353_i16(i16 %a) {
;
; CHECK-ARMV7-LABEL: fold_sub251_mul353_i16:
; CHECK-ARMV7: @ %bb.0:
+; CHECK-ARMV7-NEXT: movw r2, #23067
; CHECK-ARMV7-NEXT: movw r1, #353
-; CHECK-ARMV7-NEXT: mul r0, r0, r1
-; CHECK-ARMV7-NEXT: movw r1, #23067
-; CHECK-ARMV7-NEXT: sub r0, r0, r1
+; CHECK-ARMV7-NEXT: rsb r2, r2, #0
+; CHECK-ARMV7-NEXT: mla r0, r0, r1, r2
; CHECK-ARMV7-NEXT: bx lr
;
; CHECK-THUMBV6M-LABEL: fold_sub251_mul353_i16:
diff --git a/llvm/test/CodeGen/ARM/uadd_sat_plus.ll b/llvm/test/CodeGen/ARM/uadd_sat_plus.ll
index ffacba8cf0124..14d5052955f70 100644
--- a/llvm/test/CodeGen/ARM/uadd_sat_plus.ll
+++ b/llvm/test/CodeGen/ARM/uadd_sat_plus.ll
@@ -32,9 +32,10 @@ define i32 @func32(i32 %x, i32 %y, i32 %z) nounwind {
;
; CHECK-ARM-LABEL: func32:
; CHECK-ARM: @ %bb.0:
-; CHECK-ARM-NEXT: mul r1, r1, r2
-; CHECK-ARM-NEXT: adds r0, r0, r1
-; CHECK-ARM-NEXT: mvnhs r0, #0
+; CHECK-ARM-NEXT: mla r1, r1, r2, r0
+; CHECK-ARM-NEXT: cmp r1, r0
+; CHECK-ARM-NEXT: mvnlo r1, #0
+; CHECK-ARM-NEXT: mov r0, r1
; CHECK-ARM-NEXT: bx lr
%a = mul i32 %y, %z
%tmp = call i32 @llvm.uadd.sat.i32(i32 %x, i32 %a)
>From f9f045838331964ed3f9ec7ae8348c497457948b Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
Date: Sat, 2 May 2026 20:28:28 -0400
Subject: [PATCH 5/6] Update ARMInstrInfo.td
---
llvm/lib/Target/ARM/ARMInstrInfo.td | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/Target/ARM/ARMInstrInfo.td b/llvm/lib/Target/ARM/ARMInstrInfo.td
index c74c84a2602b1..0f9ebd97f4b13 100644
--- a/llvm/lib/Target/ARM/ARMInstrInfo.td
+++ b/llvm/lib/Target/ARM/ARMInstrInfo.td
@@ -4477,10 +4477,12 @@ def MULv5: ARMPseudoExpand<(outs GPRnopc:$Rd), (ins GPRnopc:$Rn, GPRnopc:$Rm,
Sched<[WriteMUL32, ReadMUL, ReadMUL]>;
}
+// No DAG pattern: avoid ISel folding add(mul,) -> MLA before machine scheduling.
+// MLA is formed by the ARM machine combiner (see ARMBaseInstrInfo.cpp).
def MLA : AsMul1I32<0b0000001, (outs GPRnopc:$Rd),
(ins GPRnopc:$Rn, GPRnopc:$Rm, GPRnopc:$Ra),
IIC_iMAC32, "mla", "\t$Rd, $Rn, $Rm, $Ra",
- [(set GPRnopc:$Rd, (add (mul GPRnopc:$Rn, GPRnopc:$Rm), GPRnopc:$Ra))]>,
+ []>,
Requires<[IsARM, HasV6, UseMulOps]>,
Sched<[WriteMAC32, ReadMUL, ReadMUL, ReadMAC]> {
bits<4> Ra;
@@ -4491,14 +4493,15 @@ let Constraints = "@earlyclobber $Rd" in
def MLAv5: ARMPseudoExpand<(outs GPRnopc:$Rd),
(ins GPRnopc:$Rn, GPRnopc:$Rm, GPRnopc:$Ra,
pred:$p, cc_out:$s), 4, IIC_iMAC32,
- [(set GPRnopc:$Rd, (add (mul GPRnopc:$Rn, GPRnopc:$Rm), GPRnopc:$Ra))],
+ [],
(MLA GPRnopc:$Rd, GPRnopc:$Rn, GPRnopc:$Rm, GPRnopc:$Ra, pred:$p, cc_out:$s)>,
Requires<[IsARM, NoV6]>,
Sched<[WriteMAC32, ReadMUL, ReadMUL, ReadMAC]>;
+// No DAG pattern; MLS is formed by the ARM machine combiner.
def MLS : AMul1I<0b0000011, (outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm, GPR:$Ra),
IIC_iMAC32, "mls", "\t$Rd, $Rn, $Rm, $Ra",
- [(set GPR:$Rd, (sub GPR:$Ra, (mul GPR:$Rn, GPR:$Rm)))]>,
+ []>,
Requires<[IsARM, HasV6T2, UseMulOps]>,
Sched<[WriteMAC32, ReadMUL, ReadMUL, ReadMAC]> {
bits<4> Rd;
>From 69f10d31651302995e723521f09040ca8394ba68 Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
Date: Sat, 2 May 2026 20:31:52 -0400
Subject: [PATCH 6/6] d
---
llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp | 260 ++++++++++++++++--
llvm/test/CodeGen/ARM/addimm-mulimm.ll | 6 +-
.../CodeGen/ARM/srem-seteq-illegal-types.ll | 69 +++--
3 files changed, 276 insertions(+), 59 deletions(-)
diff --git a/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp b/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
index b796a686026b2..324dd7190166b 100644
--- a/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
+++ b/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
@@ -601,18 +601,18 @@ template <> bool IsCPSRDead<MachineInstr>(const MachineInstr *MI) {
} // end namespace llvm
//
-// Utility routine that checks if \param MO is defined by an
-// \param CombineOpc instruction in the basic block \param MBB.
-// ARM GPR \p MUL does not use AArch64-style MADD-with-zero; require \p MUL.
-static bool canCombine(MachineBasicBlock &MBB, MachineOperand &MO,
- unsigned CombineOpc) {
+// Utility routine that checks if \param MO is defined by an integer multiply
+// (\p MulOpc is ARM::MUL or ARM::t2MUL) in \p MBB and can be fused with its
+// single user.
+static bool canCombineMulDef(MachineBasicBlock &MBB, MachineOperand &MO,
+ unsigned MulOpc) {
MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();
MachineInstr *MI = nullptr;
if (MO.isReg() && MO.getReg().isVirtual())
MI = MRI.getUniqueVRegDef(MO.getReg());
// And it needs to be in the trace (otherwise, it won't have a depth).
- if (!MI || MI->getParent() != &MBB || MI->getOpcode() != CombineOpc)
+ if (!MI || MI->getParent() != &MBB || MI->getOpcode() != MulOpc)
return false;
// Must only used by the user we combine with.
if (!MRI.hasOneNonDBGUse(MI->getOperand(0).getReg()))
@@ -623,9 +623,12 @@ static bool canCombine(MachineBasicBlock &MBB, MachineOperand &MO,
//
// Is \param MO defined by an integer multiply and can be combined?
-static bool canCombineWithMUL(MachineBasicBlock &MBB, MachineOperand &MO,
- unsigned MulOpc) {
- return canCombine(MBB, MO, MulOpc);
+static bool canCombineWithMUL(MachineBasicBlock &MBB, MachineOperand &MO) {
+ return canCombineMulDef(MBB, MO, ARM::MUL);
+}
+
+static bool canCombineWithT2MUL(MachineBasicBlock &MBB, MachineOperand &MO) {
+ return canCombineMulDef(MBB, MO, ARM::t2MUL);
}
// GPR register/register add/sub roots that can fuse with ARM-mode \p MUL.
@@ -639,6 +642,17 @@ static bool isCombineInstrCandidate(unsigned Opc) {
}
}
+// Thumb2 GPR add/sub roots that can fuse with \p t2MUL.
+static bool isCombineThumb2InstrCandidate(unsigned Opc) {
+ switch (Opc) {
+ case ARM::t2ADDrr:
+ case ARM::t2SUBrr:
+ return true;
+ default:
+ return false;
+ }
+}
+
/// Append predicate / cc operands from \p Root onto \p MIB so they match \p
/// NewDesc's trailing operands (MLS has predicate only; MLA matches Root).
static void armAppendConditionOperands(MachineInstrBuilder &MIB,
@@ -654,6 +668,145 @@ static void armAppendConditionOperands(MachineInstrBuilder &MIB,
MIB.add(Root.getOperand(RP + i));
}
+/// Copy predicate / optional cc operands from \p Root so the fused Thumb2 MI
+/// matches \p NewDesc (e.g. \p t2MLA has predicate only; \p t2ADDrr has cc_out).
+static void thumb2AppendMatchingTailOperands(MachineInstrBuilder &MIB,
+ const MachineInstr &Root,
+ const MCInstrDesc &NewDesc) {
+ int RP = Root.findFirstPredOperandIdx();
+ int NP = NewDesc.findFirstPredOperandIdx();
+ assert(RP >= 0 && NP >= 0 && "Expected predicate operands");
+ unsigned NTailRoot = Root.getNumOperands() - RP;
+ unsigned NTailNew = NewDesc.getNumOperands() - NP;
+ unsigned NTail = std::min(NTailRoot, NTailNew);
+ for (unsigned i = 0; i < NTail; ++i)
+ MIB.add(Root.getOperand(RP + i));
+}
+
+/// Emit t2MLA merging Thumb2 \p Root with ARM::t2MUL feeding operand \p IdxMulOpd.
+static MachineInstr *genThumb2GPRMLA(MachineFunction &MF,
+ MachineRegisterInfo &MRI,
+ const TargetInstrInfo *TII, MachineInstr &Root,
+ SmallVectorImpl<MachineInstr *> &InsInstrs,
+ unsigned IdxMulOpd,
+ const TargetRegisterClass *RC) {
+ assert(IdxMulOpd == 1 || IdxMulOpd == 2);
+ MachineInstr *Mul =
+ MRI.getUniqueVRegDef(Root.getOperand(IdxMulOpd).getReg());
+ assert(Mul->getOpcode() == ARM::t2MUL && "Expected Thumb2 t2MUL");
+
+ Register Dst = Root.getOperand(0).getReg();
+ Register MulRn = Mul->getOperand(1).getReg();
+ bool MulRnKill = Mul->getOperand(1).isKill();
+ Register MulRm = Mul->getOperand(2).getReg();
+ bool MulRmKill = Mul->getOperand(2).isKill();
+ unsigned IdxOther = IdxMulOpd == 1 ? 2 : 1;
+ Register Other = Root.getOperand(IdxOther).getReg();
+ bool OtherKill = Root.getOperand(IdxOther).isKill();
+
+ if (Dst.isVirtual())
+ MRI.constrainRegClass(Dst, RC);
+ if (MulRn.isVirtual())
+ MRI.constrainRegClass(MulRn, RC);
+ if (MulRm.isVirtual())
+ MRI.constrainRegClass(MulRm, RC);
+ if (Other.isVirtual())
+ MRI.constrainRegClass(Other, RC);
+
+ MachineInstrBuilder MIB =
+ BuildMI(MF, MIMetadata(Root), TII->get(ARM::t2MLA), Dst)
+ .addReg(MulRn, getKillRegState(MulRnKill))
+ .addReg(MulRm, getKillRegState(MulRmKill))
+ .addReg(Other, getKillRegState(OtherKill));
+ thumb2AppendMatchingTailOperands(MIB, Root, TII->get(ARM::t2MLA));
+ InsInstrs.push_back(MIB);
+ return Mul;
+}
+
+/// Emit t2MLS Rd = Ra - Rn*Rm for t2SUBrr where \p IdxMulOpd points at the product.
+static MachineInstr *genThumb2GPRMLS(MachineFunction &MF,
+ MachineRegisterInfo &MRI,
+ const TargetInstrInfo *TII, MachineInstr &Root,
+ SmallVectorImpl<MachineInstr *> &InsInstrs,
+ unsigned IdxMulOpd,
+ const TargetRegisterClass *RC) {
+ assert(IdxMulOpd == 2 &&
+ "MLS fusion only matches SUB when multiply uses subtract operand");
+ MachineInstr *Mul =
+ MRI.getUniqueVRegDef(Root.getOperand(IdxMulOpd).getReg());
+ assert(Mul->getOpcode() == ARM::t2MUL && "Expected Thumb2 t2MUL");
+
+ Register Dst = Root.getOperand(0).getReg();
+ Register MulRn = Mul->getOperand(1).getReg();
+ bool MulRnKill = Mul->getOperand(1).isKill();
+ Register MulRm = Mul->getOperand(2).getReg();
+ bool MulRmKill = Mul->getOperand(2).isKill();
+ Register Ra = Root.getOperand(1).getReg();
+ bool RaKill = Root.getOperand(1).isKill();
+
+ if (Dst.isVirtual())
+ MRI.constrainRegClass(Dst, RC);
+ if (MulRn.isVirtual())
+ MRI.constrainRegClass(MulRn, RC);
+ if (MulRm.isVirtual())
+ MRI.constrainRegClass(MulRm, RC);
+ if (Ra.isVirtual())
+ MRI.constrainRegClass(Ra, RC);
+
+ MachineInstrBuilder MIB =
+ BuildMI(MF, MIMetadata(Root), TII->get(ARM::t2MLS), Dst)
+ .addReg(MulRn, getKillRegState(MulRnKill))
+ .addReg(MulRm, getKillRegState(MulRmKill))
+ .addReg(Ra, getKillRegState(RaKill));
+ thumb2AppendMatchingTailOperands(MIB, Root, TII->get(ARM::t2MLS));
+ InsInstrs.push_back(MIB);
+ return Mul;
+}
+
+/// t2SUBrr with mul on operand 1: emit t2RSBri + t2MLA.
+static MachineInstr *genThumb2GPRMLASubMulOp1(
+ MachineFunction &MF, MachineRegisterInfo &MRI, const TargetInstrInfo *TII,
+ MachineInstr &Root, SmallVectorImpl<MachineInstr *> &InsInstrs,
+ DenseMap<Register, unsigned> &InstrIdxForVirtReg) {
+ MachineInstr *Mul =
+ MRI.getUniqueVRegDef(Root.getOperand(1).getReg());
+ assert(Mul->getOpcode() == ARM::t2MUL && "Expected Thumb2 t2MUL");
+
+ Register Dst = Root.getOperand(0).getReg();
+ Register Other = Root.getOperand(2).getReg();
+ bool OtherKill = Root.getOperand(2).isKill();
+ Register MulRn = Mul->getOperand(1).getReg();
+ bool MulRnKill = Mul->getOperand(1).isKill();
+ Register MulRm = Mul->getOperand(2).getReg();
+ bool MulRmKill = Mul->getOperand(2).isKill();
+
+ const TargetRegisterClass *MLARc = &ARM::rGPRRegClass;
+ Register NegVr = MRI.createVirtualRegister(MLARc);
+ MachineInstrBuilder RsbMIB =
+ BuildMI(MF, MIMetadata(Root), TII->get(ARM::t2RSBri), NegVr)
+ .addReg(Other, getKillRegState(OtherKill))
+ .addImm(0);
+ thumb2AppendMatchingTailOperands(RsbMIB, Root, TII->get(ARM::t2RSBri));
+ InsInstrs.push_back(RsbMIB);
+ InstrIdxForVirtReg.insert(std::make_pair(NegVr, 0));
+
+ if (Dst.isVirtual())
+ MRI.constrainRegClass(Dst, MLARc);
+ if (MulRn.isVirtual())
+ MRI.constrainRegClass(MulRn, MLARc);
+ if (MulRm.isVirtual())
+ MRI.constrainRegClass(MulRm, MLARc);
+
+ MachineInstrBuilder MlaMIB =
+ BuildMI(MF, MIMetadata(Root), TII->get(ARM::t2MLA), Dst)
+ .addReg(MulRn, getKillRegState(MulRnKill))
+ .addReg(MulRm, getKillRegState(MulRmKill))
+ .addReg(NegVr, RegState::Kill);
+ thumb2AppendMatchingTailOperands(MlaMIB, Root, TII->get(ARM::t2MLA));
+ InsInstrs.push_back(MlaMIB);
+ return Mul;
+}
+
/// Emit MLA merging ARM-mode \p Root with ARM::MUL feeding operand \p IdxMulOpd.
static MachineInstr *genArmGPRMLA(MachineFunction &MF,
MachineRegisterInfo &MRI,
@@ -778,9 +931,55 @@ static MachineInstr *genArmGPRMLASubMulOp1(
return Mul;
}
+/// Find instructions that can be turned into t2MLA / t2MLS (Thumb2 GPR).
+static bool getThumb2MaddPatterns(const ARMSubtarget &Subtarget,
+ MachineInstr &Root,
+ SmallVectorImpl<unsigned> &Patterns) {
+ unsigned Opc = Root.getOpcode();
+ MachineBasicBlock &MBB = *Root.getParent();
+ bool Found = false;
+
+ if (!Subtarget.isThumb2() || !Subtarget.useMulOps())
+ return false;
+
+ if (!isCombineThumb2InstrCandidate(Opc))
+ return false;
+
+ // Same CPSR-def rule as ARM-mode fusion (t2ADDrr / t2SUBrr may set flags).
+ if (Root.findRegisterDefOperandIdx(ARM::CPSR, /*TRI=*/nullptr, false) != -1)
+ return false;
+
+ auto setFound = [&](unsigned OperandIdx, unsigned Pattern) {
+ if (!Root.getOperand(OperandIdx).isReg())
+ return;
+ if (canCombineWithT2MUL(MBB, Root.getOperand(OperandIdx))) {
+ Patterns.push_back(Pattern);
+ Found = true;
+ }
+ };
+
+ typedef ARMMachineCombinerPattern MCP;
+
+ switch (Opc) {
+ default:
+ break;
+ case ARM::t2ADDrr:
+ assert(Root.getOperand(1).isReg() && Root.getOperand(2).isReg() &&
+ "t2ADDrr must use register operands");
+ setFound(1, MCP::MULADD_OP1);
+ setFound(2, MCP::MULADD_OP2);
+ break;
+ case ARM::t2SUBrr:
+ setFound(2, MCP::MULSUB_OP2);
+ setFound(1, MCP::MULSUB_OP1);
+ break;
+ }
+ return Found;
+}
+
/// Find instructions that can be turned into MLA / MLS (ARM-state GPR).
-static bool getMaddPatterns(const ARMSubtarget &Subtarget, MachineInstr &Root,
- SmallVectorImpl<unsigned> &Patterns) {
+static bool getARMMaddPatterns(const ARMSubtarget &Subtarget, MachineInstr &Root,
+ SmallVectorImpl<unsigned> &Patterns) {
unsigned Opc = Root.getOpcode();
MachineBasicBlock &MBB = *Root.getParent();
bool Found = false;
@@ -810,7 +1009,7 @@ static bool getMaddPatterns(const ARMSubtarget &Subtarget, MachineInstr &Root,
auto setFound = [&](unsigned OperandIdx, unsigned Pattern) {
if (!Root.getOperand(OperandIdx).isReg())
return;
- if (canCombineWithMUL(MBB, Root.getOperand(OperandIdx), ARM::MUL)) {
+ if (canCombineWithMUL(MBB, Root.getOperand(OperandIdx))) {
Patterns.push_back(Pattern);
Found = true;
}
@@ -843,8 +1042,12 @@ bool ARMBaseInstrInfo::getMachineCombinerPatterns(
MachineInstr &Root, SmallVectorImpl<unsigned> &Patterns,
bool DoRegPressureReduce) const {
+ if (Subtarget.isThumb2()) {
+ if (getThumb2MaddPatterns(Subtarget, Root, Patterns))
+ return true;
+ }
if (!Subtarget.isThumb()) {
- if (getMaddPatterns(Subtarget, Root, Patterns))
+ if (getARMMaddPatterns(Subtarget, Root, Patterns))
return true;
}
@@ -864,6 +1067,8 @@ void ARMBaseInstrInfo::genAlternativeCodeSequence(
MachineInstr *MulToDelete = nullptr;
typedef ARMMachineCombinerPattern MCP;
+ const bool Thumb2GPRMLxRoot = Root.getOpcode() == ARM::t2ADDrr ||
+ Root.getOpcode() == ARM::t2SUBrr;
switch (Pattern) {
default:
@@ -871,20 +1076,33 @@ void ARMBaseInstrInfo::genAlternativeCodeSequence(
DelInstrs, InstrIdxForVirtReg);
return;
case MCP::MULADD_OP1:
- MulToDelete =
- genArmGPRMLA(MF, MRI, TII, Root, InsInstrs, 1, &ARM::GPRnopcRegClass);
+ MulToDelete = Thumb2GPRMLxRoot
+ ? genThumb2GPRMLA(MF, MRI, TII, Root, InsInstrs, 1,
+ &ARM::rGPRRegClass)
+ : genArmGPRMLA(MF, MRI, TII, Root, InsInstrs, 1,
+ &ARM::GPRnopcRegClass);
break;
case MCP::MULADD_OP2:
- MulToDelete =
- genArmGPRMLA(MF, MRI, TII, Root, InsInstrs, 2, &ARM::GPRnopcRegClass);
+ MulToDelete = Thumb2GPRMLxRoot
+ ? genThumb2GPRMLA(MF, MRI, TII, Root, InsInstrs, 2,
+ &ARM::rGPRRegClass)
+ : genArmGPRMLA(MF, MRI, TII, Root, InsInstrs, 2,
+ &ARM::GPRnopcRegClass);
break;
case MCP::MULSUB_OP1:
- MulToDelete = genArmGPRMLASubMulOp1(MF, MRI, TII, Root, InsInstrs,
- InstrIdxForVirtReg);
+ MulToDelete =
+ Thumb2GPRMLxRoot
+ ? genThumb2GPRMLASubMulOp1(MF, MRI, TII, Root, InsInstrs,
+ InstrIdxForVirtReg)
+ : genArmGPRMLASubMulOp1(MF, MRI, TII, Root, InsInstrs,
+ InstrIdxForVirtReg);
break;
case MCP::MULSUB_OP2:
- MulToDelete =
- genArmGPRMLS(MF, MRI, TII, Root, InsInstrs, 2, &ARM::GPRRegClass);
+ MulToDelete = Thumb2GPRMLxRoot
+ ? genThumb2GPRMLS(MF, MRI, TII, Root, InsInstrs, 2,
+ &ARM::rGPRRegClass)
+ : genArmGPRMLS(MF, MRI, TII, Root, InsInstrs, 2,
+ &ARM::GPRRegClass);
break;
}
diff --git a/llvm/test/CodeGen/ARM/addimm-mulimm.ll b/llvm/test/CodeGen/ARM/addimm-mulimm.ll
index ae9fc901bb4f2..eb3afa8201a47 100644
--- a/llvm/test/CodeGen/ARM/addimm-mulimm.ll
+++ b/llvm/test/CodeGen/ARM/addimm-mulimm.ll
@@ -447,9 +447,9 @@ define i16 @fold_add251_mul353_i16(i16 %a) {
;
; CHECK-ARMV7-LABEL: fold_add251_mul353_i16:
; CHECK-ARMV7: @ %bb.0:
-; CHECK-ARMV7-NEXT: movw r1, #23067
-; CHECK-ARMV7-NEXT: movw r2, #353
-; CHECK-ARMV7-NEXT: mla r0, r0, r2, r1
+; CHECK-ARMV7-NEXT: movw r1, #353
+; CHECK-ARMV7-NEXT: movw r2, #23067
+; CHECK-ARMV7-NEXT: mla r0, r0, r1, r2
; CHECK-ARMV7-NEXT: bx lr
;
; CHECK-THUMBV6M-LABEL: fold_add251_mul353_i16:
diff --git a/llvm/test/CodeGen/ARM/srem-seteq-illegal-types.ll b/llvm/test/CodeGen/ARM/srem-seteq-illegal-types.ll
index 4600a6c141e02..1ce3268e58da5 100644
--- a/llvm/test/CodeGen/ARM/srem-seteq-illegal-types.ll
+++ b/llvm/test/CodeGen/ARM/srem-seteq-illegal-types.ll
@@ -9,29 +9,30 @@
define i1 @test_srem_odd(i29 %X) nounwind {
; ARM5-LABEL: test_srem_odd:
; ARM5: @ %bb.0:
-; ARM5-NEXT: ldr r2, .LCPI0_1
; ARM5-NEXT: ldr r1, .LCPI0_0
-; ARM5-NEXT: mla r3, r0, r2, r1
+; ARM5-NEXT: mul r2, r0, r1
+; ARM5-NEXT: ldr r0, .LCPI0_1
+; ARM5-NEXT: add r0, r2, r0
; ARM5-NEXT: ldr r2, .LCPI0_2
+; ARM5-NEXT: bic r1, r0, #-536870912
; ARM5-NEXT: mov r0, #0
-; ARM5-NEXT: bic r1, r3, #-536870912
; ARM5-NEXT: cmp r1, r2
; ARM5-NEXT: movlo r0, #1
; ARM5-NEXT: bx lr
; ARM5-NEXT: .p2align 2
; ARM5-NEXT: @ %bb.1:
; ARM5-NEXT: .LCPI0_0:
-; ARM5-NEXT: .long 2711469 @ 0x295fad
-; ARM5-NEXT: .LCPI0_1:
; ARM5-NEXT: .long 526025035 @ 0x1f5a814b
+; ARM5-NEXT: .LCPI0_1:
+; ARM5-NEXT: .long 2711469 @ 0x295fad
; ARM5-NEXT: .LCPI0_2:
; ARM5-NEXT: .long 5422939 @ 0x52bf5b
;
; ARM6-LABEL: test_srem_odd:
; ARM6: @ %bb.0:
-; ARM6-NEXT: ldr r2, .LCPI0_1
; ARM6-NEXT: ldr r1, .LCPI0_0
-; ARM6-NEXT: mla r0, r0, r2, r1
+; ARM6-NEXT: ldr r2, .LCPI0_1
+; ARM6-NEXT: mla r0, r0, r1, r2
; ARM6-NEXT: ldr r2, .LCPI0_2
; ARM6-NEXT: bic r1, r0, #-536870912
; ARM6-NEXT: mov r0, #0
@@ -41,19 +42,19 @@ define i1 @test_srem_odd(i29 %X) nounwind {
; ARM6-NEXT: .p2align 2
; ARM6-NEXT: @ %bb.1:
; ARM6-NEXT: .LCPI0_0:
-; ARM6-NEXT: .long 2711469 @ 0x295fad
-; ARM6-NEXT: .LCPI0_1:
; ARM6-NEXT: .long 526025035 @ 0x1f5a814b
+; ARM6-NEXT: .LCPI0_1:
+; ARM6-NEXT: .long 2711469 @ 0x295fad
; ARM6-NEXT: .LCPI0_2:
; ARM6-NEXT: .long 5422939 @ 0x52bf5b
;
; ARM7-LABEL: test_srem_odd:
; ARM7: @ %bb.0:
-; ARM7-NEXT: movw r1, #24493
-; ARM7-NEXT: movw r2, #33099
-; ARM7-NEXT: movt r1, #41
-; ARM7-NEXT: movt r2, #8026
-; ARM7-NEXT: mla r0, r0, r2, r1
+; ARM7-NEXT: movw r1, #33099
+; ARM7-NEXT: movw r2, #24493
+; ARM7-NEXT: movt r1, #8026
+; ARM7-NEXT: movt r2, #41
+; ARM7-NEXT: mla r0, r0, r1, r2
; ARM7-NEXT: movw r2, #48987
; ARM7-NEXT: movt r2, #82
; ARM7-NEXT: bic r1, r0, #-536870912
@@ -64,11 +65,11 @@ define i1 @test_srem_odd(i29 %X) nounwind {
;
; ARM8-LABEL: test_srem_odd:
; ARM8: @ %bb.0:
-; ARM8-NEXT: movw r1, #24493
-; ARM8-NEXT: movw r2, #33099
-; ARM8-NEXT: movt r1, #41
-; ARM8-NEXT: movt r2, #8026
-; ARM8-NEXT: mla r0, r0, r2, r1
+; ARM8-NEXT: movw r1, #33099
+; ARM8-NEXT: movw r2, #24493
+; ARM8-NEXT: movt r1, #8026
+; ARM8-NEXT: movt r2, #41
+; ARM8-NEXT: mla r0, r0, r1, r2
; ARM8-NEXT: movw r2, #48987
; ARM8-NEXT: movt r2, #82
; ARM8-NEXT: bic r1, r0, #-536870912
@@ -79,11 +80,11 @@ define i1 @test_srem_odd(i29 %X) nounwind {
;
; NEON7-LABEL: test_srem_odd:
; NEON7: @ %bb.0:
-; NEON7-NEXT: movw r1, #24493
-; NEON7-NEXT: movw r2, #33099
-; NEON7-NEXT: movt r1, #41
-; NEON7-NEXT: movt r2, #8026
-; NEON7-NEXT: mla r0, r0, r2, r1
+; NEON7-NEXT: movw r1, #33099
+; NEON7-NEXT: movw r2, #24493
+; NEON7-NEXT: movt r1, #8026
+; NEON7-NEXT: movt r2, #41
+; NEON7-NEXT: mla r0, r0, r1, r2
; NEON7-NEXT: movw r2, #48987
; NEON7-NEXT: movt r2, #82
; NEON7-NEXT: bic r1, r0, #-536870912
@@ -94,11 +95,11 @@ define i1 @test_srem_odd(i29 %X) nounwind {
;
; NEON8-LABEL: test_srem_odd:
; NEON8: @ %bb.0:
-; NEON8-NEXT: movw r1, #24493
-; NEON8-NEXT: movw r2, #33099
-; NEON8-NEXT: movt r1, #41
-; NEON8-NEXT: movt r2, #8026
-; NEON8-NEXT: mla r0, r0, r2, r1
+; NEON8-NEXT: movw r1, #33099
+; NEON8-NEXT: movw r2, #24493
+; NEON8-NEXT: movt r1, #8026
+; NEON8-NEXT: movt r2, #41
+; NEON8-NEXT: mla r0, r0, r1, r2
; NEON8-NEXT: movw r2, #48987
; NEON8-NEXT: movt r2, #82
; NEON8-NEXT: bic r1, r0, #-536870912
@@ -119,9 +120,8 @@ define i1 @test_srem_even(i4 %X) nounwind {
; ARM5-NEXT: add r1, r1, r1, lsl #1
; ARM5-NEXT: lsr r2, r1, #4
; ARM5-NEXT: add r1, r2, r1, lsr #31
-; ARM5-NEXT: mov r2, #6
-; ARM5-NEXT: mul r3, r1, r2
-; ARM5-NEXT: sub r0, r0, r3
+; ARM5-NEXT: add r1, r1, r1, lsl #1
+; ARM5-NEXT: sub r0, r0, r1, lsl #1
; ARM5-NEXT: and r0, r0, #15
; ARM5-NEXT: sub r0, r0, #1
; ARM5-NEXT: clz r0, r0
@@ -135,9 +135,8 @@ define i1 @test_srem_even(i4 %X) nounwind {
; ARM6-NEXT: add r1, r1, r1, lsl #1
; ARM6-NEXT: lsr r2, r1, #4
; ARM6-NEXT: add r1, r2, r1, lsr #31
-; ARM6-NEXT: mov r2, #6
-; ARM6-NEXT: mul r1, r1, r2
-; ARM6-NEXT: sub r0, r0, r1
+; ARM6-NEXT: add r1, r1, r1, lsl #1
+; ARM6-NEXT: sub r0, r0, r1, lsl #1
; ARM6-NEXT: and r0, r0, #15
; ARM6-NEXT: sub r0, r0, #1
; ARM6-NEXT: clz r0, r0
More information about the llvm-commits
mailing list