Skip to content

[TBAA] Only emit pointer tbaa metedata for record types. #116991

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Nov 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 23 additions & 4 deletions clang/lib/CodeGen/CodeGenTBAA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,14 +205,27 @@ llvm::MDNode *CodeGenTBAA::getTypeInfoHelper(const Type *Ty) {
llvm::MDNode *AnyPtr = createScalarTypeNode("any pointer", getChar(), Size);
if (!CodeGenOpts.PointerTBAA)
return AnyPtr;
// Compute the depth of the pointer and generate a tag of the form "p<depth>
// <base type tag>".
// C++ [basic.lval]p11 permits objects to accessed through an l-value of
// similar type. Two types are similar under C++ [conv.qual]p2 if the
// decomposition of the types into pointers, member pointers, and arrays has
// the same structure when ignoring cv-qualifiers at each level of the
// decomposition. Meanwhile, C makes T(*)[] and T(*)[N] compatible, which
// would really complicate any attempt to distinguish pointers to arrays by
// their bounds. It's simpler, and much easier to explain to users, to
// simply treat all pointers to arrays as pointers to their element type for
// aliasing purposes. So when creating a TBAA tag for a pointer type, we
// recursively ignore both qualifiers and array types when decomposing the
// pointee type. The only meaningful remaining structure is the number of
// pointer types we encountered along the way, so we just produce the tag
// "p<depth> <base type tag>". If we do find a member pointer type, for now
// we just conservatively bail out with AnyPtr (below) rather than trying to
// create a tag that honors the similar-type rules while still
// distinguishing different kinds of member pointer.
unsigned PtrDepth = 0;
do {
PtrDepth++;
Ty = Ty->getPointeeType().getTypePtr();
Ty = Ty->getPointeeType()->getBaseElementTypeUnsafe();
} while (Ty->isPointerType());
Ty = Context.getBaseElementType(QualType(Ty, 0)).getTypePtr();
assert(!isa<VariableArrayType>(Ty));
// When the underlying type is a builtin type, we compute the pointee type
// string recursively, which is implicitly more forgiving than the standards
Expand All @@ -230,6 +243,12 @@ llvm::MDNode *CodeGenTBAA::getTypeInfoHelper(const Type *Ty) {
->getString();
TyName = Name;
} else {
// Be conservative if the type isn't a RecordType. We are specifically
// required to do this for member pointers until we implement the
// similar-types rule.
if (!Ty->isRecordType())
return AnyPtr;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You know, you were probably right the first time to bail out for all non-record types — if we run into a vector type, or an ObjC pointer type, or something like that, it'd be better to fall back on AnyPtr. Please leave a comment saying that we're specifically required to do this for member pointers until we implement the similar-types rule, though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restored and added, thanks!


// For non-builtin types use the mangled name of the canonical type.
llvm::raw_svector_ostream TyOut(TyName);
MangleCtx->mangleCanonicalTypeName(QualType(Ty, 0), TyOut);
Expand Down
24 changes: 20 additions & 4 deletions clang/test/CXX/drs/cwg158.cpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
// RUN: %clang_cc1 -triple x86_64-linux -std=c++98 %s -O3 -disable-llvm-passes -pedantic-errors -emit-llvm -o - | FileCheck %s
// RUN: %clang_cc1 -triple x86_64-linux -std=c++11 %s -O3 -disable-llvm-passes -pedantic-errors -emit-llvm -o - | FileCheck %s
// RUN: %clang_cc1 -triple x86_64-linux -std=c++14 %s -O3 -disable-llvm-passes -pedantic-errors -emit-llvm -o - | FileCheck %s
// RUN: %clang_cc1 -triple x86_64-linux -std=c++1z %s -O3 -disable-llvm-passes -pedantic-errors -emit-llvm -o - | FileCheck %s
// RUN: %clang_cc1 -triple x86_64-linux -std=c++98 %s -O3 -disable-llvm-passes -pedantic-errors -emit-llvm -o - | FileCheck --check-prefixes=CHECK %s
// RUN: %clang_cc1 -triple x86_64-linux -std=c++11 %s -O3 -disable-llvm-passes -pedantic-errors -emit-llvm -o - | FileCheck --check-prefixes=CHECK %s
// RUN: %clang_cc1 -triple x86_64-linux -std=c++14 %s -O3 -disable-llvm-passes -pedantic-errors -emit-llvm -o - | FileCheck --check-prefixes=CHECK %s
// RUN: %clang_cc1 -triple x86_64-linux -std=c++1z %s -O3 -disable-llvm-passes -pedantic-errors -emit-llvm -o - | FileCheck --check-prefixes=CHECK %s
// RUN: %clang_cc1 -triple x86_64-linux -std=c++1z %s -O3 -pointer-tbaa -disable-llvm-passes -pedantic-errors -emit-llvm -o - | FileCheck --check-prefixes=CHECK,POINTER-TBAA %s

// cwg158: yes

// CHECK-LABEL: define {{.*}} @_Z1f
const int *f(const int * const *p, int **q) {
// CHECK: load ptr, ptr %p.addr
// CHECK: load ptr, {{.*}}, !tbaa ![[INTPTR_TBAA:[^,]*]]
const int *x = *p;
// CHECK: store ptr null, {{.*}}, !tbaa ![[INTPTR_TBAA]]
Expand All @@ -18,10 +20,24 @@ struct A {};

// CHECK-LABEL: define {{.*}} @_Z1g
const int *(A::*const *g(const int *(A::* const **p)[3], int *(A::***q)[3]))[3] {
// CHECK: load ptr, ptr %p.addr
// CHECK: load ptr, {{.*}}, !tbaa ![[MEMPTR_TBAA:[^,]*]]
const int *(A::*const *x)[3] = *p;
// CHECK: store ptr null, {{.*}}, !tbaa ![[MEMPTR_TBAA]]
*q = 0;
return x;
}

// CHECK-LABEL: define {{.*}} @_Z1h
const int * h(const int * (*p)[10], int *(*q)[9]) {
// CHECK: load ptr, ptr %p.addr, align 8, !tbaa [[PTRARRAY_TBAA:!.+]]
const int * x = *p[0];

// CHECK: load ptr, ptr %q.addr, align 8, !tbaa [[PTRARRAY_TBAA]]
*q[0] = 0;
return x;
}

// POINTER-TBAA: [[PTRARRAY_TBAA]] = !{[[PTRARRAY_TY:!.+]], [[PTRARRAY_TY]], i64 0}
// POINTER-TBAA: [[PTRARRAY_TY]] = !{!"p2 int", [[ANYPTR:!.+]], i64 0}
// POINTER-TBAA: [[ANYPTR]] = !{!"any pointer"
Loading