@@ -21,6 +21,7 @@ pub struct StructLayoutTracker<'a, 'ctx: 'a> {
2121 padding_count : usize ,
2222 latest_field_layout : Option < Layout > ,
2323 max_field_align : usize ,
24+ last_field_was_bitfield : bool ,
2425}
2526
2627/// Returns a size aligned to a given value.
@@ -37,8 +38,17 @@ pub fn align_to(size: usize, align: usize) -> usize {
3738 size + align - rem
3839}
3940
41+ /// Returns the amount of bytes from a given amount of bytes, rounding up.
42+ pub fn bytes_from_bits ( n : usize ) -> usize {
43+ if n % 8 == 0 {
44+ return n / 8 ;
45+ }
46+
47+ n / 8 + 1
48+ }
49+
4050/// Returns the lower power of two byte count that can hold at most n bits.
41- pub fn bytes_from_bits ( mut n : usize ) -> usize {
51+ pub fn bytes_from_bits_pow2 ( mut n : usize ) -> usize {
4252 if n == 0 {
4353 return 0 ;
4454 }
@@ -63,6 +73,20 @@ fn test_align_to() {
6373 assert_eq ! ( align_to( 17 , 4 ) , 20 ) ;
6474}
6575
76+ #[ test]
77+ fn test_bytes_from_bits_pow2 ( ) {
78+ assert_eq ! ( bytes_from_bits_pow2( 0 ) , 0 ) ;
79+ for i in 1 ..9 {
80+ assert_eq ! ( bytes_from_bits_pow2( i) , 1 ) ;
81+ }
82+ for i in 9 ..17 {
83+ assert_eq ! ( bytes_from_bits_pow2( i) , 2 ) ;
84+ }
85+ for i in 17 ..33 {
86+ assert_eq ! ( bytes_from_bits_pow2( i) , 4 ) ;
87+ }
88+ }
89+
6690#[ test]
6791fn test_bytes_from_bits ( ) {
6892 assert_eq ! ( bytes_from_bits( 0 ) , 0 ) ;
@@ -72,8 +96,8 @@ fn test_bytes_from_bits() {
7296 for i in 9 ..17 {
7397 assert_eq ! ( bytes_from_bits( i) , 2 ) ;
7498 }
75- for i in 17 ..33 {
76- assert_eq ! ( bytes_from_bits( i) , 4 ) ;
99+ for i in 17 ..25 {
100+ assert_eq ! ( bytes_from_bits( i) , 3 ) ;
77101 }
78102}
79103
@@ -86,6 +110,7 @@ impl<'a, 'ctx> StructLayoutTracker<'a, 'ctx> {
86110 padding_count : 0 ,
87111 latest_field_layout : None ,
88112 max_field_align : 0 ,
113+ last_field_was_bitfield : false ,
89114 }
90115 }
91116
@@ -97,26 +122,33 @@ impl<'a, 'ctx> StructLayoutTracker<'a, 'ctx> {
97122 }
98123
99124 pub fn saw_base ( & mut self , base_ty : & Type ) {
100- self . align_to_latest_field ( ) ;
101-
102125 if let Some ( layout) = base_ty. layout ( self . ctx ) {
126+ self . align_to_latest_field ( layout) ;
127+
103128 self . latest_offset += self . padding_bytes ( layout) + layout. size ;
104129 self . latest_field_layout = Some ( layout) ;
105130 self . max_field_align = cmp:: max ( self . max_field_align , layout. align ) ;
106131 }
107132 }
133+
108134 pub fn saw_bitfield_batch ( & mut self , layout : Layout ) {
109- self . align_to_latest_field ( ) ;
135+ self . align_to_latest_field ( layout) ;
136+
137+ self . latest_offset += layout. size ;
138+
139+ debug ! ( "Offset: <bitfield>: {} -> {}" ,
140+ self . latest_offset - layout. size,
141+ self . latest_offset) ;
110142
111- self . latest_offset += self . padding_bytes ( layout) + layout. size ;
112143 self . latest_field_layout = Some ( layout) ;
144+ self . last_field_was_bitfield = true ;
113145 // NB: We intentionally don't update the max_field_align here, since our
114146 // bitfields code doesn't necessarily guarantee it, so we need to
115147 // actually generate the dummy alignment.
116148 }
117149
118150 pub fn saw_union ( & mut self , layout : Layout ) {
119- self . align_to_latest_field ( ) ;
151+ self . align_to_latest_field ( layout ) ;
120152
121153 self . latest_offset += self . padding_bytes ( layout) + layout. size ;
122154 self . latest_field_layout = Some ( layout) ;
@@ -151,7 +183,7 @@ impl<'a, 'ctx> StructLayoutTracker<'a, 'ctx> {
151183 }
152184 }
153185
154- self . align_to_latest_field ( ) ;
186+ let will_merge_with_bitfield = self . align_to_latest_field ( field_layout ) ;
155187
156188 let padding_layout = if self . comp . packed ( ) {
157189 None
@@ -160,17 +192,19 @@ impl<'a, 'ctx> StructLayoutTracker<'a, 'ctx> {
160192 Some ( offset) if offset / 8 > self . latest_offset => {
161193 offset / 8 - self . latest_offset
162194 }
163- _ if field_layout. align == 0 => 0 ,
164- _ => {
165- self . padding_bytes ( field_layout)
166- }
195+ _ if will_merge_with_bitfield || field_layout. align == 0 => 0 ,
196+ _ => self . padding_bytes ( field_layout) ,
167197 } ;
168198
169199 // Otherwise the padding is useless.
170200 let need_padding = padding_bytes >= field_layout. align ;
171201
172202 self . latest_offset += padding_bytes;
173203
204+ debug ! ( "Offset: <padding>: {} -> {}" ,
205+ self . latest_offset - padding_bytes,
206+ self . latest_offset) ;
207+
174208 debug ! ( "align field {} to {}/{} with {} padding bytes {:?}" ,
175209 field_name,
176210 self . latest_offset,
@@ -188,14 +222,22 @@ impl<'a, 'ctx> StructLayoutTracker<'a, 'ctx> {
188222 self . latest_offset += field_layout. size ;
189223 self . latest_field_layout = Some ( field_layout) ;
190224 self . max_field_align = cmp:: max ( self . max_field_align , field_layout. align ) ;
225+ self . last_field_was_bitfield = false ;
226+
227+ debug ! ( "Offset: {}: {} -> {}" ,
228+ field_name,
229+ self . latest_offset - field_layout. size,
230+ self . latest_offset) ;
191231
192232 padding_layout. map ( |layout| self . padding_field ( layout) )
193233 }
194234
195235 pub fn pad_struct ( & mut self , layout : Layout ) -> Option < ast:: StructField > {
196236 if layout. size < self . latest_offset {
197- warn ! ( "calculate struct layout incorrect, too more {} bytes" ,
198- self . latest_offset - layout. size) ;
237+ if cfg ! ( debug_assertions) {
238+ panic ! ( "calculate struct layout incorrect, too more {} bytes" ,
239+ self . latest_offset - layout. size) ;
240+ }
199241
200242 return None
201243 }
@@ -204,12 +246,19 @@ impl<'a, 'ctx> StructLayoutTracker<'a, 'ctx> {
204246
205247 // We always pad to get to the correct size if the struct is one of
206248 // those we can't align properly.
249+ //
250+ // Note that if the last field we saw was a bitfield, we may need to pad
251+ // regardless, because bitfields don't respect alignment as strictly as
252+ // other fields.
207253 if padding_bytes > 0 &&
208254 ( padding_bytes >= layout. align ||
255+ ( self . last_field_was_bitfield &&
256+ padding_bytes >= self . latest_field_layout . unwrap ( ) . align ) ||
209257 layout. align > mem:: size_of :: < * mut ( ) > ( ) ) {
210258 let layout = if self . comp . packed ( ) {
211259 Layout :: new ( padding_bytes, 1 )
212- } else if layout. align > mem:: size_of :: < * mut ( ) > ( ) {
260+ } else if self . last_field_was_bitfield ||
261+ layout. align > mem:: size_of :: < * mut ( ) > ( ) {
213262 // We've already given up on alignment here.
214263 Layout :: for_size ( padding_bytes)
215264 } else {
@@ -252,11 +301,37 @@ impl<'a, 'ctx> StructLayoutTracker<'a, 'ctx> {
252301 StructFieldBuilder :: named ( padding_field_name) . pub_ ( ) . build_ty ( ty)
253302 }
254303
255- fn align_to_latest_field ( & mut self ) {
304+ /// Returns whether the new field is known to merge with a bitfield.
305+ ///
306+ /// This is just to avoid doing the same check also in pad_field.
307+ fn align_to_latest_field ( & mut self , new_field_layout : Layout ) -> bool {
256308 if self . comp . packed ( ) {
257- // skip to align field when packed
258- } else if let Some ( layout) = self . latest_field_layout . take ( ) {
259- self . latest_offset += self . padding_bytes ( layout) ;
309+ // Skip to align fields when packed.
310+ return false ;
260311 }
312+
313+ let layout = match self . latest_field_layout {
314+ Some ( l) => l,
315+ None => return false ,
316+ } ;
317+
318+ // If it was, we may or may not need to align, depending on what the
319+ // current field alignment and the bitfield size and alignment are.
320+ debug ! ( "align_to_bitfield? {}: {:?} {:?}" , self . last_field_was_bitfield,
321+ layout, new_field_layout) ;
322+
323+ if self . last_field_was_bitfield &&
324+ new_field_layout. align <= layout. size % layout. align &&
325+ new_field_layout. size <= layout. size % layout. align {
326+ // The new field will be coalesced into some of the remaining bits.
327+ //
328+ // FIXME(emilio): I think this may not catch everything?
329+ debug ! ( "Will merge with bitfield" ) ;
330+ return true ;
331+ }
332+
333+ // Else, just align the obvious way.
334+ self . latest_offset += self . padding_bytes ( layout) ;
335+ return false ;
261336 }
262337}
0 commit comments