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:: libc:: c_ulonglong;
12
57
use core:: option:: { Option , Some , None } ;
13
58
use core:: vec;
59
+
14
60
use lib:: llvm:: { ValueRef , TypeRef , True , False } ;
15
61
use middle:: trans:: _match;
16
62
use middle:: trans:: build:: * ;
@@ -22,31 +68,58 @@ use syntax::ast;
22
68
use util:: ppaux:: ty_to_str;
23
69
24
70
25
- // XXX: should this be done with boxed traits instead of ML-style?
71
+ /// Representations.
26
72
pub enum Repr {
73
+ /**
74
+ * `Unit` exists only so that an enum with a single C-like variant
75
+ * can occupy no space, for ABI compatibility with rustc from
76
+ * before (and during) the creation of this module. It may not be
77
+ * worth keeping around; `CEnum` and `Univariant` cover it
78
+ * overwise.
79
+ */
27
80
Unit ( int ) ,
28
- CEnum ( int , int ) , /* discriminant range */
81
+ /// C-like enums; basically an int.
82
+ CEnum ( int , int ) , // discriminant range
83
+ /// Single-case variants, and structs/tuples/records.
29
84
Univariant ( Struct , Destructor ) ,
85
+ /**
86
+ * General-case enums: discriminant as int, followed by fields.
87
+ * The fields start immediately after the discriminant, meaning
88
+ * that they may not be correctly aligned for the platform's ABI;
89
+ * see above.
90
+ */
30
91
General ( ~[ Struct ] )
31
92
}
32
93
94
+ /**
95
+ * Structs without destructors have historically had an extra layer of
96
+ * LLVM-struct to make accessing them work the same as structs with
97
+ * destructors. This could probably be flattened to a boolean now
98
+ * that this module exists.
99
+ */
33
100
enum Destructor {
34
- DtorPresent ,
35
- DtorAbsent ,
36
- NoDtor
101
+ StructWithDtor ,
102
+ StructWithoutDtor ,
103
+ NonStruct
37
104
}
38
105
106
+ /// For structs, and struct-like parts of anything fancier.
39
107
struct Struct {
40
108
size : u64 ,
41
109
align : u64 ,
42
110
fields : ~[ ty:: t ]
43
111
}
44
112
45
-
113
+ /**
114
+ * Convenience for `represent_type`. There should probably be more or
115
+ * these, for places in trans where the `ty::t` isn't directly
116
+ * available.
117
+ */
46
118
pub fn represent_node ( bcx : block , node : ast:: node_id ) -> @Repr {
47
119
represent_type ( bcx. ccx ( ) , node_id_type ( bcx, node) )
48
120
}
49
121
122
+ /// Decides how to represent a given type.
50
123
pub fn represent_type ( cx : @CrateContext , t : ty:: t ) -> @Repr {
51
124
debug ! ( "Representing: %s" , ty_to_str( cx. tcx, t) ) ;
52
125
match cx. adt_reprs . find ( & t) {
@@ -55,18 +128,19 @@ pub fn represent_type(cx: @CrateContext, t: ty::t) -> @Repr {
55
128
}
56
129
let repr = @match ty:: get ( t) . sty {
57
130
ty:: ty_tup( ref elems) => {
58
- Univariant ( mk_struct ( cx, * elems) , NoDtor )
131
+ Univariant ( mk_struct ( cx, * elems) , NonStruct )
59
132
}
60
133
ty:: ty_rec( ref fields) => {
61
134
// XXX: Are these in the right order?
62
- Univariant ( mk_struct ( cx, fields. map ( |f| f. mt . ty ) ) , DtorAbsent )
135
+ Univariant ( mk_struct ( cx, fields. map ( |f| f. mt . ty ) ) ,
136
+ StructWithoutDtor )
63
137
}
64
138
ty:: ty_struct( def_id, ref substs) => {
65
139
let fields = ty:: lookup_struct_fields ( cx. tcx , def_id) ;
66
140
let dt = ty:: ty_dtor ( cx. tcx , def_id) . is_present ( ) ;
67
141
Univariant ( mk_struct ( cx, fields. map ( |field| {
68
142
ty:: lookup_field_type ( cx. tcx , def_id, field. id , substs)
69
- } ) ) , if dt { DtorPresent } else { DtorAbsent } )
143
+ } ) ) , if dt { StructWithDtor } else { StructWithoutDtor } )
70
144
}
71
145
ty:: ty_enum( def_id, ref substs) => {
72
146
struct Case { discr : int , tys : ~[ ty:: t ] } ;
@@ -79,17 +153,22 @@ pub fn represent_type(cx: @CrateContext, t: ty::t) -> @Repr {
79
153
} ;
80
154
if cases. len ( ) == 0 {
81
155
// Uninhabitable; represent as unit
82
- Univariant ( mk_struct ( cx , ~ [ ] ) , NoDtor )
156
+ Unit ( 0 )
83
157
} else if cases. len ( ) == 1 && cases[ 0 ] . tys . len ( ) == 0 {
158
+ // `()`-like; see comment on definition of `Unit`.
84
159
Unit ( cases[ 0 ] . discr )
85
160
} else if cases. len ( ) == 1 {
86
- // struct, tuple, newtype, etc .
161
+ // Equivalent to a struct/tuple/newtype .
87
162
assert cases[ 0 ] . discr == 0 ;
88
- Univariant ( mk_struct ( cx, cases[ 0 ] . tys ) , NoDtor )
163
+ Univariant ( mk_struct ( cx, cases[ 0 ] . tys ) , NonStruct )
89
164
} else if cases. all ( |c| c. tys . len ( ) == 0 ) {
165
+ // All bodies empty -> intlike
90
166
let discrs = cases. map ( |c| c. discr ) ;
91
167
CEnum ( discrs. min ( ) , discrs. max ( ) )
92
168
} else {
169
+ // The general case. Since there's at least one
170
+ // non-empty body, explicit discriminants should have
171
+ // been rejected by a checker before this point.
93
172
if !cases. alli ( |i, c| c. discr == ( i as int ) ) {
94
173
cx. sess . bug ( fmt ! ( "non-C-like enum %s with specified \
95
174
discriminants",
@@ -114,13 +193,18 @@ fn mk_struct(cx: @CrateContext, tys: &[ty::t]) -> Struct {
114
193
}
115
194
}
116
195
117
-
118
- pub fn sizing_fields_of ( cx : @CrateContext , r : & Repr ) -> ~[ TypeRef ] {
119
- generic_fields_of ( cx, r, true )
120
- }
196
+ /**
197
+ * Returns the fields of a struct for the given representation.
198
+ * All nominal types are LLVM structs, in order to be able to use
199
+ * forward-declared opaque types to prevent circularity in `type_of`.
200
+ */
121
201
pub fn fields_of ( cx : @CrateContext , r : & Repr ) -> ~[ TypeRef ] {
122
202
generic_fields_of ( cx, r, false )
123
203
}
204
+ /// Like `fields_of`, but for `type_of::sizing_type_of` (q.v.).
205
+ pub fn sizing_fields_of ( cx : @CrateContext , r : & Repr ) -> ~[ TypeRef ] {
206
+ generic_fields_of ( cx, r, true )
207
+ }
124
208
fn generic_fields_of ( cx : @CrateContext , r : & Repr , sizing : bool )
125
209
-> ~[ TypeRef ] {
126
210
match * r {
@@ -133,9 +217,9 @@ fn generic_fields_of(cx: @CrateContext, r: &Repr, sizing: bool)
133
217
st. fields . map ( |& ty| type_of:: type_of ( cx, ty) )
134
218
} ;
135
219
match dt {
136
- NoDtor => f,
137
- DtorAbsent => ~[ T_struct ( f) ] ,
138
- DtorPresent => ~[ T_struct ( f) , T_i8 ( ) ]
220
+ NonStruct => f,
221
+ StructWithoutDtor => ~[ T_struct ( f) ] ,
222
+ StructWithDtor => ~[ T_struct ( f) , T_i8 ( ) ]
139
223
}
140
224
}
141
225
General ( ref sts) => {
@@ -163,6 +247,10 @@ fn load_discr(bcx: block, scrutinee: ValueRef, min: int, max: int)
163
247
}
164
248
}
165
249
250
+ /**
251
+ * Obtain as much of a "discriminant" as this representation has.
252
+ * This should ideally be less tightly tied to `_match`.
253
+ */
166
254
pub fn trans_switch ( bcx : block , r : & Repr , scrutinee : ValueRef )
167
255
-> ( _match:: branch_kind , Option < ValueRef > ) {
168
256
match * r {
@@ -175,18 +263,29 @@ pub fn trans_switch(bcx: block, r: &Repr, scrutinee: ValueRef)
175
263
}
176
264
}
177
265
266
+ /**
267
+ * If the representation is potentially of a C-like enum, implement
268
+ * coercion to numeric types.
269
+ */
178
270
pub fn trans_cast_to_int ( bcx : block , r : & Repr , scrutinee : ValueRef )
179
271
-> ValueRef {
180
272
match * r {
181
273
Unit ( the_disc) => C_int ( bcx. ccx ( ) , the_disc) ,
182
274
CEnum ( min, max) => load_discr ( bcx, scrutinee, min, max) ,
183
275
Univariant ( * ) => bcx. ccx ( ) . sess . bug ( ~"type has no explicit \
184
276
discriminant") ,
277
+ // Note: this case is used internally by trans_switch,
278
+ // even though it shouldn't be reached by an external caller.
185
279
General ( ref cases) => load_discr ( bcx, scrutinee, 0 ,
186
280
( cases. len ( ) - 1 ) as int )
187
281
}
188
282
}
189
283
284
+ /**
285
+ * Yield information about how to dispatch a case of the
286
+ * discriminant-like value returned by `trans_switch`.
287
+ * This should ideally be less tightly tied to `_match`.
288
+ */
190
289
pub fn trans_case( bcx : block , r : & Repr , discr : int ) -> _match:: opt_result {
191
290
match * r {
192
291
CEnum ( * ) => {
@@ -201,6 +300,11 @@ pub fn trans_case(bcx: block, r: &Repr, discr: int) -> _match::opt_result {
201
300
}
202
301
}
203
302
303
+ /**
304
+ * Begin initializing a new value of the given case of the given
305
+ * representation. The fields should then be initialized with
306
+ * `trans_GEP` and stores.
307
+ */
204
308
pub fn trans_set_discr ( bcx : block , r : & Repr , val : ValueRef , discr : int ) {
205
309
match * r {
206
310
Unit ( the_discr) => {
@@ -210,7 +314,7 @@ pub fn trans_set_discr(bcx: block, r: &Repr, val: ValueRef, discr: int) {
210
314
assert min <= discr && discr <= max;
211
315
Store ( bcx, C_int ( bcx. ccx ( ) , discr) , GEPi ( bcx, val, [ 0 , 0 ] ) )
212
316
}
213
- Univariant ( _, DtorPresent ) => {
317
+ Univariant ( _, StructWithDtor ) => {
214
318
assert discr == 0 ;
215
319
Store ( bcx, C_u8 ( 1 ) , GEPi ( bcx, val, [ 0 , 1 ] ) )
216
320
}
@@ -223,6 +327,10 @@ pub fn trans_set_discr(bcx: block, r: &Repr, val: ValueRef, discr: int) {
223
327
}
224
328
}
225
329
330
+ /**
331
+ * The number of fields in a given case; for use when obtaining this
332
+ * information from the type or definition is less convenient.
333
+ */
226
334
pub fn num_args ( r : & Repr , discr : int ) -> uint {
227
335
match * r {
228
336
Unit ( * ) | CEnum ( * ) => 0 ,
@@ -231,20 +339,21 @@ pub fn num_args(r: &Repr, discr: int) -> uint {
231
339
}
232
340
}
233
341
342
+ /// Access a field, at a point when the value's case is known.
234
343
pub fn trans_GEP ( bcx : block , r : & Repr , val : ValueRef , discr : int , ix : uint )
235
344
-> ValueRef {
236
345
// Note: if this ever needs to generate conditionals (e.g., if we
237
346
// decide to do some kind of cdr-coding-like non-unique repr
238
- // someday), it'll need to return a possibly-new bcx as well.
347
+ // someday), it will need to return a possibly-new bcx as well.
239
348
match * r {
240
349
Unit ( * ) | CEnum ( * ) => {
241
350
bcx. ccx ( ) . sess . bug ( ~"element access in C -like enum")
242
351
}
243
352
Univariant ( ref st, dt) => {
244
353
assert discr == 0 ;
245
354
let val = match dt {
246
- NoDtor => val,
247
- DtorPresent | DtorAbsent => GEPi ( bcx, val, [ 0 , 0 ] )
355
+ NonStruct => val,
356
+ StructWithDtor | StructWithoutDtor => GEPi ( bcx, val, [ 0 , 0 ] )
248
357
} ;
249
358
struct_GEP ( bcx, st, val, ix, false )
250
359
}
@@ -270,14 +379,26 @@ fn struct_GEP(bcx: block, st: &Struct, val: ValueRef, ix: uint,
270
379
GEPi ( bcx, val, [ 0 , ix] )
271
380
}
272
381
382
+ /// Access the struct drop flag, if present.
273
383
pub fn trans_drop_flag_ptr ( bcx : block , r : & Repr , val : ValueRef ) -> ValueRef {
274
384
match * r {
275
- Univariant ( _, DtorPresent ) => GEPi ( bcx, val, [ 0 , 1 ] ) ,
385
+ Univariant ( _, StructWithDtor ) => GEPi ( bcx, val, [ 0 , 1 ] ) ,
276
386
_ => bcx. ccx ( ) . sess . bug ( ~"tried to get drop flag of non-droppable \
277
387
type ")
278
388
}
279
389
}
280
390
391
+ /**
392
+ * Construct a constant value, suitable for initializing a
393
+ * GlobalVariable, given a case and constant values for its fields.
394
+ * Note that this may have a different LLVM type (and different
395
+ * alignment!) from the representation's `type_of`, so it needs a
396
+ * pointer cast before use.
397
+ *
398
+ * Currently it has the same size as the type, but this may be changed
399
+ * in the future to avoid allocating unnecessary space after values of
400
+ * shorter-than-maximum cases.
401
+ */
281
402
pub fn trans_const ( ccx : @CrateContext , r : & Repr , discr : int ,
282
403
vals : & [ ValueRef ] ) -> ValueRef {
283
404
match * r {
@@ -339,7 +460,7 @@ fn build_const_struct(ccx: @CrateContext, st: &Struct, vals: &[ValueRef])
339
460
#[ always_inline]
340
461
fn roundup ( x : u64 , a : u64 ) -> u64 { ( ( x + ( a - 1 ) ) / a) * a }
341
462
342
-
463
+ /// Get the discriminant of a constant value. (Not currently used.)
343
464
pub fn const_get_discrim ( ccx : @CrateContext , r : & Repr , val : ValueRef )
344
465
-> int {
345
466
match * r {
@@ -350,6 +471,7 @@ pub fn const_get_discrim(ccx: @CrateContext, r: &Repr, val: ValueRef)
350
471
}
351
472
}
352
473
474
+ /// Access a field of a constant value.
353
475
pub fn const_get_element( ccx : @CrateContext , r : & Repr , val : ValueRef ,
354
476
_discr : int , ix : uint ) -> ValueRef {
355
477
// Not to be confused with common::const_get_elt.
@@ -387,8 +509,8 @@ fn const_struct_field(ccx: @CrateContext, val: ValueRef, ix: uint)
387
509
/// Is it safe to bitcast a value to the one field of its one variant?
388
510
pub fn is_newtypeish( r: & Repr ) -> bool {
389
511
match * r {
390
- Univariant ( ref st, DtorAbsent )
391
- | Univariant ( ref st, NoDtor ) => st. fields . len ( ) == 1 ,
512
+ Univariant ( ref st, StructWithoutDtor )
513
+ | Univariant ( ref st, NonStruct ) => st. fields . len ( ) == 1 ,
392
514
_ => false
393
515
}
394
516
}
0 commit comments