421 changes: 421 additions & 0 deletions llvm/test/Transforms/InstCombine/str-int-4.ll

Large diffs are not rendered by default.

331 changes: 331 additions & 0 deletions llvm/test/Transforms/InstCombine/str-int-5.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,331 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; Verify that calls to strtoul and strtoull are interpreted correctly even
; in corner cases (or not folded).
;
; RUN: opt < %s -passes=instcombine -S | FileCheck %s

declare i32 @strtoul(i8*, i8**, i32)
declare i64 @strtoull(i8*, i8**, i32)


; All POSIX whitespace characters.
@ws = constant [7 x i8] c"\09\0d\0a\0b\0c \00"

; A negative and positive number preceded by all POSIX whitespace.
@ws_im123 = constant [11 x i8] c"\09\0d\0a\0b\0c -123\00"
@ws_ip234 = constant [11 x i8] c"\09\0d\0a\0b\0c +234\00"

@i32min = constant [13 x i8] c" -2147483648\00"
@i32min_m1 = constant [13 x i8] c" -2147483649\00"
@o32min = constant [15 x i8] c" +020000000000\00"
@mo32min = constant [15 x i8] c" -020000000000\00"
@x32min = constant [13 x i8] c" +0x80000000\00"
@mx32min = constant [13 x i8] c" +0x80000000\00"

@i32max = constant [12 x i8] c" 2147483647\00"
@i32max_p1 = constant [12 x i8] c" 2147483648\00"
@mX01 = constant [6 x i8] c" -0X1\00"

@ui32max = constant [12 x i8] c" 4294967295\00"
@ui32max_p1 = constant [12 x i8] c" 4294967296\00"

@i64min = constant [22 x i8] c" -9223372036854775808\00"
@i64min_m1 = constant [22 x i8] c" -9223372036854775809\00"

@i64max = constant [21 x i8] c" 9223372036854775807\00"
@i64max_p1 = constant [21 x i8] c" 9223372036854775808\00"

@ui64max = constant [22 x i8] c" 18446744073709551615\00"
@x64max = constant [20 x i8] c" 0xffffffffffffffff\00"
@ui64max_p1 = constant [22 x i8] c" 18446744073709551616\00"


; Exercise folding calls to 32-bit strtoul.

