xref: /llvm-project/llvm/lib/CodeGen/AssignmentTrackingAnalysis.cpp (revision c5312553cb7a49b53ba2bac40fbc3c1745855844)
17c71a09dSpaperchalice //===-- AssignmentTrackingAnalysis.cpp ------------------------------------===//
27c71a09dSpaperchalice //
37c71a09dSpaperchalice // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47c71a09dSpaperchalice // See https://llvm.org/LICENSE.txt for license information.
57c71a09dSpaperchalice // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67c71a09dSpaperchalice //
77c71a09dSpaperchalice //===----------------------------------------------------------------------===//
87c71a09dSpaperchalice 
91d1de746SOCHyams #include "llvm/CodeGen/AssignmentTrackingAnalysis.h"
10d4879d76SOCHyams #include "LiveDebugValues/LiveDebugValues.h"
11d5b2c8e5SOCHyams #include "llvm/ADT/BitVector.h"
121d1de746SOCHyams #include "llvm/ADT/DenseMapInfo.h"
131d1de746SOCHyams #include "llvm/ADT/IntervalMap.h"
141d1de746SOCHyams #include "llvm/ADT/PostOrderIterator.h"
151d1de746SOCHyams #include "llvm/ADT/STLExtras.h"
161d1de746SOCHyams #include "llvm/ADT/Statistic.h"
171d1de746SOCHyams #include "llvm/ADT/UniqueVector.h"
181d1de746SOCHyams #include "llvm/BinaryFormat/Dwarf.h"
191d1de746SOCHyams #include "llvm/IR/BasicBlock.h"
201d1de746SOCHyams #include "llvm/IR/DataLayout.h"
211d1de746SOCHyams #include "llvm/IR/DebugInfo.h"
226aeb7a71SStephen Tozer #include "llvm/IR/DebugProgramInstruction.h"
231d1de746SOCHyams #include "llvm/IR/Function.h"
241d1de746SOCHyams #include "llvm/IR/Instruction.h"
251d1de746SOCHyams #include "llvm/IR/IntrinsicInst.h"
264169338eSNikita Popov #include "llvm/IR/Module.h"
271d1de746SOCHyams #include "llvm/IR/PassManager.h"
281d1de746SOCHyams #include "llvm/IR/PrintPasses.h"
291d1de746SOCHyams #include "llvm/InitializePasses.h"
301d1de746SOCHyams #include "llvm/Support/CommandLine.h"
311d1de746SOCHyams #include "llvm/Support/ErrorHandling.h"
321d1de746SOCHyams #include "llvm/Support/raw_ostream.h"
331d1de746SOCHyams #include "llvm/Transforms/Utils/BasicBlockUtils.h"
341d1de746SOCHyams #include <assert.h>
351d1de746SOCHyams #include <cstdint>
369c444f70SKazu Hirata #include <optional>
3703f05a4eSNikita Popov #include <queue>
381d1de746SOCHyams #include <sstream>
391d1de746SOCHyams #include <unordered_map>
401d1de746SOCHyams 
411d1de746SOCHyams using namespace llvm;
421d1de746SOCHyams #define DEBUG_TYPE "debug-ata"
431d1de746SOCHyams 
441d1de746SOCHyams STATISTIC(NumDefsScanned, "Number of dbg locs that get scanned for removal");
451d1de746SOCHyams STATISTIC(NumDefsRemoved, "Number of dbg locs removed");
461d1de746SOCHyams STATISTIC(NumWedgesScanned, "Number of dbg wedges scanned");
471d1de746SOCHyams STATISTIC(NumWedgesChanged, "Number of dbg wedges changed");
481d1de746SOCHyams 
491d1de746SOCHyams static cl::opt<unsigned>
501d1de746SOCHyams     MaxNumBlocks("debug-ata-max-blocks", cl::init(10000),
511d1de746SOCHyams                  cl::desc("Maximum num basic blocks before debug info dropped"),
521d1de746SOCHyams                  cl::Hidden);
531d1de746SOCHyams /// Option for debugging the pass, determines if the memory location fragment
541d1de746SOCHyams /// filling happens after generating the variable locations.
551d1de746SOCHyams static cl::opt<bool> EnableMemLocFragFill("mem-loc-frag-fill", cl::init(true),
561d1de746SOCHyams                                           cl::Hidden);
571d1de746SOCHyams /// Print the results of the analysis. Respects -filter-print-funcs.
581d1de746SOCHyams static cl::opt<bool> PrintResults("print-debug-ata", cl::init(false),
591d1de746SOCHyams                                   cl::Hidden);
601d1de746SOCHyams 
61d4879d76SOCHyams /// Coalesce adjacent dbg locs describing memory locations that have contiguous
62d4879d76SOCHyams /// fragments. This reduces the cost of LiveDebugValues which does SSA
63d4879d76SOCHyams /// construction for each explicitly stated variable fragment.
64d4879d76SOCHyams static cl::opt<cl::boolOrDefault>
65d4879d76SOCHyams     CoalesceAdjacentFragmentsOpt("debug-ata-coalesce-frags", cl::Hidden);
66d4879d76SOCHyams 
671d1de746SOCHyams // Implicit conversions are disabled for enum class types, so unfortunately we
681d1de746SOCHyams // need to create a DenseMapInfo wrapper around the specified underlying type.
691d1de746SOCHyams template <> struct llvm::DenseMapInfo<VariableID> {
701d1de746SOCHyams   using Wrapped = DenseMapInfo<unsigned>;
711d1de746SOCHyams   static inline VariableID getEmptyKey() {
721d1de746SOCHyams     return static_cast<VariableID>(Wrapped::getEmptyKey());
731d1de746SOCHyams   }
741d1de746SOCHyams   static inline VariableID getTombstoneKey() {
751d1de746SOCHyams     return static_cast<VariableID>(Wrapped::getTombstoneKey());
761d1de746SOCHyams   }
771d1de746SOCHyams   static unsigned getHashValue(const VariableID &Val) {
781d1de746SOCHyams     return Wrapped::getHashValue(static_cast<unsigned>(Val));
791d1de746SOCHyams   }
801d1de746SOCHyams   static bool isEqual(const VariableID &LHS, const VariableID &RHS) {
811d1de746SOCHyams     return LHS == RHS;
821d1de746SOCHyams   }
831d1de746SOCHyams };
841d1de746SOCHyams 
85ababa964SOrlando Cazalet-Hyams using VarLocInsertPt = PointerUnion<const Instruction *, const DbgRecord *>;
866aeb7a71SStephen Tozer 
876aeb7a71SStephen Tozer namespace std {
886aeb7a71SStephen Tozer template <> struct hash<VarLocInsertPt> {
896aeb7a71SStephen Tozer   using argument_type = VarLocInsertPt;
906aeb7a71SStephen Tozer   using result_type = std::size_t;
916aeb7a71SStephen Tozer 
926aeb7a71SStephen Tozer   result_type operator()(const argument_type &Arg) const {
936aeb7a71SStephen Tozer     return std::hash<void *>()(Arg.getOpaqueValue());
946aeb7a71SStephen Tozer   }
956aeb7a71SStephen Tozer };
966aeb7a71SStephen Tozer } // namespace std
976aeb7a71SStephen Tozer 
981d1de746SOCHyams /// Helper class to build FunctionVarLocs, since that class isn't easy to
991d1de746SOCHyams /// modify. TODO: There's not a great deal of value in the split, it could be
1001d1de746SOCHyams /// worth merging the two classes.
1011d1de746SOCHyams class FunctionVarLocsBuilder {
1021d1de746SOCHyams   friend FunctionVarLocs;
1031d1de746SOCHyams   UniqueVector<DebugVariable> Variables;
1041d1de746SOCHyams   // Use an unordered_map so we don't invalidate iterators after
1051d1de746SOCHyams   // insert/modifications.
1066aeb7a71SStephen Tozer   std::unordered_map<VarLocInsertPt, SmallVector<VarLocInfo>> VarLocsBeforeInst;
1071d1de746SOCHyams 
1081d1de746SOCHyams   SmallVector<VarLocInfo> SingleLocVars;
1091d1de746SOCHyams 
1101d1de746SOCHyams public:
111d5b2c8e5SOCHyams   unsigned getNumVariables() const { return Variables.size(); }
112d5b2c8e5SOCHyams 
1131d1de746SOCHyams   /// Find or insert \p V and return the ID.
1141d1de746SOCHyams   VariableID insertVariable(DebugVariable V) {
1151d1de746SOCHyams     return static_cast<VariableID>(Variables.insert(V));
1161d1de746SOCHyams   }
1171d1de746SOCHyams 
1181d1de746SOCHyams   /// Get a variable from its \p ID.
1191d1de746SOCHyams   const DebugVariable &getVariable(VariableID ID) const {
1201d1de746SOCHyams     return Variables[static_cast<unsigned>(ID)];
1211d1de746SOCHyams   }
1221d1de746SOCHyams 
1231d1de746SOCHyams   /// Return ptr to wedge of defs or nullptr if no defs come just before /p
1241d1de746SOCHyams   /// Before.
1256aeb7a71SStephen Tozer   const SmallVectorImpl<VarLocInfo> *getWedge(VarLocInsertPt Before) const {
1261d1de746SOCHyams     auto R = VarLocsBeforeInst.find(Before);
1271d1de746SOCHyams     if (R == VarLocsBeforeInst.end())
1281d1de746SOCHyams       return nullptr;
1291d1de746SOCHyams     return &R->second;
1301d1de746SOCHyams   }
1311d1de746SOCHyams 
1321d1de746SOCHyams   /// Replace the defs that come just before /p Before with /p Wedge.
1336aeb7a71SStephen Tozer   void setWedge(VarLocInsertPt Before, SmallVector<VarLocInfo> &&Wedge) {
1341d1de746SOCHyams     VarLocsBeforeInst[Before] = std::move(Wedge);
1351d1de746SOCHyams   }
1361d1de746SOCHyams 
1371d1de746SOCHyams   /// Add a def for a variable that is valid for its lifetime.
1381d1de746SOCHyams   void addSingleLocVar(DebugVariable Var, DIExpression *Expr, DebugLoc DL,
1397d894374SOCHyams                        RawLocationWrapper R) {
1401d1de746SOCHyams     VarLocInfo VarLoc;
1411d1de746SOCHyams     VarLoc.VariableID = insertVariable(Var);
1421d1de746SOCHyams     VarLoc.Expr = Expr;
1431d1de746SOCHyams     VarLoc.DL = DL;
1447d894374SOCHyams     VarLoc.Values = R;
1451d1de746SOCHyams     SingleLocVars.emplace_back(VarLoc);
1461d1de746SOCHyams   }
1471d1de746SOCHyams 
1481d1de746SOCHyams   /// Add a def to the wedge of defs just before /p Before.
1496aeb7a71SStephen Tozer   void addVarLoc(VarLocInsertPt Before, DebugVariable Var, DIExpression *Expr,
1507d894374SOCHyams                  DebugLoc DL, RawLocationWrapper R) {
1511d1de746SOCHyams     VarLocInfo VarLoc;
1521d1de746SOCHyams     VarLoc.VariableID = insertVariable(Var);
1531d1de746SOCHyams     VarLoc.Expr = Expr;
1541d1de746SOCHyams     VarLoc.DL = DL;
1557d894374SOCHyams     VarLoc.Values = R;
1561d1de746SOCHyams     VarLocsBeforeInst[Before].emplace_back(VarLoc);
1571d1de746SOCHyams   }
1581d1de746SOCHyams };
1591d1de746SOCHyams 
1601d1de746SOCHyams void FunctionVarLocs::print(raw_ostream &OS, const Function &Fn) const {
1611d1de746SOCHyams   // Print the variable table first. TODO: Sorting by variable could make the
1621d1de746SOCHyams   // output more stable?
1631d1de746SOCHyams   unsigned Counter = -1;
1641d1de746SOCHyams   OS << "=== Variables ===\n";
1651d1de746SOCHyams   for (const DebugVariable &V : Variables) {
1661d1de746SOCHyams     ++Counter;
1671d1de746SOCHyams     // Skip first entry because it is a dummy entry.
1681d1de746SOCHyams     if (Counter == 0) {
1691d1de746SOCHyams       continue;
1701d1de746SOCHyams     }
1711d1de746SOCHyams     OS << "[" << Counter << "] " << V.getVariable()->getName();
1721d1de746SOCHyams     if (auto F = V.getFragment())
1731d1de746SOCHyams       OS << " bits [" << F->OffsetInBits << ", "
1741d1de746SOCHyams          << F->OffsetInBits + F->SizeInBits << ")";
1751d1de746SOCHyams     if (const auto *IA = V.getInlinedAt())
1761d1de746SOCHyams       OS << " inlined-at " << *IA;
1771d1de746SOCHyams     OS << "\n";
1781d1de746SOCHyams   }
1791d1de746SOCHyams 
1801d1de746SOCHyams   auto PrintLoc = [&OS](const VarLocInfo &Loc) {
1811d1de746SOCHyams     OS << "DEF Var=[" << (unsigned)Loc.VariableID << "]"
1827d894374SOCHyams        << " Expr=" << *Loc.Expr << " Values=(";
1837d894374SOCHyams     for (auto *Op : Loc.Values.location_ops()) {
1847d894374SOCHyams       errs() << Op->getName() << " ";
1857d894374SOCHyams     }
1867d894374SOCHyams     errs() << ")\n";
1871d1de746SOCHyams   };
1881d1de746SOCHyams 
1891d1de746SOCHyams   // Print the single location variables.
1901d1de746SOCHyams   OS << "=== Single location vars ===\n";
1911d1de746SOCHyams   for (auto It = single_locs_begin(), End = single_locs_end(); It != End;
1921d1de746SOCHyams        ++It) {
1931d1de746SOCHyams     PrintLoc(*It);
1941d1de746SOCHyams   }
1951d1de746SOCHyams 
1961d1de746SOCHyams   // Print the non-single-location defs in line with IR.
1971d1de746SOCHyams   OS << "=== In-line variable defs ===";
1981d1de746SOCHyams   for (const BasicBlock &BB : Fn) {
1991d1de746SOCHyams     OS << "\n" << BB.getName() << ":\n";
2001d1de746SOCHyams     for (const Instruction &I : BB) {
2011d1de746SOCHyams       for (auto It = locs_begin(&I), End = locs_end(&I); It != End; ++It) {
2021d1de746SOCHyams         PrintLoc(*It);
2031d1de746SOCHyams       }
2041d1de746SOCHyams       OS << I << "\n";
2051d1de746SOCHyams     }
2061d1de746SOCHyams   }
2071d1de746SOCHyams }
2081d1de746SOCHyams 
2091d1de746SOCHyams void FunctionVarLocs::init(FunctionVarLocsBuilder &Builder) {
2101d1de746SOCHyams   // Add the single-location variables first.
2111d1de746SOCHyams   for (const auto &VarLoc : Builder.SingleLocVars)
2121d1de746SOCHyams     VarLocRecords.emplace_back(VarLoc);
2131d1de746SOCHyams   // Mark the end of the section.
2141d1de746SOCHyams   SingleVarLocEnd = VarLocRecords.size();
2151d1de746SOCHyams 
2161d1de746SOCHyams   // Insert a contiguous block of VarLocInfos for each instruction, mapping it
2176aeb7a71SStephen Tozer   // to the start and end position in the vector with VarLocsBeforeInst. This
218ffd08c77SStephen Tozer   // block includes VarLocs for any DbgVariableRecords attached to that
219ffd08c77SStephen Tozer   // instruction.
2201d1de746SOCHyams   for (auto &P : Builder.VarLocsBeforeInst) {
221360da838SStephen Tozer     // Process VarLocs attached to a DbgRecord alongside their marker
222360da838SStephen Tozer     // Instruction.
223ababa964SOrlando Cazalet-Hyams     if (isa<const DbgRecord *>(P.first))
2246aeb7a71SStephen Tozer       continue;
2256aeb7a71SStephen Tozer     const Instruction *I = cast<const Instruction *>(P.first);
2261d1de746SOCHyams     unsigned BlockStart = VarLocRecords.size();
227360da838SStephen Tozer     // Any VarLocInfos attached to a DbgRecord should now be remapped to their
228360da838SStephen Tozer     // marker Instruction, in order of DbgRecord appearance and prior to any
2296aeb7a71SStephen Tozer     // VarLocInfos attached directly to that instruction.
230ffd08c77SStephen Tozer     for (const DbgVariableRecord &DVR : filterDbgVars(I->getDbgRecordRange())) {
231ffd08c77SStephen Tozer       // Even though DVR defines a variable location, VarLocsBeforeInst can
2326aeb7a71SStephen Tozer       // still be empty if that VarLoc was redundant.
233*c5312553SKazu Hirata       auto It = Builder.VarLocsBeforeInst.find(&DVR);
234*c5312553SKazu Hirata       if (It == Builder.VarLocsBeforeInst.end())
2356aeb7a71SStephen Tozer         continue;
236*c5312553SKazu Hirata       for (const VarLocInfo &VarLoc : It->second)
2376aeb7a71SStephen Tozer         VarLocRecords.emplace_back(VarLoc);
2386aeb7a71SStephen Tozer     }
2391d1de746SOCHyams     for (const VarLocInfo &VarLoc : P.second)
2401d1de746SOCHyams       VarLocRecords.emplace_back(VarLoc);
2411d1de746SOCHyams     unsigned BlockEnd = VarLocRecords.size();
2421d1de746SOCHyams     // Record the start and end indices.
2431d1de746SOCHyams     if (BlockEnd != BlockStart)
2446aeb7a71SStephen Tozer       VarLocsBeforeInst[I] = {BlockStart, BlockEnd};
2451d1de746SOCHyams   }
2461d1de746SOCHyams 
2471d1de746SOCHyams   // Copy the Variables vector from the builder's UniqueVector.
2481d1de746SOCHyams   assert(Variables.empty() && "Expect clear before init");
2491d1de746SOCHyams   // UniqueVectors IDs are one-based (which means the VarLocInfo VarID values
2501d1de746SOCHyams   // are one-based) so reserve an extra and insert a dummy.
2511d1de746SOCHyams   Variables.reserve(Builder.Variables.size() + 1);
2529c444f70SKazu Hirata   Variables.push_back(DebugVariable(nullptr, std::nullopt, nullptr));
2531d1de746SOCHyams   Variables.append(Builder.Variables.begin(), Builder.Variables.end());
2541d1de746SOCHyams }
2551d1de746SOCHyams 
2561d1de746SOCHyams void FunctionVarLocs::clear() {
2571d1de746SOCHyams   Variables.clear();
2581d1de746SOCHyams   VarLocRecords.clear();
2591d1de746SOCHyams   VarLocsBeforeInst.clear();
2601d1de746SOCHyams   SingleVarLocEnd = 0;
2611d1de746SOCHyams }
2621d1de746SOCHyams 
2631d1de746SOCHyams /// Walk backwards along constant GEPs and bitcasts to the base storage from \p
2641d1de746SOCHyams /// Start as far as possible. Prepend \Expression with the offset and append it
2651d1de746SOCHyams /// with a DW_OP_deref that haes been implicit until now. Returns the walked-to
2661d1de746SOCHyams /// value and modified expression.
2671d1de746SOCHyams static std::pair<Value *, DIExpression *>
2681d1de746SOCHyams walkToAllocaAndPrependOffsetDeref(const DataLayout &DL, Value *Start,
2691d1de746SOCHyams                                   DIExpression *Expression) {
2701d1de746SOCHyams   APInt OffsetInBytes(DL.getTypeSizeInBits(Start->getType()), false);
2711d1de746SOCHyams   Value *End =
2721d1de746SOCHyams       Start->stripAndAccumulateInBoundsConstantOffsets(DL, OffsetInBytes);
2731d1de746SOCHyams   SmallVector<uint64_t, 3> Ops;
2741d1de746SOCHyams   if (OffsetInBytes.getBoolValue()) {
2751d1de746SOCHyams     Ops = {dwarf::DW_OP_plus_uconst, OffsetInBytes.getZExtValue()};
2761d1de746SOCHyams     Expression = DIExpression::prependOpcodes(
2771d1de746SOCHyams         Expression, Ops, /*StackValue=*/false, /*EntryValue=*/false);
2781d1de746SOCHyams   }
2791d1de746SOCHyams   Expression = DIExpression::append(Expression, {dwarf::DW_OP_deref});
2801d1de746SOCHyams   return {End, Expression};
2811d1de746SOCHyams }
2821d1de746SOCHyams 
2833eebbaf0SKazu Hirata /// Extract the offset used in \p DIExpr. Returns std::nullopt if the expression
2841d1de746SOCHyams /// doesn't explicitly describe a memory location with DW_OP_deref or if the
2851d1de746SOCHyams /// expression is too complex to interpret.
28667819a72SFangrui Song static std::optional<int64_t>
28767819a72SFangrui Song getDerefOffsetInBytes(const DIExpression *DIExpr) {
2881d1de746SOCHyams   int64_t Offset = 0;
2891d1de746SOCHyams   const unsigned NumElements = DIExpr->getNumElements();
2901d1de746SOCHyams   const auto Elements = DIExpr->getElements();
29125d0f3c4SOCHyams   unsigned ExpectedDerefIdx = 0;
2921d1de746SOCHyams   // Extract the offset.
2931d1de746SOCHyams   if (NumElements > 2 && Elements[0] == dwarf::DW_OP_plus_uconst) {
2941d1de746SOCHyams     Offset = Elements[1];
29525d0f3c4SOCHyams     ExpectedDerefIdx = 2;
2961d1de746SOCHyams   } else if (NumElements > 3 && Elements[0] == dwarf::DW_OP_constu) {
29725d0f3c4SOCHyams     ExpectedDerefIdx = 3;
2981d1de746SOCHyams     if (Elements[2] == dwarf::DW_OP_plus)
2991d1de746SOCHyams       Offset = Elements[1];
3001d1de746SOCHyams     else if (Elements[2] == dwarf::DW_OP_minus)
3011d1de746SOCHyams       Offset = -Elements[1];
3021d1de746SOCHyams     else
3039c444f70SKazu Hirata       return std::nullopt;
3041d1de746SOCHyams   }
3051d1de746SOCHyams 
3061d1de746SOCHyams   // If that's all there is it means there's no deref.
30725d0f3c4SOCHyams   if (ExpectedDerefIdx >= NumElements)
3089c444f70SKazu Hirata     return std::nullopt;
3091d1de746SOCHyams 
3101d1de746SOCHyams   // Check the next element is DW_OP_deref - otherwise this is too complex or
3111d1de746SOCHyams   // isn't a deref expression.
31225d0f3c4SOCHyams   if (Elements[ExpectedDerefIdx] != dwarf::DW_OP_deref)
3139c444f70SKazu Hirata     return std::nullopt;
3141d1de746SOCHyams 
3151d1de746SOCHyams   // Check the final operation is either the DW_OP_deref or is a fragment.
31625d0f3c4SOCHyams   if (NumElements == ExpectedDerefIdx + 1)
3171d1de746SOCHyams     return Offset; // Ends with deref.
31825d0f3c4SOCHyams   unsigned ExpectedFragFirstIdx = ExpectedDerefIdx + 1;
31925d0f3c4SOCHyams   unsigned ExpectedFragFinalIdx = ExpectedFragFirstIdx + 2;
32025d0f3c4SOCHyams   if (NumElements == ExpectedFragFinalIdx + 1 &&
32125d0f3c4SOCHyams       Elements[ExpectedFragFirstIdx] == dwarf::DW_OP_LLVM_fragment)
3221d1de746SOCHyams     return Offset; // Ends with deref + fragment.
3231d1de746SOCHyams 
3241d1de746SOCHyams   // Don't bother trying to interpret anything more complex.
3259c444f70SKazu Hirata   return std::nullopt;
3261d1de746SOCHyams }
3271d1de746SOCHyams 
3281d1de746SOCHyams /// A whole (unfragmented) source variable.
3291d1de746SOCHyams using DebugAggregate = std::pair<const DILocalVariable *, const DILocation *>;
3301d1de746SOCHyams static DebugAggregate getAggregate(const DbgVariableIntrinsic *DII) {
3311d1de746SOCHyams   return DebugAggregate(DII->getVariable(), DII->getDebugLoc().getInlinedAt());
3321d1de746SOCHyams }
3331d1de746SOCHyams static DebugAggregate getAggregate(const DebugVariable &Var) {
3341d1de746SOCHyams   return DebugAggregate(Var.getVariable(), Var.getInlinedAt());
3351d1de746SOCHyams }
3361d1de746SOCHyams 
337d4879d76SOCHyams static bool shouldCoalesceFragments(Function &F) {
338d4879d76SOCHyams   // Enabling fragment coalescing reduces compiler run time when instruction
339d4879d76SOCHyams   // referencing is enabled. However, it may cause LiveDebugVariables to create
340d4879d76SOCHyams   // incorrect locations. Since instruction-referencing mode effectively
341d4879d76SOCHyams   // bypasses LiveDebugVariables we only enable coalescing if the cl::opt flag
342d4879d76SOCHyams   // has not been explicitly set and instruction-referencing is turned on.
343d4879d76SOCHyams   switch (CoalesceAdjacentFragmentsOpt) {
344d4879d76SOCHyams   case cl::boolOrDefault::BOU_UNSET:
345d4879d76SOCHyams     return debuginfoShouldUseDebugInstrRef(
346d4879d76SOCHyams         Triple(F.getParent()->getTargetTriple()));
347d4879d76SOCHyams   case cl::boolOrDefault::BOU_TRUE:
348d4879d76SOCHyams     return true;
349d4879d76SOCHyams   case cl::boolOrDefault::BOU_FALSE:
350d4879d76SOCHyams     return false;
351d4879d76SOCHyams   }
352d4879d76SOCHyams   llvm_unreachable("Unknown boolOrDefault value");
353d4879d76SOCHyams }
354d4879d76SOCHyams 
355b6942a28SBenjamin Kramer namespace {
3561d1de746SOCHyams /// In dwarf emission, the following sequence
3571d1de746SOCHyams ///    1. dbg.value ... Fragment(0, 64)
3581d1de746SOCHyams ///    2. dbg.value ... Fragment(0, 32)
3591d1de746SOCHyams /// effectively sets Fragment(32, 32) to undef (each def sets all bits not in
3601d1de746SOCHyams /// the intersection of the fragments to having "no location"). This makes
3611d1de746SOCHyams /// sense for implicit location values because splitting the computed values
3621d1de746SOCHyams /// could be troublesome, and is probably quite uncommon.  When we convert
3631d1de746SOCHyams /// dbg.assigns to dbg.value+deref this kind of thing is common, and describing
3641d1de746SOCHyams /// a location (memory) rather than a value means we don't need to worry about
3651d1de746SOCHyams /// splitting any values, so we try to recover the rest of the fragment
3661d1de746SOCHyams /// location here.
3671d1de746SOCHyams /// This class performs a(nother) dataflow analysis over the function, adding
3681d1de746SOCHyams /// variable locations so that any bits of a variable with a memory location
3691d1de746SOCHyams /// have that location explicitly reinstated at each subsequent variable
3701d1de746SOCHyams /// location definition that that doesn't overwrite those bits. i.e. after a
3711d1de746SOCHyams /// variable location def, insert new defs for the memory location with
3721d1de746SOCHyams /// fragments for the difference of "all bits currently in memory" and "the
3731d1de746SOCHyams /// fragment of the second def".
3741d1de746SOCHyams class MemLocFragmentFill {
3751d1de746SOCHyams   Function &Fn;
3761d1de746SOCHyams   FunctionVarLocsBuilder *FnVarLocs;
3771d1de746SOCHyams   const DenseSet<DebugAggregate> *VarsWithStackSlot;
378d4879d76SOCHyams   bool CoalesceAdjacentFragments;
3791d1de746SOCHyams 
3801d1de746SOCHyams   // 0 = no memory location.
3811d1de746SOCHyams   using BaseAddress = unsigned;
3821d1de746SOCHyams   using OffsetInBitsTy = unsigned;
3831d1de746SOCHyams   using FragTraits = IntervalMapHalfOpenInfo<OffsetInBitsTy>;
3841d1de746SOCHyams   using FragsInMemMap = IntervalMap<
3851d1de746SOCHyams       OffsetInBitsTy, BaseAddress,
3861d1de746SOCHyams       IntervalMapImpl::NodeSizer<OffsetInBitsTy, BaseAddress>::LeafSize,
3871d1de746SOCHyams       FragTraits>;
3881d1de746SOCHyams   FragsInMemMap::Allocator IntervalMapAlloc;
3891d1de746SOCHyams   using VarFragMap = DenseMap<unsigned, FragsInMemMap>;
3901d1de746SOCHyams 
3911d1de746SOCHyams   /// IDs for memory location base addresses in maps. Use 0 to indicate that
3921d1de746SOCHyams   /// there's no memory location.
3937d894374SOCHyams   UniqueVector<RawLocationWrapper> Bases;
3941d1de746SOCHyams   UniqueVector<DebugAggregate> Aggregates;
3951d1de746SOCHyams   DenseMap<const BasicBlock *, VarFragMap> LiveIn;
3961d1de746SOCHyams   DenseMap<const BasicBlock *, VarFragMap> LiveOut;
3971d1de746SOCHyams 
3981d1de746SOCHyams   struct FragMemLoc {
3991d1de746SOCHyams     unsigned Var;
4001d1de746SOCHyams     unsigned Base;
4011d1de746SOCHyams     unsigned OffsetInBits;
4021d1de746SOCHyams     unsigned SizeInBits;
4031d1de746SOCHyams     DebugLoc DL;
4041d1de746SOCHyams   };
4056aeb7a71SStephen Tozer   using InsertMap = MapVector<VarLocInsertPt, SmallVector<FragMemLoc>>;
4061d1de746SOCHyams 
4071d1de746SOCHyams   /// BBInsertBeforeMap holds a description for the set of location defs to be
4081d1de746SOCHyams   /// inserted after the analysis is complete. It is updated during the dataflow
4091d1de746SOCHyams   /// and the entry for a block is CLEARED each time it is (re-)visited. After
4101d1de746SOCHyams   /// the dataflow is complete, each block entry will contain the set of defs
4111d1de746SOCHyams   /// calculated during the final (fixed-point) iteration.
4121d1de746SOCHyams   DenseMap<const BasicBlock *, InsertMap> BBInsertBeforeMap;
4131d1de746SOCHyams 
4141d1de746SOCHyams   static bool intervalMapsAreEqual(const FragsInMemMap &A,
4151d1de746SOCHyams                                    const FragsInMemMap &B) {
4161d1de746SOCHyams     auto AIt = A.begin(), AEnd = A.end();
4171d1de746SOCHyams     auto BIt = B.begin(), BEnd = B.end();
4181d1de746SOCHyams     for (; AIt != AEnd; ++AIt, ++BIt) {
4191d1de746SOCHyams       if (BIt == BEnd)
4201d1de746SOCHyams         return false; // B has fewer elements than A.
4211d1de746SOCHyams       if (AIt.start() != BIt.start() || AIt.stop() != BIt.stop())
4221d1de746SOCHyams         return false; // Interval is different.
42351b68573SFangrui Song       if (*AIt != *BIt)
4241d1de746SOCHyams         return false; // Value at interval is different.
4251d1de746SOCHyams     }
4261d1de746SOCHyams     // AIt == AEnd. Check BIt is also now at end.
4271d1de746SOCHyams     return BIt == BEnd;
4281d1de746SOCHyams   }
4291d1de746SOCHyams 
4301d1de746SOCHyams   static bool varFragMapsAreEqual(const VarFragMap &A, const VarFragMap &B) {
4311d1de746SOCHyams     if (A.size() != B.size())
4321d1de746SOCHyams       return false;
4331d1de746SOCHyams     for (const auto &APair : A) {
4341d1de746SOCHyams       auto BIt = B.find(APair.first);
4351d1de746SOCHyams       if (BIt == B.end())
4361d1de746SOCHyams         return false;
4371d1de746SOCHyams       if (!intervalMapsAreEqual(APair.second, BIt->second))
4381d1de746SOCHyams         return false;
4391d1de746SOCHyams     }
4401d1de746SOCHyams     return true;
4411d1de746SOCHyams   }
4421d1de746SOCHyams 
4431d1de746SOCHyams   /// Return a string for the value that \p BaseID represents.
4441d1de746SOCHyams   std::string toString(unsigned BaseID) {
4451d1de746SOCHyams     if (BaseID)
4467d894374SOCHyams       return Bases[BaseID].getVariableLocationOp(0)->getName().str();
4471d1de746SOCHyams     else
4481d1de746SOCHyams       return "None";
4491d1de746SOCHyams   }
4501d1de746SOCHyams 
4511d1de746SOCHyams   /// Format string describing an FragsInMemMap (IntervalMap) interval.
4521d1de746SOCHyams   std::string toString(FragsInMemMap::const_iterator It, bool Newline = true) {
4531d1de746SOCHyams     std::string String;
4541d1de746SOCHyams     std::stringstream S(String);
4551d1de746SOCHyams     if (It.valid()) {
4561d1de746SOCHyams       S << "[" << It.start() << ", " << It.stop()
4571d1de746SOCHyams         << "): " << toString(It.value());
4581d1de746SOCHyams     } else {
4591d1de746SOCHyams       S << "invalid iterator (end)";
4601d1de746SOCHyams     }
4611d1de746SOCHyams     if (Newline)
4621d1de746SOCHyams       S << "\n";
4631d1de746SOCHyams     return S.str();
4641d1de746SOCHyams   };
4651d1de746SOCHyams 
4661d1de746SOCHyams   FragsInMemMap meetFragments(const FragsInMemMap &A, const FragsInMemMap &B) {
4671d1de746SOCHyams     FragsInMemMap Result(IntervalMapAlloc);
4681d1de746SOCHyams     for (auto AIt = A.begin(), AEnd = A.end(); AIt != AEnd; ++AIt) {
4691d1de746SOCHyams       LLVM_DEBUG(dbgs() << "a " << toString(AIt));
4701d1de746SOCHyams       // This is basically copied from process() and inverted (process is
4711d1de746SOCHyams       // performing something like a union whereas this is more of an
4721d1de746SOCHyams       // intersect).
4731d1de746SOCHyams 
4741d1de746SOCHyams       // There's no work to do if interval `a` overlaps no fragments in map `B`.
4751d1de746SOCHyams       if (!B.overlaps(AIt.start(), AIt.stop()))
4761d1de746SOCHyams         continue;
4771d1de746SOCHyams 
4781d1de746SOCHyams       // Does StartBit intersect an existing fragment?
4791d1de746SOCHyams       auto FirstOverlap = B.find(AIt.start());
4801d1de746SOCHyams       assert(FirstOverlap != B.end());
4811d1de746SOCHyams       bool IntersectStart = FirstOverlap.start() < AIt.start();
4821d1de746SOCHyams       LLVM_DEBUG(dbgs() << "- FirstOverlap " << toString(FirstOverlap, false)
4831d1de746SOCHyams                         << ", IntersectStart: " << IntersectStart << "\n");
4841d1de746SOCHyams 
4851d1de746SOCHyams       // Does EndBit intersect an existing fragment?
4861d1de746SOCHyams       auto LastOverlap = B.find(AIt.stop());
4871d1de746SOCHyams       bool IntersectEnd =
4881d1de746SOCHyams           LastOverlap != B.end() && LastOverlap.start() < AIt.stop();
4891d1de746SOCHyams       LLVM_DEBUG(dbgs() << "- LastOverlap " << toString(LastOverlap, false)
4901d1de746SOCHyams                         << ", IntersectEnd: " << IntersectEnd << "\n");
4911d1de746SOCHyams 
4921d1de746SOCHyams       // Check if both ends of `a` intersect the same interval `b`.
4931d1de746SOCHyams       if (IntersectStart && IntersectEnd && FirstOverlap == LastOverlap) {
4941d1de746SOCHyams         // Insert `a` (`a` is contained in `b`) if the values match.
4951d1de746SOCHyams         // [ a ]
4961d1de746SOCHyams         // [ - b - ]
4971d1de746SOCHyams         // -
4981d1de746SOCHyams         // [ r ]
4991d1de746SOCHyams         LLVM_DEBUG(dbgs() << "- a is contained within "
5001d1de746SOCHyams                           << toString(FirstOverlap));
50151b68573SFangrui Song         if (*AIt && *AIt == *FirstOverlap)
50251b68573SFangrui Song           Result.insert(AIt.start(), AIt.stop(), *AIt);
5031d1de746SOCHyams       } else {
5041d1de746SOCHyams         // There's an overlap but `a` is not fully contained within
5051d1de746SOCHyams         // `b`. Shorten any end-point intersections.
5061d1de746SOCHyams         //     [ - a - ]
5071d1de746SOCHyams         // [ - b - ]
5081d1de746SOCHyams         // -
5091d1de746SOCHyams         //     [ r ]
5101d1de746SOCHyams         auto Next = FirstOverlap;
5111d1de746SOCHyams         if (IntersectStart) {
5121d1de746SOCHyams           LLVM_DEBUG(dbgs() << "- insert intersection of a and "
5131d1de746SOCHyams                             << toString(FirstOverlap));
51451b68573SFangrui Song           if (*AIt && *AIt == *FirstOverlap)
51551b68573SFangrui Song             Result.insert(AIt.start(), FirstOverlap.stop(), *AIt);
5161d1de746SOCHyams           ++Next;
5171d1de746SOCHyams         }
5181d1de746SOCHyams         // [ - a - ]
5191d1de746SOCHyams         //     [ - b - ]
5201d1de746SOCHyams         // -
5211d1de746SOCHyams         //     [ r ]
5221d1de746SOCHyams         if (IntersectEnd) {
5231d1de746SOCHyams           LLVM_DEBUG(dbgs() << "- insert intersection of a and "
5241d1de746SOCHyams                             << toString(LastOverlap));
52551b68573SFangrui Song           if (*AIt && *AIt == *LastOverlap)
52651b68573SFangrui Song             Result.insert(LastOverlap.start(), AIt.stop(), *AIt);
5271d1de746SOCHyams         }
5281d1de746SOCHyams 
5291d1de746SOCHyams         // Insert all intervals in map `B` that are contained within interval
5301d1de746SOCHyams         // `a` where the values match.
5311d1de746SOCHyams         // [ -  - a -  - ]
5321d1de746SOCHyams         // [ b1 ]   [ b2 ]
5331d1de746SOCHyams         // -
5341d1de746SOCHyams         // [ r1 ]   [ r2 ]
5351d1de746SOCHyams         while (Next != B.end() && Next.start() < AIt.stop() &&
5361d1de746SOCHyams                Next.stop() <= AIt.stop()) {
5371d1de746SOCHyams           LLVM_DEBUG(dbgs()
5381d1de746SOCHyams                      << "- insert intersection of a and " << toString(Next));
53951b68573SFangrui Song           if (*AIt && *AIt == *Next)
54051b68573SFangrui Song             Result.insert(Next.start(), Next.stop(), *Next);
5411d1de746SOCHyams           ++Next;
5421d1de746SOCHyams         }
5431d1de746SOCHyams       }
5441d1de746SOCHyams     }
5451d1de746SOCHyams     return Result;
5461d1de746SOCHyams   }
5471d1de746SOCHyams 
5481d1de746SOCHyams   /// Meet \p A and \p B, storing the result in \p A.
5491d1de746SOCHyams   void meetVars(VarFragMap &A, const VarFragMap &B) {
5501d1de746SOCHyams     // Meet A and B.
5511d1de746SOCHyams     //
5521d1de746SOCHyams     // Result = meet(a, b) for a in A, b in B where Var(a) == Var(b)
5531d1de746SOCHyams     for (auto It = A.begin(), End = A.end(); It != End; ++It) {
5541d1de746SOCHyams       unsigned AVar = It->first;
5551d1de746SOCHyams       FragsInMemMap &AFrags = It->second;
5561d1de746SOCHyams       auto BIt = B.find(AVar);
5571d1de746SOCHyams       if (BIt == B.end()) {
5581d1de746SOCHyams         A.erase(It);
5591d1de746SOCHyams         continue; // Var has no bits defined in B.
5601d1de746SOCHyams       }
5611d1de746SOCHyams       LLVM_DEBUG(dbgs() << "meet fragment maps for "
5621d1de746SOCHyams                         << Aggregates[AVar].first->getName() << "\n");
5631d1de746SOCHyams       AFrags = meetFragments(AFrags, BIt->second);
5641d1de746SOCHyams     }
5651d1de746SOCHyams   }
5661d1de746SOCHyams 
5671d1de746SOCHyams   bool meet(const BasicBlock &BB,
5681d1de746SOCHyams             const SmallPtrSet<BasicBlock *, 16> &Visited) {
5691d1de746SOCHyams     LLVM_DEBUG(dbgs() << "meet block info from preds of " << BB.getName()
5701d1de746SOCHyams                       << "\n");
5711d1de746SOCHyams 
5721d1de746SOCHyams     VarFragMap BBLiveIn;
5731d1de746SOCHyams     bool FirstMeet = true;
5741d1de746SOCHyams     // LiveIn locs for BB is the meet of the already-processed preds' LiveOut
5751d1de746SOCHyams     // locs.
5763641efcfSKazu Hirata     for (const BasicBlock *Pred : predecessors(&BB)) {
5771d1de746SOCHyams       // Ignore preds that haven't been processed yet. This is essentially the
5781d1de746SOCHyams       // same as initialising all variables to implicit top value (⊤) which is
5791d1de746SOCHyams       // the identity value for the meet operation.
5801d1de746SOCHyams       if (!Visited.count(Pred))
5811d1de746SOCHyams         continue;
5821d1de746SOCHyams 
5831d1de746SOCHyams       auto PredLiveOut = LiveOut.find(Pred);
5841d1de746SOCHyams       assert(PredLiveOut != LiveOut.end());
5851d1de746SOCHyams 
5861d1de746SOCHyams       if (FirstMeet) {
5871d1de746SOCHyams         LLVM_DEBUG(dbgs() << "BBLiveIn = " << Pred->getName() << "\n");
5881d1de746SOCHyams         BBLiveIn = PredLiveOut->second;
5891d1de746SOCHyams         FirstMeet = false;
5901d1de746SOCHyams       } else {
5911d1de746SOCHyams         LLVM_DEBUG(dbgs() << "BBLiveIn = meet BBLiveIn, " << Pred->getName()
5921d1de746SOCHyams                           << "\n");
5931d1de746SOCHyams         meetVars(BBLiveIn, PredLiveOut->second);
5941d1de746SOCHyams       }
5951d1de746SOCHyams 
5961d1de746SOCHyams       // An empty set is ⊥ for the intersect-like meet operation. If we've
5971d1de746SOCHyams       // already got ⊥ there's no need to run the code - we know the result is
5981d1de746SOCHyams       // ⊥ since `meet(a, ⊥) = ⊥`.
5991d1de746SOCHyams       if (BBLiveIn.size() == 0)
6001d1de746SOCHyams         break;
6011d1de746SOCHyams     }
6021d1de746SOCHyams 
6031d1de746SOCHyams     auto CurrentLiveInEntry = LiveIn.find(&BB);
6041d1de746SOCHyams     // If there's no LiveIn entry for the block yet, add it.
6051d1de746SOCHyams     if (CurrentLiveInEntry == LiveIn.end()) {
6061d1de746SOCHyams       LLVM_DEBUG(dbgs() << "change=true (first) on meet on " << BB.getName()
6071d1de746SOCHyams                         << "\n");
6081d1de746SOCHyams       LiveIn[&BB] = std::move(BBLiveIn);
6091d1de746SOCHyams       return /*Changed=*/true;
6101d1de746SOCHyams     }
6111d1de746SOCHyams 
6121d1de746SOCHyams     // If the LiveIn set has changed (expensive check) update it and return
6131d1de746SOCHyams     // true.
6141d1de746SOCHyams     if (!varFragMapsAreEqual(BBLiveIn, CurrentLiveInEntry->second)) {
6151d1de746SOCHyams       LLVM_DEBUG(dbgs() << "change=true on meet on " << BB.getName() << "\n");
6161d1de746SOCHyams       CurrentLiveInEntry->second = std::move(BBLiveIn);
6171d1de746SOCHyams       return /*Changed=*/true;
6181d1de746SOCHyams     }
6191d1de746SOCHyams 
6201d1de746SOCHyams     LLVM_DEBUG(dbgs() << "change=false on meet on " << BB.getName() << "\n");
6211d1de746SOCHyams     return /*Changed=*/false;
6221d1de746SOCHyams   }
6231d1de746SOCHyams 
6246aeb7a71SStephen Tozer   void insertMemLoc(BasicBlock &BB, VarLocInsertPt Before, unsigned Var,
6251d1de746SOCHyams                     unsigned StartBit, unsigned EndBit, unsigned Base,
6261d1de746SOCHyams                     DebugLoc DL) {
6271d1de746SOCHyams     assert(StartBit < EndBit && "Cannot create fragment of size <= 0");
6281d1de746SOCHyams     if (!Base)
6291d1de746SOCHyams       return;
6301d1de746SOCHyams     FragMemLoc Loc;
6311d1de746SOCHyams     Loc.Var = Var;
6321d1de746SOCHyams     Loc.OffsetInBits = StartBit;
6331d1de746SOCHyams     Loc.SizeInBits = EndBit - StartBit;
6341d1de746SOCHyams     assert(Base && "Expected a non-zero ID for Base address");
6351d1de746SOCHyams     Loc.Base = Base;
6361d1de746SOCHyams     Loc.DL = DL;
6376aeb7a71SStephen Tozer     BBInsertBeforeMap[&BB][Before].push_back(Loc);
6381d1de746SOCHyams     LLVM_DEBUG(dbgs() << "Add mem def for " << Aggregates[Var].first->getName()
6391d1de746SOCHyams                       << " bits [" << StartBit << ", " << EndBit << ")\n");
6401d1de746SOCHyams   }
6411d1de746SOCHyams 
642d4879d76SOCHyams   /// Inserts a new dbg def if the interval found when looking up \p StartBit
643d4879d76SOCHyams   /// in \p FragMap starts before \p StartBit or ends after \p EndBit (which
644d4879d76SOCHyams   /// indicates - assuming StartBit->EndBit has just been inserted - that the
645d4879d76SOCHyams   /// slice has been coalesced in the map).
6466aeb7a71SStephen Tozer   void coalesceFragments(BasicBlock &BB, VarLocInsertPt Before, unsigned Var,
647d4879d76SOCHyams                          unsigned StartBit, unsigned EndBit, unsigned Base,
648d4879d76SOCHyams                          DebugLoc DL, const FragsInMemMap &FragMap) {
649d4879d76SOCHyams     if (!CoalesceAdjacentFragments)
650d4879d76SOCHyams       return;
651d4879d76SOCHyams     // We've inserted the location into the map. The map will have coalesced
652d4879d76SOCHyams     // adjacent intervals (variable fragments) that describe the same memory
653d4879d76SOCHyams     // location. Use this knowledge to insert a debug location that describes
654d4879d76SOCHyams     // that coalesced fragment. This may eclipse other locs we've just
655d4879d76SOCHyams     // inserted. This is okay as redundant locs will be cleaned up later.
656d4879d76SOCHyams     auto CoalescedFrag = FragMap.find(StartBit);
657d4879d76SOCHyams     // Bail if no coalescing has taken place.
658d4879d76SOCHyams     if (CoalescedFrag.start() == StartBit && CoalescedFrag.stop() == EndBit)
659d4879d76SOCHyams       return;
660d4879d76SOCHyams 
661d4879d76SOCHyams     LLVM_DEBUG(dbgs() << "- Insert loc for bits " << CoalescedFrag.start()
662d4879d76SOCHyams                       << " to " << CoalescedFrag.stop() << "\n");
663d4879d76SOCHyams     insertMemLoc(BB, Before, Var, CoalescedFrag.start(), CoalescedFrag.stop(),
664d4879d76SOCHyams                  Base, DL);
665d4879d76SOCHyams   }
666d4879d76SOCHyams 
6676aeb7a71SStephen Tozer   void addDef(const VarLocInfo &VarLoc, VarLocInsertPt Before, BasicBlock &BB,
6681d1de746SOCHyams               VarFragMap &LiveSet) {
6691d1de746SOCHyams     DebugVariable DbgVar = FnVarLocs->getVariable(VarLoc.VariableID);
6701d1de746SOCHyams     if (skipVariable(DbgVar.getVariable()))
6711d1de746SOCHyams       return;
6721d1de746SOCHyams     // Don't bother doing anything for this variables if we know it's fully
6731d1de746SOCHyams     // promoted. We're only interested in variables that (sometimes) live on
6741d1de746SOCHyams     // the stack here.
6751d1de746SOCHyams     if (!VarsWithStackSlot->count(getAggregate(DbgVar)))
6761d1de746SOCHyams       return;
6771d1de746SOCHyams     unsigned Var = Aggregates.insert(
6781d1de746SOCHyams         DebugAggregate(DbgVar.getVariable(), VarLoc.DL.getInlinedAt()));
6791d1de746SOCHyams 
6801d1de746SOCHyams     // [StartBit: EndBit) are the bits affected by this def.
6811d1de746SOCHyams     const DIExpression *DIExpr = VarLoc.Expr;
6821d1de746SOCHyams     unsigned StartBit;
6831d1de746SOCHyams     unsigned EndBit;
6841d1de746SOCHyams     if (auto Frag = DIExpr->getFragmentInfo()) {
6851d1de746SOCHyams       StartBit = Frag->OffsetInBits;
6861d1de746SOCHyams       EndBit = StartBit + Frag->SizeInBits;
6871d1de746SOCHyams     } else {
6881d1de746SOCHyams       assert(static_cast<bool>(DbgVar.getVariable()->getSizeInBits()));
6891d1de746SOCHyams       StartBit = 0;
6901d1de746SOCHyams       EndBit = *DbgVar.getVariable()->getSizeInBits();
6911d1de746SOCHyams     }
6921d1de746SOCHyams 
6931d1de746SOCHyams     // We will only fill fragments for simple memory-describing dbg.value
6941d1de746SOCHyams     // intrinsics. If the fragment offset is the same as the offset from the
6951d1de746SOCHyams     // base pointer, do The Thing, otherwise fall back to normal dbg.value
6961d1de746SOCHyams     // behaviour. AssignmentTrackingLowering has generated DIExpressions
6971d1de746SOCHyams     // written in terms of the base pointer.
6981d1de746SOCHyams     // TODO: Remove this condition since the fragment offset doesn't always
6991d1de746SOCHyams     // equal the offset from base pointer (e.g. for a SROA-split variable).
7001d1de746SOCHyams     const auto DerefOffsetInBytes = getDerefOffsetInBytes(DIExpr);
7011d1de746SOCHyams     const unsigned Base =
7021d1de746SOCHyams         DerefOffsetInBytes && *DerefOffsetInBytes * 8 == StartBit
7037d894374SOCHyams             ? Bases.insert(VarLoc.Values)
7041d1de746SOCHyams             : 0;
7051d1de746SOCHyams     LLVM_DEBUG(dbgs() << "DEF " << DbgVar.getVariable()->getName() << " ["
7061d1de746SOCHyams                       << StartBit << ", " << EndBit << "): " << toString(Base)
7071d1de746SOCHyams                       << "\n");
7081d1de746SOCHyams 
7091d1de746SOCHyams     // First of all, any locs that use mem that are disrupted need reinstating.
7101d1de746SOCHyams     // Unfortunately, IntervalMap doesn't let us insert intervals that overlap
7111d1de746SOCHyams     // with existing intervals so this code involves a lot of fiddling around
7121d1de746SOCHyams     // with intervals to do that manually.
7131d1de746SOCHyams     auto FragIt = LiveSet.find(Var);
7141d1de746SOCHyams 
7151d1de746SOCHyams     // Check if the variable does not exist in the map.
7161d1de746SOCHyams     if (FragIt == LiveSet.end()) {
7171d1de746SOCHyams       // Add this variable to the BB map.
7181d1de746SOCHyams       auto P = LiveSet.try_emplace(Var, FragsInMemMap(IntervalMapAlloc));
7191d1de746SOCHyams       assert(P.second && "Var already in map?");
7201d1de746SOCHyams       // Add the interval to the fragment map.
7211d1de746SOCHyams       P.first->second.insert(StartBit, EndBit, Base);
7221d1de746SOCHyams       return;
7231d1de746SOCHyams     }
7241d1de746SOCHyams     // The variable has an entry in the map.
7251d1de746SOCHyams 
7261d1de746SOCHyams     FragsInMemMap &FragMap = FragIt->second;
7271d1de746SOCHyams     // First check the easy case: the new fragment `f` doesn't overlap with any
7281d1de746SOCHyams     // intervals.
7291d1de746SOCHyams     if (!FragMap.overlaps(StartBit, EndBit)) {
7301d1de746SOCHyams       LLVM_DEBUG(dbgs() << "- No overlaps\n");
7311d1de746SOCHyams       FragMap.insert(StartBit, EndBit, Base);
732d4879d76SOCHyams       coalesceFragments(BB, Before, Var, StartBit, EndBit, Base, VarLoc.DL,
733d4879d76SOCHyams                         FragMap);
7341d1de746SOCHyams       return;
7351d1de746SOCHyams     }
7361d1de746SOCHyams     // There is at least one overlap.
7371d1de746SOCHyams 
7381d1de746SOCHyams     // Does StartBit intersect an existing fragment?
7391d1de746SOCHyams     auto FirstOverlap = FragMap.find(StartBit);
7401d1de746SOCHyams     assert(FirstOverlap != FragMap.end());
7411d1de746SOCHyams     bool IntersectStart = FirstOverlap.start() < StartBit;
7421d1de746SOCHyams 
7431d1de746SOCHyams     // Does EndBit intersect an existing fragment?
7441d1de746SOCHyams     auto LastOverlap = FragMap.find(EndBit);
7451d1de746SOCHyams     bool IntersectEnd = LastOverlap.valid() && LastOverlap.start() < EndBit;
7461d1de746SOCHyams 
7471d1de746SOCHyams     // Check if both ends of `f` intersect the same interval `i`.
7481d1de746SOCHyams     if (IntersectStart && IntersectEnd && FirstOverlap == LastOverlap) {
7491d1de746SOCHyams       LLVM_DEBUG(dbgs() << "- Intersect single interval @ both ends\n");
7501d1de746SOCHyams       // Shorten `i` so that there's space to insert `f`.
7511d1de746SOCHyams       //      [ f ]
7521d1de746SOCHyams       // [  -   i   -  ]
7531d1de746SOCHyams       // +
7541d1de746SOCHyams       // [ i ][ f ][ i ]
755e3a00d51SOCHyams 
756e3a00d51SOCHyams       // Save values for use after inserting a new interval.
7571d1de746SOCHyams       auto EndBitOfOverlap = FirstOverlap.stop();
758e3a00d51SOCHyams       unsigned OverlapValue = FirstOverlap.value();
759e3a00d51SOCHyams 
760e3a00d51SOCHyams       // Shorten the overlapping interval.
7611d1de746SOCHyams       FirstOverlap.setStop(StartBit);
7621d1de746SOCHyams       insertMemLoc(BB, Before, Var, FirstOverlap.start(), StartBit,
763e3a00d51SOCHyams                    OverlapValue, VarLoc.DL);
7641d1de746SOCHyams 
7651d1de746SOCHyams       // Insert a new interval to represent the end part.
766e3a00d51SOCHyams       FragMap.insert(EndBit, EndBitOfOverlap, OverlapValue);
767e3a00d51SOCHyams       insertMemLoc(BB, Before, Var, EndBit, EndBitOfOverlap, OverlapValue,
76851b68573SFangrui Song                    VarLoc.DL);
7691d1de746SOCHyams 
7701d1de746SOCHyams       // Insert the new (middle) fragment now there is space.
7711d1de746SOCHyams       FragMap.insert(StartBit, EndBit, Base);
7721d1de746SOCHyams     } else {
7731d1de746SOCHyams       // There's an overlap but `f` may not be fully contained within
7741d1de746SOCHyams       // `i`. Shorten any end-point intersections so that we can then
7751d1de746SOCHyams       // insert `f`.
7761d1de746SOCHyams       //      [ - f - ]
7771d1de746SOCHyams       // [ - i - ]
7781d1de746SOCHyams       // |   |
7791d1de746SOCHyams       // [ i ]
7801d1de746SOCHyams       // Shorten any end-point intersections.
7811d1de746SOCHyams       if (IntersectStart) {
7821d1de746SOCHyams         LLVM_DEBUG(dbgs() << "- Intersect interval at start\n");
7831d1de746SOCHyams         // Split off at the intersection.
7841d1de746SOCHyams         FirstOverlap.setStop(StartBit);
7851d1de746SOCHyams         insertMemLoc(BB, Before, Var, FirstOverlap.start(), StartBit,
78651b68573SFangrui Song                      *FirstOverlap, VarLoc.DL);
7871d1de746SOCHyams       }
7881d1de746SOCHyams       // [ - f - ]
7891d1de746SOCHyams       //      [ - i - ]
7901d1de746SOCHyams       //          |   |
7911d1de746SOCHyams       //          [ i ]
7921d1de746SOCHyams       if (IntersectEnd) {
7931d1de746SOCHyams         LLVM_DEBUG(dbgs() << "- Intersect interval at end\n");
7941d1de746SOCHyams         // Split off at the intersection.
7951d1de746SOCHyams         LastOverlap.setStart(EndBit);
79651b68573SFangrui Song         insertMemLoc(BB, Before, Var, EndBit, LastOverlap.stop(), *LastOverlap,
79751b68573SFangrui Song                      VarLoc.DL);
7981d1de746SOCHyams       }
7991d1de746SOCHyams 
8001d1de746SOCHyams       LLVM_DEBUG(dbgs() << "- Erase intervals contained within\n");
8011d1de746SOCHyams       // FirstOverlap and LastOverlap have been shortened such that they're
8021d1de746SOCHyams       // no longer overlapping with [StartBit, EndBit). Delete any overlaps
8031d1de746SOCHyams       // that remain (these will be fully contained within `f`).
8041d1de746SOCHyams       // [ - f - ]       }
8051d1de746SOCHyams       //      [ - i - ]  } Intersection shortening that has happened above.
8061d1de746SOCHyams       //          |   |  }
8071d1de746SOCHyams       //          [ i ]  }
8081d1de746SOCHyams       // -----------------
8091d1de746SOCHyams       // [i2 ]           } Intervals fully contained within `f` get erased.
8101d1de746SOCHyams       // -----------------
8111d1de746SOCHyams       // [ - f - ][ i ]  } Completed insertion.
8121d1de746SOCHyams       auto It = FirstOverlap;
8131d1de746SOCHyams       if (IntersectStart)
8141d1de746SOCHyams         ++It; // IntersectStart: first overlap has been shortened.
8151d1de746SOCHyams       while (It.valid() && It.start() >= StartBit && It.stop() <= EndBit) {
8161d1de746SOCHyams         LLVM_DEBUG(dbgs() << "- Erase " << toString(It));
8171d1de746SOCHyams         It.erase(); // This increments It after removing the interval.
8181d1de746SOCHyams       }
8191d1de746SOCHyams       // We've dealt with all the overlaps now!
8201d1de746SOCHyams       assert(!FragMap.overlaps(StartBit, EndBit));
8211d1de746SOCHyams       LLVM_DEBUG(dbgs() << "- Insert DEF into now-empty space\n");
8221d1de746SOCHyams       FragMap.insert(StartBit, EndBit, Base);
8231d1de746SOCHyams     }
824d4879d76SOCHyams 
825d4879d76SOCHyams     coalesceFragments(BB, Before, Var, StartBit, EndBit, Base, VarLoc.DL,
826d4879d76SOCHyams                       FragMap);
8271d1de746SOCHyams   }
8281d1de746SOCHyams 
8291d1de746SOCHyams   bool skipVariable(const DILocalVariable *V) { return !V->getSizeInBits(); }
8301d1de746SOCHyams 
8311d1de746SOCHyams   void process(BasicBlock &BB, VarFragMap &LiveSet) {
8321d1de746SOCHyams     BBInsertBeforeMap[&BB].clear();
8331d1de746SOCHyams     for (auto &I : BB) {
834ffd08c77SStephen Tozer       for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange())) {
835ffd08c77SStephen Tozer         if (const auto *Locs = FnVarLocs->getWedge(&DVR)) {
83630845e8aSStephen Tozer           for (const VarLocInfo &Loc : *Locs) {
837ffd08c77SStephen Tozer             addDef(Loc, &DVR, *I.getParent(), LiveSet);
83830845e8aSStephen Tozer           }
83930845e8aSStephen Tozer         }
84030845e8aSStephen Tozer       }
8411d1de746SOCHyams       if (const auto *Locs = FnVarLocs->getWedge(&I)) {
8421d1de746SOCHyams         for (const VarLocInfo &Loc : *Locs) {
8436aeb7a71SStephen Tozer           addDef(Loc, &I, *I.getParent(), LiveSet);
8441d1de746SOCHyams         }
8451d1de746SOCHyams       }
8461d1de746SOCHyams     }
8471d1de746SOCHyams   }
8481d1de746SOCHyams 
8491d1de746SOCHyams public:
8501d1de746SOCHyams   MemLocFragmentFill(Function &Fn,
851d4879d76SOCHyams                      const DenseSet<DebugAggregate> *VarsWithStackSlot,
852d4879d76SOCHyams                      bool CoalesceAdjacentFragments)
853d4879d76SOCHyams       : Fn(Fn), VarsWithStackSlot(VarsWithStackSlot),
854d4879d76SOCHyams         CoalesceAdjacentFragments(CoalesceAdjacentFragments) {}
8551d1de746SOCHyams 
8561d1de746SOCHyams   /// Add variable locations to \p FnVarLocs so that any bits of a variable
8571d1de746SOCHyams   /// with a memory location have that location explicitly reinstated at each
8581d1de746SOCHyams   /// subsequent variable location definition that that doesn't overwrite those
8591d1de746SOCHyams   /// bits. i.e. after a variable location def, insert new defs for the memory
8601d1de746SOCHyams   /// location with fragments for the difference of "all bits currently in
8611d1de746SOCHyams   /// memory" and "the fragment of the second def". e.g.
8621d1de746SOCHyams   ///
8631d1de746SOCHyams   ///     Before:
8641d1de746SOCHyams   ///
8651d1de746SOCHyams   ///     var x bits 0 to 63:  value in memory
8661d1de746SOCHyams   ///     more instructions
8671d1de746SOCHyams   ///     var x bits 0 to 31:  value is %0
8681d1de746SOCHyams   ///
8691d1de746SOCHyams   ///     After:
8701d1de746SOCHyams   ///
8711d1de746SOCHyams   ///     var x bits 0 to 63:  value in memory
8721d1de746SOCHyams   ///     more instructions
8731d1de746SOCHyams   ///     var x bits 0 to 31:  value is %0
8741d1de746SOCHyams   ///     var x bits 32 to 61: value in memory ; <-- new loc def
8751d1de746SOCHyams   ///
8761d1de746SOCHyams   void run(FunctionVarLocsBuilder *FnVarLocs) {
8771d1de746SOCHyams     if (!EnableMemLocFragFill)
8781d1de746SOCHyams       return;
8791d1de746SOCHyams 
8801d1de746SOCHyams     this->FnVarLocs = FnVarLocs;
8811d1de746SOCHyams 
8821d1de746SOCHyams     // Prepare for traversal.
8831d1de746SOCHyams     //
8841d1de746SOCHyams     ReversePostOrderTraversal<Function *> RPOT(&Fn);
8851d1de746SOCHyams     std::priority_queue<unsigned int, std::vector<unsigned int>,
8861d1de746SOCHyams                         std::greater<unsigned int>>
8871d1de746SOCHyams         Worklist;
8881d1de746SOCHyams     std::priority_queue<unsigned int, std::vector<unsigned int>,
8891d1de746SOCHyams                         std::greater<unsigned int>>
8901d1de746SOCHyams         Pending;
8911d1de746SOCHyams     DenseMap<unsigned int, BasicBlock *> OrderToBB;
8921d1de746SOCHyams     DenseMap<BasicBlock *, unsigned int> BBToOrder;
8931d1de746SOCHyams     { // Init OrderToBB and BBToOrder.
8941d1de746SOCHyams       unsigned int RPONumber = 0;
895dae061f1SKazu Hirata       for (BasicBlock *BB : RPOT) {
896dae061f1SKazu Hirata         OrderToBB[RPONumber] = BB;
897dae061f1SKazu Hirata         BBToOrder[BB] = RPONumber;
8981d1de746SOCHyams         Worklist.push(RPONumber);
8991d1de746SOCHyams         ++RPONumber;
9001d1de746SOCHyams       }
9011d1de746SOCHyams       LiveIn.init(RPONumber);
9021d1de746SOCHyams       LiveOut.init(RPONumber);
9031d1de746SOCHyams     }
9041d1de746SOCHyams 
9051d1de746SOCHyams     // Perform the traversal.
9061d1de746SOCHyams     //
9071d1de746SOCHyams     // This is a standard "intersect of predecessor outs" dataflow problem. To
9081d1de746SOCHyams     // solve it, we perform meet() and process() using the two worklist method
9091d1de746SOCHyams     // until the LiveIn data for each block becomes unchanging.
9101d1de746SOCHyams     //
9111d1de746SOCHyams     // This dataflow is essentially working on maps of sets and at each meet we
9121d1de746SOCHyams     // intersect the maps and the mapped sets. So, initialized live-in maps
9131d1de746SOCHyams     // monotonically decrease in value throughout the dataflow.
9141d1de746SOCHyams     SmallPtrSet<BasicBlock *, 16> Visited;
9151d1de746SOCHyams     while (!Worklist.empty() || !Pending.empty()) {
9161d1de746SOCHyams       // We track what is on the pending worklist to avoid inserting the same
9171d1de746SOCHyams       // thing twice.  We could avoid this with a custom priority queue, but
9181d1de746SOCHyams       // this is probably not worth it.
9191d1de746SOCHyams       SmallPtrSet<BasicBlock *, 16> OnPending;
9201d1de746SOCHyams       LLVM_DEBUG(dbgs() << "Processing Worklist\n");
9211d1de746SOCHyams       while (!Worklist.empty()) {
9221d1de746SOCHyams         BasicBlock *BB = OrderToBB[Worklist.top()];
9231d1de746SOCHyams         LLVM_DEBUG(dbgs() << "\nPop BB " << BB->getName() << "\n");
9241d1de746SOCHyams         Worklist.pop();
9251d1de746SOCHyams         bool InChanged = meet(*BB, Visited);
9261d1de746SOCHyams         // Always consider LiveIn changed on the first visit.
9271d1de746SOCHyams         InChanged |= Visited.insert(BB).second;
9281d1de746SOCHyams         if (InChanged) {
9291d1de746SOCHyams           LLVM_DEBUG(dbgs()
9301d1de746SOCHyams                      << BB->getName() << " has new InLocs, process it\n");
9311d1de746SOCHyams           //  Mutate a copy of LiveIn while processing BB. Once we've processed
9321d1de746SOCHyams           //  the terminator LiveSet is the LiveOut set for BB.
9331d1de746SOCHyams           //  This is an expensive copy!
9341d1de746SOCHyams           VarFragMap LiveSet = LiveIn[BB];
9351d1de746SOCHyams 
9361d1de746SOCHyams           // Process the instructions in the block.
9371d1de746SOCHyams           process(*BB, LiveSet);
9381d1de746SOCHyams 
9391d1de746SOCHyams           // Relatively expensive check: has anything changed in LiveOut for BB?
9401d1de746SOCHyams           if (!varFragMapsAreEqual(LiveOut[BB], LiveSet)) {
9411d1de746SOCHyams             LLVM_DEBUG(dbgs() << BB->getName()
9421d1de746SOCHyams                               << " has new OutLocs, add succs to worklist: [ ");
9431d1de746SOCHyams             LiveOut[BB] = std::move(LiveSet);
9443641efcfSKazu Hirata             for (BasicBlock *Succ : successors(BB)) {
9453641efcfSKazu Hirata               if (OnPending.insert(Succ).second) {
9463641efcfSKazu Hirata                 LLVM_DEBUG(dbgs() << Succ->getName() << " ");
9473641efcfSKazu Hirata                 Pending.push(BBToOrder[Succ]);
9481d1de746SOCHyams               }
9491d1de746SOCHyams             }
9501d1de746SOCHyams             LLVM_DEBUG(dbgs() << "]\n");
9511d1de746SOCHyams           }
9521d1de746SOCHyams         }
9531d1de746SOCHyams       }
9541d1de746SOCHyams       Worklist.swap(Pending);
9551d1de746SOCHyams       // At this point, pending must be empty, since it was just the empty
9561d1de746SOCHyams       // worklist
9571d1de746SOCHyams       assert(Pending.empty() && "Pending should be empty");
9581d1de746SOCHyams     }
9591d1de746SOCHyams 
9601d1de746SOCHyams     // Insert new location defs.
9610c36ab19SAkshay Khadse     for (auto &Pair : BBInsertBeforeMap) {
9621d1de746SOCHyams       InsertMap &Map = Pair.second;
9630c36ab19SAkshay Khadse       for (auto &Pair : Map) {
9646aeb7a71SStephen Tozer         auto InsertBefore = Pair.first;
9651d1de746SOCHyams         assert(InsertBefore && "should never be null");
9661d1de746SOCHyams         auto FragMemLocs = Pair.second;
9671d1de746SOCHyams         auto &Ctx = Fn.getContext();
9681d1de746SOCHyams 
9690c36ab19SAkshay Khadse         for (auto &FragMemLoc : FragMemLocs) {
970e03f4271SJay Foad           DIExpression *Expr = DIExpression::get(Ctx, {});
971d4879d76SOCHyams           if (FragMemLoc.SizeInBits !=
972d4879d76SOCHyams               *Aggregates[FragMemLoc.Var].first->getSizeInBits())
9731d1de746SOCHyams             Expr = *DIExpression::createFragmentExpression(
9741d1de746SOCHyams                 Expr, FragMemLoc.OffsetInBits, FragMemLoc.SizeInBits);
9751d1de746SOCHyams           Expr = DIExpression::prepend(Expr, DIExpression::DerefAfter,
9761d1de746SOCHyams                                        FragMemLoc.OffsetInBits / 8);
9771d1de746SOCHyams           DebugVariable Var(Aggregates[FragMemLoc.Var].first, Expr,
9781d1de746SOCHyams                             FragMemLoc.DL.getInlinedAt());
9791d1de746SOCHyams           FnVarLocs->addVarLoc(InsertBefore, Var, Expr, FragMemLoc.DL,
9801d1de746SOCHyams                                Bases[FragMemLoc.Base]);
9811d1de746SOCHyams         }
9821d1de746SOCHyams       }
9831d1de746SOCHyams     }
9841d1de746SOCHyams   }
9851d1de746SOCHyams };
9861d1de746SOCHyams 
9871d1de746SOCHyams /// AssignmentTrackingLowering encapsulates a dataflow analysis over a function
9881d1de746SOCHyams /// that interprets assignment tracking debug info metadata and stores in IR to
9891d1de746SOCHyams /// create a map of variable locations.
9901d1de746SOCHyams class AssignmentTrackingLowering {
9911d1de746SOCHyams public:
9921d1de746SOCHyams   /// The kind of location in use for a variable, where Mem is the stack home,
9931d1de746SOCHyams   /// Val is an SSA value or const, and None means that there is not one single
9941d1de746SOCHyams   /// kind (either because there are multiple or because there is none; it may
9951d1de746SOCHyams   /// prove useful to split this into two values in the future).
9961d1de746SOCHyams   ///
9971d1de746SOCHyams   /// LocKind is a join-semilattice with the partial order:
9981d1de746SOCHyams   /// None > Mem, Val
9991d1de746SOCHyams   ///
10001d1de746SOCHyams   /// i.e.
10011d1de746SOCHyams   /// join(Mem, Mem)   = Mem
10021d1de746SOCHyams   /// join(Val, Val)   = Val
10031d1de746SOCHyams   /// join(Mem, Val)   = None
10041d1de746SOCHyams   /// join(None, Mem)  = None
10051d1de746SOCHyams   /// join(None, Val)  = None
10061d1de746SOCHyams   /// join(None, None) = None
10071d1de746SOCHyams   ///
10081d1de746SOCHyams   /// Note: the order is not `None > Val > Mem` because we're using DIAssignID
10091d1de746SOCHyams   /// to name assignments and are not tracking the actual stored values.
10101d1de746SOCHyams   /// Therefore currently there's no way to ensure that Mem values and Val
10111d1de746SOCHyams   /// values are the same. This could be a future extension, though it's not
10121d1de746SOCHyams   /// clear that many additional locations would be recovered that way in
10131d1de746SOCHyams   /// practice as the likelihood of this sitation arising naturally seems
10141d1de746SOCHyams   /// incredibly low.
10151d1de746SOCHyams   enum class LocKind { Mem, Val, None };
10161d1de746SOCHyams 
10171d1de746SOCHyams   /// An abstraction of the assignment of a value to a variable or memory
10181d1de746SOCHyams   /// location.
10191d1de746SOCHyams   ///
10201d1de746SOCHyams   /// An Assignment is Known or NoneOrPhi. A Known Assignment means we have a
10211d1de746SOCHyams   /// DIAssignID ptr that represents it. NoneOrPhi means that we don't (or
10221d1de746SOCHyams   /// can't) know the ID of the last assignment that took place.
10231d1de746SOCHyams   ///
10241d1de746SOCHyams   /// The Status of the Assignment (Known or NoneOrPhi) is another
10251d1de746SOCHyams   /// join-semilattice. The partial order is:
10261d1de746SOCHyams   /// NoneOrPhi > Known {id_0, id_1, ...id_N}
10271d1de746SOCHyams   ///
10281d1de746SOCHyams   /// i.e. for all values x and y where x != y:
10291d1de746SOCHyams   /// join(x, x) = x
10301d1de746SOCHyams   /// join(x, y) = NoneOrPhi
1031ffd08c77SStephen Tozer   using AssignRecord = PointerUnion<DbgAssignIntrinsic *, DbgVariableRecord *>;
10321d1de746SOCHyams   struct Assignment {
10331d1de746SOCHyams     enum S { Known, NoneOrPhi } Status;
10341d1de746SOCHyams     /// ID of the assignment. nullptr if Status is not Known.
10351d1de746SOCHyams     DIAssignID *ID;
10361d1de746SOCHyams     /// The dbg.assign that marks this dbg-def. Mem-defs don't use this field.
10371d1de746SOCHyams     /// May be nullptr.
103852665432SStephen Tozer     AssignRecord Source;
10391d1de746SOCHyams 
10401d1de746SOCHyams     bool isSameSourceAssignment(const Assignment &Other) const {
10411d1de746SOCHyams       // Don't include Source in the equality check. Assignments are
10421d1de746SOCHyams       // defined by their ID, not debug intrinsic(s).
10431d1de746SOCHyams       return std::tie(Status, ID) == std::tie(Other.Status, Other.ID);
10441d1de746SOCHyams     }
10451d1de746SOCHyams     void dump(raw_ostream &OS) {
10461d1de746SOCHyams       static const char *LUT[] = {"Known", "NoneOrPhi"};
10471d1de746SOCHyams       OS << LUT[Status] << "(id=";
10481d1de746SOCHyams       if (ID)
10491d1de746SOCHyams         OS << ID;
10501d1de746SOCHyams       else
10511d1de746SOCHyams         OS << "null";
10521d1de746SOCHyams       OS << ", s=";
105352665432SStephen Tozer       if (Source.isNull())
10541d1de746SOCHyams         OS << "null";
10555b19ed8bSKazu Hirata       else if (const auto *DAI = dyn_cast<DbgAssignIntrinsic *>(Source))
10565b19ed8bSKazu Hirata         OS << DAI;
105752665432SStephen Tozer       else
10585b19ed8bSKazu Hirata         OS << cast<DbgVariableRecord *>(Source);
10591d1de746SOCHyams       OS << ")";
10601d1de746SOCHyams     }
10611d1de746SOCHyams 
10621d1de746SOCHyams     static Assignment make(DIAssignID *ID, DbgAssignIntrinsic *Source) {
10631d1de746SOCHyams       return Assignment(Known, ID, Source);
10641d1de746SOCHyams     }
1065ffd08c77SStephen Tozer     static Assignment make(DIAssignID *ID, DbgVariableRecord *Source) {
106652665432SStephen Tozer       assert(Source->isDbgAssign() &&
1067ffd08c77SStephen Tozer              "Cannot make an assignment from a non-assign DbgVariableRecord");
106852665432SStephen Tozer       return Assignment(Known, ID, Source);
106952665432SStephen Tozer     }
107052665432SStephen Tozer     static Assignment make(DIAssignID *ID, AssignRecord Source) {
107152665432SStephen Tozer       return Assignment(Known, ID, Source);
107252665432SStephen Tozer     }
10731d1de746SOCHyams     static Assignment makeFromMemDef(DIAssignID *ID) {
107452665432SStephen Tozer       return Assignment(Known, ID);
10751d1de746SOCHyams     }
107652665432SStephen Tozer     static Assignment makeNoneOrPhi() { return Assignment(NoneOrPhi, nullptr); }
10771d1de746SOCHyams     // Again, need a Top value?
107852665432SStephen Tozer     Assignment() : Status(NoneOrPhi), ID(nullptr) {} // Can we delete this?
107952665432SStephen Tozer     Assignment(S Status, DIAssignID *ID) : Status(Status), ID(ID) {
108052665432SStephen Tozer       // If the Status is Known then we expect there to be an assignment ID.
108152665432SStephen Tozer       assert(Status == NoneOrPhi || ID);
108252665432SStephen Tozer     }
10831d1de746SOCHyams     Assignment(S Status, DIAssignID *ID, DbgAssignIntrinsic *Source)
10841d1de746SOCHyams         : Status(Status), ID(ID), Source(Source) {
10851d1de746SOCHyams       // If the Status is Known then we expect there to be an assignment ID.
10861d1de746SOCHyams       assert(Status == NoneOrPhi || ID);
10871d1de746SOCHyams     }
1088ffd08c77SStephen Tozer     Assignment(S Status, DIAssignID *ID, DbgVariableRecord *Source)
108952665432SStephen Tozer         : Status(Status), ID(ID), Source(Source) {
109052665432SStephen Tozer       // If the Status is Known then we expect there to be an assignment ID.
109152665432SStephen Tozer       assert(Status == NoneOrPhi || ID);
109252665432SStephen Tozer     }
109352665432SStephen Tozer     Assignment(S Status, DIAssignID *ID, AssignRecord Source)
109452665432SStephen Tozer         : Status(Status), ID(ID), Source(Source) {
109552665432SStephen Tozer       // If the Status is Known then we expect there to be an assignment ID.
109652665432SStephen Tozer       assert(Status == NoneOrPhi || ID);
109752665432SStephen Tozer     }
10981d1de746SOCHyams   };
10991d1de746SOCHyams 
1100d5b2c8e5SOCHyams   using AssignmentMap = SmallVector<Assignment>;
1101d5b2c8e5SOCHyams   using LocMap = SmallVector<LocKind>;
1102d5b2c8e5SOCHyams   using OverlapMap = DenseMap<VariableID, SmallVector<VariableID>>;
11031d1de746SOCHyams   using UntaggedStoreAssignmentMap =
11041d1de746SOCHyams       DenseMap<const Instruction *,
11051d1de746SOCHyams                SmallVector<std::pair<VariableID, at::AssignmentInfo>>>;
11061d1de746SOCHyams 
11071d1de746SOCHyams private:
1108d5b2c8e5SOCHyams   /// The highest numbered VariableID for partially promoted variables plus 1,
1109d5b2c8e5SOCHyams   /// the values for which start at 1.
1110d5b2c8e5SOCHyams   unsigned TrackedVariablesVectorSize = 0;
11111d1de746SOCHyams   /// Map a variable to the set of variables that it fully contains.
11121d1de746SOCHyams   OverlapMap VarContains;
11131d1de746SOCHyams   /// Map untagged stores to the variable fragments they assign to. Used by
11141d1de746SOCHyams   /// processUntaggedInstruction.
11151d1de746SOCHyams   UntaggedStoreAssignmentMap UntaggedStoreVars;
11161d1de746SOCHyams 
11171d1de746SOCHyams   // Machinery to defer inserting dbg.values.
11186aeb7a71SStephen Tozer   using InstInsertMap = MapVector<VarLocInsertPt, SmallVector<VarLocInfo>>;
11196aeb7a71SStephen Tozer   InstInsertMap InsertBeforeMap;
11201d1de746SOCHyams   /// Clear the location definitions currently cached for insertion after /p
11211d1de746SOCHyams   /// After.
11221d1de746SOCHyams   void resetInsertionPoint(Instruction &After);
1123ffd08c77SStephen Tozer   void resetInsertionPoint(DbgVariableRecord &After);
112452665432SStephen Tozer 
112552665432SStephen Tozer   // emitDbgValue can be called with:
1126ffd08c77SStephen Tozer   //   Source=[AssignRecord|DbgValueInst*|DbgAssignIntrinsic*|DbgVariableRecord*]
112752665432SStephen Tozer   // Since AssignRecord can be cast to one of the latter two types, and all
112852665432SStephen Tozer   // other types have a shared interface, we use a template to handle the latter
112952665432SStephen Tozer   // three types, and an explicit overload for AssignRecord that forwards to
113052665432SStephen Tozer   // the template version with the right type.
113152665432SStephen Tozer   void emitDbgValue(LocKind Kind, AssignRecord Source, VarLocInsertPt After);
113252665432SStephen Tozer   template <typename T>
113352665432SStephen Tozer   void emitDbgValue(LocKind Kind, const T Source, VarLocInsertPt After);
11341d1de746SOCHyams 
1135d5b2c8e5SOCHyams   static bool mapsAreEqual(const BitVector &Mask, const AssignmentMap &A,
1136d5b2c8e5SOCHyams                            const AssignmentMap &B) {
1137d5b2c8e5SOCHyams     return llvm::all_of(Mask.set_bits(), [&](unsigned VarID) {
1138d5b2c8e5SOCHyams       return A[VarID].isSameSourceAssignment(B[VarID]);
1139d5b2c8e5SOCHyams     });
11401d1de746SOCHyams   }
11411d1de746SOCHyams 
11421d1de746SOCHyams   /// Represents the stack and debug assignments in a block. Used to describe
11431d1de746SOCHyams   /// the live-in and live-out values for blocks, as well as the "current"
11441d1de746SOCHyams   /// value as we process each instruction in a block.
11451d1de746SOCHyams   struct BlockInfo {
1146d5b2c8e5SOCHyams     /// The set of variables (VariableID) being tracked in this block.
1147d5b2c8e5SOCHyams     BitVector VariableIDsInBlock;
1148d5b2c8e5SOCHyams     /// Dominating assignment to memory for each variable, indexed by
1149d5b2c8e5SOCHyams     /// VariableID.
11501d1de746SOCHyams     AssignmentMap StackHomeValue;
1151d5b2c8e5SOCHyams     /// Dominating assignemnt to each variable, indexed by VariableID.
11521d1de746SOCHyams     AssignmentMap DebugValue;
11531d1de746SOCHyams     /// Location kind for each variable. LiveLoc indicates whether the
11541d1de746SOCHyams     /// dominating assignment in StackHomeValue (LocKind::Mem), DebugValue
11551d1de746SOCHyams     /// (LocKind::Val), or neither (LocKind::None) is valid, in that order of
11561d1de746SOCHyams     /// preference. This cannot be derived by inspecting DebugValue and
11571d1de746SOCHyams     /// StackHomeValue due to the fact that there's no distinction in
11581d1de746SOCHyams     /// Assignment (the class) between whether an assignment is unknown or a
11591d1de746SOCHyams     /// merge of multiple assignments (both are Status::NoneOrPhi). In other
11601d1de746SOCHyams     /// words, the memory location may well be valid while both DebugValue and
11611d1de746SOCHyams     /// StackHomeValue contain Assignments that have a Status of NoneOrPhi.
1162d5b2c8e5SOCHyams     /// Indexed by VariableID.
11631d1de746SOCHyams     LocMap LiveLoc;
11641d1de746SOCHyams 
1165d5b2c8e5SOCHyams   public:
1166d5b2c8e5SOCHyams     enum AssignmentKind { Stack, Debug };
1167d5b2c8e5SOCHyams     const AssignmentMap &getAssignmentMap(AssignmentKind Kind) const {
1168d5b2c8e5SOCHyams       switch (Kind) {
1169d5b2c8e5SOCHyams       case Stack:
1170d5b2c8e5SOCHyams         return StackHomeValue;
1171d5b2c8e5SOCHyams       case Debug:
1172d5b2c8e5SOCHyams         return DebugValue;
1173d5b2c8e5SOCHyams       }
1174d5b2c8e5SOCHyams       llvm_unreachable("Unknown AssignmentKind");
1175d5b2c8e5SOCHyams     }
1176d5b2c8e5SOCHyams     AssignmentMap &getAssignmentMap(AssignmentKind Kind) {
1177d5b2c8e5SOCHyams       return const_cast<AssignmentMap &>(
1178d5b2c8e5SOCHyams           const_cast<const BlockInfo *>(this)->getAssignmentMap(Kind));
1179d5b2c8e5SOCHyams     }
1180d5b2c8e5SOCHyams 
1181d5b2c8e5SOCHyams     bool isVariableTracked(VariableID Var) const {
1182d5b2c8e5SOCHyams       return VariableIDsInBlock[static_cast<unsigned>(Var)];
1183d5b2c8e5SOCHyams     }
1184d5b2c8e5SOCHyams 
1185d5b2c8e5SOCHyams     const Assignment &getAssignment(AssignmentKind Kind, VariableID Var) const {
1186d5b2c8e5SOCHyams       assert(isVariableTracked(Var) && "Var not tracked in block");
1187d5b2c8e5SOCHyams       return getAssignmentMap(Kind)[static_cast<unsigned>(Var)];
1188d5b2c8e5SOCHyams     }
1189d5b2c8e5SOCHyams 
1190d5b2c8e5SOCHyams     LocKind getLocKind(VariableID Var) const {
1191d5b2c8e5SOCHyams       assert(isVariableTracked(Var) && "Var not tracked in block");
1192d5b2c8e5SOCHyams       return LiveLoc[static_cast<unsigned>(Var)];
1193d5b2c8e5SOCHyams     }
1194d5b2c8e5SOCHyams 
1195d5b2c8e5SOCHyams     /// Set LocKind for \p Var only: does not set LocKind for VariableIDs of
1196d5b2c8e5SOCHyams     /// fragments contained win \p Var.
1197d5b2c8e5SOCHyams     void setLocKind(VariableID Var, LocKind K) {
1198d5b2c8e5SOCHyams       VariableIDsInBlock.set(static_cast<unsigned>(Var));
1199d5b2c8e5SOCHyams       LiveLoc[static_cast<unsigned>(Var)] = K;
1200d5b2c8e5SOCHyams     }
1201d5b2c8e5SOCHyams 
1202d5b2c8e5SOCHyams     /// Set the assignment in the \p Kind assignment map for \p Var only: does
1203d5b2c8e5SOCHyams     /// not set the assignment for VariableIDs of fragments contained win \p
1204d5b2c8e5SOCHyams     /// Var.
1205d5b2c8e5SOCHyams     void setAssignment(AssignmentKind Kind, VariableID Var,
1206d5b2c8e5SOCHyams                        const Assignment &AV) {
1207d5b2c8e5SOCHyams       VariableIDsInBlock.set(static_cast<unsigned>(Var));
1208d5b2c8e5SOCHyams       getAssignmentMap(Kind)[static_cast<unsigned>(Var)] = AV;
1209d5b2c8e5SOCHyams     }
1210d5b2c8e5SOCHyams 
1211d5b2c8e5SOCHyams     /// Return true if there is an assignment matching \p AV in the \p Kind
1212d5b2c8e5SOCHyams     /// assignment map. Does consider assignments for VariableIDs of fragments
1213d5b2c8e5SOCHyams     /// contained win \p Var.
1214d5b2c8e5SOCHyams     bool hasAssignment(AssignmentKind Kind, VariableID Var,
1215d5b2c8e5SOCHyams                        const Assignment &AV) const {
1216d5b2c8e5SOCHyams       if (!isVariableTracked(Var))
1217d5b2c8e5SOCHyams         return false;
1218d5b2c8e5SOCHyams       return AV.isSameSourceAssignment(getAssignment(Kind, Var));
1219d5b2c8e5SOCHyams     }
1220d5b2c8e5SOCHyams 
12211d1de746SOCHyams     /// Compare every element in each map to determine structural equality
12221d1de746SOCHyams     /// (slow).
12231d1de746SOCHyams     bool operator==(const BlockInfo &Other) const {
1224d5b2c8e5SOCHyams       return VariableIDsInBlock == Other.VariableIDsInBlock &&
1225d5b2c8e5SOCHyams              LiveLoc == Other.LiveLoc &&
1226d5b2c8e5SOCHyams              mapsAreEqual(VariableIDsInBlock, StackHomeValue,
1227d5b2c8e5SOCHyams                           Other.StackHomeValue) &&
1228d5b2c8e5SOCHyams              mapsAreEqual(VariableIDsInBlock, DebugValue, Other.DebugValue);
12291d1de746SOCHyams     }
12301d1de746SOCHyams     bool operator!=(const BlockInfo &Other) const { return !(*this == Other); }
12311d1de746SOCHyams     bool isValid() {
12321d1de746SOCHyams       return LiveLoc.size() == DebugValue.size() &&
12331d1de746SOCHyams              LiveLoc.size() == StackHomeValue.size();
12341d1de746SOCHyams     }
1235d5b2c8e5SOCHyams 
1236d5b2c8e5SOCHyams     /// Clear everything and initialise with ⊤-values for all variables.
1237d5b2c8e5SOCHyams     void init(int NumVars) {
1238d5b2c8e5SOCHyams       StackHomeValue.clear();
1239d5b2c8e5SOCHyams       DebugValue.clear();
1240d5b2c8e5SOCHyams       LiveLoc.clear();
1241d5b2c8e5SOCHyams       VariableIDsInBlock = BitVector(NumVars);
1242d5b2c8e5SOCHyams       StackHomeValue.insert(StackHomeValue.begin(), NumVars,
1243d5b2c8e5SOCHyams                             Assignment::makeNoneOrPhi());
1244d5b2c8e5SOCHyams       DebugValue.insert(DebugValue.begin(), NumVars,
1245d5b2c8e5SOCHyams                         Assignment::makeNoneOrPhi());
1246d5b2c8e5SOCHyams       LiveLoc.insert(LiveLoc.begin(), NumVars, LocKind::None);
1247d5b2c8e5SOCHyams     }
1248d5b2c8e5SOCHyams 
1249d5b2c8e5SOCHyams     /// Helper for join.
1250d5b2c8e5SOCHyams     template <typename ElmtType, typename FnInputType>
1251d5b2c8e5SOCHyams     static void joinElmt(int Index, SmallVector<ElmtType> &Target,
1252d5b2c8e5SOCHyams                          const SmallVector<ElmtType> &A,
1253d5b2c8e5SOCHyams                          const SmallVector<ElmtType> &B,
1254d5b2c8e5SOCHyams                          ElmtType (*Fn)(FnInputType, FnInputType)) {
1255d5b2c8e5SOCHyams       Target[Index] = Fn(A[Index], B[Index]);
1256d5b2c8e5SOCHyams     }
1257d5b2c8e5SOCHyams 
1258d5b2c8e5SOCHyams     /// See comment for AssignmentTrackingLowering::joinBlockInfo.
1259d5b2c8e5SOCHyams     static BlockInfo join(const BlockInfo &A, const BlockInfo &B, int NumVars) {
1260d5b2c8e5SOCHyams       // Join A and B.
1261d5b2c8e5SOCHyams       //
1262d5b2c8e5SOCHyams       // Intersect = join(a, b) for a in A, b in B where Var(a) == Var(b)
1263d5b2c8e5SOCHyams       // Difference = join(x, ⊤) for x where Var(x) is in A xor B
1264d5b2c8e5SOCHyams       // Join = Intersect ∪ Difference
1265d5b2c8e5SOCHyams       //
1266d5b2c8e5SOCHyams       // This is achieved by performing a join on elements from A and B with
1267d5b2c8e5SOCHyams       // variables common to both A and B (join elements indexed by var
1268d5b2c8e5SOCHyams       // intersect), then adding ⊤-value elements for vars in A xor B. The
1269d5b2c8e5SOCHyams       // latter part is equivalent to performing join on elements with variables
1270d5b2c8e5SOCHyams       // in A xor B with the ⊤-value for the map element since join(x, ⊤) = ⊤.
1271d5b2c8e5SOCHyams       // BlockInfo::init initializes all variable entries to the ⊤ value so we
1272d5b2c8e5SOCHyams       // don't need to explicitly perform that step as Join.VariableIDsInBlock
1273d5b2c8e5SOCHyams       // is set to the union of the variables in A and B at the end of this
1274d5b2c8e5SOCHyams       // function.
1275d5b2c8e5SOCHyams       BlockInfo Join;
1276d5b2c8e5SOCHyams       Join.init(NumVars);
1277d5b2c8e5SOCHyams 
1278d5b2c8e5SOCHyams       BitVector Intersect = A.VariableIDsInBlock;
1279d5b2c8e5SOCHyams       Intersect &= B.VariableIDsInBlock;
1280d5b2c8e5SOCHyams 
1281d5b2c8e5SOCHyams       for (auto VarID : Intersect.set_bits()) {
1282d5b2c8e5SOCHyams         joinElmt(VarID, Join.LiveLoc, A.LiveLoc, B.LiveLoc, joinKind);
1283d5b2c8e5SOCHyams         joinElmt(VarID, Join.DebugValue, A.DebugValue, B.DebugValue,
1284d5b2c8e5SOCHyams                  joinAssignment);
1285d5b2c8e5SOCHyams         joinElmt(VarID, Join.StackHomeValue, A.StackHomeValue, B.StackHomeValue,
1286d5b2c8e5SOCHyams                  joinAssignment);
1287d5b2c8e5SOCHyams       }
1288d5b2c8e5SOCHyams 
1289d5b2c8e5SOCHyams       Join.VariableIDsInBlock = A.VariableIDsInBlock;
1290d5b2c8e5SOCHyams       Join.VariableIDsInBlock |= B.VariableIDsInBlock;
1291d5b2c8e5SOCHyams       assert(Join.isValid());
1292d5b2c8e5SOCHyams       return Join;
1293d5b2c8e5SOCHyams     }
12941d1de746SOCHyams   };
12951d1de746SOCHyams 
12961d1de746SOCHyams   Function &Fn;
12971d1de746SOCHyams   const DataLayout &Layout;
12981d1de746SOCHyams   const DenseSet<DebugAggregate> *VarsWithStackSlot;
12991d1de746SOCHyams   FunctionVarLocsBuilder *FnVarLocs;
13001d1de746SOCHyams   DenseMap<const BasicBlock *, BlockInfo> LiveIn;
13011d1de746SOCHyams   DenseMap<const BasicBlock *, BlockInfo> LiveOut;
13021d1de746SOCHyams 
13031d1de746SOCHyams   /// Helper for process methods to track variables touched each frame.
13041d1de746SOCHyams   DenseSet<VariableID> VarsTouchedThisFrame;
13051d1de746SOCHyams 
13061d1de746SOCHyams   /// The set of variables that sometimes are not located in their stack home.
13071d1de746SOCHyams   DenseSet<DebugAggregate> NotAlwaysStackHomed;
13081d1de746SOCHyams 
13091d1de746SOCHyams   VariableID getVariableID(const DebugVariable &Var) {
13101d1de746SOCHyams     return static_cast<VariableID>(FnVarLocs->insertVariable(Var));
13111d1de746SOCHyams   }
13121d1de746SOCHyams 
13131d1de746SOCHyams   /// Join the LiveOut values of preds that are contained in \p Visited into
13141d1de746SOCHyams   /// LiveIn[BB]. Return True if LiveIn[BB] has changed as a result. LiveIn[BB]
13151d1de746SOCHyams   /// values monotonically increase. See the @link joinMethods join methods
13161d1de746SOCHyams   /// @endlink documentation for more info.
13171d1de746SOCHyams   bool join(const BasicBlock &BB, const SmallPtrSet<BasicBlock *, 16> &Visited);
13181d1de746SOCHyams   ///@name joinMethods
13191d1de746SOCHyams   /// Functions that implement `join` (the least upper bound) for the
13201d1de746SOCHyams   /// join-semilattice types used in the dataflow. There is an explicit bottom
13211d1de746SOCHyams   /// value (⊥) for some types and and explicit top value (⊤) for all types.
13221d1de746SOCHyams   /// By definition:
13231d1de746SOCHyams   ///
13241d1de746SOCHyams   ///     Join(A, B) >= A && Join(A, B) >= B
13251d1de746SOCHyams   ///     Join(A, ⊥) = A
13261d1de746SOCHyams   ///     Join(A, ⊤) = ⊤
13271d1de746SOCHyams   ///
13281d1de746SOCHyams   /// These invariants are important for monotonicity.
13291d1de746SOCHyams   ///
13301d1de746SOCHyams   /// For the map-type functions, all unmapped keys in an empty map are
13311d1de746SOCHyams   /// associated with a bottom value (⊥). This represents their values being
13321d1de746SOCHyams   /// unknown. Unmapped keys in non-empty maps (joining two maps with a key
13331d1de746SOCHyams   /// only present in one) represents either a variable going out of scope or
13341d1de746SOCHyams   /// dropped debug info. It is assumed the key is associated with a top value
13351d1de746SOCHyams   /// (⊤) in this case (unknown location / assignment).
13361d1de746SOCHyams   ///@{
13371d1de746SOCHyams   static LocKind joinKind(LocKind A, LocKind B);
13381d1de746SOCHyams   static Assignment joinAssignment(const Assignment &A, const Assignment &B);
1339d5b2c8e5SOCHyams   BlockInfo joinBlockInfo(const BlockInfo &A, const BlockInfo &B);
13401d1de746SOCHyams   ///@}
13411d1de746SOCHyams 
13421d1de746SOCHyams   /// Process the instructions in \p BB updating \p LiveSet along the way. \p
13431d1de746SOCHyams   /// LiveSet must be initialized with the current live-in locations before
13441d1de746SOCHyams   /// calling this.
13451d1de746SOCHyams   void process(BasicBlock &BB, BlockInfo *LiveSet);
13461d1de746SOCHyams   ///@name processMethods
13471d1de746SOCHyams   /// Methods to process instructions in order to update the LiveSet (current
13481d1de746SOCHyams   /// location information).
13491d1de746SOCHyams   ///@{
13501d1de746SOCHyams   void processNonDbgInstruction(Instruction &I, BlockInfo *LiveSet);
135193c194fcSOCHyams   void processDbgInstruction(DbgInfoIntrinsic &I, BlockInfo *LiveSet);
13521d1de746SOCHyams   /// Update \p LiveSet after encountering an instruction with a DIAssignID
13531d1de746SOCHyams   /// attachment, \p I.
13541d1de746SOCHyams   void processTaggedInstruction(Instruction &I, BlockInfo *LiveSet);
13551d1de746SOCHyams   /// Update \p LiveSet after encountering an instruciton without a DIAssignID
13561d1de746SOCHyams   /// attachment, \p I.
13571d1de746SOCHyams   void processUntaggedInstruction(Instruction &I, BlockInfo *LiveSet);
135852665432SStephen Tozer   void processDbgAssign(AssignRecord Assign, BlockInfo *LiveSet);
1359ffd08c77SStephen Tozer   void processDbgVariableRecord(DbgVariableRecord &DVR, BlockInfo *LiveSet);
1360ffd08c77SStephen Tozer   void processDbgValue(
1361ffd08c77SStephen Tozer       PointerUnion<DbgValueInst *, DbgVariableRecord *> DbgValueRecord,
136252665432SStephen Tozer       BlockInfo *LiveSet);
13631d1de746SOCHyams   /// Add an assignment to memory for the variable /p Var.
13641d1de746SOCHyams   void addMemDef(BlockInfo *LiveSet, VariableID Var, const Assignment &AV);
13651d1de746SOCHyams   /// Add an assignment to the variable /p Var.
13661d1de746SOCHyams   void addDbgDef(BlockInfo *LiveSet, VariableID Var, const Assignment &AV);
13671d1de746SOCHyams   ///@}
13681d1de746SOCHyams 
13691d1de746SOCHyams   /// Set the LocKind for \p Var.
13701d1de746SOCHyams   void setLocKind(BlockInfo *LiveSet, VariableID Var, LocKind K);
13711d1de746SOCHyams   /// Get the live LocKind for a \p Var. Requires addMemDef or addDbgDef to
13721d1de746SOCHyams   /// have been called for \p Var first.
13731d1de746SOCHyams   LocKind getLocKind(BlockInfo *LiveSet, VariableID Var);
13741d1de746SOCHyams   /// Return true if \p Var has an assignment in \p M matching \p AV.
1375d5b2c8e5SOCHyams   bool hasVarWithAssignment(BlockInfo *LiveSet, BlockInfo::AssignmentKind Kind,
1376d5b2c8e5SOCHyams                             VariableID Var, const Assignment &AV);
1377d5b2c8e5SOCHyams   /// Return the set of VariableIDs corresponding the fragments contained fully
1378d5b2c8e5SOCHyams   /// within the variable/fragment \p Var.
1379d5b2c8e5SOCHyams   ArrayRef<VariableID> getContainedFragments(VariableID Var) const;
1380d5b2c8e5SOCHyams 
1381d5b2c8e5SOCHyams   /// Mark \p Var as having been touched this frame. Note, this applies only
1382d5b2c8e5SOCHyams   /// to the exact fragment \p Var and not to any fragments contained within.
1383d5b2c8e5SOCHyams   void touchFragment(VariableID Var);
13841d1de746SOCHyams 
13851d1de746SOCHyams   /// Emit info for variables that are fully promoted.
13861d1de746SOCHyams   bool emitPromotedVarLocs(FunctionVarLocsBuilder *FnVarLocs);
13871d1de746SOCHyams 
13881d1de746SOCHyams public:
13891d1de746SOCHyams   AssignmentTrackingLowering(Function &Fn, const DataLayout &Layout,
13901d1de746SOCHyams                              const DenseSet<DebugAggregate> *VarsWithStackSlot)
13911d1de746SOCHyams       : Fn(Fn), Layout(Layout), VarsWithStackSlot(VarsWithStackSlot) {}
13921d1de746SOCHyams   /// Run the analysis, adding variable location info to \p FnVarLocs. Returns
13931d1de746SOCHyams   /// true if any variable locations have been added to FnVarLocs.
13941d1de746SOCHyams   bool run(FunctionVarLocsBuilder *FnVarLocs);
13951d1de746SOCHyams };
1396b6942a28SBenjamin Kramer } // namespace
13971d1de746SOCHyams 
1398d5b2c8e5SOCHyams ArrayRef<VariableID>
1399d5b2c8e5SOCHyams AssignmentTrackingLowering::getContainedFragments(VariableID Var) const {
1400d5b2c8e5SOCHyams   auto R = VarContains.find(Var);
1401d5b2c8e5SOCHyams   if (R == VarContains.end())
1402e03f4271SJay Foad     return {};
1403d5b2c8e5SOCHyams   return R->second;
1404d5b2c8e5SOCHyams }
1405d5b2c8e5SOCHyams 
1406d5b2c8e5SOCHyams void AssignmentTrackingLowering::touchFragment(VariableID Var) {
1407d5b2c8e5SOCHyams   VarsTouchedThisFrame.insert(Var);
1408d5b2c8e5SOCHyams }
1409d5b2c8e5SOCHyams 
14101d1de746SOCHyams void AssignmentTrackingLowering::setLocKind(BlockInfo *LiveSet, VariableID Var,
14111d1de746SOCHyams                                             LocKind K) {
14121d1de746SOCHyams   auto SetKind = [this](BlockInfo *LiveSet, VariableID Var, LocKind K) {
1413d5b2c8e5SOCHyams     LiveSet->setLocKind(Var, K);
1414d5b2c8e5SOCHyams     touchFragment(Var);
14151d1de746SOCHyams   };
14161d1de746SOCHyams   SetKind(LiveSet, Var, K);
14171d1de746SOCHyams 
14181d1de746SOCHyams   // Update the LocKind for all fragments contained within Var.
1419d5b2c8e5SOCHyams   for (VariableID Frag : getContainedFragments(Var))
14201d1de746SOCHyams     SetKind(LiveSet, Frag, K);
14211d1de746SOCHyams }
14221d1de746SOCHyams 
14231d1de746SOCHyams AssignmentTrackingLowering::LocKind
14241d1de746SOCHyams AssignmentTrackingLowering::getLocKind(BlockInfo *LiveSet, VariableID Var) {
1425d5b2c8e5SOCHyams   return LiveSet->getLocKind(Var);
14261d1de746SOCHyams }
14271d1de746SOCHyams 
14281d1de746SOCHyams void AssignmentTrackingLowering::addMemDef(BlockInfo *LiveSet, VariableID Var,
14291d1de746SOCHyams                                            const Assignment &AV) {
1430d5b2c8e5SOCHyams   LiveSet->setAssignment(BlockInfo::Stack, Var, AV);
14311d1de746SOCHyams 
14321d1de746SOCHyams   // Use this assigment for all fragments contained within Var, but do not
14331d1de746SOCHyams   // provide a Source because we cannot convert Var's value to a value for the
14341d1de746SOCHyams   // fragment.
14351d1de746SOCHyams   Assignment FragAV = AV;
14361d1de746SOCHyams   FragAV.Source = nullptr;
1437d5b2c8e5SOCHyams   for (VariableID Frag : getContainedFragments(Var))
1438d5b2c8e5SOCHyams     LiveSet->setAssignment(BlockInfo::Stack, Frag, FragAV);
14391d1de746SOCHyams }
14401d1de746SOCHyams 
14411d1de746SOCHyams void AssignmentTrackingLowering::addDbgDef(BlockInfo *LiveSet, VariableID Var,
14421d1de746SOCHyams                                            const Assignment &AV) {
1443d5b2c8e5SOCHyams   LiveSet->setAssignment(BlockInfo::Debug, Var, AV);
14441d1de746SOCHyams 
14451d1de746SOCHyams   // Use this assigment for all fragments contained within Var, but do not
14461d1de746SOCHyams   // provide a Source because we cannot convert Var's value to a value for the
14471d1de746SOCHyams   // fragment.
14481d1de746SOCHyams   Assignment FragAV = AV;
14491d1de746SOCHyams   FragAV.Source = nullptr;
1450d5b2c8e5SOCHyams   for (VariableID Frag : getContainedFragments(Var))
1451d5b2c8e5SOCHyams     LiveSet->setAssignment(BlockInfo::Debug, Frag, FragAV);
14521d1de746SOCHyams }
14531d1de746SOCHyams 
14541d1de746SOCHyams static DIAssignID *getIDFromInst(const Instruction &I) {
14551d1de746SOCHyams   return cast<DIAssignID>(I.getMetadata(LLVMContext::MD_DIAssignID));
14561d1de746SOCHyams }
14571d1de746SOCHyams 
14581d1de746SOCHyams static DIAssignID *getIDFromMarker(const DbgAssignIntrinsic &DAI) {
14591d1de746SOCHyams   return cast<DIAssignID>(DAI.getAssignID());
14601d1de746SOCHyams }
14611d1de746SOCHyams 
1462ffd08c77SStephen Tozer static DIAssignID *getIDFromMarker(const DbgVariableRecord &DVR) {
1463ffd08c77SStephen Tozer   assert(DVR.isDbgAssign() &&
1464ffd08c77SStephen Tozer          "Cannot get a DIAssignID from a non-assign DbgVariableRecord!");
1465ffd08c77SStephen Tozer   return DVR.getAssignID();
146652665432SStephen Tozer }
146752665432SStephen Tozer 
14681d1de746SOCHyams /// Return true if \p Var has an assignment in \p M matching \p AV.
1469d5b2c8e5SOCHyams bool AssignmentTrackingLowering::hasVarWithAssignment(
1470d5b2c8e5SOCHyams     BlockInfo *LiveSet, BlockInfo::AssignmentKind Kind, VariableID Var,
1471d5b2c8e5SOCHyams     const Assignment &AV) {
1472d5b2c8e5SOCHyams   if (!LiveSet->hasAssignment(Kind, Var, AV))
14731d1de746SOCHyams     return false;
14741d1de746SOCHyams 
14751d1de746SOCHyams   // Check all the frags contained within Var as these will have all been
14761d1de746SOCHyams   // mapped to AV at the last store to Var.
1477d5b2c8e5SOCHyams   for (VariableID Frag : getContainedFragments(Var))
1478d5b2c8e5SOCHyams     if (!LiveSet->hasAssignment(Kind, Frag, AV))
14791d1de746SOCHyams       return false;
14801d1de746SOCHyams   return true;
14811d1de746SOCHyams }
14821d1de746SOCHyams 
1483e0e48187SKazu Hirata #ifndef NDEBUG
14841d1de746SOCHyams const char *locStr(AssignmentTrackingLowering::LocKind Loc) {
14851d1de746SOCHyams   using LocKind = AssignmentTrackingLowering::LocKind;
14861d1de746SOCHyams   switch (Loc) {
14871d1de746SOCHyams   case LocKind::Val:
14881d1de746SOCHyams     return "Val";
14891d1de746SOCHyams   case LocKind::Mem:
14901d1de746SOCHyams     return "Mem";
14911d1de746SOCHyams   case LocKind::None:
14921d1de746SOCHyams     return "None";
14931d1de746SOCHyams   };
14941d1de746SOCHyams   llvm_unreachable("unknown LocKind");
14951d1de746SOCHyams }
1496e0e48187SKazu Hirata #endif
14971d1de746SOCHyams 
1498ffd08c77SStephen Tozer VarLocInsertPt getNextNode(const DbgRecord *DVR) {
1499ffd08c77SStephen Tozer   auto NextIt = ++(DVR->getIterator());
1500ffd08c77SStephen Tozer   if (NextIt == DVR->getMarker()->getDbgRecordRange().end())
1501ffd08c77SStephen Tozer     return DVR->getMarker()->MarkedInstr;
15026aeb7a71SStephen Tozer   return &*NextIt;
15036aeb7a71SStephen Tozer }
15046aeb7a71SStephen Tozer VarLocInsertPt getNextNode(const Instruction *Inst) {
15056aeb7a71SStephen Tozer   const Instruction *Next = Inst->getNextNode();
150615f3f446SStephen Tozer   if (!Next->hasDbgRecords())
15076aeb7a71SStephen Tozer     return Next;
150815f3f446SStephen Tozer   return &*Next->getDbgRecordRange().begin();
15096aeb7a71SStephen Tozer }
15106aeb7a71SStephen Tozer VarLocInsertPt getNextNode(VarLocInsertPt InsertPt) {
15116aeb7a71SStephen Tozer   if (isa<const Instruction *>(InsertPt))
15126aeb7a71SStephen Tozer     return getNextNode(cast<const Instruction *>(InsertPt));
1513ababa964SOrlando Cazalet-Hyams   return getNextNode(cast<const DbgRecord *>(InsertPt));
15146aeb7a71SStephen Tozer }
15156aeb7a71SStephen Tozer 
151652665432SStephen Tozer DbgAssignIntrinsic *CastToDbgAssign(DbgVariableIntrinsic *DVI) {
151752665432SStephen Tozer   return cast<DbgAssignIntrinsic>(DVI);
151852665432SStephen Tozer }
151952665432SStephen Tozer 
1520ffd08c77SStephen Tozer DbgVariableRecord *CastToDbgAssign(DbgVariableRecord *DVR) {
1521ffd08c77SStephen Tozer   assert(DVR->isDbgAssign() &&
1522ffd08c77SStephen Tozer          "Attempted to cast non-assign DbgVariableRecord to DVRAssign.");
1523ffd08c77SStephen Tozer   return DVR;
152452665432SStephen Tozer }
152552665432SStephen Tozer 
15261d1de746SOCHyams void AssignmentTrackingLowering::emitDbgValue(
15271d1de746SOCHyams     AssignmentTrackingLowering::LocKind Kind,
152852665432SStephen Tozer     AssignmentTrackingLowering::AssignRecord Source, VarLocInsertPt After) {
152952665432SStephen Tozer   if (isa<DbgAssignIntrinsic *>(Source))
153052665432SStephen Tozer     emitDbgValue(Kind, cast<DbgAssignIntrinsic *>(Source), After);
153152665432SStephen Tozer   else
1532ffd08c77SStephen Tozer     emitDbgValue(Kind, cast<DbgVariableRecord *>(Source), After);
153352665432SStephen Tozer }
153452665432SStephen Tozer template <typename T>
153552665432SStephen Tozer void AssignmentTrackingLowering::emitDbgValue(
153652665432SStephen Tozer     AssignmentTrackingLowering::LocKind Kind, const T Source,
153752665432SStephen Tozer     VarLocInsertPt After) {
15381d1de746SOCHyams 
15391d1de746SOCHyams   DILocation *DL = Source->getDebugLoc();
15407d894374SOCHyams   auto Emit = [this, Source, After, DL](Metadata *Val, DIExpression *Expr) {
15411d1de746SOCHyams     assert(Expr);
15421d1de746SOCHyams     if (!Val)
15437d894374SOCHyams       Val = ValueAsMetadata::get(
15447d894374SOCHyams           PoisonValue::get(Type::getInt1Ty(Source->getContext())));
15451d1de746SOCHyams 
15461d1de746SOCHyams     // Find a suitable insert point.
15476aeb7a71SStephen Tozer     auto InsertBefore = getNextNode(After);
15481d1de746SOCHyams     assert(InsertBefore && "Shouldn't be inserting after a terminator");
15491d1de746SOCHyams 
15501d1de746SOCHyams     VariableID Var = getVariableID(DebugVariable(Source));
15511d1de746SOCHyams     VarLocInfo VarLoc;
15521d1de746SOCHyams     VarLoc.VariableID = static_cast<VariableID>(Var);
15531d1de746SOCHyams     VarLoc.Expr = Expr;
15547d894374SOCHyams     VarLoc.Values = RawLocationWrapper(Val);
15551d1de746SOCHyams     VarLoc.DL = DL;
15561d1de746SOCHyams     // Insert it into the map for later.
15571d1de746SOCHyams     InsertBeforeMap[InsertBefore].push_back(VarLoc);
15581d1de746SOCHyams   };
15591d1de746SOCHyams 
15601d1de746SOCHyams   // NOTE: This block can mutate Kind.
15611d1de746SOCHyams   if (Kind == LocKind::Mem) {
156252665432SStephen Tozer     const auto *Assign = CastToDbgAssign(Source);
15631d1de746SOCHyams     // Check the address hasn't been dropped (e.g. the debug uses may not have
15641d1de746SOCHyams     // been replaced before deleting a Value).
156552665432SStephen Tozer     if (Assign->isKillAddress()) {
156683f7f86eSOCHyams       // The address isn't valid so treat this as a non-memory def.
156783f7f86eSOCHyams       Kind = LocKind::Val;
156883f7f86eSOCHyams     } else {
156952665432SStephen Tozer       Value *Val = Assign->getAddress();
157052665432SStephen Tozer       DIExpression *Expr = Assign->getAddressExpression();
15711d1de746SOCHyams       assert(!Expr->getFragmentInfo() &&
15721d1de746SOCHyams              "fragment info should be stored in value-expression only");
15731d1de746SOCHyams       // Copy the fragment info over from the value-expression to the new
15741d1de746SOCHyams       // DIExpression.
15751d1de746SOCHyams       if (auto OptFragInfo = Source->getExpression()->getFragmentInfo()) {
157651b68573SFangrui Song         auto FragInfo = *OptFragInfo;
15771d1de746SOCHyams         Expr = *DIExpression::createFragmentExpression(
15781d1de746SOCHyams             Expr, FragInfo.OffsetInBits, FragInfo.SizeInBits);
15791d1de746SOCHyams       }
15801d1de746SOCHyams       // The address-expression has an implicit deref, add it now.
15811d1de746SOCHyams       std::tie(Val, Expr) =
15821d1de746SOCHyams           walkToAllocaAndPrependOffsetDeref(Layout, Val, Expr);
15837d894374SOCHyams       Emit(ValueAsMetadata::get(Val), Expr);
15841d1de746SOCHyams       return;
15851d1de746SOCHyams     }
15861d1de746SOCHyams   }
15871d1de746SOCHyams 
15881d1de746SOCHyams   if (Kind == LocKind::Val) {
158947b99b7fSOCHyams     Emit(Source->getRawLocation(), Source->getExpression());
15901d1de746SOCHyams     return;
15911d1de746SOCHyams   }
15921d1de746SOCHyams 
15931d1de746SOCHyams   if (Kind == LocKind::None) {
159412ece768SOCHyams     Emit(nullptr, Source->getExpression());
15951d1de746SOCHyams     return;
15961d1de746SOCHyams   }
15971d1de746SOCHyams }
15981d1de746SOCHyams 
15991d1de746SOCHyams void AssignmentTrackingLowering::processNonDbgInstruction(
16001d1de746SOCHyams     Instruction &I, AssignmentTrackingLowering::BlockInfo *LiveSet) {
16011d1de746SOCHyams   if (I.hasMetadata(LLVMContext::MD_DIAssignID))
16021d1de746SOCHyams     processTaggedInstruction(I, LiveSet);
16031d1de746SOCHyams   else
16041d1de746SOCHyams     processUntaggedInstruction(I, LiveSet);
16051d1de746SOCHyams }
16061d1de746SOCHyams 
16071d1de746SOCHyams void AssignmentTrackingLowering::processUntaggedInstruction(
16081d1de746SOCHyams     Instruction &I, AssignmentTrackingLowering::BlockInfo *LiveSet) {
16091d1de746SOCHyams   // Interpret stack stores that are not tagged as an assignment in memory for
16101d1de746SOCHyams   // the variables associated with that address. These stores may not be tagged
16111d1de746SOCHyams   // because a) the store cannot be represented using dbg.assigns (non-const
16121d1de746SOCHyams   // length or offset) or b) the tag was accidentally dropped during
16131d1de746SOCHyams   // optimisations. For these stores we fall back to assuming that the stack
16141d1de746SOCHyams   // home is a valid location for the variables. The benefit is that this
16151d1de746SOCHyams   // prevents us missing an assignment and therefore incorrectly maintaining
16161d1de746SOCHyams   // earlier location definitions, and in many cases it should be a reasonable
16171d1de746SOCHyams   // assumption. However, this will occasionally lead to slight
16181d1de746SOCHyams   // inaccuracies. The value of a hoisted untagged store will be visible
16191d1de746SOCHyams   // "early", for example.
16201d1de746SOCHyams   assert(!I.hasMetadata(LLVMContext::MD_DIAssignID));
16211d1de746SOCHyams   auto It = UntaggedStoreVars.find(&I);
16221d1de746SOCHyams   if (It == UntaggedStoreVars.end())
16231d1de746SOCHyams     return; // No variables associated with the store destination.
16241d1de746SOCHyams 
16251d1de746SOCHyams   LLVM_DEBUG(dbgs() << "processUntaggedInstruction on UNTAGGED INST " << I
16261d1de746SOCHyams                     << "\n");
16271d1de746SOCHyams   // Iterate over the variables that this store affects, add a NoneOrPhi dbg
16281d1de746SOCHyams   // and mem def, set lockind to Mem, and emit a location def for each.
16291d1de746SOCHyams   for (auto [Var, Info] : It->second) {
16301d1de746SOCHyams     // This instruction is treated as both a debug and memory assignment,
16311d1de746SOCHyams     // meaning the memory location should be used. We don't have an assignment
16321d1de746SOCHyams     // ID though so use Assignment::makeNoneOrPhi() to create an imaginary one.
16331d1de746SOCHyams     addMemDef(LiveSet, Var, Assignment::makeNoneOrPhi());
16341d1de746SOCHyams     addDbgDef(LiveSet, Var, Assignment::makeNoneOrPhi());
16351d1de746SOCHyams     setLocKind(LiveSet, Var, LocKind::Mem);
16361d1de746SOCHyams     LLVM_DEBUG(dbgs() << "  setting Stack LocKind to: " << locStr(LocKind::Mem)
16371d1de746SOCHyams                       << "\n");
16381d1de746SOCHyams     // Build the dbg location def to insert.
16391d1de746SOCHyams     //
16401d1de746SOCHyams     // DIExpression: Add fragment and offset.
16411d1de746SOCHyams     DebugVariable V = FnVarLocs->getVariable(Var);
1642e03f4271SJay Foad     DIExpression *DIE = DIExpression::get(I.getContext(), {});
16431d1de746SOCHyams     if (auto Frag = V.getFragment()) {
16441d1de746SOCHyams       auto R = DIExpression::createFragmentExpression(DIE, Frag->OffsetInBits,
16451d1de746SOCHyams                                                       Frag->SizeInBits);
16461d1de746SOCHyams       assert(R && "unexpected createFragmentExpression failure");
164751b68573SFangrui Song       DIE = *R;
16481d1de746SOCHyams     }
16491d1de746SOCHyams     SmallVector<uint64_t, 3> Ops;
16501d1de746SOCHyams     if (Info.OffsetInBits)
16511d1de746SOCHyams       Ops = {dwarf::DW_OP_plus_uconst, Info.OffsetInBits / 8};
16521d1de746SOCHyams     Ops.push_back(dwarf::DW_OP_deref);
16531d1de746SOCHyams     DIE = DIExpression::prependOpcodes(DIE, Ops, /*StackValue=*/false,
16541d1de746SOCHyams                                        /*EntryValue=*/false);
1655360da838SStephen Tozer     // Find a suitable insert point, before the next instruction or DbgRecord
16566aeb7a71SStephen Tozer     // after I.
16576aeb7a71SStephen Tozer     auto InsertBefore = getNextNode(&I);
16581d1de746SOCHyams     assert(InsertBefore && "Shouldn't be inserting after a terminator");
16591d1de746SOCHyams 
16601d1de746SOCHyams     // Get DILocation for this unrecorded assignment.
16611d1de746SOCHyams     DILocation *InlinedAt = const_cast<DILocation *>(V.getInlinedAt());
16621d1de746SOCHyams     const DILocation *DILoc = DILocation::get(
16631d1de746SOCHyams         Fn.getContext(), 0, 0, V.getVariable()->getScope(), InlinedAt);
16641d1de746SOCHyams 
16651d1de746SOCHyams     VarLocInfo VarLoc;
16661d1de746SOCHyams     VarLoc.VariableID = static_cast<VariableID>(Var);
16671d1de746SOCHyams     VarLoc.Expr = DIE;
16687d894374SOCHyams     VarLoc.Values = RawLocationWrapper(
16697d894374SOCHyams         ValueAsMetadata::get(const_cast<AllocaInst *>(Info.Base)));
16701d1de746SOCHyams     VarLoc.DL = DILoc;
16711d1de746SOCHyams     // 3. Insert it into the map for later.
16721d1de746SOCHyams     InsertBeforeMap[InsertBefore].push_back(VarLoc);
16731d1de746SOCHyams   }
16741d1de746SOCHyams }
16751d1de746SOCHyams 
16761d1de746SOCHyams void AssignmentTrackingLowering::processTaggedInstruction(
16771d1de746SOCHyams     Instruction &I, AssignmentTrackingLowering::BlockInfo *LiveSet) {
16781d1de746SOCHyams   auto Linked = at::getAssignmentMarkers(&I);
1679ffd08c77SStephen Tozer   auto LinkedDPAssigns = at::getDVRAssignmentMarkers(&I);
16801d1de746SOCHyams   // No dbg.assign intrinsics linked.
16811d1de746SOCHyams   // FIXME: All vars that have a stack slot this store modifies that don't have
16821d1de746SOCHyams   // a dbg.assign linked to it should probably treat this like an untagged
16831d1de746SOCHyams   // store.
168452665432SStephen Tozer   if (Linked.empty() && LinkedDPAssigns.empty())
16851d1de746SOCHyams     return;
16861d1de746SOCHyams 
16871d1de746SOCHyams   LLVM_DEBUG(dbgs() << "processTaggedInstruction on " << I << "\n");
168852665432SStephen Tozer   auto ProcessLinkedAssign = [&](auto *Assign) {
168952665432SStephen Tozer     VariableID Var = getVariableID(DebugVariable(Assign));
16901d1de746SOCHyams     // Something has gone wrong if VarsWithStackSlot doesn't contain a variable
16911d1de746SOCHyams     // that is linked to a store.
169252665432SStephen Tozer     assert(VarsWithStackSlot->count(getAggregate(Assign)) &&
169352665432SStephen Tozer            "expected Assign's variable to have stack slot");
16941d1de746SOCHyams 
16951d1de746SOCHyams     Assignment AV = Assignment::makeFromMemDef(getIDFromInst(I));
16961d1de746SOCHyams     addMemDef(LiveSet, Var, AV);
16971d1de746SOCHyams 
169852665432SStephen Tozer     LLVM_DEBUG(dbgs() << "   linked to " << *Assign << "\n");
16991d1de746SOCHyams     LLVM_DEBUG(dbgs() << "   LiveLoc " << locStr(getLocKind(LiveSet, Var))
17001d1de746SOCHyams                       << " -> ");
17011d1de746SOCHyams 
17021d1de746SOCHyams     // The last assignment to the stack is now AV. Check if the last debug
17031d1de746SOCHyams     // assignment has a matching Assignment.
1704d5b2c8e5SOCHyams     if (hasVarWithAssignment(LiveSet, BlockInfo::Debug, Var, AV)) {
17051d1de746SOCHyams       // The StackHomeValue and DebugValue for this variable match so we can
17061d1de746SOCHyams       // emit a stack home location here.
17071d1de746SOCHyams       LLVM_DEBUG(dbgs() << "Mem, Stack matches Debug program\n";);
17081d1de746SOCHyams       LLVM_DEBUG(dbgs() << "   Stack val: "; AV.dump(dbgs()); dbgs() << "\n");
17091d1de746SOCHyams       LLVM_DEBUG(dbgs() << "   Debug val: ";
1710d5b2c8e5SOCHyams                  LiveSet->DebugValue[static_cast<unsigned>(Var)].dump(dbgs());
1711d5b2c8e5SOCHyams                  dbgs() << "\n");
17121d1de746SOCHyams       setLocKind(LiveSet, Var, LocKind::Mem);
171352665432SStephen Tozer       emitDbgValue(LocKind::Mem, Assign, &I);
171452665432SStephen Tozer       return;
17151d1de746SOCHyams     }
17161d1de746SOCHyams 
17171d1de746SOCHyams     // The StackHomeValue and DebugValue for this variable do not match. I.e.
17181d1de746SOCHyams     // The value currently stored in the stack is not what we'd expect to
17191d1de746SOCHyams     // see, so we cannot use emit a stack home location here. Now we will
17201d1de746SOCHyams     // look at the live LocKind for the variable and determine an appropriate
17211d1de746SOCHyams     // dbg.value to emit.
17221d1de746SOCHyams     LocKind PrevLoc = getLocKind(LiveSet, Var);
17231d1de746SOCHyams     switch (PrevLoc) {
17241d1de746SOCHyams     case LocKind::Val: {
17251d1de746SOCHyams       // The value in memory in memory has changed but we're not currently
17261d1de746SOCHyams       // using the memory location. Do nothing.
17271d1de746SOCHyams       LLVM_DEBUG(dbgs() << "Val, (unchanged)\n";);
17281d1de746SOCHyams       setLocKind(LiveSet, Var, LocKind::Val);
17291d1de746SOCHyams     } break;
17301d1de746SOCHyams     case LocKind::Mem: {
17311d1de746SOCHyams       // There's been an assignment to memory that we were using as a
17321d1de746SOCHyams       // location for this variable, and the Assignment doesn't match what
17331d1de746SOCHyams       // we'd expect to see in memory.
1734d5b2c8e5SOCHyams       Assignment DbgAV = LiveSet->getAssignment(BlockInfo::Debug, Var);
1735d5b2c8e5SOCHyams       if (DbgAV.Status == Assignment::NoneOrPhi) {
17361d1de746SOCHyams         // We need to terminate any previously open location now.
17371d1de746SOCHyams         LLVM_DEBUG(dbgs() << "None, No Debug value available\n";);
17381d1de746SOCHyams         setLocKind(LiveSet, Var, LocKind::None);
173952665432SStephen Tozer         emitDbgValue(LocKind::None, Assign, &I);
17401d1de746SOCHyams       } else {
17411d1de746SOCHyams         // The previous DebugValue Value can be used here.
17421d1de746SOCHyams         LLVM_DEBUG(dbgs() << "Val, Debug value is Known\n";);
17431d1de746SOCHyams         setLocKind(LiveSet, Var, LocKind::Val);
1744d5b2c8e5SOCHyams         if (DbgAV.Source) {
1745d5b2c8e5SOCHyams           emitDbgValue(LocKind::Val, DbgAV.Source, &I);
17461d1de746SOCHyams         } else {
17471d1de746SOCHyams           // PrevAV.Source is nullptr so we must emit undef here.
174852665432SStephen Tozer           emitDbgValue(LocKind::None, Assign, &I);
17491d1de746SOCHyams         }
17501d1de746SOCHyams       }
17511d1de746SOCHyams     } break;
17521d1de746SOCHyams     case LocKind::None: {
17531d1de746SOCHyams       // There's been an assignment to memory and we currently are
17541d1de746SOCHyams       // not tracking a location for the variable. Do not emit anything.
17551d1de746SOCHyams       LLVM_DEBUG(dbgs() << "None, (unchanged)\n";);
17561d1de746SOCHyams       setLocKind(LiveSet, Var, LocKind::None);
17571d1de746SOCHyams     } break;
17581d1de746SOCHyams     }
175952665432SStephen Tozer   };
176052665432SStephen Tozer   for (DbgAssignIntrinsic *DAI : Linked)
176152665432SStephen Tozer     ProcessLinkedAssign(DAI);
1762ffd08c77SStephen Tozer   for (DbgVariableRecord *DVR : LinkedDPAssigns)
1763ffd08c77SStephen Tozer     ProcessLinkedAssign(DVR);
17641d1de746SOCHyams }
17651d1de746SOCHyams 
176652665432SStephen Tozer void AssignmentTrackingLowering::processDbgAssign(AssignRecord Assign,
17671d1de746SOCHyams                                                   BlockInfo *LiveSet) {
176852665432SStephen Tozer   auto ProcessDbgAssignImpl = [&](auto *DbgAssign) {
17691d1de746SOCHyams     // Only bother tracking variables that are at some point stack homed. Other
17701d1de746SOCHyams     // variables can be dealt with trivially later.
177152665432SStephen Tozer     if (!VarsWithStackSlot->count(getAggregate(DbgAssign)))
17721d1de746SOCHyams       return;
17731d1de746SOCHyams 
177452665432SStephen Tozer     VariableID Var = getVariableID(DebugVariable(DbgAssign));
177552665432SStephen Tozer     Assignment AV = Assignment::make(getIDFromMarker(*DbgAssign), DbgAssign);
17761d1de746SOCHyams     addDbgDef(LiveSet, Var, AV);
17771d1de746SOCHyams 
177852665432SStephen Tozer     LLVM_DEBUG(dbgs() << "processDbgAssign on " << *DbgAssign << "\n";);
17791d1de746SOCHyams     LLVM_DEBUG(dbgs() << "   LiveLoc " << locStr(getLocKind(LiveSet, Var))
17801d1de746SOCHyams                       << " -> ");
17811d1de746SOCHyams 
17821d1de746SOCHyams     // Check if the DebugValue and StackHomeValue both hold the same
17831d1de746SOCHyams     // Assignment.
1784d5b2c8e5SOCHyams     if (hasVarWithAssignment(LiveSet, BlockInfo::Stack, Var, AV)) {
178552665432SStephen Tozer       // They match. We can use the stack home because the debug intrinsics
178652665432SStephen Tozer       // state that an assignment happened here, and we know that specific
178752665432SStephen Tozer       // assignment was the last one to take place in memory for this variable.
17881d1de746SOCHyams       LocKind Kind;
178952665432SStephen Tozer       if (DbgAssign->isKillAddress()) {
17901d1de746SOCHyams         LLVM_DEBUG(
179183f7f86eSOCHyams             dbgs()
179283f7f86eSOCHyams                 << "Val, Stack matches Debug program but address is killed\n";);
17931d1de746SOCHyams         Kind = LocKind::Val;
17941d1de746SOCHyams       } else {
17951d1de746SOCHyams         LLVM_DEBUG(dbgs() << "Mem, Stack matches Debug program\n";);
17961d1de746SOCHyams         Kind = LocKind::Mem;
17971d1de746SOCHyams       };
17981d1de746SOCHyams       setLocKind(LiveSet, Var, Kind);
179952665432SStephen Tozer       emitDbgValue(Kind, DbgAssign, DbgAssign);
18001d1de746SOCHyams     } else {
180152665432SStephen Tozer       // The last assignment to the memory location isn't the one that we want
180252665432SStephen Tozer       // to show to the user so emit a dbg.value(Value). Value may be undef.
18031d1de746SOCHyams       LLVM_DEBUG(dbgs() << "Val, Stack contents is unknown\n";);
18041d1de746SOCHyams       setLocKind(LiveSet, Var, LocKind::Val);
180552665432SStephen Tozer       emitDbgValue(LocKind::Val, DbgAssign, DbgAssign);
18061d1de746SOCHyams     }
180752665432SStephen Tozer   };
1808ffd08c77SStephen Tozer   if (isa<DbgVariableRecord *>(Assign))
1809ffd08c77SStephen Tozer     return ProcessDbgAssignImpl(cast<DbgVariableRecord *>(Assign));
181052665432SStephen Tozer   return ProcessDbgAssignImpl(cast<DbgAssignIntrinsic *>(Assign));
18111d1de746SOCHyams }
18121d1de746SOCHyams 
181352665432SStephen Tozer void AssignmentTrackingLowering::processDbgValue(
1814ffd08c77SStephen Tozer     PointerUnion<DbgValueInst *, DbgVariableRecord *> DbgValueRecord,
18151d1de746SOCHyams     BlockInfo *LiveSet) {
181652665432SStephen Tozer   auto ProcessDbgValueImpl = [&](auto *DbgValue) {
18171d1de746SOCHyams     // Only other tracking variables that are at some point stack homed.
18181d1de746SOCHyams     // Other variables can be dealt with trivally later.
181952665432SStephen Tozer     if (!VarsWithStackSlot->count(getAggregate(DbgValue)))
18201d1de746SOCHyams       return;
18211d1de746SOCHyams 
182252665432SStephen Tozer     VariableID Var = getVariableID(DebugVariable(DbgValue));
18231d1de746SOCHyams     // We have no ID to create an Assignment with so we mark this assignment as
18241d1de746SOCHyams     // NoneOrPhi. Note that the dbg.value still exists, we just cannot determine
18251d1de746SOCHyams     // the assignment responsible for setting this value.
18261d1de746SOCHyams     // This is fine; dbg.values are essentially interchangable with unlinked
18271d1de746SOCHyams     // dbg.assigns, and some passes such as mem2reg and instcombine add them to
18281d1de746SOCHyams     // PHIs for promoted variables.
18291d1de746SOCHyams     Assignment AV = Assignment::makeNoneOrPhi();
18301d1de746SOCHyams     addDbgDef(LiveSet, Var, AV);
18311d1de746SOCHyams 
183252665432SStephen Tozer     LLVM_DEBUG(dbgs() << "processDbgValue on " << *DbgValue << "\n";);
18331d1de746SOCHyams     LLVM_DEBUG(dbgs() << "   LiveLoc " << locStr(getLocKind(LiveSet, Var))
18341d1de746SOCHyams                       << " -> Val, dbg.value override");
18351d1de746SOCHyams 
18361d1de746SOCHyams     setLocKind(LiveSet, Var, LocKind::Val);
183752665432SStephen Tozer     emitDbgValue(LocKind::Val, DbgValue, DbgValue);
183852665432SStephen Tozer   };
1839ffd08c77SStephen Tozer   if (isa<DbgVariableRecord *>(DbgValueRecord))
1840ffd08c77SStephen Tozer     return ProcessDbgValueImpl(cast<DbgVariableRecord *>(DbgValueRecord));
184152665432SStephen Tozer   return ProcessDbgValueImpl(cast<DbgValueInst *>(DbgValueRecord));
18421d1de746SOCHyams }
18431d1de746SOCHyams 
18446aeb7a71SStephen Tozer template <typename T> static bool hasZeroSizedFragment(T &DbgValue) {
18456aeb7a71SStephen Tozer   if (auto F = DbgValue.getExpression()->getFragmentInfo())
184693c194fcSOCHyams     return F->SizeInBits == 0;
184793c194fcSOCHyams   return false;
184893c194fcSOCHyams }
184993c194fcSOCHyams 
18501d1de746SOCHyams void AssignmentTrackingLowering::processDbgInstruction(
185193c194fcSOCHyams     DbgInfoIntrinsic &I, AssignmentTrackingLowering::BlockInfo *LiveSet) {
185293c194fcSOCHyams   auto *DVI = dyn_cast<DbgVariableIntrinsic>(&I);
185393c194fcSOCHyams   if (!DVI)
185493c194fcSOCHyams     return;
185593c194fcSOCHyams 
185693c194fcSOCHyams   // Ignore assignments to zero bits of the variable.
185793c194fcSOCHyams   if (hasZeroSizedFragment(*DVI))
185893c194fcSOCHyams     return;
185993c194fcSOCHyams 
18601d1de746SOCHyams   if (auto *DAI = dyn_cast<DbgAssignIntrinsic>(&I))
186152665432SStephen Tozer     processDbgAssign(DAI, LiveSet);
18621d1de746SOCHyams   else if (auto *DVI = dyn_cast<DbgValueInst>(&I))
186352665432SStephen Tozer     processDbgValue(DVI, LiveSet);
186452665432SStephen Tozer }
1865ffd08c77SStephen Tozer void AssignmentTrackingLowering::processDbgVariableRecord(
1866ffd08c77SStephen Tozer     DbgVariableRecord &DVR, AssignmentTrackingLowering::BlockInfo *LiveSet) {
186752665432SStephen Tozer   // Ignore assignments to zero bits of the variable.
1868ffd08c77SStephen Tozer   if (hasZeroSizedFragment(DVR))
186952665432SStephen Tozer     return;
187052665432SStephen Tozer 
1871ffd08c77SStephen Tozer   if (DVR.isDbgAssign())
1872ffd08c77SStephen Tozer     processDbgAssign(&DVR, LiveSet);
1873ffd08c77SStephen Tozer   else if (DVR.isDbgValue())
1874ffd08c77SStephen Tozer     processDbgValue(&DVR, LiveSet);
18751d1de746SOCHyams }
18761d1de746SOCHyams 
18771d1de746SOCHyams void AssignmentTrackingLowering::resetInsertionPoint(Instruction &After) {
18781d1de746SOCHyams   assert(!After.isTerminator() && "Can't insert after a terminator");
187952665432SStephen Tozer   auto *R = InsertBeforeMap.find(getNextNode(&After));
188052665432SStephen Tozer   if (R == InsertBeforeMap.end())
188152665432SStephen Tozer     return;
188252665432SStephen Tozer   R->second.clear();
188352665432SStephen Tozer }
1884ffd08c77SStephen Tozer void AssignmentTrackingLowering::resetInsertionPoint(DbgVariableRecord &After) {
188552665432SStephen Tozer   auto *R = InsertBeforeMap.find(getNextNode(&After));
18861d1de746SOCHyams   if (R == InsertBeforeMap.end())
18871d1de746SOCHyams     return;
18881d1de746SOCHyams   R->second.clear();
18891d1de746SOCHyams }
18901d1de746SOCHyams 
18911d1de746SOCHyams void AssignmentTrackingLowering::process(BasicBlock &BB, BlockInfo *LiveSet) {
1892360da838SStephen Tozer   // If the block starts with DbgRecords, we need to process those DbgRecords as
189352665432SStephen Tozer   // their own frame without processing any instructions first.
1894360da838SStephen Tozer   bool ProcessedLeadingDbgRecords = !BB.begin()->hasDbgRecords();
18951d1de746SOCHyams   for (auto II = BB.begin(), EI = BB.end(); II != EI;) {
18961d1de746SOCHyams     assert(VarsTouchedThisFrame.empty());
18971d1de746SOCHyams     // Process the instructions in "frames". A "frame" includes a single
18981d1de746SOCHyams     // non-debug instruction followed any debug instructions before the
18991d1de746SOCHyams     // next non-debug instruction.
190052665432SStephen Tozer 
1901360da838SStephen Tozer     // Skip the current instruction if it has unprocessed DbgRecords attached
1902360da838SStephen Tozer     // (see comment above `ProcessedLeadingDbgRecords`).
1903360da838SStephen Tozer     if (ProcessedLeadingDbgRecords) {
190452665432SStephen Tozer       // II is now either a debug intrinsic, a non-debug instruction with no
1905360da838SStephen Tozer       // attached DbgRecords, or a non-debug instruction with attached processed
1906360da838SStephen Tozer       // DbgRecords.
190752665432SStephen Tozer       // II has not been processed.
19081d1de746SOCHyams       if (!isa<DbgInfoIntrinsic>(&*II)) {
19091d1de746SOCHyams         if (II->isTerminator())
19101d1de746SOCHyams           break;
19111d1de746SOCHyams         resetInsertionPoint(*II);
19121d1de746SOCHyams         processNonDbgInstruction(*II, LiveSet);
19131d1de746SOCHyams         assert(LiveSet->isValid());
19141d1de746SOCHyams         ++II;
19151d1de746SOCHyams       }
191652665432SStephen Tozer     }
191752665432SStephen Tozer     // II is now either a debug intrinsic, a non-debug instruction with no
1918360da838SStephen Tozer     // attached DbgRecords, or a non-debug instruction with attached unprocessed
1919360da838SStephen Tozer     // DbgRecords.
192015f3f446SStephen Tozer     if (II != EI && II->hasDbgRecords()) {
19218a164220SOrlando Cazalet-Hyams       // Skip over non-variable debug records (i.e., labels). They're going to
19228a164220SOrlando Cazalet-Hyams       // be read from IR (possibly re-ordering them within the debug record
19238a164220SOrlando Cazalet-Hyams       // range) rather than from the analysis results.
1924ffd08c77SStephen Tozer       for (DbgVariableRecord &DVR : filterDbgVars(II->getDbgRecordRange())) {
1925ffd08c77SStephen Tozer         resetInsertionPoint(DVR);
1926ffd08c77SStephen Tozer         processDbgVariableRecord(DVR, LiveSet);
192752665432SStephen Tozer         assert(LiveSet->isValid());
192852665432SStephen Tozer       }
192952665432SStephen Tozer     }
1930360da838SStephen Tozer     ProcessedLeadingDbgRecords = true;
19311d1de746SOCHyams     while (II != EI) {
193293c194fcSOCHyams       auto *Dbg = dyn_cast<DbgInfoIntrinsic>(&*II);
193393c194fcSOCHyams       if (!Dbg)
19341d1de746SOCHyams         break;
19351d1de746SOCHyams       resetInsertionPoint(*II);
193693c194fcSOCHyams       processDbgInstruction(*Dbg, LiveSet);
19371d1de746SOCHyams       assert(LiveSet->isValid());
19381d1de746SOCHyams       ++II;
19391d1de746SOCHyams     }
1940360da838SStephen Tozer     // II is now a non-debug instruction either with no attached DbgRecords, or
1941360da838SStephen Tozer     // with attached processed DbgRecords. II has not been processed, and all
1942360da838SStephen Tozer     // debug instructions or DbgRecords in the frame preceding II have been
194352665432SStephen Tozer     // processed.
19441d1de746SOCHyams 
19451d1de746SOCHyams     // We've processed everything in the "frame". Now determine which variables
19461d1de746SOCHyams     // cannot be represented by a dbg.declare.
19471d1de746SOCHyams     for (auto Var : VarsTouchedThisFrame) {
19481d1de746SOCHyams       LocKind Loc = getLocKind(LiveSet, Var);
19491d1de746SOCHyams       // If a variable's LocKind is anything other than LocKind::Mem then we
19501d1de746SOCHyams       // must note that it cannot be represented with a dbg.declare.
19511d1de746SOCHyams       // Note that this check is enough without having to check the result of
19521d1de746SOCHyams       // joins() because for join to produce anything other than Mem after
19531d1de746SOCHyams       // we've already seen a Mem we'd be joining None or Val with Mem. In that
19541d1de746SOCHyams       // case, we've already hit this codepath when we set the LocKind to Val
19551d1de746SOCHyams       // or None in that block.
19561d1de746SOCHyams       if (Loc != LocKind::Mem) {
19571d1de746SOCHyams         DebugVariable DbgVar = FnVarLocs->getVariable(Var);
19581d1de746SOCHyams         DebugAggregate Aggr{DbgVar.getVariable(), DbgVar.getInlinedAt()};
19591d1de746SOCHyams         NotAlwaysStackHomed.insert(Aggr);
19601d1de746SOCHyams       }
19611d1de746SOCHyams     }
19621d1de746SOCHyams     VarsTouchedThisFrame.clear();
19631d1de746SOCHyams   }
19641d1de746SOCHyams }
19651d1de746SOCHyams 
19661d1de746SOCHyams AssignmentTrackingLowering::LocKind
19671d1de746SOCHyams AssignmentTrackingLowering::joinKind(LocKind A, LocKind B) {
19681d1de746SOCHyams   // Partial order:
19691d1de746SOCHyams   // None > Mem, Val
19701d1de746SOCHyams   return A == B ? A : LocKind::None;
19711d1de746SOCHyams }
19721d1de746SOCHyams 
19731d1de746SOCHyams AssignmentTrackingLowering::Assignment
19741d1de746SOCHyams AssignmentTrackingLowering::joinAssignment(const Assignment &A,
19751d1de746SOCHyams                                            const Assignment &B) {
19761d1de746SOCHyams   // Partial order:
19771d1de746SOCHyams   // NoneOrPhi(null, null) > Known(v, ?s)
19781d1de746SOCHyams 
19791d1de746SOCHyams   // If either are NoneOrPhi the join is NoneOrPhi.
19801d1de746SOCHyams   // If either value is different then the result is
19811d1de746SOCHyams   // NoneOrPhi (joining two values is a Phi).
19821d1de746SOCHyams   if (!A.isSameSourceAssignment(B))
19831d1de746SOCHyams     return Assignment::makeNoneOrPhi();
19841d1de746SOCHyams   if (A.Status == Assignment::NoneOrPhi)
19851d1de746SOCHyams     return Assignment::makeNoneOrPhi();
19861d1de746SOCHyams 
19871d1de746SOCHyams   // Source is used to lookup the value + expression in the debug program if
19881d1de746SOCHyams   // the stack slot gets assigned a value earlier than expected. Because
19891d1de746SOCHyams   // we're only tracking the one dbg.assign, we can't capture debug PHIs.
19901d1de746SOCHyams   // It's unlikely that we're losing out on much coverage by avoiding that
19911d1de746SOCHyams   // extra work.
19921d1de746SOCHyams   // The Source may differ in this situation:
19931d1de746SOCHyams   // Pred.1:
19941d1de746SOCHyams   //   dbg.assign i32 0, ..., !1, ...
19951d1de746SOCHyams   // Pred.2:
19961d1de746SOCHyams   //   dbg.assign i32 1, ..., !1, ...
19971d1de746SOCHyams   // Here the same assignment (!1) was performed in both preds in the source,
19981d1de746SOCHyams   // but we can't use either one unless they are identical (e.g. .we don't
19991d1de746SOCHyams   // want to arbitrarily pick between constant values).
200052665432SStephen Tozer   auto JoinSource = [&]() -> AssignRecord {
20011d1de746SOCHyams     if (A.Source == B.Source)
20021d1de746SOCHyams       return A.Source;
200352665432SStephen Tozer     if (!A.Source || !B.Source)
200452665432SStephen Tozer       return AssignRecord();
2005ffd08c77SStephen Tozer     assert(isa<DbgVariableRecord *>(A.Source) ==
2006ffd08c77SStephen Tozer            isa<DbgVariableRecord *>(B.Source));
2007ffd08c77SStephen Tozer     if (isa<DbgVariableRecord *>(A.Source) &&
2008ffd08c77SStephen Tozer         cast<DbgVariableRecord *>(A.Source)->isEquivalentTo(
2009ffd08c77SStephen Tozer             *cast<DbgVariableRecord *>(B.Source)))
20101d1de746SOCHyams       return A.Source;
201152665432SStephen Tozer     if (isa<DbgAssignIntrinsic *>(A.Source) &&
201252665432SStephen Tozer         cast<DbgAssignIntrinsic *>(A.Source)->isIdenticalTo(
201352665432SStephen Tozer             cast<DbgAssignIntrinsic *>(B.Source)))
201452665432SStephen Tozer       return A.Source;
201552665432SStephen Tozer     return AssignRecord();
20161d1de746SOCHyams   };
201752665432SStephen Tozer   AssignRecord Source = JoinSource();
20181d1de746SOCHyams   assert(A.Status == B.Status && A.Status == Assignment::Known);
20191d1de746SOCHyams   assert(A.ID == B.ID);
20201d1de746SOCHyams   return Assignment::make(A.ID, Source);
20211d1de746SOCHyams }
20221d1de746SOCHyams 
20231d1de746SOCHyams AssignmentTrackingLowering::BlockInfo
20241d1de746SOCHyams AssignmentTrackingLowering::joinBlockInfo(const BlockInfo &A,
20251d1de746SOCHyams                                           const BlockInfo &B) {
2026d5b2c8e5SOCHyams   return BlockInfo::join(A, B, TrackedVariablesVectorSize);
20271d1de746SOCHyams }
20281d1de746SOCHyams 
20291d1de746SOCHyams bool AssignmentTrackingLowering::join(
20301d1de746SOCHyams     const BasicBlock &BB, const SmallPtrSet<BasicBlock *, 16> &Visited) {
2031c4861e32SOCHyams 
2032c4861e32SOCHyams   SmallVector<const BasicBlock *> VisitedPreds;
20331d1de746SOCHyams   // Ignore backedges if we have not visited the predecessor yet. As the
20341d1de746SOCHyams   // predecessor hasn't yet had locations propagated into it, most locations
20351d1de746SOCHyams   // will not yet be valid, so treat them as all being uninitialized and
20361d1de746SOCHyams   // potentially valid. If a location guessed to be correct here is
20371d1de746SOCHyams   // invalidated later, we will remove it when we revisit this block. This
20381d1de746SOCHyams   // is essentially the same as initialising all LocKinds and Assignments to
20391d1de746SOCHyams   // an implicit ⊥ value which is the identity value for the join operation.
204071ca5c54SKazu Hirata   for (const BasicBlock *Pred : predecessors(&BB)) {
2041c4861e32SOCHyams     if (Visited.count(Pred))
2042c4861e32SOCHyams       VisitedPreds.push_back(Pred);
20431d1de746SOCHyams   }
20441d1de746SOCHyams 
2045c4861e32SOCHyams   // No preds visited yet.
2046c4861e32SOCHyams   if (VisitedPreds.empty()) {
2047c4861e32SOCHyams     auto It = LiveIn.try_emplace(&BB, BlockInfo());
2048c4861e32SOCHyams     bool DidInsert = It.second;
2049c4861e32SOCHyams     if (DidInsert)
2050c4861e32SOCHyams       It.first->second.init(TrackedVariablesVectorSize);
2051c4861e32SOCHyams     return /*Changed*/ DidInsert;
2052c4861e32SOCHyams   }
2053d5b2c8e5SOCHyams 
2054c4861e32SOCHyams   // Exactly one visited pred. Copy the LiveOut from that pred into BB LiveIn.
2055c4861e32SOCHyams   if (VisitedPreds.size() == 1) {
2056c4861e32SOCHyams     const BlockInfo &PredLiveOut = LiveOut.find(VisitedPreds[0])->second;
2057c4861e32SOCHyams     auto CurrentLiveInEntry = LiveIn.find(&BB);
2058c4861e32SOCHyams 
2059c4861e32SOCHyams     // Check if there isn't an entry, or there is but the LiveIn set has
2060c4861e32SOCHyams     // changed (expensive check).
2061c4861e32SOCHyams     if (CurrentLiveInEntry == LiveIn.end())
2062c4861e32SOCHyams       LiveIn.insert(std::make_pair(&BB, PredLiveOut));
2063c4861e32SOCHyams     else if (PredLiveOut != CurrentLiveInEntry->second)
2064c4861e32SOCHyams       CurrentLiveInEntry->second = PredLiveOut;
2065c4861e32SOCHyams     else
2066c4861e32SOCHyams       return /*Changed*/ false;
2067c4861e32SOCHyams     return /*Changed*/ true;
2068c4861e32SOCHyams   }
2069c4861e32SOCHyams 
2070c4861e32SOCHyams   // More than one pred. Join LiveOuts of blocks 1 and 2.
2071c4861e32SOCHyams   assert(VisitedPreds.size() > 1);
2072c4861e32SOCHyams   const BlockInfo &PredLiveOut0 = LiveOut.find(VisitedPreds[0])->second;
2073c4861e32SOCHyams   const BlockInfo &PredLiveOut1 = LiveOut.find(VisitedPreds[1])->second;
2074c4861e32SOCHyams   BlockInfo BBLiveIn = joinBlockInfo(PredLiveOut0, PredLiveOut1);
2075c4861e32SOCHyams 
2076c4861e32SOCHyams   // Join the LiveOuts of subsequent blocks.
2077c4861e32SOCHyams   ArrayRef Tail = ArrayRef(VisitedPreds).drop_front(2);
2078c4861e32SOCHyams   for (const BasicBlock *Pred : Tail) {
2079c4861e32SOCHyams     const auto &PredLiveOut = LiveOut.find(Pred);
2080c4861e32SOCHyams     assert(PredLiveOut != LiveOut.end() &&
2081c4861e32SOCHyams            "block should have been processed already");
2082c4861e32SOCHyams     BBLiveIn = joinBlockInfo(std::move(BBLiveIn), PredLiveOut->second);
2083c4861e32SOCHyams   }
2084c4861e32SOCHyams 
2085c4861e32SOCHyams   // Save the joined result for BB.
20861d1de746SOCHyams   auto CurrentLiveInEntry = LiveIn.find(&BB);
20871d1de746SOCHyams   // Check if there isn't an entry, or there is but the LiveIn set has changed
20881d1de746SOCHyams   // (expensive check).
2089c4861e32SOCHyams   if (CurrentLiveInEntry == LiveIn.end())
2090c4861e32SOCHyams     LiveIn.try_emplace(&BB, std::move(BBLiveIn));
2091c4861e32SOCHyams   else if (BBLiveIn != CurrentLiveInEntry->second)
2092c4861e32SOCHyams     CurrentLiveInEntry->second = std::move(BBLiveIn);
2093c4861e32SOCHyams   else
2094c4861e32SOCHyams     return /*Changed*/ false;
2095c4861e32SOCHyams   return /*Changed*/ true;
20961d1de746SOCHyams }
20971d1de746SOCHyams 
20981d1de746SOCHyams /// Return true if A fully contains B.
20991d1de746SOCHyams static bool fullyContains(DIExpression::FragmentInfo A,
21001d1de746SOCHyams                           DIExpression::FragmentInfo B) {
21011d1de746SOCHyams   auto ALeft = A.OffsetInBits;
21021d1de746SOCHyams   auto BLeft = B.OffsetInBits;
21031d1de746SOCHyams   if (BLeft < ALeft)
21041d1de746SOCHyams     return false;
21051d1de746SOCHyams 
21061d1de746SOCHyams   auto ARight = ALeft + A.SizeInBits;
21071d1de746SOCHyams   auto BRight = BLeft + B.SizeInBits;
21081d1de746SOCHyams   if (BRight > ARight)
21091d1de746SOCHyams     return false;
21101d1de746SOCHyams   return true;
21111d1de746SOCHyams }
21121d1de746SOCHyams 
21131d1de746SOCHyams static std::optional<at::AssignmentInfo>
21141d1de746SOCHyams getUntaggedStoreAssignmentInfo(const Instruction &I, const DataLayout &Layout) {
21151d1de746SOCHyams   // Don't bother checking if this is an AllocaInst. We know this
21161d1de746SOCHyams   // instruction has no tag which means there are no variables associated
21171d1de746SOCHyams   // with it.
21181d1de746SOCHyams   if (const auto *SI = dyn_cast<StoreInst>(&I))
21191d1de746SOCHyams     return at::getAssignmentInfo(Layout, SI);
21201d1de746SOCHyams   if (const auto *MI = dyn_cast<MemIntrinsic>(&I))
21211d1de746SOCHyams     return at::getAssignmentInfo(Layout, MI);
21221d1de746SOCHyams   // Alloca or non-store-like inst.
21231d1de746SOCHyams   return std::nullopt;
21241d1de746SOCHyams }
21251d1de746SOCHyams 
212652665432SStephen Tozer DbgDeclareInst *DynCastToDbgDeclare(DbgVariableIntrinsic *DVI) {
212752665432SStephen Tozer   return dyn_cast<DbgDeclareInst>(DVI);
212852665432SStephen Tozer }
212952665432SStephen Tozer 
2130ffd08c77SStephen Tozer DbgVariableRecord *DynCastToDbgDeclare(DbgVariableRecord *DVR) {
2131ffd08c77SStephen Tozer   return DVR->isDbgDeclare() ? DVR : nullptr;
213252665432SStephen Tozer }
213352665432SStephen Tozer 
21341d1de746SOCHyams /// Build a map of {Variable x: Variables y} where all variable fragments
21351d1de746SOCHyams /// contained within the variable fragment x are in set y. This means that
21361d1de746SOCHyams /// y does not contain all overlaps because partial overlaps are excluded.
21371d1de746SOCHyams ///
21381d1de746SOCHyams /// While we're iterating over the function, add single location defs for
2139d5b2c8e5SOCHyams /// dbg.declares to \p FnVarLocs.
2140d5b2c8e5SOCHyams ///
2141d5b2c8e5SOCHyams /// Variables that are interesting to this pass in are added to
2142d5b2c8e5SOCHyams /// FnVarLocs->Variables first. TrackedVariablesVectorSize is set to the ID of
2143d5b2c8e5SOCHyams /// the last interesting variable plus 1, meaning variables with ID 1
2144d5b2c8e5SOCHyams /// (inclusive) to TrackedVariablesVectorSize (exclusive) are interesting. The
2145d5b2c8e5SOCHyams /// subsequent variables are either stack homed or fully promoted.
21461d1de746SOCHyams ///
21471d1de746SOCHyams /// Finally, populate UntaggedStoreVars with a mapping of untagged stores to
21481d1de746SOCHyams /// the stored-to variable fragments.
21491d1de746SOCHyams ///
21501d1de746SOCHyams /// These tasks are bundled together to reduce the number of times we need
21511d1de746SOCHyams /// to iterate over the function as they can be achieved together in one pass.
21521d1de746SOCHyams static AssignmentTrackingLowering::OverlapMap buildOverlapMapAndRecordDeclares(
21531d1de746SOCHyams     Function &Fn, FunctionVarLocsBuilder *FnVarLocs,
2154cbfeec66SOCHyams     const DenseSet<DebugAggregate> &VarsWithStackSlot,
2155d5b2c8e5SOCHyams     AssignmentTrackingLowering::UntaggedStoreAssignmentMap &UntaggedStoreVars,
2156d5b2c8e5SOCHyams     unsigned &TrackedVariablesVectorSize) {
21571d1de746SOCHyams   DenseSet<DebugVariable> Seen;
21581d1de746SOCHyams   // Map of Variable: [Fragments].
21591d1de746SOCHyams   DenseMap<DebugAggregate, SmallVector<DebugVariable, 8>> FragmentMap;
21601d1de746SOCHyams   // Iterate over all instructions:
21611d1de746SOCHyams   // - dbg.declare    -> add single location variable record
21621d1de746SOCHyams   // - dbg.*          -> Add fragments to FragmentMap
21631d1de746SOCHyams   // - untagged store -> Add fragments to FragmentMap and update
21641d1de746SOCHyams   //                     UntaggedStoreVars.
21651d1de746SOCHyams   // We need to add fragments for untagged stores too so that we can correctly
21661d1de746SOCHyams   // clobber overlapped fragment locations later.
216752665432SStephen Tozer   SmallVector<DbgDeclareInst *> InstDeclares;
2168ffd08c77SStephen Tozer   SmallVector<DbgVariableRecord *> DPDeclares;
216952665432SStephen Tozer   auto ProcessDbgRecord = [&](auto *Record, auto &DeclareList) {
217052665432SStephen Tozer     if (auto *Declare = DynCastToDbgDeclare(Record)) {
217152665432SStephen Tozer       DeclareList.push_back(Declare);
217252665432SStephen Tozer       return;
217352665432SStephen Tozer     }
217452665432SStephen Tozer     DebugVariable DV = DebugVariable(Record);
21751d1de746SOCHyams     DebugAggregate DA = {DV.getVariable(), DV.getInlinedAt()};
2176cbfeec66SOCHyams     if (!VarsWithStackSlot.contains(DA))
217752665432SStephen Tozer       return;
21781d1de746SOCHyams     if (Seen.insert(DV).second)
21791d1de746SOCHyams       FragmentMap[DA].push_back(DV);
218052665432SStephen Tozer   };
218152665432SStephen Tozer   for (auto &BB : Fn) {
218252665432SStephen Tozer     for (auto &I : BB) {
2183ffd08c77SStephen Tozer       for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange()))
2184ffd08c77SStephen Tozer         ProcessDbgRecord(&DVR, DPDeclares);
218552665432SStephen Tozer       if (auto *DII = dyn_cast<DbgVariableIntrinsic>(&I)) {
218652665432SStephen Tozer         ProcessDbgRecord(DII, InstDeclares);
21871d1de746SOCHyams       } else if (auto Info = getUntaggedStoreAssignmentInfo(
21889df71d76SNikita Popov                      I, Fn.getDataLayout())) {
21891d1de746SOCHyams         // Find markers linked to this alloca.
219052665432SStephen Tozer         auto HandleDbgAssignForStore = [&](auto *Assign) {
21917afc7db7SOrlando Cazalet-Hyams           std::optional<DIExpression::FragmentInfo> FragInfo;
21927afc7db7SOrlando Cazalet-Hyams 
21937afc7db7SOrlando Cazalet-Hyams           // Skip this assignment if the affected bits are outside of the
21947afc7db7SOrlando Cazalet-Hyams           // variable fragment.
21957afc7db7SOrlando Cazalet-Hyams           if (!at::calculateFragmentIntersect(
21962d209d96SNikita Popov                   I.getDataLayout(), Info->Base,
219752665432SStephen Tozer                   Info->OffsetInBits, Info->SizeInBits, Assign, FragInfo) ||
21987afc7db7SOrlando Cazalet-Hyams               (FragInfo && FragInfo->SizeInBits == 0))
219952665432SStephen Tozer             return;
22007afc7db7SOrlando Cazalet-Hyams 
22017afc7db7SOrlando Cazalet-Hyams           // FragInfo from calculateFragmentIntersect is nullopt if the
22027afc7db7SOrlando Cazalet-Hyams           // resultant fragment matches DAI's fragment or entire variable - in
22037afc7db7SOrlando Cazalet-Hyams           // which case copy the fragment info from DAI. If FragInfo is still
22047afc7db7SOrlando Cazalet-Hyams           // nullopt after the copy it means "no fragment info" instead, which
22057afc7db7SOrlando Cazalet-Hyams           // is how it is usually interpreted.
22067afc7db7SOrlando Cazalet-Hyams           if (!FragInfo)
220752665432SStephen Tozer             FragInfo = Assign->getExpression()->getFragmentInfo();
22081d1de746SOCHyams 
220952665432SStephen Tozer           DebugVariable DV =
221052665432SStephen Tozer               DebugVariable(Assign->getVariable(), FragInfo,
221152665432SStephen Tozer                             Assign->getDebugLoc().getInlinedAt());
22121d1de746SOCHyams           DebugAggregate DA = {DV.getVariable(), DV.getInlinedAt()};
2213cbfeec66SOCHyams           if (!VarsWithStackSlot.contains(DA))
221452665432SStephen Tozer             return;
22151d1de746SOCHyams 
22161d1de746SOCHyams           // Cache this info for later.
22171d1de746SOCHyams           UntaggedStoreVars[&I].push_back(
22181d1de746SOCHyams               {FnVarLocs->insertVariable(DV), *Info});
22191d1de746SOCHyams 
22201d1de746SOCHyams           if (Seen.insert(DV).second)
22211d1de746SOCHyams             FragmentMap[DA].push_back(DV);
222252665432SStephen Tozer         };
222352665432SStephen Tozer         for (DbgAssignIntrinsic *DAI : at::getAssignmentMarkers(Info->Base))
222452665432SStephen Tozer           HandleDbgAssignForStore(DAI);
2225ffd08c77SStephen Tozer         for (DbgVariableRecord *DVR : at::getDVRAssignmentMarkers(Info->Base))
2226ffd08c77SStephen Tozer           HandleDbgAssignForStore(DVR);
22271d1de746SOCHyams       }
22281d1de746SOCHyams     }
22291d1de746SOCHyams   }
22301d1de746SOCHyams 
2231b59d672eSOCHyams   // Sort the fragment map for each DebugAggregate in ascending
2232b59d672eSOCHyams   // order of fragment size - there should be no duplicates.
22331d1de746SOCHyams   for (auto &Pair : FragmentMap) {
22341d1de746SOCHyams     SmallVector<DebugVariable, 8> &Frags = Pair.second;
2235fef144ceSKazu Hirata     std::sort(Frags.begin(), Frags.end(),
2236fef144ceSKazu Hirata               [](const DebugVariable &Next, const DebugVariable &Elmt) {
22371d1de746SOCHyams                 return Elmt.getFragmentOrDefault().SizeInBits >
22381d1de746SOCHyams                        Next.getFragmentOrDefault().SizeInBits;
22391d1de746SOCHyams               });
2240b59d672eSOCHyams     // Check for duplicates.
2241b59d672eSOCHyams     assert(std::adjacent_find(Frags.begin(), Frags.end()) == Frags.end());
22421d1de746SOCHyams   }
22431d1de746SOCHyams 
22441d1de746SOCHyams   // Build the map.
22451d1de746SOCHyams   AssignmentTrackingLowering::OverlapMap Map;
224666268c8eSWang, Xin10   for (auto &Pair : FragmentMap) {
22471d1de746SOCHyams     auto &Frags = Pair.second;
22481d1de746SOCHyams     for (auto It = Frags.begin(), IEnd = Frags.end(); It != IEnd; ++It) {
22491d1de746SOCHyams       DIExpression::FragmentInfo Frag = It->getFragmentOrDefault();
22501d1de746SOCHyams       // Find the frags that this is contained within.
22511d1de746SOCHyams       //
22521d1de746SOCHyams       // Because Frags is sorted by size and none have the same offset and
22531d1de746SOCHyams       // size, we know that this frag can only be contained by subsequent
22541d1de746SOCHyams       // elements.
22551d1de746SOCHyams       SmallVector<DebugVariable, 8>::iterator OtherIt = It;
22561d1de746SOCHyams       ++OtherIt;
22571d1de746SOCHyams       VariableID ThisVar = FnVarLocs->insertVariable(*It);
22581d1de746SOCHyams       for (; OtherIt != IEnd; ++OtherIt) {
22591d1de746SOCHyams         DIExpression::FragmentInfo OtherFrag = OtherIt->getFragmentOrDefault();
22601d1de746SOCHyams         VariableID OtherVar = FnVarLocs->insertVariable(*OtherIt);
22611d1de746SOCHyams         if (fullyContains(OtherFrag, Frag))
22621d1de746SOCHyams           Map[OtherVar].push_back(ThisVar);
22631d1de746SOCHyams       }
22641d1de746SOCHyams     }
22651d1de746SOCHyams   }
22661d1de746SOCHyams 
2267d5b2c8e5SOCHyams   // VariableIDs are 1-based so the variable-tracking bitvector needs
2268d5b2c8e5SOCHyams   // NumVariables plus 1 bits.
2269d5b2c8e5SOCHyams   TrackedVariablesVectorSize = FnVarLocs->getNumVariables() + 1;
2270d5b2c8e5SOCHyams 
2271d5b2c8e5SOCHyams   // Finally, insert the declares afterwards, so the first IDs are all
2272d5b2c8e5SOCHyams   // partially stack homed vars.
227352665432SStephen Tozer   for (auto *DDI : InstDeclares)
2274d5b2c8e5SOCHyams     FnVarLocs->addSingleLocVar(DebugVariable(DDI), DDI->getExpression(),
2275d5b2c8e5SOCHyams                                DDI->getDebugLoc(), DDI->getWrappedLocation());
2276ffd08c77SStephen Tozer   for (auto *DVR : DPDeclares)
2277ffd08c77SStephen Tozer     FnVarLocs->addSingleLocVar(DebugVariable(DVR), DVR->getExpression(),
2278ffd08c77SStephen Tozer                                DVR->getDebugLoc(),
2279ffd08c77SStephen Tozer                                RawLocationWrapper(DVR->getRawLocation()));
22801d1de746SOCHyams   return Map;
22811d1de746SOCHyams }
22821d1de746SOCHyams 
22831d1de746SOCHyams bool AssignmentTrackingLowering::run(FunctionVarLocsBuilder *FnVarLocsBuilder) {
22841d1de746SOCHyams   if (Fn.size() > MaxNumBlocks) {
22851d1de746SOCHyams     LLVM_DEBUG(dbgs() << "[AT] Dropping var locs in: " << Fn.getName()
22861d1de746SOCHyams                       << ": too many blocks (" << Fn.size() << ")\n");
22871d1de746SOCHyams     at::deleteAll(&Fn);
22881d1de746SOCHyams     return false;
22891d1de746SOCHyams   }
22901d1de746SOCHyams 
22911d1de746SOCHyams   FnVarLocs = FnVarLocsBuilder;
22921d1de746SOCHyams 
22931d1de746SOCHyams   // The general structure here is inspired by VarLocBasedImpl.cpp
22941d1de746SOCHyams   // (LiveDebugValues).
22951d1de746SOCHyams 
22961d1de746SOCHyams   // Build the variable fragment overlap map.
22971d1de746SOCHyams   // Note that this pass doesn't handle partial overlaps correctly (FWIW
22981d1de746SOCHyams   // neither does LiveDebugVariables) because that is difficult to do and
22991d1de746SOCHyams   // appears to be rare occurance.
2300d5b2c8e5SOCHyams   VarContains = buildOverlapMapAndRecordDeclares(
2301cbfeec66SOCHyams       Fn, FnVarLocs, *VarsWithStackSlot, UntaggedStoreVars,
2302cbfeec66SOCHyams       TrackedVariablesVectorSize);
23031d1de746SOCHyams 
23041d1de746SOCHyams   // Prepare for traversal.
23051d1de746SOCHyams   ReversePostOrderTraversal<Function *> RPOT(&Fn);
23061d1de746SOCHyams   std::priority_queue<unsigned int, std::vector<unsigned int>,
23071d1de746SOCHyams                       std::greater<unsigned int>>
23081d1de746SOCHyams       Worklist;
23091d1de746SOCHyams   std::priority_queue<unsigned int, std::vector<unsigned int>,
23101d1de746SOCHyams                       std::greater<unsigned int>>
23111d1de746SOCHyams       Pending;
23121d1de746SOCHyams   DenseMap<unsigned int, BasicBlock *> OrderToBB;
23131d1de746SOCHyams   DenseMap<BasicBlock *, unsigned int> BBToOrder;
23141d1de746SOCHyams   { // Init OrderToBB and BBToOrder.
23151d1de746SOCHyams     unsigned int RPONumber = 0;
2316dae061f1SKazu Hirata     for (BasicBlock *BB : RPOT) {
2317dae061f1SKazu Hirata       OrderToBB[RPONumber] = BB;
2318dae061f1SKazu Hirata       BBToOrder[BB] = RPONumber;
23191d1de746SOCHyams       Worklist.push(RPONumber);
23201d1de746SOCHyams       ++RPONumber;
23211d1de746SOCHyams     }
23221d1de746SOCHyams     LiveIn.init(RPONumber);
23231d1de746SOCHyams     LiveOut.init(RPONumber);
23241d1de746SOCHyams   }
23251d1de746SOCHyams 
23261d1de746SOCHyams   // Perform the traversal.
23271d1de746SOCHyams   //
23281d1de746SOCHyams   // This is a standard "union of predecessor outs" dataflow problem. To solve
23291d1de746SOCHyams   // it, we perform join() and process() using the two worklist method until
23301d1de746SOCHyams   // the LiveIn data for each block becomes unchanging. The "proof" that this
23311d1de746SOCHyams   // terminates can be put together by looking at the comments around LocKind,
23321d1de746SOCHyams   // Assignment, and the various join methods, which show that all the elements
23331d1de746SOCHyams   // involved are made up of join-semilattices; LiveIn(n) can only
23341d1de746SOCHyams   // monotonically increase in value throughout the dataflow.
23351d1de746SOCHyams   //
23361d1de746SOCHyams   SmallPtrSet<BasicBlock *, 16> Visited;
23371d1de746SOCHyams   while (!Worklist.empty()) {
23381d1de746SOCHyams     // We track what is on the pending worklist to avoid inserting the same
23391d1de746SOCHyams     // thing twice.
23401d1de746SOCHyams     SmallPtrSet<BasicBlock *, 16> OnPending;
23411d1de746SOCHyams     LLVM_DEBUG(dbgs() << "Processing Worklist\n");
23421d1de746SOCHyams     while (!Worklist.empty()) {
23431d1de746SOCHyams       BasicBlock *BB = OrderToBB[Worklist.top()];
23441d1de746SOCHyams       LLVM_DEBUG(dbgs() << "\nPop BB " << BB->getName() << "\n");
23451d1de746SOCHyams       Worklist.pop();
23461d1de746SOCHyams       bool InChanged = join(*BB, Visited);
23471d1de746SOCHyams       // Always consider LiveIn changed on the first visit.
23481d1de746SOCHyams       InChanged |= Visited.insert(BB).second;
23491d1de746SOCHyams       if (InChanged) {
23501d1de746SOCHyams         LLVM_DEBUG(dbgs() << BB->getName() << " has new InLocs, process it\n");
23511d1de746SOCHyams         // Mutate a copy of LiveIn while processing BB. After calling process
23521d1de746SOCHyams         // LiveSet is the LiveOut set for BB.
23531d1de746SOCHyams         BlockInfo LiveSet = LiveIn[BB];
23541d1de746SOCHyams 
23551d1de746SOCHyams         // Process the instructions in the block.
23561d1de746SOCHyams         process(*BB, &LiveSet);
23571d1de746SOCHyams 
23581d1de746SOCHyams         // Relatively expensive check: has anything changed in LiveOut for BB?
23591d1de746SOCHyams         if (LiveOut[BB] != LiveSet) {
23601d1de746SOCHyams           LLVM_DEBUG(dbgs() << BB->getName()
23611d1de746SOCHyams                             << " has new OutLocs, add succs to worklist: [ ");
23621d1de746SOCHyams           LiveOut[BB] = std::move(LiveSet);
23633641efcfSKazu Hirata           for (BasicBlock *Succ : successors(BB)) {
23643641efcfSKazu Hirata             if (OnPending.insert(Succ).second) {
23653641efcfSKazu Hirata               LLVM_DEBUG(dbgs() << Succ->getName() << " ");
23663641efcfSKazu Hirata               Pending.push(BBToOrder[Succ]);
23671d1de746SOCHyams             }
23681d1de746SOCHyams           }
23691d1de746SOCHyams           LLVM_DEBUG(dbgs() << "]\n");
23701d1de746SOCHyams         }
23711d1de746SOCHyams       }
23721d1de746SOCHyams     }
23731d1de746SOCHyams     Worklist.swap(Pending);
23741d1de746SOCHyams     // At this point, pending must be empty, since it was just the empty
23751d1de746SOCHyams     // worklist
23761d1de746SOCHyams     assert(Pending.empty() && "Pending should be empty");
23771d1de746SOCHyams   }
23781d1de746SOCHyams 
23791d1de746SOCHyams   // That's the hard part over. Now we just have some admin to do.
23801d1de746SOCHyams 
23811d1de746SOCHyams   // Record whether we inserted any intrinsics.
23821d1de746SOCHyams   bool InsertedAnyIntrinsics = false;
23831d1de746SOCHyams 
23841d1de746SOCHyams   // Identify and add defs for single location variables.
23851d1de746SOCHyams   //
23861d1de746SOCHyams   // Go through all of the defs that we plan to add. If the aggregate variable
23871d1de746SOCHyams   // it's a part of is not in the NotAlwaysStackHomed set we can emit a single
23881d1de746SOCHyams   // location def and omit the rest. Add an entry to AlwaysStackHomed so that
23891d1de746SOCHyams   // we can identify those uneeded defs later.
23901d1de746SOCHyams   DenseSet<DebugAggregate> AlwaysStackHomed;
23911d1de746SOCHyams   for (const auto &Pair : InsertBeforeMap) {
239252665432SStephen Tozer     auto &Vec = Pair.second;
23931d1de746SOCHyams     for (VarLocInfo VarLoc : Vec) {
23941d1de746SOCHyams       DebugVariable Var = FnVarLocs->getVariable(VarLoc.VariableID);
23951d1de746SOCHyams       DebugAggregate Aggr{Var.getVariable(), Var.getInlinedAt()};
23961d1de746SOCHyams 
23971d1de746SOCHyams       // Skip this Var if it's not always stack homed.
23981d1de746SOCHyams       if (NotAlwaysStackHomed.contains(Aggr))
23991d1de746SOCHyams         continue;
24001d1de746SOCHyams 
24011d1de746SOCHyams       // Skip complex cases such as when different fragments of a variable have
24021d1de746SOCHyams       // been split into different allocas. Skipping in this case means falling
24031d1de746SOCHyams       // back to using a list of defs (which could reduce coverage, but is no
24041d1de746SOCHyams       // less correct).
24051d1de746SOCHyams       bool Simple =
24061d1de746SOCHyams           VarLoc.Expr->getNumElements() == 1 && VarLoc.Expr->startsWithDeref();
24071d1de746SOCHyams       if (!Simple) {
24081d1de746SOCHyams         NotAlwaysStackHomed.insert(Aggr);
24091d1de746SOCHyams         continue;
24101d1de746SOCHyams       }
24111d1de746SOCHyams 
24121d1de746SOCHyams       // All source assignments to this variable remain and all stores to any
24131d1de746SOCHyams       // part of the variable store to the same address (with varying
24141d1de746SOCHyams       // offsets). We can just emit a single location for the whole variable.
24151d1de746SOCHyams       //
24161d1de746SOCHyams       // Unless we've already done so, create the single location def now.
24171d1de746SOCHyams       if (AlwaysStackHomed.insert(Aggr).second) {
2418ac6e177cSOCHyams         assert(!VarLoc.Values.hasArgList());
24191d1de746SOCHyams         // TODO: When more complex cases are handled VarLoc.Expr should be
24201d1de746SOCHyams         // built appropriately rather than always using an empty DIExpression.
24211d1de746SOCHyams         // The assert below is a reminder.
24221d1de746SOCHyams         assert(Simple);
2423e03f4271SJay Foad         VarLoc.Expr = DIExpression::get(Fn.getContext(), {});
24241d1de746SOCHyams         DebugVariable Var = FnVarLocs->getVariable(VarLoc.VariableID);
24257d894374SOCHyams         FnVarLocs->addSingleLocVar(Var, VarLoc.Expr, VarLoc.DL, VarLoc.Values);
24261d1de746SOCHyams         InsertedAnyIntrinsics = true;
24271d1de746SOCHyams       }
24281d1de746SOCHyams     }
24291d1de746SOCHyams   }
24301d1de746SOCHyams 
24311d1de746SOCHyams   // Insert the other DEFs.
24321d1de746SOCHyams   for (const auto &[InsertBefore, Vec] : InsertBeforeMap) {
24331d1de746SOCHyams     SmallVector<VarLocInfo> NewDefs;
24341d1de746SOCHyams     for (const VarLocInfo &VarLoc : Vec) {
24351d1de746SOCHyams       DebugVariable Var = FnVarLocs->getVariable(VarLoc.VariableID);
24361d1de746SOCHyams       DebugAggregate Aggr{Var.getVariable(), Var.getInlinedAt()};
24371d1de746SOCHyams       // If this variable is always stack homed then we have already inserted a
24381d1de746SOCHyams       // dbg.declare and deleted this dbg.value.
24391d1de746SOCHyams       if (AlwaysStackHomed.contains(Aggr))
24401d1de746SOCHyams         continue;
24411d1de746SOCHyams       NewDefs.push_back(VarLoc);
24421d1de746SOCHyams       InsertedAnyIntrinsics = true;
24431d1de746SOCHyams     }
24441d1de746SOCHyams 
24451d1de746SOCHyams     FnVarLocs->setWedge(InsertBefore, std::move(NewDefs));
24461d1de746SOCHyams   }
24471d1de746SOCHyams 
24481d1de746SOCHyams   InsertedAnyIntrinsics |= emitPromotedVarLocs(FnVarLocs);
24491d1de746SOCHyams 
24501d1de746SOCHyams   return InsertedAnyIntrinsics;
24511d1de746SOCHyams }
24521d1de746SOCHyams 
24531d1de746SOCHyams bool AssignmentTrackingLowering::emitPromotedVarLocs(
24541d1de746SOCHyams     FunctionVarLocsBuilder *FnVarLocs) {
24551d1de746SOCHyams   bool InsertedAnyIntrinsics = false;
24561d1de746SOCHyams   // Go through every block, translating debug intrinsics for fully promoted
24571d1de746SOCHyams   // variables into FnVarLocs location defs. No analysis required for these.
245852665432SStephen Tozer   auto TranslateDbgRecord = [&](auto *Record) {
245952665432SStephen Tozer     // Skip variables that haven't been promoted - we've dealt with those
246052665432SStephen Tozer     // already.
246152665432SStephen Tozer     if (VarsWithStackSlot->contains(getAggregate(Record)))
246252665432SStephen Tozer       return;
246352665432SStephen Tozer     auto InsertBefore = getNextNode(Record);
246452665432SStephen Tozer     assert(InsertBefore && "Unexpected: debug intrinsics after a terminator");
246552665432SStephen Tozer     FnVarLocs->addVarLoc(InsertBefore, DebugVariable(Record),
246652665432SStephen Tozer                          Record->getExpression(), Record->getDebugLoc(),
246752665432SStephen Tozer                          RawLocationWrapper(Record->getRawLocation()));
246852665432SStephen Tozer     InsertedAnyIntrinsics = true;
246952665432SStephen Tozer   };
24701d1de746SOCHyams   for (auto &BB : Fn) {
24711d1de746SOCHyams     for (auto &I : BB) {
24721d1de746SOCHyams       // Skip instructions other than dbg.values and dbg.assigns.
2473ffd08c77SStephen Tozer       for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange()))
2474ffd08c77SStephen Tozer         if (DVR.isDbgValue() || DVR.isDbgAssign())
2475ffd08c77SStephen Tozer           TranslateDbgRecord(&DVR);
24761d1de746SOCHyams       auto *DVI = dyn_cast<DbgValueInst>(&I);
247752665432SStephen Tozer       if (DVI)
247852665432SStephen Tozer         TranslateDbgRecord(DVI);
24791d1de746SOCHyams     }
24801d1de746SOCHyams   }
24811d1de746SOCHyams   return InsertedAnyIntrinsics;
24821d1de746SOCHyams }
24831d1de746SOCHyams 
24841d1de746SOCHyams /// Remove redundant definitions within sequences of consecutive location defs.
24851d1de746SOCHyams /// This is done using a backward scan to keep the last def describing a
24861d1de746SOCHyams /// specific variable/fragment.
24871d1de746SOCHyams ///
24881d1de746SOCHyams /// This implements removeRedundantDbgInstrsUsingBackwardScan from
24891d1de746SOCHyams /// lib/Transforms/Utils/BasicBlockUtils.cpp for locations described with
24901d1de746SOCHyams /// FunctionVarLocsBuilder instead of with intrinsics.
24911d1de746SOCHyams static bool
24921d1de746SOCHyams removeRedundantDbgLocsUsingBackwardScan(const BasicBlock *BB,
24931d1de746SOCHyams                                         FunctionVarLocsBuilder &FnVarLocs) {
24941d1de746SOCHyams   bool Changed = false;
24955d558397SOrlando Cazalet-Hyams   SmallDenseMap<DebugAggregate, BitVector> VariableDefinedBytes;
24961d1de746SOCHyams   // Scan over the entire block, not just over the instructions mapped by
2497d4a01549SJay Foad   // FnVarLocs, because wedges in FnVarLocs may only be separated by debug
24981d1de746SOCHyams   // instructions.
24991d1de746SOCHyams   for (const Instruction &I : reverse(*BB)) {
25001d1de746SOCHyams     if (!isa<DbgVariableIntrinsic>(I)) {
25011d1de746SOCHyams       // Sequence of consecutive defs ended. Clear map for the next one.
25025d558397SOrlando Cazalet-Hyams       VariableDefinedBytes.clear();
25031d1de746SOCHyams     }
25041d1de746SOCHyams 
250530845e8aSStephen Tozer     auto HandleLocsForWedge = [&](auto *WedgePosition) {
25061d1de746SOCHyams       // Get the location defs that start just before this instruction.
250730845e8aSStephen Tozer       const auto *Locs = FnVarLocs.getWedge(WedgePosition);
25081d1de746SOCHyams       if (!Locs)
250930845e8aSStephen Tozer         return;
25101d1de746SOCHyams 
25111d1de746SOCHyams       NumWedgesScanned++;
25121d1de746SOCHyams       bool ChangedThisWedge = false;
25131d1de746SOCHyams       // The new pruned set of defs, reversed because we're scanning backwards.
25141d1de746SOCHyams       SmallVector<VarLocInfo> NewDefsReversed;
25151d1de746SOCHyams 
25161d1de746SOCHyams       // Iterate over the existing defs in reverse.
25171d1de746SOCHyams       for (auto RIt = Locs->rbegin(), REnd = Locs->rend(); RIt != REnd; ++RIt) {
25181d1de746SOCHyams         NumDefsScanned++;
25198e56a196SOCHyams         DebugAggregate Aggr =
25208e56a196SOCHyams             getAggregate(FnVarLocs.getVariable(RIt->VariableID));
25218e56a196SOCHyams         uint64_t SizeInBits = Aggr.first->getSizeInBits().value_or(0);
25225d558397SOrlando Cazalet-Hyams         uint64_t SizeInBytes = divideCeil(SizeInBits, 8);
25231d1de746SOCHyams 
25245d558397SOrlando Cazalet-Hyams         // Cutoff for large variables to prevent expensive bitvector operations.
25255d558397SOrlando Cazalet-Hyams         const uint64_t MaxSizeBytes = 2048;
25265d558397SOrlando Cazalet-Hyams 
25275d558397SOrlando Cazalet-Hyams         if (SizeInBytes == 0 || SizeInBytes > MaxSizeBytes) {
25288e56a196SOCHyams           // If the size is unknown (0) then keep this location def to be safe.
25295d558397SOrlando Cazalet-Hyams           // Do the same for defs of large variables, which would be expensive
25305d558397SOrlando Cazalet-Hyams           // to represent with a BitVector.
25311d1de746SOCHyams           NewDefsReversed.push_back(*RIt);
25328e56a196SOCHyams           continue;
25338e56a196SOCHyams         }
25348e56a196SOCHyams 
25358e56a196SOCHyams         // Only keep this location definition if it is not fully eclipsed by
25368e56a196SOCHyams         // other definitions in this wedge that come after it
25378e56a196SOCHyams 
25385d558397SOrlando Cazalet-Hyams         // Inert the bytes the location definition defines.
25398e56a196SOCHyams         auto InsertResult =
25405d558397SOrlando Cazalet-Hyams             VariableDefinedBytes.try_emplace(Aggr, BitVector(SizeInBytes));
25418e56a196SOCHyams         bool FirstDefinition = InsertResult.second;
25425d558397SOrlando Cazalet-Hyams         BitVector &DefinedBytes = InsertResult.first->second;
25438e56a196SOCHyams 
25448e56a196SOCHyams         DIExpression::FragmentInfo Fragment =
25458e56a196SOCHyams             RIt->Expr->getFragmentInfo().value_or(
25468e56a196SOCHyams                 DIExpression::FragmentInfo(SizeInBits, 0));
25478e56a196SOCHyams         bool InvalidFragment = Fragment.endInBits() > SizeInBits;
25485d558397SOrlando Cazalet-Hyams         uint64_t StartInBytes = Fragment.startInBits() / 8;
25495d558397SOrlando Cazalet-Hyams         uint64_t EndInBytes = divideCeil(Fragment.endInBits(), 8);
25508e56a196SOCHyams 
25515d558397SOrlando Cazalet-Hyams         // If this defines any previously undefined bytes, keep it.
25528e56a196SOCHyams         if (FirstDefinition || InvalidFragment ||
25535d558397SOrlando Cazalet-Hyams             DefinedBytes.find_first_unset_in(StartInBytes, EndInBytes) != -1) {
25548e56a196SOCHyams           if (!InvalidFragment)
25555d558397SOrlando Cazalet-Hyams             DefinedBytes.set(StartInBytes, EndInBytes);
25568e56a196SOCHyams           NewDefsReversed.push_back(*RIt);
25578e56a196SOCHyams           continue;
25588e56a196SOCHyams         }
25598e56a196SOCHyams 
25601d1de746SOCHyams         // Redundant def found: throw it away. Since the wedge of defs is being
25611d1de746SOCHyams         // rebuilt, doing nothing is the same as deleting an entry.
25621d1de746SOCHyams         ChangedThisWedge = true;
25631d1de746SOCHyams         NumDefsRemoved++;
25641d1de746SOCHyams       }
25651d1de746SOCHyams 
25661d1de746SOCHyams       // Un-reverse the defs and replace the wedge with the pruned version.
25671d1de746SOCHyams       if (ChangedThisWedge) {
25681d1de746SOCHyams         std::reverse(NewDefsReversed.begin(), NewDefsReversed.end());
256930845e8aSStephen Tozer         FnVarLocs.setWedge(WedgePosition, std::move(NewDefsReversed));
25701d1de746SOCHyams         NumWedgesChanged++;
25711d1de746SOCHyams         Changed = true;
25721d1de746SOCHyams       }
257330845e8aSStephen Tozer     };
257430845e8aSStephen Tozer     HandleLocsForWedge(&I);
2575ffd08c77SStephen Tozer     for (DbgVariableRecord &DVR : reverse(filterDbgVars(I.getDbgRecordRange())))
2576ffd08c77SStephen Tozer       HandleLocsForWedge(&DVR);
25771d1de746SOCHyams   }
25781d1de746SOCHyams 
25791d1de746SOCHyams   return Changed;
25801d1de746SOCHyams }
25811d1de746SOCHyams 
25821d1de746SOCHyams /// Remove redundant location defs using a forward scan. This can remove a
25831d1de746SOCHyams /// location definition that is redundant due to indicating that a variable has
25841d1de746SOCHyams /// the same value as is already being indicated by an earlier def.
25851d1de746SOCHyams ///
25861d1de746SOCHyams /// This implements removeRedundantDbgInstrsUsingForwardScan from
25871d1de746SOCHyams /// lib/Transforms/Utils/BasicBlockUtils.cpp for locations described with
25881d1de746SOCHyams /// FunctionVarLocsBuilder instead of with intrinsics
25891d1de746SOCHyams static bool
25901d1de746SOCHyams removeRedundantDbgLocsUsingForwardScan(const BasicBlock *BB,
25911d1de746SOCHyams                                        FunctionVarLocsBuilder &FnVarLocs) {
25921d1de746SOCHyams   bool Changed = false;
25937d894374SOCHyams   DenseMap<DebugVariable, std::pair<RawLocationWrapper, DIExpression *>>
25947d894374SOCHyams       VariableMap;
25951d1de746SOCHyams 
25961d1de746SOCHyams   // Scan over the entire block, not just over the instructions mapped by
2597d4a01549SJay Foad   // FnVarLocs, because wedges in FnVarLocs may only be separated by debug
25981d1de746SOCHyams   // instructions.
25991d1de746SOCHyams   for (const Instruction &I : *BB) {
26001d1de746SOCHyams     // Get the defs that come just before this instruction.
260130845e8aSStephen Tozer     auto HandleLocsForWedge = [&](auto *WedgePosition) {
260230845e8aSStephen Tozer       const auto *Locs = FnVarLocs.getWedge(WedgePosition);
26031d1de746SOCHyams       if (!Locs)
260430845e8aSStephen Tozer         return;
26051d1de746SOCHyams 
26061d1de746SOCHyams       NumWedgesScanned++;
26071d1de746SOCHyams       bool ChangedThisWedge = false;
26081d1de746SOCHyams       // The new pruned set of defs.
26091d1de746SOCHyams       SmallVector<VarLocInfo> NewDefs;
26101d1de746SOCHyams 
26111d1de746SOCHyams       // Iterate over the existing defs.
26121d1de746SOCHyams       for (const VarLocInfo &Loc : *Locs) {
26131d1de746SOCHyams         NumDefsScanned++;
26141d1de746SOCHyams         DebugVariable Key(FnVarLocs.getVariable(Loc.VariableID).getVariable(),
26151d1de746SOCHyams                           std::nullopt, Loc.DL.getInlinedAt());
26161d1de746SOCHyams         auto VMI = VariableMap.find(Key);
26171d1de746SOCHyams 
26181d1de746SOCHyams         // Update the map if we found a new value/expression describing the
26191d1de746SOCHyams         // variable, or if the variable wasn't mapped already.
26207d894374SOCHyams         if (VMI == VariableMap.end() || VMI->second.first != Loc.Values ||
26211d1de746SOCHyams             VMI->second.second != Loc.Expr) {
26227d894374SOCHyams           VariableMap[Key] = {Loc.Values, Loc.Expr};
26231d1de746SOCHyams           NewDefs.push_back(Loc);
26241d1de746SOCHyams           continue;
26251d1de746SOCHyams         }
26261d1de746SOCHyams 
26271d1de746SOCHyams         // Did not insert this Loc, which is the same as removing it.
26281d1de746SOCHyams         ChangedThisWedge = true;
26291d1de746SOCHyams         NumDefsRemoved++;
26301d1de746SOCHyams       }
26311d1de746SOCHyams 
26321d1de746SOCHyams       // Replace the existing wedge with the pruned version.
26331d1de746SOCHyams       if (ChangedThisWedge) {
263430845e8aSStephen Tozer         FnVarLocs.setWedge(WedgePosition, std::move(NewDefs));
26351d1de746SOCHyams         NumWedgesChanged++;
26361d1de746SOCHyams         Changed = true;
26371d1de746SOCHyams       }
263830845e8aSStephen Tozer     };
263930845e8aSStephen Tozer 
2640ffd08c77SStephen Tozer     for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange()))
2641ffd08c77SStephen Tozer       HandleLocsForWedge(&DVR);
264230845e8aSStephen Tozer     HandleLocsForWedge(&I);
26431d1de746SOCHyams   }
26441d1de746SOCHyams 
26451d1de746SOCHyams   return Changed;
26461d1de746SOCHyams }
26471d1de746SOCHyams 
26481d1de746SOCHyams static bool
26491d1de746SOCHyams removeUndefDbgLocsFromEntryBlock(const BasicBlock *BB,
26501d1de746SOCHyams                                  FunctionVarLocsBuilder &FnVarLocs) {
26511d1de746SOCHyams   assert(BB->isEntryBlock());
26521d1de746SOCHyams   // Do extra work to ensure that we remove semantically unimportant undefs.
26531d1de746SOCHyams   //
26541d1de746SOCHyams   // This is to work around the fact that SelectionDAG will hoist dbg.values
26551d1de746SOCHyams   // using argument values to the top of the entry block. That can move arg
26561d1de746SOCHyams   // dbg.values before undef and constant dbg.values which they previously
26571d1de746SOCHyams   // followed. The easiest thing to do is to just try to feed SelectionDAG
26581d1de746SOCHyams   // input it's happy with.
26591d1de746SOCHyams   //
26601d1de746SOCHyams   // Map of {Variable x: Fragments y} where the fragments y of variable x have
26611d1de746SOCHyams   // have at least one non-undef location defined already. Don't use directly,
26621d1de746SOCHyams   // instead call DefineBits and HasDefinedBits.
26631d1de746SOCHyams   SmallDenseMap<DebugAggregate, SmallDenseSet<DIExpression::FragmentInfo>>
26641d1de746SOCHyams       VarsWithDef;
26651d1de746SOCHyams   // Specify that V (a fragment of A) has a non-undef location.
26661d1de746SOCHyams   auto DefineBits = [&VarsWithDef](DebugAggregate A, DebugVariable V) {
26671d1de746SOCHyams     VarsWithDef[A].insert(V.getFragmentOrDefault());
26681d1de746SOCHyams   };
26691d1de746SOCHyams   // Return true if a non-undef location has been defined for V (a fragment of
26701d1de746SOCHyams   // A). Doesn't imply that the location is currently non-undef, just that a
26711d1de746SOCHyams   // non-undef location has been seen previously.
26721d1de746SOCHyams   auto HasDefinedBits = [&VarsWithDef](DebugAggregate A, DebugVariable V) {
26731d1de746SOCHyams     auto FragsIt = VarsWithDef.find(A);
26741d1de746SOCHyams     if (FragsIt == VarsWithDef.end())
26751d1de746SOCHyams       return false;
26761d1de746SOCHyams     return llvm::any_of(FragsIt->second, [V](auto Frag) {
26771d1de746SOCHyams       return DIExpression::fragmentsOverlap(Frag, V.getFragmentOrDefault());
26781d1de746SOCHyams     });
26791d1de746SOCHyams   };
26801d1de746SOCHyams 
26811d1de746SOCHyams   bool Changed = false;
26821d1de746SOCHyams   DenseMap<DebugVariable, std::pair<Value *, DIExpression *>> VariableMap;
26831d1de746SOCHyams 
26841d1de746SOCHyams   // Scan over the entire block, not just over the instructions mapped by
2685d4a01549SJay Foad   // FnVarLocs, because wedges in FnVarLocs may only be separated by debug
26861d1de746SOCHyams   // instructions.
26871d1de746SOCHyams   for (const Instruction &I : *BB) {
26881d1de746SOCHyams     // Get the defs that come just before this instruction.
268930845e8aSStephen Tozer     auto HandleLocsForWedge = [&](auto *WedgePosition) {
269030845e8aSStephen Tozer       const auto *Locs = FnVarLocs.getWedge(WedgePosition);
26911d1de746SOCHyams       if (!Locs)
269230845e8aSStephen Tozer         return;
26931d1de746SOCHyams 
26941d1de746SOCHyams       NumWedgesScanned++;
26951d1de746SOCHyams       bool ChangedThisWedge = false;
26961d1de746SOCHyams       // The new pruned set of defs.
26971d1de746SOCHyams       SmallVector<VarLocInfo> NewDefs;
26981d1de746SOCHyams 
26991d1de746SOCHyams       // Iterate over the existing defs.
27001d1de746SOCHyams       for (const VarLocInfo &Loc : *Locs) {
27011d1de746SOCHyams         NumDefsScanned++;
27021d1de746SOCHyams         DebugAggregate Aggr{FnVarLocs.getVariable(Loc.VariableID).getVariable(),
27031d1de746SOCHyams                             Loc.DL.getInlinedAt()};
27041d1de746SOCHyams         DebugVariable Var = FnVarLocs.getVariable(Loc.VariableID);
27051d1de746SOCHyams 
27061d1de746SOCHyams         // Remove undef entries that are encountered before any non-undef
27071d1de746SOCHyams         // intrinsics from the entry block.
27087d894374SOCHyams         if (Loc.Values.isKillLocation(Loc.Expr) && !HasDefinedBits(Aggr, Var)) {
27091d1de746SOCHyams           // Did not insert this Loc, which is the same as removing it.
27101d1de746SOCHyams           NumDefsRemoved++;
27111d1de746SOCHyams           ChangedThisWedge = true;
27121d1de746SOCHyams           continue;
27131d1de746SOCHyams         }
27141d1de746SOCHyams 
27151d1de746SOCHyams         DefineBits(Aggr, Var);
27161d1de746SOCHyams         NewDefs.push_back(Loc);
27171d1de746SOCHyams       }
27181d1de746SOCHyams 
27191d1de746SOCHyams       // Replace the existing wedge with the pruned version.
27201d1de746SOCHyams       if (ChangedThisWedge) {
272130845e8aSStephen Tozer         FnVarLocs.setWedge(WedgePosition, std::move(NewDefs));
27221d1de746SOCHyams         NumWedgesChanged++;
27231d1de746SOCHyams         Changed = true;
27241d1de746SOCHyams       }
272530845e8aSStephen Tozer     };
2726ffd08c77SStephen Tozer     for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange()))
2727ffd08c77SStephen Tozer       HandleLocsForWedge(&DVR);
272830845e8aSStephen Tozer     HandleLocsForWedge(&I);
27291d1de746SOCHyams   }
27301d1de746SOCHyams 
27311d1de746SOCHyams   return Changed;
27321d1de746SOCHyams }
27331d1de746SOCHyams 
27341d1de746SOCHyams static bool removeRedundantDbgLocs(const BasicBlock *BB,
27351d1de746SOCHyams                                    FunctionVarLocsBuilder &FnVarLocs) {
27361d1de746SOCHyams   bool MadeChanges = false;
27371d1de746SOCHyams   MadeChanges |= removeRedundantDbgLocsUsingBackwardScan(BB, FnVarLocs);
27381d1de746SOCHyams   if (BB->isEntryBlock())
27391d1de746SOCHyams     MadeChanges |= removeUndefDbgLocsFromEntryBlock(BB, FnVarLocs);
27401d1de746SOCHyams   MadeChanges |= removeRedundantDbgLocsUsingForwardScan(BB, FnVarLocs);
27411d1de746SOCHyams 
27421d1de746SOCHyams   if (MadeChanges)
27431d1de746SOCHyams     LLVM_DEBUG(dbgs() << "Removed redundant dbg locs from: " << BB->getName()
27441d1de746SOCHyams                       << "\n");
27451d1de746SOCHyams   return MadeChanges;
27461d1de746SOCHyams }
27471d1de746SOCHyams 
27481d1de746SOCHyams static DenseSet<DebugAggregate> findVarsWithStackSlot(Function &Fn) {
27491d1de746SOCHyams   DenseSet<DebugAggregate> Result;
27501d1de746SOCHyams   for (auto &BB : Fn) {
27511d1de746SOCHyams     for (auto &I : BB) {
27521d1de746SOCHyams       // Any variable linked to an instruction is considered
27531d1de746SOCHyams       // interesting. Ideally we only need to check Allocas, however, a
27541d1de746SOCHyams       // DIAssignID might get dropped from an alloca but not stores. In that
27551d1de746SOCHyams       // case, we need to consider the variable interesting for NFC behaviour
27561d1de746SOCHyams       // with this change. TODO: Consider only looking at allocas.
27571d1de746SOCHyams       for (DbgAssignIntrinsic *DAI : at::getAssignmentMarkers(&I)) {
27581d1de746SOCHyams         Result.insert({DAI->getVariable(), DAI->getDebugLoc().getInlinedAt()});
27591d1de746SOCHyams       }
2760ffd08c77SStephen Tozer       for (DbgVariableRecord *DVR : at::getDVRAssignmentMarkers(&I)) {
2761ffd08c77SStephen Tozer         Result.insert({DVR->getVariable(), DVR->getDebugLoc().getInlinedAt()});
276230845e8aSStephen Tozer       }
27631d1de746SOCHyams     }
27641d1de746SOCHyams   }
27651d1de746SOCHyams   return Result;
27661d1de746SOCHyams }
27671d1de746SOCHyams 
27681d1de746SOCHyams static void analyzeFunction(Function &Fn, const DataLayout &Layout,
27691d1de746SOCHyams                             FunctionVarLocsBuilder *FnVarLocs) {
27701d1de746SOCHyams   // The analysis will generate location definitions for all variables, but we
27711d1de746SOCHyams   // only need to perform a dataflow on the set of variables which have a stack
27721d1de746SOCHyams   // slot. Find those now.
27731d1de746SOCHyams   DenseSet<DebugAggregate> VarsWithStackSlot = findVarsWithStackSlot(Fn);
27741d1de746SOCHyams 
27751d1de746SOCHyams   bool Changed = false;
27761d1de746SOCHyams 
27771d1de746SOCHyams   // Use a scope block to clean up AssignmentTrackingLowering before running
27781d1de746SOCHyams   // MemLocFragmentFill to reduce peak memory consumption.
27791d1de746SOCHyams   {
27801d1de746SOCHyams     AssignmentTrackingLowering Pass(Fn, Layout, &VarsWithStackSlot);
27811d1de746SOCHyams     Changed = Pass.run(FnVarLocs);
27821d1de746SOCHyams   }
27831d1de746SOCHyams 
27841d1de746SOCHyams   if (Changed) {
2785d4879d76SOCHyams     MemLocFragmentFill Pass(Fn, &VarsWithStackSlot,
2786d4879d76SOCHyams                             shouldCoalesceFragments(Fn));
27871d1de746SOCHyams     Pass.run(FnVarLocs);
27881d1de746SOCHyams 
27891d1de746SOCHyams     // Remove redundant entries. As well as reducing memory consumption and
27901d1de746SOCHyams     // avoiding waiting cycles later by burning some now, this has another
27911d1de746SOCHyams     // important job. That is to work around some SelectionDAG quirks. See
27921d1de746SOCHyams     // removeRedundantDbgLocsUsingForwardScan comments for more info on that.
27931d1de746SOCHyams     for (auto &BB : Fn)
27941d1de746SOCHyams       removeRedundantDbgLocs(&BB, *FnVarLocs);
27951d1de746SOCHyams   }
27961d1de746SOCHyams }
27971d1de746SOCHyams 
27987c71a09dSpaperchalice FunctionVarLocs
27997c71a09dSpaperchalice DebugAssignmentTrackingAnalysis::run(Function &F,
28007c71a09dSpaperchalice                                      FunctionAnalysisManager &FAM) {
28017c71a09dSpaperchalice   if (!isAssignmentTrackingEnabled(*F.getParent()))
28027c71a09dSpaperchalice     return FunctionVarLocs();
28037c71a09dSpaperchalice 
28049df71d76SNikita Popov   auto &DL = F.getDataLayout();
28057c71a09dSpaperchalice 
28067c71a09dSpaperchalice   FunctionVarLocsBuilder Builder;
28077c71a09dSpaperchalice   analyzeFunction(F, DL, &Builder);
28087c71a09dSpaperchalice 
28097c71a09dSpaperchalice   // Save these results.
28107c71a09dSpaperchalice   FunctionVarLocs Results;
28117c71a09dSpaperchalice   Results.init(Builder);
28127c71a09dSpaperchalice   return Results;
28137c71a09dSpaperchalice }
28147c71a09dSpaperchalice 
28157c71a09dSpaperchalice AnalysisKey DebugAssignmentTrackingAnalysis::Key;
28167c71a09dSpaperchalice 
28177c71a09dSpaperchalice PreservedAnalyses
28187c71a09dSpaperchalice DebugAssignmentTrackingPrinterPass::run(Function &F,
28197c71a09dSpaperchalice                                         FunctionAnalysisManager &FAM) {
28207c71a09dSpaperchalice   FAM.getResult<DebugAssignmentTrackingAnalysis>(F).print(OS, F);
28217c71a09dSpaperchalice   return PreservedAnalyses::all();
28227c71a09dSpaperchalice }
28237c71a09dSpaperchalice 
28241d1de746SOCHyams bool AssignmentTrackingAnalysis::runOnFunction(Function &F) {
28254ece5073SOCHyams   if (!isAssignmentTrackingEnabled(*F.getParent()))
28264ece5073SOCHyams     return false;
28274ece5073SOCHyams 
28281d1de746SOCHyams   LLVM_DEBUG(dbgs() << "AssignmentTrackingAnalysis run on " << F.getName()
28291d1de746SOCHyams                     << "\n");
28301d1de746SOCHyams 
28311d1de746SOCHyams   // Clear previous results.
28321d1de746SOCHyams   Results->clear();
28331d1de746SOCHyams 
28341d1de746SOCHyams   FunctionVarLocsBuilder Builder;
283575c7bca7SSergei Barannikov   analyzeFunction(F, F.getDataLayout(), &Builder);
28361d1de746SOCHyams 
28371d1de746SOCHyams   // Save these results.
28381d1de746SOCHyams   Results->init(Builder);
28391d1de746SOCHyams 
28401d1de746SOCHyams   if (PrintResults && isFunctionInPrintList(F.getName()))
28411d1de746SOCHyams     Results->print(errs(), F);
28421d1de746SOCHyams 
28431d1de746SOCHyams   // Return false because this pass does not modify the function.
28441d1de746SOCHyams   return false;
28451d1de746SOCHyams }
28461d1de746SOCHyams 
28471d1de746SOCHyams AssignmentTrackingAnalysis::AssignmentTrackingAnalysis()
28481d1de746SOCHyams     : FunctionPass(ID), Results(std::make_unique<FunctionVarLocs>()) {}
28491d1de746SOCHyams 
28501d1de746SOCHyams char AssignmentTrackingAnalysis::ID = 0;
28511d1de746SOCHyams 
28521d1de746SOCHyams INITIALIZE_PASS(AssignmentTrackingAnalysis, DEBUG_TYPE,
28531d1de746SOCHyams                 "Assignment Tracking Analysis", false, true)
2854