]>
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 | ||
11 | use llvm::ValueRef; | |
12 | use rustc::middle::ty::{self, Ty}; | |
9cc50fc6 | 13 | use middle::ty::cast::{CastTy, IntTy}; |
92a42be0 SL |
14 | use rustc::mir::repr as mir; |
15 | ||
16 | use trans::asm; | |
17 | use trans::base; | |
7453a54e | 18 | use trans::common::{self, BlockAndBuilder, Result}; |
92a42be0 SL |
19 | use trans::debuginfo::DebugLoc; |
20 | use trans::declare; | |
21 | use trans::expr; | |
9cc50fc6 | 22 | use trans::adt; |
92a42be0 SL |
23 | use trans::machine; |
24 | use trans::type_::Type; | |
25 | use trans::type_of; | |
26 | use trans::tvec; | |
9cc50fc6 | 27 | use trans::Disr; |
92a42be0 SL |
28 | |
29 | use super::MirContext; | |
30 | use super::operand::{OperandRef, OperandValue}; | |
9cc50fc6 | 31 | use super::lvalue::LvalueRef; |
92a42be0 SL |
32 | |
33 | impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { | |
34 | pub fn trans_rvalue(&mut self, | |
7453a54e | 35 | bcx: BlockAndBuilder<'bcx, 'tcx>, |
9cc50fc6 | 36 | dest: LvalueRef<'tcx>, |
92a42be0 | 37 | rvalue: &mir::Rvalue<'tcx>) |
7453a54e | 38 | -> BlockAndBuilder<'bcx, 'tcx> |
92a42be0 | 39 | { |
9cc50fc6 SL |
40 | debug!("trans_rvalue(dest.llval={}, rvalue={:?})", |
41 | bcx.val_to_string(dest.llval), | |
92a42be0 SL |
42 | rvalue); |
43 | ||
44 | match *rvalue { | |
45 | mir::Rvalue::Use(ref operand) => { | |
7453a54e | 46 | self.trans_operand_into(&bcx, dest.llval, operand); |
92a42be0 SL |
47 | bcx |
48 | } | |
49 | ||
50 | mir::Rvalue::Cast(mir::CastKind::Unsize, ref operand, cast_ty) => { | |
51 | if common::type_is_fat_ptr(bcx.tcx(), cast_ty) { | |
52 | // into-coerce of a thin pointer to a fat pointer - just | |
53 | // use the operand path. | |
54 | let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue); | |
7453a54e | 55 | self.store_operand(&bcx, dest.llval, temp); |
92a42be0 SL |
56 | return bcx; |
57 | } | |
58 | ||
59 | // Unsize of a nontrivial struct. I would prefer for | |
60 | // this to be eliminated by MIR translation, but | |
61 | // `CoerceUnsized` can be passed by a where-clause, | |
62 | // so the (generic) MIR may not be able to expand it. | |
7453a54e SL |
63 | let operand = self.trans_operand(&bcx, operand); |
64 | bcx.with_block(|bcx| { | |
65 | match operand.val { | |
66 | OperandValue::FatPtr(..) => unreachable!(), | |
67 | OperandValue::Immediate(llval) => { | |
68 | // unsize from an immediate structure. We don't | |
69 | // really need a temporary alloca here, but | |
70 | // avoiding it would require us to have | |
71 | // `coerce_unsized_into` use extractvalue to | |
72 | // index into the struct, and this case isn't | |
73 | // important enough for it. | |
74 | debug!("trans_rvalue: creating ugly alloca"); | |
75 | let lltemp = base::alloc_ty(bcx, operand.ty, "__unsize_temp"); | |
76 | base::store_ty(bcx, llval, lltemp, operand.ty); | |
77 | base::coerce_unsized_into(bcx, | |
78 | lltemp, operand.ty, | |
79 | dest.llval, cast_ty); | |
80 | } | |
81 | OperandValue::Ref(llref) => { | |
82 | base::coerce_unsized_into(bcx, | |
83 | llref, operand.ty, | |
84 | dest.llval, cast_ty); | |
85 | } | |
92a42be0 | 86 | } |
7453a54e | 87 | }); |
92a42be0 SL |
88 | bcx |
89 | } | |
90 | ||
91 | mir::Rvalue::Repeat(ref elem, ref count) => { | |
7453a54e SL |
92 | let elem = self.trans_operand(&bcx, elem); |
93 | let size = self.trans_constval(&bcx, &count.value, count.ty).immediate(); | |
94 | bcx.map_block(|block| { | |
95 | let base = expr::get_dataptr(block, dest.llval); | |
96 | tvec::iter_vec_raw(block, base, elem.ty, size, |block, llslot, _| { | |
97 | self.store_operand_direct(block, llslot, elem); | |
98 | block | |
99 | }) | |
92a42be0 SL |
100 | }) |
101 | } | |
102 | ||
9cc50fc6 SL |
103 | mir::Rvalue::Aggregate(ref kind, ref operands) => { |
104 | match *kind { | |
105 | mir::AggregateKind::Adt(adt_def, index, _) => { | |
106 | let repr = adt::represent_type(bcx.ccx(), dest.ty.to_ty(bcx.tcx())); | |
107 | let disr = Disr::from(adt_def.variants[index].disr_val); | |
7453a54e SL |
108 | bcx.with_block(|bcx| { |
109 | adt::trans_set_discr(bcx, &repr, dest.llval, Disr::from(disr)); | |
110 | }); | |
9cc50fc6 | 111 | for (i, operand) in operands.iter().enumerate() { |
7453a54e | 112 | let op = self.trans_operand(&bcx, operand); |
9cc50fc6 SL |
113 | // Do not generate stores and GEPis for zero-sized fields. |
114 | if !common::type_is_zero_size(bcx.ccx(), op.ty) { | |
115 | let val = adt::MaybeSizedValue::sized(dest.llval); | |
7453a54e SL |
116 | let lldest_i = bcx.with_block(|bcx| { |
117 | adt::trans_field_ptr(bcx, &repr, val, disr, i) | |
118 | }); | |
119 | self.store_operand(&bcx, lldest_i, op); | |
9cc50fc6 SL |
120 | } |
121 | } | |
122 | }, | |
123 | _ => { | |
124 | for (i, operand) in operands.iter().enumerate() { | |
7453a54e | 125 | let op = self.trans_operand(&bcx, operand); |
9cc50fc6 SL |
126 | // Do not generate stores and GEPis for zero-sized fields. |
127 | if !common::type_is_zero_size(bcx.ccx(), op.ty) { | |
128 | // Note: perhaps this should be StructGep, but | |
129 | // note that in some cases the values here will | |
130 | // not be structs but arrays. | |
7453a54e SL |
131 | let dest = bcx.gepi(dest.llval, &[0, i]); |
132 | self.store_operand(&bcx, dest, op); | |
9cc50fc6 SL |
133 | } |
134 | } | |
135 | } | |
92a42be0 SL |
136 | } |
137 | bcx | |
138 | } | |
139 | ||
140 | mir::Rvalue::Slice { ref input, from_start, from_end } => { | |
141 | let ccx = bcx.ccx(); | |
7453a54e SL |
142 | let input = self.trans_lvalue(&bcx, input); |
143 | let (llbase, lllen) = bcx.with_block(|bcx| { | |
144 | tvec::get_base_and_len(bcx, | |
145 | input.llval, | |
146 | input.ty.to_ty(bcx.tcx())) | |
147 | }); | |
148 | let llbase1 = bcx.gepi(llbase, &[from_start]); | |
92a42be0 | 149 | let adj = common::C_uint(ccx, from_start + from_end); |
7453a54e SL |
150 | let lllen1 = bcx.sub(lllen, adj); |
151 | let (lladdrdest, llmetadest) = bcx.with_block(|bcx| { | |
152 | (expr::get_dataptr(bcx, dest.llval), expr::get_meta(bcx, dest.llval)) | |
153 | }); | |
154 | bcx.store(llbase1, lladdrdest); | |
155 | bcx.store(lllen1, llmetadest); | |
92a42be0 SL |
156 | bcx |
157 | } | |
158 | ||
9cc50fc6 | 159 | mir::Rvalue::InlineAsm(ref inline_asm) => { |
7453a54e SL |
160 | bcx.map_block(|bcx| { |
161 | asm::trans_inline_asm(bcx, inline_asm) | |
162 | }) | |
92a42be0 SL |
163 | } |
164 | ||
165 | _ => { | |
166 | assert!(rvalue_creates_operand(rvalue)); | |
167 | let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue); | |
7453a54e | 168 | self.store_operand(&bcx, dest.llval, temp); |
92a42be0 SL |
169 | bcx |
170 | } | |
171 | } | |
172 | } | |
173 | ||
174 | pub fn trans_rvalue_operand(&mut self, | |
7453a54e | 175 | bcx: BlockAndBuilder<'bcx, 'tcx>, |
92a42be0 | 176 | rvalue: &mir::Rvalue<'tcx>) |
7453a54e | 177 | -> (BlockAndBuilder<'bcx, 'tcx>, OperandRef<'tcx>) |
92a42be0 SL |
178 | { |
179 | assert!(rvalue_creates_operand(rvalue), "cannot trans {:?} to operand", rvalue); | |
180 | ||
181 | match *rvalue { | |
182 | mir::Rvalue::Use(ref operand) => { | |
7453a54e | 183 | let operand = self.trans_operand(&bcx, operand); |
92a42be0 SL |
184 | (bcx, operand) |
185 | } | |
186 | ||
187 | mir::Rvalue::Cast(ref kind, ref operand, cast_ty) => { | |
7453a54e SL |
188 | let operand = self.trans_operand(&bcx, operand); |
189 | debug!("cast operand is {}", operand.repr(&bcx)); | |
92a42be0 SL |
190 | let cast_ty = bcx.monomorphize(&cast_ty); |
191 | ||
192 | let val = match *kind { | |
193 | mir::CastKind::ReifyFnPointer | | |
194 | mir::CastKind::UnsafeFnPointer => { | |
195 | // these are no-ops at the LLVM level | |
196 | operand.val | |
197 | } | |
198 | mir::CastKind::Unsize => { | |
199 | // unsize targets other than to a fat pointer currently | |
200 | // can't be operands. | |
201 | assert!(common::type_is_fat_ptr(bcx.tcx(), cast_ty)); | |
202 | ||
203 | match operand.val { | |
204 | OperandValue::FatPtr(..) => { | |
205 | // unsize from a fat pointer - this is a | |
206 | // "trait-object-to-supertrait" coercion, for | |
207 | // example, | |
208 | // &'a fmt::Debug+Send => &'a fmt::Debug, | |
209 | // and is a no-op at the LLVM level | |
210 | operand.val | |
211 | } | |
212 | OperandValue::Immediate(lldata) => { | |
213 | // "standard" unsize | |
7453a54e | 214 | let (lldata, llextra) = bcx.with_block(|bcx| { |
92a42be0 | 215 | base::unsize_thin_ptr(bcx, lldata, |
7453a54e SL |
216 | operand.ty, cast_ty) |
217 | }); | |
92a42be0 SL |
218 | OperandValue::FatPtr(lldata, llextra) |
219 | } | |
220 | OperandValue::Ref(_) => { | |
221 | bcx.sess().bug( | |
222 | &format!("by-ref operand {} in trans_rvalue_operand", | |
7453a54e | 223 | operand.repr(&bcx))); |
92a42be0 SL |
224 | } |
225 | } | |
226 | } | |
9cc50fc6 SL |
227 | mir::CastKind::Misc if common::type_is_immediate(bcx.ccx(), operand.ty) => { |
228 | debug_assert!(common::type_is_immediate(bcx.ccx(), cast_ty)); | |
229 | let r_t_in = CastTy::from_ty(operand.ty).expect("bad input type for cast"); | |
230 | let r_t_out = CastTy::from_ty(cast_ty).expect("bad output type for cast"); | |
231 | let ll_t_in = type_of::arg_type_of(bcx.ccx(), operand.ty); | |
232 | let ll_t_out = type_of::arg_type_of(bcx.ccx(), cast_ty); | |
233 | let (llval, ll_t_in, signed) = if let CastTy::Int(IntTy::CEnum) = r_t_in { | |
234 | let repr = adt::represent_type(bcx.ccx(), operand.ty); | |
235 | let llval = operand.immediate(); | |
7453a54e SL |
236 | let discr = bcx.with_block(|bcx| { |
237 | adt::trans_get_discr(bcx, &repr, llval, None, true) | |
238 | }); | |
239 | (discr, common::val_ty(discr), adt::is_discr_signed(&repr)) | |
9cc50fc6 SL |
240 | } else { |
241 | (operand.immediate(), ll_t_in, operand.ty.is_signed()) | |
242 | }; | |
243 | ||
244 | let newval = match (r_t_in, r_t_out) { | |
245 | (CastTy::Int(_), CastTy::Int(_)) => { | |
246 | let srcsz = ll_t_in.int_width(); | |
247 | let dstsz = ll_t_out.int_width(); | |
248 | if srcsz == dstsz { | |
7453a54e | 249 | bcx.bitcast(llval, ll_t_out) |
9cc50fc6 | 250 | } else if srcsz > dstsz { |
7453a54e | 251 | bcx.trunc(llval, ll_t_out) |
9cc50fc6 | 252 | } else if signed { |
7453a54e | 253 | bcx.sext(llval, ll_t_out) |
9cc50fc6 | 254 | } else { |
7453a54e | 255 | bcx.zext(llval, ll_t_out) |
9cc50fc6 SL |
256 | } |
257 | } | |
258 | (CastTy::Float, CastTy::Float) => { | |
259 | let srcsz = ll_t_in.float_width(); | |
260 | let dstsz = ll_t_out.float_width(); | |
261 | if dstsz > srcsz { | |
7453a54e | 262 | bcx.fpext(llval, ll_t_out) |
9cc50fc6 | 263 | } else if srcsz > dstsz { |
7453a54e | 264 | bcx.fptrunc(llval, ll_t_out) |
9cc50fc6 SL |
265 | } else { |
266 | llval | |
267 | } | |
268 | } | |
269 | (CastTy::Ptr(_), CastTy::Ptr(_)) | | |
270 | (CastTy::FnPtr, CastTy::Ptr(_)) | | |
271 | (CastTy::RPtr(_), CastTy::Ptr(_)) => | |
7453a54e | 272 | bcx.pointercast(llval, ll_t_out), |
9cc50fc6 SL |
273 | (CastTy::Ptr(_), CastTy::Int(_)) | |
274 | (CastTy::FnPtr, CastTy::Int(_)) => | |
7453a54e | 275 | bcx.ptrtoint(llval, ll_t_out), |
9cc50fc6 | 276 | (CastTy::Int(_), CastTy::Ptr(_)) => |
7453a54e | 277 | bcx.inttoptr(llval, ll_t_out), |
9cc50fc6 | 278 | (CastTy::Int(_), CastTy::Float) if signed => |
7453a54e | 279 | bcx.sitofp(llval, ll_t_out), |
9cc50fc6 | 280 | (CastTy::Int(_), CastTy::Float) => |
7453a54e | 281 | bcx.uitofp(llval, ll_t_out), |
9cc50fc6 | 282 | (CastTy::Float, CastTy::Int(IntTy::I)) => |
7453a54e | 283 | bcx.fptosi(llval, ll_t_out), |
9cc50fc6 | 284 | (CastTy::Float, CastTy::Int(_)) => |
7453a54e | 285 | bcx.fptoui(llval, ll_t_out), |
9cc50fc6 SL |
286 | _ => bcx.ccx().sess().bug( |
287 | &format!("unsupported cast: {:?} to {:?}", operand.ty, cast_ty) | |
288 | ) | |
289 | }; | |
290 | OperandValue::Immediate(newval) | |
291 | } | |
292 | mir::CastKind::Misc => { // Casts from a fat-ptr. | |
293 | let ll_cast_ty = type_of::arg_type_of(bcx.ccx(), cast_ty); | |
294 | let ll_from_ty = type_of::arg_type_of(bcx.ccx(), operand.ty); | |
295 | if let OperandValue::FatPtr(data_ptr, meta_ptr) = operand.val { | |
296 | if common::type_is_fat_ptr(bcx.tcx(), cast_ty) { | |
297 | let ll_cft = ll_cast_ty.field_types(); | |
298 | let ll_fft = ll_from_ty.field_types(); | |
7453a54e | 299 | let data_cast = bcx.pointercast(data_ptr, ll_cft[0]); |
9cc50fc6 SL |
300 | assert_eq!(ll_cft[1].kind(), ll_fft[1].kind()); |
301 | OperandValue::FatPtr(data_cast, meta_ptr) | |
302 | } else { // cast to thin-ptr | |
303 | // Cast of fat-ptr to thin-ptr is an extraction of data-ptr and | |
304 | // pointer-cast of that pointer to desired pointer type. | |
7453a54e | 305 | let llval = bcx.pointercast(data_ptr, ll_cast_ty); |
9cc50fc6 SL |
306 | OperandValue::Immediate(llval) |
307 | } | |
308 | } else { | |
309 | panic!("Unexpected non-FatPtr operand") | |
310 | } | |
311 | } | |
92a42be0 | 312 | }; |
7453a54e | 313 | let operand = OperandRef { |
92a42be0 SL |
314 | val: val, |
315 | ty: cast_ty | |
7453a54e SL |
316 | }; |
317 | (bcx, operand) | |
92a42be0 SL |
318 | } |
319 | ||
320 | mir::Rvalue::Ref(_, bk, ref lvalue) => { | |
7453a54e | 321 | let tr_lvalue = self.trans_lvalue(&bcx, lvalue); |
92a42be0 SL |
322 | |
323 | let ty = tr_lvalue.ty.to_ty(bcx.tcx()); | |
324 | let ref_ty = bcx.tcx().mk_ref( | |
325 | bcx.tcx().mk_region(ty::ReStatic), | |
326 | ty::TypeAndMut { ty: ty, mutbl: bk.to_mutbl_lossy() } | |
327 | ); | |
328 | ||
329 | // Note: lvalues are indirect, so storing the `llval` into the | |
330 | // destination effectively creates a reference. | |
7453a54e SL |
331 | let operand = if common::type_is_sized(bcx.tcx(), ty) { |
332 | OperandRef { | |
92a42be0 SL |
333 | val: OperandValue::Immediate(tr_lvalue.llval), |
334 | ty: ref_ty, | |
7453a54e | 335 | } |
92a42be0 | 336 | } else { |
7453a54e | 337 | OperandRef { |
92a42be0 SL |
338 | val: OperandValue::FatPtr(tr_lvalue.llval, |
339 | tr_lvalue.llextra), | |
340 | ty: ref_ty, | |
7453a54e SL |
341 | } |
342 | }; | |
343 | (bcx, operand) | |
92a42be0 SL |
344 | } |
345 | ||
346 | mir::Rvalue::Len(ref lvalue) => { | |
7453a54e SL |
347 | let tr_lvalue = self.trans_lvalue(&bcx, lvalue); |
348 | let operand = OperandRef { | |
349 | val: OperandValue::Immediate(self.lvalue_len(&bcx, tr_lvalue)), | |
92a42be0 | 350 | ty: bcx.tcx().types.usize, |
7453a54e SL |
351 | }; |
352 | (bcx, operand) | |
92a42be0 SL |
353 | } |
354 | ||
355 | mir::Rvalue::BinaryOp(op, ref lhs, ref rhs) => { | |
7453a54e SL |
356 | let lhs = self.trans_operand(&bcx, lhs); |
357 | let rhs = self.trans_operand(&bcx, rhs); | |
92a42be0 SL |
358 | let llresult = if common::type_is_fat_ptr(bcx.tcx(), lhs.ty) { |
359 | match (lhs.val, rhs.val) { | |
360 | (OperandValue::FatPtr(lhs_addr, lhs_extra), | |
361 | OperandValue::FatPtr(rhs_addr, rhs_extra)) => { | |
7453a54e SL |
362 | bcx.with_block(|bcx| { |
363 | base::compare_fat_ptrs(bcx, | |
364 | lhs_addr, lhs_extra, | |
365 | rhs_addr, rhs_extra, | |
366 | lhs.ty, op.to_hir_binop(), | |
367 | DebugLoc::None) | |
368 | }) | |
92a42be0 SL |
369 | } |
370 | _ => unreachable!() | |
371 | } | |
372 | ||
373 | } else { | |
7453a54e | 374 | self.trans_scalar_binop(&bcx, op, |
92a42be0 | 375 | lhs.immediate(), rhs.immediate(), |
7453a54e | 376 | lhs.ty) |
92a42be0 | 377 | }; |
7453a54e | 378 | let operand = OperandRef { |
92a42be0 SL |
379 | val: OperandValue::Immediate(llresult), |
380 | ty: self.mir.binop_ty(bcx.tcx(), op, lhs.ty, rhs.ty), | |
7453a54e SL |
381 | }; |
382 | (bcx, operand) | |
92a42be0 SL |
383 | } |
384 | ||
385 | mir::Rvalue::UnaryOp(op, ref operand) => { | |
7453a54e | 386 | let operand = self.trans_operand(&bcx, operand); |
92a42be0 SL |
387 | let lloperand = operand.immediate(); |
388 | let is_float = operand.ty.is_fp(); | |
92a42be0 | 389 | let llval = match op { |
7453a54e | 390 | mir::UnOp::Not => bcx.not(lloperand), |
92a42be0 | 391 | mir::UnOp::Neg => if is_float { |
7453a54e | 392 | bcx.fneg(lloperand) |
92a42be0 | 393 | } else { |
7453a54e | 394 | bcx.neg(lloperand) |
92a42be0 SL |
395 | } |
396 | }; | |
397 | (bcx, OperandRef { | |
398 | val: OperandValue::Immediate(llval), | |
399 | ty: operand.ty, | |
400 | }) | |
401 | } | |
402 | ||
403 | mir::Rvalue::Box(content_ty) => { | |
404 | let content_ty: Ty<'tcx> = bcx.monomorphize(&content_ty); | |
405 | let llty = type_of::type_of(bcx.ccx(), content_ty); | |
406 | let llsize = machine::llsize_of(bcx.ccx(), llty); | |
407 | let align = type_of::align_of(bcx.ccx(), content_ty); | |
408 | let llalign = common::C_uint(bcx.ccx(), align); | |
409 | let llty_ptr = llty.ptr_to(); | |
410 | let box_ty = bcx.tcx().mk_box(content_ty); | |
7453a54e SL |
411 | let mut llval = None; |
412 | let bcx = bcx.map_block(|bcx| { | |
413 | let Result { bcx, val } = base::malloc_raw_dyn(bcx, | |
414 | llty_ptr, | |
415 | box_ty, | |
416 | llsize, | |
417 | llalign, | |
418 | DebugLoc::None); | |
419 | llval = Some(val); | |
420 | bcx | |
421 | }); | |
422 | let operand = OperandRef { | |
423 | val: OperandValue::Immediate(llval.unwrap()), | |
92a42be0 | 424 | ty: box_ty, |
7453a54e SL |
425 | }; |
426 | (bcx, operand) | |
92a42be0 SL |
427 | } |
428 | ||
429 | mir::Rvalue::Repeat(..) | | |
430 | mir::Rvalue::Aggregate(..) | | |
431 | mir::Rvalue::Slice { .. } | | |
432 | mir::Rvalue::InlineAsm(..) => { | |
433 | bcx.tcx().sess.bug(&format!("cannot generate operand from rvalue {:?}", rvalue)); | |
434 | } | |
435 | } | |
436 | } | |
437 | ||
438 | pub fn trans_scalar_binop(&mut self, | |
7453a54e | 439 | bcx: &BlockAndBuilder<'bcx, 'tcx>, |
92a42be0 SL |
440 | op: mir::BinOp, |
441 | lhs: ValueRef, | |
442 | rhs: ValueRef, | |
7453a54e | 443 | input_ty: Ty<'tcx>) -> ValueRef { |
92a42be0 SL |
444 | let is_float = input_ty.is_fp(); |
445 | let is_signed = input_ty.is_signed(); | |
446 | match op { | |
447 | mir::BinOp::Add => if is_float { | |
7453a54e | 448 | bcx.fadd(lhs, rhs) |
92a42be0 | 449 | } else { |
7453a54e | 450 | bcx.add(lhs, rhs) |
92a42be0 SL |
451 | }, |
452 | mir::BinOp::Sub => if is_float { | |
7453a54e | 453 | bcx.fsub(lhs, rhs) |
92a42be0 | 454 | } else { |
7453a54e | 455 | bcx.sub(lhs, rhs) |
92a42be0 SL |
456 | }, |
457 | mir::BinOp::Mul => if is_float { | |
7453a54e | 458 | bcx.fmul(lhs, rhs) |
92a42be0 | 459 | } else { |
7453a54e | 460 | bcx.mul(lhs, rhs) |
92a42be0 SL |
461 | }, |
462 | mir::BinOp::Div => if is_float { | |
7453a54e | 463 | bcx.fdiv(lhs, rhs) |
92a42be0 | 464 | } else if is_signed { |
7453a54e | 465 | bcx.sdiv(lhs, rhs) |
92a42be0 | 466 | } else { |
7453a54e | 467 | bcx.udiv(lhs, rhs) |
92a42be0 SL |
468 | }, |
469 | mir::BinOp::Rem => if is_float { | |
470 | // LLVM currently always lowers the `frem` instructions appropriate | |
471 | // library calls typically found in libm. Notably f64 gets wired up | |
472 | // to `fmod` and f32 gets wired up to `fmodf`. Inconveniently for | |
473 | // us, 32-bit MSVC does not actually have a `fmodf` symbol, it's | |
474 | // instead just an inline function in a header that goes up to a | |
475 | // f64, uses `fmod`, and then comes back down to a f32. | |
476 | // | |
477 | // Although LLVM knows that `fmodf` doesn't exist on MSVC, it will | |
478 | // still unconditionally lower frem instructions over 32-bit floats | |
479 | // to a call to `fmodf`. To work around this we special case MSVC | |
480 | // 32-bit float rem instructions and instead do the call out to | |
481 | // `fmod` ourselves. | |
482 | // | |
483 | // Note that this is currently duplicated with src/libcore/ops.rs | |
484 | // which does the same thing, and it would be nice to perhaps unify | |
485 | // these two implementations one day! Also note that we call `fmod` | |
486 | // for both 32 and 64-bit floats because if we emit any FRem | |
487 | // instruction at all then LLVM is capable of optimizing it into a | |
488 | // 32-bit FRem (which we're trying to avoid). | |
489 | let tcx = bcx.tcx(); | |
490 | let use_fmod = tcx.sess.target.target.options.is_like_msvc && | |
491 | tcx.sess.target.target.arch == "x86"; | |
492 | if use_fmod { | |
493 | let f64t = Type::f64(bcx.ccx()); | |
494 | let fty = Type::func(&[f64t, f64t], &f64t); | |
495 | let llfn = declare::declare_cfn(bcx.ccx(), "fmod", fty, | |
496 | tcx.types.f64); | |
497 | if input_ty == tcx.types.f32 { | |
7453a54e SL |
498 | let lllhs = bcx.fpext(lhs, f64t); |
499 | let llrhs = bcx.fpext(rhs, f64t); | |
500 | let llres = bcx.call(llfn, &[lllhs, llrhs], None, None); | |
501 | bcx.fptrunc(llres, Type::f32(bcx.ccx())) | |
92a42be0 | 502 | } else { |
7453a54e | 503 | bcx.call(llfn, &[lhs, rhs], None, None) |
92a42be0 SL |
504 | } |
505 | } else { | |
7453a54e | 506 | bcx.frem(lhs, rhs) |
92a42be0 SL |
507 | } |
508 | } else if is_signed { | |
7453a54e | 509 | bcx.srem(lhs, rhs) |
92a42be0 | 510 | } else { |
7453a54e | 511 | bcx.urem(lhs, rhs) |
92a42be0 | 512 | }, |
7453a54e SL |
513 | mir::BinOp::BitOr => bcx.or(lhs, rhs), |
514 | mir::BinOp::BitAnd => bcx.and(lhs, rhs), | |
515 | mir::BinOp::BitXor => bcx.xor(lhs, rhs), | |
516 | mir::BinOp::Shl => { | |
517 | bcx.with_block(|bcx| { | |
518 | common::build_unchecked_lshift(bcx, | |
519 | lhs, | |
520 | rhs, | |
521 | DebugLoc::None) | |
522 | }) | |
523 | } | |
524 | mir::BinOp::Shr => { | |
525 | bcx.with_block(|bcx| { | |
526 | common::build_unchecked_rshift(bcx, | |
527 | input_ty, | |
528 | lhs, | |
529 | rhs, | |
530 | DebugLoc::None) | |
531 | }) | |
532 | } | |
92a42be0 SL |
533 | mir::BinOp::Eq | mir::BinOp::Lt | mir::BinOp::Gt | |
534 | mir::BinOp::Ne | mir::BinOp::Le | mir::BinOp::Ge => { | |
7453a54e SL |
535 | bcx.with_block(|bcx| { |
536 | base::compare_scalar_types(bcx, lhs, rhs, input_ty, | |
537 | op.to_hir_binop(), DebugLoc::None) | |
538 | }) | |
92a42be0 SL |
539 | } |
540 | } | |
541 | } | |
542 | } | |
543 | ||
544 | pub fn rvalue_creates_operand<'tcx>(rvalue: &mir::Rvalue<'tcx>) -> bool { | |
545 | match *rvalue { | |
546 | mir::Rvalue::Use(..) | // (*) | |
547 | mir::Rvalue::Ref(..) | | |
548 | mir::Rvalue::Len(..) | | |
549 | mir::Rvalue::Cast(..) | // (*) | |
550 | mir::Rvalue::BinaryOp(..) | | |
551 | mir::Rvalue::UnaryOp(..) | | |
552 | mir::Rvalue::Box(..) => | |
553 | true, | |
554 | mir::Rvalue::Repeat(..) | | |
555 | mir::Rvalue::Aggregate(..) | | |
556 | mir::Rvalue::Slice { .. } | | |
557 | mir::Rvalue::InlineAsm(..) => | |
558 | false, | |
559 | } | |
560 | ||
561 | // (*) this is only true if the type is suitable | |
562 | } |