Skip to content

Commit adaa603

Browse files
authored
[MachineVerifier] Report errors from one thread at a time (#111605)
Create the `ReportedErrors` class to track the number of reported errors during verification. The class will block reporting errors if some other thread is currently reporting an error. I've encountered a case where there were many different verifications reporting errors at the same time on different threads. This ensures that we don't start printing the error from one case until we are completely done printing errors from other cases. Most of the time `AbortOnError = true` so we usually abort after reporting the first error. Depends on #111602.
1 parent 31b85c6 commit adaa603

File tree

2 files changed

+92
-42
lines changed

2 files changed

+92
-42
lines changed

llvm/lib/CodeGen/MachineVerifier.cpp

Lines changed: 70 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,10 @@
7777
#include "llvm/Pass.h"
7878
#include "llvm/Support/Casting.h"
7979
#include "llvm/Support/ErrorHandling.h"
80+
#include "llvm/Support/ManagedStatic.h"
8081
#include "llvm/Support/MathExtras.h"
8182
#include "llvm/Support/ModRef.h"
83+
#include "llvm/Support/Mutex.h"
8284
#include "llvm/Support/raw_ostream.h"
8385
#include "llvm/Target/TargetMachine.h"
8486
#include <algorithm>
@@ -93,21 +95,31 @@ using namespace llvm;
9395

9496
namespace {
9597

98+
/// Used the by the ReportedErrors class to guarantee only one error is reported
99+
/// at one time.
100+
static ManagedStatic<sys::SmartMutex<true>> ReportedErrorsLock;
101+
96102
struct MachineVerifier {
97103
MachineVerifier(MachineFunctionAnalysisManager &MFAM, const char *b,
98-
raw_ostream *OS)
99-
: MFAM(&MFAM), OS(OS ? *OS : nulls()), Banner(b) {}
104+
raw_ostream *OS, bool AbortOnError = true)
105+
: MFAM(&MFAM), OS(OS ? *OS : nulls()), Banner(b),
106+
ReportedErrs(AbortOnError) {}
100107

101-
MachineVerifier(Pass *pass, const char *b, raw_ostream *OS)
102-
: PASS(pass), OS(OS ? *OS : nulls()), Banner(b) {}
108+
MachineVerifier(Pass *pass, const char *b, raw_ostream *OS,
109+
bool AbortOnError = true)
110+
: PASS(pass), OS(OS ? *OS : nulls()), Banner(b),
111+
ReportedErrs(AbortOnError) {}
103112

104113
MachineVerifier(const char *b, LiveVariables *LiveVars,
105114
LiveIntervals *LiveInts, LiveStacks *LiveStks,
106-
SlotIndexes *Indexes, raw_ostream *OS)
115+
SlotIndexes *Indexes, raw_ostream *OS,
116+
bool AbortOnError = true)
107117
: OS(OS ? *OS : nulls()), Banner(b), LiveVars(LiveVars),
108-
LiveInts(LiveInts), LiveStks(LiveStks), Indexes(Indexes) {}
118+
LiveInts(LiveInts), LiveStks(LiveStks), Indexes(Indexes),
119+
ReportedErrs(AbortOnError) {}
109120

110-
unsigned verify(const MachineFunction &MF);
121+
/// \returns true if no problems were found.
122+
bool verify(const MachineFunction &MF);
111123

112124
MachineFunctionAnalysisManager *MFAM = nullptr;
113125
Pass *const PASS = nullptr;
@@ -120,8 +132,6 @@ struct MachineVerifier {
120132
const MachineRegisterInfo *MRI = nullptr;
121133
const RegisterBankInfo *RBI = nullptr;
122134

123-
unsigned foundErrors = 0;
124-
125135
// Avoid querying the MachineFunctionProperties for each operand.
126136
bool isFunctionRegBankSelected = false;
127137
bool isFunctionSelected = false;
@@ -231,6 +241,44 @@ struct MachineVerifier {
231241
LiveStacks *LiveStks = nullptr;
232242
SlotIndexes *Indexes = nullptr;
233243

244+
/// A class to track the number of reported error and to guarantee that only
245+
/// one error is reported at one time.
246+
class ReportedErrors {
247+
unsigned NumReported = 0;
248+
bool AbortOnError;
249+
250+
public:
251+
/// \param AbortOnError -- If set, abort after printing the first error.
252+
ReportedErrors(bool AbortOnError) : AbortOnError(AbortOnError) {}
253+
254+
~ReportedErrors() {
255+
if (!hasError())
256+
return;
257+
if (AbortOnError)
258+
report_fatal_error("Found " + Twine(NumReported) +
259+
" machine code errors.");
260+
// Since we haven't aborted, release the lock to allow other threads to
261+
// report errors.
262+
ReportedErrorsLock->unlock();
263+
}
264+
265+
/// Increment the number of reported errors.
266+
/// \returns true if this is the first reported error.
267+
bool increment() {
268+
// If this is the first error this thread has encountered, grab the lock
269+
// to prevent other threads from reporting errors at the same time.
270+
// Otherwise we assume we already have the lock.
271+
if (!hasError())
272+
ReportedErrorsLock->lock();
273+
++NumReported;
274+
return NumReported == 1;
275+
}
276+
277+
/// \returns true if an error was reported.
278+
bool hasError() { return NumReported; }
279+
};
280+
ReportedErrors ReportedErrs;
281+
234282
// This is calculated only when trying to verify convergence control tokens.
235283
// Similar to the LLVM IR verifier, we calculate this locally instead of
236284
// relying on the pass manager.
@@ -337,11 +385,7 @@ struct MachineVerifierLegacyPass : public MachineFunctionPass {
337385
MachineFunctionProperties::Property::FailsVerification))
338386
return false;
339387

340-
unsigned FoundErrors =
341-
MachineVerifier(this, Banner.c_str(), &errs()).verify(MF);
342-
if (FoundErrors)
343-
report_fatal_error("Found " + Twine(FoundErrors) +
344-
" machine code errors.");
388+
MachineVerifier(this, Banner.c_str(), &errs()).verify(MF);
345389
return false;
346390
}
347391
};
@@ -357,10 +401,7 @@ MachineVerifierPass::run(MachineFunction &MF,
357401
if (MF.getProperties().hasProperty(
358402
MachineFunctionProperties::Property::FailsVerification))
359403
return PreservedAnalyses::all();
360-
unsigned FoundErrors =
361-
MachineVerifier(MFAM, Banner.c_str(), &errs()).verify(MF);
362-
if (FoundErrors)
363-
report_fatal_error("Found " + Twine(FoundErrors) + " machine code errors.");
404+
MachineVerifier(MFAM, Banner.c_str(), &errs()).verify(MF);
364405
return PreservedAnalyses::all();
365406
}
366407

