| # 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 |
| ... |