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.
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.
13 use rustc::middle::ty::Ty;
15 use rustc_mir::repr as mir;
20 use trans::common::{self, Block, Result};
21 use trans::debuginfo::DebugLoc;
25 use trans::type_::Type;
29 use super::MirContext;
30 use super::operand::OperandRef;
32 impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
33 pub fn trans_rvalue(&mut self,
34 bcx: Block<'bcx, 'tcx>,
36 rvalue: &mir::Rvalue<'tcx>)
39 debug!("trans_rvalue(lldest={}, rvalue={:?})",
40 bcx.val_to_string(lldest),
44 mir::Rvalue::Use(ref operand) => {
45 self.trans_operand_into(bcx, lldest, operand);
49 mir::Rvalue::Cast(..) => {
53 mir::Rvalue::Repeat(..) => {
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);
68 mir::Rvalue::Slice { ref input, from_start, from_end } => {
70 let input = self.trans_lvalue(bcx, input);
71 let (llbase, lllen) = tvec::get_base_and_len(bcx,
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);
84 mir::Rvalue::InlineAsm(inline_asm) => {
85 asm::trans_inline_asm(bcx, inline_asm)
89 assert!(rvalue_creates_operand(rvalue));
90 let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue);
91 build::Store(bcx, temp.llval, lldest);
97 pub fn trans_rvalue_operand(&mut self,
98 bcx: Block<'bcx, 'tcx>,
99 rvalue: &mir::Rvalue<'tcx>)
100 -> (Block<'bcx, 'tcx>, OperandRef<'tcx>)
102 assert!(rvalue_creates_operand(rvalue), "cannot trans {:?} to operand", rvalue);
105 mir::Rvalue::Use(ref operand) => {
106 let operand = self.trans_operand(bcx, operand);
110 mir::Rvalue::Cast(..) => {
114 mir::Rvalue::Ref(_, _, ref lvalue) => {
115 let tr_lvalue = self.trans_lvalue(bcx, lvalue);
117 // Note: lvalues are indirect, so storing the `llval` into the
118 // destination effectively creates a reference.
120 llval: tr_lvalue.llval,
121 ty: tr_lvalue.ty.to_ty(bcx.tcx()),
125 mir::Rvalue::Len(ref lvalue) => {
126 let tr_lvalue = self.trans_lvalue(bcx, lvalue);
127 let (_, lllen) = tvec::get_base_and_len(bcx,
129 tr_lvalue.ty.to_ty(bcx.tcx()));
132 ty: bcx.tcx().types.usize,
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)
146 build::Add(bcx, lhs.llval, rhs.llval, binop_debug_loc)
148 mir::BinOp::Sub => if is_float {
149 build::FSub(bcx, lhs.llval, rhs.llval, binop_debug_loc)
151 build::Sub(bcx, lhs.llval, rhs.llval, binop_debug_loc)
153 mir::BinOp::Mul => if is_float {
154 build::FMul(bcx, lhs.llval, rhs.llval, binop_debug_loc)
156 build::Mul(bcx, lhs.llval, rhs.llval, binop_debug_loc)
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)
163 build::UDiv(bcx, lhs.llval, rhs.llval, binop_debug_loc)
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.
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
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).
186 let use_fmod = tcx.sess.target.target.options.is_like_msvc &&
187 tcx.sess.target.target.arch == "x86";
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,
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()))
200 build::Call(bcx, llfn, &[lhs.llval, rhs.llval],
201 None, binop_debug_loc)
204 build::FRem(bcx, lhs.llval, rhs.llval, binop_debug_loc)
206 } else if is_signed {
207 build::SRem(bcx, lhs.llval, rhs.llval, binop_debug_loc)
209 build::URem(bcx, lhs.llval, rhs.llval, binop_debug_loc)
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,
218 mir::BinOp::Shr => common::build_unchecked_rshift(bcx,
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),
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)
251 build::Neg(bcx, operand.llval, debug_loc)
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,
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));
290 pub fn rvalue_creates_operand<'tcx>(rvalue: &mir::Rvalue<'tcx>) -> bool {
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(..) =>
300 mir::Rvalue::Repeat(..) |
301 mir::Rvalue::Aggregate(..) |
302 mir::Rvalue::Slice { .. } |
303 mir::Rvalue::InlineAsm(..) =>
307 // (*) this is only true if the type is suitable