Skip to content

Commit

Permalink
[InstCombine] Add additional tests for strlen/strnlen (NFC)
Browse files Browse the repository at this point in the history
Taken from D122686.
  • Loading branch information
msebor authored and nikic committed Apr 1, 2022
1 parent cd55e51 commit 884d7c6
Show file tree
Hide file tree
Showing 8 changed files with 1,200 additions and 0 deletions.
195 changes: 195 additions & 0 deletions llvm/test/Transforms/InstCombine/strlen-4.ll
@@ -0,0 +1,195 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; Verify that strlen calls with conditional expressions involving constant
; string arguments with nonconstant offsets are folded as expected.
;
; RUN: opt < %s -passes=instcombine -S | FileCheck %s

declare i64 @strlen(i8* nocapture)

@sx = external global [0 x i8]
@s3 = constant [4 x i8] c"123\00", align 1
@s5 = constant [6 x i8] c"12345\00", align 1
@s7 = constant [8 x i8] c"1234567\00", align 1

@s5_3 = constant [10 x i8] c"12345\00123\00", align 1


; Fold strlen (x ? s3 + i: s5) to x ? 3 - i : 5.

define i64 @fold_strlen_s3_pi_s5(i1 %0, i64 %1) {
; CHECK-LABEL: @fold_strlen_s3_pi_s5(
; CHECK-NEXT: [[PS3_PI:%.*]] = getelementptr inbounds [4 x i8], [4 x i8]* @s3, i64 0, i64 [[TMP1:%.*]]
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[TMP0:%.*]], i8* [[PS3_PI]], i8* getelementptr inbounds ([6 x i8], [6 x i8]* @s5, i64 0, i64 0)
; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @strlen(i8* noundef nonnull dereferenceable(1) [[SEL]])
; CHECK-NEXT: ret i64 [[LEN]]
;

%ps3_pi = getelementptr inbounds [4 x i8], [4 x i8]* @s3, i64 0, i64 %1
%ps5 = getelementptr [6 x i8], [6 x i8]* @s5, i64 0, i64 0
%sel = select i1 %0, i8* %ps3_pi, i8* %ps5
%len = tail call i64 @strlen(i8* %sel)
ret i64 %len
}


; More complex expressions like the one below are not handled yet.
; Fold: strlen (x ? s3 + i + 1 : s5 + j + 2) to x ? 2 - i : 3 - j.

