https://github.com/davidbolvansky updated https://github.com/llvm/llvm-project/pull/226806
From 5d463c919547f89b0ef0fb07f1c5e89e6c8cc2ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1vid=20Bolvansk=C3=BD?= <[email protected]> Date: Sun, 27 Sep 2026 18:46:07 +0200 Subject: [PATCH] [clang][CodeGen] Add TBAA for bit-field accesses --- clang/lib/CodeGen/CGExpr.cpp | 35 +++++++++++++---- clang/lib/CodeGen/CodeGenTBAA.cpp | 28 ++++++++++---- clang/test/CodeGen/tbaa-bitfield-access.c | 47 +++++++++++++++++++++++ clang/test/CodeGen/tbaa-struct.cpp | 6 +-- 4 files changed, 99 insertions(+), 17 deletions(-) create mode 100644 clang/test/CodeGen/tbaa-bitfield-access.c diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 4a481c01f6a68..f51ca0af010f6 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -2658,8 +2658,9 @@ RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV, llvm::Type *ResLTy = ConvertType(LV.getType()); Address Ptr = LV.getBitFieldAddress(); - llvm::Value *Val = - Builder.CreateLoad(Ptr, LV.isVolatileQualified(), "bf.load"); + auto *Load = Builder.CreateLoad(Ptr, LV.isVolatileQualified(), "bf.load"); + CGM.DecorateInstructionWithTBAA(Load, LV.getTBAAInfo()); + llvm::Value *Val = Load; bool UseVolatile = LV.isVolatileQualified() && Info.VolatileStorageSize != 0 && @@ -3073,8 +3074,9 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst, // and mask together with source before storing. if (StorageSize != Info.Size) { assert(StorageSize > Info.Size && "Invalid bitfield size."); - llvm::Value *Val = - Builder.CreateLoad(Ptr, Dst.isVolatileQualified(), "bf.load"); + auto *Load = Builder.CreateLoad(Ptr, Dst.isVolatileQualified(), "bf.load"); + CGM.DecorateInstructionWithTBAA(Load, Dst.getTBAAInfo()); + llvm::Value *Val = Load; // Mask the source value as needed. if (!Dst.getType()->hasBooleanRepresentation()) @@ -3101,12 +3103,14 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst, // of the container. The two accesses are not atomic. if (Dst.isVolatileQualified() && CodeGenUtils::isAAPCS(CGM.getTarget()) && CGM.getCodeGenOpts().ForceAAPCSBitfieldLoad) - Builder.CreateLoad(Ptr, true, "bf.load"); + CGM.DecorateInstructionWithTBAA(Builder.CreateLoad(Ptr, true, "bf.load"), + Dst.getTBAAInfo()); } // Write the new value back out. auto *I = Builder.CreateStore(SrcVal, Ptr, Dst.isVolatileQualified()); addInstToCurrentSourceAtom(I, SrcVal); + CGM.DecorateInstructionWithTBAA(I, Dst.getTBAAInfo()); // Return the new value of the bit-field, if requested. if (Result) { @@ -6009,10 +6013,27 @@ LValue CodeGenFunction::EmitLValueForField(LValue base, const FieldDecl *field, QualType fieldType = field->getType().withCVRQualifiers(base.getVRQualifiers()); - // TODO: Support TBAA for bit fields. + TBAAAccessInfo FieldTBAAInfo; + if (CGM.getCodeGenOpts().NewStructPathTBAA && !UseVolatile && + !base.getTBAAInfo().isMayAlias() && !rec->hasAttr<MayAliasAttr>() && + !rec->isUnion()) { + FieldTBAAInfo = base.getTBAAInfo(); + if (!FieldTBAAInfo.BaseType) { + FieldTBAAInfo.BaseType = CGM.getTBAABaseTypeInfo(base.getType()); + assert(!FieldTBAAInfo.Offset && + "Nonzero offset for an access with no base type!"); + } + + // A bit-field access reads or writes its complete storage unit. Use + // the character type for that unit while retaining its struct path. + if (FieldTBAAInfo.BaseType) + FieldTBAAInfo.Offset += Info.StorageOffset.getQuantity(); + FieldTBAAInfo.AccessType = CGM.getTBAATypeInfo(getContext().CharTy); + FieldTBAAInfo.Size = getContext().toCharUnitsFromBits(SS).getQuantity(); + } LValueBaseInfo FieldBaseInfo(BaseInfo.getAlignmentSource()); return LValue::MakeBitfield(Addr, Info, fieldType, FieldBaseInfo, - TBAAAccessInfo()); + FieldTBAAInfo); } // Fields of may-alias structures are may-alias themselves. diff --git a/clang/lib/CodeGen/CodeGenTBAA.cpp b/clang/lib/CodeGen/CodeGenTBAA.cpp index 1854df7c7c0f1..813a23550e179 100644 --- a/clang/lib/CodeGen/CodeGenTBAA.cpp +++ b/clang/lib/CodeGen/CodeGenTBAA.cpp @@ -559,19 +559,33 @@ llvm::MDNode *CodeGenTBAA::getBaseTypeInfoHelper(const Type *Ty) { return A.Offset < B.Offset; }); } + SmallVector<std::pair<uint64_t, uint64_t>, 4> BitFieldStorageUnits; for (FieldDecl *Field : RD->fields()) { if (Field->isZeroSize(Context) || Field->isUnnamedBitField()) continue; QualType FieldQTy = Field->getType(); - llvm::MDNode *TypeNode = isValidBaseType(FieldQTy) - ? getValidBaseTypeInfo(FieldQTy) - : getTypeInfo(FieldQTy); + llvm::MDNode *TypeNode; + uint64_t Offset; + uint64_t Size; + if (CodeGenOpts.NewStructPathTBAA && Field->isBitField()) { + const CGBitFieldInfo &Info = + CGTypes.getCGRecordLayout(RD).getBitFieldInfo(Field); + TypeNode = getChar(); + Offset = Info.StorageOffset.getQuantity(); + Size = llvm::divideCeil(Info.StorageSize, Context.getCharWidth()); + if (llvm::is_contained(BitFieldStorageUnits, + std::make_pair(Offset, Size))) + continue; + BitFieldStorageUnits.emplace_back(Offset, Size); + } else { + TypeNode = isValidBaseType(FieldQTy) ? getValidBaseTypeInfo(FieldQTy) + : getTypeInfo(FieldQTy); + uint64_t BitOffset = Layout.getFieldOffset(Field->getFieldIndex()); + Offset = Context.toCharUnitsFromBits(BitOffset).getQuantity(); + Size = Context.getTypeSizeInChars(FieldQTy).getQuantity(); + } if (!TypeNode) return nullptr; - - uint64_t BitOffset = Layout.getFieldOffset(Field->getFieldIndex()); - uint64_t Offset = Context.toCharUnitsFromBits(BitOffset).getQuantity(); - uint64_t Size = Context.getTypeSizeInChars(FieldQTy).getQuantity(); Fields.push_back(llvm::MDBuilder::TBAAStructField(Offset, Size, TypeNode)); } diff --git a/clang/test/CodeGen/tbaa-bitfield-access.c b/clang/test/CodeGen/tbaa-bitfield-access.c new file mode 100644 index 0000000000000..eaee5536bde43 --- /dev/null +++ b/clang/test/CodeGen/tbaa-bitfield-access.c @@ -0,0 +1,47 @@ +// RUN: %clang_cc1 -triple x86_64-linux -O1 -emit-llvm %s -o - | \ +// RUN: FileCheck %s --check-prefix=OLD +// RUN: %clang_cc1 -triple x86_64-linux -O1 -new-struct-path-tbaa \ +// RUN: -relaxed-aliasing -emit-llvm %s -o - | FileCheck %s --check-prefix=OLD +// RUN: %clang_cc1 -triple x86_64-linux -O1 -new-struct-path-tbaa \ +// RUN: -emit-llvm %s -o - | FileCheck %s --check-prefix=NEW + +struct A { + int a : 3; + int b : 3; +}; +struct B { + struct A a1, a2; +}; +struct C { + struct B b[10]; +} *c; +struct D { + struct C c; +} *d; + +// The two bit-fields occupy different storage units. Their TBAA tags retain +// enough of the enclosing struct path to prove that the store cannot clobber +// the value written by the first store. +// OLD-LABEL: define{{.*}} i32 @different_storage( +// OLD: load i8, ptr +// OLD: ret i32 +// NEW-LABEL: define{{.*}} i32 @different_storage( +// NEW-COUNT-2: load i8, ptr +// NEW: ret i32 0 +int different_storage(int i, int j) { + c->b[i].a1.a = 0; + d->c.b[j].a2.b = 1; + return c->b[i].a1.a; +} + +// These accesses may designate the same storage unit, so the reload must be +// retained. +// NEW-LABEL: define{{.*}} i32 @same_storage( +// NEW: store i8 +// NEW: load i8, ptr +// NEW: ret i32 +int same_storage(int i, int j) { + c->b[i].a1.a = 1; + d->c.b[j].a1.a = 0; + return c->b[i].a1.a; +} diff --git a/clang/test/CodeGen/tbaa-struct.cpp b/clang/test/CodeGen/tbaa-struct.cpp index 2776ea2e4e861..ec564277efcd0 100644 --- a/clang/test/CodeGen/tbaa-struct.cpp +++ b/clang/test/CodeGen/tbaa-struct.cpp @@ -224,12 +224,12 @@ void copy12(UnionMember2 *a1, UnionMember2 *a2) { // CHECK-NEW: [[META21]] = !{[[META4]], i64 6, !"_ZTS1D", [[META4]], i64 0, i64 1, [[META4]], i64 4, i64 1, [[META4]], i64 5, i64 1} // CHECK-NEW: [[TBAA23]] = !{[[META4]], [[META4]], i64 0, i64 0} // CHECK-NEW: [[TBAA24]] = !{[[META25:![0-9]+]], [[META25]], i64 0, i64 16} -// CHECK-NEW: [[META25]] = !{[[META4]], i64 16, !"_ZTS14NamedBitfields", [[META3]], i64 0, i64 4, [[META3]], i64 1, i64 4, [[META4]], i64 2, i64 1, [[META26:![0-9]+]], i64 8, i64 8} +// CHECK-NEW: [[META25]] = !{[[META4]], i64 16, !"_ZTS14NamedBitfields", [[META4]], i64 0, i64 2, [[META4]], i64 2, i64 1, [[META26:![0-9]+]], i64 8, i64 8} // CHECK-NEW: [[META26]] = !{[[META4]], i64 8, !"double"} // CHECK-NEW: [[TBAA30]] = !{[[META31:![0-9]+]], [[META31]], i64 0, i64 24} -// CHECK-NEW: [[META31]] = !{[[META4]], i64 24, !"_ZTS15NamedBitfields2", [[META4]], i64 0, i64 1, [[META4]], i64 1, i64 1, [[META4]], i64 2, i64 1, [[META3]], i64 3, i64 4, [[META3]], i64 3, i64 4, [[META4]], i64 4, i64 1, [[META26]], i64 8, i64 8, [[META3]], i64 16, i64 4} +// CHECK-NEW: [[META31]] = !{[[META4]], i64 24, !"_ZTS15NamedBitfields2", [[META4]], i64 0, i64 1, [[META4]], i64 1, i64 1, [[META4]], i64 2, i64 1, [[META4]], i64 3, i64 2, [[META26]], i64 8, i64 8, [[META4]], i64 16, i64 1} // CHECK-NEW: [[TBAA33]] = !{[[META34:![0-9]+]], [[META34]], i64 0, i64 16} -// CHECK-NEW: [[META34]] = !{[[META4]], i64 16, !"_ZTS15NamedBitfields3", [[META3]], i64 1, i64 4, [[META3]], i64 2, i64 4, [[META26]], i64 8, i64 8} +// CHECK-NEW: [[META34]] = !{[[META4]], i64 16, !"_ZTS15NamedBitfields3", [[META4]], i64 0, i64 4, [[META26]], i64 8, i64 8} // CHECK-NEW: [[TBAA37]] = !{[[META38:![0-9]+]], [[META38]], i64 0, i64 16} // CHECK-NEW: [[META38]] = !{[[META4]], i64 16, !"_ZTS12UnionMember1", [[META4]], i64 0, i64 8, [[META3]], i64 8, i64 4} // CHECK-NEW: [[TBAA41]] = !{[[META42:![0-9]+]], [[META42]], i64 0, i64 16} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
