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