[RS4GC] Strip noalias attribute after statepoint rewrite
authorIgor Laevsky <igmyrj@gmail.com>
Mon, 26 Oct 2015 19:06:01 +0000 (19:06 +0000)
committerIgor Laevsky <igmyrj@gmail.com>
Mon, 26 Oct 2015 19:06:01 +0000 (19:06 +0000)
We should remove noalias along with dereference and dereference_or_null attributes
because statepoint could potentially touch the entire heap including noalias objects.

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

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@251333 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/IR/CallSite.h
include/llvm/IR/Function.h
include/llvm/IR/Instructions.h
lib/Transforms/Scalar/RewriteStatepointsForGC.cpp
test/Transforms/RewriteStatepointsForGC/deopt-bundles/deref-pointers.ll
test/Transforms/RewriteStatepointsForGC/deref-pointers.ll

index d8fd9fa30a6f92fe69b9bc9713cb7adcd05e6cad..235d4259a13c6e2bafd2d1f334b0a53dcc8bf8ee 100644 (file)
@@ -262,6 +262,13 @@ public:
     CALLSITE_DELEGATE_GETTER(getDereferenceableOrNullBytes(i));
   }
 
+  /// @brief Determine if the parameter or return value is marked with NoAlias
+  /// attribute.
+  /// @param n The parameter to check. 1 is the first parameter, 0 is the return
+  bool doesNotAlias(unsigned n) const {
+    CALLSITE_DELEGATE_GETTER(doesNotAlias(n));
+  }
+
   /// \brief Return true if the call should not be treated as a call to a
   /// builtin.
   bool isNoBuiltin() const {
index cb850e3d2af28b59fdeb0d609b7a6f8d6c25bbd7..a97c196ced0dfd2319e1ad1741243b9a50c9f92b 100644 (file)
@@ -348,7 +348,8 @@ public:
            AttributeSets.hasAttribute(2, Attribute::StructRet);
   }
 
-  /// @brief Determine if the parameter does not alias other parameters.
+  /// @brief Determine if the parameter or return value is marked with NoAlias
+  /// attribute.
   /// @param n The parameter to check. 1 is the first parameter, 0 is the return
   bool doesNotAlias(unsigned n) const {
     return AttributeSets.hasAttribute(n, Attribute::NoAlias);
index cb3a260e0d5fea4baaa4ee5f7cbd7492d11ed5c3..58d5221dea89abbaf4ec7400bc0019ca44660e9e 100644 (file)
@@ -1618,6 +1618,13 @@ public:
     return AttributeList.getDereferenceableOrNullBytes(i);
   }
 
+  /// @brief Determine if the parameter or return value is marked with NoAlias
+  /// attribute.
+  /// @param n The parameter to check. 1 is the first parameter, 0 is the return
+  bool doesNotAlias(unsigned n) const {
+    return AttributeList.hasAttribute(n, Attribute::NoAlias);
+  }
+
   /// \brief Return true if the call should not be treated as a call to a
   /// builtin.
   bool isNoBuiltin() const {
@@ -3480,6 +3487,13 @@ public:
     return AttributeList.getDereferenceableOrNullBytes(i);
   }
 
