xref: /freebsd-src/contrib/llvm-project/llvm/lib/CodeGen/GlobalISel/LoadStoreOpt.cpp (revision 349cc55c9796c4596a5b9904cd3281af295f878f)
1*349cc55cSDimitry Andric //===- LoadStoreOpt.cpp ----------- Generic memory optimizations -*- C++ -*-==//
2*349cc55cSDimitry Andric //
3*349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*349cc55cSDimitry Andric //
7*349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
8*349cc55cSDimitry Andric /// \file
9*349cc55cSDimitry Andric /// This file implements the LoadStoreOpt optimization pass.
10*349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
11*349cc55cSDimitry Andric 
12*349cc55cSDimitry Andric #include "llvm/CodeGen/GlobalISel/LoadStoreOpt.h"
13*349cc55cSDimitry Andric #include "llvm/ADT/Statistic.h"
14*349cc55cSDimitry Andric #include "llvm/Analysis/AliasAnalysis.h"
15*349cc55cSDimitry Andric #include "llvm/Analysis/MemoryLocation.h"
16*349cc55cSDimitry Andric #include "llvm/Analysis/OptimizationRemarkEmitter.h"
17*349cc55cSDimitry Andric #include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h"
18*349cc55cSDimitry Andric #include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
19*349cc55cSDimitry Andric #include "llvm/CodeGen/GlobalISel/MIPatternMatch.h"
20*349cc55cSDimitry Andric #include "llvm/CodeGen/GlobalISel/Utils.h"
21*349cc55cSDimitry Andric #include "llvm/CodeGen/LowLevelType.h"
22*349cc55cSDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h"
23*349cc55cSDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
24*349cc55cSDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
25*349cc55cSDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
26*349cc55cSDimitry Andric #include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
27*349cc55cSDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
28*349cc55cSDimitry Andric #include "llvm/CodeGen/Register.h"
29*349cc55cSDimitry Andric #include "llvm/CodeGen/TargetLowering.h"
30*349cc55cSDimitry Andric #include "llvm/CodeGen/TargetOpcodes.h"
31*349cc55cSDimitry Andric #include "llvm/IR/DebugInfoMetadata.h"
32*349cc55cSDimitry Andric #include "llvm/InitializePasses.h"
33*349cc55cSDimitry Andric #include "llvm/Support/AtomicOrdering.h"
34*349cc55cSDimitry Andric #include "llvm/Support/Casting.h"
35*349cc55cSDimitry Andric #include "llvm/Support/Debug.h"
36*349cc55cSDimitry Andric #include "llvm/Support/ErrorHandling.h"
37*349cc55cSDimitry Andric #include "llvm/Support/MathExtras.h"
38*349cc55cSDimitry Andric #include <algorithm>
39*349cc55cSDimitry Andric 
40*349cc55cSDimitry Andric #define DEBUG_TYPE "loadstore-opt"
41*349cc55cSDimitry Andric 
42*349cc55cSDimitry Andric using namespace llvm;
43*349cc55cSDimitry Andric using namespace ore;
44*349cc55cSDimitry Andric using namespace MIPatternMatch;
45*349cc55cSDimitry Andric 
46*349cc55cSDimitry Andric STATISTIC(NumStoresMerged, "Number of stores merged");
47*349cc55cSDimitry Andric 
48*349cc55cSDimitry Andric const unsigned MaxStoreSizeToForm = 128;
49*349cc55cSDimitry Andric 
50*349cc55cSDimitry Andric char LoadStoreOpt::ID = 0;
51*349cc55cSDimitry Andric INITIALIZE_PASS_BEGIN(LoadStoreOpt, DEBUG_TYPE, "Generic memory optimizations",
52*349cc55cSDimitry Andric                       false, false)
53*349cc55cSDimitry Andric INITIALIZE_PASS_END(LoadStoreOpt, DEBUG_TYPE, "Generic memory optimizations",
54*349cc55cSDimitry Andric                     false, false)
55*349cc55cSDimitry Andric 
56*349cc55cSDimitry Andric LoadStoreOpt::LoadStoreOpt(std::function<bool(const MachineFunction &)> F)
57*349cc55cSDimitry Andric     : MachineFunctionPass(ID), DoNotRunPass(F) {}
58*349cc55cSDimitry Andric 
59*349cc55cSDimitry Andric LoadStoreOpt::LoadStoreOpt()
60*349cc55cSDimitry Andric     : LoadStoreOpt([](const MachineFunction &) { return false; }) {}
61*349cc55cSDimitry Andric 
62*349cc55cSDimitry Andric void LoadStoreOpt::init(MachineFunction &MF) {
63*349cc55cSDimitry Andric   this->MF = &MF;
64*349cc55cSDimitry Andric   MRI = &MF.getRegInfo();
65*349cc55cSDimitry Andric   AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
66*349cc55cSDimitry Andric   TLI = MF.getSubtarget().getTargetLowering();
67*349cc55cSDimitry Andric   LI = MF.getSubtarget().getLegalizerInfo();
68*349cc55cSDimitry Andric   Builder.setMF(MF);
69*349cc55cSDimitry Andric   IsPreLegalizer = !MF.getProperties().hasProperty(
70*349cc55cSDimitry Andric       MachineFunctionProperties::Property::Legalized);
71*349cc55cSDimitry Andric   InstsToErase.clear();
72*349cc55cSDimitry Andric }
73*349cc55cSDimitry Andric 
74*349cc55cSDimitry Andric void LoadStoreOpt::getAnalysisUsage(AnalysisUsage &AU) const {
75*349cc55cSDimitry Andric   AU.addRequired<AAResultsWrapperPass>();
76*349cc55cSDimitry Andric   getSelectionDAGFallbackAnalysisUsage(AU);
77*349cc55cSDimitry Andric   MachineFunctionPass::getAnalysisUsage(AU);
78*349cc55cSDimitry Andric }
79*349cc55cSDimitry Andric 
80*349cc55cSDimitry Andric BaseIndexOffset GISelAddressing::getPointerInfo(Register Ptr,
81*349cc55cSDimitry Andric                                                 MachineRegisterInfo &MRI) {
82*349cc55cSDimitry Andric   BaseIndexOffset Info;
83*349cc55cSDimitry Andric   Register PtrAddRHS;
84*349cc55cSDimitry Andric   if (!mi_match(Ptr, MRI, m_GPtrAdd(m_Reg(Info.BaseReg), m_Reg(PtrAddRHS)))) {
85*349cc55cSDimitry Andric     Info.BaseReg = Ptr;
86*349cc55cSDimitry Andric     Info.IndexReg = Register();
87*349cc55cSDimitry Andric     Info.IsIndexSignExt = false;
88*349cc55cSDimitry Andric     return Info;
89*349cc55cSDimitry Andric   }
90*349cc55cSDimitry Andric 
91*349cc55cSDimitry Andric   auto RHSCst = getIConstantVRegValWithLookThrough(PtrAddRHS, MRI);
92*349cc55cSDimitry Andric   if (RHSCst)
93*349cc55cSDimitry Andric     Info.Offset = RHSCst->Value.getSExtValue();
94*349cc55cSDimitry Andric 
95*349cc55cSDimitry Andric   // Just recognize a simple case for now. In future we'll need to match
96*349cc55cSDimitry Andric   // indexing patterns for base + index + constant.
97*349cc55cSDimitry Andric   Info.IndexReg = PtrAddRHS;
98*349cc55cSDimitry Andric   Info.IsIndexSignExt = false;
99*349cc55cSDimitry Andric   return Info;
100*349cc55cSDimitry Andric }
101*349cc55cSDimitry Andric 
102*349cc55cSDimitry Andric bool GISelAddressing::aliasIsKnownForLoadStore(const MachineInstr &MI1,
103*349cc55cSDimitry Andric                                                const MachineInstr &MI2,
104*349cc55cSDimitry Andric                                                bool &IsAlias,
105*349cc55cSDimitry Andric                                                MachineRegisterInfo &MRI) {
106*349cc55cSDimitry Andric   auto *LdSt1 = dyn_cast<GLoadStore>(&MI1);
107*349cc55cSDimitry Andric   auto *LdSt2 = dyn_cast<GLoadStore>(&MI2);
108*349cc55cSDimitry Andric   if (!LdSt1 || !LdSt2)
109*349cc55cSDimitry Andric     return false;
110*349cc55cSDimitry Andric 
111*349cc55cSDimitry Andric   BaseIndexOffset BasePtr0 = getPointerInfo(LdSt1->getPointerReg(), MRI);
112*349cc55cSDimitry Andric   BaseIndexOffset BasePtr1 = getPointerInfo(LdSt2->getPointerReg(), MRI);
113*349cc55cSDimitry Andric 
114*349cc55cSDimitry Andric   if (!BasePtr0.BaseReg.isValid() || !BasePtr1.BaseReg.isValid())
115*349cc55cSDimitry Andric     return false;
116*349cc55cSDimitry Andric 
117*349cc55cSDimitry Andric   int64_t Size1 = LdSt1->getMemSize();
118*349cc55cSDimitry Andric   int64_t Size2 = LdSt2->getMemSize();
119*349cc55cSDimitry Andric 
120*349cc55cSDimitry Andric   int64_t PtrDiff;
121*349cc55cSDimitry Andric   if (BasePtr0.BaseReg == BasePtr1.BaseReg) {
122*349cc55cSDimitry Andric     PtrDiff = BasePtr1.Offset - BasePtr0.Offset;
123*349cc55cSDimitry Andric     // If the size of memory access is unknown, do not use it to do analysis.
124*349cc55cSDimitry Andric     // One example of unknown size memory access is to load/store scalable
125*349cc55cSDimitry Andric     // vector objects on the stack.
126*349cc55cSDimitry Andric     // BasePtr1 is PtrDiff away from BasePtr0. They alias if none of the
127*349cc55cSDimitry Andric     // following situations arise:
128*349cc55cSDimitry Andric     if (PtrDiff >= 0 &&
129*349cc55cSDimitry Andric         Size1 != static_cast<int64_t>(MemoryLocation::UnknownSize)) {
130*349cc55cSDimitry Andric       // [----BasePtr0----]
131*349cc55cSDimitry Andric       //                         [---BasePtr1--]
132*349cc55cSDimitry Andric       // ========PtrDiff========>
133*349cc55cSDimitry Andric       IsAlias = !(Size1 <= PtrDiff);
134*349cc55cSDimitry Andric       return true;
135*349cc55cSDimitry Andric     }
136*349cc55cSDimitry Andric     if (PtrDiff < 0 &&
137*349cc55cSDimitry Andric         Size2 != static_cast<int64_t>(MemoryLocation::UnknownSize)) {
138*349cc55cSDimitry Andric       //                     [----BasePtr0----]
139*349cc55cSDimitry Andric       // [---BasePtr1--]
140*349cc55cSDimitry Andric       // =====(-PtrDiff)====>
141*349cc55cSDimitry Andric       IsAlias = !((PtrDiff + Size2) <= 0);
142*349cc55cSDimitry Andric       return true;
143*349cc55cSDimitry Andric     }
144*349cc55cSDimitry Andric     return false;
145*349cc55cSDimitry Andric   }
146*349cc55cSDimitry Andric 
147*349cc55cSDimitry Andric   // If both BasePtr0 and BasePtr1 are FrameIndexes, we will not be
148*349cc55cSDimitry Andric   // able to calculate their relative offset if at least one arises
149*349cc55cSDimitry Andric   // from an alloca. However, these allocas cannot overlap and we
150*349cc55cSDimitry Andric   // can infer there is no alias.
151*349cc55cSDimitry Andric   auto *Base0Def = getDefIgnoringCopies(BasePtr0.BaseReg, MRI);
152*349cc55cSDimitry Andric   auto *Base1Def = getDefIgnoringCopies(BasePtr1.BaseReg, MRI);
153*349cc55cSDimitry Andric   if (!Base0Def || !Base1Def)
154*349cc55cSDimitry Andric     return false; // Couldn't tell anything.
155*349cc55cSDimitry Andric 
156*349cc55cSDimitry Andric 
157*349cc55cSDimitry Andric   if (Base0Def->getOpcode() != Base1Def->getOpcode())
158*349cc55cSDimitry Andric     return false;
159*349cc55cSDimitry Andric 
160*349cc55cSDimitry Andric   if (Base0Def->getOpcode() == TargetOpcode::G_FRAME_INDEX) {
161*349cc55cSDimitry Andric     MachineFrameInfo &MFI = Base0Def->getMF()->getFrameInfo();
162*349cc55cSDimitry Andric     // If the bases have the same frame index but we couldn't find a
163*349cc55cSDimitry Andric     // constant offset, (indices are different) be conservative.
164*349cc55cSDimitry Andric     if (Base0Def != Base1Def &&
165*349cc55cSDimitry Andric         (!MFI.isFixedObjectIndex(Base0Def->getOperand(1).getIndex()) ||
166*349cc55cSDimitry Andric          !MFI.isFixedObjectIndex(Base1Def->getOperand(1).getIndex()))) {
167*349cc55cSDimitry Andric       IsAlias = false;
168*349cc55cSDimitry Andric       return true;
169*349cc55cSDimitry Andric     }
170*349cc55cSDimitry Andric   }
171*349cc55cSDimitry Andric 
172*349cc55cSDimitry Andric   // This implementation is a lot more primitive than the SDAG one for now.
173*349cc55cSDimitry Andric   // FIXME: what about constant pools?
174*349cc55cSDimitry Andric   if (Base0Def->getOpcode() == TargetOpcode::G_GLOBAL_VALUE) {
175*349cc55cSDimitry Andric     auto GV0 = Base0Def->getOperand(1).getGlobal();
176*349cc55cSDimitry Andric     auto GV1 = Base1Def->getOperand(1).getGlobal();
177*349cc55cSDimitry Andric     if (GV0 != GV1) {
178*349cc55cSDimitry Andric       IsAlias = false;
179*349cc55cSDimitry Andric       return true;
180*349cc55cSDimitry Andric     }
181*349cc55cSDimitry Andric   }
182*349cc55cSDimitry Andric 
183*349cc55cSDimitry Andric   // Can't tell anything about aliasing.
184*349cc55cSDimitry Andric   return false;
185*349cc55cSDimitry Andric }
186*349cc55cSDimitry Andric 
187*349cc55cSDimitry Andric bool GISelAddressing::instMayAlias(const MachineInstr &MI,
188*349cc55cSDimitry Andric                                    const MachineInstr &Other,
189*349cc55cSDimitry Andric                                    MachineRegisterInfo &MRI,
190*349cc55cSDimitry Andric                                    AliasAnalysis *AA) {
191*349cc55cSDimitry Andric   struct MemUseCharacteristics {
192*349cc55cSDimitry Andric     bool IsVolatile;
193*349cc55cSDimitry Andric     bool IsAtomic;
194*349cc55cSDimitry Andric     Register BasePtr;
195*349cc55cSDimitry Andric     int64_t Offset;
196*349cc55cSDimitry Andric     uint64_t NumBytes;
197*349cc55cSDimitry Andric     MachineMemOperand *MMO;
198*349cc55cSDimitry Andric   };
199*349cc55cSDimitry Andric 
200*349cc55cSDimitry Andric   auto getCharacteristics =
201*349cc55cSDimitry Andric       [&](const MachineInstr *MI) -> MemUseCharacteristics {
202*349cc55cSDimitry Andric     if (const auto *LS = dyn_cast<GLoadStore>(MI)) {
203*349cc55cSDimitry Andric       Register BaseReg;
204*349cc55cSDimitry Andric       int64_t Offset = 0;
205*349cc55cSDimitry Andric       // No pre/post-inc addressing modes are considered here, unlike in SDAG.
206*349cc55cSDimitry Andric       if (!mi_match(LS->getPointerReg(), MRI,
207*349cc55cSDimitry Andric                     m_GPtrAdd(m_Reg(BaseReg), m_ICst(Offset)))) {
208*349cc55cSDimitry Andric         BaseReg = LS->getPointerReg();
209*349cc55cSDimitry Andric         Offset = 0;
210*349cc55cSDimitry Andric       }
211*349cc55cSDimitry Andric 
212*349cc55cSDimitry Andric       uint64_t Size = MemoryLocation::getSizeOrUnknown(
213*349cc55cSDimitry Andric           LS->getMMO().getMemoryType().getSizeInBytes());
214*349cc55cSDimitry Andric       return {LS->isVolatile(),       LS->isAtomic(),          BaseReg,
215*349cc55cSDimitry Andric               Offset /*base offset*/, Size, &LS->getMMO()};
216*349cc55cSDimitry Andric     }
217*349cc55cSDimitry Andric     // FIXME: support recognizing lifetime instructions.
218*349cc55cSDimitry Andric     // Default.
219*349cc55cSDimitry Andric     return {false /*isvolatile*/,
220*349cc55cSDimitry Andric             /*isAtomic*/ false,          Register(),
221*349cc55cSDimitry Andric             (int64_t)0 /*offset*/,       0 /*size*/,
222*349cc55cSDimitry Andric             (MachineMemOperand *)nullptr};
223*349cc55cSDimitry Andric   };
224*349cc55cSDimitry Andric   MemUseCharacteristics MUC0 = getCharacteristics(&MI),
225*349cc55cSDimitry Andric                         MUC1 = getCharacteristics(&Other);
226*349cc55cSDimitry Andric 
227*349cc55cSDimitry Andric   // If they are to the same address, then they must be aliases.
228*349cc55cSDimitry Andric   if (MUC0.BasePtr.isValid() && MUC0.BasePtr == MUC1.BasePtr &&
229*349cc55cSDimitry Andric       MUC0.Offset == MUC1.Offset)
230*349cc55cSDimitry Andric     return true;
231*349cc55cSDimitry Andric 
232*349cc55cSDimitry Andric   // If they are both volatile then they cannot be reordered.
233*349cc55cSDimitry Andric   if (MUC0.IsVolatile && MUC1.IsVolatile)
234*349cc55cSDimitry Andric     return true;
235*349cc55cSDimitry Andric 
236*349cc55cSDimitry Andric   // Be conservative about atomics for the moment
237*349cc55cSDimitry Andric   // TODO: This is way overconservative for unordered atomics (see D66309)
238*349cc55cSDimitry Andric   if (MUC0.IsAtomic && MUC1.IsAtomic)
239*349cc55cSDimitry Andric     return true;
240*349cc55cSDimitry Andric 
241*349cc55cSDimitry Andric   // If one operation reads from invariant memory, and the other may store, they
242*349cc55cSDimitry Andric   // cannot alias.
243*349cc55cSDimitry Andric   if (MUC0.MMO && MUC1.MMO) {
244*349cc55cSDimitry Andric     if ((MUC0.MMO->isInvariant() && MUC1.MMO->isStore()) ||
245*349cc55cSDimitry Andric         (MUC1.MMO->isInvariant() && MUC0.MMO->isStore()))
246*349cc55cSDimitry Andric       return false;
247*349cc55cSDimitry Andric   }
248*349cc55cSDimitry Andric 
249*349cc55cSDimitry Andric   // Try to prove that there is aliasing, or that there is no aliasing. Either
250*349cc55cSDimitry Andric   // way, we can return now. If nothing can be proved, proceed with more tests.
251*349cc55cSDimitry Andric   bool IsAlias;
252*349cc55cSDimitry Andric   if (GISelAddressing::aliasIsKnownForLoadStore(MI, Other, IsAlias, MRI))
253*349cc55cSDimitry Andric     return IsAlias;
254*349cc55cSDimitry Andric 
255*349cc55cSDimitry Andric   // The following all rely on MMO0 and MMO1 being valid.
256*349cc55cSDimitry Andric   if (!MUC0.MMO || !MUC1.MMO)
257*349cc55cSDimitry Andric     return true;
258*349cc55cSDimitry Andric 
259*349cc55cSDimitry Andric   // FIXME: port the alignment based alias analysis from SDAG's isAlias().
260*349cc55cSDimitry Andric   int64_t SrcValOffset0 = MUC0.MMO->getOffset();
261*349cc55cSDimitry Andric   int64_t SrcValOffset1 = MUC1.MMO->getOffset();
262*349cc55cSDimitry Andric   uint64_t Size0 = MUC0.NumBytes;
263*349cc55cSDimitry Andric   uint64_t Size1 = MUC1.NumBytes;
264*349cc55cSDimitry Andric   if (AA && MUC0.MMO->getValue() && MUC1.MMO->getValue() &&
265*349cc55cSDimitry Andric       Size0 != MemoryLocation::UnknownSize &&
266*349cc55cSDimitry Andric       Size1 != MemoryLocation::UnknownSize) {
267*349cc55cSDimitry Andric     // Use alias analysis information.
268*349cc55cSDimitry Andric     int64_t MinOffset = std::min(SrcValOffset0, SrcValOffset1);
269*349cc55cSDimitry Andric     int64_t Overlap0 = Size0 + SrcValOffset0 - MinOffset;
270*349cc55cSDimitry Andric     int64_t Overlap1 = Size1 + SrcValOffset1 - MinOffset;
271*349cc55cSDimitry Andric     if (AA->isNoAlias(MemoryLocation(MUC0.MMO->getValue(), Overlap0,
272*349cc55cSDimitry Andric                                      MUC0.MMO->getAAInfo()),
273*349cc55cSDimitry Andric                       MemoryLocation(MUC1.MMO->getValue(), Overlap1,
274*349cc55cSDimitry Andric                                      MUC1.MMO->getAAInfo())))
275*349cc55cSDimitry Andric       return false;
276*349cc55cSDimitry Andric   }
277*349cc55cSDimitry Andric 
278*349cc55cSDimitry Andric   // Otherwise we have to assume they alias.
279*349cc55cSDimitry Andric   return true;
280*349cc55cSDimitry Andric }
281*349cc55cSDimitry Andric 
282*349cc55cSDimitry Andric /// Returns true if the instruction creates an unavoidable hazard that
283*349cc55cSDimitry Andric /// forces a boundary between store merge candidates.
284*349cc55cSDimitry Andric static bool isInstHardMergeHazard(MachineInstr &MI) {
285*349cc55cSDimitry Andric   return MI.hasUnmodeledSideEffects() || MI.hasOrderedMemoryRef();
286*349cc55cSDimitry Andric }
287*349cc55cSDimitry Andric 
288*349cc55cSDimitry Andric bool LoadStoreOpt::mergeStores(SmallVectorImpl<GStore *> &StoresToMerge) {
289*349cc55cSDimitry Andric   // Try to merge all the stores in the vector, splitting into separate segments
290*349cc55cSDimitry Andric   // as necessary.
291*349cc55cSDimitry Andric   assert(StoresToMerge.size() > 1 && "Expected multiple stores to merge");
292*349cc55cSDimitry Andric   LLT OrigTy = MRI->getType(StoresToMerge[0]->getValueReg());
293*349cc55cSDimitry Andric   LLT PtrTy = MRI->getType(StoresToMerge[0]->getPointerReg());
294*349cc55cSDimitry Andric   unsigned AS = PtrTy.getAddressSpace();
295*349cc55cSDimitry Andric   // Ensure the legal store info is computed for this address space.
296*349cc55cSDimitry Andric   initializeStoreMergeTargetInfo(AS);
297*349cc55cSDimitry Andric   const auto &LegalSizes = LegalStoreSizes[AS];
298*349cc55cSDimitry Andric 
299*349cc55cSDimitry Andric #ifndef NDEBUG
300*349cc55cSDimitry Andric   for (auto StoreMI : StoresToMerge)
301*349cc55cSDimitry Andric     assert(MRI->getType(StoreMI->getValueReg()) == OrigTy);
302*349cc55cSDimitry Andric #endif
303*349cc55cSDimitry Andric 
304*349cc55cSDimitry Andric   const auto &DL = MF->getFunction().getParent()->getDataLayout();
305*349cc55cSDimitry Andric   bool AnyMerged = false;
306*349cc55cSDimitry Andric   do {
307*349cc55cSDimitry Andric     unsigned NumPow2 = PowerOf2Floor(StoresToMerge.size());
308*349cc55cSDimitry Andric     unsigned MaxSizeBits = NumPow2 * OrigTy.getSizeInBits().getFixedSize();
309*349cc55cSDimitry Andric     // Compute the biggest store we can generate to handle the number of stores.
310*349cc55cSDimitry Andric     unsigned MergeSizeBits;
311*349cc55cSDimitry Andric     for (MergeSizeBits = MaxSizeBits; MergeSizeBits > 1; MergeSizeBits /= 2) {
312*349cc55cSDimitry Andric       LLT StoreTy = LLT::scalar(MergeSizeBits);
313*349cc55cSDimitry Andric       EVT StoreEVT =
314*349cc55cSDimitry Andric           getApproximateEVTForLLT(StoreTy, DL, MF->getFunction().getContext());
315*349cc55cSDimitry Andric       if (LegalSizes.size() > MergeSizeBits && LegalSizes[MergeSizeBits] &&
316*349cc55cSDimitry Andric           TLI->canMergeStoresTo(AS, StoreEVT, *MF) &&
317*349cc55cSDimitry Andric           (TLI->isTypeLegal(StoreEVT)))
318*349cc55cSDimitry Andric         break; // We can generate a MergeSize bits store.
319*349cc55cSDimitry Andric     }
320*349cc55cSDimitry Andric     if (MergeSizeBits <= OrigTy.getSizeInBits())
321*349cc55cSDimitry Andric       return AnyMerged; // No greater merge.
322*349cc55cSDimitry Andric 
323*349cc55cSDimitry Andric     unsigned NumStoresToMerge = MergeSizeBits / OrigTy.getSizeInBits();
324*349cc55cSDimitry Andric     // Perform the actual merging.
325*349cc55cSDimitry Andric     SmallVector<GStore *, 8> SingleMergeStores(
326*349cc55cSDimitry Andric         StoresToMerge.begin(), StoresToMerge.begin() + NumStoresToMerge);
327*349cc55cSDimitry Andric     AnyMerged |= doSingleStoreMerge(SingleMergeStores);
328*349cc55cSDimitry Andric     StoresToMerge.erase(StoresToMerge.begin(),
329*349cc55cSDimitry Andric                         StoresToMerge.begin() + NumStoresToMerge);
330*349cc55cSDimitry Andric   } while (StoresToMerge.size() > 1);
331*349cc55cSDimitry Andric   return AnyMerged;
332*349cc55cSDimitry Andric }
333*349cc55cSDimitry Andric 
334*349cc55cSDimitry Andric bool LoadStoreOpt::isLegalOrBeforeLegalizer(const LegalityQuery &Query,
335*349cc55cSDimitry Andric                                             MachineFunction &MF) const {
336*349cc55cSDimitry Andric   auto Action = LI->getAction(Query).Action;
337*349cc55cSDimitry Andric   // If the instruction is unsupported, it can't be legalized at all.
338*349cc55cSDimitry Andric   if (Action == LegalizeActions::Unsupported)
339*349cc55cSDimitry Andric     return false;
340*349cc55cSDimitry Andric   return IsPreLegalizer || Action == LegalizeAction::Legal;
341*349cc55cSDimitry Andric }
342*349cc55cSDimitry Andric 
343*349cc55cSDimitry Andric bool LoadStoreOpt::doSingleStoreMerge(SmallVectorImpl<GStore *> &Stores) {
344*349cc55cSDimitry Andric   assert(Stores.size() > 1);
345*349cc55cSDimitry Andric   // We know that all the stores are consecutive and there are no aliasing
346*349cc55cSDimitry Andric   // operations in the range. However, the values that are being stored may be
347*349cc55cSDimitry Andric   // generated anywhere before each store. To ensure we have the values
348*349cc55cSDimitry Andric   // available, we materialize the wide value and new store at the place of the
349*349cc55cSDimitry Andric   // final store in the merge sequence.
350*349cc55cSDimitry Andric   GStore *FirstStore = Stores[0];
351*349cc55cSDimitry Andric   const unsigned NumStores = Stores.size();
352*349cc55cSDimitry Andric   LLT SmallTy = MRI->getType(FirstStore->getValueReg());
353*349cc55cSDimitry Andric   LLT WideValueTy =
354*349cc55cSDimitry Andric       LLT::scalar(NumStores * SmallTy.getSizeInBits().getFixedSize());
355*349cc55cSDimitry Andric 
356*349cc55cSDimitry Andric   // For each store, compute pairwise merged debug locs.
357*349cc55cSDimitry Andric   DebugLoc MergedLoc;
358*349cc55cSDimitry Andric   for (unsigned AIdx = 0, BIdx = 1; BIdx < NumStores; ++AIdx, ++BIdx)
359*349cc55cSDimitry Andric     MergedLoc = DILocation::getMergedLocation(Stores[AIdx]->getDebugLoc(),
360*349cc55cSDimitry Andric                                               Stores[BIdx]->getDebugLoc());
361*349cc55cSDimitry Andric   Builder.setInstr(*Stores.back());
362*349cc55cSDimitry Andric   Builder.setDebugLoc(MergedLoc);
363*349cc55cSDimitry Andric 
364*349cc55cSDimitry Andric   // If all of the store values are constants, then create a wide constant
365*349cc55cSDimitry Andric   // directly. Otherwise, we need to generate some instructions to merge the
366*349cc55cSDimitry Andric   // existing values together into a wider type.
367*349cc55cSDimitry Andric   SmallVector<APInt, 8> ConstantVals;
368*349cc55cSDimitry Andric   for (auto Store : Stores) {
369*349cc55cSDimitry Andric     auto MaybeCst =
370*349cc55cSDimitry Andric         getIConstantVRegValWithLookThrough(Store->getValueReg(), *MRI);
371*349cc55cSDimitry Andric     if (!MaybeCst) {
372*349cc55cSDimitry Andric       ConstantVals.clear();
373*349cc55cSDimitry Andric       break;
374*349cc55cSDimitry Andric     }
375*349cc55cSDimitry Andric     ConstantVals.emplace_back(MaybeCst->Value);
376*349cc55cSDimitry Andric   }
377*349cc55cSDimitry Andric 
378*349cc55cSDimitry Andric   Register WideReg;
379*349cc55cSDimitry Andric   auto *WideMMO =
380*349cc55cSDimitry Andric       MF->getMachineMemOperand(&FirstStore->getMMO(), 0, WideValueTy);
381*349cc55cSDimitry Andric   if (ConstantVals.empty()) {
382*349cc55cSDimitry Andric     // Mimic the SDAG behaviour here and don't try to do anything for unknown
383*349cc55cSDimitry Andric     // values. In future, we should also support the cases of loads and
384*349cc55cSDimitry Andric     // extracted vector elements.
385*349cc55cSDimitry Andric     return false;
386*349cc55cSDimitry Andric   }
387*349cc55cSDimitry Andric 
388*349cc55cSDimitry Andric   assert(ConstantVals.size() == NumStores);
389*349cc55cSDimitry Andric   // Check if our wide constant is legal.
390*349cc55cSDimitry Andric   if (!isLegalOrBeforeLegalizer({TargetOpcode::G_CONSTANT, {WideValueTy}}, *MF))
391*349cc55cSDimitry Andric     return false;
392*349cc55cSDimitry Andric   APInt WideConst(WideValueTy.getSizeInBits(), 0);
393*349cc55cSDimitry Andric   for (unsigned Idx = 0; Idx < ConstantVals.size(); ++Idx) {
394*349cc55cSDimitry Andric     // Insert the smaller constant into the corresponding position in the
395*349cc55cSDimitry Andric     // wider one.
396*349cc55cSDimitry Andric     WideConst.insertBits(ConstantVals[Idx], Idx * SmallTy.getSizeInBits());
397*349cc55cSDimitry Andric   }
398*349cc55cSDimitry Andric   WideReg = Builder.buildConstant(WideValueTy, WideConst).getReg(0);
399*349cc55cSDimitry Andric   auto NewStore =
400*349cc55cSDimitry Andric       Builder.buildStore(WideReg, FirstStore->getPointerReg(), *WideMMO);
401*349cc55cSDimitry Andric   (void) NewStore;
402*349cc55cSDimitry Andric   LLVM_DEBUG(dbgs() << "Created merged store: " << *NewStore);
403*349cc55cSDimitry Andric   NumStoresMerged += Stores.size();
404*349cc55cSDimitry Andric 
405*349cc55cSDimitry Andric   MachineOptimizationRemarkEmitter MORE(*MF, nullptr);
406*349cc55cSDimitry Andric   MORE.emit([&]() {
407*349cc55cSDimitry Andric     MachineOptimizationRemark R(DEBUG_TYPE, "MergedStore",
408*349cc55cSDimitry Andric                                 FirstStore->getDebugLoc(),
409*349cc55cSDimitry Andric                                 FirstStore->getParent());
410*349cc55cSDimitry Andric     R << "Merged " << NV("NumMerged", Stores.size()) << " stores of "
411*349cc55cSDimitry Andric       << NV("OrigWidth", SmallTy.getSizeInBytes())
412*349cc55cSDimitry Andric       << " bytes into a single store of "
413*349cc55cSDimitry Andric       << NV("NewWidth", WideValueTy.getSizeInBytes()) << " bytes";
414*349cc55cSDimitry Andric     return R;
415*349cc55cSDimitry Andric   });
416*349cc55cSDimitry Andric 
417*349cc55cSDimitry Andric   for (auto MI : Stores)
418*349cc55cSDimitry Andric     InstsToErase.insert(MI);
419*349cc55cSDimitry Andric   return true;
420*349cc55cSDimitry Andric }
421*349cc55cSDimitry Andric 
422*349cc55cSDimitry Andric bool LoadStoreOpt::processMergeCandidate(StoreMergeCandidate &C) {
423*349cc55cSDimitry Andric   if (C.Stores.size() < 2) {
424*349cc55cSDimitry Andric     C.reset();
425*349cc55cSDimitry Andric     return false;
426*349cc55cSDimitry Andric   }
427*349cc55cSDimitry Andric 
428*349cc55cSDimitry Andric   LLVM_DEBUG(dbgs() << "Checking store merge candidate with " << C.Stores.size()
429*349cc55cSDimitry Andric                     << " stores, starting with " << *C.Stores[0]);
430*349cc55cSDimitry Andric   // We know that the stores in the candidate are adjacent.
431*349cc55cSDimitry Andric   // Now we need to check if any potential aliasing instructions recorded
432*349cc55cSDimitry Andric   // during the search alias with load/stores added to the candidate after.
433*349cc55cSDimitry Andric   // For example, if we have the candidate:
434*349cc55cSDimitry Andric   //   C.Stores = [ST1, ST2, ST3, ST4]
435*349cc55cSDimitry Andric   // and after seeing ST2 we saw a load LD1, which did not alias with ST1 or
436*349cc55cSDimitry Andric   // ST2, then we would have recorded it into the PotentialAliases structure
437*349cc55cSDimitry Andric   // with the associated index value of "1". Then we see ST3 and ST4 and add
438*349cc55cSDimitry Andric   // them to the candidate group. We know that LD1 does not alias with ST1 or
439*349cc55cSDimitry Andric   // ST2, since we already did that check. However we don't yet know if it
440*349cc55cSDimitry Andric   // may alias ST3 and ST4, so we perform those checks now.
441*349cc55cSDimitry Andric   SmallVector<GStore *> StoresToMerge;
442*349cc55cSDimitry Andric 
443*349cc55cSDimitry Andric   auto DoesStoreAliasWithPotential = [&](unsigned Idx, GStore &CheckStore) {
444*349cc55cSDimitry Andric     for (auto AliasInfo : reverse(C.PotentialAliases)) {
445*349cc55cSDimitry Andric       MachineInstr *PotentialAliasOp = AliasInfo.first;
446*349cc55cSDimitry Andric       unsigned PreCheckedIdx = AliasInfo.second;
447*349cc55cSDimitry Andric       if (static_cast<unsigned>(Idx) > PreCheckedIdx) {
448*349cc55cSDimitry Andric         // Need to check this alias.
449*349cc55cSDimitry Andric         if (GISelAddressing::instMayAlias(CheckStore, *PotentialAliasOp, *MRI,
450*349cc55cSDimitry Andric                                           AA)) {
451*349cc55cSDimitry Andric           LLVM_DEBUG(dbgs() << "Potential alias " << *PotentialAliasOp
452*349cc55cSDimitry Andric                             << " detected\n");
453*349cc55cSDimitry Andric           return true;
454*349cc55cSDimitry Andric         }
455*349cc55cSDimitry Andric       } else {
456*349cc55cSDimitry Andric         // Once our store index is lower than the index associated with the
457*349cc55cSDimitry Andric         // potential alias, we know that we've already checked for this alias
458*349cc55cSDimitry Andric         // and all of the earlier potential aliases too.
459*349cc55cSDimitry Andric         return false;
460*349cc55cSDimitry Andric       }
461*349cc55cSDimitry Andric     }
462*349cc55cSDimitry Andric     return false;
463*349cc55cSDimitry Andric   };
464*349cc55cSDimitry Andric   // Start from the last store in the group, and check if it aliases with any
465*349cc55cSDimitry Andric   // of the potential aliasing operations in the list.
466*349cc55cSDimitry Andric   for (int StoreIdx = C.Stores.size() - 1; StoreIdx >= 0; --StoreIdx) {
467*349cc55cSDimitry Andric     auto *CheckStore = C.Stores[StoreIdx];
468*349cc55cSDimitry Andric     if (DoesStoreAliasWithPotential(StoreIdx, *CheckStore))
469*349cc55cSDimitry Andric       continue;
470*349cc55cSDimitry Andric     StoresToMerge.emplace_back(CheckStore);
471*349cc55cSDimitry Andric   }
472*349cc55cSDimitry Andric 
473*349cc55cSDimitry Andric   LLVM_DEBUG(dbgs() << StoresToMerge.size()
474*349cc55cSDimitry Andric                     << " stores remaining after alias checks. Merging...\n");
475*349cc55cSDimitry Andric 
476*349cc55cSDimitry Andric   // Now we've checked for aliasing hazards, merge any stores left.
477*349cc55cSDimitry Andric   C.reset();
478*349cc55cSDimitry Andric   if (StoresToMerge.size() < 2)
479*349cc55cSDimitry Andric     return false;
480*349cc55cSDimitry Andric   return mergeStores(StoresToMerge);
481*349cc55cSDimitry Andric }
482*349cc55cSDimitry Andric 
483*349cc55cSDimitry Andric bool LoadStoreOpt::operationAliasesWithCandidate(MachineInstr &MI,
484*349cc55cSDimitry Andric                                                  StoreMergeCandidate &C) {
485*349cc55cSDimitry Andric   if (C.Stores.empty())
486*349cc55cSDimitry Andric     return false;
487*349cc55cSDimitry Andric   return llvm::any_of(C.Stores, [&](MachineInstr *OtherMI) {
488*349cc55cSDimitry Andric     return instMayAlias(MI, *OtherMI, *MRI, AA);
489*349cc55cSDimitry Andric   });
490*349cc55cSDimitry Andric }
491*349cc55cSDimitry Andric 
492*349cc55cSDimitry Andric void LoadStoreOpt::StoreMergeCandidate::addPotentialAlias(MachineInstr &MI) {
493*349cc55cSDimitry Andric   PotentialAliases.emplace_back(std::make_pair(&MI, Stores.size() - 1));
494*349cc55cSDimitry Andric }
495*349cc55cSDimitry Andric 
496*349cc55cSDimitry Andric bool LoadStoreOpt::addStoreToCandidate(GStore &StoreMI,
497*349cc55cSDimitry Andric                                        StoreMergeCandidate &C) {
498*349cc55cSDimitry Andric   // Check if the given store writes to an adjacent address, and other
499*349cc55cSDimitry Andric   // requirements.
500*349cc55cSDimitry Andric   LLT ValueTy = MRI->getType(StoreMI.getValueReg());
501*349cc55cSDimitry Andric   LLT PtrTy = MRI->getType(StoreMI.getPointerReg());
502*349cc55cSDimitry Andric 
503*349cc55cSDimitry Andric   // Only handle scalars.
504*349cc55cSDimitry Andric   if (!ValueTy.isScalar())
505*349cc55cSDimitry Andric     return false;
506*349cc55cSDimitry Andric 
507*349cc55cSDimitry Andric   // Don't allow truncating stores for now.
508*349cc55cSDimitry Andric   if (StoreMI.getMemSizeInBits() != ValueTy.getSizeInBits())
509*349cc55cSDimitry Andric     return false;
510*349cc55cSDimitry Andric 
511*349cc55cSDimitry Andric   Register StoreAddr = StoreMI.getPointerReg();
512*349cc55cSDimitry Andric   auto BIO = getPointerInfo(StoreAddr, *MRI);
513*349cc55cSDimitry Andric   Register StoreBase = BIO.BaseReg;
514*349cc55cSDimitry Andric   uint64_t StoreOffCst = BIO.Offset;
515*349cc55cSDimitry Andric   if (C.Stores.empty()) {
516*349cc55cSDimitry Andric     // This is the first store of the candidate.
517*349cc55cSDimitry Andric     // If the offset can't possibly allow for a lower addressed store with the
518*349cc55cSDimitry Andric     // same base, don't bother adding it.
519*349cc55cSDimitry Andric     if (StoreOffCst < ValueTy.getSizeInBytes())
520*349cc55cSDimitry Andric       return false;
521*349cc55cSDimitry Andric     C.BasePtr = StoreBase;
522*349cc55cSDimitry Andric     C.CurrentLowestOffset = StoreOffCst;
523*349cc55cSDimitry Andric     C.Stores.emplace_back(&StoreMI);
524*349cc55cSDimitry Andric     LLVM_DEBUG(dbgs() << "Starting a new merge candidate group with: "
525*349cc55cSDimitry Andric                       << StoreMI);
526*349cc55cSDimitry Andric     return true;
527*349cc55cSDimitry Andric   }
528*349cc55cSDimitry Andric 
529*349cc55cSDimitry Andric   // Check the store is the same size as the existing ones in the candidate.
530*349cc55cSDimitry Andric   if (MRI->getType(C.Stores[0]->getValueReg()).getSizeInBits() !=
531*349cc55cSDimitry Andric       ValueTy.getSizeInBits())
532*349cc55cSDimitry Andric     return false;
533*349cc55cSDimitry Andric 
534*349cc55cSDimitry Andric   if (MRI->getType(C.Stores[0]->getPointerReg()).getAddressSpace() !=
535*349cc55cSDimitry Andric       PtrTy.getAddressSpace())
536*349cc55cSDimitry Andric     return false;
537*349cc55cSDimitry Andric 
538*349cc55cSDimitry Andric   // There are other stores in the candidate. Check that the store address
539*349cc55cSDimitry Andric   // writes to the next lowest adjacent address.
540*349cc55cSDimitry Andric   if (C.BasePtr != StoreBase)
541*349cc55cSDimitry Andric     return false;
542*349cc55cSDimitry Andric   if ((C.CurrentLowestOffset - ValueTy.getSizeInBytes()) !=
543*349cc55cSDimitry Andric       static_cast<uint64_t>(StoreOffCst))
544*349cc55cSDimitry Andric     return false;
545*349cc55cSDimitry Andric 
546*349cc55cSDimitry Andric   // This writes to an adjacent address. Allow it.
547*349cc55cSDimitry Andric   C.Stores.emplace_back(&StoreMI);
548*349cc55cSDimitry Andric   C.CurrentLowestOffset = C.CurrentLowestOffset - ValueTy.getSizeInBytes();
549*349cc55cSDimitry Andric   LLVM_DEBUG(dbgs() << "Candidate added store: " << StoreMI);
550*349cc55cSDimitry Andric   return true;
551*349cc55cSDimitry Andric }
552*349cc55cSDimitry Andric 
553*349cc55cSDimitry Andric bool LoadStoreOpt::mergeBlockStores(MachineBasicBlock &MBB) {
554*349cc55cSDimitry Andric   bool Changed = false;
555*349cc55cSDimitry Andric   // Walk through the block bottom-up, looking for merging candidates.
556*349cc55cSDimitry Andric   StoreMergeCandidate Candidate;
557*349cc55cSDimitry Andric   for (auto II = MBB.rbegin(), IE = MBB.rend(); II != IE; ++II) {
558*349cc55cSDimitry Andric     MachineInstr &MI = *II;
559*349cc55cSDimitry Andric     if (InstsToErase.contains(&MI))
560*349cc55cSDimitry Andric       continue;
561*349cc55cSDimitry Andric 
562*349cc55cSDimitry Andric     if (auto StoreMI = dyn_cast<GStore>(&*II)) {
563*349cc55cSDimitry Andric       // We have a G_STORE. Add it to the candidate if it writes to an adjacent
564*349cc55cSDimitry Andric       // address.
565*349cc55cSDimitry Andric       if (!addStoreToCandidate(*StoreMI, Candidate)) {
566*349cc55cSDimitry Andric         // Store wasn't eligible to be added. May need to record it as a
567*349cc55cSDimitry Andric         // potential alias.
568*349cc55cSDimitry Andric         if (operationAliasesWithCandidate(*StoreMI, Candidate)) {
569*349cc55cSDimitry Andric           Changed |= processMergeCandidate(Candidate);
570*349cc55cSDimitry Andric           continue;
571*349cc55cSDimitry Andric         }
572*349cc55cSDimitry Andric         Candidate.addPotentialAlias(*StoreMI);
573*349cc55cSDimitry Andric       }
574*349cc55cSDimitry Andric       continue;
575*349cc55cSDimitry Andric     }
576*349cc55cSDimitry Andric 
577*349cc55cSDimitry Andric     // If we don't have any stores yet, this instruction can't pose a problem.
578*349cc55cSDimitry Andric     if (Candidate.Stores.empty())
579*349cc55cSDimitry Andric       continue;
580*349cc55cSDimitry Andric 
581*349cc55cSDimitry Andric     // We're dealing with some other kind of instruction.
582*349cc55cSDimitry Andric     if (isInstHardMergeHazard(MI)) {
583*349cc55cSDimitry Andric       Changed |= processMergeCandidate(Candidate);
584*349cc55cSDimitry Andric       Candidate.Stores.clear();
585*349cc55cSDimitry Andric       continue;
586*349cc55cSDimitry Andric     }
587*349cc55cSDimitry Andric 
588*349cc55cSDimitry Andric     if (!MI.mayLoadOrStore())
589*349cc55cSDimitry Andric       continue;
590*349cc55cSDimitry Andric 
591*349cc55cSDimitry Andric     if (operationAliasesWithCandidate(MI, Candidate)) {
592*349cc55cSDimitry Andric       // We have a potential alias, so process the current candidate if we can
593*349cc55cSDimitry Andric       // and then continue looking for a new candidate.
594*349cc55cSDimitry Andric       Changed |= processMergeCandidate(Candidate);
595*349cc55cSDimitry Andric       continue;
596*349cc55cSDimitry Andric     }
597*349cc55cSDimitry Andric 
598*349cc55cSDimitry Andric     // Record this instruction as a potential alias for future stores that are
599*349cc55cSDimitry Andric     // added to the candidate.
600*349cc55cSDimitry Andric     Candidate.addPotentialAlias(MI);
601*349cc55cSDimitry Andric   }
602*349cc55cSDimitry Andric 
603*349cc55cSDimitry Andric   // Process any candidate left after finishing searching the entire block.
604*349cc55cSDimitry Andric   Changed |= processMergeCandidate(Candidate);
605*349cc55cSDimitry Andric 
606*349cc55cSDimitry Andric   // Erase instructions now that we're no longer iterating over the block.
607*349cc55cSDimitry Andric   for (auto *MI : InstsToErase)
608*349cc55cSDimitry Andric     MI->eraseFromParent();
609*349cc55cSDimitry Andric   InstsToErase.clear();
610*349cc55cSDimitry Andric   return Changed;
611*349cc55cSDimitry Andric }
612*349cc55cSDimitry Andric 
613*349cc55cSDimitry Andric bool LoadStoreOpt::mergeFunctionStores(MachineFunction &MF) {
614*349cc55cSDimitry Andric   bool Changed = false;
615*349cc55cSDimitry Andric   for (auto &BB : MF) {
616*349cc55cSDimitry Andric     Changed |= mergeBlockStores(BB);
617*349cc55cSDimitry Andric   }
618*349cc55cSDimitry Andric   return Changed;
619*349cc55cSDimitry Andric }
620*349cc55cSDimitry Andric 
621*349cc55cSDimitry Andric void LoadStoreOpt::initializeStoreMergeTargetInfo(unsigned AddrSpace) {
622*349cc55cSDimitry Andric   // Query the legalizer info to record what store types are legal.
623*349cc55cSDimitry Andric   // We record this because we don't want to bother trying to merge stores into
624*349cc55cSDimitry Andric   // illegal ones, which would just result in being split again.
625*349cc55cSDimitry Andric 
626*349cc55cSDimitry Andric   if (LegalStoreSizes.count(AddrSpace)) {
627*349cc55cSDimitry Andric     assert(LegalStoreSizes[AddrSpace].any());
628*349cc55cSDimitry Andric     return; // Already cached sizes for this address space.
629*349cc55cSDimitry Andric   }
630*349cc55cSDimitry Andric 
631*349cc55cSDimitry Andric   // Need to reserve at least MaxStoreSizeToForm + 1 bits.
632*349cc55cSDimitry Andric   BitVector LegalSizes(MaxStoreSizeToForm * 2);
633*349cc55cSDimitry Andric   const auto &LI = *MF->getSubtarget().getLegalizerInfo();
634*349cc55cSDimitry Andric   const auto &DL = MF->getFunction().getParent()->getDataLayout();
635*349cc55cSDimitry Andric   Type *IntPtrIRTy =
636*349cc55cSDimitry Andric       DL.getIntPtrType(MF->getFunction().getContext(), AddrSpace);
637*349cc55cSDimitry Andric   LLT PtrTy = getLLTForType(*IntPtrIRTy->getPointerTo(AddrSpace), DL);
638*349cc55cSDimitry Andric   // We assume that we're not going to be generating any stores wider than
639*349cc55cSDimitry Andric   // MaxStoreSizeToForm bits for now.
640*349cc55cSDimitry Andric   for (unsigned Size = 2; Size <= MaxStoreSizeToForm; Size *= 2) {
641*349cc55cSDimitry Andric     LLT Ty = LLT::scalar(Size);
642*349cc55cSDimitry Andric     SmallVector<LegalityQuery::MemDesc, 2> MemDescrs(
643*349cc55cSDimitry Andric         {{Ty, Ty.getSizeInBits(), AtomicOrdering::NotAtomic}});
644*349cc55cSDimitry Andric     SmallVector<LLT> StoreTys({Ty, PtrTy});
645*349cc55cSDimitry Andric     LegalityQuery Q(TargetOpcode::G_STORE, StoreTys, MemDescrs);
646*349cc55cSDimitry Andric     LegalizeActionStep ActionStep = LI.getAction(Q);
647*349cc55cSDimitry Andric     if (ActionStep.Action == LegalizeActions::Legal)
648*349cc55cSDimitry Andric       LegalSizes.set(Size);
649*349cc55cSDimitry Andric   }
650*349cc55cSDimitry Andric   assert(LegalSizes.any() && "Expected some store sizes to be legal!");
651*349cc55cSDimitry Andric   LegalStoreSizes[AddrSpace] = LegalSizes;
652*349cc55cSDimitry Andric }
653*349cc55cSDimitry Andric 
654*349cc55cSDimitry Andric bool LoadStoreOpt::runOnMachineFunction(MachineFunction &MF) {
655*349cc55cSDimitry Andric   // If the ISel pipeline failed, do not bother running that pass.
656*349cc55cSDimitry Andric   if (MF.getProperties().hasProperty(
657*349cc55cSDimitry Andric           MachineFunctionProperties::Property::FailedISel))
658*349cc55cSDimitry Andric     return false;
659*349cc55cSDimitry Andric 
660*349cc55cSDimitry Andric   LLVM_DEBUG(dbgs() << "Begin memory optimizations for: " << MF.getName()
661*349cc55cSDimitry Andric                     << '\n');
662*349cc55cSDimitry Andric 
663*349cc55cSDimitry Andric   init(MF);
664*349cc55cSDimitry Andric   bool Changed = false;
665*349cc55cSDimitry Andric   Changed |= mergeFunctionStores(MF);
666*349cc55cSDimitry Andric 
667*349cc55cSDimitry Andric   LegalStoreSizes.clear();
668*349cc55cSDimitry Andric   return Changed;
669*349cc55cSDimitry Andric }
670