public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH GCC]Add 'force-dwarf-lexical-blocks' command line option
@ 2014-05-07  9:32 Herman, Andrei
  2014-05-07  9:36 ` pinskia
                   ` (2 more replies)
  0 siblings, 3 replies; 17+ messages in thread
From: Herman, Andrei @ 2014-05-07  9:32 UTC (permalink / raw)
  To: gcc-patches; +Cc: Herman_Andrei@mentor.com

[-- Attachment #1: Type: text/plain, Size: 1497 bytes --]


Hi,

Currently GCC only emits DWARF debug information (DW_TAG_lexical_block DIEs)
for compound statements containing significant local declarations.
However, code coverage tools that process the DWARF debug information to
implement block/path coverage need more complete lexical block information. 

This patch adds the necessary functionality under the control of a new 
command line argument: -fforce-dwarf-lexical-blocks.

When this flag is set, a DW_TAG_lexical_block DIE will be emitted for every
function body, loop body, switch body, case statement, if-then and if-else
statement, even if the body is a single statement. 
Likewise, a lexical block will be emitted for the first label of a labeled
statement. This block ends at the end of the current lexical scope, or when
a break, continue, goto or return statement is encountered at the same lexical
scope level. 
Consequently, any case in a switch statement that does not flow through to 
the next case, will have its own dwarf lexical block.

The complete change proposal contains 4 patches (attached first 3):
1. Add command line option -fforce-dwarf-lexical-blocks
2. Use of flag_force_dwarf_blocks
3. Create label scopes

A forth patch, extending the proposed functionality to C++ will be submitted in a separate message.

Attached are the proposed ChangeLog additions, named according to the directory each one belongs to.

Best regards,
Andrei Herman
Mentor Graphics Corporation
Israel branch 


[-- Attachment #2: gcc_c_ChangeLog --]
[-- Type: application/octet-stream, Size: 1265 bytes --]

2014-02-24  Andrei Herman  <Andrei_Herman@codesourcery.com>

	* c-parser.c (c_parser_declaration_or_fndef): Force a block for
	function body.
	(c_parser_statement_after_labels): Likewise for compound statement.
	(c_parser_c99_block_statement): Likewise for switch and loop statement
	if its not a compound statement.
	(c_parser_if_body): Likewise for if-then statement.
	(c_parser_else_body): Likewise for if-else statement.

2014-03-10  Andrei Herman  <Andrei_Herman@codesourcery.com>

	* c-decl.c (get_enclosing_non_label_scope): New.
	(clear_keep_current_level): New.
	(pushdecl): If current scope is a label scope, put the declaration
	in the enclosing non-label scope.

	* c-parser.c (c_parser_label): Add parameter.  Create a label scope
	for the first label of a statement.
	(c_parser_force_block_for_label): New.
	(c_parser_compound_statement_nostart): Pass last_label when calling
	c_parser_label.
	(c_parser_statement): Likewise.
	(c_parser_if_body, c_parser_else_body): Likewise.

	* c-tree.h (clear_keep_current_level): New.

	* c-typeck.c (pop_scope_for_labels): New.
	(c_finish_goto_label, c_finish_goto_ptr, c_finish_return,
	c_finish_bc_stmt): Call pop_scope_for_labels to close current
        label scope if any.
	(c_end_compound_stmt): Likewise.

[-- Attachment #3: gcc_c-family_ChangeLog --]
[-- Type: application/octet-stream, Size: 372 bytes --]

2014-03-10  Andrei Herman  <Andrei_Herman@codesourcery.com>

	* c-common.h (struct block_loc_s, block_loc): New.
	(stmt_tree_s): Add x_cur_block_list stack of block_loc structs
	for statement lists of label scopes.
	(block_list_stack, cur_block_info): New macros.
	(push_block_info, pop_block_info): New.

	* c-semantics.c (push_block_info): New.
	(pop_block_info): New.


[-- Attachment #4: gcc_ChangeLog --]
[-- Type: application/octet-stream, Size: 383 bytes --]

2014-02-24  Andrei Herman  <Andrei_Herman@codesourcery.com>

	* common.opt: Add force_dwarf_lexical_blocks flag.
	* opts.c (finish_options): Limit its use to dwarf4.
	* doc/invoke.texi: Document new option.

2014-02-24  Andrei Herman  <Andrei_Herman@codesourcery.com>

	* dwarf2out.c (gen_block_die): Force output a lexical block die
	even for blocks without any local declaration.


[-- Attachment #5: 0001-Add-command-line-option-fforce_dwarf_lexical_blocks.patch --]
[-- Type: application/octet-stream, Size: 3291 bytes --]

From b751b208ddb62f8c7e32ea2834020658279a407f Mon Sep 17 00:00:00 2001
From: Andrei Herman <Andrei_Herman@codesourcery.com>
Date: Wed, 12 Feb 2014 17:28:37 +0200
Subject: [PATCH 1/3]         Add command line option -fforce_dwarf_lexical_blocks.

        * gcc/common.opt: Add force_dwarf_lexical_blocks flag.
        * gcc/opts.c (finish_options): Limit its use to dwarf4.
        * gcc/doc/invoke.texi: Document the new option.

Signed-off-by: Andrei Herman <Andrei_Herman@codesourcery.com>
---
 gcc/common.opt      |    4 ++++
 gcc/doc/invoke.texi |   10 ++++++++++
 gcc/opts.c          |   13 +++++++++++++
 3 files changed, 27 insertions(+), 0 deletions(-)

diff --git a/gcc/common.opt b/gcc/common.opt
index d334cf2..2f17f6f 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -1175,6 +1175,10 @@ fforce-addr
 Common Ignore
 Does nothing.  Preserved for backward compatibility.
 
+fforce-dwarf-lexical-blocks
+Common Report Var(flag_force_dwarf_blocks)
+Force generation of lexical blocks in dwarf output
+
 fforward-propagate
 Common Report Var(flag_forward_propagate) Optimization
 Perform a forward propagation pass on RTL
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 4d1b657..a897e79 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -329,6 +329,7 @@ Objective-C and Objective-C++ Dialects}.
 -feliminate-unused-debug-symbols -femit-class-debug-always @gol
 -fenable-@var{kind}-@var{pass} @gol
 -fenable-@var{kind}-@var{pass}=@var{range-list} @gol
+-fforce-dwarf-lexical-blocks @gol
 -fdebug-types-section -fmem-report-wpa @gol
 -fmem-report -fpre-ipa-mem-report -fpost-ipa-mem-report -fprofile-arcs @gol
 -fopt-info @gol
@@ -5180,6 +5181,15 @@ normally emits debugging information for classes because using this
 option increases the size of debugging information by as much as a
 factor of two.
 
+@item -fforce-dwarf-lexical-blocks
+Produce debug information (a DW_TAG_lexical_block) for every function
+body, loop body, switch body, case statement, if-then and if-else statement,
+even if the body is a single statement.  Likewise, a lexical block will be
+emitted for the first label of a statement.  This block ends at the end of the
+current lexical scope, or when a break, continue, goto or return statement is
+encountered at the same lexical scope level.
+This option is available when using DWARF Version 4 or higher.
+
 @item -fdebug-types-section
 @opindex fdebug-types-section
 @opindex fno-debug-types-section
diff --git a/gcc/opts.c b/gcc/opts.c
index 7dee0e7..50eab60 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -866,6 +866,19 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
   /* The -gsplit-dwarf option requires -gpubnames.  */
   if (opts->x_dwarf_split_debug_info)
     opts->x_debug_generate_pub_sections = 1;
+
+  /* The -fforce_dwarf_lexical_blocks option is only relevant when debug info
+     is in DWARF4 format */
+  if (opts->x_flag_force_dwarf_blocks)
+    {
+      if (opts->x_write_symbols != DWARF2_DEBUG || opts->x_dwarf_version < 4)
+        {
+          inform (loc,
+                  "-fforce-dwarf-lexical-blocks is only supported with "
+                  "DWARF4 debug format");
+          opts->x_flag_force_dwarf_blocks = 0;
+        }
+    }
 }
 
 #define LEFT_COLUMN	27
-- 
1.7.1


[-- Attachment #6: 0002-Use-flag_force_dwarf_blocks.patch --]
[-- Type: application/octet-stream, Size: 7102 bytes --]

From d16088a15739bdf417fc752ad05f63b6566ecaaf Mon Sep 17 00:00:00 2001
From: Andrei Herman <Andrei_Herman@codesourcery.com>
Date: Thu, 13 Feb 2014 17:39:52 +0200
Subject: [PATCH 2/3]     Use flag_force_dwarf_blocks.

    When flag_force_dwarf_blocks is true, create lexical blocks
    for function body, compound statement, loop body, switch body and
    if-then/if-else statements.

    * gcc/c/c-parser.c (c_parser_declaration_or_fndef): Force a block for
    function body.
    (c_parser_statement_after_labels): Likewise for compound statement.
    (c_parser_c99_block_statement): Likewise for switch and loop statement
    if its not a compound statement.
    (c_parser_if_body): Likewise for if-then statement.
    (c_parser_else_body): Likewise for if-else statement.

    * gcc/dwarf2out.c (gen_block_die): Force output a lexical block
    die even without vars.

Signed-off-by: Andrei Herman <Andrei_Herman@codesourcery.com>
---
 gcc/c/c-parser.c |   37 ++++++++++++++++++++++++++++++-------
 gcc/dwarf2out.c  |   39 ++++++++++++++++++++++++---------------
 2 files changed, 54 insertions(+), 22 deletions(-)

diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 66625aa..d22f79a 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -1918,7 +1918,17 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 				   omp_declare_simd_clauses);
       DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus
 	= c_parser_peek_token (parser)->location;
-      fnbody = c_parser_compound_statement (parser);
+      if (flag_force_dwarf_blocks)
+        {
+          /* Force creating a block to represent the function body.  */
+          tree block = c_begin_compound_stmt (true);
+          location_t loc = c_parser_peek_token (parser)->location;
+          keep_next_level ();
+          add_stmt (c_parser_compound_statement (parser));
+          fnbody = c_end_compound_stmt (loc, block, true);
+        }
+      else
+        fnbody = c_parser_compound_statement (parser);
       if (flag_cilkplus && contains_array_notation_expr (fnbody))
 	fnbody = expand_array_notation_exprs (fnbody);
       if (nested)
@@ -4858,6 +4868,8 @@ c_parser_statement_after_labels (c_parser *parser)
   switch (c_parser_peek_token (parser)->type)
     {
     case CPP_OPEN_BRACE:
+      if (flag_force_dwarf_blocks)
+        keep_next_level ();
       add_stmt (c_parser_compound_statement (parser));
       break;
     case CPP_KEYWORD:
@@ -5044,10 +5056,14 @@ c_parser_paren_condition (c_parser *parser)
 static tree
 c_parser_c99_block_statement (c_parser *parser)
 {
-  tree block = c_begin_compound_stmt (flag_isoc99);
+  bool force_scope = flag_force_dwarf_blocks
+    && !c_parser_next_token_is (parser, CPP_OPEN_BRACE);
+  if (force_scope)
+    keep_next_level ();
+  tree block = c_begin_compound_stmt (flag_isoc99 || force_scope);
   location_t loc = c_parser_peek_token (parser)->location;
   c_parser_statement (parser);
-  return c_end_compound_stmt (loc, block, flag_isoc99);
+  return c_end_compound_stmt (loc, block, flag_isoc99 || force_scope);
 }
 
 /* Parse the body of an if statement.  This is just parsing a
@@ -5061,7 +5077,9 @@ c_parser_c99_block_statement (c_parser *parser)
 static tree
 c_parser_if_body (c_parser *parser, bool *if_p)
 {
-  tree block = c_begin_compound_stmt (flag_isoc99);
+  if (flag_force_dwarf_blocks)
+    keep_next_level ();
+  tree block = c_begin_compound_stmt (flag_isoc99 || flag_force_dwarf_blocks);
   location_t body_loc = c_parser_peek_token (parser)->location;
   while (c_parser_next_token_is_keyword (parser, RID_CASE)
 	 || c_parser_next_token_is_keyword (parser, RID_DEFAULT)
@@ -5082,7 +5100,8 @@ c_parser_if_body (c_parser *parser, bool *if_p)
     add_stmt (c_parser_compound_statement (parser));
   else
     c_parser_statement_after_labels (parser);
-  return c_end_compound_stmt (body_loc, block, flag_isoc99);
+  return c_end_compound_stmt (body_loc, block, 
+                              flag_isoc99 || flag_force_dwarf_blocks);
 }
 
 /* Parse the else body of an if statement.  This is just parsing a
@@ -5093,7 +5112,11 @@ static tree
 c_parser_else_body (c_parser *parser)
 {
   location_t else_loc = c_parser_peek_token (parser)->location;
-  tree block = c_begin_compound_stmt (flag_isoc99);
+  bool force_scope = flag_force_dwarf_blocks
+    && !c_parser_next_token_is (parser, CPP_OPEN_BRACE);
+  if (force_scope)
+    keep_next_level ();
+  tree block = c_begin_compound_stmt (flag_isoc99 || force_scope);
   while (c_parser_next_token_is_keyword (parser, RID_CASE)
 	 || c_parser_next_token_is_keyword (parser, RID_DEFAULT)
 	 || (c_parser_next_token_is (parser, CPP_NAME)
@@ -5110,7 +5133,7 @@ c_parser_else_body (c_parser *parser)
     }
   else
     c_parser_statement_after_labels (parser);
-  return c_end_compound_stmt (else_loc, block, flag_isoc99);
+  return c_end_compound_stmt (else_loc, block, flag_isoc99 || force_scope);
 }
 
 /* Parse an if statement (C90 6.6.4, C99 6.8.4).
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index d1ca4ba..0e8850b 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -19908,21 +19908,30 @@ gen_block_die (tree stmt, dw_die_ref context_die, int depth)
     must_output_die = 1;
   else
     {
-      /* Determine if this block directly contains any "significant"
-	 local declarations which we will need to output DIEs for.  */
-      if (debug_info_level > DINFO_LEVEL_TERSE)
-	/* We are not in terse mode so *any* local declaration counts
-	   as being a "significant" one.  */
-	must_output_die = ((BLOCK_VARS (stmt) != NULL
-			    || BLOCK_NUM_NONLOCALIZED_VARS (stmt))
-			   && (TREE_USED (stmt)
-			       || TREE_ASM_WRITTEN (stmt)
-			       || BLOCK_ABSTRACT (stmt)));
-      else if ((TREE_USED (stmt)
-		|| TREE_ASM_WRITTEN (stmt)
-		|| BLOCK_ABSTRACT (stmt))
-      	       && !dwarf2out_ignore_block (stmt))
-	must_output_die = 1;
+      if (flag_force_dwarf_blocks) 
+        {
+          must_output_die = (TREE_USED (stmt)
+                             || TREE_ASM_WRITTEN (stmt)
+                             || BLOCK_ABSTRACT (stmt));
+        }
+      else 
+        {
+          /* Determine if this block directly contains any "significant"
+             local declarations which we will need to output DIEs for.  */
+          if (debug_info_level > DINFO_LEVEL_TERSE)
+            /* We are not in terse mode so *any* local declaration counts
+               as being a "significant" one.  */
+            must_output_die = ((BLOCK_VARS (stmt) != NULL
+                                || BLOCK_NUM_NONLOCALIZED_VARS (stmt))
+                               && (TREE_USED (stmt)
+                                   || TREE_ASM_WRITTEN (stmt)
+                                   || BLOCK_ABSTRACT (stmt)));
+          else if ((TREE_USED (stmt)
+                    || TREE_ASM_WRITTEN (stmt)
+                    || BLOCK_ABSTRACT (stmt))
+                   && !dwarf2out_ignore_block (stmt))
+            must_output_die = 1;
+        }
     }
 
   /* It would be a waste of space to generate a Dwarf DW_TAG_lexical_block
-- 
1.7.1


[-- Attachment #7: 0003-Create-label-scopes.patch --]
[-- Type: application/octet-stream, Size: 15211 bytes --]

From c122c455af66f54fac63ad8b46141197990965ca Mon Sep 17 00:00:00 2001
From: Andrei Herman <Andrei_Herman@codesourcery.com>
Date: Mon, 10 Mar 2014 18:16:26 +0200
Subject: [PATCH 3/3]         Create label scopes.

        When flag_force_dwarf_blocks is true, create lexical block
        for the first label of a statement.

        * gcc/c-family/c-common.h (struct block_loc_s): New.
        (stmt_tree_s): Add stack of block_loc structs for statement
        lists of label scopes.
        (block_list_stack): New macro.
        (cur_block_info): New macro.
        (push_block_info): New.
        (pop_block_info): New.

        * gcc/c-family/c-semantics.c (push_block_info): New.
        (pop_block_info): New.

        * gcc/c/c-decl.c (get_enclosing_non_label_scope): New.
        (clear_keep_current_level): New.
        (pushdecl): Add declarations to enclosing non-label scope.

        * gcc/c/c-parser.c (c_parser_force_block_for_label): New.
        (c_parser_compound_statement_nostart): Pass previous value of
        last_label to c_parser_label.
        (c_parser_label): New argument. If this is the first label of
        a statement, create a label scope for it.
        (c_parser_statement): Pass last_label to c_parser_label.
        (c_parser_if_body, c_parser_else_body): Likewise.

        * gcc/c/c-tree.h (clear_keep_current_level): New.

        * gcc/c/c-typeck.c (pop_scope_for_labels): New.
        (c_finish_goto_label, c_finish_goto_ptr, c_finish_return,
        c_finish_bc_stmt): Call pop_scope_for_labels to close current
        label scope if any.
        (c_end_compound_stmt): Likewise.

Signed-off-by: Andrei Herman <Andrei_Herman@codesourcery.com>
---
 gcc/c-family/c-common.h    |   20 +++++++++++++++
 gcc/c-family/c-semantics.c |   30 +++++++++++++++++++++++
 gcc/c/c-decl.c             |   38 +++++++++++++++++++++++++++++
 gcc/c/c-parser.c           |   57 ++++++++++++++++++++++++++++++++++++++-----
 gcc/c/c-tree.h             |    1 +
 gcc/c/c-typeck.c           |   49 ++++++++++++++++++++++++++++++++++---
 6 files changed, 184 insertions(+), 11 deletions(-)

diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index f074ab1..928c6d6 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -481,12 +481,24 @@ typedef enum ref_operator {
   RO_ARROW_STAR
 } ref_operator;
 
+/* Information about a statement list created for a label.  */
+
+struct GTY(()) block_loc_s {
+  tree block;
+  location_t loc;
+};
+
+typedef struct block_loc_s *block_loc;
+
 /* Information about a statement tree.  */
 
 struct GTY(()) stmt_tree_s {
   /* A stack of statement lists being collected.  */
   vec<tree, va_gc> *x_cur_stmt_list;
 
+  /* A stack of block-loc structs related to statement lists of labels.  */
+  vec<block_loc, va_gc> *x_cur_block_list;
+
   /* In C++, Nonzero if we should treat statements as full
      expressions.  In particular, this variable is non-zero if at the
      end of a statement we should destroy any temporaries created
@@ -522,6 +534,12 @@ struct GTY(()) c_language_function {
 
 #define building_stmt_list_p() (stmt_list_stack && !stmt_list_stack->is_empty())
 
+#define block_list_stack (current_stmt_tree ()->x_cur_block_list)
+
+/* When building a statement-tree, this is the block list element
+   corresponding to the innermost statement list created for a label.  */
+#define cur_block_info	 (block_list_stack->last ())
+
 /* Language-specific hooks.  */
 
 /* If non-NULL, this function is called after a precompile header file
@@ -533,6 +551,8 @@ extern void pop_file_scope (void);
 extern stmt_tree current_stmt_tree (void);
 extern tree push_stmt_list (void);
 extern tree pop_stmt_list (tree);
+extern void push_block_info (tree, location_t);
+extern tree pop_block_info (location_t &);
 extern tree add_stmt (tree);
 extern void push_cleanup (tree, tree, bool);
 extern tree pushdecl_top_level (tree);
diff --git a/gcc/c-family/c-semantics.c b/gcc/c-family/c-semantics.c
index f25805a..5755332 100644
--- a/gcc/c-family/c-semantics.c
+++ b/gcc/c-family/c-semantics.c
@@ -29,6 +29,36 @@ along with GCC; see the file COPYING3.  If not see
 #include "flags.h"
 #include "tree-iterator.h"
 
+/* Create a block_loc struct for a statement list created for a label.  */
+
+void
+push_block_info (tree block, location_t loc)
+{
+  if (TREE_CODE(block) != STATEMENT_LIST)
+    return;
+
+  block_loc tl;
+  size_t length = tree_code_size (TREE_CODE(block)) + sizeof(location_t);
+  tl = (block_loc) ggc_alloc_cleared_atomic (length);
+  tl->block = block;
+  tl->loc = loc;
+  vec_safe_push (block_list_stack, tl);
+}
+
+/* Pop the block_loc struct and return the statement list and its location.  */
+
+tree
+pop_block_info (location_t &loc)
+{
+  block_loc  tl = NULL;
+  tl = block_list_stack->pop ();
+
+  gcc_assert (tl != NULL);
+
+  loc = tl->loc;
+  return tl->block;
+}
+
 /* Create an empty statement tree rooted at T.  */
 
 tree
diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index 7a7d68e..b916bc0 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -538,6 +538,31 @@ static tree grokdeclarator (const struct c_declarator *,
 static tree grokparms (struct c_arg_info *, bool);
 static void layout_array_type (tree);
 \f
+/* For a given scope, if this scope is a label scope (has been created
+   for a label), then find and return the nearest enclosing scope which
+   is not a label scope.  Otherwise just return the scope as is.  */
+ 
+static c_scope *
+get_enclosing_non_label_scope (c_scope * scope)
+{
+  if (block_list_stack && !block_list_stack->is_empty ())
+    {
+      int six = stmt_list_stack->length () - 1;
+      int bix = block_list_stack->length () - 1;
+      while (six >= 0 && bix >= 0)
+        {
+          if ((*stmt_list_stack)[six] == (*block_list_stack)[bix]->block)
+            {
+              scope = scope->outer;
+              six--; bix--;
+            }
+          else
+            return scope;
+        }
+    }
+  return scope;
+}
+
 /* T is a statement.  Add it to the statement-tree.  This is the
    C/ObjC version--C++ has a slightly different version of this
    function.  */
@@ -880,6 +905,14 @@ keep_next_level (void)
   keep_next_level_flag = true;
 }
 
+/* Clear the flag that forces creation of a block for this scope.  */
+
+void
+clear_keep_current_level (void)
+{
+  current_scope->keep = false;
+}
+
 /* Set the flag for the FLOAT_CONST_DECIMAL64 pragma being ON.  */
 
 void
@@ -2641,6 +2674,11 @@ pushdecl (tree x)
       return x;
     }
 
+  if (flag_force_dwarf_blocks)
+    /* If the current scope is a label scope, put the declaration in the
+       nearest enclosing non-label scope.  */
+    scope = get_enclosing_non_label_scope (scope);
+
   /* First, see if there is another declaration with the same name in
      the current scope.  If there is, duplicate_decls may do all the
      work for us.  If duplicate_decls returns false, that indicates
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index d22f79a..779cffb 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -1167,7 +1167,7 @@ static void c_parser_initval (c_parser *, struct c_expr *,
 			      struct obstack *);
 static tree c_parser_compound_statement (c_parser *);
 static void c_parser_compound_statement_nostart (c_parser *);
-static void c_parser_label (c_parser *);
+static void c_parser_label (c_parser *, bool);
 static void c_parser_statement (c_parser *);
 static void c_parser_statement_after_labels (c_parser *);
 static void c_parser_if_statement (c_parser *);
@@ -4476,6 +4476,24 @@ c_parser_compound_statement (c_parser *parser)
   return c_end_compound_stmt (brace_loc, stmt, true);
 }
 
+/* Force creation of a new scope for a label.  If not followed by a compound
+   statement, make it a block (otherwise, the compound statement will create
+   the block).  Push the created scope onto the block_info stack, so we can
+   identify it as a label scope.  */
+
+static void
+c_parser_force_block_for_label (c_parser *parser, tree label)
+{
+  if (!flag_force_dwarf_blocks || label == NULL_TREE)
+    return;
+
+  if (!c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+    keep_next_level ();
+  tree block = c_begin_compound_stmt (true);
+  location_t loc = c_parser_peek_token (parser)->location;
+  push_block_info (block, loc);
+}
+
 /* Parse a compound statement except for the opening brace.  This is
    used for parsing both compound statements and statement expressions
    (which follow different paths to handling the opening).  */
@@ -4546,10 +4564,10 @@ c_parser_compound_statement_nostart (c_parser *parser)
 	    label_loc = c_parser_peek_2nd_token (parser)->location;
 	  else
 	    label_loc = c_parser_peek_token (parser)->location;
+	  mark_valid_location_for_stdc_pragma (false);
+	  c_parser_label (parser, last_label);
 	  last_label = true;
 	  last_stmt = false;
-	  mark_valid_location_for_stdc_pragma (false);
-	  c_parser_label (parser);
 	}
       else if (!last_label
 	       && c_parser_next_tokens_start_declaration (parser))
@@ -4665,7 +4683,7 @@ c_parser_compound_statement_nostart (c_parser *parser)
    expressions being rejected later.  */
 
 static void
-c_parser_label (c_parser *parser)
+c_parser_label (c_parser *parser, bool prev_label)
 {
   location_t loc1 = c_parser_peek_token (parser)->location;
   tree label = NULL_TREE;
@@ -4727,6 +4745,19 @@ c_parser_label (c_parser *parser)
 					 vNULL);
 	}
     }
+  if (label && flag_force_dwarf_blocks)
+    {
+      if (!prev_label)
+        /* If this is the first label on the statement, create a label scope
+           for it.  */
+        c_parser_force_block_for_label (parser, label);
+      else
+        /* The first label may not have seen the open brace and therefor set
+           the keep flag in current scope.  If we see it now, we should clear
+           the flag (the next compound statement will create the block).  */
+        if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+          clear_keep_current_level ();
+    }      
 }
 
 /* Parse a statement (C90 6.6, C99 6.8).
@@ -4848,11 +4879,15 @@ c_parser_label (c_parser *parser)
 static void
 c_parser_statement (c_parser *parser)
 {
+  bool last_label = false;
   while (c_parser_next_token_is_keyword (parser, RID_CASE)
 	 || c_parser_next_token_is_keyword (parser, RID_DEFAULT)
 	 || (c_parser_next_token_is (parser, CPP_NAME)
 	     && c_parser_peek_2nd_token (parser)->type == CPP_COLON))
-    c_parser_label (parser);
+    {
+      c_parser_label (parser, last_label);
+      last_label = true;
+    }
   c_parser_statement_after_labels (parser);
 }
 
@@ -5081,11 +5116,15 @@ c_parser_if_body (c_parser *parser, bool *if_p)
     keep_next_level ();
   tree block = c_begin_compound_stmt (flag_isoc99 || flag_force_dwarf_blocks);
   location_t body_loc = c_parser_peek_token (parser)->location;
+  bool last_label = false;
   while (c_parser_next_token_is_keyword (parser, RID_CASE)
 	 || c_parser_next_token_is_keyword (parser, RID_DEFAULT)
 	 || (c_parser_next_token_is (parser, CPP_NAME)
 	     && c_parser_peek_2nd_token (parser)->type == CPP_COLON))
-    c_parser_label (parser);
+    {
+      c_parser_label (parser, last_label);
+      last_label = true;
+    }
   *if_p = c_parser_next_token_is_keyword (parser, RID_IF);
   if (c_parser_next_token_is (parser, CPP_SEMICOLON))
     {
@@ -5117,11 +5156,15 @@ c_parser_else_body (c_parser *parser)
   if (force_scope)
     keep_next_level ();
   tree block = c_begin_compound_stmt (flag_isoc99 || force_scope);
+  bool last_label = false;
   while (c_parser_next_token_is_keyword (parser, RID_CASE)
 	 || c_parser_next_token_is_keyword (parser, RID_DEFAULT)
 	 || (c_parser_next_token_is (parser, CPP_NAME)
 	     && c_parser_peek_2nd_token (parser)->type == CPP_COLON))
-    c_parser_label (parser);
+    {
+      c_parser_label (parser, last_label);
+      last_label = true;
+    }
   if (c_parser_next_token_is (parser, CPP_SEMICOLON))
     {
       location_t loc = c_parser_peek_token (parser)->location;
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index 84d5e0b..e584595 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -504,6 +504,7 @@ extern tree groktypename (struct c_type_name *, tree *, bool *);
 extern tree grokparm (const struct c_parm *, tree *);
 extern tree implicitly_declare (location_t, tree);
 extern void keep_next_level (void);
+extern void clear_keep_current_level (void);
 extern void pending_xref_error (void);
 extern void c_push_function_context (void);
 extern void c_pop_function_context (void);
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index da6a6fc..16ed442 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -9072,6 +9072,25 @@ build_asm_expr (location_t loc, tree string, tree outputs, tree inputs,
   return args;
 }
 \f
+/* If current scope is a label scope, pop it from block info stack
+   and close it's compound statement.  */
+
+static void
+pop_scope_for_labels (void)
+{
+  while (block_list_stack && !block_list_stack->is_empty ())
+    {
+      if (cur_stmt_list == cur_block_info->block)
+        {
+          location_t loc;
+          tree block = pop_block_info (loc);
+          add_stmt(c_end_compound_stmt (loc, block, true));
+        }
+      else
+        break;
+    }
+}
+
 /* Generate a goto statement to LABEL.  LOC is the location of the
    GOTO.  */
 
