Skip to content

Commit

Permalink
[TBAA] Extend pointer TBAA to pointers of non-builtin types. (#110569)
Browse files Browse the repository at this point in the history
Extend the logic added in 123c036
(#76612) to support pointers to
non-builtin types by using the mangled name of the canonical type.

PR: #110569
  • Loading branch information
fhahn authored Oct 22, 2024
1 parent 10f0c1a commit 4334f31
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 36 deletions.
42 changes: 24 additions & 18 deletions clang/lib/CodeGen/CodeGenTBAA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,9 @@ CodeGenTBAA::CodeGenTBAA(ASTContext &Ctx, CodeGenTypes &CGTypes,
llvm::Module &M, const CodeGenOptions &CGO,
const LangOptions &Features)
: Context(Ctx), CGTypes(CGTypes), Module(M), CodeGenOpts(CGO),
Features(Features), MDHelper(M.getContext()), Root(nullptr),
Char(nullptr) {}
Features(Features),
MangleCtx(ItaniumMangleContext::create(Ctx, Ctx.getDiagnostics())),
MDHelper(M.getContext()), Root(nullptr), Char(nullptr) {}

CodeGenTBAA::~CodeGenTBAA() {
}
Expand Down Expand Up @@ -202,14 +203,6 @@ llvm::MDNode *CodeGenTBAA::getTypeInfoHelper(const Type *Ty) {
// Other qualifiers could theoretically be distinguished, especially if
// they involve a significant representation difference. We don't
// currently do so, however.
//
// Computing the pointee type string recursively is implicitly more
// forgiving than the standards require. Effectively, we are turning
// the question "are these types compatible/similar" into "are
// accesses to these types allowed to alias". In both C and C++,
// the latter question has special carve-outs for signedness
// mismatches that only apply at the top level. As a result, we are
// allowing e.g. `int *` l-values to access `unsigned *` objects.
if (Ty->isPointerType() || Ty->isReferenceType()) {
llvm::MDNode *AnyPtr = createScalarTypeNode("any pointer", getChar(), Size);
if (!CodeGenOpts.PointerTBAA)
Expand All @@ -221,21 +214,34 @@ llvm::MDNode *CodeGenTBAA::getTypeInfoHelper(const Type *Ty) {
PtrDepth++;
Ty = Ty->getPointeeType().getTypePtr();
} while (Ty->isPointerType());
// TODO: Implement C++'s type "similarity" and consider dis-"similar"
// pointers distinct for non-builtin types.
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
// require. Effectively, we are turning the question "are these types
// compatible/similar" into "are accesses to these types allowed to alias".
// In both C and C++, the latter question has special carve-outs for
// signedness mismatches that only apply at the top level. As a result, we
// are allowing e.g. `int *` l-values to access `unsigned *` objects.
SmallString<256> TyName;
if (isa<BuiltinType>(Ty)) {
llvm::MDNode *ScalarMD = getTypeInfoHelper(Ty);
StringRef Name =
cast<llvm::MDString>(
ScalarMD->getOperand(CodeGenOpts.NewStructPathTBAA ? 2 : 0))
->getString();
SmallString<256> OutName("p");
OutName += std::to_string(PtrDepth);
OutName += " ";
OutName += Name;
return createScalarTypeNode(OutName, AnyPtr, Size);
TyName = Name;
} else {
// For non-builtin types use the mangled name of the canonical type.
llvm::raw_svector_ostream TyOut(TyName);
MangleCtx->mangleCanonicalTypeName(QualType(Ty, 0), TyOut);
}
return AnyPtr;

SmallString<256> OutName("p");
OutName += std::to_string(PtrDepth);
OutName += " ";
OutName += TyName;
return createScalarTypeNode(OutName, AnyPtr, Size);
}

// Accesses to arrays are accesses to objects of their element types.
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CodeGen/CodeGenTBAA.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ namespace clang {
class ASTContext;
class CodeGenOptions;
class LangOptions;
class MangleContext;
class QualType;
class Type;

Expand Down Expand Up @@ -119,6 +120,7 @@ class CodeGenTBAA {
llvm::Module &Module;
const CodeGenOptions &CodeGenOpts;
const LangOptions &Features;
std::unique_ptr<MangleContext> MangleCtx;

// MDHelper - Helper for creating metadata.
llvm::MDBuilder MDHelper;
Expand Down
66 changes: 55 additions & 11 deletions clang/test/CodeGen/tbaa-pointers.c
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,12 @@ void p2struct(struct S1 **ptr) {
// COMMON-LABEL: define void @p2struct(
// COMMON-SAME: ptr noundef [[PTR:%.+]])
// COMMON: [[PTR_ADDR:%.+]] = alloca ptr, align 8
// ENABLED-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8, !tbaa [[ANYPTR:!.+]]
// ENABLED-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8, !tbaa [[P2S1_TAG:!.+]]
// DEFAULT-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8, !tbaa [[ANYPTR]]
// COMMON-NEXT: [[BASE:%.+]] = load ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[ANYPTR]]
// COMMON-NEXT: store ptr null, ptr [[BASE]], align 8, !tbaa [[ANYPTR]]
// ENABLED-NEXT: [[BASE:%.+]] = load ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[P2S1_TAG]]
// DEFAULT-NEXT: [[BASE:%.+]] = load ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[ANYPTR]]
// ENABLED-NEXT: store ptr null, ptr [[BASE]], align 8, !tbaa [[P1S1_TAG:!.+]]
// DEFAULT-NEXT: store ptr null, ptr [[BASE]], align 8, !tbaa [[ANYPTR]]
// COMMON-NEXT: ret void
//
*ptr = 0;
Expand All @@ -129,9 +131,10 @@ void p2struct_const(struct S1 const **ptr) {
// COMMON-LABEL: define void @p2struct_const(
// COMMON-SAME: ptr noundef [[PTR:%.+]])
// COMMON: [[PTR_ADDR:%.+]] = alloca ptr, align 8
// COMMON-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8, !tbaa [[ANYPTR]]
// COMMON-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8, !tbaa [[ANYPTR:!.+]]
// COMMON-NEXT: [[BASE:%.+]] = load ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[ANYPTR]]
// COMMON-NEXT: store ptr null, ptr [[BASE]], align 8, !tbaa [[ANYPTR]]
// ENABLED-NEXT: store ptr null, ptr [[BASE]], align 8, !tbaa [[P1S1_TAG]]
// DEFAULT-NEXT: store ptr null, ptr [[BASE]], align 8, !tbaa [[ANYPTR]]
// COMMON-NEXT: ret void
//
*ptr = 0;
Expand All @@ -145,14 +148,44 @@ void p2struct2(struct S2 *ptr) {
// COMMON-LABEL: define void @p2struct2(
// COMMON-SAME: ptr noundef [[PTR:%.+]])
// COMMON: [[PTR_ADDR:%.+]] = alloca ptr, align 8
// COMMON-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8, !tbaa [[ANYPTR]]
// COMMON-NEXT: [[BASE:%.+]] = load ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[ANYPTR]]
// COMMON-NEXT: [[S:%.+]] = getelementptr inbounds nuw %struct.S2, ptr [[BASE]], i32 0, i32 0
// COMMON-NEXT: store ptr null, ptr [[S]], align 8, !tbaa [[S2_S_TAG:!.+]]
// ENABLED-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8, !tbaa [[P1S2_TAG:!.+]]
// ENABLED-NEXT: [[BASE:%.+]] = load ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[P1S2_TAG]]
// ENABLED-NEXT: [[S:%.+]] = getelementptr inbounds nuw %struct.S2, ptr [[BASE]], i32 0, i32 0
// ENABLED-NEXT: store ptr null, ptr [[S]], align 8, !tbaa [[S2_S_TAG:!.+]]
// DEFAULT-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8, !tbaa [[ANYPTR]]
// DEFAULT-NEXT: [[BASE:%.+]] = load ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[ANYPTR]]
// DEFAULT-NEXT: [[S:%.+]] = getelementptr inbounds nuw %struct.S2, ptr [[BASE]], i32 0, i32 0
// DEFAULT-NEXT: store ptr null, ptr [[S]], align 8, !tbaa [[S2_S_TAG:!.+]]
// COMMON-NEXT: ret void
ptr->s = 0;
}


void vla1(int n, int ptr[][n], int idx) {
// COMMON-LABEL: define void @vla1(
// COMMON-SAME: i32 noundef [[N:%.+]], ptr noundef [[PTR:%.+]], i32 noundef [[IDX:%.+]])
// COMMON: [[N_ADDR:%.+]] = alloca i32, align 4
// COMMON-NEXT: [[PTR_ADDR:%.+]] = alloca ptr, align 8
// COMMON-NEXT: [[IDX_ADDR:%.+]] = alloca i32, align 4
// COMMON-NEXT: store i32 [[N]], ptr [[N_ADDR]], align 4, !tbaa [[INT_TY:!.+]]
// ENABLED-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8, !tbaa [[P1INT0:!.+]]
// DEFAULT-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8, !tbaa [[ANYPTR]]
// COMMON-NEXT: store i32 [[IDX]], ptr [[IDX_ADDR]], align 4, !tbaa [[INT_TY]]
// COMMON-NEXT: [[L:%.+]] = load i32, ptr [[N_ADDR]], align 4, !tbaa [[INT_TY]]
// COMMON-NEXT: [[L_EXT:%.+]] = zext i32 [[L]] to i64
// ENABLED-NEXT: [[L_PTR:%.+]] = load ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[P1INT0]]
// DEFAULT-NEXT: [[L_PTR:%.+]] = load ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[ANYPTR]]
// COMMON-NEXT: [[L_IDX:%.+]] = load i32, ptr [[IDX_ADDR]], align 4, !tbaa [[INT_TY]]
// COMMON-NEXT: [[IDX_EXT:%.+]] = sext i32 [[L_IDX]] to i64
// COMMON-NEXT: [[MUL:%.+]] = mul nsw i64 [[IDX_EXT]], [[L_EXT]]
// COMMON-NEXT: [[GEP1:%.+]] = getelementptr inbounds i32, ptr [[L_PTR]], i64 [[MUL]]
// COMMON-NEXT: [[GEP2:%.+]] = getelementptr inbounds i32, ptr [[GEP1]], i64 0
// COMMON-NEXT: store i32 0, ptr [[GEP2]], align 4, !tbaa [[INT_TAG:!.+]]
// ENABLED-NEXT: ret void

ptr[idx][0] = 0;
}

// ENABLED: [[P2INT_0]] = !{[[P2INT:!.+]], [[P2INT]], i64 0}
// ENABLED: [[P2INT]] = !{!"p2 int", [[ANY_POINTER:!.+]], i64 0}
// DEFAULT: [[ANYPTR]] = !{[[ANY_POINTER:!.+]], [[ANY_POINTER]], i64 0}
Expand All @@ -171,5 +204,16 @@ void p2struct2(struct S2 *ptr) {
// ENABLED: [[P2CHAR]] = !{!"p2 omnipotent char", [[ANY_POINTER]], i64 0}
// ENABLED: [[P1CHAR_0]] = !{[[P1CHAR:!.+]], [[P1CHAR]], i64 0}
// ENABLED: [[P1CHAR]] = !{!"p1 omnipotent char", [[ANY_POINTER]], i64 0}
// COMMON: [[S2_S_TAG]] = !{[[S2_TY:!.+]], [[ANY_POINTER]], i64 0}
// COMMON: [[S2_TY]] = !{!"S2", [[ANY_POINTER]], i64 0}
// ENABLED: [[P2S1_TAG]] = !{[[P2S1:!.+]], [[P2S1]], i64 0}
// ENABLED: [[P2S1]] = !{!"p2 _ZTS2S1", [[ANY_POINTER]], i64 0}
// ENABLED: [[P1S1_TAG:!.+]] = !{[[P1S1:!.+]], [[P1S1]], i64 0}
// ENABLED: [[P1S1]] = !{!"p1 _ZTS2S1", [[ANY_POINTER]], i64 0}
// ENABLED: [[P1S2_TAG]] = !{[[P1S2:!.+]], [[P1S2]], i64 0}
// ENABLED: [[P1S2]] = !{!"p1 _ZTS2S2", [[ANY_POINTER]], i64 0}

// ENABLED: [[S2_S_TAG]] = !{[[S2_TY:!.+]], [[P1S1]], i64 0}
// ENABLED: [[S2_TY]] = !{!"S2", [[P1S1]], i64 0}
// DEFAULT: [[S2_S_TAG]] = !{[[S2_TY:!.+]], [[ANY_POINTER]], i64 0}
// DEFAULT: [[S2_TY]] = !{!"S2", [[ANY_POINTER]], i64 0}
// COMMON: [[INT_TAG]] = !{[[INT_TY:!.+]], [[INT_TY]], i64 0}
// COMMON: [[INT_TY]] = !{!"int", [[CHAR]], i64 0}
30 changes: 23 additions & 7 deletions clang/test/CodeGen/tbaa-reference.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -triple x86_64-linux -O1 -disable-llvm-passes %s -emit-llvm -o - | FileCheck %s -check-prefixes=CHECK,OLD-PATH
// RUN: %clang_cc1 -triple x86_64-linux -O1 -disable-llvm-passes -pointer-tbaa %s -emit-llvm -o - | FileCheck %s -check-prefixes=CHECK,OLD-PATH
// RUN: %clang_cc1 -triple x86_64-linux -O1 -disable-llvm-passes -pointer-tbaa %s -emit-llvm -o - | FileCheck %s -check-prefixes=CHECK,OLD-PATH-POINTER
// RUN: %clang_cc1 -triple x86_64-linux -O1 -disable-llvm-passes %s -emit-llvm -new-struct-path-tbaa -o - | FileCheck %s -check-prefixes=CHECK,NEW-PATH
// RUN: %clang_cc1 -triple x86_64-linux -O1 -disable-llvm-passes %s -pointer-tbaa -emit-llvm -new-struct-path-tbaa -o - | FileCheck %s -check-prefixes=CHECK,NEW-PATH
// RUN: %clang_cc1 -triple x86_64-linux -O1 -disable-llvm-passes %s -pointer-tbaa -emit-llvm -new-struct-path-tbaa -o - | FileCheck %s -check-prefixes=CHECK,NEW-PATH-POINTER
//
// Check that we generate correct TBAA information for reference accesses.

Expand All @@ -16,13 +16,13 @@ struct B {
B::B(S &s) : s(s) {
// CHECK-LABEL: _ZN1BC2ER1S
// Check initialization of the reference parameter.
// CHECK: store ptr {{.*}}, ptr {{.*}}, !tbaa [[TAG_pointer:!.*]]
// CHECK: store ptr {{.*}}, ptr %s.addr, align 8, !tbaa [[TAG_S_PTR:!.*]]

// Check loading of the reference parameter.
// CHECK: load ptr, ptr {{.*}}, !tbaa [[TAG_pointer]]
// CHECK: load ptr, ptr {{.*}}, !tbaa [[TAG_S_PTR:!.*]]

// Check initialization of the reference member.
// CHECK: store ptr {{.*}}, ptr {{.*}}, !tbaa [[TAG_pointer]]
// CHECK: store ptr {{.*}}, ptr {{.*}}, !tbaa [[TAG_S_PTR]]
}

S &B::get() {
Expand All @@ -32,16 +32,32 @@ S &B::get() {
return s;
}

// OLD-PATH-DAG: [[TAG_pointer]] = !{[[TYPE_pointer:!.*]], [[TYPE_pointer]], i64 0}
// OLD-PATH-DAG: [[TAG_S_PTR]] = !{[[TYPE_pointer:!.*]], [[TYPE_pointer]], i64 0}
// OLD-PATH-DAG: [[TAG_B_s]] = !{[[TYPE_B:!.*]], [[TYPE_pointer]], i64 0}
//
// OLD-PATH-DAG: [[TYPE_B]] = !{!"_ZTS1B", [[TYPE_pointer]], i64 0}
// OLD-PATH-DAG: [[TYPE_pointer]] = !{!"any pointer", [[TYPE_char:!.*]], i64 0}
// OLD-PATH-DAG: [[TYPE_char]] = !{!"omnipotent char", {{!.*}}, i64 0}

// NEW-PATH-DAG: [[TAG_pointer]] = !{[[TYPE_pointer:!.*]], [[TYPE_pointer]], i64 0, i64 8}
// OLD-PATH-POINTER-DAG: [[TAG_S_PTR]] = !{[[TYPE_S_PTR:!.*]], [[TYPE_S_PTR]], i64 0}
// OLD-PATH-POINTER-DAG: [[TAG_B_s]] = !{[[TYPE_B:!.*]], [[TYPE_S_PTR:!.*]], i64 0}
//
// OLD-PATH-POINTER-DAG: [[TYPE_B]] = !{!"_ZTS1B", [[TYPE_S_PTR:!.*]], i64 0}
// OLD-PATH-POINTER-DAG: [[TYPE_pointer:!.*]] = !{!"any pointer", [[TYPE_char:!.*]], i64 0}
// OLD-PATH-POINTER-DAG: [[TYPE_char]] = !{!"omnipotent char", {{!.*}}, i64 0}
// OLD-PATH-POINTER-DAG: [[TYPE_S_PTR]] = !{!"p1 _ZTS1S", [[TYPE_pointer]], i64 0}

// NEW-PATH-DAG: [[TAG_S_PTR]] = !{[[TYPE_pointer:!.*]], [[TYPE_pointer]], i64 0, i64 8}
// NEW-PATH-DAG: [[TAG_B_s]] = !{[[TYPE_B:!.*]], [[TYPE_pointer]], i64 0, i64 8}
//
// NEW-PATH-DAG: [[TYPE_B]] = !{[[TYPE_char:!.*]], i64 8, !"_ZTS1B", [[TYPE_pointer]], i64 0, i64 8}
// NEW-PATH-DAG: [[TYPE_pointer]] = !{[[TYPE_char:!.*]], i64 8, !"any pointer"}
// NEW-PATH-DAG: [[TYPE_char]] = !{{{!.*}}, i64 1, !"omnipotent char"}

// NEW-PATH-POINTER-DAG: [[TAG_S_PTR]] = !{[[TYPE_S_PTR:!.*]], [[TYPE_S_PTR]], i64 0, i64 8}
// NEW-PATH-POINTER-DAG: [[TAG_B_s]] = !{[[TYPE_B:!.*]], [[TYPE_S_PTR]], i64 0, i64 8}
//
// NEW-PATH-POINTER-DAG: [[TYPE_B]] = !{[[TYPE_char:!.*]], i64 8, !"_ZTS1B", [[TYPE_S_PTR]], i64 0, i64 8}
// NEW-PATH-POINTER-DAG: [[TYPE_S_PTR]] = !{[[TYPE_pointer:!.+]], i64 8, !"p1 _ZTS1S"}
// NEW-PATH-POINTER-DAG: [[TYPE_pointer]] = !{[[TYPE_char:!.*]], i64 8, !"any pointer"}
// NEW-PATH-POINTER-DAG: [[TYPE_char]] = !{{{!.*}}, i64 1, !"omnipotent char"}

0 comments on commit 4334f31

Please sign in to comment.