about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMark Simulacrum <mark.simulacrum@gmail.com>2017-01-02 11:00:42 -0700
committerMark Simulacrum <mark.simulacrum@gmail.com>2017-01-04 11:37:44 -0700
commit982b8f4f49588ffe47475321a0d59c2beef1c9be (patch)
tree8ca5e14cb99311ab13c338118179e18a72969df4 /src
parentea0ebe41c7dc04374ec0e7e1173bb32b374d02fb (diff)
downloadrust-982b8f4f49588ffe47475321a0d59c2beef1c9be.tar.gz
rust-982b8f4f49588ffe47475321a0d59c2beef1c9be.zip
Move trans_const to mir::constant
Diffstat (limited to 'src')
-rw-r--r--src/librustc_trans/adt.rs154
-rw-r--r--src/librustc_trans/mir/constant.rs171
2 files changed, 164 insertions, 161 deletions
diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs
index a541306f99a..04634607c2c 100644
--- a/src/librustc_trans/adt.rs
+++ b/src/librustc_trans/adt.rs
@@ -70,9 +70,9 @@ pub enum BranchKind {
 /// Treats closures as a struct with one variant.
 /// `empty_if_no_variants` is a switch to deal with empty enums.
 /// If true, `variant_index` is disregarded and an empty Vec returned in this case.
-fn compute_fields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>,
-                            variant_index: usize,
-                            empty_if_no_variants: bool) -> Vec<Ty<'tcx>> {
+pub fn compute_fields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>,
+                                variant_index: usize,
+                                empty_if_no_variants: bool) -> Vec<Ty<'tcx>> {
     match t.sty {
         ty::TyAdt(ref def, _) if def.variants.len() == 0 && empty_if_no_variants => {
             Vec::default()
@@ -412,9 +412,7 @@ pub fn trans_case<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, value: Disr) -
 
 /// Set the discriminant for a new value of the given case of the given
 /// representation.
-pub fn trans_set_discr<'a, 'tcx>(
-    bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, val: ValueRef, to: Disr
-) {
+pub fn trans_set_discr<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, val: ValueRef, to: Disr) {
     let l = bcx.ccx.layout_of(t);
     match *l {
         layout::CEnum{ discr, min, max, .. } => {
@@ -465,7 +463,7 @@ fn target_sets_discr_via_memset<'a, 'tcx>(bcx: &Builder<'a, 'tcx>) -> bool {
     bcx.sess().target.target.arch == "arm" || bcx.sess().target.target.arch == "aarch64"
 }
 
-fn assert_discr_in_range(min: Disr, max: Disr, discr: Disr) {
+pub fn assert_discr_in_range(min: Disr, max: Disr, discr: Disr) {
     if min <= max {
         assert!(min <= discr && discr <= max)
     } else {
@@ -630,148 +628,6 @@ fn struct_field_ptr<'a, 'tcx>(
     bcx.pointercast(byte_ptr, ll_fty.ptr_to())
 }
 
-/// Construct a constant value, suitable for initializing a
-/// GlobalVariable, given a case and constant values for its fields.
-/// Note that this may have a different LLVM type (and different
-/// alignment!) from the representation's `type_of`, so it needs a
-/// pointer cast before use.
-///
-/// The LLVM type system does not directly support unions, and only
-/// pointers can be bitcast, so a constant (and, by extension, the
-/// GlobalVariable initialized by it) will have a type that can vary
-/// depending on which case of an enum it is.
-///
-/// To understand the alignment situation, consider `enum E { V64(u64),
-/// V32(u32, u32) }` on Windows.  The type has 8-byte alignment to
-/// accommodate the u64, but `V32(x, y)` would have LLVM type `{i32,
-/// i32, i32}`, which is 4-byte aligned.
-///
-/// Currently the returned value has the same size as the type, but
-/// this could be changed in the future to avoid allocating unnecessary
-/// space after values of shorter-than-maximum cases.
-pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, discr: Disr,
-                             vals: &[ValueRef]) -> ValueRef {
-    let l = ccx.layout_of(t);
-    let dl = &ccx.tcx().data_layout;
-    match *l {
-        layout::CEnum { discr: d, min, max, .. } => {
-            assert_eq!(vals.len(), 0);
-            assert_discr_in_range(Disr(min), Disr(max), discr);
-            C_integral(Type::from_integer(ccx, d), discr.0, true)
-        }
-        layout::General { discr: d, ref variants, .. } => {
-            let variant = &variants[discr.0 as usize];
-            let lldiscr = C_integral(Type::from_integer(ccx, d), discr.0 as u64, true);
-            let mut vals_with_discr = vec![lldiscr];
-            vals_with_discr.extend_from_slice(vals);
-            let mut contents = build_const_struct(ccx, &variant, &vals_with_discr[..]);
-            let needed_padding = l.size(dl).bytes() - variant.stride().bytes();
-            if needed_padding > 0 {
-                contents.push(padding(ccx, needed_padding));
-            }
-            C_struct(ccx, &contents[..], false)
-        }
-        layout::UntaggedUnion { ref variants, .. }=> {
-            assert_eq!(discr, Disr(0));
-            let contents = build_const_union(ccx, variants, vals[0]);
-            C_struct(ccx, &contents, variants.packed)
-        }
-        layout::Univariant { ref variant, .. } => {
-            assert_eq!(discr, Disr(0));
-            let contents = build_const_struct(ccx, &variant, vals);
-            C_struct(ccx, &contents[..], variant.packed)
-        }
-        layout::Vector { .. } => {
-            C_vector(vals)
-        }
-        layout::RawNullablePointer { nndiscr, .. } => {
-            let nnty = compute_fields(ccx, t, nndiscr as usize, false)[0];
-            if discr.0 == nndiscr {
-                assert_eq!(vals.len(), 1);
-                vals[0]
-            } else {
-                C_null(type_of::sizing_type_of(ccx, nnty))
-            }
-        }
-        layout::StructWrappedNullablePointer { ref nonnull, nndiscr, .. } => {
-            if discr.0 == nndiscr {
-                C_struct(ccx, &build_const_struct(ccx, &nonnull, vals), false)
-            } else {
-                let fields = compute_fields(ccx, t, nndiscr as usize, false);
-                let vals = fields.iter().map(|&ty| {
-                    // Always use null even if it's not the `discrfield`th
-                    // field; see #8506.
-                    C_null(type_of::sizing_type_of(ccx, ty))
-                }).collect::<Vec<ValueRef>>();
-                C_struct(ccx, &build_const_struct(ccx, &nonnull, &vals[..]), false)
-            }
-        }
-        _ => bug!("trans_const: cannot handle type {} repreented as {:#?}", t, l)
-    }
-}
-
-/// Building structs is a little complicated, because we might need to
-/// insert padding if a field's value is less aligned than its type.
-///
-/// Continuing the example from `trans_const`, a value of type `(u32,
-/// E)` should have the `E` at offset 8, but if that field's
-/// initializer is 4-byte aligned then simply translating the tuple as
-/// a two-element struct will locate it at offset 4, and accesses to it
-/// will read the wrong memory.
-fn build_const_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                                st: &layout::Struct,
-                                vals: &[ValueRef])
-                                -> Vec<ValueRef> {
-    assert_eq!(vals.len(), st.offsets.len());
-
-    if vals.len() == 0 {
-        return Vec::new();
-    }
-
-    // offset of current value
-    let mut offset = 0;
-    let mut cfields = Vec::new();
-    cfields.reserve(st.offsets.len()*2);
-
-    let parts = st.field_index_by_increasing_offset().map(|i| {
-        (&vals[i], st.offsets[i].bytes())
-    });
-    for (&val, target_offset) in parts {
-        if offset < target_offset {
-            cfields.push(padding(ccx, target_offset - offset));
-            offset = target_offset;
-        }
-        assert!(!is_undef(val));
-        cfields.push(val);
-        offset += machine::llsize_of_alloc(ccx, val_ty(val));
-    }
-
-    if offset < st.stride().bytes() {
-        cfields.push(padding(ccx, st.stride().bytes() - offset));
-    }
-
-    cfields
-}
-
-fn build_const_union<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                               un: &layout::Union,
-                               field_val: ValueRef)
-                               -> Vec<ValueRef> {
-    let mut cfields = vec![field_val];
-
-    let offset = machine::llsize_of_alloc(ccx, val_ty(field_val));
-    let size = un.stride().bytes();
-    if offset != size {
-        cfields.push(padding(ccx, size - offset));
-    }
-
-    cfields
-}
-
-fn padding(ccx: &CrateContext, size: u64) -> ValueRef {
-    C_undef(Type::array(&Type::i8(ccx), size))
-}
-
 // FIXME this utility routine should be somewhere more general
 #[inline]
 fn roundup(x: u64, a: u32) -> u64 { let a = a as u64; ((x + (a - 1)) / a) * a }
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index e15c25df911..13e659a5ae0 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -18,7 +18,7 @@ use rustc::hir::def_id::DefId;
 use rustc::infer::TransNormalize;
 use rustc::mir;
 use rustc::mir::tcx::LvalueTy;
-use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
+use rustc::ty::{self, layout, Ty, TyCtxt, TypeFoldable};
 use rustc::ty::cast::{CastTy, IntTy};
 use rustc::ty::subst::Substs;
 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
@@ -27,7 +27,7 @@ use callee::Callee;
 use builder::Builder;
 use common::{self, CrateContext, const_get_elt, val_ty};
 use common::{C_array, C_bool, C_bytes, C_floating_f64, C_integral, C_big_integral};
-use common::{C_null, C_struct, C_str_slice, C_undef, C_uint};
+use common::{C_null, C_struct, C_str_slice, C_undef, C_uint, C_vector, is_undef};
 use common::const_to_opt_u128;
 use consts;
 use monomorphize::{self, Instance};
@@ -549,16 +549,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
                     mir::AggregateKind::Adt(..) |
                     mir::AggregateKind::Closure(..) |
                     mir::AggregateKind::Tuple => {
-                        let disr = match *kind {
-                            mir::AggregateKind::Adt(adt_def, index, _, _) => {
-                                Disr::from(adt_def.variants[index].disr_val)
-                            }
-                            _ => Disr(0)
-                        };
-                        Const::new(
-                            adt::trans_const(self.ccx, dest_ty, disr, &fields),
-                            dest_ty
-                        )
+                        Const::new(trans_const(self.ccx, dest_ty, kind, &fields), dest_ty)
                     }
                 }
             }
@@ -946,3 +937,159 @@ pub fn trans_static_initializer(ccx: &CrateContext, def_id: DefId)
     let instance = Instance::mono(ccx.shared(), def_id);
     MirConstContext::trans_def(ccx, instance, IndexVec::new()).map(|c| c.llval)
 }
+
+/// Construct a constant value, suitable for initializing a
+/// GlobalVariable, given a case and constant values for its fields.
+/// Note that this may have a different LLVM type (and different
+/// alignment!) from the representation's `type_of`, so it needs a
+/// pointer cast before use.
+///
+/// The LLVM type system does not directly support unions, and only
+/// pointers can be bitcast, so a constant (and, by extension, the
+/// GlobalVariable initialized by it) will have a type that can vary
+/// depending on which case of an enum it is.
+///
+/// To understand the alignment situation, consider `enum E { V64(u64),
+/// V32(u32, u32) }` on Windows.  The type has 8-byte alignment to
+/// accommodate the u64, but `V32(x, y)` would have LLVM type `{i32,
+/// i32, i32}`, which is 4-byte aligned.
+///
+/// Currently the returned value has the same size as the type, but
+/// this could be changed in the future to avoid allocating unnecessary
+/// space after values of shorter-than-maximum cases.
+fn trans_const<'a, 'tcx>(
+    ccx: &CrateContext<'a, 'tcx>,
+    t: Ty<'tcx>,
+    kind: &mir::AggregateKind,
+    vals: &[ValueRef]
+) -> ValueRef {
+    let l = ccx.layout_of(t);
+    let dl = &ccx.tcx().data_layout;
+    let variant_index = match *kind {
+        mir::AggregateKind::Adt(_, index, _, _) => index,
+        _ => 0,
+    };
+    match *l {
+        layout::CEnum { discr: d, min, max, .. } => {
+            let discr = match *kind {
+                mir::AggregateKind::Adt(adt_def, _, _, _) => {
+                    Disr::from(adt_def.variants[variant_index].disr_val)
+                },
+                _ => Disr(0),
+            };
+            assert_eq!(vals.len(), 0);
+            adt::assert_discr_in_range(Disr(min), Disr(max), discr);
+            C_integral(Type::from_integer(ccx, d), discr.0, true)
+        }
+        layout::General { discr: d, ref variants, .. } => {
+            let variant = &variants[variant_index];
+            let lldiscr = C_integral(Type::from_integer(ccx, d), variant_index as u64, true);
+            let mut vals_with_discr = vec![lldiscr];
+            vals_with_discr.extend_from_slice(vals);
+            let mut contents = build_const_struct(ccx, &variant, &vals_with_discr[..]);
+            let needed_padding = l.size(dl).bytes() - variant.stride().bytes();
+            if needed_padding > 0 {
+                contents.push(padding(ccx, needed_padding));
+            }
+            C_struct(ccx, &contents[..], false)
+        }
+        layout::UntaggedUnion { ref variants, .. }=> {
+            assert_eq!(variant_index, 0);
+            let contents = build_const_union(ccx, variants, vals[0]);
+            C_struct(ccx, &contents, variants.packed)
+        }
+        layout::Univariant { ref variant, .. } => {
+            assert_eq!(variant_index, 0);
+            let contents = build_const_struct(ccx, &variant, vals);
+            C_struct(ccx, &contents[..], variant.packed)
+        }
+        layout::Vector { .. } => {
+            C_vector(vals)
+        }
+        layout::RawNullablePointer { nndiscr, .. } => {
+            let nnty = adt::compute_fields(ccx, t, nndiscr as usize, false)[0];
+            if variant_index as u64 == nndiscr {
+                assert_eq!(vals.len(), 1);
+                vals[0]
+            } else {
+                C_null(type_of::sizing_type_of(ccx, nnty))
+            }
+        }
+        layout::StructWrappedNullablePointer { ref nonnull, nndiscr, .. } => {
+            if variant_index as u64 == nndiscr {
+                C_struct(ccx, &build_const_struct(ccx, &nonnull, vals), false)
+            } else {
+                let fields = adt::compute_fields(ccx, t, nndiscr as usize, false);
+                let vals = fields.iter().map(|&ty| {
+                    // Always use null even if it's not the `discrfield`th
+                    // field; see #8506.
+                    C_null(type_of::sizing_type_of(ccx, ty))
+                }).collect::<Vec<ValueRef>>();
+                C_struct(ccx, &build_const_struct(ccx, &nonnull, &vals[..]), false)
+            }
+        }
+        _ => bug!("trans_const: cannot handle type {} repreented as {:#?}", t, l)
+    }
+}
+
+/// Building structs is a little complicated, because we might need to
+/// insert padding if a field's value is less aligned than its type.
+///
+/// Continuing the example from `trans_const`, a value of type `(u32,
+/// E)` should have the `E` at offset 8, but if that field's
+/// initializer is 4-byte aligned then simply translating the tuple as
+/// a two-element struct will locate it at offset 4, and accesses to it
+/// will read the wrong memory.
+fn build_const_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+                                st: &layout::Struct,
+                                vals: &[ValueRef])
+                                -> Vec<ValueRef> {
+    assert_eq!(vals.len(), st.offsets.len());
+
+    if vals.len() == 0 {
+        return Vec::new();
+    }
+
+    // offset of current value
+    let mut offset = 0;
+    let mut cfields = Vec::new();
+    cfields.reserve(st.offsets.len()*2);
+
+    let parts = st.field_index_by_increasing_offset().map(|i| {
+        (&vals[i], st.offsets[i].bytes())
+    });
+    for (&val, target_offset) in parts {
+        if offset < target_offset {
+            cfields.push(padding(ccx, target_offset - offset));
+            offset = target_offset;
+        }
+        assert!(!is_undef(val));
+        cfields.push(val);
+        offset += machine::llsize_of_alloc(ccx, val_ty(val));
+    }
+
+    if offset < st.stride().bytes() {
+        cfields.push(padding(ccx, st.stride().bytes() - offset));
+    }
+
+    cfields
+}
+
+fn build_const_union<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+                               un: &layout::Union,
+                               field_val: ValueRef)
+                               -> Vec<ValueRef> {
+    let mut cfields = vec![field_val];
+
+    let offset = machine::llsize_of_alloc(ccx, val_ty(field_val));
+    let size = un.stride().bytes();
+    if offset != size {
+        cfields.push(padding(ccx, size - offset));
+    }
+
+    cfields
+}
+
+fn padding(ccx: &CrateContext, size: u64) -> ValueRef {
+    C_undef(Type::array(&Type::i8(ccx), size))
+}