[Support] Recycler: Implement move constructor (#120555)
[llvm-project.git] / llvm / test / Transforms / InstCombine / stpncpy-1.ll
blob87f54918b7d25ed2c23e860e0ab91b10b01dbedc
1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals
3 ; Test that the stpncpy library call simplifier works correctly.
5 ; RUN: opt < %s -data-layout="E" -passes=instcombine -S | FileCheck %s --check-prefixes=ANY,BE
6 ; RUN: opt < %s -data-layout="e" -passes=instcombine -S | FileCheck %s --check-prefixes=ANY,LE
8 declare ptr @stpncpy(ptr, ptr, i64)
10 declare void @sink(ptr, ptr)
12 @a4 = constant [4 x i8] c"1234"
13 @s4 = constant [5 x i8] c"1234\00"
16 ; The following are generated by the stpncpy -> memcpy transformation
17 ; (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 1
22 @str.4 = private unnamed_addr constant [10 x i8] c"4\00\00\00\00\00\00\00\00\00", align 1
23 @str.5 = private unnamed_addr constant [10 x i8] c"1234\00\00\00\00\00\00", align 1
25 ; Verify that the generated constants have the expected contents.
27 ; Verify that exactly overlapping stpncpy(D, D, N) calls are transformed
28 ; to D + strnlen(D, N) or, equivalently, D + (*D != '\0'), when N < 2.
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 1
37 ; ANY: @str.4 = private unnamed_addr constant [10 x i8] c"4\00\00\00\00\00\00\00\00\00", align 1
38 ; ANY: @str.5 = private unnamed_addr constant [10 x i8] c"1234\00\00\00\00\00\00", align 1
39 ; ANY: @str.6 = private unnamed_addr constant [3 x i8] c"4\00\00", align 1
40 ; ANY: @str.7 = private unnamed_addr constant [9 x i8] c"4\00\00\00\00\00\00\00\00", align 1
41 ; ANY: @str.8 = private unnamed_addr constant [9 x i8] c"1234\00\00\00\00\00", align 1
42 ; ANY: @str.9 = private unnamed_addr constant [9 x i8] c"1234\00\00\00\00\00", align 1
44 define 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 1
48 ; ANY-NEXT:    [[STPNCPY_CHAR0CMP:%.*]] = icmp ne i8 [[STXNCPY_CHAR0]], 0
49 ; ANY-NEXT:    [[STPNCPY_SEL_IDX:%.*]] = zext i1 [[STPNCPY_CHAR0CMP]] to i64
50 ; 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 void
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)
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)
62   ret void
66 ; Verify that exactly overlapping stpncpy(D, D, N) calls are left alone
67 ; when N >= 2.  Such calls are strictly undefined and while simplifying
68 ; them to the expected result is possible there is little to gain from it.
70 define 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 [[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 [[DST]], ptr [[ES_3]])
76 ; ANY-NEXT:    [[ES_N:%.*]] = call ptr @stpncpy(ptr [[DST]], ptr [[DST]], i64 [[N:%.*]])
77 ; ANY-NEXT:    call void @sink(ptr [[DST]], ptr [[ES_N]])
78 ; ANY-NEXT:    ret void
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)
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)
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)
92   ret void
96 ; Verify that stpncpy(D, "", N) calls are transformed to memset(D, 0, N).
98 define 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 1
102 ; ANY-NEXT:    call void @sink(ptr nonnull [[DST]], ptr nonnull [[DST]])
103 ; ANY-NEXT:    store i16 0, ptr [[DST]], align 1
104 ; 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 void
111   %ps0 = getelementptr [5 x i8], ptr @s4, i32 0, i32 4
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)
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)
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)
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)
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)
133   ret void
137 ; Verify that stpncpy(D, "4", N) calls are transformed to the equivalent
138 ; of strncpy(D, "4", N) and the result folded to D + (N != 0).
140 define 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 1
144 ; BE-NEXT:    [[STPNCPY_END:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 1
145 ; BE-NEXT:    call void @sink(ptr nonnull [[DST]], ptr nonnull [[STPNCPY_END]])
146 ; BE-NEXT:    store i16 13312, ptr [[DST]], align 1
147 ; BE-NEXT:    [[ENDPTR:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 1
148 ; 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 1
151 ; 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 1
154 ; BE-NEXT:    call void @sink(ptr nonnull [[DST]], ptr nonnull [[ENDPTR2]])
155 ; BE-NEXT:    ret void
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 1
160 ; LE-NEXT:    [[STPNCPY_END:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 1
161 ; LE-NEXT:    call void @sink(ptr nonnull [[DST]], ptr nonnull [[STPNCPY_END]])
162 ; LE-NEXT:    store i16 52, ptr [[DST]], align 1
163 ; LE-NEXT:    [[ENDPTR:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 1
164 ; 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 1
167 ; 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 1
170 ; LE-NEXT:    call void @sink(ptr nonnull [[DST]], ptr nonnull [[ENDPTR2]])
171 ; LE-NEXT:    ret void
173   %ps1 = getelementptr [5 x i8], ptr @s4, i32 0, i32 3
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)
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)
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)
187 ; Transform stpncpy(D, "4", 3) to strncpy(D, "4", 3) + 1, which is then
188 ; 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)
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)
196   ret void
200 ; Verify that stpncpy(D, "1234", N) calls are transformed to the equivalent
201 ; of strncpy(D, "1234", N) and the result folded to D + min(4, N).
203 define 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 1
207 ; BE-NEXT:    [[STPNCPY_END:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 1
208 ; BE-NEXT:    call void @sink(ptr nonnull [[DST]], ptr nonnull [[STPNCPY_END]])
209 ; BE-NEXT:    store i16 12594, ptr [[DST]], align 1
210 ; BE-NEXT:    [[ENDPTR:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 2
211 ; 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 3
214 ; BE-NEXT:    call void @sink(ptr nonnull [[DST]], ptr nonnull [[ENDPTR1]])
215 ; BE-NEXT:    store i32 825373492, ptr [[DST]], align 1
216 ; BE-NEXT:    [[ENDPTR2:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 4
217 ; 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 4
220 ; BE-NEXT:    call void @sink(ptr nonnull [[DST]], ptr nonnull [[ENDPTR3]])
221 ; BE-NEXT:    ret void
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 1
226 ; LE-NEXT:    [[STPNCPY_END:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 1
227 ; LE-NEXT:    call void @sink(ptr nonnull [[DST]], ptr nonnull [[STPNCPY_END]])
228 ; LE-NEXT:    store i16 12849, ptr [[DST]], align 1
229 ; LE-NEXT:    [[ENDPTR:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 2
230 ; 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 3
233 ; LE-NEXT:    call void @sink(ptr nonnull [[DST]], ptr nonnull [[ENDPTR1]])
234 ; LE-NEXT:    store i32 875770417, ptr [[DST]], align 1
235 ; LE-NEXT:    [[ENDPTR2:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 4
236 ; 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 4
239 ; LE-NEXT:    call void @sink(ptr nonnull [[DST]], ptr nonnull [[ENDPTR3]])
240 ; LE-NEXT:    ret void
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)
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)
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)
255 ; Transform stpncpy(D, "1234", 3) to strncpy(D, "1234", 3) + 3
256   %es4_3 = call ptr @stpncpy(ptr %dst, ptr @s4, i64 3)
257   call void @sink(ptr %dst, ptr %es4_3)
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)
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)
267   ret void
271 ; Verify that a call to stpncpy(D, A, N) with a constant source larger
272 ; than one byte is left alone when N is unknown.
274 define 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 void
286 ; Do not transform stpncpy(D, A4 + 3, N) when N is unknown.
287   %pa1 = getelementptr [4 x i8], ptr @a4, i32 0, i32 3
288   %ea1_n = call ptr @stpncpy(ptr %dst, ptr %pa1, i64 %n)
289   call void @sink(ptr %dst, ptr %ea1_n)
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)
295 ; Do not transform stpncpy(D, "4", N) when N is unknown.
296   %ps1 = getelementptr [5 x i8], ptr @s4, i32 0, i32 3
297   %es1_n = call ptr @stpncpy(ptr %dst, ptr %ps1, i64 %n)
298   call void @sink(ptr %dst, ptr %es1_n)
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)
304   ret void
307 ; Verify that stpncpy(D, (char[4]){"1234"}, N) calls with an unterminated
308 ; source array are transformed to the equivalent strncpy call and the result
309 ; folded to D + min(4, N).
311 define 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 1
315 ; BE-NEXT:    [[STPNCPY_END:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 1
316 ; BE-NEXT:    call void @sink(ptr nonnull [[DST]], ptr nonnull [[STPNCPY_END]])
317 ; BE-NEXT:    store i16 12594, ptr [[DST]], align 1
318 ; BE-NEXT:    [[ENDPTR:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 2
319 ; 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 3
322 ; BE-NEXT:    call void @sink(ptr nonnull [[DST]], ptr nonnull [[ENDPTR1]])
323 ; BE-NEXT:    store i32 825373492, ptr [[DST]], align 1
324 ; BE-NEXT:    [[ENDPTR2:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 4
325 ; 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 4
328 ; 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 4
331 ; BE-NEXT:    call void @sink(ptr nonnull [[DST]], ptr nonnull [[ENDPTR4]])
332 ; BE-NEXT:    ret void
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 1
337 ; LE-NEXT:    [[STPNCPY_END:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 1
338 ; LE-NEXT:    call void @sink(ptr nonnull [[DST]], ptr nonnull [[STPNCPY_END]])
339 ; LE-NEXT:    store i16 12849, ptr [[DST]], align 1
340 ; LE-NEXT:    [[ENDPTR:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 2
341 ; 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 3
344 ; LE-NEXT:    call void @sink(ptr nonnull [[DST]], ptr nonnull [[ENDPTR1]])
345 ; LE-NEXT:    store i32 875770417, ptr [[DST]], align 1
346 ; LE-NEXT:    [[ENDPTR2:%.*]] = getelementptr inbounds nuw i8, ptr [[DST]], i64 4
347 ; 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 4
350 ; 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 4
353 ; LE-NEXT:    call void @sink(ptr nonnull [[DST]], ptr nonnull [[ENDPTR4]])
354 ; LE-NEXT:    ret void
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)
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)
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)
370 ; Transform stpncpy(D, A4, 3) to strncpy(D, A4, 3) + 3
371   %ea4_3 = call ptr @stpncpy(ptr %dst, ptr @a4, i64 3)
372   call void @sink(ptr %dst, ptr %ea4_3)
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)
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)
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)
386   ret void
390 ; Verify that stpncpy(D, S, N) calls with N < 2 are transformed to
391 ; the equivalent of strncpy and either folded to D if N == 0 or to
392 ; *D ? D + 1 : D otherwise.
394 define 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 1
398 ; ANY-NEXT:    store i8 [[STXNCPY_CHAR0]], ptr [[DST]], align 1
399 ; ANY-NEXT:    [[STPNCPY_CHAR0CMP:%.*]] = icmp ne i8 [[STXNCPY_CHAR0]], 0
400 ; ANY-NEXT:    [[STPNCPY_SEL_IDX:%.*]] = zext i1 [[STPNCPY_CHAR0CMP]] to i64
401 ; 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 void
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)
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)
413   ret void
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 following
419 ; though it's not clear that it would be a win:
420 ;   P = memccpy(D, S, 0, N)
421 ;   N' = P ? N - (P - D) : 0
422 ;   Q = P ? P : D + N
423 ;   memset(Q, 0, N')
424 ;   Q
425 ; Also verify that the arguments of the call are annotated with the right
426 ; attributes.
428 define 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 [[DST]], ptr [[ES_2]])
432 ; ANY-NEXT:    [[ES_N:%.*]] = call ptr @stpncpy(ptr [[DST]], ptr [[SRC]], i64 [[N:%.*]])
433 ; ANY-NEXT:    call void @sink(ptr [[DST]], ptr [[ES_N]])
434 ; ANY-NEXT:    ret void
436 ; Do not transform stpncpy(D, S, 2).  Both *D and *S must be derefernceable
437 ; 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)
441 ; Do not transform stpncpy(D, S, N).  Both D and S must be nonnull but
442 ; neither *D nor *S need be dereferenceable.
443 ; TODO: Both D and S should be annotated nonnull and noundef regardless
444 ; 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)
448   ret void
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) }
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) }