]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/trans/mir/rvalue.rs
address nits from dotdash
[rust.git] / src / librustc_trans / trans / mir / rvalue.rs
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 back::abi;
12 use llvm::ValueRef;
13 use rustc::middle::ty::Ty;
14 use rustc_front::hir;
15 use rustc_mir::repr as mir;
16
17 use trans::asm;
18 use trans::base;
19 use trans::build;
20 use trans::common::{self, Block, Result};
21 use trans::debuginfo::DebugLoc;
22 use trans::declare;
23 use trans::expr;
24 use trans::machine;
25 use trans::type_::Type;
26 use trans::type_of;
27 use trans::tvec;
28
29 use super::MirContext;
30 use super::operand::OperandRef;
31
32 impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
33     pub fn trans_rvalue(&mut self,
34                         bcx: Block<'bcx, 'tcx>,
35                         lldest: ValueRef,
36                         rvalue: &mir::Rvalue<'tcx>)
37                         -> Block<'bcx, 'tcx>
38     {
39         debug!("trans_rvalue(lldest={}, rvalue={:?})",
40                bcx.val_to_string(lldest),
41                rvalue);
42
43         match *rvalue {
44             mir::Rvalue::Use(ref operand) => {
45                 self.trans_operand_into(bcx, lldest, operand);
46                 bcx
47             }
48
49             mir::Rvalue::Cast(..) => {
50                 unimplemented!()
51             }
52
53             mir::Rvalue::Repeat(..) => {
54                 unimplemented!()
55             }
56
57             mir::Rvalue::Aggregate(_, ref operands) => {
58                 for (i, operand) in operands.iter().enumerate() {
59                     // Note: perhaps this should be StructGep, but
60                     // note that in some cases the values here will
61                     // not be structs but arrays.
62                     let lldest_i = build::GEPi(bcx, lldest, &[0, i]);
63                     self.trans_operand_into(bcx, lldest_i, operand);
64                 }
65                 bcx
66             }
67
68             mir::Rvalue::Slice { ref input, from_start, from_end } => {
69                 let ccx = bcx.ccx();
70                 let input = self.trans_lvalue(bcx, input);
71                 let (llbase, lllen) = tvec::get_base_and_len(bcx,
72                                                              input.llval,
73                                                              input.ty.to_ty(bcx.tcx()));
74                 let llbase1 = build::GEPi(bcx, llbase, &[from_start]);
75                 let adj = common::C_uint(ccx, from_start + from_end);
76                 let lllen1 = build::Sub(bcx, lllen, adj, DebugLoc::None);
77                 let lladdrdest = expr::get_dataptr(bcx, lldest);
78                 build::Store(bcx, llbase1, lladdrdest);
79                 let llmetadest = expr::get_meta(bcx, lldest);
80                 build::Store(bcx, lllen1, llmetadest);
81                 bcx
82             }
83
84             mir::Rvalue::InlineAsm(inline_asm) => {
85                 asm::trans_inline_asm(bcx, inline_asm)
86             }
87
88             _ => {
89                 assert!(rvalue_creates_operand(rvalue));
90                 let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue);
91                 build::Store(bcx, temp.llval, lldest);
92                 bcx
93             }
94         }
95     }
96
97     pub fn trans_rvalue_operand(&mut self,
98                                 bcx: Block<'bcx, 'tcx>,
99                                 rvalue: &mir::Rvalue<'tcx>)
100                                 -> (Block<'bcx, 'tcx>, OperandRef<'tcx>)
101     {
102         assert!(rvalue_creates_operand(rvalue), "cannot trans {:?} to operand", rvalue);
103
104         match *rvalue {
105             mir::Rvalue::Use(ref operand) => {
106                 let operand = self.trans_operand(bcx, operand);
107                 (bcx, operand)
108             }
109
110             mir::Rvalue::Cast(..) => {
111                 unimplemented!()
112             }
113
114             mir::Rvalue::Ref(_, _, ref lvalue) => {
115                 let tr_lvalue = self.trans_lvalue(bcx, lvalue);
116
117                 // Note: lvalues are indirect, so storing the `llval` into the
118                 // destination effectively creates a reference.
119                 (bcx, OperandRef {
120                     llval: tr_lvalue.llval,
121                     ty: tr_lvalue.ty.to_ty(bcx.tcx()),
122                 })
123             }
124
125             mir::Rvalue::Len(ref lvalue) => {
126                 let tr_lvalue = self.trans_lvalue(bcx, lvalue);
127                 let (_, lllen) = tvec::get_base_and_len(bcx,
128                                                         tr_lvalue.llval,
129                                                         tr_lvalue.ty.to_ty(bcx.tcx()));
130                 (bcx, OperandRef {
131                     llval: lllen,
132                     ty: bcx.tcx().types.usize,
133                 })
134             }
135
136             mir::Rvalue::BinaryOp(op, ref lhs, ref rhs) => {
137                 let lhs = self.trans_operand(bcx, lhs);
138                 let rhs = self.trans_operand(bcx, rhs);
139                 let is_float = lhs.ty.is_fp();
140                 let is_signed = lhs.ty.is_signed();
141                 let binop_debug_loc = DebugLoc::None;
142                 let llval = match op {
143                     mir::BinOp::Add => if is_float {
144                         build::FAdd(bcx, lhs.llval, rhs.llval, binop_debug_loc)
145                     } else {
146                         build::Add(bcx, lhs.llval, rhs.llval, binop_debug_loc)
147                     },
148                     mir::BinOp::Sub => if is_float {
149                         build::FSub(bcx, lhs.llval, rhs.llval, binop_debug_loc)
150                     } else {
151                         build::Sub(bcx, lhs.llval, rhs.llval, binop_debug_loc)
152                     },
153                     mir::BinOp::Mul => if is_float {
154                         build::FMul(bcx, lhs.llval, rhs.llval, binop_debug_loc)
155                     } else {
156                         build::Mul(bcx, lhs.llval, rhs.llval, binop_debug_loc)
157                     },
158                     mir::BinOp::Div => if is_float {
159                         build::FDiv(bcx, lhs.llval, rhs.llval, binop_debug_loc)
160                     } else if is_signed {
161                         build::SDiv(bcx, lhs.llval, rhs.llval, binop_debug_loc)
162                     } else {
163                         build::UDiv(bcx, lhs.llval, rhs.llval, binop_debug_loc)
164                     },
165                     mir::BinOp::Rem => if is_float {
166                         // LLVM currently always lowers the `frem` instructions appropriate
167                         // library calls typically found in libm. Notably f64 gets wired up
168                         // to `fmod` and f32 gets wired up to `fmodf`. Inconveniently for
169                         // us, 32-bit MSVC does not actually have a `fmodf` symbol, it's
170                         // instead just an inline function in a header that goes up to a
171                         // f64, uses `fmod`, and then comes back down to a f32.
172                         //
173                         // Although LLVM knows that `fmodf` doesn't exist on MSVC, it will
174                         // still unconditionally lower frem instructions over 32-bit floats
175                         // to a call to `fmodf`. To work around this we special case MSVC
176                         // 32-bit float rem instructions and instead do the call out to
177                         // `fmod` ourselves.
178                         //
179                         // Note that this is currently duplicated with src/libcore/ops.rs
180                         // which does the same thing, and it would be nice to perhaps unify
181                         // these two implementations one day! Also note that we call `fmod`
182                         // for both 32 and 64-bit floats because if we emit any FRem
183                         // instruction at all then LLVM is capable of optimizing it into a
184                         // 32-bit FRem (which we're trying to avoid).
185                         let tcx = bcx.tcx();
186                         let use_fmod = tcx.sess.target.target.options.is_like_msvc &&
187                             tcx.sess.target.target.arch == "x86";
188                         if use_fmod {
189                             let f64t = Type::f64(bcx.ccx());
190                             let fty = Type::func(&[f64t, f64t], &f64t);
191                             let llfn = declare::declare_cfn(bcx.ccx(), "fmod", fty,
192                                                             tcx.types.f64);
193                             if lhs.ty == tcx.types.f32 {
194                                 let lllhs = build::FPExt(bcx, lhs.llval, f64t);
195                                 let llrhs = build::FPExt(bcx, rhs.llval, f64t);
196                                 let llres = build::Call(bcx, llfn, &[lllhs, llrhs],
197                                                         None, binop_debug_loc);
198                                 build::FPTrunc(bcx, llres, Type::f32(bcx.ccx()))
199                             } else {
200                                 build::Call(bcx, llfn, &[lhs.llval, rhs.llval],
201                                             None, binop_debug_loc)
202                             }
203                         } else {
204                             build::FRem(bcx, lhs.llval, rhs.llval, binop_debug_loc)
205                         }
206                     } else if is_signed {
207                         build::SRem(bcx, lhs.llval, rhs.llval, binop_debug_loc)
208                     } else {
209                         build::URem(bcx, lhs.llval, rhs.llval, binop_debug_loc)
210                     },
211                     mir::BinOp::BitOr => build::Or(bcx, lhs.llval, rhs.llval, binop_debug_loc),
212                     mir::BinOp::BitAnd => build::And(bcx, lhs.llval, rhs.llval, binop_debug_loc),
213                     mir::BinOp::BitXor => build::Xor(bcx, lhs.llval, rhs.llval, binop_debug_loc),
214                     mir::BinOp::Shl => common::build_unchecked_lshift(bcx,
215                                                                       lhs.llval,
216                                                                       rhs.llval,
217                                                                       binop_debug_loc),
218                     mir::BinOp::Shr => common::build_unchecked_rshift(bcx,
219                                                                       lhs.ty,
220                                                                       lhs.llval,
221                                                                       rhs.llval,
222                                                                       binop_debug_loc),
223                     mir::BinOp::Eq => base::compare_scalar_types(bcx, lhs.llval, rhs.llval, lhs.ty,
224                                                                  hir::BiEq, binop_debug_loc),
225                     mir::BinOp::Lt => base::compare_scalar_types(bcx, lhs.llval, rhs.llval, lhs.ty,
226                                                                  hir::BiLt, binop_debug_loc),
227                     mir::BinOp::Le => base::compare_scalar_types(bcx, lhs.llval, rhs.llval, lhs.ty,
228                                                                  hir::BiLe, binop_debug_loc),
229                     mir::BinOp::Ne => base::compare_scalar_types(bcx, lhs.llval, rhs.llval, lhs.ty,
230                                                                  hir::BiNe, binop_debug_loc),
231                     mir::BinOp::Ge => base::compare_scalar_types(bcx, lhs.llval, rhs.llval, lhs.ty,
232                                                                  hir::BiGe, binop_debug_loc),
233                     mir::BinOp::Gt => base::compare_scalar_types(bcx, lhs.llval, rhs.llval, lhs.ty,
234                                                                  hir::BiGt, binop_debug_loc),
235                 };
236                 (bcx, OperandRef {
237                     llval: llval,
238                     ty: lhs.ty,
239                 })
240             }
241
242             mir::Rvalue::UnaryOp(op, ref operand) => {
243                 let operand = self.trans_operand(bcx, operand);
244                 let is_float = operand.ty.is_fp();
245                 let debug_loc = DebugLoc::None;
246                 let llval = match op {
247                     mir::UnOp::Not => build::Not(bcx, operand.llval, debug_loc),
248                     mir::UnOp::Neg => if is_float {
249                         build::FNeg(bcx, operand.llval, debug_loc)
250                     } else {
251                         build::Neg(bcx, operand.llval, debug_loc)
252                     }
253                 };
254                 (bcx, OperandRef {
255                     llval: llval,
256                     ty: operand.ty,
257                 })
258             }
259
260             mir::Rvalue::Box(content_ty) => {
261                 let content_ty: Ty<'tcx> = bcx.monomorphize(&content_ty);
262                 let llty = type_of::type_of(bcx.ccx(), content_ty);
263                 let llsize = machine::llsize_of(bcx.ccx(), llty);
264                 let align = type_of::align_of(bcx.ccx(), content_ty);
265                 let llalign = common::C_uint(bcx.ccx(), align);
266                 let llty_ptr = llty.ptr_to();
267                 let box_ty = bcx.tcx().mk_box(content_ty);
268                 let Result { bcx, val: llval } = base::malloc_raw_dyn(bcx,
269                                                                       llty_ptr,
270                                                                       box_ty,
271                                                                       llsize,
272                                                                       llalign,
273                                                                       DebugLoc::None);
274                 (bcx, OperandRef {
275                     llval: llval,
276                     ty: box_ty,
277                 })
278             }
279
280             mir::Rvalue::Repeat(..) |
281             mir::Rvalue::Aggregate(..) |
282             mir::Rvalue::Slice { .. } |
283             mir::Rvalue::InlineAsm(..) => {
284                 bcx.tcx().sess.bug(&format!("cannot generate operand from rvalue {:?}", rvalue));
285             }
286         }
287     }
288 }
289
290 pub fn rvalue_creates_operand<'tcx>(rvalue: &mir::Rvalue<'tcx>) -> bool {
291     match *rvalue {
292         mir::Rvalue::Use(..) | // (*)
293         mir::Rvalue::Ref(..) |
294         mir::Rvalue::Len(..) |
295         mir::Rvalue::Cast(..) | // (*)
296         mir::Rvalue::BinaryOp(..) |
297         mir::Rvalue::UnaryOp(..) |
298         mir::Rvalue::Box(..) =>
299             true,
300         mir::Rvalue::Repeat(..) |
301         mir::Rvalue::Aggregate(..) |
302         mir::Rvalue::Slice { .. } |
303         mir::Rvalue::InlineAsm(..) =>
304             false,
305     }
306
307     // (*) this is only true if the type is suitable
308 }