提交 602cf7ec 编写于 作者: A Ariel Ben-Yehuda

MIR: implement fat raw pointer comparisons

The implementation itself only requires changes to trans, but
a few additional bugs concerning the handling of fat pointers
had to be fixed.
上级 3beb1598
......@@ -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)
}
......@@ -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));
......
......@@ -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>,
......@@ -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");
......
......@@ -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.
......
......@@ -192,4 +192,3 @@ fn arg_value_refs<'bcx, 'tcx>(bcx: Block<'bcx, 'tcx>,
mod rvalue;
mod operand;
mod statement;
......@@ -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;
......@@ -45,6 +45,19 @@ pub fn trans_rvalue(&mut self,
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!()
}
......@@ -93,7 +106,7 @@ pub fn trans_rvalue(&mut self,
_ => {
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
}
}
......@@ -112,6 +125,10 @@ pub fn trans_rvalue_operand(&mut self,
(bcx, operand)
}
mir::Rvalue::Cast(mir::CastKind::Unsize, _, _) => {
unimplemented!()
}
mir::Rvalue::Cast(..) => {
unimplemented!()
}
......@@ -240,7 +257,7 @@ pub fn trans_rvalue_operand(&mut self,
};
(bcx, OperandRef {
llval: llval,
ty: lhs.ty,
ty: type_of_binop(bcx.tcx(), op, lhs.ty, rhs.ty),
})
}
......@@ -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
}
}
}
// Copyright 2015 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.
#![feature(rustc_attrs)]
// check raw fat pointer ops in mir
// FIXME: please improve this when we get monomorphization support
use std::mem;
#[derive(Debug, PartialEq, Eq)]
struct ComparisonResults {
lt: bool,
le: bool,
gt: bool,
ge: bool,
eq: bool,
ne: bool
}
const LT: ComparisonResults = ComparisonResults {
lt: true,
le: true,
gt: false,
ge: false,
eq: false,
ne: true
};
const EQ: ComparisonResults = ComparisonResults {
lt: false,
le: true,
gt: false,
ge: true,
eq: true,
ne: false
};
const GT: ComparisonResults = ComparisonResults {
lt: false,
le: false,
gt: true,
ge: true,
eq: false,
ne: true
};
#[rustc_mir]
fn compare_su8(a: *const S<[u8]>, b: *const S<[u8]>) -> ComparisonResults {
ComparisonResults {
lt: a < b,
le: a <= b,
gt: a > b,
ge: a >= b,
eq: a == b,
ne: a != b
}
}
#[rustc_mir]
fn compare_au8(a: *const [u8], b: *const [u8]) -> ComparisonResults {
ComparisonResults {
lt: a < b,
le: a <= b,
gt: a > b,
ge: a >= b,
eq: a == b,
ne: a != b
}
}
#[rustc_mir(graphviz="comparefoo.gv")]
fn compare_foo<'a>(a: *const (Foo+'a), b: *const (Foo+'a)) -> ComparisonResults {
ComparisonResults {
lt: a < b,
le: a <= b,
gt: a > b,
ge: a >= b,
eq: a == b,
ne: a != b
}
}
#[rustc_mir(graphviz="simpleeq.gv")]
fn simple_eq<'a>(a: *const (Foo+'a), b: *const (Foo+'a)) -> bool {
let result = a == b;
result
}
fn assert_inorder<T: Copy>(a: &[T],
compare: fn(T, T) -> ComparisonResults) {
for i in 0..a.len() {
for j in 0..a.len() {
let cres = compare(a[i], a[j]);
if i < j {
assert_eq!(cres, LT);
} else if i == j {
assert_eq!(cres, EQ);
} else {
assert_eq!(cres, GT);
}
}
}
}
trait Foo { fn foo(&self) -> usize; }
impl<T> Foo for T {
fn foo(&self) -> usize {
mem::size_of::<T>()
}
}
struct S<T:?Sized>(u32, T);
fn main() {
let array = [0,1,2,3,4];
let array2 = [5,6,7,8,9];
// fat ptr comparison: addr then extra
// check ordering for arrays
let mut ptrs: Vec<*const [u8]> = vec![
&array[0..0], &array[0..1], &array, &array[1..]
];
let array_addr = &array as *const [u8] as *const u8 as usize;
let array2_addr = &array2 as *const [u8] as *const u8 as usize;
if array2_addr < array_addr {
ptrs.insert(0, &array2);
} else {
ptrs.push(&array2);
}
assert_inorder(&ptrs, compare_au8);
let u8_ = (0u8, 1u8);
let u32_ = (4u32, 5u32);
// check ordering for ptrs
let buf: &mut [*const Foo] = &mut [
&u8_, &u8_.0,
&u32_, &u32_.0,
];
buf.sort_by(|u,v| {
let u : [*const (); 2] = unsafe { mem::transmute(*u) };
let v : [*const (); 2] = unsafe { mem::transmute(*v) };
u.cmp(&v)
});
assert_inorder(buf, compare_foo);
// check ordering for structs containing arrays
let ss: (S<[u8; 2]>,
S<[u8; 3]>,
S<[u8; 2]>) = (
S(7, [8, 9]),
S(10, [11, 12, 13]),
S(4, [5, 6])
);
assert_inorder(&[
&ss.0 as *const S<[u8]>,
&ss.1 as *const S<[u8]>,
&ss.2 as *const S<[u8]>
], compare_su8);
assert!(simple_eq(&0u8 as *const _, &0u8 as *const _));
assert!(!simple_eq(&0u8 as *const _, &1u8 as *const _));
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册