Skip to content

Commit 42067f2

Browse files
authored
[LLVM-Reduce] - Distinct Metadata Reduction (#104624)
1 parent b986438 commit 42067f2

8 files changed

+243
-10
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Helper script for distinct metadata reduction test
2+
3+
import sys
4+
import re
5+
6+
input = open(sys.argv[1], "r").read().splitlines()
7+
8+
depth_map = {"0": 1, "1": 3, "2": 3, "3": 2, "4": 1}
9+
10+
11+
for i in range(len(depth_map)):
12+
counter = 0
13+
for line in input:
14+
if re.match(rf".*interesting_{i}.*", line) != None:
15+
counter += 1
16+
if counter != depth_map[str(i)]:
17+
sys.exit(1)
18+
19+
sys.exit(0)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
; Test that every boring node is removed and all interesting distinct nodes remain after aggressive distinct metadata reduction.
2+
3+
; RUN: llvm-reduce --aggressive-named-md-reduction --test %python --test-arg %p/Inputs/reduce-distinct-metadata.py %s -o %t
4+
; RUN: FileCheck %s < %t
5+
6+
; CHECK-NOT: {{.*}}boring{{.*}}
7+
8+
define void @main() {
9+
ret void
10+
}
11+
12+
!named.metadata = !{!0, !2}
13+
!llvm.test.other.metadata = !{}
14+
15+
!0 = distinct !{!"interesting_0", !1, !3, !4, !10, !11}
16+
!1 = distinct !{!"interesting_1", !5, !7, !"something"}
17+
!2 = distinct !{!"boring_0", !3, !4, i32 5}
18+
!3 = distinct !{!"interesting_1", !3, !4}
19+
!4 = distinct !{!"interesting_1", !6, i2 1}
20+
!5 = distinct !{!"interesting_2", !8}
21+
!6 = distinct !{!"interesting_2", !10}
22+
!7 = distinct !{!"interesting_2", !12}
23+
!8 = distinct !{!"interesting_3", !10, !9}
24+
!9 = distinct !{!"interesting_3", !11, !13}
25+
!10 = distinct !{!"boring_1", i32 50}
26+
!11 = distinct !{!"boring_1", i32 2}
27+
!12 = distinct !{!"boring_3", i2 1}
28+
!13 = distinct !{!"interesting_4"}

llvm/test/tools/llvm-reduce/remove-metadata.ll

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
; Test that llvm-reduce can remove uninteresting metadata from an IR file.
22
; The Metadata pass erases named & unnamed metadata nodes.
33
;
4+
; RUN: llvm-reduce --aggressive-named-md-reduction --test %python --test-arg %p/Inputs/remove-metadata.py %s -o %t
5+
; RUN: FileCheck --check-prefixes=AGGRESSIVE --implicit-check-not=! %s < %t
6+
47
; RUN: llvm-reduce --test %python --test-arg %p/Inputs/remove-metadata.py %s -o %t
5-
; RUN: cat %t | FileCheck -implicit-check-not=! %s
8+
; RUN: FileCheck --implicit-check-not=! %s < %t
69

710
@global = global i32 0, !dbg !0
811

@@ -11,6 +14,7 @@ define void @main() !dbg !0 {
1114
}
1215

1316
!uninteresting = !{!0}
17+
; AGGRESSIVE: !interesting = !{}
1418
; CHECK: !interesting = !{!0}
1519
!interesting = !{!1}
1620

llvm/tools/llvm-reduce/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ add_llvm_tool(llvm-reduce
3131
deltas/ReduceAttributes.cpp
3232
deltas/ReduceBasicBlocks.cpp
3333
deltas/ReduceDIMetadata.cpp
34+
deltas/ReduceDistinctMetadata.cpp
3435
deltas/ReduceDbgRecords.cpp
3536
deltas/ReduceFunctionBodies.cpp
3637
deltas/ReduceFunctions.cpp

llvm/tools/llvm-reduce/DeltaManager.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "deltas/ReduceBasicBlocks.h"
2222
#include "deltas/ReduceDIMetadata.h"
2323
#include "deltas/ReduceDbgRecords.h"
24+
#include "deltas/ReduceDistinctMetadata.h"
2425
#include "deltas/ReduceFunctionBodies.h"
2526
#include "deltas/ReduceFunctions.h"
2627
#include "deltas/ReduceGlobalObjects.h"
@@ -93,6 +94,7 @@ static cl::list<std::string>
9394
DELTA_PASS("global-variables", reduceGlobalsDeltaPass) \
9495
DELTA_PASS("di-metadata", reduceDIMetadataDeltaPass) \
9596
DELTA_PASS("dbg-records", reduceDbgRecordDeltaPass) \
97+
DELTA_PASS("distinct-metadata", reduceDistinctMetadataDeltaPass) \
9698
DELTA_PASS("metadata", reduceMetadataDeltaPass) \
9799
DELTA_PASS("named-metadata", reduceNamedMetadataDeltaPass) \
98100
DELTA_PASS("arguments", reduceArgumentsDeltaPass) \
@@ -112,7 +114,7 @@ static cl::list<std::string>
112114
DELTA_PASS("atomic-ordering", reduceAtomicOrderingDeltaPass) \
113115
DELTA_PASS("syncscopes", reduceAtomicSyncScopesDeltaPass) \
114116
DELTA_PASS("instruction-flags", reduceInstructionFlagsDeltaPass) \
115-
} while (false)
117+
} while (false)
116118

