[SimplifyLibcalls] Atoi, strtol replacements
Reviewers: spatel, lebedev.ri, xbolva00, efriedma Reviewed By: xbolva00, efriedma Subscribers: efriedma, llvm-commits Differential Revision: https://reviews.llvm.org/D45418 llvm-svn: 330860
This commit is contained in:
parent
57fcd3454a
commit
cb8ca5f37c
|
@ -151,6 +151,8 @@ private:
|
||||||
Value *optimizeIsDigit(CallInst *CI, IRBuilder<> &B);
|
Value *optimizeIsDigit(CallInst *CI, IRBuilder<> &B);
|
||||||
Value *optimizeIsAscii(CallInst *CI, IRBuilder<> &B);
|
Value *optimizeIsAscii(CallInst *CI, IRBuilder<> &B);
|
||||||
Value *optimizeToAscii(CallInst *CI, IRBuilder<> &B);
|
Value *optimizeToAscii(CallInst *CI, IRBuilder<> &B);
|
||||||
|
Value *optimizeAtoi(CallInst *CI, IRBuilder<> &B);
|
||||||
|
Value *optimizeStrtol(CallInst *CI, IRBuilder<> &B);
|
||||||
|
|
||||||
// Formatting and IO Library Call Optimizations
|
// Formatting and IO Library Call Optimizations
|
||||||
Value *optimizeErrorReporting(CallInst *CI, IRBuilder<> &B,
|
Value *optimizeErrorReporting(CallInst *CI, IRBuilder<> &B,
|
||||||
|
|
|
@ -102,6 +102,31 @@ static bool callHasFloatingPointArgument(const CallInst *CI) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Value *convertStrToNumber(CallInst *CI, StringRef &Str, int64_t Base) {
|
||||||
|
if (Base < 2 || Base > 36)
|
||||||
|
// handle special zero base
|
||||||
|
if (Base != 0)
|
||||||
|
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;
|
||||||
|
|
||||||
|
// 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')
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
if (!isIntN(CI->getType()->getPrimitiveSizeInBits(), Result))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return ConstantInt::get(CI->getType(), Result);
|
||||||
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// String and Memory Library Call Optimizations
|
// String and Memory Library Call Optimizations
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
@ -1663,6 +1688,29 @@ Value *LibCallSimplifier::optimizeToAscii(CallInst *CI, IRBuilder<> &B) {
|
||||||
ConstantInt::get(CI->getType(), 0x7F));
|
ConstantInt::get(CI->getType(), 0x7F));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Value *LibCallSimplifier::optimizeAtoi(CallInst *CI, IRBuilder<> &B) {
|
||||||
|
StringRef Str;
|
||||||
|
if (!getConstantStringInfo(CI->getArgOperand(0), Str))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return convertStrToNumber(CI, Str, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
Value *LibCallSimplifier::optimizeStrtol(CallInst *CI, IRBuilder<> &B) {
|
||||||
|
StringRef Str;
|
||||||
|
if (!getConstantStringInfo(CI->getArgOperand(0), Str))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
if (!isa<ConstantPointerNull>(CI->getArgOperand(1)))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
if (ConstantInt *CInt = dyn_cast<ConstantInt>(CI->getArgOperand(2))) {
|
||||||
|
return convertStrToNumber(CI, Str, CInt->getSExtValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// Formatting and IO Library Call Optimizations
|
// Formatting and IO Library Call Optimizations
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
@ -2259,6 +2307,13 @@ Value *LibCallSimplifier::optimizeCall(CallInst *CI) {
|
||||||
return optimizeIsAscii(CI, Builder);
|
return optimizeIsAscii(CI, Builder);
|
||||||
case LibFunc_toascii:
|
case LibFunc_toascii:
|
||||||
return optimizeToAscii(CI, Builder);
|
return optimizeToAscii(CI, Builder);
|
||||||
|
case LibFunc_atoi:
|
||||||
|
case LibFunc_atol:
|
||||||
|
case LibFunc_atoll:
|
||||||
|
return optimizeAtoi(CI, Builder);
|
||||||
|
case LibFunc_strtol:
|
||||||
|
case LibFunc_strtoll:
|
||||||
|
return optimizeStrtol(CI, Builder);
|
||||||
case LibFunc_printf:
|
case LibFunc_printf:
|
||||||
return optimizePrintF(CI, Builder);
|
return optimizePrintF(CI, Builder);
|
||||||
case LibFunc_sprintf:
|
case LibFunc_sprintf:
|
||||||
|
|
|
@ -0,0 +1,131 @@
|
||||||
|
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
||||||
|
; RUN: opt < %s -instcombine -S | FileCheck %s
|
||||||
|
|
||||||
|
@.str = private unnamed_addr constant [3 x i8] c"12\00", align 1
|
||||||
|
@.str.1 = private unnamed_addr constant [2 x i8] c"0\00", align 1
|
||||||
|
@.str.2 = private unnamed_addr constant [11 x i8] c"4294967296\00", align 1
|
||||||
|
@.str.3 = private unnamed_addr constant [24 x i8] c"10000000000000000000000\00", align 1
|
||||||
|
@.str.4 = private unnamed_addr constant [20 x i8] c"9923372036854775807\00", align 1
|
||||||
|
@.str.5 = private unnamed_addr constant [11 x i8] c"4994967295\00", align 1
|
||||||
|
@.str.6 = private unnamed_addr constant [10 x i8] c"499496729\00", align 1
|
||||||
|
@.str.7 = private unnamed_addr constant [11 x i8] c"4994967295\00", align 1
|
||||||
|
|
||||||
|
declare i64 @strtol(i8*, i8**, i32)
|
||||||
|
declare i32 @atoi(i8*)
|
||||||
|
declare i64 @atol(i8*)
|
||||||
|
declare i64 @atoll(i8*)
|
||||||
|
declare i64 @strtoll(i8*, i8**, i32)
|
||||||
|
|
||||||
|
define i64 @strtol_dec() #0 {
|
||||||
|
; CHECK-LABEL: @strtol_dec(
|
||||||
|
; CHECK-NEXT: ret i64 12
|
||||||
|
;
|
||||||
|
%call = call i64 @strtol(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str, i32 0, i32 0), i8** null, i32 10) #2
|
||||||
|
ret i64 %call
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @strtol_base_zero() #0 {
|
||||||
|
; CHECK-LABEL: @strtol_base_zero(
|
||||||
|
; CHECK-NEXT: ret i64 12
|
||||||
|
;
|
||||||
|
%call = call i64 @strtol(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str, i32 0, i32 0), i8** null, i32 0) #2
|
||||||
|
ret i64 %call
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @strtol_hex() #0 {
|
||||||
|
; CHECK-LABEL: @strtol_hex(
|
||||||
|
; CHECK-NEXT: ret i64 18
|
||||||
|
;
|
||||||
|
%call = call i64 @strtol(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str, i32 0, i32 0), i8** null, i32 16) #2
|
||||||
|
ret i64 %call
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @strtol_endptr_not_null() #0 {
|
||||||
|
; CHECK-LABEL: @strtol_endptr_not_null(
|
||||||
|
; CHECK-NEXT: [[END:%.*]] = alloca i8*, align 4
|
||||||
|
; CHECK-NEXT: [[CALL:%.*]] = call i64 @strtol(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0), i8** nonnull [[END]], i32 10)
|
||||||
|
; CHECK-NEXT: ret i64 [[CALL]]
|
||||||
|
;
|
||||||
|
%end = alloca i8*, align 4
|
||||||
|
%call = call i64 @strtol(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i32 0, i32 0), i8** %end, i32 10) #2
|
||||||
|
ret i64 %call
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32 @atoi_test() #0 {
|
||||||
|
; CHECK-LABEL: @atoi_test(
|
||||||
|
; CHECK-NEXT: ret i32 12
|
||||||
|
;
|
||||||
|
%call = call i32 @atoi(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str, i32 0, i32 0)) #4
|
||||||
|
ret i32 %call
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @strtol_not_const_str(i8* %s) #0 {
|
||||||
|
; CHECK-LABEL: @strtol_not_const_str(
|
||||||
|
; CHECK-NEXT: [[CALL:%.*]] = call i64 @strtol(i8* nocapture [[S:%.*]], i8** null, i32 10)
|
||||||
|
; CHECK-NEXT: ret i64 [[CALL]]
|
||||||
|
;
|
||||||
|
%call = call i64 @strtol(i8* %s, i8** null, i32 10) #3
|
||||||
|
ret i64 %call
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32 @atoi_not_const_str(i8* %s) #0 {
|
||||||
|
; CHECK-LABEL: @atoi_not_const_str(
|
||||||
|
; CHECK-NEXT: [[CALL:%.*]] = call i32 @atoi(i8* [[S:%.*]])
|
||||||
|
; CHECK-NEXT: ret i32 [[CALL]]
|
||||||
|
;
|
||||||
|
%call = call i32 @atoi(i8* %s) #4
|
||||||
|
ret i32 %call
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @strtol_not_const_base(i32 %b) #0 {
|
||||||
|
; CHECK-LABEL: @strtol_not_const_base(
|
||||||
|
; CHECK-NEXT: [[CALL:%.*]] = call i64 @strtol(i8* nocapture getelementptr inbounds ([3 x i8], [3 x i8]* @.str, i64 0, i64 0), i8** null, i32 [[B:%.*]])
|
||||||
|
; CHECK-NEXT: ret i64 [[CALL]]
|
||||||
|
;
|
||||||
|
%call = call i64 @strtol(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str, i32 0, i32 0), i8** null, i32 %b) #2
|
||||||
|
ret i64 %call
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @strtol_long_int() #0 {
|
||||||
|
; CHECK-LABEL: @strtol_long_int(
|
||||||
|
; CHECK-NEXT: ret i64 4294967296
|
||||||
|
;
|
||||||
|
%call = call i64 @strtol(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.2, i32 0, i32 0), i8** null, i32 10) #3
|
||||||
|
ret i64 %call
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
define i64 @strtol_big_overflow() #0 {
|
||||||
|
; CHECK-LABEL: @strtol_big_overflow(
|
||||||
|
; CHECK-NEXT: [[CALL:%.*]] = call i64 @strtol(i8* nocapture getelementptr inbounds ([24 x i8], [24 x i8]* @.str.3, i64 0, i64 0), i8** null, i32 10)
|
||||||
|
; CHECK-NEXT: ret i64 [[CALL]]
|
||||||
|
;
|
||||||
|
%call = call i64 @strtol(i8* nocapture getelementptr inbounds ([24 x i8], [24 x i8]* @.str.3, i64 0, i64 0), i8** null, i32 10) #2
|
||||||
|
ret i64 %call
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @atol_test() #0 {
|
||||||
|
; CHECK-LABEL: @atol_test(
|
||||||
|
; CHECK-NEXT: ret i64 499496729
|
||||||
|
;
|
||||||
|
; CHECK-NEXT
|
||||||
|
%call = call i64 @atol(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.6, i32 0, i32 0)) #4
|
||||||
|
ret i64 %call
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @atoll_test() #0 {
|
||||||
|
; CHECK-LABEL: @atoll_test(
|
||||||
|
; CHECK-NEXT: ret i64 4994967295
|
||||||
|
;
|
||||||
|
%call = call i64 @atoll(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.5, i32 0, i32 0)) #3
|
||||||
|
ret i64 %call
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @strtoll_test() #0 {
|
||||||
|
; CHECK-LABEL: @strtoll_test(
|
||||||
|
; CHECK-NEXT: ret i64 4994967295
|
||||||
|
;
|
||||||
|
; CHECK-NEXT
|
||||||
|
%call = call i64 @strtoll(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.7, i32 0, i32 0), i8** null, i32 10) #5
|
||||||
|
ret i64 %call
|
||||||
|
}
|
|
@ -0,0 +1,134 @@
|
||||||
|
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
||||||
|
; RUN: opt < %s -instcombine -S | FileCheck %s
|
||||||
|
|
||||||
|
@.str = private unnamed_addr constant [3 x i8] c"12\00", align 1
|
||||||
|
@.str.1 = private unnamed_addr constant [2 x i8] c"0\00", align 1
|
||||||
|
@.str.2 = private unnamed_addr constant [11 x i8] c"4294967296\00", align 1
|
||||||
|
@.str.3 = private unnamed_addr constant [24 x i8] c"10000000000000000000000\00", align 1
|
||||||
|
@.str.4 = private unnamed_addr constant [20 x i8] c"9923372036854775807\00", align 1
|
||||||
|
@.str.5 = private unnamed_addr constant [11 x i8] c"4994967295\00", align 1
|
||||||
|
@.str.6 = private unnamed_addr constant [10 x i8] c"499496729\00", align 1
|
||||||
|
@.str.7 = private unnamed_addr constant [11 x i8] c"4994967295\00", align 1
|
||||||
|
|
||||||
|
declare i32 @strtol(i8*, i8**, i32)
|
||||||
|
declare i32 @atoi(i8*)
|
||||||
|
declare i32 @atol(i8*)
|
||||||
|
declare i32 @atoll(i8*)
|
||||||
|
declare i32 @strtoll(i8*, i8**, i32)
|
||||||
|
|
||||||
|
define i32 @strtol_dec() #0 {
|
||||||
|
; CHECK-LABEL: @strtol_dec(
|
||||||
|
; CHECK-NEXT: ret i32 12
|
||||||
|
;
|
||||||
|
%call = call i32 @strtol(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str, i32 0, i32 0), i8** null, i32 10) #2
|
||||||
|
ret i32 %call
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32 @strtol_base_zero() #0 {
|
||||||
|
; CHECK-LABEL: @strtol_base_zero(
|
||||||
|
; CHECK-NEXT: ret i32 12
|
||||||
|
;
|
||||||
|
%call = call i32 @strtol(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str, i32 0, i32 0), i8** null, i32 0) #2
|
||||||
|
ret i32 %call
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32 @strtol_hex() #0 {
|
||||||
|
; CHECK-LABEL: @strtol_hex(
|
||||||
|
; CHECK-NEXT: ret i32 18
|
||||||
|
;
|
||||||
|
%call = call i32 @strtol(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str, i32 0, i32 0), i8** null, i32 16) #2
|
||||||
|
ret i32 %call
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32 @strtol_endptr_not_null() #0 {
|
||||||
|
; CHECK-LABEL: @strtol_endptr_not_null(
|
||||||
|
; CHECK-NEXT: [[END:%.*]] = alloca i8*, align 4
|
||||||
|
; CHECK-NEXT: [[CALL:%.*]] = call i32 @strtol(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0), i8** nonnull [[END]], i32 10)
|
||||||
|
; CHECK-NEXT: ret i32 [[CALL]]
|
||||||
|
;
|
||||||
|
%end = alloca i8*, align 4
|
||||||
|
%call = call i32 @strtol(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i32 0, i32 0), i8** %end, i32 10) #2
|
||||||
|
ret i32 %call
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32 @atoi_test() #0 {
|
||||||
|
; CHECK-LABEL: @atoi_test(
|
||||||
|
; CHECK-NEXT: ret i32 12
|
||||||
|
;
|
||||||
|
%call = call i32 @atoi(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str, i32 0, i32 0)) #4
|
||||||
|
ret i32 %call
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32 @strtol_not_const_str(i8* %s) #0 {
|
||||||
|
; CHECK-LABEL: @strtol_not_const_str(
|
||||||
|
; CHECK-NEXT: [[CALL:%.*]] = call i32 @strtol(i8* nocapture [[S:%.*]], i8** null, i32 10)
|
||||||
|
; CHECK-NEXT: ret i32 [[CALL]]
|
||||||
|
;
|
||||||
|
%call = call i32 @strtol(i8* %s, i8** null, i32 10) #3
|
||||||
|
ret i32 %call
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32 @atoi_not_const_str(i8* %s) #0 {
|
||||||
|
; CHECK-LABEL: @atoi_not_const_str(
|
||||||
|
; CHECK-NEXT: [[CALL:%.*]] = call i32 @atoi(i8* [[S:%.*]])
|
||||||
|
; CHECK-NEXT: ret i32 [[CALL]]
|
||||||
|
;
|
||||||
|
%call = call i32 @atoi(i8* %s) #4
|
||||||
|
ret i32 %call
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32 @strtol_not_const_base(i32 %b) #0 {
|
||||||
|
; CHECK-LABEL: @strtol_not_const_base(
|
||||||
|
; CHECK-NEXT: [[CALL:%.*]] = call i32 @strtol(i8* nocapture getelementptr inbounds ([3 x i8], [3 x i8]* @.str, i64 0, i64 0), i8** null, i32 [[B:%.*]])
|
||||||
|
; CHECK-NEXT: ret i32 [[CALL]]
|
||||||
|
;
|
||||||
|
%call = call i32 @strtol(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str, i32 0, i32 0), i8** null, i32 %b) #2
|
||||||
|
ret i32 %call
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32 @strtol_long_int() #0 {
|
||||||
|
; CHECK-LABEL: @strtol_long_int(
|
||||||
|
; CHECK-NEXT: [[CALL:%.*]] = call i32 @strtol(i8* nocapture getelementptr inbounds ([11 x i8], [11 x i8]* @.str.2, i64 0, i64 0), i8** null, i32 10)
|
||||||
|
; CHECK-NEXT: ret i32 [[CALL]]
|
||||||
|
;
|
||||||
|
%call = call i32 @strtol(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.2, i32 0, i32 0), i8** null, i32 10) #3
|
||||||
|
ret i32 %call
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
define i32 @strtol_big_overflow() #0 {
|
||||||
|
; CHECK-LABEL: @strtol_big_overflow(
|
||||||
|
; CHECK-NEXT: [[CALL:%.*]] = call i32 @strtol(i8* nocapture getelementptr inbounds ([24 x i8], [24 x i8]* @.str.3, i64 0, i64 0), i8** null, i32 10)
|
||||||
|
; CHECK-NEXT: ret i32 [[CALL]]
|
||||||
|
;
|
||||||
|
%call = call i32 @strtol(i8* nocapture getelementptr inbounds ([24 x i8], [24 x i8]* @.str.3, i32 0, i32 0), i8** null, i32 10) #2
|
||||||
|
ret i32 %call
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32 @atol_test() #0 {
|
||||||
|
; CHECK-LABEL: @atol_test(
|
||||||
|
; CHECK-NEXT: ret i32 499496729
|
||||||
|
;
|
||||||
|
; CHECK-NEXT
|
||||||
|
%call = call i32 @atol(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.6, i32 0, i32 0)) #4
|
||||||
|
ret i32 %call
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32 @atoll_test() #0 {
|
||||||
|
; CHECK-LABEL: @atoll_test(
|
||||||
|
; CHECK-NEXT: [[CALL:%.*]] = call i32 @atoll(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.5, i64 0, i64 0))
|
||||||
|
; CHECK-NEXT: ret i32 [[CALL]]
|
||||||
|
;
|
||||||
|
%call = call i32 @atoll(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.5, i32 0, i32 0)) #3
|
||||||
|
ret i32 %call
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32 @strtoll_test() #0 {
|
||||||
|
; CHECK-LABEL: @strtoll_test(
|
||||||
|
; CHECK-NEXT: [[CALL:%.*]] = call i32 @strtoll(i8* nocapture getelementptr inbounds ([11 x i8], [11 x i8]* @.str.7, i64 0, i64 0), i8** null, i32 10)
|
||||||
|
; CHECK-NEXT: ret i32 [[CALL]]
|
||||||
|
;
|
||||||
|
; CHECK-NEXT
|
||||||
|
%call = call i32 @strtoll(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.7, i32 0, i32 0), i8** null, i32 10) #5
|
||||||
|
ret i32 %call
|
||||||
|
}
|
Loading…
Reference in New Issue