// Copyright 2012-2014 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 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use llvm; use rustc::mir::interpret::{ErrorHandled, read_target_uint}; use rustc_mir::const_eval::const_field; use rustc::hir::def_id::DefId; use rustc::mir; use rustc_data_structures::indexed_vec::Idx; use rustc::mir::interpret::{GlobalId, Pointer, Scalar, Allocation, ConstValue, AllocType}; use rustc::ty::{self, Ty}; use rustc::ty::layout::{self, HasDataLayout, LayoutOf, Size}; use builder::Builder; use common::{CodegenCx}; use type_of::LayoutLlvmExt; use type_::Type; use syntax::ast::Mutability; use syntax::source_map::Span; use value::Value; use interfaces::{BuilderMethods, ConstMethods, BaseTypeMethods, DerivedTypeMethods, StaticMethods}; use super::super::callee; use super::FunctionCx; pub fn scalar_to_llvm( cx: &CodegenCx<'ll, '_>, cv: Scalar, layout: &layout::Scalar, llty: &'ll Type, ) -> &'ll Value { let bitsize = if layout.is_bool() { 1 } else { layout.value.size(cx).bits() }; match cv { Scalar::Bits { size: 0, .. } => { assert_eq!(0, layout.value.size(cx).bytes()); cx.const_undef(cx.type_ix(0)) }, Scalar::Bits { bits, size } => { assert_eq!(size as u64, layout.value.size(cx).bytes()); let llval = cx.const_uint_big(cx.type_ix(bitsize), bits); if layout.value == layout::Pointer { unsafe { llvm::LLVMConstIntToPtr(llval, llty) } } else { cx.static_bitcast(llval, llty) } }, Scalar::Ptr(ptr) => { let alloc_type = cx.tcx.alloc_map.lock().get(ptr.alloc_id); let base_addr = match alloc_type { Some(AllocType::Memory(alloc)) => { let init = const_alloc_to_llvm(cx, alloc); if alloc.mutability == Mutability::Mutable { cx.static_addr_of_mut(init, alloc.align, None) } else { cx.static_addr_of(init, alloc.align, None) } } Some(AllocType::Function(fn_instance)) => { callee::get_fn(cx, fn_instance) } Some(AllocType::Static(def_id)) => { assert!(cx.tcx.is_static(def_id).is_some()); cx.get_static(def_id) } None => bug!("missing allocation {:?}", ptr.alloc_id), }; let llval = unsafe { llvm::LLVMConstInBoundsGEP( cx.static_bitcast(base_addr, cx.type_i8p()), &cx.const_usize(ptr.offset.bytes()), 1, ) }; if layout.value != layout::Pointer { unsafe { llvm::LLVMConstPtrToInt(llval, llty) } } else { cx.static_bitcast(llval, llty) } } } } pub fn const_alloc_to_llvm(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll Value { let mut llvals = Vec::with_capacity(alloc.relocations.len() + 1); let dl = cx.data_layout(); let pointer_size = dl.pointer_size.bytes() as usize; let mut next_offset = 0; for &(offset, ((), alloc_id)) in alloc.relocations.iter() { let offset = offset.bytes(); assert_eq!(offset as usize as u64, offset); let offset = offset as usize; if offset > next_offset { llvals.push(cx.const_bytes(&alloc.bytes[next_offset..offset])); } let ptr_offset = read_target_uint( dl.endian, &alloc.bytes[offset..(offset + pointer_size)], ).expect("const_alloc_to_llvm: could not read relocation pointer") as u64; llvals.push(scalar_to_llvm( cx, Pointer::new(alloc_id, Size::from_bytes(ptr_offset)).into(), &layout::Scalar { value: layout::Primitive::Pointer, valid_range: 0..=!0 }, cx.type_i8p() )); next_offset = offset + pointer_size; } if alloc.bytes.len() >= next_offset { llvals.push(cx.const_bytes(&alloc.bytes[next_offset ..])); } cx.const_struct(&llvals, true) } pub fn codegen_static_initializer( cx: &CodegenCx<'ll, 'tcx>, def_id: DefId, ) -> Result<(&'ll Value, &'tcx Allocation), ErrorHandled> { let instance = ty::Instance::mono(cx.tcx, def_id); let cid = GlobalId { instance, promoted: None, }; let param_env = ty::ParamEnv::reveal_all(); let static_ = cx.tcx.const_eval(param_env.and(cid))?; let alloc = match static_.val { ConstValue::ByRef(_, alloc, n) if n.bytes() == 0 => alloc, _ => bug!("static const eval returned {:#?}", static_), }; Ok((const_alloc_to_llvm(cx, alloc), alloc)) } impl FunctionCx<'a, 'll, 'tcx, &'ll Value> { fn fully_evaluate( &mut self, bx: &Builder<'a, 'll, 'tcx>, constant: &'tcx ty::Const<'tcx>, ) -> Result<&'tcx ty::Const<'tcx>, ErrorHandled> { match constant.val { ConstValue::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, }; tcx.const_eval(param_env.and(cid)) }, _ => Ok(constant), } } pub fn eval_mir_constant( &mut self, bx: &Builder<'a, 'll, 'tcx>, constant: &mir::Constant<'tcx>, ) -> Result<&'tcx ty::Const<'tcx>, ErrorHandled> { let c = self.monomorphize(&constant.literal); self.fully_evaluate(bx, c) } /// process constant containing SIMD shuffle indices pub fn simd_shuffle_indices( &mut self, bx: &Builder<'a, 'll, 'tcx>, span: Span, ty: Ty<'tcx>, constant: Result<&'tcx ty::Const<'tcx>, ErrorHandled>, ) -> (&'ll Value, Ty<'tcx>) { constant .and_then(|c| { let field_ty = c.ty.builtin_index().unwrap(); let fields = match c.ty.sty { ty::Array(_, n) => n.unwrap_usize(bx.tcx()), ref other => bug!("invalid simd shuffle type: {}", other), }; let values: Result, ErrorHandled> = (0..fields).map(|field| { let field = const_field( bx.tcx(), ty::ParamEnv::reveal_all(), self.instance, None, mir::Field::new(field as usize), c, )?; if let Some(prim) = field.val.try_to_scalar() { 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(scalar_to_llvm( bx.cx(), prim, scalar, layout.immediate_llvm_type(bx.cx()), )) } else { bug!("simd shuffle field {:?}", field) } }).collect(); let llval = bx.cx().const_struct(&values?, false); Ok((llval, c.ty)) }) .unwrap_or_else(|_| { bx.tcx().sess.span_err( span, "could not evaluate shuffle_indices at compile time", ); // We've errored, so we don't have to produce working code. let ty = self.monomorphize(&ty); let llty = bx.cx().layout_of(ty).llvm_type(bx.cx()); (bx.cx().const_undef(llty), ty) }) } }