1 ; RUN: llc < %s -mtriple=arm64-eabi -mattr=+mte | FileCheck %s
4 define i32* @create_tag(i32* %ptr, i32 %m) {
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*
12 ;CHECK: irg x0, x0, {{x[0-9]+}}
15 ; *********** __arm_mte_increment_tag *************
17 define i32* @increment_tag1(i32* %ptr) {
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*
24 ; CHECK: addg x0, x0, #0, #7
27 %struct.S2K = type { [512 x i32] }
28 define i32* @increment_tag1stack(i32* %ptr) {
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)
38 ; CHECK: addg x0, sp, #0, #7
42 define i32* @increment_tag2(i32* %ptr) {
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*
50 ; CHECK: addg x0, x0, #16, #7
53 define i32* @increment_tag2stack(i32* %ptr) {
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)
65 ; CHECK: addg x0, sp, #16, #7
68 define i32* @increment_tag3(i32* %ptr) {
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*
76 ; CHECK: addg x0, x0, #1008, #7
79 define i32* @increment_tag3stack(i32* %ptr) {
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)
91 ; CHECK: addg x0, sp, #1008, #7
95 define i32* @increment_tag4(i32* %ptr) {
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*
103 ; CHECK: add [[T0:x[0-9]+]], x0, #1024
104 ; CHECK-NEXT: addg x0, [[T0]], #0, #7
107 define i32* @increment_tag4stack(i32* %ptr) {
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)
119 ; CHECK: add [[T0:x[0-9]+]], {{.*}}, #1024
120 ; CHECK-NEXT: addg x0, [[T0]], #0, #7
124 define i32* @increment_tag5(i32* %ptr) {
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*
132 ; CHECK: add [[T0:x[0-9]+]], x0, #20
133 ; CHECK-NEXT: addg x0, [[T0]], #0, #7
136 define i32* @increment_tag5stack(i32* %ptr) {
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)
148 ; CHECK: add [[T0:x[0-9]+]], {{.*}}, #20
149 ; CHECK-NEXT: addg x0, [[T0]], #0, #7
153 ; *********** __arm_mte_exclude_tag *************
155 define i32 @exclude_tag(i32* %ptr, i32 %m) local_unnamed_addr #0 {
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
163 ; CHECK: gmi x0, x0, {{x[0-9]+}}
167 ; *********** __arm_mte_get_tag *************
168 %struct.S8K = type { [2048 x i32] }
169 define i32* @get_tag1(i32* %ptr) {
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*
179 define i32* @get_tag1_two_parm(i32* %ret_ptr, i32* %ptr) {
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*
190 define i32* @get_tag1stack() {
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)
200 ; CHECK: mov [[T0:x[0-9]+]], sp
201 ; CHECK: ldg [[T0]], [sp]
204 define i32* @get_tag1stack_two_param(i32* %ret_ptr) {
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)
215 ; CHECK-NOT: mov {{.*}}, sp
216 ; CHECK: ldg x0, [sp]
220 define i32* @get_tag2(i32* %ptr) {
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*
228 ; CHECK: add [[T0:x[0-9]+]], x0, #16
229 ; CHECK: ldg [[T0]], [x0, #16]
232 define i32* @get_tag2stack() {
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)
244 ; CHECK: mov [[T0:x[0-9]+]], sp
245 ; CHECK: add x0, [[T0]], #16
246 ; CHECK: ldg x0, [sp, #16]
250 define i32* @get_tag3(i32* %ptr) {
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*
258 ; CHECK: add [[T0:x[0-8]+]], x0, #4080
259 ; CHECK: ldg [[T0]], [x0, #4080]
262 define i32* @get_tag3stack() {
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)
274 ; CHECK: mov [[T0:x[0-9]+]], sp
275 ; CHECK: add x0, [[T0]], #4080
276 ; CHECK: ldg x0, [sp, #4080]
280 define i32* @get_tag4(i32* %ptr) {
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*
288 ; CHECK: add x0, x0, #1, lsl #12
289 ; CHECK-NEXT: ldg x0, [x0]
292 define i32* @get_tag4stack() {
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)
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]]]
309 define i32* @get_tag5(i32* %ptr) {
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*
317 ; CHECK: add x0, x0, #20
318 ; CHECK-NEXT: ldg x0, [x0]
321 define i32* @get_tag5stack() {
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)
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]]]
339 ; *********** __arm_mte_set_tag *************
340 define void @set_tag1(i32* %tag, i32* %ptr) {
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)
347 ; CHECK: stg x0, [x1]
350 define void @set_tag1stack(i32* %tag) {
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)
360 ; CHECK: stg x0, [sp]
364 define void @set_tag2(i32* %tag, i32* %ptr) {
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)
372 ; CHECK: stg x0, [x1, #16]
375 define void @set_tag2stack(i32* %tag, i32* %ptr) {
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)
387 ; CHECK: stg x0, [sp, #16]
392 define void @set_tag3(i32* %tag, i32* %ptr) {
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)
400 ; CHECK: stg x0, [x1, #4080]
403 define void @set_tag3stack(i32* %tag, i32* %ptr) {
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)
415 ; CHECK: stg x0, [sp, #4080]
420 define void @set_tag4(i32* %tag, i32* %ptr) {
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)
428 ; CHECK: add x[[T0:[0-9]+]], x1, #1, lsl #12
429 ; CHECK-NEXT: stg x0, [x[[T0]]]
432 define void @set_tag4stack(i32* %tag, i32* %ptr) {
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)
444 ; CHECK: add x[[T0:[0-9]+]], {{.*}}, #1, lsl #12
445 ; CHECK-NEXT: stg x0, [x[[T0]]]
449 define void @set_tag5(i32* %tag, i32* %ptr) {
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)
457 ; CHECK: add x[[T0:[0-9]+]], x1, #20
458 ; CHECK-NEXT: stg x0, [x[[T0]]]
461 define void @set_tag5stack(i32* %tag, i32* %ptr) {
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)
473 ; CHECK: add x[[T0:[0-9]+]], {{.*}}, #20
474 ; CHECK-NEXT: stg x0, [x[[T0]]]
478 ; *********** __arm_mte_ptrdiff *************
479 define i64 @subtract_pointers(i32* %ptra, i32* %ptrb) {
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)
486 ; CHECK: subp x0, x0, x1
489 declare i8* @llvm.aarch64.irg(i8*, i64)
490 declare i8* @llvm.aarch64.addg(i8*, i64)
491 declare i64 @llvm.aarch64.gmi(i8*, i64)
492 declare i8* @llvm.aarch64.ldg(i8*, i8*)
493 declare void @llvm.aarch64.stg(i8*, i8*)
494 declare i64 @llvm.aarch64.subp(i8*, i8*)
496 declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture)
497 declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture)