[BuildLibCalls] Add noundef to the returned pointers of allocators and argument of...
authorJuneyoung Lee <aqjune@gmail.com>
Sun, 20 Sep 2020 09:08:27 +0000 (18:08 +0900)
committerJuneyoung Lee <aqjune@gmail.com>
Tue, 29 Sep 2020 17:13:48 +0000 (02:13 +0900)
This patch adds noundef to the returned pointers of allocators (malloc, calloc, ...)
and the pointer argument of free.
The returned pointer of allocators cannot be poison or (partially) undef.
Since the pointer that is given to free should precisely have zero offset,
it cannot be poison or (partially) undef too.

For the size arguments of allocators, noundef wasn't attached simply because
I wasn't sure whether attaching it is okay or not.

Reviewed By: jdoerfert

Differential Revision: https://reviews.llvm.org/D87984

llvm/lib/Transforms/Utils/BuildLibCalls.cpp
llvm/test/Transforms/InferFunctionAttrs/annotate.ll

index 64e168d..2a0cdf6 100644 (file)
@@ -105,14 +105,18 @@ static bool setOnlyReadsMemory(Function &F, unsigned ArgNo) {
   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 @@ static bool setRetAndArgsNoUndef(Function &F) {
   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 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) {
     Changed |= setOnlyReadsMemory(F, 0);
     return Changed;
   case LibFunc_malloc:
+    Changed |= setRetNoUndef(F);
     Changed |= setDoesNotThrow(F);
     Changed |= setRetDoesNotAlias(F);
     return Changed;
@@ -383,10 +392,14 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) {
     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 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) {
     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 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) {
     Changed |= setDoesNotCapture(F, 0);
     return Changed;
   case LibFunc_calloc:
+    Changed |= setRetNoUndef(F);
     Changed |= setDoesNotThrow(F);
     Changed |= setRetDoesNotAlias(F);
     return Changed;
@@ -501,6 +516,7 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) {
     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 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) {
     Changed |= setOnlyReadsMemory(F, 1);
     return Changed;
   case LibFunc_valloc:
+    Changed |= setRetNoUndef(F);
     Changed |= setDoesNotThrow(F);
     Changed |= setRetDoesNotAlias(F);
     return Changed;
@@ -891,6 +908,7 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) {
   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;
index d4b0f0f..c374e90 100644 (file)
@@ -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 @@ declare void @bcopy(i8*, i8*, i64)
 ; 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 @@ declare i32 @fputs(i8*, %opaque*)
 ; 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 @@ declare i32 @lstat(i8*, %opaque*)
 ; 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 @@ declare i64 @read(i32, i8*, i64)
 ; 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 @@ declare i32 @utime(i8*, %opaque*)
 ; 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]]