Index: llvm/lib/Analysis/TargetLibraryInfo.cpp =================================================================== --- llvm/lib/Analysis/TargetLibraryInfo.cpp +++ llvm/lib/Analysis/TargetLibraryInfo.cpp @@ -912,112 +912,669 @@ return false; } -bool TargetLibraryInfoImpl::isValidProtoForLibFunc(const FunctionType &FTy, - LibFunc F, - const Module &M) const { - // FIXME: There is really no guarantee that sizeof(size_t) is equal to - // sizeof(int*) for every target. So the assumption used here to derive the - // SizeTBits based on the size of an integer pointer in address space zero - // isn't always valid. - unsigned SizeTBits = M.getDataLayout().getPointerSizeInBits(/*AddrSpace=*/0); - unsigned NumParams = FTy.getNumParams(); +// Recognized types of library function arguments and return types. +enum FuncArgTypeID: char { + Void = 0, // Must be zero. + Bool, // 8 bits on all targets + Int16, + Int32, + Int, + Long, // Either 32 or 64 bits. + IntX, // Any integer type. + Int64, + LLong, // 64 bits on all targets. + SizeT, // size_t. + SSizeT, // POSIX ssize_t. + Flt, // IEEE float. + Dbl, // IEEE double. + LDbl, // Any floating type (TODO: tighten this up). + Floating, // Any floating type. + Ptr, // Any pointer type. + Struct, // Any struct type. + Ellip, // The ellipsis (...). + Same, // Same as previous. +}; + +// Return true if ArgTy matches Ty. + +bool MatchType(FuncArgTypeID ArgTy, const Type *Ty, unsigned IntBits, + unsigned SizeTBits) { + switch (ArgTy) { + case Void: return Ty->isVoidTy(); + case Bool: return Ty->isIntegerTy(8); + case Int16: return Ty->isIntegerTy(16); + case Int32: return Ty->isIntegerTy(32); + case Int: return Ty->isIntegerTy(IntBits); + case IntX: return Ty->isIntegerTy(); + // TODO: Figure out and use long size. + case Long: return Ty->isIntegerTy(); + case Int64: return Ty->isIntegerTy(64); + case LLong: return Ty->isIntegerTy(64); + case SizeT: + case SSizeT: return Ty->isIntegerTy(SizeTBits); + case Flt: return Ty->isFloatTy(); + case Dbl: return Ty->isDoubleTy(); + // TODO: Tighten this up. + case LDbl: return Ty->isFloatingPointTy(); + case Floating: return Ty->isFloatingPointTy(); + case Ptr: return Ty->isPointerTy(); + case Struct: return Ty->isStructTy(); + default: break; + } + llvm_unreachable("Invalid type"); +} + +typedef std::array FuncProtoTy; + +// Return an std::array of type IDs corresponding to function F's proototype, +// starting with its return tyoe. The last non-Void element of the array is +// Ellip if is a variadic function. + +static FuncProtoTy getLibFuncProto(LibFunc F) +{ switch (F) { - case LibFunc_execl: - case LibFunc_execlp: - case LibFunc_execle: - return (NumParams >= 2 && FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(1)->isPointerTy() && - FTy.getReturnType()->isIntegerTy(32)); - case LibFunc_execv: - case LibFunc_execvp: - return (NumParams == 2 && FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(1)->isPointerTy() && - FTy.getReturnType()->isIntegerTy(32)); - case LibFunc_execvP: - case LibFunc_execvpe: - case LibFunc_execve: - return (NumParams == 3 && FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(1)->isPointerTy() && - FTy.getParamType(2)->isPointerTy() && - FTy.getReturnType()->isIntegerTy(32)); + // functions: + case LibFunc_isdigit: + case LibFunc_isascii: + case LibFunc_toascii: + // int (int) + return {Int, Int}; - case LibFunc_strlen_chk: - --NumParams; - if (!FTy.getParamType(NumParams)->isIntegerTy(SizeTBits)) - return false; - LLVM_FALLTHROUGH; - case LibFunc_strlen: - return NumParams == 1 && FTy.getParamType(0)->isPointerTy() && - FTy.getReturnType()->isIntegerTy(SizeTBits); + // functions: + case LibFunc_acos: + case LibFunc_acos_finite: + case LibFunc_acosh: + case LibFunc_acosh_finite: + case LibFunc_asin: + case LibFunc_asin_finite: + case LibFunc_asinh: + case LibFunc_atan: + case LibFunc_atanh: + case LibFunc_atanh_finite: + case LibFunc_cbrt: + case LibFunc_ceil: + case LibFunc_cos: + case LibFunc_cosh: + case LibFunc_cosh_finite: + case LibFunc_exp10: + case LibFunc_exp10_finite: + case LibFunc_exp2: + case LibFunc_exp2_finite: + case LibFunc_exp: + case LibFunc_exp_finite: + case LibFunc_expm1: + case LibFunc_fabs: + case LibFunc_floor: + case LibFunc_log10: + case LibFunc_log10_finite: + case LibFunc_log1p: + case LibFunc_log2: + case LibFunc_log2_finite: + case LibFunc_log: + case LibFunc_log_finite: + case LibFunc_logb: + case LibFunc_nearbyint: + case LibFunc_rint: + case LibFunc_round: + case LibFunc_roundeven: + case LibFunc_sin: + case LibFunc_sinh: + case LibFunc_sinh_finite: + case LibFunc_sqrt: + case LibFunc_sqrt_finite: + case LibFunc_tan: + case LibFunc_tanh: + case LibFunc_trunc: + // double (double) + return {Dbl, Dbl}; - case LibFunc_strchr: - case LibFunc_strrchr: - return (NumParams == 2 && FTy.getReturnType()->isPointerTy() && - FTy.getParamType(0) == FTy.getReturnType() && - FTy.getParamType(1)->isIntegerTy()); + case LibFunc_acosf: + case LibFunc_acosf_finite: + case LibFunc_acoshf: + case LibFunc_acoshf_finite: + case LibFunc_asinf: + case LibFunc_asinf_finite: + case LibFunc_asinhf: + case LibFunc_atanf: + case LibFunc_atanhf: + case LibFunc_atanhf_finite: + case LibFunc_cbrtf: + case LibFunc_ceilf: + case LibFunc_cosf: + case LibFunc_coshf: + case LibFunc_coshf_finite: + case LibFunc_expf: + case LibFunc_expf_finite: + case LibFunc_exp10f: + case LibFunc_exp10f_finite: + case LibFunc_exp2f: + case LibFunc_exp2f_finite: + case LibFunc_expm1f: + case LibFunc_fabsf: + case LibFunc_floorf: + case LibFunc_log10f: + case LibFunc_log10f_finite: + case LibFunc_log1pf: + case LibFunc_log2f: + case LibFunc_log2f_finite: + case LibFunc_logbf: + case LibFunc_logf: + case LibFunc_logf_finite: + case LibFunc_nearbyintf: + case LibFunc_rintf: + case LibFunc_roundf: + case LibFunc_roundevenf: + case LibFunc_sinf: + case LibFunc_sinhf: + case LibFunc_sinhf_finite: + case LibFunc_sqrtf: + case LibFunc_sqrtf_finite: + case LibFunc_tanf: + case LibFunc_tanhf: + case LibFunc_truncf: + // float (float) + return {Flt, Flt}; + + case LibFunc_acoshl: + case LibFunc_acoshl_finite: + case LibFunc_acosl: + case LibFunc_acosl_finite: + case LibFunc_asinhl: + case LibFunc_asinl: + case LibFunc_asinl_finite: + case LibFunc_atanhl: + case LibFunc_atanhl_finite: + case LibFunc_atanl: + case LibFunc_cbrtl: + case LibFunc_ceill: + case LibFunc_coshl: + case LibFunc_coshl_finite: + case LibFunc_cosl: + case LibFunc_exp10l: + case LibFunc_exp10l_finite: + case LibFunc_exp2l: + case LibFunc_exp2l_finite: + case LibFunc_expl: + case LibFunc_expl_finite: + case LibFunc_expm1l: + case LibFunc_fabsl: + case LibFunc_floorl: + case LibFunc_log10l: + case LibFunc_log10l_finite: + case LibFunc_log1pl: + case LibFunc_log2l: + case LibFunc_log2l_finite: + case LibFunc_logbl: + case LibFunc_logl: + case LibFunc_logl_finite: + case LibFunc_nearbyintl: + case LibFunc_rintl: + case LibFunc_roundl: + case LibFunc_roundevenl: + case LibFunc_sinhl: + case LibFunc_sinhl_finite: + case LibFunc_sinl: + case LibFunc_sqrtl: + case LibFunc_sqrtl_finite: + case LibFunc_tanhl: + case LibFunc_tanl: + case LibFunc_truncl: + // long double (long double) + return {LDbl, LDbl}; + + case LibFunc_atan2: + case LibFunc_atan2_finite: + case LibFunc_fmod: + case LibFunc_remainder: + case LibFunc_copysign: + case LibFunc_pow: + case LibFunc_pow_finite: + // double (double, double) + return {Dbl, Dbl, Dbl}; + + case LibFunc_atan2f: + case LibFunc_atan2f_finite: + case LibFunc_fmodf: + case LibFunc_remainderf: + case LibFunc_copysignf: + case LibFunc_powf: + case LibFunc_powf_finite: + // float (float, float) + return {Flt, Flt, Flt}; + + case LibFunc_atan2l: + case LibFunc_atan2l_finite: + case LibFunc_fmodl: + case LibFunc_remainderl: + case LibFunc_copysignl: + case LibFunc_powl: + case LibFunc_powl_finite: + // long double (long double, long double) + return {LDbl, LDbl, LDbl}; + + case LibFunc_ldexp: + // double (double, int) + return {Dbl, Same, Int}; + case LibFunc_ldexpf: + // float (float, int) + return {Flt, Same, Int}; + case LibFunc_ldexpl: + // long double (long double, int) + return {LDbl, Same, Int}; + + case LibFunc_frexp: + // double (double, int*) + case LibFunc_modf: + // double (double, double*) + return {Dbl, Dbl, Ptr}; + + case LibFunc_frexpf: + // float (float, int*) + case LibFunc_modff: + // float (float, float*) + return {Flt, Flt, Ptr}; + + case LibFunc_frexpl: + // long double (long double, int*) + case LibFunc_modfl: + // long double (long double, long double*) + return {LDbl, LDbl, Ptr}; + + // Calls to fmin and fmax library functions expand to the llvm.minnum + // and llvm.maxnum intrinsics with the correct parameter types for + // the arguments (all types must match). + case LibFunc_fmin: + case LibFunc_fmax: + case LibFunc_fminl: + case LibFunc_fmaxl: + case LibFunc_fminf: + case LibFunc_fmaxf: + return {Floating, Same, Same}; + + // functions: + case LibFunc_getpwnam: + return {Ptr, Ptr}; + + case LibFunc_sinpi: + case LibFunc_cospi: + return {Dbl, Dbl}; + + case LibFunc_sinpif: + case LibFunc_cospif: + return {Flt, Flt}; + + // functions: + case LibFunc_setbuf: + // void (FILE*, char*) + return {Void, Ptr, Ptr}; + + case LibFunc_setvbuf: + // int (FILE*, char*, int, size_t) + return {Int, Ptr, Ptr, Int, SizeT}; + + case LibFunc_iprintf: + case LibFunc_small_printf: + case LibFunc_printf: + case LibFunc_scanf: + case LibFunc_dunder_isoc99_scanf: + // int (const char*, ...) + return {Int, Ptr, Ellip}; + + case LibFunc_fscanf: + case LibFunc_fiprintf: + case LibFunc_small_fprintf: + case LibFunc_fprintf: + // int (FILE*, const char*, ...) + case LibFunc_sscanf: + case LibFunc_dunder_isoc99_sscanf: + // int (const char*, const char*, ...) + case LibFunc_siprintf: + case LibFunc_small_sprintf: + case LibFunc_sprintf: + // int (char*, const char*, ...) + return {Int, Ptr, Ptr, Ellip}; + + case LibFunc_sprintf_chk: + // int (char*, int, size_t, const char*, ...) + return {Int, Ptr, Int, SizeT, Ptr, Ellip}; + + case LibFunc_snprintf: + // int (char*, size_t, const char*, ...) + return {Int, Ptr, SizeT, Ptr, Ellip}; + + case LibFunc_snprintf_chk: + // int (char*, size_t, int, size_t, const char*, ...) + return {Int, Ptr, SizeT, Int, SizeT, Ptr, Ellip}; + + case LibFunc_rmdir: + case LibFunc_remove: + // int (const char*) + return {Int, Ptr}; + + case LibFunc_realpath: + // char* (const char*, char*) + return {Ptr, Ptr, Ptr}; + + case LibFunc_rename: + // int (const char*, const char*) + return {Int, Ptr, Ptr}; + + case LibFunc_readlink: + // ssize_t (const char*, char*, size_t) + return {SSizeT, Ptr, Ptr, SizeT}; + + case LibFunc_write: + // ssize_t (int, const void*, size_t) + return {SSizeT, Int, Ptr, SizeT}; + + case LibFunc_clearerr: + case LibFunc_flockfile: + case LibFunc_funlockfile: + case LibFunc_rewind: + // void (FILE*) + return {Void, Ptr}; + case LibFunc_perror: + // void (const char*) + return {Void, Ptr}; + + case LibFunc_fclose: + case LibFunc_ferror: + case LibFunc_fgetc: + case LibFunc_fgetc_unlocked: + case LibFunc_feof: + case LibFunc_fflush: + case LibFunc_fileno: + case LibFunc_getc: + case LibFunc_under_IO_getc: + case LibFunc_getc_unlocked: + // int (FILE*) + case LibFunc_closedir: + // int (DIR*) + case LibFunc_pclose: + // int (FILE*) + case LibFunc_puts: + // int (const char*) + return {Int, Ptr}; + + case LibFunc_access: + // int (const char*, int) + return {Int, Ptr, Int}; + + case LibFunc_chmod: + case LibFunc_mkdir: + // int (const char*, mode_t) + return {Int, Ptr, IntX}; + + case LibFunc_ctermid: + // char* (char*) + return {Ptr, Ptr}; + + case LibFunc_fseek: + // int (FILE*, long, int) + case LibFunc_fseeko: + // int (FILE*, off_t, int) + return {Int, Ptr, IntX, Int}; + case LibFunc_fseeko64: + // int (FILE*, off64_t, int) + return {Int, Ptr, Int64, Int}; + + case LibFunc_fsetpos: + // int (FILE*, const fpos_t*) + return {Int, Ptr, Ptr}; + + case LibFunc_ftell: + // long (FILE*) + return {Long, Ptr}; + + case LibFunc_ftello: + // off_t (FILE*) + return {IntX, Ptr}; + + case LibFunc_ftello64: + // off64_t (FILE*) + return {Int64, Ptr}; + + case LibFunc_ftrylockfile: + // int (FILE*) + return {Int, Ptr}; + + case LibFunc_fopen: + case LibFunc_fopen64: + case LibFunc_popen: + // FILE* (const char*, const char*) + return {Ptr, Ptr, Ptr}; + + case LibFunc_fdopen: + // FILE* (int, const char*) + return {Ptr, Int, Ptr}; + + case LibFunc_fstat: + // int (int, struct stat*) + case LibFunc_fstat64: + // int (int, struct stat64*) + case LibFunc_fputc: + case LibFunc_fputc_unlocked: + // int (int, FILE*) + case LibFunc_fstatvfs: + // int (int, struct statvfs*) + case LibFunc_fstatvfs64: + // int (int, struct statvfs64*) + return {Int, Int, Ptr}; + + case LibFunc_fgets: + case LibFunc_fgets_unlocked: + // char* (char*, int, FILE*) + return {Ptr, Ptr, Int, Ptr}; + + case LibFunc_fread: + case LibFunc_fread_unlocked: + // size_t (void*, size_t, size_t, FILE*) + case LibFunc_fwrite: + case LibFunc_fwrite_unlocked: + // size_t (const void*, size_t, size_t, FILE*) + return {SizeT, Ptr, SizeT, SizeT, Ptr}; + + case LibFunc_fputs: + case LibFunc_fputs_unlocked: + // int (const char*, FILE*) + case LibFunc_fgetpos: + // int (FILE*, fpos_t*) + return {Int, Ptr, Ptr}; + return {Int, Ptr, Ptr}; + + case LibFunc_getchar: + case LibFunc_getchar_unlocked: + // int (void) + return {Int, Void}; + + case LibFunc_gets: + // char* (char*) + return {Ptr, Ptr}; + + case LibFunc_ungetc: + case LibFunc_putc: + case LibFunc_putc_unlocked: + case LibFunc_under_IO_putc: + // int (int, FILE*) + return {Int, Int, Ptr}; + + case LibFunc_putchar: + case LibFunc_putchar_unlocked: + return {Int, Int}; + + case LibFunc_pread: + // ssize_t (int, void*, size_t, off_t); + case LibFunc_pwrite: + // ssize_t (int, const void*, size_t, off_t); + return {SSizeT, Int, Ptr, SizeT, IntX}; + + case LibFunc_vprintf: + case LibFunc_vscanf: + // int (const char*, va_list) + return {Int, Ptr, Ptr}; + + case LibFunc_vfprintf: + case LibFunc_vfscanf: + // int (const FILE*, const char*, va_list) + case LibFunc_vsprintf: + // int (char*, const char*, va_list) + case LibFunc_vsscanf: + // int (const char*, const char*, va_list) + return {Int, Ptr, Ptr, Ptr}; + + case LibFunc_vsprintf_chk: + // int (char*, int, size_t, const char*, va_list) + return {Int, Ptr, Int, SizeT, Ptr, Ptr}; + + case LibFunc_vsnprintf: + // int (char*, size_t, const char*, va_list) + return {Int, Ptr, SizeT, Ptr, Ptr}; + + case LibFunc_vsnprintf_chk: + // int (char*, size_t, int, size_t, const char*, va_list) + return {Int, Ptr, SizeT, Int, SizeT, Ptr, Ptr}; + + case LibFunc_tmpfile: + case LibFunc_tmpfile64: + // FILE* (void) + return {Ptr, Void}; + + // functions (including ): + case LibFunc_abs: + // int (int) + return {Int, Int}; + case LibFunc_labs: + // long (long) + return {Long, Long}; + case LibFunc_llabs: + // long long (long long) + return {LLong, LLong}; + + case LibFunc_getenv: + // char* (const char*) + return {Ptr, Ptr}; + + // TODO: + // case LibFunc_setenv: + // // int (const char*, const char*, int) + // return {Int, Ptr, Ptr, Int}; + + case LibFunc_unsetenv: + // int (const char*) + return {Int, Ptr}; + + case LibFunc_free: + case LibFunc_vec_free: + // void (void*) + return {Void, Ptr}; + + case LibFunc___kmpc_free_shared: + // void (void*, size_t) + return {Void, Ptr, SizeT}; + + case LibFunc_malloc: + case LibFunc_vec_malloc: + case LibFunc_valloc: + case LibFunc___kmpc_alloc_shared: + // void* (size_t) + return {Ptr, SizeT}; + + case LibFunc_calloc: + case LibFunc_vec_calloc: + // void* (size_t, size_t) + return {Ptr, SizeT, SizeT}; + + case LibFunc_aligned_alloc: + case LibFunc_memalign: + // void* (size_t, size_t) + return {Ptr, SizeT, SizeT}; + + case LibFunc_realloc: + case LibFunc_reallocf: + case LibFunc_vec_realloc: + // void* (void*, size_t) + return {Ptr, Ptr, SizeT}; + + case LibFunc_posix_memalign: + // int (void**, size_t, size_t) + return {Int, Ptr, SizeT, SizeT}; case LibFunc_strtod: // double (const char*, char**) - return (NumParams == 2 && FTy.getReturnType()->isDoubleTy() && - FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(1)->isPointerTy()); + return {Dbl, Ptr, Ptr}; case LibFunc_strtof: // float (const char*, char**) - return (NumParams == 2 && FTy.getReturnType()->isFloatTy() && - FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(1)->isPointerTy()); + return {Flt, Ptr, Ptr}; case LibFunc_strtold: // long double (const char*, char**) - return (NumParams == 2 && FTy.getReturnType()->isFloatingPointTy() && - FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(1)->isPointerTy()); + return {LDbl, Ptr, Ptr}; 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)); + return {Long, Ptr, Ptr, Int}; case LibFunc_strtoll: // long long (const char*, char**, int) case LibFunc_strtoull: // unsigned long long (const char*, char**, int) - return (NumParams == 3 && FTy.getReturnType()->isIntegerTy(64) && - FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(1)->isPointerTy() && - FTy.getParamType(2)->isIntegerTy(32)); + return {LLong, Ptr, Ptr, Int}; + + case LibFunc_system: + // int (const char*) + case LibFunc_atoi: + // int (const char*) + return {Int, Ptr}; + case LibFunc_atol: + // long (const char*) + return {Long, Ptr}; + case LibFunc_atoll: + // long long (const char*) + return {LLong, Ptr}; + + case LibFunc_atof: + // double (const char*) + return {Dbl, Ptr}; + + case LibFunc_qsort: + // void (void*, size_t, size_t, int (*)(const void*, const void*)) + return {Void, Ptr, SizeT, SizeT, Ptr}; + + // (and ) functions: + case LibFunc_bcopy: + // void (const void*, void*, size_t) + return {Void, Ptr, Ptr, SizeT}; + case LibFunc_bcmp: + // int (const void*, void*, size_t) + return {Int, Ptr, Ptr, SizeT}; + case LibFunc_bzero: + // void (void*, size_t) + return {Void, Ptr, SizeT}; + + case LibFunc_strlen: + return {SizeT, Ptr}; + case LibFunc_strnlen: + case LibFunc_strlen_chk: + // size_t (const char*, size_t) + return {SizeT, Ptr, SizeT}; + + case LibFunc_strchr: + case LibFunc_strrchr: + // char* (const char*, int) + return {Ptr, Ptr, Int}; - 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.getParamType(0)); + return {Ptr, Ptr, Ptr}; + case LibFunc_strcat_chk: + case LibFunc_strcpy_chk: + case LibFunc_stpcpy_chk: + // char* (char*, const char*, size_t) + return {Ptr, Ptr, Ptr, SizeT}; - 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: @@ -1026,816 +1583,421 @@ 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.getParamType(0) && - FTy.getParamType(2)->isIntegerTy(SizeTBits)); + return {Ptr, Ptr, Ptr, SizeT}; + + 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) + return {Ptr, Ptr, Ptr, SizeT, SizeT}; - 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: 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()); + return {SizeT, Ptr, Ptr, SizeT}; + + case LibFunc_strlcat_chk: + case LibFunc_strlcpy_chk: + // size_t (char*, const char*, size_t, size_t) + return {SizeT, Ptr, Ptr, SizeT, SizeT}; - case LibFunc_memset_chk: - // void* (void*, int, size_t, size_t) - --NumParams; - if (!FTy.getParamType(NumParams)->isIntegerTy(SizeTBits)) - return false; - LLVM_FALLTHROUGH; 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)); + return {Ptr, Ptr, Int, SizeT}; + case LibFunc_memset_chk: + // void* (void*, int, size_t, size_t) + return {Ptr, Ptr, Int, SizeT, SizeT}; - 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(0) && - FTy.getParamType(2)->isIntegerTy(32) && - FTy.getParamType(3)->isIntegerTy(SizeTBits)); + return {Ptr, Ptr, Ptr, Int, SizeT}; + case LibFunc_memccpy_chk: + // void* (void*, const void*, int, size_t, size_t) + return {Ptr, Ptr, Ptr, Int, SizeT, SizeT}; 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(1) == FTy.getParamType(0)); + return {Int, Ptr, Ptr}; 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(1) == FTy.getParamType(0) && - FTy.getParamType(2)->isIntegerTy(SizeTBits)); + return {Int, Ptr, Ptr, SizeT}; + + case LibFunc_memchr: + case LibFunc_memrchr: + // void* (const void*, int, size_t) + return {Ptr, Ptr, Int, SizeT}; case LibFunc_strspn: case LibFunc_strcspn: // size_t (const char*, const char*); - return (NumParams == 2 && FTy.getReturnType()->isIntegerTy(SizeTBits) && - FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(1) == FTy.getParamType(0)); + return {SizeT, Ptr, Ptr}; 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()); + return {Ptr, Ptr, Ptr}; - case LibFunc_setbuf: - // void (FILE*, char*) - return (NumParams == 2 && FTy.getReturnType()->isVoidTy() && - FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(1)->isPointerTy()); - - 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_scanf: - // int (const char*, ...*) - return (NumParams == 1 && FTy.getReturnType()->isIntegerTy(32) && - FTy.getParamType(0)->isPointerTy() && - FTy.isFunctionVarArg()); + case LibFunc_strtok_r: + case LibFunc_dunder_strtok_r: + // char* (char*, const char*, char**); + return {Ptr, Ptr, Ptr, Ptr}; case LibFunc_strdup: + case LibFunc_dunder_strdup: // char* (const char*) - return (NumParams == 1 && FTy.getReturnType()->isPointerTy() && - FTy.getParamType(0)->isPointerTy()); + return {Ptr, Ptr}; + case LibFunc_strndup: + case LibFunc_dunder_strndup: // char* (const char*, size_t) - return (NumParams == 2 && FTy.getReturnType()->isPointerTy() && - FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(1)->isIntegerTy(SizeTBits)); + return {Ptr, Ptr, SizeT}; + + case LibFunc_ffs: + case LibFunc_fls: + // int (int) + return {Int, Int}; + case LibFunc_ffsl: + case LibFunc_flsl: + // int (long) + return {Int, Long}; + case LibFunc_ffsll: + case LibFunc_flsll: + // int (long long) + return {Int, LLong}; + + // functions: + case LibFunc_mktime: + // time_t (struct tm*) + return {IntX, Ptr}; + // functions: case LibFunc_stat: + case LibFunc_lstat: // int (const char*, struct stat*) + case LibFunc_stat64: + case LibFunc_lstat64: + // int (const char*, struct stat64*) 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: - // 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) && - FTy.getParamType(3)->isPointerTy() && - FTy.getReturnType()->isIntegerTy(32); - - case LibFunc_snprintf: - // 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_statvfs64: + // int (const char*, struct statvfs64*) + return {Int, Ptr, Ptr}; - case LibFunc_snprintf_chk: - // 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()); + // functions: + case LibFunc_getitimer: + // int (int, struct itimerval*) + return {Int, Int, Ptr}; case LibFunc_setitimer: - return (NumParams == 3 && FTy.getParamType(1)->isPointerTy() && - FTy.getParamType(2)->isPointerTy()); - case LibFunc_system: - return (NumParams == 1 && FTy.getParamType(0)->isPointerTy()); - case LibFunc___kmpc_alloc_shared: - return NumParams == 1 && FTy.getReturnType()->isPointerTy(); - case LibFunc_malloc: - case LibFunc_vec_malloc: - return NumParams == 1 && FTy.getParamType(0)->isIntegerTy(SizeTBits) && - FTy.getReturnType()->isPointerTy(); - - case LibFunc_memchr: - case LibFunc_memrchr: - return (NumParams == 3 && FTy.getReturnType()->isPointerTy() && - FTy.getReturnType() == FTy.getParamType(0) && - FTy.getParamType(1)->isIntegerTy(32) && - FTy.getParamType(2)->isIntegerTy(SizeTBits)); - case LibFunc_modf: - case LibFunc_modff: - case LibFunc_modfl: - return (NumParams >= 2 && FTy.getParamType(1)->isPointerTy()); - - case LibFunc_memalign: - return (FTy.getReturnType()->isPointerTy()); - case LibFunc_realloc: - case LibFunc_reallocf: - case LibFunc_vec_realloc: - return (NumParams == 2 && FTy.getReturnType()->isPointerTy() && - FTy.getParamType(0) == FTy.getReturnType() && - FTy.getParamType(1)->isIntegerTy(SizeTBits)); - case LibFunc_read: - return (NumParams == 3 && FTy.getParamType(1)->isPointerTy()); - case LibFunc_rewind: - case LibFunc_rmdir: - case LibFunc_remove: - case LibFunc_realpath: - return (NumParams >= 1 && FTy.getParamType(0)->isPointerTy()); - case LibFunc_rename: - return (NumParams >= 2 && FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(1)->isPointerTy()); - case LibFunc_readlink: - return (NumParams >= 2 && FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(1)->isPointerTy()); - case LibFunc_write: - return (NumParams == 3 && FTy.getParamType(1)->isPointerTy()); - case LibFunc_aligned_alloc: - return (NumParams == 2 && FTy.getReturnType()->isPointerTy()); - case LibFunc_bcopy: - case LibFunc_bcmp: - return (NumParams == 3 && FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(1)->isPointerTy()); - case LibFunc_bzero: - return (NumParams == 2 && FTy.getParamType(0)->isPointerTy()); - case LibFunc_calloc: - case LibFunc_vec_calloc: - return (NumParams == 2 && FTy.getReturnType()->isPointerTy() && - FTy.getParamType(0) == FTy.getParamType(1)); + // int (int, const struct itimerval*, struct itimerval*) + return {Int, Int, Ptr, Ptr}; - 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_gettimeofday: + // int (struct timeval*, struct timezone *) + return {Int, Ptr, Ptr}; - case LibFunc_atof: - // double (const char*) - return (NumParams == 1 && FTy.getReturnType()->isDoubleTy() && - FTy.getParamType(0)->isPointerTy()); + // functions: + case LibFunc_times: + // clock_t (struct tms*) + return {IntX, Ptr}; - case LibFunc_ferror: - case LibFunc_getenv: - case LibFunc_getpwnam: - case LibFunc_iprintf: - case LibFunc_small_printf: - case LibFunc_pclose: - case LibFunc_perror: - case LibFunc_printf: - case LibFunc_puts: + // functions: case LibFunc_uname: - case LibFunc_under_IO_getc: - case LibFunc_unlink: - case LibFunc_unsetenv: - return (NumParams == 1 && FTy.getParamType(0)->isPointerTy()); - - case LibFunc_access: - case LibFunc_chmod: - case LibFunc_chown: - case LibFunc_clearerr: - case LibFunc_closedir: - case LibFunc_ctermid: - case LibFunc_fclose: - case LibFunc_feof: - case LibFunc_fflush: - case LibFunc_fgetc: - case LibFunc_fgetc_unlocked: - case LibFunc_fileno: - case LibFunc_flockfile: - case LibFunc_free: - case LibFunc_fseek: - case LibFunc_fseeko64: - case LibFunc_fseeko: - case LibFunc_fsetpos: - case LibFunc_ftell: - case LibFunc_ftello64: - case LibFunc_ftello: - case LibFunc_ftrylockfile: - case LibFunc_funlockfile: - case LibFunc_getc: - case LibFunc_getc_unlocked: - case LibFunc_getlogin_r: - case LibFunc_mkdir: - case LibFunc_mktime: - case LibFunc_times: - case LibFunc_vec_free: - return (NumParams != 0 && FTy.getParamType(0)->isPointerTy()); - case LibFunc___kmpc_free_shared: - return (NumParams == 2 && FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(1)->isIntegerTy(SizeTBits)); + // int (struct utsname*) + return {Int, Ptr}; - case LibFunc_fopen: - return (NumParams == 2 && FTy.getReturnType()->isPointerTy() && - FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(1)->isPointerTy()); - case LibFunc_fork: - return (NumParams == 0 && FTy.getReturnType()->isIntegerTy(32)); - case LibFunc_fdopen: - return (NumParams == 2 && FTy.getReturnType()->isPointerTy() && - FTy.getParamType(1)->isPointerTy()); - case LibFunc_fputc: - case LibFunc_fputc_unlocked: - case LibFunc_fstat: - case LibFunc_frexp: - case LibFunc_frexpf: - case LibFunc_frexpl: - case LibFunc_fstatvfs: - return (NumParams == 2 && FTy.getParamType(1)->isPointerTy()); - case LibFunc_fgets: - case LibFunc_fgets_unlocked: - return (NumParams == 3 && FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(2)->isPointerTy()); - case LibFunc_fread: - case LibFunc_fread_unlocked: - return (NumParams == 4 && FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(3)->isPointerTy()); - case LibFunc_fwrite: - case LibFunc_fwrite_unlocked: - return (NumParams == 4 && FTy.getReturnType()->isIntegerTy() && - FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(1)->isIntegerTy() && - FTy.getParamType(2)->isIntegerTy() && - FTy.getParamType(3)->isPointerTy()); - case LibFunc_fputs: - case LibFunc_fputs_unlocked: - return (NumParams >= 2 && FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(1)->isPointerTy()); - case LibFunc_fscanf: - case LibFunc_fiprintf: - case LibFunc_small_fprintf: - case LibFunc_fprintf: - return (NumParams >= 2 && FTy.getReturnType()->isIntegerTy() && - FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(1)->isPointerTy()); - case LibFunc_fgetpos: - return (NumParams >= 2 && FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(1)->isPointerTy()); - case LibFunc_getchar: - case LibFunc_getchar_unlocked: - return (NumParams == 0 && FTy.getReturnType()->isIntegerTy()); - case LibFunc_gets: - return (NumParams == 1 && FTy.getParamType(0)->isPointerTy()); - case LibFunc_getitimer: - return (NumParams == 2 && FTy.getParamType(1)->isPointerTy()); - case LibFunc_ungetc: - return (NumParams == 2 && FTy.getParamType(1)->isPointerTy()); - case LibFunc_utime: - case LibFunc_utimes: - return (NumParams == 2 && FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(1)->isPointerTy()); - case LibFunc_putc: - case LibFunc_putc_unlocked: - return (NumParams == 2 && FTy.getParamType(1)->isPointerTy()); - case LibFunc_pread: - case LibFunc_pwrite: - return (NumParams == 4 && FTy.getParamType(1)->isPointerTy()); - case LibFunc_popen: - return (NumParams == 2 && FTy.getReturnType()->isPointerTy() && - FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(1)->isPointerTy()); - case LibFunc_vscanf: - return (NumParams == 2 && FTy.getParamType(1)->isPointerTy()); - case LibFunc_vsscanf: - return (NumParams == 3 && FTy.getParamType(1)->isPointerTy() && - FTy.getParamType(2)->isPointerTy()); - case LibFunc_vfscanf: - return (NumParams == 3 && FTy.getParamType(1)->isPointerTy() && - FTy.getParamType(2)->isPointerTy()); - case LibFunc_valloc: - return (FTy.getReturnType()->isPointerTy()); - case LibFunc_vprintf: - return (NumParams == 2 && FTy.getParamType(0)->isPointerTy()); - case LibFunc_vfprintf: - case LibFunc_vsprintf: - return (NumParams == 3 && FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(1)->isPointerTy()); - case LibFunc_vsprintf_chk: - return NumParams == 5 && FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(1)->isIntegerTy(32) && - FTy.getParamType(2)->isIntegerTy(SizeTBits) && FTy.getParamType(3)->isPointerTy(); - case LibFunc_vsnprintf: - return (NumParams == 4 && FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(2)->isPointerTy()); - case LibFunc_vsnprintf_chk: - return NumParams == 6 && FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(2)->isIntegerTy(32) && - FTy.getParamType(3)->isIntegerTy(SizeTBits) && FTy.getParamType(4)->isPointerTy(); + // functions: case LibFunc_open: - return (NumParams >= 2 && FTy.getParamType(0)->isPointerTy()); + case LibFunc_open64: + // int (const char*, int, ...) + return {Int, Ptr, Int, Ellip}; + + // functions: case LibFunc_opendir: - return (NumParams == 1 && FTy.getReturnType()->isPointerTy() && - FTy.getParamType(0)->isPointerTy()); - case LibFunc_tmpfile: - return (FTy.getReturnType()->isPointerTy()); + // DIR* (const char*) + return {Ptr, Ptr}; + + // functions: case LibFunc_htonl: case LibFunc_ntohl: - return (NumParams == 1 && FTy.getReturnType()->isIntegerTy(32) && - FTy.getReturnType() == FTy.getParamType(0)); + // uint32_t (uint32_t) + return {Int32, Int32}; + case LibFunc_htons: case LibFunc_ntohs: - return (NumParams == 1 && FTy.getReturnType()->isIntegerTy(16) && - FTy.getReturnType() == FTy.getParamType(0)); - case LibFunc_lstat: - return (NumParams == 2 && FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(1)->isPointerTy()); + // uint16_t (uint16_t) + return {Int16, Int16}; + + // functions: + case LibFunc_execl: + case LibFunc_execlp: + case LibFunc_execle: + // int (const char*, const char *, ...) + return {Int, Ptr, Ptr, Ellip}; + + case LibFunc_execv: + case LibFunc_execvp: + // int (const char*, const char *) + return {Int, Ptr, Ptr}; + + case LibFunc_execvP: + case LibFunc_execvpe: + case LibFunc_execve: + // int (const char*, const char *, char* const[]) + return {Int, Ptr, Ptr, Ptr}; + + case LibFunc_fork: + // pid_t (void) + return {Int}; + + case LibFunc_getlogin_r: + // int (char*, size_t) + return {Int, Ptr, SizeT}; + + case LibFunc_chown: case LibFunc_lchown: - return (NumParams == 3 && FTy.getParamType(0)->isPointerTy()); - case LibFunc_qsort: - return (NumParams == 4 && FTy.getParamType(3)->isPointerTy()); - case LibFunc_dunder_strdup: - case LibFunc_dunder_strndup: - return (NumParams >= 1 && FTy.getReturnType()->isPointerTy() && - FTy.getParamType(0)->isPointerTy()); - case LibFunc_dunder_strtok_r: - return (NumParams == 3 && FTy.getParamType(1)->isPointerTy()); - case LibFunc_under_IO_putc: - return (NumParams == 2 && FTy.getParamType(1)->isPointerTy()); - case LibFunc_dunder_isoc99_scanf: - return (NumParams >= 1 && FTy.getParamType(0)->isPointerTy()); - case LibFunc_stat64: - case LibFunc_lstat64: - case LibFunc_statvfs64: - return (NumParams == 2 && FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(1)->isPointerTy()); - case LibFunc_dunder_isoc99_sscanf: - return (NumParams >= 2 && FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(1)->isPointerTy()); - case LibFunc_fopen64: - return (NumParams == 2 && FTy.getReturnType()->isPointerTy() && - FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(1)->isPointerTy()); - case LibFunc_tmpfile64: - return (FTy.getReturnType()->isPointerTy()); - case LibFunc_fstat64: - case LibFunc_fstatvfs64: - return (NumParams == 2 && FTy.getParamType(1)->isPointerTy()); - case LibFunc_open64: - return (NumParams >= 2 && FTy.getParamType(0)->isPointerTy()); - case LibFunc_gettimeofday: - return (NumParams == 2 && FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(1)->isPointerTy()); + // int (const char*, uid_t, gid_t) + return {Int, Ptr, IntX, IntX}; + + case LibFunc_read: + // ssize_t (int, void*, size_t) + return {SSizeT, Int, Ptr, SizeT}; + + case LibFunc_unlink: + // int (const char*) + return {Int, Ptr}; + + // functions: + case LibFunc_utime: + // int (const char*, const struct utimbuf*) + case LibFunc_utimes: + // int (const char*, const struct timeval[2]) + return {Int, Ptr, Ptr}; + + // functions: + case LibFunc_wcslen: + return {SizeT, Ptr}; - // new(unsigned int); + // C++ operators new and delete take a size_t argument but have + // different names depending on what size_t is an alias for (i.e., + // unsigned or unsigned long, or with 64-bit MSVC, unsigned long + // long). case LibFunc_Znwj: - // new(unsigned long); - case LibFunc_Znwm: - // new[](unsigned int); + // new(size_t = unsigned int); case LibFunc_Znaj: - // new[](unsigned long); - case LibFunc_Znam: - // new(unsigned int); + // new[](size_t = unsigned int); case LibFunc_msvc_new_int: - // new(unsigned long long); - case LibFunc_msvc_new_longlong: - // new[](unsigned int); + // new(size_t = unsigned int); case LibFunc_msvc_new_array_int: - // new[](unsigned long long); + // new[](size_t = unsigned int); + return {Ptr, Int}; + + case LibFunc_Znwm: + // new(size_t = unsigned long); + case LibFunc_Znam: + // new[](size_t = unsigned long); + return {Ptr, Long}; + + case LibFunc_msvc_new_longlong: + // new(unsigned long long); case LibFunc_msvc_new_array_longlong: - return (NumParams == 1 && FTy.getReturnType()->isPointerTy()); + // new[](unsigned long long); + return {Ptr, LLong}; - // new(unsigned int, nothrow); + // C++ std::nothrow_t is a struct passed by reference. case LibFunc_ZnwjRKSt9nothrow_t: - // new(unsigned long, nothrow); - case LibFunc_ZnwmRKSt9nothrow_t: - // new[](unsigned int, nothrow); + // new(size_t = unsigned int, const std::nothrow_t&); case LibFunc_ZnajRKSt9nothrow_t: - // new[](unsigned long, nothrow); - case LibFunc_ZnamRKSt9nothrow_t: - // new(unsigned int, nothrow); + // new[](size_t = unsigned int, const std::nothrow_t&); + return {Ptr, Int, Ptr}; + case LibFunc_msvc_new_int_nothrow: - // new(unsigned long long, nothrow); - case LibFunc_msvc_new_longlong_nothrow: - // new[](unsigned int, nothrow); + // new(unsigned int, const std::nothrow_t&); case LibFunc_msvc_new_array_int_nothrow: - // new[](unsigned long long, nothrow); + // new[](unsigned int, const std::nothrow_t&); + return {Ptr, Int, Ptr}; + + case LibFunc_ZnwmRKSt9nothrow_t: + // new(size_t = unsigned long, const std::nothrow_t&); + case LibFunc_ZnamRKSt9nothrow_t: + // new[](size_t = unsigned long, const std::nothrow_t&); + return {Ptr, Long, Ptr}; + + case LibFunc_msvc_new_longlong_nothrow: + // new(unsigned long long, const std::nothrow_t&); case LibFunc_msvc_new_array_longlong_nothrow: - // new(unsigned int, align_val_t) + // new[](unsigned long long, const std::nothrow_t&); + return {Ptr, LLong, Ptr}; + + // C++ std::align_val_t is a size_t-based enum class. case LibFunc_ZnwjSt11align_val_t: - // new(unsigned long, align_val_t) - case LibFunc_ZnwmSt11align_val_t: - // new[](unsigned int, align_val_t) + // new(size_t = unsigned int, std::align_val_t) case LibFunc_ZnajSt11align_val_t: - // new[](unsigned long, align_val_t) + // new[](size_t = unsigned int, std::align_val_t) + return {Ptr, Int, Int}; + + case LibFunc_ZnwmSt11align_val_t: + // new(size_t = unsigned long, std::align_val_t) case LibFunc_ZnamSt11align_val_t: - return (NumParams == 2 && FTy.getReturnType()->isPointerTy()); + // new[](size_t = unsigned long, std::align_val_t) + return {Ptr, Long, Long}; - // new(unsigned int, align_val_t, nothrow) case LibFunc_ZnwjSt11align_val_tRKSt9nothrow_t: - // new(unsigned long, align_val_t, nothrow) - case LibFunc_ZnwmSt11align_val_tRKSt9nothrow_t: - // new[](unsigned int, align_val_t, nothrow) + // new(size_t = unsigned int, std::align_val_t, const std::nothrow_t&) case LibFunc_ZnajSt11align_val_tRKSt9nothrow_t: - // new[](unsigned long, align_val_t, nothrow) + // new[](size_t = unsigned int, std::align_val_t, const std::nothrow_t&) + return {Ptr, Int, Int, Ptr}; + + case LibFunc_ZnwmSt11align_val_tRKSt9nothrow_t: + // new(size_t = unsigned long, std::align_val_t, const std::nothrow_t&) case LibFunc_ZnamSt11align_val_tRKSt9nothrow_t: - return (NumParams == 3 && FTy.getReturnType()->isPointerTy()); + // new[](size_t = unsigned long, std::align_val_t, const std::nothrow_t&) + return {Ptr, Long, Long, Ptr}; - // void operator delete[](void*); - case LibFunc_ZdaPv: - // void operator delete(void*); case LibFunc_ZdlPv: + // void operator delete(void*); + case LibFunc_ZdaPv: // void operator delete[](void*); case LibFunc_msvc_delete_array_ptr32: - // void operator delete[](void*); case LibFunc_msvc_delete_array_ptr64: - // void operator delete(void*); + // void operator delete[](void*); case LibFunc_msvc_delete_ptr32: - // void operator delete(void*); case LibFunc_msvc_delete_ptr64: - return (NumParams == 1 && FTy.getParamType(0)->isPointerTy()); + // void operator delete(void*); + return {Void, Ptr}; - // void operator delete[](void*, nothrow); - case LibFunc_ZdaPvRKSt9nothrow_t: - // void operator delete[](void*, unsigned int); - case LibFunc_ZdaPvj: - // void operator delete[](void*, unsigned long); - case LibFunc_ZdaPvm: - // void operator delete(void*, nothrow); case LibFunc_ZdlPvRKSt9nothrow_t: - // void operator delete(void*, unsigned int); + // void operator delete(void*, const std::nothrow_t&) + case LibFunc_ZdaPvRKSt9nothrow_t: + // void operator delete[](void*, const std::nothrow_t&) + return {Void, Ptr, Ptr}; + case LibFunc_ZdlPvj: - // void operator delete(void*, unsigned long); + // void operator delete(void*, size_t = unsigned int) + case LibFunc_ZdaPvj: + // void operator delete[](void*, size_t = unsigned int) + return {Void, Ptr, Int}; + case LibFunc_ZdlPvm: - // void operator delete(void*, align_val_t) + // void operator delete(void*, size_t = unsigned long) + return {Void, Ptr, Long}; + case LibFunc_ZdaPvm: + // void operator delete[](void*, size_t = unsigned long) + return {Void, Ptr, Long}; + case LibFunc_ZdlPvSt11align_val_t: - // void operator delete[](void*, align_val_t) + // void operator delete(void*, std::align_val_t) case LibFunc_ZdaPvSt11align_val_t: - // void operator delete[](void*, unsigned int); + // void operator delete[](void*, std::align_val_t) + return {Void, Ptr, IntX}; + case LibFunc_msvc_delete_array_ptr32_int: - // void operator delete[](void*, nothrow); - case LibFunc_msvc_delete_array_ptr32_nothrow: - // void operator delete[](void*, unsigned long long); + // void operator delete[](void*, unsigned int) + return {Void, Ptr, Int}; case LibFunc_msvc_delete_array_ptr64_longlong: - // void operator delete[](void*, nothrow); + // void operator delete[](void*, unsigned long long) + return {Void, Ptr, LLong}; + + case LibFunc_msvc_delete_array_ptr32_nothrow: + // void operator delete[](void*, const std::nothrow_t&) case LibFunc_msvc_delete_array_ptr64_nothrow: - // void operator delete(void*, unsigned int); - case LibFunc_msvc_delete_ptr32_int: - // void operator delete(void*, nothrow); + // void operator delete[](void*, const std::nothrow_t&) + return {Void, Ptr, Ptr}; + case LibFunc_msvc_delete_ptr32_nothrow: - // void operator delete(void*, unsigned long long); - case LibFunc_msvc_delete_ptr64_longlong: - // void operator delete(void*, nothrow); + // void operator delete(void*, const std::nothrow_t&) case LibFunc_msvc_delete_ptr64_nothrow: - return (NumParams == 2 && FTy.getParamType(0)->isPointerTy()); + // void operator delete(void*, const std::nothrow_t&) + return {Void, Ptr, Ptr}; + + case LibFunc_msvc_delete_ptr32_int: + // void operator delete(void*, unsigned int) + return {Void, Ptr, Int}; + case LibFunc_msvc_delete_ptr64_longlong: + // void operator delete(void*, unsigned long long) + return {Void, Ptr, LLong}; - // void operator delete(void*, align_val_t, nothrow) case LibFunc_ZdlPvSt11align_val_tRKSt9nothrow_t: - // void operator delete[](void*, align_val_t, nothrow) + // void operator delete(void*, std::align_val_t, const std::nothrow_t&) case LibFunc_ZdaPvSt11align_val_tRKSt9nothrow_t: - // void operator delete(void*, unsigned int, align_val_t) + // void operator delete[](void*, std::align_val_t, const std::nothrow_t&) + return {Void, Ptr, IntX, Ptr}; + case LibFunc_ZdlPvjSt11align_val_t: - // void operator delete(void*, unsigned long, align_val_t) - case LibFunc_ZdlPvmSt11align_val_t: - // void operator delete[](void*, unsigned int, align_val_t); + // void operator delete(void*, size_t = unsigned int, std::align_val_t) case LibFunc_ZdaPvjSt11align_val_t: - // void operator delete[](void*, unsigned long, align_val_t); + // void operator delete[](void*, size_t = unsigned int, std::align_val_t) + return {Void, Ptr, Int, Int}; + + case LibFunc_ZdlPvmSt11align_val_t: + // void operator delete(void*, size_t = unsigned long, std::align_val_t) case LibFunc_ZdaPvmSt11align_val_t: - return (NumParams == 3 && FTy.getParamType(0)->isPointerTy()); + // void operator delete[](void*, size_t = unsigned long, std::align_val_t); + return {Void, Ptr, Long, Long}; - // void __atomic_load(size_t, void *, void *, int) + // Special internal functions. case LibFunc_atomic_load: - // void __atomic_store(size_t, void *, void *, int) case LibFunc_atomic_store: - return (NumParams == 4 && FTy.getParamType(0)->isIntegerTy() && - FTy.getParamType(1)->isPointerTy() && - FTy.getParamType(2)->isPointerTy() && - FTy.getParamType(3)->isIntegerTy()); + // void (size_t, void*, void*, int) + return {Void, SizeT, Ptr, Ptr, IntX}; case LibFunc_memset_pattern4: case LibFunc_memset_pattern8: case LibFunc_memset_pattern16: - return (!FTy.isVarArg() && NumParams == 3 && - FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(1)->isPointerTy() && - FTy.getParamType(2)->isIntegerTy()); + return {Void, Ptr, Ptr, IntX}; + + case LibFunc_cxa_atexit: + // int (void (*)(void*), void*, void*) + return {Int, Ptr, Ptr, Ptr}; - case LibFunc_cxa_guard_abort: case LibFunc_cxa_guard_acquire: + // int (uint64_t*) + return {Int, Ptr}; + + case LibFunc_cxa_guard_abort: case LibFunc_cxa_guard_release: + // void (uint64_t*) + return {Void, Ptr}; + case LibFunc_nvvm_reflect: - return (NumParams == 1 && FTy.getParamType(0)->isPointerTy()); + // int (void*) + return {Int, Ptr}; + case LibFunc_cabs: + case LibFunc_cabsf: + case LibFunc_cabsl: case LibFunc_sincospi_stret: case LibFunc_sincospif_stret: - return (NumParams == 1 && FTy.getParamType(0)->isFloatingPointTy()); - - case LibFunc_acos: - case LibFunc_acos_finite: - case LibFunc_acosf: - case LibFunc_acosf_finite: - case LibFunc_acosh: - case LibFunc_acosh_finite: - case LibFunc_acoshf: - case LibFunc_acoshf_finite: - case LibFunc_acoshl: - case LibFunc_acoshl_finite: - case LibFunc_acosl: - case LibFunc_acosl_finite: - case LibFunc_asin: - case LibFunc_asin_finite: - case LibFunc_asinf: - case LibFunc_asinf_finite: - case LibFunc_asinh: - case LibFunc_asinhf: - case LibFunc_asinhl: - case LibFunc_asinl: - case LibFunc_asinl_finite: - case LibFunc_atan: - case LibFunc_atanf: - case LibFunc_atanh: - case LibFunc_atanh_finite: - case LibFunc_atanhf: - case LibFunc_atanhf_finite: - case LibFunc_atanhl: - case LibFunc_atanhl_finite: - case LibFunc_atanl: - case LibFunc_cbrt: - case LibFunc_cbrtf: - case LibFunc_cbrtl: - case LibFunc_ceil: - case LibFunc_ceilf: - case LibFunc_ceill: - case LibFunc_cos: - case LibFunc_cosf: - case LibFunc_cosh: - case LibFunc_cosh_finite: - case LibFunc_coshf: - case LibFunc_coshf_finite: - case LibFunc_coshl: - case LibFunc_coshl_finite: - case LibFunc_cosl: - case LibFunc_exp10: - case LibFunc_exp10_finite: - case LibFunc_exp10f: - case LibFunc_exp10f_finite: - case LibFunc_exp10l: - case LibFunc_exp10l_finite: - case LibFunc_exp2: - case LibFunc_exp2_finite: - case LibFunc_exp2f: - case LibFunc_exp2f_finite: - case LibFunc_exp2l: - case LibFunc_exp2l_finite: - case LibFunc_exp: - case LibFunc_exp_finite: - case LibFunc_expf: - case LibFunc_expf_finite: - case LibFunc_expl: - case LibFunc_expl_finite: - case LibFunc_expm1: - case LibFunc_expm1f: - case LibFunc_expm1l: - case LibFunc_fabs: - case LibFunc_fabsf: - case LibFunc_fabsl: - case LibFunc_floor: - case LibFunc_floorf: - case LibFunc_floorl: - case LibFunc_log10: - case LibFunc_log10_finite: - case LibFunc_log10f: - case LibFunc_log10f_finite: - case LibFunc_log10l: - case LibFunc_log10l_finite: - case LibFunc_log1p: - case LibFunc_log1pf: - case LibFunc_log1pl: - case LibFunc_log2: - case LibFunc_log2_finite: - case LibFunc_log2f: - case LibFunc_log2f_finite: - case LibFunc_log2l: - case LibFunc_log2l_finite: - case LibFunc_log: - case LibFunc_log_finite: - case LibFunc_logb: - case LibFunc_logbf: - case LibFunc_logbl: - case LibFunc_logf: - case LibFunc_logf_finite: - case LibFunc_logl: - case LibFunc_logl_finite: - case LibFunc_nearbyint: - case LibFunc_nearbyintf: - case LibFunc_nearbyintl: - case LibFunc_rint: - case LibFunc_rintf: - case LibFunc_rintl: - case LibFunc_round: - case LibFunc_roundf: - case LibFunc_roundl: - case LibFunc_roundeven: - case LibFunc_roundevenf: - case LibFunc_roundevenl: - case LibFunc_sin: - case LibFunc_sinf: - case LibFunc_sinh: - case LibFunc_sinh_finite: - case LibFunc_sinhf: - case LibFunc_sinhf_finite: - case LibFunc_sinhl: - case LibFunc_sinhl_finite: - case LibFunc_sinl: - case LibFunc_sqrt: - case LibFunc_sqrt_finite: - case LibFunc_sqrtf: - case LibFunc_sqrtf_finite: - case LibFunc_sqrtl: - case LibFunc_sqrtl_finite: - case LibFunc_tan: - case LibFunc_tanf: - case LibFunc_tanh: - case LibFunc_tanhf: - case LibFunc_tanhl: - case LibFunc_tanl: - case LibFunc_trunc: - case LibFunc_truncf: - case LibFunc_truncl: - return (NumParams == 1 && FTy.getReturnType()->isFloatingPointTy() && - FTy.getReturnType() == FTy.getParamType(0)); - - case LibFunc_atan2: - case LibFunc_atan2_finite: - case LibFunc_atan2f: - case LibFunc_atan2f_finite: - case LibFunc_atan2l: - case LibFunc_atan2l_finite: - case LibFunc_fmin: - case LibFunc_fminf: - case LibFunc_fminl: - case LibFunc_fmax: - case LibFunc_fmaxf: - case LibFunc_fmaxl: - case LibFunc_fmod: - case LibFunc_fmodf: - case LibFunc_fmodl: - case LibFunc_remainder: - case LibFunc_remainderf: - case LibFunc_remainderl: - case LibFunc_copysign: - case LibFunc_copysignf: - case LibFunc_copysignl: - case LibFunc_pow: - case LibFunc_pow_finite: - case LibFunc_powf: - case LibFunc_powf_finite: - case LibFunc_powl: - case LibFunc_powl_finite: - return (NumParams == 2 && FTy.getReturnType()->isFloatingPointTy() && - FTy.getReturnType() == FTy.getParamType(0) && - FTy.getReturnType() == FTy.getParamType(1)); - - case LibFunc_ldexp: - case LibFunc_ldexpf: - case LibFunc_ldexpl: - return (NumParams == 2 && FTy.getReturnType()->isFloatingPointTy() && - FTy.getReturnType() == FTy.getParamType(0) && - FTy.getParamType(1)->isIntegerTy(getIntSize())); - - case LibFunc_ffs: - case LibFunc_ffsl: - case LibFunc_ffsll: - case LibFunc_fls: - case LibFunc_flsl: - case LibFunc_flsll: - return (NumParams == 1 && FTy.getReturnType()->isIntegerTy(32) && - FTy.getParamType(0)->isIntegerTy()); - - case LibFunc_isdigit: - case LibFunc_isascii: - case LibFunc_toascii: - case LibFunc_putchar: - case LibFunc_putchar_unlocked: - return (NumParams == 1 && FTy.getReturnType()->isIntegerTy(32) && - FTy.getReturnType() == FTy.getParamType(0)); - - case LibFunc_abs: - case LibFunc_labs: - case LibFunc_llabs: - return (NumParams == 1 && FTy.getReturnType()->isIntegerTy() && - FTy.getReturnType() == FTy.getParamType(0)); - - case LibFunc_cxa_atexit: - return (NumParams == 3 && FTy.getReturnType()->isIntegerTy() && - FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(1)->isPointerTy() && - FTy.getParamType(2)->isPointerTy()); - - case LibFunc_sinpi: - case LibFunc_cospi: - return (NumParams == 1 && FTy.getReturnType()->isDoubleTy() && - FTy.getReturnType() == FTy.getParamType(0)); - - case LibFunc_sinpif: - case LibFunc_cospif: - return (NumParams == 1 && FTy.getReturnType()->isFloatTy() && - FTy.getReturnType() == FTy.getParamType(0)); + // Handled in the caller. + break; - case LibFunc_strnlen: - return (NumParams == 2 && FTy.getReturnType() == FTy.getParamType(1) && - FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(1)->isIntegerTy(SizeTBits)); + case LibFunc::NumLibFuncs: + case LibFunc::NotLibFunc: + break; + } - case LibFunc_posix_memalign: - return (NumParams == 3 && FTy.getReturnType()->isIntegerTy(32) && - FTy.getParamType(0)->isPointerTy() && - FTy.getParamType(1)->isIntegerTy(SizeTBits) && - FTy.getParamType(2)->isIntegerTy(SizeTBits)); + llvm_unreachable("Invalid libfunc"); +} - case LibFunc_wcslen: - return (NumParams == 1 && FTy.getParamType(0)->isPointerTy() && - FTy.getReturnType()->isIntegerTy()); +bool TargetLibraryInfoImpl::isValidProtoForLibFunc(const FunctionType &FTy, + LibFunc F, + const Module &M) const { + unsigned NumParams = FTy.getNumParams(); + switch (F) { + // Special handling for functions: case LibFunc_cabs: case LibFunc_cabsf: case LibFunc_cabsl: { @@ -1843,24 +2005,100 @@ if (!RetTy->isFloatingPointTy()) return false; + Type* ParamTy = FTy.getParamType(0); // NOTE: These prototypes are target specific and currently support // "complex" passed as an array or discrete real & imaginary parameters. // Add other calling conventions to enable libcall optimizations. if (NumParams == 1) - return (FTy.getParamType(0)->isArrayTy() && - FTy.getParamType(0)->getArrayNumElements() == 2 && - FTy.getParamType(0)->getArrayElementType() == RetTy); + return (ParamTy->isArrayTy() && + ParamTy->getArrayNumElements() == 2 && + ParamTy->getArrayElementType() == RetTy); else if (NumParams == 2) - return (FTy.getParamType(0) == RetTy && FTy.getParamType(1) == RetTy); - else + return ParamTy == RetTy && FTy.getParamType(1) == RetTy; + + return false; + } + // Special handling for the sincospi functions that return either + // a struct or vector: + case LibFunc_sincospi_stret: + case LibFunc_sincospif_stret: { + if (NumParams != 1) return false; + + Type* RetTy = FTy.getReturnType(); + Type* ParamTy = FTy.getParamType(0); + if (auto *Ty = dyn_cast(RetTy)) { + if (Ty->getNumElements() != 2) + return false; + return (Ty->getElementType(0) == ParamTy && + Ty->getElementType(1) == ParamTy); + } + + if (auto *Ty = dyn_cast(RetTy)) { + if (Ty->getNumElements() != 2) + return false; + return Ty->getElementType() == ParamTy; + } + + return false; } - case LibFunc::NumLibFuncs: - case LibFunc::NotLibFunc: + + default: break; } - llvm_unreachable("Invalid libfunc"); + // FIXME: There is no guarantee that sizeof(size_t) is equal to + // sizeof(int*) for every target. So the assumption used here to derive + // the SizeTBits based on the size of an integer pointer in address space + // zero isn't always valid. + unsigned IntBits = getIntSize(); + unsigned SizeTBits = M.getDataLayout().getPointerSizeInBits(/*AddrSpace=*/0); + unsigned Idx = 0; + + // Iterate over the type ids in the function prototype , matching each + // against the function's type FTy, starting with its return type. + // Return true if both match in number and kind, inclduing the ellipsis. + Type *Ty = FTy.getReturnType(), *LastTy = Ty; + auto ProtoTypes = getLibFuncProto(F); + for (auto TyID: ProtoTypes) { + if (Idx && TyID == Void) + // Except in the first position where it designates the function's + // return type Void ends the argument list. + break; + + if (TyID == Ellip) { + // The ellipsis ends the protoype list but is not a part of FTy's + // argument list. Except when it's last it must be followed by + // Void. + assert(Idx == ProtoTypes.size() - 1 || ProtoTypes[Idx + 1] == Void); + return FTy.isFunctionVarArg(); + } + + if (TyID == Same) { + assert(Idx != 0 && "Type ID 'Same' must not be first!"); + if (Ty != LastTy) + return false; + } + else { + if (!Ty || !MatchType(TyID, Ty, IntBits, SizeTBits)) + return false; + LastTy = Ty; + } + + if (Idx == NumParams) { + // There's at least one and at most two more type ids than there are + // arguments in FTy's argument list. + Ty = nullptr; + ++Idx; + continue; + } + + Ty = FTy.getParamType(Idx++); + } + + // Return success only if all entries on both lists have been processed + // and the function is not a variadic one. + return Idx == NumParams + 1 && !FTy.isFunctionVarArg(); } bool TargetLibraryInfoImpl::getLibFunc(const Function &FDecl, Index: llvm/test/CodeGen/AMDGPU/complex-folding.ll =================================================================== --- llvm/test/CodeGen/AMDGPU/complex-folding.ll +++ llvm/test/CodeGen/AMDGPU/complex-folding.ll @@ -5,7 +5,7 @@ define amdgpu_ps void @main(<4 x float> inreg %reg0) { entry: %0 = extractelement <4 x float> %reg0, i32 0 - %1 = call float @fabs(float %0) + %1 = call float @fabsf(float %0) %2 = fptoui float %1 to i32 %3 = bitcast i32 %2 to float %4 = insertelement <4 x float> undef, float %3, i32 0 @@ -13,5 +13,5 @@ ret void } -declare float @fabs(float ) readnone +declare float @fabsf(float ) readnone declare void @llvm.r600.store.swizzle(<4 x float>, i32, i32) Index: llvm/test/CodeGen/AMDGPU/fabs.ll =================================================================== --- llvm/test/CodeGen/AMDGPU/fabs.ll +++ llvm/test/CodeGen/AMDGPU/fabs.ll @@ -4,56 +4,56 @@ ; DAGCombiner will transform: -; (fabs (f32 bitcast (i32 a))) => (f32 bitcast (and (i32 a), 0x7FFFFFFF)) +; (fabsf (f32 bitcast (i32 a))) => (f32 bitcast (and (i32 a), 0x7FFFFFFF)) ; unless isFabsFree returns true -; FUNC-LABEL: {{^}}s_fabs_fn_free: +; FUNC-LABEL: {{^}}s_fabsf_fn_free: ; R600-NOT: AND ; R600: |PV.{{[XYZW]}}| ; GCN: s_bitset0_b32 s{{[0-9]+}}, 31 -define amdgpu_kernel void @s_fabs_fn_free(float addrspace(1)* %out, i32 %in) { +define amdgpu_kernel void @s_fabsf_fn_free(float addrspace(1)* %out, i32 %in) { %bc= bitcast i32 %in to float - %fabs = call float @fabs(float %bc) + %fabs = call float @fabsf(float %bc) store float %fabs, float addrspace(1)* %out ret void } -; FUNC-LABEL: {{^}}s_fabs_free: +; FUNC-LABEL: {{^}}s_fabsf_free: ; R600-NOT: AND ; R600: |PV.{{[XYZW]}}| ; GCN: s_bitset0_b32 s{{[0-9]+}}, 31 -define amdgpu_kernel void @s_fabs_free(float addrspace(1)* %out, i32 %in) { +define amdgpu_kernel void @s_fabsf_free(float addrspace(1)* %out, i32 %in) { %bc= bitcast i32 %in to float %fabs = call float @llvm.fabs.f32(float %bc) store float %fabs, float addrspace(1)* %out ret void } -; FUNC-LABEL: {{^}}s_fabs_f32: +; FUNC-LABEL: {{^}}s_fabsf_f32: ; R600: |{{(PV|T[0-9])\.[XYZW]}}| ; GCN: s_bitset0_b32 s{{[0-9]+}}, 31 -define amdgpu_kernel void @s_fabs_f32(float addrspace(1)* %out, float %in) { +define amdgpu_kernel void @s_fabsf_f32(float addrspace(1)* %out, float %in) { %fabs = call float @llvm.fabs.f32(float %in) store float %fabs, float addrspace(1)* %out ret void } -; FUNC-LABEL: {{^}}fabs_v2f32: +; FUNC-LABEL: {{^}}fabsf_v2f32: ; R600: |{{(PV|T[0-9])\.[XYZW]}}| ; R600: |{{(PV|T[0-9])\.[XYZW]}}| ; GCN: s_bitset0_b32 ; GCN: s_bitset0_b32 -define amdgpu_kernel void @fabs_v2f32(<2 x float> addrspace(1)* %out, <2 x float> %in) { +define amdgpu_kernel void @fabsf_v2f32(<2 x float> addrspace(1)* %out, <2 x float> %in) { %fabs = call <2 x float> @llvm.fabs.v2f32(<2 x float> %in) store <2 x float> %fabs, <2 x float> addrspace(1)* %out ret void } -; FUNC-LABEL: {{^}}fabs_v4f32: +; FUNC-LABEL: {{^}}fabsf_v4f32: ; R600: |{{(PV|T[0-9])\.[XYZW]}}| ; R600: |{{(PV|T[0-9])\.[XYZW]}}| ; R600: |{{(PV|T[0-9])\.[XYZW]}}| @@ -63,42 +63,42 @@ ; GCN: s_bitset0_b32 ; GCN: s_bitset0_b32 ; GCN: s_bitset0_b32 -define amdgpu_kernel void @fabs_v4f32(<4 x float> addrspace(1)* %out, <4 x float> %in) { +define amdgpu_kernel void @fabsf_v4f32(<4 x float> addrspace(1)* %out, <4 x float> %in) { %fabs = call <4 x float> @llvm.fabs.v4f32(<4 x float> %in) store <4 x float> %fabs, <4 x float> addrspace(1)* %out ret void } -; GCN-LABEL: {{^}}fabs_fn_fold: +; GCN-LABEL: {{^}}fabsf_fn_fold: ; SI: s_load_dwordx2 s[[[ABS_VALUE:[0-9]+]]:[[MUL_VAL:[0-9]+]]], s[{{[0-9]+:[0-9]+}}], 0xb ; VI: s_load_dwordx2 s[[[ABS_VALUE:[0-9]+]]:[[MUL_VAL:[0-9]+]]], s[{{[0-9]+:[0-9]+}}], 0x2c ; GCN-NOT: and ; GCN: v_mov_b32_e32 [[V_MUL_VI:v[0-9]+]], s[[MUL_VAL]] ; GCN: v_mul_f32_e64 v{{[0-9]+}}, |s[[ABS_VALUE]]|, [[V_MUL_VI]] -define amdgpu_kernel void @fabs_fn_fold(float addrspace(1)* %out, float %in0, float %in1) { - %fabs = call float @fabs(float %in0) +define amdgpu_kernel void @fabsf_fn_fold(float addrspace(1)* %out, float %in0, float %in1) { + %fabs = call float @fabsf(float %in0) %fmul = fmul float %fabs, %in1 store float %fmul, float addrspace(1)* %out ret void } -; FUNC-LABEL: {{^}}fabs_fold: +; FUNC-LABEL: {{^}}fabsf_fold: ; SI: s_load_dwordx2 s[[[ABS_VALUE:[0-9]+]]:[[MUL_VAL:[0-9]+]]], s[{{[0-9]+:[0-9]+}}], 0xb ; VI: s_load_dwordx2 s[[[ABS_VALUE:[0-9]+]]:[[MUL_VAL:[0-9]+]]], s[{{[0-9]+:[0-9]+}}], 0x2c ; GCN-NOT: and ; GCN: v_mov_b32_e32 [[V_MUL_VI:v[0-9]+]], s[[MUL_VAL]] ; GCN: v_mul_f32_e64 v{{[0-9]+}}, |s[[ABS_VALUE]]|, [[V_MUL_VI]] -define amdgpu_kernel void @fabs_fold(float addrspace(1)* %out, float %in0, float %in1) { +define amdgpu_kernel void @fabsf_fold(float addrspace(1)* %out, float %in0, float %in1) { %fabs = call float @llvm.fabs.f32(float %in0) %fmul = fmul float %fabs, %in1 store float %fmul, float addrspace(1)* %out ret void } -; Make sure we turn some integer operations back into fabs -; FUNC-LABEL: {{^}}bitpreserve_fabs_f32: +; Make sure we turn some integer operations back into fabsf +; FUNC-LABEL: {{^}}bitpreserve_fabsf_f32: ; GCN: v_add_f32_e64 v{{[0-9]+}}, |s{{[0-9]+}}|, 1.0 -define amdgpu_kernel void @bitpreserve_fabs_f32(float addrspace(1)* %out, float %in) { +define amdgpu_kernel void @bitpreserve_fabsf_f32(float addrspace(1)* %out, float %in) { %in.bc = bitcast float %in to i32 %int.abs = and i32 %in.bc, 2147483647 %bc = bitcast i32 %int.abs to float @@ -107,7 +107,7 @@ ret void } -declare float @fabs(float) readnone +declare float @fabsf(float) readnone declare float @llvm.fabs.f32(float) readnone declare <2 x float> @llvm.fabs.v2f32(<2 x float>) readnone declare <4 x float> @llvm.fabs.v4f32(<4 x float>) readnone Index: llvm/test/CodeGen/AMDGPU/floor.ll =================================================================== --- llvm/test/CodeGen/AMDGPU/floor.ll +++ llvm/test/CodeGen/AMDGPU/floor.ll @@ -3,12 +3,12 @@ ; CHECK: FLOOR * T{{[0-9]+\.[XYZW], T[0-9]+\.[XYZW]}} define amdgpu_ps void @test(<4 x float> inreg %reg0) { %r0 = extractelement <4 x float> %reg0, i32 0 - %r1 = call float @floor(float %r0) + %r1 = call float @floorf(float %r0) %vec = insertelement <4 x float> undef, float %r1, i32 0 call void @llvm.r600.store.swizzle(<4 x float> %vec, i32 0, i32 0) ret void } -declare float @floor(float) readonly +declare float @floorf(float) readonly declare void @llvm.r600.store.swizzle(<4 x float>, i32, i32) Index: llvm/test/CodeGen/AMDGPU/fneg-fabs.ll =================================================================== --- llvm/test/CodeGen/AMDGPU/fneg-fabs.ll +++ llvm/test/CodeGen/AMDGPU/fneg-fabs.ll @@ -2,10 +2,10 @@ ; RUN: llc -amdgpu-scalarize-global-loads=false -march=amdgcn -mcpu=tonga -verify-machineinstrs < %s | FileCheck --check-prefixes=VI,FUNC %s ; RUN: llc -amdgpu-scalarize-global-loads=false -march=r600 -mcpu=redwood < %s | FileCheck --check-prefixes=R600,FUNC %s -; FUNC-LABEL: {{^}}fneg_fabs_fadd_f32: +; FUNC-LABEL: {{^}}fneg_fabsf_fadd_f32: ; SI-NOT: and ; SI: v_sub_f32_e64 {{v[0-9]+}}, {{s[0-9]+}}, |{{v[0-9]+}}| -define amdgpu_kernel void @fneg_fabs_fadd_f32(float addrspace(1)* %out, float %x, float %y) { +define amdgpu_kernel void @fneg_fabsf_fadd_f32(float addrspace(1)* %out, float %x, float %y) { %fabs = call float @llvm.fabs.f32(float %x) %fsub = fsub float -0.000000e+00, %fabs %fadd = fadd float %y, %fsub @@ -13,11 +13,11 @@ ret void } -; FUNC-LABEL: {{^}}fneg_fabs_fmul_f32: +; FUNC-LABEL: {{^}}fneg_fabsf_fmul_f32: ; SI-NOT: and ; SI: v_mul_f32_e64 {{v[0-9]+}}, {{s[0-9]+}}, -|{{v[0-9]+}}| ; SI-NOT: and -define amdgpu_kernel void @fneg_fabs_fmul_f32(float addrspace(1)* %out, float %x, float %y) { +define amdgpu_kernel void @fneg_fabsf_fmul_f32(float addrspace(1)* %out, float %x, float %y) { %fabs = call float @llvm.fabs.f32(float %x) %fsub = fsub float -0.000000e+00, %fabs %fmul = fmul float %y, %fsub @@ -26,17 +26,17 @@ } ; DAGCombiner will transform: -; (fabs (f32 bitcast (i32 a))) => (f32 bitcast (and (i32 a), 0x7FFFFFFF)) +; (fabsf (f32 bitcast (i32 a))) => (f32 bitcast (and (i32 a), 0x7FFFFFFF)) ; unless isFabsFree returns true -; FUNC-LABEL: {{^}}fneg_fabs_free_f32: +; FUNC-LABEL: {{^}}fneg_fabsf_free_f32: ; R600-NOT: AND ; R600: |PV.{{[XYZW]}}| ; R600: -PV ; SI: s_or_b32 s{{[0-9]+}}, s{{[0-9]+}}, 0x80000000 ; VI: s_bitset1_b32 s{{[0-9]+}}, 31 -define amdgpu_kernel void @fneg_fabs_free_f32(float addrspace(1)* %out, i32 %in) { +define amdgpu_kernel void @fneg_fabsf_free_f32(float addrspace(1)* %out, i32 %in) { %bc = bitcast i32 %in to float %fabs = call float @llvm.fabs.f32(float %bc) %fsub = fsub float -0.000000e+00, %fabs @@ -44,32 +44,32 @@ ret void } -; FUNC-LABEL: {{^}}fneg_fabs_fn_free_f32: +; FUNC-LABEL: {{^}}fneg_fabsf_fn_free_f32: ; R600-NOT: AND ; R600: |PV.{{[XYZW]}}| ; R600: -PV ; SI: s_or_b32 s{{[0-9]+}}, s{{[0-9]+}}, 0x80000000 -define amdgpu_kernel void @fneg_fabs_fn_free_f32(float addrspace(1)* %out, i32 %in) { +define amdgpu_kernel void @fneg_fabsf_fn_free_f32(float addrspace(1)* %out, i32 %in) { %bc = bitcast i32 %in to float - %fabs = call float @fabs(float %bc) + %fabs = call float @fabsf(float %bc) %fsub = fsub float -0.000000e+00, %fabs store float %fsub, float addrspace(1)* %out ret void } -; FUNC-LABEL: {{^}}fneg_fabs_f32: +; FUNC-LABEL: {{^}}fneg_fabsf_f32: ; SI: s_or_b32 s{{[0-9]+}}, s{{[0-9]+}}, 0x80000000 -define amdgpu_kernel void @fneg_fabs_f32(float addrspace(1)* %out, float %in) { +define amdgpu_kernel void @fneg_fabsf_f32(float addrspace(1)* %out, float %in) { %fabs = call float @llvm.fabs.f32(float %in) %fsub = fsub float -0.000000e+00, %fabs store float %fsub, float addrspace(1)* %out, align 4 ret void } -; FUNC-LABEL: {{^}}v_fneg_fabs_f32: +; FUNC-LABEL: {{^}}v_fneg_fabsf_f32: ; SI: v_or_b32_e32 v{{[0-9]+}}, 0x80000000, v{{[0-9]+}} -define amdgpu_kernel void @v_fneg_fabs_f32(float addrspace(1)* %out, float addrspace(1)* %in) { +define amdgpu_kernel void @v_fneg_fabsf_f32(float addrspace(1)* %out, float addrspace(1)* %in) { %val = load float, float addrspace(1)* %in, align 4 %fabs = call float @llvm.fabs.f32(float %val) %fsub = fsub float -0.000000e+00, %fabs @@ -77,7 +77,7 @@ ret void } -; FUNC-LABEL: {{^}}fneg_fabs_v2f32: +; FUNC-LABEL: {{^}}fneg_fabsf_v2f32: ; R600: |{{(PV|T[0-9])\.[XYZW]}}| ; R600: -PV ; R600: |{{(PV|T[0-9])\.[XYZW]}}| @@ -86,26 +86,26 @@ ; FIXME: In this case two uses of the constant should be folded ; SI: s_bitset1_b32 s{{[0-9]+}}, 31 ; SI: s_bitset1_b32 s{{[0-9]+}}, 31 -define amdgpu_kernel void @fneg_fabs_v2f32(<2 x float> addrspace(1)* %out, <2 x float> %in) { +define amdgpu_kernel void @fneg_fabsf_v2f32(<2 x float> addrspace(1)* %out, <2 x float> %in) { %fabs = call <2 x float> @llvm.fabs.v2f32(<2 x float> %in) %fsub = fsub <2 x float> , %fabs store <2 x float> %fsub, <2 x float> addrspace(1)* %out ret void } -; FUNC-LABEL: {{^}}fneg_fabs_v4f32: +; FUNC-LABEL: {{^}}fneg_fabsf_v4f32: ; SI: s_bitset1_b32 s{{[0-9]+}}, 31 ; SI: s_bitset1_b32 s{{[0-9]+}}, 31 ; SI: s_bitset1_b32 s{{[0-9]+}}, 31 ; SI: s_bitset1_b32 s{{[0-9]+}}, 31 -define amdgpu_kernel void @fneg_fabs_v4f32(<4 x float> addrspace(1)* %out, <4 x float> %in) { +define amdgpu_kernel void @fneg_fabsf_v4f32(<4 x float> addrspace(1)* %out, <4 x float> %in) { %fabs = call <4 x float> @llvm.fabs.v4f32(<4 x float> %in) %fsub = fsub <4 x float> , %fabs store <4 x float> %fsub, <4 x float> addrspace(1)* %out ret void } -declare float @fabs(float) readnone +declare float @fabsf(float) readnone declare float @llvm.fabs.f32(float) readnone declare <2 x float> @llvm.fabs.v2f32(<2 x float>) readnone declare <4 x float> @llvm.fabs.v4f32(<4 x float>) readnone Index: llvm/test/CodeGen/AMDGPU/r600-infinite-loop-bug-while-reorganizing-vector.ll =================================================================== --- llvm/test/CodeGen/AMDGPU/r600-infinite-loop-bug-while-reorganizing-vector.ll +++ llvm/test/CodeGen/AMDGPU/r600-infinite-loop-bug-while-reorganizing-vector.ll @@ -15,7 +15,7 @@ %tmp11 = extractelement <4 x float> %tmp9, i32 1 %tmp12 = extractelement <4 x float> %tmp9, i32 2 %tmp13 = extractelement <4 x float> %tmp9, i32 3 - %tmp14 = call float @fabs(float %tmp12) + %tmp14 = call float @fabsf(float %tmp12) %tmp15 = fdiv float 1.000000e+00, %tmp14 %tmp16 = fmul float %tmp10, %tmp15 %tmp17 = fadd float %tmp16, 1.500000e+00 @@ -48,7 +48,7 @@ declare <4 x float> @llvm.r600.cube(<4 x float>) #0 ; Function Attrs: readnone -declare float @fabs(float) #0 +declare float @fabsf(float) #0 declare void @llvm.r600.store.swizzle(<4 x float>, i32, i32) Index: llvm/test/CodeGen/AMDGPU/schedule-if-2.ll =================================================================== --- llvm/test/CodeGen/AMDGPU/schedule-if-2.ll +++ llvm/test/CodeGen/AMDGPU/schedule-if-2.ll @@ -17,7 +17,7 @@ br i1 %10, label %IF, label %ELSE IF: ; preds = %main_body - %11 = call float @fabs(float %2) + %11 = call float @fabsf(float %2) %12 = fcmp ueq float %11, 0x7FF0000000000000 %13 = select i1 %12, float 1.000000e+00, float 0.000000e+00 %14 = fsub float -0.000000e+00, %13 @@ -87,7 +87,7 @@ br label %ENDIF } -declare float @fabs(float) #0 +declare float @fabsf(float) #0 declare void @llvm.r600.store.swizzle(<4 x float>, i32, i32) Index: llvm/test/Transforms/DeadStoreElimination/simple.ll =================================================================== --- llvm/test/Transforms/DeadStoreElimination/simple.ll +++ llvm/test/Transforms/DeadStoreElimination/simple.ll @@ -266,7 +266,7 @@ declare noalias i8* @malloc(i64) willreturn declare noalias i8* @custom_malloc(i32) willreturn -declare noalias i8* @calloc(i32, i32) willreturn +declare noalias i8* @calloc(i64, i64) willreturn define void @test14(i32* %Q) { ; CHECK-LABEL: @test14( @@ -321,7 +321,7 @@ ; CHECK-LABEL: @test21( ; CHECK-NEXT: ret void ; - %m = call i8* @calloc(i32 9, i32 7) + %m = call i8* @calloc(i64 9, i64 7) store i8 0, i8* %m ret void } Index: llvm/test/Transforms/InferFunctionAttrs/annotate-2.ll =================================================================== --- llvm/test/Transforms/InferFunctionAttrs/annotate-2.ll +++ llvm/test/Transforms/InferFunctionAttrs/annotate-2.ll @@ -3,11 +3,26 @@ ; annotate.ll. ; ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -inferattrs -opaque-pointers -S | FileCheck --match-full-lines %s +; RUN: opt < %s -inferattrs -opaque-pointers -S | FileCheck %s --match-full-lines + + +; Exercise function declarations. + +; Expect double fabs(double). +declare float @fabs(float) +; CHECK: declare float @fabs(float) ; Exercise function declarations. +; Expect int fgetc(FILE*). +declare i32 @fgetc(ptr, i32) +; CHECK: declare i32 @fgetc(ptr, i32) + +; Expect char* fgets(char*, int, FILE*). +declare i32 @fgets(ptr, i32, ptr) +; CHECK: declare i32 @fgets(ptr, i32, ptr) + ; Expect int sprintf(char*, const char*, ...). declare i32 @sprintf(ptr, i64, ptr, ...) ; CHECK: declare i32 @sprintf(ptr, i64, ptr, ...) Index: llvm/test/Transforms/InferFunctionAttrs/annotate.ll =================================================================== --- llvm/test/Transforms/InferFunctionAttrs/annotate.ll +++ llvm/test/Transforms/InferFunctionAttrs/annotate.ll @@ -314,8 +314,8 @@ ; CHECK: declare x86_fp80 @ceill(x86_fp80) [[NOFREE_NOUNWIND_WILLRETURN_WRITEONLY]] declare x86_fp80 @ceill(x86_fp80) -; CHECK: declare noundef i32 @chmod(i8* nocapture noundef readonly, i16 noundef zeroext) [[NOFREE_NOUNWIND]] -declare i32 @chmod(i8*, i16 zeroext) +; CHECK: declare noundef i32 @chmod(i8* nocapture noundef readonly, i32 noundef zeroext) [[NOFREE_NOUNWIND]] +declare i32 @chmod(i8*, i32 zeroext) ; CHECK: declare noundef i32 @chown(i8* nocapture noundef readonly, i32 noundef, i32 noundef) [[NOFREE_NOUNWIND]] declare i32 @chown(i8*, i32, i32) Index: llvm/test/Transforms/InstCombine/bcopy.ll =================================================================== --- llvm/test/Transforms/InstCombine/bcopy.ll +++ llvm/test/Transforms/InstCombine/bcopy.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -passes=instcombine -S | FileCheck %s +; RUN: opt < %s -passes=instcombine -data-layout=p:32:32 -S | FileCheck %s declare void @bcopy(i8* nocapture readonly, i8* nocapture, i32) Index: llvm/test/Transforms/InstCombine/deref-alloc-fns.ll =================================================================== --- llvm/test/Transforms/InstCombine/deref-alloc-fns.ll +++ llvm/test/Transforms/InstCombine/deref-alloc-fns.ll @@ -12,7 +12,7 @@ declare noalias i8* @aligned_alloc(i64, i64) declare noalias align 16 i8* @memalign(i64, i64) ; new[](unsigned int, align_val_t) -declare noalias i8* @_ZnajSt11align_val_t(i64 %size, i64 %align) +declare noalias i8* @_ZnamSt11align_val_t(i64 %size, i64 %align) @.str = private unnamed_addr constant [6 x i8] c"hello\00", align 1 @@ -347,10 +347,10 @@ define noalias i8* @op_new_align() { ; CHECK-LABEL: @op_new_align( -; CHECK-NEXT: [[CALL:%.*]] = tail call align 32 dereferenceable_or_null(32) i8* @_ZnajSt11align_val_t(i64 32, i64 32) +; CHECK-NEXT: [[CALL:%.*]] = tail call align 32 dereferenceable_or_null(32) i8* @_ZnamSt11align_val_t(i64 32, i64 32) ; CHECK-NEXT: ret i8* [[CALL]] ; - %call = tail call i8* @_ZnajSt11align_val_t(i64 32, i64 32) + %call = tail call i8* @_ZnamSt11align_val_t(i64 32, i64 32) ret i8* %call } Index: llvm/test/Transforms/InstCombine/fprintf-1.ll =================================================================== --- llvm/test/Transforms/InstCombine/fprintf-1.ll +++ llvm/test/Transforms/InstCombine/fprintf-1.ll @@ -12,6 +12,7 @@ @percent_d = constant [3 x i8] c"%d\00" @percent_f = constant [3 x i8] c"%f\00" @percent_s = constant [3 x i8] c"%s\00" +@percent_m = constant [3 x i8] c"%m\00" declare i32 @fprintf(%FILE*, i8*, ...) @@ -96,3 +97,15 @@ ret i32 %1 ; CHECK-NEXT: ret i32 %1 } + +; Verify that a call with a format string containing just the %m directive +; and no arguments is not simplified. + +define void @test_no_simplify4(%FILE* %fp) { +; CHECK-LABEL: @test_no_simplify4( + %fmt = getelementptr [3 x i8], [3 x i8]* @percent_m, i32 0, i32 0 + call i32 (%FILE*, i8*, ...) @fprintf(%FILE* %fp, i8* %fmt) +; CHECK-NEXT: call i32 (%FILE*, i8*, ...) @fprintf(%FILE* %fp, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @percent_m, i32 0, i32 0)) + ret void +; CHECK-NEXT: ret void +} Index: llvm/test/Transforms/InstCombine/fwrite-1.ll =================================================================== --- llvm/test/Transforms/InstCombine/fwrite-1.ll +++ llvm/test/Transforms/InstCombine/fwrite-1.ll @@ -2,7 +2,7 @@ ; ; 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" +target datalayout = "e-p:64:64:64" %FILE = type { } Index: llvm/test/Transforms/InstCombine/mem-deref-bytes.ll =================================================================== --- llvm/test/Transforms/InstCombine/mem-deref-bytes.ll +++ llvm/test/Transforms/InstCombine/mem-deref-bytes.ll @@ -4,7 +4,7 @@ declare i32 @memcmp(i8* nocapture, i8* nocapture, i64) declare i8* @memcpy(i8* nocapture, i8* nocapture, i64) declare i8* @memmove(i8* nocapture, i8* nocapture, i64) -declare i8* @memset(i8* nocapture, i8, i64) +declare i8* @memset(i8* nocapture, i32, i64) declare i8* @memchr(i8* nocapture, i32, i64) declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i1) declare void @llvm.memmove.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i1) @@ -118,12 +118,13 @@ ret i8* %call } -define i8* @memset_const_size_set_deref(i8* nocapture readonly %s, i8 %c) { +define i8* @memset_const_size_set_deref(i8* nocapture readonly %s, i32 %c) { ; CHECK-LABEL: @memset_const_size_set_deref( -; CHECK-NEXT: tail call void @llvm.memset.p0i8.i64(i8* noundef nonnull align 1 dereferenceable(64) [[S:%.*]], i8 [[C:%.*]], i64 64, i1 false) +; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[C:%.*]] to i8 +; CHECK-NEXT: tail call void @llvm.memset.p0i8.i64(i8* noundef nonnull align 1 dereferenceable(64) [[S:%.*]], i8 [[TMP1]], i64 64, i1 false) ; CHECK-NEXT: ret i8* [[S]] ; - %call = tail call i8* @memset(i8* %s, i8 %c, i64 64) + %call = tail call i8* @memset(i8* %s, i32 %c, i64 64) ret i8* %call } Index: llvm/test/Transforms/InstCombine/new-delete-itanium-32.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/InstCombine/new-delete-itanium-32.ll @@ -0,0 +1,100 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -passes=instcombine -S | FileCheck %s + +; Set pointer (and size_t) size to 32 bits. This lets the declarations +; below and calls to them be recognized as special. + +target datalayout = "p:32:32" + +%size_t = type i32 +%align_val_t = type %size_t +%nothrow_t = type { } + + +; operator new(size_t = unsigned int) +declare i8* @_Znwj(%size_t) + +; operator new[](size_t = unsigned int) +declare i8* @_Znaj(%size_t) + +; operator new(size_t = unsigned int, std::align_val_t) +declare i8* @_ZnwjSt11align_val_t(%size_t, %size_t) + +; operator new[](size_t = unsigned int, std::align_val_t) +declare i8* @_ZnajSt11align_val_t(%size_t, %size_t) + +; operator new(size_t = unsigned int, std::align_val_t, const std::nothrow_t&) +declare i8* @_ZnwjSt11align_val_tRKSt9nothrow_t(%size_t, %size_t, %nothrow_t*) + +; operator new[](size_t = unsigned int, std::align_val_t, const std::nothrow_t&) +declare i8* @_ZnajSt11align_val_tRKSt9nothrow_t(%size_t, %size_t, %nothrow_t*) + + +; operator delete(void*, size_t = unsigned int) +declare void @_ZdlPvj(i8*, %size_t) + +; operator delete[](void*, size_t = unsigned int) +declare void @_ZdaPvj(i8*, %size_t) + +; operator delete(void*, std::align_val_t) +declare void @_ZdlPvSt11align_val_t(i8*, %align_val_t) + +; operator delete[](void*, std::align_val_t) +declare void @_ZdaPvSt11align_val_t(i8*, %align_val_t) + +; operator delete(void*, size_t = unsigned int, std::align_val_t) +declare void @_ZdlPvjSt11align_val_t(i8*, %size_t, %align_val_t) + +; operator delete[](void*, size_t = unsigned int, std::align_val_t) +declare void @_ZdaPvjSt11align_val_t(i8*, %size_t, %align_val_t) + +; operator delete(void*, std::align_val_t, const std::nothrow_t&) +declare void @_ZdlPvSt11align_val_tRKSt9nothrow_t(i8*, %align_val_t, %nothrow_t*) + +; operator delete[](void*, std::align_val_t, const std::nothrow_t&) +declare void @_ZdaPvSt11align_val_tRKSt9nothrow_t(i8*, %align_val_t, %nothrow_t*) + +declare void @llvm.assume(i1) + + +; Verify that pairs of matching calls to new/delete are eliminated. + +define void @elim_new_delete_pairs() { +; CHECK-LABEL: @elim_new_delete_pairs( +; CHECK-NEXT: ret void +; + %nt = alloca %nothrow_t + + %nwj = call i8* @_Znwj(%size_t 32) + call void @_ZdlPvj(i8* %nwj, %size_t 32) + + %naj = call i8* @_Znaj(%size_t 32) + call void @_ZdaPvj(i8* %naj, %size_t 32) + + %nwja = call i8* @_ZnwjSt11align_val_t(%size_t 32, %size_t 8) + call void @_ZdlPvSt11align_val_t(i8* %nwja, %size_t 8) + + %naja = call i8* @_ZnajSt11align_val_t(%size_t 32, %size_t 8) + call void @_ZdaPvSt11align_val_t(i8* %naja, i32 8) + + %nwjat = call i8* @_ZnwjSt11align_val_tRKSt9nothrow_t(%size_t 32, %size_t 8, %nothrow_t* %nt) + call void @_ZdlPvSt11align_val_tRKSt9nothrow_t(i8* %nwjat, %size_t 8, %nothrow_t* %nt) + + %najat = call i8* @_ZnajSt11align_val_tRKSt9nothrow_t(%size_t 32, %size_t 8, %nothrow_t* %nt) + call void @_ZdaPvSt11align_val_tRKSt9nothrow_t(i8* %najat, i32 8, %nothrow_t* %nt) + + %nwja2 = call i8* @_ZnwjSt11align_val_t(%size_t 32, %size_t 8) + call void @_ZdlPvjSt11align_val_t(i8* %nwja2, %size_t 32, %size_t 8) + + %naja2 = call i8* @_ZnajSt11align_val_t(%size_t 32, %size_t 8) + call void @_ZdaPvjSt11align_val_t(i8* %naja2, %size_t 32, %size_t 8) + + ; Check that the alignment assume does not prevent the removal. + %nwa3 = call i8* @_ZnajSt11align_val_t(%size_t 32, %size_t 16) + + call void @llvm.assume(i1 true) [ "align"(i8* %nwa3, i32 16) ] + + call void @_ZdaPvjSt11align_val_t(i8* %nwa3, %size_t 32, %size_t 16) + + ret void +} Index: llvm/test/Transforms/InstCombine/new-delete-itanium.ll =================================================================== --- llvm/test/Transforms/InstCombine/new-delete-itanium.ll +++ llvm/test/Transforms/InstCombine/new-delete-itanium.ll @@ -111,16 +111,12 @@ ; new(size_t, align_val_t) declare i8* @_ZnwmSt11align_val_t(i64, i64) nobuiltin -declare i8* @_ZnwjSt11align_val_t(i32, i32) nobuiltin ; new[](size_t, align_val_t) declare i8* @_ZnamSt11align_val_t(i64, i64) nobuiltin -declare i8* @_ZnajSt11align_val_t(i32, i32) nobuiltin ; new(size_t, align_val_t, nothrow) declare i8* @_ZnwmSt11align_val_tRKSt9nothrow_t(i64, i64, i8*) nobuiltin -declare i8* @_ZnwjSt11align_val_tRKSt9nothrow_t(i32, i32, i8*) nobuiltin ; new[](size_t, align_val_t, nothrow) declare i8* @_ZnamSt11align_val_tRKSt9nothrow_t(i64, i64, i8*) nobuiltin -declare i8* @_ZnajSt11align_val_tRKSt9nothrow_t(i32, i32, i8*) nobuiltin ; delete(void*, align_val_t) declare void @_ZdlPvSt11align_val_t(i8*, i64) nobuiltin ; delete[](void*, align_val_t) @@ -129,12 +125,8 @@ declare void @_ZdlPvSt11align_val_tRKSt9nothrow_t(i8*, i64, i8*) nobuiltin ; delete[](void*, align_val_t, nothrow) declare void @_ZdaPvSt11align_val_tRKSt9nothrow_t(i8*, i64, i8*) nobuiltin -; delete(void*, unsigned int, align_val_t) -declare void @_ZdlPvjSt11align_val_t(i8*, i32, i32) nobuiltin ; delete(void*, unsigned long, align_val_t) declare void @_ZdlPvmSt11align_val_t(i8*, i64, i64) nobuiltin -; delete[](void*, unsigned int, align_val_t) -declare void @_ZdaPvjSt11align_val_t(i8*, i32, i32) nobuiltin ; delete[](void*, unsigned long, align_val_t) declare void @_ZdaPvmSt11align_val_t(i8*, i64, i64) nobuiltin @@ -151,36 +143,20 @@ call void @_ZdaPv(i8* %na) builtin %nwm = call i8* @_Znwm(i64 32) builtin call void @_ZdlPvm(i8* %nwm, i64 32) builtin - %nwj = call i8* @_Znwj(i32 32) builtin - call void @_ZdlPvj(i8* %nwj, i32 32) builtin %nam = call i8* @_Znam(i64 32) builtin call void @_ZdaPvm(i8* %nam, i64 32) builtin - %naj = call i8* @_Znaj(i32 32) builtin - call void @_ZdaPvj(i8* %naj, i32 32) builtin %nwa = call i8* @_ZnwmSt11align_val_t(i64 32, i64 8) builtin call void @_ZdlPvSt11align_val_t(i8* %nwa, i64 8) builtin %naa = call i8* @_ZnamSt11align_val_t(i64 32, i64 8) builtin call void @_ZdaPvSt11align_val_t(i8* %naa, i64 8) builtin - %nwja = call i8* @_ZnwjSt11align_val_t(i32 32, i32 8) builtin - call void @_ZdlPvSt11align_val_t(i8* %nwja, i64 8) builtin - %naja = call i8* @_ZnajSt11align_val_t(i32 32, i32 8) builtin - call void @_ZdaPvSt11align_val_t(i8* %naja, i64 8) builtin %nwat = call i8* @_ZnwmSt11align_val_tRKSt9nothrow_t(i64 32, i64 8, i8* %nt) builtin call void @_ZdlPvSt11align_val_tRKSt9nothrow_t(i8* %nwat, i64 8, i8* %nt) builtin %naat = call i8* @_ZnamSt11align_val_tRKSt9nothrow_t(i64 32, i64 8, i8* %nt) builtin call void @_ZdaPvSt11align_val_tRKSt9nothrow_t(i8* %naat, i64 8, i8* %nt) builtin - %nwjat = call i8* @_ZnwjSt11align_val_tRKSt9nothrow_t(i32 32, i32 8, i8* %nt) builtin - call void @_ZdlPvSt11align_val_tRKSt9nothrow_t(i8* %nwjat, i64 8, i8* %nt) builtin - %najat = call i8* @_ZnajSt11align_val_tRKSt9nothrow_t(i32 32, i32 8, i8* %nt) builtin - call void @_ZdaPvSt11align_val_tRKSt9nothrow_t(i8* %najat, i64 8, i8* %nt) builtin %nwa2 = call i8* @_ZnwmSt11align_val_t(i64 32, i64 8) builtin call void @_ZdlPvmSt11align_val_t(i8* %nwa2, i64 32, i64 8) builtin - %nwja2 = call i8* @_ZnwjSt11align_val_t(i32 32, i32 8) builtin - call void @_ZdlPvjSt11align_val_t(i8* %nwa2, i32 32, i32 8) builtin %naa2 = call i8* @_ZnamSt11align_val_t(i64 32, i64 8) builtin call void @_ZdaPvmSt11align_val_t(i8* %naa2, i64 32, i64 8) builtin - %naja2 = call i8* @_ZnajSt11align_val_t(i32 32, i32 8) builtin - call void @_ZdaPvjSt11align_val_t(i8* %naja2, i32 32, i32 8) builtin ; Check that the alignment assume does not prevent the removal. %nwa3 = call i8* @_ZnwmSt11align_val_t(i64 32, i64 16) builtin Index: llvm/test/Transforms/InstCombine/printf-2.ll =================================================================== --- llvm/test/Transforms/InstCombine/printf-2.ll +++ llvm/test/Transforms/InstCombine/printf-2.ll @@ -12,7 +12,7 @@ @charstr = constant [2 x i8] c"a\00" @empty = constant [1 x i8] c"\00" -declare void @printf(i8*, ...) +declare i32 @printf(i8*, ...) ; Check simplification of printf with void return type. @@ -33,7 +33,7 @@ ; CHECK-NEXT: ret void ; %fmt = getelementptr [2 x i8], [2 x i8]* @h, i32 0, i32 0 - call void (i8*, ...) @printf(i8* %fmt) + call i32 (i8*, ...) @printf(i8* %fmt) ret void } @@ -43,7 +43,7 @@ ; CHECK-NEXT: ret void ; %fmt = getelementptr [13 x i8], [13 x i8]* @hello_world, i32 0, i32 0 - call void (i8*, ...) @printf(i8* %fmt) + call i32 (i8*, ...) @printf(i8* %fmt) ret void } @@ -54,7 +54,7 @@ ; %fmt = getelementptr [4 x i8], [4 x i8]* @percent_s, i32 0, i32 0 %str = getelementptr [13 x i8], [13 x i8]* @hello_world, i32 0, i32 0 - call void (i8*, ...) @printf(i8* %fmt, i8* %str) + call i32 (i8*, ...) @printf(i8* %fmt, i8* %str) ret void } @@ -65,7 +65,7 @@ ; %fmt = getelementptr [3 x i8], [3 x i8]* @format_str, i32 0, i32 0 %str = getelementptr [2 x i8], [2 x i8]* @charstr, i32 0, i32 0 - call void (i8*, ...) @printf(i8* %fmt, i8* %str) + call i32 (i8*, ...) @printf(i8* %fmt, i8* %str) ret void } @@ -77,7 +77,7 @@ ; %fmt = getelementptr [3 x i8], [3 x i8]* @format_str, i32 0, i32 0 %str = getelementptr [1 x i8], [1 x i8]* @empty, i32 0, i32 0 - call void (i8*, ...) @printf(i8* %fmt, i8* %str) + call i32 (i8*, ...) @printf(i8* %fmt, i8* %str) ret void } @@ -90,7 +90,7 @@ ; %fmt = getelementptr [3 x i8], [3 x i8]* @format_str, i32 0, i32 0 %str = getelementptr [13 x i8], [13 x i8]* @hello_world, i32 0, i32 0 - call void (i8*, ...) @printf(i8* %fmt, i8* %str) + call i32 (i8*, ...) @printf(i8* %fmt, i8* %str) ret void } @@ -106,11 +106,11 @@ ; %fmt = getelementptr [3 x i8], [3 x i8]* @format_str, i32 0, i32 0 %str1 = getelementptr [1 x i8], [1 x i8]* @empty, i32 0, i32 0 - call void (i8*, ...) @printf(i8* %fmt, i8* %str1, i32 42, double 0x40091EB860000000) + call i32 (i8*, ...) @printf(i8* %fmt, i8* %str1, i32 42, double 0x40091EB860000000) %str2 = getelementptr [2 x i8], [2 x i8]* @charstr, i32 0, i32 0 - call void (i8*, ...) @printf(i8* %fmt, i8* %str2, i32 42, double 0x40091EB860000000) + call i32 (i8*, ...) @printf(i8* %fmt, i8* %str2, i32 42, double 0x40091EB860000000) %str3 = getelementptr [13 x i8], [13 x i8]* @hello_world, i32 0, i32 0 - call void (i8*, ...) @printf(i8* %fmt, i8* %str3, i32 42, double 0x40091EB860000000) + call i32 (i8*, ...) @printf(i8* %fmt, i8* %str3, i32 42, double 0x40091EB860000000) ret void } ;. Index: llvm/test/Transforms/InstCombine/simplify-libcalls-i16.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/InstCombine/simplify-libcalls-i16.ll @@ -0,0 +1,340 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -S < %s -mtriple=unknown -passes=instcombine -instcombine-infinite-loop-threshold=2 | FileCheck -check-prefixes=CHECK,CHECK32 %s +; RUN: opt -S < %s -mtriple=msp430 -passes=instcombine -instcombine-infinite-loop-threshold=2 | FileCheck -check-prefixes=CHECK,CHECK16 %s +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-f80:128:128-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32-S32" + +@G = constant [3 x i8] c"%s\00" ; <[3 x i8]*> [#uses=1] + +; A 16-bit compatible sprintf is not recognized as the standard library +; function on 32-bit targets. +declare i16 @sprintf(i8*, i8*, ...) + +define void @foo(i8* %P, i32* %X) { +; CHECK32-LABEL: @foo( +; CHECK32-NEXT: [[TMP1:%.*]] = call i16 (i8*, i8*, ...) @sprintf(i8* [[P:%.*]], i8* getelementptr inbounds ([3 x i8], [3 x i8]* @G, i32 0, i32 0), i32* [[X:%.*]]) +; CHECK32-NEXT: ret void +; +; CHECK16-LABEL: @foo( +; CHECK16-NEXT: [[CSTR:%.*]] = bitcast i32* [[X:%.*]] to i8* +; CHECK16-NEXT: [[STRCPY:%.*]] = call i8* @strcpy(i8* noundef nonnull dereferenceable(1) [[P:%.*]], i8* noundef nonnull dereferenceable(1) [[CSTR]]) +; CHECK16-NEXT: ret void +; + call i16 (i8*, i8*, ...) @sprintf(i8* %P, i8* getelementptr ([3 x i8], [3 x i8]* @G, i32 0, i32 0), i32* %X ) ; :1 [#uses=0] + ret void +} + +; PR1307 +@str = internal constant [5 x i8] c"foog\00" +@str1 = internal constant [8 x i8] c"blahhh!\00" +@str2 = internal constant [5 x i8] c"Ponk\00" + +define i8* @test1() { +; CHECK32-LABEL: @test1( +; CHECK32-NEXT: [[TMP3:%.*]] = tail call i8* @strchr(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @str, i32 0, i32 2), i16 103) +; CHECK32-NEXT: ret i8* [[TMP3]] +; +; CHECK16-LABEL: @test1( +; CHECK16-NEXT: ret i8* getelementptr inbounds ([5 x i8], [5 x i8]* @str, i32 0, i32 3) +; + %tmp3 = tail call i8* @strchr( i8* getelementptr ([5 x i8], [5 x i8]* @str, i32 0, i16 2), i16 103 ) ; [#uses=1] + ret i8* %tmp3 +} + +; A 16-bit compatible strchr is not recognized as the standard library +; function on 32-bit targets. +declare i8* @strchr(i8*, i16) + +define i8* @test2() { +; CHECK32-LABEL: @test2( +; CHECK32-NEXT: [[TMP3:%.*]] = tail call i8* @strchr(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @str1, i32 0, i32 2), i16 0) +; CHECK32-NEXT: ret i8* [[TMP3]] +; +; CHECK16-LABEL: @test2( +; CHECK16-NEXT: ret i8* getelementptr inbounds ([8 x i8], [8 x i8]* @str1, i32 0, i32 7) +; + %tmp3 = tail call i8* @strchr( i8* getelementptr ([8 x i8], [8 x i8]* @str1, i32 0, i32 2), i16 0 ) ; [#uses=1] + ret i8* %tmp3 +} + +define i8* @test3() { +; CHECK32-LABEL: @test3( +; CHECK32-NEXT: entry: +; CHECK32-NEXT: [[TMP3:%.*]] = tail call i8* @strchr(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @str2, i32 0, i32 1), i16 80) +; CHECK32-NEXT: ret i8* [[TMP3]] +; +; CHECK16-LABEL: @test3( +; CHECK16-NEXT: entry: +; CHECK16-NEXT: ret i8* null +; +entry: + %tmp3 = tail call i8* @strchr( i8* getelementptr ([5 x i8], [5 x i8]* @str2, i32 0, i32 1), i16 80 ) ; [#uses=1] + ret i8* %tmp3 + +} + +@_2E_str = external constant [5 x i8] ; <[5 x i8]*> [#uses=1] + +; A 16-bit compatible memcmp is not recognized as the standard library +; function on 32-bit targets. +declare i16 @memcmp(i8*, i8*, i16) nounwind readonly + +define i1 @PR2341(i8** %start_addr) { +; CHECK-LABEL: @PR2341( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP4:%.*]] = load i8*, i8** [[START_ADDR:%.*]], align 4 +; CHECK-NEXT: [[TMP5:%.*]] = call i16 @memcmp(i8* [[TMP4]], i8* getelementptr inbounds ([5 x i8], [5 x i8]* @_2E_str, i32 0, i32 0), i16 4) #[[ATTR0:[0-9]+]] +; CHECK-NEXT: [[TMP6:%.*]] = icmp eq i16 [[TMP5]], 0 +; CHECK-NEXT: ret i1 [[TMP6]] +; +entry: + %tmp4 = load i8*, i8** %start_addr, align 4 ; [#uses=1] + %tmp5 = call i16 @memcmp( i8* %tmp4, i8* getelementptr ([5 x i8], [5 x i8]* @_2E_str, i32 0, i32 0), i16 4 ) nounwind readonly ; [#uses=1] + %tmp6 = icmp eq i16 %tmp5, 0 ; [#uses=1] + ret i1 %tmp6 + +} + +define i16 @PR4284() nounwind { +; CHECK-LABEL: @PR4284( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[C0:%.*]] = alloca i8, align 1 +; CHECK-NEXT: [[C2:%.*]] = alloca i8, align 1 +; CHECK-NEXT: store i8 64, i8* [[C0]], align 1 +; CHECK-NEXT: store i8 -127, i8* [[C2]], align 1 +; CHECK-NEXT: [[CALL:%.*]] = call i16 @memcmp(i8* nonnull [[C0]], i8* nonnull [[C2]], i16 1) +; CHECK-NEXT: ret i16 [[CALL]] +; +entry: + %c0 = alloca i8, align 1 ; [#uses=2] + %c2 = alloca i8, align 1 ; [#uses=2] + store i8 64, i8* %c0 + store i8 -127, i8* %c2 + %call = call i16 @memcmp(i8* %c0, i8* %c2, i16 1) ; [#uses=1] + ret i16 %call + +} + +%struct.__sFILE = type { i8*, i32, i32, i16, i16, %struct.__sbuf, i32, i8*, i32 (i8*)*, i32 (i8*, i8*, i32)*, i64 (i8*, i64, i32)*, i32 (i8*, i8*, i32)*, %struct.__sbuf, i8*, i32, [3 x i8], [1 x i8], %struct.__sbuf, i32, i64, %struct.pthread_mutex*, %struct.pthread*, i32, i32, %union.anon } +%struct.__sbuf = type { i8*, i32, [4 x i8] } +%struct.pthread = type opaque +%struct.pthread_mutex = type opaque +%union.anon = type { i64, [120 x i8] } +@.str13 = external constant [2 x i8] ; <[2 x i8]*> [#uses=1] +@.str14 = external constant [2 x i8] ; <[2 x i8]*> [#uses=1] + +define i32 @PR4641(i32 %argc, i8** %argv, i1 %c1, i8* %ptr) nounwind { +; CHECK-LABEL: @PR4641( +; CHECK-NEXT: entry: +; CHECK-NEXT: call void @exit(i16 0) #[[ATTR1:[0-9]+]] +; CHECK-NEXT: [[COND392:%.*]] = select i1 [[C1:%.*]], i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str13, i32 0, i32 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str14, i32 0, i32 0) +; CHECK-NEXT: [[CALL393:%.*]] = call %struct.__sFILE* @fopen(i8* [[PTR:%.*]], i8* [[COND392]]) #[[ATTR1]] +; CHECK-NEXT: unreachable +; +entry: + call void @exit(i16 0) nounwind + %cond392 = select i1 %c1, i8* getelementptr ([2 x i8], [2 x i8]* @.str13, i32 0, i32 0), i8* getelementptr ([2 x i8], [2 x i8]* @.str14, i32 0, i32 0) ; [#uses=1] + %call393 = call %struct.__sFILE* @fopen(i8* %ptr, i8* %cond392) nounwind ; <%struct.__sFILE*> [#uses=0] + unreachable +} + +declare %struct.__sFILE* @fopen(i8*, i8*) + +; A 16-bit compatible exit is not recognized as the standard library +; function on 32-bit targets. +declare void @exit(i16) + +define i32 @PR4645(i1 %c1) { +; CHECK-LABEL: @PR4645( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[IF_THEN:%.*]] +; CHECK: lor.lhs.false: +; CHECK-NEXT: br i1 [[C1:%.*]], label [[IF_THEN]], label [[FOR_COND:%.*]] +; CHECK: if.then: +; CHECK-NEXT: call void @exit(i16 1) +; CHECK-NEXT: br label [[FOR_COND]] +; CHECK: for.cond: +; CHECK-NEXT: unreachable +; CHECK: for.end: +; CHECK-NEXT: br label [[FOR_COND]] +; +entry: + br label %if.then + +lor.lhs.false: ; preds = %while.body + br i1 %c1, label %if.then, label %for.cond + +if.then: ; preds = %lor.lhs.false, %while.body + call void @exit(i16 1) + br label %for.cond + +for.cond: ; preds = %for.end, %if.then, %lor.lhs.false + %j.0 = phi i32 [ %inc47, %for.end ], [ 0, %if.then ], [ 0, %lor.lhs.false ] ; [#uses=1] + unreachable + +for.end: ; preds = %for.cond20 + %inc47 = add i32 %j.0, 1 ; [#uses=1] + br label %for.cond +} + +@h = constant [2 x i8] c"h\00" ; <[2 x i8]*> [#uses=1] +@hel = constant [4 x i8] c"hel\00" ; <[4 x i8]*> [#uses=1] +@hello_u = constant [8 x i8] c"hello_u\00" ; <[8 x i8]*> [#uses=1] + +define i32 @MemCpy() { +; CHECK-LABEL: @MemCpy( +; CHECK-NEXT: ret i32 0 +; + %h_p = getelementptr [2 x i8], [2 x i8]* @h, i32 0, i32 0 + %hel_p = getelementptr [4 x i8], [4 x i8]* @hel, i32 0, i32 0 + %hello_u_p = getelementptr [8 x i8], [8 x i8]* @hello_u, i32 0, i32 0 + %target = alloca [1024 x i8] + %target_p = getelementptr [1024 x i8], [1024 x i8]* %target, i32 0, i32 0 + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 2 %target_p, i8* align 2 %h_p, i16 2, i1 false) + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %target_p, i8* align 4 %hel_p, i16 4, i1 false) + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %target_p, i8* align 8 %hello_u_p, i16 8, i1 false) + ret i32 0 + +} + +declare void @llvm.memcpy.p0i8.p0i8.i32(i8* nocapture, i8* nocapture, i16, i1) + +; A 16-bit compatible strcmp is not recognized as the standard library +; function on 32-bit targets. +declare i16 @strcmp(i8*, i8*) #0 + +define void @test9(i8* %x) { +; CHECK32-LABEL: @test9( +; CHECK32-NEXT: [[Y:%.*]] = call i16 @strcmp(i8* [[X:%.*]], i8* [[X]]) #[[ATTR5:[0-9]+]] +; CHECK32-NEXT: ret void +; +; CHECK16-LABEL: @test9( +; CHECK16-NEXT: ret void +; + %y = call i16 @strcmp(i8* %x, i8* %x) #1 + ret void +} + +; PR30484 - https://llvm.org/bugs/show_bug.cgi?id=30484 +; These aren't the library functions you're looking for... + +declare i32 @isdigit(i8) +declare i32 @isascii(i8) +declare i32 @toascii(i8) + +define i32 @fake_isdigit(i8 %x) { +; CHECK-LABEL: @fake_isdigit( +; CHECK-NEXT: [[Y:%.*]] = call i32 @isdigit(i8 [[X:%.*]]) +; CHECK-NEXT: ret i32 [[Y]] +; + %y = call i32 @isdigit(i8 %x) + ret i32 %y +} + +define i32 @fake_isascii(i8 %x) { +; CHECK-LABEL: @fake_isascii( +; CHECK-NEXT: [[Y:%.*]] = call i32 @isascii(i8 [[X:%.*]]) +; CHECK-NEXT: ret i32 [[Y]] +; + %y = call i32 @isascii(i8 %x) + ret i32 %y +} + +define i32 @fake_toascii(i8 %x) { +; CHECK-LABEL: @fake_toascii( +; CHECK-NEXT: [[Y:%.*]] = call i32 @toascii(i8 [[X:%.*]]) +; CHECK-NEXT: ret i32 [[Y]] +; + %y = call i32 @toascii(i8 %x) + ret i32 %y +} + +declare double @pow(double, double) +declare double @exp2(double) + +; check to make sure only the correct libcall attributes are used +define double @fake_exp2(double %x) { +; CHECK-LABEL: @fake_exp2( +; CHECK-NEXT: [[EXP2:%.*]] = call double @exp2(double [[X:%.*]]) +; CHECK-NEXT: ret double [[EXP2]] +; + + %y = call inreg double @pow(double inreg 2.0, double inreg %x) + ret double %y +} +define double @fake_ldexp(i32 %x) { +; CHECK32-LABEL: @fake_ldexp( +; CHECK32-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i32 [[X:%.*]]) +; CHECK32-NEXT: ret double [[LDEXP]] +; +; CHECK16-LABEL: @fake_ldexp( +; CHECK16-NEXT: [[Y:%.*]] = sitofp i32 [[X:%.*]] to double +; CHECK16-NEXT: [[Z:%.*]] = call inreg double @exp2(double [[Y]]) +; CHECK16-NEXT: ret double [[Z]] +; + + + %y = sitofp i32 %x to double + %z = call inreg double @exp2(double %y) + ret double %z +} +define double @fake_ldexp_16(i16 %x) { +; CHECK32-LABEL: @fake_ldexp_16( +; CHECK32-NEXT: [[TMP1:%.*]] = sext i16 [[X:%.*]] to i32 +; CHECK32-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i32 [[TMP1]]) +; CHECK32-NEXT: ret double [[LDEXP]] +; +; CHECK16-LABEL: @fake_ldexp_16( +; CHECK16-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i16 [[X:%.*]]) +; CHECK16-NEXT: ret double [[LDEXP]] +; + + + %y = sitofp i16 %x to double + %z = call inreg double @exp2(double %y) + ret double %z +} + +; PR50885 - this would crash in ValueTracking. + +; A 16-bit compatible snprintf is not recognized as the standard library +; function on 32-bit targets. +declare i16 @snprintf(i8*, double, i32*) + +define i16 @fake_snprintf(i32 %buf, double %len, i32 * %str, i8* %ptr) { +; CHECK-LABEL: @fake_snprintf( +; CHECK-NEXT: [[CALL:%.*]] = call i16 @snprintf(i8* [[PTR:%.*]], double [[LEN:%.*]], i32* [[STR:%.*]]) +; CHECK-NEXT: ret i16 [[CALL]] +; + %call = call i16 @snprintf(i8* %ptr, double %len, i32* %str) + ret i16 %call +} + +; Wrong return type for the real strlen. +; https://llvm.org/PR50836 + +define i4 @strlen(i8* %s) { +; CHECK-LABEL: @strlen( +; CHECK-NEXT: [[R:%.*]] = call i4 @strlen(i8* [[S:%.*]]) +; CHECK-NEXT: ret i4 0 +; + %r = call i4 @strlen(i8* %s) + ret i4 0 +} + +; Test emission of stpncpy. +@a = dso_local global [4 x i8] c"123\00" +@b = dso_local global [5 x i8] zeroinitializer +declare i8* @__stpncpy_chk(i8* noundef, i8* noundef, i32 noundef, i32 noundef) +define signext i32 @emit_stpncpy() { +; CHECK-LABEL: @emit_stpncpy( +; CHECK-NEXT: [[STPNCPY:%.*]] = call i8* @stpncpy(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @b, i32 0, i32 0), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @a, i32 0, i32 0), i32 2) +; CHECK-NEXT: ret i32 0 +; + %call = call i8* @__stpncpy_chk(i8* noundef getelementptr inbounds ([5 x i8], [5 x i8]* @b, i32 0, i32 0), + i8* noundef getelementptr inbounds ([4 x i8], [4 x i8]* @a, i32 0, i32 0), + i32 noundef 2, i32 noundef 5) + ret i32 0 +} + +attributes #0 = { nobuiltin } +attributes #1 = { builtin } Index: llvm/test/Transforms/InstCombine/simplify-libcalls.ll =================================================================== --- llvm/test/Transforms/InstCombine/simplify-libcalls.ll +++ llvm/test/Transforms/InstCombine/simplify-libcalls.ll @@ -5,13 +5,19 @@ @G = constant [3 x i8] c"%s\00" ; <[3 x i8]*> [#uses=1] +; A 32-bit compatible sprintf is not recognized as the standard library +; function on 16-bit targets. declare i32 @sprintf(i8*, i8*, ...) define void @foo(i8* %P, i32* %X) { -; CHECK-LABEL: @foo( -; CHECK-NEXT: [[CSTR:%.*]] = bitcast i32* [[X:%.*]] to i8* -; CHECK-NEXT: [[STRCPY:%.*]] = call i8* @strcpy(i8* noundef nonnull dereferenceable(1) [[P:%.*]], i8* noundef nonnull dereferenceable(1) [[CSTR]]) -; CHECK-NEXT: ret void +; CHECK32-LABEL: @foo( +; CHECK32-NEXT: [[CSTR:%.*]] = bitcast i32* [[X:%.*]] to i8* +; CHECK32-NEXT: [[STRCPY:%.*]] = call i8* @strcpy(i8* noundef nonnull dereferenceable(1) [[P:%.*]], i8* noundef nonnull dereferenceable(1) [[CSTR]]) +; CHECK32-NEXT: ret void +; +; CHECK16-LABEL: @foo( +; CHECK16-NEXT: [[TMP1:%.*]] = call i32 (i8*, i8*, ...) @sprintf(i8* [[P:%.*]], i8* getelementptr inbounds ([3 x i8], [3 x i8]* @G, i32 0, i32 0), i32* [[X:%.*]]) +; CHECK16-NEXT: ret void ; call i32 (i8*, i8*, ...) @sprintf( i8* %P, i8* getelementptr ([3 x i8], [3 x i8]* @G, i32 0, i32 0), i32* %X ) ; :1 [#uses=0] ret void @@ -23,27 +29,42 @@ @str2 = internal constant [5 x i8] c"Ponk\00" define i8* @test1() { -; CHECK-LABEL: @test1( -; CHECK-NEXT: ret i8* getelementptr inbounds ([5 x i8], [5 x i8]* @str, i32 0, i32 3) +; CHECK32-LABEL: @test1( +; CHECK32-NEXT: ret i8* getelementptr inbounds ([5 x i8], [5 x i8]* @str, i32 0, i32 3) +; +; CHECK16-LABEL: @test1( +; CHECK16-NEXT: [[TMP3:%.*]] = tail call i8* @strchr(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @str, i32 0, i32 2), i32 103) +; CHECK16-NEXT: ret i8* [[TMP3]] ; %tmp3 = tail call i8* @strchr( i8* getelementptr ([5 x i8], [5 x i8]* @str, i32 0, i32 2), i32 103 ) ; [#uses=1] ret i8* %tmp3 } +; A 32-bit compatible strchr is not recognized as the standard library +; function on 16-bit targets. declare i8* @strchr(i8*, i32) define i8* @test2() { -; CHECK-LABEL: @test2( -; CHECK-NEXT: ret i8* getelementptr inbounds ([8 x i8], [8 x i8]* @str1, i32 0, i32 7) +; CHECK32-LABEL: @test2( +; CHECK32-NEXT: ret i8* getelementptr inbounds ([8 x i8], [8 x i8]* @str1, i32 0, i32 7) +; +; CHECK16-LABEL: @test2( +; CHECK16-NEXT: [[TMP3:%.*]] = tail call i8* @strchr(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @str1, i32 0, i32 2), i32 0) +; CHECK16-NEXT: ret i8* [[TMP3]] ; %tmp3 = tail call i8* @strchr( i8* getelementptr ([8 x i8], [8 x i8]* @str1, i32 0, i32 2), i32 0 ) ; [#uses=1] ret i8* %tmp3 } define i8* @test3() { -; CHECK-LABEL: @test3( -; CHECK-NEXT: entry: -; CHECK-NEXT: ret i8* null +; CHECK32-LABEL: @test3( +; CHECK32-NEXT: entry: +; CHECK32-NEXT: ret i8* null +; +; CHECK16-LABEL: @test3( +; CHECK16-NEXT: entry: +; CHECK16-NEXT: [[TMP3:%.*]] = tail call i8* @strchr(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @str2, i32 0, i32 1), i32 80) +; CHECK16-NEXT: ret i8* [[TMP3]] ; entry: %tmp3 = tail call i8* @strchr( i8* getelementptr ([5 x i8], [5 x i8]* @str2, i32 0, i32 1), i32 80 ) ; [#uses=1] @@ -53,15 +74,24 @@ @_2E_str = external constant [5 x i8] ; <[5 x i8]*> [#uses=1] +; A 32-bit compatible memcmp is not recognized as the standard library +; function on 16-bit targets. declare i32 @memcmp(i8*, i8*, i32) nounwind readonly define i1 @PR2341(i8** %start_addr) { -; CHECK-LABEL: @PR2341( -; CHECK-NEXT: entry: -; CHECK-NEXT: [[TMP4:%.*]] = load i8*, i8** [[START_ADDR:%.*]], align 4 -; CHECK-NEXT: [[TMP5:%.*]] = call i32 @memcmp(i8* noundef nonnull dereferenceable(4) [[TMP4]], i8* noundef nonnull dereferenceable(4) getelementptr inbounds ([5 x i8], [5 x i8]* @_2E_str, i32 0, i32 0), i32 4) #[[ATTR0:[0-9]+]] -; CHECK-NEXT: [[TMP6:%.*]] = icmp eq i32 [[TMP5]], 0 -; CHECK-NEXT: ret i1 [[TMP6]] +; CHECK32-LABEL: @PR2341( +; CHECK32-NEXT: entry: +; CHECK32-NEXT: [[TMP4:%.*]] = load i8*, i8** [[START_ADDR:%.*]], align 4 +; CHECK32-NEXT: [[TMP5:%.*]] = call i32 @memcmp(i8* noundef nonnull dereferenceable(4) [[TMP4]], i8* noundef nonnull dereferenceable(4) getelementptr inbounds ([5 x i8], [5 x i8]* @_2E_str, i32 0, i32 0), i32 4) #[[ATTR0:[0-9]+]] +; CHECK32-NEXT: [[TMP6:%.*]] = icmp eq i32 [[TMP5]], 0 +; CHECK32-NEXT: ret i1 [[TMP6]] +; +; CHECK16-LABEL: @PR2341( +; CHECK16-NEXT: entry: +; CHECK16-NEXT: [[TMP4:%.*]] = load i8*, i8** [[START_ADDR:%.*]], align 4 +; CHECK16-NEXT: [[TMP5:%.*]] = call i32 @memcmp(i8* [[TMP4]], i8* getelementptr inbounds ([5 x i8], [5 x i8]* @_2E_str, i32 0, i32 0), i32 4) #[[ATTR0:[0-9]+]] +; CHECK16-NEXT: [[TMP6:%.*]] = icmp eq i32 [[TMP5]], 0 +; CHECK16-NEXT: ret i1 [[TMP6]] ; entry: %tmp4 = load i8*, i8** %start_addr, align 4 ; [#uses=1] @@ -72,9 +102,18 @@ } define i32 @PR4284() nounwind { -; CHECK-LABEL: @PR4284( -; CHECK-NEXT: entry: -; CHECK-NEXT: ret i32 -65 +; CHECK32-LABEL: @PR4284( +; CHECK32-NEXT: entry: +; CHECK32-NEXT: ret i32 -65 +; +; CHECK16-LABEL: @PR4284( +; CHECK16-NEXT: entry: +; CHECK16-NEXT: [[C0:%.*]] = alloca i8, align 1 +; CHECK16-NEXT: [[C2:%.*]] = alloca i8, align 1 +; CHECK16-NEXT: store i8 64, i8* [[C0]], align 1 +; CHECK16-NEXT: store i8 -127, i8* [[C2]], align 1 +; CHECK16-NEXT: [[CALL:%.*]] = call i32 @memcmp(i8* nonnull [[C0]], i8* nonnull [[C2]], i32 1) +; CHECK16-NEXT: ret i32 [[CALL]] ; entry: %c0 = alloca i8, align 1 ; [#uses=2] @@ -111,6 +150,8 @@ declare %struct.__sFILE* @fopen(i8*, i8*) +; A 32-bit compatible exit is not recognized as the standard library +; function on 16-bit targets. declare void @exit(i32) define i32 @PR4645(i1 %c1) { @@ -168,11 +209,17 @@ declare void @llvm.memcpy.p0i8.p0i8.i32(i8* nocapture, i8* nocapture, i32, i1) nounwind +; A 32-bit compatible strcmp is not recognized as the standard library +; function on 16-bit targets. declare i32 @strcmp(i8*, i8*) #0 define void @test9(i8* %x) { -; CHECK-LABEL: @test9( -; CHECK-NEXT: ret void +; CHECK32-LABEL: @test9( +; CHECK32-NEXT: ret void +; +; CHECK16-LABEL: @test9( +; CHECK16-NEXT: [[Y:%.*]] = call i32 @strcmp(i8* [[X:%.*]], i8* [[X]]) #[[ATTR5:[0-9]+]] +; CHECK16-NEXT: ret void ; %y = call i32 @strcmp(i8* %x, i8* %x) #1 ret void @@ -260,6 +307,8 @@ ; PR50885 - this would crash in ValueTracking. +; A 32-bit compatible snprintf is not recognized as the standard library +; function on 16-bit targets. declare i32 @snprintf(i8*, double, i32*) define i32 @fake_snprintf(i32 %buf, double %len, i32 * %str, i8* %ptr) { Index: llvm/test/Transforms/InstCombine/sprintf-3.ll =================================================================== --- llvm/test/Transforms/InstCombine/sprintf-3.ll +++ llvm/test/Transforms/InstCombine/sprintf-3.ll @@ -1,4 +1,4 @@ -; Test that the stpcpy library call simplifier works correctly. +; Regression test for PR51200. ; ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt < %s -passes=instcombine -S | FileCheck %s @@ -10,14 +10,9 @@ 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]] +; Don't check anything, just expect the test to compile successfully. ; %call = call i32 (i8**, i32*, ...) @sprintf(i8** %p, i32* bitcast ([3 x i8]* @percent_s to i32*), i32* %p2) ret i32 %call Index: llvm/test/Transforms/InstCombine/sqrt-nofast.ll =================================================================== --- llvm/test/Transforms/InstCombine/sqrt-nofast.ll +++ llvm/test/Transforms/InstCombine/sqrt-nofast.ll @@ -25,19 +25,20 @@ declare float @llvm.sqrt.f32(float) #1 -; FIXME: -; This is a function called "sqrtf", but its type is double. -; Assume it is a user function rather than a libm function, -; so don't transform it. +; The call below is to a function called "sqrtf", but its type is double. +; Assume it is a user function rather than a libm function, and so don't +; transform it. define double @fake_sqrt(double %a, double %b) { ; CHECK-LABEL: @fake_sqrt( -; CHECK-NEXT: [[FABS:%.*]] = call fast double @llvm.fabs.f64(double [[A:%.*]]) -; CHECK-NEXT: ret double [[FABS]] +; CHECK-NEXT: [[C:%.*]] = fmul fast double [[A:%.*]], [[A]] +; CHECK-NEXT: [[E:%.*]] = call fast double @sqrtf(double [[C]]) #[[ATTR1:[0-9]+]] +; CHECK-NEXT: ret double [[E]] ; %c = fmul fast double %a, %a %e = call fast double @sqrtf(double %c) readnone ret double %e } -declare double @sqrtf(double) readnone ; This is not the 'sqrt' you're looking for. +; Standard sqrtf takes and returns float. The following is not it. +declare double @sqrtf(double) readnone Index: llvm/test/Transforms/InstCombine/stdiocall-bad-sig.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/InstCombine/stdiocall-bad-sig.ll @@ -0,0 +1,62 @@ +; Verify that calls to known stdio 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 + +declare i32 @fwrite(i8*, i64, i64, ptr) +declare i8 @fputc(ptr, ptr) + +declare void @printf(ptr) +declare i8 @fprintf(ptr, ptr) +declare i8 @sprintf(ptr, ptr) + + +@ca1 = constant [1 x i8] c"1" +@pcnt_s = constant [3 x i8] c"%s\00" + + +; Verify that a call to fwrite isn't transformed into one to fputc when +; the latter is declared with an incompatible signature (which might +; trigger an abort). + +define void @call_fwrite(ptr %fp) { + %p = getelementptr [1 x i8], ptr @ca1, i32 0, i32 0 + call i32 @fwrite(ptr %p, i64 1, i64 1, ptr %fp) + ret void +} + + +; Verify that a call to an incompatible void printf(char*) with just "%s" +; isn't transformed. + +define void @call_printf(ptr %s) { +; CHECK-LABEL: @call_printf( +; + %fmt = getelementptr [3 x i8], ptr @pcnt_s, i32 0, i32 0 + call i32 @printf(ptr %fmt) + ret void +} + +; Verify that a call to an incompatible int fprintf(FILE*, char*) isn't +; transformed. + +define i8 @call_fprintf(ptr %fp, ptr %p) { +; CHECK-LABEL: @call_fprintf( +; + %fmt = getelementptr [3 x i8], ptr @pcnt_s, i32 0, i32 0 + %call = call i8 (ptr, ptr, ...) @fprintf(ptr %fp, ptr %fmt, ptr %p) + ret i8 %call +} + +; Verify that a call to an incompatible int sprintf(FILE*, char*) isn't +; transformed. + +define i8 @call_sprintf(ptr %p, ptr %q) { +; CHECK-LABEL: @call_sprintf( +; + %fmt = getelementptr [3 x i8], ptr @pcnt_s, i32 0, i32 0 + %call = call i8 (ptr, ptr, ...) @sprintf(ptr %p, ptr %fmt, ptr %q) + ret i8 %call +} + Index: llvm/test/Transforms/InstCombine/stpcpy-2.ll =================================================================== --- llvm/test/Transforms/InstCombine/stpcpy-2.ll +++ llvm/test/Transforms/InstCombine/stpcpy-2.ll @@ -8,7 +8,7 @@ @hello = constant [6 x i8] c"hello\00" @a = common global [32 x i8] zeroinitializer, align 1 -declare i16* @stpcpy(i8*, i8*) +declare i16 @stpcpy(i8*, i8*) define void @test_no_simplify1() { ; CHECK-LABEL: @test_no_simplify1( @@ -16,7 +16,7 @@ %dst = getelementptr [32 x i8], [32 x i8]* @a, i32 0, i32 0 %src = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0 - call i16* @stpcpy(i8* %dst, i8* %src) -; CHECK: call i16* @stpcpy + call i16 @stpcpy(i8* %dst, i8* %src) +; CHECK: call i16 @stpcpy ret void } Index: llvm/test/Transforms/InstCombine/stpcpy_chk-2.ll =================================================================== --- llvm/test/Transforms/InstCombine/stpcpy_chk-2.ll +++ llvm/test/Transforms/InstCombine/stpcpy_chk-2.ll @@ -13,9 +13,9 @@ %dst = getelementptr inbounds [60 x i16], [60 x i16]* @a, i32 0, i32 0 %src = getelementptr inbounds [8 x i8], [8 x i8]* @.str, i32 0, i32 0 -; CHECK-NEXT: call i16* @__strcpy_chk - call i16* @__strcpy_chk(i16* %dst, i8* %src, i32 8) +; CHECK-NEXT: call i16 @__strcpy_chk + call i16 @__strcpy_chk(i16* %dst, i8* %src, i32 8) ret void } -declare i16* @__strcpy_chk(i16*, i8*, i32) +declare i16 @__strcpy_chk(i16*, i8*, i32) Index: llvm/test/Transforms/InstCombine/strcall-bad-sig.ll =================================================================== --- llvm/test/Transforms/InstCombine/strcall-bad-sig.ll +++ llvm/test/Transforms/InstCombine/strcall-bad-sig.ll @@ -164,14 +164,3 @@ %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 Index: llvm/test/Transforms/InstCombine/strcat-3.ll =================================================================== --- llvm/test/Transforms/InstCombine/strcat-3.ll +++ llvm/test/Transforms/InstCombine/strcat-3.ll @@ -1,4 +1,5 @@ -; Test that the strcat libcall simplifier works correctly. +; Test that the strcat folder avoids simplifying a call to the function +; declared with an incompatible type. ; ; RUN: opt < %s -passes=instcombine -S | FileCheck %s @@ -8,15 +9,16 @@ @empty = constant [1 x i8] c"\00" @a = common global [32 x i8] zeroinitializer, align 1 -declare i16* @strcat(i8*, i8*) +; Expected type: i8* @strcat(i8*, i8*). +declare i16 @strcat(i8*, i8*) define void @test_nosimplify1() { ; CHECK-LABEL: @test_nosimplify1( -; CHECK: call i16* @strcat +; CHECK: call i16 @strcat ; CHECK: ret void %dst = getelementptr [32 x i8], [32 x i8]* @a, i32 0, i32 0 %src = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0 - call i16* @strcat(i8* %dst, i8* %src) + call i16 @strcat(i8* %dst, i8* %src) ret void } Index: llvm/test/Transforms/InstCombine/strcpy-2.ll =================================================================== --- llvm/test/Transforms/InstCombine/strcpy-2.ll +++ llvm/test/Transforms/InstCombine/strcpy-2.ll @@ -1,4 +1,6 @@ -; Test that the strcpy library call simplifier works correctly. +; Test that the strcpy folder avoids simplifying a call to the function +; declared with an incompatible type. +; ; RUN: opt < %s -passes=instcombine -S | FileCheck %s ; ; This transformation requires the pointer size, as it assumes that size_t is @@ -8,7 +10,8 @@ @hello = constant [6 x i8] c"hello\00" @a = common global [32 x i8] zeroinitializer, align 1 -declare i16* @strcpy(i8*, i8*) +; Expected type: i8* @strcpy(i8*, i8*) +declare i16 @strcpy(i8*, i8*) define void @test_no_simplify1() { ; CHECK-LABEL: @test_no_simplify1( @@ -16,7 +19,7 @@ %dst = getelementptr [32 x i8], [32 x i8]* @a, i32 0, i32 0 %src = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0 - call i16* @strcpy(i8* %dst, i8* %src) -; CHECK: call i16* @strcpy + call i16 @strcpy(i8* %dst, i8* %src) +; CHECK: call i16 @strcpy ret void } Index: llvm/test/Transforms/InstCombine/strcpy_chk-2.ll =================================================================== --- llvm/test/Transforms/InstCombine/strcpy_chk-2.ll +++ llvm/test/Transforms/InstCombine/strcpy_chk-2.ll @@ -13,9 +13,9 @@ %dst = getelementptr inbounds [60 x i16], [60 x i16]* @a, i32 0, i32 0 %src = getelementptr inbounds [8 x i8], [8 x i8]* @.str, i32 0, i32 0 -; CHECK-NEXT: call i16* @__strcpy_chk - call i16* @__strcpy_chk(i16* %dst, i8* %src, i32 8) +; CHECK-NEXT: call i16 @__strcpy_chk + call i16 @__strcpy_chk(i16* %dst, i8* %src, i32 8) ret void } -declare i16* @__strcpy_chk(i16*, i8*, i32) +declare i16 @__strcpy_chk(i16*, i8*, i32) Index: llvm/test/Transforms/InstCombine/strncat-3.ll =================================================================== --- llvm/test/Transforms/InstCombine/strncat-3.ll +++ llvm/test/Transforms/InstCombine/strncat-3.ll @@ -1,6 +1,7 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; Test that the strncat libcall simplifier works correctly. +; Test that the strncat folder avoids simplifying a call to the function +; declared with an incompatible type. ; +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; 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" @@ -9,16 +10,16 @@ @empty = constant [1 x i8] c"\00" @a = common global [32 x i8] zeroinitializer, align 1 -declare i16* @strncat(i8*, i8*, i32) +declare i16 @strncat(i8*, i8*, i32) define void @test_nosimplify1() { ; CHECK-LABEL: @test_nosimplify1( -; CHECK-NEXT: [[TMP1:%.*]] = call i16* @strncat(i8* getelementptr inbounds ([32 x i8], [32 x i8]* @a, i32 0, i32 0), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @hello, i32 0, i32 0), i32 13) +; CHECK-NEXT: [[TMP1:%.*]] = call i16 @strncat(i8* getelementptr inbounds ([32 x i8], [32 x i8]* @a, i32 0, i32 0), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @hello, i32 0, i32 0), i32 13) ; CHECK-NEXT: ret void ; %dst = getelementptr [32 x i8], [32 x i8]* @a, i32 0, i32 0 %src = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0 - call i16* @strncat(i8* %dst, i8* %src, i32 13) + call i16 @strncat(i8* %dst, i8* %src, i32 13) ret void } Index: llvm/test/Transforms/InstCombine/strncpy-2.ll =================================================================== --- llvm/test/Transforms/InstCombine/strncpy-2.ll +++ llvm/test/Transforms/InstCombine/strncpy-2.ll @@ -1,3 +1,6 @@ +; Test that the strncpy folder avoids simplifying a call to the function +; declared with an incompatible type. +; ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; Test that the strncpy library call simplifier works correctly. ; @@ -8,18 +11,18 @@ @hello = constant [6 x i8] c"hello\00" @a = common global [32 x i8] zeroinitializer, align 1 -declare i16* @strncpy(i8*, i8*, i32) +declare i16 @strncpy(i8*, i8*, i32) ; Check that 'strncpy' functions with the wrong prototype aren't simplified. define void @test_no_simplify1() { ; CHECK-LABEL: @test_no_simplify1( -; CHECK-NEXT: [[TMP1:%.*]] = call i16* @strncpy(i8* getelementptr inbounds ([32 x i8], [32 x i8]* @a, i32 0, i32 0), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @hello, i32 0, i32 0), i32 6) +; CHECK-NEXT: [[TMP1:%.*]] = call i16 @strncpy(i8* getelementptr inbounds ([32 x i8], [32 x i8]* @a, i32 0, i32 0), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @hello, i32 0, i32 0), i32 6) ; CHECK-NEXT: ret void ; %dst = getelementptr [32 x i8], [32 x i8]* @a, i32 0, i32 0 %src = getelementptr [6 x i8], [6 x i8]* @hello, i32 0, i32 0 - call i16* @strncpy(i8* %dst, i8* %src, i32 6) + call i16 @strncpy(i8* %dst, i8* %src, i32 6) ret void } Index: llvm/test/Transforms/InstCombine/strncpy_chk-2.ll =================================================================== --- llvm/test/Transforms/InstCombine/strncpy_chk-2.ll +++ llvm/test/Transforms/InstCombine/strncpy_chk-2.ll @@ -13,9 +13,9 @@ %dst = getelementptr inbounds [60 x i16], [60 x i16]* @a, i32 0, i32 0 %src = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0 -; CHECK-NEXT: call i16* @__strncpy_chk - call i16* @__strncpy_chk(i16* %dst, i8* %src, i32 60, i32 60) +; CHECK-NEXT: call i16 @__strncpy_chk + call i16 @__strncpy_chk(i16* %dst, i8* %src, i32 60, i32 60) ret void } -declare i16* @__strncpy_chk(i16*, i8*, i32, i32) +declare i16 @__strncpy_chk(i16*, i8*, i32, i32) Index: llvm/test/Transforms/InstCombine/strpbrk-2.ll =================================================================== --- llvm/test/Transforms/InstCombine/strpbrk-2.ll +++ llvm/test/Transforms/InstCombine/strpbrk-2.ll @@ -1,4 +1,5 @@ -; Test that the strpbrk library call simplifier works correctly. +; Test that the strpbrk folder doesn't simplify a call to the function +; declared with an incompatible prototype. ; ; RUN: opt < %s -passes=instcombine -S | FileCheck %s @@ -7,17 +8,17 @@ @hello = constant [12 x i8] c"hello world\00" @w = constant [2 x i8] c"w\00" -declare i16* @strpbrk(i8*, i8*) +declare i8 @strpbrk(i8*, i8*) ; Check that 'strpbrk' functions with the wrong prototype aren't simplified. -define i16* @test_no_simplify1() { +define i8 @test_no_simplify1() { ; CHECK-LABEL: @test_no_simplify1( %str = getelementptr [12 x i8], [12 x i8]* @hello, i32 0, i32 0 %pat = getelementptr [2 x i8], [2 x i8]* @w, i32 0, i32 0 - %ret = call i16* @strpbrk(i8* %str, i8* %pat) -; CHECK-NEXT: %ret = call i16* @strpbrk - ret i16* %ret -; CHECK-NEXT: ret i16* %ret + %ret = call i8 @strpbrk(i8* %str, i8* %pat) +; CHECK-NEXT: %ret = call i8 @strpbrk + ret i8 %ret +; CHECK-NEXT: ret i8 %ret } Index: llvm/test/Transforms/InstSimplify/call.ll =================================================================== --- llvm/test/Transforms/InstSimplify/call.ll +++ llvm/test/Transforms/InstSimplify/call.ll @@ -286,15 +286,15 @@ } ; Test a non-intrinsic that we know about as a library call. -declare float @fabs(float %x) +declare float @fabsf(float %x) define float @test_fabs_libcall() { ; CHECK-LABEL: @test_fabs_libcall( -; CHECK-NEXT: [[X:%.*]] = call float @fabs(float -4.200000e+01) +; CHECK-NEXT: [[X:%.*]] = call float @fabsf(float -4.200000e+01) ; CHECK-NEXT: ret float 4.200000e+01 ; - %x = call float @fabs(float -42.0) + %x = call float @fabsf(float -42.0) ; This is still a real function call, so instsimplify won't nuke it -- other ; passes have to do that. Index: llvm/test/Transforms/LoopUnroll/WebAssembly/basic-unrolling.ll =================================================================== --- llvm/test/Transforms/LoopUnroll/WebAssembly/basic-unrolling.ll +++ llvm/test/Transforms/LoopUnroll/WebAssembly/basic-unrolling.ll @@ -203,7 +203,7 @@ ; CHECK-NEXT: [[MUL:%.*]] = mul nsw i32 [[I1]], [[I]] ; CHECK-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds i32, i32* [[A:%.*]], i32 [[I_013]] ; CHECK-NEXT: store i32 [[MUL]], i32* [[ARRAYIDX2]], align 4 -; CHECK-NEXT: call void (i8*, ...) @printf(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([12 x i8], [12 x i8]* @.str, i32 0, i32 0), i32 [[I_013]], i32 [[MUL]]) +; CHECK-NEXT: call i32 (i8*, ...) @printf(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([12 x i8], [12 x i8]* @.str, i32 0, i32 0), i32 [[I_013]], i32 [[MUL]]) ; CHECK-NEXT: [[INC]] = add nuw i32 [[I_013]], 1 ; CHECK-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i32 [[INC]], [[N]] ; CHECK-NEXT: br i1 [[EXITCOND_NOT]], label [[FOR_COND_CLEANUP]], label [[FOR_BODY]] @@ -224,7 +224,7 @@ %mul = mul nsw i32 %i1, %i %arrayidx2 = getelementptr inbounds i32, i32* %a, i32 %i.013 store i32 %mul, i32* %arrayidx2, align 4 - call void (i8*, ...) @printf(i8* nonnull dereferenceable(1) getelementptr inbounds ([12 x i8], [12 x i8]* @.str, i32 0, i32 0), i32 %i.013, i32 %mul) + call i32 (i8*, ...) @printf(i8* nonnull dereferenceable(1) getelementptr inbounds ([12 x i8], [12 x i8]* @.str, i32 0, i32 0), i32 %i.013, i32 %mul) %inc = add nuw i32 %i.013, 1 %exitcond.not = icmp eq i32 %inc, %N br i1 %exitcond.not, label %for.cond.cleanup, label %for.body @@ -300,4 +300,4 @@ attributes #1 = { minsize } @.str = private unnamed_addr constant [12 x i8] c"a[%d] = %d\0A\00", align 1 -declare void @printf(i8* nocapture readonly, ...) +declare i32 @printf(i8* nocapture readonly, ...) Index: llvm/test/Transforms/LoopVectorize/AArch64/extractvalue-no-scalarization-required.ll =================================================================== --- llvm/test/Transforms/LoopVectorize/AArch64/extractvalue-no-scalarization-required.ll +++ llvm/test/Transforms/LoopVectorize/AArch64/extractvalue-no-scalarization-required.ll @@ -56,7 +56,7 @@ ; Similar to the test case above, but checks getVectorCallCost as well. -declare float @pow(float, float) readnone nounwind +declare float @powf(float, float) readnone nounwind ; CM: LV: Found uniform instruction: %a = extractvalue { float, float } %sv, 0 ; CM: LV: Found uniform instruction: %b = extractvalue { float, float } %sv, 1 @@ -94,7 +94,7 @@ %a = extractvalue { float, float } %sv, 0 %b = extractvalue { float, float } %sv, 1 %addr = getelementptr float, float* %dst, i32 %iv - %p = call float @pow(float %a, float %b) + %p = call float @powf(float %a, float %b) store float %p, float* %addr %iv.next = add nsw i32 %iv, 1 %cond = icmp ne i32 %iv.next, 0