您的位置:首页 > 其它

Studying note of GCC-3.4.6 source (159)

2011-02-11 08:09 369 查看

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.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: