[llvm] 936c777 - [AArch64] Adds a pre-indexed paired Load/Store optimization for LDR-STR.
Stelios Ioannou via llvm-commits
llvm-commits at lists.llvm.org
Fri Apr 30 09:30:11 PDT 2021
Author: Stelios Ioannou
Date: 2021-04-30T17:29:58+01:00
New Revision: 936c777e2bf86cd78b532c1331c4f7ee90b95383
URL: https://github.com/llvm/llvm-project/commit/936c777e2bf86cd78b532c1331c4f7ee90b95383
DIFF: https://github.com/llvm/llvm-project/commit/936c777e2bf86cd78b532c1331c4f7ee90b95383.diff
LOG: [AArch64] Adds a pre-indexed paired Load/Store optimization for LDR-STR.
This patch merges STR<S,D,Q,W,X>pre-STR<S,D,Q,W,X>ui and
LDR<S,D,Q,W,X>pre-LDR<S,D,Q,W,X>ui instruction pairs into a single
STP<S,D,Q,W,X>pre and LDP<S,D,Q,W,X>pre instruction, respectively.
For each pair, there is a MIR test that verifies this optimization.
Differential Revision: https://reviews.llvm.org/D99272
Change-Id: Ie97a20c8c716c08492fe229c22e14e3c98ef08b7
Added:
llvm/test/CodeGen/AArch64/ldrpre-ldr-merge.mir
llvm/test/CodeGen/AArch64/strpre-str-merge.mir
Modified:
llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
llvm/lib/Target/AArch64/AArch64InstrInfo.h
llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp
llvm/test/CodeGen/AArch64/arm64-memset-inline.ll
Removed:
################################################################################
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
index 28edf104fc0b..02fc4033e189 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
@@ -2118,22 +2118,32 @@ bool AArch64InstrInfo::isStridedAccess(const MachineInstr &MI) {
});
}
-bool AArch64InstrInfo::isUnscaledLdSt(unsigned Opc) {
+bool AArch64InstrInfo::hasUnscaledLdStOffset(unsigned Opc) {
switch (Opc) {
default:
return false;
case AArch64::STURSi:
+ case AArch64::STRSpre:
case AArch64::STURDi:
+ case AArch64::STRDpre:
case AArch64::STURQi:
+ case AArch64::STRQpre:
case AArch64::STURBBi:
case AArch64::STURHHi:
case AArch64::STURWi:
+ case AArch64::STRWpre:
case AArch64::STURXi:
+ case AArch64::STRXpre:
case AArch64::LDURSi:
+ case AArch64::LDRSpre:
case AArch64::LDURDi:
+ case AArch64::LDRDpre:
case AArch64::LDURQi:
+ case AArch64::LDRQpre:
case AArch64::LDURWi:
+ case AArch64::LDRWpre:
case AArch64::LDURXi:
+ case AArch64::LDRXpre:
case AArch64::LDURSWi:
case AArch64::LDURHHi:
case AArch64::LDURBBi:
@@ -2252,15 +2262,25 @@ bool AArch64InstrInfo::isPairableLdStInst(const MachineInstr &MI) {
case AArch64::LDRSWui:
// Unscaled instructions.
case AArch64::STURSi:
+ case AArch64::STRSpre:
case AArch64::STURDi:
+ case AArch64::STRDpre:
case AArch64::STURQi:
+ case AArch64::STRQpre:
case AArch64::STURWi:
+ case AArch64::STRWpre:
case AArch64::STURXi:
+ case AArch64::STRXpre:
case AArch64::LDURSi:
+ case AArch64::LDRSpre:
case AArch64::LDURDi:
+ case AArch64::LDRDpre:
case AArch64::LDURQi:
+ case AArch64::LDRQpre:
case AArch64::LDURWi:
+ case AArch64::LDRWpre:
case AArch64::LDURXi:
+ case AArch64::LDRXpre:
case AArch64::LDURSWi:
return true;
}
@@ -2357,20 +2377,36 @@ unsigned AArch64InstrInfo::convertToFlagSettingOpc(unsigned Opc,
// Is this a candidate for ld/st merging or pairing? For example, we don't
// touch volatiles or load/stores that have a hint to avoid pair formation.
bool AArch64InstrInfo::isCandidateToMergeOrPair(const MachineInstr &MI) const {
+
+ bool IsPreLdSt = isPreLdSt(MI);
+
// If this is a volatile load/store, don't mess with it.
if (MI.hasOrderedMemoryRef())
return false;
// Make sure this is a reg/fi+imm (as opposed to an address reloc).
- assert((MI.getOperand(1).isReg() || MI.getOperand(1).isFI()) &&
+ // For Pre-inc LD/ST, the operand is shifted by one.
+ assert((MI.getOperand(IsPreLdSt ? 2 : 1).isReg() ||
+ MI.getOperand(IsPreLdSt ? 2 : 1).isFI()) &&
"Expected a reg or frame index operand.");
- if (!MI.getOperand(2).isImm())
+
+ // For Pre-indexed addressing quadword instructions, the third operand is the
+ // immediate value.
+ bool IsImmPreLdSt = IsPreLdSt && MI.getOperand(3).isImm();
+
+ if (!MI.getOperand(2).isImm() && !IsImmPreLdSt)
return false;
// Can't merge/pair if the instruction modifies the base register.
// e.g., ldr x0, [x0]
// This case will never occur with an FI base.
- if (MI.getOperand(1).isReg()) {
+ // However, if the instruction is an LDR/STR<S,D,Q,W,X>pre, it can be merged.
+ // For example:
+ // ldr q0, [x11, #32]!
+ // ldr q1, [x11, #16]
+ // to
+ // ldp q0, q1, [x11, #32]!
+ if (MI.getOperand(1).isReg() && !IsPreLdSt) {
Register BaseReg = MI.getOperand(1).getReg();
const TargetRegisterInfo *TRI = &getRegisterInfo();
if (MI.modifiesRegister(BaseReg, TRI))
@@ -2799,14 +2835,18 @@ int AArch64InstrInfo::getMemScale(unsigned Opc) {
return 2;
case AArch64::LDRSui:
case AArch64::LDURSi:
+ case AArch64::LDRSpre:
case AArch64::LDRSWui:
case AArch64::LDURSWi:
+ case AArch64::LDRWpre:
case AArch64::LDRWui:
case AArch64::LDURWi:
case AArch64::STRSui:
case AArch64::STURSi:
+ case AArch64::STRSpre:
case AArch64::STRWui:
case AArch64::STURWi:
+ case AArch64::STRWpre:
case AArch64::LDPSi:
case AArch64::LDPSWi:
case AArch64::LDPWi:
@@ -2815,12 +2855,16 @@ int AArch64InstrInfo::getMemScale(unsigned Opc) {
return 4;
case AArch64::LDRDui:
case AArch64::LDURDi:
+ case AArch64::LDRDpre:
case AArch64::LDRXui:
case AArch64::LDURXi:
+ case AArch64::LDRXpre:
case AArch64::STRDui:
case AArch64::STURDi:
+ case AArch64::STRDpre:
case AArch64::STRXui:
case AArch64::STURXi:
+ case AArch64::STRXpre:
case AArch64::LDPDi:
case AArch64::LDPXi:
case AArch64::STPDi:
@@ -2830,7 +2874,9 @@ int AArch64InstrInfo::getMemScale(unsigned Opc) {
case AArch64::LDURQi:
case AArch64::STRQui:
case AArch64::STURQi:
+ case AArch64::STRQpre:
case AArch64::LDPQi:
+ case AArch64::LDRQpre:
case AArch64::STPQi:
case AArch64::STGOffset:
case AArch64::STZGOffset:
@@ -2841,6 +2887,36 @@ int AArch64InstrInfo::getMemScale(unsigned Opc) {
}
}
+bool AArch64InstrInfo::isPreLd(const MachineInstr &MI) {
+ switch (MI.getOpcode()) {
+ default:
+ return false;
+ case AArch64::LDRWpre:
+ case AArch64::LDRXpre:
+ case AArch64::LDRSpre:
+ case AArch64::LDRDpre:
+ case AArch64::LDRQpre:
+ return true;
+ }
+}
+
+bool AArch64InstrInfo::isPreSt(const MachineInstr &MI) {
+ switch (MI.getOpcode()) {
+ default:
+ return false;
+ case AArch64::STRWpre:
+ case AArch64::STRXpre:
+ case AArch64::STRSpre:
+ case AArch64::STRDpre:
+ case AArch64::STRQpre:
+ return true;
+ }
+}
+
+bool AArch64InstrInfo::isPreLdSt(const MachineInstr &MI) {
+ return isPreLd(MI) || isPreSt(MI);
+}
+
// Scale the unscaled offsets. Returns false if the unscaled offset can't be
// scaled.
static bool scaleOffset(unsigned Opc, int64_t &Offset) {
@@ -2944,11 +3020,11 @@ bool AArch64InstrInfo::shouldClusterMemOps(
// isCandidateToMergeOrPair guarantees that operand 2 is an immediate.
int64_t Offset1 = FirstLdSt.getOperand(2).getImm();
- if (isUnscaledLdSt(FirstOpc) && !scaleOffset(FirstOpc, Offset1))
+ if (hasUnscaledLdStOffset(FirstOpc) && !scaleOffset(FirstOpc, Offset1))
return false;
int64_t Offset2 = SecondLdSt.getOperand(2).getImm();
- if (isUnscaledLdSt(SecondOpc) && !scaleOffset(SecondOpc, Offset2))
+ if (hasUnscaledLdStOffset(SecondOpc) && !scaleOffset(SecondOpc, Offset2))
return false;
// Pairwise instructions have a 7-bit signed offset field.
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.h b/llvm/lib/Target/AArch64/AArch64InstrInfo.h
index 29492af716be..dd22e64ab713 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.h
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.h
@@ -79,10 +79,10 @@ class AArch64InstrInfo final : public AArch64GenInstrInfo {
/// Return true if the given load or store is a strided memory access.
static bool isStridedAccess(const MachineInstr &MI);
- /// Return true if this is an unscaled load/store.
- static bool isUnscaledLdSt(unsigned Opc);
- static bool isUnscaledLdSt(MachineInstr &MI) {
- return isUnscaledLdSt(MI.getOpcode());
+ /// Return true if it has an unscaled load/store offset.
+ static bool hasUnscaledLdStOffset(unsigned Opc);
+ static bool hasUnscaledLdStOffset(MachineInstr &MI) {
+ return hasUnscaledLdStOffset(MI.getOpcode());
}
/// Returns the unscaled load/store for the scaled load/store opcode,
@@ -95,6 +95,14 @@ class AArch64InstrInfo final : public AArch64GenInstrInfo {
return getMemScale(MI.getOpcode());
}
+ /// Returns whether the instruction is a pre-indexed load.
+ static bool isPreLd(const MachineInstr &MI);
+
+ /// Returns whether the instruction is a pre-indexed store.
+ static bool isPreSt(const MachineInstr &MI);
+
+ /// Returns whether the instruction is a pre-indexed load/store.
+ static bool isPreLdSt(const MachineInstr &MI);
/// Returns the index for the immediate for a given instruction.
static unsigned getLoadStoreImmIdx(unsigned Opc);
diff --git a/llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp b/llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp
index c56f4660bb1b..012bbd7eaca9 100644
--- a/llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp
+++ b/llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp
@@ -248,28 +248,38 @@ static unsigned getMatchingNonSExtOpcode(unsigned Opc,
return std::numeric_limits<unsigned>::max();
case AArch64::STRDui:
case AArch64::STURDi:
+ case AArch64::STRDpre:
case AArch64::STRQui:
case AArch64::STURQi:
+ case AArch64::STRQpre:
case AArch64::STRBBui:
case AArch64::STURBBi:
case AArch64::STRHHui:
case AArch64::STURHHi:
case AArch64::STRWui:
+ case AArch64::STRWpre:
case AArch64::STURWi:
case AArch64::STRXui:
+ case AArch64::STRXpre:
case AArch64::STURXi:
case AArch64::LDRDui:
case AArch64::LDURDi:
+ case AArch64::LDRDpre:
case AArch64::LDRQui:
case AArch64::LDURQi:
+ case AArch64::LDRQpre:
case AArch64::LDRWui:
case AArch64::LDURWi:
+ case AArch64::LDRWpre:
case AArch64::LDRXui:
case AArch64::LDURXi:
+ case AArch64::LDRXpre:
case AArch64::STRSui:
case AArch64::STURSi:
+ case AArch64::STRSpre:
case AArch64::LDRSui:
case AArch64::LDURSi:
+ case AArch64::LDRSpre:
return Opc;
case AArch64::LDRSWui:
return AArch64::LDRWui;
@@ -304,33 +314,53 @@ static unsigned getMatchingPairOpcode(unsigned Opc) {
case AArch64::STRSui:
case AArch64::STURSi:
return AArch64::STPSi;
+ case AArch64::STRSpre:
+ return AArch64::STPSpre;
case AArch64::STRDui:
case AArch64::STURDi:
return AArch64::STPDi;
+ case AArch64::STRDpre:
+ return AArch64::STPDpre;
case AArch64::STRQui:
case AArch64::STURQi:
return AArch64::STPQi;
+ case AArch64::STRQpre:
+ return AArch64::STPQpre;
case AArch64::STRWui:
case AArch64::STURWi:
return AArch64::STPWi;
+ case AArch64::STRWpre:
+ return AArch64::STPWpre;
case AArch64::STRXui:
case AArch64::STURXi:
return AArch64::STPXi;
+ case AArch64::STRXpre:
+ return AArch64::STPXpre;
case AArch64::LDRSui:
case AArch64::LDURSi:
return AArch64::LDPSi;
+ case AArch64::LDRSpre:
+ return AArch64::LDPSpre;
case AArch64::LDRDui:
case AArch64::LDURDi:
return AArch64::LDPDi;
+ case AArch64::LDRDpre:
+ return AArch64::LDPDpre;
case AArch64::LDRQui:
case AArch64::LDURQi:
return AArch64::LDPQi;
+ case AArch64::LDRQpre:
+ return AArch64::LDPQpre;
case AArch64::LDRWui:
case AArch64::LDURWi:
return AArch64::LDPWi;
+ case AArch64::LDRWpre:
+ return AArch64::LDPWpre;
case AArch64::LDRXui:
case AArch64::LDURXi:
return AArch64::LDPXi;
+ case AArch64::LDRXpre:
+ return AArch64::LDPXpre;
case AArch64::LDRSWui:
case AArch64::LDURSWi:
return AArch64::LDPSWi;
@@ -539,6 +569,37 @@ static bool isPairedLdSt(const MachineInstr &MI) {
}
}
+static bool isPreLdStPairCandidate(MachineInstr &FirstMI, MachineInstr &MI) {
+
+ unsigned OpcA = FirstMI.getOpcode();
+ unsigned OpcB = MI.getOpcode();
+
+ switch (OpcA) {
+ default:
+ return false;
+ case AArch64::STRSpre:
+ return (OpcB == AArch64::STRSui) || (OpcB == AArch64::STURSi);
+ case AArch64::STRDpre:
+ return (OpcB == AArch64::STRDui) || (OpcB == AArch64::STURDi);
+ case AArch64::STRQpre:
+ return (OpcB == AArch64::STRQui) || (OpcB == AArch64::STURQi);
+ case AArch64::STRWpre:
+ return (OpcB == AArch64::STRWui) || (OpcB == AArch64::STURWi);
+ case AArch64::STRXpre:
+ return (OpcB == AArch64::STRXui) || (OpcB == AArch64::STURXi);
+ case AArch64::LDRSpre:
+ return (OpcB == AArch64::LDRSui) || (OpcB == AArch64::LDURSi);
+ case AArch64::LDRDpre:
+ return (OpcB == AArch64::LDRDui) || (OpcB == AArch64::LDURDi);
+ case AArch64::LDRQpre:
+ return (OpcB == AArch64::LDRQui) || (OpcB == AArch64::LDURQi);
+ case AArch64::LDRWpre:
+ return (OpcB == AArch64::LDRWui) || (OpcB == AArch64::LDURWi);
+ case AArch64::LDRXpre:
+ return (OpcB == AArch64::LDRXui) || (OpcB == AArch64::LDURXi);
+ }
+}
+
// Returns the scale and offset range of pre/post indexed variants of MI.
static void getPrePostIndexedMemOpInfo(const MachineInstr &MI, int &Scale,
int &MinOffset, int &MaxOffset) {
@@ -561,17 +622,20 @@ static void getPrePostIndexedMemOpInfo(const MachineInstr &MI, int &Scale,
static MachineOperand &getLdStRegOp(MachineInstr &MI,
unsigned PairedRegOp = 0) {
assert(PairedRegOp < 2 && "Unexpected register operand idx.");
- unsigned Idx = isPairedLdSt(MI) ? PairedRegOp : 0;
+ bool IsPreLdSt = AArch64InstrInfo::isPreLdSt(MI);
+ if (IsPreLdSt)
+ PairedRegOp += 1;
+ unsigned Idx = isPairedLdSt(MI) || IsPreLdSt ? PairedRegOp : 0;
return MI.getOperand(Idx);
}
static const MachineOperand &getLdStBaseOp(const MachineInstr &MI) {
- unsigned Idx = isPairedLdSt(MI) ? 2 : 1;
+ unsigned Idx = isPairedLdSt(MI) || AArch64InstrInfo::isPreLdSt(MI) ? 2 : 1;
return MI.getOperand(Idx);
}
static const MachineOperand &getLdStOffsetOp(const MachineInstr &MI) {
- unsigned Idx = isPairedLdSt(MI) ? 3 : 2;
+ unsigned Idx = isPairedLdSt(MI) || AArch64InstrInfo::isPreLdSt(MI) ? 3 : 2;
return MI.getOperand(Idx);
}
@@ -581,10 +645,10 @@ static bool isLdOffsetInRangeOfSt(MachineInstr &LoadInst,
assert(isMatchingStore(LoadInst, StoreInst) && "Expect only matched ld/st.");
int LoadSize = TII->getMemScale(LoadInst);
int StoreSize = TII->getMemScale(StoreInst);
- int UnscaledStOffset = TII->isUnscaledLdSt(StoreInst)
+ int UnscaledStOffset = TII->hasUnscaledLdStOffset(StoreInst)
? getLdStOffsetOp(StoreInst).getImm()
: getLdStOffsetOp(StoreInst).getImm() * StoreSize;
- int UnscaledLdOffset = TII->isUnscaledLdSt(LoadInst)
+ int UnscaledLdOffset = TII->hasUnscaledLdStOffset(LoadInst)
? getLdStOffsetOp(LoadInst).getImm()
: getLdStOffsetOp(LoadInst).getImm() * LoadSize;
return (UnscaledStOffset <= UnscaledLdOffset) &&
@@ -689,7 +753,7 @@ AArch64LoadStoreOpt::mergeNarrowZeroStores(MachineBasicBlock::iterator I,
NextI = next_nodbg(NextI, E);
unsigned Opc = I->getOpcode();
- bool IsScaled = !TII->isUnscaledLdSt(Opc);
+ bool IsScaled = !TII->hasUnscaledLdStOffset(Opc);
int OffsetStride = IsScaled ? 1 : TII->getMemScale(*I);
bool MergeForward = Flags.getMergeForward();
@@ -795,7 +859,7 @@ AArch64LoadStoreOpt::mergePairedInsns(MachineBasicBlock::iterator I,
int SExtIdx = Flags.getSExtIdx();
unsigned Opc =
SExtIdx == -1 ? I->getOpcode() : getMatchingNonSExtOpcode(I->getOpcode());
- bool IsUnscaled = TII->isUnscaledLdSt(Opc);
+ bool IsUnscaled = TII->hasUnscaledLdStOffset(Opc);
int OffsetStride = IsUnscaled ? TII->getMemScale(*I) : 1;
bool MergeForward = Flags.getMergeForward();
@@ -876,7 +940,7 @@ AArch64LoadStoreOpt::mergePairedInsns(MachineBasicBlock::iterator I,
int Offset = getLdStOffsetOp(*I).getImm();
int PairedOffset = getLdStOffsetOp(*Paired).getImm();
- bool PairedIsUnscaled = TII->isUnscaledLdSt(Paired->getOpcode());
+ bool PairedIsUnscaled = TII->hasUnscaledLdStOffset(Paired->getOpcode());
if (IsUnscaled != PairedIsUnscaled) {
// We're trying to pair instructions that
diff er in how they are scaled. If
// I is scaled then scale the offset of Paired accordingly. Otherwise, do
@@ -894,8 +958,11 @@ AArch64LoadStoreOpt::mergePairedInsns(MachineBasicBlock::iterator I,
}
// Which register is Rt and which is Rt2 depends on the offset order.
+ // However, for pre load/stores the Rt should be the one of the pre
+ // load/store.
MachineInstr *RtMI, *Rt2MI;
- if (Offset == PairedOffset + OffsetStride) {
+ if (Offset == PairedOffset + OffsetStride &&
+ !AArch64InstrInfo::isPreLdSt(*I)) {
RtMI = &*Paired;
Rt2MI = &*I;
// Here we swapped the assumption made for SExtIdx.
@@ -909,7 +976,7 @@ AArch64LoadStoreOpt::mergePairedInsns(MachineBasicBlock::iterator I,
}
int OffsetImm = getLdStOffsetOp(*RtMI).getImm();
// Scale the immediate offset, if necessary.
- if (TII->isUnscaledLdSt(RtMI->getOpcode())) {
+ if (TII->hasUnscaledLdStOffset(RtMI->getOpcode())) {
assert(!(OffsetImm % TII->getMemScale(*RtMI)) &&
"Unscaled offset cannot be scaled.");
OffsetImm /= TII->getMemScale(*RtMI);
@@ -940,13 +1007,20 @@ AArch64LoadStoreOpt::mergePairedInsns(MachineBasicBlock::iterator I,
MI.clearRegisterKills(Reg, TRI);
}
}
- MIB = BuildMI(*MBB, InsertionPoint, DL, TII->get(getMatchingPairOpcode(Opc)))
- .add(RegOp0)
- .add(RegOp1)
- .add(BaseRegOp)
- .addImm(OffsetImm)
- .cloneMergedMemRefs({&*I, &*Paired})
- .setMIFlags(I->mergeFlagsWith(*Paired));
+
+ unsigned int MatchPairOpcode = getMatchingPairOpcode(Opc);
+ MIB = BuildMI(*MBB, InsertionPoint, DL, TII->get(MatchPairOpcode));
+
+ // Adds the pre-index operand for pre-indexed ld/st pairs.
+ if (AArch64InstrInfo::isPreLdSt(*RtMI))
+ MIB.addReg(BaseRegOp.getReg(), RegState::Define);
+
+ MIB.add(RegOp0)
+ .add(RegOp1)
+ .add(BaseRegOp)
+ .addImm(OffsetImm)
+ .cloneMergedMemRefs({&*I, &*Paired})
+ .setMIFlags(I->mergeFlagsWith(*Paired));
(void)MIB;
@@ -1054,8 +1128,8 @@ AArch64LoadStoreOpt::promoteLoadFromStore(MachineBasicBlock::iterator LoadI,
// performance and correctness are verified only in little-endian.
if (!Subtarget->isLittleEndian())
return NextI;
- bool IsUnscaled = TII->isUnscaledLdSt(*LoadI);
- assert(IsUnscaled == TII->isUnscaledLdSt(*StoreI) &&
+ bool IsUnscaled = TII->hasUnscaledLdStOffset(*LoadI);
+ assert(IsUnscaled == TII->hasUnscaledLdStOffset(*StoreI) &&
"Unsupported ld/st match");
assert(LoadSize <= StoreSize && "Invalid load size");
int UnscaledLdOffset = IsUnscaled
@@ -1232,9 +1306,9 @@ static bool areCandidatesToMergeOrPair(MachineInstr &FirstMI, MachineInstr &MI,
unsigned OpcA = FirstMI.getOpcode();
unsigned OpcB = MI.getOpcode();
- // Opcodes match: nothing more to check.
+ // Opcodes match: If the opcodes are pre ld/st there is nothing more to check.
if (OpcA == OpcB)
- return true;
+ return !AArch64InstrInfo::isPreLdSt(FirstMI);
// Try to match a sign-extended load/store with a zero-extended load/store.
bool IsValidLdStrOpc, PairIsValidLdStrOpc;
@@ -1257,8 +1331,14 @@ static bool areCandidatesToMergeOrPair(MachineInstr &FirstMI, MachineInstr &MI,
if (isNarrowStore(OpcA) || isNarrowStore(OpcB))
return false;
+ // The STR<S,D,Q,W,X>pre - STR<S,D,Q,W,X>ui and
+ // LDR<S,D,Q,W,X>pre-LDR<S,D,Q,W,X>ui
+ // are candidate pairs that can be merged.
+ if (isPreLdStPairCandidate(FirstMI, MI))
+ return true;
+
// Try to match an unscaled load/store with a scaled load/store.
- return TII->isUnscaledLdSt(OpcA) != TII->isUnscaledLdSt(OpcB) &&
+ return TII->hasUnscaledLdStOffset(OpcA) != TII->hasUnscaledLdStOffset(OpcB) &&
getMatchingPairOpcode(OpcA) == getMatchingPairOpcode(OpcB);
// FIXME: Can we also match a mixed sext/zext unscaled/scaled pair?
@@ -1448,7 +1528,7 @@ AArch64LoadStoreOpt::findMatchingInsn(MachineBasicBlock::iterator I,
MBBI = next_nodbg(MBBI, E);
bool MayLoad = FirstMI.mayLoad();
- bool IsUnscaled = TII->isUnscaledLdSt(FirstMI);
+ bool IsUnscaled = TII->hasUnscaledLdStOffset(FirstMI);
Register Reg = getLdStRegOp(FirstMI).getReg();
Register BaseReg = getLdStBaseOp(FirstMI).getReg();
int Offset = getLdStOffsetOp(FirstMI).getImm();
@@ -1496,7 +1576,7 @@ AArch64LoadStoreOpt::findMatchingInsn(MachineBasicBlock::iterator I,
// a relocation.
Register MIBaseReg = getLdStBaseOp(MI).getReg();
int MIOffset = getLdStOffsetOp(MI).getImm();
- bool MIIsUnscaled = TII->isUnscaledLdSt(MI);
+ bool MIIsUnscaled = TII->hasUnscaledLdStOffset(MI);
if (IsUnscaled != MIIsUnscaled) {
// We're trying to pair instructions that
diff er in how they are scaled.
// If FirstMI is scaled then scale the offset of MI accordingly.
@@ -1517,8 +1597,35 @@ AArch64LoadStoreOpt::findMatchingInsn(MachineBasicBlock::iterator I,
}
}
- if (BaseReg == MIBaseReg && ((Offset == MIOffset + OffsetStride) ||
- (Offset + OffsetStride == MIOffset))) {
+ bool IsPreLdSt = isPreLdStPairCandidate(FirstMI, MI);
+
+ if (BaseReg == MIBaseReg) {
+ // If the offset of the second ld/st is not equal to the size of the
+ // destination register it can’t be paired with a pre-index ld/st
+ // pair. Additionally if the base reg is used or modified the operations
+ // can't be paired: bail and keep looking.
+ if (IsPreLdSt) {
+ bool IsOutOfBounds = MIOffset != TII->getMemScale(MI);
+ bool IsBaseRegUsed =
+ !UsedRegUnits.available(getLdStBaseOp(MI).getReg());
+ bool IsBaseRegModified =
+ !ModifiedRegUnits.available(getLdStBaseOp(MI).getReg());
+ if (IsOutOfBounds || IsBaseRegUsed || IsBaseRegModified) {
+ LiveRegUnits::accumulateUsedDefed(MI, ModifiedRegUnits,
+ UsedRegUnits, TRI);
+ MemInsns.push_back(&MI);
+ continue;
+ }
+ } else {
+ if ((Offset != MIOffset + OffsetStride) &&
+ (Offset + OffsetStride != MIOffset)) {
+ LiveRegUnits::accumulateUsedDefed(MI, ModifiedRegUnits,
+ UsedRegUnits, TRI);
+ MemInsns.push_back(&MI);
+ continue;
+ }
+ }
+
int MinOffset = Offset < MIOffset ? Offset : MIOffset;
if (FindNarrowMerge) {
// If the alignment requirements of the scaled wide load/store
@@ -1985,7 +2092,7 @@ bool AArch64LoadStoreOpt::tryToPairLdStInst(MachineBasicBlock::iterator &MBBI) {
// Early exit if the offset is not possible to match. (6 bits of positive
// range, plus allow an extra one in case we find a later insn that matches
// with Offset-1)
- bool IsUnscaled = TII->isUnscaledLdSt(MI);
+ bool IsUnscaled = TII->hasUnscaledLdStOffset(MI);
int Offset = getLdStOffsetOp(MI).getImm();
int OffsetStride = IsUnscaled ? TII->getMemScale(MI) : 1;
// Allow one more for offset.
@@ -2000,7 +2107,7 @@ bool AArch64LoadStoreOpt::tryToPairLdStInst(MachineBasicBlock::iterator &MBBI) {
findMatchingInsn(MBBI, Flags, LdStLimit, /* FindNarrowMerge = */ false);
if (Paired != E) {
++NumPairCreated;
- if (TII->isUnscaledLdSt(MI))
+ if (TII->hasUnscaledLdStOffset(MI))
++NumUnscaledPairCreated;
// Keeping the iterator straight is a pain, so we let the merge routine tell
// us what the next instruction is after it's done mucking about.
@@ -2035,7 +2142,7 @@ bool AArch64LoadStoreOpt::tryToMergeLdStUpdate
}
// Don't know how to handle unscaled pre/post-index versions below, so bail.
- if (TII->isUnscaledLdSt(MI.getOpcode()))
+ if (TII->hasUnscaledLdStOffset(MI.getOpcode()))
return false;
// Look back to try to find a pre-index instruction. For example,
diff --git a/llvm/test/CodeGen/AArch64/arm64-memset-inline.ll b/llvm/test/CodeGen/AArch64/arm64-memset-inline.ll
index 7a9f3b2fa97f..a0b2e2168731 100644
--- a/llvm/test/CodeGen/AArch64/arm64-memset-inline.ll
+++ b/llvm/test/CodeGen/AArch64/arm64-memset-inline.ll
@@ -65,8 +65,8 @@ define void @bzero_4_stack() {
define void @bzero_8_stack() {
; CHECK-LABEL: bzero_8_stack:
-; CHECK: str xzr, [sp, #8]
-; CHECK-NEXT: bl something
+; CHECK: stp x30, xzr, [sp, #-16]!
+; CHECK: bl something
%buf = alloca [8 x i8], align 1
%cast = bitcast [8 x i8]* %buf to i8*
call void @llvm.memset.p0i8.i32(i8* %cast, i8 0, i32 8, i1 false)
@@ -232,8 +232,8 @@ define void @memset_4_stack() {
define void @memset_8_stack() {
; CHECK-LABEL: memset_8_stack:
; CHECK: mov x8, #-6148914691236517206
-; CHECK-NEXT: add x0, sp, #8
-; CHECK-NEXT: str x8, [sp, #8]
+; CHECK-NEXT: stp x30, x8, [sp, #-16]!
+; CHECK-NEXT: add x0, sp, #8 // =8
; CHECK-NEXT: bl something
%buf = alloca [8 x i8], align 1
%cast = bitcast [8 x i8]* %buf to i8*
diff --git a/llvm/test/CodeGen/AArch64/ldrpre-ldr-merge.mir b/llvm/test/CodeGen/AArch64/ldrpre-ldr-merge.mir
new file mode 100644
index 000000000000..683a92fae457
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/ldrpre-ldr-merge.mir
@@ -0,0 +1,587 @@
+# RUN: llc -o - %s -mtriple=aarch64-none-eabi -mcpu=cortex-a55 -lsr-preferred-addressing-mode=preindexed -stop-after=aarch64-ldst-opt | FileCheck %s
+
+---
+name: 1-ldrwpre-ldrwui-merge
+tracksRegLiveness: true
+liveins:
+ - { reg: '$x1' }
+ - { reg: '$w0' }
+ - { reg: '$w1' }
+machineFunctionInfo:
+ hasRedZone: false
+body: |
+ bb.0:
+ liveins: $w0, $w1, $x1
+ ; CHECK-LABEL: name: 1-ldrwpre-ldrwui-merge
+ ; CHECK: liveins: $w0, $w1, $x1
+ ; CHECK: early-clobber $x1, renamable $w0, renamable $w1 = LDPWpre renamable $x1, 5 :: (load 4)
+ ; CHECK: STPWi renamable $w0, renamable $w1, renamable $x1, 0 :: (store 4)
+ ; CHECK: RET undef $lr
+ early-clobber renamable $x1, renamable $w0 = LDRWpre killed renamable $x1, 20 :: (load 4)
+ renamable $w1 = LDRWui renamable $x1, 1 :: (load 4)
+ STRWui killed renamable $w0, renamable $x1, 0 :: (store 4)
+ STRWui killed renamable $w1, renamable $x1, 1 :: (store 4)
+ RET undef $lr
+...
+
+
+---
+name: 2-ldrxpre-ldrxui-merge
+tracksRegLiveness: true
+liveins:
+ - { reg: '$x1' }
+ - { reg: '$x2' }
+ - { reg: '$x3' }
+machineFunctionInfo:
+ hasRedZone: false
+body: |
+ bb.0:
+ liveins: $x2, $x3, $x1
+ ; CHECK-LABEL: name: 2-ldrxpre-ldrxui-merge
+ ; CHECK: liveins: $x1, $x2, $x3
+ ; CHECK: early-clobber $x1, renamable $x2, renamable $x3 = LDPXpre renamable $x1, 3 :: (load 8)
+ ; CHECK: STPXi renamable $x2, renamable $x3, renamable $x1, 0 :: (store 8)
+ ; CHECK: RET undef $lr
+ early-clobber renamable $x1, renamable $x2 = LDRXpre killed renamable $x1, 24 :: (load 8)
+ renamable $x3 = LDRXui renamable $x1, 1 :: (load 8)
+ STRXui killed renamable $x2, renamable $x1, 0 :: (store 8)
+ STRXui killed renamable $x3, renamable $x1, 1 :: (store 8)
+ RET undef $lr
+...
+
+
+---
+name: 3-ldrspre-ldrsui-merge
+tracksRegLiveness: true
+liveins:
+ - { reg: '$x1' }
+ - { reg: '$s0' }
+ - { reg: '$s1' }
+machineFunctionInfo:
+ hasRedZone: false
+body: |
+ bb.0:
+ liveins: $s0, $s1, $x1
+ ; CHECK-LABEL: name: 3-ldrspre-ldrsui-merge
+ ; CHECK: liveins: $s0, $s1, $x1
+ ; CHECK: early-clobber $x1, renamable $s0, renamable $s1 = LDPSpre renamable $x1, 3 :: (load 4)
+ ; CHECK: STRSui renamable $s0, renamable $x1, 0 :: (store 4)
+ ; CHECK: STRSui renamable $s1, renamable $x1, 1 :: ("aarch64-suppress-pair" store 4)
+ ; CHECK: RET undef $lr
+ early-clobber renamable $x1, renamable $s0 = LDRSpre killed renamable $x1, 12 :: (load 4)
+ renamable $s1 = LDRSui renamable $x1, 1 :: (load 4)
+ STRSui killed renamable $s0, renamable $x1, 0 :: (store 4)
+ STRSui killed renamable $s1, renamable $x1, 1 :: (store 4)
+ RET undef $lr
+...
+
+
+---
+name: 4-ldrqdre-ldrdui-merge
+tracksRegLiveness: true
+liveins:
+ - { reg: '$x1' }
+ - { reg: '$d0' }
+ - { reg: '$d1' }
+machineFunctionInfo:
+ hasRedZone: false
+body: |
+ bb.0:
+ liveins: $d0, $d1, $x1
+ ; CHECK-LABEL: name: 4-ldrqdre-ldrdui-merge
+ ; CHECK: liveins: $d0, $d1, $x1
+ ; CHECK: early-clobber $x1, renamable $d0, renamable $d1 = LDPDpre renamable $x1, 16 :: (load 8)
+ ; CHECK: STRDui renamable $d0, renamable $x1, 0 :: (store 8)
+ ; CHECK: STRDui renamable $d1, renamable $x1, 1 :: ("aarch64-suppress-pair" store 8)
+ ; CHECK: RET undef $lr
+ early-clobber renamable $x1, renamable $d0 = LDRDpre killed renamable $x1, 128 :: (load 8)
+ renamable $d1 = LDRDui renamable $x1, 1 :: (load 8)
+ STRDui killed renamable $d0, renamable $x1, 0 :: (store 8)
+ STRDui killed renamable $d1, renamable $x1, 1 :: (store 8)
+ RET undef $lr
+...
+
+
+---
+name: 5-ldrqpre-ldrqui-merge
+alignment: 4
+tracksRegLiveness: true
+liveins:
+ - { reg: '$x1' }
+ - { reg: '$q0' }
+ - { reg: '$q1' }
+frameInfo:
+ maxAlignment: 1
+ maxCallFrameSize: 0
+machineFunctionInfo:
+ hasRedZone: false
+body: |
+ bb.0:
+ liveins: $q0, $q1, $x1
+ ; CHECK-LABEL: name: 5-ldrqpre-ldrqui-merge
+ ; CHECK: liveins: $q0, $q1, $x1
+ ; CHECK: early-clobber $x1, renamable $q0, renamable $q1 = LDPQpre renamable $x1, 3 :: (load 16)
+ ; CHECK: STPQi renamable $q0, renamable $q1, renamable $x1, 0 :: (store 16)
+ ; CHECK: RET undef $lr
+ early-clobber renamable $x1, renamable $q0 = LDRQpre killed renamable $x1, 48 :: (load 16)
+ renamable $q1 = LDRQui renamable $x1, 1 :: (load 16)
+ STRQui killed renamable $q0, renamable $x1, 0 :: (store 16)
+ STRQui killed renamable $q1, renamable $x1, 1 :: (store 16)
+ RET undef $lr
+...
+
+
+---
+name: 6-ldrqui-ldrqpre-no-merge
+alignment: 4
+tracksRegLiveness: true
+liveins:
+ - { reg: '$x1' }
+ - { reg: '$q0' }
+ - { reg: '$q1' }
+frameInfo:
+ maxAlignment: 1
+ maxCallFrameSize: 0
+machineFunctionInfo:
+ hasRedZone: false
+body: |
+ bb.0:
+ liveins: $q0, $q1, $x1
+ ; CHECK-LABEL: name: 6-ldrqui-ldrqpre-no-merge
+ ; CHECK: liveins: $q0, $q1, $x1
+ ; CHECK: renamable $q1 = LDRQui renamable $x1, 1 :: (load 16)
+ ; CHECK: early-clobber renamable $x1, renamable $q0 = LDRQpre renamable $x1, 48, implicit $w1 :: (load 16)
+ ; CHECK: STPQi renamable $q0, renamable $q1, renamable $x1, 0 :: (store 16)
+ ; CHECK: RET undef $lr
+ renamable $q1 = LDRQui renamable $x1, 1 :: (load 16)
+ early-clobber renamable $x1, renamable $q0 = LDRQpre killed renamable $x1, 48 :: (load 16)
+ STRQui killed renamable $q0, renamable $x1, 0 :: (store 16)
+ STRQui killed renamable $q1, renamable $x1, 1 :: (store 16)
+ RET undef $lr
+...
+
+
+---
+name: 7-ldrqpre-ldrqui-max-offset-merge
+alignment: 4
+tracksRegLiveness: true
+liveins:
+ - { reg: '$x1' }
+ - { reg: '$q0' }
+ - { reg: '$q1' }
+frameInfo:
+ maxAlignment: 1
+ maxCallFrameSize: 0
+machineFunctionInfo:
+ hasRedZone: false
+body: |
+ bb.0:
+ liveins: $q0, $q1, $x1
+ ; CHECK-LABEL: name: 7-ldrqpre-ldrqui-max-offset-merge
+ ; CHECK: liveins: $q0, $q1, $x1
+ ; CHECK: early-clobber $x1, renamable $q0, renamable $q1 = LDPQpre renamable $x1, 15 :: (load 16)
+ ; CHECK: STPQi renamable $q0, renamable $q1, renamable $x1, 0 :: (store 16)
+ ; CHECK: RET undef $lr
+ early-clobber renamable $x1, renamable $q0 = LDRQpre killed renamable $x1, 240 :: (load 16)
+ renamable $q1 = LDRQui renamable $x1, 1 :: (load 16)
+ STRQui killed renamable $q0, renamable $x1, 0 :: (store 16)
+ STRQui killed renamable $q1, renamable $x1, 1 :: (store 16)
+ RET undef $lr
+...
+
+
+---
+name: 8-ldrqpre-ldrqui-min-offset-merge
+alignment: 4
+tracksRegLiveness: true
+liveins:
+ - { reg: '$x1' }
+ - { reg: '$q0' }
+ - { reg: '$q1' }
+frameInfo:
+ maxAlignment: 1
+ maxCallFrameSize: 0
+machineFunctionInfo:
+ hasRedZone: false
+body: |
+ bb.0:
+ liveins: $q0, $q1, $x1
+ ; CHECK-LABEL: name: 8-ldrqpre-ldrqui-min-offset-merge
+ ; CHECK: liveins: $q0, $q1, $x1
+ ; CHECK: early-clobber $x1, renamable $q0, renamable $q1 = LDPQpre renamable $x1, -16 :: (load 16)
+ ; CHECK: STPQi renamable $q0, renamable $q1, renamable $x1, 0 :: (store 16)
+ ; CHECK: RET undef $lr
+ early-clobber renamable $x1, renamable $q0 = LDRQpre killed renamable $x1, -256 :: (load 16)
+ renamable $q1 = LDRQui renamable $x1, 1 :: (load 16)
+ STRQui killed renamable $q0, renamable $x1, 0 :: (store 16)
+ STRQui killed renamable $q1, renamable $x1, 1 :: (store 16)
+ RET undef $lr
+...
+
+
+---
+name: 9-ldrspre-ldrsui-mod-base-reg-no-merge
+alignment: 4
+tracksRegLiveness: true
+liveins:
+ - { reg: '$x0' }
+ - { reg: '$x1' }
+ - { reg: '$s0' }
+ - { reg: '$s1' }
+frameInfo:
+ maxAlignment: 1
+ maxCallFrameSize: 0
+machineFunctionInfo:
+ hasRedZone: false
+body: |
+ bb.0:
+ liveins: $s0, $s1, $x0, $x1
+ ; CHECK-LABEL: name: 9-ldrspre-ldrsui-mod-base-reg-no-merge
+ ; CHECK: liveins: $s0, $s1, $x0, $x1
+ ; CHECK: dead early-clobber renamable $x1, renamable $s0 = LDRSpre renamable $x1, 12, implicit $w1 :: (load 4)
+ ; CHECK: renamable $x1 = LDRXui renamable $x0, 1 :: (load 8)
+ ; CHECK: renamable $s1 = LDRSui renamable $x1, 1 :: (load 4)
+ ; CHECK: STPSi renamable $s0, renamable $s1, renamable $x1, 0 :: (store 4)
+ ; CHECK: RET undef $lr
+ early-clobber renamable $x1, renamable $s0 = LDRSpre killed renamable $x1, 12 :: (load 4)
+ renamable $x1 = LDRXui renamable $x0, 1 :: (load 8)
+ renamable $s1 = LDRSui renamable $x1, 1 :: (load 4)
+ STRSui killed renamable $s0, renamable $x1, 0 :: (store 4)
+ STRSui killed renamable $s1, renamable $x1, 1 :: (store 4)
+ RET undef $lr
+...
+
+
+---
+name: 10-ldrspre-ldrsui-used-base-reg-no-merge
+alignment: 4
+tracksRegLiveness: true
+liveins:
+ - { reg: '$x0' }
+ - { reg: '$x1' }
+ - { reg: '$s0' }
+ - { reg: '$s1' }
+frameInfo:
+ maxAlignment: 1
+ maxCallFrameSize: 0
+machineFunctionInfo:
+ hasRedZone: false
+body: |
+ bb.0:
+ liveins: $s0, $s1, $x0, $x1
+ ; CHECK-LABEL: name: 10-ldrspre-ldrsui-used-base-reg-no-merge
+ ; CHECK: liveins: $s0, $s1, $x0, $x1
+ ; CHECK: early-clobber renamable $x1, renamable $s0 = LDRSpre renamable $x1, 12, implicit $w1 :: (load 4)
+ ; CHECK: renamable $x0 = LDRXui renamable $x1, 1 :: (load 8)
+ ; CHECK: STRXui renamable $x0, renamable $x0, 1 :: (store 8)
+ ; CHECK: renamable $s1 = LDRSui renamable $x1, 1 :: (load 4)
+ ; CHECK: STRSui renamable $s0, renamable $x1, 0 :: (store 4)
+ ; CHECK: STRSui renamable $s1, renamable $x1, 1 :: ("aarch64-suppress-pair" store 4)
+ ; CHECK: RET undef $lr
+ early-clobber renamable $x1, renamable $s0 = LDRSpre killed renamable $x1, 12 :: (load 4)
+ renamable $x0 = LDRXui renamable $x1, 1 :: (load 8)
+ STRXui killed renamable $x0, renamable $x0, 1 :: (store 8)
+ renamable $s1 = LDRSui renamable $x1, 1 :: (load 4)
+ STRSui killed renamable $s0, renamable $x1, 0 :: (store 4)
+ STRSui killed renamable $s1, renamable $x1, 1 :: (store 4)
+ RET undef $lr
+...
+
+
+---
+name: 11-ldrqpre-ldrqpre-no-merge
+alignment: 4
+tracksRegLiveness: true
+liveins:
+ - { reg: '$x1' }
+ - { reg: '$q0' }
+ - { reg: '$q1' }
+frameInfo:
+ maxAlignment: 1
+ maxCallFrameSize: 0
+machineFunctionInfo:
+ hasRedZone: false
+body: |
+ bb.0:
+ liveins: $q0, $q1, $x1
+ ; CHECK-LABEL: name: 11-ldrqpre-ldrqpre-no-merge
+ ; CHECK: liveins: $q0, $q1, $x1
+ ; CHECK: early-clobber renamable $x1, dead renamable $q0 = LDRQpre renamable $x1, 48, implicit $w1 :: (load 16)
+ ; CHECK: early-clobber renamable $x1, dead renamable $q1 = LDRQpre renamable $x1, 1, implicit $w1 :: (load 16)
+ ; CHECK: early-clobber renamable $x1, dead renamable $q0 = LDRQpre renamable $x1, 16, implicit $w1 :: (load 16)
+ ; CHECK: early-clobber renamable $x1, dead renamable $q1 = LDRQpre renamable $x1, 12, implicit $w1 :: (load 16)
+ ; CHECK: early-clobber renamable $x1, renamable $q0 = LDRQpre renamable $x1, 16, implicit $w1 :: (load 16)
+ ; CHECK: early-clobber renamable $x1, renamable $q1 = LDRQpre renamable $x1, 16, implicit $w1 :: (load 16)
+ ; CHECK: STPQi renamable $q0, renamable $q1, renamable $x1, 0 :: (store 16)
+ ; CHECK: RET undef $lr
+ early-clobber renamable $x1, renamable $q0 = LDRQpre killed renamable $x1, 48 :: (load 16)
+ early-clobber renamable $x1, renamable $q1 = LDRQpre killed renamable $x1, 1 :: (load 16)
+ early-clobber renamable $x1, renamable $q0 = LDRQpre killed renamable $x1, 16 :: (load 16)
+ early-clobber renamable $x1, renamable $q1 = LDRQpre killed renamable $x1, 12 :: (load 16)
+ early-clobber renamable $x1, renamable $q0 = LDRQpre killed renamable $x1, 16 :: (load 16)
+ early-clobber renamable $x1, renamable $q1 = LDRQpre killed renamable $x1, 16 :: (load 16)
+ STRQui killed renamable $q0, renamable $x1, 0 :: (store 16)
+ STRQui killed renamable $q1, renamable $x1, 1 :: (store 16)
+ RET undef $lr
+...
+
+
+---
+name: 12-ldrspre-ldrsui-no-merge
+tracksRegLiveness: true
+liveins:
+ - { reg: '$x1' }
+ - { reg: '$s0' }
+ - { reg: '$s1' }
+machineFunctionInfo:
+ hasRedZone: false
+body: |
+ bb.0:
+ liveins: $s0, $s1, $x1
+
+ ; The offset of the second load is not equal to the
+ ; size of the destination register, and hence can’t be merged.
+
+ ; CHECK-LABEL: name: 12-ldrspre-ldrsui-no-merge
+ ; CHECK: liveins: $s0, $s1, $x1
+ ; CHECK: early-clobber renamable $x1, renamable $s0 = LDRSpre renamable $x1, 12, implicit $w1 :: (load 4)
+ ; CHECK: renamable $s1 = LDRSui renamable $x1, 2 :: (load 4)
+ ; CHECK: STRSui renamable $s0, renamable $x1, 0 :: (store 4)
+ ; CHECK: STRSui renamable $s1, renamable $x1, 1 :: ("aarch64-suppress-pair" store 4)
+ ; CHECK: RET undef $lr
+ early-clobber renamable $x1, renamable $s0 = LDRSpre killed renamable $x1, 12 :: (load 4)
+ renamable $s1 = LDRSui renamable $x1, 2 :: (load 4)
+ STRSui killed renamable $s0, renamable $x1, 0 :: (store 4)
+ STRSui killed renamable $s1, renamable $x1, 1 :: (store 4)
+ RET undef $lr
+...
+
+
+---
+name: 13-ldrqpre-ldrdui-no-merge
+alignment: 4
+tracksRegLiveness: true
+liveins:
+ - { reg: '$x1' }
+ - { reg: '$q0' }
+ - { reg: '$d1' }
+frameInfo:
+ maxAlignment: 1
+ maxCallFrameSize: 0
+machineFunctionInfo:
+ hasRedZone: false
+body: |
+ bb.0:
+ liveins: $q0, $d1, $x1
+ ; CHECK-LABEL: name: 13-ldrqpre-ldrdui-no-merge
+ ; CHECK: liveins: $d1, $q0, $x1
+ ; CHECK: early-clobber renamable $x1, renamable $q0 = LDRQpre renamable $x1, 32, implicit $w1 :: (load 16)
+ ; CHECK: renamable $d1 = LDRDui renamable $x1, 1 :: (load 8)
+ ; CHECK: STRQui renamable $q0, renamable $x1, 0 :: (store 16)
+ ; CHECK: STRDui renamable $d1, renamable $x1, 1 :: (store 8)
+ ; CHECK: RET undef $lr
+ early-clobber renamable $x1, renamable $q0 = LDRQpre killed renamable $x1, 32 :: (load 16)
+ renamable $d1 = LDRDui renamable $x1, 1 :: (load 8)
+ STRQui killed renamable $q0, renamable $x1, 0 :: (store 16)
+ STRDui killed renamable $d1, renamable $x1, 1 :: (store 8)
+ RET undef $lr
+...
+
+
+---
+name: 14-ldrqpre-strqui-no-merge
+alignment: 4
+tracksRegLiveness: true
+liveins:
+ - { reg: '$x1' }
+ - { reg: '$q0' }
+ - { reg: '$q1' }
+frameInfo:
+ maxAlignment: 1
+ maxCallFrameSize: 0
+machineFunctionInfo:
+ hasRedZone: false
+body: |
+ bb.0:
+ liveins: $q0, $q1, $x1
+ ; CHECK-LABEL: name: 14-ldrqpre-strqui-no-merge
+ ; CHECK: liveins: $q0, $q1, $x1
+ ; CHECK: early-clobber renamable $x1, renamable $q0 = LDRQpre renamable $x1, 32, implicit $w1 :: (load 16)
+ ; CHECK: STRQui renamable $q0, renamable $x1, 0 :: (store 16)
+ ; CHECK: RET undef $lr
+ early-clobber renamable $x1, renamable $q0 = LDRQpre killed renamable $x1, 32 :: (load 16)
+ STRQui killed renamable $q0, renamable $x1, 0 :: (store 16)
+ RET undef $lr
+...
+
+
+---
+name: 15-ldrqpre-ldrqui-same-dst-reg-no-merge
+alignment: 4
+tracksRegLiveness: true
+liveins:
+ - { reg: '$x1' }
+ - { reg: '$q0' }
+ - { reg: '$q1' }
+frameInfo:
+ maxAlignment: 1
+ maxCallFrameSize: 0
+machineFunctionInfo:
+ hasRedZone: false
+body: |
+ bb.0:
+ liveins: $q0, $x1
+ ; CHECK-LABEL: name: 15-ldrqpre-ldrqui-same-dst-reg-no-merge
+ ; CHECK: liveins: $q0, $q1, $x1
+ ; CHECK: early-clobber renamable $x1, dead renamable $q0 = LDRQpre renamable $x1, 32, implicit $w1 :: (load 16)
+ ; CHECK: renamable $q0 = LDRQui renamable $x1, 1 :: (load 16)
+ ; CHECK: STRQui renamable $q0, renamable $x1, 0 :: (store 16)
+ ; CHECK: RET undef $lr
+ early-clobber renamable $x1, renamable $q0 = LDRQpre killed renamable $x1, 32 :: (load 16)
+ renamable $q0 = LDRQui renamable $x1, 1 :: (load 16)
+ STRQui killed renamable $q0, renamable $x1, 0 :: (store 16)
+ RET undef $lr
+...
+
+
+---
+name: 16-ldrqpre-ldrqui-
diff -base-reg-no-merge
+alignment: 4
+tracksRegLiveness: true
+liveins:
+ - { reg: '$x1' }
+ - { reg: '$x2' }
+ - { reg: '$q0' }
+ - { reg: '$q1' }
+frameInfo:
+ maxAlignment: 1
+ maxCallFrameSize: 0
+machineFunctionInfo:
+ hasRedZone: false
+body: |
+ bb.0:
+ liveins: $q0, $q1, $x1, $x2
+ ; CHECK-LABEL: name: 16-ldrqpre-ldrqui-
diff -base-reg-no-merge
+ ; CHECK: liveins: $q0, $q1, $x1, $x2
+ ; CHECK: early-clobber renamable $x1, renamable $q0 = LDRQpre renamable $x1, 32, implicit $w1 :: (load 16)
+ ; CHECK: renamable $q1 = LDRQui renamable $x2, 1 :: (load 16)
+ ; CHECK: STPQi renamable $q0, renamable $q1, renamable $x1, 0 :: (store 16)
+ ; CHECK: RET undef $lr
+ early-clobber renamable $x1, renamable $q0 = LDRQpre killed renamable $x1, 32 :: (load 16)
+ renamable $q1 = LDRQui renamable $x2, 1 :: (load 16)
+ STRQui killed renamable $q0, renamable $x1, 0 :: (store 16)
+ STRQui killed renamable $q1, renamable $x1, 1 :: (store 16)
+ RET undef $lr
+...
+
+
+---
+name: 17-ldrqpre-ldurqi-merge
+alignment: 4
+tracksRegLiveness: true
+liveins:
+ - { reg: '$x1' }
+ - { reg: '$q0' }
+ - { reg: '$q1' }
+frameInfo:
+ maxAlignment: 1
+ maxCallFrameSize: 0
+machineFunctionInfo:
+ hasRedZone: false
+body: |
+ bb.0:
+ liveins: $q0, $q1, $x1
+ ; CHECK-LABEL: name: 17-ldrqpre-ldurqi-merge
+ ; CHECK: liveins: $q0, $q1, $x1
+ ; CHECK: early-clobber $x1, renamable $q0, renamable $q1 = LDPQpre renamable $x1, 2 :: (load 16)
+ ; CHECK: STPQi renamable $q0, renamable $q1, renamable $x1, 0 :: (store 16)
+ ; CHECK: RET undef $lr
+ early-clobber renamable $x1, renamable $q0 = LDRQpre killed renamable $x1, 32 :: (load 16)
+ renamable $q1 = LDURQi renamable $x1, 16 :: (load 16)
+ STRQui killed renamable $q0, renamable $x1, 0 :: (store 16)
+ STRQui killed renamable $q1, renamable $x1, 1 :: (store 16)
+ RET undef $lr
+...
+
+
+---
+name: 18-ldrqpre-ldurqi-no-merge
+alignment: 4
+tracksRegLiveness: true
+liveins:
+ - { reg: '$x1' }
+ - { reg: '$q0' }
+ - { reg: '$q1' }
+frameInfo:
+ maxAlignment: 1
+ maxCallFrameSize: 0
+machineFunctionInfo:
+ hasRedZone: false
+body: |
+ bb.0:
+ liveins: $q0, $q1, $x1
+ ; CHECK-LABEL: name: 18-ldrqpre-ldurqi-no-merge
+ ; CHECK: liveins: $q0, $q1, $x1
+ ; CHECK: early-clobber renamable $x1, renamable $q0 = LDRQpre renamable $x1, 32, implicit $w1 :: (load 16)
+ ; CHECK: renamable $q1 = LDURQi renamable $x1, 1 :: (load 16)
+ ; CHECK: STPQi renamable $q0, renamable $q1, renamable $x1, 0 :: (store 16)
+ ; CHECK: RET undef $lr
+ early-clobber renamable $x1, renamable $q0 = LDRQpre killed renamable $x1, 32 :: (load 16)
+ renamable $q1 = LDURQi renamable $x1, 1 :: (load 16)
+ STRQui killed renamable $q0, renamable $x1, 0 :: (store 16)
+ STRQui killed renamable $q1, renamable $x1, 1 :: (store 16)
+ RET undef $lr
+...
+
+
+---
+name: 19-ldrspre-ldrsui-max-merge
+tracksRegLiveness: true
+liveins:
+ - { reg: '$x1' }
+ - { reg: '$s0' }
+ - { reg: '$s1' }
+machineFunctionInfo:
+ hasRedZone: false
+body: |
+ bb.0:
+ liveins: $s0, $s1, $x1
+ ; CHECK-LABEL: name: 19-ldrspre-ldrsui-max-merge
+ ; CHECK: liveins: $s0, $s1, $x1
+ ; CHECK: early-clobber $x1, renamable $s0, renamable $s1 = LDPSpre renamable $x1, 63 :: (load 4)
+ ; CHECK: STRSui renamable $s0, renamable $x1, 0 :: (store 4)
+ ; CHECK: STRSui renamable $s1, renamable $x1, 1 :: ("aarch64-suppress-pair" store 4)
+ ; CHECK: RET undef $lr
+ early-clobber renamable $x1, renamable $s0 = LDRSpre killed renamable $x1, 252 :: (load 4)
+ renamable $s1 = LDRSui renamable $x1, 1 :: (load 4)
+ STRSui killed renamable $s0, renamable $x1, 0 :: (store 4)
+ STRSui killed renamable $s1, renamable $x1, 1 :: (store 4)
+ RET undef $lr
+...
+
+
+---
+name: 20-ldrspre-ldrsui-unaligned-no-merge
+tracksRegLiveness: true
+liveins:
+ - { reg: '$x1' }
+ - { reg: '$s0' }
+ - { reg: '$s1' }
+machineFunctionInfo:
+ hasRedZone: false
+body: |
+ bb.0:
+ liveins: $s0, $s1, $x1
+ ; CHECK-LABEL: name: 20-ldrspre-ldrsui-unaligned-no-merge
+ ; CHECK: liveins: $s0, $s1, $x1
+ ; CHECK: early-clobber renamable $x1, renamable $s0 = LDRSpre renamable $x1, 251, implicit $w1 :: (load 4)
+ ; CHECK: renamable $s1 = LDRSui renamable $x1, 1 :: (load 4)
+ ; CHECK: STRSui renamable $s0, renamable $x1, 0 :: (store 4)
+ ; CHECK: STRSui renamable $s1, renamable $x1, 1 :: ("aarch64-suppress-pair" store 4)
+ ; CHECK: RET undef $lr
+ early-clobber renamable $x1, renamable $s0 = LDRSpre killed renamable $x1, 251 :: (load 4)
+ renamable $s1 = LDRSui renamable $x1, 1 :: (load 4)
+ STRSui killed renamable $s0, renamable $x1, 0 :: (store 4)
+ STRSui killed renamable $s1, renamable $x1, 1 :: (store 4)
+ RET undef $lr
+...
diff --git a/llvm/test/CodeGen/AArch64/strpre-str-merge.mir b/llvm/test/CodeGen/AArch64/strpre-str-merge.mir
new file mode 100644
index 000000000000..ff08acc1225d
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/strpre-str-merge.mir
@@ -0,0 +1,426 @@
+# RUN: llc -o - %s -mtriple=aarch64-none-eabi -mcpu=cortex-a55 -lsr-preferred-addressing-mode=preindexed -stop-after=aarch64-ldst-opt | FileCheck %s
+
+---
+name: 1-strwpre-strwui-merge
+alignment: 4
+tracksRegLiveness: true
+liveins:
+ - { reg: '$x0' }
+ - { reg: '$w1' }
+ - { reg: '$w2' }
+frameInfo:
+ maxAlignment: 1
+ maxCallFrameSize: 0
+machineFunctionInfo:
+ hasRedZone: false
+body: |
+ bb.0.entry:
+ liveins: $w1, $w2, $x0
+ ; CHECK-LABEL: name: 1-strwpre-strwui-merge
+ ; CHECK: liveins: $w1, $w2, $x0
+ ; CHECK: early-clobber $x0 = STPWpre renamable $w1, renamable $w2, renamable $x0, 5 :: (store 4)
+ ; CHECK: RET undef $lr, implicit $x0
+ early-clobber renamable $x0 = STRWpre killed renamable $w1, killed renamable $x0, 20 :: (store 4)
+ STRWui killed renamable $w2, renamable $x0, 1 :: (store 4)
+ RET undef $lr, implicit $x0
+
+...
+
+
+---
+name: 2-strxpre-strxui-merge
+alignment: 4
+tracksRegLiveness: true
+liveins:
+ - { reg: '$x0' }
+ - { reg: '$x1' }
+ - { reg: '$x2' }
+frameInfo:
+ maxAlignment: 1
+ maxCallFrameSize: 0
+machineFunctionInfo:
+ hasRedZone: false
+body: |
+ bb.0.entry:
+ liveins: $x0, $x1, $x2
+
+ ; CHECK-LABEL: name: 2-strxpre-strxui-merge
+ ; CHECK: liveins: $x0, $x1, $x2
+ ; CHECK: early-clobber $x0 = STPXpre renamable $x1, renamable $x2, renamable $x0, 3 :: (store 8)
+ ; CHECK: RET undef $lr, implicit $x0
+ early-clobber renamable $x0 = STRXpre killed renamable $x1, killed renamable $x0, 24 :: (store 8)
+ STRXui killed renamable $x2, renamable $x0, 1 :: (store 8)
+ RET undef $lr, implicit $x0
+
+...
+
+
+---
+name: 3-strspre-strsui-merge
+alignment: 4
+tracksRegLiveness: true
+liveins:
+ - { reg: '$x0' }
+ - { reg: '$s0' }
+ - { reg: '$s1' }
+frameInfo:
+ maxAlignment: 1
+ maxCallFrameSize: 0
+machineFunctionInfo:
+ hasRedZone: false
+body: |
+ bb.0.entry:
+ liveins: $s0, $s1, $x0
+ ; CHECK-LABEL: name: 3-strspre-strsui-merge
+ ; CHECK: liveins: $s0, $s1, $x0
+ ; CHECK: early-clobber $x0 = STPSpre renamable $s0, renamable $s1, renamable $x0, 3 :: (store 4)
+ ; CHECK: RET undef $lr, implicit $x0
+ early-clobber renamable $x0 = STRSpre killed renamable $s0, killed renamable $x0, 12 :: (store 4)
+ STRSui killed renamable $s1, renamable $x0, 1 :: (store 4)
+ RET undef $lr, implicit $x0
+...
+
+
+---
+name: 4-strdpre-strdui-merge
+alignment: 4
+tracksRegLiveness: true
+liveins:
+ - { reg: '$x0' }
+ - { reg: '$d0' }
+ - { reg: '$d1' }
+frameInfo:
+ maxAlignment: 1
+ maxCallFrameSize: 0
+machineFunctionInfo:
+ hasRedZone: false
+body: |
+ bb.0.entry:
+ liveins: $d0, $d1, $x0
+
+ ; CHECK-LABEL: name: 4-strdpre-strdui-merge
+ ; CHECK: liveins: $d0, $d1, $x0
+ ; CHECK: early-clobber $x0 = STPDpre renamable $d0, renamable $d1, renamable $x0, 16 :: (store 8)
+ ; CHECK: RET undef $lr, implicit $x0
+ early-clobber renamable $x0 = STRDpre killed renamable $d0, killed renamable $x0, 128 :: (store 8)
+ STRDui killed renamable $d1, renamable $x0, 1 :: (store 8)
+ RET undef $lr, implicit $x0
+
+...
+
+
+---
+name: 5-strqpre-strqui-merge
+alignment: 4
+tracksRegLiveness: true
+liveins:
+ - { reg: '$x0' }
+ - { reg: '$q0' }
+ - { reg: '$q1' }
+frameInfo:
+ maxAlignment: 1
+ maxCallFrameSize: 0
+machineFunctionInfo:
+ hasRedZone: false
+body: |
+ bb.0.entry:
+ liveins: $q0, $q1, $x0
+
+ ; CHECK-LABEL: name: 5-strqpre-strqui-merge
+ ; CHECK: liveins: $q0, $q1, $x0
+ ; CHECK: early-clobber $x0 = STPQpre renamable $q0, renamable $q1, renamable $x0, 3 :: (store 16)
+ ; CHECK: RET undef $lr, implicit $x0
+ early-clobber renamable $x0 = STRQpre killed renamable $q0, killed renamable $x0, 48 :: (store 16)
+ STRQui killed renamable $q1, renamable $x0, 1 :: (store 16)
+ RET undef $lr, implicit $x0
+
+...
+
+
+---
+name: 6-strqui-strqpre-no-merge
+alignment: 4
+tracksRegLiveness: true
+liveins:
+ - { reg: '$x0' }
+ - { reg: '$q0' }
+ - { reg: '$q1' }
+frameInfo:
+ maxAlignment: 1
+ maxCallFrameSize: 0
+machineFunctionInfo:
+ hasRedZone: false
+body: |
+ bb.0.entry:
+ liveins: $q0, $q1, $x0
+ ; CHECK-LABEL: name: 6-strqui-strqpre-no-merge
+ ; CHECK: liveins: $q0, $q1, $x0
+ ; CHECK: STRQui renamable $q1, renamable $x0, 1 :: (store 16)
+ ; CHECK: early-clobber renamable $x0 = STRQpre renamable $q0, renamable $x0, 48, implicit $w0 :: (store 16)
+ ; CHECK: RET undef $lr, implicit $x0
+ STRQui killed renamable $q1, renamable $x0, 1 :: (store 16)
+ early-clobber renamable $x0 = STRQpre killed renamable $q0, killed renamable $x0, 48 :: (store 16)
+ RET undef $lr, implicit $x0
+...
+
+
+---
+name: 7-strspre-strsui-max-offset-merge
+alignment: 4
+tracksRegLiveness: true
+liveins:
+ - { reg: '$x0' }
+ - { reg: '$s0' }
+ - { reg: '$s1' }
+frameInfo:
+ maxAlignment: 1
+ maxCallFrameSize: 0
+machineFunctionInfo:
+ hasRedZone: false
+body: |
+ bb.0.entry:
+ liveins: $s0, $s1, $x0
+ ; CHECK-LABEL: name: 7-strspre-strsui-max-offset-merge
+ ; CHECK: liveins: $s0, $s1, $x0
+ ; CHECK: early-clobber $x0 = STPSpre renamable $s0, renamable $s1, renamable $x0, 63 :: (store 4)
+ ; CHECK: RET undef $lr, implicit $x0
+ early-clobber renamable $x0 = STRSpre killed renamable $s0, killed renamable $x0, 252 :: (store 4)
+ STRSui killed renamable $s1, renamable $x0, 1 :: (store 4)
+ RET undef $lr, implicit $x0
+...
+
+
+---
+name: 8-strspre-strsui-min-offset-merge
+alignment: 4
+tracksRegLiveness: true
+liveins:
+ - { reg: '$x0' }
+ - { reg: '$s0' }
+ - { reg: '$s1' }
+frameInfo:
+ maxAlignment: 1
+ maxCallFrameSize: 0
+machineFunctionInfo:
+ hasRedZone: false
+body: |
+ bb.0.entry:
+ liveins: $s0, $s1, $x0
+ ; CHECK-LABEL: name: 8-strspre-strsui-min-offset-merge
+ ; CHECK: liveins: $s0, $s1, $x0
+ ; CHECK: early-clobber $x0 = STPSpre renamable $s0, renamable $s1, renamable $x0, -64 :: (store 4)
+ ; CHECK: RET undef $lr, implicit $x0
+ early-clobber renamable $x0 = STRSpre killed renamable $s0, killed renamable $x0, -256 :: (store 4)
+ STRSui killed renamable $s1, renamable $x0, 1 :: (store 4)
+ RET undef $lr, implicit $x0
+...
+
+
+---
+name: 9-strspre-strsui-mod-base-reg-no-merge
+alignment: 4
+tracksRegLiveness: true
+liveins:
+ - { reg: '$x0' }
+ - { reg: '$x1' }
+ - { reg: '$s0' }
+ - { reg: '$s1' }
+frameInfo:
+ maxAlignment: 1
+ maxCallFrameSize: 0
+machineFunctionInfo:
+ hasRedZone: false
+body: |
+ bb.0.entry:
+ liveins: $s0, $s1, $x0, $x1
+ ; CHECK-LABEL: name: 9-strspre-strsui-mod-base-reg-no-merge
+ ; CHECK: liveins: $s0, $s1, $x0, $x1
+ ; CHECK: dead early-clobber renamable $x0 = STRSpre renamable $s0, renamable $x0, 12, implicit $w0 :: (store 4)
+ ; CHECK: renamable $x0 = LDRXui renamable $x1, 1 :: (load 8)
+ ; CHECK: STRSui renamable $s1, renamable $x0, 1 :: (store 4)
+ ; CHECK: RET undef $lr, implicit $x0
+ early-clobber renamable $x0 = STRSpre killed renamable $s0, killed renamable $x0, 12 :: (store 4)
+ renamable $x0 = LDRXui renamable $x1, 1 :: (load 8)
+ STRSui killed renamable $s1, renamable $x0, 1 :: (store 4)
+ RET undef $lr, implicit $x0
+...
+
+
+---
+name: 10-strspre-strsui-used-base-reg-no-merge
+alignment: 4
+tracksRegLiveness: true
+liveins:
+ - { reg: '$x0' }
+ - { reg: '$x1' }
+ - { reg: '$s0' }
+ - { reg: '$s1' }
+frameInfo:
+ maxAlignment: 1
+ maxCallFrameSize: 0
+machineFunctionInfo:
+ hasRedZone: false
+body: |
+ bb.0.entry:
+ liveins: $s0, $s1, $x0, $x1
+ ; CHECK-LABEL: name: 10-strspre-strsui-used-base-reg-no-merge
+ ; CHECK: liveins: $s0, $s1, $x0, $x1
+ ; CHECK: early-clobber renamable $x0 = STRSpre renamable $s0, renamable $x0, 12, implicit $w0 :: (store 4)
+ ; CHECK: STRXui renamable $x1, renamable $x1, 1 :: (store 4)
+ ; CHECK: STRSui renamable $s1, renamable $x0, 1 :: (store 4)
+ ; CHECK: RET undef $lr, implicit $x0
+ early-clobber renamable $x0 = STRSpre killed renamable $s0, killed renamable $x0, 12 :: (store 4)
+
+ STRXui killed renamable $x1, renamable $x1, 1 :: (store 4)
+
+ STRSui killed renamable $s1, renamable $x0, 1 :: (store 4)
+ RET undef $lr, implicit $x0
+...
+
+
+---
+name: 11-strspre-strspre-no-merge
+alignment: 4
+tracksRegLiveness: true
+liveins:
+ - { reg: '$x0' }
+ - { reg: '$s0' }
+ - { reg: '$s1' }
+frameInfo:
+ maxAlignment: 1
+ maxCallFrameSize: 0
+machineFunctionInfo:
+ hasRedZone: false
+body: |
+ bb.0.entry:
+ liveins: $s0, $s1, $x0
+ ; CHECK-LABEL: name: 11-strspre-strspre-no-merge
+ ; CHECK: liveins: $s0, $s1, $x0
+ ; CHECK: early-clobber renamable $x0 = STRSpre renamable $s0, renamable $x0, 12, implicit $w0 :: (store 4)
+ ; CHECK: early-clobber renamable $x0 = STRSpre renamable $s1, renamable $x0, 16, implicit $w0 :: (store 4)
+ ; CHECK: early-clobber renamable $x0 = STRSpre renamable $s0, renamable $x0, 4, implicit $w0 :: (store 4)
+ ; CHECK: early-clobber renamable $x0 = STRSpre renamable $s1, renamable $x0, 12, implicit $w0 :: (store 4)
+ ; CHECK: early-clobber renamable $x0 = STRSpre renamable $s0, renamable $x0, 4, implicit $w0 :: (store 4)
+ ; CHECK: early-clobber renamable $x0 = STRSpre renamable $s1, renamable $x0, 4, implicit $w0 :: (store 4)
+ ; CHECK: RET undef $lr, implicit $x0
+ early-clobber renamable $x0 = STRSpre renamable $s0, killed renamable $x0, 12 :: (store 4)
+ early-clobber renamable $x0 = STRSpre renamable $s1, killed renamable $x0, 16 :: (store 4)
+ early-clobber renamable $x0 = STRSpre renamable $s0, killed renamable $x0, 4 :: (store 4)
+ early-clobber renamable $x0 = STRSpre renamable $s1, killed renamable $x0, 12 :: (store 4)
+ early-clobber renamable $x0 = STRSpre renamable $s0, killed renamable $x0, 4 :: (store 4)
+ early-clobber renamable $x0 = STRSpre renamable $s1, killed renamable $x0, 4 :: (store 4)
+ RET undef $lr, implicit $x0
+...
+
+
+---
+name: 12-strspre-strsui-no-merge
+alignment: 4
+tracksRegLiveness: true
+liveins:
+ - { reg: '$x0' }
+ - { reg: '$s0' }
+ - { reg: '$s1' }
+frameInfo:
+ maxAlignment: 1
+ maxCallFrameSize: 0
+machineFunctionInfo:
+ hasRedZone: false
+body: |
+ bb.0.entry:
+
+ ; The offset of the second st is not equal to the
+ ; size of the destination register, and hence can’t be merged.
+
+ liveins: $s0, $s1, $x0
+ ; CHECK-LABEL: name: 12-strspre-strsui-no-merge
+ ; CHECK: liveins: $s0, $s1, $x0
+ ; CHECK: early-clobber renamable $x0 = STRSpre renamable $s0, renamable $x0, 12, implicit $w0 :: (store 4)
+ ; CHECK: STRSui renamable $s1, renamable $x0, 2 :: (store 4)
+ ; CHECK: RET undef $lr, implicit $x0
+ early-clobber renamable $x0 = STRSpre killed renamable $s0, killed renamable $x0, 12 :: (store 4)
+ STRSui killed renamable $s1, renamable $x0, 2 :: (store 4)
+ RET undef $lr, implicit $x0
+...
+
+
+---
+name: 13-strqpre-sturqi-merge
+alignment: 4
+tracksRegLiveness: true
+liveins:
+ - { reg: '$x0' }
+ - { reg: '$q0' }
+ - { reg: '$q1' }
+frameInfo:
+ maxAlignment: 1
+ maxCallFrameSize: 0
+machineFunctionInfo:
+ hasRedZone: false
+body: |
+ bb.0.entry:
+ liveins: $q0, $q1, $x0
+
+ ; CHECK-LABEL: name: 13-strqpre-sturqi-merge
+ ; CHECK: liveins: $q0, $q1, $x0
+ ; CHECK: early-clobber $x0 = STPQpre renamable $q0, renamable $q1, renamable $x0, 3 :: (store 16)
+ ; CHECK: RET undef $lr, implicit $x0
+ early-clobber renamable $x0 = STRQpre killed renamable $q0, killed renamable $x0, 48 :: (store 16)
+ STURQi killed renamable $q1, renamable $x0, 16 :: (store 16)
+ RET undef $lr, implicit $x0
+
+...
+
+
+---
+name: 14-strqpre-sturqi-no-merge
+alignment: 4
+tracksRegLiveness: true
+liveins:
+ - { reg: '$x0' }
+ - { reg: '$q0' }
+ - { reg: '$q1' }
+frameInfo:
+ maxAlignment: 1
+ maxCallFrameSize: 0
+machineFunctionInfo:
+ hasRedZone: false
+body: |
+ bb.0.entry:
+ liveins: $q0, $q1, $x0
+ ; CHECK-LABEL: name: 14-strqpre-sturqi-no-merge
+ ; CHECK: liveins: $q0, $q1, $x0
+ ; CHECK: early-clobber renamable $x0 = STRQpre renamable $q0, renamable $x0, 48, implicit $w0 :: (store 16)
+ ; CHECK: STURQi renamable $q1, renamable $x0, 1 :: (store 16)
+ ; CHECK: RET undef $lr, implicit $x0
+ early-clobber renamable $x0 = STRQpre killed renamable $q0, killed renamable $x0, 48 :: (store 16)
+ STURQi killed renamable $q1, renamable $x0, 1 :: (store 16)
+ RET undef $lr, implicit $x0
+...
+
+
+---
+name: 15-strspre-strsui-unaligned-no-merge
+alignment: 4
+tracksRegLiveness: true
+liveins:
+ - { reg: '$x0' }
+ - { reg: '$s0' }
+ - { reg: '$s1' }
+frameInfo:
+ maxAlignment: 1
+ maxCallFrameSize: 0
+machineFunctionInfo:
+ hasRedZone: false
+body: |
+ bb.0.entry:
+ liveins: $s0, $s1, $x0
+ ; CHECK-LABEL: name: 15-strspre-strsui-unaligned-no-merge
+ ; CHECK: liveins: $s0, $s1, $x0
+ ; CHECK: early-clobber renamable $x0 = STRSpre renamable $s0, renamable $x0, 251, implicit $w0 :: (store 4)
+ ; CHECK: STRSui renamable $s1, renamable $x0, 1 :: (store 4)
+ ; CHECK: RET undef $lr, implicit $x0
+ early-clobber renamable $x0 = STRSpre killed renamable $s0, killed renamable $x0, 251 :: (store 4)
+ STRSui killed renamable $s1, renamable $x0, 1 :: (store 4)
+ RET undef $lr, implicit $x0
+...
More information about the llvm-commits
mailing list