define i64 @fold_strlen_s3_pi_p1_s5(i1 %0, i64 %1) {
; XFAIL-CHECK-LABEL: @fold_strlen_s3_pi_p1_s5(
; XFAIL-CHECK-NEXT: [[DIF_I:%.*]] = sub i64 2, %1
; XFAIL-CHECK-NEXT: [[SEL:%.*]] = select i1 %0, i64 [[DIF_I]], i64 5
; XFAIL-CHECK-NEXT: ret i64 [[SEL]]
; CHECK-LABEL: @fold_strlen_s3_pi_p1_s5(
; CHECK-NEXT: [[PS3_PI:%.*]] = getelementptr inbounds [4 x i8], [4 x i8]* @s3, i64 0, i64 [[TMP1:%.*]]
; CHECK-NEXT: [[PS3_PI_P1:%.*]] = getelementptr i8, i8* [[PS3_PI]], i64 1
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[TMP0:%.*]], i8* [[PS3_PI_P1]], i8* getelementptr inbounds ([6 x i8], [6 x i8]* @s5, i64 0, i64 0)
; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @strlen(i8* noundef nonnull dereferenceable(1) [[SEL]])
; CHECK-NEXT: ret i64 [[LEN]]
;

%ps3_pi = getelementptr inbounds [4 x i8], [4 x i8]* @s3, i64 0, i64 %1
%ps3_pi_p1 = getelementptr i8, i8* %ps3_pi, i64 1
%ps5 = getelementptr [6 x i8], [6 x i8]* @s5, i64 0, i64 0
%sel = select i1 %0, i8* %ps3_pi_p1, i8* %ps5
%len = tail call i64 @strlen(i8* %sel)
ret i64 %len
}


; Avoid folding calls with conditional expressions involving constant
; string arguments with embedded nuls such as:
; strlen (x ? s5_3 + i : s5).

define i64 @call_strlen_s5_3_pi_s5(i1 %0, i64 %1) {
; CHECK-LABEL: @call_strlen_s5_3_pi_s5(
; CHECK-NEXT: [[PS5_3_PI:%.*]] = getelementptr inbounds [10 x i8], [10 x i8]* @s5_3, i64 0, i64 [[TMP1:%.*]]
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[TMP0:%.*]], i8* [[PS5_3_PI]], i8* getelementptr inbounds ([6 x i8], [6 x i8]* @s5, i64 0, i64 0)
; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @strlen(i8* noundef nonnull dereferenceable(1) [[SEL]])
; CHECK-NEXT: ret i64 [[LEN]]
;

%ps5_3_pi = getelementptr inbounds [10 x i8], [10 x i8]* @s5_3, i64 0, i64 %1
%ps5 = getelementptr [6 x i8], [6 x i8]* @s5, i64 0, i64 0
%sel = select i1 %0, i8* %ps5_3_pi, i8* %ps5
%len = tail call i64 @strlen(i8* %sel)
ret i64 %len
}


; But do fold strlen (x ? s5_3 : s5 + j) to x ? 5 : 5 - j.

define i64 @call_strlen_s5_3_s5_pj(i1 %0, i64 %1) {
; CHECK-LABEL: @call_strlen_s5_3_s5_pj(
; CHECK-NEXT: [[PS5:%.*]] = getelementptr inbounds [6 x i8], [6 x i8]* @s5, i64 0, i64 [[TMP1:%.*]]
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[TMP0:%.*]], i8* getelementptr inbounds ([10 x i8], [10 x i8]* @s5_3, i64 0, i64 0), i8* [[PS5]]
; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @strlen(i8* noundef nonnull dereferenceable(1) [[SEL]])
; CHECK-NEXT: ret i64 [[LEN]]
;

%ps5_3_pi = getelementptr [10 x i8], [10 x i8]* @s5_3, i64 0, i64 0
%ps5 = getelementptr inbounds [6 x i8], [6 x i8]* @s5, i64 0, i64 %1
%sel = select i1 %0, i8* %ps5_3_pi, i8* %ps5
%len = tail call i64 @strlen(i8* %sel)
ret i64 %len
}


; Fold strlen (x ? s3: s5 + j) to x ? 3 : 5 - j.

define i64 @fold_strlen_s3_s5_pj(i1 %0, i64 %1) {
; CHECK-LABEL: @fold_strlen_s3_s5_pj(
; CHECK-NEXT: [[PS5_PJ:%.*]] = getelementptr inbounds [6 x i8], [6 x i8]* @s5, i64 0, i64 [[TMP1:%.*]]
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[TMP0:%.*]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @s3, i64 0, i64 0), i8* [[PS5_PJ]]
; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @strlen(i8* noundef nonnull dereferenceable(1) [[SEL]])
; CHECK-NEXT: ret i64 [[LEN]]
;

%ps3 = getelementptr [4 x i8], [4 x i8]* @s3, i64 0, i64 0
%ps5_pj = getelementptr inbounds [6 x i8], [6 x i8]* @s5, i64 0, i64 %1
%sel = select i1 %0, i8* %ps3, i8* %ps5_pj
%len = tail call i64 @strlen(i8* %sel)
ret i64 %len
}


; Same as above, avoid folding calls with conditional expressions involving
; constant string arguments with embedded nuls such as:
; strlen (x ? s3 : s5_3 + j).

define i64 @call_strlen_s3_s5_3_pj(i1 %0, i64 %1) {
; CHECK-LABEL: @call_strlen_s3_s5_3_pj(
; CHECK-NEXT: [[PS5_3_PJ:%.*]] = getelementptr inbounds [10 x i8], [10 x i8]* @s5_3, i64 0, i64 [[TMP1:%.*]]
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[TMP0:%.*]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @s3, i64 0, i64 0), i8* [[PS5_3_PJ]]
; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @strlen(i8* noundef nonnull dereferenceable(1) [[SEL]])
; CHECK-NEXT: ret i64 [[LEN]]
;

%ps3 = getelementptr [4 x i8], [4 x i8]* @s3, i64 0, i64 0
%ps5_3_pj = getelementptr inbounds [10 x i8], [10 x i8]* @s5_3, i64 0, i64 %1
%sel = select i1 %0, i8* %ps3, i8* %ps5_3_pj
%len = tail call i64 @strlen(i8* %sel)
ret i64 %len
}


; Fold strlen (x ? s3 + i: s5 + j) to x ? 3 - i : 5 - j.

define i64 @fold_strlen_s3_pi_s5_pj(i1 %0, i64 %1, i64 %2) {
; CHECK-LABEL: @fold_strlen_s3_pi_s5_pj(
; CHECK-NEXT: [[PS3_PI:%.*]] = getelementptr inbounds [4 x i8], [4 x i8]* @s3, i64 0, i64 [[TMP1:%.*]]
; CHECK-NEXT: [[PS5_PJ:%.*]] = getelementptr inbounds [6 x i8], [6 x i8]* @s5, i64 0, i64 [[TMP2:%.*]]
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[TMP0:%.*]], i8* [[PS3_PI]], i8* [[PS5_PJ]]
; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @strlen(i8* noundef nonnull [[SEL]])
; CHECK-NEXT: ret i64 [[LEN]]
;

%ps3_pi = getelementptr inbounds [4 x i8], [4 x i8]* @s3, i64 0, i64 %1
%ps5_pj = getelementptr inbounds [6 x i8], [6 x i8]* @s5, i64 0, i64 %2
%sel = select i1 %0, i8* %ps3_pi, i8* %ps5_pj
%len = tail call i64 @strlen(i8* %sel)
ret i64 %len
}


; Fold strlen(E) with E being two conditional expressions:
; strlen (x == 3 ? s3 : x == 5 ? s5 : s7) to x == 3 ? 3 : x == 5 ? 5 : 7.

define i64 @fold_strlen_s3_s5_s7(i32 %0) {
; CHECK-LABEL: @fold_strlen_s3_s5_s7(
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP0:%.*]], 3
; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP0]], 5
; CHECK-NEXT: [[TMP4:%.*]] = select i1 [[TMP3]], i8* getelementptr inbounds ([6 x i8], [6 x i8]* @s5, i64 0, i64 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* @s7, i64 0, i64 0)
; CHECK-NEXT: [[TMP5:%.*]] = select i1 [[TMP2]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @s3, i64 0, i64 0), i8* [[TMP4]]
; CHECK-NEXT: [[TMP6:%.*]] = tail call i64 @strlen(i8* noundef nonnull dereferenceable(1) [[TMP5]])
; CHECK-NEXT: ret i64 [[TMP6]]
;

