457 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals2;3; Test that the stpncpy library call simplifier works correctly.4;5; RUN: opt < %s -data-layout="E" -passes=instcombine -S | FileCheck %s --check-prefixes=ANY,BE6; RUN: opt < %s -data-layout="e" -passes=instcombine -S | FileCheck %s --check-prefixes=ANY,LE7 8declare ptr @stpncpy(ptr, ptr, i64)9 10declare void @sink(ptr, ptr)11 12@a4 = constant [4 x i8] c"1234"13@s4 = constant [5 x i8] c"1234\00"14 15 16; The following are generated by the stpncpy -> memcpy transformation17; (trading space for speed).18@str = private constant [4 x i8] c"4\00\00\00"19@str.1 = private constant [10 x i8] c"4\00\00\00\00\00\00\00\00\00"20@str.2 = private constant [10 x i8] c"1234\00\00\00\00\00\00"21@str.3 = private unnamed_addr constant [4 x i8] c"4\00\00\00", align 122@str.4 = private unnamed_addr constant [10 x i8] c"4\00\00\00\00\00\00\00\00\00", align 123@str.5 = private unnamed_addr constant [10 x i8] c"1234\00\00\00\00\00\00", align 124 25; Verify that the generated constants have the expected contents.26 27; Verify that exactly overlapping stpncpy(D, D, N) calls are transformed28; to D + strnlen(D, N) or, equivalently, D + (*D != '\0'), when N < 2.29 30;.31; ANY: @a4 = constant [4 x i8] c"1234"32; ANY: @s4 = constant [5 x i8] c"1234\00"33; ANY: @str = private constant [4 x i8] c"4\00\00\00"34; ANY: @str.1 = private constant [10 x i8] c"4\00\00\00\00\00\00\00\00\00"35; ANY: @str.2 = private constant [10 x i8] c"1234\00\00\00\00\00\00"36; ANY: @str.3 = private unnamed_addr constant [4 x i8] c"4\00\00\00", align 137; ANY: @str.4 = private unnamed_addr constant [10 x i8] c"4\00\00\00\00\00\00\00\00\00", align 138; ANY: @str.5 = private unnamed_addr constant [10 x i8] c"1234\00\00\00\00\00\00", align 139; ANY: @str.6 = private unnamed_addr constant [3 x i8] c"4\00\00", align 140; ANY: @str.7 = private unnamed_addr constant [9 x i8] c"4\00\00\00\00\00\00\00\00", align 141; ANY: @str.8 = private unnamed_addr constant [9 x i8] c"1234\00\00\00\00\00", align 142; ANY: @str.9 = private unnamed_addr constant [9 x i8] c"1234\00\00\00\00\00", align 143;.44define void @fold_stpncpy_overlap(ptr %dst, i64 %n) {45; ANY-LABEL: @fold_stpncpy_overlap(46; ANY-NEXT: call void @sink(ptr [[DST:%.*]], ptr [[DST]])47; ANY-NEXT: [[STXNCPY_CHAR0:%.*]] = load i8, ptr [[DST]], align 148; ANY-NEXT: [[STPNCPY_CHAR0CMP:%.*]] = icmp ne i8 [[STXNCPY_CHAR0]], 049; ANY-NEXT: [[STPNCPY_SEL_IDX:%.*]] = zext i1 [[STPNCPY_CHAR0CMP]] to i6450; ANY-NEXT: [[STPNCPY_SEL:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 [[STPNCPY_SEL_IDX]]51; ANY-NEXT: call void @sink(ptr nonnull [[DST]], ptr nonnull [[STPNCPY_SEL]])52; ANY-NEXT: ret void53;54; Fold stpncpy(D, D, 0) to just D.55 %es_0 = call ptr @stpncpy(ptr %dst, ptr %dst, i64 0)56 call void @sink(ptr %dst, ptr %es_0)57 58; Fold stpncpy(D, D, 1) to D + (*D != '\0').59 %es_1 = call ptr @stpncpy(ptr %dst, ptr %dst, i64 1)60 call void @sink(ptr %dst, ptr %es_1)61 62 ret void63}64 65 66; Verify that exactly overlapping stpncpy(D, D, N) calls are left alone67; when N >= 2. Such calls are strictly undefined and while simplifying68; them to the expected result is possible there is little to gain from it.69 70define void @call_stpncpy_overlap(ptr %dst, i64 %n) {71; ANY-LABEL: @call_stpncpy_overlap(72; ANY-NEXT: [[ES_2:%.*]] = call ptr @stpncpy(ptr noundef nonnull dereferenceable(1) [[DST:%.*]], ptr noundef nonnull dereferenceable(1) [[DST]], i64 2)73; ANY-NEXT: call void @sink(ptr nonnull [[DST]], ptr [[ES_2]])74; ANY-NEXT: [[ES_3:%.*]] = call ptr @stpncpy(ptr noundef nonnull dereferenceable(1) [[DST]], ptr noundef nonnull dereferenceable(1) [[DST]], i64 3)75; ANY-NEXT: call void @sink(ptr nonnull [[DST]], ptr [[ES_3]])76; ANY-NEXT: [[ES_N:%.*]] = call ptr @stpncpy(ptr nonnull [[DST]], ptr nonnull [[DST]], i64 [[N:%.*]])77; ANY-NEXT: call void @sink(ptr nonnull [[DST]], ptr [[ES_N]])78; ANY-NEXT: ret void79;80; Do not transform stpncpy(D, D, 2).81 %es_2 = call ptr @stpncpy(ptr %dst, ptr %dst, i64 2)82 call void @sink(ptr %dst, ptr %es_2)83 84; Do not transform stpncpy(D, D, 3).85 %es_3 = call ptr @stpncpy(ptr %dst, ptr %dst, i64 3)86 call void @sink(ptr %dst, ptr %es_3)87 88; Do not transform stpncpy(D, D, N).89 %es_n = call ptr @stpncpy(ptr %dst, ptr %dst, i64 %n)90 call void @sink(ptr %dst, ptr %es_n)91 92 ret void93}94 95 96; Verify that stpncpy(D, "", N) calls are transformed to memset(D, 0, N).97 98define void @fold_stpncpy_s0(ptr %dst, i64 %n) {99; ANY-LABEL: @fold_stpncpy_s0(100; ANY-NEXT: call void @sink(ptr [[DST:%.*]], ptr [[DST]])101; ANY-NEXT: store i8 0, ptr [[DST]], align 1102; ANY-NEXT: call void @sink(ptr nonnull [[DST]], ptr nonnull [[DST]])103; ANY-NEXT: store i16 0, ptr [[DST]], align 1104; ANY-NEXT: call void @sink(ptr nonnull [[DST]], ptr nonnull [[DST]])105; ANY-NEXT: call void @llvm.memset.p0.i64(ptr noundef nonnull align 1 dereferenceable(9) [[DST]], i8 0, i64 9, i1 false)106; ANY-NEXT: call void @sink(ptr nonnull [[DST]], ptr nonnull [[DST]])107; ANY-NEXT: call void @llvm.memset.p0.i64(ptr nonnull align 1 [[DST]], i8 0, i64 [[N:%.*]], i1 false)108; ANY-NEXT: call void @sink(ptr nonnull [[DST]], ptr nonnull [[DST]])109; ANY-NEXT: ret void110;111 %ps0 = getelementptr [5 x i8], ptr @s4, i32 0, i32 4112 113; Fold stpncpy(D, "", 0) to just D.114 %es0_0 = call ptr @stpncpy(ptr %dst, ptr %ps0, i64 0)115 call void @sink(ptr %dst, ptr %es0_0)116 117; Transform stpncpy(D, "", 1) to *D = '\0, D.118 %es0_1 = call ptr @stpncpy(ptr %dst, ptr %ps0, i64 1)119 call void @sink(ptr %dst, ptr %es0_1)120 121; Transform stpncpy(D, "", 2) to memset(D, 0, 2), D.122 %es0_2 = call ptr @stpncpy(ptr %dst, ptr %ps0, i64 2)123 call void @sink(ptr %dst, ptr %es0_2)124 125; Transform stpncpy(D, "", 9) to memset(D, 0, 9), D.126 %es0_9 = call ptr @stpncpy(ptr %dst, ptr %ps0, i64 9)127 call void @sink(ptr %dst, ptr %es0_9)128 129; Transform stpncpy(D, "", n) to memset(D, 0, n), D.130 %es0_n = call ptr @stpncpy(ptr %dst, ptr %ps0, i64 %n)131 call void @sink(ptr %dst, ptr %es0_n)132 133 ret void134}135 136 137; Verify that stpncpy(D, "4", N) calls are transformed to the equivalent138; of strncpy(D, "4", N) and the result folded to D + (N != 0).139 140define void @fold_stpncpy_s1(ptr %dst) {141; BE-LABEL: @fold_stpncpy_s1(142; BE-NEXT: call void @sink(ptr [[DST:%.*]], ptr [[DST]])143; BE-NEXT: store i8 52, ptr [[DST]], align 1144; BE-NEXT: [[STPNCPY_END:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 1145; BE-NEXT: call void @sink(ptr nonnull [[DST]], ptr nonnull [[STPNCPY_END]])146; BE-NEXT: store i16 13312, ptr [[DST]], align 1147; BE-NEXT: [[ENDPTR:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 1148; BE-NEXT: call void @sink(ptr nonnull [[DST]], ptr nonnull [[ENDPTR]])149; BE-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 1 dereferenceable(3) [[DST]], ptr noundef nonnull align 1 dereferenceable(3) @str.6, i64 3, i1 false)150; BE-NEXT: [[ENDPTR1:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 1151; BE-NEXT: call void @sink(ptr nonnull [[DST]], ptr nonnull [[ENDPTR1]])152; BE-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 1 dereferenceable(9) [[DST]], ptr noundef nonnull align 1 dereferenceable(9) @str.7, i64 9, i1 false)153; BE-NEXT: [[ENDPTR2:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 1154; BE-NEXT: call void @sink(ptr nonnull [[DST]], ptr nonnull [[ENDPTR2]])155; BE-NEXT: ret void156;157; LE-LABEL: @fold_stpncpy_s1(158; LE-NEXT: call void @sink(ptr [[DST:%.*]], ptr [[DST]])159; LE-NEXT: store i8 52, ptr [[DST]], align 1160; LE-NEXT: [[STPNCPY_END:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 1161; LE-NEXT: call void @sink(ptr nonnull [[DST]], ptr nonnull [[STPNCPY_END]])162; LE-NEXT: store i16 52, ptr [[DST]], align 1163; LE-NEXT: [[ENDPTR:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 1164; LE-NEXT: call void @sink(ptr nonnull [[DST]], ptr nonnull [[ENDPTR]])165; LE-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 1 dereferenceable(3) [[DST]], ptr noundef nonnull align 1 dereferenceable(3) @str.6, i64 3, i1 false)166; LE-NEXT: [[ENDPTR1:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 1167; LE-NEXT: call void @sink(ptr nonnull [[DST]], ptr nonnull [[ENDPTR1]])168; LE-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 1 dereferenceable(9) [[DST]], ptr noundef nonnull align 1 dereferenceable(9) @str.7, i64 9, i1 false)169; LE-NEXT: [[ENDPTR2:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 1170; LE-NEXT: call void @sink(ptr nonnull [[DST]], ptr nonnull [[ENDPTR2]])171; LE-NEXT: ret void172;173 %ps1 = getelementptr [5 x i8], ptr @s4, i32 0, i32 3174 175; Fold stpncpy(D, "4", 0) to just D.176 %es1_0 = call ptr @stpncpy(ptr %dst, ptr %ps1, i64 0)177 call void @sink(ptr %dst, ptr %es1_0)178 179; Transform stpncpy(D, "4", 1) to *D = '4', D + 1.180 %es1_1 = call ptr @stpncpy(ptr %dst, ptr %ps1, i64 1)181 call void @sink(ptr %dst, ptr %es1_1)182 183; Transform stpncpy(D, "4", 2) to strncpy(D, "4", 2) + 1.184 %es1_2 = call ptr @stpncpy(ptr %dst, ptr %ps1, i64 2)185 call void @sink(ptr %dst, ptr %es1_2)186 187; Transform stpncpy(D, "4", 3) to strncpy(D, "4", 3) + 1, which is then188; transformed to memcpy(D, "4", 2), D[2] = '\0', D + 1.189 %es1_3 = call ptr @stpncpy(ptr %dst, ptr %ps1, i64 3)190 call void @sink(ptr %dst, ptr %es1_3)191 192; Transform stpncpy(D, "4", 9) to strncpy(D, "4", 9) + 1.193 %es1_9 = call ptr @stpncpy(ptr %dst, ptr %ps1, i64 9)194 call void @sink(ptr %dst, ptr %es1_9)195 196 ret void197}198 199 200; Verify that stpncpy(D, "1234", N) calls are transformed to the equivalent201; of strncpy(D, "1234", N) and the result folded to D + min(4, N).202 203define void @fold_stpncpy_s4(ptr %dst, i64 %n) {204; BE-LABEL: @fold_stpncpy_s4(205; BE-NEXT: call void @sink(ptr [[DST:%.*]], ptr [[DST]])206; BE-NEXT: store i8 49, ptr [[DST]], align 1207; BE-NEXT: [[STPNCPY_END:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 1208; BE-NEXT: call void @sink(ptr nonnull [[DST]], ptr nonnull [[STPNCPY_END]])209; BE-NEXT: store i16 12594, ptr [[DST]], align 1210; BE-NEXT: [[ENDPTR:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 2211; BE-NEXT: call void @sink(ptr nonnull [[DST]], ptr nonnull [[ENDPTR]])212; BE-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 1 dereferenceable(3) [[DST]], ptr noundef nonnull align 1 dereferenceable(5) @s4, i64 3, i1 false)213; BE-NEXT: [[ENDPTR1:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 3214; BE-NEXT: call void @sink(ptr nonnull [[DST]], ptr nonnull [[ENDPTR1]])215; BE-NEXT: store i32 825373492, ptr [[DST]], align 1216; BE-NEXT: [[ENDPTR2:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 4217; BE-NEXT: call void @sink(ptr nonnull [[DST]], ptr nonnull [[ENDPTR2]])218; BE-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 1 dereferenceable(9) [[DST]], ptr noundef nonnull align 1 dereferenceable(9) @str.8, i64 9, i1 false)219; BE-NEXT: [[ENDPTR3:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 4220; BE-NEXT: call void @sink(ptr nonnull [[DST]], ptr nonnull [[ENDPTR3]])221; BE-NEXT: ret void222;223; LE-LABEL: @fold_stpncpy_s4(224; LE-NEXT: call void @sink(ptr [[DST:%.*]], ptr [[DST]])225; LE-NEXT: store i8 49, ptr [[DST]], align 1226; LE-NEXT: [[STPNCPY_END:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 1227; LE-NEXT: call void @sink(ptr nonnull [[DST]], ptr nonnull [[STPNCPY_END]])228; LE-NEXT: store i16 12849, ptr [[DST]], align 1229; LE-NEXT: [[ENDPTR:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 2230; LE-NEXT: call void @sink(ptr nonnull [[DST]], ptr nonnull [[ENDPTR]])231; LE-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 1 dereferenceable(3) [[DST]], ptr noundef nonnull align 1 dereferenceable(5) @s4, i64 3, i1 false)232; LE-NEXT: [[ENDPTR1:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 3233; LE-NEXT: call void @sink(ptr nonnull [[DST]], ptr nonnull [[ENDPTR1]])234; LE-NEXT: store i32 875770417, ptr [[DST]], align 1235; LE-NEXT: [[ENDPTR2:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 4236; LE-NEXT: call void @sink(ptr nonnull [[DST]], ptr nonnull [[ENDPTR2]])237; LE-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 1 dereferenceable(9) [[DST]], ptr noundef nonnull align 1 dereferenceable(9) @str.8, i64 9, i1 false)238; LE-NEXT: [[ENDPTR3:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 4239; LE-NEXT: call void @sink(ptr nonnull [[DST]], ptr nonnull [[ENDPTR3]])240; LE-NEXT: ret void241;242 243; Fold stpncpy(D, "1234", 0) to just D.244 %es4_0 = call ptr @stpncpy(ptr %dst, ptr @s4, i64 0)245 call void @sink(ptr %dst, ptr %es4_0)246 247; Transform stpncpy(D, "1234", 1) to *D = '4', D + 1.248 %es4_1 = call ptr @stpncpy(ptr %dst, ptr @s4, i64 1)249 call void @sink(ptr %dst, ptr %es4_1)250 251; Transform stpncpy(D, "1234", 2) to strncpy(D, "1234", 2) + 2.252 %es4_2 = call ptr @stpncpy(ptr %dst, ptr @s4, i64 2)253 call void @sink(ptr %dst, ptr %es4_2)254 255; Transform stpncpy(D, "1234", 3) to strncpy(D, "1234", 3) + 3256 %es4_3 = call ptr @stpncpy(ptr %dst, ptr @s4, i64 3)257 call void @sink(ptr %dst, ptr %es4_3)258 259; Transform stpncpy(D, "1234", 4) to strncpy(D, "1234", 4) + 4.260 %es4_4 = call ptr @stpncpy(ptr %dst, ptr @s4, i64 4)261 call void @sink(ptr %dst, ptr %es4_4)262 263; Transform stpncpy(D, "1234", 9) to strncpy(D, "1234", 9) + 4.264 %es4_9 = call ptr @stpncpy(ptr %dst, ptr @s4, i64 9)265 call void @sink(ptr %dst, ptr %es4_9)266 267 ret void268}269 270 271; Verify that a call to stpncpy(D, A, N) with a constant source larger272; than one byte is left alone when N is unknown.273 274define void @call_stpncpy_xx_n(ptr %dst, i64 %n) {275; ANY-LABEL: @call_stpncpy_xx_n(276; ANY-NEXT: [[EA1_N:%.*]] = call ptr @stpncpy(ptr [[DST:%.*]], ptr nonnull dereferenceable(2) getelementptr inbounds nuw (i8, ptr @a4, i64 3), i64 [[N:%.*]])277; ANY-NEXT: call void @sink(ptr [[DST]], ptr [[EA1_N]])278; ANY-NEXT: [[EA4_N:%.*]] = call ptr @stpncpy(ptr [[DST]], ptr nonnull dereferenceable(5) @a4, i64 [[N]])279; ANY-NEXT: call void @sink(ptr [[DST]], ptr [[EA4_N]])280; ANY-NEXT: [[ES1_N:%.*]] = call ptr @stpncpy(ptr [[DST]], ptr nonnull dereferenceable(2) getelementptr inbounds nuw (i8, ptr @s4, i64 3), i64 [[N]])281; ANY-NEXT: call void @sink(ptr [[DST]], ptr [[ES1_N]])282; ANY-NEXT: [[ES4_N:%.*]] = call ptr @stpncpy(ptr [[DST]], ptr nonnull dereferenceable(5) @s4, i64 [[N]])283; ANY-NEXT: call void @sink(ptr [[DST]], ptr [[ES4_N]])284; ANY-NEXT: ret void285;286; Do not transform stpncpy(D, A4 + 3, N) when N is unknown.287 %pa1 = getelementptr [4 x i8], ptr @a4, i32 0, i32 3288 %ea1_n = call ptr @stpncpy(ptr %dst, ptr %pa1, i64 %n)289 call void @sink(ptr %dst, ptr %ea1_n)290 291; Do not transform stpncpy(D, A4, N) when N is unknown.292 %ea4_n = call ptr @stpncpy(ptr %dst, ptr @a4, i64 %n)293 call void @sink(ptr %dst, ptr %ea4_n)294 295; Do not transform stpncpy(D, "4", N) when N is unknown.296 %ps1 = getelementptr [5 x i8], ptr @s4, i32 0, i32 3297 %es1_n = call ptr @stpncpy(ptr %dst, ptr %ps1, i64 %n)298 call void @sink(ptr %dst, ptr %es1_n)299 300; Likewise, do not transform stpncpy(D, "1234", N) when N is unknown.301 %es4_n = call ptr @stpncpy(ptr %dst, ptr @s4, i64 %n)302 call void @sink(ptr %dst, ptr %es4_n)303 304 ret void305}306 307; Verify that stpncpy(D, (char[4]){"1234"}, N) calls with an unterminated308; source array are transformed to the equivalent strncpy call and the result309; folded to D + min(4, N).310 311define void @fold_stpncpy_a4(ptr %dst, i64 %n) {312; BE-LABEL: @fold_stpncpy_a4(313; BE-NEXT: call void @sink(ptr [[DST:%.*]], ptr [[DST]])314; BE-NEXT: store i8 49, ptr [[DST]], align 1315; BE-NEXT: [[STPNCPY_END:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 1316; BE-NEXT: call void @sink(ptr nonnull [[DST]], ptr nonnull [[STPNCPY_END]])317; BE-NEXT: store i16 12594, ptr [[DST]], align 1318; BE-NEXT: [[ENDPTR:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 2319; BE-NEXT: call void @sink(ptr nonnull [[DST]], ptr nonnull [[ENDPTR]])320; BE-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 1 dereferenceable(3) [[DST]], ptr noundef nonnull align 1 dereferenceable(5) @a4, i64 3, i1 false)321; BE-NEXT: [[ENDPTR1:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 3322; BE-NEXT: call void @sink(ptr nonnull [[DST]], ptr nonnull [[ENDPTR1]])323; BE-NEXT: store i32 825373492, ptr [[DST]], align 1324; BE-NEXT: [[ENDPTR2:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 4325; BE-NEXT: call void @sink(ptr nonnull [[DST]], ptr nonnull [[ENDPTR2]])326; BE-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 1 dereferenceable(5) [[DST]], ptr noundef nonnull align 1 dereferenceable(5) @a4, i64 5, i1 false)327; BE-NEXT: [[ENDPTR3:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 4328; BE-NEXT: call void @sink(ptr nonnull [[DST]], ptr nonnull [[ENDPTR3]])329; BE-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 1 dereferenceable(9) [[DST]], ptr noundef nonnull align 1 dereferenceable(9) @str.9, i64 9, i1 false)330; BE-NEXT: [[ENDPTR4:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 4331; BE-NEXT: call void @sink(ptr nonnull [[DST]], ptr nonnull [[ENDPTR4]])332; BE-NEXT: ret void333;334; LE-LABEL: @fold_stpncpy_a4(335; LE-NEXT: call void @sink(ptr [[DST:%.*]], ptr [[DST]])336; LE-NEXT: store i8 49, ptr [[DST]], align 1337; LE-NEXT: [[STPNCPY_END:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 1338; LE-NEXT: call void @sink(ptr nonnull [[DST]], ptr nonnull [[STPNCPY_END]])339; LE-NEXT: store i16 12849, ptr [[DST]], align 1340; LE-NEXT: [[ENDPTR:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 2341; LE-NEXT: call void @sink(ptr nonnull [[DST]], ptr nonnull [[ENDPTR]])342; LE-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 1 dereferenceable(3) [[DST]], ptr noundef nonnull align 1 dereferenceable(5) @a4, i64 3, i1 false)343; LE-NEXT: [[ENDPTR1:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 3344; LE-NEXT: call void @sink(ptr nonnull [[DST]], ptr nonnull [[ENDPTR1]])345; LE-NEXT: store i32 875770417, ptr [[DST]], align 1346; LE-NEXT: [[ENDPTR2:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 4347; LE-NEXT: call void @sink(ptr nonnull [[DST]], ptr nonnull [[ENDPTR2]])348; LE-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 1 dereferenceable(5) [[DST]], ptr noundef nonnull align 1 dereferenceable(5) @a4, i64 5, i1 false)349; LE-NEXT: [[ENDPTR3:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 4350; LE-NEXT: call void @sink(ptr nonnull [[DST]], ptr nonnull [[ENDPTR3]])351; LE-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 1 dereferenceable(9) [[DST]], ptr noundef nonnull align 1 dereferenceable(9) @str.9, i64 9, i1 false)352; LE-NEXT: [[ENDPTR4:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 4353; LE-NEXT: call void @sink(ptr nonnull [[DST]], ptr nonnull [[ENDPTR4]])354; LE-NEXT: ret void355;356 357 358; Fold stpncpy(D, A4, 0) to just D.359 %ea4_0 = call ptr @stpncpy(ptr %dst, ptr @a4, i64 0)360 call void @sink(ptr %dst, ptr %ea4_0)361 362; Transform stpncpy(D, A4, 1) to *D = '4', D + 1.363 %ea4_1 = call ptr @stpncpy(ptr %dst, ptr @a4, i64 1)364 call void @sink(ptr %dst, ptr %ea4_1)365 366; Transform stpncpy(D, A4, 2) to strncpy(D, A4, 2) + 2.367 %ea4_2 = call ptr @stpncpy(ptr %dst, ptr @a4, i64 2)368 call void @sink(ptr %dst, ptr %ea4_2)369 370; Transform stpncpy(D, A4, 3) to strncpy(D, A4, 3) + 3371 %ea4_3 = call ptr @stpncpy(ptr %dst, ptr @a4, i64 3)372 call void @sink(ptr %dst, ptr %ea4_3)373 374; Transform stpncpy(D, A4, 4) to strncpy(D, A4, 4) + 4.375 %ea4_4 = call ptr @stpncpy(ptr %dst, ptr @a4, i64 4)376 call void @sink(ptr %dst, ptr %ea4_4)377 378; Transform stpncpy(D, A4, 5) to strncpy(D, A4, 5) + 4.379 %ea4_5 = call ptr @stpncpy(ptr %dst, ptr @a4, i64 5)380 call void @sink(ptr %dst, ptr %ea4_5)381 382; Transform stpncpy(D, A4, 9) to strncpy(D, A4, 9) + 4.383 %ea4_9 = call ptr @stpncpy(ptr %dst, ptr @a4, i64 9)384 call void @sink(ptr %dst, ptr %ea4_9)385 386 ret void387}388 389 390; Verify that stpncpy(D, S, N) calls with N < 2 are transformed to391; the equivalent of strncpy and either folded to D if N == 0 or to392; *D ? D + 1 : D otherwise.393 394define void @fold_stpncpy_s(ptr %dst, ptr %src) {395; ANY-LABEL: @fold_stpncpy_s(396; ANY-NEXT: call void @sink(ptr [[DST:%.*]], ptr [[DST]])397; ANY-NEXT: [[STXNCPY_CHAR0:%.*]] = load i8, ptr [[SRC:%.*]], align 1398; ANY-NEXT: store i8 [[STXNCPY_CHAR0]], ptr [[DST]], align 1399; ANY-NEXT: [[STPNCPY_CHAR0CMP:%.*]] = icmp ne i8 [[STXNCPY_CHAR0]], 0400; ANY-NEXT: [[STPNCPY_SEL_IDX:%.*]] = zext i1 [[STPNCPY_CHAR0CMP]] to i64401; ANY-NEXT: [[STPNCPY_SEL:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 [[STPNCPY_SEL_IDX]]402; ANY-NEXT: call void @sink(ptr nonnull [[DST]], ptr nonnull [[STPNCPY_SEL]])403; ANY-NEXT: ret void404;405; Fold stpncpy(D, S, 0) to just D.406 %es_0 = call ptr @stpncpy(ptr %dst, ptr %src, i64 0)407 call void @sink(ptr %dst, ptr %es_0)408 409; Transform stpncpy(D, "", 1) to *D = '\0, D.410 %es_1 = call ptr @stpncpy(ptr %dst, ptr %src, i64 1)411 call void @sink(ptr %dst, ptr %es_1)412 413 ret void414}415 416 417; Verify that stpncpy(D, S, N) calls with N >= 2 are not transformed.418; In theory they could be transformed to the equivalent of the following419; though it's not clear that it would be a win:420; P = memccpy(D, S, 0, N)421; N' = P ? N - (P - D) : 0422; Q = P ? P : D + N423; memset(Q, 0, N')424; Q425; Also verify that the arguments of the call are annotated with the right426; attributes.427 428define void @call_stpncpy_s(ptr %dst, ptr %src, i64 %n) {429; ANY-LABEL: @call_stpncpy_s(430; ANY-NEXT: [[ES_2:%.*]] = call ptr @stpncpy(ptr noundef nonnull dereferenceable(1) [[DST:%.*]], ptr noundef nonnull dereferenceable(1) [[SRC:%.*]], i64 2)431; ANY-NEXT: call void @sink(ptr nonnull [[DST]], ptr [[ES_2]])432; ANY-NEXT: [[ES_N:%.*]] = call ptr @stpncpy(ptr nonnull [[DST]], ptr nonnull [[SRC]], i64 [[N:%.*]])433; ANY-NEXT: call void @sink(ptr nonnull [[DST]], ptr [[ES_N]])434; ANY-NEXT: ret void435;436; Do not transform stpncpy(D, S, 2). Both *D and *S must be derefernceable437; but neither D[1] nor S[1] need be.438 %es_2 = call ptr @stpncpy(ptr %dst, ptr %src, i64 2)439 call void @sink(ptr %dst, ptr %es_2)440 441; Do not transform stpncpy(D, S, N). Both D and S must be nonnull but442; neither *D nor *S need be dereferenceable.443; TODO: Both D and S should be annotated nonnull and noundef regardless444; of the value of N. See https://reviews.llvm.org/D124633.445 %es_n = call ptr @stpncpy(ptr %dst, ptr %src, i64 %n)446 call void @sink(ptr %dst, ptr %es_n)447 448 ret void449}450;.451; BE: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nounwind willreturn memory(argmem: write) }452; BE: attributes #[[ATTR1:[0-9]+]] = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }453;.454; LE: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nounwind willreturn memory(argmem: write) }455; LE: attributes #[[ATTR1:[0-9]+]] = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }456;.457