Skip to content

Commit 4671b7d

Browse files
author
Daniel Kroening
committed
Visual Studio packs bit-fields differently
1 parent ae1d039 commit 4671b7d

File tree

5 files changed

+164
-35
lines changed

5 files changed

+164
-35
lines changed

appveyor.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,6 @@ test_script:
7070
rmdir /s /q ansi-c\arch_flags_mthumb_good
7171
rmdir /s /q ansi-c\Forward_Declaration2
7272
rmdir /s /q ansi-c\Incomplete_Type1
73-
rmdir /s /q ansi-c\Union_Padding1
7473
rmdir /s /q ansi-c\Universal_characters1
7574
rmdir /s /q ansi-c\function_return1
7675
rmdir /s /q ansi-c\gcc_attributes7

buildspec-windows.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ phases:
3434
Remove-Item ansi-c\arch_flags_mthumb_good -Force -Recurse
3535
Remove-Item ansi-c\Forward_Declaration2 -Force -Recurse
3636
Remove-Item ansi-c\Incomplete_Type1 -Force -Recurse
37-
Remove-Item ansi-c\Union_Padding1 -Force -Recurse
3837
Remove-Item ansi-c\Universal_characters1 -Force -Recurse
3938
Remove-Item ansi-c\function_return1 -Force -Recurse
4039
Remove-Item ansi-c\gcc_attributes7 -Force -Recurse

regression/ansi-c/Struct_Padding5/main.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,46 @@ STATIC_ASSERT(sizeof(struct flowi)==8);
2828
STATIC_ASSERT(__builtin_offsetof(struct flowi, flexible)==1);
2929
#endif
3030

31+
// bit-fields are very evil
32+
#pragma pack(push, 1)
33+
struct bit_field0
34+
{
35+
int i : 23;
36+
};
37+
38+
struct bit_field1
39+
{
40+
int i : 1;
41+
unsigned int j : 1;
42+
// in MSC, it matters that the underlying type changes!
43+
short c : 1;
44+
};
45+
46+
struct bit_field2
47+
{
48+
int i : 23;
49+
char ch;
50+
};
51+
#pragma pack(pop)
52+
53+
struct bit_field3
54+
{
55+
int i : 23;
56+
char ch;
57+
};
58+
59+
#ifdef _MSC_VER
60+
STATIC_ASSERT(sizeof(struct bit_field0) == 4);
61+
STATIC_ASSERT(sizeof(struct bit_field1) == 6);
62+
STATIC_ASSERT(sizeof(struct bit_field2) == 5);
63+
STATIC_ASSERT(sizeof(struct bit_field3) == 8);
64+
#else
65+
STATIC_ASSERT(sizeof(struct bit_field0) == 3);
66+
STATIC_ASSERT(sizeof(struct bit_field1) == 1);
67+
STATIC_ASSERT(sizeof(struct bit_field2) == 4);
68+
STATIC_ASSERT(sizeof(struct bit_field3) == 4);
69+
#endif
70+
3171
int main()
3272
{
3373
}

regression/ansi-c/Union_Padding1/main.c

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,16 @@ STATIC_ASSERT(sizeof(union some_union3)==sizeof(int));
4141
#ifdef _MSC_VER
4242

4343
// bit-fields are evil
44-
#pragma pack(1)
44+
#pragma pack(push, 1)
4545
union some_union4
4646
{
4747
int i:23;
4848
};
49+
#pragma pack(pop)
4950

5051
// Visual Studio ignores the 'packed'
5152
STATIC_ASSERT(sizeof(union some_union4)==sizeof(int));
53+
STATIC_ASSERT(__alignof(union some_union4) == 1);
5254

5355
#else
5456

@@ -59,34 +61,38 @@ union some_union4
5961
} __attribute__((__packed__));
6062

6163
STATIC_ASSERT(sizeof(union some_union4)==3);
64+
STATIC_ASSERT(_Alignof(union some_union4) == 1);
6265

