1//===- ReduceMetadata.cpp - Specialized Delta Pass ------------------------===//
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 Metadata nodes.
11//
12//===----------------------------------------------------------------------===//
13
14#include "ReduceMetadata.h"
15#include "Delta.h"
16#include "llvm/ADT/Sequence.h"
17#include "llvm/ADT/SmallVector.h"
18#include "llvm/IR/InstIterator.h"
19#include "llvm/IR/IntrinsicInst.h"
20
21using namespace llvm;
22
23static bool shouldKeepDebugIntrinsicMetadata(Instruction &I, MDNode &MD) {
24 return isa<DILocation>(Val: MD) && isa<DbgInfoIntrinsic>(Val: I);
25}
26
27static bool shouldKeepDebugNamedMetadata(NamedMDNode &MD) {
28 return MD.getName() == "llvm.dbg.cu" && MD.getNumOperands() != 0;
29}
30
31// Named metadata with simple list-like behavior, so that it's valid to remove
32// operands individually.
33static constexpr StringLiteral ListNamedMetadata[] = {
34 "llvm.module.flags",
35 "llvm.ident",
36 "opencl.spir.version",
37 "opencl.ocl.version",
38 "opencl.used.extensions",
39 "opencl.used.optional.core.features",
40 "opencl.compiler.options"
41};
42
43/// Remove unneeded arguments to named metadata.
44static void reduceNamedMetadataOperands(Oracle &O, ReducerWorkItem &WorkItem) {
45 Module &M = WorkItem.getModule();
46
47 for (StringRef MDName : ListNamedMetadata) {
48 NamedMDNode *NamedNode = M.getNamedMetadata(Name: MDName);
49 if (!NamedNode)
50 continue;
51
52 bool MadeChange = false;
53 SmallVector<MDNode *, 16> KeptOperands;
54 for (auto I : seq<unsigned>(Begin: 0, End: NamedNode->getNumOperands())) {
55 if (O.shouldKeep())
56 KeptOperands.push_back(Elt: NamedNode->getOperand(i: I));
57 else
58 MadeChange = true;
59 }
60
61 if (MadeChange) {
62 NamedNode->clearOperands();
63 for (MDNode *KeptOperand : KeptOperands)
64 NamedNode->addOperand(M: KeptOperand);
65 }
66 }
67}
68
69/// Removes all the Named and Unnamed Metadata Nodes, as well as any debug
70/// functions that aren't inside the desired Chunks.
71static void extractMetadataFromModule(Oracle &O, ReducerWorkItem &WorkItem) {
72 Module &Program = WorkItem.getModule();
73
74 // Get out-of-chunk Named metadata nodes
75 SmallVector<NamedMDNode *> NamedNodesToDelete;
76 for (NamedMDNode &MD : Program.named_metadata())
77 if (!shouldKeepDebugNamedMetadata(MD) && !O.shouldKeep())
78 NamedNodesToDelete.push_back(Elt: &MD);
79
80 for (NamedMDNode *NN : NamedNodesToDelete) {
81 for (auto I : seq<unsigned>(Begin: 0, End: NN->getNumOperands()))
82 NN->setOperand(I, New: nullptr);
83 NN->eraseFromParent();
84 }
85
86 // Delete out-of-chunk metadata attached to globals.
87 for (GlobalVariable &GV : Program.globals()) {
88 SmallVector<std::pair<unsigned, MDNode *>> MDs;
89 GV.getAllMetadata(MDs);
90 for (std::pair<unsigned, MDNode *> &MD : MDs)
91 if (!O.shouldKeep())
92 GV.setMetadata(KindID: MD.first, Node: nullptr);
93 }
94
95 for (Function &F : Program) {
96 {
97 SmallVector<std::pair<unsigned, MDNode *>> MDs;
98 // Delete out-of-chunk metadata attached to functions.
99 F.getAllMetadata(MDs);
100 for (std::pair<unsigned, MDNode *> &MD : MDs)
101 if (!O.shouldKeep())
102 F.setMetadata(KindID: MD.first, Node: nullptr);
103 }
104
105 // Delete out-of-chunk metadata attached to instructions.
106 for (Instruction &I : instructions(F)) {
107 SmallVector<std::pair<unsigned, MDNode *>> MDs;
108 I.getAllMetadata(MDs);
109 for (std::pair<unsigned, MDNode *> &MD : MDs) {
110 if (!shouldKeepDebugIntrinsicMetadata(I, MD&: *MD.second) && !O.shouldKeep())
111 I.setMetadata(KindID: MD.first, Node: nullptr);
112 }
113 }
114 }
115}
116
117void llvm::reduceMetadataDeltaPass(TestRunner &Test) {
118 runDeltaPass(Test, ExtractChunksFromModule: extractMetadataFromModule, Message: "Reducing Metadata");
119}
120
121void llvm::reduceNamedMetadataDeltaPass(TestRunner &Test) {
122 runDeltaPass(Test, ExtractChunksFromModule: reduceNamedMetadataOperands, Message: "Reducing Named Metadata");
123}
124