This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [C++] Avoid one place of frontend calling into targetm


> 	The difference in assembly for init/copy3.C is an additional
> global constructor that calls the first global constructor
> 
> _Z41__static_initialization_and_destruction_0ii:
> ...
> 
> _GLOBAL__I_copies:
> ...
>         bl ._Z41__static_initialization_and_destruction_0ii
> 
> _GLOBAL__I_0_copies:
> ...
>         bl ._GLOBAL__I_copies

Hi,
sorry for taking a while to track down the problem, but it is a bit
weird.  What I believe the situation is:
  1) aix is !target_have_ctors_dtors
  2) on these targets we produce ctors and dtors as specially named
  public functions that are recognized and collected by collect2.
  3) C++ frontend is doing it's job of producing public constructors, it
  might produce multiple of them when process iterates
  4) common C&C++ code is sort of duplicating the work by looking for
  all finished constructors and destructors to produce single function
  calling htem
  5) originally cgraph mistakely optimized out the function produced by
  4.
  6) now however we get constructors called twice, once from 3 and then
  from 4 since collect2 recognize both of them.

The patch is trying to solve the problem by moving code 4) into
callgraph so all frontends can use the infrastructure and moving the
test for static_ctors_dtors out of C++ frontend (cgraph should abstract
this completely now).

As a result the function from 3) gets inlined into function from 4) and
not exported.

I am testing the attached patch on Linux but that is not going to show
much, with fair amount of luck, I hope it will fix your problem...

Index: cgraph.c
===================================================================
*** cgraph.c	(revision 124471)
--- cgraph.c	(working copy)
*************** static GTY(()) struct cgraph_asm_node *c
*** 132,137 ****
--- 132,139 ----
     them, to support -fno-toplevel-reorder.  */
  int cgraph_order;
  
+ /* Functions called automatically at the beginning and end of execution.  */
+ 
  static hashval_t hash_node (const void *);
  static int eq_node (const void *, const void *);
  
Index: cgraph.h
===================================================================
*** cgraph.h	(revision 124471)
--- cgraph.h	(working copy)
*************** enum availability cgraph_function_body_a
*** 323,328 ****
--- 323,329 ----
  bool cgraph_is_master_clone (struct cgraph_node *);
  struct cgraph_node *cgraph_master_clone (struct cgraph_node *);
  void cgraph_add_new_function (tree, bool);
+ void cgraph_build_cdtor_fns (void);
  
  /* In cgraphunit.c  */
  void cgraph_finalize_function (tree, bool);
