Skip to content

Commit e5bcf3b

Browse files
committed
Define a type for bitfield allocation units and getting bits within
1 parent 1cb1101 commit e5bcf3b

File tree

3 files changed

+371
-0
lines changed

3 files changed

+371
-0
lines changed

src/codegen/bitfield_unit.rs

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
2+
pub struct BindgenBitfieldUnit<Storage, Align>
3+
where
4+
Storage: AsRef<[u8]> + AsMut<[u8]>,
5+
{
6+
storage: Storage,
7+
align: [Align; 0],
8+
}
9+
10+
impl<Storage, Align> BindgenBitfieldUnit<Storage, Align>
11+
where
12+
Storage: AsRef<[u8]> + AsMut<[u8]>,
13+
{
14+
#[inline]
15+
pub fn new(storage: Storage) -> Self {
16+
Self {
17+
storage,
18+
align: [],
19+
}
20+
}
21+
22+
#[inline]
23+
pub fn get_bit(&self, index: usize) -> bool {
24+
debug_assert!(index / 8 < self.storage.as_ref().len());
25+
26+
let byte_index = self.storage.as_ref().len() - (index / 8) - 1;
27+
let byte = self.storage.as_ref()[byte_index];
28+
29+
let bit_index = index % 8;
30+
let mask = 1 << bit_index;
31+
32+
byte & mask == mask
33+
}
34+
35+
#[inline]
36+
pub fn set_bit(&mut self, index: usize, val: bool) {
37+
debug_assert!(index / 8 < self.storage.as_ref().len());
38+
39+
let byte_index = self.storage.as_ref().len() - (index / 8) - 1;
40+
let byte = &mut self.storage.as_mut()[byte_index];
41+
42+
let bit_index = index % 8;
43+
let mask = 1 << bit_index;
44+
45+
if val {
46+
*byte |= mask;
47+
} else {
48+
*byte &= !mask;
49+
}
50+
}
51+
52+
#[inline]
53+
pub fn get(&self, bit_offset: usize, bit_width: u8) -> u64 {
54+
debug_assert!(bit_width <= 64);
55+
debug_assert!(bit_offset / 8 < self.storage.as_ref().len());
56+
debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len());
57+
58+
let mut val = 0;
59+
60+
for i in 0..(bit_width as usize) {
61+
if self.get_bit(i + bit_offset) {
62+
val |= 1 << i;
63+
}
64+
}
65+
66+
val
67+
}
68+
69+
#[inline]
70+
pub fn set(&mut self, bit_offset: usize, bit_width: u8, val: u64) {
71+
debug_assert!(bit_width <= 64);
72+
debug_assert!(bit_offset / 8 < self.storage.as_ref().len());
73+
debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len());
74+
75+
for i in 0..(bit_width as usize) {
76+
let mask = 1 << i;
77+
let val_bit_is_set = val & mask == mask;
78+
self.set_bit(i + bit_offset, val_bit_is_set);
79+
}
80+
}
81+
}

src/codegen/bitfield_unit_tests.rs

