1; RUN: llc < %s -mtriple=arm64-eabi -mattr=+mte | FileCheck %s
2
3; test create_tag
4define i32* @create_tag(i32* %ptr, i32 %m) {
5entry:
6; CHECK-LABEL: create_tag:
7  %0 = bitcast i32* %ptr to i8*
8  %1 = zext i32 %m to i64
9  %2 = tail call i8* @llvm.aarch64.irg(i8* %0, i64 %1)
10  %3 = bitcast i8* %2 to i32*
11  ret i32* %3
12;CHECK: irg x0, x0, {{x[0-9]+}}
13}
14
15; *********** __arm_mte_increment_tag  *************
16; test increment_tag1
17define i32* @increment_tag1(i32* %ptr) {
18entry:
19; CHECK-LABEL: increment_tag1:
20  %0 = bitcast i32* %ptr to i8*
21  %1 = tail call i8* @llvm.aarch64.addg(i8* %0, i64 7)
22  %2 = bitcast i8* %1 to i32*
23  ret i32* %2
24; CHECK: addg x0, x0, #0, #7
25}
26
27%struct.S2K = type { [512 x i32] }
28define i32* @increment_tag1stack(i32* %ptr) {
29entry:
30; CHECK-LABEL: increment_tag1stack:
31  %s = alloca %struct.S2K, align 4
32  %0 = bitcast %struct.S2K* %s to i8*
33  call void @llvm.lifetime.start.p0i8(i64 2048, i8* nonnull %0)
34  %1 = call i8* @llvm.aarch64.addg(i8* nonnull %0, i64 7)
35  %2 = bitcast i8* %1 to i32*
36  call void @llvm.lifetime.end.p0i8(i64 2048, i8* nonnull %0)
37  ret i32* %2
38; CHECK: addg x0, sp, #0, #7
39}
40
41
42define i32* @increment_tag2(i32* %ptr) {
43entry:
44; CHECK-LABEL: increment_tag2:
45  %add.ptr = getelementptr inbounds i32, i32* %ptr, i64 4
46  %0 = bitcast i32* %add.ptr to i8*
47  %1 = tail call i8* @llvm.aarch64.addg(i8* nonnull %0, i64 7)
48  %2 = bitcast i8* %1 to i32*
49  ret i32* %2
50; CHECK: addg x0, x0, #16, #7
51}
52
53define i32* @increment_tag2stack(i32* %ptr) {
54entry:
55; CHECK-LABEL: increment_tag2stack:
56  %s = alloca %struct.S2K, align 4
57  %0 = bitcast %struct.S2K* %s to i8*
58  call void @llvm.lifetime.start.p0i8(i64 2048, i8* nonnull %0)
59  %arrayidx = getelementptr inbounds %struct.S2K, %struct.S2K* %s, i64 0, i32 0, i64 4
60  %1 = bitcast i32* %arrayidx to i8*
61  %2 = call i8* @llvm.aarch64.addg(i8* nonnull %1, i64 7)
62  %3 = bitcast i8* %2 to i32*
63  call void @llvm.lifetime.end.p0i8(i64 2048, i8* nonnull %0)
64  ret i32* %3
65; CHECK: addg x0, sp, #16, #7
66}
67
68define i32* @increment_tag3(i32* %ptr) {
69entry:
70; CHECK-LABEL: increment_tag3:
71  %add.ptr = getelementptr inbounds i32, i32* %ptr, i64 252
72  %0 = bitcast i32* %add.ptr to i8*
73  %1 = tail call i8* @llvm.aarch64.addg(i8* nonnull %0, i64 7)
74  %2 = bitcast i8* %1 to i32*
75  ret i32* %2
76; CHECK: addg x0, x0, #1008, #7
77}
78
79define i32* @increment_tag3stack(i32* %ptr) {
80entry:
81; CHECK-LABEL: increment_tag3stack:
82  %s = alloca %struct.S2K, align 4
83  %0 = bitcast %struct.S2K* %s to i8*
84  call void @llvm.lifetime.start.p0i8(i64 2048, i8* nonnull %0)
85  %arrayidx = getelementptr inbounds %struct.S2K, %struct.S2K* %s, i64 0, i32 0, i64 252
86  %1 = bitcast i32* %arrayidx to i8*
87  %2 = call i8* @llvm.aarch64.addg(i8* nonnull %1, i64 7)
88  %3 = bitcast i8* %2 to i32*
89  call void @llvm.lifetime.end.p0i8(i64 2048, i8* nonnull %0)
90  ret i32* %3
91; CHECK: addg x0, sp, #1008, #7
92}
93
94
95define i32* @increment_tag4(i32* %ptr) {
96entry:
97; CHECK-LABEL: increment_tag4:
98  %add.ptr = getelementptr inbounds i32, i32* %ptr, i64 256
99  %0 = bitcast i32* %add.ptr to i8*
100  %1 = tail call i8* @llvm.aarch64.addg(i8* nonnull %0, i64 7)
101  %2 = bitcast i8* %1 to i32*
102  ret i32* %2
103; CHECK: add [[T0:x[0-9]+]], x0, #1024
104; CHECK-NEXT: addg x0, [[T0]], #0, #7
105}
106
107define i32* @increment_tag4stack(i32* %ptr) {
108entry:
109; CHECK-LABEL: increment_tag4stack:
110  %s = alloca %struct.S2K, align 4
111  %0 = bitcast %struct.S2K* %s to i8*
112  call void @llvm.lifetime.start.p0i8(i64 2048, i8* nonnull %0)
113  %arrayidx = getelementptr inbounds %struct.S2K, %struct.S2K* %s, i64 0, i32 0, i64 256
114  %1 = bitcast i32* %arrayidx to i8*
115  %2 = call i8* @llvm.aarch64.addg(i8* nonnull %1, i64 7)
116  %3 = bitcast i8* %2 to i32*
117  call void @llvm.lifetime.end.p0i8(i64 2048, i8* nonnull %0)
118  ret i32* %3
119; CHECK: add [[T0:x[0-9]+]], {{.*}}, #1024
120; CHECK-NEXT: addg x0, [[T0]], #0, #7
121}
122
123
124define i32* @increment_tag5(i32* %ptr) {
125entry:
126; CHECK-LABEL: increment_tag5:
127  %add.ptr = getelementptr inbounds i32, i32* %ptr, i64 5
128  %0 = bitcast i32* %add.ptr to i8*
129  %1 = tail call i8* @llvm.aarch64.addg(i8* nonnull %0, i64 7)
130  %2 = bitcast i8* %1 to i32*
131  ret i32* %2
132; CHECK: add [[T0:x[0-9]+]], x0, #20
133; CHECK-NEXT: addg x0, [[T0]], #0, #7
134}
135
136define i32* @increment_tag5stack(i32* %ptr) {
137entry:
138; CHECK-LABEL: increment_tag5stack:
139  %s = alloca %struct.S2K, align 4
140  %0 = bitcast %struct.S2K* %s to i8*
141  call void @llvm.lifetime.start.p0i8(i64 2048, i8* nonnull %0)
142  %arrayidx = getelementptr inbounds %struct.S2K, %struct.S2K* %s, i64 0, i32 0, i64 5
143  %1 = bitcast i32* %arrayidx to i8*
144  %2 = call i8* @llvm.aarch64.addg(i8* nonnull %1, i64 7)
145  %3 = bitcast i8* %2 to i32*
146  call void @llvm.lifetime.end.p0i8(i64 2048, i8* nonnull %0)
147  ret i32* %3
148; CHECK: add [[T0:x[0-9]+]], {{.*}}, #20
149; CHECK-NEXT: addg x0, [[T0]], #0, #7
150}
151
152
153; *********** __arm_mte_exclude_tag  *************
154; test exclude_tag
155define i32 @exclude_tag(i32* %ptr, i32 %m) local_unnamed_addr #0 {
156entry:
157;CHECK-LABEL: exclude_tag:
158  %0 = zext i32 %m to i64
159  %1 = bitcast i32* %ptr to i8*
160  %2 = tail call i64 @llvm.aarch64.gmi(i8* %1, i64 %0)
161  %conv = trunc i64 %2 to i32
162  ret i32 %conv
163; CHECK: gmi	x0, x0, {{x[0-9]+}}
164}
165
166
167; *********** __arm_mte_get_tag *************
168%struct.S8K = type { [2048 x i32] }
169define i32* @get_tag1(i32* %ptr) {
170entry:
171; CHECK-LABEL: get_tag1:
172  %0 = bitcast i32* %ptr to i8*
173  %1 = tail call i8* @llvm.aarch64.ldg(i8* %0, i8* %0)
174  %2 = bitcast i8* %1 to i32*
175  ret i32* %2
176; CHECK: ldg x0, [x0]
177}
178
179define i32* @get_tag1_two_parm(i32* %ret_ptr, i32* %ptr) {
180entry:
181; CHECK-LABEL: get_tag1_two_parm:
182  %0 = bitcast i32* %ret_ptr to i8*
183  %1 = bitcast i32* %ptr to i8*
184  %2 = tail call i8* @llvm.aarch64.ldg(i8* %0, i8* %1)
185  %3 = bitcast i8* %2 to i32*
186  ret i32* %3
187; CHECK: ldg x0, [x1]
188}
189
190define i32* @get_tag1stack() {
191entry:
192; CHECK-LABEL: get_tag1stack:
193  %s = alloca %struct.S8K, align 4
194  %0 = bitcast %struct.S8K* %s to i8*
195  call void @llvm.lifetime.start.p0i8(i64 8192, i8* nonnull %0)
196  %1 = call i8* @llvm.aarch64.ldg(i8* nonnull %0, i8* nonnull %0)
197  %2 = bitcast i8* %1 to i32*
198  call void @llvm.lifetime.end.p0i8(i64 8192, i8* nonnull %0)
199  ret i32* %2
200; CHECK: mov [[T0:x[0-9]+]], sp
201; CHECK: ldg [[T0]], [sp]
202}
203
204define i32* @get_tag1stack_two_param(i32* %ret_ptr) {
205entry:
206; CHECK-LABEL: get_tag1stack_two_param:
207  %s = alloca %struct.S8K, align 4
208  %0 = bitcast %struct.S8K* %s to i8*
209  %1 = bitcast i32*  %ret_ptr to i8*
210  call void @llvm.lifetime.start.p0i8(i64 8192, i8* nonnull %0)
211  %2 = call i8* @llvm.aarch64.ldg(i8* nonnull %1, i8* nonnull %0)
212  %3 = bitcast i8* %2 to i32*
213  call void @llvm.lifetime.end.p0i8(i64 8192, i8* nonnull %0)
214  ret i32* %3
215; CHECK-NOT: mov {{.*}}, sp
216; CHECK: ldg x0, [sp]
217}
218
219
220define i32* @get_tag2(i32* %ptr) {
221entry:
222; CHECK-LABEL: get_tag2:
223  %add.ptr = getelementptr inbounds i32, i32* %ptr, i64 4
224  %0 = bitcast i32* %add.ptr to i8*
225  %1 = tail call i8* @llvm.aarch64.ldg(i8* nonnull %0, i8* nonnull %0)
226  %2 = bitcast i8* %1 to i32*
227  ret i32* %2
228; CHECK: add  [[T0:x[0-9]+]], x0, #16
229; CHECK: ldg  [[T0]], [x0, #16]
230}
231
232define i32* @get_tag2stack() {
233entry:
234; CHECK-LABEL: get_tag2stack:
235  %s = alloca %struct.S8K, align 4
236  %0 = bitcast %struct.S8K* %s to i8*
237  call void @llvm.lifetime.start.p0i8(i64 8192, i8* nonnull %0)
238  %arrayidx = getelementptr inbounds %struct.S8K, %struct.S8K* %s, i64 0, i32 0, i64 4
239  %1 = bitcast i32* %arrayidx to i8*
240  %2 = call i8* @llvm.aarch64.ldg(i8* nonnull %1, i8* nonnull %1)
241  %3 = bitcast i8* %2 to i32*
242  call void @llvm.lifetime.end.p0i8(i64 8192, i8* nonnull %0)
243  ret i32* %3
244; CHECK: mov [[T0:x[0-9]+]], sp
245; CHECK: add x0, [[T0]], #16
246; CHECK: ldg x0, [sp, #16]
247}
248
249
250define i32* @get_tag3(i32* %ptr) {
251entry:
252; CHECK-LABEL: get_tag3:
253  %add.ptr = getelementptr inbounds i32, i32* %ptr, i64 1020
254  %0 = bitcast i32* %add.ptr to i8*
255  %1 = tail call i8* @llvm.aarch64.ldg(i8* nonnull %0, i8* nonnull %0)
256  %2 = bitcast i8* %1 to i32*
257  ret i32* %2
258; CHECK: add [[T0:x[0-8]+]], x0, #4080
259; CHECK: ldg [[T0]], [x0, #4080]
260}
261
262define i32* @get_tag3stack() {
263entry:
264; CHECK-LABEL: get_tag3stack:
265  %s = alloca %struct.S8K, align 4
266  %0 = bitcast %struct.S8K* %s to i8*
267  call void @llvm.lifetime.start.p0i8(i64 8192, i8* nonnull %0)
268  %arrayidx = getelementptr inbounds %struct.S8K, %struct.S8K* %s, i64 0, i32 0, i64 1020
269  %1 = bitcast i32* %arrayidx to i8*
270  %2 = call i8* @llvm.aarch64.ldg(i8* nonnull %1, i8* nonnull %1)
271  %3 = bitcast i8* %2 to i32*
272  call void @llvm.lifetime.end.p0i8(i64 8192, i8* nonnull %0)
273  ret i32* %3
274; CHECK: mov [[T0:x[0-9]+]], sp
275; CHECK: add x0, [[T0]], #4080
276; CHECK: ldg x0, [sp, #4080]
277}
278
279
280define i32* @get_tag4(i32* %ptr) {
281entry:
282; CHECK-LABEL: get_tag4:
283  %add.ptr = getelementptr inbounds i32, i32* %ptr, i64 1024
284  %0 = bitcast i32* %add.ptr to i8*
285  %1 = tail call i8* @llvm.aarch64.ldg(i8* nonnull %0, i8* nonnull %0)
286  %2 = bitcast i8* %1 to i32*
287  ret i32* %2
288; CHECK: add x0, x0, #1, lsl #12
289; CHECK-NEXT: ldg x0, [x0]
290}
291
292define i32* @get_tag4stack() {
293entry:
294; CHECK-LABEL: get_tag4stack:
295  %s = alloca %struct.S8K, align 4
296  %0 = bitcast %struct.S8K* %s to i8*
297  call void @llvm.lifetime.start.p0i8(i64 8192, i8* nonnull %0)
298  %arrayidx = getelementptr inbounds %struct.S8K, %struct.S8K* %s, i64 0, i32 0, i64 1024
299  %1 = bitcast i32* %arrayidx to i8*
300  %2 = call i8* @llvm.aarch64.ldg(i8* nonnull %1, i8* nonnull %1)
301  %3 = bitcast i8* %2 to i32*
302  call void @llvm.lifetime.end.p0i8(i64 8192, i8* nonnull %0)
303  ret i32* %3
304; CHECK: mov [[T0:x[0-9]+]], sp
305; CHECK-NEXT: add x[[T1:[0-9]+]], [[T0]], #1, lsl #12
306; CHECK-NEXT: ldg x[[T1]], [x[[T1]]]
307}
308
309define i32* @get_tag5(i32* %ptr) {
310entry:
311; CHECK-LABEL: get_tag5:
312  %add.ptr = getelementptr inbounds i32, i32* %ptr, i64 5
313  %0 = bitcast i32* %add.ptr to i8*
314  %1 = tail call i8* @llvm.aarch64.ldg(i8* nonnull %0, i8* nonnull %0)
315  %2 = bitcast i8* %1 to i32*
316  ret i32* %2
317; CHECK: add x0, x0, #20
318; CHECK-NEXT: ldg x0, [x0]
319}
320
321define i32* @get_tag5stack() {
322entry:
323; CHECK-LABEL: get_tag5stack:
324  %s = alloca %struct.S8K, align 4
325  %0 = bitcast %struct.S8K* %s to i8*
326  call void @llvm.lifetime.start.p0i8(i64 8192, i8* nonnull %0)
327  %arrayidx = getelementptr inbounds %struct.S8K, %struct.S8K* %s, i64 0, i32 0, i64 5
328  %1 = bitcast i32* %arrayidx to i8*
329  %2 = call i8* @llvm.aarch64.ldg(i8* nonnull %1, i8* nonnull %1)
330  %3 = bitcast i8* %2 to i32*
331  call void @llvm.lifetime.end.p0i8(i64 8192, i8* nonnull %0)
332  ret i32* %3
333; CHECK: mov [[T0:x[0-9]+]], sp
334; CHECK: add x[[T1:[0-9]+]], [[T0]], #20
335; CHECK-NEXT: ldg x[[T1]], [x[[T1]]]
336}
337
338
339; *********** __arm_mte_set_tag  *************
340define void @set_tag1(i32* %tag, i32* %ptr) {
341entry:
342; CHECK-LABEL: set_tag1:
343  %0 = bitcast i32* %tag to i8*
344  %1 = bitcast i32* %ptr to i8*
345  tail call void @llvm.aarch64.stg(i8* %0, i8* %1)
346  ret void
347; CHECK: stg x0, [x1]
348}
349
350define void @set_tag1stack(i32* %tag) {
351entry:
352; CHECK-LABEL: set_tag1stack:
353  %s = alloca %struct.S8K, align 4
354  %0 = bitcast i32* %tag to i8*
355  %1 = bitcast %struct.S8K* %s to i8*
356  call void @llvm.lifetime.start.p0i8(i64 8192, i8* nonnull %1)
357  call void @llvm.aarch64.stg(i8* %0, i8* nonnull %1)
358  call void @llvm.lifetime.end.p0i8(i64 8192, i8* nonnull %0)
359  ret void
360; CHECK: stg x0, [sp]
361}
362
363
364define void @set_tag2(i32* %tag, i32* %ptr) {
365entry:
366; CHECK-LABEL: set_tag2:
367  %add.ptr = getelementptr inbounds i32, i32* %ptr, i64 4
368  %0 = bitcast i32* %tag to i8*
369  %1 = bitcast i32* %add.ptr to i8*
370  tail call void @llvm.aarch64.stg(i8* %0, i8* %1)
371  ret void
372; CHECK: stg x0, [x1, #16]
373}
374
375define void @set_tag2stack(i32* %tag, i32* %ptr) {
376entry:
377; CHECK-LABEL: set_tag2stack:
378  %s = alloca %struct.S8K, align 4
379  %0 = bitcast %struct.S8K* %s to i8*
380  call void @llvm.lifetime.start.p0i8(i64 8192, i8* nonnull %0)
381  %arrayidx = getelementptr inbounds %struct.S8K, %struct.S8K* %s, i64 0, i32 0, i64 4
382  %1 = bitcast i32* %arrayidx to i8*
383  %2 = bitcast i32* %tag to i8*
384  call void @llvm.aarch64.stg(i8* %2, i8* nonnull %1)
385  call void @llvm.lifetime.end.p0i8(i64 8192, i8* nonnull %0)
386  ret void
387; CHECK: stg x0, [sp, #16]
388}
389
390
391
392define void @set_tag3(i32* %tag, i32* %ptr) {
393entry:
394; CHECK-LABEL: set_tag3:
395  %add.ptr = getelementptr inbounds i32, i32* %ptr, i64 1020
396  %0 = bitcast i32* %add.ptr to i8*
397  %1 = bitcast i32* %tag to i8*
398  tail call void @llvm.aarch64.stg(i8* %1, i8* %0)
399  ret void
400; CHECK: stg x0, [x1, #4080]
401}
402
403define void @set_tag3stack(i32* %tag, i32* %ptr) {
404entry:
405; CHECK-LABEL: set_tag3stack:
406  %s = alloca %struct.S8K, align 4
407  %0 = bitcast %struct.S8K* %s to i8*
408  call void @llvm.lifetime.start.p0i8(i64 8192, i8* nonnull %0)
409  %arrayidx = getelementptr inbounds %struct.S8K, %struct.S8K* %s, i64 0, i32 0, i64 1020
410  %1 = bitcast i32* %arrayidx to i8*
411  %2 = bitcast i32* %tag to i8*
412  call void @llvm.aarch64.stg(i8* %2, i8* nonnull %1)
413  call void @llvm.lifetime.end.p0i8(i64 8192, i8* nonnull %0)
414  ret void
415; CHECK: stg x0, [sp, #4080]
416}
417
418
419
420define void @set_tag4(i32* %tag, i32* %ptr) {
421entry:
422; CHECK-LABEL: set_tag4:
423  %add.ptr = getelementptr inbounds i32, i32* %ptr, i64 1024
424  %0 = bitcast i32* %add.ptr to i8*
425  %1 = bitcast i32* %tag to i8*
426  tail call void @llvm.aarch64.stg(i8* %1, i8* %0)
427  ret void
428; CHECK: add x[[T0:[0-9]+]], x1, #1, lsl #12
429; CHECK-NEXT: stg x0, [x[[T0]]]
430}
431
432define void @set_tag4stack(i32* %tag, i32* %ptr) {
433entry:
434; CHECK-LABEL: set_tag4stack:
435  %s = alloca %struct.S8K, align 4
436  %0 = bitcast %struct.S8K* %s to i8*
437  call void @llvm.lifetime.start.p0i8(i64 8192, i8* nonnull %0)
438  %arrayidx = getelementptr inbounds %struct.S8K, %struct.S8K* %s, i64 0, i32 0, i64 1024
439  %1 = bitcast i32* %arrayidx to i8*
440  %2 = bitcast i32* %tag to i8*
441  call void @llvm.aarch64.stg(i8* %2, i8* nonnull %1)
442  call void @llvm.lifetime.end.p0i8(i64 8192, i8* nonnull %0)
443  ret void
444; CHECK: add x[[T0:[0-9]+]], {{.*}}, #1, lsl #12
445; CHECK-NEXT: stg x0, [x[[T0]]]
446}
447
448
449define void @set_tag5(i32* %tag, i32* %ptr) {
450entry:
451; CHECK-LABEL: set_tag5:
452  %add.ptr = getelementptr inbounds i32, i32* %ptr, i64 5
453  %0 = bitcast i32* %add.ptr to i8*
454  %1 = bitcast i32* %tag to i8*
455  tail call void @llvm.aarch64.stg(i8* %1, i8* %0)
456  ret void
457; CHECK: add x[[T0:[0-9]+]], x1, #20
458; CHECK-NEXT: stg x0, [x[[T0]]]
459}
460
461define void @set_tag5stack(i32* %tag, i32* %ptr) {
462entry:
463; CHECK-LABEL: set_tag5stack:
464  %s = alloca %struct.S8K, align 4
465  %0 = bitcast %struct.S8K* %s to i8*
466  call void @llvm.lifetime.start.p0i8(i64 8192, i8* nonnull %0)
467  %arrayidx = getelementptr inbounds %struct.S8K, %struct.S8K* %s, i64 0, i32 0, i64 5
468  %1 = bitcast i32* %arrayidx to i8*
469  %2 = bitcast i32* %tag to i8*
470  call void @llvm.aarch64.stg(i8* %2, i8* nonnull %1)
471  call void @llvm.lifetime.end.p0i8(i64 8192, i8* nonnull %0)
472  ret void
473; CHECK: add x[[T0:[0-9]+]], {{.*}}, #20
474; CHECK-NEXT: stg x0, [x[[T0]]]
475}
476
477
478; *********** __arm_mte_ptrdiff  *************
479define i64 @subtract_pointers(i32* %ptra, i32* %ptrb) {
480entry:
481; CHECK-LABEL: subtract_pointers:
482  %0 = bitcast i32* %ptra to i8*
483  %1 = bitcast i32* %ptrb to i8*
484  %2 = tail call i64 @llvm.aarch64.subp(i8* %0, i8* %1)
485  ret i64 %2
486; CHECK: subp x0, x0, x1
487}
488
489declare i8* @llvm.aarch64.irg(i8*, i64)
490declare i8* @llvm.aarch64.addg(i8*, i64)
491declare i64 @llvm.aarch64.gmi(i8*, i64)
492declare i8* @llvm.aarch64.ldg(i8*, i8*)
493declare void @llvm.aarch64.stg(i8*, i8*)
494declare i64 @llvm.aarch64.subp(i8*, i8*)
495
496declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture)
497declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture)
498