@@ -9085,7 +9104,12 @@ c_finish_goto_label (location_t loc, tree label)
   {
     tree t = build1 (GOTO_EXPR, void_type_node, decl);
     SET_EXPR_LOCATION (t, loc);
-    return add_stmt (t);
+    {
+      tree stmt = add_stmt (t);
+      if (flag_force_dwarf_blocks)
+        pop_scope_for_labels ();
+      return stmt;
+    }
   }
 }
 
@@ -9101,7 +9125,12 @@ c_finish_goto_ptr (location_t loc, tree expr)
   expr = convert (ptr_type_node, expr);
   t = build1 (GOTO_EXPR, void_type_node, expr);
   SET_EXPR_LOCATION (t, loc);
-  return add_stmt (t);
+  {
+    tree stmt = add_stmt (t);
+    if (flag_force_dwarf_blocks)
+      pop_scope_for_labels ();
+    return stmt;
+  }
 }
 
 /* Generate a C `return' statement.  RETVAL is the expression for what
@@ -9260,7 +9289,12 @@ c_finish_return (location_t loc, tree retval, tree origtype)
 
   ret_stmt = build_stmt (loc, RETURN_EXPR, retval);
   TREE_NO_WARNING (ret_stmt) |= no_warning;
-  return add_stmt (ret_stmt);
+  {
+    tree stmt = add_stmt (ret_stmt);
+    if (flag_force_dwarf_blocks)
+      pop_scope_for_labels ();
+    return stmt;
+  }
 }
 \f
 struct c_switch {
@@ -9633,7 +9667,12 @@ c_finish_bc_stmt (location_t loc, tree *label_p, bool is_break)
   if (!is_break)
     add_stmt (build_predict_expr (PRED_CONTINUE, NOT_TAKEN));
 
-  return add_stmt (build1 (GOTO_EXPR, void_type_node, label));
+  {
+    tree stmt = add_stmt (build1 (GOTO_EXPR, void_type_node, label));
+    if (flag_force_dwarf_blocks)
+      pop_scope_for_labels ();
+    return stmt;
+  }
 }
 
 /* A helper routine for c_process_expr_stmt and c_finish_stmt_expr.  */
