You've already forked llvm-project
mirror of
https://github.com/encounter/llvm-project.git
synced 2026-03-30 11:27:19 -07:00
d9085f65db
Summary: This verifier tries to ensure that DebugLoc's don't just disappear as we transform the MIR. It observes the instructions created, erased, and changed and at checkpoints chosen by the client algorithm verifies the locations affected by those changes. In particular, it verifies that: * Every DebugLoc for an erased/changing instruction is still present on at least one new/changed instruction * Failing that, that there is a line-0 location in the new/changed instructions. It's not possible to confirm which locations were merged so it conservatively assumes all unaccounted for locations are accounted for by any line-0 location to avoid false positives. If that fails, it prints the lost locations in the debug output along with the instructions that should have accounted for them. In theory, this is usable by the legalizer, combiner, selector and any other pass that performs incremental changes to the MIR. However, it has so far only really been tested on the legalizer (not including the artifact combiner) where it has caught lots of lost locations, particularly in Custom legalizations. There's only one example here as my initial testing was on an out-of-tree target and I haven't done a pass over the in-tree targets yet. Depends on D77575, D77446 Reviewers: bogner, aprantl, vsk Subscribers: jvesely, nhaehnle, mgorny, rovka, hiraditya, volkan, kerbowa, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D77576
114 lines
3.4 KiB
C++
114 lines
3.4 KiB
C++
//===----- llvm/CodeGen/GlobalISel/LostDebugLocObserver.cpp -----*- C++ -*-===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
/// Tracks DebugLocs between checkpoints and verifies that they are transferred.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/CodeGen/GlobalISel/LostDebugLocObserver.h"
|
|
|
|
using namespace llvm;
|
|
|
|
#define LOC_DEBUG(X) DEBUG_WITH_TYPE(DebugType.str().c_str(), X)
|
|
|
|
void LostDebugLocObserver::analyzeDebugLocations() {
|
|
if (LostDebugLocs.empty()) {
|
|
LOC_DEBUG(dbgs() << ".. No debug info was present\n");
|
|
return;
|
|
}
|
|
if (PotentialMIsForDebugLocs.empty()) {
|
|
LOC_DEBUG(
|
|
dbgs() << ".. No instructions to carry debug info (dead code?)\n");
|
|
return;
|
|
}
|
|
|
|
LOC_DEBUG(dbgs() << ".. Searching " << PotentialMIsForDebugLocs.size()
|
|
<< " instrs for " << LostDebugLocs.size() << " locations\n");
|
|
SmallPtrSet<MachineInstr *, 4> FoundIn;
|
|
for (MachineInstr *MI : PotentialMIsForDebugLocs) {
|
|
if (!MI->getDebugLoc())
|
|
continue;
|
|
// Check this first in case there's a matching line-0 location on both input
|
|
// and output.
|
|
if (MI->getDebugLoc().getLine() == 0) {
|
|
LOC_DEBUG(
|
|
dbgs() << ".. Assuming line-0 location covers remainder (if any)\n");
|
|
return;
|
|
}
|
|
if (LostDebugLocs.erase(MI->getDebugLoc())) {
|
|
LOC_DEBUG(dbgs() << ".. .. found " << MI->getDebugLoc() << " in " << *MI);
|
|
FoundIn.insert(MI);
|
|
continue;
|
|
}
|
|
}
|
|
if (LostDebugLocs.empty())
|
|
return;
|
|
|
|
NumLostDebugLocs += LostDebugLocs.size();
|
|
LOC_DEBUG({
|
|
dbgs() << ".. Lost locations:\n";
|
|
for (const DebugLoc &Loc : LostDebugLocs) {
|
|
dbgs() << ".. .. ";
|
|
Loc.print(dbgs());
|
|
dbgs() << "\n";
|
|
}
|
|
dbgs() << ".. MIs with matched locations:\n";
|
|
for (MachineInstr *MI : FoundIn)
|
|
if (PotentialMIsForDebugLocs.erase(MI))
|
|
dbgs() << ".. .. " << *MI;
|
|
dbgs() << ".. Remaining MIs with unmatched/no locations:\n";
|
|
for (const MachineInstr *MI : PotentialMIsForDebugLocs)
|
|
dbgs() << ".. .. " << *MI;
|
|
});
|
|
}
|
|
|
|
void LostDebugLocObserver::checkpoint(bool CheckDebugLocs) {
|
|
if (CheckDebugLocs)
|
|
analyzeDebugLocations();
|
|
PotentialMIsForDebugLocs.clear();
|
|
LostDebugLocs.clear();
|
|
}
|
|
|
|
void LostDebugLocObserver::createdInstr(MachineInstr &MI) {
|
|
PotentialMIsForDebugLocs.insert(&MI);
|
|
}
|
|
|
|
bool irTranslatorNeverAddsLocations(unsigned Opcode) {
|
|
switch (Opcode) {
|
|
default:
|
|
return false;
|
|
case TargetOpcode::G_CONSTANT:
|
|
case TargetOpcode::G_FCONSTANT:
|
|
case TargetOpcode::G_IMPLICIT_DEF:
|
|
case TargetOpcode::G_GLOBAL_VALUE:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
void LostDebugLocObserver::erasingInstr(MachineInstr &MI) {
|
|
if (irTranslatorNeverAddsLocations(MI.getOpcode()))
|
|
return;
|
|
|
|
PotentialMIsForDebugLocs.erase(&MI);
|
|
if (MI.getDebugLoc())
|
|
LostDebugLocs.insert(MI.getDebugLoc());
|
|
}
|
|
|
|
void LostDebugLocObserver::changingInstr(MachineInstr &MI) {
|
|
if (irTranslatorNeverAddsLocations(MI.getOpcode()))
|
|
return;
|
|
|
|
PotentialMIsForDebugLocs.erase(&MI);
|
|
if (MI.getDebugLoc())
|
|
LostDebugLocs.insert(MI.getDebugLoc());
|
|
}
|
|
|
|
void LostDebugLocObserver::changedInstr(MachineInstr &MI) {
|
|
PotentialMIsForDebugLocs.insert(&MI);
|
|
}
|