auto merge of #16191 : DaGenix/rust/fix-aligned-access, r=alexcrichton

When I originally wrote the read_u32v_be() and write_u32_be() functions, I didn't consider memory alignment requirements of various architectures. Unfortunately, the current implementations may result in unaligned reads and writes. This doesn't impact x86 / x86_64, but it can cause a compiler crash on ARM. This pull requests rewrites those functions to make sure that all memory access is always correctly aligned.

This fix is a little bit academic - due to the way that LLVM aligns the structures that are passed as arguments to these functions, I believe that the end result is that all memory access happens to be aligned anyway. However, there is nothing in that code that actually enforces that, at least not explicitly. The new implementations are definitely slower than the existing ones. However, I don't believe that these functions are all that significant when looking at the overall performance of the compiler. I think getting rid of some unsafe code and removing a potential portability landmine justifies a very slight decrease in raw performance.
This commit is contained in:
bors 2014-08-03 03:06:12 +00:00
commit 46d1ee72ac

View File

@ -22,26 +22,28 @@ use serialize::hex::ToHex;
/// Write a u32 into a vector, which must be 4 bytes long. The value is written in big-endian
/// format.
fn write_u32_be(dst: &mut[u8], input: u32) {
use std::mem::to_be32;
assert!(dst.len() == 4);
unsafe {
let x = dst.unsafe_mut_ref(0) as *mut _ as *mut u32;
*x = to_be32(input);
}
dst[0] = (input >> 24) as u8;
dst[1] = (input >> 16) as u8;
dst[2] = (input >> 8) as u8;
dst[3] = input as u8;
}
/// Read the value of a vector of bytes as a u32 value in big-endian format.
fn read_u32_be(input: &[u8]) -> u32 {
return
(input[0] as u32) << 24 |
(input[1] as u32) << 16 |
(input[2] as u32) << 8 |
(input[3] as u32);
}
/// Read a vector of bytes into a vector of u32s. The values are read in big-endian format.
fn read_u32v_be(dst: &mut[u32], input: &[u8]) {
use std::mem::to_be32;
assert!(dst.len() * 4 == input.len());
unsafe {
let mut x = dst.unsafe_mut_ref(0) as *mut _ as *mut u32;
let mut y = input.unsafe_ref(0) as *const _ as *const u32;
for _ in range(0, dst.len()) {
*x = to_be32(*y);
x = x.offset(1);
y = y.offset(1);
}
let mut pos = 0u;
for chunk in input.chunks(4) {
dst[pos] = read_u32_be(chunk);
pos += 1;
}
}