1 // RUN: %clang_cc1 -emit-llvm -triple x86_64 -O3 -o %t.opt.ll %s \ 2 // RUN: -fdump-record-layouts > %t.dump.txt 3 // RUN: FileCheck -check-prefix=CHECK-RECORD < %t.dump.txt %s 4 // RUN: FileCheck -check-prefix=CHECK-OPT < %t.opt.ll %s 5 6 /****/ 7 8 // Check that we don't read off the end a packed 24-bit structure. 9 // PR6176 10 11 // CHECK-RECORD: *** Dumping IRgen Record Layout 12 // CHECK-RECORD: Record: RecordDecl{{.*}}s0 13 // CHECK-RECORD: Layout: <CGRecordLayout 14 // CHECK-RECORD: LLVMType:%struct.s0 = type <{ [3 x i8] }> 15 // CHECK-RECORD: IsZeroInitializable:1 16 // CHECK-RECORD: BitFields:[ 17 // CHECK-RECORD: <CGBitFieldInfo Offset:0 Size:24 IsSigned:1 StorageSize:24 StorageAlignment:1> 18 struct __attribute((packed)) s0 { 19 int f0 : 24; 20 }; 21 22 struct s0 g0 = { 0xdeadbeef }; 23 24 int f0_load(struct s0 *a0) { 25 int size_check[sizeof(struct s0) == 3 ? 1 : -1]; 26 return a0->f0; 27 } 28 int f0_store(struct s0 *a0) { 29 return (a0->f0 = 1); 30 } 31 int f0_reload(struct s0 *a0) { 32 return (a0->f0 += 1); 33 } 34 35 // CHECK-OPT: define i64 @test_0() 36 // CHECK-OPT: ret i64 1 37 // CHECK-OPT: } 38 unsigned long long test_0() { 39 struct s0 g0 = { 0xdeadbeef }; 40 unsigned long long res = 0; 41 res ^= g0.f0; 42 res ^= f0_load(&g0) ^ f0_store(&g0) ^ f0_reload(&g0); 43 res ^= g0.f0; 44 return res; 45 } 46 47 /****/ 48 49 // PR5591 50 51 // CHECK-RECORD: *** Dumping IRgen Record Layout 52 // CHECK-RECORD: Record: RecordDecl{{.*}}s1 53 // CHECK-RECORD: Layout: <CGRecordLayout 54 // CHECK-RECORD: LLVMType:%struct.s1 = type <{ [3 x i8] }> 55 // CHECK-RECORD: IsZeroInitializable:1 56 // CHECK-RECORD: BitFields:[ 57 // CHECK-RECORD: <CGBitFieldInfo Offset:0 Size:10 IsSigned:1 StorageSize:24 StorageAlignment:1> 58 // CHECK-RECORD: <CGBitFieldInfo Offset:10 Size:10 IsSigned:1 StorageSize:24 StorageAlignment:1> 59 60 #pragma pack(push) 61 #pragma pack(1) 62 struct __attribute((packed)) s1 { 63 signed f0 : 10; 64 signed f1 : 10; 65 }; 66 #pragma pack(pop) 67 68 struct s1 g1 = { 0xdeadbeef, 0xdeadbeef }; 69 70 int f1_load(struct s1 *a0) { 71 int size_check[sizeof(struct s1) == 3 ? 1 : -1]; 72 return a0->f1; 73 } 74 int f1_store(struct s1 *a0) { 75 return (a0->f1 = 1234); 76 } 77 int f1_reload(struct s1 *a0) { 78 return (a0->f1 += 1234); 79 } 80 81 // CHECK-OPT: define i64 @test_1() 82 // CHECK-OPT: ret i64 210 83 // CHECK-OPT: } 84 unsigned long long test_1() { 85 struct s1 g1 = { 0xdeadbeef, 0xdeadbeef }; 86 unsigned long long res = 0; 87 res ^= g1.f0 ^ g1.f1; 88 res ^= f1_load(&g1) ^ f1_store(&g1) ^ f1_reload(&g1); 89 res ^= g1.f0 ^ g1.f1; 90 return res; 91 } 92 93 /****/ 94 95 // Check that we don't access beyond the bounds of a union. 96 // 97 // PR5567 98 99 // CHECK-RECORD: *** Dumping IRgen Record Layout 100 // CHECK-RECORD: Record: RecordDecl{{.*}}u2 101 // CHECK-RECORD: Layout: <CGRecordLayout 102 // CHECK-RECORD: LLVMType:%union.u2 = type <{ i8 }> 103 // CHECK-RECORD: IsZeroInitializable:1 104 // CHECK-RECORD: BitFields:[ 105 // CHECK-RECORD: <CGBitFieldInfo Offset:0 Size:3 IsSigned:0 StorageSize:8 StorageAlignment:1> 106 107 union __attribute__((packed)) u2 { 108 unsigned long long f0 : 3; 109 }; 110 111 union u2 g2 = { 0xdeadbeef }; 112 113 int f2_load(union u2 *a0) { 114 return a0->f0; 115 } 116 int f2_store(union u2 *a0) { 117 return (a0->f0 = 1234); 118 } 119 int f2_reload(union u2 *a0) { 120 return (a0->f0 += 1234); 121 } 122 123 // CHECK-OPT: define i64 @test_2() 124 // CHECK-OPT: ret i64 2 125 // CHECK-OPT: } 126 unsigned long long test_2() { 127 union u2 g2 = { 0xdeadbeef }; 128 unsigned long long res = 0; 129 res ^= g2.f0; 130 res ^= f2_load(&g2) ^ f2_store(&g2) ^ f2_reload(&g2); 131 res ^= g2.f0; 132 return res; 133 } 134 135 /***/ 136 137 // PR5039 138 139 struct s3 { 140 long long f0 : 32; 141 long long f1 : 32; 142 }; 143 144 struct s3 g3 = { 0xdeadbeef, 0xdeadbeef }; 145 146 int f3_load(struct s3 *a0) { 147 a0->f0 = 1; 148 return a0->f0; 149 } 150 int f3_store(struct s3 *a0) { 151 a0->f0 = 1; 152 return (a0->f0 = 1234); 153 } 154 int f3_reload(struct s3 *a0) { 155 a0->f0 = 1; 156 return (a0->f0 += 1234); 157 } 158 159 // CHECK-OPT: define i64 @test_3() 160 // CHECK-OPT: ret i64 -559039940 161 // CHECK-OPT: } 162 unsigned long long test_3() { 163 struct s3 g3 = { 0xdeadbeef, 0xdeadbeef }; 164 unsigned long long res = 0; 165 res ^= g3.f0 ^ g3.f1; 166 res ^= f3_load(&g3) ^ f3_store(&g3) ^ f3_reload(&g3); 167 res ^= g3.f0 ^ g3.f1; 168 return res; 169 } 170 171 /***/ 172 173 // This is a case where the bitfield access will straddle an alignment boundary 174 // of its underlying type. 175 176 struct s4 { 177 unsigned f0 : 16; 178 unsigned f1 : 28 __attribute__ ((packed)); 179 }; 180 181 struct s4 g4 = { 0xdeadbeef, 0xdeadbeef }; 182 183 int f4_load(struct s4 *a0) { 184 return a0->f0 ^ a0->f1; 185 } 186 int f4_store(struct s4 *a0) { 187 return (a0->f0 = 1234) ^ (a0->f1 = 5678); 188 } 189 int f4_reload(struct s4 *a0) { 190 return (a0->f0 += 1234) ^ (a0->f1 += 5678); 191 } 192 193 // CHECK-OPT: define i64 @test_4() 194 // CHECK-OPT: ret i64 4860 195 // CHECK-OPT: } 196 unsigned long long test_4() { 197 struct s4 g4 = { 0xdeadbeef, 0xdeadbeef }; 198 unsigned long long res = 0; 199 res ^= g4.f0 ^ g4.f1; 200 res ^= f4_load(&g4) ^ f4_store(&g4) ^ f4_reload(&g4); 201 res ^= g4.f0 ^ g4.f1; 202 return res; 203 } 204 205 /***/ 206 207 struct s5 { 208 unsigned f0 : 2; 209 _Bool f1 : 1; 210 _Bool f2 : 1; 211 }; 212 213 struct s5 g5 = { 0xdeadbeef, 0xdeadbeef }; 214 215 int f5_load(struct s5 *a0) { 216 return a0->f0 ^ a0->f1; 217 } 218 int f5_store(struct s5 *a0) { 219 return (a0->f0 = 0xF) ^ (a0->f1 = 0xF) ^ (a0->f2 = 0xF); 220 } 221 int f5_reload(struct s5 *a0) { 222 return (a0->f0 += 0xF) ^ (a0->f1 += 0xF) ^ (a0->f2 += 0xF); 223 } 224 225 // CHECK-OPT: define i64 @test_5() 226 // CHECK-OPT: ret i64 2 227 // CHECK-OPT: } 228 unsigned long long test_5() { 229 struct s5 g5 = { 0xdeadbeef, 0xdeadbeef, 0xdeadbeef }; 230 unsigned long long res = 0; 231 res ^= g5.f0 ^ g5.f1 ^ g5.f2; 232 res ^= f5_load(&g5) ^ f5_store(&g5) ^ f5_reload(&g5); 233 res ^= g5.f0 ^ g5.f1 ^ g5.f2; 234 return res; 235 } 236 237 /***/ 238 239 struct s6 { 240 _Bool f0 : 2; 241 }; 242 243 struct s6 g6 = { 0xF }; 244 245 int f6_load(struct s6 *a0) { 246 return a0->f0; 247 } 248 int f6_store(struct s6 *a0) { 249 return a0->f0 = 0x0; 250 } 251 int f6_reload(struct s6 *a0) { 252 return (a0->f0 += 0xF); 253 } 254 255 // CHECK-OPT: define zeroext i1 @test_6() 256 // CHECK-OPT: ret i1 true 257 // CHECK-OPT: } 258 _Bool test_6() { 259 struct s6 g6 = { 0xF }; 260 unsigned long long res = 0; 261 res ^= g6.f0; 262 res ^= f6_load(&g6); 263 res ^= g6.f0; 264 return res; 265 } 266 267 /***/ 268 269 // Check that we compute the best alignment possible for each access. 270 // 271 // CHECK-RECORD: *** Dumping IRgen Record Layout 272 // CHECK-RECORD: Record: RecordDecl{{.*}}s7 273 // CHECK-RECORD: Layout: <CGRecordLayout 274 // CHECK-RECORD: LLVMType:%struct.s7 = type { i32, i32, i32, i8, [3 x i8], [4 x i8], [12 x i8] } 275 // CHECK-RECORD: IsZeroInitializable:1 276 // CHECK-RECORD: BitFields:[ 277 // CHECK-RECORD: <CGBitFieldInfo Offset:0 Size:5 IsSigned:1 StorageSize:8 StorageAlignment:4> 278 // CHECK-RECORD: <CGBitFieldInfo Offset:0 Size:29 IsSigned:1 StorageSize:32 StorageAlignment:16> 279 280 struct __attribute__((aligned(16))) s7 { 281 int a, b, c; 282 int f0 : 5; 283 int f1 : 29; 284 }; 285 286 int f7_load(struct s7 *a0) { 287 return a0->f0; 288 } 289 290 /***/ 291 292 // This is a case where we narrow the access width immediately. 293 294 struct __attribute__((packed)) s8 { 295 char f0 : 4; 296 char f1; 297 int f2 : 4; 298 char f3 : 4; 299 }; 300 301 struct s8 g8 = { 0xF }; 302 303 int f8_load(struct s8 *a0) { 304 return a0->f0 ^ a0 ->f2 ^ a0->f3; 305 } 306 int f8_store(struct s8 *a0) { 307 return (a0->f0 = 0xFD) ^ (a0->f2 = 0xFD) ^ (a0->f3 = 0xFD); 308 } 309 int f8_reload(struct s8 *a0) { 310 return (a0->f0 += 0xFD) ^ (a0->f2 += 0xFD) ^ (a0->f3 += 0xFD); 311 } 312 313 // CHECK-OPT: define i32 @test_8() 314 // CHECK-OPT: ret i32 -3 315 // CHECK-OPT: } 316 unsigned test_8() { 317 struct s8 g8 = { 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef }; 318 unsigned long long res = 0; 319 res ^= g8.f0 ^ g8.f2 ^ g8.f3; 320 res ^= f8_load(&g8) ^ f8_store(&g8) ^ f8_reload(&g8); 321 res ^= g8.f0 ^ g8.f2 ^ g8.f3; 322 return res; 323 } 324 325 /***/ 326 327 // This is another case where we narrow the access width immediately. 328 // 329 // <rdar://problem/7893760> 330 331 struct __attribute__((packed)) s9 { 332 unsigned f0 : 7; 333 unsigned f1 : 7; 334 unsigned f2 : 7; 335 unsigned f3 : 7; 336 unsigned f4 : 7; 337 unsigned f5 : 7; 338 unsigned f6 : 7; 339 unsigned f7 : 7; 340 }; 341 342 int f9_load(struct s9 *a0) { 343 return a0->f7; 344 } 345