| //===- 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<DbgSSABlock *, DbgValueDef>; |
| |
| DebugSSAUpdater::DebugSSAUpdater(SmallVectorImpl<DbgSSAPhi *> *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<std::pair<DbgSSABlock *, DbgValueDef>, 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<DebugSSAUpdater> { |
| 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<DbgSSABlock *> *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<DebugSSAUpdater> 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<BasicBlock *, SmallVector<DbgVariableRecord *>> BlockDbgRecordValues; |
| DenseSet<BasicBlock *> 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<DILocalScope>(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<BasicBlock *, DbgValueDef> LiveInMap; |
| SmallVector<DbgSSAPhi *> 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<DbgRangeEntry> BlockDbgRanges; |
| BasicBlock::iterator LastIt = BB.begin(); |
| for (auto *DVR : BlockDbgRecordValues[&BB]) { |
| // Create a range that ends as of DVR. |
| BasicBlock::iterator DVRStartIt = |
| const_cast<Instruction *>(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; |
| } |