Skip to content

Commit

Permalink
Rollup merge of rust-lang#36962 - arielb1:cast-assumptions, r=eddyb
Browse files Browse the repository at this point in the history
Emit more assumptions in trans

Perf numbers pending.
  • Loading branch information
Jonathan Turner authored Oct 6, 2016
2 parents 1a7aa75 + 45fe3a1 commit ed5a3c0
Show file tree
Hide file tree
Showing 7 changed files with 193 additions and 176 deletions.
175 changes: 46 additions & 129 deletions src/librustc_trans/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,14 @@ pub fn get_dataptr(bcx: Block, fat_ptr: ValueRef) -> ValueRef {
StructGEP(bcx, fat_ptr, abi::FAT_PTR_ADDR)
}

pub fn get_meta_builder(b: &Builder, fat_ptr: ValueRef) -> ValueRef {
b.struct_gep(fat_ptr, abi::FAT_PTR_EXTRA)
}

pub fn get_dataptr_builder(b: &Builder, fat_ptr: ValueRef) -> ValueRef {
b.struct_gep(fat_ptr, abi::FAT_PTR_ADDR)
}

fn require_alloc_fn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, info_ty: Ty<'tcx>, it: LangItem) -> DefId {
match bcx.tcx().lang_items.require(it) {
Ok(id) => id,
Expand Down Expand Up @@ -247,124 +255,6 @@ pub fn bin_op_to_fcmp_predicate(op: hir::BinOp_) -> llvm::RealPredicate {
}
}

pub fn compare_fat_ptrs<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
lhs_addr: ValueRef,
lhs_extra: ValueRef,
rhs_addr: ValueRef,
rhs_extra: ValueRef,
_t: Ty<'tcx>,
op: hir::BinOp_,
debug_loc: DebugLoc)
-> ValueRef {
match op {
hir::BiEq => {
let addr_eq = ICmp(bcx, llvm::IntEQ, lhs_addr, rhs_addr, debug_loc);
let extra_eq = ICmp(bcx, llvm::IntEQ, lhs_extra, rhs_extra, debug_loc);
And(bcx, addr_eq, extra_eq, debug_loc)
}
hir::BiNe => {
let addr_eq = ICmp(bcx, llvm::IntNE, lhs_addr, rhs_addr, debug_loc);
let extra_eq = ICmp(bcx, llvm::IntNE, lhs_extra, rhs_extra, debug_loc);
Or(bcx, addr_eq, extra_eq, debug_loc)
}
hir::BiLe | hir::BiLt | hir::BiGe | hir::BiGt => {
// a OP b ~ a.0 STRICT(OP) b.0 | (a.0 == b.0 && a.1 OP a.1)
let (op, strict_op) = match op {
hir::BiLt => (llvm::IntULT, llvm::IntULT),
hir::BiLe => (llvm::IntULE, llvm::IntULT),
hir::BiGt => (llvm::IntUGT, llvm::IntUGT),
hir::BiGe => (llvm::IntUGE, llvm::IntUGT),
_ => bug!(),
};

let addr_eq = ICmp(bcx, llvm::IntEQ, lhs_addr, rhs_addr, debug_loc);
let extra_op = ICmp(bcx, op, lhs_extra, rhs_extra, debug_loc);
let addr_eq_extra_op = And(bcx, addr_eq, extra_op, debug_loc);

let addr_strict = ICmp(bcx, strict_op, lhs_addr, rhs_addr, debug_loc);
Or(bcx, addr_strict, addr_eq_extra_op, debug_loc)
}
_ => {
bug!("unexpected fat ptr binop");
}
}
}

pub fn compare_scalar_types<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
lhs: ValueRef,
rhs: ValueRef,
t: Ty<'tcx>,
op: hir::BinOp_,
debug_loc: DebugLoc)
-> ValueRef {
match t.sty {
ty::TyTuple(ref tys) if tys.is_empty() => {
// We don't need to do actual comparisons for nil.
// () == () holds but () < () does not.
match op {
hir::BiEq | hir::BiLe | hir::BiGe => return C_bool(bcx.ccx(), true),
hir::BiNe | hir::BiLt | hir::BiGt => return C_bool(bcx.ccx(), false),
// refinements would be nice
_ => bug!("compare_scalar_types: must be a comparison operator"),
}
}
ty::TyBool => {
// FIXME(#36856) -- using `from_immediate` forces these booleans into `i8`,
// which works around some LLVM bugs
ICmp(bcx,
bin_op_to_icmp_predicate(op, false),
from_immediate(bcx, lhs),
from_immediate(bcx, rhs),
debug_loc)
}
ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyUint(_) | ty::TyChar => {
ICmp(bcx,
bin_op_to_icmp_predicate(op, false),
lhs,
rhs,
debug_loc)
}
ty::TyRawPtr(mt) if common::type_is_sized(bcx.tcx(), mt.ty) => {
ICmp(bcx,
bin_op_to_icmp_predicate(op, false),
lhs,
rhs,
debug_loc)
}
ty::TyRawPtr(_) => {
let lhs_addr = Load(bcx, GEPi(bcx, lhs, &[0, abi::FAT_PTR_ADDR]));
let lhs_extra = Load(bcx, GEPi(bcx, lhs, &[0, abi::FAT_PTR_EXTRA]));

let rhs_addr = Load(bcx, GEPi(bcx, rhs, &[0, abi::FAT_PTR_ADDR]));
let rhs_extra = Load(bcx, GEPi(bcx, rhs, &[0, abi::FAT_PTR_EXTRA]));
compare_fat_ptrs(bcx,
lhs_addr,
lhs_extra,
rhs_addr,
rhs_extra,
t,
op,
debug_loc)
}
ty::TyInt(_) => {
ICmp(bcx,
bin_op_to_icmp_predicate(op, true),
lhs,
rhs,
debug_loc)
}
ty::TyFloat(_) => {
FCmp(bcx,
bin_op_to_fcmp_predicate(op),
lhs,
rhs,
debug_loc)
}
// Should never get here, because t is scalar.
_ => bug!("non-scalar type passed to compare_scalar_types"),
}
}

