diff options
Diffstat (limited to 'src/librustc_trans/adt.rs')
| -rw-r--r-- | src/librustc_trans/adt.rs | 196 |
1 files changed, 0 insertions, 196 deletions
diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs deleted file mode 100644 index 07c64c35c07..00000000000 --- a/src/librustc_trans/adt.rs +++ /dev/null @@ -1,196 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! # Representation of Algebraic Data Types -//! -//! This module determines how to represent enums, structs, and tuples -//! based on their monomorphized types; it is responsible both for -//! choosing a representation and translating basic operations on -//! values of those types. (Note: exporting the representations for -//! debuggers is handled in debuginfo.rs, not here.) -//! -//! Note that the interface treats everything as a general case of an -//! enum, so structs/tuples/etc. have one pseudo-variant with -//! discriminant 0; i.e., as if they were a univariant enum. -//! -//! Having everything in one place will enable improvements to data -//! structure representation; possibilities include: -//! -//! - User-specified alignment (e.g., cacheline-aligning parts of -//! concurrently accessed data structures); LLVM can't represent this -//! directly, so we'd have to insert padding fields in any structure -//! that might contain one and adjust GEP indices accordingly. See -//! issue #4578. -//! -//! - Store nested enums' discriminants in the same word. Rather, if -//! some variants start with enums, and those enums representations -//! have unused alignment padding between discriminant and body, the -//! outer enum's discriminant can be stored there and those variants -//! can start at offset 0. Kind of fancy, and might need work to -//! make copies of the inner enum type cooperate, but it could help -//! with `Option` or `Result` wrapped around another enum. -//! -//! - Tagged pointers would be neat, but given that any type can be -//! used unboxed and any field can have pointers (including mutable) -//! taken to it, implementing them for Rust seems difficult. - -use rustc::ty::{self, Ty}; -use rustc::ty::layout::{self, HasDataLayout, LayoutOf, Size, FullLayout}; - -use context::CrateContext; -use type_::Type; - -/// LLVM-level types are a little complicated. -/// -/// C-like enums need to be actual ints, not wrapped in a struct, -/// because that changes the ABI on some platforms (see issue #10308). -/// -/// For nominal types, in some cases, we need to use LLVM named structs -/// and fill in the actual contents in a second pass to prevent -/// unbounded recursion; see also the comments in `trans::type_of`. -pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type { - generic_type_of(cx, t, None) -} - -pub fn incomplete_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, - t: Ty<'tcx>, name: &str) -> Type { - generic_type_of(cx, t, Some(name)) -} - -pub fn finish_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, - t: Ty<'tcx>, llty: &mut Type) { - let l = cx.layout_of(t); - debug!("finish_type_of: {} with layout {:#?}", t, l); - if let layout::Abi::Scalar(_) = l.abi { - return; - } - match *l.layout { - layout::Univariant => { - let is_enum = if let ty::TyAdt(def, _) = t.sty { - def.is_enum() - } else { - false - }; - let variant_layout = if is_enum { - l.for_variant(0) - } else { - l - }; - llty.set_struct_body(&struct_llfields(cx, variant_layout), - variant_layout.is_packed()) - } - - _ => {} - } -} - -fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, - t: Ty<'tcx>, - name: Option<&str>) -> Type { - let l = cx.layout_of(t); - debug!("adt::generic_type_of {:#?} name: {:?}", l, name); - if let layout::Abi::Scalar(value) = l.abi { - return cx.llvm_type_of(value.to_ty(cx.tcx())); - } - match *l.layout { - layout::Univariant => { - match name { - None => { - Type::struct_(cx, &struct_llfields(cx, l), l.is_packed()) - } - Some(name) => { - Type::named_struct(cx, name) - } - } - } - _ => { - let align = l.align(cx); - let abi_align = align.abi(); - let elem_ty = if let Some(ity) = layout::Integer::for_abi_align(cx, align) { - Type::from_integer(cx, ity) - } else { - let vec_align = cx.data_layout().vector_align(Size::from_bytes(abi_align)); - assert_eq!(vec_align.abi(), abi_align); - Type::vector(&Type::i32(cx), abi_align / 4) - }; - - let size = l.size(cx).bytes(); - assert_eq!(size % abi_align, 0); - let fill = Type::array(&elem_ty, size / abi_align); - match name { - None => { - Type::struct_(cx, &[fill], l.is_packed()) - } - Some(name) => { - let mut llty = Type::named_struct(cx, name); - llty.set_struct_body(&[fill], l.is_packed()); - llty - } - } - } - } -} - -/// Double an index and add 1 to account for padding. -pub fn memory_index_to_gep(index: u64) -> u64 { - 1 + index * 2 -} - -pub fn struct_llfields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, - layout: FullLayout<'tcx>) -> Vec<Type> { - debug!("struct_llfields: {:#?}", layout); - let align = layout.align(cx); - let size = layout.size(cx); - let field_count = layout.fields.count(); - - let mut offset = Size::from_bytes(0); - let mut result: Vec<Type> = Vec::with_capacity(1 + field_count * 2); - for i in layout.fields.index_by_increasing_offset() { - let field = layout.field(cx, i); - let target_offset = layout.fields.offset(i as usize); - debug!("struct_llfields: {}: {:?} offset: {:?} target_offset: {:?}", - i, field, offset, target_offset); - assert!(target_offset >= offset); - let padding = target_offset - offset; - result.push(Type::array(&Type::i8(cx), padding.bytes())); - debug!(" padding before: {:?}", padding); - - let llty = cx.llvm_type_of(field.ty); - result.push(llty); - - if layout.is_packed() { - assert_eq!(padding.bytes(), 0); - } else { - let field_align = field.align(cx); - assert!(field_align.abi() <= align.abi(), - "non-packed type has field with larger align ({}): {:#?}", - field_align.abi(), layout); - } - - offset = target_offset + field.size(cx); - } - if !layout.is_unsized() && field_count > 0 { - if offset > size { - bug!("layout: {:#?} stride: {:?} offset: {:?}", - layout, size, offset); - } - let padding = size - offset; - debug!("struct_llfields: pad_bytes: {:?} offset: {:?} stride: {:?}", - padding, offset, size); - result.push(Type::array(&Type::i8(cx), padding.bytes())); - assert!(result.len() == 1 + field_count * 2); - } else { - debug!("struct_llfields: offset: {:?} stride: {:?}", - offset, size); - } - - result -} - |
