forked from OSchip/llvm-project
[InstCombine] Add additional tests for strlen/strnlen (NFC)
Taken from D122686.
This commit is contained in:
parent
cd55e51516
commit
884d7c60f3
|
@ -0,0 +1,195 @@
|
|||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
||||
; Verify that strlen calls with conditional expressions involving constant
|
||||
; string arguments with nonconstant offsets are folded as expected.
|
||||
;
|
||||
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
|
||||
|
||||
declare i64 @strlen(i8* nocapture)
|
||||
|
||||
@sx = external global [0 x i8]
|
||||
@s3 = constant [4 x i8] c"123\00", align 1
|
||||
@s5 = constant [6 x i8] c"12345\00", align 1
|
||||
@s7 = constant [8 x i8] c"1234567\00", align 1
|
||||
|
||||
@s5_3 = constant [10 x i8] c"12345\00123\00", align 1
|
||||
|
||||
|
||||
; Fold strlen (x ? s3 + i: s5) to x ? 3 - i : 5.
|
||||
|
||||
define i64 @fold_strlen_s3_pi_s5(i1 %0, i64 %1) {
|
||||
; CHECK-LABEL: @fold_strlen_s3_pi_s5(
|
||||
; CHECK-NEXT: [[PS3_PI:%.*]] = getelementptr inbounds [4 x i8], [4 x i8]* @s3, i64 0, i64 [[TMP1:%.*]]
|
||||
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[TMP0:%.*]], i8* [[PS3_PI]], i8* getelementptr inbounds ([6 x i8], [6 x i8]* @s5, i64 0, i64 0)
|
||||
; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @strlen(i8* noundef nonnull dereferenceable(1) [[SEL]])
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
|
||||
%ps3_pi = getelementptr inbounds [4 x i8], [4 x i8]* @s3, i64 0, i64 %1
|
||||
%ps5 = getelementptr [6 x i8], [6 x i8]* @s5, i64 0, i64 0
|
||||
%sel = select i1 %0, i8* %ps3_pi, i8* %ps5
|
||||
%len = tail call i64 @strlen(i8* %sel)
|
||||
ret i64 %len
|
||||
}
|
||||
|
||||
|
||||
; More complex expressions like the one below are not handled yet.
|
||||
; Fold: strlen (x ? s3 + i + 1 : s5 + j + 2) to x ? 2 - i : 3 - j.
|
||||
|
||||
define i64 @fold_strlen_s3_pi_p1_s5(i1 %0, i64 %1) {
|
||||
; XFAIL-CHECK-LABEL: @fold_strlen_s3_pi_p1_s5(
|
||||
; XFAIL-CHECK-NEXT: [[DIF_I:%.*]] = sub i64 2, %1
|
||||
; XFAIL-CHECK-NEXT: [[SEL:%.*]] = select i1 %0, i64 [[DIF_I]], i64 5
|
||||
; XFAIL-CHECK-NEXT: ret i64 [[SEL]]
|
||||
; CHECK-LABEL: @fold_strlen_s3_pi_p1_s5(
|
||||
; CHECK-NEXT: [[PS3_PI:%.*]] = getelementptr inbounds [4 x i8], [4 x i8]* @s3, i64 0, i64 [[TMP1:%.*]]
|
||||
; CHECK-NEXT: [[PS3_PI_P1:%.*]] = getelementptr i8, i8* [[PS3_PI]], i64 1
|
||||
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[TMP0:%.*]], i8* [[PS3_PI_P1]], i8* getelementptr inbounds ([6 x i8], [6 x i8]* @s5, i64 0, i64 0)
|
||||
; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @strlen(i8* noundef nonnull dereferenceable(1) [[SEL]])
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
|
||||
%ps3_pi = getelementptr inbounds [4 x i8], [4 x i8]* @s3, i64 0, i64 %1
|
||||
%ps3_pi_p1 = getelementptr i8, i8* %ps3_pi, i64 1
|
||||
%ps5 = getelementptr [6 x i8], [6 x i8]* @s5, i64 0, i64 0
|
||||
%sel = select i1 %0, i8* %ps3_pi_p1, i8* %ps5
|
||||
%len = tail call i64 @strlen(i8* %sel)
|
||||
ret i64 %len
|
||||
}
|
||||
|
||||
|
||||
; Avoid folding calls with conditional expressions involving constant
|
||||
; string arguments with embedded nuls such as:
|
||||
; strlen (x ? s5_3 + i : s5).
|
||||
|
||||
define i64 @call_strlen_s5_3_pi_s5(i1 %0, i64 %1) {
|
||||
; CHECK-LABEL: @call_strlen_s5_3_pi_s5(
|
||||
; CHECK-NEXT: [[PS5_3_PI:%.*]] = getelementptr inbounds [10 x i8], [10 x i8]* @s5_3, i64 0, i64 [[TMP1:%.*]]
|
||||
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[TMP0:%.*]], i8* [[PS5_3_PI]], i8* getelementptr inbounds ([6 x i8], [6 x i8]* @s5, i64 0, i64 0)
|
||||
; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @strlen(i8* noundef nonnull dereferenceable(1) [[SEL]])
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
|
||||
%ps5_3_pi = getelementptr inbounds [10 x i8], [10 x i8]* @s5_3, i64 0, i64 %1
|
||||
%ps5 = getelementptr [6 x i8], [6 x i8]* @s5, i64 0, i64 0
|
||||
%sel = select i1 %0, i8* %ps5_3_pi, i8* %ps5
|
||||
%len = tail call i64 @strlen(i8* %sel)
|
||||
ret i64 %len
|
||||
}
|
||||
|
||||
|
||||
; But do fold strlen (x ? s5_3 : s5 + j) to x ? 5 : 5 - j.
|
||||
|
||||
define i64 @call_strlen_s5_3_s5_pj(i1 %0, i64 %1) {
|
||||
; CHECK-LABEL: @call_strlen_s5_3_s5_pj(
|
||||
; CHECK-NEXT: [[PS5:%.*]] = getelementptr inbounds [6 x i8], [6 x i8]* @s5, i64 0, i64 [[TMP1:%.*]]
|
||||
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[TMP0:%.*]], i8* getelementptr inbounds ([10 x i8], [10 x i8]* @s5_3, i64 0, i64 0), i8* [[PS5]]
|
||||
; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @strlen(i8* noundef nonnull dereferenceable(1) [[SEL]])
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
|
||||
%ps5_3_pi = getelementptr [10 x i8], [10 x i8]* @s5_3, i64 0, i64 0
|
||||
%ps5 = getelementptr inbounds [6 x i8], [6 x i8]* @s5, i64 0, i64 %1
|
||||
%sel = select i1 %0, i8* %ps5_3_pi, i8* %ps5
|
||||
%len = tail call i64 @strlen(i8* %sel)
|
||||
ret i64 %len
|
||||
}
|
||||
|
||||
|
||||
; Fold strlen (x ? s3: s5 + j) to x ? 3 : 5 - j.
|
||||
|
||||
define i64 @fold_strlen_s3_s5_pj(i1 %0, i64 %1) {
|
||||
; CHECK-LABEL: @fold_strlen_s3_s5_pj(
|
||||
; CHECK-NEXT: [[PS5_PJ:%.*]] = getelementptr inbounds [6 x i8], [6 x i8]* @s5, i64 0, i64 [[TMP1:%.*]]
|
||||
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[TMP0:%.*]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @s3, i64 0, i64 0), i8* [[PS5_PJ]]
|
||||
; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @strlen(i8* noundef nonnull dereferenceable(1) [[SEL]])
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
|
||||
%ps3 = getelementptr [4 x i8], [4 x i8]* @s3, i64 0, i64 0
|
||||
%ps5_pj = getelementptr inbounds [6 x i8], [6 x i8]* @s5, i64 0, i64 %1
|
||||
%sel = select i1 %0, i8* %ps3, i8* %ps5_pj
|
||||
%len = tail call i64 @strlen(i8* %sel)
|
||||
ret i64 %len
|
||||
}
|
||||
|
||||
|
||||
; Same as above, avoid folding calls with conditional expressions involving
|
||||
; constant string arguments with embedded nuls such as:
|
||||
; strlen (x ? s3 : s5_3 + j).
|
||||
|
||||
define i64 @call_strlen_s3_s5_3_pj(i1 %0, i64 %1) {
|
||||
; CHECK-LABEL: @call_strlen_s3_s5_3_pj(
|
||||
; CHECK-NEXT: [[PS5_3_PJ:%.*]] = getelementptr inbounds [10 x i8], [10 x i8]* @s5_3, i64 0, i64 [[TMP1:%.*]]
|
||||
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[TMP0:%.*]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @s3, i64 0, i64 0), i8* [[PS5_3_PJ]]
|
||||
; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @strlen(i8* noundef nonnull dereferenceable(1) [[SEL]])
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
|
||||
%ps3 = getelementptr [4 x i8], [4 x i8]* @s3, i64 0, i64 0
|
||||
%ps5_3_pj = getelementptr inbounds [10 x i8], [10 x i8]* @s5_3, i64 0, i64 %1
|
||||
%sel = select i1 %0, i8* %ps3, i8* %ps5_3_pj
|
||||
%len = tail call i64 @strlen(i8* %sel)
|
||||
ret i64 %len
|
||||
}
|
||||
|
||||
|
||||
; Fold strlen (x ? s3 + i: s5 + j) to x ? 3 - i : 5 - j.
|
||||
|
||||
define i64 @fold_strlen_s3_pi_s5_pj(i1 %0, i64 %1, i64 %2) {
|
||||
; CHECK-LABEL: @fold_strlen_s3_pi_s5_pj(
|
||||
; CHECK-NEXT: [[PS3_PI:%.*]] = getelementptr inbounds [4 x i8], [4 x i8]* @s3, i64 0, i64 [[TMP1:%.*]]
|
||||
; CHECK-NEXT: [[PS5_PJ:%.*]] = getelementptr inbounds [6 x i8], [6 x i8]* @s5, i64 0, i64 [[TMP2:%.*]]
|
||||
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[TMP0:%.*]], i8* [[PS3_PI]], i8* [[PS5_PJ]]
|
||||
; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @strlen(i8* noundef nonnull [[SEL]])
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
|
||||
%ps3_pi = getelementptr inbounds [4 x i8], [4 x i8]* @s3, i64 0, i64 %1
|
||||
%ps5_pj = getelementptr inbounds [6 x i8], [6 x i8]* @s5, i64 0, i64 %2
|
||||
%sel = select i1 %0, i8* %ps3_pi, i8* %ps5_pj
|
||||
%len = tail call i64 @strlen(i8* %sel)
|
||||
ret i64 %len
|
||||
}
|
||||
|
||||
|
||||
; Fold strlen(E) with E being two conditional expressions:
|
||||
; strlen (x == 3 ? s3 : x == 5 ? s5 : s7) to x == 3 ? 3 : x == 5 ? 5 : 7.
|
||||
|
||||
define i64 @fold_strlen_s3_s5_s7(i32 %0) {
|
||||
; CHECK-LABEL: @fold_strlen_s3_s5_s7(
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP0:%.*]], 3
|
||||
; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP0]], 5
|
||||
; CHECK-NEXT: [[TMP4:%.*]] = select i1 [[TMP3]], i8* getelementptr inbounds ([6 x i8], [6 x i8]* @s5, i64 0, i64 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* @s7, i64 0, i64 0)
|
||||
; CHECK-NEXT: [[TMP5:%.*]] = select i1 [[TMP2]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @s3, i64 0, i64 0), i8* [[TMP4]]
|
||||
; CHECK-NEXT: [[TMP6:%.*]] = tail call i64 @strlen(i8* noundef nonnull dereferenceable(1) [[TMP5]])
|
||||
; CHECK-NEXT: ret i64 [[TMP6]]
|
||||
;
|
||||
|
||||
%2 = icmp eq i32 %0, 3
|
||||
%3 = icmp eq i32 %0, 5
|
||||
%4 = select i1 %3, i8* getelementptr ([6 x i8], [6 x i8]* @s5, i64 0, i64 0), i8* getelementptr ([8 x i8], [8 x i8]* @s7, i64 0, i64 0)
|
||||
%5 = select i1 %2, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @s3, i64 0, i64 0), i8* %4
|
||||
%6 = tail call i64 @strlen(i8* %5)
|
||||
ret i64 %6
|
||||
}
|
||||
|
||||
|
||||
; Do not fold strlen (x == 3 ? sx : x == 5 ? s5 : s7).
|
||||
|
||||
define i64 @call_strlen_sx_s5_s7(i32 %0) {
|
||||
; CHECK-LABEL: @call_strlen_sx_s5_s7(
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP0:%.*]], 3
|
||||
; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP0]], 5
|
||||
; CHECK-NEXT: [[TMP4:%.*]] = select i1 [[TMP3]], i8* getelementptr inbounds ([6 x i8], [6 x i8]* @s5, i64 0, i64 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* @s7, i64 0, i64 0)
|
||||
; CHECK-NEXT: [[TMP5:%.*]] = select i1 [[TMP2]], i8* getelementptr inbounds ([0 x i8], [0 x i8]* @sx, i64 0, i64 0), i8* [[TMP4]]
|
||||
; CHECK-NEXT: [[TMP6:%.*]] = tail call i64 @strlen(i8* noundef nonnull dereferenceable(1) [[TMP5]])
|
||||
; CHECK-NEXT: ret i64 [[TMP6]]
|
||||
;
|
||||
|
||||
%2 = icmp eq i32 %0, 3
|
||||
%3 = icmp eq i32 %0, 5
|
||||
%4 = select i1 %3, i8* getelementptr ([6 x i8], [6 x i8]* @s5, i64 0, i64 0), i8* getelementptr ([8 x i8], [8 x i8]* @s7, i64 0, i64 0)
|
||||
%5 = select i1 %2, i8* getelementptr inbounds ([0 x i8], [0 x i8]* @sx, i64 0, i64 0), i8* %4
|
||||
%6 = tail call i64 @strlen(i8* %5)
|
||||
ret i64 %6
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
||||
; Verify that strnlen calls with constant string arguments and offsets
|
||||
; and constant bounds are folded correctly.
|
||||
;
|
||||
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
|
||||
|
||||
declare i64 @strnlen(i8*, i64)
|
||||
|
||||
@s5 = constant [6 x i8] c"12345\00"
|
||||
@s5_3 = constant [9 x i8] c"12345\00xyz"
|
||||
|
||||
|
||||
; Fold strnlen(s5, 0) to 0.
|
||||
|
||||
define i64 @fold_strnlen_s5_0() {
|
||||
; CHECK-LABEL: @fold_strnlen_s5_0(
|
||||
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @s5, i64 0, i64 0), i64 0)
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
%ptr = getelementptr [6 x i8], [6 x i8]* @s5, i32 0, i32 0
|
||||
%len = call i64 @strnlen(i8* %ptr, i64 0)
|
||||
ret i64 %len
|
||||
}
|
||||
|
||||
|
||||
; Fold strnlen(s5, 4) to 4.
|
||||
|
||||
define i64 @fold_strnlen_s5_4() {
|
||||
; CHECK-LABEL: @fold_strnlen_s5_4(
|
||||
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @s5, i64 0, i64 0), i64 4)
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
%ptr = getelementptr [6 x i8], [6 x i8]* @s5, i32 0, i32 0
|
||||
%len = call i64 @strnlen(i8* %ptr, i64 4)
|
||||
ret i64 %len
|
||||
}
|
||||
|
||||
|
||||
; Fold strnlen(s5, 5) to 5.
|
||||
|
||||
define i64 @fold_strnlen_s5_5() {
|
||||
; CHECK-LABEL: @fold_strnlen_s5_5(
|
||||
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @s5, i64 0, i64 0), i64 5)
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
%ptr = getelementptr [6 x i8], [6 x i8]* @s5, i32 0, i32 0
|
||||
%len = call i64 @strnlen(i8* %ptr, i64 5)
|
||||
ret i64 %len
|
||||
}
|
||||
|
||||
|
||||
; Fold strnlen(s5, (size_t)-1) to 5.
|
||||
|
||||
define i64 @fold_strnlen_s5_m1() {
|
||||
; CHECK-LABEL: @fold_strnlen_s5_m1(
|
||||
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @s5, i64 0, i64 0), i64 -1)
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
%ptr = getelementptr [6 x i8], [6 x i8]* @s5, i32 0, i32 0
|
||||
%len = call i64 @strnlen(i8* %ptr, i64 -1)
|
||||
ret i64 %len
|
||||
}
|
||||
|
||||
|
||||
; Fold strnlen(s5_3 + 4, 5) to 1.
|
||||
|
||||
define i64 @fold_strnlen_s5_3_p4_5() {
|
||||
; CHECK-LABEL: @fold_strnlen_s5_3_p4_5(
|
||||
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @s5_3, i64 0, i64 4), i64 5)
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
%ptr = getelementptr [9 x i8], [9 x i8]* @s5_3, i32 0, i32 4
|
||||
%len = call i64 @strnlen(i8* %ptr, i64 5)
|
||||
ret i64 %len
|
||||
}
|
||||
|
||||
|
||||
; Fold strnlen(s5_3 + 5, 5) to 1.
|
||||
|
||||
define i64 @fold_strnlen_s5_3_p5_5() {
|
||||
; CHECK-LABEL: @fold_strnlen_s5_3_p5_5(
|
||||
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @s5_3, i64 0, i64 5), i64 5)
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
%ptr = getelementptr [9 x i8], [9 x i8]* @s5_3, i32 0, i32 5
|
||||
%len = call i64 @strnlen(i8* %ptr, i64 5)
|
||||
ret i64 %len
|
||||
}
|
||||
|
||||
|
||||
; Fold strnlen(s5_3 + 6, 5) to 3.
|
||||
|
||||
define i64 @fold_strnlen_s5_3_p6_5() {
|
||||
; CHECK-LABEL: @fold_strnlen_s5_3_p6_5(
|
||||
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @s5_3, i64 0, i64 6), i64 5)
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
%ptr = getelementptr [9 x i8], [9 x i8]* @s5_3, i32 0, i32 6
|
||||
%len = call i64 @strnlen(i8* %ptr, i64 5)
|
||||
ret i64 %len
|
||||
}
|
|
@ -0,0 +1,172 @@
|
|||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
||||
; Verify that strnlen calls with conditional expressions involving constant
|
||||
; string arguments and constant bounds are folded correctly.
|
||||
;
|
||||
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
|
||||
|
||||
declare i64 @strnlen(i8*, i64)
|
||||
|
||||
@s3 = constant [4 x i8] c"123\00"
|
||||
@s5 = constant [6 x i8] c"12345\00"
|
||||
@s5_3 = constant [10 x i8] c"12345\00678\00"
|
||||
@s6 = constant [7 x i8] c"123456\00"
|
||||
@s7 = constant [8 x i8] c"1234567\00"
|
||||
|
||||
|
||||
; Fold strnlen (%0 ? s3 : s5, 0) to 0.
|
||||
|
||||
define i64 @fold_strnlen_s3_s5_0(i1 %0) {
|
||||
; CHECK-LABEL: @fold_strnlen_s3_s5_0(
|
||||
; CHECK-NEXT: [[PTR:%.*]] = select i1 [[TMP0:%.*]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @s3, i64 0, i64 0), i8* getelementptr inbounds ([7 x i8], [7 x i8]* @s6, i64 0, i64 0)
|
||||
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* [[PTR]], i64 0)
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
%ptr = select i1 %0, i8* getelementptr ([4 x i8], [4 x i8]* @s3, i64 0, i64 0), i8* getelementptr ([7 x i8], [7 x i8]* @s6, i64 0, i64 0)
|
||||
|
||||
%len = call i64 @strnlen(i8* %ptr, i64 0)
|
||||
ret i64 %len
|
||||
}
|
||||
|
||||
|
||||
; Fold strnlen (%0 ? s3 : s5, 1) to 1.
|
||||
|
||||
define i64 @fold_strnlen_s3_s5_1(i1 %0) {
|
||||
; CHECK-LABEL: @fold_strnlen_s3_s5_1(
|
||||
; CHECK-NEXT: [[PTR:%.*]] = select i1 [[TMP0:%.*]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @s3, i64 0, i64 0), i8* getelementptr inbounds ([7 x i8], [7 x i8]* @s6, i64 0, i64 0)
|
||||
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* [[PTR]], i64 1)
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
%ptr = select i1 %0, i8* getelementptr ([4 x i8], [4 x i8]* @s3, i64 0, i64 0), i8* getelementptr ([7 x i8], [7 x i8]* @s6, i64 0, i64 0)
|
||||
|
||||
%len = call i64 @strnlen(i8* %ptr, i64 1)
|
||||
ret i64 %len
|
||||
}
|
||||
|
||||
|
||||
; Fold strnlen (%0 ? s3 : s5, 3) to 3.
|
||||
|
||||
define i64 @fold_strnlen_s3_s5_3(i1 %0) {
|
||||
; CHECK-LABEL: @fold_strnlen_s3_s5_3(
|
||||
; CHECK-NEXT: [[PTR:%.*]] = select i1 [[TMP0:%.*]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @s3, i64 0, i64 0), i8* getelementptr inbounds ([7 x i8], [7 x i8]* @s6, i64 0, i64 0)
|
||||
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* [[PTR]], i64 3)
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
%ptr = select i1 %0, i8* getelementptr ([4 x i8], [4 x i8]* @s3, i64 0, i64 0), i8* getelementptr ([7 x i8], [7 x i8]* @s6, i64 0, i64 0)
|
||||
|
||||
%len = call i64 @strnlen(i8* %ptr, i64 3)
|
||||
ret i64 %len
|
||||
}
|
||||
|
||||
|
||||
; Fold strnlen (%0 ? s3 : s5, 4) to %0 ? 3 : 4.
|
||||
|
||||
define i64 @fold_strnlen_s3_s5_4(i1 %0) {
|
||||
; CHECK-LABEL: @fold_strnlen_s3_s5_4(
|
||||
; CHECK-NEXT: [[PTR:%.*]] = select i1 [[TMP0:%.*]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @s3, i64 0, i64 0), i8* getelementptr inbounds ([7 x i8], [7 x i8]* @s6, i64 0, i64 0)
|
||||
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* [[PTR]], i64 4)
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
%ptr = select i1 %0, i8* getelementptr ([4 x i8], [4 x i8]* @s3, i64 0, i64 0), i8* getelementptr ([7 x i8], [7 x i8]* @s6, i64 0, i64 0)
|
||||
|
||||
%len = call i64 @strnlen(i8* %ptr, i64 4)
|
||||
ret i64 %len
|
||||
}
|
||||
|
||||
|
||||
; Fold strnlen (%0 ? s3 : s5, 5) to %0 ? 3 : 5.
|
||||
|
||||
define i64 @fold_strnlen_s3_s5_5(i1 %0) {
|
||||
; CHECK-LABEL: @fold_strnlen_s3_s5_5(
|
||||
; CHECK-NEXT: [[PTR:%.*]] = select i1 [[TMP0:%.*]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @s3, i64 0, i64 0), i8* getelementptr inbounds ([7 x i8], [7 x i8]* @s6, i64 0, i64 0)
|
||||
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* [[PTR]], i64 5)
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
%ptr = select i1 %0, i8* getelementptr ([4 x i8], [4 x i8]* @s3, i64 0, i64 0), i8* getelementptr ([7 x i8], [7 x i8]* @s6, i64 0, i64 0)
|
||||
|
||||
%len = call i64 @strnlen(i8* %ptr, i64 5)
|
||||
ret i64 %len
|
||||
}
|
||||
|
||||
|
||||
; Fold strnlen (%0 ? s3 : s5, 6) to %0 ? 3 : 5.
|
||||
|
||||
define i64 @fold_strnlen_s5_6(i1 %0) {
|
||||
; CHECK-LABEL: @fold_strnlen_s5_6(
|
||||
; CHECK-NEXT: [[PTR:%.*]] = select i1 [[TMP0:%.*]], i8* getelementptr inbounds ([6 x i8], [6 x i8]* @s5, i64 0, i64 0), i8* getelementptr inbounds ([7 x i8], [7 x i8]* @s6, i64 0, i64 0)
|
||||
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* [[PTR]], i64 6)
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
|
||||
%ptr = select i1 %0, i8* getelementptr ([6 x i8], [6 x i8]* @s5, i64 0, i64 0), i8* getelementptr ([7 x i8], [7 x i8]* @s6, i64 0, i64 0)
|
||||
|
||||
%len = call i64 @strnlen(i8* %ptr, i64 6)
|
||||
ret i64 %len
|
||||
}
|
||||
|
||||
|
||||
; Fold strnlen(E, N) with E being two conditional expressions:
|
||||
; strlen (x == 3 ? s3 : x == 5 ? s5 : s7, 4) to x == 3 ? 3 : 4.
|
||||
|
||||
define i64 @fold_strnlen_s3_s5_s7_4(i32 %0) {
|
||||
; CHECK-LABEL: @fold_strnlen_s3_s5_s7_4(
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP0:%.*]], 3
|
||||
; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP0]], 5
|
||||
; CHECK-NEXT: [[TMP4:%.*]] = select i1 [[TMP3]], i8* getelementptr inbounds ([6 x i8], [6 x i8]* @s5, i64 0, i64 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* @s7, i64 0, i64 0)
|
||||
; CHECK-NEXT: [[TMP5:%.*]] = select i1 [[TMP2]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @s3, i64 0, i64 0), i8* [[TMP4]]
|
||||
; CHECK-NEXT: [[TMP6:%.*]] = tail call i64 @strnlen(i8* [[TMP5]], i64 4)
|
||||
; CHECK-NEXT: ret i64 [[TMP6]]
|
||||
;
|
||||
|
||||
%2 = icmp eq i32 %0, 3
|
||||
%3 = icmp eq i32 %0, 5
|
||||
%4 = select i1 %3, i8* getelementptr ([6 x i8], [6 x i8]* @s5, i64 0, i64 0), i8* getelementptr ([8 x i8], [8 x i8]* @s7, i64 0, i64 0)
|
||||
%5 = select i1 %2, i8* getelementptr ([4 x i8], [4 x i8]* @s3, i64 0, i64 0), i8* %4
|
||||
%6 = tail call i64 @strnlen(i8* %5, i64 4)
|
||||
ret i64 %6
|
||||
}
|
||||
|
||||
|
||||
; As above, fold strnlen(E, N) with E being two conditional expressions
|
||||
; but with N == 6:
|
||||
; strlen (x == 3 ? s3 : x == 5 ? s5 : s7, 6) to x == 3 ? 3 : x == 5 ? 5 : 6.
|
||||
|
||||
define i64 @fold_strnlen_s3_s5_s7_6(i32 %0) {
|
||||
; CHECK-LABEL: @fold_strnlen_s3_s5_s7_6(
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP0:%.*]], 3
|
||||
; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP0]], 5
|
||||
; CHECK-NEXT: [[TMP4:%.*]] = select i1 [[TMP3]], i8* getelementptr inbounds ([6 x i8], [6 x i8]* @s5, i64 0, i64 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* @s7, i64 0, i64 0)
|
||||
; CHECK-NEXT: [[TMP5:%.*]] = select i1 [[TMP2]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @s3, i64 0, i64 0), i8* [[TMP4]]
|
||||
; CHECK-NEXT: [[TMP6:%.*]] = tail call i64 @strnlen(i8* [[TMP5]], i64 6)
|
||||
; CHECK-NEXT: ret i64 [[TMP6]]
|
||||
;
|
||||
|
||||
%2 = icmp eq i32 %0, 3
|
||||
%3 = icmp eq i32 %0, 5
|
||||
%4 = select i1 %3, i8* getelementptr ([6 x i8], [6 x i8]* @s5, i64 0, i64 0), i8* getelementptr ([8 x i8], [8 x i8]* @s7, i64 0, i64 0)
|
||||
%5 = select i1 %2, i8* getelementptr ([4 x i8], [4 x i8]* @s3, i64 0, i64 0), i8* %4
|
||||
%6 = tail call i64 @strnlen(i8* %5, i64 6)
|
||||
ret i64 %6
|
||||
}
|
||||
|
||||
|
||||
; And again, fold strnlen(E, N) with E being two conditional expressions
|
||||
; but with N == 8:
|
||||
; strlen (x == 3 ? s3 : x == 5 ? s5 : s7, 8) to x == 3 ? 3 : x == 5 ? 5 : 7.
|
||||
|
||||
define i64 @fold_strnlen_s3_s5_s7_8(i32 %0) {
|
||||
; CHECK-LABEL: @fold_strnlen_s3_s5_s7_8(
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP0:%.*]], 3
|
||||
; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP0]], 5
|
||||
; CHECK-NEXT: [[TMP4:%.*]] = select i1 [[TMP3]], i8* getelementptr inbounds ([6 x i8], [6 x i8]* @s5, i64 0, i64 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* @s7, i64 0, i64 0)
|
||||
; CHECK-NEXT: [[TMP5:%.*]] = select i1 [[TMP2]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @s3, i64 0, i64 0), i8* [[TMP4]]
|
||||
; CHECK-NEXT: [[TMP6:%.*]] = tail call i64 @strnlen(i8* [[TMP5]], i64 8)
|
||||
; CHECK-NEXT: ret i64 [[TMP6]]
|
||||
;
|
||||
|
||||
%2 = icmp eq i32 %0, 3
|
||||
%3 = icmp eq i32 %0, 5
|
||||
%4 = select i1 %3, i8* getelementptr ([6 x i8], [6 x i8]* @s5, i64 0, i64 0), i8* getelementptr ([8 x i8], [8 x i8]* @s7, i64 0, i64 0)
|
||||
%5 = select i1 %2, i8* getelementptr ([4 x i8], [4 x i8]* @s3, i64 0, i64 0), i8* %4
|
||||
%6 = tail call i64 @strnlen(i8* %5, i64 8)
|
||||
ret i64 %6
|
||||
}
|
|
@ -0,0 +1,233 @@
|
|||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
||||
; Verify that strnlen calls with conditional expressions involving constant
|
||||
; string arguments with nonconstant offsets and constant bounds or constant
|
||||
; offsets and nonconstant bounds are folded correctly.
|
||||
;
|
||||
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
|
||||
|
||||
declare i64 @strnlen(i8*, i64)
|
||||
|
||||
@sx = external global [0 x i8]
|
||||
@a3 = constant [3 x i8] c"123"
|
||||
@s3 = constant [4 x i8] c"123\00"
|
||||
@s5 = constant [6 x i8] c"12345\00"
|
||||
@s5_3 = constant [10 x i8] c"12345\00abc\00"
|
||||
|
||||
|
||||
; Fold strnlen(sx + %0, 0) to 0.
|
||||
|
||||
define i64 @fold_strnlen_sx_pi_0(i64 %0) {
|
||||
; CHECK-LABEL: @fold_strnlen_sx_pi_0(
|
||||
; CHECK-NEXT: [[PTR:%.*]] = getelementptr [0 x i8], [0 x i8]* @sx, i64 0, i64 [[TMP0:%.*]]
|
||||
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* [[PTR]], i64 0)
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
|
||||
%ptr = getelementptr [0 x i8], [0 x i8]* @sx, i64 0, i64 %0
|
||||
%len = call i64 @strnlen(i8* %ptr, i64 0)
|
||||
ret i64 %len
|
||||
}
|
||||
|
||||
|
||||
; Do not fold strnlen(sx + %0, %1).
|
||||
|
||||
define i64 @call_strnlen_sx_pi_n(i64 %0, i64 %1) {
|
||||
; CHECK-LABEL: @call_strnlen_sx_pi_n(
|
||||
; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds [0 x i8], [0 x i8]* @sx, i64 0, i64 [[TMP0:%.*]]
|
||||
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* nonnull [[PTR]], i64 [[TMP1:%.*]])
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
|
||||
%ptr = getelementptr inbounds [0 x i8], [0 x i8]* @sx, i64 0, i64 %0
|
||||
%len = call i64 @strnlen(i8* %ptr, i64 %1)
|
||||
ret i64 %len
|
||||
}
|
||||
|
||||
|
||||
; Fold strnlen(a3 + %0, 2) to min(3 - %0, 2).
|
||||
|
||||
define i64 @call_strnlen_a3_pi_2(i64 %0) {
|
||||
; CHECK-LABEL: @call_strnlen_a3_pi_2(
|
||||
; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds [3 x i8], [3 x i8]* @a3, i64 0, i64 [[TMP0:%.*]]
|
||||
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* nonnull [[PTR]], i64 2)
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
|
||||
%ptr = getelementptr inbounds [3 x i8], [3 x i8]* @a3, i64 0, i64 %0
|
||||
%len = call i64 @strnlen(i8* %ptr, i64 2)
|
||||
ret i64 %len
|
||||
}
|
||||
|
||||
|
||||
; Fold strnlen(a3 + %0, 3) to min(3 - %0, 3).
|
||||
|
||||
define i64 @call_strnlen_a3_pi_3(i64 %0) {
|
||||
; CHECK-LABEL: @call_strnlen_a3_pi_3(
|
||||
; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds [3 x i8], [3 x i8]* @a3, i64 0, i64 [[TMP0:%.*]]
|
||||
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* nonnull [[PTR]], i64 3)
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
|
||||
%ptr = getelementptr inbounds [3 x i8], [3 x i8]* @a3, i64 0, i64 %0
|
||||
%len = call i64 @strnlen(i8* %ptr, i64 3)
|
||||
ret i64 %len
|
||||
}
|
||||
|
||||
|
||||
; Fold strnlen(s3 + %0, 0) to 0.
|
||||
|
||||
define i64 @fold_strnlen_s3_pi_0(i64 %0) {
|
||||
; CHECK-LABEL: @fold_strnlen_s3_pi_0(
|
||||
; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds [4 x i8], [4 x i8]* @s3, i64 0, i64 [[TMP0:%.*]]
|
||||
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* nonnull [[PTR]], i64 0)
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
%ptr = getelementptr inbounds [4 x i8], [4 x i8]* @s3, i64 0, i64 %0
|
||||
%len = call i64 @strnlen(i8* %ptr, i64 0)
|
||||
ret i64 %len
|
||||
}
|
||||
|
||||
|
||||
; Fold strnlen(s5 + %0, 0) to 0.
|
||||
|
||||
define i64 @call_strnlen_s5_pi_0(i64 zeroext %0) {
|
||||
; CHECK-LABEL: @call_strnlen_s5_pi_0(
|
||||
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @s5, i64 0, i64 0), i64 0)
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
%ptr = getelementptr [6 x i8], [6 x i8]* @s5, i32 0, i32 0
|
||||
%len = call i64 @strnlen(i8* %ptr, i64 0)
|
||||
ret i64 %len
|
||||
}
|
||||
|
||||
|
||||
; Fold strnlen(s5_3 + %0, 0) to 0.
|
||||
|
||||
define i64 @fold_strnlen_s5_3_pi_0(i64 zeroext %0) {
|
||||
; CHECK-LABEL: @fold_strnlen_s5_3_pi_0(
|
||||
; CHECK-NEXT: [[PTR:%.*]] = getelementptr [10 x i8], [10 x i8]* @s5_3, i64 0, i64 [[TMP0:%.*]]
|
||||
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* [[PTR]], i64 0)
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
%ptr = getelementptr [10 x i8], [10 x i8]* @s5_3, i32 0, i64 %0
|
||||
%len = call i64 @strnlen(i8* %ptr, i64 0)
|
||||
ret i64 %len
|
||||
}
|
||||
|
||||
|
||||
; Do not fold strnlen(s5_3 + %0, %1).
|
||||
|
||||
define i64 @fold_strnlen_s5_3_pi_n(i64 zeroext %0, i64 %1) {
|
||||
; CHECK-LABEL: @fold_strnlen_s5_3_pi_n(
|
||||
; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds [10 x i8], [10 x i8]* @s5_3, i64 0, i64 [[TMP0:%.*]]
|
||||
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* nonnull [[PTR]], i64 [[TMP1:%.*]])
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
%ptr = getelementptr inbounds [10 x i8], [10 x i8]* @s5_3, i32 0, i64 %0
|
||||
%len = call i64 @strnlen(i8* %ptr, i64 %1)
|
||||
ret i64 %len
|
||||
}
|
||||
|
||||
|
||||
; Fold strnlen(a3, %0) to min(sizeof(a3), %0)
|
||||
|
||||
define i64 @fold_strnlen_a3_n(i64 %0) {
|
||||
; CHECK-LABEL: @fold_strnlen_a3_n(
|
||||
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @a3, i64 0, i64 0), i64 [[TMP0:%.*]])
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
|
||||
%ptr = getelementptr [3 x i8], [3 x i8]* @a3, i64 0, i64 0
|
||||
%len = call i64 @strnlen(i8* %ptr, i64 %0)
|
||||
ret i64 %len
|
||||
}
|
||||
|
||||
|
||||
; Fold strnlen(s3, %0) to min(strlen(s3), %0)
|
||||
|
||||
define i64 @fold_strnlen_s3_n(i64 %0) {
|
||||
; CHECK-LABEL: @fold_strnlen_s3_n(
|
||||
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @s3, i64 0, i64 0), i64 [[TMP0:%.*]])
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
|
||||
%ptr = getelementptr [4 x i8], [4 x i8]* @s3, i64 0, i64 0
|
||||
%len = call i64 @strnlen(i8* %ptr, i64 %0)
|
||||
ret i64 %len
|
||||
}
|
||||
|
||||
|
||||
; Fold strnlen(a3 + %0, 2) to min(sizeof(a3) - %0, 2)
|
||||
|
||||
define i64 @fold_strnlen_a3_pi_2(i64 %0) {
|
||||
; CHECK-LABEL: @fold_strnlen_a3_pi_2(
|
||||
; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds [3 x i8], [3 x i8]* @a3, i64 0, i64 [[TMP0:%.*]]
|
||||
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* nonnull [[PTR]], i64 2)
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
|
||||
%ptr = getelementptr inbounds [3 x i8], [3 x i8]* @a3, i64 0, i64 %0
|
||||
%len = call i64 @strnlen(i8* %ptr, i64 2)
|
||||
ret i64 %len
|
||||
}
|
||||
|
||||
|
||||
; Fold strnlen(s3 + %0, 2) to min(strlen(s3) - %0, 2)
|
||||
|
||||
define i64 @fold_strnlen_s3_pi_2(i64 %0) {
|
||||
; CHECK-LABEL: @fold_strnlen_s3_pi_2(
|
||||
; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds [4 x i8], [4 x i8]* @s3, i64 0, i64 [[TMP0:%.*]]
|
||||
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* nonnull [[PTR]], i64 2)
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
|
||||
%ptr = getelementptr inbounds [4 x i8], [4 x i8]* @s3, i64 0, i64 %0
|
||||
%len = call i64 @strnlen(i8* %ptr, i64 2)
|
||||
ret i64 %len
|
||||
}
|
||||
|
||||
|
||||
; Fold strnlen(s3 + %0, 3) to min(strlen(s3) - %0, 3)
|
||||
|
||||
define i64 @fold_strnlen_s3_pi_3(i64 %0) {
|
||||
; CHECK-LABEL: @fold_strnlen_s3_pi_3(
|
||||
; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds [4 x i8], [4 x i8]* @s3, i64 0, i64 [[TMP0:%.*]]
|
||||
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* nonnull [[PTR]], i64 3)
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
|
||||
%ptr = getelementptr inbounds [4 x i8], [4 x i8]* @s3, i64 0, i64 %0
|
||||
%len = call i64 @strnlen(i8* %ptr, i64 3)
|
||||
ret i64 %len
|
||||
}
|
||||
|
||||
|
||||
; Fold strnlen(s3 + %0, %1) to min(strlen(s3) - %0, %1)
|
||||
|
||||
define i64 @fold_strnlen_s3_pi_n(i64 %0, i64 %1) {
|
||||
; CHECK-LABEL: @fold_strnlen_s3_pi_n(
|
||||
; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds [4 x i8], [4 x i8]* @s3, i64 0, i64 [[TMP0:%.*]]
|
||||
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* nonnull [[PTR]], i64 [[TMP1:%.*]])
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
|
||||
%ptr = getelementptr inbounds [4 x i8], [4 x i8]* @s3, i64 0, i64 %0
|
||||
%len = call i64 @strnlen(i8* %ptr, i64 %1)
|
||||
ret i64 %len
|
||||
}
|
||||
|
||||
|
||||
; Do not fold strnlen(s5_3 + %0, 2). The result is in [0, 2] but there's
|
||||
; no simple way to derive its lower bound from the offset.
|
||||
|
||||
define i64 @call_strnlen_s5_3_pi_2(i64 %0) {
|
||||
; CHECK-LABEL: @call_strnlen_s5_3_pi_2(
|
||||
; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds [10 x i8], [10 x i8]* @s5_3, i64 0, i64 [[TMP0:%.*]]
|
||||
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* nonnull [[PTR]], i64 2)
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
|
||||
%ptr = getelementptr inbounds [10 x i8], [10 x i8]* @s5_3, i64 0, i64 %0
|
||||
%len = call i64 @strnlen(i8* %ptr, i64 2)
|
||||
ret i64 %len
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
||||
; Verify that strnlen calls with conditional expressions involving constant
|
||||
; string arguments with nonconstant bounds are folded correctly.
|
||||
;
|
||||
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
|
||||
|
||||
declare i64 @strnlen(i8*, i64)
|
||||
|
||||
@sx = external global [0 x i8]
|
||||
@s3 = constant [4 x i8] c"123\00"
|
||||
@s5 = constant [6 x i8] c"12345\00"
|
||||
@s5_3 = constant [10 x i8] c"12345\00abc\00"
|
||||
|
||||
|
||||
; Fold strnlen (%0 ? s3 + %1 : s5, %2) to min(%0 ? 3 : 5, %1) when
|
||||
; s3 + %1 is guaranteed to be within the bounds of s3.
|
||||
|
||||
define i64 @fold_strnlen_s3_pi_s5_n(i1 %0, i64 %1, i64 %2) {
|
||||
; CHECK-LABEL: @fold_strnlen_s3_pi_s5_n(
|
||||
; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds [4 x i8], [4 x i8]* @s3, i64 0, i64 [[TMP1:%.*]]
|
||||
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[TMP0:%.*]], i8* [[PTR]], i8* getelementptr inbounds ([6 x i8], [6 x i8]* @s5, i64 0, i64 0)
|
||||
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* [[SEL]], i64 [[TMP2:%.*]])
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
|
||||
%ptr = getelementptr inbounds [4 x i8], [4 x i8]* @s3, i64 0, i64 %1
|
||||
%sel = select i1 %0, i8* %ptr, i8* getelementptr ([6 x i8], [6 x i8]* @s5, i64 0, i64 0)
|
||||
%len = call i64 @strnlen(i8* %sel, i64 %2)
|
||||
ret i64 %len
|
||||
}
|
||||
|
||||
|
||||
; Do not fold the same expression as above when s3 + %i is not guaranteed
|
||||
; to be within the bounds of s3. Also verify that the call is not marked
|
||||
; noundef, nonnull, or dereferenceable because a zero bound implies no
|
||||
; access.
|
||||
|
||||
define i64 @call_strnlen_s3_pi_xbounds_s5_n(i1 %0, i64 %1, i64 %2) {
|
||||
; CHECK-LABEL: @call_strnlen_s3_pi_xbounds_s5_n(
|
||||
; CHECK-NEXT: [[PTR:%.*]] = getelementptr [4 x i8], [4 x i8]* @s3, i64 0, i64 [[TMP1:%.*]]
|
||||
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[TMP0:%.*]], i8* [[PTR]], i8* getelementptr inbounds ([6 x i8], [6 x i8]* @s5, i64 0, i64 0)
|
||||
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* [[SEL]], i64 [[TMP2:%.*]])
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
|
||||
%ptr = getelementptr [4 x i8], [4 x i8]* @s3, i64 0, i64 %1
|
||||
%sel = select i1 %0, i8* %ptr, i8* getelementptr ([6 x i8], [6 x i8]* @s5, i64 0, i64 0)
|
||||
%len = call i64 @strnlen(i8* %sel, i64 %2)
|
||||
ret i64 %len
|
||||
}
|
||||
|
||||
|
||||
; Do not fold strnlen(%0 ? s3 + %1 : sx, %1) when sx's length and size
|
||||
; are unknown. This also verifies that the folder cleans up the IR after
|
||||
; successfully folding the first subexpression IR when folding the second
|
||||
; subexpression fails.
|
||||
|
||||
define i64 @call_strnlen_s3_pi_sx_n(i1 %0, i64 %1, i64 %2) {
|
||||
; CHECK-LABEL: @call_strnlen_s3_pi_sx_n(
|
||||
; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds [4 x i8], [4 x i8]* @s3, i64 0, i64 [[TMP1:%.*]]
|
||||
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[TMP0:%.*]], i8* [[PTR]], i8* getelementptr inbounds ([0 x i8], [0 x i8]* @sx, i64 0, i64 0)
|
||||
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* [[SEL]], i64 [[TMP2:%.*]])
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
|
||||
%ptr = getelementptr inbounds [4 x i8], [4 x i8]* @s3, i64 0, i64 %1
|
||||
%sel = select i1 %0, i8* %ptr, i8* getelementptr ([0 x i8], [0 x i8]* @sx, i64 0, i64 0)
|
||||
%len = call i64 @strnlen(i8* %sel, i64 %2)
|
||||
ret i64 %len
|
||||
}
|
||||
|
||||
|
||||
; Fold strnlen (%0 ? s3 : s5 + %1, %2) to min(%0 ? 3 : 5, %1).
|
||||
|
||||
define i64 @fold_strnlen_s3_s5_pi_n(i1 %0, i64 %1, i64 %2) {
|
||||
; CHECK-LABEL: @fold_strnlen_s3_s5_pi_n(
|
||||
; CHECK-NEXT: [[PTR:%.*]] = select i1 [[TMP0:%.*]], i8* getelementptr inbounds ([6 x i8], [6 x i8]* @s5, i64 0, i64 0), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @s3, i64 0, i64 0)
|
||||
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* [[PTR]], i64 [[TMP1:%.*]])
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
|
||||
%ptr = select i1 %0, i8* getelementptr ([6 x i8], [6 x i8]* @s5, i64 0, i64 0), i8* getelementptr ([4 x i8], [4 x i8]* @s3, i64 0, i64 0)
|
||||
%len = call i64 @strnlen(i8* %ptr, i64 %1)
|
||||
ret i64 %len
|
||||
}
|
|
@ -0,0 +1,201 @@
|
|||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
||||
; Verify that equality tests of strnlen calls against zero are folded
|
||||
; correctly.
|
||||
;
|
||||
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
|
||||
|
||||
declare i64 @strnlen(i8*, i64)
|
||||
|
||||
@ax = external global [0 x i8]
|
||||
@a5 = external global [5 x i8]
|
||||
@s5 = constant [6 x i8] c"12345\00"
|
||||
|
||||
|
||||
; Fold strnlen(ax, 0) == 0 to true.
|
||||
|
||||
define i1 @fold_strnlen_ax_0_eqz() {
|
||||
; CHECK-LABEL: @fold_strnlen_ax_0_eqz(
|
||||
; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @strnlen(i8* getelementptr inbounds ([0 x i8], [0 x i8]* @ax, i64 0, i64 0), i64 0)
|
||||
; CHECK-NEXT: [[EQZ:%.*]] = icmp eq i64 [[LEN]], 0
|
||||
; CHECK-NEXT: ret i1 [[EQZ]]
|
||||
;
|
||||
|
||||
%ptr = getelementptr [0 x i8], [0 x i8]* @ax, i64 0, i64 0
|
||||
%len = tail call i64 @strnlen(i8* %ptr, i64 0)
|
||||
%eqz = icmp eq i64 %len, 0
|
||||
ret i1 %eqz
|
||||
}
|
||||
|
||||
|
||||
; Fold strnlen(ax, 0) > 0 to false.
|
||||
|
||||
define i1 @fold_strnlen_ax_0_gtz() {
|
||||
; CHECK-LABEL: @fold_strnlen_ax_0_gtz(
|
||||
; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @strnlen(i8* getelementptr inbounds ([0 x i8], [0 x i8]* @ax, i64 0, i64 0), i64 0)
|
||||
; CHECK-NEXT: [[GTZ:%.*]] = icmp ne i64 [[LEN]], 0
|
||||
; CHECK-NEXT: ret i1 [[GTZ]]
|
||||
;
|
||||
|
||||
%ptr = getelementptr [0 x i8], [0 x i8]* @ax, i64 0, i64 0
|
||||
%len = tail call i64 @strnlen(i8* %ptr, i64 0)
|
||||
%gtz = icmp ugt i64 %len, 0
|
||||
ret i1 %gtz
|
||||
}
|
||||
|
||||
|
||||
; Fold strnlen(ax, 1) == 0 to *ax == 0.
|
||||
|
||||
define i1 @fold_strnlen_ax_1_eqz() {
|
||||
; CHECK-LABEL: @fold_strnlen_ax_1_eqz(
|
||||
; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @strnlen(i8* getelementptr inbounds ([0 x i8], [0 x i8]* @ax, i64 0, i64 0), i64 1)
|
||||
; CHECK-NEXT: [[EQZ:%.*]] = icmp eq i64 [[LEN]], 0
|
||||
; CHECK-NEXT: ret i1 [[EQZ]]
|
||||
;
|
||||
|
||||
%ptr = getelementptr [0 x i8], [0 x i8]* @ax, i64 0, i64 0
|
||||
%len = tail call i64 @strnlen(i8* %ptr, i64 1)
|
||||
%eqz = icmp eq i64 %len, 0
|
||||
ret i1 %eqz
|
||||
}
|
||||
|
||||
|
||||
; Fold strnlen(ax, 1) != 0 to *ax != 0.
|
||||
|
||||
define i1 @fold_strnlen_ax_1_neqz() {
|
||||
; CHECK-LABEL: @fold_strnlen_ax_1_neqz(
|
||||
; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @strnlen(i8* getelementptr inbounds ([0 x i8], [0 x i8]* @ax, i64 0, i64 0), i64 1)
|
||||
; CHECK-NEXT: [[NEZ:%.*]] = icmp ne i64 [[LEN]], 0
|
||||
; CHECK-NEXT: ret i1 [[NEZ]]
|
||||
;
|
||||
|
||||
%ptr = getelementptr [0 x i8], [0 x i8]* @ax, i64 0, i64 0
|
||||
%len = tail call i64 @strnlen(i8* %ptr, i64 1)
|
||||
%nez = icmp ne i64 %len, 0
|
||||
ret i1 %nez
|
||||
}
|
||||
|
||||
|
||||
; Fold strnlen(ax, 9) == 0 to *ax == 0.
|
||||
|
||||
define i1 @fold_strnlen_ax_9_eqz() {
|
||||
; CHECK-LABEL: @fold_strnlen_ax_9_eqz(
|
||||
; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @strnlen(i8* getelementptr inbounds ([0 x i8], [0 x i8]* @ax, i64 0, i64 0), i64 9)
|
||||
; CHECK-NEXT: [[EQZ:%.*]] = icmp eq i64 [[LEN]], 0
|
||||
; CHECK-NEXT: ret i1 [[EQZ]]
|
||||
;
|
||||
|
||||
%ptr = getelementptr [0 x i8], [0 x i8]* @ax, i64 0, i64 0
|
||||
%len = tail call i64 @strnlen(i8* %ptr, i64 9)
|
||||
%eqz = icmp eq i64 %len, 0
|
||||
ret i1 %eqz
|
||||
}
|
||||
|
||||
|
||||
; Do not fold strnlen(ax, %0) == 0 for %0 that might be zero.
|
||||
|
||||
define i1 @call_strnlen_ax_n_eqz(i64 %0) {
|
||||
; CHECK-LABEL: @call_strnlen_ax_n_eqz(
|
||||
; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @strnlen(i8* getelementptr inbounds ([0 x i8], [0 x i8]* @ax, i64 0, i64 0), i64 [[TMP0:%.*]])
|
||||
; CHECK-NEXT: [[EQZ:%.*]] = icmp eq i64 [[LEN]], 0
|
||||
; CHECK-NEXT: ret i1 [[EQZ]]
|
||||
;
|
||||
|
||||
%ptr = getelementptr [0 x i8], [0 x i8]* @ax, i64 0, i64 0
|
||||
%len = tail call i64 @strnlen(i8* %ptr, i64 %0)
|
||||
%eqz = icmp eq i64 %len, 0
|
||||
ret i1 %eqz
|
||||
}
|
||||
|
||||
|
||||
; Fold strnlen(ax, %0) == 0 to *ax == 0 for %0 that's not zero.
|
||||
|
||||
define i1 @fold_strnlen_ax_nz_eqz(i64 %0) {
|
||||
; CHECK-LABEL: @fold_strnlen_ax_nz_eqz(
|
||||
; CHECK-NEXT: [[MAX:%.*]] = or i64 [[TMP0:%.*]], 1
|
||||
; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @strnlen(i8* getelementptr inbounds ([0 x i8], [0 x i8]* @ax, i64 0, i64 0), i64 [[MAX]])
|
||||
; CHECK-NEXT: [[EQZ:%.*]] = icmp eq i64 [[LEN]], 0
|
||||
; CHECK-NEXT: ret i1 [[EQZ]]
|
||||
;
|
||||
|
||||
%max = or i64 %0, 1
|
||||
%ptr = getelementptr [0 x i8], [0 x i8]* @ax, i64 0, i64 0
|
||||
%len = tail call i64 @strnlen(i8* %ptr, i64 %max)
|
||||
%eqz = icmp eq i64 %len, 0
|
||||
ret i1 %eqz
|
||||
}
|
||||
|
||||
|
||||
; Fold strnlen(ax, %0) > 0 to *ax != 0 for %0 that's not zero.
|
||||
|
||||
define i1 @fold_strnlen_ax_nz_gtz(i64 %0) {
|
||||
; CHECK-LABEL: @fold_strnlen_ax_nz_gtz(
|
||||
; CHECK-NEXT: [[MAX:%.*]] = or i64 [[TMP0:%.*]], 1
|
||||
; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @strnlen(i8* getelementptr inbounds ([0 x i8], [0 x i8]* @ax, i64 0, i64 0), i64 [[MAX]])
|
||||
; CHECK-NEXT: [[GTZ:%.*]] = icmp ne i64 [[LEN]], 0
|
||||
; CHECK-NEXT: ret i1 [[GTZ]]
|
||||
;
|
||||
|
||||
%max = or i64 %0, 1
|
||||
%ptr = getelementptr [0 x i8], [0 x i8]* @ax, i64 0, i64 0
|
||||
%len = tail call i64 @strnlen(i8* %ptr, i64 %max)
|
||||
%gtz = icmp ugt i64 %len, 0
|
||||
ret i1 %gtz
|
||||
}
|
||||
|
||||
|
||||
; Fold strnlen(a5 + %0, %1) == 0 to a5[%0] == 0 for a nonconstant a5
|
||||
; and a nonzero %1.
|
||||
|
||||
define i1 @fold_strnlen_a5_pi_nz_eqz(i64 %0, i64 %1) {
|
||||
; CHECK-LABEL: @fold_strnlen_a5_pi_nz_eqz(
|
||||
; CHECK-NEXT: [[NZ:%.*]] = or i64 [[TMP1:%.*]], 1
|
||||
; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds [5 x i8], [5 x i8]* @a5, i64 0, i64 [[TMP0:%.*]]
|
||||
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* nonnull [[PTR]], i64 [[NZ]])
|
||||
; CHECK-NEXT: [[EQZ:%.*]] = icmp eq i64 [[LEN]], 0
|
||||
; CHECK-NEXT: ret i1 [[EQZ]]
|
||||
;
|
||||
|
||||
%nz = or i64 %1, 1
|
||||
%ptr = getelementptr inbounds [5 x i8], [5 x i8]* @a5, i64 0, i64 %0
|
||||
%len = call i64 @strnlen(i8* nonnull %ptr, i64 %nz)
|
||||
%eqz = icmp eq i64 %len, 0
|
||||
ret i1 %eqz
|
||||
}
|
||||
|
||||
|
||||
; Fold strnlen(s5 + %0, %1) == 0 for a constant s5 and nonzero %1.
|
||||
; This is first folded to s5[%0] == 0 like the above and then finally
|
||||
; to %0 == 5.
|
||||
|
||||
define i1 @fold_strnlen_s5_pi_nz_eqz(i64 %0, i64 %1) {
|
||||
; CHECK-LABEL: @fold_strnlen_s5_pi_nz_eqz(
|
||||
; CHECK-NEXT: [[TMP3:%.*]] = or i64 [[TMP1:%.*]], 1
|
||||
; CHECK-NEXT: [[TMP4:%.*]] = getelementptr inbounds [6 x i8], [6 x i8]* @s5, i64 0, i64 [[TMP0:%.*]]
|
||||
; CHECK-NEXT: [[TMP5:%.*]] = call i64 @strnlen(i8* nonnull [[TMP4]], i64 [[TMP3]])
|
||||
; CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 0
|
||||
; CHECK-NEXT: ret i1 [[TMP6]]
|
||||
;
|
||||
|
||||
%3 = or i64 %1, 1
|
||||
%4 = getelementptr inbounds [6 x i8], [6 x i8]* @s5, i64 0, i64 %0
|
||||
%5 = call i64 @strnlen(i8* nonnull %4, i64 %3)
|
||||
%6 = icmp eq i64 %5, 0
|
||||
ret i1 %6
|
||||
}
|
||||
|
||||
|
||||
; Do not fold strnlen(s5 + %0, %1) for a constant s5 when %1 might be zero.
|
||||
|
||||
define i1 @call_strnlen_s5_pi_n_eqz(i64 %0, i64 %1) {
|
||||
; CHECK-LABEL: @call_strnlen_s5_pi_n_eqz(
|
||||
; CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds [6 x i8], [6 x i8]* @s5, i64 0, i64 [[TMP0:%.*]]
|
||||
; CHECK-NEXT: [[TMP4:%.*]] = call i64 @strnlen(i8* nonnull [[TMP3]], i64 [[TMP1:%.*]])
|
||||
; CHECK-NEXT: [[TMP5:%.*]] = icmp eq i64 [[TMP4]], 0
|
||||
; CHECK-NEXT: ret i1 [[TMP5]]
|
||||
;
|
||||
|
||||
%3 = getelementptr inbounds [6 x i8], [6 x i8]* @s5, i64 0, i64 %0
|
||||
%4 = call i64 @strnlen(i8* nonnull %3, i64 %1)
|
||||
%5 = icmp eq i64 %4, 0
|
||||
ret i1 %5
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
||||
; Verify that strnlen calls that aren't folded into constants are annotated
|
||||
; with noundef, nonnull, and dereferenceable only when maxlen is known to
|
||||
; to be nonzero.
|
||||
;
|
||||
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
|
||||
|
||||
declare i64 @strnlen(i8*, i64)
|
||||
|
||||
@ecp = external global i8*, align 8
|
||||
|
||||
|
||||
; Annotate strnlen(ecp, 3) call with noundef, nonnull, and dereferenceable
|
||||
; based on the access to *ecp.
|
||||
|
||||
define i64 @deref_strnlen_ecp_3() {
|
||||
; CHECK-LABEL: @deref_strnlen_ecp_3(
|
||||
; CHECK-NEXT: [[PTR:%.*]] = load i8*, i8** @ecp, align 8
|
||||
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* [[PTR]], i64 3)
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
%ptr = load i8*, i8** @ecp
|
||||
%len = call i64 @strnlen(i8* %ptr, i64 3)
|
||||
ret i64 %len
|
||||
}
|
||||
|
||||
|
||||
; Annotate strnlen(ecp, %n) call with nonzero %n with noundef, nonnull, and
|
||||
; dereferenceable based on the access to *ecp.
|
||||
|
||||
define i64 @deref_strnlen_ecp_nz(i64 %n) {
|
||||
; CHECK-LABEL: @deref_strnlen_ecp_nz(
|
||||
; CHECK-NEXT: [[NONZERO:%.*]] = or i64 [[N:%.*]], 1
|
||||
; CHECK-NEXT: [[PTR:%.*]] = load i8*, i8** @ecp, align 8
|
||||
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* [[PTR]], i64 [[NONZERO]])
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
%nonzero = or i64 %n, 1
|
||||
%ptr = load i8*, i8** @ecp
|
||||
%len = call i64 @strnlen(i8* %ptr, i64 %nonzero)
|
||||
ret i64 %len
|
||||
}
|
||||
|
||||
|
||||
|
||||
; Do not annotate strnlen(ecp, %n) call with nonnull etc. because it need
|
||||
; not access *ecp. (Strictly, every pointer function argument must be
|
||||
; noundef, so this is overly conservative.)
|
||||
|
||||
|
||||
define i64 @noderef_strnlen_ecp_n(i64 %n) {
|
||||
; CHECK-LABEL: @noderef_strnlen_ecp_n(
|
||||
; CHECK-NEXT: [[PTR:%.*]] = load i8*, i8** @ecp, align 8
|
||||
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* [[PTR]], i64 [[N:%.*]])
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
%ptr = load i8*, i8** @ecp
|
||||
%len = call i64 @strnlen(i8* %ptr, i64 %n)
|
||||
ret i64 %len
|
||||
}
|
|
@ -0,0 +1,153 @@
|
|||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
||||
; Verify that wcslen calls with conditional expressions involving constant
|
||||
; string arguments with nonconstant offsets are folded as expected. See
|
||||
; strlen-4.ll for the corresponding strlen test.
|
||||
;
|
||||
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
|
||||
|
||||
declare i64 @wcslen(i32*)
|
||||
|
||||
!0 = !{i32 1, !"wchar_size", i32 4}
|
||||
!llvm.module.flags = !{!0}
|
||||
|
||||
@ws3 = constant [4 x i32] [i32 1, i32 2, i32 3, i32 0]
|
||||
@ws5 = constant [6 x i32] [i32 1, i32 2, i32 3, i32 4, i32 5, i32 0]
|
||||
@ws5_3 = constant [10 x i32] [i32 1, i32 2, i32 3, i32 4, i32 5, i32 0, i32 6, i32 7, i32 8, i32 0]
|
||||
|
||||
|
||||
; Fold wcslen (x ? s3 + i: s5) to x ? 3 - i : 5.
|
||||
|
||||
define dso_local i64 @fold_wcslen_s3_pi_s5(i1 zeroext %0, i64 %1) {
|
||||
; CHECK-LABEL: @fold_wcslen_s3_pi_s5(
|
||||
; CHECK-NEXT: [[PS3_PI:%.*]] = getelementptr inbounds [4 x i32], [4 x i32]* @ws3, i64 0, i64 [[TMP1:%.*]]
|
||||
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[TMP0:%.*]], i32* [[PS3_PI]], i32* getelementptr inbounds ([6 x i32], [6 x i32]* @ws5, i64 0, i64 0)
|
||||
; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @wcslen(i32* [[SEL]])
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
|
||||
%ps3_pi = getelementptr inbounds [4 x i32], [4 x i32]* @ws3, i64 0, i64 %1
|
||||
%ps5 = getelementptr inbounds [6 x i32], [6 x i32]* @ws5, i64 0, i64 0
|
||||
%sel = select i1 %0, i32* %ps3_pi, i32* %ps5
|
||||
%len = tail call i64 @wcslen(i32* %sel)
|
||||
ret i64 %len
|
||||
}
|
||||
|
||||
|
||||
; More complex expressions like the one below are not handled yet.
|
||||
; Fold: wcslen (x ? s3 + i + 1 : s5 + j + 2) to x ? 2 - i : 3 - j.
|
||||
|
||||
define dso_local i64 @fold_wcslen_s3_pi_p1_s5(i1 zeroext %0, i64 %1) {
|
||||
; XFAIL-CHECK-LABEL: @fold_wcslen_s3_pi_p1_s5(
|
||||
; XFAIL-CHECK-NEXT: [[DIF_I:%.*]] = sub i64 2, %1
|
||||
; XFAIL-CHECK-NEXT: [[SEL:%.*]] = select i1 %0, i64 [[DIF_I]], i64 5
|
||||
; XFAIL-CHECK-NEXT: ret i64 [[SEL]]
|
||||
; CHECK-LABEL: @fold_wcslen_s3_pi_p1_s5(
|
||||
; CHECK-NEXT: [[PS3_PI:%.*]] = getelementptr inbounds [4 x i32], [4 x i32]* @ws3, i64 0, i64 [[TMP1:%.*]]
|
||||
; CHECK-NEXT: [[PS3_PI_P1:%.*]] = getelementptr inbounds i32, i32* [[PS3_PI]], i64 1
|
||||
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[TMP0:%.*]], i32* [[PS3_PI_P1]], i32* getelementptr inbounds ([6 x i32], [6 x i32]* @ws5, i64 0, i64 0)
|
||||
; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @wcslen(i32* [[SEL]])
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
|
||||
%ps3_pi = getelementptr inbounds [4 x i32], [4 x i32]* @ws3, i64 0, i64 %1
|
||||
%ps3_pi_p1 = getelementptr inbounds i32, i32* %ps3_pi, i64 1
|
||||
%ps5 = getelementptr inbounds [6 x i32], [6 x i32]* @ws5, i64 0, i64 0
|
||||
%sel = select i1 %0, i32* %ps3_pi_p1, i32* %ps5
|
||||
%len = tail call i64 @wcslen(i32* %sel)
|
||||
ret i64 %len
|
||||
}
|
||||
|
||||
|
||||
; Avoid folding calls with conditional expressions involving constant
|
||||
; string arguments with embedded nuls such as:
|
||||
; wcslen (x ? s5_3 + i : s5).
|
||||
|
||||
define dso_local i64 @call_wcslen_s5_3_pi_s5(i1 zeroext %0, i64 %1) {
|
||||
; CHECK-LABEL: @call_wcslen_s5_3_pi_s5(
|
||||
; CHECK-NEXT: [[PS5_3_PI:%.*]] = getelementptr inbounds [10 x i32], [10 x i32]* @ws5_3, i64 0, i64 [[TMP1:%.*]]
|
||||
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[TMP0:%.*]], i32* [[PS5_3_PI]], i32* getelementptr inbounds ([6 x i32], [6 x i32]* @ws5, i64 0, i64 0)
|
||||
; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @wcslen(i32* [[SEL]])
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
|
||||
%ps5_3_pi = getelementptr inbounds [10 x i32], [10 x i32]* @ws5_3, i64 0, i64 %1
|
||||
%ps5 = getelementptr inbounds [6 x i32], [6 x i32]* @ws5, i64 0, i64 0
|
||||
%sel = select i1 %0, i32* %ps5_3_pi, i32* %ps5
|
||||
%len = tail call i64 @wcslen(i32* %sel)
|
||||
ret i64 %len
|
||||
}
|
||||
|
||||
|
||||
; But do fold wcslen (x ? s5_3 : s5 + j) to x ? 5 : 5 - j.
|
||||
|
||||
define dso_local i64 @call_wcslen_s5_3_s5_pj(i1 zeroext %0, i64 %1) {
|
||||
; CHECK-LABEL: @call_wcslen_s5_3_s5_pj(
|
||||
; CHECK-NEXT: [[PS5:%.*]] = getelementptr inbounds [6 x i32], [6 x i32]* @ws5, i64 0, i64 [[TMP1:%.*]]
|
||||
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[TMP0:%.*]], i32* getelementptr inbounds ([10 x i32], [10 x i32]* @ws5_3, i64 0, i64 0), i32* [[PS5]]
|
||||
; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @wcslen(i32* [[SEL]])
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
|
||||
%ps5_3_pi = getelementptr inbounds [10 x i32], [10 x i32]* @ws5_3, i64 0, i64 0
|
||||
%ps5 = getelementptr inbounds [6 x i32], [6 x i32]* @ws5, i64 0, i64 %1
|
||||
%sel = select i1 %0, i32* %ps5_3_pi, i32* %ps5
|
||||
%len = tail call i64 @wcslen(i32* %sel)
|
||||
ret i64 %len
|
||||
}
|
||||
|
||||
|
||||
; Fold wcslen (x ? s3: s5 + j) to x ? 3 : 5 - j.
|
||||
|
||||
define dso_local i64 @fold_wcslen_s3_s5_pj(i1 zeroext %0, i64 %1) {
|
||||
; CHECK-LABEL: @fold_wcslen_s3_s5_pj(
|
||||
; CHECK-NEXT: [[PS5_PJ:%.*]] = getelementptr inbounds [6 x i32], [6 x i32]* @ws5, i64 0, i64 [[TMP1:%.*]]
|
||||
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[TMP0:%.*]], i32* getelementptr inbounds ([4 x i32], [4 x i32]* @ws3, i64 0, i64 0), i32* [[PS5_PJ]]
|
||||
; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @wcslen(i32* [[SEL]])
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
|
||||
%ps3 = getelementptr inbounds [4 x i32], [4 x i32]* @ws3, i64 0, i64 0
|
||||
%ps5_pj = getelementptr inbounds [6 x i32], [6 x i32]* @ws5, i64 0, i64 %1
|
||||
%sel = select i1 %0, i32* %ps3, i32* %ps5_pj
|
||||
%len = tail call i64 @wcslen(i32* %sel)
|
||||
ret i64 %len
|
||||
}
|
||||
|
||||
|
||||
; Same as above, avoid folding calls with conditional expressions involving
|
||||
; constant string arguments with embedded nuls such as:
|
||||
; wcslen (x ? s3 : s5_3 + j).
|
||||
|
||||
define dso_local i64 @call_wcslen_s3_s5_3_pj(i1 zeroext %0, i64 %1) {
|
||||
; CHECK-LABEL: @call_wcslen_s3_s5_3_pj(
|
||||
; CHECK-NEXT: [[PS5_3_PJ:%.*]] = getelementptr inbounds [10 x i32], [10 x i32]* @ws5_3, i64 0, i64 [[TMP1:%.*]]
|
||||
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[TMP0:%.*]], i32* getelementptr inbounds ([4 x i32], [4 x i32]* @ws3, i64 0, i64 0), i32* [[PS5_3_PJ]]
|
||||
; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @wcslen(i32* [[SEL]])
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
|
||||
%ps3 = getelementptr inbounds [4 x i32], [4 x i32]* @ws3, i64 0, i64 0
|
||||
%ps5_3_pj = getelementptr inbounds [10 x i32], [10 x i32]* @ws5_3, i64 0, i64 %1
|
||||
%sel = select i1 %0, i32* %ps3, i32* %ps5_3_pj
|
||||
%len = tail call i64 @wcslen(i32* %sel)
|
||||
ret i64 %len
|
||||
}
|
||||
|
||||
|
||||
; Fold wcslen (x ? s3 + i: s5 + j) to x ? 3 - i : 5 - j.
|
||||
|
||||
define dso_local i64 @fold_wcslen_s3_pi_s5_pj(i1 zeroext %0, i64 %1, i64 %2) {
|
||||
; CHECK-LABEL: @fold_wcslen_s3_pi_s5_pj(
|
||||
; CHECK-NEXT: [[PS3_PI:%.*]] = getelementptr inbounds [4 x i32], [4 x i32]* @ws3, i64 0, i64 [[TMP1:%.*]]
|
||||
; CHECK-NEXT: [[PS5_PJ:%.*]] = getelementptr inbounds [6 x i32], [6 x i32]* @ws5, i64 0, i64 [[TMP2:%.*]]
|
||||
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[TMP0:%.*]], i32* [[PS3_PI]], i32* [[PS5_PJ]]
|
||||
; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @wcslen(i32* nonnull [[SEL]])
|
||||
; CHECK-NEXT: ret i64 [[LEN]]
|
||||
;
|
||||
|
||||
%ps3_pi = getelementptr inbounds [4 x i32], [4 x i32]* @ws3, i64 0, i64 %1
|
||||
%ps5_pj = getelementptr inbounds [6 x i32], [6 x i32]* @ws5, i64 0, i64 %2
|
||||
%sel = select i1 %0, i32* %ps3_pi, i32* %ps5_pj
|
||||
%len = tail call i64 @wcslen(i32* %sel)
|
||||
ret i64 %len
|
||||
}
|
Loading…
Reference in New Issue