From 14ff71aa42b29a6167be5370aeccf3ad26040de0 Mon Sep 17 00:00:00 2001 From: Igor Laevsky Date: Mon, 26 Oct 2015 19:06:01 +0000 Subject: [PATCH] [RS4GC] Strip noalias attribute after statepoint rewrite 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 | 7 ++++ include/llvm/IR/Function.h | 3 +- include/llvm/IR/Instructions.h | 14 +++++++ .../Scalar/RewriteStatepointsForGC.cpp | 5 ++- .../deopt-bundles/deref-pointers.ll | 29 ++++++++++++++- .../RewriteStatepointsForGC/deref-pointers.ll | 37 +++++++++++++++++++ 6 files changed, 92 insertions(+), 3 deletions(-) diff --git a/include/llvm/IR/CallSite.h b/include/llvm/IR/CallSite.h index d8fd9fa30a6..235d4259a13 100644 --- a/include/llvm/IR/CallSite.h +++ b/include/llvm/IR/CallSite.h @@ -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 { diff --git a/include/llvm/IR/Function.h b/include/llvm/IR/Function.h index cb850e3d2af..a97c196ced0 100644 --- a/include/llvm/IR/Function.h +++ b/include/llvm/IR/Function.h @@ -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); diff --git a/include/llvm/IR/Instructions.h b/include/llvm/IR/Instructions.h index cb3a260e0d5..58d5221dea8 100644 --- a/include/llvm/IR/Instructions.h +++ b/include/llvm/IR/Instructions.h @@ -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 { diff --git a/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp b/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp index a5fbbf92d9b..a5eb0f9d5dc 100644 --- a/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp +++ b/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp @@ -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( diff --git a/test/Transforms/RewriteStatepointsForGC/deopt-bundles/deref-pointers.ll b/test/Transforms/RewriteStatepointsForGC/deopt-bundles/deref-pointers.ll index f868d5b8361..f04c6784a87 100644 --- a/test/Transforms/RewriteStatepointsForGC/deopt-bundles/deref-pointers.ll +++ b/test/Transforms/RewriteStatepointsForGC/deopt-bundles/deref-pointers.ll @@ -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 } diff --git a/test/Transforms/RewriteStatepointsForGC/deref-pointers.ll b/test/Transforms/RewriteStatepointsForGC/deref-pointers.ll index 5913db21fcf..9778cdbbb2c 100644 --- a/test/Transforms/RewriteStatepointsForGC/deref-pointers.ll +++ b/test/Transforms/RewriteStatepointsForGC/deref-pointers.ll @@ -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} -- 2.34.1