[llvm] c80cf48 - [Attributor] AAReachability : use isPotentiallyReachable in isKnownReachable

Johannes Doerfert via llvm-commits llvm-commits at lists.llvm.org
Sat Apr 4 17:22:45 PDT 2020


Author: Shinji Okumura
Date: 2020-04-04T19:16:17-05:00
New Revision: c80cf48801be54ee008730a9fad7dbccc963fc80

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

LOG: [Attributor] AAReachability : use isPotentiallyReachable in isKnownReachable

`isKnownReachable` had only interface (always returns true).
 Changed it to call `isPotentiallyReachable`.
This change enables deductions of other Abstract Attributes depending on
AAReachability to use reachability information obtained from CFG, and it
can make them stronger.

Reviewed By: jdoerfert

Differential Revision: https://reviews.llvm.org/D76210

Added: 
    

Modified: 
    llvm/include/llvm/Transforms/IPO/Attributor.h
    llvm/test/Transforms/Attributor/heap_to_stack.ll
    llvm/test/Transforms/Attributor/misc.ll
    llvm/test/Transforms/Attributor/noalias.ll

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h
index 1165c68a37e9..f150b5581f1b 100644
--- a/llvm/include/llvm/Transforms/IPO/Attributor.h
+++ b/llvm/include/llvm/Transforms/IPO/Attributor.h
@@ -102,6 +102,7 @@
 #include "llvm/ADT/SetVector.h"
 #include "llvm/Analysis/AliasAnalysis.h"
 #include "llvm/Analysis/AssumeBundleQueries.h"
+#include "llvm/Analysis/CFG.h"
 #include "llvm/Analysis/CGSCCPassManager.h"
 #include "llvm/Analysis/CallGraph.h"
 #include "llvm/Analysis/InlineCost.h"
@@ -2106,14 +2107,14 @@ struct AAReachability : public StateWrapper<BooleanState, AbstractAttribute>,
   /// determines (and caches) reachability.
   bool isAssumedReachable(const Instruction *From,
                           const Instruction *To) const {
-    return true;
+    return isPotentiallyReachable(From, To);
   }
 
   /// Returns true if 'From' instruction is known to reach, 'To' instruction.
   /// Users should provide two positions they are interested in, and the class
   /// determines (and caches) reachability.
   bool isKnownReachable(const Instruction *From, const Instruction *To) const {
-    return true;
+    return isPotentiallyReachable(From, To);
   }
 
   /// Return an IR position, see struct IRPosition.

diff  --git a/llvm/test/Transforms/Attributor/heap_to_stack.ll b/llvm/test/Transforms/Attributor/heap_to_stack.ll
index 707aea7bfda8..3adbf3812f17 100644
--- a/llvm/test/Transforms/Attributor/heap_to_stack.ll
+++ b/llvm/test/Transforms/Attributor/heap_to_stack.ll
@@ -184,7 +184,7 @@ define void @test7() {
 define void @test8() {
   %1 = tail call noalias i8* @malloc(i64 4)
   ; CHECK: %1 = tail call noalias i8* @malloc(i64 4)
-  ; CHECK-NEXT: @no_sync_func(i8* nocapture nofree %1)
+  ; CHECK-NEXT: @no_sync_func(i8* noalias nocapture nofree %1)
   tail call void @no_sync_func(i8* %1)
   %2 = bitcast i8* %1 to i32*
   store i32 10, i32* %2
@@ -199,7 +199,7 @@ define void @test8() {
 define void @test9() {
   %1 = tail call noalias i8* @malloc(i64 4)
   ; CHECK: %1 = tail call noalias i8* @malloc(i64 4)
-  ; CHECK-NEXT: @no_sync_func(i8* nocapture nofree %1)
+  ; CHECK-NEXT: @no_sync_func(i8* noalias nocapture nofree %1)
   tail call void @no_sync_func(i8* %1)
   %2 = bitcast i8* %1 to i32*
   store i32 10, i32* %2

diff  --git a/llvm/test/Transforms/Attributor/misc.ll b/llvm/test/Transforms/Attributor/misc.ll
index 2b79bdbee21f..b660300bcc20 100644
--- a/llvm/test/Transforms/Attributor/misc.ll
+++ b/llvm/test/Transforms/Attributor/misc.ll
@@ -9,7 +9,7 @@ define internal void @internal(void (i8*)* %fp) {
 ; CHECK-SAME: (void (i8*)* nonnull [[FP:%.*]])
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
-; CHECK-NEXT:    call void @foo(i32* nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[A]])
+; CHECK-NEXT:    call void @foo(i32* noalias nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[A]])
 ; CHECK-NEXT:    call void [[FP]](i8* bitcast (void (i32*)* @foo to i8*))
 ; CHECK-NEXT:    call void @callback1(void (i32*)* nonnull @foo)
 ; CHECK-NEXT:    call void @callback2(void (i8*)* bitcast (void (i32*)* @foo to void (i8*)*))
@@ -22,7 +22,7 @@ define internal void @internal(void (i8*)* %fp) {
 ; DECL_CS-SAME: (void (i8*)* nonnull [[FP:%.*]])
 ; DECL_CS-NEXT:  entry:
 ; DECL_CS-NEXT:    [[A:%.*]] = alloca i32, align 4
-; DECL_CS-NEXT:    call void @foo(i32* nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[A]])
+; DECL_CS-NEXT:    call void @foo(i32* noalias nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[A]])
 ; DECL_CS-NEXT:    call void [[FP]](i8* bitcast (void (i32*)* @foo to i8*))
 ; DECL_CS-NEXT:    call void @callback1(void (i32*)* nonnull @foo)
 ; DECL_CS-NEXT:    call void @callback2(void (i8*)* nonnull bitcast (void (i32*)* @foo to void (i8*)*))
@@ -49,7 +49,7 @@ define void @external(void (i8*)* %fp) {
 ; CHECK-SAME: (void (i8*)* [[FP:%.*]])
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
-; CHECK-NEXT:    call void @foo(i32* nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[A]])
+; CHECK-NEXT:    call void @foo(i32* noalias nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[A]])
 ; CHECK-NEXT:    call void @callback1(void (i32*)* nonnull @foo)
 ; CHECK-NEXT:    call void @callback2(void (i8*)* bitcast (void (i32*)* @foo to void (i8*)*))
 ; CHECK-NEXT:    call void @callback2(void (i8*)* [[FP]])
@@ -63,7 +63,7 @@ define void @external(void (i8*)* %fp) {
 ; DECL_CS-SAME: (void (i8*)* [[FP:%.*]])
 ; DECL_CS-NEXT:  entry:
 ; DECL_CS-NEXT:    [[A:%.*]] = alloca i32, align 4
-; DECL_CS-NEXT:    call void @foo(i32* nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[A]])
+; DECL_CS-NEXT:    call void @foo(i32* noalias nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[A]])
 ; DECL_CS-NEXT:    call void @callback1(void (i32*)* nonnull @foo)
 ; DECL_CS-NEXT:    call void @callback2(void (i8*)* nonnull bitcast (void (i32*)* @foo to void (i8*)*))
 ; DECL_CS-NEXT:    call void @callback2(void (i8*)* [[FP]])

