reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    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 --dump-input-on-failure

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