2.2.3.1.5.2.2.6. RECORD_TYPE中的FIELD_DECL
上面已经提到FIELD_DECL用于表示非静态成员,具体的描述如下:
FIELD_DECL[2]
² 这些节点表示类的非静态成员。其DECL_SIZE和DECL_ALIGN的行为与VAR_DECL节点的相同。而DECL_FIELD_BITPOS给出了该域使用的第一个比特,它是一个INTEGER_CST。这些值从0开始,0则表示对象开头的第一个比特。
如果DECL_C_BIT_FIELD成立,这个域是位域。
2.2.3.1.5.2.2.6.1. 确定FIELD_DECL的对齐量
同样RECORD_TYPE(对应class或struct)中的域,由place_field 来布局。需要指出,它不仅仅由layout_type来调用,对编译器声明的类进行布局。它还会由layout_class_type调用,来对用户声明类进行布局。
域的对齐量将深刻影响RECORD_TYPE的布局。在一些机器上,主要是RISC机器,非对齐的数据将使机器崩溃;而在其他机器,虽然不至崩溃,但相当影响运行效率。因此,没有特别的指明,编译器都会使数据对齐。当然这也不是没有代价的,数据对齐的程序比紧凑数据的程序要大一些,会多占些硬盘和内存。有时为了使数据在不同平台上都有一样的大小,或者为了使数据放入特定的尺寸,需要指明数据的对齐量或者使其紧凑布局。在Linux的内核及驱动程序中,都能找到这样的例子。为了控制数据的布局,GCC提供了属性诸如:packed,align;指示(directive),例如#pragma pack(N);及编译选项ms-bitfields/noms-bitfields。
另外,位域也使得域布局更复杂。MS布局允许只要类型的大小不被突破,相同类型的,相邻的位域,可以共用同一个内存单元。而在GCC的默认布局中,不同类型的位域也可以共享同一个内存单元。位域一个重要的变种是,0大小位域。对于这样的位域声明,它们必须是匿名的。总之,插入其他位域间的0大小位域,会使跟随其后的位域被放置在它的对齐边界,不管之前的内存单元是否用完。而拖尾的0大小位域将被忽略。
以下place_field的片段按上面提到的方案来布局域。
place_field (continue)
860 /* Work out the known alignment so far. Note that A & (-A) is the
861 value of the least-significant bit in A that is one. */
862 if (!integer_zerop (rli->bitpos))
863 known_align = (tree_low_cst (rli->bitpos, 1)
864 & - tree_low_cst (rli->bitpos, 1));
865 else if (integer_zerop (rli->offset))
866 known_align = BIGGEST_ALIGNMENT;
867 else if (host_integerp (rli->offset, 1))
868 known_align = (BITS_PER_UNIT
869 * (tree_low_cst (rli->offset, 1)
870 & - tree_low_cst (rli->offset, 1)));
871 else
872 known_align = rli->offset_align;
873
874 desired_align = update_alignment_for_field (rli, field, known_align);
在record_layout_info中的bitpos记录着当前比特的位置,它由offset后的比特记起。而offset则记录了当前已布局部分的字节大小,但不包括bitpos中的比特。后面我们会看到这一点。
因此在862行开始,如上例所示的,如果较小的类型跟在较大类型的后面(862行条件),known_align被设为bitpos的最低非0位构成的数值。那么如果是刚开始布局结构体(offset是size_zero_node,865行条件),known_align被设为BIGGEST_ALIGNMENT(对于x86是128比特);否则,如果offset是可以被有效率处理的整型常量(小于4G的整型常量),则known_align被设为offset的最低非0位构成的数值乘上。而进入871行条件,则意味着出现了非常量大小的域(对于C++,基本上这意味着错误的声明。后面可以看到,对于模板这样的东西,只有具现时才会被布局),这样known_align已无法通过已布局部分来确定,唯有假定其为offset_align。
上面我们已经看过了update_alignment_for_field,这个函数会返回最终决定的域的对齐量。我们在位域声明节点的处理一节看到,对于大小非0的位域,如果在layout_decl中,它没有被合适的整型模式匹配,它的DECL_ALIGN会是0。
2.2.3.1.5.2.2.6.2. 不必要的紧凑布局
如果使用了编译选项-Wpacked,下面的warn_packed会被设为非0值。在packed属性不需要或导致低效代码时,发出警告。另外,对于域声明,DECL_PACKED非0,意味着该域是紧凑的(即使用了packed属性)。
place_field (continue)
876 if (warn_packed && DECL_PACKED (field))
877 {
878 if (known_align >= TYPE_ALIGN (type))
879 {
880 if (TYPE_ALIGN (type) > desired_align)
881 {
882 if (STRICT_ALIGNMENT)
883 warning ("%Jpacked attribute causes inefficient alignment "
884 "for '%D'", field, field);
885 else
886 warning ("%Jpacked attribute is unnecessary for '%D'",
887 field, field);
888 }
889 }
890 else
891 rli->packed_maybe_necessary = 1;
892 }
已知known_align基本上是前一个域的最后比特地址的对齐量(注意下一个比特是空的),而desired_align是当前域所期望的对齐量。显然,如果known_align大于desired_align,这个域可以很自然地从这下一个比特开始放置,而不需要packed属性。为这个不需要的packed属性,编译器会产生低效的代码,例如,在882行的STRICT_ALIGNMENT,在那些move指令不能用于非对齐数据的平台上,被设置为1(x86不是这样的平台)。对这些平台,编译器将避免产生这样的代码,虽然这样做是不必要的。
2.2.3.1.5.2.2.6.3. 需要填充的情况
如果desired_align大于known_align,那么在域与域之间就出现了空隙,这些空隙需要填充,使下一个的域可以被放置在期望的边界。下面的warn_padded由编译选项-Wpadded设置,当出现填充时,发出警告。
place_field (continue)
894 /* Does this field automatically have alignment it needs by virtue
895 of the fields that precede it and the record's own alignment? */
896 if (known_align < desired_align)
897 {
898 /* No, we need to skip space before this field.
899 Bump the cumulative size to multiple of field alignment. */
900
901 if (warn_padded)
902 warning ("%Jpadding struct to align '%D'", field, field);
903
904 /* If the alignment is still within offset_align, just align
905 the bit position. */
906 if (desired_align < rli->offset_align)
907 rli->bitpos = round_up (rli->bitpos, desired_align);
908 else
909 {
910 /* First adjust OFFSET by the partial bits, then align. */
911 rli->offset
912 = size_binop (PLUS_EXPR, rli->offset,
913 convert (sizetype,
914 size_binop (CEIL_DIV_EXPR, rli->bitpos,
915 bitsize_unit_node)));
916 rli->bitpos = bitsize_zero_node;
917
918 rli->offset = round_up (rli->offset, desired_align / BITS_PER_UNIT);
919 }
920
921 if (! TREE_CONSTANT (rli->offset))
922 rli->offset_align = desired_align;
923
924 }
当desired_align大于known_algin,但小于offset_align,例如下例中的f2:
struct temp {
int f1:17; // known_align: 15, offset_align: 128, bitpos: 17
short f2:10; // desired_align: 16
};
在这种情况下,如果是GCC的默认布局,f1和f2可以共享同一个int大小的内存。因为bitpos记录了正在布局,没有超出对齐边界的部分,那么即便包括这个域,它也可能不会越界。因此它被取整到desired_align的边界(下面会看到,对于MS的位域布局,这个调整是无用的)。
而如果desired_align大于offset_align,这意味着我们正在非常量大小的布局中(所有域都是常量大小的布局中,offset_align维持在128,为最大的可能对齐量),offset_align记录着已布局部分的对齐量。而921行的条件也将满足,offset_align将持续记录着该对齐量。
2.2.3.1.5.2.2.6.4. GCC默认布局下的位域
我们已经知道,对于没有位域操作指令的机器,PCC_BITFIELD_TYPE_MATTERS必须定义为1,以防止位域跨越类型边界(x86就是这样的机器)。虽然,GCC默认布局允许不同类型大小的位域共享同一个内存单元,但在PCC_BITFIELD_TYPE_MATTERS为1的情况下,必须保证没有位域跨越对齐边界。
place_field (continue)
926 /* Handle compatibility with PCC. Note that if the record has any
927 variable-sized fields, we need not worry about compatibility. */
928 #ifdef PCC_BITFIELD_TYPE_MATTERS
929 if (PCC_BITFIELD_TYPE_MATTERS
930 && ! (* targetm.ms_bitfield_layout_p) (rli->t)
931 && TREE_CODE (field) == FIELD_DECL
932 && type != error_mark_node
933 && DECL_BIT_FIELD (field)
934 && ! DECL_PACKED (field)
935 && maximum_field_alignment == 0
936 && ! integer_zerop (DECL_SIZE (field))
937 && host_integerp (DECL_SIZE (field), 1)
938 && host_integerp (rli->offset, 1)
939 && host_integerp (TYPE_SIZE (type), 1))
940 {
941 unsigned int type_align = TYPE_ALIGN (type);
942 tree dsize = DECL_SIZE (field);
943 HOST_WIDE_INT field_size = tree_low_cst (dsize, 1);
944 HOST_WIDE_INT offset = tree_low_cst (rli->offset, 0);
945 HOST_WIDE_INT bit_offset = tree_low_cst (rli->bitpos, 0);
946
947 #ifdef ADJUST_FIELD_ALIGN
948 if (! TYPE_USER_ALIGN (type))
949 type_align = ADJUST_FIELD_ALIGN (field, type_align);
950 #endif
951
952 /* A bit field may not span more units of alignment of its type
953 than its type itself. Advance to next boundary if necessary. */
954 if (excess_unit_span (offset, bit_offset, field_size, type_align, type))
955 rli->bitpos = round_up (rli->bitpos, type_align);
956
957 TYPE_USER_ALIGN (rli->t) |= TYPE_USER_ALIGN (type);
958 }
959 #endif
960
961 #ifdef BITFIELD_NBYTES_LIMITED
…
998 #endif
在对union的布局中,已经看到宏ADJUST_FIELD_ALIGN调用x86_field_alignment来根据目标平台来进一步调整对齐量。如果位域会跨过自己的类型对齐边界,bitpos会被取整到最接近的类型对齐边界,位域将放置在这个边界上。
函数excess_unit_span用于检查越界的情况。
801 static int
802 excess_unit_span (HOST_WIDE_INT byte_offset, HOST_WIDE_INT bit_offset, in stor-layout.c
803 HOST_WIDE_INT size, HOST_WIDE_INT align, tree type)
804 {
805 /* Note that the calculation of OFFSET might overflow; we calculate it so
806 that we still get the right result as long as ALIGN is a power of two. */
807 unsigned HOST_WIDE_INT offset = byte_offset * BITS_PER_UNIT + bit_offset;
808
809 offset = offset % align;
810 return ((offset + size + align - 1) / align
811 > ((unsigned HOST_WIDE_INT) tree_low_cst (TYPE_SIZE (type), 1)
812 / align));
813 }
注意到810行的(offset + size + align - 1) / align。它把offset+size取整到了最接近的align倍数上。而811行则计算类型大小对类型对齐量的倍数(例如,对于double,在x86上,这是2)。同时957行暗示,对于GCC的默认布局,对一个域使用了aligned属性,整个结构体也被视为由用户指定对齐的。而在961行, BITFIELD_NBYTES_LIMITED如果定义,意味着位域甚至不能跨越字节边界,除非它占满了前一个字节。对x86,这个宏没有定义。
2.2.3.1.5.2.2.6.5. MS布局下的位域
参考union布局一节中位域声明节点的处理部分。这里处理与之有类似之处。但需要考虑位域出现在结构中的次序,更为复杂些。下面1024行,在MS布局中,如果rli->prev_field不为NULL,表明前一个域也是位域。1032行的条件确保前一个位域和当前位域都不是0大小的。
place_field (continue)
1000 /* See the docs for TARGET_MS_BITFIELD_LAYOUT_P for details.
1001 A subtlety:
1002 When a bit field is inserted into a packed record, the whole
1003 size of the underlying type is used by one or more same-size
1004 adjacent bitfields. (That is, if its long:3, 32 bits is
1005 used in the record, and any additional adjacent long bitfields are
1006 packed into the same chunk of 32 bits. However, if the size
1007 changes, a new field of that size is allocated.) In an unpacked
1008 record, this is the same as using alignment, but not equivalent
1009 when packing.
1010
1011 Note: for compatibility, we use the type size, not the type alignment
1012 to determine alignment, since that matches the documentation */
1013
1014 if ((* targetm.ms_bitfield_layout_p) (rli->t)
1015 && ((DECL_BIT_FIELD_TYPE (field) && ! DECL_PACKED (field))
1016 || (rli->prev_field && ! DECL_PACKED (rli->prev_field))))
1017 {
1018 /* At this point, either the prior or current are bitfields,
1019 (possibly both), and we're dealing with MS packing. */
1020 tree prev_saved = rli->prev_field;
1021
1022 /* Is the prior field a bitfield? If so, handle "runs" of same
1023 type size fields. */
1024 if (rli->prev_field /* necessarily a bitfield if it exists. */)
1025 {
1026 /* If both are bitfields, nonzero, and the same size, this is
1027 the middle of a run. Zero declared size fields are special
1028 and handled as "end of run". (Note: it's nonzero declared
1029 size, but equal type sizes!) (Since we know that both
1030 the current and previous fields are bitfields by the
1031 time we check it, DECL_SIZE must be present for both.) */
1032 if (DECL_BIT_FIELD_TYPE (field)
1033 && ! integer_zerop (DECL_SIZE (field))
1034 && ! integer_zerop (DECL_SIZE (rli->prev_field))
1035 && host_integerp (DECL_SIZE (rli->prev_field), 0)
1036 && host_integerp (TYPE_SIZE (type), 0)
1037 && simple_cst_equal (TYPE_SIZE (type),
1038 TYPE_SIZE (TREE_TYPE (rli->prev_field))))
1039 {
1040 /* We're in the middle of a run of equal type size fields; make
1041 sure we realign if we run out of bits. (Not decl size,
1042 type size!) */
1043 HOST_WIDE_INT bitsize = tree_low_cst (DECL_SIZE (field), 0);
1044
1045 if (rli->remaining_in_alignment < bitsize)
1046 {
1047 /* out of bits; bump up to next 'word'. */
1048 rli->offset = DECL_FIELD_OFFSET (rli->prev_field);
1049 rli->bitpos
1050 = size_binop (PLUS_EXPR, TYPE_SIZE (type),
1051 DECL_FIELD_BIT_OFFSET (rli->prev_field));
1052 rli->prev_field = field;
1053 rli->remaining_in_alignment
1054 = tree_low_cst (TYPE_SIZE (type), 0);
1055 }
1056
1057 rli->remaining_in_alignment -= bitsize;
1058 }
MS布局和GCC默认布局的一大不同在于,对于MS布局,只有类型相同的位域才能共享同一的类型内存单元。在record_layout_info中remaining_in_alignment记录了共享单元中余下的位。如果这些剩余位对当前位域而言已不足够,那么就需要跳到下一个对齐边界上。注意到1049行的bitpos,对于MS布局,它布局的作用被remaining_in_alignment所代替,但它仍然记录未提交部分的大小。这里有个微妙的前提,因为layout_decl对位域的处理中,会把位域的类型替换为大小最接近的整型,因此2个类型相同的相邻位域的总大小,必然超出类型大小。
place_field (continue)
1059 else
1060 {
1061 /* End of a run: if leaving a run of bitfields of the same type
1062 size, we have to "use up" the rest of the bits of the type
1063 size.
1064
1065 Compute the new position as the sum of the size for the prior
1066 type and where we first started working on that type.
1067 Note: since the beginning of the field was aligned then
1068 of course the end will be too. No round needed. */
1069
1070 if (!integer_zerop (DECL_SIZE (rli->prev_field)))
1071 {
1072 tree type_size = TYPE_SIZE (TREE_TYPE (rli->prev_field));
1073
1074 rli->bitpos
1075 = size_binop (PLUS_EXPR, type_size,
1076 DECL_FIELD_BIT_OFFSET (rli->prev_field));
1077 }
1078 else
1079 /* We "use up" size zero fields; the code below should behave
1080 as if the prior field was not a bitfield. */
1081 prev_saved = NULL;
1082
1083 /* Cause a new bitfield to be captured, either this time (if
1084 currently a bitfield) or next time we see one. */
1085 if (!DECL_BIT_FIELD_TYPE(field)
1086 || integer_zerop (DECL_SIZE (field)))
1087 rli->prev_field = NULL;
1088 }
1089
1090 normalize_rli (rli);
1091 }
如果进入1059行的代码块,而且满足1070行的条件,表示或者,1)0大小位域跟在非0大小位域后,或者2)当前域也是非0大小位域,但与前一个域的类型不同,或者3)当前域不是位域。在MS布局中,当前域需要放置在新的内存单元。因此,1074行的表达式不完全正确,在v4.3.0,这个表达式已更改为:
rli->bitpos=size_binop (PLUS_EXPR, rli->bitpos, bitsize_int (rli->remaining_in_alignment));
否则如果前一个位域是0大小的,将执行1081行的代码。
接下来在1085行,如果当前域不是位域,或者是大小为0的位域。在处理下一个域时,它被视为跟在非位域后。
因为在上面的过程中,bitpos可能被更新了,它可能超过了对齐的边界,因此需要规范化bitpos和offset。这是normalize_rli的功能。
659 void
660 normalize_rli (record_layout_info rli) in stor-layout.c
661 {
662 normalize_offset (&rli->offset, &rli->bitpos, rli->offset_align);
663 }
在规范形式中,bitpos必须小于对齐量。
614 void
615 normalize_offset (tree *poffset, tree *pbitpos, unsigned int off_align) in stor-layout.c
616 {
617 /* If the bit position is now larger than it should be, adjust it
618 downwards. */
619 if (compare_tree_int (*pbitpos, off_align) >= 0)
620 {
621 tree extra_aligns = size_binop (FLOOR_DIV_EXPR, *pbitpos,
622 bitsize_int (off_align));
623
624 *poffset
625 = size_binop (PLUS_EXPR, *poffset,
626 size_binop (MULT_EXPR, convert (sizetype, extra_aligns),
627 size_int (off_align / BITS_PER_UNIT)));
628
629 *pbitpos
630 = size_binop (FLOOR_MOD_EXPR, *pbitpos, bitsize_int (off_align));
631 }
632 }
下面,如果当前域是,或者1)非位域,或者当前域是位域,而2)前一个域是位域,而且类型不同,或者3)前一个域不是位域,而当前域大小不为0;1105行的条件满足。注意对于非位域,其DECL_SIZE与其类型的TYPE_SIZE相同,因此对于这种域1121行的remaining_in_alignment是0。而对于位域,它是TYPE_SIZE中余下的比特数。
place_field (continue)
1093 /* If we're starting a new run of same size type bitfields
1094 (or a run of non-bitfields), set up the "first of the run"
1095 fields.
1096
1097 That is, if the current field is not a bitfield, or if there
1098 was a prior bitfield the type sizes differ, or if there wasn't
1099 a prior bitfield the size of the current field is nonzero.
1100
1101 Note: we must be sure to test ONLY the type size if there was
1102 a prior bitfield and ONLY for the current field being zero if
1103 there wasn't. */
1104
1105 if (!DECL_BIT_FIELD_TYPE (field)
1106 || ( prev_saved != NULL
1107 ? !simple_cst_equal (TYPE_SIZE (type),
1108 TYPE_SIZE (TREE_TYPE (prev_saved)))
1109 : ! integer_zerop (DECL_SIZE (field)) ))
1110 {
1111 /* Never smaller than a byte for compatibility. */
1112 unsigned int type_align = BITS_PER_UNIT;
1113
1114 /* (When not a bitfield), we could be seeing a flex array (with
1115 no DECL_SIZE). Since we won't be using remaining_in_alignment
1116 until we see a bitfield (and come by here again) we just skip
1117 calculating it. */
1118 if (DECL_SIZE (field) != NULL
1119 && host_integerp (TYPE_SIZE (TREE_TYPE (field)), 0)
1120 && host_integerp (DECL_SIZE (field), 0))
1121 rli->remaining_in_alignment
1122 = tree_low_cst (TYPE_SIZE (TREE_TYPE (field)), 0)
1123 - tree_low_cst (DECL_SIZE (field), 0);
1124
1125 /* Now align (conventionally) for the new type. */
1126 if (!DECL_PACKED(field))
1127 type_align = MAX(TYPE_ALIGN (type), type_align);
1128
1129 if (prev_saved
1130 && DECL_BIT_FIELD_TYPE (prev_saved)
1131 /* If the previous bit-field is zero-sized, we've already
1132 accounted for its alignment needs (or ignored it, if
1133 appropriate) while placing it. */
1134 && ! integer_zerop (DECL_SIZE (prev_saved)))
1135 type_align = MAX (type_align,
1136 TYPE_ALIGN (TREE_TYPE (prev_saved)));
1137
1138 if (maximum_field_alignment != 0)
1139 type_align = MIN (type_align, maximum_field_alignment);
1140
1141 rli->bitpos = round_up (rli->bitpos, type_align);
1142
1143 /* If we really aligned, don't allow subsequent bitfields
1144 to undo that. */
1145 rli->prev_field = NULL;
1146 }
1147 }
注意,1129行的prev_saved在前一个域为位域且大小为0时,被设为0,否则为前一个位域。对于位域,其大小已被计入remaining_in_alignment,但这部分需要被放置在对齐边界上,那么在1141行,bitpos计入这个到边界的调整。这个bitpos对于非位域同样有效。
2.2.3.1.5.2.2.6.6. 更新 record_layout_info
现在我们已经获取了当前域的对齐量,开始比特位的偏移量(通过offset和bispos),是时候把这些信息计入FIELD_DECL节点中,并更新record_layout_info。
place_field (continue)
1149 /* Offset so far becomes the position of this field after normalizing. */
1150 normalize_rli (rli);
1151 DECL_FIELD_OFFSET (field) = rli->offset;
1152 DECL_FIELD_BIT_OFFSET (field) = rli->bitpos;
1153 SET_DECL_OFFSET_ALIGN (field, rli->offset_align);
1154
1155 /* If this field ended up more aligned than we thought it would be (we
1156 approximate this by seeing if its position changed), lay out the field
1157 again; perhaps we can use an integral mode for it now. */
1158 if (!integer_zerop (DECL_FIELD_OFFSET (field)))
1159 actual_align = (tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 1)
1160 & - tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 1));
1161 else if (integer_zerop (DECL_FIELD_OFFSET (field)))
1162 actual_align = BIGGEST_ALIGNMENT;
1163 else if (host_integerp (DECL_FIELD_OFFSET (field), 1))
1164 actual_align = (BITS_PER_UNIT
1165 * (tree_low_cst (DECL_FIELD_OFFSET (field), 1)
1166 & - tree_low_cst (DECL_FIELD_OFFSET (field), 1)));
1167 else
1168 actual_align = DECL_OFFSET_ALIGN (field);
1169
1170 if (known_align != actual_align)
1171 layout_decl (field, actual_align);
1172
1173 /* Only the MS bitfields use this. */
1174 if (rli->prev_field == NULL && DECL_BIT_FIELD_TYPE(field))
1175 rli->prev_field = field;
1176
1177 /* Now add size of this field to the size of the record. If the size is
1178 not constant, treat the field as being a multiple of bytes and just
1179 adjust the offset, resetting the bit position. Otherwise, apportion the
1180 size amongst the bit position and offset. First handle the case of an
1181 unspecified size, which can happen when we have an invalid nested struct
1182 definition, such as struct j { struct j { int i; } }. The error message
1183 is printed in finish_struct. */
1184 if (DECL_SIZE (field) == 0)
1185 /* Do nothing. */;
1186 else if (TREE_CODE (DECL_SIZE_UNIT (field)) != INTEGER_CST
1187 || TREE_CONSTANT_OVERFLOW (DECL_SIZE_UNIT (field)))
1188 {
1189 rli->offset
1190 = size_binop (PLUS_EXPR, rli->offset,
1191 convert (sizetype,
1192 size_binop (CEIL_DIV_EXPR, rli->bitpos,
1193 bitsize_unit_node)));
1194 rli->offset
1195 = size_binop (PLUS_EXPR, rli->offset, DECL_SIZE_UNIT (field));
1196 rli->bitpos = bitsize_zero_node;
1197 rli->offset_align = MIN (rli->offset_align, desired_align);
1198 }
1199 else
1200 {
1201 rli->bitpos = size_binop (PLUS_EXPR, rli->bitpos, DECL_SIZE (field));
1202 normalize_rli (rli);
1203 }
1204 }
注意到对actual_align的赋值次序和862行的known_align是一致的。如果2者不相等,调用layout_decl对域重新布局,这对于位域,也许这次就能找到合适的整型模式。
既然域已被放置,调整相应的rli中的参数。对于非常量大小布局,offset_align必须被同步更新。
2.2.3.1.5.2.3. 完成布局
当所有域的布局都完成后,在layout_type的1748行,lang_adjust_rli是可被前端设置的钩子,用于提供特定的处理。在这个版本里,这个钩子没有使用(在v4.3.0,它被移除了)。接下来就可以确定整个结构体的大小、对齐等参数。
1444 void
1445 finish_record_layout (record_layout_info rli, int free_p) in stor-layout.c
1446 {
1447 /* Compute the final size. */
1448 finalize_record_size (rli);
1449
1450 /* Compute the TYPE_MODE for the record. */
1451 compute_record_mode (rli->t);
1452
1453 /* Perform any last tweaks to the TYPE_SIZE, etc. */
1454 finalize_type_size (rli->t);
1455
1456 /* Lay out any static members. This is done now because their type
1457 may use the record's type. */
1458 while (rli->pending_statics)
1459 {
1460 layout_decl (TREE_VALUE (rli->pending_statics), 0);
1461 rli->pending_statics = TREE_CHAIN (rli->pending_statics);
1462 }
1463
1464 /* Clean up. */
1465 if (free_p)
1466 free (rli);
1467 }
2.2.3.1.5.2.3.1. 确定类型大小
函数finalize_record_size用于根据给定的record_layout_info来计算聚集类型的最终大小。
1210 static void
1211 finalize_record_size (record_layout_info rli) in stor-layout.c
1212 {
1213 tree unpadded_size, unpadded_size_unit;
1214
1215 /* Now we want just byte and bit offsets, so set the offset alignment
1216 to be a byte and then normalize. */
1217 rli->offset_align = BITS_PER_UNIT;
1218 normalize_rli (rli);
1219
1220 /* Determine the desired alignment. */
1221 #ifdef ROUND_TYPE_ALIGN
1222 TYPE_ALIGN (rli->t) = ROUND_TYPE_ALIGN (rli->t, TYPE_ALIGN (rli->t),
1223 rli->record_align);
1224 #else
1225 TYPE_ALIGN (rli->t) = MAX (TYPE_ALIGN (rli->t), rli->record_align);
1226 #endif
1227
1228 /* Compute the size so far. Be sure to allow for extra bits in the
1229 size in bytes. We have guaranteed above that it will be no more
1230 than a single byte. */
1231 unpadded_size = rli_size_so_far (rli);
1232 unpadded_size_unit = rli_size_unit_so_far (rli);
1233 if (! integer_zerop (rli->bitpos))
1234 unpadded_size_unit
1235 = size_binop (PLUS_EXPR, unpadded_size_unit, size_one_node);
1236
1237 /* Round the size up to be a multiple of the required alignment. */
1238 TYPE_SIZE (rli->t) = round_up (unpadded_size, TYPE_ALIGN (rli->t));
1239 TYPE_SIZE_UNIT (rli->t) = round_up (unpadded_size_unit,
1240 TYPE_ALIGN (rli->t) / BITS_PER_UNIT);
1241
1242 if (warn_padded && TREE_CONSTANT (unpadded_size)
1243 && simple_cst_equal (unpadded_size, TYPE_SIZE (rli->t)) == 0)
1244 warning ("padding struct size to alignment boundary");
1245
1246 if (warn_packed && TREE_CODE (rli->t) == RECORD_TYPE
1247 && TYPE_PACKED (rli->t) && ! rli->packed_maybe_necessary
1248 && TREE_CONSTANT (unpadded_size))
1249 {
1250 tree unpacked_size;
1251
1252 #ifdef ROUND_TYPE_ALIGN
1253 rli->unpacked_align
1254 = ROUND_TYPE_ALIGN (rli->t, TYPE_ALIGN (rli->t), rli->unpacked_align);
1255 #else
1256 rli->unpacked_align = MAX (TYPE_ALIGN (rli->t), rli->unpacked_align);
1257 #endif
1258
1259 unpacked_size = round_up (TYPE_SIZE (rli->t), rli->unpacked_align);
1260 if (simple_cst_equal (unpacked_size, TYPE_SIZE (rli->t)))
1261 {
1262 TYPE_PACKED (rli->t) = 0;
1263
1264 if (TYPE_NAME (rli->t))
1265 {
1266 const char *name;
1267
1268 if (TREE_CODE (TYPE_NAME (rli->t)) == IDENTIFIER_NODE)
1269 name = IDENTIFIER_POINTER (TYPE_NAME (rli->t));
1270 else
1271 name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (rli->t)));
1272
1273 if (STRICT_ALIGNMENT)
1274 warning ("packed attribute causes inefficient alignment for `%s'", name);
1275 else
1276 warning ("packed attribute is unnecessary for `%s'", name);
1277 }
1278 else
1279 {
1280 if (STRICT_ALIGNMENT)
1281 warning ("packed attribute causes inefficient alignment");
1282 else
1283 warning ("packed attribute is unnecessary");
1284 }
1285 }
1286 }
1287 }
1217和1218行将结构的大小调整为字节数(offset)及余下的比特(bitpos)。在1221行,ROUND_TYPE_ALIGN对于x86系统没有定义。而1231及1232行,将找出结构实际所占据的字节数和比特数。
675 tree
676 rli_size_so_far (record_layout_info rli) in stor-layout.c
677 {
678 return bit_from_pos (rli->offset, rli->bitpos);
679 }
582 tree
583 bit_from_pos (tree offset, tree bitpos) in stor-layout.c
584 {
585 return size_binop (PLUS_EXPR, bitpos,
586 size_binop (MULT_EXPR, convert (bitsizetype, offset),
587 bitsize_unit_node));
588 }
667 tree
668 rli_size_unit_so_far (record_layout_info rli)
669 {
670 return byte_from_pos (rli->offset, rli->bitpos);
671 }
590 tree
591 byte_from_pos (tree offset, tree bitpos) in stor-layout.c
592 {
593 return size_binop (PLUS_EXPR, offset,
594 convert (sizetype,
595 size_binop (TRUNC_DIV_EXPR, bitpos,
596 bitsize_unit_node)));
597 }
注意到在函数byte_from_pos中,所计算出的字节数是不包括余下比特的(bitpos)。因此,如果在1233行,如果bitpos不为0,需要加上额外的字节。
1225行的record_align记录了结构体中域的最大对齐量,它也用作结构体的对齐量。而结构体的大小必须是对齐量的整数倍。
307 tree
308 round_up (tree value, int divisor) in stor-layout.c
309 {
310 tree arg = size_int_type (divisor, TREE_TYPE (value));
311
312 return size_binop (MULT_EXPR, size_binop (CEIL_DIV_EXPR, value, arg), arg);
313 }
剩下的,如果结构体结尾插入填充字节,又使用了-Wpadded,则发出警告。而对于紧凑布局,如果得到的大小和正常布局一样,只要使用了-Wpacked,也有发出警告。
2.2.3.1.5.2.3.2. 确定类型模式
因为BLKmode的数据是不会被放入寄存器(换而言之它只能被间接寻址),而对于不超过一定大小的RECORD_TYPE,事实上是可以被放入寄存器的。因此,需要为这样的类型确定类型模式,这样后端就可以产生有效的代码。
1291 void
1292 compute_record_mode (tree type) in stor-layout.c
1293 {
1294 tree field;
1295 enum machine_mode mode = VOIDmode;
1296
1297 /* Most RECORD_TYPEs have BLKmode, so we start off assuming that.
1298 However, if possible, we use a mode that fits in a register
1299 instead, in order to allow for better optimization down the
1300 line. */
1301 TYPE_MODE (type) = BLKmode;
1302
1303 if (! host_integerp (TYPE_SIZE (type), 1))
1304 return;
1305
1306 /* A record which has any BLKmode members must itself be
1307 BLKmode; it can't go in a register. Unless the member is
1308 BLKmode only because it isn't aligned. */
1309 for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
1310 {
1311 if (TREE_CODE (field) != FIELD_DECL)
1312 continue;
1313
1314 if (TREE_CODE (TREE_TYPE (field)) == ERROR_MARK
1315 || (TYPE_MODE (TREE_TYPE (field)) == BLKmode
1316 && ! TYPE_NO_FORCE_BLK (TREE_TYPE (field))
1317 && !(TYPE_SIZE (TREE_TYPE (field)) != 0
1318 && integer_zerop (TYPE_SIZE (TREE_TYPE (field)))))
1319 || ! host_integerp (bit_position (field), 1)
1320 || DECL_SIZE (field) == 0
1321 || ! host_integerp (DECL_SIZE (field), 1))
1322 return;
1323
1324 /* If this field is the whole struct, remember its mode so
1325 that, say, we can put a double in a class into a DF
1326 register instead of forcing it to live in the stack. */
1327 if (simple_cst_equal (TYPE_SIZE (type), DECL_SIZE (field)))
1328 mode = DECL_MODE (field);
1329
1330 #ifdef MEMBER_TYPE_FORCES_BLK
1331 /* With some targets, eg. c4x, it is sub-optimal
1332 to access an aligned BLKmode structure as a scalar. */
1333
1334 if (MEMBER_TYPE_FORCES_BLK (field, mode))
1335 return;
1336 #endif /* MEMBER_TYPE_FORCES_BLK */
1337 }
1338
1339 /* If we only have one real field; use its mode. This only applies to
1340 RECORD_TYPE. This does not apply to unions. */
1341 if (TREE_CODE (type) == RECORD_TYPE && mode != VOIDmode)
1342 TYPE_MODE (type) = mode;
1343 else
1344 TYPE_MODE (type) = mode_for_size_tree (TYPE_SIZE (type), MODE_INT, 1);
1345
1346 /* If structure's known alignment is less than what the scalar
1347 mode would need, and it matters, then stick with BLKmode. */
1348 if (TYPE_MODE (type) != BLKmode
1349 && STRICT_ALIGNMENT
1350 && ! (TYPE_ALIGN (type) >= BIGGEST_ALIGNMENT
1351 || TYPE_ALIGN (type) >= GET_MODE_ALIGNMENT (TYPE_MODE (type))))
1352 {
1353 /* If this is the only reason this type is BLKmode, then
1354 don't force containing types to be BLKmode. */
1355 TYPE_NO_FORCE_BLK (type) = 1;
1356 TYPE_MODE (type) = BLKmode;
1357 }
1358 }
一个显而易见的机会,是一个仅包含非BLKmode数据成员的结构体。这个结构体满足1327行条件。注意1320行,含有0大小位域的结构体只能是BLKmode的。
接下来,在finalize_record_size的基础上,finalize_type_size进行了一些微调,并把参数应用到类型的cv-qualifier变种上。同时对于非常量大小的类型,要调用variable_size为其表达式创建SAVE_EXPR节点,以防止编译器引入额外的求值。
在最后,处理所有挂起的静态变量声明。