llvm-mirror/lib/CodeGen/LexicalScopes.cpp
Jan-Willem Maessen 088194d6a5 [NFC] Fix quadratic LexicalScopes::constructScopeNest
We sometimes have functions with large numbers of sibling basic
blocks (usually with an error path exit from each one). This was
triggering the qudratic behavior in this function - after visiting
each child llvm would re-scan the parent from the beginning again. We
modify the work stack to record the next index to be worked on
alongside the pointer. This avoids the need to linearly search for
the next unfinished child.

Differential Revision: https://reviews.llvm.org/D80029
2020-06-08 18:40:56 +01:00

348 lines
12 KiB
C++

//===- LexicalScopes.cpp - Collecting lexical scope info ------------------===//
//
// 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 LexicalScopes analysis.
//
// This pass collects lexical scope information and maps machine instructions
// to respective lexical scopes.
//
//===----------------------------------------------------------------------===//
#include "llvm/CodeGen/LexicalScopes.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Metadata.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <string>
#include <tuple>
#include <utility>
using namespace llvm;
#define DEBUG_TYPE "lexicalscopes"
/// reset - Reset the instance so that it's prepared for another function.
void LexicalScopes::reset() {
MF = nullptr;
CurrentFnLexicalScope = nullptr;
LexicalScopeMap.clear();
AbstractScopeMap.clear();
InlinedLexicalScopeMap.clear();
AbstractScopesList.clear();
DominatedBlocks.clear();
}
/// initialize - Scan machine function and constuct lexical scope nest.
void LexicalScopes::initialize(const MachineFunction &Fn) {
reset();
// Don't attempt any lexical scope creation for a NoDebug compile unit.
if (Fn.getFunction().getSubprogram()->getUnit()->getEmissionKind() ==
DICompileUnit::NoDebug)
return;
MF = &Fn;
SmallVector<InsnRange, 4> MIRanges;
DenseMap<const MachineInstr *, LexicalScope *> MI2ScopeMap;
extractLexicalScopes(MIRanges, MI2ScopeMap);
if (CurrentFnLexicalScope) {
constructScopeNest(CurrentFnLexicalScope);
assignInstructionRanges(MIRanges, MI2ScopeMap);
}
}
/// extractLexicalScopes - Extract instruction ranges for each lexical scopes
/// for the given machine function.
void LexicalScopes::extractLexicalScopes(
SmallVectorImpl<InsnRange> &MIRanges,
DenseMap<const MachineInstr *, LexicalScope *> &MI2ScopeMap) {
// Scan each instruction and create scopes. First build working set of scopes.
for (const auto &MBB : *MF) {
const MachineInstr *RangeBeginMI = nullptr;
const MachineInstr *PrevMI = nullptr;
const DILocation *PrevDL = nullptr;
for (const auto &MInsn : MBB) {
// Check if instruction has valid location information.
const DILocation *MIDL = MInsn.getDebugLoc();
if (!MIDL) {
PrevMI = &MInsn;
continue;
}
// If scope has not changed then skip this instruction.
if (MIDL == PrevDL) {
PrevMI = &MInsn;
continue;
}
// Ignore DBG_VALUE and similar instruction that do not contribute to any
// instruction in the output.
if (MInsn.isMetaInstruction())
continue;
if (RangeBeginMI) {
// If we have already seen a beginning of an instruction range and
// current instruction scope does not match scope of first instruction
// in this range then create a new instruction range.
InsnRange R(RangeBeginMI, PrevMI);
MI2ScopeMap[RangeBeginMI] = getOrCreateLexicalScope(PrevDL);
MIRanges.push_back(R);
}
// This is a beginning of a new instruction range.
RangeBeginMI = &MInsn;
// Reset previous markers.
PrevMI = &MInsn;
PrevDL = MIDL;
}
// Create last instruction range.
if (RangeBeginMI && PrevMI && PrevDL) {
InsnRange R(RangeBeginMI, PrevMI);
MIRanges.push_back(R);
MI2ScopeMap[RangeBeginMI] = getOrCreateLexicalScope(PrevDL);
}
}
}
/// findLexicalScope - Find lexical scope, either regular or inlined, for the
/// given DebugLoc. Return NULL if not found.
LexicalScope *LexicalScopes::findLexicalScope(const DILocation *DL) {
DILocalScope *Scope = DL->getScope();
if (!Scope)
return nullptr;
// The scope that we were created with could have an extra file - which
// isn't what we care about in this case.
Scope = Scope->getNonLexicalBlockFileScope();
if (auto *IA = DL->getInlinedAt()) {
auto I = InlinedLexicalScopeMap.find(std::make_pair(Scope, IA));
return I != InlinedLexicalScopeMap.end() ? &I->second : nullptr;
}
return findLexicalScope(Scope);
}
/// getOrCreateLexicalScope - Find lexical scope for the given DebugLoc. If
/// not available then create new lexical scope.
LexicalScope *LexicalScopes::getOrCreateLexicalScope(const DILocalScope *Scope,
const DILocation *IA) {
if (IA) {
// Skip scopes inlined from a NoDebug compile unit.
if (Scope->getSubprogram()->getUnit()->getEmissionKind() ==
DICompileUnit::NoDebug)
return getOrCreateLexicalScope(IA);
// Create an abstract scope for inlined function.
getOrCreateAbstractScope(Scope);
// Create an inlined scope for inlined function.
return getOrCreateInlinedScope(Scope, IA);
}
return getOrCreateRegularScope(Scope);
}
/// getOrCreateRegularScope - Find or create a regular lexical scope.
LexicalScope *
LexicalScopes::getOrCreateRegularScope(const DILocalScope *Scope) {
assert(Scope && "Invalid Scope encoding!");
Scope = Scope->getNonLexicalBlockFileScope();
auto I = LexicalScopeMap.find(Scope);
if (I != LexicalScopeMap.end())
return &I->second;
// FIXME: Should the following dyn_cast be DILexicalBlock?
LexicalScope *Parent = nullptr;
if (auto *Block = dyn_cast<DILexicalBlockBase>(Scope))
Parent = getOrCreateLexicalScope(Block->getScope());
I = LexicalScopeMap.emplace(std::piecewise_construct,
std::forward_as_tuple(Scope),
std::forward_as_tuple(Parent, Scope, nullptr,
false)).first;
if (!Parent) {
assert(cast<DISubprogram>(Scope)->describes(&MF->getFunction()));
assert(!CurrentFnLexicalScope);
CurrentFnLexicalScope = &I->second;
}
return &I->second;
}
/// getOrCreateInlinedScope - Find or create an inlined lexical scope.
LexicalScope *
LexicalScopes::getOrCreateInlinedScope(const DILocalScope *Scope,
const DILocation *InlinedAt) {
assert(Scope && "Invalid Scope encoding!");
Scope = Scope->getNonLexicalBlockFileScope();
std::pair<const DILocalScope *, const DILocation *> P(Scope, InlinedAt);
auto I = InlinedLexicalScopeMap.find(P);
if (I != InlinedLexicalScopeMap.end())
return &I->second;
LexicalScope *Parent;
if (auto *Block = dyn_cast<DILexicalBlockBase>(Scope))
Parent = getOrCreateInlinedScope(Block->getScope(), InlinedAt);
else
Parent = getOrCreateLexicalScope(InlinedAt);
I = InlinedLexicalScopeMap
.emplace(std::piecewise_construct, std::forward_as_tuple(P),
std::forward_as_tuple(Parent, Scope, InlinedAt, false))
.first;
return &I->second;
}
/// getOrCreateAbstractScope - Find or create an abstract lexical scope.
LexicalScope *
LexicalScopes::getOrCreateAbstractScope(const DILocalScope *Scope) {
assert(Scope && "Invalid Scope encoding!");
Scope = Scope->getNonLexicalBlockFileScope();
auto I = AbstractScopeMap.find(Scope);
if (I != AbstractScopeMap.end())
return &I->second;
// FIXME: Should the following isa be DILexicalBlock?
LexicalScope *Parent = nullptr;
if (auto *Block = dyn_cast<DILexicalBlockBase>(Scope))
Parent = getOrCreateAbstractScope(Block->getScope());
I = AbstractScopeMap.emplace(std::piecewise_construct,
std::forward_as_tuple(Scope),
std::forward_as_tuple(Parent, Scope,
nullptr, true)).first;
if (isa<DISubprogram>(Scope))
AbstractScopesList.push_back(&I->second);
return &I->second;
}
/// constructScopeNest - Traverse the Scope tree depth-first, storing
/// traversal state in WorkStack and recording the depth-first
/// numbering (setDFSIn, setDFSOut) for edge classification.
void LexicalScopes::constructScopeNest(LexicalScope *Scope) {
assert(Scope && "Unable to calculate scope dominance graph!");
SmallVector<std::pair<LexicalScope *, size_t>, 4> WorkStack;
WorkStack.push_back(std::make_pair(Scope, 0));
unsigned Counter = 0;
while (!WorkStack.empty()) {
auto &ScopePosition = WorkStack.back();
LexicalScope *WS = ScopePosition.first;
size_t ChildNum = ScopePosition.second++;
const SmallVectorImpl<LexicalScope *> &Children = WS->getChildren();
if (ChildNum < Children.size()) {
auto &ChildScope = Children[ChildNum];
WorkStack.push_back(std::make_pair(ChildScope, 0));
ChildScope->setDFSIn(++Counter);
} else {
WorkStack.pop_back();
WS->setDFSOut(++Counter);
}
}
}
/// assignInstructionRanges - Find ranges of instructions covered by each
/// lexical scope.
void LexicalScopes::assignInstructionRanges(
SmallVectorImpl<InsnRange> &MIRanges,
DenseMap<const MachineInstr *, LexicalScope *> &MI2ScopeMap) {
LexicalScope *PrevLexicalScope = nullptr;
for (const auto &R : MIRanges) {
LexicalScope *S = MI2ScopeMap.lookup(R.first);
assert(S && "Lost LexicalScope for a machine instruction!");
if (PrevLexicalScope && !PrevLexicalScope->dominates(S))
PrevLexicalScope->closeInsnRange(S);
S->openInsnRange(R.first);
S->extendInsnRange(R.second);
PrevLexicalScope = S;
}
if (PrevLexicalScope)
PrevLexicalScope->closeInsnRange();
}
/// getMachineBasicBlocks - Populate given set using machine basic blocks which
/// have machine instructions that belong to lexical scope identified by
/// DebugLoc.
void LexicalScopes::getMachineBasicBlocks(
const DILocation *DL, SmallPtrSetImpl<const MachineBasicBlock *> &MBBs) {
assert(MF && "Method called on a uninitialized LexicalScopes object!");
MBBs.clear();
LexicalScope *Scope = getOrCreateLexicalScope(DL);
if (!Scope)
return;
if (Scope == CurrentFnLexicalScope) {
for (const auto &MBB : *MF)
MBBs.insert(&MBB);
return;
}
// The scope ranges can cover multiple basic blocks in each span. Iterate over
// all blocks (in the order they are in the function) until we reach the one
// containing the end of the span.
SmallVectorImpl<InsnRange> &InsnRanges = Scope->getRanges();
for (auto &R : InsnRanges)
for (auto CurMBBIt = R.first->getParent()->getIterator(),
EndBBIt = std::next(R.second->getParent()->getIterator());
CurMBBIt != EndBBIt; CurMBBIt++)
MBBs.insert(&*CurMBBIt);
}
bool LexicalScopes::dominates(const DILocation *DL, MachineBasicBlock *MBB) {
assert(MF && "Unexpected uninitialized LexicalScopes object!");
LexicalScope *Scope = getOrCreateLexicalScope(DL);
if (!Scope)
return false;
// Current function scope covers all basic blocks in the function.
if (Scope == CurrentFnLexicalScope && MBB->getParent() == MF)
return true;
// Fetch all the blocks in DLs scope. Because the range / block list also
// contain any subscopes, any instruction that DL dominates can be found in
// the block set.
//
// Cache the set of fetched blocks to avoid repeatedly recomputing the set in
// the LiveDebugValues pass.
std::unique_ptr<BlockSetT> &Set = DominatedBlocks[DL];
if (!Set) {
Set = std::make_unique<BlockSetT>();
getMachineBasicBlocks(DL, *Set);
}
return Set->count(MBB) != 0;
}
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
LLVM_DUMP_METHOD void LexicalScope::dump(unsigned Indent) const {
raw_ostream &err = dbgs();
err.indent(Indent);
err << "DFSIn: " << DFSIn << " DFSOut: " << DFSOut << "\n";
const MDNode *N = Desc;
err.indent(Indent);
N->dump();
if (AbstractScope)
err << std::string(Indent, ' ') << "Abstract Scope\n";
if (!Children.empty())
err << std::string(Indent + 2, ' ') << "Children ...\n";
for (unsigned i = 0, e = Children.size(); i != e; ++i)
if (Children[i] != this)
Children[i]->dump(Indent + 2);
}
#endif