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 "llvm/ADT/Sequence.h"
16#include "llvm/ADT/SmallVector.h"
17#include "llvm/IR/InstIterator.h"
18#include "llvm/Support/CommandLine.h"
19
20using namespace llvm;
21
22extern cl::OptionCategory LLVMReduceOptions;
23
24static cl::opt<bool> AggressiveMetadataReduction(
25 "aggressive-named-md-reduction",
26 cl::desc("Reduce named metadata without taking its type into account"),
27 cl::cat(LLVMReduceOptions));
28
29static bool shouldKeepDebugNamedMetadata(NamedMDNode &MD) {
30 return MD.getName() == "llvm.dbg.cu" && MD.getNumOperands() != 0;
31}
32
33// Named metadata with simple list-like behavior, so that it's valid to remove
34// operands individually.
35static constexpr StringLiteral ListNamedMetadata[] = {
36 "llvm.module.flags",
37 "llvm.ident",
38 "opencl.spir.version",
39 "opencl.ocl.version",
40 "opencl.used.extensions",
41 "opencl.used.optional.core.features",
42 "opencl.compiler.options"
43};
44
45/// Remove unneeded arguments to named metadata.
46void llvm::reduceNamedMetadataDeltaPass(Oracle &O, ReducerWorkItem &WorkItem) {
47 Module &M = WorkItem.getModule();
48
49 for (NamedMDNode &I : M.named_metadata()) {
50 // If we don't want to reduce mindlessly, check if our node is part of
51 // ListNamedMetadata before reducing it
52 if (!AggressiveMetadataReduction &&
53 !is_contained(Range: ListNamedMetadata, Element: I.getName()))
54 continue;
55
56 bool MadeChange = false;
57 SmallVector<MDNode *> KeptOperands;
58 for (auto J : seq<unsigned>(Begin: 0, End: I.getNumOperands())) {
59 if (O.shouldKeep())
60 KeptOperands.push_back(Elt: I.getOperand(i: J));
61 else
62 MadeChange = true;
63 }
64
65 if (MadeChange) {
66 I.clearOperands();
67 for (MDNode *KeptOperand : KeptOperands)
68 I.addOperand(M: KeptOperand);
69 }
70 }
71}
72
73/// Removes all the Named and Unnamed Metadata Nodes, as well as any debug
74/// functions that aren't inside the desired Chunks.
75void llvm::reduceMetadataDeltaPass(Oracle &O, ReducerWorkItem &WorkItem) {
76 Module &Program = WorkItem.getModule();
77
78 // Get out-of-chunk Named metadata nodes
79 SmallVector<NamedMDNode *> NamedNodesToDelete;
80 for (NamedMDNode &MD : Program.named_metadata())
81 if (!shouldKeepDebugNamedMetadata(MD) && !O.shouldKeep())
82 NamedNodesToDelete.push_back(Elt: &MD);
83
84 for (NamedMDNode *NN : NamedNodesToDelete) {
85 for (auto I : seq<unsigned>(Begin: 0, End: NN->getNumOperands()))
86 NN->setOperand(I, New: nullptr);
87 NN->eraseFromParent();
88 }
89
90 // Delete out-of-chunk metadata attached to globals.
91 for (GlobalVariable &GV : Program.globals()) {
92 SmallVector<std::pair<unsigned, MDNode *>> MDs;
93 GV.getAllMetadata(MDs);
94 for (std::pair<unsigned, MDNode *> &MD : MDs)
95 if (!O.shouldKeep())
96 GV.setMetadata(KindID: MD.first, Node: nullptr);
97 }
98
99 for (Function &F : Program) {
100 {
101 SmallVector<std::pair<unsigned, MDNode *>> MDs;
102 // Delete out-of-chunk metadata attached to functions.
103 F.getAllMetadata(MDs);
104 for (std::pair<unsigned, MDNode *> &MD : MDs)
105 if (!O.shouldKeep())
106 F.setMetadata(KindID: MD.first, Node: nullptr);
107 }
108
109 // Delete out-of-chunk metadata attached to instructions.
110 for (Instruction &I : instructions(F)) {
111 SmallVector<std::pair<unsigned, MDNode *>> MDs;
112 I.getAllMetadata(MDs);
113 for (std::pair<unsigned, MDNode *> &MD : MDs) {
114 if (!O.shouldKeep())
115 I.setMetadata(KindID: MD.first, Node: nullptr);
116 }
117 }
118 }
119}
120