From d9562a8e4528411aa22bd960a6487c0e2708dd4e Mon Sep 17 00:00:00 2001 From: Michael Kruse Date: Wed, 29 Sep 2021 10:51:13 -0500 Subject: [PATCH] [llvm-reduce] Reduce metadata references. The ReduceMetadata pass before this patch removed metadata on a per-MDNode (or NamedMDNode) basis. Either all references to an MDNode are kept, or all of them are removed. However, MDNodes are uniqued, meaning that references to MDNodes with the same data become references to the same MDNodes. As a consequence, e.g. tbaa references to the same type will all have the same MDNode reference and hence make it impossible to reduce only keeping metadata on those memory access for which they are interesting. Moreover, MDNodes can also be referenced by some intrinsics or other MDNodes. These references were not considered for removal leading to the possibility that MDNodes are not actually removed even if selected to be removed by the oracle. This patch changes ReduceMetadata to reduces based on removable metadata references instead. MDNodes without references implicitly dropped anyway. References by intrinsic calls should be removed by ReduceOperands or ReduceInstructions. References in other MDNodes cannot be removed as it would violate the immutability of MDNodes. Additionally, ReduceMetadata pass before this patch used `setMetadata(I, NULL)` to remove references, where `I` is the index in the array returned by `getAllMetadata`. However, `setMetadata` expects a MDKind (such as `MD_tbaa`) as first argument. `getAllMetadata` does not return those in consecutive order (otherwise it would not need to be a `std::pair` with `first` representing the MDKind). Reviewed By: aeubanks, swamulism Differential Revision: https://reviews.llvm.org/D110534 --- .../test/tools/llvm-reduce/remove-metadata-args.ll | 29 +++++ llvm/tools/llvm-reduce/deltas/ReduceMetadata.cpp | 127 ++++++++------------- 2 files changed, 79 insertions(+), 77 deletions(-) create mode 100644 llvm/test/tools/llvm-reduce/remove-metadata-args.ll diff --git a/llvm/test/tools/llvm-reduce/remove-metadata-args.ll b/llvm/test/tools/llvm-reduce/remove-metadata-args.ll new file mode 100644 index 0000000..817f1eb --- /dev/null +++ b/llvm/test/tools/llvm-reduce/remove-metadata-args.ll @@ -0,0 +1,29 @@ +; RUN: llvm-reduce %s -o %t --delta-passes=metadata --test FileCheck --test-arg %s --test-arg --check-prefix=EXCITING --test-arg --input-file +; RUN: FileCheck %s --input-file %t --check-prefix=REDUCED + +; All exciting stuff must remain in the reduced file. +; EXCITING-DAG: ExcitingGlobal = global i32 0, !md !0 +; EXCITING-DAG: define void @ExcitingFunc() !md !0 +; EXCITING-DAG: store i32 0, i32* @ExcitingGlobal, align 4, !md !0 +; EXCITING-DAG: !ExcitingNamedMD = !{!0} + +; Boring stuff's metadata must have been removed. +; REDUCED-NOT: Boring{{.*}} !md !0 +; REDUCED-NOT: !md !0 {{.*}}Boring + + +@ExcitingGlobal = global i32 0, !md !0 +@BoringGlobal = global i32 0, !md !0 + +define void @ExcitingFunc() !md !0 { + store i32 0, i32* @ExcitingGlobal, align 4, !md !0 + store i32 0, i32* @BoringGlobal, align 4, !md !0 + ret void +} + +declare !md !0 void @BoringFunc() + +!ExcitingNamedMD = !{!0} +!BoringNamedMD = !{!0} + +!0 = !{!"my metadata"} diff --git a/llvm/tools/llvm-reduce/deltas/ReduceMetadata.cpp b/llvm/tools/llvm-reduce/deltas/ReduceMetadata.cpp index 4587295..8eb4533 100644 --- a/llvm/tools/llvm-reduce/deltas/ReduceMetadata.cpp +++ b/llvm/tools/llvm-reduce/deltas/ReduceMetadata.cpp @@ -13,110 +13,83 @@ #include "ReduceMetadata.h" #include "Delta.h" +#include "llvm/ADT/Sequence.h" #include "llvm/ADT/SmallVector.h" -#include +#include "llvm/IR/InstIterator.h" #include using namespace llvm; -/// Adds all Unnamed Metadata Nodes that are inside desired Chunks to set -template -static void getChunkMetadataNodes(T &MDUser, Oracle &O, - std::set &SeenNodes, - std::set &NodesToKeep) { - SmallVector, 4> MDs; - MDUser.getAllMetadata(MDs); - for (auto &MD : MDs) { - SeenNodes.insert(MD.second); - if (O.shouldKeep()) - NodesToKeep.insert(MD.second); - } -} - -/// Erases out-of-chunk unnamed metadata nodes from its user -template -static void eraseMetadataIfOutsideChunk(T &MDUser, - const std::set &NodesToKeep) { - SmallVector, 4> MDs; - MDUser.getAllMetadata(MDs); - for (int I = 0, E = MDs.size(); I != E; ++I) - if (!NodesToKeep.count(MDs[I].second)) - MDUser.setMetadata(I, NULL); -} - /// Removes all the Named and Unnamed Metadata Nodes, as well as any debug /// functions that aren't inside the desired Chunks. static void extractMetadataFromModule(const std::vector &ChunksToKeep, Module *Program) { Oracle O(ChunksToKeep); - std::set SeenNodes; - std::set NodesToKeep; - - // Add chunk MDNodes used by GVs, Functions, and Instructions to set - for (auto &GV : Program->globals()) - getChunkMetadataNodes(GV, O, SeenNodes, NodesToKeep); - - for (auto &F : *Program) { - getChunkMetadataNodes(F, O, SeenNodes, NodesToKeep); - for (auto &BB : F) - for (auto &Inst : BB) - getChunkMetadataNodes(Inst, O, SeenNodes, NodesToKeep); - } - - // Once more, go over metadata nodes, but deleting the ones outside chunks - for (auto &GV : Program->globals()) - eraseMetadataIfOutsideChunk(GV, NodesToKeep); - - for (auto &F : *Program) { - eraseMetadataIfOutsideChunk(F, NodesToKeep); - for (auto &BB : F) - for (auto &Inst : BB) - eraseMetadataIfOutsideChunk(Inst, NodesToKeep); - } - - // Get out-of-chunk Named metadata nodes - std::vector NamedNodesToDelete; - for (auto &MD : Program->named_metadata()) + SmallVector NamedNodesToDelete; + for (NamedMDNode &MD : Program->named_metadata()) if (!O.shouldKeep()) NamedNodesToDelete.push_back(&MD); - for (auto *NN : NamedNodesToDelete) { - for (int I = 0, E = NN->getNumOperands(); I != E; ++I) + for (NamedMDNode *NN : NamedNodesToDelete) { + for (auto I : seq(0, NN->getNumOperands())) NN->setOperand(I, NULL); NN->eraseFromParent(); } -} -// Gets unnamed metadata nodes used by a given instruction/GV/function and adds -// them to the set of seen nodes -template -static void addMetadataToSet(T &MDUser, std::set &UnnamedNodes) { - SmallVector, 4> MDs; - MDUser.getAllMetadata(MDs); - for (auto &MD : MDs) - UnnamedNodes.insert(MD.second); + // Delete out-of-chunk metadata attached to globals. + SmallVector> MDs; + for (GlobalVariable &GV : Program->globals()) { + GV.getAllMetadata(MDs); + for (std::pair &MD : MDs) + if (!O.shouldKeep()) + GV.setMetadata(MD.first, NULL); + } + + for (Function &F : *Program) { + // Delete out-of-chunk metadata attached to functions. + F.getAllMetadata(MDs); + for (std::pair &MD : MDs) + if (!O.shouldKeep()) + F.setMetadata(MD.first, NULL); + + // Delete out-of-chunk metadata attached to instructions. + for (Instruction &I : instructions(F)) { + I.getAllMetadata(MDs); + for (std::pair &MD : MDs) + if (!O.shouldKeep()) + I.setMetadata(MD.first, NULL); + } + } } -/// Returns the amount of Named and Unnamed Metadata Nodes static int countMetadataTargets(Module *Program) { - std::set UnnamedNodes; int NamedMetadataNodes = Program->named_metadata_size(); - // Get metadata nodes used by globals - for (auto &GV : Program->globals()) - addMetadataToSet(GV, UnnamedNodes); + // Get metadata attached to globals. + int GlobalMetadataArgs = 0; + SmallVector> MDs; + for (GlobalVariable &GV : Program->globals()) { + GV.getAllMetadata(MDs); + GlobalMetadataArgs += MDs.size(); + } - // Do the same for nodes used by functions & instructions - for (auto &F : *Program) { - addMetadataToSet(F, UnnamedNodes); - for (auto &BB : F) - for (auto &I : BB) - addMetadataToSet(I, UnnamedNodes); + // Get metadata attached to functions & instructions. + int FunctionMetadataArgs = 0; + int InstructionMetadataArgs = 0; + for (Function &F : *Program) { + F.getAllMetadata(MDs); + FunctionMetadataArgs += MDs.size(); + + for (Instruction &I : instructions(F)) { + I.getAllMetadata(MDs); + InstructionMetadataArgs += MDs.size(); + } } - return UnnamedNodes.size() + NamedMetadataNodes; + return NamedMetadataNodes + GlobalMetadataArgs + FunctionMetadataArgs + + InstructionMetadataArgs; } void llvm::reduceMetadataDeltaPass(TestRunner &Test) { -- 2.7.4