}
}
-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,
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);
}
use debuginfo::DebugLoc;
use adt;
use machine;
+use type_::Type;
use type_of;
use tvec;
use value::Value;
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!()
}
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)
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");
}
}
}