1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; Assertions have been autogenerated by utils/update_test_checks.py 3; 4; RUN: opt < %s -data-layout="E" -passes=instcombine -S | FileCheck %s --check-prefixes=ANY,BE 5; RUN: opt < %s -data-layout="e" -passes=instcombine -S | FileCheck %s --check-prefixes=ANY,LE 6; 7; Test that the strncpy library call simplifier works correctly. 8 9declare i64 @strlcpy(ptr, ptr, i64) 10 11declare void @sink(ptr, i64) 12 13 14@s4 = constant [5 x i8] c"1234\00" 15 16 17; Verify that strlcpy(D, "", N) calls are transformed to a nul store 18; to *D for nonzero N and folded to zero for all values of N. 19 20define void @fold_strlcpy_s0(ptr %dst) { 21; ANY-LABEL: @fold_strlcpy_s0( 22; ANY-NEXT: call void @sink(ptr [[DST:%.*]], i64 0) 23; ANY-NEXT: store i8 0, ptr [[DST]], align 1 24; ANY-NEXT: call void @sink(ptr nonnull [[DST]], i64 0) 25; ANY-NEXT: store i8 0, ptr [[DST]], align 1 26; ANY-NEXT: call void @sink(ptr nonnull [[DST]], i64 0) 27; ANY-NEXT: ret void 28; 29 %ps0 = getelementptr [5 x i8], ptr @s4, i32 0, i32 4 30 31; Fold strlcpy(D, "", 0) to just 0. 32 %ns0_0 = call i64 @strlcpy(ptr %dst, ptr %ps0, i64 0) 33 call void @sink(ptr %dst, i64 %ns0_0) 34 35; Transform strlcpy(D, "", 1) to *D = '\0, 0. 36 %ns0_1 = call i64 @strlcpy(ptr %dst, ptr %ps0, i64 1) 37 call void @sink(ptr %dst, i64 %ns0_1) 38 39; Transform strlcpy(D, "", SIZE_MAX) to *D = '\0, 0. 40 %ns0_m1 = call i64 @strlcpy(ptr %dst, ptr %ps0, i64 -1) 41 call void @sink(ptr %dst, i64 %ns0_m1) 42 43 ret void 44} 45 46 47; Verify that strlcpy(D, "4", N) calls are transformed to a store to 48; D[0] for nonzero N (and a nul store to D[1] for N greater than 1) 49; and folded to 1 for all values of N. 50 51define void @fold_strlcpy_s1(ptr %dst) { 52; BE-LABEL: @fold_strlcpy_s1( 53; BE-NEXT: call void @sink(ptr [[DST:%.*]], i64 1) 54; BE-NEXT: store i8 0, ptr [[DST]], align 1 55; BE-NEXT: call void @sink(ptr nonnull [[DST]], i64 1) 56; BE-NEXT: store i16 13312, ptr [[DST]], align 1 57; BE-NEXT: call void @sink(ptr nonnull [[DST]], i64 1) 58; BE-NEXT: store i16 13312, ptr [[DST]], align 1 59; BE-NEXT: call void @sink(ptr nonnull [[DST]], i64 1) 60; BE-NEXT: store i16 13312, ptr [[DST]], align 1 61; BE-NEXT: call void @sink(ptr nonnull [[DST]], i64 1) 62; BE-NEXT: ret void 63; 64; LE-LABEL: @fold_strlcpy_s1( 65; LE-NEXT: call void @sink(ptr [[DST:%.*]], i64 1) 66; LE-NEXT: store i8 0, ptr [[DST]], align 1 67; LE-NEXT: call void @sink(ptr nonnull [[DST]], i64 1) 68; LE-NEXT: store i16 52, ptr [[DST]], align 1 69; LE-NEXT: call void @sink(ptr nonnull [[DST]], i64 1) 70; LE-NEXT: store i16 52, ptr [[DST]], align 1 71; LE-NEXT: call void @sink(ptr nonnull [[DST]], i64 1) 72; LE-NEXT: store i16 52, ptr [[DST]], align 1 73; LE-NEXT: call void @sink(ptr nonnull [[DST]], i64 1) 74; LE-NEXT: ret void 75; 76 %ps1 = getelementptr [5 x i8], ptr @s4, i32 0, i32 3 77 78; Fold strlcpy(D, "4", 0) to 1. 79 %ns1_0 = call i64 @strlcpy(ptr %dst, ptr %ps1, i64 0) 80 call void @sink(ptr %dst, i64 %ns1_0) 81 82; Transform strlcpy(D, "4", 1) to *D = '\0', 1. 83 %ns1_1 = call i64 @strlcpy(ptr %dst, ptr %ps1, i64 1) 84 call void @sink(ptr %dst, i64 %ns1_1) 85 86; Transform strlcpy(D, "4", 2) to D[0] = '\4, D[1] = '\0', 1. 87 %ns1_2 = call i64 @strlcpy(ptr %dst, ptr %ps1, i64 2) 88 call void @sink(ptr %dst, i64 %ns1_2) 89 90; Transform strlcpy(D, "4", 3) to D[0] = '\4, D[1] = '\0', 1.. 91 %ns1_3 = call i64 @strlcpy(ptr %dst, ptr %ps1, i64 3) 92 call void @sink(ptr %dst, i64 %ns1_3) 93 94; Transform strlcpy(D, "4", SIZE_MAX) to D[0] = '\4, D[1] = '\0', 1. 95 %ns1_m1 = call i64 @strlcpy(ptr %dst, ptr %ps1, i64 -1) 96 call void @sink(ptr %dst, i64 %ns1_m1) 97 98 ret void 99} 100 101 102; Verify that strlcpy(D, "1234", N) calls are transformed to a copy of 103; the N - 1 leading characters of the string to D and folded to 4 for 104; all values of N. 105 106define void @fold_strlcpy_s5(ptr %dst) { 107; BE-LABEL: @fold_strlcpy_s5( 108; BE-NEXT: call void @sink(ptr [[DST:%.*]], i64 4) 109; BE-NEXT: store i8 0, ptr [[DST]], align 1 110; BE-NEXT: call void @sink(ptr nonnull [[DST]], i64 4) 111; BE-NEXT: store i8 49, ptr [[DST]], align 1 112; BE-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 1 113; BE-NEXT: store i8 0, ptr [[TMP1]], align 1 114; BE-NEXT: call void @sink(ptr nonnull [[DST]], i64 4) 115; BE-NEXT: store i16 12594, ptr [[DST]], align 1 116; BE-NEXT: [[TMP2:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 2 117; BE-NEXT: store i8 0, ptr [[TMP2]], align 1 118; BE-NEXT: call void @sink(ptr nonnull [[DST]], i64 4) 119; BE-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 1 dereferenceable(3) [[DST]], ptr noundef nonnull align 1 dereferenceable(3) @s4, i64 3, i1 false) 120; BE-NEXT: [[TMP3:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 3 121; BE-NEXT: store i8 0, ptr [[TMP3]], align 1 122; BE-NEXT: call void @sink(ptr nonnull [[DST]], i64 4) 123; BE-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 1 dereferenceable(5) [[DST]], ptr noundef nonnull align 1 dereferenceable(5) @s4, i64 5, i1 false) 124; BE-NEXT: call void @sink(ptr nonnull [[DST]], i64 4) 125; BE-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 1 dereferenceable(5) [[DST]], ptr noundef nonnull align 1 dereferenceable(5) @s4, i64 5, i1 false) 126; BE-NEXT: call void @sink(ptr nonnull [[DST]], i64 4) 127; BE-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 1 dereferenceable(5) [[DST]], ptr noundef nonnull align 1 dereferenceable(5) @s4, i64 5, i1 false) 128; BE-NEXT: call void @sink(ptr nonnull [[DST]], i64 4) 129; BE-NEXT: ret void 130; 131; LE-LABEL: @fold_strlcpy_s5( 132; LE-NEXT: call void @sink(ptr [[DST:%.*]], i64 4) 133; LE-NEXT: store i8 0, ptr [[DST]], align 1 134; LE-NEXT: call void @sink(ptr nonnull [[DST]], i64 4) 135; LE-NEXT: store i8 49, ptr [[DST]], align 1 136; LE-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 1 137; LE-NEXT: store i8 0, ptr [[TMP1]], align 1 138; LE-NEXT: call void @sink(ptr nonnull [[DST]], i64 4) 139; LE-NEXT: store i16 12849, ptr [[DST]], align 1 140; LE-NEXT: [[TMP2:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 2 141; LE-NEXT: store i8 0, ptr [[TMP2]], align 1 142; LE-NEXT: call void @sink(ptr nonnull [[DST]], i64 4) 143; LE-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 1 dereferenceable(3) [[DST]], ptr noundef nonnull align 1 dereferenceable(3) @s4, i64 3, i1 false) 144; LE-NEXT: [[TMP3:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 3 145; LE-NEXT: store i8 0, ptr [[TMP3]], align 1 146; LE-NEXT: call void @sink(ptr nonnull [[DST]], i64 4) 147; LE-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 1 dereferenceable(5) [[DST]], ptr noundef nonnull align 1 dereferenceable(5) @s4, i64 5, i1 false) 148; LE-NEXT: call void @sink(ptr nonnull [[DST]], i64 4) 149; LE-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 1 dereferenceable(5) [[DST]], ptr noundef nonnull align 1 dereferenceable(5) @s4, i64 5, i1 false) 150; LE-NEXT: call void @sink(ptr nonnull [[DST]], i64 4) 151; LE-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 1 dereferenceable(5) [[DST]], ptr noundef nonnull align 1 dereferenceable(5) @s4, i64 5, i1 false) 152; LE-NEXT: call void @sink(ptr nonnull [[DST]], i64 4) 153; LE-NEXT: ret void 154; 155 156; Fold strlcpy(D, "1234", 0) to 4. 157 %ns4_0 = call i64 @strlcpy(ptr %dst, ptr @s4, i64 0) 158 call void @sink(ptr %dst, i64 %ns4_0) 159 160; Transform strlcpy(D, "1234", 1) to *D = '\0', 4. 161 %ns4_1 = call i64 @strlcpy(ptr %dst, ptr @s4, i64 1) 162 call void @sink(ptr %dst, i64 %ns4_1) 163 164; Transform strlcpy(D, "1234", 2) to D[0] = '1', D[1] = '\0', 4. 165 %ns4_2 = call i64 @strlcpy(ptr %dst, ptr @s4, i64 2) 166 call void @sink(ptr %dst, i64 %ns4_2) 167 168; Transform strlcpy(D, S="1234", 3) to memcpy(D, S, 2), D[2] = '\0', 4. 169 %ns4_3 = call i64 @strlcpy(ptr %dst, ptr @s4, i64 3) 170 call void @sink(ptr %dst, i64 %ns4_3) 171 172; Transform strlcpy(D, S="1234", 4) to memcpy(D, S, 3), D[3] = '\0', 4. 173 %ns4_4 = call i64 @strlcpy(ptr %dst, ptr @s4, i64 4) 174 call void @sink(ptr %dst, i64 %ns4_4) 175 176; Transform strlcpy(D, S="1234", 5) to memcpy(D, S, 5), 4. 177 %ns4_5 = call i64 @strlcpy(ptr %dst, ptr @s4, i64 5) 178 call void @sink(ptr %dst, i64 %ns4_5) 179 180; Transform strlcpy(D, S="1234", 9) to memcpy(D, S, 5), 4. 181 %ns4_9 = call i64 @strlcpy(ptr %dst, ptr @s4, i64 5) 182 call void @sink(ptr %dst, i64 %ns4_9) 183 184; Transform strlcpy(D, S="1234", SIZE_MAX) to memcpy(D, S, 5), 4. 185 %ns4_m1 = call i64 @strlcpy(ptr %dst, ptr @s4, i64 -1) 186 call void @sink(ptr %dst, i64 %ns4_m1) 187 188 ret void 189} 190 191; Verify that strlcpy(D, S, 1) calls are transformed into a nul store 192; to *D, strlcpy(D, S, 0) to a no-op, and the result of both folded 193; to strlen(S). 194 195define void @fold_strlcpy_s_0(ptr %dst, ptr %s, i64 %n) { 196; ANY-LABEL: @fold_strlcpy_s_0( 197; ANY-NEXT: store i8 0, ptr [[DST:%.*]], align 1 198; ANY-NEXT: [[STRLEN:%.*]] = call i64 @strlen(ptr noundef nonnull dereferenceable(1) [[S:%.*]]) 199; ANY-NEXT: call void @sink(ptr nonnull [[DST]], i64 [[STRLEN]]) 200; ANY-NEXT: [[STRLEN1:%.*]] = call i64 @strlen(ptr noundef nonnull dereferenceable(1) [[S]]) 201; ANY-NEXT: call void @sink(ptr nonnull [[DST]], i64 [[STRLEN1]]) 202; ANY-NEXT: [[STRLEN2:%.*]] = call i64 @strlen(ptr noundef nonnull dereferenceable(1) [[S]]) 203; ANY-NEXT: call void @sink(ptr nonnull [[DST]], i64 [[STRLEN2]]) 204; ANY-NEXT: ret void 205; 206; Transform strlcpy(D, S, 1) to *D = '\0', strlen(S). 207 %ns_1 = call i64 @strlcpy(ptr %dst, ptr %s, i64 1) 208 call void @sink(ptr %dst, i64 %ns_1) 209 210; For strlcpy(D, S, 0) to strlen(S). 211 %ns_0 = call i64 @strlcpy(ptr %dst, ptr %s, i64 0) 212 call void @sink(ptr %dst, i64 %ns_0) 213 214 ; Verify that calling strlcpy with a null destination is also folded 215 ; (to match a possible extension of some implementations that emulate 216 ; snprintf(0, 0, "%s", S)). 217 %n0_s_0 = call i64 @strlcpy(ptr null, ptr %s, i64 0) 218 call void @sink(ptr %dst, i64 %n0_s_0) 219 220 ret void 221} 222 223 224; Verify that strlcpy(D, S, N) calls are left alone when S and/or N are 225; not known (except for the cases handled above). Also verify that they 226; annotate the destination argument with the dereferenceable attribute 227; only with nonzero N. 228 229define void @call_strlcpy_s0_n(ptr %dst, ptr %s, i64 %n) { 230; ANY-LABEL: @call_strlcpy_s0_n( 231; ANY-NEXT: [[NS_2:%.*]] = call i64 @strlcpy(ptr noundef nonnull dereferenceable(1) [[DST:%.*]], ptr noundef nonnull dereferenceable(1) [[S:%.*]], i64 2) 232; ANY-NEXT: call void @sink(ptr nonnull [[DST]], i64 [[NS_2]]) 233; ANY-NEXT: [[NS_N:%.*]] = call i64 @strlcpy(ptr nonnull [[DST]], ptr noundef nonnull dereferenceable(1) [[S]], i64 [[N:%.*]]) 234; ANY-NEXT: call void @sink(ptr nonnull [[DST]], i64 [[NS_N]]) 235; ANY-NEXT: [[NZ:%.*]] = or i64 [[N]], 1 236; ANY-NEXT: [[NS_NZ:%.*]] = call i64 @strlcpy(ptr noundef nonnull dereferenceable(1) [[DST]], ptr noundef nonnull dereferenceable(1) [[S]], i64 [[NZ]]) 237; ANY-NEXT: call void @sink(ptr nonnull [[DST]], i64 [[NS_NZ]]) 238; ANY-NEXT: [[NS0_N:%.*]] = call i64 @strlcpy(ptr nonnull [[DST]], ptr noundef nonnull dereferenceable(1) getelementptr inbounds nuw (i8, ptr @s4, i64 4), i64 [[N]]) 239; ANY-NEXT: call void @sink(ptr nonnull [[DST]], i64 [[NS0_N]]) 240; ANY-NEXT: [[NS1_N:%.*]] = call i64 @strlcpy(ptr nonnull [[DST]], ptr noundef nonnull dereferenceable(1) getelementptr inbounds nuw (i8, ptr @s4, i64 3), i64 [[N]]) 241; ANY-NEXT: call void @sink(ptr nonnull [[DST]], i64 [[NS1_N]]) 242; ANY-NEXT: [[NS4_N:%.*]] = call i64 @strlcpy(ptr nonnull [[DST]], ptr noundef nonnull dereferenceable(1) @s4, i64 [[N]]) 243; ANY-NEXT: call void @sink(ptr nonnull [[DST]], i64 [[NS4_N]]) 244; ANY-NEXT: ret void 245; 246 %ns_2 = call i64 @strlcpy(ptr %dst, ptr %s, i64 2) 247 call void @sink(ptr %dst, i64 %ns_2) 248 249 %ns_n = call i64 @strlcpy(ptr %dst, ptr %s, i64 %n) 250 call void @sink(ptr %dst, i64 %ns_n) 251 252 %nz = or i64 %n, 1 253 %ns_nz = call i64 @strlcpy(ptr %dst, ptr %s, i64 %nz) 254 call void @sink(ptr %dst, i64 %ns_nz) 255 256 257 %ps0 = getelementptr [5 x i8], ptr @s4, i32 0, i32 4 258 %ns0_n = call i64 @strlcpy(ptr %dst, ptr %ps0, i64 %n) 259 call void @sink(ptr %dst, i64 %ns0_n) 260 261 %ps1 = getelementptr [5 x i8], ptr @s4, i32 0, i32 3 262 %ns1_n = call i64 @strlcpy(ptr %dst, ptr %ps1, i64 %n) 263 call void @sink(ptr %dst, i64 %ns1_n) 264 265 %ns4_n = call i64 @strlcpy(ptr %dst, ptr @s4, i64 %n) 266 call void @sink(ptr %dst, i64 %ns4_n) 267 268 ret void 269} 270 271 272@a5 = constant [5 x i8] c"12345" 273 274; Verify that the transformation behaves reasonably even when the source 275; array is not a nul-terminated string as it's required to be (and doesn't 276; for example attempt to read past its end). All the calls below are 277; undefined so technically reading past the end would be fine but it's 278; easy to avoid. 279 280define void @fold_strlcpy_a5(ptr %dst, i64 %n) { 281; BE-LABEL: @fold_strlcpy_a5( 282; BE-NEXT: call void @sink(ptr [[DST:%.*]], i64 5) 283; BE-NEXT: store i8 0, ptr [[DST]], align 1 284; BE-NEXT: call void @sink(ptr nonnull [[DST]], i64 5) 285; BE-NEXT: store i8 49, ptr [[DST]], align 1 286; BE-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 1 287; BE-NEXT: store i8 0, ptr [[TMP1]], align 1 288; BE-NEXT: call void @sink(ptr nonnull [[DST]], i64 5) 289; BE-NEXT: store i32 825373492, ptr [[DST]], align 1 290; BE-NEXT: [[TMP2:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 4 291; BE-NEXT: store i8 0, ptr [[TMP2]], align 1 292; BE-NEXT: call void @sink(ptr nonnull [[DST]], i64 5) 293; BE-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 1 dereferenceable(5) [[DST]], ptr noundef nonnull align 1 dereferenceable(5) @a5, i64 5, i1 false) 294; BE-NEXT: [[TMP3:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 5 295; BE-NEXT: store i8 0, ptr [[TMP3]], align 1 296; BE-NEXT: call void @sink(ptr nonnull [[DST]], i64 5) 297; BE-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 1 dereferenceable(5) [[DST]], ptr noundef nonnull align 1 dereferenceable(5) @a5, i64 5, i1 false) 298; BE-NEXT: [[TMP4:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 5 299; BE-NEXT: store i8 0, ptr [[TMP4]], align 1 300; BE-NEXT: call void @sink(ptr nonnull [[DST]], i64 5) 301; BE-NEXT: ret void 302; 303; LE-LABEL: @fold_strlcpy_a5( 304; LE-NEXT: call void @sink(ptr [[DST:%.*]], i64 5) 305; LE-NEXT: store i8 0, ptr [[DST]], align 1 306; LE-NEXT: call void @sink(ptr nonnull [[DST]], i64 5) 307; LE-NEXT: store i8 49, ptr [[DST]], align 1 308; LE-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 1 309; LE-NEXT: store i8 0, ptr [[TMP1]], align 1 310; LE-NEXT: call void @sink(ptr nonnull [[DST]], i64 5) 311; LE-NEXT: store i32 875770417, ptr [[DST]], align 1 312; LE-NEXT: [[TMP2:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 4 313; LE-NEXT: store i8 0, ptr [[TMP2]], align 1 314; LE-NEXT: call void @sink(ptr nonnull [[DST]], i64 5) 315; LE-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 1 dereferenceable(5) [[DST]], ptr noundef nonnull align 1 dereferenceable(5) @a5, i64 5, i1 false) 316; LE-NEXT: [[TMP3:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 5 317; LE-NEXT: store i8 0, ptr [[TMP3]], align 1 318; LE-NEXT: call void @sink(ptr nonnull [[DST]], i64 5) 319; LE-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 1 dereferenceable(5) [[DST]], ptr noundef nonnull align 1 dereferenceable(5) @a5, i64 5, i1 false) 320; LE-NEXT: [[TMP4:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 5 321; LE-NEXT: store i8 0, ptr [[TMP4]], align 1 322; LE-NEXT: call void @sink(ptr nonnull [[DST]], i64 5) 323; LE-NEXT: ret void 324; 325 %na5_0 = call i64 @strlcpy(ptr %dst, ptr @a5, i64 0) 326 call void @sink(ptr %dst, i64 %na5_0) 327 328 %na5_1 = call i64 @strlcpy(ptr %dst, ptr @a5, i64 1) 329 call void @sink(ptr %dst, i64 %na5_1) 330 331 %na5_2 = call i64 @strlcpy(ptr %dst, ptr @a5, i64 2) 332 call void @sink(ptr %dst, i64 %na5_2) 333 334 %na5_5 = call i64 @strlcpy(ptr %dst, ptr @a5, i64 5) 335 call void @sink(ptr %dst, i64 %na5_5) 336 337 %na5_6 = call i64 @strlcpy(ptr %dst, ptr @a5, i64 6) 338 call void @sink(ptr %dst, i64 %na5_6) 339 340 %na5_9 = call i64 @strlcpy(ptr %dst, ptr @a5, i64 9) 341 call void @sink(ptr %dst, i64 %na5_9) 342 343 ret void 344} 345