[llvm-commits] [llvm-gcc-4.2] r104842 - in /llvm-gcc-4.2/trunk/gcc: llvm-backend.cpp llvm-convert.cpp llvm-debug.cpp llvm-debug.h llvm-internal.h
Stuart Hastings
stuart at apple.com
Thu May 27 09:16:58 PDT 2010
Author: stuart
Date: Thu May 27 11:16:58 2010
New Revision: 104842
URL: http://llvm.org/viewvc/llvm-project?rev=104842&view=rev
Log:
Support for nested functions/classes in debug output. Radar 7424645.
Modified:
llvm-gcc-4.2/trunk/gcc/llvm-backend.cpp
llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp
llvm-gcc-4.2/trunk/gcc/llvm-debug.cpp
llvm-gcc-4.2/trunk/gcc/llvm-debug.h
llvm-gcc-4.2/trunk/gcc/llvm-internal.h
Modified: llvm-gcc-4.2/trunk/gcc/llvm-backend.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/gcc/llvm-backend.cpp?rev=104842&r1=104841&r2=104842&view=diff
==============================================================================
--- llvm-gcc-4.2/trunk/gcc/llvm-backend.cpp (original)
+++ llvm-gcc-4.2/trunk/gcc/llvm-backend.cpp Thu May 27 11:16:58 2010
@@ -531,6 +531,8 @@
if (debug_info_level > DINFO_LEVEL_NONE)
TheDebugInfo = new DebugInfo(TheModule);
+ else
+ TheDebugInfo = 0;
}
/// performLateBackendInitialization - Set backend options that may only be
@@ -1023,7 +1025,7 @@
// Convert the AST to raw/ugly LLVM code.
Function *Fn;
{
- TreeToLLVM Emitter(fndecl);
+ TreeToLLVM *Emitter = new TreeToLLVM(fndecl);
enum symbol_visibility vis = DECL_VISIBILITY (fndecl);
if (vis != VISIBILITY_DEFAULT)
@@ -1031,7 +1033,8 @@
// visibility that's not supported by the target.
targetm.asm_out.visibility(fndecl, vis);
- Fn = Emitter.EmitFunction();
+ Fn = TheTreeToLLVM->EmitFunction();
+ Emitter->~TreeToLLVM();
}
#if 0
Modified: llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp?rev=104842&r1=104841&r2=104842&view=diff
==============================================================================
--- llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp (original)
+++ llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp Thu May 27 11:16:58 2010
@@ -148,7 +148,7 @@
//===----------------------------------------------------------------------===//
/// TheTreeToLLVM - Keep track of the current function being compiled.
-static TreeToLLVM *TheTreeToLLVM = 0;
+TreeToLLVM *TheTreeToLLVM = 0;
const TargetData &getTargetData() {
return *TheTarget->getTargetData();
@@ -157,7 +157,7 @@
/// EmitDebugInfo - Return true if debug info is to be emitted for current
/// function.
bool TreeToLLVM::EmitDebugInfo() {
- if (TheDebugInfo && !DECL_IGNORED_P(getFUNCTION_DECL()))
+ if (TheDebugInfo && getFUNCTION_DECL() && !DECL_IGNORED_P(getFUNCTION_DECL()))
return true;
return false;
}
@@ -425,13 +425,13 @@
return (Val = false);
}
-// Walk the GCC BLOCK() tree. Set BLOCK_NUMBER() to the depth of each
-// block; this is necessary for lexical block debug info. Visit all
-// the BLOCK_VARS(), and add them to the set s. Since the
-// unexpanded_var_list seems to be a superset of all the scoped
-// variables in every lexical BLOCK(), this facilitates allocating the
-// scoped variables in their blocks, and the rest at the outermost
-// scope of the function.
+// Depth-first walk of the GCC BLOCK() tree. Set BLOCK_NUMBER() to
+// the depth of each block; this is necessary for lexical block debug
+// info. Visit all the BLOCK_VARS(), and add them to the set s.
+// Since the unexpanded_var_list seems to be a superset of all the
+// scoped variables in every lexical BLOCK(), this facilitates
+// allocating the scoped variables in their blocks, and the rest at
+// the outermost scope of the function.
void TreeToLLVM::setLexicalBlockDepths(tree t, treeset &s, unsigned level) {
tree bstep, step;
switch (TREE_CODE(t)) {
@@ -616,7 +616,7 @@
SeenBlocks.clear();
if (EmitDebugInfo())
- TheDebugInfo->EmitFunctionStart(FnDecl, Fn, Builder.GetInsertBlock());
+ TheDebugInfo->EmitFunctionStart(FnDecl);
// Loop over all of the arguments to the function, setting Argument names and
// creating argument alloca's for the PARM_DECLs in case their address is
@@ -631,7 +631,7 @@
ABIConverter.HandleReturnType(TREE_TYPE(TREE_TYPE(FnDecl)), FnDecl,
DECL_BUILT_IN(FnDecl));
// Remember this for use by FinishFunctionBody.
- TheTreeToLLVM->ReturnOffset = Client.Offset;
+ ReturnOffset = Client.Offset;
// Prepend the static chain (if any) to the list of arguments.
tree Args = static_chain ? static_chain : DECL_ARGUMENTS(FnDecl);
Modified: llvm-gcc-4.2/trunk/gcc/llvm-debug.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/gcc/llvm-debug.cpp?rev=104842&r1=104841&r2=104842&view=diff
==============================================================================
--- llvm-gcc-4.2/trunk/gcc/llvm-debug.cpp (original)
+++ llvm-gcc-4.2/trunk/gcc/llvm-debug.cpp Thu May 27 11:16:58 2010
@@ -263,6 +263,8 @@
"expected 'desired' to be a GCC BLOCK or FUNCTION_DECL");
assert ((TREE_CODE(grand) == BLOCK || TREE_CODE(grand) == FUNCTION_DECL) &&
"expected 'grand' to be a GCC BLOCK or FUNCTION_DECL");
+ // Call myself to recursively walk back to the grandparent BLOCK;
+ // I'll push the RegionStack[] at every level on the way back here:
if (grand != desired)
push_regions(BLOCK_SUPERCONTEXT(desired), grand);
// FIXME: push_regions is currently never called with desired ==
@@ -277,39 +279,40 @@
// regions to arrive at 'desired'. This was inspired (cribbed from)
// by GCC's cfglayout.c:change_scope().
void DebugInfo::change_regions(tree desired, tree grand) {
- tree current_lexical_block = getCurrentLexicalBlock();
+ tree current_lexical_block;
// FIXME: change_regions is currently never called with desired ==
// grand, but it should be fixed so nothing weird happens if they're
// equal.
- while (current_lexical_block != grand) {
+ for( current_lexical_block = getCurrentLexicalBlock();
+ current_lexical_block != grand;
+ current_lexical_block = BLOCK_SUPERCONTEXT(current_lexical_block)) {
assert(BLOCK_SUPERCONTEXT(getCurrentLexicalBlock()) &&
"lost BLOCK context!");
- current_lexical_block = BLOCK_SUPERCONTEXT(current_lexical_block);
RegionStack.pop_back();
}
DebugInfo::push_regions(desired, grand);
- setCurrentLexicalBlock(desired);
+ setCurrentLexicalBlock(current_lexical_block);
}
-/// EmitFunctionStart - Constructs the debug code for entering a function.
-void DebugInfo::EmitFunctionStart(tree FnDecl, Function *Fn,
- BasicBlock *CurBB) {
- setCurrentLexicalBlock(FnDecl);
-
+/// CreateSubprogramFromFnDecl - Constructs the debug code for
+/// entering a function - "llvm.dbg.func.start."
+DISubprogram DebugInfo::CreateSubprogramFromFnDecl(tree FnDecl) {
+ DISubprogram SPDecl;
+ bool SPDeclIsSet = false;
+ // True if we're currently generating LLVM for this function.
+ bool definition = llvm_set_decl_p(FnDecl);
DIType FNType = getOrCreateType(TREE_TYPE(FnDecl));
std::map<tree_node *, WeakVH >::iterator I = SPCache.find(FnDecl);
if (I != SPCache.end()) {
- DISubprogram SPDecl(cast<MDNode>(I->second));
- DISubprogram SP =
- DebugFactory.CreateSubprogramDefinition(SPDecl);
- SPDecl->replaceAllUsesWith(SP);
-
- // Push function on region stack.
- RegionStack.push_back(WeakVH(SP));
- RegionMap[FnDecl] = WeakVH(SP);
- return;
- }
+ SPDecl = DISubprogram(cast<MDNode>(I->second));
+ SPDeclIsSet = true;
+ // If we've already created the defining instance, OR this
+ // invocation won't create the defining instance, return what we
+ // already have.
+ if (SPDecl.isDefinition() || !definition)
+ return SPDecl;
+ }
bool ArtificialFnWithAbstractOrigin = false;
// If this artificial function has abstract origin then put this function
@@ -323,11 +326,19 @@
getOrCreateFile(main_input_filename) :
findRegion (DECL_CONTEXT(FnDecl));
+ // The region/scope returned above can be arbitrarily deep.
+ // Sometimes GCC reports the true nested scoping of a function, but
+ // GCC usually places functions at module scope, ignoring their real
+ // context. Here we arbitrarily declare "__foo_block_invoke_3"
+ // functions at module scope for GDB sanity.
+ if (BLOCK_SYNTHESIZED_FUNC(FnDecl))
+ SPContext = findRegion(NULL_TREE);
+
// Creating context may have triggered creation of this SP descriptor. So
// check the cache again.
I = SPCache.find(FnDecl);
- if (I != SPCache.end()) {
- DISubprogram SPDecl(cast<MDNode>(I->second));
+ if (!SPDeclIsSet && I != SPCache.end()) {
+ SPDecl = DISubprogram(cast<MDNode>(I->second));
DISubprogram SP =
DebugFactory.CreateSubprogramDefinition(SPDecl);
SPDecl->replaceAllUsesWith(SP);
@@ -335,14 +346,14 @@
// Push function on region stack.
RegionStack.push_back(WeakVH(SP));
RegionMap[FnDecl] = WeakVH(SP);
- return;
+ return SP;
}
// Gather location information.
expanded_location Loc = GetNodeLocation(FnDecl, false);
StringRef LinkageName = getLinkageName(FnDecl);
- unsigned lineno = CurLineNo;
+ unsigned lineno = LOCATION_LINE(Loc);
if (isCopyOrDestroyHelper(FnDecl))
lineno = 0;
@@ -357,23 +368,37 @@
}
StringRef FnName = getFunctionName(FnDecl);
-
+ // If the Function * hasn't been created yet, use a bogus value for
+ // the debug internal linkage bit.
+ bool hasInternalLinkage = true;
+ if (GET_DECL_LLVM_INDEX(FnDecl)) {
+ Function *Fn = cast<Function>DECL_LLVM(FnDecl);
+ hasInternalLinkage = Fn->hasInternalLinkage();
+ }
DISubprogram SP =
DebugFactory.CreateSubprogram(SPContext,
FnName, FnName,
LinkageName,
getOrCreateFile(Loc.file), lineno,
FNType,
- Fn->hasInternalLinkage(),
- true /*definition*/,
+ hasInternalLinkage,
+ definition,
Virtuality, VIndex, ContainingType,
DECL_ARTIFICIAL (FnDecl), optimize);
SPCache[FnDecl] = WeakVH(SP);
+ RegionMap[FnDecl] = WeakVH(SP);
+ if (SPDeclIsSet && SPDecl != SP)
+ SPDecl->replaceAllUsesWith(SP);
+ return SP;
+}
+/// EmitFunctionStart - Constructs the debug code for entering a function.
+void DebugInfo::EmitFunctionStart(tree FnDecl) {
+ setCurrentLexicalBlock(FnDecl);
+ DISubprogram SP = CreateSubprogramFromFnDecl(FnDecl);
// Push function on region stack.
RegionStack.push_back(WeakVH(SP));
- RegionMap[FnDecl] = WeakVH(SP);
}
/// getOrCreateNameSpace - Get name space descriptor for the tree node.
@@ -406,20 +431,61 @@
DIType Ty = getOrCreateType(Node);
return DIDescriptor(Ty);
} else if (DECL_P (Node)) {
- if (TREE_CODE (Node) == NAMESPACE_DECL) {
+ switch (TREE_CODE(Node)) {
+ default:
+ /// What kind of DECL is this?
+ return findRegion (DECL_CONTEXT (Node));
+ case NAMESPACE_DECL: {
DIDescriptor NSContext = findRegion(DECL_CONTEXT(Node));
DINameSpace NS = getOrCreateNameSpace(Node, NSContext);
return DIDescriptor(NS);
}
- return findRegion (DECL_CONTEXT (Node));
+ case FUNCTION_DECL: {
+ DISubprogram SP = CreateSubprogramFromFnDecl(Node);
+ return SP;
+ }
+ }
} else if (TREE_CODE(Node) == BLOCK) {
// TREE_BLOCK is GCC's lexical block.
- // Recursively create all necessary contexts:
- DIDescriptor context = findRegion(BLOCK_SUPERCONTEXT(Node));
- DILexicalBlock lexical_block =
- DebugFactory.CreateLexicalBlock(context, CurLineNo);
- RegionMap[Node] = WeakVH(lexical_block);
- return DIDescriptor(lexical_block);
+ tree nonempty_block, nonempty_supercontext=NULL_TREE;
+ // Find the nearest non-empty (has variables) BLOCK. This is what
+ // we'll declare, assumming we don't omit it entirely.
+ for (nonempty_block = Node;
+ TREE_CODE(nonempty_block) == BLOCK && !BLOCK_VARS(nonempty_block);
+ nonempty_block = BLOCK_SUPERCONTEXT(nonempty_block))
+ ;
+ // Find a parent BLOCK that declares variables, and isn't the
+ // FUNCTION_DECL. If such a parent BLOCK exists, we'll omit it
+ // and declare its variables at the function scope.
+ if (TREE_CODE(nonempty_block) == BLOCK)
+ for (nonempty_supercontext = BLOCK_SUPERCONTEXT(nonempty_block);
+ TREE_CODE(nonempty_supercontext) == BLOCK &&
+ !BLOCK_VARS(nonempty_supercontext);
+ nonempty_supercontext = BLOCK_SUPERCONTEXT(nonempty_supercontext))
+ ;
+ // If the nearest non-empty context is the FUNCTION_DECL, that's
+ // our region; declare it. Otherwise, carefully avoid declaring
+ // the outermost lexical block. If this block hangs directly
+ // underneath the FUNCTION_DECL and has no siblings, we skip it;
+ // return the FUNCTION_DECL scope instead. Child BLOCKS will be
+ // emitted normally. While technically incorrect, this is what
+ // GCC does and GDB expects.
+ if (nonempty_supercontext) {
+ // O.K., this nonempty_block isn't the topmost BLOCK; declare it.
+ DIDescriptor context = findRegion(BLOCK_SUPERCONTEXT(nonempty_block));
+ DILexicalBlock lexical_block =
+ DebugFactory.CreateLexicalBlock(context, CurLineNo);
+ RegionMap[Node] = WeakVH(lexical_block);
+ return DIDescriptor(lexical_block);
+ }
+ tree function_decl;
+ // Find the enclosing FUNCTION_DECL.
+ for (function_decl = nonempty_block;
+ TREE_CODE(function_decl) == BLOCK;
+ function_decl = BLOCK_SUPERCONTEXT(function_decl))
+ ;
+ DISubprogram SP = CreateSubprogramFromFnDecl(function_decl);
+ return SP;
}
// Otherwise main compile unit covers everything.
@@ -651,7 +717,7 @@
sprintf(FwdTypeName, "fwd.type.%d", FwdTypeCount++);
llvm::DIType FwdType =
DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_subroutine_type,
- getOrCreateFile(main_input_filename),
+ findRegion(TYPE_CONTEXT(type)),
FwdTypeName,
getOrCreateFile(main_input_filename),
0, 0, 0, 0, 0,
@@ -738,7 +804,7 @@
StringRef PName = FromTy.getName();
DIType PTy =
- DebugFactory.CreateDerivedType(Tag, findRegion(TYPE_CONTEXT(type)),
+ DebugFactory.CreateDerivedType(Tag, findRegion(TYPE_CONTEXT(type)),
Tag == DW_TAG_pointer_type ?
StringRef() : PName,
getOrCreateFile(main_input_filename),
Modified: llvm-gcc-4.2/trunk/gcc/llvm-debug.h
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/gcc/llvm-debug.h?rev=104842&r1=104841&r2=104842&view=diff
==============================================================================
--- llvm-gcc-4.2/trunk/gcc/llvm-debug.h (original)
+++ llvm-gcc-4.2/trunk/gcc/llvm-debug.h Thu May 27 11:16:58 2010
@@ -118,9 +118,13 @@
// by GCC's cfglayout.c:change_scope().
void change_regions(tree_node *desired, tree_node *grand);
- /// EmitFunctionStart - Constructs the debug code for entering a function -
+ /// CreateSubprogramFromFnDecl - Constructs the debug code for entering a function -
/// "llvm.dbg.func.start."
- void EmitFunctionStart(tree_node *FnDecl, Function *Fn, BasicBlock *CurBB);
+ DISubprogram CreateSubprogramFromFnDecl(tree_node *FnDecl);
+
+ /// EmitFunctionStart - Constructs the debug code for entering a function -
+ /// "llvm.dbg.func.start", and pushes it onto the RegionStack.
+ void EmitFunctionStart(tree_node *FnDecl);
/// EmitFunctionEnd - Constructs the debug code for exiting a declarative
/// region - "llvm.dbg.region.end."
Modified: llvm-gcc-4.2/trunk/gcc/llvm-internal.h
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/gcc/llvm-internal.h?rev=104842&r1=104841&r2=104842&view=diff
==============================================================================
--- llvm-gcc-4.2/trunk/gcc/llvm-internal.h (original)
+++ llvm-gcc-4.2/trunk/gcc/llvm-internal.h Thu May 27 11:16:58 2010
@@ -75,7 +75,7 @@
extern llvm::Module *TheModule;
/// TheDebugInfo - This object is responsible for gather all debug information.
-/// If it's value is NULL then no debug information should be gathered.
+/// If its value is NULL then no debug information should be gathered.
extern llvm::DebugInfo *TheDebugInfo;
/// TheTarget - The current target being compiled for.
@@ -281,6 +281,7 @@
BasicBlock *ReturnBB;
BasicBlock *UnwindBB;
unsigned ReturnOffset;
+
// Lexical BLOCKS that we have previously seen and processed.
treeset SeenBlocks;
@@ -397,6 +398,10 @@
// allocation would change with -g, and users dislike that.
void switchLexicalBlock(tree_node *exp);
+ /// StartFunctionBody - Start the emission of 'FnDecl', outputing all
+ /// declarations for parameters and setting things up.
+ void StartFunctionBody();
+
private: // Helper functions.
// Walk over the lexical BLOCK() tree of the given FUNCTION_DECL;
@@ -405,10 +410,6 @@
// the given set.
void setLexicalBlockDepths(tree_node *t, treeset &s, unsigned level);
- /// StartFunctionBody - Start the emission of 'fndecl', outputing all
- /// declarations for parameters and setting things up.
- void StartFunctionBody();
-
/// FinishFunctionBody - Once the body of the function has been emitted, this
/// cleans up and returns the result function.
Function *FinishFunctionBody();
@@ -608,6 +609,9 @@
Constant *EmitLV_LABEL_DECL(tree_node *exp);
};
+/// TheTreeToLLVM - Keep track of the current function being compiled.
+extern TreeToLLVM *TheTreeToLLVM;
+
/// TreeConstantToLLVM - An instance of this class is created and used to
/// convert tree constant values to LLVM. This is primarily for things like
/// global variable initializers.
More information about the llvm-commits
mailing list