Patchwork [google/gcc-4_6] More Fission updates (revised) (issue6219049)

login
register
mail settings
Submitter Cary Coutant
Date May 23, 2012, 1:56 a.m.
Message ID <20120523015657.449F8E1279@ccoutant.mtv.corp.google.com>
Download mbox | patch
Permalink /patch/160764/
State New
Headers show

Comments

Cary Coutant - May 23, 2012, 1:56 a.m.
[Revised to address review comments and to fix a bug we found late:
We've changed want_pubnames to a static inline function, and changed
the pubnames output to include (ironically enough) inline functions.]

This patch is for the google/gcc-4_6 branch.

Fission improvements and bug fixes.  Adds new DW_OP_GNU_const_index to
handle TLS offsets in debug info.  Adds -gpubnames/-gno-pubnames options
to explicitly request .debug_pubnames/pubtypes sections.  Adds style
parameter to C/C++ pretty-printer so that we can get canonical pubnames
without affecting diagnostic output.

Bootstrapped and tested on x86_64.


2012-05-21  Sterling Augustine  <saugustine@google.com>
	    Cary Coutant  <ccoutant@google.com>

include/
	* dwarf2.h: Add DW_OP_GNU_const_index.

gcc/
	* opts.c (finish_options): -gfission implies -gpubnames.
	(common_handle_option): Pass empty arg string to set_debug_level.
	* common.opt (gno-fission): New option.
	(gfission): Remove JoinedOrMissing, add RejectNegative.
	(gno-pubnames, gpubnames): New options.
	* target.def (want_debug_pub_sections): Change default to false.
	* gcc.c (check_live_switch): Check -g options for -gno- options.

	* c-family/c-pretty-print.c (pp_c_specifier_qualifier_list): Add
	support for gnu_v3 style.
	* c-family/c-pretty-print.h (pp_c_flag_gnu_v3): New enum constant.
	* cp/error.c (dump_decl): Add support for gnu_v3 style.
	(decl_as_string): Likewise.
	(lang_decl_name): Likewise.
	* cp/cp-lang.c (cxx_dwarf_name): Likewise.
	* cp/cp-tree.h (enum overload_flags): Add TFF_MATCH_GNU_V3_DEMANGLER.

	* dwarf2out.c (dwarf_stack_op_name): Add DW_OP_GNU_const_index.
	(size_of_loc_descr): Likewise.
	(output_loc_operands): Likewise.
	(output_loc_operands_raw): Likewise.
	(dw_addr_op): New function.
	(new_addr_loc_descr): Call dw_addr_op.
	(want_pubnames): New function.
	(add_AT_pubnames): Add DW_AT_GNU_pubnames/pubtypes only if
	generating .debug_pubnames/pubtypes sections.
	(add_pubname_string): Check for -gpubnames option.
	(add_pubname): Likewise.
	(add_pubtype): Likewise.
	(output_pubnames): Likewise.
	(mem_loc_descriptor): Call new_addr_loc_desc for TLS vars.
	(loc_list_from_tree): Likewise.
	(gen_subprogram_die): Output pubnames for all inlined functions.
	(output_addr_table): Handle DW_OP_GNU_const_index.  Add missing
	newline.
	(hash_loc_operands): Add DW_OP_GNU_const_index.
	(compare_loc_operands): Likewise.

	* testsuite/g++.old-deja/g++.pt/memtemp77.C: Revert earlier change
	to expected results.
	* testsuite/g++.dg/ext/pretty3.C: Likewise.
	* testsuite/g++.dg/warn/Wuninitializable-member.C: Likewise.
	* testsuite/g++.dg/warn/pr35711.C: Likewise.
	* testsuite/g++.dg/pr44486.C: Likewise.



