Skip to content

Commit d6acb96

Browse files
committed
Add lots of comments to adt.rs, and some minor cleanup.
1 parent a9026c7 commit d6acb96

File tree

1 file changed

+152
-30
lines changed
  • src/librustc/middle/trans

1 file changed

+152
-30
lines changed

src/librustc/middle/trans/adt.rs

Lines changed: 152 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,56 @@
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+
1156
use core::container::Map;
1257
use core::libc::c_ulonglong;
1358
use core::option::{Option, Some, None};
1459
use core::vec;
60+
1561
use lib::llvm::{ValueRef, TypeRef, True, False};
1662
use middle::trans::_match;
1763
use middle::trans::build::*;
@@ -23,31 +69,58 @@ use syntax::ast;
2369
use util::ppaux::ty_to_str;
2470

2571

26-
// XXX: should this be done with boxed traits instead of ML-style?
72+
/// Representations.
2773
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+
*/
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+
*/
34101
enum 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.
40108
struct 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+
*/
47119
pub 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.
51124
pub 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+
*/
122202
pub 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+
}
125209
fn 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+
*/
167255
pub 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+
*/
179271
pub 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+
*/
191290
pub 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+
*/
205309
pub 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+
*/
227335
pub 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.
235344
pub 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.
274384
pub 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+
*/
282403
pub 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]
346467
fn roundup(x: u64, a: u64) -> u64 { ((x + (a - 1)) / a) * a }
347468

348-
469+
/// Get the discriminant of a constant value. (Not currently used.)
349470
pub 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.
359481
pub 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?
396518
pub 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

Comments
 (0)