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