@@ -9885,6 +9924,8 @@ c_end_compound_stmt (location_t loc, tree stmt, bool do_scope)
     {
       if (c_dialect_objc ())
 	objc_clear_super_receiver ();
+      if (flag_force_dwarf_blocks)
+        pop_scope_for_labels ();
       block = pop_scope ();
     }
 
-- 
1.7.1


^ permalink raw reply	[flat|nested] 17+ messages in thread
* [PATCH GCC]Add 'force-dwarf-lexical-blocks' command line option
@ 2014-06-01 10:33 Herman, Andrei
  2014-06-19 21:09 ` Joseph S. Myers
  0 siblings, 1 reply; 17+ messages in thread
From: Herman, Andrei @ 2014-06-01 10:33 UTC (permalink / raw)
  To: gcc-patches; +Cc: Alex_Rozenman

[-- Attachment #1: Type: text/plain, Size: 1795 bytes --]

Hi,

Currently GCC only emits DWARF debug information (DW_TAG_lexical_block 
DIEs) for compound statements containing significant local declarations.
However, code coverage tools that process the DWARF debug information to
implement block/path coverage need more complete lexical block information.

This patch adds the necessary functionality under the control of a new
command line argument: -fforce-dwarf-lexical-blocks.

When this flag is set, a DW_TAG_lexical_block DIE will be emitted for 
every function body, loop body, switch body, case statement, if-then and 
if-else statement, even if the body is a single statement.
Likewise, a lexical block will be emitted for the first label of a 
labeled statement. This block ends at the end of the current lexical 
scope, or when a break, continue, goto or return statement is 
encountered at the same lexical scope level.
Consequently, any case in a switch statement that does not flow through 
to the next case, will have its own dwarf lexical block.

The complete change proposal contains 3 patches (attached first 2):
   1.  Add command line option -fforce-dwarf-lexical-blocks
   2.  Use of flag_force_dwarf_blocks in C.

Attached are the proposed ChangeLog additions, named according to the 
directory each one belongs to.

A third patch, extending the proposed functionality to C++ will be 
submitted in a separate message.

NOTE: This is a second submit, with changes made according to 
maintainer's sugestions.

All check-c and check-c++ tests have been run for unix target.
The only test that failed with the -fforce-dwarf-lexical-blocks set
was:
FAIL: gcc.dg/debug/dwarf2/inline2.c scan-assembler-times \\(DIE 
\\([^\n]*\\) DW_TAG_lexical_block 6
as expected.

Best regards,
Andrei Herman
Mentor Graphics Corporation
Israel branch


[-- Attachment #2: 0001-Add-command-line-option-fforce-dwarf-lexical-blocks.patch --]
[-- Type: text/plain, Size: 3474 bytes --]

From 6dd5796f04ca249e8e59026208e90e7619534a80 Mon Sep 17 00:00:00 2001
From: Andrei Herman <Andrei_Herman@codesourcery.com>
Date: Sun, 1 Jun 2014 11:13:09 +0300
Subject: [PATCH 1/2]             Add command line option -fforce-dwarf-lexical-blocks.

            * gcc/c-family/c.opt: Add -fforce-dwarf-lexical-blocks flag.
            * gcc/c-family/c-opts.c (c_common_post_options): Limit its use
            to dwarf4.
            * gcc/doc/invoke.texi: Document the new option.

Signed-off-by: Andrei Herman <Andrei_Herman@codesourcery.com>
---
 gcc/c-family/c-opts.c |   13 +++++++++++++
 gcc/c-family/c.opt    |    4 ++++
 gcc/doc/invoke.texi   |   12 ++++++++++++
 3 files changed, 29 insertions(+), 0 deletions(-)

diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c
index 29e9a35..7c9dbfc 100644
--- a/gcc/c-family/c-opts.c
+++ b/gcc/c-family/c-opts.c
@@ -936,6 +936,19 @@ c_common_post_options (const char **pfilename)
 #endif
     }
 
+  /* The -fforce-dwarf-lexical-blocks option is only relevant when debug
+     info is in DWARF4 format */
+  if (flag_force_dwarf_blocks) {
+    if (write_symbols != DWARF2_DEBUG)
+      flag_force_dwarf_blocks = 0;
+    if (write_symbols == DWARF2_DEBUG && dwarf_version < 4) {
+      inform (input_location,
+              "-fforce-dwarf-lexical-blocks is only supported with "
+              "DWARF4 debug format");
+      flag_force_dwarf_blocks = 0;
+    }
+  }
+
   if (flag_preprocess_only)
     {
       /* Open the output now.  We must do so even if flag_no_output is
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index c586e65..b66389e 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -960,6 +960,10 @@ ffor-scope
 C++ ObjC++ Var(flag_new_for_scope) Init(1)
 Scope of for-init-statement variables is local to the loop
 
+fforce-dwarf-lexical-blocks
+C C++ Var(flag_force_dwarf_blocks)
+Force generation of lexical blocks in dwarf output
+
 ffreestanding
 C ObjC C++ ObjC++
 Do not assume that standard C libraries and \"main\" exist
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 9475594..5bf154a 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -333,6 +333,7 @@ Objective-C and Objective-C++ Dialects}.
 -feliminate-unused-debug-symbols -femit-class-debug-always @gol
 -fenable-@var{kind}-@var{pass} @gol
 -fenable-@var{kind}-@var{pass}=@var{range-list} @gol
+-fforce-dwarf-lexical-blocks @gol
 -fdebug-types-section -fmem-report-wpa @gol
 -fmem-report -fpre-ipa-mem-report -fpost-ipa-mem-report -fprofile-arcs @gol
 -fopt-info @gol
@@ -5200,6 +5201,17 @@ normally emits debugging information for classes because using this
 option increases the size of debugging information by as much as a
 factor of two.
 
+@item -fforce-dwarf-lexical-blocks
+Produce debug information (a DW_TAG_lexical_block) for every function
+body, loop body, switch body, case statement, if-then and if-else statement,
+even if the body is a single statement.  Likewise, a lexical block will be
+emitted for the first label of a statement.  This block ends at the end of the
+current lexical scope, or when a break, continue, goto or return statement is
+encountered at the same lexical scope level.  This option is usefull for
+coverage tools that utilize the dwarf debug information.
+This option only applies to C/C++ code and is available when using DWARF
+Version 4 or higher.
+
 @item -fdebug-types-section
 @opindex fdebug-types-section
 @opindex fno-debug-types-section
-- 
1.7.1


[-- Attachment #3: 0002-Use-flag_force_dwarf_blocks.patch --]
[-- Type: text/plain, Size: 24102 bytes --]

From f107431bf094ed2491d8338c4f0157d8b4c7b433 Mon Sep 17 00:00:00 2001
From: Andrei Herman <Andrei_Herman@codesourcery.com>
Date: Sun, 1 Jun 2014 12:35:17 +0300
Subject: [PATCH 2/2]         Use flag_force_dwarf_blocks.

        When flag_force_dwarf_blocks is true, create lexical blocks
        for function body, compound statement, loop body, switch body,
        if-then/if-else statements and labels.

	* c-common.h (struct block_loc_s, block_loc): New.
	(stmt_tree_s): Add x_cur_block_list stack of block_loc structs
	for statement lists of forced scopes (label and c99).
	(block_list_stack, cur_block_info): New macros.
	(push_block_info, pop_block_info, check_pop_block_info): New.

	* c-semantics.c (push_block_info): New.
	(pop_block_info): New.
	(check_pop_block_info): New.

	* c-parser.c (c_parser_declaration_or_fndef): Force a block for
	function body.
	(c_parser_force_block_for_label): New.
	(c_parser_label): Add parameter.  Create a label scope for the first
	label of a statement.
	(c_parser_compound_statement_nostart): Pass last_label when calling
	c_parser_label.
	(c_parser_statement): Likewise.
	(c_parser_statement_after_labels): Force a block for compound statement.
	(c_parser_c99_block_statement): Likewise for switch and loop statement
	if its not a compound statement.  Push/pop the forced scope.
	(c_parser_if_body): Likewise for if-then statement.  Pass last_label
	when calling c_parser_label.
	(c_parser_else_body): Likewise for if-else statement.

	* c-decl.c (get_enclosing_non_forced_scope): New.
	(clear_keep_current_level): New.
	(pushdecl): If current scope is a forced scope, put the declaration
	in the enclosing non-forced scope.

	* c-tree.h (clear_keep_current_level): New.

	* c-typeck.c (pop_scope_for_labels): New.
	(c_finish_goto_label, c_finish_goto_ptr, c_finish_return,
	c_finish_bc_stmt): Call pop_scope_for_labels to close current
        label scope if any.
	(c_end_compound_stmt): Likewise.

	* dwarf2out.c (gen_block_die): Force output a lexical block die
	even for blocks without any local declaration.

	* function.c (reorder_blocks): Skip the forced block, when function
	has no inner blocks.

	* tree-ssa-live.c (remove_unused_scope_block_p): Mark the function
	level forced block as used.

Signed-off-by: Andrei Herman <Andrei_Herman@codesourcery.com>
---
 gcc/c-family/c-common.h    |   23 +++++++++
 gcc/c-family/c-semantics.c |   46 ++++++++++++++++++
 gcc/c/c-decl.c             |   39 +++++++++++++++
 gcc/c/c-parser.c           |  111 ++++++++++++++++++++++++++++++++++++++------
 gcc/c/c-tree.h             |    1 +
 gcc/c/c-typeck.c           |   49 ++++++++++++++++++--
 gcc/dwarf2out.c            |   39 +++++++++------
 gcc/function.c             |    7 +++
 gcc/tree-ssa-live.c        |    6 ++-
 9 files changed, 287 insertions(+), 34 deletions(-)

diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 0d34004..bda689b 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -476,12 +476,27 @@ typedef enum ref_operator {
   RO_ARROW_STAR
 } ref_operator;
 
+/* Information about a statement list created for a label (is_label=true)
+   or for a forced c99 scope.  The -fforce-dwarf-lexical-blocks will
+   force such a scope even if flag_isoc99 is not set.  */
+
+struct GTY(()) block_loc_s {
+  tree block;
+  location_t loc;
+  bool is_label;
+};
+
+typedef struct block_loc_s *block_loc;
+
 /* Information about a statement tree.  */
 
 struct GTY(()) stmt_tree_s {
   /* A stack of statement lists being collected.  */
   vec<tree, va_gc> *x_cur_stmt_list;
 
+  /* A stack of block-loc structs related to forced statement lists.  */
+  vec<block_loc, va_gc> *x_cur_block_list;
+
   /* In C++, Nonzero if we should treat statements as full
      expressions.  In particular, this variable is non-zero if at the
      end of a statement we should destroy any temporaries created
@@ -510,11 +525,16 @@ struct GTY(()) c_language_function {
 };
 
 #define stmt_list_stack (current_stmt_tree ()->x_cur_stmt_list)
+#define block_list_stack (current_stmt_tree ()->x_cur_block_list)
 
 /* When building a statement-tree, this is the current statement list
    being collected.  */
 #define cur_stmt_list	(stmt_list_stack->last ())
 
+/* When building a statement-tree, this is the block list element
+   corresponding to the innermost forced statement list created.  */
+#define cur_block_info	 (block_list_stack->last ())
+
 #define building_stmt_list_p() (stmt_list_stack && !stmt_list_stack->is_empty())
 
 /* Language-specific hooks.  */
@@ -528,6 +548,9 @@ extern void pop_file_scope (void);
 extern stmt_tree current_stmt_tree (void);
 extern tree push_stmt_list (void);
 extern tree pop_stmt_list (tree);
+extern void push_block_info (tree, location_t, bool);
+extern tree pop_block_info (location_t &);
+extern void check_pop_block_info (tree, location_t);
 extern tree add_stmt (tree);
 extern void push_cleanup (tree, tree, bool);
 extern tree pushdecl_top_level (tree);
diff --git a/gcc/c-family/c-semantics.c b/gcc/c-family/c-semantics.c
index f25805a..ec3045f 100644
--- a/gcc/c-family/c-semantics.c
+++ b/gcc/c-family/c-semantics.c
@@ -29,6 +29,52 @@ along with GCC; see the file COPYING3.  If not see
 #include "flags.h"
 #include "tree-iterator.h"
 
+/* Create a block_loc struct for a statement list created on behalf of
+   flag_force_dwarf_blocks.  We use this for label or forced c99 scopes.  */
+
+void
+push_block_info (tree block, location_t loc, bool is_label)
+{
+  if (TREE_CODE(block) != STATEMENT_LIST)
+    return;
+
+  block_loc tl;
+  tl = (block_loc) ggc_internal_cleared_alloc (sizeof(struct block_loc_s));
+  tl->block = block;
+  tl->loc = loc;
+  tl->is_label = is_label;
+  vec_safe_push (block_list_stack, tl);
+}
+
+/* Pop the block_loc struct and return the statement list and its location.  */
+
+tree
+pop_block_info (location_t &loc)
+{
+  block_loc  tl = NULL;
+  tl = block_list_stack->pop ();
+
+  gcc_assert (tl != NULL);
+
+  loc = tl->loc;
+  return tl->block;
+}
+
+/* Pop the last block_loc element if it referes to BLOCK and LOC.  */ 
+
+void
+check_pop_block_info(tree block, location_t loc)
+{
+  if (block_list_stack && !block_list_stack->is_empty())
+    {
+      if (block == cur_block_info->block && loc == cur_block_info->loc
+          && !cur_block_info->is_label)
+        {
+          block_list_stack->pop();
+        }
+    }
+}
+
 /* Create an empty statement tree rooted at T.  */
 
 tree
diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index e8e6bd2..b0d4c0f 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -538,6 +538,32 @@ static tree grokdeclarator (const struct c_declarator *,
 static tree grokparms (struct c_arg_info *, bool);
 static void layout_array_type (tree);
 \f
+/* For a given scope, if this scope has been forced by flag_force_dwarf_blocks
+   (either for a label, or for a c99 block), then find and return the nearest
+   enclosing scope which is not a forced scope.  Otherwise just return the 
+   scope as is.  */
+ 
+static c_scope *
+get_enclosing_non_forced_scope (c_scope * scope)
+{
+  if (block_list_stack && !block_list_stack->is_empty ())
+    {
+      int six = stmt_list_stack->length () - 1;
+      int bix = block_list_stack->length () - 1;
+      while (six >= 0 && bix >= 0)
+        {
+          if ((*stmt_list_stack)[six] == (*block_list_stack)[bix]->block)
+            {
+              scope = scope->outer;
+              six--; bix--;
+            }
+          else
+            return scope;
+        }
+    }
+  return scope;
+}
+
 /* T is a statement.  Add it to the statement-tree.  This is the
    C/ObjC version--C++ has a slightly different version of this
    function.  */
@@ -880,6 +906,14 @@ keep_next_level (void)
   keep_next_level_flag = true;
 }
 
+/* Clear the flag that forces creation of a block for this scope.  */
+
+void
+clear_keep_current_level (void)
+{
+  current_scope->keep = false;
+}
+
 /* Set the flag for the FLOAT_CONST_DECIMAL64 pragma being ON.  */
 
 void
@@ -2674,6 +2708,11 @@ pushdecl (tree x)
       return x;
     }
 
+  if (flag_force_dwarf_blocks)
+    /* If the current scope is a forced scope (by flag_force_dwarf_blocks),
+       put the declaration in the nearest enclosing normal scope.  */
+    scope = get_enclosing_non_forced_scope (scope);
+
   /* First, see if there is another declaration with the same name in
      the current scope.  If there is, duplicate_decls may do all the
      work for us.  If duplicate_decls returns false, that indicates
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 88edf36..f373855 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -1167,7 +1167,7 @@ static void c_parser_initval (c_parser *, struct c_expr *,
 			      struct obstack *);
 static tree c_parser_compound_statement (c_parser *);
 static void c_parser_compound_statement_nostart (c_parser *);
-static void c_parser_label (c_parser *);
+static void c_parser_label (c_parser *, bool);
 static void c_parser_statement (c_parser *);
 static void c_parser_statement_after_labels (c_parser *);
 static void c_parser_if_statement (c_parser *);
@@ -1930,7 +1930,17 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 				   omp_declare_simd_clauses);
       DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus
 	= c_parser_peek_token (parser)->location;
-      fnbody = c_parser_compound_statement (parser);
+      if (flag_force_dwarf_blocks)
+        {
+          /* Force creating a block to represent the function body.  */
+          tree block = c_begin_compound_stmt (true);
+          location_t loc = c_parser_peek_token (parser)->location;
+          keep_next_level ();
+          add_stmt (c_parser_compound_statement (parser));
+          fnbody = c_end_compound_stmt (loc, block, true);
+        }
+      else
+        fnbody = c_parser_compound_statement (parser);
       if (flag_cilkplus && contains_array_notation_expr (fnbody))
 	fnbody = expand_array_notation_exprs (fnbody);
       if (nested)
@@ -4490,6 +4500,29 @@ c_parser_compound_statement (c_parser *parser)
   return c_end_compound_stmt (brace_loc, stmt, true);
 }
 
+/* Force creation of a new scope for a label.  If not followed by a compound
+   statement, make it a block (otherwise, the compound statement will create
+   the block).  Push the created scope onto the block_info stack, so we can
+   identify it as a label scope.  */
+
+static void
+c_parser_force_block_for_label (c_parser *parser, tree label)
+{
+  if (!flag_force_dwarf_blocks || label == NULL_TREE)
+    return;
+
+  /* If the current statement list is a statement expression,
+     do nothing.  */
+  if (STATEMENT_LIST_STMT_EXPR(cur_stmt_list))
+    return;
+
+  if (!c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+    keep_next_level ();
+  tree block = c_begin_compound_stmt (true);
+  location_t loc = c_parser_peek_token (parser)->location;
+  push_block_info (block, loc, true);
+}
+
 /* Parse a compound statement except for the opening brace.  This is
    used for parsing both compound statements and statement expressions
    (which follow different paths to handling the opening).  */
@@ -4560,10 +4593,10 @@ c_parser_compound_statement_nostart (c_parser *parser)
 	    label_loc = c_parser_peek_2nd_token (parser)->location;
 	  else
 	    label_loc = c_parser_peek_token (parser)->location;
+	  mark_valid_location_for_stdc_pragma (false);
+	  c_parser_label (parser, last_label);
 	  last_label = true;
 	  last_stmt = false;
-	  mark_valid_location_for_stdc_pragma (false);
-	  c_parser_label (parser);
 	}
       else if (!last_label
 	       && c_parser_next_tokens_start_declaration (parser))
@@ -4679,7 +4712,7 @@ c_parser_compound_statement_nostart (c_parser *parser)
    expressions being rejected later.  */
 
 static void
-c_parser_label (c_parser *parser)
+c_parser_label (c_parser *parser, bool prev_label)
 {
   location_t loc1 = c_parser_peek_token (parser)->location;
   tree label = NULL_TREE;
@@ -4741,6 +4774,19 @@ c_parser_label (c_parser *parser)
 					 vNULL);
 	}
     }
+  if (label && flag_force_dwarf_blocks)
+    {
+      if (!prev_label)
+        /* If this is the first label on the statement, create a label scope
+           for it.  */
+        c_parser_force_block_for_label (parser, label);
+      else
+        /* The first label may not have seen the open brace and therefor set
+           the keep flag in current scope.  If we see it now, we should clear
+           the flag (the next compound statement will create the block).  */
+        if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+          clear_keep_current_level ();
+    }      
 }
 
 /* Parse a statement (C90 6.6, C99 6.8).
@@ -4862,11 +4908,15 @@ c_parser_label (c_parser *parser)
 static void
 c_parser_statement (c_parser *parser)
 {
+  bool last_label = false;
   while (c_parser_next_token_is_keyword (parser, RID_CASE)
 	 || c_parser_next_token_is_keyword (parser, RID_DEFAULT)
 	 || (c_parser_next_token_is (parser, CPP_NAME)
 	     && c_parser_peek_2nd_token (parser)->type == CPP_COLON))
-    c_parser_label (parser);
+    {
+      c_parser_label (parser, last_label);
+      last_label = true;
+    }
   c_parser_statement_after_labels (parser);
 }
 
@@ -4882,6 +4932,8 @@ c_parser_statement_after_labels (c_parser *parser)
   switch (c_parser_peek_token (parser)->type)
     {
     case CPP_OPEN_BRACE:
+      if (flag_force_dwarf_blocks)
+        keep_next_level ();
       add_stmt (c_parser_compound_statement (parser));
       break;
     case CPP_KEYWORD:
@@ -5068,10 +5120,18 @@ c_parser_paren_condition (c_parser *parser)
 static tree
 c_parser_c99_block_statement (c_parser *parser)
 {
-  tree block = c_begin_compound_stmt (flag_isoc99);
+  bool force_scope = flag_force_dwarf_blocks
+    && !c_parser_next_token_is (parser, CPP_OPEN_BRACE);
+  if (force_scope)
+    keep_next_level ();
+  tree block = c_begin_compound_stmt (flag_isoc99 || force_scope);
   location_t loc = c_parser_peek_token (parser)->location;
+  if (force_scope && !flag_isoc99)
+    push_block_info (block, loc, false);
   c_parser_statement (parser);
-  return c_end_compound_stmt (loc, block, flag_isoc99);
+  if (force_scope && !flag_isoc99)
+    check_pop_block_info(block, loc);
+  return c_end_compound_stmt (loc, block, flag_isoc99 || force_scope);
 }
 
 /* Parse the body of an if statement.  This is just parsing a
@@ -5085,13 +5145,21 @@ c_parser_c99_block_statement (c_parser *parser)
 static tree
 c_parser_if_body (c_parser *parser, bool *if_p)
 {
-  tree block = c_begin_compound_stmt (flag_isoc99);
+  if (flag_force_dwarf_blocks)
+    keep_next_level ();
+  tree block = c_begin_compound_stmt (flag_isoc99 || flag_force_dwarf_blocks);
   location_t body_loc = c_parser_peek_token (parser)->location;
+  if (flag_force_dwarf_blocks && !flag_isoc99)
+    push_block_info (block, body_loc, false);
+  bool last_label = false;
   while (c_parser_next_token_is_keyword (parser, RID_CASE)
 	 || c_parser_next_token_is_keyword (parser, RID_DEFAULT)
 	 || (c_parser_next_token_is (parser, CPP_NAME)
 	     && c_parser_peek_2nd_token (parser)->type == CPP_COLON))
-    c_parser_label (parser);
+    {
+      c_parser_label (parser, last_label);
+      last_label = true;
+    }
   *if_p = c_parser_next_token_is_keyword (parser, RID_IF);
   if (c_parser_next_token_is (parser, CPP_SEMICOLON))
     {
@@ -5106,7 +5174,10 @@ c_parser_if_body (c_parser *parser, bool *if_p)
     add_stmt (c_parser_compound_statement (parser));
   else
     c_parser_statement_after_labels (parser);
-  return c_end_compound_stmt (body_loc, block, flag_isoc99);
+  if (flag_force_dwarf_blocks && !flag_isoc99)
+    check_pop_block_info(block, body_loc);
+  return c_end_compound_stmt (body_loc, block, 
+                              flag_isoc99 || flag_force_dwarf_blocks);
 }
 
 /* Parse the else body of an if statement.  This is just parsing a
@@ -5117,12 +5188,22 @@ static tree
 c_parser_else_body (c_parser *parser)
 {
   location_t else_loc = c_parser_peek_token (parser)->location;
-  tree block = c_begin_compound_stmt (flag_isoc99);
+  bool force_scope = flag_force_dwarf_blocks
+    && !c_parser_next_token_is (parser, CPP_OPEN_BRACE);
+  if (force_scope)
+    keep_next_level ();
+  tree block = c_begin_compound_stmt (flag_isoc99 || force_scope);
+  if (force_scope && !flag_isoc99)
+    push_block_info (block, else_loc, false);
+  bool last_label = false;
   while (c_parser_next_token_is_keyword (parser, RID_CASE)
 	 || c_parser_next_token_is_keyword (parser, RID_DEFAULT)
 	 || (c_parser_next_token_is (parser, CPP_NAME)
 	     && c_parser_peek_2nd_token (parser)->type == CPP_COLON))
-    c_parser_label (parser);
+    {
+      c_parser_label (parser, last_label);
+      last_label = true;
+    }
   if (c_parser_next_token_is (parser, CPP_SEMICOLON))
     {
       location_t loc = c_parser_peek_token (parser)->location;
@@ -5134,7 +5215,9 @@ c_parser_else_body (c_parser *parser)
     }
   else
     c_parser_statement_after_labels (parser);
-  return c_end_compound_stmt (else_loc, block, flag_isoc99);
+  if (force_scope && !flag_isoc99)
+    check_pop_block_info(block, else_loc);
+  return c_end_compound_stmt (else_loc, block, flag_isoc99 || force_scope);
 }
 
 /* Parse an if statement (C90 6.6.4, C99 6.8.4).
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index e7dcb35..bb40d82 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -504,6 +504,7 @@ extern tree groktypename (struct c_type_name *, tree *, bool *);
 extern tree grokparm (const struct c_parm *, tree *);
 extern tree implicitly_declare (location_t, tree);
 extern void keep_next_level (void);
+extern void clear_keep_current_level (void);
 extern void pending_xref_error (void);
 extern void c_push_function_context (void);
 extern void c_pop_function_context (void);
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 6ca584b..1c8eb2f 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -9132,6 +9132,25 @@ build_asm_expr (location_t loc, tree string, tree outputs, tree inputs,
   return args;
 }
 \f
+/* If current scope is a label scope, pop it from block info stack
+   and close it's compound statement.  */
+
+static void
+pop_scope_for_labels (void)
+{
+  while (block_list_stack && !block_list_stack->is_empty ())
+    {
+      if (cur_stmt_list == cur_block_info->block && cur_block_info->is_label)
+        {
+          location_t loc;
+          tree block = pop_block_info (loc);
+          add_stmt(c_end_compound_stmt (loc, block, true));
+        }
+      else
+        break;
+    }
+}
+
 /* Generate a goto statement to LABEL.  LOC is the location of the
    GOTO.  */
 
@@ -9145,7 +9164,12 @@ c_finish_goto_label (location_t loc, tree label)
   {
     tree t = build1 (GOTO_EXPR, void_type_node, decl);
     SET_EXPR_LOCATION (t, loc);
-    return add_stmt (t);
+    {
+      tree stmt = add_stmt (t);
+      if (flag_force_dwarf_blocks)
+        pop_scope_for_labels ();
+      return stmt;
+    }
   }
 }
 
@@ -9161,7 +9185,12 @@ c_finish_goto_ptr (location_t loc, tree expr)
   expr = convert (ptr_type_node, expr);
   t = build1 (GOTO_EXPR, void_type_node, expr);
   SET_EXPR_LOCATION (t, loc);
-  return add_stmt (t);
+  {
+    tree stmt = add_stmt (t);
+    if (flag_force_dwarf_blocks)
+      pop_scope_for_labels ();
+    return stmt;
+  }
 }
 
 /* Generate a C `return' statement.  RETVAL is the expression for what
