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