xref: /llvm-project/llvm/test/Transforms/FunctionAttrs/writeonly.ll (revision 29441e4f5fa5f5c7709f7cf180815ba97f611297)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes
2; RUN: opt -passes=function-attrs -S < %s | FileCheck --check-prefixes=COMMON,FNATTRS %s
3; RUN: opt -passes=attributor-light -S < %s | FileCheck --check-prefixes=COMMON,ATTRIBUTOR %s
4
5define void @nouses-argworn-funrn(ptr writeonly %.aaa) {
6; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
7; FNATTRS-LABEL: define {{[^@]+}}@nouses-argworn-funrn
8; FNATTRS-SAME: (ptr readnone captures(none) [[DOTAAA:%.*]]) #[[ATTR0:[0-9]+]] {
9; FNATTRS-NEXT:  nouses-argworn-funrn_entry:
10; FNATTRS-NEXT:    ret void
11;
12; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
13; ATTRIBUTOR-LABEL: define {{[^@]+}}@nouses-argworn-funrn
14; ATTRIBUTOR-SAME: (ptr nofree readnone captures(none) [[DOTAAA:%.*]]) #[[ATTR0:[0-9]+]] {
15; ATTRIBUTOR-NEXT:  nouses-argworn-funrn_entry:
16; ATTRIBUTOR-NEXT:    ret void
17;
18nouses-argworn-funrn_entry:
19  ret void
20}
21
22define void @nouses-argworn-funro(ptr writeonly %.aaa, ptr %.bbb) {
23; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
24; FNATTRS-LABEL: define {{[^@]+}}@nouses-argworn-funro
25; FNATTRS-SAME: (ptr readnone captures(none) [[DOTAAA:%.*]], ptr readonly captures(none) [[DOTBBB:%.*]]) #[[ATTR1:[0-9]+]] {
26; FNATTRS-NEXT:  nouses-argworn-funro_entry:
27; FNATTRS-NEXT:    [[VAL:%.*]] = load i32, ptr [[DOTBBB]], align 4
28; FNATTRS-NEXT:    ret void
29;
30; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
31; ATTRIBUTOR-LABEL: define {{[^@]+}}@nouses-argworn-funro
32; ATTRIBUTOR-SAME: (ptr nofree readnone captures(none) [[DOTAAA:%.*]], ptr nofree nonnull readonly captures(none) [[DOTBBB:%.*]]) #[[ATTR1:[0-9]+]] {
33; ATTRIBUTOR-NEXT:  nouses-argworn-funro_entry:
34; ATTRIBUTOR-NEXT:    [[VAL:%.*]] = load i32, ptr [[DOTBBB]], align 4
35; ATTRIBUTOR-NEXT:    ret void
36;
37nouses-argworn-funro_entry:
38  %val = load i32 , ptr %.bbb
39  ret void
40}
41
42%_type_of_d-ccc = type <{ ptr, i8, i8, i8, i8 }>
43
44@d-ccc = internal global %_type_of_d-ccc <{ ptr null, i8 1, i8 13, i8 0, i8 -127 }>, align 8
45
46define void @nouses-argworn-funwo(ptr writeonly %.aaa) {
47; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write, argmem: none, inaccessiblemem: none)
48; FNATTRS-LABEL: define {{[^@]+}}@nouses-argworn-funwo
49; FNATTRS-SAME: (ptr readnone captures(none) [[DOTAAA:%.*]]) #[[ATTR2:[0-9]+]] {
50; FNATTRS-NEXT:  nouses-argworn-funwo_entry:
51; FNATTRS-NEXT:    store i8 0, ptr getelementptr inbounds ([[_TYPE_OF_D_CCC:%.*]], ptr @d-ccc, i32 0, i32 3), align 1
52; FNATTRS-NEXT:    ret void
53;
54; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write)
55; ATTRIBUTOR-LABEL: define {{[^@]+}}@nouses-argworn-funwo
56; ATTRIBUTOR-SAME: (ptr nofree readnone captures(none) [[DOTAAA:%.*]]) #[[ATTR2:[0-9]+]] {
57; ATTRIBUTOR-NEXT:  nouses-argworn-funwo_entry:
58; ATTRIBUTOR-NEXT:    store i8 0, ptr getelementptr inbounds ([[_TYPE_OF_D_CCC:%.*]], ptr @d-ccc, i32 0, i32 3), align 1
59; ATTRIBUTOR-NEXT:    ret void
60;
61nouses-argworn-funwo_entry:
62  store i8 0, ptr getelementptr inbounds (%_type_of_d-ccc, ptr @d-ccc, i32 0, i32 3)
63  ret void
64}
65
66define void @test_store(ptr %p) {
67; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
68; FNATTRS-LABEL: define {{[^@]+}}@test_store
69; FNATTRS-SAME: (ptr writeonly captures(none) initializes((0, 1)) [[P:%.*]]) #[[ATTR3:[0-9]+]] {
70; FNATTRS-NEXT:    store i8 0, ptr [[P]], align 1
71; FNATTRS-NEXT:    ret void
72;
73; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
74; ATTRIBUTOR-LABEL: define {{[^@]+}}@test_store
75; ATTRIBUTOR-SAME: (ptr nofree nonnull writeonly captures(none) [[P:%.*]]) #[[ATTR3:[0-9]+]] {
76; ATTRIBUTOR-NEXT:    store i8 0, ptr [[P]], align 1
77; ATTRIBUTOR-NEXT:    ret void
78;
79  store i8 0, ptr %p
80  ret void
81}
82
83@G = external global ptr
84define i8 @test_store_capture(ptr %p) {
85; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(readwrite, argmem: read, inaccessiblemem: none)
86; FNATTRS-LABEL: define {{[^@]+}}@test_store_capture
87; FNATTRS-SAME: (ptr [[P:%.*]]) #[[ATTR4:[0-9]+]] {
88; FNATTRS-NEXT:    store ptr [[P]], ptr @G, align 8
89; FNATTRS-NEXT:    [[P2:%.*]] = load ptr, ptr @G, align 8
90; FNATTRS-NEXT:    [[V:%.*]] = load i8, ptr [[P2]], align 1
91; FNATTRS-NEXT:    ret i8 [[V]]
92;
93; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn
94; ATTRIBUTOR-LABEL: define {{[^@]+}}@test_store_capture
95; ATTRIBUTOR-SAME: (ptr nofree [[P:%.*]]) #[[ATTR4:[0-9]+]] {
96; ATTRIBUTOR-NEXT:    store ptr [[P]], ptr @G, align 8
97; ATTRIBUTOR-NEXT:    [[P2:%.*]] = load ptr, ptr @G, align 8
98; ATTRIBUTOR-NEXT:    [[V:%.*]] = load i8, ptr [[P2]], align 1
99; ATTRIBUTOR-NEXT:    ret i8 [[V]]
100;
101  store ptr %p, ptr @G
102  %p2 = load ptr, ptr @G
103  %v = load i8, ptr %p2
104  ret i8 %v
105}
106
107define void @test_addressing(ptr %p) {
108; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
109; FNATTRS-LABEL: define {{[^@]+}}@test_addressing
110; FNATTRS-SAME: (ptr writeonly captures(none) initializes((8, 12)) [[P:%.*]]) #[[ATTR3]] {
111; FNATTRS-NEXT:    [[GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
112; FNATTRS-NEXT:    store i32 0, ptr [[GEP]], align 4
113; FNATTRS-NEXT:    ret void
114;
115; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
116; ATTRIBUTOR-LABEL: define {{[^@]+}}@test_addressing
117; ATTRIBUTOR-SAME: (ptr nofree writeonly captures(none) [[P:%.*]]) #[[ATTR3]] {
118; ATTRIBUTOR-NEXT:    [[GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
119; ATTRIBUTOR-NEXT:    store i32 0, ptr [[GEP]], align 4
120; ATTRIBUTOR-NEXT:    ret void
121;
122  %gep = getelementptr i8, ptr %p, i64 8
123  store i32 0, ptr %gep
124  ret void
125}
126
127define void @test_readwrite(ptr %p) {
128; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite)
129; FNATTRS-LABEL: define {{[^@]+}}@test_readwrite
130; FNATTRS-SAME: (ptr captures(none) [[P:%.*]]) #[[ATTR5:[0-9]+]] {
131; FNATTRS-NEXT:    [[V:%.*]] = load i8, ptr [[P]], align 1
132; FNATTRS-NEXT:    store i8 [[V]], ptr [[P]], align 1
133; FNATTRS-NEXT:    ret void
134;
135; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite)
136; ATTRIBUTOR-LABEL: define {{[^@]+}}@test_readwrite
137; ATTRIBUTOR-SAME: (ptr nofree nonnull captures(none) [[P:%.*]]) #[[ATTR5:[0-9]+]] {
138; ATTRIBUTOR-NEXT:    [[V:%.*]] = load i8, ptr [[P]], align 1
139; ATTRIBUTOR-NEXT:    store i8 [[V]], ptr [[P]], align 1
140; ATTRIBUTOR-NEXT:    ret void
141;
142  %v = load i8, ptr %p
143  store i8 %v, ptr %p
144  ret void
145}
146
147define void @test_volatile(ptr %p) {
148; FNATTRS: Function Attrs: nofree norecurse nounwind memory(argmem: readwrite, inaccessiblemem: readwrite)
149; FNATTRS-LABEL: define {{[^@]+}}@test_volatile
150; FNATTRS-SAME: (ptr [[P:%.*]]) #[[ATTR6:[0-9]+]] {
151; FNATTRS-NEXT:    store volatile i8 0, ptr [[P]], align 1
152; FNATTRS-NEXT:    ret void
153;
154; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite)
155; ATTRIBUTOR-LABEL: define {{[^@]+}}@test_volatile
156; ATTRIBUTOR-SAME: (ptr nofree [[P:%.*]]) #[[ATTR6:[0-9]+]] {
157; ATTRIBUTOR-NEXT:    store volatile i8 0, ptr [[P]], align 1
158; ATTRIBUTOR-NEXT:    ret void
159;
160  store volatile i8 0, ptr %p
161  ret void
162}
163
164define void @test_atomicrmw(ptr %p) {
165; FNATTRS: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite)
166; FNATTRS-LABEL: define {{[^@]+}}@test_atomicrmw
167; FNATTRS-SAME: (ptr captures(none) [[P:%.*]]) #[[ATTR7:[0-9]+]] {
168; FNATTRS-NEXT:    [[TMP1:%.*]] = atomicrmw add ptr [[P]], i8 0 seq_cst, align 1
169; FNATTRS-NEXT:    ret void
170;
171; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite)
172; ATTRIBUTOR-LABEL: define {{[^@]+}}@test_atomicrmw
173; ATTRIBUTOR-SAME: (ptr nofree nonnull captures(none) [[P:%.*]]) #[[ATTR6]] {
174; ATTRIBUTOR-NEXT:    [[TMP1:%.*]] = atomicrmw add ptr [[P]], i8 0 seq_cst, align 1
175; ATTRIBUTOR-NEXT:    ret void
176;
177  atomicrmw add ptr %p, i8 0  seq_cst
178  ret void
179}
180
181define void @test_ptrmask(ptr %p) {
182; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
183; FNATTRS-LABEL: define {{[^@]+}}@test_ptrmask
184; FNATTRS-SAME: (ptr writeonly [[P:%.*]]) #[[ATTR3]] {
185; FNATTRS-NEXT:    [[MASK:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P]], i64 -5)
186; FNATTRS-NEXT:    store i8 0, ptr [[MASK]], align 1
187; FNATTRS-NEXT:    ret void
188;
189; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
190; ATTRIBUTOR-LABEL: define {{[^@]+}}@test_ptrmask
191; ATTRIBUTOR-SAME: (ptr nofree writeonly [[P:%.*]]) #[[ATTR3]] {
192; ATTRIBUTOR-NEXT:    [[MASK:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P]], i64 -5) #[[ATTR9:[0-9]+]]
193; ATTRIBUTOR-NEXT:    store i8 0, ptr [[MASK]], align 1
194; ATTRIBUTOR-NEXT:    ret void
195;
196  %mask = call ptr @llvm.ptrmask.p0.i64(ptr %p, i64 -5)
197  store i8 0, ptr %mask
198  ret void
199}
200
201declare ptr @llvm.ptrmask.p0.i64(ptr, i64)
202
203declare void @direct1_callee(ptr %p)
204
205define void @direct1(ptr %p) {
206; COMMON-LABEL: define {{[^@]+}}@direct1
207; COMMON-SAME: (ptr [[P:%.*]]) {
208; COMMON-NEXT:    call void @direct1_callee(ptr [[P]])
209; COMMON-NEXT:    ret void
210;
211  call void @direct1_callee(ptr %p)
212  ret void
213}
214
215declare void @direct2_callee(ptr %p) writeonly
216
217; writeonly w/o nocapture is not enough
218define void @direct2(ptr %p) {
219; FNATTRS: Function Attrs: memory(write)
220; FNATTRS-LABEL: define {{[^@]+}}@direct2
221; FNATTRS-SAME: (ptr [[P:%.*]]) #[[ATTR9:[0-9]+]] {
222; FNATTRS-NEXT:    call void @direct2_callee(ptr [[P]])
223; FNATTRS-NEXT:    ret void
224;
225; ATTRIBUTOR: Function Attrs: memory(write)
226; ATTRIBUTOR-LABEL: define {{[^@]+}}@direct2
227; ATTRIBUTOR-SAME: (ptr writeonly [[P:%.*]]) #[[ATTR8:[0-9]+]] {
228; ATTRIBUTOR-NEXT:    call void @direct2_callee(ptr [[P]]) #[[ATTR8]]
229; ATTRIBUTOR-NEXT:    ret void
230;
231  call void @direct2_callee(ptr %p)
232  ; read back from global, read through pointer...
233  ret void
234}
235
236define void @direct2b(ptr %p) {
237; FNATTRS: Function Attrs: memory(write)
238; FNATTRS-LABEL: define {{[^@]+}}@direct2b
239; FNATTRS-SAME: (ptr writeonly captures(none) [[P:%.*]]) #[[ATTR9]] {
240; FNATTRS-NEXT:    call void @direct2_callee(ptr captures(none) [[P]])
241; FNATTRS-NEXT:    ret void
242;
243; ATTRIBUTOR: Function Attrs: memory(write)
244; ATTRIBUTOR-LABEL: define {{[^@]+}}@direct2b
245; ATTRIBUTOR-SAME: (ptr writeonly captures(none) [[P:%.*]]) #[[ATTR8]] {
246; ATTRIBUTOR-NEXT:    call void @direct2_callee(ptr writeonly captures(none) [[P]]) #[[ATTR8]]
247; ATTRIBUTOR-NEXT:    ret void
248;
249  call void @direct2_callee(ptr nocapture %p)
250  ret void
251}
252
253declare void @direct3_callee(ptr nocapture writeonly %p)
254
255define void @direct3(ptr %p) {
256; FNATTRS-LABEL: define {{[^@]+}}@direct3
257; FNATTRS-SAME: (ptr writeonly captures(none) [[P:%.*]]) {
258; FNATTRS-NEXT:    call void @direct3_callee(ptr [[P]])
259; FNATTRS-NEXT:    ret void
260;
261; ATTRIBUTOR-LABEL: define {{[^@]+}}@direct3
262; ATTRIBUTOR-SAME: (ptr writeonly captures(none) [[P:%.*]]) {
263; ATTRIBUTOR-NEXT:    call void @direct3_callee(ptr writeonly captures(none) [[P]])
264; ATTRIBUTOR-NEXT:    ret void
265;
266  call void @direct3_callee(ptr %p)
267  ret void
268}
269
270define void @direct3b(ptr %p) {
271; COMMON-LABEL: define {{[^@]+}}@direct3b
272; COMMON-SAME: (ptr [[P:%.*]]) {
273; COMMON-NEXT:    call void @direct3_callee(ptr [[P]]) [ "may-read-and-capture"(ptr [[P]]) ]
274; COMMON-NEXT:    ret void
275;
276  call void @direct3_callee(ptr %p) ["may-read-and-capture"(ptr %p)]
277  ret void
278}
279
280define void @direct3c(ptr %p) {
281; FNATTRS-LABEL: define {{[^@]+}}@direct3c
282; FNATTRS-SAME: (ptr captures(none) [[P:%.*]]) {
283; FNATTRS-NEXT:    call void @direct3_callee(ptr [[P]]) [ "may-read"() ]
284; FNATTRS-NEXT:    ret void
285;
286; ATTRIBUTOR-LABEL: define {{[^@]+}}@direct3c
287; ATTRIBUTOR-SAME: (ptr captures(none) [[P:%.*]]) {
288; ATTRIBUTOR-NEXT:    call void @direct3_callee(ptr captures(none) [[P]]) [ "may-read"() ]
289; ATTRIBUTOR-NEXT:    ret void
290;
291  call void @direct3_callee(ptr %p) ["may-read"()]
292  ret void
293}
294
295define void @fptr_test1(ptr %p, ptr %f) {
296; FNATTRS-LABEL: define {{[^@]+}}@fptr_test1
297; FNATTRS-SAME: (ptr [[P:%.*]], ptr readonly captures(none) [[F:%.*]]) {
298; FNATTRS-NEXT:    call void [[F]](ptr [[P]])
299; FNATTRS-NEXT:    ret void
300;
301; ATTRIBUTOR-LABEL: define {{[^@]+}}@fptr_test1
302; ATTRIBUTOR-SAME: (ptr [[P:%.*]], ptr nofree nonnull captures(none) [[F:%.*]]) {
303; ATTRIBUTOR-NEXT:    call void [[F]](ptr [[P]])
304; ATTRIBUTOR-NEXT:    ret void
305;
306  call void %f(ptr %p)
307  ret void
308}
309
310define void @fptr_test2(ptr %p, ptr %f) {
311; FNATTRS-LABEL: define {{[^@]+}}@fptr_test2
312; FNATTRS-SAME: (ptr writeonly captures(none) [[P:%.*]], ptr readonly captures(none) [[F:%.*]]) {
313; FNATTRS-NEXT:    call void [[F]](ptr writeonly captures(none) [[P]])
314; FNATTRS-NEXT:    ret void
315;
316; ATTRIBUTOR-LABEL: define {{[^@]+}}@fptr_test2
317; ATTRIBUTOR-SAME: (ptr captures(none) [[P:%.*]], ptr nofree nonnull captures(none) [[F:%.*]]) {
318; ATTRIBUTOR-NEXT:    call void [[F]](ptr writeonly captures(none) [[P]])
319; ATTRIBUTOR-NEXT:    ret void
320;
321  call void %f(ptr nocapture writeonly %p)
322  ret void
323}
324
325define void @fptr_test3(ptr %p, ptr %f) {
326; FNATTRS: Function Attrs: memory(write)
327; FNATTRS-LABEL: define {{[^@]+}}@fptr_test3
328; FNATTRS-SAME: (ptr writeonly captures(none) [[P:%.*]], ptr readonly captures(none) [[F:%.*]]) #[[ATTR9]] {
329; FNATTRS-NEXT:    call void [[F]](ptr captures(none) [[P]]) #[[ATTR9]]
330; FNATTRS-NEXT:    ret void
331;
332; ATTRIBUTOR: Function Attrs: memory(write)
333; ATTRIBUTOR-LABEL: define {{[^@]+}}@fptr_test3
334; ATTRIBUTOR-SAME: (ptr writeonly captures(none) [[P:%.*]], ptr nofree nonnull writeonly captures(none) [[F:%.*]]) #[[ATTR8]] {
335; ATTRIBUTOR-NEXT:    call void [[F]](ptr captures(none) [[P]]) #[[ATTR8]]
336; ATTRIBUTOR-NEXT:    ret void
337;
338  call void %f(ptr nocapture %p) writeonly
339  ret void
340}
341
342define void @test_argmem_none_callee(ptr %p) {
343; FNATTRS-LABEL: define {{[^@]+}}@test_argmem_none_callee
344; FNATTRS-SAME: (ptr readnone captures(none) [[P:%.*]]) {
345; FNATTRS-NEXT:    call void @direct1_callee(ptr captures(none) [[P]]) #[[ATTR10:[0-9]+]]
346; FNATTRS-NEXT:    ret void
347;
348; ATTRIBUTOR-LABEL: define {{[^@]+}}@test_argmem_none_callee
349; ATTRIBUTOR-SAME: (ptr captures(none) [[P:%.*]]) {
350; ATTRIBUTOR-NEXT:    call void @direct1_callee(ptr captures(none) [[P]]) #[[ATTR10:[0-9]+]]
351; ATTRIBUTOR-NEXT:    ret void
352;
353  call void @direct1_callee(ptr nocapture %p) memory(readwrite, argmem: none)
354  ret void
355}
356
357define void @test_argmem_read_callee(ptr %p) {
358; FNATTRS-LABEL: define {{[^@]+}}@test_argmem_read_callee
359; FNATTRS-SAME: (ptr readonly captures(none) [[P:%.*]]) {
360; FNATTRS-NEXT:    call void @direct1_callee(ptr captures(none) [[P]]) #[[ATTR11:[0-9]+]]
361; FNATTRS-NEXT:    ret void
362;
363; ATTRIBUTOR-LABEL: define {{[^@]+}}@test_argmem_read_callee
364; ATTRIBUTOR-SAME: (ptr captures(none) [[P:%.*]]) {
365; ATTRIBUTOR-NEXT:    call void @direct1_callee(ptr captures(none) [[P]]) #[[ATTR11:[0-9]+]]
366; ATTRIBUTOR-NEXT:    ret void
367;
368  call void @direct1_callee(ptr nocapture %p) memory(readwrite, argmem: read)
369  ret void
370}
371
372define void @test_argmem_write_callee(ptr %p) {
373; FNATTRS-LABEL: define {{[^@]+}}@test_argmem_write_callee
374; FNATTRS-SAME: (ptr writeonly captures(none) [[P:%.*]]) {
375; FNATTRS-NEXT:    call void @direct1_callee(ptr captures(none) [[P]]) #[[ATTR12:[0-9]+]]
376; FNATTRS-NEXT:    ret void
377;
378; ATTRIBUTOR-LABEL: define {{[^@]+}}@test_argmem_write_callee
379; ATTRIBUTOR-SAME: (ptr captures(none) [[P:%.*]]) {
380; ATTRIBUTOR-NEXT:    call void @direct1_callee(ptr captures(none) [[P]]) #[[ATTR12:[0-9]+]]
381; ATTRIBUTOR-NEXT:    ret void
382;
383  call void @direct1_callee(ptr nocapture %p) memory(readwrite, argmem: write)
384  ret void
385}
386