xref: /llvm-project/llvm/test/CodeGen/AArch64/speculation-hardening-sls.ll (revision 5ddce70ef0e5a641d7fea95e31fc5e2439cb98cb)
1; RUN: llc -mattr=harden-sls-retbr,harden-sls-blr -verify-machineinstrs -mtriple=aarch64-none-linux-gnu < %s | FileCheck %s --check-prefixes=CHECK,HARDEN,HARDEN-COMDAT,ISBDSB,ISBDSBDAGISEL
2; RUN: llc -mattr=harden-sls-retbr,harden-sls-blr,harden-sls-nocomdat -verify-machineinstrs -mtriple=aarch64-none-linux-gnu < %s | FileCheck %s --check-prefixes=CHECK,HARDEN,HARDEN-COMDAT-OFF,ISBDSB,ISBDSBDAGISEL
3; RUN: llc -mattr=harden-sls-retbr,harden-sls-blr -mattr=+sb -verify-machineinstrs -mtriple=aarch64-none-linux-gnu < %s | FileCheck %s --check-prefixes=CHECK,HARDEN,SB,SBDAGISEL
4; RUN: llc -global-isel -global-isel-abort=0 -mattr=harden-sls-retbr,harden-sls-blr -verify-machineinstrs -mtriple=aarch64-none-linux-gnu < %s | FileCheck %s --check-prefixes=CHECK,HARDEN,HARDEN-COMDAT,ISBDSB
5; RUN: llc -verify-machineinstrs -mtriple=aarch64-none-linux-gnu < %s | FileCheck %s --check-prefixes=CHECK,NOHARDEN
6; RUN: llc -global-isel -global-isel-abort=0 -mattr=harden-sls-retbr,harden-sls-blr,harden-sls-nocomdat -verify-machineinstrs -mtriple=aarch64-none-linux-gnu < %s | FileCheck %s --check-prefixes=CHECK,HARDEN,HARDEN-COMDAT-OFF,ISBDSB
7; RUN: llc -global-isel -global-isel-abort=0 -mattr=harden-sls-retbr,harden-sls-blr -mattr=+sb -verify-machineinstrs -mtriple=aarch64-none-linux-gnu < %s | FileCheck %s --check-prefixes=CHECK,HARDEN,SB
8
9; Function Attrs: norecurse nounwind readnone
10define dso_local i32 @double_return(i32 %a, i32 %b) local_unnamed_addr {
11entry:
12  %cmp = icmp sgt i32 %a, 0
13  br i1 %cmp, label %if.then, label %if.else
14
15if.then:                                          ; preds = %entry
16  %div = sdiv i32 %a, %b
17  ret i32 %div
18
19if.else:                                          ; preds = %entry
20  %div1 = sdiv i32 %b, %a
21  ret i32 %div1
22; CHECK-LABEL: double_return:
23; CHECK:       {{ret$}}
24; ISBDSB-NEXT: dsb sy
25; ISBDSB-NEXT: isb
26; SB-NEXT:     {{ sb$}}
27; CHECK:       {{ret$}}
28; ISBDSB-NEXT: dsb sy
29; ISBDSB-NEXT: isb
30; SB-NEXT:     {{ sb$}}
31; CHECK-NEXT: .Lfunc_end
32}
33
34@__const.indirect_branch.ptr = private unnamed_addr constant [2 x ptr] [ptr blockaddress(@indirect_branch, %return), ptr blockaddress(@indirect_branch, %l2)], align 8
35
36; Function Attrs: norecurse nounwind readnone
37define dso_local i32 @indirect_branch(i32 %a, i32 %b, i32 %i) {
38; CHECK-LABEL: indirect_branch:
39entry:
40  %idxprom = sext i32 %i to i64
41  %arrayidx = getelementptr inbounds [2 x ptr], ptr @__const.indirect_branch.ptr, i64 0, i64 %idxprom
42  %0 = load ptr, ptr %arrayidx, align 8
43  indirectbr ptr %0, [label %return, label %l2]
44; CHECK:       br x
45; ISBDSB-NEXT: dsb sy
46; ISBDSB-NEXT: isb
47; SB-NEXT:     {{ sb$}}
48
49l2:                                               ; preds = %entry
50  br label %return
51; CHECK:       {{ret$}}
52; ISBDSB-NEXT: dsb sy
53; ISBDSB-NEXT: isb
54; SB-NEXT:     {{ sb$}}
55
56return:                                           ; preds = %entry, %l2
57  %retval.0 = phi i32 [ 1, %l2 ], [ 0, %entry ]
58  ret i32 %retval.0
59; CHECK:       {{ret$}}
60; ISBDSB-NEXT: dsb sy
61; ISBDSB-NEXT: isb
62; SB-NEXT:     {{ sb$}}
63; CHECK-NEXT: .Lfunc_end
64}
65
66; Check that RETAA and RETAB instructions are also protected as expected.
67define dso_local i32 @ret_aa(i32 returned %a) local_unnamed_addr "target-features"="+neon,+v8.3a" "sign-return-address"="all" "sign-return-address-key"="a_key" {
68entry:
69; CHECK-LABEL: ret_aa:
70; CHECK:       {{ retaa$}}
71; ISBDSB-NEXT: dsb sy
72; ISBDSB-NEXT: isb
73; SB-NEXT:     {{ sb$}}
74; CHECK-NEXT: .Lfunc_end
75	  ret i32 %a
76}
77
78define dso_local i32 @ret_ab(i32 returned %a) local_unnamed_addr "target-features"="+neon,+v8.3a" "sign-return-address"="all" "sign-return-address-key"="b_key" {
79entry:
80; CHECK-LABEL: ret_ab:
81; CHECK:       {{ retab$}}
82; ISBDSB-NEXT: dsb sy
83; ISBDSB-NEXT: isb
84; SB-NEXT:     {{ sb$}}
85; CHECK-NEXT: .Lfunc_end
86	  ret i32 %a
87}
88
89define i32 @asmgoto() {
90entry:
91; CHECK-LABEL: asmgoto:
92  callbr void asm sideeffect "B $0", "!i"()
93            to label %asm.fallthrough [label %d]
94     ; The asm goto above produces a direct branch:
95; CHECK:           //APP
96; CHECK-NEXT:      {{^[ \t]+b }}
97; CHECK-NEXT:      //NO_APP
98     ; For direct branches, no mitigation is needed.
99; ISDDSB-NOT: dsb sy
100; SB-NOT:     {{ sb$}}
101
102asm.fallthrough:               ; preds = %entry
103  ret i32 0
104; CHECK:       {{ret$}}
105; ISBDSB-NEXT: dsb sy
106; ISBDSB-NEXT: isb
107; SB-NEXT:     {{ sb$}}
108
109d:                             ; preds = %asm.fallthrough, %entry
110  ret i32 1
111; CHECK:       {{ret$}}
112; ISBDSB-NEXT: dsb sy
113; ISBDSB-NEXT: isb
114; SB-NEXT:     {{ sb$}}
115; CHECK-NEXT: .Lfunc_end
116}
117
118define dso_local i32 @indirect_call(
119ptr nocapture %f1, ptr nocapture %f2) {
120entry:
121; CHECK-LABEL: indirect_call:
122  %call = tail call i32 %f1()
123; HARDEN: bl {{__llvm_slsblr_thunk_x[0-9]+$}}
124  %call2 = tail call i32 %f2()
125; HARDEN: bl {{__llvm_slsblr_thunk_x[0-9]+$}}
126  %add = add nsw i32 %call2, %call
127  ret i32 %add
128; CHECK: .Lfunc_end
129}
130
131; verify calling through a function pointer.
132@a = dso_local local_unnamed_addr global ptr null, align 8
133@b = dso_local local_unnamed_addr global i32 0, align 4
134define dso_local void @indirect_call_global() local_unnamed_addr {
135; CHECK-LABEL: indirect_call_global:
136entry:
137  %0 = load ptr, ptr @a, align 8
138  %call = tail call i32 %0()  nounwind
139; HARDEN: bl {{__llvm_slsblr_thunk_x[0-9]+$}}
140  store i32 %call, ptr @b, align 4
141  ret void
142; CHECK: .Lfunc_end
143}
144
145; Verify that neither x16 nor x17 are used when the BLR mitigation is enabled,
146; as a linker is allowed to clobber x16 or x17 on calls, which would break the
147; correct execution of the code sequence produced by the mitigation. The below
148; test attempts to force *%f into x16 using inline assembly.
149define i64 @check_x16(ptr nocapture readonly %fp, ptr nocapture readonly %fp2) "target-features"="+neon,+reserve-x10,+reserve-x11,+reserve-x12,+reserve-x13,+reserve-x14,+reserve-x15,+reserve-x18,+reserve-x20,+reserve-x21,+reserve-x22,+reserve-x23,+reserve-x24,+reserve-x25,+reserve-x26,+reserve-x27,+reserve-x28,+reserve-x30,+reserve-x9" {
150entry:
151; CHECK-LABEL: check_x16:
152  %f = load ptr, ptr %fp, align 8
153  %x16_f = tail call ptr asm "add $0, $1, #0", "={x16},{x16}"(ptr %f) nounwind
154  %call1 = call i64 %x16_f()
155; NOHARDEN:   blr x16
156; ISBDSB-NOT: bl __llvm_slsblr_thunk_x16
157; SB-NOT:     bl __llvm_slsblr_thunk_x16
158; CHECK
159  ret i64 %call1
160; CHECK: .Lfunc_end
161}
162
163; Verify that the transformation works correctly for x29 when it is not
164; reserved to be used as a frame pointer.
165; Since this is sensitive to register allocation choices, only check this with
166; DAGIsel to avoid too much accidental breaking of this test that is a bit
167; brittle.
168define i64 @check_x29(ptr nocapture readonly %fp,
169                      ptr nocapture readonly %fp2,
170                      ptr nocapture readonly %fp3)
171"target-features"="+neon,+reserve-x10,+reserve-x11,+reserve-x12,+reserve-x13,+reserve-x14,+reserve-x15,+reserve-x18,+reserve-x20,+reserve-x21,+reserve-x22,+reserve-x23,+reserve-x24,+reserve-x25,+reserve-x26,+reserve-x27,+reserve-x28,+reserve-x9"
172"frame-pointer"="none"
173{
174entry:
175; CHECK-LABEL: check_x29:
176  %0 = load ptr, ptr %fp, align 8
177  %1 = load ptr, ptr %fp2, align 8
178  %2 = load ptr, ptr %fp2, align 8
179  %3 = load ptr, ptr %fp3, align 8
180  %4 = load ptr, ptr %fp3, align 8
181  %5 = load ptr, ptr %fp, align 8
182  %call = call i64 %0(ptr %1, ptr %3, i64 0, i64 0, i64 0, i64 0, i64 0, i64 0)
183  %call1 = call i64 %2(ptr %1, ptr %3, i64 0, i64 0, i64 0, i64 0, i64 0, i64 0)
184; NOHARDEN:      blr x29
185; ISBDSBDAGISEL: bl __llvm_slsblr_thunk_x29
186; SBDAGISEL:     bl __llvm_slsblr_thunk_x29
187; CHECK
188  %call2 = call i64 %4(ptr %1, ptr %5, i64 0, i64 0, i64 0, i64 0, i64 0, i64 0)
189  %add = add nsw i64 %call1, %call
190  %add1 = add nsw i64 %call2, %add
191  ret i64 %add1
192; CHECK: .Lfunc_end
193}
194
195; HARDEN-label: __llvm_slsblr_thunk_x0:
196; HARDEN:    mov x16, x0
197; HARDEN:    br x16
198; ISBDSB-NEXT: dsb sy
199; ISBDSB-NEXT: isb
200; SB-NEXT:     dsb sy
201; SB-NEXT:     isb
202; HARDEN-NEXT: .Lfunc_end
203; HARDEN-COMDAT:  .section .text.__llvm_slsblr_thunk_x19
204; HARDEN-COMDAT:  .hidden __llvm_slsblr_thunk_x19
205; HARDEN-COMDAT:  .weak __llvm_slsblr_thunk_x19
206; HARDEN-COMDAT: .type  __llvm_slsblr_thunk_x19,@function
207; HARDEN-COMDAT-OFF-NOT:  .section .text.__llvm_slsblr_thunk_x19
208; HARDEN-COMDAT-OFF-NOT:  .hidden __llvm_slsblr_thunk_x19
209; HARDEN-COMDAT-OFF-NOT:  .weak __llvm_slsblr_thunk_x19
210; HARDEN-COMDAT-OFF:      .type __llvm_slsblr_thunk_x19,@function
211; HARDEN-label: __llvm_slsblr_thunk_x19:
212; HARDEN:    mov x16, x19
213; HARDEN:    br x16
214; ISBDSB-NEXT: dsb sy
215; ISBDSB-NEXT: isb
216; SB-NEXT:     dsb sy
217; SB-NEXT:     isb
218; HARDEN-NEXT: .Lfunc_end
219