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_const_math::{ConstInt, ConstMathErr};
13 use rustc::middle::const_val::{ConstVal, ConstEvalErr};
14 use rustc_mir::interpret::{read_target_uint, const_val_field};
15 use rustc::hir::def_id::DefId;
18 use rustc_data_structures::indexed_vec::Idx;
19 use rustc::mir::interpret::{Allocation, GlobalId, MemoryPointer, PrimVal, Value as MiriValue};
20 use rustc::ty::{self, Ty, TyCtxt};
21 use rustc::ty::layout::{self, HasDataLayout, LayoutOf, Scalar};
24 use common::{CodegenCx};
25 use common::{C_bytes, C_struct, C_uint_big, C_undef, C_usize};
26 use common::const_to_opt_u128;
28 use type_of::LayoutLlvmExt;
31 use super::super::callee;
32 use super::FunctionCx;
34 fn to_const_int(value: ValueRef, t: Ty, tcx: TyCtxt) -> Option<ConstInt> {
36 ty::TyInt(int_type) => const_to_opt_u128(value, true)
37 .and_then(|input| ConstInt::new_signed(input as i128, int_type,
38 tcx.sess.target.isize_ty)),
39 ty::TyUint(uint_type) => const_to_opt_u128(value, false)
40 .and_then(|input| ConstInt::new_unsigned(input, uint_type,
41 tcx.sess.target.usize_ty)),
47 pub fn const_scalar_binop(op: mir::BinOp,
50 input_ty: Ty) -> ValueRef {
51 assert!(!input_ty.is_simd());
52 let is_float = input_ty.is_fp();
53 let signed = input_ty.is_signed();
57 mir::BinOp::Add if is_float => llvm::LLVMConstFAdd(lhs, rhs),
58 mir::BinOp::Add => llvm::LLVMConstAdd(lhs, rhs),
60 mir::BinOp::Sub if is_float => llvm::LLVMConstFSub(lhs, rhs),
61 mir::BinOp::Sub => llvm::LLVMConstSub(lhs, rhs),
63 mir::BinOp::Mul if is_float => llvm::LLVMConstFMul(lhs, rhs),
64 mir::BinOp::Mul => llvm::LLVMConstMul(lhs, rhs),
66 mir::BinOp::Div if is_float => llvm::LLVMConstFDiv(lhs, rhs),
67 mir::BinOp::Div if signed => llvm::LLVMConstSDiv(lhs, rhs),
68 mir::BinOp::Div => llvm::LLVMConstUDiv(lhs, rhs),
70 mir::BinOp::Rem if is_float => llvm::LLVMConstFRem(lhs, rhs),
71 mir::BinOp::Rem if signed => llvm::LLVMConstSRem(lhs, rhs),
72 mir::BinOp::Rem => llvm::LLVMConstURem(lhs, rhs),
74 mir::BinOp::BitXor => llvm::LLVMConstXor(lhs, rhs),
75 mir::BinOp::BitAnd => llvm::LLVMConstAnd(lhs, rhs),
76 mir::BinOp::BitOr => llvm::LLVMConstOr(lhs, rhs),
78 let rhs = base::cast_shift_const_rhs(op.to_hir_binop(), lhs, rhs);
79 llvm::LLVMConstShl(lhs, rhs)
82 let rhs = base::cast_shift_const_rhs(op.to_hir_binop(), lhs, rhs);
83 if signed { llvm::LLVMConstAShr(lhs, rhs) }
84 else { llvm::LLVMConstLShr(lhs, rhs) }
86 mir::BinOp::Eq | mir::BinOp::Ne |
87 mir::BinOp::Lt | mir::BinOp::Le |
88 mir::BinOp::Gt | mir::BinOp::Ge => {
90 let cmp = base::bin_op_to_fcmp_predicate(op.to_hir_binop());
91 llvm::LLVMConstFCmp(cmp, lhs, rhs)
93 let cmp = base::bin_op_to_icmp_predicate(op.to_hir_binop(),
95 llvm::LLVMConstICmp(cmp, lhs, rhs)
98 mir::BinOp::Offset => unreachable!("BinOp::Offset in const-eval!")
103 pub fn const_scalar_checked_binop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
108 -> Option<(ValueRef, bool)> {
109 if let (Some(lhs), Some(rhs)) = (to_const_int(lllhs, input_ty, tcx),
110 to_const_int(llrhs, input_ty, tcx)) {
111 let result = match op {
112 mir::BinOp::Add => lhs + rhs,
113 mir::BinOp::Sub => lhs - rhs,
114 mir::BinOp::Mul => lhs * rhs,
115 mir::BinOp::Shl => lhs << rhs,
116 mir::BinOp::Shr => lhs >> rhs,
118 bug!("Operator `{:?}` is not a checkable operator", op)
122 let of = match result {
124 Err(ConstMathErr::Overflow(_)) |
125 Err(ConstMathErr::ShiftNegative) => true,
127 bug!("Operator `{:?}` on `{:?}` and `{:?}` errored: {}",
128 op, lhs, rhs, err.description());
132 Some((const_scalar_binop(op, lllhs, llrhs, input_ty), of))
138 pub fn primval_to_llvm(cx: &CodegenCx,
141 llty: Type) -> ValueRef {
142 let bits = if scalar.is_bool() { 1 } else { scalar.value.size(cx).bits() };
144 PrimVal::Undef => C_undef(Type::ix(cx, bits)),
145 PrimVal::Bytes(b) => {
146 let llval = C_uint_big(Type::ix(cx, bits), b);
147 if scalar.value == layout::Pointer {
148 unsafe { llvm::LLVMConstIntToPtr(llval, llty.to_ref()) }
150 consts::bitcast(llval, llty)
153 PrimVal::Ptr(ptr) => {
154 if let Some(fn_instance) = cx.tcx.interpret_interner.get_fn(ptr.alloc_id) {
155 callee::get_fn(cx, fn_instance)
160 .get_corresponding_static_def_id(ptr.alloc_id);
161 let base_addr = if let Some(def_id) = static_ {
162 assert!(cx.tcx.is_static(def_id).is_some());
163 consts::get_static(cx, def_id)
164 } else if let Some(alloc) = cx.tcx.interpret_interner
165 .get_alloc(ptr.alloc_id) {
166 let init = global_initializer(cx, alloc);
168 consts::addr_of_mut(cx, init, alloc.align, "byte_str")
170 consts::addr_of(cx, init, alloc.align, "byte_str")
173 bug!("missing allocation {:?}", ptr.alloc_id);
176 let llval = unsafe { llvm::LLVMConstInBoundsGEP(
177 consts::bitcast(base_addr, Type::i8p(cx)),
178 &C_usize(cx, ptr.offset),
181 if scalar.value != layout::Pointer {
182 unsafe { llvm::LLVMConstPtrToInt(llval, llty.to_ref()) }
184 consts::bitcast(llval, llty)
191 pub fn global_initializer(cx: &CodegenCx, alloc: &Allocation) -> ValueRef {
192 let mut llvals = Vec::with_capacity(alloc.relocations.len() + 1);
193 let layout = cx.data_layout();
194 let pointer_size = layout.pointer_size.bytes() as usize;
196 let mut next_offset = 0;
197 for (&offset, &alloc_id) in &alloc.relocations {
198 assert_eq!(offset as usize as u64, offset);
199 let offset = offset as usize;
200 if offset > next_offset {
201 llvals.push(C_bytes(cx, &alloc.bytes[next_offset..offset]));
203 let ptr_offset = read_target_uint(
205 &alloc.bytes[offset..(offset + pointer_size)],
206 ).expect("global_initializer: could not read relocation pointer") as u64;
207 llvals.push(primval_to_llvm(
209 PrimVal::Ptr(MemoryPointer { alloc_id, offset: ptr_offset }),
211 value: layout::Primitive::Pointer,
216 next_offset = offset + pointer_size;
218 if alloc.bytes.len() >= next_offset {
219 llvals.push(C_bytes(cx, &alloc.bytes[next_offset ..]));
222 C_struct(cx, &llvals, true)
225 pub fn trans_static_initializer<'a, 'tcx>(
226 cx: &CodegenCx<'a, 'tcx>,
228 -> Result<ValueRef, ConstEvalErr<'tcx>>
230 let instance = ty::Instance::mono(cx.tcx, def_id);
235 let param_env = ty::ParamEnv::empty(traits::Reveal::All);
236 cx.tcx.const_eval(param_env.and(cid))?;
242 .expect("global not cached");
248 .expect("miri allocation never successfully created");
249 Ok(global_initializer(cx, alloc))
252 impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
253 fn const_to_miri_value(
255 bx: &Builder<'a, 'tcx>,
256 constant: &'tcx ty::Const<'tcx>,
257 ) -> Result<MiriValue, ConstEvalErr<'tcx>> {
259 ConstVal::Unevaluated(def_id, ref substs) => {
261 let param_env = ty::ParamEnv::empty(traits::Reveal::All);
262 let instance = ty::Instance::resolve(tcx, param_env, def_id, substs).unwrap();
267 let c = tcx.const_eval(param_env.and(cid))?;
268 self.const_to_miri_value(bx, c)
270 ConstVal::Value(miri_val) => Ok(miri_val),
274 pub fn mir_constant_to_miri_value(
276 bx: &Builder<'a, 'tcx>,
277 constant: &mir::Constant<'tcx>,
278 ) -> Result<MiriValue, ConstEvalErr<'tcx>> {
279 match constant.literal {
280 mir::Literal::Promoted { index } => {
281 let param_env = ty::ParamEnv::empty(traits::Reveal::All);
282 let cid = mir::interpret::GlobalId {
283 instance: self.instance,
284 promoted: Some(index),
286 bx.tcx().const_eval(param_env.and(cid))
288 mir::Literal::Value { value } => {
289 Ok(self.monomorphize(&value))
291 }.and_then(|c| self.const_to_miri_value(bx, c))
294 // Old version of trans_constant now used just for SIMD shuffle
295 pub fn remove_me_shuffle_indices(&mut self,
296 bx: &Builder<'a, 'tcx>,
297 constant: &mir::Constant<'tcx>)
298 -> (ValueRef, Ty<'tcx>)
300 let layout = bx.cx.layout_of(constant.ty);
301 self.mir_constant_to_miri_value(bx, constant)
303 let llval = match c {
304 MiriValue::ByVal(val) => {
305 let scalar = match layout.abi {
306 layout::Abi::Scalar(ref x) => x,
307 _ => bug!("from_const: invalid ByVal layout: {:#?}", layout)
309 primval_to_llvm(bx.cx, val, scalar, layout.immediate_llvm_type(bx.cx))
311 MiriValue::ByValPair(a_val, b_val) => {
312 let (a_scalar, b_scalar) = match layout.abi {
313 layout::Abi::ScalarPair(ref a, ref b) => (a, b),
314 _ => bug!("from_const: invalid ByValPair layout: {:#?}", layout)
316 let a_llval = primval_to_llvm(
320 layout.scalar_pair_element_llvm_type(bx.cx, 0),
322 let b_llval = primval_to_llvm(
326 layout.scalar_pair_element_llvm_type(bx.cx, 1),
328 C_struct(bx.cx, &[a_llval, b_llval], false)
330 MiriValue::ByRef(..) => {
331 let field_ty = constant.ty.builtin_index().unwrap();
332 let fields = match constant.ty.sty {
333 ty::TyArray(_, n) => n.val.unwrap_u64(),
334 ref other => bug!("invalid simd shuffle type: {}", other),
336 let values: Result<Vec<ValueRef>, _> = (0..fields).map(|field| {
337 let field = const_val_field(
339 ty::ParamEnv::empty(traits::Reveal::All),
342 mir::Field::new(field as usize),
347 ConstVal::Value(MiriValue::ByVal(prim)) => {
348 let layout = bx.cx.layout_of(field_ty);
349 let scalar = match layout.abi {
350 layout::Abi::Scalar(ref x) => x,
351 _ => bug!("from_const: invalid ByVal layout: {:#?}", layout)
355 layout.immediate_llvm_type(bx.cx),
358 other => bug!("simd shuffle field {:?}, {}", other, constant.ty),
361 C_struct(bx.cx, &values?, false)
364 Ok((llval, constant.ty))
366 .unwrap_or_else(|e| {
367 e.report(bx.tcx(), constant.span, "shuffle_indices");
368 // We've errored, so we don't have to produce working code.
369 let ty = self.monomorphize(&constant.ty);
370 let llty = bx.cx.layout_of(ty).llvm_type(bx.cx);