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