xref: /llvm-project/llvm/test/CodeGen/AArch64/speculation-hardening.mir (revision 1ee315ae7964c8433b772e0b5d667834994ba753)
1# RUN: llc -verify-machineinstrs -mtriple=aarch64-none-linux-gnu \
2# RUN:     -start-before aarch64-speculation-hardening -o - %s \
3# RUN:   | FileCheck %s
4
5# Check that the speculation hardening pass generates code as expected for
6# basic blocks ending with a variety of branch patterns:
7# - (1) no branches (fallthrough)
8# - (2) one unconditional branch
9# - (3) one conditional branch + fall-through
10# - (4) one conditional branch + one unconditional branch
11# - other direct branches don't seem to be generated by the AArch64 codegen
12--- |
13  define void @nobranch_fallthrough(i32 %a, i32 %b) speculative_load_hardening {
14   ret void
15  }
16  define void @uncondbranch(i32 %a, i32 %b) speculative_load_hardening {
17   ret void
18  }
19  define void @condbranch_fallthrough(i32 %a, i32 %b) speculative_load_hardening {
20   ret void
21  }
22  define void @condbranch_uncondbranch(i32 %a, i32 %b) speculative_load_hardening {
23   ret void
24  }
25  define void @indirectbranch(i32 %a, i32 %b) speculative_load_hardening {
26   ret void
27  }
28  ; Also check that a non-default temporary register gets picked correctly to
29  ; transfer the SP to to and it with the taint register when the default
30  ; temporary isn't available.
31  define void @indirect_call_x17(i32 %a, i32 %b) speculative_load_hardening {
32   ret void
33  }
34  @g = common dso_local local_unnamed_addr global ptr null, align 8
35  define void @indirect_tailcall_x17(i32 %a, i32 %b) speculative_load_hardening {
36   ret void
37  }
38  define void @indirect_call_lr(i32 %a, i32 %b) speculative_load_hardening {
39   ret void
40  }
41  define void @RS_cannot_find_available_regs() speculative_load_hardening {
42   ret void
43  }
44...
45---
46name:            nobranch_fallthrough
47tracksRegLiveness: true
48body:             |
49  ; CHECK-LABEL: nobranch_fallthrough
50  bb.0:
51    successors: %bb.1
52    liveins: $w0, $w1
53  ; CHECK-NOT: csel
54  bb.1:
55    liveins: $w0
56   RET undef $lr, implicit $w0
57...
58---
59name:            uncondbranch
60tracksRegLiveness: true
61body:             |
62  ; CHECK-LABEL: uncondbranch
63  bb.0:
64    successors: %bb.1
65    liveins: $w0, $w1
66    B %bb.1
67  ; CHECK-NOT: csel
68  bb.1:
69   liveins: $w0
70   RET undef $lr, implicit $w0
71...
72---
73name:            condbranch_fallthrough
74tracksRegLiveness: true
75body:             |
76  ; CHECK-LABEL: condbranch_fallthrough
77  bb.0:
78    successors: %bb.1, %bb.2
79    liveins: $w0, $w1
80    $wzr = SUBSWrs renamable $w0, renamable $w1, 0, implicit-def $nzcv, implicit-def $nzcv
81    Bcc 11, %bb.2, implicit $nzcv
82  ; CHECK: b.lt [[BB_LT_T:\.LBB[0-9_]+]]
83
84  bb.1:
85    liveins: $nzcv, $w0
86  ; CHECK: csel x16, x16, xzr, ge
87    RET undef $lr, implicit $w0
88  bb.2:
89    liveins: $nzcv, $w0
90  ; CHECK: csel x16, x16, xzr, lt
91    RET undef $lr, implicit $w0
92...
93---
94name:            condbranch_uncondbranch
95tracksRegLiveness: true
96body:             |
97  ; CHECK-LABEL: condbranch_uncondbranch
98  bb.0:
99    successors: %bb.1, %bb.2
100    liveins: $w0, $w1
101    $wzr = SUBSWrs renamable $w0, renamable $w1, 0, implicit-def $nzcv, implicit-def $nzcv
102    Bcc 11, %bb.2, implicit $nzcv
103    B %bb.1, implicit $nzcv
104  ; CHECK: b.lt [[BB_LT_T:\.LBB[0-9_]+]]
105
106  bb.1:
107    liveins: $nzcv, $w0
108  ; CHECK: csel x16, x16, xzr, ge
109    RET undef $lr, implicit $w0
110  bb.2:
111    liveins: $nzcv, $w0
112  ; CHECK: csel x16, x16, xzr, lt
113    RET undef $lr, implicit $w0
114...
115---
116name:            indirectbranch
117tracksRegLiveness: true
118body:             |
119  ; Check that no instrumentation is done on indirect branches (for now).
120  ; CHECK-LABEL: indirectbranch
121  bb.0:
122    successors: %bb.1, %bb.2
123    liveins: $x0
124    BR $x0
125  bb.1:
126   liveins: $x0
127  ; CHECK-NOT: csel
128   RET undef $lr, implicit $x0
129  bb.2:
130   liveins: $x0
131  ; CHECK-NOT: csel
132   RET undef $lr, implicit $x0
133...
134---
135name:            indirect_call_x17
136tracksRegLiveness: true
137body:             |
138  bb.0:
139    liveins: $x17
140    ; CHECK-LABEL: indirect_call_x17
141    ; CHECK:       mov x0, sp
142    ; CHECK:       and x0, x0, x16
143    ; CHECK:       mov sp, x0
144    ; CHECK:       blr x17
145    BLR killed renamable $x17, implicit-def dead $lr, implicit $sp
146    RET undef $lr, implicit undef $w0
147...
148---
149name:           indirect_tailcall_x17
150tracksRegLiveness: true
151body:             |
152  bb.0:
153    liveins: $x0
154    ; CHECK-LABEL: indirect_tailcall_x17
155    ; CHECK:       mov x1, sp
156    ; CHECK:       and x1, x1, x16
157    ; CHECK:       mov sp, x1
158    ; CHECK:       br x17
159    $x8 = ADRP target-flags(aarch64-page) @g
160    $x17 = LDRXui killed $x8, target-flags(aarch64-pageoff, aarch64-nc) @g
161    TCRETURNri killed $x17, 0, implicit $sp, implicit $x0
162...
163---
164name:           indirect_call_lr
165tracksRegLiveness: true
166body:             |
167  bb.0:
168    ; CHECK-LABEL: indirect_call_lr
169    ; CHECK:            mov x1, sp
170    ; CHECK:            and x1, x1, x16
171    ; CHECK-NEXT:       mov sp, x1
172    ; CHECK-NEXT:       blr x30
173    liveins: $x0, $lr
174    BLR killed renamable $lr, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def $w0, implicit $x0
175    $w0 = nsw ADDWri killed $w0, 1, 0
176    RET undef $lr, implicit $w0
177...
178---
179name:           RS_cannot_find_available_regs
180tracksRegLiveness: true
181body:             |
182  bb.0:
183    ; In the rare case when no free temporary register is available for the
184    ; propagate taint-to-sp operation, just put in a full speculation barrier
185    ; (isb+dsb sy) at the start of the basic block. And don't put masks on
186    ; instructions for the rest of the basic block, since speculation in that
187    ; basic block was already done, so no need to do masking.
188    ; CHECK-LABEL: RS_cannot_find_available_regs
189    ; CHECK:       dsb sy
190    ; CHECK-NEXT:  isb
191    ; CHECK-NEXT:  ldr x0, [x0]
192    ; The following 2 instructions come from propagating the taint encoded in
193    ; sp at function entry to x16. It turns out the taint info in x16 is not
194    ; used in this function, so those instructions could be optimized away. An
195    ; optimization for later if it turns out this situation occurs often enough.
196    ; CHECK-NEXT:  cmp sp, #0
197    ; CHECK-NEXT:  csetm x16, ne
198    ; CHECK-NEXT:  ret
199    liveins: $x0, $x1, $x2, $x3, $x4, $x5, $x6, $x7, $x8, $x9, $x10, $x11, $x12, $x13, $x14, $x15, $x17, $x18, $x19, $x20, $x21, $x22, $x23, $x24, $x25, $x26, $x27, $x28, $fp, $lr
200    $x0 = LDRXui killed $x0, 0
201    RET $lr, implicit $x0, implicit $x1, implicit $x2, implicit $x3, implicit $x4, implicit $x5, implicit $x6, implicit $x7, implicit $x8, implicit $x9, implicit $x10, implicit $x11, implicit $x12, implicit $x13, implicit $x14, implicit $x15, implicit $x17, implicit $x18, implicit $x19, implicit $x20, implicit $x21, implicit $x22, implicit $x23, implicit $x24, implicit $x25, implicit $x26, implicit $x27, implicit $x28
202...
203