]>
Commit | Line | Data |
---|---|---|
54a0048b SL |
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 | ||
a7813a04 | 11 | use llvm::{self, ValueRef}; |
54a0048b | 12 | use rustc::middle::const_val::ConstVal; |
9e0c209e | 13 | use rustc_const_eval::{ErrKind, ConstEvalErr, report_const_eval_err}; |
54a0048b | 14 | use rustc_const_math::ConstInt::*; |
3157f602 | 15 | use rustc_const_math::ConstFloat::*; |
32a655c1 | 16 | use rustc_const_math::{ConstInt, ConstMathErr}; |
a7813a04 XL |
17 | use rustc::hir::def_id::DefId; |
18 | use rustc::infer::TransNormalize; | |
c30ab7b3 | 19 | use rustc::mir; |
a7813a04 | 20 | use rustc::mir::tcx::LvalueTy; |
32a655c1 | 21 | use rustc::ty::{self, layout, Ty, TyCtxt, TypeFoldable}; |
a7813a04 | 22 | use rustc::ty::cast::{CastTy, IntTy}; |
8bb4bdeb | 23 | use rustc::ty::subst::{Kind, Substs, Subst}; |
3157f602 | 24 | use rustc_data_structures::indexed_vec::{Idx, IndexVec}; |
9e0c209e | 25 | use {abi, adt, base, Disr, machine}; |
a7813a04 | 26 | use callee::Callee; |
32a655c1 SL |
27 | use builder::Builder; |
28 | use common::{self, CrateContext, const_get_elt, val_ty}; | |
29 | use common::{C_array, C_bool, C_bytes, C_floating_f64, C_integral, C_big_integral}; | |
30 | use common::{C_null, C_struct, C_str_slice, C_undef, C_uint, C_vector, is_undef}; | |
31 | use common::const_to_opt_u128; | |
9e0c209e | 32 | use consts; |
a7813a04 | 33 | use monomorphize::{self, Instance}; |
54a0048b SL |
34 | use type_of; |
35 | use type_::Type; | |
a7813a04 | 36 | use value::Value; |
54a0048b | 37 | |
32a655c1 | 38 | use syntax_pos::Span; |
54a0048b | 39 | |
5bcae85e | 40 | use std::fmt; |
a7813a04 | 41 | use std::ptr; |
54a0048b | 42 | |
32a655c1 | 43 | use super::lvalue::Alignment; |
a7813a04 XL |
44 | use super::operand::{OperandRef, OperandValue}; |
45 | use super::MirContext; | |
54a0048b | 46 | |
a7813a04 XL |
47 | /// A sized constant rvalue. |
48 | /// The LLVM type might not be the same for a single Rust type, | |
49 | /// e.g. each enum variant would have its own LLVM struct type. | |
50 | #[derive(Copy, Clone)] | |
51 | pub struct Const<'tcx> { | |
52 | pub llval: ValueRef, | |
53 | pub ty: Ty<'tcx> | |
54 | } | |
54a0048b | 55 | |
a7813a04 XL |
56 | impl<'tcx> Const<'tcx> { |
57 | pub fn new(llval: ValueRef, ty: Ty<'tcx>) -> Const<'tcx> { | |
58 | Const { | |
59 | llval: llval, | |
60 | ty: ty | |
54a0048b SL |
61 | } |
62 | } | |
63 | ||
8bb4bdeb XL |
64 | pub fn from_constint<'a>(ccx: &CrateContext<'a, 'tcx>, ci: &ConstInt) |
65 | -> Const<'tcx> { | |
66 | let tcx = ccx.tcx(); | |
67 | let (llval, ty) = match *ci { | |
68 | I8(v) => (C_integral(Type::i8(ccx), v as u64, true), tcx.types.i8), | |
69 | I16(v) => (C_integral(Type::i16(ccx), v as u64, true), tcx.types.i16), | |
70 | I32(v) => (C_integral(Type::i32(ccx), v as u64, true), tcx.types.i32), | |
71 | I64(v) => (C_integral(Type::i64(ccx), v as u64, true), tcx.types.i64), | |
72 | I128(v) => (C_big_integral(Type::i128(ccx), v as u128), tcx.types.i128), | |
73 | Isize(v) => { | |
74 | let i = v.as_i64(ccx.tcx().sess.target.int_type); | |
75 | (C_integral(Type::int(ccx), i as u64, true), tcx.types.isize) | |
76 | }, | |
77 | U8(v) => (C_integral(Type::i8(ccx), v as u64, false), tcx.types.u8), | |
78 | U16(v) => (C_integral(Type::i16(ccx), v as u64, false), tcx.types.u16), | |
79 | U32(v) => (C_integral(Type::i32(ccx), v as u64, false), tcx.types.u32), | |
80 | U64(v) => (C_integral(Type::i64(ccx), v, false), tcx.types.u64), | |
81 | U128(v) => (C_big_integral(Type::i128(ccx), v), tcx.types.u128), | |
82 | Usize(v) => { | |
83 | let u = v.as_u64(ccx.tcx().sess.target.uint_type); | |
84 | (C_integral(Type::int(ccx), u, false), tcx.types.usize) | |
85 | }, | |
86 | }; | |
87 | Const { llval: llval, ty: ty } | |
88 | } | |
89 | ||
a7813a04 XL |
90 | /// Translate ConstVal into a LLVM constant value. |
91 | pub fn from_constval<'a>(ccx: &CrateContext<'a, 'tcx>, | |
92 | cv: ConstVal, | |
93 | ty: Ty<'tcx>) | |
94 | -> Const<'tcx> { | |
54a0048b | 95 | let llty = type_of::type_of(ccx, ty); |
a7813a04 | 96 | let val = match cv { |
3157f602 XL |
97 | ConstVal::Float(F32(v)) => C_floating_f64(v as f64, llty), |
98 | ConstVal::Float(F64(v)) => C_floating_f64(v, llty), | |
54a0048b | 99 | ConstVal::Bool(v) => C_bool(ccx, v), |
8bb4bdeb | 100 | ConstVal::Integral(ref i) => return Const::from_constint(ccx, i), |
54a0048b SL |
101 | ConstVal::Str(ref v) => C_str_slice(ccx, v.clone()), |
102 | ConstVal::ByteStr(ref v) => consts::addr_of(ccx, C_bytes(ccx, v), 1, "byte_str"), | |
103 | ConstVal::Struct(_) | ConstVal::Tuple(_) | | |
104 | ConstVal::Array(..) | ConstVal::Repeat(..) | | |
8bb4bdeb | 105 | ConstVal::Function(..) => { |
3157f602 | 106 | bug!("MIR must not use `{:?}` (which refers to a local ID)", cv) |
54a0048b SL |
107 | } |
108 | ConstVal::Char(c) => C_integral(Type::char(ccx), c as u64, false), | |
a7813a04 XL |
109 | }; |
110 | ||
111 | assert!(!ty.has_erasable_regions()); | |
112 | ||
113 | Const::new(val, ty) | |
114 | } | |
115 | ||
3157f602 XL |
116 | fn get_pair(&self) -> (ValueRef, ValueRef) { |
117 | (const_get_elt(self.llval, &[0]), | |
118 | const_get_elt(self.llval, &[1])) | |
119 | } | |
120 | ||
a7813a04 | 121 | fn get_fat_ptr(&self) -> (ValueRef, ValueRef) { |
3157f602 XL |
122 | assert_eq!(abi::FAT_PTR_ADDR, 0); |
123 | assert_eq!(abi::FAT_PTR_EXTRA, 1); | |
124 | self.get_pair() | |
a7813a04 XL |
125 | } |
126 | ||
127 | fn as_lvalue(&self) -> ConstLvalue<'tcx> { | |
128 | ConstLvalue { | |
129 | base: Base::Value(self.llval), | |
130 | llextra: ptr::null_mut(), | |
131 | ty: self.ty | |
132 | } | |
133 | } | |
134 | ||
135 | pub fn to_operand<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> OperandRef<'tcx> { | |
136 | let llty = type_of::immediate_type_of(ccx, self.ty); | |
137 | let llvalty = val_ty(self.llval); | |
138 | ||
3157f602 XL |
139 | let val = if llty == llvalty && common::type_is_imm_pair(ccx, self.ty) { |
140 | let (a, b) = self.get_pair(); | |
141 | OperandValue::Pair(a, b) | |
142 | } else if llty == llvalty && common::type_is_immediate(ccx, self.ty) { | |
a7813a04 XL |
143 | // If the types match, we can use the value directly. |
144 | OperandValue::Immediate(self.llval) | |
145 | } else { | |
146 | // Otherwise, or if the value is not immediate, we create | |
147 | // a constant LLVM global and cast its address if necessary. | |
148 | let align = type_of::align_of(ccx, self.ty); | |
149 | let ptr = consts::addr_of(ccx, self.llval, align, "const"); | |
32a655c1 | 150 | OperandValue::Ref(consts::ptrcast(ptr, llty.ptr_to()), Alignment::AbiAligned) |
a7813a04 XL |
151 | }; |
152 | ||
153 | OperandRef { | |
154 | val: val, | |
155 | ty: self.ty | |
156 | } | |
157 | } | |
158 | } | |
159 | ||
5bcae85e SL |
160 | impl<'tcx> fmt::Debug for Const<'tcx> { |
161 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
162 | write!(f, "Const({:?}: {:?})", Value(self.llval), self.ty) | |
163 | } | |
164 | } | |
165 | ||
a7813a04 XL |
166 | #[derive(Copy, Clone)] |
167 | enum Base { | |
168 | /// A constant value without an unique address. | |
169 | Value(ValueRef), | |
170 | ||
171 | /// String literal base pointer (cast from array). | |
172 | Str(ValueRef), | |
173 | ||
174 | /// The address of a static. | |
175 | Static(ValueRef) | |
176 | } | |
177 | ||
178 | /// An lvalue as seen from a constant. | |
179 | #[derive(Copy, Clone)] | |
180 | struct ConstLvalue<'tcx> { | |
181 | base: Base, | |
182 | llextra: ValueRef, | |
183 | ty: Ty<'tcx> | |
184 | } | |
185 | ||
186 | impl<'tcx> ConstLvalue<'tcx> { | |
187 | fn to_const(&self, span: Span) -> Const<'tcx> { | |
188 | match self.base { | |
189 | Base::Value(val) => Const::new(val, self.ty), | |
190 | Base::Str(ptr) => { | |
191 | span_bug!(span, "loading from `str` ({:?}) in constant", | |
192 | Value(ptr)) | |
193 | } | |
194 | Base::Static(val) => { | |
195 | span_bug!(span, "loading from `static` ({:?}) in constant", | |
196 | Value(val)) | |
197 | } | |
198 | } | |
199 | } | |
200 | ||
201 | pub fn len<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> ValueRef { | |
202 | match self.ty.sty { | |
203 | ty::TyArray(_, n) => C_uint(ccx, n), | |
204 | ty::TySlice(_) | ty::TyStr => { | |
205 | assert!(self.llextra != ptr::null_mut()); | |
206 | self.llextra | |
207 | } | |
208 | _ => bug!("unexpected type `{}` in ConstLvalue::len", self.ty) | |
209 | } | |
210 | } | |
211 | } | |
212 | ||
213 | /// Machinery for translating a constant's MIR to LLVM values. | |
214 | /// FIXME(eddyb) use miri and lower its allocations to LLVM. | |
215 | struct MirConstContext<'a, 'tcx: 'a> { | |
216 | ccx: &'a CrateContext<'a, 'tcx>, | |
217 | mir: &'a mir::Mir<'tcx>, | |
218 | ||
219 | /// Type parameters for const fn and associated constants. | |
220 | substs: &'tcx Substs<'tcx>, | |
221 | ||
3157f602 XL |
222 | /// Values of locals in a constant or const fn. |
223 | locals: IndexVec<mir::Local, Option<Const<'tcx>>> | |
a7813a04 XL |
224 | } |
225 | ||
226 | ||
227 | impl<'a, 'tcx> MirConstContext<'a, 'tcx> { | |
228 | fn new(ccx: &'a CrateContext<'a, 'tcx>, | |
229 | mir: &'a mir::Mir<'tcx>, | |
230 | substs: &'tcx Substs<'tcx>, | |
c30ab7b3 | 231 | args: IndexVec<mir::Local, Const<'tcx>>) |
a7813a04 | 232 | -> MirConstContext<'a, 'tcx> { |
3157f602 | 233 | let mut context = MirConstContext { |
a7813a04 XL |
234 | ccx: ccx, |
235 | mir: mir, | |
236 | substs: substs, | |
c30ab7b3 | 237 | locals: (0..mir.local_decls.len()).map(|_| None).collect(), |
3157f602 XL |
238 | }; |
239 | for (i, arg) in args.into_iter().enumerate() { | |
c30ab7b3 SL |
240 | // Locals after local 0 are the function arguments |
241 | let index = mir::Local::new(i + 1); | |
3157f602 | 242 | context.locals[index] = Some(arg); |
54a0048b | 243 | } |
3157f602 | 244 | context |
54a0048b SL |
245 | } |
246 | ||
a7813a04 | 247 | fn trans_def(ccx: &'a CrateContext<'a, 'tcx>, |
32a655c1 | 248 | instance: Instance<'tcx>, |
c30ab7b3 | 249 | args: IndexVec<mir::Local, Const<'tcx>>) |
8bb4bdeb | 250 | -> Result<Const<'tcx>, ConstEvalErr<'tcx>> { |
32a655c1 | 251 | let instance = instance.resolve_const(ccx.shared()); |
c30ab7b3 | 252 | let mir = ccx.tcx().item_mir(instance.def); |
a7813a04 XL |
253 | MirConstContext::new(ccx, &mir, instance.substs, args).trans() |
254 | } | |
255 | ||
256 | fn monomorphize<T>(&self, value: &T) -> T | |
257 | where T: TransNormalize<'tcx> | |
258 | { | |
9e0c209e | 259 | monomorphize::apply_param_substs(self.ccx.shared(), |
a7813a04 XL |
260 | self.substs, |
261 | value) | |
262 | } | |
263 | ||
8bb4bdeb | 264 | fn trans(&mut self) -> Result<Const<'tcx>, ConstEvalErr<'tcx>> { |
a7813a04 XL |
265 | let tcx = self.ccx.tcx(); |
266 | let mut bb = mir::START_BLOCK; | |
3157f602 XL |
267 | |
268 | // Make sure to evaluate all statemenets to | |
269 | // report as many errors as we possibly can. | |
270 | let mut failure = Ok(()); | |
271 | ||
a7813a04 | 272 | loop { |
3157f602 | 273 | let data = &self.mir[bb]; |
a7813a04 | 274 | for statement in &data.statements { |
3157f602 | 275 | let span = statement.source_info.span; |
a7813a04 XL |
276 | match statement.kind { |
277 | mir::StatementKind::Assign(ref dest, ref rvalue) => { | |
5bcae85e | 278 | let ty = dest.ty(self.mir, tcx); |
a7813a04 | 279 | let ty = self.monomorphize(&ty).to_ty(tcx); |
3157f602 XL |
280 | match self.const_rvalue(rvalue, ty, span) { |
281 | Ok(value) => self.store(dest, value, span), | |
282 | Err(err) => if failure.is_ok() { failure = Err(err); } | |
283 | } | |
a7813a04 | 284 | } |
5bcae85e | 285 | mir::StatementKind::StorageLive(_) | |
9e0c209e SL |
286 | mir::StatementKind::StorageDead(_) | |
287 | mir::StatementKind::Nop => {} | |
8bb4bdeb | 288 | mir::StatementKind::InlineAsm { .. } | |
5bcae85e | 289 | mir::StatementKind::SetDiscriminant{ .. } => { |
8bb4bdeb | 290 | span_bug!(span, "{:?} should not appear in constants?", statement.kind); |
5bcae85e | 291 | } |
a7813a04 XL |
292 | } |
293 | } | |
294 | ||
295 | let terminator = data.terminator(); | |
3157f602 | 296 | let span = terminator.source_info.span; |
a7813a04 XL |
297 | bb = match terminator.kind { |
298 | mir::TerminatorKind::Drop { target, .. } | // No dropping. | |
299 | mir::TerminatorKind::Goto { target } => target, | |
300 | mir::TerminatorKind::Return => { | |
3157f602 | 301 | failure?; |
c30ab7b3 | 302 | return Ok(self.locals[mir::RETURN_POINTER].unwrap_or_else(|| { |
a7813a04 | 303 | span_bug!(span, "no returned value in constant"); |
3157f602 | 304 | })); |
a7813a04 XL |
305 | } |
306 | ||
3157f602 | 307 | mir::TerminatorKind::Assert { ref cond, expected, ref msg, target, .. } => { |
a7813a04 | 308 | let cond = self.const_operand(cond, span)?; |
3157f602 XL |
309 | let cond_bool = common::const_to_uint(cond.llval) != 0; |
310 | if cond_bool != expected { | |
311 | let err = match *msg { | |
312 | mir::AssertMessage::BoundsCheck { ref len, ref index } => { | |
313 | let len = self.const_operand(len, span)?; | |
314 | let index = self.const_operand(index, span)?; | |
315 | ErrKind::IndexOutOfBounds { | |
316 | len: common::const_to_uint(len.llval), | |
317 | index: common::const_to_uint(index.llval) | |
318 | } | |
319 | } | |
320 | mir::AssertMessage::Math(ref err) => { | |
321 | ErrKind::Math(err.clone()) | |
322 | } | |
323 | }; | |
9e0c209e SL |
324 | |
325 | let err = ConstEvalErr{ span: span, kind: err }; | |
8bb4bdeb | 326 | report_const_eval_err(tcx, &err, span, "expression"); |
9e0c209e | 327 | failure = Err(err); |
a7813a04 | 328 | } |
3157f602 | 329 | target |
a7813a04 XL |
330 | } |
331 | ||
332 | mir::TerminatorKind::Call { ref func, ref args, ref destination, .. } => { | |
5bcae85e | 333 | let fn_ty = func.ty(self.mir, tcx); |
a7813a04 XL |
334 | let fn_ty = self.monomorphize(&fn_ty); |
335 | let instance = match fn_ty.sty { | |
336 | ty::TyFnDef(def_id, substs, _) => { | |
337 | Instance::new(def_id, substs) | |
338 | } | |
339 | _ => span_bug!(span, "calling {:?} (of type {}) in constant", | |
340 | func, fn_ty) | |
341 | }; | |
342 | ||
3157f602 XL |
343 | let mut const_args = IndexVec::with_capacity(args.len()); |
344 | for arg in args { | |
345 | match self.const_operand(arg, span) { | |
346 | Ok(arg) => { const_args.push(arg); }, | |
347 | Err(err) => if failure.is_ok() { failure = Err(err); } | |
348 | } | |
a7813a04 | 349 | } |
a7813a04 | 350 | if let Some((ref dest, target)) = *destination { |
3157f602 XL |
351 | match MirConstContext::trans_def(self.ccx, instance, const_args) { |
352 | Ok(value) => self.store(dest, value, span), | |
353 | Err(err) => if failure.is_ok() { failure = Err(err); } | |
354 | } | |
a7813a04 XL |
355 | target |
356 | } else { | |
3157f602 | 357 | span_bug!(span, "diverging {:?} in constant", terminator.kind); |
a7813a04 XL |
358 | } |
359 | } | |
360 | _ => span_bug!(span, "{:?} in constant", terminator.kind) | |
361 | }; | |
362 | } | |
363 | } | |
364 | ||
365 | fn store(&mut self, dest: &mir::Lvalue<'tcx>, value: Const<'tcx>, span: Span) { | |
c30ab7b3 | 366 | if let mir::Lvalue::Local(index) = *dest { |
3157f602 XL |
367 | self.locals[index] = Some(value); |
368 | } else { | |
369 | span_bug!(span, "assignment to {:?} in constant", dest); | |
370 | } | |
a7813a04 XL |
371 | } |
372 | ||
373 | fn const_lvalue(&self, lvalue: &mir::Lvalue<'tcx>, span: Span) | |
8bb4bdeb | 374 | -> Result<ConstLvalue<'tcx>, ConstEvalErr<'tcx>> { |
a7813a04 | 375 | let tcx = self.ccx.tcx(); |
3157f602 | 376 | |
c30ab7b3 | 377 | if let mir::Lvalue::Local(index) = *lvalue { |
3157f602 XL |
378 | return Ok(self.locals[index].unwrap_or_else(|| { |
379 | span_bug!(span, "{:?} not initialized", lvalue) | |
380 | }).as_lvalue()); | |
381 | } | |
382 | ||
a7813a04 | 383 | let lvalue = match *lvalue { |
c30ab7b3 | 384 | mir::Lvalue::Local(_) => bug!(), // handled above |
8bb4bdeb | 385 | mir::Lvalue::Static(box mir::Static { def_id, ty }) => { |
a7813a04 | 386 | ConstLvalue { |
9e0c209e | 387 | base: Base::Static(consts::get_static(self.ccx, def_id)), |
a7813a04 | 388 | llextra: ptr::null_mut(), |
8bb4bdeb | 389 | ty: self.monomorphize(&ty), |
a7813a04 XL |
390 | } |
391 | } | |
a7813a04 XL |
392 | mir::Lvalue::Projection(ref projection) => { |
393 | let tr_base = self.const_lvalue(&projection.base, span)?; | |
394 | let projected_ty = LvalueTy::Ty { ty: tr_base.ty } | |
395 | .projection_ty(tcx, &projection.elem); | |
396 | let base = tr_base.to_const(span); | |
397 | let projected_ty = self.monomorphize(&projected_ty).to_ty(tcx); | |
32a655c1 | 398 | let is_sized = self.ccx.shared().type_is_sized(projected_ty); |
a7813a04 XL |
399 | |
400 | let (projected, llextra) = match projection.elem { | |
401 | mir::ProjectionElem::Deref => { | |
402 | let (base, extra) = if is_sized { | |
403 | (base.llval, ptr::null_mut()) | |
404 | } else { | |
405 | base.get_fat_ptr() | |
406 | }; | |
407 | if self.ccx.statics().borrow().contains_key(&base) { | |
408 | (Base::Static(base), extra) | |
409 | } else if let ty::TyStr = projected_ty.sty { | |
410 | (Base::Str(base), extra) | |
411 | } else { | |
9e0c209e SL |
412 | let v = base; |
413 | let v = self.ccx.const_unsized().borrow().get(&v).map_or(v, |&v| v); | |
414 | let mut val = unsafe { llvm::LLVMGetInitializer(v) }; | |
a7813a04 XL |
415 | if val.is_null() { |
416 | span_bug!(span, "dereference of non-constant pointer `{:?}`", | |
417 | Value(base)); | |
418 | } | |
9e0c209e SL |
419 | if projected_ty.is_bool() { |
420 | unsafe { | |
421 | val = llvm::LLVMConstTrunc(val, Type::i1(self.ccx).to_ref()); | |
422 | } | |
423 | } | |
a7813a04 XL |
424 | (Base::Value(val), extra) |
425 | } | |
426 | } | |
427 | mir::ProjectionElem::Field(ref field, _) => { | |
9e0c209e | 428 | let llprojected = adt::const_get_field(self.ccx, tr_base.ty, base.llval, |
a7813a04 XL |
429 | Disr(0), field.index()); |
430 | let llextra = if is_sized { | |
431 | ptr::null_mut() | |
432 | } else { | |
433 | tr_base.llextra | |
434 | }; | |
435 | (Base::Value(llprojected), llextra) | |
436 | } | |
437 | mir::ProjectionElem::Index(ref index) => { | |
438 | let llindex = self.const_operand(index, span)?.llval; | |
439 | ||
32a655c1 | 440 | let iv = if let Some(iv) = common::const_to_opt_u128(llindex, false) { |
a7813a04 XL |
441 | iv |
442 | } else { | |
443 | span_bug!(span, "index is not an integer-constant expression") | |
444 | }; | |
3157f602 XL |
445 | |
446 | // Produce an undef instead of a LLVM assertion on OOB. | |
447 | let len = common::const_to_uint(tr_base.len(self.ccx)); | |
32a655c1 | 448 | let llelem = if iv < len as u128 { |
3157f602 XL |
449 | const_get_elt(base.llval, &[iv as u32]) |
450 | } else { | |
451 | C_undef(type_of::type_of(self.ccx, projected_ty)) | |
452 | }; | |
453 | ||
454 | (Base::Value(llelem), ptr::null_mut()) | |
a7813a04 XL |
455 | } |
456 | _ => span_bug!(span, "{:?} in constant", projection.elem) | |
457 | }; | |
458 | ConstLvalue { | |
459 | base: projected, | |
460 | llextra: llextra, | |
461 | ty: projected_ty | |
462 | } | |
463 | } | |
464 | }; | |
465 | Ok(lvalue) | |
466 | } | |
467 | ||
468 | fn const_operand(&self, operand: &mir::Operand<'tcx>, span: Span) | |
8bb4bdeb | 469 | -> Result<Const<'tcx>, ConstEvalErr<'tcx>> { |
5bcae85e SL |
470 | debug!("const_operand({:?} @ {:?})", operand, span); |
471 | let result = match *operand { | |
a7813a04 XL |
472 | mir::Operand::Consume(ref lvalue) => { |
473 | Ok(self.const_lvalue(lvalue, span)?.to_const(span)) | |
474 | } | |
475 | ||
476 | mir::Operand::Constant(ref constant) => { | |
477 | let ty = self.monomorphize(&constant.ty); | |
478 | match constant.literal.clone() { | |
479 | mir::Literal::Item { def_id, substs } => { | |
480 | // Shortcut for zero-sized types, including function item | |
481 | // types, which would not work with MirConstContext. | |
482 | if common::type_is_zero_size(self.ccx, ty) { | |
483 | let llty = type_of::type_of(self.ccx, ty); | |
484 | return Ok(Const::new(C_null(llty), ty)); | |
485 | } | |
486 | ||
487 | let substs = self.monomorphize(&substs); | |
488 | let instance = Instance::new(def_id, substs); | |
3157f602 | 489 | MirConstContext::trans_def(self.ccx, instance, IndexVec::new()) |
a7813a04 XL |
490 | } |
491 | mir::Literal::Promoted { index } => { | |
492 | let mir = &self.mir.promoted[index]; | |
3157f602 | 493 | MirConstContext::new(self.ccx, mir, self.substs, IndexVec::new()).trans() |
a7813a04 XL |
494 | } |
495 | mir::Literal::Value { value } => { | |
496 | Ok(Const::from_constval(self.ccx, value, ty)) | |
497 | } | |
498 | } | |
499 | } | |
5bcae85e SL |
500 | }; |
501 | debug!("const_operand({:?} @ {:?}) = {:?}", operand, span, | |
502 | result.as_ref().ok()); | |
503 | result | |
504 | } | |
505 | ||
506 | fn const_array(&self, array_ty: Ty<'tcx>, fields: &[ValueRef]) | |
507 | -> Const<'tcx> | |
508 | { | |
509 | let elem_ty = array_ty.builtin_index().unwrap_or_else(|| { | |
510 | bug!("bad array type {:?}", array_ty) | |
511 | }); | |
512 | let llunitty = type_of::type_of(self.ccx, elem_ty); | |
513 | // If the array contains enums, an LLVM array won't work. | |
514 | let val = if fields.iter().all(|&f| val_ty(f) == llunitty) { | |
515 | C_array(llunitty, fields) | |
516 | } else { | |
517 | C_struct(self.ccx, fields, false) | |
518 | }; | |
519 | Const::new(val, array_ty) | |
a7813a04 XL |
520 | } |
521 | ||
522 | fn const_rvalue(&self, rvalue: &mir::Rvalue<'tcx>, | |
523 | dest_ty: Ty<'tcx>, span: Span) | |
8bb4bdeb | 524 | -> Result<Const<'tcx>, ConstEvalErr<'tcx>> { |
a7813a04 | 525 | let tcx = self.ccx.tcx(); |
5bcae85e | 526 | debug!("const_rvalue({:?}: {:?} @ {:?})", rvalue, dest_ty, span); |
a7813a04 XL |
527 | let val = match *rvalue { |
528 | mir::Rvalue::Use(ref operand) => self.const_operand(operand, span)?, | |
529 | ||
530 | mir::Rvalue::Repeat(ref elem, ref count) => { | |
531 | let elem = self.const_operand(elem, span)?; | |
8bb4bdeb | 532 | let size = count.as_u64(tcx.sess.target.uint_type); |
a7813a04 | 533 | let fields = vec![elem.llval; size as usize]; |
5bcae85e | 534 | self.const_array(dest_ty, &fields) |
a7813a04 XL |
535 | } |
536 | ||
537 | mir::Rvalue::Aggregate(ref kind, ref operands) => { | |
3157f602 XL |
538 | // Make sure to evaluate all operands to |
539 | // report as many errors as we possibly can. | |
540 | let mut fields = Vec::with_capacity(operands.len()); | |
541 | let mut failure = Ok(()); | |
542 | for operand in operands { | |
543 | match self.const_operand(operand, span) { | |
544 | Ok(val) => fields.push(val.llval), | |
545 | Err(err) => if failure.is_ok() { failure = Err(err); } | |
546 | } | |
547 | } | |
548 | failure?; | |
a7813a04 | 549 | |
5bcae85e | 550 | match *kind { |
8bb4bdeb | 551 | mir::AggregateKind::Array(_) => { |
5bcae85e | 552 | self.const_array(dest_ty, &fields) |
a7813a04 | 553 | } |
5bcae85e SL |
554 | mir::AggregateKind::Adt(..) | |
555 | mir::AggregateKind::Closure(..) | | |
556 | mir::AggregateKind::Tuple => { | |
32a655c1 | 557 | Const::new(trans_const(self.ccx, dest_ty, kind, &fields), dest_ty) |
5bcae85e SL |
558 | } |
559 | } | |
a7813a04 XL |
560 | } |
561 | ||
562 | mir::Rvalue::Cast(ref kind, ref source, cast_ty) => { | |
563 | let operand = self.const_operand(source, span)?; | |
564 | let cast_ty = self.monomorphize(&cast_ty); | |
565 | ||
566 | let val = match *kind { | |
567 | mir::CastKind::ReifyFnPointer => { | |
568 | match operand.ty.sty { | |
569 | ty::TyFnDef(def_id, substs, _) => { | |
570 | Callee::def(self.ccx, def_id, substs) | |
9e0c209e | 571 | .reify(self.ccx) |
a7813a04 XL |
572 | } |
573 | _ => { | |
574 | span_bug!(span, "{} cannot be reified to a fn ptr", | |
575 | operand.ty) | |
576 | } | |
577 | } | |
578 | } | |
8bb4bdeb XL |
579 | mir::CastKind::ClosureFnPointer => { |
580 | match operand.ty.sty { | |
581 | ty::TyClosure(def_id, substs) => { | |
582 | // Get the def_id for FnOnce::call_once | |
583 | let fn_once = tcx.lang_items.fn_once_trait().unwrap(); | |
584 | let call_once = tcx | |
585 | .global_tcx().associated_items(fn_once) | |
586 | .find(|it| it.kind == ty::AssociatedKind::Method) | |
587 | .unwrap().def_id; | |
588 | // Now create its substs [Closure, Tuple] | |
589 | let input = tcx.closure_type(def_id) | |
590 | .subst(tcx, substs.substs).input(0); | |
591 | let substs = tcx.mk_substs([operand.ty, input.skip_binder()] | |
592 | .iter().cloned().map(Kind::from)); | |
593 | Callee::def(self.ccx, call_once, substs) | |
594 | .reify(self.ccx) | |
595 | } | |
596 | _ => { | |
597 | bug!("{} cannot be cast to a fn ptr", operand.ty) | |
598 | } | |
599 | } | |
600 | } | |
a7813a04 XL |
601 | mir::CastKind::UnsafeFnPointer => { |
602 | // this is a no-op at the LLVM level | |
603 | operand.llval | |
604 | } | |
605 | mir::CastKind::Unsize => { | |
606 | // unsize targets other than to a fat pointer currently | |
607 | // can't be in constants. | |
32a655c1 | 608 | assert!(common::type_is_fat_ptr(self.ccx, cast_ty)); |
a7813a04 XL |
609 | |
610 | let pointee_ty = operand.ty.builtin_deref(true, ty::NoPreference) | |
611 | .expect("consts: unsizing got non-pointer type").ty; | |
32a655c1 | 612 | let (base, old_info) = if !self.ccx.shared().type_is_sized(pointee_ty) { |
a7813a04 XL |
613 | // Normally, the source is a thin pointer and we are |
614 | // adding extra info to make a fat pointer. The exception | |
615 | // is when we are upcasting an existing object fat pointer | |
616 | // to use a different vtable. In that case, we want to | |
617 | // load out the original data pointer so we can repackage | |
618 | // it. | |
619 | let (base, extra) = operand.get_fat_ptr(); | |
620 | (base, Some(extra)) | |
621 | } else { | |
622 | (operand.llval, None) | |
623 | }; | |
624 | ||
625 | let unsized_ty = cast_ty.builtin_deref(true, ty::NoPreference) | |
626 | .expect("consts: unsizing got non-pointer target type").ty; | |
627 | let ptr_ty = type_of::in_memory_type_of(self.ccx, unsized_ty).ptr_to(); | |
628 | let base = consts::ptrcast(base, ptr_ty); | |
629 | let info = base::unsized_info(self.ccx, pointee_ty, | |
630 | unsized_ty, old_info); | |
631 | ||
632 | if old_info.is_none() { | |
633 | let prev_const = self.ccx.const_unsized().borrow_mut() | |
634 | .insert(base, operand.llval); | |
635 | assert!(prev_const.is_none() || prev_const == Some(operand.llval)); | |
636 | } | |
637 | assert_eq!(abi::FAT_PTR_ADDR, 0); | |
638 | assert_eq!(abi::FAT_PTR_EXTRA, 1); | |
639 | C_struct(self.ccx, &[base, info], false) | |
640 | } | |
641 | mir::CastKind::Misc if common::type_is_immediate(self.ccx, operand.ty) => { | |
642 | debug_assert!(common::type_is_immediate(self.ccx, cast_ty)); | |
643 | let r_t_in = CastTy::from_ty(operand.ty).expect("bad input type for cast"); | |
644 | let r_t_out = CastTy::from_ty(cast_ty).expect("bad output type for cast"); | |
645 | let ll_t_out = type_of::immediate_type_of(self.ccx, cast_ty); | |
646 | let llval = operand.llval; | |
647 | let signed = if let CastTy::Int(IntTy::CEnum) = r_t_in { | |
9e0c209e SL |
648 | let l = self.ccx.layout_of(operand.ty); |
649 | adt::is_discr_signed(&l) | |
a7813a04 XL |
650 | } else { |
651 | operand.ty.is_signed() | |
652 | }; | |
653 | ||
654 | unsafe { | |
655 | match (r_t_in, r_t_out) { | |
656 | (CastTy::Int(_), CastTy::Int(_)) => { | |
657 | let s = signed as llvm::Bool; | |
658 | llvm::LLVMConstIntCast(llval, ll_t_out.to_ref(), s) | |
659 | } | |
660 | (CastTy::Int(_), CastTy::Float) => { | |
661 | if signed { | |
662 | llvm::LLVMConstSIToFP(llval, ll_t_out.to_ref()) | |
663 | } else { | |
664 | llvm::LLVMConstUIToFP(llval, ll_t_out.to_ref()) | |
665 | } | |
666 | } | |
667 | (CastTy::Float, CastTy::Float) => { | |
668 | llvm::LLVMConstFPCast(llval, ll_t_out.to_ref()) | |
669 | } | |
670 | (CastTy::Float, CastTy::Int(IntTy::I)) => { | |
671 | llvm::LLVMConstFPToSI(llval, ll_t_out.to_ref()) | |
672 | } | |
673 | (CastTy::Float, CastTy::Int(_)) => { | |
674 | llvm::LLVMConstFPToUI(llval, ll_t_out.to_ref()) | |
675 | } | |
676 | (CastTy::Ptr(_), CastTy::Ptr(_)) | | |
677 | (CastTy::FnPtr, CastTy::Ptr(_)) | | |
678 | (CastTy::RPtr(_), CastTy::Ptr(_)) => { | |
679 | consts::ptrcast(llval, ll_t_out) | |
680 | } | |
681 | (CastTy::Int(_), CastTy::Ptr(_)) => { | |
682 | llvm::LLVMConstIntToPtr(llval, ll_t_out.to_ref()) | |
683 | } | |
684 | (CastTy::Ptr(_), CastTy::Int(_)) | | |
685 | (CastTy::FnPtr, CastTy::Int(_)) => { | |
686 | llvm::LLVMConstPtrToInt(llval, ll_t_out.to_ref()) | |
687 | } | |
688 | _ => bug!("unsupported cast: {:?} to {:?}", operand.ty, cast_ty) | |
689 | } | |
690 | } | |
691 | } | |
692 | mir::CastKind::Misc => { // Casts from a fat-ptr. | |
693 | let ll_cast_ty = type_of::immediate_type_of(self.ccx, cast_ty); | |
694 | let ll_from_ty = type_of::immediate_type_of(self.ccx, operand.ty); | |
32a655c1 | 695 | if common::type_is_fat_ptr(self.ccx, operand.ty) { |
a7813a04 | 696 | let (data_ptr, meta_ptr) = operand.get_fat_ptr(); |
32a655c1 | 697 | if common::type_is_fat_ptr(self.ccx, cast_ty) { |
a7813a04 XL |
698 | let ll_cft = ll_cast_ty.field_types(); |
699 | let ll_fft = ll_from_ty.field_types(); | |
700 | let data_cast = consts::ptrcast(data_ptr, ll_cft[0]); | |
701 | assert_eq!(ll_cft[1].kind(), ll_fft[1].kind()); | |
702 | C_struct(self.ccx, &[data_cast, meta_ptr], false) | |
703 | } else { // cast to thin-ptr | |
704 | // Cast of fat-ptr to thin-ptr is an extraction of data-ptr and | |
705 | // pointer-cast of that pointer to desired pointer type. | |
706 | consts::ptrcast(data_ptr, ll_cast_ty) | |
707 | } | |
708 | } else { | |
3157f602 | 709 | bug!("Unexpected non-fat-pointer operand") |
a7813a04 XL |
710 | } |
711 | } | |
712 | }; | |
713 | Const::new(val, cast_ty) | |
714 | } | |
715 | ||
716 | mir::Rvalue::Ref(_, bk, ref lvalue) => { | |
717 | let tr_lvalue = self.const_lvalue(lvalue, span)?; | |
718 | ||
719 | let ty = tr_lvalue.ty; | |
3157f602 | 720 | let ref_ty = tcx.mk_ref(tcx.mk_region(ty::ReErased), |
a7813a04 XL |
721 | ty::TypeAndMut { ty: ty, mutbl: bk.to_mutbl_lossy() }); |
722 | ||
723 | let base = match tr_lvalue.base { | |
724 | Base::Value(llval) => { | |
9e0c209e | 725 | // FIXME: may be wrong for &*(&simd_vec as &fmt::Debug) |
32a655c1 | 726 | let align = if self.ccx.shared().type_is_sized(ty) { |
9e0c209e SL |
727 | type_of::align_of(self.ccx, ty) |
728 | } else { | |
729 | self.ccx.tcx().data_layout.pointer_align.abi() as machine::llalign | |
730 | }; | |
a7813a04 XL |
731 | if bk == mir::BorrowKind::Mut { |
732 | consts::addr_of_mut(self.ccx, llval, align, "ref_mut") | |
733 | } else { | |
734 | consts::addr_of(self.ccx, llval, align, "ref") | |
735 | } | |
736 | } | |
737 | Base::Str(llval) | | |
738 | Base::Static(llval) => llval | |
739 | }; | |
740 | ||
32a655c1 | 741 | let ptr = if self.ccx.shared().type_is_sized(ty) { |
a7813a04 XL |
742 | base |
743 | } else { | |
744 | C_struct(self.ccx, &[base, tr_lvalue.llextra], false) | |
745 | }; | |
746 | Const::new(ptr, ref_ty) | |
747 | } | |
748 | ||
749 | mir::Rvalue::Len(ref lvalue) => { | |
750 | let tr_lvalue = self.const_lvalue(lvalue, span)?; | |
751 | Const::new(tr_lvalue.len(self.ccx), tcx.types.usize) | |
752 | } | |
753 | ||
754 | mir::Rvalue::BinaryOp(op, ref lhs, ref rhs) => { | |
755 | let lhs = self.const_operand(lhs, span)?; | |
756 | let rhs = self.const_operand(rhs, span)?; | |
757 | let ty = lhs.ty; | |
5bcae85e | 758 | let binop_ty = op.ty(tcx, lhs.ty, rhs.ty); |
a7813a04 | 759 | let (lhs, rhs) = (lhs.llval, rhs.llval); |
3157f602 XL |
760 | Const::new(const_scalar_binop(op, lhs, rhs, ty), binop_ty) |
761 | } | |
a7813a04 | 762 | |
3157f602 XL |
763 | mir::Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) => { |
764 | let lhs = self.const_operand(lhs, span)?; | |
765 | let rhs = self.const_operand(rhs, span)?; | |
766 | let ty = lhs.ty; | |
5bcae85e | 767 | let val_ty = op.ty(tcx, lhs.ty, rhs.ty); |
8bb4bdeb | 768 | let binop_ty = tcx.intern_tup(&[val_ty, tcx.types.bool], false); |
3157f602 XL |
769 | let (lhs, rhs) = (lhs.llval, rhs.llval); |
770 | assert!(!ty.is_fp()); | |
a7813a04 | 771 | |
3157f602 XL |
772 | match const_scalar_checked_binop(tcx, op, lhs, rhs, ty) { |
773 | Some((llval, of)) => { | |
774 | let llof = C_bool(self.ccx, of); | |
775 | Const::new(C_struct(self.ccx, &[llval, llof], false), binop_ty) | |
a7813a04 | 776 | } |
3157f602 XL |
777 | None => { |
778 | span_bug!(span, "{:?} got non-integer operands: {:?} and {:?}", | |
779 | rvalue, Value(lhs), Value(rhs)); | |
780 | } | |
781 | } | |
a7813a04 XL |
782 | } |
783 | ||
784 | mir::Rvalue::UnaryOp(op, ref operand) => { | |
785 | let operand = self.const_operand(operand, span)?; | |
786 | let lloperand = operand.llval; | |
787 | let llval = match op { | |
788 | mir::UnOp::Not => { | |
789 | unsafe { | |
790 | llvm::LLVMConstNot(lloperand) | |
791 | } | |
792 | } | |
793 | mir::UnOp::Neg => { | |
a7813a04 XL |
794 | let is_float = operand.ty.is_fp(); |
795 | unsafe { | |
796 | if is_float { | |
797 | llvm::LLVMConstFNeg(lloperand) | |
798 | } else { | |
799 | llvm::LLVMConstNeg(lloperand) | |
800 | } | |
801 | } | |
802 | } | |
803 | }; | |
804 | Const::new(llval, operand.ty) | |
805 | } | |
806 | ||
807 | _ => span_bug!(span, "{:?} in constant", rvalue) | |
808 | }; | |
809 | ||
5bcae85e SL |
810 | debug!("const_rvalue({:?}: {:?} @ {:?}) = {:?}", rvalue, dest_ty, span, val); |
811 | ||
a7813a04 XL |
812 | Ok(val) |
813 | } | |
3157f602 XL |
814 | |
815 | } | |
816 | ||
9e0c209e SL |
817 | fn to_const_int(value: ValueRef, t: Ty, tcx: TyCtxt) -> Option<ConstInt> { |
818 | match t.sty { | |
32a655c1 SL |
819 | ty::TyInt(int_type) => const_to_opt_u128(value, true) |
820 | .and_then(|input| ConstInt::new_signed(input as i128, int_type, | |
821 | tcx.sess.target.int_type)), | |
822 | ty::TyUint(uint_type) => const_to_opt_u128(value, false) | |
823 | .and_then(|input| ConstInt::new_unsigned(input, uint_type, | |
824 | tcx.sess.target.uint_type)), | |
825 | _ => None | |
826 | ||
9e0c209e SL |
827 | } |
828 | } | |
829 | ||
3157f602 XL |
830 | pub fn const_scalar_binop(op: mir::BinOp, |
831 | lhs: ValueRef, | |
832 | rhs: ValueRef, | |
833 | input_ty: Ty) -> ValueRef { | |
834 | assert!(!input_ty.is_simd()); | |
835 | let is_float = input_ty.is_fp(); | |
836 | let signed = input_ty.is_signed(); | |
837 | ||
838 | unsafe { | |
839 | match op { | |
840 | mir::BinOp::Add if is_float => llvm::LLVMConstFAdd(lhs, rhs), | |
841 | mir::BinOp::Add => llvm::LLVMConstAdd(lhs, rhs), | |
842 | ||
843 | mir::BinOp::Sub if is_float => llvm::LLVMConstFSub(lhs, rhs), | |
844 | mir::BinOp::Sub => llvm::LLVMConstSub(lhs, rhs), | |
845 | ||
846 | mir::BinOp::Mul if is_float => llvm::LLVMConstFMul(lhs, rhs), | |
847 | mir::BinOp::Mul => llvm::LLVMConstMul(lhs, rhs), | |
848 | ||
849 | mir::BinOp::Div if is_float => llvm::LLVMConstFDiv(lhs, rhs), | |
850 | mir::BinOp::Div if signed => llvm::LLVMConstSDiv(lhs, rhs), | |
851 | mir::BinOp::Div => llvm::LLVMConstUDiv(lhs, rhs), | |
852 | ||
853 | mir::BinOp::Rem if is_float => llvm::LLVMConstFRem(lhs, rhs), | |
854 | mir::BinOp::Rem if signed => llvm::LLVMConstSRem(lhs, rhs), | |
855 | mir::BinOp::Rem => llvm::LLVMConstURem(lhs, rhs), | |
856 | ||
857 | mir::BinOp::BitXor => llvm::LLVMConstXor(lhs, rhs), | |
858 | mir::BinOp::BitAnd => llvm::LLVMConstAnd(lhs, rhs), | |
859 | mir::BinOp::BitOr => llvm::LLVMConstOr(lhs, rhs), | |
860 | mir::BinOp::Shl => { | |
861 | let rhs = base::cast_shift_const_rhs(op.to_hir_binop(), lhs, rhs); | |
862 | llvm::LLVMConstShl(lhs, rhs) | |
863 | } | |
864 | mir::BinOp::Shr => { | |
865 | let rhs = base::cast_shift_const_rhs(op.to_hir_binop(), lhs, rhs); | |
866 | if signed { llvm::LLVMConstAShr(lhs, rhs) } | |
867 | else { llvm::LLVMConstLShr(lhs, rhs) } | |
868 | } | |
869 | mir::BinOp::Eq | mir::BinOp::Ne | | |
870 | mir::BinOp::Lt | mir::BinOp::Le | | |
871 | mir::BinOp::Gt | mir::BinOp::Ge => { | |
872 | if is_float { | |
873 | let cmp = base::bin_op_to_fcmp_predicate(op.to_hir_binop()); | |
5bcae85e | 874 | llvm::LLVMConstFCmp(cmp, lhs, rhs) |
3157f602 XL |
875 | } else { |
876 | let cmp = base::bin_op_to_icmp_predicate(op.to_hir_binop(), | |
877 | signed); | |
5bcae85e | 878 | llvm::LLVMConstICmp(cmp, lhs, rhs) |
3157f602 XL |
879 | } |
880 | } | |
881 | } | |
882 | } | |
883 | } | |
884 | ||
885 | pub fn const_scalar_checked_binop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, | |
886 | op: mir::BinOp, | |
887 | lllhs: ValueRef, | |
888 | llrhs: ValueRef, | |
889 | input_ty: Ty<'tcx>) | |
890 | -> Option<(ValueRef, bool)> { | |
891 | if let (Some(lhs), Some(rhs)) = (to_const_int(lllhs, input_ty, tcx), | |
892 | to_const_int(llrhs, input_ty, tcx)) { | |
893 | let result = match op { | |
894 | mir::BinOp::Add => lhs + rhs, | |
895 | mir::BinOp::Sub => lhs - rhs, | |
896 | mir::BinOp::Mul => lhs * rhs, | |
897 | mir::BinOp::Shl => lhs << rhs, | |
898 | mir::BinOp::Shr => lhs >> rhs, | |
899 | _ => { | |
900 | bug!("Operator `{:?}` is not a checkable operator", op) | |
901 | } | |
902 | }; | |
903 | ||
904 | let of = match result { | |
905 | Ok(_) => false, | |
906 | Err(ConstMathErr::Overflow(_)) | | |
907 | Err(ConstMathErr::ShiftNegative) => true, | |
908 | Err(err) => { | |
909 | bug!("Operator `{:?}` on `{:?}` and `{:?}` errored: {}", | |
910 | op, lhs, rhs, err.description()); | |
911 | } | |
912 | }; | |
913 | ||
914 | Some((const_scalar_binop(op, lllhs, llrhs, input_ty), of)) | |
915 | } else { | |
916 | None | |
917 | } | |
a7813a04 XL |
918 | } |
919 | ||
32a655c1 | 920 | impl<'a, 'tcx> MirContext<'a, 'tcx> { |
54a0048b | 921 | pub fn trans_constant(&mut self, |
32a655c1 | 922 | bcx: &Builder<'a, 'tcx>, |
54a0048b | 923 | constant: &mir::Constant<'tcx>) |
a7813a04 | 924 | -> Const<'tcx> |
54a0048b | 925 | { |
5bcae85e | 926 | debug!("trans_constant({:?})", constant); |
32a655c1 | 927 | let ty = self.monomorphize(&constant.ty); |
a7813a04 | 928 | let result = match constant.literal.clone() { |
54a0048b SL |
929 | mir::Literal::Item { def_id, substs } => { |
930 | // Shortcut for zero-sized types, including function item | |
a7813a04 | 931 | // types, which would not work with MirConstContext. |
32a655c1 SL |
932 | if common::type_is_zero_size(bcx.ccx, ty) { |
933 | let llty = type_of::type_of(bcx.ccx, ty); | |
a7813a04 | 934 | return Const::new(C_null(llty), ty); |
54a0048b SL |
935 | } |
936 | ||
32a655c1 | 937 | let substs = self.monomorphize(&substs); |
a7813a04 | 938 | let instance = Instance::new(def_id, substs); |
32a655c1 | 939 | MirConstContext::trans_def(bcx.ccx, instance, IndexVec::new()) |
a7813a04 XL |
940 | } |
941 | mir::Literal::Promoted { index } => { | |
942 | let mir = &self.mir.promoted[index]; | |
32a655c1 | 943 | MirConstContext::new(bcx.ccx, mir, self.param_substs, IndexVec::new()).trans() |
a7813a04 XL |
944 | } |
945 | mir::Literal::Value { value } => { | |
32a655c1 | 946 | Ok(Const::from_constval(bcx.ccx, value, ty)) |
54a0048b | 947 | } |
a7813a04 XL |
948 | }; |
949 | ||
9e0c209e SL |
950 | let result = result.unwrap_or_else(|_| { |
951 | // We've errored, so we don't have to produce working code. | |
32a655c1 | 952 | let llty = type_of::type_of(bcx.ccx, ty); |
9e0c209e SL |
953 | Const::new(C_undef(llty), ty) |
954 | }); | |
5bcae85e SL |
955 | |
956 | debug!("trans_constant({:?}) = {:?}", constant, result); | |
957 | result | |
54a0048b SL |
958 | } |
959 | } | |
a7813a04 XL |
960 | |
961 | ||
8bb4bdeb XL |
962 | pub fn trans_static_initializer<'a, 'tcx>( |
963 | ccx: &CrateContext<'a, 'tcx>, | |
964 | def_id: DefId) | |
965 | -> Result<ValueRef, ConstEvalErr<'tcx>> | |
966 | { | |
a7813a04 | 967 | let instance = Instance::mono(ccx.shared(), def_id); |
3157f602 | 968 | MirConstContext::trans_def(ccx, instance, IndexVec::new()).map(|c| c.llval) |
a7813a04 | 969 | } |
32a655c1 SL |
970 | |
971 | /// Construct a constant value, suitable for initializing a | |
972 | /// GlobalVariable, given a case and constant values for its fields. | |
973 | /// Note that this may have a different LLVM type (and different | |
974 | /// alignment!) from the representation's `type_of`, so it needs a | |
975 | /// pointer cast before use. | |
976 | /// | |
977 | /// The LLVM type system does not directly support unions, and only | |
978 | /// pointers can be bitcast, so a constant (and, by extension, the | |
979 | /// GlobalVariable initialized by it) will have a type that can vary | |
980 | /// depending on which case of an enum it is. | |
981 | /// | |
982 | /// To understand the alignment situation, consider `enum E { V64(u64), | |
983 | /// V32(u32, u32) }` on Windows. The type has 8-byte alignment to | |
984 | /// accommodate the u64, but `V32(x, y)` would have LLVM type `{i32, | |
985 | /// i32, i32}`, which is 4-byte aligned. | |
986 | /// | |
987 | /// Currently the returned value has the same size as the type, but | |
988 | /// this could be changed in the future to avoid allocating unnecessary | |
989 | /// space after values of shorter-than-maximum cases. | |
990 | fn trans_const<'a, 'tcx>( | |
991 | ccx: &CrateContext<'a, 'tcx>, | |
992 | t: Ty<'tcx>, | |
993 | kind: &mir::AggregateKind, | |
994 | vals: &[ValueRef] | |
995 | ) -> ValueRef { | |
996 | let l = ccx.layout_of(t); | |
997 | let dl = &ccx.tcx().data_layout; | |
998 | let variant_index = match *kind { | |
999 | mir::AggregateKind::Adt(_, index, _, _) => index, | |
1000 | _ => 0, | |
1001 | }; | |
1002 | match *l { | |
1003 | layout::CEnum { discr: d, min, max, .. } => { | |
1004 | let discr = match *kind { | |
1005 | mir::AggregateKind::Adt(adt_def, _, _, _) => { | |
8bb4bdeb | 1006 | Disr::for_variant(ccx.tcx(), adt_def, variant_index) |
32a655c1 SL |
1007 | }, |
1008 | _ => Disr(0), | |
1009 | }; | |
1010 | assert_eq!(vals.len(), 0); | |
1011 | adt::assert_discr_in_range(Disr(min), Disr(max), discr); | |
1012 | C_integral(Type::from_integer(ccx, d), discr.0, true) | |
1013 | } | |
1014 | layout::General { discr: d, ref variants, .. } => { | |
1015 | let variant = &variants[variant_index]; | |
1016 | let lldiscr = C_integral(Type::from_integer(ccx, d), variant_index as u64, true); | |
1017 | let mut vals_with_discr = vec![lldiscr]; | |
1018 | vals_with_discr.extend_from_slice(vals); | |
1019 | let mut contents = build_const_struct(ccx, &variant, &vals_with_discr[..]); | |
1020 | let needed_padding = l.size(dl).bytes() - variant.stride().bytes(); | |
1021 | if needed_padding > 0 { | |
1022 | contents.push(padding(ccx, needed_padding)); | |
1023 | } | |
1024 | C_struct(ccx, &contents[..], false) | |
1025 | } | |
1026 | layout::UntaggedUnion { ref variants, .. }=> { | |
1027 | assert_eq!(variant_index, 0); | |
1028 | let contents = build_const_union(ccx, variants, vals[0]); | |
1029 | C_struct(ccx, &contents, variants.packed) | |
1030 | } | |
1031 | layout::Univariant { ref variant, .. } => { | |
1032 | assert_eq!(variant_index, 0); | |
1033 | let contents = build_const_struct(ccx, &variant, vals); | |
1034 | C_struct(ccx, &contents[..], variant.packed) | |
1035 | } | |
1036 | layout::Vector { .. } => { | |
1037 | C_vector(vals) | |
1038 | } | |
1039 | layout::RawNullablePointer { nndiscr, .. } => { | |
1040 | let nnty = adt::compute_fields(ccx, t, nndiscr as usize, false)[0]; | |
1041 | if variant_index as u64 == nndiscr { | |
1042 | assert_eq!(vals.len(), 1); | |
1043 | vals[0] | |
1044 | } else { | |
1045 | C_null(type_of::sizing_type_of(ccx, nnty)) | |
1046 | } | |
1047 | } | |
1048 | layout::StructWrappedNullablePointer { ref nonnull, nndiscr, .. } => { | |
1049 | if variant_index as u64 == nndiscr { | |
1050 | C_struct(ccx, &build_const_struct(ccx, &nonnull, vals), false) | |
1051 | } else { | |
1052 | let fields = adt::compute_fields(ccx, t, nndiscr as usize, false); | |
1053 | let vals = fields.iter().map(|&ty| { | |
1054 | // Always use null even if it's not the `discrfield`th | |
1055 | // field; see #8506. | |
1056 | C_null(type_of::sizing_type_of(ccx, ty)) | |
1057 | }).collect::<Vec<ValueRef>>(); | |
1058 | C_struct(ccx, &build_const_struct(ccx, &nonnull, &vals[..]), false) | |
1059 | } | |
1060 | } | |
1061 | _ => bug!("trans_const: cannot handle type {} repreented as {:#?}", t, l) | |
1062 | } | |
1063 | } | |
1064 | ||
1065 | /// Building structs is a little complicated, because we might need to | |
1066 | /// insert padding if a field's value is less aligned than its type. | |
1067 | /// | |
1068 | /// Continuing the example from `trans_const`, a value of type `(u32, | |
1069 | /// E)` should have the `E` at offset 8, but if that field's | |
1070 | /// initializer is 4-byte aligned then simply translating the tuple as | |
1071 | /// a two-element struct will locate it at offset 4, and accesses to it | |
1072 | /// will read the wrong memory. | |
1073 | fn build_const_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, | |
1074 | st: &layout::Struct, | |
1075 | vals: &[ValueRef]) | |
1076 | -> Vec<ValueRef> { | |
1077 | assert_eq!(vals.len(), st.offsets.len()); | |
1078 | ||
1079 | if vals.len() == 0 { | |
1080 | return Vec::new(); | |
1081 | } | |
1082 | ||
1083 | // offset of current value | |
1084 | let mut offset = 0; | |
1085 | let mut cfields = Vec::new(); | |
1086 | cfields.reserve(st.offsets.len()*2); | |
1087 | ||
1088 | let parts = st.field_index_by_increasing_offset().map(|i| { | |
1089 | (&vals[i], st.offsets[i].bytes()) | |
1090 | }); | |
1091 | for (&val, target_offset) in parts { | |
1092 | if offset < target_offset { | |
1093 | cfields.push(padding(ccx, target_offset - offset)); | |
1094 | offset = target_offset; | |
1095 | } | |
1096 | assert!(!is_undef(val)); | |
1097 | cfields.push(val); | |
1098 | offset += machine::llsize_of_alloc(ccx, val_ty(val)); | |
1099 | } | |
1100 | ||
1101 | if offset < st.stride().bytes() { | |
1102 | cfields.push(padding(ccx, st.stride().bytes() - offset)); | |
1103 | } | |
1104 | ||
1105 | cfields | |
1106 | } | |
1107 | ||
1108 | fn build_const_union<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, | |
1109 | un: &layout::Union, | |
1110 | field_val: ValueRef) | |
1111 | -> Vec<ValueRef> { | |
1112 | let mut cfields = vec![field_val]; | |
1113 | ||
1114 | let offset = machine::llsize_of_alloc(ccx, val_ty(field_val)); | |
1115 | let size = un.stride().bytes(); | |
1116 | if offset != size { | |
1117 | cfields.push(padding(ccx, size - offset)); | |
1118 | } | |
1119 | ||
1120 | cfields | |
1121 | } | |
1122 | ||
1123 | fn padding(ccx: &CrateContext, size: u64) -> ValueRef { | |
1124 | C_undef(Type::array(&Type::i8(ccx), size)) | |
1125 | } |