xref: /llvm-project/llvm/test/Transforms/Attributor/callbacks.ll (revision 29441e4f5fa5f5c7709f7cf180815ba97f611297)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
2; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal  -attributor-annotate-decl-cs  -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
3; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal  -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
4
5target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
6
7; Test 0
8;
9; Make sure we propagate information from the caller to the callback callee but
10; only for arguments that are mapped through the callback metadata. Here, the
11; first two arguments of the call and the callback callee do not correspond to
12; each other but argument 3-5 of the transitive call site in the caller match
13; arguments 2-4 of the callback callee. Here we should see information and value
14; transfer in both directions.
15
16define void @t0_caller(ptr %a) {
17; TUNIT-LABEL: define {{[^@]+}}@t0_caller
18; TUNIT-SAME: (ptr align 256 [[A:%.*]]) {
19; TUNIT-NEXT:  entry:
20; TUNIT-NEXT:    [[B:%.*]] = alloca i32, align 32
21; TUNIT-NEXT:    [[C:%.*]] = alloca ptr, align 64
22; TUNIT-NEXT:    [[PTR:%.*]] = alloca i32, align 128
23; TUNIT-NEXT:    store i32 42, ptr [[B]], align 32
24; TUNIT-NEXT:    store ptr [[B]], ptr [[C]], align 64
25; TUNIT-NEXT:    call void (ptr, ptr, ptr, ...) @t0_callback_broker(ptr noundef align 4294967296 null, ptr noundef nonnull align 128 dereferenceable(4) [[PTR]], ptr noundef nonnull @t0_callback_callee, ptr align 256 [[A]], i64 undef, ptr noalias nofree noundef nonnull readonly align 64 captures(none) dereferenceable(8) [[C]])
26; TUNIT-NEXT:    ret void
27;
28; CGSCC-LABEL: define {{[^@]+}}@t0_caller
29; CGSCC-SAME: (ptr align 256 [[A:%.*]]) {
30; CGSCC-NEXT:  entry:
31; CGSCC-NEXT:    [[B:%.*]] = alloca i32, align 32
32; CGSCC-NEXT:    [[C:%.*]] = alloca ptr, align 64
33; CGSCC-NEXT:    [[PTR:%.*]] = alloca i32, align 128
34; CGSCC-NEXT:    store i32 42, ptr [[B]], align 32
35; CGSCC-NEXT:    store ptr [[B]], ptr [[C]], align 64
36; CGSCC-NEXT:    call void (ptr, ptr, ptr, ...) @t0_callback_broker(ptr noundef align 4294967296 null, ptr noundef nonnull align 128 dereferenceable(4) [[PTR]], ptr noundef nonnull @t0_callback_callee, ptr align 256 [[A]], i64 noundef 99, ptr noalias nofree noundef nonnull readonly align 64 captures(none) dereferenceable(8) [[C]])
37; CGSCC-NEXT:    ret void
38;
39entry:
40  %b = alloca i32, align 32
41  %c = alloca ptr, align 64
42  %ptr = alloca i32, align 128
43  store i32 42, ptr %b, align 4
44  store ptr %b, ptr %c, align 8
45  call void (ptr, ptr, ptr, ...) @t0_callback_broker(ptr null, ptr %ptr, ptr @t0_callback_callee, ptr %a, i64 99, ptr %c)
46  ret void
47}
48
49; Note that the first two arguments are provided by the callback_broker according to the callback in !1 below!
50; The others are annotated with alignment information, amongst others, or even replaced by the constants passed to the call.
51define internal void @t0_callback_callee(ptr %is_not_null, ptr %ptr, ptr %a, i64 %b, ptr %c) {
52;
53; TUNIT-LABEL: define {{[^@]+}}@t0_callback_callee
54; TUNIT-SAME: (ptr nofree noundef nonnull writeonly align 4 captures(none) dereferenceable(4) [[IS_NOT_NULL:%.*]], ptr nofree noundef nonnull readonly align 8 captures(none) dereferenceable(4) [[PTR:%.*]], ptr align 256 [[A:%.*]], i64 [[B:%.*]], ptr noalias nofree noundef nonnull readonly align 64 captures(none) dereferenceable(8) [[C:%.*]]) {
55; TUNIT-NEXT:  entry:
56; TUNIT-NEXT:    [[PTR_VAL:%.*]] = load i32, ptr [[PTR]], align 8
57; TUNIT-NEXT:    store i32 [[PTR_VAL]], ptr [[IS_NOT_NULL]], align 4
58; TUNIT-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[C]], align 64
59; TUNIT-NEXT:    tail call void @t0_check(ptr align 256 [[A]], i64 noundef 99, ptr align 32 [[TMP0]])
60; TUNIT-NEXT:    ret void
61;
62; CGSCC-LABEL: define {{[^@]+}}@t0_callback_callee
63; CGSCC-SAME: (ptr nofree noundef nonnull writeonly align 4 captures(none) dereferenceable(4) [[IS_NOT_NULL:%.*]], ptr nofree noundef nonnull readonly align 8 captures(none) dereferenceable(4) [[PTR:%.*]], ptr align 256 [[A:%.*]], i64 [[B:%.*]], ptr noalias nofree noundef nonnull readonly align 64 captures(none) dereferenceable(8) [[C:%.*]]) {
64; CGSCC-NEXT:  entry:
65; CGSCC-NEXT:    [[PTR_VAL:%.*]] = load i32, ptr [[PTR]], align 8
66; CGSCC-NEXT:    store i32 [[PTR_VAL]], ptr [[IS_NOT_NULL]], align 4
67; CGSCC-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[C]], align 64
68; CGSCC-NEXT:    tail call void @t0_check(ptr align 256 [[A]], i64 noundef 99, ptr [[TMP0]])
69; CGSCC-NEXT:    ret void
70;
71entry:
72  %ptr_val = load i32, ptr %ptr, align 8
73  store i32 %ptr_val, ptr %is_not_null
74  %0 = load ptr, ptr %c, align 8
75  tail call void @t0_check(ptr %a, i64 %b, ptr %0)
76  ret void
77}
78
79declare void @t0_check(ptr align 256, i64, ptr)
80
81declare !callback !0 void @t0_callback_broker(ptr, ptr, ptr, ...)
82
83; Test 1
84;
85; Similar to test 0 but with some additional annotations (noalias/nocapute) to make sure
86; we deduce and propagate noalias and others properly.
87
88define void @t1_caller(ptr noalias %a) {
89;
90; TUNIT-LABEL: define {{[^@]+}}@t1_caller
91; TUNIT-SAME: (ptr noalias align 256 captures(none) [[A:%.*]]) {
92; TUNIT-NEXT:  entry:
93; TUNIT-NEXT:    [[B:%.*]] = alloca i32, align 32
94; TUNIT-NEXT:    [[C:%.*]] = alloca ptr, align 64
95; TUNIT-NEXT:    [[PTR:%.*]] = alloca i32, align 128
96; TUNIT-NEXT:    store i32 42, ptr [[B]], align 32
97; TUNIT-NEXT:    store ptr [[B]], ptr [[C]], align 64
98; TUNIT-NEXT:    call void (ptr, ptr, ptr, ...) @t1_callback_broker(ptr noundef align 4294967296 null, ptr noalias noundef nonnull align 128 captures(none) dereferenceable(4) [[PTR]], ptr noundef nonnull captures(none) @t1_callback_callee, ptr align 256 captures(none) [[A]], i64 undef, ptr noalias nofree noundef nonnull readonly align 64 captures(none) dereferenceable(8) [[C]])
99; TUNIT-NEXT:    ret void
100;
101; CGSCC-LABEL: define {{[^@]+}}@t1_caller
102; CGSCC-SAME: (ptr noalias align 256 captures(none) [[A:%.*]]) {
103; CGSCC-NEXT:  entry:
104; CGSCC-NEXT:    [[B:%.*]] = alloca i32, align 32
105; CGSCC-NEXT:    [[C:%.*]] = alloca ptr, align 64
106; CGSCC-NEXT:    [[PTR:%.*]] = alloca i32, align 128
107; CGSCC-NEXT:    store i32 42, ptr [[B]], align 32
108; CGSCC-NEXT:    store ptr [[B]], ptr [[C]], align 64
109; CGSCC-NEXT:    call void (ptr, ptr, ptr, ...) @t1_callback_broker(ptr noundef align 4294967296 null, ptr noalias noundef nonnull align 128 captures(none) dereferenceable(4) [[PTR]], ptr noundef nonnull captures(none) @t1_callback_callee, ptr align 256 captures(none) [[A]], i64 noundef 99, ptr noalias nofree noundef nonnull readonly align 64 captures(none) dereferenceable(8) [[C]])
110; CGSCC-NEXT:    ret void
111;
112entry:
113  %b = alloca i32, align 32
114  %c = alloca ptr, align 64
115  %ptr = alloca i32, align 128
116  store i32 42, ptr %b, align 4
117  store ptr %b, ptr %c, align 8
118  call void (ptr, ptr, ptr, ...) @t1_callback_broker(ptr null, ptr %ptr, ptr @t1_callback_callee, ptr %a, i64 99, ptr %c)
119  ret void
120}
121
122; Note that the first two arguments are provided by the callback_broker according to the callback in !1 below!
123; The others are annotated with alignment information, amongst others, or even replaced by the constants passed to the call.
124define internal void @t1_callback_callee(ptr %is_not_null, ptr %ptr, ptr %a, i64 %b, ptr %c) {
125;
126; TUNIT: Function Attrs: nosync
127; TUNIT-LABEL: define {{[^@]+}}@t1_callback_callee
128; TUNIT-SAME: (ptr nofree noundef nonnull writeonly align 4 captures(none) dereferenceable(4) [[IS_NOT_NULL:%.*]], ptr nofree noundef nonnull readonly align 8 captures(none) dereferenceable(4) [[PTR:%.*]], ptr align 256 captures(none) [[A:%.*]], i64 [[B:%.*]], ptr noalias nofree noundef nonnull readonly align 64 captures(none) dereferenceable(8) [[C:%.*]]) #[[ATTR0:[0-9]+]] {
129; TUNIT-NEXT:  entry:
130; TUNIT-NEXT:    [[PTR_VAL:%.*]] = load i32, ptr [[PTR]], align 8
131; TUNIT-NEXT:    store i32 [[PTR_VAL]], ptr [[IS_NOT_NULL]], align 4
132; TUNIT-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[C]], align 64
133; TUNIT-NEXT:    tail call void @t1_check(ptr align 256 captures(none) [[A]], i64 noundef 99, ptr align 32 captures(none) [[TMP0]])
134; TUNIT-NEXT:    ret void
135;
136; CGSCC: Function Attrs: nosync
137; CGSCC-LABEL: define {{[^@]+}}@t1_callback_callee
138; CGSCC-SAME: (ptr nofree noundef nonnull writeonly align 4 captures(none) dereferenceable(4) [[IS_NOT_NULL:%.*]], ptr nofree noundef nonnull readonly align 8 captures(none) dereferenceable(4) [[PTR:%.*]], ptr align 256 captures(none) [[A:%.*]], i64 [[B:%.*]], ptr noalias nofree noundef nonnull readonly align 64 captures(none) dereferenceable(8) [[C:%.*]]) #[[ATTR0:[0-9]+]] {
139; CGSCC-NEXT:  entry:
140; CGSCC-NEXT:    [[PTR_VAL:%.*]] = load i32, ptr [[PTR]], align 8
141; CGSCC-NEXT:    store i32 [[PTR_VAL]], ptr [[IS_NOT_NULL]], align 4
142; CGSCC-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[C]], align 64
143; CGSCC-NEXT:    tail call void @t1_check(ptr align 256 captures(none) [[A]], i64 noundef 99, ptr captures(none) [[TMP0]])
144; CGSCC-NEXT:    ret void
145;
146entry:
147  %ptr_val = load i32, ptr %ptr, align 8
148  store i32 %ptr_val, ptr %is_not_null
149  %0 = load ptr, ptr %c, align 8
150  tail call void @t1_check(ptr %a, i64 %b, ptr %0)
151  ret void
152}
153
154declare void @t1_check(ptr nocapture align 256, i64, ptr nocapture) nosync
155
156declare !callback !0 void @t1_callback_broker(ptr nocapture , ptr nocapture , ptr nocapture, ...)
157
158; Test 2
159;
160; Similar to test 1 but checking that the noalias is only placed if potential synchronization through @t2_check is preserved.
161
162define void @t2_caller(ptr noalias %a) {
163; TUNIT-LABEL: define {{[^@]+}}@t2_caller
164; TUNIT-SAME: (ptr noalias align 256 captures(none) [[A:%.*]]) {
165; TUNIT-NEXT:  entry:
166; TUNIT-NEXT:    [[B:%.*]] = alloca i32, align 32
167; TUNIT-NEXT:    [[C:%.*]] = alloca ptr, align 64
168; TUNIT-NEXT:    [[PTR:%.*]] = alloca i32, align 128
169; TUNIT-NEXT:    store i32 42, ptr [[B]], align 32
170; TUNIT-NEXT:    store ptr [[B]], ptr [[C]], align 64
171; TUNIT-NEXT:    call void (ptr, ptr, ptr, ...) @t2_callback_broker(ptr noundef align 4294967296 null, ptr noalias noundef nonnull align 128 captures(none) dereferenceable(4) [[PTR]], ptr noundef nonnull captures(none) @t2_callback_callee, ptr align 256 captures(none) [[A]], i64 undef, ptr noalias nofree noundef nonnull readonly align 64 captures(none) dereferenceable(8) [[C]])
172; TUNIT-NEXT:    ret void
173;
174; CGSCC-LABEL: define {{[^@]+}}@t2_caller
175; CGSCC-SAME: (ptr noalias align 256 captures(none) [[A:%.*]]) {
176; CGSCC-NEXT:  entry:
177; CGSCC-NEXT:    [[B:%.*]] = alloca i32, align 32
178; CGSCC-NEXT:    [[C:%.*]] = alloca ptr, align 64
179; CGSCC-NEXT:    [[PTR:%.*]] = alloca i32, align 128
180; CGSCC-NEXT:    store i32 42, ptr [[B]], align 32
181; CGSCC-NEXT:    store ptr [[B]], ptr [[C]], align 64
182; CGSCC-NEXT:    call void (ptr, ptr, ptr, ...) @t2_callback_broker(ptr noundef align 4294967296 null, ptr noalias noundef nonnull align 128 captures(none) dereferenceable(4) [[PTR]], ptr noundef nonnull captures(none) @t2_callback_callee, ptr align 256 captures(none) [[A]], i64 noundef 99, ptr noalias nofree noundef nonnull readonly align 64 captures(none) dereferenceable(8) [[C]])
183; CGSCC-NEXT:    ret void
184;
185entry:
186  %b = alloca i32, align 32
187  %c = alloca ptr, align 64
188  %ptr = alloca i32, align 128
189  store i32 42, ptr %b, align 4
190  store ptr %b, ptr %c, align 8
191  call void (ptr, ptr, ptr, ...) @t2_callback_broker(ptr null, ptr %ptr, ptr @t2_callback_callee, ptr %a, i64 99, ptr %c)
192  ret void
193}
194
195; Note that the first two arguments are provided by the callback_broker according to the callback in !1 below!
196; The others are annotated with alignment information, amongst others, or even replaced by the constants passed to the call.
197;
198; FIXME: We should derive noalias for %a and add a "fake use" of %a in all potentially synchronizing calls.
199define internal void @t2_callback_callee(ptr %is_not_null, ptr %ptr, ptr %a, i64 %b, ptr %c) {
200;
201; TUNIT-LABEL: define {{[^@]+}}@t2_callback_callee
202; TUNIT-SAME: (ptr nofree noundef nonnull writeonly align 4 captures(none) dereferenceable(4) [[IS_NOT_NULL:%.*]], ptr nofree noundef nonnull readonly align 8 captures(none) dereferenceable(4) [[PTR:%.*]], ptr align 256 captures(none) [[A:%.*]], i64 [[B:%.*]], ptr noalias nofree noundef nonnull readonly align 64 captures(none) dereferenceable(8) [[C:%.*]]) {
203; TUNIT-NEXT:  entry:
204; TUNIT-NEXT:    [[PTR_VAL:%.*]] = load i32, ptr [[PTR]], align 8
205; TUNIT-NEXT:    store i32 [[PTR_VAL]], ptr [[IS_NOT_NULL]], align 4
206; TUNIT-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[C]], align 64
207; TUNIT-NEXT:    tail call void @t2_check(ptr align 256 captures(none) [[A]], i64 noundef 99, ptr align 32 captures(none) [[TMP0]])
208; TUNIT-NEXT:    ret void
209;
210; CGSCC-LABEL: define {{[^@]+}}@t2_callback_callee
211; CGSCC-SAME: (ptr nofree noundef nonnull writeonly align 4 captures(none) dereferenceable(4) [[IS_NOT_NULL:%.*]], ptr nofree noundef nonnull readonly align 8 captures(none) dereferenceable(4) [[PTR:%.*]], ptr align 256 captures(none) [[A:%.*]], i64 [[B:%.*]], ptr noalias nofree noundef nonnull readonly align 64 captures(none) dereferenceable(8) [[C:%.*]]) {
212; CGSCC-NEXT:  entry:
213; CGSCC-NEXT:    [[PTR_VAL:%.*]] = load i32, ptr [[PTR]], align 8
214; CGSCC-NEXT:    store i32 [[PTR_VAL]], ptr [[IS_NOT_NULL]], align 4
215; CGSCC-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[C]], align 64
216; CGSCC-NEXT:    tail call void @t2_check(ptr align 256 captures(none) [[A]], i64 noundef 99, ptr captures(none) [[TMP0]])
217; CGSCC-NEXT:    ret void
218;
219entry:
220  %ptr_val = load i32, ptr %ptr, align 8
221  store i32 %ptr_val, ptr %is_not_null
222  %0 = load ptr, ptr %c, align 8
223  tail call void @t2_check(ptr %a, i64 %b, ptr %0)
224  ret void
225}
226
227declare void @t2_check(ptr nocapture align 256, i64, ptr nocapture)
228
229declare !callback !0 void @t2_callback_broker(ptr nocapture , ptr nocapture , ptr nocapture, ...)
230
231; Test 3
232;
233; Basically test 2 with the casted callback callee used twice.
234
235define void @t3_caller(ptr noalias %a) {
236; TUNIT-LABEL: define {{[^@]+}}@t3_caller
237; TUNIT-SAME: (ptr noalias align 256 captures(none) [[A:%.*]]) {
238; TUNIT-NEXT:  entry:
239; TUNIT-NEXT:    [[B:%.*]] = alloca i32, align 32
240; TUNIT-NEXT:    [[C:%.*]] = alloca ptr, align 64
241; TUNIT-NEXT:    [[PTR:%.*]] = alloca i32, align 128
242; TUNIT-NEXT:    store i32 42, ptr [[B]], align 32
243; TUNIT-NEXT:    store ptr [[B]], ptr [[C]], align 64
244; TUNIT-NEXT:    call void (ptr, ptr, ptr, ...) @t3_callback_broker(ptr noundef align 4294967296 null, ptr noalias noundef nonnull align 128 captures(none) dereferenceable(4) [[PTR]], ptr noundef nonnull captures(none) @t3_callback_callee, ptr align 256 captures(none) [[A]], i64 undef, ptr noalias nofree noundef nonnull readonly align 64 captures(none) dereferenceable(8) [[C]])
245; TUNIT-NEXT:    call void (ptr, ptr, ptr, ...) @t3_callback_broker(ptr noundef align 4294967296 null, ptr noalias noundef nonnull align 128 captures(none) dereferenceable(4) [[PTR]], ptr noundef nonnull captures(none) @t3_callback_callee, ptr align 256 captures(none) [[A]], i64 undef, ptr noalias nofree noundef nonnull readonly align 64 captures(none) dereferenceable(8) [[C]])
246; TUNIT-NEXT:    ret void
247;
248; CGSCC-LABEL: define {{[^@]+}}@t3_caller
249; CGSCC-SAME: (ptr noalias align 256 captures(none) [[A:%.*]]) {
250; CGSCC-NEXT:  entry:
251; CGSCC-NEXT:    [[B:%.*]] = alloca i32, align 32
252; CGSCC-NEXT:    [[C:%.*]] = alloca ptr, align 64
253; CGSCC-NEXT:    [[PTR:%.*]] = alloca i32, align 128
254; CGSCC-NEXT:    store i32 42, ptr [[B]], align 32
255; CGSCC-NEXT:    store ptr [[B]], ptr [[C]], align 64
256; CGSCC-NEXT:    call void (ptr, ptr, ptr, ...) @t3_callback_broker(ptr noundef align 4294967296 null, ptr noalias noundef nonnull align 128 captures(none) dereferenceable(4) [[PTR]], ptr noundef nonnull captures(none) @t3_callback_callee, ptr align 256 captures(none) [[A]], i64 noundef 99, ptr noalias nofree noundef nonnull readonly align 64 captures(none) dereferenceable(8) [[C]])
257; CGSCC-NEXT:    call void (ptr, ptr, ptr, ...) @t3_callback_broker(ptr noundef align 4294967296 null, ptr noalias noundef nonnull align 128 captures(none) dereferenceable(4) [[PTR]], ptr noundef nonnull captures(none) @t3_callback_callee, ptr align 256 captures(none) [[A]], i64 noundef 99, ptr noalias nofree noundef nonnull readonly align 64 captures(none) dereferenceable(8) [[C]])
258; CGSCC-NEXT:    ret void
259;
260entry:
261  %b = alloca i32, align 32
262  %c = alloca ptr, align 64
263  %ptr = alloca i32, align 128
264  store i32 42, ptr %b, align 4
265  store ptr %b, ptr %c, align 8
266  call void (ptr, ptr, ptr, ...) @t3_callback_broker(ptr null, ptr %ptr, ptr @t3_callback_callee, ptr %a, i64 99, ptr %c)
267  call void (ptr, ptr, ptr, ...) @t3_callback_broker(ptr null, ptr %ptr, ptr @t3_callback_callee, ptr %a, i64 99, ptr %c)
268  ret void
269}
270
271; Note that the first two arguments are provided by the callback_broker according to the callback in !1 below!
272; The others are annotated with alignment information, amongst others, or even replaced by the constants passed to the call.
273;
274; FIXME: We should derive noalias for %a and add a "fake use" of %a in all potentially synchronizing calls.
275define internal void @t3_callback_callee(ptr %is_not_null, ptr %ptr, ptr %a, i64 %b, ptr %c) {
276;
277; TUNIT-LABEL: define {{[^@]+}}@t3_callback_callee
278; TUNIT-SAME: (ptr nofree noundef nonnull writeonly align 4 captures(none) dereferenceable(4) [[IS_NOT_NULL:%.*]], ptr nofree noundef nonnull readonly align 8 captures(none) dereferenceable(4) [[PTR:%.*]], ptr align 256 captures(none) [[A:%.*]], i64 [[B:%.*]], ptr noalias nofree noundef nonnull readonly align 64 captures(none) dereferenceable(8) [[C:%.*]]) {
279; TUNIT-NEXT:  entry:
280; TUNIT-NEXT:    [[PTR_VAL:%.*]] = load i32, ptr [[PTR]], align 8
281; TUNIT-NEXT:    store i32 [[PTR_VAL]], ptr [[IS_NOT_NULL]], align 4
282; TUNIT-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[C]], align 64
283; TUNIT-NEXT:    tail call void @t3_check(ptr align 256 captures(none) [[A]], i64 noundef 99, ptr align 32 captures(none) [[TMP0]])
284; TUNIT-NEXT:    ret void
285;
286; CGSCC-LABEL: define {{[^@]+}}@t3_callback_callee
287; CGSCC-SAME: (ptr nofree noundef nonnull writeonly align 4 captures(none) dereferenceable(4) [[IS_NOT_NULL:%.*]], ptr nofree noundef nonnull readonly align 8 captures(none) dereferenceable(4) [[PTR:%.*]], ptr align 256 captures(none) [[A:%.*]], i64 [[B:%.*]], ptr noalias nofree noundef nonnull readonly align 64 captures(none) dereferenceable(8) [[C:%.*]]) {
288; CGSCC-NEXT:  entry:
289; CGSCC-NEXT:    [[PTR_VAL:%.*]] = load i32, ptr [[PTR]], align 8
290; CGSCC-NEXT:    store i32 [[PTR_VAL]], ptr [[IS_NOT_NULL]], align 4
291; CGSCC-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[C]], align 64
292; CGSCC-NEXT:    tail call void @t3_check(ptr align 256 captures(none) [[A]], i64 noundef 99, ptr captures(none) [[TMP0]])
293; CGSCC-NEXT:    ret void
294;
295entry:
296  %ptr_val = load i32, ptr %ptr, align 8
297  store i32 %ptr_val, ptr %is_not_null
298  %0 = load ptr, ptr %c, align 8
299  tail call void @t3_check(ptr %a, i64 %b, ptr %0)
300  ret void
301}
302
303declare void @t3_check(ptr nocapture align 256, i64, ptr nocapture)
304
305declare !callback !0 void @t3_callback_broker(ptr nocapture , ptr nocapture , ptr nocapture, ...)
306
307!0 = !{!1}
308!1 = !{i64 2, i64 -1, i64 -1, i1 true}
309;.
310; TUNIT: attributes #[[ATTR0]] = { nosync }
311;.
312; CGSCC: attributes #[[ATTR0]] = { nosync }
313;.
314; TUNIT: [[META0:![0-9]+]] = !{[[META1:![0-9]+]]}
315; TUNIT: [[META1]] = !{i64 2, i64 -1, i64 -1, i1 true}
316;.
317; CGSCC: [[META0:![0-9]+]] = !{[[META1:![0-9]+]]}
318; CGSCC: [[META1]] = !{i64 2, i64 -1, i64 -1, i1 true}
319;.
320;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
321; CHECK: {{.*}}
322