1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
; RUN: llc -mtriple=armv7-linux-gnueabi -verify-machineinstrs < %s | FileCheck %s --check-prefix=ASM
; RUN: llc -mtriple=armv7-linux-gnueabi -verify-machineinstrs -stop-after=finalize-isel < %s | FileCheck %s --check-prefixes=MIR,ISEL
; RUN: llc -mtriple=armv7-linux-gnueabi -verify-machineinstrs -stop-after=kcfi < %s | FileCheck %s --check-prefixes=MIR,KCFI
; MIR checks for all functions (grouped here to prevent update_llc_test_checks.py from removing them)
; MIR-LABEL: name: f1
; MIR: body:
; ISEL: BLX %0, csr_aapcs,{{.*}} cfi-type 12345678
; KCFI: BUNDLE{{.*}} {
; KCFI-NEXT: KCFI_CHECK_ARM $r0, 12345678
; KCFI-NEXT: BLX killed $r0, csr_aapcs,{{.*}}
; KCFI-NEXT: }
; MIR-LABEL: name: f2
; MIR: body:
; ISEL: TCRETURNri %0, 0, csr_aapcs, implicit $sp, cfi-type 12345678
; KCFI: BUNDLE{{.*}} {
; KCFI-NEXT: KCFI_CHECK_ARM $r0, 12345678
; KCFI-NEXT: TAILJMPr killed $r0, csr_aapcs, implicit $sp, implicit $sp
; KCFI-NEXT: }
; ASM: .long 12345678
define void @f1(ptr noundef %x) !kcfi_type !1 {
; ASM-LABEL: f1:
; ASM: @ %bb.0:
; ASM-NEXT: .save {r11, lr}
; ASM-NEXT: push {r11, lr}
; ASM-NEXT: bic r12, r0, #1
; ASM-NEXT: ldr r12, [r12, #-4]
; ASM-NEXT: eor r12, r12, #78
; ASM-NEXT: eor r12, r12, #24832
; ASM-NEXT: eor r12, r12, #12320768
; ASM-NEXT: eors r12, r12, #0
; ASM-NEXT: beq .Ltmp0
; ASM-NEXT: udf #33760
; ASM-NEXT: .Ltmp0:
; ASM-NEXT: blx r0
; ASM-NEXT: pop {r11, pc}
call void %x() [ "kcfi"(i32 12345678) ]
ret void
}
; Test with tail call
define void @f2(ptr noundef %x) !kcfi_type !1 {
; ASM-LABEL: f2:
; ASM: @ %bb.0:
; ASM-NEXT: bic r12, r0, #1
; ASM-NEXT: ldr r12, [r12, #-4]
; ASM-NEXT: eor r12, r12, #78
; ASM-NEXT: eor r12, r12, #24832
; ASM-NEXT: eor r12, r12, #12320768
; ASM-NEXT: eors r12, r12, #0
; ASM-NEXT: beq .Ltmp1
; ASM-NEXT: udf #33760
; ASM-NEXT: .Ltmp1:
; ASM-NEXT: bx r0
tail call void %x() [ "kcfi"(i32 12345678) ]
ret void
}
; Test r3 spill/reload when target is r12 and r3 is a call argument.
; With 5+ arguments (target + 4 args), r0-r3 are all used for arguments,
; forcing r3 to be spilled when we need it as scratch register.
define void @f3_r3_spill(ptr noundef %target, i32 %a, i32 %b, i32 %c, i32 %d) !kcfi_type !1 {
; ASM-LABEL: f3_r3_spill:
; ASM: @ %bb.0:
; ASM-NEXT: .save {r11, lr}
; ASM-NEXT: push {r11, lr}
; ASM-NEXT: mov lr, r3
; ASM-NEXT: ldr r3, [sp, #8]
; ASM-NEXT: mov r12, r0
; ASM-NEXT: mov r0, r1
; ASM-NEXT: mov r1, r2
; ASM-NEXT: mov r2, lr
; ASM-NEXT: stmdb sp!, {r3}
; ASM-NEXT: bic r3, r12, #1
; ASM-NEXT: ldr r3, [r3, #-4]
; ASM-NEXT: eor r3, r3, #78
; ASM-NEXT: eor r3, r3, #24832
; ASM-NEXT: eor r3, r3, #12320768
; ASM-NEXT: eors r3, r3, #0
; ASM-NEXT: ldm sp!, {r3}
; ASM-NEXT: beq .Ltmp2
; ASM-NEXT: udf #33772
; ASM-NEXT: .Ltmp2:
; ASM-NEXT: blx r12
; ASM-NEXT: pop {r11, pc}
; Arguments: r0=%target, r1=%a, r2=%b, r3=%c, [sp]=%d
; Call needs: r0=%a, r1=%b, r2=%c, r3=%d, target in r12
; Compiler shuffles arguments into place, saving r3 (c) in lr, loading d from stack
; r3 is live as 4th argument, so push it before KCFI check
; Restore r3 immediately after comparison, before branch
call void %target(i32 %a, i32 %b, i32 %c, i32 %d) [ "kcfi"(i32 12345678) ]
ret void
}
; Test with 3 arguments - r3 not live, target in r12, so r3 used as scratch without spilling
define void @f4_r3_unused(ptr noundef %target, i32 %a, i32 %b) !kcfi_type !1 {
; ASM-LABEL: f4_r3_unused:
; ASM: @ %bb.0:
; ASM-NEXT: .save {r11, lr}
; ASM-NEXT: push {r11, lr}
; ASM-NEXT: mov r3, r0
; ASM-NEXT: mov r0, r1
; ASM-NEXT: mov r1, r2
; ASM-NEXT: bic r12, r3, #1
; ASM-NEXT: ldr r12, [r12, #-4]
; ASM-NEXT: eor r12, r12, #78
; ASM-NEXT: eor r12, r12, #24832
; ASM-NEXT: eor r12, r12, #12320768
; ASM-NEXT: eors r12, r12, #0
; ASM-NEXT: beq .Ltmp3
; ASM-NEXT: udf #33763
; ASM-NEXT: .Ltmp3:
; ASM-NEXT: blx r3
; ASM-NEXT: pop {r11, pc}
; Only 3 arguments total, so r3 is not used as call argument
; Compiler puts target→r3, a→r0, b→r1
; r3 is the target, so we use r12 as scratch (no spill needed)
call void %target(i32 %a, i32 %b) [ "kcfi"(i32 12345678) ]
ret void
}
!llvm.module.flags = !{!0}
!0 = !{i32 4, !"kcfi", i32 1}
!1 = !{i32 12345678}
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
; ISEL: {{.*}}
; KCFI: {{.*}}
; MIR: {{.*}}
|