Skip to content

Commit

Permalink
MIR: implement fat raw pointer comparisons
Browse files Browse the repository at this point in the history
The implementation itself only requires changes to trans, but
a few additional bugs concerning the handling of fat pointers
had to be fixed.
  • Loading branch information
arielb1 committed Nov 13, 2015
1 parent 3beb159 commit 602cf7e
Show file tree
Hide file tree
Showing 6 changed files with 279 additions and 61 deletions.
44 changes: 44 additions & 0 deletions src/librustc_trans/trans/base.rs
Expand Up @@ -336,6 +336,46 @@ pub fn compare_scalar_types<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
ty::TyRawPtr(mt) if common::type_is_sized(bcx.tcx(), mt.ty) => {
ICmp(bcx, bin_op_to_icmp_predicate(bcx.ccx(), 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]));

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),
_ => unreachable!()
};

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)
}
_ => {
bcx.tcx().sess.bug("unexpected fat ptr binop");
}
}
}
ty::TyInt(_) => {
ICmp(bcx, bin_op_to_icmp_predicate(bcx.ccx(), op, true), lhs, rhs, debug_loc)
}
Expand Down Expand Up @@ -828,6 +868,10 @@ pub fn store_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, v: ValueRef, dst: ValueRef, t
return;
}

debug!("store_ty: {} : {:?} <- {}",
cx.val_to_string(dst), t,
cx.val_to_string(v));

if common::type_is_fat_ptr(cx.tcx(), t) {
Store(cx, ExtractValue(cx, v, abi::FAT_PTR_ADDR), expr::get_dataptr(cx, dst));
Store(cx, ExtractValue(cx, v, abi::FAT_PTR_EXTRA), expr::get_meta(cx, dst));
Expand Down
62 changes: 9 additions & 53 deletions src/librustc_trans/trans/expr.rs
Expand Up @@ -1725,58 +1725,6 @@ fn trans_addr_of<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
}
}

fn trans_fat_ptr_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
binop_expr: &hir::Expr,
binop_ty: Ty<'tcx>,
op: hir::BinOp,
lhs: Datum<'tcx, Rvalue>,
rhs: Datum<'tcx, Rvalue>)
-> DatumBlock<'blk, 'tcx, Expr>
{
let debug_loc = binop_expr.debug_loc();

let lhs_addr = Load(bcx, GEPi(bcx, lhs.val, &[0, abi::FAT_PTR_ADDR]));
let lhs_extra = Load(bcx, GEPi(bcx, lhs.val, &[0, abi::FAT_PTR_EXTRA]));

let rhs_addr = Load(bcx, GEPi(bcx, rhs.val, &[0, abi::FAT_PTR_ADDR]));
let rhs_extra = Load(bcx, GEPi(bcx, rhs.val, &[0, abi::FAT_PTR_EXTRA]));

let val = match op.node {
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.node {
hir::BiLt => (llvm::IntULT, llvm::IntULT),
hir::BiLe => (llvm::IntULE, llvm::IntULT),
hir::BiGt => (llvm::IntUGT, llvm::IntUGT),
hir::BiGe => (llvm::IntUGE, llvm::IntUGT),
_ => unreachable!()
};

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)
}
_ => {
bcx.tcx().sess.span_bug(binop_expr.span, "unexpected binop");
}
};

immediate_rvalue_bcx(bcx, val, binop_ty).to_expr_datumblock()
}

