2015-10-21 16:42:25 -05:00
|
|
|
|
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
|
//
|
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
|
// except according to those terms.
|
|
|
|
|
|
|
|
|
|
use llvm::ValueRef;
|
2015-11-08 18:16:19 -06:00
|
|
|
|
use rustc::middle::ty::{self, Ty};
|
2015-11-05 05:33:06 -06:00
|
|
|
|
use middle::ty::cast::{CastTy, IntTy};
|
2015-11-19 09:37:34 -06:00
|
|
|
|
use rustc::mir::repr as mir;
|
2015-10-21 16:42:25 -05:00
|
|
|
|
|
|
|
|
|
use trans::asm;
|
|
|
|
|
use trans::base;
|
2016-02-01 04:04:46 -06:00
|
|
|
|
use trans::common::{self, BlockAndBuilder, Result};
|
2015-10-21 16:42:25 -05:00
|
|
|
|
use trans::debuginfo::DebugLoc;
|
|
|
|
|
use trans::declare;
|
2015-11-03 14:50:04 -06:00
|
|
|
|
use trans::expr;
|
2015-12-24 17:02:34 -06:00
|
|
|
|
use trans::adt;
|
2015-10-21 16:42:25 -05:00
|
|
|
|
use trans::machine;
|
|
|
|
|
use trans::type_::Type;
|
|
|
|
|
use trans::type_of;
|
|
|
|
|
use trans::tvec;
|
2016-01-16 09:03:09 -06:00
|
|
|
|
use trans::Disr;
|
2015-10-21 16:42:25 -05:00
|
|
|
|
|
|
|
|
|
use super::MirContext;
|
2015-11-10 14:05:11 -06:00
|
|
|
|
use super::operand::{OperandRef, OperandValue};
|
2015-12-24 17:02:34 -06:00
|
|
|
|
use super::lvalue::LvalueRef;
|
2015-10-21 16:42:25 -05:00
|
|
|
|
|
|
|
|
|
impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|
|
|
|
pub fn trans_rvalue(&mut self,
|
2016-02-01 04:04:46 -06:00
|
|
|
|
bcx: BlockAndBuilder<'bcx, 'tcx>,
|
2015-12-24 17:02:34 -06:00
|
|
|
|
dest: LvalueRef<'tcx>,
|
2015-10-21 16:42:25 -05:00
|
|
|
|
rvalue: &mir::Rvalue<'tcx>)
|
2016-02-01 04:04:46 -06:00
|
|
|
|
-> BlockAndBuilder<'bcx, 'tcx>
|
2015-10-21 16:42:25 -05:00
|
|
|
|
{
|
2015-12-24 17:02:34 -06:00
|
|
|
|
debug!("trans_rvalue(dest.llval={}, rvalue={:?})",
|
|
|
|
|
bcx.val_to_string(dest.llval),
|
2015-10-21 16:42:25 -05:00
|
|
|
|
rvalue);
|
|
|
|
|
|
|
|
|
|
match *rvalue {
|
2016-02-04 11:40:28 -06:00
|
|
|
|
mir::Rvalue::Use(ref operand) => {
|
2016-02-26 06:12:28 -06:00
|
|
|
|
let tr_operand = self.trans_operand(&bcx, operand);
|
2016-02-04 11:40:28 -06:00
|
|
|
|
// FIXME: consider not copying constants through stack. (fixable by translating
|
|
|
|
|
// constants into OperandValue::Ref, why don’t we do that yet if we don’t?)
|
|
|
|
|
self.store_operand(&bcx, dest.llval, tr_operand);
|
|
|
|
|
self.set_operand_dropped(&bcx, operand);
|
|
|
|
|
bcx
|
|
|
|
|
}
|
2015-10-21 16:42:25 -05:00
|
|
|
|
|
2015-11-08 18:16:19 -06:00
|
|
|
|
mir::Rvalue::Cast(mir::CastKind::Unsize, ref operand, cast_ty) => {
|
2015-11-11 14:02:51 -06:00
|
|
|
|
if common::type_is_fat_ptr(bcx.tcx(), cast_ty) {
|
2015-11-12 16:12:50 -06:00
|
|
|
|
// into-coerce of a thin pointer to a fat pointer - just
|
|
|
|
|
// use the operand path.
|
2015-11-11 14:02:51 -06:00
|
|
|
|
let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue);
|
2016-02-01 04:04:46 -06:00
|
|
|
|
self.store_operand(&bcx, dest.llval, temp);
|
2015-11-08 18:16:19 -06:00
|
|
|
|
return bcx;
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-11 14:02:51 -06:00
|
|
|
|
// Unsize of a nontrivial struct. I would prefer for
|
|
|
|
|
// this to be eliminated by MIR translation, but
|
|
|
|
|
// `CoerceUnsized` can be passed by a where-clause,
|
|
|
|
|
// so the (generic) MIR may not be able to expand it.
|
2016-02-01 04:04:46 -06:00
|
|
|
|
let operand = self.trans_operand(&bcx, operand);
|
|
|
|
|
bcx.with_block(|bcx| {
|
|
|
|
|
match operand.val {
|
|
|
|
|
OperandValue::FatPtr(..) => unreachable!(),
|
|
|
|
|
OperandValue::Immediate(llval) => {
|
|
|
|
|
// unsize from an immediate structure. We don't
|
|
|
|
|
// really need a temporary alloca here, but
|
|
|
|
|
// avoiding it would require us to have
|
|
|
|
|
// `coerce_unsized_into` use extractvalue to
|
|
|
|
|
// index into the struct, and this case isn't
|
|
|
|
|
// important enough for it.
|
|
|
|
|
debug!("trans_rvalue: creating ugly alloca");
|
|
|
|
|
let lltemp = base::alloc_ty(bcx, operand.ty, "__unsize_temp");
|
|
|
|
|
base::store_ty(bcx, llval, lltemp, operand.ty);
|
|
|
|
|
base::coerce_unsized_into(bcx,
|
|
|
|
|
lltemp, operand.ty,
|
|
|
|
|
dest.llval, cast_ty);
|
|
|
|
|
}
|
|
|
|
|
OperandValue::Ref(llref) => {
|
|
|
|
|
base::coerce_unsized_into(bcx,
|
|
|
|
|
llref, operand.ty,
|
|
|
|
|
dest.llval, cast_ty);
|
|
|
|
|
}
|
2015-11-11 14:02:51 -06:00
|
|
|
|
}
|
2016-02-01 04:04:46 -06:00
|
|
|
|
});
|
2015-11-11 14:02:51 -06:00
|
|
|
|
bcx
|
2015-10-21 16:42:25 -05:00
|
|
|
|
}
|
|
|
|
|
|
2015-11-05 08:50:36 -06:00
|
|
|
|
mir::Rvalue::Repeat(ref elem, ref count) => {
|
2016-02-04 11:40:28 -06:00
|
|
|
|
let tr_elem = self.trans_operand(&bcx, elem);
|
2016-02-01 04:04:46 -06:00
|
|
|
|
let size = self.trans_constval(&bcx, &count.value, count.ty).immediate();
|
2016-02-04 11:40:28 -06:00
|
|
|
|
let bcx = bcx.map_block(|block| {
|
2016-02-01 04:04:46 -06:00
|
|
|
|
let base = expr::get_dataptr(block, dest.llval);
|
2016-02-04 11:40:28 -06:00
|
|
|
|
tvec::iter_vec_raw(block, base, tr_elem.ty, size, |block, llslot, _| {
|
|
|
|
|
self.store_operand_direct(block, llslot, tr_elem);
|
2016-02-01 04:04:46 -06:00
|
|
|
|
block
|
|
|
|
|
})
|
2016-02-04 11:40:28 -06:00
|
|
|
|
});
|
|
|
|
|
self.set_operand_dropped(&bcx, elem);
|
|
|
|
|
bcx
|
2015-10-21 16:42:25 -05:00
|
|
|
|
}
|
|
|
|
|
|
2015-12-24 17:02:34 -06:00
|
|
|
|
mir::Rvalue::Aggregate(ref kind, ref operands) => {
|
|
|
|
|
match *kind {
|
2016-01-13 18:55:46 -06:00
|
|
|
|
mir::AggregateKind::Adt(adt_def, index, _) => {
|
2015-12-24 17:02:34 -06:00
|
|
|
|
let repr = adt::represent_type(bcx.ccx(), dest.ty.to_ty(bcx.tcx()));
|
2016-01-16 09:03:09 -06:00
|
|
|
|
let disr = Disr::from(adt_def.variants[index].disr_val);
|
2016-02-01 04:04:46 -06:00
|
|
|
|
bcx.with_block(|bcx| {
|
2016-02-09 14:24:11 -06:00
|
|
|
|
adt::trans_set_discr(bcx, &repr, dest.llval, Disr::from(disr));
|
2016-02-01 04:04:46 -06:00
|
|
|
|
});
|
2016-01-13 18:55:46 -06:00
|
|
|
|
for (i, operand) in operands.iter().enumerate() {
|
2016-02-01 04:04:46 -06:00
|
|
|
|
let op = self.trans_operand(&bcx, operand);
|
2016-01-13 18:55:46 -06:00
|
|
|
|
// Do not generate stores and GEPis for zero-sized fields.
|
|
|
|
|
if !common::type_is_zero_size(bcx.ccx(), op.ty) {
|
|
|
|
|
let val = adt::MaybeSizedValue::sized(dest.llval);
|
2016-02-01 04:04:46 -06:00
|
|
|
|
let lldest_i = bcx.with_block(|bcx| {
|
2016-02-09 14:24:11 -06:00
|
|
|
|
adt::trans_field_ptr(bcx, &repr, val, disr, i)
|
2016-02-01 04:04:46 -06:00
|
|
|
|
});
|
|
|
|
|
self.store_operand(&bcx, lldest_i, op);
|
2016-02-04 11:40:28 -06:00
|
|
|
|
self.set_operand_dropped(&bcx, operand);
|
2016-01-13 18:55:46 -06:00
|
|
|
|
}
|
|
|
|
|
}
|
2015-12-24 17:02:34 -06:00
|
|
|
|
},
|
|
|
|
|
_ => {
|
|
|
|
|
for (i, operand) in operands.iter().enumerate() {
|
2016-02-01 04:04:46 -06:00
|
|
|
|
let op = self.trans_operand(&bcx, operand);
|
2016-01-12 08:36:47 -06:00
|
|
|
|
// Do not generate stores and GEPis for zero-sized fields.
|
|
|
|
|
if !common::type_is_zero_size(bcx.ccx(), op.ty) {
|
|
|
|
|
// Note: perhaps this should be StructGep, but
|
|
|
|
|
// note that in some cases the values here will
|
|
|
|
|
// not be structs but arrays.
|
2016-02-01 04:04:46 -06:00
|
|
|
|
let dest = bcx.gepi(dest.llval, &[0, i]);
|
|
|
|
|
self.store_operand(&bcx, dest, op);
|
2016-02-04 11:40:28 -06:00
|
|
|
|
self.set_operand_dropped(&bcx, operand);
|
2016-01-12 08:36:47 -06:00
|
|
|
|
}
|
2015-12-24 17:02:34 -06:00
|
|
|
|
}
|
|
|
|
|
}
|
2015-11-02 08:39:59 -06:00
|
|
|
|
}
|
|
|
|
|
bcx
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mir::Rvalue::Slice { ref input, from_start, from_end } => {
|
|
|
|
|
let ccx = bcx.ccx();
|
2016-02-01 04:04:46 -06:00
|
|
|
|
let input = self.trans_lvalue(&bcx, input);
|
|
|
|
|
let (llbase, lllen) = bcx.with_block(|bcx| {
|
|
|
|
|
tvec::get_base_and_len(bcx,
|
|
|
|
|
input.llval,
|
|
|
|
|
input.ty.to_ty(bcx.tcx()))
|
|
|
|
|
});
|
|
|
|
|
let llbase1 = bcx.gepi(llbase, &[from_start]);
|
2015-11-02 08:39:59 -06:00
|
|
|
|
let adj = common::C_uint(ccx, from_start + from_end);
|
2016-02-01 04:04:46 -06:00
|
|
|
|
let lllen1 = bcx.sub(lllen, adj);
|
|
|
|
|
let (lladdrdest, llmetadest) = bcx.with_block(|bcx| {
|
|
|
|
|
(expr::get_dataptr(bcx, dest.llval), expr::get_meta(bcx, dest.llval))
|
|
|
|
|
});
|
|
|
|
|
bcx.store(llbase1, lladdrdest);
|
|
|
|
|
bcx.store(lllen1, llmetadest);
|
2015-11-02 08:39:59 -06:00
|
|
|
|
bcx
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-10 15:39:17 -06:00
|
|
|
|
mir::Rvalue::InlineAsm(ref inline_asm) => {
|
2016-02-01 04:04:46 -06:00
|
|
|
|
bcx.map_block(|bcx| {
|
|
|
|
|
asm::trans_inline_asm(bcx, inline_asm)
|
|
|
|
|
})
|
2015-11-02 08:39:59 -06:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_ => {
|
2015-11-03 05:35:09 -06:00
|
|
|
|
assert!(rvalue_creates_operand(rvalue));
|
2015-11-02 08:39:59 -06:00
|
|
|
|
let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue);
|
2016-02-01 04:04:46 -06:00
|
|
|
|
self.store_operand(&bcx, dest.llval, temp);
|
2015-11-02 08:39:59 -06:00
|
|
|
|
bcx
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn trans_rvalue_operand(&mut self,
|
2016-02-01 04:04:46 -06:00
|
|
|
|
bcx: BlockAndBuilder<'bcx, 'tcx>,
|
2015-11-02 08:39:59 -06:00
|
|
|
|
rvalue: &mir::Rvalue<'tcx>)
|
2016-02-01 04:04:46 -06:00
|
|
|
|
-> (BlockAndBuilder<'bcx, 'tcx>, OperandRef<'tcx>)
|
2015-11-02 08:39:59 -06:00
|
|
|
|
{
|
2015-11-03 05:35:09 -06:00
|
|
|
|
assert!(rvalue_creates_operand(rvalue), "cannot trans {:?} to operand", rvalue);
|
2015-11-02 08:39:59 -06:00
|
|
|
|
|
|
|
|
|
match *rvalue {
|
2015-11-11 14:02:51 -06:00
|
|
|
|
mir::Rvalue::Cast(ref kind, ref operand, cast_ty) => {
|
2016-02-01 04:04:46 -06:00
|
|
|
|
let operand = self.trans_operand(&bcx, operand);
|
|
|
|
|
debug!("cast operand is {}", operand.repr(&bcx));
|
2015-11-11 14:02:51 -06:00
|
|
|
|
let cast_ty = bcx.monomorphize(&cast_ty);
|
|
|
|
|
|
|
|
|
|
let val = match *kind {
|
|
|
|
|
mir::CastKind::ReifyFnPointer |
|
|
|
|
|
mir::CastKind::UnsafeFnPointer => {
|
|
|
|
|
// these are no-ops at the LLVM level
|
|
|
|
|
operand.val
|
|
|
|
|
}
|
|
|
|
|
mir::CastKind::Unsize => {
|
|
|
|
|
// unsize targets other than to a fat pointer currently
|
|
|
|
|
// can't be operands.
|
|
|
|
|
assert!(common::type_is_fat_ptr(bcx.tcx(), cast_ty));
|
|
|
|
|
|
|
|
|
|
match operand.val {
|
|
|
|
|
OperandValue::FatPtr(..) => {
|
|
|
|
|
// unsize from a fat pointer - this is a
|
|
|
|
|
// "trait-object-to-supertrait" coercion, for
|
|
|
|
|
// example,
|
|
|
|
|
// &'a fmt::Debug+Send => &'a fmt::Debug,
|
|
|
|
|
// and is a no-op at the LLVM level
|
|
|
|
|
operand.val
|
|
|
|
|
}
|
2015-11-12 16:12:50 -06:00
|
|
|
|
OperandValue::Immediate(lldata) => {
|
2015-11-11 14:02:51 -06:00
|
|
|
|
// "standard" unsize
|
2016-02-01 04:04:46 -06:00
|
|
|
|
let (lldata, llextra) = bcx.with_block(|bcx| {
|
2015-11-11 14:02:51 -06:00
|
|
|
|
base::unsize_thin_ptr(bcx, lldata,
|
2016-02-01 04:04:46 -06:00
|
|
|
|
operand.ty, cast_ty)
|
|
|
|
|
});
|
2015-11-11 14:02:51 -06:00
|
|
|
|
OperandValue::FatPtr(lldata, llextra)
|
|
|
|
|
}
|
|
|
|
|
OperandValue::Ref(_) => {
|
|
|
|
|
bcx.sess().bug(
|
|
|
|
|
&format!("by-ref operand {} in trans_rvalue_operand",
|
2016-02-01 04:04:46 -06:00
|
|
|
|
operand.repr(&bcx)));
|
2015-11-11 14:02:51 -06:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-11-05 05:33:06 -06:00
|
|
|
|
mir::CastKind::Misc if common::type_is_immediate(bcx.ccx(), operand.ty) => {
|
|
|
|
|
debug_assert!(common::type_is_immediate(bcx.ccx(), cast_ty));
|
|
|
|
|
let r_t_in = CastTy::from_ty(operand.ty).expect("bad input type for cast");
|
|
|
|
|
let r_t_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
|
|
|
|
|
let ll_t_in = type_of::arg_type_of(bcx.ccx(), operand.ty);
|
|
|
|
|
let ll_t_out = type_of::arg_type_of(bcx.ccx(), cast_ty);
|
|
|
|
|
let (llval, ll_t_in, signed) = if let CastTy::Int(IntTy::CEnum) = r_t_in {
|
|
|
|
|
let repr = adt::represent_type(bcx.ccx(), operand.ty);
|
|
|
|
|
let llval = operand.immediate();
|
2016-02-01 04:04:46 -06:00
|
|
|
|
let discr = bcx.with_block(|bcx| {
|
2016-02-09 14:24:11 -06:00
|
|
|
|
adt::trans_get_discr(bcx, &repr, llval, None, true)
|
2016-02-01 04:04:46 -06:00
|
|
|
|
});
|
2016-02-09 14:24:11 -06:00
|
|
|
|
(discr, common::val_ty(discr), adt::is_discr_signed(&repr))
|
2015-11-05 05:33:06 -06:00
|
|
|
|
} else {
|
|
|
|
|
(operand.immediate(), ll_t_in, operand.ty.is_signed())
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let newval = match (r_t_in, r_t_out) {
|
|
|
|
|
(CastTy::Int(_), CastTy::Int(_)) => {
|
|
|
|
|
let srcsz = ll_t_in.int_width();
|
|
|
|
|
let dstsz = ll_t_out.int_width();
|
|
|
|
|
if srcsz == dstsz {
|
2016-02-01 04:04:46 -06:00
|
|
|
|
bcx.bitcast(llval, ll_t_out)
|
2015-11-05 05:33:06 -06:00
|
|
|
|
} else if srcsz > dstsz {
|
2016-02-01 04:04:46 -06:00
|
|
|
|
bcx.trunc(llval, ll_t_out)
|
2015-11-05 05:33:06 -06:00
|
|
|
|
} else if signed {
|
2016-02-01 04:04:46 -06:00
|
|
|
|
bcx.sext(llval, ll_t_out)
|
2015-11-05 05:33:06 -06:00
|
|
|
|
} else {
|
2016-02-01 04:04:46 -06:00
|
|
|
|
bcx.zext(llval, ll_t_out)
|
2015-11-05 05:33:06 -06:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
(CastTy::Float, CastTy::Float) => {
|
|
|
|
|
let srcsz = ll_t_in.float_width();
|
|
|
|
|
let dstsz = ll_t_out.float_width();
|
|
|
|
|
if dstsz > srcsz {
|
2016-02-01 04:04:46 -06:00
|
|
|
|
bcx.fpext(llval, ll_t_out)
|
2015-11-05 05:33:06 -06:00
|
|
|
|
} else if srcsz > dstsz {
|
2016-02-01 04:04:46 -06:00
|
|
|
|
bcx.fptrunc(llval, ll_t_out)
|
2015-11-05 05:33:06 -06:00
|
|
|
|
} else {
|
|
|
|
|
llval
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
(CastTy::Ptr(_), CastTy::Ptr(_)) |
|
|
|
|
|
(CastTy::FnPtr, CastTy::Ptr(_)) |
|
|
|
|
|
(CastTy::RPtr(_), CastTy::Ptr(_)) =>
|
2016-02-01 04:04:46 -06:00
|
|
|
|
bcx.pointercast(llval, ll_t_out),
|
2015-11-05 05:33:06 -06:00
|
|
|
|
(CastTy::Ptr(_), CastTy::Int(_)) |
|
|
|
|
|
(CastTy::FnPtr, CastTy::Int(_)) =>
|
2016-02-01 04:04:46 -06:00
|
|
|
|
bcx.ptrtoint(llval, ll_t_out),
|
2015-11-05 05:33:06 -06:00
|
|
|
|
(CastTy::Int(_), CastTy::Ptr(_)) =>
|
2016-02-01 04:04:46 -06:00
|
|
|
|
bcx.inttoptr(llval, ll_t_out),
|
2015-11-05 05:33:06 -06:00
|
|
|
|
(CastTy::Int(_), CastTy::Float) if signed =>
|
2016-02-01 04:04:46 -06:00
|
|
|
|
bcx.sitofp(llval, ll_t_out),
|
2015-11-05 05:33:06 -06:00
|
|
|
|
(CastTy::Int(_), CastTy::Float) =>
|
2016-02-01 04:04:46 -06:00
|
|
|
|
bcx.uitofp(llval, ll_t_out),
|
2015-11-05 05:33:06 -06:00
|
|
|
|
(CastTy::Float, CastTy::Int(IntTy::I)) =>
|
2016-02-01 04:04:46 -06:00
|
|
|
|
bcx.fptosi(llval, ll_t_out),
|
2015-11-05 05:33:06 -06:00
|
|
|
|
(CastTy::Float, CastTy::Int(_)) =>
|
2016-02-01 04:04:46 -06:00
|
|
|
|
bcx.fptoui(llval, ll_t_out),
|
2015-11-05 05:33:06 -06:00
|
|
|
|
_ => bcx.ccx().sess().bug(
|
|
|
|
|
&format!("unsupported cast: {:?} to {:?}", operand.ty, cast_ty)
|
|
|
|
|
)
|
|
|
|
|
};
|
|
|
|
|
OperandValue::Immediate(newval)
|
|
|
|
|
}
|
|
|
|
|
mir::CastKind::Misc => { // Casts from a fat-ptr.
|
|
|
|
|
let ll_cast_ty = type_of::arg_type_of(bcx.ccx(), cast_ty);
|
|
|
|
|
let ll_from_ty = type_of::arg_type_of(bcx.ccx(), operand.ty);
|
|
|
|
|
if let OperandValue::FatPtr(data_ptr, meta_ptr) = operand.val {
|
|
|
|
|
if common::type_is_fat_ptr(bcx.tcx(), cast_ty) {
|
|
|
|
|
let ll_cft = ll_cast_ty.field_types();
|
|
|
|
|
let ll_fft = ll_from_ty.field_types();
|
2016-02-01 04:04:46 -06:00
|
|
|
|
let data_cast = bcx.pointercast(data_ptr, ll_cft[0]);
|
2015-11-05 05:33:06 -06:00
|
|
|
|
assert_eq!(ll_cft[1].kind(), ll_fft[1].kind());
|
|
|
|
|
OperandValue::FatPtr(data_cast, meta_ptr)
|
|
|
|
|
} else { // cast to thin-ptr
|
|
|
|
|
// Cast of fat-ptr to thin-ptr is an extraction of data-ptr and
|
|
|
|
|
// pointer-cast of that pointer to desired pointer type.
|
2016-02-01 04:04:46 -06:00
|
|
|
|
let llval = bcx.pointercast(data_ptr, ll_cast_ty);
|
2015-11-05 05:33:06 -06:00
|
|
|
|
OperandValue::Immediate(llval)
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
panic!("Unexpected non-FatPtr operand")
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-11-11 14:02:51 -06:00
|
|
|
|
};
|
2016-02-01 04:04:46 -06:00
|
|
|
|
let operand = OperandRef {
|
2015-11-11 14:02:51 -06:00
|
|
|
|
val: val,
|
|
|
|
|
ty: cast_ty
|
2016-02-01 04:04:46 -06:00
|
|
|
|
};
|
|
|
|
|
(bcx, operand)
|
2015-11-02 08:39:59 -06:00
|
|
|
|
}
|
|
|
|
|
|
2015-11-11 14:02:51 -06:00
|
|
|
|
mir::Rvalue::Ref(_, bk, ref lvalue) => {
|
2016-02-01 04:04:46 -06:00
|
|
|
|
let tr_lvalue = self.trans_lvalue(&bcx, lvalue);
|
2015-11-02 08:39:59 -06:00
|
|
|
|
|
2015-11-10 14:05:11 -06:00
|
|
|
|
let ty = tr_lvalue.ty.to_ty(bcx.tcx());
|
2015-11-11 14:02:51 -06:00
|
|
|
|
let ref_ty = bcx.tcx().mk_ref(
|
|
|
|
|
bcx.tcx().mk_region(ty::ReStatic),
|
|
|
|
|
ty::TypeAndMut { ty: ty, mutbl: bk.to_mutbl_lossy() }
|
|
|
|
|
);
|
|
|
|
|
|
2015-10-21 16:42:25 -05:00
|
|
|
|
// Note: lvalues are indirect, so storing the `llval` into the
|
|
|
|
|
// destination effectively creates a reference.
|
2016-02-01 04:04:46 -06:00
|
|
|
|
let operand = if common::type_is_sized(bcx.tcx(), ty) {
|
|
|
|
|
OperandRef {
|
2015-11-12 16:12:50 -06:00
|
|
|
|
val: OperandValue::Immediate(tr_lvalue.llval),
|
2015-11-11 14:02:51 -06:00
|
|
|
|
ty: ref_ty,
|
2016-02-01 04:04:46 -06:00
|
|
|
|
}
|
2015-11-10 14:05:11 -06:00
|
|
|
|
} else {
|
2016-02-01 04:04:46 -06:00
|
|
|
|
OperandRef {
|
2015-11-10 14:05:11 -06:00
|
|
|
|
val: OperandValue::FatPtr(tr_lvalue.llval,
|
|
|
|
|
tr_lvalue.llextra),
|
2015-11-11 14:02:51 -06:00
|
|
|
|
ty: ref_ty,
|
2016-02-01 04:04:46 -06:00
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
(bcx, operand)
|
2015-10-21 16:42:25 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mir::Rvalue::Len(ref lvalue) => {
|
2016-02-01 04:04:46 -06:00
|
|
|
|
let tr_lvalue = self.trans_lvalue(&bcx, lvalue);
|
|
|
|
|
let operand = OperandRef {
|
|
|
|
|
val: OperandValue::Immediate(self.lvalue_len(&bcx, tr_lvalue)),
|
2015-11-02 08:39:59 -06:00
|
|
|
|
ty: bcx.tcx().types.usize,
|
2016-02-01 04:04:46 -06:00
|
|
|
|
};
|
|
|
|
|
(bcx, operand)
|
2015-10-21 16:42:25 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mir::Rvalue::BinaryOp(op, ref lhs, ref rhs) => {
|
2016-02-01 04:04:46 -06:00
|
|
|
|
let lhs = self.trans_operand(&bcx, lhs);
|
|
|
|
|
let rhs = self.trans_operand(&bcx, rhs);
|
2015-11-10 14:05:11 -06:00
|
|
|
|
let llresult = if common::type_is_fat_ptr(bcx.tcx(), lhs.ty) {
|
|
|
|
|
match (lhs.val, rhs.val) {
|
|
|
|
|
(OperandValue::FatPtr(lhs_addr, lhs_extra),
|
|
|
|
|
OperandValue::FatPtr(rhs_addr, rhs_extra)) => {
|
2016-02-01 04:04:46 -06:00
|
|
|
|
bcx.with_block(|bcx| {
|
|
|
|
|
base::compare_fat_ptrs(bcx,
|
|
|
|
|
lhs_addr, lhs_extra,
|
|
|
|
|
rhs_addr, rhs_extra,
|
|
|
|
|
lhs.ty, op.to_hir_binop(),
|
|
|
|
|
DebugLoc::None)
|
|
|
|
|
})
|
2015-10-21 16:42:25 -05:00
|
|
|
|
}
|
2015-11-10 14:05:11 -06:00
|
|
|
|
_ => unreachable!()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
2016-02-01 04:04:46 -06:00
|
|
|
|
self.trans_scalar_binop(&bcx, op,
|
2015-11-10 14:05:11 -06:00
|
|
|
|
lhs.immediate(), rhs.immediate(),
|
2016-02-01 04:04:46 -06:00
|
|
|
|
lhs.ty)
|
2015-10-21 16:42:25 -05:00
|
|
|
|
};
|
2016-02-01 04:04:46 -06:00
|
|
|
|
let operand = OperandRef {
|
2015-11-12 16:12:50 -06:00
|
|
|
|
val: OperandValue::Immediate(llresult),
|
|
|
|
|
ty: self.mir.binop_ty(bcx.tcx(), op, lhs.ty, rhs.ty),
|
2016-02-01 04:04:46 -06:00
|
|
|
|
};
|
|
|
|
|
(bcx, operand)
|
2015-10-21 16:42:25 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mir::Rvalue::UnaryOp(op, ref operand) => {
|
2016-02-01 04:04:46 -06:00
|
|
|
|
let operand = self.trans_operand(&bcx, operand);
|
2015-11-10 14:05:11 -06:00
|
|
|
|
let lloperand = operand.immediate();
|
2015-10-21 16:42:25 -05:00
|
|
|
|
let is_float = operand.ty.is_fp();
|
|
|
|
|
let llval = match op {
|
2016-02-01 04:04:46 -06:00
|
|
|
|
mir::UnOp::Not => bcx.not(lloperand),
|
2015-10-21 16:42:25 -05:00
|
|
|
|
mir::UnOp::Neg => if is_float {
|
2016-02-01 04:04:46 -06:00
|
|
|
|
bcx.fneg(lloperand)
|
2015-10-21 16:42:25 -05:00
|
|
|
|
} else {
|
2016-02-01 04:04:46 -06:00
|
|
|
|
bcx.neg(lloperand)
|
2015-10-21 16:42:25 -05:00
|
|
|
|
}
|
|
|
|
|
};
|
2015-11-02 08:39:59 -06:00
|
|
|
|
(bcx, OperandRef {
|
2015-11-12 16:12:50 -06:00
|
|
|
|
val: OperandValue::Immediate(llval),
|
2015-11-02 08:39:59 -06:00
|
|
|
|
ty: operand.ty,
|
|
|
|
|
})
|
2015-10-21 16:42:25 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mir::Rvalue::Box(content_ty) => {
|
2015-11-02 08:39:59 -06:00
|
|
|
|
let content_ty: Ty<'tcx> = bcx.monomorphize(&content_ty);
|
2015-10-21 16:42:25 -05:00
|
|
|
|
let llty = type_of::type_of(bcx.ccx(), content_ty);
|
|
|
|
|
let llsize = machine::llsize_of(bcx.ccx(), llty);
|
|
|
|
|
let align = type_of::align_of(bcx.ccx(), content_ty);
|
|
|
|
|
let llalign = common::C_uint(bcx.ccx(), align);
|
|
|
|
|
let llty_ptr = llty.ptr_to();
|
|
|
|
|
let box_ty = bcx.tcx().mk_box(content_ty);
|
2016-02-01 04:04:46 -06:00
|
|
|
|
let mut llval = None;
|
|
|
|
|
let bcx = bcx.map_block(|bcx| {
|
|
|
|
|
let Result { bcx, val } = base::malloc_raw_dyn(bcx,
|
|
|
|
|
llty_ptr,
|
|
|
|
|
box_ty,
|
|
|
|
|
llsize,
|
|
|
|
|
llalign,
|
|
|
|
|
DebugLoc::None);
|
|
|
|
|
llval = Some(val);
|
|
|
|
|
bcx
|
|
|
|
|
});
|
|
|
|
|
let operand = OperandRef {
|
|
|
|
|
val: OperandValue::Immediate(llval.unwrap()),
|
2015-11-02 08:39:59 -06:00
|
|
|
|
ty: box_ty,
|
2016-02-01 04:04:46 -06:00
|
|
|
|
};
|
|
|
|
|
(bcx, operand)
|
2015-10-21 16:42:25 -05:00
|
|
|
|
}
|
|
|
|
|
|
2016-02-04 11:40:28 -06:00
|
|
|
|
mir::Rvalue::Use(..) |
|
2015-11-02 08:39:59 -06:00
|
|
|
|
mir::Rvalue::Repeat(..) |
|
|
|
|
|
mir::Rvalue::Aggregate(..) |
|
|
|
|
|
mir::Rvalue::Slice { .. } |
|
|
|
|
|
mir::Rvalue::InlineAsm(..) => {
|
|
|
|
|
bcx.tcx().sess.bug(&format!("cannot generate operand from rvalue {:?}", rvalue));
|
2015-10-21 16:42:25 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-11-10 14:05:11 -06:00
|
|
|
|
|
|
|
|
|
pub fn trans_scalar_binop(&mut self,
|
2016-02-01 04:04:46 -06:00
|
|
|
|
bcx: &BlockAndBuilder<'bcx, 'tcx>,
|
2015-11-10 14:05:11 -06:00
|
|
|
|
op: mir::BinOp,
|
|
|
|
|
lhs: ValueRef,
|
|
|
|
|
rhs: ValueRef,
|
2016-02-01 04:04:46 -06:00
|
|
|
|
input_ty: Ty<'tcx>) -> ValueRef {
|
2015-11-10 14:05:11 -06:00
|
|
|
|
let is_float = input_ty.is_fp();
|
|
|
|
|
let is_signed = input_ty.is_signed();
|
|
|
|
|
match op {
|
|
|
|
|
mir::BinOp::Add => if is_float {
|
2016-02-01 04:04:46 -06:00
|
|
|
|
bcx.fadd(lhs, rhs)
|
2015-11-10 14:05:11 -06:00
|
|
|
|
} else {
|
2016-02-01 04:04:46 -06:00
|
|
|
|
bcx.add(lhs, rhs)
|
2015-11-10 14:05:11 -06:00
|
|
|
|
},
|
|
|
|
|
mir::BinOp::Sub => if is_float {
|
2016-02-01 04:04:46 -06:00
|
|
|
|
bcx.fsub(lhs, rhs)
|
2015-11-10 14:05:11 -06:00
|
|
|
|
} else {
|
2016-02-01 04:04:46 -06:00
|
|
|
|
bcx.sub(lhs, rhs)
|
2015-11-10 14:05:11 -06:00
|
|
|
|
},
|
|
|
|
|
mir::BinOp::Mul => if is_float {
|
2016-02-01 04:04:46 -06:00
|
|
|
|
bcx.fmul(lhs, rhs)
|
2015-11-10 14:05:11 -06:00
|
|
|
|
} else {
|
2016-02-01 04:04:46 -06:00
|
|
|
|
bcx.mul(lhs, rhs)
|
2015-11-10 14:05:11 -06:00
|
|
|
|
},
|
|
|
|
|
mir::BinOp::Div => if is_float {
|
2016-02-01 04:04:46 -06:00
|
|
|
|
bcx.fdiv(lhs, rhs)
|
2015-11-10 14:05:11 -06:00
|
|
|
|
} else if is_signed {
|
2016-02-01 04:04:46 -06:00
|
|
|
|
bcx.sdiv(lhs, rhs)
|
2015-11-10 14:05:11 -06:00
|
|
|
|
} else {
|
2016-02-01 04:04:46 -06:00
|
|
|
|
bcx.udiv(lhs, rhs)
|
2015-11-10 14:05:11 -06:00
|
|
|
|
},
|
|
|
|
|
mir::BinOp::Rem => if is_float {
|
|
|
|
|
// LLVM currently always lowers the `frem` instructions appropriate
|
|
|
|
|
// library calls typically found in libm. Notably f64 gets wired up
|
|
|
|
|
// to `fmod` and f32 gets wired up to `fmodf`. Inconveniently for
|
|
|
|
|
// us, 32-bit MSVC does not actually have a `fmodf` symbol, it's
|
|
|
|
|
// instead just an inline function in a header that goes up to a
|
|
|
|
|
// f64, uses `fmod`, and then comes back down to a f32.
|
|
|
|
|
//
|
|
|
|
|
// Although LLVM knows that `fmodf` doesn't exist on MSVC, it will
|
|
|
|
|
// still unconditionally lower frem instructions over 32-bit floats
|
|
|
|
|
// to a call to `fmodf`. To work around this we special case MSVC
|
|
|
|
|
// 32-bit float rem instructions and instead do the call out to
|
|
|
|
|
// `fmod` ourselves.
|
|
|
|
|
//
|
|
|
|
|
// Note that this is currently duplicated with src/libcore/ops.rs
|
|
|
|
|
// which does the same thing, and it would be nice to perhaps unify
|
|
|
|
|
// these two implementations one day! Also note that we call `fmod`
|
|
|
|
|
// for both 32 and 64-bit floats because if we emit any FRem
|
|
|
|
|
// instruction at all then LLVM is capable of optimizing it into a
|
|
|
|
|
// 32-bit FRem (which we're trying to avoid).
|
|
|
|
|
let tcx = bcx.tcx();
|
|
|
|
|
let use_fmod = tcx.sess.target.target.options.is_like_msvc &&
|
|
|
|
|
tcx.sess.target.target.arch == "x86";
|
|
|
|
|
if use_fmod {
|
|
|
|
|
let f64t = Type::f64(bcx.ccx());
|
|
|
|
|
let fty = Type::func(&[f64t, f64t], &f64t);
|
|
|
|
|
let llfn = declare::declare_cfn(bcx.ccx(), "fmod", fty,
|
|
|
|
|
tcx.types.f64);
|
|
|
|
|
if input_ty == tcx.types.f32 {
|
2016-02-01 04:04:46 -06:00
|
|
|
|
let lllhs = bcx.fpext(lhs, f64t);
|
|
|
|
|
let llrhs = bcx.fpext(rhs, f64t);
|
2016-02-08 16:08:47 -06:00
|
|
|
|
let llres = bcx.call(llfn, &[lllhs, llrhs], None, None);
|
2016-02-01 04:04:46 -06:00
|
|
|
|
bcx.fptrunc(llres, Type::f32(bcx.ccx()))
|
2015-11-10 14:05:11 -06:00
|
|
|
|
} else {
|
2016-02-08 16:08:47 -06:00
|
|
|
|
bcx.call(llfn, &[lhs, rhs], None, None)
|
2015-11-10 14:05:11 -06:00
|
|
|
|
}
|
|
|
|
|
} else {
|
2016-02-01 04:04:46 -06:00
|
|
|
|
bcx.frem(lhs, rhs)
|
2015-11-10 14:05:11 -06:00
|
|
|
|
}
|
|
|
|
|
} else if is_signed {
|
2016-02-01 04:04:46 -06:00
|
|
|
|
bcx.srem(lhs, rhs)
|
2015-11-10 14:05:11 -06:00
|
|
|
|
} else {
|
2016-02-01 04:04:46 -06:00
|
|
|
|
bcx.urem(lhs, rhs)
|
2015-11-10 14:05:11 -06:00
|
|
|
|
},
|
2016-02-01 04:04:46 -06:00
|
|
|
|
mir::BinOp::BitOr => bcx.or(lhs, rhs),
|
|
|
|
|
mir::BinOp::BitAnd => bcx.and(lhs, rhs),
|
|
|
|
|
mir::BinOp::BitXor => bcx.xor(lhs, rhs),
|
|
|
|
|
mir::BinOp::Shl => {
|
|
|
|
|
bcx.with_block(|bcx| {
|
|
|
|
|
common::build_unchecked_lshift(bcx,
|
|
|
|
|
lhs,
|
|
|
|
|
rhs,
|
|
|
|
|
DebugLoc::None)
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
mir::BinOp::Shr => {
|
|
|
|
|
bcx.with_block(|bcx| {
|
|
|
|
|
common::build_unchecked_rshift(bcx,
|
|
|
|
|
input_ty,
|
|
|
|
|
lhs,
|
|
|
|
|
rhs,
|
|
|
|
|
DebugLoc::None)
|
|
|
|
|
})
|
|
|
|
|
}
|
2015-11-10 14:05:11 -06:00
|
|
|
|
mir::BinOp::Eq | mir::BinOp::Lt | mir::BinOp::Gt |
|
|
|
|
|
mir::BinOp::Ne | mir::BinOp::Le | mir::BinOp::Ge => {
|
2016-02-01 04:04:46 -06:00
|
|
|
|
bcx.with_block(|bcx| {
|
|
|
|
|
base::compare_scalar_types(bcx, lhs, rhs, input_ty,
|
|
|
|
|
op.to_hir_binop(), DebugLoc::None)
|
|
|
|
|
})
|
2015-11-10 14:05:11 -06:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-10-21 16:42:25 -05:00
|
|
|
|
}
|
2015-11-03 05:35:09 -06:00
|
|
|
|
|
|
|
|
|
pub fn rvalue_creates_operand<'tcx>(rvalue: &mir::Rvalue<'tcx>) -> bool {
|
|
|
|
|
match *rvalue {
|
|
|
|
|
mir::Rvalue::Ref(..) |
|
|
|
|
|
mir::Rvalue::Len(..) |
|
|
|
|
|
mir::Rvalue::Cast(..) | // (*)
|
|
|
|
|
mir::Rvalue::BinaryOp(..) |
|
|
|
|
|
mir::Rvalue::UnaryOp(..) |
|
|
|
|
|
mir::Rvalue::Box(..) =>
|
|
|
|
|
true,
|
2016-02-04 11:40:28 -06:00
|
|
|
|
mir::Rvalue::Use(..) | // (**)
|
2015-11-03 05:35:09 -06:00
|
|
|
|
mir::Rvalue::Repeat(..) |
|
|
|
|
|
mir::Rvalue::Aggregate(..) |
|
|
|
|
|
mir::Rvalue::Slice { .. } |
|
|
|
|
|
mir::Rvalue::InlineAsm(..) =>
|
|
|
|
|
false,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// (*) this is only true if the type is suitable
|
2016-02-26 06:12:28 -06:00
|
|
|
|
// (**) we need to zero-out the source operand after moving, so we are restricted to either
|
|
|
|
|
// ensuring all users of `Use` zero it out themselves or not allowing to “create” operand for
|
|
|
|
|
// it.
|
2015-11-03 05:35:09 -06:00
|
|
|
|
}
|