]> git.proxmox.com Git - rustc.git/blame - src/librustc_trans/mir/rvalue.rs
New upstream version 1.17.0+dfsg1
[rustc.git] / src / librustc_trans / mir / rvalue.rs
CommitLineData
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 11use llvm::{self, ValueRef};
54a0048b
SL
12use rustc::ty::{self, Ty};
13use rustc::ty::cast::{CastTy, IntTy};
c30ab7b3 14use rustc::ty::layout::Layout;
8bb4bdeb 15use rustc::ty::subst::{Kind, Subst};
32a655c1 16use rustc::mir::tcx::LvalueTy;
c30ab7b3 17use rustc::mir;
32a655c1 18use middle::lang_items::ExchangeMallocFnLangItem;
92a42be0 19
54a0048b 20use base;
32a655c1 21use builder::Builder;
54a0048b 22use callee::Callee;
32a655c1 23use common::{self, val_ty, C_bool, C_null, C_uint};
c30ab7b3 24use common::{C_integral};
54a0048b
SL
25use adt;
26use machine;
c30ab7b3 27use type_::Type;
54a0048b
SL
28use type_of;
29use tvec;
30use value::Value;
31use Disr;
92a42be0
SL
32
33use super::MirContext;
3157f602 34use super::constant::const_scalar_checked_binop;
92a42be0 35use super::operand::{OperandRef, OperandValue};
32a655c1 36use super::lvalue::LvalueRef;
92a42be0 37
32a655c1 38impl<'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 667pub 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)]
688enum OverflowOp {
689 Add, Sub, Mul
690}
691
32a655c1 692fn 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}