Index: include/llvm/Analysis/TargetLibraryInfo.def =================================================================== --- include/llvm/Analysis/TargetLibraryInfo.def +++ include/llvm/Analysis/TargetLibraryInfo.def @@ -601,12 +601,18 @@ /// int fgetc(FILE *stream); TLI_DEFINE_ENUM_INTERNAL(fgetc) TLI_DEFINE_STRING_INTERNAL("fgetc") +/// int fgetc_unlocked(FILE *stream); +TLI_DEFINE_ENUM_INTERNAL(fgetc_unlocked) +TLI_DEFINE_STRING_INTERNAL("fgetc_unlocked") /// int fgetpos(FILE *stream, fpos_t *pos); TLI_DEFINE_ENUM_INTERNAL(fgetpos) TLI_DEFINE_STRING_INTERNAL("fgetpos") /// char *fgets(char *s, int n, FILE *stream); TLI_DEFINE_ENUM_INTERNAL(fgets) TLI_DEFINE_STRING_INTERNAL("fgets") +/// char *fgets_unlocked(char *s, int n, FILE *stream); +TLI_DEFINE_ENUM_INTERNAL(fgets_unlocked) +TLI_DEFINE_STRING_INTERNAL("fgets_unlocked") /// int fileno(FILE *stream); TLI_DEFINE_ENUM_INTERNAL(fileno) TLI_DEFINE_STRING_INTERNAL("fileno") @@ -673,12 +679,21 @@ /// int fputc(int c, FILE *stream); TLI_DEFINE_ENUM_INTERNAL(fputc) TLI_DEFINE_STRING_INTERNAL("fputc") +/// int fputc_unlocked(int c, FILE *stream); +TLI_DEFINE_ENUM_INTERNAL(fputc_unlocked) +TLI_DEFINE_STRING_INTERNAL("fputc_unlocked") /// int fputs(const char *s, FILE *stream); TLI_DEFINE_ENUM_INTERNAL(fputs) TLI_DEFINE_STRING_INTERNAL("fputs") +/// int fputs_unlocked(const char *s, FILE *stream); +TLI_DEFINE_ENUM_INTERNAL(fputs_unlocked) +TLI_DEFINE_STRING_INTERNAL("fputs_unlocked") /// size_t fread(void *ptr, size_t size, size_t nitems, FILE *stream); TLI_DEFINE_ENUM_INTERNAL(fread) TLI_DEFINE_STRING_INTERNAL("fread") +/// size_t fread_unlocked(void *ptr, size_t size, size_t nitems, FILE *stream); +TLI_DEFINE_ENUM_INTERNAL(fread_unlocked) +TLI_DEFINE_STRING_INTERNAL("fread_unlocked") /// void free(void *ptr); TLI_DEFINE_ENUM_INTERNAL(free) TLI_DEFINE_STRING_INTERNAL("free") @@ -736,6 +751,9 @@ /// size_t fwrite(const void *ptr, size_t size, size_t nitems, FILE *stream); TLI_DEFINE_ENUM_INTERNAL(fwrite) TLI_DEFINE_STRING_INTERNAL("fwrite") +/// size_t fwrite_unlocked(const void *ptr, size_t size, size_t nitems, FILE *stream); +TLI_DEFINE_ENUM_INTERNAL(fwrite_unlocked) +TLI_DEFINE_STRING_INTERNAL("fwrite_unlocked") /// int getc(FILE *stream); TLI_DEFINE_ENUM_INTERNAL(getc) TLI_DEFINE_STRING_INTERNAL("getc") @@ -745,6 +763,9 @@ /// int getchar(void); TLI_DEFINE_ENUM_INTERNAL(getchar) TLI_DEFINE_STRING_INTERNAL("getchar") +/// int getchar_unlocked(void); +TLI_DEFINE_ENUM_INTERNAL(getchar_unlocked) +TLI_DEFINE_STRING_INTERNAL("getchar_unlocked") /// char *getenv(const char *name); TLI_DEFINE_ENUM_INTERNAL(getenv) TLI_DEFINE_STRING_INTERNAL("getenv") @@ -950,9 +971,15 @@ /// int putc(int c, FILE *stream); TLI_DEFINE_ENUM_INTERNAL(putc) TLI_DEFINE_STRING_INTERNAL("putc") +/// int putc_unlocked(int c, FILE *stream); +TLI_DEFINE_ENUM_INTERNAL(putc_unlocked) +TLI_DEFINE_STRING_INTERNAL("putc_unlocked") /// int putchar(int c); TLI_DEFINE_ENUM_INTERNAL(putchar) TLI_DEFINE_STRING_INTERNAL("putchar") +/// int putchar_unlocked(int c); +TLI_DEFINE_ENUM_INTERNAL(putchar_unlocked) +TLI_DEFINE_STRING_INTERNAL("putchar_unlocked") /// int puts(const char *s); TLI_DEFINE_ENUM_INTERNAL(puts) TLI_DEFINE_STRING_INTERNAL("puts") Index: include/llvm/Transforms/Utils/BuildLibCalls.h =================================================================== --- include/llvm/Transforms/Utils/BuildLibCalls.h +++ include/llvm/Transforms/Utils/BuildLibCalls.h @@ -96,6 +96,11 @@ /// Emit a call to the putchar function. This assumes that Char is an integer. Value *emitPutChar(Value *Char, IRBuilder<> &B, const TargetLibraryInfo *TLI); + /// Emit a call to the putchar_unlocked function. + /// This assumes that Char is an integer. + Value *emitPutCharUnlocked(Value *Char, IRBuilder<> &B, + const TargetLibraryInfo *TLI); + /// Emit a call to the puts function. This assumes that Str is some pointer. Value *emitPutS(Value *Str, IRBuilder<> &B, const TargetLibraryInfo *TLI); @@ -104,15 +109,48 @@ Value *emitFPutC(Value *Char, Value *File, IRBuilder<> &B, const TargetLibraryInfo *TLI); - /// Emit a call to the puts function. Str is required to be a pointer and + /// Emit a call to the fputc_unlocked function. This assumes that Char is an i32, and + /// File is a pointer to FILE. + Value *emitFPutCUnlocked(Value *Char, Value *File, IRBuilder<> &B, + const TargetLibraryInfo *TLI); + + /// Emit a call to the fputs function. Str is required to be a pointer and /// File is a pointer to FILE. Value *emitFPutS(Value *Str, Value *File, IRBuilder<> &B, const TargetLibraryInfo *TLI); + /// Emit a call to the fputs_unlocked function. Str is required to be a + /// pointer and File is a pointer to FILE. + Value *emitFPutSUnlocked(Value *Str, Value *File, IRBuilder<> &B, + const TargetLibraryInfo *TLI); + /// Emit a call to the fwrite function. This assumes that Ptr is a pointer, /// Size is an 'intptr_t', and File is a pointer to FILE. Value *emitFWrite(Value *Ptr, Value *Size, Value *File, IRBuilder<> &B, const DataLayout &DL, const TargetLibraryInfo *TLI); + + /// Emit a call to the fwrite_unlocked function. This assumes that Ptr is a + /// pointer, Size is an 'intptr_t', and File is a pointer to FILE. + Value *emitFWriteUnlocked(Value *Ptr, Value *Size, Value *File, + IRBuilder<> &B, const DataLayout &DL, + const TargetLibraryInfo *TLI); + + /// Emit a call to the fgetc_unlocked function. File is a pointer to FILE. + Value *emitFGetCUnlocked(Value *File, IRBuilder<> &B, + const TargetLibraryInfo *TLI); + + /// Emit a call to the getchar_unlocked function. + Value *emitGetCharUnlocked(IRBuilder<> &B, const TargetLibraryInfo *TLI); + + /// Emit a call to the fgets_unlocked function. Str is required to be a + /// pointer, Size is an 'int' and File is a pointer to FILE. + Value *emitFGetSUnlocked(Value *Str, Value *Size, Value *File, + IRBuilder<> &B, const TargetLibraryInfo *TLI); + + /// Emit a call to the fread_unlocked function. This assumes that Ptr is a + /// pointer, Size is an 'intptr_t', and File is a pointer to FILE. + Value *emitFReadUnlocked(Value *Ptr, Value *Size, Value *File, IRBuilder<> &B, + const DataLayout &DL, const TargetLibraryInfo *TLI); } #endif Index: include/llvm/Transforms/Utils/SimplifyLibCalls.h =================================================================== --- include/llvm/Transforms/Utils/SimplifyLibCalls.h +++ include/llvm/Transforms/Utils/SimplifyLibCalls.h @@ -158,7 +158,13 @@ Value *optimizeSPrintF(CallInst *CI, IRBuilder<> &B); Value *optimizeFPrintF(CallInst *CI, IRBuilder<> &B); Value *optimizeFWrite(CallInst *CI, IRBuilder<> &B); + Value *optimizeFRead(CallInst *CI, IRBuilder<> &B); Value *optimizeFPuts(CallInst *CI, IRBuilder<> &B); + Value *optimizeFGets(CallInst *CI, IRBuilder<> &B); + Value *optimizeFPutc(CallInst *CI, IRBuilder<> &B); + Value *optimizeFGetc(CallInst *CI, IRBuilder<> &B); + Value *optimizePutChar(CallInst *CI, IRBuilder<> &B); + Value *optimizeGetChar(CallInst *CI, IRBuilder<> &B); Value *optimizePuts(CallInst *CI, IRBuilder<> &B); // Helper methods Index: lib/Analysis/TargetLibraryInfo.cpp =================================================================== --- lib/Analysis/TargetLibraryInfo.cpp +++ lib/Analysis/TargetLibraryInfo.cpp @@ -310,6 +310,15 @@ TLI.setUnavailable(LibFunc_ftrylockfile); TLI.setUnavailable(LibFunc_funlockfile); TLI.setUnavailable(LibFunc_getc_unlocked); + TLI.setUnavailable(LibFunc_getchar_unlocked); + TLI.setUnavailable(LibFunc_putc_unlocked); + TLI.setUnavailable(LibFunc_putchar_unlocked); + TLI.setUnavailable(LibFunc_fputc_unlocked); + TLI.setUnavailable(LibFunc_fgetc_unlocked); + TLI.setUnavailable(LibFunc_fread_unlocked); + TLI.setUnavailable(LibFunc_fwrite_unlocked); + TLI.setUnavailable(LibFunc_fputs_unlocked); + TLI.setUnavailable(LibFunc_fgets_unlocked); TLI.setUnavailable(LibFunc_getitimer); TLI.setUnavailable(LibFunc_getlogin_r); TLI.setUnavailable(LibFunc_getpwnam); @@ -802,6 +811,7 @@ case LibFunc_feof: case LibFunc_fflush: case LibFunc_fgetc: + case LibFunc_fgetc_unlocked: case LibFunc_fileno: case LibFunc_flockfile: case LibFunc_free: @@ -830,6 +840,7 @@ 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: @@ -837,18 +848,22 @@ 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: @@ -861,6 +876,7 @@ 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) == PCharTy); @@ -873,6 +889,7 @@ 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: @@ -1231,6 +1248,7 @@ 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)); Index: lib/Transforms/Utils/BuildLibCalls.cpp =================================================================== --- lib/Transforms/Utils/BuildLibCalls.cpp +++ lib/Transforms/Utils/BuildLibCalls.cpp @@ -375,6 +375,7 @@ case LibFunc_fseek: case LibFunc_ftell: case LibFunc_fgetc: + case LibFunc_fgetc_unlocked: case LibFunc_fseeko: case LibFunc_ftello: case LibFunc_fileno: @@ -393,6 +394,7 @@ Changed |= setOnlyReadsMemory(F); return Changed; case LibFunc_fputc: + case LibFunc_fputc_unlocked: case LibFunc_fstat: case LibFunc_frexp: case LibFunc_frexpf: @@ -402,21 +404,25 @@ Changed |= setDoesNotCapture(F, 1); return Changed; case LibFunc_fgets: + case LibFunc_fgets_unlocked: Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 2); return Changed; case LibFunc_fread: + case LibFunc_fread_unlocked: Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setDoesNotCapture(F, 3); return Changed; case LibFunc_fwrite: + case LibFunc_fwrite_unlocked: Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setDoesNotCapture(F, 3); // FIXME: readonly #1? return Changed; case LibFunc_fputs: + case LibFunc_fputs_unlocked: Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setDoesNotCapture(F, 1); @@ -435,8 +441,8 @@ Changed |= setDoesNotCapture(F, 1); return Changed; case LibFunc_getc: - case LibFunc_getlogin_r: case LibFunc_getc_unlocked: + case LibFunc_getlogin_r: Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); return Changed; @@ -447,6 +453,7 @@ return Changed; case LibFunc_gets: case LibFunc_getchar: + case LibFunc_getchar_unlocked: Changed |= setDoesNotThrow(F); return Changed; case LibFunc_getitimer: @@ -485,6 +492,7 @@ Changed |= setOnlyReadsMemory(F, 1); return Changed; case LibFunc_putc: + case LibFunc_putc_unlocked: Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 1); return Changed; @@ -505,6 +513,7 @@ Changed |= setOnlyReadsMemory(F, 1); return Changed; case LibFunc_putchar: + case LibFunc_putchar_unlocked: Changed |= setDoesNotThrow(F); return Changed; case LibFunc_popen: @@ -939,6 +948,26 @@ return CI; } +Value *llvm::emitPutCharUnlocked(Value *Char, IRBuilder<> &B, + const TargetLibraryInfo *TLI) { + if (!TLI->has(LibFunc_putchar_unlocked)) + return nullptr; + + Module *M = B.GetInsertBlock()->getModule(); + Value *PutCharUnlocked = M->getOrInsertFunction( + "putchar_unlocked", B.getInt32Ty(), B.getInt32Ty()); + inferLibFuncAttributes(*M->getFunction("putchar_unlocked"), *TLI); + CallInst *CI = B.CreateCall(PutCharUnlocked, + B.CreateIntCast(Char, B.getInt32Ty(), + /*isSigned*/ true, "chari"), + "putchar_unlocked"); + + if (const Function *F = + dyn_cast(PutCharUnlocked->stripPointerCasts())) + CI->setCallingConv(F->getCallingConv()); + return CI; +} + Value *llvm::emitPutS(Value *Str, IRBuilder<> &B, const TargetLibraryInfo *TLI) { if (!TLI->has(LibFunc_puts)) @@ -973,6 +1002,24 @@ return CI; } +Value *llvm::emitFPutCUnlocked(Value *Char, Value *File, IRBuilder<> &B, + const TargetLibraryInfo *TLI) { + if (!TLI->has(LibFunc_fputc_unlocked)) + return nullptr; + + Module *M = B.GetInsertBlock()->getModule(); + Constant *F = M->getOrInsertFunction("fputc_unlocked", B.getInt32Ty(), + B.getInt32Ty(), File->getType()); + if (File->getType()->isPointerTy()) + inferLibFuncAttributes(*M->getFunction("fputc_unlocked"), *TLI); + Char = B.CreateIntCast(Char, B.getInt32Ty(), /*isSigned*/ true, "chari"); + CallInst *CI = B.CreateCall(F, {Char, File}, "fputc_unlocked"); + + if (const Function *Fn = dyn_cast(F->stripPointerCasts())) + CI->setCallingConv(Fn->getCallingConv()); + return CI; +} + Value *llvm::emitFPutS(Value *Str, Value *File, IRBuilder<> &B, const TargetLibraryInfo *TLI) { if (!TLI->has(LibFunc_fputs)) @@ -991,6 +1038,24 @@ return CI; } +Value *llvm::emitFPutSUnlocked(Value *Str, Value *File, IRBuilder<> &B, + const TargetLibraryInfo *TLI) { + if (!TLI->has(LibFunc_fputs_unlocked)) + return nullptr; + + Module *M = B.GetInsertBlock()->getModule(); + StringRef FPutsUnlockedName = TLI->getName(LibFunc_fputs_unlocked); + Constant *F = M->getOrInsertFunction(FPutsUnlockedName, B.getInt32Ty(), + B.getInt8PtrTy(), File->getType()); + if (File->getType()->isPointerTy()) + inferLibFuncAttributes(*M->getFunction(FPutsUnlockedName), *TLI); + CallInst *CI = B.CreateCall(F, {castToCStr(Str, B), File}, "fputs_unlocked"); + + if (const Function *Fn = dyn_cast(F->stripPointerCasts())) + CI->setCallingConv(Fn->getCallingConv()); + return CI; +} + Value *llvm::emitFWrite(Value *Ptr, Value *Size, Value *File, IRBuilder<> &B, const DataLayout &DL, const TargetLibraryInfo *TLI) { if (!TLI->has(LibFunc_fwrite)) @@ -1013,3 +1078,102 @@ CI->setCallingConv(Fn->getCallingConv()); return CI; } + +Value *llvm::emitFWriteUnlocked(Value *Ptr, Value *Size, Value *File, + IRBuilder<> &B, const DataLayout &DL, + const TargetLibraryInfo *TLI) { + if (!TLI->has(LibFunc_fwrite_unlocked)) + return nullptr; + + Module *M = B.GetInsertBlock()->getModule(); + LLVMContext &Context = B.GetInsertBlock()->getContext(); + StringRef FWriteUnlockedName = TLI->getName(LibFunc_fwrite_unlocked); + Constant *F = M->getOrInsertFunction( + FWriteUnlockedName, DL.getIntPtrType(Context), B.getInt8PtrTy(), + DL.getIntPtrType(Context), DL.getIntPtrType(Context), File->getType()); + + if (File->getType()->isPointerTy()) + inferLibFuncAttributes(*M->getFunction(FWriteUnlockedName), *TLI); + CallInst *CI = + B.CreateCall(F, + {castToCStr(Ptr, B), Size, + ConstantInt::get(DL.getIntPtrType(Context), 1), File}); + + if (const Function *Fn = dyn_cast(F->stripPointerCasts())) + CI->setCallingConv(Fn->getCallingConv()); + return CI; +} + +Value *llvm::emitFGetCUnlocked(Value *File, IRBuilder<> &B, + const TargetLibraryInfo *TLI) { + if (!TLI->has(LibFunc_fgetc_unlocked)) + return nullptr; + + Module *M = B.GetInsertBlock()->getModule(); + Constant *F = + M->getOrInsertFunction("fgetc_unlocked", B.getInt32Ty(), File->getType()); + if (File->getType()->isPointerTy()) + inferLibFuncAttributes(*M->getFunction("fgetc_unlocked"), *TLI); + CallInst *CI = B.CreateCall(F, File, "fgetc_unlocked"); + + if (const Function *Fn = dyn_cast(F->stripPointerCasts())) + CI->setCallingConv(Fn->getCallingConv()); + return CI; +} + +Value *llvm::emitGetCharUnlocked(IRBuilder<> &B, const TargetLibraryInfo *TLI) { + if (!TLI->has(LibFunc_getchar_unlocked)) + return nullptr; + + Module *M = B.GetInsertBlock()->getModule(); + Constant *F = M->getOrInsertFunction("getchar_unlocked", B.getInt32Ty()); + inferLibFuncAttributes(*M->getFunction("getchar_unlocked"), *TLI); + CallInst *CI = B.CreateCall(F, {}, "getchar_unlocked"); + + if (const Function *Fn = dyn_cast(F->stripPointerCasts())) + CI->setCallingConv(Fn->getCallingConv()); + return CI; +} + +Value *llvm::emitFGetSUnlocked(Value *Str, Value *Size, Value *File, + IRBuilder<> &B, const TargetLibraryInfo *TLI) { + if (!TLI->has(LibFunc_fgets_unlocked)) + return nullptr; + + Module *M = B.GetInsertBlock()->getModule(); + Constant *F = + M->getOrInsertFunction("fgets_unlocked", B.getInt32Ty(), B.getInt8PtrTy(), + B.getInt32Ty(), File->getType()); + inferLibFuncAttributes(*M->getFunction("fgets_unlocked"), *TLI); + CallInst *CI = + B.CreateCall(F, {castToCStr(Str, B), Size, File}, "fgets_unlocked"); + + if (const Function *Fn = dyn_cast(F->stripPointerCasts())) + CI->setCallingConv(Fn->getCallingConv()); + return CI; +} + +Value *llvm::emitFReadUnlocked(Value *Ptr, Value *Size, Value *File, + IRBuilder<> &B, const DataLayout &DL, + const TargetLibraryInfo *TLI) { + if (!TLI->has(LibFunc_fread_unlocked)) + return nullptr; + + Module *M = B.GetInsertBlock()->getModule(); + LLVMContext &Context = B.GetInsertBlock()->getContext(); + StringRef FReadUnlockedName = TLI->getName(LibFunc_fread_unlocked); + Constant *F = M->getOrInsertFunction( + FReadUnlockedName, DL.getIntPtrType(Context), B.getInt8PtrTy(), + DL.getIntPtrType(Context), DL.getIntPtrType(Context), File->getType()); + + if (File->getType()->isPointerTy()) + inferLibFuncAttributes(*M->getFunction(FReadUnlockedName), *TLI); + CallInst *CI = + B.CreateCall(F, + {castToCStr(Ptr, B), Size, + ConstantInt::get(DL.getIntPtrType(Context), 1), File}); + + if (const Function *Fn = dyn_cast(F->stripPointerCasts())) + CI->setCallingConv(Fn->getCallingConv()); + return CI; +} \ No newline at end of file Index: lib/Transforms/Utils/SimplifyLibCalls.cpp =================================================================== --- lib/Transforms/Utils/SimplifyLibCalls.cpp +++ lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -22,6 +22,7 @@ #include "llvm/Analysis/OptimizationRemarkEmitter.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/ValueTracking.h" +#include "llvm/Analysis/CaptureTracking.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" @@ -119,6 +120,23 @@ } } +static bool isReplaceableWithUnlockedVariant(CallInst *CI, IRBuilder<> &B, + const TargetLibraryInfo *TLI) { + if (!CI->getFunction()->hasInternalLinkage()) + return false; + + inferLibFuncAttributes(*CI->getCalledFunction(), *TLI); + for (unsigned i = 1; i < CI->getNumArgOperands(); ++i) { + Value *Op = CI->getArgOperand(i); + if (Op->getType()->isPointerTy() && !isa(Op)) { + if (PointerMayBeCaptured(Op, true, true)) + return false; + } + } + + return true; +} + //===----------------------------------------------------------------------===// // String and Memory Library Call Optimizations //===----------------------------------------------------------------------===// @@ -1973,22 +1991,26 @@ // Get the element size and count. ConstantInt *SizeC = dyn_cast(CI->getArgOperand(1)); ConstantInt *CountC = dyn_cast(CI->getArgOperand(2)); - if (!SizeC || !CountC) - return nullptr; - uint64_t Bytes = SizeC->getZExtValue() * CountC->getZExtValue(); - - // If this is writing zero records, remove the call (it's a noop). - if (Bytes == 0) - return ConstantInt::get(CI->getType(), 0); - - // If this is writing one byte, turn it into fputc. - // This optimisation is only valid, if the return value is unused. - if (Bytes == 1 && CI->use_empty()) { // fwrite(S,1,1,F) -> fputc(S[0],F) - Value *Char = B.CreateLoad(castToCStr(CI->getArgOperand(0), B), "char"); - Value *NewCI = emitFPutC(Char, CI->getArgOperand(3), B, TLI); - return NewCI ? ConstantInt::get(CI->getType(), 1) : nullptr; + if (SizeC && CountC) { + uint64_t Bytes = SizeC->getZExtValue() * CountC->getZExtValue(); + + // If this is writing zero records, remove the call (it's a noop). + if (Bytes == 0) + return ConstantInt::get(CI->getType(), 0); + + // If this is writing one byte, turn it into fputc. + // This optimisation is only valid, if the return value is unused. + if (Bytes == 1 && CI->use_empty()) { // fwrite(S,1,1,F) -> fputc(S[0],F) + Value *Char = B.CreateLoad(castToCStr(CI->getArgOperand(0), B), "char"); + Value *NewCI = emitFPutC(Char, CI->getArgOperand(3), B, TLI); + return NewCI ? ConstantInt::get(CI->getType(), 1) : nullptr; + } } + if (isReplaceableWithUnlockedVariant(CI, B, TLI)) + return emitFWriteUnlocked(CI->getArgOperand(0), CI->getArgOperand(1), + CI->getArgOperand(2), B, DL, TLI); + return nullptr; } @@ -2000,9 +2022,14 @@ if (CI->getParent()->getParent()->optForSize()) return nullptr; - // We can't optimize if return value is used. - if (!CI->use_empty()) - return nullptr; + if (CI->use_empty()) { + if (isReplaceableWithUnlockedVariant(CI, B, TLI)) + return emitFPutSUnlocked(CI->getArgOperand(0), CI->getArgOperand(1), B, + TLI); + else + // We can't optimize if return value is used. + return nullptr; + } // fputs(s,F) --> fwrite(s,1,strlen(s),F) uint64_t Len = GetStringLength(CI->getArgOperand(0)); @@ -2016,6 +2043,52 @@ CI->getArgOperand(1), B, DL, TLI); } +Value *LibCallSimplifier::optimizeFPutc(CallInst *CI, IRBuilder<> &B) { + optimizeErrorReporting(CI, B, 1); + + if (isReplaceableWithUnlockedVariant(CI, B, TLI)) + return emitFPutCUnlocked(CI->getArgOperand(0), CI->getArgOperand(1), B, + TLI); + + return nullptr; +} + +Value *LibCallSimplifier::optimizeFGetc(CallInst *CI, IRBuilder<> &B) { + if (isReplaceableWithUnlockedVariant(CI, B, TLI)) + return emitFGetCUnlocked(CI->getArgOperand(0), B, TLI); + + return nullptr; +} + +Value *LibCallSimplifier::optimizePutChar(CallInst *CI, IRBuilder<> &B) { + if (isReplaceableWithUnlockedVariant(CI, B, TLI)) + return emitPutCharUnlocked(CI->getArgOperand(0), B, TLI); + + return nullptr; +} + +Value *LibCallSimplifier::optimizeGetChar(CallInst *CI, IRBuilder<> &B) { + if (isReplaceableWithUnlockedVariant(CI, B, TLI)) + return emitGetCharUnlocked(B, TLI); + + return nullptr; +} + +Value *LibCallSimplifier::optimizeFGets(CallInst *CI, IRBuilder<> &B) { + if (isReplaceableWithUnlockedVariant(CI, B, TLI)) + return emitFGetSUnlocked(CI->getArgOperand(0), CI->getArgOperand(1), CI->getArgOperand(2), B, TLI); + + return nullptr; +} + +Value *LibCallSimplifier::optimizeFRead(CallInst *CI, IRBuilder<> &B) { + if (isReplaceableWithUnlockedVariant(CI, B, TLI)) + return emitFReadUnlocked(CI->getArgOperand(0), CI->getArgOperand(1), + CI->getArgOperand(2), B, DL, TLI); + + return nullptr; +} + Value *LibCallSimplifier::optimizePuts(CallInst *CI, IRBuilder<> &B) { // Check for a constant string. StringRef Str; @@ -2298,17 +2371,29 @@ return optimizeFPrintF(CI, Builder); case LibFunc_fwrite: return optimizeFWrite(CI, Builder); + case LibFunc_fread: + return optimizeFRead(CI, Builder); case LibFunc_fputs: return optimizeFPuts(CI, Builder); + case LibFunc_fgets: + return optimizeFGets(CI, Builder); + case LibFunc_fputc: + case LibFunc_putc: + return optimizeFPutc(CI, Builder); + case LibFunc_fgetc: + case LibFunc_getc: + return optimizeFGetc(CI, Builder); case LibFunc_puts: return optimizePuts(CI, Builder); + case LibFunc_putchar: + return optimizePutChar(CI, Builder); + case LibFunc_getchar: + return optimizeGetChar(CI, Builder); case LibFunc_perror: return optimizeErrorReporting(CI, Builder); case LibFunc_vfprintf: case LibFunc_fiprintf: return optimizeErrorReporting(CI, Builder, 0); - case LibFunc_fputc: - return optimizeErrorReporting(CI, Builder, 1); default: return nullptr; }