+284
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
1+
//! Tests for `BindgenBitfieldUnit`.
2+
//!
3+
//! Note that bit-fields are allocated right to left (least to most significant
4+
//! bits).
5+
//!
6+
//! From the x86 PS ABI:
7+
//!
8+
//! ```c
9+
//! struct {
10+
//! int j : 5;
11+
//! int k : 6;
12+
//! int m : 7;
13+
//! };
14+
//! ```
15+
//!
16+
//! ```ignore
17+
//! +------------------------------------------------------------+
18+
//! | | | | |
19+
//! | padding | m | k | j |
20+
//! |31 18|17 11|10 5|4 0|
21+
//! +------------------------------------------------------------+
22+
//! ```
23+
24+
use super::bitfield_unit::BindgenBitfieldUnit;
25+
use std::mem;
26+
27+
#[test]
28+
fn bitfield_unit_get_bit() {
29+
let unit = BindgenBitfieldUnit::<[u8; 2], u64>::new([0b10011101, 0b00011101]);
30+
31+
let mut bits = vec![];
32+
for i in 0..16 {
33+
bits.push(unit.get_bit(i));
34+
}
35+
36+
println!();
37+
println!("bits = {:?}", bits);
38+
assert_eq!(bits, &[
39+
// 0b00011101
40+
true,
41+
false,
42+
true,
43+
true,
44+
true,
45+
false,
46+
false,
47+
false,
48+
49+
// 0b10011101
50+
true,
51+
false,
52+
true,
53+
true,
54+
true,
55+
false,
56+
false,
57+
true
58+
]);
59+
}
60+
61+
#[test]
62+
fn bitfield_unit_set_bit() {
63+
let mut unit = BindgenBitfieldUnit::<[u8; 2], u64>::new([0b00000000, 0b00000000]);
64+
65+
for i in 0..16 {
66+
if i % 3 == 0 {
67+
unit.set_bit(i, true);
68+
}
69+
}
70+
71+
for i in 0..16 {
72+
assert_eq!(unit.get_bit(i), i % 3 == 0);
73+
}
74+
75+
let mut unit = BindgenBitfieldUnit::<[u8; 2], u64>::new([0b11111111, 0b11111111]);
76+
77+
for i in 0..16 {
78+
if i % 3 == 0 {
79+
unit.set_bit(i, false);
80+
}
81+
}
82+
83+
for i in 0..16 {
84+
assert_eq!(unit.get_bit(i), i % 3 != 0);
85+
}
86+
}
87+
88+
#[test]
89+
fn bitfield_unit_align() {
90+
assert_eq!(mem::align_of::<BindgenBitfieldUnit<[u8; 1], u8>>(), mem::align_of::<u8>());
91+
assert_eq!(mem::align_of::<BindgenBitfieldUnit<[u8; 1], u16>>(), mem::align_of::<u16>());
92+
assert_eq!(mem::align_of::<BindgenBitfieldUnit<[u8; 1], u32>>(), mem::align_of::<u32>());
93+
assert_eq!(mem::align_of::<BindgenBitfieldUnit<[u8; 1], u64>>(), mem::align_of::<u64>());
94+
95+
assert_eq!(mem::align_of::<BindgenBitfieldUnit<[u8; 8], u8>>(), mem::align_of::<u8>());
96+
assert_eq!(mem::align_of::<BindgenBitfieldUnit<[u8; 8], u16>>(), mem::align_of::<u16>());
97+
assert_eq!(mem::align_of::<BindgenBitfieldUnit<[u8; 8], u32>>(), mem::align_of::<u32>());
98+
assert_eq!(mem::align_of::<BindgenBitfieldUnit<[u8; 8], u64>>(), mem::align_of::<u64>());
99+
}
100+
101+
macro_rules! bitfield_unit_get {
102+
(
103+
$(
104+
With $storage:expr , then get($start:expr, $len:expr) is $expected:expr;
105+
)*
106+
) => {
107+
#[test]
108+
fn bitfield_unit_get() {
109+
$({
110+
let expected = $expected;
111+
let unit = BindgenBitfieldUnit::<_, u64>::new($storage);
112+
let actual = unit.get($start, $len);
113+
114+
println!();
115+
println!("expected = {:064b}", expected);
116+
println!("actual = {:064b}", actual);
117+
118+
assert_eq!(expected, actual);
119+
})*
120+
}
121+
}
122+
}
123+
124+
bitfield_unit_get! {
125+
// Let's just exhaustively test getting the bits from a single byte, since
126+
// there are few enough combinations...
127+
128+
With [0b11100010], then get(0, 1) is 0;
129+
With [0b11100010], then get(1, 1) is 1;
130+
With [0b11100010], then get(2, 1) is 0;
131+
With [0b11100010], then get(3, 1) is 0;
132+
With [0b11100010], then get(4, 1) is 0;
133+
With [0b11100010], then get(5, 1) is 1;
134+
With [0b11100010], then get(6, 1) is 1;
135+
With [0b11100010], then get(7, 1) is 1;
136+
137+
With [0b11100010], then get(0, 2) is 0b10;
138+
With [0b11100010], then get(1, 2) is 0b01;
139+
With [0b11100010], then get(2, 2) is 0b00;
140+
With [0b11100010], then get(3, 2) is 0b00;
141+
With [0b11100010], then get(4, 2) is 0b10;
142+
With [0b11100010], then get(5, 2) is 0b11;
143+
With [0b11100010], then get(6, 2) is 0b11;
144+
145+
With [0b11100010], then get(0, 3) is 0b010;
146+
With [0b11100010], then get(1, 3) is 0b001;
147+
With [0b11100010], then get(2, 3) is 0b000;
148+
With [0b11100010], then get(3, 3) is 0b100;
149+
With [0b11100010], then get(4, 3) is 0b110;
150+
With [0b11100010], then get(5, 3) is 0b111;
151+
152+
With [0b11100010], then get(0, 4) is 0b0010;
153+
With [0b11100010], then get(1, 4) is 0b0001;
154+
With [0b11100010], then get(2, 4) is 0b1000;
155+
With [0b11100010], then get(3, 4) is 0b1100;
156+
With [0b11100010], then get(4, 4) is 0b1110;
157+
158+
With [0b11100010], then get(0, 5) is 0b00010;
159+
With [0b11100010], then get(1, 5) is 0b10001;
160+
With [0b11100010], then get(2, 5) is 0b11000;
161+
With [0b11100010], then get(3, 5) is 0b11100;
162+
163+
With [0b11100010], then get(0, 6) is 0b100010;
164+
With [0b11100010], then get(1, 6) is 0b110001;
165+
With [0b11100010], then get(2, 6) is 0b111000;
166+
167+
With [0b11100010], then get(0, 7) is 0b1100010;
168+
With [0b11100010], then get(1, 7) is 0b1110001;
169+
170+
With [0b11100010], then get(0, 8) is 0b11100010;
171+
172+
// OK. Now let's test getting bits from across byte boundaries.
173+
174+
With [0b01010101, 0b11111111, 0b00000000, 0b11111111],
175+
then get(0, 16) is 0b0000000011111111;
176+
177+
With [0b01010101, 0b11111111, 0b00000000, 0b11111111],
178+
then get(1, 16) is 0b1000000001111111;
179+
180+
With [0b01010101, 0b11111111, 0b00000000, 0b11111111],
181+
then get(2, 16) is 0b1100000000111111;
182+
183+
With [0b01010101, 0b11111111, 0b00000000, 0b11111111],
184+
then get(3, 16) is 0b1110000000011111;
185+
186+
With [0b01010101, 0b11111111, 0b00000000, 0b11111111],
187+
then get(4, 16) is 0b1111000000001111;
188+
189+
With [0b01010101, 0b11111111, 0b00000000, 0b11111111],
190+
then get(5, 16) is 0b1111100000000111;
191+
192+
With [0b01010101, 0b11111111, 0b00000000, 0b11111111],
193+
then get(6, 16) is 0b1111110000000011;
194+
195+
With [0b01010101, 0b11111111, 0b00000000, 0b11111111],
196+
then get(7, 16) is 0b1111111000000001;
197+
198+
With [0b01010101, 0b11111111, 0b00000000, 0b11111111],
199+
then get(8, 16) is 0b1111111100000000;
200+
}
201+
202+
macro_rules! bitfield_unit_set {
203+
(
204+
$(
205+
set($start:expr, $len:expr, $val:expr) is $expected:expr;
206+
)*
207+
) => {
208+
#[test]
209+
fn bitfield_unit_set() {
210+
$(
211+
let mut unit = BindgenBitfieldUnit::<[u8; 4], u64>::new([0, 0, 0, 0]);
212+
unit.set($start, $len, $val);
213+
let actual = unit.get(0, 32);
214+
215+
println!();
216+
println!("set({}, {}, {:032b}", $start, $len, $val);
217+
println!("expected = {:064b}", $expected);
218+
println!("actual = {:064b}", actual);
219+
220+
assert_eq!($expected, actual);
221+
)*
222+
}
223+
}
224+
}
225+
226+
bitfield_unit_set! {
227+
// Once again, let's exhaustively test single byte combinations.
228+
229+
set(0, 1, 0b11111111) is 0b00000001;
230+
set(1, 1, 0b11111111) is 0b00000010;
231+
set(2, 1, 0b11111111) is 0b00000100;
232+
set(3, 1, 0b11111111) is 0b00001000;
233+
set(4, 1, 0b11111111) is 0b00010000;
234+
set(5, 1, 0b11111111) is 0b00100000;
235+
set(6, 1, 0b11111111) is 0b01000000;
236+
set(7, 1, 0b11111111) is 0b10000000;
237+
238+
set(0, 2, 0b11111111) is 0b00000011;
239+
set(1, 2, 0b11111111) is 0b00000110;
240+
set(2, 2, 0b11111111) is 0b00001100;
241+
set(3, 2, 0b11111111) is 0b00011000;
242+
set(4, 2, 0b11111111) is 0b00110000;
243+
set(5, 2, 0b11111111) is 0b01100000;
244+
set(6, 2, 0b11111111) is 0b11000000;
245+
246+
set(0, 3, 0b11111111) is 0b00000111;
247+
set(1, 3, 0b11111111) is 0b00001110;
248+
set(2, 3, 0b11111111) is 0b00011100;
249+
set(3, 3, 0b11111111) is 0b00111000;
250+
set(4, 3, 0b11111111) is 0b01110000;
251+
set(5, 3, 0b11111111) is 0b11100000;
252+
253+
set(0, 4, 0b11111111) is 0b00001111;
254+
set(1, 4, 0b11111111) is 0b00011110;
255+
set(2, 4, 0b11111111) is 0b00111100;
256+
set(3, 4, 0b11111111) is 0b01111000;
257+
set(4, 4, 0b11111111) is 0b11110000;
258+
259+
set(0, 5, 0b11111111) is 0b00011111;
260+
set(1, 5, 0b11111111) is 0b00111110;
261+
set(2, 5, 0b11111111) is 0b01111100;
262+
set(3, 5, 0b11111111) is 0b11111000;
263+
264+
set(0, 6, 0b11111111) is 0b00111111;
265+
set(1, 6, 0b11111111) is 0b01111110;
266+
set(2, 6, 0b11111111) is 0b11111100;
267+
268+
set(0, 7, 0b11111111) is 0b01111111;
269+
set(1, 7, 0b11111111) is 0b11111110;
270+
271+
set(0, 8, 0b11111111) is 0b11111111;
272+
273+
// And, now let's cross byte boundaries.
274+
275+
set(0, 16, 0b1111111111111111) is 0b00000000000000001111111111111111;
276+
set(1, 16, 0b1111111111111111) is 0b00000000000000011111111111111110;
277+
set(2, 16, 0b1111111111111111) is 0b00000000000000111111111111111100;
278+
set(3, 16, 0b1111111111111111) is 0b00000000000001111111111111111000;
279+
set(4, 16, 0b1111111111111111) is 0b00000000000011111111111111110000;
280+
set(5, 16, 0b1111111111111111) is 0b00000000000111111111111111100000;
281+
set(6, 16, 0b1111111111111111) is 0b00000000001111111111111111000000;
282+
set(7, 16, 0b1111111111111111) is 0b00000000011111111111111110000000;
283+
set(8, 16, 0b1111111111111111) is 0b00000000111111111111111100000000;
284+
}

src/codegen/mod.rs

+6
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ mod error;
44
mod helpers;
55
pub mod struct_layout;
66

7+
#[cfg(test)]
8+
#[allow(warnings)]
9+
pub(crate) mod bitfield_unit;
10+
#[cfg(test)]
11+
mod bitfield_unit_tests;
12+
713
use self::helpers::attributes;
814
use self::struct_layout::StructLayoutTracker;
915

0 commit comments

Comments
 (0)