Skip to content

Commit a721557

Browse files
committed
[wip] Rework how bitfields are handled.
1 parent f1caa10 commit a721557

20 files changed

+374
-941
lines changed

build.rs

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ mod codegen {
1111
quasi_codegen::expand(&src, &dst).unwrap();
1212
println!("cargo:rerun-if-changed=src/codegen/mod.rs");
1313
println!("cargo:rerun-if-changed=src/codegen/helpers.rs");
14+
println!("cargo:rerun-if-changed=src/codegen/struct_layout.rs");
1415
}
1516
}
1617

src/codegen/mod.rs

+84-83
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ mod helpers;
22
mod struct_layout;
33

44
use self::helpers::{BlobTyBuilder, attributes};
5-
use self::struct_layout::StructLayoutTracker;
5+
use self::struct_layout::{align_to, bytes_from_bits, StructLayoutTracker};
66
use aster;
77

88
use ir::annotations::FieldAccessorKind;
@@ -363,8 +363,7 @@ impl CodeGenerator for Module {
363363
}
364364

365365
if item.id() == ctx.root_module() {
366-
let saw_union = result.saw_union;
367-
if saw_union && !ctx.options().unstable_rust {
366+
if result.saw_union && !ctx.options().unstable_rust {
368367
utils::prepend_union_types(ctx, &mut *result);
369368
}
370369
if result.saw_incomplete_array {
@@ -717,12 +716,12 @@ impl<'a> ItemToRustTy for Vtable<'a> {
717716
}
718717

719718
struct Bitfield<'a> {
720-
index: usize,
719+
index: &'a mut usize,
721720
fields: Vec<&'a Field>,
722721
}
723722

724723
impl<'a> Bitfield<'a> {
725-
fn new(index: usize, fields: Vec<&'a Field>) -> Self {
724+
fn new(index: &'a mut usize, fields: Vec<&'a Field>) -> Self {
726725
Bitfield {
727726
index: index,
728727
fields: fields,
@@ -732,89 +731,96 @@ impl<'a> Bitfield<'a> {
732731
fn codegen_fields(self,
733732
ctx: &BindgenContext,
734733
fields: &mut Vec<ast::StructField>,
735-
methods: &mut Vec<ast::ImplItem>)
734+
_methods: &mut Vec<ast::ImplItem>)
736735
-> Layout {
737736
use aster::struct_field::StructFieldBuilder;
738-
let mut total_width = self.fields
739-
.iter()
740-
.fold(0u32, |acc, f| acc + f.bitfield().unwrap());
741-
742-
if !total_width.is_power_of_two() || total_width < 8 {
743-
total_width = cmp::max(8, total_width.next_power_of_two());
744-
}
745-
debug_assert_eq!(total_width % 8, 0);
746-
let total_width_in_bytes = total_width as usize / 8;
747-
748-
let bitfield_layout = Layout::new(total_width_in_bytes,
749-
total_width_in_bytes);
750-
let bitfield_type = BlobTyBuilder::new(bitfield_layout).build();
751-
let field_name = format!("_bitfield_{}", self.index);
752-
let field_ident = ctx.ext_cx().ident_of(&field_name);
753-
let field = StructFieldBuilder::named(&field_name)
754-
.pub_()
755-
.build_ty(bitfield_type.clone());
756-
fields.push(field);
757737

738+
// NOTE: What follows is reverse-engineered from LLVM's
739+
// lib/AST/RecordLayoutBuilder.cpp
740+
//
741+
// FIXME(emilio): There are some differences between Microsoft and the
742+
// Itanium ABI, but we'll ignore those and stick to Itanium for now.
743+
//
744+
// Also, we need to handle packed bitfields and stuff.
745+
// TODO(emilio): Take into account C++'s wide bitfields, and
746+
// packing, sigh.
747+
let mut total_size_in_bits = 0;
748+
let mut max_align = 0;
749+
let mut unfilled_bits_in_last_unit = 0;
750+
let mut field_size_in_bits = 0;
751+
*self.index += 1;
752+
let mut last_field_name = format!("_bitfield_{}", self.index);
753+
let mut last_field_align = 0;
758754

759-
let mut offset = 0;
760755
for field in self.fields {
761756
let width = field.bitfield().unwrap();
762-
let field_name = field.name()
763-
.map(ToOwned::to_owned)
764-
.unwrap_or_else(|| format!("at_offset_{}", offset));
765-
766757
let field_item = ctx.resolve_item(field.ty());
767758
let field_ty_layout = field_item.kind()
768759
.expect_type()
769760
.layout(ctx)
770761
.expect("Bitfield without layout? Gah!");
771762

772-
let field_type = field_item.to_rust_ty(ctx);
773-
let int_type = BlobTyBuilder::new(field_ty_layout).build();
763+
let field_align = field_ty_layout.align;
774764

775-
let getter_name = ctx.rust_ident(&field_name);
776-
let setter_name = ctx.ext_cx()
777-
.ident_of(&format!("set_{}", &field_name));
778-
let mask = ((1usize << width) - 1) << offset;
779-
let prefix = ctx.trait_prefix();
780-
// The transmute is unfortunate, but it's needed for enums in
781-
// bitfields.
782-
let item = quote_item!(ctx.ext_cx(),
783-
impl X {
784-
#[inline]
785-
pub fn $getter_name(&self) -> $field_type {
786-
unsafe {
787-
::$prefix::mem::transmute(
788-
(
789-
(self.$field_ident &
790-
($mask as $bitfield_type))
791-
>> $offset
792-
) as $int_type
793-
)
794-
}
795-
}
765+
if field_size_in_bits != 0 &&
766+
(width == 0 || width as usize > unfilled_bits_in_last_unit) {
767+
field_size_in_bits = align_to(field_size_in_bits, field_align);
768+
// Push the new field.
769+
let ty =
770+
BlobTyBuilder::new(Layout::new(bytes_from_bits(field_size_in_bits),
771+
bytes_from_bits(last_field_align)))
772+
.build();
796773

797-
#[inline]
798-
pub fn $setter_name(&mut self, val: $field_type) {
799-
self.$field_ident &= !($mask as $bitfield_type);
800-
self.$field_ident |=
801-
(val as $int_type as $bitfield_type << $offset) &
802-
($mask as $bitfield_type);
803-
}
804-
}
805-
)
806-
.unwrap();
774+
let field = StructFieldBuilder::named(&last_field_name)
775+
.pub_()
776+
.build_ty(ty);
777+
fields.push(field);
807778

808-
let items = match item.unwrap().node {
809-
ast::ItemKind::Impl(_, _, _, _, _, items) => items,
810-
_ => unreachable!(),
811-
};
779+
// TODO(emilio): dedup this.
780+
*self.index += 1;
781+
last_field_name = format!("_bitfield_{}", self.index);
782+
783+
// Now reset the size and the rest of stuff.
784+
// unfilled_bits_in_last_unit = 0;
785+
field_size_in_bits = 0;
786+
last_field_align = 0;
787+
}
788+
789+
// TODO(emilio): Create the accessors. Problem here is that we still
790+
// don't know which one is going to be the final alignment of the
791+
// bitfield, and whether we have to index in it. Thus, we don't know
792+
// which integer type do we need.
793+
//
794+
// We could push them to a Vec or something, but given how buggy
795+
// they where maybe it's not a great idea?
796+
field_size_in_bits += width as usize;
797+
total_size_in_bits += width as usize;
798+
799+
800+
let data_size = align_to(field_size_in_bits, field_align * 8);
801+
802+
max_align = cmp::max(max_align, field_align);
803+
804+
// NB: The width here is completely, absolutely intentional.
805+
last_field_align = cmp::max(last_field_align, width as usize);
806+
807+
unfilled_bits_in_last_unit = data_size - field_size_in_bits;
808+
}
809+
810+
if field_size_in_bits != 0 {
811+
// Push the last field.
812+
let ty =
813+
BlobTyBuilder::new(Layout::new(bytes_from_bits(field_size_in_bits),
814+
bytes_from_bits(last_field_align)))
815+
.build();
812816

813-
methods.extend(items.into_iter());
814-
offset += width;
817+
let field = StructFieldBuilder::named(&last_field_name)
818+
.pub_()
819+
.build_ty(ty);
820+
fields.push(field);
815821
}
816822

817-
bitfield_layout
823+
Layout::new(bytes_from_bits(total_size_in_bits), max_align)
818824
}
819825
}
820826

@@ -1062,12 +1068,10 @@ impl CodeGenerator for CompInfo {
10621068
debug_assert!(!current_bitfield_fields.is_empty());
10631069
let bitfield_fields =
10641070
mem::replace(&mut current_bitfield_fields, vec![]);
1065-
bitfield_count += 1;
1066-
let bitfield_layout = Bitfield::new(bitfield_count,
1071+
let bitfield_layout = Bitfield::new(&mut bitfield_count,
10671072
bitfield_fields)
10681073
.codegen_fields(ctx, &mut fields, &mut methods);
1069-
1070-
struct_layout.saw_bitfield(bitfield_layout);
1074+
struct_layout.saw_bitfield_batch(bitfield_layout);
10711075

10721076
current_bitfield_width = None;
10731077
current_bitfield_layout = None;
@@ -1099,8 +1103,7 @@ impl CodeGenerator for CompInfo {
10991103
} else {
11001104
quote_ty!(ctx.ext_cx(), __BindgenUnionField<$ty>)
11011105
}
1102-
} else if let Some(item) =
1103-
field_ty.is_incomplete_array(ctx) {
1106+
} else if let Some(item) = field_ty.is_incomplete_array(ctx) {
11041107
result.saw_incomplete_array();
11051108

11061109
let inner = item.to_rust_ty(ctx);
@@ -1224,12 +1227,10 @@ impl CodeGenerator for CompInfo {
12241227
debug_assert!(!current_bitfield_fields.is_empty());
12251228
let bitfield_fields = mem::replace(&mut current_bitfield_fields,
12261229
vec![]);
1227-
bitfield_count += 1;
1228-
let bitfield_layout = Bitfield::new(bitfield_count,
1230+
let bitfield_layout = Bitfield::new(&mut bitfield_count,
12291231
bitfield_fields)
12301232
.codegen_fields(ctx, &mut fields, &mut methods);
1231-
1232-
struct_layout.saw_bitfield(bitfield_layout);
1233+
struct_layout.saw_bitfield_batch(bitfield_layout);
12331234
}
12341235
debug_assert!(current_bitfield_fields.is_empty());
12351236

@@ -2174,8 +2175,8 @@ impl ToRustTy for Type {
21742175
quote_ty!(ctx.ext_cx(), ::$prefix::option::Option<$ty>)
21752176
}
21762177
TypeKind::Array(item, len) => {
2177-
let inner = item.to_rust_ty(ctx);
2178-
aster::ty::TyBuilder::new().array(len).build(inner)
2178+
let ty = item.to_rust_ty(ctx);
2179+
aster::ty::TyBuilder::new().array(len).build(ty)
21792180
}
21802181
TypeKind::Enum(..) => {
21812182
let path = item.namespace_aware_canonical_path(ctx);
@@ -2190,7 +2191,7 @@ impl ToRustTy for Type {
21902191
.map(|arg| arg.to_rust_ty(ctx))
21912192
.collect::<Vec<_>>();
21922193

2193-
path.segments.last_mut().unwrap().parameters = if
2194+
path.segments.last_mut().unwrap().parameters = if
21942195
template_args.is_empty() {
21952196
None
21962197
} else {

0 commit comments

Comments
 (0)