xref: /freebsd-src/contrib/llvm-project/llvm/lib/CodeGen/GlobalISel/LoadStoreOpt.cpp (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
1349cc55cSDimitry Andric //===- LoadStoreOpt.cpp ----------- Generic memory optimizations -*- C++ -*-==//
2349cc55cSDimitry Andric //
3349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6349cc55cSDimitry Andric //
7349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
8349cc55cSDimitry Andric /// \file
9349cc55cSDimitry Andric /// This file implements the LoadStoreOpt optimization pass.
10349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
11349cc55cSDimitry Andric 
12349cc55cSDimitry Andric #include "llvm/CodeGen/GlobalISel/LoadStoreOpt.h"
13349cc55cSDimitry Andric #include "llvm/ADT/Statistic.h"
14349cc55cSDimitry Andric #include "llvm/Analysis/AliasAnalysis.h"
15349cc55cSDimitry Andric #include "llvm/Analysis/MemoryLocation.h"
16349cc55cSDimitry Andric #include "llvm/Analysis/OptimizationRemarkEmitter.h"
17349cc55cSDimitry Andric #include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h"
18349cc55cSDimitry Andric #include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
19349cc55cSDimitry Andric #include "llvm/CodeGen/GlobalISel/MIPatternMatch.h"
20349cc55cSDimitry Andric #include "llvm/CodeGen/GlobalISel/Utils.h"
21349cc55cSDimitry Andric #include "llvm/CodeGen/LowLevelType.h"
22349cc55cSDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h"
23349cc55cSDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
24349cc55cSDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
25349cc55cSDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
26349cc55cSDimitry Andric #include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
27349cc55cSDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
28349cc55cSDimitry Andric #include "llvm/CodeGen/Register.h"
29349cc55cSDimitry Andric #include "llvm/CodeGen/TargetLowering.h"
30349cc55cSDimitry Andric #include "llvm/CodeGen/TargetOpcodes.h"
31349cc55cSDimitry Andric #include "llvm/IR/DebugInfoMetadata.h"
32349cc55cSDimitry Andric #include "llvm/InitializePasses.h"
33349cc55cSDimitry Andric #include "llvm/Support/AtomicOrdering.h"
34349cc55cSDimitry Andric #include "llvm/Support/Casting.h"
35349cc55cSDimitry Andric #include "llvm/Support/Debug.h"
36349cc55cSDimitry Andric #include "llvm/Support/ErrorHandling.h"
37349cc55cSDimitry Andric #include "llvm/Support/MathExtras.h"
38349cc55cSDimitry Andric #include <algorithm>
39349cc55cSDimitry Andric 
40349cc55cSDimitry Andric #define DEBUG_TYPE "loadstore-opt"
41349cc55cSDimitry Andric 
42349cc55cSDimitry Andric using namespace llvm;
43349cc55cSDimitry Andric using namespace ore;
44349cc55cSDimitry Andric using namespace MIPatternMatch;
45349cc55cSDimitry Andric 
46349cc55cSDimitry Andric STATISTIC(NumStoresMerged, "Number of stores merged");
47349cc55cSDimitry Andric 
48349cc55cSDimitry Andric const unsigned MaxStoreSizeToForm = 128;
49349cc55cSDimitry Andric 
50349cc55cSDimitry Andric char LoadStoreOpt::ID = 0;
51349cc55cSDimitry Andric INITIALIZE_PASS_BEGIN(LoadStoreOpt, DEBUG_TYPE, "Generic memory optimizations",
52349cc55cSDimitry Andric                       false, false)
53349cc55cSDimitry Andric INITIALIZE_PASS_END(LoadStoreOpt, DEBUG_TYPE, "Generic memory optimizations",
54349cc55cSDimitry Andric                     false, false)
55349cc55cSDimitry Andric 
56349cc55cSDimitry Andric LoadStoreOpt::LoadStoreOpt(std::function<bool(const MachineFunction &)> F)
57349cc55cSDimitry Andric     : MachineFunctionPass(ID), DoNotRunPass(F) {}
58349cc55cSDimitry Andric 
59349cc55cSDimitry Andric LoadStoreOpt::LoadStoreOpt()
60349cc55cSDimitry Andric     : LoadStoreOpt([](const MachineFunction &) { return false; }) {}
61349cc55cSDimitry Andric 
62349cc55cSDimitry Andric void LoadStoreOpt::init(MachineFunction &MF) {
63349cc55cSDimitry Andric   this->MF = &MF;
64349cc55cSDimitry Andric   MRI = &MF.getRegInfo();
65349cc55cSDimitry Andric   AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
66349cc55cSDimitry Andric   TLI = MF.getSubtarget().getTargetLowering();
67349cc55cSDimitry Andric   LI = MF.getSubtarget().getLegalizerInfo();
68349cc55cSDimitry Andric   Builder.setMF(MF);
69349cc55cSDimitry Andric   IsPreLegalizer = !MF.getProperties().hasProperty(
70349cc55cSDimitry Andric       MachineFunctionProperties::Property::Legalized);
71349cc55cSDimitry Andric   InstsToErase.clear();
72349cc55cSDimitry Andric }
73349cc55cSDimitry Andric 
74349cc55cSDimitry Andric void LoadStoreOpt::getAnalysisUsage(AnalysisUsage &AU) const {
75349cc55cSDimitry Andric   AU.addRequired<AAResultsWrapperPass>();
76*81ad6265SDimitry Andric   AU.setPreservesAll();
77349cc55cSDimitry Andric   getSelectionDAGFallbackAnalysisUsage(AU);
78349cc55cSDimitry Andric   MachineFunctionPass::getAnalysisUsage(AU);
79349cc55cSDimitry Andric }
80349cc55cSDimitry Andric 
81349cc55cSDimitry Andric BaseIndexOffset GISelAddressing::getPointerInfo(Register Ptr,
82349cc55cSDimitry Andric                                                 MachineRegisterInfo &MRI) {
83349cc55cSDimitry Andric   BaseIndexOffset Info;
84349cc55cSDimitry Andric   Register PtrAddRHS;
85349cc55cSDimitry Andric   if (!mi_match(Ptr, MRI, m_GPtrAdd(m_Reg(Info.BaseReg), m_Reg(PtrAddRHS)))) {
86349cc55cSDimitry Andric     Info.BaseReg = Ptr;
87349cc55cSDimitry Andric     Info.IndexReg = Register();
88349cc55cSDimitry Andric     Info.IsIndexSignExt = false;
89349cc55cSDimitry Andric     return Info;
90349cc55cSDimitry Andric   }
91349cc55cSDimitry Andric 
92349cc55cSDimitry Andric   auto RHSCst = getIConstantVRegValWithLookThrough(PtrAddRHS, MRI);
93349cc55cSDimitry Andric   if (RHSCst)
94349cc55cSDimitry Andric     Info.Offset = RHSCst->Value.getSExtValue();
95349cc55cSDimitry Andric 
96349cc55cSDimitry Andric   // Just recognize a simple case for now. In future we'll need to match
97349cc55cSDimitry Andric   // indexing patterns for base + index + constant.
98349cc55cSDimitry Andric   Info.IndexReg = PtrAddRHS;
99349cc55cSDimitry Andric   Info.IsIndexSignExt = false;
100349cc55cSDimitry Andric   return Info;
101349cc55cSDimitry Andric }
102349cc55cSDimitry Andric 
103349cc55cSDimitry Andric bool GISelAddressing::aliasIsKnownForLoadStore(const MachineInstr &MI1,
104349cc55cSDimitry Andric                                                const MachineInstr &MI2,
105349cc55cSDimitry Andric                                                bool &IsAlias,
106349cc55cSDimitry Andric                                                MachineRegisterInfo &MRI) {
107349cc55cSDimitry Andric   auto *LdSt1 = dyn_cast<GLoadStore>(&MI1);
108349cc55cSDimitry Andric   auto *LdSt2 = dyn_cast<GLoadStore>(&MI2);
109349cc55cSDimitry Andric   if (!LdSt1 || !LdSt2)
110349cc55cSDimitry Andric     return false;
111349cc55cSDimitry Andric 
112349cc55cSDimitry Andric   BaseIndexOffset BasePtr0 = getPointerInfo(LdSt1->getPointerReg(), MRI);
113349cc55cSDimitry Andric   BaseIndexOffset BasePtr1 = getPointerInfo(LdSt2->getPointerReg(), MRI);
114349cc55cSDimitry Andric 
115349cc55cSDimitry Andric   if (!BasePtr0.BaseReg.isValid() || !BasePtr1.BaseReg.isValid())
116349cc55cSDimitry Andric     return false;
117349cc55cSDimitry Andric 
118349cc55cSDimitry Andric   int64_t Size1 = LdSt1->getMemSize();
119349cc55cSDimitry Andric   int64_t Size2 = LdSt2->getMemSize();
120349cc55cSDimitry Andric 
121349cc55cSDimitry Andric   int64_t PtrDiff;
122349cc55cSDimitry Andric   if (BasePtr0.BaseReg == BasePtr1.BaseReg) {
123349cc55cSDimitry Andric     PtrDiff = BasePtr1.Offset - BasePtr0.Offset;
124349cc55cSDimitry Andric     // If the size of memory access is unknown, do not use it to do analysis.
125349cc55cSDimitry Andric     // One example of unknown size memory access is to load/store scalable
126349cc55cSDimitry Andric     // vector objects on the stack.
127349cc55cSDimitry Andric     // BasePtr1 is PtrDiff away from BasePtr0. They alias if none of the
128349cc55cSDimitry Andric     // following situations arise:
129349cc55cSDimitry Andric     if (PtrDiff >= 0 &&
130349cc55cSDimitry Andric         Size1 != static_cast<int64_t>(MemoryLocation::UnknownSize)) {
131349cc55cSDimitry Andric       // [----BasePtr0----]
132349cc55cSDimitry Andric       //                         [---BasePtr1--]
133349cc55cSDimitry Andric       // ========PtrDiff========>
134349cc55cSDimitry Andric       IsAlias = !(Size1 <= PtrDiff);
135349cc55cSDimitry Andric       return true;
136349cc55cSDimitry Andric     }
137349cc55cSDimitry Andric     if (PtrDiff < 0 &&
138349cc55cSDimitry Andric         Size2 != static_cast<int64_t>(MemoryLocation::UnknownSize)) {
139349cc55cSDimitry Andric       //                     [----BasePtr0----]
140349cc55cSDimitry Andric       // [---BasePtr1--]
141349cc55cSDimitry Andric       // =====(-PtrDiff)====>
142349cc55cSDimitry Andric       IsAlias = !((PtrDiff + Size2) <= 0);
143349cc55cSDimitry Andric       return true;
144349cc55cSDimitry Andric     }
145349cc55cSDimitry Andric     return false;
146349cc55cSDimitry Andric   }
147349cc55cSDimitry Andric 
148349cc55cSDimitry Andric   // If both BasePtr0 and BasePtr1 are FrameIndexes, we will not be
149349cc55cSDimitry Andric   // able to calculate their relative offset if at least one arises
150349cc55cSDimitry Andric   // from an alloca. However, these allocas cannot overlap and we
151349cc55cSDimitry Andric   // can infer there is no alias.
152349cc55cSDimitry Andric   auto *Base0Def = getDefIgnoringCopies(BasePtr0.BaseReg, MRI);
153349cc55cSDimitry Andric   auto *Base1Def = getDefIgnoringCopies(BasePtr1.BaseReg, MRI);
154349cc55cSDimitry Andric   if (!Base0Def || !Base1Def)
155349cc55cSDimitry Andric     return false; // Couldn't tell anything.
156349cc55cSDimitry Andric 
157349cc55cSDimitry Andric 
158349cc55cSDimitry Andric   if (Base0Def->getOpcode() != Base1Def->getOpcode())
159349cc55cSDimitry Andric     return false;
160349cc55cSDimitry Andric 
161349cc55cSDimitry Andric   if (Base0Def->getOpcode() == TargetOpcode::G_FRAME_INDEX) {
162349cc55cSDimitry Andric     MachineFrameInfo &MFI = Base0Def->getMF()->getFrameInfo();
163349cc55cSDimitry Andric     // If the bases have the same frame index but we couldn't find a
164349cc55cSDimitry Andric     // constant offset, (indices are different) be conservative.
165349cc55cSDimitry Andric     if (Base0Def != Base1Def &&
166349cc55cSDimitry Andric         (!MFI.isFixedObjectIndex(Base0Def->getOperand(1).getIndex()) ||
167349cc55cSDimitry Andric          !MFI.isFixedObjectIndex(Base1Def->getOperand(1).getIndex()))) {
168349cc55cSDimitry Andric       IsAlias = false;
169349cc55cSDimitry Andric       return true;
170349cc55cSDimitry Andric     }
171349cc55cSDimitry Andric   }
172349cc55cSDimitry Andric 
173349cc55cSDimitry Andric   // This implementation is a lot more primitive than the SDAG one for now.
174349cc55cSDimitry Andric   // FIXME: what about constant pools?
175349cc55cSDimitry Andric   if (Base0Def->getOpcode() == TargetOpcode::G_GLOBAL_VALUE) {
176349cc55cSDimitry Andric     auto GV0 = Base0Def->getOperand(1).getGlobal();
177349cc55cSDimitry Andric     auto GV1 = Base1Def->getOperand(1).getGlobal();
178349cc55cSDimitry Andric     if (GV0 != GV1) {
179349cc55cSDimitry Andric       IsAlias = false;
180349cc55cSDimitry Andric       return true;
181349cc55cSDimitry Andric     }
182349cc55cSDimitry Andric   }
183349cc55cSDimitry Andric 
184349cc55cSDimitry Andric   // Can't tell anything about aliasing.
185349cc55cSDimitry Andric   return false;
186349cc55cSDimitry Andric }
187349cc55cSDimitry Andric 
188349cc55cSDimitry Andric bool GISelAddressing::instMayAlias(const MachineInstr &MI,
189349cc55cSDimitry Andric                                    const MachineInstr &Other,
190349cc55cSDimitry Andric                                    MachineRegisterInfo &MRI,
191349cc55cSDimitry Andric                                    AliasAnalysis *AA) {
192349cc55cSDimitry Andric   struct MemUseCharacteristics {
193349cc55cSDimitry Andric     bool IsVolatile;
194349cc55cSDimitry Andric     bool IsAtomic;
195349cc55cSDimitry Andric     Register BasePtr;
196349cc55cSDimitry Andric     int64_t Offset;
197349cc55cSDimitry Andric     uint64_t NumBytes;
198349cc55cSDimitry Andric     MachineMemOperand *MMO;
199349cc55cSDimitry Andric   };
200349cc55cSDimitry Andric 
201349cc55cSDimitry Andric   auto getCharacteristics =
202349cc55cSDimitry Andric       [&](const MachineInstr *MI) -> MemUseCharacteristics {
203349cc55cSDimitry Andric     if (const auto *LS = dyn_cast<GLoadStore>(MI)) {
204349cc55cSDimitry Andric       Register BaseReg;
205349cc55cSDimitry Andric       int64_t Offset = 0;
206349cc55cSDimitry Andric       // No pre/post-inc addressing modes are considered here, unlike in SDAG.
207349cc55cSDimitry Andric       if (!mi_match(LS->getPointerReg(), MRI,
208349cc55cSDimitry Andric                     m_GPtrAdd(m_Reg(BaseReg), m_ICst(Offset)))) {
209349cc55cSDimitry Andric         BaseReg = LS->getPointerReg();
210349cc55cSDimitry Andric         Offset = 0;
211349cc55cSDimitry Andric       }
212349cc55cSDimitry Andric 
213349cc55cSDimitry Andric       uint64_t Size = MemoryLocation::getSizeOrUnknown(
214349cc55cSDimitry Andric           LS->getMMO().getMemoryType().getSizeInBytes());
215349cc55cSDimitry Andric       return {LS->isVolatile(),       LS->isAtomic(),          BaseReg,
216349cc55cSDimitry Andric               Offset /*base offset*/, Size, &LS->getMMO()};
217349cc55cSDimitry Andric     }
218349cc55cSDimitry Andric     // FIXME: support recognizing lifetime instructions.
219349cc55cSDimitry Andric     // Default.
220349cc55cSDimitry Andric     return {false /*isvolatile*/,
221349cc55cSDimitry Andric             /*isAtomic*/ false,          Register(),
222349cc55cSDimitry Andric             (int64_t)0 /*offset*/,       0 /*size*/,
223349cc55cSDimitry Andric             (MachineMemOperand *)nullptr};
224349cc55cSDimitry Andric   };
225349cc55cSDimitry Andric   MemUseCharacteristics MUC0 = getCharacteristics(&MI),
226349cc55cSDimitry Andric                         MUC1 = getCharacteristics(&Other);
227349cc55cSDimitry Andric 
228349cc55cSDimitry Andric   // If they are to the same address, then they must be aliases.
229349cc55cSDimitry Andric   if (MUC0.BasePtr.isValid() && MUC0.BasePtr == MUC1.BasePtr &&
230349cc55cSDimitry Andric       MUC0.Offset == MUC1.Offset)
231349cc55cSDimitry Andric     return true;
232349cc55cSDimitry Andric 
233349cc55cSDimitry Andric   // If they are both volatile then they cannot be reordered.
234349cc55cSDimitry Andric   if (MUC0.IsVolatile && MUC1.IsVolatile)
235349cc55cSDimitry Andric     return true;
236349cc55cSDimitry Andric 
237349cc55cSDimitry Andric   // Be conservative about atomics for the moment
238349cc55cSDimitry Andric   // TODO: This is way overconservative for unordered atomics (see D66309)
239349cc55cSDimitry Andric   if (MUC0.IsAtomic && MUC1.IsAtomic)
240349cc55cSDimitry Andric     return true;
241349cc55cSDimitry Andric 
242349cc55cSDimitry Andric   // If one operation reads from invariant memory, and the other may store, they
243349cc55cSDimitry Andric   // cannot alias.
244349cc55cSDimitry Andric   if (MUC0.MMO && MUC1.MMO) {
245349cc55cSDimitry Andric     if ((MUC0.MMO->isInvariant() && MUC1.MMO->isStore()) ||
246349cc55cSDimitry Andric         (MUC1.MMO->isInvariant() && MUC0.MMO->isStore()))
247349cc55cSDimitry Andric       return false;
248349cc55cSDimitry Andric   }
249349cc55cSDimitry Andric 
250349cc55cSDimitry Andric   // Try to prove that there is aliasing, or that there is no aliasing. Either
251349cc55cSDimitry Andric   // way, we can return now. If nothing can be proved, proceed with more tests.
252349cc55cSDimitry Andric   bool IsAlias;
253349cc55cSDimitry Andric   if (GISelAddressing::aliasIsKnownForLoadStore(MI, Other, IsAlias, MRI))
254349cc55cSDimitry Andric     return IsAlias;
255349cc55cSDimitry Andric 
256349cc55cSDimitry Andric   // The following all rely on MMO0 and MMO1 being valid.
257349cc55cSDimitry Andric   if (!MUC0.MMO || !MUC1.MMO)
258349cc55cSDimitry Andric     return true;
259349cc55cSDimitry Andric 
260349cc55cSDimitry Andric   // FIXME: port the alignment based alias analysis from SDAG's isAlias().
261349cc55cSDimitry Andric   int64_t SrcValOffset0 = MUC0.MMO->getOffset();
262349cc55cSDimitry Andric   int64_t SrcValOffset1 = MUC1.MMO->getOffset();
263349cc55cSDimitry Andric   uint64_t Size0 = MUC0.NumBytes;
264349cc55cSDimitry Andric   uint64_t Size1 = MUC1.NumBytes;
265349cc55cSDimitry Andric   if (AA && MUC0.MMO->getValue() && MUC1.MMO->getValue() &&
266349cc55cSDimitry Andric       Size0 != MemoryLocation::UnknownSize &&
267349cc55cSDimitry Andric       Size1 != MemoryLocation::UnknownSize) {
268349cc55cSDimitry Andric     // Use alias analysis information.
269349cc55cSDimitry Andric     int64_t MinOffset = std::min(SrcValOffset0, SrcValOffset1);
270349cc55cSDimitry Andric     int64_t Overlap0 = Size0 + SrcValOffset0 - MinOffset;
271349cc55cSDimitry Andric     int64_t Overlap1 = Size1 + SrcValOffset1 - MinOffset;
272349cc55cSDimitry Andric     if (AA->isNoAlias(MemoryLocation(MUC0.MMO->getValue(), Overlap0,
273349cc55cSDimitry Andric                                      MUC0.MMO->getAAInfo()),
274349cc55cSDimitry Andric                       MemoryLocation(MUC1.MMO->getValue(), Overlap1,
275349cc55cSDimitry Andric                                      MUC1.MMO->getAAInfo())))
276349cc55cSDimitry Andric       return false;
277349cc55cSDimitry Andric   }
278349cc55cSDimitry Andric 
279349cc55cSDimitry Andric   // Otherwise we have to assume they alias.
280349cc55cSDimitry Andric   return true;
281349cc55cSDimitry Andric }
282349cc55cSDimitry Andric 
283349cc55cSDimitry Andric /// Returns true if the instruction creates an unavoidable hazard that
284349cc55cSDimitry Andric /// forces a boundary between store merge candidates.
285349cc55cSDimitry Andric static bool isInstHardMergeHazard(MachineInstr &MI) {
286349cc55cSDimitry Andric   return MI.hasUnmodeledSideEffects() || MI.hasOrderedMemoryRef();
287349cc55cSDimitry Andric }
288349cc55cSDimitry Andric 
289349cc55cSDimitry Andric bool LoadStoreOpt::mergeStores(SmallVectorImpl<GStore *> &StoresToMerge) {
290349cc55cSDimitry Andric   // Try to merge all the stores in the vector, splitting into separate segments
291349cc55cSDimitry Andric   // as necessary.
292349cc55cSDimitry Andric   assert(StoresToMerge.size() > 1 && "Expected multiple stores to merge");
293349cc55cSDimitry Andric   LLT OrigTy = MRI->getType(StoresToMerge[0]->getValueReg());
294349cc55cSDimitry Andric   LLT PtrTy = MRI->getType(StoresToMerge[0]->getPointerReg());
295349cc55cSDimitry Andric   unsigned AS = PtrTy.getAddressSpace();
296349cc55cSDimitry Andric   // Ensure the legal store info is computed for this address space.
297349cc55cSDimitry Andric   initializeStoreMergeTargetInfo(AS);
298349cc55cSDimitry Andric   const auto &LegalSizes = LegalStoreSizes[AS];
299349cc55cSDimitry Andric 
300349cc55cSDimitry Andric #ifndef NDEBUG
301349cc55cSDimitry Andric   for (auto StoreMI : StoresToMerge)
302349cc55cSDimitry Andric     assert(MRI->getType(StoreMI->getValueReg()) == OrigTy);
303349cc55cSDimitry Andric #endif
304349cc55cSDimitry Andric 
305349cc55cSDimitry Andric   const auto &DL = MF->getFunction().getParent()->getDataLayout();
306349cc55cSDimitry Andric   bool AnyMerged = false;
307349cc55cSDimitry Andric   do {
308349cc55cSDimitry Andric     unsigned NumPow2 = PowerOf2Floor(StoresToMerge.size());
309349cc55cSDimitry Andric     unsigned MaxSizeBits = NumPow2 * OrigTy.getSizeInBits().getFixedSize();
310349cc55cSDimitry Andric     // Compute the biggest store we can generate to handle the number of stores.
311349cc55cSDimitry Andric     unsigned MergeSizeBits;
312349cc55cSDimitry Andric     for (MergeSizeBits = MaxSizeBits; MergeSizeBits > 1; MergeSizeBits /= 2) {
313349cc55cSDimitry Andric       LLT StoreTy = LLT::scalar(MergeSizeBits);
314349cc55cSDimitry Andric       EVT StoreEVT =
315349cc55cSDimitry Andric           getApproximateEVTForLLT(StoreTy, DL, MF->getFunction().getContext());
316349cc55cSDimitry Andric       if (LegalSizes.size() > MergeSizeBits && LegalSizes[MergeSizeBits] &&
317349cc55cSDimitry Andric           TLI->canMergeStoresTo(AS, StoreEVT, *MF) &&
318349cc55cSDimitry Andric           (TLI->isTypeLegal(StoreEVT)))
319349cc55cSDimitry Andric         break; // We can generate a MergeSize bits store.
320349cc55cSDimitry Andric     }
321349cc55cSDimitry Andric     if (MergeSizeBits <= OrigTy.getSizeInBits())
322349cc55cSDimitry Andric       return AnyMerged; // No greater merge.
323349cc55cSDimitry Andric 
324349cc55cSDimitry Andric     unsigned NumStoresToMerge = MergeSizeBits / OrigTy.getSizeInBits();
325349cc55cSDimitry Andric     // Perform the actual merging.
326349cc55cSDimitry Andric     SmallVector<GStore *, 8> SingleMergeStores(
327349cc55cSDimitry Andric         StoresToMerge.begin(), StoresToMerge.begin() + NumStoresToMerge);
328349cc55cSDimitry Andric     AnyMerged |= doSingleStoreMerge(SingleMergeStores);
329349cc55cSDimitry Andric     StoresToMerge.erase(StoresToMerge.begin(),
330349cc55cSDimitry Andric                         StoresToMerge.begin() + NumStoresToMerge);
331349cc55cSDimitry Andric   } while (StoresToMerge.size() > 1);
332349cc55cSDimitry Andric   return AnyMerged;
333349cc55cSDimitry Andric }
334349cc55cSDimitry Andric 
335349cc55cSDimitry Andric bool LoadStoreOpt::isLegalOrBeforeLegalizer(const LegalityQuery &Query,
336349cc55cSDimitry Andric                                             MachineFunction &MF) const {
337349cc55cSDimitry Andric   auto Action = LI->getAction(Query).Action;
338349cc55cSDimitry Andric   // If the instruction is unsupported, it can't be legalized at all.
339349cc55cSDimitry Andric   if (Action == LegalizeActions::Unsupported)
340349cc55cSDimitry Andric     return false;
341349cc55cSDimitry Andric   return IsPreLegalizer || Action == LegalizeAction::Legal;
342349cc55cSDimitry Andric }
343349cc55cSDimitry Andric 
344349cc55cSDimitry Andric bool LoadStoreOpt::doSingleStoreMerge(SmallVectorImpl<GStore *> &Stores) {
345349cc55cSDimitry Andric   assert(Stores.size() > 1);
346349cc55cSDimitry Andric   // We know that all the stores are consecutive and there are no aliasing
347349cc55cSDimitry Andric   // operations in the range. However, the values that are being stored may be
348349cc55cSDimitry Andric   // generated anywhere before each store. To ensure we have the values
349349cc55cSDimitry Andric   // available, we materialize the wide value and new store at the place of the
350349cc55cSDimitry Andric   // final store in the merge sequence.
351349cc55cSDimitry Andric   GStore *FirstStore = Stores[0];
352349cc55cSDimitry Andric   const unsigned NumStores = Stores.size();
353349cc55cSDimitry Andric   LLT SmallTy = MRI->getType(FirstStore->getValueReg());
354349cc55cSDimitry Andric   LLT WideValueTy =
355349cc55cSDimitry Andric       LLT::scalar(NumStores * SmallTy.getSizeInBits().getFixedSize());
356349cc55cSDimitry Andric 
357349cc55cSDimitry Andric   // For each store, compute pairwise merged debug locs.
358349cc55cSDimitry Andric   DebugLoc MergedLoc;
359349cc55cSDimitry Andric   for (unsigned AIdx = 0, BIdx = 1; BIdx < NumStores; ++AIdx, ++BIdx)
360349cc55cSDimitry Andric     MergedLoc = DILocation::getMergedLocation(Stores[AIdx]->getDebugLoc(),
361349cc55cSDimitry Andric                                               Stores[BIdx]->getDebugLoc());
362349cc55cSDimitry Andric   Builder.setInstr(*Stores.back());
363349cc55cSDimitry Andric   Builder.setDebugLoc(MergedLoc);
364349cc55cSDimitry Andric 
365349cc55cSDimitry Andric   // If all of the store values are constants, then create a wide constant
366349cc55cSDimitry Andric   // directly. Otherwise, we need to generate some instructions to merge the
367349cc55cSDimitry Andric   // existing values together into a wider type.
368349cc55cSDimitry Andric   SmallVector<APInt, 8> ConstantVals;
369349cc55cSDimitry Andric   for (auto Store : Stores) {
370349cc55cSDimitry Andric     auto MaybeCst =
371349cc55cSDimitry Andric         getIConstantVRegValWithLookThrough(Store->getValueReg(), *MRI);
372349cc55cSDimitry Andric     if (!MaybeCst) {
373349cc55cSDimitry Andric       ConstantVals.clear();
374349cc55cSDimitry Andric       break;
375349cc55cSDimitry Andric     }
376349cc55cSDimitry Andric     ConstantVals.emplace_back(MaybeCst->Value);
377349cc55cSDimitry Andric   }
378349cc55cSDimitry Andric 
379349cc55cSDimitry Andric   Register WideReg;
380349cc55cSDimitry Andric   auto *WideMMO =
381349cc55cSDimitry Andric       MF->getMachineMemOperand(&FirstStore->getMMO(), 0, WideValueTy);
382349cc55cSDimitry Andric   if (ConstantVals.empty()) {
383349cc55cSDimitry Andric     // Mimic the SDAG behaviour here and don't try to do anything for unknown
384349cc55cSDimitry Andric     // values. In future, we should also support the cases of loads and
385349cc55cSDimitry Andric     // extracted vector elements.
386349cc55cSDimitry Andric     return false;
387349cc55cSDimitry Andric   }
388349cc55cSDimitry Andric 
389349cc55cSDimitry Andric   assert(ConstantVals.size() == NumStores);
390349cc55cSDimitry Andric   // Check if our wide constant is legal.
391349cc55cSDimitry Andric   if (!isLegalOrBeforeLegalizer({TargetOpcode::G_CONSTANT, {WideValueTy}}, *MF))
392349cc55cSDimitry Andric     return false;
393349cc55cSDimitry Andric   APInt WideConst(WideValueTy.getSizeInBits(), 0);
394349cc55cSDimitry Andric   for (unsigned Idx = 0; Idx < ConstantVals.size(); ++Idx) {
395349cc55cSDimitry Andric     // Insert the smaller constant into the corresponding position in the
396349cc55cSDimitry Andric     // wider one.
397349cc55cSDimitry Andric     WideConst.insertBits(ConstantVals[Idx], Idx * SmallTy.getSizeInBits());
398349cc55cSDimitry Andric   }
399349cc55cSDimitry Andric   WideReg = Builder.buildConstant(WideValueTy, WideConst).getReg(0);
400349cc55cSDimitry Andric   auto NewStore =
401349cc55cSDimitry Andric       Builder.buildStore(WideReg, FirstStore->getPointerReg(), *WideMMO);
402349cc55cSDimitry Andric   (void) NewStore;
403349cc55cSDimitry Andric   LLVM_DEBUG(dbgs() << "Created merged store: " << *NewStore);
404349cc55cSDimitry Andric   NumStoresMerged += Stores.size();
405349cc55cSDimitry Andric 
406349cc55cSDimitry Andric   MachineOptimizationRemarkEmitter MORE(*MF, nullptr);
407349cc55cSDimitry Andric   MORE.emit([&]() {
408349cc55cSDimitry Andric     MachineOptimizationRemark R(DEBUG_TYPE, "MergedStore",
409349cc55cSDimitry Andric                                 FirstStore->getDebugLoc(),
410349cc55cSDimitry Andric                                 FirstStore->getParent());
411349cc55cSDimitry Andric     R << "Merged " << NV("NumMerged", Stores.size()) << " stores of "
412349cc55cSDimitry Andric       << NV("OrigWidth", SmallTy.getSizeInBytes())
413349cc55cSDimitry Andric       << " bytes into a single store of "
414349cc55cSDimitry Andric       << NV("NewWidth", WideValueTy.getSizeInBytes()) << " bytes";
415349cc55cSDimitry Andric     return R;
416349cc55cSDimitry Andric   });
417349cc55cSDimitry Andric 
418349cc55cSDimitry Andric   for (auto MI : Stores)
419349cc55cSDimitry Andric     InstsToErase.insert(MI);
420349cc55cSDimitry Andric   return true;
421349cc55cSDimitry Andric }
422349cc55cSDimitry Andric 
423349cc55cSDimitry Andric bool LoadStoreOpt::processMergeCandidate(StoreMergeCandidate &C) {
424349cc55cSDimitry Andric   if (C.Stores.size() < 2) {
425349cc55cSDimitry Andric     C.reset();
426349cc55cSDimitry Andric     return false;
427349cc55cSDimitry Andric   }
428349cc55cSDimitry Andric 
429349cc55cSDimitry Andric   LLVM_DEBUG(dbgs() << "Checking store merge candidate with " << C.Stores.size()
430349cc55cSDimitry Andric                     << " stores, starting with " << *C.Stores[0]);
431349cc55cSDimitry Andric   // We know that the stores in the candidate are adjacent.
432349cc55cSDimitry Andric   // Now we need to check if any potential aliasing instructions recorded
433349cc55cSDimitry Andric   // during the search alias with load/stores added to the candidate after.
434349cc55cSDimitry Andric   // For example, if we have the candidate:
435349cc55cSDimitry Andric   //   C.Stores = [ST1, ST2, ST3, ST4]
436349cc55cSDimitry Andric   // and after seeing ST2 we saw a load LD1, which did not alias with ST1 or
437349cc55cSDimitry Andric   // ST2, then we would have recorded it into the PotentialAliases structure
438349cc55cSDimitry Andric   // with the associated index value of "1". Then we see ST3 and ST4 and add
439349cc55cSDimitry Andric   // them to the candidate group. We know that LD1 does not alias with ST1 or
440349cc55cSDimitry Andric   // ST2, since we already did that check. However we don't yet know if it
441349cc55cSDimitry Andric   // may alias ST3 and ST4, so we perform those checks now.
442349cc55cSDimitry Andric   SmallVector<GStore *> StoresToMerge;
443349cc55cSDimitry Andric 
444349cc55cSDimitry Andric   auto DoesStoreAliasWithPotential = [&](unsigned Idx, GStore &CheckStore) {
445349cc55cSDimitry Andric     for (auto AliasInfo : reverse(C.PotentialAliases)) {
446349cc55cSDimitry Andric       MachineInstr *PotentialAliasOp = AliasInfo.first;
447349cc55cSDimitry Andric       unsigned PreCheckedIdx = AliasInfo.second;
448349cc55cSDimitry Andric       if (static_cast<unsigned>(Idx) > PreCheckedIdx) {
449349cc55cSDimitry Andric         // Need to check this alias.
450349cc55cSDimitry Andric         if (GISelAddressing::instMayAlias(CheckStore, *PotentialAliasOp, *MRI,
451349cc55cSDimitry Andric                                           AA)) {
452349cc55cSDimitry Andric           LLVM_DEBUG(dbgs() << "Potential alias " << *PotentialAliasOp
453349cc55cSDimitry Andric                             << " detected\n");
454349cc55cSDimitry Andric           return true;
455349cc55cSDimitry Andric         }
456349cc55cSDimitry Andric       } else {
457349cc55cSDimitry Andric         // Once our store index is lower than the index associated with the
458349cc55cSDimitry Andric         // potential alias, we know that we've already checked for this alias
459349cc55cSDimitry Andric         // and all of the earlier potential aliases too.
460349cc55cSDimitry Andric         return false;
461349cc55cSDimitry Andric       }
462349cc55cSDimitry Andric     }
463349cc55cSDimitry Andric     return false;
464349cc55cSDimitry Andric   };
465349cc55cSDimitry Andric   // Start from the last store in the group, and check if it aliases with any
466349cc55cSDimitry Andric   // of the potential aliasing operations in the list.
467349cc55cSDimitry Andric   for (int StoreIdx = C.Stores.size() - 1; StoreIdx >= 0; --StoreIdx) {
468349cc55cSDimitry Andric     auto *CheckStore = C.Stores[StoreIdx];
469349cc55cSDimitry Andric     if (DoesStoreAliasWithPotential(StoreIdx, *CheckStore))
470349cc55cSDimitry Andric       continue;
471349cc55cSDimitry Andric     StoresToMerge.emplace_back(CheckStore);
472349cc55cSDimitry Andric   }
473349cc55cSDimitry Andric 
474349cc55cSDimitry Andric   LLVM_DEBUG(dbgs() << StoresToMerge.size()
475349cc55cSDimitry Andric                     << " stores remaining after alias checks. Merging...\n");
476349cc55cSDimitry Andric 
477349cc55cSDimitry Andric   // Now we've checked for aliasing hazards, merge any stores left.
478349cc55cSDimitry Andric   C.reset();
479349cc55cSDimitry Andric   if (StoresToMerge.size() < 2)
480349cc55cSDimitry Andric     return false;
481349cc55cSDimitry Andric   return mergeStores(StoresToMerge);
482349cc55cSDimitry Andric }
483349cc55cSDimitry Andric 
484349cc55cSDimitry Andric bool LoadStoreOpt::operationAliasesWithCandidate(MachineInstr &MI,
485349cc55cSDimitry Andric                                                  StoreMergeCandidate &C) {
486349cc55cSDimitry Andric   if (C.Stores.empty())
487349cc55cSDimitry Andric     return false;
488349cc55cSDimitry Andric   return llvm::any_of(C.Stores, [&](MachineInstr *OtherMI) {
489349cc55cSDimitry Andric     return instMayAlias(MI, *OtherMI, *MRI, AA);
490349cc55cSDimitry Andric   });
491349cc55cSDimitry Andric }
492349cc55cSDimitry Andric 
493349cc55cSDimitry Andric void LoadStoreOpt::StoreMergeCandidate::addPotentialAlias(MachineInstr &MI) {
494349cc55cSDimitry Andric   PotentialAliases.emplace_back(std::make_pair(&MI, Stores.size() - 1));
495349cc55cSDimitry Andric }
496349cc55cSDimitry Andric 
497349cc55cSDimitry Andric bool LoadStoreOpt::addStoreToCandidate(GStore &StoreMI,
498349cc55cSDimitry Andric                                        StoreMergeCandidate &C) {
499349cc55cSDimitry Andric   // Check if the given store writes to an adjacent address, and other
500349cc55cSDimitry Andric   // requirements.
501349cc55cSDimitry Andric   LLT ValueTy = MRI->getType(StoreMI.getValueReg());
502349cc55cSDimitry Andric   LLT PtrTy = MRI->getType(StoreMI.getPointerReg());
503349cc55cSDimitry Andric 
504349cc55cSDimitry Andric   // Only handle scalars.
505349cc55cSDimitry Andric   if (!ValueTy.isScalar())
506349cc55cSDimitry Andric     return false;
507349cc55cSDimitry Andric 
508349cc55cSDimitry Andric   // Don't allow truncating stores for now.
509349cc55cSDimitry Andric   if (StoreMI.getMemSizeInBits() != ValueTy.getSizeInBits())
510349cc55cSDimitry Andric     return false;
511349cc55cSDimitry Andric 
512*81ad6265SDimitry Andric   // Avoid adding volatile or ordered stores to the candidate. We already have a
513*81ad6265SDimitry Andric   // check for this in instMayAlias() but that only get's called later between
514*81ad6265SDimitry Andric   // potential aliasing hazards.
515*81ad6265SDimitry Andric   if (!StoreMI.isSimple())
516*81ad6265SDimitry Andric     return false;
517*81ad6265SDimitry Andric 
518349cc55cSDimitry Andric   Register StoreAddr = StoreMI.getPointerReg();
519349cc55cSDimitry Andric   auto BIO = getPointerInfo(StoreAddr, *MRI);
520349cc55cSDimitry Andric   Register StoreBase = BIO.BaseReg;
521349cc55cSDimitry Andric   uint64_t StoreOffCst = BIO.Offset;
522349cc55cSDimitry Andric   if (C.Stores.empty()) {
523349cc55cSDimitry Andric     // This is the first store of the candidate.
524349cc55cSDimitry Andric     // If the offset can't possibly allow for a lower addressed store with the
525349cc55cSDimitry Andric     // same base, don't bother adding it.
526349cc55cSDimitry Andric     if (StoreOffCst < ValueTy.getSizeInBytes())
527349cc55cSDimitry Andric       return false;
528349cc55cSDimitry Andric     C.BasePtr = StoreBase;
529349cc55cSDimitry Andric     C.CurrentLowestOffset = StoreOffCst;
530349cc55cSDimitry Andric     C.Stores.emplace_back(&StoreMI);
531349cc55cSDimitry Andric     LLVM_DEBUG(dbgs() << "Starting a new merge candidate group with: "
532349cc55cSDimitry Andric                       << StoreMI);
533349cc55cSDimitry Andric     return true;
534349cc55cSDimitry Andric   }
535349cc55cSDimitry Andric 
536349cc55cSDimitry Andric   // Check the store is the same size as the existing ones in the candidate.
537349cc55cSDimitry Andric   if (MRI->getType(C.Stores[0]->getValueReg()).getSizeInBits() !=
538349cc55cSDimitry Andric       ValueTy.getSizeInBits())
539349cc55cSDimitry Andric     return false;
540349cc55cSDimitry Andric 
541349cc55cSDimitry Andric   if (MRI->getType(C.Stores[0]->getPointerReg()).getAddressSpace() !=
542349cc55cSDimitry Andric       PtrTy.getAddressSpace())
543349cc55cSDimitry Andric     return false;
544349cc55cSDimitry Andric 
545349cc55cSDimitry Andric   // There are other stores in the candidate. Check that the store address
546349cc55cSDimitry Andric   // writes to the next lowest adjacent address.
547349cc55cSDimitry Andric   if (C.BasePtr != StoreBase)
548349cc55cSDimitry Andric     return false;
549349cc55cSDimitry Andric   if ((C.CurrentLowestOffset - ValueTy.getSizeInBytes()) !=
550349cc55cSDimitry Andric       static_cast<uint64_t>(StoreOffCst))
551349cc55cSDimitry Andric     return false;
552349cc55cSDimitry Andric 
553349cc55cSDimitry Andric   // This writes to an adjacent address. Allow it.
554349cc55cSDimitry Andric   C.Stores.emplace_back(&StoreMI);
555349cc55cSDimitry Andric   C.CurrentLowestOffset = C.CurrentLowestOffset - ValueTy.getSizeInBytes();
556349cc55cSDimitry Andric   LLVM_DEBUG(dbgs() << "Candidate added store: " << StoreMI);
557349cc55cSDimitry Andric   return true;
558349cc55cSDimitry Andric }
559349cc55cSDimitry Andric 
560349cc55cSDimitry Andric bool LoadStoreOpt::mergeBlockStores(MachineBasicBlock &MBB) {
561349cc55cSDimitry Andric   bool Changed = false;
562349cc55cSDimitry Andric   // Walk through the block bottom-up, looking for merging candidates.
563349cc55cSDimitry Andric   StoreMergeCandidate Candidate;
5640eae32dcSDimitry Andric   for (MachineInstr &MI : llvm::reverse(MBB)) {
565349cc55cSDimitry Andric     if (InstsToErase.contains(&MI))
566349cc55cSDimitry Andric       continue;
567349cc55cSDimitry Andric 
5680eae32dcSDimitry Andric     if (auto *StoreMI = dyn_cast<GStore>(&MI)) {
569349cc55cSDimitry Andric       // We have a G_STORE. Add it to the candidate if it writes to an adjacent
570349cc55cSDimitry Andric       // address.
571349cc55cSDimitry Andric       if (!addStoreToCandidate(*StoreMI, Candidate)) {
572349cc55cSDimitry Andric         // Store wasn't eligible to be added. May need to record it as a
573349cc55cSDimitry Andric         // potential alias.
574349cc55cSDimitry Andric         if (operationAliasesWithCandidate(*StoreMI, Candidate)) {
575349cc55cSDimitry Andric           Changed |= processMergeCandidate(Candidate);
576349cc55cSDimitry Andric           continue;
577349cc55cSDimitry Andric         }
578349cc55cSDimitry Andric         Candidate.addPotentialAlias(*StoreMI);
579349cc55cSDimitry Andric       }
580349cc55cSDimitry Andric       continue;
581349cc55cSDimitry Andric     }
582349cc55cSDimitry Andric 
583349cc55cSDimitry Andric     // If we don't have any stores yet, this instruction can't pose a problem.
584349cc55cSDimitry Andric     if (Candidate.Stores.empty())
585349cc55cSDimitry Andric       continue;
586349cc55cSDimitry Andric 
587349cc55cSDimitry Andric     // We're dealing with some other kind of instruction.
588349cc55cSDimitry Andric     if (isInstHardMergeHazard(MI)) {
589349cc55cSDimitry Andric       Changed |= processMergeCandidate(Candidate);
590349cc55cSDimitry Andric       Candidate.Stores.clear();
591349cc55cSDimitry Andric       continue;
592349cc55cSDimitry Andric     }
593349cc55cSDimitry Andric 
594349cc55cSDimitry Andric     if (!MI.mayLoadOrStore())
595349cc55cSDimitry Andric       continue;
596349cc55cSDimitry Andric 
597349cc55cSDimitry Andric     if (operationAliasesWithCandidate(MI, Candidate)) {
598349cc55cSDimitry Andric       // We have a potential alias, so process the current candidate if we can
599349cc55cSDimitry Andric       // and then continue looking for a new candidate.
600349cc55cSDimitry Andric       Changed |= processMergeCandidate(Candidate);
601349cc55cSDimitry Andric       continue;
602349cc55cSDimitry Andric     }
603349cc55cSDimitry Andric 
604349cc55cSDimitry Andric     // Record this instruction as a potential alias for future stores that are
605349cc55cSDimitry Andric     // added to the candidate.
606349cc55cSDimitry Andric     Candidate.addPotentialAlias(MI);
607349cc55cSDimitry Andric   }
608349cc55cSDimitry Andric 
609349cc55cSDimitry Andric   // Process any candidate left after finishing searching the entire block.
610349cc55cSDimitry Andric   Changed |= processMergeCandidate(Candidate);
611349cc55cSDimitry Andric 
612349cc55cSDimitry Andric   // Erase instructions now that we're no longer iterating over the block.
613349cc55cSDimitry Andric   for (auto *MI : InstsToErase)
614349cc55cSDimitry Andric     MI->eraseFromParent();
615349cc55cSDimitry Andric   InstsToErase.clear();
616349cc55cSDimitry Andric   return Changed;
617349cc55cSDimitry Andric }
618349cc55cSDimitry Andric 
619349cc55cSDimitry Andric bool LoadStoreOpt::mergeFunctionStores(MachineFunction &MF) {
620349cc55cSDimitry Andric   bool Changed = false;
621349cc55cSDimitry Andric   for (auto &BB : MF) {
622349cc55cSDimitry Andric     Changed |= mergeBlockStores(BB);
623349cc55cSDimitry Andric   }
624349cc55cSDimitry Andric   return Changed;
625349cc55cSDimitry Andric }
626349cc55cSDimitry Andric 
627349cc55cSDimitry Andric void LoadStoreOpt::initializeStoreMergeTargetInfo(unsigned AddrSpace) {
628349cc55cSDimitry Andric   // Query the legalizer info to record what store types are legal.
629349cc55cSDimitry Andric   // We record this because we don't want to bother trying to merge stores into
630349cc55cSDimitry Andric   // illegal ones, which would just result in being split again.
631349cc55cSDimitry Andric 
632349cc55cSDimitry Andric   if (LegalStoreSizes.count(AddrSpace)) {
633349cc55cSDimitry Andric     assert(LegalStoreSizes[AddrSpace].any());
634349cc55cSDimitry Andric     return; // Already cached sizes for this address space.
635349cc55cSDimitry Andric   }
636349cc55cSDimitry Andric 
637349cc55cSDimitry Andric   // Need to reserve at least MaxStoreSizeToForm + 1 bits.
638349cc55cSDimitry Andric   BitVector LegalSizes(MaxStoreSizeToForm * 2);
639349cc55cSDimitry Andric   const auto &LI = *MF->getSubtarget().getLegalizerInfo();
640349cc55cSDimitry Andric   const auto &DL = MF->getFunction().getParent()->getDataLayout();
641349cc55cSDimitry Andric   Type *IntPtrIRTy =
642349cc55cSDimitry Andric       DL.getIntPtrType(MF->getFunction().getContext(), AddrSpace);
643349cc55cSDimitry Andric   LLT PtrTy = getLLTForType(*IntPtrIRTy->getPointerTo(AddrSpace), DL);
644349cc55cSDimitry Andric   // We assume that we're not going to be generating any stores wider than
645349cc55cSDimitry Andric   // MaxStoreSizeToForm bits for now.
646349cc55cSDimitry Andric   for (unsigned Size = 2; Size <= MaxStoreSizeToForm; Size *= 2) {
647349cc55cSDimitry Andric     LLT Ty = LLT::scalar(Size);
648349cc55cSDimitry Andric     SmallVector<LegalityQuery::MemDesc, 2> MemDescrs(
649349cc55cSDimitry Andric         {{Ty, Ty.getSizeInBits(), AtomicOrdering::NotAtomic}});
650349cc55cSDimitry Andric     SmallVector<LLT> StoreTys({Ty, PtrTy});
651349cc55cSDimitry Andric     LegalityQuery Q(TargetOpcode::G_STORE, StoreTys, MemDescrs);
652349cc55cSDimitry Andric     LegalizeActionStep ActionStep = LI.getAction(Q);
653349cc55cSDimitry Andric     if (ActionStep.Action == LegalizeActions::Legal)
654349cc55cSDimitry Andric       LegalSizes.set(Size);
655349cc55cSDimitry Andric   }
656349cc55cSDimitry Andric   assert(LegalSizes.any() && "Expected some store sizes to be legal!");
657349cc55cSDimitry Andric   LegalStoreSizes[AddrSpace] = LegalSizes;
658349cc55cSDimitry Andric }
659349cc55cSDimitry Andric 
660349cc55cSDimitry Andric bool LoadStoreOpt::runOnMachineFunction(MachineFunction &MF) {
661349cc55cSDimitry Andric   // If the ISel pipeline failed, do not bother running that pass.
662349cc55cSDimitry Andric   if (MF.getProperties().hasProperty(
663349cc55cSDimitry Andric           MachineFunctionProperties::Property::FailedISel))
664349cc55cSDimitry Andric     return false;
665349cc55cSDimitry Andric 
666349cc55cSDimitry Andric   LLVM_DEBUG(dbgs() << "Begin memory optimizations for: " << MF.getName()
667349cc55cSDimitry Andric                     << '\n');
668349cc55cSDimitry Andric 
669349cc55cSDimitry Andric   init(MF);
670349cc55cSDimitry Andric   bool Changed = false;
671349cc55cSDimitry Andric   Changed |= mergeFunctionStores(MF);
672349cc55cSDimitry Andric 
673349cc55cSDimitry Andric   LegalStoreSizes.clear();
674349cc55cSDimitry Andric   return Changed;
675349cc55cSDimitry Andric }
676