6366
#endif
6467

65-
#ifdef _MSC_VER
66-
6768
union some_union5
6869
{
6970
int i;
7071
};
7172

72-
STATIC_ASSERT(__alignof(union some_union5)==1);
73-
73+
#ifdef _MSC_VER
74+
STATIC_ASSERT(__alignof(union some_union5) == 4);
7475
#else
76+
STATIC_ASSERT(_Alignof(union some_union5) == 4);
77+
#endif
7578

76-
union some_union5
77-
{
79+
#ifdef _MSC_VER
80+
#pragma pack(push, 1)
81+
union some_union6 {
7882
int i;
7983
};
84+
#pragma pack(pop)
8085

86+
// Packing may affect alignment
87+
STATIC_ASSERT(__alignof(union some_union6) == 1);
88+
#else
8189
union some_union6
8290
{
8391
int i;
8492
} __attribute__((__packed__));
8593

8694
// Packing may affect alignment
87-
STATIC_ASSERT(_Alignof(union some_union5)==4);
8895
STATIC_ASSERT(_Alignof(union some_union6)==1);
89-
9096
#endif
9197

9298
int main()

src/ansi-c/padding.cpp

Lines changed: 109 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -100,15 +100,98 @@ mp_integer alignment(const typet &type, const namespacet &ns)
100100
return result;
101101
}
102102

