llvm-project/llvm/tools/llvm-reduce/deltas/ReduceDistinctMetadata.cpp
Kazu Hirata ef2531b63c
[llvm-reduce] Remove unused includes (NFC) (#141322)
These are identified by misc-include-cleaner.  I've filtered out those
that break builds.  Also, I'm staying away from llvm-config.h,
config.h, and Compiler.h, which likely cause platform- or
compiler-specific build failures.
2025-05-23 23:58:52 -07:00

134 lines
5.1 KiB
C++

//===- 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 "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallVector.h"
#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_or_null<MDNode>(CurrentNode->getOperand(I).get())) {
// Check whether node has been visited
if (VisitedNodes.insert(Operand))
NodesToTraverse.push(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_or_null<MDTuple>((*I))) {
if (VisitedNodes.insert(TupleI))
NodesToTraverse.push(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_or_null<MDTuple>(CurrentTuple->getOperand(I).get());
if (Operand && VisitedNodes.insert(Operand))
// If the node hasn't been traversed yet, add it to the queue of nodes
// to traverse.
NodesToTraverse.push(Operand);
}
}
}
void llvm::reduceDistinctMetadataDeltaPass(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_or_null<MDTuple>(NamedNode.getOperand(I)))
reduceNodes(Operand, NodesToDelete, TemporaryTuple, O, Program);
}
}
for (NamedMDNode &NamedNode : Program.named_metadata())
cleanUpTemporaries(NamedNode, TemporaryTuple, Program);
}