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