//===- DebugSSAUpdater.cpp - Debug Variable SSA Update Tool ---------------===// // // 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 // //===----------------------------------------------------------------------===// // // This file implements the DebugSSAUpdater class. // //===----------------------------------------------------------------------===// #include "llvm/Transforms/Utils/DebugSSAUpdater.h" #include "llvm/IR/CFG.h" #include "llvm/IR/DebugInfo.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/Transforms/Utils/SSAUpdaterImpl.h" using namespace llvm; #define DEBUG_TYPE "debug-ssa-updater" void DbgValueDef::print(raw_ostream &OS) const { OS << "DbgVal{ "; if (IsUndef) { OS << "undef }"; return; } if (Phi) { OS << *Phi << "}"; return; } OS << (IsMemory ? "Mem: " : "Def: ") << *Locations << " - " << *Expression << " }"; } void DbgSSAPhi::print(raw_ostream &OS) const { OS << "DbgPhi "; for (auto &[BB, DV] : IncomingValues) OS << "[" << BB->BB.getName() << ", " << DV << "] "; } using AvailableValsTy = DenseMap; DebugSSAUpdater::DebugSSAUpdater(SmallVectorImpl *NewPHI) : InsertedPHIs(NewPHI) {} void DebugSSAUpdater::initialize() { AV.clear(); } bool DebugSSAUpdater::hasValueForBlock(DbgSSABlock *BB) const { return AV.count(BB); } DbgValueDef DebugSSAUpdater::findValueForBlock(DbgSSABlock *BB) const { return AV.lookup(BB); } void DebugSSAUpdater::addAvailableValue(DbgSSABlock *BB, DbgValueDef DV) { AV[BB] = DV; } DbgValueDef DebugSSAUpdater::getValueAtEndOfBlock(DbgSSABlock *BB) { DbgValueDef Res = getValueAtEndOfBlockInternal(BB); return Res; } DbgValueDef DebugSSAUpdater::getValueInMiddleOfBlock(DbgSSABlock *BB) { // If there is no definition of the renamed variable in this block, just use // 'getValueAtEndOfBlock' to do our work. if (!hasValueForBlock(BB)) return getValueAtEndOfBlock(BB); // Otherwise, we have the hard case. Get the live-in values for each // predecessor. SmallVector, 8> PredValues; DbgValueDef SingularValue; bool IsFirstPred = true; for (DbgSSABlock *PredBB : BB->predecessors()) { DbgValueDef PredVal = getValueAtEndOfBlock(PredBB); PredValues.push_back(std::make_pair(PredBB, PredVal)); // Compute SingularValue. if (IsFirstPred) { SingularValue = PredVal; IsFirstPred = false; } else if (!PredVal.agreesWith(SingularValue)) SingularValue = DbgValueDef(); } // If there are no predecessors, just return undef. if (PredValues.empty()) return DbgValueDef(); // Otherwise, if all the merged values are the same, just use it. if (!SingularValue.IsUndef) return SingularValue; // Ok, we have no way out, insert a new one now. DbgSSAPhi *InsertedPHI = BB->newPHI(); // Fill in all the predecessors of the PHI. for (const auto &PredValue : PredValues) InsertedPHI->addIncoming(PredValue.first, PredValue.second); // See if the PHI node can be merged to a single value. This can happen in // loop cases when we get a PHI of itself and one other value. // If the client wants to know about all new instructions, tell it. if (InsertedPHIs) InsertedPHIs->push_back(InsertedPHI); LLVM_DEBUG(dbgs() << " Inserted PHI: " << *InsertedPHI << "\n"); return InsertedPHI; } DbgSSABlock *DbgSSABlockSuccIterator::operator*() { return Updater.getDbgSSABlock(*SuccIt); } DbgSSABlock *DbgSSABlockPredIterator::operator*() { return Updater.getDbgSSABlock(*PredIt); } namespace llvm { template <> class SSAUpdaterTraits { public: using BlkT = DbgSSABlock; using ValT = DbgValueDef; using PhiT = DbgSSAPhi; using BlkSucc_iterator = DbgSSABlockSuccIterator; static BlkSucc_iterator BlkSucc_begin(BlkT *BB) { return BB->succ_begin(); } static BlkSucc_iterator BlkSucc_end(BlkT *BB) { return BB->succ_end(); } class PHI_iterator { private: DbgSSAPhi *PHI; unsigned Idx; public: explicit PHI_iterator(DbgSSAPhi *P) // begin iterator : PHI(P), Idx(0) {} PHI_iterator(DbgSSAPhi *P, bool) // end iterator : PHI(P), Idx(PHI->getNumIncomingValues()) {} PHI_iterator &operator++() { ++Idx; return *this; } bool operator==(const PHI_iterator &X) const { return Idx == X.Idx; } bool operator!=(const PHI_iterator &X) const { return !operator==(X); } DbgValueDef getIncomingValue() { return PHI->getIncomingValue(Idx); } DbgSSABlock *getIncomingBlock() { return PHI->getIncomingBlock(Idx); } }; static PHI_iterator PHI_begin(PhiT *PHI) { return PHI_iterator(PHI); } static PHI_iterator PHI_end(PhiT *PHI) { return PHI_iterator(PHI, true); } /// FindPredecessorBlocks - Put the predecessors of BB into the Preds /// vector. static void FindPredecessorBlocks(DbgSSABlock *BB, SmallVectorImpl *Preds) { for (auto PredIt = BB->pred_begin(); PredIt != BB->pred_end(); ++PredIt) Preds->push_back(*PredIt); } /// GetPoisonVal - Get an undefined value of the same type as the value /// being handled. static DbgValueDef GetPoisonVal(DbgSSABlock *BB, DebugSSAUpdater *Updater) { return DbgValueDef(); } /// CreateEmptyPHI - Create a new debug PHI entry for the specified block. static DbgSSAPhi *CreateEmptyPHI(DbgSSABlock *BB, unsigned NumPreds, DebugSSAUpdater *Updater) { DbgSSAPhi *PHI = BB->newPHI(); return PHI; } /// AddPHIOperand - Add the specified value as an operand of the PHI for /// the specified predecessor block. static void AddPHIOperand(DbgSSAPhi *PHI, DbgValueDef Val, DbgSSABlock *Pred) { PHI->addIncoming(Pred, Val); } /// ValueIsPHI - Check if a value is a PHI. static DbgSSAPhi *ValueIsPHI(DbgValueDef Val, DebugSSAUpdater *Updater) { return Val.Phi; } /// ValueIsNewPHI - Like ValueIsPHI but also check if the PHI has no source /// operands, i.e., it was just added. static DbgSSAPhi *ValueIsNewPHI(DbgValueDef Val, DebugSSAUpdater *Updater) { DbgSSAPhi *PHI = ValueIsPHI(Val, Updater); if (PHI && PHI->getNumIncomingValues() == 0) return PHI; return nullptr; } /// GetPHIValue - For the specified PHI instruction, return the value /// that it defines. static DbgValueDef GetPHIValue(DbgSSAPhi *PHI) { return PHI; } }; } // end namespace llvm /// Check to see if AvailableVals has an entry for the specified BB and if so, /// return it. If not, construct SSA form by first calculating the required /// placement of PHIs and then inserting new PHIs where needed. DbgValueDef DebugSSAUpdater::getValueAtEndOfBlockInternal(DbgSSABlock *BB) { if (AV.contains(BB)) return AV[BB]; SSAUpdaterImpl Impl(this, &AV, InsertedPHIs); return Impl.GetValue(BB); } bool isContained(DIScope *Inner, DIScope *Outer) { if (Inner == Outer) return true; if (!Inner->getScope()) return false; return isContained(Inner->getScope(), Outer); } void DbgValueRangeTable::addVariable(Function *F, DebugVariableAggregate DVA) { const DILocalVariable *Var = DVA.getVariable(); const DILocation *InlinedAt = DVA.getInlinedAt(); DenseMap> BlockDbgRecordValues; DenseSet HasAnyInstructionsInScope; int NumRecordsFound = 0; DbgVariableRecord *LastRecordFound = nullptr; bool DeclareRecordFound = false; LLVM_DEBUG(dbgs() << "Finding variable info for " << *Var << " at " << InlinedAt << "\n"); for (auto &BB : *F) { auto &DbgRecordValues = BlockDbgRecordValues[&BB]; bool FoundInstructionInScope = false; for (auto &I : BB) { LLVM_DEBUG(dbgs() << "Instruction: '" << I << "'\n"); for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange())) { if (DVR.getVariable() == Var && DVR.getDebugLoc().getInlinedAt() == InlinedAt) { assert(!DVR.isDbgAssign() && "No support for #dbg_assign yet."); if (DVR.isDbgDeclare()) DeclareRecordFound = true; ++NumRecordsFound; LastRecordFound = &DVR; DbgRecordValues.push_back(&DVR); } } if (!FoundInstructionInScope && I.getDebugLoc()) { if (I.getDebugLoc().getInlinedAt() == InlinedAt && isContained(cast(I.getDebugLoc().getScope()), Var->getScope())) { FoundInstructionInScope = true; HasAnyInstructionsInScope.insert(&BB); } } } LLVM_DEBUG(dbgs() << "DbgRecordValues found in '" << BB.getName() << "':\n"; for_each(DbgRecordValues, [](auto *DV) { DV->dump(); })); } if (!NumRecordsFound) { LLVM_DEBUG(dbgs() << "No dbg_records found for variable!\n"); return; } // Now that we have all the DbgValues, we can start defining available values // for each block. The end goal is to have, for every block with any // instructions in scope, a LiveIn value. // Currently we anticipate that either a variable has a set of #dbg_values, in // which case we need a complete SSA liveness analysis to determine live-in // values per-block, or a variable has a single #dbg_declare. if (DeclareRecordFound) { // FIXME: This should be changed for fragments! LLVM_DEBUG(dbgs() << "Single location found for variable!\n"); assert(NumRecordsFound == 1 && "Found multiple records for a #dbg_declare variable!"); OrigSingleLocVariableValueTable[DVA] = DbgValueDef(LastRecordFound); return; } // We don't have a single location for the variable's entire scope, so instead // we must now perform a liveness analysis to create a location list. DenseMap LiveInMap; SmallVector HypotheticalPHIs; DebugSSAUpdater SSAUpdater(&HypotheticalPHIs); SSAUpdater.initialize(); for (auto &[BB, DVs] : BlockDbgRecordValues) { auto *DbgBB = SSAUpdater.getDbgSSABlock(BB); if (DVs.empty()) continue; auto *LastValueInBlock = DVs.back(); LLVM_DEBUG(dbgs() << "Last value in " << BB->getName() << ": " << *LastValueInBlock << "\n"); SSAUpdater.addAvailableValue(DbgBB, DbgValueDef(LastValueInBlock)); } for (BasicBlock &BB : *F) { if (!HasAnyInstructionsInScope.contains(&BB)) { LLVM_DEBUG(dbgs() << "Skipping finding debug ranges for '" << BB.getName() << "' due to no in-scope instructions.\n"); continue; } LLVM_DEBUG(dbgs() << "Finding live-in value for '" << BB.getName() << "'...\n"); DbgValueDef LiveValue = SSAUpdater.getValueInMiddleOfBlock(SSAUpdater.getDbgSSABlock(&BB)); LLVM_DEBUG(dbgs() << "Found live-in: " << LiveValue << "\n"); auto HasValidValue = [](DbgValueDef DV) { return !DV.IsUndef && DV.Phi == nullptr; }; SmallVector BlockDbgRanges; BasicBlock::iterator LastIt = BB.begin(); for (auto *DVR : BlockDbgRecordValues[&BB]) { // Create a range that ends as of DVR. BasicBlock::iterator DVRStartIt = const_cast(DVR->getInstruction())->getIterator(); if (HasValidValue(LiveValue)) BlockDbgRanges.push_back({LastIt, DVRStartIt, LiveValue}); LiveValue = DbgValueDef(DVR); LastIt = DVRStartIt; } // After considering all in-block debug values, if any, create a range // covering the remainder of the block. if (HasValidValue(LiveValue)) BlockDbgRanges.push_back({LastIt, BB.end(), LiveValue}); LLVM_DEBUG(dbgs() << "Create set of ranges with " << BlockDbgRanges.size() << " entries!\n"); if (!BlockDbgRanges.empty()) OrigVariableValueRangeTable[DVA].append(BlockDbgRanges); } } void DbgValueRangeTable::printValues(DebugVariableAggregate DVA, raw_ostream &OS) { OS << "Variable Table for '" << DVA.getVariable()->getName() << "' (at " << DVA.getInlinedAt() << "):\n"; if (!hasVariableEntry(DVA)) { OS << " Empty!\n"; return; } if (hasSingleLocEntry(DVA)) { OS << " SingleLoc: " << OrigSingleLocVariableValueTable[DVA] << "\n"; return; } OS << " LocRange:\n"; for (DbgRangeEntry RangeEntry : OrigVariableValueRangeTable[DVA]) { OS << " ("; if (RangeEntry.Start == RangeEntry.Start->getParent()->begin() && RangeEntry.End == RangeEntry.Start->getParent()->end()) { OS << RangeEntry.Start->getParent()->getName(); } else { OS << RangeEntry.Start->getParent()->getName() << ": " << *RangeEntry.Start << ", "; if (RangeEntry.End == RangeEntry.Start->getParent()->end()) OS << ".."; else OS << *RangeEntry.End; } OS << ") [" << RangeEntry.Value << "]\n"; } } SSAValueNameMap::ValueID SSAValueNameMap::addValue(Value *V) { auto ExistingID = ValueToIDMap.find(V); if (ExistingID != ValueToIDMap.end()) return ExistingID->second; // First, get a new ID and Map V to it. ValueID NewID = NextID++; ValueToIDMap.insert({V, NewID}); // Then, get the name string for V and map NewID to it. assert(!ValueIDToNameMap.contains(NewID) && "New value ID already maps to a name?"); std::string &ValueText = ValueIDToNameMap[NewID]; raw_string_ostream Stream(ValueText); V->printAsOperand(Stream, true); return NewID; }