1297eecfbSDimitry Andric //===-- AssignmentTrackingAnalysis.cpp ------------------------------------===// 2297eecfbSDimitry Andric // 3297eecfbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4297eecfbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5297eecfbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6297eecfbSDimitry Andric // 7297eecfbSDimitry Andric //===----------------------------------------------------------------------===// 8297eecfbSDimitry Andric 9bdd1243dSDimitry Andric #include "llvm/CodeGen/AssignmentTrackingAnalysis.h" 1006c3fb27SDimitry Andric #include "LiveDebugValues/LiveDebugValues.h" 1106c3fb27SDimitry Andric #include "llvm/ADT/BitVector.h" 12bdd1243dSDimitry Andric #include "llvm/ADT/DenseMapInfo.h" 13bdd1243dSDimitry Andric #include "llvm/ADT/IntervalMap.h" 14bdd1243dSDimitry Andric #include "llvm/ADT/PostOrderIterator.h" 15bdd1243dSDimitry Andric #include "llvm/ADT/STLExtras.h" 16bdd1243dSDimitry Andric #include "llvm/ADT/Statistic.h" 17bdd1243dSDimitry Andric #include "llvm/ADT/UniqueVector.h" 18bdd1243dSDimitry Andric #include "llvm/BinaryFormat/Dwarf.h" 19bdd1243dSDimitry Andric #include "llvm/IR/BasicBlock.h" 20bdd1243dSDimitry Andric #include "llvm/IR/DataLayout.h" 21bdd1243dSDimitry Andric #include "llvm/IR/DebugInfo.h" 227a6dacacSDimitry Andric #include "llvm/IR/DebugProgramInstruction.h" 23bdd1243dSDimitry Andric #include "llvm/IR/Function.h" 24bdd1243dSDimitry Andric #include "llvm/IR/Instruction.h" 25bdd1243dSDimitry Andric #include "llvm/IR/IntrinsicInst.h" 26*0fca6ea1SDimitry Andric #include "llvm/IR/Module.h" 27bdd1243dSDimitry Andric #include "llvm/IR/PassManager.h" 28bdd1243dSDimitry Andric #include "llvm/IR/PrintPasses.h" 29bdd1243dSDimitry Andric #include "llvm/InitializePasses.h" 30bdd1243dSDimitry Andric #include "llvm/Support/CommandLine.h" 31bdd1243dSDimitry Andric #include "llvm/Support/ErrorHandling.h" 32bdd1243dSDimitry Andric #include "llvm/Support/raw_ostream.h" 33bdd1243dSDimitry Andric #include "llvm/Transforms/Utils/BasicBlockUtils.h" 34bdd1243dSDimitry Andric #include <assert.h> 35bdd1243dSDimitry Andric #include <cstdint> 36bdd1243dSDimitry Andric #include <optional> 375f757f3fSDimitry Andric #include <queue> 38bdd1243dSDimitry Andric #include <sstream> 39bdd1243dSDimitry Andric #include <unordered_map> 40bdd1243dSDimitry Andric 41bdd1243dSDimitry Andric using namespace llvm; 42bdd1243dSDimitry Andric #define DEBUG_TYPE "debug-ata" 43bdd1243dSDimitry Andric 44bdd1243dSDimitry Andric STATISTIC(NumDefsScanned, "Number of dbg locs that get scanned for removal"); 45bdd1243dSDimitry Andric STATISTIC(NumDefsRemoved, "Number of dbg locs removed"); 46bdd1243dSDimitry Andric STATISTIC(NumWedgesScanned, "Number of dbg wedges scanned"); 47bdd1243dSDimitry Andric STATISTIC(NumWedgesChanged, "Number of dbg wedges changed"); 48bdd1243dSDimitry Andric 49bdd1243dSDimitry Andric static cl::opt<unsigned> 50bdd1243dSDimitry Andric MaxNumBlocks("debug-ata-max-blocks", cl::init(10000), 51bdd1243dSDimitry Andric cl::desc("Maximum num basic blocks before debug info dropped"), 52bdd1243dSDimitry Andric cl::Hidden); 53bdd1243dSDimitry Andric /// Option for debugging the pass, determines if the memory location fragment 54bdd1243dSDimitry Andric /// filling happens after generating the variable locations. 55bdd1243dSDimitry Andric static cl::opt<bool> EnableMemLocFragFill("mem-loc-frag-fill", cl::init(true), 56bdd1243dSDimitry Andric cl::Hidden); 57bdd1243dSDimitry Andric /// Print the results of the analysis. Respects -filter-print-funcs. 58bdd1243dSDimitry Andric static cl::opt<bool> PrintResults("print-debug-ata", cl::init(false), 59bdd1243dSDimitry Andric cl::Hidden); 60bdd1243dSDimitry Andric 6106c3fb27SDimitry Andric /// Coalesce adjacent dbg locs describing memory locations that have contiguous 6206c3fb27SDimitry Andric /// fragments. This reduces the cost of LiveDebugValues which does SSA 6306c3fb27SDimitry Andric /// construction for each explicitly stated variable fragment. 6406c3fb27SDimitry Andric static cl::opt<cl::boolOrDefault> 6506c3fb27SDimitry Andric CoalesceAdjacentFragmentsOpt("debug-ata-coalesce-frags", cl::Hidden); 6606c3fb27SDimitry Andric 67bdd1243dSDimitry Andric // Implicit conversions are disabled for enum class types, so unfortunately we 68bdd1243dSDimitry Andric // need to create a DenseMapInfo wrapper around the specified underlying type. 69bdd1243dSDimitry Andric template <> struct llvm::DenseMapInfo<VariableID> { 70bdd1243dSDimitry Andric using Wrapped = DenseMapInfo<unsigned>; 71bdd1243dSDimitry Andric static inline VariableID getEmptyKey() { 72bdd1243dSDimitry Andric return static_cast<VariableID>(Wrapped::getEmptyKey()); 73bdd1243dSDimitry Andric } 74bdd1243dSDimitry Andric static inline VariableID getTombstoneKey() { 75bdd1243dSDimitry Andric return static_cast<VariableID>(Wrapped::getTombstoneKey()); 76bdd1243dSDimitry Andric } 77bdd1243dSDimitry Andric static unsigned getHashValue(const VariableID &Val) { 78bdd1243dSDimitry Andric return Wrapped::getHashValue(static_cast<unsigned>(Val)); 79bdd1243dSDimitry Andric } 80bdd1243dSDimitry Andric static bool isEqual(const VariableID &LHS, const VariableID &RHS) { 81bdd1243dSDimitry Andric return LHS == RHS; 82bdd1243dSDimitry Andric } 83bdd1243dSDimitry Andric }; 84bdd1243dSDimitry Andric 85*0fca6ea1SDimitry Andric using VarLocInsertPt = PointerUnion<const Instruction *, const DbgRecord *>; 867a6dacacSDimitry Andric 877a6dacacSDimitry Andric namespace std { 887a6dacacSDimitry Andric template <> struct hash<VarLocInsertPt> { 897a6dacacSDimitry Andric using argument_type = VarLocInsertPt; 907a6dacacSDimitry Andric using result_type = std::size_t; 917a6dacacSDimitry Andric 927a6dacacSDimitry Andric result_type operator()(const argument_type &Arg) const { 937a6dacacSDimitry Andric return std::hash<void *>()(Arg.getOpaqueValue()); 947a6dacacSDimitry Andric } 957a6dacacSDimitry Andric }; 967a6dacacSDimitry Andric } // namespace std 977a6dacacSDimitry Andric 98bdd1243dSDimitry Andric /// Helper class to build FunctionVarLocs, since that class isn't easy to 99bdd1243dSDimitry Andric /// modify. TODO: There's not a great deal of value in the split, it could be 100bdd1243dSDimitry Andric /// worth merging the two classes. 101bdd1243dSDimitry Andric class FunctionVarLocsBuilder { 102bdd1243dSDimitry Andric friend FunctionVarLocs; 103bdd1243dSDimitry Andric UniqueVector<DebugVariable> Variables; 104bdd1243dSDimitry Andric // Use an unordered_map so we don't invalidate iterators after 105bdd1243dSDimitry Andric // insert/modifications. 1067a6dacacSDimitry Andric std::unordered_map<VarLocInsertPt, SmallVector<VarLocInfo>> VarLocsBeforeInst; 107bdd1243dSDimitry Andric 108bdd1243dSDimitry Andric SmallVector<VarLocInfo> SingleLocVars; 109bdd1243dSDimitry Andric 110bdd1243dSDimitry Andric public: 11106c3fb27SDimitry Andric unsigned getNumVariables() const { return Variables.size(); } 11206c3fb27SDimitry Andric 113bdd1243dSDimitry Andric /// Find or insert \p V and return the ID. 114bdd1243dSDimitry Andric VariableID insertVariable(DebugVariable V) { 115bdd1243dSDimitry Andric return static_cast<VariableID>(Variables.insert(V)); 116bdd1243dSDimitry Andric } 117bdd1243dSDimitry Andric 118bdd1243dSDimitry Andric /// Get a variable from its \p ID. 119bdd1243dSDimitry Andric const DebugVariable &getVariable(VariableID ID) const { 120bdd1243dSDimitry Andric return Variables[static_cast<unsigned>(ID)]; 121bdd1243dSDimitry Andric } 122bdd1243dSDimitry Andric 123bdd1243dSDimitry Andric /// Return ptr to wedge of defs or nullptr if no defs come just before /p 124bdd1243dSDimitry Andric /// Before. 1257a6dacacSDimitry Andric const SmallVectorImpl<VarLocInfo> *getWedge(VarLocInsertPt Before) const { 126bdd1243dSDimitry Andric auto R = VarLocsBeforeInst.find(Before); 127bdd1243dSDimitry Andric if (R == VarLocsBeforeInst.end()) 128bdd1243dSDimitry Andric return nullptr; 129bdd1243dSDimitry Andric return &R->second; 130bdd1243dSDimitry Andric } 131bdd1243dSDimitry Andric 132bdd1243dSDimitry Andric /// Replace the defs that come just before /p Before with /p Wedge. 1337a6dacacSDimitry Andric void setWedge(VarLocInsertPt Before, SmallVector<VarLocInfo> &&Wedge) { 134bdd1243dSDimitry Andric VarLocsBeforeInst[Before] = std::move(Wedge); 135bdd1243dSDimitry Andric } 136bdd1243dSDimitry Andric 137bdd1243dSDimitry Andric /// Add a def for a variable that is valid for its lifetime. 138bdd1243dSDimitry Andric void addSingleLocVar(DebugVariable Var, DIExpression *Expr, DebugLoc DL, 13906c3fb27SDimitry Andric RawLocationWrapper R) { 140bdd1243dSDimitry Andric VarLocInfo VarLoc; 141bdd1243dSDimitry Andric VarLoc.VariableID = insertVariable(Var); 142bdd1243dSDimitry Andric VarLoc.Expr = Expr; 143bdd1243dSDimitry Andric VarLoc.DL = DL; 14406c3fb27SDimitry Andric VarLoc.Values = R; 145bdd1243dSDimitry Andric SingleLocVars.emplace_back(VarLoc); 146bdd1243dSDimitry Andric } 147bdd1243dSDimitry Andric 148bdd1243dSDimitry Andric /// Add a def to the wedge of defs just before /p Before. 1497a6dacacSDimitry Andric void addVarLoc(VarLocInsertPt Before, DebugVariable Var, DIExpression *Expr, 15006c3fb27SDimitry Andric DebugLoc DL, RawLocationWrapper R) { 151bdd1243dSDimitry Andric VarLocInfo VarLoc; 152bdd1243dSDimitry Andric VarLoc.VariableID = insertVariable(Var); 153bdd1243dSDimitry Andric VarLoc.Expr = Expr; 154bdd1243dSDimitry Andric VarLoc.DL = DL; 15506c3fb27SDimitry Andric VarLoc.Values = R; 156bdd1243dSDimitry Andric VarLocsBeforeInst[Before].emplace_back(VarLoc); 157bdd1243dSDimitry Andric } 158bdd1243dSDimitry Andric }; 159bdd1243dSDimitry Andric 160bdd1243dSDimitry Andric void FunctionVarLocs::print(raw_ostream &OS, const Function &Fn) const { 161bdd1243dSDimitry Andric // Print the variable table first. TODO: Sorting by variable could make the 162bdd1243dSDimitry Andric // output more stable? 163bdd1243dSDimitry Andric unsigned Counter = -1; 164bdd1243dSDimitry Andric OS << "=== Variables ===\n"; 165bdd1243dSDimitry Andric for (const DebugVariable &V : Variables) { 166bdd1243dSDimitry Andric ++Counter; 167bdd1243dSDimitry Andric // Skip first entry because it is a dummy entry. 168bdd1243dSDimitry Andric if (Counter == 0) { 169bdd1243dSDimitry Andric continue; 170bdd1243dSDimitry Andric } 171bdd1243dSDimitry Andric OS << "[" << Counter << "] " << V.getVariable()->getName(); 172bdd1243dSDimitry Andric if (auto F = V.getFragment()) 173bdd1243dSDimitry Andric OS << " bits [" << F->OffsetInBits << ", " 174bdd1243dSDimitry Andric << F->OffsetInBits + F->SizeInBits << ")"; 175bdd1243dSDimitry Andric if (const auto *IA = V.getInlinedAt()) 176bdd1243dSDimitry Andric OS << " inlined-at " << *IA; 177bdd1243dSDimitry Andric OS << "\n"; 178bdd1243dSDimitry Andric } 179bdd1243dSDimitry Andric 180bdd1243dSDimitry Andric auto PrintLoc = [&OS](const VarLocInfo &Loc) { 181bdd1243dSDimitry Andric OS << "DEF Var=[" << (unsigned)Loc.VariableID << "]" 18206c3fb27SDimitry Andric << " Expr=" << *Loc.Expr << " Values=("; 18306c3fb27SDimitry Andric for (auto *Op : Loc.Values.location_ops()) { 18406c3fb27SDimitry Andric errs() << Op->getName() << " "; 18506c3fb27SDimitry Andric } 18606c3fb27SDimitry Andric errs() << ")\n"; 187bdd1243dSDimitry Andric }; 188bdd1243dSDimitry Andric 189bdd1243dSDimitry Andric // Print the single location variables. 190bdd1243dSDimitry Andric OS << "=== Single location vars ===\n"; 191bdd1243dSDimitry Andric for (auto It = single_locs_begin(), End = single_locs_end(); It != End; 192bdd1243dSDimitry Andric ++It) { 193bdd1243dSDimitry Andric PrintLoc(*It); 194bdd1243dSDimitry Andric } 195bdd1243dSDimitry Andric 196bdd1243dSDimitry Andric // Print the non-single-location defs in line with IR. 197bdd1243dSDimitry Andric OS << "=== In-line variable defs ==="; 198bdd1243dSDimitry Andric for (const BasicBlock &BB : Fn) { 199bdd1243dSDimitry Andric OS << "\n" << BB.getName() << ":\n"; 200bdd1243dSDimitry Andric for (const Instruction &I : BB) { 201bdd1243dSDimitry Andric for (auto It = locs_begin(&I), End = locs_end(&I); It != End; ++It) { 202bdd1243dSDimitry Andric PrintLoc(*It); 203bdd1243dSDimitry Andric } 204bdd1243dSDimitry Andric OS << I << "\n"; 205bdd1243dSDimitry Andric } 206bdd1243dSDimitry Andric } 207bdd1243dSDimitry Andric } 208bdd1243dSDimitry Andric 209bdd1243dSDimitry Andric void FunctionVarLocs::init(FunctionVarLocsBuilder &Builder) { 210bdd1243dSDimitry Andric // Add the single-location variables first. 211bdd1243dSDimitry Andric for (const auto &VarLoc : Builder.SingleLocVars) 212bdd1243dSDimitry Andric VarLocRecords.emplace_back(VarLoc); 213bdd1243dSDimitry Andric // Mark the end of the section. 214bdd1243dSDimitry Andric SingleVarLocEnd = VarLocRecords.size(); 215bdd1243dSDimitry Andric 216bdd1243dSDimitry Andric // Insert a contiguous block of VarLocInfos for each instruction, mapping it 2177a6dacacSDimitry Andric // to the start and end position in the vector with VarLocsBeforeInst. This 218*0fca6ea1SDimitry Andric // block includes VarLocs for any DbgVariableRecords attached to that 219*0fca6ea1SDimitry Andric // instruction. 220bdd1243dSDimitry Andric for (auto &P : Builder.VarLocsBeforeInst) { 221*0fca6ea1SDimitry Andric // Process VarLocs attached to a DbgRecord alongside their marker 222*0fca6ea1SDimitry Andric // Instruction. 223*0fca6ea1SDimitry Andric if (isa<const DbgRecord *>(P.first)) 2247a6dacacSDimitry Andric continue; 2257a6dacacSDimitry Andric const Instruction *I = cast<const Instruction *>(P.first); 226bdd1243dSDimitry Andric unsigned BlockStart = VarLocRecords.size(); 227*0fca6ea1SDimitry Andric // Any VarLocInfos attached to a DbgRecord should now be remapped to their 228*0fca6ea1SDimitry Andric // marker Instruction, in order of DbgRecord appearance and prior to any 2297a6dacacSDimitry Andric // VarLocInfos attached directly to that instruction. 230*0fca6ea1SDimitry Andric for (const DbgVariableRecord &DVR : filterDbgVars(I->getDbgRecordRange())) { 231*0fca6ea1SDimitry Andric // Even though DVR defines a variable location, VarLocsBeforeInst can 2327a6dacacSDimitry Andric // still be empty if that VarLoc was redundant. 233*0fca6ea1SDimitry Andric if (!Builder.VarLocsBeforeInst.count(&DVR)) 2347a6dacacSDimitry Andric continue; 235*0fca6ea1SDimitry Andric for (const VarLocInfo &VarLoc : Builder.VarLocsBeforeInst[&DVR]) 2367a6dacacSDimitry Andric VarLocRecords.emplace_back(VarLoc); 2377a6dacacSDimitry Andric } 238bdd1243dSDimitry Andric for (const VarLocInfo &VarLoc : P.second) 239bdd1243dSDimitry Andric VarLocRecords.emplace_back(VarLoc); 240bdd1243dSDimitry Andric unsigned BlockEnd = VarLocRecords.size(); 241bdd1243dSDimitry Andric // Record the start and end indices. 242bdd1243dSDimitry Andric if (BlockEnd != BlockStart) 2437a6dacacSDimitry Andric VarLocsBeforeInst[I] = {BlockStart, BlockEnd}; 244bdd1243dSDimitry Andric } 245bdd1243dSDimitry Andric 246bdd1243dSDimitry Andric // Copy the Variables vector from the builder's UniqueVector. 247bdd1243dSDimitry Andric assert(Variables.empty() && "Expect clear before init"); 248bdd1243dSDimitry Andric // UniqueVectors IDs are one-based (which means the VarLocInfo VarID values 249bdd1243dSDimitry Andric // are one-based) so reserve an extra and insert a dummy. 250bdd1243dSDimitry Andric Variables.reserve(Builder.Variables.size() + 1); 251bdd1243dSDimitry Andric Variables.push_back(DebugVariable(nullptr, std::nullopt, nullptr)); 252bdd1243dSDimitry Andric Variables.append(Builder.Variables.begin(), Builder.Variables.end()); 253bdd1243dSDimitry Andric } 254bdd1243dSDimitry Andric 255bdd1243dSDimitry Andric void FunctionVarLocs::clear() { 256bdd1243dSDimitry Andric Variables.clear(); 257bdd1243dSDimitry Andric VarLocRecords.clear(); 258bdd1243dSDimitry Andric VarLocsBeforeInst.clear(); 259bdd1243dSDimitry Andric SingleVarLocEnd = 0; 260bdd1243dSDimitry Andric } 261bdd1243dSDimitry Andric 262bdd1243dSDimitry Andric /// Walk backwards along constant GEPs and bitcasts to the base storage from \p 263bdd1243dSDimitry Andric /// Start as far as possible. Prepend \Expression with the offset and append it 264bdd1243dSDimitry Andric /// with a DW_OP_deref that haes been implicit until now. Returns the walked-to 265bdd1243dSDimitry Andric /// value and modified expression. 266bdd1243dSDimitry Andric static std::pair<Value *, DIExpression *> 267bdd1243dSDimitry Andric walkToAllocaAndPrependOffsetDeref(const DataLayout &DL, Value *Start, 268bdd1243dSDimitry Andric DIExpression *Expression) { 269bdd1243dSDimitry Andric APInt OffsetInBytes(DL.getTypeSizeInBits(Start->getType()), false); 270bdd1243dSDimitry Andric Value *End = 271bdd1243dSDimitry Andric Start->stripAndAccumulateInBoundsConstantOffsets(DL, OffsetInBytes); 272bdd1243dSDimitry Andric SmallVector<uint64_t, 3> Ops; 273bdd1243dSDimitry Andric if (OffsetInBytes.getBoolValue()) { 274bdd1243dSDimitry Andric Ops = {dwarf::DW_OP_plus_uconst, OffsetInBytes.getZExtValue()}; 275bdd1243dSDimitry Andric Expression = DIExpression::prependOpcodes( 276bdd1243dSDimitry Andric Expression, Ops, /*StackValue=*/false, /*EntryValue=*/false); 277bdd1243dSDimitry Andric } 278bdd1243dSDimitry Andric Expression = DIExpression::append(Expression, {dwarf::DW_OP_deref}); 279bdd1243dSDimitry Andric return {End, Expression}; 280bdd1243dSDimitry Andric } 281bdd1243dSDimitry Andric 282bdd1243dSDimitry Andric /// Extract the offset used in \p DIExpr. Returns std::nullopt if the expression 283bdd1243dSDimitry Andric /// doesn't explicitly describe a memory location with DW_OP_deref or if the 284bdd1243dSDimitry Andric /// expression is too complex to interpret. 285bdd1243dSDimitry Andric static std::optional<int64_t> 286bdd1243dSDimitry Andric getDerefOffsetInBytes(const DIExpression *DIExpr) { 287bdd1243dSDimitry Andric int64_t Offset = 0; 288bdd1243dSDimitry Andric const unsigned NumElements = DIExpr->getNumElements(); 289bdd1243dSDimitry Andric const auto Elements = DIExpr->getElements(); 29006c3fb27SDimitry Andric unsigned ExpectedDerefIdx = 0; 291bdd1243dSDimitry Andric // Extract the offset. 292bdd1243dSDimitry Andric if (NumElements > 2 && Elements[0] == dwarf::DW_OP_plus_uconst) { 293bdd1243dSDimitry Andric Offset = Elements[1]; 29406c3fb27SDimitry Andric ExpectedDerefIdx = 2; 295bdd1243dSDimitry Andric } else if (NumElements > 3 && Elements[0] == dwarf::DW_OP_constu) { 29606c3fb27SDimitry Andric ExpectedDerefIdx = 3; 297bdd1243dSDimitry Andric if (Elements[2] == dwarf::DW_OP_plus) 298bdd1243dSDimitry Andric Offset = Elements[1]; 299bdd1243dSDimitry Andric else if (Elements[2] == dwarf::DW_OP_minus) 300bdd1243dSDimitry Andric Offset = -Elements[1]; 301bdd1243dSDimitry Andric else 302bdd1243dSDimitry Andric return std::nullopt; 303bdd1243dSDimitry Andric } 304bdd1243dSDimitry Andric 305bdd1243dSDimitry Andric // If that's all there is it means there's no deref. 30606c3fb27SDimitry Andric if (ExpectedDerefIdx >= NumElements) 307bdd1243dSDimitry Andric return std::nullopt; 308bdd1243dSDimitry Andric 309bdd1243dSDimitry Andric // Check the next element is DW_OP_deref - otherwise this is too complex or 310bdd1243dSDimitry Andric // isn't a deref expression. 31106c3fb27SDimitry Andric if (Elements[ExpectedDerefIdx] != dwarf::DW_OP_deref) 312bdd1243dSDimitry Andric return std::nullopt; 313bdd1243dSDimitry Andric 314bdd1243dSDimitry Andric // Check the final operation is either the DW_OP_deref or is a fragment. 31506c3fb27SDimitry Andric if (NumElements == ExpectedDerefIdx + 1) 316bdd1243dSDimitry Andric return Offset; // Ends with deref. 31706c3fb27SDimitry Andric unsigned ExpectedFragFirstIdx = ExpectedDerefIdx + 1; 31806c3fb27SDimitry Andric unsigned ExpectedFragFinalIdx = ExpectedFragFirstIdx + 2; 31906c3fb27SDimitry Andric if (NumElements == ExpectedFragFinalIdx + 1 && 32006c3fb27SDimitry Andric Elements[ExpectedFragFirstIdx] == dwarf::DW_OP_LLVM_fragment) 321bdd1243dSDimitry Andric return Offset; // Ends with deref + fragment. 322bdd1243dSDimitry Andric 323bdd1243dSDimitry Andric // Don't bother trying to interpret anything more complex. 324bdd1243dSDimitry Andric return std::nullopt; 325bdd1243dSDimitry Andric } 326bdd1243dSDimitry Andric 327bdd1243dSDimitry Andric /// A whole (unfragmented) source variable. 328bdd1243dSDimitry Andric using DebugAggregate = std::pair<const DILocalVariable *, const DILocation *>; 329bdd1243dSDimitry Andric static DebugAggregate getAggregate(const DbgVariableIntrinsic *DII) { 330bdd1243dSDimitry Andric return DebugAggregate(DII->getVariable(), DII->getDebugLoc().getInlinedAt()); 331bdd1243dSDimitry Andric } 332bdd1243dSDimitry Andric static DebugAggregate getAggregate(const DebugVariable &Var) { 333bdd1243dSDimitry Andric return DebugAggregate(Var.getVariable(), Var.getInlinedAt()); 334bdd1243dSDimitry Andric } 335bdd1243dSDimitry Andric 33606c3fb27SDimitry Andric static bool shouldCoalesceFragments(Function &F) { 33706c3fb27SDimitry Andric // Enabling fragment coalescing reduces compiler run time when instruction 33806c3fb27SDimitry Andric // referencing is enabled. However, it may cause LiveDebugVariables to create 33906c3fb27SDimitry Andric // incorrect locations. Since instruction-referencing mode effectively 34006c3fb27SDimitry Andric // bypasses LiveDebugVariables we only enable coalescing if the cl::opt flag 34106c3fb27SDimitry Andric // has not been explicitly set and instruction-referencing is turned on. 34206c3fb27SDimitry Andric switch (CoalesceAdjacentFragmentsOpt) { 34306c3fb27SDimitry Andric case cl::boolOrDefault::BOU_UNSET: 34406c3fb27SDimitry Andric return debuginfoShouldUseDebugInstrRef( 34506c3fb27SDimitry Andric Triple(F.getParent()->getTargetTriple())); 34606c3fb27SDimitry Andric case cl::boolOrDefault::BOU_TRUE: 34706c3fb27SDimitry Andric return true; 34806c3fb27SDimitry Andric case cl::boolOrDefault::BOU_FALSE: 34906c3fb27SDimitry Andric return false; 35006c3fb27SDimitry Andric } 35106c3fb27SDimitry Andric llvm_unreachable("Unknown boolOrDefault value"); 35206c3fb27SDimitry Andric } 35306c3fb27SDimitry Andric 354bdd1243dSDimitry Andric namespace { 355bdd1243dSDimitry Andric /// In dwarf emission, the following sequence 356bdd1243dSDimitry Andric /// 1. dbg.value ... Fragment(0, 64) 357bdd1243dSDimitry Andric /// 2. dbg.value ... Fragment(0, 32) 358bdd1243dSDimitry Andric /// effectively sets Fragment(32, 32) to undef (each def sets all bits not in 359bdd1243dSDimitry Andric /// the intersection of the fragments to having "no location"). This makes 360bdd1243dSDimitry Andric /// sense for implicit location values because splitting the computed values 361bdd1243dSDimitry Andric /// could be troublesome, and is probably quite uncommon. When we convert 362bdd1243dSDimitry Andric /// dbg.assigns to dbg.value+deref this kind of thing is common, and describing 363bdd1243dSDimitry Andric /// a location (memory) rather than a value means we don't need to worry about 364bdd1243dSDimitry Andric /// splitting any values, so we try to recover the rest of the fragment 365bdd1243dSDimitry Andric /// location here. 366bdd1243dSDimitry Andric /// This class performs a(nother) dataflow analysis over the function, adding 367bdd1243dSDimitry Andric /// variable locations so that any bits of a variable with a memory location 368bdd1243dSDimitry Andric /// have that location explicitly reinstated at each subsequent variable 369bdd1243dSDimitry Andric /// location definition that that doesn't overwrite those bits. i.e. after a 370bdd1243dSDimitry Andric /// variable location def, insert new defs for the memory location with 371bdd1243dSDimitry Andric /// fragments for the difference of "all bits currently in memory" and "the 372bdd1243dSDimitry Andric /// fragment of the second def". 373bdd1243dSDimitry Andric class MemLocFragmentFill { 374bdd1243dSDimitry Andric Function &Fn; 375bdd1243dSDimitry Andric FunctionVarLocsBuilder *FnVarLocs; 376bdd1243dSDimitry Andric const DenseSet<DebugAggregate> *VarsWithStackSlot; 37706c3fb27SDimitry Andric bool CoalesceAdjacentFragments; 378bdd1243dSDimitry Andric 379bdd1243dSDimitry Andric // 0 = no memory location. 380bdd1243dSDimitry Andric using BaseAddress = unsigned; 381bdd1243dSDimitry Andric using OffsetInBitsTy = unsigned; 382bdd1243dSDimitry Andric using FragTraits = IntervalMapHalfOpenInfo<OffsetInBitsTy>; 383bdd1243dSDimitry Andric using FragsInMemMap = IntervalMap< 384bdd1243dSDimitry Andric OffsetInBitsTy, BaseAddress, 385bdd1243dSDimitry Andric IntervalMapImpl::NodeSizer<OffsetInBitsTy, BaseAddress>::LeafSize, 386bdd1243dSDimitry Andric FragTraits>; 387bdd1243dSDimitry Andric FragsInMemMap::Allocator IntervalMapAlloc; 388bdd1243dSDimitry Andric using VarFragMap = DenseMap<unsigned, FragsInMemMap>; 389bdd1243dSDimitry Andric 390bdd1243dSDimitry Andric /// IDs for memory location base addresses in maps. Use 0 to indicate that 391bdd1243dSDimitry Andric /// there's no memory location. 39206c3fb27SDimitry Andric UniqueVector<RawLocationWrapper> Bases; 393bdd1243dSDimitry Andric UniqueVector<DebugAggregate> Aggregates; 394bdd1243dSDimitry Andric DenseMap<const BasicBlock *, VarFragMap> LiveIn; 395bdd1243dSDimitry Andric DenseMap<const BasicBlock *, VarFragMap> LiveOut; 396bdd1243dSDimitry Andric 397bdd1243dSDimitry Andric struct FragMemLoc { 398bdd1243dSDimitry Andric unsigned Var; 399bdd1243dSDimitry Andric unsigned Base; 400bdd1243dSDimitry Andric unsigned OffsetInBits; 401bdd1243dSDimitry Andric unsigned SizeInBits; 402bdd1243dSDimitry Andric DebugLoc DL; 403bdd1243dSDimitry Andric }; 4047a6dacacSDimitry Andric using InsertMap = MapVector<VarLocInsertPt, SmallVector<FragMemLoc>>; 405bdd1243dSDimitry Andric 406bdd1243dSDimitry Andric /// BBInsertBeforeMap holds a description for the set of location defs to be 407bdd1243dSDimitry Andric /// inserted after the analysis is complete. It is updated during the dataflow 408bdd1243dSDimitry Andric /// and the entry for a block is CLEARED each time it is (re-)visited. After 409bdd1243dSDimitry Andric /// the dataflow is complete, each block entry will contain the set of defs 410bdd1243dSDimitry Andric /// calculated during the final (fixed-point) iteration. 411bdd1243dSDimitry Andric DenseMap<const BasicBlock *, InsertMap> BBInsertBeforeMap; 412bdd1243dSDimitry Andric 413bdd1243dSDimitry Andric static bool intervalMapsAreEqual(const FragsInMemMap &A, 414bdd1243dSDimitry Andric const FragsInMemMap &B) { 415bdd1243dSDimitry Andric auto AIt = A.begin(), AEnd = A.end(); 416bdd1243dSDimitry Andric auto BIt = B.begin(), BEnd = B.end(); 417bdd1243dSDimitry Andric for (; AIt != AEnd; ++AIt, ++BIt) { 418bdd1243dSDimitry Andric if (BIt == BEnd) 419bdd1243dSDimitry Andric return false; // B has fewer elements than A. 420bdd1243dSDimitry Andric if (AIt.start() != BIt.start() || AIt.stop() != BIt.stop()) 421bdd1243dSDimitry Andric return false; // Interval is different. 422bdd1243dSDimitry Andric if (*AIt != *BIt) 423bdd1243dSDimitry Andric return false; // Value at interval is different. 424bdd1243dSDimitry Andric } 425bdd1243dSDimitry Andric // AIt == AEnd. Check BIt is also now at end. 426bdd1243dSDimitry Andric return BIt == BEnd; 427bdd1243dSDimitry Andric } 428bdd1243dSDimitry Andric 429bdd1243dSDimitry Andric static bool varFragMapsAreEqual(const VarFragMap &A, const VarFragMap &B) { 430bdd1243dSDimitry Andric if (A.size() != B.size()) 431bdd1243dSDimitry Andric return false; 432bdd1243dSDimitry Andric for (const auto &APair : A) { 433bdd1243dSDimitry Andric auto BIt = B.find(APair.first); 434bdd1243dSDimitry Andric if (BIt == B.end()) 435bdd1243dSDimitry Andric return false; 436bdd1243dSDimitry Andric if (!intervalMapsAreEqual(APair.second, BIt->second)) 437bdd1243dSDimitry Andric return false; 438bdd1243dSDimitry Andric } 439bdd1243dSDimitry Andric return true; 440bdd1243dSDimitry Andric } 441bdd1243dSDimitry Andric 442bdd1243dSDimitry Andric /// Return a string for the value that \p BaseID represents. 443bdd1243dSDimitry Andric std::string toString(unsigned BaseID) { 444bdd1243dSDimitry Andric if (BaseID) 44506c3fb27SDimitry Andric return Bases[BaseID].getVariableLocationOp(0)->getName().str(); 446bdd1243dSDimitry Andric else 447bdd1243dSDimitry Andric return "None"; 448bdd1243dSDimitry Andric } 449bdd1243dSDimitry Andric 450bdd1243dSDimitry Andric /// Format string describing an FragsInMemMap (IntervalMap) interval. 451bdd1243dSDimitry Andric std::string toString(FragsInMemMap::const_iterator It, bool Newline = true) { 452bdd1243dSDimitry Andric std::string String; 453bdd1243dSDimitry Andric std::stringstream S(String); 454bdd1243dSDimitry Andric if (It.valid()) { 455bdd1243dSDimitry Andric S << "[" << It.start() << ", " << It.stop() 456bdd1243dSDimitry Andric << "): " << toString(It.value()); 457bdd1243dSDimitry Andric } else { 458bdd1243dSDimitry Andric S << "invalid iterator (end)"; 459bdd1243dSDimitry Andric } 460bdd1243dSDimitry Andric if (Newline) 461bdd1243dSDimitry Andric S << "\n"; 462bdd1243dSDimitry Andric return S.str(); 463bdd1243dSDimitry Andric }; 464bdd1243dSDimitry Andric 465bdd1243dSDimitry Andric FragsInMemMap meetFragments(const FragsInMemMap &A, const FragsInMemMap &B) { 466bdd1243dSDimitry Andric FragsInMemMap Result(IntervalMapAlloc); 467bdd1243dSDimitry Andric for (auto AIt = A.begin(), AEnd = A.end(); AIt != AEnd; ++AIt) { 468bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "a " << toString(AIt)); 469bdd1243dSDimitry Andric // This is basically copied from process() and inverted (process is 470bdd1243dSDimitry Andric // performing something like a union whereas this is more of an 471bdd1243dSDimitry Andric // intersect). 472bdd1243dSDimitry Andric 473bdd1243dSDimitry Andric // There's no work to do if interval `a` overlaps no fragments in map `B`. 474bdd1243dSDimitry Andric if (!B.overlaps(AIt.start(), AIt.stop())) 475bdd1243dSDimitry Andric continue; 476bdd1243dSDimitry Andric 477bdd1243dSDimitry Andric // Does StartBit intersect an existing fragment? 478bdd1243dSDimitry Andric auto FirstOverlap = B.find(AIt.start()); 479bdd1243dSDimitry Andric assert(FirstOverlap != B.end()); 480bdd1243dSDimitry Andric bool IntersectStart = FirstOverlap.start() < AIt.start(); 481bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "- FirstOverlap " << toString(FirstOverlap, false) 482bdd1243dSDimitry Andric << ", IntersectStart: " << IntersectStart << "\n"); 483bdd1243dSDimitry Andric 484bdd1243dSDimitry Andric // Does EndBit intersect an existing fragment? 485bdd1243dSDimitry Andric auto LastOverlap = B.find(AIt.stop()); 486bdd1243dSDimitry Andric bool IntersectEnd = 487bdd1243dSDimitry Andric LastOverlap != B.end() && LastOverlap.start() < AIt.stop(); 488bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "- LastOverlap " << toString(LastOverlap, false) 489bdd1243dSDimitry Andric << ", IntersectEnd: " << IntersectEnd << "\n"); 490bdd1243dSDimitry Andric 491bdd1243dSDimitry Andric // Check if both ends of `a` intersect the same interval `b`. 492bdd1243dSDimitry Andric if (IntersectStart && IntersectEnd && FirstOverlap == LastOverlap) { 493bdd1243dSDimitry Andric // Insert `a` (`a` is contained in `b`) if the values match. 494bdd1243dSDimitry Andric // [ a ] 495bdd1243dSDimitry Andric // [ - b - ] 496bdd1243dSDimitry Andric // - 497bdd1243dSDimitry Andric // [ r ] 498bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "- a is contained within " 499bdd1243dSDimitry Andric << toString(FirstOverlap)); 500bdd1243dSDimitry Andric if (*AIt && *AIt == *FirstOverlap) 501bdd1243dSDimitry Andric Result.insert(AIt.start(), AIt.stop(), *AIt); 502bdd1243dSDimitry Andric } else { 503bdd1243dSDimitry Andric // There's an overlap but `a` is not fully contained within 504bdd1243dSDimitry Andric // `b`. Shorten any end-point intersections. 505bdd1243dSDimitry Andric // [ - a - ] 506bdd1243dSDimitry Andric // [ - b - ] 507bdd1243dSDimitry Andric // - 508bdd1243dSDimitry Andric // [ r ] 509bdd1243dSDimitry Andric auto Next = FirstOverlap; 510bdd1243dSDimitry Andric if (IntersectStart) { 511bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "- insert intersection of a and " 512bdd1243dSDimitry Andric << toString(FirstOverlap)); 513bdd1243dSDimitry Andric if (*AIt && *AIt == *FirstOverlap) 514bdd1243dSDimitry Andric Result.insert(AIt.start(), FirstOverlap.stop(), *AIt); 515bdd1243dSDimitry Andric ++Next; 516bdd1243dSDimitry Andric } 517bdd1243dSDimitry Andric // [ - a - ] 518bdd1243dSDimitry Andric // [ - b - ] 519bdd1243dSDimitry Andric // - 520bdd1243dSDimitry Andric // [ r ] 521bdd1243dSDimitry Andric if (IntersectEnd) { 522bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "- insert intersection of a and " 523bdd1243dSDimitry Andric << toString(LastOverlap)); 524bdd1243dSDimitry Andric if (*AIt && *AIt == *LastOverlap) 525bdd1243dSDimitry Andric Result.insert(LastOverlap.start(), AIt.stop(), *AIt); 526bdd1243dSDimitry Andric } 527bdd1243dSDimitry Andric 528bdd1243dSDimitry Andric // Insert all intervals in map `B` that are contained within interval 529bdd1243dSDimitry Andric // `a` where the values match. 530bdd1243dSDimitry Andric // [ - - a - - ] 531bdd1243dSDimitry Andric // [ b1 ] [ b2 ] 532bdd1243dSDimitry Andric // - 533bdd1243dSDimitry Andric // [ r1 ] [ r2 ] 534bdd1243dSDimitry Andric while (Next != B.end() && Next.start() < AIt.stop() && 535bdd1243dSDimitry Andric Next.stop() <= AIt.stop()) { 536bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() 537bdd1243dSDimitry Andric << "- insert intersection of a and " << toString(Next)); 538bdd1243dSDimitry Andric if (*AIt && *AIt == *Next) 539bdd1243dSDimitry Andric Result.insert(Next.start(), Next.stop(), *Next); 540bdd1243dSDimitry Andric ++Next; 541bdd1243dSDimitry Andric } 542bdd1243dSDimitry Andric } 543bdd1243dSDimitry Andric } 544bdd1243dSDimitry Andric return Result; 545bdd1243dSDimitry Andric } 546bdd1243dSDimitry Andric 547bdd1243dSDimitry Andric /// Meet \p A and \p B, storing the result in \p A. 548bdd1243dSDimitry Andric void meetVars(VarFragMap &A, const VarFragMap &B) { 549bdd1243dSDimitry Andric // Meet A and B. 550bdd1243dSDimitry Andric // 551bdd1243dSDimitry Andric // Result = meet(a, b) for a in A, b in B where Var(a) == Var(b) 552bdd1243dSDimitry Andric for (auto It = A.begin(), End = A.end(); It != End; ++It) { 553bdd1243dSDimitry Andric unsigned AVar = It->first; 554bdd1243dSDimitry Andric FragsInMemMap &AFrags = It->second; 555bdd1243dSDimitry Andric auto BIt = B.find(AVar); 556bdd1243dSDimitry Andric if (BIt == B.end()) { 557bdd1243dSDimitry Andric A.erase(It); 558bdd1243dSDimitry Andric continue; // Var has no bits defined in B. 559bdd1243dSDimitry Andric } 560bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "meet fragment maps for " 561bdd1243dSDimitry Andric << Aggregates[AVar].first->getName() << "\n"); 562bdd1243dSDimitry Andric AFrags = meetFragments(AFrags, BIt->second); 563bdd1243dSDimitry Andric } 564bdd1243dSDimitry Andric } 565bdd1243dSDimitry Andric 566bdd1243dSDimitry Andric bool meet(const BasicBlock &BB, 567bdd1243dSDimitry Andric const SmallPtrSet<BasicBlock *, 16> &Visited) { 568bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "meet block info from preds of " << BB.getName() 569bdd1243dSDimitry Andric << "\n"); 570bdd1243dSDimitry Andric 571bdd1243dSDimitry Andric VarFragMap BBLiveIn; 572bdd1243dSDimitry Andric bool FirstMeet = true; 573bdd1243dSDimitry Andric // LiveIn locs for BB is the meet of the already-processed preds' LiveOut 574bdd1243dSDimitry Andric // locs. 575*0fca6ea1SDimitry Andric for (const BasicBlock *Pred : predecessors(&BB)) { 576bdd1243dSDimitry Andric // Ignore preds that haven't been processed yet. This is essentially the 577bdd1243dSDimitry Andric // same as initialising all variables to implicit top value (⊤) which is 578bdd1243dSDimitry Andric // the identity value for the meet operation. 579bdd1243dSDimitry Andric if (!Visited.count(Pred)) 580bdd1243dSDimitry Andric continue; 581bdd1243dSDimitry Andric 582bdd1243dSDimitry Andric auto PredLiveOut = LiveOut.find(Pred); 583bdd1243dSDimitry Andric assert(PredLiveOut != LiveOut.end()); 584bdd1243dSDimitry Andric 585bdd1243dSDimitry Andric if (FirstMeet) { 586bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "BBLiveIn = " << Pred->getName() << "\n"); 587bdd1243dSDimitry Andric BBLiveIn = PredLiveOut->second; 588bdd1243dSDimitry Andric FirstMeet = false; 589bdd1243dSDimitry Andric } else { 590bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "BBLiveIn = meet BBLiveIn, " << Pred->getName() 591bdd1243dSDimitry Andric << "\n"); 592bdd1243dSDimitry Andric meetVars(BBLiveIn, PredLiveOut->second); 593bdd1243dSDimitry Andric } 594bdd1243dSDimitry Andric 595bdd1243dSDimitry Andric // An empty set is ⊥ for the intersect-like meet operation. If we've 596bdd1243dSDimitry Andric // already got ⊥ there's no need to run the code - we know the result is 597bdd1243dSDimitry Andric // ⊥ since `meet(a, ⊥) = ⊥`. 598bdd1243dSDimitry Andric if (BBLiveIn.size() == 0) 599bdd1243dSDimitry Andric break; 600bdd1243dSDimitry Andric } 601bdd1243dSDimitry Andric 602bdd1243dSDimitry Andric auto CurrentLiveInEntry = LiveIn.find(&BB); 603bdd1243dSDimitry Andric // If there's no LiveIn entry for the block yet, add it. 604bdd1243dSDimitry Andric if (CurrentLiveInEntry == LiveIn.end()) { 605bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "change=true (first) on meet on " << BB.getName() 606bdd1243dSDimitry Andric << "\n"); 607bdd1243dSDimitry Andric LiveIn[&BB] = std::move(BBLiveIn); 608bdd1243dSDimitry Andric return /*Changed=*/true; 609bdd1243dSDimitry Andric } 610bdd1243dSDimitry Andric 611bdd1243dSDimitry Andric // If the LiveIn set has changed (expensive check) update it and return 612bdd1243dSDimitry Andric // true. 613bdd1243dSDimitry Andric if (!varFragMapsAreEqual(BBLiveIn, CurrentLiveInEntry->second)) { 614bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "change=true on meet on " << BB.getName() << "\n"); 615bdd1243dSDimitry Andric CurrentLiveInEntry->second = std::move(BBLiveIn); 616bdd1243dSDimitry Andric return /*Changed=*/true; 617bdd1243dSDimitry Andric } 618bdd1243dSDimitry Andric 619bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "change=false on meet on " << BB.getName() << "\n"); 620bdd1243dSDimitry Andric return /*Changed=*/false; 621bdd1243dSDimitry Andric } 622bdd1243dSDimitry Andric 6237a6dacacSDimitry Andric void insertMemLoc(BasicBlock &BB, VarLocInsertPt Before, unsigned Var, 624bdd1243dSDimitry Andric unsigned StartBit, unsigned EndBit, unsigned Base, 625bdd1243dSDimitry Andric DebugLoc DL) { 626bdd1243dSDimitry Andric assert(StartBit < EndBit && "Cannot create fragment of size <= 0"); 627bdd1243dSDimitry Andric if (!Base) 628bdd1243dSDimitry Andric return; 629bdd1243dSDimitry Andric FragMemLoc Loc; 630bdd1243dSDimitry Andric Loc.Var = Var; 631bdd1243dSDimitry Andric Loc.OffsetInBits = StartBit; 632bdd1243dSDimitry Andric Loc.SizeInBits = EndBit - StartBit; 633bdd1243dSDimitry Andric assert(Base && "Expected a non-zero ID for Base address"); 634bdd1243dSDimitry Andric Loc.Base = Base; 635bdd1243dSDimitry Andric Loc.DL = DL; 6367a6dacacSDimitry Andric BBInsertBeforeMap[&BB][Before].push_back(Loc); 637bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "Add mem def for " << Aggregates[Var].first->getName() 638bdd1243dSDimitry Andric << " bits [" << StartBit << ", " << EndBit << ")\n"); 639bdd1243dSDimitry Andric } 640bdd1243dSDimitry Andric 64106c3fb27SDimitry Andric /// Inserts a new dbg def if the interval found when looking up \p StartBit 64206c3fb27SDimitry Andric /// in \p FragMap starts before \p StartBit or ends after \p EndBit (which 64306c3fb27SDimitry Andric /// indicates - assuming StartBit->EndBit has just been inserted - that the 64406c3fb27SDimitry Andric /// slice has been coalesced in the map). 6457a6dacacSDimitry Andric void coalesceFragments(BasicBlock &BB, VarLocInsertPt Before, unsigned Var, 64606c3fb27SDimitry Andric unsigned StartBit, unsigned EndBit, unsigned Base, 64706c3fb27SDimitry Andric DebugLoc DL, const FragsInMemMap &FragMap) { 64806c3fb27SDimitry Andric if (!CoalesceAdjacentFragments) 64906c3fb27SDimitry Andric return; 65006c3fb27SDimitry Andric // We've inserted the location into the map. The map will have coalesced 65106c3fb27SDimitry Andric // adjacent intervals (variable fragments) that describe the same memory 65206c3fb27SDimitry Andric // location. Use this knowledge to insert a debug location that describes 65306c3fb27SDimitry Andric // that coalesced fragment. This may eclipse other locs we've just 65406c3fb27SDimitry Andric // inserted. This is okay as redundant locs will be cleaned up later. 65506c3fb27SDimitry Andric auto CoalescedFrag = FragMap.find(StartBit); 65606c3fb27SDimitry Andric // Bail if no coalescing has taken place. 65706c3fb27SDimitry Andric if (CoalescedFrag.start() == StartBit && CoalescedFrag.stop() == EndBit) 65806c3fb27SDimitry Andric return; 65906c3fb27SDimitry Andric 66006c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << "- Insert loc for bits " << CoalescedFrag.start() 66106c3fb27SDimitry Andric << " to " << CoalescedFrag.stop() << "\n"); 66206c3fb27SDimitry Andric insertMemLoc(BB, Before, Var, CoalescedFrag.start(), CoalescedFrag.stop(), 66306c3fb27SDimitry Andric Base, DL); 66406c3fb27SDimitry Andric } 66506c3fb27SDimitry Andric 6667a6dacacSDimitry Andric void addDef(const VarLocInfo &VarLoc, VarLocInsertPt Before, BasicBlock &BB, 667bdd1243dSDimitry Andric VarFragMap &LiveSet) { 668bdd1243dSDimitry Andric DebugVariable DbgVar = FnVarLocs->getVariable(VarLoc.VariableID); 669bdd1243dSDimitry Andric if (skipVariable(DbgVar.getVariable())) 670bdd1243dSDimitry Andric return; 671bdd1243dSDimitry Andric // Don't bother doing anything for this variables if we know it's fully 672bdd1243dSDimitry Andric // promoted. We're only interested in variables that (sometimes) live on 673bdd1243dSDimitry Andric // the stack here. 674bdd1243dSDimitry Andric if (!VarsWithStackSlot->count(getAggregate(DbgVar))) 675bdd1243dSDimitry Andric return; 676bdd1243dSDimitry Andric unsigned Var = Aggregates.insert( 677bdd1243dSDimitry Andric DebugAggregate(DbgVar.getVariable(), VarLoc.DL.getInlinedAt())); 678bdd1243dSDimitry Andric 679bdd1243dSDimitry Andric // [StartBit: EndBit) are the bits affected by this def. 680bdd1243dSDimitry Andric const DIExpression *DIExpr = VarLoc.Expr; 681bdd1243dSDimitry Andric unsigned StartBit; 682bdd1243dSDimitry Andric unsigned EndBit; 683bdd1243dSDimitry Andric if (auto Frag = DIExpr->getFragmentInfo()) { 684bdd1243dSDimitry Andric StartBit = Frag->OffsetInBits; 685bdd1243dSDimitry Andric EndBit = StartBit + Frag->SizeInBits; 686bdd1243dSDimitry Andric } else { 687bdd1243dSDimitry Andric assert(static_cast<bool>(DbgVar.getVariable()->getSizeInBits())); 688bdd1243dSDimitry Andric StartBit = 0; 689bdd1243dSDimitry Andric EndBit = *DbgVar.getVariable()->getSizeInBits(); 690bdd1243dSDimitry Andric } 691bdd1243dSDimitry Andric 692bdd1243dSDimitry Andric // We will only fill fragments for simple memory-describing dbg.value 693bdd1243dSDimitry Andric // intrinsics. If the fragment offset is the same as the offset from the 694bdd1243dSDimitry Andric // base pointer, do The Thing, otherwise fall back to normal dbg.value 695bdd1243dSDimitry Andric // behaviour. AssignmentTrackingLowering has generated DIExpressions 696bdd1243dSDimitry Andric // written in terms of the base pointer. 697bdd1243dSDimitry Andric // TODO: Remove this condition since the fragment offset doesn't always 698bdd1243dSDimitry Andric // equal the offset from base pointer (e.g. for a SROA-split variable). 699bdd1243dSDimitry Andric const auto DerefOffsetInBytes = getDerefOffsetInBytes(DIExpr); 700bdd1243dSDimitry Andric const unsigned Base = 701bdd1243dSDimitry Andric DerefOffsetInBytes && *DerefOffsetInBytes * 8 == StartBit 70206c3fb27SDimitry Andric ? Bases.insert(VarLoc.Values) 703bdd1243dSDimitry Andric : 0; 704bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "DEF " << DbgVar.getVariable()->getName() << " [" 705bdd1243dSDimitry Andric << StartBit << ", " << EndBit << "): " << toString(Base) 706bdd1243dSDimitry Andric << "\n"); 707bdd1243dSDimitry Andric 708bdd1243dSDimitry Andric // First of all, any locs that use mem that are disrupted need reinstating. 709bdd1243dSDimitry Andric // Unfortunately, IntervalMap doesn't let us insert intervals that overlap 710bdd1243dSDimitry Andric // with existing intervals so this code involves a lot of fiddling around 711bdd1243dSDimitry Andric // with intervals to do that manually. 712bdd1243dSDimitry Andric auto FragIt = LiveSet.find(Var); 713bdd1243dSDimitry Andric 714bdd1243dSDimitry Andric // Check if the variable does not exist in the map. 715bdd1243dSDimitry Andric if (FragIt == LiveSet.end()) { 716bdd1243dSDimitry Andric // Add this variable to the BB map. 717bdd1243dSDimitry Andric auto P = LiveSet.try_emplace(Var, FragsInMemMap(IntervalMapAlloc)); 718bdd1243dSDimitry Andric assert(P.second && "Var already in map?"); 719bdd1243dSDimitry Andric // Add the interval to the fragment map. 720bdd1243dSDimitry Andric P.first->second.insert(StartBit, EndBit, Base); 721bdd1243dSDimitry Andric return; 722bdd1243dSDimitry Andric } 723bdd1243dSDimitry Andric // The variable has an entry in the map. 724bdd1243dSDimitry Andric 725bdd1243dSDimitry Andric FragsInMemMap &FragMap = FragIt->second; 726bdd1243dSDimitry Andric // First check the easy case: the new fragment `f` doesn't overlap with any 727bdd1243dSDimitry Andric // intervals. 728bdd1243dSDimitry Andric if (!FragMap.overlaps(StartBit, EndBit)) { 729bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "- No overlaps\n"); 730bdd1243dSDimitry Andric FragMap.insert(StartBit, EndBit, Base); 73106c3fb27SDimitry Andric coalesceFragments(BB, Before, Var, StartBit, EndBit, Base, VarLoc.DL, 73206c3fb27SDimitry Andric FragMap); 733bdd1243dSDimitry Andric return; 734bdd1243dSDimitry Andric } 735bdd1243dSDimitry Andric // There is at least one overlap. 736bdd1243dSDimitry Andric 737bdd1243dSDimitry Andric // Does StartBit intersect an existing fragment? 738bdd1243dSDimitry Andric auto FirstOverlap = FragMap.find(StartBit); 739bdd1243dSDimitry Andric assert(FirstOverlap != FragMap.end()); 740bdd1243dSDimitry Andric bool IntersectStart = FirstOverlap.start() < StartBit; 741bdd1243dSDimitry Andric 742bdd1243dSDimitry Andric // Does EndBit intersect an existing fragment? 743bdd1243dSDimitry Andric auto LastOverlap = FragMap.find(EndBit); 744bdd1243dSDimitry Andric bool IntersectEnd = LastOverlap.valid() && LastOverlap.start() < EndBit; 745bdd1243dSDimitry Andric 746bdd1243dSDimitry Andric // Check if both ends of `f` intersect the same interval `i`. 747bdd1243dSDimitry Andric if (IntersectStart && IntersectEnd && FirstOverlap == LastOverlap) { 748bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "- Intersect single interval @ both ends\n"); 749bdd1243dSDimitry Andric // Shorten `i` so that there's space to insert `f`. 750bdd1243dSDimitry Andric // [ f ] 751bdd1243dSDimitry Andric // [ - i - ] 752bdd1243dSDimitry Andric // + 753bdd1243dSDimitry Andric // [ i ][ f ][ i ] 754bdd1243dSDimitry Andric 755bdd1243dSDimitry Andric // Save values for use after inserting a new interval. 756bdd1243dSDimitry Andric auto EndBitOfOverlap = FirstOverlap.stop(); 757bdd1243dSDimitry Andric unsigned OverlapValue = FirstOverlap.value(); 758bdd1243dSDimitry Andric 759bdd1243dSDimitry Andric // Shorten the overlapping interval. 760bdd1243dSDimitry Andric FirstOverlap.setStop(StartBit); 761bdd1243dSDimitry Andric insertMemLoc(BB, Before, Var, FirstOverlap.start(), StartBit, 762bdd1243dSDimitry Andric OverlapValue, VarLoc.DL); 763bdd1243dSDimitry Andric 764bdd1243dSDimitry Andric // Insert a new interval to represent the end part. 765bdd1243dSDimitry Andric FragMap.insert(EndBit, EndBitOfOverlap, OverlapValue); 766bdd1243dSDimitry Andric insertMemLoc(BB, Before, Var, EndBit, EndBitOfOverlap, OverlapValue, 767bdd1243dSDimitry Andric VarLoc.DL); 768bdd1243dSDimitry Andric 769bdd1243dSDimitry Andric // Insert the new (middle) fragment now there is space. 770bdd1243dSDimitry Andric FragMap.insert(StartBit, EndBit, Base); 771bdd1243dSDimitry Andric } else { 772bdd1243dSDimitry Andric // There's an overlap but `f` may not be fully contained within 773bdd1243dSDimitry Andric // `i`. Shorten any end-point intersections so that we can then 774bdd1243dSDimitry Andric // insert `f`. 775bdd1243dSDimitry Andric // [ - f - ] 776bdd1243dSDimitry Andric // [ - i - ] 777bdd1243dSDimitry Andric // | | 778bdd1243dSDimitry Andric // [ i ] 779bdd1243dSDimitry Andric // Shorten any end-point intersections. 780bdd1243dSDimitry Andric if (IntersectStart) { 781bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "- Intersect interval at start\n"); 782bdd1243dSDimitry Andric // Split off at the intersection. 783bdd1243dSDimitry Andric FirstOverlap.setStop(StartBit); 784bdd1243dSDimitry Andric insertMemLoc(BB, Before, Var, FirstOverlap.start(), StartBit, 785bdd1243dSDimitry Andric *FirstOverlap, VarLoc.DL); 786bdd1243dSDimitry Andric } 787bdd1243dSDimitry Andric // [ - f - ] 788bdd1243dSDimitry Andric // [ - i - ] 789bdd1243dSDimitry Andric // | | 790bdd1243dSDimitry Andric // [ i ] 791bdd1243dSDimitry Andric if (IntersectEnd) { 792bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "- Intersect interval at end\n"); 793bdd1243dSDimitry Andric // Split off at the intersection. 794bdd1243dSDimitry Andric LastOverlap.setStart(EndBit); 795bdd1243dSDimitry Andric insertMemLoc(BB, Before, Var, EndBit, LastOverlap.stop(), *LastOverlap, 796bdd1243dSDimitry Andric VarLoc.DL); 797bdd1243dSDimitry Andric } 798bdd1243dSDimitry Andric 799bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "- Erase intervals contained within\n"); 800bdd1243dSDimitry Andric // FirstOverlap and LastOverlap have been shortened such that they're 801bdd1243dSDimitry Andric // no longer overlapping with [StartBit, EndBit). Delete any overlaps 802bdd1243dSDimitry Andric // that remain (these will be fully contained within `f`). 803bdd1243dSDimitry Andric // [ - f - ] } 804bdd1243dSDimitry Andric // [ - i - ] } Intersection shortening that has happened above. 805bdd1243dSDimitry Andric // | | } 806bdd1243dSDimitry Andric // [ i ] } 807bdd1243dSDimitry Andric // ----------------- 808bdd1243dSDimitry Andric // [i2 ] } Intervals fully contained within `f` get erased. 809bdd1243dSDimitry Andric // ----------------- 810bdd1243dSDimitry Andric // [ - f - ][ i ] } Completed insertion. 811bdd1243dSDimitry Andric auto It = FirstOverlap; 812bdd1243dSDimitry Andric if (IntersectStart) 813bdd1243dSDimitry Andric ++It; // IntersectStart: first overlap has been shortened. 814bdd1243dSDimitry Andric while (It.valid() && It.start() >= StartBit && It.stop() <= EndBit) { 815bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "- Erase " << toString(It)); 816bdd1243dSDimitry Andric It.erase(); // This increments It after removing the interval. 817bdd1243dSDimitry Andric } 818bdd1243dSDimitry Andric // We've dealt with all the overlaps now! 819bdd1243dSDimitry Andric assert(!FragMap.overlaps(StartBit, EndBit)); 820bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "- Insert DEF into now-empty space\n"); 821bdd1243dSDimitry Andric FragMap.insert(StartBit, EndBit, Base); 822bdd1243dSDimitry Andric } 82306c3fb27SDimitry Andric 82406c3fb27SDimitry Andric coalesceFragments(BB, Before, Var, StartBit, EndBit, Base, VarLoc.DL, 82506c3fb27SDimitry Andric FragMap); 826bdd1243dSDimitry Andric } 827bdd1243dSDimitry Andric 828bdd1243dSDimitry Andric bool skipVariable(const DILocalVariable *V) { return !V->getSizeInBits(); } 829bdd1243dSDimitry Andric 830bdd1243dSDimitry Andric void process(BasicBlock &BB, VarFragMap &LiveSet) { 831bdd1243dSDimitry Andric BBInsertBeforeMap[&BB].clear(); 832bdd1243dSDimitry Andric for (auto &I : BB) { 833*0fca6ea1SDimitry Andric for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange())) { 834*0fca6ea1SDimitry Andric if (const auto *Locs = FnVarLocs->getWedge(&DVR)) { 8357a6dacacSDimitry Andric for (const VarLocInfo &Loc : *Locs) { 836*0fca6ea1SDimitry Andric addDef(Loc, &DVR, *I.getParent(), LiveSet); 8377a6dacacSDimitry Andric } 8387a6dacacSDimitry Andric } 8397a6dacacSDimitry Andric } 840bdd1243dSDimitry Andric if (const auto *Locs = FnVarLocs->getWedge(&I)) { 841bdd1243dSDimitry Andric for (const VarLocInfo &Loc : *Locs) { 8427a6dacacSDimitry Andric addDef(Loc, &I, *I.getParent(), LiveSet); 843bdd1243dSDimitry Andric } 844bdd1243dSDimitry Andric } 845bdd1243dSDimitry Andric } 846bdd1243dSDimitry Andric } 847bdd1243dSDimitry Andric 848bdd1243dSDimitry Andric public: 849bdd1243dSDimitry Andric MemLocFragmentFill(Function &Fn, 85006c3fb27SDimitry Andric const DenseSet<DebugAggregate> *VarsWithStackSlot, 85106c3fb27SDimitry Andric bool CoalesceAdjacentFragments) 85206c3fb27SDimitry Andric : Fn(Fn), VarsWithStackSlot(VarsWithStackSlot), 85306c3fb27SDimitry Andric CoalesceAdjacentFragments(CoalesceAdjacentFragments) {} 854bdd1243dSDimitry Andric 855bdd1243dSDimitry Andric /// Add variable locations to \p FnVarLocs so that any bits of a variable 856bdd1243dSDimitry Andric /// with a memory location have that location explicitly reinstated at each 857bdd1243dSDimitry Andric /// subsequent variable location definition that that doesn't overwrite those 858bdd1243dSDimitry Andric /// bits. i.e. after a variable location def, insert new defs for the memory 859bdd1243dSDimitry Andric /// location with fragments for the difference of "all bits currently in 860bdd1243dSDimitry Andric /// memory" and "the fragment of the second def". e.g. 861bdd1243dSDimitry Andric /// 862bdd1243dSDimitry Andric /// Before: 863bdd1243dSDimitry Andric /// 864bdd1243dSDimitry Andric /// var x bits 0 to 63: value in memory 865bdd1243dSDimitry Andric /// more instructions 866bdd1243dSDimitry Andric /// var x bits 0 to 31: value is %0 867bdd1243dSDimitry Andric /// 868bdd1243dSDimitry Andric /// After: 869bdd1243dSDimitry Andric /// 870bdd1243dSDimitry Andric /// var x bits 0 to 63: value in memory 871bdd1243dSDimitry Andric /// more instructions 872bdd1243dSDimitry Andric /// var x bits 0 to 31: value is %0 873bdd1243dSDimitry Andric /// var x bits 32 to 61: value in memory ; <-- new loc def 874bdd1243dSDimitry Andric /// 875bdd1243dSDimitry Andric void run(FunctionVarLocsBuilder *FnVarLocs) { 876bdd1243dSDimitry Andric if (!EnableMemLocFragFill) 877bdd1243dSDimitry Andric return; 878bdd1243dSDimitry Andric 879bdd1243dSDimitry Andric this->FnVarLocs = FnVarLocs; 880bdd1243dSDimitry Andric 881bdd1243dSDimitry Andric // Prepare for traversal. 882bdd1243dSDimitry Andric // 883bdd1243dSDimitry Andric ReversePostOrderTraversal<Function *> RPOT(&Fn); 884bdd1243dSDimitry Andric std::priority_queue<unsigned int, std::vector<unsigned int>, 885bdd1243dSDimitry Andric std::greater<unsigned int>> 886bdd1243dSDimitry Andric Worklist; 887bdd1243dSDimitry Andric std::priority_queue<unsigned int, std::vector<unsigned int>, 888bdd1243dSDimitry Andric std::greater<unsigned int>> 889bdd1243dSDimitry Andric Pending; 890bdd1243dSDimitry Andric DenseMap<unsigned int, BasicBlock *> OrderToBB; 891bdd1243dSDimitry Andric DenseMap<BasicBlock *, unsigned int> BBToOrder; 892bdd1243dSDimitry Andric { // Init OrderToBB and BBToOrder. 893bdd1243dSDimitry Andric unsigned int RPONumber = 0; 894*0fca6ea1SDimitry Andric for (BasicBlock *BB : RPOT) { 895*0fca6ea1SDimitry Andric OrderToBB[RPONumber] = BB; 896*0fca6ea1SDimitry Andric BBToOrder[BB] = RPONumber; 897bdd1243dSDimitry Andric Worklist.push(RPONumber); 898bdd1243dSDimitry Andric ++RPONumber; 899bdd1243dSDimitry Andric } 900bdd1243dSDimitry Andric LiveIn.init(RPONumber); 901bdd1243dSDimitry Andric LiveOut.init(RPONumber); 902bdd1243dSDimitry Andric } 903bdd1243dSDimitry Andric 904bdd1243dSDimitry Andric // Perform the traversal. 905bdd1243dSDimitry Andric // 906bdd1243dSDimitry Andric // This is a standard "intersect of predecessor outs" dataflow problem. To 907bdd1243dSDimitry Andric // solve it, we perform meet() and process() using the two worklist method 908bdd1243dSDimitry Andric // until the LiveIn data for each block becomes unchanging. 909bdd1243dSDimitry Andric // 910bdd1243dSDimitry Andric // This dataflow is essentially working on maps of sets and at each meet we 911bdd1243dSDimitry Andric // intersect the maps and the mapped sets. So, initialized live-in maps 912bdd1243dSDimitry Andric // monotonically decrease in value throughout the dataflow. 913bdd1243dSDimitry Andric SmallPtrSet<BasicBlock *, 16> Visited; 914bdd1243dSDimitry Andric while (!Worklist.empty() || !Pending.empty()) { 915bdd1243dSDimitry Andric // We track what is on the pending worklist to avoid inserting the same 916bdd1243dSDimitry Andric // thing twice. We could avoid this with a custom priority queue, but 917bdd1243dSDimitry Andric // this is probably not worth it. 918bdd1243dSDimitry Andric SmallPtrSet<BasicBlock *, 16> OnPending; 919bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "Processing Worklist\n"); 920bdd1243dSDimitry Andric while (!Worklist.empty()) { 921bdd1243dSDimitry Andric BasicBlock *BB = OrderToBB[Worklist.top()]; 922bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "\nPop BB " << BB->getName() << "\n"); 923bdd1243dSDimitry Andric Worklist.pop(); 924bdd1243dSDimitry Andric bool InChanged = meet(*BB, Visited); 925bdd1243dSDimitry Andric // Always consider LiveIn changed on the first visit. 926bdd1243dSDimitry Andric InChanged |= Visited.insert(BB).second; 927bdd1243dSDimitry Andric if (InChanged) { 928bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() 929bdd1243dSDimitry Andric << BB->getName() << " has new InLocs, process it\n"); 930bdd1243dSDimitry Andric // Mutate a copy of LiveIn while processing BB. Once we've processed 931bdd1243dSDimitry Andric // the terminator LiveSet is the LiveOut set for BB. 932bdd1243dSDimitry Andric // This is an expensive copy! 933bdd1243dSDimitry Andric VarFragMap LiveSet = LiveIn[BB]; 934bdd1243dSDimitry Andric 935bdd1243dSDimitry Andric // Process the instructions in the block. 936bdd1243dSDimitry Andric process(*BB, LiveSet); 937bdd1243dSDimitry Andric 938bdd1243dSDimitry Andric // Relatively expensive check: has anything changed in LiveOut for BB? 939bdd1243dSDimitry Andric if (!varFragMapsAreEqual(LiveOut[BB], LiveSet)) { 940bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << BB->getName() 941bdd1243dSDimitry Andric << " has new OutLocs, add succs to worklist: [ "); 942bdd1243dSDimitry Andric LiveOut[BB] = std::move(LiveSet); 943*0fca6ea1SDimitry Andric for (BasicBlock *Succ : successors(BB)) { 944*0fca6ea1SDimitry Andric if (OnPending.insert(Succ).second) { 945*0fca6ea1SDimitry Andric LLVM_DEBUG(dbgs() << Succ->getName() << " "); 946*0fca6ea1SDimitry Andric Pending.push(BBToOrder[Succ]); 947bdd1243dSDimitry Andric } 948bdd1243dSDimitry Andric } 949bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "]\n"); 950bdd1243dSDimitry Andric } 951bdd1243dSDimitry Andric } 952bdd1243dSDimitry Andric } 953bdd1243dSDimitry Andric Worklist.swap(Pending); 954bdd1243dSDimitry Andric // At this point, pending must be empty, since it was just the empty 955bdd1243dSDimitry Andric // worklist 956bdd1243dSDimitry Andric assert(Pending.empty() && "Pending should be empty"); 957bdd1243dSDimitry Andric } 958bdd1243dSDimitry Andric 959bdd1243dSDimitry Andric // Insert new location defs. 96006c3fb27SDimitry Andric for (auto &Pair : BBInsertBeforeMap) { 961bdd1243dSDimitry Andric InsertMap &Map = Pair.second; 96206c3fb27SDimitry Andric for (auto &Pair : Map) { 9637a6dacacSDimitry Andric auto InsertBefore = Pair.first; 964bdd1243dSDimitry Andric assert(InsertBefore && "should never be null"); 965bdd1243dSDimitry Andric auto FragMemLocs = Pair.second; 966bdd1243dSDimitry Andric auto &Ctx = Fn.getContext(); 967bdd1243dSDimitry Andric 96806c3fb27SDimitry Andric for (auto &FragMemLoc : FragMemLocs) { 969bdd1243dSDimitry Andric DIExpression *Expr = DIExpression::get(Ctx, std::nullopt); 97006c3fb27SDimitry Andric if (FragMemLoc.SizeInBits != 97106c3fb27SDimitry Andric *Aggregates[FragMemLoc.Var].first->getSizeInBits()) 972bdd1243dSDimitry Andric Expr = *DIExpression::createFragmentExpression( 973bdd1243dSDimitry Andric Expr, FragMemLoc.OffsetInBits, FragMemLoc.SizeInBits); 974bdd1243dSDimitry Andric Expr = DIExpression::prepend(Expr, DIExpression::DerefAfter, 975bdd1243dSDimitry Andric FragMemLoc.OffsetInBits / 8); 976bdd1243dSDimitry Andric DebugVariable Var(Aggregates[FragMemLoc.Var].first, Expr, 977bdd1243dSDimitry Andric FragMemLoc.DL.getInlinedAt()); 978bdd1243dSDimitry Andric FnVarLocs->addVarLoc(InsertBefore, Var, Expr, FragMemLoc.DL, 979bdd1243dSDimitry Andric Bases[FragMemLoc.Base]); 980bdd1243dSDimitry Andric } 981bdd1243dSDimitry Andric } 982bdd1243dSDimitry Andric } 983bdd1243dSDimitry Andric } 984bdd1243dSDimitry Andric }; 985bdd1243dSDimitry Andric 986bdd1243dSDimitry Andric /// AssignmentTrackingLowering encapsulates a dataflow analysis over a function 987bdd1243dSDimitry Andric /// that interprets assignment tracking debug info metadata and stores in IR to 988bdd1243dSDimitry Andric /// create a map of variable locations. 989bdd1243dSDimitry Andric class AssignmentTrackingLowering { 990bdd1243dSDimitry Andric public: 991bdd1243dSDimitry Andric /// The kind of location in use for a variable, where Mem is the stack home, 992bdd1243dSDimitry Andric /// Val is an SSA value or const, and None means that there is not one single 993bdd1243dSDimitry Andric /// kind (either because there are multiple or because there is none; it may 994bdd1243dSDimitry Andric /// prove useful to split this into two values in the future). 995bdd1243dSDimitry Andric /// 996bdd1243dSDimitry Andric /// LocKind is a join-semilattice with the partial order: 997bdd1243dSDimitry Andric /// None > Mem, Val 998bdd1243dSDimitry Andric /// 999bdd1243dSDimitry Andric /// i.e. 1000bdd1243dSDimitry Andric /// join(Mem, Mem) = Mem 1001bdd1243dSDimitry Andric /// join(Val, Val) = Val 1002bdd1243dSDimitry Andric /// join(Mem, Val) = None 1003bdd1243dSDimitry Andric /// join(None, Mem) = None 1004bdd1243dSDimitry Andric /// join(None, Val) = None 1005bdd1243dSDimitry Andric /// join(None, None) = None 1006bdd1243dSDimitry Andric /// 1007bdd1243dSDimitry Andric /// Note: the order is not `None > Val > Mem` because we're using DIAssignID 1008bdd1243dSDimitry Andric /// to name assignments and are not tracking the actual stored values. 1009bdd1243dSDimitry Andric /// Therefore currently there's no way to ensure that Mem values and Val 1010bdd1243dSDimitry Andric /// values are the same. This could be a future extension, though it's not 1011bdd1243dSDimitry Andric /// clear that many additional locations would be recovered that way in 1012bdd1243dSDimitry Andric /// practice as the likelihood of this sitation arising naturally seems 1013bdd1243dSDimitry Andric /// incredibly low. 1014bdd1243dSDimitry Andric enum class LocKind { Mem, Val, None }; 1015bdd1243dSDimitry Andric 1016bdd1243dSDimitry Andric /// An abstraction of the assignment of a value to a variable or memory 1017bdd1243dSDimitry Andric /// location. 1018bdd1243dSDimitry Andric /// 1019bdd1243dSDimitry Andric /// An Assignment is Known or NoneOrPhi. A Known Assignment means we have a 1020bdd1243dSDimitry Andric /// DIAssignID ptr that represents it. NoneOrPhi means that we don't (or 1021bdd1243dSDimitry Andric /// can't) know the ID of the last assignment that took place. 1022bdd1243dSDimitry Andric /// 1023bdd1243dSDimitry Andric /// The Status of the Assignment (Known or NoneOrPhi) is another 1024bdd1243dSDimitry Andric /// join-semilattice. The partial order is: 1025bdd1243dSDimitry Andric /// NoneOrPhi > Known {id_0, id_1, ...id_N} 1026bdd1243dSDimitry Andric /// 1027bdd1243dSDimitry Andric /// i.e. for all values x and y where x != y: 1028bdd1243dSDimitry Andric /// join(x, x) = x 1029bdd1243dSDimitry Andric /// join(x, y) = NoneOrPhi 1030*0fca6ea1SDimitry Andric using AssignRecord = PointerUnion<DbgAssignIntrinsic *, DbgVariableRecord *>; 1031bdd1243dSDimitry Andric struct Assignment { 1032bdd1243dSDimitry Andric enum S { Known, NoneOrPhi } Status; 1033bdd1243dSDimitry Andric /// ID of the assignment. nullptr if Status is not Known. 1034bdd1243dSDimitry Andric DIAssignID *ID; 1035bdd1243dSDimitry Andric /// The dbg.assign that marks this dbg-def. Mem-defs don't use this field. 1036bdd1243dSDimitry Andric /// May be nullptr. 10377a6dacacSDimitry Andric AssignRecord Source; 1038bdd1243dSDimitry Andric 1039bdd1243dSDimitry Andric bool isSameSourceAssignment(const Assignment &Other) const { 1040bdd1243dSDimitry Andric // Don't include Source in the equality check. Assignments are 1041bdd1243dSDimitry Andric // defined by their ID, not debug intrinsic(s). 1042bdd1243dSDimitry Andric return std::tie(Status, ID) == std::tie(Other.Status, Other.ID); 1043bdd1243dSDimitry Andric } 1044bdd1243dSDimitry Andric void dump(raw_ostream &OS) { 1045bdd1243dSDimitry Andric static const char *LUT[] = {"Known", "NoneOrPhi"}; 1046bdd1243dSDimitry Andric OS << LUT[Status] << "(id="; 1047bdd1243dSDimitry Andric if (ID) 1048bdd1243dSDimitry Andric OS << ID; 1049bdd1243dSDimitry Andric else 1050bdd1243dSDimitry Andric OS << "null"; 1051bdd1243dSDimitry Andric OS << ", s="; 10527a6dacacSDimitry Andric if (Source.isNull()) 1053bdd1243dSDimitry Andric OS << "null"; 10547a6dacacSDimitry Andric else if (isa<DbgAssignIntrinsic *>(Source)) 10557a6dacacSDimitry Andric OS << Source.get<DbgAssignIntrinsic *>(); 10567a6dacacSDimitry Andric else 1057*0fca6ea1SDimitry Andric OS << Source.get<DbgVariableRecord *>(); 1058bdd1243dSDimitry Andric OS << ")"; 1059bdd1243dSDimitry Andric } 1060bdd1243dSDimitry Andric 1061bdd1243dSDimitry Andric static Assignment make(DIAssignID *ID, DbgAssignIntrinsic *Source) { 1062bdd1243dSDimitry Andric return Assignment(Known, ID, Source); 1063bdd1243dSDimitry Andric } 1064*0fca6ea1SDimitry Andric static Assignment make(DIAssignID *ID, DbgVariableRecord *Source) { 10657a6dacacSDimitry Andric assert(Source->isDbgAssign() && 1066*0fca6ea1SDimitry Andric "Cannot make an assignment from a non-assign DbgVariableRecord"); 10677a6dacacSDimitry Andric return Assignment(Known, ID, Source); 10687a6dacacSDimitry Andric } 10697a6dacacSDimitry Andric static Assignment make(DIAssignID *ID, AssignRecord Source) { 10707a6dacacSDimitry Andric return Assignment(Known, ID, Source); 10717a6dacacSDimitry Andric } 1072bdd1243dSDimitry Andric static Assignment makeFromMemDef(DIAssignID *ID) { 10737a6dacacSDimitry Andric return Assignment(Known, ID); 1074bdd1243dSDimitry Andric } 10757a6dacacSDimitry Andric static Assignment makeNoneOrPhi() { return Assignment(NoneOrPhi, nullptr); } 1076bdd1243dSDimitry Andric // Again, need a Top value? 10777a6dacacSDimitry Andric Assignment() : Status(NoneOrPhi), ID(nullptr) {} // Can we delete this? 10787a6dacacSDimitry Andric Assignment(S Status, DIAssignID *ID) : Status(Status), ID(ID) { 10797a6dacacSDimitry Andric // If the Status is Known then we expect there to be an assignment ID. 10807a6dacacSDimitry Andric assert(Status == NoneOrPhi || ID); 10817a6dacacSDimitry Andric } 1082bdd1243dSDimitry Andric Assignment(S Status, DIAssignID *ID, DbgAssignIntrinsic *Source) 1083bdd1243dSDimitry Andric : Status(Status), ID(ID), Source(Source) { 1084bdd1243dSDimitry Andric // If the Status is Known then we expect there to be an assignment ID. 1085bdd1243dSDimitry Andric assert(Status == NoneOrPhi || ID); 1086bdd1243dSDimitry Andric } 1087*0fca6ea1SDimitry Andric Assignment(S Status, DIAssignID *ID, DbgVariableRecord *Source) 10887a6dacacSDimitry Andric : Status(Status), ID(ID), Source(Source) { 10897a6dacacSDimitry Andric // If the Status is Known then we expect there to be an assignment ID. 10907a6dacacSDimitry Andric assert(Status == NoneOrPhi || ID); 10917a6dacacSDimitry Andric } 10927a6dacacSDimitry Andric Assignment(S Status, DIAssignID *ID, AssignRecord Source) 10937a6dacacSDimitry Andric : Status(Status), ID(ID), Source(Source) { 10947a6dacacSDimitry Andric // If the Status is Known then we expect there to be an assignment ID. 10957a6dacacSDimitry Andric assert(Status == NoneOrPhi || ID); 10967a6dacacSDimitry Andric } 1097bdd1243dSDimitry Andric }; 1098bdd1243dSDimitry Andric 109906c3fb27SDimitry Andric using AssignmentMap = SmallVector<Assignment>; 110006c3fb27SDimitry Andric using LocMap = SmallVector<LocKind>; 110106c3fb27SDimitry Andric using OverlapMap = DenseMap<VariableID, SmallVector<VariableID>>; 1102bdd1243dSDimitry Andric using UntaggedStoreAssignmentMap = 1103bdd1243dSDimitry Andric DenseMap<const Instruction *, 1104bdd1243dSDimitry Andric SmallVector<std::pair<VariableID, at::AssignmentInfo>>>; 1105bdd1243dSDimitry Andric 1106bdd1243dSDimitry Andric private: 110706c3fb27SDimitry Andric /// The highest numbered VariableID for partially promoted variables plus 1, 110806c3fb27SDimitry Andric /// the values for which start at 1. 110906c3fb27SDimitry Andric unsigned TrackedVariablesVectorSize = 0; 1110bdd1243dSDimitry Andric /// Map a variable to the set of variables that it fully contains. 1111bdd1243dSDimitry Andric OverlapMap VarContains; 1112bdd1243dSDimitry Andric /// Map untagged stores to the variable fragments they assign to. Used by 1113bdd1243dSDimitry Andric /// processUntaggedInstruction. 1114bdd1243dSDimitry Andric UntaggedStoreAssignmentMap UntaggedStoreVars; 1115bdd1243dSDimitry Andric 1116bdd1243dSDimitry Andric // Machinery to defer inserting dbg.values. 11177a6dacacSDimitry Andric using InstInsertMap = MapVector<VarLocInsertPt, SmallVector<VarLocInfo>>; 11187a6dacacSDimitry Andric InstInsertMap InsertBeforeMap; 1119bdd1243dSDimitry Andric /// Clear the location definitions currently cached for insertion after /p 1120bdd1243dSDimitry Andric /// After. 1121bdd1243dSDimitry Andric void resetInsertionPoint(Instruction &After); 1122*0fca6ea1SDimitry Andric void resetInsertionPoint(DbgVariableRecord &After); 11237a6dacacSDimitry Andric 11247a6dacacSDimitry Andric // emitDbgValue can be called with: 1125*0fca6ea1SDimitry Andric // Source=[AssignRecord|DbgValueInst*|DbgAssignIntrinsic*|DbgVariableRecord*] 11267a6dacacSDimitry Andric // Since AssignRecord can be cast to one of the latter two types, and all 11277a6dacacSDimitry Andric // other types have a shared interface, we use a template to handle the latter 11287a6dacacSDimitry Andric // three types, and an explicit overload for AssignRecord that forwards to 11297a6dacacSDimitry Andric // the template version with the right type. 11307a6dacacSDimitry Andric void emitDbgValue(LocKind Kind, AssignRecord Source, VarLocInsertPt After); 11317a6dacacSDimitry Andric template <typename T> 11327a6dacacSDimitry Andric void emitDbgValue(LocKind Kind, const T Source, VarLocInsertPt After); 1133bdd1243dSDimitry Andric 113406c3fb27SDimitry Andric static bool mapsAreEqual(const BitVector &Mask, const AssignmentMap &A, 113506c3fb27SDimitry Andric const AssignmentMap &B) { 113606c3fb27SDimitry Andric return llvm::all_of(Mask.set_bits(), [&](unsigned VarID) { 113706c3fb27SDimitry Andric return A[VarID].isSameSourceAssignment(B[VarID]); 113806c3fb27SDimitry Andric }); 1139bdd1243dSDimitry Andric } 1140bdd1243dSDimitry Andric 1141bdd1243dSDimitry Andric /// Represents the stack and debug assignments in a block. Used to describe 1142bdd1243dSDimitry Andric /// the live-in and live-out values for blocks, as well as the "current" 1143bdd1243dSDimitry Andric /// value as we process each instruction in a block. 1144bdd1243dSDimitry Andric struct BlockInfo { 114506c3fb27SDimitry Andric /// The set of variables (VariableID) being tracked in this block. 114606c3fb27SDimitry Andric BitVector VariableIDsInBlock; 114706c3fb27SDimitry Andric /// Dominating assignment to memory for each variable, indexed by 114806c3fb27SDimitry Andric /// VariableID. 1149bdd1243dSDimitry Andric AssignmentMap StackHomeValue; 115006c3fb27SDimitry Andric /// Dominating assignemnt to each variable, indexed by VariableID. 1151bdd1243dSDimitry Andric AssignmentMap DebugValue; 1152bdd1243dSDimitry Andric /// Location kind for each variable. LiveLoc indicates whether the 1153bdd1243dSDimitry Andric /// dominating assignment in StackHomeValue (LocKind::Mem), DebugValue 1154bdd1243dSDimitry Andric /// (LocKind::Val), or neither (LocKind::None) is valid, in that order of 1155bdd1243dSDimitry Andric /// preference. This cannot be derived by inspecting DebugValue and 1156bdd1243dSDimitry Andric /// StackHomeValue due to the fact that there's no distinction in 1157bdd1243dSDimitry Andric /// Assignment (the class) between whether an assignment is unknown or a 1158bdd1243dSDimitry Andric /// merge of multiple assignments (both are Status::NoneOrPhi). In other 1159bdd1243dSDimitry Andric /// words, the memory location may well be valid while both DebugValue and 1160bdd1243dSDimitry Andric /// StackHomeValue contain Assignments that have a Status of NoneOrPhi. 116106c3fb27SDimitry Andric /// Indexed by VariableID. 1162bdd1243dSDimitry Andric LocMap LiveLoc; 1163bdd1243dSDimitry Andric 116406c3fb27SDimitry Andric public: 116506c3fb27SDimitry Andric enum AssignmentKind { Stack, Debug }; 116606c3fb27SDimitry Andric const AssignmentMap &getAssignmentMap(AssignmentKind Kind) const { 116706c3fb27SDimitry Andric switch (Kind) { 116806c3fb27SDimitry Andric case Stack: 116906c3fb27SDimitry Andric return StackHomeValue; 117006c3fb27SDimitry Andric case Debug: 117106c3fb27SDimitry Andric return DebugValue; 117206c3fb27SDimitry Andric } 117306c3fb27SDimitry Andric llvm_unreachable("Unknown AssignmentKind"); 117406c3fb27SDimitry Andric } 117506c3fb27SDimitry Andric AssignmentMap &getAssignmentMap(AssignmentKind Kind) { 117606c3fb27SDimitry Andric return const_cast<AssignmentMap &>( 117706c3fb27SDimitry Andric const_cast<const BlockInfo *>(this)->getAssignmentMap(Kind)); 117806c3fb27SDimitry Andric } 117906c3fb27SDimitry Andric 118006c3fb27SDimitry Andric bool isVariableTracked(VariableID Var) const { 118106c3fb27SDimitry Andric return VariableIDsInBlock[static_cast<unsigned>(Var)]; 118206c3fb27SDimitry Andric } 118306c3fb27SDimitry Andric 118406c3fb27SDimitry Andric const Assignment &getAssignment(AssignmentKind Kind, VariableID Var) const { 118506c3fb27SDimitry Andric assert(isVariableTracked(Var) && "Var not tracked in block"); 118606c3fb27SDimitry Andric return getAssignmentMap(Kind)[static_cast<unsigned>(Var)]; 118706c3fb27SDimitry Andric } 118806c3fb27SDimitry Andric 118906c3fb27SDimitry Andric LocKind getLocKind(VariableID Var) const { 119006c3fb27SDimitry Andric assert(isVariableTracked(Var) && "Var not tracked in block"); 119106c3fb27SDimitry Andric return LiveLoc[static_cast<unsigned>(Var)]; 119206c3fb27SDimitry Andric } 119306c3fb27SDimitry Andric 119406c3fb27SDimitry Andric /// Set LocKind for \p Var only: does not set LocKind for VariableIDs of 119506c3fb27SDimitry Andric /// fragments contained win \p Var. 119606c3fb27SDimitry Andric void setLocKind(VariableID Var, LocKind K) { 119706c3fb27SDimitry Andric VariableIDsInBlock.set(static_cast<unsigned>(Var)); 119806c3fb27SDimitry Andric LiveLoc[static_cast<unsigned>(Var)] = K; 119906c3fb27SDimitry Andric } 120006c3fb27SDimitry Andric 120106c3fb27SDimitry Andric /// Set the assignment in the \p Kind assignment map for \p Var only: does 120206c3fb27SDimitry Andric /// not set the assignment for VariableIDs of fragments contained win \p 120306c3fb27SDimitry Andric /// Var. 120406c3fb27SDimitry Andric void setAssignment(AssignmentKind Kind, VariableID Var, 120506c3fb27SDimitry Andric const Assignment &AV) { 120606c3fb27SDimitry Andric VariableIDsInBlock.set(static_cast<unsigned>(Var)); 120706c3fb27SDimitry Andric getAssignmentMap(Kind)[static_cast<unsigned>(Var)] = AV; 120806c3fb27SDimitry Andric } 120906c3fb27SDimitry Andric 121006c3fb27SDimitry Andric /// Return true if there is an assignment matching \p AV in the \p Kind 121106c3fb27SDimitry Andric /// assignment map. Does consider assignments for VariableIDs of fragments 121206c3fb27SDimitry Andric /// contained win \p Var. 121306c3fb27SDimitry Andric bool hasAssignment(AssignmentKind Kind, VariableID Var, 121406c3fb27SDimitry Andric const Assignment &AV) const { 121506c3fb27SDimitry Andric if (!isVariableTracked(Var)) 121606c3fb27SDimitry Andric return false; 121706c3fb27SDimitry Andric return AV.isSameSourceAssignment(getAssignment(Kind, Var)); 121806c3fb27SDimitry Andric } 121906c3fb27SDimitry Andric 1220bdd1243dSDimitry Andric /// Compare every element in each map to determine structural equality 1221bdd1243dSDimitry Andric /// (slow). 1222bdd1243dSDimitry Andric bool operator==(const BlockInfo &Other) const { 122306c3fb27SDimitry Andric return VariableIDsInBlock == Other.VariableIDsInBlock && 122406c3fb27SDimitry Andric LiveLoc == Other.LiveLoc && 122506c3fb27SDimitry Andric mapsAreEqual(VariableIDsInBlock, StackHomeValue, 122606c3fb27SDimitry Andric Other.StackHomeValue) && 122706c3fb27SDimitry Andric mapsAreEqual(VariableIDsInBlock, DebugValue, Other.DebugValue); 1228bdd1243dSDimitry Andric } 1229bdd1243dSDimitry Andric bool operator!=(const BlockInfo &Other) const { return !(*this == Other); } 1230bdd1243dSDimitry Andric bool isValid() { 1231bdd1243dSDimitry Andric return LiveLoc.size() == DebugValue.size() && 1232bdd1243dSDimitry Andric LiveLoc.size() == StackHomeValue.size(); 1233bdd1243dSDimitry Andric } 123406c3fb27SDimitry Andric 123506c3fb27SDimitry Andric /// Clear everything and initialise with ⊤-values for all variables. 123606c3fb27SDimitry Andric void init(int NumVars) { 123706c3fb27SDimitry Andric StackHomeValue.clear(); 123806c3fb27SDimitry Andric DebugValue.clear(); 123906c3fb27SDimitry Andric LiveLoc.clear(); 124006c3fb27SDimitry Andric VariableIDsInBlock = BitVector(NumVars); 124106c3fb27SDimitry Andric StackHomeValue.insert(StackHomeValue.begin(), NumVars, 124206c3fb27SDimitry Andric Assignment::makeNoneOrPhi()); 124306c3fb27SDimitry Andric DebugValue.insert(DebugValue.begin(), NumVars, 124406c3fb27SDimitry Andric Assignment::makeNoneOrPhi()); 124506c3fb27SDimitry Andric LiveLoc.insert(LiveLoc.begin(), NumVars, LocKind::None); 124606c3fb27SDimitry Andric } 124706c3fb27SDimitry Andric 124806c3fb27SDimitry Andric /// Helper for join. 124906c3fb27SDimitry Andric template <typename ElmtType, typename FnInputType> 125006c3fb27SDimitry Andric static void joinElmt(int Index, SmallVector<ElmtType> &Target, 125106c3fb27SDimitry Andric const SmallVector<ElmtType> &A, 125206c3fb27SDimitry Andric const SmallVector<ElmtType> &B, 125306c3fb27SDimitry Andric ElmtType (*Fn)(FnInputType, FnInputType)) { 125406c3fb27SDimitry Andric Target[Index] = Fn(A[Index], B[Index]); 125506c3fb27SDimitry Andric } 125606c3fb27SDimitry Andric 125706c3fb27SDimitry Andric /// See comment for AssignmentTrackingLowering::joinBlockInfo. 125806c3fb27SDimitry Andric static BlockInfo join(const BlockInfo &A, const BlockInfo &B, int NumVars) { 125906c3fb27SDimitry Andric // Join A and B. 126006c3fb27SDimitry Andric // 126106c3fb27SDimitry Andric // Intersect = join(a, b) for a in A, b in B where Var(a) == Var(b) 126206c3fb27SDimitry Andric // Difference = join(x, ⊤) for x where Var(x) is in A xor B 126306c3fb27SDimitry Andric // Join = Intersect ∪ Difference 126406c3fb27SDimitry Andric // 126506c3fb27SDimitry Andric // This is achieved by performing a join on elements from A and B with 126606c3fb27SDimitry Andric // variables common to both A and B (join elements indexed by var 126706c3fb27SDimitry Andric // intersect), then adding ⊤-value elements for vars in A xor B. The 126806c3fb27SDimitry Andric // latter part is equivalent to performing join on elements with variables 126906c3fb27SDimitry Andric // in A xor B with the ⊤-value for the map element since join(x, ⊤) = ⊤. 127006c3fb27SDimitry Andric // BlockInfo::init initializes all variable entries to the ⊤ value so we 127106c3fb27SDimitry Andric // don't need to explicitly perform that step as Join.VariableIDsInBlock 127206c3fb27SDimitry Andric // is set to the union of the variables in A and B at the end of this 127306c3fb27SDimitry Andric // function. 127406c3fb27SDimitry Andric BlockInfo Join; 127506c3fb27SDimitry Andric Join.init(NumVars); 127606c3fb27SDimitry Andric 127706c3fb27SDimitry Andric BitVector Intersect = A.VariableIDsInBlock; 127806c3fb27SDimitry Andric Intersect &= B.VariableIDsInBlock; 127906c3fb27SDimitry Andric 128006c3fb27SDimitry Andric for (auto VarID : Intersect.set_bits()) { 128106c3fb27SDimitry Andric joinElmt(VarID, Join.LiveLoc, A.LiveLoc, B.LiveLoc, joinKind); 128206c3fb27SDimitry Andric joinElmt(VarID, Join.DebugValue, A.DebugValue, B.DebugValue, 128306c3fb27SDimitry Andric joinAssignment); 128406c3fb27SDimitry Andric joinElmt(VarID, Join.StackHomeValue, A.StackHomeValue, B.StackHomeValue, 128506c3fb27SDimitry Andric joinAssignment); 128606c3fb27SDimitry Andric } 128706c3fb27SDimitry Andric 128806c3fb27SDimitry Andric Join.VariableIDsInBlock = A.VariableIDsInBlock; 128906c3fb27SDimitry Andric Join.VariableIDsInBlock |= B.VariableIDsInBlock; 129006c3fb27SDimitry Andric assert(Join.isValid()); 129106c3fb27SDimitry Andric return Join; 129206c3fb27SDimitry Andric } 1293bdd1243dSDimitry Andric }; 1294bdd1243dSDimitry Andric 1295bdd1243dSDimitry Andric Function &Fn; 1296bdd1243dSDimitry Andric const DataLayout &Layout; 1297bdd1243dSDimitry Andric const DenseSet<DebugAggregate> *VarsWithStackSlot; 1298bdd1243dSDimitry Andric FunctionVarLocsBuilder *FnVarLocs; 1299bdd1243dSDimitry Andric DenseMap<const BasicBlock *, BlockInfo> LiveIn; 1300bdd1243dSDimitry Andric DenseMap<const BasicBlock *, BlockInfo> LiveOut; 1301bdd1243dSDimitry Andric 1302bdd1243dSDimitry Andric /// Helper for process methods to track variables touched each frame. 1303bdd1243dSDimitry Andric DenseSet<VariableID> VarsTouchedThisFrame; 1304bdd1243dSDimitry Andric 1305bdd1243dSDimitry Andric /// The set of variables that sometimes are not located in their stack home. 1306bdd1243dSDimitry Andric DenseSet<DebugAggregate> NotAlwaysStackHomed; 1307bdd1243dSDimitry Andric 1308bdd1243dSDimitry Andric VariableID getVariableID(const DebugVariable &Var) { 1309bdd1243dSDimitry Andric return static_cast<VariableID>(FnVarLocs->insertVariable(Var)); 1310bdd1243dSDimitry Andric } 1311bdd1243dSDimitry Andric 1312bdd1243dSDimitry Andric /// Join the LiveOut values of preds that are contained in \p Visited into 1313bdd1243dSDimitry Andric /// LiveIn[BB]. Return True if LiveIn[BB] has changed as a result. LiveIn[BB] 1314bdd1243dSDimitry Andric /// values monotonically increase. See the @link joinMethods join methods 1315bdd1243dSDimitry Andric /// @endlink documentation for more info. 1316bdd1243dSDimitry Andric bool join(const BasicBlock &BB, const SmallPtrSet<BasicBlock *, 16> &Visited); 1317bdd1243dSDimitry Andric ///@name joinMethods 1318bdd1243dSDimitry Andric /// Functions that implement `join` (the least upper bound) for the 1319bdd1243dSDimitry Andric /// join-semilattice types used in the dataflow. There is an explicit bottom 1320bdd1243dSDimitry Andric /// value (⊥) for some types and and explicit top value (⊤) for all types. 1321bdd1243dSDimitry Andric /// By definition: 1322bdd1243dSDimitry Andric /// 1323bdd1243dSDimitry Andric /// Join(A, B) >= A && Join(A, B) >= B 1324bdd1243dSDimitry Andric /// Join(A, ⊥) = A 1325bdd1243dSDimitry Andric /// Join(A, ⊤) = ⊤ 1326bdd1243dSDimitry Andric /// 1327bdd1243dSDimitry Andric /// These invariants are important for monotonicity. 1328bdd1243dSDimitry Andric /// 1329bdd1243dSDimitry Andric /// For the map-type functions, all unmapped keys in an empty map are 1330bdd1243dSDimitry Andric /// associated with a bottom value (⊥). This represents their values being 1331bdd1243dSDimitry Andric /// unknown. Unmapped keys in non-empty maps (joining two maps with a key 1332bdd1243dSDimitry Andric /// only present in one) represents either a variable going out of scope or 1333bdd1243dSDimitry Andric /// dropped debug info. It is assumed the key is associated with a top value 1334bdd1243dSDimitry Andric /// (⊤) in this case (unknown location / assignment). 1335bdd1243dSDimitry Andric ///@{ 1336bdd1243dSDimitry Andric static LocKind joinKind(LocKind A, LocKind B); 1337bdd1243dSDimitry Andric static Assignment joinAssignment(const Assignment &A, const Assignment &B); 133806c3fb27SDimitry Andric BlockInfo joinBlockInfo(const BlockInfo &A, const BlockInfo &B); 1339bdd1243dSDimitry Andric ///@} 1340bdd1243dSDimitry Andric 1341bdd1243dSDimitry Andric /// Process the instructions in \p BB updating \p LiveSet along the way. \p 1342bdd1243dSDimitry Andric /// LiveSet must be initialized with the current live-in locations before 1343bdd1243dSDimitry Andric /// calling this. 1344bdd1243dSDimitry Andric void process(BasicBlock &BB, BlockInfo *LiveSet); 1345bdd1243dSDimitry Andric ///@name processMethods 1346bdd1243dSDimitry Andric /// Methods to process instructions in order to update the LiveSet (current 1347bdd1243dSDimitry Andric /// location information). 1348bdd1243dSDimitry Andric ///@{ 1349bdd1243dSDimitry Andric void processNonDbgInstruction(Instruction &I, BlockInfo *LiveSet); 135006c3fb27SDimitry Andric void processDbgInstruction(DbgInfoIntrinsic &I, BlockInfo *LiveSet); 1351bdd1243dSDimitry Andric /// Update \p LiveSet after encountering an instruction with a DIAssignID 1352bdd1243dSDimitry Andric /// attachment, \p I. 1353bdd1243dSDimitry Andric void processTaggedInstruction(Instruction &I, BlockInfo *LiveSet); 1354bdd1243dSDimitry Andric /// Update \p LiveSet after encountering an instruciton without a DIAssignID 1355bdd1243dSDimitry Andric /// attachment, \p I. 1356bdd1243dSDimitry Andric void processUntaggedInstruction(Instruction &I, BlockInfo *LiveSet); 13577a6dacacSDimitry Andric void processDbgAssign(AssignRecord Assign, BlockInfo *LiveSet); 1358*0fca6ea1SDimitry Andric void processDbgVariableRecord(DbgVariableRecord &DVR, BlockInfo *LiveSet); 1359*0fca6ea1SDimitry Andric void processDbgValue( 1360*0fca6ea1SDimitry Andric PointerUnion<DbgValueInst *, DbgVariableRecord *> DbgValueRecord, 13617a6dacacSDimitry Andric BlockInfo *LiveSet); 1362bdd1243dSDimitry Andric /// Add an assignment to memory for the variable /p Var. 1363bdd1243dSDimitry Andric void addMemDef(BlockInfo *LiveSet, VariableID Var, const Assignment &AV); 1364bdd1243dSDimitry Andric /// Add an assignment to the variable /p Var. 1365bdd1243dSDimitry Andric void addDbgDef(BlockInfo *LiveSet, VariableID Var, const Assignment &AV); 1366bdd1243dSDimitry Andric ///@} 1367bdd1243dSDimitry Andric 1368bdd1243dSDimitry Andric /// Set the LocKind for \p Var. 1369bdd1243dSDimitry Andric void setLocKind(BlockInfo *LiveSet, VariableID Var, LocKind K); 1370bdd1243dSDimitry Andric /// Get the live LocKind for a \p Var. Requires addMemDef or addDbgDef to 1371bdd1243dSDimitry Andric /// have been called for \p Var first. 1372bdd1243dSDimitry Andric LocKind getLocKind(BlockInfo *LiveSet, VariableID Var); 1373bdd1243dSDimitry Andric /// Return true if \p Var has an assignment in \p M matching \p AV. 137406c3fb27SDimitry Andric bool hasVarWithAssignment(BlockInfo *LiveSet, BlockInfo::AssignmentKind Kind, 137506c3fb27SDimitry Andric VariableID Var, const Assignment &AV); 137606c3fb27SDimitry Andric /// Return the set of VariableIDs corresponding the fragments contained fully 137706c3fb27SDimitry Andric /// within the variable/fragment \p Var. 137806c3fb27SDimitry Andric ArrayRef<VariableID> getContainedFragments(VariableID Var) const; 137906c3fb27SDimitry Andric 138006c3fb27SDimitry Andric /// Mark \p Var as having been touched this frame. Note, this applies only 138106c3fb27SDimitry Andric /// to the exact fragment \p Var and not to any fragments contained within. 138206c3fb27SDimitry Andric void touchFragment(VariableID Var); 1383bdd1243dSDimitry Andric 1384bdd1243dSDimitry Andric /// Emit info for variables that are fully promoted. 1385bdd1243dSDimitry Andric bool emitPromotedVarLocs(FunctionVarLocsBuilder *FnVarLocs); 1386bdd1243dSDimitry Andric 1387bdd1243dSDimitry Andric public: 1388bdd1243dSDimitry Andric AssignmentTrackingLowering(Function &Fn, const DataLayout &Layout, 1389bdd1243dSDimitry Andric const DenseSet<DebugAggregate> *VarsWithStackSlot) 1390bdd1243dSDimitry Andric : Fn(Fn), Layout(Layout), VarsWithStackSlot(VarsWithStackSlot) {} 1391bdd1243dSDimitry Andric /// Run the analysis, adding variable location info to \p FnVarLocs. Returns 1392bdd1243dSDimitry Andric /// true if any variable locations have been added to FnVarLocs. 1393bdd1243dSDimitry Andric bool run(FunctionVarLocsBuilder *FnVarLocs); 1394bdd1243dSDimitry Andric }; 1395bdd1243dSDimitry Andric } // namespace 1396bdd1243dSDimitry Andric 139706c3fb27SDimitry Andric ArrayRef<VariableID> 139806c3fb27SDimitry Andric AssignmentTrackingLowering::getContainedFragments(VariableID Var) const { 139906c3fb27SDimitry Andric auto R = VarContains.find(Var); 140006c3fb27SDimitry Andric if (R == VarContains.end()) 140106c3fb27SDimitry Andric return std::nullopt; 140206c3fb27SDimitry Andric return R->second; 140306c3fb27SDimitry Andric } 140406c3fb27SDimitry Andric 140506c3fb27SDimitry Andric void AssignmentTrackingLowering::touchFragment(VariableID Var) { 140606c3fb27SDimitry Andric VarsTouchedThisFrame.insert(Var); 140706c3fb27SDimitry Andric } 140806c3fb27SDimitry Andric 1409bdd1243dSDimitry Andric void AssignmentTrackingLowering::setLocKind(BlockInfo *LiveSet, VariableID Var, 1410bdd1243dSDimitry Andric LocKind K) { 1411bdd1243dSDimitry Andric auto SetKind = [this](BlockInfo *LiveSet, VariableID Var, LocKind K) { 141206c3fb27SDimitry Andric LiveSet->setLocKind(Var, K); 141306c3fb27SDimitry Andric touchFragment(Var); 1414bdd1243dSDimitry Andric }; 1415bdd1243dSDimitry Andric SetKind(LiveSet, Var, K); 1416bdd1243dSDimitry Andric 1417bdd1243dSDimitry Andric // Update the LocKind for all fragments contained within Var. 141806c3fb27SDimitry Andric for (VariableID Frag : getContainedFragments(Var)) 1419bdd1243dSDimitry Andric SetKind(LiveSet, Frag, K); 1420bdd1243dSDimitry Andric } 1421bdd1243dSDimitry Andric 1422bdd1243dSDimitry Andric AssignmentTrackingLowering::LocKind 1423bdd1243dSDimitry Andric AssignmentTrackingLowering::getLocKind(BlockInfo *LiveSet, VariableID Var) { 142406c3fb27SDimitry Andric return LiveSet->getLocKind(Var); 1425bdd1243dSDimitry Andric } 1426bdd1243dSDimitry Andric 1427bdd1243dSDimitry Andric void AssignmentTrackingLowering::addMemDef(BlockInfo *LiveSet, VariableID Var, 1428bdd1243dSDimitry Andric const Assignment &AV) { 142906c3fb27SDimitry Andric LiveSet->setAssignment(BlockInfo::Stack, Var, AV); 1430bdd1243dSDimitry Andric 1431bdd1243dSDimitry Andric // Use this assigment for all fragments contained within Var, but do not 1432bdd1243dSDimitry Andric // provide a Source because we cannot convert Var's value to a value for the 1433bdd1243dSDimitry Andric // fragment. 1434bdd1243dSDimitry Andric Assignment FragAV = AV; 1435bdd1243dSDimitry Andric FragAV.Source = nullptr; 143606c3fb27SDimitry Andric for (VariableID Frag : getContainedFragments(Var)) 143706c3fb27SDimitry Andric LiveSet->setAssignment(BlockInfo::Stack, Frag, FragAV); 1438bdd1243dSDimitry Andric } 1439bdd1243dSDimitry Andric 1440bdd1243dSDimitry Andric void AssignmentTrackingLowering::addDbgDef(BlockInfo *LiveSet, VariableID Var, 1441bdd1243dSDimitry Andric const Assignment &AV) { 144206c3fb27SDimitry Andric LiveSet->setAssignment(BlockInfo::Debug, Var, AV); 1443bdd1243dSDimitry Andric 1444bdd1243dSDimitry Andric // Use this assigment for all fragments contained within Var, but do not 1445bdd1243dSDimitry Andric // provide a Source because we cannot convert Var's value to a value for the 1446bdd1243dSDimitry Andric // fragment. 1447bdd1243dSDimitry Andric Assignment FragAV = AV; 1448bdd1243dSDimitry Andric FragAV.Source = nullptr; 144906c3fb27SDimitry Andric for (VariableID Frag : getContainedFragments(Var)) 145006c3fb27SDimitry Andric LiveSet->setAssignment(BlockInfo::Debug, Frag, FragAV); 1451bdd1243dSDimitry Andric } 1452bdd1243dSDimitry Andric 1453bdd1243dSDimitry Andric static DIAssignID *getIDFromInst(const Instruction &I) { 1454bdd1243dSDimitry Andric return cast<DIAssignID>(I.getMetadata(LLVMContext::MD_DIAssignID)); 1455bdd1243dSDimitry Andric } 1456bdd1243dSDimitry Andric 1457bdd1243dSDimitry Andric static DIAssignID *getIDFromMarker(const DbgAssignIntrinsic &DAI) { 1458bdd1243dSDimitry Andric return cast<DIAssignID>(DAI.getAssignID()); 1459bdd1243dSDimitry Andric } 1460bdd1243dSDimitry Andric 1461*0fca6ea1SDimitry Andric static DIAssignID *getIDFromMarker(const DbgVariableRecord &DVR) { 1462*0fca6ea1SDimitry Andric assert(DVR.isDbgAssign() && 1463*0fca6ea1SDimitry Andric "Cannot get a DIAssignID from a non-assign DbgVariableRecord!"); 1464*0fca6ea1SDimitry Andric return DVR.getAssignID(); 14657a6dacacSDimitry Andric } 14667a6dacacSDimitry Andric 1467bdd1243dSDimitry Andric /// Return true if \p Var has an assignment in \p M matching \p AV. 146806c3fb27SDimitry Andric bool AssignmentTrackingLowering::hasVarWithAssignment( 146906c3fb27SDimitry Andric BlockInfo *LiveSet, BlockInfo::AssignmentKind Kind, VariableID Var, 147006c3fb27SDimitry Andric const Assignment &AV) { 147106c3fb27SDimitry Andric if (!LiveSet->hasAssignment(Kind, Var, AV)) 1472bdd1243dSDimitry Andric return false; 1473bdd1243dSDimitry Andric 1474bdd1243dSDimitry Andric // Check all the frags contained within Var as these will have all been 1475bdd1243dSDimitry Andric // mapped to AV at the last store to Var. 147606c3fb27SDimitry Andric for (VariableID Frag : getContainedFragments(Var)) 147706c3fb27SDimitry Andric if (!LiveSet->hasAssignment(Kind, Frag, AV)) 1478bdd1243dSDimitry Andric return false; 1479bdd1243dSDimitry Andric return true; 1480bdd1243dSDimitry Andric } 1481bdd1243dSDimitry Andric 1482bdd1243dSDimitry Andric #ifndef NDEBUG 1483bdd1243dSDimitry Andric const char *locStr(AssignmentTrackingLowering::LocKind Loc) { 1484bdd1243dSDimitry Andric using LocKind = AssignmentTrackingLowering::LocKind; 1485bdd1243dSDimitry Andric switch (Loc) { 1486bdd1243dSDimitry Andric case LocKind::Val: 1487bdd1243dSDimitry Andric return "Val"; 1488bdd1243dSDimitry Andric case LocKind::Mem: 1489bdd1243dSDimitry Andric return "Mem"; 1490bdd1243dSDimitry Andric case LocKind::None: 1491bdd1243dSDimitry Andric return "None"; 1492bdd1243dSDimitry Andric }; 1493bdd1243dSDimitry Andric llvm_unreachable("unknown LocKind"); 1494bdd1243dSDimitry Andric } 1495bdd1243dSDimitry Andric #endif 1496bdd1243dSDimitry Andric 1497*0fca6ea1SDimitry Andric VarLocInsertPt getNextNode(const DbgRecord *DVR) { 1498*0fca6ea1SDimitry Andric auto NextIt = ++(DVR->getIterator()); 1499*0fca6ea1SDimitry Andric if (NextIt == DVR->getMarker()->getDbgRecordRange().end()) 1500*0fca6ea1SDimitry Andric return DVR->getMarker()->MarkedInstr; 15017a6dacacSDimitry Andric return &*NextIt; 15027a6dacacSDimitry Andric } 15037a6dacacSDimitry Andric VarLocInsertPt getNextNode(const Instruction *Inst) { 15047a6dacacSDimitry Andric const Instruction *Next = Inst->getNextNode(); 1505*0fca6ea1SDimitry Andric if (!Next->hasDbgRecords()) 15067a6dacacSDimitry Andric return Next; 1507*0fca6ea1SDimitry Andric return &*Next->getDbgRecordRange().begin(); 15087a6dacacSDimitry Andric } 15097a6dacacSDimitry Andric VarLocInsertPt getNextNode(VarLocInsertPt InsertPt) { 15107a6dacacSDimitry Andric if (isa<const Instruction *>(InsertPt)) 15117a6dacacSDimitry Andric return getNextNode(cast<const Instruction *>(InsertPt)); 1512*0fca6ea1SDimitry Andric return getNextNode(cast<const DbgRecord *>(InsertPt)); 15137a6dacacSDimitry Andric } 15147a6dacacSDimitry Andric 15157a6dacacSDimitry Andric DbgAssignIntrinsic *CastToDbgAssign(DbgVariableIntrinsic *DVI) { 15167a6dacacSDimitry Andric return cast<DbgAssignIntrinsic>(DVI); 15177a6dacacSDimitry Andric } 15187a6dacacSDimitry Andric 1519*0fca6ea1SDimitry Andric DbgVariableRecord *CastToDbgAssign(DbgVariableRecord *DVR) { 1520*0fca6ea1SDimitry Andric assert(DVR->isDbgAssign() && 1521*0fca6ea1SDimitry Andric "Attempted to cast non-assign DbgVariableRecord to DVRAssign."); 1522*0fca6ea1SDimitry Andric return DVR; 15237a6dacacSDimitry Andric } 15247a6dacacSDimitry Andric 1525bdd1243dSDimitry Andric void AssignmentTrackingLowering::emitDbgValue( 1526bdd1243dSDimitry Andric AssignmentTrackingLowering::LocKind Kind, 15277a6dacacSDimitry Andric AssignmentTrackingLowering::AssignRecord Source, VarLocInsertPt After) { 15287a6dacacSDimitry Andric if (isa<DbgAssignIntrinsic *>(Source)) 15297a6dacacSDimitry Andric emitDbgValue(Kind, cast<DbgAssignIntrinsic *>(Source), After); 15307a6dacacSDimitry Andric else 1531*0fca6ea1SDimitry Andric emitDbgValue(Kind, cast<DbgVariableRecord *>(Source), After); 15327a6dacacSDimitry Andric } 15337a6dacacSDimitry Andric template <typename T> 15347a6dacacSDimitry Andric void AssignmentTrackingLowering::emitDbgValue( 15357a6dacacSDimitry Andric AssignmentTrackingLowering::LocKind Kind, const T Source, 15367a6dacacSDimitry Andric VarLocInsertPt After) { 1537bdd1243dSDimitry Andric 1538bdd1243dSDimitry Andric DILocation *DL = Source->getDebugLoc(); 153906c3fb27SDimitry Andric auto Emit = [this, Source, After, DL](Metadata *Val, DIExpression *Expr) { 1540bdd1243dSDimitry Andric assert(Expr); 1541bdd1243dSDimitry Andric if (!Val) 154206c3fb27SDimitry Andric Val = ValueAsMetadata::get( 154306c3fb27SDimitry Andric PoisonValue::get(Type::getInt1Ty(Source->getContext()))); 1544bdd1243dSDimitry Andric 1545bdd1243dSDimitry Andric // Find a suitable insert point. 15467a6dacacSDimitry Andric auto InsertBefore = getNextNode(After); 1547bdd1243dSDimitry Andric assert(InsertBefore && "Shouldn't be inserting after a terminator"); 1548bdd1243dSDimitry Andric 1549bdd1243dSDimitry Andric VariableID Var = getVariableID(DebugVariable(Source)); 1550bdd1243dSDimitry Andric VarLocInfo VarLoc; 1551bdd1243dSDimitry Andric VarLoc.VariableID = static_cast<VariableID>(Var); 1552bdd1243dSDimitry Andric VarLoc.Expr = Expr; 155306c3fb27SDimitry Andric VarLoc.Values = RawLocationWrapper(Val); 1554bdd1243dSDimitry Andric VarLoc.DL = DL; 1555bdd1243dSDimitry Andric // Insert it into the map for later. 1556bdd1243dSDimitry Andric InsertBeforeMap[InsertBefore].push_back(VarLoc); 1557bdd1243dSDimitry Andric }; 1558bdd1243dSDimitry Andric 1559bdd1243dSDimitry Andric // NOTE: This block can mutate Kind. 1560bdd1243dSDimitry Andric if (Kind == LocKind::Mem) { 15617a6dacacSDimitry Andric const auto *Assign = CastToDbgAssign(Source); 1562bdd1243dSDimitry Andric // Check the address hasn't been dropped (e.g. the debug uses may not have 1563bdd1243dSDimitry Andric // been replaced before deleting a Value). 15647a6dacacSDimitry Andric if (Assign->isKillAddress()) { 1565bdd1243dSDimitry Andric // The address isn't valid so treat this as a non-memory def. 1566bdd1243dSDimitry Andric Kind = LocKind::Val; 1567bdd1243dSDimitry Andric } else { 15687a6dacacSDimitry Andric Value *Val = Assign->getAddress(); 15697a6dacacSDimitry Andric DIExpression *Expr = Assign->getAddressExpression(); 1570bdd1243dSDimitry Andric assert(!Expr->getFragmentInfo() && 1571bdd1243dSDimitry Andric "fragment info should be stored in value-expression only"); 1572bdd1243dSDimitry Andric // Copy the fragment info over from the value-expression to the new 1573bdd1243dSDimitry Andric // DIExpression. 1574bdd1243dSDimitry Andric if (auto OptFragInfo = Source->getExpression()->getFragmentInfo()) { 1575bdd1243dSDimitry Andric auto FragInfo = *OptFragInfo; 1576bdd1243dSDimitry Andric Expr = *DIExpression::createFragmentExpression( 1577bdd1243dSDimitry Andric Expr, FragInfo.OffsetInBits, FragInfo.SizeInBits); 1578bdd1243dSDimitry Andric } 1579bdd1243dSDimitry Andric // The address-expression has an implicit deref, add it now. 1580bdd1243dSDimitry Andric std::tie(Val, Expr) = 1581bdd1243dSDimitry Andric walkToAllocaAndPrependOffsetDeref(Layout, Val, Expr); 158206c3fb27SDimitry Andric Emit(ValueAsMetadata::get(Val), Expr); 1583bdd1243dSDimitry Andric return; 1584bdd1243dSDimitry Andric } 1585bdd1243dSDimitry Andric } 1586bdd1243dSDimitry Andric 1587bdd1243dSDimitry Andric if (Kind == LocKind::Val) { 158806c3fb27SDimitry Andric Emit(Source->getRawLocation(), Source->getExpression()); 1589bdd1243dSDimitry Andric return; 1590bdd1243dSDimitry Andric } 1591bdd1243dSDimitry Andric 1592bdd1243dSDimitry Andric if (Kind == LocKind::None) { 1593bdd1243dSDimitry Andric Emit(nullptr, Source->getExpression()); 1594bdd1243dSDimitry Andric return; 1595bdd1243dSDimitry Andric } 1596bdd1243dSDimitry Andric } 1597bdd1243dSDimitry Andric 1598bdd1243dSDimitry Andric void AssignmentTrackingLowering::processNonDbgInstruction( 1599bdd1243dSDimitry Andric Instruction &I, AssignmentTrackingLowering::BlockInfo *LiveSet) { 1600bdd1243dSDimitry Andric if (I.hasMetadata(LLVMContext::MD_DIAssignID)) 1601bdd1243dSDimitry Andric processTaggedInstruction(I, LiveSet); 1602bdd1243dSDimitry Andric else 1603bdd1243dSDimitry Andric processUntaggedInstruction(I, LiveSet); 1604bdd1243dSDimitry Andric } 1605bdd1243dSDimitry Andric 1606bdd1243dSDimitry Andric void AssignmentTrackingLowering::processUntaggedInstruction( 1607bdd1243dSDimitry Andric Instruction &I, AssignmentTrackingLowering::BlockInfo *LiveSet) { 1608bdd1243dSDimitry Andric // Interpret stack stores that are not tagged as an assignment in memory for 1609bdd1243dSDimitry Andric // the variables associated with that address. These stores may not be tagged 1610bdd1243dSDimitry Andric // because a) the store cannot be represented using dbg.assigns (non-const 1611bdd1243dSDimitry Andric // length or offset) or b) the tag was accidentally dropped during 1612bdd1243dSDimitry Andric // optimisations. For these stores we fall back to assuming that the stack 1613bdd1243dSDimitry Andric // home is a valid location for the variables. The benefit is that this 1614bdd1243dSDimitry Andric // prevents us missing an assignment and therefore incorrectly maintaining 1615bdd1243dSDimitry Andric // earlier location definitions, and in many cases it should be a reasonable 1616bdd1243dSDimitry Andric // assumption. However, this will occasionally lead to slight 1617bdd1243dSDimitry Andric // inaccuracies. The value of a hoisted untagged store will be visible 1618bdd1243dSDimitry Andric // "early", for example. 1619bdd1243dSDimitry Andric assert(!I.hasMetadata(LLVMContext::MD_DIAssignID)); 1620bdd1243dSDimitry Andric auto It = UntaggedStoreVars.find(&I); 1621bdd1243dSDimitry Andric if (It == UntaggedStoreVars.end()) 1622bdd1243dSDimitry Andric return; // No variables associated with the store destination. 1623bdd1243dSDimitry Andric 1624bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "processUntaggedInstruction on UNTAGGED INST " << I 1625bdd1243dSDimitry Andric << "\n"); 1626bdd1243dSDimitry Andric // Iterate over the variables that this store affects, add a NoneOrPhi dbg 1627bdd1243dSDimitry Andric // and mem def, set lockind to Mem, and emit a location def for each. 1628bdd1243dSDimitry Andric for (auto [Var, Info] : It->second) { 1629bdd1243dSDimitry Andric // This instruction is treated as both a debug and memory assignment, 1630bdd1243dSDimitry Andric // meaning the memory location should be used. We don't have an assignment 1631bdd1243dSDimitry Andric // ID though so use Assignment::makeNoneOrPhi() to create an imaginary one. 1632bdd1243dSDimitry Andric addMemDef(LiveSet, Var, Assignment::makeNoneOrPhi()); 1633bdd1243dSDimitry Andric addDbgDef(LiveSet, Var, Assignment::makeNoneOrPhi()); 1634bdd1243dSDimitry Andric setLocKind(LiveSet, Var, LocKind::Mem); 1635bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << " setting Stack LocKind to: " << locStr(LocKind::Mem) 1636bdd1243dSDimitry Andric << "\n"); 1637bdd1243dSDimitry Andric // Build the dbg location def to insert. 1638bdd1243dSDimitry Andric // 1639bdd1243dSDimitry Andric // DIExpression: Add fragment and offset. 1640bdd1243dSDimitry Andric DebugVariable V = FnVarLocs->getVariable(Var); 1641bdd1243dSDimitry Andric DIExpression *DIE = DIExpression::get(I.getContext(), std::nullopt); 1642bdd1243dSDimitry Andric if (auto Frag = V.getFragment()) { 1643bdd1243dSDimitry Andric auto R = DIExpression::createFragmentExpression(DIE, Frag->OffsetInBits, 1644bdd1243dSDimitry Andric Frag->SizeInBits); 1645bdd1243dSDimitry Andric assert(R && "unexpected createFragmentExpression failure"); 1646bdd1243dSDimitry Andric DIE = *R; 1647bdd1243dSDimitry Andric } 1648bdd1243dSDimitry Andric SmallVector<uint64_t, 3> Ops; 1649bdd1243dSDimitry Andric if (Info.OffsetInBits) 1650bdd1243dSDimitry Andric Ops = {dwarf::DW_OP_plus_uconst, Info.OffsetInBits / 8}; 1651bdd1243dSDimitry Andric Ops.push_back(dwarf::DW_OP_deref); 1652bdd1243dSDimitry Andric DIE = DIExpression::prependOpcodes(DIE, Ops, /*StackValue=*/false, 1653bdd1243dSDimitry Andric /*EntryValue=*/false); 1654*0fca6ea1SDimitry Andric // Find a suitable insert point, before the next instruction or DbgRecord 16557a6dacacSDimitry Andric // after I. 16567a6dacacSDimitry Andric auto InsertBefore = getNextNode(&I); 1657bdd1243dSDimitry Andric assert(InsertBefore && "Shouldn't be inserting after a terminator"); 1658bdd1243dSDimitry Andric 1659bdd1243dSDimitry Andric // Get DILocation for this unrecorded assignment. 1660bdd1243dSDimitry Andric DILocation *InlinedAt = const_cast<DILocation *>(V.getInlinedAt()); 1661bdd1243dSDimitry Andric const DILocation *DILoc = DILocation::get( 1662bdd1243dSDimitry Andric Fn.getContext(), 0, 0, V.getVariable()->getScope(), InlinedAt); 1663bdd1243dSDimitry Andric 1664bdd1243dSDimitry Andric VarLocInfo VarLoc; 1665bdd1243dSDimitry Andric VarLoc.VariableID = static_cast<VariableID>(Var); 1666bdd1243dSDimitry Andric VarLoc.Expr = DIE; 166706c3fb27SDimitry Andric VarLoc.Values = RawLocationWrapper( 166806c3fb27SDimitry Andric ValueAsMetadata::get(const_cast<AllocaInst *>(Info.Base))); 1669bdd1243dSDimitry Andric VarLoc.DL = DILoc; 1670bdd1243dSDimitry Andric // 3. Insert it into the map for later. 1671bdd1243dSDimitry Andric InsertBeforeMap[InsertBefore].push_back(VarLoc); 1672bdd1243dSDimitry Andric } 1673bdd1243dSDimitry Andric } 1674bdd1243dSDimitry Andric 1675bdd1243dSDimitry Andric void AssignmentTrackingLowering::processTaggedInstruction( 1676bdd1243dSDimitry Andric Instruction &I, AssignmentTrackingLowering::BlockInfo *LiveSet) { 1677bdd1243dSDimitry Andric auto Linked = at::getAssignmentMarkers(&I); 1678*0fca6ea1SDimitry Andric auto LinkedDPAssigns = at::getDVRAssignmentMarkers(&I); 1679bdd1243dSDimitry Andric // No dbg.assign intrinsics linked. 1680bdd1243dSDimitry Andric // FIXME: All vars that have a stack slot this store modifies that don't have 1681bdd1243dSDimitry Andric // a dbg.assign linked to it should probably treat this like an untagged 1682bdd1243dSDimitry Andric // store. 16837a6dacacSDimitry Andric if (Linked.empty() && LinkedDPAssigns.empty()) 1684bdd1243dSDimitry Andric return; 1685bdd1243dSDimitry Andric 1686bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "processTaggedInstruction on " << I << "\n"); 16877a6dacacSDimitry Andric auto ProcessLinkedAssign = [&](auto *Assign) { 16887a6dacacSDimitry Andric VariableID Var = getVariableID(DebugVariable(Assign)); 1689bdd1243dSDimitry Andric // Something has gone wrong if VarsWithStackSlot doesn't contain a variable 1690bdd1243dSDimitry Andric // that is linked to a store. 16917a6dacacSDimitry Andric assert(VarsWithStackSlot->count(getAggregate(Assign)) && 16927a6dacacSDimitry Andric "expected Assign's variable to have stack slot"); 1693bdd1243dSDimitry Andric 1694bdd1243dSDimitry Andric Assignment AV = Assignment::makeFromMemDef(getIDFromInst(I)); 1695bdd1243dSDimitry Andric addMemDef(LiveSet, Var, AV); 1696bdd1243dSDimitry Andric 16977a6dacacSDimitry Andric LLVM_DEBUG(dbgs() << " linked to " << *Assign << "\n"); 1698bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << " LiveLoc " << locStr(getLocKind(LiveSet, Var)) 1699bdd1243dSDimitry Andric << " -> "); 1700bdd1243dSDimitry Andric 1701bdd1243dSDimitry Andric // The last assignment to the stack is now AV. Check if the last debug 1702bdd1243dSDimitry Andric // assignment has a matching Assignment. 170306c3fb27SDimitry Andric if (hasVarWithAssignment(LiveSet, BlockInfo::Debug, Var, AV)) { 1704bdd1243dSDimitry Andric // The StackHomeValue and DebugValue for this variable match so we can 1705bdd1243dSDimitry Andric // emit a stack home location here. 1706bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "Mem, Stack matches Debug program\n";); 1707bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << " Stack val: "; AV.dump(dbgs()); dbgs() << "\n"); 1708bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << " Debug val: "; 170906c3fb27SDimitry Andric LiveSet->DebugValue[static_cast<unsigned>(Var)].dump(dbgs()); 171006c3fb27SDimitry Andric dbgs() << "\n"); 1711bdd1243dSDimitry Andric setLocKind(LiveSet, Var, LocKind::Mem); 17127a6dacacSDimitry Andric emitDbgValue(LocKind::Mem, Assign, &I); 17137a6dacacSDimitry Andric return; 1714bdd1243dSDimitry Andric } 1715bdd1243dSDimitry Andric 1716bdd1243dSDimitry Andric // The StackHomeValue and DebugValue for this variable do not match. I.e. 1717bdd1243dSDimitry Andric // The value currently stored in the stack is not what we'd expect to 1718bdd1243dSDimitry Andric // see, so we cannot use emit a stack home location here. Now we will 1719bdd1243dSDimitry Andric // look at the live LocKind for the variable and determine an appropriate 1720bdd1243dSDimitry Andric // dbg.value to emit. 1721bdd1243dSDimitry Andric LocKind PrevLoc = getLocKind(LiveSet, Var); 1722bdd1243dSDimitry Andric switch (PrevLoc) { 1723bdd1243dSDimitry Andric case LocKind::Val: { 1724bdd1243dSDimitry Andric // The value in memory in memory has changed but we're not currently 1725bdd1243dSDimitry Andric // using the memory location. Do nothing. 1726bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "Val, (unchanged)\n";); 1727bdd1243dSDimitry Andric setLocKind(LiveSet, Var, LocKind::Val); 1728bdd1243dSDimitry Andric } break; 1729bdd1243dSDimitry Andric case LocKind::Mem: { 1730bdd1243dSDimitry Andric // There's been an assignment to memory that we were using as a 1731bdd1243dSDimitry Andric // location for this variable, and the Assignment doesn't match what 1732bdd1243dSDimitry Andric // we'd expect to see in memory. 173306c3fb27SDimitry Andric Assignment DbgAV = LiveSet->getAssignment(BlockInfo::Debug, Var); 173406c3fb27SDimitry Andric if (DbgAV.Status == Assignment::NoneOrPhi) { 1735bdd1243dSDimitry Andric // We need to terminate any previously open location now. 1736bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "None, No Debug value available\n";); 1737bdd1243dSDimitry Andric setLocKind(LiveSet, Var, LocKind::None); 17387a6dacacSDimitry Andric emitDbgValue(LocKind::None, Assign, &I); 1739bdd1243dSDimitry Andric } else { 1740bdd1243dSDimitry Andric // The previous DebugValue Value can be used here. 1741bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "Val, Debug value is Known\n";); 1742bdd1243dSDimitry Andric setLocKind(LiveSet, Var, LocKind::Val); 174306c3fb27SDimitry Andric if (DbgAV.Source) { 174406c3fb27SDimitry Andric emitDbgValue(LocKind::Val, DbgAV.Source, &I); 1745bdd1243dSDimitry Andric } else { 1746bdd1243dSDimitry Andric // PrevAV.Source is nullptr so we must emit undef here. 17477a6dacacSDimitry Andric emitDbgValue(LocKind::None, Assign, &I); 1748bdd1243dSDimitry Andric } 1749bdd1243dSDimitry Andric } 1750bdd1243dSDimitry Andric } break; 1751bdd1243dSDimitry Andric case LocKind::None: { 1752bdd1243dSDimitry Andric // There's been an assignment to memory and we currently are 1753bdd1243dSDimitry Andric // not tracking a location for the variable. Do not emit anything. 1754bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "None, (unchanged)\n";); 1755bdd1243dSDimitry Andric setLocKind(LiveSet, Var, LocKind::None); 1756bdd1243dSDimitry Andric } break; 1757bdd1243dSDimitry Andric } 17587a6dacacSDimitry Andric }; 17597a6dacacSDimitry Andric for (DbgAssignIntrinsic *DAI : Linked) 17607a6dacacSDimitry Andric ProcessLinkedAssign(DAI); 1761*0fca6ea1SDimitry Andric for (DbgVariableRecord *DVR : LinkedDPAssigns) 1762*0fca6ea1SDimitry Andric ProcessLinkedAssign(DVR); 1763bdd1243dSDimitry Andric } 1764bdd1243dSDimitry Andric 17657a6dacacSDimitry Andric void AssignmentTrackingLowering::processDbgAssign(AssignRecord Assign, 1766bdd1243dSDimitry Andric BlockInfo *LiveSet) { 17677a6dacacSDimitry Andric auto ProcessDbgAssignImpl = [&](auto *DbgAssign) { 1768bdd1243dSDimitry Andric // Only bother tracking variables that are at some point stack homed. Other 1769bdd1243dSDimitry Andric // variables can be dealt with trivially later. 17707a6dacacSDimitry Andric if (!VarsWithStackSlot->count(getAggregate(DbgAssign))) 1771bdd1243dSDimitry Andric return; 1772bdd1243dSDimitry Andric 17737a6dacacSDimitry Andric VariableID Var = getVariableID(DebugVariable(DbgAssign)); 17747a6dacacSDimitry Andric Assignment AV = Assignment::make(getIDFromMarker(*DbgAssign), DbgAssign); 1775bdd1243dSDimitry Andric addDbgDef(LiveSet, Var, AV); 1776bdd1243dSDimitry Andric 17777a6dacacSDimitry Andric LLVM_DEBUG(dbgs() << "processDbgAssign on " << *DbgAssign << "\n";); 1778bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << " LiveLoc " << locStr(getLocKind(LiveSet, Var)) 1779bdd1243dSDimitry Andric << " -> "); 1780bdd1243dSDimitry Andric 1781bdd1243dSDimitry Andric // Check if the DebugValue and StackHomeValue both hold the same 1782bdd1243dSDimitry Andric // Assignment. 178306c3fb27SDimitry Andric if (hasVarWithAssignment(LiveSet, BlockInfo::Stack, Var, AV)) { 17847a6dacacSDimitry Andric // They match. We can use the stack home because the debug intrinsics 17857a6dacacSDimitry Andric // state that an assignment happened here, and we know that specific 17867a6dacacSDimitry Andric // assignment was the last one to take place in memory for this variable. 1787bdd1243dSDimitry Andric LocKind Kind; 17887a6dacacSDimitry Andric if (DbgAssign->isKillAddress()) { 1789bdd1243dSDimitry Andric LLVM_DEBUG( 1790bdd1243dSDimitry Andric dbgs() 1791bdd1243dSDimitry Andric << "Val, Stack matches Debug program but address is killed\n";); 1792bdd1243dSDimitry Andric Kind = LocKind::Val; 1793bdd1243dSDimitry Andric } else { 1794bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "Mem, Stack matches Debug program\n";); 1795bdd1243dSDimitry Andric Kind = LocKind::Mem; 1796bdd1243dSDimitry Andric }; 1797bdd1243dSDimitry Andric setLocKind(LiveSet, Var, Kind); 17987a6dacacSDimitry Andric emitDbgValue(Kind, DbgAssign, DbgAssign); 1799bdd1243dSDimitry Andric } else { 18007a6dacacSDimitry Andric // The last assignment to the memory location isn't the one that we want 18017a6dacacSDimitry Andric // to show to the user so emit a dbg.value(Value). Value may be undef. 1802bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "Val, Stack contents is unknown\n";); 1803bdd1243dSDimitry Andric setLocKind(LiveSet, Var, LocKind::Val); 18047a6dacacSDimitry Andric emitDbgValue(LocKind::Val, DbgAssign, DbgAssign); 1805bdd1243dSDimitry Andric } 18067a6dacacSDimitry Andric }; 1807*0fca6ea1SDimitry Andric if (isa<DbgVariableRecord *>(Assign)) 1808*0fca6ea1SDimitry Andric return ProcessDbgAssignImpl(cast<DbgVariableRecord *>(Assign)); 18097a6dacacSDimitry Andric return ProcessDbgAssignImpl(cast<DbgAssignIntrinsic *>(Assign)); 1810bdd1243dSDimitry Andric } 1811bdd1243dSDimitry Andric 18127a6dacacSDimitry Andric void AssignmentTrackingLowering::processDbgValue( 1813*0fca6ea1SDimitry Andric PointerUnion<DbgValueInst *, DbgVariableRecord *> DbgValueRecord, 1814bdd1243dSDimitry Andric BlockInfo *LiveSet) { 18157a6dacacSDimitry Andric auto ProcessDbgValueImpl = [&](auto *DbgValue) { 1816bdd1243dSDimitry Andric // Only other tracking variables that are at some point stack homed. 1817bdd1243dSDimitry Andric // Other variables can be dealt with trivally later. 18187a6dacacSDimitry Andric if (!VarsWithStackSlot->count(getAggregate(DbgValue))) 1819bdd1243dSDimitry Andric return; 1820bdd1243dSDimitry Andric 18217a6dacacSDimitry Andric VariableID Var = getVariableID(DebugVariable(DbgValue)); 1822bdd1243dSDimitry Andric // We have no ID to create an Assignment with so we mark this assignment as 1823bdd1243dSDimitry Andric // NoneOrPhi. Note that the dbg.value still exists, we just cannot determine 1824bdd1243dSDimitry Andric // the assignment responsible for setting this value. 1825bdd1243dSDimitry Andric // This is fine; dbg.values are essentially interchangable with unlinked 1826bdd1243dSDimitry Andric // dbg.assigns, and some passes such as mem2reg and instcombine add them to 1827bdd1243dSDimitry Andric // PHIs for promoted variables. 1828bdd1243dSDimitry Andric Assignment AV = Assignment::makeNoneOrPhi(); 1829bdd1243dSDimitry Andric addDbgDef(LiveSet, Var, AV); 1830bdd1243dSDimitry Andric 18317a6dacacSDimitry Andric LLVM_DEBUG(dbgs() << "processDbgValue on " << *DbgValue << "\n";); 1832bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << " LiveLoc " << locStr(getLocKind(LiveSet, Var)) 1833bdd1243dSDimitry Andric << " -> Val, dbg.value override"); 1834bdd1243dSDimitry Andric 1835bdd1243dSDimitry Andric setLocKind(LiveSet, Var, LocKind::Val); 18367a6dacacSDimitry Andric emitDbgValue(LocKind::Val, DbgValue, DbgValue); 18377a6dacacSDimitry Andric }; 1838*0fca6ea1SDimitry Andric if (isa<DbgVariableRecord *>(DbgValueRecord)) 1839*0fca6ea1SDimitry Andric return ProcessDbgValueImpl(cast<DbgVariableRecord *>(DbgValueRecord)); 18407a6dacacSDimitry Andric return ProcessDbgValueImpl(cast<DbgValueInst *>(DbgValueRecord)); 1841bdd1243dSDimitry Andric } 1842bdd1243dSDimitry Andric 18437a6dacacSDimitry Andric template <typename T> static bool hasZeroSizedFragment(T &DbgValue) { 18447a6dacacSDimitry Andric if (auto F = DbgValue.getExpression()->getFragmentInfo()) 184506c3fb27SDimitry Andric return F->SizeInBits == 0; 184606c3fb27SDimitry Andric return false; 184706c3fb27SDimitry Andric } 184806c3fb27SDimitry Andric 1849bdd1243dSDimitry Andric void AssignmentTrackingLowering::processDbgInstruction( 185006c3fb27SDimitry Andric DbgInfoIntrinsic &I, AssignmentTrackingLowering::BlockInfo *LiveSet) { 185106c3fb27SDimitry Andric auto *DVI = dyn_cast<DbgVariableIntrinsic>(&I); 185206c3fb27SDimitry Andric if (!DVI) 185306c3fb27SDimitry Andric return; 185406c3fb27SDimitry Andric 185506c3fb27SDimitry Andric // Ignore assignments to zero bits of the variable. 185606c3fb27SDimitry Andric if (hasZeroSizedFragment(*DVI)) 185706c3fb27SDimitry Andric return; 185806c3fb27SDimitry Andric 1859bdd1243dSDimitry Andric if (auto *DAI = dyn_cast<DbgAssignIntrinsic>(&I)) 18607a6dacacSDimitry Andric processDbgAssign(DAI, LiveSet); 1861bdd1243dSDimitry Andric else if (auto *DVI = dyn_cast<DbgValueInst>(&I)) 18627a6dacacSDimitry Andric processDbgValue(DVI, LiveSet); 18637a6dacacSDimitry Andric } 1864*0fca6ea1SDimitry Andric void AssignmentTrackingLowering::processDbgVariableRecord( 1865*0fca6ea1SDimitry Andric DbgVariableRecord &DVR, AssignmentTrackingLowering::BlockInfo *LiveSet) { 18667a6dacacSDimitry Andric // Ignore assignments to zero bits of the variable. 1867*0fca6ea1SDimitry Andric if (hasZeroSizedFragment(DVR)) 18687a6dacacSDimitry Andric return; 18697a6dacacSDimitry Andric 1870*0fca6ea1SDimitry Andric if (DVR.isDbgAssign()) 1871*0fca6ea1SDimitry Andric processDbgAssign(&DVR, LiveSet); 1872*0fca6ea1SDimitry Andric else if (DVR.isDbgValue()) 1873*0fca6ea1SDimitry Andric processDbgValue(&DVR, LiveSet); 1874bdd1243dSDimitry Andric } 1875bdd1243dSDimitry Andric 1876bdd1243dSDimitry Andric void AssignmentTrackingLowering::resetInsertionPoint(Instruction &After) { 1877bdd1243dSDimitry Andric assert(!After.isTerminator() && "Can't insert after a terminator"); 18787a6dacacSDimitry Andric auto *R = InsertBeforeMap.find(getNextNode(&After)); 18797a6dacacSDimitry Andric if (R == InsertBeforeMap.end()) 18807a6dacacSDimitry Andric return; 18817a6dacacSDimitry Andric R->second.clear(); 18827a6dacacSDimitry Andric } 1883*0fca6ea1SDimitry Andric void AssignmentTrackingLowering::resetInsertionPoint(DbgVariableRecord &After) { 18847a6dacacSDimitry Andric auto *R = InsertBeforeMap.find(getNextNode(&After)); 1885bdd1243dSDimitry Andric if (R == InsertBeforeMap.end()) 1886bdd1243dSDimitry Andric return; 1887bdd1243dSDimitry Andric R->second.clear(); 1888bdd1243dSDimitry Andric } 1889bdd1243dSDimitry Andric 1890bdd1243dSDimitry Andric void AssignmentTrackingLowering::process(BasicBlock &BB, BlockInfo *LiveSet) { 1891*0fca6ea1SDimitry Andric // If the block starts with DbgRecords, we need to process those DbgRecords as 18927a6dacacSDimitry Andric // their own frame without processing any instructions first. 1893*0fca6ea1SDimitry Andric bool ProcessedLeadingDbgRecords = !BB.begin()->hasDbgRecords(); 1894bdd1243dSDimitry Andric for (auto II = BB.begin(), EI = BB.end(); II != EI;) { 1895bdd1243dSDimitry Andric assert(VarsTouchedThisFrame.empty()); 1896bdd1243dSDimitry Andric // Process the instructions in "frames". A "frame" includes a single 1897bdd1243dSDimitry Andric // non-debug instruction followed any debug instructions before the 1898bdd1243dSDimitry Andric // next non-debug instruction. 18997a6dacacSDimitry Andric 1900*0fca6ea1SDimitry Andric // Skip the current instruction if it has unprocessed DbgRecords attached 1901*0fca6ea1SDimitry Andric // (see comment above `ProcessedLeadingDbgRecords`). 1902*0fca6ea1SDimitry Andric if (ProcessedLeadingDbgRecords) { 19037a6dacacSDimitry Andric // II is now either a debug intrinsic, a non-debug instruction with no 1904*0fca6ea1SDimitry Andric // attached DbgRecords, or a non-debug instruction with attached processed 1905*0fca6ea1SDimitry Andric // DbgRecords. 19067a6dacacSDimitry Andric // II has not been processed. 1907bdd1243dSDimitry Andric if (!isa<DbgInfoIntrinsic>(&*II)) { 1908bdd1243dSDimitry Andric if (II->isTerminator()) 1909bdd1243dSDimitry Andric break; 1910bdd1243dSDimitry Andric resetInsertionPoint(*II); 1911bdd1243dSDimitry Andric processNonDbgInstruction(*II, LiveSet); 1912bdd1243dSDimitry Andric assert(LiveSet->isValid()); 1913bdd1243dSDimitry Andric ++II; 1914bdd1243dSDimitry Andric } 19157a6dacacSDimitry Andric } 19167a6dacacSDimitry Andric // II is now either a debug intrinsic, a non-debug instruction with no 1917*0fca6ea1SDimitry Andric // attached DbgRecords, or a non-debug instruction with attached unprocessed 1918*0fca6ea1SDimitry Andric // DbgRecords. 1919*0fca6ea1SDimitry Andric if (II != EI && II->hasDbgRecords()) { 1920*0fca6ea1SDimitry Andric // Skip over non-variable debug records (i.e., labels). They're going to 1921*0fca6ea1SDimitry Andric // be read from IR (possibly re-ordering them within the debug record 1922*0fca6ea1SDimitry Andric // range) rather than from the analysis results. 1923*0fca6ea1SDimitry Andric for (DbgVariableRecord &DVR : filterDbgVars(II->getDbgRecordRange())) { 1924*0fca6ea1SDimitry Andric resetInsertionPoint(DVR); 1925*0fca6ea1SDimitry Andric processDbgVariableRecord(DVR, LiveSet); 19267a6dacacSDimitry Andric assert(LiveSet->isValid()); 19277a6dacacSDimitry Andric } 19287a6dacacSDimitry Andric } 1929*0fca6ea1SDimitry Andric ProcessedLeadingDbgRecords = true; 1930bdd1243dSDimitry Andric while (II != EI) { 193106c3fb27SDimitry Andric auto *Dbg = dyn_cast<DbgInfoIntrinsic>(&*II); 193206c3fb27SDimitry Andric if (!Dbg) 1933bdd1243dSDimitry Andric break; 1934bdd1243dSDimitry Andric resetInsertionPoint(*II); 193506c3fb27SDimitry Andric processDbgInstruction(*Dbg, LiveSet); 1936bdd1243dSDimitry Andric assert(LiveSet->isValid()); 1937bdd1243dSDimitry Andric ++II; 1938bdd1243dSDimitry Andric } 1939*0fca6ea1SDimitry Andric // II is now a non-debug instruction either with no attached DbgRecords, or 1940*0fca6ea1SDimitry Andric // with attached processed DbgRecords. II has not been processed, and all 1941*0fca6ea1SDimitry Andric // debug instructions or DbgRecords in the frame preceding II have been 19427a6dacacSDimitry Andric // processed. 1943bdd1243dSDimitry Andric 1944bdd1243dSDimitry Andric // We've processed everything in the "frame". Now determine which variables 1945bdd1243dSDimitry Andric // cannot be represented by a dbg.declare. 1946bdd1243dSDimitry Andric for (auto Var : VarsTouchedThisFrame) { 1947bdd1243dSDimitry Andric LocKind Loc = getLocKind(LiveSet, Var); 1948bdd1243dSDimitry Andric // If a variable's LocKind is anything other than LocKind::Mem then we 1949bdd1243dSDimitry Andric // must note that it cannot be represented with a dbg.declare. 1950bdd1243dSDimitry Andric // Note that this check is enough without having to check the result of 1951bdd1243dSDimitry Andric // joins() because for join to produce anything other than Mem after 1952bdd1243dSDimitry Andric // we've already seen a Mem we'd be joining None or Val with Mem. In that 1953bdd1243dSDimitry Andric // case, we've already hit this codepath when we set the LocKind to Val 1954bdd1243dSDimitry Andric // or None in that block. 1955bdd1243dSDimitry Andric if (Loc != LocKind::Mem) { 1956bdd1243dSDimitry Andric DebugVariable DbgVar = FnVarLocs->getVariable(Var); 1957bdd1243dSDimitry Andric DebugAggregate Aggr{DbgVar.getVariable(), DbgVar.getInlinedAt()}; 1958bdd1243dSDimitry Andric NotAlwaysStackHomed.insert(Aggr); 1959bdd1243dSDimitry Andric } 1960bdd1243dSDimitry Andric } 1961bdd1243dSDimitry Andric VarsTouchedThisFrame.clear(); 1962bdd1243dSDimitry Andric } 1963bdd1243dSDimitry Andric } 1964bdd1243dSDimitry Andric 1965bdd1243dSDimitry Andric AssignmentTrackingLowering::LocKind 1966bdd1243dSDimitry Andric AssignmentTrackingLowering::joinKind(LocKind A, LocKind B) { 1967bdd1243dSDimitry Andric // Partial order: 1968bdd1243dSDimitry Andric // None > Mem, Val 1969bdd1243dSDimitry Andric return A == B ? A : LocKind::None; 1970bdd1243dSDimitry Andric } 1971bdd1243dSDimitry Andric 1972bdd1243dSDimitry Andric AssignmentTrackingLowering::Assignment 1973bdd1243dSDimitry Andric AssignmentTrackingLowering::joinAssignment(const Assignment &A, 1974bdd1243dSDimitry Andric const Assignment &B) { 1975bdd1243dSDimitry Andric // Partial order: 1976bdd1243dSDimitry Andric // NoneOrPhi(null, null) > Known(v, ?s) 1977bdd1243dSDimitry Andric 1978bdd1243dSDimitry Andric // If either are NoneOrPhi the join is NoneOrPhi. 1979bdd1243dSDimitry Andric // If either value is different then the result is 1980bdd1243dSDimitry Andric // NoneOrPhi (joining two values is a Phi). 1981bdd1243dSDimitry Andric if (!A.isSameSourceAssignment(B)) 1982bdd1243dSDimitry Andric return Assignment::makeNoneOrPhi(); 1983bdd1243dSDimitry Andric if (A.Status == Assignment::NoneOrPhi) 1984bdd1243dSDimitry Andric return Assignment::makeNoneOrPhi(); 1985bdd1243dSDimitry Andric 1986bdd1243dSDimitry Andric // Source is used to lookup the value + expression in the debug program if 1987bdd1243dSDimitry Andric // the stack slot gets assigned a value earlier than expected. Because 1988bdd1243dSDimitry Andric // we're only tracking the one dbg.assign, we can't capture debug PHIs. 1989bdd1243dSDimitry Andric // It's unlikely that we're losing out on much coverage by avoiding that 1990bdd1243dSDimitry Andric // extra work. 1991bdd1243dSDimitry Andric // The Source may differ in this situation: 1992bdd1243dSDimitry Andric // Pred.1: 1993bdd1243dSDimitry Andric // dbg.assign i32 0, ..., !1, ... 1994bdd1243dSDimitry Andric // Pred.2: 1995bdd1243dSDimitry Andric // dbg.assign i32 1, ..., !1, ... 1996bdd1243dSDimitry Andric // Here the same assignment (!1) was performed in both preds in the source, 1997bdd1243dSDimitry Andric // but we can't use either one unless they are identical (e.g. .we don't 1998bdd1243dSDimitry Andric // want to arbitrarily pick between constant values). 19997a6dacacSDimitry Andric auto JoinSource = [&]() -> AssignRecord { 2000bdd1243dSDimitry Andric if (A.Source == B.Source) 2001bdd1243dSDimitry Andric return A.Source; 20027a6dacacSDimitry Andric if (!A.Source || !B.Source) 20037a6dacacSDimitry Andric return AssignRecord(); 2004*0fca6ea1SDimitry Andric assert(isa<DbgVariableRecord *>(A.Source) == 2005*0fca6ea1SDimitry Andric isa<DbgVariableRecord *>(B.Source)); 2006*0fca6ea1SDimitry Andric if (isa<DbgVariableRecord *>(A.Source) && 2007*0fca6ea1SDimitry Andric cast<DbgVariableRecord *>(A.Source)->isEquivalentTo( 2008*0fca6ea1SDimitry Andric *cast<DbgVariableRecord *>(B.Source))) 2009bdd1243dSDimitry Andric return A.Source; 20107a6dacacSDimitry Andric if (isa<DbgAssignIntrinsic *>(A.Source) && 20117a6dacacSDimitry Andric cast<DbgAssignIntrinsic *>(A.Source)->isIdenticalTo( 20127a6dacacSDimitry Andric cast<DbgAssignIntrinsic *>(B.Source))) 20137a6dacacSDimitry Andric return A.Source; 20147a6dacacSDimitry Andric return AssignRecord(); 2015bdd1243dSDimitry Andric }; 20167a6dacacSDimitry Andric AssignRecord Source = JoinSource(); 2017bdd1243dSDimitry Andric assert(A.Status == B.Status && A.Status == Assignment::Known); 2018bdd1243dSDimitry Andric assert(A.ID == B.ID); 2019bdd1243dSDimitry Andric return Assignment::make(A.ID, Source); 2020bdd1243dSDimitry Andric } 2021bdd1243dSDimitry Andric 2022bdd1243dSDimitry Andric AssignmentTrackingLowering::BlockInfo 2023bdd1243dSDimitry Andric AssignmentTrackingLowering::joinBlockInfo(const BlockInfo &A, 2024bdd1243dSDimitry Andric const BlockInfo &B) { 202506c3fb27SDimitry Andric return BlockInfo::join(A, B, TrackedVariablesVectorSize); 2026bdd1243dSDimitry Andric } 2027bdd1243dSDimitry Andric 2028bdd1243dSDimitry Andric bool AssignmentTrackingLowering::join( 2029bdd1243dSDimitry Andric const BasicBlock &BB, const SmallPtrSet<BasicBlock *, 16> &Visited) { 203006c3fb27SDimitry Andric 203106c3fb27SDimitry Andric SmallVector<const BasicBlock *> VisitedPreds; 2032bdd1243dSDimitry Andric // Ignore backedges if we have not visited the predecessor yet. As the 2033bdd1243dSDimitry Andric // predecessor hasn't yet had locations propagated into it, most locations 2034bdd1243dSDimitry Andric // will not yet be valid, so treat them as all being uninitialized and 2035bdd1243dSDimitry Andric // potentially valid. If a location guessed to be correct here is 2036bdd1243dSDimitry Andric // invalidated later, we will remove it when we revisit this block. This 2037bdd1243dSDimitry Andric // is essentially the same as initialising all LocKinds and Assignments to 2038bdd1243dSDimitry Andric // an implicit ⊥ value which is the identity value for the join operation. 20397a6dacacSDimitry Andric for (const BasicBlock *Pred : predecessors(&BB)) { 204006c3fb27SDimitry Andric if (Visited.count(Pred)) 204106c3fb27SDimitry Andric VisitedPreds.push_back(Pred); 2042bdd1243dSDimitry Andric } 2043bdd1243dSDimitry Andric 204406c3fb27SDimitry Andric // No preds visited yet. 204506c3fb27SDimitry Andric if (VisitedPreds.empty()) { 204606c3fb27SDimitry Andric auto It = LiveIn.try_emplace(&BB, BlockInfo()); 204706c3fb27SDimitry Andric bool DidInsert = It.second; 204806c3fb27SDimitry Andric if (DidInsert) 204906c3fb27SDimitry Andric It.first->second.init(TrackedVariablesVectorSize); 205006c3fb27SDimitry Andric return /*Changed*/ DidInsert; 205106c3fb27SDimitry Andric } 205206c3fb27SDimitry Andric 205306c3fb27SDimitry Andric // Exactly one visited pred. Copy the LiveOut from that pred into BB LiveIn. 205406c3fb27SDimitry Andric if (VisitedPreds.size() == 1) { 205506c3fb27SDimitry Andric const BlockInfo &PredLiveOut = LiveOut.find(VisitedPreds[0])->second; 205606c3fb27SDimitry Andric auto CurrentLiveInEntry = LiveIn.find(&BB); 205706c3fb27SDimitry Andric 205806c3fb27SDimitry Andric // Check if there isn't an entry, or there is but the LiveIn set has 205906c3fb27SDimitry Andric // changed (expensive check). 206006c3fb27SDimitry Andric if (CurrentLiveInEntry == LiveIn.end()) 206106c3fb27SDimitry Andric LiveIn.insert(std::make_pair(&BB, PredLiveOut)); 206206c3fb27SDimitry Andric else if (PredLiveOut != CurrentLiveInEntry->second) 206306c3fb27SDimitry Andric CurrentLiveInEntry->second = PredLiveOut; 206406c3fb27SDimitry Andric else 206506c3fb27SDimitry Andric return /*Changed*/ false; 206606c3fb27SDimitry Andric return /*Changed*/ true; 206706c3fb27SDimitry Andric } 206806c3fb27SDimitry Andric 206906c3fb27SDimitry Andric // More than one pred. Join LiveOuts of blocks 1 and 2. 207006c3fb27SDimitry Andric assert(VisitedPreds.size() > 1); 207106c3fb27SDimitry Andric const BlockInfo &PredLiveOut0 = LiveOut.find(VisitedPreds[0])->second; 207206c3fb27SDimitry Andric const BlockInfo &PredLiveOut1 = LiveOut.find(VisitedPreds[1])->second; 207306c3fb27SDimitry Andric BlockInfo BBLiveIn = joinBlockInfo(PredLiveOut0, PredLiveOut1); 207406c3fb27SDimitry Andric 207506c3fb27SDimitry Andric // Join the LiveOuts of subsequent blocks. 207606c3fb27SDimitry Andric ArrayRef Tail = ArrayRef(VisitedPreds).drop_front(2); 207706c3fb27SDimitry Andric for (const BasicBlock *Pred : Tail) { 207806c3fb27SDimitry Andric const auto &PredLiveOut = LiveOut.find(Pred); 207906c3fb27SDimitry Andric assert(PredLiveOut != LiveOut.end() && 208006c3fb27SDimitry Andric "block should have been processed already"); 208106c3fb27SDimitry Andric BBLiveIn = joinBlockInfo(std::move(BBLiveIn), PredLiveOut->second); 208206c3fb27SDimitry Andric } 208306c3fb27SDimitry Andric 208406c3fb27SDimitry Andric // Save the joined result for BB. 2085bdd1243dSDimitry Andric auto CurrentLiveInEntry = LiveIn.find(&BB); 2086bdd1243dSDimitry Andric // Check if there isn't an entry, or there is but the LiveIn set has changed 2087bdd1243dSDimitry Andric // (expensive check). 208806c3fb27SDimitry Andric if (CurrentLiveInEntry == LiveIn.end()) 208906c3fb27SDimitry Andric LiveIn.try_emplace(&BB, std::move(BBLiveIn)); 209006c3fb27SDimitry Andric else if (BBLiveIn != CurrentLiveInEntry->second) 209106c3fb27SDimitry Andric CurrentLiveInEntry->second = std::move(BBLiveIn); 209206c3fb27SDimitry Andric else 209306c3fb27SDimitry Andric return /*Changed*/ false; 209406c3fb27SDimitry Andric return /*Changed*/ true; 2095bdd1243dSDimitry Andric } 2096bdd1243dSDimitry Andric 2097bdd1243dSDimitry Andric /// Return true if A fully contains B. 2098bdd1243dSDimitry Andric static bool fullyContains(DIExpression::FragmentInfo A, 2099bdd1243dSDimitry Andric DIExpression::FragmentInfo B) { 2100bdd1243dSDimitry Andric auto ALeft = A.OffsetInBits; 2101bdd1243dSDimitry Andric auto BLeft = B.OffsetInBits; 2102bdd1243dSDimitry Andric if (BLeft < ALeft) 2103bdd1243dSDimitry Andric return false; 2104bdd1243dSDimitry Andric 2105bdd1243dSDimitry Andric auto ARight = ALeft + A.SizeInBits; 2106bdd1243dSDimitry Andric auto BRight = BLeft + B.SizeInBits; 2107bdd1243dSDimitry Andric if (BRight > ARight) 2108bdd1243dSDimitry Andric return false; 2109bdd1243dSDimitry Andric return true; 2110bdd1243dSDimitry Andric } 2111bdd1243dSDimitry Andric 2112bdd1243dSDimitry Andric static std::optional<at::AssignmentInfo> 2113bdd1243dSDimitry Andric getUntaggedStoreAssignmentInfo(const Instruction &I, const DataLayout &Layout) { 2114bdd1243dSDimitry Andric // Don't bother checking if this is an AllocaInst. We know this 2115bdd1243dSDimitry Andric // instruction has no tag which means there are no variables associated 2116bdd1243dSDimitry Andric // with it. 2117bdd1243dSDimitry Andric if (const auto *SI = dyn_cast<StoreInst>(&I)) 2118bdd1243dSDimitry Andric return at::getAssignmentInfo(Layout, SI); 2119bdd1243dSDimitry Andric if (const auto *MI = dyn_cast<MemIntrinsic>(&I)) 2120bdd1243dSDimitry Andric return at::getAssignmentInfo(Layout, MI); 2121bdd1243dSDimitry Andric // Alloca or non-store-like inst. 2122bdd1243dSDimitry Andric return std::nullopt; 2123bdd1243dSDimitry Andric } 2124bdd1243dSDimitry Andric 21257a6dacacSDimitry Andric DbgDeclareInst *DynCastToDbgDeclare(DbgVariableIntrinsic *DVI) { 21267a6dacacSDimitry Andric return dyn_cast<DbgDeclareInst>(DVI); 21277a6dacacSDimitry Andric } 21287a6dacacSDimitry Andric 2129*0fca6ea1SDimitry Andric DbgVariableRecord *DynCastToDbgDeclare(DbgVariableRecord *DVR) { 2130*0fca6ea1SDimitry Andric return DVR->isDbgDeclare() ? DVR : nullptr; 21317a6dacacSDimitry Andric } 21327a6dacacSDimitry Andric 2133bdd1243dSDimitry Andric /// Build a map of {Variable x: Variables y} where all variable fragments 2134bdd1243dSDimitry Andric /// contained within the variable fragment x are in set y. This means that 2135bdd1243dSDimitry Andric /// y does not contain all overlaps because partial overlaps are excluded. 2136bdd1243dSDimitry Andric /// 2137bdd1243dSDimitry Andric /// While we're iterating over the function, add single location defs for 213806c3fb27SDimitry Andric /// dbg.declares to \p FnVarLocs. 213906c3fb27SDimitry Andric /// 214006c3fb27SDimitry Andric /// Variables that are interesting to this pass in are added to 214106c3fb27SDimitry Andric /// FnVarLocs->Variables first. TrackedVariablesVectorSize is set to the ID of 214206c3fb27SDimitry Andric /// the last interesting variable plus 1, meaning variables with ID 1 214306c3fb27SDimitry Andric /// (inclusive) to TrackedVariablesVectorSize (exclusive) are interesting. The 214406c3fb27SDimitry Andric /// subsequent variables are either stack homed or fully promoted. 2145bdd1243dSDimitry Andric /// 2146bdd1243dSDimitry Andric /// Finally, populate UntaggedStoreVars with a mapping of untagged stores to 2147bdd1243dSDimitry Andric /// the stored-to variable fragments. 2148bdd1243dSDimitry Andric /// 2149bdd1243dSDimitry Andric /// These tasks are bundled together to reduce the number of times we need 2150bdd1243dSDimitry Andric /// to iterate over the function as they can be achieved together in one pass. 2151bdd1243dSDimitry Andric static AssignmentTrackingLowering::OverlapMap buildOverlapMapAndRecordDeclares( 2152bdd1243dSDimitry Andric Function &Fn, FunctionVarLocsBuilder *FnVarLocs, 215306c3fb27SDimitry Andric const DenseSet<DebugAggregate> &VarsWithStackSlot, 215406c3fb27SDimitry Andric AssignmentTrackingLowering::UntaggedStoreAssignmentMap &UntaggedStoreVars, 215506c3fb27SDimitry Andric unsigned &TrackedVariablesVectorSize) { 2156bdd1243dSDimitry Andric DenseSet<DebugVariable> Seen; 2157bdd1243dSDimitry Andric // Map of Variable: [Fragments]. 2158bdd1243dSDimitry Andric DenseMap<DebugAggregate, SmallVector<DebugVariable, 8>> FragmentMap; 2159bdd1243dSDimitry Andric // Iterate over all instructions: 2160bdd1243dSDimitry Andric // - dbg.declare -> add single location variable record 2161bdd1243dSDimitry Andric // - dbg.* -> Add fragments to FragmentMap 2162bdd1243dSDimitry Andric // - untagged store -> Add fragments to FragmentMap and update 2163bdd1243dSDimitry Andric // UntaggedStoreVars. 2164bdd1243dSDimitry Andric // We need to add fragments for untagged stores too so that we can correctly 2165bdd1243dSDimitry Andric // clobber overlapped fragment locations later. 21667a6dacacSDimitry Andric SmallVector<DbgDeclareInst *> InstDeclares; 2167*0fca6ea1SDimitry Andric SmallVector<DbgVariableRecord *> DPDeclares; 21687a6dacacSDimitry Andric auto ProcessDbgRecord = [&](auto *Record, auto &DeclareList) { 21697a6dacacSDimitry Andric if (auto *Declare = DynCastToDbgDeclare(Record)) { 21707a6dacacSDimitry Andric DeclareList.push_back(Declare); 21717a6dacacSDimitry Andric return; 21727a6dacacSDimitry Andric } 21737a6dacacSDimitry Andric DebugVariable DV = DebugVariable(Record); 2174bdd1243dSDimitry Andric DebugAggregate DA = {DV.getVariable(), DV.getInlinedAt()}; 217506c3fb27SDimitry Andric if (!VarsWithStackSlot.contains(DA)) 21767a6dacacSDimitry Andric return; 2177bdd1243dSDimitry Andric if (Seen.insert(DV).second) 2178bdd1243dSDimitry Andric FragmentMap[DA].push_back(DV); 21797a6dacacSDimitry Andric }; 21807a6dacacSDimitry Andric for (auto &BB : Fn) { 21817a6dacacSDimitry Andric for (auto &I : BB) { 2182*0fca6ea1SDimitry Andric for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange())) 2183*0fca6ea1SDimitry Andric ProcessDbgRecord(&DVR, DPDeclares); 21847a6dacacSDimitry Andric if (auto *DII = dyn_cast<DbgVariableIntrinsic>(&I)) { 21857a6dacacSDimitry Andric ProcessDbgRecord(DII, InstDeclares); 2186bdd1243dSDimitry Andric } else if (auto Info = getUntaggedStoreAssignmentInfo( 2187*0fca6ea1SDimitry Andric I, Fn.getDataLayout())) { 2188bdd1243dSDimitry Andric // Find markers linked to this alloca. 21897a6dacacSDimitry Andric auto HandleDbgAssignForStore = [&](auto *Assign) { 21905f757f3fSDimitry Andric std::optional<DIExpression::FragmentInfo> FragInfo; 21915f757f3fSDimitry Andric 21925f757f3fSDimitry Andric // Skip this assignment if the affected bits are outside of the 21935f757f3fSDimitry Andric // variable fragment. 21945f757f3fSDimitry Andric if (!at::calculateFragmentIntersect( 2195*0fca6ea1SDimitry Andric I.getDataLayout(), Info->Base, 21967a6dacacSDimitry Andric Info->OffsetInBits, Info->SizeInBits, Assign, FragInfo) || 21975f757f3fSDimitry Andric (FragInfo && FragInfo->SizeInBits == 0)) 21987a6dacacSDimitry Andric return; 21995f757f3fSDimitry Andric 22005f757f3fSDimitry Andric // FragInfo from calculateFragmentIntersect is nullopt if the 22015f757f3fSDimitry Andric // resultant fragment matches DAI's fragment or entire variable - in 22025f757f3fSDimitry Andric // which case copy the fragment info from DAI. If FragInfo is still 22035f757f3fSDimitry Andric // nullopt after the copy it means "no fragment info" instead, which 22045f757f3fSDimitry Andric // is how it is usually interpreted. 22055f757f3fSDimitry Andric if (!FragInfo) 22067a6dacacSDimitry Andric FragInfo = Assign->getExpression()->getFragmentInfo(); 2207bdd1243dSDimitry Andric 22087a6dacacSDimitry Andric DebugVariable DV = 22097a6dacacSDimitry Andric DebugVariable(Assign->getVariable(), FragInfo, 22107a6dacacSDimitry Andric Assign->getDebugLoc().getInlinedAt()); 2211bdd1243dSDimitry Andric DebugAggregate DA = {DV.getVariable(), DV.getInlinedAt()}; 221206c3fb27SDimitry Andric if (!VarsWithStackSlot.contains(DA)) 22137a6dacacSDimitry Andric return; 2214bdd1243dSDimitry Andric 2215bdd1243dSDimitry Andric // Cache this info for later. 2216bdd1243dSDimitry Andric UntaggedStoreVars[&I].push_back( 2217bdd1243dSDimitry Andric {FnVarLocs->insertVariable(DV), *Info}); 2218bdd1243dSDimitry Andric 2219bdd1243dSDimitry Andric if (Seen.insert(DV).second) 2220bdd1243dSDimitry Andric FragmentMap[DA].push_back(DV); 22217a6dacacSDimitry Andric }; 22227a6dacacSDimitry Andric for (DbgAssignIntrinsic *DAI : at::getAssignmentMarkers(Info->Base)) 22237a6dacacSDimitry Andric HandleDbgAssignForStore(DAI); 2224*0fca6ea1SDimitry Andric for (DbgVariableRecord *DVR : at::getDVRAssignmentMarkers(Info->Base)) 2225*0fca6ea1SDimitry Andric HandleDbgAssignForStore(DVR); 2226bdd1243dSDimitry Andric } 2227bdd1243dSDimitry Andric } 2228bdd1243dSDimitry Andric } 2229bdd1243dSDimitry Andric 223006c3fb27SDimitry Andric // Sort the fragment map for each DebugAggregate in ascending 223106c3fb27SDimitry Andric // order of fragment size - there should be no duplicates. 2232bdd1243dSDimitry Andric for (auto &Pair : FragmentMap) { 2233bdd1243dSDimitry Andric SmallVector<DebugVariable, 8> &Frags = Pair.second; 223406c3fb27SDimitry Andric std::sort(Frags.begin(), Frags.end(), 223506c3fb27SDimitry Andric [](const DebugVariable &Next, const DebugVariable &Elmt) { 2236bdd1243dSDimitry Andric return Elmt.getFragmentOrDefault().SizeInBits > 2237bdd1243dSDimitry Andric Next.getFragmentOrDefault().SizeInBits; 2238bdd1243dSDimitry Andric }); 223906c3fb27SDimitry Andric // Check for duplicates. 224006c3fb27SDimitry Andric assert(std::adjacent_find(Frags.begin(), Frags.end()) == Frags.end()); 2241bdd1243dSDimitry Andric } 2242bdd1243dSDimitry Andric 2243bdd1243dSDimitry Andric // Build the map. 2244bdd1243dSDimitry Andric AssignmentTrackingLowering::OverlapMap Map; 224506c3fb27SDimitry Andric for (auto &Pair : FragmentMap) { 2246bdd1243dSDimitry Andric auto &Frags = Pair.second; 2247bdd1243dSDimitry Andric for (auto It = Frags.begin(), IEnd = Frags.end(); It != IEnd; ++It) { 2248bdd1243dSDimitry Andric DIExpression::FragmentInfo Frag = It->getFragmentOrDefault(); 2249bdd1243dSDimitry Andric // Find the frags that this is contained within. 2250bdd1243dSDimitry Andric // 2251bdd1243dSDimitry Andric // Because Frags is sorted by size and none have the same offset and 2252bdd1243dSDimitry Andric // size, we know that this frag can only be contained by subsequent 2253bdd1243dSDimitry Andric // elements. 2254bdd1243dSDimitry Andric SmallVector<DebugVariable, 8>::iterator OtherIt = It; 2255bdd1243dSDimitry Andric ++OtherIt; 2256bdd1243dSDimitry Andric VariableID ThisVar = FnVarLocs->insertVariable(*It); 2257bdd1243dSDimitry Andric for (; OtherIt != IEnd; ++OtherIt) { 2258bdd1243dSDimitry Andric DIExpression::FragmentInfo OtherFrag = OtherIt->getFragmentOrDefault(); 2259bdd1243dSDimitry Andric VariableID OtherVar = FnVarLocs->insertVariable(*OtherIt); 2260bdd1243dSDimitry Andric if (fullyContains(OtherFrag, Frag)) 2261bdd1243dSDimitry Andric Map[OtherVar].push_back(ThisVar); 2262bdd1243dSDimitry Andric } 2263bdd1243dSDimitry Andric } 2264bdd1243dSDimitry Andric } 2265bdd1243dSDimitry Andric 226606c3fb27SDimitry Andric // VariableIDs are 1-based so the variable-tracking bitvector needs 226706c3fb27SDimitry Andric // NumVariables plus 1 bits. 226806c3fb27SDimitry Andric TrackedVariablesVectorSize = FnVarLocs->getNumVariables() + 1; 226906c3fb27SDimitry Andric 227006c3fb27SDimitry Andric // Finally, insert the declares afterwards, so the first IDs are all 227106c3fb27SDimitry Andric // partially stack homed vars. 22727a6dacacSDimitry Andric for (auto *DDI : InstDeclares) 227306c3fb27SDimitry Andric FnVarLocs->addSingleLocVar(DebugVariable(DDI), DDI->getExpression(), 227406c3fb27SDimitry Andric DDI->getDebugLoc(), DDI->getWrappedLocation()); 2275*0fca6ea1SDimitry Andric for (auto *DVR : DPDeclares) 2276*0fca6ea1SDimitry Andric FnVarLocs->addSingleLocVar(DebugVariable(DVR), DVR->getExpression(), 2277*0fca6ea1SDimitry Andric DVR->getDebugLoc(), 2278*0fca6ea1SDimitry Andric RawLocationWrapper(DVR->getRawLocation())); 2279bdd1243dSDimitry Andric return Map; 2280bdd1243dSDimitry Andric } 2281bdd1243dSDimitry Andric 2282bdd1243dSDimitry Andric bool AssignmentTrackingLowering::run(FunctionVarLocsBuilder *FnVarLocsBuilder) { 2283bdd1243dSDimitry Andric if (Fn.size() > MaxNumBlocks) { 2284bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "[AT] Dropping var locs in: " << Fn.getName() 2285bdd1243dSDimitry Andric << ": too many blocks (" << Fn.size() << ")\n"); 2286bdd1243dSDimitry Andric at::deleteAll(&Fn); 2287bdd1243dSDimitry Andric return false; 2288bdd1243dSDimitry Andric } 2289bdd1243dSDimitry Andric 2290bdd1243dSDimitry Andric FnVarLocs = FnVarLocsBuilder; 2291bdd1243dSDimitry Andric 2292bdd1243dSDimitry Andric // The general structure here is inspired by VarLocBasedImpl.cpp 2293bdd1243dSDimitry Andric // (LiveDebugValues). 2294bdd1243dSDimitry Andric 2295bdd1243dSDimitry Andric // Build the variable fragment overlap map. 2296bdd1243dSDimitry Andric // Note that this pass doesn't handle partial overlaps correctly (FWIW 2297bdd1243dSDimitry Andric // neither does LiveDebugVariables) because that is difficult to do and 2298bdd1243dSDimitry Andric // appears to be rare occurance. 229906c3fb27SDimitry Andric VarContains = buildOverlapMapAndRecordDeclares( 230006c3fb27SDimitry Andric Fn, FnVarLocs, *VarsWithStackSlot, UntaggedStoreVars, 230106c3fb27SDimitry Andric TrackedVariablesVectorSize); 2302bdd1243dSDimitry Andric 2303bdd1243dSDimitry Andric // Prepare for traversal. 2304bdd1243dSDimitry Andric ReversePostOrderTraversal<Function *> RPOT(&Fn); 2305bdd1243dSDimitry Andric std::priority_queue<unsigned int, std::vector<unsigned int>, 2306bdd1243dSDimitry Andric std::greater<unsigned int>> 2307bdd1243dSDimitry Andric Worklist; 2308bdd1243dSDimitry Andric std::priority_queue<unsigned int, std::vector<unsigned int>, 2309bdd1243dSDimitry Andric std::greater<unsigned int>> 2310bdd1243dSDimitry Andric Pending; 2311bdd1243dSDimitry Andric DenseMap<unsigned int, BasicBlock *> OrderToBB; 2312bdd1243dSDimitry Andric DenseMap<BasicBlock *, unsigned int> BBToOrder; 2313bdd1243dSDimitry Andric { // Init OrderToBB and BBToOrder. 2314bdd1243dSDimitry Andric unsigned int RPONumber = 0; 2315*0fca6ea1SDimitry Andric for (BasicBlock *BB : RPOT) { 2316*0fca6ea1SDimitry Andric OrderToBB[RPONumber] = BB; 2317*0fca6ea1SDimitry Andric BBToOrder[BB] = RPONumber; 2318bdd1243dSDimitry Andric Worklist.push(RPONumber); 2319bdd1243dSDimitry Andric ++RPONumber; 2320bdd1243dSDimitry Andric } 2321bdd1243dSDimitry Andric LiveIn.init(RPONumber); 2322bdd1243dSDimitry Andric LiveOut.init(RPONumber); 2323bdd1243dSDimitry Andric } 2324bdd1243dSDimitry Andric 2325bdd1243dSDimitry Andric // Perform the traversal. 2326bdd1243dSDimitry Andric // 2327bdd1243dSDimitry Andric // This is a standard "union of predecessor outs" dataflow problem. To solve 2328bdd1243dSDimitry Andric // it, we perform join() and process() using the two worklist method until 2329bdd1243dSDimitry Andric // the LiveIn data for each block becomes unchanging. The "proof" that this 2330bdd1243dSDimitry Andric // terminates can be put together by looking at the comments around LocKind, 2331bdd1243dSDimitry Andric // Assignment, and the various join methods, which show that all the elements 2332bdd1243dSDimitry Andric // involved are made up of join-semilattices; LiveIn(n) can only 2333bdd1243dSDimitry Andric // monotonically increase in value throughout the dataflow. 2334bdd1243dSDimitry Andric // 2335bdd1243dSDimitry Andric SmallPtrSet<BasicBlock *, 16> Visited; 2336bdd1243dSDimitry Andric while (!Worklist.empty()) { 2337bdd1243dSDimitry Andric // We track what is on the pending worklist to avoid inserting the same 2338bdd1243dSDimitry Andric // thing twice. 2339bdd1243dSDimitry Andric SmallPtrSet<BasicBlock *, 16> OnPending; 2340bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "Processing Worklist\n"); 2341bdd1243dSDimitry Andric while (!Worklist.empty()) { 2342bdd1243dSDimitry Andric BasicBlock *BB = OrderToBB[Worklist.top()]; 2343bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "\nPop BB " << BB->getName() << "\n"); 2344bdd1243dSDimitry Andric Worklist.pop(); 2345bdd1243dSDimitry Andric bool InChanged = join(*BB, Visited); 2346bdd1243dSDimitry Andric // Always consider LiveIn changed on the first visit. 2347bdd1243dSDimitry Andric InChanged |= Visited.insert(BB).second; 2348bdd1243dSDimitry Andric if (InChanged) { 2349bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << BB->getName() << " has new InLocs, process it\n"); 2350bdd1243dSDimitry Andric // Mutate a copy of LiveIn while processing BB. After calling process 2351bdd1243dSDimitry Andric // LiveSet is the LiveOut set for BB. 2352bdd1243dSDimitry Andric BlockInfo LiveSet = LiveIn[BB]; 2353bdd1243dSDimitry Andric 2354bdd1243dSDimitry Andric // Process the instructions in the block. 2355bdd1243dSDimitry Andric process(*BB, &LiveSet); 2356bdd1243dSDimitry Andric 2357bdd1243dSDimitry Andric // Relatively expensive check: has anything changed in LiveOut for BB? 2358bdd1243dSDimitry Andric if (LiveOut[BB] != LiveSet) { 2359bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << BB->getName() 2360bdd1243dSDimitry Andric << " has new OutLocs, add succs to worklist: [ "); 2361bdd1243dSDimitry Andric LiveOut[BB] = std::move(LiveSet); 2362*0fca6ea1SDimitry Andric for (BasicBlock *Succ : successors(BB)) { 2363*0fca6ea1SDimitry Andric if (OnPending.insert(Succ).second) { 2364*0fca6ea1SDimitry Andric LLVM_DEBUG(dbgs() << Succ->getName() << " "); 2365*0fca6ea1SDimitry Andric Pending.push(BBToOrder[Succ]); 2366bdd1243dSDimitry Andric } 2367bdd1243dSDimitry Andric } 2368bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "]\n"); 2369bdd1243dSDimitry Andric } 2370bdd1243dSDimitry Andric } 2371bdd1243dSDimitry Andric } 2372bdd1243dSDimitry Andric Worklist.swap(Pending); 2373bdd1243dSDimitry Andric // At this point, pending must be empty, since it was just the empty 2374bdd1243dSDimitry Andric // worklist 2375bdd1243dSDimitry Andric assert(Pending.empty() && "Pending should be empty"); 2376bdd1243dSDimitry Andric } 2377bdd1243dSDimitry Andric 2378bdd1243dSDimitry Andric // That's the hard part over. Now we just have some admin to do. 2379bdd1243dSDimitry Andric 2380bdd1243dSDimitry Andric // Record whether we inserted any intrinsics. 2381bdd1243dSDimitry Andric bool InsertedAnyIntrinsics = false; 2382bdd1243dSDimitry Andric 2383bdd1243dSDimitry Andric // Identify and add defs for single location variables. 2384bdd1243dSDimitry Andric // 2385bdd1243dSDimitry Andric // Go through all of the defs that we plan to add. If the aggregate variable 2386bdd1243dSDimitry Andric // it's a part of is not in the NotAlwaysStackHomed set we can emit a single 2387bdd1243dSDimitry Andric // location def and omit the rest. Add an entry to AlwaysStackHomed so that 2388bdd1243dSDimitry Andric // we can identify those uneeded defs later. 2389bdd1243dSDimitry Andric DenseSet<DebugAggregate> AlwaysStackHomed; 2390bdd1243dSDimitry Andric for (const auto &Pair : InsertBeforeMap) { 23917a6dacacSDimitry Andric auto &Vec = Pair.second; 2392bdd1243dSDimitry Andric for (VarLocInfo VarLoc : Vec) { 2393bdd1243dSDimitry Andric DebugVariable Var = FnVarLocs->getVariable(VarLoc.VariableID); 2394bdd1243dSDimitry Andric DebugAggregate Aggr{Var.getVariable(), Var.getInlinedAt()}; 2395bdd1243dSDimitry Andric 2396bdd1243dSDimitry Andric // Skip this Var if it's not always stack homed. 2397bdd1243dSDimitry Andric if (NotAlwaysStackHomed.contains(Aggr)) 2398bdd1243dSDimitry Andric continue; 2399bdd1243dSDimitry Andric 2400bdd1243dSDimitry Andric // Skip complex cases such as when different fragments of a variable have 2401bdd1243dSDimitry Andric // been split into different allocas. Skipping in this case means falling 2402bdd1243dSDimitry Andric // back to using a list of defs (which could reduce coverage, but is no 2403bdd1243dSDimitry Andric // less correct). 2404bdd1243dSDimitry Andric bool Simple = 2405bdd1243dSDimitry Andric VarLoc.Expr->getNumElements() == 1 && VarLoc.Expr->startsWithDeref(); 2406bdd1243dSDimitry Andric if (!Simple) { 2407bdd1243dSDimitry Andric NotAlwaysStackHomed.insert(Aggr); 2408bdd1243dSDimitry Andric continue; 2409bdd1243dSDimitry Andric } 2410bdd1243dSDimitry Andric 2411bdd1243dSDimitry Andric // All source assignments to this variable remain and all stores to any 2412bdd1243dSDimitry Andric // part of the variable store to the same address (with varying 2413bdd1243dSDimitry Andric // offsets). We can just emit a single location for the whole variable. 2414bdd1243dSDimitry Andric // 2415bdd1243dSDimitry Andric // Unless we've already done so, create the single location def now. 2416bdd1243dSDimitry Andric if (AlwaysStackHomed.insert(Aggr).second) { 241706c3fb27SDimitry Andric assert(!VarLoc.Values.hasArgList()); 2418bdd1243dSDimitry Andric // TODO: When more complex cases are handled VarLoc.Expr should be 2419bdd1243dSDimitry Andric // built appropriately rather than always using an empty DIExpression. 2420bdd1243dSDimitry Andric // The assert below is a reminder. 2421bdd1243dSDimitry Andric assert(Simple); 2422bdd1243dSDimitry Andric VarLoc.Expr = DIExpression::get(Fn.getContext(), std::nullopt); 2423bdd1243dSDimitry Andric DebugVariable Var = FnVarLocs->getVariable(VarLoc.VariableID); 242406c3fb27SDimitry Andric FnVarLocs->addSingleLocVar(Var, VarLoc.Expr, VarLoc.DL, VarLoc.Values); 2425bdd1243dSDimitry Andric InsertedAnyIntrinsics = true; 2426bdd1243dSDimitry Andric } 2427bdd1243dSDimitry Andric } 2428bdd1243dSDimitry Andric } 2429bdd1243dSDimitry Andric 2430bdd1243dSDimitry Andric // Insert the other DEFs. 2431bdd1243dSDimitry Andric for (const auto &[InsertBefore, Vec] : InsertBeforeMap) { 2432bdd1243dSDimitry Andric SmallVector<VarLocInfo> NewDefs; 2433bdd1243dSDimitry Andric for (const VarLocInfo &VarLoc : Vec) { 2434bdd1243dSDimitry Andric DebugVariable Var = FnVarLocs->getVariable(VarLoc.VariableID); 2435bdd1243dSDimitry Andric DebugAggregate Aggr{Var.getVariable(), Var.getInlinedAt()}; 2436bdd1243dSDimitry Andric // If this variable is always stack homed then we have already inserted a 2437bdd1243dSDimitry Andric // dbg.declare and deleted this dbg.value. 2438bdd1243dSDimitry Andric if (AlwaysStackHomed.contains(Aggr)) 2439bdd1243dSDimitry Andric continue; 2440bdd1243dSDimitry Andric NewDefs.push_back(VarLoc); 2441bdd1243dSDimitry Andric InsertedAnyIntrinsics = true; 2442bdd1243dSDimitry Andric } 2443bdd1243dSDimitry Andric 2444bdd1243dSDimitry Andric FnVarLocs->setWedge(InsertBefore, std::move(NewDefs)); 2445bdd1243dSDimitry Andric } 2446bdd1243dSDimitry Andric 2447bdd1243dSDimitry Andric InsertedAnyIntrinsics |= emitPromotedVarLocs(FnVarLocs); 2448bdd1243dSDimitry Andric 2449bdd1243dSDimitry Andric return InsertedAnyIntrinsics; 2450bdd1243dSDimitry Andric } 2451bdd1243dSDimitry Andric 2452bdd1243dSDimitry Andric bool AssignmentTrackingLowering::emitPromotedVarLocs( 2453bdd1243dSDimitry Andric FunctionVarLocsBuilder *FnVarLocs) { 2454bdd1243dSDimitry Andric bool InsertedAnyIntrinsics = false; 2455bdd1243dSDimitry Andric // Go through every block, translating debug intrinsics for fully promoted 2456bdd1243dSDimitry Andric // variables into FnVarLocs location defs. No analysis required for these. 24577a6dacacSDimitry Andric auto TranslateDbgRecord = [&](auto *Record) { 24587a6dacacSDimitry Andric // Skip variables that haven't been promoted - we've dealt with those 24597a6dacacSDimitry Andric // already. 24607a6dacacSDimitry Andric if (VarsWithStackSlot->contains(getAggregate(Record))) 24617a6dacacSDimitry Andric return; 24627a6dacacSDimitry Andric auto InsertBefore = getNextNode(Record); 24637a6dacacSDimitry Andric assert(InsertBefore && "Unexpected: debug intrinsics after a terminator"); 24647a6dacacSDimitry Andric FnVarLocs->addVarLoc(InsertBefore, DebugVariable(Record), 24657a6dacacSDimitry Andric Record->getExpression(), Record->getDebugLoc(), 24667a6dacacSDimitry Andric RawLocationWrapper(Record->getRawLocation())); 24677a6dacacSDimitry Andric InsertedAnyIntrinsics = true; 24687a6dacacSDimitry Andric }; 2469bdd1243dSDimitry Andric for (auto &BB : Fn) { 2470bdd1243dSDimitry Andric for (auto &I : BB) { 2471bdd1243dSDimitry Andric // Skip instructions other than dbg.values and dbg.assigns. 2472*0fca6ea1SDimitry Andric for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange())) 2473*0fca6ea1SDimitry Andric if (DVR.isDbgValue() || DVR.isDbgAssign()) 2474*0fca6ea1SDimitry Andric TranslateDbgRecord(&DVR); 2475bdd1243dSDimitry Andric auto *DVI = dyn_cast<DbgValueInst>(&I); 24767a6dacacSDimitry Andric if (DVI) 24777a6dacacSDimitry Andric TranslateDbgRecord(DVI); 2478bdd1243dSDimitry Andric } 2479bdd1243dSDimitry Andric } 2480bdd1243dSDimitry Andric return InsertedAnyIntrinsics; 2481bdd1243dSDimitry Andric } 2482bdd1243dSDimitry Andric 2483bdd1243dSDimitry Andric /// Remove redundant definitions within sequences of consecutive location defs. 2484bdd1243dSDimitry Andric /// This is done using a backward scan to keep the last def describing a 2485bdd1243dSDimitry Andric /// specific variable/fragment. 2486bdd1243dSDimitry Andric /// 2487bdd1243dSDimitry Andric /// This implements removeRedundantDbgInstrsUsingBackwardScan from 2488bdd1243dSDimitry Andric /// lib/Transforms/Utils/BasicBlockUtils.cpp for locations described with 2489bdd1243dSDimitry Andric /// FunctionVarLocsBuilder instead of with intrinsics. 2490bdd1243dSDimitry Andric static bool 2491bdd1243dSDimitry Andric removeRedundantDbgLocsUsingBackwardScan(const BasicBlock *BB, 2492bdd1243dSDimitry Andric FunctionVarLocsBuilder &FnVarLocs) { 2493bdd1243dSDimitry Andric bool Changed = false; 24945f757f3fSDimitry Andric SmallDenseMap<DebugAggregate, BitVector> VariableDefinedBytes; 2495bdd1243dSDimitry Andric // Scan over the entire block, not just over the instructions mapped by 2496*0fca6ea1SDimitry Andric // FnVarLocs, because wedges in FnVarLocs may only be separated by debug 2497bdd1243dSDimitry Andric // instructions. 2498bdd1243dSDimitry Andric for (const Instruction &I : reverse(*BB)) { 2499bdd1243dSDimitry Andric if (!isa<DbgVariableIntrinsic>(I)) { 2500bdd1243dSDimitry Andric // Sequence of consecutive defs ended. Clear map for the next one. 25015f757f3fSDimitry Andric VariableDefinedBytes.clear(); 2502bdd1243dSDimitry Andric } 2503bdd1243dSDimitry Andric 25047a6dacacSDimitry Andric auto HandleLocsForWedge = [&](auto *WedgePosition) { 2505bdd1243dSDimitry Andric // Get the location defs that start just before this instruction. 25067a6dacacSDimitry Andric const auto *Locs = FnVarLocs.getWedge(WedgePosition); 2507bdd1243dSDimitry Andric if (!Locs) 25087a6dacacSDimitry Andric return; 2509bdd1243dSDimitry Andric 2510bdd1243dSDimitry Andric NumWedgesScanned++; 2511bdd1243dSDimitry Andric bool ChangedThisWedge = false; 2512bdd1243dSDimitry Andric // The new pruned set of defs, reversed because we're scanning backwards. 2513bdd1243dSDimitry Andric SmallVector<VarLocInfo> NewDefsReversed; 2514bdd1243dSDimitry Andric 2515bdd1243dSDimitry Andric // Iterate over the existing defs in reverse. 2516bdd1243dSDimitry Andric for (auto RIt = Locs->rbegin(), REnd = Locs->rend(); RIt != REnd; ++RIt) { 2517bdd1243dSDimitry Andric NumDefsScanned++; 251806c3fb27SDimitry Andric DebugAggregate Aggr = 251906c3fb27SDimitry Andric getAggregate(FnVarLocs.getVariable(RIt->VariableID)); 252006c3fb27SDimitry Andric uint64_t SizeInBits = Aggr.first->getSizeInBits().value_or(0); 25215f757f3fSDimitry Andric uint64_t SizeInBytes = divideCeil(SizeInBits, 8); 2522bdd1243dSDimitry Andric 25235f757f3fSDimitry Andric // Cutoff for large variables to prevent expensive bitvector operations. 25245f757f3fSDimitry Andric const uint64_t MaxSizeBytes = 2048; 25255f757f3fSDimitry Andric 25265f757f3fSDimitry Andric if (SizeInBytes == 0 || SizeInBytes > MaxSizeBytes) { 252706c3fb27SDimitry Andric // If the size is unknown (0) then keep this location def to be safe. 25285f757f3fSDimitry Andric // Do the same for defs of large variables, which would be expensive 25295f757f3fSDimitry Andric // to represent with a BitVector. 2530bdd1243dSDimitry Andric NewDefsReversed.push_back(*RIt); 253106c3fb27SDimitry Andric continue; 253206c3fb27SDimitry Andric } 253306c3fb27SDimitry Andric 253406c3fb27SDimitry Andric // Only keep this location definition if it is not fully eclipsed by 253506c3fb27SDimitry Andric // other definitions in this wedge that come after it 253606c3fb27SDimitry Andric 25375f757f3fSDimitry Andric // Inert the bytes the location definition defines. 253806c3fb27SDimitry Andric auto InsertResult = 25395f757f3fSDimitry Andric VariableDefinedBytes.try_emplace(Aggr, BitVector(SizeInBytes)); 254006c3fb27SDimitry Andric bool FirstDefinition = InsertResult.second; 25415f757f3fSDimitry Andric BitVector &DefinedBytes = InsertResult.first->second; 254206c3fb27SDimitry Andric 254306c3fb27SDimitry Andric DIExpression::FragmentInfo Fragment = 254406c3fb27SDimitry Andric RIt->Expr->getFragmentInfo().value_or( 254506c3fb27SDimitry Andric DIExpression::FragmentInfo(SizeInBits, 0)); 254606c3fb27SDimitry Andric bool InvalidFragment = Fragment.endInBits() > SizeInBits; 25475f757f3fSDimitry Andric uint64_t StartInBytes = Fragment.startInBits() / 8; 25485f757f3fSDimitry Andric uint64_t EndInBytes = divideCeil(Fragment.endInBits(), 8); 254906c3fb27SDimitry Andric 25505f757f3fSDimitry Andric // If this defines any previously undefined bytes, keep it. 255106c3fb27SDimitry Andric if (FirstDefinition || InvalidFragment || 25525f757f3fSDimitry Andric DefinedBytes.find_first_unset_in(StartInBytes, EndInBytes) != -1) { 255306c3fb27SDimitry Andric if (!InvalidFragment) 25545f757f3fSDimitry Andric DefinedBytes.set(StartInBytes, EndInBytes); 255506c3fb27SDimitry Andric NewDefsReversed.push_back(*RIt); 255606c3fb27SDimitry Andric continue; 255706c3fb27SDimitry Andric } 255806c3fb27SDimitry Andric 2559bdd1243dSDimitry Andric // Redundant def found: throw it away. Since the wedge of defs is being 2560bdd1243dSDimitry Andric // rebuilt, doing nothing is the same as deleting an entry. 2561bdd1243dSDimitry Andric ChangedThisWedge = true; 2562bdd1243dSDimitry Andric NumDefsRemoved++; 2563bdd1243dSDimitry Andric } 2564bdd1243dSDimitry Andric 2565bdd1243dSDimitry Andric // Un-reverse the defs and replace the wedge with the pruned version. 2566bdd1243dSDimitry Andric if (ChangedThisWedge) { 2567bdd1243dSDimitry Andric std::reverse(NewDefsReversed.begin(), NewDefsReversed.end()); 25687a6dacacSDimitry Andric FnVarLocs.setWedge(WedgePosition, std::move(NewDefsReversed)); 2569bdd1243dSDimitry Andric NumWedgesChanged++; 2570bdd1243dSDimitry Andric Changed = true; 2571bdd1243dSDimitry Andric } 25727a6dacacSDimitry Andric }; 25737a6dacacSDimitry Andric HandleLocsForWedge(&I); 2574*0fca6ea1SDimitry Andric for (DbgVariableRecord &DVR : reverse(filterDbgVars(I.getDbgRecordRange()))) 2575*0fca6ea1SDimitry Andric HandleLocsForWedge(&DVR); 2576bdd1243dSDimitry Andric } 2577bdd1243dSDimitry Andric 2578bdd1243dSDimitry Andric return Changed; 2579bdd1243dSDimitry Andric } 2580bdd1243dSDimitry Andric 2581bdd1243dSDimitry Andric /// Remove redundant location defs using a forward scan. This can remove a 2582bdd1243dSDimitry Andric /// location definition that is redundant due to indicating that a variable has 2583bdd1243dSDimitry Andric /// the same value as is already being indicated by an earlier def. 2584bdd1243dSDimitry Andric /// 2585bdd1243dSDimitry Andric /// This implements removeRedundantDbgInstrsUsingForwardScan from 2586bdd1243dSDimitry Andric /// lib/Transforms/Utils/BasicBlockUtils.cpp for locations described with 2587bdd1243dSDimitry Andric /// FunctionVarLocsBuilder instead of with intrinsics 2588bdd1243dSDimitry Andric static bool 2589bdd1243dSDimitry Andric removeRedundantDbgLocsUsingForwardScan(const BasicBlock *BB, 2590bdd1243dSDimitry Andric FunctionVarLocsBuilder &FnVarLocs) { 2591bdd1243dSDimitry Andric bool Changed = false; 259206c3fb27SDimitry Andric DenseMap<DebugVariable, std::pair<RawLocationWrapper, DIExpression *>> 259306c3fb27SDimitry Andric VariableMap; 2594bdd1243dSDimitry Andric 2595bdd1243dSDimitry Andric // Scan over the entire block, not just over the instructions mapped by 2596*0fca6ea1SDimitry Andric // FnVarLocs, because wedges in FnVarLocs may only be separated by debug 2597bdd1243dSDimitry Andric // instructions. 2598bdd1243dSDimitry Andric for (const Instruction &I : *BB) { 2599bdd1243dSDimitry Andric // Get the defs that come just before this instruction. 26007a6dacacSDimitry Andric auto HandleLocsForWedge = [&](auto *WedgePosition) { 26017a6dacacSDimitry Andric const auto *Locs = FnVarLocs.getWedge(WedgePosition); 2602bdd1243dSDimitry Andric if (!Locs) 26037a6dacacSDimitry Andric return; 2604bdd1243dSDimitry Andric 2605bdd1243dSDimitry Andric NumWedgesScanned++; 2606bdd1243dSDimitry Andric bool ChangedThisWedge = false; 2607bdd1243dSDimitry Andric // The new pruned set of defs. 2608bdd1243dSDimitry Andric SmallVector<VarLocInfo> NewDefs; 2609bdd1243dSDimitry Andric 2610bdd1243dSDimitry Andric // Iterate over the existing defs. 2611bdd1243dSDimitry Andric for (const VarLocInfo &Loc : *Locs) { 2612bdd1243dSDimitry Andric NumDefsScanned++; 2613bdd1243dSDimitry Andric DebugVariable Key(FnVarLocs.getVariable(Loc.VariableID).getVariable(), 2614bdd1243dSDimitry Andric std::nullopt, Loc.DL.getInlinedAt()); 2615bdd1243dSDimitry Andric auto VMI = VariableMap.find(Key); 2616bdd1243dSDimitry Andric 2617bdd1243dSDimitry Andric // Update the map if we found a new value/expression describing the 2618bdd1243dSDimitry Andric // variable, or if the variable wasn't mapped already. 261906c3fb27SDimitry Andric if (VMI == VariableMap.end() || VMI->second.first != Loc.Values || 2620bdd1243dSDimitry Andric VMI->second.second != Loc.Expr) { 262106c3fb27SDimitry Andric VariableMap[Key] = {Loc.Values, Loc.Expr}; 2622bdd1243dSDimitry Andric NewDefs.push_back(Loc); 2623bdd1243dSDimitry Andric continue; 2624bdd1243dSDimitry Andric } 2625bdd1243dSDimitry Andric 2626bdd1243dSDimitry Andric // Did not insert this Loc, which is the same as removing it. 2627bdd1243dSDimitry Andric ChangedThisWedge = true; 2628bdd1243dSDimitry Andric NumDefsRemoved++; 2629bdd1243dSDimitry Andric } 2630bdd1243dSDimitry Andric 2631bdd1243dSDimitry Andric // Replace the existing wedge with the pruned version. 2632bdd1243dSDimitry Andric if (ChangedThisWedge) { 26337a6dacacSDimitry Andric FnVarLocs.setWedge(WedgePosition, std::move(NewDefs)); 2634bdd1243dSDimitry Andric NumWedgesChanged++; 2635bdd1243dSDimitry Andric Changed = true; 2636bdd1243dSDimitry Andric } 26377a6dacacSDimitry Andric }; 26387a6dacacSDimitry Andric 2639*0fca6ea1SDimitry Andric for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange())) 2640*0fca6ea1SDimitry Andric HandleLocsForWedge(&DVR); 26417a6dacacSDimitry Andric HandleLocsForWedge(&I); 2642bdd1243dSDimitry Andric } 2643bdd1243dSDimitry Andric 2644bdd1243dSDimitry Andric return Changed; 2645bdd1243dSDimitry Andric } 2646bdd1243dSDimitry Andric 2647bdd1243dSDimitry Andric static bool 2648bdd1243dSDimitry Andric removeUndefDbgLocsFromEntryBlock(const BasicBlock *BB, 2649bdd1243dSDimitry Andric FunctionVarLocsBuilder &FnVarLocs) { 2650bdd1243dSDimitry Andric assert(BB->isEntryBlock()); 2651bdd1243dSDimitry Andric // Do extra work to ensure that we remove semantically unimportant undefs. 2652bdd1243dSDimitry Andric // 2653bdd1243dSDimitry Andric // This is to work around the fact that SelectionDAG will hoist dbg.values 2654bdd1243dSDimitry Andric // using argument values to the top of the entry block. That can move arg 2655bdd1243dSDimitry Andric // dbg.values before undef and constant dbg.values which they previously 2656bdd1243dSDimitry Andric // followed. The easiest thing to do is to just try to feed SelectionDAG 2657bdd1243dSDimitry Andric // input it's happy with. 2658bdd1243dSDimitry Andric // 2659bdd1243dSDimitry Andric // Map of {Variable x: Fragments y} where the fragments y of variable x have 2660bdd1243dSDimitry Andric // have at least one non-undef location defined already. Don't use directly, 2661bdd1243dSDimitry Andric // instead call DefineBits and HasDefinedBits. 2662bdd1243dSDimitry Andric SmallDenseMap<DebugAggregate, SmallDenseSet<DIExpression::FragmentInfo>> 2663bdd1243dSDimitry Andric VarsWithDef; 2664bdd1243dSDimitry Andric // Specify that V (a fragment of A) has a non-undef location. 2665bdd1243dSDimitry Andric auto DefineBits = [&VarsWithDef](DebugAggregate A, DebugVariable V) { 2666bdd1243dSDimitry Andric VarsWithDef[A].insert(V.getFragmentOrDefault()); 2667bdd1243dSDimitry Andric }; 2668bdd1243dSDimitry Andric // Return true if a non-undef location has been defined for V (a fragment of 2669bdd1243dSDimitry Andric // A). Doesn't imply that the location is currently non-undef, just that a 2670bdd1243dSDimitry Andric // non-undef location has been seen previously. 2671bdd1243dSDimitry Andric auto HasDefinedBits = [&VarsWithDef](DebugAggregate A, DebugVariable V) { 2672bdd1243dSDimitry Andric auto FragsIt = VarsWithDef.find(A); 2673bdd1243dSDimitry Andric if (FragsIt == VarsWithDef.end()) 2674bdd1243dSDimitry Andric return false; 2675bdd1243dSDimitry Andric return llvm::any_of(FragsIt->second, [V](auto Frag) { 2676bdd1243dSDimitry Andric return DIExpression::fragmentsOverlap(Frag, V.getFragmentOrDefault()); 2677bdd1243dSDimitry Andric }); 2678bdd1243dSDimitry Andric }; 2679bdd1243dSDimitry Andric 2680bdd1243dSDimitry Andric bool Changed = false; 2681bdd1243dSDimitry Andric DenseMap<DebugVariable, std::pair<Value *, DIExpression *>> VariableMap; 2682bdd1243dSDimitry Andric 2683bdd1243dSDimitry Andric // Scan over the entire block, not just over the instructions mapped by 2684*0fca6ea1SDimitry Andric // FnVarLocs, because wedges in FnVarLocs may only be separated by debug 2685bdd1243dSDimitry Andric // instructions. 2686bdd1243dSDimitry Andric for (const Instruction &I : *BB) { 2687bdd1243dSDimitry Andric // Get the defs that come just before this instruction. 26887a6dacacSDimitry Andric auto HandleLocsForWedge = [&](auto *WedgePosition) { 26897a6dacacSDimitry Andric const auto *Locs = FnVarLocs.getWedge(WedgePosition); 2690bdd1243dSDimitry Andric if (!Locs) 26917a6dacacSDimitry Andric return; 2692bdd1243dSDimitry Andric 2693bdd1243dSDimitry Andric NumWedgesScanned++; 2694bdd1243dSDimitry Andric bool ChangedThisWedge = false; 2695bdd1243dSDimitry Andric // The new pruned set of defs. 2696bdd1243dSDimitry Andric SmallVector<VarLocInfo> NewDefs; 2697bdd1243dSDimitry Andric 2698bdd1243dSDimitry Andric // Iterate over the existing defs. 2699bdd1243dSDimitry Andric for (const VarLocInfo &Loc : *Locs) { 2700bdd1243dSDimitry Andric NumDefsScanned++; 2701bdd1243dSDimitry Andric DebugAggregate Aggr{FnVarLocs.getVariable(Loc.VariableID).getVariable(), 2702bdd1243dSDimitry Andric Loc.DL.getInlinedAt()}; 2703bdd1243dSDimitry Andric DebugVariable Var = FnVarLocs.getVariable(Loc.VariableID); 2704bdd1243dSDimitry Andric 2705bdd1243dSDimitry Andric // Remove undef entries that are encountered before any non-undef 2706bdd1243dSDimitry Andric // intrinsics from the entry block. 270706c3fb27SDimitry Andric if (Loc.Values.isKillLocation(Loc.Expr) && !HasDefinedBits(Aggr, Var)) { 2708bdd1243dSDimitry Andric // Did not insert this Loc, which is the same as removing it. 2709bdd1243dSDimitry Andric NumDefsRemoved++; 2710bdd1243dSDimitry Andric ChangedThisWedge = true; 2711bdd1243dSDimitry Andric continue; 2712bdd1243dSDimitry Andric } 2713bdd1243dSDimitry Andric 2714bdd1243dSDimitry Andric DefineBits(Aggr, Var); 2715bdd1243dSDimitry Andric NewDefs.push_back(Loc); 2716bdd1243dSDimitry Andric } 2717bdd1243dSDimitry Andric 2718bdd1243dSDimitry Andric // Replace the existing wedge with the pruned version. 2719bdd1243dSDimitry Andric if (ChangedThisWedge) { 27207a6dacacSDimitry Andric FnVarLocs.setWedge(WedgePosition, std::move(NewDefs)); 2721bdd1243dSDimitry Andric NumWedgesChanged++; 2722bdd1243dSDimitry Andric Changed = true; 2723bdd1243dSDimitry Andric } 27247a6dacacSDimitry Andric }; 2725*0fca6ea1SDimitry Andric for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange())) 2726*0fca6ea1SDimitry Andric HandleLocsForWedge(&DVR); 27277a6dacacSDimitry Andric HandleLocsForWedge(&I); 2728bdd1243dSDimitry Andric } 2729bdd1243dSDimitry Andric 2730bdd1243dSDimitry Andric return Changed; 2731bdd1243dSDimitry Andric } 2732bdd1243dSDimitry Andric 2733bdd1243dSDimitry Andric static bool removeRedundantDbgLocs(const BasicBlock *BB, 2734bdd1243dSDimitry Andric FunctionVarLocsBuilder &FnVarLocs) { 2735bdd1243dSDimitry Andric bool MadeChanges = false; 2736bdd1243dSDimitry Andric MadeChanges |= removeRedundantDbgLocsUsingBackwardScan(BB, FnVarLocs); 2737bdd1243dSDimitry Andric if (BB->isEntryBlock()) 2738bdd1243dSDimitry Andric MadeChanges |= removeUndefDbgLocsFromEntryBlock(BB, FnVarLocs); 2739bdd1243dSDimitry Andric MadeChanges |= removeRedundantDbgLocsUsingForwardScan(BB, FnVarLocs); 2740bdd1243dSDimitry Andric 2741bdd1243dSDimitry Andric if (MadeChanges) 2742bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "Removed redundant dbg locs from: " << BB->getName() 2743bdd1243dSDimitry Andric << "\n"); 2744bdd1243dSDimitry Andric return MadeChanges; 2745bdd1243dSDimitry Andric } 2746bdd1243dSDimitry Andric 2747bdd1243dSDimitry Andric static DenseSet<DebugAggregate> findVarsWithStackSlot(Function &Fn) { 2748bdd1243dSDimitry Andric DenseSet<DebugAggregate> Result; 2749bdd1243dSDimitry Andric for (auto &BB : Fn) { 2750bdd1243dSDimitry Andric for (auto &I : BB) { 2751bdd1243dSDimitry Andric // Any variable linked to an instruction is considered 2752bdd1243dSDimitry Andric // interesting. Ideally we only need to check Allocas, however, a 2753bdd1243dSDimitry Andric // DIAssignID might get dropped from an alloca but not stores. In that 2754bdd1243dSDimitry Andric // case, we need to consider the variable interesting for NFC behaviour 2755bdd1243dSDimitry Andric // with this change. TODO: Consider only looking at allocas. 2756bdd1243dSDimitry Andric for (DbgAssignIntrinsic *DAI : at::getAssignmentMarkers(&I)) { 2757bdd1243dSDimitry Andric Result.insert({DAI->getVariable(), DAI->getDebugLoc().getInlinedAt()}); 2758bdd1243dSDimitry Andric } 2759*0fca6ea1SDimitry Andric for (DbgVariableRecord *DVR : at::getDVRAssignmentMarkers(&I)) { 2760*0fca6ea1SDimitry Andric Result.insert({DVR->getVariable(), DVR->getDebugLoc().getInlinedAt()}); 27617a6dacacSDimitry Andric } 2762bdd1243dSDimitry Andric } 2763bdd1243dSDimitry Andric } 2764bdd1243dSDimitry Andric return Result; 2765bdd1243dSDimitry Andric } 2766bdd1243dSDimitry Andric 2767bdd1243dSDimitry Andric static void analyzeFunction(Function &Fn, const DataLayout &Layout, 2768bdd1243dSDimitry Andric FunctionVarLocsBuilder *FnVarLocs) { 2769bdd1243dSDimitry Andric // The analysis will generate location definitions for all variables, but we 2770bdd1243dSDimitry Andric // only need to perform a dataflow on the set of variables which have a stack 2771bdd1243dSDimitry Andric // slot. Find those now. 2772bdd1243dSDimitry Andric DenseSet<DebugAggregate> VarsWithStackSlot = findVarsWithStackSlot(Fn); 2773bdd1243dSDimitry Andric 2774bdd1243dSDimitry Andric bool Changed = false; 2775bdd1243dSDimitry Andric 2776bdd1243dSDimitry Andric // Use a scope block to clean up AssignmentTrackingLowering before running 2777bdd1243dSDimitry Andric // MemLocFragmentFill to reduce peak memory consumption. 2778bdd1243dSDimitry Andric { 2779bdd1243dSDimitry Andric AssignmentTrackingLowering Pass(Fn, Layout, &VarsWithStackSlot); 2780bdd1243dSDimitry Andric Changed = Pass.run(FnVarLocs); 2781bdd1243dSDimitry Andric } 2782bdd1243dSDimitry Andric 2783bdd1243dSDimitry Andric if (Changed) { 278406c3fb27SDimitry Andric MemLocFragmentFill Pass(Fn, &VarsWithStackSlot, 278506c3fb27SDimitry Andric shouldCoalesceFragments(Fn)); 2786bdd1243dSDimitry Andric Pass.run(FnVarLocs); 2787bdd1243dSDimitry Andric 2788bdd1243dSDimitry Andric // Remove redundant entries. As well as reducing memory consumption and 2789bdd1243dSDimitry Andric // avoiding waiting cycles later by burning some now, this has another 2790bdd1243dSDimitry Andric // important job. That is to work around some SelectionDAG quirks. See 2791bdd1243dSDimitry Andric // removeRedundantDbgLocsUsingForwardScan comments for more info on that. 2792bdd1243dSDimitry Andric for (auto &BB : Fn) 2793bdd1243dSDimitry Andric removeRedundantDbgLocs(&BB, *FnVarLocs); 2794bdd1243dSDimitry Andric } 2795bdd1243dSDimitry Andric } 2796bdd1243dSDimitry Andric 2797297eecfbSDimitry Andric FunctionVarLocs 2798297eecfbSDimitry Andric DebugAssignmentTrackingAnalysis::run(Function &F, 2799297eecfbSDimitry Andric FunctionAnalysisManager &FAM) { 2800297eecfbSDimitry Andric if (!isAssignmentTrackingEnabled(*F.getParent())) 2801297eecfbSDimitry Andric return FunctionVarLocs(); 2802297eecfbSDimitry Andric 2803*0fca6ea1SDimitry Andric auto &DL = F.getDataLayout(); 2804297eecfbSDimitry Andric 2805297eecfbSDimitry Andric FunctionVarLocsBuilder Builder; 2806297eecfbSDimitry Andric analyzeFunction(F, DL, &Builder); 2807297eecfbSDimitry Andric 2808297eecfbSDimitry Andric // Save these results. 2809297eecfbSDimitry Andric FunctionVarLocs Results; 2810297eecfbSDimitry Andric Results.init(Builder); 2811297eecfbSDimitry Andric return Results; 2812297eecfbSDimitry Andric } 2813297eecfbSDimitry Andric 2814297eecfbSDimitry Andric AnalysisKey DebugAssignmentTrackingAnalysis::Key; 2815297eecfbSDimitry Andric 2816297eecfbSDimitry Andric PreservedAnalyses 2817297eecfbSDimitry Andric DebugAssignmentTrackingPrinterPass::run(Function &F, 2818297eecfbSDimitry Andric FunctionAnalysisManager &FAM) { 2819297eecfbSDimitry Andric FAM.getResult<DebugAssignmentTrackingAnalysis>(F).print(OS, F); 2820297eecfbSDimitry Andric return PreservedAnalyses::all(); 2821297eecfbSDimitry Andric } 2822297eecfbSDimitry Andric 2823bdd1243dSDimitry Andric bool AssignmentTrackingAnalysis::runOnFunction(Function &F) { 2824bdd1243dSDimitry Andric if (!isAssignmentTrackingEnabled(*F.getParent())) 2825bdd1243dSDimitry Andric return false; 2826bdd1243dSDimitry Andric 2827bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "AssignmentTrackingAnalysis run on " << F.getName() 2828bdd1243dSDimitry Andric << "\n"); 2829bdd1243dSDimitry Andric auto DL = std::make_unique<DataLayout>(F.getParent()); 2830bdd1243dSDimitry Andric 2831bdd1243dSDimitry Andric // Clear previous results. 2832bdd1243dSDimitry Andric Results->clear(); 2833bdd1243dSDimitry Andric 2834bdd1243dSDimitry Andric FunctionVarLocsBuilder Builder; 2835bdd1243dSDimitry Andric analyzeFunction(F, *DL.get(), &Builder); 2836bdd1243dSDimitry Andric 2837bdd1243dSDimitry Andric // Save these results. 2838bdd1243dSDimitry Andric Results->init(Builder); 2839bdd1243dSDimitry Andric 2840bdd1243dSDimitry Andric if (PrintResults && isFunctionInPrintList(F.getName())) 2841bdd1243dSDimitry Andric Results->print(errs(), F); 2842bdd1243dSDimitry Andric 2843bdd1243dSDimitry Andric // Return false because this pass does not modify the function. 2844bdd1243dSDimitry Andric return false; 2845bdd1243dSDimitry Andric } 2846bdd1243dSDimitry Andric 2847bdd1243dSDimitry Andric AssignmentTrackingAnalysis::AssignmentTrackingAnalysis() 2848bdd1243dSDimitry Andric : FunctionPass(ID), Results(std::make_unique<FunctionVarLocs>()) {} 2849bdd1243dSDimitry Andric 2850bdd1243dSDimitry Andric char AssignmentTrackingAnalysis::ID = 0; 2851bdd1243dSDimitry Andric 2852bdd1243dSDimitry Andric INITIALIZE_PASS(AssignmentTrackingAnalysis, DEBUG_TYPE, 2853bdd1243dSDimitry Andric "Assignment Tracking Analysis", false, true) 2854