117119
#define DELTA_PASSES_MIR \
118120
do { \
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
//===- ReduceDistinctMetadata.cpp - Specialized Delta Pass ----------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file implements two functions used by the Generic Delta Debugging
10+
// Algorithm, which are used to reduce unnamed distinct metadata nodes.
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#include "ReduceDistinctMetadata.h"
15+
#include "Delta.h"
16+
#include "llvm/ADT/Sequence.h"
17+
#include "llvm/ADT/SetVector.h"
18+
#include "llvm/ADT/SmallVector.h"
19+
#include "llvm/IR/InstIterator.h"
20+
#include <algorithm>
21+
#include <queue>
22+
23+
using namespace llvm;
24+
25+
// Traverse the graph breadth-first and try to remove unnamed metadata nodes
26+
static void
27+
reduceNodes(MDNode *Root,
28+
SetVector<std::pair<unsigned int, MDNode *>> &NodesToDelete,
29+
MDNode *TemporaryNode, Oracle &O, Module &Program) {
30+
std::queue<MDNode *> NodesToTraverse{};
31+
// Keep track of visited nodes not to get into loops
32+
SetVector<MDNode *> VisitedNodes{};
33+
NodesToTraverse.push(Root);
34+
35+
while (!NodesToTraverse.empty()) {
36+
MDNode *CurrentNode = NodesToTraverse.front();
37+
NodesToTraverse.pop();
38+
39+
// Mark the nodes for removal
40+
for (unsigned int I = 0; I < CurrentNode->getNumOperands(); ++I) {
41+
if (MDNode *Operand =
42+
dyn_cast<MDNode>(CurrentNode->getOperand(I).get())) {
43+
// Check whether node has been visited
44+
if (!VisitedNodes.contains(Operand)) {
45+
NodesToTraverse.push(Operand);
46+
VisitedNodes.insert(Operand);
47+
}
48+
// Delete the node only if it is distinct
49+
if (Operand->isDistinct()) {
50+
// Add to removal list
51+
NodesToDelete.insert(std::make_pair(I, CurrentNode));
52+
}
53+
}
54+
}
55+
56+
// Remove the nodes
57+
for (auto [PositionToReplace, Node] : NodesToDelete) {
58+
if (!O.shouldKeep())
59+
Node->replaceOperandWith(PositionToReplace, TemporaryNode);
60+
}
61+
NodesToDelete.clear();
62+
}
63+
}
64+
65+
// After reducing metadata, we need to remove references to the temporary node,
66+
// this is also done with BFS
67+
static void cleanUpTemporaries(NamedMDNode &NamedNode, MDTuple *TemporaryTuple,
68+
Module &Program) {
69+
std::queue<MDTuple *> NodesToTraverse{};
70+
SetVector<MDTuple *> VisitedNodes{};
71+
72+
// Push all first level operands of the named node to the queue
73+
for (auto I = NamedNode.op_begin(); I != NamedNode.op_end(); ++I) {
74+
// If the node hasn't been traversed yet, add it to the queue of nodes to
75+
// traverse.
76+
if (MDTuple *TupleI = dyn_cast<MDTuple>((*I))) {
77+
if (!VisitedNodes.contains(TupleI)) {
78+
NodesToTraverse.push(TupleI);
79+
VisitedNodes.insert(TupleI);
80+
}
81+
}
82+
}
83+
84+
while (!NodesToTraverse.empty()) {
85+
MDTuple *CurrentTuple = NodesToTraverse.front();
86+
NodesToTraverse.pop();
87+
88+
// Shift all of the interesting elements to the left, pop remaining
89+
// afterwards
90+
if (CurrentTuple->isDistinct()) {
91+
// Do resizing and cleaning operations only if the node is distinct,
92+
// as resizing is not supported for unique nodes and is redundant.
93+
unsigned int NotToRemove = 0;
94+
for (unsigned int I = 0; I < CurrentTuple->getNumOperands(); ++I) {
95+
Metadata *Operand = CurrentTuple->getOperand(I).get();
96+
// If current operand is not the temporary node, move it to the front
97+
// and increase notToRemove so that it will be saved
98+
if (Operand != TemporaryTuple) {
99+
Metadata *TemporaryMetadata =
100+
CurrentTuple->getOperand(NotToRemove).get();
101+
CurrentTuple->replaceOperandWith(NotToRemove, Operand);
102+
CurrentTuple->replaceOperandWith(I, TemporaryMetadata);
103+
++NotToRemove;
104+
}
105+
}
106+
107+
// Remove all the uninteresting elements
108+
unsigned int OriginalOperands = CurrentTuple->getNumOperands();
109+
for (unsigned int I = 0; I < OriginalOperands - NotToRemove; ++I)
110+
CurrentTuple->pop_back();
111+
}
112+
113+
// Push the remaining nodes into the queue
114+
for (unsigned int I = 0; I < CurrentTuple->getNumOperands(); ++I) {
115+
MDTuple *Operand = dyn_cast<MDTuple>(CurrentTuple->getOperand(I).get());
116+
if (Operand && !VisitedNodes.contains(Operand)) {
117+
NodesToTraverse.push(Operand);
118+
// If the node hasn't been traversed yet, add it to the queue of nodes
119+
// to traverse.
120+
VisitedNodes.insert(Operand);
121+
}
122+
}
123+
}
124+
}
125+
126+
static void extractDistinctMetadataFromModule(Oracle &O,
127+
ReducerWorkItem &WorkItem) {
128+
Module &Program = WorkItem.getModule();
129+
MDTuple *TemporaryTuple =
130+
MDTuple::getDistinct(Program.getContext(), SmallVector<Metadata *, 1>{});
131+
SetVector<std::pair<unsigned int, MDNode *>> NodesToDelete{};
132+
for (NamedMDNode &NamedNode :
133+
Program.named_metadata()) { // Iterate over the named nodes
134+
for (unsigned int I = 0; I < NamedNode.getNumOperands();
135+
++I) { // Iterate over first level unnamed nodes..
136+
if (MDTuple *Operand = dyn_cast<MDTuple>(NamedNode.getOperand(I)))
137+
reduceNodes(Operand, NodesToDelete, TemporaryTuple, O, Program);
138+
}
139+
}
140+
for (NamedMDNode &NamedNode : Program.named_metadata())
141+
cleanUpTemporaries(NamedNode, TemporaryTuple, Program);
142+
}
143+
144+
void llvm::reduceDistinctMetadataDeltaPass(TestRunner &Test) {
145+
runDeltaPass(Test, extractDistinctMetadataFromModule,
146+
"Reducing Distinct Metadata");
147+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//===- ReduceDistinctMetadata.h - Specialized Delta Pass ------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------------===//
8+
//
9+
// This file implements two functions used by the Generic Delta Debugging
10+
// Algorithm, which are used to reduce Metadata nodes.
11+
//
12+
//===----------------------------------------------------------------------------===//
13+
14+
#ifndef LLVM_TOOLS_LLVM_REDUCE_DELTAS_REDUCEDISTINCTMETADATA_H
15+
#define LLVM_TOOLS_LLVM_REDUCE_DELTAS_REDUCEDISTINCTMETADATA_H
16+
17+
#include "TestRunner.h"
18+
19+
namespace llvm {
20+
void reduceDistinctMetadataDeltaPass(TestRunner &Test);
21+
} // namespace llvm
22+
23+
#endif

llvm/tools/llvm-reduce/deltas/ReduceMetadata.cpp

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,13 @@
2020

2121
using namespace llvm;
2222

23+
extern cl::OptionCategory LLVMReduceOptions;
24+
25+
static cl::opt<bool> AggressiveMetadataReduction(
26+
"aggressive-named-md-reduction",
27+
cl::desc("Reduce named metadata without taking its type into account"),
28+
cl::cat(LLVMReduceOptions));
29+
2330
static bool shouldKeepDebugIntrinsicMetadata(Instruction &I, MDNode &MD) {
2431
return isa<DILocation>(MD) && isa<DbgInfoIntrinsic>(I);
2532
}
@@ -44,24 +51,26 @@ static constexpr StringLiteral ListNamedMetadata[] = {
4451
static void reduceNamedMetadataOperands(Oracle &O, ReducerWorkItem &WorkItem) {
4552
Module &M = WorkItem.getModule();
4653

47-
for (StringRef MDName : ListNamedMetadata) {
48-
NamedMDNode *NamedNode = M.getNamedMetadata(MDName);
49-
if (!NamedNode)
54+
for (NamedMDNode &I : M.named_metadata()) {
55+
// If we don't want to reduce mindlessly, check if our node is part of
56+
// ListNamedMetadata before reducing it
57+
if (!AggressiveMetadataReduction &&
58+
!is_contained(ListNamedMetadata, I.getName()))
5059
continue;
5160

5261
bool MadeChange = false;
53-
SmallVector<MDNode *, 16> KeptOperands;
54-
for (auto I : seq<unsigned>(0, NamedNode->getNumOperands())) {
62+
SmallVector<MDNode *> KeptOperands;
63+
for (auto J : seq<unsigned>(0, I.getNumOperands())) {
5564
if (O.shouldKeep())
56-
KeptOperands.push_back(NamedNode->getOperand(I));
65+
KeptOperands.push_back(I.getOperand(J));
5766
else
5867
MadeChange = true;
5968
}
6069

6170
if (MadeChange) {
62-
NamedNode->clearOperands();
71+
I.clearOperands();
6372
for (MDNode *KeptOperand : KeptOperands)
64-
NamedNode->addOperand(KeptOperand);
73+
I.addOperand(KeptOperand);
6574
}
6675
}
6776
}

0 commit comments

Comments
 (0)