summaryrefslogtreecommitdiff
path: root/src/codegen/bitfield_unit_tests.rs
diff options
context:
space:
mode:
authorNick Fitzgerald <fitzgen@gmail.com>2017-10-25 17:31:21 -0700
committerGlyn Normington <gnormington@pivotal.io>2017-11-21 13:55:00 +0000
commitf0e05310b43e88e541ed011d20994c02fdcc1a3a (patch)
treebe05ee8a3fa1a1d7f696daa630e48a824276ff61 /src/codegen/bitfield_unit_tests.rs
parent5e0cf9c356960e0459fea22cf0754dbec66f58b4 (diff)
Support bitfield allocation units larger than 64 bits
Individual bitfields are still limited to at most 64 bits, but this restriction can be weakened when Rust supports u128. This implements issue #816. Usage notes: * Since common code is added to each generated binding, a program which uses more than one binding may need to work around the duplication by including each binding in its own module. * The values created by bitfield allocation unit constructors can be assigned directly to the corresponding struct fields with no need for transmutation. Implementation notes: __BindgenBitfieldUnit represents a bitfield allocation unit using a Storage type accessible as a slice of u8. The alignment of the unit is inherited from an Align type by virtue of the field: align: [Align; 0], The position of this field in the struct is irrelevant. The alignment of the Storage type is intended to be no larger than the alignment of the Align type, which will be true if the Storage type is, for example, an array of u8. Although the double underscore (__) prefix is reserved for implementations of C++, there are precedents for this convention elsewhere in bindgen and so the convention is adopted here too. Acknowledgement: Thanks to @fitzgen for an initial implementation of __BindgenBitfieldUnit and code to integrate it into bindgen.
Diffstat (limited to 'src/codegen/bitfield_unit_tests.rs')
-rw-r--r--src/codegen/bitfield_unit_tests.rs284
1 files changed, 284 insertions, 0 deletions
diff --git a/src/codegen/bitfield_unit_tests.rs b/src/codegen/bitfield_unit_tests.rs
new file mode 100644
index 00000000..d39878cc
--- /dev/null
+++ b/src/codegen/bitfield_unit_tests.rs
@@ -0,0 +1,284 @@
+//! Tests for `__BindgenBitfieldUnit`.
+//!
+//! Note that bit-fields are allocated right to left (least to most significant
+//! bits).
+//!
+//! From the x86 PS ABI:
+//!
+//! ```c
+//! struct {
+//! int j : 5;
+//! int k : 6;
+//! int m : 7;
+//! };
+//! ```
+//!
+//! ```ignore
+//! +------------------------------------------------------------+
+//! | | | | |
+//! | padding | m | k | j |
+//! |31 18|17 11|10 5|4 0|
+//! +------------------------------------------------------------+
+//! ```
+
+use super::bitfield_unit::__BindgenBitfieldUnit;
+use std::mem;
+
+#[test]
+fn bitfield_unit_get_bit() {
+ let unit = __BindgenBitfieldUnit::<[u8; 2], u64>::new([0b10011101, 0b00011101]);
+
+ let mut bits = vec![];
+ for i in 0..16 {
+ bits.push(unit.get_bit(i));
+ }
+
+ println!();
+ println!("bits = {:?}", bits);
+ assert_eq!(bits, &[
+ // 0b10011101
+ true,
+ false,
+ true,
+ true,
+ true,
+ false,
+ false,
+ true ,
+
+ // 0b00011101
+ true,
+ false,
+ true,
+ true,
+ true,
+ false,
+ false,
+ false
+ ]);
+}
+
+#[test]
+fn bitfield_unit_set_bit() {
+ let mut unit = __BindgenBitfieldUnit::<[u8; 2], u64>::new([0b00000000, 0b00000000]);
+
+ for i in 0..16 {
+ if i % 3 == 0 {
+ unit.set_bit(i, true);
+ }
+ }
+
+ for i in 0..16 {
+ assert_eq!(unit.get_bit(i), i % 3 == 0);
+ }
+
+ let mut unit = __BindgenBitfieldUnit::<[u8; 2], u64>::new([0b11111111, 0b11111111]);
+
+ for i in 0..16 {
+ if i % 3 == 0 {
+ unit.set_bit(i, false);
+ }
+ }
+
+ for i in 0..16 {
+ assert_eq!(unit.get_bit(i), i % 3 != 0);
+ }
+}
+
+#[test]
+fn bitfield_unit_align() {
+ assert_eq!(mem::align_of::<__BindgenBitfieldUnit<[u8; 1], u8>>(), mem::align_of::<u8>());
+ assert_eq!(mem::align_of::<__BindgenBitfieldUnit<[u8; 1], u16>>(), mem::align_of::<u16>());
+ assert_eq!(mem::align_of::<__BindgenBitfieldUnit<[u8; 1], u32>>(), mem::align_of::<u32>());
+ assert_eq!(mem::align_of::<__BindgenBitfieldUnit<[u8; 1], u64>>(), mem::align_of::<u64>());
+
+ assert_eq!(mem::align_of::<__BindgenBitfieldUnit<[u8; 8], u8>>(), mem::align_of::<u8>());
+ assert_eq!(mem::align_of::<__BindgenBitfieldUnit<[u8; 8], u16>>(), mem::align_of::<u16>());
+ assert_eq!(mem::align_of::<__BindgenBitfieldUnit<[u8; 8], u32>>(), mem::align_of::<u32>());
+ assert_eq!(mem::align_of::<__BindgenBitfieldUnit<[u8; 8], u64>>(), mem::align_of::<u64>());
+}
+
+macro_rules! bitfield_unit_get {
+ (
+ $(
+ With $storage:expr , then get($start:expr, $len:expr) is $expected:expr;
+ )*
+ ) => {
+ #[test]
+ fn bitfield_unit_get() {
+ $({
+ let expected = $expected;
+ let unit = __BindgenBitfieldUnit::<_, u64>::new($storage);
+ let actual = unit.get($start, $len);
+
+ println!();
+ println!("expected = {:064b}", expected);
+ println!("actual = {:064b}", actual);
+
+ assert_eq!(expected, actual);
+ })*
+ }
+ }
+}
+
+bitfield_unit_get! {
+ // Let's just exhaustively test getting the bits from a single byte, since
+ // there are few enough combinations...
+
+ With [0b11100010], then get(0, 1) is 0;
+ With [0b11100010], then get(1, 1) is 1;
+ With [0b11100010], then get(2, 1) is 0;
+ With [0b11100010], then get(3, 1) is 0;
+ With [0b11100010], then get(4, 1) is 0;
+ With [0b11100010], then get(5, 1) is 1;
+ With [0b11100010], then get(6, 1) is 1;
+ With [0b11100010], then get(7, 1) is 1;
+
+ With [0b11100010], then get(0, 2) is 0b10;
+ With [0b11100010], then get(1, 2) is 0b01;
+ With [0b11100010], then get(2, 2) is 0b00;
+ With [0b11100010], then get(3, 2) is 0b00;
+ With [0b11100010], then get(4, 2) is 0b10;
+ With [0b11100010], then get(5, 2) is 0b11;
+ With [0b11100010], then get(6, 2) is 0b11;
+
+ With [0b11100010], then get(0, 3) is 0b010;
+ With [0b11100010], then get(1, 3) is 0b001;
+ With [0b11100010], then get(2, 3) is 0b000;
+ With [0b11100010], then get(3, 3) is 0b100;
+ With [0b11100010], then get(4, 3) is 0b110;
+ With [0b11100010], then get(5, 3) is 0b111;
+
+ With [0b11100010], then get(0, 4) is 0b0010;
+ With [0b11100010], then get(1, 4) is 0b0001;
+ With [0b11100010], then get(2, 4) is 0b1000;
+ With [0b11100010], then get(3, 4) is 0b1100;
+ With [0b11100010], then get(4, 4) is 0b1110;
+
+ With [0b11100010], then get(0, 5) is 0b00010;
+ With [0b11100010], then get(1, 5) is 0b10001;
+ With [0b11100010], then get(2, 5) is 0b11000;
+ With [0b11100010], then get(3, 5) is 0b11100;
+
+ With [0b11100010], then get(0, 6) is 0b100010;
+ With [0b11100010], then get(1, 6) is 0b110001;
+ With [0b11100010], then get(2, 6) is 0b111000;
+
+ With [0b11100010], then get(0, 7) is 0b1100010;
+ With [0b11100010], then get(1, 7) is 0b1110001;
+
+ With [0b11100010], then get(0, 8) is 0b11100010;
+
+ // OK. Now let's test getting bits from across byte boundaries.
+
+ With [0b01010101, 0b11111111, 0b00000000, 0b11111111],
+ then get(0, 16) is 0b1111111101010101;
+
+ With [0b01010101, 0b11111111, 0b00000000, 0b11111111],
+ then get(1, 16) is 0b0111111110101010;
+
+ With [0b01010101, 0b11111111, 0b00000000, 0b11111111],
+ then get(2, 16) is 0b0011111111010101;
+
+ With [0b01010101, 0b11111111, 0b00000000, 0b11111111],
+ then get(3, 16) is 0b0001111111101010;
+
+ With [0b01010101, 0b11111111, 0b00000000, 0b11111111],
+ then get(4, 16) is 0b0000111111110101;
+
+ With [0b01010101, 0b11111111, 0b00000000, 0b11111111],
+ then get(5, 16) is 0b0000011111111010;
+
+ With [0b01010101, 0b11111111, 0b00000000, 0b11111111],
+ then get(6, 16) is 0b0000001111111101;
+
+ With [0b01010101, 0b11111111, 0b00000000, 0b11111111],
+ then get(7, 16) is 0b0000000111111110;
+
+ With [0b01010101, 0b11111111, 0b00000000, 0b11111111],
+ then get(8, 16) is 0b0000000011111111;
+}
+
+macro_rules! bitfield_unit_set {
+ (
+ $(
+ set($start:expr, $len:expr, $val:expr) is $expected:expr;
+ )*
+ ) => {
+ #[test]
+ fn bitfield_unit_set() {
+ $(
+ let mut unit = __BindgenBitfieldUnit::<[u8; 4], u64>::new([0, 0, 0, 0]);
+ unit.set($start, $len, $val);
+ let actual = unit.get(0, 32);
+
+ println!();
+ println!("set({}, {}, {:032b}", $start, $len, $val);
+ println!("expected = {:064b}", $expected);
+ println!("actual = {:064b}", actual);
+
+ assert_eq!($expected, actual);
+ )*
+ }
+ }
+}
+
+bitfield_unit_set! {
+ // Once again, let's exhaustively test single byte combinations.
+
+ set(0, 1, 0b11111111) is 0b00000001;
+ set(1, 1, 0b11111111) is 0b00000010;
+ set(2, 1, 0b11111111) is 0b00000100;
+ set(3, 1, 0b11111111) is 0b00001000;
+ set(4, 1, 0b11111111) is 0b00010000;
+ set(5, 1, 0b11111111) is 0b00100000;
+ set(6, 1, 0b11111111) is 0b01000000;
+ set(7, 1, 0b11111111) is 0b10000000;
+
+ set(0, 2, 0b11111111) is 0b00000011;
+ set(1, 2, 0b11111111) is 0b00000110;
+ set(2, 2, 0b11111111) is 0b00001100;
+ set(3, 2, 0b11111111) is 0b00011000;
+ set(4, 2, 0b11111111) is 0b00110000;
+ set(5, 2, 0b11111111) is 0b01100000;
+ set(6, 2, 0b11111111) is 0b11000000;
+
+ set(0, 3, 0b11111111) is 0b00000111;
+ set(1, 3, 0b11111111) is 0b00001110;
+ set(2, 3, 0b11111111) is 0b00011100;
+ set(3, 3, 0b11111111) is 0b00111000;
+ set(4, 3, 0b11111111) is 0b01110000;
+ set(5, 3, 0b11111111) is 0b11100000;
+
+ set(0, 4, 0b11111111) is 0b00001111;
+ set(1, 4, 0b11111111) is 0b00011110;
+ set(2, 4, 0b11111111) is 0b00111100;
+ set(3, 4, 0b11111111) is 0b01111000;
+ set(4, 4, 0b11111111) is 0b11110000;
+
+ set(0, 5, 0b11111111) is 0b00011111;
+ set(1, 5, 0b11111111) is 0b00111110;
+ set(2, 5, 0b11111111) is 0b01111100;
+ set(3, 5, 0b11111111) is 0b11111000;
+
+ set(0, 6, 0b11111111) is 0b00111111;
+ set(1, 6, 0b11111111) is 0b01111110;
+ set(2, 6, 0b11111111) is 0b11111100;
+
+ set(0, 7, 0b11111111) is 0b01111111;
+ set(1, 7, 0b11111111) is 0b11111110;
+
+ set(0, 8, 0b11111111) is 0b11111111;
+
+ // And, now let's cross byte boundaries.
+
+ set(0, 16, 0b1111111111111111) is 0b00000000000000001111111111111111;
+ set(1, 16, 0b1111111111111111) is 0b00000000000000011111111111111110;
+ set(2, 16, 0b1111111111111111) is 0b00000000000000111111111111111100;
+ set(3, 16, 0b1111111111111111) is 0b00000000000001111111111111111000;
+ set(4, 16, 0b1111111111111111) is 0b00000000000011111111111111110000;
+ set(5, 16, 0b1111111111111111) is 0b00000000000111111111111111100000;
+ set(6, 16, 0b1111111111111111) is 0b00000000001111111111111111000000;
+ set(7, 16, 0b1111111111111111) is 0b00000000011111111111111110000000;
+ set(8, 16, 0b1111111111111111) is 0b00000000111111111111111100000000;
+}