Skip to content

Commit

Permalink
Auto merge of #28270 - arielb1:raw-fat-ops, r=nrc
Browse files Browse the repository at this point in the history
r? @nrc 

Fixes #17736
Fixes #18829
Fixes #23888
Fixes #28236
  • Loading branch information
bors committed Sep 6, 2015
2 parents 3dd1a48 + 34bc99f commit f6aac80
Show file tree
Hide file tree
Showing 3 changed files with 234 additions and 40 deletions.
133 changes: 93 additions & 40 deletions src/librustc_trans/trans/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1682,20 +1682,70 @@ fn trans_addr_of<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
}
}

// Important to get types for both lhs and rhs, because one might be _|_
// and the other not.
fn trans_eager_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
binop_expr: &hir::Expr,
binop_ty: Ty<'tcx>,
op: hir::BinOp,
lhs_t: Ty<'tcx>,
lhs: ValueRef,
rhs_t: Ty<'tcx>,
rhs: ValueRef)
-> DatumBlock<'blk, 'tcx, Expr> {
let _icx = push_ctxt("trans_eager_binop");
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>,
op: hir::BinOp,
lhs: Datum<'tcx, Rvalue>,
rhs: Datum<'tcx, Rvalue>)
-> DatumBlock<'blk, 'tcx, Expr>
{
let _icx = push_ctxt("trans_scalar_binop");

let tcx = bcx.tcx();
let lhs_t = lhs.ty;
assert!(!lhs_t.is_simd());
let is_float = lhs_t.is_fp();
let is_signed = lhs_t.is_signed();
Expand All @@ -1704,6 +1754,8 @@ fn trans_eager_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
let binop_debug_loc = binop_expr.debug_loc();

let mut bcx = bcx;
let lhs = lhs.to_llscalarish(bcx);
let rhs = rhs.to_llscalarish(bcx);
let val = match op.node {
hir::BiAdd => {
if is_float {
Expand Down Expand Up @@ -1745,7 +1797,7 @@ fn trans_eager_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
op,
lhs,
rhs,
rhs_t);
lhs_t);
if is_signed {
SDiv(bcx, lhs, rhs, binop_debug_loc)
} else {
Expand Down Expand Up @@ -1796,7 +1848,7 @@ fn trans_eager_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
// Only zero-check integers; fp %0 is NaN
bcx = base::fail_if_zero_or_overflows(bcx,
expr_info(binop_expr),
op, lhs, rhs, rhs_t);
op, lhs, rhs, lhs_t);
if is_signed {
SRem(bcx, lhs, rhs, binop_debug_loc)
} else {
Expand Down Expand Up @@ -1896,23 +1948,26 @@ fn trans_binary<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
}
_ => {
let mut bcx = bcx;
let lhs_datum = unpack_datum!(bcx, trans(bcx, lhs));
let rhs_datum = unpack_datum!(bcx, trans(bcx, rhs));
let binop_ty = expr_ty(bcx, expr);

debug!("trans_binary (expr {}): lhs_datum={}",
expr.id,
lhs_datum.to_string(ccx));
let lhs_ty = lhs_datum.ty;
let lhs = lhs_datum.to_llscalarish(bcx);

debug!("trans_binary (expr {}): rhs_datum={}",
expr.id,
rhs_datum.to_string(ccx));
let rhs_ty = rhs_datum.ty;
let rhs = rhs_datum.to_llscalarish(bcx);
trans_eager_binop(bcx, expr, binop_ty, op,
lhs_ty, lhs, rhs_ty, rhs)
let lhs = unpack_datum!(bcx, trans(bcx, lhs));
let lhs = unpack_datum!(bcx, lhs.to_rvalue_datum(bcx, "binop_lhs"));
debug!("trans_binary (expr {}): lhs={}",
expr.id, lhs.to_string(ccx));
let rhs = unpack_datum!(bcx, trans(bcx, rhs));
let rhs = unpack_datum!(bcx, rhs.to_rvalue_datum(bcx, "binop_rhs"));
debug!("trans_binary (expr {}): rhs={}",
expr.id, rhs.to_string(ccx));

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)
} else {
assert!(!type_is_fat_ptr(ccx.tcx(), rhs.ty),
"built-in binary operators on fat pointers are homogeneous");
trans_scalar_binop(bcx, expr, binop_ty, op, lhs, rhs)
}
}
}
}
Expand Down Expand Up @@ -2123,21 +2178,19 @@ fn trans_assign_op<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
assert!(!bcx.tcx().is_method_call(expr.id));

