1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 use llvm::{self, ValueRef};
12 use rustc::middle::const_val::{ConstVal, ConstEvalErr};
13 use rustc_mir::interpret::{read_target_uint, const_val_field};
14 use rustc::hir::def_id::DefId;
16 use rustc_data_structures::indexed_vec::Idx;
17 use rustc::mir::interpret::{Allocation, GlobalId, MemoryPointer, PrimVal, Value as MiriValue};
18 use rustc::ty::{self, Ty};
19 use rustc::ty::layout::{self, HasDataLayout, LayoutOf, Scalar};
21 use common::{CodegenCx};
22 use common::{C_bytes, C_struct, C_uint_big, C_undef, C_usize};
24 use type_of::LayoutLlvmExt;
26 use syntax::ast::Mutability;
28 use super::super::callee;
29 use super::FunctionCx;
31 pub fn primval_to_llvm(cx: &CodegenCx,
34 llty: Type) -> ValueRef {
35 let bits = if scalar.is_bool() { 1 } else { scalar.value.size(cx).bits() };
37 PrimVal::Undef => C_undef(Type::ix(cx, bits)),
38 PrimVal::Bytes(b) => {
39 let llval = C_uint_big(Type::ix(cx, bits), b);
40 if scalar.value == layout::Pointer {
41 unsafe { llvm::LLVMConstIntToPtr(llval, llty.to_ref()) }
43 consts::bitcast(llval, llty)
46 PrimVal::Ptr(ptr) => {
47 if let Some(fn_instance) = cx.tcx.interpret_interner.get_fn(ptr.alloc_id) {
48 callee::get_fn(cx, fn_instance)
53 .get_corresponding_static_def_id(ptr.alloc_id);
54 let base_addr = if let Some(def_id) = static_ {
55 assert!(cx.tcx.is_static(def_id).is_some());
56 consts::get_static(cx, def_id)
57 } else if let Some(alloc) = cx.tcx.interpret_interner
58 .get_alloc(ptr.alloc_id) {
59 let init = global_initializer(cx, alloc);
60 if alloc.runtime_mutability == Mutability::Mutable {
61 consts::addr_of_mut(cx, init, alloc.align, "byte_str")
63 consts::addr_of(cx, init, alloc.align, "byte_str")
66 bug!("missing allocation {:?}", ptr.alloc_id);
69 let llval = unsafe { llvm::LLVMConstInBoundsGEP(
70 consts::bitcast(base_addr, Type::i8p(cx)),
71 &C_usize(cx, ptr.offset),
74 if scalar.value != layout::Pointer {
75 unsafe { llvm::LLVMConstPtrToInt(llval, llty.to_ref()) }
77 consts::bitcast(llval, llty)
84 pub fn global_initializer(cx: &CodegenCx, alloc: &Allocation) -> ValueRef {
85 let mut llvals = Vec::with_capacity(alloc.relocations.len() + 1);
86 let layout = cx.data_layout();
87 let pointer_size = layout.pointer_size.bytes() as usize;
89 let mut next_offset = 0;
90 for (&offset, &alloc_id) in &alloc.relocations {
91 assert_eq!(offset as usize as u64, offset);
92 let offset = offset as usize;
93 if offset > next_offset {
94 llvals.push(C_bytes(cx, &alloc.bytes[next_offset..offset]));
96 let ptr_offset = read_target_uint(
98 &alloc.bytes[offset..(offset + pointer_size)],
99 ).expect("global_initializer: could not read relocation pointer") as u64;
100 llvals.push(primval_to_llvm(
102 PrimVal::Ptr(MemoryPointer { alloc_id, offset: ptr_offset }),
104 value: layout::Primitive::Pointer,
109 next_offset = offset + pointer_size;
111 if alloc.bytes.len() >= next_offset {
112 llvals.push(C_bytes(cx, &alloc.bytes[next_offset ..]));
115 C_struct(cx, &llvals, true)
118 pub fn trans_static_initializer<'a, 'tcx>(
119 cx: &CodegenCx<'a, 'tcx>,
121 -> Result<ValueRef, ConstEvalErr<'tcx>>
123 let instance = ty::Instance::mono(cx.tcx, def_id);
128 let param_env = ty::ParamEnv::reveal_all();
129 cx.tcx.const_eval(param_env.and(cid))?;
135 .expect("global not cached");
141 .expect("miri allocation never successfully created");
142 Ok(global_initializer(cx, alloc))
145 impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
146 fn const_to_miri_value(
148 bx: &Builder<'a, 'tcx>,
149 constant: &'tcx ty::Const<'tcx>,
150 ) -> Result<MiriValue, ConstEvalErr<'tcx>> {
152 ConstVal::Unevaluated(def_id, ref substs) => {
154 let param_env = ty::ParamEnv::reveal_all();
155 let instance = ty::Instance::resolve(tcx, param_env, def_id, substs).unwrap();
160 let c = tcx.const_eval(param_env.and(cid))?;
161 self.const_to_miri_value(bx, c)
163 ConstVal::Value(miri_val) => Ok(miri_val),
167 pub fn mir_constant_to_miri_value(
169 bx: &Builder<'a, 'tcx>,
170 constant: &mir::Constant<'tcx>,
171 ) -> Result<MiriValue, ConstEvalErr<'tcx>> {
172 match constant.literal {
173 mir::Literal::Promoted { index } => {
174 let param_env = ty::ParamEnv::reveal_all();
175 let cid = mir::interpret::GlobalId {
176 instance: self.instance,
177 promoted: Some(index),
179 bx.tcx().const_eval(param_env.and(cid))
181 mir::Literal::Value { value } => {
182 Ok(self.monomorphize(&value))
184 }.and_then(|c| self.const_to_miri_value(bx, c))
187 /// process constant containing SIMD shuffle indices
188 pub fn simd_shuffle_indices(
190 bx: &Builder<'a, 'tcx>,
191 constant: &mir::Constant<'tcx>,
192 ) -> (ValueRef, Ty<'tcx>) {
193 self.mir_constant_to_miri_value(bx, constant)
195 let field_ty = constant.ty.builtin_index().unwrap();
196 let fields = match constant.ty.sty {
197 ty::TyArray(_, n) => n.val.unwrap_u64(),
198 ref other => bug!("invalid simd shuffle type: {}", other),
200 let values: Result<Vec<ValueRef>, _> = (0..fields).map(|field| {
201 let field = const_val_field(
203 ty::ParamEnv::reveal_all(),
206 mir::Field::new(field as usize),
211 ConstVal::Value(MiriValue::ByVal(prim)) => {
212 let layout = bx.cx.layout_of(field_ty);
213 let scalar = match layout.abi {
214 layout::Abi::Scalar(ref x) => x,
215 _ => bug!("from_const: invalid ByVal layout: {:#?}", layout)
219 layout.immediate_llvm_type(bx.cx),
222 other => bug!("simd shuffle field {:?}, {}", other, constant.ty),
225 let llval = C_struct(bx.cx, &values?, false);
226 Ok((llval, constant.ty))
228 .unwrap_or_else(|e| {
229 e.report(bx.tcx(), constant.span, "shuffle_indices");
230 // We've errored, so we don't have to produce working code.
231 let ty = self.monomorphize(&constant.ty);
232 let llty = bx.cx.layout_of(ty).llvm_type(bx.cx);