Skip to content

Commit

Permalink
Use the unsigned integer types for bitwise intrinsics.
Browse files Browse the repository at this point in the history
Exposing ctpop, ctlz, cttz and bswap as taking signed i8/i16/... is just
exposing the internal LLVM names pointlessly (LLVM doesn't have "signed
integers" or "unsigned integers", it just has sized integer types
with (un)signed *operations*).

These operations are semantically working with raw bytes, which the
unsigned types model better.
  • Loading branch information
huonw committed Apr 15, 2014
1 parent 168b2d1 commit c4a9d8a
Show file tree
Hide file tree
Showing 15 changed files with 238 additions and 219 deletions.
4 changes: 2 additions & 2 deletions src/libnative/io/net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ use super::{IoResult, retry, keep_going};
#[cfg(unix)] pub type sock_t = super::file::fd_t;

pub fn htons(u: u16) -> u16 {
mem::to_be16(u as i16) as u16
mem::to_be16(u)
}
pub fn ntohs(u: u16) -> u16 {
mem::from_be16(u as i16) as u16
mem::from_be16(u)
}

enum InAddr {
Expand Down
30 changes: 15 additions & 15 deletions src/librustc/middle/typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4143,21 +4143,21 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) {
"nearbyintf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
"roundf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
"roundf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
"ctpop8" => (0, vec!( ty::mk_i8() ), ty::mk_i8()),
"ctpop16" => (0, vec!( ty::mk_i16() ), ty::mk_i16()),
"ctpop32" => (0, vec!( ty::mk_i32() ), ty::mk_i32()),
"ctpop64" => (0, vec!( ty::mk_i64() ), ty::mk_i64()),
"ctlz8" => (0, vec!( ty::mk_i8() ), ty::mk_i8()),
"ctlz16" => (0, vec!( ty::mk_i16() ), ty::mk_i16()),
"ctlz32" => (0, vec!( ty::mk_i32() ), ty::mk_i32()),
"ctlz64" => (0, vec!( ty::mk_i64() ), ty::mk_i64()),
"cttz8" => (0, vec!( ty::mk_i8() ), ty::mk_i8()),
"cttz16" => (0, vec!( ty::mk_i16() ), ty::mk_i16()),
"cttz32" => (0, vec!( ty::mk_i32() ), ty::mk_i32()),
"cttz64" => (0, vec!( ty::mk_i64() ), ty::mk_i64()),
"bswap16" => (0, vec!( ty::mk_i16() ), ty::mk_i16()),
"bswap32" => (0, vec!( ty::mk_i32() ), ty::mk_i32()),
"bswap64" => (0, vec!( ty::mk_i64() ), ty::mk_i64()),
"ctpop8" => (0, vec!( ty::mk_u8() ), ty::mk_u8()),
"ctpop16" => (0, vec!( ty::mk_u16() ), ty::mk_u16()),
"ctpop32" => (0, vec!( ty::mk_u32() ), ty::mk_u32()),
"ctpop64" => (0, vec!( ty::mk_u64() ), ty::mk_u64()),
"ctlz8" => (0, vec!( ty::mk_u8() ), ty::mk_u8()),
"ctlz16" => (0, vec!( ty::mk_u16() ), ty::mk_u16()),
"ctlz32" => (0, vec!( ty::mk_u32() ), ty::mk_u32()),
"ctlz64" => (0, vec!( ty::mk_u64() ), ty::mk_u64()),
"cttz8" => (0, vec!( ty::mk_u8() ), ty::mk_u8()),
"cttz16" => (0, vec!( ty::mk_u16() ), ty::mk_u16()),
"cttz32" => (0, vec!( ty::mk_u32() ), ty::mk_u32()),
"cttz64" => (0, vec!( ty::mk_u64() ), ty::mk_u64()),
"bswap16" => (0, vec!( ty::mk_u16() ), ty::mk_u16()),
"bswap32" => (0, vec!( ty::mk_u32() ), ty::mk_u32()),
"bswap64" => (0, vec!( ty::mk_u64() ), ty::mk_u64()),

"volatile_load" =>
(1, vec!( ty::mk_imm_ptr(tcx, param(ccx, 0)) ), param(ccx, 0)),
Expand Down
10 changes: 4 additions & 6 deletions src/librustc/util/sha2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,21 @@ 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::cast::transmute;
use std::mem::to_be32;
assert!(dst.len() == 4);
unsafe {
let x: *mut i32 = transmute(dst.unsafe_mut_ref(0));
*x = to_be32(input as i32);
let x = dst.unsafe_mut_ref(0) as *mut _ as *mut u32;
*x = to_be32(input);
}
}

