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