From 790a62f2d8dafa49afc22f4e0b77d1d4942cb3e3 Mon Sep 17 00:00:00 2001 From: Antonio Frighetto Date: Thu, 26 Jun 2025 15:35:41 +0200 Subject: [PATCH 1/5] [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 Date: Wed, 2 Jul 2025 14:52:07 +0200 Subject: [PATCH 2/5] [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 Date: Wed, 9 Jul 2025 10:29:11 +0200 Subject: [PATCH 3/5] !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] From 4ea77e30f362d8731c9fdc14e81b522e07777833 Mon Sep 17 00:00:00 2001 From: Antonio Frighetto Date: Wed, 9 Jul 2025 11:55:43 +0200 Subject: [PATCH 4/5] !fixup explicitly escape braces --- llvm/utils/UpdateTestChecks/common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/utils/UpdateTestChecks/common.py b/llvm/utils/UpdateTestChecks/common.py index d4982aa2f4966..ff7b88cc5e7ae 100644 --- a/llvm/utils/UpdateTestChecks/common.py +++ b/llvm/utils/UpdateTestChecks/common.py @@ -621,7 +621,7 @@ 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) +METADATA_NODES_RE = re.compile(r"^\s*!(\d+)\s*=\s*!\{(.*)\}", re.M) TBAA_TAGS_RE = re.compile(r"!tbaa\s*!([0-9]+)") From 32ef6ba7f72f0ce42a674f0275ff32ff451abfff Mon Sep 17 00:00:00 2001 From: Antonio Frighetto Date: Wed, 9 Jul 2025 16:18:23 +0200 Subject: [PATCH 5/5] !fixup relax assert first operand node be a mdstring --- llvm/utils/UpdateTestChecks/common.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/llvm/utils/UpdateTestChecks/common.py b/llvm/utils/UpdateTestChecks/common.py index ff7b88cc5e7ae..8a916ca43f81d 100644 --- a/llvm/utils/UpdateTestChecks/common.py +++ b/llvm/utils/UpdateTestChecks/common.py @@ -716,10 +716,12 @@ def get_tbaa_records(version, raw_output_tools): parent_ty = md_nodes.get(access_ty) assert parent_ty, f"Couldn't find metadata for access type {access_ty}." + # First operand should be a MDString. If not, likely dealing with + # `new-struct-path-tbaa`. + # TODO: Support `new-struct-path-tbaa` TBAA format. ty_name_field = parent_ty.split(",")[0] - assert ty_name_field.startswith('!"') and ty_name_field.endswith( - '"' - ), "First operand should be a MDString." + if not (ty_name_field.startswith('!"') and ty_name_field.endswith('"')): + return {} ty_name = ty_name_field[2:-1] if ty_name.startswith("p"):