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