Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line | 
|---|---|---|---|
| 14 | pmbaty | 1 | //===------ VirtualInstruction.cpp ------------------------------*- 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 | // | ||
| 9 | // Tools for determining which instructions are within a statement and the | ||
| 10 | // nature of their operands. | ||
| 11 | // | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | |||
| 14 | #ifndef POLLY_SUPPORT_VIRTUALINSTRUCTION_H | ||
| 15 | #define POLLY_SUPPORT_VIRTUALINSTRUCTION_H | ||
| 16 | |||
| 17 | #include "polly/ScopInfo.h" | ||
| 18 | |||
| 19 | namespace polly { | ||
| 20 | using llvm::User; | ||
| 21 | |||
| 22 | /// Determine the nature of a value's use within a statement. | ||
| 23 | /// | ||
| 24 | /// These are not always representable by llvm::Use. For instance, scalar write | ||
| 25 | /// MemoryAccesses do use a value, but are not associated with an instruction's | ||
| 26 | /// argument. | ||
| 27 | /// | ||
| 28 | /// Despite its name it is not tied to virtual instructions (although it works | ||
| 29 | /// fine with them), but to promote consistent handling of values used in | ||
| 30 | /// statements. | ||
| 31 | class VirtualUse final { | ||
| 32 | public: | ||
| 33 |   /// The different types of uses. Handling usually differentiates a lot between | ||
| 34 |   /// these; one can use a switch to handle each case (and get warned by the | ||
| 35 |   /// compiler if one is not handled). | ||
| 36 | enum UseKind { | ||
| 37 |     // An llvm::Constant. | ||
| 38 | Constant, | ||
| 39 | |||
| 40 |     // An llvm::BasicBlock. | ||
| 41 | Block, | ||
| 42 | |||
| 43 |     // A value that can be generated using ScopExpander. | ||
| 44 | Synthesizable, | ||
| 45 | |||
| 46 |     // A load that always reads the same value throughout the SCoP (address and | ||
| 47 |     // the value located there a SCoP-invariant) and has been hoisted in front | ||
| 48 |     // of the SCoP. | ||
| 49 | Hoisted, | ||
| 50 | |||
| 51 |     // Definition before the SCoP and not synthesizable. Can be an instruction | ||
| 52 |     // outside the SCoP, a function argument or a global value. Whether there is | ||
| 53 |     // a scalar MemoryAccess in this statement for reading it depends on the | ||
| 54 |     // -polly-analyze-read-only-scalars switch. | ||
| 55 | ReadOnly, | ||
| 56 | |||
| 57 |     // A definition within the same statement. No MemoryAccess between | ||
| 58 |     // definition and use are necessary. | ||
| 59 | Intra, | ||
| 60 | |||
| 61 |     // Definition in another statement. There is a scalar MemoryAccess that | ||
| 62 |     // makes it available in this statement. | ||
| 63 | Inter | ||
| 64 | }; | ||
| 65 | |||
| 66 | private: | ||
| 67 |   /// The statement where a value is used. | ||
| 68 | ScopStmt *User; | ||
| 69 | |||
| 70 |   /// The value that is used. | ||
| 71 | Value *Val; | ||
| 72 | |||
| 73 |   /// The type of value use. | ||
| 74 |   UseKind Kind; | ||
| 75 | |||
| 76 |   /// The value represented as llvm::SCEV expression. | ||
| 77 | const SCEV *ScevExpr; | ||
| 78 | |||
| 79 |   /// If this is an inter-statement (or read-only) use, contains the | ||
| 80 |   /// MemoryAccess that makes the value available in this statement. In case of | ||
| 81 |   /// intra-statement uses, can contain a MemoryKind::Array access. In all other | ||
| 82 |   /// cases, it is a nullptr. | ||
| 83 | MemoryAccess *InputMA; | ||
| 84 | |||
| 85 | VirtualUse(ScopStmt *User, Value *Val, UseKind Kind, const SCEV *ScevExpr, | ||
| 86 | MemoryAccess *InputMA) | ||
| 87 | : User(User), Val(Val), Kind(Kind), ScevExpr(ScevExpr), InputMA(InputMA) { | ||
| 88 |   } | ||
| 89 | |||
| 90 | public: | ||
| 91 |   /// Get a VirtualUse for an llvm::Use. | ||
| 92 |   /// | ||
| 93 |   /// @param S       The Scop object. | ||
| 94 |   /// @param U       The llvm::Use the get information for. | ||
| 95 |   /// @param LI      The LoopInfo analysis. Needed to determine whether the | ||
| 96 |   ///                value is synthesizable. | ||
| 97 |   /// @param Virtual Whether to ignore existing MemoryAccess. | ||
| 98 |   /// | ||
| 99 |   /// @return The VirtualUse representing the same use as @p U. | ||
| 100 | static VirtualUse create(Scop *S, const Use &U, LoopInfo *LI, bool Virtual); | ||
| 101 | |||
| 102 |   /// Get a VirtualUse for uses within statements. | ||
| 103 |   /// | ||
| 104 |   /// It is assumed that the user is not a PHINode. Such uses are always | ||
| 105 |   /// VirtualUse::Inter unless in a regions statement. | ||
| 106 |   /// | ||
| 107 |   /// @param S         The Scop object. | ||
| 108 |   /// @param UserStmt  The statement in which @p Val is used. Can be nullptr, in | ||
| 109 |   ///                  which case it assumed that the statement has been | ||
| 110 |   ///                  removed, which is only possible if no instruction in it | ||
| 111 |   ///                  had side-effects or computes a value used by another | ||
| 112 |   ///                  statement. | ||
| 113 |   /// @param UserScope Loop scope in which the value is used. Needed to | ||
| 114 |   ///                  determine whether the value is synthesizable. | ||
| 115 |   /// @param Val       The value being used. | ||
| 116 |   /// @param Virtual   Whether to use (and prioritize over instruction location) | ||
| 117 |   ///                  information about MemoryAccesses. | ||
| 118 |   /// | ||
| 119 |   /// @return A VirtualUse object that gives information about @p Val's use in | ||
| 120 |   ///         @p UserStmt. | ||
| 121 | static VirtualUse create(Scop *S, ScopStmt *UserStmt, Loop *UserScope, | ||
| 122 | Value *Val, bool Virtual); | ||
| 123 | |||
| 124 | static VirtualUse create(ScopStmt *UserStmt, Loop *UserScope, Value *Val, | ||
| 125 | bool Virtual) { | ||
| 126 | return create(UserStmt->getParent(), UserStmt, UserScope, Val, Virtual); | ||
| 127 |   } | ||
| 128 | |||
| 129 | bool isConstant() const { return Kind == Constant; } | ||
| 130 | bool isBlock() const { return Kind == Block; } | ||
| 131 | bool isSynthesizable() const { return Kind == Synthesizable; } | ||
| 132 | bool isHoisted() const { return Kind == Hoisted; } | ||
| 133 | bool isReadOnly() const { return Kind == ReadOnly; } | ||
| 134 | bool isIntra() const { return Kind == Intra; } | ||
| 135 | bool isInter() const { return Kind == Inter; } | ||
| 136 | |||
| 137 |   /// Return user statement. | ||
| 138 | ScopStmt *getUser() const { return User; } | ||
| 139 | |||
| 140 |   /// Return the used value. | ||
| 141 | llvm::Value *getValue() const { return Val; } | ||
| 142 | |||
| 143 |   /// Return the type of use. | ||
| 144 | UseKind getKind() const { return Kind; } | ||
| 145 | |||
| 146 |   /// Return the ScalarEvolution representation of @p Val. | ||
| 147 | const SCEV *getScevExpr() const { return ScevExpr; } | ||
| 148 | |||
| 149 |   /// Return the MemoryAccess that makes the value available in this statement, | ||
| 150 |   /// if any. | ||
| 151 | MemoryAccess *getMemoryAccess() const { return InputMA; } | ||
| 152 | |||
| 153 |   /// Print a description of this object. | ||
| 154 |   /// | ||
| 155 |   /// @param OS           Stream to print to. | ||
| 156 |   /// @param Reproducible If true, ensures that the output is stable between | ||
| 157 |   ///                     runs and is suitable to check in regression tests. | ||
| 158 |   ///                     This excludes printing e.g. pointer values. If false, | ||
| 159 |   ///                     the output should not be used for regression tests, | ||
| 160 |   ///                     but may contain more information useful in debugger | ||
| 161 |   ///                     sessions. | ||
| 162 | void print(raw_ostream &OS, bool Reproducible = true) const; | ||
| 163 | |||
| 164 | #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) | ||
| 165 | void dump() const; | ||
| 166 | #endif | ||
| 167 | }; | ||
| 168 | |||
| 169 | /// An iterator for virtual operands. | ||
| 170 | class VirtualOperandIterator final { | ||
| 171 | friend class VirtualInstruction; | ||
| 172 | friend class VirtualUse; | ||
| 173 | |||
| 174 | using Self = VirtualOperandIterator; | ||
| 175 | |||
| 176 | ScopStmt *User; | ||
| 177 | User::op_iterator U; | ||
| 178 | |||
| 179 | VirtualOperandIterator(ScopStmt *User, User::op_iterator U) | ||
| 180 | : User(User), U(U) {} | ||
| 181 | |||
| 182 | public: | ||
| 183 | using iterator_category = std::forward_iterator_tag; | ||
| 184 | using value_type = VirtualUse; | ||
| 185 | using difference_type = std::ptrdiff_t; | ||
| 186 | using pointer = value_type *; | ||
| 187 | using reference = value_type &; | ||
| 188 | |||
| 189 | inline bool operator==(const Self &that) const { | ||
| 190 | assert(this->User == that.User); | ||
| 191 | return this->U == that.U; | ||
| 192 |   } | ||
| 193 | |||
| 194 | inline bool operator!=(const Self &that) const { | ||
| 195 | assert(this->User == that.User); | ||
| 196 | return this->U != that.U; | ||
| 197 |   } | ||
| 198 | |||
| 199 | VirtualUse operator*() const { | ||
| 200 | return VirtualUse::create(User, User->getSurroundingLoop(), U->get(), true); | ||
| 201 |   } | ||
| 202 | |||
| 203 | Use *operator->() const { return U; } | ||
| 204 | |||
| 205 | Self &operator++() { | ||
| 206 | U++; | ||
| 207 | return *this; | ||
| 208 |   } | ||
| 209 | |||
| 210 | Self operator++(int) { | ||
| 211 | Self tmp = *this; | ||
| 212 | ++*this; | ||
| 213 | return tmp; | ||
| 214 |   } | ||
| 215 | }; | ||
| 216 | |||
| 217 | /// This class represents a "virtual instruction", an instruction in a ScopStmt, | ||
| 218 | /// effectively a ScopStmt/Instruction-pair. | ||
| 219 | /// | ||
| 220 | /// An instructions can be moved between statements (e.g. to avoid a scalar | ||
| 221 | /// dependency) and even can be contained in multiple statements (for instance, | ||
| 222 | /// to recompute a value instead of transferring it), hence 'virtual'. This | ||
| 223 | /// class is required to represent such instructions that are not in their | ||
| 224 | /// 'physical' location anymore. | ||
| 225 | /// | ||
| 226 | /// A statement can currently not contain the same instructions multiple times | ||
| 227 | /// (that is, from different loop iterations). Therefore, a | ||
| 228 | /// ScopStmt/Instruction-pair uniquely identifies a virtual instructions. | ||
| 229 | /// ScopStmt::getInstruction() can contain the same instruction multiple times, | ||
| 230 | /// but they necessarily compute the same value. | ||
| 231 | class VirtualInstruction final { | ||
| 232 | friend class VirtualOperandIterator; | ||
| 233 | friend struct llvm::DenseMapInfo<VirtualInstruction>; | ||
| 234 | |||
| 235 | private: | ||
| 236 |   /// The statement this virtual instruction is in. | ||
| 237 | ScopStmt *Stmt = nullptr; | ||
| 238 | |||
| 239 |   /// The instruction of a statement. | ||
| 240 | Instruction *Inst = nullptr; | ||
| 241 | |||
| 242 | public: | ||
| 243 | VirtualInstruction() {} | ||
| 244 | |||
| 245 |   /// Create a new virtual instruction of an instruction @p Inst in @p Stmt. | ||
| 246 | VirtualInstruction(ScopStmt *Stmt, Instruction *Inst) | ||
| 247 | : Stmt(Stmt), Inst(Inst) { | ||
| 248 | assert(Stmt && Inst); | ||
| 249 |   } | ||
| 250 | |||
| 251 | VirtualOperandIterator operand_begin() const { | ||
| 252 | return VirtualOperandIterator(Stmt, Inst->op_begin()); | ||
| 253 |   } | ||
| 254 | |||
| 255 | VirtualOperandIterator operand_end() const { | ||
| 256 | return VirtualOperandIterator(Stmt, Inst->op_end()); | ||
| 257 |   } | ||
| 258 | |||
| 259 |   /// Returns a list of virtual operands. | ||
| 260 |   /// | ||
| 261 |   /// Virtual operands, like virtual instructions, need to encode the ScopStmt | ||
| 262 |   /// they are in. | ||
| 263 | llvm::iterator_range<VirtualOperandIterator> operands() const { | ||
| 264 | return {operand_begin(), operand_end()}; | ||
| 265 |   } | ||
| 266 | |||
| 267 |   /// Return the SCoP everything is contained in. | ||
| 268 | Scop *getScop() const { return Stmt->getParent(); } | ||
| 269 | |||
| 270 |   /// Return the ScopStmt this virtual instruction is in. | ||
| 271 | ScopStmt *getStmt() const { return Stmt; } | ||
| 272 | |||
| 273 |   /// Return the instruction in the statement. | ||
| 274 | Instruction *getInstruction() const { return Inst; } | ||
| 275 | |||
| 276 |   /// Print a description of this object. | ||
| 277 |   /// | ||
| 278 |   /// @param OS           Stream to print to. | ||
| 279 |   /// @param Reproducible If true, ensures that the output is stable between | ||
| 280 |   ///                     runs and is suitable for checks in regression tests. | ||
| 281 |   ///                     This excludes printing e.g., pointer values. If false, | ||
| 282 |   ///                     the output should not be used for regression tests, | ||
| 283 |   ///                     but may contain more information useful in debugger | ||
| 284 |   ///                     sessions. | ||
| 285 | void print(raw_ostream &OS, bool Reproducible = true) const; | ||
| 286 | |||
| 287 | #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) | ||
| 288 | void dump() const; | ||
| 289 | #endif | ||
| 290 | }; | ||
| 291 | |||
| 292 | static inline bool operator==(VirtualInstruction LHS, VirtualInstruction RHS) { | ||
| 293 | return LHS.getStmt() == RHS.getStmt() && | ||
| 294 | LHS.getInstruction() == RHS.getInstruction(); | ||
| 295 | } | ||
| 296 | |||
| 297 | /// Find all reachable instructions and accesses. | ||
| 298 | /// | ||
| 299 | /// @param S              The SCoP to find everything reachable in. | ||
| 300 | /// @param LI             LoopInfo required for analysis. | ||
| 301 | /// @param UsedInsts[out] Receives all reachable instructions. | ||
| 302 | /// @param UsedAccs[out]  Receives all reachable accesses. | ||
| 303 | /// @param OnlyLocal      If non-nullptr, activates local mode: The SCoP is | ||
| 304 | ///                       assumed to consist only of this statement and is | ||
| 305 | ///                       conservatively correct. Does not require walking the | ||
| 306 | ///                       whole SCoP. | ||
| 307 | void markReachable(Scop *S, LoopInfo *LI, | ||
| 308 | DenseSet<VirtualInstruction> &UsedInsts, | ||
| 309 | DenseSet<MemoryAccess *> &UsedAccs, | ||
| 310 | ScopStmt *OnlyLocal = nullptr); | ||
| 311 | } // namespace polly | ||
| 312 | |||
| 313 | namespace llvm { | ||
| 314 | /// Support VirtualInstructions in llvm::DenseMaps. | ||
| 315 | template <> struct DenseMapInfo<polly::VirtualInstruction> { | ||
| 316 | public: | ||
| 317 | static bool isEqual(polly::VirtualInstruction LHS, | ||
| 318 | polly::VirtualInstruction RHS) { | ||
| 319 | return DenseMapInfo<polly::ScopStmt *>::isEqual(LHS.getStmt(), | ||
| 320 | RHS.getStmt()) && | ||
| 321 | DenseMapInfo<Instruction *>::isEqual(LHS.getInstruction(), | ||
| 322 | RHS.getInstruction()); | ||
| 323 |   } | ||
| 324 | |||
| 325 | static polly::VirtualInstruction getTombstoneKey() { | ||
| 326 | polly::VirtualInstruction TombstoneKey; | ||
| 327 | TombstoneKey.Stmt = DenseMapInfo<polly::ScopStmt *>::getTombstoneKey(); | ||
| 328 | TombstoneKey.Inst = DenseMapInfo<Instruction *>::getTombstoneKey(); | ||
| 329 | return TombstoneKey; | ||
| 330 |   } | ||
| 331 | |||
| 332 | static polly::VirtualInstruction getEmptyKey() { | ||
| 333 | polly::VirtualInstruction EmptyKey; | ||
| 334 | EmptyKey.Stmt = DenseMapInfo<polly::ScopStmt *>::getEmptyKey(); | ||
| 335 | EmptyKey.Inst = DenseMapInfo<Instruction *>::getEmptyKey(); | ||
| 336 | return EmptyKey; | ||
| 337 |   } | ||
| 338 | |||
| 339 | static unsigned getHashValue(polly::VirtualInstruction Val) { | ||
| 340 | return DenseMapInfo<std::pair<polly::ScopStmt *, Instruction *>>:: | ||
| 341 | getHashValue(std::make_pair(Val.getStmt(), Val.getInstruction())); | ||
| 342 |   } | ||
| 343 | }; | ||
| 344 | } // namespace llvm | ||
| 345 | |||
| 346 | #endif /* POLLY_SUPPORT_VIRTUALINSTRUCTION_H */ |