@@ -9325,7 +9354,12 @@ c_finish_return (location_t loc, tree retval, tree origtype)
 
   ret_stmt = build_stmt (loc, RETURN_EXPR, retval);
   TREE_NO_WARNING (ret_stmt) |= no_warning;
-  return add_stmt (ret_stmt);
+  {
+    tree stmt = add_stmt (ret_stmt);
+    if (flag_force_dwarf_blocks)
+      pop_scope_for_labels ();
+    return stmt;
+  }
 }
 \f
 struct c_switch {
@@ -9698,7 +9732,12 @@ c_finish_bc_stmt (location_t loc, tree *label_p, bool is_break)
   if (!is_break)
     add_stmt (build_predict_expr (PRED_CONTINUE, NOT_TAKEN));
 
-  return add_stmt (build1 (GOTO_EXPR, void_type_node, label));
+  {
+    tree stmt = add_stmt (build1 (GOTO_EXPR, void_type_node, label));
+    if (flag_force_dwarf_blocks)
+      pop_scope_for_labels ();
+    return stmt;
+  }
 }
 
 /* A helper routine for c_process_expr_stmt and c_finish_stmt_expr.  */
@@ -9951,6 +9990,8 @@ c_end_compound_stmt (location_t loc, tree stmt, bool do_scope)
     {
       if (c_dialect_objc ())
 	objc_clear_super_receiver ();
+      if (flag_force_dwarf_blocks)
+        pop_scope_for_labels ();
       block = pop_scope ();
     }
 
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 7c93074..3b8be30 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -20129,21 +20129,30 @@ gen_block_die (tree stmt, dw_die_ref context_die, int depth)
     must_output_die = 1;
   else
     {
-      /* Determine if this block directly contains any "significant"
-	 local declarations which we will need to output DIEs for.  */
-      if (debug_info_level > DINFO_LEVEL_TERSE)
-	/* We are not in terse mode so *any* local declaration counts
-	   as being a "significant" one.  */
-	must_output_die = ((BLOCK_VARS (stmt) != NULL
-			    || BLOCK_NUM_NONLOCALIZED_VARS (stmt))
-			   && (TREE_USED (stmt)
-			       || TREE_ASM_WRITTEN (stmt)
-			       || BLOCK_ABSTRACT (stmt)));
-      else if ((TREE_USED (stmt)
-		|| TREE_ASM_WRITTEN (stmt)
-		|| BLOCK_ABSTRACT (stmt))
-      	       && !dwarf2out_ignore_block (stmt))
-	must_output_die = 1;
+      if (flag_force_dwarf_blocks) 
+        {
+          must_output_die = (TREE_USED (stmt)
+                             || TREE_ASM_WRITTEN (stmt)
+                             || BLOCK_ABSTRACT (stmt));
+        }
+      else 
+        {
+          /* Determine if this block directly contains any "significant"
+             local declarations which we will need to output DIEs for.  */
+          if (debug_info_level > DINFO_LEVEL_TERSE)
+            /* We are not in terse mode so *any* local declaration counts
+               as being a "significant" one.  */
+            must_output_die = ((BLOCK_VARS (stmt) != NULL
+                                || BLOCK_NUM_NONLOCALIZED_VARS (stmt))
+                               && (TREE_USED (stmt)
+                                   || TREE_ASM_WRITTEN (stmt)
+                                   || BLOCK_ABSTRACT (stmt)));
+          else if ((TREE_USED (stmt)
+                    || TREE_ASM_WRITTEN (stmt)
+                    || BLOCK_ABSTRACT (stmt))
+                   && !dwarf2out_ignore_block (stmt))
+            must_output_die = 1;
+        }
     }
 
   /* It would be a waste of space to generate a Dwarf DW_TAG_lexical_block
diff --git a/gcc/function.c b/gcc/function.c
index ec2ea26..7a6418b 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -4117,6 +4117,13 @@ reorder_blocks (void)
   if (block == NULL_TREE)
     return;
 
+  /* In case we added another block level to functions, use it as top block  */
+  if (flag_force_dwarf_blocks
+      && BLOCK_SUBBLOCKS (block) && BLOCK_CHAIN (block) == NULL_TREE
+      && BLOCK_VARS (block) == NULL_TREE
+      && BLOCK_SUBBLOCKS (BLOCK_SUBBLOCKS (block)) == NULL_TREE
+      && BLOCK_CHAIN (BLOCK_SUBBLOCKS (block)) == NULL_TREE)
+    block = BLOCK_SUBBLOCKS (block);
   auto_vec<tree, 10> block_stack;
 
   /* Reset the TREE_ASM_WRITTEN bit for all blocks.  */
