diff --git a/llvm/lib/Transforms/Utils/BuildLibCalls.cpp b/llvm/lib/Transforms/Utils/BuildLibCalls.cpp --- a/llvm/lib/Transforms/Utils/BuildLibCalls.cpp +++ b/llvm/lib/Transforms/Utils/BuildLibCalls.cpp @@ -105,14 +105,18 @@ return true; } -static bool setRetAndArgsNoUndef(Function &F) { - bool Changed = false; +static bool setRetNoUndef(Function &F) { if (!F.getReturnType()->isVoidTy() && !F.hasAttribute(AttributeList::ReturnIndex, Attribute::NoUndef)) { F.addAttribute(AttributeList::ReturnIndex, Attribute::NoUndef); ++NumNoUndef; - Changed = true; + return true; } + return false; +} + +static bool setArgsNoUndef(Function &F) { + bool Changed = false; for (unsigned ArgNo = 0; ArgNo < F.arg_size(); ++ArgNo) { if (!F.hasParamAttribute(ArgNo, Attribute::NoUndef)) { F.addParamAttr(ArgNo, Attribute::NoUndef); @@ -123,6 +127,10 @@ return Changed; } +static bool setRetAndArgsNoUndef(Function &F) { + return setRetNoUndef(F) | setArgsNoUndef(F); +} + static bool setRetNonNull(Function &F) { assert(F.getReturnType()->isPointerTy() && "nonnull applies only to pointers"); @@ -318,6 +326,7 @@ Changed |= setOnlyReadsMemory(F, 0); return Changed; case LibFunc_malloc: + Changed |= setRetNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setRetDoesNotAlias(F); return Changed; @@ -383,10 +392,14 @@ Changed |= setDoesNotCapture(F, 0); return Changed; case LibFunc_realloc: + Changed |= setRetNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setRetDoesNotAlias(F); Changed |= setDoesNotCapture(F, 0); return Changed; + case LibFunc_reallocf: + Changed |= setRetNoUndef(F); + return Changed; case LibFunc_read: // May throw; "read" is a valid pthread cancellation point. Changed |= setRetAndArgsNoUndef(F); @@ -427,6 +440,7 @@ Changed |= setOnlyReadsMemory(F, 1); return Changed; case LibFunc_aligned_alloc: + Changed |= setRetNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setRetDoesNotAlias(F); return Changed; @@ -448,6 +462,7 @@ Changed |= setDoesNotCapture(F, 0); return Changed; case LibFunc_calloc: + Changed |= setRetNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setRetDoesNotAlias(F); return Changed; @@ -501,6 +516,7 @@ Changed |= setDoesNotCapture(F, 0); return Changed; case LibFunc_free: + Changed |= setArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); return Changed; @@ -723,6 +739,7 @@ Changed |= setOnlyReadsMemory(F, 1); return Changed; case LibFunc_valloc: + Changed |= setRetNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setRetDoesNotAlias(F); return Changed; @@ -891,6 +908,7 @@ case LibFunc_msvc_new_array_int: // new[](unsigned int) case LibFunc_msvc_new_array_longlong: // new[](unsigned long long) // Operator new always returns a nonnull noalias pointer + Changed |= setRetNoUndef(F); Changed |= setRetNonNull(F); Changed |= setRetDoesNotAlias(F); return Changed; diff --git a/llvm/test/Transforms/InferFunctionAttrs/annotate.ll b/llvm/test/Transforms/InferFunctionAttrs/annotate.ll --- 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 nonnull i8* @_Znwj(i64) [[G0:#[0-9]+]] +; CHECK: declare noalias noundef nonnull i8* @_Znwj(i64) [[G0:#[0-9]+]] declare i8* @_Znwm(i64) -; CHECK: declare noalias nonnull i8* @_Znwm(i64) [[G0]] +; CHECK: declare noalias noundef nonnull i8* @_Znwm(i64) [[G0]] declare i32 @__nvvm_reflect(i8*) ; CHECK-NVPTX: declare noundef i32 @__nvvm_reflect(i8* noundef) [[G0:#[0-9]+]] @@ -253,7 +253,7 @@ ; CHECK: declare void @bzero(i8* nocapture, i64) [[G1]] declare void @bzero(i8*, i64) -; CHECK: declare noalias i8* @calloc(i64, i64) [[G1]] +; CHECK: declare noalias noundef i8* @calloc(i64, i64) [[G1]] declare i8* @calloc(i64, i64) ; CHECK: declare double @cbrt(double) [[G0]] @@ -451,7 +451,7 @@ ; CHECK: declare noundef i64 @fread(i8* nocapture noundef, i64 noundef, i64 noundef, %opaque* nocapture noundef) [[G1]] declare i64 @fread(i8*, i64, i64, %opaque*) -; CHECK: declare void @free(i8* nocapture) [[G3:#[0-9]+]] +; CHECK: declare void @free(i8* nocapture noundef) [[G3:#[0-9]+]] declare void @free(i8*) ; CHECK: declare double @frexp(double, i32* nocapture) [[G1]] @@ -613,7 +613,7 @@ ; CHECK-LINUX: declare noundef i32 @lstat64(i8* nocapture noundef readonly, %opaque* nocapture noundef) [[G1]] declare i32 @lstat64(i8*, %opaque*) -; CHECK: declare noalias i8* @malloc(i64) [[G1]] +; CHECK: declare noalias noundef i8* @malloc(i64) [[G1]] declare i8* @malloc(i64) ; CHECK-LINUX: declare noalias i8* @memalign(i64, i64) [[G0]] @@ -726,10 +726,10 @@ ; CHECK: declare noundef i64 @readlink(i8* nocapture noundef readonly, i8* nocapture noundef, i64 noundef) [[G1]] declare i64 @readlink(i8*, i8*, i64) -; CHECK: declare noalias i8* @realloc(i8* nocapture, i64) [[G3]] +; CHECK: declare noalias noundef i8* @realloc(i8* nocapture, i64) [[G3]] declare i8* @realloc(i8*, i64) -; CHECK: declare i8* @reallocf(i8*, i64) +; CHECK: declare noundef i8* @reallocf(i8*, i64) declare i8* @reallocf(i8*, i64) ; CHECK: declare noundef i8* @realpath(i8* nocapture noundef readonly, i8* noundef) [[G1]] @@ -978,7 +978,7 @@ ; CHECK: declare noundef i32 @utimes(i8* nocapture noundef readonly, %opaque* nocapture noundef readonly) [[G1]] declare i32 @utimes(i8*, %opaque*) -; CHECK: declare noalias i8* @valloc(i64) [[G1]] +; CHECK: declare noalias noundef i8* @valloc(i64) [[G1]] declare i8* @valloc(i64) ; CHECK: declare noundef i32 @vfprintf(%opaque* nocapture noundef, i8* nocapture noundef readonly, %opaque* noundef) [[G1]]