/// 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::cast::transmute;
use std::mem::to_be32;
assert!(dst.len() * 4 == input.len());
unsafe {
let mut x: *mut i32 = transmute(dst.unsafe_mut_ref(0));
let mut y: *i32 = transmute(input.unsafe_ref(0));
let mut x = dst.unsafe_mut_ref(0) as *mut _ as *mut u32;
let mut y = input.unsafe_ref(0) as *_ as *u32;
for _ in range(0, dst.len()) {
*x = to_be32(*y);
x = x.offset(1);
Expand Down
4 changes: 2 additions & 2 deletions src/librustuv/net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ use uvll;
/// Generic functions related to dealing with sockaddr things
////////////////////////////////////////////////////////////////////////////////

pub fn htons(u: u16) -> u16 { mem::to_be16(u as i16) as u16 }
pub fn ntohs(u: u16) -> u16 { mem::from_be16(u as i16) as u16 }
pub fn htons(u: u16) -> u16 { mem::to_be16(u) }
pub fn ntohs(u: u16) -> u16 { mem::from_be16(u) }

pub fn sockaddr_to_addr(storage: &libc::sockaddr_storage,
len: uint) -> ip::SocketAddr {
Expand Down
4 changes: 2 additions & 2 deletions src/libserialize/ebml.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,8 @@ pub mod reader {
];

unsafe {
let ptr = data.as_ptr().offset(start as int) as *i32;
let val = from_be32(*ptr) as u32;
let ptr = data.as_ptr().offset(start as int) as *u32;
let val = from_be32(*ptr);

let i = (val >> 28u) as uint;
let (shift, mask) = SHIFT_MASK_TABLE[i];
Expand Down
60 changes: 42 additions & 18 deletions src/libstd/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -394,26 +394,50 @@ extern "rust-intrinsic" {

pub fn roundf32(x: f32) -> f32;
pub fn roundf64(x: f64) -> f64;
}
#[cfg(not(stage0))]
extern "rust-intrinsic" {
pub fn ctpop8(x: u8) -> u8;
pub fn ctpop16(x: u16) -> u16;
pub fn ctpop32(x: u32) -> u32;
pub fn ctpop64(x: u64) -> u64;

pub fn ctlz8(x: u8) -> u8;
pub fn ctlz16(x: u16) -> u16;
pub fn ctlz32(x: u32) -> u32;
pub fn ctlz64(x: u64) -> u64;

pub fn cttz8(x: u8) -> u8;
pub fn cttz16(x: u16) -> u16;
pub fn cttz32(x: u32) -> u32;
pub fn cttz64(x: u64) -> u64;

pub fn bswap16(x: u16) -> u16;
pub fn bswap32(x: u32) -> u32;
pub fn bswap64(x: u64) -> u64;
}

pub fn ctpop8(x: i8) -> i8;
pub fn ctpop16(x: i16) -> i16;
pub fn ctpop32(x: i32) -> i32;
pub fn ctpop64(x: i64) -> i64;

pub fn ctlz8(x: i8) -> i8;
pub fn ctlz16(x: i16) -> i16;
pub fn ctlz32(x: i32) -> i32;
pub fn ctlz64(x: i64) -> i64;

pub fn cttz8(x: i8) -> i8;
pub fn cttz16(x: i16) -> i16;
pub fn cttz32(x: i32) -> i32;
pub fn cttz64(x: i64) -> i64;

pub fn bswap16(x: i16) -> i16;
pub fn bswap32(x: i32) -> i32;
pub fn bswap64(x: i64) -> i64;
// NOTE: remove this after a snap, and merge the extern block above
macro_rules! stage0_hack {
($( $u_ty:ty, $i_ty:ty => $($name:ident),*);*) => {
$(
$(
#[cfg(stage0)]
pub unsafe fn $name(x: $u_ty) -> $u_ty {
extern "rust-intrinsic" { fn $name(x: $i_ty) -> $i_ty; }
$name(x as $i_ty) as $u_ty
}
)*)*
}
}
stage0_hack! {
u8, i8 => ctpop8, ctlz8, cttz8;
u16, i16 => ctpop16, ctlz16, cttz16, bswap16;
u32, i32 => ctpop32, ctlz32, cttz32, bswap32;
u64, i64 => ctpop64, ctlz64, cttz64, bswap64
}

extern "rust-intrinsic" {
pub fn i8_add_with_overflow(x: i8, y: i8) -> (i8, bool);
pub fn i16_add_with_overflow(x: i16, y: i16) -> (i16, bool);
pub fn i32_add_with_overflow(x: i32, y: i32) -> (i32, bool);
Expand Down
14 changes: 7 additions & 7 deletions src/libstd/io/extensions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,9 @@ pub fn u64_to_le_bytes<T>(n: u64, size: uint, f: |v: &[u8]| -> T) -> T {
assert!(size <= 8u);
match size {
1u => f(&[n as u8]),
2u => f(unsafe { transmute::<i16, [u8, ..2]>(to_le16(n as i16)) }),
4u => f(unsafe { transmute::<i32, [u8, ..4]>(to_le32(n as i32)) }),
8u => f(unsafe { transmute::<i64, [u8, ..8]>(to_le64(n as i64)) }),
2u => f(unsafe { transmute::<_, [u8, ..2]>(to_le16(n as u16)) }),
4u => f(unsafe { transmute::<_, [u8, ..4]>(to_le32(n as u32)) }),
8u => f(unsafe { transmute::<_, [u8, ..8]>(to_le64(n)) }),
_ => {

let mut bytes = vec!();
Expand Down Expand Up @@ -123,9 +123,9 @@ pub fn u64_to_be_bytes<T>(n: u64, size: uint, f: |v: &[u8]| -> T) -> T {
assert!(size <= 8u);
match size {
1u => f(&[n as u8]),
2u => f(unsafe { transmute::<i16, [u8, ..2]>(to_be16(n as i16)) }),
4u => f(unsafe { transmute::<i32, [u8, ..4]>(to_be32(n as i32)) }),
8u => f(unsafe { transmute::<i64, [u8, ..8]>(to_be64(n as i64)) }),
2u => f(unsafe { transmute::<_, [u8, ..2]>(to_be16(n as u16)) }),
4u => f(unsafe { transmute::<_, [u8, ..4]>(to_be32(n as u32)) }),
8u => f(unsafe { transmute::<_, [u8, ..8]>(to_be64(n)) }),
_ => {
let mut bytes = vec!();
let mut i = size;
Expand Down Expand Up @@ -166,7 +166,7 @@ pub fn u64_from_be_bytes(data: &[u8], start: uint, size: uint) -> u64 {
let ptr = data.as_ptr().offset(start as int);
let out = buf.as_mut_ptr();
copy_nonoverlapping_memory(out.offset((8 - size) as int), ptr, size);
from_be64(*(out as *i64)) as u64
from_be64(*(out as *u64))
}
}

Expand Down
96 changes: 48 additions & 48 deletions src/libstd/mem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,128 +99,128 @@ pub unsafe fn move_val_init<T>(dst: &mut T, src: T) {
intrinsics::move_val_init(dst, src)
}

/// Convert an i16 to little endian from the target's endianness.
/// Convert an u16 to little endian from the target's endianness.
///
/// On little endian, this is a no-op. On big endian, the bytes are swapped.
#[cfg(target_endian = "little")] #[inline] pub fn to_le16(x: i16) -> i16 { x }
#[cfg(target_endian = "little")] #[inline] pub fn to_le16(x: u16) -> u16 { x }

/// Convert an i16 to little endian from the target's endianness.
/// Convert an u16 to little endian from the target's endianness.
///
/// On little endian, this is a no-op. On big endian, the bytes are swapped.
#[cfg(target_endian = "big")] #[inline] pub fn to_le16(x: i16) -> i16 { unsafe { bswap16(x) } }
#[cfg(target_endian = "big")] #[inline] pub fn to_le16(x: u16) -> u16 { unsafe { bswap16(x) } }

/// Convert an i32 to little endian from the target's endianness.
/// Convert an u32 to little endian from the target's endianness.
///
/// On little endian, this is a no-op. On big endian, the bytes are swapped.
#[cfg(target_endian = "little")] #[inline] pub fn to_le32(x: i32) -> i32 { x }
#[cfg(target_endian = "little")] #[inline] pub fn to_le32(x: u32) -> u32 { x }

/// Convert an i32 to little endian from the target's endianness.
/// Convert an u32 to little endian from the target's endianness.
///
/// On little endian, this is a no-op. On big endian, the bytes are swapped.
#[cfg(target_endian = "big")] #[inline] pub fn to_le32(x: i32) -> i32 { unsafe { bswap32(x) } }
#[cfg(target_endian = "big")] #[inline] pub fn to_le32(x: u32) -> u32 { unsafe { bswap32(x) } }

/// Convert an i64 to little endian from the target's endianness.
/// Convert an u64 to little endian from the target's endianness.
///
/// On little endian, this is a no-op. On big endian, the bytes are swapped.
#[cfg(target_endian = "little")] #[inline] pub fn to_le64(x: i64) -> i64 { x }
#[cfg(target_endian = "little")] #[inline] pub fn to_le64(x: u64) -> u64 { x }

/// Convert an i64 to little endian from the target's endianness.
/// Convert an u64 to little endian from the target's endianness.
///
/// On little endian, this is a no-op. On big endian, the bytes are swapped.
#[cfg(target_endian = "big")] #[inline] pub fn to_le64(x: i64) -> i64 { unsafe { bswap64(x) } }
#[cfg(target_endian = "big")] #[inline] pub fn to_le64(x: u64) -> u64 { unsafe { bswap64(x) } }


/// Convert an i16 to big endian from the target's endianness.
/// Convert an u16 to big endian from the target's endianness.
///
/// On big endian, this is a no-op. On little endian, the bytes are swapped.
#[cfg(target_endian = "little")] #[inline] pub fn to_be16(x: i16) -> i16 { unsafe { bswap16(x) } }
#[cfg(target_endian = "little")] #[inline] pub fn to_be16(x: u16) -> u16 { unsafe { bswap16(x) } }

/// Convert an i16 to big endian from the target's endianness.
/// Convert an u16 to big endian from the target's endianness.
///
/// On big endian, this is a no-op. On little endian, the bytes are swapped.
#[cfg(target_endian = "big")] #[inline] pub fn to_be16(x: i16) -> i16 { x }
#[cfg(target_endian = "big")] #[inline] pub fn to_be16(x: u16) -> u16 { x }

/// Convert an i32 to big endian from the target's endianness.
/// Convert an u32 to big endian from the target's endianness.
///
/// On big endian, this is a no-op. On little endian, the bytes are swapped.
#[cfg(target_endian = "little")] #[inline] pub fn to_be32(x: i32) -> i32 { unsafe { bswap32(x) } }
#[cfg(target_endian = "little")] #[inline] pub fn to_be32(x: u32) -> u32 { unsafe { bswap32(x) } }

/// Convert an i32 to big endian from the target's endianness.
/// Convert an u32 to big endian from the target's endianness.
///
/// On big endian, this is a no-op. On little endian, the bytes are swapped.
#[cfg(target_endian = "big")] #[inline] pub fn to_be32(x: i32) -> i32 { x }
#[cfg(target_endian = "big")] #[inline] pub fn to_be32(x: u32) -> u32 { x }

/// Convert an i64 to big endian from the target's endianness.
/// Convert an u64 to big endian from the target's endianness.
///
/// On big endian, this is a no-op. On little endian, the bytes are swapped.
#[cfg(target_endian = "little")] #[inline] pub fn to_be64(x: i64) -> i64 { unsafe { bswap64(x) } }
#[cfg(target_endian = "little")] #[inline] pub fn to_be64(x: u64) -> u64 { unsafe { bswap64(x) } }

/// Convert an i64 to big endian from the target's endianness.
/// Convert an u64 to big endian from the target's endianness.
///
/// On big endian, this is a no-op. On little endian, the bytes are swapped.
#[cfg(target_endian = "big")] #[inline] pub fn to_be64(x: i64) -> i64 { x }
#[cfg(target_endian = "big")] #[inline] pub fn to_be64(x: u64) -> u64 { x }


/// Convert an i16 from little endian to the target's endianness.
/// Convert an u16 from little endian to the target's endianness.
///
/// On little endian, this is a no-op. On big endian, the bytes are swapped.
#[cfg(target_endian = "little")] #[inline] pub fn from_le16(x: i16) -> i16 { x }
#[cfg(target_endian = "little")] #[inline] pub fn from_le16(x: u16) -> u16 { x }

/// Convert an i16 from little endian to the target's endianness.
/// Convert an u16 from little endian to the target's endianness.
///
/// On little endian, this is a no-op. On big endian, the bytes are swapped.
#[cfg(target_endian = "big")] #[inline] pub fn from_le16(x: i16) -> i16 { unsafe { bswap16(x) } }
#[cfg(target_endian = "big")] #[inline] pub fn from_le16(x: u16) -> u16 { unsafe { bswap16(x) } }

/// Convert an i32 from little endian to the target's endianness.
/// Convert an u32 from little endian to the target's endianness.
///
/// On little endian, this is a no-op. On big endian, the bytes are swapped.
#[cfg(target_endian = "little")] #[inline] pub fn from_le32(x: i32) -> i32 { x }
#[cfg(target_endian = "little")] #[inline] pub fn from_le32(x: u32) -> u32 { x }

/// Convert an i32 from little endian to the target's endianness.
/// Convert an u32 from little endian to the target's endianness.
///
/// On little endian, this is a no-op. On big endian, the bytes are swapped.
#[cfg(target_endian = "big")] #[inline] pub fn from_le32(x: i32) -> i32 { unsafe { bswap32(x) } }
#[cfg(target_endian = "big")] #[inline] pub fn from_le32(x: u32) -> u32 { unsafe { bswap32(x) } }

/// Convert an i64 from little endian to the target's endianness.
/// Convert an u64 from little endian to the target's endianness.
///
/// On little endian, this is a no-op. On big endian, the bytes are swapped.
#[cfg(target_endian = "little")] #[inline] pub fn from_le64(x: i64) -> i64 { x }
#[cfg(target_endian = "little")] #[inline] pub fn from_le64(x: u64) -> u64 { x }

/// Convert an i64 from little endian to the target's endianness.
/// Convert an u64 from little endian to the target's endianness.
///
/// On little endian, this is a no-op. On big endian, the bytes are swapped.
#[cfg(target_endian = "big")] #[inline] pub fn from_le64(x: i64) -> i64 { unsafe { bswap64(x) } }
#[cfg(target_endian = "big")] #[inline] pub fn from_le64(x: u64) -> u64 { unsafe { bswap64(x) } }


/// Convert an i16 from big endian to the target's endianness.
/// Convert an u16 from big endian to the target's endianness.
///
/// On big endian, this is a no-op. On little endian, the bytes are swapped.
#[cfg(target_endian = "little")] #[inline] pub fn from_be16(x: i16) -> i16 { unsafe { bswap16(x) } }
#[cfg(target_endian = "little")] #[inline] pub fn from_be16(x: u16) -> u16 { unsafe { bswap16(x) } }

/// Convert an i16 from big endian to the target's endianness.
/// Convert an u16 from big endian to the target's endianness.
///
/// On big endian, this is a no-op. On little endian, the bytes are swapped.
#[cfg(target_endian = "big")] #[inline] pub fn from_be16(x: i16) -> i16 { x }
#[cfg(target_endian = "big")] #[inline] pub fn from_be16(x: u16) -> u16 { x }

/// Convert an i32 from big endian to the target's endianness.
/// Convert an u32 from big endian to the target's endianness.
///
/// On big endian, this is a no-op. On little endian, the bytes are swapped.
#[cfg(target_endian = "little")] #[inline] pub fn from_be32(x: i32) -> i32 { unsafe { bswap32(x) } }
#[cfg(target_endian = "little")] #[inline] pub fn from_be32(x: u32) -> u32 { unsafe { bswap32(x) } }

/// Convert an i32 from big endian to the target's endianness.
/// Convert an u32 from big endian to the target's endianness.
///
/// On big endian, this is a no-op. On little endian, the bytes are swapped.
#[cfg(target_endian = "big")] #[inline] pub fn from_be32(x: i32) -> i32 { x }
#[cfg(target_endian = "big")] #[inline] pub fn from_be32(x: u32) -> u32 { x }

/// Convert an i64 from big endian to the target's endianness.
/// Convert an u64 from big endian to the target's endianness.
///
/// On big endian, this is a no-op. On little endian, the bytes are swapped.
#[cfg(target_endian = "little")] #[inline] pub fn from_be64(x: i64) -> i64 { unsafe { bswap64(x) } }
#[cfg(target_endian = "little")] #[inline] pub fn from_be64(x: u64) -> u64 { unsafe { bswap64(x) } }

/// Convert an i64 from big endian to the target's endianness.
/// Convert an u64 from big endian to the target's endianness.
///
/// On big endian, this is a no-op. On little endian, the bytes are swapped.
#[cfg(target_endian = "big")] #[inline] pub fn from_be64(x: i64) -> i64 { x }
#[cfg(target_endian = "big")] #[inline] pub fn from_be64(x: u64) -> u64 { x }


/**
Expand Down
Loading

4 comments on commit c4a9d8a

@bors
Copy link
Contributor

@bors bors commented on c4a9d8a Apr 15, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

saw approval from alexcrichton
at huonw@c4a9d8a

@bors
Copy link
Contributor

@bors bors commented on c4a9d8a Apr 15, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merging huonw/rust/bitwise-byte-intrinsics = c4a9d8a into auto

@bors
Copy link
Contributor

@bors bors commented on c4a9d8a Apr 15, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

huonw/rust/bitwise-byte-intrinsics = c4a9d8a merged ok, testing candidate = 0f692a8d

Please sign in to comment.