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 11declare void @call_target() 12declare void @call_target1(i32 %arg0) 13declare void @call_target2(i32 %arg0, i32 %arg1) 14declare 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. 18define internal void @test_direct_call() { 19entry: 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. 31define internal void @test_direct_call_with_padding_1() { 32entry: 33 call void @call_target() 34 ; bundle aigned. 35 36 br label %next1 ; add 1 inst. 37next1: 38 br label %next2 ; add 1 inst. 39next2: 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. 54define internal void @test_direct_call_with_padding_2() { 55entry: 56 call void @call_target() 57 ; bundle aigned. 58 59 br label %next1 ; add 1 inst. 60next1: 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. 76define internal void @test_direct_call_with_padding_3() { 77entry: 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. 95define internal void @test_indirect_call(i32 %target) { 96entry: 97 %__1 = inttoptr i32 %target to void ()* 98 call void @call_target(); 99 ; bundle aigned. 100 101 br label %next ; add 1 inst. 102next: 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. 118define internal void @test_indirect_call_with_padding_1(i32 %target) { 119entry: 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. 138define internal void @test_indirect_call_with_padding_2(i32 %target) { 139entry: 140 %__1 = inttoptr i32 %target to void ()* 141 call void @call_target(); 142 ; bundle aigned. 143 144 br label %next1 ; add 1 inst. 145next1: 146 br label %next2 ; add 1 inst. 147next2: 148 br label %next3 ; add 1 inst. 149next3: 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. 169define internal void @test_indirect_call_with_padding_3(i32 %target) { 170entry: 171 %__1 = inttoptr i32 %target to void ()* 172 call void @call_target(); 173 ; bundle aigned. 174 175 br label %next1 ; add 1 inst 176next1: 177 br label %next2 ; add 1 inst 178next2: 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. 196define internal void @test_ret() { 197entry: 198 call void @call_target() 199 ; Bundle boundary. 200 br label %next ; add 1 inst. 201next: 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. 215define 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. 232define internal void @test_store() { 233entry: 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. 250define internal void @test_store_with_padding() { 251entry: 252 call void @call_target() 253 ; bundle boundary 254 br label %next ; add 1 inst. 255next: 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. 271define internal i32 @test_load() { 272entry: 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. 287define internal i32 @test_load_with_padding() { 288entry: 289 call void @call_target() 290 ; Bundle boundary 291 br label %next1 ; add 1 inst. 292next1: 293 br label %next2 ; add 1 inst. 294next2: 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