--
This patch is available for review at http://codereview.appspot.com/6219049
Diego Novillo - May 24, 2012, 8:23 p.m.
On 12-05-22 21:56 , Cary Coutant wrote:
> [Revised to address review comments and to fix a bug we found late:
> We've changed want_pubnames to a static inline function, and changed
> the pubnames output to include (ironically enough) inline functions.]
>
> This patch is for the google/gcc-4_6 branch.
>
> Fission improvements and bug fixes.  Adds new DW_OP_GNU_const_index to
> handle TLS offsets in debug info.  Adds -gpubnames/-gno-pubnames options
> to explicitly request .debug_pubnames/pubtypes sections.  Adds style
> parameter to C/C++ pretty-printer so that we can get canonical pubnames
> without affecting diagnostic output.
>
> Bootstrapped and tested on x86_64.
>
>
> 2012-05-21  Sterling Augustine<saugustine@google.com>
> 	Cary Coutant<ccoutant@google.com>
>
> include/
> 	* dwarf2.h: Add DW_OP_GNU_const_index.
>
> gcc/
> 	* opts.c (finish_options): -gfission implies -gpubnames.
> 	(common_handle_option): Pass empty arg string to set_debug_level.
> 	* common.opt (gno-fission): New option.
> 	(gfission): Remove JoinedOrMissing, add RejectNegative.
> 	(gno-pubnames, gpubnames): New options.
> 	* target.def (want_debug_pub_sections): Change default to false.
> 	* gcc.c (check_live_switch): Check -g options for -gno- options.
>
> 	* c-family/c-pretty-print.c (pp_c_specifier_qualifier_list): Add
> 	support for gnu_v3 style.
> 	* c-family/c-pretty-print.h (pp_c_flag_gnu_v3): New enum constant.
> 	* cp/error.c (dump_decl): Add support for gnu_v3 style.
> 	(decl_as_string): Likewise.
> 	(lang_decl_name): Likewise.
> 	* cp/cp-lang.c (cxx_dwarf_name): Likewise.
> 	* cp/cp-tree.h (enum overload_flags): Add TFF_MATCH_GNU_V3_DEMANGLER.
>
> 	* dwarf2out.c (dwarf_stack_op_name): Add DW_OP_GNU_const_index.
> 	(size_of_loc_descr): Likewise.
> 	(output_loc_operands): Likewise.
> 	(output_loc_operands_raw): Likewise.
> 	(dw_addr_op): New function.
> 	(new_addr_loc_descr): Call dw_addr_op.
> 	(want_pubnames): New function.
> 	(add_AT_pubnames): Add DW_AT_GNU_pubnames/pubtypes only if
> 	generating .debug_pubnames/pubtypes sections.
> 	(add_pubname_string): Check for -gpubnames option.
> 	(add_pubname): Likewise.
> 	(add_pubtype): Likewise.
> 	(output_pubnames): Likewise.
> 	(mem_loc_descriptor): Call new_addr_loc_desc for TLS vars.
> 	(loc_list_from_tree): Likewise.
> 	(gen_subprogram_die): Output pubnames for all inlined functions.
> 	(output_addr_table): Handle DW_OP_GNU_const_index.  Add missing
> 	newline.
> 	(hash_loc_operands): Add DW_OP_GNU_const_index.
> 	(compare_loc_operands): Likewise.
>
> 	* testsuite/g++.old-deja/g++.pt/memtemp77.C: Revert earlier change
> 	to expected results.
> 	* testsuite/g++.dg/ext/pretty3.C: Likewise.
> 	* testsuite/g++.dg/warn/Wuninitializable-member.C: Likewise.
> 	* testsuite/g++.dg/warn/pr35711.C: Likewise.
> 	* testsuite/g++.dg/pr44486.C: Likewise.

OK with a couple of nits I found on the second read.

