build can be used to create tree node for expression. But it can only accept nodes of expression, and composes them into a more complex one. It can’t be used to create the first level expression (that is, according to the semantics components analyized by parser, constructs the node of expression. These procedures require far more complex functions to do the handling. We will see some code scrap later). Anyway, build is still used extensively, since in C/C++, the expression of expressions due most to their ability of nesting and the places they can appear. And constructing complex expression from simple ones is the task of the function.
As we have seen, the program will be transformed into a tree which is semantic equivalence, the nodes of the tree are various of which each corresponds to certain syntax component. Here build will create node of tree_exp for expressoions.
In front-end, experssion is an instance of tree_exp as following.
852 struct tree_exp GTY(()) in tree.h
853 {
854 struct tree_common common;
855 int complexity;
856 tree GTY ((special ("tree_exp"),
857 desc ("TREE_CODE ((tree) &%0)")))
858 operands[1];
859 };
tree_exp is one type of tree nodes, so it will be created by make_node as other tree nodes.
2295 tree
2296 build (enum tree_code code, tree tt, ...) in tree.c
2297 {
2298 tree t;
2299 int length;
2300 int i;
2301 int fro;
2302 int constant;
2303 va_list p;
2304 tree node;
2305
2306 va_start (p, tt);
2307
2308 t = make_node (code);
2309 length = TREE_CODE_LENGTH (code);
2310 TREE_TYPE (t) = tt;
Notice that va_start at line 2306 is not that we use for programing. In GCC, it is the so-called builtin function. We will see detail of builtin function later.
Function build accepts variable number of parameters, so first it needs decide the number of parameter passed in. This number is determined by the type of expression (via tree code).
build (continued)
2312 /* Below, we automatically set TREE_SIDE_EFFECTS and TREE_READONLY for the
2313 result based on those same flags for the arguments. But if the
2314 arguments aren't really even `tree' expressions, we shouldn't be trying
2315 to do this. */
2316 fro = first_rtl_op (code);
2317
2318 /* Expressions without side effects may be constant if their
2319 arguments are as well. */
2320 constant = (TREE_CODE_CLASS (code) == '<'
2321 || TREE_CODE_CLASS (code) == '1'
2322 || TREE_CODE_CLASS (code) == '2'
2323 || TREE_CODE_CLASS (code) == 'c');
At line 2316 above, first_rtl_op can find out the number of operands required by the creating expression.
1448 int
1449 first_rtl_op (enum tree_code code) in tree.c
1450 {
1451 switch (code)
1452 {
1453 case SAVE_EXPR:
1454 return 2;
1455 case GOTO_SUBROUTINE_EXPR:
1456 case RTL_EXPR:
1457 return 0;
1458 case WITH_CLEANUP_EXPR:
1459 return 2;
1460 default:
1461 return TREE_CODE_LENGTH (code);
1462 }
1463 }
Line 2320, comparison expression (class “<”), unary arithmetic expression (class “1”), binary arithmetic expression (for example, shift, bit operation, etc. class “2”), constant expression (class “c”) are expressions without side effect, so long as their arguments are without side effect, and are constant if the arguments are constant.
build (continued)
2325 if (length == 2)
2326 {
2327 /* This is equivalent to the loop below, but faster. */
2328 tree arg0 = va_arg (p, tree);
2329 tree arg1 = va_arg (p, tree);
2330
2331 TREE_OPERAND (t, 0) = arg0;
2332 TREE_OPERAND (t, 1) = arg1;
2333 TREE_READONLY (t) = 1;
2334 if (arg0 && fro > 0)
2335 {
2336 if (TREE_SIDE_EFFECTS (arg0))
2337 TREE_SIDE_EFFECTS (t) = 1;
2338 if (!TREE_READONLY (arg0))
2339 TREE_READONLY (t) = 0;
2340 if (!TREE_CONSTANT (arg0))
2341 constant = 0;
2342 }
2343
2344 if (arg1 && fro > 1)
2345 {
2346 if (TREE_SIDE_EFFECTS (arg1))
2347 TREE_SIDE_EFFECTS (t) = 1;
2348 if (!TREE_READONLY (arg1))
2349 TREE_READONLY (t) = 0;
2350 if (!TREE_CONSTANT (arg1))
2351 constant = 0;
2352 }
2353 }
2354 else if (length == 1)
2355 {
2356 tree arg0 = va_arg (p, tree);
2357
2358 /* The only one-operand cases we handle here are those with side-effects.
2359 Others are handled with build1. So don't bother checked if the
2360 arg has side-effects since we'll already have set it.
2361
2362 ??? This really should use build1 too. */
2363 if (TREE_CODE_CLASS (code) != 's')
2364 abort ();
2365 TREE_OPERAND (t, 0) = arg0;
2366 }
2367 else
2368 {
2369 for (i = 0; i < length; i++)
2370 {
2371 tree operand = va_arg (p, tree);
2372
2373 TREE_OPERAND (t, i) = operand;
2374 if (operand && fro > i)
2375 {
2376 if (TREE_SIDE_EFFECTS (operand))
2377 TREE_SIDE_EFFECTS (t) = 1;
2378 if (!TREE_CONSTANT (operand))
2379 constant = 0;
2380 }
2381 }
2382 }
2383 va_end (p);
For expressoion other than CALL_EXPR, the object is ready. But CALL_EXPR requests further treatment to detect the real effect of side effect. Because the side effect of CALL_EXPR depends on the function it invokes. And the fresh created CALL_EXPR node should always have TREE_SIDE_EFFECTS return 0. So it needs extra code to step into the invoked function to determine the real side effect.
build (continued)
2385 TREE_CONSTANT (t) = constant;
2386
2387 if (code == CALL_EXPR && !TREE_SIDE_EFFECTS (t))
2388 {
2389 /* Calls have side-effects, except those to const or
2390 pure functions. */
2391 i = call_expr_flags (t);
2392 if (!(i & (ECF_CONST | ECF_PURE)))
2393 TREE_SIDE_EFFECTS (t) = 1;
2394
2395 /* And even those have side-effects if their arguments do. */
2396 else for (node = TREE_OPERAND (t, 1); node; node = TREE_CHAIN (node))
2397 if (TREE_SIDE_EFFECTS (TREE_VALUE (node)))
2398 {
2399 TREE_SIDE_EFFECTS (t) = 1;
2400 break;
2401 }
2402 }
2403
2404 return t;
2405 }
First see what is CALL_EXPR.
CALL_EXPR[2]
² The node is used to represent calls to functions, including non-static member functions. The first operand is a pointer to the function to call; it is always an expression whose type is a POINTER_TYPE. The second argument is a TREE_LIST. The arguments to the call appear left-to-right in the list. The TREE_VALUE of each list node contains the expression corresponding to that argument. (The value of TREE_PURPOSE for these nodes is unspecified, and should be ignored.) For non-static member functions, there will be an operand corresponding to the this pointer. There will always be expressions corresponding to all of the arguments, even if the function is declared with default arguments and some arguments are not explicitly provided at the call sites.
751 int
752 call_expr_flags (tree t) in calls.c
753 {
754 int flags;
755 tree decl = get_callee_fndecl (t);
756
757 if (decl)
758 flags = flags_from_decl_or_type (decl);
759 else
760 {
761 t = TREE_TYPE (TREE_OPERAND (t, 0));
762 if (t && TREE_CODE (t) == POINTER_TYPE)
763 flags = flags_from_decl_or_type (TREE_TYPE (t));
764 else
765 flags = 0;
766 }
767
768 return flags;
769 }
Above at line 755, get_callee_fndecl is used to determine the address of the function called. As description of CALL_EXPR above reveals, the first operand is a pointer to the function called (that is the address of the function), and it is always an expression having type of POINTER_TYPE. So we need first see what is FUNCTION_DECL, the object pointed by the pointer.
What is FUNCTION_DECL
FUNCTION_DECL[2]
² A function is represented by a FUNCTION_DECL node. A set of overloaded functions is sometimes represented by a OVERLOAD node.
An OVERLOAD node is not a declaration, so none of the DECL_* macros should be used on an OVERLOAD. An OVERLOAD node is similar to a TREE_LIST. Use OVL_CURRENT to get the function associated with an OVERLOAD node; use OVL_NEXT to get the next OVERLOAD node in the list of overloaded functions. The macros OVL_CURRENT and OVL_NEXT are actually polymorphic; you can use them to work with FUNCTION_DECL nodes as well as with overloads. In the case of a FUNCTION_DECL, OVL_CURRENT will always return the function itself, and OVL_NEXT will always be NULL_TREE.
To determine the scope of a function, you can use the DECL_CONTEXT macro. This macro will return the class (either a RECORD_TYPE or a UNION_TYPE) or namespace (a NAMESPACE_DECL) of which the function is a member. For a virtual function, this macro returns the class in which the function was actually defined, not the base class in which the virtual declaration occurred.
If a friend function is defined in a class scope, the DECL_FRIEND_CONTEXT macro can be used to determine the class in which it was defined. For example, in class C { friend void f() {} }; the DECL_CONTEXT for f will be the global_namespace, but the DECL_FRIEND_CONTEXT will be the RECORD_TYPE for C.
In C, the DECL_CONTEXT for a function maybe another function. This representation indicates that the GNU nested function extension is in use. For details on the semantics of nested functions, see the GCC Manual[6]. The nested function can refer to local variables in its containing function. Such references are not explicitly marked in the tree structure; back ends must look at the DECL_CONTEXT for the referenced VAR_DECL. If the DECL_CONTEXT for the referenced VAR_DECL is not the same as the function currently being processed, and neither DECL_EXTERNAL nor DECL_STATIC hold, then the reference is to a local variable in a containing function, and the back end must take appropriate action.
At line 4482 below, STRIP_NOPS strips topmost NON_LVALUE_EXPR and NOP_EXPR nodes that don't change the machine mode (or more precise, skips off these nodes and steps into their operand in turn). For normal function invocation, after STRIP_NOP, it maybe encounters FUNCTION_DECL.
DECL_P at line 4485 if nonzero means addr is declaration. If addr is a declaration but not FUNCTION_DECL, it is assumed as funciton pointer, and if it is read-only and non-volatile; its initial value should contain the address we expect.
Then at line 4492, we expect to reach ADDR_EXPR statement of FUNCTION_DECL. The contained FUNCTION_DECL is what we find.
4468 tree
4469 get_callee_fndecl (tree call) in tree.c
4470 {
4471 tree addr;
4472
4473 /* It's invalid to call this function with anything but a
4474 CALL_EXPR. */
4475 if (TREE_CODE (call) != CALL_EXPR)
4476 abort ();
4477
4478 /* The first operand to the CALL is the address of the function
4479 called. */
4480 addr = TREE_OPERAND (call, 0);
4481
4482 STRIP_NOPS (addr);
4483
4484 /* If this is a readonly function pointer, extract its initial value. */
4485 if (DECL_P (addr) && TREE_CODE (addr) != FUNCTION_DECL
4486 && TREE_READONLY (addr) && ! TREE_THIS_VOLATILE (addr)
4487 && DECL_INITIAL (addr))
4488 addr = DECL_INITIAL (addr);
4489
4490 /* If the address is just `&f' for some function `f', then we know
4491 that `f' is being called. */
4492 if (TREE_CODE (addr) == ADDR_EXPR
4493 && TREE_CODE (TREE_OPERAND (addr, 0)) == FUNCTION_DECL)
4494 return TREE_OPERAND (addr, 0);
4495
4496 /* We couldn't figure out what was being called. Maybe the front
4497 end has some idea. */
4498 return (*lang_hooks.lang_get_callee_fndecl) (call);
4499 }
If we are still unable to determine the function invoked at line 4492 above, function pointer lang_get_callee_fndecl in lang_hooks will be invoked. For default, function lhd_return_null_tree will be invoked and does nothing. Front-end can define funciton appropriate for its purpose. For C/C++, default function will be used.
Function flags_from_decl_or_type detects function’s attributes. GCC will create a graph to describe the callee and caller during compilation.
698 int
699 flags_from_decl_or_type (tree exp) in calls.c
700 {
701 int flags = 0;
702 tree type = exp;
703
704 if (DECL_P (exp))
705 {
706 struct cgraph_rtl_info *i = cgraph_rtl_info (exp);
707 type = TREE_TYPE (exp);
1.3.2.1.3.2.1. Structure of graph nodes
Above at line 706, function cgraph_rtl_info fetches the graph node of the function via cgraph_node. If decl is the function currently processing (current_function_decl below if non-null, always points to the function currently under compilation), the corresponding node of cgraph_rtl_info. Otherwise, the function must be assembled already.
348 struct cgraph_rtl_info *
349 cgraph_rtl_info (tree decl) in cgraph.c
350 {
351 struct cgraph_node *node;
352 if (TREE_CODE (decl) != FUNCTION_DECL)
353 abort ();
354 node = cgraph_node (decl);
355 if (decl != current_function_decl
356 && !TREE_ASM_WRITTEN (node->decl))
357 return NULL;
358 return &node->rtl;
359 }
Struct cgraph_node below acts as a node within the graph is used to describe the invocation relationship for the function. Since GCC supports nested function, fieds origin, nested, next_nested are used for the purpose and describes the level and position of the function.
85 struct cgraph_node GTY((chain_next ("%h.next"), chain_prev ("%h.previous"))) in cgraph.h
86 {
87 tree decl;
88 struct cgraph_edge *callees;
89 struct cgraph_edge *callers;
90 struct cgraph_node *next;
91 struct cgraph_node *previous;
92 /* For nested functions points to function the node is nested in. */
93 struct cgraph_node *origin;
94 /* Points to first nested function, if any. */
95 struct cgraph_node *nested;
96 /* Pointer to the next function with same origin, if any. */
97 struct cgraph_node *next_nested;
98 /* Pointer to the next function in cgraph_nodes_queue. */
99 struct cgraph_node *next_needed;
100 PTR GTY ((skip (""))) aux;
101
102 struct cgraph_local_info local;
103 struct cgraph_global_info global;
104 struct cgraph_rtl_info rtl;
105 /* Unique id of the node. */
106 int uid;
107 /* Set when function must be output - it is externally visible
108 or it's address is taken. */
109 bool needed;
110 /* Set when function is reachable by call from other function
111 that is either reachable or needed. */
112 bool reachable;
113 /* Set once the function has been instantiated and its callee
114 lists created. */
115 bool analyzed;
116 /* Set when function is scheduled to be assembled. */
117 bool output;
118 };
In above structure, cgraph_edge is used as edge to connect graph nodes. It saves all information of the function being caller and callee.
120 struct cgraph_edge GTY(()) in cgraph.h
121 {
122 struct cgraph_node *caller;
123 struct cgraph_node *callee;
124 struct cgraph_edge *next_caller;
125 struct cgraph_edge *next_callee;
126 /* When NULL, inline this call. When non-NULL, points to the explanation
127 why function was not inlined. */
128 const char *inline_failed;
129 };
The relation among callers and callees can be built into graph by cgraph nodes and cgraph edges as following figure demonstrated. In the figure, N1 invokes N3 first, then N3 calls N4, when N4 returns, N2 calls N3, then N3 invokes N5 in turn. First nodes N1 to N5 are connected via next according to the order of creation (same is previous). In cgrap_node of N3, field caller points to Edge1-3 (the first caller). Field caller in Edge1-3 points to N1, and callee points to N3; and at the same time, next_caller points to Edge2-3 (the second caller). Next, in cgrap_node of N3, field callee points to Edge3-4 (the first callee), and next_callee of Edge3-4 points to Edge3-5 (the second callee); and if N3 continues to invoke other function, then next_callee of Edge3-5 points to corresponding cgraph_edge. And to N5, Edge3-5 is the caller, its next_caller points to cgraph_edge that invokes N5 next。
Figure 1 example of graph of caller and callee
In cgraph_node definition, at line 102, struct cgraph_local_info contains information about the function collected locally. It is available after function is analyzed.
28 struct cgraph_local_info GTY(()) in cgraph.h
29 {
30 /* Size of the function before inlining. */
31 int self_insns;
32
33 /* Set when function function is visible in current compilation unit only
34 and it's address is never taken. */
35 bool local;
36 /* Set once it has been finalized so we consider it to be output. */
37 bool finalized;
38
39 /* False when there something makes inlining impossible (such as va_arg). */
40 bool inlinable;
41 /* True when function should be inlined independently on it's size. */
42 bool disregard_inline_limits;
43 /* True when the function has been originally extern inline, but it is
44 redefined now. */
45 bool redefined_extern_inline;
46 };
Then at line 103 above, struct cgraph_global_info contains information about the function that needs to be computed globally once compilation is finished. It is available only with switch -funit-at-time.
51 struct cgraph_global_info GTY(()) in cgraph.h
52 {
53 /* Estimated size of the function after inlining. */
54 int insns;
55
56 /* Number of times given function will be cloned during output. */
57 int cloned_times;
58
59 /* Set when the function will be inlined exactly once. */
60 bool inline_once;
61
62 /* Set to true for all reachable functions before inlining is decided.
63 Once we inline all calls to the function and the function is local,
64 it is set to false. */
65 bool will_be_output;
66
67 /* Set iff at least one of the caller edges has inline_call flag set. */
68 bool inlined;
69 };
And at line104, structure cgraph_rtl_info contains information about the function that is propagated by the RTL backend. It is available only for functions that have been already assembled.
74 struct cgraph_rtl_info GTY(()) in cgraph.h
75 {
76 bool const_function;
77 bool pure_function;
78 int preferred_incoming_stack_boundary;
79 };
1.3.1.1.1.1.1. Creation of cgaph_node
Function cgraph_node creates object of cgraph_node. All cgraph_nodes are linked by a double link.
95 struct cgraph_node *
96 cgraph_node (tree decl) in cgraph.c
97 {
98 struct cgraph_node *node;
99 struct cgraph_node **slot;
100
101 if (TREE_CODE (decl) != FUNCTION_DECL)
102 abort ();
103
104 if (!cgraph_hash)
105 cgraph_hash = htab_create_ggc (10, hash_node, eq_node, NULL);
106
107 slot = (struct cgraph_node **)
108 htab_find_slot_with_hash (cgraph_hash, DECL_ASSEMBLER_NAME (decl),
109 IDENTIFIER_HASH_VALUE
110 (DECL_ASSEMBLER_NAME (decl)), INSERT);
111 if (*slot)
112 return *slot;
113 node = ggc_alloc_cleared (sizeof (*node));
114 node->decl = decl;
115 node->next = cgraph_nodes;
116 node->uid = cgraph_max_uid++;
117 if (cgraph_nodes)
118 cgraph_nodes->previous = node;
119 node->previous = NULL;
120 cgraph_nodes = node;
121 cgraph_n_nodes++;
122 *slot = node;
123 if (DECL_CONTEXT (decl) && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL)
124 {
125 node->origin = cgraph_node (DECL_CONTEXT (decl));
126 node->next_nested = node->origin->nested;
127 node->origin->nested = node;
128 }
129 return node;
130 }
At the same time all cgraph_nodes are saved into hashtable to ensure one node per function.
As mentioned above, data cgraph_rtl_info is available only after the function being assembled (otherwise, function cgraph_rtl_info returns NULL). If it is usable, it is the most correct data (see assemble is ready).
flags_from_decl_or_type (continued)
698 if (i)
699 {
700 if (i->pure_function)
701 flags |= ECF_PURE | ECF_LIBCALL_BLOCK;
702 if (i->const_function)
703 flags |= ECF_CONST | ECF_LIBCALL_BLOCK;
704 }
705
706 /* The function exp may have the `malloc' attribute. */
707 if (DECL_IS_MALLOC (exp))
708 flags |= ECF_MALLOC;
709
710 /* The function exp may have the `pure' attribute. */
711 if (DECL_IS_PURE (exp))
712 flags |= ECF_PURE | ECF_LIBCALL_BLOCK;
713
714 if (TREE_NOTHROW (exp))
715 flags |= ECF_NOTHROW;
716
717 if (TREE_READONLY (exp) && ! TREE_THIS_VOLATILE (exp))
718 flags |= ECF_LIBCALL_BLOCK;
719 }
720
721 if (TREE_READONLY (exp) && ! TREE_THIS_VOLATILE (exp))
722 flags |= ECF_CONST;
723
724 if (TREE_THIS_VOLATILE (exp))
725 flags |= ECF_NORETURN;
726
727 /* Mark if the function returns with the stack pointer depressed. We
728 cannot consider it pure or constant in that case. */
729 if (TREE_CODE (type) == FUNCTION_TYPE && TYPE_RETURNS_STACK_DEPRESSED (type))
730 {
731 flags |= ECF_SP_DEPRESSED;
732 flags &= ~(ECF_PURE | ECF_CONST | ECF_LIBCALL_BLOCK);
733 }
734
735 return flags;
736 }
Above, following flags are used to indicate the attribution.
ECF_CONST, if nonzero, this is a call to a const function.
ECF_NORETURN, if nonzero, this is a call to a volatile function.
ECF_MALLOC, if nonzero, this is a call to malloc or a related function.
ECF_MAY_BE_ALLOCA, if nonzero, it is plausible that this is a call to alloca.
ECF_NOTHROW, if nonzero, this is a call to a function that won't throw an exception.
ECF_RETURNS_TWICE, if nonzero, this is a call to setjmp or a related function.
ECF_LONGJMP, if nonzero, this is a call to longjmp.
ECF_FORK_OR_EXEC, ECF_SIBCALL, if nonzero, this is a syscall that makes a new process in the image of the current one.
ECF_PURE, if nonzero, this is a call to pure function. In [6], there is a description of pure function as below:
Many functions have no effects except the return value and their return value depends only on the parameters and/or global variables. Such a function can be subject to common subexpression elimination and loop optimization just as an arithmetic operator would be. These functions should be declared with the attribute pure. Some of common examples of pure functions are strlen or memcmp.
ECF_SP_DEPRESSED, if nonzero, this is a call to a function that returns with the stack pointer depressed (make it possible for a called function to return an object whose size is unknown to the caller, essentially for Ada).
ECF_ALWAYS_RETURN, if nonzero, this call is known to always return.
ECF_LIBCALL_BLOCK, creates libcall block around the call (emit_libcall_block).
Then back build, side_effects_flag field of the tree_exp object is set accordingly. Note that if the function is neither pure nor constant, it is considered as having side-effect (i.e, can’t change its time of invocation arbitrarily).