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 1/2] [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 4a481c01f6a68b..f51ca0af010f6c 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 1854df7c7c0f11..813a23550e179a 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 00000000000000..eaee5536bde43a --- /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 2776ea2e4e8619..ec564277efcd05 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} From 8278f6d48ac1ae861fd4cd18230ee9b79a090250 Mon Sep 17 00:00:00 2001 From: David Bolvansky <[email protected]> Date: Mon, 28 Sep 2026 13:15:02 +0200 Subject: [PATCH 2/2] clang: Check bit-field TBAA metadata from IRGen --- clang/test/CodeGen/tbaa-bitfield-access.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/clang/test/CodeGen/tbaa-bitfield-access.c b/clang/test/CodeGen/tbaa-bitfield-access.c index eaee5536bde43a..1e04e6b9cff96b 100644 --- a/clang/test/CodeGen/tbaa-bitfield-access.c +++ b/clang/test/CodeGen/tbaa-bitfield-access.c @@ -4,6 +4,9 @@ // 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 +// RUN: %clang_cc1 -triple x86_64-linux -O1 -disable-llvm-passes \ +// RUN: -new-struct-path-tbaa -emit-llvm %s -o - | \ +// RUN: FileCheck %s --check-prefix=IRGEN struct A { int a : 3; @@ -28,6 +31,12 @@ struct D { // NEW-LABEL: define{{.*}} i32 @different_storage( // NEW-COUNT-2: load i8, ptr // NEW: ret i32 0 +// IRGEN-LABEL: define{{.*}} i32 @different_storage( +// IRGEN: %bf.load = load i8, ptr %a1, align 4, !tbaa [[C_A1:![0-9]+]] +// IRGEN: store i8 %bf.set, ptr %a1, align 4, !tbaa [[C_A1]] +// IRGEN: %bf.load4 = load i8, ptr %a2, align 4, !tbaa [[D_A2:![0-9]+]] +// IRGEN: store i8 %bf.set6, ptr %a2, align 4, !tbaa [[D_A2]] +// IRGEN: %bf.load11 = load i8, ptr %a110, align 4, !tbaa [[C_A1]] int different_storage(int i, int j) { c->b[i].a1.a = 0; d->c.b[j].a2.b = 1; @@ -40,8 +49,19 @@ int different_storage(int i, int j) { // NEW: store i8 // NEW: load i8, ptr // NEW: ret i32 +// IRGEN-LABEL: define{{.*}} i32 @same_storage( +// IRGEN: %bf.load = load i8, ptr %a1, align 4, !tbaa [[C_A1]] +// IRGEN: store i8 %bf.set, ptr %a1, align 4, !tbaa [[C_A1]] +// IRGEN: %bf.load5 = load i8, ptr %a14, align 4, !tbaa [[D_A1:![0-9]+]] +// IRGEN: store i8 %bf.set7, ptr %a14, align 4, !tbaa [[D_A1]] +// IRGEN: %bf.load12 = load i8, ptr %a111, align 4, !tbaa [[C_A1]] 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; } + +// IRGEN-DAG: [[C_A1]] = !{[[C:![0-9]+]], [[CHAR:![0-9]+]], i64 0, i64 1} +// IRGEN-DAG: [[D_A2]] = !{[[D:![0-9]+]], [[CHAR]], i64 4, i64 1} +// IRGEN-DAG: [[D_A1]] = !{[[D]], [[CHAR]], i64 0, i64 1} +// IRGEN-DAG: [[A:![0-9]+]] = !{[[CHAR]], i64 4, !"A", [[CHAR]], i64 0, i64 1} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
