[llvm] 884d7c6 - [InstCombine] Add additional tests for strlen/strnlen (NFC)
Nikita Popov via llvm-commits
llvm-commits at lists.llvm.org
Fri Apr 1 07:59:24 PDT 2022
Author: Martin Sebor
Date: 2022-04-01T16:58:38+02:00
New Revision: 884d7c60f367dd753f0528b28f0029edc1b91c5e
URL: https://github.com/llvm/llvm-project/commit/884d7c60f367dd753f0528b28f0029edc1b91c5e
DIFF: https://github.com/llvm/llvm-project/commit/884d7c60f367dd753f0528b28f0029edc1b91c5e.diff
LOG: [InstCombine] Add additional tests for strlen/strnlen (NFC)
Taken from D122686.
Added:
llvm/test/Transforms/InstCombine/strlen-4.ll
llvm/test/Transforms/InstCombine/strnlen-1.ll
llvm/test/Transforms/InstCombine/strnlen-2.ll
llvm/test/Transforms/InstCombine/strnlen-3.ll
llvm/test/Transforms/InstCombine/strnlen-4.ll
llvm/test/Transforms/InstCombine/strnlen-5.ll
llvm/test/Transforms/InstCombine/strnlen-6.ll
llvm/test/Transforms/InstCombine/wcslen-5.ll
Modified:
Removed:
################################################################################
diff --git a/llvm/test/Transforms/InstCombine/strlen-4.ll b/llvm/test/Transforms/InstCombine/strlen-4.ll
new file mode 100644
index 0000000000000..7b8ab18836e2f
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/strlen-4.ll
@@ -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)
+
+ at sx = external global [0 x i8]
+ at s3 = constant [4 x i8] c"123\00", align 1
+ at s5 = constant [6 x i8] c"12345\00", align 1
+ at s7 = constant [8 x i8] c"1234567\00", align 1
+
+ at 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
+}
diff --git a/llvm/test/Transforms/InstCombine/strnlen-1.ll b/llvm/test/Transforms/InstCombine/strnlen-1.ll
new file mode 100644
index 0000000000000..0fb94dba6c0ff
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/strnlen-1.ll
@@ -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)
+
+ at s5 = constant [6 x i8] c"12345\00"
+ at 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
+}
diff --git a/llvm/test/Transforms/InstCombine/strnlen-2.ll b/llvm/test/Transforms/InstCombine/strnlen-2.ll
new file mode 100644
index 0000000000000..4af460ba0abc2
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/strnlen-2.ll
@@ -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)
+
+ at s3 = constant [4 x i8] c"123\00"
+ at s5 = constant [6 x i8] c"12345\00"
+ at s5_3 = constant [10 x i8] c"12345\00678\00"
+ at s6 = constant [7 x i8] c"123456\00"
+ at 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
+}
diff --git a/llvm/test/Transforms/InstCombine/strnlen-3.ll b/llvm/test/Transforms/InstCombine/strnlen-3.ll
new file mode 100644
index 0000000000000..33792f426d3c3
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/strnlen-3.ll
@@ -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)
+
+ at sx = external global [0 x i8]
+ at a3 = constant [3 x i8] c"123"
+ at s3 = constant [4 x i8] c"123\00"
+ at s5 = constant [6 x i8] c"12345\00"
+ at 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
+}
diff --git a/llvm/test/Transforms/InstCombine/strnlen-4.ll b/llvm/test/Transforms/InstCombine/strnlen-4.ll
new file mode 100644
index 0000000000000..96cb6cc5de37a
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/strnlen-4.ll
@@ -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)
+
+ at sx = external global [0 x i8]
+ at s3 = constant [4 x i8] c"123\00"
+ at s5 = constant [6 x i8] c"12345\00"
+ at 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
+}
diff --git a/llvm/test/Transforms/InstCombine/strnlen-5.ll b/llvm/test/Transforms/InstCombine/strnlen-5.ll
new file mode 100644
index 0000000000000..9887d2916023c
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/strnlen-5.ll
@@ -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)
+
+ at ax = external global [0 x i8]
+ at a5 = external global [5 x i8]
+ at 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
+}
diff --git a/llvm/test/Transforms/InstCombine/strnlen-6.ll b/llvm/test/Transforms/InstCombine/strnlen-6.ll
new file mode 100644
index 0000000000000..91c85825ba4ca
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/strnlen-6.ll
@@ -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)
+
+ at 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
+}
diff --git a/llvm/test/Transforms/InstCombine/wcslen-5.ll b/llvm/test/Transforms/InstCombine/wcslen-5.ll
new file mode 100644
index 0000000000000..106867bba4fa4
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/wcslen-5.ll
@@ -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}
+
+ at ws3 = constant [4 x i32] [i32 1, i32 2, i32 3, i32 0]
+ at ws5 = constant [6 x i32] [i32 1, i32 2, i32 3, i32 4, i32 5, i32 0]
+ at 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
+}
More information about the llvm-commits
mailing list