[llvm] cc2ce81 - [SimplifyLibcalls] Tests for libcall folding of subobjects [NFC]

Martin Sebor via llvm-commits llvm-commits at lists.llvm.org
Fri May 6 09:43:36 PDT 2022


Author: Martin Sebor
Date: 2022-05-06T10:43:02-06:00
New Revision: cc2ce81bd859ec5c3b698cf2039e273264bb6abe

URL: https://github.com/llvm/llvm-project/commit/cc2ce81bd859ec5c3b698cf2039e273264bb6abe
DIFF: https://github.com/llvm/llvm-project/commit/cc2ce81bd859ec5c3b698cf2039e273264bb6abe.diff

LOG: [SimplifyLibcalls] Tests for libcall folding of subobjects [NFC]

Add tests exercising the future enancement of folding library function
calls with arguments involving subobjects such as elements of arrays
or struct members.

Added: 
    llvm/test/Transforms/InstCombine/memchr-5.ll
    llvm/test/Transforms/InstCombine/memcmp-3.ll
    llvm/test/Transforms/InstCombine/memcmp-4.ll
    llvm/test/Transforms/InstCombine/memrchr-5.ll
    llvm/test/Transforms/InstCombine/sprintf-2.ll
    llvm/test/Transforms/InstCombine/str-int-3.ll
    llvm/test/Transforms/InstCombine/strcmp-3.ll
    llvm/test/Transforms/InstCombine/strcmp-4.ll
    llvm/test/Transforms/InstCombine/strlen-5.ll
    llvm/test/Transforms/InstCombine/strlen-6.ll
    llvm/test/Transforms/InstCombine/strlen-7.ll
    llvm/test/Transforms/InstCombine/strlen-8.ll
    llvm/test/Transforms/InstCombine/strncmp-4.ll

Modified: 
    

Removed: 
    


