Index: llvm/include/llvm/Analysis/TargetLibraryInfo.def =================================================================== --- llvm/include/llvm/Analysis/TargetLibraryInfo.def +++ llvm/include/llvm/Analysis/TargetLibraryInfo.def @@ -329,6 +329,10 @@ /// long double __logl_finite(long double x); TLI_DEFINE_ENUM_INTERNAL(logl_finite) TLI_DEFINE_STRING_INTERNAL("__logl_finite") +/// void *__memccpy_chk(void *dst, const void *src, int c, size_t n, +/// size_t dstsize) +TLI_DEFINE_ENUM_INTERNAL(memccpy_chk) +TLI_DEFINE_STRING_INTERNAL("__memccpy_chk") /// void *__memcpy_chk(void *s1, const void *s2, size_t n, size_t s1size); TLI_DEFINE_ENUM_INTERNAL(memcpy_chk) TLI_DEFINE_STRING_INTERNAL("__memcpy_chk") @@ -381,6 +385,14 @@ /// int __small_sprintf(char *str, const char *format, ...); TLI_DEFINE_ENUM_INTERNAL(small_sprintf) TLI_DEFINE_STRING_INTERNAL("__small_sprintf") +/// int __snprintf_chk(char *s, size_t n, int flags, size_t slen, +/// const char *format, ...); +TLI_DEFINE_ENUM_INTERNAL(snprintf_chk) +TLI_DEFINE_STRING_INTERNAL("__snprintf_chk") +/// int __sprintf_chk(char *str, int flags, size_t str_len, +/// const char *format, ...); +TLI_DEFINE_ENUM_INTERNAL(sprintf_chk) +TLI_DEFINE_STRING_INTERNAL("__sprintf_chk") /// double __sqrt_finite(double x); TLI_DEFINE_ENUM_INTERNAL(sqrt_finite) TLI_DEFINE_STRING_INTERNAL("__sqrt_finite") @@ -396,12 +408,26 @@ /// char *__stpncpy_chk(char *s1, const char *s2, size_t n, size_t s1size); TLI_DEFINE_ENUM_INTERNAL(stpncpy_chk) TLI_DEFINE_STRING_INTERNAL("__stpncpy_chk") +/// char *__strcat_chk(char *s1, const char *s2, size_t s1size); +TLI_DEFINE_ENUM_INTERNAL(strcat_chk) +TLI_DEFINE_STRING_INTERNAL("__strcat_chk") /// char *__strcpy_chk(char *s1, const char *s2, size_t s1size); TLI_DEFINE_ENUM_INTERNAL(strcpy_chk) TLI_DEFINE_STRING_INTERNAL("__strcpy_chk") /// char * __strdup(const char *s); TLI_DEFINE_ENUM_INTERNAL(dunder_strdup) TLI_DEFINE_STRING_INTERNAL("__strdup") +/// size_t __strlcat_chk(char *dst, const char *src, size_t size, +/// size_t dstsize); +TLI_DEFINE_ENUM_INTERNAL(strlcat_chk) +TLI_DEFINE_STRING_INTERNAL("__strlcat_chk") +/// size_t __strlcpy_chk(char *dst, const char *src, size_t size, +/// size_t dstsize); +TLI_DEFINE_ENUM_INTERNAL(strlcpy_chk) +TLI_DEFINE_STRING_INTERNAL("__strlcpy_chk") +/// char *strncat_chk(char *s1, const char *s2, size_t n, size_t s1size); +TLI_DEFINE_ENUM_INTERNAL(strncat_chk) +TLI_DEFINE_STRING_INTERNAL("__strncat_chk") /// char *__strncpy_chk(char *s1, const char *s2, size_t n, size_t s1size); TLI_DEFINE_ENUM_INTERNAL(strncpy_chk) TLI_DEFINE_STRING_INTERNAL("__strncpy_chk") @@ -411,6 +437,14 @@ /// char * __strtok_r(char *s, const char *delim, char **save_ptr); TLI_DEFINE_ENUM_INTERNAL(dunder_strtok_r) TLI_DEFINE_STRING_INTERNAL("__strtok_r") +/// int __vsnprintf_chk(char *s, size_t n, int flags, size_t slen, +/// const char *format, va_list ap); +TLI_DEFINE_ENUM_INTERNAL(vsnprintf_chk) +TLI_DEFINE_STRING_INTERNAL("__vsnprintf_chk") +/// int __vsprintf_chk(char *s, int flags, size_t slen, const char *format, +/// va_list ap); +TLI_DEFINE_ENUM_INTERNAL(vsprintf_chk) +TLI_DEFINE_STRING_INTERNAL("__vsprintf_chk") /// int abs(int j); TLI_DEFINE_ENUM_INTERNAL(abs) TLI_DEFINE_STRING_INTERNAL("abs") @@ -1200,6 +1234,12 @@ /// char *strdup(const char *s1); TLI_DEFINE_ENUM_INTERNAL(strdup) TLI_DEFINE_STRING_INTERNAL("strdup") +/// size_t strlcat(char *dst, const char *src, size_t size); +TLI_DEFINE_ENUM_INTERNAL(strlcat) +TLI_DEFINE_STRING_INTERNAL("strlcat") +/// size_t strlcpy(char *dst, const char *src, size_t size); +TLI_DEFINE_ENUM_INTERNAL(strlcpy) +TLI_DEFINE_STRING_INTERNAL("strlcpy") /// size_t strlen(const char *s); TLI_DEFINE_ENUM_INTERNAL(strlen) TLI_DEFINE_STRING_INTERNAL("strlen") Index: llvm/include/llvm/Transforms/Utils/BuildLibCalls.h =================================================================== --- llvm/include/llvm/Transforms/Utils/BuildLibCalls.h +++ llvm/include/llvm/Transforms/Utils/BuildLibCalls.h @@ -70,12 +70,22 @@ /// Emit a call to the strcpy function to the builder, for the specified /// pointer arguments. Value *emitStrCpy(Value *Dst, Value *Src, IRBuilder<> &B, - const TargetLibraryInfo *TLI, StringRef Name = "strcpy"); + const TargetLibraryInfo *TLI); + + /// Emit a call to the stpcpy function to the builder, for the specified + /// pointer arguments. + Value *emitStpCpy(Value *Dst, Value *Src, IRBuilder<> &B, + const TargetLibraryInfo *TLI); /// Emit a call to the strncpy function to the builder, for the specified /// pointer arguments and length. Value *emitStrNCpy(Value *Dst, Value *Src, Value *Len, IRBuilder<> &B, - const TargetLibraryInfo *TLI, StringRef Name = "strncpy"); + const TargetLibraryInfo *TLI); + + /// Emit a call to the stpncpy function to the builder, for the specified + /// pointer arguments and length. + Value *emitStpNCpy(Value *Dst, Value *Src, Value *Len, IRBuilder<> &B, + const TargetLibraryInfo *TLI); /// Emit a call to the __memcpy_chk function to the builder. This expects that /// the Len and ObjSize have type 'intptr_t' and Dst/Src are pointers. @@ -96,6 +106,26 @@ Value *emitBCmp(Value *Ptr1, Value *Ptr2, Value *Len, IRBuilder<> &B, const DataLayout &DL, const TargetLibraryInfo *TLI); + Value *emitMemCCpy(Value *Ptr1, Value *Ptr2, Value *Val, Value *Len, + IRBuilder<> &B, const TargetLibraryInfo *TLI); + Value *emitSNPrintf(Value *Dest, Value *Size, Value *Fmt, + ArrayRef Args, IRBuilder<> &B, + const TargetLibraryInfo *TLI); + Value *emitSPrintf(Value *Dest, Value *Fmt, ArrayRef VariadicArgs, + IRBuilder<> &B, const TargetLibraryInfo *TLI); + Value *emitStrCat(Value *Dest, Value *Src, IRBuilder<> &B, + const TargetLibraryInfo *TLI); + Value *emitStrLCpy(Value *Dest, Value *Src, Value *Size, IRBuilder<> &B, + const TargetLibraryInfo *TLI); + Value *emitStrLCat(Value *Dest, Value *Src, Value *Size, IRBuilder<> &B, + const TargetLibraryInfo *TLI); + Value *emitStrNCat(Value *Dest, Value *Src, Value *Size, IRBuilder<> &B, + const TargetLibraryInfo *TLI); + Value *emitVSNPrintf(Value *Dest, Value *Size, Value *Fmt, Value *VAList, + IRBuilder<> &B, const TargetLibraryInfo *TLI); + Value *emitVSPrintf(Value *Dest, Value *Fmt, Value *VAList, IRBuilder<> &B, + const TargetLibraryInfo *TLI); + /// Emit a call to the unary function named 'Name' (e.g. 'floor'). This /// function is known to take a single of type matching 'Op' and returns one /// value with the same type. If 'Op' is a long double, 'l' is added as the Index: llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h =================================================================== --- llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h +++ llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h @@ -56,15 +56,36 @@ Value *optimizeMemCpyChk(CallInst *CI, IRBuilder<> &B); Value *optimizeMemMoveChk(CallInst *CI, IRBuilder<> &B); Value *optimizeMemSetChk(CallInst *CI, IRBuilder<> &B); - - // Str/Stp cpy are similar enough to be handled in the same functions. + /// Str/Stp cpy are similar enough to be handled in the same functions. Value *optimizeStrpCpyChk(CallInst *CI, IRBuilder<> &B, LibFunc Func); Value *optimizeStrpNCpyChk(CallInst *CI, IRBuilder<> &B, LibFunc Func); + Value *optimizeMemCCpyChk(CallInst *CI, IRBuilder<> &B); + Value *optimizeSNPrintfChk(CallInst *CI, IRBuilder<> &B); + Value *optimizeSPrintfChk(CallInst *CI,IRBuilder<> &B); + Value *optimizeStrCatChk(CallInst *CI, IRBuilder<> &B); + Value *optimizeStrLCat(CallInst *CI, IRBuilder<> &B); + Value *optimizeStrNCatChk(CallInst *CI, IRBuilder<> &B); + Value *optimizeStrLCpyChk(CallInst *CI, IRBuilder<> &B); + Value *optimizeVSNPrintfChk(CallInst *CI, IRBuilder<> &B); + Value *optimizeVSPrintfChk(CallInst *CI, IRBuilder<> &B); /// Checks whether the call \p CI to a fortified libcall is foldable /// to the non-fortified version. + /// + /// \param SizeOp optionally set to the parameter index of an explicit buffer + /// size argument. For instance, set to '2' for __strncpy_chk. + /// + /// \param StrOp optionally set to the parameter index of the source string + /// parameter to strcpy-like functions, where only the strlen of the source + /// will be writtin into the destination. + /// + /// \param FlagsOp optionally set to the parameter index of a 'flags' + /// parameter. These are used by an implementation to opt-into stricter + /// checking. bool isFortifiedCallFoldable(CallInst *CI, unsigned ObjSizeOp, - unsigned SizeOp, bool isString); + Optional SizeOp = None, + Optional StrOp = None, + Optional FlagsOp = None); }; /// LibCallSimplifier - This class implements a collection of optimizations Index: llvm/lib/Analysis/TargetLibraryInfo.cpp =================================================================== --- llvm/lib/Analysis/TargetLibraryInfo.cpp +++ llvm/lib/Analysis/TargetLibraryInfo.cpp @@ -691,11 +691,21 @@ return ((NumParams == 2 || NumParams == 3) && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); + case LibFunc_strcat_chk: + --NumParams; + if (!IsSizeTTy(FTy.getParamType(NumParams))) + return false; + LLVM_FALLTHROUGH; case LibFunc_strcat: return (NumParams == 2 && FTy.getReturnType()->isPointerTy() && FTy.getParamType(0) == FTy.getReturnType() && FTy.getParamType(1) == FTy.getReturnType()); + case LibFunc_strncat_chk: + --NumParams; + if (!IsSizeTTy(FTy.getParamType(NumParams))) + return false; + LLVM_FALLTHROUGH; case LibFunc_strncat: return (NumParams == 3 && FTy.getReturnType()->isPointerTy() && FTy.getParamType(0) == FTy.getReturnType() && @@ -714,6 +724,19 @@ FTy.getParamType(0) == FTy.getParamType(1) && FTy.getParamType(0) == PCharTy); + case LibFunc_strlcat_chk: + case LibFunc_strlcpy_chk: + --NumParams; + if (!IsSizeTTy(FTy.getParamType(NumParams))) + return false; + LLVM_FALLTHROUGH; + case LibFunc_strlcat: + case LibFunc_strlcpy: + return NumParams == 3 && IsSizeTTy(FTy.getReturnType()) && + FTy.getParamType(0)->isPointerTy() && + FTy.getParamType(1)->isPointerTy() && + IsSizeTTy(FTy.getParamType(2)); + case LibFunc_strncpy_chk: case LibFunc_stpncpy_chk: --NumParams; @@ -784,10 +807,27 @@ return (NumParams >= 2 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy() && FTy.getReturnType()->isIntegerTy(32)); + + case LibFunc_sprintf_chk: + return NumParams == 4 && FTy.getParamType(0)->isPointerTy() && + FTy.getParamType(1)->isIntegerTy(32) && + IsSizeTTy(FTy.getParamType(2)) && + FTy.getParamType(3)->isPointerTy() && + FTy.getReturnType()->isIntegerTy(32); + case LibFunc_snprintf: return (NumParams == 3 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(2)->isPointerTy() && FTy.getReturnType()->isIntegerTy(32)); + + case LibFunc_snprintf_chk: + return NumParams == 5 && FTy.getParamType(0)->isPointerTy() && + IsSizeTTy(FTy.getParamType(1)) && + FTy.getParamType(2)->isIntegerTy(32) && + IsSizeTTy(FTy.getParamType(3)) && + FTy.getParamType(4)->isPointerTy() && + FTy.getReturnType()->isIntegerTy(32); + case LibFunc_setitimer: return (NumParams == 3 && FTy.getParamType(1)->isPointerTy() && FTy.getParamType(2)->isPointerTy()); @@ -836,6 +876,11 @@ FTy.getParamType(1)->isIntegerTy() && IsSizeTTy(FTy.getParamType(2))); + case LibFunc_memccpy_chk: + --NumParams; + if (!IsSizeTTy(FTy.getParamType(NumParams))) + return false; + LLVM_FALLTHROUGH; case LibFunc_memccpy: return (NumParams >= 2 && FTy.getParamType(1)->isPointerTy()); case LibFunc_memalign: @@ -1004,9 +1049,17 @@ 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) && + IsSizeTTy(FTy.getParamType(2)) && 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) && + IsSizeTTy(FTy.getParamType(3)) && FTy.getParamType(4)->isPointerTy(); case LibFunc_open: return (NumParams >= 2 && FTy.getParamType(0)->isPointerTy()); case LibFunc_opendir: Index: llvm/lib/Transforms/Utils/BuildLibCalls.cpp =================================================================== --- llvm/lib/Transforms/Utils/BuildLibCalls.cpp +++ llvm/lib/Transforms/Utils/BuildLibCalls.cpp @@ -789,100 +789,76 @@ return B.CreateBitCast(V, B.getInt8PtrTy(AS), "cstr"); } +static Value *emitLibCall(LibFunc TheLibFunc, Type *ReturnType, + ArrayRef ParamTypes, + ArrayRef Operands, IRBuilder<> &B, + const TargetLibraryInfo *TLI, + bool IsVaArgs = false) { + if (!TLI->has(TheLibFunc)) + return nullptr; + + Module *M = B.GetInsertBlock()->getModule(); + StringRef FuncName = TLI->getName(TheLibFunc); + FunctionType *FuncType = FunctionType::get(ReturnType, ParamTypes, IsVaArgs); + FunctionCallee Callee = M->getOrInsertFunction(FuncName, FuncType); + inferLibFuncAttributes(M, FuncName, *TLI); + CallInst *CI = B.CreateCall(Callee, Operands, FuncName); + if (const Function *F = + dyn_cast(Callee.getCallee()->stripPointerCasts())) + CI->setCallingConv(F->getCallingConv()); + return CI; +} + Value *llvm::emitStrLen(Value *Ptr, IRBuilder<> &B, const DataLayout &DL, const TargetLibraryInfo *TLI) { - if (!TLI->has(LibFunc_strlen)) - return nullptr; - - Module *M = B.GetInsertBlock()->getModule(); - StringRef StrlenName = TLI->getName(LibFunc_strlen); LLVMContext &Context = B.GetInsertBlock()->getContext(); - FunctionCallee StrLen = M->getOrInsertFunction( - StrlenName, DL.getIntPtrType(Context), B.getInt8PtrTy()); - inferLibFuncAttributes(M, StrlenName, *TLI); - CallInst *CI = B.CreateCall(StrLen, castToCStr(Ptr, B), StrlenName); - if (const Function *F = - dyn_cast(StrLen.getCallee()->stripPointerCasts())) - CI->setCallingConv(F->getCallingConv()); - - return CI; + return emitLibCall(LibFunc_strlen, DL.getIntPtrType(Context), + B.getInt8PtrTy(), castToCStr(Ptr, B), B, TLI); } Value *llvm::emitStrChr(Value *Ptr, char C, IRBuilder<> &B, const TargetLibraryInfo *TLI) { - if (!TLI->has(LibFunc_strchr)) - return nullptr; - - Module *M = B.GetInsertBlock()->getModule(); - StringRef StrChrName = TLI->getName(LibFunc_strchr); Type *I8Ptr = B.getInt8PtrTy(); Type *I32Ty = B.getInt32Ty(); - FunctionCallee StrChr = - M->getOrInsertFunction(StrChrName, I8Ptr, I8Ptr, I32Ty); - inferLibFuncAttributes(M, StrChrName, *TLI); - CallInst *CI = B.CreateCall( - StrChr, {castToCStr(Ptr, B), ConstantInt::get(I32Ty, C)}, StrChrName); - if (const Function *F = - dyn_cast(StrChr.getCallee()->stripPointerCasts())) - CI->setCallingConv(F->getCallingConv()); - return CI; + return emitLibCall(LibFunc_strchr, I8Ptr, {I8Ptr, I32Ty}, + {castToCStr(Ptr, B), ConstantInt::get(I32Ty, C)}, B, TLI); } Value *llvm::emitStrNCmp(Value *Ptr1, Value *Ptr2, Value *Len, IRBuilder<> &B, const DataLayout &DL, const TargetLibraryInfo *TLI) { - if (!TLI->has(LibFunc_strncmp)) - return nullptr; - - Module *M = B.GetInsertBlock()->getModule(); - StringRef StrNCmpName = TLI->getName(LibFunc_strncmp); LLVMContext &Context = B.GetInsertBlock()->getContext(); - FunctionCallee StrNCmp = - M->getOrInsertFunction(StrNCmpName, B.getInt32Ty(), B.getInt8PtrTy(), - B.getInt8PtrTy(), DL.getIntPtrType(Context)); - inferLibFuncAttributes(M, StrNCmpName, *TLI); - CallInst *CI = B.CreateCall( - StrNCmp, {castToCStr(Ptr1, B), castToCStr(Ptr2, B), Len}, StrNCmpName); - - if (const Function *F = - dyn_cast(StrNCmp.getCallee()->stripPointerCasts())) - CI->setCallingConv(F->getCallingConv()); - - return CI; + return emitLibCall( + LibFunc_strncmp, B.getInt32Ty(), + {B.getInt8PtrTy(), B.getInt8PtrTy(), DL.getIntPtrType(Context)}, + {castToCStr(Ptr1, B), castToCStr(Ptr2, B), Len}, B, TLI); } Value *llvm::emitStrCpy(Value *Dst, Value *Src, IRBuilder<> &B, - const TargetLibraryInfo *TLI, StringRef Name) { - if (!TLI->has(LibFunc_strcpy)) - return nullptr; + const TargetLibraryInfo *TLI) { + Type *I8Ptr = B.getInt8PtrTy(); + return emitLibCall(LibFunc_strcpy, I8Ptr, {I8Ptr, I8Ptr}, + {castToCStr(Dst, B), castToCStr(Src, B)}, B, TLI); +} - Module *M = B.GetInsertBlock()->getModule(); +Value *llvm::emitStpCpy(Value *Dst, Value *Src, IRBuilder<> &B, + const TargetLibraryInfo *TLI) { Type *I8Ptr = B.getInt8PtrTy(); - FunctionCallee StrCpy = M->getOrInsertFunction(Name, I8Ptr, I8Ptr, I8Ptr); - inferLibFuncAttributes(M, Name, *TLI); - CallInst *CI = - B.CreateCall(StrCpy, {castToCStr(Dst, B), castToCStr(Src, B)}, Name); - if (const Function *F = - dyn_cast(StrCpy.getCallee()->stripPointerCasts())) - CI->setCallingConv(F->getCallingConv()); - return CI; + return emitLibCall(LibFunc_stpcpy, I8Ptr, {I8Ptr, I8Ptr}, + {castToCStr(Dst, B), castToCStr(Src, B)}, B, TLI); } Value *llvm::emitStrNCpy(Value *Dst, Value *Src, Value *Len, IRBuilder<> &B, - const TargetLibraryInfo *TLI, StringRef Name) { - if (!TLI->has(LibFunc_strncpy)) - return nullptr; + const TargetLibraryInfo *TLI) { + Type *I8Ptr = B.getInt8PtrTy(); + return emitLibCall(LibFunc_strncpy, I8Ptr, {I8Ptr, I8Ptr, Len->getType()}, + {castToCStr(Dst, B), castToCStr(Src, B), Len}, B, TLI); +} - Module *M = B.GetInsertBlock()->getModule(); +Value *llvm::emitStpNCpy(Value *Dst, Value *Src, Value *Len, IRBuilder<> &B, + const TargetLibraryInfo *TLI) { Type *I8Ptr = B.getInt8PtrTy(); - FunctionCallee StrNCpy = - M->getOrInsertFunction(Name, I8Ptr, I8Ptr, I8Ptr, Len->getType()); - inferLibFuncAttributes(M, Name, *TLI); - CallInst *CI = B.CreateCall( - StrNCpy, {castToCStr(Dst, B), castToCStr(Src, B), Len}, Name); - if (const Function *F = - dyn_cast(StrNCpy.getCallee()->stripPointerCasts())) - CI->setCallingConv(F->getCallingConv()); - return CI; + return emitLibCall(LibFunc_stpncpy, I8Ptr, {I8Ptr, I8Ptr, Len->getType()}, + {castToCStr(Dst, B), castToCStr(Src, B), Len}, B, TLI); } Value *llvm::emitMemCpyChk(Value *Dst, Value *Src, Value *Len, Value *ObjSize, @@ -911,58 +887,100 @@ Value *llvm::emitMemChr(Value *Ptr, Value *Val, Value *Len, IRBuilder<> &B, const DataLayout &DL, const TargetLibraryInfo *TLI) { - if (!TLI->has(LibFunc_memchr)) - return nullptr; - - Module *M = B.GetInsertBlock()->getModule(); - StringRef MemChrName = TLI->getName(LibFunc_memchr); LLVMContext &Context = B.GetInsertBlock()->getContext(); - FunctionCallee MemChr = - M->getOrInsertFunction(MemChrName, B.getInt8PtrTy(), B.getInt8PtrTy(), - B.getInt32Ty(), DL.getIntPtrType(Context)); - inferLibFuncAttributes(M, MemChrName, *TLI); - CallInst *CI = B.CreateCall(MemChr, {castToCStr(Ptr, B), Val, Len}, MemChrName); - - if (const Function *F = - dyn_cast(MemChr.getCallee()->stripPointerCasts())) - CI->setCallingConv(F->getCallingConv()); - - return CI; -} - -// Common code for memcmp() and bcmp(), which have the exact same properties, -// just a slight difference in semantics. -static Value *emitMemCmpOrBcmp(llvm::LibFunc libfunc, Value *Ptr1, Value *Ptr2, - Value *Len, IRBuilder<> &B, const DataLayout &DL, - const TargetLibraryInfo *TLI) { - if (!TLI->has(libfunc)) - return nullptr; - - Module *M = B.GetInsertBlock()->getModule(); - StringRef CmpFnName = TLI->getName(libfunc); - LLVMContext &Context = B.GetInsertBlock()->getContext(); - FunctionCallee CmpFn = - M->getOrInsertFunction(CmpFnName, B.getInt32Ty(), B.getInt8PtrTy(), - B.getInt8PtrTy(), DL.getIntPtrType(Context)); - inferLibFuncAttributes(M, CmpFnName, *TLI); - CallInst *CI = B.CreateCall( - CmpFn, {castToCStr(Ptr1, B), castToCStr(Ptr2, B), Len}, CmpFnName); - - if (const Function *F = - dyn_cast(CmpFn.getCallee()->stripPointerCasts())) - CI->setCallingConv(F->getCallingConv()); - - return CI; + return emitLibCall( + LibFunc_memchr, B.getInt8PtrTy(), + {B.getInt8PtrTy(), B.getInt32Ty(), DL.getIntPtrType(Context)}, + {castToCStr(Ptr, B), Val, Len}, B, TLI); } Value *llvm::emitMemCmp(Value *Ptr1, Value *Ptr2, Value *Len, IRBuilder<> &B, const DataLayout &DL, const TargetLibraryInfo *TLI) { - return emitMemCmpOrBcmp(LibFunc_memcmp, Ptr1, Ptr2, Len, B, DL, TLI); + LLVMContext &Context = B.GetInsertBlock()->getContext(); + return emitLibCall( + LibFunc_memcmp, B.getInt32Ty(), + {B.getInt8PtrTy(), B.getInt8PtrTy(), DL.getIntPtrType(Context)}, + {castToCStr(Ptr1, B), castToCStr(Ptr2, B), Len}, B, TLI); } Value *llvm::emitBCmp(Value *Ptr1, Value *Ptr2, Value *Len, IRBuilder<> &B, const DataLayout &DL, const TargetLibraryInfo *TLI) { - return emitMemCmpOrBcmp(LibFunc_bcmp, Ptr1, Ptr2, Len, B, DL, TLI); + LLVMContext &Context = B.GetInsertBlock()->getContext(); + return emitLibCall( + LibFunc_bcmp, B.getInt32Ty(), + {B.getInt8PtrTy(), B.getInt8PtrTy(), DL.getIntPtrType(Context)}, + {castToCStr(Ptr1, B), castToCStr(Ptr2, B), Len}, B, TLI); +} + +Value *llvm::emitMemCCpy(Value *Ptr1, Value *Ptr2, Value *Val, Value *Len, + IRBuilder<> &B, const TargetLibraryInfo *TLI) { + return emitLibCall( + LibFunc_memccpy, B.getInt8PtrTy(), + {B.getInt8PtrTy(), B.getInt8PtrTy(), B.getInt32Ty(), Len->getType()}, + {Ptr1, Ptr2, Val, Len}, B, TLI); +} + +Value *llvm::emitSNPrintf(Value *Dest, Value *Size, Value *Fmt, + ArrayRef VariadicArgs, IRBuilder<> &B, + const TargetLibraryInfo *TLI) { + SmallVector Args{castToCStr(Dest, B), Size, castToCStr(Fmt, B)}; + Args.insert(Args.end(), VariadicArgs.begin(), VariadicArgs.end()); + return emitLibCall(LibFunc_snprintf, B.getInt32Ty(), + {B.getInt8PtrTy(), Size->getType(), B.getInt8PtrTy()}, + Args, B, TLI, /*IsVaArgs=*/true); +} + +Value *llvm::emitSPrintf(Value *Dest, Value *Fmt, + ArrayRef VariadicArgs, IRBuilder<> &B, + const TargetLibraryInfo *TLI) { + SmallVector Args{castToCStr(Dest, B), castToCStr(Fmt, B)}; + Args.insert(Args.end(), VariadicArgs.begin(), VariadicArgs.end()); + return emitLibCall(LibFunc_sprintf, B.getInt32Ty(), + {B.getInt8PtrTy(), B.getInt8PtrTy()}, Args, B, TLI, + /*IsVaArgs=*/true); +} + +Value *llvm::emitStrCat(Value *Dest, Value *Src, IRBuilder<> &B, + const TargetLibraryInfo *TLI) { + return emitLibCall(LibFunc_strcat, B.getInt8PtrTy(), + {B.getInt8PtrTy(), B.getInt8PtrTy()}, + {castToCStr(Dest, B), castToCStr(Src, B)}, B, TLI); +} + +Value *llvm::emitStrLCpy(Value *Dest, Value *Src, Value *Size, IRBuilder<> &B, + const TargetLibraryInfo *TLI) { + return emitLibCall(LibFunc_strlcpy, Size->getType(), + {B.getInt8PtrTy(), B.getInt8PtrTy(), Size->getType()}, + {castToCStr(Dest, B), castToCStr(Src, B), Size}, B, TLI); +} + +Value *llvm::emitStrLCat(Value *Dest, Value *Src, Value *Size, IRBuilder<> &B, + const TargetLibraryInfo *TLI) { + return emitLibCall(LibFunc_strlcat, Size->getType(), + {B.getInt8PtrTy(), B.getInt8PtrTy(), Size->getType()}, + {castToCStr(Dest, B), castToCStr(Src, B), Size}, B, TLI); +} + +Value *llvm::emitStrNCat(Value *Dest, Value *Src, Value *Size, IRBuilder<> &B, + const TargetLibraryInfo *TLI) { + return emitLibCall(LibFunc_strncat, B.getInt8PtrTy(), + {B.getInt8PtrTy(), B.getInt8PtrTy(), Size->getType()}, + {castToCStr(Dest, B), castToCStr(Src, B), Size}, B, TLI); +} + +Value *llvm::emitVSNPrintf(Value *Dest, Value *Size, Value *Fmt, Value *VAList, + IRBuilder<> &B, const TargetLibraryInfo *TLI) { + return emitLibCall( + LibFunc_vsnprintf, B.getInt32Ty(), + {B.getInt8PtrTy(), Size->getType(), B.getInt8PtrTy(), VAList->getType()}, + {castToCStr(Dest, B), Size, castToCStr(Fmt, B), VAList}, B, TLI); +} + +Value *llvm::emitVSPrintf(Value *Dest, Value *Fmt, Value *VAList, + IRBuilder<> &B, const TargetLibraryInfo *TLI) { + return emitLibCall(LibFunc_vsprintf, B.getInt32Ty(), + {B.getInt8PtrTy(), B.getInt8PtrTy(), VAList->getType()}, + {castToCStr(Dest, B), castToCStr(Fmt, B), VAList}, B, TLI); } /// Append a suffix to the function name according to the type of 'Op'. Index: llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp =================================================================== --- llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp +++ llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -2825,12 +2825,23 @@ // Fortified Library Call Optimizations //===----------------------------------------------------------------------===// -bool FortifiedLibCallSimplifier::isFortifiedCallFoldable(CallInst *CI, - unsigned ObjSizeOp, - unsigned SizeOp, - bool isString) { - if (CI->getArgOperand(ObjSizeOp) == CI->getArgOperand(SizeOp)) +bool +FortifiedLibCallSimplifier::isFortifiedCallFoldable(CallInst *CI, + unsigned ObjSizeOp, + Optional SizeOp, + Optional StrOp, + Optional FlagOp) { + // If this function takes a flag argument, the implementation may use it to + // perform extra checks. Don't fold into the non-checking variant. + if (FlagOp) { + ConstantInt *Flag = dyn_cast(CI->getArgOperand(*FlagOp)); + if (!Flag || !Flag->isZero()) + return false; + } + + if (SizeOp && CI->getArgOperand(ObjSizeOp) == CI->getArgOperand(*SizeOp)) return true; + if (ConstantInt *ObjSizeCI = dyn_cast(CI->getArgOperand(ObjSizeOp))) { if (ObjSizeCI->isMinusOne()) @@ -2838,23 +2849,27 @@ // If the object size wasn't -1 (unknown), bail out if we were asked to. if (OnlyLowerUnknownSize) return false; - if (isString) { - uint64_t Len = GetStringLength(CI->getArgOperand(SizeOp)); + if (StrOp) { + uint64_t Len = GetStringLength(CI->getArgOperand(*StrOp)); // If the length is 0 we don't know how long it is and so we can't // remove the check. if (Len == 0) return false; return ObjSizeCI->getZExtValue() >= Len; } - if (ConstantInt *SizeCI = dyn_cast(CI->getArgOperand(SizeOp))) - return ObjSizeCI->getZExtValue() >= SizeCI->getZExtValue(); + + if (SizeOp) { + if (ConstantInt *SizeCI = + dyn_cast(CI->getArgOperand(*SizeOp))) + return ObjSizeCI->getZExtValue() >= SizeCI->getZExtValue(); + } } return false; } Value *FortifiedLibCallSimplifier::optimizeMemCpyChk(CallInst *CI, IRBuilder<> &B) { - if (isFortifiedCallFoldable(CI, 3, 2, false)) { + if (isFortifiedCallFoldable(CI, 3, 2)) { B.CreateMemCpy(CI->getArgOperand(0), 1, CI->getArgOperand(1), 1, CI->getArgOperand(2)); return CI->getArgOperand(0); @@ -2864,7 +2879,7 @@ Value *FortifiedLibCallSimplifier::optimizeMemMoveChk(CallInst *CI, IRBuilder<> &B) { - if (isFortifiedCallFoldable(CI, 3, 2, false)) { + if (isFortifiedCallFoldable(CI, 3, 2)) { B.CreateMemMove(CI->getArgOperand(0), 1, CI->getArgOperand(1), 1, CI->getArgOperand(2)); return CI->getArgOperand(0); @@ -2876,7 +2891,7 @@ IRBuilder<> &B) { // TODO: Try foldMallocMemset() here. - if (isFortifiedCallFoldable(CI, 3, 2, false)) { + if (isFortifiedCallFoldable(CI, 3, 2)) { Value *Val = B.CreateIntCast(CI->getArgOperand(1), B.getInt8Ty(), false); B.CreateMemSet(CI->getArgOperand(0), Val, CI->getArgOperand(2), 1); return CI->getArgOperand(0); @@ -2887,8 +2902,6 @@ Value *FortifiedLibCallSimplifier::optimizeStrpCpyChk(CallInst *CI, IRBuilder<> &B, LibFunc Func) { - Function *Callee = CI->getCalledFunction(); - StringRef Name = Callee->getName(); const DataLayout &DL = CI->getModule()->getDataLayout(); Value *Dst = CI->getArgOperand(0), *Src = CI->getArgOperand(1), *ObjSize = CI->getArgOperand(2); @@ -2904,8 +2917,12 @@ // st[rp]cpy_chk call which may fail at runtime if the size is too long. // TODO: It might be nice to get a maximum length out of the possible // string lengths for varying. - if (isFortifiedCallFoldable(CI, 2, 1, true)) - return emitStrCpy(Dst, Src, B, TLI, Name.substr(2, 6)); + if (isFortifiedCallFoldable(CI, 2, None, 1)) { + if (Func == LibFunc_strcpy_chk) + return emitStrCpy(Dst, Src, B, TLI); + else + return emitStpCpy(Dst, Src, B, TLI); + } if (OnlyLowerUnknownSize) return nullptr; @@ -2928,16 +2945,101 @@ Value *FortifiedLibCallSimplifier::optimizeStrpNCpyChk(CallInst *CI, IRBuilder<> &B, LibFunc Func) { - Function *Callee = CI->getCalledFunction(); - StringRef Name = Callee->getName(); - if (isFortifiedCallFoldable(CI, 3, 2, false)) { - Value *Ret = emitStrNCpy(CI->getArgOperand(0), CI->getArgOperand(1), - CI->getArgOperand(2), B, TLI, Name.substr(2, 7)); - return Ret; + if (isFortifiedCallFoldable(CI, 3, 2)) { + if (Func == LibFunc_strncpy_chk) + return emitStrNCpy(CI->getArgOperand(0), CI->getArgOperand(1), + CI->getArgOperand(2), B, TLI); + else + return emitStpNCpy(CI->getArgOperand(0), CI->getArgOperand(1), + CI->getArgOperand(2), B, TLI); } return nullptr; } +Value *FortifiedLibCallSimplifier::optimizeMemCCpyChk(CallInst *CI, + IRBuilder<> &B) { + if (isFortifiedCallFoldable(CI, 4, 3)) + return emitMemCCpy(CI->getArgOperand(0), CI->getArgOperand(1), + CI->getArgOperand(2), CI->getArgOperand(3), B, TLI); + + return nullptr; +} + +Value *FortifiedLibCallSimplifier::optimizeSNPrintfChk(CallInst *CI, + IRBuilder<> &B) { + if (isFortifiedCallFoldable(CI, 3, 1, None, 2)) { + SmallVector VariadicArgs(CI->arg_begin() + 5, CI->arg_end()); + return emitSNPrintf(CI->getArgOperand(0), CI->getArgOperand(1), + CI->getArgOperand(4), VariadicArgs, B, TLI); + } + + return nullptr; +} + +Value *FortifiedLibCallSimplifier::optimizeSPrintfChk(CallInst *CI, + IRBuilder<> &B) { + if (isFortifiedCallFoldable(CI, 2, None, None, 1)) { + SmallVector VariadicArgs(CI->arg_begin() + 4, CI->arg_end()); + return emitSPrintf(CI->getArgOperand(0), CI->getArgOperand(3), VariadicArgs, + B, TLI); + } + + return nullptr; +} + +Value *FortifiedLibCallSimplifier::optimizeStrCatChk(CallInst *CI, + IRBuilder<> &B) { + if (isFortifiedCallFoldable(CI, 2)) + return emitStrCat(CI->getArgOperand(0), CI->getArgOperand(1), B, TLI); + + return nullptr; +} + +Value *FortifiedLibCallSimplifier::optimizeStrLCat(CallInst *CI, + IRBuilder<> &B) { + if (isFortifiedCallFoldable(CI, 3)) + return emitStrLCat(CI->getArgOperand(0), CI->getArgOperand(1), + CI->getArgOperand(2), B, TLI); + + return nullptr; +} + +Value *FortifiedLibCallSimplifier::optimizeStrNCatChk(CallInst *CI, + IRBuilder<> &B) { + if (isFortifiedCallFoldable(CI, 3)) + return emitStrNCat(CI->getArgOperand(0), CI->getArgOperand(1), + CI->getArgOperand(2), B, TLI); + + return nullptr; +} + +Value *FortifiedLibCallSimplifier::optimizeStrLCpyChk(CallInst *CI, + IRBuilder<> &B) { + if (isFortifiedCallFoldable(CI, 3)) + return emitStrLCpy(CI->getArgOperand(0), CI->getArgOperand(1), + CI->getArgOperand(2), B, TLI); + + return nullptr; +} + +Value *FortifiedLibCallSimplifier::optimizeVSNPrintfChk(CallInst *CI, + IRBuilder<> &B) { + if (isFortifiedCallFoldable(CI, 3, 1, None, 2)) + return emitVSNPrintf(CI->getArgOperand(0), CI->getArgOperand(1), + CI->getArgOperand(4), CI->getArgOperand(5), B, TLI); + + return nullptr; +} + +Value *FortifiedLibCallSimplifier::optimizeVSPrintfChk(CallInst *CI, + IRBuilder<> &B) { + if (isFortifiedCallFoldable(CI, 2, None, None, 1)) + return emitVSPrintf(CI->getArgOperand(0), CI->getArgOperand(3), + CI->getArgOperand(4), B, TLI); + + return nullptr; +} + Value *FortifiedLibCallSimplifier::optimizeCall(CallInst *CI) { // FIXME: We shouldn't be changing "nobuiltin" or TLI unavailable calls here. // Some clang users checked for _chk libcall availability using: @@ -2982,6 +3084,24 @@ case LibFunc_stpncpy_chk: case LibFunc_strncpy_chk: return optimizeStrpNCpyChk(CI, Builder, Func); + case LibFunc_memccpy_chk: + return optimizeMemCCpyChk(CI, Builder); + case LibFunc_snprintf_chk: + return optimizeSNPrintfChk(CI, Builder); + case LibFunc_sprintf_chk: + return optimizeSPrintfChk(CI, Builder); + case LibFunc_strcat_chk: + return optimizeStrCatChk(CI, Builder); + case LibFunc_strlcat_chk: + return optimizeStrLCat(CI, Builder); + case LibFunc_strncat_chk: + return optimizeStrNCatChk(CI, Builder); + case LibFunc_strlcpy_chk: + return optimizeStrLCpyChk(CI, Builder); + case LibFunc_vsnprintf_chk: + return optimizeVSNPrintfChk(CI, Builder); + case LibFunc_vsprintf_chk: + return optimizeVSPrintfChk(CI, Builder); default: break; } Index: llvm/test/Transforms/InstCombine/fortify-folding.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/InstCombine/fortify-folding.ll @@ -0,0 +1,207 @@ +; RUN: opt < %s -instcombine -S | FileCheck %s --dump-input-on-failure + +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" + +@a = common global [60 x i8] zeroinitializer, align 1 +@b = common global [60 x i8] zeroinitializer, align 1 +@.str = private constant [12 x i8] c"abcdefghijk\00" + +%struct.__va_list_tag = type { i32, i32, i8*, i8* } + +define i8* @test_memccpy() { + ; CHECK-LABEL: define i8* @test_memccpy + ; CHECK-NEXT: call i8* @memccpy(i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i64 0, i64 0), i8* getelementptr inbounds ([60 x i8], [60 x i8]* @b, i64 0, i64 0), i32 0, i64 60) + ; CHECK-NEXT: ret i8* + %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0 + %src = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0 + %ret = call i8* @__memccpy_chk(i8* %dst, i8* %src, i32 0, i64 60, i64 -1) + ret i8* %ret +} + +define i8* @test_not_memccpy() { + ; CHECK-LABEL: define i8* @test_not_memccpy + ; CHECK-NEXT: call i8* @__memccpy_chk + ; CHECK-NEXT: ret i8* + %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0 + %src = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0 + %ret = call i8* @__memccpy_chk(i8* %dst, i8* %src, i32 0, i64 60, i64 59) + ret i8* %ret +} + +define i32 @test_snprintf() { + ; CHECK-LABEL: define i32 @test_snprintf + ; CHECK-NEXT: call i32 (i8*, i64, i8*, ...) @snprintf(i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i64 0, i64 0), i64 60, i8* getelementptr inbounds ([60 x i8], [60 x i8]* @b, i64 0, i64 0)) + ; CHECK-NEXT: ret i32 + %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0 + %fmt = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0 + %ret = call i32 (i8*, i64, i32, i64, i8*, ...) @__snprintf_chk(i8* %dst, i64 60, i32 0, i64 -1, i8* %fmt) + ret i32 %ret +} + +define i32 @test_not_snprintf() { + ; CHECK-LABEL: define i32 @test_not_snprintf + ; CHECK-NEXT: call i32 (i8*, i64, i32, i64, i8*, ...) @__snprintf_chk + ; CHECK-NEXT: call i32 (i8*, i64, i32, i64, i8*, ...) @__snprintf_chk + ; CHECK-NEXT: ret i32 + %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0 + %fmt = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0 + %ret = call i32 (i8*, i64, i32, i64, i8*, ...) @__snprintf_chk(i8* %dst, i64 60, i32 0, i64 59, i8* %fmt) + %ign = call i32 (i8*, i64, i32, i64, i8*, ...) @__snprintf_chk(i8* %dst, i64 60, i32 1, i64 -1, i8* %fmt) + ret i32 %ret +} + +define i32 @test_sprintf() { + ; CHECK-LABEL: define i32 @test_sprintf + ; CHECK-NEXT: call i32 (i8*, i8*, ...) @sprintf(i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i64 0, i64 0), i8* getelementptr inbounds ([60 x i8], [60 x i8]* @b, i64 0, i64 0)) + ; CHECK-NEXT: ret i32 + %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0 + %fmt = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0 + %ret = call i32 (i8*, i32, i64, i8*, ...) @__sprintf_chk(i8* %dst, i32 0, i64 -1, i8* %fmt) + ret i32 %ret +} + +define i32 @test_not_sprintf() { + ; CHECK-LABEL: define i32 @test_not_sprintf + ; CHECK-NEXT: call i32 (i8*, i32, i64, i8*, ...) @__sprintf_chk + ; CHECK-NEXT: call i32 (i8*, i32, i64, i8*, ...) @__sprintf_chk + ; CHECK-NEXT: ret i32 + %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0 + %fmt = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0 + %ret = call i32 (i8*, i32, i64, i8*, ...) @__sprintf_chk(i8* %dst, i32 0, i64 59, i8* %fmt) + %ignored = call i32 (i8*, i32, i64, i8*, ...) @__sprintf_chk(i8* %dst, i32 1, i64 -1, i8* %fmt) + ret i32 %ret +} + +define i8* @test_strcat() { + ; CHECK-LABEL: define i8* @test_strcat + ; CHECK-NEXT: call i8* @strcat(i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i64 0, i64 0), i8* getelementptr inbounds ([60 x i8], [60 x i8]* @b, i64 0, i64 0)) + ; CHECK-NEXT: ret i8* + %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0 + %src = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0 + %ret = call i8* @__strcat_chk(i8* %dst, i8* %src, i64 -1) + ret i8* %ret +} + +define i8* @test_not_strcat() { + ; CHECK-LABEL: define i8* @test_not_strcat + ; CHECK-NEXT: call i8* @__strcat_chk + ; CHECK-NEXT: ret i8* + %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0 + %src = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0 + %ret = call i8* @__strcat_chk(i8* %dst, i8* %src, i64 0) + ret i8* %ret +} + +define i64 @test_strlcat() { + ; CHECK-LABEL: define i64 @test_strlcat + ; CHECK-NEXT: call i64 @strlcat(i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i64 0, i64 0), i8* getelementptr inbounds ([60 x i8], [60 x i8]* @b, i64 0, i64 0), i64 22) + ; CHECK-NEXT: ret i64 + %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0 + %src = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0 + %ret = call i64 @__strlcat_chk(i8* %dst, i8* %src, i64 22, i64 -1) + ret i64 %ret +} + +define i64 @test_not_strlcat() { + ; CHECK-LABEL: define i64 @test_not_strlcat + ; CHECK-NEXT: call i64 @__strlcat_chk + ; CHECK-NEXT: ret i64 + %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0 + %src = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0 + %ret = call i64 @__strlcat_chk(i8* %dst, i8* %src, i64 22, i64 0) + ret i64 %ret +} + +define i8* @test_strncat() { + ; CHECK-LABEL: define i8* @test_strncat + ; CHECK-NEXT: call i8* @strncat(i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i64 0, i64 0), i8* getelementptr inbounds ([60 x i8], [60 x i8]* @b, i64 0, i64 0), i64 22) + ; CHECK-NEXT: ret i8* + %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0 + %src = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0 + %ret = call i8* @__strncat_chk(i8* %dst, i8* %src, i64 22, i64 -1) + ret i8* %ret +} + +define i8* @test_not_strncat() { + ; CHECK-LABEL: define i8* @test_not_strncat + ; CHECK-NEXT: call i8* @__strncat_chk(i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i64 0, i64 0), i8* getelementptr inbounds ([60 x i8], [60 x i8]* @b, i64 0, i64 0), i64 22, i64 3) + ; CHECK-NEXT: ret i8* + %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0 + %src = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0 + %ret = call i8* @__strncat_chk(i8* %dst, i8* %src, i64 22, i64 3) + ret i8* %ret +} + +define i64 @test_strlcpy() { + ; CHECK-LABEL: define i64 @test_strlcpy + ; CHECK-NEXT: call i64 @strlcpy(i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i64 0, i64 0), i8* getelementptr inbounds ([60 x i8], [60 x i8]* @b, i64 0, i64 0), i64 22) + ; CHECK-NEXT: ret i64 + %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0 + %src = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0 + %ret = call i64 @__strlcpy_chk(i8* %dst, i8* %src, i64 22, i64 -1) + ret i64 %ret +} + +define i64 @test_not_strlcpy() { + ; CHECK-LABEL: define i64 @test_not_strlcpy + ; CHECK-NEXT: call i64 @__strlcpy_chk(i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i64 0, i64 0), i8* getelementptr inbounds ([60 x i8], [60 x i8]* @b, i64 0, i64 0), i64 22, i64 2) + ; CHECK-NEXT: ret i64 + %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0 + %src = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0 + %ret = call i64 @__strlcpy_chk(i8* %dst, i8* %src, i64 22, i64 2) + ret i64 %ret +} + +define i32 @test_vsnprintf() { + ; CHECK-LABEL: define i32 @test_vsnprintf + ; CHECK-NEXT: call i32 @vsnprintf(i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i64 0, i64 0), i64 4, i8* getelementptr inbounds ([60 x i8], [60 x i8]* @b, i64 0, i64 0), %struct.__va_list_tag* null) + ; ret i32 + %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0 + %src = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0 + %ret = call i32 @__vsnprintf_chk(i8* %dst, i64 4, i32 0, i64 -1, i8* %src, %struct.__va_list_tag* null) + ret i32 %ret +} + +define i32 @test_not_vsnprintf() { + ; CHECK-LABEL: define i32 @test_not_vsnprintf + ; CHECK-NEXT: call i32 @__vsnprintf_chk(i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i64 0, i64 0), i64 4, i32 0, i64 3, i8* getelementptr inbounds ([60 x i8], [60 x i8]* @b, i64 0, i64 0), %struct.__va_list_tag* null) + ; CHECK-NEXT: call i32 @__vsnprintf_chk(i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i64 0, i64 0), i64 4, i32 1, i64 -1, i8* getelementptr inbounds ([60 x i8], [60 x i8]* @b, i64 0, i64 0), %struct.__va_list_tag* null) + ; ret i32 + %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0 + %src = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0 + %ret = call i32 @__vsnprintf_chk(i8* %dst, i64 4, i32 0, i64 3, i8* %src, %struct.__va_list_tag* null) + %ign = call i32 @__vsnprintf_chk(i8* %dst, i64 4, i32 1, i64 -1, i8* %src, %struct.__va_list_tag* null) + ret i32 %ret +} + +define i32 @test_vsprintf() { + ; CHECK-LABEL: define i32 @test_vsprintf + ; CHECK-NEXT: call i32 @vsprintf(i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i64 0, i64 0), i8* getelementptr inbounds ([60 x i8], [60 x i8]* @b, i64 0, i64 0), %struct.__va_list_tag* null) + ; ret i32 + %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0 + %src = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0 + %ret = call i32 @__vsprintf_chk(i8* %dst, i32 0, i64 -1, i8* %src, %struct.__va_list_tag* null) + ret i32 %ret +} + +define i32 @test_not_vsprintf() { + ; CHECK-LABEL: define i32 @test_not_vsprintf + ; CHECK-NEXT: call i32 @__vsprintf_chk(i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i64 0, i64 0), i32 0, i64 3, i8* getelementptr inbounds ([60 x i8], [60 x i8]* @b, i64 0, i64 0), %struct.__va_list_tag* null) + ; CHECK-NEXT: call i32 @__vsprintf_chk(i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i64 0, i64 0), i32 1, i64 -1, i8* getelementptr inbounds ([60 x i8], [60 x i8]* @b, i64 0, i64 0), %struct.__va_list_tag* null) + ; ret i32 + %dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0 + %src = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0 + %ret = call i32 @__vsprintf_chk(i8* %dst, i32 0, i64 3, i8* %src, %struct.__va_list_tag* null) + %ign = call i32 @__vsprintf_chk(i8* %dst, i32 1, i64 -1, i8* %src, %struct.__va_list_tag* null) + ret i32 %ret +} + +declare i8* @__memccpy_chk(i8*, i8*, i32, i64, i64) +declare i32 @__snprintf_chk(i8*, i64, i32, i64, i8*, ...) +declare i32 @__sprintf_chk(i8*, i32, i64, i8*, ...) +declare i8* @__strcat_chk(i8*, i8*, i64) +declare i64 @__strlcat_chk(i8*, i8*, i64, i64) +declare i8* @__strncat_chk(i8*, i8*, i64, i64) +declare i64 @__strlcpy_chk(i8*, i8*, i64, i64) +declare i32 @__vsnprintf_chk(i8*, i64, i32, i64, i8*, %struct.__va_list_tag*) +declare i32 @__vsprintf_chk(i8*, i32, i64, i8*, %struct.__va_list_tag*) Index: llvm/unittests/Analysis/TargetLibraryInfoTest.cpp =================================================================== --- llvm/unittests/Analysis/TargetLibraryInfoTest.cpp +++ llvm/unittests/Analysis/TargetLibraryInfoTest.cpp @@ -313,6 +313,8 @@ "declare i8* @strtok(i8*, i8*)\n" "declare i8* @strtok_r(i8*, i8*, i8**)\n" "declare i64 @strtol(i8*, i8**, i32)\n" + "declare i64 @strlcat(i8*, i8**, i64)\n" + "declare i64 @strlcpy(i8*, i8**, i64)\n" "declare x86_fp80 @strtold(i8*, i8**)\n" "declare i64 @strtoll(i8*, i8**, i32)\n" "declare i64 @strtoul(i8*, i8**, i32)\n" @@ -467,6 +469,15 @@ "declare i8* @__stpncpy_chk(i8*, i8*, i64, i64)\n" "declare i8* @__strcpy_chk(i8*, i8*, i64)\n" "declare i8* @__strncpy_chk(i8*, i8*, i64, i64)\n" + "declare i8* @__memccpy_chk(i8*, i8*, i32, i64)\n" + "declare i32 @__snprintf_chk(i8*, i64, i32, i64, i8*, ...)\n" + "declare i32 @__sprintf_chk(i8*, i32, i64, i8*, ...)\n" + "declare i8* @__strcat_chk(i8*, i8*, i64)\n" + "declare i64 @__strlcat_chk(i8*, i8*, i64, i64)\n" + "declare i8* @__strncat_chk(i8*, i8*, i64, i64)\n" + "declare i64 @__strlcpy_chk(i8*, i8*, i64, i64)\n" + "declare i32 @__vsnprintf_chk(i8*, i64, i32, i64, i8*, %struct*)\n" + "declare i32 @__vsprintf_chk(i8*, i32, i64, i8*, %struct*)\n" "declare i8* @memalign(i64, i64)\n" "declare i8* @mempcpy(i8*, i8*, i64)\n"