diff options
author | Chad Rosier <mcrosier@codeaurora.org> | 2015-09-03 14:41:37 +0000 |
---|---|---|
committer | Chad Rosier <mcrosier@codeaurora.org> | 2015-09-03 14:41:37 +0000 |
commit | 491a1bd998d6ef9af56b631659c80751abaa25dc (patch) | |
tree | f7b2f4292b083848d2a53914dfc3773958220587 /llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp | |
parent | a448f046971f379d5e981d764b78fd8838456755 (diff) | |
download | bcm5719-llvm-491a1bd998d6ef9af56b631659c80751abaa25dc.tar.gz bcm5719-llvm-491a1bd998d6ef9af56b631659c80751abaa25dc.zip |
[AArch64] Improve load/store optimizer to handle LDUR + LDR.
This patch allows the mixing of scaled and unscaled load/stores to form
load/store pairs.
PR24465
http://reviews.llvm.org/D12116
Many thanks to Ahmed and Michael for fixes and code review.
llvm-svn: 246769
Diffstat (limited to 'llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp')
-rw-r--r-- | llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp | 98 |
1 files changed, 77 insertions, 21 deletions
diff --git a/llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp b/llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp index 83dd806421e..87ac4d0eb2c 100644 --- a/llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp +++ b/llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp @@ -382,10 +382,24 @@ AArch64LoadStoreOpt::mergePairedInsns(MachineBasicBlock::iterator I, const MachineOperand &BaseRegOp = MergeForward ? getLdStBaseOp(Paired) : getLdStBaseOp(I); + int Offset = getLdStOffsetOp(I).getImm(); + int PairedOffset = getLdStOffsetOp(Paired).getImm(); + bool PairedIsUnscaled = isUnscaledLdSt(Paired->getOpcode()); + + // We're trying to pair instructions that differ in how they are scaled. + // If I is scaled then scale the offset of Paired accordingly. + // Otherwise, do the opposite (i.e., make Paired's offset unscaled). + if (IsUnscaled != PairedIsUnscaled) { + int MemSize = getMemSize(Paired); + assert(!(PairedOffset % getMemSize(Paired)) && + "Offset should be a multiple of the stride!"); + PairedOffset = + PairedIsUnscaled ? PairedOffset / MemSize : PairedOffset * MemSize; + } + // Which register is Rt and which is Rt2 depends on the offset order. MachineInstr *RtMI, *Rt2MI; - if (getLdStOffsetOp(I).getImm() == - getLdStOffsetOp(Paired).getImm() + OffsetStride) { + if (Offset == PairedOffset + OffsetStride) { RtMI = Paired; Rt2MI = I; // Here we swapped the assumption made for SExtIdx. @@ -397,10 +411,13 @@ AArch64LoadStoreOpt::mergePairedInsns(MachineBasicBlock::iterator I, RtMI = I; Rt2MI = Paired; } - // Handle Unscaled + // Scale the immediate offset, if necessary. int OffsetImm = getLdStOffsetOp(RtMI).getImm(); - if (IsUnscaled && EnableAArch64UnscaledMemOp) - OffsetImm /= OffsetStride; + if (isUnscaledLdSt(RtMI->getOpcode()) && EnableAArch64UnscaledMemOp) { + assert(!(OffsetImm % getMemSize(RtMI)) && + "Offset should be a multiple of the stride!"); + OffsetImm /= getMemSize(RtMI); + } // Construct the new instruction. MachineInstrBuilder MIB = BuildMI(*I->getParent(), InsertionPoint, @@ -494,8 +511,13 @@ static void trackRegDefsUses(const MachineInstr *MI, BitVector &ModifiedRegs, static bool inBoundsForPair(bool IsUnscaled, int Offset, int OffsetStride) { // Convert the byte-offset used by unscaled into an "element" offset used // by the scaled pair load/store instructions. - if (IsUnscaled) + if (IsUnscaled) { + // If the byte-offset isn't a multiple of the stride, there's no point + // trying to match it. + if (Offset % OffsetStride) + return false; Offset /= OffsetStride; + } return Offset <= 63 && Offset >= -64; } @@ -531,6 +553,34 @@ static bool mayAlias(MachineInstr *MIa, return false; } +static bool canMergeOpc(unsigned Opc, unsigned PairOpc, LdStPairFlags &Flags) { + // Opcodes match: nothing more to check. + if (Opc == PairOpc) + return true; + + // Try to match a sign-extended load/store with a zero-extended load/store. + Flags.setSExtIdx(-1); + bool IsValidLdStrOpc, PairIsValidLdStrOpc; + unsigned NonSExtOpc = getMatchingNonSExtOpcode(Opc, &IsValidLdStrOpc); + assert(IsValidLdStrOpc && + "Given Opc should be a Load or Store with an immediate"); + // Opc will be the first instruction in the pair. + if (NonSExtOpc == getMatchingNonSExtOpcode(PairOpc, &PairIsValidLdStrOpc)) { + Flags.setSExtIdx(NonSExtOpc == (unsigned)Opc ? 1 : 0); + return true; + } + + // FIXME: Can we also match a mixed sext/zext unscaled/scaled pair? + + // If the second instruction isn't even a load/store, bail out. + if (!PairIsValidLdStrOpc) + return false; + + // Try to match an unscaled load/store with a scaled load/store. + return isUnscaledLdSt(Opc) != isUnscaledLdSt(PairOpc) && + getMatchingPairOpcode(Opc) == getMatchingPairOpcode(PairOpc); +} + /// findMatchingInsn - Scan the instructions looking for a load/store that can /// be combined with the current instruction into a load/store pair. MachineBasicBlock::iterator @@ -581,19 +631,8 @@ AArch64LoadStoreOpt::findMatchingInsn(MachineBasicBlock::iterator I, // Now that we know this is a real instruction, count it. ++Count; - bool CanMergeOpc = Opc == MI->getOpcode(); - Flags.setSExtIdx(-1); - if (!CanMergeOpc) { - bool IsValidLdStrOpc; - unsigned NonSExtOpc = getMatchingNonSExtOpcode(Opc, &IsValidLdStrOpc); - assert(IsValidLdStrOpc && - "Given Opc should be a Load or Store with an immediate"); - // Opc will be the first instruction in the pair. - Flags.setSExtIdx(NonSExtOpc == (unsigned)Opc ? 1 : 0); - CanMergeOpc = NonSExtOpc == getMatchingNonSExtOpcode(MI->getOpcode()); - } - - if (CanMergeOpc && getLdStOffsetOp(MI).isImm()) { + if (canMergeOpc(Opc, MI->getOpcode(), Flags) && + getLdStOffsetOp(MI).isImm()) { assert(MI->mayLoadOrStore() && "Expected memory operation."); // If we've found another instruction with the same opcode, check to see // if the base and offset are compatible with our starting instruction. @@ -607,6 +646,24 @@ AArch64LoadStoreOpt::findMatchingInsn(MachineBasicBlock::iterator I, // final offset must be in range. unsigned MIBaseReg = getLdStBaseOp(MI).getReg(); int MIOffset = getLdStOffsetOp(MI).getImm(); + + // We're trying to pair instructions that differ in how they are scaled. + // If FirstMI is scaled then scale the offset of MI accordingly. + // Otherwise, do the opposite (i.e., make MI's offset unscaled). + bool MIIsUnscaled = isUnscaledLdSt(MI); + if (IsUnscaled != MIIsUnscaled) { + int MemSize = getMemSize(MI); + if (MIIsUnscaled) { + // If the unscaled offset isn't a multiple of the MemSize, we can't + // pair the operations together: bail and keep looking. + if (MIOffset % MemSize) + continue; + MIOffset /= MemSize; + } else { + MIOffset *= MemSize; + } + } + if (BaseReg == MIBaseReg && ((Offset == MIOffset + OffsetStride) || (Offset + OffsetStride == MIOffset))) { int MinOffset = Offset < MIOffset ? Offset : MIOffset; @@ -617,8 +674,7 @@ AArch64LoadStoreOpt::findMatchingInsn(MachineBasicBlock::iterator I, return E; // If the resultant immediate offset of merging these instructions // is out of range for a pairwise instruction, bail and keep looking. - bool MIIsUnscaled = isUnscaledLdSt(MI); - if (!inBoundsForPair(MIIsUnscaled, MinOffset, OffsetStride)) { + if (!inBoundsForPair(IsUnscaled, MinOffset, OffsetStride)) { trackRegDefsUses(MI, ModifiedRegs, UsedRegs, TRI); MemInsns.push_back(MI); continue; |