Skip to content

Emit more assumptions in trans #36962

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Oct 6, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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