diff --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h --- 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 @@ /// 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 --- a/llvm/test/Transforms/Attributor/heap_to_stack.ll +++ b/llvm/test/Transforms/Attributor/heap_to_stack.ll @@ -184,7 +184,7 @@ 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 @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 --- a/llvm/test/Transforms/Attributor/misc.ll +++ b/llvm/test/Transforms/Attributor/misc.ll @@ -9,7 +9,7 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 --- a/llvm/test/Transforms/Attributor/noalias.ll +++ b/llvm/test/Transforms/Attributor/noalias.ll @@ -255,10 +255,8 @@ 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 @@ ; 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 + +@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 +}