GCC-3.4.6源代码学习笔记(15)

2.2.3.1.5.2.2.6.        RECORD_TYPE中的FIELD_DECL

上面已经提到FIELD_DECL用于表示非静态成员,具体的描述如下:

FIELD_DECL[2]

²        这些节点表示类的非静态成员。其DECL_SIZEDECL_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(对应classstruct)中的域,由place_field 来布局。需要指出,它不仅仅由layout_type来调用,对编译器声明的类进行布局。它还会由layout_class_type调用,来对用户声明类进行布局。

域的对齐量将深刻影响RECORD_TYPE的布局。在一些机器上,主要是RISC机器,非对齐的数据将使机器崩溃;而在其他机器,虽然不至崩溃,但相当影响运行效率。因此,没有特别的指明,编译器都会使数据对齐。当然这也不是没有代价的,数据对齐的程序比紧凑数据的程序要大一些,会多占些硬盘和内存。有时为了使数据在不同平台上都有一样的大小,或者为了使数据放入特定的尺寸,需要指明数据的对齐量或者使其紧凑布局。在Linux的内核及驱动程序中,都能找到这样的例子。为了控制数据的布局,GCC提供了属性诸如:packedalign;指示(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位构成的数值。那么如果是刚开始布局结构体(offsetsize_zero_node865行条件),known_align被设为BIGGEST_ALIGNMENT(对于x86128比特);否则,如果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_PACKED0,意味着该域是紧凑的(即使用了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指令不能用于非对齐数据的平台上,被设置为1x86不是这样的平台)。对这些平台,编译器将避免产生这样的代码,虽然这样做是不必要的。

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的默认布局,f1f2可以共享同一个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_MATTERS1的情况下,必须保证没有位域跨越对齐边界。

 

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_inforemaining_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行的条件,表示或者,10大小位域跟在非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可能被更新了,它可能超过了对齐的边界,因此需要规范化bitposoffset。这是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)前一个域不是位域,而当前域大小不为01105行的条件满足。注意对于非位域,其DECL_SIZE与其类型的TYPE_SIZE相同,因此对于这种域1121行的remaining_in_alignment0。而对于位域,它是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

现在我们已经获取了当前域的对齐量,开始比特位的偏移量(通过offsetbispos),是时候把这些信息计入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_type1748行,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 }

 

12171218行将结构的大小调整为字节数(offset)及余下的比特(bitpos)。在1221行,ROUND_TYPE_ALIGN对于x86系统没有定义。而12311232行,将找出结构实际所占据的字节数和比特数。

 

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节点,以防止编译器引入额外的求值。

在最后,处理所有挂起的静态变量声明。

 

你可能感兴趣的:(struct,tree,layout,Integer,编译器,alignment)