summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Transforms/Utils
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Transforms/Utils')
-rw-r--r--llvm/lib/Transforms/Utils/BuildLibCalls.cpp124
-rw-r--r--llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp112
2 files changed, 217 insertions, 19 deletions
diff --git a/llvm/lib/Transforms/Utils/BuildLibCalls.cpp b/llvm/lib/Transforms/Utils/BuildLibCalls.cpp
index beb8886b1ac..bf912b078f6 100644
--- a/llvm/lib/Transforms/Utils/BuildLibCalls.cpp
+++ b/llvm/lib/Transforms/Utils/BuildLibCalls.cpp
@@ -386,6 +386,7 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) {
case LibFunc_fseek:
case LibFunc_ftell:
case LibFunc_fgetc:
+ case LibFunc_fgetc_unlocked:
case LibFunc_fseeko:
case LibFunc_ftello:
case LibFunc_fileno:
@@ -404,6 +405,7 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) {
Changed |= setOnlyReadsMemory(F);
return Changed;
case LibFunc_fputc:
+ case LibFunc_fputc_unlocked:
case LibFunc_fstat:
case LibFunc_frexp:
case LibFunc_frexpf:
@@ -413,21 +415,25 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) {
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);
@@ -458,6 +464,7 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) {
return Changed;
case LibFunc_gets:
case LibFunc_getchar:
+ case LibFunc_getchar_unlocked:
Changed |= setDoesNotThrow(F);
return Changed;
case LibFunc_getitimer:
@@ -496,6 +503,7 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) {
Changed |= setOnlyReadsMemory(F, 1);
return Changed;
case LibFunc_putc:
+ case LibFunc_putc_unlocked:
Changed |= setDoesNotThrow(F);
Changed |= setDoesNotCapture(F, 1);
return Changed;
@@ -516,6 +524,7 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) {
Changed |= setOnlyReadsMemory(F, 1);
return Changed;
case LibFunc_putchar:
+ case LibFunc_putchar_unlocked:
Changed |= setDoesNotThrow(F);
return Changed;
case LibFunc_popen:
@@ -997,6 +1006,24 @@ Value *llvm::emitFPutC(Value *Char, Value *File, IRBuilder<> &B,
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<Function>(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))
@@ -1015,6 +1042,24 @@ Value *llvm::emitFPutS(Value *Str, Value *File, IRBuilder<> &B,
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<Function>(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))
@@ -1074,3 +1119,82 @@ Value *llvm::emitCalloc(Value *Num, Value *Size, const AttributeList &Attrs,
return CI;
}
+
+Value *llvm::emitFWriteUnlocked(Value *Ptr, Value *Size, Value *N, 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, N, File});
+
+ if (const Function *Fn = dyn_cast<Function>(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<Function>(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<Function>(F->stripPointerCasts()))
+ CI->setCallingConv(Fn->getCallingConv());
+ return CI;
+}
+
+Value *llvm::emitFReadUnlocked(Value *Ptr, Value *Size, Value *N, 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, N, File});
+
+ if (const Function *Fn = dyn_cast<Function>(F->stripPointerCasts()))
+ CI->setCallingConv(Fn->getCallingConv());
+ return CI;
+}
diff --git a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
index 6e351d4447b..d97eb0507ba 100644
--- a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
@@ -21,6 +21,7 @@
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Analysis/Utils/Local.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"
@@ -127,6 +128,28 @@ static Value *convertStrToNumber(CallInst *CI, StringRef &Str, int64_t Base) {
return ConstantInt::get(CI->getType(), Result);
}
+static bool isLocallyOpenedFile(Value *File, CallInst *CI, IRBuilder<> &B,
+ const TargetLibraryInfo *TLI) {
+ CallInst *FOpen = dyn_cast<CallInst>(File);
+ if (!FOpen)
+ return false;
+
+ Function *InnerCallee = FOpen->getCalledFunction();
+ if (!InnerCallee)
+ return false;
+
+ LibFunc Func;
+ if (!TLI->getLibFunc(*InnerCallee, Func) || !TLI->has(Func) ||
+ Func != LibFunc_fopen)
+ return false;
+
+ inferLibFuncAttributes(*CI->getCalledFunction(), *TLI);
+ if (PointerMayBeCaptured(File, true, true))
+ return false;
+
+ return true;
+}
+
//===----------------------------------------------------------------------===//
// String and Memory Library Call Optimizations
//===----------------------------------------------------------------------===//
@@ -2076,22 +2099,27 @@ Value *LibCallSimplifier::optimizeFWrite(CallInst *CI, IRBuilder<> &B) {
// Get the element size and count.
ConstantInt *SizeC = dyn_cast<ConstantInt>(CI->getArgOperand(1));
ConstantInt *CountC = dyn_cast<ConstantInt>(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 (isLocallyOpenedFile(CI->getArgOperand(3), CI, B, TLI))
+ return emitFWriteUnlocked(CI->getArgOperand(0), CI->getArgOperand(1),
+ CI->getArgOperand(2), CI->getArgOperand(3), B, DL,
+ TLI);
+
return nullptr;
}
@@ -2103,9 +2131,15 @@ Value *LibCallSimplifier::optimizeFPuts(CallInst *CI, IRBuilder<> &B) {
if (CI->getParent()->getParent()->optForSize())
return nullptr;
- // We can't optimize if return value is used.
- if (!CI->use_empty())
- return nullptr;
+ // Check if has any use
+ if (!CI->use_empty()) {
+ if (isLocallyOpenedFile(CI->getArgOperand(1), 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));
@@ -2119,6 +2153,40 @@ Value *LibCallSimplifier::optimizeFPuts(CallInst *CI, IRBuilder<> &B) {
CI->getArgOperand(1), B, DL, TLI);
}
+Value *LibCallSimplifier::optimizeFPutc(CallInst *CI, IRBuilder<> &B) {
+ optimizeErrorReporting(CI, B, 1);
+
+ if (isLocallyOpenedFile(CI->getArgOperand(1), CI, B, TLI))
+ return emitFPutCUnlocked(CI->getArgOperand(0), CI->getArgOperand(1), B,
+ TLI);
+
+ return nullptr;
+}
+
+Value *LibCallSimplifier::optimizeFGetc(CallInst *CI, IRBuilder<> &B) {
+ if (isLocallyOpenedFile(CI->getArgOperand(0), CI, B, TLI))
+ return emitFGetCUnlocked(CI->getArgOperand(0), B, TLI);
+
+ return nullptr;
+}
+
+Value *LibCallSimplifier::optimizeFGets(CallInst *CI, IRBuilder<> &B) {
+ if (isLocallyOpenedFile(CI->getArgOperand(2), 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 (isLocallyOpenedFile(CI->getArgOperand(3), CI, B, TLI))
+ return emitFReadUnlocked(CI->getArgOperand(0), CI->getArgOperand(1),
+ CI->getArgOperand(2), CI->getArgOperand(3), B, DL,
+ TLI);
+
+ return nullptr;
+}
+
Value *LibCallSimplifier::optimizePuts(CallInst *CI, IRBuilder<> &B) {
// Check for a constant string.
StringRef Str;
@@ -2412,8 +2480,16 @@ Value *LibCallSimplifier::optimizeCall(CallInst *CI) {
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:
+ return optimizeFPutc(CI, Builder);
+ case LibFunc_fgetc:
+ return optimizeFGetc(CI, Builder);
case LibFunc_puts:
return optimizePuts(CI, Builder);
case LibFunc_perror:
@@ -2421,8 +2497,6 @@ Value *LibCallSimplifier::optimizeCall(CallInst *CI) {
case LibFunc_vfprintf:
case LibFunc_fiprintf:
return optimizeErrorReporting(CI, Builder, 0);
- case LibFunc_fputc:
- return optimizeErrorReporting(CI, Builder, 1);
default:
return nullptr;
}
OpenPOWER on IntegriCloud