[llvm] [UTC] Record TBAA semantics when autogenerating check lines (PR #147670)

Antonio Frighetto via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 9 01:29:47 PDT 2025


https://github.com/antoniofrighetto updated https://github.com/llvm/llvm-project/pull/147670

>From 790a62f2d8dafa49afc22f4e0b77d1d4942cb3e3 Mon Sep 17 00:00:00 2001
From: Antonio Frighetto <me at antoniofrighetto.com>
Date: Thu, 26 Jun 2025 15:35:41 +0200
Subject: [PATCH 1/3] [UTC] Introduce test (NFC)

---
 .../Inputs/tbaa-semantics-checks.ll           |  84 ++++++++++
 .../Inputs/tbaa-semantics-checks.ll.expected  | 156 ++++++++++++++++++
 .../tbaa-semantics-checks.test                |   7 +
 3 files changed, 247 insertions(+)
 create mode 100644 llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/tbaa-semantics-checks.ll
 create mode 100644 llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/tbaa-semantics-checks.ll.expected
 create mode 100644 llvm/test/tools/UpdateTestChecks/update_test_checks/tbaa-semantics-checks.test

diff --git a/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/tbaa-semantics-checks.ll b/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/tbaa-semantics-checks.ll
new file mode 100644
index 0000000000000..9d6059602bdb3
--- /dev/null
+++ b/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/tbaa-semantics-checks.ll
@@ -0,0 +1,84 @@
+; RUN: opt < %s -S | FileCheck %s
+
+define void @store_unsignedptr(ptr %ptr) {
+entry:
+  store ptr null, ptr %ptr, align 8, !tbaa !0
+  ret void
+}
+
+define void @store_char(ptr %ptr) {
+entry:
+  store i8 0, ptr %ptr, align 1, !tbaa !5
+  ret void
+}
+
+define float @ptr_to_float(ptr %ptr) {
+entry:
+  store float 0.000000e+00, ptr %ptr, align 4, !tbaa !6
+  call void @opaque(ptr %ptr)
+  %val = load float, ptr %ptr, align 4, !tbaa !6
+  ret float %val
+}
+
+define i64 @ptr_to_longlong(ptr %ptr) {
+entry:
+  %val = load i64, ptr %ptr, align 8, !tbaa !8
+  store i64 0, ptr %ptr, align 8, !tbaa !8
+  ret i64 %val
+}
+
+; struct STRUCT1 {
+;   int x;
+;   int y;
+; };
+
+define void @store_struct1ptr(ptr %ptr) {
+entry:
+  ; *(struct STRUCT1 **)ptr = 0;
+  store ptr null, ptr %ptr, align 8, !tbaa !10
+  ret void
+}
+
+; struct STRUCT2 {
+;   struct STRUCT1 *s;
+; };
+
+define void @store_struct2(ptr %ptr) {
+entry:
+  ; ptr->s = 0;
+  store ptr null, ptr %ptr, align 8, !tbaa !12
+  ret void
+}
+
+define double @access_matrix(ptr %ptr) {
+entry:
+  %alloca.ptr = alloca ptr, align 8
+  store ptr %ptr, ptr %alloca.ptr, align 8, !tbaa !14
+  %ptr.idx = load ptr, ptr %alloca.ptr, align 8, !tbaa !14
+  %add.ptr = getelementptr inbounds ptr, ptr %ptr.idx, i64 4
+  %ptr.idx.1 = load ptr, ptr %add.ptr, align 8, !tbaa !16
+  %add.ptr1 = getelementptr inbounds [6 x double], ptr %ptr.idx.1, i64 6
+  %ptr.idx.2 = load <6 x double>, ptr %add.ptr1, align 8, !tbaa !5
+  %matrixext = extractelement <6 x double> %ptr.idx.2, i64 5
+  ret double %matrixext
+}
+
+declare void @opaque(ptr)
+
+!0 = !{!1, !1, i64 0}
+!1 = !{!"p1 int", !2, i64 0}
+!2 = !{!"any pointer", !3, i64 0}
+!3 = !{!"omnipotent char", !4, i64 0}
+!4 = !{!"Simple C/C++ TBAA"}
+!5 = !{!3, !3, i64 0}
+!6 = !{!7, !7, i64 0}
+!7 = !{!"float", !3, i64 0}
+!8 = !{!9, !9, i64 0}
+!9 = !{!"long long", !3, i64 0}
+!10 = !{!11, !11, i64 0}
+!11 = !{!"p1 _ZTS7STRUCT1", !2, i64 0}
+!12 = !{!13, !11, i64 0}
+!13 = !{!"STRUCT2", !11, i64 0}
+!14 = !{!15, !15, i64 0}
+!15 = !{!"any p2 pointer", !2, i64 0}
+!16 = !{!2, !2, i64 0}
diff --git a/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/tbaa-semantics-checks.ll.expected b/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/tbaa-semantics-checks.ll.expected
new file mode 100644
index 0000000000000..0cd8b9c4817d0
--- /dev/null
+++ b/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/tbaa-semantics-checks.ll.expected
@@ -0,0 +1,156 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt < %s -S | FileCheck %s
+
+define void @store_unsignedptr(ptr %ptr) {
+; CHECK-LABEL: define void @store_unsignedptr(
+; CHECK-SAME: ptr [[PTR:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    store ptr null, ptr [[PTR]], align 8, !tbaa [[TBAA0:![0-9]+]]
+; CHECK-NEXT:    ret void
+;
+entry:
+  store ptr null, ptr %ptr, align 8, !tbaa !0
+  ret void
+}
+
+define void @store_char(ptr %ptr) {
+; CHECK-LABEL: define void @store_char(
+; CHECK-SAME: ptr [[PTR:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    store i8 0, ptr [[PTR]], align 1, !tbaa [[TBAA5:![0-9]+]]
+; CHECK-NEXT:    ret void
+;
+entry:
+  store i8 0, ptr %ptr, align 1, !tbaa !5
+  ret void
+}
+
+define float @ptr_to_float(ptr %ptr) {
+; CHECK-LABEL: define float @ptr_to_float(
+; CHECK-SAME: ptr [[PTR:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    store float 0.000000e+00, ptr [[PTR]], align 4, !tbaa [[TBAA6:![0-9]+]]
+; CHECK-NEXT:    call void @opaque(ptr [[PTR]])
+; CHECK-NEXT:    [[VAL:%.*]] = load float, ptr [[PTR]], align 4, !tbaa [[TBAA6]]
+; CHECK-NEXT:    ret float [[VAL]]
+;
+entry:
+  store float 0.000000e+00, ptr %ptr, align 4, !tbaa !6
+  call void @opaque(ptr %ptr)
+  %val = load float, ptr %ptr, align 4, !tbaa !6
+  ret float %val
+}
+
+define i64 @ptr_to_longlong(ptr %ptr) {
+; CHECK-LABEL: define i64 @ptr_to_longlong(
+; CHECK-SAME: ptr [[PTR:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[VAL:%.*]] = load i64, ptr [[PTR]], align 8, !tbaa [[TBAA8:![0-9]+]]
+; CHECK-NEXT:    store i64 0, ptr [[PTR]], align 8, !tbaa [[TBAA8]]
+; CHECK-NEXT:    ret i64 [[VAL]]
+;
+entry:
+  %val = load i64, ptr %ptr, align 8, !tbaa !8
+  store i64 0, ptr %ptr, align 8, !tbaa !8
+  ret i64 %val
+}
+
+; struct STRUCT1 {
+;   int x;
+;   int y;
+; };
+
+define void @store_struct1ptr(ptr %ptr) {
+; CHECK-LABEL: define void @store_struct1ptr(
+; CHECK-SAME: ptr [[PTR:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    store ptr null, ptr [[PTR]], align 8, !tbaa [[TBAA10:![0-9]+]]
+; CHECK-NEXT:    ret void
+;
+entry:
+  ; *(struct STRUCT1 **)ptr = 0;
+  store ptr null, ptr %ptr, align 8, !tbaa !10
+  ret void
+}
+
+; struct STRUCT2 {
+;   struct STRUCT1 *s;
+; };
+
+define void @store_struct2(ptr %ptr) {
+; CHECK-LABEL: define void @store_struct2(
+; CHECK-SAME: ptr [[PTR:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    store ptr null, ptr [[PTR]], align 8, !tbaa [[TBAA12:![0-9]+]]
+; CHECK-NEXT:    ret void
+;
+entry:
+  ; ptr->s = 0;
+  store ptr null, ptr %ptr, align 8, !tbaa !12
+  ret void
+}
+
+define double @access_matrix(ptr %ptr) {
+; CHECK-LABEL: define double @access_matrix(
+; CHECK-SAME: ptr [[PTR:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[ALLOCA_PTR:%.*]] = alloca ptr, align 8
+; CHECK-NEXT:    store ptr [[PTR]], ptr [[ALLOCA_PTR]], align 8, !tbaa [[TBAA14:![0-9]+]]
+; CHECK-NEXT:    [[PTR_IDX:%.*]] = load ptr, ptr [[ALLOCA_PTR]], align 8, !tbaa [[TBAA14]]
+; CHECK-NEXT:    [[ADD_PTR:%.*]] = getelementptr inbounds ptr, ptr [[PTR_IDX]], i64 4
+; CHECK-NEXT:    [[PTR_IDX_1:%.*]] = load ptr, ptr [[ADD_PTR]], align 8, !tbaa [[TBAA16:![0-9]+]]
+; CHECK-NEXT:    [[ADD_PTR1:%.*]] = getelementptr inbounds [6 x double], ptr [[PTR_IDX_1]], i64 6
+; CHECK-NEXT:    [[PTR_IDX_2:%.*]] = load <6 x double>, ptr [[ADD_PTR1]], align 8, !tbaa [[TBAA5]]
+; CHECK-NEXT:    [[MATRIXEXT:%.*]] = extractelement <6 x double> [[PTR_IDX_2]], i64 5
+; CHECK-NEXT:    ret double [[MATRIXEXT]]
+;
+entry:
+  %alloca.ptr = alloca ptr, align 8
+  store ptr %ptr, ptr %alloca.ptr, align 8, !tbaa !14
+  %ptr.idx = load ptr, ptr %alloca.ptr, align 8, !tbaa !14
+  %add.ptr = getelementptr inbounds ptr, ptr %ptr.idx, i64 4
+  %ptr.idx.1 = load ptr, ptr %add.ptr, align 8, !tbaa !16
+  %add.ptr1 = getelementptr inbounds [6 x double], ptr %ptr.idx.1, i64 6
+  %ptr.idx.2 = load <6 x double>, ptr %add.ptr1, align 8, !tbaa !5
+  %matrixext = extractelement <6 x double> %ptr.idx.2, i64 5
+  ret double %matrixext
+}
+
+declare void @opaque(ptr)
+
+!0 = !{!1, !1, i64 0}
+!1 = !{!"p1 int", !2, i64 0}
+!2 = !{!"any pointer", !3, i64 0}
+!3 = !{!"omnipotent char", !4, i64 0}
+!4 = !{!"Simple C/C++ TBAA"}
+!5 = !{!3, !3, i64 0}
+!6 = !{!7, !7, i64 0}
+!7 = !{!"float", !3, i64 0}
+!8 = !{!9, !9, i64 0}
+!9 = !{!"long long", !3, i64 0}
+!10 = !{!11, !11, i64 0}
+!11 = !{!"p1 _ZTS7STRUCT1", !2, i64 0}
+!12 = !{!13, !11, i64 0}
+!13 = !{!"STRUCT2", !11, i64 0}
+!14 = !{!15, !15, i64 0}
+!15 = !{!"any p2 pointer", !2, i64 0}
+!16 = !{!2, !2, i64 0}
+;.
+; CHECK: [[TBAA0]] = !{[[META1:![0-9]+]], [[META1]], i64 0}
+; CHECK: [[META1]] = !{!"p1 int", [[META2:![0-9]+]], i64 0}
+; CHECK: [[META2]] = !{!"any pointer", [[META3:![0-9]+]], i64 0}
+; CHECK: [[META3]] = !{!"omnipotent char", [[META4:![0-9]+]], i64 0}
+; CHECK: [[META4]] = !{!"Simple C/C++ TBAA"}
+; CHECK: [[TBAA5]] = !{[[META3]], [[META3]], i64 0}
+; CHECK: [[TBAA6]] = !{[[META7:![0-9]+]], [[META7]], i64 0}
+; CHECK: [[META7]] = !{!"float", [[META3]], i64 0}
+; CHECK: [[TBAA8]] = !{[[META9:![0-9]+]], [[META9]], i64 0}
+; CHECK: [[META9]] = !{!"long long", [[META3]], i64 0}
+; CHECK: [[TBAA10]] = !{[[META11:![0-9]+]], [[META11]], i64 0}
+; CHECK: [[META11]] = !{!"p1 _ZTS7STRUCT1", [[META2]], i64 0}
+; CHECK: [[TBAA12]] = !{[[META13:![0-9]+]], [[META11]], i64 0}
+; CHECK: [[META13]] = !{!"STRUCT2", [[META11]], i64 0}
+; CHECK: [[TBAA14]] = !{[[META15:![0-9]+]], [[META15]], i64 0}
+; CHECK: [[META15]] = !{!"any p2 pointer", [[META2]], i64 0}
+; CHECK: [[TBAA16]] = !{[[META2]], [[META2]], i64 0}
+;.
diff --git a/llvm/test/tools/UpdateTestChecks/update_test_checks/tbaa-semantics-checks.test b/llvm/test/tools/UpdateTestChecks/update_test_checks/tbaa-semantics-checks.test
new file mode 100644
index 0000000000000..e715639394846
--- /dev/null
+++ b/llvm/test/tools/UpdateTestChecks/update_test_checks/tbaa-semantics-checks.test
@@ -0,0 +1,7 @@
+## Test correct application of TBAA semantics in TBAA check lines.
+# RUN: cp -f %S/Inputs/tbaa-semantics-checks.ll %t.ll && %update_test_checks --version 5 %t.ll
+# RUN: diff -u %t.ll %S/Inputs/tbaa-semantics-checks.ll.expected
+
+## Check that running the script again does not change the result.
+# RUN: %update_test_checks %t.ll
+# RUN: diff -u %t.ll %S/Inputs/tbaa-semantics-checks.ll.expected

>From fd9a4baec4805d0a4ef58858e43b25dd11a0b801 Mon Sep 17 00:00:00 2001
From: Antonio Frighetto <me at antoniofrighetto.com>
Date: Wed, 2 Jul 2025 14:52:07 +0200
Subject: [PATCH 2/3] [UTC] Record TBAA semantics when autogenerating check
 lines
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

UpdateTestChecks have been updated to take into account TBAA
semantics as well, when emitting checks. This is achieved by
parsing TBAA metadata for each tool invocation – whose tool
is identified by their prefixes –, and maintaining a global
dict of prefixes, TBAA nodes.
---
 .../Inputs/tbaa-semantics-checks.ll.expected  | 42 ++++-----
 .../tbaa-semantics-checks.test                |  2 +-
 llvm/utils/UpdateTestChecks/common.py         | 91 ++++++++++++++++++-
 llvm/utils/update_cc_test_checks.py           | 10 ++
 llvm/utils/update_test_checks.py              | 10 ++
 5 files changed, 130 insertions(+), 25 deletions(-)

diff --git a/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/tbaa-semantics-checks.ll.expected b/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/tbaa-semantics-checks.ll.expected
index 0cd8b9c4817d0..39d573208e7b6 100644
--- a/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/tbaa-semantics-checks.ll.expected
+++ b/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/tbaa-semantics-checks.ll.expected
@@ -1,11 +1,11 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
 ; RUN: opt < %s -S | FileCheck %s
 
 define void @store_unsignedptr(ptr %ptr) {
 ; CHECK-LABEL: define void @store_unsignedptr(
 ; CHECK-SAME: ptr [[PTR:%.*]]) {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
-; CHECK-NEXT:    store ptr null, ptr [[PTR]], align 8, !tbaa [[TBAA0:![0-9]+]]
+; CHECK-NEXT:    store ptr null, ptr [[PTR]], align 8, !tbaa [[INTPTR_TBAA0:![0-9]+]]
 ; CHECK-NEXT:    ret void
 ;
 entry:
@@ -17,7 +17,7 @@ define void @store_char(ptr %ptr) {
 ; CHECK-LABEL: define void @store_char(
 ; CHECK-SAME: ptr [[PTR:%.*]]) {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
-; CHECK-NEXT:    store i8 0, ptr [[PTR]], align 1, !tbaa [[TBAA5:![0-9]+]]
+; CHECK-NEXT:    store i8 0, ptr [[PTR]], align 1, !tbaa [[CHAR_TBAA5:![0-9]+]]
 ; CHECK-NEXT:    ret void
 ;
 entry:
@@ -29,9 +29,9 @@ define float @ptr_to_float(ptr %ptr) {
 ; CHECK-LABEL: define float @ptr_to_float(
 ; CHECK-SAME: ptr [[PTR:%.*]]) {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
-; CHECK-NEXT:    store float 0.000000e+00, ptr [[PTR]], align 4, !tbaa [[TBAA6:![0-9]+]]
+; CHECK-NEXT:    store float 0.000000e+00, ptr [[PTR]], align 4, !tbaa [[FLOAT_TBAA6:![0-9]+]]
 ; CHECK-NEXT:    call void @opaque(ptr [[PTR]])
-; CHECK-NEXT:    [[VAL:%.*]] = load float, ptr [[PTR]], align 4, !tbaa [[TBAA6]]
+; CHECK-NEXT:    [[VAL:%.*]] = load float, ptr [[PTR]], align 4, !tbaa [[FLOAT_TBAA6]]
 ; CHECK-NEXT:    ret float [[VAL]]
 ;
 entry:
@@ -45,8 +45,8 @@ define i64 @ptr_to_longlong(ptr %ptr) {
 ; CHECK-LABEL: define i64 @ptr_to_longlong(
 ; CHECK-SAME: ptr [[PTR:%.*]]) {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
-; CHECK-NEXT:    [[VAL:%.*]] = load i64, ptr [[PTR]], align 8, !tbaa [[TBAA8:![0-9]+]]
-; CHECK-NEXT:    store i64 0, ptr [[PTR]], align 8, !tbaa [[TBAA8]]
+; CHECK-NEXT:    [[VAL:%.*]] = load i64, ptr [[PTR]], align 8, !tbaa [[LONG_LONG_TBAA8:![0-9]+]]
+; CHECK-NEXT:    store i64 0, ptr [[PTR]], align 8, !tbaa [[LONG_LONG_TBAA8]]
 ; CHECK-NEXT:    ret i64 [[VAL]]
 ;
 entry:
@@ -64,7 +64,7 @@ define void @store_struct1ptr(ptr %ptr) {
 ; CHECK-LABEL: define void @store_struct1ptr(
 ; CHECK-SAME: ptr [[PTR:%.*]]) {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
-; CHECK-NEXT:    store ptr null, ptr [[PTR]], align 8, !tbaa [[TBAA10:![0-9]+]]
+; CHECK-NEXT:    store ptr null, ptr [[PTR]], align 8, !tbaa [[_ZTS7STRUCT1PTR_TBAA10:![0-9]+]]
 ; CHECK-NEXT:    ret void
 ;
 entry:
@@ -81,7 +81,7 @@ define void @store_struct2(ptr %ptr) {
 ; CHECK-LABEL: define void @store_struct2(
 ; CHECK-SAME: ptr [[PTR:%.*]]) {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
-; CHECK-NEXT:    store ptr null, ptr [[PTR]], align 8, !tbaa [[TBAA12:![0-9]+]]
+; CHECK-NEXT:    store ptr null, ptr [[PTR]], align 8, !tbaa [[_ZTS7STRUCT1PTR_TBAA12:![0-9]+]]
 ; CHECK-NEXT:    ret void
 ;
 entry:
@@ -95,12 +95,12 @@ define double @access_matrix(ptr %ptr) {
 ; CHECK-SAME: ptr [[PTR:%.*]]) {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
 ; CHECK-NEXT:    [[ALLOCA_PTR:%.*]] = alloca ptr, align 8
-; CHECK-NEXT:    store ptr [[PTR]], ptr [[ALLOCA_PTR]], align 8, !tbaa [[TBAA14:![0-9]+]]
-; CHECK-NEXT:    [[PTR_IDX:%.*]] = load ptr, ptr [[ALLOCA_PTR]], align 8, !tbaa [[TBAA14]]
+; CHECK-NEXT:    store ptr [[PTR]], ptr [[ALLOCA_PTR]], align 8, !tbaa [[ANYPTR_TBAA14:![0-9]+]]
+; CHECK-NEXT:    [[PTR_IDX:%.*]] = load ptr, ptr [[ALLOCA_PTR]], align 8, !tbaa [[ANYPTR_TBAA14]]
 ; CHECK-NEXT:    [[ADD_PTR:%.*]] = getelementptr inbounds ptr, ptr [[PTR_IDX]], i64 4
-; CHECK-NEXT:    [[PTR_IDX_1:%.*]] = load ptr, ptr [[ADD_PTR]], align 8, !tbaa [[TBAA16:![0-9]+]]
+; CHECK-NEXT:    [[PTR_IDX_1:%.*]] = load ptr, ptr [[ADD_PTR]], align 8, !tbaa [[ANYPTR_TBAA16:![0-9]+]]
 ; CHECK-NEXT:    [[ADD_PTR1:%.*]] = getelementptr inbounds [6 x double], ptr [[PTR_IDX_1]], i64 6
-; CHECK-NEXT:    [[PTR_IDX_2:%.*]] = load <6 x double>, ptr [[ADD_PTR1]], align 8, !tbaa [[TBAA5]]
+; CHECK-NEXT:    [[PTR_IDX_2:%.*]] = load <6 x double>, ptr [[ADD_PTR1]], align 8, !tbaa [[CHAR_TBAA5]]
 ; CHECK-NEXT:    [[MATRIXEXT:%.*]] = extractelement <6 x double> [[PTR_IDX_2]], i64 5
 ; CHECK-NEXT:    ret double [[MATRIXEXT]]
 ;
@@ -136,21 +136,21 @@ declare void @opaque(ptr)
 !15 = !{!"any p2 pointer", !2, i64 0}
 !16 = !{!2, !2, i64 0}
 ;.
-; CHECK: [[TBAA0]] = !{[[META1:![0-9]+]], [[META1]], i64 0}
+; CHECK: [[INTPTR_TBAA0]] = !{[[META1:![0-9]+]], [[META1]], i64 0}
 ; CHECK: [[META1]] = !{!"p1 int", [[META2:![0-9]+]], i64 0}
 ; CHECK: [[META2]] = !{!"any pointer", [[META3:![0-9]+]], i64 0}
 ; CHECK: [[META3]] = !{!"omnipotent char", [[META4:![0-9]+]], i64 0}
 ; CHECK: [[META4]] = !{!"Simple C/C++ TBAA"}
-; CHECK: [[TBAA5]] = !{[[META3]], [[META3]], i64 0}
-; CHECK: [[TBAA6]] = !{[[META7:![0-9]+]], [[META7]], i64 0}
+; CHECK: [[CHAR_TBAA5]] = !{[[META3]], [[META3]], i64 0}
+; CHECK: [[FLOAT_TBAA6]] = !{[[META7:![0-9]+]], [[META7]], i64 0}
 ; CHECK: [[META7]] = !{!"float", [[META3]], i64 0}
-; CHECK: [[TBAA8]] = !{[[META9:![0-9]+]], [[META9]], i64 0}
+; CHECK: [[LONG_LONG_TBAA8]] = !{[[META9:![0-9]+]], [[META9]], i64 0}
 ; CHECK: [[META9]] = !{!"long long", [[META3]], i64 0}
-; CHECK: [[TBAA10]] = !{[[META11:![0-9]+]], [[META11]], i64 0}
+; CHECK: [[_ZTS7STRUCT1PTR_TBAA10]] = !{[[META11:![0-9]+]], [[META11]], i64 0}
 ; CHECK: [[META11]] = !{!"p1 _ZTS7STRUCT1", [[META2]], i64 0}
-; CHECK: [[TBAA12]] = !{[[META13:![0-9]+]], [[META11]], i64 0}
+; CHECK: [[_ZTS7STRUCT1PTR_TBAA12]] = !{[[META13:![0-9]+]], [[META11]], i64 0}
 ; CHECK: [[META13]] = !{!"STRUCT2", [[META11]], i64 0}
-; CHECK: [[TBAA14]] = !{[[META15:![0-9]+]], [[META15]], i64 0}
+; CHECK: [[ANYPTR_TBAA14]] = !{[[META15:![0-9]+]], [[META15]], i64 0}
 ; CHECK: [[META15]] = !{!"any p2 pointer", [[META2]], i64 0}
-; CHECK: [[TBAA16]] = !{[[META2]], [[META2]], i64 0}
+; CHECK: [[ANYPTR_TBAA16]] = !{[[META2]], [[META2]], i64 0}
 ;.
diff --git a/llvm/test/tools/UpdateTestChecks/update_test_checks/tbaa-semantics-checks.test b/llvm/test/tools/UpdateTestChecks/update_test_checks/tbaa-semantics-checks.test
index e715639394846..0849e8940084c 100644
--- a/llvm/test/tools/UpdateTestChecks/update_test_checks/tbaa-semantics-checks.test
+++ b/llvm/test/tools/UpdateTestChecks/update_test_checks/tbaa-semantics-checks.test
@@ -1,5 +1,5 @@
 ## Test correct application of TBAA semantics in TBAA check lines.
-# RUN: cp -f %S/Inputs/tbaa-semantics-checks.ll %t.ll && %update_test_checks --version 5 %t.ll
+# RUN: cp -f %S/Inputs/tbaa-semantics-checks.ll %t.ll && %update_test_checks --version 6 %t.ll
 # RUN: diff -u %t.ll %S/Inputs/tbaa-semantics-checks.ll.expected
 
 ## Check that running the script again does not change the result.
diff --git a/llvm/utils/UpdateTestChecks/common.py b/llvm/utils/UpdateTestChecks/common.py
index 178c623e33e0e..4e662c35dd8ff 100644
--- a/llvm/utils/UpdateTestChecks/common.py
+++ b/llvm/utils/UpdateTestChecks/common.py
@@ -28,8 +28,9 @@
 4: --check-globals now has a third option ('smart'). The others are now called
    'none' and 'all'. 'smart' is the default.
 5: Basic block labels are matched by FileCheck expressions
+6: The semantics of TBAA checks has been incorporated in the check lines.
 """
-DEFAULT_VERSION = 5
+DEFAULT_VERSION = 6
 
 
 SUPPORTED_ANALYSES = {
@@ -620,6 +621,9 @@ def invoke_tool(exe, cmd_args, ir, preprocess_cmd=None, verbose=False):
 
 SEPARATOR = "."
 
+METADATA_NODES_RE = re.compile(r'^\s*!(\d+)\s*=\s*!{(.*)}', re.M)
+TBAA_TAGS_RE = re.compile(r'!tbaa\s*!([0-9]+)')
+
 
 def error(msg, test_file=None):
     if test_file:
@@ -685,6 +689,59 @@ def get_globals_name_prefix(raw_tool_output):
     return "_" if ch == "o" or ch == "x" else None
 
 
+def get_tbaa_records(version, raw_output_tools):
+    if version < 6:
+        return {}
+
+    # Retrieve all unique tbaa tags for the given IR.
+    unique_tbaa_tags = {f'!{n}' for n in TBAA_TAGS_RE.findall(raw_output_tools)}
+    if not unique_tbaa_tags:
+        return {}
+
+    # Small dict of metadata ID and its node content as value.
+    md_nodes = {
+        f'!{m.group(1)}': m.group(2)
+        for m in METADATA_NODES_RE.finditer(raw_output_tools)
+    }
+    assert md_nodes, "Shouldn't have TBAA tags without their type descriptors."
+
+    result = {}
+    for tag in unique_tbaa_tags:
+        type_desc = md_nodes.get(tag)
+        assert type_desc, f"Expected type descriptor for node {tag}."
+
+        # We deal with a tag of kind `(BaseTy, AccessTy, Offset)`.
+        access_ty = type_desc.split(',')[1].strip()
+
+        parent_ty = md_nodes.get(access_ty)
+        assert parent_ty, f"Couldn't find metadata for access type {access_ty}."
+
+        ty_name_field = parent_ty.split(',')[0]
+        assert ty_name_field.startswith('!"') and ty_name_field.endswith('"'), \
+            "First operand should be a MDString."
+        ty_name = ty_name_field[2:-1]
+
+        if ty_name.startswith("p"):
+            # Dealing with a pointer here.
+            pointee_ty_name = ty_name.split(maxsplit=1)[1]
+            if pointee_ty_name.startswith("omnipotent"):
+                pointee_ty_name = "char"
+            # TODO: If pointee_ty_name is a C++ name, should it be demangled?
+            tbaa_prefix = f'{pointee_ty_name.replace(" ", "_")}ptr'
+        elif ty_name.startswith("any"):
+            tbaa_prefix = "anyptr"
+        elif ty_name.startswith("omnipotent"):
+            tbaa_prefix = "char"
+        else:
+            tbaa_prefix = ty_name.replace(" ", "_")
+
+        # Record tag node and its semantics (e.g., INT_TBAA, INTPTR_TBAA).
+        tbaa_sema = f'{tbaa_prefix.upper()}_TBAA'
+        result[tag] = tbaa_sema
+
+    return result
+
+
 def apply_filters(line, filters):
     has_filter = False
     for f in filters:
@@ -1775,6 +1832,7 @@ def generalize_check_lines(
     ginfo: GeneralizerInfo,
     vars_seen,
     global_vars_seen,
+    global_tbaa_records = {},
     preserve_names=False,
     original_check_lines=None,
     *,
@@ -1935,14 +1993,25 @@ def escape_braces(match_obj):
                 else:
                     vars_dict = global_vars_seen
 
+                mapped_name = mapping[value.name]
+
+                # We have computed the name mapping. Now, if possible,
+                # substitute the TBAA value name with its semantics.
+                if ginfo.get_version() >= 6:
+                    if value.key == "!" and global_tbaa_records \
+                        and mapped_name.startswith("TBAA") and mapped_name[4:].isdigit():
+                        tbaa_sema = global_tbaa_records.get(value.text)
+                        assert tbaa_sema, f"Shouldn't miss TBAA name for {value.text}?"
+                        mapped_name = f"{tbaa_sema}{mapped_name[4:]}"
+
                 if key in defs:
                     line += vars_dict[key].get_def(
-                        mapping[value.name], value.prefix, value.suffix
+                        mapped_name, value.prefix, value.suffix
                     )
                     defs.remove(key)
                 else:
                     line += vars_dict[key].get_use(
-                        mapping[value.name], value.prefix, value.suffix
+                        mapped_name, value.prefix, value.suffix
                     )
 
             line += line_template
@@ -1968,6 +2037,7 @@ def add_checks(
     ginfo,
     global_vars_seen_dict,
     is_filtered,
+    global_tbaa_records_for_prefixes = {},
     preserve_names=False,
     original_check_lines: Mapping[str, List[str]] = {},
 ):
@@ -2018,6 +2088,10 @@ def add_checks(
                 global_vars_seen_dict[checkprefix] = {}
 
             global_vars_seen_before = [key for key in global_vars_seen.keys()]
+            global_tbaa_records = next(
+                (val for key, val in global_tbaa_records_for_prefixes.items() if checkprefix in key),
+                None
+            )
 
             vars_seen = {}
             printed_prefixes.append(checkprefix)
@@ -2041,6 +2115,7 @@ def add_checks(
                     ginfo,
                     vars_seen,
                     global_vars_seen,
+                    global_tbaa_records,
                     preserve_names,
                     original_check_lines=[],
                     no_meta_details=ginfo.no_meta_details(),
@@ -2155,6 +2230,7 @@ def add_checks(
                     ginfo,
                     vars_seen,
                     global_vars_seen,
+                    global_tbaa_records,
                     preserve_names,
                     original_check_lines=original_check_lines.get(checkprefix),
                 )
@@ -2217,6 +2293,7 @@ def add_ir_checks(
     function_sig,
     ginfo: GeneralizerInfo,
     global_vars_seen_dict,
+    global_tbaa_records_for_prefixes,
     is_filtered,
     original_check_lines={},
 ):
@@ -2241,6 +2318,7 @@ def add_ir_checks(
         ginfo,
         global_vars_seen_dict,
         is_filtered,
+        global_tbaa_records_for_prefixes,
         preserve_names,
         original_check_lines=original_check_lines,
     )
@@ -2627,6 +2705,7 @@ def add_global_checks(
     output_lines,
     ginfo: GeneralizerInfo,
     global_vars_seen_dict,
+    global_tbaa_records_for_prefixes,
     preserve_names,
     is_before_functions,
     global_check_setting,
@@ -2659,6 +2738,11 @@ def add_global_checks(
 
                 check_lines = []
                 global_vars_seen_before = [key for key in global_vars_seen.keys()]
+                global_tbaa_records = next(
+                    (val for key, val in global_tbaa_records_for_prefixes.items() if checkprefix in key),
+                    None
+                )
+
                 lines_w_index = glob_val_dict[checkprefix][nameless_value.check_prefix]
                 lines_w_index = filter_globals_according_to_preference(
                     lines_w_index,
@@ -2682,6 +2766,7 @@ def add_global_checks(
                         ginfo,
                         {},
                         global_vars_seen,
+                        global_tbaa_records,
                         preserve_names,
                         unstable_globals_only=True,
                     )
diff --git a/llvm/utils/update_cc_test_checks.py b/llvm/utils/update_cc_test_checks.py
index 4102ee4ecbd22..97b446d565973 100755
--- a/llvm/utils/update_cc_test_checks.py
+++ b/llvm/utils/update_cc_test_checks.py
@@ -365,6 +365,7 @@ def update_test(ti: common.TestInfo):
         ginfo=ginfo,
     )
 
+    global_tbaa_records_for_prefixes = {}
     for prefixes, args, extra_commands, triple_in_cmd in run_list:
         # Execute non-filechecked runline.
         if not prefixes:
@@ -391,6 +392,10 @@ def update_test(ti: common.TestInfo):
             raw_tool_output,
         )
 
+        # Extract TBAA metadata for later usage in check lines.
+        tbaa_map = common.get_tbaa_records(ti.args.version, raw_tool_output)
+        global_tbaa_records_for_prefixes[tuple(prefixes)] = tbaa_map
+
         # Invoke clang -Xclang -ast-dump=json to get mapping from start lines to
         # mangled names. Forward all clang args for now.
         for k, v in get_line2func_list(
@@ -436,6 +441,7 @@ def check_generator(my_output_lines, prefixes, func):
                 ti.args.function_signature,
                 ginfo,
                 global_vars_seen_dict,
+                global_tbaa_records_for_prefixes,
                 is_filtered=builder.is_filtered(),
             )
 
@@ -448,6 +454,7 @@ def check_generator(my_output_lines, prefixes, func):
                     output_lines,
                     ginfo,
                     global_vars_seen_dict,
+                    global_tbaa_records_for_prefixes,
                     False,
                     True,
                     ti.args.check_globals,
@@ -509,6 +516,7 @@ def check_generator(my_output_lines, prefixes, func):
                                     output_lines,
                                     ginfo,
                                     global_vars_seen_dict,
+                                    global_tbaa_records_for_prefixes,
                                     False,
                                     True,
                                     ti.args.check_globals,
@@ -529,6 +537,7 @@ def check_generator(my_output_lines, prefixes, func):
                                 args.function_signature,
                                 ginfo,
                                 global_vars_seen_dict,
+                                global_tbaa_records_for_prefixes,
                                 is_filtered=builder.is_filtered(),
                             )
                         )
@@ -547,6 +556,7 @@ def check_generator(my_output_lines, prefixes, func):
                 output_lines,
                 ginfo,
                 global_vars_seen_dict,
+                global_tbaa_records_for_prefixes,
                 False,
                 False,
                 ti.args.check_globals,
diff --git a/llvm/utils/update_test_checks.py b/llvm/utils/update_test_checks.py
index ff5bb7d782346..3b562fbc54f78 100755
--- a/llvm/utils/update_test_checks.py
+++ b/llvm/utils/update_test_checks.py
@@ -93,6 +93,7 @@ def update_test(ti: common.TestInfo):
 
     ginfo = common.make_ir_generalizer(ti.args.version, ti.args.check_globals == "none")
     global_vars_seen_dict = {}
+    global_tbaa_records_for_prefixes = {}
     builder = common.FunctionTestBuilder(
         run_list=prefix_list,
         flags=ti.args,
@@ -124,6 +125,10 @@ def update_test(ti: common.TestInfo):
         )
         builder.processed_prefixes(prefixes)
 
+        # Extract TBAA metadata for later usage in check lines.
+        tbaa_map = common.get_tbaa_records(ti.args.version, raw_tool_output)
+        global_tbaa_records_for_prefixes[tuple(prefixes)] = tbaa_map
+
     prefix_set = set([prefix for prefixes, _, _ in prefix_list for prefix in prefixes])
 
     if not ti.args.reset_variable_names:
@@ -165,6 +170,7 @@ def update_test(ti: common.TestInfo):
                     output_lines,
                     ginfo,
                     global_vars_seen_dict,
+                    global_tbaa_records_for_prefixes,
                     args.preserve_names,
                     True,
                     args.check_globals,
@@ -188,6 +194,7 @@ def update_test(ti: common.TestInfo):
                     args.function_signature,
                     ginfo,
                     global_vars_seen_dict,
+                    global_tbaa_records_for_prefixes,
                     is_filtered=builder.is_filtered(),
                     original_check_lines=original_check_lines.get(func, {}),
                 ),
@@ -220,6 +227,7 @@ def update_test(ti: common.TestInfo):
                         args.function_signature,
                         ginfo,
                         global_vars_seen_dict,
+                        global_tbaa_records_for_prefixes,
                         is_filtered=builder.is_filtered(),
                         original_check_lines=original_check_lines.get(func_name, {}),
                     )
@@ -237,6 +245,7 @@ def update_test(ti: common.TestInfo):
                             output_lines,
                             ginfo,
                             global_vars_seen_dict,
+                            global_tbaa_records_for_prefixes,
                             args.preserve_names,
                             True,
                             args.check_globals,
@@ -286,6 +295,7 @@ def update_test(ti: common.TestInfo):
                 output_lines,
                 ginfo,
                 global_vars_seen_dict,
+                global_tbaa_records_for_prefixes,
                 args.preserve_names,
                 False,
                 args.check_globals,

>From 00af9aff53d67209537026fe446a358c900ab98c Mon Sep 17 00:00:00 2001
From: Antonio Frighetto <me at antoniofrighetto.com>
Date: Wed, 9 Jul 2025 10:29:11 +0200
Subject: [PATCH 3/3] !fixup darker format

---
 llvm/utils/UpdateTestChecks/common.py | 47 +++++++++++++++++----------
 1 file changed, 30 insertions(+), 17 deletions(-)

diff --git a/llvm/utils/UpdateTestChecks/common.py b/llvm/utils/UpdateTestChecks/common.py
index 4e662c35dd8ff..d4982aa2f4966 100644
--- a/llvm/utils/UpdateTestChecks/common.py
+++ b/llvm/utils/UpdateTestChecks/common.py
@@ -621,8 +621,8 @@ def invoke_tool(exe, cmd_args, ir, preprocess_cmd=None, verbose=False):
 
 SEPARATOR = "."
 
-METADATA_NODES_RE = re.compile(r'^\s*!(\d+)\s*=\s*!{(.*)}', re.M)
-TBAA_TAGS_RE = re.compile(r'!tbaa\s*!([0-9]+)')
+METADATA_NODES_RE = re.compile(r"^\s*!(\d+)\s*=\s*!{(.*)}", re.M)
+TBAA_TAGS_RE = re.compile(r"!tbaa\s*!([0-9]+)")
 
 
 def error(msg, test_file=None):
@@ -694,13 +694,13 @@ def get_tbaa_records(version, raw_output_tools):
         return {}
 
     # Retrieve all unique tbaa tags for the given IR.
-    unique_tbaa_tags = {f'!{n}' for n in TBAA_TAGS_RE.findall(raw_output_tools)}
+    unique_tbaa_tags = {f"!{n}" for n in TBAA_TAGS_RE.findall(raw_output_tools)}
     if not unique_tbaa_tags:
         return {}
 
     # Small dict of metadata ID and its node content as value.
     md_nodes = {
-        f'!{m.group(1)}': m.group(2)
+        f"!{m.group(1)}": m.group(2)
         for m in METADATA_NODES_RE.finditer(raw_output_tools)
     }
     assert md_nodes, "Shouldn't have TBAA tags without their type descriptors."
@@ -711,14 +711,15 @@ def get_tbaa_records(version, raw_output_tools):
         assert type_desc, f"Expected type descriptor for node {tag}."
 
         # We deal with a tag of kind `(BaseTy, AccessTy, Offset)`.
-        access_ty = type_desc.split(',')[1].strip()
+        access_ty = type_desc.split(",")[1].strip()
 
         parent_ty = md_nodes.get(access_ty)
         assert parent_ty, f"Couldn't find metadata for access type {access_ty}."
 
-        ty_name_field = parent_ty.split(',')[0]
-        assert ty_name_field.startswith('!"') and ty_name_field.endswith('"'), \
-            "First operand should be a MDString."
+        ty_name_field = parent_ty.split(",")[0]
+        assert ty_name_field.startswith('!"') and ty_name_field.endswith(
+            '"'
+        ), "First operand should be a MDString."
         ty_name = ty_name_field[2:-1]
 
         if ty_name.startswith("p"):
@@ -736,7 +737,7 @@ def get_tbaa_records(version, raw_output_tools):
             tbaa_prefix = ty_name.replace(" ", "_")
 
         # Record tag node and its semantics (e.g., INT_TBAA, INTPTR_TBAA).
-        tbaa_sema = f'{tbaa_prefix.upper()}_TBAA'
+        tbaa_sema = f"{tbaa_prefix.upper()}_TBAA"
         result[tag] = tbaa_sema
 
     return result
@@ -1832,7 +1833,7 @@ def generalize_check_lines(
     ginfo: GeneralizerInfo,
     vars_seen,
     global_vars_seen,
-    global_tbaa_records = {},
+    global_tbaa_records={},
     preserve_names=False,
     original_check_lines=None,
     *,
@@ -1998,8 +1999,12 @@ def escape_braces(match_obj):
                 # We have computed the name mapping. Now, if possible,
                 # substitute the TBAA value name with its semantics.
                 if ginfo.get_version() >= 6:
-                    if value.key == "!" and global_tbaa_records \
-                        and mapped_name.startswith("TBAA") and mapped_name[4:].isdigit():
+                    if (
+                        value.key == "!"
+                        and global_tbaa_records
+                        and mapped_name.startswith("TBAA")
+                        and mapped_name[4:].isdigit()
+                    ):
                         tbaa_sema = global_tbaa_records.get(value.text)
                         assert tbaa_sema, f"Shouldn't miss TBAA name for {value.text}?"
                         mapped_name = f"{tbaa_sema}{mapped_name[4:]}"
@@ -2037,7 +2042,7 @@ def add_checks(
     ginfo,
     global_vars_seen_dict,
     is_filtered,
-    global_tbaa_records_for_prefixes = {},
+    global_tbaa_records_for_prefixes={},
     preserve_names=False,
     original_check_lines: Mapping[str, List[str]] = {},
 ):
@@ -2089,8 +2094,12 @@ def add_checks(
 
             global_vars_seen_before = [key for key in global_vars_seen.keys()]
             global_tbaa_records = next(
-                (val for key, val in global_tbaa_records_for_prefixes.items() if checkprefix in key),
-                None
+                (
+                    val
+                    for key, val in global_tbaa_records_for_prefixes.items()
+                    if checkprefix in key
+                ),
+                None,
             )
 
             vars_seen = {}
@@ -2739,8 +2748,12 @@ def add_global_checks(
                 check_lines = []
                 global_vars_seen_before = [key for key in global_vars_seen.keys()]
                 global_tbaa_records = next(
-                    (val for key, val in global_tbaa_records_for_prefixes.items() if checkprefix in key),
-                    None
+                    (
+                        val
+                        for key, val in global_tbaa_records_for_prefixes.items()
+                        if checkprefix in key
+                    ),
+                    None,
                 )
 
                 lines_w_index = glob_val_dict[checkprefix][nameless_value.check_prefix]



More information about the llvm-commits mailing list