Rollup merge of #36962 - arielb1:cast-assumptions, r=eddyb
Emit more assumptions in trans Perf numbers pending.
This commit is contained in:
commit
ed5a3c01a0
@ -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,
|
||||
@ -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,
|
||||
@ -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.
|
||||
@ -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);
|
||||
}
|
||||
@ -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 {
|
||||
|
@ -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::*;
|
||||
|
||||
@ -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
|
||||
|
@ -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;
|
||||
@ -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>,
|
||||
|
@ -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};
|
||||
@ -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);
|
||||
}
|
||||
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -11,15 +11,18 @@
|
||||
use llvm::{self, ValueRef};
|
||||
use rustc::ty::{self, Ty};
|
||||
use rustc::ty::cast::{CastTy, IntTy};
|
||||
use rustc::ty::layout::Layout;
|
||||
use rustc::mir::repr as mir;
|
||||
|
||||
use asm;
|
||||
use base;
|
||||
use callee::Callee;
|
||||
use common::{self, val_ty, C_bool, C_null, C_uint, BlockAndBuilder, Result};
|
||||
use common::{C_integral};
|
||||
use debuginfo::DebugLoc;
|
||||
use adt;
|
||||
use machine;
|
||||
use type_::Type;
|
||||
use type_of;
|
||||
use tvec;
|
||||
use value::Value;
|
||||
@ -28,7 +31,7 @@ use Disr;
|
||||
use super::MirContext;
|
||||
use super::constant::const_scalar_checked_binop;
|
||||
use super::operand::{OperandRef, OperandValue};
|
||||
use super::lvalue::{LvalueRef, get_dataptr};
|
||||
use super::lvalue::{LvalueRef};
|
||||
|
||||
impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
||||
pub fn trans_rvalue(&mut self,
|
||||
@ -98,7 +101,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
||||
let tr_elem = self.trans_operand(&bcx, elem);
|
||||
let size = count.value.as_u64(bcx.tcx().sess.target.uint_type);
|
||||
let size = C_uint(bcx.ccx(), size);
|
||||
let base = get_dataptr(&bcx, dest.llval);
|
||||
let base = base::get_dataptr_builder(&bcx, dest.llval);
|
||||
let bcx = bcx.map_block(|block| {
|
||||
tvec::slice_for_each(block, base, tr_elem.ty, size, |block, llslot| {
|
||||
self.store_operand_direct(block, llslot, tr_elem);
|
||||
@ -281,7 +284,26 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
||||
}
|
||||
OperandValue::Pair(..) => bug!("Unexpected Pair operand")
|
||||
};
|
||||
(discr, adt::is_discr_signed(&l))
|
||||
let (signed, min, max) = match l {
|
||||
&Layout::CEnum { signed, min, max, .. } => {
|
||||
(signed, min, max)
|
||||
}
|
||||
_ => bug!("CEnum {:?} is not an enum", operand)
|
||||
};
|
||||
|
||||
if max > min {
|
||||
// We want `table[e as usize]` to not
|
||||
// have bound checks, and this is the most
|
||||
// convenient place to put the `assume`.
|
||||
|
||||
base::call_assume(&bcx, bcx.icmp(
|
||||
llvm::IntULE,
|
||||
discr,
|
||||
C_integral(common::val_ty(discr), max, false)
|
||||
))
|
||||
}
|
||||
|
||||
(discr, signed)
|
||||
} else {
|
||||
(operand.immediate(), operand.ty.is_signed())
|
||||
};
|
||||
@ -382,13 +404,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
||||
match (lhs.val, rhs.val) {
|
||||
(OperandValue::Pair(lhs_addr, lhs_extra),
|
||||
OperandValue::Pair(rhs_addr, rhs_extra)) => {
|
||||
bcx.with_block(|bcx| {
|
||||
base::compare_fat_ptrs(bcx,
|
||||
lhs_addr, lhs_extra,
|
||||
rhs_addr, rhs_extra,
|
||||
lhs.ty, op.to_hir_binop(),
|
||||
debug_loc)
|
||||
})
|
||||
self.trans_fat_ptr_binop(&bcx, op,
|
||||
lhs_addr, lhs_extra,
|
||||
rhs_addr, rhs_extra,
|
||||
lhs.ty)
|
||||
}
|
||||
_ => bug!()
|
||||
}
|
||||
@ -485,6 +504,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
||||
input_ty: Ty<'tcx>) -> ValueRef {
|
||||
let is_float = input_ty.is_fp();
|
||||
let is_signed = input_ty.is_signed();
|
||||
let is_nil = input_ty.is_nil();
|
||||
let is_bool = input_ty.is_bool();
|
||||
match op {
|
||||
mir::BinOp::Add => if is_float {
|
||||
bcx.fadd(lhs, rhs)
|
||||
@ -535,12 +556,79 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
||||
DebugLoc::None)
|
||||
})
|
||||
}
|
||||
mir::BinOp::Eq | mir::BinOp::Lt | mir::BinOp::Gt |
|
||||
mir::BinOp::Ne | mir::BinOp::Le | mir::BinOp::Ge => {
|
||||
bcx.with_block(|bcx| {
|
||||
base::compare_scalar_types(bcx, lhs, rhs, input_ty,
|
||||
op.to_hir_binop(), DebugLoc::None)
|
||||
mir::BinOp::Ne | mir::BinOp::Lt | mir::BinOp::Gt |
|
||||
mir::BinOp::Eq | mir::BinOp::Le | mir::BinOp::Ge => if is_nil {
|
||||
C_bool(bcx.ccx(), match op {
|
||||
mir::BinOp::Ne | mir::BinOp::Lt | mir::BinOp::Gt => false,
|
||||
mir::BinOp::Eq | mir::BinOp::Le | mir::BinOp::Ge => true,
|
||||
_ => unreachable!()
|
||||
})
|
||||
} else if is_float {
|
||||
bcx.fcmp(
|
||||
base::bin_op_to_fcmp_predicate(op.to_hir_binop()),
|
||||
lhs, rhs
|
||||
)
|
||||
} else {
|
||||
let (lhs, rhs) = if is_bool {
|
||||
// FIXME(#36856) -- extend the bools into `i8` because
|
||||
// LLVM's i1 comparisons are broken.
|
||||
(bcx.zext(lhs, Type::i8(bcx.ccx())),
|
||||
bcx.zext(rhs, Type::i8(bcx.ccx())))
|
||||
} else {
|
||||
(lhs, rhs)
|
||||
};
|
||||
|
||||
bcx.icmp(
|
||||
base::bin_op_to_icmp_predicate(op.to_hir_binop(), is_signed),
|
||||
lhs, rhs
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn trans_fat_ptr_binop(&mut self,
|
||||
bcx: &BlockAndBuilder<'bcx, 'tcx>,
|
||||
op: mir::BinOp,
|
||||
lhs_addr: ValueRef,
|
||||
lhs_extra: ValueRef,
|
||||
rhs_addr: ValueRef,
|
||||
rhs_extra: ValueRef,
|
||||
_input_ty: Ty<'tcx>)
|
||||
-> ValueRef {
|
||||
match op {
|
||||
mir::BinOp::Eq => {
|
||||
bcx.and(
|
||||
bcx.icmp(llvm::IntEQ, lhs_addr, rhs_addr),
|
||||
bcx.icmp(llvm::IntEQ, lhs_extra, rhs_extra)
|
||||
)
|
||||
}
|
||||
mir::BinOp::Ne => {
|
||||
bcx.or(
|
||||
bcx.icmp(llvm::IntNE, lhs_addr, rhs_addr),
|
||||
bcx.icmp(llvm::IntNE, lhs_extra, rhs_extra)
|
||||
)
|
||||
}
|
||||
mir::BinOp::Le | mir::BinOp::Lt |
|
||||
mir::BinOp::Ge | mir::BinOp::Gt => {
|
||||
// a OP b ~ a.0 STRICT(OP) b.0 | (a.0 == b.0 && a.1 OP a.1)
|
||||
let (op, strict_op) = match op {
|
||||
mir::BinOp::Lt => (llvm::IntULT, llvm::IntULT),
|
||||
mir::BinOp::Le => (llvm::IntULE, llvm::IntULT),
|
||||
mir::BinOp::Gt => (llvm::IntUGT, llvm::IntUGT),
|
||||
mir::BinOp::Ge => (llvm::IntUGE, llvm::IntUGT),
|
||||
_ => bug!(),
|
||||
};
|
||||
|
||||
bcx.or(
|
||||
bcx.icmp(strict_op, lhs_addr, rhs_addr),
|
||||
bcx.and(
|
||||
bcx.icmp(llvm::IntEQ, lhs_addr, rhs_addr),
|
||||
bcx.icmp(op, lhs_extra, rhs_extra)
|
||||
)
|
||||
)
|
||||
}
|
||||
_ => {
|
||||
bug!("unexpected fat ptr binop");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
24
src/test/codegen/enum-bounds-check.rs
Normal file
24
src/test/codegen/enum-bounds-check.rs
Normal file
@ -0,0 +1,24 @@
|
||||
// Copyright 2016 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.
|
||||
|
||||
// compile-flags: -O
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
||||
pub enum Foo {
|
||||
A, B
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @lookup
|
||||
#[no_mangle]
|
||||
pub fn lookup(buf: &[u8; 2], f: Foo) -> u8 {
|
||||
// CHECK-NOT: panic_bounds_check
|
||||
buf[f as usize]
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user