540 lines · cpp
1// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fdump-record-layouts-simple \2// RUN: -emit-llvm -o %t %s | FileCheck -check-prefixes=LAYOUT,LAYOUT-X86-64 %s3// RUN: FileCheck -check-prefix=CHECK-X86-64 %s <%t4// RUN: %clang_cc1 -triple powerpc64-unknown-unknown -fdump-record-layouts-simple\5// RUN: -emit-llvm -o %t %s | FileCheck -check-prefixes=LAYOUT,LAYOUT-PPC64 %s6// RUN: FileCheck -check-prefix=CHECK-PPC64 %s <%t7//8// Tests for bitfield access patterns in C++ with special attention to9// conformance to C++11 memory model requirements.10 11namespace N0 {12 // Test basic bitfield layout access across interesting byte and word13 // boundaries on both little endian and big endian platforms.14 struct __attribute__((packed)) S {15 unsigned b00 : 14;16 unsigned b01 : 2;17 unsigned b20 : 6;18 unsigned b21 : 2;19 unsigned b30 : 30;20 unsigned b31 : 2;21 unsigned b70 : 6;22 unsigned b71 : 2;23 };24// LAYOUT-LABEL: LLVMType:%"struct.N0::S" =25// LAYOUT-SAME: type { i64 }26// LAYOUT: BitFields:[27// LAYOUT-X86-64-NEXT: <CGBitFieldInfo Offset:0 Size:14 IsSigned:0 StorageSize:64 StorageOffset:028// LAYOUT-X86-64-NEXT: <CGBitFieldInfo Offset:14 Size:2 IsSigned:0 StorageSize:64 StorageOffset:029// LAYOUT-X86-64-NEXT: <CGBitFieldInfo Offset:16 Size:6 IsSigned:0 StorageSize:64 StorageOffset:030// LAYOUT-X86-64-NEXT: <CGBitFieldInfo Offset:22 Size:2 IsSigned:0 StorageSize:64 StorageOffset:031// LAYOUT-X86-64-NEXT: <CGBitFieldInfo Offset:24 Size:30 IsSigned:0 StorageSize:64 StorageOffset:032// LAYOUT-X86-64-NEXT: <CGBitFieldInfo Offset:54 Size:2 IsSigned:0 StorageSize:64 StorageOffset:033// LAYOUT-X86-64-NEXT: <CGBitFieldInfo Offset:56 Size:6 IsSigned:0 StorageSize:64 StorageOffset:034// LAYOUT-X86-64-NEXT: <CGBitFieldInfo Offset:62 Size:2 IsSigned:0 StorageSize:64 StorageOffset:035// LAYOUT-PPC64-NEXT: <CGBitFieldInfo Offset:50 Size:14 IsSigned:0 StorageSize:64 StorageOffset:036// LAYOUT-PPC64-NEXT: <CGBitFieldInfo Offset:48 Size:2 IsSigned:0 StorageSize:64 StorageOffset:037// LAYOUT-PPC64-NEXT: <CGBitFieldInfo Offset:42 Size:6 IsSigned:0 StorageSize:64 StorageOffset:038// LAYOUT-PPC64-NEXT: <CGBitFieldInfo Offset:40 Size:2 IsSigned:0 StorageSize:64 StorageOffset:039// LAYOUT-PPC64-NEXT: <CGBitFieldInfo Offset:10 Size:30 IsSigned:0 StorageSize:64 StorageOffset:040// LAYOUT-PPC64-NEXT: <CGBitFieldInfo Offset:8 Size:2 IsSigned:0 StorageSize:64 StorageOffset:041// LAYOUT-PPC64-NEXT: <CGBitFieldInfo Offset:2 Size:6 IsSigned:0 StorageSize:64 StorageOffset:042// LAYOUT-PPC64-NEXT: <CGBitFieldInfo Offset:0 Size:2 IsSigned:0 StorageSize:64 StorageOffset:043// LAYOUT-NEXT: ]>44 45 unsigned read00(S* s) {46 // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N06read0047 // CHECK-X86-64: %[[val:.*]] = load i64, ptr %{{.*}}48 // CHECK-X86-64: %[[and:.*]] = and i64 %[[val]], 1638349 // CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[and]] to i3250 // CHECK-X86-64: ret i32 %[[trunc]]51 // CHECK-PPC64-LABEL: define{{.*}} zeroext i32 @_ZN2N06read0052 // CHECK-PPC64: %[[val:.*]] = load i64, ptr %{{.*}}53 // CHECK-PPC64: %[[shr:.*]] = lshr i64 %[[val]], 5054 // CHECK-PPC64: %[[trunc:.*]] = trunc i64 %[[shr]] to i3255 // CHECK-PPC64: ret i32 %[[trunc]]56 return s->b00;57 }58 unsigned read01(S* s) {59 // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N06read0160 // CHECK-X86-64: %[[val:.*]] = load i64, ptr %{{.*}}61 // CHECK-X86-64: %[[shr:.*]] = lshr i64 %[[val]], 1462 // CHECK-X86-64: %[[and:.*]] = and i64 %[[shr]], 363 // CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[and]] to i3264 // CHECK-X86-64: ret i32 %[[trunc]]65 // CHECK-PPC64-LABEL: define{{.*}} zeroext i32 @_ZN2N06read0166 // CHECK-PPC64: %[[val:.*]] = load i64, ptr %{{.*}}67 // CHECK-PPC64: %[[shr:.*]] = lshr i64 %[[val]], 4868 // CHECK-PPC64: %[[and:.*]] = and i64 %[[shr]], 369 // CHECK-PPC64: %[[trunc:.*]] = trunc i64 %[[and]] to i3270 // CHECK-PPC64: ret i32 %[[trunc]]71 return s->b01;72 }73 unsigned read20(S* s) {74 // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N06read2075 // CHECK-X86-64: %[[val:.*]] = load i64, ptr %{{.*}}76 // CHECK-X86-64: %[[shr:.*]] = lshr i64 %[[val]], 1677 // CHECK-X86-64: %[[and:.*]] = and i64 %[[shr]], 6378 // CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[and]] to i3279 // CHECK-X86-64: ret i32 %[[trunc]]80 // CHECK-PPC64-LABEL: define{{.*}} zeroext i32 @_ZN2N06read2081 // CHECK-PPC64: %[[val:.*]] = load i64, ptr %{{.*}}82 // CHECK-PPC64: %[[shr:.*]] = lshr i64 %[[val]], 4283 // CHECK-PPC64: %[[and:.*]] = and i64 %[[shr]], 6384 // CHECK-PPC64: %[[trunc:.*]] = trunc i64 %[[and]] to i3285 // CHECK-PPC64: ret i32 %[[trunc]]86 return s->b20;87 }88 unsigned read21(S* s) {89 // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N06read2190 // CHECK-X86-64: %[[val:.*]] = load i64, ptr %{{.*}}91 // CHECK-X86-64: %[[shr:.*]] = lshr i64 %[[val]], 2292 // CHECK-X86-64: %[[and:.*]] = and i64 %[[shr]], 393 // CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[and]] to i3294 // CHECK-X86-64: ret i32 %[[trunc]]95 // CHECK-PPC64-LABEL: define{{.*}} zeroext i32 @_ZN2N06read2196 // CHECK-PPC64: %[[val:.*]] = load i64, ptr %{{.*}}97 // CHECK-PPC64: %[[shr:.*]] = lshr i64 %[[val]], 4098 // CHECK-PPC64: %[[and:.*]] = and i64 %[[shr]], 399 // CHECK-PPC64: %[[trunc:.*]] = trunc i64 %[[and]] to i32100 // CHECK-PPC64: ret i32 %[[trunc]]101 return s->b21;102 }103 unsigned read30(S* s) {104 // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N06read30105 // CHECK-X86-64: %[[val:.*]] = load i64, ptr %{{.*}}106 // CHECK-X86-64: %[[shr:.*]] = lshr i64 %[[val]], 24107 // CHECK-X86-64: %[[and:.*]] = and i64 %[[shr]], 1073741823108 // CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[and]] to i32109 // CHECK-X86-64: ret i32 %[[trunc]]110 // CHECK-PPC64-LABEL: define{{.*}} zeroext i32 @_ZN2N06read30111 // CHECK-PPC64: %[[val:.*]] = load i64, ptr %{{.*}}112 // CHECK-PPC64: %[[shr:.*]] = lshr i64 %[[val]], 10113 // CHECK-PPC64: %[[and:.*]] = and i64 %[[shr]], 1073741823114 // CHECK-PPC64: %[[trunc:.*]] = trunc i64 %[[and]] to i32115 // CHECK-PPC64: ret i32 %[[trunc]]116 return s->b30;117 }118 unsigned read31(S* s) {119 // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N06read31120 // CHECK-X86-64: %[[val:.*]] = load i64, ptr %{{.*}}121 // CHECK-X86-64: %[[shr:.*]] = lshr i64 %[[val]], 54122 // CHECK-X86-64: %[[and:.*]] = and i64 %[[shr]], 3123 // CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[and]] to i32124 // CHECK-X86-64: ret i32 %[[trunc]]125 // CHECK-PPC64-LABEL: define{{.*}} zeroext i32 @_ZN2N06read31126 // CHECK-PPC64: %[[val:.*]] = load i64, ptr %{{.*}}127 // CHECK-PPC64: %[[shr:.*]] = lshr i64 %[[val]], 8128 // CHECK-PPC64: %[[and:.*]] = and i64 %[[shr]], 3129 // CHECK-PPC64: %[[trunc:.*]] = trunc i64 %[[and]] to i32130 // CHECK-PPC64: ret i32 %[[trunc]]131 return s->b31;132 }133 unsigned read70(S* s) {134 // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N06read70135 // CHECK-X86-64: %[[val:.*]] = load i64, ptr %{{.*}}136 // CHECK-X86-64: %[[shr:.*]] = lshr i64 %[[val]], 56137 // CHECK-X86-64: %[[and:.*]] = and i64 %[[shr]], 63138 // CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[and]] to i32139 // CHECK-X86-64: ret i32 %[[trunc]]140 // CHECK-PPC64-LABEL: define{{.*}} zeroext i32 @_ZN2N06read70141 // CHECK-PPC64: %[[val:.*]] = load i64, ptr %{{.*}}142 // CHECK-PPC64: %[[shr:.*]] = lshr i64 %[[val]], 2143 // CHECK-PPC64: %[[and:.*]] = and i64 %[[shr]], 63144 // CHECK-PPC64: %[[trunc:.*]] = trunc i64 %[[and]] to i32145 // CHECK-PPC64: ret i32 %[[trunc]]146 return s->b70;147 }148 unsigned read71(S* s) {149 // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N06read71150 // CHECK-X86-64: %[[val:.*]] = load i64, ptr %{{.*}}151 // CHECK-X86-64: %[[shr:.*]] = lshr i64 %[[val]], 62152 // CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[shr]] to i32153 // CHECK-X86-64: ret i32 %[[trunc]]154 // CHECK-PPC64-LABEL: define{{.*}} zeroext i32 @_ZN2N06read71155 // CHECK-PPC64: %[[val:.*]] = load i64, ptr %{{.*}}156 // CHECK-PPC64: %[[and:.*]] = and i64 %[[val]], 3157 // CHECK-PPC64: %[[trunc:.*]] = trunc i64 %[[and]] to i32158 // CHECK-PPC64: ret i32 %[[trunc]]159 return s->b71;160 }161}162 163namespace N1 {164 // Ensure that neither loads nor stores to bitfields are not widened into165 // other memory locations. (PR13691)166 //167 // NOTE: We could potentially widen loads based on their alignment if we are168 // comfortable requiring that subsequent memory locations within the169 // alignment-widened load are not volatile.170 struct S {171 char a;172 unsigned b : 1;173 char c;174 };175// LAYOUT-LABEL: LLVMType:%"struct.N1::S" =176// LAYOUT-SAME: type { i8, i8, i8, i8 }177// LAYOUT: BitFields:[178// LAYOUT-X86-64-NEXT: <CGBitFieldInfo Offset:0 Size:1 IsSigned:0 StorageSize:8 StorageOffset:1179// LAYOUT-PPC64-NEXT: <CGBitFieldInfo Offset:7 Size:1 IsSigned:0 StorageSize:8 StorageOffset:1180// LAYOUT-NEXT: ]>181 182 unsigned read(S* s) {183 // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N14read184 // CHECK-X86-64: %[[ptr:.*]] = getelementptr inbounds nuw %{{.*}}, ptr %{{.*}}, i32 0, i32 1185 // CHECK-X86-64: %[[val:.*]] = load i8, ptr %[[ptr]]186 // CHECK-X86-64: %[[and:.*]] = and i8 %[[val]], 1187 // CHECK-X86-64: %[[ext:.*]] = zext i8 %[[and]] to i32188 // CHECK-X86-64: ret i32 %[[ext]]189 // CHECK-PPC64-LABEL: define{{.*}} zeroext i32 @_ZN2N14read190 // CHECK-PPC64: %[[ptr:.*]] = getelementptr inbounds nuw %{{.*}}, ptr %{{.*}}, i32 0, i32 1191 // CHECK-PPC64: %[[val:.*]] = load i8, ptr %[[ptr]]192 // CHECK-PPC64: %[[shr:.*]] = lshr i8 %[[val]], 7193 // CHECK-PPC64: %[[ext:.*]] = zext i8 %[[shr]] to i32194 // CHECK-PPC64: ret i32 %[[ext]]195 return s->b;196 }197 void write(S* s, unsigned x) {198 // CHECK-X86-64-LABEL: define{{.*}} void @_ZN2N15write199 // CHECK-X86-64: %[[ptr:.*]] = getelementptr inbounds nuw %{{.*}}, ptr %{{.*}}, i32 0, i32 1200 // CHECK-X86-64: %[[x_trunc:.*]] = trunc i32 %{{.*}} to i8201 // CHECK-X86-64: %[[old:.*]] = load i8, ptr %[[ptr]]202 // CHECK-X86-64: %[[x_and:.*]] = and i8 %[[x_trunc]], 1203 // CHECK-X86-64: %[[old_and:.*]] = and i8 %[[old]], -2204 // CHECK-X86-64: %[[new:.*]] = or i8 %[[old_and]], %[[x_and]]205 // CHECK-X86-64: store i8 %[[new]], ptr %[[ptr]]206 // CHECK-PPC64-LABEL: define{{.*}} void @_ZN2N15write207 // CHECK-PPC64: %[[ptr:.*]] = getelementptr inbounds nuw %{{.*}}, ptr %{{.*}}, i32 0, i32 1208 // CHECK-PPC64: %[[x_trunc:.*]] = trunc i32 %{{.*}} to i8209 // CHECK-PPC64: %[[old:.*]] = load i8, ptr %[[ptr]]210 // CHECK-PPC64: %[[x_and:.*]] = and i8 %[[x_trunc]], 1211 // CHECK-PPC64: %[[x_shl:.*]] = shl i8 %[[x_and]], 7212 // CHECK-PPC64: %[[old_and:.*]] = and i8 %[[old]], 127213 // CHECK-PPC64: %[[new:.*]] = or i8 %[[old_and]], %[[x_shl]]214 // CHECK-PPC64: store i8 %[[new]], ptr %[[ptr]]215 s->b = x;216 }217}218 219namespace N2 {220 // Do widen loads and stores to bitfields when those bitfields have padding221 // within the struct following them.222 struct S {223 unsigned b : 24;224 void *p;225 };226// LAYOUT-LABEL: LLVMType:%"struct.N2::S" =227// LAYOUT-SAME: type { i32, ptr }228// LAYOUT: BitFields:[229// LAYOUT-X86-64-NEXT: <CGBitFieldInfo Offset:0 Size:24 IsSigned:0 StorageSize:32 StorageOffset:0230// LAYOUT-PPC64-NEXT: <CGBitFieldInfo Offset:8 Size:24 IsSigned:0 StorageSize:32 StorageOffset:0231// LAYOUT-NEXT: ]>232 233 unsigned read(S* s) {234 // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N24read235 // CHECK-X86-64: %[[val:.*]] = load i32, ptr %{{.*}}236 // CHECK-X86-64: %[[and:.*]] = and i32 %[[val]], 16777215237 // CHECK-X86-64: ret i32 %[[and]]238 // CHECK-PPC64-LABEL: define{{.*}} zeroext i32 @_ZN2N24read239 // CHECK-PPC64: %[[val:.*]] = load i32, ptr %{{.*}}240 // CHECK-PPC64: %[[shr:.*]] = lshr i32 %[[val]], 8241 // CHECK-PPC64: ret i32 %[[shr]]242 return s->b;243 }244 void write(S* s, unsigned x) {245 // CHECK-X86-64-LABEL: define{{.*}} void @_ZN2N25write246 // CHECK-X86-64: %[[ptr:.*]] = load ptr, ptr %{{.*}}247 // CHECK-X86-64: %[[old:.*]] = load i32, ptr %[[ptr]]248 // CHECK-X86-64: %[[x_and:.*]] = and i32 %{{.*}}, 16777215249 // CHECK-X86-64: %[[old_and:.*]] = and i32 %[[old]], -16777216250 // CHECK-X86-64: %[[new:.*]] = or i32 %[[old_and]], %[[x_and]]251 // CHECK-X86-64: store i32 %[[new]], ptr %{{.*}}252 // CHECK-PPC64-LABEL: define{{.*}} void @_ZN2N25write253 // CHECK-PPC64: %[[ptr:.*]] = load ptr, ptr %{{.*}}254 // CHECK-PPC64: %[[old:.*]] = load i32, ptr %[[ptr]]255 // CHECK-PPC64: %[[x_and:.*]] = and i32 %{{.*}}, 16777215256 // CHECK-PPC64: %[[x_shl:.*]] = shl i32 %[[x_and]], 8257 // CHECK-PPC64: %[[old_and:.*]] = and i32 %[[old]], 255258 // CHECK-PPC64: %[[new:.*]] = or i32 %[[old_and]], %[[x_shl]]259 // CHECK-PPC64: store i32 %[[new]], ptr %{{.*}}260 s->b = x;261 }262}263 264namespace N3 {265 // Do widen loads and stores to bitfields through the trailing padding at the266 // end of a struct.267 struct S {268 unsigned b : 24;269 };270// LAYOUT-LABEL: LLVMType:%"struct.N3::S" =271// LAYOUT-SAME: type { i32 }272// LAYOUT: BitFields:[273// LAYOUT-X86-64-NEXT: <CGBitFieldInfo Offset:0 Size:24 IsSigned:0 StorageSize:32 StorageOffset:0274// LAYOUT-PPC64-NEXT: <CGBitFieldInfo Offset:8 Size:24 IsSigned:0 StorageSize:32 StorageOffset:0275// LAYOUT-NEXT: ]>276 277 unsigned read(S* s) {278 // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N34read279 // CHECK-X86-64: %[[val:.*]] = load i32, ptr %{{.*}}280 // CHECK-X86-64: %[[and:.*]] = and i32 %[[val]], 16777215281 // CHECK-X86-64: ret i32 %[[and]]282 // CHECK-PPC64-LABEL: define{{.*}} zeroext i32 @_ZN2N34read283 // CHECK-PPC64: %[[val:.*]] = load i32, ptr %{{.*}}284 // CHECK-PPC64: %[[shr:.*]] = lshr i32 %[[val]], 8285 // CHECK-PPC64: ret i32 %[[shr]]286 return s->b;287 }288 void write(S* s, unsigned x) {289 // CHECK-X86-64-LABEL: define{{.*}} void @_ZN2N35write290 // CHECK-X86-64: %[[ptr:.*]] = load ptr, ptr %{{.*}}291 // CHECK-X86-64: %[[old:.*]] = load i32, ptr %[[ptr]]292 // CHECK-X86-64: %[[x_and:.*]] = and i32 %{{.*}}, 16777215293 // CHECK-X86-64: %[[old_and:.*]] = and i32 %[[old]], -16777216294 // CHECK-X86-64: %[[new:.*]] = or i32 %[[old_and]], %[[x_and]]295 // CHECK-X86-64: store i32 %[[new]], ptr %{{.*}}296 // CHECK-PPC64-LABEL: define{{.*}} void @_ZN2N35write297 // CHECK-PPC64: %[[ptr:.*]] = load ptr, ptr %{{.*}}298 // CHECK-PPC64: %[[old:.*]] = load i32, ptr %[[ptr]]299 // CHECK-PPC64: %[[x_and:.*]] = and i32 %{{.*}}, 16777215300 // CHECK-PPC64: %[[x_shl:.*]] = shl i32 %[[x_and]], 8301 // CHECK-PPC64: %[[old_and:.*]] = and i32 %[[old]], 255302 // CHECK-PPC64: %[[new:.*]] = or i32 %[[old_and]], %[[x_shl]]303 // CHECK-PPC64: store i32 %[[new]], ptr %{{.*}}304 s->b = x;305 }306}307 308namespace N4 {309 // Do NOT widen loads and stores to bitfields into padding at the end of310 // a class which might end up with members inside of it when inside a derived311 // class.312 struct Base {313 virtual ~Base() {}314 315 unsigned b : 24;316 };317 // Imagine some other translation unit introduces:318#if 0319 struct Derived : public Base {320 char c;321 };322#endif323// LAYOUT-LABEL: LLVMType:%"struct.N4::Base" =324// LAYOUT-SAME: type <{ ptr, [3 x i8], [5 x i8] }>325// LAYOUT-NEXT: NonVirtualBaseLLVMType:%"struct.N4::Base.base" = type <{ ptr, [3 x i8] }>326// LAYOUT: BitFields:[327// LAYOUT-X86-64-NEXT: <CGBitFieldInfo Offset:0 Size:24 IsSigned:0 StorageSize:24 StorageOffset:8328// LAYOUT-PPC64-NEXT: <CGBitFieldInfo Offset:0 Size:24 IsSigned:0 StorageSize:24 StorageOffset:8329// LAYOUT-NEXT: ]>330 331 unsigned read(Base* s) {332 // FIXME: We should widen this load as long as the function isn't being333 // instrumented by ThreadSanitizer.334 //335 // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N44read336 // CHECK-X86-64: %[[gep:.*]] = getelementptr inbounds nuw {{.*}}, ptr %{{.*}}, i32 0, i32 1337 // CHECK-X86-64: %[[val:.*]] = load i24, ptr %[[gep]]338 // CHECK-X86-64: %[[ext:.*]] = zext i24 %[[val]] to i32339 // CHECK-X86-64: ret i32 %[[ext]]340 // CHECK-PPC64-LABEL: define{{.*}} zeroext i32 @_ZN2N44read341 // CHECK-PPC64: %[[gep:.*]] = getelementptr inbounds nuw {{.*}}, ptr %{{.*}}, i32 0, i32 1342 // CHECK-PPC64: %[[val:.*]] = load i24, ptr %[[gep]]343 // CHECK-PPC64: %[[ext:.*]] = zext i24 %[[val]] to i32344 // CHECK-PPC64: ret i32 %[[ext]]345 return s->b;346 }347 void write(Base* s, unsigned x) {348 // CHECK-X86-64-LABEL: define{{.*}} void @_ZN2N45write349 // CHECK-X86-64: %[[gep:.*]] = getelementptr inbounds nuw {{.*}}, ptr %{{.*}}, i32 0, i32 1350 // CHECK-X86-64: %[[new:.*]] = trunc i32 %{{.*}} to i24351 // CHECK-X86-64: store i24 %[[new]], ptr %[[gep]]352 // CHECK-PPC64-LABEL: define{{.*}} void @_ZN2N45write353 // CHECK-PPC64: %[[gep:.*]] = getelementptr inbounds nuw {{.*}}, ptr %{{.*}}, i32 0, i32 1354 // CHECK-PPC64: %[[new:.*]] = trunc i32 %{{.*}} to i24355 // CHECK-PPC64: store i24 %[[new]], ptr %[[gep]]356 s->b = x;357 }358}359 360namespace N5 {361 // Widen through padding at the end of a struct even if that struct362 // participates in a union with another struct which has a separate field in363 // that location. The reasoning is that if the operation is storing to that364 // member of the union, it must be the active member, and thus we can write365 // through the padding. If it is a load, it might be a load of a common366 // prefix through a non-active member, but in such a case the extra bits367 // loaded are masked off anyways.368 union U {369 struct X { unsigned b : 24; char c; } x;370 struct Y { unsigned b : 24; } y;371 };372// LAYOUT-LABEL: LLVMType:%"struct.N5::U::X" =373// LAYOUT-SAME: type { [3 x i8], i8 }374// LAYOUT-NEXT: NonVirtualBaseLLVMType:%"struct.N5::U::X" =375// LAYOUT: BitFields:[376// LAYOUT-X86-64-NEXT: <CGBitFieldInfo Offset:0 Size:24 IsSigned:0 StorageSize:24 StorageOffset:0377// LAYOUT-PPC64-NEXT: <CGBitFieldInfo Offset:0 Size:24 IsSigned:0 StorageSize:24 StorageOffset:0378// LAYOUT-NEXT: ]>379 380// LAYOUT-LABEL: LLVMType:%"struct.N5::U::Y" =381// LAYOUT-SAME: type { i32 }382// LAYOUT-NEXT: NonVirtualBaseLLVMType:%"struct.N5::U::Y" =383// LAYOUT: BitFields:[384// LAYOUT-X86-64-NEXT: <CGBitFieldInfo Offset:0 Size:24 IsSigned:0 StorageSize:32 StorageOffset:0385// LAYOUT-PPC64-NEXT: <CGBitFieldInfo Offset:8 Size:24 IsSigned:0 StorageSize:32 StorageOffset:0386// LAYOUT-NEXT: ]>387 388 unsigned read(U* u) {389 // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N54read390 // CHECK-X86-64: %[[val:.*]] = load i32, ptr %{{.*}}391 // CHECK-X86-64: %[[and:.*]] = and i32 %[[val]], 16777215392 // CHECK-X86-64: ret i32 %[[and]]393 // CHECK-PPC64-LABEL: define{{.*}} zeroext i32 @_ZN2N54read394 // CHECK-PPC64: %[[val:.*]] = load i32, ptr %{{.*}}395 // CHECK-PPC64: %[[shr:.*]] = lshr i32 %[[val]], 8396 // CHECK-PPC64: ret i32 %[[shr]]397 return u->y.b;398 }399 void write(U* u, unsigned x) {400 // CHECK-X86-64-LABEL: define{{.*}} void @_ZN2N55write401 // CHECK-X86-64: %[[ptr:.*]] = load ptr, ptr %{{.*}}402 // CHECK-X86-64: %[[old:.*]] = load i32, ptr %[[ptr]]403 // CHECK-X86-64: %[[x_and:.*]] = and i32 %{{.*}}, 16777215404 // CHECK-X86-64: %[[old_and:.*]] = and i32 %[[old]], -16777216405 // CHECK-X86-64: %[[new:.*]] = or i32 %[[old_and]], %[[x_and]]406 // CHECK-X86-64: store i32 %[[new]], ptr %{{.*}}407 // CHECK-PPC64-LABEL: define{{.*}} void @_ZN2N55write408 // CHECK-PPC64: %[[ptr:.*]] = load ptr, ptr %{{.*}}409 // CHECK-PPC64: %[[old:.*]] = load i32, ptr %[[ptr]]410 // CHECK-PPC64: %[[x_and:.*]] = and i32 %{{.*}}, 16777215411 // CHECK-PPC64: %[[x_shl:.*]] = shl i32 %[[x_and]], 8412 // CHECK-PPC64: %[[old_and:.*]] = and i32 %[[old]], 255413 // CHECK-PPC64: %[[new:.*]] = or i32 %[[old_and]], %[[x_shl]]414 // CHECK-PPC64: store i32 %[[new]], ptr %{{.*}}415 u->y.b = x;416 }417}418 419namespace N6 {420 // Zero-length bitfields partition the memory locations of bitfields for the421 // purposes of the memory model. That means stores must not span zero-length422 // bitfields and loads may only span them when we are not instrumenting with423 // ThreadSanitizer.424 // FIXME: We currently don't widen loads even without ThreadSanitizer, even425 // though we could.426 struct S {427 unsigned b1 : 24;428 unsigned char : 0;429 unsigned char b2 : 8;430 };431// LAYOUT-LABEL: LLVMType:%"struct.N6::S" =432// LAYOUT-SAME: type { [3 x i8], i8 }433// LAYOUT: BitFields:[434// LAYOUT-X86-64-NEXT: <CGBitFieldInfo Offset:0 Size:24 IsSigned:0 StorageSize:24 StorageOffset:0435// LAYOUT-X86-64-NEXT: <CGBitFieldInfo Offset:0 Size:8 IsSigned:0 StorageSize:8 StorageOffset:3436// LAYOUT-PPC64-NEXT: <CGBitFieldInfo Offset:0 Size:24 IsSigned:0 StorageSize:24 StorageOffset:0437// LAYOUT-PPC64-NEXT: <CGBitFieldInfo Offset:0 Size:8 IsSigned:0 StorageSize:8 StorageOffset:3438// LAYOUT-NEXT: ]>439 440 unsigned read(S* s) {441 // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N64read442 // CHECK-X86-64: %[[val1:.*]] = load i24, ptr %{{.*}}443 // CHECK-X86-64: %[[ext1:.*]] = zext i24 %[[val1]] to i32444 // CHECK-X86-64: %[[ptr2:.*]] = getelementptr inbounds nuw {{.*}}, ptr %{{.*}}, i32 0, i32 1445 // CHECK-X86-64: %[[val2:.*]] = load i8, ptr %[[ptr2]]446 // CHECK-X86-64: %[[ext2:.*]] = zext i8 %[[val2]] to i32447 // CHECK-X86-64: %[[add:.*]] = add nsw i32 %[[ext1]], %[[ext2]]448 // CHECK-X86-64: ret i32 %[[add]]449 // CHECK-PPC64-LABEL: define{{.*}} zeroext i32 @_ZN2N64read450 // CHECK-PPC64: %[[val1:.*]] = load i24, ptr %{{.*}}451 // CHECK-PPC64: %[[ext1:.*]] = zext i24 %[[val1]] to i32452 // CHECK-PPC64: %[[ptr2:.*]] = getelementptr inbounds nuw {{.*}}, ptr %{{.*}}, i32 0, i32 1453 // CHECK-PPC64: %[[val2:.*]] = load i8, ptr %[[ptr2]]454 // CHECK-PPC64: %[[ext2:.*]] = zext i8 %[[val2]] to i32455 // CHECK-PPC64: %[[add:.*]] = add nsw i32 %[[ext1]], %[[ext2]]456 // CHECK-PPC64: ret i32 %[[add]]457 return s->b1 + s->b2;458 }459 void write(S* s, unsigned x) {460 // CHECK-X86-64-LABEL: define{{.*}} void @_ZN2N65write461 // CHECK-X86-64: %[[new1:.*]] = trunc i32 %{{.*}} to i24462 // CHECK-X86-64: store i24 %[[new1]], ptr %{{.*}}463 // CHECK-X86-64: %[[new2:.*]] = trunc i32 %{{.*}} to i8464 // CHECK-X86-64: %[[ptr2:.*]] = getelementptr inbounds nuw {{.*}}, ptr %{{.*}}, i32 0, i32 1465 // CHECK-X86-64: store i8 %[[new2]], ptr %[[ptr2]]466 // CHECK-PPC64-LABEL: define{{.*}} void @_ZN2N65write467 // CHECK-PPC64: %[[new1:.*]] = trunc i32 %{{.*}} to i24468 // CHECK-PPC64: store i24 %[[new1]], ptr %{{.*}}469 // CHECK-PPC64: %[[new2:.*]] = trunc i32 %{{.*}} to i8470 // CHECK-PPC64: %[[ptr2:.*]] = getelementptr inbounds nuw {{.*}}, ptr %{{.*}}, i32 0, i32 1471 // CHECK-PPC64: store i8 %[[new2]], ptr %[[ptr2]]472 s->b1 = x;473 s->b2 = x;474 }475}476 477namespace N7 {478 // Similar to N4 except that this adds a virtual base to the picture. (PR18430)479 // Do NOT widen loads and stores to bitfields into padding at the end of480 // a class which might end up with members inside of it when inside a derived481 // class.482 struct B1 {483 virtual void f();484 unsigned b1 : 24;485 };486 struct B2 : virtual B1 {487 virtual ~B2();488 unsigned b : 24;489 };490 // Imagine some other translation unit introduces:491#if 0492 struct Derived : public B2 {493 char c;494 };495#endif496// LAYOUT-LABEL: LLVMType:%"struct.N7::B1" =497// LAYOUT-SAME: type <{ ptr, [3 x i8], [5 x i8] }>498// LAYOUT-NEXT: NonVirtualBaseLLVMType:%"struct.N7::B1.base" = type <{ ptr, [3 x i8] }>499// LAYOUT: BitFields:[500// LAYOUT-X86-64-NEXT: <CGBitFieldInfo Offset:0 Size:24 IsSigned:0 StorageSize:24 StorageOffset:8501// LAYOUT-PPC64-NEXT: <CGBitFieldInfo Offset:0 Size:24 IsSigned:0 StorageSize:24 StorageOffset:8502// LAYOUT-NEXT: ]>503 504// LAYOUT-LABEL: LLVMType:%"struct.N7::B2" =505// LAYOUT-SAME: type <{ ptr, [3 x i8], [5 x i8], %"struct.N7::B1.base", [5 x i8] }>506// LAYOUT-NEXT: NonVirtualBaseLLVMType:%"struct.N7::B2.base" = type <{ ptr, [3 x i8] }>507// LAYOUT: BitFields:[508// LAYOUT-X86-64-NEXT: <CGBitFieldInfo Offset:0 Size:24 IsSigned:0 StorageSize:24 StorageOffset:8509// LAYOUT-PPC64-NEXT: <CGBitFieldInfo Offset:0 Size:24 IsSigned:0 StorageSize:24 StorageOffset:8510// LAYOUT-NEXT: ]>511 512 unsigned read(B2* s) {513 // FIXME: We should widen this load as long as the function isn't being514 // instrumented by ThreadSanitizer.515 //516 // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N74read517 // CHECK-X86-64: %[[gep:.*]] = getelementptr inbounds nuw {{.*}}, ptr %{{.*}}, i32 0, i32 1518 // CHECK-X86-64: %[[val:.*]] = load i24, ptr %[[gep]]519 // CHECK-X86-64: %[[ext:.*]] = zext i24 %[[val]] to i32520 // CHECK-X86-64: ret i32 %[[ext]]521 // CHECK-PPC64-LABEL: define{{.*}} zeroext i32 @_ZN2N74read522 // CHECK-PPC64: %[[gep:.*]] = getelementptr inbounds nuw {{.*}}, ptr %{{.*}}, i32 0, i32 1523 // CHECK-PPC64: %[[val:.*]] = load i24, ptr %[[gep]]524 // CHECK-PPC64: %[[ext:.*]] = zext i24 %[[val]] to i32525 // CHECK-PPC64: ret i32 %[[ext]]526 return s->b;527 }528 void write(B2* s, unsigned x) {529 // CHECK-X86-64-LABEL: define{{.*}} void @_ZN2N75write530 // CHECK-X86-64: %[[gep:.*]] = getelementptr inbounds nuw {{.*}}, ptr %{{.*}}, i32 0, i32 1531 // CHECK-X86-64: %[[new:.*]] = trunc i32 %{{.*}} to i24532 // CHECK-X86-64: store i24 %[[new]], ptr %[[gep]]533 // CHECK-PPC64-LABEL: define{{.*}} void @_ZN2N75write534 // CHECK-PPC64: %[[gep:.*]] = getelementptr inbounds nuw {{.*}}, ptr %{{.*}}, i32 0, i32 1535 // CHECK-PPC64: %[[new:.*]] = trunc i32 %{{.*}} to i24536 // CHECK-PPC64: store i24 %[[new]], ptr %[[gep]]537 s->b = x;538 }539}540