//===- DebugInfo.h - Debug Information Helpers ------------------*- C++ -*-===// // // 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 // //===----------------------------------------------------------------------===// // // This file defines a bunch of datatypes that are useful for creating and // walking debug info in LLVM IR form. They essentially provide wrappers around // the information in the global variables that's needed when constructing the // DWARF information. // //===----------------------------------------------------------------------===// #ifndef LLVM_IR_DEBUGINFO_H #define LLVM_IR_DEBUGINFO_H #include "llvm/ADT/DenseMapInfo.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/TinyPtrVector.h" #include "llvm/ADT/iterator_range.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/PassManager.h" #include <optional> namespace llvm { class DbgDeclareInst; class DbgValueInst; class DbgVariableIntrinsic; class DbgVariableRecord; class Instruction; class Module; /// Finds dbg.declare intrinsics declaring local variables as living in the /// memory that 'V' points to. TinyPtrVector<DbgDeclareInst *> findDbgDeclares(Value *V); /// As above, for DVRDeclares. TinyPtrVector<DbgVariableRecord *> findDVRDeclares(Value *V); /// As above, for DVRValues. TinyPtrVector<DbgVariableRecord *> findDVRValues(Value *V); /// Finds the llvm.dbg.value intrinsics describing a value. void findDbgValues( SmallVectorImpl<DbgValueInst *> &DbgValues, Value *V, SmallVectorImpl<DbgVariableRecord *> *DbgVariableRecords = nullptr); /// Finds the debug info intrinsics describing a value. void findDbgUsers( SmallVectorImpl<DbgVariableIntrinsic *> &DbgInsts, Value *V, SmallVectorImpl<DbgVariableRecord *> *DbgVariableRecords = nullptr); /// Find subprogram that is enclosing this scope. DISubprogram *getDISubprogram(const MDNode *Scope); /// Produce a DebugLoc to use for each dbg.declare that is promoted to a /// dbg.value. DebugLoc getDebugValueLoc(DbgVariableIntrinsic *DII); DebugLoc getDebugValueLoc(DbgVariableRecord *DVR); /// Strip debug info in the module if it exists. /// /// To do this, we remove all calls to the debugger intrinsics and any named /// metadata for debugging. We also remove debug locations for instructions. /// Return true if module is modified. bool StripDebugInfo(Module &M); bool stripDebugInfo(Function &F); /// Downgrade the debug info in a module to contain only line table information. /// /// In order to convert debug info to what -gline-tables-only would have /// created, this does the following: /// 1) Delete all debug intrinsics. /// 2) Delete all non-CU named metadata debug info nodes. /// 3) Create new DebugLocs for each instruction. /// 4) Create a new CU debug info, and similarly for every metadata node /// that's reachable from the CU debug info. /// All debug type metadata nodes are unreachable and garbage collected. bool stripNonLineTableDebugInfo(Module &M); /// Update the debug locations contained within the MD_loop metadata attached /// to the instruction \p I, if one exists. \p Updater is applied to Metadata /// operand in the MD_loop metadata: the returned value is included in the /// updated loop metadata node if it is non-null. void updateLoopMetadataDebugLocations( Instruction &I, function_ref<Metadata *(Metadata *)> Updater); /// Return Debug Info Metadata Version by checking module flags. unsigned getDebugMetadataVersionFromModule(const Module &M); /// Utility to find all debug info in a module. /// /// DebugInfoFinder tries to list all debug info MDNodes used in a module. To /// list debug info MDNodes used by an instruction, DebugInfoFinder uses /// processDeclare, processValue and processLocation to handle DbgDeclareInst, /// DbgValueInst and DbgLoc attached to instructions. processModule will go /// through all DICompileUnits in llvm.dbg.cu and list debug info MDNodes /// used by the CUs. class DebugInfoFinder { … }; /// Assignment Tracking (at). namespace at { // // Utilities for enumerating storing instructions from an assignment ID. // /// A range of instructions. AssignmentInstRange; /// Return a range of instructions (typically just one) that have \p ID /// as an attachment. /// Iterators invalidated by adding or removing DIAssignID metadata to/from any /// instruction (including by deleting or cloning instructions). AssignmentInstRange getAssignmentInsts(DIAssignID *ID); /// Return a range of instructions (typically just one) that perform the /// assignment that \p DAI encodes. /// Iterators invalidated by adding or removing DIAssignID metadata to/from any /// instruction (including by deleting or cloning instructions). inline AssignmentInstRange getAssignmentInsts(const DbgAssignIntrinsic *DAI) { … } inline AssignmentInstRange getAssignmentInsts(const DbgVariableRecord *DVR) { … } // // Utilities for enumerating llvm.dbg.assign intrinsic from an assignment ID. // /// High level: this is an iterator for llvm.dbg.assign intrinsics. /// Implementation details: this is a wrapper around Value's User iterator that /// dereferences to a DbgAssignIntrinsic ptr rather than a User ptr. class DbgAssignIt : public iterator_adaptor_base<DbgAssignIt, Value::user_iterator, typename std::iterator_traits< Value::user_iterator>::iterator_category, DbgAssignIntrinsic *, std::ptrdiff_t, DbgAssignIntrinsic **, DbgAssignIntrinsic *&> { … }; /// A range of llvm.dbg.assign intrinsics. AssignmentMarkerRange; /// Return a range of dbg.assign intrinsics which use \ID as an operand. /// Iterators invalidated by deleting an intrinsic contained in this range. AssignmentMarkerRange getAssignmentMarkers(DIAssignID *ID); /// Return a range of dbg.assign intrinsics for which \p Inst performs the /// assignment they encode. /// Iterators invalidated by deleting an intrinsic contained in this range. inline AssignmentMarkerRange getAssignmentMarkers(const Instruction *Inst) { … } inline SmallVector<DbgVariableRecord *> getDVRAssignmentMarkers(const Instruction *Inst) { … } /// Delete the llvm.dbg.assign intrinsics linked to \p Inst. void deleteAssignmentMarkers(const Instruction *Inst); /// Replace all uses (and attachments) of \p Old with \p New. void RAUW(DIAssignID *Old, DIAssignID *New); /// Remove all Assignment Tracking related intrinsics and metadata from \p F. void deleteAll(Function *F); /// Calculate the fragment of the variable in \p DAI covered /// from (Dest + SliceOffsetInBits) to /// to (Dest + SliceOffsetInBits + SliceSizeInBits) /// /// Return false if it can't be calculated for any reason. /// Result is set to nullopt if the intersect equals the variable fragment (or /// variable size) in DAI. /// /// Result contains a zero-sized fragment if there's no intersect. bool calculateFragmentIntersect( const DataLayout &DL, const Value *Dest, uint64_t SliceOffsetInBits, uint64_t SliceSizeInBits, const DbgAssignIntrinsic *DbgAssign, std::optional<DIExpression::FragmentInfo> &Result); bool calculateFragmentIntersect( const DataLayout &DL, const Value *Dest, uint64_t SliceOffsetInBits, uint64_t SliceSizeInBits, const DbgVariableRecord *DVRAssign, std::optional<DIExpression::FragmentInfo> &Result); /// Replace DIAssignID uses and attachments with IDs from \p Map. /// If an ID is unmapped a new ID is generated and added to \p Map. void remapAssignID(DenseMap<DIAssignID *, DIAssignID *> &Map, Instruction &I); /// Helper struct for trackAssignments, below. We don't use the similar /// DebugVariable class because trackAssignments doesn't (yet?) understand /// partial variables (fragment info) as input and want to make that clear and /// explicit using types. In addition, eventually we will want to understand /// expressions that modify the base address too, which a DebugVariable doesn't /// capture. struct VarRecord { … }; } // namespace at template <> struct DenseMapInfo<at::VarRecord> { … }; namespace at { /// Map of backing storage to a set of variables that are stored to it. /// TODO: Backing storage shouldn't be limited to allocas only. Some local /// variables have their storage allocated by the calling function (addresses /// passed in with sret & byval parameters). StorageToVarsMap; /// Track assignments to \p Vars between \p Start and \p End. void trackAssignments(Function::iterator Start, Function::iterator End, const StorageToVarsMap &Vars, const DataLayout &DL, bool DebugPrints = false); /// Describes properties of a store that has a static size and offset into a /// some base storage. Used by the getAssignmentInfo functions. struct AssignmentInfo { … }; std::optional<AssignmentInfo> getAssignmentInfo(const DataLayout &DL, const MemIntrinsic *I); std::optional<AssignmentInfo> getAssignmentInfo(const DataLayout &DL, const StoreInst *SI); std::optional<AssignmentInfo> getAssignmentInfo(const DataLayout &DL, const AllocaInst *AI); } // end namespace at /// Convert @llvm.dbg.declare intrinsics into sets of @llvm.dbg.assign /// intrinsics by treating stores to the dbg.declare'd address as assignments /// to the variable. Not all kinds of variables are supported yet; those will /// be left with their dbg.declare intrinsics. /// The pass sets the debug-info-assignment-tracking module flag to true to /// indicate assignment tracking has been enabled. class AssignmentTrackingPass : public PassInfoMixin<AssignmentTrackingPass> { … }; /// Return true if assignment tracking is enabled for module \p M. bool isAssignmentTrackingEnabled(const Module &M); } // end namespace llvm #endif // LLVM_IR_DEBUGINFO_H