192 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py2; Verify that strlen calls with conditional expressions involving constant3; string arguments with nonconstant offsets are folded as expected.4;5; RUN: opt < %s -passes=instcombine -S | FileCheck %s6 7declare i64 @strlen(ptr)8 9@sx = external global [0 x i8]10@s3 = constant [4 x i8] c"123\00"11@s5 = constant [6 x i8] c"12345\00"12@s7 = constant [8 x i8] c"1234567\00"13 14@s5_3 = constant [10 x i8] c"12345\00123\00"15 16 17; Fold strlen (x ? s3 + i : s5) to x ? 3 - i : 5.18 19define i64 @fold_strlen_s3_pi_s5(i1 %X, i64 %I) {20; CHECK-LABEL: @fold_strlen_s3_pi_s5(21; CHECK-NEXT: [[PS3_PI:%.*]] = getelementptr inbounds i8, ptr @s3, i64 [[I:%.*]]22; CHECK-NEXT: [[SEL:%.*]] = select i1 [[X:%.*]], ptr [[PS3_PI]], ptr @s523; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @strlen(ptr noundef nonnull dereferenceable(1) [[SEL]])24; CHECK-NEXT: ret i64 [[LEN]]25;26 27 %ps3_pi = getelementptr inbounds [4 x i8], ptr @s3, i64 0, i64 %I28 %sel = select i1 %X, ptr %ps3_pi, ptr @s529 %len = tail call i64 @strlen(ptr %sel)30 ret i64 %len31}32 33 34; More complex expressions like the one below are not handled yet.35; Fold: strlen (x ? s3 + i + 1 : s5) to x ? 2 - i : 5.36 37define i64 @fold_strlen_s3_pi_p1_s5(i1 %0, i64 %1) {38; XFAIL-CHECK-LABEL: @fold_strlen_s3_pi_p1_s5(39; XFAIL-CHECK-NEXT: [[DIF_I:%.*]] = sub i64 2, %140; XFAIL-CHECK-NEXT: [[SEL:%.*]] = select i1 %0, i64 [[DIF_I]], i64 541; XFAIL-CHECK-NEXT: ret i64 [[SEL]]42; CHECK-LABEL: @fold_strlen_s3_pi_p1_s5(43; CHECK-NEXT: [[PS3_PI:%.*]] = getelementptr inbounds i8, ptr @s3, i64 [[TMP1:%.*]]44; CHECK-NEXT: [[PS3_PI_P1:%.*]] = getelementptr i8, ptr [[PS3_PI]], i64 145; CHECK-NEXT: [[SEL:%.*]] = select i1 [[TMP0:%.*]], ptr [[PS3_PI_P1]], ptr @s546; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @strlen(ptr noundef nonnull dereferenceable(1) [[SEL]])47; CHECK-NEXT: ret i64 [[LEN]]48;49 50 %ps3_pi = getelementptr inbounds [4 x i8], ptr @s3, i64 0, i64 %151 %ps3_pi_p1 = getelementptr i8, ptr %ps3_pi, i64 152 %sel = select i1 %0, ptr %ps3_pi_p1, ptr @s553 %len = tail call i64 @strlen(ptr %sel)54 ret i64 %len55}56 57 58; Avoid folding calls with conditional expressions involving constant59; string arguments with embedded nuls such as:60; strlen (x ? s5_3 + i : s5).61 62define i64 @call_strlen_s5_3_pi_s5(i1 %0, i64 %1) {63; CHECK-LABEL: @call_strlen_s5_3_pi_s5(64; CHECK-NEXT: [[PS5_3_PI:%.*]] = getelementptr inbounds i8, ptr @s5_3, i64 [[TMP1:%.*]]65; CHECK-NEXT: [[SEL:%.*]] = select i1 [[TMP0:%.*]], ptr [[PS5_3_PI]], ptr @s566; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @strlen(ptr noundef nonnull dereferenceable(1) [[SEL]])67; CHECK-NEXT: ret i64 [[LEN]]68;69 70 %ps5_3_pi = getelementptr inbounds [10 x i8], ptr @s5_3, i64 0, i64 %171 %sel = select i1 %0, ptr %ps5_3_pi, ptr @s572 %len = tail call i64 @strlen(ptr %sel)73 ret i64 %len74}75 76 77; But do fold strlen (x ? s5_3 : s5 + j) to x ? 5 : 5 - j.78 79define i64 @call_strlen_s5_3_s5_pj(i1 %X, i64 %J) {80; CHECK-LABEL: @call_strlen_s5_3_s5_pj(81; CHECK-NEXT: [[PS5:%.*]] = getelementptr inbounds i8, ptr @s5, i64 [[J:%.*]]82; CHECK-NEXT: [[SEL:%.*]] = select i1 [[X:%.*]], ptr @s5_3, ptr [[PS5]]83; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @strlen(ptr noundef nonnull dereferenceable(1) [[SEL]])84; CHECK-NEXT: ret i64 [[LEN]]85;86 87 %ps5 = getelementptr inbounds [6 x i8], ptr @s5, i64 0, i64 %J88 %sel = select i1 %X, ptr @s5_3, ptr %ps589 %len = tail call i64 @strlen(ptr %sel)90 ret i64 %len91}92 93 94; Fold strlen (x ? s3: s5 + j) to x ? 3 : 5 - j.95 96define i64 @fold_strlen_s3_s5_pj(i1 %X, i64 %J) {97; CHECK-LABEL: @fold_strlen_s3_s5_pj(98; CHECK-NEXT: [[PS5_PJ:%.*]] = getelementptr inbounds i8, ptr @s5, i64 [[J:%.*]]99; CHECK-NEXT: [[SEL:%.*]] = select i1 [[X:%.*]], ptr @s3, ptr [[PS5_PJ]]100; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @strlen(ptr noundef nonnull dereferenceable(1) [[SEL]])101; CHECK-NEXT: ret i64 [[LEN]]102;103 104 %ps5_pj = getelementptr inbounds [6 x i8], ptr @s5, i64 0, i64 %J105 %sel = select i1 %X, ptr @s3, ptr %ps5_pj106 %len = tail call i64 @strlen(ptr %sel)107 ret i64 %len108}109 110 111; Same as above, avoid folding calls with conditional expressions involving112; constant string arguments with embedded nuls such as:113; strlen (x ? s3 : s5_3 + j).114 115define i64 @call_strlen_s3_s5_3_pj(i1 %0, i64 %1) {116; CHECK-LABEL: @call_strlen_s3_s5_3_pj(117; CHECK-NEXT: [[PS5_3_PJ:%.*]] = getelementptr inbounds i8, ptr @s5_3, i64 [[TMP1:%.*]]118; CHECK-NEXT: [[SEL:%.*]] = select i1 [[TMP0:%.*]], ptr @s3, ptr [[PS5_3_PJ]]119; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @strlen(ptr noundef nonnull dereferenceable(1) [[SEL]])120; CHECK-NEXT: ret i64 [[LEN]]121;122 123 %ps5_3_pj = getelementptr inbounds [10 x i8], ptr @s5_3, i64 0, i64 %1124 %sel = select i1 %0, ptr @s3, ptr %ps5_3_pj125 %len = tail call i64 @strlen(ptr %sel)126 ret i64 %len127}128 129 130; Fold strlen (x ? s3 + i: s5 + j) to x ? 3 - i : 5 - j.131 132define i64 @fold_strlen_s3_pi_s5_pj(i1 %X, i64 %I, i64 %J) {133; CHECK-LABEL: @fold_strlen_s3_pi_s5_pj(134; CHECK-NEXT: [[PS3_PI:%.*]] = getelementptr inbounds i8, ptr @s3, i64 [[I:%.*]]135; CHECK-NEXT: [[PS5_PJ:%.*]] = getelementptr inbounds i8, ptr @s5, i64 [[J:%.*]]136; CHECK-NEXT: [[SEL:%.*]] = select i1 [[X:%.*]], ptr [[PS3_PI]], ptr [[PS5_PJ]]137; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @strlen(ptr noundef nonnull dereferenceable(1) [[SEL]])138; CHECK-NEXT: ret i64 [[LEN]]139;140; Use CHECK-DAG since the two instructions below might be emitted in reverse141; order.142 143 %ps3_pi = getelementptr inbounds [4 x i8], ptr @s3, i64 0, i64 %I144 %ps5_pj = getelementptr inbounds [6 x i8], ptr @s5, i64 0, i64 %J145 %sel = select i1 %X, ptr %ps3_pi, ptr %ps5_pj146 %len = tail call i64 @strlen(ptr %sel)147 ret i64 %len148}149 150 151; Fold strlen(E) with E being two conditional expressions:152; strlen (x == 3 ? s3 : x == 5 ? s5 : s7) to x == 3 ? 3 : x == 5 ? 5 : 7.153 154define i64 @fold_strlen_s3_s5_s7(i32 %X) {155; CHECK-LABEL: @fold_strlen_s3_s5_s7(156; CHECK-NEXT: [[X_EQ_3:%.*]] = icmp eq i32 [[X:%.*]], 3157; CHECK-NEXT: [[X_EQ_5:%.*]] = icmp eq i32 [[X]], 5158; CHECK-NEXT: [[SEL_X_EQ_5:%.*]] = select i1 [[X_EQ_5]], ptr @s5, ptr @s7159; CHECK-NEXT: [[SEL:%.*]] = select i1 [[X_EQ_3]], ptr @s3, ptr [[SEL_X_EQ_5]]160; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @strlen(ptr noundef nonnull dereferenceable(1) [[SEL]])161; CHECK-NEXT: ret i64 [[LEN]]162;163 164 %x_eq_3 = icmp eq i32 %X, 3165 %x_eq_5 = icmp eq i32 %X, 5166 %sel_x_eq_5 = select i1 %x_eq_5, ptr @s5, ptr @s7167 %sel = select i1 %x_eq_3, ptr @s3, ptr %sel_x_eq_5168 %len = tail call i64 @strlen(ptr %sel)169 ret i64 %len170}171 172 173; Do not fold strlen (x == 3 ? sx : x == 5 ? s5 : s7).174 175define i64 @call_strlen_sx_s5_s7(i32 %X) {176; CHECK-LABEL: @call_strlen_sx_s5_s7(177; CHECK-NEXT: [[X_EQ_3:%.*]] = icmp eq i32 [[X:%.*]], 3178; CHECK-NEXT: [[X_EQ_5:%.*]] = icmp eq i32 [[X]], 5179; CHECK-NEXT: [[SEL_X_EQ_5:%.*]] = select i1 [[X_EQ_5]], ptr @s5, ptr @s7180; CHECK-NEXT: [[SEL:%.*]] = select i1 [[X_EQ_3]], ptr @sx, ptr [[SEL_X_EQ_5]]181; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @strlen(ptr noundef nonnull dereferenceable(1) [[SEL]])182; CHECK-NEXT: ret i64 [[LEN]]183;184 185 %x_eq_3 = icmp eq i32 %X, 3186 %x_eq_5 = icmp eq i32 %X, 5187 %sel_x_eq_5 = select i1 %x_eq_5, ptr @s5, ptr @s7188 %sel = select i1 %x_eq_3, ptr @sx, ptr %sel_x_eq_5189 %len = tail call i64 @strlen(ptr %sel)190 ret i64 %len191}192