390 lines
13 KiB
C++
390 lines
13 KiB
C++
//===- 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.
|
|
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;
|
|
}
|