brintos

brintos / llvm-project-archived public Read only

0
0
Text · 25.8 KiB · f25f19e Raw
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