Skip to content

Commit 60ffbeb

Browse files
committed
auto merge of #11973 : dotdash/rust/u64_to_bytes, r=huonw
LLVM fails to properly optimize the shifts used to convert the source value to the right endianess. The resulting assembly copies the value to the stack one byte at a time even when there's no conversion required (e.g. u64_to_le_bytes on a little endian machine). Instead of doing the conversion ourselves using shifts, we can use the existing intrinsics to perform the endianess conversion and then transmute the value to get a fixed vector of its bytes. Before: ```` test be_i8 ... bench: 21442 ns/iter (+/- 70) test be_i16 ... bench: 21447 ns/iter (+/- 45) test be_i32 ... bench: 23832 ns/iter (+/- 63) test be_i64 ... bench: 26887 ns/iter (+/- 267) test le_i8 ... bench: 21442 ns/iter (+/- 56) test le_i16 ... bench: 21448 ns/iter (+/- 36) test le_i32 ... bench: 23825 ns/iter (+/- 153) test le_i64 ... bench: 26271 ns/iter (+/- 138) ```` After: ```` test be_i8 ... bench: 21438 ns/iter (+/- 10) test be_i16 ... bench: 21441 ns/iter (+/- 15) test be_i32 ... bench: 19057 ns/iter (+/- 6) test be_i64 ... bench: 21439 ns/iter (+/- 34) test le_i8 ... bench: 21438 ns/iter (+/- 19) test le_i16 ... bench: 21439 ns/iter (+/- 8) test le_i32 ... bench: 21439 ns/iter (+/- 19) test le_i64 ... bench: 21438 ns/iter (+/- 22) ````
2 parents df044ea + 5afc63a commit 60ffbeb

File tree

1 file changed

+14
-28
lines changed

1 file changed

+14
-28
lines changed

src/libstd/io/extensions.rs

+14-28
Original file line numberDiff line numberDiff line change
@@ -51,23 +51,16 @@ impl<'r, R: Reader> Iterator<u8> for Bytes<'r, R> {
5151
}
5252

5353
pub fn u64_to_le_bytes<T>(n: u64, size: uint, f: |v: &[u8]| -> T) -> T {
54+
use unstable::intrinsics::{to_le16, to_le32, to_le64};
55+
use cast::transmute;
56+
57+
// LLVM fails to properly optimize this when using shifts instead of the to_le* intrinsics
5458
assert!(size <= 8u);
5559
match size {
5660
1u => f(&[n as u8]),
57-
2u => f(&[n as u8,
58-
(n >> 8) as u8]),
59-
4u => f(&[n as u8,
60-
(n >> 8) as u8,
61-
(n >> 16) as u8,
62-
(n >> 24) as u8]),
63-
8u => f(&[n as u8,
64-
(n >> 8) as u8,
65-
(n >> 16) as u8,
66-
(n >> 24) as u8,
67-
(n >> 32) as u8,
68-
(n >> 40) as u8,
69-
(n >> 48) as u8,
70-
(n >> 56) as u8]),
61+
2u => f(unsafe { transmute::<i16, [u8, ..2]>(to_le16(n as i16)) }),
62+
4u => f(unsafe { transmute::<i32, [u8, ..4]>(to_le32(n as i32)) }),
63+
8u => f(unsafe { transmute::<i64, [u8, ..8]>(to_le64(n as i64)) }),
7164
_ => {
7265

7366
let mut bytes: ~[u8] = ~[];
@@ -84,23 +77,16 @@ pub fn u64_to_le_bytes<T>(n: u64, size: uint, f: |v: &[u8]| -> T) -> T {
8477
}
8578

8679
pub fn u64_to_be_bytes<T>(n: u64, size: uint, f: |v: &[u8]| -> T) -> T {
80+
use unstable::intrinsics::{to_be16, to_be32, to_be64};
81+
use cast::transmute;
82+
83+
// LLVM fails to properly optimize this when using shifts instead of the to_be* intrinsics
8784
assert!(size <= 8u);
8885
match size {
8986
1u => f(&[n as u8]),
90-
2u => f(&[(n >> 8) as u8,
91-
n as u8]),
92-
4u => f(&[(n >> 24) as u8,
93-
(n >> 16) as u8,
94-
(n >> 8) as u8,
95-
n as u8]),
96-
8u => f(&[(n >> 56) as u8,
97-
(n >> 48) as u8,
98-
(n >> 40) as u8,
99-
(n >> 32) as u8,
100-
(n >> 24) as u8,
101-
(n >> 16) as u8,
102-
(n >> 8) as u8,
103-
n as u8]),
87+
2u => f(unsafe { transmute::<i16, [u8, ..2]>(to_be16(n as i16)) }),
88+
4u => f(unsafe { transmute::<i32, [u8, ..4]>(to_be32(n as i32)) }),
89+
8u => f(unsafe { transmute::<i64, [u8, ..8]>(to_be64(n as i64)) }),
10490
_ => {
10591
let mut bytes: ~[u8] = ~[];
10692
let mut i = size;

0 commit comments

Comments
 (0)