Skip to content

Commit

Permalink
Auto merge of rust-lang#762 - emilio:much-brokenness, r=fitzgen
Browse files Browse the repository at this point in the history
Moar bitfield fixes

Now with the right branch name. See individual commits for details.
  • Loading branch information
bors-servo authored Jun 19, 2017
2 parents b08b59a + 700a3ea commit 77d6962
Show file tree
Hide file tree
Showing 20 changed files with 2,750 additions and 488 deletions.
25 changes: 25 additions & 0 deletions bindgen-integration/cpp/Test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,29 @@ Date2::assert(unsigned short nWeekDay,
this->byte == byte;
}

bool
Fifth::assert(unsigned short nWeekDay,
unsigned short nMonthDay,
unsigned short nMonth,
unsigned short nYear,
unsigned char byte)
{
return this->nWeekDay == nWeekDay &&
this->nMonthDay == nMonthDay &&
this->nMonth == nMonth &&
this->nYear == nYear &&
this->byte == byte;
}

bool
Sixth::assert(unsigned char byte,
unsigned char nWeekDay,
unsigned char nMonth,
unsigned char nMonthDay) {
return this->nWeekDay == nWeekDay &&
this->nMonthDay == nMonthDay &&
this->nMonth == nMonth &&
this->byte == byte;
};

} // namespace bitfields
30 changes: 30 additions & 0 deletions bindgen-integration/cpp/Test.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,36 @@ struct Date2 {
unsigned short byte);
};


struct Fifth {
unsigned short nWeekDay : 3; // 0..7 (3 bits)
unsigned short nMonthDay : 6; // 0..31 (6 bits)
unsigned short nMonth : 5; // 0..12 (5 bits)
unsigned short nYear : 8; // 0..100 (8 bits)
unsigned char byte;

/// Returns true if the bitfields match the arguments, false otherwise.
bool assert(unsigned short nWeekDay,
unsigned short nMonthDay,
unsigned short nMonth,
unsigned short nYear,
unsigned char byte);
};

struct Sixth {
unsigned char byte;
unsigned char nWeekDay : 3;
unsigned char nMonth : 5;
unsigned char nMonthDay : 6;

/// Returns true if the bitfields match the arguments, false otherwise.
bool assert(unsigned char byte,
unsigned char nWeekDay,
unsigned char nMonth,
unsigned char nMonthDay);
};


} // namespace bitfields

struct AutoRestoreBool {
Expand Down
42 changes: 42 additions & 0 deletions bindgen-integration/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,48 @@ fn test_bitfields_date2() {
});
}

#[test]
fn test_bitfields_fifth() {
let mut date: bindings::bitfields::Fifth = unsafe {
mem::zeroed()
};

assert!(unsafe {
date.assert(0, 0, 0, 0, 0)
});

date.byte = 255; // Set this first, to ensure we don't override it.

date.set_nWeekDay(6); // saturdays are the best
date.set_nMonthDay(20);
date.set_nMonth(11);
date.set_nYear(95);

assert!(unsafe {
date.assert(6, 20, 11, 95, 255)
});
}

#[test]
fn test_bitfields_sixth() {
let mut date: bindings::bitfields::Sixth = unsafe {
mem::zeroed()
};

assert!(unsafe {
date.assert(0, 0, 0, 0)
});

date.byte = 255;
date.set_nWeekDay(6); // saturdays are the best
date.set_nMonthDay(20);
date.set_nMonth(11);

assert!(unsafe {
date.assert(255, 6, 11, 20)
});
}

