]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/mir/constant.rs
Auto merge of #48326 - RalfJung:generic-bounds, r=petrochenkov
[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::traits;
16 use rustc::mir;
17 use rustc_data_structures::indexed_vec::Idx;
18 use rustc::mir::interpret::{Allocation, GlobalId, MemoryPointer, PrimVal, Value as MiriValue};
19 use rustc::ty::{self, Ty};
20 use rustc::ty::layout::{self, HasDataLayout, LayoutOf, Scalar};
21 use builder::Builder;
22 use common::{CodegenCx};
23 use common::{C_bytes, C_struct, C_uint_big, C_undef, C_usize};
24 use consts;
25 use type_of::LayoutLlvmExt;
26 use type_::Type;
27 use syntax::ast::Mutability;
28
29 use super::super::callee;
30 use super::FunctionCx;
31
32 pub fn primval_to_llvm(cx: &CodegenCx,
33                        cv: PrimVal,
34                        scalar: &Scalar,
35                        llty: Type) -> ValueRef {
36     let bits = if scalar.is_bool() { 1 } else { scalar.value.size(cx).bits() };
37     match cv {
38         PrimVal::Undef => C_undef(Type::ix(cx, bits)),
39         PrimVal::Bytes(b) => {
40             let llval = C_uint_big(Type::ix(cx, bits), b);
41             if scalar.value == layout::Pointer {
42                 unsafe { llvm::LLVMConstIntToPtr(llval, llty.to_ref()) }
43             } else {
44                 consts::bitcast(llval, llty)
45             }
46         },
47         PrimVal::Ptr(ptr) => {
48             if let Some(fn_instance) = cx.tcx.interpret_interner.get_fn(ptr.alloc_id) {
49                 callee::get_fn(cx, fn_instance)
50             } else {
51                 let static_ = cx
52                     .tcx
53                     .interpret_interner
54                     .get_corresponding_static_def_id(ptr.alloc_id);
55                 let base_addr = if let Some(def_id) = static_ {
56                     assert!(cx.tcx.is_static(def_id).is_some());
57                     consts::get_static(cx, def_id)
58                 } else if let Some(alloc) = cx.tcx.interpret_interner
59                                               .get_alloc(ptr.alloc_id) {
60                     let init = global_initializer(cx, alloc);
61                     if alloc.runtime_mutability == Mutability::Mutable {
62                         consts::addr_of_mut(cx, init, alloc.align, "byte_str")
63                     } else {
64                         consts::addr_of(cx, init, alloc.align, "byte_str")
65                     }
66                 } else {
67                     bug!("missing allocation {:?}", ptr.alloc_id);
68                 };
69
70                 let llval = unsafe { llvm::LLVMConstInBoundsGEP(
71                     consts::bitcast(base_addr, Type::i8p(cx)),
72                     &C_usize(cx, ptr.offset),
73                     1,
74                 ) };
75                 if scalar.value != layout::Pointer {
76                     unsafe { llvm::LLVMConstPtrToInt(llval, llty.to_ref()) }
77                 } else {
78                     consts::bitcast(llval, llty)
79                 }
80             }
81         }
82     }
83 }
84
85 pub fn global_initializer(cx: &CodegenCx, alloc: &Allocation) -> ValueRef {
86     let mut llvals = Vec::with_capacity(alloc.relocations.len() + 1);
87     let layout = cx.data_layout();
88     let pointer_size = layout.pointer_size.bytes() as usize;
89
90     let mut next_offset = 0;
91     for (&offset, &alloc_id) in &alloc.relocations {
92         assert_eq!(offset as usize as u64, offset);
93         let offset = offset as usize;
94         if offset > next_offset {
95             llvals.push(C_bytes(cx, &alloc.bytes[next_offset..offset]));
96         }
97         let ptr_offset = read_target_uint(
98             layout.endian,
99             &alloc.bytes[offset..(offset + pointer_size)],
100         ).expect("global_initializer: could not read relocation pointer") as u64;
101         llvals.push(primval_to_llvm(
102             cx,
103             PrimVal::Ptr(MemoryPointer { alloc_id, offset: ptr_offset }),
104             &Scalar {
105                 value: layout::Primitive::Pointer,
106                 valid_range: 0..=!0
107             },
108             Type::i8p(cx)
109         ));
110         next_offset = offset + pointer_size;
111     }
112     if alloc.bytes.len() >= next_offset {
113         llvals.push(C_bytes(cx, &alloc.bytes[next_offset ..]));
114     }
115
116     C_struct(cx, &llvals, true)
117 }
118
119 pub fn trans_static_initializer<'a, 'tcx>(
120     cx: &CodegenCx<'a, 'tcx>,
121     def_id: DefId)
122     -> Result<ValueRef, ConstEvalErr<'tcx>>
123 {
124     let instance = ty::Instance::mono(cx.tcx, def_id);
125     let cid = GlobalId {
126         instance,
127         promoted: None
128     };
129     let param_env = ty::ParamEnv::empty(traits::Reveal::All);
130     cx.tcx.const_eval(param_env.and(cid))?;
131
132     let alloc_id = cx
133         .tcx
134         .interpret_interner
135         .get_cached(def_id)
136         .expect("global not cached");
137
138     let alloc = cx
139         .tcx
140         .interpret_interner
141         .get_alloc(alloc_id)
142         .expect("miri allocation never successfully created");
143     Ok(global_initializer(cx, alloc))
144 }
145
146 impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
147     fn const_to_miri_value(
148         &mut self,
149         bx: &Builder<'a, 'tcx>,
150         constant: &'tcx ty::Const<'tcx>,
151     ) -> Result<MiriValue, ConstEvalErr<'tcx>> {
152         match constant.val {
153             ConstVal::Unevaluated(def_id, ref substs) => {
154                 let tcx = bx.tcx();
155                 let param_env = ty::ParamEnv::empty(traits::Reveal::All);
156                 let instance = ty::Instance::resolve(tcx, param_env, def_id, substs).unwrap();
157                 let cid = GlobalId {
158                     instance,
159                     promoted: None,
160                 };
161                 let c = tcx.const_eval(param_env.and(cid))?;
162                 self.const_to_miri_value(bx, c)
163             },
164             ConstVal::Value(miri_val) => Ok(miri_val),
165         }
166     }
167
168     pub fn mir_constant_to_miri_value(
169         &mut self,
170         bx: &Builder<'a, 'tcx>,
171         constant: &mir::Constant<'tcx>,
172     ) -> Result<MiriValue, ConstEvalErr<'tcx>> {
173         match constant.literal {
174             mir::Literal::Promoted { index } => {
175                 let param_env = ty::ParamEnv::empty(traits::Reveal::All);
176                 let cid = mir::interpret::GlobalId {
177                     instance: self.instance,
178                     promoted: Some(index),
179                 };
180                 bx.tcx().const_eval(param_env.and(cid))
181             }
182             mir::Literal::Value { value } => {
183                 Ok(self.monomorphize(&value))
184             }
185         }.and_then(|c| self.const_to_miri_value(bx, c))
186     }
187
188     /// process constant containing SIMD shuffle indices
189     pub fn simd_shuffle_indices(
190         &mut self,
191         bx: &Builder<'a, 'tcx>,
192         constant: &mir::Constant<'tcx>,
193     ) -> (ValueRef, Ty<'tcx>) {
194         self.mir_constant_to_miri_value(bx, constant)
195             .and_then(|c| {
196                 let field_ty = constant.ty.builtin_index().unwrap();
197                 let fields = match constant.ty.sty {
198                     ty::TyArray(_, n) => n.val.unwrap_u64(),
199                     ref other => bug!("invalid simd shuffle type: {}", other),
200                 };
201                 let values: Result<Vec<ValueRef>, _> = (0..fields).map(|field| {
202                     let field = const_val_field(
203                         bx.tcx(),
204                         ty::ParamEnv::empty(traits::Reveal::All),
205                         self.instance,
206                         None,
207                         mir::Field::new(field as usize),
208                         c,
209                         constant.ty,
210                     )?;
211                     match field.val {
212                         ConstVal::Value(MiriValue::ByVal(prim)) => {
213                             let layout = bx.cx.layout_of(field_ty);
214                             let scalar = match layout.abi {
215                                 layout::Abi::Scalar(ref x) => x,
216                                 _ => bug!("from_const: invalid ByVal layout: {:#?}", layout)
217                             };
218                             Ok(primval_to_llvm(
219                                 bx.cx, prim, scalar,
220                                 layout.immediate_llvm_type(bx.cx),
221                             ))
222                         },
223                         other => bug!("simd shuffle field {:?}, {}", other, constant.ty),
224                     }
225                 }).collect();
226                 let llval = C_struct(bx.cx, &values?, false);
227                 Ok((llval, constant.ty))
228             })
229             .unwrap_or_else(|e| {
230                 e.report(bx.tcx(), constant.span, "shuffle_indices");
231                 // We've errored, so we don't have to produce working code.
232                 let ty = self.monomorphize(&constant.ty);
233                 let llty = bx.cx.layout_of(ty).llvm_type(bx.cx);
234                 (C_undef(llty), ty)
235             })
236     }
237 }