Index: cgraphunit.c
===================================================================
*** cgraphunit.c	(revision 124471)
--- cgraphunit.c	(working copy)
*************** static void cgraph_output_pending_asms (
*** 168,173 ****
--- 168,242 ----
  
  static FILE *cgraph_dump_file;
  
+ static GTY (()) tree static_ctors;
+ static GTY (()) tree static_dtors;
+ 
+ /* When target does not have ctors and dtors, we call all constructor
+    and destructor by special initialization/destruction functio
+    recognized by collect2.  
+    
+    When we are going to build this function, collect all constructors and
+    destructors and turn them into normal functions.  */
+ 
+ static void
+ record_cdtor_fn (tree fndecl)
+ {
+   if (targetm.have_ctors_dtors)
+     return;
+ 
+   if (DECL_STATIC_CONSTRUCTOR (fndecl))
+     {
+       static_ctors = tree_cons (NULL_TREE, fndecl, static_ctors);
+       DECL_STATIC_CONSTRUCTOR (fndecl) = 0;
+       cgraph_mark_reachable_node (cgraph_node (fndecl));
+     }
+   if (DECL_STATIC_DESTRUCTOR (fndecl))
+     {
+       static_dtors = tree_cons (NULL_TREE, fndecl, static_dtors);
+       DECL_STATIC_DESTRUCTOR (fndecl) = 0;
+       cgraph_mark_reachable_node (cgraph_node (fndecl));
+     }
+ }
+ 
+ /* Synthesize a function which calls all the global ctors or global
+    dtors in this file.  This is only used for targets which do not
+    support .ctors/.dtors sections.  */
+ static void
+ build_cdtor (int method_type, tree cdtors)
+ {
+   tree body = 0;
+ 
+   if (!cdtors)
+     return;
+ 
+   for (; cdtors; cdtors = TREE_CHAIN (cdtors))
+     append_to_statement_list (build_function_call_expr (TREE_VALUE (cdtors), 0),
+ 			      &body);
+ 
+   cgraph_build_static_cdtor (method_type, body, DEFAULT_INIT_PRIORITY);
+ }
+ 
+ /* Generate functions to call static constructors and destructors
+    for targets that do not support .ctors/.dtors sections.  These
+    functions have magic names which are detected by collect2.  */
+ 
+ void
+ cgraph_build_cdtor_fns (void)
+ {
+   if (!targetm.have_ctors_dtors)
+     {
+       build_cdtor ('I', static_ctors); 
+       static_ctors = NULL_TREE;
+       build_cdtor ('D', static_dtors); 
+       static_dtors = NULL_TREE;
+     }
+   else
+     {
+       gcc_assert (!static_ctors);
+       gcc_assert (!static_dtors);
+     }
+ }
+ 
  /* Determine if function DECL is needed.  That is, visible to something
     either outside this translation unit, something magic in the system
     configury, or (if not doing unit-at-a-time) to something we havn't
*************** cgraph_finalize_function (tree decl, boo
*** 458,463 ****
--- 527,533 ----
    node->decl = decl;
    node->local.finalized = true;
    node->lowered = DECL_STRUCT_FUNCTION (decl)->cfg != NULL;
+   record_cdtor_fn (node->decl);
    if (node->nested)
      lower_nested_functions (decl);
    gcc_assert (!node->nested);
*************** cgraph_optimize (void)
*** 1222,1227 ****
--- 1292,1301 ----
  #ifdef ENABLE_CHECKING
    verify_cgraph ();
  #endif
+ 
+   /* Call functions declared with the "constructor" or "destructor"
+      attribute.  */
+   cgraph_build_cdtor_fns ();
    if (!flag_unit_at_a_time)
      {
        cgraph_assemble_pending_functions ();
*************** save_inline_function_body (struct cgraph
*** 1572,1574 ****
--- 1646,1650 ----
  #endif
    return first_clone;
  }
+ 
+ #include "gt-cgraphunit.h"
Index: cp/semantics.c
===================================================================
*** cp/semantics.c	(revision 124471)
--- cp/semantics.c	(working copy)
*************** expand_or_defer_fn (tree fn)
*** 3188,3197 ****
        return;
      }
  
-   /* Keep track of functions declared with the "constructor" and
-      "destructor" attribute.  */
-   c_record_cdtor_fn (fn);
- 
    /* We make a decision about linkage for these functions at the end
       of the compilation.  Until that point, we do not want the back
       end to output them -- but we do want it to see the bodies of
--- 3188,3193 ----
Index: cp/decl2.c
===================================================================
*** cp/decl2.c	(revision 124471)
--- cp/decl2.c	(working copy)
*************** start_objects (int method_type, int init
*** 2333,2341 ****
  						 void_list_node));
    start_preparsed_function (fndecl, /*attrs=*/NULL_TREE, SF_PRE_PARSED);
  
!   /* It can be a static function as long as collect2 does not have
!      to scan the object file to find its ctor/dtor routine.  */
!   TREE_PUBLIC (current_function_decl) = ! targetm.have_ctors_dtors;
  
    /* Mark this declaration as used to avoid spurious warnings.  */
    TREE_USED (current_function_decl) = 1;
--- 2333,2339 ----
  						 void_list_node));
    start_preparsed_function (fndecl, /*attrs=*/NULL_TREE, SF_PRE_PARSED);
  
!   TREE_PUBLIC (current_function_decl) = 0;
  
    /* Mark this declaration as used to avoid spurious warnings.  */
    TREE_USED (current_function_decl) = 1;
*************** cp_write_global_declarations (void)
*** 3299,3306 ****
    if (priority_info_map)
      splay_tree_delete (priority_info_map);
  
-   c_build_cdtor_fns ();
- 
    /* Generate any missing aliases.  */
    maybe_apply_pending_pragma_weaks ();
  
--- 3297,3302 ----
Index: c-decl.c
===================================================================
*** c-decl.c	(revision 124471)
--- c-decl.c	(working copy)
*************** finish_function (void)
*** 6799,6808 ****
       info for the epilogue.  */
    cfun->function_end_locus = input_location;
  
-   /* Keep track of functions declared with the "constructor" and
-      "destructor" attribute.  */
-   c_record_cdtor_fn (fndecl);
- 
    /* Finalize the ELF visibility for the function.  */
    c_determine_visibility (fndecl);
  
--- 6799,6804 ----
*************** c_write_global_declarations (void)
*** 7923,7932 ****
      c_write_global_declarations_1 (BLOCK_VARS (DECL_INITIAL (t)));
    c_write_global_declarations_1 (BLOCK_VARS (ext_block));
  
-   /* Call functions declared with the "constructor" or "destructor"
-      attribute.  */
-   c_build_cdtor_fns ();
- 
    /* We're done parsing; proceed to optimize and emit assembly.
       FIXME: shouldn't be the front end's responsibility to call this.  */
    cgraph_optimize ();
--- 7919,7924 ----
Index: c-common.c
===================================================================
*** c-common.c	(revision 124471)
--- c-common.c	(working copy)
*************** const struct attribute_spec c_common_for
*** 670,680 ****
    { NULL,                     0, 0, false, false, false, NULL }
  };
  
- /* Functions called automatically at the beginning and end of execution.  */
- 
- tree static_ctors;
- tree static_dtors;
- 
  /* Push current bindings for the function name VAR_DECLS.  */
  
  void
--- 670,675 ----
*************** warn_for_unused_label (tree label)
*** 6994,7054 ****
      }
  }
  
- /* If FNDECL is a static constructor or destructor, add it to the list
-    of functions to be called by the file scope initialization
-    function.  */
- 
- void
- c_record_cdtor_fn (tree fndecl)
- {
-   if (targetm.have_ctors_dtors)
-     return;
- 
-   if (DECL_STATIC_CONSTRUCTOR (fndecl))
-     static_ctors = tree_cons (NULL_TREE, fndecl, static_ctors);
-   if (DECL_STATIC_DESTRUCTOR (fndecl))
-     static_dtors = tree_cons (NULL_TREE, fndecl, static_dtors);
- }
- 
- /* Synthesize a function which calls all the global ctors or global
-    dtors in this file.  This is only used for targets which do not
-    support .ctors/.dtors sections.  FIXME: Migrate into cgraph.  */
- static void
- build_cdtor (int method_type, tree cdtors)
- {
-   tree body = 0;
- 
-   if (!cdtors)
-     return;
- 
-   for (; cdtors; cdtors = TREE_CHAIN (cdtors))
-     append_to_statement_list (build_function_call (TREE_VALUE (cdtors), 0),
- 			      &body);
- 
-   cgraph_build_static_cdtor (method_type, body, DEFAULT_INIT_PRIORITY);
- }
- 
- /* Generate functions to call static constructors and destructors
-    for targets that do not support .ctors/.dtors sections.  These
-    functions have magic names which are detected by collect2.  */
- 
- void
- c_build_cdtor_fns (void)
- {
-   if (!targetm.have_ctors_dtors)
-     {
-       build_cdtor ('I', static_ctors); 
-       static_ctors = NULL_TREE;
-       build_cdtor ('D', static_dtors); 
-       static_dtors = NULL_TREE;
-     }
-   else
-     {
-       gcc_assert (!static_ctors);
-       gcc_assert (!static_dtors);
-     }
- }
- 
  #ifndef TARGET_HAS_TARGETCM
  struct gcc_targetcm targetcm = TARGETCM_INITIALIZER;
  #endif
