]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_trans/mir/constant.rs
refactor `ParamEnv::empty(Reveal)` into two distinct methods
[rust.git] / src / librustc_trans / mir / constant.rs
index d470f92b75231de8df503ef557b020cd83605e03..977c7c983d6f2458dd4eb0e08b54897de84f2837 100644 (file)
 // except according to those terms.
 
 use llvm::{self, ValueRef};
-use rustc::middle::const_val::{ConstEvalErr, ConstVal, ErrKind};
-use rustc_const_math::ConstInt::*;
-use rustc_const_math::{ConstInt, ConstMathErr, MAX_F32_PLUS_HALF_ULP};
+use rustc::middle::const_val::{ConstVal, ConstEvalErr};
+use rustc_mir::interpret::{read_target_uint, const_val_field};
 use rustc::hir::def_id::DefId;
-use rustc::infer::TransNormalize;
-use rustc::traits;
 use rustc::mir;
-use rustc::mir::tcx::PlaceTy;
-use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
-use rustc::ty::layout::{self, LayoutOf, Size};
-use rustc::ty::cast::{CastTy, IntTy};
-use rustc::ty::subst::{Kind, Substs};
-use rustc_apfloat::{ieee, Float, Status};
-use rustc_data_structures::indexed_vec::{Idx, IndexVec};
-use base;
-use abi::{self, Abi};
-use callee;
+use rustc_data_structures::indexed_vec::Idx;
+use rustc::mir::interpret::{Allocation, GlobalId, MemoryPointer, PrimVal, Value as MiriValue};
+use rustc::ty::{self, Ty};
+use rustc::ty::layout::{self, HasDataLayout, LayoutOf, Scalar};
 use builder::Builder;
-use common::{self, CodegenCx, const_get_elt, val_ty};
-use common::{C_array, C_bool, C_bytes, C_int, C_uint, C_uint_big, C_u32, C_u64};
-use common::{C_null, C_struct, C_str_slice, C_undef, C_usize, C_vector, C_fat_ptr};
-use common::const_to_opt_u128;
+use common::{CodegenCx};
+use common::{C_bytes, C_struct, C_uint_big, C_undef, C_usize};
 use consts;
 use type_of::LayoutLlvmExt;
 use type_::Type;
-use value::Value;
+use syntax::ast::Mutability;
 
-use syntax_pos::Span;
-use syntax::ast;
-
-use std::fmt;
-use std::ptr;
-
-use super::operand::{OperandRef, OperandValue};
+use super::super::callee;
 use super::FunctionCx;
 
