GCC-3.4.6源代码学习笔记(159)
来源:互联网 发布:局域网传输软件 编辑:程序博客网 时间:2024/06/10 17:46
5.13.4.4. 迭代– 为延迟函数发布代码
由编译器产生的函数(经由implicitly_declare_fn,mark_decl_instantiated或build_clone)或内联函数缓存在deferred_fns中。因为到这里,我们已经完成了整个源文件的代码解析,处理这些延迟函数的信息都应该齐备了。
首先,对于由编译器自己产生的“人造”函数,其设置了标记DECL_ARTIFICIAL;并且FUNCTION_DECL节点,其DECL_INITIAL域,在完成前端的处理后,应该是绑定在该函数域中的对象子树(即,各种BLOCK节点),否则将是空的。对于DECL_INITIAL域是空的“人造”函数,编译器到目前为止仅是做了声明,现在需要合成其定义。
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 willautomatically 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 accesscheck. 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 positionwhere it is needed,
772 rather than within the body of the class.That way, an error
773 during the generation of the implicit bodypoints at the place
774 where the attempt to generate the functionoccurs, giving the
775 user a hint as to why we are attempting togenerate 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 thefunction, 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 }
看到对synthesize_method的定义在全局名字空间上下文中完成。不过这没有关系,因为这些函数的声明节点中已经包括了正确的上下文信息。另外,上下文信息实际上只是用于名字查找中,所有的代码都将使用修饰名被发布在全局名字空间里。
注意808行的expand_or_defer_fn,在finish_file的2769行亦调用了expand_or_defer_fn。不过只要在这里调用了这个函数,finish_file的2762行条件不成立,因而不会再调用该函数。在前面看到expand_or_defer_fn的一个主要操作是遍历给定的函数树,调用函数simplify_aggr_init_exprs_r来处理AGGR_INIT_EXPR类型的节点。【2】对此有如下的描述:
AGGR_INIT_EXPR
一个AGGR_INIT_EXPR节点代表一个初始化,它源自一个函数调用返回值,或一个构造函数执行结果。一个AGGR_INIT_EXPR只能作为一个TARGET_EXPR节点第二个操作数出现。AGGR_INIT_EXPR的第一个操作数是被调用函数的地址,就像在一个CALL_EXPR节点那样。第二个操作数是传递给该函数的实参,它是一个TREE_LIST,同样类似于一个CALL_EXPR节点的实参的形式。该表达式(AGGR_INIT_EXPR)的值是该函数返回的值。
对于特定的AGGR_INIT_EXPR,如果AGGR_INIT_VIA_CTOR_P成立,那么这个初始化通过一个构造函数的调用完成。该AGGR_INIT_EXPR的第三个操作数,它总是一个VAR_DECL节点,其地址替换参数列表的第一个参数。在这种情况下,该表达式的值是AGGR_INIT_EXPR第三个操作数所给出的VAR_DECL;构造函数不返回任何值。
这个结构用于具名返回值优化(nrv——named returnvalue optimization),调用者传入把值所要存入的内存块的地址。这个地址称为“构造体值地址”(structure value address)。simplify_aggr_init_exprs_r把CALL_EXPR与其实参及这个临时局部变量结合起来(它被作为额外实参加入,因为我们尝试返回聚集类型);并把这些节点插入DECL_SAVED_TREE(fn)链表中。
2769 static tree
2770 simplify_aggr_init_exprs_r (tree* tp, in semantics.c
2771 int* walk_subtrees,
2772 void* dataATTRIBUTE_UNUSED)
2773 {
2774 /* We don't need towalk 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, wedon't want to wander
2777 into the default arguments for aFUNCTION_DECL that appears in a
2778 CALL_EXPR.) */
2779 if (TYPE_P (*tp))
2780 {
2781 *walk_subtrees = 0;
2782 returnNULL_TREE;
2783 }
2784 /* OnlyAGGR_INIT_EXPRs are interesting. */
2785 else if (TREE_CODE (*tp) != AGGR_INIT_EXPR)
2786 returnNULL_TREE;
2787
2788 simplify_aggr_init_expr(tp);
2789
2790 /* Keepiterating. */
2791 returnNULL_TREE;
2792 }
看到simplify_aggr_init_exprs_r总是返回NULL,这将使得walk_tree遍历整棵树。这是因为在一个函数定义中可能有多于1个AGGR_INIT_EXPR节点。例如:
class A {…};
class B {
public:
B (constA&);
…
};
A func1 () {…}
B func2 () {
B b = func1 (); // 1st AGGR_INIT_EXPR
return b; // 2nd AGGR_INIT_EXPR
}
AGGR_INIT_EXPR由下面的函数来具体地处理。注意2804行的fn获得的是函数的地址(即ADDR_EXPR类型的节点)。
2798 void
2799 simplify_aggr_init_expr (tree *tp) in semantics.c
2800 {
2801 tree aggr_init_expr = *tp;
2802
2803 /* Form anappropriate 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 #ifdefPCC_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'tbuild 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 theaddress of the slot. If this is a constructor, we
2828 replace the first argument;otherwise, we tack on a new one. */
2829 treeaddr;
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 returntype 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 thebackend 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 usingthe non-reentrant PCC calling convention, then we
2862 need to copy the returned value out of thestatic 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 usethe value of the initialized location as the
2871 result. */
2872 call_expr = build (COMPOUND_EXPR, type,
2873 call_expr, slot);
2874
2875 /* Replace theAGGR_INIT_EXPR with the CALL_EXPR. */
2876 TREE_CHAIN (call_expr) = TREE_CHAIN(aggr_init_expr);
2877 *tp = call_expr;
2878 }
因为具名返回值优化将去掉函数的返回语句,因此在2872行原来的调用语句需要用一个复合语句来替代,使得返回值能正确地获得。另外,注意2834行,保存函数返回值的人造变量被标记为可寻址,这对其RTL代码的生成将有深刻的影响。而在某些目标机器上,结构体或联合体的返回值,由被调用函数通过返回包含结构体或联合体的静态变量地址来返回。在这些机器上,2814行的宏PCC_STATIC_STRUCT_RETURN将被定义。对于x86机器,这个宏没有定义。
- GCC-3.4.6源代码学习笔记(159)
- GCC-3.4.6源代码学习笔记 (100)
- GCC-3.4.6源代码学习笔记 (101)
- GCC-3.4.6源代码学习笔记 (102)
- GCC-3.4.6源代码学习笔记 (103)
- GCC-3.4.6源代码学习笔记 (104)
- GCC-3.4.6源代码学习笔记 (105)
- GCC-3.4.6源代码学习笔记 (106)
- GCC-3.4.6源代码学习笔记(166)
- GCC-3.4.6源代码学习笔记
- GCC-3.4.6源代码学习笔记(6)
- GCC-3.4.6源代码学习笔记(1)
- GCC-3.4.6源代码学习笔记(2)
- GCC-3.4.6源代码学习笔记(3)
- GCC-3.4.6源代码学习笔记(4)
- GCC-3.4.6源代码学习笔记(5)
- GCC-3.4.6源代码学习笔记(7)
- GCC-3.4.6源代码学习笔记(8)
- 数据库系统的模型和结构
- GCC-3.4.6源代码学习笔记(157)
- Studying note of GCC-3.4.6 source (157)
- GCC-3.4.6源代码学习笔记(158)
- Studying note of GCC-3.4.6 source (158)
- GCC-3.4.6源代码学习笔记(159)
- Studying note of GCC-3.4.6 source (159)
- GCC-3.4.6源代码学习笔记(160)
- Studying note of GCC-3.4.6 source (160)
- java中的单实例模式
- printf输出各种格式(转)
- C/C++获取当前时间(转)
- extjs中的fileuploadfield出现两个按钮
- 如何同时打开多个网页