--- 6989,6994 ----
Index: c-common.h
===================================================================
*** c-common.h	(revision 124471)
--- c-common.h	(working copy)
*************** extern tree c_omp_remap_decl (tree, bool
*** 1003,1013 ****
  #define GCC_DIAG_STYLE __gcc_cdiag__
  #endif
  
- /* Functions called automatically at the beginning and end of execution.  */
- extern GTY (()) tree static_ctors;
- extern GTY (()) tree static_dtors;
- 
- extern void c_record_cdtor_fn (tree);
- extern void c_build_cdtor_fns (void);
- 
  #endif /* ! GCC_C_COMMON_H */
--- 1003,1006 ----
Index: Makefile.in
===================================================================
*** Makefile.in	(revision 124471)
--- Makefile.in	(working copy)
*************** cgraphunit.o : cgraphunit.c $(CONFIG_H) 
*** 2370,2376 ****
     $(TREE_H) langhooks.h $(TREE_INLINE_H) toplev.h $(FLAGS_H) $(GGC_H) \
     $(TARGET_H) $(CGRAPH_H) intl.h pointer-set.h $(FUNCTION_H) $(TREE_GIMPLE_H) \
     $(TREE_FLOW_H) tree-pass.h $(C_COMMON_H) debug.h $(DIAGNOSTIC_H) \
!    $(FIBHEAP_H) output.h $(PARAMS_H) $(RTL_H) $(TIMEVAR_H) ipa-prop.h
  cgraphbuild.o : cgraphbuild.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
     $(TREE_H) langhooks.h $(CGRAPH_H) intl.h pointer-set.h $(TREE_GIMPLE_H) \
     $(TREE_FLOW_H) tree-pass.h
--- 2370,2377 ----
     $(TREE_H) langhooks.h $(TREE_INLINE_H) toplev.h $(FLAGS_H) $(GGC_H) \
     $(TARGET_H) $(CGRAPH_H) intl.h pointer-set.h $(FUNCTION_H) $(TREE_GIMPLE_H) \
     $(TREE_FLOW_H) tree-pass.h $(C_COMMON_H) debug.h $(DIAGNOSTIC_H) \
!    $(FIBHEAP_H) output.h $(PARAMS_H) $(RTL_H) $(TIMEVAR_H) ipa-prop.h \
!    gt-cgraphunit.h 
  cgraphbuild.o : cgraphbuild.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
     $(TREE_H) langhooks.h $(CGRAPH_H) intl.h pointer-set.h $(TREE_GIMPLE_H) \
     $(TREE_FLOW_H) tree-pass.h
*************** GTFILES = $(srcdir)/input.h $(srcdir)/co
*** 2965,2971 ****
    $(srcdir)/ipa-reference.c $(srcdir)/tree-ssa-structalias.h \
    $(srcdir)/tree-ssa-structalias.c \
    $(srcdir)/omp-low.c $(srcdir)/varpool.c \
!   $(srcdir)/targhooks.c $(out_file) $(srcdir)/passes.c \
    @all_gtfiles@
  
  GTFILES_H = $(subst /,-, $(subst $(srcdir)/,gt-, $(subst .c,.h, \
--- 2966,2972 ----
    $(srcdir)/ipa-reference.c $(srcdir)/tree-ssa-structalias.h \
    $(srcdir)/tree-ssa-structalias.c \
    $(srcdir)/omp-low.c $(srcdir)/varpool.c \
!   $(srcdir)/targhooks.c $(out_file) $(srcdir)/passes.c $(srcdir)/cgraphunit.c \
    @all_gtfiles@
  
  GTFILES_H = $(subst /,-, $(subst $(srcdir)/,gt-, $(subst .c,.h, \


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]