xref: /llvm-project/llvm/test/CodeGen/AArch64/ptrauth-call.ll (revision 1fccba5ca1997db13cfa88f788b7acb8cc300b48)
1; RUN: llc -mtriple arm64e-apple-darwin   -o - %s -asm-verbose=0 \
2; RUN:   | FileCheck %s --check-prefixes=CHECK,DARWIN
3
4; RUN: llc -mtriple aarch64 -mattr=+pauth -o - %s -asm-verbose=0 \
5; RUN:   | FileCheck %s --check-prefixes=CHECK,ELF
6
7; RUN: llc -mtriple arm64e-apple-darwin   -o - %s -asm-verbose=0 \
8; RUN:   -global-isel -global-isel-abort=1 -verify-machineinstrs \
9; RUN:   | FileCheck %s --check-prefixes=CHECK,DARWIN
10
11; RUN: llc -mtriple aarch64 -mattr=+pauth -o - %s -asm-verbose=0 \
12; RUN:   -global-isel -global-isel-abort=1 -verify-machineinstrs \
13; RUN:   | FileCheck %s --check-prefixes=CHECK,ELF
14
15
16define i32 @test_call_ia_0(ptr %arg0) #0 {
17; DARWIN-LABEL: test_call_ia_0:
18; DARWIN-NEXT:    stp x29, x30, [sp, #-16]!
19; DARWIN-NEXT:    blraaz x0
20; DARWIN-NEXT:    ldp x29, x30, [sp], #16
21; DARWIN-NEXT:    ret
22;
23; ELF-LABEL: test_call_ia_0:
24; ELF-NEXT:    str x30, [sp, #-16]!
25; ELF-NEXT:    blraaz x0
26; ELF-NEXT:    ldr x30, [sp], #16
27; ELF-NEXT:    ret
28  %tmp0 = call i32 %arg0() [ "ptrauth"(i32 0, i64 0) ]
29  ret i32 %tmp0
30}
31
32define i32 @test_call_ib_0(ptr %arg0) #0 {
33; DARWIN-LABEL: test_call_ib_0:
34; DARWIN-NEXT:    stp x29, x30, [sp, #-16]!
35; DARWIN-NEXT:    blrabz x0
36; DARWIN-NEXT:    ldp x29, x30, [sp], #16
37; DARWIN-NEXT:    ret
38;
39; ELF-LABEL: test_call_ib_0:
40; ELF-NEXT:    str x30, [sp, #-16]!
41; ELF-NEXT:    blrabz x0
42; ELF-NEXT:    ldr x30, [sp], #16
43; ELF-NEXT:    ret
44  %tmp0 = call i32 %arg0() [ "ptrauth"(i32 1, i64 0) ]
45  ret i32 %tmp0
46}
47
48define i32 @test_tailcall_ia_0(ptr %arg0) #0 {
49; CHECK-LABEL: test_tailcall_ia_0:
50; CHECK-NEXT:    braaz x0
51  %tmp0 = tail call i32 %arg0() [ "ptrauth"(i32 0, i64 0) ]
52  ret i32 %tmp0
53}
54
55define i32 @test_tailcall_ib_0(ptr %arg0) #0 {
56; CHECK-LABEL: test_tailcall_ib_0:
57; CHECK-NEXT:   brabz x0
58  %tmp0 = tail call i32 %arg0() [ "ptrauth"(i32 1, i64 0) ]
59  ret i32 %tmp0
60}
61
62define i32 @test_call_ia_imm(ptr %arg0) #0 {
63; DARWIN-LABEL: test_call_ia_imm:
64; DARWIN-NEXT:    stp x29, x30, [sp, #-16]!
65; DARWIN-NEXT:    mov x17, #42
66; DARWIN-NEXT:    blraa x0, x17
67; DARWIN-NEXT:    ldp x29, x30, [sp], #16
68; DARWIN-NEXT:    ret
69;
70; ELF-LABEL: test_call_ia_imm:
71; ELF-NEXT:    str x30, [sp, #-16]!
72; ELF-NEXT:    mov x17, #42
73; ELF-NEXT:    blraa x0, x17
74; ELF-NEXT:    ldr x30, [sp], #16
75; ELF-NEXT:    ret
76  %tmp0 = call i32 %arg0() [ "ptrauth"(i32 0, i64 42) ]
77  ret i32 %tmp0
78}
79
80define i32 @test_call_ib_imm(ptr %arg0) #0 {
81; DARWIN-LABEL: test_call_ib_imm:
82; DARWIN-NEXT:    stp x29, x30, [sp, #-16]!
83; DARWIN-NEXT:    mov x17, #42
84; DARWIN-NEXT:    blrab x0, x17
85; DARWIN-NEXT:    ldp x29, x30, [sp], #16
86; DARWIN-NEXT:    ret
87;
88; ELF-LABEL: test_call_ib_imm:
89; ELF-NEXT:    str x30, [sp, #-16]!
90; ELF-NEXT:    mov x17, #42
91; ELF-NEXT:    blrab x0, x17
92; ELF-NEXT:    ldr x30, [sp], #16
93; ELF-NEXT:    ret
94  %tmp0 = call i32 %arg0() [ "ptrauth"(i32 1, i64 42) ]
95  ret i32 %tmp0
96}
97
98define i32 @test_tailcall_ia_imm(ptr %arg0) #0 {
99; CHECK-LABEL: test_tailcall_ia_imm:
100; CHECK-NEXT:    mov x16, #42
101; CHECK-NEXT:    braa x0, x16
102  %tmp0 = tail call i32 %arg0() [ "ptrauth"(i32 0, i64 42) ]
103  ret i32 %tmp0
104}
105
106define i32 @test_tailcall_ib_imm(ptr %arg0) #0 {
107; CHECK-LABEL: test_tailcall_ib_imm:
108; CHECK-NEXT:    mov x16, #42
109; CHECK-NEXT:    brab x0, x16
110  %tmp0 = tail call i32 %arg0() [ "ptrauth"(i32 1, i64 42) ]
111  ret i32 %tmp0
112}
113
114define i32 @test_call_ia_var(ptr %arg0, ptr %arg1) #0 {
115; DARWIN-LABEL: test_call_ia_var:
116; DARWIN-NEXT:    stp x29, x30, [sp, #-16]!
117; DARWIN-NEXT:    ldr x8, [x1]
118; DARWIN-NEXT:    blraa x0, x8
119; DARWIN-NEXT:    ldp x29, x30, [sp], #16
120; DARWIN-NEXT:    ret
121;
122; ELF-LABEL: test_call_ia_var:
123; ELF-NEXT:    str x30, [sp, #-16]!
124; ELF-NEXT:    ldr x8, [x1]
125; ELF-NEXT:    blraa x0, x8
126; ELF-NEXT:    ldr x30, [sp], #16
127; ELF-NEXT:    ret
128  %tmp0 = load i64, ptr %arg1
129  %tmp1 = call i32 %arg0() [ "ptrauth"(i32 0, i64 %tmp0) ]
130  ret i32 %tmp1
131}
132
133define i32 @test_call_ib_var(ptr %arg0, ptr %arg1) #0 {
134; DARWIN-LABEL: test_call_ib_var:
135; DARWIN-NEXT:    stp x29, x30, [sp, #-16]!
136; DARWIN-NEXT:    ldr x8, [x1]
137; DARWIN-NEXT:    blrab x0, x8
138; DARWIN-NEXT:    ldp x29, x30, [sp], #16
139; DARWIN-NEXT:    ret
140;
141; ELF-LABEL: test_call_ib_var:
142; ELF-NEXT:    str x30, [sp, #-16]!
143; ELF-NEXT:    ldr x8, [x1]
144; ELF-NEXT:    blrab x0, x8
145; ELF-NEXT:    ldr x30, [sp], #16
146; ELF-NEXT:    ret
147  %tmp0 = load i64, ptr %arg1
148  %tmp1 = call i32 %arg0() [ "ptrauth"(i32 1, i64 %tmp0) ]
149  ret i32 %tmp1
150}
151
152define i32 @test_tailcall_ia_var(ptr %arg0, ptr %arg1) #0 {
153; CHECK-LABEL: test_tailcall_ia_var:
154; CHECK:    ldr x1, [x1]
155; CHECK:    braa x0, x1
156  %tmp0 = load i64, ptr %arg1
157  %tmp1 = tail call i32 %arg0() [ "ptrauth"(i32 0, i64 %tmp0) ]
158  ret i32 %tmp1
159}
160
161define i32 @test_tailcall_ib_var(ptr %arg0, ptr %arg1) #0 {
162; CHECK-LABEL: test_tailcall_ib_var:
163; CHECK:    ldr x1, [x1]
164; CHECK:    brab x0, x1
165  %tmp0 = load i64, ptr %arg1
166  %tmp1 = tail call i32 %arg0() [ "ptrauth"(i32 1, i64 %tmp0) ]
167  ret i32 %tmp1
168}
169
170define void @test_tailcall_omit_mov_x16_x16(ptr %objptr) #0 {
171; CHECK-LABEL: test_tailcall_omit_mov_x16_x16:
172; CHECK-NEXT:    ldr     x16, [x0]
173; CHECK-NEXT:    mov     x17, x0
174; CHECK-NEXT:    movk    x17, #6503, lsl #48
175; CHECK-NEXT:    autda   x16, x17
176; CHECK-NEXT:    ldr     x1, [x16]
177; CHECK-NEXT:    movk    x16, #54167, lsl #48
178; CHECK-NEXT:    braa    x1, x16
179  %vtable.signed = load ptr, ptr %objptr, align 8
180  %objptr.int = ptrtoint ptr %objptr to i64
181  %vtable.discr = tail call i64 @llvm.ptrauth.blend(i64 %objptr.int, i64 6503)
182  %vtable.signed.int = ptrtoint ptr %vtable.signed to i64
183  %vtable.unsigned.int = tail call i64 @llvm.ptrauth.auth(i64 %vtable.signed.int, i32 2, i64 %vtable.discr)
184  %vtable.unsigned = inttoptr i64 %vtable.unsigned.int to ptr
185  %virt.func.signed = load ptr, ptr %vtable.unsigned, align 8
186  %virt.func.discr = tail call i64 @llvm.ptrauth.blend(i64 %vtable.unsigned.int, i64 54167)
187  tail call void %virt.func.signed(ptr %objptr) [ "ptrauth"(i32 0, i64 %virt.func.discr) ]
188  ret void
189}
190
191define i32 @test_call_omit_extra_moves(ptr %objptr) #0 {
192; CHECK-LABEL: test_call_omit_extra_moves:
193; DARWIN-NEXT:   stp     x29, x30, [sp, #-16]!
194; ELF-NEXT:      str     x30, [sp, #-16]!
195; CHECK-NEXT:    ldr     x16, [x0]
196; CHECK-NEXT:    mov     x17, x0
197; CHECK-NEXT:    movk    x17, #6503, lsl #48
198; CHECK-NEXT:    autda   x16, x17
199; CHECK-NEXT:    ldr     x8, [x16]
200; CHECK-NEXT:    movk    x16, #34646, lsl #48
201; CHECK-NEXT:    blraa   x8, x16
202; CHECK-NEXT:    mov     w0, #42
203; DARWIN-NEXT:   ldp     x29, x30, [sp], #16
204; ELF-NEXT:      ldr     x30, [sp], #16
205; CHECK-NEXT:    ret
206  %vtable.signed = load ptr, ptr %objptr
207  %objptr.int = ptrtoint ptr %objptr to i64
208  %vtable.discr = tail call i64 @llvm.ptrauth.blend(i64 %objptr.int, i64 6503)
209  %vtable.signed.int = ptrtoint ptr %vtable.signed to i64
210  %vtable.int = tail call i64 @llvm.ptrauth.auth(i64 %vtable.signed.int, i32 2, i64 %vtable.discr)
211  %vtable = inttoptr i64 %vtable.int to ptr
212  %callee.signed = load ptr, ptr %vtable
213  %callee.discr = tail call i64 @llvm.ptrauth.blend(i64 %vtable.int, i64 34646)
214  %call.result = tail call i32 %callee.signed(ptr %objptr) [ "ptrauth"(i32 0, i64 %callee.discr) ]
215  ret i32 42
216}
217
218define i32 @test_call_ia_arg(ptr %arg0, i64 %arg1) #0 {
219; DARWIN-LABEL: test_call_ia_arg:
220; DARWIN-NEXT:    stp x29, x30, [sp, #-16]!
221; DARWIN-NEXT:    blraa x0, x1
222; DARWIN-NEXT:    ldp x29, x30, [sp], #16
223; DARWIN-NEXT:    ret
224;
225; ELF-LABEL: test_call_ia_arg:
226; ELF-NEXT:    str x30, [sp, #-16]!
227; ELF-NEXT:    blraa x0, x1
228; ELF-NEXT:    ldr x30, [sp], #16
229; ELF-NEXT:    ret
230  %tmp0 = call i32 %arg0() [ "ptrauth"(i32 0, i64 %arg1) ]
231  ret i32 %tmp0
232}
233
234define i32 @test_call_ib_arg(ptr %arg0, i64 %arg1) #0 {
235; DARWIN-LABEL: test_call_ib_arg:
236; DARWIN-NEXT:    stp x29, x30, [sp, #-16]!
237; DARWIN-NEXT:    blrab x0, x1
238; DARWIN-NEXT:    ldp x29, x30, [sp], #16
239; DARWIN-NEXT:    ret
240;
241; ELF-LABEL: test_call_ib_arg:
242; ELF-NEXT:    str x30, [sp, #-16]!
243; ELF-NEXT:    blrab x0, x1
244; ELF-NEXT:    ldr x30, [sp], #16
245; ELF-NEXT:    ret
246  %tmp0 = call i32 %arg0() [ "ptrauth"(i32 1, i64 %arg1) ]
247  ret i32 %tmp0
248}
249
250define i32 @test_tailcall_ia_arg(ptr %arg0, i64 %arg1) #0 {
251; CHECK-LABEL: test_tailcall_ia_arg:
252; CHECK:    braa x0, x1
253  %tmp0 = tail call i32 %arg0() [ "ptrauth"(i32 0, i64 %arg1) ]
254  ret i32 %tmp0
255}
256
257define i32 @test_tailcall_ib_arg(ptr %arg0, i64 %arg1) #0 {
258; CHECK-LABEL: test_tailcall_ib_arg:
259; CHECK:    brab x0, x1
260  %tmp0 = tail call i32 %arg0() [ "ptrauth"(i32 1, i64 %arg1) ]
261  ret i32 %tmp0
262}
263
264define i32 @test_call_ia_arg_ind(ptr %arg0, i64 %arg1) #0 {
265; DARWIN-LABEL: test_call_ia_arg_ind:
266; DARWIN-NEXT:    stp x29, x30, [sp, #-16]!
267; DARWIN-NEXT:    ldr x8, [x0]
268; DARWIN-NEXT:    blraa x8, x1
269; DARWIN-NEXT:    ldp x29, x30, [sp], #16
270; DARWIN-NEXT:    ret
271;
272; ELF-LABEL: test_call_ia_arg_ind:
273; ELF-NEXT:    str x30, [sp, #-16]!
274; ELF-NEXT:    ldr x8, [x0]
275; ELF-NEXT:    blraa x8, x1
276; ELF-NEXT:    ldr x30, [sp], #16
277; ELF-NEXT:    ret
278  %tmp0 = load ptr, ptr %arg0
279  %tmp1 = call i32 %tmp0() [ "ptrauth"(i32 0, i64 %arg1) ]
280  ret i32 %tmp1
281}
282
283define i32 @test_call_ib_arg_ind(ptr %arg0, i64 %arg1) #0 {
284; DARWIN-LABEL: test_call_ib_arg_ind:
285; DARWIN-NEXT:    stp x29, x30, [sp, #-16]!
286; DARWIN-NEXT:    ldr x8, [x0]
287; DARWIN-NEXT:    blrab x8, x1
288; DARWIN-NEXT:    ldp x29, x30, [sp], #16
289; DARWIN-NEXT:    ret
290;
291; ELF-LABEL: test_call_ib_arg_ind:
292; ELF-NEXT:    str x30, [sp, #-16]!
293; ELF-NEXT:    ldr x8, [x0]
294; ELF-NEXT:    blrab x8, x1
295; ELF-NEXT:    ldr x30, [sp], #16
296; ELF-NEXT:    ret
297  %tmp0 = load ptr, ptr %arg0
298  %tmp1 = call i32 %tmp0() [ "ptrauth"(i32 1, i64 %arg1) ]
299  ret i32 %tmp1
300}
301
302define i32 @test_tailcall_ia_arg_ind(ptr %arg0, i64 %arg1) #0 {
303; CHECK-LABEL: test_tailcall_ia_arg_ind:
304; CHECK:    ldr x0, [x0]
305; CHECK:    braa x0, x1
306  %tmp0 = load ptr, ptr %arg0
307  %tmp1 = tail call i32 %tmp0() [ "ptrauth"(i32 0, i64 %arg1) ]
308  ret i32 %tmp1
309}
310
311define i32 @test_tailcall_ib_arg_ind(ptr %arg0, i64 %arg1) #0 {
312; CHECK-LABEL: test_tailcall_ib_arg_ind:
313; CHECK:    ldr x0, [x0]
314; CHECK:    brab x0, x1
315  %tmp0 = load ptr, ptr %arg0
316  %tmp1 = tail call i32 %tmp0() [ "ptrauth"(i32 1, i64 %arg1) ]
317  ret i32 %tmp1
318}
319
320; Test direct calls
321
322define i32 @test_direct_call() #0 {
323; DARWIN-LABEL: test_direct_call:
324; DARWIN-NEXT:   stp x29, x30, [sp, #-16]!
325; DARWIN-NEXT:   bl _f
326; DARWIN-NEXT:   ldp x29, x30, [sp], #16
327; DARWIN-NEXT:   ret
328;
329; ELF-LABEL: test_direct_call:
330; ELF-NEXT:   str x30, [sp, #-16]!
331; ELF-NEXT:   bl f
332; ELF-NEXT:   ldr x30, [sp], #16
333; ELF-NEXT:   ret
334  %tmp0 = call i32 ptrauth(ptr @f, i32 0, i64 42)() [ "ptrauth"(i32 0, i64 42) ]
335  ret i32 %tmp0
336}
337
338define i32 @test_direct_tailcall(ptr %arg0) #0 {
339; DARWIN-LABEL: test_direct_tailcall:
340; DARWIN:    b _f
341;
342; ELF-LABEL: test_direct_tailcall:
343; ELF-NEXT:   b f
344  %tmp0 = tail call i32 ptrauth(ptr @f, i32 0, i64 42)() [ "ptrauth"(i32 0, i64 42) ]
345  ret i32 %tmp0
346}
347
348define i32 @test_direct_call_mismatch() #0 {
349; DARWIN-LABEL: test_direct_call_mismatch:
350; DARWIN-NEXT:   stp x29, x30, [sp, #-16]!
351; DARWIN-NEXT:   adrp x16, _f@GOTPAGE
352; DARWIN-NEXT:   ldr x16, [x16, _f@GOTPAGEOFF]
353; DARWIN-NEXT:   mov x17, #42
354; DARWIN-NEXT:   pacia x16, x17
355; DARWIN-NEXT:   mov x8, x16
356; DARWIN-NEXT:   mov x17, #42
357; DARWIN-NEXT:   blrab x8, x17
358; DARWIN-NEXT:   ldp x29, x30, [sp], #16
359; DARWIN-NEXT:   ret
360;
361; ELF-LABEL: test_direct_call_mismatch:
362; ELF-NEXT:   str x30, [sp, #-16]!
363; ELF-NEXT:   adrp x16, :got:f
364; ELF-NEXT:   ldr x16, [x16, :got_lo12:f]
365; ELF-NEXT:   mov x17, #42
366; ELF-NEXT:   pacia x16, x17
367; ELF-NEXT:   mov x8, x16
368; ELF-NEXT:   mov x17, #42
369; ELF-NEXT:   blrab x8, x17
370; ELF-NEXT:   ldr x30, [sp], #16
371; ELF-NEXT:   ret
372  %tmp0 = call i32 ptrauth(ptr @f, i32 0, i64 42)() [ "ptrauth"(i32 1, i64 42) ]
373  ret i32 %tmp0
374}
375
376define i32 @test_direct_call_addr() #0 {
377; DARWIN-LABEL: test_direct_call_addr:
378; DARWIN-NEXT:   stp x29, x30, [sp, #-16]!
379; DARWIN-NEXT:   bl _f
380; DARWIN-NEXT:   ldp x29, x30, [sp], #16
381; DARWIN-NEXT:   ret
382;
383; ELF-LABEL: test_direct_call_addr:
384; ELF-NEXT:   str x30, [sp, #-16]!
385; ELF-NEXT:   bl f
386; ELF-NEXT:   ldr x30, [sp], #16
387; ELF-NEXT:   ret
388  %tmp0 = call i32 ptrauth(ptr @f, i32 1, i64 0, ptr @f.ref.ib.0.addr)() [ "ptrauth"(i32 1, i64 ptrtoint (ptr @f.ref.ib.0.addr to i64)) ]
389  ret i32 %tmp0
390}
391
392define i32 @test_direct_call_addr_blend() #0 {
393; DARWIN-LABEL: test_direct_call_addr_blend:
394; DARWIN-NEXT:   stp x29, x30, [sp, #-16]!
395; DARWIN-NEXT:   bl _f
396; DARWIN-NEXT:   ldp x29, x30, [sp], #16
397; DARWIN-NEXT:   ret
398;
399; ELF-LABEL: test_direct_call_addr_blend:
400; ELF-NEXT:   str x30, [sp, #-16]!
401; ELF-NEXT:   bl f
402; ELF-NEXT:   ldr x30, [sp], #16
403; ELF-NEXT:   ret
404  %tmp0 = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr @f.ref.ib.42.addr to i64), i64 42)
405  %tmp1 = call i32 ptrauth(ptr @f, i32 1, i64 42, ptr @f.ref.ib.42.addr)() [ "ptrauth"(i32 1, i64 %tmp0) ]
406  ret i32 %tmp1
407}
408
409define i32 @test_direct_call_addr_gep_different_index_types() #0 {
410; DARWIN-LABEL: test_direct_call_addr_gep_different_index_types:
411; DARWIN-NEXT:   stp x29, x30, [sp, #-16]!
412; DARWIN-NEXT:   bl _f
413; DARWIN-NEXT:   ldp x29, x30, [sp], #16
414; DARWIN-NEXT:   ret
415;
416; ELF-LABEL: test_direct_call_addr_gep_different_index_types:
417; ELF-NEXT:   str x30, [sp, #-16]!
418; ELF-NEXT:   bl f
419; ELF-NEXT:   ldr x30, [sp], #16
420; ELF-NEXT:   ret
421  %tmp0 = call i32 ptrauth(ptr @f, i32 1, i64 0, ptr getelementptr ({ ptr }, ptr @f_struct.ref.ib.0.addr, i64 0, i32 0))() [ "ptrauth"(i32 1, i64 ptrtoint (ptr getelementptr ({ ptr }, ptr @f_struct.ref.ib.0.addr, i32 0, i32 0) to i64)) ]
422  ret i32 %tmp0
423}
424
425define i32 @test_direct_call_addr_blend_gep_different_index_types() #0 {
426; DARWIN-LABEL: test_direct_call_addr_blend_gep_different_index_types:
427; DARWIN-NEXT:   stp x29, x30, [sp, #-16]!
428; DARWIN-NEXT:   bl _f
429; DARWIN-NEXT:   ldp x29, x30, [sp], #16
430; DARWIN-NEXT:   ret
431;
432; ELF-LABEL: test_direct_call_addr_blend_gep_different_index_types:
433; ELF-NEXT:   str x30, [sp, #-16]!
434; ELF-NEXT:   bl f
435; ELF-NEXT:   ldr x30, [sp], #16
436; ELF-NEXT:   ret
437  %tmp0 = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr getelementptr ({ ptr }, ptr @f_struct.ref.ib.123.addr, i32 0, i32 0) to i64), i64 123)
438  %tmp1 = call i32 ptrauth(ptr @f, i32 1, i64 123, ptr getelementptr ({ ptr }, ptr @f_struct.ref.ib.123.addr, i64 0, i32 0))() [ "ptrauth"(i32 1, i64 %tmp0) ]
439  ret i32 %tmp1
440}
441
442@f.ref.ib.42.addr = external global ptr
443@f.ref.ib.0.addr = external global ptr
444@f_struct.ref.ib.0.addr = external global ptr
445@f_struct.ref.ib.123.addr = external global ptr
446
447declare void @f()
448
449declare i64 @llvm.ptrauth.auth(i64, i32, i64)
450declare i64 @llvm.ptrauth.blend(i64, i64)
451
452attributes #0 = { nounwind }
453