forked from OSchip/llvm-project
Generate subprogram debug info with -g.
Also take care of freeing memory at the right places. llvm-svn: 51553
This commit is contained in:
parent
d042a969c9
commit
98070578bf
|
@ -133,6 +133,10 @@ public:
|
||||||
void addVolatile() { ThePtr |= Volatile; }
|
void addVolatile() { ThePtr |= Volatile; }
|
||||||
void addRestrict() { ThePtr |= Restrict; }
|
void addRestrict() { ThePtr |= Restrict; }
|
||||||
|
|
||||||
|
void removeConst() { ThePtr &= ~Const; }
|
||||||
|
void removeVolatile() { ThePtr &= ~Volatile; }
|
||||||
|
void removeRestrict() { ThePtr &= ~Restrict; }
|
||||||
|
|
||||||
QualType getQualifiedType(unsigned TQs) const {
|
QualType getQualifiedType(unsigned TQs) const {
|
||||||
return QualType(getTypePtr(), TQs);
|
return QualType(getTypePtr(), TQs);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,20 +13,20 @@
|
||||||
|
|
||||||
#include "CGDebugInfo.h"
|
#include "CGDebugInfo.h"
|
||||||
#include "CodeGenModule.h"
|
#include "CodeGenModule.h"
|
||||||
|
#include "clang/AST/ASTContext.h"
|
||||||
|
#include "clang/Basic/SourceManager.h"
|
||||||
|
#include "clang/Basic/FileManager.h"
|
||||||
#include "llvm/Constants.h"
|
#include "llvm/Constants.h"
|
||||||
#include "llvm/DerivedTypes.h"
|
#include "llvm/DerivedTypes.h"
|
||||||
#include "llvm/Instructions.h"
|
#include "llvm/Instructions.h"
|
||||||
#include "llvm/Intrinsics.h"
|
#include "llvm/Intrinsics.h"
|
||||||
#include "llvm/Module.h"
|
#include "llvm/Module.h"
|
||||||
#include "llvm/Support/Dwarf.h"
|
|
||||||
#include "llvm/Support/IRBuilder.h"
|
|
||||||
#include "llvm/Target/TargetMachine.h"
|
|
||||||
#include "llvm/ADT/StringExtras.h"
|
#include "llvm/ADT/StringExtras.h"
|
||||||
#include "llvm/ADT/SmallVector.h"
|
#include "llvm/ADT/SmallVector.h"
|
||||||
#include "llvm/CodeGen/MachineModuleInfo.h"
|
#include "llvm/CodeGen/MachineModuleInfo.h"
|
||||||
#include "clang/Basic/SourceManager.h"
|
#include "llvm/Support/Dwarf.h"
|
||||||
#include "clang/Basic/FileManager.h"
|
#include "llvm/Support/IRBuilder.h"
|
||||||
#include "clang/AST/ASTContext.h"
|
#include "llvm/Target/TargetMachine.h"
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
using namespace clang::CodeGen;
|
using namespace clang::CodeGen;
|
||||||
|
|
||||||
|
@ -35,13 +35,16 @@ CGDebugInfo::CGDebugInfo(CodeGenModule *m)
|
||||||
, CurLoc()
|
, CurLoc()
|
||||||
, PrevLoc()
|
, PrevLoc()
|
||||||
, CompileUnitCache()
|
, CompileUnitCache()
|
||||||
|
, TypeCache()
|
||||||
, StopPointFn(NULL)
|
, StopPointFn(NULL)
|
||||||
, CompileUnitAnchor(NULL)
|
, FuncStartFn(NULL)
|
||||||
, SubProgramAnchor(NULL)
|
, DeclareFn(NULL)
|
||||||
, RegionStartFn(NULL)
|
, RegionStartFn(NULL)
|
||||||
, RegionEndFn(NULL)
|
, RegionEndFn(NULL)
|
||||||
, FuncStartFn(NULL)
|
, CompileUnitAnchor(NULL)
|
||||||
, CurFuncDesc(NULL)
|
, SubprogramAnchor(NULL)
|
||||||
|
, RegionStack()
|
||||||
|
, Subprogram(NULL)
|
||||||
{
|
{
|
||||||
SR = new llvm::DISerializer();
|
SR = new llvm::DISerializer();
|
||||||
SR->setModule (&M->getModule());
|
SR->setModule (&M->getModule());
|
||||||
|
@ -50,19 +53,28 @@ CGDebugInfo::CGDebugInfo(CodeGenModule *m)
|
||||||
CGDebugInfo::~CGDebugInfo()
|
CGDebugInfo::~CGDebugInfo()
|
||||||
{
|
{
|
||||||
delete SR;
|
delete SR;
|
||||||
// Clean up allocated debug info; we can't do this until after the
|
|
||||||
// serializer is destroyed because it caches pointers to
|
// Free CompileUnitCache.
|
||||||
// the debug info
|
for (std::map<unsigned, llvm::CompileUnitDesc *>::iterator I
|
||||||
|
= CompileUnitCache.begin(); I != CompileUnitCache.end(); ++I) {
|
||||||
|
delete I->second;
|
||||||
|
}
|
||||||
|
CompileUnitCache.clear();
|
||||||
|
|
||||||
|
// Free TypeCache.
|
||||||
|
for (std::map<void *, llvm::TypeDesc *>::iterator I
|
||||||
|
= TypeCache.begin(); I != TypeCache.end(); ++I) {
|
||||||
|
delete I->second;
|
||||||
|
}
|
||||||
|
TypeCache.clear();
|
||||||
|
|
||||||
|
for (std::vector<llvm::DebugInfoDesc *>::iterator I
|
||||||
|
= RegionStack.begin(); I != RegionStack.end(); ++I) {
|
||||||
|
delete *I;
|
||||||
|
}
|
||||||
|
|
||||||
delete CompileUnitAnchor;
|
delete CompileUnitAnchor;
|
||||||
delete SubProgramAnchor;
|
delete SubprogramAnchor;
|
||||||
// Clean up compile unit descriptions
|
|
||||||
std::map<unsigned, llvm::CompileUnitDesc *>::iterator MI;
|
|
||||||
for (MI = CompileUnitCache.begin(); MI != CompileUnitCache.end(); ++MI)
|
|
||||||
delete MI->second;
|
|
||||||
// Clean up misc allocations
|
|
||||||
std::vector<llvm::DebugInfoDesc*>::iterator VI;
|
|
||||||
for (VI = DebugAllocationList.begin(); VI != DebugAllocationList.end(); ++VI)
|
|
||||||
delete *VI;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -73,6 +85,12 @@ llvm::Value *CGDebugInfo::getCastValueFor(llvm::DebugInfoDesc *DD) {
|
||||||
SR->getEmptyStructPtrType());
|
SR->getEmptyStructPtrType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// getValueFor - Return a llvm representation for a given debug information
|
||||||
|
/// descriptor.
|
||||||
|
llvm::Value *CGDebugInfo::getValueFor(llvm::DebugInfoDesc *DD) {
|
||||||
|
return SR->Serialize(DD);
|
||||||
|
}
|
||||||
|
|
||||||
/// getOrCreateCompileUnit - Get the compile unit from the cache or create a new
|
/// getOrCreateCompileUnit - Get the compile unit from the cache or create a new
|
||||||
/// one if necessary.
|
/// one if necessary.
|
||||||
llvm::CompileUnitDesc
|
llvm::CompileUnitDesc
|
||||||
|
@ -123,10 +141,313 @@ llvm::CompileUnitDesc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
llvm::TypeDesc *
|
||||||
CGDebugInfo::EmitStopPoint(llvm::Function *Fn, llvm::IRBuilder &Builder) {
|
CGDebugInfo::getOrCreateCVRType(QualType type, llvm::CompileUnitDesc *Unit)
|
||||||
if (CurLoc.isInvalid() || CurLoc.isMacroID()) return;
|
{
|
||||||
|
// We will create a Derived type.
|
||||||
|
llvm::DerivedTypeDesc *DTy = NULL;
|
||||||
|
llvm::TypeDesc *FromTy = NULL;
|
||||||
|
|
||||||
|
if (type.isConstQualified()) {
|
||||||
|
DTy = new llvm::DerivedTypeDesc(llvm::dwarf::DW_TAG_const_type);
|
||||||
|
type.removeConst();
|
||||||
|
FromTy = getOrCreateType(type, Unit);
|
||||||
|
} else if (type.isVolatileQualified()) {
|
||||||
|
DTy = new llvm::DerivedTypeDesc(llvm::dwarf::DW_TAG_volatile_type);
|
||||||
|
type.removeVolatile();
|
||||||
|
FromTy = getOrCreateType(type, Unit);
|
||||||
|
} else if (type.isRestrictQualified()) {
|
||||||
|
DTy = new llvm::DerivedTypeDesc(llvm::dwarf::DW_TAG_restrict_type);
|
||||||
|
type.removeRestrict();
|
||||||
|
FromTy = getOrCreateType(type, Unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
// No need to fill in the Name, Line, Size, Alignment, Offset in case of // CVR derived types.
|
||||||
|
DTy->setContext(Unit);
|
||||||
|
DTy->setFromType(FromTy);
|
||||||
|
|
||||||
|
return DTy;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// getOrCreateType - Get the Basic type from the cache or create a new
|
||||||
|
/// one if necessary.
|
||||||
|
llvm::TypeDesc *
|
||||||
|
CGDebugInfo::getOrCreateBuiltinType(QualType type, llvm::CompileUnitDesc *Unit)
|
||||||
|
{
|
||||||
|
assert (type->getTypeClass() == Type::Builtin);
|
||||||
|
|
||||||
|
const BuiltinType *BT = type->getAsBuiltinType();
|
||||||
|
|
||||||
|
unsigned Encoding = 0;
|
||||||
|
switch (BT->getKind())
|
||||||
|
{
|
||||||
|
case BuiltinType::Void:
|
||||||
|
return NULL;
|
||||||
|
case BuiltinType::UChar:
|
||||||
|
case BuiltinType::Char_U:
|
||||||
|
Encoding = llvm::dwarf::DW_ATE_unsigned_char;
|
||||||
|
break;
|
||||||
|
case BuiltinType::Char_S:
|
||||||
|
case BuiltinType::SChar:
|
||||||
|
Encoding = llvm::dwarf::DW_ATE_signed_char;
|
||||||
|
break;
|
||||||
|
case BuiltinType::UShort:
|
||||||
|
case BuiltinType::UInt:
|
||||||
|
case BuiltinType::ULong:
|
||||||
|
case BuiltinType::ULongLong:
|
||||||
|
Encoding = llvm::dwarf::DW_ATE_unsigned;
|
||||||
|
break;
|
||||||
|
case BuiltinType::Short:
|
||||||
|
case BuiltinType::Int:
|
||||||
|
case BuiltinType::Long:
|
||||||
|
case BuiltinType::LongLong:
|
||||||
|
Encoding = llvm::dwarf::DW_ATE_signed;
|
||||||
|
break;
|
||||||
|
case BuiltinType::Bool:
|
||||||
|
Encoding = llvm::dwarf::DW_ATE_boolean;
|
||||||
|
break;
|
||||||
|
case BuiltinType::Float:
|
||||||
|
case BuiltinType::Double:
|
||||||
|
Encoding = llvm::dwarf::DW_ATE_float;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Encoding = llvm::dwarf::DW_ATE_signed;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ty will have contain the resulting type.
|
||||||
|
llvm::BasicTypeDesc *BTy = new llvm::BasicTypeDesc();
|
||||||
|
|
||||||
|
// Get the name and location early to assist debugging.
|
||||||
|
const char *TyName = BT->getName();
|
||||||
|
|
||||||
|
// Bit size, align and offset of the type.
|
||||||
|
uint64_t Size = M->getContext().getTypeSize(type);
|
||||||
|
uint64_t Align = M->getContext().getTypeAlign(type);
|
||||||
|
uint64_t Offset = 0;
|
||||||
|
|
||||||
|
// If the type is defined, fill in the details.
|
||||||
|
if (BTy) {
|
||||||
|
BTy->setContext(Unit);
|
||||||
|
BTy->setName(TyName);
|
||||||
|
BTy->setSize(Size);
|
||||||
|
BTy->setAlign(Align);
|
||||||
|
BTy->setOffset(Offset);
|
||||||
|
BTy->setEncoding(Encoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
return BTy;
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm::TypeDesc *
|
||||||
|
CGDebugInfo::getOrCreatePointerType(QualType type, llvm::CompileUnitDesc *Unit)
|
||||||
|
{
|
||||||
|
// type*
|
||||||
|
llvm::DerivedTypeDesc *DTy =
|
||||||
|
new llvm::DerivedTypeDesc(llvm::dwarf::DW_TAG_pointer_type);
|
||||||
|
|
||||||
|
// Handle the derived type.
|
||||||
|
const PointerType *PTRT = type->getAsPointerType();
|
||||||
|
llvm::TypeDesc *FromTy = getOrCreateType(PTRT->getPointeeType(), Unit);
|
||||||
|
|
||||||
|
// Get the name and location early to assist debugging.
|
||||||
|
SourceManager &SM = M->getContext().getSourceManager();
|
||||||
|
uint64_t Line = SM.getLogicalLineNumber(CurLoc);
|
||||||
|
|
||||||
|
// Bit size, align and offset of the type.
|
||||||
|
uint64_t Size = M->getContext().getTypeSize(type);
|
||||||
|
uint64_t Align = M->getContext().getTypeAlign(type);
|
||||||
|
uint64_t Offset = 0;
|
||||||
|
|
||||||
|
// If the type is defined, fill in the details.
|
||||||
|
if (DTy) {
|
||||||
|
DTy->setContext(Unit);
|
||||||
|
DTy->setLine(Line);
|
||||||
|
DTy->setSize(Size);
|
||||||
|
DTy->setAlign(Align);
|
||||||
|
DTy->setOffset(Offset);
|
||||||
|
DTy->setFromType(FromTy);
|
||||||
|
}
|
||||||
|
|
||||||
|
return DTy;
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm::TypeDesc *
|
||||||
|
CGDebugInfo::getOrCreateTypedefType(QualType type, llvm::CompileUnitDesc *Unit)
|
||||||
|
{
|
||||||
|
// typedefs are derived from some other type.
|
||||||
|
llvm::DerivedTypeDesc *DTy =
|
||||||
|
new llvm::DerivedTypeDesc(llvm::dwarf::DW_TAG_typedef);
|
||||||
|
|
||||||
|
// Handle derived type.
|
||||||
|
const TypedefType *TDT = type->getAsTypedefType();
|
||||||
|
llvm::TypeDesc *FromTy = getOrCreateType(TDT->LookThroughTypedefs(),
|
||||||
|
Unit);
|
||||||
|
|
||||||
|
// Get the name and location early to assist debugging.
|
||||||
|
const char *TyName = TDT->getDecl()->getName();
|
||||||
|
SourceManager &SM = M->getContext().getSourceManager();
|
||||||
|
uint64_t Line = SM.getLogicalLineNumber(TDT->getDecl()->getLocation());
|
||||||
|
|
||||||
|
// If the type is defined, fill in the details.
|
||||||
|
if (DTy) {
|
||||||
|
DTy->setContext(Unit);
|
||||||
|
DTy->setFile(getOrCreateCompileUnit(TDT->getDecl()->getLocation()));
|
||||||
|
DTy->setLine(Line);
|
||||||
|
DTy->setName(TyName);
|
||||||
|
DTy->setFromType(FromTy);
|
||||||
|
}
|
||||||
|
|
||||||
|
return DTy;
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm::TypeDesc *
|
||||||
|
CGDebugInfo::getOrCreateFunctionType(QualType type, llvm::CompileUnitDesc *Unit)
|
||||||
|
{
|
||||||
|
llvm::CompositeTypeDesc *SubrTy =
|
||||||
|
new llvm::CompositeTypeDesc(llvm::dwarf::DW_TAG_subroutine_type);
|
||||||
|
|
||||||
|
// Prepare to add the arguments for the subroutine.
|
||||||
|
std::vector<llvm::DebugInfoDesc *> &Elements = SubrTy->getElements();
|
||||||
|
|
||||||
|
// Get result type.
|
||||||
|
const FunctionType *FT = type->getAsFunctionType();
|
||||||
|
llvm::TypeDesc *ArgTy = getOrCreateType(FT->getResultType(), Unit);
|
||||||
|
if (ArgTy) Elements.push_back(ArgTy);
|
||||||
|
|
||||||
|
// Set up remainder of arguments.
|
||||||
|
if (type->getTypeClass() == Type::FunctionProto) {
|
||||||
|
const FunctionTypeProto *FTPro = dyn_cast<FunctionTypeProto>(type);
|
||||||
|
for (unsigned int i =0; i < FTPro->getNumArgs(); i++) {
|
||||||
|
QualType ParamType = FTPro->getArgType(i);
|
||||||
|
ArgTy = getOrCreateType(ParamType, Unit);
|
||||||
|
if (ArgTy) Elements.push_back(ArgTy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: set other fields file, line here.
|
||||||
|
SubrTy->setContext(Unit);
|
||||||
|
|
||||||
|
return SubrTy;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// getOrCreateType - Get the type from the cache or create a new
|
||||||
|
/// one if necessary.
|
||||||
|
llvm::TypeDesc *
|
||||||
|
CGDebugInfo::getOrCreateType(QualType type, llvm::CompileUnitDesc *Unit)
|
||||||
|
{
|
||||||
|
if (type.isNull())
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// Check to see if the compile unit already has created this type.
|
||||||
|
llvm::TypeDesc *&Slot = TypeCache[type.getAsOpaquePtr()];
|
||||||
|
if (Slot) return Slot;
|
||||||
|
|
||||||
|
// We need to check for the CVR qualifiers as the first thing.
|
||||||
|
if (type.getCVRQualifiers()) {
|
||||||
|
Slot = getOrCreateCVRType (type, Unit);
|
||||||
|
return Slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Work out details of type.
|
||||||
|
switch(type->getTypeClass()) {
|
||||||
|
case Type::Complex:
|
||||||
|
case Type::Reference:
|
||||||
|
case Type::ConstantArray:
|
||||||
|
case Type::VariableArray:
|
||||||
|
case Type::IncompleteArray:
|
||||||
|
case Type::Vector:
|
||||||
|
case Type::ExtVector:
|
||||||
|
case Type::Tagged:
|
||||||
|
case Type::ASQual:
|
||||||
|
case Type::ObjCInterface:
|
||||||
|
case Type::ObjCQualifiedInterface:
|
||||||
|
case Type::ObjCQualifiedId:
|
||||||
|
case Type::TypeOfExp:
|
||||||
|
case Type::TypeOfTyp:
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
assert (0 && "Unsupported type");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Type::TypeName:
|
||||||
|
Slot = getOrCreateTypedefType(type, Unit);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Type::FunctionProto:
|
||||||
|
case Type::FunctionNoProto:
|
||||||
|
Slot = getOrCreateFunctionType(type, Unit);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Type::Builtin:
|
||||||
|
Slot = getOrCreateBuiltinType(type, Unit);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Type::Pointer:
|
||||||
|
Slot = getOrCreatePointerType(type, Unit);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// EmitFunctionStart - Constructs the debug code for entering a function -
|
||||||
|
/// "llvm.dbg.func.start.".
|
||||||
|
void CGDebugInfo::EmitFunctionStart(const FunctionDecl *FnDecl,
|
||||||
|
llvm::Function *Fn,
|
||||||
|
llvm::IRBuilder &Builder)
|
||||||
|
{
|
||||||
|
// Create subprogram descriptor.
|
||||||
|
Subprogram = new llvm::SubprogramDesc();
|
||||||
|
|
||||||
|
// Make sure we have an anchor.
|
||||||
|
if (!SubprogramAnchor) {
|
||||||
|
SubprogramAnchor = new llvm::AnchorDesc(Subprogram);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get name information.
|
||||||
|
Subprogram->setName(FnDecl->getName());
|
||||||
|
Subprogram->setFullName(FnDecl->getName());
|
||||||
|
|
||||||
|
// Gather location information.
|
||||||
|
llvm::CompileUnitDesc *Unit = getOrCreateCompileUnit(CurLoc);
|
||||||
|
SourceManager &SM = M->getContext().getSourceManager();
|
||||||
|
uint64_t Loc = SM.getLogicalLineNumber(CurLoc);
|
||||||
|
|
||||||
|
// Get Function Type.
|
||||||
|
QualType type = FnDecl->getResultType();
|
||||||
|
llvm::TypeDesc *SPTy = getOrCreateType(type, Unit);
|
||||||
|
|
||||||
|
Subprogram->setAnchor(SubprogramAnchor);
|
||||||
|
Subprogram->setContext(Unit);
|
||||||
|
Subprogram->setFile(Unit);
|
||||||
|
Subprogram->setLine(Loc);
|
||||||
|
Subprogram->setType(SPTy);
|
||||||
|
Subprogram->setIsStatic(Fn->hasInternalLinkage());
|
||||||
|
Subprogram->setIsDefinition(true);
|
||||||
|
|
||||||
|
// Lazily construct llvm.dbg.func.start.
|
||||||
|
if (!FuncStartFn)
|
||||||
|
FuncStartFn = llvm::Intrinsic::getDeclaration(&M->getModule(),
|
||||||
|
llvm::Intrinsic::dbg_func_start);
|
||||||
|
|
||||||
|
// Call llvm.dbg.func.start which also implicitly calls llvm.dbg.stoppoint.
|
||||||
|
Builder.CreateCall(FuncStartFn, getCastValueFor(Subprogram), "");
|
||||||
|
|
||||||
|
// Push function on region stack.
|
||||||
|
RegionStack.push_back(Subprogram);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
CGDebugInfo::EmitStopPoint(llvm::Function *Fn, llvm::IRBuilder &Builder)
|
||||||
|
{
|
||||||
|
if (CurLoc.isInvalid() || CurLoc.isMacroID()) return;
|
||||||
|
|
||||||
// Don't bother if things are the same as last time.
|
// Don't bother if things are the same as last time.
|
||||||
SourceManager &SM = M->getContext().getSourceManager();
|
SourceManager &SM = M->getContext().getSourceManager();
|
||||||
if (CurLoc == PrevLoc
|
if (CurLoc == PrevLoc
|
||||||
|
@ -157,35 +478,25 @@ CGDebugInfo::EmitStopPoint(llvm::Function *Fn, llvm::IRBuilder &Builder) {
|
||||||
|
|
||||||
/// EmitRegionStart- Constructs the debug code for entering a declarative
|
/// EmitRegionStart- Constructs the debug code for entering a declarative
|
||||||
/// region - "llvm.dbg.region.start.".
|
/// region - "llvm.dbg.region.start.".
|
||||||
void CGDebugInfo::EmitFunctionStart(llvm::Function *Fn, llvm::IRBuilder &Builder)
|
void CGDebugInfo::EmitRegionStart(llvm::Function *Fn, llvm::IRBuilder &Builder)
|
||||||
{
|
{
|
||||||
// Get the appropriate compile unit.
|
llvm::BlockDesc *Block = new llvm::BlockDesc();
|
||||||
llvm::CompileUnitDesc *Unit = getOrCreateCompileUnit(CurLoc);
|
if (RegionStack.size() > 0)
|
||||||
|
Block->setContext(RegionStack.back());
|
||||||
|
RegionStack.push_back(Block);
|
||||||
|
|
||||||
llvm::SubprogramDesc* Block = new llvm::SubprogramDesc;
|
// Lazily construct llvm.dbg.region.start function.
|
||||||
DebugAllocationList.push_back(Block);
|
if (!RegionStartFn)
|
||||||
Block->setFile(Unit);
|
RegionStartFn = llvm::Intrinsic::getDeclaration(&M->getModule(),
|
||||||
Block->setContext(Unit);
|
llvm::Intrinsic::dbg_region_start);
|
||||||
if (!SubProgramAnchor) {
|
|
||||||
SubProgramAnchor = new llvm::AnchorDesc(Block);
|
// Call llvm.dbg.func.start.
|
||||||
SR->Serialize(SubProgramAnchor);
|
Builder.CreateCall(RegionStartFn, getCastValueFor(Block), "");
|
||||||
}
|
|
||||||
Block->setAnchor(SubProgramAnchor);
|
|
||||||
Block->setName(Fn->getName());
|
|
||||||
Block->setFullName(Fn->getName());
|
|
||||||
Block->setIsDefinition(true);
|
|
||||||
SourceManager &SM = M->getContext().getSourceManager();
|
|
||||||
Block->setLine(SM.getLogicalLineNumber(CurLoc));
|
|
||||||
CurFuncDesc = getCastValueFor(Block);
|
|
||||||
if (!FuncStartFn)
|
|
||||||
FuncStartFn = llvm::Intrinsic::getDeclaration(&M->getModule(),
|
|
||||||
llvm::Intrinsic::dbg_func_start);
|
|
||||||
Builder.CreateCall(FuncStartFn, CurFuncDesc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// EmitRegionEnd - Constructs the debug code for exiting a declarative
|
/// EmitRegionEnd - Constructs the debug code for exiting a declarative
|
||||||
/// region - "llvm.dbg.region.end."
|
/// region - "llvm.dbg.region.end."
|
||||||
void CGDebugInfo::EmitFunctionEnd(llvm::Function *Fn, llvm::IRBuilder &Builder)
|
void CGDebugInfo::EmitRegionEnd(llvm::Function *Fn, llvm::IRBuilder &Builder)
|
||||||
{
|
{
|
||||||
// Lazily construct llvm.dbg.region.end function.
|
// Lazily construct llvm.dbg.region.end function.
|
||||||
if (!RegionEndFn)
|
if (!RegionEndFn)
|
||||||
|
@ -196,6 +507,8 @@ void CGDebugInfo::EmitFunctionEnd(llvm::Function *Fn, llvm::IRBuilder &Builder)
|
||||||
EmitStopPoint(Fn, Builder);
|
EmitStopPoint(Fn, Builder);
|
||||||
|
|
||||||
// Call llvm.dbg.func.end.
|
// Call llvm.dbg.func.end.
|
||||||
Builder.CreateCall(RegionEndFn, CurFuncDesc, "");
|
llvm::DebugInfoDesc *DID = RegionStack.back();
|
||||||
|
Builder.CreateCall(RegionEndFn, getCastValueFor(DID), "");
|
||||||
|
RegionStack.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#ifndef CLANG_CODEGEN_CGDEBUGINFO_H
|
#ifndef CLANG_CODEGEN_CGDEBUGINFO_H
|
||||||
#define CLANG_CODEGEN_CGDEBUGINFO_H
|
#define CLANG_CODEGEN_CGDEBUGINFO_H
|
||||||
|
|
||||||
|
#include "clang/AST/Type.h"
|
||||||
#include "clang/Basic/SourceLocation.h"
|
#include "clang/Basic/SourceLocation.h"
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -28,14 +29,18 @@ namespace llvm {
|
||||||
class AnchorDesc;
|
class AnchorDesc;
|
||||||
class DebugInfoDesc;
|
class DebugInfoDesc;
|
||||||
class Value;
|
class Value;
|
||||||
|
class TypeDesc;
|
||||||
|
class SubprogramDesc;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace clang {
|
namespace clang {
|
||||||
|
class FunctionDecl;
|
||||||
namespace CodeGen {
|
namespace CodeGen {
|
||||||
class CodeGenModule;
|
class CodeGenModule;
|
||||||
|
|
||||||
/// DebugInfo - This class gathers all debug information during compilation and
|
/// CGDebugInfo - This class gathers all debug information during compilation
|
||||||
/// is responsible for emitting to llvm globals or pass directly to the backend.
|
/// and is responsible for emitting to llvm globals or pass directly to
|
||||||
|
/// the backend.
|
||||||
class CGDebugInfo {
|
class CGDebugInfo {
|
||||||
private:
|
private:
|
||||||
CodeGenModule *M;
|
CodeGenModule *M;
|
||||||
|
@ -45,41 +50,70 @@ private:
|
||||||
|
|
||||||
/// CompileUnitCache - Cache of previously constructed CompileUnits.
|
/// CompileUnitCache - Cache of previously constructed CompileUnits.
|
||||||
std::map<unsigned, llvm::CompileUnitDesc *> CompileUnitCache;
|
std::map<unsigned, llvm::CompileUnitDesc *> CompileUnitCache;
|
||||||
std::vector<llvm::DebugInfoDesc*> DebugAllocationList;
|
|
||||||
|
/// TypeCache - Cache of previously constructed Types.
|
||||||
|
std::map<void *, llvm::TypeDesc *> TypeCache;
|
||||||
|
|
||||||
llvm::Function *StopPointFn;
|
llvm::Function *StopPointFn;
|
||||||
llvm::AnchorDesc *CompileUnitAnchor;
|
llvm::Function *FuncStartFn;
|
||||||
llvm::AnchorDesc *SubProgramAnchor;
|
llvm::Function *DeclareFn;
|
||||||
llvm::Function *RegionStartFn;
|
llvm::Function *RegionStartFn;
|
||||||
llvm::Function *RegionEndFn;
|
llvm::Function *RegionEndFn;
|
||||||
llvm::Function *FuncStartFn;
|
llvm::AnchorDesc *CompileUnitAnchor;
|
||||||
llvm::Value *CurFuncDesc;
|
llvm::AnchorDesc *SubprogramAnchor;
|
||||||
|
std::vector<llvm::DebugInfoDesc *> RegionStack;
|
||||||
|
llvm::SubprogramDesc *Subprogram;
|
||||||
|
|
||||||
/// getOrCreateCompileUnit - Get the compile unit from the cache or create a
|
/// Helper functions for getOrCreateType.
|
||||||
/// new one if necessary.
|
llvm::TypeDesc *getOrCreateCVRType(QualType type,
|
||||||
llvm::CompileUnitDesc *getOrCreateCompileUnit(SourceLocation loc);
|
llvm::CompileUnitDesc *unit);
|
||||||
|
llvm::TypeDesc *getOrCreateBuiltinType(QualType type,
|
||||||
/// getCastValueFor - Return a llvm representation for a given debug
|
llvm::CompileUnitDesc *unit);
|
||||||
/// information descriptor cast to an empty struct pointer.
|
llvm::TypeDesc *getOrCreateTypedefType(QualType type,
|
||||||
llvm::Value *getCastValueFor(llvm::DebugInfoDesc *DD);
|
llvm::CompileUnitDesc *unit);
|
||||||
|
llvm::TypeDesc *getOrCreatePointerType(QualType type,
|
||||||
|
llvm::CompileUnitDesc *unit);
|
||||||
|
llvm::TypeDesc *getOrCreateFunctionType(QualType type,
|
||||||
|
llvm::CompileUnitDesc *unit);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CGDebugInfo(CodeGenModule *m);
|
CGDebugInfo(CodeGenModule *m);
|
||||||
~CGDebugInfo();
|
~CGDebugInfo();
|
||||||
|
|
||||||
void setLocation(SourceLocation loc) { CurLoc = loc; };
|
void setLocation(SourceLocation loc) { CurLoc = loc; }
|
||||||
|
|
||||||
/// EmitStopPoint - Emit a call to llvm.dbg.stoppoint to indicate a change of
|
/// EmitStopPoint - Emit a call to llvm.dbg.stoppoint to indicate a change of
|
||||||
/// source line.
|
/// source line.
|
||||||
void EmitStopPoint(llvm::Function *Fn, llvm::IRBuilder &Builder);
|
void EmitStopPoint(llvm::Function *Fn, llvm::IRBuilder &Builder);
|
||||||
|
|
||||||
|
/// EmitFunctionStart - Emit a call to llvm.dbg.function.start to indicate
|
||||||
|
/// start of a new function
|
||||||
|
void EmitFunctionStart(const FunctionDecl *FnDecl, llvm::Function *Fn,
|
||||||
|
llvm::IRBuilder &Builder);
|
||||||
|
|
||||||
/// EmitFunctionStart - Emit a call to llvm.dbg.func.start to indicate start
|
/// EmitRegionStart - Emit a call to llvm.dbg.region.start to indicate start
|
||||||
/// of a new block.
|
/// of a new block.
|
||||||
void EmitFunctionStart(llvm::Function *Fn, llvm::IRBuilder &Builder);
|
void EmitRegionStart(llvm::Function *Fn, llvm::IRBuilder &Builder);
|
||||||
|
|
||||||
/// EmitFunctionEnd - Emit call to llvm.dbg.region.end to indicate end of a
|
/// EmitRegionEnd - Emit call to llvm.dbg.region.end to indicate end of a
|
||||||
/// block.
|
/// block.
|
||||||
void EmitFunctionEnd(llvm::Function *Fn, llvm::IRBuilder &Builder);
|
void EmitRegionEnd(llvm::Function *Fn, llvm::IRBuilder &Builder);
|
||||||
|
|
||||||
|
/// getOrCreateCompileUnit - Get the compile unit from the cache or create a
|
||||||
|
/// new one if necessary.
|
||||||
|
llvm::CompileUnitDesc *getOrCreateCompileUnit(SourceLocation loc);
|
||||||
|
|
||||||
|
/// getOrCreateType - Get the type from the cache or create a new type if
|
||||||
|
/// necessary.
|
||||||
|
llvm::TypeDesc *getOrCreateType(QualType type, llvm::CompileUnitDesc *unit);
|
||||||
|
|
||||||
|
/// getCastValueFor - Return a llvm representation for a given debug
|
||||||
|
/// information descriptor cast to an empty struct pointer.
|
||||||
|
llvm::Value *getCastValueFor(llvm::DebugInfoDesc *DD);
|
||||||
|
|
||||||
|
/// getValueFor - Return a llvm representation for a given debug information
|
||||||
|
/// descriptor.
|
||||||
|
llvm::Value *getValueFor(llvm::DebugInfoDesc *DD);
|
||||||
};
|
};
|
||||||
} // namespace CodeGen
|
} // namespace CodeGen
|
||||||
} // namespace clang
|
} // namespace clang
|
||||||
|
|
|
@ -88,10 +88,25 @@ RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast,
|
||||||
// FIXME: handle vla's etc.
|
// FIXME: handle vla's etc.
|
||||||
if (S.body_empty() || !isa<Expr>(S.body_back())) GetLast = false;
|
if (S.body_empty() || !isa<Expr>(S.body_back())) GetLast = false;
|
||||||
|
|
||||||
|
CGDebugInfo *DI = CGM.getDebugInfo();
|
||||||
|
if (DI) {
|
||||||
|
if (S.getLBracLoc().isValid()) {
|
||||||
|
DI->setLocation(S.getLBracLoc());
|
||||||
|
}
|
||||||
|
DI->EmitRegionStart(CurFn, Builder);
|
||||||
|
}
|
||||||
|
|
||||||
for (CompoundStmt::const_body_iterator I = S.body_begin(),
|
for (CompoundStmt::const_body_iterator I = S.body_begin(),
|
||||||
E = S.body_end()-GetLast; I != E; ++I)
|
E = S.body_end()-GetLast; I != E; ++I)
|
||||||
EmitStmt(*I);
|
EmitStmt(*I);
|
||||||
|
|
||||||
|
if (DI) {
|
||||||
|
if (S.getRBracLoc().isValid()) {
|
||||||
|
DI->setLocation(S.getRBracLoc());
|
||||||
|
}
|
||||||
|
DI->EmitRegionEnd(CurFn, Builder);
|
||||||
|
}
|
||||||
|
|
||||||
if (!GetLast)
|
if (!GetLast)
|
||||||
return RValue::get(0);
|
return RValue::get(0);
|
||||||
|
|
||||||
|
@ -368,15 +383,6 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
|
||||||
EmitAggExpr(RV, SRetPtr, false);
|
EmitAggExpr(RV, SRetPtr, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
CGDebugInfo *DI = CGM.getDebugInfo();
|
|
||||||
if (DI) {
|
|
||||||
CompoundStmt* body = cast<CompoundStmt>(CurFuncDecl->getBody());
|
|
||||||
if (body->getRBracLoc().isValid()) {
|
|
||||||
DI->setLocation(body->getRBracLoc());
|
|
||||||
}
|
|
||||||
DI->EmitFunctionEnd(CurFn, Builder);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (RetValue) {
|
if (RetValue) {
|
||||||
Builder.CreateRet(RetValue);
|
Builder.CreateRet(RetValue);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -205,7 +205,7 @@ void CodeGenFunction::GenerateCode(const FunctionDecl *FD) {
|
||||||
if (body->getLBracLoc().isValid()) {
|
if (body->getLBracLoc().isValid()) {
|
||||||
DI->setLocation(body->getLBracLoc());
|
DI->setLocation(body->getLBracLoc());
|
||||||
}
|
}
|
||||||
DI->EmitFunctionStart(CurFn, Builder);
|
DI->EmitFunctionStart(FD, CurFn, Builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emit allocs for param decls. Give the LLVM Argument nodes names.
|
// Emit allocs for param decls. Give the LLVM Argument nodes names.
|
||||||
|
@ -225,21 +225,20 @@ void CodeGenFunction::GenerateCode(const FunctionDecl *FD) {
|
||||||
// Emit the function body.
|
// Emit the function body.
|
||||||
EmitStmt(FD->getBody());
|
EmitStmt(FD->getBody());
|
||||||
|
|
||||||
|
if (DI) {
|
||||||
|
CompoundStmt* body = cast<CompoundStmt>(CurFuncDecl->getBody());
|
||||||
|
if (body->getRBracLoc().isValid()) {
|
||||||
|
DI->setLocation(body->getRBracLoc());
|
||||||
|
}
|
||||||
|
DI->EmitRegionEnd(CurFn, Builder);
|
||||||
|
}
|
||||||
|
|
||||||
// Emit a return for code that falls off the end. If insert point
|
// Emit a return for code that falls off the end. If insert point
|
||||||
// is a dummy block with no predecessors then remove the block itself.
|
// is a dummy block with no predecessors then remove the block itself.
|
||||||
llvm::BasicBlock *BB = Builder.GetInsertBlock();
|
llvm::BasicBlock *BB = Builder.GetInsertBlock();
|
||||||
if (isDummyBlock(BB))
|
if (isDummyBlock(BB))
|
||||||
BB->eraseFromParent();
|
BB->eraseFromParent();
|
||||||
else {
|
else {
|
||||||
CGDebugInfo *DI = CGM.getDebugInfo();
|
|
||||||
if (DI) {
|
|
||||||
CompoundStmt* body = cast<CompoundStmt>(CurFuncDecl->getBody());
|
|
||||||
if (body->getRBracLoc().isValid()) {
|
|
||||||
DI->setLocation(body->getRBracLoc());
|
|
||||||
}
|
|
||||||
DI->EmitFunctionEnd(CurFn, Builder);
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: if this is C++ main, this should return 0.
|
// FIXME: if this is C++ main, this should return 0.
|
||||||
if (CurFn->getReturnType() == llvm::Type::VoidTy)
|
if (CurFn->getReturnType() == llvm::Type::VoidTy)
|
||||||
Builder.CreateRetVoid();
|
Builder.CreateRetVoid();
|
||||||
|
|
Loading…
Reference in New Issue