88// option. This file may not be copied, modified, or distributed
99// except according to those terms.
1010
11+ /*!
12+ * # Representation of Algebraic Data Types
13+ *
14+ * This module determines how to represent enums, structs, tuples, and
15+ * (deprecated) structural records based on their monomorphized types;
16+ * it is responsible both for choosing a representation and
17+ * translating basic operations on values of those types.
18+ *
19+ * Note that the interface treats everything as a general case of an
20+ * enum, so structs/tuples/etc. have one pseudo-variant with
21+ * discriminant 0; i.e., as if they were a univariant enum.
22+ *
23+ * Having everything in one place will enable improvements to data
24+ * structure representation; possibilities include:
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+ * - User-specified alignment (e.g., cacheline-aligning parts of
31+ * concurrently accessed data structures); LLVM can't represent this
32+ * directly, so we'd have to insert padding fields in any structure
33+ * that might contain one and adjust GEP indices accordingly. See
34+ * issue #4578.
35+ *
36+ * - Rendering `Option<&T>` as a possibly-null `*T` instead of using
37+ * an extra word (and likewise for `@T` and `~T`). Can and probably
38+ * should also apply to any enum with one empty case and one case
39+ * starting with a non-null pointer (e.g., `Result<(), ~str>`).
40+ *
41+ * - Using smaller integer types for discriminants.
42+ *
43+ * - Store nested enums' discriminants in the same word. Rather, if
44+ * some variants start with enums, and those enums representations
45+ * have unused alignment padding between discriminant and body, the
46+ * outer enum's discriminant can be stored there and those variants
47+ * can start at offset 0. Kind of fancy, and might need work to
48+ * make copies of the inner enum type cooperate, but it could help
49+ * with `Option` or `Result` wrapped around another enum.
50+ *
51+ * - Tagged pointers would be neat, but given that any type can be
52+ * used unboxed and any field can have pointers (including mutable)
53+ * taken to it, implementing them for Rust seems difficult.
54+ */
55+
1156use core:: container:: Map ;
1257use core:: libc:: c_ulonglong;
1358use core:: option:: { Option , Some , None } ;
1459use core:: vec;
60+
1561use lib:: llvm:: { ValueRef , TypeRef , True , False } ;
1662use middle:: trans:: _match;
1763use middle:: trans:: build:: * ;
@@ -23,31 +69,58 @@ use syntax::ast;
2369use util:: ppaux:: ty_to_str;
2470
2571
26- // XXX: should this be done with boxed traits instead of ML-style?
72+ /// Representations.
2773pub enum Repr {
74+ /**
75+ * `Unit` exists only so that an enum with a single C-like variant
76+ * can occupy no space, for ABI compatibility with rustc from
77+ * before (and during) the creation of this module. It may not be
78+ * worth keeping around; `CEnum` and `Univariant` cover it
79+ * overwise.
80+ */
2881 Unit ( int ) ,
29- CEnum ( int , int ) , /* discriminant range */
82+ /// C-like enums; basically an int.
83+ CEnum ( int , int ) , // discriminant range
84+ /// Single-case variants, and structs/tuples/records.
3085 Univariant ( Struct , Destructor ) ,
86+ /**
87+ * General-case enums: discriminant as int, followed by fields.
88+ * The fields start immediately after the discriminant, meaning
89+ * that they may not be correctly aligned for the platform's ABI;
90+ * see above.
91+ */
3192 General ( ~[ Struct ] )
3293}
3394
95+ /**
96+ * Structs without destructors have historically had an extra layer of
97+ * LLVM-struct to make accessing them work the same as structs with
98+ * destructors. This could probably be flattened to a boolean now
99+ * that this module exists.
100+ */
34101enum Destructor {
35- DtorPresent ,
36- DtorAbsent ,
37- NoDtor
102+ StructWithDtor ,
103+ StructWithoutDtor ,
104+ NonStruct
38105}
39106
107+ /// For structs, and struct-like parts of anything fancier.
40108struct Struct {
41109 size : u64 ,
42110 align : u64 ,
43111 fields : ~[ ty:: t ]
44112}
45113
46-
114+ /**
115+ * Convenience for `represent_type`. There should probably be more or
116+ * these, for places in trans where the `ty::t` isn't directly
117+ * available.
118+ */
47119pub fn represent_node ( bcx : block , node : ast:: node_id ) -> @Repr {
48120 represent_type ( bcx. ccx ( ) , node_id_type ( bcx, node) )
49121}
50122
123+ /// Decides how to represent a given type.
51124pub fn represent_type ( cx : @CrateContext , t : ty:: t ) -> @Repr {
52125 debug ! ( "Representing: %s" , ty_to_str( cx. tcx, t) ) ;
53126 match cx. adt_reprs . find ( & t) {
@@ -56,18 +129,19 @@ pub fn represent_type(cx: @CrateContext, t: ty::t) -> @Repr {
56129 }
57130 let repr = @match ty:: get ( t) . sty {
58131 ty:: ty_tup( ref elems) => {
59- Univariant ( mk_struct ( cx, * elems) , NoDtor )
132+ Univariant ( mk_struct ( cx, * elems) , NonStruct )
60133 }
61134 ty:: ty_rec( ref fields) => {
62135 // XXX: Are these in the right order?
63- Univariant ( mk_struct ( cx, fields. map ( |f| f. mt . ty ) ) , DtorAbsent )
136+ Univariant ( mk_struct ( cx, fields. map ( |f| f. mt . ty ) ) ,
137+ StructWithoutDtor )
64138 }
65139 ty:: ty_struct( def_id, ref substs) => {
66140 let fields = ty:: lookup_struct_fields ( cx. tcx , def_id) ;
67141 let dt = ty:: ty_dtor ( cx. tcx , def_id) . is_present ( ) ;
68142 Univariant ( mk_struct ( cx, fields. map ( |field| {
69143 ty:: lookup_field_type ( cx. tcx , def_id, field. id , substs)
70- } ) ) , if dt { DtorPresent } else { DtorAbsent } )
144+ } ) ) , if dt { StructWithDtor } else { StructWithoutDtor } )
71145 }
72146 ty:: ty_enum( def_id, ref substs) => {
73147 struct Case { discr : int , tys : ~[ ty:: t ] } ;
@@ -80,17 +154,22 @@ pub fn represent_type(cx: @CrateContext, t: ty::t) -> @Repr {
80154 } ;
81155 if cases. len ( ) == 0 {
82156 // Uninhabitable; represent as unit
83- Univariant ( mk_struct ( cx , ~ [ ] ) , NoDtor )
157+ Unit ( 0 )
84158 } else if cases. len ( ) == 1 && cases[ 0 ] . tys . len ( ) == 0 {
159+ // `()`-like; see comment on definition of `Unit`.
85160 Unit ( cases[ 0 ] . discr )
86161 } else if cases. len ( ) == 1 {
87- // struct, tuple, newtype, etc .
162+ // Equivalent to a struct/tuple/newtype .
88163 assert cases[ 0 ] . discr == 0 ;
89- Univariant ( mk_struct ( cx, cases[ 0 ] . tys ) , NoDtor )
164+ Univariant ( mk_struct ( cx, cases[ 0 ] . tys ) , NonStruct )
90165 } else if cases. all ( |c| c. tys . len ( ) == 0 ) {
166+ // All bodies empty -> intlike
91167 let discrs = cases. map ( |c| c. discr ) ;
92168 CEnum ( discrs. min ( ) , discrs. max ( ) )
93169 } else {
170+ // The general case. Since there's at least one
171+ // non-empty body, explicit discriminants should have
172+ // been rejected by a checker before this point.
94173 if !cases. alli ( |i, c| c. discr == ( i as int ) ) {
95174 cx. sess . bug ( fmt ! ( "non-C-like enum %s with specified \
96175 discriminants",
@@ -115,13 +194,18 @@ fn mk_struct(cx: @CrateContext, tys: &[ty::t]) -> Struct {
115194 }
116195}
117196
118-
119- pub fn sizing_fields_of ( cx : @CrateContext , r : & Repr ) -> ~[ TypeRef ] {
120- generic_fields_of ( cx, r, true )
121- }
197+ /**
198+ * Returns the fields of a struct for the given representation.
199+ * All nominal types are LLVM structs, in order to be able to use
200+ * forward-declared opaque types to prevent circularity in `type_of`.
201+ */
122202pub fn fields_of ( cx : @CrateContext , r : & Repr ) -> ~[ TypeRef ] {
123203 generic_fields_of ( cx, r, false )
124204}
205+ /// Like `fields_of`, but for `type_of::sizing_type_of` (q.v.).
206+ pub fn sizing_fields_of ( cx : @CrateContext , r : & Repr ) -> ~[ TypeRef ] {
207+ generic_fields_of ( cx, r, true )
208+ }
125209fn generic_fields_of ( cx : @CrateContext , r : & Repr , sizing : bool )
126210 -> ~[ TypeRef ] {
127211 match * r {
@@ -134,9 +218,9 @@ fn generic_fields_of(cx: @CrateContext, r: &Repr, sizing: bool)
134218 st. fields . map ( |& ty| type_of:: type_of ( cx, ty) )
135219 } ;
136220 match dt {
137- NoDtor => f,
138- DtorAbsent => ~[ T_struct ( f) ] ,
139- DtorPresent => ~[ T_struct ( f) , T_i8 ( ) ]
221+ NonStruct => f,
222+ StructWithoutDtor => ~[ T_struct ( f) ] ,
223+ StructWithDtor => ~[ T_struct ( f) , T_i8 ( ) ]
140224 }
141225 }
142226 General ( ref sts) => {
@@ -164,6 +248,10 @@ fn load_discr(bcx: block, scrutinee: ValueRef, min: int, max: int)
164248 }
165249}
166250
251+ /**
252+ * Obtain as much of a "discriminant" as this representation has.
253+ * This should ideally be less tightly tied to `_match`.
254+ */
167255pub fn trans_switch ( bcx : block , r : & Repr , scrutinee : ValueRef )
168256 -> ( _match:: branch_kind , Option < ValueRef > ) {
169257 match * r {
@@ -176,18 +264,29 @@ pub fn trans_switch(bcx: block, r: &Repr, scrutinee: ValueRef)
176264 }
177265}
178266
267+ /**
268+ * If the representation is potentially of a C-like enum, implement
269+ * coercion to numeric types.
270+ */
179271pub fn trans_cast_to_int ( bcx : block , r : & Repr , scrutinee : ValueRef )
180272 -> ValueRef {
181273 match * r {
182274 Unit ( the_disc) => C_int ( bcx. ccx ( ) , the_disc) ,
183275 CEnum ( min, max) => load_discr ( bcx, scrutinee, min, max) ,
184276 Univariant ( * ) => bcx. ccx ( ) . sess . bug ( ~"type has no explicit \
185277 discriminant") ,
278+ // Note: this case is used internally by trans_switch,
279+ // even though it shouldn't be reached by an external caller.
186280 General ( ref cases) => load_discr ( bcx, scrutinee, 0 ,
187281 ( cases. len ( ) - 1 ) as int )
188282 }
189283}
190284
285+ /**
286+ * Yield information about how to dispatch a case of the
287+ * discriminant-like value returned by `trans_switch`.
288+ * This should ideally be less tightly tied to `_match`.
289+ */
191290pub fn trans_case( bcx : block , r : & Repr , discr : int ) -> _match:: opt_result {
192291 match * r {
193292 CEnum ( * ) => {
@@ -202,6 +301,11 @@ pub fn trans_case(bcx: block, r: &Repr, discr: int) -> _match::opt_result {
202301 }
203302}
204303
304+ /**
305+ * Begin initializing a new value of the given case of the given
306+ * representation. The fields should then be initialized with
307+ * `trans_GEP` and stores.
308+ */
205309pub fn trans_set_discr ( bcx : block , r : & Repr , val : ValueRef , discr : int ) {
206310 match * r {
207311 Unit ( the_discr) => {
@@ -211,7 +315,7 @@ pub fn trans_set_discr(bcx: block, r: &Repr, val: ValueRef, discr: int) {
211315 assert min <= discr && discr <= max;
212316 Store ( bcx, C_int ( bcx. ccx ( ) , discr) , GEPi ( bcx, val, [ 0 , 0 ] ) )
213317 }
214- Univariant ( _, DtorPresent ) => {
318+ Univariant ( _, StructWithDtor ) => {
215319 assert discr == 0 ;
216320 Store ( bcx, C_u8 ( 1 ) , GEPi ( bcx, val, [ 0 , 1 ] ) )
217321 }
@@ -224,6 +328,10 @@ pub fn trans_set_discr(bcx: block, r: &Repr, val: ValueRef, discr: int) {
224328 }
225329}
226330
331+ /**
332+ * The number of fields in a given case; for use when obtaining this
333+ * information from the type or definition is less convenient.
334+ */
227335pub fn num_args ( r : & Repr , discr : int ) -> uint {
228336 match * r {
229337 Unit ( * ) | CEnum ( * ) => 0 ,
@@ -232,20 +340,21 @@ pub fn num_args(r: &Repr, discr: int) -> uint {
232340 }
233341}
234342
343+ /// Access a field, at a point when the value's case is known.
235344pub fn trans_GEP ( bcx : block , r : & Repr , val : ValueRef , discr : int , ix : uint )
236345 -> ValueRef {
237346 // Note: if this ever needs to generate conditionals (e.g., if we
238347 // decide to do some kind of cdr-coding-like non-unique repr
239- // someday), it'll need to return a possibly-new bcx as well.
348+ // someday), it will need to return a possibly-new bcx as well.
240349 match * r {
241350 Unit ( * ) | CEnum ( * ) => {
242351 bcx. ccx ( ) . sess . bug ( ~"element access in C -like enum")
243352 }
244353 Univariant ( ref st, dt) => {
245354 assert discr == 0 ;
246355 let val = match dt {
247- NoDtor => val,
248- DtorPresent | DtorAbsent => GEPi ( bcx, val, [ 0 , 0 ] )
356+ NonStruct => val,
357+ StructWithDtor | StructWithoutDtor => GEPi ( bcx, val, [ 0 , 0 ] )
249358 } ;
250359 struct_GEP ( bcx, st, val, ix, false )
251360 }
@@ -271,14 +380,26 @@ fn struct_GEP(bcx: block, st: &Struct, val: ValueRef, ix: uint,
271380 GEPi ( bcx, val, [ 0 , ix] )
272381}
273382
383+ /// Access the struct drop flag, if present.
274384pub fn trans_drop_flag_ptr ( bcx : block , r : & Repr , val : ValueRef ) -> ValueRef {
275385 match * r {
276- Univariant ( _, DtorPresent ) => GEPi ( bcx, val, [ 0 , 1 ] ) ,
386+ Univariant ( _, StructWithDtor ) => GEPi ( bcx, val, [ 0 , 1 ] ) ,
277387 _ => bcx. ccx ( ) . sess . bug ( ~"tried to get drop flag of non-droppable \
278388 type ")
279389 }
280390}
281391
392+ /**
393+ * Construct a constant value, suitable for initializing a
394+ * GlobalVariable, given a case and constant values for its fields.
395+ * Note that this may have a different LLVM type (and different
396+ * alignment!) from the representation's `type_of`, so it needs a
397+ * pointer cast before use.
398+ *
399+ * Currently it has the same size as the type, but this may be changed
400+ * in the future to avoid allocating unnecessary space after values of
401+ * shorter-than-maximum cases.
402+ */
282403pub fn trans_const ( ccx : @CrateContext , r : & Repr , discr : int ,
283404 vals : & [ ValueRef ] ) -> ValueRef {
284405 match * r {
@@ -294,10 +415,10 @@ pub fn trans_const(ccx: @CrateContext, r: &Repr, discr: int,
294415 assert discr == 0 ;
295416 let s = C_struct ( build_const_struct ( ccx, st, vals) ) ;
296417 match dt {
297- NoDtor => s,
418+ NonStruct => s,
298419 // The actual destructor flag doesn't need to be present.
299420 // But add an extra struct layer for compatibility.
300- DtorPresent | DtorAbsent => C_struct ( ~[ s] )
421+ StructWithDtor | StructWithoutDtor => C_struct ( ~[ s] )
301422 }
302423 }
303424 General ( ref cases) => {
@@ -345,7 +466,7 @@ fn build_const_struct(ccx: @CrateContext, st: &Struct, vals: &[ValueRef])
345466#[ always_inline]
346467fn roundup ( x : u64 , a : u64 ) -> u64 { ( ( x + ( a - 1 ) ) / a) * a }
347468
348-
469+ /// Get the discriminant of a constant value. (Not currently used.)
349470pub fn const_get_discrim ( ccx : @CrateContext , r : & Repr , val : ValueRef )
350471 -> int {
351472 match * r {
@@ -356,13 +477,14 @@ pub fn const_get_discrim(ccx: @CrateContext, r: &Repr, val: ValueRef)
356477 }
357478}
358479
480+ /// Access a field of a constant value.
359481pub fn const_get_element ( ccx : @CrateContext , r : & Repr , val : ValueRef ,
360482 _discr : int , ix : uint ) -> ValueRef {
361483 // Not to be confused with common::const_get_elt.
362484 match * r {
363485 Unit ( * ) | CEnum ( * ) => ccx. sess . bug ( ~"element access in C -like enum \
364486 const ") ,
365- Univariant ( _, NoDtor ) => const_struct_field ( ccx, val, ix) ,
487+ Univariant ( _, NonStruct ) => const_struct_field ( ccx, val, ix) ,
366488 Univariant ( * ) => const_struct_field ( ccx, const_get_elt ( ccx, val,
367489 [ 0 ] ) , ix) ,
368490 General ( * ) => const_struct_field ( ccx, const_get_elt ( ccx, val,
@@ -395,8 +517,8 @@ fn const_struct_field(ccx: @CrateContext, val: ValueRef, ix: uint)
395517/// Is it safe to bitcast a value to the one field of its one variant?
396518pub fn is_newtypeish ( r : & Repr ) -> bool {
397519 match * r {
398- Univariant ( ref st, DtorAbsent )
399- | Univariant ( ref st, NoDtor ) => st. fields . len ( ) == 1 ,
520+ Univariant ( ref st, StructWithoutDtor )
521+ | Univariant ( ref st, NonStruct ) => st. fields . len ( ) == 1 ,
400522 _ => false
401523 }
402524}
0 commit comments