-/// A sized constant rvalue.
-/// The LLVM type might not be the same for a single Rust type,
-/// e.g. each enum variant would have its own LLVM struct type.
-#[derive(Copy, Clone)]
-pub struct Const<'tcx> {
-    pub llval: ValueRef,
-    pub ty: Ty<'tcx>
-}
-
-impl<'a, 'tcx> Const<'tcx> {
-    pub fn new(llval: ValueRef, ty: Ty<'tcx>) -> Const<'tcx> {
-        Const {
-            llval,
-            ty,
-        }
-    }
-
-    pub fn from_constint(cx: &CodegenCx<'a, 'tcx>, ci: &ConstInt) -> Const<'tcx> {
-        let tcx = cx.tcx;
-        let (llval, ty) = match *ci {
-            I8(v) => (C_int(Type::i8(cx), v as i64), tcx.types.i8),
-            I16(v) => (C_int(Type::i16(cx), v as i64), tcx.types.i16),
-            I32(v) => (C_int(Type::i32(cx), v as i64), tcx.types.i32),
-            I64(v) => (C_int(Type::i64(cx), v as i64), tcx.types.i64),
-            I128(v) => (C_uint_big(Type::i128(cx), v as u128), tcx.types.i128),
-            Isize(v) => (C_int(Type::isize(cx), v.as_i64()), tcx.types.isize),
-            U8(v) => (C_uint(Type::i8(cx), v as u64), tcx.types.u8),
-            U16(v) => (C_uint(Type::i16(cx), v as u64), tcx.types.u16),
-            U32(v) => (C_uint(Type::i32(cx), v as u64), tcx.types.u32),
-            U64(v) => (C_uint(Type::i64(cx), v), tcx.types.u64),
-            U128(v) => (C_uint_big(Type::i128(cx), v), tcx.types.u128),
-            Usize(v) => (C_uint(Type::isize(cx), v.as_u64()), tcx.types.usize),
-        };
-        Const { llval: llval, ty: ty }
-    }
-
-    /// Translate ConstVal into a LLVM constant value.
-    pub fn from_constval(cx: &CodegenCx<'a, 'tcx>,
-                         cv: &ConstVal,
-                         ty: Ty<'tcx>)
-                         -> Const<'tcx> {
-        let llty = cx.layout_of(ty).llvm_type(cx);
-        let val = match *cv {
-            ConstVal::Float(v) => {
-                let bits = match v.ty {
-                    ast::FloatTy::F32 => C_u32(cx, v.bits as u32),
-                    ast::FloatTy::F64 => C_u64(cx, v.bits as u64)
-                };
-                consts::bitcast(bits, llty)
-            }
-            ConstVal::Bool(v) => C_bool(cx, v),
-            ConstVal::Integral(ref i) => return Const::from_constint(cx, i),
-            ConstVal::Str(ref v) => C_str_slice(cx, v.clone()),
-            ConstVal::ByteStr(v) => {
-                consts::addr_of(cx, C_bytes(cx, v.data), cx.align_of(ty), "byte_str")
-            }
-            ConstVal::Char(c) => C_uint(Type::char(cx), c as u64),
-            ConstVal::Function(..) => C_undef(llty),
-            ConstVal::Variant(_) |
-            ConstVal::Aggregate(..) |
-            ConstVal::Unevaluated(..) => {
-                bug!("MIR must not use `{:?}` (aggregates are expanded to MIR rvalues)", cv)
-            }
-        };
-
-        assert!(!ty.has_erasable_regions());
-
-        Const::new(val, ty)
-    }
-
-    fn get_field(&self, cx: &CodegenCx<'a, 'tcx>, i: usize) -> ValueRef {
-        let layout = cx.layout_of(self.ty);
-        let field = layout.field(cx, i);
-        if field.is_zst() {
-            return C_undef(field.immediate_llvm_type(cx));
-        }
-        let offset = layout.fields.offset(i);
-        match layout.abi {
-            layout::Abi::Scalar(_) |
-            layout::Abi::ScalarPair(..) |
-            layout::Abi::Vector { .. }
-                if offset.bytes() == 0 && field.size == layout.size => self.llval,
-
-            layout::Abi::ScalarPair(ref a, ref b) => {
-                if offset.bytes() == 0 {
-                    assert_eq!(field.size, a.value.size(cx));
-                    const_get_elt(self.llval, 0)
-                } else {
-                    assert_eq!(offset, a.value.size(cx)
-                        .abi_align(b.value.align(cx)));
-                    assert_eq!(field.size, b.value.size(cx));
-                    const_get_elt(self.llval, 1)
-                }
-            }
-            _ => {
-                match layout.fields {
-                    layout::FieldPlacement::Union(_) => self.llval,
-                    _ => const_get_elt(self.llval, layout.llvm_field_index(i)),
-                }
-            }
-        }
-    }
-
-    fn get_pair(&self, cx: &CodegenCx<'a, 'tcx>) -> (ValueRef, ValueRef) {
-        (self.get_field(cx, 0), self.get_field(cx, 1))
-    }
-
-    fn get_fat_ptr(&self, cx: &CodegenCx<'a, 'tcx>) -> (ValueRef, ValueRef) {
-        assert_eq!(abi::FAT_PTR_ADDR, 0);
-        assert_eq!(abi::FAT_PTR_EXTRA, 1);
-        self.get_pair(cx)
-    }
-
-    fn as_place(&self) -> ConstPlace<'tcx> {
-        ConstPlace {
-            base: Base::Value(self.llval),
-            llextra: ptr::null_mut(),
-            ty: self.ty
-        }
-    }
-
-    pub fn to_operand(&self, cx: &CodegenCx<'a, 'tcx>) -> OperandRef<'tcx> {
-        let layout = cx.layout_of(self.ty);
-        let llty = layout.immediate_llvm_type(cx);
-        let llvalty = val_ty(self.llval);
-
-        let val = if llty == llvalty && layout.is_llvm_scalar_pair() {
-            OperandValue::Pair(
-                const_get_elt(self.llval, 0),
-                const_get_elt(self.llval, 1))
-        } else if llty == llvalty && layout.is_llvm_immediate() {
-            // If the types match, we can use the value directly.
-            OperandValue::Immediate(self.llval)
-        } else {
-            // Otherwise, or if the value is not immediate, we create
-            // a constant LLVM global and cast its address if necessary.
-            let align = cx.align_of(self.ty);
-            let ptr = consts::addr_of(cx, self.llval, align, "const");
-            OperandValue::Ref(consts::ptrcast(ptr, layout.llvm_type(cx).ptr_to()),
-                              layout.align)
-        };
-
-        OperandRef {
-            val,
-            layout
-        }
-    }
-}
-
-impl<'tcx> fmt::Debug for Const<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "Const({:?}: {:?})", Value(self.llval), self.ty)
-    }
-}
-
-#[derive(Copy, Clone)]
-enum Base {
-    /// A constant value without an unique address.
-    Value(ValueRef),
-
-    /// String literal base pointer (cast from array).
-    Str(ValueRef),
-
-    /// The address of a static.
-    Static(ValueRef)
-}
-
-/// A place as seen from a constant.
-#[derive(Copy, Clone)]
-struct ConstPlace<'tcx> {
-    base: Base,
-    llextra: ValueRef,
-    ty: Ty<'tcx>
-}
-
-impl<'tcx> ConstPlace<'tcx> {
-    fn to_const(&self, span: Span) -> Const<'tcx> {
-        match self.base {
-            Base::Value(val) => Const::new(val, self.ty),
-            Base::Str(ptr) => {
-                span_bug!(span, "loading from `str` ({:?}) in constant",
-                          Value(ptr))
-            }
-            Base::Static(val) => {
-                span_bug!(span, "loading from `static` ({:?}) in constant",
-                          Value(val))
-            }
-        }
-    }
-
-    pub fn len<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> ValueRef {
-        match self.ty.sty {
-            ty::TyArray(_, n) => {
-                C_usize(cx, n.val.to_const_int().unwrap().to_u64().unwrap())
-            }
-            ty::TySlice(_) | ty::TyStr => {
-                assert!(self.llextra != ptr::null_mut());
-                self.llextra
-            }
-            _ => bug!("unexpected type `{}` in ConstPlace::len", self.ty)
-        }
-    }
-}
-
-/// Machinery for translating a constant's MIR to LLVM values.
-/// FIXME(eddyb) use miri and lower its allocations to LLVM.
-struct MirConstContext<'a, 'tcx: 'a> {
-    cx: &'a CodegenCx<'a, 'tcx>,
-    mir: &'a mir::Mir<'tcx>,
-
-    /// Type parameters for const fn and associated constants.
-    substs: &'tcx Substs<'tcx>,
-
-    /// Values of locals in a constant or const fn.
-    locals: IndexVec<mir::Local, Option<Result<Const<'tcx>, ConstEvalErr<'tcx>>>>
-}
-
-fn add_err<'tcx, U, V>(failure: &mut Result<U, ConstEvalErr<'tcx>>,
-                       value: &Result<V, ConstEvalErr<'tcx>>)
-{
-    if let &Err(ref err) = value {
-        if failure.is_ok() {
-            *failure = Err(err.clone());
-        }
-    }
-}
-
-impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
-    fn new(cx: &'a CodegenCx<'a, 'tcx>,
-           mir: &'a mir::Mir<'tcx>,
-           substs: &'tcx Substs<'tcx>,
-           args: IndexVec<mir::Local, Result<Const<'tcx>, ConstEvalErr<'tcx>>>)
-           -> MirConstContext<'a, 'tcx> {
-        let mut context = MirConstContext {
-            cx,
-            mir,
-            substs,
-            locals: (0..mir.local_decls.len()).map(|_| None).collect(),
-        };
-        for (i, arg) in args.into_iter().enumerate() {
-            // Locals after local 0 are the function arguments
-            let index = mir::Local::new(i + 1);
-            context.locals[index] = Some(arg);
-        }
-        context
-    }
-
-    fn trans_def(cx: &'a CodegenCx<'a, 'tcx>,
-                 def_id: DefId,
-                 substs: &'tcx Substs<'tcx>,
-                 args: IndexVec<mir::Local, Result<Const<'tcx>, ConstEvalErr<'tcx>>>)
-                 -> Result<Const<'tcx>, ConstEvalErr<'tcx>> {
-        let instance = ty::Instance::resolve(cx.tcx,
-                                             ty::ParamEnv::empty(traits::Reveal::All),
-                                             def_id,
-                                             substs).unwrap();
-        let mir = cx.tcx.instance_mir(instance.def);
-        MirConstContext::new(cx, &mir, instance.substs, args).trans()
-    }
-
-    fn monomorphize<T>(&self, value: &T) -> T
-        where T: TransNormalize<'tcx>
-    {
-        self.cx.tcx.trans_apply_param_substs(self.substs, value)
-    }
-
-    fn trans(&mut self) -> Result<Const<'tcx>, ConstEvalErr<'tcx>> {
-        let tcx = self.cx.tcx;
-        let mut bb = mir::START_BLOCK;
-
-        // Make sure to evaluate all statemenets to
-        // report as many errors as we possibly can.
-        let mut failure = Ok(());
-
-        loop {
-            let data = &self.mir[bb];
-            for statement in &data.statements {
-                let span = statement.source_info.span;
-                match statement.kind {
-                    mir::StatementKind::Assign(ref dest, ref rvalue) => {
-                        let ty = dest.ty(self.mir, tcx);
-                        let ty = self.monomorphize(&ty).to_ty(tcx);
-                        let value = self.const_rvalue(rvalue, ty, span);
-                        add_err(&mut failure, &value);
-                        self.store(dest, value, span);
-                    }
-                    mir::StatementKind::StorageLive(_) |
-                    mir::StatementKind::StorageDead(_) |
-                    mir::StatementKind::Validate(..) |
-                    mir::StatementKind::EndRegion(_) |
-                    mir::StatementKind::Nop => {}
-                    mir::StatementKind::InlineAsm { .. } |
-                    mir::StatementKind::SetDiscriminant{ .. } => {
-                        span_bug!(span, "{:?} should not appear in constants?", statement.kind);
-                    }
-                }
+pub fn primval_to_llvm(cx: &CodegenCx,
+                       cv: PrimVal,
+                       scalar: &Scalar,
+                       llty: Type) -> ValueRef {
+    let bits = if scalar.is_bool() { 1 } else { scalar.value.size(cx).bits() };
+    match cv {
+        PrimVal::Undef => C_undef(Type::ix(cx, bits)),
+        PrimVal::Bytes(b) => {
+            let llval = C_uint_big(Type::ix(cx, bits), b);
+            if scalar.value == layout::Pointer {
+                unsafe { llvm::LLVMConstIntToPtr(llval, llty.to_ref()) }
+            } else {
+                consts::bitcast(llval, llty)
             }
-
-            let terminator = data.terminator();
-            let span = terminator.source_info.span;
-            bb = match terminator.kind {
-                mir::TerminatorKind::Drop { target, .. } | // No dropping.
-                mir::TerminatorKind::Goto { target } => target,
-                mir::TerminatorKind::Return => {
-                    failure?;
-                    return self.locals[mir::RETURN_PLACE].clone().unwrap_or_else(|| {
-                        span_bug!(span, "no returned value in constant");
-                    });
-                }
-
-                mir::TerminatorKind::Assert { ref cond, expected, ref msg, target, .. } => {
-                    let cond = self.const_operand(cond, span)?;
-                    let cond_bool = common::const_to_uint(cond.llval) != 0;
-                    if cond_bool != expected {
-                        let err = match *msg {
-                            mir::AssertMessage::BoundsCheck { ref len, ref index } => {
-                                let len = self.const_operand(len, span)?;
-                                let index = self.const_operand(index, span)?;
-                                ErrKind::IndexOutOfBounds {
-                                    len: common::const_to_uint(len.llval),
-                                    index: common::const_to_uint(index.llval)
-                                }
-                            }
-                            mir::AssertMessage::Math(ref err) => {
-                                ErrKind::Math(err.clone())
-                            }
-                            mir::AssertMessage::GeneratorResumedAfterReturn |
-                            mir::AssertMessage::GeneratorResumedAfterPanic =>
-                                span_bug!(span, "{:?} should not appear in constants?", msg),
-                        };
-
-                        let err = ConstEvalErr { span: span, kind: err };
-                        err.report(tcx, span, "expression");
-                        failure = Err(err);
-                    }
-                    target
-                }
-
-                mir::TerminatorKind::Call { ref func, ref args, ref destination, .. } => {
-                    let fn_ty = func.ty(self.mir, tcx);
-                    let fn_ty = self.monomorphize(&fn_ty);
-                    let (def_id, substs) = match fn_ty.sty {
-                        ty::TyFnDef(def_id, substs) => (def_id, substs),
-                        _ => span_bug!(span, "calling {:?} (of type {}) in constant",
-                                       func, fn_ty)
-                    };
-
-                    let mut arg_vals = IndexVec::with_capacity(args.len());
-                    for arg in args {
-                        let arg_val = self.const_operand(arg, span);
-                        add_err(&mut failure, &arg_val);
-                        arg_vals.push(arg_val);
-                    }
-                    if let Some((ref dest, target)) = *destination {
-                        let result = if fn_ty.fn_sig(tcx).abi() == Abi::RustIntrinsic {
-                            match &tcx.item_name(def_id)[..] {
-                                "size_of" => {
-                                    let llval = C_usize(self.cx,
-                                        self.cx.size_of(substs.type_at(0)).bytes());
-                                    Ok(Const::new(llval, tcx.types.usize))
-                                }
-                                "min_align_of" => {
-                                    let llval = C_usize(self.cx,
-                                        self.cx.align_of(substs.type_at(0)).abi());
-                                    Ok(Const::new(llval, tcx.types.usize))
-                                }
-                                "type_id" => {
-                                    let llval = C_u64(self.cx,
-                                        self.cx.tcx.type_id_hash(substs.type_at(0)));
-                                    Ok(Const::new(llval, tcx.types.u64))
-                                }
-                                _ => span_bug!(span, "{:?} in constant", terminator.kind)
-                            }
-                        } else if let Some((op, is_checked)) = self.is_binop_lang_item(def_id) {
-                            (||{
-                                assert_eq!(arg_vals.len(), 2);
-                                let rhs = arg_vals.pop().unwrap()?;
-                                let lhs = arg_vals.pop().unwrap()?;
-                                if !is_checked {
-                                    let binop_ty = op.ty(tcx, lhs.ty, rhs.ty);
-                                    let (lhs, rhs) = (lhs.llval, rhs.llval);
-                                    Ok(Const::new(const_scalar_binop(op, lhs, rhs, binop_ty),
-                                                  binop_ty))
-                                } else {
-                                    let ty = lhs.ty;
-                                    let val_ty = op.ty(tcx, lhs.ty, rhs.ty);
-                                    let binop_ty = tcx.intern_tup(&[val_ty, tcx.types.bool], false);
-                                    let (lhs, rhs) = (lhs.llval, rhs.llval);
-                                    assert!(!ty.is_fp());
-
-                                    match const_scalar_checked_binop(tcx, op, lhs, rhs, ty) {
-                                        Some((llval, of)) => {
-                                            Ok(trans_const_adt(
-                                                self.cx,
-                                                binop_ty,
-                                                &mir::AggregateKind::Tuple,
-                                                &[
-                                                    Const::new(llval, val_ty),
-                                                    Const::new(C_bool(self.cx, of), tcx.types.bool)
-                                                ]))
-                                        }
-                                        None => {
-                                            span_bug!(span,
-                                                "{:?} got non-integer operands: {:?} and {:?}",
-                                                op, Value(lhs), Value(rhs));
-                                        }
-                                    }
-                                }
-                            })()
-                        } else {
-                            MirConstContext::trans_def(self.cx, def_id, substs, arg_vals)
-                        };
-                        add_err(&mut failure, &result);
-                        self.store(dest, result, span);
-                        target
+        },
+        PrimVal::Ptr(ptr) => {
+            if let Some(fn_instance) = cx.tcx.interpret_interner.get_fn(ptr.alloc_id) {
+                callee::get_fn(cx, fn_instance)
+            } else {
+                let static_ = cx
+                    .tcx
+                    .interpret_interner
+                    .get_corresponding_static_def_id(ptr.alloc_id);
+                let base_addr = if let Some(def_id) = static_ {
+                    assert!(cx.tcx.is_static(def_id).is_some());
+                    consts::get_static(cx, def_id)
+                } else if let Some(alloc) = cx.tcx.interpret_interner
+                                              .get_alloc(ptr.alloc_id) {
+                    let init = global_initializer(cx, alloc);
+                    if alloc.runtime_mutability == Mutability::Mutable {
+                        consts::addr_of_mut(cx, init, alloc.align, "byte_str")
                     } else {
-                        span_bug!(span, "diverging {:?} in constant", terminator.kind);
-                    }
-                }
-                _ => span_bug!(span, "{:?} in constant", terminator.kind)
-            };
-        }
-    }
-
-    fn is_binop_lang_item(&mut self, def_id: DefId) -> Option<(mir::BinOp, bool)> {
-        let tcx = self.cx.tcx;
-        let items = tcx.lang_items();
-        let def_id = Some(def_id);
-        if items.i128_add_fn() == def_id { Some((mir::BinOp::Add, false)) }
-        else if items.u128_add_fn() == def_id { Some((mir::BinOp::Add, false)) }
-        else if items.i128_sub_fn() == def_id { Some((mir::BinOp::Sub, false)) }
-        else if items.u128_sub_fn() == def_id { Some((mir::BinOp::Sub, false)) }
-        else if items.i128_mul_fn() == def_id { Some((mir::BinOp::Mul, false)) }
-        else if items.u128_mul_fn() == def_id { Some((mir::BinOp::Mul, false)) }
-        else if items.i128_div_fn() == def_id { Some((mir::BinOp::Div, false)) }
-        else if items.u128_div_fn() == def_id { Some((mir::BinOp::Div, false)) }
-        else if items.i128_rem_fn() == def_id { Some((mir::BinOp::Rem, false)) }
-        else if items.u128_rem_fn() == def_id { Some((mir::BinOp::Rem, false)) }
-        else if items.i128_shl_fn() == def_id { Some((mir::BinOp::Shl, false)) }
-        else if items.u128_shl_fn() == def_id { Some((mir::BinOp::Shl, false)) }
-        else if items.i128_shr_fn() == def_id { Some((mir::BinOp::Shr, false)) }
-        else if items.u128_shr_fn() == def_id { Some((mir::BinOp::Shr, false)) }
-        else if items.i128_addo_fn() == def_id { Some((mir::BinOp::Add, true)) }
-        else if items.u128_addo_fn() == def_id { Some((mir::BinOp::Add, true)) }
-        else if items.i128_subo_fn() == def_id { Some((mir::BinOp::Sub, true)) }
-        else if items.u128_subo_fn() == def_id { Some((mir::BinOp::Sub, true)) }
-        else if items.i128_mulo_fn() == def_id { Some((mir::BinOp::Mul, true)) }
-        else if items.u128_mulo_fn() == def_id { Some((mir::BinOp::Mul, true)) }
-        else if items.i128_shlo_fn() == def_id { Some((mir::BinOp::Shl, true)) }
-        else if items.u128_shlo_fn() == def_id { Some((mir::BinOp::Shl, true)) }
-        else if items.i128_shro_fn() == def_id { Some((mir::BinOp::Shr, true)) }
-        else if items.u128_shro_fn() == def_id { Some((mir::BinOp::Shr, true)) }
-        else { None }
-    }
-
-    fn store(&mut self,
-             dest: &mir::Place<'tcx>,
-             value: Result<Const<'tcx>, ConstEvalErr<'tcx>>,
-             span: Span) {
-        if let mir::Place::Local(index) = *dest {
-            self.locals[index] = Some(value);
-        } else {
-            span_bug!(span, "assignment to {:?} in constant", dest);
-        }
-    }
-
-    fn const_place(&self, place: &mir::Place<'tcx>, span: Span)
-                    -> Result<ConstPlace<'tcx>, ConstEvalErr<'tcx>> {
-        let tcx = self.cx.tcx;
-
-        if let mir::Place::Local(index) = *place {
-            return self.locals[index].clone().unwrap_or_else(|| {
-                span_bug!(span, "{:?} not initialized", place)
-            }).map(|v| v.as_place());
-        }
-
-        let place = match *place {
-            mir::Place::Local(_)  => bug!(), // handled above
-            mir::Place::Static(box mir::Static { def_id, ty }) => {
-                ConstPlace {
-                    base: Base::Static(consts::get_static(self.cx, def_id)),
-                    llextra: ptr::null_mut(),
-                    ty: self.monomorphize(&ty),
-                }
-            }
-            mir::Place::Projection(ref projection) => {
-                let tr_base = self.const_place(&projection.base, span)?;
-                let projected_ty = PlaceTy::Ty { ty: tr_base.ty }
-                    .projection_ty(tcx, &projection.elem);
-                let base = tr_base.to_const(span);
-                let projected_ty = self.monomorphize(&projected_ty).to_ty(tcx);
-                let has_metadata = self.cx.type_has_metadata(projected_ty);
-
-                let (projected, llextra) = match projection.elem {
-                    mir::ProjectionElem::Deref => {
-                        let (base, extra) = if !has_metadata {
-                            (base.llval, ptr::null_mut())
-                        } else {
-                            base.get_fat_ptr(self.cx)
-                        };
-                        if self.cx.statics.borrow().contains_key(&base) {
-                            (Base::Static(base), extra)
-                        } else if let ty::TyStr = projected_ty.sty {
-                            (Base::Str(base), extra)
-                        } else {
-                            let v = base;
-                            let v = self.cx.const_unsized.borrow().get(&v).map_or(v, |&v| v);
-                            let mut val = unsafe { llvm::LLVMGetInitializer(v) };
-                            if val.is_null() {
-                                span_bug!(span, "dereference of non-constant pointer `{:?}`",
-                                          Value(base));
-                            }
-                            let layout = self.cx.layout_of(projected_ty);
-                            if let layout::Abi::Scalar(ref scalar) = layout.abi {
-                                let i1_type = Type::i1(self.cx);
-                                if scalar.is_bool() && val_ty(val) != i1_type {
-                                    unsafe {
-                                        val = llvm::LLVMConstTrunc(val, i1_type.to_ref());
-                                    }
-                                }
-                            }
-                            (Base::Value(val), extra)
-                        }
-                    }
-                    mir::ProjectionElem::Field(ref field, _) => {
-                        let llprojected = base.get_field(self.cx, field.index());
-                        let llextra = if !has_metadata {
-                            ptr::null_mut()
-                        } else {
-                            tr_base.llextra
-                        };
-                        (Base::Value(llprojected), llextra)
-                    }
-                    mir::ProjectionElem::Index(index) => {
-                        let index = &mir::Operand::Copy(mir::Place::Local(index));
-                        let llindex = self.const_operand(index, span)?.llval;
-
-                        let iv = if let Some(iv) = common::const_to_opt_u128(llindex, false) {
-                            iv
-                        } else {
-                            span_bug!(span, "index is not an integer-constant expression")
-                        };
-
-                        // Produce an undef instead of a LLVM assertion on OOB.
-                        let len = common::const_to_uint(tr_base.len(self.cx));
-                        let llelem = if iv < len as u128 {
-                            const_get_elt(base.llval, iv as u64)
-                        } else {
-                            C_undef(self.cx.layout_of(projected_ty).llvm_type(self.cx))
-                        };
-
-                        (Base::Value(llelem), ptr::null_mut())
-                    }
-                    _ => span_bug!(span, "{:?} in constant", projection.elem)
-                };
-                ConstPlace {
-                    base: projected,
-                    llextra,
-                    ty: projected_ty
-                }
-            }
-        };
-        Ok(place)
-    }
-
-    fn const_operand(&self, operand: &mir::Operand<'tcx>, span: Span)
-                     -> Result<Const<'tcx>, ConstEvalErr<'tcx>> {
-        debug!("const_operand({:?} @ {:?})", operand, span);
-        let result = match *operand {
-            mir::Operand::Copy(ref place) |
-            mir::Operand::Move(ref place) => {
-                Ok(self.const_place(place, span)?.to_const(span))
-            }
-
-            mir::Operand::Constant(ref constant) => {
-                let ty = self.monomorphize(&constant.ty);
-                match constant.literal.clone() {
-                    mir::Literal::Promoted { index } => {
-                        let mir = &self.mir.promoted[index];
-                        MirConstContext::new(self.cx, mir, self.substs, IndexVec::new()).trans()
-                    }
-                    mir::Literal::Value { value } => {
-                        if let ConstVal::Unevaluated(def_id, substs) = value.val {
-                            let substs = self.monomorphize(&substs);
-                            MirConstContext::trans_def(self.cx, def_id, substs, IndexVec::new())
-                        } else {
-                            Ok(Const::from_constval(self.cx, &value.val, ty))
-                        }
-                    }
-                }
-            }
-        };
-        debug!("const_operand({:?} @ {:?}) = {:?}", operand, span,
-               result.as_ref().ok());
-        result
-    }
-
-    fn const_array(&self, array_ty: Ty<'tcx>, fields: &[ValueRef])
-                   -> Const<'tcx>
-    {
-        let elem_ty = array_ty.builtin_index().unwrap_or_else(|| {
-            bug!("bad array type {:?}", array_ty)
-        });
-        let llunitty = self.cx.layout_of(elem_ty).llvm_type(self.cx);
-        // If the array contains enums, an LLVM array won't work.
-        let val = if fields.iter().all(|&f| val_ty(f) == llunitty) {
-            C_array(llunitty, fields)
-        } else {
-            C_struct(self.cx, fields, false)
-        };
-        Const::new(val, array_ty)
-    }
-
-    fn const_rvalue(&self, rvalue: &mir::Rvalue<'tcx>,
-                    dest_ty: Ty<'tcx>, span: Span)
-                    -> Result<Const<'tcx>, ConstEvalErr<'tcx>> {
-        let tcx = self.cx.tcx;
-        debug!("const_rvalue({:?}: {:?} @ {:?})", rvalue, dest_ty, span);
-        let val = match *rvalue {
-            mir::Rvalue::Use(ref operand) => self.const_operand(operand, span)?,
-
-            mir::Rvalue::Repeat(ref elem, count) => {
-                let elem = self.const_operand(elem, span)?;
-                let size = count.as_u64();
-                assert_eq!(size as usize as u64, size);
-                let fields = vec![elem.llval; size as usize];
-                self.const_array(dest_ty, &fields)
-            }
-
-            mir::Rvalue::Aggregate(box mir::AggregateKind::Array(_), ref operands) => {
-                // Make sure to evaluate all operands to
-                // report as many errors as we possibly can.
-                let mut fields = Vec::with_capacity(operands.len());
-                let mut failure = Ok(());
-                for operand in operands {
-                    match self.const_operand(operand, span) {
-                        Ok(val) => fields.push(val.llval),
-                        Err(err) => if failure.is_ok() { failure = Err(err); }
-                    }
-                }
-                failure?;
-
-                self.const_array(dest_ty, &fields)
-            }
-
-            mir::Rvalue::Aggregate(ref kind, ref operands) => {
-                // Make sure to evaluate all operands to
-                // report as many errors as we possibly can.
-                let mut fields = Vec::with_capacity(operands.len());
-                let mut failure = Ok(());
-                for operand in operands {
-                    match self.const_operand(operand, span) {
-                        Ok(val) => fields.push(val),
-                        Err(err) => if failure.is_ok() { failure = Err(err); }
-                    }
-                }
-                failure?;
-
-                trans_const_adt(self.cx, dest_ty, kind, &fields)
-            }
-
-            mir::Rvalue::Cast(ref kind, ref source, cast_ty) => {
-                let operand = self.const_operand(source, span)?;
-                let cast_ty = self.monomorphize(&cast_ty);
-
-                let val = match *kind {
-                    mir::CastKind::ReifyFnPointer => {
-                        match operand.ty.sty {
-                            ty::TyFnDef(def_id, substs) => {
-                                if tcx.has_attr(def_id, "rustc_args_required_const") {
-                                    bug!("reifying a fn ptr that requires \
-                                          const arguments");
-                                }
-                                callee::resolve_and_get_fn(self.cx, def_id, substs)
-                            }
-                            _ => {
-                                span_bug!(span, "{} cannot be reified to a fn ptr",
-                                          operand.ty)
-                            }
-                        }
-                    }
-                    mir::CastKind::ClosureFnPointer => {
-                        match operand.ty.sty {
-                            ty::TyClosure(def_id, substs) => {
-                                // Get the def_id for FnOnce::call_once
-                                let fn_once = tcx.lang_items().fn_once_trait().unwrap();
-                                let call_once = tcx
-                                    .global_tcx().associated_items(fn_once)
-                                    .find(|it| it.kind == ty::AssociatedKind::Method)
-                                    .unwrap().def_id;
-                                // Now create its substs [Closure, Tuple]
-                                let input = substs.closure_sig(def_id, tcx).input(0);
-                                let input = tcx.erase_late_bound_regions_and_normalize(&input);
-                                let substs = tcx.mk_substs([operand.ty, input]
-                                    .iter().cloned().map(Kind::from));
-                                callee::resolve_and_get_fn(self.cx, call_once, substs)
-                            }
-                            _ => {
-                                bug!("{} cannot be cast to a fn ptr", operand.ty)
-                            }
-                        }
+                        consts::addr_of(cx, init, alloc.align, "byte_str")
                     }
-                    mir::CastKind::UnsafeFnPointer => {
-                        // this is a no-op at the LLVM level
-                        operand.llval
-                    }
-                    mir::CastKind::Unsize => {
-                        let pointee_ty = operand.ty.builtin_deref(true)
-                            .expect("consts: unsizing got non-pointer type").ty;
-                        let (base, old_info) = if !self.cx.type_is_sized(pointee_ty) {
-                            // Normally, the source is a thin pointer and we are
-                            // adding extra info to make a fat pointer. The exception
-                            // is when we are upcasting an existing object fat pointer
-                            // to use a different vtable. In that case, we want to
-                            // load out the original data pointer so we can repackage
-                            // it.
-                            let (base, extra) = operand.get_fat_ptr(self.cx);
-                            (base, Some(extra))
-                        } else {
-                            (operand.llval, None)
-                        };
-
-                        let unsized_ty = cast_ty.builtin_deref(true)
-                            .expect("consts: unsizing got non-pointer target type").ty;
-                        let ptr_ty = self.cx.layout_of(unsized_ty).llvm_type(self.cx).ptr_to();
-                        let base = consts::ptrcast(base, ptr_ty);
-                        let info = base::unsized_info(self.cx, pointee_ty,
-                                                      unsized_ty, old_info);
-
-                        if old_info.is_none() {
-                            let prev_const = self.cx.const_unsized.borrow_mut()
-                                                     .insert(base, operand.llval);
-                            assert!(prev_const.is_none() || prev_const == Some(operand.llval));
-                        }
-                        C_fat_ptr(self.cx, base, info)
-                    }
-                    mir::CastKind::Misc if self.cx.layout_of(operand.ty).is_llvm_immediate() => {
-                        let r_t_in = CastTy::from_ty(operand.ty).expect("bad input type for cast");
-                        let r_t_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
-                        let cast_layout = self.cx.layout_of(cast_ty);
-                        assert!(cast_layout.is_llvm_immediate());
-                        let ll_t_out = cast_layout.immediate_llvm_type(self.cx);
-                        let llval = operand.llval;
-
-                        let mut signed = false;
-                        let l = self.cx.layout_of(operand.ty);
-                        if let layout::Abi::Scalar(ref scalar) = l.abi {
-                            if let layout::Int(_, true) = scalar.value {
-                                signed = true;
-                            }
-                        }
-
-                        unsafe {
-                            match (r_t_in, r_t_out) {
-                                (CastTy::Int(_), CastTy::Int(_)) => {
-                                    let s = signed as llvm::Bool;
-                                    llvm::LLVMConstIntCast(llval, ll_t_out.to_ref(), s)
-                                }
-                                (CastTy::Int(_), CastTy::Float) => {
-                                    cast_const_int_to_float(self.cx, llval, signed, ll_t_out)
-                                }
-                                (CastTy::Float, CastTy::Float) => {
-                                    llvm::LLVMConstFPCast(llval, ll_t_out.to_ref())
-                                }
-                                (CastTy::Float, CastTy::Int(IntTy::I)) => {
-                                    cast_const_float_to_int(self.cx, &operand,
-                                                            true, ll_t_out, span)
-                                }
-                                (CastTy::Float, CastTy::Int(_)) => {
-                                    cast_const_float_to_int(self.cx, &operand,
-                                                            false, ll_t_out, span)
-                                }
-                                (CastTy::Ptr(_), CastTy::Ptr(_)) |
-                                (CastTy::FnPtr, CastTy::Ptr(_)) |
-                                (CastTy::RPtr(_), CastTy::Ptr(_)) => {
-                                    consts::ptrcast(llval, ll_t_out)
-                                }
-                                (CastTy::Int(_), CastTy::Ptr(_)) => {
-                                    let s = signed as llvm::Bool;
-                                    let usize_llval = llvm::LLVMConstIntCast(llval,
-                                        self.cx.isize_ty.to_ref(), s);
-                                    llvm::LLVMConstIntToPtr(usize_llval, ll_t_out.to_ref())
-                                }
-                                (CastTy::Ptr(_), CastTy::Int(_)) |
-                                (CastTy::FnPtr, CastTy::Int(_)) => {
-                                    llvm::LLVMConstPtrToInt(llval, ll_t_out.to_ref())
-                                }
-                                _ => bug!("unsupported cast: {:?} to {:?}", operand.ty, cast_ty)
-                            }
-                        }
-                    }
-                    mir::CastKind::Misc => { // Casts from a fat-ptr.
-                        let l = self.cx.layout_of(operand.ty);
-                        let cast = self.cx.layout_of(cast_ty);
-                        if l.is_llvm_scalar_pair() {
-                            let (data_ptr, meta) = operand.get_fat_ptr(self.cx);
-                            if cast.is_llvm_scalar_pair() {
-                                let data_cast = consts::ptrcast(data_ptr,
-                                    cast.scalar_pair_element_llvm_type(self.cx, 0));
-                                C_fat_ptr(self.cx, data_cast, meta)
-                            } else { // cast to thin-ptr
-                                // Cast of fat-ptr to thin-ptr is an extraction of data-ptr and
-                                // pointer-cast of that pointer to desired pointer type.
-                                let llcast_ty = cast.immediate_llvm_type(self.cx);
-                                consts::ptrcast(data_ptr, llcast_ty)
-                            }
-                        } else {
-                            bug!("Unexpected non-fat-pointer operand")
-                        }
-                    }
-                };
-                Const::new(val, cast_ty)
-            }
-
-            mir::Rvalue::Ref(_, bk, ref place) => {
-                let tr_place = self.const_place(place, span)?;
-
-                let ty = tr_place.ty;
-                let ref_ty = tcx.mk_ref(tcx.types.re_erased,
-                    ty::TypeAndMut { ty: ty, mutbl: bk.to_mutbl_lossy() });
-
-                let base = match tr_place.base {
-                    Base::Value(llval) => {
-                        // FIXME: may be wrong for &*(&simd_vec as &fmt::Debug)
-                        let align = if self.cx.type_is_sized(ty) {
-                            self.cx.align_of(ty)
-                        } else {
-                            self.cx.tcx.data_layout.pointer_align
-                        };
-                        if let mir::BorrowKind::Mut { .. } = bk {
-                            consts::addr_of_mut(self.cx, llval, align, "ref_mut")
-                        } else {
-                            consts::addr_of(self.cx, llval, align, "ref")
-                        }
-                    }
-                    Base::Str(llval) |
-                    Base::Static(llval) => llval
-                };
-
-                let ptr = if self.cx.type_is_sized(ty) {
-                    base
                 } else {
-                    C_fat_ptr(self.cx, base, tr_place.llextra)
+                    bug!("missing allocation {:?}", ptr.alloc_id);
                 };
-                Const::new(ptr, ref_ty)
-            }
-
-            mir::Rvalue::Len(ref place) => {
-                let tr_place = self.const_place(place, span)?;
-                Const::new(tr_place.len(self.cx), tcx.types.usize)
-            }
-
-            mir::Rvalue::BinaryOp(op, ref lhs, ref rhs) => {
-                let lhs = self.const_operand(lhs, span)?;
-                let rhs = self.const_operand(rhs, span)?;
-                let ty = lhs.ty;
-                let binop_ty = op.ty(tcx, lhs.ty, rhs.ty);
-                let (lhs, rhs) = (lhs.llval, rhs.llval);
-                Const::new(const_scalar_binop(op, lhs, rhs, ty), binop_ty)
-            }
-
-            mir::Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) => {
-                let lhs = self.const_operand(lhs, span)?;
-                let rhs = self.const_operand(rhs, span)?;
-                let ty = lhs.ty;
-                let val_ty = op.ty(tcx, lhs.ty, rhs.ty);
-                let binop_ty = tcx.intern_tup(&[val_ty, tcx.types.bool], false);
-                let (lhs, rhs) = (lhs.llval, rhs.llval);
-                assert!(!ty.is_fp());
-
-                match const_scalar_checked_binop(tcx, op, lhs, rhs, ty) {
-                    Some((llval, of)) => {
-                        trans_const_adt(self.cx, binop_ty, &mir::AggregateKind::Tuple, &[
-                            Const::new(llval, val_ty),
-                            Const::new(C_bool(self.cx, of), tcx.types.bool)
-                        ])
-                    }
-                    None => {
-                        span_bug!(span, "{:?} got non-integer operands: {:?} and {:?}",
-                                  rvalue, Value(lhs), Value(rhs));
-                    }
-                }
-            }
-
-            mir::Rvalue::UnaryOp(op, ref operand) => {
-                let operand = self.const_operand(operand, span)?;
-                let lloperand = operand.llval;
-                let llval = match op {
-                    mir::UnOp::Not => {
-                        unsafe {
-                            llvm::LLVMConstNot(lloperand)
-                        }
-                    }
-                    mir::UnOp::Neg => {
-                        let is_float = operand.ty.is_fp();
-                        unsafe {
-                            if is_float {
-                                llvm::LLVMConstFNeg(lloperand)
-                            } else {
-                                llvm::LLVMConstNeg(lloperand)
-                            }
-                        }
-                    }
-                };
-                Const::new(llval, operand.ty)
-            }
-
-            mir::Rvalue::NullaryOp(mir::NullOp::SizeOf, ty) => {
-                assert!(self.cx.type_is_sized(ty));
-                let llval = C_usize(self.cx, self.cx.size_of(ty).bytes());
-                Const::new(llval, tcx.types.usize)
-            }
-
-            _ => span_bug!(span, "{:?} in constant", rvalue)
-        };
-
-        debug!("const_rvalue({:?}: {:?} @ {:?}) = {:?}", rvalue, dest_ty, span, val);
-
-        Ok(val)
-    }
-
-}
-
-fn to_const_int(value: ValueRef, t: Ty, tcx: TyCtxt) -> Option<ConstInt> {
-    match t.sty {
-        ty::TyInt(int_type) => const_to_opt_u128(value, true)
-            .and_then(|input| ConstInt::new_signed(input as i128, int_type,
-                                                   tcx.sess.target.isize_ty)),
-        ty::TyUint(uint_type) => const_to_opt_u128(value, false)
-            .and_then(|input| ConstInt::new_unsigned(input, uint_type,
-                                                     tcx.sess.target.usize_ty)),
-        _ => None
-
-    }
-}
-
-pub fn const_scalar_binop(op: mir::BinOp,
-                          lhs: ValueRef,
-                          rhs: ValueRef,
-                          input_ty: Ty) -> ValueRef {
-    assert!(!input_ty.is_simd());
-    let is_float = input_ty.is_fp();
-    let signed = input_ty.is_signed();
-
-    unsafe {
-        match op {
-            mir::BinOp::Add if is_float => llvm::LLVMConstFAdd(lhs, rhs),
-            mir::BinOp::Add             => llvm::LLVMConstAdd(lhs, rhs),
-
-            mir::BinOp::Sub if is_float => llvm::LLVMConstFSub(lhs, rhs),
-            mir::BinOp::Sub             => llvm::LLVMConstSub(lhs, rhs),
-
-            mir::BinOp::Mul if is_float => llvm::LLVMConstFMul(lhs, rhs),
-            mir::BinOp::Mul             => llvm::LLVMConstMul(lhs, rhs),
 
-            mir::BinOp::Div if is_float => llvm::LLVMConstFDiv(lhs, rhs),
-            mir::BinOp::Div if signed   => llvm::LLVMConstSDiv(lhs, rhs),
-            mir::BinOp::Div             => llvm::LLVMConstUDiv(lhs, rhs),
-
-            mir::BinOp::Rem if is_float => llvm::LLVMConstFRem(lhs, rhs),
-            mir::BinOp::Rem if signed   => llvm::LLVMConstSRem(lhs, rhs),
-            mir::BinOp::Rem             => llvm::LLVMConstURem(lhs, rhs),
-
-            mir::BinOp::BitXor => llvm::LLVMConstXor(lhs, rhs),
-            mir::BinOp::BitAnd => llvm::LLVMConstAnd(lhs, rhs),
-            mir::BinOp::BitOr  => llvm::LLVMConstOr(lhs, rhs),
-            mir::BinOp::Shl    => {
-                let rhs = base::cast_shift_const_rhs(op.to_hir_binop(), lhs, rhs);
-                llvm::LLVMConstShl(lhs, rhs)
-            }
-            mir::BinOp::Shr    => {
-                let rhs = base::cast_shift_const_rhs(op.to_hir_binop(), lhs, rhs);
-                if signed { llvm::LLVMConstAShr(lhs, rhs) }
-                else      { llvm::LLVMConstLShr(lhs, rhs) }
-            }
-            mir::BinOp::Eq | mir::BinOp::Ne |
-            mir::BinOp::Lt | mir::BinOp::Le |
-            mir::BinOp::Gt | mir::BinOp::Ge => {
-                if is_float {
-                    let cmp = base::bin_op_to_fcmp_predicate(op.to_hir_binop());
-                    llvm::LLVMConstFCmp(cmp, lhs, rhs)
+                let llval = unsafe { llvm::LLVMConstInBoundsGEP(
+                    consts::bitcast(base_addr, Type::i8p(cx)),
+                    &C_usize(cx, ptr.offset),
+                    1,
+                ) };
+                if scalar.value != layout::Pointer {
+                    unsafe { llvm::LLVMConstPtrToInt(llval, llty.to_ref()) }
                 } else {
-                    let cmp = base::bin_op_to_icmp_predicate(op.to_hir_binop(),
-                                                                signed);
-                    llvm::LLVMConstICmp(cmp, lhs, rhs)
+                    consts::bitcast(llval, llty)
                 }
             }
-            mir::BinOp::Offset => unreachable!("BinOp::Offset in const-eval!")
         }
     }
 }
 
-pub fn const_scalar_checked_binop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                            op: mir::BinOp,
-                                            lllhs: ValueRef,
-                                            llrhs: ValueRef,
-                                            input_ty: Ty<'tcx>)
-                                            -> Option<(ValueRef, bool)> {
-    if let (Some(lhs), Some(rhs)) = (to_const_int(lllhs, input_ty, tcx),
-                                     to_const_int(llrhs, input_ty, tcx)) {
-        let result = match op {
-            mir::BinOp::Add => lhs + rhs,
-            mir::BinOp::Sub => lhs - rhs,
-            mir::BinOp::Mul => lhs * rhs,
-            mir::BinOp::Shl => lhs << rhs,
-            mir::BinOp::Shr => lhs >> rhs,
-            _ => {
-                bug!("Operator `{:?}` is not a checkable operator", op)
-            }
-        };
+pub fn global_initializer(cx: &CodegenCx, alloc: &Allocation) -> ValueRef {
+    let mut llvals = Vec::with_capacity(alloc.relocations.len() + 1);
+    let layout = cx.data_layout();
+    let pointer_size = layout.pointer_size.bytes() as usize;
 
-        let of = match result {
-            Ok(_) => false,
-            Err(ConstMathErr::Overflow(_)) |
-            Err(ConstMathErr::ShiftNegative) => true,
-            Err(err) => {
-                bug!("Operator `{:?}` on `{:?}` and `{:?}` errored: {}",
-                     op, lhs, rhs, err.description());
-            }
-        };
-
-        Some((const_scalar_binop(op, lllhs, llrhs, input_ty), of))
-    } else {
-        None
+    let mut next_offset = 0;
+    for (&offset, &alloc_id) in &alloc.relocations {
+        assert_eq!(offset as usize as u64, offset);
+        let offset = offset as usize;
+        if offset > next_offset {
+            llvals.push(C_bytes(cx, &alloc.bytes[next_offset..offset]));
+        }
+        let ptr_offset = read_target_uint(
+            layout.endian,
+            &alloc.bytes[offset..(offset + pointer_size)],
+        ).expect("global_initializer: could not read relocation pointer") as u64;
+        llvals.push(primval_to_llvm(
+            cx,
+            PrimVal::Ptr(MemoryPointer { alloc_id, offset: ptr_offset }),
+            &Scalar {
+                value: layout::Primitive::Pointer,
+                valid_range: 0..=!0
+            },
+            Type::i8p(cx)
+        ));
+        next_offset = offset + pointer_size;
     }
-}
-
-unsafe fn cast_const_float_to_int(cx: &CodegenCx,
-                                  operand: &Const,
-                                  signed: bool,
-                                  int_ty: Type,
-                                  span: Span) -> ValueRef {
-    let llval = operand.llval;
-    let float_bits = match operand.ty.sty {
-        ty::TyFloat(fty) => fty.bit_width(),
-        _ => bug!("cast_const_float_to_int: operand not a float"),
-    };
-    // Note: this breaks if llval is a complex constant expression rather than a simple constant.
-    // One way that might happen would be if addresses could be turned into integers in constant
-    // expressions, but that doesn't appear to be possible?
-    // In any case, an ICE is better than producing undef.
-    let llval_bits = consts::bitcast(llval, Type::ix(cx, float_bits as u64));
-    let bits = const_to_opt_u128(llval_bits, false).unwrap_or_else(|| {
-        panic!("could not get bits of constant float {:?}",
-               Value(llval));
-    });
-    let int_width = int_ty.int_width() as usize;
-    // Try to convert, but report an error for overflow and NaN. This matches HIR const eval.
-    let cast_result = match float_bits {
-        32 if signed => ieee::Single::from_bits(bits).to_i128(int_width).map(|v| v as u128),
-        64 if signed => ieee::Double::from_bits(bits).to_i128(int_width).map(|v| v as u128),
-        32 => ieee::Single::from_bits(bits).to_u128(int_width),
-        64 => ieee::Double::from_bits(bits).to_u128(int_width),
-        n => bug!("unsupported float width {}", n),
-    };
-    if cast_result.status.contains(Status::INVALID_OP) {
-        let err = ConstEvalErr { span: span, kind: ErrKind::CannotCast };
-        err.report(cx.tcx, span, "expression");
+    if alloc.bytes.len() >= next_offset {
+        llvals.push(C_bytes(cx, &alloc.bytes[next_offset ..]));
     }
-    C_uint_big(int_ty, cast_result.value)
-}
 
-unsafe fn cast_const_int_to_float(cx: &CodegenCx,
-                                  llval: ValueRef,
-                                  signed: bool,
-                                  float_ty: Type) -> ValueRef {
-    // Note: this breaks if llval is a complex constant expression rather than a simple constant.
-    // One way that might happen would be if addresses could be turned into integers in constant
-    // expressions, but that doesn't appear to be possible?
-    // In any case, an ICE is better than producing undef.
-    let value = const_to_opt_u128(llval, signed).unwrap_or_else(|| {
-        panic!("could not get z128 value of constant integer {:?}",
-               Value(llval));
-    });
-    if signed {
-        llvm::LLVMConstSIToFP(llval, float_ty.to_ref())
-    } else if float_ty.float_width() == 32 && value >= MAX_F32_PLUS_HALF_ULP {
-        // We're casting to f32 and the value is > f32::MAX + 0.5 ULP -> round up to infinity.
-        let infinity_bits = C_u32(cx, ieee::Single::INFINITY.to_bits() as u32);
-        consts::bitcast(infinity_bits, float_ty)
-    } else {
-        llvm::LLVMConstUIToFP(llval, float_ty.to_ref())
-    }
+    C_struct(cx, &llvals, true)
 }
 
-impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
-    pub fn trans_constant(&mut self,
-                          bx: &Builder<'a, 'tcx>,
-                          constant: &mir::Constant<'tcx>)
-                          -> Const<'tcx>
-    {
-        debug!("trans_constant({:?})", constant);
-        let ty = self.monomorphize(&constant.ty);
-        let result = match constant.literal.clone() {
-            mir::Literal::Promoted { index } => {
-                let mir = &self.mir.promoted[index];
-                MirConstContext::new(bx.cx, mir, self.param_substs, IndexVec::new()).trans()
-            }
-            mir::Literal::Value { value } => {
-                if let ConstVal::Unevaluated(def_id, substs) = value.val {
-                    let substs = self.monomorphize(&substs);
-                    MirConstContext::trans_def(bx.cx, def_id, substs, IndexVec::new())
-                } else {
-                    Ok(Const::from_constval(bx.cx, &value.val, ty))
-                }
-            }
-        };
-
-        let result = result.unwrap_or_else(|_| {
-            // We've errored, so we don't have to produce working code.
-            let llty = bx.cx.layout_of(ty).llvm_type(bx.cx);
-            Const::new(C_undef(llty), ty)
-        });
-
-        debug!("trans_constant({:?}) = {:?}", constant, result);
-        result
-    }
-}
-
-
 pub fn trans_static_initializer<'a, 'tcx>(
     cx: &CodegenCx<'a, 'tcx>,
     def_id: DefId)
     -> Result<ValueRef, ConstEvalErr<'tcx>>
 {
-    MirConstContext::trans_def(cx, def_id, Substs::empty(), 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_adt<'a, 'tcx>(
-    cx: &CodegenCx<'a, 'tcx>,
-    t: Ty<'tcx>,
-    kind: &mir::AggregateKind,
-    vals: &[Const<'tcx>]
-) -> Const<'tcx> {
-    let l = cx.layout_of(t);
-    let variant_index = match *kind {
-        mir::AggregateKind::Adt(_, index, _, _) => index,
-        _ => 0,
+    let instance = ty::Instance::mono(cx.tcx, def_id);
+    let cid = GlobalId {
+        instance,
+        promoted: None
     };
+    let param_env = ty::ParamEnv::reveal_all();
+    cx.tcx.const_eval(param_env.and(cid))?;
 
-    if let layout::Abi::Uninhabited = l.abi {
-        return Const::new(C_undef(l.llvm_type(cx)), t);
-    }
+    let alloc_id = cx
+        .tcx
+        .interpret_interner
+        .get_cached(def_id)
+        .expect("global not cached");
 
-    match l.variants {
-        layout::Variants::Single { index } => {
-            assert_eq!(variant_index, index);
-            if let layout::FieldPlacement::Union(_) = l.fields {
-                assert_eq!(variant_index, 0);
-                assert_eq!(vals.len(), 1);
-                let (field_size, field_align) = cx.size_and_align_of(vals[0].ty);
-                let contents = [
-                    vals[0].llval,
-                    padding(cx, l.size - field_size)
-                ];
+    let alloc = cx
+        .tcx
+        .interpret_interner
+        .get_alloc(alloc_id)
+        .expect("miri allocation never successfully created");
+    Ok(global_initializer(cx, alloc))
+}
 
-                let packed = l.align.abi() < field_align.abi();
-                Const::new(C_struct(cx, &contents, packed), t)
-            } else {
-                if let layout::Abi::Vector { .. } = l.abi {
-                    if let layout::FieldPlacement::Array { .. } = l.fields {
-                        return Const::new(C_vector(&vals.iter().map(|x| x.llval)
-                            .collect::<Vec<_>>()), t);
-                    }
-                }
-                build_const_struct(cx, l, vals, None)
-            }
-        }
-        layout::Variants::Tagged { .. } => {
-            let discr = match *kind {
-                mir::AggregateKind::Adt(adt_def, _, _, _) => {
-                    adt_def.discriminant_for_variant(cx.tcx, variant_index)
-                           .to_u128_unchecked() as u64
-                },
-                _ => 0,
-            };
-            let discr_field = l.field(cx, 0);
-            let discr = C_int(discr_field.llvm_type(cx), discr as i64);
-            if let layout::Abi::Scalar(_) = l.abi {
-                Const::new(discr, t)
-            } else {
-                let discr = Const::new(discr, discr_field.ty);
-                build_const_struct(cx, l.for_variant(cx, variant_index), vals, Some(discr))
-            }
-        }
-        layout::Variants::NicheFilling {
-            dataful_variant,
-            ref niche_variants,
-            niche_start,
-            ..
-        } => {
-            if variant_index == dataful_variant {
-                build_const_struct(cx, l.for_variant(cx, dataful_variant), vals, None)
-            } else {
-                let niche = l.field(cx, 0);
-                let niche_llty = niche.llvm_type(cx);
-                let niche_value = ((variant_index - niche_variants.start) as u128)
-                    .wrapping_add(niche_start);
-                // FIXME(eddyb) Check the actual primitive type here.
-                let niche_llval = if niche_value == 0 {
-                    // HACK(eddyb) Using `C_null` as it works on all types.
-                    C_null(niche_llty)
-                } else {
-                    C_uint_big(niche_llty, niche_value)
+impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
+    fn const_to_miri_value(
+        &mut self,
+        bx: &Builder<'a, 'tcx>,
+        constant: &'tcx ty::Const<'tcx>,
+    ) -> Result<MiriValue, ConstEvalErr<'tcx>> {
+        match constant.val {
+            ConstVal::Unevaluated(def_id, ref substs) => {
+                let tcx = bx.tcx();
+                let param_env = ty::ParamEnv::reveal_all();
+                let instance = ty::Instance::resolve(tcx, param_env, def_id, substs).unwrap();
+                let cid = GlobalId {
+                    instance,
+                    promoted: None,
                 };
-                build_const_struct(cx, l, &[Const::new(niche_llval, niche.ty)], None)
-            }
+                let c = tcx.const_eval(param_env.and(cid))?;
+                self.const_to_miri_value(bx, c)
+            },
+            ConstVal::Value(miri_val) => Ok(miri_val),
         }
     }
-}
-
-/// 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_adt`, 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>(cx: &CodegenCx<'a, 'tcx>,
-                                layout: layout::TyLayout<'tcx>,
-                                vals: &[Const<'tcx>],
-                                discr: Option<Const<'tcx>>)
-                                -> Const<'tcx> {
-    assert_eq!(vals.len(), layout.fields.count());
 
-    match layout.abi {
-        layout::Abi::Scalar(_) |
-        layout::Abi::ScalarPair(..) |
-        layout::Abi::Vector { .. } if discr.is_none() => {
-            let mut non_zst_fields = vals.iter().enumerate().map(|(i, f)| {
-                (f, layout.fields.offset(i))
-            }).filter(|&(f, _)| !cx.layout_of(f.ty).is_zst());
-            match (non_zst_fields.next(), non_zst_fields.next()) {
-                (Some((x, offset)), None) if offset.bytes() == 0 => {
-                    return Const::new(x.llval, layout.ty);
-                }
-                (Some((a, a_offset)), Some((b, _))) if a_offset.bytes() == 0 => {
-                    return Const::new(C_struct(cx, &[a.llval, b.llval], false), layout.ty);
-                }
-                (Some((a, _)), Some((b, b_offset))) if b_offset.bytes() == 0 => {
-                    return Const::new(C_struct(cx, &[b.llval, a.llval], false), layout.ty);
-                }
-                _ => {}
+    pub fn mir_constant_to_miri_value(
+        &mut self,
+        bx: &Builder<'a, 'tcx>,
+        constant: &mir::Constant<'tcx>,
+    ) -> Result<MiriValue, ConstEvalErr<'tcx>> {
+        match constant.literal {
+            mir::Literal::Promoted { index } => {
+                let param_env = ty::ParamEnv::reveal_all();
+                let cid = mir::interpret::GlobalId {
+                    instance: self.instance,
+                    promoted: Some(index),
+                };
+                bx.tcx().const_eval(param_env.and(cid))
             }
-        }
-        _ => {}
-    }
-
-    // offset of current value
-    let mut packed = false;
-    let mut offset = Size::from_bytes(0);
-    let mut cfields = Vec::new();
-    cfields.reserve(discr.is_some() as usize + 1 + layout.fields.count() * 2);
-
-    if let Some(discr) = discr {
-        let (field_size, field_align) = cx.size_and_align_of(discr.ty);
-        packed |= layout.align.abi() < field_align.abi();
-        cfields.push(discr.llval);
-        offset = field_size;
-    }
-
-    let parts = layout.fields.index_by_increasing_offset().map(|i| {
-        (vals[i], layout.fields.offset(i))
-    });
-    for (val, target_offset) in parts {
-        let (field_size, field_align) = cx.size_and_align_of(val.ty);
-        packed |= layout.align.abi() < field_align.abi();
-        cfields.push(padding(cx, target_offset - offset));
-        cfields.push(val.llval);
-        offset = target_offset + field_size;
+            mir::Literal::Value { value } => {
+                Ok(self.monomorphize(&value))
+            }
+        }.and_then(|c| self.const_to_miri_value(bx, c))
+    }
+
+    /// process constant containing SIMD shuffle indices
+    pub fn simd_shuffle_indices(
+        &mut self,
+        bx: &Builder<'a, 'tcx>,
+        constant: &mir::Constant<'tcx>,
+    ) -> (ValueRef, Ty<'tcx>) {
+        self.mir_constant_to_miri_value(bx, constant)
+            .and_then(|c| {
+                let field_ty = constant.ty.builtin_index().unwrap();
+                let fields = match constant.ty.sty {
+                    ty::TyArray(_, n) => n.val.unwrap_u64(),
+                    ref other => bug!("invalid simd shuffle type: {}", other),
+                };
+                let values: Result<Vec<ValueRef>, _> = (0..fields).map(|field| {
+                    let field = const_val_field(
+                        bx.tcx(),
+                        ty::ParamEnv::reveal_all(),
+                        self.instance,
+                        None,
+                        mir::Field::new(field as usize),
+                        c,
+                        constant.ty,
+                    )?;
+                    match field.val {
+                        ConstVal::Value(MiriValue::ByVal(prim)) => {
+                            let layout = bx.cx.layout_of(field_ty);
+                            let scalar = match layout.abi {
+                                layout::Abi::Scalar(ref x) => x,
+                                _ => bug!("from_const: invalid ByVal layout: {:#?}", layout)
+                            };
+                            Ok(primval_to_llvm(
+                                bx.cx, prim, scalar,
+                                layout.immediate_llvm_type(bx.cx),
+                            ))
+                        },
+                        other => bug!("simd shuffle field {:?}, {}", other, constant.ty),
+                    }
+                }).collect();
+                let llval = C_struct(bx.cx, &values?, false);
+                Ok((llval, constant.ty))
+            })
+            .unwrap_or_else(|e| {
+                e.report(bx.tcx(), constant.span, "shuffle_indices");
+                // We've errored, so we don't have to produce working code.
+                let ty = self.monomorphize(&constant.ty);
+                let llty = bx.cx.layout_of(ty).llvm_type(bx.cx);
+                (C_undef(llty), ty)
+            })
     }
-
-    // Pad to the size of the whole type, not e.g. the variant.
-    cfields.push(padding(cx, cx.size_of(layout.ty) - offset));
-
-    Const::new(C_struct(cx, &cfields, packed), layout.ty)
-}
-
-fn padding(cx: &CodegenCx, size: Size) -> ValueRef {
-    C_undef(Type::array(&Type::i8(cx), size.bytes()))
 }