aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp')
-rw-r--r--contrib/llvm-project/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp137
1 files changed, 109 insertions, 28 deletions
diff --git a/contrib/llvm-project/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp b/contrib/llvm-project/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
index bca3b0538c5d..03087d8370d5 100644
--- a/contrib/llvm-project/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
+++ b/contrib/llvm-project/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
@@ -75,39 +75,109 @@ static bool callHasFP128Argument(const CallInst *CI) {
});
}
-static Value *convertStrToNumber(CallInst *CI, StringRef &Str, Value *EndPtr,
- int64_t Base, IRBuilderBase &B) {
+// Convert the entire string Str representing an integer in Base, up to
+// the terminating nul if present, to a constant according to the rules
+// of strtoul[l] or, when AsSigned is set, of strtol[l]. On success
+// return the result, otherwise null.
+// The function assumes the string is encoded in ASCII and carefully
+// avoids converting sequences (including "") that the corresponding
+// library call might fail and set errno for.
+static Value *convertStrToInt(CallInst *CI, StringRef &Str, Value *EndPtr,
+ uint64_t Base, bool AsSigned, IRBuilderBase &B) {
if (Base < 2 || Base > 36)
- // handle special zero base
if (Base != 0)
+ // Fail for an invalid base (required by POSIX).
return nullptr;
- char *End;
- std::string nptr = Str.str();
- errno = 0;
- long long int Result = strtoll(nptr.c_str(), &End, Base);
- if (errno)
- return nullptr;
+ // Strip leading whitespace.
+ for (unsigned i = 0; i != Str.size(); ++i)
+ if (!isSpace((unsigned char)Str[i])) {
+ Str = Str.substr(i);
+ break;
+ }
- // if we assume all possible target locales are ASCII supersets,
- // then if strtoll successfully parses a number on the host,
- // it will also successfully parse the same way on the target
- if (*End != '\0')
+ if (Str.empty())
+ // Fail for empty subject sequences (POSIX allows but doesn't require
+ // strtol[l]/strtoul[l] to fail with EINVAL).
return nullptr;
- if (!isIntN(CI->getType()->getPrimitiveSizeInBits(), Result))
- return nullptr;
+ // Strip but remember the sign.
+ bool Negate = Str[0] == '-';
+ if (Str[0] == '-' || Str[0] == '+') {
+ Str = Str.drop_front();
+ if (Str.empty())
+ // Fail for a sign with nothing after it.
+ return nullptr;
+ }
+
+ // Set Max to the absolute value of the minimum (for signed), or
+ // to the maximum (for unsigned) value representable in the type.
+ Type *RetTy = CI->getType();
+ unsigned NBits = RetTy->getPrimitiveSizeInBits();
+ uint64_t Max = AsSigned && Negate ? 1 : 0;
+ Max += AsSigned ? maxIntN(NBits) : maxUIntN(NBits);
+
+ // Autodetect Base if it's zero and consume the "0x" prefix.
+ if (Str.size() > 1) {
+ if (Str[0] == '0') {
+ if (toUpper((unsigned char)Str[1]) == 'X') {
+ if (Str.size() == 2 || (Base && Base != 16))
+ // Fail if Base doesn't allow the "0x" prefix or for the prefix
+ // alone that implementations like BSD set errno to EINVAL for.
+ return nullptr;
+
+ Str = Str.drop_front(2);
+ Base = 16;
+ }
+ else if (Base == 0)
+ Base = 8;
+ } else if (Base == 0)
+ Base = 10;
+ }
+ else if (Base == 0)
+ Base = 10;
+
+ // Convert the rest of the subject sequence, not including the sign,
+ // to its uint64_t representation (this assumes the source character
+ // set is ASCII).
+ uint64_t Result = 0;
+ for (unsigned i = 0; i != Str.size(); ++i) {
+ unsigned char DigVal = Str[i];
+ if (isDigit(DigVal))
+ DigVal = DigVal - '0';
+ else {
+ DigVal = toUpper(DigVal);
+ if (isAlpha(DigVal))
+ DigVal = DigVal - 'A' + 10;
+ else
+ return nullptr;
+ }
+
+ if (DigVal >= Base)
+ // Fail if the digit is not valid in the Base.
+ return nullptr;
+
+ // Add the digit and fail if the result is not representable in
+ // the (unsigned form of the) destination type.
+ bool VFlow;
+ Result = SaturatingMultiplyAdd(Result, Base, (uint64_t)DigVal, &VFlow);
+ if (VFlow || Result > Max)
+ return nullptr;
+ }
if (EndPtr) {
// Store the pointer to the end.
- uint64_t ILen = End - nptr.c_str();
- Value *Off = B.getInt64(ILen);
+ Value *Off = B.getInt64(Str.size());
Value *StrBeg = CI->getArgOperand(0);
Value *StrEnd = B.CreateInBoundsGEP(B.getInt8Ty(), StrBeg, Off, "endptr");
B.CreateStore(StrEnd, EndPtr);
}
- return ConstantInt::get(CI->getType(), Result);
+ if (Negate)
+ // Unsigned negation doesn't overflow.
+ Result = -Result;
+
+ return ConstantInt::get(RetTy, Result);
}
static bool isOnlyUsedInComparisonWithZero(Value *V) {
@@ -2531,27 +2601,35 @@ Value *LibCallSimplifier::optimizeToAscii(CallInst *CI, IRBuilderBase &B) {
ConstantInt::get(CI->getType(), 0x7F));
}
+// Fold calls to atoi, atol, and atoll.
Value *LibCallSimplifier::optimizeAtoi(CallInst *CI, IRBuilderBase &B) {
+ CI->addParamAttr(0, Attribute::NoCapture);
+
StringRef Str;
if (!getConstantStringInfo(CI->getArgOperand(0), Str))
return nullptr;
- return convertStrToNumber(CI, Str, nullptr, 10, B);
+ return convertStrToInt(CI, Str, nullptr, 10, /*AsSigned=*/true, B);
}
-Value *LibCallSimplifier::optimizeStrtol(CallInst *CI, IRBuilderBase &B) {
- StringRef Str;
- if (!getConstantStringInfo(CI->getArgOperand(0), Str))
- return nullptr;
-
+// Fold calls to strtol, strtoll, strtoul, and strtoull.
+Value *LibCallSimplifier::optimizeStrToInt(CallInst *CI, IRBuilderBase &B,
+ bool AsSigned) {
Value *EndPtr = CI->getArgOperand(1);
- if (isa<ConstantPointerNull>(EndPtr))
+ if (isa<ConstantPointerNull>(EndPtr)) {
+ // With a null EndPtr, this function won't capture the main argument.
+ // It would be readonly too, except that it still may write to errno.
+ CI->addParamAttr(0, Attribute::NoCapture);
EndPtr = nullptr;
- else if (!isKnownNonZero(EndPtr, DL))
+ } else if (!isKnownNonZero(EndPtr, DL))
+ return nullptr;
+
+ StringRef Str;
+ if (!getConstantStringInfo(CI->getArgOperand(0), Str))
return nullptr;
if (ConstantInt *CInt = dyn_cast<ConstantInt>(CI->getArgOperand(2))) {
- return convertStrToNumber(CI, Str, EndPtr, CInt->getSExtValue(), B);
+ return convertStrToInt(CI, Str, EndPtr, CInt->getSExtValue(), AsSigned, B);
}
return nullptr;
@@ -3390,7 +3468,10 @@ Value *LibCallSimplifier::optimizeCall(CallInst *CI, IRBuilderBase &Builder) {
return optimizeAtoi(CI, Builder);
case LibFunc_strtol:
case LibFunc_strtoll:
- return optimizeStrtol(CI, Builder);
+ return optimizeStrToInt(CI, Builder, /*AsSigned=*/true);
+ case LibFunc_strtoul:
+ case LibFunc_strtoull:
+ return optimizeStrToInt(CI, Builder, /*AsSigned=*/false);
case LibFunc_printf:
return optimizePrintF(CI, Builder);
case LibFunc_sprintf: