//===- MergedLoadStoreMotion.cpp - merge and hoist/sink load/stores -------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // //! \file //! This pass performs merges of loads and stores on both sides of a // diamond (hammock). It hoists the loads and sinks the stores. // // The algorithm iteratively hoists two loads to the same address out of a // diamond (hammock) and merges them into a single load in the header. Similar // it sinks and merges two stores to the tail block (footer). The algorithm // iterates over the instructions of one side of the diamond and attempts to // find a matching load/store on the other side. New tail/footer block may be // insterted if the tail/footer block has more predecessors (not only the two // predecessors that are forming the diamond). It hoists / sinks when it thinks // it safe to do so. This optimization helps with eg. hiding load latencies, // triggering if-conversion, and reducing static code size. // // NOTE: This code no longer performs load hoisting, it is subsumed by GVNHoist. // //===----------------------------------------------------------------------===// // // // Example: // Diamond shaped code before merge: // // header: // br %cond, label %if.then, label %if.else // + + // + + // + + // if.then: if.else: // %lt = load %addr_l %le = load %addr_l // <use %lt> <use %le> // <...> <...> // store %st, %addr_s store %se, %addr_s // br label %if.end br label %if.end // + + // + + // + + // if.end ("footer"): // <...> // // Diamond shaped code after merge: // // header: // %l = load %addr_l // br %cond, label %if.then, label %if.else // + + // + + // + + // if.then: if.else: // <use %l> <use %l> // <...> <...> // br label %if.end br label %if.end // + + // + + // + + // if.end ("footer"): // %s.sink = phi [%st, if.then], [%se, if.else] // <...> // store %s.sink, %addr_s // <...> // // //===----------------------- TODO -----------------------------------------===// // // 1) Generalize to regions other than diamonds // 2) Be more aggressive merging memory operations // Note that both changes require register pressure control // //===----------------------------------------------------------------------===// #include "llvm/Transforms/Scalar/MergedLoadStoreMotion.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/GlobalsModRef.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Instructions.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" usingnamespacellvm; #define DEBUG_TYPE … namespace { //===----------------------------------------------------------------------===// // MergedLoadStoreMotion Pass //===----------------------------------------------------------------------===// class MergedLoadStoreMotion { … }; } // end anonymous namespace /// /// Return tail block of a diamond. /// BasicBlock *MergedLoadStoreMotion::getDiamondTail(BasicBlock *BB) { … } /// /// True when BB is the head of a diamond (hammock) /// bool MergedLoadStoreMotion::isDiamondHead(BasicBlock *BB) { … } /// /// True when instruction is a sink barrier for a store /// located in Loc /// /// Whenever an instruction could possibly read or modify the /// value being stored or protect against the store from /// happening it is considered a sink barrier. /// bool MergedLoadStoreMotion::isStoreSinkBarrierInRange(const Instruction &Start, const Instruction &End, MemoryLocation Loc) { … } /// /// Check if \p BB contains a store to the same address as \p SI /// /// \return The store in \p when it is safe to sink. Otherwise return Null. /// StoreInst *MergedLoadStoreMotion::canSinkFromBlock(BasicBlock *BB1, StoreInst *Store0) { … } /// /// Create a PHI node in BB for the operands of S0 and S1 /// PHINode *MergedLoadStoreMotion::getPHIOperand(BasicBlock *BB, StoreInst *S0, StoreInst *S1) { … } /// /// Check if 2 stores can be sunk, optionally together with corresponding GEPs. /// bool MergedLoadStoreMotion::canSinkStoresAndGEPs(StoreInst *S0, StoreInst *S1) const { … } /// /// Merge two stores to same address and sink into \p BB /// /// Optionally also sinks GEP instruction computing the store address /// void MergedLoadStoreMotion::sinkStoresAndGEPs(BasicBlock *BB, StoreInst *S0, StoreInst *S1) { … } /// /// True when two stores are equivalent and can sink into the footer /// /// Starting from a diamond head block, iterate over the instructions in one /// successor block and try to match a store in the second successor. /// bool MergedLoadStoreMotion::mergeStores(BasicBlock *HeadBB) { … } bool MergedLoadStoreMotion::run(Function &F, AliasAnalysis &AA) { … } PreservedAnalyses MergedLoadStoreMotionPass::run(Function &F, FunctionAnalysisManager &AM) { … } void MergedLoadStoreMotionPass::printPipeline( raw_ostream &OS, function_ref<StringRef(StringRef)> MapClassName2PassName) { … }