Skip to content

Commit 34bc99f

Browse files
author
Ariel Ben-Yehuda
committed
implement raw fat pointer ops
1 parent 205c356 commit 34bc99f

File tree

3 files changed

+234
-40
lines changed

3 files changed

+234
-40
lines changed

src/librustc_trans/trans/expr.rs

+93-40
Original file line numberDiff line numberDiff line change
@@ -1682,20 +1682,70 @@ fn trans_addr_of<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
16821682
}
16831683
}
16841684

1685-
// Important to get types for both lhs and rhs, because one might be _|_
1686-
// and the other not.
1687-
fn trans_eager_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
1688-
binop_expr: &hir::Expr,
1689-
binop_ty: Ty<'tcx>,
1690-
op: hir::BinOp,
1691-
lhs_t: Ty<'tcx>,
1692-
lhs: ValueRef,
1693-
rhs_t: Ty<'tcx>,
1694-
rhs: ValueRef)
1695-
-> DatumBlock<'blk, 'tcx, Expr> {
1696-
let _icx = push_ctxt("trans_eager_binop");
1685+
fn trans_fat_ptr_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
1686+
binop_expr: &hir::Expr,
1687+
binop_ty: Ty<'tcx>,
1688+
op: hir::BinOp,
1689+
lhs: Datum<'tcx, Rvalue>,
1690+
rhs: Datum<'tcx, Rvalue>)
1691+
-> DatumBlock<'blk, 'tcx, Expr>
1692+
{
1693+
let debug_loc = binop_expr.debug_loc();
1694+
1695+
let lhs_addr = Load(bcx, GEPi(bcx, lhs.val, &[0, abi::FAT_PTR_ADDR]));
1696+
let lhs_extra = Load(bcx, GEPi(bcx, lhs.val, &[0, abi::FAT_PTR_EXTRA]));
1697+
1698+
let rhs_addr = Load(bcx, GEPi(bcx, rhs.val, &[0, abi::FAT_PTR_ADDR]));
1699+
let rhs_extra = Load(bcx, GEPi(bcx, rhs.val, &[0, abi::FAT_PTR_EXTRA]));
1700+
1701+
let val = match op.node {
1702+
hir::BiEq => {
1703+
let addr_eq = ICmp(bcx, llvm::IntEQ, lhs_addr, rhs_addr, debug_loc);
1704+
let extra_eq = ICmp(bcx, llvm::IntEQ, lhs_extra, rhs_extra, debug_loc);
1705+
And(bcx, addr_eq, extra_eq, debug_loc)
1706+
}
1707+
hir::BiNe => {
1708+
let addr_eq = ICmp(bcx, llvm::IntNE, lhs_addr, rhs_addr, debug_loc);
1709+
let extra_eq = ICmp(bcx, llvm::IntNE, lhs_extra, rhs_extra, debug_loc);
1710+
Or(bcx, addr_eq, extra_eq, debug_loc)
1711+
}
1712+
hir::BiLe | hir::BiLt | hir::BiGe | hir::BiGt => {
1713+
// a OP b ~ a.0 STRICT(OP) b.0 | (a.0 == b.0 && a.1 OP a.1)
1714+
let (op, strict_op) = match op.node {
1715+
hir::BiLt => (llvm::IntULT, llvm::IntULT),
1716+
hir::BiLe => (llvm::IntULE, llvm::IntULT),
1717+
hir::BiGt => (llvm::IntUGT, llvm::IntUGT),
1718+
hir::BiGe => (llvm::IntUGE, llvm::IntUGT),
1719+
_ => unreachable!()
1720+
};
1721+
1722+
let addr_eq = ICmp(bcx, llvm::IntEQ, lhs_addr, rhs_addr, debug_loc);
1723+
let extra_op = ICmp(bcx, op, lhs_extra, rhs_extra, debug_loc);
1724+
let addr_eq_extra_op = And(bcx, addr_eq, extra_op, debug_loc);
1725+
1726+
let addr_strict = ICmp(bcx, strict_op, lhs_addr, rhs_addr, debug_loc);
1727+
Or(bcx, addr_strict, addr_eq_extra_op, debug_loc)
1728+
}
1729+
_ => {
1730+
bcx.tcx().sess.span_bug(binop_expr.span, "unexpected binop");
1731+
}
1732+
};
1733+
1734+
immediate_rvalue_bcx(bcx, val, binop_ty).to_expr_datumblock()
1735+
}
1736+
1737+
fn trans_scalar_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
1738+
binop_expr: &hir::Expr,
1739+
binop_ty: Ty<'tcx>,
1740+
op: hir::BinOp,
1741+
lhs: Datum<'tcx, Rvalue>,
1742+
rhs: Datum<'tcx, Rvalue>)
1743+
-> DatumBlock<'blk, 'tcx, Expr>
1744+
{
1745+
let _icx = push_ctxt("trans_scalar_binop");
16971746

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

17061756
let mut bcx = bcx;
1757+
let lhs = lhs.to_llscalarish(bcx);
1758+
let rhs = rhs.to_llscalarish(bcx);
17071759
let val = match op.node {
17081760
hir::BiAdd => {
17091761
if is_float {
@@ -1745,7 +1797,7 @@ fn trans_eager_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
17451797
op,
17461798
lhs,
17471799
rhs,
1748-
rhs_t);
1800+
lhs_t);
17491801
if is_signed {
17501802
SDiv(bcx, lhs, rhs, binop_debug_loc)
17511803
} else {
@@ -1796,7 +1848,7 @@ fn trans_eager_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
17961848
// Only zero-check integers; fp %0 is NaN
17971849
bcx = base::fail_if_zero_or_overflows(bcx,
17981850
expr_info(binop_expr),
1799-
op, lhs, rhs, rhs_t);
1851+
op, lhs, rhs, lhs_t);
18001852
if is_signed {
18011853
SRem(bcx, lhs, rhs, binop_debug_loc)
18021854
} else {
@@ -1896,23 +1948,26 @@ fn trans_binary<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
18961948
}
18971949
_ => {
18981950
let mut bcx = bcx;
1899-
let lhs_datum = unpack_datum!(bcx, trans(bcx, lhs));
1900-
let rhs_datum = unpack_datum!(bcx, trans(bcx, rhs));
19011951
let binop_ty = expr_ty(bcx, expr);
19021952

1903-
debug!("trans_binary (expr {}): lhs_datum={}",
1904-
expr.id,
1905-
lhs_datum.to_string(ccx));
1906-
let lhs_ty = lhs_datum.ty;
1907-
let lhs = lhs_datum.to_llscalarish(bcx);
1908-
1909-
debug!("trans_binary (expr {}): rhs_datum={}",
1910-
expr.id,
1911-
rhs_datum.to_string(ccx));
1912-
let rhs_ty = rhs_datum.ty;
1913-
let rhs = rhs_datum.to_llscalarish(bcx);
1914-
trans_eager_binop(bcx, expr, binop_ty, op,
1915-
lhs_ty, lhs, rhs_ty, rhs)
1953+
let lhs = unpack_datum!(bcx, trans(bcx, lhs));
1954+
let lhs = unpack_datum!(bcx, lhs.to_rvalue_datum(bcx, "binop_lhs"));
1955+
debug!("trans_binary (expr {}): lhs={}",
1956+
expr.id, lhs.to_string(ccx));
1957+
let rhs = unpack_datum!(bcx, trans(bcx, rhs));
1958+
let rhs = unpack_datum!(bcx, rhs.to_rvalue_datum(bcx, "binop_rhs"));
1959+
debug!("trans_binary (expr {}): rhs={}",
1960+
expr.id, rhs.to_string(ccx));
1961+
1962+
if type_is_fat_ptr(ccx.tcx(), lhs.ty) {
1963+
assert!(type_is_fat_ptr(ccx.tcx(), rhs.ty),
1964+
"built-in binary operators on fat pointers are homogeneous");
1965+
trans_fat_ptr_binop(bcx, expr, binop_ty, op, lhs, rhs)
1966+
} else {
1967+
assert!(!type_is_fat_ptr(ccx.tcx(), rhs.ty),
1968+
"built-in binary operators on fat pointers are homogeneous");
1969+
trans_scalar_binop(bcx, expr, binop_ty, op, lhs, rhs)
1970+
}
19161971
}
19171972
}
19181973
}
@@ -2123,21 +2178,19 @@ fn trans_assign_op<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
21232178
assert!(!bcx.tcx().is_method_call(expr.id));
21242179

21252180
// Evaluate LHS (destination), which should be an lvalue
2126-
let dst_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, dst, "assign_op"));
2127-
assert!(!bcx.fcx.type_needs_drop(dst_datum.ty));
2128-
let dst_ty = dst_datum.ty;
2129-
let dst = load_ty(bcx, dst_datum.val, dst_datum.ty);
2181+
let dst = unpack_datum!(bcx, trans_to_lvalue(bcx, dst, "assign_op"));
2182+
assert!(!bcx.fcx.type_needs_drop(dst.ty));
2183+
let lhs = load_ty(bcx, dst.val, dst.ty);
2184+
let lhs = immediate_rvalue(lhs, dst.ty);
21302185