%2 = icmp eq i32 %0, 3
%3 = icmp eq i32 %0, 5
%4 = select i1 %3, i8* getelementptr ([6 x i8], [6 x i8]* @s5, i64 0, i64 0), i8* getelementptr ([8 x i8], [8 x i8]* @s7, i64 0, i64 0)
%5 = select i1 %2, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @s3, i64 0, i64 0), i8* %4
%6 = tail call i64 @strlen(i8* %5)
ret i64 %6
}


; Do not fold strlen (x == 3 ? sx : x == 5 ? s5 : s7).

define i64 @call_strlen_sx_s5_s7(i32 %0) {
; CHECK-LABEL: @call_strlen_sx_s5_s7(
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP0:%.*]], 3
; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP0]], 5
; CHECK-NEXT: [[TMP4:%.*]] = select i1 [[TMP3]], i8* getelementptr inbounds ([6 x i8], [6 x i8]* @s5, i64 0, i64 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* @s7, i64 0, i64 0)
; CHECK-NEXT: [[TMP5:%.*]] = select i1 [[TMP2]], i8* getelementptr inbounds ([0 x i8], [0 x i8]* @sx, i64 0, i64 0), i8* [[TMP4]]
; CHECK-NEXT: [[TMP6:%.*]] = tail call i64 @strlen(i8* noundef nonnull dereferenceable(1) [[TMP5]])
; CHECK-NEXT: ret i64 [[TMP6]]
;

