23
23
* Having everything in one place will enable improvements to data
24
24
* structure representation; possibilities include:
25
25
*
26
- * - Aligning enum bodies correctly, which in turn makes possible SIMD
27
- * vector types (which are strict-alignment even on x86) and ports
28
- * to strict-alignment architectures (PowerPC, SPARC, etc.).
29
- *
30
26
* - User-specified alignment (e.g., cacheline-aligning parts of
31
27
* concurrently accessed data structures); LLVM can't represent this
32
28
* directly, so we'd have to insert padding fields in any structure
@@ -82,10 +78,8 @@ pub enum Repr {
82
78
*/
83
79
Univariant ( Struct , bool ) ,
84
80
/**
85
- * General-case enums: discriminant as int, followed by fields.
86
- * The fields start immediately after the discriminant, meaning
87
- * that they may not be correctly aligned for the platform's ABI;
88
- * see above.
81
+ * General-case enums: for each case there is a struct, and they
82
+ * all start with a field for the discriminant.
89
83
*/
90
84
General ( ~[ Struct ] )
91
85
}
@@ -156,7 +150,8 @@ pub fn represent_type(cx: @CrateContext, t: ty::t) -> @Repr {
156
150
discriminants",
157
151
ty:: item_path_str( cx. tcx, def_id) ) )
158
152
}
159
- General ( cases. map ( |c| mk_struct ( cx, c. tys ) ) )
153
+ let discr = ~[ ty:: mk_int ( cx. tcx ) ] ;
154
+ General ( cases. map ( |c| mk_struct ( cx, discr + c. tys ) ) )
160
155
}
161
156
}
162
157
_ => cx. sess . bug ( ~"adt:: represent_type called on non-ADT type")
@@ -191,20 +186,44 @@ fn generic_fields_of(cx: @CrateContext, r: &Repr, sizing: bool)
191
186
-> ~[ TypeRef ] {
192
187
match * r {
193
188
CEnum ( * ) => ~[ T_enum_discrim ( cx) ] ,
194
- Univariant ( ref st, _dtor) => {
195
- if sizing {
196
- st. fields . map ( |& ty| type_of:: sizing_type_of ( cx, ty) )
197
- } else {
198
- st. fields . map ( |& ty| type_of:: type_of ( cx, ty) )
199
- }
200
- }
189
+ Univariant ( ref st, _dtor) => struct_llfields ( cx, st, sizing) ,
201
190
General ( ref sts) => {
202
- ~[ T_enum_discrim ( cx) ,
203
- T_array ( T_i8 ( ) , sts. map ( |st| st. size ) . max ( ) /*bad*/ as uint ) ]
191
+ // To get "the" type of a general enum, we pick the case
192
+ // with the largest alignment (so it will always align
193
+ // correctly in containing structures) and pad it out.
194
+ fail_unless ! ( sts. len( ) >= 1 ) ;
195
+ let mut most_aligned = None ;
196
+ let mut largest_align = 0 ;
197
+ let mut largest_size = 0 ;
198
+ for sts. each |st| {
199
+ if largest_size < st. size {
200
+ largest_size = st. size ;
201
+ }
202
+ if largest_align < st. align {
203
+ // Clang breaks ties by size; it is unclear if
204
+ // that accomplishes anything important.
205
+ largest_align = st. align ;
206
+ most_aligned = Some ( st) ;
207
+ }
208
+ }
209
+ let most_aligned = most_aligned. get ( ) ;
210
+ let padding = largest_size - most_aligned. size ;
211
+
212
+ struct_llfields ( cx, most_aligned, sizing)
213
+ + [ T_array ( T_i8 ( ) , padding /*bad*/ as uint ) ]
204
214
}
205
215
}
206
216
}
207
217
218
+ fn struct_llfields ( cx : @CrateContext , st : & Struct , sizing : bool )
219
+ -> ~[ TypeRef ] {
220
+ if sizing {
221
+ st. fields . map ( |& ty| type_of:: sizing_type_of ( cx, ty) )
222
+ } else {
223
+ st. fields . map ( |& ty| type_of:: type_of ( cx, ty) )
224
+ }
225
+ }
226
+
208
227
/**
209
228
* Obtain a representation of the discriminant sufficient to translate
210
229
* destructuring; this may or may not involve the actual discriminant.
@@ -309,7 +328,7 @@ pub fn num_args(r: &Repr, discr: int) -> uint {
309
328
fail_unless ! ( discr == 0 ) ;
310
329
st. fields . len ( ) - ( if dtor { 1 } else { 0 } )
311
330
}
312
- General ( ref cases) => cases[ discr as uint ] . fields . len ( )
331
+ General ( ref cases) => cases[ discr as uint ] . fields . len ( ) - 1
313
332
}
314
333
}
315
334
@@ -328,8 +347,7 @@ pub fn trans_field_ptr(bcx: block, r: &Repr, val: ValueRef, discr: int,
328
347
struct_field_ptr ( bcx, st, val, ix, false )
329
348
}
330
349
General ( ref cases) => {
331
- struct_field_ptr ( bcx, & cases[ discr as uint ] ,
332
- GEPi ( bcx, val, [ 0 , 1 ] ) , ix, true )
350
+ struct_field_ptr ( bcx, & cases[ discr as uint ] , val, ix + 1 , true )
333
351
}
334
352
}
335
353
}
@@ -371,13 +389,12 @@ pub fn trans_drop_flag_ptr(bcx: block, r: &Repr, val: ValueRef) -> ValueRef {
371
389
* depending on which case of an enum it is.
372
390
*
373
391
* To understand the alignment situation, consider `enum E { V64(u64),
374
- * V32(u32, u32) }` on win32. The type should have 8-byte alignment
375
- * to accommodate the u64 (currently it doesn't; this is a known bug),
376
- * but `V32(x, y)` would have LLVM type `{i32, i32, i32}`, which is
377
- * 4-byte aligned.
392
+ * V32(u32, u32) }` on win32. The type has 8-byte alignment to
393
+ * accommodate the u64, but `V32(x, y)` would have LLVM type `{i32,
394
+ * i32, i32}`, which is 4-byte aligned.
378
395
*
379
396
* Currently the returned value has the same size as the type, but
380
- * this may be changed in the future to avoid allocating unnecessary
397
+ * this could be changed in the future to avoid allocating unnecessary
381
398
* space after values of shorter-than-maximum cases.
382
399
*/
383
400
pub fn trans_const ( ccx : @CrateContext , r : & Repr , discr : int ,
@@ -395,14 +412,9 @@ pub fn trans_const(ccx: @CrateContext, r: &Repr, discr: int,
395
412
General ( ref cases) => {
396
413
let case = & cases[ discr as uint ] ;
397
414
let max_sz = cases. map ( |s| s. size ) . max ( ) ;
398
- let body = build_const_struct ( ccx, case, vals) ;
399
-
400
- // The unary packed struct has alignment 1 regardless of
401
- // its contents, so it will always be located at the
402
- // expected offset at runtime.
403
- C_struct ( [ C_int ( ccx, discr) ,
404
- C_packed_struct ( [ C_struct ( body) ] ) ,
405
- padding ( max_sz - case. size ) ] )
415
+ let contents = build_const_struct ( ccx, case,
416
+ ~[ C_int ( ccx, discr) ] + vals) ;
417
+ C_struct ( contents + [ padding ( max_sz - case. size ) ] )
406
418
}
407
419
}
408
420
}
@@ -472,11 +484,9 @@ pub fn const_get_discrim(ccx: @CrateContext, r: &Repr, val: ValueRef)
472
484
pub fn const_get_field( ccx : @CrateContext , r : & Repr , val : ValueRef ,
473
485
_discr : int , ix : uint ) -> ValueRef {
474
486
match * r {
475
- CEnum ( * ) => ccx. sess . bug ( ~"element access in C -like enum \
476
- const ") ,
487
+ CEnum ( * ) => ccx. sess . bug ( ~"element access in C -like enum const ") ,
477
488
Univariant ( * ) => const_struct_field ( ccx, val, ix) ,
478
- General ( * ) => const_struct_field ( ccx, const_get_elt ( ccx, val,
479
- [ 1 , 0 ] ) , ix)
489
+ General ( * ) => const_struct_field ( ccx, val, ix + 1 )
480
490
}
481
491
}
482
492
0 commit comments