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 %s 3 // RUN: FileCheck -check-prefix=CHECK-X86-64 %s <%t 4 // RUN: %clang_cc1 -triple powerpc64-unknown-unknown -fdump-record-layouts-simple\ 5 // RUN: -emit-llvm -o %t %s | FileCheck -check-prefixes=LAYOUT,LAYOUT-PPC64 %s 6 // RUN: FileCheck -check-prefix=CHECK-PPC64 %s <%t 7 // 8 // Tests for bitfield access patterns in C++ with special attention to 9 // conformance to C++11 memory model requirements. 10 11 namespace N0 { 12 // Test basic bitfield layout access across interesting byte and word 13 // 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:0 28 // LAYOUT-X86-64-NEXT: <CGBitFieldInfo Offset:14 Size:2 IsSigned:0 StorageSize:64 StorageOffset:0 29 // LAYOUT-X86-64-NEXT: <CGBitFieldInfo Offset:16 Size:6 IsSigned:0 StorageSize:64 StorageOffset:0 30 // LAYOUT-X86-64-NEXT: <CGBitFieldInfo Offset:22 Size:2 IsSigned:0 StorageSize:64 StorageOffset:0 31 // LAYOUT-X86-64-NEXT: <CGBitFieldInfo Offset:24 Size:30 IsSigned:0 StorageSize:64 StorageOffset:0 32 // LAYOUT-X86-64-NEXT: <CGBitFieldInfo Offset:54 Size:2 IsSigned:0 StorageSize:64 StorageOffset:0 33 // LAYOUT-X86-64-NEXT: <CGBitFieldInfo Offset:56 Size:6 IsSigned:0 StorageSize:64 StorageOffset:0 34 // LAYOUT-X86-64-NEXT: <CGBitFieldInfo Offset:62 Size:2 IsSigned:0 StorageSize:64 StorageOffset:0 35 // LAYOUT-PPC64-NEXT: <CGBitFieldInfo Offset:50 Size:14 IsSigned:0 StorageSize:64 StorageOffset:0 36 // LAYOUT-PPC64-NEXT: <CGBitFieldInfo Offset:48 Size:2 IsSigned:0 StorageSize:64 StorageOffset:0 37 // LAYOUT-PPC64-NEXT: <CGBitFieldInfo Offset:42 Size:6 IsSigned:0 StorageSize:64 StorageOffset:0 38 // LAYOUT-PPC64-NEXT: <CGBitFieldInfo Offset:40 Size:2 IsSigned:0 StorageSize:64 StorageOffset:0 39 // LAYOUT-PPC64-NEXT: <CGBitFieldInfo Offset:10 Size:30 IsSigned:0 StorageSize:64 StorageOffset:0 40 // LAYOUT-PPC64-NEXT: <CGBitFieldInfo Offset:8 Size:2 IsSigned:0 StorageSize:64 StorageOffset:0 41 // LAYOUT-PPC64-NEXT: <CGBitFieldInfo Offset:2 Size:6 IsSigned:0 StorageSize:64 StorageOffset:0 42 // LAYOUT-PPC64-NEXT: <CGBitFieldInfo Offset:0 Size:2 IsSigned:0 StorageSize:64 StorageOffset:0 43 // LAYOUT-NEXT: ]> 44 45 unsigned read00(S* s) { 46 // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N06read00 47 // CHECK-X86-64: %[[val:.*]] = load i64, ptr %{{.*}} 48 // CHECK-X86-64: %[[and:.*]] = and i64 %[[val]], 16383 49 // CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[and]] to i32 50 // CHECK-X86-64: ret i32 %[[trunc]] 51 // CHECK-PPC64-LABEL: define{{.*}} zeroext i32 @_ZN2N06read00 52 // CHECK-PPC64: %[[val:.*]] = load i64, ptr %{{.*}} 53 // CHECK-PPC64: %[[shr:.*]] = lshr i64 %[[val]], 50 54 // CHECK-PPC64: %[[trunc:.*]] = trunc i64 %[[shr]] to i32 55 // CHECK-PPC64: ret i32 %[[trunc]] 56 return s->b00; 57 } 58 unsigned read01(S* s) { 59 // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N06read01 60 // CHECK-X86-64: %[[val:.*]] = load i64, ptr %{{.*}} 61 // CHECK-X86-64: %[[shr:.*]] = lshr i64 %[[val]], 14 62 // CHECK-X86-64: %[[and:.*]] = and i64 %[[shr]], 3 63 // CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[and]] to i32 64 // CHECK-X86-64: ret i32 %[[trunc]] 65 // CHECK-PPC64-LABEL: define{{.*}} zeroext i32 @_ZN2N06read01 66 // CHECK-PPC64: %[[val:.*]] = load i64, ptr %{{.*}} 67 // CHECK-PPC64: %[[shr:.*]] = lshr i64 %[[val]], 48 68 // CHECK-PPC64: %[[and:.*]] = and i64 %[[shr]], 3 69 // CHECK-PPC64: %[[trunc:.*]] = trunc i64 %[[and]] to i32 70 // CHECK-PPC64: ret i32 %[[trunc]] 71 return s->b01; 72 } 73 unsigned read20(S* s) { 74 // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N06read20 75 // CHECK-X86-64: %[[val:.*]] = load i64, ptr %{{.*}} 76 // CHECK-X86-64: %[[shr:.*]] = lshr i64 %[[val]], 16 77 // CHECK-X86-64: %[[and:.*]] = and i64 %[[shr]], 63 78 // CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[and]] to i32 79 // CHECK-X86-64: ret i32 %[[trunc]] 80 // CHECK-PPC64-LABEL: define{{.*}} zeroext i32 @_ZN2N06read20 81 // CHECK-PPC64: %[[val:.*]] = load i64, ptr %{{.*}} 82 // CHECK-PPC64: %[[shr:.*]] = lshr i64 %[[val]], 42 83 // CHECK-PPC64: %[[and:.*]] = and i64 %[[shr]], 63 84 // CHECK-PPC64: %[[trunc:.*]] = trunc i64 %[[and]] to i32 85 // CHECK-PPC64: ret i32 %[[trunc]] 86 return s->b20; 87 } 88 unsigned read21(S* s) { 89 // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N06read21 90 // CHECK-X86-64: %[[val:.*]] = load i64, ptr %{{.*}} 91 // CHECK-X86-64: %[[shr:.*]] = lshr i64 %[[val]], 22 92 // CHECK-X86-64: %[[and:.*]] = and i64 %[[shr]], 3 93 // CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[and]] to i32 94 // CHECK-X86-64: ret i32 %[[trunc]] 95 // CHECK-PPC64-LABEL: define{{.*}} zeroext i32 @_ZN2N06read21 96 // CHECK-PPC64: %[[val:.*]] = load i64, ptr %{{.*}} 97 // CHECK-PPC64: %[[shr:.*]] = lshr i64 %[[val]], 40 98 // CHECK-PPC64: %[[and:.*]] = and i64 %[[shr]], 3 99 // CHECK-PPC64: %[[trunc:.*]] = trunc i64 %[[and]] to i32 100 // CHECK-PPC64: ret i32 %[[trunc]] 101 return s->b21; 102 } 103 unsigned read30(S* s) { 104 // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N06read30 105 // CHECK-X86-64: %[[val:.*]] = load i64, ptr %{{.*}} 106 // CHECK-X86-64: %[[shr:.*]] = lshr i64 %[[val]], 24 107 // CHECK-X86-64: %[[and:.*]] = and i64 %[[shr]], 1073741823 108 // CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[and]] to i32 109 // CHECK-X86-64: ret i32 %[[trunc]] 110 // CHECK-PPC64-LABEL: define{{.*}} zeroext i32 @_ZN2N06read30 111 // CHECK-PPC64: %[[val:.*]] = load i64, ptr %{{.*}} 112 // CHECK-PPC64: %[[shr:.*]] = lshr i64 %[[val]], 10 113 // CHECK-PPC64: %[[and:.*]] = and i64 %[[shr]], 1073741823 114 // CHECK-PPC64: %[[trunc:.*]] = trunc i64 %[[and]] to i32 115 // CHECK-PPC64: ret i32 %[[trunc]] 116 return s->b30; 117 } 118 unsigned read31(S* s) { 119 // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N06read31 120 // CHECK-X86-64: %[[val:.*]] = load i64, ptr %{{.*}} 121 // CHECK-X86-64: %[[shr:.*]] = lshr i64 %[[val]], 54 122 // CHECK-X86-64: %[[and:.*]] = and i64 %[[shr]], 3 123 // CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[and]] to i32 124 // CHECK-X86-64: ret i32 %[[trunc]] 125 // CHECK-PPC64-LABEL: define{{.*}} zeroext i32 @_ZN2N06read31 126 // CHECK-PPC64: %[[val:.*]] = load i64, ptr %{{.*}} 127 // CHECK-PPC64: %[[shr:.*]] = lshr i64 %[[val]], 8 128 // CHECK-PPC64: %[[and:.*]] = and i64 %[[shr]], 3 129 // CHECK-PPC64: %[[trunc:.*]] = trunc i64 %[[and]] to i32 130 // CHECK-PPC64: ret i32 %[[trunc]] 131 return s->b31; 132 } 133 unsigned read70(S* s) { 134 // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N06read70 135 // CHECK-X86-64: %[[val:.*]] = load i64, ptr %{{.*}} 136 // CHECK-X86-64: %[[shr:.*]] = lshr i64 %[[val]], 56 137 // CHECK-X86-64: %[[and:.*]] = and i64 %[[shr]], 63 138 // CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[and]] to i32 139 // CHECK-X86-64: ret i32 %[[trunc]] 140 // CHECK-PPC64-LABEL: define{{.*}} zeroext i32 @_ZN2N06read70 141 // CHECK-PPC64: %[[val:.*]] = load i64, ptr %{{.*}} 142 // CHECK-PPC64: %[[shr:.*]] = lshr i64 %[[val]], 2 143 // CHECK-PPC64: %[[and:.*]] = and i64 %[[shr]], 63 144 // CHECK-PPC64: %[[trunc:.*]] = trunc i64 %[[and]] to i32 145 // CHECK-PPC64: ret i32 %[[trunc]] 146 return s->b70; 147 } 148 unsigned read71(S* s) { 149 // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N06read71 150 // CHECK-X86-64: %[[val:.*]] = load i64, ptr %{{.*}} 151 // CHECK-X86-64: %[[shr:.*]] = lshr i64 %[[val]], 62 152 // CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[shr]] to i32 153 // CHECK-X86-64: ret i32 %[[trunc]] 154 // CHECK-PPC64-LABEL: define{{.*}} zeroext i32 @_ZN2N06read71 155 // CHECK-PPC64: %[[val:.*]] = load i64, ptr %{{.*}} 156 // CHECK-PPC64: %[[and:.*]] = and i64 %[[val]], 3 157 // CHECK-PPC64: %[[trunc:.*]] = trunc i64 %[[and]] to i32 158 // CHECK-PPC64: ret i32 %[[trunc]] 159 return s->b71; 160 } 161 } 162 163 namespace N1 { 164 // Ensure that neither loads nor stores to bitfields are not widened into 165 // other memory locations. (PR13691) 166 // 167 // NOTE: We could potentially widen loads based on their alignment if we are 168 // comfortable requiring that subsequent memory locations within the 169 // 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:1 179 // LAYOUT-PPC64-NEXT: <CGBitFieldInfo Offset:7 Size:1 IsSigned:0 StorageSize:8 StorageOffset:1 180 // LAYOUT-NEXT: ]> 181 182 unsigned read(S* s) { 183 // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N14read 184 // CHECK-X86-64: %[[ptr:.*]] = getelementptr inbounds nuw %{{.*}}, ptr %{{.*}}, i32 0, i32 1 185 // CHECK-X86-64: %[[val:.*]] = load i8, ptr %[[ptr]] 186 // CHECK-X86-64: %[[and:.*]] = and i8 %[[val]], 1 187 // CHECK-X86-64: %[[ext:.*]] = zext i8 %[[and]] to i32 188 // CHECK-X86-64: ret i32 %[[ext]] 189 // CHECK-PPC64-LABEL: define{{.*}} zeroext i32 @_ZN2N14read 190 // CHECK-PPC64: %[[ptr:.*]] = getelementptr inbounds nuw %{{.*}}, ptr %{{.*}}, i32 0, i32 1 191 // CHECK-PPC64: %[[val:.*]] = load i8, ptr %[[ptr]] 192 // CHECK-PPC64: %[[shr:.*]] = lshr i8 %[[val]], 7 193 // CHECK-PPC64: %[[ext:.*]] = zext i8 %[[shr]] to i32 194 // CHECK-PPC64: ret i32 %[[ext]] 195 return s->b; 196 } 197 void write(S* s, unsigned x) { 198 // CHECK-X86-64-LABEL: define{{.*}} void @_ZN2N15write 199 // CHECK-X86-64: %[[ptr:.*]] = getelementptr inbounds nuw %{{.*}}, ptr %{{.*}}, i32 0, i32 1 200 // CHECK-X86-64: %[[x_trunc:.*]] = trunc i32 %{{.*}} to i8 201 // CHECK-X86-64: %[[old:.*]] = load i8, ptr %[[ptr]] 202 // CHECK-X86-64: %[[x_and:.*]] = and i8 %[[x_trunc]], 1 203 // CHECK-X86-64: %[[old_and:.*]] = and i8 %[[old]], -2 204 // 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 @_ZN2N15write 207 // CHECK-PPC64: %[[ptr:.*]] = getelementptr inbounds nuw %{{.*}}, ptr %{{.*}}, i32 0, i32 1 208 // CHECK-PPC64: %[[x_trunc:.*]] = trunc i32 %{{.*}} to i8 209 // CHECK-PPC64: %[[old:.*]] = load i8, ptr %[[ptr]] 210 // CHECK-PPC64: %[[x_and:.*]] = and i8 %[[x_trunc]], 1 211 // CHECK-PPC64: %[[x_shl:.*]] = shl i8 %[[x_and]], 7 212 // CHECK-PPC64: %[[old_and:.*]] = and i8 %[[old]], 127 213 // CHECK-PPC64: %[[new:.*]] = or i8 %[[old_and]], %[[x_shl]] 214 // CHECK-PPC64: store i8 %[[new]], ptr %[[ptr]] 215 s->b = x; 216 } 217 } 218 219 namespace N2 { 220 // Do widen loads and stores to bitfields when those bitfields have padding 221 // 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:0 230 // LAYOUT-PPC64-NEXT: <CGBitFieldInfo Offset:8 Size:24 IsSigned:0 StorageSize:32 StorageOffset:0 231 // LAYOUT-NEXT: ]> 232 233 unsigned read(S* s) { 234 // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N24read 235 // CHECK-X86-64: %[[val:.*]] = load i32, ptr %{{.*}} 236 // CHECK-X86-64: %[[and:.*]] = and i32 %[[val]], 16777215 237 // CHECK-X86-64: ret i32 %[[and]] 238 // CHECK-PPC64-LABEL: define{{.*}} zeroext i32 @_ZN2N24read 239 // CHECK-PPC64: %[[val:.*]] = load i32, ptr %{{.*}} 240 // CHECK-PPC64: %[[shr:.*]] = lshr i32 %[[val]], 8 241 // CHECK-PPC64: ret i32 %[[shr]] 242 return s->b; 243 } 244 void write(S* s, unsigned x) { 245 // CHECK-X86-64-LABEL: define{{.*}} void @_ZN2N25write 246 // CHECK-X86-64: %[[ptr:.*]] = load ptr, ptr %{{.*}} 247 // CHECK-X86-64: %[[old:.*]] = load i32, ptr %[[ptr]] 248 // CHECK-X86-64: %[[x_and:.*]] = and i32 %{{.*}}, 16777215 249 // CHECK-X86-64: %[[old_and:.*]] = and i32 %[[old]], -16777216 250 // CHECK-X86-64: %[[new:.*]] = or i32 %[[old_and]], %[[x_and]] 251 // CHECK-X86-64: store i32 %[[new]], ptr %{{.*}} 252 // CHECK-PPC64-LABEL: define{{.*}} void @_ZN2N25write 253 // CHECK-PPC64: %[[ptr:.*]] = load ptr, ptr %{{.*}} 254 // CHECK-PPC64: %[[old:.*]] = load i32, ptr %[[ptr]] 255 // CHECK-PPC64: %[[x_and:.*]] = and i32 %{{.*}}, 16777215 256 // CHECK-PPC64: %[[x_shl:.*]] = shl i32 %[[x_and]], 8 257 // CHECK-PPC64: %[[old_and:.*]] = and i32 %[[old]], 255 258 // CHECK-PPC64: %[[new:.*]] = or i32 %[[old_and]], %[[x_shl]] 259 // CHECK-PPC64: store i32 %[[new]], ptr %{{.*}} 260 s->b = x; 261 } 262 } 263 264 namespace N3 { 265 // Do widen loads and stores to bitfields through the trailing padding at the 266 // 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:0 274 // LAYOUT-PPC64-NEXT: <CGBitFieldInfo Offset:8 Size:24 IsSigned:0 StorageSize:32 StorageOffset:0 275 // LAYOUT-NEXT: ]> 276 277 unsigned read(S* s) { 278 // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N34read 279 // CHECK-X86-64: %[[val:.*]] = load i32, ptr %{{.*}} 280 // CHECK-X86-64: %[[and:.*]] = and i32 %[[val]], 16777215 281 // CHECK-X86-64: ret i32 %[[and]] 282 // CHECK-PPC64-LABEL: define{{.*}} zeroext i32 @_ZN2N34read 283 // CHECK-PPC64: %[[val:.*]] = load i32, ptr %{{.*}} 284 // CHECK-PPC64: %[[shr:.*]] = lshr i32 %[[val]], 8 285 // CHECK-PPC64: ret i32 %[[shr]] 286 return s->b; 287 } 288 void write(S* s, unsigned x) { 289 // CHECK-X86-64-LABEL: define{{.*}} void @_ZN2N35write 290 // CHECK-X86-64: %[[ptr:.*]] = load ptr, ptr %{{.*}} 291 // CHECK-X86-64: %[[old:.*]] = load i32, ptr %[[ptr]] 292 // CHECK-X86-64: %[[x_and:.*]] = and i32 %{{.*}}, 16777215 293 // CHECK-X86-64: %[[old_and:.*]] = and i32 %[[old]], -16777216 294 // CHECK-X86-64: %[[new:.*]] = or i32 %[[old_and]], %[[x_and]] 295 // CHECK-X86-64: store i32 %[[new]], ptr %{{.*}} 296 // CHECK-PPC64-LABEL: define{{.*}} void @_ZN2N35write 297 // CHECK-PPC64: %[[ptr:.*]] = load ptr, ptr %{{.*}} 298 // CHECK-PPC64: %[[old:.*]] = load i32, ptr %[[ptr]] 299 // CHECK-PPC64: %[[x_and:.*]] = and i32 %{{.*}}, 16777215 300 // CHECK-PPC64: %[[x_shl:.*]] = shl i32 %[[x_and]], 8 301 // CHECK-PPC64: %[[old_and:.*]] = and i32 %[[old]], 255 302 // CHECK-PPC64: %[[new:.*]] = or i32 %[[old_and]], %[[x_shl]] 303 // CHECK-PPC64: store i32 %[[new]], ptr %{{.*}} 304 s->b = x; 305 } 306 } 307 308 namespace N4 { 309 // Do NOT widen loads and stores to bitfields into padding at the end of 310 // a class which might end up with members inside of it when inside a derived 311 // class. 312 struct Base { 313 virtual ~Base() {} 314 315 unsigned b : 24; 316 }; 317 // Imagine some other translation unit introduces: 318 #if 0 319 struct Derived : public Base { 320 char c; 321 }; 322 #endif 323 // 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:8 328 // LAYOUT-PPC64-NEXT: <CGBitFieldInfo Offset:0 Size:24 IsSigned:0 StorageSize:24 StorageOffset:8 329 // LAYOUT-NEXT: ]> 330 331 unsigned read(Base* s) { 332 // FIXME: We should widen this load as long as the function isn't being 333 // instrumented by ThreadSanitizer. 334 // 335 // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N44read 336 // CHECK-X86-64: %[[gep:.*]] = getelementptr inbounds nuw {{.*}}, ptr %{{.*}}, i32 0, i32 1 337 // CHECK-X86-64: %[[val:.*]] = load i24, ptr %[[gep]] 338 // CHECK-X86-64: %[[ext:.*]] = zext i24 %[[val]] to i32 339 // CHECK-X86-64: ret i32 %[[ext]] 340 // CHECK-PPC64-LABEL: define{{.*}} zeroext i32 @_ZN2N44read 341 // CHECK-PPC64: %[[gep:.*]] = getelementptr inbounds nuw {{.*}}, ptr %{{.*}}, i32 0, i32 1 342 // CHECK-PPC64: %[[val:.*]] = load i24, ptr %[[gep]] 343 // CHECK-PPC64: %[[ext:.*]] = zext i24 %[[val]] to i32 344 // CHECK-PPC64: ret i32 %[[ext]] 345 return s->b; 346 } 347 void write(Base* s, unsigned x) { 348 // CHECK-X86-64-LABEL: define{{.*}} void @_ZN2N45write 349 // CHECK-X86-64: %[[gep:.*]] = getelementptr inbounds nuw {{.*}}, ptr %{{.*}}, i32 0, i32 1 350 // CHECK-X86-64: %[[new:.*]] = trunc i32 %{{.*}} to i24 351 // CHECK-X86-64: store i24 %[[new]], ptr %[[gep]] 352 // CHECK-PPC64-LABEL: define{{.*}} void @_ZN2N45write 353 // CHECK-PPC64: %[[gep:.*]] = getelementptr inbounds nuw {{.*}}, ptr %{{.*}}, i32 0, i32 1 354 // CHECK-PPC64: %[[new:.*]] = trunc i32 %{{.*}} to i24 355 // CHECK-PPC64: store i24 %[[new]], ptr %[[gep]] 356 s->b = x; 357 } 358 } 359 360 namespace N5 { 361 // Widen through padding at the end of a struct even if that struct 362 // participates in a union with another struct which has a separate field in 363 // that location. The reasoning is that if the operation is storing to that 364 // member of the union, it must be the active member, and thus we can write 365 // through the padding. If it is a load, it might be a load of a common 366 // prefix through a non-active member, but in such a case the extra bits 367 // 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:0 377 // LAYOUT-PPC64-NEXT: <CGBitFieldInfo Offset:0 Size:24 IsSigned:0 StorageSize:24 StorageOffset:0 378 // 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:0 385 // LAYOUT-PPC64-NEXT: <CGBitFieldInfo Offset:8 Size:24 IsSigned:0 StorageSize:32 StorageOffset:0 386 // LAYOUT-NEXT: ]> 387 388 unsigned read(U* u) { 389 // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N54read 390 // CHECK-X86-64: %[[val:.*]] = load i32, ptr %{{.*}} 391 // CHECK-X86-64: %[[and:.*]] = and i32 %[[val]], 16777215 392 // CHECK-X86-64: ret i32 %[[and]] 393 // CHECK-PPC64-LABEL: define{{.*}} zeroext i32 @_ZN2N54read 394 // CHECK-PPC64: %[[val:.*]] = load i32, ptr %{{.*}} 395 // CHECK-PPC64: %[[shr:.*]] = lshr i32 %[[val]], 8 396 // 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 @_ZN2N55write 401 // CHECK-X86-64: %[[ptr:.*]] = load ptr, ptr %{{.*}} 402 // CHECK-X86-64: %[[old:.*]] = load i32, ptr %[[ptr]] 403 // CHECK-X86-64: %[[x_and:.*]] = and i32 %{{.*}}, 16777215 404 // CHECK-X86-64: %[[old_and:.*]] = and i32 %[[old]], -16777216 405 // CHECK-X86-64: %[[new:.*]] = or i32 %[[old_and]], %[[x_and]] 406 // CHECK-X86-64: store i32 %[[new]], ptr %{{.*}} 407 // CHECK-PPC64-LABEL: define{{.*}} void @_ZN2N55write 408 // CHECK-PPC64: %[[ptr:.*]] = load ptr, ptr %{{.*}} 409 // CHECK-PPC64: %[[old:.*]] = load i32, ptr %[[ptr]] 410 // CHECK-PPC64: %[[x_and:.*]] = and i32 %{{.*}}, 16777215 411 // CHECK-PPC64: %[[x_shl:.*]] = shl i32 %[[x_and]], 8 412 // CHECK-PPC64: %[[old_and:.*]] = and i32 %[[old]], 255 413 // CHECK-PPC64: %[[new:.*]] = or i32 %[[old_and]], %[[x_shl]] 414 // CHECK-PPC64: store i32 %[[new]], ptr %{{.*}} 415 u->y.b = x; 416 } 417 } 418 419 namespace N6 { 420 // Zero-length bitfields partition the memory locations of bitfields for the 421 // purposes of the memory model. That means stores must not span zero-length 422 // bitfields and loads may only span them when we are not instrumenting with 423 // ThreadSanitizer. 424 // FIXME: We currently don't widen loads even without ThreadSanitizer, even 425 // 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:0 435 // LAYOUT-X86-64-NEXT: <CGBitFieldInfo Offset:0 Size:8 IsSigned:0 StorageSize:8 StorageOffset:3 436 // LAYOUT-PPC64-NEXT: <CGBitFieldInfo Offset:0 Size:24 IsSigned:0 StorageSize:24 StorageOffset:0 437 // LAYOUT-PPC64-NEXT: <CGBitFieldInfo Offset:0 Size:8 IsSigned:0 StorageSize:8 StorageOffset:3 438 // LAYOUT-NEXT: ]> 439 440 unsigned read(S* s) { 441 // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N64read 442 // CHECK-X86-64: %[[val1:.*]] = load i24, ptr %{{.*}} 443 // CHECK-X86-64: %[[ext1:.*]] = zext i24 %[[val1]] to i32 444 // CHECK-X86-64: %[[ptr2:.*]] = getelementptr inbounds nuw {{.*}}, ptr %{{.*}}, i32 0, i32 1 445 // CHECK-X86-64: %[[val2:.*]] = load i8, ptr %[[ptr2]] 446 // CHECK-X86-64: %[[ext2:.*]] = zext i8 %[[val2]] to i32 447 // CHECK-X86-64: %[[add:.*]] = add nsw i32 %[[ext1]], %[[ext2]] 448 // CHECK-X86-64: ret i32 %[[add]] 449 // CHECK-PPC64-LABEL: define{{.*}} zeroext i32 @_ZN2N64read 450 // CHECK-PPC64: %[[val1:.*]] = load i24, ptr %{{.*}} 451 // CHECK-PPC64: %[[ext1:.*]] = zext i24 %[[val1]] to i32 452 // CHECK-PPC64: %[[ptr2:.*]] = getelementptr inbounds nuw {{.*}}, ptr %{{.*}}, i32 0, i32 1 453 // CHECK-PPC64: %[[val2:.*]] = load i8, ptr %[[ptr2]] 454 // CHECK-PPC64: %[[ext2:.*]] = zext i8 %[[val2]] to i32 455 // 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 @_ZN2N65write 461 // CHECK-X86-64: %[[new1:.*]] = trunc i32 %{{.*}} to i24 462 // CHECK-X86-64: store i24 %[[new1]], ptr %{{.*}} 463 // CHECK-X86-64: %[[new2:.*]] = trunc i32 %{{.*}} to i8 464 // CHECK-X86-64: %[[ptr2:.*]] = getelementptr inbounds nuw {{.*}}, ptr %{{.*}}, i32 0, i32 1 465 // CHECK-X86-64: store i8 %[[new2]], ptr %[[ptr2]] 466 // CHECK-PPC64-LABEL: define{{.*}} void @_ZN2N65write 467 // CHECK-PPC64: %[[new1:.*]] = trunc i32 %{{.*}} to i24 468 // CHECK-PPC64: store i24 %[[new1]], ptr %{{.*}} 469 // CHECK-PPC64: %[[new2:.*]] = trunc i32 %{{.*}} to i8 470 // CHECK-PPC64: %[[ptr2:.*]] = getelementptr inbounds nuw {{.*}}, ptr %{{.*}}, i32 0, i32 1 471 // CHECK-PPC64: store i8 %[[new2]], ptr %[[ptr2]] 472 s->b1 = x; 473 s->b2 = x; 474 } 475 } 476 477 namespace 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 of 480 // a class which might end up with members inside of it when inside a derived 481 // 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 0 492 struct Derived : public B2 { 493 char c; 494 }; 495 #endif 496 // 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:8 501 // LAYOUT-PPC64-NEXT: <CGBitFieldInfo Offset:0 Size:24 IsSigned:0 StorageSize:24 StorageOffset:8 502 // 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:8 509 // LAYOUT-PPC64-NEXT: <CGBitFieldInfo Offset:0 Size:24 IsSigned:0 StorageSize:24 StorageOffset:8 510 // LAYOUT-NEXT: ]> 511 512 unsigned read(B2* s) { 513 // FIXME: We should widen this load as long as the function isn't being 514 // instrumented by ThreadSanitizer. 515 // 516 // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N74read 517 // CHECK-X86-64: %[[gep:.*]] = getelementptr inbounds nuw {{.*}}, ptr %{{.*}}, i32 0, i32 1 518 // CHECK-X86-64: %[[val:.*]] = load i24, ptr %[[gep]] 519 // CHECK-X86-64: %[[ext:.*]] = zext i24 %[[val]] to i32 520 // CHECK-X86-64: ret i32 %[[ext]] 521 // CHECK-PPC64-LABEL: define{{.*}} zeroext i32 @_ZN2N74read 522 // CHECK-PPC64: %[[gep:.*]] = getelementptr inbounds nuw {{.*}}, ptr %{{.*}}, i32 0, i32 1 523 // CHECK-PPC64: %[[val:.*]] = load i24, ptr %[[gep]] 524 // CHECK-PPC64: %[[ext:.*]] = zext i24 %[[val]] to i32 525 // CHECK-PPC64: ret i32 %[[ext]] 526 return s->b; 527 } 528 void write(B2* s, unsigned x) { 529 // CHECK-X86-64-LABEL: define{{.*}} void @_ZN2N75write 530 // CHECK-X86-64: %[[gep:.*]] = getelementptr inbounds nuw {{.*}}, ptr %{{.*}}, i32 0, i32 1 531 // CHECK-X86-64: %[[new:.*]] = trunc i32 %{{.*}} to i24 532 // CHECK-X86-64: store i24 %[[new]], ptr %[[gep]] 533 // CHECK-PPC64-LABEL: define{{.*}} void @_ZN2N75write 534 // CHECK-PPC64: %[[gep:.*]] = getelementptr inbounds nuw {{.*}}, ptr %{{.*}}, i32 0, i32 1 535 // CHECK-PPC64: %[[new:.*]] = trunc i32 %{{.*}} to i24 536 // CHECK-PPC64: store i24 %[[new]], ptr %[[gep]] 537 s->b = x; 538 } 539 } 540