fhahn created this revision.
fhahn added reviewers: rjmccall, aaron.ballman, scanon, rsmith, hfinkel.
Herald added subscribers: jeroen.dobbelaere, kosarev.
Herald added a project: All.
fhahn requested review of this revision.
Herald added a project: clang.

This patch extends Clang's TBAA generation code to emit distinct tags
for incompatible pointer types.

Pointers with different element types are incompatible if the pointee
types are also incompatible (modulo sugar/modifiers).

Express this in TBAA by generating different tags for pointers based
on the pointer depth and pointee type. To get the TBAA tag for the
pointee type it uses getTypeInfoHelper on the pointee type.

I'd appreciate a careful review,  because this is probably quite easy to
get subtly wrong.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D122573

Files:
  clang/lib/CodeGen/CodeGenTBAA.cpp
  clang/test/CodeGen/tbaa-pointers.c

Index: clang/test/CodeGen/tbaa-pointers.c
===================================================================
--- clang/test/CodeGen/tbaa-pointers.c
+++ 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}
Index: clang/lib/CodeGen/CodeGenTBAA.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenTBAA.cpp
+++ 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<depth>
+    // <base type tag>".
+    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<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);
+    }
+    return AnyPtr;
+  }
 
   // Accesses to arrays are accesses to objects of their element types.
   if (CodeGenOpts.NewStructPathTBAA && Ty->isArrayType())
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to