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 "Delta.h" |
16 | #include "llvm/ADT/Sequence.h" |
17 | #include "llvm/ADT/SetVector.h" |
18 | #include "llvm/ADT/SmallVector.h" |
19 | #include "llvm/IR/DebugInfoMetadata.h" |
20 | #include "llvm/IR/InstIterator.h" |
21 | #include <tuple> |
22 | #include <vector> |
23 | |
24 | using namespace llvm; |
25 | |
26 | using MDNodeList = SmallVector<MDNode *>; |
27 | |
28 | void identifyUninterestingMDNodes(Oracle &O, MDNodeList &MDs) { |
29 | SetVector<std::tuple<MDNode *, size_t, MDNode *>> Tuples; |
30 | std::vector<MDNode *> ToLook; |
31 | SetVector<MDNode *> Visited; |
32 | |
33 | // Start by looking at the attachments we collected |
34 | for (const auto &NMD : MDs) |
35 | if (NMD) |
36 | ToLook.push_back(x: NMD); |
37 | |
38 | while (!ToLook.empty()) { |
39 | MDNode *MD = ToLook.back(); |
40 | ToLook.pop_back(); |
41 | |
42 | if (Visited.count(key: MD)) |
43 | continue; |
44 | |
45 | // Determine if the current MDNode is DebugInfo |
46 | if (DINode *DIM = dyn_cast_or_null<DINode>(Val: MD)) { |
47 | // Scan operands and record attached tuples |
48 | for (size_t I = 0; I < DIM->getNumOperands(); ++I) |
49 | if (MDTuple *MDT = dyn_cast_or_null<MDTuple>(Val: DIM->getOperand(I))) |
50 | if (!Visited.count(key: MDT) && MDT->getNumOperands()) |
51 | Tuples.insert(X: {DIM, I, MDT}); |
52 | } |
53 | |
54 | // Add all of the operands of the current node to the loop's todo list. |
55 | for (Metadata *Op : MD->operands()) |
56 | if (MDNode *OMD = dyn_cast_or_null<MDNode>(Val: Op)) |
57 | ToLook.push_back(x: OMD); |
58 | |
59 | Visited.insert(X: MD); |
60 | } |
61 | |
62 | for (auto &T : Tuples) { |
63 | auto [DbgNode, OpIdx, Tup] = T; |
64 | // Remove the operands of the tuple that are not in the desired chunks. |
65 | SmallVector<Metadata *, 16> TN; |
66 | for (size_t I = 0; I < Tup->getNumOperands(); ++I) { |
67 | // Ignore any operands that are not DebugInfo metadata nodes. |
68 | if (Metadata *Op = Tup->getOperand(I).get()) { |
69 | if (isa<DINode>(Val: Op) || isa<DIGlobalVariableExpression>(Val: Op)) |
70 | // Don't add uninteresting operands to the tuple. |
71 | if (!O.shouldKeep()) |
72 | continue; |
73 | TN.push_back(Elt: Op); |
74 | } |
75 | } |
76 | if (TN.size() != Tup->getNumOperands()) |
77 | DbgNode->replaceOperandWith(I: OpIdx, New: DbgNode->get(Context&: DbgNode->getContext(), MDs: TN)); |
78 | } |
79 | } |
80 | |
81 | static void (Oracle &O, ReducerWorkItem &WorkItem) { |
82 | Module &Program = WorkItem.getModule(); |
83 | |
84 | MDNodeList MDs; |
85 | // Collect all !dbg metadata attachments. |
86 | for (const auto &DC : Program.debug_compile_units()) |
87 | if (DC) |
88 | MDs.push_back(Elt: DC); |
89 | for (GlobalVariable &GV : Program.globals()) |
90 | GV.getMetadata(KindID: llvm::LLVMContext::MD_dbg, MDs); |
91 | for (Function &F : Program.functions()) { |
92 | F.getMetadata(KindID: llvm::LLVMContext::MD_dbg, MDs); |
93 | for (Instruction &I : instructions(F)) |
94 | if (auto *DI = I.getMetadata(KindID: llvm::LLVMContext::MD_dbg)) |
95 | MDs.push_back(Elt: DI); |
96 | } |
97 | identifyUninterestingMDNodes(O, MDs); |
98 | } |
99 | |
100 | void llvm::reduceDIMetadataDeltaPass(TestRunner &Test) { |
101 | runDeltaPass(Test, ExtractChunksFromModule: extractDIMetadataFromModule, Message: "Reducing DIMetadata" ); |
102 | } |
103 | |