103-
void add_padding(struct_typet &type, const namespacet &ns)
103+
std::size_t underlying_width(const c_bit_field_typet &type)
104+
{
105+
return type.subtype().get_size_t(ID_width);
106+
}
107+
108+
struct_typet::componentst::iterator pad_bit_field(
109+
struct_typet::componentst &components,
110+
struct_typet::componentst::iterator where,
111+
std::size_t pad_bits)
112+
{
113+
c_bit_field_typet padding_type(unsignedbv_typet(pad_bits), pad_bits);
114+
115+
struct_typet::componentt component;
116+
component.type() = padding_type;
117+
component.set_name(
118+
"$bit_field_pad" + std::to_string(where - components.begin()));
119+
component.set_is_padding(true);
120+
121+
auto it = components.insert(where, component);
122+
it++;
123+
return it;
124+
}
125+
126+
void bit_field_padding(struct_typet &type, const namespacet &ns)
104127
{
105128
struct_typet::componentst &components=type.components();
106129

107-
// First do padding for bit-fields to make them
108-
// appear on byte boundaries.
130+
// bit-field padding depends greatly on compiler
131+
if(config.ansi_c.mode == configt::ansi_ct::flavourt::VISUAL_STUDIO)
132+
{
133+
std::size_t bit_field_bits = 0, underlying_bits = 0;
134+
135+
for(struct_typet::componentst::iterator it = components.begin();
136+
it != components.end();
137+
it++)
138+
{
139+
if(
140+
it->type().id() == ID_c_bit_field &&
141+
to_c_bit_field_type(it->type()).get_width() != 0)
142+
{
143+
const auto &bit_field_type = to_c_bit_field_type(it->type());
144+
145+
std::size_t new_underlying_bits = underlying_width(bit_field_type);
146+
147+
CHECK_RETURN(new_underlying_bits != 0);
148+
149+
if(underlying_bits == 0)
150+
{
151+
underlying_bits = new_underlying_bits;
152+
bit_field_bits = 0;
153+
}
154+
else if(new_underlying_bits != underlying_bits)
155+
{
156+
// new underlying width, we pad up
157+
if((bit_field_bits % underlying_bits) != 0)
158+
{
159+
std::size_t pad =
160+
underlying_bits - (bit_field_bits % underlying_bits);
161+
it = pad_bit_field(components, it, pad);
162+
}
163+
164+
underlying_bits = new_underlying_bits;
165+
bit_field_bits = 0;
166+
}
167+
168+
// count the bits
169+
std::size_t width = bit_field_type.get_width();
170+
bit_field_bits += width;
171+
}
172+
else
173+
{
174+
// pad up
175+
if(underlying_bits != 0 && (bit_field_bits % underlying_bits) != 0)
176+
{
177+
std::size_t pad =
178+
underlying_bits - (bit_field_bits % underlying_bits);
179+
it = pad_bit_field(components, it, pad);
180+
underlying_bits = bit_field_bits = 0;
181+
}
182+
}
183+
}
109184

185+
// Add padding at the end?
186+
if(underlying_bits != 0 && (bit_field_bits % underlying_bits) != 0)
187+
{
188+
std::size_t pad = underlying_bits - (bit_field_bits % underlying_bits);
189+
pad_bit_field(components, components.end(), pad);
190+
}
191+
}
192+
else
110193
{
111-
std::size_t padding_counter=0;
194+
// Make bit-fields appear on byte boundaries
112195
std::size_t bit_field_bits=0;
113196

114197
for(struct_typet::componentst::iterator
@@ -129,18 +212,7 @@ void add_padding(struct_typet &type, const namespacet &ns)
129212
if((bit_field_bits%8)!=0)
130213
{
131214
std::size_t pad=8-bit_field_bits%8;
132-
c_bit_field_typet padding_type(unsignedbv_typet(pad), pad);
133-
134-
struct_typet::componentt component;
135-
component.type()=padding_type;
136-
component.set_name(
137-
"$bit_field_pad"+std::to_string(padding_counter++));
138-
component.set_is_padding(true);
139-
140-
it=components.insert(it, component);
141-
it++; // skip over
142-
143-
bit_field_bits+=pad;
215+
it = pad_bit_field(components, it, pad);
144216
}
145217

146218
bit_field_bits=0;
@@ -151,16 +223,14 @@ void add_padding(struct_typet &type, const namespacet &ns)
151223
if((bit_field_bits%8)!=0)
152224
{
153225
std::size_t pad=8-bit_field_bits%8;
154-
c_bit_field_typet padding_type(unsignedbv_typet(pad), pad);
155-
156-
struct_typet::componentt component;
157-
component.type()=padding_type;
158-
component.set_name("$bit_field_pad"+std::to_string(padding_counter++));
159-
component.set_is_padding(true);
160-
161-
components.push_back(component);
226+
pad_bit_field(components, components.end(), pad);
162227
}
163228
}
229+
}
230+
231+
void add_padding(struct_typet &type, const namespacet &ns)
232+
{
233+
bit_field_padding(type, ns);
164234

165235
// Is the struct packed, without any alignment specification?
166236
if(type.get_bool(ID_C_packed) &&
@@ -172,6 +242,8 @@ void add_padding(struct_typet &type, const namespacet &ns)
172242
mp_integer max_alignment=0;
173243
std::size_t bit_field_bits=0;
174244

245+
struct_typet::componentst &components = type.components();
246+
175247
for(struct_typet::componentst::iterator
176248
it=components.begin();
177249
it!=components.end();
@@ -313,6 +385,19 @@ void add_padding(union_typet &type, const namespacet &ns)
313385
max_alignment_bits=8;
314386
}
315387

388+
if(config.ansi_c.mode == configt::ansi_ct::flavourt::VISUAL_STUDIO)
389+
{
390+
// Visual Studio pads up to the underlying width of
391+
// any bit field.
392+
for(const auto &c : type.components())
393+
if(c.type().id() == ID_c_bit_field)
394+
{
395+
std::size_t w = underlying_width(to_c_bit_field_type(c.type()));
396+
if(w > max_alignment_bits)
397+
max_alignment_bits = w;
398+
}
399+
}
400+
316401
// The size must be a multiple of the alignment, or
317402
// we add a padding member to the union.
318403

0 commit comments

Comments
 (0)