| 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 | |
| 20 | using namespace llvm; |
| 21 | |
| 22 | extern cl::OptionCategory LLVMReduceOptions; |
| 23 | |
| 24 | static 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 | |
| 29 | static bool shouldKeepDebugIntrinsicMetadata(Instruction &I, MDNode &MD) { |
| 30 | return isa<DILocation>(Val: MD) && isa<DbgInfoIntrinsic>(Val: I); |
| 31 | } |
| 32 | |
| 33 | static 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. |
| 39 | static 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. |
| 50 | void 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. |
| 79 | void 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 | |