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 */ |