]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/mir/constant.rs
refactor `ParamEnv::empty(Reveal)` into two distinct methods
[rust.git] / src / librustc_trans / mir / constant.rs
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.
4 //
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.
10
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;
15 use rustc::mir;
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};
20 use builder::Builder;
21 use common::{CodegenCx};
22 use common::{C_bytes, C_struct, C_uint_big, C_undef, C_usize};
23 use consts;
24 use type_of::LayoutLlvmExt;
25 use type_::Type;
26 use syntax::ast::Mutability;
27
28 use super::super::callee;
29 use super::FunctionCx;
30
31 pub fn primval_to_llvm(cx: &CodegenCx,
32                        cv: PrimVal,
33                        scalar: &Scalar,
34                        llty: Type) -> ValueRef {
35     let bits = if scalar.is_bool() { 1 } else { scalar.value.size(cx).bits() };
36     match cv {
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()) }
42             } else {
43                 consts::bitcast(llval, llty)
44             }
45         },
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)
49             } else {
50                 let static_ = cx
51                     .tcx
52                     .interpret_interner
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")
62                     } else {
63                         consts::addr_of(cx, init, alloc.align, "byte_str")
64                     }
65                 } else {
66                     bug!("missing allocation {:?}", ptr.alloc_id);
67                 };
68
69                 let llval = unsafe { llvm::LLVMConstInBoundsGEP(
70                     consts::bitcast(base_addr, Type::i8p(cx)),
71                     &C_usize(cx, ptr.offset),
72                     1,
73                 ) };
74                 if scalar.value != layout::Pointer {
75                     unsafe { llvm::LLVMConstPtrToInt(llval, llty.to_ref()) }
76                 } else {
77                     consts::bitcast(llval, llty)
78                 }
79             }
80         }
81     }
82 }
83
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;
88
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]));
95         }
96         let ptr_offset = read_target_uint(
97             layout.endian,
98             &alloc.bytes[offset..(offset + pointer_size)],
99         ).expect("global_initializer: could not read relocation pointer") as u64;
100         llvals.push(primval_to_llvm(
101             cx,
102             PrimVal::Ptr(MemoryPointer { alloc_id, offset: ptr_offset }),
103             &Scalar {
104                 value: layout::Primitive::Pointer,
105                 valid_range: 0..=!0
106             },
107             Type::i8p(cx)
108         ));
109         next_offset = offset + pointer_size;
110     }
111     if alloc.bytes.len() >= next_offset {
112         llvals.push(C_bytes(cx, &alloc.bytes[next_offset ..]));
113     }
114
115     C_struct(cx, &llvals, true)
116 }
117
118 pub fn trans_static_initializer<'a, 'tcx>(
119     cx: &CodegenCx<'a, 'tcx>,
120     def_id: DefId)
121     -> Result<ValueRef, ConstEvalErr<'tcx>>
122 {
123     let instance = ty::Instance::mono(cx.tcx, def_id);
124     let cid = GlobalId {
125         instance,
126         promoted: None
127     };
128     let param_env = ty::ParamEnv::reveal_all();
129     cx.tcx.const_eval(param_env.and(cid))?;
130
131     let alloc_id = cx
132         .tcx
133         .interpret_interner
134         .get_cached(def_id)
135         .expect("global not cached");
136
137     let alloc = cx
138         .tcx
139         .interpret_interner
140         .get_alloc(alloc_id)
141         .expect("miri allocation never successfully created");
142     Ok(global_initializer(cx, alloc))
143 }
144
145 impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
146     fn const_to_miri_value(
147         &mut self,
148         bx: &Builder<'a, 'tcx>,
149         constant: &'tcx ty::Const<'tcx>,
150     ) -> Result<MiriValue, ConstEvalErr<'tcx>> {
151         match constant.val {
152             ConstVal::Unevaluated(def_id, ref substs) => {
153                 let tcx = bx.tcx();
154                 let param_env = ty::ParamEnv::reveal_all();
155                 let instance = ty::Instance::resolve(tcx, param_env, def_id, substs).unwrap();
156                 let cid = GlobalId {
157                     instance,
158                     promoted: None,
159                 };
160                 let c = tcx.const_eval(param_env.and(cid))?;
161                 self.const_to_miri_value(bx, c)
162             },
163             ConstVal::Value(miri_val) => Ok(miri_val),
164         }
165     }
166
167     pub fn mir_constant_to_miri_value(
168         &mut self,
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),
178                 };
179                 bx.tcx().const_eval(param_env.and(cid))
180             }
181             mir::Literal::Value { value } => {
182                 Ok(self.monomorphize(&value))
183             }
184         }.and_then(|c| self.const_to_miri_value(bx, c))
185     }
186
187     /// process constant containing SIMD shuffle indices
188     pub fn simd_shuffle_indices(
189         &mut self,
190         bx: &Builder<'a, 'tcx>,
191         constant: &mir::Constant<'tcx>,
192     ) -> (ValueRef, Ty<'tcx>) {
193         self.mir_constant_to_miri_value(bx, constant)
194             .and_then(|c| {
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),
199                 };
200                 let values: Result<Vec<ValueRef>, _> = (0..fields).map(|field| {
201                     let field = const_val_field(
202                         bx.tcx(),
203                         ty::ParamEnv::reveal_all(),
204                         self.instance,
205                         None,
206                         mir::Field::new(field as usize),
207                         c,
208                         constant.ty,
209                     )?;
210                     match field.val {
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)
216                             };
217                             Ok(primval_to_llvm(
218                                 bx.cx, prim, scalar,
219                                 layout.immediate_llvm_type(bx.cx),
220                             ))
221                         },
222                         other => bug!("simd shuffle field {:?}, {}", other, constant.ty),
223                     }
224                 }).collect();
225                 let llval = C_struct(bx.cx, &values?, false);
226                 Ok((llval, constant.ty))
227             })
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);
233                 (C_undef(llty), ty)
234             })
235     }
236 }