[llvm] 6f44f33 - [TBAA] Only keep the immutable flag if both merged tags have it (#225907)

via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 25 00:32:00 PDT 2026


Author: Mian Miftah
Date: 2026-09-25T09:31:53+02:00
New Revision: 6f44f333c3572d3ee54cdfdcba9124424b6ad1df

URL: https://github.com/llvm/llvm-project/commit/6f44f333c3572d3ee54cdfdcba9124424b6ad1df
DIFF: https://github.com/llvm/llvm-project/commit/6f44f333c3572d3ee54cdfdcba9124424b6ad1df.diff

LOG: [TBAA] Only keep the immutable flag if both merged tags have it (#225907)

getMostGenericTBAA() can return one of the two tags unchanged, as it
does when both have the same base type and offset. If only that tag has
the immutable flag, the merged access claims that the memory is constant
on both paths. For example, after SimplifyCFG hoists two such loads, GVN
can forward a load across a store to the same location.

Keep the immutable flag only if both tags have it. Otherwise drop just
the flag and keep the rest of the tag.

Added: 
    llvm/test/Analysis/TypeBasedAliasAnalysis/merge-immutable.ll

Modified: 
    llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp b/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp
index dbe4ccac7801da..134e1c28b4caaf 100644
--- a/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp
+++ b/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp
@@ -615,8 +615,19 @@ static bool mayBeAccessToSubobjectOf(TBAAStructTagNode BaseTag,
                  BaseType.getNode() == BaseTag.getAccessType() ||
                  SubobjectTag.getBaseType() == SubobjectTag.getAccessType();
       if (GenericTag) {
-        *GenericTag =
-            MayAlias ? SubobjectTag.getNode() : createAccessTag(CommonType);
+        if (!MayAlias) {
+          *GenericTag = createAccessTag(CommonType);
+        } else if (SubobjectTag.isTypeImmutable() &&
+                   !BaseTag.isTypeImmutable()) {
+          // The generic tag can only be immutable if both accesses are, so
+          // drop the flag and keep the rest of the tag.
+          const MDNode *Tag = SubobjectTag.getNode();
+          unsigned FlagOpNo = SubobjectTag.isNewFormat() ? 4 : 3;
+          SmallVector<Metadata *, 4> Ops(Tag->operands().take_front(FlagOpNo));
+          *GenericTag = MDNode::get(Tag->getContext(), Ops);
+        } else {
+          *GenericTag = SubobjectTag.getNode();
+        }
       }
       return true;
     }

diff  --git a/llvm/test/Analysis/TypeBasedAliasAnalysis/merge-immutable.ll b/llvm/test/Analysis/TypeBasedAliasAnalysis/merge-immutable.ll
new file mode 100644
index 00000000000000..71eeccc4baf186
--- /dev/null
+++ b/llvm/test/Analysis/TypeBasedAliasAnalysis/merge-immutable.ll
@@ -0,0 +1,128 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals all --version 6
+; RUN: opt -S -passes='simplifycfg<hoist-common-insts>' < %s | FileCheck %s
+
+; When two loads are merged, the merged access tag can only describe immutable
+; memory if both access tags do.
+
+define i32 @same_access_path(i1 %c, ptr %p) {
+; CHECK-LABEL: define i32 @same_access_path(
+; CHECK-SAME: i1 [[C:%.*]], ptr [[P:%.*]]) {
+; CHECK-NEXT:  [[END:.*:]]
+; CHECK-NEXT:    [[A:%.*]] = load i32, ptr [[P]], align 4, !tbaa [[TBAA0:![0-9]+]]
+; CHECK-NEXT:    ret i32 [[A]]
+;
+  br i1 %c, label %if, label %else
+
+if:
+  %a = load i32, ptr %p, align 4, !tbaa !5
+  br label %end
+
+else:
+  %b = load i32, ptr %p, align 4, !tbaa !6
+  br label %end
+
+end:
+  %r = phi i32 [ %a, %if ], [ %b, %else ]
+  ret i32 %r
+}
+
+; The generic tag of accesses to Outer.s.y and S.y is the tag of the latter.
+define i32 @subobject(i1 %c, ptr %p) {
+; CHECK-LABEL: define i32 @subobject(
+; CHECK-SAME: i1 [[C:%.*]], ptr [[P:%.*]]) {
+; CHECK-NEXT:  [[END:.*:]]
+; CHECK-NEXT:    [[A:%.*]] = load i32, ptr [[P]], align 4, !tbaa [[TBAA5:![0-9]+]]
+; CHECK-NEXT:    ret i32 [[A]]
+;
+  br i1 %c, label %if, label %else
+
+if:
+  %a = load i32, ptr %p, align 4, !tbaa !8
+  br label %end
+
+else:
+  %b = load i32, ptr %p, align 4, !tbaa !7
+  br label %end
+
+end:
+  %r = phi i32 [ %a, %if ], [ %b, %else ]
+  ret i32 %r
+}
+
+define i32 @subobject_both_immutable(i1 %c, ptr %p) {
+; CHECK-LABEL: define i32 @subobject_both_immutable(
+; CHECK-SAME: i1 [[C:%.*]], ptr [[P:%.*]]) {
+; CHECK-NEXT:  [[END:.*:]]
+; CHECK-NEXT:    [[A:%.*]] = load i32, ptr [[P]], align 4, !tbaa [[TBAA6:![0-9]+]]
+; CHECK-NEXT:    ret i32 [[A]]
+;
+  br i1 %c, label %if, label %else
+
+if:
+  %a = load i32, ptr %p, align 4, !tbaa !9
+  br label %end
+
+else:
+  %b = load i32, ptr %p, align 4, !tbaa !7
+  br label %end
+
+end:
+  %r = phi i32 [ %a, %if ], [ %b, %else ]
+  ret i32 %r
+}
+
+define i32 @same_access_path_new_format(i1 %c, ptr %p) {
+; CHECK-LABEL: define i32 @same_access_path_new_format(
+; CHECK-SAME: i1 [[C:%.*]], ptr [[P:%.*]]) {
+; CHECK-NEXT:  [[END:.*:]]
+; CHECK-NEXT:    [[A:%.*]] = load i32, ptr [[P]], align 4, !tbaa [[TBAA7:![0-9]+]]
+; CHECK-NEXT:    ret i32 [[A]]
+;
+  br i1 %c, label %if, label %else
+
+if:
+  %a = load i32, ptr %p, align 4, !tbaa !14
+  br label %end
+
+else:
+  %b = load i32, ptr %p, align 4, !tbaa !15
+  br label %end
+
+end:
+  %r = phi i32 [ %a, %if ], [ %b, %else ]
+  ret i32 %r
+}
+
+; struct S { int x; int y; }; struct Outer { int a; struct S s; };
+!0 = !{!"Simple C/C++ TBAA"}
+!1 = !{!"omnipotent char", !0, i64 0}
+!2 = !{!"int", !1, i64 0}
+!3 = !{!"S", !2, i64 0, !2, i64 4}
+!4 = !{!"Outer", !2, i64 0, !3, i64 4}
+!5 = !{!3, !2, i64 0, i64 1} ; S.x, immutable
+!6 = !{!3, !2, i64 0} ; S.x
+!7 = !{!3, !2, i64 4, i64 1} ; S.y, immutable
+!8 = !{!4, !2, i64 8} ; Outer.s.y
+!9 = !{!4, !2, i64 8, i64 1} ; Outer.s.y, immutable
+
+; The same types in the new format.
+!10 = !{!"new-format root"}
+!11 = !{!10, i64 1, !"omnipotent char"}
+!12 = !{!11, i64 4, !"int"}
+!13 = !{!11, i64 8, !"S", !12, i64 0, i64 4, !12, i64 4, i64 4}
+!14 = !{!13, !12, i64 0, i64 4, i64 1} ; S.x, immutable
+!15 = !{!13, !12, i64 0, i64 4} ; S.x
+;.
+; CHECK: [[TBAA0]] = !{[[META1:![0-9]+]], [[META2:![0-9]+]], i64 0}
+; CHECK: [[META1]] = !{!"S", [[META2]], i64 0, [[META2]], i64 4}
+; CHECK: [[META2]] = !{!"int", [[META3:![0-9]+]], i64 0}
+; CHECK: [[META3]] = !{!"omnipotent char", [[META4:![0-9]+]], i64 0}
+; CHECK: [[META4]] = !{!"Simple C/C++ TBAA"}
+; CHECK: [[TBAA5]] = !{[[META1]], [[META2]], i64 4}
+; CHECK: [[TBAA6]] = !{[[META1]], [[META2]], i64 4, i64 1}
+; CHECK: [[TBAA7]] = !{[[META8:![0-9]+]], [[META11:![0-9]+]], i64 0, i64 4}
+; CHECK: [[META8]] = !{[[META9:![0-9]+]], i64 8, !"S", [[META11]], i64 0, i64 4, [[META11]], i64 4, i64 4}
+; CHECK: [[META9]] = !{[[META10:![0-9]+]], i64 1, !"omnipotent char"}
+; CHECK: [[META10]] = !{!"new-format root"}
+; CHECK: [[META11]] = !{[[META9]], i64 4, !"int"}
+;.


        


More information about the llvm-commits mailing list