1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; Verify that strlen calls with conditional expressions involving constant 3; string arguments with nonconstant offsets are folded as expected. 4; 5; RUN: opt < %s -passes=instcombine -S | FileCheck %s 6 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 [4 x i8], ptr @s3, i64 0, i64 [[I:%.*]] 22; CHECK-NEXT: [[SEL:%.*]] = select i1 [[X:%.*]], ptr [[PS3_PI]], ptr @s5 23; 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 %I 28 %sel = select i1 %X, ptr %ps3_pi, ptr @s5 29 %len = tail call i64 @strlen(ptr %sel) 30 ret i64 %len 31} 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, %1 40; XFAIL-CHECK-NEXT: [[SEL:%.*]] = select i1 %0, i64 [[DIF_I]], i64 5 41; XFAIL-CHECK-NEXT: ret i64 [[SEL]] 42; CHECK-LABEL: @fold_strlen_s3_pi_p1_s5( 43; CHECK-NEXT: [[PS3_PI:%.*]] = getelementptr inbounds [4 x i8], ptr @s3, i64 0, i64 [[TMP1:%.*]] 44; CHECK-NEXT: [[PS3_PI_P1:%.*]] = getelementptr i8, ptr [[PS3_PI]], i64 1 45; CHECK-NEXT: [[SEL:%.*]] = select i1 [[TMP0:%.*]], ptr [[PS3_PI_P1]], ptr @s5 46; 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 %1 51 %ps3_pi_p1 = getelementptr i8, ptr %ps3_pi, i64 1 52 %sel = select i1 %0, ptr %ps3_pi_p1, ptr @s5 53 %len = tail call i64 @strlen(ptr %sel) 54 ret i64 %len 55} 56 57 58; Avoid folding calls with conditional expressions involving constant 59; 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 [10 x i8], ptr @s5_3, i64 0, i64 [[TMP1:%.*]] 65; CHECK-NEXT: [[SEL:%.*]] = select i1 [[TMP0:%.*]], ptr [[PS5_3_PI]], ptr @s5 66; 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 %1 71 %sel = select i1 %0, ptr %ps5_3_pi, ptr @s5 72 %len = tail call i64 @strlen(ptr %sel) 73 ret i64 %len 74} 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 [6 x i8], ptr @s5, i64 0, 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 %J 88 %sel = select i1 %X, ptr @s5_3, ptr %ps5 89 %len = tail call i64 @strlen(ptr %sel) 90 ret i64 %len 91} 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 [6 x i8], ptr @s5, i64 0, 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 %J 105 %sel = select i1 %X, ptr @s3, ptr %ps5_pj 106 %len = tail call i64 @strlen(ptr %sel) 107 ret i64 %len 108} 109 110 111; Same as above, avoid folding calls with conditional expressions involving 112; 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 [10 x i8], ptr @s5_3, i64 0, 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 %1 124 %sel = select i1 %0, ptr @s3, ptr %ps5_3_pj 125 %len = tail call i64 @strlen(ptr %sel) 126 ret i64 %len 127} 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 [4 x i8], ptr @s3, i64 0, i64 [[I:%.*]] 135; CHECK-NEXT: [[PS5_PJ:%.*]] = getelementptr inbounds [6 x i8], ptr @s5, i64 0, 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 reverse 141; order. 142 143 %ps3_pi = getelementptr inbounds [4 x i8], ptr @s3, i64 0, i64 %I 144 %ps5_pj = getelementptr inbounds [6 x i8], ptr @s5, i64 0, i64 %J 145 %sel = select i1 %X, ptr %ps3_pi, ptr %ps5_pj 146 %len = tail call i64 @strlen(ptr %sel) 147 ret i64 %len 148} 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:%.*]], 3 157; CHECK-NEXT: [[X_EQ_5:%.*]] = icmp eq i32 [[X]], 5 158; CHECK-NEXT: [[SEL_X_EQ_5:%.*]] = select i1 [[X_EQ_5]], ptr @s5, ptr @s7 159; 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, 3 165 %x_eq_5 = icmp eq i32 %X, 5 166 %sel_x_eq_5 = select i1 %x_eq_5, ptr @s5, ptr @s7 167 %sel = select i1 %x_eq_3, ptr @s3, ptr %sel_x_eq_5 168 %len = tail call i64 @strlen(ptr %sel) 169 ret i64 %len 170} 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:%.*]], 3 178; CHECK-NEXT: [[X_EQ_5:%.*]] = icmp eq i32 [[X]], 5 179; CHECK-NEXT: [[SEL_X_EQ_5:%.*]] = select i1 [[X_EQ_5]], ptr @s5, ptr @s7 180; 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, 3 186 %x_eq_5 = icmp eq i32 %X, 5 187 %sel_x_eq_5 = select i1 %x_eq_5, ptr @s5, ptr @s7 188 %sel = select i1 %x_eq_3, ptr @sx, ptr %sel_x_eq_5 189 %len = tail call i64 @strlen(ptr %sel) 190 ret i64 %len 191} 192