David Blaikie | 477c1df | 2019-09-10 22:09:58 +0000 | [diff] [blame] | 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/SmallVector.h" |
| 17 | #include <set> |
| 18 | #include <vector> |
| 19 | |
| 20 | using namespace llvm; |
| 21 | |
| 22 | /// Adds all Unnamed Metadata Nodes that are inside desired Chunks to set |
| 23 | template <class T> |
| 24 | static void getChunkMetadataNodes(T &MDUser, unsigned &I, |
| 25 | const std::vector<Chunk> &ChunksToKeep, |
| 26 | std::set<MDNode *> &SeenNodes, |
| 27 | std::set<MDNode *> &NodesToKeep) { |
| 28 | SmallVector<std::pair<unsigned, MDNode *>, 4> MDs; |
| 29 | MDUser.getAllMetadata(MDs); |
| 30 | for (auto &MD : MDs) { |
| 31 | SeenNodes.insert(MD.second); |
| 32 | if (I < ChunksToKeep.size()) { |
| 33 | if (ChunksToKeep[I].contains(SeenNodes.size())) |
| 34 | NodesToKeep.insert(MD.second); |
| 35 | if (ChunksToKeep[I].end == SeenNodes.size()) |
| 36 | ++I; |
| 37 | } |
| 38 | } |
| 39 | } |
| 40 | |
| 41 | /// Erases out-of-chunk unnamed metadata nodes from its user |
| 42 | template <class T> |
| 43 | static void eraseMetadataIfOutsideChunk(T &MDUser, |
| 44 | const std::set<MDNode *> &NodesToKeep) { |
| 45 | SmallVector<std::pair<unsigned, MDNode *>, 4> MDs; |
| 46 | MDUser.getAllMetadata(MDs); |
| 47 | for (int I = 0, E = MDs.size(); I != E; ++I) |
| 48 | if (!NodesToKeep.count(MDs[I].second)) |
| 49 | MDUser.setMetadata(I, NULL); |
| 50 | } |
| 51 | |
| 52 | /// Removes all the Named and Unnamed Metadata Nodes, as well as any debug |
| 53 | /// functions that aren't inside the desired Chunks. |
David Blaikie | 477c1df | 2019-09-10 22:09:58 +0000 | [diff] [blame] | 54 | static void extractMetadataFromModule(const std::vector<Chunk> &ChunksToKeep, |
| 55 | Module *Program) { |
| 56 | std::set<MDNode *> SeenNodes; |
| 57 | std::set<MDNode *> NodesToKeep; |
| 58 | unsigned I = 0; |
| 59 | |
| 60 | // Add chunk MDNodes used by GVs, Functions, and Instructions to set |
| 61 | for (auto &GV : Program->globals()) |
| 62 | getChunkMetadataNodes(GV, I, ChunksToKeep, SeenNodes, NodesToKeep); |
| 63 | |
| 64 | for (auto &F : *Program) { |
| 65 | getChunkMetadataNodes(F, I, ChunksToKeep, SeenNodes, NodesToKeep); |
| 66 | for (auto &BB : F) |
| 67 | for (auto &Inst : BB) |
| 68 | getChunkMetadataNodes(Inst, I, ChunksToKeep, SeenNodes, NodesToKeep); |
| 69 | } |
| 70 | |
| 71 | // Once more, go over metadata nodes, but deleting the ones outside chunks |
| 72 | for (auto &GV : Program->globals()) |
| 73 | eraseMetadataIfOutsideChunk(GV, NodesToKeep); |
| 74 | |
| 75 | for (auto &F : *Program) { |
| 76 | eraseMetadataIfOutsideChunk(F, NodesToKeep); |
| 77 | for (auto &BB : F) |
| 78 | for (auto &Inst : BB) |
| 79 | eraseMetadataIfOutsideChunk(Inst, NodesToKeep); |
| 80 | } |
| 81 | |
| 82 | |
| 83 | // Get out-of-chunk Named metadata nodes |
| 84 | unsigned MetadataCount = SeenNodes.size(); |
| 85 | std::vector<NamedMDNode *> NamedNodesToDelete; |
| 86 | for (auto &MD : Program->named_metadata()) { |
| 87 | if (I < ChunksToKeep.size()) { |
| 88 | if (!ChunksToKeep[I].contains(++MetadataCount)) |
| 89 | NamedNodesToDelete.push_back(&MD); |
| 90 | if (ChunksToKeep[I].end == SeenNodes.size()) |
| 91 | ++I; |
| 92 | } else |
| 93 | NamedNodesToDelete.push_back(&MD); |
| 94 | } |
| 95 | |
| 96 | for (auto *NN : NamedNodesToDelete) { |
| 97 | for (int I = 0, E = NN->getNumOperands(); I != E; ++I) |
| 98 | NN->setOperand(I, NULL); |
| 99 | NN->eraseFromParent(); |
| 100 | } |
| 101 | } |
| 102 | |
| 103 | // Gets unnamed metadata nodes used by a given instruction/GV/function and adds |
| 104 | // them to the set of seen nodes |
| 105 | template <class T> |
| 106 | static void addMetadataToSet(T &MDUser, std::set<MDNode *> &UnnamedNodes) { |
| 107 | SmallVector<std::pair<unsigned, MDNode *>, 4> MDs; |
| 108 | MDUser.getAllMetadata(MDs); |
| 109 | for (auto &MD : MDs) |
| 110 | UnnamedNodes.insert(MD.second); |
| 111 | } |
| 112 | |
| 113 | /// Returns the amount of Named and Unnamed Metadata Nodes |
| 114 | static unsigned countMetadataTargets(Module *Program) { |
| 115 | std::set<MDNode *> UnnamedNodes; |
| 116 | int NamedMetadataNodes = Program->named_metadata_size(); |
| 117 | |
| 118 | // Get metadata nodes used by globals |
| 119 | for (auto &GV : Program->globals()) |
| 120 | addMetadataToSet(GV, UnnamedNodes); |
| 121 | |
| 122 | // Do the same for nodes used by functions & instructions |
| 123 | for (auto &F : *Program) { |
| 124 | addMetadataToSet(F, UnnamedNodes); |
| 125 | for (auto &BB : F) |
| 126 | for (auto &I : BB) |
| 127 | addMetadataToSet(I, UnnamedNodes); |
| 128 | } |
| 129 | |
| 130 | return UnnamedNodes.size() + NamedMetadataNodes; |
| 131 | } |
| 132 | |
| 133 | void llvm::reduceMetadataDeltaPass(TestRunner &Test) { |
| 134 | outs() << "*** Reducing Metadata...\n"; |
| 135 | unsigned MDCount = countMetadataTargets(Test.getProgram()); |
| 136 | runDeltaPass(Test, MDCount, extractMetadataFromModule); |
| 137 | outs() << "----------------------------\n"; |
| 138 | } |