@@ -380,31 +421,20 @@ void llvm::verifyMachineFunction(const std::string &Banner,
380421
// LiveIntervals *LiveInts;
381422
// LiveStacks *LiveStks;
382423
// SlotIndexes *Indexes;
383-
unsigned FoundErrors =
384-
MachineVerifier(nullptr, Banner.c_str(), &errs()).verify(MF);
385-
if (FoundErrors)
386-
report_fatal_error("Found " + Twine(FoundErrors) + " machine code errors.");
424+
MachineVerifier(nullptr, Banner.c_str(), &errs()).verify(MF);
387425
}
388426

389427
bool MachineFunction::verify(Pass *p, const char *Banner, raw_ostream *OS,
390-
bool AbortOnErrors) const {
391-
MachineFunction &MF = const_cast<MachineFunction&>(*this);
392-
unsigned FoundErrors = MachineVerifier(p, Banner, OS).verify(MF);
393-
if (AbortOnErrors && FoundErrors)
394-
report_fatal_error("Found "+Twine(FoundErrors)+" machine code errors.");
395-
return FoundErrors == 0;
428+
bool AbortOnError) const {
429+
return MachineVerifier(p, Banner, OS, AbortOnError).verify(*this);
396430
}
397431

398432
bool MachineFunction::verify(LiveIntervals *LiveInts, SlotIndexes *Indexes,
399433
const char *Banner, raw_ostream *OS,
400-
bool AbortOnErrors) const {
401-
MachineFunction &MF = const_cast<MachineFunction &>(*this);
402-
unsigned FoundErrors =
403-
MachineVerifier(Banner, nullptr, LiveInts, nullptr, Indexes, OS)
404-
.verify(MF);
405-
if (AbortOnErrors && FoundErrors)
406-
report_fatal_error("Found " + Twine(FoundErrors) + " machine code errors.");
407-
return FoundErrors == 0;
434+
bool AbortOnError) const {
435+
return MachineVerifier(Banner, /*LiveVars=*/nullptr, LiveInts,
436+
/*LiveStks=*/nullptr, Indexes, OS, AbortOnError)
437+
.verify(*this);
408438
}
409439

410440
void MachineVerifier::verifySlotIndexes() const {
@@ -430,9 +460,7 @@ void MachineVerifier::verifyProperties(const MachineFunction &MF) {
430460
report("Function has NoVRegs property but there are VReg operands", &MF);
431461
}
432462

433-
unsigned MachineVerifier::verify(const MachineFunction &MF) {
434-
foundErrors = 0;
435-
463+
bool MachineVerifier::verify(const MachineFunction &MF) {
436464
this->MF = &MF;
437465
TM = &MF.getTarget();
438466
TII = MF.getSubtarget().getInstrInfo();
@@ -447,7 +475,7 @@ unsigned MachineVerifier::verify(const MachineFunction &MF) {
447475
// it's expected that the MIR is somewhat broken but that's ok since we'll
448476
// reset it and clear the FailedISel attribute in ResetMachineFunctions.
449477
if (isFunctionFailedISel)
450-
return foundErrors;
478+
return true;
451479

452480
isFunctionRegBankSelected = MF.getProperties().hasProperty(
453481
MachineFunctionProperties::Property::RegBankSelected);
@@ -544,13 +572,13 @@ unsigned MachineVerifier::verify(const MachineFunction &MF) {
544572
regMasks.clear();
545573
MBBInfoMap.clear();
546574

547-
return foundErrors;
575+
return !ReportedErrs.hasError();
548576
}
549577

550578
void MachineVerifier::report(const char *msg, const MachineFunction *MF) {
551579
assert(MF);
552580
OS << '\n';
553-
if (!foundErrors++) {
581+
if (ReportedErrs.increment()) {
554582
if (Banner)
555583
OS << "# " << Banner << '\n';
556584

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# RUN: not --crash llc -mtriple=aarch64 -o /dev/null -run-pass=none %s 2>&1 | FileCheck %s --implicit-check-not="Bad machine code"
2+
# REQUIRES: aarch64-registered-target
3+
4+
# Since we abort after reporting the first error, we should only expect one error to be reported.
5+
# CHECK: *** Bad machine code: Generic virtual register use cannot be undef ***
6+
# CHECK: Found 1 machine code errors.
7+
8+
---
9+
name: foo
10+
liveins:
11+
body: |
12+
bb.0:
13+
$x0 = COPY undef %0:_(s64)
14+
...
15+
16+
---
17+
name: bar
18+
liveins:
19+
body: |
20+
bb.0:
21+
$x0 = COPY undef %0:_(s64)
22+
...

0 commit comments

Comments
 (0)