mirror of
https://github.com/RPCSX/llvm.git
synced 2025-01-18 18:32:32 +00:00
Add a new "NewDebugLoc" class which will eventually replace DebugLoc,
and will replace the 'DbgInfo' member in Instruction. The benefit of NewDebugLoc is that it is compact (8 bytes vs 12/24 bytes for the DbgInfo member in Instruction on a 32/64 bit system), it means that we will end up not having to allocate MDNodes to represent the "DILocations" in common cases of -O0 -g, and it is much more efficient to get things out of than the MDNode. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@100072 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
1118b5e490
commit
b227925fa3
@ -20,6 +20,61 @@
|
||||
|
||||
namespace llvm {
|
||||
class MDNode;
|
||||
class LLVMContext;
|
||||
|
||||
/// DebugLoc - Debug location id. This is carried by Instruction, SDNode,
|
||||
/// and MachineInstr to compactly encode file/line/scope information for an
|
||||
/// operation.
|
||||
class NewDebugLoc {
|
||||
/// LineCol - This 32-bit value encodes the line and column number for the
|
||||
/// location, encoded as 24-bits for line and 8 bits for col. A value of 0
|
||||
/// for either means unknown.
|
||||
unsigned LineCol;
|
||||
|
||||
/// ScopeIdx - This is an opaque ID# for Scope/InlinedAt information,
|
||||
/// decoded by LLVMContext. 0 is unknown.
|
||||
int ScopeIdx;
|
||||
public:
|
||||
NewDebugLoc() : LineCol(0), ScopeIdx(0) {} // Defaults to unknown.
|
||||
|
||||
static NewDebugLoc get(unsigned Line, unsigned Col,
|
||||
MDNode *Scope, MDNode *InlinedAt);
|
||||
|
||||
/// isUnknown - Return true if this is an unknown location.
|
||||
bool isUnknown() const { return ScopeIdx == 0; }
|
||||
|
||||
unsigned getLine() const {
|
||||
return (LineCol << 8) >> 8; // Mask out column.
|
||||
}
|
||||
|
||||
unsigned getCol() const {
|
||||
return LineCol >> 24;
|
||||
}
|
||||
|
||||
/// getScope - This returns the scope pointer for this DebugLoc, or null if
|
||||
/// invalid.
|
||||
MDNode *getScope(const LLVMContext &Ctx) const;
|
||||
|
||||
/// getInlinedAt - This returns the InlinedAt pointer for this DebugLoc, or
|
||||
/// null if invalid or not present.
|
||||
MDNode *getInlinedAt(const LLVMContext &Ctx) const;
|
||||
|
||||
/// getScopeAndInlinedAt - Return both the Scope and the InlinedAt values.
|
||||
void getScopeAndInlinedAt(MDNode *&Scope, MDNode *&IA,
|
||||
const LLVMContext &Ctx) const;
|
||||
|
||||
|
||||
/// getAsMDNode - This method converts the compressed DebugLoc node into a
|
||||
/// DILocation compatible MDNode.
|
||||
MDNode *getAsMDNode(const LLVMContext &Ctx) const;
|
||||
|
||||
bool operator==(const NewDebugLoc &DL) const {
|
||||
return LineCol == DL.LineCol && ScopeIdx == DL.ScopeIdx;
|
||||
}
|
||||
bool operator!=(const NewDebugLoc &DL) const { return !(*this == DL); }
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// DebugLoc - Debug location id. This is carried by SDNode and MachineInstr
|
||||
/// to index into a vector of unique debug location tuples.
|
||||
|
270
lib/VMCore/DebugLoc.cpp
Normal file
270
lib/VMCore/DebugLoc.cpp
Normal file
@ -0,0 +1,270 @@
|
||||
//===-- DebugLoc.cpp - Implement DebugLoc class ---------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Support/DebugLoc.h"
|
||||
#include "LLVMContextImpl.h"
|
||||
using namespace llvm;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// DebugLoc Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
MDNode *NewDebugLoc::getScope(const LLVMContext &Ctx) const {
|
||||
if (ScopeIdx == 0) return 0;
|
||||
|
||||
if (ScopeIdx > 0) {
|
||||
// Positive ScopeIdx is an index into ScopeRecords, which has no inlined-at
|
||||
// position specified.
|
||||
assert(unsigned(ScopeIdx) <= Ctx.pImpl->ScopeRecords.size() &&
|
||||
"Invalid ScopeIdx!");
|
||||
return Ctx.pImpl->ScopeRecords[ScopeIdx-1].get();
|
||||
}
|
||||
|
||||
// Otherwise, the index is in the ScopeInlinedAtRecords array.
|
||||
assert(unsigned(-ScopeIdx) <= Ctx.pImpl->ScopeInlinedAtRecords.size() &&
|
||||
"Invalid ScopeIdx");
|
||||
return Ctx.pImpl->ScopeInlinedAtRecords[-ScopeIdx-1].first.get();
|
||||
}
|
||||
|
||||
MDNode *NewDebugLoc::getInlinedAt(const LLVMContext &Ctx) const {
|
||||
// Positive ScopeIdx is an index into ScopeRecords, which has no inlined-at
|
||||
// position specified. Zero is invalid.
|
||||
if (ScopeIdx >= 0) return 0;
|
||||
|
||||
// Otherwise, the index is in the ScopeInlinedAtRecords array.
|
||||
assert(unsigned(-ScopeIdx) <= Ctx.pImpl->ScopeInlinedAtRecords.size() &&
|
||||
"Invalid ScopeIdx");
|
||||
return Ctx.pImpl->ScopeInlinedAtRecords[-ScopeIdx-1].second.get();
|
||||
}
|
||||
|
||||
/// Return both the Scope and the InlinedAt values.
|
||||
void NewDebugLoc::getScopeAndInlinedAt(MDNode *&Scope, MDNode *&IA,
|
||||
const LLVMContext &Ctx) const {
|
||||
if (ScopeIdx == 0) {
|
||||
Scope = IA = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (ScopeIdx > 0) {
|
||||
// Positive ScopeIdx is an index into ScopeRecords, which has no inlined-at
|
||||
// position specified.
|
||||
assert(unsigned(ScopeIdx) <= Ctx.pImpl->ScopeRecords.size() &&
|
||||
"Invalid ScopeIdx!");
|
||||
Scope = Ctx.pImpl->ScopeRecords[ScopeIdx-1].get();
|
||||
IA = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, the index is in the ScopeInlinedAtRecords array.
|
||||
assert(unsigned(-ScopeIdx) <= Ctx.pImpl->ScopeInlinedAtRecords.size() &&
|
||||
"Invalid ScopeIdx");
|
||||
Scope = Ctx.pImpl->ScopeInlinedAtRecords[-ScopeIdx-1].first.get();
|
||||
IA = Ctx.pImpl->ScopeInlinedAtRecords[-ScopeIdx-1].second.get();
|
||||
}
|
||||
|
||||
|
||||
NewDebugLoc NewDebugLoc::get(unsigned Line, unsigned Col,
|
||||
MDNode *Scope, MDNode *InlinedAt) {
|
||||
NewDebugLoc Result;
|
||||
|
||||
// If no scope is available, this is an unknown location.
|
||||
if (Scope == 0) return Result;
|
||||
|
||||
// Saturate line and col to "unknown".
|
||||
if (Col > 255) Col = 0;
|
||||
if (Line >= (1 << 24)) Line = 0;
|
||||
Result.LineCol = Line | (Col << 24);
|
||||
|
||||
LLVMContext &Ctx = Scope->getContext();
|
||||
|
||||
// If there is no inlined-at location, use the ScopeRecords array.
|
||||
if (InlinedAt == 0)
|
||||
Result.ScopeIdx = Ctx.pImpl->getOrAddScopeRecordIdxEntry(Scope, 0);
|
||||
else
|
||||
Result.ScopeIdx = Ctx.pImpl->getOrAddScopeInlinedAtIdxEntry(Scope,
|
||||
InlinedAt, 0);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
/// getAsMDNode - This method converts the compressed DebugLoc node into a
|
||||
/// DILocation compatible MDNode.
|
||||
MDNode *NewDebugLoc::getAsMDNode(const LLVMContext &Ctx) const {
|
||||
if (isUnknown()) return 0;
|
||||
|
||||
MDNode *Scope, *IA;
|
||||
getScopeAndInlinedAt(Scope, IA, Ctx);
|
||||
assert(Scope && "If scope is null, this should be isUnknown()");
|
||||
|
||||
LLVMContext &Ctx2 = Scope->getContext();
|
||||
const Type *Int32 = Type::getInt32Ty(Ctx2);
|
||||
Value *Elts[] = {
|
||||
ConstantInt::get(Int32, getLine()), ConstantInt::get(Int32, getCol()),
|
||||
Scope, IA
|
||||
};
|
||||
return MDNode::get(Ctx2, &Elts[0], 4);
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// LLVMContextImpl Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
int LLVMContextImpl::getOrAddScopeRecordIdxEntry(MDNode *Scope,
|
||||
int ExistingIdx) {
|
||||
// If we already have an entry for this scope, return it.
|
||||
int &Idx = ScopeRecordIdx[Scope];
|
||||
if (Idx) return Idx;
|
||||
|
||||
// If we don't have an entry, but ExistingIdx is specified, use it.
|
||||
if (ExistingIdx)
|
||||
return Idx = ExistingIdx;
|
||||
|
||||
// Otherwise add a new entry.
|
||||
|
||||
// Start out ScopeRecords with a minimal reasonable size to avoid
|
||||
// excessive reallocation starting out.
|
||||
if (ScopeRecords.empty())
|
||||
ScopeRecords.reserve(128);
|
||||
|
||||
// Index is biased by 1 for index.
|
||||
Idx = ScopeRecords.size()+1;
|
||||
ScopeRecords.push_back(DebugRecVH(Scope, this, Idx));
|
||||
return Idx;
|
||||
}
|
||||
|
||||
int LLVMContextImpl::getOrAddScopeInlinedAtIdxEntry(MDNode *Scope, MDNode *IA,
|
||||
int ExistingIdx) {
|
||||
// If we already have an entry, return it.
|
||||
int &Idx = ScopeInlinedAtIdx[std::make_pair(Scope, IA)];
|
||||
if (Idx) return Idx;
|
||||
|
||||
// If we don't have an entry, but ExistingIdx is specified, use it.
|
||||
if (ExistingIdx)
|
||||
return Idx = ExistingIdx;
|
||||
|
||||
// Start out ScopeInlinedAtRecords with a minimal reasonable size to avoid
|
||||
// excessive reallocation starting out.
|
||||
if (ScopeInlinedAtRecords.empty())
|
||||
ScopeInlinedAtRecords.reserve(128);
|
||||
|
||||
// Index is biased by 1 and negated.
|
||||
Idx = -ScopeInlinedAtRecords.size()-1;
|
||||
ScopeInlinedAtRecords.push_back(std::make_pair(DebugRecVH(Scope, this, Idx),
|
||||
DebugRecVH(IA, this, Idx)));
|
||||
return Idx;
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// DebugRecVH Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// deleted - The MDNode this is pointing to got deleted, so this pointer needs
|
||||
/// to drop to null and we need remove our entry from the DenseMap.
|
||||
void DebugRecVH::deleted() {
|
||||
// If this is a non-canonical reference, just drop the value to null, we know
|
||||
// it doesn't have a map entry.
|
||||
if (Idx == 0) {
|
||||
setValPtr(0);
|
||||
return;
|
||||
}
|
||||
|
||||
MDNode *Cur = get();
|
||||
|
||||
// If the index is positive, it is an entry in ScopeRecords.
|
||||
if (Idx > 0) {
|
||||
assert(Ctx->ScopeRecordIdx[Cur] == Idx && "Mapping out of date!");
|
||||
Ctx->ScopeRecordIdx.erase(Cur);
|
||||
// Reset this VH to null and we're done.
|
||||
setValPtr(0);
|
||||
Idx = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, it is an entry in ScopeInlinedAtRecords, we don't know if it
|
||||
// is the scope or the inlined-at record entry.
|
||||
assert(unsigned(-Idx-1) < Ctx->ScopeInlinedAtRecords.size());
|
||||
std::pair<DebugRecVH, DebugRecVH> &Entry = Ctx->ScopeInlinedAtRecords[-Idx-1];
|
||||
assert((this == &Entry.first || this == &Entry.second) &&
|
||||
"Mapping out of date!");
|
||||
|
||||
MDNode *OldScope = Entry.first.get();
|
||||
MDNode *OldInlinedAt = Entry.second.get();
|
||||
assert(OldScope != 0 && OldInlinedAt != 0 &&
|
||||
"Entry should be non-canonical if either val dropped to null");
|
||||
|
||||
// Otherwise, we do have an entry in it, nuke it and we're done.
|
||||
assert(Ctx->ScopeInlinedAtIdx[std::make_pair(OldScope, OldInlinedAt)] == Idx&&
|
||||
"Mapping out of date");
|
||||
Ctx->ScopeInlinedAtIdx.erase(std::make_pair(OldScope, OldInlinedAt));
|
||||
|
||||
// Reset this VH to null.
|
||||
setValPtr(0);
|
||||
Idx = 0;
|
||||
}
|
||||
|
||||
void DebugRecVH::allUsesReplacedWith(Value *NewVa) {
|
||||
// If being replaced with a non-mdnode value (e.g. undef) handle this as if
|
||||
// the mdnode got deleted.
|
||||
MDNode *NewVal = dyn_cast<MDNode>(NewVa);
|
||||
if (NewVal == 0) return deleted();
|
||||
|
||||
// If this is a non-canonical reference, just change it, we know it already
|
||||
// doesn't have a map entry.
|
||||
if (Idx == 0) {
|
||||
setValPtr(NewVa);
|
||||
return;
|
||||
}
|
||||
|
||||
MDNode *OldVal = get();
|
||||
assert(OldVal != NewVa && "Node replaced with self?");
|
||||
|
||||
// If the index is positive, it is an entry in ScopeRecords.
|
||||
if (Idx > 0) {
|
||||
assert(Ctx->ScopeRecordIdx[OldVal] == Idx && "Mapping out of date!");
|
||||
Ctx->ScopeRecordIdx.erase(OldVal);
|
||||
setValPtr(NewVal);
|
||||
|
||||
int NewEntry = Ctx->getOrAddScopeRecordIdxEntry(NewVal, Idx);
|
||||
|
||||
// If NewVal already has an entry, this becomes a non-canonical reference,
|
||||
// just drop Idx to 0 to signify this.
|
||||
if (NewEntry != Idx)
|
||||
Idx = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, it is an entry in ScopeInlinedAtRecords, we don't know if it
|
||||
// is the scope or the inlined-at record entry.
|
||||
assert(unsigned(-Idx-1) < Ctx->ScopeInlinedAtRecords.size());
|
||||
std::pair<DebugRecVH, DebugRecVH> &Entry = Ctx->ScopeInlinedAtRecords[-Idx-1];
|
||||
assert((this == &Entry.first || this == &Entry.second) &&
|
||||
"Mapping out of date!");
|
||||
|
||||
MDNode *OldScope = Entry.first.get();
|
||||
MDNode *OldInlinedAt = Entry.second.get();
|
||||
assert(OldScope != 0 && OldInlinedAt != 0 &&
|
||||
"Entry should be non-canonical if either val dropped to null");
|
||||
|
||||
// Otherwise, we do have an entry in it, nuke it and we're done.
|
||||
assert(Ctx->ScopeInlinedAtIdx[std::make_pair(OldScope, OldInlinedAt)] == Idx&&
|
||||
"Mapping out of date");
|
||||
Ctx->ScopeInlinedAtIdx.erase(std::make_pair(OldScope, OldInlinedAt));
|
||||
|
||||
// Reset this VH to the new value.
|
||||
setValPtr(NewVal);
|
||||
|
||||
int NewIdx = Ctx->getOrAddScopeInlinedAtIdxEntry(Entry.first.get(),
|
||||
Entry.second.get(), Idx);
|
||||
// If NewVal already has an entry, this becomes a non-canonical reference,
|
||||
// just drop Idx to 0 to signify this.
|
||||
if (NewIdx != Idx)
|
||||
Idx = 0;
|
||||
}
|
@ -90,6 +90,29 @@ struct DenseMapAPFloatKeyInfo {
|
||||
}
|
||||
};
|
||||
|
||||
/// DebugRecVH - This is a CallbackVH used to keep the Scope -> index maps
|
||||
/// up to date as MDNodes mutate. This class is implemented in DebugLoc.cpp.
|
||||
class DebugRecVH : public CallbackVH {
|
||||
/// Ctx - This is the LLVM Context being referenced.
|
||||
LLVMContextImpl *Ctx;
|
||||
|
||||
/// Idx - The index into either ScopeRecordIdx or ScopeInlinedAtRecords that
|
||||
/// this reference lives in. If this is zero, then it represents a
|
||||
/// non-canonical entry that has no DenseMap value. This can happen due to
|
||||
/// RAUW.
|
||||
int Idx;
|
||||
public:
|
||||
DebugRecVH(MDNode *n, LLVMContextImpl *ctx, int idx)
|
||||
: CallbackVH(n), Ctx(ctx), Idx(idx) {}
|
||||
|
||||
MDNode *get() const {
|
||||
return cast_or_null<MDNode>(getValPtr());
|
||||
}
|
||||
|
||||
virtual void deleted();
|
||||
virtual void allUsesReplacedWith(Value *VNew);
|
||||
};
|
||||
|
||||
class LLVMContextImpl {
|
||||
public:
|
||||
typedef DenseMap<DenseMapAPIntKeyInfo::KeyTy, ConstantInt*,
|
||||
@ -128,7 +151,6 @@ public:
|
||||
VectorConstantsTy VectorConstants;
|
||||
|
||||
ConstantUniqueMap<char, PointerType, ConstantPointerNull> NullPtrConstants;
|
||||
|
||||
ConstantUniqueMap<char, Type, UndefValue> UndefValueConstants;
|
||||
|
||||
DenseMap<std::pair<Function*, BasicBlock*> , BlockAddress*> BlockAddresses;
|
||||
@ -195,6 +217,27 @@ public:
|
||||
/// context.
|
||||
DenseMap<const Instruction *, MDMapTy> MetadataStore;
|
||||
|
||||
/// ScopeRecordIdx - This is the index in ScopeRecords for an MDNode scope
|
||||
/// entry with no "inlined at" element.
|
||||
DenseMap<MDNode*, int> ScopeRecordIdx;
|
||||
|
||||
/// ScopeRecords - These are the actual mdnodes (in a value handle) for an
|
||||
/// index. The ValueHandle ensures that ScopeRecordIdx stays up to date if
|
||||
/// the MDNode is RAUW'd.
|
||||
std::vector<DebugRecVH> ScopeRecords;
|
||||
|
||||
/// ScopeInlinedAtIdx - This is the index in ScopeInlinedAtRecords for an
|
||||
/// scope/inlined-at pair.
|
||||
DenseMap<std::pair<MDNode*, MDNode*>, int> ScopeInlinedAtIdx;
|
||||
|
||||
/// ScopeInlinedAtRecords - These are the actual mdnodes (in value handles)
|
||||
/// for an index. The ValueHandle ensures that ScopeINlinedAtIdx stays up
|
||||
/// to date.
|
||||
std::vector<std::pair<DebugRecVH, DebugRecVH> > ScopeInlinedAtRecords;
|
||||
|
||||
int getOrAddScopeRecordIdxEntry(MDNode *N, int ExistingIdx);
|
||||
int getOrAddScopeInlinedAtIdxEntry(MDNode *Scope, MDNode *IA,int ExistingIdx);
|
||||
|
||||
LLVMContextImpl(LLVMContext &C);
|
||||
~LLVMContextImpl();
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user