Index: llvm/trunk/include/llvm/IR/CallSite.h =================================================================== --- llvm/trunk/include/llvm/IR/CallSite.h +++ llvm/trunk/include/llvm/IR/CallSite.h @@ -262,6 +262,13 @@ 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: llvm/trunk/include/llvm/IR/Function.h =================================================================== --- llvm/trunk/include/llvm/IR/Function.h +++ llvm/trunk/include/llvm/IR/Function.h @@ -348,7 +348,8 @@ 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: llvm/trunk/include/llvm/IR/Instructions.h =================================================================== --- llvm/trunk/include/llvm/IR/Instructions.h +++ llvm/trunk/include/llvm/IR/Instructions.h @@ -1618,6 +1618,13 @@ 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 @@ 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: llvm/trunk/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp +++ llvm/trunk/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp @@ -115,7 +115,8 @@ /// 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 @@ 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: llvm/trunk/test/Transforms/RewriteStatepointsForGC/deopt-bundles/deref-pointers.ll =================================================================== --- llvm/trunk/test/Transforms/RewriteStatepointsForGC/deopt-bundles/deref-pointers.ll +++ llvm/trunk/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 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 @@ 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 @@ 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 @@ 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 @@ ; 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: llvm/trunk/test/Transforms/RewriteStatepointsForGC/deref-pointers.ll =================================================================== --- llvm/trunk/test/Transforms/RewriteStatepointsForGC/deref-pointers.ll +++ llvm/trunk/test/Transforms/RewriteStatepointsForGC/deref-pointers.ll @@ -5,6 +5,8 @@ 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 @@ 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}