Index: llvm/test/tools/llvm-reduce/Inputs/remove-dimetadata.py =================================================================== --- /dev/null +++ llvm/test/tools/llvm-reduce/Inputs/remove-dimetadata.py @@ -0,0 +1,8 @@ +import sys + +input = open(sys.argv[1], "r") +for line in input: + if "interesting" in line: + sys.exit(0) + +sys.exit(1) Index: llvm/test/tools/llvm-reduce/remove-dimetadata.ll =================================================================== --- /dev/null +++ llvm/test/tools/llvm-reduce/remove-dimetadata.ll @@ -0,0 +1,32 @@ +; Test that llvm-reduce can remove uninteresting DI metadata from an IR file. +; +; RUN: llvm-reduce --abort-on-invalid-reduction --delta-passes=di-metadata --test %python --test-arg %p/Inputs/remove-dimetadata.py %s -o %t +; RUN: cat %t | FileCheck %s + +@global = global i32 0 + +define void @main() !dbg !5 { + ret void +} + +!llvm.module.flags = !{!0} +!llvm.dbg.cu = !{!4} + +!0 = !{i32 2, !"Debug Info Version", i32 3} +!1 = !DIFile(filename: "test.c", directory: "test") +!2 = !{!10} +!4 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "clang", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !9) +!5 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 498, type: !6, scopeLine: 0, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !4, retainedNodes: !2) +!6 = !DISubroutineType(types: !7) +!7 = !{!13} +; CHECK: !{} +!8 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "clang", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !9) +!9 = !{} +!10 = !DILocalVariable(name: "one", scope: !14, file: !1, line: 0, type: !15) +!13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!14 = distinct !DILexicalBlock(scope: !5, file: !1, line: 3) +!15 = !DICompositeType(tag: DW_TAG_structure_type, name: "test", file: !1, size: 64, align: 32, flags: DIFlagPublic, elements: !16) +!16 = !{!17, !18} +; CHECK: !{!{{[0-9]+}}, null} +!17 = !DIDerivedType(tag: DW_TAG_member, name: "interesting", scope: !14, file: !1, baseType: !13, size: 32, align: 32, flags: DIFlagPublic) +!18 = !DIDerivedType(tag: DW_TAG_member, name: "uninteresting", scope: !14, file: !1, baseType: !13, size: 32, align: 32, offset: 32, flags: DIFlagPublic) Index: llvm/tools/llvm-reduce/CMakeLists.txt =================================================================== --- llvm/tools/llvm-reduce/CMakeLists.txt +++ llvm/tools/llvm-reduce/CMakeLists.txt @@ -28,6 +28,7 @@ deltas/ReduceArguments.cpp deltas/ReduceAttributes.cpp deltas/ReduceBasicBlocks.cpp + deltas/ReduceDIMetadata.cpp deltas/ReduceFunctionBodies.cpp deltas/ReduceFunctions.cpp deltas/ReduceGlobalObjects.cpp Index: llvm/tools/llvm-reduce/DeltaManager.cpp =================================================================== --- llvm/tools/llvm-reduce/DeltaManager.cpp +++ llvm/tools/llvm-reduce/DeltaManager.cpp @@ -19,6 +19,7 @@ #include "deltas/ReduceArguments.h" #include "deltas/ReduceAttributes.h" #include "deltas/ReduceBasicBlocks.h" +#include "deltas/ReduceDIMetadata.h" #include "deltas/ReduceFunctionBodies.h" #include "deltas/ReduceFunctions.h" #include "deltas/ReduceGlobalObjects.h" @@ -60,11 +61,14 @@ DELTA_PASS("function-bodies", reduceFunctionBodiesDeltaPass) \ DELTA_PASS("special-globals", reduceSpecialGlobalsDeltaPass) \ DELTA_PASS("aliases", reduceAliasesDeltaPass) \ + DELTA_PASS("function-bodies", reduceFunctionBodiesDeltaPass) \ + DELTA_PASS("functions", reduceFunctionsDeltaPass) \ DELTA_PASS("basic-blocks", reduceBasicBlocksDeltaPass) \ DELTA_PASS("global-values", reduceGlobalValuesDeltaPass) \ DELTA_PASS("global-objects", reduceGlobalObjectsDeltaPass) \ DELTA_PASS("global-initializers", reduceGlobalsInitializersDeltaPass) \ DELTA_PASS("global-variables", reduceGlobalsDeltaPass) \ + DELTA_PASS("di-metadata", reduceDIMetadataDeltaPass) \ DELTA_PASS("metadata", reduceMetadataDeltaPass) \ DELTA_PASS("arguments", reduceArgumentsDeltaPass) \ DELTA_PASS("instructions", reduceInstructionsDeltaPass) \ Index: llvm/tools/llvm-reduce/deltas/ReduceDIMetadata.h =================================================================== --- /dev/null +++ llvm/tools/llvm-reduce/deltas/ReduceDIMetadata.h @@ -0,0 +1,23 @@ +//===- ReduceMetadata.h - Specialized Delta Pass --------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements two functions used by the Generic Delta Debugging +// Algorithm, which are used to reduce Metadata nodes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVM_REDUCE_DELTAS_REDUCEDIMETADATA_H +#define LLVM_TOOLS_LLVM_REDUCE_DELTAS_REDUCEDIMETADATA_H + +#include "TestRunner.h" + +namespace llvm { +void reduceDIMetadataDeltaPass(TestRunner &Test); +} // namespace llvm + +#endif Index: llvm/tools/llvm-reduce/deltas/ReduceDIMetadata.cpp =================================================================== --- /dev/null +++ llvm/tools/llvm-reduce/deltas/ReduceDIMetadata.cpp @@ -0,0 +1,100 @@ +//===- ReduceMetadata.cpp - Specialized Delta Pass ------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements two functions used by the Generic Delta Debugging +// Algorithm, which are used to reduce Metadata nodes. +// +//===----------------------------------------------------------------------===// + +#include "ReduceDIMetadata.h" +#include "Delta.h" +#include "llvm/ADT/Sequence.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/IR/DebugInfoMetadata.h" +#include "llvm/IR/InstIterator.h" +#include +#include +#include +#include + +using namespace llvm; + +using MDNodeList = SmallVector; + +void identifyUninterestingMDNodes(Oracle &O, MDNodeList &MDs) { + std::set> Tuples; + std::vector ToLook; + std::set Visited; + + // Start by looking at the attachments we collected + for (const auto &NMD : MDs) + if (NMD && !Visited.count(NMD)) + ToLook.push_back(NMD); + + while (!ToLook.empty()) { + MDNode *MD = ToLook.back(); + ToLook.pop_back(); + + // Determine if the current MDNode is DebugInfo + if (DINode *DIM = dyn_cast_or_null(MD)) { + // Scan operands and record attached tuples + for (size_t I = 0; I < DIM->getNumOperands(); ++I) + if (MDTuple *MDT = dyn_cast_or_null(DIM->getOperand(I))) + if (MDT && !Visited.count(MDT) && MDT->getNumOperands()) + Tuples.insert({DIM, I, MDT}); + } + + // Add all of the operands of the current node to the loop's todo list. + for (Metadata *Op : MD->operands()) + if (MDNode *OMD = dyn_cast_or_null(Op)) + if (OMD && !Visited.count(OMD)) + ToLook.push_back(OMD); + + Visited.insert(MD); + } + + for (auto &T : Tuples) { + size_t Z = 0; + auto [MO, J, MT] = T; + // Null the operands of the tuple that are not in the desired chunks. + for (size_t I = 0; I < MT->getNumOperands(); ++I) { + // Ignore any operands that are not DebugInfo metadata nodes. + if (MDNode *OMD = dyn_cast_or_null(MT->getOperand(I))) { + if (!O.shouldKeep()) { + MT->replaceOperandWith(I, nullptr); + Z++; + } + } + } + + // If no operands of the current tuple are within the current chunks, + // replace it with a empty tuple. + if (MT->getNumOperands() == Z) + MO->replaceOperandWith(J, MT->get(MT->getContext(), {})); + } +} + +static void extractDIMetadataFromModule(Oracle &O, Module &Program) { + MDNodeList MDs; + // Collect all !dbg metadata attachments. + for (GlobalVariable &GV : Program.globals()) + GV.getMetadata(llvm::LLVMContext::MD_dbg, MDs); + for (Function &F : Program.functions()) { + F.getMetadata(llvm::LLVMContext::MD_dbg, MDs); + for (Instruction &I : instructions(F)) + if (auto *DI = I.getMetadata(llvm::LLVMContext::MD_dbg)) + MDs.push_back(DI); + } + identifyUninterestingMDNodes(O, MDs); +} + +void llvm::reduceDIMetadataDeltaPass(TestRunner &Test) { + outs() << "*** Reducing DIMetadata...\n"; + runDeltaPass(Test, extractDIMetadataFromModule); + outs() << "----------------------------\n"; +}