xref: /llvm-project/llvm/test/Transforms/InstCombine/strlcpy-1.ll (revision f226cabbb1b9737676536bc4417336bef4808992)
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