Skip to content

Commit 1489639

Browse files
committed
Add lots of comments to adt.rs, and some minor cleanup.
1 parent 5565f5f commit 1489639

File tree

1 file changed

+149
-27
lines changed
  • src/librustc/middle/trans

1 file changed

+149
-27
lines changed

src/librustc/middle/trans/adt.rs

Lines changed: 149 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,55 @@
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::libc::c_ulonglong;
1257
use core::option::{Option, Some, None};
1358
use core::vec;
59+
1460
use lib::llvm::{ValueRef, TypeRef, True, False};
1561
use middle::trans::_match;
1662
use middle::trans::build::*;
@@ -22,31 +68,58 @@ use syntax::ast;
2268
use util::ppaux::ty_to_str;
2369

2470

25-
// XXX: should this be done with boxed traits instead of ML-style?
71+
/// Representations.
2672
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+
*/
2780
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.
2984
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+
*/
3091
General(~[Struct])
3192
}
3293

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+
*/
33100
enum Destructor {
34-
DtorPresent,
35-
DtorAbsent,
36-
NoDtor
101+
StructWithDtor,
102+
StructWithoutDtor,
103+
NonStruct
37104
}
38105

106+
/// For structs, and struct-like parts of anything fancier.
39107
struct Struct {
40108
size: u64,
41109
align: u64,
42110
fields: ~[ty::t]
43111
}
44112

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+
*/
46118
pub fn represent_node(bcx: block, node: ast::node_id) -> @Repr {
47119
represent_type(bcx.ccx(), node_id_type(bcx, node))
48120
}
49121

122+
/// Decides how to represent a given type.
50123
pub fn represent_type(cx: @CrateContext, t: ty::t) -> @Repr {
51124
debug!("Representing: %s", ty_to_str(cx.tcx, t));
52125
match cx.adt_reprs.find(&t) {
@@ -55,18 +128,19 @@ pub fn represent_type(cx: @CrateContext, t: ty::t) -> @Repr {
55128
}
56129
let repr = @match ty::get(t).sty {
57130
ty::ty_tup(ref elems) => {
58-
Univariant(mk_struct(cx, *elems), NoDtor)
131+
Univariant(mk_struct(cx, *elems), NonStruct)
59132
}
60133
ty::ty_rec(ref fields) => {
61134
// 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)
63137
}
64138
ty::ty_struct(def_id, ref substs) => {
65139
let fields = ty::lookup_struct_fields(cx.tcx, def_id);
66140
let dt = ty::ty_dtor(cx.tcx, def_id).is_present();
67141
Univariant(mk_struct(cx, fields.map(|field| {
68142
ty::lookup_field_type(cx.tcx, def_id, field.id, substs)
69-
})), if dt { DtorPresent } else { DtorAbsent })
143+
})), if dt { StructWithDtor } else { StructWithoutDtor })
70144
}
71145
ty::ty_enum(def_id, ref substs) => {
72146
struct Case { discr: int, tys: ~[ty::t] };
@@ -79,17 +153,22 @@ pub fn represent_type(cx: @CrateContext, t: ty::t) -> @Repr {
79153
};
80154
if cases.len() == 0 {
81155
// Uninhabitable; represent as unit
82-
Univariant(mk_struct(cx, ~[]), NoDtor)
156+
Unit(0)
83157
} else if cases.len() == 1 && cases[0].tys.len() == 0 {
158+
// `()`-like; see comment on definition of `Unit`.
84159
Unit(cases[0].discr)
85160
} else if cases.len() == 1 {
86-
// struct, tuple, newtype, etc.
161+
// Equivalent to a struct/tuple/newtype.
87162
assert cases[0].discr == 0;
88-
Univariant(mk_struct(cx, cases[0].tys), NoDtor)
163+
Univariant(mk_struct(cx, cases[0].tys), NonStruct)
89164
} else if cases.all(|c| c.tys.len() == 0) {
165+
// All bodies empty -> intlike
90166
let discrs = cases.map(|c| c.discr);
91167
CEnum(discrs.min(), discrs.max())
92168
} 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.
93172
if !cases.alli(|i,c| c.discr == (i as int)) {
94173
cx.sess.bug(fmt!("non-C-like enum %s with specified \
95174
discriminants",
@@ -114,13 +193,18 @@ fn mk_struct(cx: @CrateContext, tys: &[ty::t]) -> Struct {
114193
}
115194
}
116195

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+
*/
121201
pub fn fields_of(cx: @CrateContext, r: &Repr) -> ~[TypeRef] {
122202
generic_fields_of(cx, r, false)
123203
}
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+
}
124208
fn generic_fields_of(cx: @CrateContext, r: &Repr, sizing: bool)
125209
-> ~[TypeRef] {
126210
match *r {
@@ -133,9 +217,9 @@ fn generic_fields_of(cx: @CrateContext, r: &Repr, sizing: bool)
133217
st.fields.map(|&ty| type_of::type_of(cx, ty))
134218
};
135219
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()]
139223
}
140224
}
141225
General(ref sts) => {
@@ -163,6 +247,10 @@ fn load_discr(bcx: block, scrutinee: ValueRef, min: int, max: int)
163247
}
164248
}
165249