pub fn compare_simd_types<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
lhs: ValueRef,
rhs: ValueRef,
Expand Down Expand Up @@ -632,6 +522,11 @@ pub fn need_invoke(bcx: Block) -> bool {
}
}

pub fn call_assume<'a, 'tcx>(b: &Builder<'a, 'tcx>, val: ValueRef) {
let assume_intrinsic = b.ccx.get_intrinsic("llvm.assume");
b.call(assume_intrinsic, &[val], None);
}

/// Helper for loading values from memory. Does the necessary conversion if the in-memory type
/// differs from the type used for SSA values. Also handles various special cases where the type
/// gives us better information about what we are loading.
Expand Down Expand Up @@ -685,12 +580,9 @@ pub fn store_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, v: ValueRef, dst: ValueRef, t
debug!("store_ty: {:?} : {:?} <- {:?}", Value(dst), t, Value(v));

if common::type_is_fat_ptr(cx.tcx(), t) {
Store(cx,
ExtractValue(cx, v, abi::FAT_PTR_ADDR),
get_dataptr(cx, dst));
Store(cx,
ExtractValue(cx, v, abi::FAT_PTR_EXTRA),
get_meta(cx, dst));
let lladdr = ExtractValue(cx, v, abi::FAT_PTR_ADDR);
let llextra = ExtractValue(cx, v, abi::FAT_PTR_EXTRA);
store_fat_ptr(cx, lladdr, llextra, dst, t);
} else {
Store(cx, from_immediate(cx, v), dst);
}
Expand All @@ -708,11 +600,36 @@ pub fn store_fat_ptr<'blk, 'tcx>(cx: Block<'blk, 'tcx>,

pub fn load_fat_ptr<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
src: ValueRef,
_ty: Ty<'tcx>)
-> (ValueRef, ValueRef) {
// FIXME: emit metadata
(Load(cx, get_dataptr(cx, src)),
Load(cx, get_meta(cx, src)))
ty: Ty<'tcx>)
-> (ValueRef, ValueRef)
{
if cx.unreachable.get() {
// FIXME: remove me
return (Load(cx, get_dataptr(cx, src)),
Load(cx, get_meta(cx, src)));
}

load_fat_ptr_builder(&B(cx), src, ty)
}

pub fn load_fat_ptr_builder<'a, 'tcx>(
b: &Builder<'a, 'tcx>,
src: ValueRef,
t: Ty<'tcx>)
-> (ValueRef, ValueRef)
{

let ptr = get_dataptr_builder(b, src);
let ptr = if t.is_region_ptr() || t.is_unique() {
b.load_nonnull(ptr)
} else {
b.load(ptr)
};

// FIXME: emit metadata on `meta`.
let meta = b.load(get_meta_builder(b, src));

(ptr, meta)
}

pub fn from_immediate(bcx: Block, val: ValueRef) -> ValueRef {
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_trans/mir/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ use syntax::parse::token;
use super::{MirContext, LocalRef};
use super::analyze::CleanupKind;
use super::constant::Const;
use super::lvalue::{LvalueRef, load_fat_ptr};
use super::lvalue::{LvalueRef};
use super::operand::OperandRef;
use super::operand::OperandValue::*;

Expand Down Expand Up @@ -703,7 +703,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
for (n, &ty) in arg_types.iter().enumerate() {
let ptr = adt::trans_field_ptr_builder(bcx, tuple.ty, base, Disr(0), n);
let val = if common::type_is_fat_ptr(bcx.tcx(), ty) {
let (lldata, llextra) = load_fat_ptr(bcx, ptr);
let (lldata, llextra) = base::load_fat_ptr_builder(bcx, ptr, ty);
Pair(lldata, llextra)
} else {
// trans_argument will load this if it needs to
Expand Down
14 changes: 0 additions & 14 deletions src/librustc_trans/mir/lvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,8 @@ use rustc::ty::{self, Ty, TypeFoldable};
use rustc::mir::repr as mir;
use rustc::mir::tcx::LvalueTy;
use rustc_data_structures::indexed_vec::Idx;
use abi;
use adt;
use base;
use builder::Builder;
use common::{self, BlockAndBuilder, CrateContext, C_uint, C_undef};
use consts;
use machine;
Expand Down Expand Up @@ -69,18 +67,6 @@ impl<'tcx> LvalueRef<'tcx> {
}
}

pub fn get_meta(b: &Builder, fat_ptr: ValueRef) -> ValueRef {
b.struct_gep(fat_ptr, abi::FAT_PTR_EXTRA)
}

pub fn get_dataptr(b: &Builder, fat_ptr: ValueRef) -> ValueRef {
b.struct_gep(fat_ptr, abi::FAT_PTR_ADDR)
}

pub fn load_fat_ptr(b: &Builder, fat_ptr: ValueRef) -> (ValueRef, ValueRef) {
(b.load(get_dataptr(b, fat_ptr)), b.load(get_meta(b, fat_ptr)))
}

impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
pub fn trans_lvalue(&mut self,
bcx: &BlockAndBuilder<'bcx, 'tcx>,
Expand Down
14 changes: 9 additions & 5 deletions src/librustc_trans/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ use rustc_data_structures::indexed_vec::{IndexVec, Idx};

pub use self::constant::trans_static_initializer;

use self::lvalue::{LvalueRef, get_dataptr, get_meta};
use self::lvalue::{LvalueRef};
use rustc::mir::traversal;

use self::operand::{OperandRef, OperandValue};
Expand Down Expand Up @@ -384,8 +384,10 @@ fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
// they are the two sub-fields of a single aggregate field.
let meta = &fcx.fn_ty.args[idx];
idx += 1;
arg.store_fn_arg(bcx, &mut llarg_idx, get_dataptr(bcx, dst));
meta.store_fn_arg(bcx, &mut llarg_idx, get_meta(bcx, dst));
arg.store_fn_arg(bcx, &mut llarg_idx,
base::get_dataptr_builder(bcx, dst));
meta.store_fn_arg(bcx, &mut llarg_idx,
base::get_meta_builder(bcx, dst));
} else {
arg.store_fn_arg(bcx, &mut llarg_idx, dst);
}
Expand Down Expand Up @@ -466,8 +468,10 @@ fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
// so make an alloca to store them in.
let meta = &fcx.fn_ty.args[idx];
idx += 1;
arg.store_fn_arg(bcx, &mut llarg_idx, get_dataptr(bcx, lltemp));
meta.store_fn_arg(bcx, &mut llarg_idx, get_meta(bcx, lltemp));
arg.store_fn_arg(bcx, &mut llarg_idx,
base::get_dataptr_builder(bcx, lltemp));
meta.store_fn_arg(bcx, &mut llarg_idx,
base::get_meta_builder(bcx, lltemp));
} else {
// otherwise, arg is passed by value, so make a
// temporary and store it there
Expand Down
20 changes: 9 additions & 11 deletions src/librustc_trans/mir/operand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,20 +143,18 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
{
debug!("trans_load: {:?} @ {:?}", Value(llval), ty);

let val = if common::type_is_imm_pair(bcx.ccx(), ty) {
let val = if common::type_is_fat_ptr(bcx.tcx(), ty) {
let (lldata, llextra) = base::load_fat_ptr_builder(bcx, llval, ty);
OperandValue::Pair(lldata, llextra)
} else if common::type_is_imm_pair(bcx.ccx(), ty) {
let [a_ty, b_ty] = common::type_pair_fields(bcx.ccx(), ty).unwrap();
let a_ptr = bcx.struct_gep(llval, 0);
let b_ptr = bcx.struct_gep(llval, 1);

// This is None only for fat pointers, which don't
// need any special load-time behavior anyway.
let pair_fields = common::type_pair_fields(bcx.ccx(), ty);
let (a, b) = if let Some([a_ty, b_ty]) = pair_fields {
(base::load_ty_builder(bcx, a_ptr, a_ty),
base::load_ty_builder(bcx, b_ptr, b_ty))
} else {
(bcx.load(a_ptr), bcx.load(b_ptr))
};
OperandValue::Pair(a, b)
OperandValue::Pair(
base::load_ty_builder(bcx, a_ptr, a_ty),
base::load_ty_builder(bcx, b_ptr, b_ty)
)
} else if common::type_is_immediate(bcx.ccx(), ty) {
OperandValue::Immediate(base::load_ty_builder(bcx, llval, ty))
} else {
Expand Down
Loading

0 comments on commit ed5a3c0

Please sign in to comment.