Index: llvm/lib/Transforms/Utils/BuildLibCalls.cpp =================================================================== --- llvm/lib/Transforms/Utils/BuildLibCalls.cpp +++ llvm/lib/Transforms/Utils/BuildLibCalls.cpp @@ -31,8 +31,12 @@ //- Infer Attributes ---------------------------------------------------------// STATISTIC(NumReadNone, "Number of functions inferred as readnone"); +STATISTIC(NumInaccessibleMemOnly, + "Number of functions inferred as inaccessiblememonly"); STATISTIC(NumReadOnly, "Number of functions inferred as readonly"); STATISTIC(NumArgMemOnly, "Number of functions inferred as argmemonly"); +STATISTIC(NumInaccessibleMemOrArgMemOnly, + "Number of functions inferred as inaccessiblemem_or_argmemonly"); STATISTIC(NumNoUnwind, "Number of functions inferred as nounwind"); STATISTIC(NumNoCapture, "Number of arguments inferred as nocapture"); STATISTIC(NumWriteOnlyArg, "Number of arguments inferred as writeonly"); @@ -51,6 +55,14 @@ return true; } +static bool setOnlyAccessesInaccessibleMemory(Function &F) { + if (F.onlyAccessesInaccessibleMemory()) + return false; + F.setOnlyAccessesInaccessibleMemory(); + ++NumInaccessibleMemOnly; + return true; +} + static bool setOnlyReadsMemory(Function &F) { if (F.onlyReadsMemory()) return false; @@ -67,6 +79,14 @@ return true; } +static bool setOnlyAccessesInaccessibleMemOrArgMem(Function &F) { + if (F.onlyAccessesInaccessibleMemOrArgMem()) + return false; + F.setOnlyAccessesInaccessibleMemOrArgMem(); + ++NumInaccessibleMemOrArgMemOnly; + return true; +} + static bool setDoesNotThrow(Function &F) { if (F.doesNotThrow()) return false; @@ -349,6 +369,7 @@ Changed |= setOnlyReadsMemory(F, 0); return Changed; case LibFunc_malloc: + Changed |= setOnlyAccessesInaccessibleMemory(F); Changed |= setRetNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setRetDoesNotAlias(F); @@ -418,6 +439,7 @@ Changed |= setDoesNotCapture(F, 0); return Changed; case LibFunc_realloc: + Changed |= setOnlyAccessesInaccessibleMemOrArgMem(F); Changed |= setRetNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setRetDoesNotAlias(F); @@ -466,6 +488,7 @@ Changed |= setOnlyReadsMemory(F, 1); return Changed; case LibFunc_aligned_alloc: + Changed |= setOnlyAccessesInaccessibleMemory(F); Changed |= setRetNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setRetDoesNotAlias(F); @@ -492,6 +515,7 @@ Changed |= setOnlyWritesMemory(F, 0); return Changed; case LibFunc_calloc: + Changed |= setOnlyAccessesInaccessibleMemory(F); Changed |= setRetNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setRetDoesNotAlias(F); @@ -546,6 +570,7 @@ Changed |= setDoesNotCapture(F, 0); return Changed; case LibFunc_free: + Changed |= setOnlyAccessesInaccessibleMemOrArgMem(F); Changed |= setArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); @@ -769,6 +794,7 @@ Changed |= setOnlyReadsMemory(F, 1); return Changed; case LibFunc_valloc: + Changed |= setOnlyAccessesInaccessibleMemory(F); Changed |= setRetNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setRetDoesNotAlias(F); @@ -937,6 +963,7 @@ case LibFunc_msvc_new_longlong: // new(unsigned long long) case LibFunc_msvc_new_array_int: // new[](unsigned int) case LibFunc_msvc_new_array_longlong: // new[](unsigned long long) + Changed |= setOnlyAccessesInaccessibleMemory(F); // Operator new always returns a nonnull noalias pointer Changed |= setRetNoUndef(F); Changed |= setRetNonNull(F); Index: llvm/test/Transforms/InferFunctionAttrs/annotate.ll =================================================================== --- llvm/test/Transforms/InferFunctionAttrs/annotate.ll +++ llvm/test/Transforms/InferFunctionAttrs/annotate.ll @@ -6,9 +6,9 @@ ; operator new routines declare i8* @_Znwj(i64 ) -; CHECK: declare noalias noundef nonnull i8* @_Znwj(i64) [[NOFREE:#[0-9]+]] +; CHECK: declare noalias noundef nonnull i8* @_Znwj(i64) [[INACCESSIBLEMEMONLY_NOFREE:#[0-9]+]] declare i8* @_Znwm(i64) -; CHECK: declare noalias noundef nonnull i8* @_Znwm(i64) [[NOFREE]] +; CHECK: declare noalias noundef nonnull i8* @_Znwm(i64) [[INACCESSIBLEMEMONLY_NOFREE]] declare i32 @__nvvm_reflect(i8*) ; CHECK-NVPTX: declare noundef i32 @__nvvm_reflect(i8* noundef) [[NOFREE:#[0-9]+]] @@ -160,7 +160,7 @@ ; CHECK: declare float @__sinpif(float) declare float @__sinpif(float) -; CHECK: declare i32 @abs(i32) [[NOFREE]] +; CHECK: declare i32 @abs(i32) [[NOFREE:#[0-9]+]] declare i32 @abs(i32) ; CHECK: declare noundef i32 @access(i8* nocapture noundef readonly, i32 noundef) [[NOFREE_NOUNWIND:#[0-9]+]] @@ -184,6 +184,9 @@ ; CHECK: declare x86_fp80 @acosl(x86_fp80) [[NOFREE]] declare x86_fp80 @acosl(x86_fp80) +; CHECK: declare noalias noundef i8* @aligned_alloc(i64, i64) [[INACCESSIBLEMEMONLY_NOFREE_NOUNWIND:#[0-9]+]] +declare i8* @aligned_alloc(i64, i64) + ; CHECK: declare double @asin(double) [[NOFREE]] declare double @asin(double) @@ -253,7 +256,7 @@ ; CHECK: declare void @bzero(i8* nocapture writeonly, i64) [[ARGMEMONLY_NOFREE_NOUNWIND:#[0-9]+]] declare void @bzero(i8*, i64) -; CHECK: declare noalias noundef i8* @calloc(i64, i64) [[NOFREE_NOUNWIND]] +; CHECK: declare noalias noundef i8* @calloc(i64, i64) [[INACCESSIBLEMEMONLY_NOFREE_NOUNWIND]] declare i8* @calloc(i64, i64) ; CHECK: declare double @cbrt(double) [[NOFREE]] @@ -451,7 +454,7 @@ ; CHECK: declare noundef i64 @fread(i8* nocapture noundef, i64 noundef, i64 noundef, %opaque* nocapture noundef) [[NOFREE_NOUNWIND]] declare i64 @fread(i8*, i64, i64, %opaque*) -; CHECK: declare void @free(i8* nocapture noundef) [[NOUNWIND:#[0-9]+]] +; CHECK: declare void @free(i8* nocapture noundef) [[INACCESSIBLEMEMORARGMEMONLY_NOUNWIND:#[0-9]+]] declare void @free(i8*) ; CHECK: declare double @frexp(double, i32* nocapture) [[NOFREE_NOUNWIND]] @@ -613,7 +616,7 @@ ; CHECK-LINUX: declare noundef i32 @lstat64(i8* nocapture noundef readonly, %opaque* nocapture noundef) [[NOFREE_NOUNWIND]] declare i32 @lstat64(i8*, %opaque*) -; CHECK: declare noalias noundef i8* @malloc(i64) [[NOFREE_NOUNWIND]] +; CHECK: declare noalias noundef i8* @malloc(i64) [[INACCESSIBLEMEMONLY_NOFREE_NOUNWIND]] declare i8* @malloc(i64) ; CHECK-LINUX: declare noalias i8* @memalign(i64, i64) [[NOFREE]] @@ -726,7 +729,7 @@ ; CHECK: declare noundef i64 @readlink(i8* nocapture noundef readonly, i8* nocapture noundef, i64 noundef) [[NOFREE_NOUNWIND]] declare i64 @readlink(i8*, i8*, i64) -; CHECK: declare noalias noundef i8* @realloc(i8* nocapture, i64) [[NOUNWIND]] +; CHECK: declare noalias noundef i8* @realloc(i8* nocapture, i64) [[INACCESSIBLEMEMORARGMEMONLY_NOUNWIND]] declare i8* @realloc(i8*, i64) ; CHECK: declare noundef i8* @reallocf(i8*, i64) @@ -978,7 +981,7 @@ ; CHECK: declare noundef i32 @utimes(i8* nocapture noundef readonly, %opaque* nocapture noundef readonly) [[NOFREE_NOUNWIND]] declare i32 @utimes(i8*, %opaque*) -; CHECK: declare noalias noundef i8* @valloc(i64) [[NOFREE_NOUNWIND]] +; CHECK: declare noalias noundef i8* @valloc(i64) [[INACCESSIBLEMEMONLY_NOFREE_NOUNWIND]] declare i8* @valloc(i64) ; CHECK: declare noundef i32 @vfprintf(%opaque* nocapture noundef, i8* nocapture noundef readonly, %opaque* noundef) [[NOFREE_NOUNWIND]] @@ -1010,20 +1013,19 @@ ; CHECK-DARWIN: declare void @memset_pattern16(i8* nocapture writeonly, i8* nocapture readonly, i64) [[ARGMEMONLY_NOFREE:#[0-9]+]] declare void @memset_pattern16(i8*, i8*, i64) +; CHECK: attributes [[INACCESSIBLEMEMONLY_NOFREE]] = { inaccessiblememonly nofree } ; CHECK: attributes [[NOFREE]] = { nofree } ; CHECK: attributes [[NOFREE_NOUNWIND]] = { nofree nounwind } -; CHECK: attributes [[NOFREE_NOUNWIND_READONLY]] = { nofree nounwind readonly } +; CHECK-DAG-UNKNOWN: attributes [[INACCESSIBLEMEMONLY_NOFREE_NOUNWIND]] = { inaccessiblememonly nofree nounwind } +; CHECK-DAG-UNKNOWN: attributes [[NOFREE_NOUNWIND_READONLY]] = { nofree nounwind readonly } ; CHECK-DAG-UNKNOWN: attributes [[ARGMEMONLY_NOFREE_NOUNWIND]] = { argmemonly nofree nounwind } -; CHECK-DAG-UNKNOWN: attributes [[NOUNWIND]] = { nounwind } +; CHECK-DAG-UNKNOWN: attributes [[INACCESSIBLEMEMORARGMEMONLY_NOUNWIND]] = { inaccessiblemem_or_argmemonly nounwind } ; CHECK-DAG-UNKNOWN: attributes [[ARGMEMONLY_NOFREE_NOUNWIND_READONLY]] = { argmemonly nofree nounwind readonly } +; CHECK-DAG-LINUX: attributes [[INACCESSIBLEMEMONLY_NOFREE_NOUNWIND]] = { inaccessiblememonly nofree nounwind } +; CHECK-DAG-LINUX: attributes [[NOFREE_NOUNWIND_READONLY]] = { nofree nounwind readonly } ; CHECK-DAG-LINUX: attributes [[ARGMEMONLY_NOFREE_NOUNWIND_READONLY]] = { argmemonly nofree nounwind readonly } ; CHECK-DAG-LINUX: attributes [[ARGMEMONLY_NOFREE_NOUNWIND]] = { argmemonly nofree nounwind } -; CHECK-DAG-LINUX: attributes [[NOUNWIND]] = { nounwind } - -; CHECK-DAG-DARWIN: attributes [[ARGMEMONLY_NOFREE_NOUNWIND]] = { argmemonly nofree nounwind } -; CHECK-DAG-DARWIN: attributes [[NOUNWIND]] = { nounwind } -; CHECK-DAG-DARWIN: attributes [[ARGMEMONLY_NOFREE_NOUNWIND_READONLY]] = { argmemonly nofree nounwind readonly } -; CHECK-DAG-DARWIN: attributes [[ARGMEMONLY_NOFREE]] = { argmemonly nofree } +; CHECK-DAG-LINUX: attributes [[INACCESSIBLEMEMORARGMEMONLY_NOUNWIND]] = { inaccessiblemem_or_argmemonly nounwind }