Skip to content

Commit 34ca831

Browse files
committed
[bugpoint] Add a named metadata (+their operands) reducer
Summary: We frequently run bugpoint on a linked module that consists of all modules we create while jitting the julia standard library. This module has a very large number of compile units (10000+) in `llvm.dbg.cu`, which didn't get reduced at all, requiring manual post processing. This is an attempt to have bugpoint go through and attempt to reduce the number of global named metadata nodes as well as their operands, to cut down the number of roots for such metadata. Reviewers: dexonsmith, reames, pete Subscribers: pete, dexonsmith, reames, llvm-commits Differential Revision: http://reviews.llvm.org/D14043 llvm-svn: 252247
1 parent 6efa6fb commit 34ca831

File tree

3 files changed

+252
-13
lines changed

3 files changed

+252
-13
lines changed

llvm/test/BugPoint/named-md.ll

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
; RUN: bugpoint -load %llvmshlibdir/BugpointPasses%shlibext %s -output-prefix %t -bugpoint-crash-too-many-cus -silence-passes > /dev/null
2+
; RUN: llvm-dis %t-reduced-simplified.bc -o - | FileCheck %s
3+
; RUN-DISABLE: bugpoint -disable-namedmd-remove -load %llvmshlibdir/BugpointPasses%shlibext %s -output-prefix %t -bugpoint-crash-too-many-cus -silence-passes > /dev/null
4+
; RUN-DISABLE: llvm-dis %t-reduced-simplified.bc -o - | FileCheck %s
5+
; REQUIRES: loadable_module
6+
7+
; CHECK: !llvm.dbg.cu = !{![[FIRST:[0-9]+]], ![[SECOND:[0-9]+]]}
8+
; CHECK-DISABLE: !llvm.dbg.cu = !{![[FIRST:[0-9]+]], ![[SECOND:[0-9]+]],
9+
; CHECK-DISABLE-SAME: ![[THIRD:[0-9]+]], ![[FOURTH:[0-9]+]], ![[FIFTH:[0-9]+]]}
10+
!llvm.dbg.cu = !{!0, !1, !2, !3, !4, !5}
11+
; CHECK-NOT: !named
12+
; CHECK-DISABLE: !named
13+
!named = !{!0, !1, !2, !3, !4, !5}
14+
; CHECK: !llvm.module.flags = !{![[DIVERSION:[0-9]+]]}
15+
!llvm.module.flags = !{!6, !7}
16+
17+
; CHECK-DAG: ![[FIRST]] = distinct !DICompileUnit(language: DW_LANG_Julia,
18+
; CHECK-DAG: ![[SECOND]] = distinct !DICompileUnit(language: DW_LANG_Julia,
19+
; CHECK-DAG: ![[DIVERSION]] = !{i32 2, !"Debug Info Version", i32 3}
20+
; CHECK-DAG: !DIFile(filename: "a", directory: "b")
21+
22+
; 4 nodes survive. Due to renumbering !4 should not exist
23+
; CHECK-NOT: !4
24+
25+
!0 = distinct !DICompileUnit(language: DW_LANG_Julia,
26+
file: !8)
27+
!1 = distinct !DICompileUnit(language: DW_LANG_Julia,
28+
file: !8)
29+
!2 = distinct !DICompileUnit(language: DW_LANG_Julia,
30+
file: !8)
31+
!3 = distinct !DICompileUnit(language: DW_LANG_Julia,
32+
file: !8)
33+
!4 = distinct !DICompileUnit(language: DW_LANG_Julia,
34+
file: !8)
35+
!5 = distinct !DICompileUnit(language: DW_LANG_Julia,
36+
file: !8)
37+
!6 = !{i32 2, !"Dwarf Version", i32 2}
38+
!7 = !{i32 2, !"Debug Info Version", i32 3}
39+
!8 = !DIFile(filename: "a", directory: "b")

llvm/tools/bugpoint-passes/TestPasses.cpp

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -76,24 +76,51 @@ static RegisterPass<DeleteCalls>
7676

7777
namespace {
7878
/// CrashOnDeclFunc - This pass is used to test bugpoint. It intentionally
79-
/// crash if the module has an undefined function (ie a function that is
80-
/// defined in an external module).
81-
class CrashOnDeclFunc : public ModulePass {
82-
public:
83-
static char ID; // Pass ID, replacement for typeid
84-
CrashOnDeclFunc() : ModulePass(ID) {}
85-
private:
86-
bool runOnModule(Module &M) override {
87-
for (auto &F : M.functions()) {
88-
if (F.isDeclaration())
89-
abort();
90-
}
91-
return false;
79+
/// crashes if the module has an undefined function (ie a function that is
80+
/// defined in an external module).
81+
class CrashOnDeclFunc : public ModulePass {
82+
public:
83+
static char ID; // Pass ID, replacement for typeid
84+
CrashOnDeclFunc() : ModulePass(ID) {}
85+
86+
private:
87+
bool runOnModule(Module &M) override {
88+
for (auto &F : M.functions()) {
89+
if (F.isDeclaration())
90+
abort();
9291
}
92+
return false;
93+
}
9394
};
9495
}
9596

9697
char CrashOnDeclFunc::ID = 0;
9798
static RegisterPass<CrashOnDeclFunc>
9899
Z("bugpoint-crash-decl-funcs",
99100
"BugPoint Test Pass - Intentionally crash on declared functions");
101+
102+
#include <iostream>
103+
namespace {
104+
/// CrashOnOneCU - This pass is used to test bugpoint. It intentionally
105+
/// crashes if the Module has two or more compile units
106+
class CrashOnTooManyCUs : public ModulePass {
107+
public:
108+
static char ID;
109+
CrashOnTooManyCUs() : ModulePass(ID) {}
110+
111+
private:
112+
bool runOnModule(Module &M) override {
113+
NamedMDNode *CU_Nodes = M.getNamedMetadata("llvm.dbg.cu");
114+
if (!CU_Nodes)
115+
return false;
116+
if (CU_Nodes->getNumOperands() >= 2)
117+
abort();
118+
return false;
119+
}
120+
};
121+
}
122+
123+
char CrashOnTooManyCUs::ID = 0;
124+
static RegisterPass<CrashOnTooManyCUs>
125+
A("bugpoint-crash-too-many-cus",
126+
"BugPoint Test Pass - Intentionally crash on too many CUs");

llvm/tools/bugpoint/CrashDebugger.cpp

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "ListReducer.h"
1616
#include "ToolRunner.h"
1717
#include "llvm/ADT/SmallPtrSet.h"
18+
#include "llvm/ADT/StringSet.h"
1819
#include "llvm/IR/CFG.h"
1920
#include "llvm/IR/Constants.h"
2021
#include "llvm/IR/DerivedTypes.h"
@@ -49,6 +50,10 @@ namespace {
4950
DontReducePassList("disable-pass-list-reduction",
5051
cl::desc("Skip pass list reduction steps"),
5152
cl::init(false));
53+
54+
cl::opt<bool> NoNamedMDRM("disable-namedmd-remove",
55+
cl::desc("Do not remove global named metadata"),
56+
cl::init(false));
5257
}
5358

5459
namespace llvm {
@@ -497,6 +502,149 @@ bool ReduceCrashingInstructions::TestInsts(std::vector<const Instruction*>
497502
return false;
498503
}
499504

505+
namespace {
506+
// Reduce the list of Named Metadata nodes. We keep this as a list of
507+
// names to avoid having to convert back and forth every time.
508+
class ReduceCrashingNamedMD : public ListReducer<std::string> {
509+
BugDriver &BD;
510+
bool (*TestFn)(const BugDriver &, Module *);
511+
512+
public:
513+
ReduceCrashingNamedMD(BugDriver &bd,
514+
bool (*testFn)(const BugDriver &, Module *))
515+
: BD(bd), TestFn(testFn) {}
516+
517+
TestResult doTest(std::vector<std::string> &Prefix,
518+
std::vector<std::string> &Kept,
519+
std::string &Error) override {
520+
if (!Kept.empty() && TestNamedMDs(Kept))
521+
return KeepSuffix;
522+
if (!Prefix.empty() && TestNamedMDs(Prefix))
523+
return KeepPrefix;
524+
return NoFailure;
525+
}
526+
527+
bool TestNamedMDs(std::vector<std::string> &NamedMDs);
528+
};
529+
}
530+
531+
bool ReduceCrashingNamedMD::TestNamedMDs(std::vector<std::string> &NamedMDs) {
532+
533+
ValueToValueMapTy VMap;
534+
Module *M = CloneModule(BD.getProgram(), VMap);
535+
536+
outs() << "Checking for crash with only these named metadata nodes:";
537+
unsigned NumPrint = std::min<size_t>(NamedMDs.size(), 10);
538+
for (unsigned i = 0, e = NumPrint; i != e; ++i)
539+
outs() << " " << NamedMDs[i];
540+
if (NumPrint < NamedMDs.size())
541+
outs() << "... <" << NamedMDs.size() << " total>";
542+
outs() << ": ";
543+
544+
// Make a StringMap for faster lookup
545+
StringSet<> Names;
546+
for (const std::string &Name : NamedMDs)
547+
Names.insert(Name);
548+
549+
// First collect all the metadata to delete in a vector, then
550+
// delete them all at once to avoid invalidating the iterator
551+
std::vector<NamedMDNode *> ToDelete;
552+
ToDelete.reserve(M->named_metadata_size() - Names.size());
553+
for (auto &NamedMD : M->named_metadata())
554+
if (!Names.count(NamedMD.getName()))
555+
ToDelete.push_back(&NamedMD);
556+
557+
for (auto *NamedMD : ToDelete)
558+
NamedMD->eraseFromParent();
559+
560+
// Verify that this is still valid.
561+
legacy::PassManager Passes;
562+
Passes.add(createVerifierPass());
563+
Passes.run(*M);
564+
565+
// Try running on the hacked up program...
566+
if (TestFn(BD, M)) {
567+
BD.setNewProgram(M); // It crashed, keep the trimmed version...
568+
return true;
569+
}
570+
delete M; // It didn't crash, try something else.
571+
return false;
572+
}
573+
574+
namespace {
575+
// Reduce the list of operands to named metadata nodes
576+
class ReduceCrashingNamedMDOps : public ListReducer<const MDNode *> {
577+
BugDriver &BD;
578+
bool (*TestFn)(const BugDriver &, Module *);
579+
580+
public:
581+
ReduceCrashingNamedMDOps(BugDriver &bd,
582+
bool (*testFn)(const BugDriver &, Module *))
583+
: BD(bd), TestFn(testFn) {}
584+
585+
TestResult doTest(std::vector<const MDNode *> &Prefix,
586+
std::vector<const MDNode *> &Kept,
587+
std::string &Error) override {
588+
if (!Kept.empty() && TestNamedMDOps(Kept))
589+
return KeepSuffix;
590+
if (!Prefix.empty() && TestNamedMDOps(Prefix))
591+
return KeepPrefix;
592+
return NoFailure;
593+
}
594+
595+
bool TestNamedMDOps(std::vector<const MDNode *> &NamedMDOps);
596+
};
597+
}
598+
599+
bool ReduceCrashingNamedMDOps::TestNamedMDOps(
600+
std::vector<const MDNode *> &NamedMDOps) {
601+
// Convert list to set for fast lookup...
602+
SmallPtrSet<const MDNode *, 64> OldMDNodeOps;
603+
for (unsigned i = 0, e = NamedMDOps.size(); i != e; ++i) {
604+
OldMDNodeOps.insert(NamedMDOps[i]);
605+
}
606+
607+
outs() << "Checking for crash with only " << OldMDNodeOps.size();
608+
if (OldMDNodeOps.size() == 1)
609+
outs() << " named metadata operand: ";
610+
else
611+
outs() << " named metadata operands: ";
612+
613+
ValueToValueMapTy VMap;
614+
Module *M = CloneModule(BD.getProgram(), VMap);
615+
616+
// This is a little wasteful. In the future it might be good if we could have
617+
// these dropped during cloning.
618+
for (auto &NamedMD : BD.getProgram()->named_metadata()) {
619+
// Drop the old one and create a new one
620+
M->eraseNamedMetadata(M->getNamedMetadata(NamedMD.getName()));
621+
NamedMDNode *NewNamedMDNode =
622+
M->getOrInsertNamedMetadata(NamedMD.getName());
623+
for (MDNode *op : NamedMD.operands())
624+
if (OldMDNodeOps.count(op))
625+
NewNamedMDNode->addOperand(cast<MDNode>(MapMetadata(op, VMap)));
626+
}
627+
628+
// Verify that this is still valid.
629+
legacy::PassManager Passes;
630+
Passes.add(createVerifierPass());
631+
Passes.run(*M);
632+
633+
// Try running on the hacked up program...
634+
if (TestFn(BD, M)) {
635+
// Make sure to use instruction pointers that point into the now-current
636+
// module, and that they don't include any deleted blocks.
637+
NamedMDOps.clear();
638+
for (const MDNode *Node : OldMDNodeOps)
639+
NamedMDOps.push_back(cast<MDNode>(VMap.MD()[Node].get()));
640+
641+
BD.setNewProgram(M); // It crashed, keep the trimmed version...
642+
return true;
643+
}
644+
delete M; // It didn't crash, try something else.
645+
return false;
646+
}
647+
500648
/// DebugACrash - Given a predicate that determines whether a component crashes
501649
/// on a program, try to destructively reduce the program while still keeping
502650
/// the predicate true.
@@ -661,6 +809,31 @@ static bool DebugACrash(BugDriver &BD,
661809
}
662810

663811
} while (Simplification);
812+
813+
if (!NoNamedMDRM) {
814+
BD.EmitProgressBitcode(BD.getProgram(), "reduced-instructions");
815+
816+
if (!BugpointIsInterrupted) {
817+
// Try to reduce the amount of global metadata (particularly debug info),
818+
// by dropping global named metadata that anchors them
819+
outs() << "\n*** Attempting to remove named metadata: ";
820+
std::vector<std::string> NamedMDNames;
821+
for (auto &NamedMD : BD.getProgram()->named_metadata())
822+
NamedMDNames.push_back(NamedMD.getName().str());
823+
ReduceCrashingNamedMD(BD, TestFn).reduceList(NamedMDNames, Error);
824+
}
825+
826+
if (!BugpointIsInterrupted) {
827+
// Now that we quickly dropped all the named metadata that doesn't
828+
// contribute to the crash, bisect the operands of the remaining ones
829+
std::vector<const MDNode *> NamedMDOps;
830+
for (auto &NamedMD : BD.getProgram()->named_metadata())
831+
NamedMDOps.insert(NamedMDOps.end(), NamedMD.op_begin(),
832+
NamedMD.op_end());
833+
ReduceCrashingNamedMDOps(BD, TestFn).reduceList(NamedMDOps, Error);
834+
}
835+
}
836+
664837
ExitLoops:
665838

666839
// Try to clean up the testcase by running funcresolve and globaldce...

0 commit comments

Comments
 (0)