define void @fold_strtoul(i32* %ps) {
; CHECK-LABEL: @fold_strtoul(
; CHECK-NEXT: store i32 -123, i32* [[PS:%.*]], align 4
; CHECK-NEXT: [[PS1:%.*]] = getelementptr i32, i32* [[PS]], i64 1
; CHECK-NEXT: store i32 234, i32* [[PS1]], align 4
; CHECK-NEXT: [[PS2:%.*]] = getelementptr i32, i32* [[PS]], i64 2
; CHECK-NEXT: store i32 2147483647, i32* [[PS2]], align 4
; CHECK-NEXT: [[PS3:%.*]] = getelementptr i32, i32* [[PS]], i64 3
; CHECK-NEXT: store i32 -2147483648, i32* [[PS3]], align 4
; CHECK-NEXT: [[PS4:%.*]] = getelementptr i32, i32* [[PS]], i64 4
; CHECK-NEXT: store i32 -2147483648, i32* [[PS4]], align 4
; CHECK-NEXT: [[PS5:%.*]] = getelementptr i32, i32* [[PS]], i64 5
; CHECK-NEXT: store i32 -2147483648, i32* [[PS5]], align 4
; CHECK-NEXT: [[PS6:%.*]] = getelementptr i32, i32* [[PS]], i64 6
; CHECK-NEXT: store i32 -2147483648, i32* [[PS6]], align 4
; CHECK-NEXT: [[PS7:%.*]] = getelementptr i32, i32* [[PS]], i64 7
; CHECK-NEXT: store i32 -2147483648, i32* [[PS7]], align 4
; CHECK-NEXT: [[PS8:%.*]] = getelementptr i32, i32* [[PS]], i64 8
; CHECK-NEXT: store i32 2147483647, i32* [[PS8]], align 4
; CHECK-NEXT: [[PS9:%.*]] = getelementptr i32, i32* [[PS]], i64 9
; CHECK-NEXT: store i32 -1, i32* [[PS9]], align 4
; CHECK-NEXT: [[PS10:%.*]] = getelementptr i32, i32* [[PS]], i64 10
; CHECK-NEXT: store i32 -2147483648, i32* [[PS10]], align 4
; CHECK-NEXT: [[PS11:%.*]] = getelementptr i32, i32* [[PS]], i64 11
; CHECK-NEXT: store i32 -1, i32* [[PS11]], align 4
; CHECK-NEXT: ret void
;
; Fold a valid sequence with leading POSIX whitespace and a minus to
; (uint32_t)-123.
%pwsm123 = getelementptr [11 x i8], [11 x i8]* @ws_im123, i32 0, i32 0
%im123 = call i32 @strtoul(i8* %pwsm123, i8** null, i32 10)
%ps0 = getelementptr i32, i32* %ps, i32 0
store i32 %im123, i32* %ps0

; Fold a valid sequence with leading POSIX whitespace and a plus to +234.
%pwsp234 = getelementptr [11 x i8], [11 x i8]* @ws_ip234, i32 0, i32 0
%ip234 = call i32 @strtoul(i8* %pwsp234, i8** null, i32 10)
%ps1 = getelementptr i32, i32* %ps, i32 1
store i32 %ip234, i32* %ps1

; Fold the result of conversion that's equal to INT32_MIN - 1.
%psi32minm1 = getelementptr [13 x i8], [13 x i8]* @i32min_m1, i32 0, i32 0
%i32min32m1 = call i32 @strtoul(i8* %psi32minm1, i8** null, i32 10)
%ps2 = getelementptr i32, i32* %ps, i32 2
store i32 %i32min32m1, i32* %ps2

; Fold INT32_MIN.
%psi32min = getelementptr [13 x i8], [13 x i8]* @i32min, i32 0, i32 0
%i32min = call i32 @strtoul(i8* %psi32min, i8** null, i32 10)
%ps3 = getelementptr i32, i32* %ps, i32 3
store i32 %i32min, i32* %ps3

; Fold INT32_MIN in octal.
%pso32min = getelementptr [15 x i8], [15 x i8]* @o32min, i32 0, i32 0
%o32min = call i32 @strtoul(i8* %pso32min, i8** null, i32 0)
%ps4 = getelementptr i32, i32* %ps, i32 4
store i32 %o32min, i32* %ps4

; Fold -INT32_MIN in octal.
%psmo32min = getelementptr [15 x i8], [15 x i8]* @mo32min, i32 0, i32 0
%mo32min = call i32 @strtoul(i8* %psmo32min, i8** null, i32 0)
%ps5 = getelementptr i32, i32* %ps, i32 5
store i32 %mo32min, i32* %ps5

; Fold INT32_MIN in hex.
%psx32min = getelementptr [13 x i8], [13 x i8]* @x32min, i32 0, i32 0
%x32min = call i32 @strtoul(i8* %psx32min, i8** null, i32 0)
%ps6 = getelementptr i32, i32* %ps, i32 6
store i32 %x32min, i32* %ps6

; Fold -INT32_MIN in hex.
%psmx32min = getelementptr [13 x i8], [13 x i8]* @mx32min, i32 0, i32 0
%mx32min = call i32 @strtoul(i8* %psmx32min, i8** null, i32 0)
%ps7 = getelementptr i32, i32* %ps, i32 7
store i32 %x32min, i32* %ps7

; Fold INT32_MAX.
%psi32max = getelementptr [12 x i8], [12 x i8]* @i32max, i32 0, i32 0
%i32max = call i32 @strtoul(i8* %psi32max, i8** null, i32 10)
%ps8 = getelementptr i32, i32* %ps, i32 8
store i32 %i32max, i32* %ps8

; Fold -0x01.
%psmX01 = getelementptr [6 x i8], [6 x i8]* @mX01, i32 0, i32 0
%mX01 = call i32 @strtoul(i8* %psmX01, i8** null, i32 0)
%ps9 = getelementptr i32, i32* %ps, i32 9
store i32 %mX01, i32* %ps9

; Fold the result of conversion that's equal to INT32_MAX + 1.
%psmax32p1 = getelementptr [12 x i8], [12 x i8]* @i32max_p1, i32 0, i32 0
%i32max32p1 = call i32 @strtoul(i8* %psmax32p1, i8** null, i32 10)
%ps10 = getelementptr i32, i32* %ps, i32 10
store i32 %i32max32p1, i32* %ps10

; Fold UINT32_MAX.
%psmax = getelementptr [12 x i8], [12 x i8]* @ui32max, i32 0, i32 0
%ui32max = call i32 @strtoul(i8* %psmax, i8** null, i32 10)
%ps11 = getelementptr i32, i32* %ps, i32 11
store i32 %ui32max, i32* %ps11

ret void
}


; Exercise not folding calls to 32-bit strtoul.

define void @call_strtoul(i32* %ps) {
; CHECK-LABEL: @call_strtoul(
; CHECK-NEXT: [[MINM1:%.*]] = call i32 @strtoul(i8* nocapture getelementptr inbounds ([22 x i8], [22 x i8]* @i64min_m1, i64 0, i64 0), i8** null, i32 10)
; CHECK-NEXT: store i32 [[MINM1]], i32* [[PS:%.*]], align 4
; CHECK-NEXT: [[MAXP1:%.*]] = call i32 @strtoul(i8* nocapture getelementptr inbounds ([12 x i8], [12 x i8]* @ui32max_p1, i64 0, i64 0), i8** null, i32 10)
; CHECK-NEXT: [[PS1:%.*]] = getelementptr i32, i32* [[PS]], i64 1
; CHECK-NEXT: store i32 [[MAXP1]], i32* [[PS1]], align 4
; CHECK-NEXT: [[NWS:%.*]] = call i32 @strtoul(i8* nocapture getelementptr inbounds ([7 x i8], [7 x i8]* @ws, i64 0, i64 0), i8** null, i32 10)
; CHECK-NEXT: [[PS2:%.*]] = getelementptr i32, i32* [[PS]], i64 2
; CHECK-NEXT: store i32 [[NWS]], i32* [[PS2]], align 4
; CHECK-NEXT: [[NWSP6:%.*]] = call i32 @strtoul(i8* nocapture getelementptr inbounds ([7 x i8], [7 x i8]* @ws, i64 0, i64 6), i8** null, i32 10)
; CHECK-NEXT: [[PS3:%.*]] = getelementptr i32, i32* [[PS]], i64 3
; CHECK-NEXT: store i32 [[NWSP6]], i32* [[PS3]], align 4
; CHECK-NEXT: ret void
;
; Do not fold the result of conversion that overflows uint32_t. This
; could be folded into a constant provided errnor were set to ERANGE.
%psminm1 = getelementptr [22 x i8], [22 x i8]* @i64min_m1, i32 0, i32 0
%minm1 = call i32 @strtoul(i8* %psminm1, i8** null, i32 10)
%ps0 = getelementptr i32, i32* %ps, i32 0
store i32 %minm1, i32* %ps0

; Do not fold the result of conversion that's greater than UINT32_MAX
; (same logic as above applies here).
%psui32maxp1 = getelementptr [12 x i8], [12 x i8]* @ui32max_p1, i32 0, i32 0
%maxp1 = call i32 @strtoul(i8* %psui32maxp1, i8** null, i32 10)
%ps1 = getelementptr i32, i32* %ps, i32 1
store i32 %maxp1, i32* %ps1

; Do not fold a sequence consisting of just whitespace characters.
%psws = getelementptr [7 x i8], [7 x i8]* @ws, i32 0, i32 0
%nws = call i32 @strtoul(i8* %psws, i8** null, i32 10)
%ps2 = getelementptr i32, i32* %ps, i32 2
store i32 %nws, i32* %ps2

; Do not fold an empty sequence. The library call may or may not end up
; storing EINVAL in errno.
%pswsp6 = getelementptr [7 x i8], [7 x i8]* @ws, i32 0, i32 6
%nwsp6 = call i32 @strtoul(i8* %pswsp6, i8** null, i32 10)
%ps3 = getelementptr i32, i32* %ps, i32 3
store i32 %nwsp6, i32* %ps3

ret void
}


; Exercise folding calls to 64-bit strtoull.

define void @fold_strtoull(i64* %ps) {
; CHECK-LABEL: @fold_strtoull(
; CHECK-NEXT: store i64 -123, i64* [[PS:%.*]], align 4
; CHECK-NEXT: [[PS1:%.*]] = getelementptr i64, i64* [[PS]], i64 1
; CHECK-NEXT: store i64 234, i64* [[PS1]], align 4
; CHECK-NEXT: [[PS2:%.*]] = getelementptr i64, i64* [[PS]], i64 2
; CHECK-NEXT: store i64 9223372036854775807, i64* [[PS2]], align 4
; CHECK-NEXT: [[PS3:%.*]] = getelementptr i64, i64* [[PS]], i64 3
; CHECK-NEXT: store i64 -2147483648, i64* [[PS3]], align 4
; CHECK-NEXT: [[PS4:%.*]] = getelementptr i64, i64* [[PS]], i64 4
; CHECK-NEXT: store i64 2147483648, i64* [[PS4]], align 4
; CHECK-NEXT: [[PS5:%.*]] = getelementptr i64, i64* [[PS]], i64 5
; CHECK-NEXT: store i64 2147483648, i64* [[PS5]], align 4
; CHECK-NEXT: [[PS6:%.*]] = getelementptr i64, i64* [[PS]], i64 6
; CHECK-NEXT: store i64 -9223372036854775808, i64* [[PS6]], align 4
; CHECK-NEXT: [[PS7:%.*]] = getelementptr i64, i64* [[PS]], i64 7
; CHECK-NEXT: store i64 9223372036854775807, i64* [[PS7]], align 4
; CHECK-NEXT: [[PS8:%.*]] = getelementptr i64, i64* [[PS]], i64 8
; CHECK-NEXT: store i64 -9223372036854775808, i64* [[PS8]], align 4
; CHECK-NEXT: [[PS9:%.*]] = getelementptr i64, i64* [[PS]], i64 9
; CHECK-NEXT: store i64 -1, i64* [[PS9]], align 4
; CHECK-NEXT: [[PS10:%.*]] = getelementptr i64, i64* [[PS]], i64 10
; CHECK-NEXT: store i64 -1, i64* [[PS10]], align 4
; CHECK-NEXT: ret void
;
; Fold a valid sequence with leading POSIX whitespace and a minus to
; (uint64_t)-123.
%pwsm123 = getelementptr [11 x i8], [11 x i8]* @ws_im123, i32 0, i32 0
%im123 = call i64 @strtoull(i8* %pwsm123, i8** null, i32 10)
%ps0 = getelementptr i64, i64* %ps, i32 0
store i64 %im123, i64* %ps0

; Fold a valid sequence with leading POSIX whitespace and a plus to +234.
%pwsp234 = getelementptr [11 x i8], [11 x i8]* @ws_ip234, i32 0, i32 0
%ip234 = call i64 @strtoull(i8* %pwsp234, i8** null, i32 10)
%ps1 = getelementptr i64, i64* %ps, i32 1
store i64 %ip234, i64* %ps1

; Fold the result of conversion that's equal to INT64_MIN - 1.
%psi64minm1 = getelementptr [22 x i8], [22 x i8]* @i64min_m1, i32 0, i32 0
%i64min32m1 = call i64 @strtoull(i8* %psi64minm1, i8** null, i32 10)
%ps2 = getelementptr i64, i64* %ps, i32 2
store i64 %i64min32m1, i64* %ps2

; Fold INT32_MIN.
%psi32min = getelementptr [13 x i8], [13 x i8]* @i32min, i32 0, i32 0
%i32min = call i64 @strtoull(i8* %psi32min, i8** null, i32 10)
%ps3 = getelementptr i64, i64* %ps, i32 3
store i64 %i32min, i64* %ps3

; Fold INT32_MIN in octal.
%pso32min = getelementptr [15 x i8], [15 x i8]* @o32min, i32 0, i32 0
%o32min = call i64 @strtoull(i8* %pso32min, i8** null, i32 0)
%ps4 = getelementptr i64, i64* %ps, i32 4
store i64 %o32min, i64* %ps4

; Fold INT32_MIN in hex.
%psx32min = getelementptr [13 x i8], [13 x i8]* @x32min, i32 0, i32 0
%x32min = call i64 @strtoull(i8* %psx32min, i8** null, i32 0)
%ps5 = getelementptr i64, i64* %ps, i32 5
store i64 %x32min, i64* %ps5

; Fold INT64_MIN.
%psi64min = getelementptr [22 x i8], [22 x i8]* @i64min, i32 0, i32 0
%i64min = call i64 @strtoull(i8* %psi64min, i8** null, i32 10)
%ps6 = getelementptr i64, i64* %ps, i32 6
store i64 %i64min, i64* %ps6

; Fold INT64_MAX.
%psi64max = getelementptr [21 x i8], [21 x i8]* @i64max, i32 0, i32 0
%i64max = call i64 @strtoull(i8* %psi64max, i8** null, i32 10)
%ps7 = getelementptr i64, i64* %ps, i32 7
store i64 %i64max, i64* %ps7

; Fold the result of conversion that's equal to INT64_MAX + 1 to INT64_MIN.
%psmax32p1 = getelementptr [21 x i8], [21 x i8]* @i64max_p1, i32 0, i32 0
%i64max32p1 = call i64 @strtoull(i8* %psmax32p1, i8** null, i32 10)
%ps8 = getelementptr i64, i64* %ps, i32 8
store i64 %i64max32p1, i64* %ps8

; Fold UINT64_MAX.
%psmax = getelementptr [22 x i8], [22 x i8]* @ui64max, i32 0, i32 0
%ui64max = call i64 @strtoull(i8* %psmax, i8** null, i32 10)
%ps9 = getelementptr i64, i64* %ps, i32 9
store i64 %ui64max, i64* %ps9

; Fold UINT64_MAX in hex.
%psxmax = getelementptr [20 x i8], [20 x i8]* @x64max, i32 0, i32 0
%x64max = call i64 @strtoull(i8* %psxmax, i8** null, i32 0)
%ps10 = getelementptr i64, i64* %ps, i32 10
store i64 %x64max, i64* %ps10

ret void
}


; Exercise not folding calls to 64-bit strtoull.

define void @call_strtoull(i64* %ps) {
; CHECK-LABEL: @call_strtoull(
; CHECK-NEXT: [[MAXP1:%.*]] = call i64 @strtoull(i8* nocapture getelementptr inbounds ([22 x i8], [22 x i8]* @ui64max_p1, i64 0, i64 0), i8** null, i32 10)
; CHECK-NEXT: [[PS1:%.*]] = getelementptr i64, i64* [[PS:%.*]], i64 1
; CHECK-NEXT: store i64 [[MAXP1]], i64* [[PS1]], align 4
; CHECK-NEXT: [[NWS:%.*]] = call i64 @strtoull(i8* nocapture getelementptr inbounds ([7 x i8], [7 x i8]* @ws, i64 0, i64 0), i8** null, i32 10)
; CHECK-NEXT: [[PS2:%.*]] = getelementptr i64, i64* [[PS]], i64 2
; CHECK-NEXT: store i64 [[NWS]], i64* [[PS2]], align 4
; CHECK-NEXT: [[NWSP6:%.*]] = call i64 @strtoull(i8* nocapture getelementptr inbounds ([7 x i8], [7 x i8]* @ws, i64 0, i64 6), i8** null, i32 10)
; CHECK-NEXT: [[PS3:%.*]] = getelementptr i64, i64* [[PS]], i64 3
; CHECK-NEXT: store i64 [[NWSP6]], i64* [[PS3]], align 4
; CHECK-NEXT: ret void
;
; Do not fold the result of conversion that overflows uint64_t. This
; could be folded into a constant provided errnor were set to ERANGE.
%psui64maxp1 = getelementptr [22 x i8], [22 x i8]* @ui64max_p1, i32 0, i32 0
%maxp1 = call i64 @strtoull(i8* %psui64maxp1, i8** null, i32 10)
%ps1 = getelementptr i64, i64* %ps, i32 1
store i64 %maxp1, i64* %ps1

; Do not fold a sequence consisting of just whitespace characters.
%psws = getelementptr [7 x i8], [7 x i8]* @ws, i32 0, i32 0
%nws = call i64 @strtoull(i8* %psws, i8** null, i32 10)
%ps2 = getelementptr i64, i64* %ps, i32 2
store i64 %nws, i64* %ps2

; Do not fold an empty sequence. The library call may or may not end up
; storing EINVAL in errno.
%pswsp6 = getelementptr [7 x i8], [7 x i8]* @ws, i32 0, i32 6
%nwsp6 = call i64 @strtoull(i8* %pswsp6, i8** null, i32 10)
%ps3 = getelementptr i64, i64* %ps, i32 3
store i64 %nwsp6, i64* %ps3

ret void
}
4 changes: 2 additions & 2 deletions llvm/test/Transforms/InstCombine/str-int.ll
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ define i32 @strtol_not_const_str(i8* %s) #0 {

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: [[CALL:%.*]] = call i32 @atoi(i8* nocapture [[S:%.*]])
; CHECK-NEXT: ret i32 [[CALL]]
;
%call = call i32 @atoi(i8* %s) #4
Expand Down Expand Up @@ -130,7 +130,7 @@ define i32 @atol_test() #0 {

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: [[CALL:%.*]] = call i32 @atoll(i8* nocapture 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
Expand Down
76 changes: 76 additions & 0 deletions llvm/test/Transforms/InstCombine/strcall-no-nul.ll
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ declare i8* @strpbrk(i8*, i8*)
declare i64 @strspn(i8*, i8*)
declare i64 @strcspn(i8*, i8*)

declare i32 @atoi(i8*)
declare i64 @atol(i8*)
declare i64 @atoll(i8*)
declare i64 @strtol(i8*, i8**, i32)
declare i64 @strtoll(i8*, i8**, i32)
declare i64 @strtoul(i8*, i8**, i32)
declare i64 @strtoull(i8*, i8**, i32)

declare i32 @sprintf(i8*, i8*, ...)
declare i32 @snprintf(i8*, i64, i8*, ...)

Expand Down Expand Up @@ -267,6 +275,74 @@ define void @fold_strcspn_past_end(i64* %poff) {
}


; TODO: Fold the 32-bit atoi(a5 + 5) to zero.
; Verify that processing the invalid call doesn't run into trouble.

define i32 @fold_atoi_past_end() {
; CHECK-LABEL: @fold_atoi_past_end(
; CHECK-NEXT: [[I:%.*]] = call i32 @atoi(i8* nocapture getelementptr inbounds ([5 x i8], [5 x i8]* @a5, i64 1, i64 0))
; CHECK-NEXT: ret i32 [[I]]
;
%p5 = getelementptr [5 x i8], [5 x i8]* @a5, i32 0, i32 5
%i = call i32 @atoi(i8* %p5)
ret i32 %i
}

; TODO: Likewise, fold the 64-bit atol(a5 + 5) to zero, and similarly
; for atoll and strtrol and similar.
; Verify that processing the invalid call doesn't run into trouble.

define void @fold_atol_strtol_past_end(i64* %ps) {
; CHECK-LABEL: @fold_atol_strtol_past_end(
; CHECK-NEXT: [[I0:%.*]] = call i64 @atol(i8* nocapture getelementptr inbounds ([5 x i8], [5 x i8]* @a5, i64 1, i64 0))
; CHECK-NEXT: store i64 [[I0]], i64* [[PS:%.*]], align 4
; CHECK-NEXT: [[I1:%.*]] = call i64 @atoll(i8* nocapture getelementptr inbounds ([5 x i8], [5 x i8]* @a5, i64 1, i64 0))
; CHECK-NEXT: [[P1:%.*]] = getelementptr i64, i64* [[PS]], i64 1
; CHECK-NEXT: store i64 [[I1]], i64* [[P1]], align 4
; CHECK-NEXT: [[I2:%.*]] = call i64 @strtol(i8* nocapture getelementptr inbounds ([5 x i8], [5 x i8]* @a5, i64 1, i64 0), i8** null, i32 0)
; CHECK-NEXT: [[P2:%.*]] = getelementptr i64, i64* [[PS]], i64 2
; CHECK-NEXT: store i64 [[I2]], i64* [[P2]], align 4
; CHECK-NEXT: [[I3:%.*]] = call i64 @strtoul(i8* nocapture getelementptr inbounds ([5 x i8], [5 x i8]* @a5, i64 1, i64 0), i8** null, i32 8)
; CHECK-NEXT: [[P3:%.*]] = getelementptr i64, i64* [[PS]], i64 3
; CHECK-NEXT: store i64 [[I3]], i64* [[P3]], align 4
; CHECK-NEXT: [[I4:%.*]] = call i64 @strtoll(i8* nocapture getelementptr inbounds ([5 x i8], [5 x i8]* @a5, i64 1, i64 0), i8** null, i32 10)
; CHECK-NEXT: [[P4:%.*]] = getelementptr i64, i64* [[PS]], i64 4
; CHECK-NEXT: store i64 [[I4]], i64* [[P4]], align 4
; CHECK-NEXT: [[I5:%.*]] = call i64 @strtoul(i8* nocapture getelementptr inbounds ([5 x i8], [5 x i8]* @a5, i64 1, i64 0), i8** null, i32 16)
; CHECK-NEXT: [[P5:%.*]] = getelementptr i64, i64* [[PS]], i64 5
; CHECK-NEXT: store i64 [[I5]], i64* [[P5]], align 4
; CHECK-NEXT: ret void
;
%pa5 = getelementptr [5 x i8], [5 x i8]* @a5, i32 0, i32 5

%i0 = call i64 @atol(i8* %pa5)
%p0 = getelementptr i64, i64* %ps, i32 0
store i64 %i0, i64* %p0

%i1 = call i64 @atoll(i8* %pa5)
%p1 = getelementptr i64, i64* %ps, i32 1
store i64 %i1, i64* %p1

%i2 = call i64 @strtol(i8* %pa5, i8** null, i32 0)
%p2 = getelementptr i64, i64* %ps, i32 2
store i64 %i2, i64* %p2

%i3 = call i64 @strtoul(i8* %pa5, i8** null, i32 8)
%p3 = getelementptr i64, i64* %ps, i32 3
store i64 %i3, i64* %p3

%i4 = call i64 @strtoll(i8* %pa5, i8** null, i32 10)
%p4 = getelementptr i64, i64* %ps, i32 4
store i64 %i4, i64* %p4

%i5 = call i64 @strtoul(i8* %pa5, i8** null, i32 16)
%p5 = getelementptr i64, i64* %ps, i32 5
store i64 %i5, i64* %p5

ret void
}


; Fold sprintf(dst, a5 + 5) to zero, and also
; TODO: fold sprintf(dst, "%s", a5 + 5) to zero.

Expand Down