Home | History | Annotate | Download | only in arm32
      1 ; Tests basics and corner cases of arm32 sandboxing, using -Om1 in the hope that
      2 ; the output will remain stable.  When packing bundles, we try to limit to a few
      3 ; instructions with well known sizes and minimal use of registers and stack
      4 ; slots in the lowering sequence.
      5 
      6 ; REQUIRES: allow_dump, target_ARM32
      7 ; RUN: %p2i -i %s --sandbox --filetype=asm --target=arm32 --assemble \
      8 ; RUN:   --disassemble --args -Om1 -allow-externally-defined-symbols \
      9 ; RUN:   -ffunction-sections -reg-use r0,r1,r3 | FileCheck %s
     10 
     11 declare void @call_target()
     12 declare void @call_target1(i32 %arg0)
     13 declare void @call_target2(i32 %arg0, i32 %arg1)
     14 declare void @call_target3(i32 %arg0, i32 %arg1, i32 %arg2)
     15 @global_short = internal global [2 x i8] zeroinitializer
     16 
     17 ; A direct call sequence uses the right mask and register-call sequence.
     18 define internal void @test_direct_call() {
     19 entry:
     20   call void @call_target()
     21   ; bundle aigned.
     22   ret void
     23 }
     24 
     25 ; CHECK-LABEL:<test_direct_call>:
     26 ;             Search for bundle alignment of first call.
     27 ; CHECK:      {{[0-9a-f]*}}c: {{.*}} bl {{.*}} call_target
     28 
     29 ; Same as above, but force bundle padding by adding three (branch) instruction
     30 ; before the tested call.
     31 define internal void @test_direct_call_with_padding_1() {
     32 entry:
     33   call void @call_target()
     34   ; bundle aigned.
     35 
     36   br label %next1 ; add 1 inst.
     37 next1:
     38   br label %next2 ; add 1 inst.
     39 next2:
     40   call void @call_target()
     41   ret void
     42 }
     43 ; CHECK-LABEL:<test_direct_call_with_padding_1>:
     44 ;             Search for bundle alignment of first call.
     45 ; CHECK:      {{[0-9a-f]*}}c: {{.+}} bl
     46 ; CHECK-NEXT: b
     47 ; CHECK-NEXT: b
     48 ; CHECK-NEXT: nop
     49 ; CHECK-NEXT: bl {{.*}} call_target
     50 ; CHECK-NEXT: {{[0-9a-f]*}}0:
     51 
     52 ; Same as above, but force bundle padding by adding two (branch) instruction
     53 ; before the tested call.
     54 define internal void @test_direct_call_with_padding_2() {
     55 entry:
     56   call void @call_target()
     57   ; bundle aigned.
     58 
     59   br label %next1 ; add 1 inst.
     60 next1:
     61   call void @call_target()
     62   ret void
     63 }
     64 
     65 ; CHECK-LABEL:<test_direct_call_with_padding_2>:
     66 ;             Search for bundle alignment of first call.
     67 ; CHECK:      {{[0-9a-f]*}}c: {{.+}} bl
     68 ; CHECK-NEXT: b
     69 ; CHECK-NEXT: nop
     70 ; CHECK-NEXT: nop
     71 ; CHECK-NEXT: bl {{.*}} call_target
     72 ; CHECK-NEXT: {{[0-9a-f]*}}0:
     73 
     74 ; Same as above, but force bundle padding by adding single (branch) instruction
     75 ; before the tested call.
     76 define internal void @test_direct_call_with_padding_3() {
     77 entry:
     78   call void @call_target()
     79   ; bundle aigned.
     80 
     81   call void @call_target()
     82   ret void
     83 }
     84 
     85 ; CHECK-LABEL:<test_direct_call_with_padding_3>:
     86 ;             Search for bundle alignment of first call.
     87 ; CHECK:      {{[0-9a-f]*}}c: {{.+}} bl
     88 ; CHECK-NEXT: nop
     89 ; CHECK-NEXT: nop
     90 ; CHECK-NEXT: nop
     91 ; CHECK-NEXT: bl {{.*}} call_target
     92 ; CHECK-NEXT: {{[0-9a-f]*}}0:
     93 
     94 ; An indirect call sequence uses the right mask and register-call sequence.
     95 define internal void @test_indirect_call(i32 %target) {
     96 entry:
     97   %__1 = inttoptr i32 %target to void ()*
     98   call void @call_target();
     99   ; bundle aigned.
    100 
    101   br label %next ; add 1 inst.
    102 next:
    103   call void %__1() ; requires 3 insts.
    104   ret void
    105 }
    106 
    107 ; CHECK-LABEL:<test_indirect_call>:
    108 ;             Search for bundle alignment of first call.
    109 ; CHECK:      {{[0-9a-f]*}}c: {{.+}} bl
    110 ; CHECK-NEXT: b
    111 ; CHECK-NEXT: ldr
    112 ; CHECK-NEXT: bic [[REG:r[0-3]]], [[REG]], {{.*}} 0xc000000f
    113 ; CHECK-NEXT: blx [[REG]]
    114 ; CHECK-NEXT: {{[0-9]+}}0:
    115 
    116 ; An indirect call sequence uses the right mask and register-call sequence.
    117 ; Forces bundling before the tested call.
    118 define internal void @test_indirect_call_with_padding_1(i32 %target) {
    119 entry:
    120   %__1 = inttoptr i32 %target to void ()*
    121   call void @call_target();
    122   ; bundle aigned.
    123   call void %__1() ; requires 3 insts.
    124   ret void
    125 }
    126 
    127 ; CHECK-LABEL: <test_indirect_call_with_padding_1>:
    128 ;              Search for bundle alignment of first call.
    129 ; CHECK:      {{[0-9a-f]*}}c: {{.+}} bl
    130 ; CHECK-NEXT: ldr
    131 ; CHECK-NEXT: nop
    132 ; CHECK-NEXT: bic [[REG:r[0-3]]], [[REG]], {{.*}} 0xc000000f
    133 ; CHECK-NEXT: blx [[REG]]
    134 ; CHECK-NEXT: {{[0-9]+}}0:
    135 
    136 ; An indirect call sequence uses the right mask and register-call sequence.
    137 ; Forces bundling by adding three (branch) instructions befor the tested call.
    138 define internal void @test_indirect_call_with_padding_2(i32 %target) {
    139 entry:
    140   %__1 = inttoptr i32 %target to void ()*
    141   call void @call_target();
    142   ; bundle aigned.
    143 
    144   br label %next1 ; add 1 inst.
    145 next1:
    146   br label %next2 ; add 1 inst.
    147 next2:
    148   br label %next3 ; add 1 inst.
    149 next3:
    150   call void %__1() ; requires 3 insts.
    151   ret void
    152 }
    153 
    154 ; CHECK-LABEL: <test_indirect_call_with_padding_2>:
    155 ;              Search for bundle alignment of first call.
    156 ; CHECK:      {{[0-9a-f]*}}c: {{.+}} bl
    157 ; CHECK-NEXT: b
    158 ; CHECK-NEXT: b
    159 ; CHECK-NEXT: b
    160 ; CHECK-NEXT: ldr
    161 ; CHECK-NEXT: nop
    162 ; CHECK-NEXT: nop
    163 ; CHECK-NEXT: bic [[REG:r[0-3]]], [[REG]], {{.*}} 0xc000000f
    164 ; CHECK-NEXT: blx [[REG]]
    165 ; CHECK-NEXT: {{[0-9]+}}0:
    166 
    167 ; An indirect call sequence uses the right mask and register-call sequence.
    168 ; Forces bundling by adding two (branch) instructions befor the tested call.
    169 define internal void @test_indirect_call_with_padding_3(i32 %target) {
    170 entry:
    171   %__1 = inttoptr i32 %target to void ()*
    172   call void @call_target();
    173   ; bundle aigned.
    174 
    175   br label %next1 ; add 1 inst
    176 next1:
    177   br label %next2 ; add 1 inst
    178 next2:
    179   call void %__1() ; requires 3 insts.
    180   ret void
    181 }
    182 ; CHECK-LABEL: <test_indirect_call_with_padding_3>:
    183 ;              Search for bundle alignment of first call.
    184 ; CHECK:      {{[0-9a-f]*}}c: {{.+}} bl
    185 ; CHECK-NEXT: b
    186 ; CHECK-NEXT: b
    187 ; CHECK-NEXT: ldr
    188 ; CHECK-NEXT: nop
    189 ; CHECK-NEXT: nop
    190 ; CHECK-NEXT: nop
    191 ; CHECK-NEXT: bic [[REG:r[0-3]]], [[REG]], {{.*}} 0xc000000f
    192 ; CHECK-NEXT: blx [[REG]]
    193 ; CHECK-NEXT: {{[0-9]+}}0:
    194 
    195 ; A return sequences uses the right pop / mask / jmp sequence.
    196 define internal void @test_ret() {
    197 entry:
    198   call void @call_target()
    199   ; Bundle boundary.
    200   br label %next ; add 1 inst.
    201 next:
    202   ret void
    203 }
    204 ; CHECK-LABEL:<test_ret>:
    205 ;             Search for bundle alignment of first call.
    206 ; CHECK:      {{[0-9a-f]*}}c: {{.+}} bl
    207 ; CHECK-NEXT: b
    208 ; CHECK-NEXT: add sp, sp
    209 ; CHECK-NEXT: bic sp, sp, {{.+}} ; 0xc0000000
    210 ; CHECK-NEXT: pop {lr}
    211 ; CHECK-NEXT: {{[0-9a-f]*}}0: {{.+}} bic lr, lr, {{.+}} ; 0xc000000f
    212 ; CHECK-NEXT: bx lr
    213 
    214 ; A return sequence with padding for bundle lock.
    215 define internal void @test_ret_with_padding() {
    216   call void @call_target()
    217   ; Bundle boundary.
    218   ret void
    219 }
    220 
    221 ; CHECK-LABEL:<test_ret_with_padding>:
    222 ;             Search for bundle alignment of first call.
    223 ; CHECK:      {{[0-9a-f]*}}c: {{.+}} bl
    224 ; CHECK-NEXT: add sp, sp
    225 ; CHECK-NEXT: bic sp, sp, {{.+}} ; 0xc0000000
    226 ; CHECK-NEXT: pop {lr}
    227 ; CHECK-NEXT: nop
    228 ; CHECK-NEXT: {{[0-9a-f]*}}0: {{.+}} bic lr, lr, {{.+}} ; 0xc000000f
    229 ; CHECK-NEXT: bx lr
    230 
    231 ; Store without bundle padding.
    232 define internal void @test_store() {
    233 entry:
    234   call void @call_target()
    235   ; Bundle boundary
    236   store i16 1, i16* undef, align 1   ; 3 insts + bic.
    237   ret void
    238 }
    239 
    240 ; CHECK-LABEL: test_store
    241 ;             Search for call at end of bundle.
    242 ; CHECK:      {{[0-9a-f]*}}c: {{.+}} bl
    243 ; CHECK-NEXT: mov [[REG:r[0-9]]], #0
    244 ; CHECK-NEXT: mov
    245 ; CHECK-NEXT: bic [[REG]], [[REG]], {{.+}} ; 0xc0000000
    246 ; CHECK-NEXT: strh r{{.+}}[[REG]]
    247 
    248 ; Store with bundle padding. Force padding by adding a single branch
    249 ; instruction.
    250 define internal void @test_store_with_padding() {
    251 entry:
    252   call void @call_target()
    253   ; bundle boundary
    254   br label %next ; add 1 inst.
    255 next:
    256   store i16 0, i16* undef, align 1   ; 3 insts
    257   ret void
    258 }
    259 ; CHECK-LABEL: test_store_with_padding
    260 ;             Search for call at end of bundle.
    261 ; CHECK:      {{[0-9a-f]*}}c: {{.+}} bl
    262 ; CHECK-NEXT: b
    263 ; CHECK-NEXT: mov [[REG:r[0-9]]], #0
    264 ; CHECK-NEXT: mov
    265 ; CHECK-NEXT: nop
    266 ; CHECK-NEXT: bic [[REG]], [[REG]], {{.+}} ; 0xc0000000
    267 ; CHECK-NEXT: strh r{{.+}}[[REG]]
    268 
    269 
    270 ; Store without bundle padding.
    271 define internal i32 @test_load() {
    272 entry:
    273   call void @call_target()
    274   ; Bundle boundary
    275   %v = load i32, i32* undef, align 1 ; 4 insts, bundling middle 2.
    276   ret i32 %v
    277 }
    278 
    279 ; CHECK-LABEL: test_load
    280 ;             Search for call at end of bundle.
    281 ; CHECK:      {{[0-9a-f]*}}c: {{.+}} bl
    282 ; CHECK-NEXT: mov [[REG:r[0-9]]], #0
    283 ; CHECK-NEXT: bic [[REG]], [[REG]], {{.+}} ; 0xc0000000
    284 ; CHECK-NEXT: ldr r{{.+}}[[REG]]
    285 
    286 ; Store with bundle padding.
    287 define internal i32 @test_load_with_padding() {
    288 entry:
    289   call void @call_target()
    290   ; Bundle boundary
    291   br label %next1 ; add 1 inst.
    292 next1:
    293   br label %next2 ; add 1 inst.
    294 next2:
    295   %v = load i32, i32* undef, align 1 ; 4 insts, bundling middle 2.
    296   ret i32 %v
    297 }
    298 
    299 ; CHECK-LABEL: test_load_with_padding
    300 ;             Search for call at end of bundle.
    301 ; CHECK:      {{[0-9a-f]*}}c: {{.+}} bl
    302 ; CHECK-NEXT: b
    303 ; CHECK-NEXT: b
    304 ; CHECK-NEXT: mov [[REG:r[0-9]]], #0
    305 ; CHECK-NEXT: nop
    306 ; CHECK-NEXT: bic [[REG]], [[REG]], {{.+}} ; 0xc0000000
    307 ; CHECK-NEXT: ldr r{{.+}}[[REG]]
    308