diff --git a/llvm/test/tools/llvm-reduce/Inputs/remove-metadata.py b/llvm/test/tools/llvm-reduce/Inputs/remove-metadata.py deleted file mode 100755 --- a/llvm/test/tools/llvm-reduce/Inputs/remove-metadata.py +++ /dev/null @@ -1,8 +0,0 @@ -import sys - -input = open(sys.argv[1], "r") -for line in input: - if "!interesting" in line: - sys.exit(0) - -sys.exit(1) diff --git a/llvm/test/tools/llvm-reduce/remove-debug-info-nodes.ll b/llvm/test/tools/llvm-reduce/remove-debug-info-nodes.ll --- a/llvm/test/tools/llvm-reduce/remove-debug-info-nodes.ll +++ b/llvm/test/tools/llvm-reduce/remove-debug-info-nodes.ll @@ -12,6 +12,10 @@ ; CHECK-INTERESTINGNESS-DAG: [[CU]] = distinct !DICompileUnit(language: DW_LANG_C99,{{.*}}, retainedTypes: [[TYPES:![0-9]+]] ; CHECK-INTERESTINGNESS-DAG: [[TYPES]] = !{[[T0:![0-9]+]] ; CHECK-INTERESTINGNESS-DAG: [[T0]] = !DIBasicType(name: "unsigned int", +; CHECK-INTERESTINGNESS-DAG: !DIGlobalVariable( +; CHECK-INTERESTINGNESS-DAG: !DILocalVariable(name: "A" +; CHECK-INTERESTINGNESS-DAG: !DILocalVariable(name: "B" +; CHECK-INTERESTINGNESS-DAG: !DILocalVariable(name: "C" diff --git a/llvm/test/tools/llvm-reduce/remove-metadata-elements.ll b/llvm/test/tools/llvm-reduce/remove-metadata-elements.ll new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-reduce/remove-metadata-elements.ll @@ -0,0 +1,35 @@ +; RUN: llvm-reduce %s -o %t --delta-passes=metadata --test FileCheck --test-arg %s --test-arg --input-file +; RUN: FileCheck %s < %t --implicit-check-not="boring" + +; Test that debug metadata lists can be reduced by making sure debug info for +; "boring" globals are removed. + +; $ cat a.c +; int boringA, interesting, boringB; +; $ clang a.c -g -S -emit-llvm -o - + +@A = dso_local global i32 0, align 4, !dbg !0 +@B = dso_local global i32 0, align 4, !dbg !5 +@C = dso_local global i32 0, align 4, !dbg !8 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!10, !11, !12, !13, !14, !15, !16} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "boringA", scope: !2, file: !3, line: 1, type: !7, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None) +!3 = !DIFile(filename: "a.c", directory: "") +!4 = !{!0, !5, !8} +!5 = !DIGlobalVariableExpression(var: !6, expr: !DIExpression()) +; CHECK: !DIGlobalVariable(name: "interesting" +!6 = distinct !DIGlobalVariable(name: "interesting", scope: !2, file: !3, line: 1, type: !7, isLocal: false, isDefinition: true) +!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!8 = !DIGlobalVariableExpression(var: !9, expr: !DIExpression()) +!9 = distinct !DIGlobalVariable(name: "boringB", scope: !2, file: !3, line: 1, type: !7, isLocal: false, isDefinition: true) +!10 = !{i32 7, !"Dwarf Version", i32 5} +!11 = !{i32 2, !"Debug Info Version", i32 3} +!12 = !{i32 1, !"wchar_size", i32 4} +!13 = !{i32 8, !"PIC Level", i32 2} +!14 = !{i32 7, !"PIE Level", i32 2} +!15 = !{i32 7, !"uwtable", i32 2} +!16 = !{i32 7, !"frame-pointer", i32 2} diff --git a/llvm/test/tools/llvm-reduce/remove-metadata.ll b/llvm/test/tools/llvm-reduce/remove-metadata.ll --- a/llvm/test/tools/llvm-reduce/remove-metadata.ll +++ b/llvm/test/tools/llvm-reduce/remove-metadata.ll @@ -1,8 +1,8 @@ ; Test that llvm-reduce can remove uninteresting metadata from an IR file. ; The Metadata pass erases named & unnamed metadata nodes. ; -; RUN: llvm-reduce --test %python --test-arg %p/Inputs/remove-metadata.py %s -o %t -; RUN: cat %t | FileCheck -implicit-check-not=! %s +; RUN: llvm-reduce %s -o %t --delta-passes=metadata --test FileCheck --test-arg %s --test-arg --input-file +; RUN: FileCheck %s < %t @global = global i32 0, !dbg !0 @@ -11,9 +11,9 @@ } !uninteresting = !{!0} -; CHECK: !interesting = !{!0} +; CHECK: !interesting = !{![[I:[0-9]+]]} !interesting = !{!1} !0 = !{!"uninteresting"} -; CHECK: !0 = !{!"interesting"} +; CHECK: ![[I]] = !{!"interesting"} !1 = !{!"interesting"} diff --git a/llvm/test/tools/llvm-reduce/remove-named-metadata-elements.ll b/llvm/test/tools/llvm-reduce/remove-named-metadata-elements.ll new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-reduce/remove-named-metadata-elements.ll @@ -0,0 +1,23 @@ +; RUN: llvm-reduce %s -o %t --delta-passes=metadata --test FileCheck --test-arg %s --test-arg --input-file +; RUN: FileCheck %s < %t --implicit-check-not="boring" --check-prefixes=CHECK,REDUCED + +; Test that we can remove elements from named metadata. + +!llvm.dbg.cu = !{!0, !1} +; CHECK: !llvm.module.flags = +; REDUCED-SAME: !{} +!llvm.module.flags = !{!10, !11, !12, !13, !14, !15, !16} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !2, isOptimized: false, runtimeVersion: 0, emissionKind: NoDebug) +!1 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, isOptimized: false, runtimeVersion: 0, emissionKind: NoDebug) +; CHECK: !DIFile(filename: "interesting.c" +!2 = !DIFile(filename: "interesting.c", directory: "") +!3 = !DIFile(filename: "boring.c", directory: "") + +!10 = !{i32 7, !"Dwarf Version", i32 5} +!11 = !{i32 2, !"Debug Info Version", i32 3} +!12 = !{i32 1, !"wchar_size", i32 4} +!13 = !{i32 8, !"PIC Level", i32 2} +!14 = !{i32 7, !"PIE Level", i32 2} +!15 = !{i32 7, !"uwtable", i32 2} +!16 = !{i32 7, !"frame-pointer", i32 2} diff --git a/llvm/tools/llvm-reduce/deltas/ReduceMetadata.cpp b/llvm/tools/llvm-reduce/deltas/ReduceMetadata.cpp --- a/llvm/tools/llvm-reduce/deltas/ReduceMetadata.cpp +++ b/llvm/tools/llvm-reduce/deltas/ReduceMetadata.cpp @@ -23,11 +23,18 @@ /// Removes all the Named and Unnamed Metadata Nodes, as well as any debug /// functions that aren't inside the desired Chunks. static void extractMetadataFromModule(Oracle &O, Module &Program) { + SmallSetVector NodesToVisit; + // Get out-of-chunk Named metadata nodes SmallVector NamedNodesToDelete; - for (NamedMDNode &MD : Program.named_metadata()) - if (!O.shouldKeep()) + for (NamedMDNode &MD : Program.named_metadata()) { + if (O.shouldKeep()) { + for (auto *Op : MD.operands()) + NodesToVisit.insert(Op); + } else { NamedNodesToDelete.push_back(&MD); + } + } for (NamedMDNode *NN : NamedNodesToDelete) { for (auto I : seq(0, NN->getNumOperands())) @@ -35,13 +42,30 @@ NN->eraseFromParent(); } + // Delete elements from named metadata lists + for (auto &NamedList : Program.named_metadata()) { + SmallVector NewOperands; + for (auto *Op : NamedList.operands()) + if (O.shouldKeep()) + NewOperands.push_back(Op); + if (NewOperands.size() == NamedList.getNumOperands()) + continue; + NamedList.clearOperands(); + for (auto *Op : NewOperands) + NamedList.addOperand(Op); + } + // Delete out-of-chunk metadata attached to globals. for (GlobalVariable &GV : Program.globals()) { SmallVector> MDs; GV.getAllMetadata(MDs); - for (std::pair &MD : MDs) - if (!O.shouldKeep()) + for (std::pair &MD : MDs) { + if (O.shouldKeep()) { + NodesToVisit.insert(MD.second); + } else { GV.setMetadata(MD.first, nullptr); + } + } } for (Function &F : Program) { @@ -49,20 +73,57 @@ SmallVector> MDs; // Delete out-of-chunk metadata attached to functions. F.getAllMetadata(MDs); - for (std::pair &MD : MDs) - if (!O.shouldKeep()) + for (std::pair &MD : MDs) { + if (O.shouldKeep()) { + NodesToVisit.insert(MD.second); + } else { F.setMetadata(MD.first, nullptr); + } + } } // Delete out-of-chunk metadata attached to instructions. for (Instruction &I : instructions(F)) { SmallVector> MDs; I.getAllMetadata(MDs); - for (std::pair &MD : MDs) - if (!O.shouldKeep()) + for (std::pair &MD : MDs) { + if (O.shouldKeep()) { + NodesToVisit.insert(MD.second); + } else { I.setMetadata(MD.first, nullptr); + } + } } } + + // Gather all metadata tuples and their parents + SmallVector> OperandsOfTuples; + SmallSet VisitedNodes; + while (!NodesToVisit.empty()) { + auto *Node = NodesToVisit.pop_back_val(); + if (!VisitedNodes.insert(Node).second) + continue; + for (auto I : seq(0, Node->getNumOperands())) { + auto *Op = Node->getOperand(I).get(); + if (auto *MD = dyn_cast_or_null(Op)) + NodesToVisit.insert(MD); + if (isa_and_nonnull(Op)) + OperandsOfTuples.push_back(std::make_pair(Node, I)); + } + } + + // Delete elements from metadata tuples + for (auto [Node, NodeOpID] : OperandsOfTuples) { + auto *Tuple = dyn_cast(Node->getOperand(NodeOpID)); + SmallVector NewOperands; + for (auto &Op : Tuple->operands()) + if (O.shouldKeep()) + NewOperands.push_back(Op.get()); + if (NewOperands.size() == Tuple->getNumOperands()) + continue; + Node->replaceOperandWith( + NodeOpID, MDTuple::get(Tuple->getContext(), makeArrayRef(NewOperands))); + } } void llvm::reduceMetadataDeltaPass(TestRunner &Test) {