1950076cdSDimitry Andric //===-- AssignmentTrackingAnalysis.cpp ------------------------------------===//
2950076cdSDimitry Andric //
3950076cdSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4950076cdSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5950076cdSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6950076cdSDimitry Andric //
7950076cdSDimitry Andric //===----------------------------------------------------------------------===//
8950076cdSDimitry Andric
9e3b55780SDimitry Andric #include "llvm/CodeGen/AssignmentTrackingAnalysis.h"
107fa27ce4SDimitry Andric #include "LiveDebugValues/LiveDebugValues.h"
117fa27ce4SDimitry Andric #include "llvm/ADT/BitVector.h"
12e3b55780SDimitry Andric #include "llvm/ADT/DenseMapInfo.h"
13e3b55780SDimitry Andric #include "llvm/ADT/IntervalMap.h"
14e3b55780SDimitry Andric #include "llvm/ADT/PostOrderIterator.h"
15e3b55780SDimitry Andric #include "llvm/ADT/STLExtras.h"
16e3b55780SDimitry Andric #include "llvm/ADT/Statistic.h"
17e3b55780SDimitry Andric #include "llvm/ADT/UniqueVector.h"
18e3b55780SDimitry Andric #include "llvm/BinaryFormat/Dwarf.h"
19e3b55780SDimitry Andric #include "llvm/IR/BasicBlock.h"
20e3b55780SDimitry Andric #include "llvm/IR/DataLayout.h"
21e3b55780SDimitry Andric #include "llvm/IR/DebugInfo.h"
224df029ccSDimitry Andric #include "llvm/IR/DebugProgramInstruction.h"
23e3b55780SDimitry Andric #include "llvm/IR/Function.h"
24e3b55780SDimitry Andric #include "llvm/IR/Instruction.h"
25e3b55780SDimitry Andric #include "llvm/IR/IntrinsicInst.h"
26ac9a064cSDimitry Andric #include "llvm/IR/Module.h"
27e3b55780SDimitry Andric #include "llvm/IR/PassManager.h"
28e3b55780SDimitry Andric #include "llvm/IR/PrintPasses.h"
29e3b55780SDimitry Andric #include "llvm/InitializePasses.h"
30e3b55780SDimitry Andric #include "llvm/Support/CommandLine.h"
31e3b55780SDimitry Andric #include "llvm/Support/ErrorHandling.h"
32e3b55780SDimitry Andric #include "llvm/Support/raw_ostream.h"
33e3b55780SDimitry Andric #include "llvm/Transforms/Utils/BasicBlockUtils.h"
34e3b55780SDimitry Andric #include <assert.h>
35e3b55780SDimitry Andric #include <cstdint>
36e3b55780SDimitry Andric #include <optional>
37b1c73532SDimitry Andric #include <queue>
38e3b55780SDimitry Andric #include <sstream>
39e3b55780SDimitry Andric #include <unordered_map>
40e3b55780SDimitry Andric
41e3b55780SDimitry Andric using namespace llvm;
42e3b55780SDimitry Andric #define DEBUG_TYPE "debug-ata"
43e3b55780SDimitry Andric
44e3b55780SDimitry Andric STATISTIC(NumDefsScanned, "Number of dbg locs that get scanned for removal");
45e3b55780SDimitry Andric STATISTIC(NumDefsRemoved, "Number of dbg locs removed");
46e3b55780SDimitry Andric STATISTIC(NumWedgesScanned, "Number of dbg wedges scanned");
47e3b55780SDimitry Andric STATISTIC(NumWedgesChanged, "Number of dbg wedges changed");
48e3b55780SDimitry Andric
49e3b55780SDimitry Andric static cl::opt<unsigned>
50e3b55780SDimitry Andric MaxNumBlocks("debug-ata-max-blocks", cl::init(10000),
51e3b55780SDimitry Andric cl::desc("Maximum num basic blocks before debug info dropped"),
52e3b55780SDimitry Andric cl::Hidden);
53e3b55780SDimitry Andric /// Option for debugging the pass, determines if the memory location fragment
54e3b55780SDimitry Andric /// filling happens after generating the variable locations.
55e3b55780SDimitry Andric static cl::opt<bool> EnableMemLocFragFill("mem-loc-frag-fill", cl::init(true),
56e3b55780SDimitry Andric cl::Hidden);
57e3b55780SDimitry Andric /// Print the results of the analysis. Respects -filter-print-funcs.
58e3b55780SDimitry Andric static cl::opt<bool> PrintResults("print-debug-ata", cl::init(false),
59e3b55780SDimitry Andric cl::Hidden);
60e3b55780SDimitry Andric
617fa27ce4SDimitry Andric /// Coalesce adjacent dbg locs describing memory locations that have contiguous
627fa27ce4SDimitry Andric /// fragments. This reduces the cost of LiveDebugValues which does SSA
637fa27ce4SDimitry Andric /// construction for each explicitly stated variable fragment.
647fa27ce4SDimitry Andric static cl::opt<cl::boolOrDefault>
657fa27ce4SDimitry Andric CoalesceAdjacentFragmentsOpt("debug-ata-coalesce-frags", cl::Hidden);
667fa27ce4SDimitry Andric
67e3b55780SDimitry Andric // Implicit conversions are disabled for enum class types, so unfortunately we
68e3b55780SDimitry Andric // need to create a DenseMapInfo wrapper around the specified underlying type.
69e3b55780SDimitry Andric template <> struct llvm::DenseMapInfo<VariableID> {
70e3b55780SDimitry Andric using Wrapped = DenseMapInfo<unsigned>;
getEmptyKeyllvm::DenseMapInfo71e3b55780SDimitry Andric static inline VariableID getEmptyKey() {
72e3b55780SDimitry Andric return static_cast<VariableID>(Wrapped::getEmptyKey());
73e3b55780SDimitry Andric }
getTombstoneKeyllvm::DenseMapInfo74e3b55780SDimitry Andric static inline VariableID getTombstoneKey() {
75e3b55780SDimitry Andric return static_cast<VariableID>(Wrapped::getTombstoneKey());
76e3b55780SDimitry Andric }
getHashValuellvm::DenseMapInfo77e3b55780SDimitry Andric static unsigned getHashValue(const VariableID &Val) {
78e3b55780SDimitry Andric return Wrapped::getHashValue(static_cast<unsigned>(Val));
79e3b55780SDimitry Andric }
isEqualllvm::DenseMapInfo80e3b55780SDimitry Andric static bool isEqual(const VariableID &LHS, const VariableID &RHS) {
81e3b55780SDimitry Andric return LHS == RHS;
82e3b55780SDimitry Andric }
83e3b55780SDimitry Andric };
84e3b55780SDimitry Andric
85ac9a064cSDimitry Andric using VarLocInsertPt = PointerUnion<const Instruction *, const DbgRecord *>;
864df029ccSDimitry Andric
874df029ccSDimitry Andric namespace std {
884df029ccSDimitry Andric template <> struct hash<VarLocInsertPt> {
894df029ccSDimitry Andric using argument_type = VarLocInsertPt;
904df029ccSDimitry Andric using result_type = std::size_t;
914df029ccSDimitry Andric
operator ()std::hash924df029ccSDimitry Andric result_type operator()(const argument_type &Arg) const {
934df029ccSDimitry Andric return std::hash<void *>()(Arg.getOpaqueValue());
944df029ccSDimitry Andric }
954df029ccSDimitry Andric };
964df029ccSDimitry Andric } // namespace std
974df029ccSDimitry Andric
98e3b55780SDimitry Andric /// Helper class to build FunctionVarLocs, since that class isn't easy to
99e3b55780SDimitry Andric /// modify. TODO: There's not a great deal of value in the split, it could be
100e3b55780SDimitry Andric /// worth merging the two classes.
101e3b55780SDimitry Andric class FunctionVarLocsBuilder {
102e3b55780SDimitry Andric friend FunctionVarLocs;
103e3b55780SDimitry Andric UniqueVector<DebugVariable> Variables;
104e3b55780SDimitry Andric // Use an unordered_map so we don't invalidate iterators after
105e3b55780SDimitry Andric // insert/modifications.
1064df029ccSDimitry Andric std::unordered_map<VarLocInsertPt, SmallVector<VarLocInfo>> VarLocsBeforeInst;
107e3b55780SDimitry Andric
108e3b55780SDimitry Andric SmallVector<VarLocInfo> SingleLocVars;
109e3b55780SDimitry Andric
110e3b55780SDimitry Andric public:
getNumVariables() const1117fa27ce4SDimitry Andric unsigned getNumVariables() const { return Variables.size(); }
1127fa27ce4SDimitry Andric
113e3b55780SDimitry Andric /// Find or insert \p V and return the ID.
insertVariable(DebugVariable V)114e3b55780SDimitry Andric VariableID insertVariable(DebugVariable V) {
115e3b55780SDimitry Andric return static_cast<VariableID>(Variables.insert(V));
116e3b55780SDimitry Andric }
117e3b55780SDimitry Andric
118e3b55780SDimitry Andric /// Get a variable from its \p ID.
getVariable(VariableID ID) const119e3b55780SDimitry Andric const DebugVariable &getVariable(VariableID ID) const {
120e3b55780SDimitry Andric return Variables[static_cast<unsigned>(ID)];
121e3b55780SDimitry Andric }
122e3b55780SDimitry Andric
123e3b55780SDimitry Andric /// Return ptr to wedge of defs or nullptr if no defs come just before /p
124e3b55780SDimitry Andric /// Before.
getWedge(VarLocInsertPt Before) const1254df029ccSDimitry Andric const SmallVectorImpl<VarLocInfo> *getWedge(VarLocInsertPt Before) const {
126e3b55780SDimitry Andric auto R = VarLocsBeforeInst.find(Before);
127e3b55780SDimitry Andric if (R == VarLocsBeforeInst.end())
128e3b55780SDimitry Andric return nullptr;
129e3b55780SDimitry Andric return &R->second;
130e3b55780SDimitry Andric }
131e3b55780SDimitry Andric
132e3b55780SDimitry Andric /// Replace the defs that come just before /p Before with /p Wedge.
setWedge(VarLocInsertPt Before,SmallVector<VarLocInfo> && Wedge)1334df029ccSDimitry Andric void setWedge(VarLocInsertPt Before, SmallVector<VarLocInfo> &&Wedge) {
134e3b55780SDimitry Andric VarLocsBeforeInst[Before] = std::move(Wedge);
135e3b55780SDimitry Andric }
136e3b55780SDimitry Andric
137e3b55780SDimitry Andric /// Add a def for a variable that is valid for its lifetime.
addSingleLocVar(DebugVariable Var,DIExpression * Expr,DebugLoc DL,RawLocationWrapper R)138e3b55780SDimitry Andric void addSingleLocVar(DebugVariable Var, DIExpression *Expr, DebugLoc DL,
1397fa27ce4SDimitry Andric RawLocationWrapper R) {
140e3b55780SDimitry Andric VarLocInfo VarLoc;
141e3b55780SDimitry Andric VarLoc.VariableID = insertVariable(Var);
142e3b55780SDimitry Andric VarLoc.Expr = Expr;
143e3b55780SDimitry Andric VarLoc.DL = DL;
1447fa27ce4SDimitry Andric VarLoc.Values = R;
145e3b55780SDimitry Andric SingleLocVars.emplace_back(VarLoc);
146e3b55780SDimitry Andric }
147e3b55780SDimitry Andric
148e3b55780SDimitry Andric /// Add a def to the wedge of defs just before /p Before.
addVarLoc(VarLocInsertPt Before,DebugVariable Var,DIExpression * Expr,DebugLoc DL,RawLocationWrapper R)1494df029ccSDimitry Andric void addVarLoc(VarLocInsertPt Before, DebugVariable Var, DIExpression *Expr,
1507fa27ce4SDimitry Andric DebugLoc DL, RawLocationWrapper R) {
151e3b55780SDimitry Andric VarLocInfo VarLoc;
152e3b55780SDimitry Andric VarLoc.VariableID = insertVariable(Var);
153e3b55780SDimitry Andric VarLoc.Expr = Expr;
154e3b55780SDimitry Andric VarLoc.DL = DL;
1557fa27ce4SDimitry Andric VarLoc.Values = R;
156e3b55780SDimitry Andric VarLocsBeforeInst[Before].emplace_back(VarLoc);
157e3b55780SDimitry Andric }
158e3b55780SDimitry Andric };
159e3b55780SDimitry Andric
print(raw_ostream & OS,const Function & Fn) const160e3b55780SDimitry Andric void FunctionVarLocs::print(raw_ostream &OS, const Function &Fn) const {
161e3b55780SDimitry Andric // Print the variable table first. TODO: Sorting by variable could make the
162e3b55780SDimitry Andric // output more stable?
163e3b55780SDimitry Andric unsigned Counter = -1;
164e3b55780SDimitry Andric OS << "=== Variables ===\n";
165e3b55780SDimitry Andric for (const DebugVariable &V : Variables) {
166e3b55780SDimitry Andric ++Counter;
167e3b55780SDimitry Andric // Skip first entry because it is a dummy entry.
168e3b55780SDimitry Andric if (Counter == 0) {
169e3b55780SDimitry Andric continue;
170e3b55780SDimitry Andric }
171e3b55780SDimitry Andric OS << "[" << Counter << "] " << V.getVariable()->getName();
172e3b55780SDimitry Andric if (auto F = V.getFragment())
173e3b55780SDimitry Andric OS << " bits [" << F->OffsetInBits << ", "
174e3b55780SDimitry Andric << F->OffsetInBits + F->SizeInBits << ")";
175e3b55780SDimitry Andric if (const auto *IA = V.getInlinedAt())
176e3b55780SDimitry Andric OS << " inlined-at " << *IA;
177e3b55780SDimitry Andric OS << "\n";
178e3b55780SDimitry Andric }
179e3b55780SDimitry Andric
180e3b55780SDimitry Andric auto PrintLoc = [&OS](const VarLocInfo &Loc) {
181e3b55780SDimitry Andric OS << "DEF Var=[" << (unsigned)Loc.VariableID << "]"
1827fa27ce4SDimitry Andric << " Expr=" << *Loc.Expr << " Values=(";
1837fa27ce4SDimitry Andric for (auto *Op : Loc.Values.location_ops()) {
1847fa27ce4SDimitry Andric errs() << Op->getName() << " ";
1857fa27ce4SDimitry Andric }
1867fa27ce4SDimitry Andric errs() << ")\n";
187e3b55780SDimitry Andric };
188e3b55780SDimitry Andric
189e3b55780SDimitry Andric // Print the single location variables.
190e3b55780SDimitry Andric OS << "=== Single location vars ===\n";
191e3b55780SDimitry Andric for (auto It = single_locs_begin(), End = single_locs_end(); It != End;
192e3b55780SDimitry Andric ++It) {
193e3b55780SDimitry Andric PrintLoc(*It);
194e3b55780SDimitry Andric }
195e3b55780SDimitry Andric
196e3b55780SDimitry Andric // Print the non-single-location defs in line with IR.
197e3b55780SDimitry Andric OS << "=== In-line variable defs ===";
198e3b55780SDimitry Andric for (const BasicBlock &BB : Fn) {
199e3b55780SDimitry Andric OS << "\n" << BB.getName() << ":\n";
200e3b55780SDimitry Andric for (const Instruction &I : BB) {
201e3b55780SDimitry Andric for (auto It = locs_begin(&I), End = locs_end(&I); It != End; ++It) {
202e3b55780SDimitry Andric PrintLoc(*It);
203e3b55780SDimitry Andric }
204e3b55780SDimitry Andric OS << I << "\n";
205e3b55780SDimitry Andric }
206e3b55780SDimitry Andric }
207e3b55780SDimitry Andric }
208e3b55780SDimitry Andric
init(FunctionVarLocsBuilder & Builder)209e3b55780SDimitry Andric void FunctionVarLocs::init(FunctionVarLocsBuilder &Builder) {
210e3b55780SDimitry Andric // Add the single-location variables first.
211e3b55780SDimitry Andric for (const auto &VarLoc : Builder.SingleLocVars)
212e3b55780SDimitry Andric VarLocRecords.emplace_back(VarLoc);
213e3b55780SDimitry Andric // Mark the end of the section.
214e3b55780SDimitry Andric SingleVarLocEnd = VarLocRecords.size();
215e3b55780SDimitry Andric
216e3b55780SDimitry Andric // Insert a contiguous block of VarLocInfos for each instruction, mapping it
2174df029ccSDimitry Andric // to the start and end position in the vector with VarLocsBeforeInst. This
218ac9a064cSDimitry Andric // block includes VarLocs for any DbgVariableRecords attached to that
219ac9a064cSDimitry Andric // instruction.
220e3b55780SDimitry Andric for (auto &P : Builder.VarLocsBeforeInst) {
221ac9a064cSDimitry Andric // Process VarLocs attached to a DbgRecord alongside their marker
222ac9a064cSDimitry Andric // Instruction.
223ac9a064cSDimitry Andric if (isa<const DbgRecord *>(P.first))
2244df029ccSDimitry Andric continue;
2254df029ccSDimitry Andric const Instruction *I = cast<const Instruction *>(P.first);
226e3b55780SDimitry Andric unsigned BlockStart = VarLocRecords.size();
227ac9a064cSDimitry Andric // Any VarLocInfos attached to a DbgRecord should now be remapped to their
228ac9a064cSDimitry Andric // marker Instruction, in order of DbgRecord appearance and prior to any
2294df029ccSDimitry Andric // VarLocInfos attached directly to that instruction.
230ac9a064cSDimitry Andric for (const DbgVariableRecord &DVR : filterDbgVars(I->getDbgRecordRange())) {
231ac9a064cSDimitry Andric // Even though DVR defines a variable location, VarLocsBeforeInst can
2324df029ccSDimitry Andric // still be empty if that VarLoc was redundant.
233ac9a064cSDimitry Andric if (!Builder.VarLocsBeforeInst.count(&DVR))
2344df029ccSDimitry Andric continue;
235ac9a064cSDimitry Andric for (const VarLocInfo &VarLoc : Builder.VarLocsBeforeInst[&DVR])
2364df029ccSDimitry Andric VarLocRecords.emplace_back(VarLoc);
2374df029ccSDimitry Andric }
238e3b55780SDimitry Andric for (const VarLocInfo &VarLoc : P.second)
239e3b55780SDimitry Andric VarLocRecords.emplace_back(VarLoc);
240e3b55780SDimitry Andric unsigned BlockEnd = VarLocRecords.size();
241e3b55780SDimitry Andric // Record the start and end indices.
242e3b55780SDimitry Andric if (BlockEnd != BlockStart)
2434df029ccSDimitry Andric VarLocsBeforeInst[I] = {BlockStart, BlockEnd};
244e3b55780SDimitry Andric }
245e3b55780SDimitry Andric
246e3b55780SDimitry Andric // Copy the Variables vector from the builder's UniqueVector.
247e3b55780SDimitry Andric assert(Variables.empty() && "Expect clear before init");
248e3b55780SDimitry Andric // UniqueVectors IDs are one-based (which means the VarLocInfo VarID values
249e3b55780SDimitry Andric // are one-based) so reserve an extra and insert a dummy.
250e3b55780SDimitry Andric Variables.reserve(Builder.Variables.size() + 1);
251e3b55780SDimitry Andric Variables.push_back(DebugVariable(nullptr, std::nullopt, nullptr));
252e3b55780SDimitry Andric Variables.append(Builder.Variables.begin(), Builder.Variables.end());
253e3b55780SDimitry Andric }
254e3b55780SDimitry Andric
clear()255e3b55780SDimitry Andric void FunctionVarLocs::clear() {
256e3b55780SDimitry Andric Variables.clear();
257e3b55780SDimitry Andric VarLocRecords.clear();
258e3b55780SDimitry Andric VarLocsBeforeInst.clear();
259e3b55780SDimitry Andric SingleVarLocEnd = 0;
260e3b55780SDimitry Andric }
261e3b55780SDimitry Andric
262e3b55780SDimitry Andric /// Walk backwards along constant GEPs and bitcasts to the base storage from \p
263e3b55780SDimitry Andric /// Start as far as possible. Prepend \Expression with the offset and append it
264e3b55780SDimitry Andric /// with a DW_OP_deref that haes been implicit until now. Returns the walked-to
265e3b55780SDimitry Andric /// value and modified expression.
266e3b55780SDimitry Andric static std::pair<Value *, DIExpression *>
walkToAllocaAndPrependOffsetDeref(const DataLayout & DL,Value * Start,DIExpression * Expression)267e3b55780SDimitry Andric walkToAllocaAndPrependOffsetDeref(const DataLayout &DL, Value *Start,
268e3b55780SDimitry Andric DIExpression *Expression) {
269e3b55780SDimitry Andric APInt OffsetInBytes(DL.getTypeSizeInBits(Start->getType()), false);
270e3b55780SDimitry Andric Value *End =
271e3b55780SDimitry Andric Start->stripAndAccumulateInBoundsConstantOffsets(DL, OffsetInBytes);
272e3b55780SDimitry Andric SmallVector<uint64_t, 3> Ops;
273e3b55780SDimitry Andric if (OffsetInBytes.getBoolValue()) {
274e3b55780SDimitry Andric Ops = {dwarf::DW_OP_plus_uconst, OffsetInBytes.getZExtValue()};
275e3b55780SDimitry Andric Expression = DIExpression::prependOpcodes(
276e3b55780SDimitry Andric Expression, Ops, /*StackValue=*/false, /*EntryValue=*/false);
277e3b55780SDimitry Andric }
278e3b55780SDimitry Andric Expression = DIExpression::append(Expression, {dwarf::DW_OP_deref});
279e3b55780SDimitry Andric return {End, Expression};
280e3b55780SDimitry Andric }
281e3b55780SDimitry Andric
282e3b55780SDimitry Andric /// Extract the offset used in \p DIExpr. Returns std::nullopt if the expression
283e3b55780SDimitry Andric /// doesn't explicitly describe a memory location with DW_OP_deref or if the
284e3b55780SDimitry Andric /// expression is too complex to interpret.
285e3b55780SDimitry Andric static std::optional<int64_t>
getDerefOffsetInBytes(const DIExpression * DIExpr)286e3b55780SDimitry Andric getDerefOffsetInBytes(const DIExpression *DIExpr) {
287e3b55780SDimitry Andric int64_t Offset = 0;
288e3b55780SDimitry Andric const unsigned NumElements = DIExpr->getNumElements();
289e3b55780SDimitry Andric const auto Elements = DIExpr->getElements();
2907fa27ce4SDimitry Andric unsigned ExpectedDerefIdx = 0;
291e3b55780SDimitry Andric // Extract the offset.
292e3b55780SDimitry Andric if (NumElements > 2 && Elements[0] == dwarf::DW_OP_plus_uconst) {
293e3b55780SDimitry Andric Offset = Elements[1];
2947fa27ce4SDimitry Andric ExpectedDerefIdx = 2;
295e3b55780SDimitry Andric } else if (NumElements > 3 && Elements[0] == dwarf::DW_OP_constu) {
2967fa27ce4SDimitry Andric ExpectedDerefIdx = 3;
297e3b55780SDimitry Andric if (Elements[2] == dwarf::DW_OP_plus)
298e3b55780SDimitry Andric Offset = Elements[1];
299e3b55780SDimitry Andric else if (Elements[2] == dwarf::DW_OP_minus)
300e3b55780SDimitry Andric Offset = -Elements[1];
301e3b55780SDimitry Andric else
302e3b55780SDimitry Andric return std::nullopt;
303e3b55780SDimitry Andric }
304e3b55780SDimitry Andric
305e3b55780SDimitry Andric // If that's all there is it means there's no deref.
3067fa27ce4SDimitry Andric if (ExpectedDerefIdx >= NumElements)
307e3b55780SDimitry Andric return std::nullopt;
308e3b55780SDimitry Andric
309e3b55780SDimitry Andric // Check the next element is DW_OP_deref - otherwise this is too complex or
310e3b55780SDimitry Andric // isn't a deref expression.
3117fa27ce4SDimitry Andric if (Elements[ExpectedDerefIdx] != dwarf::DW_OP_deref)
312e3b55780SDimitry Andric return std::nullopt;
313e3b55780SDimitry Andric
314e3b55780SDimitry Andric // Check the final operation is either the DW_OP_deref or is a fragment.
3157fa27ce4SDimitry Andric if (NumElements == ExpectedDerefIdx + 1)
316e3b55780SDimitry Andric return Offset; // Ends with deref.
3177fa27ce4SDimitry Andric unsigned ExpectedFragFirstIdx = ExpectedDerefIdx + 1;
3187fa27ce4SDimitry Andric unsigned ExpectedFragFinalIdx = ExpectedFragFirstIdx + 2;
3197fa27ce4SDimitry Andric if (NumElements == ExpectedFragFinalIdx + 1 &&
3207fa27ce4SDimitry Andric Elements[ExpectedFragFirstIdx] == dwarf::DW_OP_LLVM_fragment)
321e3b55780SDimitry Andric return Offset; // Ends with deref + fragment.
322e3b55780SDimitry Andric
323e3b55780SDimitry Andric // Don't bother trying to interpret anything more complex.
324e3b55780SDimitry Andric return std::nullopt;
325e3b55780SDimitry Andric }
326e3b55780SDimitry Andric
327e3b55780SDimitry Andric /// A whole (unfragmented) source variable.
328e3b55780SDimitry Andric using DebugAggregate = std::pair<const DILocalVariable *, const DILocation *>;
getAggregate(const DbgVariableIntrinsic * DII)329e3b55780SDimitry Andric static DebugAggregate getAggregate(const DbgVariableIntrinsic *DII) {
330e3b55780SDimitry Andric return DebugAggregate(DII->getVariable(), DII->getDebugLoc().getInlinedAt());
331e3b55780SDimitry Andric }
getAggregate(const DebugVariable & Var)332e3b55780SDimitry Andric static DebugAggregate getAggregate(const DebugVariable &Var) {
333e3b55780SDimitry Andric return DebugAggregate(Var.getVariable(), Var.getInlinedAt());
334e3b55780SDimitry Andric }
335e3b55780SDimitry Andric
shouldCoalesceFragments(Function & F)3367fa27ce4SDimitry Andric static bool shouldCoalesceFragments(Function &F) {
3377fa27ce4SDimitry Andric // Enabling fragment coalescing reduces compiler run time when instruction
3387fa27ce4SDimitry Andric // referencing is enabled. However, it may cause LiveDebugVariables to create
3397fa27ce4SDimitry Andric // incorrect locations. Since instruction-referencing mode effectively
3407fa27ce4SDimitry Andric // bypasses LiveDebugVariables we only enable coalescing if the cl::opt flag
3417fa27ce4SDimitry Andric // has not been explicitly set and instruction-referencing is turned on.
3427fa27ce4SDimitry Andric switch (CoalesceAdjacentFragmentsOpt) {
3437fa27ce4SDimitry Andric case cl::boolOrDefault::BOU_UNSET:
3447fa27ce4SDimitry Andric return debuginfoShouldUseDebugInstrRef(
3457fa27ce4SDimitry Andric Triple(F.getParent()->getTargetTriple()));
3467fa27ce4SDimitry Andric case cl::boolOrDefault::BOU_TRUE:
3477fa27ce4SDimitry Andric return true;
3487fa27ce4SDimitry Andric case cl::boolOrDefault::BOU_FALSE:
3497fa27ce4SDimitry Andric return false;
3507fa27ce4SDimitry Andric }
3517fa27ce4SDimitry Andric llvm_unreachable("Unknown boolOrDefault value");
3527fa27ce4SDimitry Andric }
3537fa27ce4SDimitry Andric
354e3b55780SDimitry Andric namespace {
355e3b55780SDimitry Andric /// In dwarf emission, the following sequence
356e3b55780SDimitry Andric /// 1. dbg.value ... Fragment(0, 64)
357e3b55780SDimitry Andric /// 2. dbg.value ... Fragment(0, 32)
358e3b55780SDimitry Andric /// effectively sets Fragment(32, 32) to undef (each def sets all bits not in
359e3b55780SDimitry Andric /// the intersection of the fragments to having "no location"). This makes
360e3b55780SDimitry Andric /// sense for implicit location values because splitting the computed values
361e3b55780SDimitry Andric /// could be troublesome, and is probably quite uncommon. When we convert
362e3b55780SDimitry Andric /// dbg.assigns to dbg.value+deref this kind of thing is common, and describing
363e3b55780SDimitry Andric /// a location (memory) rather than a value means we don't need to worry about
364e3b55780SDimitry Andric /// splitting any values, so we try to recover the rest of the fragment
365e3b55780SDimitry Andric /// location here.
366e3b55780SDimitry Andric /// This class performs a(nother) dataflow analysis over the function, adding
367e3b55780SDimitry Andric /// variable locations so that any bits of a variable with a memory location
368e3b55780SDimitry Andric /// have that location explicitly reinstated at each subsequent variable
369e3b55780SDimitry Andric /// location definition that that doesn't overwrite those bits. i.e. after a
370e3b55780SDimitry Andric /// variable location def, insert new defs for the memory location with
371e3b55780SDimitry Andric /// fragments for the difference of "all bits currently in memory" and "the
372e3b55780SDimitry Andric /// fragment of the second def".
373e3b55780SDimitry Andric class MemLocFragmentFill {
374e3b55780SDimitry Andric Function &Fn;
375e3b55780SDimitry Andric FunctionVarLocsBuilder *FnVarLocs;
376e3b55780SDimitry Andric const DenseSet<DebugAggregate> *VarsWithStackSlot;
3777fa27ce4SDimitry Andric bool CoalesceAdjacentFragments;
378e3b55780SDimitry Andric
379e3b55780SDimitry Andric // 0 = no memory location.
380e3b55780SDimitry Andric using BaseAddress = unsigned;
381e3b55780SDimitry Andric using OffsetInBitsTy = unsigned;
382e3b55780SDimitry Andric using FragTraits = IntervalMapHalfOpenInfo<OffsetInBitsTy>;
383e3b55780SDimitry Andric using FragsInMemMap = IntervalMap<
384e3b55780SDimitry Andric OffsetInBitsTy, BaseAddress,
385e3b55780SDimitry Andric IntervalMapImpl::NodeSizer<OffsetInBitsTy, BaseAddress>::LeafSize,
386e3b55780SDimitry Andric FragTraits>;
387e3b55780SDimitry Andric FragsInMemMap::Allocator IntervalMapAlloc;
388e3b55780SDimitry Andric using VarFragMap = DenseMap<unsigned, FragsInMemMap>;
389e3b55780SDimitry Andric
390e3b55780SDimitry Andric /// IDs for memory location base addresses in maps. Use 0 to indicate that
391e3b55780SDimitry Andric /// there's no memory location.
3927fa27ce4SDimitry Andric UniqueVector<RawLocationWrapper> Bases;
393e3b55780SDimitry Andric UniqueVector<DebugAggregate> Aggregates;
394e3b55780SDimitry Andric DenseMap<const BasicBlock *, VarFragMap> LiveIn;
395e3b55780SDimitry Andric DenseMap<const BasicBlock *, VarFragMap> LiveOut;
396e3b55780SDimitry Andric
397e3b55780SDimitry Andric struct FragMemLoc {
398e3b55780SDimitry Andric unsigned Var;
399e3b55780SDimitry Andric unsigned Base;
400e3b55780SDimitry Andric unsigned OffsetInBits;
401e3b55780SDimitry Andric unsigned SizeInBits;
402e3b55780SDimitry Andric DebugLoc DL;
403e3b55780SDimitry Andric };
4044df029ccSDimitry Andric using InsertMap = MapVector<VarLocInsertPt, SmallVector<FragMemLoc>>;
405e3b55780SDimitry Andric
406e3b55780SDimitry Andric /// BBInsertBeforeMap holds a description for the set of location defs to be
407e3b55780SDimitry Andric /// inserted after the analysis is complete. It is updated during the dataflow
408e3b55780SDimitry Andric /// and the entry for a block is CLEARED each time it is (re-)visited. After
409e3b55780SDimitry Andric /// the dataflow is complete, each block entry will contain the set of defs
410e3b55780SDimitry Andric /// calculated during the final (fixed-point) iteration.
411e3b55780SDimitry Andric DenseMap<const BasicBlock *, InsertMap> BBInsertBeforeMap;
412e3b55780SDimitry Andric
intervalMapsAreEqual(const FragsInMemMap & A,const FragsInMemMap & B)413e3b55780SDimitry Andric static bool intervalMapsAreEqual(const FragsInMemMap &A,
414e3b55780SDimitry Andric const FragsInMemMap &B) {
415e3b55780SDimitry Andric auto AIt = A.begin(), AEnd = A.end();
416e3b55780SDimitry Andric auto BIt = B.begin(), BEnd = B.end();
417e3b55780SDimitry Andric for (; AIt != AEnd; ++AIt, ++BIt) {
418e3b55780SDimitry Andric if (BIt == BEnd)
419e3b55780SDimitry Andric return false; // B has fewer elements than A.
420e3b55780SDimitry Andric if (AIt.start() != BIt.start() || AIt.stop() != BIt.stop())
421e3b55780SDimitry Andric return false; // Interval is different.
422e3b55780SDimitry Andric if (*AIt != *BIt)
423e3b55780SDimitry Andric return false; // Value at interval is different.
424e3b55780SDimitry Andric }
425e3b55780SDimitry Andric // AIt == AEnd. Check BIt is also now at end.
426e3b55780SDimitry Andric return BIt == BEnd;
427e3b55780SDimitry Andric }
428e3b55780SDimitry Andric
varFragMapsAreEqual(const VarFragMap & A,const VarFragMap & B)429e3b55780SDimitry Andric static bool varFragMapsAreEqual(const VarFragMap &A, const VarFragMap &B) {
430e3b55780SDimitry Andric if (A.size() != B.size())
431e3b55780SDimitry Andric return false;
432e3b55780SDimitry Andric for (const auto &APair : A) {
433e3b55780SDimitry Andric auto BIt = B.find(APair.first);
434e3b55780SDimitry Andric if (BIt == B.end())
435e3b55780SDimitry Andric return false;
436e3b55780SDimitry Andric if (!intervalMapsAreEqual(APair.second, BIt->second))
437e3b55780SDimitry Andric return false;
438e3b55780SDimitry Andric }
439e3b55780SDimitry Andric return true;
440e3b55780SDimitry Andric }
441e3b55780SDimitry Andric
442e3b55780SDimitry Andric /// Return a string for the value that \p BaseID represents.
toString(unsigned BaseID)443e3b55780SDimitry Andric std::string toString(unsigned BaseID) {
444e3b55780SDimitry Andric if (BaseID)
4457fa27ce4SDimitry Andric return Bases[BaseID].getVariableLocationOp(0)->getName().str();
446e3b55780SDimitry Andric else
447e3b55780SDimitry Andric return "None";
448e3b55780SDimitry Andric }
449e3b55780SDimitry Andric
450e3b55780SDimitry Andric /// Format string describing an FragsInMemMap (IntervalMap) interval.
toString(FragsInMemMap::const_iterator It,bool Newline=true)451e3b55780SDimitry Andric std::string toString(FragsInMemMap::const_iterator It, bool Newline = true) {
452e3b55780SDimitry Andric std::string String;
453e3b55780SDimitry Andric std::stringstream S(String);
454e3b55780SDimitry Andric if (It.valid()) {
455e3b55780SDimitry Andric S << "[" << It.start() << ", " << It.stop()
456e3b55780SDimitry Andric << "): " << toString(It.value());
457e3b55780SDimitry Andric } else {
458e3b55780SDimitry Andric S << "invalid iterator (end)";
459e3b55780SDimitry Andric }
460e3b55780SDimitry Andric if (Newline)
461e3b55780SDimitry Andric S << "\n";
462e3b55780SDimitry Andric return S.str();
463e3b55780SDimitry Andric };
464e3b55780SDimitry Andric
meetFragments(const FragsInMemMap & A,const FragsInMemMap & B)465e3b55780SDimitry Andric FragsInMemMap meetFragments(const FragsInMemMap &A, const FragsInMemMap &B) {
466e3b55780SDimitry Andric FragsInMemMap Result(IntervalMapAlloc);
467e3b55780SDimitry Andric for (auto AIt = A.begin(), AEnd = A.end(); AIt != AEnd; ++AIt) {
468e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << "a " << toString(AIt));
469e3b55780SDimitry Andric // This is basically copied from process() and inverted (process is
470e3b55780SDimitry Andric // performing something like a union whereas this is more of an
471e3b55780SDimitry Andric // intersect).
472e3b55780SDimitry Andric
473e3b55780SDimitry Andric // There's no work to do if interval `a` overlaps no fragments in map `B`.
474e3b55780SDimitry Andric if (!B.overlaps(AIt.start(), AIt.stop()))
475e3b55780SDimitry Andric continue;
476e3b55780SDimitry Andric
477e3b55780SDimitry Andric // Does StartBit intersect an existing fragment?
478e3b55780SDimitry Andric auto FirstOverlap = B.find(AIt.start());
479e3b55780SDimitry Andric assert(FirstOverlap != B.end());
480e3b55780SDimitry Andric bool IntersectStart = FirstOverlap.start() < AIt.start();
481e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << "- FirstOverlap " << toString(FirstOverlap, false)
482e3b55780SDimitry Andric << ", IntersectStart: " << IntersectStart << "\n");
483e3b55780SDimitry Andric
484e3b55780SDimitry Andric // Does EndBit intersect an existing fragment?
485e3b55780SDimitry Andric auto LastOverlap = B.find(AIt.stop());
486e3b55780SDimitry Andric bool IntersectEnd =
487e3b55780SDimitry Andric LastOverlap != B.end() && LastOverlap.start() < AIt.stop();
488e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << "- LastOverlap " << toString(LastOverlap, false)
489e3b55780SDimitry Andric << ", IntersectEnd: " << IntersectEnd << "\n");
490e3b55780SDimitry Andric
491e3b55780SDimitry Andric // Check if both ends of `a` intersect the same interval `b`.
492e3b55780SDimitry Andric if (IntersectStart && IntersectEnd && FirstOverlap == LastOverlap) {
493e3b55780SDimitry Andric // Insert `a` (`a` is contained in `b`) if the values match.
494e3b55780SDimitry Andric // [ a ]
495e3b55780SDimitry Andric // [ - b - ]
496e3b55780SDimitry Andric // -
497e3b55780SDimitry Andric // [ r ]
498e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << "- a is contained within "
499e3b55780SDimitry Andric << toString(FirstOverlap));
500e3b55780SDimitry Andric if (*AIt && *AIt == *FirstOverlap)
501e3b55780SDimitry Andric Result.insert(AIt.start(), AIt.stop(), *AIt);
502e3b55780SDimitry Andric } else {
503e3b55780SDimitry Andric // There's an overlap but `a` is not fully contained within
504e3b55780SDimitry Andric // `b`. Shorten any end-point intersections.
505e3b55780SDimitry Andric // [ - a - ]
506e3b55780SDimitry Andric // [ - b - ]
507e3b55780SDimitry Andric // -
508e3b55780SDimitry Andric // [ r ]
509e3b55780SDimitry Andric auto Next = FirstOverlap;
510e3b55780SDimitry Andric if (IntersectStart) {
511e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << "- insert intersection of a and "
512e3b55780SDimitry Andric << toString(FirstOverlap));
513e3b55780SDimitry Andric if (*AIt && *AIt == *FirstOverlap)
514e3b55780SDimitry Andric Result.insert(AIt.start(), FirstOverlap.stop(), *AIt);
515e3b55780SDimitry Andric ++Next;
516e3b55780SDimitry Andric }
517e3b55780SDimitry Andric // [ - a - ]
518e3b55780SDimitry Andric // [ - b - ]
519e3b55780SDimitry Andric // -
520e3b55780SDimitry Andric // [ r ]
521e3b55780SDimitry Andric if (IntersectEnd) {
522e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << "- insert intersection of a and "
523e3b55780SDimitry Andric << toString(LastOverlap));
524e3b55780SDimitry Andric if (*AIt && *AIt == *LastOverlap)
525e3b55780SDimitry Andric Result.insert(LastOverlap.start(), AIt.stop(), *AIt);
526e3b55780SDimitry Andric }
527e3b55780SDimitry Andric
528e3b55780SDimitry Andric // Insert all intervals in map `B` that are contained within interval
529e3b55780SDimitry Andric // `a` where the values match.
530e3b55780SDimitry Andric // [ - - a - - ]
531e3b55780SDimitry Andric // [ b1 ] [ b2 ]
532e3b55780SDimitry Andric // -
533e3b55780SDimitry Andric // [ r1 ] [ r2 ]
534e3b55780SDimitry Andric while (Next != B.end() && Next.start() < AIt.stop() &&
535e3b55780SDimitry Andric Next.stop() <= AIt.stop()) {
536e3b55780SDimitry Andric LLVM_DEBUG(dbgs()
537e3b55780SDimitry Andric << "- insert intersection of a and " << toString(Next));
538e3b55780SDimitry Andric if (*AIt && *AIt == *Next)
539e3b55780SDimitry Andric Result.insert(Next.start(), Next.stop(), *Next);
540e3b55780SDimitry Andric ++Next;
541e3b55780SDimitry Andric }
542e3b55780SDimitry Andric }
543e3b55780SDimitry Andric }
544e3b55780SDimitry Andric return Result;
545e3b55780SDimitry Andric }
546e3b55780SDimitry Andric
547e3b55780SDimitry Andric /// Meet \p A and \p B, storing the result in \p A.
meetVars(VarFragMap & A,const VarFragMap & B)548e3b55780SDimitry Andric void meetVars(VarFragMap &A, const VarFragMap &B) {
549e3b55780SDimitry Andric // Meet A and B.
550e3b55780SDimitry Andric //
551e3b55780SDimitry Andric // Result = meet(a, b) for a in A, b in B where Var(a) == Var(b)
552e3b55780SDimitry Andric for (auto It = A.begin(), End = A.end(); It != End; ++It) {
553e3b55780SDimitry Andric unsigned AVar = It->first;
554e3b55780SDimitry Andric FragsInMemMap &AFrags = It->second;
555e3b55780SDimitry Andric auto BIt = B.find(AVar);
556e3b55780SDimitry Andric if (BIt == B.end()) {
557e3b55780SDimitry Andric A.erase(It);
558e3b55780SDimitry Andric continue; // Var has no bits defined in B.
559e3b55780SDimitry Andric }
560e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << "meet fragment maps for "
561e3b55780SDimitry Andric << Aggregates[AVar].first->getName() << "\n");
562e3b55780SDimitry Andric AFrags = meetFragments(AFrags, BIt->second);
563e3b55780SDimitry Andric }
564e3b55780SDimitry Andric }
565e3b55780SDimitry Andric
meet(const BasicBlock & BB,const SmallPtrSet<BasicBlock *,16> & Visited)566e3b55780SDimitry Andric bool meet(const BasicBlock &BB,
567e3b55780SDimitry Andric const SmallPtrSet<BasicBlock *, 16> &Visited) {
568e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << "meet block info from preds of " << BB.getName()
569e3b55780SDimitry Andric << "\n");
570e3b55780SDimitry Andric
571e3b55780SDimitry Andric VarFragMap BBLiveIn;
572e3b55780SDimitry Andric bool FirstMeet = true;
573e3b55780SDimitry Andric // LiveIn locs for BB is the meet of the already-processed preds' LiveOut
574e3b55780SDimitry Andric // locs.
575ac9a064cSDimitry Andric for (const BasicBlock *Pred : predecessors(&BB)) {
576e3b55780SDimitry Andric // Ignore preds that haven't been processed yet. This is essentially the
577e3b55780SDimitry Andric // same as initialising all variables to implicit top value (⊤) which is
578e3b55780SDimitry Andric // the identity value for the meet operation.
579e3b55780SDimitry Andric if (!Visited.count(Pred))
580e3b55780SDimitry Andric continue;
581e3b55780SDimitry Andric
582e3b55780SDimitry Andric auto PredLiveOut = LiveOut.find(Pred);
583e3b55780SDimitry Andric assert(PredLiveOut != LiveOut.end());
584e3b55780SDimitry Andric
585e3b55780SDimitry Andric if (FirstMeet) {
586e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << "BBLiveIn = " << Pred->getName() << "\n");
587e3b55780SDimitry Andric BBLiveIn = PredLiveOut->second;
588e3b55780SDimitry Andric FirstMeet = false;
589e3b55780SDimitry Andric } else {
590e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << "BBLiveIn = meet BBLiveIn, " << Pred->getName()
591e3b55780SDimitry Andric << "\n");
592e3b55780SDimitry Andric meetVars(BBLiveIn, PredLiveOut->second);
593e3b55780SDimitry Andric }
594e3b55780SDimitry Andric
595e3b55780SDimitry Andric // An empty set is ⊥ for the intersect-like meet operation. If we've
596e3b55780SDimitry Andric // already got ⊥ there's no need to run the code - we know the result is
597e3b55780SDimitry Andric // ⊥ since `meet(a, ⊥) = ⊥`.
598e3b55780SDimitry Andric if (BBLiveIn.size() == 0)
599e3b55780SDimitry Andric break;
600e3b55780SDimitry Andric }
601e3b55780SDimitry Andric
602e3b55780SDimitry Andric auto CurrentLiveInEntry = LiveIn.find(&BB);
603e3b55780SDimitry Andric // If there's no LiveIn entry for the block yet, add it.
604e3b55780SDimitry Andric if (CurrentLiveInEntry == LiveIn.end()) {
605e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << "change=true (first) on meet on " << BB.getName()
606e3b55780SDimitry Andric << "\n");
607e3b55780SDimitry Andric LiveIn[&BB] = std::move(BBLiveIn);
608e3b55780SDimitry Andric return /*Changed=*/true;
609e3b55780SDimitry Andric }
610e3b55780SDimitry Andric
611e3b55780SDimitry Andric // If the LiveIn set has changed (expensive check) update it and return
612e3b55780SDimitry Andric // true.
613e3b55780SDimitry Andric if (!varFragMapsAreEqual(BBLiveIn, CurrentLiveInEntry->second)) {
614e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << "change=true on meet on " << BB.getName() << "\n");
615e3b55780SDimitry Andric CurrentLiveInEntry->second = std::move(BBLiveIn);
616e3b55780SDimitry Andric return /*Changed=*/true;
617e3b55780SDimitry Andric }
618e3b55780SDimitry Andric
619e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << "change=false on meet on " << BB.getName() << "\n");
620e3b55780SDimitry Andric return /*Changed=*/false;
621e3b55780SDimitry Andric }
622e3b55780SDimitry Andric
insertMemLoc(BasicBlock & BB,VarLocInsertPt Before,unsigned Var,unsigned StartBit,unsigned EndBit,unsigned Base,DebugLoc DL)6234df029ccSDimitry Andric void insertMemLoc(BasicBlock &BB, VarLocInsertPt Before, unsigned Var,
624e3b55780SDimitry Andric unsigned StartBit, unsigned EndBit, unsigned Base,
625e3b55780SDimitry Andric DebugLoc DL) {
626e3b55780SDimitry Andric assert(StartBit < EndBit && "Cannot create fragment of size <= 0");
627e3b55780SDimitry Andric if (!Base)
628e3b55780SDimitry Andric return;
629e3b55780SDimitry Andric FragMemLoc Loc;
630e3b55780SDimitry Andric Loc.Var = Var;
631e3b55780SDimitry Andric Loc.OffsetInBits = StartBit;
632e3b55780SDimitry Andric Loc.SizeInBits = EndBit - StartBit;
633e3b55780SDimitry Andric assert(Base && "Expected a non-zero ID for Base address");
634e3b55780SDimitry Andric Loc.Base = Base;
635e3b55780SDimitry Andric Loc.DL = DL;
6364df029ccSDimitry Andric BBInsertBeforeMap[&BB][Before].push_back(Loc);
637e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << "Add mem def for " << Aggregates[Var].first->getName()
638e3b55780SDimitry Andric << " bits [" << StartBit << ", " << EndBit << ")\n");
639e3b55780SDimitry Andric }
640e3b55780SDimitry Andric
6417fa27ce4SDimitry Andric /// Inserts a new dbg def if the interval found when looking up \p StartBit
6427fa27ce4SDimitry Andric /// in \p FragMap starts before \p StartBit or ends after \p EndBit (which
6437fa27ce4SDimitry Andric /// indicates - assuming StartBit->EndBit has just been inserted - that the
6447fa27ce4SDimitry Andric /// slice has been coalesced in the map).
coalesceFragments(BasicBlock & BB,VarLocInsertPt Before,unsigned Var,unsigned StartBit,unsigned EndBit,unsigned Base,DebugLoc DL,const FragsInMemMap & FragMap)6454df029ccSDimitry Andric void coalesceFragments(BasicBlock &BB, VarLocInsertPt Before, unsigned Var,
6467fa27ce4SDimitry Andric unsigned StartBit, unsigned EndBit, unsigned Base,
6477fa27ce4SDimitry Andric DebugLoc DL, const FragsInMemMap &FragMap) {
6487fa27ce4SDimitry Andric if (!CoalesceAdjacentFragments)
6497fa27ce4SDimitry Andric return;
6507fa27ce4SDimitry Andric // We've inserted the location into the map. The map will have coalesced
6517fa27ce4SDimitry Andric // adjacent intervals (variable fragments) that describe the same memory
6527fa27ce4SDimitry Andric // location. Use this knowledge to insert a debug location that describes
6537fa27ce4SDimitry Andric // that coalesced fragment. This may eclipse other locs we've just
6547fa27ce4SDimitry Andric // inserted. This is okay as redundant locs will be cleaned up later.
6557fa27ce4SDimitry Andric auto CoalescedFrag = FragMap.find(StartBit);
6567fa27ce4SDimitry Andric // Bail if no coalescing has taken place.
6577fa27ce4SDimitry Andric if (CoalescedFrag.start() == StartBit && CoalescedFrag.stop() == EndBit)
6587fa27ce4SDimitry Andric return;
6597fa27ce4SDimitry Andric
6607fa27ce4SDimitry Andric LLVM_DEBUG(dbgs() << "- Insert loc for bits " << CoalescedFrag.start()
6617fa27ce4SDimitry Andric << " to " << CoalescedFrag.stop() << "\n");
6627fa27ce4SDimitry Andric insertMemLoc(BB, Before, Var, CoalescedFrag.start(), CoalescedFrag.stop(),
6637fa27ce4SDimitry Andric Base, DL);
6647fa27ce4SDimitry Andric }
6657fa27ce4SDimitry Andric
addDef(const VarLocInfo & VarLoc,VarLocInsertPt Before,BasicBlock & BB,VarFragMap & LiveSet)6664df029ccSDimitry Andric void addDef(const VarLocInfo &VarLoc, VarLocInsertPt Before, BasicBlock &BB,
667e3b55780SDimitry Andric VarFragMap &LiveSet) {
668e3b55780SDimitry Andric DebugVariable DbgVar = FnVarLocs->getVariable(VarLoc.VariableID);
669e3b55780SDimitry Andric if (skipVariable(DbgVar.getVariable()))
670e3b55780SDimitry Andric return;
671e3b55780SDimitry Andric // Don't bother doing anything for this variables if we know it's fully
672e3b55780SDimitry Andric // promoted. We're only interested in variables that (sometimes) live on
673e3b55780SDimitry Andric // the stack here.
674e3b55780SDimitry Andric if (!VarsWithStackSlot->count(getAggregate(DbgVar)))
675e3b55780SDimitry Andric return;
676e3b55780SDimitry Andric unsigned Var = Aggregates.insert(
677e3b55780SDimitry Andric DebugAggregate(DbgVar.getVariable(), VarLoc.DL.getInlinedAt()));
678e3b55780SDimitry Andric
679e3b55780SDimitry Andric // [StartBit: EndBit) are the bits affected by this def.
680e3b55780SDimitry Andric const DIExpression *DIExpr = VarLoc.Expr;
681e3b55780SDimitry Andric unsigned StartBit;
682e3b55780SDimitry Andric unsigned EndBit;
683e3b55780SDimitry Andric if (auto Frag = DIExpr->getFragmentInfo()) {
684e3b55780SDimitry Andric StartBit = Frag->OffsetInBits;
685e3b55780SDimitry Andric EndBit = StartBit + Frag->SizeInBits;
686e3b55780SDimitry Andric } else {
687e3b55780SDimitry Andric assert(static_cast<bool>(DbgVar.getVariable()->getSizeInBits()));
688e3b55780SDimitry Andric StartBit = 0;
689e3b55780SDimitry Andric EndBit = *DbgVar.getVariable()->getSizeInBits();
690e3b55780SDimitry Andric }
691e3b55780SDimitry Andric
692e3b55780SDimitry Andric // We will only fill fragments for simple memory-describing dbg.value
693e3b55780SDimitry Andric // intrinsics. If the fragment offset is the same as the offset from the
694e3b55780SDimitry Andric // base pointer, do The Thing, otherwise fall back to normal dbg.value
695e3b55780SDimitry Andric // behaviour. AssignmentTrackingLowering has generated DIExpressions
696e3b55780SDimitry Andric // written in terms of the base pointer.
697e3b55780SDimitry Andric // TODO: Remove this condition since the fragment offset doesn't always
698e3b55780SDimitry Andric // equal the offset from base pointer (e.g. for a SROA-split variable).
699e3b55780SDimitry Andric const auto DerefOffsetInBytes = getDerefOffsetInBytes(DIExpr);
700e3b55780SDimitry Andric const unsigned Base =
701e3b55780SDimitry Andric DerefOffsetInBytes && *DerefOffsetInBytes * 8 == StartBit
7027fa27ce4SDimitry Andric ? Bases.insert(VarLoc.Values)
703e3b55780SDimitry Andric : 0;
704e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << "DEF " << DbgVar.getVariable()->getName() << " ["
705e3b55780SDimitry Andric << StartBit << ", " << EndBit << "): " << toString(Base)
706e3b55780SDimitry Andric << "\n");
707e3b55780SDimitry Andric
708e3b55780SDimitry Andric // First of all, any locs that use mem that are disrupted need reinstating.
709e3b55780SDimitry Andric // Unfortunately, IntervalMap doesn't let us insert intervals that overlap
710e3b55780SDimitry Andric // with existing intervals so this code involves a lot of fiddling around
711e3b55780SDimitry Andric // with intervals to do that manually.
712e3b55780SDimitry Andric auto FragIt = LiveSet.find(Var);
713e3b55780SDimitry Andric
714e3b55780SDimitry Andric // Check if the variable does not exist in the map.
715e3b55780SDimitry Andric if (FragIt == LiveSet.end()) {
716e3b55780SDimitry Andric // Add this variable to the BB map.
717e3b55780SDimitry Andric auto P = LiveSet.try_emplace(Var, FragsInMemMap(IntervalMapAlloc));
718e3b55780SDimitry Andric assert(P.second && "Var already in map?");
719e3b55780SDimitry Andric // Add the interval to the fragment map.
720e3b55780SDimitry Andric P.first->second.insert(StartBit, EndBit, Base);
721e3b55780SDimitry Andric return;
722e3b55780SDimitry Andric }
723e3b55780SDimitry Andric // The variable has an entry in the map.
724e3b55780SDimitry Andric
725e3b55780SDimitry Andric FragsInMemMap &FragMap = FragIt->second;
726e3b55780SDimitry Andric // First check the easy case: the new fragment `f` doesn't overlap with any
727e3b55780SDimitry Andric // intervals.
728e3b55780SDimitry Andric if (!FragMap.overlaps(StartBit, EndBit)) {
729e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << "- No overlaps\n");
730e3b55780SDimitry Andric FragMap.insert(StartBit, EndBit, Base);
7317fa27ce4SDimitry Andric coalesceFragments(BB, Before, Var, StartBit, EndBit, Base, VarLoc.DL,
7327fa27ce4SDimitry Andric FragMap);
733e3b55780SDimitry Andric return;
734e3b55780SDimitry Andric }
735e3b55780SDimitry Andric // There is at least one overlap.
736e3b55780SDimitry Andric
737e3b55780SDimitry Andric // Does StartBit intersect an existing fragment?
738e3b55780SDimitry Andric auto FirstOverlap = FragMap.find(StartBit);
739e3b55780SDimitry Andric assert(FirstOverlap != FragMap.end());
740e3b55780SDimitry Andric bool IntersectStart = FirstOverlap.start() < StartBit;
741e3b55780SDimitry Andric
742e3b55780SDimitry Andric // Does EndBit intersect an existing fragment?
743e3b55780SDimitry Andric auto LastOverlap = FragMap.find(EndBit);
744e3b55780SDimitry Andric bool IntersectEnd = LastOverlap.valid() && LastOverlap.start() < EndBit;
745e3b55780SDimitry Andric
746e3b55780SDimitry Andric // Check if both ends of `f` intersect the same interval `i`.
747e3b55780SDimitry Andric if (IntersectStart && IntersectEnd && FirstOverlap == LastOverlap) {
748e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << "- Intersect single interval @ both ends\n");
749e3b55780SDimitry Andric // Shorten `i` so that there's space to insert `f`.
750e3b55780SDimitry Andric // [ f ]
751e3b55780SDimitry Andric // [ - i - ]
752e3b55780SDimitry Andric // +
753e3b55780SDimitry Andric // [ i ][ f ][ i ]
754e3b55780SDimitry Andric
755e3b55780SDimitry Andric // Save values for use after inserting a new interval.
756e3b55780SDimitry Andric auto EndBitOfOverlap = FirstOverlap.stop();
757e3b55780SDimitry Andric unsigned OverlapValue = FirstOverlap.value();
758e3b55780SDimitry Andric
759e3b55780SDimitry Andric // Shorten the overlapping interval.
760e3b55780SDimitry Andric FirstOverlap.setStop(StartBit);
761e3b55780SDimitry Andric insertMemLoc(BB, Before, Var, FirstOverlap.start(), StartBit,
762e3b55780SDimitry Andric OverlapValue, VarLoc.DL);
763e3b55780SDimitry Andric
764e3b55780SDimitry Andric // Insert a new interval to represent the end part.
765e3b55780SDimitry Andric FragMap.insert(EndBit, EndBitOfOverlap, OverlapValue);
766e3b55780SDimitry Andric insertMemLoc(BB, Before, Var, EndBit, EndBitOfOverlap, OverlapValue,
767e3b55780SDimitry Andric VarLoc.DL);
768e3b55780SDimitry Andric
769e3b55780SDimitry Andric // Insert the new (middle) fragment now there is space.
770e3b55780SDimitry Andric FragMap.insert(StartBit, EndBit, Base);
771e3b55780SDimitry Andric } else {
772e3b55780SDimitry Andric // There's an overlap but `f` may not be fully contained within
773e3b55780SDimitry Andric // `i`. Shorten any end-point intersections so that we can then
774e3b55780SDimitry Andric // insert `f`.
775e3b55780SDimitry Andric // [ - f - ]
776e3b55780SDimitry Andric // [ - i - ]
777e3b55780SDimitry Andric // | |
778e3b55780SDimitry Andric // [ i ]
779e3b55780SDimitry Andric // Shorten any end-point intersections.
780e3b55780SDimitry Andric if (IntersectStart) {
781e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << "- Intersect interval at start\n");
782e3b55780SDimitry Andric // Split off at the intersection.
783e3b55780SDimitry Andric FirstOverlap.setStop(StartBit);
784e3b55780SDimitry Andric insertMemLoc(BB, Before, Var, FirstOverlap.start(), StartBit,
785e3b55780SDimitry Andric *FirstOverlap, VarLoc.DL);
786e3b55780SDimitry Andric }
787e3b55780SDimitry Andric // [ - f - ]
788e3b55780SDimitry Andric // [ - i - ]
789e3b55780SDimitry Andric // | |
790e3b55780SDimitry Andric // [ i ]
791e3b55780SDimitry Andric if (IntersectEnd) {
792e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << "- Intersect interval at end\n");
793e3b55780SDimitry Andric // Split off at the intersection.
794e3b55780SDimitry Andric LastOverlap.setStart(EndBit);
795e3b55780SDimitry Andric insertMemLoc(BB, Before, Var, EndBit, LastOverlap.stop(), *LastOverlap,
796e3b55780SDimitry Andric VarLoc.DL);
797e3b55780SDimitry Andric }
798e3b55780SDimitry Andric
799e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << "- Erase intervals contained within\n");
800e3b55780SDimitry Andric // FirstOverlap and LastOverlap have been shortened such that they're
801e3b55780SDimitry Andric // no longer overlapping with [StartBit, EndBit). Delete any overlaps
802e3b55780SDimitry Andric // that remain (these will be fully contained within `f`).
803e3b55780SDimitry Andric // [ - f - ] }
804e3b55780SDimitry Andric // [ - i - ] } Intersection shortening that has happened above.
805e3b55780SDimitry Andric // | | }
806e3b55780SDimitry Andric // [ i ] }
807e3b55780SDimitry Andric // -----------------
808e3b55780SDimitry Andric // [i2 ] } Intervals fully contained within `f` get erased.
809e3b55780SDimitry Andric // -----------------
810e3b55780SDimitry Andric // [ - f - ][ i ] } Completed insertion.
811e3b55780SDimitry Andric auto It = FirstOverlap;
812e3b55780SDimitry Andric if (IntersectStart)
813e3b55780SDimitry Andric ++It; // IntersectStart: first overlap has been shortened.
814e3b55780SDimitry Andric while (It.valid() && It.start() >= StartBit && It.stop() <= EndBit) {
815e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << "- Erase " << toString(It));
816e3b55780SDimitry Andric It.erase(); // This increments It after removing the interval.
817e3b55780SDimitry Andric }
818e3b55780SDimitry Andric // We've dealt with all the overlaps now!
819e3b55780SDimitry Andric assert(!FragMap.overlaps(StartBit, EndBit));
820e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << "- Insert DEF into now-empty space\n");
821e3b55780SDimitry Andric FragMap.insert(StartBit, EndBit, Base);
822e3b55780SDimitry Andric }
8237fa27ce4SDimitry Andric
8247fa27ce4SDimitry Andric coalesceFragments(BB, Before, Var, StartBit, EndBit, Base, VarLoc.DL,
8257fa27ce4SDimitry Andric FragMap);
826e3b55780SDimitry Andric }
827e3b55780SDimitry Andric
skipVariable(const DILocalVariable * V)828e3b55780SDimitry Andric bool skipVariable(const DILocalVariable *V) { return !V->getSizeInBits(); }
829e3b55780SDimitry Andric
process(BasicBlock & BB,VarFragMap & LiveSet)830e3b55780SDimitry Andric void process(BasicBlock &BB, VarFragMap &LiveSet) {
831e3b55780SDimitry Andric BBInsertBeforeMap[&BB].clear();
832e3b55780SDimitry Andric for (auto &I : BB) {
833ac9a064cSDimitry Andric for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange())) {
834ac9a064cSDimitry Andric if (const auto *Locs = FnVarLocs->getWedge(&DVR)) {
8354df029ccSDimitry Andric for (const VarLocInfo &Loc : *Locs) {
836ac9a064cSDimitry Andric addDef(Loc, &DVR, *I.getParent(), LiveSet);
8374df029ccSDimitry Andric }
8384df029ccSDimitry Andric }
8394df029ccSDimitry Andric }
840e3b55780SDimitry Andric if (const auto *Locs = FnVarLocs->getWedge(&I)) {
841e3b55780SDimitry Andric for (const VarLocInfo &Loc : *Locs) {
8424df029ccSDimitry Andric addDef(Loc, &I, *I.getParent(), LiveSet);
843e3b55780SDimitry Andric }
844e3b55780SDimitry Andric }
845e3b55780SDimitry Andric }
846e3b55780SDimitry Andric }
847e3b55780SDimitry Andric
848e3b55780SDimitry Andric public:
MemLocFragmentFill(Function & Fn,const DenseSet<DebugAggregate> * VarsWithStackSlot,bool CoalesceAdjacentFragments)849e3b55780SDimitry Andric MemLocFragmentFill(Function &Fn,
8507fa27ce4SDimitry Andric const DenseSet<DebugAggregate> *VarsWithStackSlot,
8517fa27ce4SDimitry Andric bool CoalesceAdjacentFragments)
8527fa27ce4SDimitry Andric : Fn(Fn), VarsWithStackSlot(VarsWithStackSlot),
8537fa27ce4SDimitry Andric CoalesceAdjacentFragments(CoalesceAdjacentFragments) {}
854e3b55780SDimitry Andric
855e3b55780SDimitry Andric /// Add variable locations to \p FnVarLocs so that any bits of a variable
856e3b55780SDimitry Andric /// with a memory location have that location explicitly reinstated at each
857e3b55780SDimitry Andric /// subsequent variable location definition that that doesn't overwrite those
858e3b55780SDimitry Andric /// bits. i.e. after a variable location def, insert new defs for the memory
859e3b55780SDimitry Andric /// location with fragments for the difference of "all bits currently in
860e3b55780SDimitry Andric /// memory" and "the fragment of the second def". e.g.
861e3b55780SDimitry Andric ///
862e3b55780SDimitry Andric /// Before:
863e3b55780SDimitry Andric ///
864e3b55780SDimitry Andric /// var x bits 0 to 63: value in memory
865e3b55780SDimitry Andric /// more instructions
866e3b55780SDimitry Andric /// var x bits 0 to 31: value is %0
867e3b55780SDimitry Andric ///
868e3b55780SDimitry Andric /// After:
869e3b55780SDimitry Andric ///
870e3b55780SDimitry Andric /// var x bits 0 to 63: value in memory
871e3b55780SDimitry Andric /// more instructions
872e3b55780SDimitry Andric /// var x bits 0 to 31: value is %0
873e3b55780SDimitry Andric /// var x bits 32 to 61: value in memory ; <-- new loc def
874e3b55780SDimitry Andric ///
run(FunctionVarLocsBuilder * FnVarLocs)875e3b55780SDimitry Andric void run(FunctionVarLocsBuilder *FnVarLocs) {
876e3b55780SDimitry Andric if (!EnableMemLocFragFill)
877e3b55780SDimitry Andric return;
878e3b55780SDimitry Andric
879e3b55780SDimitry Andric this->FnVarLocs = FnVarLocs;
880e3b55780SDimitry Andric
881e3b55780SDimitry Andric // Prepare for traversal.
882e3b55780SDimitry Andric //
883e3b55780SDimitry Andric ReversePostOrderTraversal<Function *> RPOT(&Fn);
884e3b55780SDimitry Andric std::priority_queue<unsigned int, std::vector<unsigned int>,
885e3b55780SDimitry Andric std::greater<unsigned int>>
886e3b55780SDimitry Andric Worklist;
887e3b55780SDimitry Andric std::priority_queue<unsigned int, std::vector<unsigned int>,
888e3b55780SDimitry Andric std::greater<unsigned int>>
889e3b55780SDimitry Andric Pending;
890e3b55780SDimitry Andric DenseMap<unsigned int, BasicBlock *> OrderToBB;
891e3b55780SDimitry Andric DenseMap<BasicBlock *, unsigned int> BBToOrder;
892e3b55780SDimitry Andric { // Init OrderToBB and BBToOrder.
893e3b55780SDimitry Andric unsigned int RPONumber = 0;
894ac9a064cSDimitry Andric for (BasicBlock *BB : RPOT) {
895ac9a064cSDimitry Andric OrderToBB[RPONumber] = BB;
896ac9a064cSDimitry Andric BBToOrder[BB] = RPONumber;
897e3b55780SDimitry Andric Worklist.push(RPONumber);
898e3b55780SDimitry Andric ++RPONumber;
899e3b55780SDimitry Andric }
900e3b55780SDimitry Andric LiveIn.init(RPONumber);
901e3b55780SDimitry Andric LiveOut.init(RPONumber);
902e3b55780SDimitry Andric }
903e3b55780SDimitry Andric
904e3b55780SDimitry Andric // Perform the traversal.
905e3b55780SDimitry Andric //
906e3b55780SDimitry Andric // This is a standard "intersect of predecessor outs" dataflow problem. To
907e3b55780SDimitry Andric // solve it, we perform meet() and process() using the two worklist method
908e3b55780SDimitry Andric // until the LiveIn data for each block becomes unchanging.
909e3b55780SDimitry Andric //
910e3b55780SDimitry Andric // This dataflow is essentially working on maps of sets and at each meet we
911e3b55780SDimitry Andric // intersect the maps and the mapped sets. So, initialized live-in maps
912e3b55780SDimitry Andric // monotonically decrease in value throughout the dataflow.
913e3b55780SDimitry Andric SmallPtrSet<BasicBlock *, 16> Visited;
914e3b55780SDimitry Andric while (!Worklist.empty() || !Pending.empty()) {
915e3b55780SDimitry Andric // We track what is on the pending worklist to avoid inserting the same
916e3b55780SDimitry Andric // thing twice. We could avoid this with a custom priority queue, but
917e3b55780SDimitry Andric // this is probably not worth it.
918e3b55780SDimitry Andric SmallPtrSet<BasicBlock *, 16> OnPending;
919e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << "Processing Worklist\n");
920e3b55780SDimitry Andric while (!Worklist.empty()) {
921e3b55780SDimitry Andric BasicBlock *BB = OrderToBB[Worklist.top()];
922e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << "\nPop BB " << BB->getName() << "\n");
923e3b55780SDimitry Andric Worklist.pop();
924e3b55780SDimitry Andric bool InChanged = meet(*BB, Visited);
925e3b55780SDimitry Andric // Always consider LiveIn changed on the first visit.
926e3b55780SDimitry Andric InChanged |= Visited.insert(BB).second;
927e3b55780SDimitry Andric if (InChanged) {
928e3b55780SDimitry Andric LLVM_DEBUG(dbgs()
929e3b55780SDimitry Andric << BB->getName() << " has new InLocs, process it\n");
930e3b55780SDimitry Andric // Mutate a copy of LiveIn while processing BB. Once we've processed
931e3b55780SDimitry Andric // the terminator LiveSet is the LiveOut set for BB.
932e3b55780SDimitry Andric // This is an expensive copy!
933e3b55780SDimitry Andric VarFragMap LiveSet = LiveIn[BB];
934e3b55780SDimitry Andric
935e3b55780SDimitry Andric // Process the instructions in the block.
936e3b55780SDimitry Andric process(*BB, LiveSet);
937e3b55780SDimitry Andric
938e3b55780SDimitry Andric // Relatively expensive check: has anything changed in LiveOut for BB?
939e3b55780SDimitry Andric if (!varFragMapsAreEqual(LiveOut[BB], LiveSet)) {
940e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << BB->getName()
941e3b55780SDimitry Andric << " has new OutLocs, add succs to worklist: [ ");
942e3b55780SDimitry Andric LiveOut[BB] = std::move(LiveSet);
943ac9a064cSDimitry Andric for (BasicBlock *Succ : successors(BB)) {
944ac9a064cSDimitry Andric if (OnPending.insert(Succ).second) {
945ac9a064cSDimitry Andric LLVM_DEBUG(dbgs() << Succ->getName() << " ");
946ac9a064cSDimitry Andric Pending.push(BBToOrder[Succ]);
947e3b55780SDimitry Andric }
948e3b55780SDimitry Andric }
949e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << "]\n");
950e3b55780SDimitry Andric }
951e3b55780SDimitry Andric }
952e3b55780SDimitry Andric }
953e3b55780SDimitry Andric Worklist.swap(Pending);
954e3b55780SDimitry Andric // At this point, pending must be empty, since it was just the empty
955e3b55780SDimitry Andric // worklist
956e3b55780SDimitry Andric assert(Pending.empty() && "Pending should be empty");
957e3b55780SDimitry Andric }
958e3b55780SDimitry Andric
959e3b55780SDimitry Andric // Insert new location defs.
9607fa27ce4SDimitry Andric for (auto &Pair : BBInsertBeforeMap) {
961e3b55780SDimitry Andric InsertMap &Map = Pair.second;
9627fa27ce4SDimitry Andric for (auto &Pair : Map) {
9634df029ccSDimitry Andric auto InsertBefore = Pair.first;
964e3b55780SDimitry Andric assert(InsertBefore && "should never be null");
965e3b55780SDimitry Andric auto FragMemLocs = Pair.second;
966e3b55780SDimitry Andric auto &Ctx = Fn.getContext();
967e3b55780SDimitry Andric
9687fa27ce4SDimitry Andric for (auto &FragMemLoc : FragMemLocs) {
969e3b55780SDimitry Andric DIExpression *Expr = DIExpression::get(Ctx, std::nullopt);
9707fa27ce4SDimitry Andric if (FragMemLoc.SizeInBits !=
9717fa27ce4SDimitry Andric *Aggregates[FragMemLoc.Var].first->getSizeInBits())
972e3b55780SDimitry Andric Expr = *DIExpression::createFragmentExpression(
973e3b55780SDimitry Andric Expr, FragMemLoc.OffsetInBits, FragMemLoc.SizeInBits);
974e3b55780SDimitry Andric Expr = DIExpression::prepend(Expr, DIExpression::DerefAfter,
975e3b55780SDimitry Andric FragMemLoc.OffsetInBits / 8);
976e3b55780SDimitry Andric DebugVariable Var(Aggregates[FragMemLoc.Var].first, Expr,
977e3b55780SDimitry Andric FragMemLoc.DL.getInlinedAt());
978e3b55780SDimitry Andric FnVarLocs->addVarLoc(InsertBefore, Var, Expr, FragMemLoc.DL,
979e3b55780SDimitry Andric Bases[FragMemLoc.Base]);
980e3b55780SDimitry Andric }
981e3b55780SDimitry Andric }
982e3b55780SDimitry Andric }
983e3b55780SDimitry Andric }
984e3b55780SDimitry Andric };
985e3b55780SDimitry Andric
986e3b55780SDimitry Andric /// AssignmentTrackingLowering encapsulates a dataflow analysis over a function
987e3b55780SDimitry Andric /// that interprets assignment tracking debug info metadata and stores in IR to
988e3b55780SDimitry Andric /// create a map of variable locations.
989e3b55780SDimitry Andric class AssignmentTrackingLowering {
990e3b55780SDimitry Andric public:
991e3b55780SDimitry Andric /// The kind of location in use for a variable, where Mem is the stack home,
992e3b55780SDimitry Andric /// Val is an SSA value or const, and None means that there is not one single
993e3b55780SDimitry Andric /// kind (either because there are multiple or because there is none; it may
994e3b55780SDimitry Andric /// prove useful to split this into two values in the future).
995e3b55780SDimitry Andric ///
996e3b55780SDimitry Andric /// LocKind is a join-semilattice with the partial order:
997e3b55780SDimitry Andric /// None > Mem, Val
998e3b55780SDimitry Andric ///
999e3b55780SDimitry Andric /// i.e.
1000e3b55780SDimitry Andric /// join(Mem, Mem) = Mem
1001e3b55780SDimitry Andric /// join(Val, Val) = Val
1002e3b55780SDimitry Andric /// join(Mem, Val) = None
1003e3b55780SDimitry Andric /// join(None, Mem) = None
1004e3b55780SDimitry Andric /// join(None, Val) = None
1005e3b55780SDimitry Andric /// join(None, None) = None
1006e3b55780SDimitry Andric ///
1007e3b55780SDimitry Andric /// Note: the order is not `None > Val > Mem` because we're using DIAssignID
1008e3b55780SDimitry Andric /// to name assignments and are not tracking the actual stored values.
1009e3b55780SDimitry Andric /// Therefore currently there's no way to ensure that Mem values and Val
1010e3b55780SDimitry Andric /// values are the same. This could be a future extension, though it's not
1011e3b55780SDimitry Andric /// clear that many additional locations would be recovered that way in
1012e3b55780SDimitry Andric /// practice as the likelihood of this sitation arising naturally seems
1013e3b55780SDimitry Andric /// incredibly low.
1014e3b55780SDimitry Andric enum class LocKind { Mem, Val, None };
1015e3b55780SDimitry Andric
1016e3b55780SDimitry Andric /// An abstraction of the assignment of a value to a variable or memory
1017e3b55780SDimitry Andric /// location.
1018e3b55780SDimitry Andric ///
1019e3b55780SDimitry Andric /// An Assignment is Known or NoneOrPhi. A Known Assignment means we have a
1020e3b55780SDimitry Andric /// DIAssignID ptr that represents it. NoneOrPhi means that we don't (or
1021e3b55780SDimitry Andric /// can't) know the ID of the last assignment that took place.
1022e3b55780SDimitry Andric ///
1023e3b55780SDimitry Andric /// The Status of the Assignment (Known or NoneOrPhi) is another
1024e3b55780SDimitry Andric /// join-semilattice. The partial order is:
1025e3b55780SDimitry Andric /// NoneOrPhi > Known {id_0, id_1, ...id_N}
1026e3b55780SDimitry Andric ///
1027e3b55780SDimitry Andric /// i.e. for all values x and y where x != y:
1028e3b55780SDimitry Andric /// join(x, x) = x
1029e3b55780SDimitry Andric /// join(x, y) = NoneOrPhi
1030ac9a064cSDimitry Andric using AssignRecord = PointerUnion<DbgAssignIntrinsic *, DbgVariableRecord *>;
1031e3b55780SDimitry Andric struct Assignment {
1032e3b55780SDimitry Andric enum S { Known, NoneOrPhi } Status;
1033e3b55780SDimitry Andric /// ID of the assignment. nullptr if Status is not Known.
1034e3b55780SDimitry Andric DIAssignID *ID;
1035e3b55780SDimitry Andric /// The dbg.assign that marks this dbg-def. Mem-defs don't use this field.
1036e3b55780SDimitry Andric /// May be nullptr.
10374df029ccSDimitry Andric AssignRecord Source;
1038e3b55780SDimitry Andric
isSameSourceAssignment__anon8b6cc4990211::AssignmentTrackingLowering::Assignment1039e3b55780SDimitry Andric bool isSameSourceAssignment(const Assignment &Other) const {
1040e3b55780SDimitry Andric // Don't include Source in the equality check. Assignments are
1041e3b55780SDimitry Andric // defined by their ID, not debug intrinsic(s).
1042e3b55780SDimitry Andric return std::tie(Status, ID) == std::tie(Other.Status, Other.ID);
1043e3b55780SDimitry Andric }
dump__anon8b6cc4990211::AssignmentTrackingLowering::Assignment1044e3b55780SDimitry Andric void dump(raw_ostream &OS) {
1045e3b55780SDimitry Andric static const char *LUT[] = {"Known", "NoneOrPhi"};
1046e3b55780SDimitry Andric OS << LUT[Status] << "(id=";
1047e3b55780SDimitry Andric if (ID)
1048e3b55780SDimitry Andric OS << ID;
1049e3b55780SDimitry Andric else
1050e3b55780SDimitry Andric OS << "null";
1051e3b55780SDimitry Andric OS << ", s=";
10524df029ccSDimitry Andric if (Source.isNull())
1053e3b55780SDimitry Andric OS << "null";
10544df029ccSDimitry Andric else if (isa<DbgAssignIntrinsic *>(Source))
10554df029ccSDimitry Andric OS << Source.get<DbgAssignIntrinsic *>();
10564df029ccSDimitry Andric else
1057ac9a064cSDimitry Andric OS << Source.get<DbgVariableRecord *>();
1058e3b55780SDimitry Andric OS << ")";
1059e3b55780SDimitry Andric }
1060e3b55780SDimitry Andric
make__anon8b6cc4990211::AssignmentTrackingLowering::Assignment1061e3b55780SDimitry Andric static Assignment make(DIAssignID *ID, DbgAssignIntrinsic *Source) {
1062e3b55780SDimitry Andric return Assignment(Known, ID, Source);
1063e3b55780SDimitry Andric }
make__anon8b6cc4990211::AssignmentTrackingLowering::Assignment1064ac9a064cSDimitry Andric static Assignment make(DIAssignID *ID, DbgVariableRecord *Source) {
10654df029ccSDimitry Andric assert(Source->isDbgAssign() &&
1066ac9a064cSDimitry Andric "Cannot make an assignment from a non-assign DbgVariableRecord");
10674df029ccSDimitry Andric return Assignment(Known, ID, Source);
10684df029ccSDimitry Andric }
make__anon8b6cc4990211::AssignmentTrackingLowering::Assignment10694df029ccSDimitry Andric static Assignment make(DIAssignID *ID, AssignRecord Source) {
10704df029ccSDimitry Andric return Assignment(Known, ID, Source);
10714df029ccSDimitry Andric }
makeFromMemDef__anon8b6cc4990211::AssignmentTrackingLowering::Assignment1072e3b55780SDimitry Andric static Assignment makeFromMemDef(DIAssignID *ID) {
10734df029ccSDimitry Andric return Assignment(Known, ID);
1074e3b55780SDimitry Andric }
makeNoneOrPhi__anon8b6cc4990211::AssignmentTrackingLowering::Assignment10754df029ccSDimitry Andric static Assignment makeNoneOrPhi() { return Assignment(NoneOrPhi, nullptr); }
1076e3b55780SDimitry Andric // Again, need a Top value?
Assignment__anon8b6cc4990211::AssignmentTrackingLowering::Assignment10774df029ccSDimitry Andric Assignment() : Status(NoneOrPhi), ID(nullptr) {} // Can we delete this?
Assignment__anon8b6cc4990211::AssignmentTrackingLowering::Assignment10784df029ccSDimitry Andric Assignment(S Status, DIAssignID *ID) : Status(Status), ID(ID) {
10794df029ccSDimitry Andric // If the Status is Known then we expect there to be an assignment ID.
10804df029ccSDimitry Andric assert(Status == NoneOrPhi || ID);
10814df029ccSDimitry Andric }
Assignment__anon8b6cc4990211::AssignmentTrackingLowering::Assignment1082e3b55780SDimitry Andric Assignment(S Status, DIAssignID *ID, DbgAssignIntrinsic *Source)
1083e3b55780SDimitry Andric : Status(Status), ID(ID), Source(Source) {
1084e3b55780SDimitry Andric // If the Status is Known then we expect there to be an assignment ID.
1085e3b55780SDimitry Andric assert(Status == NoneOrPhi || ID);
1086e3b55780SDimitry Andric }
Assignment__anon8b6cc4990211::AssignmentTrackingLowering::Assignment1087ac9a064cSDimitry Andric Assignment(S Status, DIAssignID *ID, DbgVariableRecord *Source)
10884df029ccSDimitry Andric : Status(Status), ID(ID), Source(Source) {
10894df029ccSDimitry Andric // If the Status is Known then we expect there to be an assignment ID.
10904df029ccSDimitry Andric assert(Status == NoneOrPhi || ID);
10914df029ccSDimitry Andric }
Assignment__anon8b6cc4990211::AssignmentTrackingLowering::Assignment10924df029ccSDimitry Andric Assignment(S Status, DIAssignID *ID, AssignRecord Source)
10934df029ccSDimitry Andric : Status(Status), ID(ID), Source(Source) {
10944df029ccSDimitry Andric // If the Status is Known then we expect there to be an assignment ID.
10954df029ccSDimitry Andric assert(Status == NoneOrPhi || ID);
10964df029ccSDimitry Andric }
1097e3b55780SDimitry Andric };
1098e3b55780SDimitry Andric
10997fa27ce4SDimitry Andric using AssignmentMap = SmallVector<Assignment>;
11007fa27ce4SDimitry Andric using LocMap = SmallVector<LocKind>;
11017fa27ce4SDimitry Andric using OverlapMap = DenseMap<VariableID, SmallVector<VariableID>>;
1102e3b55780SDimitry Andric using UntaggedStoreAssignmentMap =
1103e3b55780SDimitry Andric DenseMap<const Instruction *,
1104e3b55780SDimitry Andric SmallVector<std::pair<VariableID, at::AssignmentInfo>>>;
1105e3b55780SDimitry Andric
1106e3b55780SDimitry Andric private:
11077fa27ce4SDimitry Andric /// The highest numbered VariableID for partially promoted variables plus 1,
11087fa27ce4SDimitry Andric /// the values for which start at 1.
11097fa27ce4SDimitry Andric unsigned TrackedVariablesVectorSize = 0;
1110e3b55780SDimitry Andric /// Map a variable to the set of variables that it fully contains.
1111e3b55780SDimitry Andric OverlapMap VarContains;
1112e3b55780SDimitry Andric /// Map untagged stores to the variable fragments they assign to. Used by
1113e3b55780SDimitry Andric /// processUntaggedInstruction.
1114e3b55780SDimitry Andric UntaggedStoreAssignmentMap UntaggedStoreVars;
1115e3b55780SDimitry Andric
1116e3b55780SDimitry Andric // Machinery to defer inserting dbg.values.
11174df029ccSDimitry Andric using InstInsertMap = MapVector<VarLocInsertPt, SmallVector<VarLocInfo>>;
11184df029ccSDimitry Andric InstInsertMap InsertBeforeMap;
1119e3b55780SDimitry Andric /// Clear the location definitions currently cached for insertion after /p
1120e3b55780SDimitry Andric /// After.
1121e3b55780SDimitry Andric void resetInsertionPoint(Instruction &After);
1122ac9a064cSDimitry Andric void resetInsertionPoint(DbgVariableRecord &After);
11234df029ccSDimitry Andric
11244df029ccSDimitry Andric // emitDbgValue can be called with:
1125ac9a064cSDimitry Andric // Source=[AssignRecord|DbgValueInst*|DbgAssignIntrinsic*|DbgVariableRecord*]
11264df029ccSDimitry Andric // Since AssignRecord can be cast to one of the latter two types, and all
11274df029ccSDimitry Andric // other types have a shared interface, we use a template to handle the latter
11284df029ccSDimitry Andric // three types, and an explicit overload for AssignRecord that forwards to
11294df029ccSDimitry Andric // the template version with the right type.
11304df029ccSDimitry Andric void emitDbgValue(LocKind Kind, AssignRecord Source, VarLocInsertPt After);
11314df029ccSDimitry Andric template <typename T>
11324df029ccSDimitry Andric void emitDbgValue(LocKind Kind, const T Source, VarLocInsertPt After);
1133e3b55780SDimitry Andric
mapsAreEqual(const BitVector & Mask,const AssignmentMap & A,const AssignmentMap & B)11347fa27ce4SDimitry Andric static bool mapsAreEqual(const BitVector &Mask, const AssignmentMap &A,
11357fa27ce4SDimitry Andric const AssignmentMap &B) {
11367fa27ce4SDimitry Andric return llvm::all_of(Mask.set_bits(), [&](unsigned VarID) {
11377fa27ce4SDimitry Andric return A[VarID].isSameSourceAssignment(B[VarID]);
11387fa27ce4SDimitry Andric });
1139e3b55780SDimitry Andric }
1140e3b55780SDimitry Andric
1141e3b55780SDimitry Andric /// Represents the stack and debug assignments in a block. Used to describe
1142e3b55780SDimitry Andric /// the live-in and live-out values for blocks, as well as the "current"
1143e3b55780SDimitry Andric /// value as we process each instruction in a block.
1144e3b55780SDimitry Andric struct BlockInfo {
11457fa27ce4SDimitry Andric /// The set of variables (VariableID) being tracked in this block.
11467fa27ce4SDimitry Andric BitVector VariableIDsInBlock;
11477fa27ce4SDimitry Andric /// Dominating assignment to memory for each variable, indexed by
11487fa27ce4SDimitry Andric /// VariableID.
1149e3b55780SDimitry Andric AssignmentMap StackHomeValue;
11507fa27ce4SDimitry Andric /// Dominating assignemnt to each variable, indexed by VariableID.
1151e3b55780SDimitry Andric AssignmentMap DebugValue;
1152e3b55780SDimitry Andric /// Location kind for each variable. LiveLoc indicates whether the
1153e3b55780SDimitry Andric /// dominating assignment in StackHomeValue (LocKind::Mem), DebugValue
1154e3b55780SDimitry Andric /// (LocKind::Val), or neither (LocKind::None) is valid, in that order of
1155e3b55780SDimitry Andric /// preference. This cannot be derived by inspecting DebugValue and
1156e3b55780SDimitry Andric /// StackHomeValue due to the fact that there's no distinction in
1157e3b55780SDimitry Andric /// Assignment (the class) between whether an assignment is unknown or a
1158e3b55780SDimitry Andric /// merge of multiple assignments (both are Status::NoneOrPhi). In other
1159e3b55780SDimitry Andric /// words, the memory location may well be valid while both DebugValue and
1160e3b55780SDimitry Andric /// StackHomeValue contain Assignments that have a Status of NoneOrPhi.
11617fa27ce4SDimitry Andric /// Indexed by VariableID.
1162e3b55780SDimitry Andric LocMap LiveLoc;
1163e3b55780SDimitry Andric
11647fa27ce4SDimitry Andric public:
11657fa27ce4SDimitry Andric enum AssignmentKind { Stack, Debug };
getAssignmentMap__anon8b6cc4990211::AssignmentTrackingLowering::BlockInfo11667fa27ce4SDimitry Andric const AssignmentMap &getAssignmentMap(AssignmentKind Kind) const {
11677fa27ce4SDimitry Andric switch (Kind) {
11687fa27ce4SDimitry Andric case Stack:
11697fa27ce4SDimitry Andric return StackHomeValue;
11707fa27ce4SDimitry Andric case Debug:
11717fa27ce4SDimitry Andric return DebugValue;
11727fa27ce4SDimitry Andric }
11737fa27ce4SDimitry Andric llvm_unreachable("Unknown AssignmentKind");
11747fa27ce4SDimitry Andric }
getAssignmentMap__anon8b6cc4990211::AssignmentTrackingLowering::BlockInfo11757fa27ce4SDimitry Andric AssignmentMap &getAssignmentMap(AssignmentKind Kind) {
11767fa27ce4SDimitry Andric return const_cast<AssignmentMap &>(
11777fa27ce4SDimitry Andric const_cast<const BlockInfo *>(this)->getAssignmentMap(Kind));
11787fa27ce4SDimitry Andric }
11797fa27ce4SDimitry Andric
isVariableTracked__anon8b6cc4990211::AssignmentTrackingLowering::BlockInfo11807fa27ce4SDimitry Andric bool isVariableTracked(VariableID Var) const {
11817fa27ce4SDimitry Andric return VariableIDsInBlock[static_cast<unsigned>(Var)];
11827fa27ce4SDimitry Andric }
11837fa27ce4SDimitry Andric
getAssignment__anon8b6cc4990211::AssignmentTrackingLowering::BlockInfo11847fa27ce4SDimitry Andric const Assignment &getAssignment(AssignmentKind Kind, VariableID Var) const {
11857fa27ce4SDimitry Andric assert(isVariableTracked(Var) && "Var not tracked in block");
11867fa27ce4SDimitry Andric return getAssignmentMap(Kind)[static_cast<unsigned>(Var)];
11877fa27ce4SDimitry Andric }
11887fa27ce4SDimitry Andric
getLocKind__anon8b6cc4990211::AssignmentTrackingLowering::BlockInfo11897fa27ce4SDimitry Andric LocKind getLocKind(VariableID Var) const {
11907fa27ce4SDimitry Andric assert(isVariableTracked(Var) && "Var not tracked in block");
11917fa27ce4SDimitry Andric return LiveLoc[static_cast<unsigned>(Var)];
11927fa27ce4SDimitry Andric }
11937fa27ce4SDimitry Andric
11947fa27ce4SDimitry Andric /// Set LocKind for \p Var only: does not set LocKind for VariableIDs of
11957fa27ce4SDimitry Andric /// fragments contained win \p Var.
setLocKind__anon8b6cc4990211::AssignmentTrackingLowering::BlockInfo11967fa27ce4SDimitry Andric void setLocKind(VariableID Var, LocKind K) {
11977fa27ce4SDimitry Andric VariableIDsInBlock.set(static_cast<unsigned>(Var));
11987fa27ce4SDimitry Andric LiveLoc[static_cast<unsigned>(Var)] = K;
11997fa27ce4SDimitry Andric }
12007fa27ce4SDimitry Andric
12017fa27ce4SDimitry Andric /// Set the assignment in the \p Kind assignment map for \p Var only: does
12027fa27ce4SDimitry Andric /// not set the assignment for VariableIDs of fragments contained win \p
12037fa27ce4SDimitry Andric /// Var.
setAssignment__anon8b6cc4990211::AssignmentTrackingLowering::BlockInfo12047fa27ce4SDimitry Andric void setAssignment(AssignmentKind Kind, VariableID Var,
12057fa27ce4SDimitry Andric const Assignment &AV) {
12067fa27ce4SDimitry Andric VariableIDsInBlock.set(static_cast<unsigned>(Var));
12077fa27ce4SDimitry Andric getAssignmentMap(Kind)[static_cast<unsigned>(Var)] = AV;
12087fa27ce4SDimitry Andric }
12097fa27ce4SDimitry Andric
12107fa27ce4SDimitry Andric /// Return true if there is an assignment matching \p AV in the \p Kind
12117fa27ce4SDimitry Andric /// assignment map. Does consider assignments for VariableIDs of fragments
12127fa27ce4SDimitry Andric /// contained win \p Var.
hasAssignment__anon8b6cc4990211::AssignmentTrackingLowering::BlockInfo12137fa27ce4SDimitry Andric bool hasAssignment(AssignmentKind Kind, VariableID Var,
12147fa27ce4SDimitry Andric const Assignment &AV) const {
12157fa27ce4SDimitry Andric if (!isVariableTracked(Var))
12167fa27ce4SDimitry Andric return false;
12177fa27ce4SDimitry Andric return AV.isSameSourceAssignment(getAssignment(Kind, Var));
12187fa27ce4SDimitry Andric }
12197fa27ce4SDimitry Andric
1220e3b55780SDimitry Andric /// Compare every element in each map to determine structural equality
1221e3b55780SDimitry Andric /// (slow).
operator ==__anon8b6cc4990211::AssignmentTrackingLowering::BlockInfo1222e3b55780SDimitry Andric bool operator==(const BlockInfo &Other) const {
12237fa27ce4SDimitry Andric return VariableIDsInBlock == Other.VariableIDsInBlock &&
12247fa27ce4SDimitry Andric LiveLoc == Other.LiveLoc &&
12257fa27ce4SDimitry Andric mapsAreEqual(VariableIDsInBlock, StackHomeValue,
12267fa27ce4SDimitry Andric Other.StackHomeValue) &&
12277fa27ce4SDimitry Andric mapsAreEqual(VariableIDsInBlock, DebugValue, Other.DebugValue);
1228e3b55780SDimitry Andric }
operator !=__anon8b6cc4990211::AssignmentTrackingLowering::BlockInfo1229e3b55780SDimitry Andric bool operator!=(const BlockInfo &Other) const { return !(*this == Other); }
isValid__anon8b6cc4990211::AssignmentTrackingLowering::BlockInfo1230e3b55780SDimitry Andric bool isValid() {
1231e3b55780SDimitry Andric return LiveLoc.size() == DebugValue.size() &&
1232e3b55780SDimitry Andric LiveLoc.size() == StackHomeValue.size();
1233e3b55780SDimitry Andric }
12347fa27ce4SDimitry Andric
12357fa27ce4SDimitry Andric /// Clear everything and initialise with ⊤-values for all variables.
init__anon8b6cc4990211::AssignmentTrackingLowering::BlockInfo12367fa27ce4SDimitry Andric void init(int NumVars) {
12377fa27ce4SDimitry Andric StackHomeValue.clear();
12387fa27ce4SDimitry Andric DebugValue.clear();
12397fa27ce4SDimitry Andric LiveLoc.clear();
12407fa27ce4SDimitry Andric VariableIDsInBlock = BitVector(NumVars);
12417fa27ce4SDimitry Andric StackHomeValue.insert(StackHomeValue.begin(), NumVars,
12427fa27ce4SDimitry Andric Assignment::makeNoneOrPhi());
12437fa27ce4SDimitry Andric DebugValue.insert(DebugValue.begin(), NumVars,
12447fa27ce4SDimitry Andric Assignment::makeNoneOrPhi());
12457fa27ce4SDimitry Andric LiveLoc.insert(LiveLoc.begin(), NumVars, LocKind::None);
12467fa27ce4SDimitry Andric }
12477fa27ce4SDimitry Andric
12487fa27ce4SDimitry Andric /// Helper for join.
12497fa27ce4SDimitry Andric template <typename ElmtType, typename FnInputType>
joinElmt__anon8b6cc4990211::AssignmentTrackingLowering::BlockInfo12507fa27ce4SDimitry Andric static void joinElmt(int Index, SmallVector<ElmtType> &Target,
12517fa27ce4SDimitry Andric const SmallVector<ElmtType> &A,
12527fa27ce4SDimitry Andric const SmallVector<ElmtType> &B,
12537fa27ce4SDimitry Andric ElmtType (*Fn)(FnInputType, FnInputType)) {
12547fa27ce4SDimitry Andric Target[Index] = Fn(A[Index], B[Index]);
12557fa27ce4SDimitry Andric }
12567fa27ce4SDimitry Andric
12577fa27ce4SDimitry Andric /// See comment for AssignmentTrackingLowering::joinBlockInfo.
join__anon8b6cc4990211::AssignmentTrackingLowering::BlockInfo12587fa27ce4SDimitry Andric static BlockInfo join(const BlockInfo &A, const BlockInfo &B, int NumVars) {
12597fa27ce4SDimitry Andric // Join A and B.
12607fa27ce4SDimitry Andric //
12617fa27ce4SDimitry Andric // Intersect = join(a, b) for a in A, b in B where Var(a) == Var(b)
12627fa27ce4SDimitry Andric // Difference = join(x, ⊤) for x where Var(x) is in A xor B
12637fa27ce4SDimitry Andric // Join = Intersect ∪ Difference
12647fa27ce4SDimitry Andric //
12657fa27ce4SDimitry Andric // This is achieved by performing a join on elements from A and B with
12667fa27ce4SDimitry Andric // variables common to both A and B (join elements indexed by var
12677fa27ce4SDimitry Andric // intersect), then adding ⊤-value elements for vars in A xor B. The
12687fa27ce4SDimitry Andric // latter part is equivalent to performing join on elements with variables
12697fa27ce4SDimitry Andric // in A xor B with the ⊤-value for the map element since join(x, ⊤) = ⊤.
12707fa27ce4SDimitry Andric // BlockInfo::init initializes all variable entries to the ⊤ value so we
12717fa27ce4SDimitry Andric // don't need to explicitly perform that step as Join.VariableIDsInBlock
12727fa27ce4SDimitry Andric // is set to the union of the variables in A and B at the end of this
12737fa27ce4SDimitry Andric // function.
12747fa27ce4SDimitry Andric BlockInfo Join;
12757fa27ce4SDimitry Andric Join.init(NumVars);
12767fa27ce4SDimitry Andric
12777fa27ce4SDimitry Andric BitVector Intersect = A.VariableIDsInBlock;
12787fa27ce4SDimitry Andric Intersect &= B.VariableIDsInBlock;
12797fa27ce4SDimitry Andric
12807fa27ce4SDimitry Andric for (auto VarID : Intersect.set_bits()) {
12817fa27ce4SDimitry Andric joinElmt(VarID, Join.LiveLoc, A.LiveLoc, B.LiveLoc, joinKind);
12827fa27ce4SDimitry Andric joinElmt(VarID, Join.DebugValue, A.DebugValue, B.DebugValue,
12837fa27ce4SDimitry Andric joinAssignment);
12847fa27ce4SDimitry Andric joinElmt(VarID, Join.StackHomeValue, A.StackHomeValue, B.StackHomeValue,
12857fa27ce4SDimitry Andric joinAssignment);
12867fa27ce4SDimitry Andric }
12877fa27ce4SDimitry Andric
12887fa27ce4SDimitry Andric Join.VariableIDsInBlock = A.VariableIDsInBlock;
12897fa27ce4SDimitry Andric Join.VariableIDsInBlock |= B.VariableIDsInBlock;
12907fa27ce4SDimitry Andric assert(Join.isValid());
12917fa27ce4SDimitry Andric return Join;
12927fa27ce4SDimitry Andric }
1293e3b55780SDimitry Andric };
1294e3b55780SDimitry Andric
1295e3b55780SDimitry Andric Function &Fn;
1296e3b55780SDimitry Andric const DataLayout &Layout;
1297e3b55780SDimitry Andric const DenseSet<DebugAggregate> *VarsWithStackSlot;
1298e3b55780SDimitry Andric FunctionVarLocsBuilder *FnVarLocs;
1299e3b55780SDimitry Andric DenseMap<const BasicBlock *, BlockInfo> LiveIn;
1300e3b55780SDimitry Andric DenseMap<const BasicBlock *, BlockInfo> LiveOut;
1301e3b55780SDimitry Andric
1302e3b55780SDimitry Andric /// Helper for process methods to track variables touched each frame.
1303e3b55780SDimitry Andric DenseSet<VariableID> VarsTouchedThisFrame;
1304e3b55780SDimitry Andric
1305e3b55780SDimitry Andric /// The set of variables that sometimes are not located in their stack home.
1306e3b55780SDimitry Andric DenseSet<DebugAggregate> NotAlwaysStackHomed;
1307e3b55780SDimitry Andric
getVariableID(const DebugVariable & Var)1308e3b55780SDimitry Andric VariableID getVariableID(const DebugVariable &Var) {
1309e3b55780SDimitry Andric return static_cast<VariableID>(FnVarLocs->insertVariable(Var));
1310e3b55780SDimitry Andric }
1311e3b55780SDimitry Andric
1312e3b55780SDimitry Andric /// Join the LiveOut values of preds that are contained in \p Visited into
1313e3b55780SDimitry Andric /// LiveIn[BB]. Return True if LiveIn[BB] has changed as a result. LiveIn[BB]
1314e3b55780SDimitry Andric /// values monotonically increase. See the @link joinMethods join methods
1315e3b55780SDimitry Andric /// @endlink documentation for more info.
1316e3b55780SDimitry Andric bool join(const BasicBlock &BB, const SmallPtrSet<BasicBlock *, 16> &Visited);
1317e3b55780SDimitry Andric ///@name joinMethods
1318e3b55780SDimitry Andric /// Functions that implement `join` (the least upper bound) for the
1319e3b55780SDimitry Andric /// join-semilattice types used in the dataflow. There is an explicit bottom
1320e3b55780SDimitry Andric /// value (⊥) for some types and and explicit top value (⊤) for all types.
1321e3b55780SDimitry Andric /// By definition:
1322e3b55780SDimitry Andric ///
1323e3b55780SDimitry Andric /// Join(A, B) >= A && Join(A, B) >= B
1324e3b55780SDimitry Andric /// Join(A, ⊥) = A
1325e3b55780SDimitry Andric /// Join(A, ⊤) = ⊤
1326e3b55780SDimitry Andric ///
1327e3b55780SDimitry Andric /// These invariants are important for monotonicity.
1328e3b55780SDimitry Andric ///
1329e3b55780SDimitry Andric /// For the map-type functions, all unmapped keys in an empty map are
1330e3b55780SDimitry Andric /// associated with a bottom value (⊥). This represents their values being
1331e3b55780SDimitry Andric /// unknown. Unmapped keys in non-empty maps (joining two maps with a key
1332e3b55780SDimitry Andric /// only present in one) represents either a variable going out of scope or
1333e3b55780SDimitry Andric /// dropped debug info. It is assumed the key is associated with a top value
1334e3b55780SDimitry Andric /// (⊤) in this case (unknown location / assignment).
1335e3b55780SDimitry Andric ///@{
1336e3b55780SDimitry Andric static LocKind joinKind(LocKind A, LocKind B);
1337e3b55780SDimitry Andric static Assignment joinAssignment(const Assignment &A, const Assignment &B);
13387fa27ce4SDimitry Andric BlockInfo joinBlockInfo(const BlockInfo &A, const BlockInfo &B);
1339e3b55780SDimitry Andric ///@}
1340e3b55780SDimitry Andric
1341e3b55780SDimitry Andric /// Process the instructions in \p BB updating \p LiveSet along the way. \p
1342e3b55780SDimitry Andric /// LiveSet must be initialized with the current live-in locations before
1343e3b55780SDimitry Andric /// calling this.
1344e3b55780SDimitry Andric void process(BasicBlock &BB, BlockInfo *LiveSet);
1345e3b55780SDimitry Andric ///@name processMethods
1346e3b55780SDimitry Andric /// Methods to process instructions in order to update the LiveSet (current
1347e3b55780SDimitry Andric /// location information).
1348e3b55780SDimitry Andric ///@{
1349e3b55780SDimitry Andric void processNonDbgInstruction(Instruction &I, BlockInfo *LiveSet);
13507fa27ce4SDimitry Andric void processDbgInstruction(DbgInfoIntrinsic &I, BlockInfo *LiveSet);
1351e3b55780SDimitry Andric /// Update \p LiveSet after encountering an instruction with a DIAssignID
1352e3b55780SDimitry Andric /// attachment, \p I.
1353e3b55780SDimitry Andric void processTaggedInstruction(Instruction &I, BlockInfo *LiveSet);
1354e3b55780SDimitry Andric /// Update \p LiveSet after encountering an instruciton without a DIAssignID
1355e3b55780SDimitry Andric /// attachment, \p I.
1356e3b55780SDimitry Andric void processUntaggedInstruction(Instruction &I, BlockInfo *LiveSet);
13574df029ccSDimitry Andric void processDbgAssign(AssignRecord Assign, BlockInfo *LiveSet);
1358ac9a064cSDimitry Andric void processDbgVariableRecord(DbgVariableRecord &DVR, BlockInfo *LiveSet);
1359ac9a064cSDimitry Andric void processDbgValue(
1360ac9a064cSDimitry Andric PointerUnion<DbgValueInst *, DbgVariableRecord *> DbgValueRecord,
13614df029ccSDimitry Andric BlockInfo *LiveSet);
1362e3b55780SDimitry Andric /// Add an assignment to memory for the variable /p Var.
1363e3b55780SDimitry Andric void addMemDef(BlockInfo *LiveSet, VariableID Var, const Assignment &AV);
1364e3b55780SDimitry Andric /// Add an assignment to the variable /p Var.
1365e3b55780SDimitry Andric void addDbgDef(BlockInfo *LiveSet, VariableID Var, const Assignment &AV);
1366e3b55780SDimitry Andric ///@}
1367e3b55780SDimitry Andric
1368e3b55780SDimitry Andric /// Set the LocKind for \p Var.
1369e3b55780SDimitry Andric void setLocKind(BlockInfo *LiveSet, VariableID Var, LocKind K);
1370e3b55780SDimitry Andric /// Get the live LocKind for a \p Var. Requires addMemDef or addDbgDef to
1371e3b55780SDimitry Andric /// have been called for \p Var first.
1372e3b55780SDimitry Andric LocKind getLocKind(BlockInfo *LiveSet, VariableID Var);
1373e3b55780SDimitry Andric /// Return true if \p Var has an assignment in \p M matching \p AV.
13747fa27ce4SDimitry Andric bool hasVarWithAssignment(BlockInfo *LiveSet, BlockInfo::AssignmentKind Kind,
13757fa27ce4SDimitry Andric VariableID Var, const Assignment &AV);
13767fa27ce4SDimitry Andric /// Return the set of VariableIDs corresponding the fragments contained fully
13777fa27ce4SDimitry Andric /// within the variable/fragment \p Var.
13787fa27ce4SDimitry Andric ArrayRef<VariableID> getContainedFragments(VariableID Var) const;
13797fa27ce4SDimitry Andric
13807fa27ce4SDimitry Andric /// Mark \p Var as having been touched this frame. Note, this applies only
13817fa27ce4SDimitry Andric /// to the exact fragment \p Var and not to any fragments contained within.
13827fa27ce4SDimitry Andric void touchFragment(VariableID Var);
1383e3b55780SDimitry Andric
1384e3b55780SDimitry Andric /// Emit info for variables that are fully promoted.
1385e3b55780SDimitry Andric bool emitPromotedVarLocs(FunctionVarLocsBuilder *FnVarLocs);
1386e3b55780SDimitry Andric
1387e3b55780SDimitry Andric public:
AssignmentTrackingLowering(Function & Fn,const DataLayout & Layout,const DenseSet<DebugAggregate> * VarsWithStackSlot)1388e3b55780SDimitry Andric AssignmentTrackingLowering(Function &Fn, const DataLayout &Layout,
1389e3b55780SDimitry Andric const DenseSet<DebugAggregate> *VarsWithStackSlot)
1390e3b55780SDimitry Andric : Fn(Fn), Layout(Layout), VarsWithStackSlot(VarsWithStackSlot) {}
1391e3b55780SDimitry Andric /// Run the analysis, adding variable location info to \p FnVarLocs. Returns
1392e3b55780SDimitry Andric /// true if any variable locations have been added to FnVarLocs.
1393e3b55780SDimitry Andric bool run(FunctionVarLocsBuilder *FnVarLocs);
1394e3b55780SDimitry Andric };
1395e3b55780SDimitry Andric } // namespace
1396e3b55780SDimitry Andric
13977fa27ce4SDimitry Andric ArrayRef<VariableID>
getContainedFragments(VariableID Var) const13987fa27ce4SDimitry Andric AssignmentTrackingLowering::getContainedFragments(VariableID Var) const {
13997fa27ce4SDimitry Andric auto R = VarContains.find(Var);
14007fa27ce4SDimitry Andric if (R == VarContains.end())
14017fa27ce4SDimitry Andric return std::nullopt;
14027fa27ce4SDimitry Andric return R->second;
14037fa27ce4SDimitry Andric }
14047fa27ce4SDimitry Andric
touchFragment(VariableID Var)14057fa27ce4SDimitry Andric void AssignmentTrackingLowering::touchFragment(VariableID Var) {
14067fa27ce4SDimitry Andric VarsTouchedThisFrame.insert(Var);
14077fa27ce4SDimitry Andric }
14087fa27ce4SDimitry Andric
setLocKind(BlockInfo * LiveSet,VariableID Var,LocKind K)1409e3b55780SDimitry Andric void AssignmentTrackingLowering::setLocKind(BlockInfo *LiveSet, VariableID Var,
1410e3b55780SDimitry Andric LocKind K) {
1411e3b55780SDimitry Andric auto SetKind = [this](BlockInfo *LiveSet, VariableID Var, LocKind K) {
14127fa27ce4SDimitry Andric LiveSet->setLocKind(Var, K);
14137fa27ce4SDimitry Andric touchFragment(Var);
1414e3b55780SDimitry Andric };
1415e3b55780SDimitry Andric SetKind(LiveSet, Var, K);
1416e3b55780SDimitry Andric
1417e3b55780SDimitry Andric // Update the LocKind for all fragments contained within Var.
14187fa27ce4SDimitry Andric for (VariableID Frag : getContainedFragments(Var))
1419e3b55780SDimitry Andric SetKind(LiveSet, Frag, K);
1420e3b55780SDimitry Andric }
1421e3b55780SDimitry Andric
1422e3b55780SDimitry Andric AssignmentTrackingLowering::LocKind
getLocKind(BlockInfo * LiveSet,VariableID Var)1423e3b55780SDimitry Andric AssignmentTrackingLowering::getLocKind(BlockInfo *LiveSet, VariableID Var) {
14247fa27ce4SDimitry Andric return LiveSet->getLocKind(Var);
1425e3b55780SDimitry Andric }
1426e3b55780SDimitry Andric
addMemDef(BlockInfo * LiveSet,VariableID Var,const Assignment & AV)1427e3b55780SDimitry Andric void AssignmentTrackingLowering::addMemDef(BlockInfo *LiveSet, VariableID Var,
1428e3b55780SDimitry Andric const Assignment &AV) {
14297fa27ce4SDimitry Andric LiveSet->setAssignment(BlockInfo::Stack, Var, AV);
1430e3b55780SDimitry Andric
1431e3b55780SDimitry Andric // Use this assigment for all fragments contained within Var, but do not
1432e3b55780SDimitry Andric // provide a Source because we cannot convert Var's value to a value for the
1433e3b55780SDimitry Andric // fragment.
1434e3b55780SDimitry Andric Assignment FragAV = AV;
1435e3b55780SDimitry Andric FragAV.Source = nullptr;
14367fa27ce4SDimitry Andric for (VariableID Frag : getContainedFragments(Var))
14377fa27ce4SDimitry Andric LiveSet->setAssignment(BlockInfo::Stack, Frag, FragAV);
1438e3b55780SDimitry Andric }
1439e3b55780SDimitry Andric
addDbgDef(BlockInfo * LiveSet,VariableID Var,const Assignment & AV)1440e3b55780SDimitry Andric void AssignmentTrackingLowering::addDbgDef(BlockInfo *LiveSet, VariableID Var,
1441e3b55780SDimitry Andric const Assignment &AV) {
14427fa27ce4SDimitry Andric LiveSet->setAssignment(BlockInfo::Debug, Var, AV);
1443e3b55780SDimitry Andric
1444e3b55780SDimitry Andric // Use this assigment for all fragments contained within Var, but do not
1445e3b55780SDimitry Andric // provide a Source because we cannot convert Var's value to a value for the
1446e3b55780SDimitry Andric // fragment.
1447e3b55780SDimitry Andric Assignment FragAV = AV;
1448e3b55780SDimitry Andric FragAV.Source = nullptr;
14497fa27ce4SDimitry Andric for (VariableID Frag : getContainedFragments(Var))
14507fa27ce4SDimitry Andric LiveSet->setAssignment(BlockInfo::Debug, Frag, FragAV);
1451e3b55780SDimitry Andric }
1452e3b55780SDimitry Andric
getIDFromInst(const Instruction & I)1453e3b55780SDimitry Andric static DIAssignID *getIDFromInst(const Instruction &I) {
1454e3b55780SDimitry Andric return cast<DIAssignID>(I.getMetadata(LLVMContext::MD_DIAssignID));
1455e3b55780SDimitry Andric }
1456e3b55780SDimitry Andric
getIDFromMarker(const DbgAssignIntrinsic & DAI)1457e3b55780SDimitry Andric static DIAssignID *getIDFromMarker(const DbgAssignIntrinsic &DAI) {
1458e3b55780SDimitry Andric return cast<DIAssignID>(DAI.getAssignID());
1459e3b55780SDimitry Andric }
1460e3b55780SDimitry Andric
getIDFromMarker(const DbgVariableRecord & DVR)1461ac9a064cSDimitry Andric static DIAssignID *getIDFromMarker(const DbgVariableRecord &DVR) {
1462ac9a064cSDimitry Andric assert(DVR.isDbgAssign() &&
1463ac9a064cSDimitry Andric "Cannot get a DIAssignID from a non-assign DbgVariableRecord!");
1464ac9a064cSDimitry Andric return DVR.getAssignID();
14654df029ccSDimitry Andric }
14664df029ccSDimitry Andric
1467e3b55780SDimitry Andric /// Return true if \p Var has an assignment in \p M matching \p AV.
hasVarWithAssignment(BlockInfo * LiveSet,BlockInfo::AssignmentKind Kind,VariableID Var,const Assignment & AV)14687fa27ce4SDimitry Andric bool AssignmentTrackingLowering::hasVarWithAssignment(
14697fa27ce4SDimitry Andric BlockInfo *LiveSet, BlockInfo::AssignmentKind Kind, VariableID Var,
14707fa27ce4SDimitry Andric const Assignment &AV) {
14717fa27ce4SDimitry Andric if (!LiveSet->hasAssignment(Kind, Var, AV))
1472e3b55780SDimitry Andric return false;
1473e3b55780SDimitry Andric
1474e3b55780SDimitry Andric // Check all the frags contained within Var as these will have all been
1475e3b55780SDimitry Andric // mapped to AV at the last store to Var.
14767fa27ce4SDimitry Andric for (VariableID Frag : getContainedFragments(Var))
14777fa27ce4SDimitry Andric if (!LiveSet->hasAssignment(Kind, Frag, AV))
1478e3b55780SDimitry Andric return false;
1479e3b55780SDimitry Andric return true;
1480e3b55780SDimitry Andric }
1481e3b55780SDimitry Andric
1482e3b55780SDimitry Andric #ifndef NDEBUG
locStr(AssignmentTrackingLowering::LocKind Loc)1483e3b55780SDimitry Andric const char *locStr(AssignmentTrackingLowering::LocKind Loc) {
1484e3b55780SDimitry Andric using LocKind = AssignmentTrackingLowering::LocKind;
1485e3b55780SDimitry Andric switch (Loc) {
1486e3b55780SDimitry Andric case LocKind::Val:
1487e3b55780SDimitry Andric return "Val";
1488e3b55780SDimitry Andric case LocKind::Mem:
1489e3b55780SDimitry Andric return "Mem";
1490e3b55780SDimitry Andric case LocKind::None:
1491e3b55780SDimitry Andric return "None";
1492e3b55780SDimitry Andric };
1493e3b55780SDimitry Andric llvm_unreachable("unknown LocKind");
1494e3b55780SDimitry Andric }
1495e3b55780SDimitry Andric #endif
1496e3b55780SDimitry Andric
getNextNode(const DbgRecord * DVR)1497ac9a064cSDimitry Andric VarLocInsertPt getNextNode(const DbgRecord *DVR) {
1498ac9a064cSDimitry Andric auto NextIt = ++(DVR->getIterator());
1499ac9a064cSDimitry Andric if (NextIt == DVR->getMarker()->getDbgRecordRange().end())
1500ac9a064cSDimitry Andric return DVR->getMarker()->MarkedInstr;
15014df029ccSDimitry Andric return &*NextIt;
15024df029ccSDimitry Andric }
getNextNode(const Instruction * Inst)15034df029ccSDimitry Andric VarLocInsertPt getNextNode(const Instruction *Inst) {
15044df029ccSDimitry Andric const Instruction *Next = Inst->getNextNode();
1505ac9a064cSDimitry Andric if (!Next->hasDbgRecords())
15064df029ccSDimitry Andric return Next;
1507ac9a064cSDimitry Andric return &*Next->getDbgRecordRange().begin();
15084df029ccSDimitry Andric }
getNextNode(VarLocInsertPt InsertPt)15094df029ccSDimitry Andric VarLocInsertPt getNextNode(VarLocInsertPt InsertPt) {
15104df029ccSDimitry Andric if (isa<const Instruction *>(InsertPt))
15114df029ccSDimitry Andric return getNextNode(cast<const Instruction *>(InsertPt));
1512ac9a064cSDimitry Andric return getNextNode(cast<const DbgRecord *>(InsertPt));
15134df029ccSDimitry Andric }
15144df029ccSDimitry Andric
CastToDbgAssign(DbgVariableIntrinsic * DVI)15154df029ccSDimitry Andric DbgAssignIntrinsic *CastToDbgAssign(DbgVariableIntrinsic *DVI) {
15164df029ccSDimitry Andric return cast<DbgAssignIntrinsic>(DVI);
15174df029ccSDimitry Andric }
15184df029ccSDimitry Andric
CastToDbgAssign(DbgVariableRecord * DVR)1519ac9a064cSDimitry Andric DbgVariableRecord *CastToDbgAssign(DbgVariableRecord *DVR) {
1520ac9a064cSDimitry Andric assert(DVR->isDbgAssign() &&
1521ac9a064cSDimitry Andric "Attempted to cast non-assign DbgVariableRecord to DVRAssign.");
1522ac9a064cSDimitry Andric return DVR;
15234df029ccSDimitry Andric }
15244df029ccSDimitry Andric
emitDbgValue(AssignmentTrackingLowering::LocKind Kind,AssignmentTrackingLowering::AssignRecord Source,VarLocInsertPt After)1525e3b55780SDimitry Andric void AssignmentTrackingLowering::emitDbgValue(
1526e3b55780SDimitry Andric AssignmentTrackingLowering::LocKind Kind,
15274df029ccSDimitry Andric AssignmentTrackingLowering::AssignRecord Source, VarLocInsertPt After) {
15284df029ccSDimitry Andric if (isa<DbgAssignIntrinsic *>(Source))
15294df029ccSDimitry Andric emitDbgValue(Kind, cast<DbgAssignIntrinsic *>(Source), After);
15304df029ccSDimitry Andric else
1531ac9a064cSDimitry Andric emitDbgValue(Kind, cast<DbgVariableRecord *>(Source), After);
15324df029ccSDimitry Andric }
15334df029ccSDimitry Andric template <typename T>
emitDbgValue(AssignmentTrackingLowering::LocKind Kind,const T Source,VarLocInsertPt After)15344df029ccSDimitry Andric void AssignmentTrackingLowering::emitDbgValue(
15354df029ccSDimitry Andric AssignmentTrackingLowering::LocKind Kind, const T Source,
15364df029ccSDimitry Andric VarLocInsertPt After) {
1537e3b55780SDimitry Andric
1538e3b55780SDimitry Andric DILocation *DL = Source->getDebugLoc();
15397fa27ce4SDimitry Andric auto Emit = [this, Source, After, DL](Metadata *Val, DIExpression *Expr) {
1540e3b55780SDimitry Andric assert(Expr);
1541e3b55780SDimitry Andric if (!Val)
15427fa27ce4SDimitry Andric Val = ValueAsMetadata::get(
15437fa27ce4SDimitry Andric PoisonValue::get(Type::getInt1Ty(Source->getContext())));
1544e3b55780SDimitry Andric
1545e3b55780SDimitry Andric // Find a suitable insert point.
15464df029ccSDimitry Andric auto InsertBefore = getNextNode(After);
1547e3b55780SDimitry Andric assert(InsertBefore && "Shouldn't be inserting after a terminator");
1548e3b55780SDimitry Andric
1549e3b55780SDimitry Andric VariableID Var = getVariableID(DebugVariable(Source));
1550e3b55780SDimitry Andric VarLocInfo VarLoc;
1551e3b55780SDimitry Andric VarLoc.VariableID = static_cast<VariableID>(Var);
1552e3b55780SDimitry Andric VarLoc.Expr = Expr;
15537fa27ce4SDimitry Andric VarLoc.Values = RawLocationWrapper(Val);
1554e3b55780SDimitry Andric VarLoc.DL = DL;
1555e3b55780SDimitry Andric // Insert it into the map for later.
1556e3b55780SDimitry Andric InsertBeforeMap[InsertBefore].push_back(VarLoc);
1557e3b55780SDimitry Andric };
1558e3b55780SDimitry Andric
1559e3b55780SDimitry Andric // NOTE: This block can mutate Kind.
1560e3b55780SDimitry Andric if (Kind == LocKind::Mem) {
15614df029ccSDimitry Andric const auto *Assign = CastToDbgAssign(Source);
1562e3b55780SDimitry Andric // Check the address hasn't been dropped (e.g. the debug uses may not have
1563e3b55780SDimitry Andric // been replaced before deleting a Value).
15644df029ccSDimitry Andric if (Assign->isKillAddress()) {
1565e3b55780SDimitry Andric // The address isn't valid so treat this as a non-memory def.
1566e3b55780SDimitry Andric Kind = LocKind::Val;
1567e3b55780SDimitry Andric } else {
15684df029ccSDimitry Andric Value *Val = Assign->getAddress();
15694df029ccSDimitry Andric DIExpression *Expr = Assign->getAddressExpression();
1570e3b55780SDimitry Andric assert(!Expr->getFragmentInfo() &&
1571e3b55780SDimitry Andric "fragment info should be stored in value-expression only");
1572e3b55780SDimitry Andric // Copy the fragment info over from the value-expression to the new
1573e3b55780SDimitry Andric // DIExpression.
1574e3b55780SDimitry Andric if (auto OptFragInfo = Source->getExpression()->getFragmentInfo()) {
1575e3b55780SDimitry Andric auto FragInfo = *OptFragInfo;
1576e3b55780SDimitry Andric Expr = *DIExpression::createFragmentExpression(
1577e3b55780SDimitry Andric Expr, FragInfo.OffsetInBits, FragInfo.SizeInBits);
1578e3b55780SDimitry Andric }
1579e3b55780SDimitry Andric // The address-expression has an implicit deref, add it now.
1580e3b55780SDimitry Andric std::tie(Val, Expr) =
1581e3b55780SDimitry Andric walkToAllocaAndPrependOffsetDeref(Layout, Val, Expr);
15827fa27ce4SDimitry Andric Emit(ValueAsMetadata::get(Val), Expr);
1583e3b55780SDimitry Andric return;
1584e3b55780SDimitry Andric }
1585e3b55780SDimitry Andric }
1586e3b55780SDimitry Andric
1587e3b55780SDimitry Andric if (Kind == LocKind::Val) {
15887fa27ce4SDimitry Andric Emit(Source->getRawLocation(), Source->getExpression());
1589e3b55780SDimitry Andric return;
1590e3b55780SDimitry Andric }
1591e3b55780SDimitry Andric
1592e3b55780SDimitry Andric if (Kind == LocKind::None) {
1593e3b55780SDimitry Andric Emit(nullptr, Source->getExpression());
1594e3b55780SDimitry Andric return;
1595e3b55780SDimitry Andric }
1596e3b55780SDimitry Andric }
1597e3b55780SDimitry Andric
processNonDbgInstruction(Instruction & I,AssignmentTrackingLowering::BlockInfo * LiveSet)1598e3b55780SDimitry Andric void AssignmentTrackingLowering::processNonDbgInstruction(
1599e3b55780SDimitry Andric Instruction &I, AssignmentTrackingLowering::BlockInfo *LiveSet) {
1600e3b55780SDimitry Andric if (I.hasMetadata(LLVMContext::MD_DIAssignID))
1601e3b55780SDimitry Andric processTaggedInstruction(I, LiveSet);
1602e3b55780SDimitry Andric else
1603e3b55780SDimitry Andric processUntaggedInstruction(I, LiveSet);
1604e3b55780SDimitry Andric }
1605e3b55780SDimitry Andric
processUntaggedInstruction(Instruction & I,AssignmentTrackingLowering::BlockInfo * LiveSet)1606e3b55780SDimitry Andric void AssignmentTrackingLowering::processUntaggedInstruction(
1607e3b55780SDimitry Andric Instruction &I, AssignmentTrackingLowering::BlockInfo *LiveSet) {
1608e3b55780SDimitry Andric // Interpret stack stores that are not tagged as an assignment in memory for
1609e3b55780SDimitry Andric // the variables associated with that address. These stores may not be tagged
1610e3b55780SDimitry Andric // because a) the store cannot be represented using dbg.assigns (non-const
1611e3b55780SDimitry Andric // length or offset) or b) the tag was accidentally dropped during
1612e3b55780SDimitry Andric // optimisations. For these stores we fall back to assuming that the stack
1613e3b55780SDimitry Andric // home is a valid location for the variables. The benefit is that this
1614e3b55780SDimitry Andric // prevents us missing an assignment and therefore incorrectly maintaining
1615e3b55780SDimitry Andric // earlier location definitions, and in many cases it should be a reasonable
1616e3b55780SDimitry Andric // assumption. However, this will occasionally lead to slight
1617e3b55780SDimitry Andric // inaccuracies. The value of a hoisted untagged store will be visible
1618e3b55780SDimitry Andric // "early", for example.
1619e3b55780SDimitry Andric assert(!I.hasMetadata(LLVMContext::MD_DIAssignID));
1620e3b55780SDimitry Andric auto It = UntaggedStoreVars.find(&I);
1621e3b55780SDimitry Andric if (It == UntaggedStoreVars.end())
1622e3b55780SDimitry Andric return; // No variables associated with the store destination.
1623e3b55780SDimitry Andric
1624e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << "processUntaggedInstruction on UNTAGGED INST " << I
1625e3b55780SDimitry Andric << "\n");
1626e3b55780SDimitry Andric // Iterate over the variables that this store affects, add a NoneOrPhi dbg
1627e3b55780SDimitry Andric // and mem def, set lockind to Mem, and emit a location def for each.
1628e3b55780SDimitry Andric for (auto [Var, Info] : It->second) {
1629e3b55780SDimitry Andric // This instruction is treated as both a debug and memory assignment,
1630e3b55780SDimitry Andric // meaning the memory location should be used. We don't have an assignment
1631e3b55780SDimitry Andric // ID though so use Assignment::makeNoneOrPhi() to create an imaginary one.
1632e3b55780SDimitry Andric addMemDef(LiveSet, Var, Assignment::makeNoneOrPhi());
1633e3b55780SDimitry Andric addDbgDef(LiveSet, Var, Assignment::makeNoneOrPhi());
1634e3b55780SDimitry Andric setLocKind(LiveSet, Var, LocKind::Mem);
1635e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << " setting Stack LocKind to: " << locStr(LocKind::Mem)
1636e3b55780SDimitry Andric << "\n");
1637e3b55780SDimitry Andric // Build the dbg location def to insert.
1638e3b55780SDimitry Andric //
1639e3b55780SDimitry Andric // DIExpression: Add fragment and offset.
1640e3b55780SDimitry Andric DebugVariable V = FnVarLocs->getVariable(Var);
1641e3b55780SDimitry Andric DIExpression *DIE = DIExpression::get(I.getContext(), std::nullopt);
1642e3b55780SDimitry Andric if (auto Frag = V.getFragment()) {
1643e3b55780SDimitry Andric auto R = DIExpression::createFragmentExpression(DIE, Frag->OffsetInBits,
1644e3b55780SDimitry Andric Frag->SizeInBits);
1645e3b55780SDimitry Andric assert(R && "unexpected createFragmentExpression failure");
1646e3b55780SDimitry Andric DIE = *R;
1647e3b55780SDimitry Andric }
1648e3b55780SDimitry Andric SmallVector<uint64_t, 3> Ops;
1649e3b55780SDimitry Andric if (Info.OffsetInBits)
1650e3b55780SDimitry Andric Ops = {dwarf::DW_OP_plus_uconst, Info.OffsetInBits / 8};
1651e3b55780SDimitry Andric Ops.push_back(dwarf::DW_OP_deref);
1652e3b55780SDimitry Andric DIE = DIExpression::prependOpcodes(DIE, Ops, /*StackValue=*/false,
1653e3b55780SDimitry Andric /*EntryValue=*/false);
1654ac9a064cSDimitry Andric // Find a suitable insert point, before the next instruction or DbgRecord
16554df029ccSDimitry Andric // after I.
16564df029ccSDimitry Andric auto InsertBefore = getNextNode(&I);
1657e3b55780SDimitry Andric assert(InsertBefore && "Shouldn't be inserting after a terminator");
1658e3b55780SDimitry Andric
1659e3b55780SDimitry Andric // Get DILocation for this unrecorded assignment.
1660e3b55780SDimitry Andric DILocation *InlinedAt = const_cast<DILocation *>(V.getInlinedAt());
1661e3b55780SDimitry Andric const DILocation *DILoc = DILocation::get(
1662e3b55780SDimitry Andric Fn.getContext(), 0, 0, V.getVariable()->getScope(), InlinedAt);
1663e3b55780SDimitry Andric
1664e3b55780SDimitry Andric VarLocInfo VarLoc;
1665e3b55780SDimitry Andric VarLoc.VariableID = static_cast<VariableID>(Var);
1666e3b55780SDimitry Andric VarLoc.Expr = DIE;
16677fa27ce4SDimitry Andric VarLoc.Values = RawLocationWrapper(
16687fa27ce4SDimitry Andric ValueAsMetadata::get(const_cast<AllocaInst *>(Info.Base)));
1669e3b55780SDimitry Andric VarLoc.DL = DILoc;
1670e3b55780SDimitry Andric // 3. Insert it into the map for later.
1671e3b55780SDimitry Andric InsertBeforeMap[InsertBefore].push_back(VarLoc);
1672e3b55780SDimitry Andric }
1673e3b55780SDimitry Andric }
1674e3b55780SDimitry Andric
processTaggedInstruction(Instruction & I,AssignmentTrackingLowering::BlockInfo * LiveSet)1675e3b55780SDimitry Andric void AssignmentTrackingLowering::processTaggedInstruction(
1676e3b55780SDimitry Andric Instruction &I, AssignmentTrackingLowering::BlockInfo *LiveSet) {
1677e3b55780SDimitry Andric auto Linked = at::getAssignmentMarkers(&I);
1678ac9a064cSDimitry Andric auto LinkedDPAssigns = at::getDVRAssignmentMarkers(&I);
1679e3b55780SDimitry Andric // No dbg.assign intrinsics linked.
1680e3b55780SDimitry Andric // FIXME: All vars that have a stack slot this store modifies that don't have
1681e3b55780SDimitry Andric // a dbg.assign linked to it should probably treat this like an untagged
1682e3b55780SDimitry Andric // store.
16834df029ccSDimitry Andric if (Linked.empty() && LinkedDPAssigns.empty())
1684e3b55780SDimitry Andric return;
1685e3b55780SDimitry Andric
1686e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << "processTaggedInstruction on " << I << "\n");
16874df029ccSDimitry Andric auto ProcessLinkedAssign = [&](auto *Assign) {
16884df029ccSDimitry Andric VariableID Var = getVariableID(DebugVariable(Assign));
1689e3b55780SDimitry Andric // Something has gone wrong if VarsWithStackSlot doesn't contain a variable
1690e3b55780SDimitry Andric // that is linked to a store.
16914df029ccSDimitry Andric assert(VarsWithStackSlot->count(getAggregate(Assign)) &&
16924df029ccSDimitry Andric "expected Assign's variable to have stack slot");
1693e3b55780SDimitry Andric
1694e3b55780SDimitry Andric Assignment AV = Assignment::makeFromMemDef(getIDFromInst(I));
1695e3b55780SDimitry Andric addMemDef(LiveSet, Var, AV);
1696e3b55780SDimitry Andric
16974df029ccSDimitry Andric LLVM_DEBUG(dbgs() << " linked to " << *Assign << "\n");
1698e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << " LiveLoc " << locStr(getLocKind(LiveSet, Var))
1699e3b55780SDimitry Andric << " -> ");
1700e3b55780SDimitry Andric
1701e3b55780SDimitry Andric // The last assignment to the stack is now AV. Check if the last debug
1702e3b55780SDimitry Andric // assignment has a matching Assignment.
17037fa27ce4SDimitry Andric if (hasVarWithAssignment(LiveSet, BlockInfo::Debug, Var, AV)) {
1704e3b55780SDimitry Andric // The StackHomeValue and DebugValue for this variable match so we can
1705e3b55780SDimitry Andric // emit a stack home location here.
1706e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << "Mem, Stack matches Debug program\n";);
1707e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << " Stack val: "; AV.dump(dbgs()); dbgs() << "\n");
1708e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << " Debug val: ";
17097fa27ce4SDimitry Andric LiveSet->DebugValue[static_cast<unsigned>(Var)].dump(dbgs());
17107fa27ce4SDimitry Andric dbgs() << "\n");
1711e3b55780SDimitry Andric setLocKind(LiveSet, Var, LocKind::Mem);
17124df029ccSDimitry Andric emitDbgValue(LocKind::Mem, Assign, &I);
17134df029ccSDimitry Andric return;
1714e3b55780SDimitry Andric }
1715e3b55780SDimitry Andric
1716e3b55780SDimitry Andric // The StackHomeValue and DebugValue for this variable do not match. I.e.
1717e3b55780SDimitry Andric // The value currently stored in the stack is not what we'd expect to
1718e3b55780SDimitry Andric // see, so we cannot use emit a stack home location here. Now we will
1719e3b55780SDimitry Andric // look at the live LocKind for the variable and determine an appropriate
1720e3b55780SDimitry Andric // dbg.value to emit.
1721e3b55780SDimitry Andric LocKind PrevLoc = getLocKind(LiveSet, Var);
1722e3b55780SDimitry Andric switch (PrevLoc) {
1723e3b55780SDimitry Andric case LocKind::Val: {
1724e3b55780SDimitry Andric // The value in memory in memory has changed but we're not currently
1725e3b55780SDimitry Andric // using the memory location. Do nothing.
1726e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << "Val, (unchanged)\n";);
1727e3b55780SDimitry Andric setLocKind(LiveSet, Var, LocKind::Val);
1728e3b55780SDimitry Andric } break;
1729e3b55780SDimitry Andric case LocKind::Mem: {
1730e3b55780SDimitry Andric // There's been an assignment to memory that we were using as a
1731e3b55780SDimitry Andric // location for this variable, and the Assignment doesn't match what
1732e3b55780SDimitry Andric // we'd expect to see in memory.
17337fa27ce4SDimitry Andric Assignment DbgAV = LiveSet->getAssignment(BlockInfo::Debug, Var);
17347fa27ce4SDimitry Andric if (DbgAV.Status == Assignment::NoneOrPhi) {
1735e3b55780SDimitry Andric // We need to terminate any previously open location now.
1736e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << "None, No Debug value available\n";);
1737e3b55780SDimitry Andric setLocKind(LiveSet, Var, LocKind::None);
17384df029ccSDimitry Andric emitDbgValue(LocKind::None, Assign, &I);
1739e3b55780SDimitry Andric } else {
1740e3b55780SDimitry Andric // The previous DebugValue Value can be used here.
1741e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << "Val, Debug value is Known\n";);
1742e3b55780SDimitry Andric setLocKind(LiveSet, Var, LocKind::Val);
17437fa27ce4SDimitry Andric if (DbgAV.Source) {
17447fa27ce4SDimitry Andric emitDbgValue(LocKind::Val, DbgAV.Source, &I);
1745e3b55780SDimitry Andric } else {
1746e3b55780SDimitry Andric // PrevAV.Source is nullptr so we must emit undef here.
17474df029ccSDimitry Andric emitDbgValue(LocKind::None, Assign, &I);
1748e3b55780SDimitry Andric }
1749e3b55780SDimitry Andric }
1750e3b55780SDimitry Andric } break;
1751e3b55780SDimitry Andric case LocKind::None: {
1752e3b55780SDimitry Andric // There's been an assignment to memory and we currently are
1753e3b55780SDimitry Andric // not tracking a location for the variable. Do not emit anything.
1754e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << "None, (unchanged)\n";);
1755e3b55780SDimitry Andric setLocKind(LiveSet, Var, LocKind::None);
1756e3b55780SDimitry Andric } break;
1757e3b55780SDimitry Andric }
17584df029ccSDimitry Andric };
17594df029ccSDimitry Andric for (DbgAssignIntrinsic *DAI : Linked)
17604df029ccSDimitry Andric ProcessLinkedAssign(DAI);
1761ac9a064cSDimitry Andric for (DbgVariableRecord *DVR : LinkedDPAssigns)
1762ac9a064cSDimitry Andric ProcessLinkedAssign(DVR);
1763e3b55780SDimitry Andric }
1764e3b55780SDimitry Andric
processDbgAssign(AssignRecord Assign,BlockInfo * LiveSet)17654df029ccSDimitry Andric void AssignmentTrackingLowering::processDbgAssign(AssignRecord Assign,
1766e3b55780SDimitry Andric BlockInfo *LiveSet) {
17674df029ccSDimitry Andric auto ProcessDbgAssignImpl = [&](auto *DbgAssign) {
1768e3b55780SDimitry Andric // Only bother tracking variables that are at some point stack homed. Other
1769e3b55780SDimitry Andric // variables can be dealt with trivially later.
17704df029ccSDimitry Andric if (!VarsWithStackSlot->count(getAggregate(DbgAssign)))
1771e3b55780SDimitry Andric return;
1772e3b55780SDimitry Andric
17734df029ccSDimitry Andric VariableID Var = getVariableID(DebugVariable(DbgAssign));
17744df029ccSDimitry Andric Assignment AV = Assignment::make(getIDFromMarker(*DbgAssign), DbgAssign);
1775e3b55780SDimitry Andric addDbgDef(LiveSet, Var, AV);
1776e3b55780SDimitry Andric
17774df029ccSDimitry Andric LLVM_DEBUG(dbgs() << "processDbgAssign on " << *DbgAssign << "\n";);
1778e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << " LiveLoc " << locStr(getLocKind(LiveSet, Var))
1779e3b55780SDimitry Andric << " -> ");
1780e3b55780SDimitry Andric
1781e3b55780SDimitry Andric // Check if the DebugValue and StackHomeValue both hold the same
1782e3b55780SDimitry Andric // Assignment.
17837fa27ce4SDimitry Andric if (hasVarWithAssignment(LiveSet, BlockInfo::Stack, Var, AV)) {
17844df029ccSDimitry Andric // They match. We can use the stack home because the debug intrinsics
17854df029ccSDimitry Andric // state that an assignment happened here, and we know that specific
17864df029ccSDimitry Andric // assignment was the last one to take place in memory for this variable.
1787e3b55780SDimitry Andric LocKind Kind;
17884df029ccSDimitry Andric if (DbgAssign->isKillAddress()) {
1789e3b55780SDimitry Andric LLVM_DEBUG(
1790e3b55780SDimitry Andric dbgs()
1791e3b55780SDimitry Andric << "Val, Stack matches Debug program but address is killed\n";);
1792e3b55780SDimitry Andric Kind = LocKind::Val;
1793e3b55780SDimitry Andric } else {
1794e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << "Mem, Stack matches Debug program\n";);
1795e3b55780SDimitry Andric Kind = LocKind::Mem;
1796e3b55780SDimitry Andric };
1797e3b55780SDimitry Andric setLocKind(LiveSet, Var, Kind);
17984df029ccSDimitry Andric emitDbgValue(Kind, DbgAssign, DbgAssign);
1799e3b55780SDimitry Andric } else {
18004df029ccSDimitry Andric // The last assignment to the memory location isn't the one that we want
18014df029ccSDimitry Andric // to show to the user so emit a dbg.value(Value). Value may be undef.
1802e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << "Val, Stack contents is unknown\n";);
1803e3b55780SDimitry Andric setLocKind(LiveSet, Var, LocKind::Val);
18044df029ccSDimitry Andric emitDbgValue(LocKind::Val, DbgAssign, DbgAssign);
1805e3b55780SDimitry Andric }
18064df029ccSDimitry Andric };
1807ac9a064cSDimitry Andric if (isa<DbgVariableRecord *>(Assign))
1808ac9a064cSDimitry Andric return ProcessDbgAssignImpl(cast<DbgVariableRecord *>(Assign));
18094df029ccSDimitry Andric return ProcessDbgAssignImpl(cast<DbgAssignIntrinsic *>(Assign));
1810e3b55780SDimitry Andric }
1811e3b55780SDimitry Andric
processDbgValue(PointerUnion<DbgValueInst *,DbgVariableRecord * > DbgValueRecord,BlockInfo * LiveSet)18124df029ccSDimitry Andric void AssignmentTrackingLowering::processDbgValue(
1813ac9a064cSDimitry Andric PointerUnion<DbgValueInst *, DbgVariableRecord *> DbgValueRecord,
1814e3b55780SDimitry Andric BlockInfo *LiveSet) {
18154df029ccSDimitry Andric auto ProcessDbgValueImpl = [&](auto *DbgValue) {
1816e3b55780SDimitry Andric // Only other tracking variables that are at some point stack homed.
1817e3b55780SDimitry Andric // Other variables can be dealt with trivally later.
18184df029ccSDimitry Andric if (!VarsWithStackSlot->count(getAggregate(DbgValue)))
1819e3b55780SDimitry Andric return;
1820e3b55780SDimitry Andric
18214df029ccSDimitry Andric VariableID Var = getVariableID(DebugVariable(DbgValue));
1822e3b55780SDimitry Andric // We have no ID to create an Assignment with so we mark this assignment as
1823e3b55780SDimitry Andric // NoneOrPhi. Note that the dbg.value still exists, we just cannot determine
1824e3b55780SDimitry Andric // the assignment responsible for setting this value.
1825e3b55780SDimitry Andric // This is fine; dbg.values are essentially interchangable with unlinked
1826e3b55780SDimitry Andric // dbg.assigns, and some passes such as mem2reg and instcombine add them to
1827e3b55780SDimitry Andric // PHIs for promoted variables.
1828e3b55780SDimitry Andric Assignment AV = Assignment::makeNoneOrPhi();
1829e3b55780SDimitry Andric addDbgDef(LiveSet, Var, AV);
1830e3b55780SDimitry Andric
18314df029ccSDimitry Andric LLVM_DEBUG(dbgs() << "processDbgValue on " << *DbgValue << "\n";);
1832e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << " LiveLoc " << locStr(getLocKind(LiveSet, Var))
1833e3b55780SDimitry Andric << " -> Val, dbg.value override");
1834e3b55780SDimitry Andric
1835e3b55780SDimitry Andric setLocKind(LiveSet, Var, LocKind::Val);
18364df029ccSDimitry Andric emitDbgValue(LocKind::Val, DbgValue, DbgValue);
18374df029ccSDimitry Andric };
1838ac9a064cSDimitry Andric if (isa<DbgVariableRecord *>(DbgValueRecord))
1839ac9a064cSDimitry Andric return ProcessDbgValueImpl(cast<DbgVariableRecord *>(DbgValueRecord));
18404df029ccSDimitry Andric return ProcessDbgValueImpl(cast<DbgValueInst *>(DbgValueRecord));
1841e3b55780SDimitry Andric }
1842e3b55780SDimitry Andric
hasZeroSizedFragment(T & DbgValue)18434df029ccSDimitry Andric template <typename T> static bool hasZeroSizedFragment(T &DbgValue) {
18444df029ccSDimitry Andric if (auto F = DbgValue.getExpression()->getFragmentInfo())
18457fa27ce4SDimitry Andric return F->SizeInBits == 0;
18467fa27ce4SDimitry Andric return false;
18477fa27ce4SDimitry Andric }
18487fa27ce4SDimitry Andric
processDbgInstruction(DbgInfoIntrinsic & I,AssignmentTrackingLowering::BlockInfo * LiveSet)1849e3b55780SDimitry Andric void AssignmentTrackingLowering::processDbgInstruction(
18507fa27ce4SDimitry Andric DbgInfoIntrinsic &I, AssignmentTrackingLowering::BlockInfo *LiveSet) {
18517fa27ce4SDimitry Andric auto *DVI = dyn_cast<DbgVariableIntrinsic>(&I);
18527fa27ce4SDimitry Andric if (!DVI)
18537fa27ce4SDimitry Andric return;
18547fa27ce4SDimitry Andric
18557fa27ce4SDimitry Andric // Ignore assignments to zero bits of the variable.
18567fa27ce4SDimitry Andric if (hasZeroSizedFragment(*DVI))
18577fa27ce4SDimitry Andric return;
18587fa27ce4SDimitry Andric
1859e3b55780SDimitry Andric if (auto *DAI = dyn_cast<DbgAssignIntrinsic>(&I))
18604df029ccSDimitry Andric processDbgAssign(DAI, LiveSet);
1861e3b55780SDimitry Andric else if (auto *DVI = dyn_cast<DbgValueInst>(&I))
18624df029ccSDimitry Andric processDbgValue(DVI, LiveSet);
18634df029ccSDimitry Andric }
processDbgVariableRecord(DbgVariableRecord & DVR,AssignmentTrackingLowering::BlockInfo * LiveSet)1864ac9a064cSDimitry Andric void AssignmentTrackingLowering::processDbgVariableRecord(
1865ac9a064cSDimitry Andric DbgVariableRecord &DVR, AssignmentTrackingLowering::BlockInfo *LiveSet) {
18664df029ccSDimitry Andric // Ignore assignments to zero bits of the variable.
1867ac9a064cSDimitry Andric if (hasZeroSizedFragment(DVR))
18684df029ccSDimitry Andric return;
18694df029ccSDimitry Andric
1870ac9a064cSDimitry Andric if (DVR.isDbgAssign())
1871ac9a064cSDimitry Andric processDbgAssign(&DVR, LiveSet);
1872ac9a064cSDimitry Andric else if (DVR.isDbgValue())
1873ac9a064cSDimitry Andric processDbgValue(&DVR, LiveSet);
1874e3b55780SDimitry Andric }
1875e3b55780SDimitry Andric
resetInsertionPoint(Instruction & After)1876e3b55780SDimitry Andric void AssignmentTrackingLowering::resetInsertionPoint(Instruction &After) {
1877e3b55780SDimitry Andric assert(!After.isTerminator() && "Can't insert after a terminator");
18784df029ccSDimitry Andric auto *R = InsertBeforeMap.find(getNextNode(&After));
18794df029ccSDimitry Andric if (R == InsertBeforeMap.end())
18804df029ccSDimitry Andric return;
18814df029ccSDimitry Andric R->second.clear();
18824df029ccSDimitry Andric }
resetInsertionPoint(DbgVariableRecord & After)1883ac9a064cSDimitry Andric void AssignmentTrackingLowering::resetInsertionPoint(DbgVariableRecord &After) {
18844df029ccSDimitry Andric auto *R = InsertBeforeMap.find(getNextNode(&After));
1885e3b55780SDimitry Andric if (R == InsertBeforeMap.end())
1886e3b55780SDimitry Andric return;
1887e3b55780SDimitry Andric R->second.clear();
1888e3b55780SDimitry Andric }
1889e3b55780SDimitry Andric
process(BasicBlock & BB,BlockInfo * LiveSet)1890e3b55780SDimitry Andric void AssignmentTrackingLowering::process(BasicBlock &BB, BlockInfo *LiveSet) {
1891ac9a064cSDimitry Andric // If the block starts with DbgRecords, we need to process those DbgRecords as
18924df029ccSDimitry Andric // their own frame without processing any instructions first.
1893ac9a064cSDimitry Andric bool ProcessedLeadingDbgRecords = !BB.begin()->hasDbgRecords();
1894e3b55780SDimitry Andric for (auto II = BB.begin(), EI = BB.end(); II != EI;) {
1895e3b55780SDimitry Andric assert(VarsTouchedThisFrame.empty());
1896e3b55780SDimitry Andric // Process the instructions in "frames". A "frame" includes a single
1897e3b55780SDimitry Andric // non-debug instruction followed any debug instructions before the
1898e3b55780SDimitry Andric // next non-debug instruction.
18994df029ccSDimitry Andric
1900ac9a064cSDimitry Andric // Skip the current instruction if it has unprocessed DbgRecords attached
1901ac9a064cSDimitry Andric // (see comment above `ProcessedLeadingDbgRecords`).
1902ac9a064cSDimitry Andric if (ProcessedLeadingDbgRecords) {
19034df029ccSDimitry Andric // II is now either a debug intrinsic, a non-debug instruction with no
1904ac9a064cSDimitry Andric // attached DbgRecords, or a non-debug instruction with attached processed
1905ac9a064cSDimitry Andric // DbgRecords.
19064df029ccSDimitry Andric // II has not been processed.
1907e3b55780SDimitry Andric if (!isa<DbgInfoIntrinsic>(&*II)) {
1908e3b55780SDimitry Andric if (II->isTerminator())
1909e3b55780SDimitry Andric break;
1910e3b55780SDimitry Andric resetInsertionPoint(*II);
1911e3b55780SDimitry Andric processNonDbgInstruction(*II, LiveSet);
1912e3b55780SDimitry Andric assert(LiveSet->isValid());
1913e3b55780SDimitry Andric ++II;
1914e3b55780SDimitry Andric }
19154df029ccSDimitry Andric }
19164df029ccSDimitry Andric // II is now either a debug intrinsic, a non-debug instruction with no
1917ac9a064cSDimitry Andric // attached DbgRecords, or a non-debug instruction with attached unprocessed
1918ac9a064cSDimitry Andric // DbgRecords.
1919ac9a064cSDimitry Andric if (II != EI && II->hasDbgRecords()) {
1920ac9a064cSDimitry Andric // Skip over non-variable debug records (i.e., labels). They're going to
1921ac9a064cSDimitry Andric // be read from IR (possibly re-ordering them within the debug record
1922ac9a064cSDimitry Andric // range) rather than from the analysis results.
1923ac9a064cSDimitry Andric for (DbgVariableRecord &DVR : filterDbgVars(II->getDbgRecordRange())) {
1924ac9a064cSDimitry Andric resetInsertionPoint(DVR);
1925ac9a064cSDimitry Andric processDbgVariableRecord(DVR, LiveSet);
19264df029ccSDimitry Andric assert(LiveSet->isValid());
19274df029ccSDimitry Andric }
19284df029ccSDimitry Andric }
1929ac9a064cSDimitry Andric ProcessedLeadingDbgRecords = true;
1930e3b55780SDimitry Andric while (II != EI) {
19317fa27ce4SDimitry Andric auto *Dbg = dyn_cast<DbgInfoIntrinsic>(&*II);
19327fa27ce4SDimitry Andric if (!Dbg)
1933e3b55780SDimitry Andric break;
1934e3b55780SDimitry Andric resetInsertionPoint(*II);
19357fa27ce4SDimitry Andric processDbgInstruction(*Dbg, LiveSet);
1936e3b55780SDimitry Andric assert(LiveSet->isValid());
1937e3b55780SDimitry Andric ++II;
1938e3b55780SDimitry Andric }
1939ac9a064cSDimitry Andric // II is now a non-debug instruction either with no attached DbgRecords, or
1940ac9a064cSDimitry Andric // with attached processed DbgRecords. II has not been processed, and all
1941ac9a064cSDimitry Andric // debug instructions or DbgRecords in the frame preceding II have been
19424df029ccSDimitry Andric // processed.
1943e3b55780SDimitry Andric
1944e3b55780SDimitry Andric // We've processed everything in the "frame". Now determine which variables
1945e3b55780SDimitry Andric // cannot be represented by a dbg.declare.
1946e3b55780SDimitry Andric for (auto Var : VarsTouchedThisFrame) {
1947e3b55780SDimitry Andric LocKind Loc = getLocKind(LiveSet, Var);
1948e3b55780SDimitry Andric // If a variable's LocKind is anything other than LocKind::Mem then we
1949e3b55780SDimitry Andric // must note that it cannot be represented with a dbg.declare.
1950e3b55780SDimitry Andric // Note that this check is enough without having to check the result of
1951e3b55780SDimitry Andric // joins() because for join to produce anything other than Mem after
1952e3b55780SDimitry Andric // we've already seen a Mem we'd be joining None or Val with Mem. In that
1953e3b55780SDimitry Andric // case, we've already hit this codepath when we set the LocKind to Val
1954e3b55780SDimitry Andric // or None in that block.
1955e3b55780SDimitry Andric if (Loc != LocKind::Mem) {
1956e3b55780SDimitry Andric DebugVariable DbgVar = FnVarLocs->getVariable(Var);
1957e3b55780SDimitry Andric DebugAggregate Aggr{DbgVar.getVariable(), DbgVar.getInlinedAt()};
1958e3b55780SDimitry Andric NotAlwaysStackHomed.insert(Aggr);
1959e3b55780SDimitry Andric }
1960e3b55780SDimitry Andric }
1961e3b55780SDimitry Andric VarsTouchedThisFrame.clear();
1962e3b55780SDimitry Andric }
1963e3b55780SDimitry Andric }
1964e3b55780SDimitry Andric
1965e3b55780SDimitry Andric AssignmentTrackingLowering::LocKind
joinKind(LocKind A,LocKind B)1966e3b55780SDimitry Andric AssignmentTrackingLowering::joinKind(LocKind A, LocKind B) {
1967e3b55780SDimitry Andric // Partial order:
1968e3b55780SDimitry Andric // None > Mem, Val
1969e3b55780SDimitry Andric return A == B ? A : LocKind::None;
1970e3b55780SDimitry Andric }
1971e3b55780SDimitry Andric
1972e3b55780SDimitry Andric AssignmentTrackingLowering::Assignment
joinAssignment(const Assignment & A,const Assignment & B)1973e3b55780SDimitry Andric AssignmentTrackingLowering::joinAssignment(const Assignment &A,
1974e3b55780SDimitry Andric const Assignment &B) {
1975e3b55780SDimitry Andric // Partial order:
1976e3b55780SDimitry Andric // NoneOrPhi(null, null) > Known(v, ?s)
1977e3b55780SDimitry Andric
1978e3b55780SDimitry Andric // If either are NoneOrPhi the join is NoneOrPhi.
1979e3b55780SDimitry Andric // If either value is different then the result is
1980e3b55780SDimitry Andric // NoneOrPhi (joining two values is a Phi).
1981e3b55780SDimitry Andric if (!A.isSameSourceAssignment(B))
1982e3b55780SDimitry Andric return Assignment::makeNoneOrPhi();
1983e3b55780SDimitry Andric if (A.Status == Assignment::NoneOrPhi)
1984e3b55780SDimitry Andric return Assignment::makeNoneOrPhi();
1985e3b55780SDimitry Andric
1986e3b55780SDimitry Andric // Source is used to lookup the value + expression in the debug program if
1987e3b55780SDimitry Andric // the stack slot gets assigned a value earlier than expected. Because
1988e3b55780SDimitry Andric // we're only tracking the one dbg.assign, we can't capture debug PHIs.
1989e3b55780SDimitry Andric // It's unlikely that we're losing out on much coverage by avoiding that
1990e3b55780SDimitry Andric // extra work.
1991e3b55780SDimitry Andric // The Source may differ in this situation:
1992e3b55780SDimitry Andric // Pred.1:
1993e3b55780SDimitry Andric // dbg.assign i32 0, ..., !1, ...
1994e3b55780SDimitry Andric // Pred.2:
1995e3b55780SDimitry Andric // dbg.assign i32 1, ..., !1, ...
1996e3b55780SDimitry Andric // Here the same assignment (!1) was performed in both preds in the source,
1997e3b55780SDimitry Andric // but we can't use either one unless they are identical (e.g. .we don't
1998e3b55780SDimitry Andric // want to arbitrarily pick between constant values).
19994df029ccSDimitry Andric auto JoinSource = [&]() -> AssignRecord {
2000e3b55780SDimitry Andric if (A.Source == B.Source)
2001e3b55780SDimitry Andric return A.Source;
20024df029ccSDimitry Andric if (!A.Source || !B.Source)
20034df029ccSDimitry Andric return AssignRecord();
2004ac9a064cSDimitry Andric assert(isa<DbgVariableRecord *>(A.Source) ==
2005ac9a064cSDimitry Andric isa<DbgVariableRecord *>(B.Source));
2006ac9a064cSDimitry Andric if (isa<DbgVariableRecord *>(A.Source) &&
2007ac9a064cSDimitry Andric cast<DbgVariableRecord *>(A.Source)->isEquivalentTo(
2008ac9a064cSDimitry Andric *cast<DbgVariableRecord *>(B.Source)))
2009e3b55780SDimitry Andric return A.Source;
20104df029ccSDimitry Andric if (isa<DbgAssignIntrinsic *>(A.Source) &&
20114df029ccSDimitry Andric cast<DbgAssignIntrinsic *>(A.Source)->isIdenticalTo(
20124df029ccSDimitry Andric cast<DbgAssignIntrinsic *>(B.Source)))
20134df029ccSDimitry Andric return A.Source;
20144df029ccSDimitry Andric return AssignRecord();
2015e3b55780SDimitry Andric };
20164df029ccSDimitry Andric AssignRecord Source = JoinSource();
2017e3b55780SDimitry Andric assert(A.Status == B.Status && A.Status == Assignment::Known);
2018e3b55780SDimitry Andric assert(A.ID == B.ID);
2019e3b55780SDimitry Andric return Assignment::make(A.ID, Source);
2020e3b55780SDimitry Andric }
2021e3b55780SDimitry Andric
2022e3b55780SDimitry Andric AssignmentTrackingLowering::BlockInfo
joinBlockInfo(const BlockInfo & A,const BlockInfo & B)2023e3b55780SDimitry Andric AssignmentTrackingLowering::joinBlockInfo(const BlockInfo &A,
2024e3b55780SDimitry Andric const BlockInfo &B) {
20257fa27ce4SDimitry Andric return BlockInfo::join(A, B, TrackedVariablesVectorSize);
2026e3b55780SDimitry Andric }
2027e3b55780SDimitry Andric
join(const BasicBlock & BB,const SmallPtrSet<BasicBlock *,16> & Visited)2028e3b55780SDimitry Andric bool AssignmentTrackingLowering::join(
2029e3b55780SDimitry Andric const BasicBlock &BB, const SmallPtrSet<BasicBlock *, 16> &Visited) {
20307fa27ce4SDimitry Andric
20317fa27ce4SDimitry Andric SmallVector<const BasicBlock *> VisitedPreds;
2032e3b55780SDimitry Andric // Ignore backedges if we have not visited the predecessor yet. As the
2033e3b55780SDimitry Andric // predecessor hasn't yet had locations propagated into it, most locations
2034e3b55780SDimitry Andric // will not yet be valid, so treat them as all being uninitialized and
2035e3b55780SDimitry Andric // potentially valid. If a location guessed to be correct here is
2036e3b55780SDimitry Andric // invalidated later, we will remove it when we revisit this block. This
2037e3b55780SDimitry Andric // is essentially the same as initialising all LocKinds and Assignments to
2038e3b55780SDimitry Andric // an implicit ⊥ value which is the identity value for the join operation.
20394df029ccSDimitry Andric for (const BasicBlock *Pred : predecessors(&BB)) {
20407fa27ce4SDimitry Andric if (Visited.count(Pred))
20417fa27ce4SDimitry Andric VisitedPreds.push_back(Pred);
2042e3b55780SDimitry Andric }
2043e3b55780SDimitry Andric
20447fa27ce4SDimitry Andric // No preds visited yet.
20457fa27ce4SDimitry Andric if (VisitedPreds.empty()) {
20467fa27ce4SDimitry Andric auto It = LiveIn.try_emplace(&BB, BlockInfo());
20477fa27ce4SDimitry Andric bool DidInsert = It.second;
20487fa27ce4SDimitry Andric if (DidInsert)
20497fa27ce4SDimitry Andric It.first->second.init(TrackedVariablesVectorSize);
20507fa27ce4SDimitry Andric return /*Changed*/ DidInsert;
20517fa27ce4SDimitry Andric }
20527fa27ce4SDimitry Andric
20537fa27ce4SDimitry Andric // Exactly one visited pred. Copy the LiveOut from that pred into BB LiveIn.
20547fa27ce4SDimitry Andric if (VisitedPreds.size() == 1) {
20557fa27ce4SDimitry Andric const BlockInfo &PredLiveOut = LiveOut.find(VisitedPreds[0])->second;
20567fa27ce4SDimitry Andric auto CurrentLiveInEntry = LiveIn.find(&BB);
20577fa27ce4SDimitry Andric
20587fa27ce4SDimitry Andric // Check if there isn't an entry, or there is but the LiveIn set has
20597fa27ce4SDimitry Andric // changed (expensive check).
20607fa27ce4SDimitry Andric if (CurrentLiveInEntry == LiveIn.end())
20617fa27ce4SDimitry Andric LiveIn.insert(std::make_pair(&BB, PredLiveOut));
20627fa27ce4SDimitry Andric else if (PredLiveOut != CurrentLiveInEntry->second)
20637fa27ce4SDimitry Andric CurrentLiveInEntry->second = PredLiveOut;
20647fa27ce4SDimitry Andric else
20657fa27ce4SDimitry Andric return /*Changed*/ false;
20667fa27ce4SDimitry Andric return /*Changed*/ true;
20677fa27ce4SDimitry Andric }
20687fa27ce4SDimitry Andric
20697fa27ce4SDimitry Andric // More than one pred. Join LiveOuts of blocks 1 and 2.
20707fa27ce4SDimitry Andric assert(VisitedPreds.size() > 1);
20717fa27ce4SDimitry Andric const BlockInfo &PredLiveOut0 = LiveOut.find(VisitedPreds[0])->second;
20727fa27ce4SDimitry Andric const BlockInfo &PredLiveOut1 = LiveOut.find(VisitedPreds[1])->second;
20737fa27ce4SDimitry Andric BlockInfo BBLiveIn = joinBlockInfo(PredLiveOut0, PredLiveOut1);
20747fa27ce4SDimitry Andric
20757fa27ce4SDimitry Andric // Join the LiveOuts of subsequent blocks.
20767fa27ce4SDimitry Andric ArrayRef Tail = ArrayRef(VisitedPreds).drop_front(2);
20777fa27ce4SDimitry Andric for (const BasicBlock *Pred : Tail) {
20787fa27ce4SDimitry Andric const auto &PredLiveOut = LiveOut.find(Pred);
20797fa27ce4SDimitry Andric assert(PredLiveOut != LiveOut.end() &&
20807fa27ce4SDimitry Andric "block should have been processed already");
20817fa27ce4SDimitry Andric BBLiveIn = joinBlockInfo(std::move(BBLiveIn), PredLiveOut->second);
20827fa27ce4SDimitry Andric }
20837fa27ce4SDimitry Andric
20847fa27ce4SDimitry Andric // Save the joined result for BB.
2085e3b55780SDimitry Andric auto CurrentLiveInEntry = LiveIn.find(&BB);
2086e3b55780SDimitry Andric // Check if there isn't an entry, or there is but the LiveIn set has changed
2087e3b55780SDimitry Andric // (expensive check).
20887fa27ce4SDimitry Andric if (CurrentLiveInEntry == LiveIn.end())
20897fa27ce4SDimitry Andric LiveIn.try_emplace(&BB, std::move(BBLiveIn));
20907fa27ce4SDimitry Andric else if (BBLiveIn != CurrentLiveInEntry->second)
20917fa27ce4SDimitry Andric CurrentLiveInEntry->second = std::move(BBLiveIn);
20927fa27ce4SDimitry Andric else
20937fa27ce4SDimitry Andric return /*Changed*/ false;
20947fa27ce4SDimitry Andric return /*Changed*/ true;
2095e3b55780SDimitry Andric }
2096e3b55780SDimitry Andric
2097e3b55780SDimitry Andric /// Return true if A fully contains B.
fullyContains(DIExpression::FragmentInfo A,DIExpression::FragmentInfo B)2098e3b55780SDimitry Andric static bool fullyContains(DIExpression::FragmentInfo A,
2099e3b55780SDimitry Andric DIExpression::FragmentInfo B) {
2100e3b55780SDimitry Andric auto ALeft = A.OffsetInBits;
2101e3b55780SDimitry Andric auto BLeft = B.OffsetInBits;
2102e3b55780SDimitry Andric if (BLeft < ALeft)
2103e3b55780SDimitry Andric return false;
2104e3b55780SDimitry Andric
2105e3b55780SDimitry Andric auto ARight = ALeft + A.SizeInBits;
2106e3b55780SDimitry Andric auto BRight = BLeft + B.SizeInBits;
2107e3b55780SDimitry Andric if (BRight > ARight)
2108e3b55780SDimitry Andric return false;
2109e3b55780SDimitry Andric return true;
2110e3b55780SDimitry Andric }
2111e3b55780SDimitry Andric
2112e3b55780SDimitry Andric static std::optional<at::AssignmentInfo>
getUntaggedStoreAssignmentInfo(const Instruction & I,const DataLayout & Layout)2113e3b55780SDimitry Andric getUntaggedStoreAssignmentInfo(const Instruction &I, const DataLayout &Layout) {
2114e3b55780SDimitry Andric // Don't bother checking if this is an AllocaInst. We know this
2115e3b55780SDimitry Andric // instruction has no tag which means there are no variables associated
2116e3b55780SDimitry Andric // with it.
2117e3b55780SDimitry Andric if (const auto *SI = dyn_cast<StoreInst>(&I))
2118e3b55780SDimitry Andric return at::getAssignmentInfo(Layout, SI);
2119e3b55780SDimitry Andric if (const auto *MI = dyn_cast<MemIntrinsic>(&I))
2120e3b55780SDimitry Andric return at::getAssignmentInfo(Layout, MI);
2121e3b55780SDimitry Andric // Alloca or non-store-like inst.
2122e3b55780SDimitry Andric return std::nullopt;
2123e3b55780SDimitry Andric }
2124e3b55780SDimitry Andric
DynCastToDbgDeclare(DbgVariableIntrinsic * DVI)21254df029ccSDimitry Andric DbgDeclareInst *DynCastToDbgDeclare(DbgVariableIntrinsic *DVI) {
21264df029ccSDimitry Andric return dyn_cast<DbgDeclareInst>(DVI);
21274df029ccSDimitry Andric }
21284df029ccSDimitry Andric
DynCastToDbgDeclare(DbgVariableRecord * DVR)2129ac9a064cSDimitry Andric DbgVariableRecord *DynCastToDbgDeclare(DbgVariableRecord *DVR) {
2130ac9a064cSDimitry Andric return DVR->isDbgDeclare() ? DVR : nullptr;
21314df029ccSDimitry Andric }
21324df029ccSDimitry Andric
2133e3b55780SDimitry Andric /// Build a map of {Variable x: Variables y} where all variable fragments
2134e3b55780SDimitry Andric /// contained within the variable fragment x are in set y. This means that
2135e3b55780SDimitry Andric /// y does not contain all overlaps because partial overlaps are excluded.
2136e3b55780SDimitry Andric ///
2137e3b55780SDimitry Andric /// While we're iterating over the function, add single location defs for
21387fa27ce4SDimitry Andric /// dbg.declares to \p FnVarLocs.
21397fa27ce4SDimitry Andric ///
21407fa27ce4SDimitry Andric /// Variables that are interesting to this pass in are added to
21417fa27ce4SDimitry Andric /// FnVarLocs->Variables first. TrackedVariablesVectorSize is set to the ID of
21427fa27ce4SDimitry Andric /// the last interesting variable plus 1, meaning variables with ID 1
21437fa27ce4SDimitry Andric /// (inclusive) to TrackedVariablesVectorSize (exclusive) are interesting. The
21447fa27ce4SDimitry Andric /// subsequent variables are either stack homed or fully promoted.
2145e3b55780SDimitry Andric ///
2146e3b55780SDimitry Andric /// Finally, populate UntaggedStoreVars with a mapping of untagged stores to
2147e3b55780SDimitry Andric /// the stored-to variable fragments.
2148e3b55780SDimitry Andric ///
2149e3b55780SDimitry Andric /// These tasks are bundled together to reduce the number of times we need
2150e3b55780SDimitry Andric /// to iterate over the function as they can be achieved together in one pass.
buildOverlapMapAndRecordDeclares(Function & Fn,FunctionVarLocsBuilder * FnVarLocs,const DenseSet<DebugAggregate> & VarsWithStackSlot,AssignmentTrackingLowering::UntaggedStoreAssignmentMap & UntaggedStoreVars,unsigned & TrackedVariablesVectorSize)2151e3b55780SDimitry Andric static AssignmentTrackingLowering::OverlapMap buildOverlapMapAndRecordDeclares(
2152e3b55780SDimitry Andric Function &Fn, FunctionVarLocsBuilder *FnVarLocs,
21537fa27ce4SDimitry Andric const DenseSet<DebugAggregate> &VarsWithStackSlot,
21547fa27ce4SDimitry Andric AssignmentTrackingLowering::UntaggedStoreAssignmentMap &UntaggedStoreVars,
21557fa27ce4SDimitry Andric unsigned &TrackedVariablesVectorSize) {
2156e3b55780SDimitry Andric DenseSet<DebugVariable> Seen;
2157e3b55780SDimitry Andric // Map of Variable: [Fragments].
2158e3b55780SDimitry Andric DenseMap<DebugAggregate, SmallVector<DebugVariable, 8>> FragmentMap;
2159e3b55780SDimitry Andric // Iterate over all instructions:
2160e3b55780SDimitry Andric // - dbg.declare -> add single location variable record
2161e3b55780SDimitry Andric // - dbg.* -> Add fragments to FragmentMap
2162e3b55780SDimitry Andric // - untagged store -> Add fragments to FragmentMap and update
2163e3b55780SDimitry Andric // UntaggedStoreVars.
2164e3b55780SDimitry Andric // We need to add fragments for untagged stores too so that we can correctly
2165e3b55780SDimitry Andric // clobber overlapped fragment locations later.
21664df029ccSDimitry Andric SmallVector<DbgDeclareInst *> InstDeclares;
2167ac9a064cSDimitry Andric SmallVector<DbgVariableRecord *> DPDeclares;
21684df029ccSDimitry Andric auto ProcessDbgRecord = [&](auto *Record, auto &DeclareList) {
21694df029ccSDimitry Andric if (auto *Declare = DynCastToDbgDeclare(Record)) {
21704df029ccSDimitry Andric DeclareList.push_back(Declare);
21714df029ccSDimitry Andric return;
21724df029ccSDimitry Andric }
21734df029ccSDimitry Andric DebugVariable DV = DebugVariable(Record);
2174e3b55780SDimitry Andric DebugAggregate DA = {DV.getVariable(), DV.getInlinedAt()};
21757fa27ce4SDimitry Andric if (!VarsWithStackSlot.contains(DA))
21764df029ccSDimitry Andric return;
2177e3b55780SDimitry Andric if (Seen.insert(DV).second)
2178e3b55780SDimitry Andric FragmentMap[DA].push_back(DV);
21794df029ccSDimitry Andric };
21804df029ccSDimitry Andric for (auto &BB : Fn) {
21814df029ccSDimitry Andric for (auto &I : BB) {
2182ac9a064cSDimitry Andric for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange()))
2183ac9a064cSDimitry Andric ProcessDbgRecord(&DVR, DPDeclares);
21844df029ccSDimitry Andric if (auto *DII = dyn_cast<DbgVariableIntrinsic>(&I)) {
21854df029ccSDimitry Andric ProcessDbgRecord(DII, InstDeclares);
2186e3b55780SDimitry Andric } else if (auto Info = getUntaggedStoreAssignmentInfo(
2187ac9a064cSDimitry Andric I, Fn.getDataLayout())) {
2188e3b55780SDimitry Andric // Find markers linked to this alloca.
21894df029ccSDimitry Andric auto HandleDbgAssignForStore = [&](auto *Assign) {
2190b1c73532SDimitry Andric std::optional<DIExpression::FragmentInfo> FragInfo;
2191b1c73532SDimitry Andric
2192b1c73532SDimitry Andric // Skip this assignment if the affected bits are outside of the
2193b1c73532SDimitry Andric // variable fragment.
2194b1c73532SDimitry Andric if (!at::calculateFragmentIntersect(
2195ac9a064cSDimitry Andric I.getDataLayout(), Info->Base,
21964df029ccSDimitry Andric Info->OffsetInBits, Info->SizeInBits, Assign, FragInfo) ||
2197b1c73532SDimitry Andric (FragInfo && FragInfo->SizeInBits == 0))
21984df029ccSDimitry Andric return;
2199b1c73532SDimitry Andric
2200b1c73532SDimitry Andric // FragInfo from calculateFragmentIntersect is nullopt if the
2201b1c73532SDimitry Andric // resultant fragment matches DAI's fragment or entire variable - in
2202b1c73532SDimitry Andric // which case copy the fragment info from DAI. If FragInfo is still
2203b1c73532SDimitry Andric // nullopt after the copy it means "no fragment info" instead, which
2204b1c73532SDimitry Andric // is how it is usually interpreted.
2205b1c73532SDimitry Andric if (!FragInfo)
22064df029ccSDimitry Andric FragInfo = Assign->getExpression()->getFragmentInfo();
2207e3b55780SDimitry Andric
22084df029ccSDimitry Andric DebugVariable DV =
22094df029ccSDimitry Andric DebugVariable(Assign->getVariable(), FragInfo,
22104df029ccSDimitry Andric Assign->getDebugLoc().getInlinedAt());
2211e3b55780SDimitry Andric DebugAggregate DA = {DV.getVariable(), DV.getInlinedAt()};
22127fa27ce4SDimitry Andric if (!VarsWithStackSlot.contains(DA))
22134df029ccSDimitry Andric return;
2214e3b55780SDimitry Andric
2215e3b55780SDimitry Andric // Cache this info for later.
2216e3b55780SDimitry Andric UntaggedStoreVars[&I].push_back(
2217e3b55780SDimitry Andric {FnVarLocs->insertVariable(DV), *Info});
2218e3b55780SDimitry Andric
2219e3b55780SDimitry Andric if (Seen.insert(DV).second)
2220e3b55780SDimitry Andric FragmentMap[DA].push_back(DV);
22214df029ccSDimitry Andric };
22224df029ccSDimitry Andric for (DbgAssignIntrinsic *DAI : at::getAssignmentMarkers(Info->Base))
22234df029ccSDimitry Andric HandleDbgAssignForStore(DAI);
2224ac9a064cSDimitry Andric for (DbgVariableRecord *DVR : at::getDVRAssignmentMarkers(Info->Base))
2225ac9a064cSDimitry Andric HandleDbgAssignForStore(DVR);
2226e3b55780SDimitry Andric }
2227e3b55780SDimitry Andric }
2228e3b55780SDimitry Andric }
2229e3b55780SDimitry Andric
22307fa27ce4SDimitry Andric // Sort the fragment map for each DebugAggregate in ascending
22317fa27ce4SDimitry Andric // order of fragment size - there should be no duplicates.
2232e3b55780SDimitry Andric for (auto &Pair : FragmentMap) {
2233e3b55780SDimitry Andric SmallVector<DebugVariable, 8> &Frags = Pair.second;
22347fa27ce4SDimitry Andric std::sort(Frags.begin(), Frags.end(),
22357fa27ce4SDimitry Andric [](const DebugVariable &Next, const DebugVariable &Elmt) {
2236e3b55780SDimitry Andric return Elmt.getFragmentOrDefault().SizeInBits >
2237e3b55780SDimitry Andric Next.getFragmentOrDefault().SizeInBits;
2238e3b55780SDimitry Andric });
22397fa27ce4SDimitry Andric // Check for duplicates.
22407fa27ce4SDimitry Andric assert(std::adjacent_find(Frags.begin(), Frags.end()) == Frags.end());
2241e3b55780SDimitry Andric }
2242e3b55780SDimitry Andric
2243e3b55780SDimitry Andric // Build the map.
2244e3b55780SDimitry Andric AssignmentTrackingLowering::OverlapMap Map;
22457fa27ce4SDimitry Andric for (auto &Pair : FragmentMap) {
2246e3b55780SDimitry Andric auto &Frags = Pair.second;
2247e3b55780SDimitry Andric for (auto It = Frags.begin(), IEnd = Frags.end(); It != IEnd; ++It) {
2248e3b55780SDimitry Andric DIExpression::FragmentInfo Frag = It->getFragmentOrDefault();
2249e3b55780SDimitry Andric // Find the frags that this is contained within.
2250e3b55780SDimitry Andric //
2251e3b55780SDimitry Andric // Because Frags is sorted by size and none have the same offset and
2252e3b55780SDimitry Andric // size, we know that this frag can only be contained by subsequent
2253e3b55780SDimitry Andric // elements.
2254e3b55780SDimitry Andric SmallVector<DebugVariable, 8>::iterator OtherIt = It;
2255e3b55780SDimitry Andric ++OtherIt;
2256e3b55780SDimitry Andric VariableID ThisVar = FnVarLocs->insertVariable(*It);
2257e3b55780SDimitry Andric for (; OtherIt != IEnd; ++OtherIt) {
2258e3b55780SDimitry Andric DIExpression::FragmentInfo OtherFrag = OtherIt->getFragmentOrDefault();
2259e3b55780SDimitry Andric VariableID OtherVar = FnVarLocs->insertVariable(*OtherIt);
2260e3b55780SDimitry Andric if (fullyContains(OtherFrag, Frag))
2261e3b55780SDimitry Andric Map[OtherVar].push_back(ThisVar);
2262e3b55780SDimitry Andric }
2263e3b55780SDimitry Andric }
2264e3b55780SDimitry Andric }
2265e3b55780SDimitry Andric
22667fa27ce4SDimitry Andric // VariableIDs are 1-based so the variable-tracking bitvector needs
22677fa27ce4SDimitry Andric // NumVariables plus 1 bits.
22687fa27ce4SDimitry Andric TrackedVariablesVectorSize = FnVarLocs->getNumVariables() + 1;
22697fa27ce4SDimitry Andric
22707fa27ce4SDimitry Andric // Finally, insert the declares afterwards, so the first IDs are all
22717fa27ce4SDimitry Andric // partially stack homed vars.
22724df029ccSDimitry Andric for (auto *DDI : InstDeclares)
22737fa27ce4SDimitry Andric FnVarLocs->addSingleLocVar(DebugVariable(DDI), DDI->getExpression(),
22747fa27ce4SDimitry Andric DDI->getDebugLoc(), DDI->getWrappedLocation());
2275ac9a064cSDimitry Andric for (auto *DVR : DPDeclares)
2276ac9a064cSDimitry Andric FnVarLocs->addSingleLocVar(DebugVariable(DVR), DVR->getExpression(),
2277ac9a064cSDimitry Andric DVR->getDebugLoc(),
2278ac9a064cSDimitry Andric RawLocationWrapper(DVR->getRawLocation()));
2279e3b55780SDimitry Andric return Map;
2280e3b55780SDimitry Andric }
2281e3b55780SDimitry Andric
run(FunctionVarLocsBuilder * FnVarLocsBuilder)2282e3b55780SDimitry Andric bool AssignmentTrackingLowering::run(FunctionVarLocsBuilder *FnVarLocsBuilder) {
2283e3b55780SDimitry Andric if (Fn.size() > MaxNumBlocks) {
2284e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << "[AT] Dropping var locs in: " << Fn.getName()
2285e3b55780SDimitry Andric << ": too many blocks (" << Fn.size() << ")\n");
2286e3b55780SDimitry Andric at::deleteAll(&Fn);
2287e3b55780SDimitry Andric return false;
2288e3b55780SDimitry Andric }
2289e3b55780SDimitry Andric
2290e3b55780SDimitry Andric FnVarLocs = FnVarLocsBuilder;
2291e3b55780SDimitry Andric
2292e3b55780SDimitry Andric // The general structure here is inspired by VarLocBasedImpl.cpp
2293e3b55780SDimitry Andric // (LiveDebugValues).
2294e3b55780SDimitry Andric
2295e3b55780SDimitry Andric // Build the variable fragment overlap map.
2296e3b55780SDimitry Andric // Note that this pass doesn't handle partial overlaps correctly (FWIW
2297e3b55780SDimitry Andric // neither does LiveDebugVariables) because that is difficult to do and
2298e3b55780SDimitry Andric // appears to be rare occurance.
22997fa27ce4SDimitry Andric VarContains = buildOverlapMapAndRecordDeclares(
23007fa27ce4SDimitry Andric Fn, FnVarLocs, *VarsWithStackSlot, UntaggedStoreVars,
23017fa27ce4SDimitry Andric TrackedVariablesVectorSize);
2302e3b55780SDimitry Andric
2303e3b55780SDimitry Andric // Prepare for traversal.
2304e3b55780SDimitry Andric ReversePostOrderTraversal<Function *> RPOT(&Fn);
2305e3b55780SDimitry Andric std::priority_queue<unsigned int, std::vector<unsigned int>,
2306e3b55780SDimitry Andric std::greater<unsigned int>>
2307e3b55780SDimitry Andric Worklist;
2308e3b55780SDimitry Andric std::priority_queue<unsigned int, std::vector<unsigned int>,
2309e3b55780SDimitry Andric std::greater<unsigned int>>
2310e3b55780SDimitry Andric Pending;
2311e3b55780SDimitry Andric DenseMap<unsigned int, BasicBlock *> OrderToBB;
2312e3b55780SDimitry Andric DenseMap<BasicBlock *, unsigned int> BBToOrder;
2313e3b55780SDimitry Andric { // Init OrderToBB and BBToOrder.
2314e3b55780SDimitry Andric unsigned int RPONumber = 0;
2315ac9a064cSDimitry Andric for (BasicBlock *BB : RPOT) {
2316ac9a064cSDimitry Andric OrderToBB[RPONumber] = BB;
2317ac9a064cSDimitry Andric BBToOrder[BB] = RPONumber;
2318e3b55780SDimitry Andric Worklist.push(RPONumber);
2319e3b55780SDimitry Andric ++RPONumber;
2320e3b55780SDimitry Andric }
2321e3b55780SDimitry Andric LiveIn.init(RPONumber);
2322e3b55780SDimitry Andric LiveOut.init(RPONumber);
2323e3b55780SDimitry Andric }
2324e3b55780SDimitry Andric
2325e3b55780SDimitry Andric // Perform the traversal.
2326e3b55780SDimitry Andric //
2327e3b55780SDimitry Andric // This is a standard "union of predecessor outs" dataflow problem. To solve
2328e3b55780SDimitry Andric // it, we perform join() and process() using the two worklist method until
2329e3b55780SDimitry Andric // the LiveIn data for each block becomes unchanging. The "proof" that this
2330e3b55780SDimitry Andric // terminates can be put together by looking at the comments around LocKind,
2331e3b55780SDimitry Andric // Assignment, and the various join methods, which show that all the elements
2332e3b55780SDimitry Andric // involved are made up of join-semilattices; LiveIn(n) can only
2333e3b55780SDimitry Andric // monotonically increase in value throughout the dataflow.
2334e3b55780SDimitry Andric //
2335e3b55780SDimitry Andric SmallPtrSet<BasicBlock *, 16> Visited;
2336e3b55780SDimitry Andric while (!Worklist.empty()) {
2337e3b55780SDimitry Andric // We track what is on the pending worklist to avoid inserting the same
2338e3b55780SDimitry Andric // thing twice.
2339e3b55780SDimitry Andric SmallPtrSet<BasicBlock *, 16> OnPending;
2340e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << "Processing Worklist\n");
2341e3b55780SDimitry Andric while (!Worklist.empty()) {
2342e3b55780SDimitry Andric BasicBlock *BB = OrderToBB[Worklist.top()];
2343e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << "\nPop BB " << BB->getName() << "\n");
2344e3b55780SDimitry Andric Worklist.pop();
2345e3b55780SDimitry Andric bool InChanged = join(*BB, Visited);
2346e3b55780SDimitry Andric // Always consider LiveIn changed on the first visit.
2347e3b55780SDimitry Andric InChanged |= Visited.insert(BB).second;
2348e3b55780SDimitry Andric if (InChanged) {
2349e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << BB->getName() << " has new InLocs, process it\n");
2350e3b55780SDimitry Andric // Mutate a copy of LiveIn while processing BB. After calling process
2351e3b55780SDimitry Andric // LiveSet is the LiveOut set for BB.
2352e3b55780SDimitry Andric BlockInfo LiveSet = LiveIn[BB];
2353e3b55780SDimitry Andric
2354e3b55780SDimitry Andric // Process the instructions in the block.
2355e3b55780SDimitry Andric process(*BB, &LiveSet);
2356e3b55780SDimitry Andric
2357e3b55780SDimitry Andric // Relatively expensive check: has anything changed in LiveOut for BB?
2358e3b55780SDimitry Andric if (LiveOut[BB] != LiveSet) {
2359e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << BB->getName()
2360e3b55780SDimitry Andric << " has new OutLocs, add succs to worklist: [ ");
2361e3b55780SDimitry Andric LiveOut[BB] = std::move(LiveSet);
2362ac9a064cSDimitry Andric for (BasicBlock *Succ : successors(BB)) {
2363ac9a064cSDimitry Andric if (OnPending.insert(Succ).second) {
2364ac9a064cSDimitry Andric LLVM_DEBUG(dbgs() << Succ->getName() << " ");
2365ac9a064cSDimitry Andric Pending.push(BBToOrder[Succ]);
2366e3b55780SDimitry Andric }
2367e3b55780SDimitry Andric }
2368e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << "]\n");
2369e3b55780SDimitry Andric }
2370e3b55780SDimitry Andric }
2371e3b55780SDimitry Andric }
2372e3b55780SDimitry Andric Worklist.swap(Pending);
2373e3b55780SDimitry Andric // At this point, pending must be empty, since it was just the empty
2374e3b55780SDimitry Andric // worklist
2375e3b55780SDimitry Andric assert(Pending.empty() && "Pending should be empty");
2376e3b55780SDimitry Andric }
2377e3b55780SDimitry Andric
2378e3b55780SDimitry Andric // That's the hard part over. Now we just have some admin to do.
2379e3b55780SDimitry Andric
2380e3b55780SDimitry Andric // Record whether we inserted any intrinsics.
2381e3b55780SDimitry Andric bool InsertedAnyIntrinsics = false;
2382e3b55780SDimitry Andric
2383e3b55780SDimitry Andric // Identify and add defs for single location variables.
2384e3b55780SDimitry Andric //
2385e3b55780SDimitry Andric // Go through all of the defs that we plan to add. If the aggregate variable
2386e3b55780SDimitry Andric // it's a part of is not in the NotAlwaysStackHomed set we can emit a single
2387e3b55780SDimitry Andric // location def and omit the rest. Add an entry to AlwaysStackHomed so that
2388e3b55780SDimitry Andric // we can identify those uneeded defs later.
2389e3b55780SDimitry Andric DenseSet<DebugAggregate> AlwaysStackHomed;
2390e3b55780SDimitry Andric for (const auto &Pair : InsertBeforeMap) {
23914df029ccSDimitry Andric auto &Vec = Pair.second;
2392e3b55780SDimitry Andric for (VarLocInfo VarLoc : Vec) {
2393e3b55780SDimitry Andric DebugVariable Var = FnVarLocs->getVariable(VarLoc.VariableID);
2394e3b55780SDimitry Andric DebugAggregate Aggr{Var.getVariable(), Var.getInlinedAt()};
2395e3b55780SDimitry Andric
2396e3b55780SDimitry Andric // Skip this Var if it's not always stack homed.
2397e3b55780SDimitry Andric if (NotAlwaysStackHomed.contains(Aggr))
2398e3b55780SDimitry Andric continue;
2399e3b55780SDimitry Andric
2400e3b55780SDimitry Andric // Skip complex cases such as when different fragments of a variable have
2401e3b55780SDimitry Andric // been split into different allocas. Skipping in this case means falling
2402e3b55780SDimitry Andric // back to using a list of defs (which could reduce coverage, but is no
2403e3b55780SDimitry Andric // less correct).
2404e3b55780SDimitry Andric bool Simple =
2405e3b55780SDimitry Andric VarLoc.Expr->getNumElements() == 1 && VarLoc.Expr->startsWithDeref();
2406e3b55780SDimitry Andric if (!Simple) {
2407e3b55780SDimitry Andric NotAlwaysStackHomed.insert(Aggr);
2408e3b55780SDimitry Andric continue;
2409e3b55780SDimitry Andric }
2410e3b55780SDimitry Andric
2411e3b55780SDimitry Andric // All source assignments to this variable remain and all stores to any
2412e3b55780SDimitry Andric // part of the variable store to the same address (with varying
2413e3b55780SDimitry Andric // offsets). We can just emit a single location for the whole variable.
2414e3b55780SDimitry Andric //
2415e3b55780SDimitry Andric // Unless we've already done so, create the single location def now.
2416e3b55780SDimitry Andric if (AlwaysStackHomed.insert(Aggr).second) {
24177fa27ce4SDimitry Andric assert(!VarLoc.Values.hasArgList());
2418e3b55780SDimitry Andric // TODO: When more complex cases are handled VarLoc.Expr should be
2419e3b55780SDimitry Andric // built appropriately rather than always using an empty DIExpression.
2420e3b55780SDimitry Andric // The assert below is a reminder.
2421e3b55780SDimitry Andric assert(Simple);
2422e3b55780SDimitry Andric VarLoc.Expr = DIExpression::get(Fn.getContext(), std::nullopt);
2423e3b55780SDimitry Andric DebugVariable Var = FnVarLocs->getVariable(VarLoc.VariableID);
24247fa27ce4SDimitry Andric FnVarLocs->addSingleLocVar(Var, VarLoc.Expr, VarLoc.DL, VarLoc.Values);
2425e3b55780SDimitry Andric InsertedAnyIntrinsics = true;
2426e3b55780SDimitry Andric }
2427e3b55780SDimitry Andric }
2428e3b55780SDimitry Andric }
2429e3b55780SDimitry Andric
2430e3b55780SDimitry Andric // Insert the other DEFs.
2431e3b55780SDimitry Andric for (const auto &[InsertBefore, Vec] : InsertBeforeMap) {
2432e3b55780SDimitry Andric SmallVector<VarLocInfo> NewDefs;
2433e3b55780SDimitry Andric for (const VarLocInfo &VarLoc : Vec) {
2434e3b55780SDimitry Andric DebugVariable Var = FnVarLocs->getVariable(VarLoc.VariableID);
2435e3b55780SDimitry Andric DebugAggregate Aggr{Var.getVariable(), Var.getInlinedAt()};
2436e3b55780SDimitry Andric // If this variable is always stack homed then we have already inserted a
2437e3b55780SDimitry Andric // dbg.declare and deleted this dbg.value.
2438e3b55780SDimitry Andric if (AlwaysStackHomed.contains(Aggr))
2439e3b55780SDimitry Andric continue;
2440e3b55780SDimitry Andric NewDefs.push_back(VarLoc);
2441e3b55780SDimitry Andric InsertedAnyIntrinsics = true;
2442e3b55780SDimitry Andric }
2443e3b55780SDimitry Andric
2444e3b55780SDimitry Andric FnVarLocs->setWedge(InsertBefore, std::move(NewDefs));
2445e3b55780SDimitry Andric }
2446e3b55780SDimitry Andric
2447e3b55780SDimitry Andric InsertedAnyIntrinsics |= emitPromotedVarLocs(FnVarLocs);
2448e3b55780SDimitry Andric
2449e3b55780SDimitry Andric return InsertedAnyIntrinsics;
2450e3b55780SDimitry Andric }
2451e3b55780SDimitry Andric
emitPromotedVarLocs(FunctionVarLocsBuilder * FnVarLocs)2452e3b55780SDimitry Andric bool AssignmentTrackingLowering::emitPromotedVarLocs(
2453e3b55780SDimitry Andric FunctionVarLocsBuilder *FnVarLocs) {
2454e3b55780SDimitry Andric bool InsertedAnyIntrinsics = false;
2455e3b55780SDimitry Andric // Go through every block, translating debug intrinsics for fully promoted
2456e3b55780SDimitry Andric // variables into FnVarLocs location defs. No analysis required for these.
24574df029ccSDimitry Andric auto TranslateDbgRecord = [&](auto *Record) {
24584df029ccSDimitry Andric // Skip variables that haven't been promoted - we've dealt with those
24594df029ccSDimitry Andric // already.
24604df029ccSDimitry Andric if (VarsWithStackSlot->contains(getAggregate(Record)))
24614df029ccSDimitry Andric return;
24624df029ccSDimitry Andric auto InsertBefore = getNextNode(Record);
24634df029ccSDimitry Andric assert(InsertBefore && "Unexpected: debug intrinsics after a terminator");
24644df029ccSDimitry Andric FnVarLocs->addVarLoc(InsertBefore, DebugVariable(Record),
24654df029ccSDimitry Andric Record->getExpression(), Record->getDebugLoc(),
24664df029ccSDimitry Andric RawLocationWrapper(Record->getRawLocation()));
24674df029ccSDimitry Andric InsertedAnyIntrinsics = true;
24684df029ccSDimitry Andric };
2469e3b55780SDimitry Andric for (auto &BB : Fn) {
2470e3b55780SDimitry Andric for (auto &I : BB) {
2471e3b55780SDimitry Andric // Skip instructions other than dbg.values and dbg.assigns.
2472ac9a064cSDimitry Andric for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange()))
2473ac9a064cSDimitry Andric if (DVR.isDbgValue() || DVR.isDbgAssign())
2474ac9a064cSDimitry Andric TranslateDbgRecord(&DVR);
2475e3b55780SDimitry Andric auto *DVI = dyn_cast<DbgValueInst>(&I);
24764df029ccSDimitry Andric if (DVI)
24774df029ccSDimitry Andric TranslateDbgRecord(DVI);
2478e3b55780SDimitry Andric }
2479e3b55780SDimitry Andric }
2480e3b55780SDimitry Andric return InsertedAnyIntrinsics;
2481e3b55780SDimitry Andric }
2482e3b55780SDimitry Andric
2483e3b55780SDimitry Andric /// Remove redundant definitions within sequences of consecutive location defs.
2484e3b55780SDimitry Andric /// This is done using a backward scan to keep the last def describing a
2485e3b55780SDimitry Andric /// specific variable/fragment.
2486e3b55780SDimitry Andric ///
2487e3b55780SDimitry Andric /// This implements removeRedundantDbgInstrsUsingBackwardScan from
2488e3b55780SDimitry Andric /// lib/Transforms/Utils/BasicBlockUtils.cpp for locations described with
2489e3b55780SDimitry Andric /// FunctionVarLocsBuilder instead of with intrinsics.
2490e3b55780SDimitry Andric static bool
removeRedundantDbgLocsUsingBackwardScan(const BasicBlock * BB,FunctionVarLocsBuilder & FnVarLocs)2491e3b55780SDimitry Andric removeRedundantDbgLocsUsingBackwardScan(const BasicBlock *BB,
2492e3b55780SDimitry Andric FunctionVarLocsBuilder &FnVarLocs) {
2493e3b55780SDimitry Andric bool Changed = false;
2494312c0ed1SDimitry Andric SmallDenseMap<DebugAggregate, BitVector> VariableDefinedBytes;
2495e3b55780SDimitry Andric // Scan over the entire block, not just over the instructions mapped by
2496ac9a064cSDimitry Andric // FnVarLocs, because wedges in FnVarLocs may only be separated by debug
2497e3b55780SDimitry Andric // instructions.
2498e3b55780SDimitry Andric for (const Instruction &I : reverse(*BB)) {
2499e3b55780SDimitry Andric if (!isa<DbgVariableIntrinsic>(I)) {
2500e3b55780SDimitry Andric // Sequence of consecutive defs ended. Clear map for the next one.
2501312c0ed1SDimitry Andric VariableDefinedBytes.clear();
2502e3b55780SDimitry Andric }
2503e3b55780SDimitry Andric
25044df029ccSDimitry Andric auto HandleLocsForWedge = [&](auto *WedgePosition) {
2505e3b55780SDimitry Andric // Get the location defs that start just before this instruction.
25064df029ccSDimitry Andric const auto *Locs = FnVarLocs.getWedge(WedgePosition);
2507e3b55780SDimitry Andric if (!Locs)
25084df029ccSDimitry Andric return;
2509e3b55780SDimitry Andric
2510e3b55780SDimitry Andric NumWedgesScanned++;
2511e3b55780SDimitry Andric bool ChangedThisWedge = false;
2512e3b55780SDimitry Andric // The new pruned set of defs, reversed because we're scanning backwards.
2513e3b55780SDimitry Andric SmallVector<VarLocInfo> NewDefsReversed;
2514e3b55780SDimitry Andric
2515e3b55780SDimitry Andric // Iterate over the existing defs in reverse.
2516e3b55780SDimitry Andric for (auto RIt = Locs->rbegin(), REnd = Locs->rend(); RIt != REnd; ++RIt) {
2517e3b55780SDimitry Andric NumDefsScanned++;
25187fa27ce4SDimitry Andric DebugAggregate Aggr =
25197fa27ce4SDimitry Andric getAggregate(FnVarLocs.getVariable(RIt->VariableID));
25207fa27ce4SDimitry Andric uint64_t SizeInBits = Aggr.first->getSizeInBits().value_or(0);
2521312c0ed1SDimitry Andric uint64_t SizeInBytes = divideCeil(SizeInBits, 8);
2522e3b55780SDimitry Andric
2523312c0ed1SDimitry Andric // Cutoff for large variables to prevent expensive bitvector operations.
2524312c0ed1SDimitry Andric const uint64_t MaxSizeBytes = 2048;
2525312c0ed1SDimitry Andric
2526312c0ed1SDimitry Andric if (SizeInBytes == 0 || SizeInBytes > MaxSizeBytes) {
25277fa27ce4SDimitry Andric // If the size is unknown (0) then keep this location def to be safe.
2528312c0ed1SDimitry Andric // Do the same for defs of large variables, which would be expensive
2529312c0ed1SDimitry Andric // to represent with a BitVector.
2530e3b55780SDimitry Andric NewDefsReversed.push_back(*RIt);
25317fa27ce4SDimitry Andric continue;
25327fa27ce4SDimitry Andric }
25337fa27ce4SDimitry Andric
25347fa27ce4SDimitry Andric // Only keep this location definition if it is not fully eclipsed by
25357fa27ce4SDimitry Andric // other definitions in this wedge that come after it
25367fa27ce4SDimitry Andric
2537312c0ed1SDimitry Andric // Inert the bytes the location definition defines.
25387fa27ce4SDimitry Andric auto InsertResult =
2539312c0ed1SDimitry Andric VariableDefinedBytes.try_emplace(Aggr, BitVector(SizeInBytes));
25407fa27ce4SDimitry Andric bool FirstDefinition = InsertResult.second;
2541312c0ed1SDimitry Andric BitVector &DefinedBytes = InsertResult.first->second;
25427fa27ce4SDimitry Andric
25437fa27ce4SDimitry Andric DIExpression::FragmentInfo Fragment =
25447fa27ce4SDimitry Andric RIt->Expr->getFragmentInfo().value_or(
25457fa27ce4SDimitry Andric DIExpression::FragmentInfo(SizeInBits, 0));
25467fa27ce4SDimitry Andric bool InvalidFragment = Fragment.endInBits() > SizeInBits;
2547312c0ed1SDimitry Andric uint64_t StartInBytes = Fragment.startInBits() / 8;
2548312c0ed1SDimitry Andric uint64_t EndInBytes = divideCeil(Fragment.endInBits(), 8);
25497fa27ce4SDimitry Andric
2550312c0ed1SDimitry Andric // If this defines any previously undefined bytes, keep it.
25517fa27ce4SDimitry Andric if (FirstDefinition || InvalidFragment ||
2552312c0ed1SDimitry Andric DefinedBytes.find_first_unset_in(StartInBytes, EndInBytes) != -1) {
25537fa27ce4SDimitry Andric if (!InvalidFragment)
2554312c0ed1SDimitry Andric DefinedBytes.set(StartInBytes, EndInBytes);
25557fa27ce4SDimitry Andric NewDefsReversed.push_back(*RIt);
25567fa27ce4SDimitry Andric continue;
25577fa27ce4SDimitry Andric }
25587fa27ce4SDimitry Andric
2559e3b55780SDimitry Andric // Redundant def found: throw it away. Since the wedge of defs is being
2560e3b55780SDimitry Andric // rebuilt, doing nothing is the same as deleting an entry.
2561e3b55780SDimitry Andric ChangedThisWedge = true;
2562e3b55780SDimitry Andric NumDefsRemoved++;
2563e3b55780SDimitry Andric }
2564e3b55780SDimitry Andric
2565e3b55780SDimitry Andric // Un-reverse the defs and replace the wedge with the pruned version.
2566e3b55780SDimitry Andric if (ChangedThisWedge) {
2567e3b55780SDimitry Andric std::reverse(NewDefsReversed.begin(), NewDefsReversed.end());
25684df029ccSDimitry Andric FnVarLocs.setWedge(WedgePosition, std::move(NewDefsReversed));
2569e3b55780SDimitry Andric NumWedgesChanged++;
2570e3b55780SDimitry Andric Changed = true;
2571e3b55780SDimitry Andric }
25724df029ccSDimitry Andric };
25734df029ccSDimitry Andric HandleLocsForWedge(&I);
2574ac9a064cSDimitry Andric for (DbgVariableRecord &DVR : reverse(filterDbgVars(I.getDbgRecordRange())))
2575ac9a064cSDimitry Andric HandleLocsForWedge(&DVR);
2576e3b55780SDimitry Andric }
2577e3b55780SDimitry Andric
2578e3b55780SDimitry Andric return Changed;
2579e3b55780SDimitry Andric }
2580e3b55780SDimitry Andric
2581e3b55780SDimitry Andric /// Remove redundant location defs using a forward scan. This can remove a
2582e3b55780SDimitry Andric /// location definition that is redundant due to indicating that a variable has
2583e3b55780SDimitry Andric /// the same value as is already being indicated by an earlier def.
2584e3b55780SDimitry Andric ///
2585e3b55780SDimitry Andric /// This implements removeRedundantDbgInstrsUsingForwardScan from
2586e3b55780SDimitry Andric /// lib/Transforms/Utils/BasicBlockUtils.cpp for locations described with
2587e3b55780SDimitry Andric /// FunctionVarLocsBuilder instead of with intrinsics
2588e3b55780SDimitry Andric static bool
removeRedundantDbgLocsUsingForwardScan(const BasicBlock * BB,FunctionVarLocsBuilder & FnVarLocs)2589e3b55780SDimitry Andric removeRedundantDbgLocsUsingForwardScan(const BasicBlock *BB,
2590e3b55780SDimitry Andric FunctionVarLocsBuilder &FnVarLocs) {
2591e3b55780SDimitry Andric bool Changed = false;
25927fa27ce4SDimitry Andric DenseMap<DebugVariable, std::pair<RawLocationWrapper, DIExpression *>>
25937fa27ce4SDimitry Andric VariableMap;
2594e3b55780SDimitry Andric
2595e3b55780SDimitry Andric // Scan over the entire block, not just over the instructions mapped by
2596ac9a064cSDimitry Andric // FnVarLocs, because wedges in FnVarLocs may only be separated by debug
2597e3b55780SDimitry Andric // instructions.
2598e3b55780SDimitry Andric for (const Instruction &I : *BB) {
2599e3b55780SDimitry Andric // Get the defs that come just before this instruction.
26004df029ccSDimitry Andric auto HandleLocsForWedge = [&](auto *WedgePosition) {
26014df029ccSDimitry Andric const auto *Locs = FnVarLocs.getWedge(WedgePosition);
2602e3b55780SDimitry Andric if (!Locs)
26034df029ccSDimitry Andric return;
2604e3b55780SDimitry Andric
2605e3b55780SDimitry Andric NumWedgesScanned++;
2606e3b55780SDimitry Andric bool ChangedThisWedge = false;
2607e3b55780SDimitry Andric // The new pruned set of defs.
2608e3b55780SDimitry Andric SmallVector<VarLocInfo> NewDefs;
2609e3b55780SDimitry Andric
2610e3b55780SDimitry Andric // Iterate over the existing defs.
2611e3b55780SDimitry Andric for (const VarLocInfo &Loc : *Locs) {
2612e3b55780SDimitry Andric NumDefsScanned++;
2613e3b55780SDimitry Andric DebugVariable Key(FnVarLocs.getVariable(Loc.VariableID).getVariable(),
2614e3b55780SDimitry Andric std::nullopt, Loc.DL.getInlinedAt());
2615e3b55780SDimitry Andric auto VMI = VariableMap.find(Key);
2616e3b55780SDimitry Andric
2617e3b55780SDimitry Andric // Update the map if we found a new value/expression describing the
2618e3b55780SDimitry Andric // variable, or if the variable wasn't mapped already.
26197fa27ce4SDimitry Andric if (VMI == VariableMap.end() || VMI->second.first != Loc.Values ||
2620e3b55780SDimitry Andric VMI->second.second != Loc.Expr) {
26217fa27ce4SDimitry Andric VariableMap[Key] = {Loc.Values, Loc.Expr};
2622e3b55780SDimitry Andric NewDefs.push_back(Loc);
2623e3b55780SDimitry Andric continue;
2624e3b55780SDimitry Andric }
2625e3b55780SDimitry Andric
2626e3b55780SDimitry Andric // Did not insert this Loc, which is the same as removing it.
2627e3b55780SDimitry Andric ChangedThisWedge = true;
2628e3b55780SDimitry Andric NumDefsRemoved++;
2629e3b55780SDimitry Andric }
2630e3b55780SDimitry Andric
2631e3b55780SDimitry Andric // Replace the existing wedge with the pruned version.
2632e3b55780SDimitry Andric if (ChangedThisWedge) {
26334df029ccSDimitry Andric FnVarLocs.setWedge(WedgePosition, std::move(NewDefs));
2634e3b55780SDimitry Andric NumWedgesChanged++;
2635e3b55780SDimitry Andric Changed = true;
2636e3b55780SDimitry Andric }
26374df029ccSDimitry Andric };
26384df029ccSDimitry Andric
2639ac9a064cSDimitry Andric for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange()))
2640ac9a064cSDimitry Andric HandleLocsForWedge(&DVR);
26414df029ccSDimitry Andric HandleLocsForWedge(&I);
2642e3b55780SDimitry Andric }
2643e3b55780SDimitry Andric
2644e3b55780SDimitry Andric return Changed;
2645e3b55780SDimitry Andric }
2646e3b55780SDimitry Andric
2647e3b55780SDimitry Andric static bool
removeUndefDbgLocsFromEntryBlock(const BasicBlock * BB,FunctionVarLocsBuilder & FnVarLocs)2648e3b55780SDimitry Andric removeUndefDbgLocsFromEntryBlock(const BasicBlock *BB,
2649e3b55780SDimitry Andric FunctionVarLocsBuilder &FnVarLocs) {
2650e3b55780SDimitry Andric assert(BB->isEntryBlock());
2651e3b55780SDimitry Andric // Do extra work to ensure that we remove semantically unimportant undefs.
2652e3b55780SDimitry Andric //
2653e3b55780SDimitry Andric // This is to work around the fact that SelectionDAG will hoist dbg.values
2654e3b55780SDimitry Andric // using argument values to the top of the entry block. That can move arg
2655e3b55780SDimitry Andric // dbg.values before undef and constant dbg.values which they previously
2656e3b55780SDimitry Andric // followed. The easiest thing to do is to just try to feed SelectionDAG
2657e3b55780SDimitry Andric // input it's happy with.
2658e3b55780SDimitry Andric //
2659e3b55780SDimitry Andric // Map of {Variable x: Fragments y} where the fragments y of variable x have
2660e3b55780SDimitry Andric // have at least one non-undef location defined already. Don't use directly,
2661e3b55780SDimitry Andric // instead call DefineBits and HasDefinedBits.
2662e3b55780SDimitry Andric SmallDenseMap<DebugAggregate, SmallDenseSet<DIExpression::FragmentInfo>>
2663e3b55780SDimitry Andric VarsWithDef;
2664e3b55780SDimitry Andric // Specify that V (a fragment of A) has a non-undef location.
2665e3b55780SDimitry Andric auto DefineBits = [&VarsWithDef](DebugAggregate A, DebugVariable V) {
2666e3b55780SDimitry Andric VarsWithDef[A].insert(V.getFragmentOrDefault());
2667e3b55780SDimitry Andric };
2668e3b55780SDimitry Andric // Return true if a non-undef location has been defined for V (a fragment of
2669e3b55780SDimitry Andric // A). Doesn't imply that the location is currently non-undef, just that a
2670e3b55780SDimitry Andric // non-undef location has been seen previously.
2671e3b55780SDimitry Andric auto HasDefinedBits = [&VarsWithDef](DebugAggregate A, DebugVariable V) {
2672e3b55780SDimitry Andric auto FragsIt = VarsWithDef.find(A);
2673e3b55780SDimitry Andric if (FragsIt == VarsWithDef.end())
2674e3b55780SDimitry Andric return false;
2675e3b55780SDimitry Andric return llvm::any_of(FragsIt->second, [V](auto Frag) {
2676e3b55780SDimitry Andric return DIExpression::fragmentsOverlap(Frag, V.getFragmentOrDefault());
2677e3b55780SDimitry Andric });
2678e3b55780SDimitry Andric };
2679e3b55780SDimitry Andric
2680e3b55780SDimitry Andric bool Changed = false;
2681e3b55780SDimitry Andric DenseMap<DebugVariable, std::pair<Value *, DIExpression *>> VariableMap;
2682e3b55780SDimitry Andric
2683e3b55780SDimitry Andric // Scan over the entire block, not just over the instructions mapped by
2684ac9a064cSDimitry Andric // FnVarLocs, because wedges in FnVarLocs may only be separated by debug
2685e3b55780SDimitry Andric // instructions.
2686e3b55780SDimitry Andric for (const Instruction &I : *BB) {
2687e3b55780SDimitry Andric // Get the defs that come just before this instruction.
26884df029ccSDimitry Andric auto HandleLocsForWedge = [&](auto *WedgePosition) {
26894df029ccSDimitry Andric const auto *Locs = FnVarLocs.getWedge(WedgePosition);
2690e3b55780SDimitry Andric if (!Locs)
26914df029ccSDimitry Andric return;
2692e3b55780SDimitry Andric
2693e3b55780SDimitry Andric NumWedgesScanned++;
2694e3b55780SDimitry Andric bool ChangedThisWedge = false;
2695e3b55780SDimitry Andric // The new pruned set of defs.
2696e3b55780SDimitry Andric SmallVector<VarLocInfo> NewDefs;
2697e3b55780SDimitry Andric
2698e3b55780SDimitry Andric // Iterate over the existing defs.
2699e3b55780SDimitry Andric for (const VarLocInfo &Loc : *Locs) {
2700e3b55780SDimitry Andric NumDefsScanned++;
2701e3b55780SDimitry Andric DebugAggregate Aggr{FnVarLocs.getVariable(Loc.VariableID).getVariable(),
2702e3b55780SDimitry Andric Loc.DL.getInlinedAt()};
2703e3b55780SDimitry Andric DebugVariable Var = FnVarLocs.getVariable(Loc.VariableID);
2704e3b55780SDimitry Andric
2705e3b55780SDimitry Andric // Remove undef entries that are encountered before any non-undef
2706e3b55780SDimitry Andric // intrinsics from the entry block.
27077fa27ce4SDimitry Andric if (Loc.Values.isKillLocation(Loc.Expr) && !HasDefinedBits(Aggr, Var)) {
2708e3b55780SDimitry Andric // Did not insert this Loc, which is the same as removing it.
2709e3b55780SDimitry Andric NumDefsRemoved++;
2710e3b55780SDimitry Andric ChangedThisWedge = true;
2711e3b55780SDimitry Andric continue;
2712e3b55780SDimitry Andric }
2713e3b55780SDimitry Andric
2714e3b55780SDimitry Andric DefineBits(Aggr, Var);
2715e3b55780SDimitry Andric NewDefs.push_back(Loc);
2716e3b55780SDimitry Andric }
2717e3b55780SDimitry Andric
2718e3b55780SDimitry Andric // Replace the existing wedge with the pruned version.
2719e3b55780SDimitry Andric if (ChangedThisWedge) {
27204df029ccSDimitry Andric FnVarLocs.setWedge(WedgePosition, std::move(NewDefs));
2721e3b55780SDimitry Andric NumWedgesChanged++;
2722e3b55780SDimitry Andric Changed = true;
2723e3b55780SDimitry Andric }
27244df029ccSDimitry Andric };
2725ac9a064cSDimitry Andric for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange()))
2726ac9a064cSDimitry Andric HandleLocsForWedge(&DVR);
27274df029ccSDimitry Andric HandleLocsForWedge(&I);
2728e3b55780SDimitry Andric }
2729e3b55780SDimitry Andric
2730e3b55780SDimitry Andric return Changed;
2731e3b55780SDimitry Andric }
2732e3b55780SDimitry Andric
removeRedundantDbgLocs(const BasicBlock * BB,FunctionVarLocsBuilder & FnVarLocs)2733e3b55780SDimitry Andric static bool removeRedundantDbgLocs(const BasicBlock *BB,
2734e3b55780SDimitry Andric FunctionVarLocsBuilder &FnVarLocs) {
2735e3b55780SDimitry Andric bool MadeChanges = false;
2736e3b55780SDimitry Andric MadeChanges |= removeRedundantDbgLocsUsingBackwardScan(BB, FnVarLocs);
2737e3b55780SDimitry Andric if (BB->isEntryBlock())
2738e3b55780SDimitry Andric MadeChanges |= removeUndefDbgLocsFromEntryBlock(BB, FnVarLocs);
2739e3b55780SDimitry Andric MadeChanges |= removeRedundantDbgLocsUsingForwardScan(BB, FnVarLocs);
2740e3b55780SDimitry Andric
2741e3b55780SDimitry Andric if (MadeChanges)
2742e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << "Removed redundant dbg locs from: " << BB->getName()
2743e3b55780SDimitry Andric << "\n");
2744e3b55780SDimitry Andric return MadeChanges;
2745e3b55780SDimitry Andric }
2746e3b55780SDimitry Andric
findVarsWithStackSlot(Function & Fn)2747e3b55780SDimitry Andric static DenseSet<DebugAggregate> findVarsWithStackSlot(Function &Fn) {
2748e3b55780SDimitry Andric DenseSet<DebugAggregate> Result;
2749e3b55780SDimitry Andric for (auto &BB : Fn) {
2750e3b55780SDimitry Andric for (auto &I : BB) {
2751e3b55780SDimitry Andric // Any variable linked to an instruction is considered
2752e3b55780SDimitry Andric // interesting. Ideally we only need to check Allocas, however, a
2753e3b55780SDimitry Andric // DIAssignID might get dropped from an alloca but not stores. In that
2754e3b55780SDimitry Andric // case, we need to consider the variable interesting for NFC behaviour
2755e3b55780SDimitry Andric // with this change. TODO: Consider only looking at allocas.
2756e3b55780SDimitry Andric for (DbgAssignIntrinsic *DAI : at::getAssignmentMarkers(&I)) {
2757e3b55780SDimitry Andric Result.insert({DAI->getVariable(), DAI->getDebugLoc().getInlinedAt()});
2758e3b55780SDimitry Andric }
2759ac9a064cSDimitry Andric for (DbgVariableRecord *DVR : at::getDVRAssignmentMarkers(&I)) {
2760ac9a064cSDimitry Andric Result.insert({DVR->getVariable(), DVR->getDebugLoc().getInlinedAt()});
27614df029ccSDimitry Andric }
2762e3b55780SDimitry Andric }
2763e3b55780SDimitry Andric }
2764e3b55780SDimitry Andric return Result;
2765e3b55780SDimitry Andric }
2766e3b55780SDimitry Andric
analyzeFunction(Function & Fn,const DataLayout & Layout,FunctionVarLocsBuilder * FnVarLocs)2767e3b55780SDimitry Andric static void analyzeFunction(Function &Fn, const DataLayout &Layout,
2768e3b55780SDimitry Andric FunctionVarLocsBuilder *FnVarLocs) {
2769e3b55780SDimitry Andric // The analysis will generate location definitions for all variables, but we
2770e3b55780SDimitry Andric // only need to perform a dataflow on the set of variables which have a stack
2771e3b55780SDimitry Andric // slot. Find those now.
2772e3b55780SDimitry Andric DenseSet<DebugAggregate> VarsWithStackSlot = findVarsWithStackSlot(Fn);
2773e3b55780SDimitry Andric
2774e3b55780SDimitry Andric bool Changed = false;
2775e3b55780SDimitry Andric
2776e3b55780SDimitry Andric // Use a scope block to clean up AssignmentTrackingLowering before running
2777e3b55780SDimitry Andric // MemLocFragmentFill to reduce peak memory consumption.
2778e3b55780SDimitry Andric {
2779e3b55780SDimitry Andric AssignmentTrackingLowering Pass(Fn, Layout, &VarsWithStackSlot);
2780e3b55780SDimitry Andric Changed = Pass.run(FnVarLocs);
2781e3b55780SDimitry Andric }
2782e3b55780SDimitry Andric
2783e3b55780SDimitry Andric if (Changed) {
27847fa27ce4SDimitry Andric MemLocFragmentFill Pass(Fn, &VarsWithStackSlot,
27857fa27ce4SDimitry Andric shouldCoalesceFragments(Fn));
2786e3b55780SDimitry Andric Pass.run(FnVarLocs);
2787e3b55780SDimitry Andric
2788e3b55780SDimitry Andric // Remove redundant entries. As well as reducing memory consumption and
2789e3b55780SDimitry Andric // avoiding waiting cycles later by burning some now, this has another
2790e3b55780SDimitry Andric // important job. That is to work around some SelectionDAG quirks. See
2791e3b55780SDimitry Andric // removeRedundantDbgLocsUsingForwardScan comments for more info on that.
2792e3b55780SDimitry Andric for (auto &BB : Fn)
2793e3b55780SDimitry Andric removeRedundantDbgLocs(&BB, *FnVarLocs);
2794e3b55780SDimitry Andric }
2795e3b55780SDimitry Andric }
2796e3b55780SDimitry Andric
2797950076cdSDimitry Andric FunctionVarLocs
run(Function & F,FunctionAnalysisManager & FAM)2798950076cdSDimitry Andric DebugAssignmentTrackingAnalysis::run(Function &F,
2799950076cdSDimitry Andric FunctionAnalysisManager &FAM) {
2800950076cdSDimitry Andric if (!isAssignmentTrackingEnabled(*F.getParent()))
2801950076cdSDimitry Andric return FunctionVarLocs();
2802950076cdSDimitry Andric
2803ac9a064cSDimitry Andric auto &DL = F.getDataLayout();
2804950076cdSDimitry Andric
2805950076cdSDimitry Andric FunctionVarLocsBuilder Builder;
2806950076cdSDimitry Andric analyzeFunction(F, DL, &Builder);
2807950076cdSDimitry Andric
2808950076cdSDimitry Andric // Save these results.
2809950076cdSDimitry Andric FunctionVarLocs Results;
2810950076cdSDimitry Andric Results.init(Builder);
2811950076cdSDimitry Andric return Results;
2812950076cdSDimitry Andric }
2813950076cdSDimitry Andric
2814950076cdSDimitry Andric AnalysisKey DebugAssignmentTrackingAnalysis::Key;
2815950076cdSDimitry Andric
2816950076cdSDimitry Andric PreservedAnalyses
run(Function & F,FunctionAnalysisManager & FAM)2817950076cdSDimitry Andric DebugAssignmentTrackingPrinterPass::run(Function &F,
2818950076cdSDimitry Andric FunctionAnalysisManager &FAM) {
2819950076cdSDimitry Andric FAM.getResult<DebugAssignmentTrackingAnalysis>(F).print(OS, F);
2820950076cdSDimitry Andric return PreservedAnalyses::all();
2821950076cdSDimitry Andric }
2822950076cdSDimitry Andric
runOnFunction(Function & F)2823e3b55780SDimitry Andric bool AssignmentTrackingAnalysis::runOnFunction(Function &F) {
2824e3b55780SDimitry Andric if (!isAssignmentTrackingEnabled(*F.getParent()))
2825e3b55780SDimitry Andric return false;
2826e3b55780SDimitry Andric
2827e3b55780SDimitry Andric LLVM_DEBUG(dbgs() << "AssignmentTrackingAnalysis run on " << F.getName()
2828e3b55780SDimitry Andric << "\n");
2829e3b55780SDimitry Andric auto DL = std::make_unique<DataLayout>(F.getParent());
2830e3b55780SDimitry Andric
2831e3b55780SDimitry Andric // Clear previous results.
2832e3b55780SDimitry Andric Results->clear();
2833e3b55780SDimitry Andric
2834e3b55780SDimitry Andric FunctionVarLocsBuilder Builder;
2835e3b55780SDimitry Andric analyzeFunction(F, *DL.get(), &Builder);
2836e3b55780SDimitry Andric
2837e3b55780SDimitry Andric // Save these results.
2838e3b55780SDimitry Andric Results->init(Builder);
2839e3b55780SDimitry Andric
2840e3b55780SDimitry Andric if (PrintResults && isFunctionInPrintList(F.getName()))
2841e3b55780SDimitry Andric Results->print(errs(), F);
2842e3b55780SDimitry Andric
2843e3b55780SDimitry Andric // Return false because this pass does not modify the function.
2844e3b55780SDimitry Andric return false;
2845e3b55780SDimitry Andric }
2846e3b55780SDimitry Andric
AssignmentTrackingAnalysis()2847e3b55780SDimitry Andric AssignmentTrackingAnalysis::AssignmentTrackingAnalysis()
2848e3b55780SDimitry Andric : FunctionPass(ID), Results(std::make_unique<FunctionVarLocs>()) {}
2849e3b55780SDimitry Andric
2850e3b55780SDimitry Andric char AssignmentTrackingAnalysis::ID = 0;
2851e3b55780SDimitry Andric
2852e3b55780SDimitry Andric INITIALIZE_PASS(AssignmentTrackingAnalysis, DEBUG_TYPE,
2853e3b55780SDimitry Andric "Assignment Tracking Analysis", false, true)
2854