]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/trans/adt.rs
librustc: Don't use the same alloca for match binding which we reassign to in arm...
[rust.git] / src / librustc / middle / trans / adt.rs
1 // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 /*!
12  * # Representation of Algebraic Data Types
13  *
14  * This module determines how to represent enums, structs, and tuples
15  * based on their monomorphized types; it is responsible both for
16  * choosing a representation and translating basic operations on
17  * values of those types.  (Note: exporting the representations for
18  * debuggers is handled in debuginfo.rs, not here.)
19  *
20  * Note that the interface treats everything as a general case of an
21  * enum, so structs/tuples/etc. have one pseudo-variant with
22  * discriminant 0; i.e., as if they were a univariant enum.
23  *
24  * Having everything in one place will enable improvements to data
25  * structure representation; possibilities include:
26  *
27  * - User-specified alignment (e.g., cacheline-aligning parts of
28  *   concurrently accessed data structures); LLVM can't represent this
29  *   directly, so we'd have to insert padding fields in any structure
30  *   that might contain one and adjust GEP indices accordingly.  See
31  *   issue #4578.
32  *
33  * - Store nested enums' discriminants in the same word.  Rather, if
34  *   some variants start with enums, and those enums representations
35  *   have unused alignment padding between discriminant and body, the
36  *   outer enum's discriminant can be stored there and those variants
37  *   can start at offset 0.  Kind of fancy, and might need work to
38  *   make copies of the inner enum type cooperate, but it could help
39  *   with `Option` or `Result` wrapped around another enum.
40  *
41  * - Tagged pointers would be neat, but given that any type can be
42  *   used unboxed and any field can have pointers (including mutable)
43  *   taken to it, implementing them for Rust seems difficult.
44  */
45
46 #![allow(unsigned_negate)]
47
48 use libc::c_ulonglong;
49 use std::rc::Rc;
50
51 use llvm::{ValueRef, True, IntEQ, IntNE};
52 use middle::subst;
53 use middle::subst::Subst;
54 use middle::trans::_match;
55 use middle::trans::build::*;
56 use middle::trans::cleanup;
57 use middle::trans::cleanup::CleanupMethods;
58 use middle::trans::common::*;
59 use middle::trans::datum;
60 use middle::trans::machine;
61 use middle::trans::type_::Type;
62 use middle::trans::type_of;
63 use middle::ty;
64 use middle::ty::Disr;
65 use syntax::abi::{X86, X86_64, Arm, Mips, Mipsel};
66 use syntax::ast;
67 use syntax::attr;
68 use syntax::attr::IntType;
69 use util::ppaux::ty_to_string;
70
71 type Hint = attr::ReprAttr;
72
73
74 /// Representations.
75 pub enum Repr {
76     /// C-like enums; basically an int.
77     CEnum(IntType, Disr, Disr), // discriminant range (signedness based on the IntType)
78     /**
79      * Single-case variants, and structs/tuples/records.
80      *
81      * Structs with destructors need a dynamic destroyedness flag to
82      * avoid running the destructor too many times; this is included
83      * in the `Struct` if present.
84      */
85     Univariant(Struct, bool),
86     /**
87      * General-case enums: for each case there is a struct, and they
88      * all start with a field for the discriminant.
89      *
90      * Types with destructors need a dynamic destroyedness flag to
91      * avoid running the destructor too many times; the last argument
92      * indicates whether such a flag is present.
93      */
94     General(IntType, Vec<Struct>, bool),
95     /**
96      * Two cases distinguished by a nullable pointer: the case with discriminant
97      * `nndiscr` must have single field which is known to be nonnull due to its type.
98      * The other case is known to be zero sized. Hence we represent the enum
99      * as simply a nullable pointer: if not null it indicates the `nndiscr` variant,
100      * otherwise it indicates the other case.
101      */
102     RawNullablePointer {
103         pub nndiscr: Disr,
104         pub nnty: ty::t,
105         pub nullfields: Vec<ty::t>
106     },
107     /**
108      * Two cases distinguished by a nullable pointer: the case with discriminant
109      * `nndiscr` is represented by the struct `nonnull`, where the `ptrfield`th
110      * field is known to be nonnull due to its type; if that field is null, then
111      * it represents the other case, which is inhabited by at most one value
112      * (and all other fields are undefined/unused).
113      *
114      * For example, `std::option::Option` instantiated at a safe pointer type
115      * is represented such that `None` is a null pointer and `Some` is the
116      * identity function.
117      */
118     StructWrappedNullablePointer {
119         pub nonnull: Struct,
120         pub nndiscr: Disr,
121         pub ptrfield: PointerField,
122         pub nullfields: Vec<ty::t>,
123     }
124 }
125
126 /// For structs, and struct-like parts of anything fancier.
127 pub struct Struct {
128     pub size: u64,
129     pub align: u64,
130     pub packed: bool,
131     pub fields: Vec<ty::t>
132 }
133
134 /**
135  * Convenience for `represent_type`.  There should probably be more or
136  * these, for places in trans where the `ty::t` isn't directly
137  * available.
138  */
139 pub fn represent_node(bcx: &Block, node: ast::NodeId) -> Rc<Repr> {
140     represent_type(bcx.ccx(), node_id_type(bcx, node))
141 }
142
143 /// Decides how to represent a given type.
144 pub fn represent_type(cx: &CrateContext, t: ty::t) -> Rc<Repr> {
145     debug!("Representing: {}", ty_to_string(cx.tcx(), t));
146     match cx.adt_reprs.borrow().find(&t) {
147         Some(repr) => return repr.clone(),
148         None => {}
149     }
150
151     let repr = Rc::new(represent_type_uncached(cx, t));
152     debug!("Represented as: {:?}", repr)
153     cx.adt_reprs.borrow_mut().insert(t, repr.clone());
154     repr
155 }
156
157 fn represent_type_uncached(cx: &CrateContext, t: ty::t) -> Repr {
158     match ty::get(t).sty {
159         ty::ty_tup(ref elems) => {
160             return Univariant(mk_struct(cx, elems.as_slice(), false), false)
161         }
162         ty::ty_struct(def_id, ref substs) => {
163             let fields = ty::lookup_struct_fields(cx.tcx(), def_id);
164             let mut ftys = fields.iter().map(|field| {
165                 ty::lookup_field_type(cx.tcx(), def_id, field.id, substs)
166             }).collect::<Vec<_>>();
167             let packed = ty::lookup_packed(cx.tcx(), def_id);
168             let dtor = ty::ty_dtor(cx.tcx(), def_id).has_drop_flag();
169             if dtor { ftys.push(ty::mk_bool()); }
170
171             return Univariant(mk_struct(cx, ftys.as_slice(), packed), dtor)
172         }
173         ty::ty_unboxed_closure(def_id) => {
174             let upvars = ty::unboxed_closure_upvars(cx.tcx(), def_id);
175             let upvar_types = upvars.iter().map(|u| u.ty).collect::<Vec<_>>();
176             return Univariant(mk_struct(cx, upvar_types.as_slice(), false),
177                               false)
178         }
179         ty::ty_enum(def_id, ref substs) => {
180             let cases = get_cases(cx.tcx(), def_id, substs);
181             let hint = ty::lookup_repr_hint(cx.tcx(), def_id);
182
183             let dtor = ty::ty_dtor(cx.tcx(), def_id).has_drop_flag();
184
185             if cases.len() == 0 {
186                 // Uninhabitable; represent as unit
187                 // (Typechecking will reject discriminant-sizing attrs.)
188                 assert_eq!(hint, attr::ReprAny);
189                 let ftys = if dtor { vec!(ty::mk_bool()) } else { vec!() };
190                 return Univariant(mk_struct(cx, ftys.as_slice(), false), dtor);
191             }
192
193             if !dtor && cases.iter().all(|c| c.tys.len() == 0) {
194                 // All bodies empty -> intlike
195                 let discrs: Vec<u64> = cases.iter().map(|c| c.discr).collect();
196                 let bounds = IntBounds {
197                     ulo: *discrs.iter().min().unwrap(),
198                     uhi: *discrs.iter().max().unwrap(),
199                     slo: discrs.iter().map(|n| *n as i64).min().unwrap(),
200                     shi: discrs.iter().map(|n| *n as i64).max().unwrap()
201                 };
202                 return mk_cenum(cx, hint, &bounds);
203             }
204
205             // Since there's at least one
206             // non-empty body, explicit discriminants should have
207             // been rejected by a checker before this point.
208             if !cases.iter().enumerate().all(|(i,c)| c.discr == (i as Disr)) {
209                 cx.sess().bug(format!("non-C-like enum {} with specified \
210                                       discriminants",
211                                       ty::item_path_str(cx.tcx(),
212                                                         def_id)).as_slice());
213             }
214
215             if cases.len() == 1 {
216                 // Equivalent to a struct/tuple/newtype.
217                 // (Typechecking will reject discriminant-sizing attrs.)
218                 assert_eq!(hint, attr::ReprAny);
219                 let mut ftys = cases.get(0).tys.clone();
220                 if dtor { ftys.push(ty::mk_bool()); }
221                 return Univariant(mk_struct(cx, ftys.as_slice(), false), dtor);
222             }
223
224             if !dtor && cases.len() == 2 && hint == attr::ReprAny {
225                 // Nullable pointer optimization
226                 let mut discr = 0;
227                 while discr < 2 {
228                     if cases.get(1 - discr).is_zerolen(cx) {
229                         let st = mk_struct(cx, cases.get(discr).tys.as_slice(), false);
230                         match cases.get(discr).find_ptr() {
231                             Some(ThinPointer(_)) if st.fields.len() == 1 => {
232                                 return RawNullablePointer {
233                                     nndiscr: discr as Disr,
234                                     nnty: *st.fields.get(0),
235                                     nullfields: cases.get(1 - discr).tys.clone()
236                                 };
237                             }
238                             Some(ptrfield) => {
239                                 return StructWrappedNullablePointer {
240                                     nndiscr: discr as Disr,
241                                     nonnull: st,
242                                     ptrfield: ptrfield,
243                                     nullfields: cases.get(1 - discr).tys.clone()
244                                 };
245                             }
246                             None => { }
247                         }
248                     }
249                     discr += 1;
250                 }
251             }
252
253             // The general case.
254             assert!((cases.len() - 1) as i64 >= 0);
255             let bounds = IntBounds { ulo: 0, uhi: (cases.len() - 1) as u64,
256                                      slo: 0, shi: (cases.len() - 1) as i64 };
257             let ity = range_to_inttype(cx, hint, &bounds);
258
259             return General(ity, cases.iter().map(|c| {
260                 let mut ftys = vec!(ty_of_inttype(ity)).append(c.tys.as_slice());
261                 if dtor { ftys.push(ty::mk_bool()); }
262                 mk_struct(cx, ftys.as_slice(), false)
263             }).collect(), dtor);
264         }
265         _ => cx.sess().bug("adt::represent_type called on non-ADT type")
266     }
267 }
268
269 /// Determine, without doing translation, whether an ADT must be FFI-safe.
270 /// For use in lint or similar, where being sound but slightly incomplete is acceptable.
271 pub fn is_ffi_safe(tcx: &ty::ctxt, def_id: ast::DefId) -> bool {
272     match ty::get(ty::lookup_item_type(tcx, def_id).ty).sty {
273         ty::ty_enum(def_id, _) => {
274             let variants = ty::enum_variants(tcx, def_id);
275             // Univariant => like struct/tuple.
276             if variants.len() <= 1 {
277                 return true;
278             }
279             let hint = ty::lookup_repr_hint(tcx, def_id);
280             // Appropriate representation explicitly selected?
281             if hint.is_ffi_safe() {
282                 return true;
283             }
284             // Option<Box<T>> and similar are used in FFI.  Rather than try to
285             // resolve type parameters and recognize this case exactly, this
286             // overapproximates -- assuming that if a non-C-like enum is being
287             // used in FFI then the user knows what they're doing.
288             if variants.iter().any(|vi| !vi.args.is_empty()) {
289                 return true;
290             }
291             false
292         }
293         // struct, tuple, etc.
294         // (is this right in the present of typedefs?)
295         _ => true
296     }
297 }
298
299 // this should probably all be in ty
300 struct Case {
301     discr: Disr,
302     tys: Vec<ty::t>
303 }
304
305
306 #[deriving(Show)]
307 pub enum PointerField {
308     ThinPointer(uint),
309     FatPointer(uint, uint)
310 }
311
312 impl Case {
313     fn is_zerolen(&self, cx: &CrateContext) -> bool {
314         mk_struct(cx, self.tys.as_slice(), false).size == 0
315     }
316     fn find_ptr(&self) -> Option<PointerField> {
317         use back::abi::{fn_field_code, slice_elt_base, trt_field_box};
318
319         for (i, &ty) in self.tys.iter().enumerate() {
320             match ty::get(ty).sty {
321                 // &T/&mut T could either be a thin or fat pointer depending on T
322                 ty::ty_rptr(_, ty::mt { ty, .. }) => match ty::get(ty).sty {
323                     // &[T] and &str are a pointer and length pair
324                     ty::ty_vec(_, None) | ty::ty_str => return Some(FatPointer(i, slice_elt_base)),
325
326                     // &Trait/&mut Trait are a pair of pointers: the actual object and a vtable
327                     ty::ty_trait(..) => return Some(FatPointer(i, trt_field_box)),
328
329                     // Any other &T/&mut T is just a pointer
330                     _ => return Some(ThinPointer(i))
331                 },
332
333                 // Box<T> could either be a thin or fat pointer depending on T
334                 ty::ty_uniq(t) => match ty::get(t).sty {
335                     // Box<[T]>/Box<str> might be FatPointer in a post DST world
336                     ty::ty_vec(_, None) | ty::ty_str => continue,
337
338                     // Box<Trait> is a pair of pointers: the actual object and a vtable
339                     ty::ty_trait(..) => return Some(FatPointer(i, trt_field_box)),
340
341                     // Any other Box<T> is just a pointer
342                     _ => return Some(ThinPointer(i))
343                 },
344
345                 // Gc<T> is just a pointer
346                 ty::ty_box(..) => return Some(ThinPointer(i)),
347
348                 // Functions are just pointers
349                 ty::ty_bare_fn(..) => return Some(ThinPointer(i)),
350
351                 // Closures are a pair of pointers: the code and environment
352                 ty::ty_closure(..) => return Some(FatPointer(i, fn_field_code)),
353
354                 // Anything else is not a pointer
355                 _ => continue
356
357             }
358         }
359
360         None
361     }
362 }
363
364 fn get_cases(tcx: &ty::ctxt, def_id: ast::DefId, substs: &subst::Substs) -> Vec<Case> {
365     ty::enum_variants(tcx, def_id).iter().map(|vi| {
366         let arg_tys = vi.args.iter().map(|&raw_ty| {
367             raw_ty.subst(tcx, substs)
368         }).collect();
369         Case { discr: vi.disr_val, tys: arg_tys }
370     }).collect()
371 }
372
373 fn mk_struct(cx: &CrateContext, tys: &[ty::t], packed: bool) -> Struct {
374     let lltys = tys.iter().map(|&ty| type_of::sizing_type_of(cx, ty)).collect::<Vec<_>>();
375     let llty_rec = Type::struct_(cx, lltys.as_slice(), packed);
376     Struct {
377         size: machine::llsize_of_alloc(cx, llty_rec) /*bad*/as u64,
378         align: machine::llalign_of_min(cx, llty_rec) /*bad*/as u64,
379         packed: packed,
380         fields: Vec::from_slice(tys),
381     }
382 }
383
384 struct IntBounds {
385     slo: i64,
386     shi: i64,
387     ulo: u64,
388     uhi: u64
389 }
390
391 fn mk_cenum(cx: &CrateContext, hint: Hint, bounds: &IntBounds) -> Repr {
392     let it = range_to_inttype(cx, hint, bounds);
393     match it {
394         attr::SignedInt(_) => CEnum(it, bounds.slo as Disr, bounds.shi as Disr),
395         attr::UnsignedInt(_) => CEnum(it, bounds.ulo, bounds.uhi)
396     }
397 }
398
399 fn range_to_inttype(cx: &CrateContext, hint: Hint, bounds: &IntBounds) -> IntType {
400     debug!("range_to_inttype: {:?} {:?}", hint, bounds);
401     // Lists of sizes to try.  u64 is always allowed as a fallback.
402     static choose_shortest: &'static[IntType] = &[
403         attr::UnsignedInt(ast::TyU8), attr::SignedInt(ast::TyI8),
404         attr::UnsignedInt(ast::TyU16), attr::SignedInt(ast::TyI16),
405         attr::UnsignedInt(ast::TyU32), attr::SignedInt(ast::TyI32)];
406     static at_least_32: &'static[IntType] = &[
407         attr::UnsignedInt(ast::TyU32), attr::SignedInt(ast::TyI32)];
408
409     let attempts;
410     match hint {
411         attr::ReprInt(span, ity) => {
412             if !bounds_usable(cx, ity, bounds) {
413                 cx.sess().span_bug(span, "representation hint insufficient for discriminant range")
414             }
415             return ity;
416         }
417         attr::ReprExtern => {
418             attempts = match cx.sess().targ_cfg.arch {
419                 X86 | X86_64 => at_least_32,
420                 // WARNING: the ARM EABI has two variants; the one corresponding to `at_least_32`
421                 // appears to be used on Linux and NetBSD, but some systems may use the variant
422                 // corresponding to `choose_shortest`.  However, we don't run on those yet...?
423                 Arm => at_least_32,
424                 Mips => at_least_32,
425                 Mipsel => at_least_32,
426             }
427         }
428         attr::ReprAny => {
429             attempts = choose_shortest;
430         }
431     }
432     for &ity in attempts.iter() {
433         if bounds_usable(cx, ity, bounds) {
434             return ity;
435         }
436     }
437     return attr::UnsignedInt(ast::TyU64);
438 }
439
440 pub fn ll_inttype(cx: &CrateContext, ity: IntType) -> Type {
441     match ity {
442         attr::SignedInt(t) => Type::int_from_ty(cx, t),
443         attr::UnsignedInt(t) => Type::uint_from_ty(cx, t)
444     }
445 }
446
447 fn bounds_usable(cx: &CrateContext, ity: IntType, bounds: &IntBounds) -> bool {
448     debug!("bounds_usable: {:?} {:?}", ity, bounds);
449     match ity {
450         attr::SignedInt(_) => {
451             let lllo = C_integral(ll_inttype(cx, ity), bounds.slo as u64, true);
452             let llhi = C_integral(ll_inttype(cx, ity), bounds.shi as u64, true);
453             bounds.slo == const_to_int(lllo) as i64 && bounds.shi == const_to_int(llhi) as i64
454         }
455         attr::UnsignedInt(_) => {
456             let lllo = C_integral(ll_inttype(cx, ity), bounds.ulo, false);
457             let llhi = C_integral(ll_inttype(cx, ity), bounds.uhi, false);
458             bounds.ulo == const_to_uint(lllo) as u64 && bounds.uhi == const_to_uint(llhi) as u64
459         }
460     }
461 }
462
463 pub fn ty_of_inttype(ity: IntType) -> ty::t {
464     match ity {
465         attr::SignedInt(t) => ty::mk_mach_int(t),
466         attr::UnsignedInt(t) => ty::mk_mach_uint(t)
467     }
468 }
469
470
471 /**
472  * LLVM-level types are a little complicated.
473  *
474  * C-like enums need to be actual ints, not wrapped in a struct,
475  * because that changes the ABI on some platforms (see issue #10308).
476  *
477  * For nominal types, in some cases, we need to use LLVM named structs
478  * and fill in the actual contents in a second pass to prevent
479  * unbounded recursion; see also the comments in `trans::type_of`.
480  */
481 pub fn type_of(cx: &CrateContext, r: &Repr) -> Type {
482     generic_type_of(cx, r, None, false)
483 }
484 pub fn sizing_type_of(cx: &CrateContext, r: &Repr) -> Type {
485     generic_type_of(cx, r, None, true)
486 }
487 pub fn incomplete_type_of(cx: &CrateContext, r: &Repr, name: &str) -> Type {
488     generic_type_of(cx, r, Some(name), false)
489 }
490 pub fn finish_type_of(cx: &CrateContext, r: &Repr, llty: &mut Type) {
491     match *r {
492         CEnum(..) | General(..) | RawNullablePointer { .. } => { }
493         Univariant(ref st, _) | StructWrappedNullablePointer { nonnull: ref st, .. } =>
494             llty.set_struct_body(struct_llfields(cx, st, false).as_slice(),
495                                  st.packed)
496     }
497 }
498
499 fn generic_type_of(cx: &CrateContext, r: &Repr, name: Option<&str>, sizing: bool) -> Type {
500     match *r {
501         CEnum(ity, _, _) => ll_inttype(cx, ity),
502         RawNullablePointer { nnty, .. } => type_of::sizing_type_of(cx, nnty),
503         Univariant(ref st, _) | StructWrappedNullablePointer { nonnull: ref st, .. } => {
504             match name {
505                 None => {
506                     Type::struct_(cx, struct_llfields(cx, st, sizing).as_slice(),
507                                   st.packed)
508                 }
509                 Some(name) => { assert_eq!(sizing, false); Type::named_struct(cx, name) }
510             }
511         }
512         General(ity, ref sts, _) => {
513             // We need a representation that has:
514             // * The alignment of the most-aligned field
515             // * The size of the largest variant (rounded up to that alignment)
516             // * No alignment padding anywhere any variant has actual data
517             //   (currently matters only for enums small enough to be immediate)
518             // * The discriminant in an obvious place.
519             //
520             // So we start with the discriminant, pad it up to the alignment with
521             // more of its own type, then use alignment-sized ints to get the rest
522             // of the size.
523             //
524             // FIXME #10604: this breaks when vector types are present.
525             let size = sts.iter().map(|st| st.size).max().unwrap();
526             let most_aligned = sts.iter().max_by(|st| st.align).unwrap();
527             let align = most_aligned.align;
528             let discr_ty = ll_inttype(cx, ity);
529             let discr_size = machine::llsize_of_alloc(cx, discr_ty) as u64;
530             let align_units = (size + align - 1) / align - 1;
531             let pad_ty = match align {
532                 1 => Type::array(&Type::i8(cx), align_units),
533                 2 => Type::array(&Type::i16(cx), align_units),
534                 4 => Type::array(&Type::i32(cx), align_units),
535                 8 if machine::llalign_of_min(cx, Type::i64(cx)) == 8 =>
536                                  Type::array(&Type::i64(cx), align_units),
537                 a if a.count_ones() == 1 => Type::array(&Type::vector(&Type::i32(cx), a / 4),
538                                                               align_units),
539                 _ => fail!("unsupported enum alignment: {:?}", align)
540             };
541             assert_eq!(machine::llalign_of_min(cx, pad_ty) as u64, align);
542             assert_eq!(align % discr_size, 0);
543             let fields = vec!(discr_ty,
544                            Type::array(&discr_ty, align / discr_size - 1),
545                            pad_ty);
546             match name {
547                 None => Type::struct_(cx, fields.as_slice(), false),
548                 Some(name) => {
549                     let mut llty = Type::named_struct(cx, name);
550                     llty.set_struct_body(fields.as_slice(), false);
551                     llty
552                 }
553             }
554         }
555     }
556 }
557
558 fn struct_llfields(cx: &CrateContext, st: &Struct, sizing: bool) -> Vec<Type> {
559     if sizing {
560         st.fields.iter().map(|&ty| type_of::sizing_type_of(cx, ty)).collect()
561     } else {
562         st.fields.iter().map(|&ty| type_of::type_of(cx, ty)).collect()
563     }
564 }
565
566 /**
567  * Obtain a representation of the discriminant sufficient to translate
568  * destructuring; this may or may not involve the actual discriminant.
569  *
570  * This should ideally be less tightly tied to `_match`.
571  */
572 pub fn trans_switch(bcx: &Block, r: &Repr, scrutinee: ValueRef)
573     -> (_match::branch_kind, Option<ValueRef>) {
574     match *r {
575         CEnum(..) | General(..) |
576         RawNullablePointer { .. } | StructWrappedNullablePointer { .. } => {
577             (_match::switch, Some(trans_get_discr(bcx, r, scrutinee, None)))
578         }
579         Univariant(..) => {
580             (_match::single, None)
581         }
582     }
583 }
584
585
586
587 /// Obtain the actual discriminant of a value.
588 pub fn trans_get_discr(bcx: &Block, r: &Repr, scrutinee: ValueRef, cast_to: Option<Type>)
589     -> ValueRef {
590     let signed;
591     let val;
592     match *r {
593         CEnum(ity, min, max) => {
594             val = load_discr(bcx, ity, scrutinee, min, max);
595             signed = ity.is_signed();
596         }
597         General(ity, ref cases, _) => {
598             let ptr = GEPi(bcx, scrutinee, [0, 0]);
599             val = load_discr(bcx, ity, ptr, 0, (cases.len() - 1) as Disr);
600             signed = ity.is_signed();
601         }
602         Univariant(..) => {
603             val = C_u8(bcx.ccx(), 0);
604             signed = false;
605         }
606         RawNullablePointer { nndiscr, nnty, .. } =>  {
607             let cmp = if nndiscr == 0 { IntEQ } else { IntNE };
608             let llptrty = type_of::sizing_type_of(bcx.ccx(), nnty);
609             val = ICmp(bcx, cmp, Load(bcx, scrutinee), C_null(llptrty));
610             signed = false;
611         }
612         StructWrappedNullablePointer { nndiscr, ptrfield, .. } => {
613             val = struct_wrapped_nullable_bitdiscr(bcx, nndiscr, ptrfield, scrutinee);
614             signed = false;
615         }
616     }
617     match cast_to {
618         None => val,
619         Some(llty) => if signed { SExt(bcx, val, llty) } else { ZExt(bcx, val, llty) }
620     }
621 }
622
623 fn struct_wrapped_nullable_bitdiscr(bcx: &Block, nndiscr: Disr, ptrfield: PointerField,
624                                     scrutinee: ValueRef) -> ValueRef {
625     let llptrptr = match ptrfield {
626         ThinPointer(field) => GEPi(bcx, scrutinee, [0, field]),
627         FatPointer(field, pair) => GEPi(bcx, scrutinee, [0, field, pair])
628     };
629     let llptr = Load(bcx, llptrptr);
630     let cmp = if nndiscr == 0 { IntEQ } else { IntNE };
631     ICmp(bcx, cmp, llptr, C_null(val_ty(llptr)))
632 }
633
634 /// Helper for cases where the discriminant is simply loaded.
635 fn load_discr(bcx: &Block, ity: IntType, ptr: ValueRef, min: Disr, max: Disr)
636     -> ValueRef {
637     let llty = ll_inttype(bcx.ccx(), ity);
638     assert_eq!(val_ty(ptr), llty.ptr_to());
639     let bits = machine::llbitsize_of_real(bcx.ccx(), llty);
640     assert!(bits <= 64);
641     let  bits = bits as uint;
642     let mask = (-1u64 >> (64 - bits)) as Disr;
643     if (max + 1) & mask == min & mask {
644         // i.e., if the range is everything.  The lo==hi case would be
645         // rejected by the LLVM verifier (it would mean either an
646         // empty set, which is impossible, or the entire range of the
647         // type, which is pointless).
648         Load(bcx, ptr)
649     } else {
650         // llvm::ConstantRange can deal with ranges that wrap around,
651         // so an overflow on (max + 1) is fine.
652         LoadRangeAssert(bcx, ptr, min as c_ulonglong,
653                         (max + 1) as c_ulonglong,
654                         /* signed: */ True)
655     }
656 }
657
658 /**
659  * Yield information about how to dispatch a case of the
660  * discriminant-like value returned by `trans_switch`.
661  *
662  * This should ideally be less tightly tied to `_match`.
663  */
664 pub fn trans_case<'a>(bcx: &'a Block<'a>, r: &Repr, discr: Disr)
665                   -> _match::opt_result<'a> {
666     match *r {
667         CEnum(ity, _, _) => {
668             _match::single_result(Result::new(bcx, C_integral(ll_inttype(bcx.ccx(), ity),
669                                                               discr as u64, true)))
670         }
671         General(ity, _, _) => {
672             _match::single_result(Result::new(bcx, C_integral(ll_inttype(bcx.ccx(), ity),
673                                                               discr as u64, true)))
674         }
675         Univariant(..) => {
676             bcx.ccx().sess().bug("no cases for univariants or structs")
677         }
678         RawNullablePointer { .. } |
679         StructWrappedNullablePointer { .. } => {
680             assert!(discr == 0 || discr == 1);
681             _match::single_result(Result::new(bcx, C_bool(bcx.ccx(), discr != 0)))
682         }
683     }
684 }
685
686 /**
687  * Set the discriminant for a new value of the given case of the given
688  * representation.
689  */
690 pub fn trans_set_discr(bcx: &Block, r: &Repr, val: ValueRef, discr: Disr) {
691     match *r {
692         CEnum(ity, min, max) => {
693             assert_discr_in_range(ity, min, max, discr);
694             Store(bcx, C_integral(ll_inttype(bcx.ccx(), ity), discr as u64, true),
695                   val)
696         }
697         General(ity, ref cases, dtor) => {
698             if dtor {
699                 let ptr = trans_field_ptr(bcx, r, val, discr,
700                                           cases.get(discr as uint).fields.len() - 2);
701                 Store(bcx, C_u8(bcx.ccx(), 1), ptr);
702             }
703             Store(bcx, C_integral(ll_inttype(bcx.ccx(), ity), discr as u64, true),
704                   GEPi(bcx, val, [0, 0]))
705         }
706         Univariant(ref st, dtor) => {
707             assert_eq!(discr, 0);
708             if dtor {
709                 Store(bcx, C_u8(bcx.ccx(), 1),
710                     GEPi(bcx, val, [0, st.fields.len() - 1]));
711             }
712         }
713         RawNullablePointer { nndiscr, nnty, ..} => {
714             if discr != nndiscr {
715                 let llptrty = type_of::sizing_type_of(bcx.ccx(), nnty);
716                 Store(bcx, C_null(llptrty), val)
717             }
718         }
719         StructWrappedNullablePointer { nonnull: ref nonnull, nndiscr, ptrfield, .. } => {
720             if discr != nndiscr {
721                 let (llptrptr, llptrty) = match ptrfield {
722                     ThinPointer(field) =>
723                         (GEPi(bcx, val, [0, field]),
724                          type_of::type_of(bcx.ccx(), *nonnull.fields.get(field))),
725                     FatPointer(field, pair) => {
726                         let v = GEPi(bcx, val, [0, field, pair]);
727                         (v, val_ty(v).element_type())
728                     }
729                 };
730                 Store(bcx, C_null(llptrty), llptrptr)
731             }
732         }
733     }
734 }
735
736 fn assert_discr_in_range(ity: IntType, min: Disr, max: Disr, discr: Disr) {
737     match ity {
738         attr::UnsignedInt(_) => assert!(min <= discr && discr <= max),
739         attr::SignedInt(_) => assert!(min as i64 <= discr as i64 && discr as i64 <= max as i64)
740     }
741 }
742
743 /**
744  * The number of fields in a given case; for use when obtaining this
745  * information from the type or definition is less convenient.
746  */
747 pub fn num_args(r: &Repr, discr: Disr) -> uint {
748     match *r {
749         CEnum(..) => 0,
750         Univariant(ref st, dtor) => {
751             assert_eq!(discr, 0);
752             st.fields.len() - (if dtor { 1 } else { 0 })
753         }
754         General(_, ref cases, dtor) => {
755             cases.get(discr as uint).fields.len() - 1 - (if dtor { 1 } else { 0 })
756         }
757         RawNullablePointer { nndiscr, ref nullfields, .. } => {
758             if discr == nndiscr { 1 } else { nullfields.len() }
759         }
760         StructWrappedNullablePointer { nonnull: ref nonnull, nndiscr,
761                                        nullfields: ref nullfields, .. } => {
762             if discr == nndiscr { nonnull.fields.len() } else { nullfields.len() }
763         }
764     }
765 }
766
767 /// Access a field, at a point when the value's case is known.
768 pub fn trans_field_ptr(bcx: &Block, r: &Repr, val: ValueRef, discr: Disr,
769                        ix: uint) -> ValueRef {
770     // Note: if this ever needs to generate conditionals (e.g., if we
771     // decide to do some kind of cdr-coding-like non-unique repr
772     // someday), it will need to return a possibly-new bcx as well.
773     match *r {
774         CEnum(..) => {
775             bcx.ccx().sess().bug("element access in C-like enum")
776         }
777         Univariant(ref st, _dtor) => {
778             assert_eq!(discr, 0);
779             struct_field_ptr(bcx, st, val, ix, false)
780         }
781         General(_, ref cases, _) => {
782             struct_field_ptr(bcx, cases.get(discr as uint), val, ix + 1, true)
783         }
784         RawNullablePointer { nndiscr, ref nullfields, .. } |
785         StructWrappedNullablePointer { nndiscr, ref nullfields, .. } if discr != nndiscr => {
786             // The unit-like case might have a nonzero number of unit-like fields.
787             // (e.d., Result of Either with (), as one side.)
788             let ty = type_of::type_of(bcx.ccx(), *nullfields.get(ix));
789             assert_eq!(machine::llsize_of_alloc(bcx.ccx(), ty), 0);
790             // The contents of memory at this pointer can't matter, but use
791             // the value that's "reasonable" in case of pointer comparison.
792             PointerCast(bcx, val, ty.ptr_to())
793         }
794         RawNullablePointer { nndiscr, nnty, .. } => {
795             assert_eq!(ix, 0);
796             assert_eq!(discr, nndiscr);
797             let ty = type_of::type_of(bcx.ccx(), nnty);
798             PointerCast(bcx, val, ty.ptr_to())
799         }
800         StructWrappedNullablePointer { ref nonnull, nndiscr, .. } => {
801             assert_eq!(discr, nndiscr);
802             struct_field_ptr(bcx, nonnull, val, ix, false)
803         }
804     }
805 }
806
807 pub fn struct_field_ptr(bcx: &Block, st: &Struct, val: ValueRef,
808                         ix: uint, needs_cast: bool) -> ValueRef {
809     let val = if needs_cast {
810         let ccx = bcx.ccx();
811         let fields = st.fields.iter().map(|&ty| type_of::type_of(ccx, ty)).collect::<Vec<_>>();
812         let real_ty = Type::struct_(ccx, fields.as_slice(), st.packed);
813         PointerCast(bcx, val, real_ty.ptr_to())
814     } else {
815         val
816     };
817
818     GEPi(bcx, val, [0, ix])
819 }
820
821 pub fn fold_variants<'r, 'b>(
822     bcx: &'b Block<'b>, r: &Repr, value: ValueRef,
823     f: |&'b Block<'b>, &Struct, ValueRef|: 'r -> &'b Block<'b>
824 ) -> &'b Block<'b> {
825     let fcx = bcx.fcx;
826     match *r {
827         Univariant(ref st, _) => {
828             f(bcx, st, value)
829         }
830         General(ity, ref cases, _) => {
831             let ccx = bcx.ccx();
832             let unr_cx = fcx.new_temp_block("enum-variant-iter-unr");
833             Unreachable(unr_cx);
834
835             let discr_val = trans_get_discr(bcx, r, value, None);
836             let llswitch = Switch(bcx, discr_val, unr_cx.llbb, cases.len());
837             let bcx_next = fcx.new_temp_block("enum-variant-iter-next");
838
839             for (discr, case) in cases.iter().enumerate() {
840                 let mut variant_cx = fcx.new_temp_block(
841                     format!("enum-variant-iter-{}", discr.to_string()).as_slice()
842                 );
843                 let rhs_val = C_integral(ll_inttype(ccx, ity), discr as u64, true);
844                 AddCase(llswitch, rhs_val, variant_cx.llbb);
845
846                 let fields = case.fields.iter().map(|&ty|
847                     type_of::type_of(bcx.ccx(), ty)).collect::<Vec<_>>();
848                 let real_ty = Type::struct_(ccx, fields.as_slice(), case.packed);
849                 let variant_value = PointerCast(variant_cx, value, real_ty.ptr_to());
850
851                 variant_cx = f(variant_cx, case, variant_value);
852                 Br(variant_cx, bcx_next.llbb);
853             }
854
855             bcx_next
856         }
857         _ => unreachable!()
858     }
859 }
860
861 /// Access the struct drop flag, if present.
862 pub fn trans_drop_flag_ptr<'b>(mut bcx: &'b Block<'b>, r: &Repr,
863                                val: ValueRef) -> datum::DatumBlock<'b, datum::Expr> {
864     let ptr_ty = ty::mk_imm_ptr(bcx.tcx(), ty::mk_bool());
865     match *r {
866         Univariant(ref st, true) => {
867             let flag_ptr = GEPi(bcx, val, [0, st.fields.len() - 1]);
868             datum::immediate_rvalue_bcx(bcx, flag_ptr, ptr_ty).to_expr_datumblock()
869         }
870         General(_, _, true) => {
871             let fcx = bcx.fcx;
872             let custom_cleanup_scope = fcx.push_custom_cleanup_scope();
873             let scratch = unpack_datum!(bcx, datum::lvalue_scratch_datum(
874                 bcx, ty::mk_bool(), "drop_flag", false,
875                 cleanup::CustomScope(custom_cleanup_scope), (), |_, bcx, _| bcx
876             ));
877             bcx = fold_variants(bcx, r, val, |variant_cx, st, value| {
878                 let ptr = struct_field_ptr(variant_cx, st, value, (st.fields.len() - 1), false);
879                 datum::Datum::new(ptr, ptr_ty, datum::Rvalue::new(datum::ByRef))
880                     .store_to(variant_cx, scratch.val)
881             });
882             let expr_datum = scratch.to_expr_datum();
883             fcx.pop_custom_cleanup_scope(custom_cleanup_scope);
884             datum::DatumBlock::new(bcx, expr_datum)
885         }
886         _ => bcx.ccx().sess().bug("tried to get drop flag of non-droppable type")
887     }
888 }
889
890 /**
891  * Construct a constant value, suitable for initializing a
892  * GlobalVariable, given a case and constant values for its fields.
893  * Note that this may have a different LLVM type (and different
894  * alignment!) from the representation's `type_of`, so it needs a
895  * pointer cast before use.
896  *
897  * The LLVM type system does not directly support unions, and only
898  * pointers can be bitcast, so a constant (and, by extension, the
899  * GlobalVariable initialized by it) will have a type that can vary
900  * depending on which case of an enum it is.
901  *
902  * To understand the alignment situation, consider `enum E { V64(u64),
903  * V32(u32, u32) }` on win32.  The type has 8-byte alignment to
904  * accommodate the u64, but `V32(x, y)` would have LLVM type `{i32,
905  * i32, i32}`, which is 4-byte aligned.
906  *
907  * Currently the returned value has the same size as the type, but
908  * this could be changed in the future to avoid allocating unnecessary
909  * space after values of shorter-than-maximum cases.
910  */
911 pub fn trans_const(ccx: &CrateContext, r: &Repr, discr: Disr,
912                    vals: &[ValueRef]) -> ValueRef {
913     match *r {
914         CEnum(ity, min, max) => {
915             assert_eq!(vals.len(), 0);
916             assert_discr_in_range(ity, min, max, discr);
917             C_integral(ll_inttype(ccx, ity), discr as u64, true)
918         }
919         General(ity, ref cases, _) => {
920             let case = cases.get(discr as uint);
921             let max_sz = cases.iter().map(|x| x.size).max().unwrap();
922             let lldiscr = C_integral(ll_inttype(ccx, ity), discr as u64, true);
923             let contents = build_const_struct(ccx,
924                                               case,
925                                               (vec!(lldiscr)).append(vals).as_slice());
926             C_struct(ccx, contents.append([padding(ccx, max_sz - case.size)]).as_slice(),
927                      false)
928         }
929         Univariant(ref st, _dro) => {
930             assert!(discr == 0);
931             let contents = build_const_struct(ccx, st, vals);
932             C_struct(ccx, contents.as_slice(), st.packed)
933         }
934         RawNullablePointer { nndiscr, nnty, .. } => {
935             if discr == nndiscr {
936                 assert_eq!(vals.len(), 1);
937                 vals[0]
938             } else {
939                 C_null(type_of::sizing_type_of(ccx, nnty))
940             }
941         }
942         StructWrappedNullablePointer { nonnull: ref nonnull, nndiscr, .. } => {
943             if discr == nndiscr {
944                 C_struct(ccx, build_const_struct(ccx,
945                                                  nonnull,
946                                                  vals).as_slice(),
947                          false)
948             } else {
949                 let vals = nonnull.fields.iter().map(|&ty| {
950                     // Always use null even if it's not the `ptrfield`th
951                     // field; see #8506.
952                     C_null(type_of::sizing_type_of(ccx, ty))
953                 }).collect::<Vec<ValueRef>>();
954                 C_struct(ccx, build_const_struct(ccx,
955                                                  nonnull,
956                                                  vals.as_slice()).as_slice(),
957                          false)
958             }
959         }
960     }
961 }
962
963 /**
964  * Compute struct field offsets relative to struct begin.
965  */
966 fn compute_struct_field_offsets(ccx: &CrateContext, st: &Struct) -> Vec<u64> {
967     let mut offsets = vec!();
968
969     let mut offset = 0;
970     for &ty in st.fields.iter() {
971         let llty = type_of::sizing_type_of(ccx, ty);
972         if !st.packed {
973             let type_align = machine::llalign_of_min(ccx, llty) as u64;
974             offset = roundup(offset, type_align);
975         }
976         offsets.push(offset);
977         offset += machine::llsize_of_alloc(ccx, llty) as u64;
978     }
979     assert_eq!(st.fields.len(), offsets.len());
980     offsets
981 }
982
983 /**
984  * Building structs is a little complicated, because we might need to
985  * insert padding if a field's value is less aligned than its type.
986  *
987  * Continuing the example from `trans_const`, a value of type `(u32,
988  * E)` should have the `E` at offset 8, but if that field's
989  * initializer is 4-byte aligned then simply translating the tuple as
990  * a two-element struct will locate it at offset 4, and accesses to it
991  * will read the wrong memory.
992  */
993 fn build_const_struct(ccx: &CrateContext, st: &Struct, vals: &[ValueRef])
994     -> Vec<ValueRef> {
995     assert_eq!(vals.len(), st.fields.len());
996
997     let target_offsets = compute_struct_field_offsets(ccx, st);
998
999     // offset of current value
1000     let mut offset = 0;
1001     let mut cfields = Vec::new();
1002     for (&val, &target_offset) in vals.iter().zip(target_offsets.iter()) {
1003         if !st.packed {
1004             let val_align = machine::llalign_of_min(ccx, val_ty(val))
1005                 /*bad*/as u64;
1006             offset = roundup(offset, val_align);
1007         }
1008         if offset != target_offset {
1009             cfields.push(padding(ccx, target_offset - offset));
1010             offset = target_offset;
1011         }
1012         assert!(!is_undef(val));
1013         cfields.push(val);
1014         offset += machine::llsize_of_alloc(ccx, val_ty(val)) as u64;
1015     }
1016
1017     assert!(offset <= st.size);
1018     if offset != st.size {
1019         cfields.push(padding(ccx, st.size - offset));
1020     }
1021
1022     cfields
1023 }
1024
1025 fn padding(ccx: &CrateContext, size: u64) -> ValueRef {
1026     C_undef(Type::array(&Type::i8(ccx), size))
1027 }
1028
1029 // FIXME this utility routine should be somewhere more general
1030 #[inline]
1031 fn roundup(x: u64, a: u64) -> u64 { ((x + (a - 1)) / a) * a }
1032
1033 /// Get the discriminant of a constant value.  (Not currently used.)
1034 pub fn const_get_discrim(ccx: &CrateContext, r: &Repr, val: ValueRef)
1035     -> Disr {
1036     match *r {
1037         CEnum(ity, _, _) => {
1038             match ity {
1039                 attr::SignedInt(..) => const_to_int(val) as Disr,
1040                 attr::UnsignedInt(..) => const_to_uint(val) as Disr
1041             }
1042         }
1043         General(ity, _, _) => {
1044             match ity {
1045                 attr::SignedInt(..) => const_to_int(const_get_elt(ccx, val, [0])) as Disr,
1046                 attr::UnsignedInt(..) => const_to_uint(const_get_elt(ccx, val, [0])) as Disr
1047             }
1048         }
1049         Univariant(..) => 0,
1050         RawNullablePointer { nndiscr, .. } => {
1051             if is_null(val) {
1052                 /* subtraction as uint is ok because nndiscr is either 0 or 1 */
1053                 (1 - nndiscr) as Disr
1054             } else {
1055                 nndiscr
1056             }
1057         }
1058         StructWrappedNullablePointer { nndiscr, ptrfield, .. } => {
1059             let (idx, sub_idx) = match ptrfield {
1060                 ThinPointer(field) => (field, None),
1061                 FatPointer(field, pair) => (field, Some(pair))
1062             };
1063             if is_null(const_struct_field(ccx, val, idx, sub_idx)) {
1064                 /* subtraction as uint is ok because nndiscr is either 0 or 1 */
1065                 (1 - nndiscr) as Disr
1066             } else {
1067                 nndiscr
1068             }
1069         }
1070     }
1071 }
1072
1073 /**
1074  * Extract a field of a constant value, as appropriate for its
1075  * representation.
1076  *
1077  * (Not to be confused with `common::const_get_elt`, which operates on
1078  * raw LLVM-level structs and arrays.)
1079  */
1080 pub fn const_get_field(ccx: &CrateContext, r: &Repr, val: ValueRef,
1081                        _discr: Disr, ix: uint) -> ValueRef {
1082     match *r {
1083         CEnum(..) => ccx.sess().bug("element access in C-like enum const"),
1084         Univariant(..) => const_struct_field(ccx, val, ix, None),
1085         General(..) => const_struct_field(ccx, val, ix + 1, None),
1086         RawNullablePointer { .. } => {
1087             assert_eq!(ix, 0);
1088             val
1089         }
1090         StructWrappedNullablePointer{ .. } => const_struct_field(ccx, val, ix, None)
1091     }
1092 }
1093
1094 /// Extract field of struct-like const, skipping our alignment padding.
1095 fn const_struct_field(ccx: &CrateContext, val: ValueRef, ix: uint, sub_idx: Option<uint>)
1096     -> ValueRef {
1097     // Get the ix-th non-undef element of the struct.
1098     let mut real_ix = 0; // actual position in the struct
1099     let mut ix = ix; // logical index relative to real_ix
1100     let mut field;
1101     loop {
1102         loop {
1103             field = match sub_idx {
1104                 Some(si) => const_get_elt(ccx, val, [real_ix, si as u32]),
1105                 None => const_get_elt(ccx, val, [real_ix])
1106             };
1107             if !is_undef(field) {
1108                 break;
1109             }
1110             real_ix = real_ix + 1;
1111         }
1112         if ix == 0 {
1113             return field;
1114         }
1115         ix = ix - 1;
1116         real_ix = real_ix + 1;
1117     }
1118 }