aboutsummaryrefslogtreecommitdiff
path: root/test/CodeGen/bitfield-2.c
blob: e91859fb728753cc258589f378c1f391c46542eb (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
// RUN: %clang_cc1 -emit-llvm -triple x86_64 -O3 -o %t.opt.ll %s \
// RUN:   -fdump-record-layouts 2> %t.dump.txt
// RUN: FileCheck -check-prefix=CHECK-RECORD < %t.dump.txt %s
// RUN: FileCheck -check-prefix=CHECK-OPT < %t.opt.ll %s

/****/

// Check that we don't read off the end a packed 24-bit structure.
// PR6176

// CHECK-RECORD: *** Dumping IRgen Record Layout
// CHECK-RECORD: Record: struct s0
// CHECK-RECORD: Layout: <CGRecordLayout
// CHECK-RECORD:   LLVMType:<{ [3 x i8] }>
// CHECK-RECORD:   ContainsPointerToDataMember:0
// CHECK-RECORD:   BitFields:[
// CHECK-RECORD:     <CGBitFieldInfo Size:24 IsSigned:1
// CHECK-RECORD:                     NumComponents:2 Components: [
// CHECK-RECORD:         <AccessInfo FieldIndex:0 FieldByteOffset:0 FieldBitStart:0 AccessWidth:16
// CHECK-RECORD:                     AccessAlignment:1 TargetBitOffset:0 TargetBitWidth:16>
// CHECK-RECORD:         <AccessInfo FieldIndex:0 FieldByteOffset:2 FieldBitStart:0 AccessWidth:8
// CHECK-RECORD:                     AccessAlignment:1 TargetBitOffset:16 TargetBitWidth:8>
struct __attribute((packed)) s0 {
  int f0 : 24;
};

struct s0 g0 = { 0xdeadbeef };

int f0_load(struct s0 *a0) {
  int size_check[sizeof(struct s0) == 3 ? 1 : -1];
  return a0->f0;
}
int f0_store(struct s0 *a0) {
  return (a0->f0 = 1);
}
int f0_reload(struct s0 *a0) {
  return (a0->f0 += 1);
}

// CHECK-OPT: define i64 @test_0()
// CHECK-OPT:  ret i64 1
// CHECK-OPT: }
unsigned long long test_0() {
  struct s0 g0 = { 0xdeadbeef };
  unsigned long long res = 0;
  res ^= g0.f0;
  res ^= f0_load(&g0) ^ f0_store(&g0) ^ f0_reload(&g0);
  res ^= g0.f0;
  return res;
}

/****/

// PR5591

// CHECK-RECORD: *** Dumping IRgen Record Layout
// CHECK-RECORD: Record: struct s1
// CHECK-RECORD: Layout: <CGRecordLayout
// CHECK-RECORD:   LLVMType:<{ [2 x i8], i8 }>
// CHECK-RECORD:   ContainsPointerToDataMember:0
// CHECK-RECORD:   BitFields:[
// CHECK-RECORD:     <CGBitFieldInfo Size:10 IsSigned:1
// CHECK-RECORD:                     NumComponents:1 Components: [
// CHECK-RECORD:         <AccessInfo FieldIndex:0 FieldByteOffset:0 FieldBitStart:0 AccessWidth:16
// CHECK-RECORD:                     AccessAlignment:1 TargetBitOffset:0 TargetBitWidth:10>
// CHECK-RECORD:     ]>
// CHECK-RECORD:     <CGBitFieldInfo Size:10 IsSigned:1
// CHECK-RECORD:                     NumComponents:2 Components: [
// CHECK-RECORD:         <AccessInfo FieldIndex:0 FieldByteOffset:0 FieldBitStart:10 AccessWidth:16
// CHECK-RECORD:                     AccessAlignment:1 TargetBitOffset:0 TargetBitWidth:6>
// CHECK-RECORD:         <AccessInfo FieldIndex:0 FieldByteOffset:2 FieldBitStart:0 AccessWidth:8
// CHECK-RECORD:                     AccessAlignment:1 TargetBitOffset:6 TargetBitWidth:4>

#pragma pack(push)
#pragma pack(1)
struct __attribute((packed)) s1 {
  signed f0 : 10;
  signed f1 : 10;
};
#pragma pack(pop)

struct s1 g1 = { 0xdeadbeef, 0xdeadbeef };

int f1_load(struct s1 *a0) {
  int size_check[sizeof(struct s1) == 3 ? 1 : -1];
  return a0->f1;
}
int f1_store(struct s1 *a0) {
  return (a0->f1 = 1234);
}
int f1_reload(struct s1 *a0) {
  return (a0->f1 += 1234);
}

// CHECK-OPT: define i64 @test_1()
// CHECK-OPT:  ret i64 210
// CHECK-OPT: }
unsigned long long test_1() {
  struct s1 g1 = { 0xdeadbeef, 0xdeadbeef };
  unsigned long long res = 0;
  res ^= g1.f0 ^ g1.f1;
  res ^= f1_load(&g1) ^ f1_store(&g1) ^ f1_reload(&g1);
  res ^= g1.f0 ^ g1.f1;
  return res;
}

/****/

// Check that we don't access beyond the bounds of a union.
//
// PR5567

// CHECK-RECORD: *** Dumping IRgen Record Layout
// CHECK-RECORD: Record: union u2
// CHECK-RECORD: Layout: <CGRecordLayout
// CHECK-RECORD:   LLVMType:<{ i8 }>
// CHECK-RECORD:   ContainsPointerToDataMember:0
// CHECK-RECORD:   BitFields:[
// CHECK-RECORD:     <CGBitFieldInfo Size:3 IsSigned:0
// CHECK-RECORD:                     NumComponents:1 Components: [
// CHECK-RECORD:         <AccessInfo FieldIndex:0 FieldByteOffset:0 FieldBitStart:0 AccessWidth:8
// CHECK-RECORD:                     AccessAlignment:1 TargetBitOffset:0 TargetBitWidth:3>

union __attribute__((packed)) u2 {
  unsigned long long f0 : 3;
};

union u2 g2 = { 0xdeadbeef };

int f2_load(union u2 *a0) {
  return a0->f0;
}
int f2_store(union u2 *a0) {
  return (a0->f0 = 1234);
}
int f2_reload(union u2 *a0) {
  return (a0->f0 += 1234);
}

// CHECK-OPT: define i64 @test_2()
// CHECK-OPT:  ret i64 2
// CHECK-OPT: }
unsigned long long test_2() {
  union u2 g2 = { 0xdeadbeef };
  unsigned long long res = 0;
  res ^= g2.f0;
  res ^= f2_load(&g2) ^ f2_store(&g2) ^ f2_reload(&g2);
  res ^= g2.f0;
  return res;
}

/***/

// PR5039

struct s3 {
  long long f0 : 32;
  long long f1 : 32;
};

struct s3 g3 = { 0xdeadbeef, 0xdeadbeef };

int f3_load(struct s3 *a0) {
  a0->f0 = 1;
  return a0->f0;
}
int f3_store(struct s3 *a0) {
  a0->f0 = 1;
  return (a0->f0 = 1234);
}
int f3_reload(struct s3 *a0) {
  a0->f0 = 1;
  return (a0->f0 += 1234);
}

// CHECK-OPT: define i64 @test_3()
// CHECK-OPT:  ret i64 -559039940
// CHECK-OPT: }
unsigned long long test_3() {
  struct s3 g3 = { 0xdeadbeef, 0xdeadbeef };
  unsigned long long res = 0;
  res ^= g3.f0 ^ g3.f1;
  res ^= f3_load(&g3) ^ f3_store(&g3) ^ f3_reload(&g3);
  res ^= g3.f0 ^ g3.f1;
  return res;
}

/***/

// This is a case where the bitfield access will straddle an alignment boundary
// of its underlying type.

struct s4 {
  unsigned f0 : 16;
  unsigned f1 : 28 __attribute__ ((packed));
};

struct s4 g4 = { 0xdeadbeef, 0xdeadbeef };

int f4_load(struct s4 *a0) {
  return a0->f0 ^ a0->f1;
}
int f4_store(struct s4 *a0) {
  return (a0->f0 = 1234) ^ (a0->f1 = 5678);
}
int f4_reload(struct s4 *a0) {
  return (a0->f0 += 1234) ^ (a0->f1 += 5678);
}

// CHECK-OPT: define i64 @test_4()
// CHECK-OPT:  ret i64 4860
// CHECK-OPT: }
unsigned long long test_4() {
  struct s4 g4 = { 0xdeadbeef, 0xdeadbeef };
  unsigned long long res = 0;
  res ^= g4.f0 ^ g4.f1;
  res ^= f4_load(&g4) ^ f4_store(&g4) ^ f4_reload(&g4);
  res ^= g4.f0 ^ g4.f1;
  return res;
}

/***/

struct s5 {
  unsigned f0 : 2;
  _Bool f1 : 1;
  _Bool f2 : 1;
};

struct s5 g5 = { 0xdeadbeef, 0xdeadbeef };

int f5_load(struct s5 *a0) {
  return a0->f0 ^ a0->f1;
}
int f5_store(struct s5 *a0) {
  return (a0->f0 = 0xF) ^ (a0->f1 = 0xF) ^ (a0->f2 = 0xF);
}
int f5_reload(struct s5 *a0) {
  return (a0->f0 += 0xF) ^ (a0->f1 += 0xF) ^ (a0->f2 += 0xF);
}

// CHECK-OPT: define i64 @test_5()
// CHECK-OPT:  ret i64 2
// CHECK-OPT: }
unsigned long long test_5() {
  struct s5 g5 = { 0xdeadbeef, 0xdeadbeef, 0xdeadbeef };
  unsigned long long res = 0;
  res ^= g5.f0 ^ g5.f1 ^ g5.f2;
  res ^= f5_load(&g5) ^ f5_store(&g5) ^ f5_reload(&g5);
  res ^= g5.f0 ^ g5.f1 ^ g5.f2;
  return res;
}

/***/

struct s6 {
  _Bool f0 : 2;
};

struct s6 g6 = { 0xF };

int f6_load(struct s6 *a0) {
  return a0->f0;
}
int f6_store(struct s6 *a0) {
  return a0->f0 = 0x0;
}
int f6_reload(struct s6 *a0) {
  return (a0->f0 += 0xF);
}

// CHECK-OPT: define zeroext i1 @test_6()
// CHECK-OPT:  ret i1 true
// CHECK-OPT: }
_Bool test_6() {
  struct s6 g6 = { 0xF };
  unsigned long long res = 0;
  res ^= g6.f0;
  res ^= f6_load(&g6);
  res ^= g6.f0;
  return res;
}

/***/

// Check that we compute the best alignment possible for each access.
//
// CHECK-RECORD: *** Dumping IRgen Record Layout
// CHECK-RECORD: Record: struct s7
// CHECK-RECORD: Layout: <CGRecordLayout
// CHECK-RECORD:   LLVMType:{ i32, i32, i32, i8, [3 x i8], [4 x i8], [12 x i8] }
// CHECK-RECORD:   ContainsPointerToDataMember:0
// CHECK-RECORD:   BitFields:[
// CHECK-RECORD:     <CGBitFieldInfo Size:5 IsSigned:1
// CHECK-RECORD:                     NumComponents:1 Components: [
// CHECK-RECORD:         <AccessInfo FieldIndex:0 FieldByteOffset:12 FieldBitStart:0 AccessWidth:32
// CHECK-RECORD:                     AccessAlignment:4 TargetBitOffset:0 TargetBitWidth:5>
// CHECK-RECORD:     ]>
// CHECK-RECORD:     <CGBitFieldInfo Size:29 IsSigned:1
// CHECK-RECORD:                     NumComponents:1 Components: [
// CHECK-RECORD:         <AccessInfo FieldIndex:0 FieldByteOffset:16 FieldBitStart:0 AccessWidth:32
// CHECK-RECORD:                     AccessAlignment:16 TargetBitOffset:0 TargetBitWidth:29>

struct __attribute__((aligned(16))) s7 {
  int a, b, c;
  int f0 : 5;
  int f1 : 29;
};

int f7_load(struct s7 *a0) {
  return a0->f0;
}

/***/

// This is a case where we narrow the access width immediately.

struct __attribute__((packed)) s8 {
  char f0 : 4;
  char f1;
  int  f2 : 4;
  char f3 : 4;
};

struct s8 g8 = { 0xF };

int f8_load(struct s8 *a0) {
  return a0->f0 ^ a0 ->f2 ^ a0->f3;
}
int f8_store(struct s8 *a0) {
  return (a0->f0 = 0xFD) ^ (a0->f2 = 0xFD) ^ (a0->f3 = 0xFD);
}
int f8_reload(struct s8 *a0) {
  return (a0->f0 += 0xFD) ^ (a0->f2 += 0xFD) ^ (a0->f3 += 0xFD);
}

// CHECK-OPT: define i32 @test_8()
// CHECK-OPT:  ret i32 -3
// CHECK-OPT: }
unsigned test_8() {
  struct s8 g8 = { 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef };
  unsigned long long res = 0;
  res ^= g8.f0 ^ g8.f2 ^ g8.f3;
  res ^= f8_load(&g8) ^ f8_store(&g8) ^ f8_reload(&g8);
  res ^= g8.f0 ^ g8.f2 ^ g8.f3;
  return res;
}

/***/

// This is another case where we narrow the access width immediately.
//
// <rdar://problem/7893760>

struct __attribute__((packed)) s9 {
  unsigned f0 : 7;
  unsigned f1 : 7;
  unsigned f2 : 7;
  unsigned f3 : 7;
  unsigned f4 : 7;
  unsigned f5 : 7;
  unsigned f6 : 7;
  unsigned f7 : 7;
};

int f9_load(struct s9 *a0) {
  return a0->f7;
}