fn trans_scalar_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
binop_expr: &hir::Expr,
binop_ty: Ty<'tcx>,
Expand Down Expand Up @@ -2005,7 +1953,15 @@ fn trans_binary<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
if type_is_fat_ptr(ccx.tcx(), lhs.ty) {
assert!(type_is_fat_ptr(ccx.tcx(), rhs.ty),
"built-in binary operators on fat pointers are homogeneous");
trans_fat_ptr_binop(bcx, expr, binop_ty, op, lhs, rhs)
assert_eq!(binop_ty, bcx.tcx().types.bool);
let val = base::compare_scalar_types(
bcx,
lhs.val,
rhs.val,
lhs.ty,
op.node,
expr.debug_loc());
immediate_rvalue_bcx(bcx, val, binop_ty).to_expr_datumblock()
} else {
assert!(!type_is_fat_ptr(ccx.tcx(), rhs.ty),
"built-in binary operators on fat pointers are homogeneous");
Expand Down
9 changes: 5 additions & 4 deletions src/librustc_trans/trans/mir/analyze.rs
Expand Up @@ -28,10 +28,11 @@ pub fn lvalue_temps<'bcx,'tcx>(bcx: Block<'bcx,'tcx>,
let ty = bcx.monomorphize(&temp_decl.ty);
debug!("temp {:?} has type {:?}", index, ty);
if
ty.is_scalar() ||
ty.is_unique() ||
(ty.is_region_ptr() && !common::type_is_fat_ptr(bcx.tcx(), ty)) ||
ty.is_simd()
(ty.is_scalar() ||
ty.is_unique() ||
ty.is_region_ptr() ||
ty.is_simd())
&& !common::type_is_fat_ptr(bcx.tcx(), ty)
{
// These sorts of types are immediates that we can store
// in an ValueRef without an alloca.
Expand Down
1 change: 0 additions & 1 deletion src/librustc_trans/trans/mir/mod.rs
Expand Up @@ -192,4 +192,3 @@ mod lvalue;
mod rvalue;
mod operand;
mod statement;

51 changes: 48 additions & 3 deletions src/librustc_trans/trans/mir/rvalue.rs
Expand Up @@ -9,7 +9,7 @@
// except according to those terms.

use llvm::ValueRef;
use rustc::middle::ty::Ty;
use rustc::middle::ty::{self, Ty};
use rustc_front::hir;
use rustc_mir::repr as mir;

Expand Down Expand Up @@ -45,6 +45,19 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
bcx
}

mir::Rvalue::Cast(mir::CastKind::Unsize, ref operand, cast_ty) => {
let expr_ty =
bcx.monomorphize(&self.mir.operand_ty(bcx.tcx(), operand));
let cast_ty =
bcx.monomorphize(&cast_ty);
if expr_ty == cast_ty {
debug!("trans_rvalue: trivial unsize at {:?}", expr_ty);
self.trans_operand_into(bcx, lldest, operand);
return bcx;
}
unimplemented!()
}

mir::Rvalue::Cast(..) => {
unimplemented!()
}
Expand Down Expand Up @@ -93,7 +106,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
_ => {
assert!(rvalue_creates_operand(rvalue));
let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue);
build::Store(bcx, temp.llval, lldest);
base::store_ty(bcx, temp.llval, lldest, temp.ty);
bcx
}
}
Expand All @@ -112,6 +125,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
(bcx, operand)
}

mir::Rvalue::Cast(mir::CastKind::Unsize, _, _) => {
unimplemented!()
}

mir::Rvalue::Cast(..) => {
unimplemented!()
}
Expand Down Expand Up @@ -240,7 +257,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
};
(bcx, OperandRef {
llval: llval,
ty: lhs.ty,
ty: type_of_binop(bcx.tcx(), op, lhs.ty, rhs.ty),
})
}

Expand Down Expand Up @@ -311,3 +328,31 @@ pub fn rvalue_creates_operand<'tcx>(rvalue: &mir::Rvalue<'tcx>) -> bool {

// (*) this is only true if the type is suitable
}

/// FIXME(nikomatsakis): I don't think this function should go here
fn type_of_binop<'tcx>(
tcx: &ty::ctxt<'tcx>,
op: mir::BinOp,
lhs_ty: Ty<'tcx>,
rhs_ty: Ty<'tcx>)
-> Ty<'tcx>
{
match op {
mir::BinOp::Add | mir::BinOp::Sub |
mir::BinOp::Mul | mir::BinOp::Div | mir::BinOp::Rem |
mir::BinOp::BitXor | mir::BinOp::BitAnd | mir::BinOp::BitOr => {
// these should be integers or floats of the same size. We
// probably want to dump all ops in some intrinsics framework
// someday.
assert_eq!(lhs_ty, rhs_ty);
lhs_ty
}
mir::BinOp::Shl | mir::BinOp::Shr => {
lhs_ty // lhs_ty can be != rhs_ty
}
mir::BinOp::Eq | mir::BinOp::Lt | mir::BinOp::Le |
mir::BinOp::Ne | mir::BinOp::Ge | mir::BinOp::Gt => {
tcx.types.bool
}
}
}

0 comments on commit 602cf7e

Please sign in to comment.