[llvm] 42067f2 - [LLVM-Reduce] - Distinct Metadata Reduction (#104624)

via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 20 03:34:45 PDT 2024


Author: Robert Barinov
Date: 2024-08-20T14:34:41+04:00
New Revision: 42067f26cd084d29fdd08a75a36b8785ae9f3982

URL: https://github.com/llvm/llvm-project/commit/42067f26cd084d29fdd08a75a36b8785ae9f3982
DIFF: https://github.com/llvm/llvm-project/commit/42067f26cd084d29fdd08a75a36b8785ae9f3982.diff

LOG: [LLVM-Reduce] - Distinct Metadata Reduction (#104624)

Added: 
    llvm/test/tools/llvm-reduce/Inputs/reduce-distinct-metadata.py
    llvm/test/tools/llvm-reduce/reduce-distinct-metadata.ll
    llvm/tools/llvm-reduce/deltas/ReduceDistinctMetadata.cpp
    llvm/tools/llvm-reduce/deltas/ReduceDistinctMetadata.h

Modified: 
    llvm/test/tools/llvm-reduce/remove-metadata.ll
    llvm/tools/llvm-reduce/CMakeLists.txt
    llvm/tools/llvm-reduce/DeltaManager.cpp
    llvm/tools/llvm-reduce/deltas/ReduceMetadata.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/test/tools/llvm-reduce/Inputs/reduce-distinct-metadata.py b/llvm/test/tools/llvm-reduce/Inputs/reduce-distinct-metadata.py
new file mode 100644
index 00000000000000..155031ab5d8aa7
--- /dev/null
+++ b/llvm/test/tools/llvm-reduce/Inputs/reduce-distinct-metadata.py
@@ -0,0 +1,19 @@
+# Helper script for distinct metadata reduction test
+
+import sys
+import re
+
+input = open(sys.argv[1], "r").read().splitlines()
+
+depth_map = {"0": 1, "1": 3, "2": 3, "3": 2, "4": 1}
+
+
+for i in range(len(depth_map)):
+    counter = 0
+    for line in input:
+        if re.match(rf".*interesting_{i}.*", line) != None:
+            counter += 1
+    if counter != depth_map[str(i)]:
+        sys.exit(1)
+
+sys.exit(0)

diff  --git a/llvm/test/tools/llvm-reduce/reduce-distinct-metadata.ll b/llvm/test/tools/llvm-reduce/reduce-distinct-metadata.ll
new file mode 100644
index 00000000000000..4f51e78c63821c
--- /dev/null
+++ b/llvm/test/tools/llvm-reduce/reduce-distinct-metadata.ll
@@ -0,0 +1,28 @@
+; Test that every boring node is removed and all interesting distinct nodes remain after aggressive distinct metadata reduction.
+
+; RUN: llvm-reduce --aggressive-named-md-reduction --test %python --test-arg %p/Inputs/reduce-distinct-metadata.py %s -o %t
+; RUN: FileCheck %s < %t
+
+; CHECK-NOT: {{.*}}boring{{.*}}
+
+define void @main() {
+  ret void
+}
+
+!named.metadata = !{!0, !2}
+!llvm.test.other.metadata = !{}
+
+!0 = distinct !{!"interesting_0", !1, !3, !4, !10, !11}
+!1 = distinct !{!"interesting_1", !5, !7, !"something"}
+!2 = distinct !{!"boring_0", !3, !4, i32 5}
+!3 = distinct !{!"interesting_1", !3, !4}
+!4 = distinct !{!"interesting_1", !6, i2 1}
+!5 = distinct !{!"interesting_2", !8}
+!6 = distinct !{!"interesting_2", !10}
+!7 = distinct !{!"interesting_2", !12}
+!8 = distinct !{!"interesting_3", !10, !9}
+!9 = distinct !{!"interesting_3", !11, !13}
+!10 = distinct !{!"boring_1", i32 50}
+!11 = distinct !{!"boring_1", i32 2}
+!12 = distinct !{!"boring_3", i2 1}
+!13 = distinct !{!"interesting_4"}

diff  --git a/llvm/test/tools/llvm-reduce/remove-metadata.ll b/llvm/test/tools/llvm-reduce/remove-metadata.ll
index 51a50ca20a9854..2401201c2947ba 100644
--- a/llvm/test/tools/llvm-reduce/remove-metadata.ll
+++ b/llvm/test/tools/llvm-reduce/remove-metadata.ll
@@ -1,8 +1,11 @@
 ; Test that llvm-reduce can remove uninteresting metadata from an IR file.
 ; The Metadata pass erases named & unnamed metadata nodes.
 ;
+; RUN: llvm-reduce --aggressive-named-md-reduction --test %python --test-arg %p/Inputs/remove-metadata.py %s -o %t
+; RUN: FileCheck --check-prefixes=AGGRESSIVE --implicit-check-not=! %s < %t 
+
 ; RUN: llvm-reduce --test %python --test-arg %p/Inputs/remove-metadata.py %s -o %t
-; RUN: cat %t | FileCheck -implicit-check-not=! %s
+; RUN: FileCheck --implicit-check-not=! %s < %t
 
 @global = global i32 0, !dbg !0
 
@@ -11,6 +14,7 @@ define void @main() !dbg !0 {
 }
 
 !uninteresting = !{!0}
+; AGGRESSIVE: !interesting = !{}
 ; CHECK: !interesting = !{!0}
 !interesting = !{!1}
 

diff  --git a/llvm/tools/llvm-reduce/CMakeLists.txt b/llvm/tools/llvm-reduce/CMakeLists.txt
index a4c605fcd2443c..b8ad6f71b41e59 100644
--- a/llvm/tools/llvm-reduce/CMakeLists.txt
+++ b/llvm/tools/llvm-reduce/CMakeLists.txt
@@ -31,6 +31,7 @@ add_llvm_tool(llvm-reduce
   deltas/ReduceAttributes.cpp
   deltas/ReduceBasicBlocks.cpp
   deltas/ReduceDIMetadata.cpp
+  deltas/ReduceDistinctMetadata.cpp
   deltas/ReduceDbgRecords.cpp
   deltas/ReduceFunctionBodies.cpp
   deltas/ReduceFunctions.cpp

diff  --git a/llvm/tools/llvm-reduce/DeltaManager.cpp b/llvm/tools/llvm-reduce/DeltaManager.cpp
index 67fbc2fdc7ad43..624b5306bc71be 100644
--- a/llvm/tools/llvm-reduce/DeltaManager.cpp
+++ b/llvm/tools/llvm-reduce/DeltaManager.cpp
@@ -21,6 +21,7 @@
 #include "deltas/ReduceBasicBlocks.h"
 #include "deltas/ReduceDIMetadata.h"
 #include "deltas/ReduceDbgRecords.h"
+#include "deltas/ReduceDistinctMetadata.h"
 #include "deltas/ReduceFunctionBodies.h"
 #include "deltas/ReduceFunctions.h"
 #include "deltas/ReduceGlobalObjects.h"
@@ -93,6 +94,7 @@ static cl::list<std::string>
     DELTA_PASS("global-variables", reduceGlobalsDeltaPass)                     \
     DELTA_PASS("di-metadata", reduceDIMetadataDeltaPass)                       \
     DELTA_PASS("dbg-records", reduceDbgRecordDeltaPass)                        \
+    DELTA_PASS("distinct-metadata", reduceDistinctMetadataDeltaPass)           \
     DELTA_PASS("metadata", reduceMetadataDeltaPass)                            \
     DELTA_PASS("named-metadata", reduceNamedMetadataDeltaPass)                 \
     DELTA_PASS("arguments", reduceArgumentsDeltaPass)                          \
@@ -112,7 +114,7 @@ static cl::list<std::string>
     DELTA_PASS("atomic-ordering", reduceAtomicOrderingDeltaPass)               \
     DELTA_PASS("syncscopes", reduceAtomicSyncScopesDeltaPass)                  \
     DELTA_PASS("instruction-flags", reduceInstructionFlagsDeltaPass)           \
-} while (false)
+  } while (false)
 
 #define DELTA_PASSES_MIR                                                       \
   do {                                                                         \

diff  --git a/llvm/tools/llvm-reduce/deltas/ReduceDistinctMetadata.cpp b/llvm/tools/llvm-reduce/deltas/ReduceDistinctMetadata.cpp
new file mode 100644
index 00000000000000..32fca80b5e5d60
--- /dev/null
+++ b/llvm/tools/llvm-reduce/deltas/ReduceDistinctMetadata.cpp
@@ -0,0 +1,147 @@
+//===- ReduceDistinctMetadata.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 unnamed distinct metadata nodes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ReduceDistinctMetadata.h"
+#include "Delta.h"
+#include "llvm/ADT/Sequence.h"
+#include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/IR/InstIterator.h"
+#include <algorithm>
+#include <queue>
+
+using namespace llvm;
+
+// Traverse the graph breadth-first and try to remove unnamed metadata nodes
+static void
+reduceNodes(MDNode *Root,
+            SetVector<std::pair<unsigned int, MDNode *>> &NodesToDelete,
+            MDNode *TemporaryNode, Oracle &O, Module &Program) {
+  std::queue<MDNode *> NodesToTraverse{};
+  // Keep track of visited nodes not to get into loops
+  SetVector<MDNode *> VisitedNodes{};
+  NodesToTraverse.push(Root);
+
+  while (!NodesToTraverse.empty()) {
+    MDNode *CurrentNode = NodesToTraverse.front();
+    NodesToTraverse.pop();
+
+    // Mark the nodes for removal
+    for (unsigned int I = 0; I < CurrentNode->getNumOperands(); ++I) {
+      if (MDNode *Operand =
+              dyn_cast<MDNode>(CurrentNode->getOperand(I).get())) {
+        // Check whether node has been visited
+        if (!VisitedNodes.contains(Operand)) {
+          NodesToTraverse.push(Operand);
+          VisitedNodes.insert(Operand);
+        }
+        // Delete the node only if it is distinct
+        if (Operand->isDistinct()) {
+          // Add to removal list
+          NodesToDelete.insert(std::make_pair(I, CurrentNode));
+        }
+      }
+    }
+
+    // Remove the nodes
+    for (auto [PositionToReplace, Node] : NodesToDelete) {
+      if (!O.shouldKeep())
+        Node->replaceOperandWith(PositionToReplace, TemporaryNode);
+    }
+    NodesToDelete.clear();
+  }
+}
+
+// After reducing metadata, we need to remove references to the temporary node,
+// this is also done with BFS
+static void cleanUpTemporaries(NamedMDNode &NamedNode, MDTuple *TemporaryTuple,
+                               Module &Program) {
+  std::queue<MDTuple *> NodesToTraverse{};
+  SetVector<MDTuple *> VisitedNodes{};
+
+  // Push all first level operands of the named node to the queue
+  for (auto I = NamedNode.op_begin(); I != NamedNode.op_end(); ++I) {
+    // If the node hasn't been traversed yet, add it to the queue of nodes to
+    // traverse.
+    if (MDTuple *TupleI = dyn_cast<MDTuple>((*I))) {
+      if (!VisitedNodes.contains(TupleI)) {
+        NodesToTraverse.push(TupleI);
+        VisitedNodes.insert(TupleI);
+      }
+    }
+  }
+
+  while (!NodesToTraverse.empty()) {
+    MDTuple *CurrentTuple = NodesToTraverse.front();
+    NodesToTraverse.pop();
+
+    // Shift all of the interesting elements to the left, pop remaining
+    // afterwards
+    if (CurrentTuple->isDistinct()) {
+      // Do resizing and cleaning operations only if the node is distinct,
+      // as resizing is not supported for unique nodes and is redundant.
+      unsigned int NotToRemove = 0;
+      for (unsigned int I = 0; I < CurrentTuple->getNumOperands(); ++I) {
+        Metadata *Operand = CurrentTuple->getOperand(I).get();
+        // If current operand is not the temporary node, move it to the front
+        // and increase notToRemove so that it will be saved
+        if (Operand != TemporaryTuple) {
+          Metadata *TemporaryMetadata =
+              CurrentTuple->getOperand(NotToRemove).get();
+          CurrentTuple->replaceOperandWith(NotToRemove, Operand);
+          CurrentTuple->replaceOperandWith(I, TemporaryMetadata);
+          ++NotToRemove;
+        }
+      }
+
+      // Remove all the uninteresting elements
+      unsigned int OriginalOperands = CurrentTuple->getNumOperands();
+      for (unsigned int I = 0; I < OriginalOperands - NotToRemove; ++I)
+        CurrentTuple->pop_back();
+    }
+
+    // Push the remaining nodes into the queue
+    for (unsigned int I = 0; I < CurrentTuple->getNumOperands(); ++I) {
+      MDTuple *Operand = dyn_cast<MDTuple>(CurrentTuple->getOperand(I).get());
+      if (Operand && !VisitedNodes.contains(Operand)) {
+        NodesToTraverse.push(Operand);
+        // If the node hasn't been traversed yet, add it to the queue of nodes
+        // to traverse.
+        VisitedNodes.insert(Operand);
+      }
+    }
+  }
+}
+
+static void extractDistinctMetadataFromModule(Oracle &O,
+                                              ReducerWorkItem &WorkItem) {
+  Module &Program = WorkItem.getModule();
+  MDTuple *TemporaryTuple =
+      MDTuple::getDistinct(Program.getContext(), SmallVector<Metadata *, 1>{});
+  SetVector<std::pair<unsigned int, MDNode *>> NodesToDelete{};
+  for (NamedMDNode &NamedNode :
+       Program.named_metadata()) { // Iterate over the named nodes
+    for (unsigned int I = 0; I < NamedNode.getNumOperands();
+         ++I) { // Iterate over first level unnamed nodes..
+      if (MDTuple *Operand = dyn_cast<MDTuple>(NamedNode.getOperand(I)))
+        reduceNodes(Operand, NodesToDelete, TemporaryTuple, O, Program);
+    }
+  }
+  for (NamedMDNode &NamedNode : Program.named_metadata())
+    cleanUpTemporaries(NamedNode, TemporaryTuple, Program);
+}
+
+void llvm::reduceDistinctMetadataDeltaPass(TestRunner &Test) {
+  runDeltaPass(Test, extractDistinctMetadataFromModule,
+               "Reducing Distinct Metadata");
+}

diff  --git a/llvm/tools/llvm-reduce/deltas/ReduceDistinctMetadata.h b/llvm/tools/llvm-reduce/deltas/ReduceDistinctMetadata.h
new file mode 100644
index 00000000000000..d02e8e6107b756
--- /dev/null
+++ b/llvm/tools/llvm-reduce/deltas/ReduceDistinctMetadata.h
@@ -0,0 +1,23 @@
+//===- ReduceDistinctMetadata.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_REDUCEDISTINCTMETADATA_H
+#define LLVM_TOOLS_LLVM_REDUCE_DELTAS_REDUCEDISTINCTMETADATA_H
+
+#include "TestRunner.h"
+
+namespace llvm {
+void reduceDistinctMetadataDeltaPass(TestRunner &Test);
+} // namespace llvm
+
+#endif

diff  --git a/llvm/tools/llvm-reduce/deltas/ReduceMetadata.cpp b/llvm/tools/llvm-reduce/deltas/ReduceMetadata.cpp
index 30bf612fe9694f..316c74876025a5 100644
--- a/llvm/tools/llvm-reduce/deltas/ReduceMetadata.cpp
+++ b/llvm/tools/llvm-reduce/deltas/ReduceMetadata.cpp
@@ -20,6 +20,13 @@
 
 using namespace llvm;
 
+extern cl::OptionCategory LLVMReduceOptions;
+
+static cl::opt<bool> AggressiveMetadataReduction(
+    "aggressive-named-md-reduction",
+    cl::desc("Reduce named metadata without taking its type into account"),
+    cl::cat(LLVMReduceOptions));
+
 static bool shouldKeepDebugIntrinsicMetadata(Instruction &I, MDNode &MD) {
   return isa<DILocation>(MD) && isa<DbgInfoIntrinsic>(I);
 }
@@ -44,24 +51,26 @@ static constexpr StringLiteral ListNamedMetadata[] = {
 static void reduceNamedMetadataOperands(Oracle &O, ReducerWorkItem &WorkItem) {
   Module &M = WorkItem.getModule();
 
-  for (StringRef MDName : ListNamedMetadata) {
-    NamedMDNode *NamedNode = M.getNamedMetadata(MDName);
-    if (!NamedNode)
+  for (NamedMDNode &I : M.named_metadata()) {
+    // If we don't want to reduce mindlessly, check if our node is part of
+    // ListNamedMetadata before reducing it
+    if (!AggressiveMetadataReduction &&
+        !is_contained(ListNamedMetadata, I.getName()))
       continue;
 
     bool MadeChange = false;
-    SmallVector<MDNode *, 16> KeptOperands;
-    for (auto I : seq<unsigned>(0, NamedNode->getNumOperands())) {
+    SmallVector<MDNode *> KeptOperands;
+    for (auto J : seq<unsigned>(0, I.getNumOperands())) {
       if (O.shouldKeep())
-        KeptOperands.push_back(NamedNode->getOperand(I));
+        KeptOperands.push_back(I.getOperand(J));
       else
         MadeChange = true;
     }
 
     if (MadeChange) {
-      NamedNode->clearOperands();
+      I.clearOperands();
       for (MDNode *KeptOperand : KeptOperands)
-        NamedNode->addOperand(KeptOperand);
+        I.addOperand(KeptOperand);
     }
   }
 }


        


More information about the llvm-commits mailing list