|
| 1 | +//===- DebugSSAUpdater.h - Debug SSA Update Tool ----------------*- 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 | +// This file declares the DebugSSAUpdater class, which is used to evaluate the |
| 10 | +// live values of debug variables in IR. This uses SSA construction, treating |
| 11 | +// debug value records as definitions, to determine at each point in the program |
| 12 | +// which definition(s) are live at a given point. This is useful for analysis of |
| 13 | +// the state of debug variables, such as measuring the change in values of a |
| 14 | +// variable over time, or calculating coverage stats. |
| 15 | +// |
| 16 | +// NB: This is an expensive analysis that is generally not suitable for use in |
| 17 | +// LLVM passes, but may be useful for standalone tools. |
| 18 | +// |
| 19 | +//===----------------------------------------------------------------------===// |
| 20 | + |
| 21 | +#ifndef LLVM_TRANSFORMS_UTILS_DEBUGSSAUPDATER_H |
| 22 | +#define LLVM_TRANSFORMS_UTILS_DEBUGSSAUPDATER_H |
| 23 | + |
| 24 | +#include "llvm/ADT/SmallVector.h" |
| 25 | +#include "llvm/IR/BasicBlock.h" |
| 26 | +#include "llvm/IR/CFG.h" |
| 27 | +#include "llvm/IR/DebugInfoMetadata.h" |
| 28 | +#include "llvm/IR/DebugProgramInstruction.h" |
| 29 | +#include "llvm/IR/Instruction.h" |
| 30 | +#include "llvm/IR/ValueHandle.h" |
| 31 | +#include "llvm/IR/ValueMap.h" |
| 32 | +#include <cstdint> |
| 33 | + |
| 34 | +namespace llvm { |
| 35 | + |
| 36 | +//////////////////////////////////////// |
| 37 | +// SSAUpdater specialization classes |
| 38 | + |
| 39 | +class DbgSSAPhi; |
| 40 | +template <typename T> class SSAUpdaterTraits; |
| 41 | + |
| 42 | +/// A definition of a variable; can represent either a debug value, no |
| 43 | +/// definition (the variable has not yet been defined), or a phi value*. |
| 44 | +/// *Meaning multiple definitions that are live-in to a block from different |
| 45 | +/// predecessors, not a debug value that uses an IR PHINode. |
| 46 | +struct DbgValueDef { |
| 47 | + DbgSSAPhi *Phi; |
| 48 | + bool IsUndef; |
| 49 | + bool IsMemory; |
| 50 | + Metadata *Locations; |
| 51 | + DIExpression *Expression; |
| 52 | + |
| 53 | + DbgValueDef() |
| 54 | + : Phi(nullptr), IsUndef(true), IsMemory(false), Locations(nullptr), |
| 55 | + Expression(nullptr) {} |
| 56 | + DbgValueDef(int) |
| 57 | + : Phi(nullptr), IsUndef(true), IsMemory(false), Locations(nullptr), |
| 58 | + Expression(nullptr) {} |
| 59 | + DbgValueDef(bool IsMemory, Metadata *Locations, DIExpression *Expression) |
| 60 | + : Phi(nullptr), IsUndef(false), IsMemory(IsMemory), Locations(Locations), |
| 61 | + Expression(Expression) {} |
| 62 | + DbgValueDef(DbgVariableRecord *DVR) : Phi(nullptr) { |
| 63 | + assert(!DVR->isDbgAssign() && "#dbg_assign not yet supported"); |
| 64 | + IsUndef = DVR->isKillLocation(); |
| 65 | + IsMemory = DVR->isAddressOfVariable(); |
| 66 | + Locations = DVR->getRawLocation(); |
| 67 | + Expression = DVR->getExpression(); |
| 68 | + } |
| 69 | + DbgValueDef(DbgSSAPhi *Phi) |
| 70 | + : Phi(Phi), IsUndef(false), IsMemory(false), Locations(nullptr), |
| 71 | + Expression(nullptr) {} |
| 72 | + |
| 73 | + bool agreesWith(DbgValueDef Other) const { |
| 74 | + if (IsUndef && Other.IsUndef) |
| 75 | + return true; |
| 76 | + return std::tie(Phi, IsUndef, IsMemory, Locations, Expression) == |
| 77 | + std::tie(Other.Phi, Other.IsUndef, Other.IsMemory, Other.Locations, |
| 78 | + Other.Expression); |
| 79 | + } |
| 80 | + |
| 81 | + operator bool() const { return !IsUndef; } |
| 82 | + bool operator==(DbgValueDef Other) const { return agreesWith(Other); } |
| 83 | + bool operator!=(DbgValueDef Other) const { return !agreesWith(Other); } |
| 84 | + |
| 85 | + void print(raw_ostream &OS) const; |
| 86 | +}; |
| 87 | + |
| 88 | +class DbgSSABlock; |
| 89 | +class DebugSSAUpdater; |
| 90 | + |
| 91 | +/// Represents the live-in definitions of a variable to a block with multiple |
| 92 | +/// predecessors. |
| 93 | +class DbgSSAPhi { |
| 94 | +public: |
| 95 | + SmallVector<std::pair<DbgSSABlock *, DbgValueDef>, 4> IncomingValues; |
| 96 | + DbgSSABlock *ParentBlock; |
| 97 | + DbgSSAPhi(DbgSSABlock *ParentBlock) : ParentBlock(ParentBlock) {} |
| 98 | + |
| 99 | + DbgSSABlock *getParent() { return ParentBlock; } |
| 100 | + unsigned getNumIncomingValues() const { return IncomingValues.size(); } |
| 101 | + DbgSSABlock *getIncomingBlock(size_t Idx) { |
| 102 | + return IncomingValues[Idx].first; |
| 103 | + } |
| 104 | + DbgValueDef getIncomingValue(size_t Idx) { |
| 105 | + return IncomingValues[Idx].second; |
| 106 | + } |
| 107 | + void addIncoming(DbgSSABlock *BB, DbgValueDef DV) { |
| 108 | + IncomingValues.push_back({BB, DV}); |
| 109 | + } |
| 110 | + |
| 111 | + void print(raw_ostream &OS) const; |
| 112 | +}; |
| 113 | + |
| 114 | +inline raw_ostream &operator<<(raw_ostream &OS, const DbgValueDef &DV) { |
| 115 | + DV.print(OS); |
| 116 | + return OS; |
| 117 | +} |
| 118 | +inline raw_ostream &operator<<(raw_ostream &OS, const DbgSSAPhi &PHI) { |
| 119 | + PHI.print(OS); |
| 120 | + return OS; |
| 121 | +} |
| 122 | + |
| 123 | +/// Thin wrapper around a block successor iterator. |
| 124 | +class DbgSSABlockSuccIterator { |
| 125 | +public: |
| 126 | + succ_iterator SuccIt; |
| 127 | + DebugSSAUpdater &Updater; |
| 128 | + |
| 129 | + DbgSSABlockSuccIterator(succ_iterator SuccIt, DebugSSAUpdater &Updater) |
| 130 | + : SuccIt(SuccIt), Updater(Updater) {} |
| 131 | + |
| 132 | + bool operator!=(const DbgSSABlockSuccIterator &OtherIt) const { |
| 133 | + return OtherIt.SuccIt != SuccIt; |
| 134 | + } |
| 135 | + |
| 136 | + DbgSSABlockSuccIterator &operator++() { |
| 137 | + ++SuccIt; |
| 138 | + return *this; |
| 139 | + } |
| 140 | + |
| 141 | + DbgSSABlock *operator*(); |
| 142 | +}; |
| 143 | + |
| 144 | +/// Thin wrapper around a block successor iterator. |
| 145 | +class DbgSSABlockPredIterator { |
| 146 | +public: |
| 147 | + pred_iterator PredIt; |
| 148 | + DebugSSAUpdater &Updater; |
| 149 | + |
| 150 | + DbgSSABlockPredIterator(pred_iterator PredIt, DebugSSAUpdater &Updater) |
| 151 | + : PredIt(PredIt), Updater(Updater) {} |
| 152 | + |
| 153 | + bool operator!=(const DbgSSABlockPredIterator &OtherIt) const { |
| 154 | + return OtherIt.PredIt != PredIt; |
| 155 | + } |
| 156 | + |
| 157 | + DbgSSABlockPredIterator &operator++() { |
| 158 | + ++PredIt; |
| 159 | + return *this; |
| 160 | + } |
| 161 | + |
| 162 | + DbgSSABlock *operator*(); |
| 163 | +}; |
| 164 | + |
| 165 | +class DbgSSABlock { |
| 166 | +public: |
| 167 | + BasicBlock &BB; |
| 168 | + DebugSSAUpdater &Updater; |
| 169 | + using PHIListT = SmallVector<DbgSSAPhi, 1>; |
| 170 | + /// List of PHIs in this block. There should only ever be one, but this needs |
| 171 | + /// to be a list for the SSAUpdater. |
| 172 | + PHIListT PHIList; |
| 173 | + |
| 174 | + DbgSSABlock(BasicBlock &BB, DebugSSAUpdater &Updater) |
| 175 | + : BB(BB), Updater(Updater) {} |
| 176 | + |
| 177 | + DbgSSABlockPredIterator pred_begin() { |
| 178 | + return DbgSSABlockPredIterator(llvm::pred_begin(&BB), Updater); |
| 179 | + } |
| 180 | + |
| 181 | + DbgSSABlockPredIterator pred_end() { |
| 182 | + return DbgSSABlockPredIterator(llvm::pred_end(&BB), Updater); |
| 183 | + } |
| 184 | + |
| 185 | + iterator_range<DbgSSABlockPredIterator> predecessors() { |
| 186 | + return iterator_range(pred_begin(), pred_end()); |
| 187 | + } |
| 188 | + |
| 189 | + DbgSSABlockSuccIterator succ_begin() { |
| 190 | + return DbgSSABlockSuccIterator(llvm::succ_begin(&BB), Updater); |
| 191 | + } |
| 192 | + |
| 193 | + DbgSSABlockSuccIterator succ_end() { |
| 194 | + return DbgSSABlockSuccIterator(llvm::succ_end(&BB), Updater); |
| 195 | + } |
| 196 | + |
| 197 | + iterator_range<DbgSSABlockSuccIterator> successors() { |
| 198 | + return iterator_range(succ_begin(), succ_end()); |
| 199 | + } |
| 200 | + |
| 201 | + /// SSAUpdater has requested a PHI: create that within this block record. |
| 202 | + DbgSSAPhi *newPHI() { |
| 203 | + assert(PHIList.empty() && |
| 204 | + "Only one PHI should exist per-block per-variable"); |
| 205 | + PHIList.emplace_back(this); |
| 206 | + return &PHIList.back(); |
| 207 | + } |
| 208 | + |
| 209 | + /// SSAUpdater wishes to know what PHIs already exist in this block. |
| 210 | + PHIListT &phis() { return PHIList; } |
| 211 | +}; |
| 212 | + |
| 213 | +/// Class used to determine the live ranges of debug variables in IR using |
| 214 | +/// SSA construction (via the SSAUpdaterImpl class), used for analysis purposes. |
| 215 | +class DebugSSAUpdater { |
| 216 | + friend class SSAUpdaterTraits<DebugSSAUpdater>; |
| 217 | + using AvailableValsTy = DenseMap<DbgSSABlock *, DbgValueDef>; |
| 218 | + |
| 219 | +private: |
| 220 | + /// This keeps track of which value to use on a per-block basis. When we |
| 221 | + /// insert PHI nodes, we keep track of them here. |
| 222 | + AvailableValsTy AV; |
| 223 | + |
| 224 | + /// Pointer to an optionally-passed vector into which, if it is non-null, |
| 225 | + /// the PHIs that describe ambiguous variable locations will be inserted. |
| 226 | + SmallVectorImpl<DbgSSAPhi *> *InsertedPHIs; |
| 227 | + |
| 228 | + DenseMap<BasicBlock *, DbgSSABlock *> BlockMap; |
| 229 | + |
| 230 | +public: |
| 231 | + /// If InsertedPHIs is specified, it will be filled |
| 232 | + /// in with all PHI Nodes created by rewriting. |
| 233 | + explicit DebugSSAUpdater( |
| 234 | + SmallVectorImpl<DbgSSAPhi *> *InsertedPHIs = nullptr); |
| 235 | + DebugSSAUpdater(const DebugSSAUpdater &) = delete; |
| 236 | + DebugSSAUpdater &operator=(const DebugSSAUpdater &) = delete; |
| 237 | + |
| 238 | + void reset() { |
| 239 | + for (auto &Block : BlockMap) |
| 240 | + delete Block.second; |
| 241 | + |
| 242 | + if (InsertedPHIs) |
| 243 | + InsertedPHIs->clear(); |
| 244 | + BlockMap.clear(); |
| 245 | + } |
| 246 | + |
| 247 | + void initialize(); |
| 248 | + |
| 249 | + /// For a given BB, create a wrapper block for it. Stores it in the |
| 250 | + /// DebugSSAUpdater block map. |
| 251 | + DbgSSABlock *getDbgSSABlock(BasicBlock *BB) { |
| 252 | + auto it = BlockMap.find(BB); |
| 253 | + if (it == BlockMap.end()) { |
| 254 | + BlockMap[BB] = new DbgSSABlock(*BB, *this); |
| 255 | + it = BlockMap.find(BB); |
| 256 | + } |
| 257 | + return it->second; |
| 258 | + } |
| 259 | + |
| 260 | + /// Indicate that a rewritten value is available in the specified block |
| 261 | + /// with the specified value. |
| 262 | + void addAvailableValue(DbgSSABlock *BB, DbgValueDef DV); |
| 263 | + |
| 264 | + /// Return true if the DebugSSAUpdater already has a value for the specified |
| 265 | + /// block. |
| 266 | + bool hasValueForBlock(DbgSSABlock *BB) const; |
| 267 | + |
| 268 | + /// Return the value for the specified block if the DebugSSAUpdater has one, |
| 269 | + /// otherwise return nullptr. |
| 270 | + DbgValueDef findValueForBlock(DbgSSABlock *BB) const; |
| 271 | + |
| 272 | + /// Construct SSA form, materializing a value that is live at the end |
| 273 | + /// of the specified block. |
| 274 | + DbgValueDef getValueAtEndOfBlock(DbgSSABlock *BB); |
| 275 | + |
| 276 | + /// Construct SSA form, materializing a value that is live in the |
| 277 | + /// middle of the specified block. |
| 278 | + /// |
| 279 | + /// \c getValueInMiddleOfBlock is the same as \c GetValueAtEndOfBlock except |
| 280 | + /// in one important case: if there is a definition of the rewritten value |
| 281 | + /// after the 'use' in BB. Consider code like this: |
| 282 | + /// |
| 283 | + /// \code |
| 284 | + /// X1 = ... |
| 285 | + /// SomeBB: |
| 286 | + /// use(X) |
| 287 | + /// X2 = ... |
| 288 | + /// br Cond, SomeBB, OutBB |
| 289 | + /// \endcode |
| 290 | + /// |
| 291 | + /// In this case, there are two values (X1 and X2) added to the AvailableVals |
| 292 | + /// set by the client of the rewriter, and those values are both live out of |
| 293 | + /// their respective blocks. However, the use of X happens in the *middle* of |
| 294 | + /// a block. Because of this, we need to insert a new PHI node in SomeBB to |
| 295 | + /// merge the appropriate values, and this value isn't live out of the block. |
| 296 | + DbgValueDef getValueInMiddleOfBlock(DbgSSABlock *BB); |
| 297 | + |
| 298 | +private: |
| 299 | + DbgValueDef getValueAtEndOfBlockInternal(DbgSSABlock *BB); |
| 300 | +}; |
| 301 | + |
| 302 | +struct DbgRangeEntry { |
| 303 | + BasicBlock::iterator Start; |
| 304 | + BasicBlock::iterator End; |
| 305 | + // Should be non-PHI. |
| 306 | + DbgValueDef Value; |
| 307 | +}; |
| 308 | + |
| 309 | +/// Utility class used to store the names of SSA values after their owning |
| 310 | +/// modules have been destroyed. Values are added via \c addValue to receive a |
| 311 | +/// corresponding ID, which can then be used to retrieve the name of the SSA |
| 312 | +/// value via \c getName at any point. Adding the same value multiple times |
| 313 | +/// returns the same ID, making \c addValue idempotent. |
| 314 | +class SSAValueNameMap { |
| 315 | + struct Config : ValueMapConfig<Value *> { |
| 316 | + enum { FollowRAUW = false }; |
| 317 | + }; |
| 318 | + |
| 319 | +public: |
| 320 | + using ValueID = uint64_t; |
| 321 | + ValueID addValue(Value *V); |
| 322 | + std::string getName(ValueID ID) { return ValueIDToNameMap[ID]; } |
| 323 | + |
| 324 | +private: |
| 325 | + DenseMap<ValueID, std::string> ValueIDToNameMap; |
| 326 | + ValueMap<Value *, ValueID, Config> ValueToIDMap; |
| 327 | + ValueID NextID = 0; |
| 328 | +}; |
| 329 | + |
| 330 | +/// Utility class used to find and store the live debug ranges for variables in |
| 331 | +/// a module. This class uses the DebugSSAUpdater for each variable added with |
| 332 | +/// \c addVariable to find either a single-location value, e.g. #dbg_declare, or |
| 333 | +/// a set of live value ranges corresponding to the set of #dbg_value records. |
| 334 | +class DbgValueRangeTable { |
| 335 | + DenseMap<DebugVariableAggregate, SmallVector<DbgRangeEntry>> |
| 336 | + OrigVariableValueRangeTable; |
| 337 | + DenseMap<DebugVariableAggregate, DbgValueDef> OrigSingleLocVariableValueTable; |
| 338 | + |
| 339 | +public: |
| 340 | + void addVariable(Function *F, DebugVariableAggregate DVA); |
| 341 | + bool hasVariableEntry(DebugVariableAggregate DVA) const { |
| 342 | + return OrigVariableValueRangeTable.contains(DVA) || |
| 343 | + OrigSingleLocVariableValueTable.contains(DVA); |
| 344 | + } |
| 345 | + bool hasSingleLocEntry(DebugVariableAggregate DVA) const { |
| 346 | + return OrigSingleLocVariableValueTable.contains(DVA); |
| 347 | + } |
| 348 | + ArrayRef<DbgRangeEntry> getVariableRanges(DebugVariableAggregate DVA) { |
| 349 | + return OrigVariableValueRangeTable[DVA]; |
| 350 | + } |
| 351 | + DbgValueDef getSingleLoc(DebugVariableAggregate DVA) { |
| 352 | + return OrigSingleLocVariableValueTable[DVA]; |
| 353 | + } |
| 354 | + |
| 355 | + void printValues(DebugVariableAggregate DVA, raw_ostream &OS); |
| 356 | +}; |
| 357 | + |
| 358 | +} // end namespace llvm |
| 359 | + |
| 360 | +#endif // LLVM_TRANSFORMS_UTILS_DEBUGSSAUPDATER_H |
0 commit comments