+  /// @brief Determine if the parameter or return value is marked with NoAlias
+  /// attribute.
+  /// @param n The parameter to check. 1 is the first parameter, 0 is the return
+  bool doesNotAlias(unsigned n) const {
+    return AttributeList.hasAttribute(n, Attribute::NoAlias);
+  }
+
   /// \brief Return true if the call should not be treated as a call to a
   /// builtin.
   bool isNoBuiltin() const {
index a5fbbf92d9bcffbfcd436dbef090546b4cb9eeb0..a5eb0f9d5dc3c4d4e228409a310b6af45ed1ca55 100644 (file)
@@ -115,7 +115,8 @@ struct RewriteStatepointsForGC : public ModulePass {
   /// heap.  stripNonValidAttributes (conservatively) restores correctness
   /// by erasing all attributes in the module that externally imply
   /// dereferenceability.
-  ///
+  /// Similar reasoning also applies to the noalias attributes. gc.statepoint
+  /// can touch the entire heap including noalias objects.
   void stripNonValidAttributes(Module &M);
 
   // Helpers for stripNonValidAttributes
@@ -2501,6 +2502,8 @@ static void RemoveNonValidAttrAtIndex(LLVMContext &Ctx, AttrHolder &AH,
   if (AH.getDereferenceableOrNullBytes(Index))
     R.addAttribute(Attribute::get(Ctx, Attribute::DereferenceableOrNull,
                                   AH.getDereferenceableOrNullBytes(Index)));
+  if (AH.doesNotAlias(Index))
+    R.addAttribute(Attribute::NoAlias);
 
   if (!R.empty())
     AH.setAttributes(AH.getAttributes().removeAttributes(
index f868d5b83613fcbfab3af00cbefbf9a0dac865bc..f04c6784a8782f7bfbda903be4230ab62870829d 100644 (file)
@@ -3,6 +3,7 @@
 ; CHECK: declare i8 addrspace(1)* @some_function_ret_deref()
 ; CHECK: define i8 addrspace(1)* @test_deref_arg(i8 addrspace(1)* %a)
 ; CHECK: define i8 addrspace(1)* @test_deref_or_null_arg(i8 addrspace(1)* %a)
+; CHECK: define i8 addrspace(1)* @test_noalias_arg(i8 addrspace(1)* %a)
 
 declare void @foo()
 
@@ -11,6 +12,7 @@ declare i8 addrspace(1)* @some_function() "gc-leaf-function"
 declare void @some_function_consumer(i8 addrspace(1)*) "gc-leaf-function"
 
 declare dereferenceable(4) i8 addrspace(1)* @some_function_ret_deref() "gc-leaf-function"
+declare noalias i8 addrspace(1)* @some_function_ret_noalias() "gc-leaf-function"
 
 define i8 addrspace(1)* @test_deref_arg(i8 addrspace(1)* dereferenceable(4) %a) gc "statepoint-example" {
 entry:
@@ -24,6 +26,12 @@ entry:
   ret i8 addrspace(1)* %a
 }
 
+define i8 addrspace(1)* @test_noalias_arg(i8 addrspace(1)* noalias %a) gc "statepoint-example" {
+entry:
+  call void @foo() [ "deopt"(i32 0, i32 -1, i32 0, i32 0, i32 0) ]
+  ret i8 addrspace(1)* %a
+}
+
 define i8 addrspace(1)* @test_deref_retval() gc "statepoint-example" {
 ; CHECK-LABEL: @test_deref_retval(
 ; CHECK: %a = call i8 addrspace(1)* @some_function()
@@ -42,6 +50,15 @@ entry:
   ret i8 addrspace(1)* %a
 }
 
+define i8 addrspace(1)* @test_noalias_retval() gc "statepoint-example" {
+; CHECK-LABEL: @test_noalias_retval(
+; CHECK: %a = call i8 addrspace(1)* @some_function()
+entry:
+  %a = call noalias i8 addrspace(1)* @some_function()
+  call void @foo() [ "deopt"(i32 0, i32 -1, i32 0, i32 0, i32 0) ]
+  ret i8 addrspace(1)* %a
+}
+
 define i8 @test_md(i8 addrspace(1)* %ptr) gc "statepoint-example" {
 ; CHECK-LABEL: @test_md(
 ; CHECK: %tmp = load i8, i8 addrspace(1)* %ptr, !tbaa !0
@@ -61,6 +78,16 @@ entry:
   ret i8 addrspace(1)* %a
 }
 
+define i8 addrspace(1)* @test_decl_only_noalias(i8 addrspace(1)* %ptr) gc "statepoint-example" {
+; CHECK-LABEL: @test_decl_only_noalias(
+; No change here, but the prototype of some_function_ret_noalias should have changed.
+; CHECK: call i8 addrspace(1)* @some_function_ret_noalias()
+entry:
+  %a = call i8 addrspace(1)* @some_function_ret_noalias()
+  call void @foo() [ "deopt"(i32 0, i32 -1, i32 0, i32 0, i32 0) ]
+  ret i8 addrspace(1)* %a
+}
+
 define i8 addrspace(1)* @test_callsite_arg_attribute(i8 addrspace(1)* %ptr) gc "statepoint-example" {
 ; CHECK-LABEL: @test_callsite_arg_attribute(
 ; CHECK: call void @some_function_consumer(i8 addrspace(1)* %ptr)
@@ -68,7 +95,7 @@ define i8 addrspace(1)* @test_callsite_arg_attribute(i8 addrspace(1)* %ptr) gc "
 ; CHECK: !1 = !{!"red", !2}
 ; CHECK: !2 = !{!"blue"}
 entry:
-  call void @some_function_consumer(i8 addrspace(1)* dereferenceable(4) %ptr)
+  call void @some_function_consumer(i8 addrspace(1)* dereferenceable(4) noalias %ptr)
   call void @foo() [ "deopt"(i32 0, i32 -1, i32 0, i32 0, i32 0) ]
   ret i8 addrspace(1)* %ptr
 }
index 5913db21fcf383be3ad17c5270c486085e3d9e91..9778cdbbb2c610204445dd4f7798e548357beed0 100644 (file)
@@ -5,6 +5,8 @@ declare i8 addrspace(1)* @some_function()
 declare void @some_function_consumer(i8 addrspace(1)*)
 declare dereferenceable(4) i8 addrspace(1)* @some_function_ret_deref()
 ; CHECK: declare i8 addrspace(1)* @some_function_ret_deref()
+declare noalias i8 addrspace(1)* @some_function_ret_noalias()
+; CHECK: declare i8 addrspace(1)* @some_function_ret_noalias()
 
 define i8 addrspace(1)* @test_deref_arg(i8 addrspace(1)* dereferenceable(4) %a) gc "statepoint-example" {
 ; CHECK: define i8 addrspace(1)* @test_deref_arg(i8 addrspace(1)* %a)
@@ -66,6 +68,41 @@ entry:
   ret i8 addrspace(1)* %ptr
 }
 
+define i8 addrspace(1)* @test_noalias_arg(i8 addrspace(1)* noalias %a) gc "statepoint-example" {
+; CHECK: define i8 addrspace(1)* @test_noalias_arg(i8 addrspace(1)* %a)
+entry:
+  call i32 (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @foo, i32 0, i32 0, i32 0, i32 5, i32 0, i32 -1, i32 0, i32 0, i32 0)
+  ret i8 addrspace(1)* %a
+}
+
+define i8 addrspace(1)* @test_noalias_retval() gc "statepoint-example" {
+; CHECK-LABEL: @test_noalias_retval(
+entry:
+  %a = call noalias i8 addrspace(1)* @some_function()
+; CHECK: %a = call i8 addrspace(1)* @some_function()
+  call i32 (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @foo, i32 0, i32 0, i32 0, i32 5, i32 0, i32 -1, i32 0, i32 0, i32 0)
+  ret i8 addrspace(1)* %a
+}
+
+define i8 addrspace(1)* @test_decl_only_noalias(i8 addrspace(1)* %ptr) gc "statepoint-example" {
+; CHECK-LABEL: @test_decl_only_noalias(
+entry:
+; No change here, but the prototype of some_function_ret_noalias should have changed.
+; CHECK: call i8 addrspace(1)* @some_function_ret_noalias()
+  %a = call i8 addrspace(1)* @some_function_ret_noalias()
+  call i32 (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @foo, i32 0, i32 0, i32 0, i32 5, i32 0, i32 -1, i32 0, i32 0, i32 0)
+  ret i8 addrspace(1)* %a
+}
+
+define i8 addrspace(1)* @test_callsite_arg_noalias(i8 addrspace(1)* %ptr) gc "statepoint-example" {
+; CHECK-LABEL: @test_callsite_arg_noalias(
+entry:
+; CHECK: call void @some_function_consumer(i8 addrspace(1)* %ptr)
+  call void @some_function_consumer(i8 addrspace(1)* noalias %ptr)
+  call i32 (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @foo, i32 0, i32 0, i32 0, i32 5, i32 0, i32 -1, i32 0, i32 0, i32 0)
+  ret i8 addrspace(1)* %ptr
+}
+
 declare i32 @llvm.experimental.gc.statepoint.p0f_isVoidf(i64, i32, void ()*, i32, i32, ...)
 
 !0 = !{!1, !1, i64 0, i64 1}