Index: clang/lib/CodeGen/CodeGenTBAA.h =================================================================== --- clang/lib/CodeGen/CodeGenTBAA.h +++ clang/lib/CodeGen/CodeGenTBAA.h @@ -146,6 +146,12 @@ /// considered to be equivalent to it. llvm::MDNode *getChar(); + /// AddCollectedField - Add one collected field to Fields vector + void + AddCollectedField(SmallVectorImpl &Fields, + uint64_t Offset, uint64_t Size, QualType QTy, bool MayAlias, + bool FuseOverlapping); + /// CollectFields - Collect information about the fields of a type for /// !tbaa.struct metadata formation. Return false for an unsupported type. bool CollectFields(uint64_t BaseOffset, Index: clang/lib/CodeGen/CodeGenTBAA.cpp =================================================================== --- clang/lib/CodeGen/CodeGenTBAA.cpp +++ clang/lib/CodeGen/CodeGenTBAA.cpp @@ -272,13 +272,44 @@ Size); } +void CodeGenTBAA::AddCollectedField( + SmallVectorImpl &Fields, uint64_t Offset, + uint64_t Size, QualType QTy, bool MayAlias, bool FuseOverlapping) { + + // Fuse fields that overlap in their byte position (e.g. caused by bitfields) + if (FuseOverlapping && !Fields.empty() && Fields.back().Offset <= Offset && + Offset < Fields.back().Offset + Fields.back().Size) { + Fields.back().Size = (Offset + Size) - Fields.back().Offset; + return; + } + + llvm::MDNode *TBAAType = MayAlias ? getChar() : getTypeInfo(QTy); + llvm::MDNode *TBAATag = getAccessTagInfo(TBAAAccessInfo(TBAAType, Size)); + Fields.push_back(llvm::MDBuilder::TBAAStructField(Offset, Size, TBAATag)); +} + +// Calculate the number of bytes a bitfield affects. +// E.g. a 6-bit field starting a bit 0 affects 1 byte, +// a 6-bit field starting at bit 4 affects 2 bytes. +static uint64_t getBitFieldByteSize(ASTContext &Context, + uint64_t FieldBitOffset, + const FieldDecl *Field) { + assert(Field->isBitField()); + + uint64_t LastBitOffset = + FieldBitOffset + Field->getBitWidthValue(Context) - 1; + uint64_t LastByteOffset = LastBitOffset / Context.getCharWidth(); + uint64_t FirstByteOffset = FieldBitOffset / Context.getCharWidth(); + return LastByteOffset - FirstByteOffset + 1; +} + bool CodeGenTBAA::CollectFields(uint64_t BaseOffset, QualType QTy, SmallVectorImpl & Fields, bool MayAlias) { - /* Things not handled yet include: C++ base classes, bitfields, */ + /* Things not handled yet include: C++ base classes */ if (const RecordType *TTy = QTy->getAs()) { const RecordDecl *RD = TTy->getDecl()->getDefinition(); @@ -300,19 +331,23 @@ uint64_t Offset = BaseOffset + Layout.getFieldOffset(idx) / Context.getCharWidth(); QualType FieldQTy = i->getType(); - if (!CollectFields(Offset, FieldQTy, Fields, - MayAlias || TypeHasMayAlias(FieldQTy))) - return false; + bool FieldMayAlias = MayAlias || TypeHasMayAlias(FieldQTy); + if ((*i)->isBitField()) { + uint64_t Size = + getBitFieldByteSize(Context, Layout.getFieldOffset(idx), *i); + + AddCollectedField(Fields, Offset, Size, FieldQTy, FieldMayAlias, true); + } else { + if (!CollectFields(Offset, FieldQTy, Fields, FieldMayAlias)) + return false; + } } return true; } /* Otherwise, treat whatever it is as a field. */ - uint64_t Offset = BaseOffset; uint64_t Size = Context.getTypeSizeInChars(QTy).getQuantity(); - llvm::MDNode *TBAAType = MayAlias ? getChar() : getTypeInfo(QTy); - llvm::MDNode *TBAATag = getAccessTagInfo(TBAAAccessInfo(TBAAType, Size)); - Fields.push_back(llvm::MDBuilder::TBAAStructField(Offset, Size, TBAATag)); + AddCollectedField(Fields, BaseOffset, Size, QTy, MayAlias, false); return true; } @@ -382,7 +417,10 @@ uint64_t BitOffset = Layout.getFieldOffset(Field->getFieldIndex()); uint64_t Offset = Context.toCharUnitsFromBits(BitOffset).getQuantity(); - uint64_t Size = Context.getTypeSizeInChars(FieldQTy).getQuantity(); + uint64_t Size = Field->isBitField() + ? getBitFieldByteSize(Context, BitOffset, Field) + : Context.getTypeSizeInChars(FieldQTy).getQuantity(); + Fields.push_back(llvm::MDBuilder::TBAAStructField(Offset, Size, TypeNode)); } Index: clang/test/CodeGen/tbaa-struct.cpp =================================================================== --- clang/test/CodeGen/tbaa-struct.cpp +++ clang/test/CodeGen/tbaa-struct.cpp @@ -102,6 +102,32 @@ *a1 = *a2; } +struct E { + int : 8; + int a1 : 8; + int : 8; + int a2 : 8; + + int b1 : 9; + int : (32-9-9); + int b2 : 9; + + int c1 : 15; + int c2 : 1; + int c3 : 1; + int : (32-15-1-1); + + char dummy[4]; +}; + +void copy8(E *e1, E *e2) { +// CHECK-LABEL: _Z5copy8P1ES0_ +// CHECK: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 4 dereferenceable(16) %{{.*}}, ptr noundef nonnull align 4 dereferenceable(16) %{{.*}}, i64 16, i1 false) +// CHECK-OLD-SAME: !tbaa.struct [[TS6:!.*]] +// CHECK-NEW-SAME: !tbaa [[TAG_E:![0-9]*]] + *e1 = *e2; +} + // CHECK-OLD: [[TS]] = !{i64 0, i64 2, !{{.*}}, i64 4, i64 4, !{{.*}}, i64 8, i64 1, !{{.*}}, i64 12, i64 4, !{{.*}}} // CHECK-OLD: [[CHAR:!.*]] = !{!"omnipotent char", !{{.*}}} // CHECK-OLD: [[TAG_INT:!.*]] = !{[[INT:!.*]], [[INT]], i64 0} @@ -113,6 +139,7 @@ // CHECK-OLD: [[TS3]] = !{i64 0, i64 8, !{{.*}}, i64 0, i64 2, !{{.*}}, i64 4, i64 8, !{{.*}}} // CHECK-OLD: [[TS4]] = !{i64 0, i64 1, [[TAG_CHAR]], i64 1, i64 1, [[TAG_CHAR]], i64 2, i64 1, [[TAG_CHAR]]} // CHECK-OLD: [[TS5]] = !{i64 0, i64 1, [[TAG_CHAR]], i64 4, i64 1, [[TAG_CHAR]], i64 5, i64 1, [[TAG_CHAR]]} +// CHECK-OLD: [[TS6]] = !{i64 1, i64 1, [[TAG_INT]], i64 3, i64 1, [[TAG_INT]], i64 4, i64 2, [[TAG_INT]], i64 6, i64 2, [[TAG_INT]], i64 8, i64 2, [[TAG_INT]], i64 10, i64 1, [[TAG_INT]], i64 12, i64 4, [[TAG_CHAR]]} // CHECK-NEW-DAG: [[TYPE_char:!.*]] = !{{{.*}}, i64 1, !"omnipotent char"} // CHECK-NEW-DAG: [[TAG_char]] = !{[[TYPE_char]], [[TYPE_char]], i64 0, i64 0} @@ -127,3 +154,5 @@ // CHECK-NEW-DAG: [[TAG_C]] = !{[[TYPE_C]], [[TYPE_C]], i64 0, i64 3} // CHECK-NEW-DAG: [[TYPE_D:!.*]] = !{[[TYPE_char]], i64 6, !"_ZTS1D", [[TYPE_char]], i64 0, i64 1, [[TYPE_char]], i64 4, i64 1, [[TYPE_char]], i64 5, i64 1} // CHECK-NEW-DAG: [[TAG_D]] = !{[[TYPE_D]], [[TYPE_D]], i64 0, i64 6} +// CHECK-NEW-DAG: [[TYPE_E:!.*]] = !{[[TYPE_char]], i64 16, !"_ZTS1E", [[TYPE_int]], i64 1, i64 1, [[TYPE_int]], i64 3, i64 1, [[TYPE_int]], i64 4, i64 2, [[TYPE_int]], i64 6, i64 2, [[TYPE_int]], i64 8, i64 2, [[TYPE_int]], i64 9, i64 1, [[TYPE_int]], i64 10, i64 1, [[TYPE_char]], i64 12, i64 4} +// CHECK-NEW-DAG: [[TAG_E]] = !{[[TYPE_E]], [[TYPE_E]], i64 0, i64 16} Index: llvm/docs/LangRef.rst =================================================================== --- llvm/docs/LangRef.rst +++ llvm/docs/LangRef.rst @@ -6406,6 +6406,11 @@ 4 byte gap between the two fields. This gap represents padding which does not carry useful data and need not be preserved. +The order of the fields is unspecified. The byte range +[offset, offset + size) of two fields must not overlap. The size +of one field might be greater than the size of its TBAA tag (e.g. in +case of arrays) or might be smaller (e.g. in case of bitfields). + '``noalias``' and '``alias.scope``' Metadata ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^