1 | //===- ReduceDIMetadata.cpp - Specialized Delta pass for DebugInfo --------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file implements two functions used by the Generic Delta Debugging |
10 | // Algorithm, which are used to reduce DebugInfo metadata nodes. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "ReduceDIMetadata.h" |
15 | #include "llvm/ADT/SetVector.h" |
16 | #include "llvm/ADT/SmallVector.h" |
17 | #include "llvm/IR/DebugInfoMetadata.h" |
18 | #include "llvm/IR/InstIterator.h" |
19 | #include <tuple> |
20 | #include <vector> |
21 | |
22 | using namespace llvm; |
23 | |
24 | using MDNodeList = SmallVector<MDNode *>; |
25 | |
26 | void identifyUninterestingMDNodes(Oracle &O, MDNodeList &MDs) { |
27 | SetVector<std::tuple<MDNode *, size_t, MDNode *>> Tuples; |
28 | std::vector<MDNode *> ToLook; |
29 | SetVector<MDNode *> Visited; |
30 | |
31 | // Start by looking at the attachments we collected |
32 | for (const auto &NMD : MDs) |
33 | if (NMD) |
34 | ToLook.push_back(x: NMD); |
35 | |
36 | while (!ToLook.empty()) { |
37 | MDNode *MD = ToLook.back(); |
38 | ToLook.pop_back(); |
39 | |
40 | if (!Visited.insert(X: MD)) |
41 | continue; |
42 | |
43 | // Determine if the current MDNode is DebugInfo |
44 | if (DINode *DIM = dyn_cast_or_null<DINode>(Val: MD)) { |
45 | // Scan operands and record attached tuples |
46 | for (size_t I = 0; I < DIM->getNumOperands(); ++I) |
47 | if (MDTuple *MDT = dyn_cast_or_null<MDTuple>(Val: DIM->getOperand(I))) |
48 | if (!Visited.count(key: MDT) && MDT->getNumOperands()) |
49 | Tuples.insert(X: {DIM, I, MDT}); |
50 | } |
51 | |
52 | // Add all of the operands of the current node to the loop's todo list. |
53 | for (Metadata *Op : MD->operands()) |
54 | if (MDNode *OMD = dyn_cast_or_null<MDNode>(Val: Op)) |
55 | ToLook.push_back(x: OMD); |
56 | } |
57 | |
58 | for (auto &T : Tuples) { |
59 | auto [DbgNode, OpIdx, Tup] = T; |
60 | // Remove the operands of the tuple that are not in the desired chunks. |
61 | SmallVector<Metadata *, 16> TN; |
62 | for (size_t I = 0; I < Tup->getNumOperands(); ++I) { |
63 | // Ignore any operands that are not DebugInfo metadata nodes. |
64 | if (Metadata *Op = Tup->getOperand(I).get()) { |
65 | if (isa<DINode>(Val: Op) || isa<DIGlobalVariableExpression>(Val: Op)) |
66 | // Don't add uninteresting operands to the tuple. |
67 | if (!O.shouldKeep()) |
68 | continue; |
69 | } |
70 | TN.push_back(Elt: Tup->getOperand(I)); |
71 | } |
72 | if (TN.size() != Tup->getNumOperands()) |
73 | DbgNode->replaceOperandWith(I: OpIdx, New: DbgNode->get(Context&: DbgNode->getContext(), MDs: TN)); |
74 | } |
75 | } |
76 | |
77 | void llvm::reduceDIMetadataDeltaPass(Oracle &O, ReducerWorkItem &WorkItem) { |
78 | Module &Program = WorkItem.getModule(); |
79 | |
80 | MDNodeList MDs; |
81 | // Collect all !dbg metadata attachments. |
82 | for (const auto &DC : Program.debug_compile_units()) |
83 | if (DC) |
84 | MDs.push_back(Elt: DC); |
85 | for (GlobalVariable &GV : Program.globals()) |
86 | GV.getMetadata(KindID: llvm::LLVMContext::MD_dbg, MDs); |
87 | for (Function &F : Program.functions()) { |
88 | F.getMetadata(KindID: llvm::LLVMContext::MD_dbg, MDs); |
89 | for (Instruction &I : instructions(F)) |
90 | if (auto *DI = I.getMetadata(KindID: llvm::LLVMContext::MD_dbg)) |
91 | MDs.push_back(Elt: DI); |
92 | } |
93 | identifyUninterestingMDNodes(O, MDs); |
94 | } |
95 | |