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