[llvm] r275066 - [Sink] Don't move calls to readonly functions across stores

Nicolai Haehnle via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 11 07:11:51 PDT 2016


Author: nha
Date: Mon Jul 11 09:11:51 2016
New Revision: 275066

URL: http://llvm.org/viewvc/llvm-project?rev=275066&view=rev
Log:
[Sink] Don't move calls to readonly functions across stores

Summary:

Reviewers: hfinkel, majnemer, tstellarAMD, sunfish

Subscribers: llvm-commits

Differential Revision: http://reviews.llvm.org/D17279

Added:
    llvm/trunk/test/Transforms/Sink/call.ll
Modified:
    llvm/trunk/lib/Transforms/Scalar/Sink.cpp

Modified: llvm/trunk/lib/Transforms/Scalar/Sink.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/Sink.cpp?rev=275066&r1=275065&r2=275066&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Scalar/Sink.cpp (original)
+++ llvm/trunk/lib/Transforms/Scalar/Sink.cpp Mon Jul 11 09:11:51 2016
@@ -76,11 +76,15 @@ static bool isSafeToMove(Instruction *In
       Inst->mayThrow())
     return false;
 
-  // Convergent operations cannot be made control-dependent on additional
-  // values.
   if (auto CS = CallSite(Inst)) {
+    // Convergent operations cannot be made control-dependent on additional
+    // values.
     if (CS.hasFnAttr(Attribute::Convergent))
       return false;
+
+    for (Instruction *S : Stores)
+      if (AA.getModRefInfo(S, CS) & MRI_Mod)
+        return false;
   }
 
   return true;

Added: llvm/trunk/test/Transforms/Sink/call.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/Sink/call.ll?rev=275066&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/Sink/call.ll (added)
+++ llvm/trunk/test/Transforms/Sink/call.ll Mon Jul 11 09:11:51 2016
@@ -0,0 +1,112 @@
+; RUN: opt < %s -basicaa -sink -S | FileCheck %s
+
+declare i32 @f_load_global() nounwind readonly
+declare i32 @f_load_arg(i32*) nounwind readonly argmemonly
+declare void @f_store_global(i32) nounwind
+declare void @f_store_arg(i32*) nounwind argmemonly
+declare void @f_readonly_arg(i32* readonly, i32*) nounwind argmemonly
+declare i32 @f_readnone(i32) nounwind readnone
+
+ at A = external global i32
+ at B = external global i32
+
+; Sink readonly call if no stores are in the way.
+;
+; CHECK-LABEL: @test_sink_no_stores(
+; CHECK: true:
+; CHECK-NEXT: %l = call i32 @f_load_global
+; CHECK-NEXT: ret i32 %l
+define i32 @test_sink_no_stores(i1 %z) {
+  %l = call i32 @f_load_global()
+  br i1 %z, label %true, label %false
+true:
+  ret i32 %l
+false:
+  ret i32 0
+}
+
+; CHECK-LABEL: @test_sink_argmem_store(
+; CHECK: true:
+; CHECK-NEXT: %l = call i32 @f_load_arg
+; CHECK-NEXT: ret i32 %l
+define i32 @test_sink_argmem_store(i1 %z) {
+  %l = call i32 @f_load_arg(i32* @A)
+  store i32 0, i32* @B
+  br i1 %z, label %true, label %false
+true:
+  ret i32 %l
+false:
+  ret i32 0
+}
+
+; CHECK-LABEL: @test_sink_argmem_call(
+; CHECK: true:
+; CHECK-NEXT: %l = call i32 @f_load_arg
+; CHECK-NEXT: ret i32 %l
+define i32 @test_sink_argmem_call(i1 %z) {
+  %l = call i32 @f_load_arg(i32* @A)
+  call void @f_store_arg(i32* @B)
+  br i1 %z, label %true, label %false
+true:
+  ret i32 %l
+false:
+  ret i32 0
+}
+
+; CHECK-LABEL: @test_sink_argmem_multiple(
+; CHECK: true:
+; CHECK-NEXT: %l = call i32 @f_load_arg
+; CHECK-NEXT: ret i32 %l
+define i32 @test_sink_argmem_multiple(i1 %z) {
+  %l = call i32 @f_load_arg(i32* @A)
+  call void @f_readonly_arg(i32* @A, i32* @B)
+  br i1 %z, label %true, label %false
+true:
+  ret i32 %l
+false:
+  ret i32 0
+}
+
+; But don't sink if there is a store.
+;
+; CHECK-LABEL: @test_nosink_store(
+; CHECK: call i32 @f_load_global
+; CHECK-NEXT: store i32
+define i32 @test_nosink_store(i1 %z) {
+  %l = call i32 @f_load_global()
+  store i32 0, i32* @A
+  br i1 %z, label %true, label %false
+true:
+  ret i32 %l
+false:
+  ret i32 0
+}
+
+; CHECK-LABEL: @test_nosink_call(
+; CHECK: call i32 @f_load_global
+; CHECK-NEXT: call void @f_store_global
+define i32 @test_nosink_call(i1 %z) {
+  %l = call i32 @f_load_global()
+  call void @f_store_global(i32 0)
+  br i1 %z, label %true, label %false
+true:
+  ret i32 %l
+false:
+  ret i32 0
+}
+
+; readnone calls are sunk across stores.
+;
+; CHECK-LABEL: @test_sink_readnone(
+; CHECK: true:
+; CHECK-NEXT: %l = call i32 @f_readnone(
+; CHECK-NEXT: ret i32 %l
+define i32 @test_sink_readnone(i1 %z) {
+  %l = call i32 @f_readnone(i32 0)
+  store i32 0, i32* @A
+  br i1 %z, label %true, label %false
+true:
+  ret i32 %l
+false:
+  ret i32 0
+}




More information about the llvm-commits mailing list