1.2.4. Create node for address concept
In C++, concept of pointer, reference, and address are exchangable at certain level. The langauage allows to manipulate the content of the address directly via pointer or reference, and the invocation of function in fact is jumping to the address of the function, and the name of an array always refers to the address of the array, so the compiler may need build node for the address concept first and make it the base of other nodes, for example for function, array, etc.
1.2.4.1. Create node for pointer type
1.2.4.1.1. Node of tree_type
The kind of tree node standing for type of the language is tree_type which has following definition.
1089 struct tree_type GTY(()) in tree.h
1090 {
1091 struct tree_common common;
1092 tree values;
1093 tree size;
1094 tree size_unit;
1095 tree attributes;
1096 unsigned int uid;
1097
1098 unsigned int precision : 9;
1099 ENUM_BITFIELD(machine_mode) mode : 7;
1100
1101 unsigned string_flag : 1;
1102 unsigned no_force_blk_flag : 1;
1103 unsigned needs_constructing_flag : 1;
1104 unsigned transparent_union_flag : 1;
1105 unsigned packed_flag : 1;
1106 unsigned restrict_flag : 1;
1107 unsigned spare : 2;
1108
1109 unsigned lang_flag_0 : 1;
1110 unsigned lang_flag_1 : 1;
1111 unsigned lang_flag_2 : 1;
1112 unsigned lang_flag_3 : 1;
1113 unsigned lang_flag_4 : 1;
1114 unsigned lang_flag_5 : 1;
1115 unsigned lang_flag_6 : 1;
1116 unsigned user_align : 1;
1117
1118 unsigned int align;
1119 tree pointer_to;
1120 tree reference_to;
1121 union tree_type_symtab {
1122 int GTY ((tag ("0"))) address;
1123 char * GTY ((tag ("1"))) pointer;
1124 struct die_struct * GTY ((tag ("2"))) die;
1125 } GTY ((desc ("debug_hooks == &sdb_debug_hooks? 1: debug_hooks == &dwarf2_debug_hooks? 2: 0"),
1126 descbits ("2"))) symtab;
1127 tree name;
1128 tree minval;
1129 tree maxval;
1130 tree next_variant;
1131 tree main_variant;
1132 tree binfo;
1133 tree context;
1134 HOST_WIDE_INT alias_set;
1135 /* Points to a structure whose details depend on the language in use. */
1136 struct lang_type *lang_specific;
1137 };
For above fields, following macros are defined for the accessment.
Ø TYPE_BINFO (TYPE_CHECK (NODE)->type.binfo)
² For aggregate types, information about this type, as a base type for itself. Used in a language-dependent way for types that are neither a RECORD_TYPE, QUAL_UNION_TYPE, nor a UNION_TYPE.
Ø TYPE_ALIAS_SET (TYPE_CHECK (NODE)->type.alias_set)
² The (language-specific) typed-based alias set for this type. Objects whose TYPE_ALIAS_SETs are different cannot alias each other. If the TYPE_ALIAS_SET is -1, no alias set has yet been assigned to this type. If the TYPE_ALIAS_SET is 0, objects of this type can alias objects of any type (for example, char*).
Ø TYPE_ALIAS_SET_KNOWN_P (TYPE_CHECK (NODE)->type.alias_set != -1)
² Nonzero iff the typed-based alias set for this type has been calculated.
Ø TYPE_ATTRIBUTES (TYPE_CHECK (NODE)->type.attributes)
² A TREE_LIST of IDENTIFIER nodes of the attributes that apply to this type. GCC supports a rich attribute set as extension.
Ø TYPE_ALIGN (TYPE_CHECK (NODE)->type.align)
² The alignment necessary for objects of this type. The value is an int, measured in bits.
Ø TYPE_USER_ALIGN (TYPE_CHECK (NODE)->type.user_align)
² 1 if the alignment for this type was requested by "aligned" attribute, 0 if it is the default for this type.
Ø TYPE_ALIGN_UNIT (TYPE_ALIGN (NODE) / BITS_PER_UNIT)
² The alignment for NODE, in bytes.
Ø TYPE_NO_FORCE_BLK (TYPE_CHECK (NODE)->type.no_force_blk_flag)
² In a RECORD_TYPE, UNION_TYPE or QUAL_UNION_TYPE, it means the type has BLKmode only because it lacks the alignment requirement for its size.
Ø TYPE_IS_SIZETYPE (INTEGER_TYPE_CHECK (NODE)->type.no_force_blk_flag)
² In an INTEGER_TYPE, it means the type represents a size. We use this both for validity checking and to permit optimizations that are unsafe for other types. Note that the C `size_t' type should *not* have this flag set. The `size_t' type is simply a typedef for an ordinary integer type that happens to be the type of an expression returned by `sizeof'; `size_t' has no special properties. Expressions whose type have TYPE_IS_SIZETYPE set are always actual sizes.
Ø TYPE_RETURNS_STACK_DEPRESSED
(FUNCTION_TYPE_CHECK (NODE)->type.no_force_blk_flag)
² In a FUNCTION_TYPE, indicates that the function returns with the stack pointer depressed.
Ø TYPE_STRING_FLAG (TYPE_CHECK (NODE)->type.string_flag)
² If set in an ARRAY_TYPE, indicates a string type (for languages that distinguish string from array of char). If set in a SET_TYPE, indicates a bitstring type.
GET_MODE_NUNITS (VECTOR_TYPE_CHECK (VECTOR_TYPE)->type.mode)
² For a VECTOR_TYPE, this is the number of sub-parts of the vector.
(TYPE_CHECK (NODE)->type.needs_constructing_flag)
² Indicates that objects of this type must be initialized by calling a function when they are created.
(UNION_TYPE_CHECK (NODE)->type.transparent_union_flag)
² Indicates that objects of this type (a UNION_TYPE), should be passed the same way that the first union alternative would be passed.
(ARRAY_TYPE_CHECK (NODE)->type.transparent_union_flag)
² For an ARRAY_TYPE, indicates that it is not permitted to take the address of a component of the type.
Ø TYPE_PACKED (TYPE_CHECK (NODE)->type.packed_flag)
² Indicated that objects of this type should be laid out in as compact a way as possible.
Ø TYPE_LANG_FLAG_0 ~ TYPE_LANG_FLAG_6
² These flags are available for each language front end to use internally.
Ø TYPE_NEXT_VARIANT (TYPE_CHECK (NODE)->type.next_variant)
² Used to chain together types that are variants made by type modifiers such as "const" and "volatile".
Ø TYPE_MAIN_VARIANT (TYPE_CHECK (NODE)->type.main_variant)
² In any member of such a chain (previous), points to the start of the chain.
List 2 flags in tree_type
1.2.4.1.2. Node creation
The node of pointer type is built by following function.
3654 build_pointer_type (tree to_type) in tree.c
3655 {
3656 return build_pointer_type_for_mode (to_type, ptr_mode);
3657 }
Here, to_type is the type to which it will create the node of pointer type, and note that the second parameter for build_pointer_type_for_mode is ptr_mode. This function will also be invoked to create pointer for vector mode data (refer to Back-end 7. Tool of genmodes for detail).
3625 tree
3626 build_pointer_type_for_mode (tree to_type, enum machine_mode mode) in tree.c
3627 {
3628 tree t = TYPE_POINTER_TO (to_type);
3629
3630 /* First, if we already have a type for pointers to TO_TYPE, use it. */
3631 if (t != 0 && mode == ptr_mode)
3632 return t;
3633
3634 t = make_node (POINTER_TYPE);
3635
3636 TREE_TYPE (t) = to_type;
3637 TYPE_MODE (t) = mode;
3638
3639 /* Record this type as the pointer to TO_TYPE. */
3640 if (mode == ptr_mode)
3641 TYPE_POINTER_TO (to_type) = t;
3642
3643 /* Lay out the type. This function has many callers that are concerned
3644 with expression-construction, and this simplifies them all.
3645 Also, it guarantees the TYPE_SIZE is in the same obstack as the type. */
3646 layout_type (t);
3647
3648 return t;
3649 }
For the type pointed to, it should ensure that the inforamtion about it has been collect, it includes: size in unit (accessed by TYPE_SIZE_UNIT), size in bits (accessed by TYPE_SIZE), and fittest mode. While for aggregate types (for example, array type, struct or union in C/C++), besides, every data member in it must have the alignment, offset from the beginning of the aggregate type, both size in bits and bytes after adjusted by alignment settled. This is done by layout_type below.
1.2.4.1.3. Layout the type
Below we just focus on the code related to the pointer type; while for other situations we have to leave them to other chapters. All information about size, sign and alignment is indicated by the tree mode (refer to 1.2.2.1.5.1.2 The Concept of Mode) for fundmental types.
1516 void
1517 layout_type (tree type) in stor-layout..c
1518 {
1519 if (type == 0)
1520 abort ();
1521
1522 /* Do nothing if type has been laid out before. */
1523 if (TYPE_SIZE (type))
1524 return;
1525
1526 switch (TREE_CODE (type))
1527 {
…
1602 case POINTER_TYPE:
1603 case REFERENCE_TYPE:
1604 {
1605
1606 enum machine_mode mode = ((TREE_CODE (type) == REFERENCE_TYPE
1607 && reference_types_internal)
1608 ? Pmode : TYPE_MODE (type));
1609
1610 int nbits = GET_MODE_BITSIZE (mode);
1611
1612 TYPE_SIZE (type) = bitsize_int (nbits);
1613 TYPE_SIZE_UNIT (type) = size_int (GET_MODE_SIZE (mode));
1614 TREE_UNSIGNED (type) = 1;
1615 TYPE_PRECISION (type) = nbits;
1616 }
1617 break;
…
1795 }
…
1797 if (TREE_CODE (type) != RECORD_TYPE
1798 && TREE_CODE (type) != UNION_TYPE
1799 && TREE_CODE (type) != QUAL_UNION_TYPE)
1800 finalize_type_size (type);
…
1818 }
At line 1607 reference_types_internal is nonzero, if all REFERENCE_TYPEs are internal and hence should be allocated in Pmode (Pmode is a macro aliases to appropriate mode in target machine), not ptr_mode (which only indicates mode size of POINTER_SIZE, see following section 1.2.1.2 node for reference type). This global variable is set only by internal_reference_types called only by front end. But for C++, it stays with 0.
And finalize_type_size at line 1804 gets alignment information by mode.
1363 static void
1364 finalize_type_size (tree type)
1365 {
1366 /* Normally, use the alignment corresponding to the mode chosen.
1367 However, where strict alignment is not required, avoid
1368 over-aligning structures, since most compilers do not do this
1369 alignment. */
1370
1371 if (TYPE_MODE (type) != BLKmode && TYPE_MODE (type) != VOIDmode
1372 && (STRICT_ALIGNMENT
1373 || (TREE_CODE (type) != RECORD_TYPE && TREE_CODE (type) != UNION_TYPE
1374 && TREE_CODE (type) != QUAL_UNION_TYPE
1375 && TREE_CODE (type) != ARRAY_TYPE)))
1376 {
1377 TYPE_ALIGN (type) = GET_MODE_ALIGNMENT (TYPE_MODE (type));
1378 TYPE_USER_ALIGN (type) = 0;
1379 }
…
1412 /* Also layout any other variants of the type. */
1413 if (TYPE_NEXT_VARIANT (type)
1414 || type != TYPE_MAIN_VARIANT (type))
1415 {
1416 tree variant;
1417 /* Record layout info of this variant. */
1418 tree size = TYPE_SIZE (type);
1419 tree size_unit = TYPE_SIZE_UNIT (type);
1420 unsigned int align = TYPE_ALIGN (type);
1421 unsigned int user_align = TYPE_USER_ALIGN (type);
1422 enum machine_mode mode = TYPE_MODE (type);
1423
1424 /* Copy it into all variants. */
1425 for (variant = TYPE_MAIN_VARIANT (type);
1426 variant != 0;
1427 variant = TYPE_NEXT_VARIANT (variant))
1428 {
1429 TYPE_SIZE (variant) = size;
1430 TYPE_SIZE_UNIT (variant) = size_unit;
1431 TYPE_ALIGN (variant) = align;
1432 TYPE_USER_ALIGN (variant) = user_align;
1433 TYPE_MODE (variant) = mode;
1434 }
1435 }
1436 }
For types qualified by keywords “const”, “volatile”, “register”, they are chained tegother with TYPE_MAIN_VARIANT points to the unqualified version, and visiting others via TYPE_NEXT_VARIANT. All these versions are updated from line 1413.
1.2.4.2. Create node for reference type
Reference type is no different than pointer type, see line 3693, the mode of reference type is ptr_mode. As result, the creation is very similar with that of pointer type.
3690 tree
3691 build_reference_type (tree to_type) in tree.c
3692 {
3693 return build_reference_type_for_mode (to_type, ptr_mode);
3694 }
3663 tree
3664 build_reference_type_for_mode (tree to_type, enum machine_mode mode) in tree.c
3665 {
3666 tree t = TYPE_REFERENCE_TO (to_type);
3667
3668 /* First, if we already have a type for pointers to TO_TYPE, use it. */
3669 if (t != 0 && mode == ptr_mode)
3670 return t;
3671
3672 t = make_node (REFERENCE_TYPE);
3673
3674 TREE_TYPE (t) = to_type;
3675 TYPE_MODE (t) = mode;
3676
3677 /* Record this type as the pointer to TO_TYPE. */
3678 if (mode == ptr_mode)
3679 TYPE_REFERENCE_TO (to_type) = t;
3680
3681 layout_type (t);
3682
3683 return t;
3684 }
1.2.4.3. Create node for address
The return type of build_address is tree_exp (more precisely, it is an address expression), as line 3683 indicates. Something about ADDR_EXPR is shown below:
ADDR_EXPR[2]
² These nodes are used to represent the address of an object. (These expressions will always have pointer or reference type.) The operand may be another expression, or it may be a declaration. As an extension, GCC allows users to take the address of a label. In this case, the operand of the ADDR_EXPR will be a LABEL_DECL. The type of such an expression is void*. If the object addressed is not an lvalue, a temporary is created, and the address of the temporary is used.
3675 tree
3676 build_address (tree t) in typeck.c
3677 {
3678 tree addr;
3679
3680 if (error_operand_p (t) || !cxx_mark_addressable (t))
3681 return error_mark_node;
3682
3683 addr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (t)), t);
3684 if (staticp (t))
3685 TREE_CONSTANT (addr) = 1;
3686
3687 return addr;
3688 }
At line 3680, cxx_mark_addressable marks t saying that we need to be able to take the address of t; t should not be allocated in a register. The function returns true if successful. And staticp at line 3684 checks if the address refers to static memory (for example, a string constant, label, and static/global variable). Address of this kind will not change in run time, on the contrary local variable in a function may have different address in each invocation - considering recursion, this address of such type is not constant.
1.2.4.4. Create node for OFFSET_TYPE
In C/C++ programing, we can use macro offsetof to find out the offset of certain data member from the beginning of the containing struct/class. What the macro finds out is the OFFSET_TYPE created here. It is used when we access data member like A.b or A->b.
3956 tree
3957 build_offset_type (tree basetype, tree type) in tree.c
3958 {
3959 tree t;
3960 unsigned int hashcode;
3961
3962 /* Make a node of the sort we want. */
3963 t = make_node (OFFSET_TYPE);
3964
3965 TYPE_OFFSET_BASETYPE (t) = TYPE_MAIN_VARIANT (basetype);
3966 TREE_TYPE (t) = type;
3967
3968 /* If we already have such a type, use the old one and free this one. */
3969 hashcode = TYPE_HASH (basetype) + TYPE_HASH (type);
3970 t = type_hash_canon (hashcode, t);
3971
3972 if (!COMPLETE_TYPE_P (t))
3973 layout_type (t);
3974
3975 return t;
3976 }
As we have known, TYPE_MAIN_VARIANT returns the unqualified version of a type, and other type variants made by type modifiers such as "const" and "volatile" are chained together by TYPE_NEXT_VARIANT. We use unqualified version as the base type for offset.