From a80c79b5bfb7f8632571a2631d9883933600be07 Mon Sep 17 00:00:00 2001 From: "Ivan A. Kosarev" Date: Mon, 18 Dec 2017 20:05:20 +0000 Subject: [PATCH] [Analysis] Generate more precise TBAA tags when one access encloses the other There are cases when two tags with different base types denote accesses to the same direct or indirect member of a structure type. Currently, merging of such tags results in a tag that represents an access to an object that has the type of that member. This patch changes this so that if one of the accesses encloses the other, then the generic tag is the one of the enclosed access. Differential Revision: https://reviews.llvm.org/D39557 llvm-svn: 321019 --- llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp | 23 ++++++-- llvm/test/Transforms/GVN/tbaa.ll | 61 +++++++++++++------- llvm/test/Transforms/NewGVN/tbaa.ll | 61 +++++++++++++------- 3 files changed, 97 insertions(+), 48 deletions(-) diff --git a/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp b/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp index c9ed026a1e335..173db399b9d60 100644 --- a/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp +++ b/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp @@ -544,21 +544,32 @@ static bool matchAccessTags(const MDNode *A, const MDNode *B, TBAAStructTagNode TagA(A), TagB(B); const MDNode *CommonType = getLeastCommonType(TagA.getAccessType(), TagB.getAccessType()); - if (GenericTag) - *GenericTag = createAccessTag(CommonType); // TODO: We need to check if AccessType of TagA encloses AccessType of // TagB to support aggregate AccessType. If yes, return true. // Climb the type DAG from base type of A to see if we reach base type of B. uint64_t OffsetA; - if (findAccessType(TagA, TagB.getBaseType(), OffsetA)) - return OffsetA == TagB.getOffset(); + if (findAccessType(TagA, TagB.getBaseType(), OffsetA)) { + bool SameMemberAccess = OffsetA == TagB.getOffset(); + if (GenericTag) + *GenericTag = SameMemberAccess ? TagB.getNode() : + createAccessTag(CommonType); + return SameMemberAccess; + } // Climb the type DAG from base type of B to see if we reach base type of A. uint64_t OffsetB; - if (findAccessType(TagB, TagA.getBaseType(), OffsetB)) - return OffsetB == TagA.getOffset(); + if (findAccessType(TagB, TagA.getBaseType(), OffsetB)) { + bool SameMemberAccess = OffsetB == TagA.getOffset(); + if (GenericTag) + *GenericTag = SameMemberAccess ? TagA.getNode() : + createAccessTag(CommonType); + return SameMemberAccess; + } + + if (GenericTag) + *GenericTag = createAccessTag(CommonType); // If the final access types have different roots, they're part of different // potentially unrelated type systems, so we must be conservative. diff --git a/llvm/test/Transforms/GVN/tbaa.ll b/llvm/test/Transforms/GVN/tbaa.ll index 7c05fda6cb8f1..5cb4e03599700 100644 --- a/llvm/test/Transforms/GVN/tbaa.ll +++ b/llvm/test/Transforms/GVN/tbaa.ll @@ -1,7 +1,7 @@ ; RUN: opt -tbaa -basicaa -gvn -S < %s | FileCheck %s define i32 @test1(i8* %p, i8* %q) { -; CHECK: @test1(i8* %p, i8* %q) +; CHECK-LABEL: @test1(i8* %p, i8* %q) ; CHECK: call i32 @foo(i8* %p) ; CHECK-NOT: tbaa ; CHECK: %c = add i32 %a, %a @@ -12,7 +12,7 @@ define i32 @test1(i8* %p, i8* %q) { } define i32 @test2(i8* %p, i8* %q) { -; CHECK: @test2(i8* %p, i8* %q) +; CHECK-LABEL: @test2(i8* %p, i8* %q) ; CHECK: call i32 @foo(i8* %p), !tbaa [[TAGC:!.*]] ; CHECK: %c = add i32 %a, %a %a = call i32 @foo(i8* %p), !tbaa !0 @@ -22,7 +22,7 @@ define i32 @test2(i8* %p, i8* %q) { } define i32 @test3(i8* %p, i8* %q) { -; CHECK: @test3(i8* %p, i8* %q) +; CHECK-LABEL: @test3(i8* %p, i8* %q) ; CHECK: call i32 @foo(i8* %p), !tbaa [[TAGB:!.*]] ; CHECK: %c = add i32 %a, %a %a = call i32 @foo(i8* %p), !tbaa !3 @@ -32,7 +32,7 @@ define i32 @test3(i8* %p, i8* %q) { } define i32 @test4(i8* %p, i8* %q) { -; CHECK: @test4(i8* %p, i8* %q) +; CHECK-LABEL: @test4(i8* %p, i8* %q) ; CHECK: call i32 @foo(i8* %p), !tbaa [[TAGA:!.*]] ; CHECK: %c = add i32 %a, %a %a = call i32 @foo(i8* %p), !tbaa !1 @@ -42,8 +42,8 @@ define i32 @test4(i8* %p, i8* %q) { } define i32 @test5(i8* %p, i8* %q) { -; CHECK: @test5(i8* %p, i8* %q) -; CHECK: call i32 @foo(i8* %p), !tbaa [[TAGA:!.*]] +; CHECK-LABEL: @test5(i8* %p, i8* %q) +; CHECK: call i32 @foo(i8* %p), !tbaa [[TAGA]] ; CHECK: %c = add i32 %a, %a %a = call i32 @foo(i8* %p), !tbaa !0 %b = call i32 @foo(i8* %p), !tbaa !1 @@ -52,8 +52,8 @@ define i32 @test5(i8* %p, i8* %q) { } define i32 @test6(i8* %p, i8* %q) { -; CHECK: @test6(i8* %p, i8* %q) -; CHECK: call i32 @foo(i8* %p), !tbaa [[TAGA:!.*]] +; CHECK-LABEL: @test6(i8* %p, i8* %q) +; CHECK: call i32 @foo(i8* %p), !tbaa [[TAGA]] ; CHECK: %c = add i32 %a, %a %a = call i32 @foo(i8* %p), !tbaa !0 %b = call i32 @foo(i8* %p), !tbaa !3 @@ -62,7 +62,7 @@ define i32 @test6(i8* %p, i8* %q) { } define i32 @test7(i8* %p, i8* %q) { -; CHECK: @test7(i8* %p, i8* %q) +; CHECK-LABEL: @test7(i8* %p, i8* %q) ; CHECK: call i32 @foo(i8* %p) ; CHECK-NOT: tbaa ; CHECK: %c = add i32 %a, %a @@ -72,10 +72,8 @@ define i32 @test7(i8* %p, i8* %q) { ret i32 %c } - - define i32 @test8(i32* %p, i32* %q) { -; CHECK-LABEL: test8 +; CHECK-LABEL: @test8 ; CHECK-NEXT: store i32 15, i32* %p ; CHECK-NEXT: ret i32 0 ; Since we know the location is invariant, we can forward the @@ -87,8 +85,9 @@ define i32 @test8(i32* %p, i32* %q) { %c = sub i32 %a, %b ret i32 %c } + define i32 @test9(i32* %p, i32* %q) { -; CHECK-LABEL: test9 +; CHECK-LABEL: @test9 ; CHECK-NEXT: call void @clobber() ; CHECK-NEXT: ret i32 0 ; Since we know the location is invariant, we can forward the @@ -101,16 +100,27 @@ define i32 @test9(i32* %p, i32* %q) { ret i32 %c } +define i32 @test10(i8* %p, i8* %q) { +; If one access encloses the other, then the merged access is the enclosed one +; and not just the common final access type. +; CHECK-LABEL: @test10 +; CHECK: call i32 @foo(i8* %p), !tbaa [[TAG_X_i:!.*]] +; CHECK: %c = add i32 %a, %a + %a = call i32 @foo(i8* %p), !tbaa !15 ; TAG_X_i + %b = call i32 @foo(i8* %p), !tbaa !19 ; TAG_Y_x_i + %c = add i32 %a, %b + ret i32 %c +} declare void @clobber() declare i32 @foo(i8*) readonly -; CHECK: [[TAGC]] = !{[[TYPEC:!.*]], [[TYPEC]], i64 0} -; CHECK: [[TYPEC]] = !{!"C", [[TYPEA:!.*]]} -; CHECK: [[TYPEA]] = !{!"A", !{{.*}}} -; CHECK: [[TAGB]] = !{[[TYPEB:!.*]], [[TYPEB]], i64 0} -; CHECK: [[TYPEB]] = !{!"B", [[TYPEA]]} -; CHECK: [[TAGA]] = !{[[TYPEA]], [[TYPEA]], i64 0} +; CHECK-DAG: [[TAGC]] = !{[[TYPEC:!.*]], [[TYPEC]], i64 0} +; CHECK-DAG: [[TYPEC]] = !{!"C", [[TYPEA:!.*]]} +; CHECK-DAG: [[TYPEA]] = !{!"A", !{{.*}}} +; CHECK-DAG: [[TAGB]] = !{[[TYPEB:!.*]], [[TYPEB]], i64 0} +; CHECK-DAG: [[TYPEB]] = !{!"B", [[TYPEA]]} +; CHECK-DAG: [[TAGA]] = !{[[TYPEA]], [[TYPEA]], i64 0} !0 = !{!5, !5, i64 0} !1 = !{!6, !6, i64 0} !2 = !{!"tbaa root"} @@ -122,8 +132,17 @@ declare i32 @foo(i8*) readonly !8 = !{!"another root"} !11 = !{!"scalar type", !8} +; CHECK-DAG: [[TAG_X_i]] = !{[[TYPE_X:!.*]], [[TYPE_int:!.*]], i64 0} +; CHECK-DAG: [[TYPE_X:!.*]] = !{!"struct X", [[TYPE_int]], i64 0} +; CHECK-DAG: [[TYPE_int]] = !{!"int", {{!.*}}, i64 0} +!15 = !{!16, !17, i64 0} ; TAG_X_i +!16 = !{!"struct X", !17, i64 0} ; struct X { int i; }; +!17 = !{!"int", !18, i64 0} +!18 = !{!"char", !2, i64 0} -;; A TBAA structure who's only point is to have a constant location +!19 = !{!20, !17, i64 0} ; TAG_Y_x_i +!20 = !{!"struct Y", !16, i64 0} ; struct Y { struct X x; }; + +; A TBAA structure who's only point is to have a constant location. !9 = !{!"yet another root"} !10 = !{!"node", !9, i64 1} - diff --git a/llvm/test/Transforms/NewGVN/tbaa.ll b/llvm/test/Transforms/NewGVN/tbaa.ll index 3dcc4f8acc14a..d48ededac03aa 100644 --- a/llvm/test/Transforms/NewGVN/tbaa.ll +++ b/llvm/test/Transforms/NewGVN/tbaa.ll @@ -1,7 +1,7 @@ ; RUN: opt -tbaa -basicaa -newgvn -S < %s | FileCheck %s define i32 @test1(i8* %p, i8* %q) { -; CHECK: @test1(i8* %p, i8* %q) +; CHECK-LABEL: @test1(i8* %p, i8* %q) ; CHECK: call i32 @foo(i8* %p) ; CHECK-NOT: tbaa ; CHECK: %c = add i32 %a, %a @@ -12,7 +12,7 @@ define i32 @test1(i8* %p, i8* %q) { } define i32 @test2(i8* %p, i8* %q) { -; CHECK: @test2(i8* %p, i8* %q) +; CHECK-LABEL: @test2(i8* %p, i8* %q) ; CHECK: call i32 @foo(i8* %p), !tbaa [[TAGC:!.*]] ; CHECK: %c = add i32 %a, %a %a = call i32 @foo(i8* %p), !tbaa !0 @@ -22,7 +22,7 @@ define i32 @test2(i8* %p, i8* %q) { } define i32 @test3(i8* %p, i8* %q) { -; CHECK: @test3(i8* %p, i8* %q) +; CHECK-LABEL: @test3(i8* %p, i8* %q) ; CHECK: call i32 @foo(i8* %p), !tbaa [[TAGB:!.*]] ; CHECK: %c = add i32 %a, %a %a = call i32 @foo(i8* %p), !tbaa !3 @@ -32,7 +32,7 @@ define i32 @test3(i8* %p, i8* %q) { } define i32 @test4(i8* %p, i8* %q) { -; CHECK: @test4(i8* %p, i8* %q) +; CHECK-LABEL: @test4(i8* %p, i8* %q) ; CHECK: call i32 @foo(i8* %p), !tbaa [[TAGA:!.*]] ; CHECK: %c = add i32 %a, %a %a = call i32 @foo(i8* %p), !tbaa !1 @@ -42,8 +42,8 @@ define i32 @test4(i8* %p, i8* %q) { } define i32 @test5(i8* %p, i8* %q) { -; CHECK: @test5(i8* %p, i8* %q) -; CHECK: call i32 @foo(i8* %p), !tbaa [[TAGA:!.*]] +; CHECK-LABEL: @test5(i8* %p, i8* %q) +; CHECK: call i32 @foo(i8* %p), !tbaa [[TAGA]] ; CHECK: %c = add i32 %a, %a %a = call i32 @foo(i8* %p), !tbaa !0 %b = call i32 @foo(i8* %p), !tbaa !1 @@ -52,8 +52,8 @@ define i32 @test5(i8* %p, i8* %q) { } define i32 @test6(i8* %p, i8* %q) { -; CHECK: @test6(i8* %p, i8* %q) -; CHECK: call i32 @foo(i8* %p), !tbaa [[TAGA:!.*]] +; CHECK-LABEL: @test6(i8* %p, i8* %q) +; CHECK: call i32 @foo(i8* %p), !tbaa [[TAGA]] ; CHECK: %c = add i32 %a, %a %a = call i32 @foo(i8* %p), !tbaa !0 %b = call i32 @foo(i8* %p), !tbaa !3 @@ -62,7 +62,7 @@ define i32 @test6(i8* %p, i8* %q) { } define i32 @test7(i8* %p, i8* %q) { -; CHECK: @test7(i8* %p, i8* %q) +; CHECK-LABEL: @test7(i8* %p, i8* %q) ; CHECK: call i32 @foo(i8* %p) ; CHECK-NOT: tbaa ; CHECK: %c = add i32 %a, %a @@ -72,10 +72,8 @@ define i32 @test7(i8* %p, i8* %q) { ret i32 %c } - - define i32 @test8(i32* %p, i32* %q) { -; CHECK-LABEL: test8 +; CHECK-LABEL: @test8 ; CHECK-NEXT: store i32 15, i32* %p ; CHECK-NEXT: ret i32 0 ; Since we know the location is invariant, we can forward the @@ -87,8 +85,9 @@ define i32 @test8(i32* %p, i32* %q) { %c = sub i32 %a, %b ret i32 %c } + define i32 @test9(i32* %p, i32* %q) { -; CHECK-LABEL: test9 +; CHECK-LABEL: @test9 ; CHECK-NEXT: call void @clobber() ; CHECK-NEXT: ret i32 0 ; Since we know the location is invariant, we can forward the @@ -101,16 +100,27 @@ define i32 @test9(i32* %p, i32* %q) { ret i32 %c } +define i32 @test10(i8* %p, i8* %q) { +; If one access encloses the other, then the merged access is the enclosed one +; and not just the common final access type. +; CHECK-LABEL: @test10 +; CHECK: call i32 @foo(i8* %p), !tbaa [[TAG_X_i:!.*]] +; CHECK: %c = add i32 %a, %a + %a = call i32 @foo(i8* %p), !tbaa !15 ; TAG_X_i + %b = call i32 @foo(i8* %p), !tbaa !19 ; TAG_Y_x_i + %c = add i32 %a, %b + ret i32 %c +} declare void @clobber() declare i32 @foo(i8*) readonly -; CHECK: [[TAGC]] = !{[[TYPEC:!.*]], [[TYPEC]], i64 0} -; CHECK: [[TYPEC]] = !{!"C", [[TYPEA:!.*]]} -; CHECK: [[TYPEA]] = !{!"A", !{{.*}}} -; CHECK: [[TAGB]] = !{[[TYPEB:!.*]], [[TYPEB]], i64 0} -; CHECK: [[TYPEB]] = !{!"B", [[TYPEA]]} -; CHECK: [[TAGA]] = !{[[TYPEA]], [[TYPEA]], i64 0} +; CHECK-DAG: [[TAGC]] = !{[[TYPEC:!.*]], [[TYPEC]], i64 0} +; CHECK-DAG: [[TYPEC]] = !{!"C", [[TYPEA:!.*]]} +; CHECK-DAG: [[TYPEA]] = !{!"A", !{{.*}}} +; CHECK-DAG: [[TAGB]] = !{[[TYPEB:!.*]], [[TYPEB]], i64 0} +; CHECK-DAG: [[TYPEB]] = !{!"B", [[TYPEA]]} +; CHECK-DAG: [[TAGA]] = !{[[TYPEA]], [[TYPEA]], i64 0} !0 = !{!5, !5, i64 0} !1 = !{!6, !6, i64 0} !2 = !{!"tbaa root"} @@ -122,8 +132,17 @@ declare i32 @foo(i8*) readonly !8 = !{!"another root"} !11 = !{!"scalar type", !8} +; CHECK-DAG: [[TAG_X_i]] = !{[[TYPE_X:!.*]], [[TYPE_int:!.*]], i64 0} +; CHECK-DAG: [[TYPE_X:!.*]] = !{!"struct X", [[TYPE_int]], i64 0} +; CHECK-DAG: [[TYPE_int]] = !{!"int", {{!.*}}, i64 0} +!15 = !{!16, !17, i64 0} ; TAG_X_i +!16 = !{!"struct X", !17, i64 0} ; struct X { int i; }; +!17 = !{!"int", !18, i64 0} +!18 = !{!"char", !2, i64 0} -;; A TBAA structure who's only point is to have a constant location +!19 = !{!20, !17, i64 0} ; TAG_Y_x_i +!20 = !{!"struct Y", !16, i64 0} ; struct Y { struct X x; }; + +; A TBAA structure who's only point is to have a constant location. !9 = !{!"yet another root"} !10 = !{!"node", !9, i64 1} -