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