Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line | 
|---|---|---|---|
| 14 | pmbaty | 1 | //===- SROA.h - Scalar Replacement Of Aggregates ----------------*- C++ -*-===// | 
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | /// \file | ||
| 9 | /// This file provides the interface for LLVM's Scalar Replacement of | ||
| 10 | /// Aggregates pass. This pass provides both aggregate splitting and the | ||
| 11 | /// primary SSA formation used in the compiler. | ||
| 12 | /// | ||
| 13 | //===----------------------------------------------------------------------===// | ||
| 14 | |||
| 15 | #ifndef LLVM_TRANSFORMS_SCALAR_SROA_H | ||
| 16 | #define LLVM_TRANSFORMS_SCALAR_SROA_H | ||
| 17 | |||
| 18 | #include "llvm/ADT/MapVector.h" | ||
| 19 | #include "llvm/ADT/PointerIntPair.h" | ||
| 20 | #include "llvm/ADT/SetVector.h" | ||
| 21 | #include "llvm/ADT/SmallVector.h" | ||
| 22 | #include "llvm/IR/PassManager.h" | ||
| 23 | #include "llvm/IR/ValueHandle.h" | ||
| 24 | #include <vector> | ||
| 25 | |||
| 26 | namespace llvm { | ||
| 27 | |||
| 28 | class AllocaInst; | ||
| 29 | class LoadInst; | ||
| 30 | class StoreInst; | ||
| 31 | class AssumptionCache; | ||
| 32 | class DominatorTree; | ||
| 33 | class DomTreeUpdater; | ||
| 34 | class Function; | ||
| 35 | class LLVMContext; | ||
| 36 | class PHINode; | ||
| 37 | class SelectInst; | ||
| 38 | class Use; | ||
| 39 | |||
| 40 | /// A private "module" namespace for types and utilities used by SROA. These | ||
| 41 | /// are implementation details and should not be used by clients. | ||
| 42 | namespace sroa LLVM_LIBRARY_VISIBILITY { | ||
| 43 | |||
| 44 | class AllocaSliceRewriter; | ||
| 45 | class AllocaSlices; | ||
| 46 | class Partition; | ||
| 47 | class SROALegacyPass; | ||
| 48 | |||
| 49 | class SelectHandSpeculativity { | ||
| 50 | unsigned char Storage = 0; // None are speculatable by default. | ||
| 51 | using TrueVal = Bitfield::Element<bool, 0, 1>; // Low 0'th bit. | ||
| 52 | using FalseVal = Bitfield::Element<bool, 1, 1>; // Low 1'th bit. | ||
| 53 | public: | ||
| 54 | SelectHandSpeculativity() = default; | ||
| 55 | SelectHandSpeculativity &setAsSpeculatable(bool isTrueVal); | ||
| 56 | bool isSpeculatable(bool isTrueVal) const; | ||
| 57 | bool areAllSpeculatable() const; | ||
| 58 | bool areAnySpeculatable() const; | ||
| 59 | bool areNoneSpeculatable() const; | ||
| 60 |   // For interop as int half of PointerIntPair. | ||
| 61 | explicit operator intptr_t() const { return static_cast<intptr_t>(Storage); } | ||
| 62 | explicit SelectHandSpeculativity(intptr_t Storage_) : Storage(Storage_) {} | ||
| 63 | }; | ||
| 64 | static_assert(sizeof(SelectHandSpeculativity) == sizeof(unsigned char)); | ||
| 65 | |||
| 66 | using PossiblySpeculatableLoad = | ||
| 67 | PointerIntPair<LoadInst *, 2, sroa::SelectHandSpeculativity>; | ||
| 68 | using UnspeculatableStore = StoreInst *; | ||
| 69 | using RewriteableMemOp = | ||
| 70 | std::variant<PossiblySpeculatableLoad, UnspeculatableStore>; | ||
| 71 | using RewriteableMemOps = SmallVector<RewriteableMemOp, 2>; | ||
| 72 | |||
| 73 | } // end namespace sroa | ||
| 74 | |||
| 75 | enum class SROAOptions : bool { ModifyCFG, PreserveCFG }; | ||
| 76 | |||
| 77 | /// An optimization pass providing Scalar Replacement of Aggregates. | ||
| 78 | /// | ||
| 79 | /// This pass takes allocations which can be completely analyzed (that is, they | ||
| 80 | /// don't escape) and tries to turn them into scalar SSA values. There are | ||
| 81 | /// a few steps to this process. | ||
| 82 | /// | ||
| 83 | /// 1) It takes allocations of aggregates and analyzes the ways in which they | ||
| 84 | ///    are used to try to split them into smaller allocations, ideally of | ||
| 85 | ///    a single scalar data type. It will split up memcpy and memset accesses | ||
| 86 | ///    as necessary and try to isolate individual scalar accesses. | ||
| 87 | /// 2) It will transform accesses into forms which are suitable for SSA value | ||
| 88 | ///    promotion. This can be replacing a memset with a scalar store of an | ||
| 89 | ///    integer value, or it can involve speculating operations on a PHI or | ||
| 90 | ///    select to be a PHI or select of the results. | ||
| 91 | /// 3) Finally, this will try to detect a pattern of accesses which map cleanly | ||
| 92 | ///    onto insert and extract operations on a vector value, and convert them to | ||
| 93 | ///    this form. By doing so, it will enable promotion of vector aggregates to | ||
| 94 | ///    SSA vector values. | ||
| 95 | class SROAPass : public PassInfoMixin<SROAPass> { | ||
| 96 | LLVMContext *C = nullptr; | ||
| 97 | DomTreeUpdater *DTU = nullptr; | ||
| 98 | AssumptionCache *AC = nullptr; | ||
| 99 | const bool PreserveCFG; | ||
| 100 | |||
| 101 |   /// Worklist of alloca instructions to simplify. | ||
| 102 |   /// | ||
| 103 |   /// Each alloca in the function is added to this. Each new alloca formed gets | ||
| 104 |   /// added to it as well to recursively simplify unless that alloca can be | ||
| 105 |   /// directly promoted. Finally, each time we rewrite a use of an alloca other | ||
| 106 |   /// the one being actively rewritten, we add it back onto the list if not | ||
| 107 |   /// already present to ensure it is re-visited. | ||
| 108 | SetVector<AllocaInst *, SmallVector<AllocaInst *, 16>> Worklist; | ||
| 109 | |||
| 110 |   /// A collection of instructions to delete. | ||
| 111 |   /// We try to batch deletions to simplify code and make things a bit more | ||
| 112 |   /// efficient. We also make sure there is no dangling pointers. | ||
| 113 | SmallVector<WeakVH, 8> DeadInsts; | ||
| 114 | |||
| 115 |   /// Post-promotion worklist. | ||
| 116 |   /// | ||
| 117 |   /// Sometimes we discover an alloca which has a high probability of becoming | ||
| 118 |   /// viable for SROA after a round of promotion takes place. In those cases, | ||
| 119 |   /// the alloca is enqueued here for re-processing. | ||
| 120 |   /// | ||
| 121 |   /// Note that we have to be very careful to clear allocas out of this list in | ||
| 122 |   /// the event they are deleted. | ||
| 123 | SetVector<AllocaInst *, SmallVector<AllocaInst *, 16>> PostPromotionWorklist; | ||
| 124 | |||
| 125 |   /// A collection of alloca instructions we can directly promote. | ||
| 126 | std::vector<AllocaInst *> PromotableAllocas; | ||
| 127 | |||
| 128 |   /// A worklist of PHIs to speculate prior to promoting allocas. | ||
| 129 |   /// | ||
| 130 |   /// All of these PHIs have been checked for the safety of speculation and by | ||
| 131 |   /// being speculated will allow promoting allocas currently in the promotable | ||
| 132 |   /// queue. | ||
| 133 | SetVector<PHINode *, SmallVector<PHINode *, 8>> SpeculatablePHIs; | ||
| 134 | |||
| 135 |   /// A worklist of select instructions to rewrite prior to promoting | ||
| 136 |   /// allocas. | ||
| 137 | SmallMapVector<SelectInst *, sroa::RewriteableMemOps, 8> SelectsToRewrite; | ||
| 138 | |||
| 139 |   /// Select instructions that use an alloca and are subsequently loaded can be | ||
| 140 |   /// rewritten to load both input pointers and then select between the result, | ||
| 141 |   /// allowing the load of the alloca to be promoted. | ||
| 142 |   /// From this: | ||
| 143 |   ///   %P2 = select i1 %cond, ptr %Alloca, ptr %Other | ||
| 144 |   ///   %V = load <type>, ptr %P2 | ||
| 145 |   /// to: | ||
| 146 |   ///   %V1 = load <type>, ptr %Alloca      -> will be mem2reg'd | ||
| 147 |   ///   %V2 = load <type>, ptr %Other | ||
| 148 |   ///   %V = select i1 %cond, <type> %V1, <type> %V2 | ||
| 149 |   /// | ||
| 150 |   /// We can do this to a select if its only uses are loads | ||
| 151 |   /// and if either the operand to the select can be loaded unconditionally, | ||
| 152 |   ///        or if we are allowed to perform CFG modifications. | ||
| 153 |   /// If found an intervening bitcast with a single use of the load, | ||
| 154 |   /// allow the promotion. | ||
| 155 | static std::optional<sroa::RewriteableMemOps> | ||
| 156 | isSafeSelectToSpeculate(SelectInst &SI, bool PreserveCFG); | ||
| 157 | |||
| 158 | public: | ||
| 159 |   /// If \p PreserveCFG is set, then the pass is not allowed to modify CFG | ||
| 160 |   /// in any way, even if it would update CFG analyses. | ||
| 161 | SROAPass(SROAOptions PreserveCFG); | ||
| 162 | |||
| 163 |   /// Run the pass over the function. | ||
| 164 | PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); | ||
| 165 | |||
| 166 | void printPipeline(raw_ostream &OS, | ||
| 167 | function_ref<StringRef(StringRef)> MapClassName2PassName); | ||
| 168 | |||
| 169 | private: | ||
| 170 | friend class sroa::AllocaSliceRewriter; | ||
| 171 | friend class sroa::SROALegacyPass; | ||
| 172 | |||
| 173 |   /// Helper used by both the public run method and by the legacy pass. | ||
| 174 | PreservedAnalyses runImpl(Function &F, DomTreeUpdater &RunDTU, | ||
| 175 | AssumptionCache &RunAC); | ||
| 176 | PreservedAnalyses runImpl(Function &F, DominatorTree &RunDT, | ||
| 177 | AssumptionCache &RunAC); | ||
| 178 | |||
| 179 | bool presplitLoadsAndStores(AllocaInst &AI, sroa::AllocaSlices &AS); | ||
| 180 | AllocaInst *rewritePartition(AllocaInst &AI, sroa::AllocaSlices &AS, | ||
| 181 | sroa::Partition &P); | ||
| 182 | bool splitAlloca(AllocaInst &AI, sroa::AllocaSlices &AS); | ||
| 183 | std::pair<bool /*Changed*/, bool /*CFGChanged*/> runOnAlloca(AllocaInst &AI); | ||
| 184 | void clobberUse(Use &U); | ||
| 185 | bool deleteDeadInstructions(SmallPtrSetImpl<AllocaInst *> &DeletedAllocas); | ||
| 186 | bool promoteAllocas(Function &F); | ||
| 187 | }; | ||
| 188 | |||
| 189 | } // end namespace llvm | ||
| 190 | |||
| 191 | #endif // LLVM_TRANSFORMS_SCALAR_SROA_H |