diff --git a/llvm/lib/Analysis/TargetLibraryInfo.cpp b/llvm/lib/Analysis/TargetLibraryInfo.cpp --- a/llvm/lib/Analysis/TargetLibraryInfo.cpp +++ b/llvm/lib/Analysis/TargetLibraryInfo.cpp @@ -941,6 +941,7 @@ FTy.getParamType(1)->isPointerTy() && FTy.getParamType(2)->isPointerTy() && FTy.getReturnType()->isIntegerTy(32)); + case LibFunc_strlen_chk: --NumParams; if (!FTy.getParamType(NumParams)->isIntegerTy(SizeTBits)) @@ -956,134 +957,213 @@ FTy.getParamType(0) == FTy.getReturnType() && FTy.getParamType(1)->isIntegerTy()); - case LibFunc_strtol: case LibFunc_strtod: + // double (const char*, char**) + return (NumParams == 2 && FTy.getReturnType()->isDoubleTy() & + FTy.getParamType(0)->isPointerTy() && + FTy.getParamType(1)->isPointerTy()); case LibFunc_strtof: + // float (const char*, char**) + return (NumParams == 2 && FTy.getReturnType()->isFloatTy() & + FTy.getParamType(0)->isPointerTy() && + FTy.getParamType(1)->isPointerTy()); + case LibFunc_strtold: + // long double (const char*, char**) + return (NumParams == 2 && FTy.getReturnType()->isFloatingPointTy() & + FTy.getParamType(0)->isPointerTy() && + FTy.getParamType(1)->isPointerTy()); + + case LibFunc_strtol: + // long (const char*, char**, int) case LibFunc_strtoul: + // unsigned long (const char*, char**, int) + return (NumParams == 3 && FTy.getReturnType()->isIntegerTy() && + FTy.getParamType(0)->isPointerTy() && + FTy.getParamType(1)->isPointerTy() && + FTy.getParamType(2)->isIntegerTy(32)); case LibFunc_strtoll: - case LibFunc_strtold: + // long long (const char*, char**, int) case LibFunc_strtoull: - return ((NumParams == 2 || NumParams == 3) && + // unsigned long long (const char*, char**, int) + return (NumParams == 3 && FTy.getReturnType()->isIntegerTy(64) && FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(1)->isPointerTy()); + FTy.getParamType(1)->isPointerTy() && + FTy.getParamType(2)->isIntegerTy(32)); + case LibFunc_strcat_chk: + case LibFunc_strcpy_chk: + case LibFunc_stpcpy_chk: + // char* (char*, const char*, size_t) --NumParams; if (!FTy.getParamType(NumParams)->isIntegerTy(SizeTBits)) return false; LLVM_FALLTHROUGH; case LibFunc_strcat: + case LibFunc_strcpy: + case LibFunc_stpcpy: + // char* (char*, const char*) return (NumParams == 2 && FTy.getReturnType()->isPointerTy() && FTy.getParamType(0) == FTy.getReturnType() && - FTy.getParamType(1) == FTy.getReturnType()); + FTy.getParamType(1) == FTy.getParamType(0)); + case LibFunc_memcpy_chk: + case LibFunc_mempcpy_chk: + case LibFunc_memmove_chk: + // void* (void*, const void*, size_t, size_t) case LibFunc_strncat_chk: + case LibFunc_strncpy_chk: + case LibFunc_stpncpy_chk: + // char* (char*, const char*, size_t, size_t) --NumParams; if (!FTy.getParamType(NumParams)->isIntegerTy(SizeTBits)) return false; LLVM_FALLTHROUGH; + case LibFunc_memcpy: + case LibFunc_mempcpy: + case LibFunc_memmove: + // void* (void*, const void*, size_t) case LibFunc_strncat: + case LibFunc_strncpy: + case LibFunc_stpncpy: + // char* (char*, const char*, size_t) return (NumParams == 3 && FTy.getReturnType()->isPointerTy() && FTy.getParamType(0) == FTy.getReturnType() && - FTy.getParamType(1) == FTy.getReturnType() && + FTy.getParamType(1) == FTy.getParamType(0) && FTy.getParamType(2)->isIntegerTy(SizeTBits)); - case LibFunc_strcpy_chk: - case LibFunc_stpcpy_chk: - --NumParams; - if (!FTy.getParamType(NumParams)->isIntegerTy(SizeTBits)) - return false; - LLVM_FALLTHROUGH; - case LibFunc_strcpy: - case LibFunc_stpcpy: - return (NumParams == 2 && FTy.getReturnType() == FTy.getParamType(0) && - FTy.getParamType(0) == FTy.getParamType(1) && - FTy.getParamType(0)->isPointerTy()); - case LibFunc_strlcat_chk: case LibFunc_strlcpy_chk: + // size_t (char*, const char*, size_t, size_t) --NumParams; if (!FTy.getParamType(NumParams)->isIntegerTy(SizeTBits)) return false; LLVM_FALLTHROUGH; case LibFunc_strlcat: case LibFunc_strlcpy: - return NumParams == 3 && FTy.getReturnType()->isIntegerTy(SizeTBits) && - FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(1)->isPointerTy() && - FTy.getParamType(2)->isIntegerTy(SizeTBits); + case LibFunc_strxfrm: + // size_t (char*, const char*, size_t) + return (NumParams == 3 && FTy.getReturnType()->isIntegerTy(SizeTBits) && + FTy.getParamType(0)->isPointerTy() && + FTy.getParamType(1) == FTy.getParamType(0) && + FTy.getParamType(2) == FTy.getReturnType()); - case LibFunc_strncpy_chk: - case LibFunc_stpncpy_chk: + case LibFunc_memset_chk: + // void* (void*, int, size_t, size_t) --NumParams; if (!FTy.getParamType(NumParams)->isIntegerTy(SizeTBits)) return false; LLVM_FALLTHROUGH; - case LibFunc_strncpy: - case LibFunc_stpncpy: - return (NumParams == 3 && FTy.getReturnType() == FTy.getParamType(0) && - FTy.getParamType(0) == FTy.getParamType(1) && - FTy.getParamType(0)->isPointerTy() && + case LibFunc_memset: + // void* (void*, int, size_t) + return (NumParams == 3 && FTy.getReturnType()->isPointerTy() && + FTy.getParamType(0) == FTy.getReturnType() && + FTy.getParamType(1)->isIntegerTy() && FTy.getParamType(2)->isIntegerTy(SizeTBits)); - case LibFunc_strxfrm: - return (NumParams == 3 && FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(1)->isPointerTy()); + case LibFunc_memccpy_chk: + // void* (void*, const void*, int, size_t, size_t) + --NumParams; + if (!FTy.getParamType(NumParams)->isIntegerTy(SizeTBits)) + return false; + LLVM_FALLTHROUGH; + case LibFunc_memccpy: + // void* (void*, const void*, int, size_t) + return (NumParams == 4 && FTy.getReturnType()->isPointerTy() && + FTy.getParamType(0) == FTy.getReturnType() && + FTy.getParamType(1) == FTy.getParamType(1) && + FTy.getParamType(2)->isIntegerTy(32) && + FTy.getParamType(3)->isIntegerTy(SizeTBits)); case LibFunc_strcmp: + case LibFunc_strcoll: + case LibFunc_strcasecmp: + // int (const char*, const char*); return (NumParams == 2 && FTy.getReturnType()->isIntegerTy(32) && FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(0) == FTy.getParamType(1)); + FTy.getParamType(1) == FTy.getParamType(0)); + case LibFunc_memcmp: case LibFunc_strncmp: + case LibFunc_strncasecmp: + // int (const char*, const char*, size_t); return (NumParams == 3 && FTy.getReturnType()->isIntegerTy(32) && FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(0) == FTy.getParamType(1) && + FTy.getParamType(1) == FTy.getParamType(0) && FTy.getParamType(2)->isIntegerTy(SizeTBits)); case LibFunc_strspn: case LibFunc_strcspn: - return (NumParams == 2 && FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(0) == FTy.getParamType(1) && - FTy.getReturnType()->isIntegerTy()); - - case LibFunc_strcoll: - case LibFunc_strcasecmp: - case LibFunc_strncasecmp: - return (NumParams >= 2 && FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(1)->isPointerTy()); + // size_t (const char*, const char*); + return (NumParams == 2 && FTy.getReturnType()->isIntegerTy(SizeTBits) && + FTy.getParamType(0)->isPointerTy() && + FTy.getParamType(1) == FTy.getParamType(0)); case LibFunc_strstr: + case LibFunc_strpbrk: + // char* (const char*, const char*); + case LibFunc_strtok: + // char* (char*, const char*); return (NumParams == 2 && FTy.getReturnType()->isPointerTy() && + FTy.getParamType(0) == FTy.getReturnType() && + FTy.getParamType(1) == FTy.getParamType(0)); + case LibFunc_strtok_r: + // char* (char*, const char*, char**); + return (NumParams == 3 && FTy.getReturnType()->isPointerTy() && + FTy.getParamType(0) == FTy.getReturnType() && + FTy.getParamType(1) == FTy.getParamType(0) && + FTy.getParamType(2)->isPointerTy()); + + case LibFunc_setbuf: + // void (FILE*, char*) + return (NumParams == 2 && FTy.getReturnType()->isVoidTy() && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); - case LibFunc_strpbrk: - return (NumParams == 2 && FTy.getParamType(0)->isPointerTy() && - FTy.getReturnType() == FTy.getParamType(0) && - FTy.getParamType(0) == FTy.getParamType(1)); + case LibFunc_setvbuf: + // int (FILE*, char*, int, size_t) + return (NumParams == 4 && FTy.getReturnType()->isIntegerTy(32) && + FTy.getParamType(0)->isPointerTy() && + FTy.getParamType(1)->isPointerTy() && + FTy.getParamType(2)->isIntegerTy(32) && + FTy.getParamType(3)->isIntegerTy(SizeTBits)); - case LibFunc_strtok: - case LibFunc_strtok_r: - return (NumParams >= 2 && FTy.getParamType(1)->isPointerTy()); case LibFunc_scanf: - case LibFunc_setbuf: - case LibFunc_setvbuf: - return (NumParams >= 1 && FTy.getParamType(0)->isPointerTy()); + // int (const char*, ...*) + return (NumParams == 1 && FTy.getReturnType()->isIntegerTy(32) && + FTy.getParamType(0)->isPointerTy() && + FTy.isFunctionVarArg()); + case LibFunc_strdup: - case LibFunc_strndup: - return (NumParams >= 1 && FTy.getReturnType()->isPointerTy() && + // char* (const char*) + return (NumParams == 1 && FTy.getReturnType()->isPointerTy() && FTy.getParamType(0)->isPointerTy()); - case LibFunc_sscanf: + case LibFunc_strndup: + // char* (const char*, size_t) + return (NumParams == 2 && FTy.getReturnType()->isPointerTy() && + FTy.getParamType(0)->isPointerTy() && + FTy.getParamType(1)->isIntegerTy(SizeTBits)); + case LibFunc_stat: + // int (const char*, struct stat*) case LibFunc_statvfs: + // int (const char*, struct statvfs*) + return (NumParams == 2 && FTy.getReturnType()->isIntegerTy(32) && + FTy.getParamType(0)->isPointerTy() && + FTy.getParamType(1)->isPointerTy()); + + case LibFunc_sscanf: + // int (const char*, const char*, ...) case LibFunc_siprintf: case LibFunc_small_sprintf: case LibFunc_sprintf: - return (NumParams >= 2 && FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(1)->isPointerTy() && - FTy.getReturnType()->isIntegerTy(32)); + // int (char*, const char*, ...) + return (NumParams == 2 && FTy.getReturnType()->isIntegerTy(32) && + FTy.getParamType(0)->isPointerTy() && + FTy.getParamType(1) == FTy.getParamType(0) && + FTy.isFunctionVarArg()); case LibFunc_sprintf_chk: + // int (char*, int, size_t, const char*, ...) return NumParams == 4 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isIntegerTy(32) && FTy.getParamType(2)->isIntegerTy(SizeTBits) && @@ -1091,18 +1171,22 @@ FTy.getReturnType()->isIntegerTy(32); case LibFunc_snprintf: - return NumParams == 3 && FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(1)->isIntegerTy(SizeTBits) && - FTy.getParamType(2)->isPointerTy() && - FTy.getReturnType()->isIntegerTy(32); + // int (char*, size_t, const char*, ...) + return (NumParams == 3 && FTy.getParamType(0)->isPointerTy() && + FTy.getParamType(1)->isIntegerTy(SizeTBits) && + FTy.getParamType(2)->isPointerTy() && + FTy.getReturnType()->isIntegerTy(32) && + FTy.isFunctionVarArg()); case LibFunc_snprintf_chk: - return NumParams == 5 && FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(1)->isIntegerTy(SizeTBits) && - FTy.getParamType(2)->isIntegerTy(32) && - FTy.getParamType(3)->isIntegerTy(SizeTBits) && - FTy.getParamType(4)->isPointerTy() && - FTy.getReturnType()->isIntegerTy(32); + // int (char*, size_t, int, size_t, const char*, ...) + return (NumParams == 5 && FTy.getParamType(0)->isPointerTy() && + FTy.getParamType(1)->isIntegerTy(SizeTBits) && + FTy.getParamType(2)->isIntegerTy(32) && + FTy.getParamType(3)->isIntegerTy(SizeTBits) && + FTy.getParamType(4)->isPointerTy() && + FTy.getReturnType()->isIntegerTy(32) && + FTy.isFunctionVarArg()); case LibFunc_setitimer: return (NumParams == 3 && FTy.getParamType(1)->isPointerTy() && @@ -1115,11 +1199,6 @@ case LibFunc_vec_malloc: return NumParams == 1 && FTy.getParamType(0)->isIntegerTy(SizeTBits) && FTy.getReturnType()->isPointerTy(); - case LibFunc_memcmp: - return NumParams == 3 && FTy.getReturnType()->isIntegerTy(32) && - FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(1)->isPointerTy() && - FTy.getParamType(2)->isIntegerTy(SizeTBits); case LibFunc_memchr: case LibFunc_memrchr: @@ -1132,39 +1211,6 @@ case LibFunc_modfl: return (NumParams >= 2 && FTy.getParamType(1)->isPointerTy()); - case LibFunc_memcpy_chk: - case LibFunc_mempcpy_chk: - case LibFunc_memmove_chk: - --NumParams; - if (!FTy.getParamType(NumParams)->isIntegerTy(SizeTBits)) - return false; - LLVM_FALLTHROUGH; - case LibFunc_memcpy: - case LibFunc_mempcpy: - case LibFunc_memmove: - return (NumParams == 3 && FTy.getReturnType() == FTy.getParamType(0) && - FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(1)->isPointerTy() && - FTy.getParamType(2)->isIntegerTy(SizeTBits)); - - case LibFunc_memset_chk: - --NumParams; - if (!FTy.getParamType(NumParams)->isIntegerTy(SizeTBits)) - return false; - LLVM_FALLTHROUGH; - case LibFunc_memset: - return (NumParams == 3 && FTy.getReturnType() == FTy.getParamType(0) && - FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(1)->isIntegerTy() && - FTy.getParamType(2)->isIntegerTy(SizeTBits)); - - case LibFunc_memccpy_chk: - --NumParams; - if (!FTy.getParamType(NumParams)->isIntegerTy(SizeTBits)) - return false; - LLVM_FALLTHROUGH; - case LibFunc_memccpy: - return (NumParams >= 2 && FTy.getParamType(1)->isPointerTy()); case LibFunc_memalign: return (FTy.getReturnType()->isPointerTy()); case LibFunc_realloc: @@ -1201,10 +1247,24 @@ return (NumParams == 2 && FTy.getReturnType()->isPointerTy() && FTy.getParamType(0) == FTy.getParamType(1)); - case LibFunc_atof: case LibFunc_atoi: + // int (const char*) + return (NumParams == 1 && FTy.getReturnType()->isIntegerTy(32) && + FTy.getParamType(0)->isPointerTy()); case LibFunc_atol: + // long (const char*) + return (NumParams == 1 && FTy.getReturnType()->isIntegerTy() && + FTy.getParamType(0)->isPointerTy()); case LibFunc_atoll: + // long long (const char*) + return (NumParams == 1 && FTy.getReturnType()->isIntegerTy(64) && + FTy.getParamType(0)->isPointerTy()); + + case LibFunc_atof: + // double (const char*) + return (NumParams == 1 && FTy.getReturnType()->isDoubleTy() && + FTy.getParamType(0)->isPointerTy()); + case LibFunc_ferror: case LibFunc_getenv: case LibFunc_getpwnam: diff --git a/llvm/test/Transforms/InferFunctionAttrs/annotate-2.ll b/llvm/test/Transforms/InferFunctionAttrs/annotate-2.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/InferFunctionAttrs/annotate-2.ll @@ -0,0 +1,94 @@ +; Verify that incompatible declarations of known library functions are +; not annotated with argument attributes. This negative test complements +; annotate.ll. +; +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -inferattrs -opaque-pointers -S | FileCheck %s + + +; Exercise function declarations. + +; Expect int sprintf(char*, const char*, ...). +declare i32 @sprintf(ptr, i64, ptr, ...) +; CHECK: declare i32 @sprintf(ptr, i64, ptr, ...) + +; Expect int snprintf(char*, size_t, const char*, ...). +declare i32 @snprintf(ptr, i64, ptr) +; CHECK: declare i32 @snprintf(ptr, i64, ptr) + +; Expect int sscanf(const char*, const char*, ...). +declare i32 @sscanf(ptr, ...) +; CHECK: declare i32 @sscanf(ptr, ...) + + +; Exercise function declarations. + +; Expect int atoi(const char*). +declare i8 @atoi(ptr) +; CHECK: declare i8 @atoi(ptr) + +; Expect long long atoll(const char*). +declare i1 @atoll(ptr) +; CHECK: declare i1 @atoll(ptr) + +; Expect double atof(const char*). +declare float @atof(ptr) +; CHECK: declare float @atof(ptr) + +; Expect double strtod(const char*, char**). +declare double @strtod(ptr, ptr, i32) +; CHECK: declare double @strtod(ptr, ptr, i32) + +; Expect float strtof(const char*, char**). +declare double @strtof(ptr, ptr) +; CHECK: declare double @strtof(ptr, ptr) + + +; Exercise function declarations. + +; Expect void* memccpy(void*, const void*, int, size_t). +declare ptr @memccpy(ptr, ptr, i64, i64) +; CHECK: ptr @memccpy(ptr, ptr, i64, i64) + +; Expect int strcasecmp(const char*, const char*). +declare i1 @strcasecmp(ptr, ptr) +; CHECK: declare i1 @strcasecmp(ptr, ptr) + +; Expect int strcoll(const char*, const char*). +declare ptr @strcoll(ptr, ptr) +; CHECK: declare ptr @strcoll(ptr, ptr) + +; Expect int strncasecmp(const char*, const char*, size_t). +declare i32 @strncasecmp(ptr, ptr, i64, i64) +; CHECK: declare i32 @strncasecmp(ptr, ptr, i64, i64) + +; Expect int strxfrm(const char*, const char*). +declare i16 @strxfrm(ptr, ptr) +; CHECK: declare i16 @strxfrm(ptr, ptr) + +; Expect char* strtok(const char*, const char*). +declare ptr @strtok(ptr, i8) +; CHECK: declare ptr @strtok(ptr, i8) + +; Expect char* strtok_r(const char*, const char*, char**). +declare ptr @strtok_r(ptr, ptr, i64) +; CHECK: declare ptr @strtok_r(ptr, ptr, i64) + +; Expect char* strdup(const char*). +declare ptr @strdup(ptr, i64) +; CHECK: declare ptr @strdup(ptr, i64) + +; Expect char* strndup(const char*, size_t). +declare ptr @strndup(ptr, i64, i64) +; CHECK: declare ptr @strndup(ptr, i64, i64) + + +; Exercise and function declarations. + +; Expect int stat(const char*, struct stat*). +declare i32 @stat(ptr, ptr, i64) +; CHECK: declare i32 @stat(ptr, ptr, i64) + +; Expect int statvfs(const char*, struct statvfs*). +declare i32 @statvfs(ptr, ptr, i64) +; CHECK: declare i32 @statvfs(ptr, ptr, i64) diff --git a/llvm/test/Transforms/InstCombine/mem-deref-bytes-addrspaces.ll b/llvm/test/Transforms/InstCombine/mem-deref-bytes-addrspaces.ll --- a/llvm/test/Transforms/InstCombine/mem-deref-bytes-addrspaces.ll +++ b/llvm/test/Transforms/InstCombine/mem-deref-bytes-addrspaces.ll @@ -1,22 +1,22 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -passes=instcombine -S < %s | FileCheck %s -declare i32 @memcmp(i8 addrspace(1)* nocapture, i8* nocapture, i64) +declare i32 @memcmp(i8 addrspace(1)* nocapture, i8 addrspace(1)* nocapture, i64) -define i32 @memcmp_const_size_update_deref(i8 addrspace(1)* nocapture readonly %d, i8* nocapture readonly %s) { +define i32 @memcmp_const_size_update_deref(i8 addrspace(1)* nocapture readonly %d, i8 addrspace(1)* nocapture readonly %s) { ; CHECK-LABEL: @memcmp_const_size_update_deref( -; CHECK-NEXT: [[CALL:%.*]] = tail call i32 @memcmp(i8 addrspace(1)* noundef dereferenceable(16) dereferenceable_or_null(40) [[D:%.*]], i8* noundef nonnull dereferenceable(16) [[S:%.*]], i64 16) +; CHECK-NEXT: [[CALL:%.*]] = tail call i32 @memcmp(i8 addrspace(1)* noundef dereferenceable(16) dereferenceable_or_null(40) [[D:%.*]], i8 addrspace(1)* noundef dereferenceable(16) [[S:%.*]], i64 16) ; CHECK-NEXT: ret i32 [[CALL]] ; - %call = tail call i32 @memcmp(i8 addrspace(1)* dereferenceable_or_null(40) %d, i8* %s, i64 16) + %call = tail call i32 @memcmp(i8 addrspace(1)* dereferenceable_or_null(40) %d, i8 addrspace(1)* %s, i64 16) ret i32 %call } -define i32 @memcmp_nonconst_size_nonnnull(i8 addrspace(1)* nocapture readonly %d, i8* nocapture readonly %s, i64 %n) { +define i32 @memcmp_nonconst_size_nonnnull(i8 addrspace(1)* nocapture readonly %d, i8 addrspace(1)* nocapture readonly %s, i64 %n) { ; CHECK-LABEL: @memcmp_nonconst_size_nonnnull( -; CHECK-NEXT: [[CALL:%.*]] = tail call i32 @memcmp(i8 addrspace(1)* nonnull dereferenceable_or_null(40) [[D:%.*]], i8* nonnull [[S:%.*]], i64 [[N:%.*]]) +; CHECK-NEXT: [[CALL:%.*]] = tail call i32 @memcmp(i8 addrspace(1)* nonnull dereferenceable_or_null(40) [[D:%.*]], i8 addrspace(1)* nonnull [[S:%.*]], i64 [[N:%.*]]) ; CHECK-NEXT: ret i32 [[CALL]] ; - %call = tail call i32 @memcmp(i8 addrspace(1)* nonnull dereferenceable_or_null(40) %d, i8* nonnull %s, i64 %n) + %call = tail call i32 @memcmp(i8 addrspace(1)* nonnull dereferenceable_or_null(40) %d, i8 addrspace(1)* nonnull %s, i64 %n) ret i32 %call } diff --git a/llvm/test/Transforms/InstCombine/sprintf-3.ll b/llvm/test/Transforms/InstCombine/sprintf-3.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/sprintf-3.ll @@ -0,0 +1,24 @@ +; Test that the stpcpy library call simplifier works correctly. +; +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -passes=instcombine -S | FileCheck %s +; +; This transformation requires the pointer size, as it assumes that size_t is +; the size of a pointer. + +@percent_s = constant [3 x i8] c"%s\00" + +declare i32 @sprintf(i8**, i32*, ...) + +; The libcall prototype checker does not check for exact pointer type +; (just pointer of some type), so we identify this as a standard sprintf +; call. This requires a cast to operate on mismatched pointer types. + +define i32 @PR51200(i8** %p, i32* %p2) { +; CHECK-LABEL: @PR51200( +; CHECK-NEXT: [[CALL:%.*]] = call i32 (i8**, i32*, ...) @sprintf(i8** [[P:%.*]], i32* bitcast ([3 x i8]* @percent_s to i32*), i32* [[P2:%.*]]) +; CHECK-NEXT: ret i32 [[CALL]] +; + %call = call i32 (i8**, i32*, ...) @sprintf(i8** %p, i32* bitcast ([3 x i8]* @percent_s to i32*), i32* %p2) + ret i32 %call +} diff --git a/llvm/test/Transforms/InstCombine/stpcpy-1.ll b/llvm/test/Transforms/InstCombine/stpcpy-1.ll --- a/llvm/test/Transforms/InstCombine/stpcpy-1.ll +++ b/llvm/test/Transforms/InstCombine/stpcpy-1.ll @@ -11,7 +11,6 @@ @b = common global [32 x i8] zeroinitializer, align 1 @percent_s = constant [3 x i8] c"%s\00" -declare i32 @sprintf(i8**, i32*, ...) declare i8* @stpcpy(i8*, i8*) define i8* @test_simplify1() { @@ -76,21 +75,3 @@ %ret = call dereferenceable(1) i8* @stpcpy(i8* %dst, i8* %src) ret i8* %ret } - -; The libcall prototype checker does not check for exact pointer type -; (just pointer of some type), so we identify this as a standard sprintf -; call. This requires a cast to operate on mismatched pointer types. - -define i32 @PR51200(i8** %p, i32* %p2) { -; CHECK-LABEL: @PR51200( -; CHECK-NEXT: [[CSTR:%.*]] = bitcast i8** [[P:%.*]] to i8* -; CHECK-NEXT: [[CSTR1:%.*]] = bitcast i32* [[P2:%.*]] to i8* -; CHECK-NEXT: [[STPCPY:%.*]] = call i8* @stpcpy(i8* [[CSTR]], i8* [[CSTR1]]) -; CHECK-NEXT: [[TMP1:%.*]] = ptrtoint i8* [[STPCPY]] to i32 -; CHECK-NEXT: [[TMP2:%.*]] = ptrtoint i8** [[P]] to i32 -; CHECK-NEXT: [[TMP3:%.*]] = sub i32 [[TMP1]], [[TMP2]] -; CHECK-NEXT: ret i32 [[TMP3]] -; - %call = call i32 (i8**, i32*, ...) @sprintf(i8** %p, i32* bitcast ([3 x i8]* @percent_s to i32*), i32* %p2) - ret i32 %call -} diff --git a/llvm/test/Transforms/InstCombine/str-int.ll b/llvm/test/Transforms/InstCombine/str-int.ll --- a/llvm/test/Transforms/InstCombine/str-int.ll +++ b/llvm/test/Transforms/InstCombine/str-int.ll @@ -13,8 +13,8 @@ declare i32 @strtol(i8*, i8**, i32) declare i32 @atoi(i8*) declare i32 @atol(i8*) -declare i32 @atoll(i8*) -declare i32 @strtoll(i8*, i8**, i32) +declare i64 @atoll(i8*) +declare i64 @strtoll(i8*, i8**, i32) define i32 @strtol_dec() #0 { ; CHECK-LABEL: @strtol_dec( @@ -128,21 +128,19 @@ ret i32 %call } -define i32 @atoll_test() #0 { +define i64 @atoll_test() #0 { ; CHECK-LABEL: @atoll_test( -; CHECK-NEXT: [[CALL:%.*]] = call i32 @atoll(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.5, i64 0, i64 0)) -; CHECK-NEXT: ret i32 [[CALL]] +; CHECK-NEXT: ret i64 4994967295 ; - %call = call i32 @atoll(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.5, i32 0, i32 0)) #3 - ret i32 %call + %call = call i64 @atoll(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.5, i32 0, i32 0)) #3 + ret i64 %call } -define i32 @strtoll_test() #0 { +define i64 @strtoll_test() #0 { ; CHECK-LABEL: @strtoll_test( -; CHECK-NEXT: [[CALL:%.*]] = call i32 @strtoll(i8* nocapture getelementptr inbounds ([11 x i8], [11 x i8]* @.str.7, i64 0, i64 0), i8** null, i32 10) -; CHECK-NEXT: ret i32 [[CALL]] +; CHECK-NEXT: ret i64 4994967295 ; ; CHECK-NEXT - %call = call i32 @strtoll(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.7, i32 0, i32 0), i8** null, i32 10) #5 - ret i32 %call + %call = call i64 @strtoll(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.7, i32 0, i32 0), i8** null, i32 10) #5 + ret i64 %call } diff --git a/llvm/test/Transforms/InstCombine/strcall-bad-sig.ll b/llvm/test/Transforms/InstCombine/strcall-bad-sig.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/strcall-bad-sig.ll @@ -0,0 +1,177 @@ +; Verify that calls to known string library functions declared with +; incompatible signatures are handled gracefully and without aborting. +; +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -passes=instcombine -opaque-pointers -S | FileCheck %s + +@a = constant [2 x i8] c"1\00" + +declare ptr @atoi(ptr) +declare ptr @atol(ptr) +declare ptr @atoll(ptr) + +define void @call_bad_ato(ptr %ps) { +; CHECK-LABEL: @call_bad_ato( +; CHECK-NEXT: [[IR:%.*]] = call ptr @atoi(ptr nonnull @a) +; CHECK-NEXT: store ptr [[IR]], ptr [[PS:%.*]], align 8 +; CHECK-NEXT: [[LR:%.*]] = call ptr @atol(ptr nonnull @a) +; CHECK-NEXT: [[PS1:%.*]] = getelementptr ptr, ptr [[PS]], i64 1 +; CHECK-NEXT: store ptr [[LR]], ptr [[PS1]], align 8 +; CHECK-NEXT: [[LLR:%.*]] = call ptr @atol(ptr nonnull @a) +; CHECK-NEXT: [[PS2:%.*]] = getelementptr ptr, ptr [[PS]], i64 2 +; CHECK-NEXT: store ptr [[LLR]], ptr [[PS2]], align 8 +; CHECK-NEXT: ret void +; + %p = getelementptr [2 x i8], [2 x i8]* @a, i32 0, i32 0 + + %ir = call ptr @atoi(ptr %p) + %ps0 = getelementptr ptr, ptr %ps, i32 0 + store ptr %ir, ptr %ps0 + + %lr = call ptr @atol(ptr %p) + %ps1 = getelementptr ptr, ptr %ps, i32 1 + store ptr %lr, ptr %ps1 + + %llr = call ptr @atol(ptr %p) + %ps2 = getelementptr ptr, ptr %ps, i32 2 + store ptr %llr, ptr %ps2 + + ret void +} + + +declare ptr @strncasecmp(ptr, ptr) + +define ptr @call_bad_strncasecmp() { +; CHECK-LABEL: @call_bad_strncasecmp( +; CHECK-NEXT: [[CMP:%.*]] = call ptr @strncasecmp(ptr nonnull @a, ptr getelementptr inbounds ([2 x i8], ptr @a, i64 0, i64 1)) +; CHECK-NEXT: ret ptr [[CMP]] +; + %p0 = getelementptr [2 x i8], [2 x i8]* @a, i32 0, i32 0 + %p1 = getelementptr [2 x i8], [2 x i8]* @a, i32 0, i32 1 + %cmp = call ptr @strncasecmp(ptr %p0, ptr %p1) + ret ptr %cmp +} + + +declare i1 @strcoll(ptr, ptr, ptr) + +define i1 @call_bad_strcoll() { +; CHECK-LABEL: @call_bad_strcoll( +; CHECK-NEXT: [[I:%.*]] = call i1 @strcoll(ptr nonnull @a, ptr getelementptr inbounds ([2 x i8], ptr @a, i64 0, i64 1), ptr nonnull @a) +; CHECK-NEXT: ret i1 [[I]] +; + %p0 = getelementptr [2 x i8], [2 x i8]* @a, i32 0, i32 0 + %p1 = getelementptr [2 x i8], [2 x i8]* @a, i32 0, i32 1 + %i = call i1 @strcoll(ptr %p0, ptr %p1, ptr %p0) + ret i1 %i +} + + +declare ptr @strndup(ptr) + +define ptr @call_bad_strndup() { +; CHECK-LABEL: @call_bad_strndup( +; CHECK-NEXT: [[D:%.*]] = call ptr @strndup(ptr nonnull @a) +; CHECK-NEXT: ret ptr [[D]] +; + %p = getelementptr [2 x i8], [2 x i8]* @a, i32 0, i32 0 + %d = call ptr @strndup(ptr %p) + ret ptr %d +} + + +declare i1 @strtok(ptr, ptr, i1) + +define i1 @call_bad_strtok() { +; CHECK-LABEL: @call_bad_strtok( +; CHECK-NEXT: [[RET:%.*]] = call i1 @strtok(ptr nonnull @a, ptr getelementptr inbounds ([2 x i8], ptr @a, i64 0, i64 1), i1 false) +; CHECK-NEXT: ret i1 [[RET]] +; + %p0 = getelementptr [2 x i8], [2 x i8]* @a, i32 0, i32 0 + %p1 = getelementptr [2 x i8], [2 x i8]* @a, i32 0, i32 1 + %ret = call i1 @strtok(ptr %p0, ptr %p1, i1 0) + ret i1 %ret +} + + + +declare i1 @strtok_r(ptr, ptr) + +define i1 @call_bad_strtok_r() { +; CHECK-LABEL: @call_bad_strtok_r( +; CHECK-NEXT: [[RET:%.*]] = call i1 @strtok_r(ptr nonnull @a, ptr getelementptr inbounds ([2 x i8], ptr @a, i64 0, i64 1)) +; CHECK-NEXT: ret i1 [[RET]] +; + %p0 = getelementptr [2 x i8], [2 x i8]* @a, i32 0, i32 0 + %p1 = getelementptr [2 x i8], [2 x i8]* @a, i32 0, i32 1 + %ret = call i1 @strtok_r(ptr %p0, ptr %p1) + ret i1 %ret +} + + +declare i32 @strtol(ptr, ptr) +declare i32 @strtoul(ptr, ptr) + +declare i64 @strtoll(ptr, ptr) +declare i64 @strtoull(ptr, ptr) + +define void @call_bad_strto(i32* %psi32, i64* %psi64) { +; CHECK-LABEL: @call_bad_strto( +; CHECK-NEXT: [[LR:%.*]] = call i32 @strtol(ptr nonnull @a, ptr null) +; CHECK-NEXT: store i32 [[LR]], ptr [[PSI32:%.*]], align 4 +; CHECK-NEXT: [[ULR:%.*]] = call i32 @strtoul(ptr nonnull @a, ptr null) +; CHECK-NEXT: [[PS1:%.*]] = getelementptr i32, ptr [[PSI32]], i64 1 +; CHECK-NEXT: store i32 [[ULR]], ptr [[PS1]], align 4 +; CHECK-NEXT: [[LLR:%.*]] = call i64 @strtoll(ptr nonnull @a, ptr null) +; CHECK-NEXT: store i64 [[LLR]], ptr [[PSI64:%.*]], align 4 +; CHECK-NEXT: [[ULLR:%.*]] = call i64 @strtoull(ptr nonnull @a, ptr null) +; CHECK-NEXT: [[PS3:%.*]] = getelementptr i64, ptr [[PSI64]], i64 3 +; CHECK-NEXT: store i64 [[ULLR]], ptr [[PS3]], align 4 +; CHECK-NEXT: ret void +; + %p = getelementptr [2 x i8], [2 x i8]* @a, i32 0, i32 0 + + %lr = call i32 @strtol(ptr %p, ptr null) + %ps0 = getelementptr i32, i32* %psi32, i32 0 + store i32 %lr, i32* %ps0 + + %ulr = call i32 @strtoul(ptr %p, ptr null) + %ps1 = getelementptr i32, i32* %psi32, i32 1 + store i32 %ulr, i32* %ps1 + + %llr = call i64 @strtoll(ptr %p, ptr null) + %ps2 = getelementptr i64, i64* %psi64, i32 0 + store i64 %llr, i64* %ps2 + + %ullr = call i64 @strtoull(ptr %p, ptr null) + %ps3 = getelementptr i64, i64* %psi64, i32 3 + store i64 %ullr, i64* %ps3 + + ret void +} + + +declare ptr @strxfrm(ptr, ptr) + +define ptr @call_bad_strxfrm() { +; CHECK-LABEL: @call_bad_strxfrm( +; CHECK-NEXT: [[RET:%.*]] = call ptr @strxfrm(ptr nonnull @a, ptr getelementptr inbounds ([2 x i8], ptr @a, i64 0, i64 1)) +; CHECK-NEXT: ret ptr [[RET]] +; + %p0 = getelementptr [2 x i8], [2 x i8]* @a, i32 0, i32 0 + %p1 = getelementptr [2 x i8], [2 x i8]* @a, i32 0, i32 1 + %ret = call ptr @strxfrm(ptr %p0, ptr %p1) + ret ptr %ret +} + + +@s = constant [3 x i8] c"%s\00" + +declare i32 @sprintf(i8**, i32*, ...) + +define void @PR53463(i8** %p, i32* %q) { + %fmt = bitcast [3 x i8]* @s to i32* + %call = call i32 (i8**, i32*, ...) @sprintf(i8** %p, i32* %fmt, i32* %q) + ret void +} \ No newline at end of file diff --git a/llvm/test/Transforms/InstCombine/strndup.ll b/llvm/test/Transforms/InstCombine/strndup.ll --- a/llvm/test/Transforms/InstCombine/strndup.ll +++ b/llvm/test/Transforms/InstCombine/strndup.ll @@ -4,7 +4,7 @@ @hello = constant [6 x i8] c"hello\00" @null = constant [1 x i8] zeroinitializer -declare i8* @strndup(i8*, i32) +declare i8* @strndup(i8*, i64) define i8* @test1() { ; CHECK-LABEL: @test1( @@ -12,17 +12,17 @@ ; CHECK-NEXT: ret i8* [[STRDUP]] ; %src = getelementptr [1 x i8], [1 x i8]* @null, i32 0, i32 0 - %ret = call i8* @strndup(i8* %src, i32 0) + %ret = call i8* @strndup(i8* %src, i64 0) ret i8* %ret } define i8* @test2() { ; CHECK-LABEL: @test2( -; CHECK-NEXT: [[RET:%.*]] = call dereferenceable_or_null(5) i8* @strndup(i8* dereferenceable(6) getelementptr inbounds ([6 x i8], [6 x i8]* @hello, i64 0, i64 0), i32 4) +; CHECK-NEXT: [[RET:%.*]] = call dereferenceable_or_null(5) i8* @strndup(i8* dereferenceable(6) getelementptr inbounds ([6 x i8], [6 x i8]* @hello, i64 0, i64 0), i64 4) ; CHECK-NEXT: ret i8* [[RET]] ; %src = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0 - %ret = call i8* @strndup(i8* %src, i32 4) + %ret = call i8* @strndup(i8* %src, i64 4) ret i8* %ret } @@ -32,7 +32,7 @@ ; CHECK-NEXT: ret i8* [[STRDUP]] ; %src = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0 - %ret = call i8* @strndup(i8* %src, i32 5) + %ret = call i8* @strndup(i8* %src, i64 5) ret i8* %ret } @@ -42,7 +42,7 @@ ; CHECK-NEXT: ret i8* [[STRDUP]] ; %src = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0 - %ret = call i8* @strndup(i8* %src, i32 6) + %ret = call i8* @strndup(i8* %src, i64 6) ret i8* %ret } @@ -52,16 +52,16 @@ ; CHECK-NEXT: ret i8* [[STRDUP]] ; %src = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0 - %ret = call i8* @strndup(i8* %src, i32 7) + %ret = call i8* @strndup(i8* %src, i64 7) ret i8* %ret } -define i8* @test6(i32 %n) { +define i8* @test6(i64 %n) { ; CHECK-LABEL: @test6( -; CHECK-NEXT: [[RET:%.*]] = call i8* @strndup(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @hello, i64 0, i64 0), i32 [[N:%.*]]) +; CHECK-NEXT: [[RET:%.*]] = call i8* @strndup(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @hello, i64 0, i64 0), i64 [[N:%.*]]) ; CHECK-NEXT: ret i8* [[RET]] ; %src = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0 - %ret = call i8* @strndup(i8* %src, i32 %n) + %ret = call i8* @strndup(i8* %src, i64 %n) ret i8* %ret } diff --git a/llvm/test/Transforms/InstCombine/strspn-1.ll b/llvm/test/Transforms/InstCombine/strspn-1.ll --- a/llvm/test/Transforms/InstCombine/strspn-1.ll +++ b/llvm/test/Transforms/InstCombine/strspn-1.ll @@ -2,8 +2,6 @@ ; ; RUN: opt < %s -passes=instcombine -S | FileCheck %s -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" - @abcba = constant [6 x i8] c"abcba\00" @abc = constant [4 x i8] c"abc\00" @null = constant [1 x i8] zeroinitializer diff --git a/llvm/test/Transforms/InstCombine/strto-1.ll b/llvm/test/Transforms/InstCombine/strto-1.ll --- a/llvm/test/Transforms/InstCombine/strto-1.ll +++ b/llvm/test/Transforms/InstCombine/strto-1.ll @@ -4,14 +4,14 @@ 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 i32 @strtol(i8* %s, i8** %endptr, i32 %base) +; CHECK: declare i32 @strtol(i8* 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* %s, i8** %endptr) +; CHECK: declare double @strtod(i8* readonly, i8** nocapture) -declare float @strtof(i8* %s, i8** %endptr, i32 %base) -; CHECK: declare float @strtof(i8* readonly, i8** nocapture, i32) +declare float @strtof(i8* %s, i8** %endptr) +; CHECK: declare float @strtof(i8* readonly, i8** nocapture) declare i64 @strtoul(i8* %s, i8** %endptr, i32 %base) ; CHECK: declare i64 @strtoul(i8* readonly, i8** nocapture, i32) @@ -27,22 +27,22 @@ define void @test_simplify1(i8* %x, i8** %endptr) { ; CHECK-LABEL: @test_simplify1( - call i64 @strtol(i8* %x, i8** null, i32 10) -; CHECK-NEXT: call i64 @strtol(i8* nocapture %x, i8** null, i32 10) + call i32 @strtol(i8* %x, i8** null, i32 10) +; CHECK-NEXT: call i32 @strtol(i8* nocapture %x, i8** null, i32 10) ret void } define void @test_simplify2(i8* %x, i8** %endptr) { ; CHECK-LABEL: @test_simplify2( - call double @strtod(i8* %x, i8** null, i32 10) -; CHECK-NEXT: call double @strtod(i8* nocapture %x, i8** null, i32 10) + call double @strtod(i8* %x, i8** null) +; CHECK-NEXT: call double @strtod(i8* nocapture %x, i8** null) ret void } define void @test_simplify3(i8* %x, i8** %endptr) { ; CHECK-LABEL: @test_simplify3( - call float @strtof(i8* %x, i8** null, i32 10) -; CHECK-NEXT: call float @strtof(i8* nocapture %x, i8** null, i32 10) + call float @strtof(i8* %x, i8** null) +; CHECK-NEXT: call float @strtof(i8* nocapture %x, i8** null) ret void } @@ -76,7 +76,7 @@ define void @test_no_simplify1(i8* %x, i8** %endptr) { ; CHECK-LABEL: @test_no_simplify1( - call i64 @strtol(i8* %x, i8** %endptr, i32 10) -; CHECK-NEXT: call i64 @strtol(i8* %x, i8** %endptr, i32 10) + call i32 @strtol(i8* %x, i8** %endptr, i32 10) +; CHECK-NEXT: call i32 @strtol(i8* %x, i8** %endptr, i32 10) ret void } diff --git a/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp b/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp --- a/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp +++ b/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp @@ -322,8 +322,8 @@ "declare i8* @strtok(i8*, i8*)\n" "declare i8* @strtok_r(i8*, i8*, i8**)\n" "declare i64 @strtol(i8*, i8**, i32)\n" - "declare i64 @strlcat(i8*, i8**, i64)\n" - "declare i64 @strlcpy(i8*, i8**, i64)\n" + "declare i64 @strlcat(i8*, i8*, i64)\n" + "declare i64 @strlcpy(i8*, i8*, i64)\n" "declare x86_fp80 @strtold(i8*, i8**)\n" "declare i64 @strtoll(i8*, i8**, i32)\n" "declare i64 @strtoul(i8*, i8**, i32)\n" @@ -482,7 +482,7 @@ "declare i8* @__stpncpy_chk(i8*, i8*, i64, i64)\n" "declare i8* @__strcpy_chk(i8*, i8*, i64)\n" "declare i8* @__strncpy_chk(i8*, i8*, i64, i64)\n" - "declare i8* @__memccpy_chk(i8*, i8*, i32, i64)\n" + "declare i8* @__memccpy_chk(i8*, i8*, i32, i64, i64)\n" "declare i8* @__mempcpy_chk(i8*, i8*, i64, i64)\n" "declare i32 @__snprintf_chk(i8*, i64, i32, i64, i8*, ...)\n" "declare i32 @__sprintf_chk(i8*, i32, i64, i8*, ...)\n"