From 16d6e8527189298c75bf5690c771e8ab6dc3628d Mon Sep 17 00:00:00 2001 From: =?utf8?q?D=C3=A1vid=20Bolvansk=C3=BD?= Date: Wed, 20 Jan 2021 19:45:13 +0100 Subject: [PATCH] [BuildLibcalls] Mark some libcalls with inaccessiblememonly and inaccessiblemem_or_argmemonly Reviewed By: jdoerfert Differential Revision: https://reviews.llvm.org/D94850 --- llvm/lib/Transforms/Utils/BuildLibCalls.cpp | 32 ++++++++++ .../test/Transforms/InferFunctionAttrs/annotate.ll | 69 +++++++++++++--------- 2 files changed, 72 insertions(+), 29 deletions(-) diff --git a/llvm/lib/Transforms/Utils/BuildLibCalls.cpp b/llvm/lib/Transforms/Utils/BuildLibCalls.cpp index d2ffb99..857c3d9 100644 --- a/llvm/lib/Transforms/Utils/BuildLibCalls.cpp +++ b/llvm/lib/Transforms/Utils/BuildLibCalls.cpp @@ -31,8 +31,12 @@ using namespace llvm; //- 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"); @@ -52,6 +56,14 @@ static bool setDoesNotAccessMemory(Function &F) { 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; @@ -68,6 +80,14 @@ static bool setOnlyAccessesArgMemory(Function &F) { 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; @@ -315,6 +335,7 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) { return Changed; case LibFunc_strdup: case LibFunc_strndup: + Changed |= setOnlyAccessesInaccessibleMemOrArgMem(F); Changed |= setDoesNotThrow(F); Changed |= setRetDoesNotAlias(F); Changed |= setWillReturn(F); @@ -370,6 +391,7 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) { Changed |= setOnlyReadsMemory(F, 0); return Changed; case LibFunc_malloc: + Changed |= setOnlyAccessesInaccessibleMemory(F); Changed |= setRetNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setRetDoesNotAlias(F); @@ -432,6 +454,9 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) { Changed |= setDoesNotThrow(F); return Changed; case LibFunc_memalign: + Changed |= setOnlyAccessesInaccessibleMemory(F); + Changed |= setRetNoUndef(F); + Changed |= setDoesNotThrow(F); Changed |= setRetDoesNotAlias(F); Changed |= setWillReturn(F); return Changed; @@ -448,6 +473,7 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) { Changed |= setDoesNotCapture(F, 0); return Changed; case LibFunc_realloc: + Changed |= setOnlyAccessesInaccessibleMemOrArgMem(F); Changed |= setRetNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setRetDoesNotAlias(F); @@ -498,6 +524,7 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) { Changed |= setOnlyReadsMemory(F, 1); return Changed; case LibFunc_aligned_alloc: + Changed |= setOnlyAccessesInaccessibleMemory(F); Changed |= setRetNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setRetDoesNotAlias(F); @@ -528,6 +555,7 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) { Changed |= setOnlyWritesMemory(F, 0); return Changed; case LibFunc_calloc: + Changed |= setOnlyAccessesInaccessibleMemory(F); Changed |= setRetNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setRetDoesNotAlias(F); @@ -584,6 +612,7 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) { Changed |= setDoesNotCapture(F, 0); return Changed; case LibFunc_free: + Changed |= setOnlyAccessesInaccessibleMemOrArgMem(F); Changed |= setArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setWillReturn(F); @@ -809,9 +838,11 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) { Changed |= setOnlyReadsMemory(F, 1); return Changed; case LibFunc_valloc: + Changed |= setOnlyAccessesInaccessibleMemory(F); Changed |= setRetNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setRetDoesNotAlias(F); + Changed |= setWillReturn(F); return Changed; case LibFunc_vprintf: Changed |= setRetAndArgsNoUndef(F); @@ -978,6 +1009,7 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) { 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); diff --git a/llvm/test/Transforms/InferFunctionAttrs/annotate.ll b/llvm/test/Transforms/InferFunctionAttrs/annotate.ll index eaf9bac..0af1815 100644 --- a/llvm/test/Transforms/InferFunctionAttrs/annotate.ll +++ b/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_WILLRETURN:#[0-9]+]] +; CHECK: declare noalias noundef nonnull i8* @_Znwj(i64) [[INACCESSIBLEMEMONLY_NOFREE_WILLRETURN:#[0-9]+]] declare i8* @_Znwm(i64) -; CHECK: declare noalias noundef nonnull i8* @_Znwm(i64) [[NOFREE_WILLRETURN]] +; CHECK: declare noalias noundef nonnull i8* @_Znwm(i64) [[INACCESSIBLEMEMONLY_NOFREE_WILLRETURN]] declare i32 @__nvvm_reflect(i8*) ; CHECK-NVPTX: declare noundef i32 @__nvvm_reflect(i8* noundef) [[NOFREE_NOUNWIND_READNONE:#[0-9]+]] @@ -184,6 +184,9 @@ declare x86_fp80 @acoshl(x86_fp80) ; CHECK: declare x86_fp80 @acosl(x86_fp80) [[NOFREE_NOUNWIND_WILLRETURN]] 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_NOUNWIND_WILLRETURN]] declare double @asin(double) @@ -253,7 +256,7 @@ declare void @bcopy(i8*, i8*, i64) ; 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_WILLRETURN:#[0-9]+]] +; CHECK: declare noalias noundef i8* @calloc(i64, i64) [[INACCESSIBLEMEMONLY_NOFREE_NOUNWIND_WILLRETURN:#[0-9]+]] declare i8* @calloc(i64, i64) ; CHECK: declare double @cbrt(double) [[NOFREE_NOUNWIND_WILLRETURN]] @@ -550,7 +553,7 @@ declare i64 @labs(i64) ; CHECK: declare noundef i32 @lchown(i8* nocapture noundef readonly, i32 noundef, i32 noundef) [[NOFREE_NOUNWIND]] declare i32 @lchown(i8*, i32, i32) -; CHECK: declare double @ldexp(double, i32 signext) [[NOFREE_WILLRETURN]] +; CHECK: declare double @ldexp(double, i32 signext) [[NOFREE_WILLRETURN:#[0-9]+]] declare double @ldexp(double, i32) ; CHECK: declare float @ldexpf(float, i32 signext) [[NOFREE_WILLRETURN]] @@ -613,10 +616,10 @@ declare i32 @lstat(i8*, %opaque*) ; 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_WILLRETURN]] +; CHECK: declare noalias noundef i8* @malloc(i64) [[INACCESSIBLEMEMONLY_NOFREE_NOUNWIND_WILLRETURN]] declare i8* @malloc(i64) -; CHECK-LINUX: declare noalias i8* @memalign(i64, i64) [[NOFREE_WILLRETURN]] +; CHECK-LINUX: declare noalias noundef i8* @memalign(i64, i64) [[INACCESSIBLEMEMONLY_NOFREE_NOUNWIND_WILLRETURN]] declare i8* @memalign(i64, i64) ; CHECK: declare i8* @memccpy(i8* noalias writeonly, i8* noalias nocapture readonly, i32, i64) [[ARGMEMONLY_NOFREE_NOUNWIND:#[0-9]+]] @@ -856,7 +859,7 @@ declare i8* @strcpy(i8*, i8*) ; CHECK: declare i64 @strcspn(i8* nocapture, i8* nocapture) [[ARGMEMONLY_NOFREE_NOUNWIND_READONLY]] declare i64 @strcspn(i8*, i8*) -; CHECK: declare noalias i8* @strdup(i8* nocapture readonly) [[NOFREE_NOUNWIND_WILLRETURN]] +; CHECK: declare noalias i8* @strdup(i8* nocapture readonly) [[INACCESSIBLEMEMORARGONLY_NOFREE_NOUNWIND_WILLRETURN:#[0-9]+]] declare i8* @strdup(i8*) ; CHECK: declare i64 @strlen(i8* nocapture) [[ARGMEMONLY_NOFREE_NOUNWIND_READONLY]] @@ -874,7 +877,7 @@ declare i32 @strncmp(i8*, i8*, i64) ; CHECK: declare i8* @strncpy(i8* noalias returned writeonly, i8* noalias nocapture readonly, i64) [[ARGMEMONLY_NOFREE_NOUNWIND]] declare i8* @strncpy(i8*, i8*, i64) -; CHECK: declare noalias i8* @strndup(i8* nocapture readonly, i64) [[NOFREE_NOUNWIND_WILLRETURN]] +; CHECK: declare noalias i8* @strndup(i8* nocapture readonly, i64) [[INACCESSIBLEMEMORARGONLY_NOFREE_NOUNWIND_WILLRETURN]] declare i8* @strndup(i8*, i64) ; CHECK: declare i64 @strnlen(i8*, i64) [[NOFREE_NOUNWIND_WILLRETURN]] @@ -982,7 +985,7 @@ declare i32 @utime(i8*, %opaque*) ; 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_WILLRETURN]] declare i8* @valloc(i64) ; CHECK: declare noundef i32 @vfprintf(%opaque* nocapture noundef, i8* nocapture noundef readonly, %opaque* noundef) [[NOFREE_NOUNWIND]] @@ -1014,23 +1017,31 @@ declare i64 @write(i32, i8*, i64) ; 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-DAG: attributes [[NOFREE_WILLRETURN]] = { nofree willreturn } -; CHECK-DAG: attributes [[NOFREE]] = { nofree } -; CHECK-DAG: attributes [[NOFREE_NOUNWIND_WILLRETURN]] = { nofree nounwind willreturn } -; CHECK-DAG: attributes [[ARGMEMONLY_NOFREE_NOUNWIND_WILLRETURN]] = { argmemonly nofree nounwind willreturn } -; CHECK-DAG: attributes [[NOFREE_NOUNWIND_READONLY]] = { nofree nounwind readonly } -; CHECK-DAG: attributes [[NOFREE_NOUNWIND_READONLY_WILLRETURN]] = { nofree nounwind readonly willreturn } - -; CHECK-DAG-UNKNOWN: attributes [[ARGMEMONLY_NOFREE_NOUNWIND]] = { argmemonly nofree nounwind } -; CHECK-DAG-UNKNOWN: attributes [[NOUNWIND]] = { nounwind } -; CHECK-DAG-UNKNOWN: attributes [[ARGMEMONLY_NOFREE_NOUNWIND_READONLY]] = { argmemonly 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-UNKNOWN: attributes [[INACCESSIBLEMEMONLY_NOFREE_WILLRETURN]] = { inaccessiblememonly nofree willreturn } +; CHECK-DAG-UNKNOWN: attributes [[NOFREE_NOUNWIND_WILLRETURN]] = { nofree nounwind willreturn } +; CHECK-DAG-UNKNOWN: attributes [[NOFREE_NOUNWIND]] = { nofree nounwind } +; CHECK-DAG-UNKNOWN: attributes [[INACCESSIBLEMEMONLY_NOFREE_NOUNWIND_WILLRETURN]] = { inaccessiblememonly nofree nounwind willreturn } +; CHECK-DAG-UNKNOWN: attributes [[NOFREE_NOUNWIND_READONLY_WILLRETURN]] = { nofree nounwind readonly willreturn } +; CHECK-DAG-UNKNOWN: attributes [[NOFREE_NOUNWIND_READONLY_WILLRETURN]] = { argmemonly nofree nounwind willreturn } +; CHECK-DAG-UNKNOWN: attributes [[NOFREE_NOUNWIND_READONLY]] = { nofree nounwind readonly } +; CHECK-DAG-UNKNOWN: attributes [[INACCESSIBLEMEMORARGONLY_NOUNWIND_WILLRETURN]] = { inaccessiblemem_or_argmemonly nounwind willreturn } +; CHECK-DAG-UNKNOWN: attributes [[NOFREE_WILLRETURN]] = { nofree willreturn } +; CHECK-DAG-UNKNOWN: attributes [[ARGMEMONLY_NOFREE_NOUNWIND_READONLY_WILLRETURN]] = { argmemonly nofree nounwind readonly willreturn } +; CHECK-DAG-UNKNOWN: attributes [[NOFREE]] = { nofree } +; CHECK-DAG-UNKNOWN: attributes [[WILLRETURN]]= { willreturn } +; CHECK-DAG-UNKNOWN: attributes [[INACCESSIBLEMEMORARGONLY_NOFREE_NOUNWIND_WILLRETURN]] = { inaccessiblemem_or_argmemonly nofree nounwind willreturn } + +; CHECK-DAG-LINUX: attributes [[INACCESSIBLEMEMONLY_NOFREE_WILLRETURN]] = { inaccessiblememonly nofree willreturn } +; CHECK-DAG-LINUX: attributes [[NOFREE]] = { nofree } +; CHECK-DAG-LINUX: attributes [[NOFREE_NOUNWIND_WILLRETURN]] = { nofree nounwind willreturn } +; CHECK-DAG-LINUX: attributes [[NOFREE_NOUNWIND]] = { nofree nounwind } +; CHECK-DAG-LINUX: attributes [[INACCESSIBLEMEMONLY_NOFREE_NOUNWIND_WILLRETURN]] = { inaccessiblememonly nofree nounwind willreturn } +; CHECK-DAG-LINUX: attributes [[NOFREE_NOUNWIND_READONLY_WILLRETURN]] = { nofree nounwind readonly willreturn } +; CHECK-DAG-LINUX: attributes [[ARGMEMONLY_NOFREE_NOUNWIND_READONLY_WILLRETURN]] = { argmemonly nofree nounwind readonly willreturn } +; CHECK-DAG-LINUX: attributes [[NOFREE_NOUNWIND_READONLY_WILLRETURN]] = { argmemonly nofree nounwind willreturn } +; CHECK-DAG-LINUX: attributes [[NOFREE_NOUNWIND_READONLY]] = { nofree nounwind readonly } +; CHECK-DAG-LINUX: attributes [[INACCESSIBLEMEMORARGONLY_NOUNWIND_WILLRETURN]] = { inaccessiblemem_or_argmemonly nounwind willreturn } +; CHECK-DAG-LINUX: attributes [[NOFREE_WILLRETURN]] = { nofree willreturn } +; CHECK-DAG-LINUX: attributes [[WILLRETURN]]= { willreturn } +; CHECK-DAG-LINUX: attributes [[INACCESSIBLEMEMORARGONLY_NOFREE_NOUNWIND_WILLRETURN]] = { inaccessiblemem_or_argmemonly nofree nounwind willreturn } +; CHECK-DAG-LINUX: attributes [[ARGMEMONLY_NOFREE_NOUNWIND]] = { inaccessiblememonly nofree nounwind } -- 2.7.4