diff --git a/clang/lib/CodeGen/CodeGenTBAA.cpp b/clang/lib/CodeGen/CodeGenTBAA.cpp --- a/clang/lib/CodeGen/CodeGenTBAA.cpp +++ b/clang/lib/CodeGen/CodeGenTBAA.cpp @@ -184,10 +184,31 @@ return getChar(); // Handle pointers and references. - // TODO: Implement C++'s type "similarity" and consider dis-"similar" - // pointers distinct. - if (Ty->isPointerType() || Ty->isReferenceType()) - return createScalarTypeNode("any pointer", getChar(), Size); + if (Ty->isPointerType() || Ty->isReferenceType()) { + llvm::MDNode *AnyPtr = createScalarTypeNode("any pointer", getChar(), Size); + // Compute the depth of the pointer and generate a tag of the form "p + // ". + unsigned PtrDepth = 0; + do { + PtrDepth++; + Ty = Ty->getPointeeType().getTypePtr(); + } while (Ty->isPointerType() || Ty->isReferenceType()); + // TODO: Implement C++'s type "similarity" and consider dis-"similar" + // pointers distinct for non-builtin types. + 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); + } + return AnyPtr; + } // Accesses to arrays are accesses to objects of their element types. if (CodeGenOpts.NewStructPathTBAA && Ty->isArrayType()) diff --git a/clang/test/CodeGen/tbaa-pointers.c b/clang/test/CodeGen/tbaa-pointers.c --- a/clang/test/CodeGen/tbaa-pointers.c +++ b/clang/test/CodeGen/tbaa-pointers.c @@ -1,79 +1,79 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin -O1 -disable-llvm-passes %s -emit-llvm -o - | FileCheck %s -void p2unsigned(unsigned **ptr) { +void p2unsigned(unsigned** ptr) { // CHECK-LABEL: define void @p2unsigned(i32** noundef %ptr) // CHECK-NEXT: entry: // CHECK-NEXT: %ptr.addr = alloca i32**, align 8 - // CHECK-NEXT: store i32** %ptr, i32*** %ptr.addr, align 8, !tbaa [[ANY_POINTER_0:!.+]] - // CHECK-NEXT: [[BASE:%.+]] = load i32**, i32*** %ptr.addr, align 8, !tbaa [[ANY_POINTER_0]] - // CHECK-NEXT: store i32* null, i32** [[BASE]], align 8, !tbaa [[ANY_POINTER_0]] + // CHECK-NEXT: store i32** %ptr, i32*** %ptr.addr, align 8, !tbaa [[P2INT_0:!.+]] + // CHECK-NEXT: [[BASE:%.+]] = load i32**, i32*** %ptr.addr, align 8, !tbaa [[P2INT_0]] + // CHECK-NEXT: store i32* null, i32** [[BASE]], align 8, !tbaa [[P1INT_0:!.+]] // CHECK-NEXT: ret void // *ptr = 0; } -void p2unsigned_volatile(unsigned *volatile *ptr) { +void p2unsigned_volatile(unsigned* volatile* ptr) { // CHECK-LABEL: define void @p2unsigned_volatile(i32** noundef %ptr) // CHECK-NEXT: entry: // CHECK-NEXT: %ptr.addr = alloca i32**, align 8 - // CHECK-NEXT: store i32** %ptr, i32*** %ptr.addr, align 8, !tbaa [[ANY_POINTER_0]] - // CHECK-NEXT: [[BASE:%.+]] = load i32**, i32*** %ptr.addr, align 8, !tbaa [[ANY_POINTER_0]] - // CHECK-NEXT: store volatile i32* null, i32** [[BASE]], align 8, !tbaa [[ANY_POINTER_0]] + // CHECK-NEXT: store i32** %ptr, i32*** %ptr.addr, align 8, !tbaa [[P2INT_0]] + // CHECK-NEXT: [[BASE:%.+]] = load i32**, i32*** %ptr.addr, align 8, !tbaa [[P2INT_0]] + // CHECK-NEXT: store volatile i32* null, i32** [[BASE]], align 8, !tbaa [[P1INT_0]] // CHECK-NEXT: ret void // *ptr = 0; } -void p3int(int ***ptr) { +void p3int(int*** ptr) { // CHECK-LABEL: define void @p3int(i32*** noundef %ptr) // CHECK-NEXT: entry: // CHECK-NEXT: %ptr.addr = alloca i32***, align 8 - // CHECK-NEXT: store i32*** %ptr, i32**** %ptr.addr, align 8, !tbaa [[ANY_POINTER_0]] - // CHECK-NEXT: [[BASE_0:%.+]] = load i32***, i32**** %ptr.addr, align 8, !tbaa [[ANY_POINTER_0]] - // CHECK-NEXT: [[BASE_1:%.+]] = load i32**, i32*** [[BASE_0]], align 8, !tbaa [[ANY_POINTER_0]] - // CHECK-NEXT: store i32* null, i32** [[BASE_1]], align 8, !tbaa [[ANY_POINTER_0]] + // CHECK-NEXT: store i32*** %ptr, i32**** %ptr.addr, align 8, !tbaa [[P3INT_0:!.+]] + // CHECK-NEXT: [[BASE_0:%.+]] = load i32***, i32**** %ptr.addr, align 8, !tbaa [[P3INT_0]] + // CHECK-NEXT: [[BASE_1:%.+]] = load i32**, i32*** [[BASE_0]], align 8, !tbaa [[P2INT_0]] + // CHECK-NEXT: store i32* null, i32** [[BASE_1]], align 8, !tbaa [[P1INT_0]] // CHECK-NEXT: ret void // **ptr = 0; } -void p4char(char ****ptr) { +void p4char(char**** ptr) { // CHECK-LABEL: define void @p4char(i8**** noundef %ptr) // CHECK-NEXT: entry: // CHECK-NEXT: %ptr.addr = alloca i8****, align 8 - // CHECK-NEXT: store i8**** %ptr, i8***** %ptr.addr, align 8, !tbaa [[ANY_POINTER_0]] - // CHECK-NEXT: [[BASE_0:%.+]] = load i8****, i8***** %ptr.addr, align 8, !tbaa [[ANY_POINTER_0]] - // CHECK-NEXT: [[BASE_1:%.+]] = load i8***, i8**** [[BASE_0]], align 8, !tbaa [[ANY_POINTER_0]] - // CHECK-NEXT: [[BASE_2:%.+]] = load i8**, i8*** [[BASE_1]], align 8, !tbaa [[ANY_POINTER_0]] - // CHECK-NEXT: store i8* null, i8** [[BASE_2]], align 8, !tbaa [[ANY_POINTER_0]] + // CHECK-NEXT: store i8**** %ptr, i8***** %ptr.addr, align 8, !tbaa [[P4CHAR_0:!.+]] + // CHECK-NEXT: [[BASE_0:%.+]] = load i8****, i8***** %ptr.addr, align 8, !tbaa [[P4CHAR_0]] + // CHECK-NEXT: [[BASE_1:%.+]] = load i8***, i8**** [[BASE_0]], align 8, !tbaa [[P3CHAR_0:!.+]] + // CHECK-NEXT: [[BASE_2:%.+]] = load i8**, i8*** [[BASE_1]], align 8, !tbaa [[P2CHAR_0:!.+]] + // CHECK-NEXT: store i8* null, i8** [[BASE_2]], align 8, !tbaa [[P1CHAR_0:!.+]] // CHECK-NEXT: ret void // ***ptr = 0; } -void p4char_const1(const char ****ptr) { +void p4char_const1(const char**** ptr) { // CHECK-LABEL: define void @p4char_const1(i8**** noundef %ptr) // CHECK-NEXT: entry: // CHECK-NEXT: %ptr.addr = alloca i8****, align 8 - // CHECK-NEXT: store i8**** %ptr, i8***** %ptr.addr, align 8, !tbaa [[ANY_POINTER_0]] - // CHECK-NEXT: [[BASE_0:%.+]] = load i8****, i8***** %ptr.addr, align 8, !tbaa [[ANY_POINTER_0]] - // CHECK-NEXT: [[BASE_1:%.+]] = load i8***, i8**** [[BASE_0]], align 8, !tbaa [[ANY_POINTER_0]] - // CHECK-NEXT: [[BASE_2:%.+]] = load i8**, i8*** [[BASE_1]], align 8, !tbaa [[ANY_POINTER_0]] - // CHECK-NEXT: store i8* null, i8** [[BASE_2]], align 8, !tbaa [[ANY_POINTER_0]] + // CHECK-NEXT: store i8**** %ptr, i8***** %ptr.addr, align 8, !tbaa [[P4CHAR_0]] + // CHECK-NEXT: [[BASE_0:%.+]] = load i8****, i8***** %ptr.addr, align 8, !tbaa [[P4CHAR_0]] + // CHECK-NEXT: [[BASE_1:%.+]] = load i8***, i8**** [[BASE_0]], align 8, !tbaa [[P3CHAR_0]] + // CHECK-NEXT: [[BASE_2:%.+]] = load i8**, i8*** [[BASE_1]], align 8, !tbaa [[P2CHAR_0]] + // CHECK-NEXT: store i8* null, i8** [[BASE_2]], align 8, !tbaa [[P1CHAR_0]] // CHECK-NEXT: ret void // ***ptr = 0; } -void p4char_const2(const char **const **ptr) { +void p4char_const2(const char**const ** ptr) { // CHECK-LABEL: define void @p4char_const2(i8**** noundef %ptr) // CHECK-NEXT: entry: // CHECK-NEXT: %ptr.addr = alloca i8****, align 8 - // CHECK-NEXT: store i8**** %ptr, i8***** %ptr.addr, align 8, !tbaa [[ANY_POINTER_0]] - // CHECK-NEXT: [[BASE_0:%.+]] = load i8****, i8***** %ptr.addr, align 8, !tbaa [[ANY_POINTER_0]] - // CHECK-NEXT: [[BASE_1:%.+]] = load i8***, i8**** [[BASE_0]], align 8, !tbaa [[ANY_POINTER_0]] - // CHECK-NEXT: [[BASE_2:%.+]] = load i8**, i8*** [[BASE_1]], align 8, !tbaa [[ANY_POINTER_0]] - // CHECK-NEXT: store i8* null, i8** [[BASE_2]], align 8, !tbaa [[ANY_POINTER_0]] + // CHECK-NEXT: store i8**** %ptr, i8***** %ptr.addr, align 8, !tbaa [[P4CHAR_0]] + // CHECK-NEXT: [[BASE_0:%.+]] = load i8****, i8***** %ptr.addr, align 8, !tbaa [[P4CHAR_0]] + // CHECK-NEXT: [[BASE_1:%.+]] = load i8***, i8**** [[BASE_0]], align 8, !tbaa [[P3CHAR_0]] + // CHECK-NEXT: [[BASE_2:%.+]] = load i8**, i8*** [[BASE_1]], align 8, !tbaa [[P2CHAR_0]] + // CHECK-NEXT: store i8* null, i8** [[BASE_2]], align 8, !tbaa [[P1CHAR_0]] // CHECK-NEXT: ret void // ***ptr = 0; @@ -84,20 +84,32 @@ int y; }; -void p2struct(struct S1 **ptr) { +void p2struct(struct S1** ptr) { // CHECK-LABEL: define void @p2struct(%struct.S1** noundef %ptr) // CHECK-NEXT: entry: // CHECK-NEXT: %ptr.addr = alloca %struct.S1**, align 8 - // CHECK-NEXT: store %struct.S1** %ptr, %struct.S1*** %ptr.addr, align 8, !tbaa [[ANY_POINTER_0]] - // CHECK-NEXT: [[BASE:%.+]] = load %struct.S1**, %struct.S1*** %ptr.addr, align 8, !tbaa [[ANY_POINTER_0]] - // CHECK-NEXT: store %struct.S1* null, %struct.S1** [[BASE]], align 8, !tbaa [[ANY_POINTER_0]] + // CHECK-NEXT: store %struct.S1** %ptr, %struct.S1*** %ptr.addr, align 8, !tbaa [[P2S1_0:!.+]] + // CHECK-NEXT: [[BASE:%.+]] = load %struct.S1**, %struct.S1*** %ptr.addr, align 8, !tbaa [[P2S1_0]] + // CHECK-NEXT: store %struct.S1* null, %struct.S1** [[BASE]], align 8, !tbaa [[P1S1_:!.+]] // CHECK-NEXT: ret void // *ptr = 0; } -// CHECK: [[ANY_POINTER_0]] = !{[[ANY_POINTER:!.+]], [[ANY_POINTER]], i64 0} +// CHECK: [[P2INT_0]] = !{[[P2INT:!.+]], [[P2INT]], i64 0} +// CHECK: [[P2INT]] = !{!"p2 int", [[ANY_POINTER:!.+]], i64 0} // CHECK: [[ANY_POINTER]] = !{!"any pointer", [[CHAR:!.+]], i64 0} // CHECK: [[CHAR]] = !{!"omnipotent char", [[TBAA_ROOT:!.+]], i64 0} // CHECK: [[TBAA_ROOT]] = !{!"Simple C/C++ TBAA"} -// +// CHECK: [[P1INT_0]] = !{[[P1INT:!.+]], [[P1INT]], i64 0} +// CHECK: [[P1INT]] = !{!"p1 int", [[ANY_POINTER]], i64 0} +// CHECK: [[P3INT_0]] = !{[[P3INT:!.+]], [[P3INT]], i64 0} +// CHECK: [[P3INT]] = !{!"p3 int", [[ANY_POINTER]], i64 0} +// CHECK: [[P4CHAR_0]] = !{[[P4CHAR:!.+]], [[P4CHAR]], i64 0} +// CHECK: [[P4CHAR]] = !{!"p4 omnipotent char", [[ANY_POINTER]], i64 0} +// CHECK: [[P3CHAR_0]] = !{[[P3CHAR:!.+]], [[P3CHAR]], i64 0} +// CHECK: [[P3CHAR]] = !{!"p3 omnipotent char", [[ANY_POINTER]], i64 0} +// CHECK: [[P2CHAR_0]] = !{[[P2CHAR:!.+]], [[P2CHAR]], i64 0} +// CHECK: [[P2CHAR]] = !{!"p2 omnipotent char", [[ANY_POINTER]], i64 0} +// CHECK: [[P1CHAR_0]] = !{[[P1CHAR:!.+]], [[P1CHAR]], i64 0} +// CHECK: [[P1CHAR]] = !{!"p1 omnipotent char", [[ANY_POINTER]], i64 0}