| //===----- 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); | |
| } | |
| static 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); | |
| } |