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