Index: lib/Transforms/Utils/BuildLibCalls.cpp =================================================================== --- lib/Transforms/Utils/BuildLibCalls.cpp +++ lib/Transforms/Utils/BuildLibCalls.cpp @@ -37,7 +37,8 @@ STATISTIC(NumNoCapture, "Number of arguments inferred as nocapture"); STATISTIC(NumReadOnlyArg, "Number of arguments inferred as readonly"); STATISTIC(NumNoAlias, "Number of function returns inferred as noalias"); -STATISTIC(NumNonNull, "Number of function returns inferred as nonnull returns"); +STATISTIC(NumRetNonNull, "Number of function returns inferred as nonnull returns"); +STATISTIC(NumArgNonNull, "Number of function arguments inferred as nonnull"); static bool setDoesNotAccessMemory(Function &F) { if (F.doesNotAccessMemory()) @@ -95,13 +96,21 @@ return true; } +static bool setArgNotNull(Function &F, unsigned ArgNo) { + if (F.hasParamAttribute(ArgNo, Attribute::NonNull)) + return false; + F.addParamAttr(ArgNo, Attribute::NonNull); + ++NumArgNonNull; + return true; +} + static bool setRetNonNull(Function &F) { assert(F.getReturnType()->isPointerTy() && "nonnull applies only to pointers"); if (F.hasAttribute(AttributeList::ReturnIndex, Attribute::NonNull)) return false; F.addAttribute(AttributeList::ReturnIndex, Attribute::NonNull); - ++NumNonNull; + ++NumRetNonNull; return true; } @@ -129,11 +138,13 @@ Changed |= setDoesNotThrow(F); Changed |= setOnlyAccessesArgMemory(F); Changed |= setDoesNotCapture(F, 0); + Changed |= setArgNotNull(F, 0); return Changed; case LibFunc_strchr: case LibFunc_strrchr: Changed |= setOnlyReadsMemory(F); Changed |= setDoesNotThrow(F); + Changed |= setArgNotNull(F, 0); return Changed; case LibFunc_strtol: case LibFunc_strtod: @@ -145,16 +156,24 @@ Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 1); Changed |= setOnlyReadsMemory(F, 0); + Changed |= setArgNotNull(F, 0); return Changed; case LibFunc_strcpy: case LibFunc_stpcpy: case LibFunc_strcat: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 1); + Changed |= setOnlyReadsMemory(F, 1); + Changed |= setArgNotNull(F, 0); + Changed |= setArgNotNull(F, 1); + return Changed; case LibFunc_strncat: case LibFunc_strncpy: case LibFunc_stpncpy: Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 1); Changed |= setOnlyReadsMemory(F, 1); + Changed |= setArgNotNull(F, 0); return Changed; case LibFunc_strxfrm: Changed |= setDoesNotThrow(F); @@ -164,9 +183,21 @@ return Changed; case LibFunc_strcmp: // 0,1 case LibFunc_strspn: // 0,1 - case LibFunc_strncmp: // 0,1 case LibFunc_strcspn: // 0,1 case LibFunc_strcoll: // 0,1 + Changed |= setOnlyReadsMemory(F); + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setDoesNotCapture(F, 1); + Changed |= setArgNotNull(F, 0); + Changed |= setArgNotNull(F, 1); + return Changed; + case LibFunc_strncmp: // 0,1 + Changed |= setOnlyReadsMemory(F); + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setDoesNotCapture(F, 1); + return Changed; case LibFunc_strcasecmp: // 0,1 case LibFunc_strncasecmp: // Changed |= setOnlyReadsMemory(F); @@ -179,24 +210,36 @@ Changed |= setOnlyReadsMemory(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 1); + Changed |= setArgNotNull(F, 0); + Changed |= setArgNotNull(F, 1); return Changed; case LibFunc_strtok: case LibFunc_strtok_r: Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 1); Changed |= setOnlyReadsMemory(F, 1); + Changed |= setArgNotNull(F, 1); return Changed; case LibFunc_scanf: Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setOnlyReadsMemory(F, 0); + Changed |= setArgNotNull(F, 0); return Changed; case LibFunc_setbuf: case LibFunc_setvbuf: Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); + Changed |= setArgNotNull(F, 0); + Changed |= setArgNotNull(F, 1); return Changed; case LibFunc_strdup: + Changed |= setDoesNotThrow(F); + Changed |= setRetDoesNotAlias(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setOnlyReadsMemory(F, 0); + Changed |= setArgNotNull(F, 0); + return Changed; case LibFunc_strndup: Changed |= setDoesNotThrow(F); Changed |= setRetDoesNotAlias(F); @@ -209,6 +252,8 @@ Changed |= setDoesNotCapture(F, 0); Changed |= setDoesNotCapture(F, 1); Changed |= setOnlyReadsMemory(F, 0); + Changed |= setArgNotNull(F, 0); + Changed |= setArgNotNull(F, 1); return Changed; case LibFunc_sscanf: Changed |= setDoesNotThrow(F); @@ -216,18 +261,22 @@ Changed |= setDoesNotCapture(F, 1); Changed |= setOnlyReadsMemory(F, 0); Changed |= setOnlyReadsMemory(F, 1); + Changed |= setArgNotNull(F, 0); + Changed |= setArgNotNull(F, 1); return Changed; case LibFunc_sprintf: Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setDoesNotCapture(F, 1); Changed |= setOnlyReadsMemory(F, 1); + Changed |= setArgNotNull(F, 1); return Changed; case LibFunc_snprintf: Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setDoesNotCapture(F, 2); Changed |= setOnlyReadsMemory(F, 2); + Changed |= setArgNotNull(F, 2); return Changed; case LibFunc_setitimer: Changed |= setDoesNotThrow(F); @@ -239,6 +288,7 @@ // May throw; "system" is a valid pthread cancellation point. Changed |= setDoesNotCapture(F, 0); Changed |= setOnlyReadsMemory(F, 0); + Changed |= setArgNotNull(F, 0); return Changed; case LibFunc_malloc: Changed |= setDoesNotThrow(F); @@ -279,6 +329,7 @@ Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setOnlyReadsMemory(F, 0); + Changed |= setArgNotNull(F, 0); return Changed; case LibFunc_mktime: Changed |= setDoesNotThrow(F); @@ -296,6 +347,7 @@ case LibFunc_rewind: Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); + Changed |= setArgNotNull(F, 0); return Changed; case LibFunc_rmdir: case LibFunc_remove: @@ -303,6 +355,7 @@ Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setOnlyReadsMemory(F, 0); + Changed |= setArgNotNull(F, 0); return Changed; case LibFunc_rename: Changed |= setDoesNotThrow(F); @@ -310,6 +363,8 @@ Changed |= setDoesNotCapture(F, 1); Changed |= setOnlyReadsMemory(F, 0); Changed |= setOnlyReadsMemory(F, 1); + Changed |= setArgNotNull(F, 0); + Changed |= setArgNotNull(F, 1); return Changed; case LibFunc_readlink: Changed |= setDoesNotThrow(F); @@ -347,6 +402,7 @@ Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setOnlyReadsMemory(F, 0); + Changed |= setArgNotNull(F, 0); return Changed; case LibFunc_ctermid: case LibFunc_clearerr: @@ -361,11 +417,13 @@ Changed |= setDoesNotThrow(F); Changed |= setOnlyReadsMemory(F); Changed |= setDoesNotCapture(F, 0); + Changed |= setArgNotNull(F, 0); return Changed; case LibFunc_access: Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setOnlyReadsMemory(F, 0); + Changed |= setArgNotNull(F, 0); return Changed; case LibFunc_fopen: Changed |= setDoesNotThrow(F); @@ -374,15 +432,21 @@ Changed |= setDoesNotCapture(F, 1); Changed |= setOnlyReadsMemory(F, 0); Changed |= setOnlyReadsMemory(F, 1); + Changed |= setArgNotNull(F, 0); + Changed |= setArgNotNull(F, 1); return Changed; case LibFunc_fdopen: Changed |= setDoesNotThrow(F); Changed |= setRetDoesNotAlias(F); Changed |= setDoesNotCapture(F, 1); Changed |= setOnlyReadsMemory(F, 1); + Changed |= setArgNotNull(F, 1); return Changed; - case LibFunc_feof: case LibFunc_free: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + return Changed; + case LibFunc_feof: case LibFunc_fseek: case LibFunc_ftell: case LibFunc_fgetc: @@ -398,14 +462,20 @@ case LibFunc_ftrylockfile: Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); + Changed |= setArgNotNull(F, 0); return Changed; case LibFunc_ferror: Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setOnlyReadsMemory(F); + Changed |= setArgNotNull(F, 0); return Changed; case LibFunc_fputc: case LibFunc_fputc_unlocked: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 1); + Changed |= setArgNotNull(F, 1); + return Changed; case LibFunc_fstat: case LibFunc_frexp: case LibFunc_frexpf: @@ -418,18 +488,24 @@ case LibFunc_fgets_unlocked: Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 2); + Changed |= setArgNotNull(F, 0); + Changed |= setArgNotNull(F, 2); return Changed; case LibFunc_fread: case LibFunc_fread_unlocked: Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setDoesNotCapture(F, 3); + Changed |= setArgNotNull(F, 0); + Changed |= setArgNotNull(F, 3); return Changed; case LibFunc_fwrite: case LibFunc_fwrite_unlocked: Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setDoesNotCapture(F, 3); + Changed |= setArgNotNull(F, 0); + Changed |= setArgNotNull(F, 3); // FIXME: readonly #1? return Changed; case LibFunc_fputs: @@ -438,6 +514,8 @@ Changed |= setDoesNotCapture(F, 0); Changed |= setDoesNotCapture(F, 1); Changed |= setOnlyReadsMemory(F, 0); + Changed |= setArgNotNull(F, 0); + Changed |= setArgNotNull(F, 1); return Changed; case LibFunc_fscanf: case LibFunc_fprintf: @@ -445,24 +523,33 @@ Changed |= setDoesNotCapture(F, 0); Changed |= setDoesNotCapture(F, 1); Changed |= setOnlyReadsMemory(F, 1); + Changed |= setArgNotNull(F, 0); + Changed |= setArgNotNull(F, 1); return Changed; case LibFunc_fgetpos: Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setDoesNotCapture(F, 1); + Changed |= setArgNotNull(F, 0); + Changed |= setArgNotNull(F, 1); return Changed; case LibFunc_getc: case LibFunc_getlogin_r: case LibFunc_getc_unlocked: Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); + Changed |= setArgNotNull(F, 0); return Changed; case LibFunc_getenv: Changed |= setDoesNotThrow(F); Changed |= setOnlyReadsMemory(F); Changed |= setDoesNotCapture(F, 0); + Changed |= setArgNotNull(F, 0); return Changed; case LibFunc_gets: + Changed |= setDoesNotThrow(F); + Changed |= setArgNotNull(F, 0); + return Changed; case LibFunc_getchar: case LibFunc_getchar_unlocked: Changed |= setDoesNotThrow(F); @@ -506,6 +593,7 @@ case LibFunc_putc_unlocked: Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 1); + Changed |= setArgNotNull(F, 1); return Changed; case LibFunc_puts: case LibFunc_printf: @@ -513,6 +601,7 @@ Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setOnlyReadsMemory(F, 0); + Changed |= setArgNotNull(F, 0); return Changed; case LibFunc_pread: // May throw; "pread" is a valid pthread cancellation point. @@ -534,10 +623,12 @@ Changed |= setDoesNotCapture(F, 1); Changed |= setOnlyReadsMemory(F, 0); Changed |= setOnlyReadsMemory(F, 1); + Changed |= setArgNotNull(F, 0); return Changed; case LibFunc_pclose: Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); + Changed |= setArgNotNull(F, 0); return Changed; case LibFunc_vscanf: Changed |= setDoesNotThrow(F); @@ -621,6 +712,12 @@ Changed |= setDoesNotCapture(F, 3); return Changed; case LibFunc_dunder_strdup: + Changed |= setDoesNotThrow(F); + Changed |= setRetDoesNotAlias(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setOnlyReadsMemory(F, 0); + Changed |= setArgNotNull(F, 0); + return Changed; case LibFunc_dunder_strndup: Changed |= setDoesNotThrow(F); Changed |= setRetDoesNotAlias(F); @@ -631,19 +728,23 @@ Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 1); Changed |= setOnlyReadsMemory(F, 1); + Changed |= setArgNotNull(F, 1); return Changed; case LibFunc_under_IO_getc: Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); + Changed |= setArgNotNull(F, 0); return Changed; case LibFunc_under_IO_putc: Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 1); + Changed |= setArgNotNull(F, 1); return Changed; case LibFunc_dunder_isoc99_scanf: Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setOnlyReadsMemory(F, 0); + Changed |= setArgNotNull(F, 0); return Changed; case LibFunc_stat64: case LibFunc_lstat64: @@ -659,6 +760,8 @@ Changed |= setDoesNotCapture(F, 1); Changed |= setOnlyReadsMemory(F, 0); Changed |= setOnlyReadsMemory(F, 1); + Changed |= setArgNotNull(F, 0); + Changed |= setArgNotNull(F, 1); return Changed; case LibFunc_fopen64: Changed |= setDoesNotThrow(F); @@ -667,11 +770,14 @@ Changed |= setDoesNotCapture(F, 1); Changed |= setOnlyReadsMemory(F, 0); Changed |= setOnlyReadsMemory(F, 1); + Changed |= setArgNotNull(F, 0); + Changed |= setArgNotNull(F, 1); return Changed; case LibFunc_fseeko64: case LibFunc_ftello64: Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); + Changed |= setArgNotNull(F, 0); return Changed; case LibFunc_tmpfile64: Changed |= setDoesNotThrow(F); Index: test/CodeGen/X86/no-plt-libcalls.ll =================================================================== --- test/CodeGen/X86/no-plt-libcalls.ll +++ test/CodeGen/X86/no-plt-libcalls.ll @@ -13,7 +13,7 @@ } ; CHECK: Function Attrs: nounwind nonlazybind -; CHECK-NEXT: declare i32 @puts(i8* nocapture readonly) +; CHECK-NEXT: declare i32 @puts(i8* nocapture nonnull readonly) !llvm.module.flags = !{!0} !0 = !{i32 7, !"RtLibUseGOT", i32 1} Index: test/Transforms/InferFunctionAttrs/annotate.ll =================================================================== --- test/Transforms/InferFunctionAttrs/annotate.ll +++ test/Transforms/InferFunctionAttrs/annotate.ll @@ -1,3 +1,4 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt < %s -mtriple=x86_64-- -inferattrs -S | FileCheck %s ; RUN: opt < %s -mtriple=x86_64-- -passes=inferattrs -S | FileCheck %s ; RUN: opt < %s -mtriple=x86_64-apple-macosx10.8.0 -inferattrs -S | FileCheck -check-prefix=CHECK -check-prefix=CHECK-DARWIN %s @@ -163,7 +164,7 @@ ; CHECK: declare i32 @abs(i32) declare i32 @abs(i32) -; CHECK: declare i32 @access(i8* nocapture readonly, i32) [[G0:#[0-9]+]] +; CHECK: declare i32 @access(i8* nocapture nonnull readonly, i32) [[G0:#[0-9]+]] declare i32 @access(i8*, i32) ; CHECK: declare double @acos(double) @@ -229,16 +230,16 @@ ; CHECK: declare x86_fp80 @atanl(x86_fp80) declare x86_fp80 @atanl(x86_fp80) -; CHECK: declare double @atof(i8* nocapture) [[G1:#[0-9]+]] +; CHECK: declare double @atof(i8* nocapture nonnull) [[G1:#[0-9]+]] declare double @atof(i8*) -; CHECK: declare i32 @atoi(i8* nocapture) [[G1]] +; CHECK: declare i32 @atoi(i8* nocapture nonnull) [[G1]] declare i32 @atoi(i8*) -; CHECK: declare i64 @atol(i8* nocapture) [[G1]] +; CHECK: declare i64 @atol(i8* nocapture nonnull) [[G1]] declare i64 @atol(i8*) -; CHECK: declare i64 @atoll(i8* nocapture) [[G1]] +; CHECK: declare i64 @atoll(i8* nocapture nonnull) [[G1]] declare i64 @atoll(i8*) ; CHECK: declare i32 @bcmp(i8* nocapture, i8* nocapture, i64) [[G1]] @@ -271,10 +272,10 @@ ; CHECK: declare x86_fp80 @ceill(x86_fp80) declare x86_fp80 @ceill(x86_fp80) -; CHECK: declare i32 @chmod(i8* nocapture readonly, i16 zeroext) [[G0]] +; CHECK: declare i32 @chmod(i8* nocapture nonnull readonly, i16 zeroext) [[G0]] declare i32 @chmod(i8*, i16 zeroext) -; CHECK: declare i32 @chown(i8* nocapture readonly, i32, i32) [[G0]] +; CHECK: declare i32 @chown(i8* nocapture nonnull readonly, i32, i32) [[G0]] declare i32 @chown(i8*, i32, i32) ; CHECK: declare void @clearerr(%opaque* nocapture) [[G0]] @@ -349,19 +350,19 @@ ; CHECK: declare x86_fp80 @fabsl(x86_fp80) declare x86_fp80 @fabsl(x86_fp80) -; CHECK: declare i32 @fclose(%opaque* nocapture) [[G0]] +; CHECK: declare i32 @fclose(%opaque* nocapture nonnull) [[G0]] declare i32 @fclose(%opaque*) -; CHECK: declare noalias %opaque* @fdopen(i32, i8* nocapture readonly) [[G0]] +; CHECK: declare noalias %opaque* @fdopen(i32, i8* nocapture nonnull readonly) [[G0]] declare %opaque* @fdopen(i32, i8*) -; CHECK: declare i32 @feof(%opaque* nocapture) [[G0]] +; CHECK: declare i32 @feof(%opaque* nocapture nonnull) [[G0]] declare i32 @feof(%opaque*) -; CHECK: declare i32 @ferror(%opaque* nocapture) [[G1]] +; CHECK: declare i32 @ferror(%opaque* nocapture nonnull) [[G1]] declare i32 @ferror(%opaque*) -; CHECK: declare i32 @fflush(%opaque* nocapture) [[G0]] +; CHECK: declare i32 @fflush(%opaque* nocapture nonnull) [[G0]] declare i32 @fflush(%opaque*) ; CHECK: declare i32 @ffs(i32) @@ -373,19 +374,19 @@ ; CHECK: declare i32 @ffsll(i64) declare i32 @ffsll(i64) -; CHECK: declare i32 @fgetc(%opaque* nocapture) [[G0]] +; CHECK: declare i32 @fgetc(%opaque* nocapture nonnull) [[G0]] declare i32 @fgetc(%opaque*) -; CHECK: declare i32 @fgetpos(%opaque* nocapture, i64* nocapture) [[G0]] +; CHECK: declare i32 @fgetpos(%opaque* nocapture nonnull, i64* nocapture nonnull) [[G0]] declare i32 @fgetpos(%opaque*, i64*) -; CHECK: declare i8* @fgets(i8*, i32, %opaque* nocapture) [[G0]] +; CHECK: declare i8* @fgets(i8* nonnull, i32, %opaque* nocapture nonnull) [[G0]] declare i8* @fgets(i8*, i32, %opaque*) -; CHECK: declare i32 @fileno(%opaque* nocapture) [[G0]] +; CHECK: declare i32 @fileno(%opaque* nocapture nonnull) [[G0]] declare i32 @fileno(%opaque*) -; CHECK: declare void @flockfile(%opaque* nocapture) [[G0]] +; CHECK: declare void @flockfile(%opaque* nocapture nonnull) [[G0]] declare void @flockfile(%opaque*) ; CHECK: declare double @floor(double) @@ -433,19 +434,19 @@ ; CHECK: declare x86_fp80 @fmodl(x86_fp80, x86_fp80) declare x86_fp80 @fmodl(x86_fp80, x86_fp80) -; CHECK: declare noalias %opaque* @fopen(i8* nocapture readonly, i8* nocapture readonly) [[G0]] +; CHECK: declare noalias %opaque* @fopen(i8* nocapture nonnull readonly, i8* nocapture nonnull readonly) [[G0]] declare %opaque* @fopen(i8*, i8*) -; CHECK: declare i32 @fprintf(%opaque* nocapture, i8* nocapture readonly, ...) [[G0]] +; CHECK: declare i32 @fprintf(%opaque* nocapture nonnull, i8* nocapture nonnull readonly, ...) [[G0]] declare i32 @fprintf(%opaque*, i8*, ...) -; CHECK: declare i32 @fputc(i32, %opaque* nocapture) [[G0]] +; CHECK: declare i32 @fputc(i32, %opaque* nocapture nonnull) [[G0]] declare i32 @fputc(i32, %opaque*) -; CHECK: declare i32 @fputs(i8* nocapture readonly, %opaque* nocapture) [[G0]] +; CHECK: declare i32 @fputs(i8* nocapture nonnull readonly, %opaque* nocapture nonnull) [[G0]] declare i32 @fputs(i8*, %opaque*) -; CHECK: declare i64 @fread(i8* nocapture, i64, i64, %opaque* nocapture) [[G0]] +; CHECK: declare i64 @fread(i8* nocapture nonnull, i64, i64, %opaque* nocapture nonnull) [[G0]] declare i64 @fread(i8*, i64, i64, %opaque*) ; CHECK: declare void @free(i8* nocapture) [[G0]] @@ -460,19 +461,19 @@ ; CHECK: declare x86_fp80 @frexpl(x86_fp80, i32* nocapture) [[G0]] declare x86_fp80 @frexpl(x86_fp80, i32*) -; CHECK: declare i32 @fscanf(%opaque* nocapture, i8* nocapture readonly, ...) [[G0]] +; CHECK: declare i32 @fscanf(%opaque* nocapture nonnull, i8* nocapture nonnull readonly, ...) [[G0]] declare i32 @fscanf(%opaque*, i8*, ...) -; CHECK: declare i32 @fseek(%opaque* nocapture, i64, i32) [[G0]] +; CHECK: declare i32 @fseek(%opaque* nocapture nonnull, i64, i32) [[G0]] declare i32 @fseek(%opaque*, i64, i32) -; CHECK: declare i32 @fseeko(%opaque* nocapture, i64, i32) [[G0]] +; CHECK: declare i32 @fseeko(%opaque* nocapture nonnull, i64, i32) [[G0]] declare i32 @fseeko(%opaque*, i64, i32) -; CHECK-LINUX: declare i32 @fseeko64(%opaque* nocapture, i64, i32) [[G0]] +; CHECK-LINUX: declare i32 @fseeko64(%opaque* nocapture nonnull, i64, i32) [[G0]] declare i32 @fseeko64(%opaque*, i64, i32) -; CHECK: declare i32 @fsetpos(%opaque* nocapture, i64*) [[G0]] +; CHECK: declare i32 @fsetpos(%opaque* nocapture nonnull, i64*) [[G0]] declare i32 @fsetpos(%opaque*, i64*) ; CHECK: declare i32 @fstat(i32, %opaque* nocapture) [[G0]] @@ -487,28 +488,28 @@ ; CHECK-LINUX: declare i32 @fstatvfs64(i32, %opaque* nocapture) [[G0]] declare i32 @fstatvfs64(i32, %opaque*) -; CHECK: declare i64 @ftell(%opaque* nocapture) [[G0]] +; CHECK: declare i64 @ftell(%opaque* nocapture nonnull) [[G0]] declare i64 @ftell(%opaque*) -; CHECK: declare i64 @ftello(%opaque* nocapture) [[G0]] +; CHECK: declare i64 @ftello(%opaque* nocapture nonnull) [[G0]] declare i64 @ftello(%opaque*) -; CHECK-LINUX: declare i64 @ftello64(%opaque* nocapture) [[G0]] +; CHECK-LINUX: declare i64 @ftello64(%opaque* nocapture nonnull) [[G0]] declare i64 @ftello64(%opaque*) -; CHECK: declare i32 @ftrylockfile(%opaque* nocapture) [[G0]] +; CHECK: declare i32 @ftrylockfile(%opaque* nocapture nonnull) [[G0]] declare i32 @ftrylockfile(%opaque*) -; CHECK: declare void @funlockfile(%opaque* nocapture) [[G0]] +; CHECK: declare void @funlockfile(%opaque* nocapture nonnull) [[G0]] declare void @funlockfile(%opaque*) -; CHECK: declare i64 @fwrite(i8* nocapture, i64, i64, %opaque* nocapture) [[G0]] +; CHECK: declare i64 @fwrite(i8* nocapture nonnull, i64, i64, %opaque* nocapture nonnull) [[G0]] declare i64 @fwrite(i8*, i64, i64, %opaque*) -; CHECK: declare i32 @getc(%opaque* nocapture) [[G0]] +; CHECK: declare i32 @getc(%opaque* nocapture nonnull) [[G0]] declare i32 @getc(%opaque*) -; CHECK: declare i32 @getc_unlocked(%opaque* nocapture) [[G0]] +; CHECK: declare i32 @getc_unlocked(%opaque* nocapture nonnull) [[G0]] declare i32 @getc_unlocked(%opaque*) ; CHECK: declare i32 @getchar() @@ -517,19 +518,19 @@ ; CHECK: declare i32 @getchar_unlocked() declare i32 @getchar_unlocked() -; CHECK: declare i8* @getenv(i8* nocapture) [[G1]] +; CHECK: declare i8* @getenv(i8* nocapture nonnull) [[G1]] declare i8* @getenv(i8*) ; CHECK: declare i32 @getitimer(i32, %opaque* nocapture) [[G0]] declare i32 @getitimer(i32, %opaque*) -; CHECK: declare i32 @getlogin_r(i8* nocapture, i64) [[G0]] +; CHECK: declare i32 @getlogin_r(i8* nocapture nonnull, i64) [[G0]] declare i32 @getlogin_r(i8*, i64) ; CHECK: declare %opaque* @getpwnam(i8* nocapture readonly) [[G0]] declare %opaque* @getpwnam(i8*) -; CHECK: declare i8* @gets(i8*) +; CHECK: declare i8* @gets(i8* nonnull) declare i8* @gets(i8*) ; CHECK: declare i32 @gettimeofday(%opaque* nocapture, i8* nocapture) [[G0]] @@ -637,7 +638,7 @@ ; CHECK: declare i8* @memset(i8*, i32, i64) declare i8* @memset(i8*, i32, i64) -; CHECK: declare i32 @mkdir(i8* nocapture readonly, i16 zeroext) [[G0]] +; CHECK: declare i32 @mkdir(i8* nocapture nonnull readonly, i16 zeroext) [[G0]] declare i32 @mkdir(i8*, i16 zeroext) ; CHECK: declare i64 @mktime(%opaque* nocapture) [[G0]] @@ -670,13 +671,13 @@ ; CHECK: declare noalias %opaque* @opendir(i8* nocapture readonly) [[G0]] declare %opaque* @opendir(i8*) -; CHECK: declare i32 @pclose(%opaque* nocapture) [[G0]] +; CHECK: declare i32 @pclose(%opaque* nocapture nonnull) [[G0]] declare i32 @pclose(%opaque*) -; CHECK: declare void @perror(i8* nocapture readonly) [[G0]] +; CHECK: declare void @perror(i8* nocapture nonnull readonly) [[G0]] declare void @perror(i8*) -; CHECK: declare noalias %opaque* @popen(i8* nocapture readonly, i8* nocapture readonly) [[G0]] +; CHECK: declare noalias %opaque* @popen(i8* nocapture nonnull readonly, i8* nocapture readonly) [[G0]] declare %opaque* @popen(i8*, i8*) ; CHECK: declare i32 @posix_memalign(i8**, i64, i64) @@ -694,10 +695,10 @@ ; CHECK: declare i64 @pread(i32, i8* nocapture, i64, i64) declare i64 @pread(i32, i8*, i64, i64) -; CHECK: declare i32 @printf(i8* nocapture readonly, ...) [[G0]] +; CHECK: declare i32 @printf(i8* nocapture nonnull readonly, ...) [[G0]] declare i32 @printf(i8*, ...) -; CHECK: declare i32 @putc(i32, %opaque* nocapture) [[G0]] +; CHECK: declare i32 @putc(i32, %opaque* nocapture nonnull) [[G0]] declare i32 @putc(i32, %opaque*) ; CHECK: declare i32 @putchar(i32) @@ -706,7 +707,7 @@ ; CHECK: declare i32 @putchar_unlocked(i32) declare i32 @putchar_unlocked(i32) -; CHECK: declare i32 @puts(i8* nocapture readonly) [[G0]] +; CHECK: declare i32 @puts(i8* nocapture nonnull readonly) [[G0]] declare i32 @puts(i8*) ; CHECK: declare i64 @pwrite(i32, i8* nocapture readonly, i64, i64) @@ -727,16 +728,16 @@ ; CHECK: declare i8* @reallocf(i8*, i64) declare i8* @reallocf(i8*, i64) -; CHECK: declare i8* @realpath(i8* nocapture readonly, i8*) +; CHECK: declare i8* @realpath(i8* nocapture nonnull readonly, i8*) declare i8* @realpath(i8*, i8*) -; CHECK: declare i32 @remove(i8* nocapture readonly) [[G0]] +; CHECK: declare i32 @remove(i8* nocapture nonnull readonly) [[G0]] declare i32 @remove(i8*) -; CHECK: declare i32 @rename(i8* nocapture readonly, i8* nocapture readonly) [[G0]] +; CHECK: declare i32 @rename(i8* nocapture nonnull readonly, i8* nocapture nonnull readonly) [[G0]] declare i32 @rename(i8*, i8*) -; CHECK: declare void @rewind(%opaque* nocapture) [[G0]] +; CHECK: declare void @rewind(%opaque* nocapture nonnull) [[G0]] declare void @rewind(%opaque*) ; CHECK: declare double @rint(double) @@ -748,7 +749,7 @@ ; CHECK: declare x86_fp80 @rintl(x86_fp80) declare x86_fp80 @rintl(x86_fp80) -; CHECK: declare i32 @rmdir(i8* nocapture readonly) [[G0]] +; CHECK: declare i32 @rmdir(i8* nocapture nonnull readonly) [[G0]] declare i32 @rmdir(i8*) ; CHECK: declare double @round(double) @@ -760,16 +761,16 @@ ; CHECK: declare x86_fp80 @roundl(x86_fp80) declare x86_fp80 @roundl(x86_fp80) -; CHECK: declare i32 @scanf(i8* nocapture readonly, ...) [[G0]] +; CHECK: declare i32 @scanf(i8* nocapture nonnull readonly, ...) [[G0]] declare i32 @scanf(i8*, ...) -; CHECK: declare void @setbuf(%opaque* nocapture, i8*) [[G0]] +; CHECK: declare void @setbuf(%opaque* nocapture nonnull, i8* nonnull) [[G0]] declare void @setbuf(%opaque*, i8*) ; CHECK: declare i32 @setitimer(i32, %opaque* nocapture readonly, %opaque* nocapture) [[G0]] declare i32 @setitimer(i32, %opaque*, %opaque*) -; CHECK: declare i32 @setvbuf(%opaque* nocapture, i8*, i32, i64) [[G0]] +; CHECK: declare i32 @setvbuf(%opaque* nocapture nonnull, i8* nonnull, i32, i64) [[G0]] declare i32 @setvbuf(%opaque*, i8*, i32, i64) ; CHECK: declare double @sin(double) @@ -790,10 +791,10 @@ ; CHECK: declare x86_fp80 @sinl(x86_fp80) declare x86_fp80 @sinl(x86_fp80) -; CHECK: declare i32 @snprintf(i8* nocapture, i64, i8* nocapture readonly, ...) [[G0]] +; CHECK: declare i32 @snprintf(i8* nocapture, i64, i8* nocapture nonnull readonly, ...) [[G0]] declare i32 @snprintf(i8*, i64, i8*, ...) -; CHECK: declare i32 @sprintf(i8* nocapture, i8* nocapture readonly, ...) [[G0]] +; CHECK: declare i32 @sprintf(i8* nocapture, i8* nocapture nonnull readonly, ...) [[G0]] declare i32 @sprintf(i8*, i8*, ...) ; CHECK: declare double @sqrt(double) @@ -805,64 +806,64 @@ ; CHECK: declare x86_fp80 @sqrtl(x86_fp80) declare x86_fp80 @sqrtl(x86_fp80) -; CHECK: declare i32 @sscanf(i8* nocapture readonly, i8* nocapture readonly, ...) [[G0]] +; CHECK: declare i32 @sscanf(i8* nocapture nonnull readonly, i8* nocapture nonnull readonly, ...) [[G0]] declare i32 @sscanf(i8*, i8*, ...) -; CHECK: declare i32 @stat(i8* nocapture readonly, %opaque* nocapture) [[G0]] +; CHECK: declare i32 @stat(i8* nocapture nonnull readonly, %opaque* nocapture nonnull) [[G0]] declare i32 @stat(i8*, %opaque*) ; CHECK-LINUX: declare i32 @stat64(i8* nocapture readonly, %opaque* nocapture) [[G0]] declare i32 @stat64(i8*, %opaque*) -; CHECK: declare i32 @statvfs(i8* nocapture readonly, %opaque* nocapture) [[G0]] +; CHECK: declare i32 @statvfs(i8* nocapture nonnull readonly, %opaque* nocapture nonnull) [[G0]] declare i32 @statvfs(i8*, %opaque*) ; CHECK-LINUX: declare i32 @statvfs64(i8* nocapture readonly, %opaque* nocapture) [[G0]] declare i32 @statvfs64(i8*, %opaque*) -; CHECK: declare i8* @stpcpy(i8*, i8* nocapture readonly) [[G0]] +; CHECK: declare i8* @stpcpy(i8* nonnull, i8* nocapture nonnull readonly) [[G0]] declare i8* @stpcpy(i8*, i8*) -; CHECK: declare i8* @stpncpy(i8*, i8* nocapture readonly, i64) [[G0]] +; CHECK: declare i8* @stpncpy(i8* nonnull, i8* nocapture readonly, i64) [[G0]] declare i8* @stpncpy(i8*, i8*, i64) ; CHECK: declare i32 @strcasecmp(i8* nocapture, i8* nocapture) [[G1]] declare i32 @strcasecmp(i8*, i8*) -; CHECK: declare i8* @strcat(i8*, i8* nocapture readonly) [[G0]] +; CHECK: declare i8* @strcat(i8* nonnull, i8* nocapture nonnull readonly) [[G0]] declare i8* @strcat(i8*, i8*) -; CHECK: declare i8* @strchr(i8*, i32) [[G1]] +; CHECK: declare i8* @strchr(i8* nonnull, i32) [[G1]] declare i8* @strchr(i8*, i32) -; CHECK: declare i32 @strcmp(i8* nocapture, i8* nocapture) [[G1]] +; CHECK: declare i32 @strcmp(i8* nocapture nonnull, i8* nocapture nonnull) [[G1]] declare i32 @strcmp(i8*, i8*) -; CHECK: declare i32 @strcoll(i8* nocapture, i8* nocapture) [[G1]] +; CHECK: declare i32 @strcoll(i8* nocapture nonnull, i8* nocapture nonnull) [[G1]] declare i32 @strcoll(i8*, i8*) -; CHECK: declare i8* @strcpy(i8*, i8* nocapture readonly) [[G0]] +; CHECK: declare i8* @strcpy(i8* nonnull, i8* nocapture nonnull readonly) [[G0]] declare i8* @strcpy(i8*, i8*) -; CHECK: declare i64 @strcspn(i8* nocapture, i8* nocapture) [[G1]] +; CHECK: declare i64 @strcspn(i8* nocapture nonnull, i8* nocapture nonnull) [[G1]] declare i64 @strcspn(i8*, i8*) -; CHECK: declare noalias i8* @strdup(i8* nocapture readonly) [[G0]] +; CHECK: declare noalias i8* @strdup(i8* nocapture nonnull readonly) [[G0]] declare i8* @strdup(i8*) -; CHECK: declare i64 @strlen(i8* nocapture) [[G2:#[0-9]+]] +; CHECK: declare i64 @strlen(i8* nocapture nonnull) [[G2:#[0-9]+]] declare i64 @strlen(i8*) ; CHECK: declare i32 @strncasecmp(i8* nocapture, i8* nocapture, i64) [[G1]] declare i32 @strncasecmp(i8*, i8*, i64) -; CHECK: declare i8* @strncat(i8*, i8* nocapture readonly, i64) [[G0]] +; CHECK: declare i8* @strncat(i8* nonnull, i8* nocapture readonly, i64) [[G0]] declare i8* @strncat(i8*, i8*, i64) ; CHECK: declare i32 @strncmp(i8* nocapture, i8* nocapture, i64) [[G1]] declare i32 @strncmp(i8*, i8*, i64) -; CHECK: declare i8* @strncpy(i8*, i8* nocapture readonly, i64) [[G0]] +; CHECK: declare i8* @strncpy(i8* nonnull, i8* nocapture readonly, i64) [[G0]] declare i8* @strncpy(i8*, i8*, i64) ; CHECK: declare noalias i8* @strndup(i8* nocapture readonly, i64) [[G0]] @@ -871,49 +872,49 @@ ; CHECK: declare i64 @strnlen(i8*, i64) declare i64 @strnlen(i8*, i64) -; CHECK: declare i8* @strpbrk(i8*, i8* nocapture) [[G1]] +; CHECK: declare i8* @strpbrk(i8* nonnull, i8* nocapture nonnull) [[G1]] declare i8* @strpbrk(i8*, i8*) -; CHECK: declare i8* @strrchr(i8*, i32) [[G1]] +; CHECK: declare i8* @strrchr(i8* nonnull, i32) [[G1]] declare i8* @strrchr(i8*, i32) -; CHECK: declare i64 @strspn(i8* nocapture, i8* nocapture) [[G1]] +; CHECK: declare i64 @strspn(i8* nocapture nonnull, i8* nocapture nonnull) [[G1]] declare i64 @strspn(i8*, i8*) -; CHECK: declare i8* @strstr(i8*, i8* nocapture) [[G1]] +; CHECK: declare i8* @strstr(i8* nonnull, i8* nocapture nonnull) [[G1]] declare i8* @strstr(i8*, i8*) -; CHECK: declare double @strtod(i8* readonly, i8** nocapture) [[G0]] +; CHECK: declare double @strtod(i8* nonnull readonly, i8** nocapture) [[G0]] declare double @strtod(i8*, i8**) -; CHECK: declare float @strtof(i8* readonly, i8** nocapture) [[G0]] +; CHECK: declare float @strtof(i8* nonnull readonly, i8** nocapture) [[G0]] declare float @strtof(i8*, i8**) -; CHECK: declare i8* @strtok(i8*, i8* nocapture readonly) [[G0]] +; CHECK: declare i8* @strtok(i8*, i8* nocapture nonnull readonly) [[G0]] declare i8* @strtok(i8*, i8*) -; CHECK: declare i8* @strtok_r(i8*, i8* nocapture readonly, i8**) [[G0]] +; CHECK: declare i8* @strtok_r(i8*, i8* nocapture nonnull readonly, i8**) [[G0]] declare i8* @strtok_r(i8*, i8*, i8**) -; CHECK: declare i64 @strtol(i8* readonly, i8** nocapture, i32) [[G0]] +; CHECK: declare i64 @strtol(i8* nonnull readonly, i8** nocapture, i32) [[G0]] declare i64 @strtol(i8*, i8**, i32) -; CHECK: declare x86_fp80 @strtold(i8* readonly, i8** nocapture) [[G0]] +; CHECK: declare x86_fp80 @strtold(i8* nonnull readonly, i8** nocapture) [[G0]] declare x86_fp80 @strtold(i8*, i8**) -; CHECK: declare i64 @strtoll(i8* readonly, i8** nocapture, i32) [[G0]] +; CHECK: declare i64 @strtoll(i8* nonnull readonly, i8** nocapture, i32) [[G0]] declare i64 @strtoll(i8*, i8**, i32) -; CHECK: declare i64 @strtoul(i8* readonly, i8** nocapture, i32) [[G0]] +; CHECK: declare i64 @strtoul(i8* nonnull readonly, i8** nocapture, i32) [[G0]] declare i64 @strtoul(i8*, i8**, i32) -; CHECK: declare i64 @strtoull(i8* readonly, i8** nocapture, i32) [[G0]] +; CHECK: declare i64 @strtoull(i8* nonnull readonly, i8** nocapture, i32) [[G0]] declare i64 @strtoull(i8*, i8**, i32) ; CHECK: declare i64 @strxfrm(i8* nocapture, i8* nocapture readonly, i64) [[G0]] declare i64 @strxfrm(i8*, i8*, i64) -; CHECK: declare i32 @system(i8* nocapture readonly) +; CHECK: declare i32 @system(i8* nocapture nonnull readonly) declare i32 @system(i8*) ; CHECK: declare double @tan(double) Index: test/Transforms/InstCombine/sprintf-1.ll =================================================================== --- test/Transforms/InstCombine/sprintf-1.ll +++ test/Transforms/InstCombine/sprintf-1.ll @@ -1,3 +1,4 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; Test that the sprintf library call simplifier works correctly. ; ; RUN: opt < %s -instcombine -S | FileCheck %s @@ -20,81 +21,125 @@ define void @test_simplify1(i8* %dst) { ; CHECK-LABEL: @test_simplify1( +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 1 [[DST:%.*]], i8* align 1 getelementptr inbounds ([13 x i8], [13 x i8]* @hello_world, i32 0, i32 0), i32 13, i1 false) +; CHECK-NEXT: ret void +; +; CHECK-IPRINTF-LABEL: @test_simplify1( +; CHECK-IPRINTF-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 1 [[DST:%.*]], i8* align 1 getelementptr inbounds ([13 x i8], [13 x i8]* @hello_world, i32 0, i32 0), i32 13, i1 false) +; CHECK-IPRINTF-NEXT: ret void +; %fmt = getelementptr [13 x i8], [13 x i8]* @hello_world, i32 0, i32 0 call i32 (i8*, i8*, ...) @sprintf(i8* %dst, i8* %fmt) -; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 1 %dst, i8* align 1 getelementptr inbounds ([13 x i8], [13 x i8]* @hello_world, i32 0, i32 0), i32 13, i1 false) ret void -; CHECK-NEXT: ret void } define void @test_simplify2(i8* %dst) { ; CHECK-LABEL: @test_simplify2( +; CHECK-NEXT: store i8 0, i8* [[DST:%.*]], align 1 +; CHECK-NEXT: ret void +; +; CHECK-IPRINTF-LABEL: @test_simplify2( +; CHECK-IPRINTF-NEXT: store i8 0, i8* [[DST:%.*]], align 1 +; CHECK-IPRINTF-NEXT: ret void +; %fmt = getelementptr [1 x i8], [1 x i8]* @null, i32 0, i32 0 call i32 (i8*, i8*, ...) @sprintf(i8* %dst, i8* %fmt) -; CHECK-NEXT: store i8 0, i8* %dst, align 1 ret void -; CHECK-NEXT: ret void } define void @test_simplify3(i8* %dst) { ; CHECK-LABEL: @test_simplify3( +; CHECK-NEXT: store i8 0, i8* [[DST:%.*]], align 1 +; CHECK-NEXT: ret void +; +; CHECK-IPRINTF-LABEL: @test_simplify3( +; CHECK-IPRINTF-NEXT: store i8 0, i8* [[DST:%.*]], align 1 +; CHECK-IPRINTF-NEXT: ret void +; %fmt = getelementptr [7 x i8], [7 x i8]* @null_hello, i32 0, i32 0 call i32 (i8*, i8*, ...) @sprintf(i8* %dst, i8* %fmt) -; CHECK-NEXT: store i8 0, i8* %dst, align 1 ret void -; CHECK-NEXT: ret void } ; Check sprintf(dst, "%c", chr) -> *(i8*)dst = chr; *((i8*)dst + 1) = 0. define void @test_simplify4(i8* %dst) { ; CHECK-LABEL: @test_simplify4( +; CHECK-NEXT: store i8 104, i8* [[DST:%.*]], align 1 +; CHECK-NEXT: [[NUL:%.*]] = getelementptr i8, i8* [[DST]], i32 1 +; CHECK-NEXT: store i8 0, i8* [[NUL]], align 1 +; CHECK-NEXT: ret void +; +; CHECK-IPRINTF-LABEL: @test_simplify4( +; CHECK-IPRINTF-NEXT: store i8 104, i8* [[DST:%.*]], align 1 +; CHECK-IPRINTF-NEXT: [[NUL:%.*]] = getelementptr i8, i8* [[DST]], i32 1 +; CHECK-IPRINTF-NEXT: store i8 0, i8* [[NUL]], align 1 +; CHECK-IPRINTF-NEXT: ret void +; %fmt = getelementptr [3 x i8], [3 x i8]* @percent_c, i32 0, i32 0 call i32 (i8*, i8*, ...) @sprintf(i8* %dst, i8* %fmt, i8 104) -; CHECK-NEXT: store i8 104, i8* %dst, align 1 -; CHECK-NEXT: [[NUL:%[a-z0-9]+]] = getelementptr i8, i8* %dst, i32 1 -; CHECK-NEXT: store i8 0, i8* [[NUL]], align 1 ret void -; CHECK-NEXT: ret void } ; Check sprintf(dst, "%s", str) -> llvm.memcpy(dest, str, strlen(str) + 1, 1). define void @test_simplify5(i8* %dst, i8* %str) { ; CHECK-LABEL: @test_simplify5( +; CHECK-NEXT: [[STRLEN:%.*]] = call i32 @strlen(i8* [[STR:%.*]]) +; CHECK-NEXT: [[LENINC:%.*]] = add i32 [[STRLEN]], 1 +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 1 [[DST:%.*]], i8* nonnull align 1 [[STR]], i32 [[LENINC]], i1 false) +; CHECK-NEXT: ret void +; +; CHECK-IPRINTF-LABEL: @test_simplify5( +; CHECK-IPRINTF-NEXT: [[STRLEN:%.*]] = call i32 @strlen(i8* [[STR:%.*]]) +; CHECK-IPRINTF-NEXT: [[LENINC:%.*]] = add i32 [[STRLEN]], 1 +; CHECK-IPRINTF-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 1 [[DST:%.*]], i8* nonnull align 1 [[STR]], i32 [[LENINC]], i1 false) +; CHECK-IPRINTF-NEXT: ret void +; %fmt = getelementptr [3 x i8], [3 x i8]* @percent_s, i32 0, i32 0 call i32 (i8*, i8*, ...) @sprintf(i8* %dst, i8* %fmt, i8* %str) -; CHECK-NEXT: [[STRLEN:%[a-z0-9]+]] = call i32 @strlen(i8* %str) -; CHECK-NEXT: [[LENINC:%[a-z0-9]+]] = add i32 [[STRLEN]], 1 -; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 1 %dst, i8* align 1 %str, i32 [[LENINC]], i1 false) ret void -; CHECK-NEXT: ret void } ; Check sprintf(dst, format, ...) -> siprintf(str, format, ...) if no floating. define void @test_simplify6(i8* %dst) { +; CHECK-LABEL: @test_simplify6( +; CHECK-NEXT: [[TMP1:%.*]] = call i32 (i8*, i8*, ...) @sprintf(i8* [[DST:%.*]], i8* getelementptr inbounds ([3 x i8], [3 x i8]* @percent_d, i32 0, i32 0), i32 187) +; CHECK-NEXT: ret void +; ; CHECK-IPRINTF-LABEL: @test_simplify6( +; CHECK-IPRINTF-NEXT: [[TMP1:%.*]] = call i32 (i8*, i8*, ...) @siprintf(i8* [[DST:%.*]], i8* getelementptr inbounds ([3 x i8], [3 x i8]* @percent_d, i32 0, i32 0), i32 187) +; CHECK-IPRINTF-NEXT: ret void +; %fmt = getelementptr [3 x i8], [3 x i8]* @percent_d, i32 0, i32 0 call i32 (i8*, i8*, ...) @sprintf(i8* %dst, i8* %fmt, i32 187) -; CHECK-IPRINTF-NEXT: call i32 (i8*, i8*, ...) @siprintf(i8* %dst, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @percent_d, i32 0, i32 0), i32 187) ret void -; CHECK-IPRINTF-NEXT: ret void } define void @test_no_simplify1(i8* %dst) { +; CHECK-LABEL: @test_no_simplify1( +; CHECK-NEXT: [[TMP1:%.*]] = call i32 (i8*, i8*, ...) @sprintf(i8* [[DST:%.*]], i8* getelementptr inbounds ([3 x i8], [3 x i8]* @percent_f, i32 0, i32 0), double 1.870000e+00) +; CHECK-NEXT: ret void +; ; CHECK-IPRINTF-LABEL: @test_no_simplify1( +; CHECK-IPRINTF-NEXT: [[TMP1:%.*]] = call i32 (i8*, i8*, ...) @sprintf(i8* [[DST:%.*]], i8* getelementptr inbounds ([3 x i8], [3 x i8]* @percent_f, i32 0, i32 0), double 1.870000e+00) +; CHECK-IPRINTF-NEXT: ret void +; %fmt = getelementptr [3 x i8], [3 x i8]* @percent_f, i32 0, i32 0 call i32 (i8*, i8*, ...) @sprintf(i8* %dst, i8* %fmt, double 1.87) -; CHECK-IPRINTF-NEXT: call i32 (i8*, i8*, ...) @sprintf(i8* %dst, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @percent_f, i32 0, i32 0), double 1.870000e+00) ret void -; CHECK-IPRINTF-NEXT: ret void } define void @test_no_simplify2(i8* %dst, i8* %fmt, double %d) { ; CHECK-LABEL: @test_no_simplify2( +; CHECK-NEXT: [[TMP1:%.*]] = call i32 (i8*, i8*, ...) @sprintf(i8* [[DST:%.*]], i8* [[FMT:%.*]], double [[D:%.*]]) +; CHECK-NEXT: ret void +; +; CHECK-IPRINTF-LABEL: @test_no_simplify2( +; CHECK-IPRINTF-NEXT: [[TMP1:%.*]] = call i32 (i8*, i8*, ...) @sprintf(i8* [[DST:%.*]], i8* [[FMT:%.*]], double [[D:%.*]]) +; CHECK-IPRINTF-NEXT: ret void +; call i32 (i8*, i8*, ...) @sprintf(i8* %dst, i8* %fmt, double %d) -; CHECK-NEXT: call i32 (i8*, i8*, ...) @sprintf(i8* %dst, i8* %fmt, double %d) ret void -; CHECK-NEXT: ret void } Index: test/Transforms/InstCombine/strstr-1.ll =================================================================== --- test/Transforms/InstCombine/strstr-1.ll +++ test/Transforms/InstCombine/strstr-1.ll @@ -1,3 +1,4 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; Test that the strstr library call simplifier works correctly. ; ; RUN: opt < %s -instcombine -S | FileCheck %s @@ -15,51 +16,57 @@ define i8* @test_simplify1(i8* %str) { ; CHECK-LABEL: @test_simplify1( +; CHECK-NEXT: ret i8* [[STR:%.*]] +; %pat = getelementptr inbounds [1 x i8], [1 x i8]* @.str, i32 0, i32 0 %ret = call i8* @strstr(i8* %str, i8* %pat) ret i8* %ret -; CHECK-NEXT: ret i8* %str } ; Check strstr(str, "a") -> strchr(str, 'a'). define i8* @test_simplify2(i8* %str) { ; CHECK-LABEL: @test_simplify2( +; CHECK-NEXT: [[STRCHR:%.*]] = call i8* @strchr(i8* [[STR:%.*]], i32 97) +; CHECK-NEXT: ret i8* [[STRCHR]] +; %pat = getelementptr inbounds [2 x i8], [2 x i8]* @.str1, i32 0, i32 0 %ret = call i8* @strstr(i8* %str, i8* %pat) ret i8* %ret -; CHECK-NEXT: @strchr(i8* %str, i32 97) } ; Check strstr("abcde", "bcd") -> "abcde" + 1. define i8* @test_simplify3() { ; CHECK-LABEL: @test_simplify3( +; CHECK-NEXT: ret i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str2, i64 0, i64 1) +; %str = getelementptr inbounds [6 x i8], [6 x i8]* @.str2, i32 0, i32 0 %pat = getelementptr inbounds [4 x i8], [4 x i8]* @.str3, i32 0, i32 0 %ret = call i8* @strstr(i8* %str, i8* %pat) ret i8* %ret -; CHECK-NEXT: getelementptr inbounds ([6 x i8], [6 x i8]* @.str2, i64 0, i64 1) } ; Check strstr(str, str) -> str. define i8* @test_simplify4(i8* %str) { ; CHECK-LABEL: @test_simplify4( +; CHECK-NEXT: ret i8* [[STR:%.*]] +; %ret = call i8* @strstr(i8* %str, i8* %str) ret i8* %ret -; CHECK-NEXT: ret i8* %str } ; Check strstr(str, pat) == str -> strncmp(str, pat, strlen(str)) == 0. define i1 @test_simplify5(i8* %str, i8* %pat) { ; CHECK-LABEL: @test_simplify5( +; CHECK-NEXT: [[STRLEN:%.*]] = call i64 @strlen(i8* [[PAT:%.*]]) +; CHECK-NEXT: [[STRNCMP:%.*]] = call i32 @strncmp(i8* [[STR:%.*]], i8* nonnull [[PAT]], i64 [[STRLEN]]) +; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[STRNCMP]], 0 +; CHECK-NEXT: ret i1 [[CMP1]] +; %ret = call i8* @strstr(i8* %str, i8* %pat) %cmp = icmp eq i8* %ret, %str ret i1 %cmp -; CHECK: [[LEN:%[a-z]+]] = call {{i[0-9]+}} @strlen(i8* %pat) -; CHECK: [[NCMP:%[a-z]+]] = call {{i[0-9]+}} @strncmp(i8* %str, i8* %pat, {{i[0-9]+}} [[LEN]]) -; CHECK: icmp eq {{i[0-9]+}} [[NCMP]], 0 -; CHECK: ret i1 } Index: test/Transforms/InstCombine/strto-1.ll =================================================================== --- test/Transforms/InstCombine/strto-1.ll +++ test/Transforms/InstCombine/strto-1.ll @@ -4,79 +4,95 @@ target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128" -declare i64 @strtol(i8* %s, i8** %endptr, i32 %base) -; CHECK: declare i64 @strtol(i8* readonly, i8** nocapture, i32) +declare i64 @strtol(i8* nonnull %s, i8** %endptr, i32 %base) +; CHECK: declare i64 @strtol(i8* nonnull readonly, i8** nocapture, i32) -declare double @strtod(i8* %s, i8** %endptr, i32 %base) -; CHECK: declare double @strtod(i8* readonly, i8** nocapture, i32) +declare double @strtod(i8* nonnull %s, i8** %endptr, i32 %base) +; CHECK: declare double @strtod(i8* nonnull readonly, i8** nocapture, i32) -declare float @strtof(i8* %s, i8** %endptr, i32 %base) -; CHECK: declare float @strtof(i8* readonly, i8** nocapture, i32) +declare float @strtof(i8* nonnull %s, i8** %endptr, i32 %base) +; CHECK: declare float @strtof(i8* nonnull readonly, i8** nocapture, i32) -declare i64 @strtoul(i8* %s, i8** %endptr, i32 %base) -; CHECK: declare i64 @strtoul(i8* readonly, i8** nocapture, i32) +declare i64 @strtoul(i8* nonnull %s, i8** %endptr, i32 %base) +; CHECK: declare i64 @strtoul(i8* nonnull readonly, i8** nocapture, i32) -declare i64 @strtoll(i8* %s, i8** %endptr, i32 %base) -; CHECK: declare i64 @strtoll(i8* readonly, i8** nocapture, i32) +declare i64 @strtoll(i8* nonnull %s, i8** %endptr, i32 %base) +; CHECK: declare i64 @strtoll(i8* nonnull readonly, i8** nocapture, i32) -declare double @strtold(i8* %s, i8** %endptr) -; CHECK: declare double @strtold(i8* readonly, i8** nocapture) +declare double @strtold(i8* nonnull %s, i8** %endptr) +; CHECK: declare double @strtold(i8* nonnull readonly, i8** nocapture) -declare i64 @strtoull(i8* %s, i8** %endptr, i32 %base) -; CHECK: declare i64 @strtoull(i8* readonly, i8** nocapture, i32) +declare i64 @strtoull(i8* nonnull %s, i8** %endptr, i32 %base) +; CHECK: declare i64 @strtoull(i8* nonnull readonly, i8** nocapture, i32) define void @test_simplify1(i8* %x, i8** %endptr) { ; CHECK-LABEL: @test_simplify1( +; CHECK-NEXT: [[TMP1:%.*]] = call i64 @strtol(i8* nocapture [[X:%.*]], i8** null, i32 10) +; CHECK-NEXT: ret void +; call i64 @strtol(i8* %x, i8** null, i32 10) -; CHECK-NEXT: call i64 @strtol(i8* nocapture %x, i8** null, i32 10) ret void } define void @test_simplify2(i8* %x, i8** %endptr) { ; CHECK-LABEL: @test_simplify2( +; CHECK-NEXT: [[TMP1:%.*]] = call double @strtod(i8* nocapture [[X:%.*]], i8** null, i32 10) +; CHECK-NEXT: ret void +; call double @strtod(i8* %x, i8** null, i32 10) -; CHECK-NEXT: call double @strtod(i8* nocapture %x, i8** null, i32 10) ret void } define void @test_simplify3(i8* %x, i8** %endptr) { ; CHECK-LABEL: @test_simplify3( +; CHECK-NEXT: [[TMP1:%.*]] = call float @strtof(i8* nocapture [[X:%.*]], i8** null, i32 10) +; CHECK-NEXT: ret void +; call float @strtof(i8* %x, i8** null, i32 10) -; CHECK-NEXT: call float @strtof(i8* nocapture %x, i8** null, i32 10) ret void } define void @test_simplify4(i8* %x, i8** %endptr) { ; CHECK-LABEL: @test_simplify4( +; CHECK-NEXT: [[TMP1:%.*]] = call i64 @strtoul(i8* nocapture [[X:%.*]], i8** null, i32 10) +; CHECK-NEXT: ret void +; call i64 @strtoul(i8* %x, i8** null, i32 10) -; CHECK-NEXT: call i64 @strtoul(i8* nocapture %x, i8** null, i32 10) ret void } define void @test_simplify5(i8* %x, i8** %endptr) { ; CHECK-LABEL: @test_simplify5( +; CHECK-NEXT: [[TMP1:%.*]] = call i64 @strtoll(i8* nocapture [[X:%.*]], i8** null, i32 10) +; CHECK-NEXT: ret void +; call i64 @strtoll(i8* %x, i8** null, i32 10) -; CHECK-NEXT: call i64 @strtoll(i8* nocapture %x, i8** null, i32 10) ret void } define void @test_simplify6(i8* %x, i8** %endptr) { ; CHECK-LABEL: @test_simplify6( +; CHECK-NEXT: [[TMP1:%.*]] = call double @strtold(i8* nocapture [[X:%.*]], i8** null) +; CHECK-NEXT: ret void +; call double @strtold(i8* %x, i8** null) -; CHECK-NEXT: call double @strtold(i8* nocapture %x, i8** null) ret void } define void @test_simplify7(i8* %x, i8** %endptr) { ; CHECK-LABEL: @test_simplify7( +; CHECK-NEXT: [[TMP1:%.*]] = call i64 @strtoull(i8* nocapture [[X:%.*]], i8** null, i32 10) +; CHECK-NEXT: ret void +; call i64 @strtoull(i8* %x, i8** null, i32 10) -; CHECK-NEXT: call i64 @strtoull(i8* nocapture %x, i8** null, i32 10) ret void } define void @test_no_simplify1(i8* %x, i8** %endptr) { ; CHECK-LABEL: @test_no_simplify1( +; CHECK-NEXT: [[TMP1:%.*]] = call i64 @strtol(i8* [[X:%.*]], i8** [[ENDPTR:%.*]], i32 10) +; CHECK-NEXT: ret void +; call i64 @strtol(i8* %x, i8** %endptr, i32 10) -; CHECK-NEXT: call i64 @strtol(i8* %x, i8** %endptr, i32 10) ret void } Index: test/Transforms/InstCombine/unlocked-stdio.ll =================================================================== --- test/Transforms/InstCombine/unlocked-stdio.ll +++ test/Transforms/InstCombine/unlocked-stdio.ll @@ -60,7 +60,7 @@ ; CHECK-NEXT: [[S:%.*]] = alloca [10 x i8], align 1 ; CHECK-NEXT: [[CALL:%.*]] = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0)) ; CHECK-NEXT: [[ARRAYDECAY:%.*]] = getelementptr inbounds [10 x i8], [10 x i8]* [[S]], i64 0, i64 0 -; CHECK-NEXT: [[TMP1:%.*]] = call i64 @fwrite_unlocked(i8* nonnull [[ARRAYDECAY]], i64 10, i64 10, %struct._IO_FILE* [[CALL]]) +; CHECK-NEXT: [[TMP1:%.*]] = call i64 @fwrite_unlocked(i8* [[ARRAYDECAY]], i64 10, i64 10, %struct._IO_FILE* [[CALL]]) ; CHECK-NEXT: ret void ; %s = alloca [10 x i8], align 1 @@ -75,7 +75,7 @@ ; CHECK-NEXT: [[S:%.*]] = alloca [10 x i8], align 1 ; CHECK-NEXT: [[CALL:%.*]] = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0)) ; CHECK-NEXT: [[ARRAYDECAY:%.*]] = getelementptr inbounds [10 x i8], [10 x i8]* [[S]], i64 0, i64 0 -; CHECK-NEXT: [[TMP1:%.*]] = call i64 @fread_unlocked(i8* nonnull [[ARRAYDECAY]], i64 10, i64 10, %struct._IO_FILE* [[CALL]]) +; CHECK-NEXT: [[TMP1:%.*]] = call i64 @fread_unlocked(i8* [[ARRAYDECAY]], i64 10, i64 10, %struct._IO_FILE* [[CALL]]) ; CHECK-NEXT: ret void ; %s = alloca [10 x i8], align 1 @@ -101,7 +101,7 @@ ; CHECK-NEXT: [[BUF:%.*]] = alloca [10 x i8], align 1 ; CHECK-NEXT: [[CALL:%.*]] = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0)) ; CHECK-NEXT: [[ARRAYDECAY:%.*]] = getelementptr inbounds [10 x i8], [10 x i8]* [[BUF]], i64 0, i64 0 -; CHECK-NEXT: [[FGETS_UNLOCKED:%.*]] = call i8* @fgets_unlocked(i8* nonnull [[ARRAYDECAY]], i32 10, %struct._IO_FILE* [[CALL]]) +; CHECK-NEXT: [[FGETS_UNLOCKED:%.*]] = call i8* @fgets_unlocked(i8* [[ARRAYDECAY]], i32 10, %struct._IO_FILE* [[CALL]]) ; CHECK-NEXT: ret void ; %buf = alloca [10 x i8], align 1 @@ -147,7 +147,7 @@ ; CHECK-LABEL: @test_with_fclose( ; CHECK-NEXT: [[CALL:%.*]] = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0)) ; CHECK-NEXT: [[TMP1:%.*]] = call i64 @fwrite_unlocked(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.2, i64 0, i64 0), i64 3, i64 1, %struct._IO_FILE* [[CALL]]) -; CHECK-NEXT: [[CALL2:%.*]] = call i32 @fclose(%struct._IO_FILE* [[CALL]]) +; CHECK-NEXT: [[CALL2:%.*]] = call i32 @fclose(%struct._IO_FILE* nonnull [[CALL]]) ; CHECK-NEXT: ret void ; %call = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0)) #2 @@ -163,7 +163,7 @@ ; CHECK-NEXT: [[CALL:%.*]] = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0)) ; CHECK-NEXT: call void @modify_file(%struct._IO_FILE* [[CALL]]) ; CHECK-NEXT: [[CALL1:%.*]] = call i64 @fwrite(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.2, i64 0, i64 0), i64 3, i64 1, %struct._IO_FILE* [[CALL]]) -; CHECK-NEXT: [[CALL2:%.*]] = call i32 @fclose(%struct._IO_FILE* [[CALL]]) +; CHECK-NEXT: [[CALL2:%.*]] = call i32 @fclose(%struct._IO_FILE* nonnull [[CALL]]) ; CHECK-NEXT: ret void ; %call = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0)) #2 @@ -179,7 +179,7 @@ ; CHECK-NEXT: [[DOTCAST:%.*]] = ptrtoint %struct._IO_FILE* [[CALL]] to i64 ; CHECK-NEXT: store i64 [[DOTCAST]], i64* bitcast (%struct._IO_FILE** @global_file to i64*), align 8 ; CHECK-NEXT: [[CALL1:%.*]] = call i64 @fwrite(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.2, i64 0, i64 0), i64 3, i64 1, %struct._IO_FILE* [[CALL]]) -; CHECK-NEXT: [[CALL2:%.*]] = call i32 @fclose(%struct._IO_FILE* [[CALL]]) +; CHECK-NEXT: [[CALL2:%.*]] = call i32 @fclose(%struct._IO_FILE* nonnull [[CALL]]) ; CHECK-NEXT: ret void ; %call = call %struct._IO_FILE* @fopen(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0)) #2 Index: test/Transforms/LICM/strlen.ll =================================================================== --- test/Transforms/LICM/strlen.ll +++ test/Transforms/LICM/strlen.ll @@ -12,7 +12,7 @@ br label %loop } -; CHECK: declare i64 @strlen(i8* nocapture) #0 +; CHECK: declare i64 @strlen(i8* nocapture nonnull) #0 ; CHECK: attributes #0 = { argmemonly nounwind readonly } declare i64 @strlen(i8*)