@@ -736,10 +736,8 @@ impl<'a> Bitfield<'a> {
736
736
fn codegen_fields ( self ,
737
737
ctx : & BindgenContext ,
738
738
fields : & mut Vec < ast:: StructField > ,
739
- _methods : & mut Vec < ast:: ImplItem > )
739
+ methods : & mut Vec < ast:: ImplItem > )
740
740
-> Layout {
741
- use aster:: struct_field:: StructFieldBuilder ;
742
-
743
741
// NOTE: What follows is reverse-engineered from LLVM's
744
742
// lib/AST/RecordLayoutBuilder.cpp
745
743
//
@@ -757,29 +755,28 @@ impl<'a> Bitfield<'a> {
757
755
let mut last_field_name = format ! ( "_bitfield_{}" , self . index) ;
758
756
let mut last_field_align = 0 ;
759
757
758
+ // (name, mask, width, bitfield's type, bitfield's layout)
759
+ let mut bitfields: Vec < ( & str , usize , usize , ast:: Ty , Layout ) > = vec ! [ ] ;
760
+
760
761
for field in self . fields {
761
- let width = field. bitfield ( ) . unwrap ( ) ;
762
+ let width = field. bitfield ( ) . unwrap ( ) as usize ;
762
763
let field_item = ctx. resolve_item ( field. ty ( ) ) ;
763
764
let field_ty_layout = field_item. kind ( )
764
765
. expect_type ( )
765
766
. layout ( ctx)
766
767
. expect ( "Bitfield without layout? Gah!" ) ;
767
-
768
768
let field_align = field_ty_layout. align ;
769
769
770
770
if field_size_in_bits != 0 &&
771
- ( width == 0 || width as usize > unfilled_bits_in_last_unit) {
771
+ ( width == 0 || width > unfilled_bits_in_last_unit) {
772
+ // We've finished a physical field, so flush it and its bitfields.
772
773
field_size_in_bits = align_to ( field_size_in_bits, field_align) ;
773
- // Push the new field.
774
- let ty =
775
- BlobTyBuilder :: new ( Layout :: new ( bytes_from_bits_pow2 ( field_size_in_bits) ,
776
- bytes_from_bits_pow2 ( last_field_align) ) )
777
- . build ( ) ;
778
-
779
- let field = StructFieldBuilder :: named ( & last_field_name)
780
- . pub_ ( )
781
- . build_ty ( ty) ;
782
- fields. push ( field) ;
774
+ fields. push ( flush_bitfields ( ctx,
775
+ field_size_in_bits,
776
+ last_field_align,
777
+ & last_field_name,
778
+ bitfields. drain ( ..) ,
779
+ methods) ) ;
783
780
784
781
// TODO(emilio): dedup this.
785
782
* self . index += 1 ;
@@ -791,44 +788,127 @@ impl<'a> Bitfield<'a> {
791
788
last_field_align = 0 ;
792
789
}
793
790
794
- // TODO(emilio): Create the accessors. Problem here is that we still
795
- // don't know which one is going to be the final alignment of the
796
- // bitfield, and whether we have to index in it. Thus, we don't know
797
- // which integer type do we need.
798
- //
799
- // We could push them to a Vec or something, but given how buggy
800
- // they where maybe it's not a great idea?
801
- field_size_in_bits += width as usize ;
802
- total_size_in_bits += width as usize ;
791
+ if let Some ( name) = field. name ( ) {
792
+ bitfields. push ( ( name,
793
+ field_size_in_bits,
794
+ width,
795
+ field_item. to_rust_ty ( ctx) . unwrap ( ) ,
796
+ field_ty_layout) ) ;
797
+ }
803
798
799
+ field_size_in_bits += width;
800
+ total_size_in_bits += width;
804
801
805
802
let data_size = align_to ( field_size_in_bits, field_align * 8 ) ;
806
803
807
804
max_align = cmp:: max ( max_align, field_align) ;
808
805
809
806
// NB: The width here is completely, absolutely intentional.
810
- last_field_align = cmp:: max ( last_field_align, width as usize ) ;
807
+ last_field_align = cmp:: max ( last_field_align, width) ;
811
808
812
809
unfilled_bits_in_last_unit = data_size - field_size_in_bits;
813
810
}
814
811
815
812
if field_size_in_bits != 0 {
816
- // Push the last field.
817
- let ty =
818
- BlobTyBuilder :: new ( Layout :: new ( bytes_from_bits_pow2 ( field_size_in_bits) ,
819
- bytes_from_bits_pow2 ( last_field_align) ) )
820
- . build ( ) ;
821
-
822
- let field = StructFieldBuilder :: named ( & last_field_name)
823
- . pub_ ( )
824
- . build_ty ( ty) ;
825
- fields. push ( field) ;
813
+ // Flush the last physical field and its bitfields.
814
+ fields. push ( flush_bitfields ( ctx,
815
+ field_size_in_bits,
816
+ last_field_align,
817
+ & last_field_name,
818
+ bitfields. drain ( ..) ,
819
+ methods) ) ;
826
820
}
827
821
828
822
Layout :: new ( bytes_from_bits ( total_size_in_bits) , max_align)
829
823
}
830
824
}
831
825
826
+ /// A physical field (which is a word or byte or ...) has many logical bitfields
827
+ /// contained within it, but not all bitfields are in the same physical field of
828
+ /// a struct. This function creates a single physical field and flushes all the
829
+ /// accessors for the logical `bitfields` within that physical field to the
830
+ /// outgoing `methods`.
831
+ fn flush_bitfields < ' a , I > ( ctx : & BindgenContext ,
832
+ field_size_in_bits : usize ,
833
+ field_align : usize ,
834
+ field_name : & str ,
835
+ bitfields : I ,
836
+ methods : & mut Vec < ast:: ImplItem > ) -> ast:: StructField
837
+ where I : IntoIterator < Item = ( & ' a str , usize , usize , ast:: Ty , Layout ) >
838
+ {
839
+ use aster:: struct_field:: StructFieldBuilder ;
840
+
841
+ let field_layout = Layout :: new ( bytes_from_bits_pow2 ( field_size_in_bits) ,
842
+ bytes_from_bits_pow2 ( field_align) ) ;
843
+ let field_ty = BlobTyBuilder :: new ( field_layout) . build ( ) ;
844
+
845
+ let field = StructFieldBuilder :: named ( field_name)
846
+ . pub_ ( )
847
+ . build_ty ( field_ty. clone ( ) ) ;
848
+
849
+ for ( name, offset, width, bitfield_ty, bitfield_layout) in bitfields {
850
+ let prefix = ctx. trait_prefix ( ) ;
851
+ let getter_name = ctx. rust_ident ( name) ;
852
+ let setter_name = ctx. ext_cx ( )
853
+ . ident_of ( & format ! ( "set_{}" , & name) ) ;
854
+ let field_ident = ctx. ext_cx ( ) . ident_of ( field_name) ;
855
+
856
+ let field_int_ty = match field_layout. size {
857
+ 8 => quote_ty ! ( ctx. ext_cx( ) , u64 ) ,
858
+ 4 => quote_ty ! ( ctx. ext_cx( ) , u32 ) ,
859
+ 2 => quote_ty ! ( ctx. ext_cx( ) , u16 ) ,
860
+ 1 => quote_ty ! ( ctx. ext_cx( ) , u8 ) ,
861
+ _ => panic ! ( "physical field containing bitfields should be sized \
862
+ 8, 4, 2, or 1 bytes")
863
+ } ;
864
+ let bitfield_int_ty = BlobTyBuilder :: new ( bitfield_layout) . build ( ) ;
865
+
866
+ let mask: usize = ( ( 1usize << width) - 1usize ) << offset;
867
+
868
+ let impl_item = quote_item ! (
869
+ ctx. ext_cx( ) ,
870
+ impl XxxIgnored {
871
+ #[ inline]
872
+ pub fn $getter_name( & self ) -> $bitfield_ty {
873
+ let mask = $mask as $field_int_ty;
874
+ let field_val: $field_int_ty = unsafe {
875
+ :: $prefix:: mem:: transmute( self . $field_ident)
876
+ } ;
877
+ let val = ( field_val & mask) >> $offset;
878
+ unsafe {
879
+ :: $prefix:: mem:: transmute( val as $bitfield_int_ty)
880
+ }
881
+ }
882
+
883
+ #[ inline]
884
+ pub fn $setter_name( & mut self , val: $bitfield_ty) {
885
+ let mask = $mask as $field_int_ty;
886
+ let val = val as $bitfield_int_ty as $field_int_ty;
887
+
888
+ let mut field_val: $field_int_ty = unsafe {
889
+ :: $prefix:: mem:: transmute( self . $field_ident)
890
+ } ;
891
+ field_val &= !mask;
892
+ field_val |= ( val << $offset) & mask;
893
+
894
+ self . $field_ident = unsafe {
895
+ :: $prefix:: mem:: transmute( field_val)
896
+ } ;
897
+ }
898
+ }
899
+ ) . unwrap ( ) ;
900
+
901
+ match impl_item. unwrap ( ) . node {
902
+ ast:: ItemKind :: Impl ( _, _, _, _, _, items) => {
903
+ methods. extend ( items. into_iter ( ) ) ;
904
+ } ,
905
+ _ => unreachable ! ( ) ,
906
+ } ;
907
+ }
908
+
909
+ field
910
+ }
911
+
832
912
impl CodeGenerator for TemplateInstantiation {
833
913
type Extra = Item ;
834
914
0 commit comments