250+
/**
251+
* Obtain as much of a "discriminant" as this representation has.
252+
* This should ideally be less tightly tied to `_match`.
253+
*/
166254
pub fn trans_switch(bcx: block, r: &Repr, scrutinee: ValueRef)
167255
-> (_match::branch_kind, Option<ValueRef>) {
168256
match *r {
@@ -175,18 +263,29 @@ pub fn trans_switch(bcx: block, r: &Repr, scrutinee: ValueRef)
175263
}
176264
}
177265

266+
/**
267+
* If the representation is potentially of a C-like enum, implement
268+
* coercion to numeric types.
269+
*/
178270
pub fn trans_cast_to_int(bcx: block, r: &Repr, scrutinee: ValueRef)
179271
-> ValueRef {
180272
match *r {
181273
Unit(the_disc) => C_int(bcx.ccx(), the_disc),
182274
CEnum(min, max) => load_discr(bcx, scrutinee, min, max),
183275
Univariant(*) => bcx.ccx().sess.bug(~"type has no explicit \
184276
discriminant"),
277+
// Note: this case is used internally by trans_switch,
278+
// even though it shouldn't be reached by an external caller.
185279
General(ref cases) => load_discr(bcx, scrutinee, 0,
186280
(cases.len() - 1) as int)
187281
}
188282
}
189283

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+
*/
190289
pub fn trans_case(bcx: block, r: &Repr, discr: int) -> _match::opt_result {
191290
match *r {
192291
CEnum(*) => {
@@ -201,6 +300,11 @@ pub fn trans_case(bcx: block, r: &Repr, discr: int) -> _match::opt_result {
201300
}
202301
}
203302

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+
*/
204308
pub fn trans_set_discr(bcx: block, r: &Repr, val: ValueRef, discr: int) {
205309
match *r {
206310
Unit(the_discr) => {
@@ -210,7 +314,7 @@ pub fn trans_set_discr(bcx: block, r: &Repr, val: ValueRef, discr: int) {
210314
assert min <= discr && discr <= max;
211315
Store(bcx, C_int(bcx.ccx(), discr), GEPi(bcx, val, [0, 0]))
212316
}
213-
Univariant(_, DtorPresent) => {
317+
Univariant(_, StructWithDtor) => {
214318
assert discr == 0;
215319
Store(bcx, C_u8(1), GEPi(bcx, val, [0, 1]))
216320
}
@@ -223,6 +327,10 @@ pub fn trans_set_discr(bcx: block, r: &Repr, val: ValueRef, discr: int) {
223327
}
224328
}
225329

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+
*/
226334
pub fn num_args(r: &Repr, discr: int) -> uint {
227335
match *r {
228336
Unit(*) | CEnum(*) => 0,
@@ -231,20 +339,21 @@ pub fn num_args(r: &Repr, discr: int) -> uint {
231339
}
232340
}
233341

342+
/// Access a field, at a point when the value's case is known.
234343
pub fn trans_GEP(bcx: block, r: &Repr, val: ValueRef, discr: int, ix: uint)
235344
-> ValueRef {
236345
// Note: if this ever needs to generate conditionals (e.g., if we
237346
// 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.
239348
match *r {
240349
Unit(*) | CEnum(*) => {
241350
bcx.ccx().sess.bug(~"element access in C-like enum")
242351
}
243352
Univariant(ref st, dt) => {
244353
assert discr == 0;
245354
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])
248357
};
249358
struct_GEP(bcx, st, val, ix, false)
250359
}
@@ -270,14 +379,26 @@ fn struct_GEP(bcx: block, st: &Struct, val: ValueRef, ix: uint,
270379
GEPi(bcx, val, [0, ix])
271380
}
272381

382+
/// Access the struct drop flag, if present.
273383
pub fn trans_drop_flag_ptr(bcx: block, r: &Repr, val: ValueRef) -> ValueRef {
274384
match *r {
275-
Univariant(_, DtorPresent) => GEPi(bcx, val, [0, 1]),
385+
Univariant(_, StructWithDtor) => GEPi(bcx, val, [0, 1]),
276386
_ => bcx.ccx().sess.bug(~"tried to get drop flag of non-droppable \
277387
type")
278388
}
279389
}
280390

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+
*/
281402
pub fn trans_const(ccx: @CrateContext, r: &Repr, discr: int,
282403
vals: &[ValueRef]) -> ValueRef {
283404
match *r {
@@ -339,7 +460,7 @@ fn build_const_struct(ccx: @CrateContext, st: &Struct, vals: &[ValueRef])
339460
#[always_inline]
340461
fn roundup(x: u64, a: u64) -> u64 { ((x + (a - 1)) / a) * a }
341462

342-
463+
/// Get the discriminant of a constant value. (Not currently used.)
343464
pub fn const_get_discrim(ccx: @CrateContext, r: &Repr, val: ValueRef)
344465
-> int {
345466
match *r {
@@ -350,6 +471,7 @@ pub fn const_get_discrim(ccx: @CrateContext, r: &Repr, val: ValueRef)
350471
}
351472
}
352473

474+
/// Access a field of a constant value.
353475
pub fn const_get_element(ccx: @CrateContext, r: &Repr, val: ValueRef,
354476
_discr: int, ix: uint) -> ValueRef {
355477
// Not to be confused with common::const_get_elt.
@@ -387,8 +509,8 @@ fn const_struct_field(ccx: @CrateContext, val: ValueRef, ix: uint)
387509
/// Is it safe to bitcast a value to the one field of its one variant?
388510
pub fn is_newtypeish(r: &Repr) -> bool {
389511
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,
392514
_ => false
393515
}
394516
}

0 commit comments

Comments
 (0)