2131-
// Evaluate RHS
2132-
let rhs_datum = unpack_datum!(bcx, trans(bcx, &*src));
2133-
let rhs_ty = rhs_datum.ty;
2134-
let rhs = rhs_datum.to_llscalarish(bcx);
2186+
// Evaluate RHS - FIXME(#28160) this sucks
2187+
let rhs = unpack_datum!(bcx, trans(bcx, &*src));
2188+
let rhs = unpack_datum!(bcx, rhs.to_rvalue_datum(bcx, "assign_op_rhs"));
21352189

21362190
// Perform computation and store the result
21372191
let result_datum = unpack_datum!(
2138-
bcx, trans_eager_binop(bcx, expr, dst_datum.ty, op,
2139-
dst_ty, dst, rhs_ty, rhs));
2140-
return result_datum.store_to(bcx, dst_datum.val);
2192+
bcx, trans_scalar_binop(bcx, expr, dst.ty, op, lhs, rhs));
2193+
return result_datum.store_to(bcx, dst.val);
21412194
}
21422195

21432196
fn auto_ref<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
fn main() {
12+
let x = &mut 1;
13+
assert_eq!(*x + { *x=2; 1 }, 2);
14+
}

src/test/run-pass/raw-fat-ptr.rs

+127
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// check raw fat pointer ops
12+
13+
use std::mem;
14+
15+
fn assert_inorder<T: PartialEq + PartialOrd>(a: &[T]) {
16+
for i in 0..a.len() {
17+
for j in 0..a.len() {
18+
if i < j {
19+
assert!(a[i] < a[j]);
20+
assert!(a[i] <= a[j]);
21+
assert!(!(a[i] == a[j]));
22+
assert!(a[i] != a[j]);
23+
assert!(!(a[i] >= a[j]));
24+
assert!(!(a[i] > a[j]));
25+
} else if i == j {
26+
assert!(!(a[i] < a[j]));
27+
assert!(a[i] <= a[j]);
28+
assert!(a[i] == a[j]);
29+
assert!(!(a[i] != a[j]));
30+
assert!(a[i] >= a[j]);
31+
assert!(!(a[i] > a[j]));
32+
} else {
33+
assert!(!(a[i] < a[j]));
34+
assert!(!(a[i] <= a[j]));
35+
assert!(!(a[i] == a[j]));
36+
assert!(a[i] != a[j]);
37+
assert!(a[i] >= a[j]);
38+
assert!(a[i] > a[j]);
39+
}
40+
}
41+
}
42+
}
43+
44+
trait Foo { fn foo(&self) -> usize; }
45+
impl<T> Foo for T {
46+
fn foo(&self) -> usize {
47+
mem::size_of::<T>()
48+
}
49+
}
50+
51+
struct S<T:?Sized>(u32, T);
52+
53+
fn main() {
54+
let mut array = [0,1,2,3,4];
55+
let mut array2 = [5,6,7,8,9];
56+
57+
// fat ptr comparison: addr then extra
58+
59+
// check ordering for arrays
60+
let mut ptrs: Vec<*const [u8]> = vec![
61+
&array[0..0], &array[0..1], &array, &array[1..]
62+
];
63+
64+
let array_addr = &array as *const [u8] as *const u8 as usize;
65+
let array2_addr = &array2 as *const [u8] as *const u8 as usize;
66+
if array2_addr < array_addr {
67+
ptrs.insert(0, &array2);
68+
} else {
69+
ptrs.push(&array2);
70+
}
71+
assert_inorder(&ptrs);
72+
73+
// check ordering for mut arrays
74+
let mut ptrs: Vec<*mut [u8]> = vec![
75+
&mut array[0..0], &mut array[0..1], &mut array, &mut array[1..]
76+
];
77+
78+
let array_addr = &mut array as *mut [u8] as *mut u8 as usize;
79+
let array2_addr = &mut array2 as *mut [u8] as *mut u8 as usize;
80+
if array2_addr < array_addr {
81+
ptrs.insert(0, &mut array2);
82+
} else {
83+
ptrs.push(&mut array2);
84+
}
85+
assert_inorder(&ptrs);
86+
87+
let mut u8_ = (0u8, 1u8);
88+
let mut u32_ = (4u32, 5u32);
89+
90+
// check ordering for ptrs
91+
let buf: &mut [*const Foo] = &mut [
92+
&u8_, &u8_.0,
93+
&u32_, &u32_.0,
94+
];
95+
buf.sort_by(|u,v| {
96+
let u : [*const (); 2] = unsafe { mem::transmute(*u) };
97+
let v : [*const (); 2] = unsafe { mem::transmute(*v) };
98+
u.cmp(&v)
99+
});
100+
assert_inorder(buf);
101+
102+
// check ordering for mut ptrs
103+
let buf: &mut [*mut Foo] = &mut [
104+
&mut u8_, &mut u8_.0,
105+
&mut u32_, &mut u32_.0,
106+
];
107+
buf.sort_by(|u,v| {
108+
let u : [*const (); 2] = unsafe { mem::transmute(*u) };
109+
let v : [*const (); 2] = unsafe { mem::transmute(*v) };
110+
u.cmp(&v)
111+
});
112+
assert_inorder(buf);
113+
114+
// check ordering for structs containing arrays
115+
let ss: (S<[u8; 2]>,
116+
S<[u8; 3]>,
117+
S<[u8; 2]>) = (
118+
S(7, [8, 9]),
119+
S(10, [11, 12, 13]),
120+
S(4, [5, 6])
121+
);
122+
assert_inorder(&[
123+
&ss.0 as *const S<[u8]>,
124+
&ss.1 as *const S<[u8]>,
125+
&ss.2 as *const S<[u8]>
126+
]);
127+
}

0 commit comments

Comments
 (0)