]>
Commit | Line | Data |
---|---|---|
92a42be0 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 | ||
3157f602 | 11 | use llvm::{self, ValueRef}; |
54a0048b SL |
12 | use rustc::ty::{self, Ty}; |
13 | use rustc::ty::cast::{CastTy, IntTy}; | |
c30ab7b3 | 14 | use rustc::ty::layout::Layout; |
8bb4bdeb | 15 | use rustc::ty::subst::{Kind, Subst}; |
32a655c1 | 16 | use rustc::mir::tcx::LvalueTy; |
c30ab7b3 | 17 | use rustc::mir; |
32a655c1 | 18 | use middle::lang_items::ExchangeMallocFnLangItem; |
92a42be0 | 19 | |
54a0048b | 20 | use base; |
32a655c1 | 21 | use builder::Builder; |
54a0048b | 22 | use callee::Callee; |
32a655c1 | 23 | use common::{self, val_ty, C_bool, C_null, C_uint}; |
c30ab7b3 | 24 | use common::{C_integral}; |
54a0048b SL |
25 | use adt; |
26 | use machine; | |
c30ab7b3 | 27 | use type_::Type; |
54a0048b SL |
28 | use type_of; |
29 | use tvec; | |
30 | use value::Value; | |
31 | use Disr; | |
92a42be0 SL |
32 | |
33 | use super::MirContext; | |
3157f602 | 34 | use super::constant::const_scalar_checked_binop; |
92a42be0 | 35 | use super::operand::{OperandRef, OperandValue}; |
32a655c1 | 36 | use super::lvalue::LvalueRef; |
92a42be0 | 37 | |
32a655c1 | 38 | impl<'a, 'tcx> MirContext<'a, 'tcx> { |
92a42be0 | 39 | pub fn trans_rvalue(&mut self, |
32a655c1 | 40 | bcx: Builder<'a, 'tcx>, |
9cc50fc6 | 41 | dest: LvalueRef<'tcx>, |
32a655c1 SL |
42 | rvalue: &mir::Rvalue<'tcx>) |
43 | -> Builder<'a, 'tcx> | |
92a42be0 | 44 | { |
54a0048b SL |
45 | debug!("trans_rvalue(dest.llval={:?}, rvalue={:?})", |
46 | Value(dest.llval), rvalue); | |
92a42be0 SL |
47 | |
48 | match *rvalue { | |
54a0048b SL |
49 | mir::Rvalue::Use(ref operand) => { |
50 | let tr_operand = self.trans_operand(&bcx, operand); | |
51 | // FIXME: consider not copying constants through stack. (fixable by translating | |
52 | // constants into OperandValue::Ref, why don’t we do that yet if we don’t?) | |
32a655c1 | 53 | self.store_operand(&bcx, dest.llval, dest.alignment.to_align(), tr_operand); |
54a0048b SL |
54 | bcx |
55 | } | |
92a42be0 | 56 | |
54a0048b | 57 | mir::Rvalue::Cast(mir::CastKind::Unsize, ref source, cast_ty) => { |
32a655c1 | 58 | let cast_ty = self.monomorphize(&cast_ty); |
a7813a04 | 59 | |
32a655c1 | 60 | if common::type_is_fat_ptr(bcx.ccx, cast_ty) { |
92a42be0 SL |
61 | // into-coerce of a thin pointer to a fat pointer - just |
62 | // use the operand path. | |
32a655c1 SL |
63 | let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue); |
64 | self.store_operand(&bcx, dest.llval, dest.alignment.to_align(), temp); | |
92a42be0 SL |
65 | return bcx; |
66 | } | |
67 | ||
68 | // Unsize of a nontrivial struct. I would prefer for | |
69 | // this to be eliminated by MIR translation, but | |
70 | // `CoerceUnsized` can be passed by a where-clause, | |
71 | // so the (generic) MIR may not be able to expand it. | |
54a0048b | 72 | let operand = self.trans_operand(&bcx, source); |
3157f602 | 73 | let operand = operand.pack_if_pair(&bcx); |
32a655c1 SL |
74 | let llref = match operand.val { |
75 | OperandValue::Pair(..) => bug!(), | |
76 | OperandValue::Immediate(llval) => { | |
77 | // unsize from an immediate structure. We don't | |
78 | // really need a temporary alloca here, but | |
79 | // avoiding it would require us to have | |
80 | // `coerce_unsized_into` use extractvalue to | |
81 | // index into the struct, and this case isn't | |
82 | // important enough for it. | |
83 | debug!("trans_rvalue: creating ugly alloca"); | |
84 | let scratch = LvalueRef::alloca(&bcx, operand.ty, "__unsize_temp"); | |
85 | base::store_ty(&bcx, llval, scratch.llval, scratch.alignment, operand.ty); | |
86 | scratch | |
87 | } | |
88 | OperandValue::Ref(llref, align) => { | |
89 | LvalueRef::new_sized_ty(llref, operand.ty, align) | |
92a42be0 | 90 | } |
32a655c1 SL |
91 | }; |
92 | base::coerce_unsized_into(&bcx, &llref, &dest); | |
92a42be0 SL |
93 | bcx |
94 | } | |
95 | ||
96 | mir::Rvalue::Repeat(ref elem, ref count) => { | |
54a0048b | 97 | let tr_elem = self.trans_operand(&bcx, elem); |
8bb4bdeb | 98 | let size = count.as_u64(bcx.tcx().sess.target.uint_type); |
32a655c1 SL |
99 | let size = C_uint(bcx.ccx, size); |
100 | let base = base::get_dataptr(&bcx, dest.llval); | |
101 | tvec::slice_for_each(&bcx, base, tr_elem.ty, size, |bcx, llslot| { | |
102 | self.store_operand(bcx, llslot, dest.alignment.to_align(), tr_elem); | |
103 | }) | |
92a42be0 SL |
104 | } |
105 | ||
9cc50fc6 SL |
106 | mir::Rvalue::Aggregate(ref kind, ref operands) => { |
107 | match *kind { | |
32a655c1 | 108 | mir::AggregateKind::Adt(adt_def, variant_index, substs, active_field_index) => { |
8bb4bdeb | 109 | let disr = Disr::for_variant(bcx.tcx(), adt_def, variant_index); |
32a655c1 | 110 | let dest_ty = dest.ty.to_ty(bcx.tcx()); |
8bb4bdeb | 111 | adt::trans_set_discr(&bcx, dest_ty, dest.llval, disr); |
9cc50fc6 | 112 | for (i, operand) in operands.iter().enumerate() { |
7453a54e | 113 | let op = self.trans_operand(&bcx, operand); |
9cc50fc6 | 114 | // Do not generate stores and GEPis for zero-sized fields. |
32a655c1 SL |
115 | if !common::type_is_zero_size(bcx.ccx, op.ty) { |
116 | let mut val = LvalueRef::new_sized( | |
117 | dest.llval, dest.ty, dest.alignment); | |
9e0c209e | 118 | let field_index = active_field_index.unwrap_or(i); |
32a655c1 SL |
119 | val.ty = LvalueTy::Downcast { |
120 | adt_def: adt_def, | |
121 | substs: self.monomorphize(&substs), | |
8bb4bdeb | 122 | variant_index: variant_index, |
32a655c1 SL |
123 | }; |
124 | let (lldest_i, align) = val.trans_field_ptr(&bcx, field_index); | |
125 | self.store_operand(&bcx, lldest_i, align.to_align(), op); | |
9cc50fc6 SL |
126 | } |
127 | } | |
128 | }, | |
129 | _ => { | |
476ff2be | 130 | // If this is a tuple or closure, we need to translate GEP indices. |
32a655c1 | 131 | let layout = bcx.ccx.layout_of(dest.ty.to_ty(bcx.tcx())); |
476ff2be SL |
132 | let translation = if let Layout::Univariant { ref variant, .. } = *layout { |
133 | Some(&variant.memory_index) | |
134 | } else { | |
135 | None | |
136 | }; | |
32a655c1 | 137 | let alignment = dest.alignment; |
9cc50fc6 | 138 | for (i, operand) in operands.iter().enumerate() { |
7453a54e | 139 | let op = self.trans_operand(&bcx, operand); |
9cc50fc6 | 140 | // Do not generate stores and GEPis for zero-sized fields. |
32a655c1 | 141 | if !common::type_is_zero_size(bcx.ccx, op.ty) { |
9cc50fc6 SL |
142 | // Note: perhaps this should be StructGep, but |
143 | // note that in some cases the values here will | |
144 | // not be structs but arrays. | |
476ff2be SL |
145 | let i = if let Some(ref t) = translation { |
146 | t[i] as usize | |
147 | } else { | |
148 | i | |
149 | }; | |
7453a54e | 150 | let dest = bcx.gepi(dest.llval, &[0, i]); |
32a655c1 | 151 | self.store_operand(&bcx, dest, alignment.to_align(), op); |
9cc50fc6 SL |
152 | } |
153 | } | |
154 | } | |
92a42be0 SL |
155 | } |
156 | bcx | |
157 | } | |
158 | ||
92a42be0 | 159 | _ => { |
32a655c1 SL |
160 | assert!(rvalue_creates_operand(rvalue)); |
161 | let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue); | |
162 | self.store_operand(&bcx, dest.llval, dest.alignment.to_align(), temp); | |
92a42be0 SL |
163 | bcx |
164 | } | |
165 | } | |
166 | } | |
167 | ||
168 | pub fn trans_rvalue_operand(&mut self, | |
32a655c1 SL |
169 | bcx: Builder<'a, 'tcx>, |
170 | rvalue: &mir::Rvalue<'tcx>) | |
171 | -> (Builder<'a, 'tcx>, OperandRef<'tcx>) | |
92a42be0 | 172 | { |
32a655c1 | 173 | assert!(rvalue_creates_operand(rvalue), "cannot trans {:?} to operand", rvalue); |
92a42be0 SL |
174 | |
175 | match *rvalue { | |
54a0048b SL |
176 | mir::Rvalue::Cast(ref kind, ref source, cast_ty) => { |
177 | let operand = self.trans_operand(&bcx, source); | |
178 | debug!("cast operand is {:?}", operand); | |
32a655c1 | 179 | let cast_ty = self.monomorphize(&cast_ty); |
92a42be0 SL |
180 | |
181 | let val = match *kind { | |
54a0048b SL |
182 | mir::CastKind::ReifyFnPointer => { |
183 | match operand.ty.sty { | |
184 | ty::TyFnDef(def_id, substs, _) => { | |
185 | OperandValue::Immediate( | |
32a655c1 SL |
186 | Callee::def(bcx.ccx, def_id, substs) |
187 | .reify(bcx.ccx)) | |
54a0048b SL |
188 | } |
189 | _ => { | |
190 | bug!("{} cannot be reified to a fn ptr", operand.ty) | |
191 | } | |
192 | } | |
193 | } | |
8bb4bdeb XL |
194 | mir::CastKind::ClosureFnPointer => { |
195 | match operand.ty.sty { | |
196 | ty::TyClosure(def_id, substs) => { | |
197 | // Get the def_id for FnOnce::call_once | |
198 | let fn_once = bcx.tcx().lang_items.fn_once_trait().unwrap(); | |
199 | let call_once = bcx.tcx() | |
200 | .global_tcx().associated_items(fn_once) | |
201 | .find(|it| it.kind == ty::AssociatedKind::Method) | |
202 | .unwrap().def_id; | |
203 | // Now create its substs [Closure, Tuple] | |
204 | let input = bcx.tcx().closure_type(def_id) | |
205 | .subst(bcx.tcx(), substs.substs).input(0); | |
206 | let substs = bcx.tcx().mk_substs([operand.ty, input.skip_binder()] | |
207 | .iter().cloned().map(Kind::from)); | |
208 | OperandValue::Immediate( | |
209 | Callee::def(bcx.ccx, call_once, substs) | |
210 | .reify(bcx.ccx)) | |
211 | } | |
212 | _ => { | |
213 | bug!("{} cannot be cast to a fn ptr", operand.ty) | |
214 | } | |
215 | } | |
216 | } | |
92a42be0 | 217 | mir::CastKind::UnsafeFnPointer => { |
54a0048b | 218 | // this is a no-op at the LLVM level |
92a42be0 SL |
219 | operand.val |
220 | } | |
221 | mir::CastKind::Unsize => { | |
222 | // unsize targets other than to a fat pointer currently | |
223 | // can't be operands. | |
32a655c1 | 224 | assert!(common::type_is_fat_ptr(bcx.ccx, cast_ty)); |
92a42be0 SL |
225 | |
226 | match operand.val { | |
3157f602 | 227 | OperandValue::Pair(lldata, llextra) => { |
92a42be0 SL |
228 | // unsize from a fat pointer - this is a |
229 | // "trait-object-to-supertrait" coercion, for | |
230 | // example, | |
231 | // &'a fmt::Debug+Send => &'a fmt::Debug, | |
a7813a04 XL |
232 | // So we need to pointercast the base to ensure |
233 | // the types match up. | |
32a655c1 | 234 | let llcast_ty = type_of::fat_ptr_base_ty(bcx.ccx, cast_ty); |
a7813a04 | 235 | let lldata = bcx.pointercast(lldata, llcast_ty); |
3157f602 | 236 | OperandValue::Pair(lldata, llextra) |
92a42be0 SL |
237 | } |
238 | OperandValue::Immediate(lldata) => { | |
239 | // "standard" unsize | |
32a655c1 SL |
240 | let (lldata, llextra) = base::unsize_thin_ptr(&bcx, lldata, |
241 | operand.ty, cast_ty); | |
3157f602 | 242 | OperandValue::Pair(lldata, llextra) |
92a42be0 | 243 | } |
32a655c1 | 244 | OperandValue::Ref(..) => { |
54a0048b SL |
245 | bug!("by-ref operand {:?} in trans_rvalue_operand", |
246 | operand); | |
92a42be0 SL |
247 | } |
248 | } | |
249 | } | |
32a655c1 SL |
250 | mir::CastKind::Misc if common::type_is_fat_ptr(bcx.ccx, operand.ty) => { |
251 | let ll_cast_ty = type_of::immediate_type_of(bcx.ccx, cast_ty); | |
252 | let ll_from_ty = type_of::immediate_type_of(bcx.ccx, operand.ty); | |
5bcae85e | 253 | if let OperandValue::Pair(data_ptr, meta_ptr) = operand.val { |
32a655c1 | 254 | if common::type_is_fat_ptr(bcx.ccx, cast_ty) { |
5bcae85e SL |
255 | let ll_cft = ll_cast_ty.field_types(); |
256 | let ll_fft = ll_from_ty.field_types(); | |
257 | let data_cast = bcx.pointercast(data_ptr, ll_cft[0]); | |
258 | assert_eq!(ll_cft[1].kind(), ll_fft[1].kind()); | |
259 | OperandValue::Pair(data_cast, meta_ptr) | |
260 | } else { // cast to thin-ptr | |
261 | // Cast of fat-ptr to thin-ptr is an extraction of data-ptr and | |
262 | // pointer-cast of that pointer to desired pointer type. | |
263 | let llval = bcx.pointercast(data_ptr, ll_cast_ty); | |
264 | OperandValue::Immediate(llval) | |
265 | } | |
266 | } else { | |
267 | bug!("Unexpected non-Pair operand") | |
268 | } | |
269 | } | |
270 | mir::CastKind::Misc => { | |
32a655c1 | 271 | debug_assert!(common::type_is_immediate(bcx.ccx, cast_ty)); |
9cc50fc6 SL |
272 | let r_t_in = CastTy::from_ty(operand.ty).expect("bad input type for cast"); |
273 | let r_t_out = CastTy::from_ty(cast_ty).expect("bad output type for cast"); | |
32a655c1 SL |
274 | let ll_t_in = type_of::immediate_type_of(bcx.ccx, operand.ty); |
275 | let ll_t_out = type_of::immediate_type_of(bcx.ccx, cast_ty); | |
276 | let llval = operand.immediate(); | |
277 | let l = bcx.ccx.layout_of(operand.ty); | |
278 | let signed = if let Layout::CEnum { signed, min, max, .. } = *l { | |
c30ab7b3 SL |
279 | if max > min { |
280 | // We want `table[e as usize]` to not | |
281 | // have bound checks, and this is the most | |
282 | // convenient place to put the `assume`. | |
283 | ||
284 | base::call_assume(&bcx, bcx.icmp( | |
285 | llvm::IntULE, | |
32a655c1 SL |
286 | llval, |
287 | C_integral(common::val_ty(llval), max, false) | |
288 | )); | |
c30ab7b3 SL |
289 | } |
290 | ||
32a655c1 | 291 | signed |
9cc50fc6 | 292 | } else { |
32a655c1 | 293 | operand.ty.is_signed() |
9cc50fc6 SL |
294 | }; |
295 | ||
296 | let newval = match (r_t_in, r_t_out) { | |
297 | (CastTy::Int(_), CastTy::Int(_)) => { | |
8bb4bdeb | 298 | bcx.intcast(llval, ll_t_out, signed) |
9cc50fc6 SL |
299 | } |
300 | (CastTy::Float, CastTy::Float) => { | |
301 | let srcsz = ll_t_in.float_width(); | |
302 | let dstsz = ll_t_out.float_width(); | |
303 | if dstsz > srcsz { | |
7453a54e | 304 | bcx.fpext(llval, ll_t_out) |
9cc50fc6 | 305 | } else if srcsz > dstsz { |
7453a54e | 306 | bcx.fptrunc(llval, ll_t_out) |
9cc50fc6 SL |
307 | } else { |
308 | llval | |
309 | } | |
310 | } | |
311 | (CastTy::Ptr(_), CastTy::Ptr(_)) | | |
312 | (CastTy::FnPtr, CastTy::Ptr(_)) | | |
313 | (CastTy::RPtr(_), CastTy::Ptr(_)) => | |
7453a54e | 314 | bcx.pointercast(llval, ll_t_out), |
9cc50fc6 SL |
315 | (CastTy::Ptr(_), CastTy::Int(_)) | |
316 | (CastTy::FnPtr, CastTy::Int(_)) => | |
7453a54e | 317 | bcx.ptrtoint(llval, ll_t_out), |
9cc50fc6 | 318 | (CastTy::Int(_), CastTy::Ptr(_)) => |
7453a54e | 319 | bcx.inttoptr(llval, ll_t_out), |
9cc50fc6 | 320 | (CastTy::Int(_), CastTy::Float) if signed => |
7453a54e | 321 | bcx.sitofp(llval, ll_t_out), |
9cc50fc6 | 322 | (CastTy::Int(_), CastTy::Float) => |
7453a54e | 323 | bcx.uitofp(llval, ll_t_out), |
9cc50fc6 | 324 | (CastTy::Float, CastTy::Int(IntTy::I)) => |
7453a54e | 325 | bcx.fptosi(llval, ll_t_out), |
9cc50fc6 | 326 | (CastTy::Float, CastTy::Int(_)) => |
7453a54e | 327 | bcx.fptoui(llval, ll_t_out), |
54a0048b | 328 | _ => bug!("unsupported cast: {:?} to {:?}", operand.ty, cast_ty) |
9cc50fc6 SL |
329 | }; |
330 | OperandValue::Immediate(newval) | |
331 | } | |
92a42be0 | 332 | }; |
7453a54e | 333 | let operand = OperandRef { |
92a42be0 SL |
334 | val: val, |
335 | ty: cast_ty | |
7453a54e SL |
336 | }; |
337 | (bcx, operand) | |
92a42be0 SL |
338 | } |
339 | ||
340 | mir::Rvalue::Ref(_, bk, ref lvalue) => { | |
7453a54e | 341 | let tr_lvalue = self.trans_lvalue(&bcx, lvalue); |
92a42be0 SL |
342 | |
343 | let ty = tr_lvalue.ty.to_ty(bcx.tcx()); | |
344 | let ref_ty = bcx.tcx().mk_ref( | |
3157f602 | 345 | bcx.tcx().mk_region(ty::ReErased), |
92a42be0 SL |
346 | ty::TypeAndMut { ty: ty, mutbl: bk.to_mutbl_lossy() } |
347 | ); | |
348 | ||
349 | // Note: lvalues are indirect, so storing the `llval` into the | |
350 | // destination effectively creates a reference. | |
32a655c1 | 351 | let operand = if bcx.ccx.shared().type_is_sized(ty) { |
7453a54e | 352 | OperandRef { |
92a42be0 SL |
353 | val: OperandValue::Immediate(tr_lvalue.llval), |
354 | ty: ref_ty, | |
7453a54e | 355 | } |
92a42be0 | 356 | } else { |
7453a54e | 357 | OperandRef { |
3157f602 XL |
358 | val: OperandValue::Pair(tr_lvalue.llval, |
359 | tr_lvalue.llextra), | |
92a42be0 | 360 | ty: ref_ty, |
7453a54e SL |
361 | } |
362 | }; | |
363 | (bcx, operand) | |
92a42be0 SL |
364 | } |
365 | ||
366 | mir::Rvalue::Len(ref lvalue) => { | |
7453a54e SL |
367 | let tr_lvalue = self.trans_lvalue(&bcx, lvalue); |
368 | let operand = OperandRef { | |
32a655c1 | 369 | val: OperandValue::Immediate(tr_lvalue.len(bcx.ccx)), |
92a42be0 | 370 | ty: bcx.tcx().types.usize, |
7453a54e SL |
371 | }; |
372 | (bcx, operand) | |
92a42be0 SL |
373 | } |
374 | ||
375 | mir::Rvalue::BinaryOp(op, ref lhs, ref rhs) => { | |
7453a54e SL |
376 | let lhs = self.trans_operand(&bcx, lhs); |
377 | let rhs = self.trans_operand(&bcx, rhs); | |
32a655c1 | 378 | let llresult = if common::type_is_fat_ptr(bcx.ccx, lhs.ty) { |
92a42be0 | 379 | match (lhs.val, rhs.val) { |
3157f602 XL |
380 | (OperandValue::Pair(lhs_addr, lhs_extra), |
381 | OperandValue::Pair(rhs_addr, rhs_extra)) => { | |
c30ab7b3 SL |
382 | self.trans_fat_ptr_binop(&bcx, op, |
383 | lhs_addr, lhs_extra, | |
384 | rhs_addr, rhs_extra, | |
385 | lhs.ty) | |
92a42be0 | 386 | } |
54a0048b | 387 | _ => bug!() |
92a42be0 SL |
388 | } |
389 | ||
390 | } else { | |
7453a54e | 391 | self.trans_scalar_binop(&bcx, op, |
92a42be0 | 392 | lhs.immediate(), rhs.immediate(), |
7453a54e | 393 | lhs.ty) |
92a42be0 | 394 | }; |
7453a54e | 395 | let operand = OperandRef { |
92a42be0 | 396 | val: OperandValue::Immediate(llresult), |
5bcae85e | 397 | ty: op.ty(bcx.tcx(), lhs.ty, rhs.ty), |
7453a54e SL |
398 | }; |
399 | (bcx, operand) | |
92a42be0 | 400 | } |
3157f602 XL |
401 | mir::Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) => { |
402 | let lhs = self.trans_operand(&bcx, lhs); | |
403 | let rhs = self.trans_operand(&bcx, rhs); | |
404 | let result = self.trans_scalar_checked_binop(&bcx, op, | |
405 | lhs.immediate(), rhs.immediate(), | |
406 | lhs.ty); | |
5bcae85e | 407 | let val_ty = op.ty(bcx.tcx(), lhs.ty, rhs.ty); |
8bb4bdeb | 408 | let operand_ty = bcx.tcx().intern_tup(&[val_ty, bcx.tcx().types.bool], false); |
3157f602 XL |
409 | let operand = OperandRef { |
410 | val: result, | |
411 | ty: operand_ty | |
412 | }; | |
413 | ||
414 | (bcx, operand) | |
415 | } | |
92a42be0 SL |
416 | |
417 | mir::Rvalue::UnaryOp(op, ref operand) => { | |
7453a54e | 418 | let operand = self.trans_operand(&bcx, operand); |
92a42be0 SL |
419 | let lloperand = operand.immediate(); |
420 | let is_float = operand.ty.is_fp(); | |
92a42be0 | 421 | let llval = match op { |
7453a54e | 422 | mir::UnOp::Not => bcx.not(lloperand), |
92a42be0 | 423 | mir::UnOp::Neg => if is_float { |
7453a54e | 424 | bcx.fneg(lloperand) |
92a42be0 | 425 | } else { |
7453a54e | 426 | bcx.neg(lloperand) |
92a42be0 SL |
427 | } |
428 | }; | |
429 | (bcx, OperandRef { | |
430 | val: OperandValue::Immediate(llval), | |
431 | ty: operand.ty, | |
432 | }) | |
433 | } | |
434 | ||
8bb4bdeb XL |
435 | mir::Rvalue::Discriminant(ref lvalue) => { |
436 | let discr_lvalue = self.trans_lvalue(&bcx, lvalue); | |
437 | let enum_ty = discr_lvalue.ty.to_ty(bcx.tcx()); | |
438 | let discr_ty = rvalue.ty(&*self.mir, bcx.tcx()); | |
439 | let discr_type = type_of::immediate_type_of(bcx.ccx, discr_ty); | |
440 | let discr = adt::trans_get_discr(&bcx, enum_ty, discr_lvalue.llval, | |
441 | discr_lvalue.alignment, Some(discr_type), true); | |
442 | (bcx, OperandRef { | |
443 | val: OperandValue::Immediate(discr), | |
444 | ty: discr_ty | |
445 | }) | |
446 | } | |
447 | ||
92a42be0 | 448 | mir::Rvalue::Box(content_ty) => { |
32a655c1 SL |
449 | let content_ty: Ty<'tcx> = self.monomorphize(&content_ty); |
450 | let llty = type_of::type_of(bcx.ccx, content_ty); | |
451 | let llsize = machine::llsize_of(bcx.ccx, llty); | |
452 | let align = type_of::align_of(bcx.ccx, content_ty); | |
453 | let llalign = C_uint(bcx.ccx, align); | |
92a42be0 SL |
454 | let llty_ptr = llty.ptr_to(); |
455 | let box_ty = bcx.tcx().mk_box(content_ty); | |
32a655c1 SL |
456 | |
457 | // Allocate space: | |
458 | let def_id = match bcx.tcx().lang_items.require(ExchangeMallocFnLangItem) { | |
459 | Ok(id) => id, | |
460 | Err(s) => { | |
461 | bcx.sess().fatal(&format!("allocation of `{}` {}", box_ty, s)); | |
462 | } | |
463 | }; | |
464 | let r = Callee::def(bcx.ccx, def_id, bcx.tcx().intern_substs(&[])) | |
465 | .reify(bcx.ccx); | |
466 | let val = bcx.pointercast(bcx.call(r, &[llsize, llalign], None), llty_ptr); | |
467 | ||
7453a54e | 468 | let operand = OperandRef { |
32a655c1 | 469 | val: OperandValue::Immediate(val), |
92a42be0 | 470 | ty: box_ty, |
7453a54e SL |
471 | }; |
472 | (bcx, operand) | |
92a42be0 SL |
473 | } |
474 | ||
a7813a04 XL |
475 | mir::Rvalue::Use(ref operand) => { |
476 | let operand = self.trans_operand(&bcx, operand); | |
477 | (bcx, operand) | |
478 | } | |
92a42be0 | 479 | mir::Rvalue::Repeat(..) | |
8bb4bdeb | 480 | mir::Rvalue::Aggregate(..) => { |
54a0048b SL |
481 | bug!("cannot generate operand from rvalue {:?}", rvalue); |
482 | ||
92a42be0 SL |
483 | } |
484 | } | |
485 | } | |
486 | ||
487 | pub fn trans_scalar_binop(&mut self, | |
32a655c1 | 488 | bcx: &Builder<'a, 'tcx>, |
92a42be0 SL |
489 | op: mir::BinOp, |
490 | lhs: ValueRef, | |
491 | rhs: ValueRef, | |
7453a54e | 492 | input_ty: Ty<'tcx>) -> ValueRef { |
92a42be0 SL |
493 | let is_float = input_ty.is_fp(); |
494 | let is_signed = input_ty.is_signed(); | |
c30ab7b3 SL |
495 | let is_nil = input_ty.is_nil(); |
496 | let is_bool = input_ty.is_bool(); | |
92a42be0 SL |
497 | match op { |
498 | mir::BinOp::Add => if is_float { | |
7453a54e | 499 | bcx.fadd(lhs, rhs) |
92a42be0 | 500 | } else { |
7453a54e | 501 | bcx.add(lhs, rhs) |
92a42be0 SL |
502 | }, |
503 | mir::BinOp::Sub => if is_float { | |
7453a54e | 504 | bcx.fsub(lhs, rhs) |
92a42be0 | 505 | } else { |
7453a54e | 506 | bcx.sub(lhs, rhs) |
92a42be0 SL |
507 | }, |
508 | mir::BinOp::Mul => if is_float { | |
7453a54e | 509 | bcx.fmul(lhs, rhs) |
92a42be0 | 510 | } else { |
7453a54e | 511 | bcx.mul(lhs, rhs) |
92a42be0 SL |
512 | }, |
513 | mir::BinOp::Div => if is_float { | |
7453a54e | 514 | bcx.fdiv(lhs, rhs) |
92a42be0 | 515 | } else if is_signed { |
7453a54e | 516 | bcx.sdiv(lhs, rhs) |
92a42be0 | 517 | } else { |
7453a54e | 518 | bcx.udiv(lhs, rhs) |
92a42be0 SL |
519 | }, |
520 | mir::BinOp::Rem => if is_float { | |
a7813a04 | 521 | bcx.frem(lhs, rhs) |
92a42be0 | 522 | } else if is_signed { |
7453a54e | 523 | bcx.srem(lhs, rhs) |
92a42be0 | 524 | } else { |
7453a54e | 525 | bcx.urem(lhs, rhs) |
92a42be0 | 526 | }, |
7453a54e SL |
527 | mir::BinOp::BitOr => bcx.or(lhs, rhs), |
528 | mir::BinOp::BitAnd => bcx.and(lhs, rhs), | |
529 | mir::BinOp::BitXor => bcx.xor(lhs, rhs), | |
32a655c1 SL |
530 | mir::BinOp::Shl => common::build_unchecked_lshift(bcx, lhs, rhs), |
531 | mir::BinOp::Shr => common::build_unchecked_rshift(bcx, input_ty, lhs, rhs), | |
c30ab7b3 SL |
532 | mir::BinOp::Ne | mir::BinOp::Lt | mir::BinOp::Gt | |
533 | mir::BinOp::Eq | mir::BinOp::Le | mir::BinOp::Ge => if is_nil { | |
32a655c1 | 534 | C_bool(bcx.ccx, match op { |
c30ab7b3 SL |
535 | mir::BinOp::Ne | mir::BinOp::Lt | mir::BinOp::Gt => false, |
536 | mir::BinOp::Eq | mir::BinOp::Le | mir::BinOp::Ge => true, | |
537 | _ => unreachable!() | |
7453a54e | 538 | }) |
c30ab7b3 SL |
539 | } else if is_float { |
540 | bcx.fcmp( | |
541 | base::bin_op_to_fcmp_predicate(op.to_hir_binop()), | |
542 | lhs, rhs | |
543 | ) | |
544 | } else { | |
545 | let (lhs, rhs) = if is_bool { | |
546 | // FIXME(#36856) -- extend the bools into `i8` because | |
547 | // LLVM's i1 comparisons are broken. | |
32a655c1 SL |
548 | (bcx.zext(lhs, Type::i8(bcx.ccx)), |
549 | bcx.zext(rhs, Type::i8(bcx.ccx))) | |
c30ab7b3 SL |
550 | } else { |
551 | (lhs, rhs) | |
552 | }; | |
553 | ||
554 | bcx.icmp( | |
555 | base::bin_op_to_icmp_predicate(op.to_hir_binop(), is_signed), | |
556 | lhs, rhs | |
557 | ) | |
558 | } | |
559 | } | |
560 | } | |
561 | ||
562 | pub fn trans_fat_ptr_binop(&mut self, | |
32a655c1 | 563 | bcx: &Builder<'a, 'tcx>, |
c30ab7b3 SL |
564 | op: mir::BinOp, |
565 | lhs_addr: ValueRef, | |
566 | lhs_extra: ValueRef, | |
567 | rhs_addr: ValueRef, | |
568 | rhs_extra: ValueRef, | |
569 | _input_ty: Ty<'tcx>) | |
570 | -> ValueRef { | |
571 | match op { | |
572 | mir::BinOp::Eq => { | |
573 | bcx.and( | |
574 | bcx.icmp(llvm::IntEQ, lhs_addr, rhs_addr), | |
575 | bcx.icmp(llvm::IntEQ, lhs_extra, rhs_extra) | |
576 | ) | |
577 | } | |
578 | mir::BinOp::Ne => { | |
579 | bcx.or( | |
580 | bcx.icmp(llvm::IntNE, lhs_addr, rhs_addr), | |
581 | bcx.icmp(llvm::IntNE, lhs_extra, rhs_extra) | |
582 | ) | |
583 | } | |
584 | mir::BinOp::Le | mir::BinOp::Lt | | |
585 | mir::BinOp::Ge | mir::BinOp::Gt => { | |
586 | // a OP b ~ a.0 STRICT(OP) b.0 | (a.0 == b.0 && a.1 OP a.1) | |
587 | let (op, strict_op) = match op { | |
588 | mir::BinOp::Lt => (llvm::IntULT, llvm::IntULT), | |
589 | mir::BinOp::Le => (llvm::IntULE, llvm::IntULT), | |
590 | mir::BinOp::Gt => (llvm::IntUGT, llvm::IntUGT), | |
591 | mir::BinOp::Ge => (llvm::IntUGE, llvm::IntUGT), | |
592 | _ => bug!(), | |
593 | }; | |
594 | ||
595 | bcx.or( | |
596 | bcx.icmp(strict_op, lhs_addr, rhs_addr), | |
597 | bcx.and( | |
598 | bcx.icmp(llvm::IntEQ, lhs_addr, rhs_addr), | |
599 | bcx.icmp(op, lhs_extra, rhs_extra) | |
600 | ) | |
601 | ) | |
602 | } | |
603 | _ => { | |
604 | bug!("unexpected fat ptr binop"); | |
92a42be0 SL |
605 | } |
606 | } | |
607 | } | |
3157f602 XL |
608 | |
609 | pub fn trans_scalar_checked_binop(&mut self, | |
32a655c1 | 610 | bcx: &Builder<'a, 'tcx>, |
3157f602 XL |
611 | op: mir::BinOp, |
612 | lhs: ValueRef, | |
613 | rhs: ValueRef, | |
614 | input_ty: Ty<'tcx>) -> OperandValue { | |
615 | // This case can currently arise only from functions marked | |
616 | // with #[rustc_inherit_overflow_checks] and inlined from | |
617 | // another crate (mostly core::num generic/#[inline] fns), | |
618 | // while the current crate doesn't use overflow checks. | |
32a655c1 | 619 | if !bcx.ccx.check_overflow() { |
3157f602 | 620 | let val = self.trans_scalar_binop(bcx, op, lhs, rhs, input_ty); |
32a655c1 | 621 | return OperandValue::Pair(val, C_bool(bcx.ccx, false)); |
3157f602 XL |
622 | } |
623 | ||
624 | // First try performing the operation on constants, which | |
625 | // will only succeed if both operands are constant. | |
626 | // This is necessary to determine when an overflow Assert | |
627 | // will always panic at runtime, and produce a warning. | |
628 | if let Some((val, of)) = const_scalar_checked_binop(bcx.tcx(), op, lhs, rhs, input_ty) { | |
32a655c1 | 629 | return OperandValue::Pair(val, C_bool(bcx.ccx, of)); |
3157f602 XL |
630 | } |
631 | ||
632 | let (val, of) = match op { | |
633 | // These are checked using intrinsics | |
634 | mir::BinOp::Add | mir::BinOp::Sub | mir::BinOp::Mul => { | |
635 | let oop = match op { | |
636 | mir::BinOp::Add => OverflowOp::Add, | |
637 | mir::BinOp::Sub => OverflowOp::Sub, | |
638 | mir::BinOp::Mul => OverflowOp::Mul, | |
639 | _ => unreachable!() | |
640 | }; | |
641 | let intrinsic = get_overflow_intrinsic(oop, bcx, input_ty); | |
642 | let res = bcx.call(intrinsic, &[lhs, rhs], None); | |
643 | ||
644 | (bcx.extract_value(res, 0), | |
645 | bcx.extract_value(res, 1)) | |
646 | } | |
647 | mir::BinOp::Shl | mir::BinOp::Shr => { | |
648 | let lhs_llty = val_ty(lhs); | |
649 | let rhs_llty = val_ty(rhs); | |
32a655c1 | 650 | let invert_mask = common::shift_mask_val(&bcx, lhs_llty, rhs_llty, true); |
3157f602 XL |
651 | let outer_bits = bcx.and(rhs, invert_mask); |
652 | ||
653 | let of = bcx.icmp(llvm::IntNE, outer_bits, C_null(rhs_llty)); | |
654 | let val = self.trans_scalar_binop(bcx, op, lhs, rhs, input_ty); | |
655 | ||
656 | (val, of) | |
657 | } | |
658 | _ => { | |
659 | bug!("Operator `{:?}` is not a checkable operator", op) | |
660 | } | |
661 | }; | |
662 | ||
663 | OperandValue::Pair(val, of) | |
664 | } | |
92a42be0 SL |
665 | } |
666 | ||
32a655c1 | 667 | pub fn rvalue_creates_operand(rvalue: &mir::Rvalue) -> bool { |
92a42be0 | 668 | match *rvalue { |
92a42be0 SL |
669 | mir::Rvalue::Ref(..) | |
670 | mir::Rvalue::Len(..) | | |
671 | mir::Rvalue::Cast(..) | // (*) | |
672 | mir::Rvalue::BinaryOp(..) | | |
3157f602 | 673 | mir::Rvalue::CheckedBinaryOp(..) | |
92a42be0 | 674 | mir::Rvalue::UnaryOp(..) | |
8bb4bdeb | 675 | mir::Rvalue::Discriminant(..) | |
3157f602 XL |
676 | mir::Rvalue::Box(..) | |
677 | mir::Rvalue::Use(..) => | |
92a42be0 SL |
678 | true, |
679 | mir::Rvalue::Repeat(..) | | |
8bb4bdeb | 680 | mir::Rvalue::Aggregate(..) => |
92a42be0 SL |
681 | false, |
682 | } | |
683 | ||
684 | // (*) this is only true if the type is suitable | |
685 | } | |
3157f602 XL |
686 | |
687 | #[derive(Copy, Clone)] | |
688 | enum OverflowOp { | |
689 | Add, Sub, Mul | |
690 | } | |
691 | ||
32a655c1 | 692 | fn get_overflow_intrinsic(oop: OverflowOp, bcx: &Builder, ty: Ty) -> ValueRef { |
3157f602 XL |
693 | use syntax::ast::IntTy::*; |
694 | use syntax::ast::UintTy::*; | |
695 | use rustc::ty::{TyInt, TyUint}; | |
696 | ||
697 | let tcx = bcx.tcx(); | |
698 | ||
699 | let new_sty = match ty.sty { | |
700 | TyInt(Is) => match &tcx.sess.target.target.target_pointer_width[..] { | |
476ff2be | 701 | "16" => TyInt(I16), |
3157f602 XL |
702 | "32" => TyInt(I32), |
703 | "64" => TyInt(I64), | |
704 | _ => panic!("unsupported target word size") | |
705 | }, | |
706 | TyUint(Us) => match &tcx.sess.target.target.target_pointer_width[..] { | |
476ff2be | 707 | "16" => TyUint(U16), |
3157f602 XL |
708 | "32" => TyUint(U32), |
709 | "64" => TyUint(U64), | |
710 | _ => panic!("unsupported target word size") | |
711 | }, | |
712 | ref t @ TyUint(_) | ref t @ TyInt(_) => t.clone(), | |
713 | _ => panic!("tried to get overflow intrinsic for op applied to non-int type") | |
714 | }; | |
715 | ||
716 | let name = match oop { | |
717 | OverflowOp::Add => match new_sty { | |
718 | TyInt(I8) => "llvm.sadd.with.overflow.i8", | |
719 | TyInt(I16) => "llvm.sadd.with.overflow.i16", | |
720 | TyInt(I32) => "llvm.sadd.with.overflow.i32", | |
721 | TyInt(I64) => "llvm.sadd.with.overflow.i64", | |
32a655c1 | 722 | TyInt(I128) => "llvm.sadd.with.overflow.i128", |
3157f602 XL |
723 | |
724 | TyUint(U8) => "llvm.uadd.with.overflow.i8", | |
725 | TyUint(U16) => "llvm.uadd.with.overflow.i16", | |
726 | TyUint(U32) => "llvm.uadd.with.overflow.i32", | |
727 | TyUint(U64) => "llvm.uadd.with.overflow.i64", | |
32a655c1 | 728 | TyUint(U128) => "llvm.uadd.with.overflow.i128", |
3157f602 XL |
729 | |
730 | _ => unreachable!(), | |
731 | }, | |
732 | OverflowOp::Sub => match new_sty { | |
733 | TyInt(I8) => "llvm.ssub.with.overflow.i8", | |
734 | TyInt(I16) => "llvm.ssub.with.overflow.i16", | |
735 | TyInt(I32) => "llvm.ssub.with.overflow.i32", | |
736 | TyInt(I64) => "llvm.ssub.with.overflow.i64", | |
32a655c1 | 737 | TyInt(I128) => "llvm.ssub.with.overflow.i128", |
3157f602 XL |
738 | |
739 | TyUint(U8) => "llvm.usub.with.overflow.i8", | |
740 | TyUint(U16) => "llvm.usub.with.overflow.i16", | |
741 | TyUint(U32) => "llvm.usub.with.overflow.i32", | |
742 | TyUint(U64) => "llvm.usub.with.overflow.i64", | |
32a655c1 | 743 | TyUint(U128) => "llvm.usub.with.overflow.i128", |
3157f602 XL |
744 | |
745 | _ => unreachable!(), | |
746 | }, | |
747 | OverflowOp::Mul => match new_sty { | |
748 | TyInt(I8) => "llvm.smul.with.overflow.i8", | |
749 | TyInt(I16) => "llvm.smul.with.overflow.i16", | |
750 | TyInt(I32) => "llvm.smul.with.overflow.i32", | |
751 | TyInt(I64) => "llvm.smul.with.overflow.i64", | |
32a655c1 | 752 | TyInt(I128) => "llvm.smul.with.overflow.i128", |
3157f602 XL |
753 | |
754 | TyUint(U8) => "llvm.umul.with.overflow.i8", | |
755 | TyUint(U16) => "llvm.umul.with.overflow.i16", | |
756 | TyUint(U32) => "llvm.umul.with.overflow.i32", | |
757 | TyUint(U64) => "llvm.umul.with.overflow.i64", | |
32a655c1 | 758 | TyUint(U128) => "llvm.umul.with.overflow.i128", |
3157f602 XL |
759 | |
760 | _ => unreachable!(), | |
761 | }, | |
762 | }; | |
763 | ||
32a655c1 | 764 | bcx.ccx.get_intrinsic(&name) |
3157f602 | 765 | } |