Index: include/llvm/IR/CallSite.h =================================================================== --- include/llvm/IR/CallSite.h +++ include/llvm/IR/CallSite.h @@ -262,6 +262,12 @@ CALLSITE_DELEGATE_GETTER(getDereferenceableOrNullBytes(i)); } + /// @brief Determine if the parameter does not alias other parameters. + /// @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: include/llvm/IR/Instructions.h =================================================================== --- include/llvm/IR/Instructions.h +++ include/llvm/IR/Instructions.h @@ -1618,6 +1618,12 @@ return AttributeList.getDereferenceableOrNullBytes(i); } + /// @brief Determine if the parameter does not alias other parameters. + /// @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 +3486,12 @@ return AttributeList.getDereferenceableOrNullBytes(i); } + /// @brief Determine if the parameter does not alias other parameters. + /// @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: lib/Transforms/Scalar/RewriteStatepointsForGC.cpp =================================================================== --- lib/Transforms/Scalar/RewriteStatepointsForGC.cpp +++ 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 thing also applies to the noalias attributes. gc.tatepoint 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: test/Transforms/RewriteStatepointsForGC/deref-pointers.ll =================================================================== --- test/Transforms/RewriteStatepointsForGC/deref-pointers.ll +++ 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}