mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-02-12 15:51:35 +00:00
[SimplifyLibCalls] Fold more fortified functions into non-fortified variants
When the object size argument is -1, no checking can be done, so calling the _chk variant is unnecessary. We already did this for a bunch of these functions. rdar://50797197 Differential revision: https://reviews.llvm.org/D62358 llvm-svn: 362272
This commit is contained in:
parent
3ec122b081
commit
97e1411c56
@ -329,6 +329,10 @@ TLI_DEFINE_STRING_INTERNAL("__logf_finite")
|
||||
/// 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 @@ TLI_DEFINE_STRING_INTERNAL("__small_printf")
|
||||
/// 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 @@ TLI_DEFINE_STRING_INTERNAL("__stpcpy_chk")
|
||||
/// 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 @@ TLI_DEFINE_STRING_INTERNAL("__strndup")
|
||||
/// 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 @@ TLI_DEFINE_STRING_INTERNAL("strcspn")
|
||||
/// 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")
|
||||
|
@ -106,6 +106,43 @@ namespace llvm {
|
||||
Value *emitBCmp(Value *Ptr1, Value *Ptr2, Value *Len, IRBuilder<> &B,
|
||||
const DataLayout &DL, const TargetLibraryInfo *TLI);
|
||||
|
||||
/// Emit a call to the memccpy function.
|
||||
Value *emitMemCCpy(Value *Ptr1, Value *Ptr2, Value *Val, Value *Len,
|
||||
IRBuilder<> &B, const TargetLibraryInfo *TLI);
|
||||
|
||||
/// Emit a call to the snprintf function.
|
||||
Value *emitSNPrintf(Value *Dest, Value *Size, Value *Fmt,
|
||||
ArrayRef<Value *> Args, IRBuilder<> &B,
|
||||
const TargetLibraryInfo *TLI);
|
||||
|
||||
/// Emit a call to the sprintf function.
|
||||
Value *emitSPrintf(Value *Dest, Value *Fmt, ArrayRef<Value *> VariadicArgs,
|
||||
IRBuilder<> &B, const TargetLibraryInfo *TLI);
|
||||
|
||||
/// Emit a call to the strcat function.
|
||||
Value *emitStrCat(Value *Dest, Value *Src, IRBuilder<> &B,
|
||||
const TargetLibraryInfo *TLI);
|
||||
|
||||
/// Emit a call to the strlcpy function.
|
||||
Value *emitStrLCpy(Value *Dest, Value *Src, Value *Size, IRBuilder<> &B,
|
||||
const TargetLibraryInfo *TLI);
|
||||
|
||||
/// Emit a call to the strlcat function.
|
||||
Value *emitStrLCat(Value *Dest, Value *Src, Value *Size, IRBuilder<> &B,
|
||||
const TargetLibraryInfo *TLI);
|
||||
|
||||
/// Emit a call to the strncat function.
|
||||
Value *emitStrNCat(Value *Dest, Value *Src, Value *Size, IRBuilder<> &B,
|
||||
const TargetLibraryInfo *TLI);
|
||||
|
||||
/// Emit a call to the vsnprintf function.
|
||||
Value *emitVSNPrintf(Value *Dest, Value *Size, Value *Fmt, Value *VAList,
|
||||
IRBuilder<> &B, const TargetLibraryInfo *TLI);
|
||||
|
||||
/// Emit a call to the vsprintf function.
|
||||
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
|
||||
|
@ -57,14 +57,41 @@ private:
|
||||
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 CI the call to the fortified libcall.
|
||||
///
|
||||
/// \param ObjSizeOp the index of the object size parameter of this chk
|
||||
/// function. Not optional since this is mandatory.
|
||||
///
|
||||
/// \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<unsigned> SizeOp = None,
|
||||
Optional<unsigned> StrOp = None,
|
||||
Optional<unsigned> FlagsOp = None);
|
||||
};
|
||||
|
||||
/// LibCallSimplifier - This class implements a collection of optimizations
|
||||
|
@ -691,11 +691,21 @@ bool TargetLibraryInfoImpl::isValidProtoForLibFunc(const FunctionType &FTy,
|
||||
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 @@ bool TargetLibraryInfoImpl::isValidProtoForLibFunc(const FunctionType &FTy,
|
||||
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 @@ bool TargetLibraryInfoImpl::isValidProtoForLibFunc(const FunctionType &FTy,
|
||||
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 @@ bool TargetLibraryInfoImpl::isValidProtoForLibFunc(const FunctionType &FTy,
|
||||
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 @@ bool TargetLibraryInfoImpl::isValidProtoForLibFunc(const FunctionType &FTy,
|
||||
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:
|
||||
|
@ -912,6 +912,77 @@ Value *llvm::emitBCmp(Value *Ptr1, Value *Ptr2, Value *Len, IRBuilder<> &B,
|
||||
{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<Value *> VariadicArgs, IRBuilder<> &B,
|
||||
const TargetLibraryInfo *TLI) {
|
||||
SmallVector<Value *, 8> 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<Value *> VariadicArgs, IRBuilder<> &B,
|
||||
const TargetLibraryInfo *TLI) {
|
||||
SmallVector<Value *, 8> 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'.
|
||||
static void appendTypeSuffix(Value *Op, StringRef &Name,
|
||||
SmallString<20> &NameBuffer) {
|
||||
|
@ -2825,12 +2825,23 @@ void LibCallSimplifier::eraseFromParent(Instruction *I) {
|
||||
// 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<unsigned> SizeOp,
|
||||
Optional<unsigned> StrOp,
|
||||
Optional<unsigned> 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<ConstantInt>(CI->getArgOperand(*FlagOp));
|
||||
if (!Flag || !Flag->isZero())
|
||||
return false;
|
||||
}
|
||||
|
||||
if (SizeOp && CI->getArgOperand(ObjSizeOp) == CI->getArgOperand(*SizeOp))
|
||||
return true;
|
||||
|
||||
if (ConstantInt *ObjSizeCI =
|
||||
dyn_cast<ConstantInt>(CI->getArgOperand(ObjSizeOp))) {
|
||||
if (ObjSizeCI->isMinusOne())
|
||||
@ -2838,23 +2849,27 @@ bool FortifiedLibCallSimplifier::isFortifiedCallFoldable(CallInst *CI,
|
||||
// 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<ConstantInt>(CI->getArgOperand(SizeOp)))
|
||||
return ObjSizeCI->getZExtValue() >= SizeCI->getZExtValue();
|
||||
|
||||
if (SizeOp) {
|
||||
if (ConstantInt *SizeCI =
|
||||
dyn_cast<ConstantInt>(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::optimizeMemCpyChk(CallInst *CI,
|
||||
|
||||
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 @@ Value *FortifiedLibCallSimplifier::optimizeMemSetChk(CallInst *CI,
|
||||
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);
|
||||
@ -2902,7 +2917,7 @@ Value *FortifiedLibCallSimplifier::optimizeStrpCpyChk(CallInst *CI,
|
||||
// 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)) {
|
||||
if (isFortifiedCallFoldable(CI, 2, None, 1)) {
|
||||
if (Func == LibFunc_strcpy_chk)
|
||||
return emitStrCpy(Dst, Src, B, TLI);
|
||||
else
|
||||
@ -2930,10 +2945,10 @@ Value *FortifiedLibCallSimplifier::optimizeStrpCpyChk(CallInst *CI,
|
||||
Value *FortifiedLibCallSimplifier::optimizeStrpNCpyChk(CallInst *CI,
|
||||
IRBuilder<> &B,
|
||||
LibFunc Func) {
|
||||
if (isFortifiedCallFoldable(CI, 3, 2, false)) {
|
||||
if (isFortifiedCallFoldable(CI, 3, 2)) {
|
||||
if (Func == LibFunc_strncpy_chk)
|
||||
return emitStrNCpy(CI->getArgOperand(0), CI->getArgOperand(1),
|
||||
CI->getArgOperand(2), B, TLI);
|
||||
CI->getArgOperand(2), B, TLI);
|
||||
else
|
||||
return emitStpNCpy(CI->getArgOperand(0), CI->getArgOperand(1),
|
||||
CI->getArgOperand(2), B, TLI);
|
||||
@ -2942,6 +2957,90 @@ Value *FortifiedLibCallSimplifier::optimizeStrpNCpyChk(CallInst *CI,
|
||||
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<Value *, 8> 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<Value *, 8> 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:
|
||||
@ -2986,6 +3085,24 @@ Value *FortifiedLibCallSimplifier::optimizeCall(CallInst *CI) {
|
||||
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;
|
||||
}
|
||||
|
207
test/Transforms/InstCombine/fortify-folding.ll
Normal file
207
test/Transforms/InstCombine/fortify-folding.ll
Normal file
@ -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*)
|
@ -313,6 +313,8 @@ TEST_F(TargetLibraryInfoTest, ValidProto) {
|
||||
"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 @@ TEST_F(TargetLibraryInfoTest, ValidProto) {
|
||||
"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"
|
||||
|
Loading…
x
Reference in New Issue
Block a user