Newer
Older
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
// Just make sure this has 2 arguments of the same FP type, which match the
// result type.
if (FT->getNumParams() != 1 || FT->getReturnType() != Type::Int32Ty ||
!isa<IntegerType>(FT->getParamType(0)))
return 0;
Value *Op = CI->getOperand(1);
// Constant fold.
if (ConstantInt *CI = dyn_cast<ConstantInt>(Op)) {
if (CI->getValue() == 0) // ffs(0) -> 0.
return Constant::getNullValue(CI->getType());
return ConstantInt::get(Type::Int32Ty, // ffs(c) -> cttz(c)+1
CI->getValue().countTrailingZeros()+1);
}
// ffs(x) -> x != 0 ? (i32)llvm.cttz(x)+1 : 0
const Type *ArgType = Op->getType();
Value *F = Intrinsic::getDeclaration(Callee->getParent(),
Intrinsic::cttz, &ArgType, 1);
Value *V = B.CreateCall(F, Op, "cttz");
V = B.CreateAdd(V, ConstantInt::get(Type::Int32Ty, 1), "tmp");
V = B.CreateIntCast(V, Type::Int32Ty, false, "tmp");
Value *Cond = B.CreateICmpNE(Op, Constant::getNullValue(ArgType), "tmp");
return B.CreateSelect(Cond, V, ConstantInt::get(Type::Int32Ty, 0));
}
};
//===---------------------------------------===//
// 'isdigit' Optimizations
struct VISIBILITY_HIDDEN IsDigitOpt : public LibCallOptimization {
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
const FunctionType *FT = Callee->getFunctionType();
// We require integer(i32)
if (FT->getNumParams() != 1 || !isa<IntegerType>(FT->getReturnType()) ||
FT->getParamType(0) != Type::Int32Ty)
return 0;
// isdigit(c) -> (c-'0') <u 10
Value *Op = CI->getOperand(1);
Op = B.CreateSub(Op, ConstantInt::get(Type::Int32Ty, '0'), "isdigittmp");
Op = B.CreateICmpULT(Op, ConstantInt::get(Type::Int32Ty, 10), "isdigit");
return B.CreateZExt(Op, CI->getType());
}
};
//===---------------------------------------===//
// 'isascii' Optimizations
struct VISIBILITY_HIDDEN IsAsciiOpt : public LibCallOptimization {
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
const FunctionType *FT = Callee->getFunctionType();
// We require integer(i32)
if (FT->getNumParams() != 1 || !isa<IntegerType>(FT->getReturnType()) ||
FT->getParamType(0) != Type::Int32Ty)
return 0;
// isascii(c) -> c <u 128
Value *Op = CI->getOperand(1);
Op = B.CreateICmpULT(Op, ConstantInt::get(Type::Int32Ty, 128), "isascii");
return B.CreateZExt(Op, CI->getType());
}
};
//===---------------------------------------===//
// 'abs', 'labs', 'llabs' Optimizations
struct VISIBILITY_HIDDEN AbsOpt : public LibCallOptimization {
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
const FunctionType *FT = Callee->getFunctionType();
// We require integer(integer) where the types agree.
if (FT->getNumParams() != 1 || !isa<IntegerType>(FT->getReturnType()) ||
FT->getParamType(0) != FT->getReturnType())
return 0;
// abs(x) -> x >s -1 ? x : -x
Value *Op = CI->getOperand(1);
Value *Pos = B.CreateICmpSGT(Op,ConstantInt::getAllOnesValue(Op->getType()),
"ispos");
Value *Neg = B.CreateNeg(Op, "neg");
return B.CreateSelect(Pos, Op, Neg);
}
};
//===---------------------------------------===//
// 'toascii' Optimizations
struct VISIBILITY_HIDDEN ToAsciiOpt : public LibCallOptimization {
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
const FunctionType *FT = Callee->getFunctionType();
// We require i32(i32)
if (FT->getNumParams() != 1 || FT->getReturnType() != FT->getParamType(0) ||
FT->getParamType(0) != Type::Int32Ty)
return 0;
// isascii(c) -> c & 0x7f
return B.CreateAnd(CI->getOperand(1), ConstantInt::get(CI->getType(),0x7F));
}
};
//===----------------------------------------------------------------------===//
// Formatting and IO Optimizations
//===----------------------------------------------------------------------===//
//===---------------------------------------===//
// 'printf' Optimizations
struct VISIBILITY_HIDDEN PrintFOpt : public LibCallOptimization {
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
// Require one fixed pointer argument and an integer/void result.
const FunctionType *FT = Callee->getFunctionType();
if (FT->getNumParams() < 1 || !isa<PointerType>(FT->getParamType(0)) ||
!(isa<IntegerType>(FT->getReturnType()) ||
FT->getReturnType() == Type::VoidTy))
return 0;
// Check for a fixed format string.
const char *FormatCStr = GetConstantStringInfo(CI->getOperand(1));
if (!FormatCStr) return 0;
std::string FormatStr = FormatCStr;
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
// Empty format string -> noop.
if (FormatStr.empty()) // Tolerate printf's declared void.
return CI->use_empty() ? (Value*)CI : ConstantInt::get(CI->getType(), 0);
// printf("x") -> putchar('x'), even for '%'.
if (FormatStr.size() == 1) {
EmitPutChar(ConstantInt::get(Type::Int32Ty, FormatStr[0]), B);
return CI->use_empty() ? (Value*)CI : ConstantInt::get(CI->getType(), 1);
}
// printf("foo\n") --> puts("foo")
if (FormatStr[FormatStr.size()-1] == '\n' &&
FormatStr.find('%') == std::string::npos) { // no format characters.
// Create a string literal with no \n on it. We expect the constant merge
// pass to be run after this pass, to merge duplicate strings.
FormatStr.erase(FormatStr.end()-1);
Constant *C = ConstantArray::get(FormatStr, true);
C = new GlobalVariable(C->getType(), true,GlobalVariable::InternalLinkage,
C, "str", Callee->getParent());
EmitPutS(C, B);
return CI->use_empty() ? (Value*)CI :
ConstantInt::get(CI->getType(), FormatStr.size()+1);
}
// Optimize specific format strings.
// printf("%c", chr) --> putchar(*(i8*)dst)
if (FormatStr == "%c" && CI->getNumOperands() > 2 &&
isa<IntegerType>(CI->getOperand(2)->getType())) {
EmitPutChar(CI->getOperand(2), B);
return CI->use_empty() ? (Value*)CI : ConstantInt::get(CI->getType(), 1);
}
// printf("%s\n", str) --> puts(str)
if (FormatStr == "%s\n" && CI->getNumOperands() > 2 &&
isa<PointerType>(CI->getOperand(2)->getType()) &&
CI->use_empty()) {
EmitPutS(CI->getOperand(2), B);
return CI;
}
return 0;
}
};
//===---------------------------------------===//
// 'sprintf' Optimizations
struct VISIBILITY_HIDDEN SPrintFOpt : public LibCallOptimization {
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
// Require two fixed pointer arguments and an integer result.
const FunctionType *FT = Callee->getFunctionType();
if (FT->getNumParams() != 2 || !isa<PointerType>(FT->getParamType(0)) ||
!isa<PointerType>(FT->getParamType(1)) ||
!isa<IntegerType>(FT->getReturnType()))
return 0;
// Check for a fixed format string.
const char *FormatCStr = GetConstantStringInfo(CI->getOperand(2));
if (!FormatCStr) return 0;
std::string FormatStr = FormatCStr;
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
// If we just have a format string (nothing else crazy) transform it.
if (CI->getNumOperands() == 3) {
// Make sure there's no % in the constant array. We could try to handle
// %% -> % in the future if we cared.
for (unsigned i = 0, e = FormatStr.size(); i != e; ++i)
if (FormatStr[i] == '%')
return 0; // we found a format specifier, bail out.
// sprintf(str, fmt) -> llvm.memcpy(str, fmt, strlen(fmt)+1, 1)
EmitMemCpy(CI->getOperand(1), CI->getOperand(2), // Copy the nul byte.
ConstantInt::get(TD->getIntPtrType(), FormatStr.size()+1),1,B);
return ConstantInt::get(CI->getType(), FormatStr.size());
}
// The remaining optimizations require the format string to be "%s" or "%c"
// and have an extra operand.
if (FormatStr.size() != 2 || FormatStr[0] != '%' || CI->getNumOperands() <4)
return 0;
// Decode the second character of the format string.
if (FormatStr[1] == 'c') {
// sprintf(dst, "%c", chr) --> *(i8*)dst = chr; *((i8*)dst+1) = 0
if (!isa<IntegerType>(CI->getOperand(3)->getType())) return 0;
Value *V = B.CreateTrunc(CI->getOperand(3), Type::Int8Ty, "char");
Value *Ptr = CastToCStr(CI->getOperand(1), B);
B.CreateStore(V, Ptr);
Ptr = B.CreateGEP(Ptr, ConstantInt::get(Type::Int32Ty, 1), "nul");
B.CreateStore(Constant::getNullValue(Type::Int8Ty), Ptr);
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
return ConstantInt::get(CI->getType(), 1);
}
if (FormatStr[1] == 's') {
// sprintf(dest, "%s", str) -> llvm.memcpy(dest, str, strlen(str)+1, 1)
if (!isa<PointerType>(CI->getOperand(3)->getType())) return 0;
Value *Len = EmitStrLen(CI->getOperand(3), B);
Value *IncLen = B.CreateAdd(Len, ConstantInt::get(Len->getType(), 1),
"leninc");
EmitMemCpy(CI->getOperand(1), CI->getOperand(3), IncLen, 1, B);
// The sprintf result is the unincremented number of bytes in the string.
return B.CreateIntCast(Len, CI->getType(), false);
}
return 0;
}
};
//===---------------------------------------===//
// 'fwrite' Optimizations
struct VISIBILITY_HIDDEN FWriteOpt : public LibCallOptimization {
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
// Require a pointer, an integer, an integer, a pointer, returning integer.
const FunctionType *FT = Callee->getFunctionType();
if (FT->getNumParams() != 4 || !isa<PointerType>(FT->getParamType(0)) ||
!isa<IntegerType>(FT->getParamType(1)) ||
!isa<IntegerType>(FT->getParamType(2)) ||
!isa<PointerType>(FT->getParamType(3)) ||
!isa<IntegerType>(FT->getReturnType()))
return 0;
// Get the element size and count.
ConstantInt *SizeC = dyn_cast<ConstantInt>(CI->getOperand(2));
ConstantInt *CountC = dyn_cast<ConstantInt>(CI->getOperand(3));
if (!SizeC || !CountC) return 0;
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.
if (Bytes == 1) { // fwrite(S,1,1,F) -> fputc(S[0],F)
Value *Char = B.CreateLoad(CastToCStr(CI->getOperand(1), B), "char");
EmitFPutC(Char, CI->getOperand(4), B);
return ConstantInt::get(CI->getType(), 1);
}
return 0;
}
};
//===---------------------------------------===//
// 'fputs' Optimizations
struct VISIBILITY_HIDDEN FPutsOpt : public LibCallOptimization {
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
// Require two pointers. Also, we can't optimize if return value is used.
const FunctionType *FT = Callee->getFunctionType();
if (FT->getNumParams() != 2 || !isa<PointerType>(FT->getParamType(0)) ||
!isa<PointerType>(FT->getParamType(1)) ||
!CI->use_empty())
return 0;
// fputs(s,F) --> fwrite(s,1,strlen(s),F)
uint64_t Len = GetStringLength(CI->getOperand(1));
EmitFWrite(CI->getOperand(1), ConstantInt::get(TD->getIntPtrType(), Len-1),
CI->getOperand(2), B);
return CI; // Known to have no uses (see above).
}
};
//===---------------------------------------===//
// 'fprintf' Optimizations
struct VISIBILITY_HIDDEN FPrintFOpt : public LibCallOptimization {
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
// Require two fixed paramters as pointers and integer result.
const FunctionType *FT = Callee->getFunctionType();
if (FT->getNumParams() != 2 || !isa<PointerType>(FT->getParamType(0)) ||
!isa<PointerType>(FT->getParamType(1)) ||
!isa<IntegerType>(FT->getReturnType()))
return 0;
// All the optimizations depend on the format string.
const char *FormatCStr = GetConstantStringInfo(CI->getOperand(2));
if (!FormatCStr) return 0;
std::string FormatStr = FormatCStr;
// fprintf(F, "foo") --> fwrite("foo", 3, 1, F)
if (CI->getNumOperands() == 3) {
for (unsigned i = 0, e = FormatStr.size(); i != e; ++i)
if (FormatStr[i] == '%') // Could handle %% -> % if we cared.
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
EmitFWrite(CI->getOperand(2), ConstantInt::get(TD->getIntPtrType(),
FormatStr.size()),
CI->getOperand(1), B);
return ConstantInt::get(CI->getType(), FormatStr.size());
}
// The remaining optimizations require the format string to be "%s" or "%c"
// and have an extra operand.
if (FormatStr.size() != 2 || FormatStr[0] != '%' || CI->getNumOperands() <4)
return 0;
// Decode the second character of the format string.
if (FormatStr[1] == 'c') {
// fprintf(F, "%c", chr) --> *(i8*)dst = chr
if (!isa<IntegerType>(CI->getOperand(3)->getType())) return 0;
EmitFPutC(CI->getOperand(3), CI->getOperand(1), B);
return ConstantInt::get(CI->getType(), 1);
}
if (FormatStr[1] == 's') {
// fprintf(F, "%s", str) -> fputs(str, F)
if (!isa<PointerType>(CI->getOperand(3)->getType()) || !CI->use_empty())
return 0;
EmitFPutS(CI->getOperand(3), CI->getOperand(1), B);
return CI;
}
return 0;
}
};
Bill Wendling
committed
} // end anonymous namespace.
//===----------------------------------------------------------------------===//
// SimplifyLibCalls Pass Implementation
//===----------------------------------------------------------------------===//
namespace {
/// This pass optimizes well known library functions from libc and libm.
///
class VISIBILITY_HIDDEN SimplifyLibCalls : public FunctionPass {
StringMap<LibCallOptimization*> Optimizations;
// Miscellaneous LibCall Optimizations
ExitOpt Exit;
// String and Memory LibCall Optimizations
StrCatOpt StrCat; StrChrOpt StrChr; StrCmpOpt StrCmp; StrNCmpOpt StrNCmp;
Nick Lewycky
committed
StrCpyOpt StrCpy; StrLenOpt StrLen; StrToOpt StrTo; MemCmpOpt MemCmp;
MemCpyOpt MemCpy; MemMoveOpt MemMove; MemSetOpt MemSet;
// Math Library Optimizations
PowOpt Pow; Exp2Opt Exp2; UnaryDoubleFPOpt UnaryDoubleFP;
// Integer Optimizations
FFSOpt FFS; AbsOpt Abs; IsDigitOpt IsDigit; IsAsciiOpt IsAscii;
ToAsciiOpt ToAscii;
// Formatting and IO Optimizations
SPrintFOpt SPrintF; PrintFOpt PrintF;
FWriteOpt FWrite; FPutsOpt FPuts; FPrintFOpt FPrintF;
bool Modified; // This is only used by doInitialization.
public:
static char ID; // Pass identification
SimplifyLibCalls() : FunctionPass(&ID) {}
void InitOptimizations();
bool runOnFunction(Function &F);
void setDoesNotAccessMemory(Function &F);
void setOnlyReadsMemory(Function &F);
void setDoesNotThrow(Function &F);
void setDoesNotCapture(Function &F, unsigned n);
void setDoesNotAlias(Function &F, unsigned n);
bool doInitialization(Module &M);
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<TargetData>();
}
};
char SimplifyLibCalls::ID = 0;
} // end anonymous namespace.
static RegisterPass<SimplifyLibCalls>
X("simplify-libcalls", "Simplify well-known library calls");
// Public interface to the Simplify LibCalls pass.
FunctionPass *llvm::createSimplifyLibCallsPass() {
return new SimplifyLibCalls();
}
/// Optimizations - Populate the Optimizations map with all the optimizations
/// we know.
void SimplifyLibCalls::InitOptimizations() {
// Miscellaneous LibCall Optimizations
Optimizations["exit"] = &Exit;
// String and Memory LibCall Optimizations
Optimizations["strcat"] = &StrCat;
Optimizations["strchr"] = &StrChr;
Optimizations["strcmp"] = &StrCmp;
Optimizations["strncmp"] = &StrNCmp;
Optimizations["strcpy"] = &StrCpy;
Optimizations["strlen"] = &StrLen;
Nick Lewycky
committed
Optimizations["strtol"] = &StrTo;
Optimizations["strtod"] = &StrTo;
Optimizations["strtof"] = &StrTo;
Optimizations["strtoul"] = &StrTo;
Optimizations["strtoll"] = &StrTo;
Optimizations["strtold"] = &StrTo;
Optimizations["strtoull"] = &StrTo;
Optimizations["memcmp"] = &MemCmp;
Optimizations["memcpy"] = &MemCpy;
Optimizations["memmove"] = &MemMove;
Optimizations["memset"] = &MemSet;
// Math Library Optimizations
Optimizations["powf"] = &Pow;
Optimizations["pow"] = &Pow;
Optimizations["powl"] = &Pow;
Optimizations["llvm.pow.f32"] = &Pow;
Optimizations["llvm.pow.f64"] = &Pow;
Optimizations["llvm.pow.f80"] = &Pow;
Optimizations["llvm.pow.f128"] = &Pow;
Optimizations["llvm.pow.ppcf128"] = &Pow;
Optimizations["exp2l"] = &Exp2;
Optimizations["exp2"] = &Exp2;
Optimizations["exp2f"] = &Exp2;
Optimizations["llvm.exp2.ppcf128"] = &Exp2;
Optimizations["llvm.exp2.f128"] = &Exp2;
Optimizations["llvm.exp2.f80"] = &Exp2;
Optimizations["llvm.exp2.f64"] = &Exp2;
Optimizations["llvm.exp2.f32"] = &Exp2;
#ifdef HAVE_FLOORF
Optimizations["floor"] = &UnaryDoubleFP;
#endif
#ifdef HAVE_CEILF
Optimizations["ceil"] = &UnaryDoubleFP;
#endif
#ifdef HAVE_ROUNDF
Optimizations["round"] = &UnaryDoubleFP;
#endif
#ifdef HAVE_RINTF
Optimizations["rint"] = &UnaryDoubleFP;
#endif
#ifdef HAVE_NEARBYINTF
Optimizations["nearbyint"] = &UnaryDoubleFP;
#endif
// Integer Optimizations
Optimizations["ffs"] = &FFS;
Optimizations["ffsl"] = &FFS;
Optimizations["ffsll"] = &FFS;
Optimizations["abs"] = &Abs;
Optimizations["labs"] = &Abs;
Optimizations["llabs"] = &Abs;
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
Optimizations["isdigit"] = &IsDigit;
Optimizations["isascii"] = &IsAscii;
Optimizations["toascii"] = &ToAscii;
// Formatting and IO Optimizations
Optimizations["sprintf"] = &SPrintF;
Optimizations["printf"] = &PrintF;
Optimizations["fwrite"] = &FWrite;
Optimizations["fputs"] = &FPuts;
Optimizations["fprintf"] = &FPrintF;
}
/// runOnFunction - Top level algorithm.
///
bool SimplifyLibCalls::runOnFunction(Function &F) {
if (Optimizations.empty())
InitOptimizations();
const TargetData &TD = getAnalysis<TargetData>();
IRBuilder<> Builder;
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
bool Changed = false;
for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB) {
for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ) {
// Ignore non-calls.
CallInst *CI = dyn_cast<CallInst>(I++);
if (!CI) continue;
// Ignore indirect calls and calls to non-external functions.
Function *Callee = CI->getCalledFunction();
if (Callee == 0 || !Callee->isDeclaration() ||
!(Callee->hasExternalLinkage() || Callee->hasDLLImportLinkage()))
continue;
// Ignore unknown calls.
const char *CalleeName = Callee->getNameStart();
StringMap<LibCallOptimization*>::iterator OMI =
Optimizations.find(CalleeName, CalleeName+Callee->getNameLen());
if (OMI == Optimizations.end()) continue;
// Set the builder to the instruction after the call.
Builder.SetInsertPoint(BB, I);
// Try to optimize this call.
Value *Result = OMI->second->OptimizeCall(CI, TD, Builder);
if (Result == 0) continue;
DEBUG(DOUT << "SimplifyLibCalls simplified: " << *CI;
DOUT << " into: " << *Result << "\n");
// Something changed!
Changed = true;
++NumSimplified;
// Inspect the instruction after the call (which was potentially just
// added) next.
I = CI; ++I;
if (CI != Result && !CI->use_empty()) {
CI->replaceAllUsesWith(Result);
if (!Result->hasName())
Result->takeName(CI);
}
CI->eraseFromParent();
}
}
return Changed;
}
// Utility methods for doInitialization.
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
void SimplifyLibCalls::setDoesNotAccessMemory(Function &F) {
if (!F.doesNotAccessMemory()) {
F.setDoesNotAccessMemory();
++NumAnnotated;
Modified = true;
}
}
void SimplifyLibCalls::setOnlyReadsMemory(Function &F) {
if (!F.onlyReadsMemory()) {
F.setOnlyReadsMemory();
++NumAnnotated;
Modified = true;
}
}
void SimplifyLibCalls::setDoesNotThrow(Function &F) {
if (!F.doesNotThrow()) {
F.setDoesNotThrow();
++NumAnnotated;
Modified = true;
}
}
void SimplifyLibCalls::setDoesNotCapture(Function &F, unsigned n) {
if (!F.doesNotCapture(n)) {
F.setDoesNotCapture(n);
++NumAnnotated;
Modified = true;
}
}
void SimplifyLibCalls::setDoesNotAlias(Function &F, unsigned n) {
if (!F.doesNotAlias(n)) {
F.setDoesNotAlias(n);
++NumAnnotated;
Modified = true;
}
}
/// doInitialization - Add attributes to well-known functions.
bool SimplifyLibCalls::doInitialization(Module &M) {
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
Modified = false;
for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) {
Function &F = *I;
if (!F.isDeclaration())
continue;
unsigned NameLen = F.getNameLen();
if (!NameLen)
continue;
const FunctionType *FTy = F.getFunctionType();
const char *NameStr = F.getNameStart();
switch (NameStr[0]) {
case 's':
if (NameLen == 6 && !strcmp(NameStr, "strlen")) {
if (FTy->getNumParams() != 1 ||
!isa<PointerType>(FTy->getParamType(0)))
continue;
setOnlyReadsMemory(F);
setDoesNotThrow(F);
setDoesNotCapture(F, 1);
} else if ((NameLen == 6 && !strcmp(NameStr, "strcpy")) ||
(NameLen == 6 && !strcmp(NameStr, "stpcpy")) ||
(NameLen == 6 && !strcmp(NameStr, "strcat")) ||
Nick Lewycky
committed
(NameLen == 6 && !strcmp(NameStr, "strtol")) ||
(NameLen == 6 && !strcmp(NameStr, "strtod")) ||
(NameLen == 6 && !strcmp(NameStr, "strtof")) ||
(NameLen == 7 && !strcmp(NameStr, "strtoul")) ||
(NameLen == 7 && !strcmp(NameStr, "strtoll")) ||
(NameLen == 7 && !strcmp(NameStr, "strtold")) ||
(NameLen == 7 && !strcmp(NameStr, "strncat")) ||
Nick Lewycky
committed
(NameLen == 7 && !strcmp(NameStr, "strncpy")) ||
(NameLen == 8 && !strcmp(NameStr, "strtoull"))) {
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
if (FTy->getNumParams() < 2 ||
!isa<PointerType>(FTy->getParamType(1)))
continue;
setDoesNotThrow(F);
setDoesNotCapture(F, 2);
} else if (NameLen == 7 && !strcmp(NameStr, "strxfrm")) {
if (FTy->getNumParams() != 3 ||
!isa<PointerType>(FTy->getParamType(0)) ||
!isa<PointerType>(FTy->getParamType(1)))
continue;
setDoesNotThrow(F);
setDoesNotCapture(F, 1);
setDoesNotCapture(F, 2);
} else if ((NameLen == 6 && !strcmp(NameStr, "strcmp")) ||
(NameLen == 6 && !strcmp(NameStr, "strspn")) ||
(NameLen == 7 && !strcmp(NameStr, "strncmp")) ||
(NameLen == 7 && !strcmp(NameStr, "strcspn")) ||
(NameLen == 7 && !strcmp(NameStr, "strcoll")) ||
(NameLen == 10 && !strcmp(NameStr, "strcasecmp")) ||
(NameLen == 11 && !strcmp(NameStr, "strncasecmp"))) {
if (FTy->getNumParams() < 2 ||
!isa<PointerType>(FTy->getParamType(0)) ||
!isa<PointerType>(FTy->getParamType(1)))
continue;
setOnlyReadsMemory(F);
setDoesNotThrow(F);
setDoesNotCapture(F, 1);
setDoesNotCapture(F, 2);
} else if ((NameLen == 6 && !strcmp(NameStr, "strstr")) ||
(NameLen == 7 && !strcmp(NameStr, "strpbrk"))) {
if (FTy->getNumParams() != 2 ||
!isa<PointerType>(FTy->getParamType(1)))
continue;
setOnlyReadsMemory(F);
setDoesNotThrow(F);
setDoesNotCapture(F, 2);
} else if ((NameLen == 6 && !strcmp(NameStr, "strtok")) ||
(NameLen == 8 && !strcmp(NameStr, "strtok_r"))) {
if (FTy->getNumParams() < 2 ||
!isa<PointerType>(FTy->getParamType(1)))
continue;
setDoesNotThrow(F);
setDoesNotCapture(F, 2);
} else if ((NameLen == 5 && !strcmp(NameStr, "scanf")) ||
(NameLen == 6 && !strcmp(NameStr, "setbuf")) ||
(NameLen == 7 && !strcmp(NameStr, "setvbuf"))) {
if (FTy->getNumParams() < 1 ||
!isa<PointerType>(FTy->getParamType(0)))
continue;
setDoesNotThrow(F);
setDoesNotCapture(F, 1);
} else if ((NameLen == 6 && !strcmp(NameStr, "strdup")) ||
(NameLen == 7 && !strcmp(NameStr, "strndup"))) {
if (FTy->getNumParams() < 1 ||
!isa<PointerType>(FTy->getReturnType()) ||
!isa<PointerType>(FTy->getParamType(0)))
continue;
setDoesNotThrow(F);
setDoesNotAlias(F, 0);
setDoesNotCapture(F, 1);
} else if ((NameLen == 4 && !strcmp(NameStr, "stat")) ||
(NameLen == 6 && !strcmp(NameStr, "sscanf")) ||
(NameLen == 7 && !strcmp(NameStr, "sprintf")) ||
(NameLen == 7 && !strcmp(NameStr, "statvfs"))) {
if (FTy->getNumParams() < 2 ||
!isa<PointerType>(FTy->getParamType(0)) ||
!isa<PointerType>(FTy->getParamType(1)))
continue;
setDoesNotThrow(F);
setDoesNotCapture(F, 1);
setDoesNotCapture(F, 2);
} else if (NameLen == 8 && !strcmp(NameStr, "snprintf")) {
if (FTy->getNumParams() != 3 ||
!isa<PointerType>(FTy->getParamType(0)) ||
!isa<PointerType>(FTy->getParamType(2)))
continue;
setDoesNotThrow(F);
setDoesNotCapture(F, 1);
setDoesNotCapture(F, 3);
} else if (NameLen == 9 && !strcmp(NameStr, "setitimer")) {
if (FTy->getNumParams() != 3 ||
!isa<PointerType>(FTy->getParamType(1)) ||
!isa<PointerType>(FTy->getParamType(2)))
continue;
setDoesNotThrow(F);
setDoesNotCapture(F, 2);
setDoesNotCapture(F, 3);
} else if (NameLen == 6 && !strcmp(NameStr, "system")) {
if (FTy->getNumParams() != 1 ||
!isa<PointerType>(FTy->getParamType(0)))
continue;
// May throw; "system" is a valid pthread cancellation point.
setDoesNotCapture(F, 1);
}
break;
case 'm':
if (NameLen == 6 && !strcmp(NameStr, "memcmp")) {
if (FTy->getNumParams() != 3 ||
!isa<PointerType>(FTy->getParamType(0)) ||
!isa<PointerType>(FTy->getParamType(1)))
continue;
setOnlyReadsMemory(F);
setDoesNotThrow(F);
setDoesNotCapture(F, 1);
setDoesNotCapture(F, 2);
} else if ((NameLen == 6 && !strcmp(NameStr, "memchr")) ||
(NameLen == 7 && !strcmp(NameStr, "memrchr"))) {
if (FTy->getNumParams() != 3)
continue;
setOnlyReadsMemory(F);
setDoesNotThrow(F);
} else if ((NameLen == 4 && !strcmp(NameStr, "modf")) ||
(NameLen == 5 && !strcmp(NameStr, "modff")) ||
(NameLen == 5 && !strcmp(NameStr, "modfl")) ||
(NameLen == 6 && !strcmp(NameStr, "memcpy")) ||
(NameLen == 7 && !strcmp(NameStr, "memccpy")) ||
(NameLen == 7 && !strcmp(NameStr, "memmove"))) {
if (FTy->getNumParams() < 2 ||
!isa<PointerType>(FTy->getParamType(1)))
continue;
setDoesNotThrow(F);
setDoesNotCapture(F, 2);
} else if (NameLen == 8 && !strcmp(NameStr, "memalign")) {
if (!isa<PointerType>(FTy->getReturnType()))
continue;
setDoesNotAlias(F, 0);
} else if ((NameLen == 5 && !strcmp(NameStr, "mkdir")) ||
(NameLen == 6 && !strcmp(NameStr, "mktime"))) {
if (FTy->getNumParams() == 0 ||
!isa<PointerType>(FTy->getParamType(0)))
continue;
setDoesNotThrow(F);
setDoesNotCapture(F, 1);
}
break;
case 'r':
if (NameLen == 7 && !strcmp(NameStr, "realloc")) {
if (FTy->getNumParams() != 2 ||
!isa<PointerType>(FTy->getParamType(0)) ||
!isa<PointerType>(FTy->getReturnType()))
continue;
setDoesNotThrow(F);
setDoesNotAlias(F, 0);
setDoesNotCapture(F, 1);
} else if (NameLen == 4 && !strcmp(NameStr, "read")) {
if (FTy->getNumParams() != 3 ||
!isa<PointerType>(FTy->getParamType(1)))
continue;
// May throw; "read" is a valid pthread cancellation point.
setDoesNotCapture(F, 2);
} else if ((NameLen == 5 && !strcmp(NameStr, "rmdir")) ||
(NameLen == 6 && !strcmp(NameStr, "rewind")) ||
(NameLen == 6 && !strcmp(NameStr, "remove")) ||
(NameLen == 8 && !strcmp(NameStr, "realpath"))) {
if (FTy->getNumParams() < 1 ||
!isa<PointerType>(FTy->getParamType(0)))
continue;
setDoesNotThrow(F);
setDoesNotCapture(F, 1);
} else if ((NameLen == 6 && !strcmp(NameStr, "rename")) ||
(NameLen == 8 && !strcmp(NameStr, "readlink"))) {
if (FTy->getNumParams() < 2 ||
!isa<PointerType>(FTy->getParamType(0)) ||
!isa<PointerType>(FTy->getParamType(1)))
continue;
setDoesNotThrow(F);
setDoesNotCapture(F, 1);
setDoesNotCapture(F, 2);
}
break;
case 'w':
if (NameLen == 5 && !strcmp(NameStr, "write")) {
if (FTy->getNumParams() != 3 ||
!isa<PointerType>(FTy->getParamType(1)))
continue;
// May throw; "write" is a valid pthread cancellation point.
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
setDoesNotCapture(F, 2);
}
break;
case 'b':
if (NameLen == 5 && !strcmp(NameStr, "bcopy")) {
if (FTy->getNumParams() != 3 ||
!isa<PointerType>(FTy->getParamType(0)) ||
!isa<PointerType>(FTy->getParamType(1)))
continue;
setDoesNotThrow(F);
setDoesNotCapture(F, 1);
setDoesNotCapture(F, 2);
} else if (NameLen == 4 && !strcmp(NameStr, "bcmp")) {
if (FTy->getNumParams() != 3 ||
!isa<PointerType>(FTy->getParamType(0)) ||
!isa<PointerType>(FTy->getParamType(1)))
continue;
setDoesNotThrow(F);
setOnlyReadsMemory(F);
setDoesNotCapture(F, 1);
setDoesNotCapture(F, 2);
} else if (NameLen == 5 && !strcmp(NameStr, "bzero")) {
if (FTy->getNumParams() != 2 ||
!isa<PointerType>(FTy->getParamType(0)))
continue;
setDoesNotThrow(F);
setDoesNotCapture(F, 1);
}
break;
case 'c':
if (NameLen == 6 && !strcmp(NameStr, "calloc")) {
if (FTy->getNumParams() != 2 ||
!isa<PointerType>(FTy->getReturnType()))
continue;
setDoesNotThrow(F);
setDoesNotAlias(F, 0);
} else if ((NameLen == 5 && !strcmp(NameStr, "chmod")) ||
(NameLen == 5 && !strcmp(NameStr, "chown")) ||
(NameLen == 7 && !strcmp(NameStr, "ctermid")) ||
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
(NameLen == 8 && !strcmp(NameStr, "clearerr")) ||
(NameLen == 8 && !strcmp(NameStr, "closedir"))) {
if (FTy->getNumParams() == 0 ||
!isa<PointerType>(FTy->getParamType(0)))
continue;
setDoesNotThrow(F);
setDoesNotCapture(F, 1);
}
break;
case 'a':
if ((NameLen == 4 && !strcmp(NameStr, "atoi")) ||
(NameLen == 4 && !strcmp(NameStr, "atol")) ||
(NameLen == 4 && !strcmp(NameStr, "atof")) ||
(NameLen == 5 && !strcmp(NameStr, "atoll"))) {
if (FTy->getNumParams() != 1 ||
!isa<PointerType>(FTy->getParamType(0)))
continue;
setDoesNotThrow(F);
setOnlyReadsMemory(F);
setDoesNotCapture(F, 1);
} else if (NameLen == 6 && !strcmp(NameStr, "access")) {
if (FTy->getNumParams() != 2 ||
!isa<PointerType>(FTy->getParamType(0)))
continue;
setDoesNotThrow(F);
setDoesNotCapture(F, 1);
}
break;
case 'f':
if (NameLen == 5 && !strcmp(NameStr, "fopen")) {
if (FTy->getNumParams() != 2 ||
!isa<PointerType>(FTy->getReturnType()) ||
!isa<PointerType>(FTy->getParamType(0)) ||
!isa<PointerType>(FTy->getParamType(1)))
continue;
setDoesNotThrow(F);
setDoesNotAlias(F, 0);
setDoesNotCapture(F, 1);
setDoesNotCapture(F, 2);
} else if (NameLen == 6 && !strcmp(NameStr, "fdopen")) {
if (FTy->getNumParams() != 2 ||
!isa<PointerType>(FTy->getReturnType()) ||
!isa<PointerType>(FTy->getParamType(1)))
continue;
setDoesNotThrow(F);
setDoesNotAlias(F, 0);
setDoesNotCapture(F, 2);
} else if ((NameLen == 4 && !strcmp(NameStr, "feof")) ||
(NameLen == 4 && !strcmp(NameStr, "free")) ||
(NameLen == 5 && !strcmp(NameStr, "fseek")) ||
(NameLen == 5 && !strcmp(NameStr, "ftell")) ||
(NameLen == 5 && !strcmp(NameStr, "fgetc")) ||
(NameLen == 6 && !strcmp(NameStr, "fseeko")) ||
(NameLen == 6 && !strcmp(NameStr, "ftello")) ||
(NameLen == 6 && !strcmp(NameStr, "fileno")) ||
(NameLen == 6 && !strcmp(NameStr, "fflush")) ||
(NameLen == 6 && !strcmp(NameStr, "fclose")) ||
(NameLen == 7 && !strcmp(NameStr, "fsetpos")) ||
(NameLen == 9 && !strcmp(NameStr, "flockfile")) ||
(NameLen == 11 && !strcmp(NameStr, "funlockfile")) ||
(NameLen == 12 && !strcmp(NameStr, "ftrylockfile"))) {
if (FTy->getNumParams() == 0 ||
!isa<PointerType>(FTy->getParamType(0)))
continue;
setDoesNotThrow(F);
setDoesNotCapture(F, 1);
} else if (NameLen == 6 && !strcmp(NameStr, "ferror")) {
if (FTy->getNumParams() != 1 ||
!isa<PointerType>(FTy->getParamType(0)))
continue;
setDoesNotThrow(F);
setDoesNotCapture(F, 1);
setOnlyReadsMemory(F);
} else if ((NameLen == 5 && !strcmp(NameStr, "fputc")) ||
(NameLen == 5 && !strcmp(NameStr, "fstat")) ||
(NameLen == 5 && !strcmp(NameStr, "frexp")) ||
(NameLen == 6 && !strcmp(NameStr, "frexpf")) ||
(NameLen == 6 && !strcmp(NameStr, "frexpl")) ||
(NameLen == 8 && !strcmp(NameStr, "fstatvfs"))) {
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
if (FTy->getNumParams() != 2 ||
!isa<PointerType>(FTy->getParamType(1)))
continue;
setDoesNotThrow(F);
setDoesNotCapture(F, 2);
} else if (NameLen == 5 && !strcmp(NameStr, "fgets")) {
if (FTy->getNumParams() != 3 ||
!isa<PointerType>(FTy->getParamType(0)) ||
!isa<PointerType>(FTy->getParamType(2)))
continue;
setDoesNotThrow(F);
setDoesNotCapture(F, 3);
} else if ((NameLen == 5 && !strcmp(NameStr, "fread")) ||
(NameLen == 6 && !strcmp(NameStr, "fwrite"))) {
if (FTy->getNumParams() != 4 ||
!isa<PointerType>(FTy->getParamType(0)) ||
!isa<PointerType>(FTy->getParamType(3)))
continue;
setDoesNotThrow(F);
setDoesNotCapture(F, 1);
setDoesNotCapture(F, 4);
} else if ((NameLen == 5 && !strcmp(NameStr, "fputs")) ||
(NameLen == 6 && !strcmp(NameStr, "fscanf")) ||
(NameLen == 7 && !strcmp(NameStr, "fprintf")) ||
(NameLen == 7 && !strcmp(NameStr, "fgetpos"))) {
if (FTy->getNumParams() < 2 ||
!isa<PointerType>(FTy->getParamType(0)) ||
!isa<PointerType>(FTy->getParamType(1)))
continue;
setDoesNotThrow(F);
setDoesNotCapture(F, 1);
setDoesNotCapture(F, 2);
}
break;
case 'g':
if ((NameLen == 4 && !strcmp(NameStr, "getc")) ||
(NameLen == 10 && !strcmp(NameStr, "getlogin_r")) ||
(NameLen == 13 && !strcmp(NameStr, "getc_unlocked"))) {
if (FTy->getNumParams() == 0 ||
!isa<PointerType>(FTy->getParamType(0)))
continue;
setDoesNotThrow(F);
setDoesNotCapture(F, 1);
} else if (NameLen == 6 && !strcmp(NameStr, "getenv")) {
if (FTy->getNumParams() != 1 ||
!isa<PointerType>(FTy->getParamType(0)))
continue;
setDoesNotThrow(F);
setOnlyReadsMemory(F);
setDoesNotCapture(F, 1);
} else if ((NameLen == 4 && !strcmp(NameStr, "gets")) ||
(NameLen == 7 && !strcmp(NameStr, "getchar"))) {
setDoesNotThrow(F);
} else if (NameLen == 9 && !strcmp(NameStr, "getitimer")) {
if (FTy->getNumParams() != 2 ||
!isa<PointerType>(FTy->getParamType(1)))
continue;
setDoesNotThrow(F);
setDoesNotCapture(F, 2);
} else if (NameLen == 8 && !strcmp(NameStr, "getpwnam")) {
if (FTy->getNumParams() != 1 ||
!isa<PointerType>(FTy->getParamType(0)))
continue;
setDoesNotThrow(F);
setDoesNotCapture(F, 1);
}
break;
case 'u':
if (NameLen == 6 && !strcmp(NameStr, "ungetc")) {
if (FTy->getNumParams() != 2 ||
!isa<PointerType>(FTy->getParamType(1)))
continue;
setDoesNotThrow(F);
setDoesNotCapture(F, 2);
} else if ((NameLen == 5 && !strcmp(NameStr, "uname")) ||
(NameLen == 6 && !strcmp(NameStr, "unlink")) ||
(NameLen == 8 && !strcmp(NameStr, "unsetenv"))) {
if (FTy->getNumParams() != 1 ||
!isa<PointerType>(FTy->getParamType(0)))
continue;
setDoesNotThrow(F);
setDoesNotCapture(F, 1);
} else if ((NameLen == 5 && !strcmp(NameStr, "utime")) ||
(NameLen == 6 && !strcmp(NameStr, "utimes"))) {
if (FTy->getNumParams() != 2 ||
!isa<PointerType>(FTy->getParamType(0)) ||
!isa<PointerType>(FTy->getParamType(1)))
continue;
setDoesNotThrow(F);
setDoesNotCapture(F, 1);
setDoesNotCapture(F, 2);
}
break;
case 'p':
if (NameLen == 4 && !strcmp(NameStr, "putc")) {
if (FTy->getNumParams() != 2 ||
!isa<PointerType>(FTy->getParamType(1)))