%2 = icmp eq i32 %0, 3
%3 = icmp eq i32 %0, 5
%4 = select i1 %3, i8* getelementptr ([6 x i8], [6 x i8]* @s5, i64 0, i64 0), i8* getelementptr ([8 x i8], [8 x i8]* @s7, i64 0, i64 0)
%5 = select i1 %2, i8* getelementptr inbounds ([0 x i8], [0 x i8]* @sx, i64 0, i64 0), i8* %4
%6 = tail call i64 @strlen(i8* %5)
ret i64 %6
}
101 changes: 101 additions & 0 deletions llvm/test/Transforms/InstCombine/strnlen-1.ll
@@ -0,0 +1,101 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; Verify that strnlen calls with constant string arguments and offsets
; and constant bounds are folded correctly.
;
; RUN: opt < %s -passes=instcombine -S | FileCheck %s

declare i64 @strnlen(i8*, i64)

@s5 = constant [6 x i8] c"12345\00"
@s5_3 = constant [9 x i8] c"12345\00xyz"


; Fold strnlen(s5, 0) to 0.

define i64 @fold_strnlen_s5_0() {
; CHECK-LABEL: @fold_strnlen_s5_0(
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @s5, i64 0, i64 0), i64 0)
; CHECK-NEXT: ret i64 [[LEN]]
;
%ptr = getelementptr [6 x i8], [6 x i8]* @s5, i32 0, i32 0
%len = call i64 @strnlen(i8* %ptr, i64 0)
ret i64 %len
}


; Fold strnlen(s5, 4) to 4.

define i64 @fold_strnlen_s5_4() {
; CHECK-LABEL: @fold_strnlen_s5_4(
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @s5, i64 0, i64 0), i64 4)
; CHECK-NEXT: ret i64 [[LEN]]
;
%ptr = getelementptr [6 x i8], [6 x i8]* @s5, i32 0, i32 0
%len = call i64 @strnlen(i8* %ptr, i64 4)
ret i64 %len
}


; Fold strnlen(s5, 5) to 5.

define i64 @fold_strnlen_s5_5() {
; CHECK-LABEL: @fold_strnlen_s5_5(
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @s5, i64 0, i64 0), i64 5)
; CHECK-NEXT: ret i64 [[LEN]]
;
%ptr = getelementptr [6 x i8], [6 x i8]* @s5, i32 0, i32 0
%len = call i64 @strnlen(i8* %ptr, i64 5)
ret i64 %len
}


; Fold strnlen(s5, (size_t)-1) to 5.

define i64 @fold_strnlen_s5_m1() {
; CHECK-LABEL: @fold_strnlen_s5_m1(
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @s5, i64 0, i64 0), i64 -1)
; CHECK-NEXT: ret i64 [[LEN]]
;
%ptr = getelementptr [6 x i8], [6 x i8]* @s5, i32 0, i32 0
%len = call i64 @strnlen(i8* %ptr, i64 -1)
ret i64 %len
}


; Fold strnlen(s5_3 + 4, 5) to 1.

define i64 @fold_strnlen_s5_3_p4_5() {
; CHECK-LABEL: @fold_strnlen_s5_3_p4_5(
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @s5_3, i64 0, i64 4), i64 5)
; CHECK-NEXT: ret i64 [[LEN]]
;
%ptr = getelementptr [9 x i8], [9 x i8]* @s5_3, i32 0, i32 4
%len = call i64 @strnlen(i8* %ptr, i64 5)
ret i64 %len
}


; Fold strnlen(s5_3 + 5, 5) to 1.

define i64 @fold_strnlen_s5_3_p5_5() {
; CHECK-LABEL: @fold_strnlen_s5_3_p5_5(
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @s5_3, i64 0, i64 5), i64 5)
; CHECK-NEXT: ret i64 [[LEN]]
;
%ptr = getelementptr [9 x i8], [9 x i8]* @s5_3, i32 0, i32 5
%len = call i64 @strnlen(i8* %ptr, i64 5)
ret i64 %len
}


; Fold strnlen(s5_3 + 6, 5) to 3.

define i64 @fold_strnlen_s5_3_p6_5() {
; CHECK-LABEL: @fold_strnlen_s5_3_p6_5(
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @s5_3, i64 0, i64 6), i64 5)
; CHECK-NEXT: ret i64 [[LEN]]
;
%ptr = getelementptr [9 x i8], [9 x i8]* @s5_3, i32 0, i32 6
%len = call i64 @strnlen(i8* %ptr, i64 5)
ret i64 %len
}

0 comments on commit 884d7c6

Please sign in to comment.