[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.
This commit is contained in:
Martin Sebor 2022-05-06 10:34:13 -06:00
parent 2ca78d2bdf
commit cc2ce81bd8
13 changed files with 2667 additions and 0 deletions

View File

@ -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' }
@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
}

View File

@ -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' }
@ia6a = constant [4 x i16] [i16 24930, i16 25444, i16 25958, i16 26472]
; Same as the BE representation above except ending in "gg".
@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
}

View File

@ -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)
@ia16a = constant [4 x i16] [i16 24930, i16 25444, i16 25958, i16 26472]
@ia16b = constant [5 x i16] [i16 24930, i16 25444, i16 25958, i16 26472, i16 26992]
@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
; differ. 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
}

View File

@ -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' }
@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
}

View File

@ -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] }
@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" }]
@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
}

View File

@ -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] }
@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
}

View File

@ -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*)
@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
}

View File

@ -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*)
@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
}

View File

@ -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*)
@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
}

View File

@ -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] }
@a_s3 = constant %struct.A_a4 { [4 x i8 ] c"123\00" }
@a_s3_s4 = constant %struct.A_a4_a5 { [4 x i8 ] c"123\00", [5 x i8] c"1234\00" }
@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.
@ax_s3 = constant { i8, [4 x i8] } { i8 3, [4 x i8] c"123\00" }
@ax_s5 = constant { i16, [6 x i8] } { i16 5, [6 x i8] c"12345\00" }
@ax_s7 = constant { i32, i32, [8 x i8] } { i32 7, i32 0, [8 x i8] c"1234567\00" }
@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
}

View File

@ -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] }
@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
}

View File

@ -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*)
@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
}

View File

@ -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] }
@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
}