From 7d69ba5480448c68067ef10b9478f03929e6e4a8 Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Tue, 22 Oct 2024 16:23:34 -0700 Subject: [PATCH] [TBAA] Extend pointer TBAA to pointers of non-builtin types. (#110569) Extend the logic added in 123c036bd361d (https://github.com/llvm/llvm-project/pull/76612) to support pointers to non-builtin types by using the mangled name of the canonical type. PR: https://github.com/llvm/llvm-project/pull/110569 --- clang/lib/CodeGen/CodeGenTBAA.cpp | 42 +++++++++-------- clang/lib/CodeGen/CodeGenTBAA.h | 2 + clang/test/CodeGen/tbaa-pointers.c | 66 ++++++++++++++++++++++----- clang/test/CodeGen/tbaa-reference.cpp | 30 +++++++++--- 4 files changed, 104 insertions(+), 36 deletions(-) diff --git a/clang/lib/CodeGen/CodeGenTBAA.cpp b/clang/lib/CodeGen/CodeGenTBAA.cpp index 5b3393ec150e44..ec175b7fabe61f 100644 --- a/clang/lib/CodeGen/CodeGenTBAA.cpp +++ b/clang/lib/CodeGen/CodeGenTBAA.cpp @@ -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() { } @@ -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) @@ -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(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(Ty)) { llvm::MDNode *ScalarMD = getTypeInfoHelper(Ty); StringRef Name = cast( 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. diff --git a/clang/lib/CodeGen/CodeGenTBAA.h b/clang/lib/CodeGen/CodeGenTBAA.h index ba74a39a4d25ee..ab3b05df7713ba 100644 --- a/clang/lib/CodeGen/CodeGenTBAA.h +++ b/clang/lib/CodeGen/CodeGenTBAA.h @@ -24,6 +24,7 @@ namespace clang { class ASTContext; class CodeGenOptions; class LangOptions; + class MangleContext; class QualType; class Type; @@ -119,6 +120,7 @@ class CodeGenTBAA { llvm::Module &Module; const CodeGenOptions &CodeGenOpts; const LangOptions &Features; + std::unique_ptr MangleCtx; // MDHelper - Helper for creating metadata. llvm::MDBuilder MDHelper; diff --git a/clang/test/CodeGen/tbaa-pointers.c b/clang/test/CodeGen/tbaa-pointers.c index 8860b7042d0a25..f33281ada9903f 100644 --- a/clang/test/CodeGen/tbaa-pointers.c +++ b/clang/test/CodeGen/tbaa-pointers.c @@ -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; @@ -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; @@ -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} @@ -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} diff --git a/clang/test/CodeGen/tbaa-reference.cpp b/clang/test/CodeGen/tbaa-reference.cpp index d22cd90b43ae90..8395badf35ded5 100644 --- a/clang/test/CodeGen/tbaa-reference.cpp +++ b/clang/test/CodeGen/tbaa-reference.cpp @@ -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. @@ -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() { @@ -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"}