1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; Verify that strnlen calls with conditional expressions involving constant 3; string arguments with nonconstant offsets and constant bounds or constant 4; offsets and nonconstant bounds are folded correctly. 5; 6; RUN: opt < %s -passes=instcombine -S | FileCheck %s 7 8declare i64 @strnlen(ptr, i64) 9 10@sx = external global [0 x i8] 11@a3 = constant [3 x i8] c"123" 12@s3 = constant [4 x i8] c"123\00" 13@s5 = constant [6 x i8] c"12345\00" 14@s5_3 = constant [10 x i8] c"12345\00abc\00" 15 16 17; Fold strnlen(sx + i, 0) to 0. 18 19define i64 @fold_strnlen_sx_pi_0(i64 %i) { 20; CHECK-LABEL: @fold_strnlen_sx_pi_0( 21; CHECK-NEXT: ret i64 0 22; 23 24 %ptr = getelementptr [0 x i8], ptr @sx, i64 0, i64 %i 25 %len = call i64 @strnlen(ptr %ptr, i64 0) 26 ret i64 %len 27} 28 29 30; Do not fold strnlen(sx + i, n). 31 32define i64 @call_strnlen_sx_pi_n(i64 %i, i64 %n) { 33; CHECK-LABEL: @call_strnlen_sx_pi_n( 34; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds [0 x i8], ptr @sx, i64 0, i64 [[I:%.*]] 35; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(ptr nonnull [[PTR]], i64 [[N:%.*]]) 36; CHECK-NEXT: ret i64 [[LEN]] 37; 38 39 %ptr = getelementptr inbounds [0 x i8], ptr @sx, i64 0, i64 %i 40 %len = call i64 @strnlen(ptr %ptr, i64 %n) 41 ret i64 %len 42} 43 44 45; Fold strnlen(a3 + i, 2) to min(3 - i, 2). 46 47define i64 @call_strnlen_a3_pi_2(i64 %i) { 48; CHECK-LABEL: @call_strnlen_a3_pi_2( 49; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds [3 x i8], ptr @a3, i64 0, i64 [[I:%.*]] 50; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(ptr noundef nonnull dereferenceable(1) [[PTR]], i64 2) 51; CHECK-NEXT: ret i64 [[LEN]] 52; 53 54 %ptr = getelementptr inbounds [3 x i8], ptr @a3, i64 0, i64 %i 55 %len = call i64 @strnlen(ptr %ptr, i64 2) 56 ret i64 %len 57} 58 59 60; Fold strnlen(a3 + i, 3) to min(3 - i, 3). 61 62define i64 @call_strnlen_a3_pi_3(i64 %i) { 63; CHECK-LABEL: @call_strnlen_a3_pi_3( 64; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds [3 x i8], ptr @a3, i64 0, i64 [[I:%.*]] 65; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(ptr noundef nonnull dereferenceable(1) [[PTR]], i64 3) 66; CHECK-NEXT: ret i64 [[LEN]] 67; 68 69 %ptr = getelementptr inbounds [3 x i8], ptr @a3, i64 0, i64 %i 70 %len = call i64 @strnlen(ptr %ptr, i64 3) 71 ret i64 %len 72} 73 74 75; Fold strnlen(s3 + i, 0) to 0. 76 77define i64 @fold_strnlen_s3_pi_0(i64 %i) { 78; CHECK-LABEL: @fold_strnlen_s3_pi_0( 79; CHECK-NEXT: ret i64 0 80; 81 %ptr = getelementptr inbounds [4 x i8], ptr @s3, i64 0, i64 %i 82 %len = call i64 @strnlen(ptr %ptr, i64 0) 83 ret i64 %len 84} 85 86 87; Fold strnlen(s5 + i, 0) to 0. 88 89define i64 @call_strnlen_s5_pi_0(i64 zeroext %i) { 90; CHECK-LABEL: @call_strnlen_s5_pi_0( 91; CHECK-NEXT: ret i64 0 92; 93 %len = call i64 @strnlen(ptr @s5, i64 0) 94 ret i64 %len 95} 96 97 98; Fold strnlen(s5_3 + i, 0) to 0. 99 100define i64 @fold_strnlen_s5_3_pi_0(i64 zeroext %i) { 101; CHECK-LABEL: @fold_strnlen_s5_3_pi_0( 102; CHECK-NEXT: ret i64 0 103; 104 %ptr = getelementptr [10 x i8], ptr @s5_3, i32 0, i64 %i 105 %len = call i64 @strnlen(ptr %ptr, i64 0) 106 ret i64 %len 107} 108 109 110; Do not fold strnlen(s5_3 + i, n). 111 112define i64 @call_strnlen_s5_3_pi_n(i64 zeroext %i, i64 %n) { 113; CHECK-LABEL: @call_strnlen_s5_3_pi_n( 114; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds [10 x i8], ptr @s5_3, i64 0, i64 [[I:%.*]] 115; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(ptr nonnull [[PTR]], i64 [[N:%.*]]) 116; CHECK-NEXT: ret i64 [[LEN]] 117; 118 %ptr = getelementptr inbounds [10 x i8], ptr @s5_3, i32 0, i64 %i 119 %len = call i64 @strnlen(ptr %ptr, i64 %n) 120 ret i64 %len 121} 122 123 124; Fold strnlen(a3, n) to min(sizeof(a3), n) 125 126define i64 @fold_strnlen_a3_n(i64 %n) { 127; CHECK-LABEL: @fold_strnlen_a3_n( 128; CHECK-NEXT: [[LEN:%.*]] = call i64 @llvm.umin.i64(i64 [[N:%.*]], i64 3) 129; CHECK-NEXT: ret i64 [[LEN]] 130; 131 132 %len = call i64 @strnlen(ptr @a3, i64 %n) 133 ret i64 %len 134} 135 136 137; Fold strnlen(s3, n) to min(strlen(s3), n) 138 139define i64 @fold_strnlen_s3_n(i64 %n) { 140; CHECK-LABEL: @fold_strnlen_s3_n( 141; CHECK-NEXT: [[LEN:%.*]] = call i64 @llvm.umin.i64(i64 [[N:%.*]], i64 3) 142; CHECK-NEXT: ret i64 [[LEN]] 143; 144 145 %len = call i64 @strnlen(ptr @s3, i64 %n) 146 ret i64 %len 147} 148 149 150; Fold strnlen(a3 + i, 2) to min(sizeof(a3) - i, 2) 151 152define i64 @fold_strnlen_a3_pi_2(i64 %i) { 153; CHECK-LABEL: @fold_strnlen_a3_pi_2( 154; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds [3 x i8], ptr @a3, i64 0, i64 [[I:%.*]] 155; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(ptr noundef nonnull dereferenceable(1) [[PTR]], i64 2) 156; CHECK-NEXT: ret i64 [[LEN]] 157; 158 159 %ptr = getelementptr inbounds [3 x i8], ptr @a3, i64 0, i64 %i 160 %len = call i64 @strnlen(ptr %ptr, i64 2) 161 ret i64 %len 162} 163 164 165; Fold strnlen(s3 + i, 2) to min(strlen(s3) - i, 2) 166 167define i64 @fold_strnlen_s3_pi_2(i64 %i) { 168; CHECK-LABEL: @fold_strnlen_s3_pi_2( 169; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds [4 x i8], ptr @s3, i64 0, i64 [[I:%.*]] 170; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(ptr noundef nonnull dereferenceable(1) [[PTR]], i64 2) 171; CHECK-NEXT: ret i64 [[LEN]] 172; 173 174 %ptr = getelementptr inbounds [4 x i8], ptr @s3, i64 0, i64 %i 175 %len = call i64 @strnlen(ptr %ptr, i64 2) 176 ret i64 %len 177} 178 179 180; Fold strnlen(s3 + i, 3) to min(strlen(s3) - i, 3) 181 182define i64 @fold_strnlen_s3_pi_3(i64 %i) { 183; CHECK-LABEL: @fold_strnlen_s3_pi_3( 184; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds [4 x i8], ptr @s3, i64 0, i64 [[I:%.*]] 185; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(ptr noundef nonnull dereferenceable(1) [[PTR]], i64 3) 186; CHECK-NEXT: ret i64 [[LEN]] 187; 188 189 %ptr = getelementptr inbounds [4 x i8], ptr @s3, i64 0, i64 %i 190 %len = call i64 @strnlen(ptr %ptr, i64 3) 191 ret i64 %len 192} 193 194 195; Fold strnlen(s3 + i, n) to min(strlen(s3) - i, n) 196 197define i64 @fold_strnlen_s3_pi_n(i64 %i, i64 %n) { 198; CHECK-LABEL: @fold_strnlen_s3_pi_n( 199; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds [4 x i8], ptr @s3, i64 0, i64 [[I:%.*]] 200; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(ptr nonnull [[PTR]], i64 [[N:%.*]]) 201; CHECK-NEXT: ret i64 [[LEN]] 202; 203 204 %ptr = getelementptr inbounds [4 x i8], ptr @s3, i64 0, i64 %i 205 %len = call i64 @strnlen(ptr %ptr, i64 %n) 206 ret i64 %len 207} 208 209 210; Do not fold strnlen(s5_3 + i, 2). The result is in [0, 2] but there's 211; no simple way to derive its lower bound from the offset. 212 213define i64 @call_strnlen_s5_3_pi_2(i64 %i) { 214; CHECK-LABEL: @call_strnlen_s5_3_pi_2( 215; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds [10 x i8], ptr @s5_3, i64 0, i64 [[I:%.*]] 216; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(ptr noundef nonnull dereferenceable(1) [[PTR]], i64 2) 217; CHECK-NEXT: ret i64 [[LEN]] 218; 219 220 %ptr = getelementptr inbounds [10 x i8], ptr @s5_3, i64 0, i64 %i 221 %len = call i64 @strnlen(ptr %ptr, i64 2) 222 ret i64 %len 223} 224