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 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
|
# RUN: llc -verify-machineinstrs -mtriple=aarch64-none-linux-gnu \
# RUN: -start-before aarch64-speculation-hardening -o - %s \
# RUN: | FileCheck %s
# Check that the speculation hardening pass generates code as expected for
# basic blocks ending with a variety of branch patterns:
# - (1) no branches (fallthrough)
# - (2) one unconditional branch
# - (3) one conditional branch + fall-through
# - (4) one conditional branch + one unconditional branch
# - other direct branches don't seem to be generated by the AArch64 codegen
--- |
define void @nobranch_fallthrough(i32 %a, i32 %b) speculative_load_hardening {
ret void
}
define void @uncondbranch(i32 %a, i32 %b) speculative_load_hardening {
ret void
}
define void @condbranch_fallthrough(i32 %a, i32 %b) speculative_load_hardening {
ret void
}
define void @condbranch_uncondbranch(i32 %a, i32 %b) speculative_load_hardening {
ret void
}
define void @indirectbranch(i32 %a, i32 %b) speculative_load_hardening {
ret void
}
; Also check that a non-default temporary register gets picked correctly to
; transfer the SP to to and it with the taint register when the default
; temporary isn't available.
define void @indirect_call_x17(i32 %a, i32 %b) speculative_load_hardening {
ret void
}
@g = common dso_local local_unnamed_addr global i64 (...)* null, align 8
define void @indirect_tailcall_x17(i32 %a, i32 %b) speculative_load_hardening {
ret void
}
define void @indirect_call_lr(i32 %a, i32 %b) speculative_load_hardening {
ret void
}
define void @RS_cannot_find_available_regs() speculative_load_hardening {
ret void
}
...
---
name: nobranch_fallthrough
tracksRegLiveness: true
body: |
; CHECK-LABEL: nobranch_fallthrough
bb.0:
successors: %bb.1
liveins: $w0, $w1
; CHECK-NOT: csel
bb.1:
liveins: $w0
RET undef $lr, implicit $w0
...
---
name: uncondbranch
tracksRegLiveness: true
body: |
; CHECK-LABEL: uncondbranch
bb.0:
successors: %bb.1
liveins: $w0, $w1
B %bb.1
; CHECK-NOT: csel
bb.1:
liveins: $w0
RET undef $lr, implicit $w0
...
---
name: condbranch_fallthrough
tracksRegLiveness: true
body: |
; CHECK-LABEL: condbranch_fallthrough
bb.0:
successors: %bb.1, %bb.2
liveins: $w0, $w1
$wzr = SUBSWrs renamable $w0, renamable $w1, 0, implicit-def $nzcv, implicit-def $nzcv
Bcc 11, %bb.2, implicit $nzcv
; CHECK: b.lt [[BB_LT_T:\.LBB[0-9_]+]]
bb.1:
liveins: $nzcv, $w0
; CHECK: csel x16, x16, xzr, ge
RET undef $lr, implicit $w0
bb.2:
liveins: $nzcv, $w0
; CHECK: csel x16, x16, xzr, lt
RET undef $lr, implicit $w0
...
---
name: condbranch_uncondbranch
tracksRegLiveness: true
body: |
; CHECK-LABEL: condbranch_uncondbranch
bb.0:
successors: %bb.1, %bb.2
liveins: $w0, $w1
$wzr = SUBSWrs renamable $w0, renamable $w1, 0, implicit-def $nzcv, implicit-def $nzcv
Bcc 11, %bb.2, implicit $nzcv
B %bb.1, implicit $nzcv
; CHECK: b.lt [[BB_LT_T:\.LBB[0-9_]+]]
bb.1:
liveins: $nzcv, $w0
; CHECK: csel x16, x16, xzr, ge
RET undef $lr, implicit $w0
bb.2:
liveins: $nzcv, $w0
; CHECK: csel x16, x16, xzr, lt
RET undef $lr, implicit $w0
...
---
name: indirectbranch
tracksRegLiveness: true
body: |
; Check that no instrumentation is done on indirect branches (for now).
; CHECK-LABEL: indirectbranch
bb.0:
successors: %bb.1, %bb.2
liveins: $x0
BR $x0
bb.1:
liveins: $x0
; CHECK-NOT: csel
RET undef $lr, implicit $x0
bb.2:
liveins: $x0
; CHECK-NOT: csel
RET undef $lr, implicit $x0
...
---
name: indirect_call_x17
tracksRegLiveness: true
body: |
bb.0:
liveins: $x17
; CHECK-LABEL: indirect_call_x17
; CHECK: mov x0, sp
; CHECK: and x0, x0, x16
; CHECK: mov sp, x0
; CHECK: blr x17
BLR killed renamable $x17, implicit-def dead $lr, implicit $sp
RET undef $lr, implicit undef $w0
...
---
name: indirect_tailcall_x17
tracksRegLiveness: true
body: |
bb.0:
liveins: $x0
; CHECK-LABEL: indirect_tailcall_x17
; CHECK: mov x1, sp
; CHECK: and x1, x1, x16
; CHECK: mov sp, x1
; CHECK: br x17
$x8 = ADRP target-flags(aarch64-page) @g
$x17 = LDRXui killed $x8, target-flags(aarch64-pageoff, aarch64-nc) @g
TCRETURNri killed $x17, 0, implicit $sp, implicit $x0
...
---
name: indirect_call_lr
tracksRegLiveness: true
body: |
bb.0:
; CHECK-LABEL: indirect_call_lr
; CHECK: mov x1, sp
; CHECK: and x1, x1, x16
; CHECK-NEXT: mov sp, x1
; CHECK-NEXT: blr x30
liveins: $x0, $lr
BLR killed renamable $lr, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def $w0
$w0 = nsw ADDWri killed $w0, 1, 0
RET undef $lr, implicit $w0
...
---
name: RS_cannot_find_available_regs
tracksRegLiveness: true
body: |
bb.0:
; In the rare case when no free temporary register is available for the
; propagate taint-to-sp operation, just put in a full speculation barrier
; (isb+dsb sy) at the start of the basic block. And don't put masks on
; instructions for the rest of the basic block, since speculation in that
; basic block was already done, so no need to do masking.
; CHECK-LABEL: RS_cannot_find_available_regs
; CHECK: dsb sy
; CHECK-NEXT: isb
; CHECK-NEXT: ldr x0, [x0]
; The following 2 instructions come from propagating the taint encoded in
; sp at function entry to x16. It turns out the taint info in x16 is not
; used in this function, so those instructions could be optimized away. An
; optimization for later if it turns out this situation occurs often enough.
; CHECK-NEXT: cmp sp, #0
; CHECK-NEXT: csetm x16, ne
; CHECK-NEXT: ret
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
$x0 = LDRXui killed $x0, 0
RET undef $lr, implicit $x0
...
|