#[test]
fn test_bitfield_constructors() {
use std::mem;
Expand Down
35 changes: 24 additions & 11 deletions src/codegen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1113,9 +1113,9 @@ impl Bitfield {
#[inline]
$fn_prefix $ctor_name($params $param_name : $bitfield_ty)
-> $unit_field_int_ty {
($body |
(($param_name as $bitfield_int_ty as $unit_field_int_ty) << $offset) &
($mask as $unit_field_int_ty))
($body |
(($param_name as $bitfield_int_ty as $unit_field_int_ty) << $offset) &
($mask as $unit_field_int_ty))
}
}
).unwrap()
Expand Down Expand Up @@ -1147,12 +1147,18 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit {
.build_ty(field_ty.clone());
fields.extend(Some(field));

let unit_field_int_ty = match self.layout().size {
let mut field_int_size = self.layout().size;
if !field_int_size.is_power_of_two() {
field_int_size = field_int_size.next_power_of_two();
}

let unit_field_int_ty = match field_int_size {
8 => quote_ty!(ctx.ext_cx(), u64),
4 => quote_ty!(ctx.ext_cx(), u32),
2 => quote_ty!(ctx.ext_cx(), u16),
1 => quote_ty!(ctx.ext_cx(), u8),
_ => {
size => {
debug_assert!(size > 8);
// Can't generate bitfield accessors for unit sizes larget than
// 64 bits at the moment.
struct_layout.saw_bitfield_unit(self.layout());
Expand Down Expand Up @@ -1273,7 +1279,7 @@ impl<'a> FieldCodegen<'a> for Bitfield {
let bitfield_ty = bitfield_ty.to_rust_ty_or_opaque(ctx, bitfield_ty_item);

let offset = self.offset_into_unit();
let mask: usize = self.mask();
let mask = self.mask();

let impl_item = quote_item!(
ctx.ext_cx(),
Expand All @@ -1282,7 +1288,9 @@ impl<'a> FieldCodegen<'a> for Bitfield {
pub fn $getter_name(&self) -> $bitfield_ty {
let mask = $mask as $unit_field_int_ty;
let unit_field_val: $unit_field_int_ty = unsafe {
::$prefix::mem::transmute(self.$unit_field_ident)
::$prefix::ptr::read_unaligned(
&self.$unit_field_ident as *const _ as *const $unit_field_int_ty
)
};
let val = (unit_field_val & mask) >> $offset;
unsafe {
Expand All @@ -1296,14 +1304,19 @@ impl<'a> FieldCodegen<'a> for Bitfield {
let val = val as $bitfield_int_ty as $unit_field_int_ty;

let mut unit_field_val: $unit_field_int_ty = unsafe {
::$prefix::mem::transmute(self.$unit_field_ident)
::$prefix::ptr::read_unaligned(
&self.$unit_field_ident as *const _ as *const $unit_field_int_ty)
};

unit_field_val &= !mask;
unit_field_val |= (val << $offset) & mask;

self.$unit_field_ident = unsafe {
::$prefix::mem::transmute(unit_field_val)
};
unsafe {
::$prefix::ptr::write_unaligned(
&mut self.$unit_field_ident as *mut _ as *mut $unit_field_int_ty,
unit_field_val
);
}
}
}
).unwrap();
Expand Down
18 changes: 8 additions & 10 deletions src/ir/comp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,18 +293,15 @@ impl Bitfield {

/// Get the mask value that when &'ed with this bitfield's allocation unit
/// produces this bitfield's value.
///
/// TODO(emilio): This should probably use the target's word size, and what
/// about bitfields that are bigger than that?
pub fn mask(&self) -> usize {
pub fn mask(&self) -> u64 {
use std::mem;
use std::usize;
use std::u64;

let unoffseted_mask =
if self.width() as usize == mem::size_of::<usize>() * 8 {
usize::MAX
if self.width() as u64 == mem::size_of::<u64>() as u64 * 8 {
u64::MAX
} else {
((1usize << self.width()) - 1usize)
((1u64 << self.width()) - 1u64)
};

unoffseted_mask << self.offset_into_unit()
Expand Down Expand Up @@ -488,8 +485,9 @@ fn bitfields_to_allocation_units<E, I>(ctx: &BindgenContext,
where E: Extend<Field>
{
*bitfield_unit_count += 1;
let layout = Layout::new(bytes_from_bits_pow2(unit_size_in_bits),
bytes_from_bits_pow2(unit_align_in_bits));
let align = bytes_from_bits_pow2(unit_align_in_bits);
let size = align_to(unit_size_in_bits, align * 8) / 8;
let layout = Layout::new(size, align);
fields.extend(Some(Field::Bitfields(BitfieldUnit {
nth: *bitfield_unit_count,
layout: layout,
Expand Down
Loading

0 comments on commit 77d6962

Please sign in to comment.