diff  --git a/llvm/test/Transforms/Attributor/noalias.ll b/llvm/test/Transforms/Attributor/noalias.ll
index 358528546f9d..0b7856e01d9a 100644
--- a/llvm/test/Transforms/Attributor/noalias.ll
+++ b/llvm/test/Transforms/Attributor/noalias.ll
@@ -255,10 +255,8 @@ define void @test12_1() {
 define void @test12_2(){
 ; CHECK-LABEL: @test12_2(
 ; CHECK-NEXT:    [[A:%.*]] = tail call noalias i8* @malloc(i64 4)
-; FIXME: This should be @use_nocapture(i8* noalias [[A]])
-; CHECK-NEXT:    tail call void @use_nocapture(i8* nocapture [[A]])
-; FIXME: This should be @use_nocapture(i8* noalias nocapture [[A]])
-; CHECK-NEXT:    tail call void @use_nocapture(i8* nocapture [[A]])
+; CHECK-NEXT:    tail call void @use_nocapture(i8* noalias nocapture [[A]])
+; CHECK-NEXT:    tail call void @use_nocapture(i8* noalias nocapture [[A]])
 ; CHECK-NEXT:    tail call void @use(i8* [[A]])
 ; CHECK-NEXT:    tail call void @use_nocapture(i8* nocapture [[A]])
 ; CHECK-NEXT:    ret void
@@ -393,3 +391,82 @@ declare dso_local double @__floatscan(%struct._IO_FILE*, i32, i32) local_unnamed
 
 ; Function Attrs: argmemonly nounwind willreturn
 declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture)
+
+; Test 15
+; propagate noalias to some callsite arguments that there is no possibly reachable capture before it 
+
+ at alias_of_p = external global i32*
+
+define void @make_alias(i32* %p) {
+  store i32* %p, i32** @alias_of_p
+  ret void
+}
+
+define void @only_store(i32* %p) {
+  store i32 0, i32* %p
+  ret void
+}
+
+; CHECK-LABEL define void @test15_caller(i32* noalias %p, i32 %c)
+define void @test15_caller(i32* noalias %p, i32 %c) {
+  %tobool = icmp eq i32 %c, 0
+  br i1 %tobool, label %if.end, label %if.then
+
+; CHECK tail call void @only_store(i32* noalias %p)
+; CHECK tail call void @make_alias(i32* %p)
+
+if.then:
+  tail call void @only_store(i32* %p)
+  br label %if.end
+
+if.end:
+  tail call void @make_alias(i32* %p)
+  ret void
+}
+
+; Test 16
+;
+; __attribute__((noinline)) static void test16_sub(int * restrict p, int c1, int c2) {
+;   if (c1) {
+;     only_store(p);
+;     make_alias(p);
+;   }
+;   if (!c2) {
+;     only_store(p);
+;   }
+; }
+; void test16_caller(int * restrict p, int c) {
+;   test16_sub(p, c, c);
+; }
+
+; CHECK-LABEL define internal void @test16_sub(i32* noalias %p, i32 %c1, i32 %c2)
+define internal void @test16_sub(i32* noalias %p, i32 %c1, i32 %c2) {
+  %tobool = icmp eq i32 %c1, 0
+  br i1 %tobool, label %if.end, label %if.then
+
+; CHECK tail call void @only_store(i32* noalias %p)
+if.then:
+  tail call void @only_store(i32* %p) 
+  tail call void @make_alias(i32* %p) 
+  br label %if.end
+if.end:
+
+  %tobool1 = icmp eq i32 %c2, 0
+  br i1 %tobool1, label %if.then2, label %if.end3
+
+; FIXME: this should be tail @only_store(i32* noalias %p)
+;        when test16_caller is called, c1 always equals to c2. (Note that linkage is internal)
+;        Therefore, only one of the two conditions of if statementes will be fulfilled.
+; CHECK tail call void @only_store(i32* %p)
+if.then2:
+  tail call void @only_store(i32* %p)
+  br label %if.end3
+if.end3:
+
+  ret void
+}
+
+define void @test16_caller(i32* %p, i32 %c) {
+  tail call void @test16_sub(i32* %p, i32 %c, i32 %c)
+  ret void
+}


        


More information about the llvm-commits mailing list