[llvm] [LLVM-Reduce] - Distinct Metadata Reduction (PR #96072)
Michal Paszkowski via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 20 03:39:00 PDT 2024
================
@@ -0,0 +1,146 @@
+//===- 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/SmallVector.h"
+#include "llvm/IR/InstIterator.h"
+#include <algorithm>
+#include <queue>
+#include <set>
+
+using namespace llvm;
+
+// Traverse the graph breadth-first and try to remove unnamed metadata nodes
+void BFS_removal(MDNode *root,
+ std::set<std::pair<unsigned int, MDNode *>> &nodesToDelete,
+ MDNode *tmp, Oracle &O, Module &Program) {
+ std::queue<MDNode *> q{};
+ std::set<MDNode *>
+ visited{}; // Keep track of visited nodes not to get into loops
+ q.push(root);
+
+ while (!q.empty()) {
+ MDNode *current = q.front();
+ q.pop();
+
+ // Mark the nodes for removal
+ for (unsigned int i = 0; i < current->getNumOperands(); ++i) {
+ Metadata *operand = current->getOperand(i).get();
+ if (isa_and_nonnull<MDNode>(operand)) {
+ if (std::find(visited.begin(), visited.end(), operand) ==
+ visited.end()) { // Check whether node has been visited
+ q.push(static_cast<MDNode *>(operand));
+ visited.insert(static_cast<MDNode *>(operand));
+ }
+ // Delete the node only if it is distinct
+ if (static_cast<MDNode *>(operand)->isDistinct())
+ nodesToDelete.insert(
+ std::make_pair(i, current)); // Add to removal list
+ }
+ }
+
+ // Remove the nodes
+ for (std::pair<unsigned int, MDNode *> node : nodesToDelete) {
+ if (!O.shouldKeep())
+ node.second->replaceOperandWith(node.first, tmp);
+ }
+ nodesToDelete.clear();
+ }
+}
+
+// After reducing metadata, we need to remove references to the temporary node,
+// this is also done with BFS
+void cleanup(NamedMDNode &namedNode, MDTuple *tmp, Module &Program) {
+ std::queue<MDTuple *> q{};
+ std::set<MDTuple *> visited{};
+
+ // 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 (std::find(visited.begin(), visited.end(), *i) == visited.end()) {
+ q.push(static_cast<MDTuple *>(*i));
+ visited.insert(static_cast<MDTuple *>(*i));
+ }
+ }
+
+ while (!q.empty()) {
+ MDTuple *current = q.front();
+ q.pop();
+
+ // Shift all of the interesting elements to the left, pop remaining
+ // afterwards
+ if (current->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 < current->getNumOperands(); ++i) {
+ Metadata *operand = current->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 != tmp) {
+ Metadata *temporary = current->getOperand(notToRemove).get();
+ current->replaceOperandWith(notToRemove, operand);
+ current->replaceOperandWith(i, temporary);
+ ++notToRemove;
+ }
+ }
+
+ // Remove all the uninteresting elements
+ unsigned int originalOperands = current->getNumOperands();
+ for (unsigned int i = 0; i < originalOperands - notToRemove; ++i)
+ current->pop_back();
+ }
+
+ // Push the remaining nodes into the queue
+ for (unsigned int i = 0; i < current->getNumOperands(); ++i) {
+ Metadata *operand = current->getOperand(i).get();
+ if (isa_and_nonnull<MDTuple>(operand) &&
+ std::find(visited.begin(), visited.end(), operand) == visited.end()) {
+ q.push(static_cast<MDTuple *>(operand));
+ visited.insert(static_cast<MDTuple *>(
+ operand)); // If the node hasn't been traversed yet, add it to the
+ // queue of nodes to traverse.
+ }
+ }
+ }
+}
+
+static void extractDistinctMetadataFromModule(Oracle &O,
+ ReducerWorkItem &WorkItem) {
+ Module &Program = WorkItem.getModule();
+ MDTuple *tmp = MDTuple::getDistinct(
+ Program.getContext(), SmallVector<Metadata *, 1>{llvm::MDString::get(
+ Program.getContext(), "temporary_node")});
+ std::set<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..
+ Metadata *operand = namedNode.getOperand(i);
+ if (isa_and_nonnull<MDTuple>(operand))
+ BFS_removal(static_cast<MDTuple *>(operand), nodesToDelete, tmp, O,
+ Program);
+ }
+ }
+ for (NamedMDNode &namedNode : Program.named_metadata())
+ cleanup(namedNode, tmp, Program);
+}
+
+void llvm::reduceDistinctMetadataDeltaPass(TestRunner &Test) {
+ runDeltaPass(Test, extractDistinctMetadataFromModule,
+ "Reducing Distinct Metadata");
+}
----------------
michalpaszkowski wrote:
Please add new lines at the end of files
https://github.com/llvm/llvm-project/pull/96072
More information about the llvm-commits
mailing list