################################################################################
diff  --git a/llvm/test/Transforms/InstCombine/memchr-5.ll b/llvm/test/Transforms/InstCombine/memchr-5.ll
new file mode 100644
index 000000000000..f1225ae08837
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/memchr-5.ll
@@ -0,0 +1,284 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; Verify that calls to memchr with arrays of elements larger than char
+; are folded correctly.
+; RUN: opt < %s -passes=instcombine -S -data-layout="E" | FileCheck %s --check-prefixes=BE
+; RUN: opt < %s -passes=instcombine -S -data-layout="e" | FileCheck %s --check-prefixes=LE
+
+declare i8* @memchr(i8*, i32, i64)
+
+; BE representation: { 'a', 'b', 'c', 'd', 'e', ..., 'p' }
+; LE representation: { 'd', 'c', 'b', 'a', 'h', ..., 'm' }
+ at a = constant [4 x i32] [i32 1633837924, i32 1701209960, i32 1768581996, i32 1835954032]
+
+
+; Fold memchr(a, C, 16) for C in ['a', 'd'] U ['o', 'q'].
+
+define void @fold_memchr_a(i64* %pcmp) {
+; BE-LABEL: @fold_memchr_a(
+; BE-NEXT:    [[PA:%.*]] = call i8* @memchr(i8* noundef nonnull dereferenceable(1) bitcast ([4 x i32]* @a to i8*), i32 97, i64 16)
+; BE-NEXT:    [[IPA:%.*]] = ptrtoint i8* [[PA]] to i64
+; BE-NEXT:    [[OFFA:%.*]] = sub i64 [[IPA]], ptrtoint ([4 x i32]* @a to i64)
+; BE-NEXT:    store i64 [[OFFA]], i64* [[PCMP:%.*]], align 4
+; BE-NEXT:    [[PB:%.*]] = call i8* @memchr(i8* noundef nonnull dereferenceable(1) bitcast ([4 x i32]* @a to i8*), i32 98, i64 16)
+; BE-NEXT:    [[IPB:%.*]] = ptrtoint i8* [[PB]] to i64
+; BE-NEXT:    [[OFFB:%.*]] = sub i64 [[IPB]], ptrtoint ([4 x i32]* @a to i64)
+; BE-NEXT:    [[PSTOR1:%.*]] = getelementptr i64, i64* [[PCMP]], i64 1
+; BE-NEXT:    store i64 [[OFFB]], i64* [[PSTOR1]], align 4
+; BE-NEXT:    [[PC:%.*]] = call i8* @memchr(i8* noundef nonnull dereferenceable(1) bitcast ([4 x i32]* @a to i8*), i32 99, i64 16)
+; BE-NEXT:    [[IPC:%.*]] = ptrtoint i8* [[PC]] to i64
+; BE-NEXT:    [[OFFC:%.*]] = sub i64 [[IPC]], ptrtoint ([4 x i32]* @a to i64)
+; BE-NEXT:    [[PSTOR2:%.*]] = getelementptr i64, i64* [[PCMP]], i64 2
+; BE-NEXT:    store i64 [[OFFC]], i64* [[PSTOR2]], align 4
+; BE-NEXT:    [[PD:%.*]] = call i8* @memchr(i8* noundef nonnull dereferenceable(1) bitcast ([4 x i32]* @a to i8*), i32 100, i64 16)
+; BE-NEXT:    [[IPD:%.*]] = ptrtoint i8* [[PD]] to i64
+; BE-NEXT:    [[OFFD:%.*]] = sub i64 [[IPD]], ptrtoint ([4 x i32]* @a to i64)
+; BE-NEXT:    [[PSTOR3:%.*]] = getelementptr i64, i64* [[PCMP]], i64 3
+; BE-NEXT:    store i64 [[OFFD]], i64* [[PSTOR3]], align 4
+; BE-NEXT:    [[PN:%.*]] = call i8* @memchr(i8* noundef nonnull dereferenceable(1) bitcast ([4 x i32]* @a to i8*), i32 110, i64 16)
+; BE-NEXT:    [[IPN:%.*]] = ptrtoint i8* [[PN]] to i64
+; BE-NEXT:    [[OFFN:%.*]] = sub i64 [[IPN]], ptrtoint ([4 x i32]* @a to i64)
+; BE-NEXT:    [[PSTOR4:%.*]] = getelementptr i64, i64* [[PCMP]], i64 4
+; BE-NEXT:    store i64 [[OFFN]], i64* [[PSTOR4]], align 4
+; BE-NEXT:    [[PO:%.*]] = call i8* @memchr(i8* noundef nonnull dereferenceable(1) bitcast ([4 x i32]* @a to i8*), i32 111, i64 16)
+; BE-NEXT:    [[IPO:%.*]] = ptrtoint i8* [[PO]] to i64
+; BE-NEXT:    [[OFFO:%.*]] = sub i64 [[IPO]], ptrtoint ([4 x i32]* @a to i64)
+; BE-NEXT:    [[PSTOR6:%.*]] = getelementptr i64, i64* [[PCMP]], i64 6
+; BE-NEXT:    store i64 [[OFFO]], i64* [[PSTOR6]], align 4
+; BE-NEXT:    [[PP:%.*]] = call i8* @memchr(i8* noundef nonnull dereferenceable(1) bitcast ([4 x i32]* @a to i8*), i32 112, i64 16)
+; BE-NEXT:    [[IPP:%.*]] = ptrtoint i8* [[PP]] to i64
+; BE-NEXT:    [[OFFP:%.*]] = sub i64 [[IPP]], ptrtoint ([4 x i32]* @a to i64)
+; BE-NEXT:    [[PSTOR7:%.*]] = getelementptr i64, i64* [[PCMP]], i64 7
+; BE-NEXT:    store i64 [[OFFP]], i64* [[PSTOR7]], align 4
+; BE-NEXT:    [[PQ:%.*]] = call i8* @memchr(i8* noundef nonnull dereferenceable(1) bitcast ([4 x i32]* @a to i8*), i32 113, i64 16)
+; BE-NEXT:    [[IPQ:%.*]] = ptrtoint i8* [[PQ]] to i64
+; BE-NEXT:    [[PSTOR8:%.*]] = getelementptr i64, i64* [[PCMP]], i64 8
+; BE-NEXT:    store i64 [[IPQ]], i64* [[PSTOR8]], align 4
+; BE-NEXT:    ret void
+;
+; LE-LABEL: @fold_memchr_a(
+; LE-NEXT:    [[PA:%.*]] = call i8* @memchr(i8* noundef nonnull dereferenceable(1) bitcast ([4 x i32]* @a to i8*), i32 97, i64 16)
+; LE-NEXT:    [[IPA:%.*]] = ptrtoint i8* [[PA]] to i64
+; LE-NEXT:    [[OFFA:%.*]] = sub i64 [[IPA]], ptrtoint ([4 x i32]* @a to i64)
+; LE-NEXT:    store i64 [[OFFA]], i64* [[PCMP:%.*]], align 4
+; LE-NEXT:    [[PB:%.*]] = call i8* @memchr(i8* noundef nonnull dereferenceable(1) bitcast ([4 x i32]* @a to i8*), i32 98, i64 16)
+; LE-NEXT:    [[IPB:%.*]] = ptrtoint i8* [[PB]] to i64
+; LE-NEXT:    [[OFFB:%.*]] = sub i64 [[IPB]], ptrtoint ([4 x i32]* @a to i64)
+; LE-NEXT:    [[PSTOR1:%.*]] = getelementptr i64, i64* [[PCMP]], i64 1
+; LE-NEXT:    store i64 [[OFFB]], i64* [[PSTOR1]], align 4
+; LE-NEXT:    [[PC:%.*]] = call i8* @memchr(i8* noundef nonnull dereferenceable(1) bitcast ([4 x i32]* @a to i8*), i32 99, i64 16)
+; LE-NEXT:    [[IPC:%.*]] = ptrtoint i8* [[PC]] to i64
+; LE-NEXT:    [[OFFC:%.*]] = sub i64 [[IPC]], ptrtoint ([4 x i32]* @a to i64)
+; LE-NEXT:    [[PSTOR2:%.*]] = getelementptr i64, i64* [[PCMP]], i64 2
+; LE-NEXT:    store i64 [[OFFC]], i64* [[PSTOR2]], align 4
+; LE-NEXT:    [[PD:%.*]] = call i8* @memchr(i8* noundef nonnull dereferenceable(1) bitcast ([4 x i32]* @a to i8*), i32 100, i64 16)
+; LE-NEXT:    [[IPD:%.*]] = ptrtoint i8* [[PD]] to i64
+; LE-NEXT:    [[OFFD:%.*]] = sub i64 [[IPD]], ptrtoint ([4 x i32]* @a to i64)
+; LE-NEXT:    [[PSTOR3:%.*]] = getelementptr i64, i64* [[PCMP]], i64 3
+; LE-NEXT:    store i64 [[OFFD]], i64* [[PSTOR3]], align 4
+; LE-NEXT:    [[PN:%.*]] = call i8* @memchr(i8* noundef nonnull dereferenceable(1) bitcast ([4 x i32]* @a to i8*), i32 110, i64 16)
+; LE-NEXT:    [[IPN:%.*]] = ptrtoint i8* [[PN]] to i64
+; LE-NEXT:    [[OFFN:%.*]] = sub i64 [[IPN]], ptrtoint ([4 x i32]* @a to i64)
+; LE-NEXT:    [[PSTOR4:%.*]] = getelementptr i64, i64* [[PCMP]], i64 4
+; LE-NEXT:    store i64 [[OFFN]], i64* [[PSTOR4]], align 4
+; LE-NEXT:    [[PO:%.*]] = call i8* @memchr(i8* noundef nonnull dereferenceable(1) bitcast ([4 x i32]* @a to i8*), i32 111, i64 16)
+; LE-NEXT:    [[IPO:%.*]] = ptrtoint i8* [[PO]] to i64
+; LE-NEXT:    [[OFFO:%.*]] = sub i64 [[IPO]], ptrtoint ([4 x i32]* @a to i64)
+; LE-NEXT:    [[PSTOR6:%.*]] = getelementptr i64, i64* [[PCMP]], i64 6
+; LE-NEXT:    store i64 [[OFFO]], i64* [[PSTOR6]], align 4
+; LE-NEXT:    [[PP:%.*]] = call i8* @memchr(i8* noundef nonnull dereferenceable(1) bitcast ([4 x i32]* @a to i8*), i32 112, i64 16)
+; LE-NEXT:    [[IPP:%.*]] = ptrtoint i8* [[PP]] to i64
+; LE-NEXT:    [[OFFP:%.*]] = sub i64 [[IPP]], ptrtoint ([4 x i32]* @a to i64)
+; LE-NEXT:    [[PSTOR7:%.*]] = getelementptr i64, i64* [[PCMP]], i64 7
+; LE-NEXT:    store i64 [[OFFP]], i64* [[PSTOR7]], align 4
+; LE-NEXT:    [[PQ:%.*]] = call i8* @memchr(i8* noundef nonnull dereferenceable(1) bitcast ([4 x i32]* @a to i8*), i32 113, i64 16)
+; LE-NEXT:    [[IPQ:%.*]] = ptrtoint i8* [[PQ]] to i64
+; LE-NEXT:    [[PSTOR8:%.*]] = getelementptr i64, i64* [[PCMP]], i64 8
+; LE-NEXT:    store i64 [[IPQ]], i64* [[PSTOR8]], align 4
+; LE-NEXT:    ret void
+;
+  %p0 = getelementptr [4 x i32], [4 x i32]* @a, i64 0, i64 0
+  %p1 = bitcast i32* %p0 to i8*
+  %ip0 = ptrtoint [4 x i32]* @a to i64
+
+; Fold memchr(a, 'a', 16) - a to 0 (3 in LE).
+
+  %pa = call i8* @memchr(i8* %p1, i32 97, i64 16)
+  %ipa = ptrtoint i8* %pa to i64
+  %offa = sub i64 %ipa, %ip0
+  %pstor0 = getelementptr i64, i64* %pcmp, i64 0
+  store i64 %offa, i64* %pstor0
+
+; Fold memchr(a, 'b', 16) - a to 1 (2 in LE)
+
+  %pb = call i8* @memchr(i8* %p1, i32 98, i64 16)
+  %ipb = ptrtoint i8* %pb to i64
+  %offb = sub i64 %ipb, %ip0
+  %pstor1 = getelementptr i64, i64* %pcmp, i64 1
+  store i64 %offb, i64* %pstor1
+
+; Fold memchr(a, 'c', 16) - a to 2 (1 in LE)
+
+  %pc = call i8* @memchr(i8* %p1, i32 99, i64 16)
+  %ipc = ptrtoint i8* %pc to i64
+  %offc = sub i64 %ipc, %ip0
+  %pstor2 = getelementptr i64, i64* %pcmp, i64 2
+  store i64 %offc, i64* %pstor2
+
+; Fold memchr(a, 'd', 16) - a to 3 (0 in LE)
+
+  %pd = call i8* @memchr(i8* %p1, i32 100, i64 16)
+  %ipd = ptrtoint i8* %pd to i64
+  %offd = sub i64 %ipd, %ip0
+  %pstor3 = getelementptr i64, i64* %pcmp, i64 3
+  store i64 %offd, i64* %pstor3
+
+; Fold memchr(a, 'n', 16) - a to 13 (14 in LE)
+
+  %pn = call i8* @memchr(i8* %p1, i32 110, i64 16)
+  %ipn = ptrtoint i8* %pn to i64
+  %offn = sub i64 %ipn, %ip0
+  %pstor4 = getelementptr i64, i64* %pcmp, i64 4
+  store i64 %offn, i64* %pstor4
+
+; Fold memchr(a, 'o', 16) - a to 14 (13 in LE)
+
+  %po = call i8* @memchr(i8* %p1, i32 111, i64 16)
+  %ipo = ptrtoint i8* %po to i64
+  %offo = sub i64 %ipo, %ip0
+  %pstor6 = getelementptr i64, i64* %pcmp, i64 6
+  store i64 %offo, i64* %pstor6
+
+; Fold memchr(a, 'p', 16) - a to 15 (12 in LE)
+
+  %pp = call i8* @memchr(i8* %p1, i32 112, i64 16)
+  %ipp = ptrtoint i8* %pp to i64
+  %offp = sub i64 %ipp, %ip0
+  %pstor7 = getelementptr i64, i64* %pcmp, i64 7
+  store i64 %offp, i64* %pstor7
+
+; Fold memchr(a, 'q', 16) to null in both BE and LE.
+
+  %pq = call i8* @memchr(i8* %p1, i32 113, i64 16)
+  %ipq = ptrtoint i8* %pq to i64
+  %pstor8 = getelementptr i64, i64* %pcmp, i64 8
+  store i64 %ipq, i64* %pstor8
+
+  ret void
+}
+
+
+; Fold memchr(a + 1, C, 12) for C in ['e', 'h'] U ['a', 'd'].
+
+define void @fold_memchr_a_p1(i64* %pcmp) {
+; BE-LABEL: @fold_memchr_a_p1(
+; BE-NEXT:    [[PE:%.*]] = call i8* @memchr(i8* noundef nonnull dereferenceable(1) bitcast (i32* getelementptr inbounds ([4 x i32], [4 x i32]* @a, i64 0, i64 1) to i8*), i32 101, i64 12)
+; BE-NEXT:    [[IPE:%.*]] = ptrtoint i8* [[PE]] to i64
+; BE-NEXT:    [[OFFE:%.*]] = sub i64 [[IPE]], ptrtoint (i32* getelementptr inbounds ([4 x i32], [4 x i32]* @a, i64 0, i64 1) to i64)
+; BE-NEXT:    store i64 [[OFFE]], i64* [[PCMP:%.*]], align 4
+; BE-NEXT:    [[PF:%.*]] = call i8* @memchr(i8* noundef nonnull dereferenceable(1) bitcast (i32* getelementptr inbounds ([4 x i32], [4 x i32]* @a, i64 0, i64 1) to i8*), i32 102, i64 12)
+; BE-NEXT:    [[IPF:%.*]] = ptrtoint i8* [[PF]] to i64
+; BE-NEXT:    [[OFFF:%.*]] = sub i64 [[IPF]], ptrtoint (i32* getelementptr inbounds ([4 x i32], [4 x i32]* @a, i64 0, i64 1) to i64)
+; BE-NEXT:    [[PSTOR1:%.*]] = getelementptr i64, i64* [[PCMP]], i64 1
+; BE-NEXT:    store i64 [[OFFF]], i64* [[PSTOR1]], align 4
+; BE-NEXT:    [[PG:%.*]] = call i8* @memchr(i8* noundef nonnull dereferenceable(1) bitcast (i32* getelementptr inbounds ([4 x i32], [4 x i32]* @a, i64 0, i64 1) to i8*), i32 103, i64 12)
+; BE-NEXT:    [[IPG:%.*]] = ptrtoint i8* [[PG]] to i64
+; BE-NEXT:    [[OFFG:%.*]] = sub i64 [[IPG]], ptrtoint (i32* getelementptr inbounds ([4 x i32], [4 x i32]* @a, i64 0, i64 1) to i64)
+; BE-NEXT:    [[PSTOR2:%.*]] = getelementptr i64, i64* [[PCMP]], i64 2
+; BE-NEXT:    store i64 [[OFFG]], i64* [[PSTOR2]], align 4
+; BE-NEXT:    [[PH:%.*]] = call i8* @memchr(i8* noundef nonnull dereferenceable(1) bitcast (i32* getelementptr inbounds ([4 x i32], [4 x i32]* @a, i64 0, i64 1) to i8*), i32 104, i64 12)
+; BE-NEXT:    [[IPH:%.*]] = ptrtoint i8* [[PH]] to i64
+; BE-NEXT:    [[OFFH:%.*]] = sub i64 [[IPH]], ptrtoint (i32* getelementptr inbounds ([4 x i32], [4 x i32]* @a, i64 0, i64 1) to i64)
+; BE-NEXT:    [[PSTOR3:%.*]] = getelementptr i64, i64* [[PCMP]], i64 3
+; BE-NEXT:    store i64 [[OFFH]], i64* [[PSTOR3]], align 4
+; BE-NEXT:    [[PA:%.*]] = call i8* @memchr(i8* noundef nonnull dereferenceable(1) bitcast (i32* getelementptr inbounds ([4 x i32], [4 x i32]* @a, i64 0, i64 1) to i8*), i32 97, i64 12)
+; BE-NEXT:    [[IPA:%.*]] = ptrtoint i8* [[PA]] to i64
+; BE-NEXT:    [[PSTOR4:%.*]] = getelementptr i64, i64* [[PCMP]], i64 4
+; BE-NEXT:    store i64 [[IPA]], i64* [[PSTOR4]], align 4
+; BE-NEXT:    [[PD:%.*]] = call i8* @memchr(i8* noundef nonnull dereferenceable(1) bitcast (i32* getelementptr inbounds ([4 x i32], [4 x i32]* @a, i64 0, i64 1) to i8*), i32 100, i64 12)
+; BE-NEXT:    [[IPD:%.*]] = ptrtoint i8* [[PD]] to i64
+; BE-NEXT:    [[PSTOR5:%.*]] = getelementptr i64, i64* [[PCMP]], i64 5
+; BE-NEXT:    store i64 [[IPD]], i64* [[PSTOR5]], align 4
+; BE-NEXT:    ret void
+;
+; LE-LABEL: @fold_memchr_a_p1(
+; LE-NEXT:    [[PE:%.*]] = call i8* @memchr(i8* noundef nonnull dereferenceable(1) bitcast (i32* getelementptr inbounds ([4 x i32], [4 x i32]* @a, i64 0, i64 1) to i8*), i32 101, i64 12)
+; LE-NEXT:    [[IPE:%.*]] = ptrtoint i8* [[PE]] to i64
+; LE-NEXT:    [[OFFE:%.*]] = sub i64 [[IPE]], ptrtoint (i32* getelementptr inbounds ([4 x i32], [4 x i32]* @a, i64 0, i64 1) to i64)
+; LE-NEXT:    store i64 [[OFFE]], i64* [[PCMP:%.*]], align 4
+; LE-NEXT:    [[PF:%.*]] = call i8* @memchr(i8* noundef nonnull dereferenceable(1) bitcast (i32* getelementptr inbounds ([4 x i32], [4 x i32]* @a, i64 0, i64 1) to i8*), i32 102, i64 12)
+; LE-NEXT:    [[IPF:%.*]] = ptrtoint i8* [[PF]] to i64
+; LE-NEXT:    [[OFFF:%.*]] = sub i64 [[IPF]], ptrtoint (i32* getelementptr inbounds ([4 x i32], [4 x i32]* @a, i64 0, i64 1) to i64)
+; LE-NEXT:    [[PSTOR1:%.*]] = getelementptr i64, i64* [[PCMP]], i64 1
+; LE-NEXT:    store i64 [[OFFF]], i64* [[PSTOR1]], align 4
+; LE-NEXT:    [[PG:%.*]] = call i8* @memchr(i8* noundef nonnull dereferenceable(1) bitcast (i32* getelementptr inbounds ([4 x i32], [4 x i32]* @a, i64 0, i64 1) to i8*), i32 103, i64 12)
+; LE-NEXT:    [[IPG:%.*]] = ptrtoint i8* [[PG]] to i64
+; LE-NEXT:    [[OFFG:%.*]] = sub i64 [[IPG]], ptrtoint (i32* getelementptr inbounds ([4 x i32], [4 x i32]* @a, i64 0, i64 1) to i64)
+; LE-NEXT:    [[PSTOR2:%.*]] = getelementptr i64, i64* [[PCMP]], i64 2
+; LE-NEXT:    store i64 [[OFFG]], i64* [[PSTOR2]], align 4
+; LE-NEXT:    [[PH:%.*]] = call i8* @memchr(i8* noundef nonnull dereferenceable(1) bitcast (i32* getelementptr inbounds ([4 x i32], [4 x i32]* @a, i64 0, i64 1) to i8*), i32 104, i64 12)
+; LE-NEXT:    [[IPH:%.*]] = ptrtoint i8* [[PH]] to i64
+; LE-NEXT:    [[OFFH:%.*]] = sub i64 [[IPH]], ptrtoint (i32* getelementptr inbounds ([4 x i32], [4 x i32]* @a, i64 0, i64 1) to i64)
+; LE-NEXT:    [[PSTOR3:%.*]] = getelementptr i64, i64* [[PCMP]], i64 3
+; LE-NEXT:    store i64 [[OFFH]], i64* [[PSTOR3]], align 4
+; LE-NEXT:    [[PA:%.*]] = call i8* @memchr(i8* noundef nonnull dereferenceable(1) bitcast (i32* getelementptr inbounds ([4 x i32], [4 x i32]* @a, i64 0, i64 1) to i8*), i32 97, i64 12)
+; LE-NEXT:    [[IPA:%.*]] = ptrtoint i8* [[PA]] to i64
+; LE-NEXT:    [[PSTOR4:%.*]] = getelementptr i64, i64* [[PCMP]], i64 4
+; LE-NEXT:    store i64 [[IPA]], i64* [[PSTOR4]], align 4
+; LE-NEXT:    [[PD:%.*]] = call i8* @memchr(i8* noundef nonnull dereferenceable(1) bitcast (i32* getelementptr inbounds ([4 x i32], [4 x i32]* @a, i64 0, i64 1) to i8*), i32 100, i64 12)
+; LE-NEXT:    [[IPD:%.*]] = ptrtoint i8* [[PD]] to i64
+; LE-NEXT:    [[PSTOR5:%.*]] = getelementptr i64, i64* [[PCMP]], i64 5
+; LE-NEXT:    store i64 [[IPD]], i64* [[PSTOR5]], align 4
+; LE-NEXT:    ret void
+;
+  %p0 = getelementptr [4 x i32], [4 x i32]* @a, i64 0, i64 1
+  %p1 = bitcast i32* %p0 to i8*
+  %ip0 = ptrtoint i8* %p1 to i64
+
+; Fold memchr(a + 1, 'e', 12) - a to 0 (3 in LE).
+
+  %pe = call i8* @memchr(i8* %p1, i32 101, i64 12)
+  %ipe = ptrtoint i8* %pe to i64
+  %offe = sub i64 %ipe, %ip0
+  %pstor0 = getelementptr i64, i64* %pcmp, i64 0
+  store i64 %offe, i64* %pstor0
+
+; Fold memchr(a + 1, 'f', 12) - a to 1 (2 in LE).
+
+  %pf = call i8* @memchr(i8* %p1, i32 102, i64 12)
+  %ipf = ptrtoint i8* %pf to i64
+  %offf = sub i64 %ipf, %ip0
+  %pstor1 = getelementptr i64, i64* %pcmp, i64 1
+  store i64 %offf, i64* %pstor1
+
+; Fold memchr(a + 1, 'g', 12) - a to 2 (1 in LE).
+
+  %pg = call i8* @memchr(i8* %p1, i32 103, i64 12)
+  %ipg = ptrtoint i8* %pg to i64
+  %offg = sub i64 %ipg, %ip0
+  %pstor2 = getelementptr i64, i64* %pcmp, i64 2
+  store i64 %offg, i64* %pstor2
+
+; Fold memchr(a + 1, 'h', 12) - a to 3 (0 in LE).
+
+  %ph = call i8* @memchr(i8* %p1, i32 104, i64 12)
+  %iph = ptrtoint i8* %ph to i64
+  %offh = sub i64 %iph, %ip0
+  %pstor3 = getelementptr i64, i64* %pcmp, i64 3
+  store i64 %offh, i64* %pstor3
+
+; Fold memchr(a + 1, 'a', 12) to null in both BE and LE.
+
+  %pa = call i8* @memchr(i8* %p1, i32 97, i64 12)
+  %ipa = ptrtoint i8* %pa to i64
+  %pstor4 = getelementptr i64, i64* %pcmp, i64 4
+  store i64 %ipa, i64* %pstor4
+
+; Fold memchr(a + 1, 'd', 12) to null in both BE and LE.
+
+  %pd = call i8* @memchr(i8* %p1, i32 100, i64 12)
+  %ipd = ptrtoint i8* %pd to i64
+  %pstor5 = getelementptr i64, i64* %pcmp, i64 5
+  store i64 %ipd, i64* %pstor5
+
+  ret void
+}

diff  --git a/llvm/test/Transforms/InstCombine/memcmp-3.ll b/llvm/test/Transforms/InstCombine/memcmp-3.ll
new file mode 100644
index 000000000000..143a5a6b0950
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/memcmp-3.ll
@@ -0,0 +1,253 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; Verify that calls to memcmp with arrays of elements larger than char
+; are folded correctly.
+; RUN: opt < %s -passes=instcombine -S -data-layout="E" | FileCheck %s --check-prefixes=BE
+; RUN: opt < %s -passes=instcombine -S -data-layout="e" | FileCheck %s --check-prefixes=LE
+
+declare i32 @memcmp(i8*, i8*, i64)
+
+; BE representation: { 'a', 'b', 'c', ..., 'f', 'g', 'h' }
+; LE representation: { 'b', 'a', 'd', ..., 'e', 'h', 'g' }
+ at ia6a = constant [4 x i16] [i16 24930, i16 25444, i16 25958, i16 26472]
+
+; Same as the BE representation above except ending in "gg".
+ at i8a = constant [8 x i8] c"abcdefgg"
+
+; Fold memcmp(ia6a, i8a, N) for N in [0, 8].
+
+define void @fold_memcmp_ia6a_i8a(i32* %pcmp) {
+; BE-LABEL: @fold_memcmp_ia6a_i8a(
+; BE-NEXT:    store i32 0, i32* [[PCMP:%.*]], align 4
+; BE-NEXT:    [[PSTOR1:%.*]] = getelementptr i32, i32* [[PCMP]], i64 1
+; BE-NEXT:    store i32 0, i32* [[PSTOR1]], align 4
+; BE-NEXT:    [[CMP2:%.*]] = call i32 @memcmp(i8* noundef nonnull dereferenceable(2) bitcast ([4 x i16]* @ia6a to i8*), i8* noundef nonnull dereferenceable(2) getelementptr inbounds ([8 x i8], [8 x i8]* @i8a, i64 0, i64 0), i64 2)
+; BE-NEXT:    [[PSTOR2:%.*]] = getelementptr i32, i32* [[PCMP]], i64 2
+; BE-NEXT:    store i32 [[CMP2]], i32* [[PSTOR2]], align 4
+; BE-NEXT:    [[CMP3:%.*]] = call i32 @memcmp(i8* noundef nonnull dereferenceable(3) bitcast ([4 x i16]* @ia6a to i8*), i8* noundef nonnull dereferenceable(3) getelementptr inbounds ([8 x i8], [8 x i8]* @i8a, i64 0, i64 0), i64 3)
+; BE-NEXT:    [[PSTOR3:%.*]] = getelementptr i32, i32* [[PCMP]], i64 3
+; BE-NEXT:    store i32 [[CMP3]], i32* [[PSTOR3]], align 4
+; BE-NEXT:    [[CMP4:%.*]] = call i32 @memcmp(i8* noundef nonnull dereferenceable(4) bitcast ([4 x i16]* @ia6a to i8*), i8* noundef nonnull dereferenceable(4) getelementptr inbounds ([8 x i8], [8 x i8]* @i8a, i64 0, i64 0), i64 4)
+; BE-NEXT:    [[PSTOR4:%.*]] = getelementptr i32, i32* [[PCMP]], i64 4
+; BE-NEXT:    store i32 [[CMP4]], i32* [[PSTOR4]], align 4
+; BE-NEXT:    [[CMP5:%.*]] = call i32 @memcmp(i8* noundef nonnull dereferenceable(5) bitcast ([4 x i16]* @ia6a to i8*), i8* noundef nonnull dereferenceable(5) getelementptr inbounds ([8 x i8], [8 x i8]* @i8a, i64 0, i64 0), i64 5)
+; BE-NEXT:    [[PSTOR5:%.*]] = getelementptr i32, i32* [[PCMP]], i64 5
+; BE-NEXT:    store i32 [[CMP5]], i32* [[PSTOR5]], align 4
+; BE-NEXT:    [[CMP6:%.*]] = call i32 @memcmp(i8* noundef nonnull dereferenceable(6) bitcast ([4 x i16]* @ia6a to i8*), i8* noundef nonnull dereferenceable(6) getelementptr inbounds ([8 x i8], [8 x i8]* @i8a, i64 0, i64 0), i64 6)
+; BE-NEXT:    [[PSTOR6:%.*]] = getelementptr i32, i32* [[PCMP]], i64 6
+; BE-NEXT:    store i32 [[CMP6]], i32* [[PSTOR6]], align 4
+; BE-NEXT:    [[CMP7:%.*]] = call i32 @memcmp(i8* noundef nonnull dereferenceable(7) bitcast ([4 x i16]* @ia6a to i8*), i8* noundef nonnull dereferenceable(7) getelementptr inbounds ([8 x i8], [8 x i8]* @i8a, i64 0, i64 0), i64 7)
+; BE-NEXT:    [[PSTOR7:%.*]] = getelementptr i32, i32* [[PCMP]], i64 7
+; BE-NEXT:    store i32 [[CMP7]], i32* [[PSTOR7]], align 4
+; BE-NEXT:    [[CMP8:%.*]] = call i32 @memcmp(i8* noundef nonnull dereferenceable(8) bitcast ([4 x i16]* @ia6a to i8*), i8* noundef nonnull dereferenceable(8) getelementptr inbounds ([8 x i8], [8 x i8]* @i8a, i64 0, i64 0), i64 8)
+; BE-NEXT:    [[PSTOR8:%.*]] = getelementptr i32, i32* [[PCMP]], i64 8
+; BE-NEXT:    store i32 [[CMP8]], i32* [[PSTOR8]], align 4
+; BE-NEXT:    ret void
+;
+; LE-LABEL: @fold_memcmp_ia6a_i8a(
+; LE-NEXT:    store i32 0, i32* [[PCMP:%.*]], align 4
+; LE-NEXT:    [[PSTOR1:%.*]] = getelementptr i32, i32* [[PCMP]], i64 1
+; LE-NEXT:    store i32 1, i32* [[PSTOR1]], align 4
+; LE-NEXT:    [[CMP2:%.*]] = call i32 @memcmp(i8* noundef nonnull dereferenceable(2) bitcast ([4 x i16]* @ia6a to i8*), i8* noundef nonnull dereferenceable(2) getelementptr inbounds ([8 x i8], [8 x i8]* @i8a, i64 0, i64 0), i64 2)
+; LE-NEXT:    [[PSTOR2:%.*]] = getelementptr i32, i32* [[PCMP]], i64 2
+; LE-NEXT:    store i32 [[CMP2]], i32* [[PSTOR2]], align 4
+; LE-NEXT:    [[CMP3:%.*]] = call i32 @memcmp(i8* noundef nonnull dereferenceable(3) bitcast ([4 x i16]* @ia6a to i8*), i8* noundef nonnull dereferenceable(3) getelementptr inbounds ([8 x i8], [8 x i8]* @i8a, i64 0, i64 0), i64 3)
+; LE-NEXT:    [[PSTOR3:%.*]] = getelementptr i32, i32* [[PCMP]], i64 3
+; LE-NEXT:    store i32 [[CMP3]], i32* [[PSTOR3]], align 4
+; LE-NEXT:    [[CMP4:%.*]] = call i32 @memcmp(i8* noundef nonnull dereferenceable(4) bitcast ([4 x i16]* @ia6a to i8*), i8* noundef nonnull dereferenceable(4) getelementptr inbounds ([8 x i8], [8 x i8]* @i8a, i64 0, i64 0), i64 4)
+; LE-NEXT:    [[PSTOR4:%.*]] = getelementptr i32, i32* [[PCMP]], i64 4
+; LE-NEXT:    store i32 [[CMP4]], i32* [[PSTOR4]], align 4
+; LE-NEXT:    [[CMP5:%.*]] = call i32 @memcmp(i8* noundef nonnull dereferenceable(5) bitcast ([4 x i16]* @ia6a to i8*), i8* noundef nonnull dereferenceable(5) getelementptr inbounds ([8 x i8], [8 x i8]* @i8a, i64 0, i64 0), i64 5)
+; LE-NEXT:    [[PSTOR5:%.*]] = getelementptr i32, i32* [[PCMP]], i64 5
+; LE-NEXT:    store i32 [[CMP5]], i32* [[PSTOR5]], align 4
+; LE-NEXT:    [[CMP6:%.*]] = call i32 @memcmp(i8* noundef nonnull dereferenceable(6) bitcast ([4 x i16]* @ia6a to i8*), i8* noundef nonnull dereferenceable(6) getelementptr inbounds ([8 x i8], [8 x i8]* @i8a, i64 0, i64 0), i64 6)
+; LE-NEXT:    [[PSTOR6:%.*]] = getelementptr i32, i32* [[PCMP]], i64 6
+; LE-NEXT:    store i32 [[CMP6]], i32* [[PSTOR6]], align 4
+; LE-NEXT:    [[CMP7:%.*]] = call i32 @memcmp(i8* noundef nonnull dereferenceable(7) bitcast ([4 x i16]* @ia6a to i8*), i8* noundef nonnull dereferenceable(7) getelementptr inbounds ([8 x i8], [8 x i8]* @i8a, i64 0, i64 0), i64 7)
+; LE-NEXT:    [[PSTOR7:%.*]] = getelementptr i32, i32* [[PCMP]], i64 7
+; LE-NEXT:    store i32 [[CMP7]], i32* [[PSTOR7]], align 4
+; LE-NEXT:    [[CMP8:%.*]] = call i32 @memcmp(i8* noundef nonnull dereferenceable(8) bitcast ([4 x i16]* @ia6a to i8*), i8* noundef nonnull dereferenceable(8) getelementptr inbounds ([8 x i8], [8 x i8]* @i8a, i64 0, i64 0), i64 8)
+; LE-NEXT:    [[PSTOR8:%.*]] = getelementptr i32, i32* [[PCMP]], i64 8
+; LE-NEXT:    store i32 [[CMP8]], i32* [[PSTOR8]], align 4
+; LE-NEXT:    ret void
+;
+  %p0 = getelementptr [4 x i16], [4 x i16]* @ia6a, i64 0, i64 0
+  %p1 = bitcast i16* %p0 to i8*
+  %q = getelementptr [8 x i8], [8 x i8]* @i8a, i64 0, i64 0
+
+  %cmp0 = call i32 @memcmp(i8* %p1, i8* %q, i64 0)
+  %pstor0 = getelementptr i32, i32* %pcmp, i64 0
+  store i32 %cmp0, i32* %pstor0
+
+  %cmp1 = call i32 @memcmp(i8* %p1, i8* %q, i64 1)
+  %pstor1 = getelementptr i32, i32* %pcmp, i64 1
+  store i32 %cmp1, i32* %pstor1
+
+  %cmp2 = call i32 @memcmp(i8* %p1, i8* %q, i64 2)
+  %pstor2 = getelementptr i32, i32* %pcmp, i64 2
+  store i32 %cmp2, i32* %pstor2
+
+  %cmp3 = call i32 @memcmp(i8* %p1, i8* %q, i64 3)
+  %pstor3 = getelementptr i32, i32* %pcmp, i64 3
+  store i32 %cmp3, i32* %pstor3
+
+  %cmp4 = call i32 @memcmp(i8* %p1, i8* %q, i64 4)
+  %pstor4 = getelementptr i32, i32* %pcmp, i64 4
+  store i32 %cmp4, i32* %pstor4
+
+  %cmp5 = call i32 @memcmp(i8* %p1, i8* %q, i64 5)
+  %pstor5 = getelementptr i32, i32* %pcmp, i64 5
+  store i32 %cmp5, i32* %pstor5
+
+  %cmp6 = call i32 @memcmp(i8* %p1, i8* %q, i64 6)
+  %pstor6 = getelementptr i32, i32* %pcmp, i64 6
+  store i32 %cmp6, i32* %pstor6
+
+  %cmp7 = call i32 @memcmp(i8* %p1, i8* %q, i64 7)
+  %pstor7 = getelementptr i32, i32* %pcmp, i64 7
+  store i32 %cmp7, i32* %pstor7
+
+  %cmp8 = call i32 @memcmp(i8* %p1, i8* %q, i64 8)
+  %pstor8 = getelementptr i32, i32* %pcmp, i64 8
+  store i32 %cmp8, i32* %pstor8
+
+  ret void
+}
+
+
+; Fold memcmp(ia6a + 1, i8a + 2, N) for N in [0, 6].
+
+define void @fold_memcmp_ia6a_p1_i8a_p1(i32* %pcmp) {
+; BE-LABEL: @fold_memcmp_ia6a_p1_i8a_p1(
+; BE-NEXT:    store i32 0, i32* [[PCMP:%.*]], align 4
+; BE-NEXT:    [[PSTOR1:%.*]] = getelementptr i32, i32* [[PCMP]], i64 1
+; BE-NEXT:    store i32 1, i32* [[PSTOR1]], align 4
+; BE-NEXT:    [[CMP2:%.*]] = call i32 @memcmp(i8* noundef nonnull dereferenceable(2) bitcast (i16* getelementptr inbounds ([4 x i16], [4 x i16]* @ia6a, i64 0, i64 1) to i8*), i8* noundef nonnull dereferenceable(2) getelementptr inbounds ([8 x i8], [8 x i8]* @i8a, i64 0, i64 1), i64 2)
+; BE-NEXT:    [[PSTOR2:%.*]] = getelementptr i32, i32* [[PCMP]], i64 2
+; BE-NEXT:    store i32 [[CMP2]], i32* [[PSTOR2]], align 4
+; BE-NEXT:    [[CMP3:%.*]] = call i32 @memcmp(i8* noundef nonnull dereferenceable(3) bitcast (i16* getelementptr inbounds ([4 x i16], [4 x i16]* @ia6a, i64 0, i64 1) to i8*), i8* noundef nonnull dereferenceable(3) getelementptr inbounds ([8 x i8], [8 x i8]* @i8a, i64 0, i64 1), i64 3)
+; BE-NEXT:    [[PSTOR3:%.*]] = getelementptr i32, i32* [[PCMP]], i64 3
+; BE-NEXT:    store i32 [[CMP3]], i32* [[PSTOR3]], align 4
+; BE-NEXT:    [[CMP4:%.*]] = call i32 @memcmp(i8* noundef nonnull dereferenceable(4) bitcast (i16* getelementptr inbounds ([4 x i16], [4 x i16]* @ia6a, i64 0, i64 1) to i8*), i8* noundef nonnull dereferenceable(4) getelementptr inbounds ([8 x i8], [8 x i8]* @i8a, i64 0, i64 1), i64 4)
+; BE-NEXT:    [[PSTOR4:%.*]] = getelementptr i32, i32* [[PCMP]], i64 4
+; BE-NEXT:    store i32 [[CMP4]], i32* [[PSTOR4]], align 4
+; BE-NEXT:    [[CMP5:%.*]] = call i32 @memcmp(i8* noundef nonnull dereferenceable(5) bitcast (i16* getelementptr inbounds ([4 x i16], [4 x i16]* @ia6a, i64 0, i64 1) to i8*), i8* noundef nonnull dereferenceable(5) getelementptr inbounds ([8 x i8], [8 x i8]* @i8a, i64 0, i64 1), i64 5)
+; BE-NEXT:    [[PSTOR5:%.*]] = getelementptr i32, i32* [[PCMP]], i64 5
+; BE-NEXT:    store i32 [[CMP5]], i32* [[PSTOR5]], align 4
+; BE-NEXT:    [[CMP6:%.*]] = call i32 @memcmp(i8* noundef nonnull dereferenceable(6) bitcast (i16* getelementptr inbounds ([4 x i16], [4 x i16]* @ia6a, i64 0, i64 1) to i8*), i8* noundef nonnull dereferenceable(6) getelementptr inbounds ([8 x i8], [8 x i8]* @i8a, i64 0, i64 1), i64 6)
+; BE-NEXT:    [[PSTOR6:%.*]] = getelementptr i32, i32* [[PCMP]], i64 6
+; BE-NEXT:    store i32 [[CMP6]], i32* [[PSTOR6]], align 4
+; BE-NEXT:    ret void
+;
+; LE-LABEL: @fold_memcmp_ia6a_p1_i8a_p1(
+; LE-NEXT:    store i32 0, i32* [[PCMP:%.*]], align 4
+; LE-NEXT:    [[PSTOR1:%.*]] = getelementptr i32, i32* [[PCMP]], i64 1
+; LE-NEXT:    store i32 2, i32* [[PSTOR1]], align 4
+; LE-NEXT:    [[CMP2:%.*]] = call i32 @memcmp(i8* noundef nonnull dereferenceable(2) bitcast (i16* getelementptr inbounds ([4 x i16], [4 x i16]* @ia6a, i64 0, i64 1) to i8*), i8* noundef nonnull dereferenceable(2) getelementptr inbounds ([8 x i8], [8 x i8]* @i8a, i64 0, i64 1), i64 2)
+; LE-NEXT:    [[PSTOR2:%.*]] = getelementptr i32, i32* [[PCMP]], i64 2
+; LE-NEXT:    store i32 [[CMP2]], i32* [[PSTOR2]], align 4
+; LE-NEXT:    [[CMP3:%.*]] = call i32 @memcmp(i8* noundef nonnull dereferenceable(3) bitcast (i16* getelementptr inbounds ([4 x i16], [4 x i16]* @ia6a, i64 0, i64 1) to i8*), i8* noundef nonnull dereferenceable(3) getelementptr inbounds ([8 x i8], [8 x i8]* @i8a, i64 0, i64 1), i64 3)
+; LE-NEXT:    [[PSTOR3:%.*]] = getelementptr i32, i32* [[PCMP]], i64 3
+; LE-NEXT:    store i32 [[CMP3]], i32* [[PSTOR3]], align 4
+; LE-NEXT:    [[CMP4:%.*]] = call i32 @memcmp(i8* noundef nonnull dereferenceable(4) bitcast (i16* getelementptr inbounds ([4 x i16], [4 x i16]* @ia6a, i64 0, i64 1) to i8*), i8* noundef nonnull dereferenceable(4) getelementptr inbounds ([8 x i8], [8 x i8]* @i8a, i64 0, i64 1), i64 4)
+; LE-NEXT:    [[PSTOR4:%.*]] = getelementptr i32, i32* [[PCMP]], i64 4
+; LE-NEXT:    store i32 [[CMP4]], i32* [[PSTOR4]], align 4
+; LE-NEXT:    [[CMP5:%.*]] = call i32 @memcmp(i8* noundef nonnull dereferenceable(5) bitcast (i16* getelementptr inbounds ([4 x i16], [4 x i16]* @ia6a, i64 0, i64 1) to i8*), i8* noundef nonnull dereferenceable(5) getelementptr inbounds ([8 x i8], [8 x i8]* @i8a, i64 0, i64 1), i64 5)
+; LE-NEXT:    [[PSTOR5:%.*]] = getelementptr i32, i32* [[PCMP]], i64 5
+; LE-NEXT:    store i32 [[CMP5]], i32* [[PSTOR5]], align 4
+; LE-NEXT:    [[CMP6:%.*]] = call i32 @memcmp(i8* noundef nonnull dereferenceable(6) bitcast (i16* getelementptr inbounds ([4 x i16], [4 x i16]* @ia6a, i64 0, i64 1) to i8*), i8* noundef nonnull dereferenceable(6) getelementptr inbounds ([8 x i8], [8 x i8]* @i8a, i64 0, i64 1), i64 6)
+; LE-NEXT:    [[PSTOR6:%.*]] = getelementptr i32, i32* [[PCMP]], i64 6
+; LE-NEXT:    store i32 [[CMP6]], i32* [[PSTOR6]], align 4
+; LE-NEXT:    ret void
+;
+  %p0 = getelementptr [4 x i16], [4 x i16]* @ia6a, i64 0, i64 1
+  %p1 = bitcast i16* %p0 to i8*
+  %q = getelementptr [8 x i8], [8 x i8]* @i8a, i64 0, i64 1
+
+  %cmp0 = call i32 @memcmp(i8* %p1, i8* %q, i64 0)
+  %pstor0 = getelementptr i32, i32* %pcmp, i64 0
+  store i32 %cmp0, i32* %pstor0
+
+  %cmp1 = call i32 @memcmp(i8* %p1, i8* %q, i64 1)
+  %pstor1 = getelementptr i32, i32* %pcmp, i64 1
+  store i32 %cmp1, i32* %pstor1
+
+  %cmp2 = call i32 @memcmp(i8* %p1, i8* %q, i64 2)
+  %pstor2 = getelementptr i32, i32* %pcmp, i64 2
+  store i32 %cmp2, i32* %pstor2
+
+  %cmp3 = call i32 @memcmp(i8* %p1, i8* %q, i64 3)
+  %pstor3 = getelementptr i32, i32* %pcmp, i64 3
+  store i32 %cmp3, i32* %pstor3
+
+  %cmp4 = call i32 @memcmp(i8* %p1, i8* %q, i64 4)
+  %pstor4 = getelementptr i32, i32* %pcmp, i64 4
+  store i32 %cmp4, i32* %pstor4
+
+  %cmp5 = call i32 @memcmp(i8* %p1, i8* %q, i64 5)
+  %pstor5 = getelementptr i32, i32* %pcmp, i64 5
+  store i32 %cmp5, i32* %pstor5
+
+  %cmp6 = call i32 @memcmp(i8* %p1, i8* %q, i64 6)
+  %pstor6 = getelementptr i32, i32* %pcmp, i64 6
+  store i32 %cmp6, i32* %pstor6
+
+  ret void
+}
+
+
+; Don't fold calls with excessive sizes.
+
+define void @call_memcmp_too_big(i32* %pcmp) {
+; BE-LABEL: @call_memcmp_too_big(
+; BE-NEXT:    [[CMP9:%.*]] = call i32 @memcmp(i8* noundef nonnull dereferenceable(9) bitcast ([4 x i16]* @ia6a to i8*), i8* noundef nonnull dereferenceable(9) getelementptr inbounds ([8 x i8], [8 x i8]* @i8a, i64 0, i64 0), i64 9)
+; BE-NEXT:    store i32 [[CMP9]], i32* [[PCMP:%.*]], align 4
+; BE-NEXT:    [[CMPM1:%.*]] = call i32 @memcmp(i8* noundef nonnull dereferenceable(18446744073709551615) bitcast ([4 x i16]* @ia6a to i8*), i8* noundef nonnull dereferenceable(18446744073709551615) getelementptr inbounds ([8 x i8], [8 x i8]* @i8a, i64 0, i64 0), i64 -1)
+; BE-NEXT:    [[PSTORM1:%.*]] = getelementptr i32, i32* [[PCMP]], i64 1
+; BE-NEXT:    store i32 [[CMPM1]], i32* [[PSTORM1]], align 4
+; BE-NEXT:    [[CMPX2:%.*]] = call i32 @memcmp(i8* noundef nonnull dereferenceable(8) bitcast ([4 x i16]* @ia6a to i8*), i8* noundef nonnull dereferenceable(8) getelementptr inbounds ([8 x i8], [8 x i8]* @i8a, i64 0, i64 1), i64 8)
+; BE-NEXT:    [[PSTORX2:%.*]] = getelementptr i32, i32* [[PCMP]], i64 2
+; BE-NEXT:    store i32 [[CMPX2]], i32* [[PSTORX2]], align 4
+; BE-NEXT:    [[CMPX1:%.*]] = call i32 @memcmp(i8* noundef nonnull dereferenceable(8) getelementptr (i8, i8* bitcast ([4 x i16]* @ia6a to i8*), i64 1), i8* noundef nonnull dereferenceable(8) getelementptr inbounds ([8 x i8], [8 x i8]* @i8a, i64 0, i64 0), i64 8)
+; BE-NEXT:    [[PSTORX1:%.*]] = getelementptr i32, i32* [[PCMP]], i64 2
+; BE-NEXT:    store i32 [[CMPX1]], i32* [[PSTORX1]], align 4
+; BE-NEXT:    ret void
+;
+; LE-LABEL: @call_memcmp_too_big(
+; LE-NEXT:    [[CMP9:%.*]] = call i32 @memcmp(i8* noundef nonnull dereferenceable(9) bitcast ([4 x i16]* @ia6a to i8*), i8* noundef nonnull dereferenceable(9) getelementptr inbounds ([8 x i8], [8 x i8]* @i8a, i64 0, i64 0), i64 9)
+; LE-NEXT:    store i32 [[CMP9]], i32* [[PCMP:%.*]], align 4
+; LE-NEXT:    [[CMPM1:%.*]] = call i32 @memcmp(i8* noundef nonnull dereferenceable(18446744073709551615) bitcast ([4 x i16]* @ia6a to i8*), i8* noundef nonnull dereferenceable(18446744073709551615) getelementptr inbounds ([8 x i8], [8 x i8]* @i8a, i64 0, i64 0), i64 -1)
+; LE-NEXT:    [[PSTORM1:%.*]] = getelementptr i32, i32* [[PCMP]], i64 1
+; LE-NEXT:    store i32 [[CMPM1]], i32* [[PSTORM1]], align 4
+; LE-NEXT:    [[CMPX2:%.*]] = call i32 @memcmp(i8* noundef nonnull dereferenceable(8) bitcast ([4 x i16]* @ia6a to i8*), i8* noundef nonnull dereferenceable(8) getelementptr inbounds ([8 x i8], [8 x i8]* @i8a, i64 0, i64 1), i64 8)
+; LE-NEXT:    [[PSTORX2:%.*]] = getelementptr i32, i32* [[PCMP]], i64 2
+; LE-NEXT:    store i32 [[CMPX2]], i32* [[PSTORX2]], align 4
+; LE-NEXT:    [[CMPX1:%.*]] = call i32 @memcmp(i8* noundef nonnull dereferenceable(8) getelementptr (i8, i8* bitcast ([4 x i16]* @ia6a to i8*), i64 1), i8* noundef nonnull dereferenceable(8) getelementptr inbounds ([8 x i8], [8 x i8]* @i8a, i64 0, i64 0), i64 8)
+; LE-NEXT:    [[PSTORX1:%.*]] = getelementptr i32, i32* [[PCMP]], i64 2
+; LE-NEXT:    store i32 [[CMPX1]], i32* [[PSTORX1]], align 4
+; LE-NEXT:    ret void
+;
+  %p0 = getelementptr [4 x i16], [4 x i16]* @ia6a, i64 0, i64 0
+  %p1 = bitcast i16* %p0 to i8*
+  %q = getelementptr [8 x i8], [8 x i8]* @i8a, i64 0, i64 0
+
+  %cmp9 = call i32 @memcmp(i8* %p1, i8* %q, i64 9)
+  %pstor9 = getelementptr i32, i32* %pcmp, i64 0
+  store i32 %cmp9, i32* %pstor9
+
+  %cmpm1 = call i32 @memcmp(i8* %p1, i8* %q, i64 -1)
+  %pstorm1 = getelementptr i32, i32* %pcmp, i64 1
+  store i32 %cmpm1, i32* %pstorm1
+
+  ; Exercise size that's greater than just one of the arrays.
+  %q2 = getelementptr [8 x i8], [8 x i8]* @i8a, i64 0, i64 1
+  %cmpx2 = call i32 @memcmp(i8* %p1, i8* %q2, i64 8)
+  %pstorx2 = getelementptr i32, i32* %pcmp, i64 2
+  store i32 %cmpx2, i32* %pstorx2
+
+  %p2 = getelementptr i8, i8* %p1, i64 1
+  %cmpx1 = call i32 @memcmp(i8* %p2, i8* %q, i64 8)
+  %pstorx1 = getelementptr i32, i32* %pcmp, i64 2
+  store i32 %cmpx1, i32* %pstorx1
+
+  ret void
+}

diff  --git a/llvm/test/Transforms/InstCombine/memcmp-4.ll b/llvm/test/Transforms/InstCombine/memcmp-4.ll
new file mode 100644
index 000000000000..50c64f6e6413
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/memcmp-4.ll
@@ -0,0 +1,87 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; Verify that calls to memcmp with counts in excess of the array sizes are
+; either folded gracefully or expanded to library calls.
+;
+; RUN: opt < %s -passes=instcombine -S -data-layout="E" | FileCheck %s --check-prefixes=BE
+; RUN: opt < %s -passes=instcombine -S -data-layout="e" | FileCheck %s --check-prefixes=LE
+
+declare i32 @memcmp(i8*, i8*, i64)
+
+ at ia16a = constant [4 x i16] [i16 24930, i16 25444, i16 25958, i16 26472]
+ at ia16b = constant [5 x i16] [i16 24930, i16 25444, i16 25958, i16 26472, i16 26992]
+ at ia16c = constant [6 x i16] [i16 24930, i16 25444, i16 25958, i16 26472, i16 26993, i16 29042]
+
+
+; Fold calls with a count in excess of the size of one of the arrays that
+; 
diff er.  They're strictly undefined but folding the result to the expected
+; value (analogous to strncmp) is safer than letting a SIMD library
+; implementation return a bogus value.
+
+define void @fold_memcmp_too_big(i32* %pcmp) {
+; BE-LABEL: @fold_memcmp_too_big(
+; BE-NEXT:    [[CMP_BC:%.*]] = call i32 @memcmp(i8* noundef nonnull dereferenceable(12) bitcast ([5 x i16]* @ia16b to i8*), i8* noundef nonnull dereferenceable(12) bitcast ([6 x i16]* @ia16c to i8*), i64 12)
+; BE-NEXT:    store i32 [[CMP_BC]], i32* [[PCMP:%.*]], align 4
+; BE-NEXT:    [[CMP_CB:%.*]] = call i32 @memcmp(i8* noundef nonnull dereferenceable(12) bitcast ([6 x i16]* @ia16c to i8*), i8* noundef nonnull dereferenceable(12) bitcast ([5 x i16]* @ia16b to i8*), i64 12)
+; BE-NEXT:    [[PSTOR_CB:%.*]] = getelementptr i32, i32* [[PCMP]], i64 1
+; BE-NEXT:    store i32 [[CMP_CB]], i32* [[PSTOR_CB]], align 4
+; BE-NEXT:    ret void
+;
+; LE-LABEL: @fold_memcmp_too_big(
+; LE-NEXT:    [[CMP_BC:%.*]] = call i32 @memcmp(i8* noundef nonnull dereferenceable(12) bitcast ([5 x i16]* @ia16b to i8*), i8* noundef nonnull dereferenceable(12) bitcast ([6 x i16]* @ia16c to i8*), i64 12)
+; LE-NEXT:    store i32 [[CMP_BC]], i32* [[PCMP:%.*]], align 4
+; LE-NEXT:    [[CMP_CB:%.*]] = call i32 @memcmp(i8* noundef nonnull dereferenceable(12) bitcast ([6 x i16]* @ia16c to i8*), i8* noundef nonnull dereferenceable(12) bitcast ([5 x i16]* @ia16b to i8*), i64 12)
+; LE-NEXT:    [[PSTOR_CB:%.*]] = getelementptr i32, i32* [[PCMP]], i64 1
+; LE-NEXT:    store i32 [[CMP_CB]], i32* [[PSTOR_CB]], align 4
+; LE-NEXT:    ret void
+;
+  %p0 = getelementptr [5 x i16], [5 x i16]* @ia16b, i64 0, i64 0
+  %p1 = bitcast i16* %p0 to i8*
+  %q0 = getelementptr [6 x i16], [6 x i16]* @ia16c, i64 0, i64 0
+  %q1 = bitcast i16* %q0 to i8*
+
+  %cmp_bc = call i32 @memcmp(i8* %p1, i8* %q1, i64 12)
+  %pstor_bc = getelementptr i32, i32* %pcmp, i64 0
+  store i32 %cmp_bc, i32* %pstor_bc
+
+  %cmp_cb = call i32 @memcmp(i8* %q1, i8* %p1, i64 12)
+  %pstor_cb = getelementptr i32, i32* %pcmp, i64 1
+  store i32 %cmp_cb, i32* %pstor_cb
+
+  ret void
+}
+
+
+; Don't fold calls with excessive byte counts of arrays with the same bytes.
+
+define void @call_memcmp_too_big(i32* %pcmp) {
+; BE-LABEL: @call_memcmp_too_big(
+; BE-NEXT:    [[CMP_AB_9:%.*]] = call i32 @memcmp(i8* noundef nonnull dereferenceable(9) bitcast ([4 x i16]* @ia16a to i8*), i8* noundef nonnull dereferenceable(9) bitcast ([5 x i16]* @ia16b to i8*), i64 9)
+; BE-NEXT:    store i32 [[CMP_AB_9]], i32* [[PCMP:%.*]], align 4
+; BE-NEXT:    [[CMP_AB_M1:%.*]] = call i32 @memcmp(i8* noundef nonnull dereferenceable(18446744073709551615) bitcast ([4 x i16]* @ia16a to i8*), i8* noundef nonnull dereferenceable(18446744073709551615) bitcast ([5 x i16]* @ia16b to i8*), i64 -1)
+; BE-NEXT:    [[PSTOR_AB_M1:%.*]] = getelementptr i32, i32* [[PCMP]], i64 1
+; BE-NEXT:    store i32 [[CMP_AB_M1]], i32* [[PSTOR_AB_M1]], align 4
+; BE-NEXT:    ret void
+;
+; LE-LABEL: @call_memcmp_too_big(
+; LE-NEXT:    [[CMP_AB_9:%.*]] = call i32 @memcmp(i8* noundef nonnull dereferenceable(9) bitcast ([4 x i16]* @ia16a to i8*), i8* noundef nonnull dereferenceable(9) bitcast ([5 x i16]* @ia16b to i8*), i64 9)
+; LE-NEXT:    store i32 [[CMP_AB_9]], i32* [[PCMP:%.*]], align 4
+; LE-NEXT:    [[CMP_AB_M1:%.*]] = call i32 @memcmp(i8* noundef nonnull dereferenceable(18446744073709551615) bitcast ([4 x i16]* @ia16a to i8*), i8* noundef nonnull dereferenceable(18446744073709551615) bitcast ([5 x i16]* @ia16b to i8*), i64 -1)
+; LE-NEXT:    [[PSTOR_AB_M1:%.*]] = getelementptr i32, i32* [[PCMP]], i64 1
+; LE-NEXT:    store i32 [[CMP_AB_M1]], i32* [[PSTOR_AB_M1]], align 4
+; LE-NEXT:    ret void
+;
+  %p0 = getelementptr [4 x i16], [4 x i16]* @ia16a, i64 0, i64 0
+  %p1 = bitcast i16* %p0 to i8*
+  %q0 = getelementptr [5 x i16], [5 x i16]* @ia16b, i64 0, i64 0
+  %q1 = bitcast i16* %q0 to i8*
+
+  %cmp_ab_9 = call i32 @memcmp(i8* %p1, i8* %q1, i64 9)
+  %pstor_ab_9 = getelementptr i32, i32* %pcmp, i64 0
+  store i32 %cmp_ab_9, i32* %pstor_ab_9
+
+  %cmp_ab_m1 = call i32 @memcmp(i8* %p1, i8* %q1, i64 -1)
+  %pstor_ab_m1 = getelementptr i32, i32* %pcmp, i64 1
+  store i32 %cmp_ab_m1, i32* %pstor_ab_m1
+
+  ret void
+}

diff  --git a/llvm/test/Transforms/InstCombine/memrchr-5.ll b/llvm/test/Transforms/InstCombine/memrchr-5.ll
new file mode 100644
index 000000000000..caae72f68e3d
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/memrchr-5.ll
@@ -0,0 +1,389 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; Verify that calls to memrchr with arrays of elements larger than char
+; are folded correctly.
+; RUN: opt < %s -passes=instcombine -S -data-layout="E" | FileCheck %s --check-prefixes=BE
+; RUN: opt < %s -passes=instcombine -S -data-layout="e" | FileCheck %s --check-prefixes=LE
+
+declare i8* @memrchr(i8*, i32, i64)
+
+; BE representation: { 'a', 'b', 'c', 'd', 'e', ..., 'p', 'a', 'b', 'c', 'd' }
+; LE representation: { 'd', 'c', 'b', 'a', 'h', ..., 'm', 'd', 'c', 'b', 'a' }
+ at a = constant [5 x i32] [i32 1633837924, i32 1701209960, i32 1768581996, i32 1835954032, i32 1633837924]
+
+
+; Fold memrchr(a, C, 16) for C in ['a', 'd'] U ['o', 'q'].
+
+define void @fold_memrchr_a_16(i64* %pcmp) {
+; BE-LABEL: @fold_memrchr_a_16(
+; BE-NEXT:    [[PA:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(16) bitcast ([5 x i32]* @a to i8*), i32 97, i64 16)
+; BE-NEXT:    [[IPA:%.*]] = ptrtoint i8* [[PA]] to i64
+; BE-NEXT:    [[OFFA:%.*]] = sub i64 [[IPA]], ptrtoint ([5 x i32]* @a to i64)
+; BE-NEXT:    store i64 [[OFFA]], i64* [[PCMP:%.*]], align 4
+; BE-NEXT:    [[PB:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(16) bitcast ([5 x i32]* @a to i8*), i32 98, i64 16)
+; BE-NEXT:    [[IPB:%.*]] = ptrtoint i8* [[PB]] to i64
+; BE-NEXT:    [[OFFB:%.*]] = sub i64 [[IPB]], ptrtoint ([5 x i32]* @a to i64)
+; BE-NEXT:    [[PSTOR1:%.*]] = getelementptr i64, i64* [[PCMP]], i64 1
+; BE-NEXT:    store i64 [[OFFB]], i64* [[PSTOR1]], align 4
+; BE-NEXT:    [[PC:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(16) bitcast ([5 x i32]* @a to i8*), i32 99, i64 16)
+; BE-NEXT:    [[IPC:%.*]] = ptrtoint i8* [[PC]] to i64
+; BE-NEXT:    [[OFFC:%.*]] = sub i64 [[IPC]], ptrtoint ([5 x i32]* @a to i64)
+; BE-NEXT:    [[PSTOR2:%.*]] = getelementptr i64, i64* [[PCMP]], i64 2
+; BE-NEXT:    store i64 [[OFFC]], i64* [[PSTOR2]], align 4
+; BE-NEXT:    [[PD:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(16) bitcast ([5 x i32]* @a to i8*), i32 100, i64 16)
+; BE-NEXT:    [[IPD:%.*]] = ptrtoint i8* [[PD]] to i64
+; BE-NEXT:    [[OFFD:%.*]] = sub i64 [[IPD]], ptrtoint ([5 x i32]* @a to i64)
+; BE-NEXT:    [[PSTOR3:%.*]] = getelementptr i64, i64* [[PCMP]], i64 3
+; BE-NEXT:    store i64 [[OFFD]], i64* [[PSTOR3]], align 4
+; BE-NEXT:    [[PN:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(16) bitcast ([5 x i32]* @a to i8*), i32 110, i64 16)
+; BE-NEXT:    [[IPN:%.*]] = ptrtoint i8* [[PN]] to i64
+; BE-NEXT:    [[OFFN:%.*]] = sub i64 [[IPN]], ptrtoint ([5 x i32]* @a to i64)
+; BE-NEXT:    [[PSTOR4:%.*]] = getelementptr i64, i64* [[PCMP]], i64 4
+; BE-NEXT:    store i64 [[OFFN]], i64* [[PSTOR4]], align 4
+; BE-NEXT:    [[PO:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(16) bitcast ([5 x i32]* @a to i8*), i32 111, i64 16)
+; BE-NEXT:    [[IPO:%.*]] = ptrtoint i8* [[PO]] to i64
+; BE-NEXT:    [[OFFO:%.*]] = sub i64 [[IPO]], ptrtoint ([5 x i32]* @a to i64)
+; BE-NEXT:    [[PSTOR6:%.*]] = getelementptr i64, i64* [[PCMP]], i64 6
+; BE-NEXT:    store i64 [[OFFO]], i64* [[PSTOR6]], align 4
+; BE-NEXT:    [[PP:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(16) bitcast ([5 x i32]* @a to i8*), i32 112, i64 16)
+; BE-NEXT:    [[IPP:%.*]] = ptrtoint i8* [[PP]] to i64
+; BE-NEXT:    [[OFFP:%.*]] = sub i64 [[IPP]], ptrtoint ([5 x i32]* @a to i64)
+; BE-NEXT:    [[PSTOR7:%.*]] = getelementptr i64, i64* [[PCMP]], i64 7
+; BE-NEXT:    store i64 [[OFFP]], i64* [[PSTOR7]], align 4
+; BE-NEXT:    [[PQ:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(16) bitcast ([5 x i32]* @a to i8*), i32 113, i64 16)
+; BE-NEXT:    [[IPQ:%.*]] = ptrtoint i8* [[PQ]] to i64
+; BE-NEXT:    [[PSTOR8:%.*]] = getelementptr i64, i64* [[PCMP]], i64 8
+; BE-NEXT:    store i64 [[IPQ]], i64* [[PSTOR8]], align 4
+; BE-NEXT:    ret void
+;
+; LE-LABEL: @fold_memrchr_a_16(
+; LE-NEXT:    [[PA:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(16) bitcast ([5 x i32]* @a to i8*), i32 97, i64 16)
+; LE-NEXT:    [[IPA:%.*]] = ptrtoint i8* [[PA]] to i64
+; LE-NEXT:    [[OFFA:%.*]] = sub i64 [[IPA]], ptrtoint ([5 x i32]* @a to i64)
+; LE-NEXT:    store i64 [[OFFA]], i64* [[PCMP:%.*]], align 4
+; LE-NEXT:    [[PB:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(16) bitcast ([5 x i32]* @a to i8*), i32 98, i64 16)
+; LE-NEXT:    [[IPB:%.*]] = ptrtoint i8* [[PB]] to i64
+; LE-NEXT:    [[OFFB:%.*]] = sub i64 [[IPB]], ptrtoint ([5 x i32]* @a to i64)
+; LE-NEXT:    [[PSTOR1:%.*]] = getelementptr i64, i64* [[PCMP]], i64 1
+; LE-NEXT:    store i64 [[OFFB]], i64* [[PSTOR1]], align 4
+; LE-NEXT:    [[PC:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(16) bitcast ([5 x i32]* @a to i8*), i32 99, i64 16)
+; LE-NEXT:    [[IPC:%.*]] = ptrtoint i8* [[PC]] to i64
+; LE-NEXT:    [[OFFC:%.*]] = sub i64 [[IPC]], ptrtoint ([5 x i32]* @a to i64)
+; LE-NEXT:    [[PSTOR2:%.*]] = getelementptr i64, i64* [[PCMP]], i64 2
+; LE-NEXT:    store i64 [[OFFC]], i64* [[PSTOR2]], align 4
+; LE-NEXT:    [[PD:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(16) bitcast ([5 x i32]* @a to i8*), i32 100, i64 16)
+; LE-NEXT:    [[IPD:%.*]] = ptrtoint i8* [[PD]] to i64
+; LE-NEXT:    [[OFFD:%.*]] = sub i64 [[IPD]], ptrtoint ([5 x i32]* @a to i64)
+; LE-NEXT:    [[PSTOR3:%.*]] = getelementptr i64, i64* [[PCMP]], i64 3
+; LE-NEXT:    store i64 [[OFFD]], i64* [[PSTOR3]], align 4
+; LE-NEXT:    [[PN:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(16) bitcast ([5 x i32]* @a to i8*), i32 110, i64 16)
+; LE-NEXT:    [[IPN:%.*]] = ptrtoint i8* [[PN]] to i64
+; LE-NEXT:    [[OFFN:%.*]] = sub i64 [[IPN]], ptrtoint ([5 x i32]* @a to i64)
+; LE-NEXT:    [[PSTOR4:%.*]] = getelementptr i64, i64* [[PCMP]], i64 4
+; LE-NEXT:    store i64 [[OFFN]], i64* [[PSTOR4]], align 4
+; LE-NEXT:    [[PO:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(16) bitcast ([5 x i32]* @a to i8*), i32 111, i64 16)
+; LE-NEXT:    [[IPO:%.*]] = ptrtoint i8* [[PO]] to i64
+; LE-NEXT:    [[OFFO:%.*]] = sub i64 [[IPO]], ptrtoint ([5 x i32]* @a to i64)
+; LE-NEXT:    [[PSTOR6:%.*]] = getelementptr i64, i64* [[PCMP]], i64 6
+; LE-NEXT:    store i64 [[OFFO]], i64* [[PSTOR6]], align 4
+; LE-NEXT:    [[PP:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(16) bitcast ([5 x i32]* @a to i8*), i32 112, i64 16)
+; LE-NEXT:    [[IPP:%.*]] = ptrtoint i8* [[PP]] to i64
+; LE-NEXT:    [[OFFP:%.*]] = sub i64 [[IPP]], ptrtoint ([5 x i32]* @a to i64)
+; LE-NEXT:    [[PSTOR7:%.*]] = getelementptr i64, i64* [[PCMP]], i64 7
+; LE-NEXT:    store i64 [[OFFP]], i64* [[PSTOR7]], align 4
+; LE-NEXT:    [[PQ:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(16) bitcast ([5 x i32]* @a to i8*), i32 113, i64 16)
+; LE-NEXT:    [[IPQ:%.*]] = ptrtoint i8* [[PQ]] to i64
+; LE-NEXT:    [[PSTOR8:%.*]] = getelementptr i64, i64* [[PCMP]], i64 8
+; LE-NEXT:    store i64 [[IPQ]], i64* [[PSTOR8]], align 4
+; LE-NEXT:    ret void
+;
+  %p0 = getelementptr [5 x i32], [5 x i32]* @a, i64 0, i64 0
+  %p1 = bitcast i32* %p0 to i8*
+  %ip0 = ptrtoint [5 x i32]* @a to i64
+
+; Fold memrchr(a, 'a', 16) - a to 0 (3 in LE).
+
+  %pa = call i8* @memrchr(i8* %p1, i32 97, i64 16)
+  %ipa = ptrtoint i8* %pa to i64
+  %offa = sub i64 %ipa, %ip0
+  %pstor0 = getelementptr i64, i64* %pcmp, i64 0
+  store i64 %offa, i64* %pstor0
+
+; Fold memrchr(a, 'b', 16) - a to 1 (2 in LE)
+
+  %pb = call i8* @memrchr(i8* %p1, i32 98, i64 16)
+  %ipb = ptrtoint i8* %pb to i64
+  %offb = sub i64 %ipb, %ip0
+  %pstor1 = getelementptr i64, i64* %pcmp, i64 1
+  store i64 %offb, i64* %pstor1
+
+; Fold memrchr(a, 'c', 16) - a to 2 (1 in LE)
+
+  %pc = call i8* @memrchr(i8* %p1, i32 99, i64 16)
+  %ipc = ptrtoint i8* %pc to i64
+  %offc = sub i64 %ipc, %ip0
+  %pstor2 = getelementptr i64, i64* %pcmp, i64 2
+  store i64 %offc, i64* %pstor2
+
+; Fold memrchr(a, 'd', 16) - a to 3 (0 in LE)
+
+  %pd = call i8* @memrchr(i8* %p1, i32 100, i64 16)
+  %ipd = ptrtoint i8* %pd to i64
+  %offd = sub i64 %ipd, %ip0
+  %pstor3 = getelementptr i64, i64* %pcmp, i64 3
+  store i64 %offd, i64* %pstor3
+
+; Fold memrchr(a, 'n', 16) - a to 13 (14 in LE)
+
+  %pn = call i8* @memrchr(i8* %p1, i32 110, i64 16)
+  %ipn = ptrtoint i8* %pn to i64
+  %offn = sub i64 %ipn, %ip0
+  %pstor4 = getelementptr i64, i64* %pcmp, i64 4
+  store i64 %offn, i64* %pstor4
+
+; Fold memrchr(a, 'o', 16) - a to 14 (13 in LE)
+
+  %po = call i8* @memrchr(i8* %p1, i32 111, i64 16)
+  %ipo = ptrtoint i8* %po to i64
+  %offo = sub i64 %ipo, %ip0
+  %pstor6 = getelementptr i64, i64* %pcmp, i64 6
+  store i64 %offo, i64* %pstor6
+
+; Fold memrchr(a, 'p', 16) - a to 15 (12 in LE)
+
+  %pp = call i8* @memrchr(i8* %p1, i32 112, i64 16)
+  %ipp = ptrtoint i8* %pp to i64
+  %offp = sub i64 %ipp, %ip0
+  %pstor7 = getelementptr i64, i64* %pcmp, i64 7
+  store i64 %offp, i64* %pstor7
+
+; Fold memrchr(a, 'q', 16) to null in both BE and LE.
+
+  %pq = call i8* @memrchr(i8* %p1, i32 113, i64 16)
+  %ipq = ptrtoint i8* %pq to i64
+  %pstor8 = getelementptr i64, i64* %pcmp, i64 8
+  store i64 %ipq, i64* %pstor8
+
+  ret void
+}
+
+
+; Fold memrchr(a + 1, C, 12) for C in ['e', 'h'] U ['a', 'd'].
+
+define void @fold_memrchr_a_p1_16(i64* %pcmp) {
+; BE-LABEL: @fold_memrchr_a_p1_16(
+; BE-NEXT:    [[PE:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(12) bitcast (i32* getelementptr inbounds ([5 x i32], [5 x i32]* @a, i64 0, i64 1) to i8*), i32 101, i64 12)
+; BE-NEXT:    [[IPE:%.*]] = ptrtoint i8* [[PE]] to i64
+; BE-NEXT:    [[OFFE:%.*]] = sub i64 [[IPE]], ptrtoint (i32* getelementptr inbounds ([5 x i32], [5 x i32]* @a, i64 0, i64 1) to i64)
+; BE-NEXT:    store i64 [[OFFE]], i64* [[PCMP:%.*]], align 4
+; BE-NEXT:    [[PF:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(12) bitcast (i32* getelementptr inbounds ([5 x i32], [5 x i32]* @a, i64 0, i64 1) to i8*), i32 102, i64 12)
+; BE-NEXT:    [[IPF:%.*]] = ptrtoint i8* [[PF]] to i64
+; BE-NEXT:    [[OFFF:%.*]] = sub i64 [[IPF]], ptrtoint (i32* getelementptr inbounds ([5 x i32], [5 x i32]* @a, i64 0, i64 1) to i64)
+; BE-NEXT:    [[PSTOR1:%.*]] = getelementptr i64, i64* [[PCMP]], i64 1
+; BE-NEXT:    store i64 [[OFFF]], i64* [[PSTOR1]], align 4
+; BE-NEXT:    [[PG:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(12) bitcast (i32* getelementptr inbounds ([5 x i32], [5 x i32]* @a, i64 0, i64 1) to i8*), i32 103, i64 12)
+; BE-NEXT:    [[IPG:%.*]] = ptrtoint i8* [[PG]] to i64
+; BE-NEXT:    [[OFFG:%.*]] = sub i64 [[IPG]], ptrtoint (i32* getelementptr inbounds ([5 x i32], [5 x i32]* @a, i64 0, i64 1) to i64)
+; BE-NEXT:    [[PSTOR2:%.*]] = getelementptr i64, i64* [[PCMP]], i64 2
+; BE-NEXT:    store i64 [[OFFG]], i64* [[PSTOR2]], align 4
+; BE-NEXT:    [[PH:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(12) bitcast (i32* getelementptr inbounds ([5 x i32], [5 x i32]* @a, i64 0, i64 1) to i8*), i32 104, i64 12)
+; BE-NEXT:    [[IPH:%.*]] = ptrtoint i8* [[PH]] to i64
+; BE-NEXT:    [[OFFH:%.*]] = sub i64 [[IPH]], ptrtoint (i32* getelementptr inbounds ([5 x i32], [5 x i32]* @a, i64 0, i64 1) to i64)
+; BE-NEXT:    [[PSTOR3:%.*]] = getelementptr i64, i64* [[PCMP]], i64 3
+; BE-NEXT:    store i64 [[OFFH]], i64* [[PSTOR3]], align 4
+; BE-NEXT:    [[PA:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(12) bitcast (i32* getelementptr inbounds ([5 x i32], [5 x i32]* @a, i64 0, i64 1) to i8*), i32 97, i64 12)
+; BE-NEXT:    [[IPA:%.*]] = ptrtoint i8* [[PA]] to i64
+; BE-NEXT:    [[PSTOR4:%.*]] = getelementptr i64, i64* [[PCMP]], i64 4
+; BE-NEXT:    store i64 [[IPA]], i64* [[PSTOR4]], align 4
+; BE-NEXT:    [[PD:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(12) bitcast (i32* getelementptr inbounds ([5 x i32], [5 x i32]* @a, i64 0, i64 1) to i8*), i32 100, i64 12)
+; BE-NEXT:    [[IPD:%.*]] = ptrtoint i8* [[PD]] to i64
+; BE-NEXT:    [[PSTOR5:%.*]] = getelementptr i64, i64* [[PCMP]], i64 5
+; BE-NEXT:    store i64 [[IPD]], i64* [[PSTOR5]], align 4
+; BE-NEXT:    ret void
+;
+; LE-LABEL: @fold_memrchr_a_p1_16(
+; LE-NEXT:    [[PE:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(12) bitcast (i32* getelementptr inbounds ([5 x i32], [5 x i32]* @a, i64 0, i64 1) to i8*), i32 101, i64 12)
+; LE-NEXT:    [[IPE:%.*]] = ptrtoint i8* [[PE]] to i64
+; LE-NEXT:    [[OFFE:%.*]] = sub i64 [[IPE]], ptrtoint (i32* getelementptr inbounds ([5 x i32], [5 x i32]* @a, i64 0, i64 1) to i64)
+; LE-NEXT:    store i64 [[OFFE]], i64* [[PCMP:%.*]], align 4
+; LE-NEXT:    [[PF:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(12) bitcast (i32* getelementptr inbounds ([5 x i32], [5 x i32]* @a, i64 0, i64 1) to i8*), i32 102, i64 12)
+; LE-NEXT:    [[IPF:%.*]] = ptrtoint i8* [[PF]] to i64
+; LE-NEXT:    [[OFFF:%.*]] = sub i64 [[IPF]], ptrtoint (i32* getelementptr inbounds ([5 x i32], [5 x i32]* @a, i64 0, i64 1) to i64)
+; LE-NEXT:    [[PSTOR1:%.*]] = getelementptr i64, i64* [[PCMP]], i64 1
+; LE-NEXT:    store i64 [[OFFF]], i64* [[PSTOR1]], align 4
+; LE-NEXT:    [[PG:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(12) bitcast (i32* getelementptr inbounds ([5 x i32], [5 x i32]* @a, i64 0, i64 1) to i8*), i32 103, i64 12)
+; LE-NEXT:    [[IPG:%.*]] = ptrtoint i8* [[PG]] to i64
+; LE-NEXT:    [[OFFG:%.*]] = sub i64 [[IPG]], ptrtoint (i32* getelementptr inbounds ([5 x i32], [5 x i32]* @a, i64 0, i64 1) to i64)
+; LE-NEXT:    [[PSTOR2:%.*]] = getelementptr i64, i64* [[PCMP]], i64 2
+; LE-NEXT:    store i64 [[OFFG]], i64* [[PSTOR2]], align 4
+; LE-NEXT:    [[PH:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(12) bitcast (i32* getelementptr inbounds ([5 x i32], [5 x i32]* @a, i64 0, i64 1) to i8*), i32 104, i64 12)
+; LE-NEXT:    [[IPH:%.*]] = ptrtoint i8* [[PH]] to i64
+; LE-NEXT:    [[OFFH:%.*]] = sub i64 [[IPH]], ptrtoint (i32* getelementptr inbounds ([5 x i32], [5 x i32]* @a, i64 0, i64 1) to i64)
+; LE-NEXT:    [[PSTOR3:%.*]] = getelementptr i64, i64* [[PCMP]], i64 3
+; LE-NEXT:    store i64 [[OFFH]], i64* [[PSTOR3]], align 4
+; LE-NEXT:    [[PA:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(12) bitcast (i32* getelementptr inbounds ([5 x i32], [5 x i32]* @a, i64 0, i64 1) to i8*), i32 97, i64 12)
+; LE-NEXT:    [[IPA:%.*]] = ptrtoint i8* [[PA]] to i64
+; LE-NEXT:    [[PSTOR4:%.*]] = getelementptr i64, i64* [[PCMP]], i64 4
+; LE-NEXT:    store i64 [[IPA]], i64* [[PSTOR4]], align 4
+; LE-NEXT:    [[PD:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(12) bitcast (i32* getelementptr inbounds ([5 x i32], [5 x i32]* @a, i64 0, i64 1) to i8*), i32 100, i64 12)
+; LE-NEXT:    [[IPD:%.*]] = ptrtoint i8* [[PD]] to i64
+; LE-NEXT:    [[PSTOR5:%.*]] = getelementptr i64, i64* [[PCMP]], i64 5
+; LE-NEXT:    store i64 [[IPD]], i64* [[PSTOR5]], align 4
+; LE-NEXT:    ret void
+;
+  %p0 = getelementptr [5 x i32], [5 x i32]* @a, i64 0, i64 1
+  %p1 = bitcast i32* %p0 to i8*
+  %ip0 = ptrtoint i8* %p1 to i64
+
+; Fold memrchr(a + 1, 'e', 12) - a to 0 (3 in LE).
+
+  %pe = call i8* @memrchr(i8* %p1, i32 101, i64 12)
+  %ipe = ptrtoint i8* %pe to i64
+  %offe = sub i64 %ipe, %ip0
+  %pstor0 = getelementptr i64, i64* %pcmp, i64 0
+  store i64 %offe, i64* %pstor0
+
+; Fold memrchr(a + 1, 'f', 12) - a to 1 (2 in LE).
+
+  %pf = call i8* @memrchr(i8* %p1, i32 102, i64 12)
+  %ipf = ptrtoint i8* %pf to i64
+  %offf = sub i64 %ipf, %ip0
+  %pstor1 = getelementptr i64, i64* %pcmp, i64 1
+  store i64 %offf, i64* %pstor1
+
+; Fold memrchr(a + 1, 'g', 12) - a to 2 (1 in LE).
+
+  %pg = call i8* @memrchr(i8* %p1, i32 103, i64 12)
+  %ipg = ptrtoint i8* %pg to i64
+  %offg = sub i64 %ipg, %ip0
+  %pstor2 = getelementptr i64, i64* %pcmp, i64 2
+  store i64 %offg, i64* %pstor2
+
+; Fold memrchr(a + 1, 'h', 12) - a to 3 (0 in LE).
+
+  %ph = call i8* @memrchr(i8* %p1, i32 104, i64 12)
+  %iph = ptrtoint i8* %ph to i64
+  %offh = sub i64 %iph, %ip0
+  %pstor3 = getelementptr i64, i64* %pcmp, i64 3
+  store i64 %offh, i64* %pstor3
+
+; Fold memrchr(a + 1, 'a', 12) to null in both BE and LE.
+
+  %pa = call i8* @memrchr(i8* %p1, i32 97, i64 12)
+  %ipa = ptrtoint i8* %pa to i64
+  %pstor4 = getelementptr i64, i64* %pcmp, i64 4
+  store i64 %ipa, i64* %pstor4
+
+; Fold memrchr(a + 1, 'd', 12) to null in both BE and LE.
+
+  %pd = call i8* @memrchr(i8* %p1, i32 100, i64 12)
+  %ipd = ptrtoint i8* %pd to i64
+  %pstor5 = getelementptr i64, i64* %pcmp, i64 5
+  store i64 %ipd, i64* %pstor5
+
+  ret void
+}
+
+
+; Fold memrchr(a, C, 20) for C in ['a', 'e'].
+
+define void @fold_memrchr_a_20(i64* %pcmp) {
+; BE-LABEL: @fold_memrchr_a_20(
+; BE-NEXT:    [[PA:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(20) bitcast ([5 x i32]* @a to i8*), i32 97, i64 20)
+; BE-NEXT:    [[IPA:%.*]] = ptrtoint i8* [[PA]] to i64
+; BE-NEXT:    [[OFFA:%.*]] = sub i64 [[IPA]], ptrtoint ([5 x i32]* @a to i64)
+; BE-NEXT:    store i64 [[OFFA]], i64* [[PCMP:%.*]], align 4
+; BE-NEXT:    [[PB:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(20) bitcast ([5 x i32]* @a to i8*), i32 98, i64 20)
+; BE-NEXT:    [[IPB:%.*]] = ptrtoint i8* [[PB]] to i64
+; BE-NEXT:    [[OFFB:%.*]] = sub i64 [[IPB]], ptrtoint ([5 x i32]* @a to i64)
+; BE-NEXT:    [[PSTOR1:%.*]] = getelementptr i64, i64* [[PCMP]], i64 1
+; BE-NEXT:    store i64 [[OFFB]], i64* [[PSTOR1]], align 4
+; BE-NEXT:    [[PC:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(20) bitcast ([5 x i32]* @a to i8*), i32 99, i64 20)
+; BE-NEXT:    [[IPC:%.*]] = ptrtoint i8* [[PC]] to i64
+; BE-NEXT:    [[OFFC:%.*]] = sub i64 [[IPC]], ptrtoint ([5 x i32]* @a to i64)
+; BE-NEXT:    [[PSTOR2:%.*]] = getelementptr i64, i64* [[PCMP]], i64 2
+; BE-NEXT:    store i64 [[OFFC]], i64* [[PSTOR2]], align 4
+; BE-NEXT:    [[PD:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(20) bitcast ([5 x i32]* @a to i8*), i32 100, i64 20)
+; BE-NEXT:    [[IPD:%.*]] = ptrtoint i8* [[PD]] to i64
+; BE-NEXT:    [[OFFD:%.*]] = sub i64 [[IPD]], ptrtoint ([5 x i32]* @a to i64)
+; BE-NEXT:    [[PSTOR3:%.*]] = getelementptr i64, i64* [[PCMP]], i64 3
+; BE-NEXT:    store i64 [[OFFD]], i64* [[PSTOR3]], align 4
+; BE-NEXT:    [[PE:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(20) bitcast ([5 x i32]* @a to i8*), i32 101, i64 20)
+; BE-NEXT:    [[IPE:%.*]] = ptrtoint i8* [[PE]] to i64
+; BE-NEXT:    [[OFFE:%.*]] = sub i64 [[IPE]], ptrtoint ([5 x i32]* @a to i64)
+; BE-NEXT:    [[PSTOR4:%.*]] = getelementptr i64, i64* [[PCMP]], i64 4
+; BE-NEXT:    store i64 [[OFFE]], i64* [[PSTOR4]], align 4
+; BE-NEXT:    ret void
+;
+; LE-LABEL: @fold_memrchr_a_20(
+; LE-NEXT:    [[PA:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(20) bitcast ([5 x i32]* @a to i8*), i32 97, i64 20)
+; LE-NEXT:    [[IPA:%.*]] = ptrtoint i8* [[PA]] to i64
+; LE-NEXT:    [[OFFA:%.*]] = sub i64 [[IPA]], ptrtoint ([5 x i32]* @a to i64)
+; LE-NEXT:    store i64 [[OFFA]], i64* [[PCMP:%.*]], align 4
+; LE-NEXT:    [[PB:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(20) bitcast ([5 x i32]* @a to i8*), i32 98, i64 20)
+; LE-NEXT:    [[IPB:%.*]] = ptrtoint i8* [[PB]] to i64
+; LE-NEXT:    [[OFFB:%.*]] = sub i64 [[IPB]], ptrtoint ([5 x i32]* @a to i64)
+; LE-NEXT:    [[PSTOR1:%.*]] = getelementptr i64, i64* [[PCMP]], i64 1
+; LE-NEXT:    store i64 [[OFFB]], i64* [[PSTOR1]], align 4
+; LE-NEXT:    [[PC:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(20) bitcast ([5 x i32]* @a to i8*), i32 99, i64 20)
+; LE-NEXT:    [[IPC:%.*]] = ptrtoint i8* [[PC]] to i64
+; LE-NEXT:    [[OFFC:%.*]] = sub i64 [[IPC]], ptrtoint ([5 x i32]* @a to i64)
+; LE-NEXT:    [[PSTOR2:%.*]] = getelementptr i64, i64* [[PCMP]], i64 2
+; LE-NEXT:    store i64 [[OFFC]], i64* [[PSTOR2]], align 4
+; LE-NEXT:    [[PD:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(20) bitcast ([5 x i32]* @a to i8*), i32 100, i64 20)
+; LE-NEXT:    [[IPD:%.*]] = ptrtoint i8* [[PD]] to i64
+; LE-NEXT:    [[OFFD:%.*]] = sub i64 [[IPD]], ptrtoint ([5 x i32]* @a to i64)
+; LE-NEXT:    [[PSTOR3:%.*]] = getelementptr i64, i64* [[PCMP]], i64 3
+; LE-NEXT:    store i64 [[OFFD]], i64* [[PSTOR3]], align 4
+; LE-NEXT:    [[PE:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(20) bitcast ([5 x i32]* @a to i8*), i32 101, i64 20)
+; LE-NEXT:    [[IPE:%.*]] = ptrtoint i8* [[PE]] to i64
+; LE-NEXT:    [[OFFE:%.*]] = sub i64 [[IPE]], ptrtoint ([5 x i32]* @a to i64)
+; LE-NEXT:    [[PSTOR4:%.*]] = getelementptr i64, i64* [[PCMP]], i64 4
+; LE-NEXT:    store i64 [[OFFE]], i64* [[PSTOR4]], align 4
+; LE-NEXT:    ret void
+;
+  %p0 = getelementptr [5 x i32], [5 x i32]* @a, i64 0, i64 0
+  %p1 = bitcast i32* %p0 to i8*
+  %ip0 = ptrtoint i8* %p1 to i64
+
+; Fold memrchr(a, 'a', 20) - a to 16 (19 in LE).
+
+  %pa = call i8* @memrchr(i8* %p1, i32 97, i64 20)
+  %ipa = ptrtoint i8* %pa to i64
+  %offa = sub i64 %ipa, %ip0
+  %pstor0 = getelementptr i64, i64* %pcmp, i64 0
+  store i64 %offa, i64* %pstor0
+
+; Fold memrchr(a, 'b', 16) - a to 17 (18 in LE)
+
+  %pb = call i8* @memrchr(i8* %p1, i32 98, i64 20)
+  %ipb = ptrtoint i8* %pb to i64
+  %offb = sub i64 %ipb, %ip0
+  %pstor1 = getelementptr i64, i64* %pcmp, i64 1
+  store i64 %offb, i64* %pstor1
+
+; Fold memrchr(a, 'c', 16) - a to 18 (17 in LE)
+
+  %pc = call i8* @memrchr(i8* %p1, i32 99, i64 20)
+  %ipc = ptrtoint i8* %pc to i64
+  %offc = sub i64 %ipc, %ip0
+  %pstor2 = getelementptr i64, i64* %pcmp, i64 2
+  store i64 %offc, i64* %pstor2
+
+; Fold memrchr(a, 'd', 16) - a to 19 (16 in LE)
+
+  %pd = call i8* @memrchr(i8* %p1, i32 100, i64 20)
+  %ipd = ptrtoint i8* %pd to i64
+  %offd = sub i64 %ipd, %ip0
+  %pstor3 = getelementptr i64, i64* %pcmp, i64 3
+  store i64 %offd, i64* %pstor3
+
+; Fold memrchr(a, 'e', 16) - a to 4 (7 in LE)
+
+  %pe = call i8* @memrchr(i8* %p1, i32 101, i64 20)
+  %ipe = ptrtoint i8* %pe to i64
+  %offe = sub i64 %ipe, %ip0
+  %pstor4 = getelementptr i64, i64* %pcmp, i64 4
+  store i64 %offe, i64* %pstor4
+
+  ret void
+}

diff  --git a/llvm/test/Transforms/InstCombine/sprintf-2.ll b/llvm/test/Transforms/InstCombine/sprintf-2.ll
new file mode 100644
index 000000000000..826cde9c1929
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/sprintf-2.ll
@@ -0,0 +1,104 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; Verify that calls to snprintf with members of constant structs as arguments
+; are folded to constants as expected.
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+declare i32 @snprintf(i8*, i64, i8*, ...)
+
+%struct.A = type { [5 x i8], [6 x i8], [7 x i8] }
+
+ at a = constant [2 x %struct.A] [%struct.A { [5 x i8] c"1\00\00\00\00", [6 x i8] c"12\00\00\00\00", [7 x i8] c"123\00\00\00\00" }, %struct.A { [5 x i8] c"1234\00", [6 x i8] c"12345\00", [7 x i8] c"123456\00" }]
+
+ at pcnt_s = constant [3 x i8] c"%s\00"
+
+
+; Fold snprintf(0, 0, "%s", a[I].M + C) for constant I in [0, 1],
+; member M in [a, b, c], and C in a valid range to a constant.
+
+define void @fold_snprintf_member_pC(i32* %pi) {
+; CHECK-LABEL: @fold_snprintf_member_pC(
+; CHECK-NEXT:    [[IA0A:%.*]] = call i32 (i8*, i64, i8*, ...) @snprintf(i8* null, i64 0, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @pcnt_s, i64 0, i64 0), i8* getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 0, i64 0))
+; CHECK-NEXT:    store i32 [[IA0A]], i32* [[PI:%.*]], align 4
+; CHECK-NEXT:    [[IA0AP1:%.*]] = call i32 (i8*, i64, i8*, ...) @snprintf(i8* null, i64 0, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @pcnt_s, i64 0, i64 0), i8* getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 0, i64 1))
+; CHECK-NEXT:    [[PIA0AP1:%.*]] = getelementptr i32, i32* [[PI]], i64 1
+; CHECK-NEXT:    store i32 [[IA0AP1]], i32* [[PIA0AP1]], align 4
+; CHECK-NEXT:    [[IA0B:%.*]] = call i32 (i8*, i64, i8*, ...) @snprintf(i8* null, i64 0, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @pcnt_s, i64 0, i64 0), i8* getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 1, i64 0))
+; CHECK-NEXT:    [[PIA0B:%.*]] = getelementptr i32, i32* [[PI]], i64 2
+; CHECK-NEXT:    store i32 [[IA0B]], i32* [[PIA0B]], align 4
+; CHECK-NEXT:    [[IA0BP1:%.*]] = call i32 (i8*, i64, i8*, ...) @snprintf(i8* null, i64 0, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @pcnt_s, i64 0, i64 0), i8* getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 1, i64 1))
+; CHECK-NEXT:    [[PIA0BP1:%.*]] = getelementptr i32, i32* [[PI]], i64 3
+; CHECK-NEXT:    store i32 [[IA0BP1]], i32* [[PIA0BP1]], align 4
+; CHECK-NEXT:    [[IA0BP2:%.*]] = call i32 (i8*, i64, i8*, ...) @snprintf(i8* null, i64 0, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @pcnt_s, i64 0, i64 0), i8* getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 1, i64 2))
+; CHECK-NEXT:    [[PIA0BP2:%.*]] = getelementptr i32, i32* [[PI]], i64 4
+; CHECK-NEXT:    store i32 [[IA0BP2]], i32* [[PIA0BP2]], align 4
+; CHECK-NEXT:    [[IA0C:%.*]] = call i32 (i8*, i64, i8*, ...) @snprintf(i8* null, i64 0, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @pcnt_s, i64 0, i64 0), i8* getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 2, i64 0))
+; CHECK-NEXT:    [[PIA0C:%.*]] = getelementptr i32, i32* [[PI]], i64 5
+; CHECK-NEXT:    store i32 [[IA0C]], i32* [[PIA0C]], align 4
+; CHECK-NEXT:    [[IA1A:%.*]] = call i32 (i8*, i64, i8*, ...) @snprintf(i8* null, i64 0, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @pcnt_s, i64 0, i64 0), i8* getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 0, i64 0))
+; CHECK-NEXT:    [[PIA1A:%.*]] = getelementptr i32, i32* [[PI]], i64 6
+; CHECK-NEXT:    store i32 [[IA1A]], i32* [[PIA1A]], align 4
+; CHECK-NEXT:    [[IA1B:%.*]] = call i32 (i8*, i64, i8*, ...) @snprintf(i8* null, i64 0, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @pcnt_s, i64 0, i64 0), i8* getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 1, i64 0))
+; CHECK-NEXT:    [[PIA1B:%.*]] = getelementptr i32, i32* [[PI]], i64 7
+; CHECK-NEXT:    store i32 [[IA1B]], i32* [[PIA1B]], align 4
+; CHECK-NEXT:    [[IA1C:%.*]] = call i32 (i8*, i64, i8*, ...) @snprintf(i8* null, i64 0, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @pcnt_s, i64 0, i64 0), i8* getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 2, i64 0))
+; CHECK-NEXT:    [[PIA1C:%.*]] = getelementptr i32, i32* [[PI]], i64 8
+; CHECK-NEXT:    store i32 [[IA1C]], i32* [[PIA1C]], align 4
+; CHECK-NEXT:    ret void
+;
+  %fmt = getelementptr [3 x i8], [3 x i8]* @pcnt_s, i32 0, i32 0
+; Fold snprintf(0, 0, "%s", a[0].a) to 1.
+  %pa0a = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 0, i64 0
+  %ia0a = call i32 (i8*, i64, i8*, ...) @snprintf(i8* null, i64 0, i8* %fmt, i8* %pa0a)
+  %pia0a = getelementptr i32, i32* %pi, i32 0
+  store i32 %ia0a, i32* %pia0a
+
+; Fold snprintf(0, 0, "%s", a[0].a) to 0.
+  %pa0ap1 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 0, i64 1
+  %ia0ap1 = call i32 (i8*, i64, i8*, ...) @snprintf(i8* null, i64 0, i8* %fmt, i8* %pa0ap1)
+  %pia0ap1 = getelementptr i32, i32* %pi, i32 1
+  store i32 %ia0ap1, i32* %pia0ap1
+
+; Fold snprintf(0, 0, "%s", a[0].b) to 2.
+  %pa0b = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 1, i64 0
+  %ia0b = call i32 (i8*, i64, i8*, ...) @snprintf(i8* null, i64 0, i8* %fmt, i8* %pa0b)
+  %pia0b = getelementptr i32, i32* %pi, i32 2
+  store i32 %ia0b, i32* %pia0b
+
+; Fold snprintf(0, 0, "%s", a[0].b + 1) to 1.
+  %pa0bp1 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 1, i64 1
+  %ia0bp1 = call i32 (i8*, i64, i8*, ...) @snprintf(i8* null, i64 0, i8* %fmt, i8* %pa0bp1)
+  %pia0bp1 = getelementptr i32, i32* %pi, i32 3
+  store i32 %ia0bp1, i32* %pia0bp1
+
+; Fold snprintf(0, 0, "%s", a[0].b + 2) to 0.
+  %pa0bp2 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 1, i64 2
+  %ia0bp2 = call i32 (i8*, i64, i8*, ...) @snprintf(i8* null, i64 0, i8* %fmt, i8* %pa0bp2)
+  %pia0bp2 = getelementptr i32, i32* %pi, i32 4
+  store i32 %ia0bp2, i32* %pia0bp2
+
+; Fold snprintf(0, 0, "%s", a[0].c) to 3.
+  %pa0c = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 2, i64 0
+  %ia0c = call i32 (i8*, i64, i8*, ...) @snprintf(i8* null, i64 0, i8* %fmt, i8* %pa0c)
+  %pia0c = getelementptr i32, i32* %pi, i32 5
+  store i32 %ia0c, i32* %pia0c
+
+; Fold snprintf(0, 0, "%s", a[1].a) to 4.
+  %pa1a = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 0, i64 0
+  %ia1a = call i32 (i8*, i64, i8*, ...) @snprintf(i8* null, i64 0, i8* %fmt, i8* %pa1a)
+  %pia1a = getelementptr i32, i32* %pi, i32 6
+  store i32 %ia1a, i32* %pia1a
+
+; Fold snprintf(0, 0, "%s", a[1].b) to 5.
+  %pa1b = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 1, i64 0
+  %ia1b = call i32 (i8*, i64, i8*, ...) @snprintf(i8* null, i64 0, i8* %fmt, i8* %pa1b)
+  %pia1b = getelementptr i32, i32* %pi, i32 7
+  store i32 %ia1b, i32* %pia1b
+
+; Fold snprintf(0, 0, "%s", a[1].c) to 6.
+  %pa1c = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 2, i64 0
+  %ia1c = call i32 (i8*, i64, i8*, ...) @snprintf(i8* null, i64 0, i8* %fmt, i8* %pa1c)
+  %pia1c = getelementptr i32, i32* %pi, i32 8
+  store i32 %ia1c, i32* %pia1c
+
+  ret void
+}

diff  --git a/llvm/test/Transforms/InstCombine/str-int-3.ll b/llvm/test/Transforms/InstCombine/str-int-3.ll
new file mode 100644
index 000000000000..835e045483d1
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/str-int-3.ll
@@ -0,0 +1,345 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; Verify that calls to atoi and related conversion functions with members
+; of constant structs as arguments are folded to constants as expected.
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+declare i32 @atoi(i8*)
+declare i64 @atol(i8*)
+declare i64 @atoll(i8*)
+
+declare i64 @strtol(i8*, i8**, i32)
+declare i64 @strtoll(i8*, i8**, i32)
+
+%struct.A = type { [4 x i8], [5 x i8], [7 x i8] }
+
+ at a = constant [2 x %struct.A] [%struct.A { [4 x i8] c"1\00\00\00", [5 x i8] c"12\00\00\00", [7 x i8] c"56789\00\00" }, %struct.A { [4 x i8] c"123\00", [5 x i8] c"1234\00", [7 x i8] c"67890\00\00" }]
+
+
+; Fold atoi(a[I].M) for constant I in [0, 1] and member M in [a, b]
+; to a constant.
+
+define void @fold_atoi_member(i32* %pi) {
+; CHECK-LABEL: @fold_atoi_member(
+; CHECK-NEXT:    [[IA0A:%.*]] = call i32 @atoi(i8* getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 0, i64 0))
+; CHECK-NEXT:    store i32 [[IA0A]], i32* [[PI:%.*]], align 4
+; CHECK-NEXT:    [[IA0B:%.*]] = call i32 @atoi(i8* getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 1, i64 0))
+; CHECK-NEXT:    [[PIA0B:%.*]] = getelementptr i32, i32* [[PI]], i64 1
+; CHECK-NEXT:    store i32 [[IA0B]], i32* [[PIA0B]], align 4
+; CHECK-NEXT:    [[IA1A:%.*]] = call i32 @atoi(i8* getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 0, i64 0))
+; CHECK-NEXT:    [[PIA1A:%.*]] = getelementptr i32, i32* [[PI]], i64 2
+; CHECK-NEXT:    store i32 [[IA1A]], i32* [[PIA1A]], align 4
+; CHECK-NEXT:    [[IA1B:%.*]] = call i32 @atoi(i8* getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 1, i64 0))
+; CHECK-NEXT:    [[PIA1B:%.*]] = getelementptr i32, i32* [[PI]], i64 3
+; CHECK-NEXT:    store i32 [[IA1B]], i32* [[PIA1B]], align 4
+; CHECK-NEXT:    ret void
+;
+; Fold atoi(a[0].a) to 1.
+  %pa0a = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 0, i64 0
+  %ia0a = call i32 @atoi(i8* %pa0a)
+  %pia0a = getelementptr i32, i32* %pi, i32 0
+  store i32 %ia0a, i32* %pia0a
+
+; Fold atoi(a[0].b) to 12.
+  %pa0b = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 1, i64 0
+  %ia0b = call i32 @atoi(i8* %pa0b)
+  %pia0b = getelementptr i32, i32* %pi, i32 1
+  store i32 %ia0b, i32* %pia0b
+
+; Fold atoi(a[1].a) to 123.
+  %pa1a = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 0, i64 0
+  %ia1a = call i32 @atoi(i8* %pa1a)
+  %pia1a = getelementptr i32, i32* %pi, i32 2
+  store i32 %ia1a, i32* %pia1a
+
+; Fold atoi(a[1].b) to 1234.
+  %pa1b = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 1, i64 0
+  %ia1b = call i32 @atoi(i8* %pa1b)
+  %pia1b = getelementptr i32, i32* %pi, i32 3
+  store i32 %ia1b, i32* %pia1b
+
+  ret void
+}
+
+
+; Do not fold atoi with an excessive offset.  It's undefined so folding
+; it (e.g., to zero) would be valid and might prevent crashes or returning
+; a bogus value but could also prevent detecting the bug by sanitizers.
+
+define void @call_atoi_offset_out_of_bounds(i32* %pi) {
+; CHECK-LABEL: @call_atoi_offset_out_of_bounds(
+; CHECK-NEXT:    [[IA_0_0_32:%.*]] = call i32 @atoi(i8* getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 1, i64 0, i32 0, i64 0))
+; CHECK-NEXT:    store i32 [[IA_0_0_32]], i32* [[PI:%.*]], align 4
+; CHECK-NEXT:    [[IA_0_0_33:%.*]] = call i32 @atoi(i8* getelementptr ([2 x %struct.A], [2 x %struct.A]* @a, i64 1, i64 0, i32 0, i64 1))
+; CHECK-NEXT:    store i32 [[IA_0_0_33]], i32* [[PI]], align 4
+; CHECK-NEXT:    ret void
+;
+; Do not fold atoi((const char*)a + sizeof a).
+  %pa_0_0_32 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 0, i64 32
+  %ia_0_0_32 = call i32 @atoi(i8* %pa_0_0_32)
+  %pia_0_0_32 = getelementptr i32, i32* %pi, i32 0
+  store i32 %ia_0_0_32, i32* %pia_0_0_32
+
+; Likewise, do not fold atoi((const char*)a + sizeof a + 1).
+  %pa_0_0_33 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 0, i64 33
+  %ia_0_0_33 = call i32 @atoi(i8* %pa_0_0_33)
+  %pia_0_0_33 = getelementptr i32, i32* %pi, i32 0
+  store i32 %ia_0_0_33, i32* %pia_0_0_33
+
+  ret void
+}
+
+
+; Fold atol(a[I].M) for constant I in [0, 1] and member M in [a, b, c]
+; to a constant.
+
+define void @fold_atol_member(i64* %pi) {
+; CHECK-LABEL: @fold_atol_member(
+; CHECK-NEXT:    [[IA0A:%.*]] = call i64 @atol(i8* getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 0, i64 0))
+; CHECK-NEXT:    store i64 [[IA0A]], i64* [[PI:%.*]], align 4
+; CHECK-NEXT:    [[IA0B:%.*]] = call i64 @atol(i8* getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 1, i64 0))
+; CHECK-NEXT:    [[PIA0B:%.*]] = getelementptr i64, i64* [[PI]], i64 1
+; CHECK-NEXT:    store i64 [[IA0B]], i64* [[PIA0B]], align 4
+; CHECK-NEXT:    [[IA0C:%.*]] = call i64 @atol(i8* getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 2, i64 0))
+; CHECK-NEXT:    [[PIA0C:%.*]] = getelementptr i64, i64* [[PI]], i64 2
+; CHECK-NEXT:    store i64 [[IA0C]], i64* [[PIA0C]], align 4
+; CHECK-NEXT:    [[IA1A:%.*]] = call i64 @atol(i8* getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 0, i64 0))
+; CHECK-NEXT:    [[PIA1A:%.*]] = getelementptr i64, i64* [[PI]], i64 3
+; CHECK-NEXT:    store i64 [[IA1A]], i64* [[PIA1A]], align 4
+; CHECK-NEXT:    [[IA1B:%.*]] = call i64 @atol(i8* getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 1, i64 0))
+; CHECK-NEXT:    [[PIA1B:%.*]] = getelementptr i64, i64* [[PI]], i64 4
+; CHECK-NEXT:    store i64 [[IA1B]], i64* [[PIA1B]], align 4
+; CHECK-NEXT:    [[IA1C:%.*]] = call i64 @atol(i8* getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 2, i64 0))
+; CHECK-NEXT:    [[PIA1C:%.*]] = getelementptr i64, i64* [[PI]], i64 5
+; CHECK-NEXT:    store i64 [[IA1C]], i64* [[PIA1C]], align 4
+; CHECK-NEXT:    ret void
+;
+; Fold atol(a[0].a) to 1.
+  %pa0a = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 0, i64 0
+  %ia0a = call i64 @atol(i8* %pa0a)
+  %pia0a = getelementptr i64, i64* %pi, i32 0
+  store i64 %ia0a, i64* %pia0a
+
+; Fold atol(a[0].b) to 12.
+  %pa0b = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 1, i64 0
+  %ia0b = call i64 @atol(i8* %pa0b)
+  %pia0b = getelementptr i64, i64* %pi, i32 1
+  store i64 %ia0b, i64* %pia0b
+
+; Fold atol(a[0].c) to 56789.
+  %pa0c = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 2, i64 0
+  %ia0c = call i64 @atol(i8* %pa0c)
+  %pia0c = getelementptr i64, i64* %pi, i32 2
+  store i64 %ia0c, i64* %pia0c
+
+; Fold atol(a[1].a) to 123.
+  %pa1a = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 0, i64 0
+  %ia1a = call i64 @atol(i8* %pa1a)
+  %pia1a = getelementptr i64, i64* %pi, i32 3
+  store i64 %ia1a, i64* %pia1a
+
+; Fold atol(a[1].b) to 1234.
+  %pa1b = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 1, i64 0
+  %ia1b = call i64 @atol(i8* %pa1b)
+  %pia1b = getelementptr i64, i64* %pi, i32 4
+  store i64 %ia1b, i64* %pia1b
+
+; Fold atol(a[1].c) to 67890.
+  %pa1c = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 2, i64 0
+  %ia1c = call i64 @atol(i8* %pa1c)
+  %pia1c = getelementptr i64, i64* %pi, i32 5
+  store i64 %ia1c, i64* %pia1c
+
+  ret void
+}
+
+
+; Fold atoll(a[I].M + C) for constant I in [0, 1], member M in [a, b, c],
+; and C in a valid range to a constant.
+
+define void @fold_atoll_member_pC(i64* %pi) {
+; CHECK-LABEL: @fold_atoll_member_pC(
+; CHECK-NEXT:    [[IA0A:%.*]] = call i64 @atol(i8* getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 0, i64 0))
+; CHECK-NEXT:    store i64 [[IA0A]], i64* [[PI:%.*]], align 4
+; CHECK-NEXT:    [[IA0BP1:%.*]] = call i64 @atol(i8* getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 1, i64 1))
+; CHECK-NEXT:    [[PIA0BP1:%.*]] = getelementptr i64, i64* [[PI]], i64 1
+; CHECK-NEXT:    store i64 [[IA0BP1]], i64* [[PIA0BP1]], align 4
+; CHECK-NEXT:    [[IA0CP3:%.*]] = call i64 @atol(i8* getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 2, i64 3))
+; CHECK-NEXT:    [[PIA0CP3:%.*]] = getelementptr i64, i64* [[PI]], i64 2
+; CHECK-NEXT:    store i64 [[IA0CP3]], i64* [[PIA0CP3]], align 4
+; CHECK-NEXT:    [[IA1AP2:%.*]] = call i64 @atol(i8* getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 0, i64 2))
+; CHECK-NEXT:    [[PIA1AP2:%.*]] = getelementptr i64, i64* [[PI]], i64 3
+; CHECK-NEXT:    store i64 [[IA1AP2]], i64* [[PIA1AP2]], align 4
+; CHECK-NEXT:    [[IA1BP3:%.*]] = call i64 @atol(i8* getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 1, i64 3))
+; CHECK-NEXT:    [[PIA1BP3:%.*]] = getelementptr i64, i64* [[PI]], i64 4
+; CHECK-NEXT:    store i64 [[IA1BP3]], i64* [[PIA1BP3]], align 4
+; CHECK-NEXT:    [[IA1CP4:%.*]] = call i64 @atol(i8* getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 2, i64 4))
+; CHECK-NEXT:    [[PIA1CP4:%.*]] = getelementptr i64, i64* [[PI]], i64 5
+; CHECK-NEXT:    store i64 [[IA1CP4]], i64* [[PIA1CP4]], align 4
+; CHECK-NEXT:    ret void
+;
+; Fold atoll(a[0].a) to 1.
+  %pa0a = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 0, i64 0
+  %ia0a = call i64 @atol(i8* %pa0a)
+  %pia0a = getelementptr i64, i64* %pi, i32 0
+  store i64 %ia0a, i64* %pia0a
+
+; Fold atoll(a[0].b + 1) to 2.
+  %pa0bp1 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 1, i64 1
+  %ia0bp1 = call i64 @atol(i8* %pa0bp1)
+  %pia0bp1 = getelementptr i64, i64* %pi, i32 1
+  store i64 %ia0bp1, i64* %pia0bp1
+
+; Fold atoll(a[0].c + 3) to 89.
+  %pa0cp3 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 2, i64 3
+  %ia0cp3 = call i64 @atol(i8* %pa0cp3)
+  %pia0cp3 = getelementptr i64, i64* %pi, i32 2
+  store i64 %ia0cp3, i64* %pia0cp3
+
+; Fold atoll(a[1].a + 2) to 3.
+  %pa1ap2 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 0, i64 2
+  %ia1ap2 = call i64 @atol(i8* %pa1ap2)
+  %pia1ap2 = getelementptr i64, i64* %pi, i32 3
+  store i64 %ia1ap2, i64* %pia1ap2
+
+; Fold atoll(a[1].b + 3) to 4.
+  %pa1bp3 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 1, i64 3
+  %ia1bp3 = call i64 @atol(i8* %pa1bp3)
+  %pia1bp3 = getelementptr i64, i64* %pi, i32 4
+  store i64 %ia1bp3, i64* %pia1bp3
+
+; Fold atoll(a[1].c + 4) to 0.
+  %pa1cp4 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 2, i64 4
+  %ia1cp4 = call i64 @atol(i8* %pa1cp4)
+  %pia1cp4 = getelementptr i64, i64* %pi, i32 5
+  store i64 %ia1cp4, i64* %pia1cp4
+
+  ret void
+}
+
+
+; Fold strtol(a[I].M + C, 0, 0) for constant I in [0, 1], member M in [a, b, c],
+; and C in a valid range to a constant.
+
+define void @fold_strtol_member_pC(i64* %pi) {
+; CHECK-LABEL: @fold_strtol_member_pC(
+; CHECK-NEXT:    [[IA0A:%.*]] = call i64 @strtol(i8* nocapture getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 0, i64 0), i8** null, i32 0)
+; CHECK-NEXT:    store i64 [[IA0A]], i64* [[PI:%.*]], align 4
+; CHECK-NEXT:    [[IA0BP1:%.*]] = call i64 @strtol(i8* nocapture getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 1, i64 1), i8** null, i32 0)
+; CHECK-NEXT:    [[PIA0BP1:%.*]] = getelementptr i64, i64* [[PI]], i64 1
+; CHECK-NEXT:    store i64 [[IA0BP1]], i64* [[PIA0BP1]], align 4
+; CHECK-NEXT:    [[IA0CP3:%.*]] = call i64 @strtol(i8* nocapture getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 2, i64 3), i8** null, i32 0)
+; CHECK-NEXT:    [[PIA0CP3:%.*]] = getelementptr i64, i64* [[PI]], i64 2
+; CHECK-NEXT:    store i64 [[IA0CP3]], i64* [[PIA0CP3]], align 4
+; CHECK-NEXT:    [[IA1AP2:%.*]] = call i64 @strtol(i8* nocapture getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 0, i64 2), i8** null, i32 0)
+; CHECK-NEXT:    [[PIA1AP2:%.*]] = getelementptr i64, i64* [[PI]], i64 3
+; CHECK-NEXT:    store i64 [[IA1AP2]], i64* [[PIA1AP2]], align 4
+; CHECK-NEXT:    [[IA1BP3:%.*]] = call i64 @strtol(i8* nocapture getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 1, i64 3), i8** null, i32 0)
+; CHECK-NEXT:    [[PIA1BP3:%.*]] = getelementptr i64, i64* [[PI]], i64 4
+; CHECK-NEXT:    store i64 [[IA1BP3]], i64* [[PIA1BP3]], align 4
+; CHECK-NEXT:    [[IA1CP4:%.*]] = call i64 @strtol(i8* nocapture getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 2, i64 4), i8** null, i32 0)
+; CHECK-NEXT:    [[PIA1CP4:%.*]] = getelementptr i64, i64* [[PI]], i64 5
+; CHECK-NEXT:    store i64 [[IA1CP4]], i64* [[PIA1CP4]], align 4
+; CHECK-NEXT:    ret void
+;
+; Fold strtol(a[0].a, 0, 0) to 1.
+  %pa0a = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 0, i64 0
+  %ia0a = call i64 @strtol(i8* %pa0a, i8** null, i32 0)
+  %pia0a = getelementptr i64, i64* %pi, i32 0
+  store i64 %ia0a, i64* %pia0a
+
+; Fold strtol(a[0].b + 1, 0, 0, i8** null, i32 0) to 2.
+  %pa0bp1 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 1, i64 1
+  %ia0bp1 = call i64 @strtol(i8* %pa0bp1, i8** null, i32 0)
+  %pia0bp1 = getelementptr i64, i64* %pi, i32 1
+  store i64 %ia0bp1, i64* %pia0bp1
+
+; Fold strtol(a[0].c + 3, 0, 0, i8** null, i32 0) to 89.
+  %pa0cp3 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 2, i64 3
+  %ia0cp3 = call i64 @strtol(i8* %pa0cp3, i8** null, i32 0)
+  %pia0cp3 = getelementptr i64, i64* %pi, i32 2
+  store i64 %ia0cp3, i64* %pia0cp3
+
+; Fold strtol(a[1].a + 2, 0, 0, i8** null, i32 0) to 3.
+  %pa1ap2 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 0, i64 2
+  %ia1ap2 = call i64 @strtol(i8* %pa1ap2, i8** null, i32 0)
+  %pia1ap2 = getelementptr i64, i64* %pi, i32 3
+  store i64 %ia1ap2, i64* %pia1ap2
+
+; Fold strtol(a[1].b + 3, 0, 0, i8** null, i32 0) to 4.
+  %pa1bp3 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 1, i64 3
+  %ia1bp3 = call i64 @strtol(i8* %pa1bp3, i8** null, i32 0)
+  %pia1bp3 = getelementptr i64, i64* %pi, i32 4
+  store i64 %ia1bp3, i64* %pia1bp3
+
+; Fold strtol(a[1].c + 4, 0, 0, i8** null, i32 0) to 0.
+  %pa1cp4 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 2, i64 4
+  %ia1cp4 = call i64 @strtol(i8* %pa1cp4, i8** null, i32 0)
+  %pia1cp4 = getelementptr i64, i64* %pi, i32 5
+  store i64 %ia1cp4, i64* %pia1cp4
+
+  ret void
+}
+
+
+; Fold strtoll(a[I].M + C, 0, 0) for constant I in [0, 1], member M
+; in [a, b, c], and C in a valid range to a constant.
+
+define void @fold_strtoll_member_pC(i64* %pi) {
+; CHECK-LABEL: @fold_strtoll_member_pC(
+; CHECK-NEXT:    [[IA0A:%.*]] = call i64 @strtoll(i8* nocapture getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 0, i64 0), i8** null, i32 0)
+; CHECK-NEXT:    store i64 [[IA0A]], i64* [[PI:%.*]], align 4
+; CHECK-NEXT:    [[IA0BP1:%.*]] = call i64 @strtoll(i8* nocapture getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 1, i64 1), i8** null, i32 0)
+; CHECK-NEXT:    [[PIA0BP1:%.*]] = getelementptr i64, i64* [[PI]], i64 1
+; CHECK-NEXT:    store i64 [[IA0BP1]], i64* [[PIA0BP1]], align 4
+; CHECK-NEXT:    [[IA0CP3:%.*]] = call i64 @strtoll(i8* nocapture getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 2, i64 3), i8** null, i32 0)
+; CHECK-NEXT:    [[PIA0CP3:%.*]] = getelementptr i64, i64* [[PI]], i64 2
+; CHECK-NEXT:    store i64 [[IA0CP3]], i64* [[PIA0CP3]], align 4
+; CHECK-NEXT:    [[IA1AP2:%.*]] = call i64 @strtoll(i8* nocapture getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 0, i64 2), i8** null, i32 0)
+; CHECK-NEXT:    [[PIA1AP2:%.*]] = getelementptr i64, i64* [[PI]], i64 3
+; CHECK-NEXT:    store i64 [[IA1AP2]], i64* [[PIA1AP2]], align 4
+; CHECK-NEXT:    [[IA1BP3:%.*]] = call i64 @strtoll(i8* nocapture getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 1, i64 3), i8** null, i32 0)
+; CHECK-NEXT:    [[PIA1BP3:%.*]] = getelementptr i64, i64* [[PI]], i64 4
+; CHECK-NEXT:    store i64 [[IA1BP3]], i64* [[PIA1BP3]], align 4
+; CHECK-NEXT:    [[IA1CP4:%.*]] = call i64 @strtoll(i8* nocapture getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 2, i64 4), i8** null, i32 0)
+; CHECK-NEXT:    [[PIA1CP4:%.*]] = getelementptr i64, i64* [[PI]], i64 5
+; CHECK-NEXT:    store i64 [[IA1CP4]], i64* [[PIA1CP4]], align 4
+; CHECK-NEXT:    ret void
+;
+; Fold strtoll(a[0].a, 0, 0) to 1.
+  %pa0a = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 0, i64 0
+  %ia0a = call i64 @strtoll(i8* %pa0a, i8** null, i32 0)
+  %pia0a = getelementptr i64, i64* %pi, i32 0
+  store i64 %ia0a, i64* %pia0a
+
+; Fold strtoll(a[0].b + 1, 0, 0, i8** null, i32 0) to 2.
+  %pa0bp1 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 1, i64 1
+  %ia0bp1 = call i64 @strtoll(i8* %pa0bp1, i8** null, i32 0)
+  %pia0bp1 = getelementptr i64, i64* %pi, i32 1
+  store i64 %ia0bp1, i64* %pia0bp1
+
+; Fold strtoll(a[0].c + 3, 0, 0, i8** null, i32 0) to 89.
+  %pa0cp3 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 2, i64 3
+  %ia0cp3 = call i64 @strtoll(i8* %pa0cp3, i8** null, i32 0)
+  %pia0cp3 = getelementptr i64, i64* %pi, i32 2
+  store i64 %ia0cp3, i64* %pia0cp3
+
+; Fold strtoll(a[1].a + 2, 0, 0, i8** null, i32 0) to 3.
+  %pa1ap2 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 0, i64 2
+  %ia1ap2 = call i64 @strtoll(i8* %pa1ap2, i8** null, i32 0)
+  %pia1ap2 = getelementptr i64, i64* %pi, i32 3
+  store i64 %ia1ap2, i64* %pia1ap2
+
+; Fold strtoll(a[1].b + 3, 0, 0, i8** null, i32 0) to 4.
+  %pa1bp3 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 1, i64 3
+  %ia1bp3 = call i64 @strtoll(i8* %pa1bp3, i8** null, i32 0)
+  %pia1bp3 = getelementptr i64, i64* %pi, i32 4
+  store i64 %ia1bp3, i64* %pia1bp3
+
+; Fold strtoll(a[1].c + 4, 0, 0, i8** null, i32 0) to 0.
+  %pa1cp4 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 2, i64 4
+  %ia1cp4 = call i64 @strtoll(i8* %pa1cp4, i8** null, i32 0)
+  %pia1cp4 = getelementptr i64, i64* %pi, i32 5
+  store i64 %ia1cp4, i64* %pia1cp4
+
+  ret void
+}

diff  --git a/llvm/test/Transforms/InstCombine/strcmp-3.ll b/llvm/test/Transforms/InstCombine/strcmp-3.ll
new file mode 100644
index 000000000000..499fed31ec39
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/strcmp-3.ll
@@ -0,0 +1,131 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; Verify that strlen calls with elements of constant arrays are folded.
+;
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+declare i32 @strcmp(i8*, i8*)
+
+ at a5 = constant [5 x [4 x i8]] [[4 x i8] c"123\00", [4 x i8] c"123\00", [4 x i8] c"12\00\00", [4 x i8] zeroinitializer, [4 x i8] zeroinitializer]
+
+
+; Fold strcmp(a5[0], a5[1]) to '1' - '1'.
+
+define i32 @fold_strcmp_a5i0_a5i1_to_0() {
+; CHECK-LABEL: @fold_strcmp_a5i0_a5i1_to_0(
+; CHECK-NEXT:    [[CMP:%.*]] = call i32 @strcmp(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([5 x [4 x i8]], [5 x [4 x i8]]* @a5, i64 0, i64 0, i64 0), i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([5 x [4 x i8]], [5 x [4 x i8]]* @a5, i64 0, i64 1, i64 0))
+; CHECK-NEXT:    ret i32 [[CMP]]
+;
+  %p = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5, i64 0, i64 0, i64 0
+  %q = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5, i64 0, i64 1, i64 0
+
+  %cmp = call i32 @strcmp(i8* %p, i8* %q)
+  ret i32 %cmp
+}
+
+
+; Do not fold strcmp(a5[0], a5[I]) where the index I is not constant.
+
+define i32 @call_strcmp_a5i0_a5iI(i64 %I) {
+; CHECK-LABEL: @call_strcmp_a5i0_a5iI(
+; CHECK-NEXT:    [[Q:%.*]] = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5, i64 0, i64 [[I:%.*]], i64 0
+; CHECK-NEXT:    [[CMP:%.*]] = call i32 @strcmp(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([5 x [4 x i8]], [5 x [4 x i8]]* @a5, i64 0, i64 0, i64 0), i8* noundef nonnull dereferenceable(1) [[Q]])
+; CHECK-NEXT:    ret i32 [[CMP]]
+;
+  %p = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5, i64 0, i64 0, i64 0
+  %q = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5, i64 0, i64 %I, i64 0
+
+  %cmp = call i32 @strcmp(i8* %p, i8* %q)
+  ret i32 %cmp
+}
+
+
+; Same as above but for strcmp(a5[I], a5[0]).
+
+define i32 @call_strcmp_a5iI_a5i0(i64 %I) {
+; CHECK-LABEL: @call_strcmp_a5iI_a5i0(
+; CHECK-NEXT:    [[P:%.*]] = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5, i64 0, i64 [[I:%.*]], i64 0
+; CHECK-NEXT:    [[CMP:%.*]] = call i32 @strcmp(i8* noundef nonnull dereferenceable(1) [[P]], i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([5 x [4 x i8]], [5 x [4 x i8]]* @a5, i64 0, i64 0, i64 0))
+; CHECK-NEXT:    ret i32 [[CMP]]
+;
+  %p = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5, i64 0, i64 %I, i64 0
+  %q = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5, i64 0, i64 0, i64 0
+
+  %cmp = call i32 @strcmp(i8* %p, i8* %q)
+  ret i32 %cmp
+}
+
+
+; Fold strcmp(a5[0], &a5[1][1]) to '1' - '2'.
+
+define i32 @fold_strcmp_a5i0_a5i1_p1_to_0() {
+; CHECK-LABEL: @fold_strcmp_a5i0_a5i1_p1_to_0(
+; CHECK-NEXT:    [[CMP:%.*]] = call i32 @strcmp(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([5 x [4 x i8]], [5 x [4 x i8]]* @a5, i64 0, i64 0, i64 0), i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([5 x [4 x i8]], [5 x [4 x i8]]* @a5, i64 0, i64 1, i64 1))
+; CHECK-NEXT:    ret i32 [[CMP]]
+;
+  %p = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5, i64 0, i64 0, i64 0
+  %q = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5, i64 0, i64 1, i64 1
+
+  %cmp = call i32 @strcmp(i8* %p, i8* %q)
+  ret i32 %cmp
+}
+
+
+; Do not fold strcmp(a5[0], &a5[1][I]) when the index I is not constant.
+
+define i32 @call_strcmp_a5i0_a5i1_pI(i64 %I) {
+; CHECK-LABEL: @call_strcmp_a5i0_a5i1_pI(
+; CHECK-NEXT:    [[Q:%.*]] = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5, i64 0, i64 1, i64 [[I:%.*]]
+; CHECK-NEXT:    [[CMP:%.*]] = call i32 @strcmp(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([5 x [4 x i8]], [5 x [4 x i8]]* @a5, i64 0, i64 0, i64 0), i8* noundef nonnull dereferenceable(1) [[Q]])
+; CHECK-NEXT:    ret i32 [[CMP]]
+;
+  %p = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5, i64 0, i64 0, i64 0
+  %q = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5, i64 0, i64 1, i64 %I
+
+  %cmp = call i32 @strcmp(i8* %p, i8* %q)
+  ret i32 %cmp
+}
+
+
+; Fold strcmp(&a5[0][1], a5[1]) to '2' - '1'.
+
+define i32 @fold_strcmp_a5i0_p1_a5i1_to_0() {
+; CHECK-LABEL: @fold_strcmp_a5i0_p1_a5i1_to_0(
+; CHECK-NEXT:    [[CMP:%.*]] = call i32 @strcmp(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([5 x [4 x i8]], [5 x [4 x i8]]* @a5, i64 0, i64 0, i64 1), i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([5 x [4 x i8]], [5 x [4 x i8]]* @a5, i64 0, i64 1, i64 0))
+; CHECK-NEXT:    ret i32 [[CMP]]
+;
+  %p = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5, i64 0, i64 0, i64 1
+  %q = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5, i64 0, i64 1, i64 0
+
+  %cmp = call i32 @strcmp(i8* %p, i8* %q)
+  ret i32 %cmp
+}
+
+
+; Fold strcmp(a5[0], a5[2]) to a5[0][2] - a5[2][2] or 1.
+
+define i32 @fold_strcmp_a5i0_a5i2_to_0() {
+; CHECK-LABEL: @fold_strcmp_a5i0_a5i2_to_0(
+; CHECK-NEXT:    [[CMP:%.*]] = call i32 @strcmp(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([5 x [4 x i8]], [5 x [4 x i8]]* @a5, i64 0, i64 0, i64 0), i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([5 x [4 x i8]], [5 x [4 x i8]]* @a5, i64 0, i64 2, i64 0))
+; CHECK-NEXT:    ret i32 [[CMP]]
+;
+  %p = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5, i64 0, i64 0, i64 0
+  %q = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5, i64 0, i64 2, i64 0
+
+  %cmp = call i32 @strcmp(i8* %p, i8* %q)
+  ret i32 %cmp
+}
+
+
+; Fold strcmp(a5[2], a5[0]) to a5[0][2] - a5[2][2] or 1.
+
+define i32 @fold_strcmp_a5i2_a5i0_to_m1() {
+; CHECK-LABEL: @fold_strcmp_a5i2_a5i0_to_m1(
+; CHECK-NEXT:    [[CMP:%.*]] = call i32 @strcmp(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([5 x [4 x i8]], [5 x [4 x i8]]* @a5, i64 0, i64 2, i64 0), i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([5 x [4 x i8]], [5 x [4 x i8]]* @a5, i64 0, i64 0, i64 0))
+; CHECK-NEXT:    ret i32 [[CMP]]
+;
+  %p = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5, i64 0, i64 0, i64 0
+  %q = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5, i64 0, i64 2, i64 0
+
+  %cmp = call i32 @strcmp(i8* %q, i8* %p)
+  ret i32 %cmp
+}

diff  --git a/llvm/test/Transforms/InstCombine/strcmp-4.ll b/llvm/test/Transforms/InstCombine/strcmp-4.ll
new file mode 100644
index 000000000000..7bf3dacd52e6
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/strcmp-4.ll
@@ -0,0 +1,25 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; TODO: Test that ...
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+declare i32 @strcmp(i8*, i8*)
+
+ at s9 = constant [10 x i8] c"123456789\00"
+
+
+; Fold strcmp(C ? s3 : s5, s3) to C ? 0 : 1.
+
+define i32 @fold_strcmp_s3_x_s4_s3(i1 %C) {
+; CHECK-LABEL: @fold_strcmp_s3_x_s4_s3(
+; CHECK-NEXT:    [[PTR:%.*]] = select i1 [[C:%.*]], i8* getelementptr inbounds ([10 x i8], [10 x i8]* @s9, i64 0, i64 6), i8* getelementptr inbounds ([10 x i8], [10 x i8]* @s9, i64 0, i64 5)
+; CHECK-NEXT:    [[CMP:%.*]] = call i32 @strcmp(i8* noundef nonnull dereferenceable(1) [[PTR]], i8* noundef nonnull dereferenceable(4) getelementptr inbounds ([10 x i8], [10 x i8]* @s9, i64 0, i64 6))
+; CHECK-NEXT:    ret i32 [[CMP]]
+;
+
+  %ps3 = getelementptr [10 x i8], [10 x i8]* @s9, i64 0, i64 6
+  %ps4 = getelementptr [10 x i8], [10 x i8]* @s9, i64 0, i64 5
+
+  %ptr = select i1 %C, i8* %ps3, i8* %ps4
+  %cmp = call i32 @strcmp(i8* %ptr, i8* %ps3)
+  ret i32 %cmp
+}

diff  --git a/llvm/test/Transforms/InstCombine/strlen-5.ll b/llvm/test/Transforms/InstCombine/strlen-5.ll
new file mode 100644
index 000000000000..db8a10d82de2
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/strlen-5.ll
@@ -0,0 +1,268 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; Verify that strlen calls with elements of constant arrays are folded.
+;
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+declare i64 @strlen(i8*)
+
+ at a5_4 = constant [5 x [4 x i8]] [[4 x i8] c"123\00", [4 x i8] c"12\00\00", [4 x i8] c"1\00\00\00", [4 x i8] zeroinitializer, [4 x i8] zeroinitializer]
+
+
+; Fold strlen(a5_4[0]) to 3.
+
+define i64 @fold_a5_4_i0_to_3() {
+; CHECK-LABEL: @fold_a5_4_i0_to_3(
+; CHECK-NEXT:    [[LEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 0, i64 0))
+; CHECK-NEXT:    ret i64 [[LEN]]
+;
+  %ptr = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 0, i64 0
+  %len = call i64 @strlen(i8* %ptr)
+  ret i64 %len
+}
+
+
+; Fold strlen(&a5_4[0][1]) to 2.
+
+define i64 @fold_a5_4_i0_p1_to_2() {
+; CHECK-LABEL: @fold_a5_4_i0_p1_to_2(
+; CHECK-NEXT:    [[LEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 0, i64 1))
+; CHECK-NEXT:    ret i64 [[LEN]]
+;
+  %ptr = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 0, i64 1
+  %len = call i64 @strlen(i8* %ptr)
+  ret i64 %len
+}
+
+
+; Fold strlen(&a5_4[0][2]) to 1.
+
+define i64 @fold_a5_4_i0_p2_to_1() {
+; CHECK-LABEL: @fold_a5_4_i0_p2_to_1(
+; CHECK-NEXT:    [[LEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 0, i64 2))
+; CHECK-NEXT:    ret i64 [[LEN]]
+;
+  %ptr = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 0, i64 2
+  %len = call i64 @strlen(i8* %ptr)
+  ret i64 %len
+}
+
+
+; Fold strlen(&a5_4[0][3]) to 0.
+
+define i64 @fold_a5_4_i0_p3_to_0() {
+; CHECK-LABEL: @fold_a5_4_i0_p3_to_0(
+; CHECK-NEXT:    [[LEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 0, i64 3))
+; CHECK-NEXT:    ret i64 [[LEN]]
+;
+  %ptr = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 0, i64 3
+  %len = call i64 @strlen(i8* %ptr)
+  ret i64 %len
+}
+
+
+; Fold strlen(a5_4[1]) to 2.
+
+define i64 @fold_a5_4_i1_to_2() {
+; CHECK-LABEL: @fold_a5_4_i1_to_2(
+; CHECK-NEXT:    [[LEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 1, i64 0))
+; CHECK-NEXT:    ret i64 [[LEN]]
+;
+  %ptr = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 1, i64 0
+  %len = call i64 @strlen(i8* %ptr)
+  ret i64 %len
+}
+
+
+; Fold strlen(&a5_4[1][1]) to 1.
+
+define i64 @fold_a5_4_i1_p1_to_1() {
+; CHECK-LABEL: @fold_a5_4_i1_p1_to_1(
+; CHECK-NEXT:    [[LEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 1, i64 1))
+; CHECK-NEXT:    ret i64 [[LEN]]
+;
+  %ptr = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 1, i64 1
+  %len = call i64 @strlen(i8* %ptr)
+  ret i64 %len
+}
+
+
+; Fold strlen(&a5_4[1][2]) to 0.
+
+define i64 @fold_a5_4_i1_p2_to_0() {
+; CHECK-LABEL: @fold_a5_4_i1_p2_to_0(
+; CHECK-NEXT:    [[LEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 1, i64 2))
+; CHECK-NEXT:    ret i64 [[LEN]]
+;
+  %ptr = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 1, i64 2
+  %len = call i64 @strlen(i8* %ptr)
+  ret i64 %len
+}
+
+
+; Fold strlen(&a5_4[1][3]) to 0.
+
+define i64 @fold_a5_4_i1_p3_to_0() {
+; CHECK-LABEL: @fold_a5_4_i1_p3_to_0(
+; CHECK-NEXT:    [[LEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 1, i64 3))
+; CHECK-NEXT:    ret i64 [[LEN]]
+;
+  %ptr = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 1, i64 3
+  %len = call i64 @strlen(i8* %ptr)
+  ret i64 %len
+}
+
+
+; Fold strlen(a5_4[2]) to 1.
+
+define i64 @fold_a5_4_i2_to_1() {
+; CHECK-LABEL: @fold_a5_4_i2_to_1(
+; CHECK-NEXT:    [[LEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 2, i64 0))
+; CHECK-NEXT:    ret i64 [[LEN]]
+;
+  %ptr = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 2, i64 0
+  %len = call i64 @strlen(i8* %ptr)
+  ret i64 %len
+}
+
+
+; Fold strlen(&a5_4[2][1]) to 0.
+
+define i64 @fold_a5_4_i2_p1_to_0() {
+; CHECK-LABEL: @fold_a5_4_i2_p1_to_0(
+; CHECK-NEXT:    [[LEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 2, i64 1))
+; CHECK-NEXT:    ret i64 [[LEN]]
+;
+  %ptr = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 2, i64 1
+  %len = call i64 @strlen(i8* %ptr)
+  ret i64 %len
+}
+
+
+; Fold strlen(&a5_4[2][2]) to 0.
+
+define i64 @fold_a5_4_i2_p2_to_0() {
+; CHECK-LABEL: @fold_a5_4_i2_p2_to_0(
+; CHECK-NEXT:    [[LEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 2, i64 2))
+; CHECK-NEXT:    ret i64 [[LEN]]
+;
+  %ptr = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 2, i64 2
+  %len = call i64 @strlen(i8* %ptr)
+  ret i64 %len
+}
+
+
+; Fold strlen(&a5_4[2][3]) to 0.
+
+define i64 @fold_a5_4_i2_p3_to_0() {
+; CHECK-LABEL: @fold_a5_4_i2_p3_to_0(
+; CHECK-NEXT:    [[LEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 2, i64 3))
+; CHECK-NEXT:    ret i64 [[LEN]]
+;
+  %ptr = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 2, i64 3
+  %len = call i64 @strlen(i8* %ptr)
+  ret i64 %len
+}
+
+
+; Fold strlen(a5_4[3]) to 0
+
+define i64 @fold_a5_4_i3_to_0() {
+; CHECK-LABEL: @fold_a5_4_i3_to_0(
+; CHECK-NEXT:    [[LEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 3, i64 0))
+; CHECK-NEXT:    ret i64 [[LEN]]
+;
+  %ptr = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 3, i64 0
+  %len = call i64 @strlen(i8* %ptr)
+  ret i64 %len
+}
+
+
+; Fold strlen(&a5_4[3][1]) to 0
+
+define i64 @fold_a5_4_i3_p1_to_0() {
+; CHECK-LABEL: @fold_a5_4_i3_p1_to_0(
+; CHECK-NEXT:    [[LEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 3, i64 1))
+; CHECK-NEXT:    ret i64 [[LEN]]
+;
+  %ptr = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 3, i64 1
+  %len = call i64 @strlen(i8* %ptr)
+  ret i64 %len
+}
+
+
+; Fold strlen(&a5_4[3][2]) to 0
+
+define i64 @fold_a5_4_i3_p2_to_0() {
+; CHECK-LABEL: @fold_a5_4_i3_p2_to_0(
+; CHECK-NEXT:    [[LEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 3, i64 2))
+; CHECK-NEXT:    ret i64 [[LEN]]
+;
+  %ptr = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 3, i64 2
+  %len = call i64 @strlen(i8* %ptr)
+  ret i64 %len
+}
+
+
+; Fold strlen(&a5_4[3][3]) to 0
+
+define i64 @fold_a5_3_i4_p3_to_0() {
+; CHECK-LABEL: @fold_a5_3_i4_p3_to_0(
+; CHECK-NEXT:    [[LEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 3, i64 3))
+; CHECK-NEXT:    ret i64 [[LEN]]
+;
+  %ptr = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 3, i64 3
+  %len = call i64 @strlen(i8* %ptr)
+  ret i64 %len
+}
+
+
+; Fold strlen(a5_4[4]) to 0
+
+define i64 @fold_a5_4_i4_to_0() {
+; CHECK-LABEL: @fold_a5_4_i4_to_0(
+; CHECK-NEXT:    [[LEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 4, i64 0))
+; CHECK-NEXT:    ret i64 [[LEN]]
+;
+  %ptr = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 4, i64 0
+  %len = call i64 @strlen(i8* %ptr)
+  ret i64 %len
+}
+
+
+; Fold strlen(&a5_4[4][1]) to 0
+
+define i64 @fold_a5_4_i4_p1_to_0() {
+; CHECK-LABEL: @fold_a5_4_i4_p1_to_0(
+; CHECK-NEXT:    [[LEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 4, i64 1))
+; CHECK-NEXT:    ret i64 [[LEN]]
+;
+  %ptr = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 4, i64 1
+  %len = call i64 @strlen(i8* %ptr)
+  ret i64 %len
+}
+
+
+; Fold strlen(&a5_4[4][2]) to 0
+
+define i64 @fold_a5_4_i4_p2_to_0() {
+; CHECK-LABEL: @fold_a5_4_i4_p2_to_0(
+; CHECK-NEXT:    [[LEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 4, i64 2))
+; CHECK-NEXT:    ret i64 [[LEN]]
+;
+  %ptr = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 4, i64 2
+  %len = call i64 @strlen(i8* %ptr)
+  ret i64 %len
+}
+
+
+; Fold strlen(&a5_4[4][3]) to 0
+
+define i64 @fold_a5_4_i4_p3_to_0() {
+; CHECK-LABEL: @fold_a5_4_i4_p3_to_0(
+; CHECK-NEXT:    [[LEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 4, i64 3))
+; CHECK-NEXT:    ret i64 [[LEN]]
+;
+  %ptr = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 4, i64 3
+  %len = call i64 @strlen(i8* %ptr)
+  ret i64 %len
+}

diff  --git a/llvm/test/Transforms/InstCombine/strlen-6.ll b/llvm/test/Transforms/InstCombine/strlen-6.ll
new file mode 100644
index 000000000000..42c755260b15
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/strlen-6.ll
@@ -0,0 +1,312 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; Verify that strlen calls with members of constant structs are folded.
+;
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+; struct A_a4 { char a[4]; };
+%struct.A_a4 = type { [4 x i8] }
+
+; struct A_a4_a5 { char a[4], b[5]; };
+%struct.A_a4_a5 = type { [4 x i8], [5 x i8] }
+
+; struct A_a4_i32_a5 { char a[4]; int32_t i; char b[5]; };
+%struct.A_a4_i32_a5 = type { [4 x i8], i32, [5 x i8] }
+
+ at a_s3 = constant %struct.A_a4 { [4 x i8 ] c"123\00" }
+ at a_s3_s4 = constant %struct.A_a4_a5 { [4 x i8 ] c"123\00", [5 x i8] c"1234\00" }
+ at a_s3_i32_s4 = constant %struct.A_a4_i32_a5 { [4 x i8 ] c"123\00", i32 -1, [5 x i8] c"1234\00" }
+
+; Structs with flexible array members.
+ at ax_s3 = constant { i8, [4 x i8] } { i8 3, [4 x i8] c"123\00" }
+ at ax_s5 = constant { i16, [6 x i8] } { i16 5, [6 x i8] c"12345\00" }
+ at ax_s7 = constant { i32, i32, [8 x i8] } { i32 7, i32 0, [8 x i8] c"1234567\00" }
+
+ at ax = external global [0 x i64]
+
+
+declare i64 @strlen(i8*)
+
+
+; Fold strlen(a_s3.a) to 3.
+
+define i64 @fold_strlen_a_S3_to_3() {
+; CHECK-LABEL: @fold_strlen_a_S3_to_3(
+; CHECK-NEXT:    [[LEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4:%.*]], %struct.A_a4* @a_s3, i64 0, i32 0, i64 0))
+; CHECK-NEXT:    ret i64 [[LEN]]
+;
+  %ptr = getelementptr %struct.A_a4, %struct.A_a4* @a_s3, i32 0, i32 0, i32 0
+  %len = call i64 @strlen(i8* %ptr)
+  ret i64 %len
+}
+
+
+; Fold strlen(&a_s3.a[1]) to 2.
+
+define i64 @fold_strlen_a_S3_p1_to_2() {
+; CHECK-LABEL: @fold_strlen_a_S3_p1_to_2(
+; CHECK-NEXT:    [[LEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4:%.*]], %struct.A_a4* @a_s3, i64 0, i32 0, i64 1))
+; CHECK-NEXT:    ret i64 [[LEN]]
+;
+  %ptr = getelementptr %struct.A_a4, %struct.A_a4* @a_s3, i32 0, i32 0, i32 1
+  %len = call i64 @strlen(i8* %ptr)
+  ret i64 %len
+}
+
+
+; Fold strlen(&a_s3.a[2]) to 1.
+
+define i64 @fold_strlen_a_S3_p2_to_1() {
+; CHECK-LABEL: @fold_strlen_a_S3_p2_to_1(
+; CHECK-NEXT:    [[LEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4:%.*]], %struct.A_a4* @a_s3, i64 0, i32 0, i64 2))
+; CHECK-NEXT:    ret i64 [[LEN]]
+;
+  %ptr = getelementptr %struct.A_a4, %struct.A_a4* @a_s3, i32 0, i32 0, i32 2
+  %len = call i64 @strlen(i8* %ptr)
+  ret i64 %len
+}
+
+
+; Fold strlen(&a_s3.a[3]) to 0.
+
+define i64 @fold_strlen_a_S3_p3_to_0() {
+; CHECK-LABEL: @fold_strlen_a_S3_p3_to_0(
+; CHECK-NEXT:    [[LEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4:%.*]], %struct.A_a4* @a_s3, i64 0, i32 0, i64 3))
+; CHECK-NEXT:    ret i64 [[LEN]]
+;
+  %ptr = getelementptr %struct.A_a4, %struct.A_a4* @a_s3, i32 0, i32 0, i32 3
+  %len = call i64 @strlen(i8* %ptr)
+  ret i64 %len
+}
+
+
+; Fold strlen(a_s3_s4.a) to 3.
+
+define i64 @fold_strlen_a_S3_s4_to_3() {
+; CHECK-LABEL: @fold_strlen_a_S3_s4_to_3(
+; CHECK-NEXT:    [[LEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_A5:%.*]], %struct.A_a4_a5* @a_s3_s4, i64 0, i32 0, i64 0))
+; CHECK-NEXT:    ret i64 [[LEN]]
+;
+  %ptr = getelementptr %struct.A_a4_a5, %struct.A_a4_a5* @a_s3_s4, i32 0, i32 0, i32 0
+  %len = call i64 @strlen(i8* %ptr)
+  ret i64 %len
+}
+
+
+; Fold strlen(&a_s3_s4.a[2]) to 1.
+
+define i64 @fold_strlen_a_S3_p2_s4_to_1() {
+; CHECK-LABEL: @fold_strlen_a_S3_p2_s4_to_1(
+; CHECK-NEXT:    [[LEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_A5:%.*]], %struct.A_a4_a5* @a_s3_s4, i64 0, i32 0, i64 2))
+; CHECK-NEXT:    ret i64 [[LEN]]
+;
+  %ptr = getelementptr %struct.A_a4_a5, %struct.A_a4_a5* @a_s3_s4, i32 0, i32 0, i32 2
+  %len = call i64 @strlen(i8* %ptr)
+  ret i64 %len
+}
+
+
+; Fold strlen(a_s3_s4.b) to 4.
+; Exercise both variants of the GEP index.
+
+define void @fold_strlen_a_s3_S4_to_4() {
+; CHECK-LABEL: @fold_strlen_a_s3_S4_to_4(
+; CHECK-NEXT:    [[LEN1:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_A5:%.*]], %struct.A_a4_a5* @a_s3_s4, i64 0, i32 1, i64 0))
+; CHECK-NEXT:    store i64 [[LEN1]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 0), align 4
+; CHECK-NEXT:    [[LEN2:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_A5]], %struct.A_a4_a5* @a_s3_s4, i64 0, i32 1, i64 0))
+; CHECK-NEXT:    store i64 [[LEN1]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 1), align 4
+; CHECK-NEXT:    ret void
+;
+  %p1 = getelementptr %struct.A_a4_a5, %struct.A_a4_a5* @a_s3_s4, i32 0, i32 0, i32 4
+  %len1 = call i64 @strlen(i8* %p1)
+  %pax0 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 0
+  store i64 %len1, i64* %pax0
+
+  %p2 = getelementptr %struct.A_a4_a5, %struct.A_a4_a5* @a_s3_s4, i32 0, i32 1, i32 0
+  %len2 = call i64 @strlen(i8* %p2)
+  %pax1 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 1
+  store i64 %len1, i64* %pax1
+
+  ret void
+}
+
+
+; Fold strlen(&a_s3_s4.b[1]) to 3.
+; Exercise both variants of the GEP index.
+
+define void @fold_strlen_a_s3_S4_p1_to_3() {
+; CHECK-LABEL: @fold_strlen_a_s3_S4_p1_to_3(
+; CHECK-NEXT:    [[LEN1:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_A5:%.*]], %struct.A_a4_a5* @a_s3_s4, i64 0, i32 1, i64 1))
+; CHECK-NEXT:    store i64 [[LEN1]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 0), align 4
+; CHECK-NEXT:    [[LEN2:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_A5]], %struct.A_a4_a5* @a_s3_s4, i64 0, i32 1, i64 1))
+; CHECK-NEXT:    store i64 [[LEN1]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 1), align 4
+; CHECK-NEXT:    ret void
+;
+  %p1 = getelementptr %struct.A_a4_a5, %struct.A_a4_a5* @a_s3_s4, i32 0, i32 0, i32 5
+  %len1 = call i64 @strlen(i8* %p1)
+  %pax0 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 0
+  store i64 %len1, i64* %pax0
+
+  %p2 = getelementptr %struct.A_a4_a5, %struct.A_a4_a5* @a_s3_s4, i32 0, i32 1, i32 1
+  %len2 = call i64 @strlen(i8* %p2)
+  %pax1 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 1
+  store i64 %len1, i64* %pax1
+
+  ret void
+}
+
+
+; Fold strlen(a_s3_i32_s4.b) to 4.
+; Exercise both variants of the GEP index.
+
+define void @fold_strlen_a_s3_i32_S4_to_4() {
+; CHECK-LABEL: @fold_strlen_a_s3_i32_S4_to_4(
+; CHECK-NEXT:    [[LEN1:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_I32_A5:%.*]], %struct.A_a4_i32_a5* @a_s3_i32_s4, i64 0, i32 2, i64 0))
+; CHECK-NEXT:    store i64 [[LEN1]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 0), align 4
+; CHECK-NEXT:    [[LEN2:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_I32_A5]], %struct.A_a4_i32_a5* @a_s3_i32_s4, i64 0, i32 2, i64 0))
+; CHECK-NEXT:    store i64 [[LEN1]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 1), align 4
+; CHECK-NEXT:    ret void
+;
+  %p1 = getelementptr %struct.A_a4_i32_a5, %struct.A_a4_i32_a5* @a_s3_i32_s4, i32 0, i32 0, i32 8
+  %len1 = call i64 @strlen(i8* %p1)
+  %pax0 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 0
+  store i64 %len1, i64* %pax0
+
+  %p2 = getelementptr %struct.A_a4_i32_a5, %struct.A_a4_i32_a5* @a_s3_i32_s4, i32 0, i32 2, i32 0
+  %len2 = call i64 @strlen(i8* %p2)
+  %pax1 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 1
+  store i64 %len1, i64* %pax1
+
+  ret void
+}
+
+
+; Fold strlen(&a_s3_i32_s4.b[1]) to 3.
+; Exercise both variants of the GEP index.
+
+define void @fold_strlen_a_s3_i32_S4_p1_to_3() {
+; CHECK-LABEL: @fold_strlen_a_s3_i32_S4_p1_to_3(
+; CHECK-NEXT:    [[LEN1:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_I32_A5:%.*]], %struct.A_a4_i32_a5* @a_s3_i32_s4, i64 0, i32 2, i64 1))
+; CHECK-NEXT:    store i64 [[LEN1]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 0), align 4
+; CHECK-NEXT:    [[LEN2:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_I32_A5]], %struct.A_a4_i32_a5* @a_s3_i32_s4, i64 0, i32 2, i64 0))
+; CHECK-NEXT:    store i64 [[LEN1]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 1), align 4
+; CHECK-NEXT:    ret void
+;
+  %p1 = getelementptr %struct.A_a4_i32_a5, %struct.A_a4_i32_a5* @a_s3_i32_s4, i32 0, i32 0, i32 9
+  %len1 = call i64 @strlen(i8* %p1)
+  %pax0 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 0
+  store i64 %len1, i64* %pax0
+
+  %p2 = getelementptr %struct.A_a4_i32_a5, %struct.A_a4_i32_a5* @a_s3_i32_s4, i32 0, i32 2, i32 0
+  %len2 = call i64 @strlen(i8* %p2)
+  %pax1 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 1
+  store i64 %len1, i64* %pax1
+
+  ret void
+}
+
+
+; Fold strlen(&a_s3_i32_s4.b[2]) to 2.
+; Exercise both variants of the GEP index.
+
+define void @fold_strlen_a_s3_i32_S4_p2_to_2() {
+; CHECK-LABEL: @fold_strlen_a_s3_i32_S4_p2_to_2(
+; CHECK-NEXT:    [[LEN1:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_I32_A5:%.*]], %struct.A_a4_i32_a5* @a_s3_i32_s4, i64 0, i32 2, i64 2))
+; CHECK-NEXT:    store i64 [[LEN1]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 0), align 4
+; CHECK-NEXT:    [[LEN2:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_I32_A5]], %struct.A_a4_i32_a5* @a_s3_i32_s4, i64 0, i32 2, i64 2))
+; CHECK-NEXT:    store i64 [[LEN1]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 1), align 4
+; CHECK-NEXT:    ret void
+;
+  %p1 = getelementptr %struct.A_a4_i32_a5, %struct.A_a4_i32_a5* @a_s3_i32_s4, i32 0, i32 0, i32 10
+  %len1 = call i64 @strlen(i8* %p1)
+  %pax0 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 0
+  store i64 %len1, i64* %pax0
+
+  %p2 = getelementptr %struct.A_a4_i32_a5, %struct.A_a4_i32_a5* @a_s3_i32_s4, i32 0, i32 2, i32 2
+  %len2 = call i64 @strlen(i8* %p2)
+  %pax1 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 1
+  store i64 %len1, i64* %pax1
+
+  ret void
+}
+
+
+; Fold strlen(&a_s3_i32_s4.b[3]) to 1.
+; Exercise both variants of the GEP index.
+
+define void @fold_strlen_a_s3_i32_S4_p3_to_1() {
+; CHECK-LABEL: @fold_strlen_a_s3_i32_S4_p3_to_1(
+; CHECK-NEXT:    [[LEN1:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_I32_A5:%.*]], %struct.A_a4_i32_a5* @a_s3_i32_s4, i64 0, i32 2, i64 3))
+; CHECK-NEXT:    store i64 [[LEN1]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 0), align 4
+; CHECK-NEXT:    [[LEN2:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_I32_A5]], %struct.A_a4_i32_a5* @a_s3_i32_s4, i64 0, i32 2, i64 3))
+; CHECK-NEXT:    store i64 [[LEN1]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 1), align 4
+; CHECK-NEXT:    ret void
+;
+  %p1 = getelementptr %struct.A_a4_i32_a5, %struct.A_a4_i32_a5* @a_s3_i32_s4, i32 0, i32 0, i32 11
+  %len1 = call i64 @strlen(i8* %p1)
+  %pax0 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 0
+  store i64 %len1, i64* %pax0
+
+  %p2 = getelementptr %struct.A_a4_i32_a5, %struct.A_a4_i32_a5* @a_s3_i32_s4, i32 0, i32 2, i32 3
+  %len2 = call i64 @strlen(i8* %p2)
+  %pax1 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 1
+  store i64 %len1, i64* %pax1
+
+  ret void
+}
+
+
+; Fold strlen(&a_s3_i32_s4.b[4]) to 0.
+; Exercise both variants of the GEP index.
+
+define void @fold_strlen_a_s3_i32_S4_p4_to_0() {
+; CHECK-LABEL: @fold_strlen_a_s3_i32_S4_p4_to_0(
+; CHECK-NEXT:    [[LEN1:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_I32_A5:%.*]], %struct.A_a4_i32_a5* @a_s3_i32_s4, i64 0, i32 2, i64 4))
+; CHECK-NEXT:    store i64 [[LEN1]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 0), align 4
+; CHECK-NEXT:    [[LEN2:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_I32_A5]], %struct.A_a4_i32_a5* @a_s3_i32_s4, i64 0, i32 2, i64 4))
+; CHECK-NEXT:    store i64 [[LEN1]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 1), align 4
+; CHECK-NEXT:    ret void
+;
+  %p1 = getelementptr %struct.A_a4_i32_a5, %struct.A_a4_i32_a5* @a_s3_i32_s4, i32 0, i32 0, i32 12
+  %len1 = call i64 @strlen(i8* %p1)
+  %pax0 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 0
+  store i64 %len1, i64* %pax0
+
+  %p2 = getelementptr %struct.A_a4_i32_a5, %struct.A_a4_i32_a5* @a_s3_i32_s4, i32 0, i32 2, i32 4
+  %len2 = call i64 @strlen(i8* %p2)
+  %pax1 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 1
+  store i64 %len1, i64* %pax1
+
+  ret void
+}
+
+
+; Fold strlen(ax_sN.a) of an constant initialized flexible array member
+; to N for N in { 3, 5, 7 }.
+
+define void @fold_strlen_ax_s() {
+; CHECK-LABEL: @fold_strlen_ax_s(
+; CHECK-NEXT:    [[LEN3:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ({ i8, [4 x i8] }, { i8, [4 x i8] }* @ax_s3, i64 0, i32 1, i64 0))
+; CHECK-NEXT:    store i64 [[LEN3]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 0), align 4
+; CHECK-NEXT:    [[LEN5:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ({ i16, [6 x i8] }, { i16, [6 x i8] }* @ax_s5, i64 0, i32 1, i64 0))
+; CHECK-NEXT:    store i64 [[LEN5]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 1), align 4
+; CHECK-NEXT:    [[LEN7:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ({ i32, i32, [8 x i8] }, { i32, i32, [8 x i8] }* @ax_s7, i64 0, i32 2, i64 0))
+; CHECK-NEXT:    store i64 [[LEN7]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 2), align 4
+; CHECK-NEXT:    ret void
+;
+  %pax_s3 = getelementptr { i8, [4 x i8] }, { i8, [4 x i8] }* @ax_s3, i64 0, i32 1, i64 0
+  %len3 = call i64 @strlen(i8* %pax_s3)
+  %pax1 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 0
+  store i64 %len3, i64* %pax1
+
+  %pax_s5 = getelementptr { i16, [6 x i8] }, { i16, [6 x i8] }* @ax_s5, i64 0, i32 1, i64 0
+  %len5 = call i64 @strlen(i8* %pax_s5)
+  %pax2 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 1
+  store i64 %len5, i64* %pax2
+
+  %pax_s7 = getelementptr { i32, i32, [8 x i8] }, { i32, i32, [8 x i8] }* @ax_s7, i64 0, i32 2, i64 0
+  %len7 = call i64 @strlen(i8* %pax_s7)
+  %pax3 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 2
+  store i64 %len7, i64* %pax3
+
+  ret void
+}

diff  --git a/llvm/test/Transforms/InstCombine/strlen-7.ll b/llvm/test/Transforms/InstCombine/strlen-7.ll
new file mode 100644
index 000000000000..61801770d483
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/strlen-7.ll
@@ -0,0 +1,228 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; Verify that strlen calls with members of constant structs are folded.
+;
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+declare i64 @strlen(i8*)
+
+%struct.A = type { [4 x i8], [5 x i8] }
+
+ at a = constant [2 x %struct.A] [%struct.A { [4 x i8] c"1\00\00\00", [5 x i8] c"12\00\00\00" }, %struct.A { [4 x i8] c"123\00", [5 x i8] c"1234\00" }], align 16
+
+
+; Fold strlen(a[I].a + J) and strlen(a[I].b + J) with constant I and J
+; to constants.
+
+define void @fold_strlen_A(i64* %plen) {
+; CHECK-LABEL: @fold_strlen_A(
+; CHECK-NEXT:    [[LENA0A:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 0, i64 0))
+; CHECK-NEXT:    store i64 [[LENA0A]], i64* [[PLEN:%.*]], align 4
+; CHECK-NEXT:    [[LENA0AP1:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 0, i64 1))
+; CHECK-NEXT:    [[PLEN1:%.*]] = getelementptr i64, i64* [[PLEN]], i64 1
+; CHECK-NEXT:    store i64 [[LENA0AP1]], i64* [[PLEN1]], align 4
+; CHECK-NEXT:    [[LENA0AP2:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 0, i64 2))
+; CHECK-NEXT:    [[PLEN2:%.*]] = getelementptr i64, i64* [[PLEN]], i64 2
+; CHECK-NEXT:    store i64 [[LENA0AP2]], i64* [[PLEN2]], align 4
+; CHECK-NEXT:    [[LENA0AP3:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 0, i64 3))
+; CHECK-NEXT:    [[PLEN3:%.*]] = getelementptr i64, i64* [[PLEN]], i64 3
+; CHECK-NEXT:    store i64 [[LENA0AP3]], i64* [[PLEN3]], align 4
+; CHECK-NEXT:    [[LENA0B:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 1, i64 0))
+; CHECK-NEXT:    [[PLEN4:%.*]] = getelementptr i64, i64* [[PLEN]], i64 4
+; CHECK-NEXT:    store i64 [[LENA0B]], i64* [[PLEN4]], align 4
+; CHECK-NEXT:    [[LENA0BP1:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 1, i64 1))
+; CHECK-NEXT:    [[PLEN5:%.*]] = getelementptr i64, i64* [[PLEN]], i64 5
+; CHECK-NEXT:    store i64 [[LENA0BP1]], i64* [[PLEN5]], align 4
+; CHECK-NEXT:    [[LENA0BP2:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 1, i64 2))
+; CHECK-NEXT:    [[PLEN6:%.*]] = getelementptr i64, i64* [[PLEN]], i64 6
+; CHECK-NEXT:    store i64 [[LENA0BP2]], i64* [[PLEN6]], align 4
+; CHECK-NEXT:    [[LENA0BP3:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 1, i64 3))
+; CHECK-NEXT:    [[PLEN7:%.*]] = getelementptr i64, i64* [[PLEN]], i64 7
+; CHECK-NEXT:    store i64 [[LENA0BP3]], i64* [[PLEN7]], align 4
+; CHECK-NEXT:    [[LENA0BP4:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 1, i64 4))
+; CHECK-NEXT:    [[PLEN8:%.*]] = getelementptr i64, i64* [[PLEN]], i64 8
+; CHECK-NEXT:    store i64 [[LENA0BP4]], i64* [[PLEN8]], align 4
+; CHECK-NEXT:    [[LENA1A:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 0, i64 0))
+; CHECK-NEXT:    [[PLEN9:%.*]] = getelementptr i64, i64* [[PLEN]], i64 9
+; CHECK-NEXT:    store i64 [[LENA1A]], i64* [[PLEN9]], align 4
+; CHECK-NEXT:    [[LENA1AP1:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 0, i64 1))
+; CHECK-NEXT:    [[PLEN10:%.*]] = getelementptr i64, i64* [[PLEN]], i64 10
+; CHECK-NEXT:    store i64 [[LENA1AP1]], i64* [[PLEN10]], align 4
+; CHECK-NEXT:    [[LENA1AP2:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 0, i64 2))
+; CHECK-NEXT:    [[PLEN11:%.*]] = getelementptr i64, i64* [[PLEN]], i64 11
+; CHECK-NEXT:    store i64 [[LENA1AP2]], i64* [[PLEN11]], align 4
+; CHECK-NEXT:    [[LENA1AP3:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 0, i64 3))
+; CHECK-NEXT:    [[PLEN12:%.*]] = getelementptr i64, i64* [[PLEN]], i64 12
+; CHECK-NEXT:    store i64 [[LENA1AP3]], i64* [[PLEN12]], align 4
+; CHECK-NEXT:    [[LENA1B:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 1, i64 0))
+; CHECK-NEXT:    [[PLEN14:%.*]] = getelementptr i64, i64* [[PLEN]], i64 14
+; CHECK-NEXT:    store i64 [[LENA1B]], i64* [[PLEN14]], align 4
+; CHECK-NEXT:    [[LENA1BP1:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 1, i64 1))
+; CHECK-NEXT:    [[PLEN15:%.*]] = getelementptr i64, i64* [[PLEN]], i64 15
+; CHECK-NEXT:    store i64 [[LENA1BP1]], i64* [[PLEN15]], align 4
+; CHECK-NEXT:    [[LENA1BP2:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 1, i64 2))
+; CHECK-NEXT:    [[PLEN16:%.*]] = getelementptr i64, i64* [[PLEN]], i64 16
+; CHECK-NEXT:    store i64 [[LENA1BP2]], i64* [[PLEN16]], align 4
+; CHECK-NEXT:    [[LENA1BP3:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 1, i64 3))
+; CHECK-NEXT:    [[PLEN17:%.*]] = getelementptr i64, i64* [[PLEN]], i64 17
+; CHECK-NEXT:    store i64 [[LENA1BP3]], i64* [[PLEN17]], align 4
+; CHECK-NEXT:    [[LENA1BP4:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 1, i64 4))
+; CHECK-NEXT:    [[PLEN18:%.*]] = getelementptr i64, i64* [[PLEN]], i64 18
+; CHECK-NEXT:    store i64 [[LENA1BP4]], i64* [[PLEN18]], align 4
+; CHECK-NEXT:    ret void
+;
+; Fold strlen(a[0].a) to 1.
+  %pa0a = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 0, i64 0
+  %lena0a = call i64 @strlen(i8* %pa0a)
+  %plen0 = getelementptr i64, i64* %plen, i32 0
+  store i64 %lena0a, i64* %plen0
+
+; Fold strlen(a[0].a + 1) to 0.
+  %pa0ap1 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 0, i64 1
+  %lena0ap1 = call i64 @strlen(i8* %pa0ap1)
+  %plen1 = getelementptr i64, i64* %plen, i32 1
+  store i64 %lena0ap1, i64* %plen1
+
+; Fold strlen(a[0].a + 2) to 0.
+  %pa0ap2 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 0, i64 2
+  %lena0ap2 = call i64 @strlen(i8* %pa0ap2)
+  %plen2 = getelementptr i64, i64* %plen, i32 2
+  store i64 %lena0ap2, i64* %plen2
+
+; Fold strlen(a[0].a + 3) to 0.
+  %pa0ap3 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 0, i64 3
+  %lena0ap3 = call i64 @strlen(i8* %pa0ap3)
+  %plen3 = getelementptr i64, i64* %plen, i32 3
+  store i64 %lena0ap3, i64* %plen3
+
+; Fold strlen(a[0].b) to 2.
+  %pa0b = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 1, i64 0
+  %lena0b = call i64 @strlen(i8* %pa0b)
+  %plen4 = getelementptr i64, i64* %plen, i32 4
+  store i64 %lena0b, i64* %plen4
+
+; Fold strlen(a[0].b + 1) to 1.
+  %pa0bp1 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 1, i64 1
+  %lena0bp1 = call i64 @strlen(i8* %pa0bp1)
+  %plen5 = getelementptr i64, i64* %plen, i32 5
+  store i64 %lena0bp1, i64* %plen5
+
+; Fold strlen(a[0].b + 2) to 0.
+  %pa0bp2 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 1, i64 2
+  %lena0bp2 = call i64 @strlen(i8* %pa0bp2)
+  %plen6 = getelementptr i64, i64* %plen, i32 6
+  store i64 %lena0bp2, i64* %plen6
+
+; Fold strlen(a[0].b + 3) to 0.
+  %pa0bp3 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 1, i64 3
+  %lena0bp3 = call i64 @strlen(i8* %pa0bp3)
+  %plen7 = getelementptr i64, i64* %plen, i32 7
+  store i64 %lena0bp3, i64* %plen7
+
+; Fold strlen(a[0].b + 4) to 0.
+  %pa0bp4 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 1, i64 4
+  %lena0bp4 = call i64 @strlen(i8* %pa0bp4)
+  %plen8 = getelementptr i64, i64* %plen, i32 8
+  store i64 %lena0bp4, i64* %plen8
+
+; Fold strlen(a[1].a) to 3.
+  %pa1a = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 0, i64 0
+  %lena1a = call i64 @strlen(i8* %pa1a)
+  %plen9 = getelementptr i64, i64* %plen, i32 9
+  store i64 %lena1a, i64* %plen9
+
+; Fold strlen(a[1].a + 1) to 2.
+  %pa1ap1 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 0, i64 1
+  %lena1ap1 = call i64 @strlen(i8* %pa1ap1)
+  %plen10 = getelementptr i64, i64* %plen, i32 10
+  store i64 %lena1ap1, i64* %plen10
+
+; Fold strlen(a[1].a + 2) to 1.
+  %pa1ap2 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 0, i64 2
+  %lena1ap2 = call i64 @strlen(i8* %pa1ap2)
+  %plen11 = getelementptr i64, i64* %plen, i32 11
+  store i64 %lena1ap2, i64* %plen11
+
+; Fold strlen(a[1].a + 3) to 0.
+  %pa1ap3 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 0, i64 3
+  %lena1ap3 = call i64 @strlen(i8* %pa1ap3)
+  %plen12 = getelementptr i64, i64* %plen, i32 12
+  store i64 %lena1ap3, i64* %plen12
+
+; Fold strlen(a[1].b) to 4.
+  %pa1b = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 1, i64 0
+  %lena1b = call i64 @strlen(i8* %pa1b)
+  %plen14 = getelementptr i64, i64* %plen, i32 14
+  store i64 %lena1b, i64* %plen14
+
+; Fold strlen(a[1].b + 1) to 3.
+  %pa1bp1 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 1, i64 1
+  %lena1bp1 = call i64 @strlen(i8* %pa1bp1)
+  %plen15 = getelementptr i64, i64* %plen, i32 15
+  store i64 %lena1bp1, i64* %plen15
+
+; Fold strlen(a[1].b + 2) to 2.
+  %pa1bp2 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 1, i64 2
+  %lena1bp2 = call i64 @strlen(i8* %pa1bp2)
+  %plen16 = getelementptr i64, i64* %plen, i32 16
+  store i64 %lena1bp2, i64* %plen16
+
+; Fold strlen(a[1].b + 3) to 1.
+  %pa1bp3 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 1, i64 3
+  %lena1bp3 = call i64 @strlen(i8* %pa1bp3)
+  %plen17 = getelementptr i64, i64* %plen, i32 17
+  store i64 %lena1bp3, i64* %plen17
+
+; Fold strlen(a[1].b + 4) to 0.
+  %pa1bp4 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 1, i64 4
+  %lena1bp4 = call i64 @strlen(i8* %pa1bp4)
+  %plen18 = getelementptr i64, i64* %plen, i32 18
+  store i64 %lena1bp4, i64* %plen18
+
+  ret void
+}
+
+
+; TODO: Fold strlen(a[I].a + X) and strlen(a[I].b + X) with constant I and
+; variable X to (X - strlen(a[I].a)) and (X - strlen(a[I].b)) respectively.
+
+define void @fold_strlen_A_pI(i64* %plen, i64 %I) {
+; CHECK-LABEL: @fold_strlen_A_pI(
+; CHECK-NEXT:    [[PA0A:%.*]] = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 0, i64 [[I:%.*]]
+; CHECK-NEXT:    [[LENA0A:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) [[PA0A]])
+; CHECK-NEXT:    store i64 [[LENA0A]], i64* [[PLEN:%.*]], align 4
+; CHECK-NEXT:    [[PA0B:%.*]] = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 1, i64 [[I]]
+; CHECK-NEXT:    [[LENA0B:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) [[PA0B]])
+; CHECK-NEXT:    [[PLEN1:%.*]] = getelementptr i64, i64* [[PLEN]], i64 1
+; CHECK-NEXT:    store i64 [[LENA0B]], i64* [[PLEN1]], align 4
+; CHECK-NEXT:    [[PA1A:%.*]] = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 0, i64 [[I]]
+; CHECK-NEXT:    [[LENA1A:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) [[PA1A]])
+; CHECK-NEXT:    [[PLEN2:%.*]] = getelementptr i64, i64* [[PLEN]], i64 2
+; CHECK-NEXT:    store i64 [[LENA1A]], i64* [[PLEN2]], align 4
+; CHECK-NEXT:    [[PA1B:%.*]] = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 1, i64 [[I]]
+; CHECK-NEXT:    [[LENA1B:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) [[PA1B]])
+; CHECK-NEXT:    [[PLEN3:%.*]] = getelementptr i64, i64* [[PLEN]], i64 3
+; CHECK-NEXT:    store i64 [[LENA1B]], i64* [[PLEN3]], align 4
+; CHECK-NEXT:    ret void
+;
+  %pa0a = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 0, i64 %I
+  %lena0a = call i64 @strlen(i8* %pa0a)
+  %plen0 = getelementptr i64, i64* %plen, i32 0
+  store i64 %lena0a, i64* %plen0
+
+  %pa0b = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 1, i64 %I
+  %lena0b = call i64 @strlen(i8* %pa0b)
+  %plen1 = getelementptr i64, i64* %plen, i32 1
+  store i64 %lena0b, i64* %plen1
+
+  %pa1a = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 0, i64 %I
+  %lena1a = call i64 @strlen(i8* %pa1a)
+  %plen2 = getelementptr i64, i64* %plen, i32 2
+  store i64 %lena1a, i64* %plen2
+
+  %pa1b = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 1, i64 %I
+  %lena1b = call i64 @strlen(i8* %pa1b)
+  %plen3 = getelementptr i64, i64* %plen, i32 3
+  store i64 %lena1b, i64* %plen3
+
+  ret void
+}

diff  --git a/llvm/test/Transforms/InstCombine/strlen-8.ll b/llvm/test/Transforms/InstCombine/strlen-8.ll
new file mode 100644
index 000000000000..fc218626e81b
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/strlen-8.ll
@@ -0,0 +1,78 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; Verify that strlen calls with variable offsets into elements of constant
+; arrays are folded.
+;
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+declare i64 @strlen(i8*)
+
+ at a5_4 = constant [5 x [4 x i8]] [[4 x i8] c"123\00", [4 x i8] c"12\00\00", [4 x i8] c"1\00\00\00", [4 x i8] zeroinitializer, [4 x i8] zeroinitializer]
+
+
+; Fold strlen(&a5_4[0][I]) to I <= 3 ? 3 - I : 0.
+
+define i64 @fold_a5_4_i0_pI(i64 %I) {
+; CHECK-LABEL: @fold_a5_4_i0_pI(
+; CHECK-NEXT:    [[PTR:%.*]] = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 0, i64 [[I:%.*]]
+; CHECK-NEXT:    [[LEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) [[PTR]])
+; CHECK-NEXT:    ret i64 [[LEN]]
+;
+  %ptr = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 0, i64 %I
+  %len = call i64 @strlen(i8* %ptr)
+  ret i64 %len
+}
+
+
+; Fold strlen(&a5_4[1][I]) to I <= 2 ? 2 - I : 0.
+
+define i64 @fold_a5_4_i1_pI(i64 %I) {
+; CHECK-LABEL: @fold_a5_4_i1_pI(
+; CHECK-NEXT:    [[PTR:%.*]] = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 1, i64 [[I:%.*]]
+; CHECK-NEXT:    [[LEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) [[PTR]])
+; CHECK-NEXT:    ret i64 [[LEN]]
+;
+  %ptr = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 1, i64 %I
+  %len = call i64 @strlen(i8* %ptr)
+  ret i64 %len
+}
+
+
+; Fold strlen(&a5_4[2][I]) to i <= 1 ? 1 - I : 0.
+
+define i64 @fold_a5_4_i2_pI(i64 %I) {
+; CHECK-LABEL: @fold_a5_4_i2_pI(
+; CHECK-NEXT:    [[LEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 2, i64 1))
+; CHECK-NEXT:    ret i64 [[LEN]]
+;
+  %ptr = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 2, i64 1
+  %len = call i64 @strlen(i8* %ptr)
+  ret i64 %len
+}
+
+
+; Fold strlen(&a5_4[3][I]) to 0.
+
+define i64 @fold_a5_4_i3_pI_to_0(i64 %I) {
+; CHECK-LABEL: @fold_a5_4_i3_pI_to_0(
+; CHECK-NEXT:    [[PTR:%.*]] = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 3, i64 [[I:%.*]]
+; CHECK-NEXT:    [[LEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) [[PTR]])
+; CHECK-NEXT:    ret i64 [[LEN]]
+;
+  %ptr = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 3, i64 %I
+  %len = call i64 @strlen(i8* %ptr)
+  ret i64 %len
+}
+
+
+; Fold strlen(&a5_4[4][I]) to 0.
+
+define i64 @fold_a5_4_i4_pI_to_0(i64 %I) {
+; CHECK-LABEL: @fold_a5_4_i4_pI_to_0(
+; CHECK-NEXT:    [[PTR:%.*]] = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 4, i64 [[I:%.*]]
+; CHECK-NEXT:    [[LEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) [[PTR]])
+; CHECK-NEXT:    ret i64 [[LEN]]
+;
+  %ptr = getelementptr [5 x [4 x i8]], [5 x [4 x i8]]* @a5_4, i64 0, i64 4, i64 %I
+  %len = call i64 @strlen(i8* %ptr)
+  ret i64 %len
+}

diff  --git a/llvm/test/Transforms/InstCombine/strncmp-4.ll b/llvm/test/Transforms/InstCombine/strncmp-4.ll
new file mode 100644
index 000000000000..fc02bb7e4890
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/strncmp-4.ll
@@ -0,0 +1,163 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; Verify that strncmp calls with members of constant structs are folded.
+;
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+; struct A { char a[3], b[4], c[4]; };
+%struct.A = type { [3 x i8], [4 x i8], [4 x i8] }
+
+ at a = constant %struct.A { [3 x i8] c"123", [4 x i8] c"1231", [4 x i8] c"2345" }
+
+declare i32 @strncmp(i8*, i8*, i64)
+
+define void @fold_strncmp_Aa_b(i32* %pcmp) {
+; CHECK-LABEL: @fold_strncmp_Aa_b(
+; CHECK-NEXT:    store i32 0, i32* [[PCMP:%.*]], align 4
+; CHECK-NEXT:    [[PCMP1:%.*]] = getelementptr i32, i32* [[PCMP]], i64 1
+; CHECK-NEXT:    store i32 0, i32* [[PCMP1]], align 4
+; CHECK-NEXT:    [[CMP2:%.*]] = call i32 @strncmp(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A:%.*]], %struct.A* @a, i64 0, i32 0, i64 0), i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A]], %struct.A* @a, i64 0, i32 1, i64 0), i64 2)
+; CHECK-NEXT:    [[PCMP2:%.*]] = getelementptr i32, i32* [[PCMP]], i64 2
+; CHECK-NEXT:    store i32 [[CMP2]], i32* [[PCMP2]], align 4
+; CHECK-NEXT:    [[CMP3:%.*]] = call i32 @strncmp(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A]], %struct.A* @a, i64 0, i32 0, i64 0), i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A]], %struct.A* @a, i64 0, i32 1, i64 0), i64 3)
+; CHECK-NEXT:    [[PCMP3:%.*]] = getelementptr i32, i32* [[PCMP]], i64 3
+; CHECK-NEXT:    store i32 [[CMP3]], i32* [[PCMP3]], align 4
+; CHECK-NEXT:    [[CMP4:%.*]] = call i32 @strncmp(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A]], %struct.A* @a, i64 0, i32 0, i64 0), i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A]], %struct.A* @a, i64 0, i32 1, i64 0), i64 4)
+; CHECK-NEXT:    [[PCMP4:%.*]] = getelementptr i32, i32* [[PCMP]], i64 4
+; CHECK-NEXT:    store i32 [[CMP4]], i32* [[PCMP4]], align 4
+; CHECK-NEXT:    [[CMP5:%.*]] = call i32 @strncmp(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A]], %struct.A* @a, i64 0, i32 0, i64 0), i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A]], %struct.A* @a, i64 0, i32 1, i64 0), i64 5)
+; CHECK-NEXT:    [[PCMP5:%.*]] = getelementptr i32, i32* [[PCMP]], i64 5
+; CHECK-NEXT:    store i32 [[CMP5]], i32* [[PCMP5]], align 4
+; CHECK-NEXT:    [[CMP6:%.*]] = call i32 @strncmp(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A]], %struct.A* @a, i64 0, i32 0, i64 0), i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A]], %struct.A* @a, i64 0, i32 1, i64 0), i64 6)
+; CHECK-NEXT:    [[PCMP6:%.*]] = getelementptr i32, i32* [[PCMP]], i64 6
+; CHECK-NEXT:    store i32 [[CMP6]], i32* [[PCMP6]], align 4
+; CHECK-NEXT:    [[CMP7:%.*]] = call i32 @strncmp(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A]], %struct.A* @a, i64 0, i32 0, i64 0), i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A]], %struct.A* @a, i64 0, i32 1, i64 0), i64 7)
+; CHECK-NEXT:    [[PCMP7:%.*]] = getelementptr i32, i32* [[PCMP]], i64 7
+; CHECK-NEXT:    store i32 [[CMP7]], i32* [[PCMP7]], align 4
+; CHECK-NEXT:    [[CMP8:%.*]] = call i32 @strncmp(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A]], %struct.A* @a, i64 0, i32 0, i64 0), i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A]], %struct.A* @a, i64 0, i32 1, i64 0), i64 8)
+; CHECK-NEXT:    [[PCMP8:%.*]] = getelementptr i32, i32* [[PCMP]], i64 8
+; CHECK-NEXT:    store i32 [[CMP8]], i32* [[PCMP8]], align 4
+; CHECK-NEXT:    [[CMP9:%.*]] = call i32 @strncmp(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A]], %struct.A* @a, i64 0, i32 0, i64 0), i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A]], %struct.A* @a, i64 0, i32 1, i64 0), i64 9)
+; CHECK-NEXT:    [[PCMP9:%.*]] = getelementptr i32, i32* [[PCMP]], i64 9
+; CHECK-NEXT:    store i32 [[CMP9]], i32* [[PCMP9]], align 4
+; CHECK-NEXT:    ret void
+;
+; p1 = a.a
+  %p1 = getelementptr %struct.A, %struct.A* @a, i32 0, i32 0, i32 0
+; p2 = a.b
+  %p2 = getelementptr %struct.A, %struct.A* @a, i32 0, i32 1, i32 0
+
+; Fold strncmp(a.a = "123", a.b = "1231", 0) to 0.
+  %cmp0 = call i32 @strncmp(i8* %p1, i8* %p2, i64 0)
+  %pcmp0 = getelementptr i32, i32* %pcmp, i64 0
+  store i32 %cmp0, i32* %pcmp0
+
+; Fold strncmp(a.a = "123", a.b = "1231", 1) to 0.
+  %cmp1 = call i32 @strncmp(i8* %p1, i8* %p2, i64 1)
+  %pcmp1 = getelementptr i32, i32* %pcmp, i64 1
+  store i32 %cmp1, i32* %pcmp1
+
+; Fold strncmp(a.a = "123", a.b = "1231", 2) to 0.
+  %cmp2 = call i32 @strncmp(i8* %p1, i8* %p2, i64 2)
+  %pcmp2 = getelementptr i32, i32* %pcmp, i64 2
+  store i32 %cmp2, i32* %pcmp2
+
+; Fold strncmp(a.a = "123", a.b = "1231", 3) to 0.
+  %cmp3 = call i32 @strncmp(i8* %p1, i8* %p2, i64 3)
+  %pcmp3 = getelementptr i32, i32* %pcmp, i64 3
+  store i32 %cmp3, i32* %pcmp3
+
+; Fold strncmp(a.a = "123", a.b = "1231", 4) to 0.
+; In this and the subsequent tests, reading past the end of a.a is
+; strictly undefined in C/C++ (because it forms a pointer to a distinct
+; subobject) but handling such cases as if they were well-defined is
+; simpler than trying to exclude them.
+
+  %cmp4 = call i32 @strncmp(i8* %p1, i8* %p2, i64 4)
+  %pcmp4 = getelementptr i32, i32* %pcmp, i64 4
+  store i32 %cmp4, i32* %pcmp4
+
+; Fold strncmp("123", "1231" "2", 5) to 0.
+  %cmp5 = call i32 @strncmp(i8* %p1, i8* %p2, i64 5)
+  %pcmp5 = getelementptr i32, i32* %pcmp, i64 5
+  store i32 %cmp5, i32* %pcmp5
+
+; Fold strncmp("123", "1231" "23", 6) to 0.
+  %cmp6 = call i32 @strncmp(i8* %p1, i8* %p2, i64 6)
+  %pcmp6 = getelementptr i32, i32* %pcmp, i64 6
+  store i32 %cmp6, i32* %pcmp6
+
+; Fold strncmp("123", "1231" "2345", 7) to 1.
+  %cmp7 = call i32 @strncmp(i8* %p1, i8* %p2, i64 7)
+  %pcmp7 = getelementptr i32, i32* %pcmp, i64 7
+  store i32 %cmp7, i32* %pcmp7
+
+; Fold strncmp("123", "1231" "2345", 8) to 1.
+  %cmp8 = call i32 @strncmp(i8* %p1, i8* %p2, i64 8)
+  %pcmp8 = getelementptr i32, i32* %pcmp, i64 8
+  store i32 %cmp8, i32* %pcmp8
+
+; Fold strncmp("123", "1231" "2345", 9) to 1.
+  %cmp9 = call i32 @strncmp(i8* %p1, i8* %p2, i64 9)
+  %pcmp9 = getelementptr i32, i32* %pcmp, i64 9
+  store i32 %cmp9, i32* %pcmp9
+
+  ret void
+}
+
+
+define void @fold_strncmp_Ab_a(i32* %pcmp) {
+; CHECK-LABEL: @fold_strncmp_Ab_a(
+; CHECK-NEXT:    store i32 0, i32* [[PCMP:%.*]], align 4
+; CHECK-NEXT:    [[PCMP1:%.*]] = getelementptr i32, i32* [[PCMP]], i64 1
+; CHECK-NEXT:    store i32 0, i32* [[PCMP1]], align 4
+; CHECK-NEXT:    [[CMP2:%.*]] = call i32 @strncmp(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A:%.*]], %struct.A* @a, i64 0, i32 1, i64 3), i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A]], %struct.A* @a, i64 0, i32 0, i64 0), i64 2)
+; CHECK-NEXT:    [[PCMP2:%.*]] = getelementptr i32, i32* [[PCMP]], i64 2
+; CHECK-NEXT:    store i32 [[CMP2]], i32* [[PCMP2]], align 4
+; CHECK-NEXT:    [[CMP3:%.*]] = call i32 @strncmp(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A]], %struct.A* @a, i64 0, i32 1, i64 3), i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A]], %struct.A* @a, i64 0, i32 0, i64 0), i64 3)
+; CHECK-NEXT:    [[PCMP3:%.*]] = getelementptr i32, i32* [[PCMP]], i64 3
+; CHECK-NEXT:    store i32 [[CMP3]], i32* [[PCMP3]], align 4
+; CHECK-NEXT:    [[CMP4:%.*]] = call i32 @strncmp(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A]], %struct.A* @a, i64 0, i32 1, i64 3), i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A]], %struct.A* @a, i64 0, i32 0, i64 0), i64 4)
+; CHECK-NEXT:    [[PCMP4:%.*]] = getelementptr i32, i32* [[PCMP]], i64 4
+; CHECK-NEXT:    store i32 [[CMP4]], i32* [[PCMP4]], align 4
+; CHECK-NEXT:    [[CMP5:%.*]] = call i32 @strncmp(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A]], %struct.A* @a, i64 0, i32 1, i64 3), i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A]], %struct.A* @a, i64 0, i32 0, i64 0), i64 5)
+; CHECK-NEXT:    [[PCMP5:%.*]] = getelementptr i32, i32* [[PCMP]], i64 5
+; CHECK-NEXT:    store i32 [[CMP5]], i32* [[PCMP5]], align 4
+; CHECK-NEXT:    ret void
+;
+; p1 = &a.b[3]
+  %p1 = getelementptr %struct.A, %struct.A* @a, i32 0, i32 1, i32 3
+; p2 = &a.a
+  %p2 = getelementptr %struct.A, %struct.A* @a, i32 0, i32 0, i32 0
+
+; Fold strncmp(a.a = "123", &a.b[3] = "1" "2345", 0) to 0.
+  %cmp0 = call i32 @strncmp(i8* %p1, i8* %p2, i64 0)
+  %pcmp0 = getelementptr i32, i32* %pcmp, i64 0
+  store i32 %cmp0, i32* %pcmp0
+
+; Fold strncmp(a.a = "123", &a.b[3] = "1" "2345", 1) to 0.
+  %cmp1 = call i32 @strncmp(i8* %p1, i8* %p2, i64 1)
+  %pcmp1 = getelementptr i32, i32* %pcmp, i64 1
+  store i32 %cmp1, i32* %pcmp1
+
+; Fold strncmp(a.a = "123", &a.b[3] = "1" "2345", 2) to 0.
+  %cmp2 = call i32 @strncmp(i8* %p1, i8* %p2, i64 2)
+  %pcmp2 = getelementptr i32, i32* %pcmp, i64 2
+  store i32 %cmp2, i32* %pcmp2
+
+; Fold strncmp(a.a = "123", &a.b[3] = "1" "2345", 3) to 0.
+  %cmp3 = call i32 @strncmp(i8* %p1, i8* %p2, i64 3)
+  %pcmp3 = getelementptr i32, i32* %pcmp, i64 3
+  store i32 %cmp3, i32* %pcmp3
+
+; Fold strncmp(a.a = "123", &a.b[3] = "1" "2345", 4) to 1.
+  %cmp4 = call i32 @strncmp(i8* %p1, i8* %p2, i64 4)
+  %pcmp4 = getelementptr i32, i32* %pcmp, i64 4
+  store i32 %cmp4, i32* %pcmp4
+
+; Fold strncmp(a.a = "123", &a.b[3] = "1" "2345", 5) to 1.
+  %cmp5 = call i32 @strncmp(i8* %p1, i8* %p2, i64 5)
+  %pcmp5 = getelementptr i32, i32* %pcmp, i64 5
+  store i32 %cmp5, i32* %pcmp5
+
+  ret void
+}


        


More information about the llvm-commits mailing list