diff --git a/gcc/tree-ssa-live.c b/gcc/tree-ssa-live.c
index 3cd3613..9aa4124 100644
--- a/gcc/tree-ssa-live.c
+++ b/gcc/tree-ssa-live.c
@@ -599,7 +599,11 @@ remove_unused_scope_block_p (tree scope)
      ;
    /* Outer scope is always used.  */
    else if (!BLOCK_SUPERCONTEXT (scope)
-            || TREE_CODE (BLOCK_SUPERCONTEXT (scope)) == FUNCTION_DECL)
+            || TREE_CODE (BLOCK_SUPERCONTEXT (scope)) == FUNCTION_DECL
+            || (flag_force_dwarf_blocks && 
+                BLOCK_SUPERCONTEXT (BLOCK_SUPERCONTEXT (scope)) &&
+                TREE_CODE (BLOCK_SUPERCONTEXT
+                           (BLOCK_SUPERCONTEXT (scope))) == FUNCTION_DECL))
      unused = false;
    /* Innermost blocks with no live variables nor statements can be always
       eliminated.  */
-- 
1.7.1


[-- Attachment #4: gcc_c_ChangeLog --]
[-- Type: text/plain, Size: 1222 bytes --]

2014-06-01  Andrei Herman  <Andrei_Herman@codesourcery.com>

	* c-parser.c (c_parser_declaration_or_fndef): Force a block for
	function body.
	(c_parser_force_block_for_label): New.
	(c_parser_label): Add parameter.  Create a label scope for the first
	label of a statement.
	(c_parser_compound_statement_nostart): Pass last_label when calling
	c_parser_label.
	(c_parser_statement): Likewise.
	(c_parser_statement_after_labels): Force a block for compound statement.
	(c_parser_c99_block_statement): Likewise for switch and loop statement
	if its not a compound statement.  Push/pop the forced scope.
	(c_parser_if_body): Likewise for if-then statement.  Pass last_label
	when calling c_parser_label.
	(c_parser_else_body): Likewise for if-else statement.

	* c-decl.c (get_enclosing_non_forced_scope): New.
	(clear_keep_current_level): New.
	(pushdecl): If current scope is a forced scope, put the declaration
	in the enclosing non-forced scope.

	* c-tree.h (clear_keep_current_level): New.

	* c-typeck.c (pop_scope_for_labels): New.
	(c_finish_goto_label, c_finish_goto_ptr, c_finish_return,
	c_finish_bc_stmt): Call pop_scope_for_labels to close current
        label scope if any.
	(c_end_compound_stmt): Likewise.

[-- Attachment #5: gcc_c-family_ChangeLog --]
[-- Type: text/plain, Size: 555 bytes --]

2014-06-01  Andrei Herman  <Andrei_Herman@codesourcery.com>

	* c.opt: Add -fforce-dwarf-lexical-blocks option

	* c-opts.c (c_common_post_options): Limit its use to dwarf4.

	* c-common.h (struct block_loc_s, block_loc): New.
	(stmt_tree_s): Add x_cur_block_list stack of block_loc structs
	for statement lists of forced scopes (label and c99).
	(block_list_stack, cur_block_info): New macros.
	(push_block_info, pop_block_info, check_pop_block_info): New.

	* c-semantics.c (push_block_info): New.
	(pop_block_info): New.
	(check_pop_block_info): New.


[-- Attachment #6: gcc_ChangeLog --]
[-- Type: text/plain, Size: 429 bytes --]

2014-06-01  Andrei Herman  <Andrei_Herman@codesourcery.com>

	* doc/invoke.texi: Document force-dwarf-lexical-blocks option.

	* dwarf2out.c (gen_block_die): Force output a lexical block die
	even for blocks without any local declaration.

	* function.c (reorder_blocks): Skip the forced block, when function
	has no inner blocks.

	* tree-ssa-live.c (remove_unused_scope_block_p): Mark the function
	level forced block as used.

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2014-08-14 21:14 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-05-07  9:32 [PATCH GCC]Add 'force-dwarf-lexical-blocks' command line option Herman, Andrei
2014-05-07  9:36 ` pinskia
2014-05-07  9:43   ` Herman, Andrei
2014-05-07 15:59 ` Mike Stump
2014-05-07 17:19   ` Herman, Andrei
2014-05-07 17:25     ` Andrew Pinski
2014-05-07 18:01     ` Mike Stump
2014-05-07 18:01 ` Joseph S. Myers
2014-05-08 14:57   ` Herman, Andrei
2014-05-08 17:26     ` Joseph S. Myers
2014-05-08 17:44       ` Herman, Andrei
2014-05-08 21:01         ` Joseph S. Myers
2014-06-01 10:33 Herman, Andrei
2014-06-19 21:09 ` Joseph S. Myers
2014-06-21 17:06   ` Herman, Andrei
2014-07-28 13:50   ` Herman, Andrei
2014-08-14 21:14     ` Joseph S. Myers

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).