Studying note of GCC-3.4.6 source (159)

    技术2025-03-06  36

    5.13.4.4.              Iterate – emitting code for deferred function

    Function generated by the compiler (via implicitly_declare_fn , mark_decl_instantiated , or build_clone ) or inline method is cached in deferred_fns . Arriving here, we have parsed the whole source file, information needed in handling these deferred functions should be available.

    First, for “artificial” method generated by the compiler itself, it has flag DECL_ARTIFICIAL set; In FUNCTION_DECL, its DECL_INITIAL field, after the front-end doing its job, should be trees of entities bound in this function scope (i.e., BLOCK nodes), otherwise it would be NULL. For “artificial” methods having empty DECL_INITIAL, the compiler just makes the declarations so far, now it needs to synthesize the definitions.

     

    742  void

    743  synthesize_method (tree fndecl)                                                                  in method.c

    744  {

    745    bool nested = (current_function_decl != NULL_TREE);

    746    tree context = decl_function_context (fndecl);

    747    bool need_body = true;

    748    tree stmt;

    749 

    750    if (at_eof )

    751      import_export_decl (fndecl);

    752 

    753    /* If we've been asked to synthesize a clone, just synthesize the

    754      cloned function instead. Doing so will automatically fill in the

    755      body for the clone.  */

    756    if (DECL_CLONED_FUNCTION_P (fndecl))

    757    {

    758      synthesize_method (DECL_CLONED_FUNCTION (fndecl));

    759      return ;

    760    }

    761 

    762    /* We may be in the middle of deferred access check. Disable

    763      it now.  */

    764    push_deferring_access_checks (dk_no_deferred);

    765 

    766    if (! context)

    767      push_to_top_level ();

    768    else if (nested)

    769      push_function_context_to (context);

    770 

    771    /* Put the function definition at the position where it is needed,

    772      rather than within the body of the class. That way, an error

    773      during the generation of the implicit body points at the place

    774      where the attempt to generate the function occurs, giving the

    775      user a hint as to why we are attempting to generate the

    776      function.  */

    777    DECL_SOURCE_LOCATION (fndecl) = input_location ;

    778 

    779    interface_unknown = 1;

    780    start_function (NULL_TREE, fndecl, NULL_TREE, SF_DEFAULT | SF_PRE_PARSED);

    781    clear_last_expr ();

    782    stmt = begin_function_body ();

    783 

    784    if (DECL_OVERLOADED_OPERATOR_P (fndecl) == NOP_EXPR)

    785    {

    786      do_build_assign_ref (fndecl);

    787      need_body = false;

    788    }

    789    else if (DECL_CONSTRUCTOR_P (fndecl))

    790    {

    791      tree arg_chain = FUNCTION_FIRST_USER_PARMTYPE (fndecl);

    792      if (arg_chain != void_list_node)

    793        do_build_copy_constructor (fndecl);

    794      else if (TYPE_NEEDS_CONSTRUCTING (current_class_type ))

    795        finish_mem_initializers (NULL_TREE);

    796    }

    797 

    798    /* If we haven't yet generated the body of the function, just

    799      generate an empty compound statement.  */

    800    if (need_body)

    801    {

    802      tree compound_stmt;

    803      compound_stmt = begin_compound_stmt (/*has_no_scope=*/ false);

    804      finish_compound_stmt (compound_stmt);

    805    }

    806 

    807    finish_function_body (stmt);

    808    expand_or_defer_fn (finish_function (0));

    809 

    810    extract_interface_info ();

    811    if (! context)

    812       pop_from_top_level ();

    813    else if (nested)

    814      pop_function_context_from (context);

    815 

    816    pop_deferring_access_checks ();

    817  }

     

    See the definition of synthesize_method will be done in global namespace. But never mind, as node of the function declarations already contain correct context information. Besides, context information only is used for name-lookup, all code should be emitted within global namespace with mangled name instead.

    Note expand_or_defer_fn at line 808, which is also called at line 2769 in finish_file . However, as long as invoking this function here, in finish_file , condition at line 2762 is not satisfied, so no call any more. Before, one of major operation of expand_or_defer_fn is traversing the given function tree, and calling simplify_aggr_init_exprs_r to processing AGGR_INIT_EXPR nodes found. Gccint [2] gives below description:

    AGGR_INIT_EXPR

    An AGGR_INIT_EXPR represents the initialization as the return value of a function call, or as the result of a constructor. An AGGR_INIT_EXPR will only appear as the second operand of a TARGET_EXPR. The first operand to the AGGR_INIT_EXPR is the address of a function to call, just as in a CALL_EXPR. The second operand are the arguments to pass that function, as a TREE_LIST, again in a manner similar to that of a CALL_EXPR. The value of the expression is that returned by the function.

    If AGGR_INIT_VIA_CTOR_P holds of the AGGR_INIT_EXPR, then the initialization is via a constructor call. The address of the third operand of the AGGR_INIT_EXPR, which is always a VAR_DECL, is taken, and this value replaces the first argument in the argument list. In this case, the value of the expression is the VAR_DECL given by the third operand to the AGGR_INIT_EXPR; constructors do not return a value.

    It is the structure used in named return value optimization, the caller passes the address of a block of memory in which the value should be stored. This address is called the "structure value address". simplify_aggr_init_exprs_r combines the CALL_EXPR with its arguments and the temperary local variable (which is added as extra argument, as we try to return aggregate type); and inserts these nodes within the chain of DECL_SAVED_TREE (fn) .

     

    2769 static tree

    2770 simplify_aggr_init_exprs_r (tree* tp,                                                    in semantics.c

    2771                        int* walk_subtrees,

    2772                        void* data ATTRIBUTE_UNUSED)

    2773 {

    2774   /* We don't need to walk into types; there's nothing in a type that

    2775     needs simplification. (And, furthermore, there are places we

    2776     actively don't want to go. For example, we don't want to wander

    2777     into the default arguments for a FUNCTION_DECL that appears in a

    2778     CALL_EXPR.)  */

    2779   if (TYPE_P (*tp))

    2780   {

    2781     *walk_subtrees = 0;

    2782     return NULL_TREE;

    2783   }

    2784   /* Only AGGR_INIT_EXPRs are interesting.  */

    2785   else if (TREE_CODE (*tp) != AGGR_INIT_EXPR)

    2786     return NULL_TREE;

    2787

    2788   simplify_aggr_init_expr (tp);

    2789

    2790   /* Keep iterating.  */

    2791   return NULL_TREE;

    2792 }

     

    It see that simplify_aggr_init_exprs_r always returns NULL, which forces walk_tree to visit the whole tree. As in a function definition it may contain more than 1 node of AGGR_INIT_EXPR. For example:

    class A {…};

     

    class B {

    public :

    B (const A&);

    };

     

    A func1 () {…}

     

    B func2 () {

    B b = func1 ();   // 1st AGGR_INIT_EXPR

    return b;     // 2nd AGGR_INIT_EXPR

    }

    AGGR_INIT_EXPR is handled by below function. Note that fn gotten at line 2804 is the address of the function (i.e., node of ADDR_EXPR).

     

    2798 void

    2799 simplify_aggr_init_expr (tree *tp)                                                        in semantics.c

    2800 {

    2801   tree aggr_init_expr = *tp;

    2802

    2803   /* Form an appropriate CALL_EXPR.  */

    2804   tree fn = TREE_OPERAND (aggr_init_expr, 0);

    2805   tree args = TREE_OPERAND (aggr_init_expr, 1);

    2806   tree slot = TREE_OPERAND (aggr_init_expr, 2);

    2807   tree type = TREE_TYPE (aggr_init_expr);

    2808

    2809   tree call_expr;

    2810   enum style_t { ctor, arg, pcc } style;

    2811

    2812   if (AGGR_INIT_VIA_CTOR_P (aggr_init_expr))

    2813     style = ctor;

    2814 #ifdef PCC_STATIC_STRUCT_RETURN

    2815   else if (1)

    2816     style = pcc;

    2817 #endif

    2818   else if (TREE_ADDRESSABLE (type))

    2819     style = arg;

    2820   else

    2821     /* We shouldn't build an AGGR_INIT_EXPR if we don't need any special

    2822       handling. See build_cplus_new.  */

    2823     abort ();

    2824

    2825   if (style == ctor || style == arg)

    2826   {

    2827     /* Pass the address of the slot. If this is a constructor, we

    2828       replace the first argument; otherwise, we tack on a new one.  */

    2829        tree addr;

    2830

    2831     if (style == ctor)

    2832        args = TREE_CHAIN (args);

    2833

    2834     cxx_mark_addressable (slot);

    2835     addr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (slot)), slot);

    2836     if (style == arg)

    2837     {

    2838       /* The return type might have different cv-quals from the slot.  */

    2839       tree fntype = TREE_TYPE (TREE_TYPE (fn));

    2840 #ifdef ENABLE_CHECKING

    2841       if (TREE_CODE (fntype) != FUNCTION_TYPE

    2842          && TREE_CODE (fntype) != METHOD_TYPE)

    2843         abort ();

    2844 #endif

    2845       addr = convert (build_pointer_type (TREE_TYPE (fntype)), addr);

    2846     }

    2847

    2848     args = tree_cons (NULL_TREE, addr, args);

    2849   }

    2850

    2851   call_expr = build (CALL_EXPR,

    2852                  TREE_TYPE (TREE_TYPE (TREE_TYPE (fn))),

    2853                   fn, args, NULL_TREE);

    2854

    2855   if (style == arg)

    2856     /* Tell the backend that we've added our return slot to the argument

    2857       list.  */

    2858     CALL_EXPR_HAS_RETURN_SLOT_ADDR (call_expr) = 1;

    2859   else if (style == pcc)

    2860   {

    2861     /* If we're using the non-reentrant PCC calling convention, then we

    2862         need to copy the returned value out of the static buffer into the

    2863        SLOT.  */

    2864     push_deferring_access_checks (dk_no_check);

    2865     call_expr = build_aggr_init (slot, call_expr,

    2866                            DIRECT_BIND | LOOKUP_ONLYCONVERTING);

    2867     pop_deferring_access_checks ();

    2868   }

    2869

    2870   /* We want to use the value of the initialized location as the

    2871     result.  */

    2872   call_expr = build (COMPOUND_EXPR, type,

    2873                    call_expr, slot);

    2874

    2875   /* Replace the AGGR_INIT_EXPR with the CALL_EXPR.  */

    2876   TREE_CHAIN (call_expr) = TREE_CHAIN (aggr_init_expr);

    2877   *tp = call_expr;

    2878 }

     

    As named return value optimization will strip the return statement from the function, at line 2872, the original call expression needs be replaced by a compound statement to make the return value can be acquired correctly. Next see line 2834, the variable holding the return value is marked as addressable, it will affect the RTL generation deeply. And PCC_STATIC_STRUCT_RETURN at line 2814 is defined if the usual system convention on the target  machine for returning structures and unions is for the called function to return the address of a static variable containing the value. It is not defined for x86 machine.

     

    最新回复(0)