8
8
// option. This file may not be copied, modified, or distributed
9
9
// except according to those terms.
10
10
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
+
11
56
use core:: container:: Map ;
12
57
use core:: libc:: c_ulonglong;
13
58
use core:: option:: { Option , Some , None } ;
14
59
use core:: vec;
60
+
15
61
use lib:: llvm:: { ValueRef , TypeRef , True , False } ;
16
62
use middle:: trans:: _match;
17
63
use middle:: trans:: build:: * ;
@@ -23,31 +69,58 @@ use syntax::ast;
23
69
use util:: ppaux:: ty_to_str;
24
70
25
71
26
- // XXX: should this be done with boxed traits instead of ML-style?
72
+ /// Representations.
27
73
pub 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
+ */
28
81
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.
30
85
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
+ */
31
92
General ( ~[ Struct ] )
32
93
}
33
94
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
+ */
34
101
enum Destructor {
35
- DtorPresent ,
36
- DtorAbsent ,
37
- NoDtor
102
+ StructWithDtor ,
103
+ StructWithoutDtor ,
104
+ NonStruct
38
105
}
39
106
107
+ /// For structs, and struct-like parts of anything fancier.
40
108
struct Struct {
41
109
size : u64 ,
42
110
align : u64 ,
43
111
fields : ~[ ty:: t ]
44
112
}
45
113
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
+ */
47
119
pub fn represent_node ( bcx : block , node : ast:: node_id ) -> @Repr {
48
120
represent_type ( bcx. ccx ( ) , node_id_type ( bcx, node) )
49
121
}
50
122
123
+ /// Decides how to represent a given type.
51
124
pub fn represent_type ( cx : @CrateContext , t : ty:: t ) -> @Repr {
52
125
debug ! ( "Representing: %s" , ty_to_str( cx. tcx, t) ) ;
53
126
match cx. adt_reprs . find ( & t) {
@@ -56,18 +129,19 @@ pub fn represent_type(cx: @CrateContext, t: ty::t) -> @Repr {
56
129
}
57
130
let repr = @match ty:: get ( t) . sty {
58
131
ty:: ty_tup( ref elems) => {
59
- Univariant ( mk_struct ( cx, * elems) , NoDtor )
132
+ Univariant ( mk_struct ( cx, * elems) , NonStruct )
60
133
}
61
134
ty:: ty_rec( ref fields) => {
62
135
// 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 )
64
138
}
65
139
ty:: ty_struct( def_id, ref substs) => {
66
140
let fields = ty:: lookup_struct_fields ( cx. tcx , def_id) ;
67
141
let dt = ty:: ty_dtor ( cx. tcx , def_id) . is_present ( ) ;
68
142
Univariant ( mk_struct ( cx, fields. map ( |field| {
69
143
ty:: lookup_field_type ( cx. tcx , def_id, field. id , substs)
70
- } ) ) , if dt { DtorPresent } else { DtorAbsent } )
144
+ } ) ) , if dt { StructWithDtor } else { StructWithoutDtor } )
71
145
}
72
146
ty:: ty_enum( def_id, ref substs) => {
73
147
struct Case { discr : int , tys : ~[ ty:: t ] } ;
@@ -80,17 +154,22 @@ pub fn represent_type(cx: @CrateContext, t: ty::t) -> @Repr {
80
154
} ;
81
155
if cases. len ( ) == 0 {
82
156
// Uninhabitable; represent as unit
83
- Univariant ( mk_struct ( cx , ~ [ ] ) , NoDtor )
157
+ Unit ( 0 )
84
158
} else if cases. len ( ) == 1 && cases[ 0 ] . tys . len ( ) == 0 {
159
+ // `()`-like; see comment on definition of `Unit`.
85
160
Unit ( cases[ 0 ] . discr )
86
161
} else if cases. len ( ) == 1 {
87
- // struct, tuple, newtype, etc .
162
+ // Equivalent to a struct/tuple/newtype .
88
163
assert cases[ 0 ] . discr == 0 ;
89
- Univariant ( mk_struct ( cx, cases[ 0 ] . tys ) , NoDtor )
164
+ Univariant ( mk_struct ( cx, cases[ 0 ] . tys ) , NonStruct )
90
165
} else if cases. all ( |c| c. tys . len ( ) == 0 ) {
166
+ // All bodies empty -> intlike
91
167
let discrs = cases. map ( |c| c. discr ) ;
92
168
CEnum ( discrs. min ( ) , discrs. max ( ) )
93
169
} 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.
94
173
if !cases. alli ( |i, c| c. discr == ( i as int ) ) {
95
174
cx. sess . bug ( fmt ! ( "non-C-like enum %s with specified \
96
175
discriminants",
@@ -115,13 +194,18 @@ fn mk_struct(cx: @CrateContext, tys: &[ty::t]) -> Struct {
115
194
}
116
195
}
117
196
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
+ */
122
202
pub fn fields_of ( cx : @CrateContext , r : & Repr ) -> ~[ TypeRef ] {
123
203
generic_fields_of ( cx, r, false )
124
204
}
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
+ }
125
209
fn generic_fields_of ( cx : @CrateContext , r : & Repr , sizing : bool )
126
210
-> ~[ TypeRef ] {
127
211
match * r {
@@ -134,9 +218,9 @@ fn generic_fields_of(cx: @CrateContext, r: &Repr, sizing: bool)
134
218
st. fields . map ( |& ty| type_of:: type_of ( cx, ty) )
135
219
} ;
136
220
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 ( ) ]
140
224
}
141
225
}
142
226
General ( ref sts) => {
@@ -164,6 +248,10 @@ fn load_discr(bcx: block, scrutinee: ValueRef, min: int, max: int)
164
248
}
165
249
}
166
250
251
+ /**
252
+ * Obtain as much of a "discriminant" as this representation has.
253
+ * This should ideally be less tightly tied to `_match`.
254
+ */
167
255
pub fn trans_switch ( bcx : block , r : & Repr , scrutinee : ValueRef )
168
256
-> ( _match:: branch_kind , Option < ValueRef > ) {
169
257
match * r {
@@ -176,18 +264,29 @@ pub fn trans_switch(bcx: block, r: &Repr, scrutinee: ValueRef)
176
264
}
177
265
}
178
266
267
+ /**
268
+ * If the representation is potentially of a C-like enum, implement
269
+ * coercion to numeric types.
270
+ */
179
271
pub fn trans_cast_to_int ( bcx : block , r : & Repr , scrutinee : ValueRef )
180
272
-> ValueRef {
181
273
match * r {
182
274
Unit ( the_disc) => C_int ( bcx. ccx ( ) , the_disc) ,
183
275
CEnum ( min, max) => load_discr ( bcx, scrutinee, min, max) ,
184
276
Univariant ( * ) => bcx. ccx ( ) . sess . bug ( ~"type has no explicit \
185
277
discriminant") ,
278
+ // Note: this case is used internally by trans_switch,
279
+ // even though it shouldn't be reached by an external caller.
186
280
General ( ref cases) => load_discr ( bcx, scrutinee, 0 ,
187
281
( cases. len ( ) - 1 ) as int )
188
282
}
189
283
}
190
284
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
+ */
191
290
pub fn trans_case( bcx : block , r : & Repr , discr : int ) -> _match:: opt_result {
192
291
match * r {
193
292
CEnum ( * ) => {
@@ -202,6 +301,11 @@ pub fn trans_case(bcx: block, r: &Repr, discr: int) -> _match::opt_result {
202
301
}
203
302
}
204
303
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
+ */
205
309
pub fn trans_set_discr ( bcx : block , r : & Repr , val : ValueRef , discr : int ) {
206
310
match * r {
207
311
Unit ( the_discr) => {
@@ -211,7 +315,7 @@ pub fn trans_set_discr(bcx: block, r: &Repr, val: ValueRef, discr: int) {
211
315
assert min <= discr && discr <= max;
212
316
Store ( bcx, C_int ( bcx. ccx ( ) , discr) , GEPi ( bcx, val, [ 0 , 0 ] ) )
213
317
}
214
- Univariant ( _, DtorPresent ) => {
318
+ Univariant ( _, StructWithDtor ) => {
215
319
assert discr == 0 ;
216
320
Store ( bcx, C_u8 ( 1 ) , GEPi ( bcx, val, [ 0 , 1 ] ) )
217
321
}
@@ -224,6 +328,10 @@ pub fn trans_set_discr(bcx: block, r: &Repr, val: ValueRef, discr: int) {
224
328
}
225
329
}
226
330
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
+ */
227
335
pub fn num_args ( r : & Repr , discr : int ) -> uint {
228
336
match * r {
229
337
Unit ( * ) | CEnum ( * ) => 0 ,
@@ -232,20 +340,21 @@ pub fn num_args(r: &Repr, discr: int) -> uint {
232
340
}
233
341
}
234
342
343
+ /// Access a field, at a point when the value's case is known.
235
344
pub fn trans_GEP ( bcx : block , r : & Repr , val : ValueRef , discr : int , ix : uint )
236
345
-> ValueRef {
237
346
// Note: if this ever needs to generate conditionals (e.g., if we
238
347
// 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.
240
349
match * r {
241
350
Unit ( * ) | CEnum ( * ) => {
242
351
bcx. ccx ( ) . sess . bug ( ~"element access in C -like enum")
243
352
}
244
353
Univariant ( ref st, dt) => {
245
354
assert discr == 0 ;
246
355
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 ] )
249
358
} ;
250
359
struct_GEP ( bcx, st, val, ix, false )
251
360
}
@@ -271,14 +380,26 @@ fn struct_GEP(bcx: block, st: &Struct, val: ValueRef, ix: uint,
271
380
GEPi ( bcx, val, [ 0 , ix] )
272
381
}
273
382
383
+ /// Access the struct drop flag, if present.
274
384
pub fn trans_drop_flag_ptr ( bcx : block , r : & Repr , val : ValueRef ) -> ValueRef {
275
385
match * r {
276
- Univariant ( _, DtorPresent ) => GEPi ( bcx, val, [ 0 , 1 ] ) ,
386
+ Univariant ( _, StructWithDtor ) => GEPi ( bcx, val, [ 0 , 1 ] ) ,
277
387
_ => bcx. ccx ( ) . sess . bug ( ~"tried to get drop flag of non-droppable \
278
388
type ")
279
389
}
280
390
}
281
391
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
+ */
282
403
pub fn trans_const ( ccx : @CrateContext , r : & Repr , discr : int ,
283
404
vals : & [ ValueRef ] ) -> ValueRef {
284
405
match * r {
@@ -294,10 +415,10 @@ pub fn trans_const(ccx: @CrateContext, r: &Repr, discr: int,
294
415
assert discr == 0 ;
295
416
let s = C_struct ( build_const_struct ( ccx, st, vals) ) ;
296
417
match dt {
297
- NoDtor => s,
418
+ NonStruct => s,
298
419
// The actual destructor flag doesn't need to be present.
299
420
// But add an extra struct layer for compatibility.
300
- DtorPresent | DtorAbsent => C_struct ( ~[ s] )
421
+ StructWithDtor | StructWithoutDtor => C_struct ( ~[ s] )
301
422
}
302
423
}
303
424
General ( ref cases) => {
@@ -345,7 +466,7 @@ fn build_const_struct(ccx: @CrateContext, st: &Struct, vals: &[ValueRef])
345
466
#[ always_inline]
346
467
fn roundup ( x : u64 , a : u64 ) -> u64 { ( ( x + ( a - 1 ) ) / a) * a }
347
468
348
-
469
+ /// Get the discriminant of a constant value. (Not currently used.)
349
470
pub fn const_get_discrim ( ccx : @CrateContext , r : & Repr , val : ValueRef )
350
471
-> int {
351
472
match * r {
@@ -356,13 +477,14 @@ pub fn const_get_discrim(ccx: @CrateContext, r: &Repr, val: ValueRef)
356
477
}
357
478
}
358
479
480
+ /// Access a field of a constant value.
359
481
pub fn const_get_element ( ccx : @CrateContext , r : & Repr , val : ValueRef ,
360
482
_discr : int , ix : uint ) -> ValueRef {
361
483
// Not to be confused with common::const_get_elt.
362
484
match * r {
363
485
Unit ( * ) | CEnum ( * ) => ccx. sess . bug ( ~"element access in C -like enum \
364
486
const ") ,
365
- Univariant ( _, NoDtor ) => const_struct_field ( ccx, val, ix) ,
487
+ Univariant ( _, NonStruct ) => const_struct_field ( ccx, val, ix) ,
366
488
Univariant ( * ) => const_struct_field ( ccx, const_get_elt ( ccx, val,
367
489
[ 0 ] ) , ix) ,
368
490
General ( * ) => const_struct_field ( ccx, const_get_elt ( ccx, val,
@@ -395,8 +517,8 @@ fn const_struct_field(ccx: @CrateContext, val: ValueRef, ix: uint)
395
517
/// Is it safe to bitcast a value to the one field of its one variant?
396
518
pub fn is_newtypeish ( r : & Repr ) -> bool {
397
519
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 ,
400
522
_ => false
401
523
}
402
524
}
0 commit comments