> @@ -445,6 +445,9 @@ pp_c_specifier_qualifier_list (c_pretty_
>   {
>     const enum tree_code code = TREE_CODE (t);
>
> +  if (!(pp->flags&  pp_c_flag_gnu_v3)&&  TREE_CODE (t) != POINTER_TYPE)
> +    pp_c_type_qualifier_list (pp, t);

You can use 'code' here instead of TREE_CODE(t).  Either that, or remove 
the declaration of 'code' above.

> +
>     switch (code)
>       {
>       case REFERENCE_TYPE:
> @@ -489,7 +492,7 @@ pp_c_specifier_qualifier_list (c_pretty_
>         pp_simple_type_specifier (pp, t);
>         break;
>       }
> -  if (TREE_CODE (t) != POINTER_TYPE)
> +  if ((pp->flags&  pp_c_flag_gnu_v3)&&  TREE_CODE (t) != POINTER_TYPE)

Likewise here.

> @@ -6589,17 +6595,30 @@ static bool generic_type_p (tree);
>   static void schedule_generic_params_dies_gen (tree t);
>   static void gen_scheduled_generic_parms_dies (void);
>
> +/* DW_OP_addr is relocated by the debug info consumer, while
> +   tls relative operands should not be.  */
> +
> +static inline enum dwarf_location_atom dw_addr_op (bool dtprel)

Can you describe what DTPREL is used for here?



Diego.
Cary Coutant - May 24, 2012, 9:03 p.m.
> OK with a couple of nits I found on the second read.
>
>> +  if (!(pp->flags&  pp_c_flag_gnu_v3)&&  TREE_CODE (t) != POINTER_TYPE)
>> +    pp_c_type_qualifier_list (pp, t);
>
> You can use 'code' here instead of TREE_CODE(t).  Either that, or remove the
> declaration of 'code' above.
>
>> -  if (TREE_CODE (t) != POINTER_TYPE)
>> +  if ((pp->flags&  pp_c_flag_gnu_v3)&&  TREE_CODE (t) != POINTER_TYPE)
>
> Likewise here.

Fixed. Note that the original code was guilty as well. :-)

>> +/* DW_OP_addr is relocated by the debug info consumer, while
>> +   tls relative operands should not be.  */
>> +
>> +static inline enum dwarf_location_atom dw_addr_op (bool dtprel)
>
> Can you describe what DTPREL is used for here?

I've rewritten the comment as follows:

/* Return the operator to use for an address of a variable.
   DTPREL is true for thread-local variables whose address
   is really an offset relative to the TLS pointer, which
   will need link-time relocation, but will not need relocation
   by the DWARF consumer.  For those, we use DW_OP_const*.
   For regular variables, which need both link-time relocation
   and consumer-level relocation (e.g., to account for
   shared objects loaded at a random address), we use
   DW_OP_addr*.  */

Thanks!

-cary

Patch

Index: include/dwarf2.h
===================================================================
--- include/dwarf2.h	(revision 187751)
+++ include/dwarf2.h	(working copy)
@@ -546,8 +546,9 @@  enum dwarf_location_atom
     DW_OP_GNU_uninit     = 0xf0,
     DW_OP_GNU_encoded_addr = 0xf1,
     DW_OP_GNU_implicit_pointer = 0xf2,
-    /* Extension for Fission.  See http://gcc.gnu.org/wiki/DebugFission.  */
+    /* Extensions for Fission.  See http://gcc.gnu.org/wiki/DebugFission.  */
     DW_OP_GNU_addr_index = 0xfb,
+    DW_OP_GNU_const_index = 0xfc,
     /* HP extensions.  */
     DW_OP_HP_unknown     = 0xe0, /* Ouch, the same as GNU_push_tls_address.  */
     DW_OP_HP_is_value    = 0xe1,
Index: gcc/c-family/c-pretty-print.c
===================================================================
--- gcc/c-family/c-pretty-print.c	(revision 187751)
+++ gcc/c-family/c-pretty-print.c	(working copy)
@@ -445,6 +445,9 @@  pp_c_specifier_qualifier_list (c_pretty_
 {
   const enum tree_code code = TREE_CODE (t);
 
+  if (!(pp->flags & pp_c_flag_gnu_v3) && TREE_CODE (t) != POINTER_TYPE)
+    pp_c_type_qualifier_list (pp, t);
+
   switch (code)
     {
     case REFERENCE_TYPE:
@@ -489,7 +492,7 @@  pp_c_specifier_qualifier_list (c_pretty_
       pp_simple_type_specifier (pp, t);
       break;
     }
-  if (TREE_CODE (t) != POINTER_TYPE)
+  if ((pp->flags & pp_c_flag_gnu_v3) && TREE_CODE (t) != POINTER_TYPE)
     pp_c_type_qualifier_list (pp, t);
 }
 
Index: gcc/c-family/c-pretty-print.h
===================================================================
--- gcc/c-family/c-pretty-print.h	(revision 187751)
+++ gcc/c-family/c-pretty-print.h	(working copy)
@@ -30,7 +30,8 @@  along with GCC; see the file COPYING3.  
 typedef enum
   {
      pp_c_flag_abstract = 1 << 1,
-     pp_c_flag_last_bit = 2
+     pp_c_flag_last_bit = 2,
+     pp_c_flag_gnu_v3 = 4
   } pp_c_pretty_print_flags;
 
 
Index: gcc/target.def
===================================================================
--- gcc/target.def	(revision 187751)
+++ gcc/target.def	(working copy)
@@ -2795,7 +2795,7 @@  DEFHOOKPOD
  "True if the @code{.debug_pubtypes} and @code{.debug_pubnames} sections\
  should be emitted.  These sections are not used on most platforms, and\
  in particular GDB does not use them.",
- bool, true)
+ bool, false)
 
 DEFHOOKPOD
 (delay_sched2, "True if sched2 is not to be run at its normal place.  \
Index: gcc/gcc.c
===================================================================
--- gcc/gcc.c	(revision 187751)
+++ gcc/gcc.c	(working copy)
@@ -448,7 +448,7 @@  ignored.  White space may also appear an
 colon in these constructs, except between . or * and the corresponding
 word.
 
-The -O, -f, -m, and -W switches are handled specifically in these
+The -O, -f, -g, -m, and -W switches are handled specifically in these
 constructs.  If another value of -O or the negated form of a -f, -m, or
 -W switch is found later in the command line, the earlier switch
 value is ignored, except with {S*} where S is just one letter; this
@@ -5867,7 +5867,7 @@  process_brace_body (const char *p, const
    on the command line.  PREFIX_LENGTH is the length of XXX in an {XXX*}
    spec, or -1 if either exact match or %* is used.
 
-   A -O switch is obsoleted by a later -O switch.  A -f, -m, or -W switch
+   A -O switch is obsoleted by a later -O switch.  A -f, -g, -m, or -W switch
    whose value does not begin with "no-" is obsoleted by the same value
    with the "no-", similarly for a switch with the "no-" prefix.  */
 
@@ -5904,7 +5904,7 @@  check_live_switch (int switchnum, int pr
 	  }
       break;
 
-    case 'W':  case 'f':  case 'm':
+    case 'W':  case 'f':  case 'm': case 'g':
       if (! strncmp (name + 1, "no-", 3))
 	{
 	  /* We have Xno-YYY, search for XYYY.  */
Index: gcc/testsuite/g++.old-deja/g++.pt/memtemp77.C
===================================================================
--- gcc/testsuite/g++.old-deja/g++.pt/memtemp77.C	(revision 187751)
+++ gcc/testsuite/g++.old-deja/g++.pt/memtemp77.C	(working copy)
@@ -19,7 +19,7 @@  const char* S3<char>::h(int) { return __
 int main()
 {
   if (strcmp (S3<double>::h(7), 
-	      "static char const* S3<T>::h(U) [with U = int, T = double]") == 0)
+	      "static const char* S3<T>::h(U) [with U = int, T = double]") == 0)
     return 0;
   else 
     return 1;
Index: gcc/testsuite/g++.dg/ext/pretty3.C
===================================================================
--- gcc/testsuite/g++.dg/ext/pretty3.C	(revision 187751)
+++ gcc/testsuite/g++.dg/ext/pretty3.C	(working copy)
@@ -16,4 +16,4 @@  int main ()
 {
   printf ("%s\n", D<int>().foo (0));
 }
-// { dg-final { scan-assembler "char const\\* D<U>::foo\\(typename B<U>::X\\)" } }
+// { dg-final { scan-assembler "const char\\* D<U>::foo\\(typename B<U>::X\\)" } }
Index: gcc/testsuite/g++.dg/warn/Wuninitializable-member.C
===================================================================
--- gcc/testsuite/g++.dg/warn/Wuninitializable-member.C	(revision 187751)
+++ gcc/testsuite/g++.dg/warn/Wuninitializable-member.C	(working copy)
@@ -8,7 +8,7 @@  public:
 };
 
 class Y {
-  const int var;// { dg-warning "non-static const member 'int const Y::var' in class without a constructor" }
+  const int var;// { dg-warning "non-static const member 'const int Y::var' in class without a constructor" }
 public:
   int g(){ return 2*var; }
 };
Index: gcc/testsuite/g++.dg/warn/pr35711.C
===================================================================
--- gcc/testsuite/g++.dg/warn/pr35711.C	(revision 187751)
+++ gcc/testsuite/g++.dg/warn/pr35711.C	(working copy)
@@ -4,5 +4,5 @@ 
 
 int* foo (volatile int *p)
 {
-  return (int*)p; // { dg-warning "cast from type 'int volatile\\*' to type 'int\\*' casts away qualifiers" }
+  return (int*)p; // { dg-warning "cast from type 'volatile int\\*' to type 'int\\*' casts away qualifiers" }
 }
Index: gcc/testsuite/g++.dg/pr44486.C
===================================================================
--- gcc/testsuite/g++.dg/pr44486.C	(revision 187751)
+++ gcc/testsuite/g++.dg/pr44486.C	(working copy)
@@ -7,4 +7,4 @@  namespace { S f() { const char * s = __P
 
 int main() { f(); }
 
-// { dg-final { scan-assembler "S \\(anonymous namespace\\)::f" } }
+// { dg-final { scan-assembler "S \{anonymous\}::f" } }
Index: gcc/cp/error.c
===================================================================
--- gcc/cp/error.c	(revision 187751)
+++ gcc/cp/error.c	(working copy)
@@ -974,7 +974,12 @@  dump_decl (tree t, int flags)
 	    dump_scope (CP_DECL_CONTEXT (t), flags);
 	  flags &= ~TFF_UNQUALIFIED_NAME;
 	  if (DECL_NAME (t) == NULL_TREE)
-	    pp_cxx_ws_string (cxx_pp, M_("(anonymous namespace)"));
+            {
+              if (!(pp_c_base (cxx_pp)->flags & pp_c_flag_gnu_v3))
+                pp_cxx_ws_string (cxx_pp, M_("{anonymous}"));
+              else
+                pp_cxx_ws_string (cxx_pp, M_("(anonymous namespace)"));
+            }
 	  else
 	    pp_cxx_tree_identifier (cxx_pp, DECL_NAME (t));
 	}
@@ -2459,7 +2464,10 @@  decl_as_string (tree decl, int flags)
 {
   reinit_cxx_pp ();
   pp_translate_identifiers (cxx_pp) = false;
+  if (flags & TFF_MATCH_GNU_V3_DEMANGLER)
+    pp_c_base (cxx_pp)->flags |= pp_c_flag_gnu_v3;
   dump_decl (decl, flags);
+  pp_c_base (cxx_pp)->flags &= ~pp_c_flag_gnu_v3;
   return pp_formatted_text (cxx_pp);
 }
 
@@ -2494,8 +2502,9 @@  lang_decl_name (tree decl, int v, bool t
 
   if (TREE_CODE (decl) == FUNCTION_DECL)
     dump_function_name (decl, TFF_PLAIN_IDENTIFIER);
-  else if (DECL_NAME (decl) == NULL && TREE_CODE (decl) == NAMESPACE_DECL)
-    pp_string (cxx_pp, M_("(anonymous namespace)"));
+  else if ((DECL_NAME (decl) == NULL_TREE)
+           && TREE_CODE (decl) == NAMESPACE_DECL)
+    dump_decl (decl, TFF_PLAIN_IDENTIFIER);
   else
     dump_decl (DECL_NAME (decl), TFF_PLAIN_IDENTIFIER);
 
Index: gcc/cp/cp-lang.c
===================================================================
--- gcc/cp/cp-lang.c	(revision 187751)
+++ gcc/cp/cp-lang.c	(working copy)
@@ -185,8 +185,14 @@  cxx_dwarf_name (tree t, int verbosity)
   if (verbosity >= 2)
     return decl_as_string (t,
 			   TFF_DECL_SPECIFIERS | TFF_UNQUALIFIED_NAME
-			   | TFF_NO_OMIT_DEFAULT_TEMPLATE_ARGUMENTS);
+			   | TFF_NO_OMIT_DEFAULT_TEMPLATE_ARGUMENTS
+                           | TFF_MATCH_GNU_V3_DEMANGLER);
 
+  /* decl_as_string handles namespaces--especially anonymous ones--more
+     appropriately for debugging than cxx_printable_name.  But
+     cxx_printable_name handles templates and global ctors and dtors better.  */
+  if (TREE_CODE (t) == NAMESPACE_DECL)
+    return decl_as_string (t, TFF_MATCH_GNU_V3_DEMANGLER);
   return cxx_printable_name (t, verbosity);
 }
 
Index: gcc/cp/cp-tree.h
===================================================================
--- gcc/cp/cp-tree.h	(revision 187751)
+++ gcc/cp/cp-tree.h	(working copy)
@@ -4365,7 +4365,9 @@  enum overload_flags { NO_SPECIAL = 0, DT
    TFF_UNQUALIFIED_NAME: do not print the qualifying scope of the
        top-level entity.
    TFF_NO_OMIT_DEFAULT_TEMPLATE_ARGUMENTS: do not omit template arguments
-       identical to their defaults.  */
+       identical to their defaults.
+   TFF_MATCH_GNU_V3_DEMANGLER: match the GNU v3 demangler's names for anonymous
+       namespaces and order of type-qualifiers vs type-specifiers.  */
 
 #define TFF_PLAIN_IDENTIFIER			(0)
 #define TFF_SCOPE				(1)
@@ -4381,6 +4383,7 @@  enum overload_flags { NO_SPECIAL = 0, DT
 #define TFF_NO_FUNCTION_ARGUMENTS		(1 << 10)
 #define TFF_UNQUALIFIED_NAME			(1 << 11)
 #define TFF_NO_OMIT_DEFAULT_TEMPLATE_ARGUMENTS	(1 << 12)
+#define TFF_MATCH_GNU_V3_DEMANGLER	        (1 << 13)
 
 /* Returns the TEMPLATE_DECL associated to a TEMPLATE_TEMPLATE_PARM
    node.  */
Index: gcc/dwarf2out.c
===================================================================
--- gcc/dwarf2out.c	(revision 187751)
+++ gcc/dwarf2out.c	(working copy)
@@ -4782,6 +4782,8 @@  dwarf_stack_op_name (unsigned int op)
       return "DW_OP_GNU_implicit_pointer";
     case DW_OP_GNU_addr_index:
       return "DW_OP_GNU_addr_index";
+    case DW_OP_GNU_const_index:
+      return "DW_OP_GNU_const_index";
 
     default:
       return "OP_<unknown>";
@@ -4903,6 +4905,7 @@  size_of_loc_descr (dw_loc_descr_ref loc)
       size += DWARF2_ADDR_SIZE;
       break;
     case DW_OP_GNU_addr_index:
+    case DW_OP_GNU_const_index:
       size += size_of_uleb128 (loc->dw_loc_oprnd1.val_index);
       break;
     case DW_OP_const1u:
@@ -5284,8 +5287,9 @@  output_loc_operands (dw_loc_descr_ref lo
       break;
 
     case DW_OP_GNU_addr_index:
+    case DW_OP_GNU_const_index:
       dw2_asm_output_data_uleb128 (loc->dw_loc_oprnd1.val_index,
-                                   "(address index)");
+                                   "(index into .debug_addr)");
       break;
 
     case DW_OP_GNU_implicit_pointer:
@@ -5357,6 +5361,7 @@  output_loc_operands_raw (dw_loc_descr_re
     {
     case DW_OP_addr:
     case DW_OP_GNU_addr_index:
+    case DW_OP_GNU_const_index:
     case DW_OP_implicit_value:
       /* We cannot output addresses in .cfi_escape, only bytes.  */
       gcc_unreachable ();
@@ -6570,6 +6575,7 @@  static dw_loc_list_ref new_loc_list (dw_
 				     const char *, const char *);
 static void output_loc_list (dw_loc_list_ref);
 static char *gen_internal_sym (const char *);
+static bool want_pubnames (void);
 
 static void prune_unmark_dies (dw_die_ref);
 static void prune_unused_types_mark_generic_parms_dies (dw_die_ref);
@@ -6589,17 +6595,30 @@  static bool generic_type_p (tree);
 static void schedule_generic_params_dies_gen (tree t);
 static void gen_scheduled_generic_parms_dies (void);
 
+/* DW_OP_addr is relocated by the debug info consumer, while
+   tls relative operands should not be.  */
+
+static inline enum dwarf_location_atom dw_addr_op (bool dtprel)
+{
+  if (dtprel)
+    return (dwarf_split_debug_info ? DW_OP_GNU_const_index
+            : (DWARF2_ADDR_SIZE == 4 ? DW_OP_const4u : DW_OP_const8u));
+  else
+    return (dwarf_split_debug_info ? DW_OP_GNU_addr_index : DW_OP_addr);
+}
+
 /* Return a pointer to a newly allocated address location description.  If
    dwarf_split_debug_info is true, then record the address with the appropriate
    relocation.  */
 static inline dw_loc_descr_ref
 new_addr_loc_descr (rtx addr, int dtprel)
 {
-  dw_loc_descr_ref ref = new_loc_descr (DW_OP_addr, 0, 0);
+  dw_loc_descr_ref ref = new_loc_descr (dw_addr_op (dtprel), 0, 0);
 
   ref->dw_loc_oprnd1.val_class = dw_val_class_addr;
   ref->dw_loc_oprnd1.val_index = -1U;
   ref->dw_loc_oprnd1.v.val_addr = addr;
+  ref->dtprel = dtprel;
   if (dwarf_split_debug_info)
     {
       dw_attr_node attr;
@@ -6610,7 +6629,6 @@  new_addr_loc_descr (rtx addr, int dtprel
       attr.dw_attr_val.val_index = -1U;
       attr.dw_attr_val.v.val_addr = addr;
 
-      ref->dw_loc_opc = DW_OP_GNU_addr_index;
       ref->dw_loc_oprnd1.val_index = add_addr_table_entry (&attr);
     }
   return ref;
@@ -11926,15 +11944,30 @@  output_comp_unit (dw_die_ref die, int ou
     }
 }
 
+/* Whether to generate the DWARF accelerator tables in .debug_pubnames
+   and .debug_pubtypes.  This is configured per-target, but can be
+   overridden by the -gpubnames or -gno-pubnames options.  */
+
+static inline bool
+want_pubnames (void)
+{
+  return (debug_generate_pub_sections != -1
+	  ? debug_generate_pub_sections
+	  : targetm.want_debug_pub_sections);
+}
+
 /* Add the DW_AT_GNU_pubnames and DW_AT_GNU_pubtypes attributes.  */
 
 static void
 add_AT_pubnames (dw_die_ref die)
 {
-  /* FIXME: Should use add_AT_pubnamesptr.  This works because most targets
-     don't care what the base section is.  */
-  add_AT_lineptr (die, DW_AT_GNU_pubnames, debug_pubnames_section_label);
-  add_AT_lineptr (die, DW_AT_GNU_pubtypes, debug_pubtypes_section_label);
+  if (want_pubnames ())
+    {
+      /* FIXME: Should use add_AT_pubnamesptr.  This works because most targets
+         don't care what the base section is.  */
+      add_AT_lineptr (die, DW_AT_GNU_pubnames, debug_pubnames_section_label);
+      add_AT_lineptr (die, DW_AT_GNU_pubtypes, debug_pubtypes_section_label);
+    }
 }
 
 /* Helper function to generate top-level dies for skeleton debug_info and
@@ -12136,7 +12169,7 @@  dwarf2_name (tree decl, int scope)
 static void
 add_pubname_string (const char *str, dw_die_ref die)
 {
-  if (!GENERATE_MINIMUM_LINE_TABLE && targetm.want_debug_pub_sections)
+  if (!GENERATE_MINIMUM_LINE_TABLE && want_pubnames ())
     {
       pubname_entry e;
 
@@ -12149,7 +12182,7 @@  add_pubname_string (const char *str, dw_
 static void
 add_pubname (tree decl, dw_die_ref die)
 {
-  if (!GENERATE_MINIMUM_LINE_TABLE && targetm.want_debug_pub_sections)
+  if (!GENERATE_MINIMUM_LINE_TABLE && want_pubnames ())
     {
       if ((TREE_PUBLIC (decl) && !is_class_die (die->die_parent))
           || is_cu_die (die->die_parent) || is_namespace_die (die->die_parent))
@@ -12182,7 +12215,7 @@  add_pubtype (tree decl, dw_die_ref die)
 {
   pubname_entry e;
 
-  if (!targetm.want_debug_pub_sections)
+  if (!want_pubnames ())
     return;
 
   if ((TREE_PUBLIC (decl)
@@ -12243,7 +12276,7 @@  output_pubnames (VEC (pubname_entry, gc)
   unsigned long pubnames_length = size_of_pubnames (names);
   pubname_ref pub;
 
-  if (!targetm.want_debug_pub_sections || !info_section_emitted)
+  if (!want_pubnames () || !info_section_emitted)
     return;
   if (names == pubname_table)
     {
@@ -14528,15 +14561,7 @@  mem_loc_descriptor (rtx rtl, enum machin
 	  if (!targetm.have_tls || !targetm.asm_out.output_dwarf_dtprel)
 	    break;
 
-	  /* We used to emit DW_OP_addr here, but that's wrong, since
-	     DW_OP_addr should be relocated by the debug info consumer,
-	     while DW_OP_GNU_push_tls_address operand should not.  */
-	  temp = new_loc_descr (DWARF2_ADDR_SIZE == 4
-				? DW_OP_const4u : DW_OP_const8u, 0, 0);
-	  temp->dw_loc_oprnd1.val_class = dw_val_class_addr;
-	  temp->dw_loc_oprnd1.val_index = -1U;
-	  temp->dw_loc_oprnd1.v.val_addr = rtl;
-	  temp->dtprel = true;
+	  temp = new_addr_loc_descr (rtl, true);
 
 	  mem_loc_result = new_loc_descr (DW_OP_GNU_push_tls_address, 0, 0);
 	  add_loc_descr (&mem_loc_result, temp);
@@ -16113,8 +16138,7 @@  loc_list_from_tree (tree loc, int want_a
       if (DECL_THREAD_LOCAL_P (loc))
 	{
 	  rtx rtl;
-	  enum dwarf_location_atom first_op;
-	  enum dwarf_location_atom second_op;
+	  enum dwarf_location_atom tls_op;
 	  bool dtprel = false;
 
 	  if (targetm.have_tls)
@@ -16132,9 +16156,8 @@  loc_list_from_tree (tree loc, int want_a
 		  operand shouldn't be.  */
 	      if (DECL_EXTERNAL (loc) && !targetm.binds_local_p (loc))
 		return 0;
-	      first_op = DWARF2_ADDR_SIZE == 4 ? DW_OP_const4u : DW_OP_const8u;
 	      dtprel = true;
-	      second_op = DW_OP_GNU_push_tls_address;
+	      tls_op = DW_OP_GNU_push_tls_address;
 	    }
 	  else
 	    {
@@ -16146,8 +16169,7 @@  loc_list_from_tree (tree loc, int want_a
 		 no longer appear in gimple code.  We used the control
 		 variable in specific so that we could pick it up here.  */
 	      loc = DECL_VALUE_EXPR (loc);
-	      first_op = DW_OP_addr;
-	      second_op = DW_OP_form_tls_address;
+	      tls_op = DW_OP_form_tls_address;
 	    }
 
 	  rtl = rtl_for_decl_location (loc);
@@ -16160,19 +16182,8 @@  loc_list_from_tree (tree loc, int want_a
 	  if (! CONSTANT_P (rtl))
 	    return 0;
 
-          if (dwarf_split_debug_info && first_op == DW_OP_addr)
-            ret = new_addr_loc_descr (rtl, dtprel);
-          else
-            {
-              ret = new_loc_descr (first_op, 0, 0);
-              ret->dw_loc_oprnd1.val_class = dw_val_class_addr;
-              ret->dw_loc_oprnd1.val_index = -1U;
-              ret->dw_loc_oprnd1.v.val_addr = rtl;
-            }
-
-	  ret->dtprel = dtprel;
-
-	  ret1 = new_loc_descr (second_op, 0, 0);
+	  ret = new_addr_loc_descr (rtl, dtprel);
+	  ret1 = new_loc_descr (tls_op, 0, 0);
 	  add_loc_descr (&ret, ret1);
 
 	  have_address = 1;
@@ -19793,6 +19804,7 @@  gen_subprogram_die (tree decl, dw_die_re
 	{
 	  subr_die = new_die (DW_TAG_subprogram, context_die, decl);
 	  add_AT_specification (subr_die, old_die);
+          add_pubname (decl, subr_die);
 	  if (get_AT_file (old_die, DW_AT_decl_file) != file_index)
 	    add_AT_file (subr_die, DW_AT_decl_file, file_index);
 	  if (get_AT_unsigned (old_die, DW_AT_decl_line) != (unsigned) s.line)
@@ -19807,6 +19819,7 @@  gen_subprogram_die (tree decl, dw_die_re
 	add_AT_flag (subr_die, DW_AT_external, 1);
 
       add_name_and_src_coords_attributes (subr_die, decl);
+      add_pubname (decl, subr_die);
       if (debug_info_level > DINFO_LEVEL_TERSE)
 	{
 	  add_prototyped_attribute (subr_die, TREE_TYPE (decl));
@@ -19918,7 +19931,6 @@  gen_subprogram_die (tree decl, dw_die_re
       }
 #endif
 
-	  add_pubname (decl, subr_die);
 	}
       else
 	{  /* Generate pubnames entries for the split function code
@@ -19940,7 +19952,6 @@  gen_subprogram_die (tree decl, dw_die_re
 		  add_ranges_by_labels (subr_die, fde->dw_fde_second_begin,
 					fde->dw_fde_second_end,
 					&range_list_added, false);
-		  add_pubname (decl, subr_die);
 		  if (range_list_added)
 		    add_ranges (NULL);
 		}
@@ -19962,8 +19973,6 @@  gen_subprogram_die (tree decl, dw_die_re
 				 fde->dw_fde_begin, false);
 		  add_AT_lbl_id (subr_die, DW_AT_high_pc,
 				 fde->dw_fde_end, false);
-		  /* Add it.   */
-		  add_pubname (decl, subr_die);
 
 		  /* Build a minimal DIE for the secondary section.  */
 		  seg_die = new_die (DW_TAG_subprogram,
@@ -19999,7 +20008,6 @@  gen_subprogram_die (tree decl, dw_die_re
 	    {
 	      add_AT_lbl_id (subr_die, DW_AT_low_pc, fde->dw_fde_begin, false);
 	      add_AT_lbl_id (subr_die, DW_AT_high_pc, fde->dw_fde_end, false);
-	      add_pubname (decl, subr_die);
 	    }
 	}
 
@@ -23195,7 +23203,8 @@  output_addr_table (void)
             gcc_assert (targetm.asm_out.output_dwarf_dtprel);
             targetm.asm_out.output_dwarf_dtprel (asm_out_file,
                                                  DWARF2_ADDR_SIZE,
-                                                 AT_addr (node));
+                                                 node->dw_attr_val.v.val_addr);
+            fputc ('\n', asm_out_file);
             break;
           case dw_val_class_lbl_id:
             dw2_asm_output_addr (DWARF2_ADDR_SIZE, AT_lbl (node), "%s", name);
@@ -23949,6 +23958,7 @@  hash_loc_operands (dw_loc_descr_ref loc,
       hash = iterative_hash_rtx (val1->v.val_addr, hash);
       break;
     case DW_OP_GNU_addr_index:
+    case DW_OP_GNU_const_index:
       {
         dw_attr_ref attr = VEC_index (dw_attr_node, addr_index_table,
                                       val1->val_index);
@@ -24116,6 +24126,7 @@  compare_loc_operands (dw_loc_descr_ref x
     hash_addr:
       return rtx_equal_p (valx1->v.val_addr, valy1->v.val_addr);
     case DW_OP_GNU_addr_index:
+    case DW_OP_GNU_const_index:
       {
         dw_attr_node *attrx1 = VEC_index (dw_attr_node,
                                           addr_index_table,
Index: gcc/opts.c
===================================================================
--- gcc/opts.c	(revision 187751)
+++ gcc/opts.c	(working copy)
@@ -850,6 +850,10 @@  finish_options (struct gcc_options *opts
   /* Turn on -ffunction-sections when -freorder-functions=* is used.  */
   if (opts->x_flag_reorder_functions > 1)
     opts->x_flag_function_sections = 1;
+
+  /* The -gfission option requires -gpubnames.  */
+  if (opts->x_dwarf_split_debug_info)
+    opts->x_debug_generate_pub_sections = 1;
 }
 
 #define LEFT_COLUMN	27
@@ -1714,7 +1718,7 @@  common_handle_option (struct gcc_options
       break;
 
     case OPT_gfission:
-      set_debug_level (NO_DEBUG, DEFAULT_GDB_EXTENSIONS, arg, opts, opts_set,
+      set_debug_level (NO_DEBUG, DEFAULT_GDB_EXTENSIONS, "", opts, opts_set,
 		       loc);
       break;
 
Index: gcc/common.opt
===================================================================
--- gcc/common.opt	(revision 187751)
+++ gcc/common.opt	(working copy)
@@ -2374,8 +2374,12 @@  gdwarf-
 Common Joined UInteger Var(dwarf_version) Init(2) Negative(gstabs)
 Generate debug information in DWARF v2 (or later) format
 
+gno-fission
+Common Driver RejectNegative Var(dwarf_split_debug_info,0) Init(0)
+Don't generate debug information in separate .dwo files
+
 gfission
-Common Driver JoinedOrMissing Var(dwarf_split_debug_info,1)
+Common Driver RejectNegative Var(dwarf_split_debug_info,1)
 Generate debug information in separate .dwo files
 
 ggdb
@@ -2386,6 +2390,14 @@  gmlt
 Common RejectNegative
 Generate debug information at level 1 with minimal line table
 
+gno-pubnames
+Common RejectNegative Var(debug_generate_pub_sections, 0) Init(-1)
+Don't generate DWARF pubnames and pubtypes sections.
+
+gpubnames
+Common RejectNegative Var(debug_generate_pub_sections, 1)
+Generate DWARF pubnames and pubtypes sections.
+
 gstabs
 Common JoinedOrMissing Negative(gstabs+)
 Generate debug information in STABS format