// Evaluate LHS (destination), which should be an lvalue
let dst_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, dst, "assign_op"));
assert!(!bcx.fcx.type_needs_drop(dst_datum.ty));
let dst_ty = dst_datum.ty;
let dst = load_ty(bcx, dst_datum.val, dst_datum.ty);
let dst = unpack_datum!(bcx, trans_to_lvalue(bcx, dst, "assign_op"));
assert!(!bcx.fcx.type_needs_drop(dst.ty));
let lhs = load_ty(bcx, dst.val, dst.ty);
let lhs = immediate_rvalue(lhs, dst.ty);

// Evaluate RHS
let rhs_datum = unpack_datum!(bcx, trans(bcx, &*src));
let rhs_ty = rhs_datum.ty;
let rhs = rhs_datum.to_llscalarish(bcx);
// Evaluate RHS - FIXME(#28160) this sucks
let rhs = unpack_datum!(bcx, trans(bcx, &*src));
let rhs = unpack_datum!(bcx, rhs.to_rvalue_datum(bcx, "assign_op_rhs"));

// Perform computation and store the result
let result_datum = unpack_datum!(
bcx, trans_eager_binop(bcx, expr, dst_datum.ty, op,
dst_ty, dst, rhs_ty, rhs));
return result_datum.store_to(bcx, dst_datum.val);
bcx, trans_scalar_binop(bcx, expr, dst.ty, op, lhs, rhs));
return result_datum.store_to(bcx, dst.val);
}

fn auto_ref<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
Expand Down
14 changes: 14 additions & 0 deletions src/test/run-pass/issue-27054-primitive-binary-ops.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// 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.

fn main() {
let x = &mut 1;
assert_eq!(*x + { *x=2; 1 }, 2);
}
127 changes: 127 additions & 0 deletions src/test/run-pass/raw-fat-ptr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
// 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.

// check raw fat pointer ops

use std::mem;

fn assert_inorder<T: PartialEq + PartialOrd>(a: &[T]) {
for i in 0..a.len() {
for j in 0..a.len() {
if i < j {
assert!(a[i] < a[j]);
assert!(a[i] <= a[j]);
assert!(!(a[i] == a[j]));
assert!(a[i] != a[j]);
assert!(!(a[i] >= a[j]));
assert!(!(a[i] > a[j]));
} else if i == j {
assert!(!(a[i] < a[j]));
assert!(a[i] <= a[j]);
assert!(a[i] == a[j]);
assert!(!(a[i] != a[j]));
assert!(a[i] >= a[j]);
assert!(!(a[i] > a[j]));
} else {
assert!(!(a[i] < a[j]));
assert!(!(a[i] <= a[j]));
assert!(!(a[i] == a[j]));
assert!(a[i] != a[j]);
assert!(a[i] >= a[j]);
assert!(a[i] > a[j]);
}
}
}
}

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 mut array = [0,1,2,3,4];
let mut 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);

// check ordering for mut arrays
let mut ptrs: Vec<*mut [u8]> = vec![
&mut array[0..0], &mut array[0..1], &mut array, &mut array[1..]
];

let array_addr = &mut array as *mut [u8] as *mut u8 as usize;
let array2_addr = &mut array2 as *mut [u8] as *mut u8 as usize;
if array2_addr < array_addr {
ptrs.insert(0, &mut array2);
} else {
ptrs.push(&mut array2);
}
assert_inorder(&ptrs);

let mut u8_ = (0u8, 1u8);
let mut 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);

// check ordering for mut ptrs
let buf: &mut [*mut Foo] = &mut [
&mut u8_, &mut u8_.0,
&mut u32_, &mut 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);

// 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]>
]);
}

0 comments on commit f6aac80

Please sign in to comment.