Studying note of GCC-3.4.6 source (160)

    技术2025-03-02  35

    5.13.4.5.              Iterate – handling globals in namespaces

    Before, we have prepared and registered initialize and exitting function for global or static objects having constructor or destructor. In this iteration, it checks if there is any global not finialized, and makes it. Function walk_namespaces visits the tree of namespaces from top down in pre-order.

     

    848    int

    849    walk_namespaces (walk_namespaces_fn f, void* data)                                      in decl.c

    850    {

    851      return walk_namespaces_r (global_namespace , f, data);

    852    }

     

    Slot namespaces holds a chain of namespace declared within namespace .

     

    831    static int

    832    walk_namespaces_r (tree namespace, walk_namespaces_fn f, void* data)           in decl.c

    833    {

    834      int result = 0;

    835      tree current = NAMESPACE_LEVEL (namespace)->namespaces;    

    836   

    837      result |= (*f) (namespace, data);

    838   

    839      for (; current; current = TREE_CHAIN (current))

    840        result |= walk_namespaces_r (current, f, data);

    841   

    842      return result;

    843    }

     

    Below function is the argument f executed upon every node of namespace during the traversal. Argument data is passed from caller to indicate whether it is the last time invocation of the function. Here it is 0, and later at line 2856 in finish_file , it is 1.

     

    905    int

    906    wrapup_globals_for_namespace (tree namespace, void* data)                                    in decl.c

    907    {

    908      struct cp_binding_level *level = NAMESPACE_LEVEL (namespace);

    909      varray_type statics = level->static_decls;

    910      tree *vec = &VARRAY_TREE (statics, 0);

    911       int len = VARRAY_ACTIVE_SIZE (statics);

    912      int last_time = (data != 0);

    913   

    914      if (last_time)

    915      {

    916        check_global_declarations (vec, len);

    917        return 0;

    918      }

    919   

    920      /* Write out any globals that need to be output.  */

    921      return wrapup_global_declarations (vec, len);

    922    }

     

    If it is not the last invocation, then following function is invoked to process global or static declarations within the namespace. Below hook finish_incomplete_decl at line 1572 hooks lhd_do_nothing_t for C++ front-end, which is an empty function.

     

    1554   int

    1555   wrapup_global_declarations (tree *vec, int len)                                           in toplev.c

    1556   {

    1557     tree decl;

    1558     int i;

    1559     int reconsider;

    1560     int output_something = 0;

    1561  

    1562     for (i = 0; i < len; i++)

    1563     {

    1564       decl = vec[i];

    1565  

    1566        /* We're not deferring this any longer. Assignment is

    1567         conditional to avoid needlessly dirtying PCH pages.  */

    1568       if (DECL_DEFER_OUTPUT (decl) != 0)

    1569         DECL_DEFER_OUTPUT (decl) = 0;

    1570  

    1571       if (TREE_CODE (decl) == VAR_DECL && DECL_SIZE (decl) == 0)

    1572         (*lang_hooks .finish_incomplete_decl) (decl);

    1573     }

    1574  

    1575     /* Now emit any global variables or functions that we have been

    1576       putting off. We need to loop in case one of the things emitted

    1577       here references another one which comes earlier in the list.  */

    1578     do

    1579     {

    1580       reconsider = 0;

    1581       for (i = 0; i < len; i++)

    1582       {

    1583         decl = vec[i];

    1584  

    1585         if (TREE_ASM_WRITTEN (decl) || DECL_EXTERNAL (decl))

    1586           continue ;

    1587  

    1588         /* Don't write out static consts, unless we still need them.

    1589  

    1590           We also keep static consts if not optimizing (for debugging),

    1591           unless the user specified -fno-keep-static-consts.

    1592           ??? They might be better written into the debug information.

    1593           This is possible when using DWARF.

    1594  

    1595           A language processor that wants static constants to be always

    1596           written out (even if it is not used) is responsible for

    1597           calling rest_of_decl_compilation itself. E.g. the C front-end

    1598           calls rest_of_decl_compilation from finish_decl.

    1599           One motivation for this is that is conventional in some

    1600           environments to write things like:

    1601           static const char rcsid[] = "... version string ...";

    1602           intending to force the string to be in the executable.

    1603  

    1604           A language processor that would prefer to have unneeded

    1605           static constants "optimized away" would just defer writing

    1606           them out until here. E.g. C++ does this, because static

    1607           constants are often defined in header files.

    1608  

    1609           ??? A tempting alternative (for both C and C++) would be

    1610           to force a constant to be written if and only if it is

    1611           defined in a main file, as opposed to an include file.  */

    1612  

    1613         if (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl))

    1614         {

    1615           bool needed = 1;

    1616  

    1617           if (flag_unit_at_a_time

    1618              && cgraph_varpool_node (decl)->finalized)

    1619             needed = 0;

    1620             else if ((flag_unit_at_a_time && !cgraph_global_info_ready )

    1621                   && (TREE_USED (decl)

    1622                       || TREE_USED (DECL_ASSEMBLER_NAME (decl))))

    1623             /* needed */ ;

    1624           else if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))

    1625             /* needed */ ;

    1626           else if (DECL_COMDAT (decl))

    1627             needed = 0;

    1628           else if (TREE_READONLY (decl) && !TREE_PUBLIC (decl)

    1629                 && (optimize || !flag_keep_static_consts

    1630                      || DECL_ARTIFICIAL (decl)))

    1631             needed = 0;

    1632  

    1633           if (needed)

    1634           {

    1635             reconsider = 1;

    1636             rest_of_decl_compilation (decl, NULL, 1, 1);

    1637           }

    1638         }

    1639  

    1640         if (TREE_CODE (decl) == FUNCTION_DECL

    1641            && DECL_INITIAL (decl) != 0

    1642            && DECL_SAVED_INSNS (decl) != 0

    1643            && DECL_SAVED_INSNS (decl)->saved_for_inline

    1644            && (flag_keep_inline_functions

    1645                || (TREE_PUBLIC (decl) && !DECL_COMDAT (decl))

    1646                || TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))))

    1647         {

    1648           reconsider = 1;

    1649           output_inline_function (decl);

    1650         }

    1651       }

    1652  

    1653       if (reconsider)

    1654         output_something = 1;

    1655     }

    1656     while (reconsider);

    1657  

    1658     return output_something;

    1659   }

     

    Note at this point, cgraph_global_info_ready at line 1620 is still false. See if the variable is really used, at line 1636 rest_of_decl_compilation is invoked, which in turn, for non-external variable, invokes cgraph_varpool_finalize_decl to ensure associated cgrap_varpool_node is generated and marks the node as finialized (for FUNCTION_DECL, assemble_variable does nothing meaningful but cleans last_assemble_variable_decl ).

    Further for inline function which is in-used, or visible external; or using compilation option –fkeep-inline-functions to emit any and all inline functions; the corresponding call expression should be replaced by the function body, which is done by below function.

    Below write_symbols indicates the type of debugging information produced. See the real work is done by rest_of_compilation at line 2995, which embodies a complex operation, so we leave it for later section.

     

    2965   void

    2966   output_inline_function (tree fndecl)                                                            in integrate.c

    2967   {

    2968     enum debug_info_type old_write_symbols = write_symbols ;

    2969     const struct gcc_debug_hooks *const old_debug_hooks = debug_hooks ;

    2970     struct function *f = DECL_SAVED_INSNS (fndecl);

    2971  

    2972     old_cfun = cfun ;

    2973     cfun = f;

    2974     current_function_decl = fndecl;

    2975  

    2976     set_new_last_label_num (f->inl_max_label_num);

    2977  

    2978     /* We're not deferring this any longer.  */

    2979     DECL_DEFER_OUTPUT (fndecl) = 0;

    2980  

    2981     /* If requested, suppress debugging information.  */

    2982     if (f->no_debugging_symbols)

    2983     {

    2984       write_symbols = NO_DEBUG;

    2985       debug_hooks = &do_nothing_debug_hooks ;

    2986     }

    2987  

    2988     /* Make sure warnings emitted by the optimizers (e.g. control reaches

    2989       end of non-void function) is not wildly incorrect.  */

    2990     input_location = DECL_SOURCE_LOCATION (fndecl);

    2991  

    2992     /* Compile this function all the way down to assembly code. As a

    2993       side effect this destroys the saved RTL representation, but

    2994       that's okay, because we don't need to inline this anymore.  */

    2995     rest_of_compilation (fndecl);

    2996     DECL_INLINE (fndecl) = 0;

    2997  

    2998     cfun = old_cfun;

    2999     current_function_decl = old_cfun ? old_cfun->decl : 0;

    3000     write_symbols = old_write_symbols;

    3001     debug_hooks = old_debug_hooks;

    3002   }

    5.13.4.6.              Iterate – handling static member without initializers in classes

    Next, pending_statics holds a list of static class variables. This is needed, because a static class variable can be declared inside the class without an initializer, and then initialized, statically, outside the class. Note that pending_statics may overlap with static_aggregates , but those variables already handled in previous section, and will not be processed here.

    First, import_export_decl needs be invoked to determine visibility and linkage property of the variables; then comes wrapup_global_declarations . Note that without initializers, there is no need to build initialization functions for these objects like section Iterate – emitting code for ctor/dtor of global aggregate .

    Then at line 2797 at the end of the DO…WHILE loop, cgraph_assemble_pending_functions does nothing if flag_unit_at_a_time is set.

     

    最新回复(0)