2323 * Having everything in one place will enable improvements to data
2424 * structure representation; possibilities include:
2525 *
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- *
3026 * - User-specified alignment (e.g., cacheline-aligning parts of
3127 * concurrently accessed data structures); LLVM can't represent this
3228 * directly, so we'd have to insert padding fields in any structure
@@ -82,10 +78,8 @@ pub enum Repr {
8278 */
8379 Univariant ( Struct , bool ) ,
8480 /**
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.
8983 */
9084 General ( ~[ Struct ] )
9185}
@@ -156,7 +150,8 @@ pub fn represent_type(cx: @CrateContext, t: ty::t) -> @Repr {
156150 discriminants",
157151 ty:: item_path_str( cx. tcx, def_id) ) )
158152 }
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 ) ) )
160155 }
161156 }
162157 _ => 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)
191186 -> ~[ TypeRef ] {
192187 match * r {
193188 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) ,
201190 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 ) ]
204214 }
205215 }
206216}
207217
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+
208227/**
209228 * Obtain a representation of the discriminant sufficient to translate
210229 * destructuring; this may or may not involve the actual discriminant.
@@ -309,7 +328,7 @@ pub fn num_args(r: &Repr, discr: int) -> uint {
309328 fail_unless ! ( discr == 0 ) ;
310329 st. fields . len ( ) - ( if dtor { 1 } else { 0 } )
311330 }
312- General ( ref cases) => cases[ discr as uint ] . fields . len ( )
331+ General ( ref cases) => cases[ discr as uint ] . fields . len ( ) - 1
313332 }
314333}
315334
@@ -328,8 +347,7 @@ pub fn trans_field_ptr(bcx: block, r: &Repr, val: ValueRef, discr: int,
328347 struct_field_ptr ( bcx, st, val, ix, false )
329348 }
330349 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 )
333351 }
334352 }
335353}
@@ -371,13 +389,12 @@ pub fn trans_drop_flag_ptr(bcx: block, r: &Repr, val: ValueRef) -> ValueRef {
371389 * depending on which case of an enum it is.
372390 *
373391 * 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.
378395 *
379396 * 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
381398 * space after values of shorter-than-maximum cases.
382399 */
383400pub fn trans_const ( ccx : @CrateContext , r : & Repr , discr : int ,
@@ -395,14 +412,9 @@ pub fn trans_const(ccx: @CrateContext, r: &Repr, discr: int,
395412 General ( ref cases) => {
396413 let case = & cases[ discr as uint ] ;
397414 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 ) ] )
406418 }
407419 }
408420}
@@ -472,11 +484,9 @@ pub fn const_get_discrim(ccx: @CrateContext, r: &Repr, val: ValueRef)
472484pub fn const_get_field( ccx : @CrateContext , r : & Repr , val : ValueRef ,
473485 _discr : int , ix : uint ) -> ValueRef {
474486 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 ") ,
477488 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 )
480490 }
481491}
482492
0 commit comments