|  | ; Tests basics and corner cases of arm32 sandboxing, using -Om1 in the hope that | 
|  | ; the output will remain stable.  When packing bundles, we try to limit to a few | 
|  | ; instructions with well known sizes and minimal use of registers and stack | 
|  | ; slots in the lowering sequence. | 
|  |  | 
|  | ; REQUIRES: allow_dump, target_ARM32 | 
|  | ; RUN: %p2i -i %s --sandbox --filetype=asm --target=arm32 --assemble \ | 
|  | ; RUN:   --disassemble --args -Om1 -allow-externally-defined-symbols \ | 
|  | ; RUN:   -ffunction-sections -reg-use r0,r1,r3 | FileCheck %s | 
|  |  | 
|  | declare void @call_target() | 
|  | declare void @call_target1(i32 %arg0) | 
|  | declare void @call_target2(i32 %arg0, i32 %arg1) | 
|  | declare void @call_target3(i32 %arg0, i32 %arg1, i32 %arg2) | 
|  | @global_short = internal global [2 x i8] zeroinitializer | 
|  |  | 
|  | ; A direct call sequence uses the right mask and register-call sequence. | 
|  | define internal void @test_direct_call() { | 
|  | entry: | 
|  | call void @call_target() | 
|  | ; bundle aigned. | 
|  | ret void | 
|  | } | 
|  |  | 
|  | ; CHECK-LABEL:<test_direct_call>: | 
|  | ;             Search for bundle alignment of first call. | 
|  | ; CHECK:      {{[0-9a-f]*}}c: {{.*}} bl {{.*}} call_target | 
|  |  | 
|  | ; Same as above, but force bundle padding by adding three (branch) instruction | 
|  | ; before the tested call. | 
|  | define internal void @test_direct_call_with_padding_1() { | 
|  | entry: | 
|  | call void @call_target() | 
|  | ; bundle aigned. | 
|  |  | 
|  | br label %next1 ; add 1 inst. | 
|  | next1: | 
|  | br label %next2 ; add 1 inst. | 
|  | next2: | 
|  | call void @call_target() | 
|  | ret void | 
|  | } | 
|  | ; CHECK-LABEL:<test_direct_call_with_padding_1>: | 
|  | ;             Search for bundle alignment of first call. | 
|  | ; CHECK:      {{[0-9a-f]*}}c: {{.+}} bl | 
|  | ; CHECK-NEXT: b | 
|  | ; CHECK-NEXT: b | 
|  | ; CHECK-NEXT: nop | 
|  | ; CHECK-NEXT: bl {{.*}} call_target | 
|  | ; CHECK-NEXT: {{[0-9a-f]*}}0: | 
|  |  | 
|  | ; Same as above, but force bundle padding by adding two (branch) instruction | 
|  | ; before the tested call. | 
|  | define internal void @test_direct_call_with_padding_2() { | 
|  | entry: | 
|  | call void @call_target() | 
|  | ; bundle aigned. | 
|  |  | 
|  | br label %next1 ; add 1 inst. | 
|  | next1: | 
|  | call void @call_target() | 
|  | ret void | 
|  | } | 
|  |  | 
|  | ; CHECK-LABEL:<test_direct_call_with_padding_2>: | 
|  | ;             Search for bundle alignment of first call. | 
|  | ; CHECK:      {{[0-9a-f]*}}c: {{.+}} bl | 
|  | ; CHECK-NEXT: b | 
|  | ; CHECK-NEXT: nop | 
|  | ; CHECK-NEXT: nop | 
|  | ; CHECK-NEXT: bl {{.*}} call_target | 
|  | ; CHECK-NEXT: {{[0-9a-f]*}}0: | 
|  |  | 
|  | ; Same as above, but force bundle padding by adding single (branch) instruction | 
|  | ; before the tested call. | 
|  | define internal void @test_direct_call_with_padding_3() { | 
|  | entry: | 
|  | call void @call_target() | 
|  | ; bundle aigned. | 
|  |  | 
|  | call void @call_target() | 
|  | ret void | 
|  | } | 
|  |  | 
|  | ; CHECK-LABEL:<test_direct_call_with_padding_3>: | 
|  | ;             Search for bundle alignment of first call. | 
|  | ; CHECK:      {{[0-9a-f]*}}c: {{.+}} bl | 
|  | ; CHECK-NEXT: nop | 
|  | ; CHECK-NEXT: nop | 
|  | ; CHECK-NEXT: nop | 
|  | ; CHECK-NEXT: bl {{.*}} call_target | 
|  | ; CHECK-NEXT: {{[0-9a-f]*}}0: | 
|  |  | 
|  | ; An indirect call sequence uses the right mask and register-call sequence. | 
|  | define internal void @test_indirect_call(i32 %target) { | 
|  | entry: | 
|  | %__1 = inttoptr i32 %target to void ()* | 
|  | call void @call_target(); | 
|  | ; bundle aigned. | 
|  |  | 
|  | br label %next ; add 1 inst. | 
|  | next: | 
|  | call void %__1() ; requires 3 insts. | 
|  | ret void | 
|  | } | 
|  |  | 
|  | ; CHECK-LABEL:<test_indirect_call>: | 
|  | ;             Search for bundle alignment of first call. | 
|  | ; CHECK:      {{[0-9a-f]*}}c: {{.+}} bl | 
|  | ; CHECK-NEXT: b | 
|  | ; CHECK-NEXT: ldr | 
|  | ; CHECK-NEXT: bic [[REG:r[0-3]]], [[REG]], {{.*}} 0xc000000f | 
|  | ; CHECK-NEXT: blx [[REG]] | 
|  | ; CHECK-NEXT: {{[0-9]+}}0: | 
|  |  | 
|  | ; An indirect call sequence uses the right mask and register-call sequence. | 
|  | ; Forces bundling before the tested call. | 
|  | define internal void @test_indirect_call_with_padding_1(i32 %target) { | 
|  | entry: | 
|  | %__1 = inttoptr i32 %target to void ()* | 
|  | call void @call_target(); | 
|  | ; bundle aigned. | 
|  | call void %__1() ; requires 3 insts. | 
|  | ret void | 
|  | } | 
|  |  | 
|  | ; CHECK-LABEL: <test_indirect_call_with_padding_1>: | 
|  | ;              Search for bundle alignment of first call. | 
|  | ; CHECK:      {{[0-9a-f]*}}c: {{.+}} bl | 
|  | ; CHECK-NEXT: ldr | 
|  | ; CHECK-NEXT: nop | 
|  | ; CHECK-NEXT: bic [[REG:r[0-3]]], [[REG]], {{.*}} 0xc000000f | 
|  | ; CHECK-NEXT: blx [[REG]] | 
|  | ; CHECK-NEXT: {{[0-9]+}}0: | 
|  |  | 
|  | ; An indirect call sequence uses the right mask and register-call sequence. | 
|  | ; Forces bundling by adding three (branch) instructions befor the tested call. | 
|  | define internal void @test_indirect_call_with_padding_2(i32 %target) { | 
|  | entry: | 
|  | %__1 = inttoptr i32 %target to void ()* | 
|  | call void @call_target(); | 
|  | ; bundle aigned. | 
|  |  | 
|  | br label %next1 ; add 1 inst. | 
|  | next1: | 
|  | br label %next2 ; add 1 inst. | 
|  | next2: | 
|  | br label %next3 ; add 1 inst. | 
|  | next3: | 
|  | call void %__1() ; requires 3 insts. | 
|  | ret void | 
|  | } | 
|  |  | 
|  | ; CHECK-LABEL: <test_indirect_call_with_padding_2>: | 
|  | ;              Search for bundle alignment of first call. | 
|  | ; CHECK:      {{[0-9a-f]*}}c: {{.+}} bl | 
|  | ; CHECK-NEXT: b | 
|  | ; CHECK-NEXT: b | 
|  | ; CHECK-NEXT: b | 
|  | ; CHECK-NEXT: ldr | 
|  | ; CHECK-NEXT: nop | 
|  | ; CHECK-NEXT: nop | 
|  | ; CHECK-NEXT: bic [[REG:r[0-3]]], [[REG]], {{.*}} 0xc000000f | 
|  | ; CHECK-NEXT: blx [[REG]] | 
|  | ; CHECK-NEXT: {{[0-9]+}}0: | 
|  |  | 
|  | ; An indirect call sequence uses the right mask and register-call sequence. | 
|  | ; Forces bundling by adding two (branch) instructions befor the tested call. | 
|  | define internal void @test_indirect_call_with_padding_3(i32 %target) { | 
|  | entry: | 
|  | %__1 = inttoptr i32 %target to void ()* | 
|  | call void @call_target(); | 
|  | ; bundle aigned. | 
|  |  | 
|  | br label %next1 ; add 1 inst | 
|  | next1: | 
|  | br label %next2 ; add 1 inst | 
|  | next2: | 
|  | call void %__1() ; requires 3 insts. | 
|  | ret void | 
|  | } | 
|  | ; CHECK-LABEL: <test_indirect_call_with_padding_3>: | 
|  | ;              Search for bundle alignment of first call. | 
|  | ; CHECK:      {{[0-9a-f]*}}c: {{.+}} bl | 
|  | ; CHECK-NEXT: b | 
|  | ; CHECK-NEXT: b | 
|  | ; CHECK-NEXT: ldr | 
|  | ; CHECK-NEXT: nop | 
|  | ; CHECK-NEXT: nop | 
|  | ; CHECK-NEXT: nop | 
|  | ; CHECK-NEXT: bic [[REG:r[0-3]]], [[REG]], {{.*}} 0xc000000f | 
|  | ; CHECK-NEXT: blx [[REG]] | 
|  | ; CHECK-NEXT: {{[0-9]+}}0: | 
|  |  | 
|  | ; A return sequences uses the right pop / mask / jmp sequence. | 
|  | define internal void @test_ret() { | 
|  | entry: | 
|  | call void @call_target() | 
|  | ; Bundle boundary. | 
|  | br label %next ; add 1 inst. | 
|  | next: | 
|  | ret void | 
|  | } | 
|  | ; CHECK-LABEL:<test_ret>: | 
|  | ;             Search for bundle alignment of first call. | 
|  | ; CHECK:      {{[0-9a-f]*}}c: {{.+}} bl | 
|  | ; CHECK-NEXT: b | 
|  | ; CHECK-NEXT: add sp, sp | 
|  | ; CHECK-NEXT: bic sp, sp, {{.+}} ; 0xc0000000 | 
|  | ; CHECK-NEXT: pop {lr} | 
|  | ; CHECK-NEXT: {{[0-9a-f]*}}0: {{.+}} bic lr, lr, {{.+}} ; 0xc000000f | 
|  | ; CHECK-NEXT: bx lr | 
|  |  | 
|  | ; A return sequence with padding for bundle lock. | 
|  | define internal void @test_ret_with_padding() { | 
|  | call void @call_target() | 
|  | ; Bundle boundary. | 
|  | ret void | 
|  | } | 
|  |  | 
|  | ; CHECK-LABEL:<test_ret_with_padding>: | 
|  | ;             Search for bundle alignment of first call. | 
|  | ; CHECK:      {{[0-9a-f]*}}c: {{.+}} bl | 
|  | ; CHECK-NEXT: add sp, sp | 
|  | ; CHECK-NEXT: bic sp, sp, {{.+}} ; 0xc0000000 | 
|  | ; CHECK-NEXT: pop {lr} | 
|  | ; CHECK-NEXT: nop | 
|  | ; CHECK-NEXT: {{[0-9a-f]*}}0: {{.+}} bic lr, lr, {{.+}} ; 0xc000000f | 
|  | ; CHECK-NEXT: bx lr | 
|  |  | 
|  | ; Store without bundle padding. | 
|  | define internal void @test_store() { | 
|  | entry: | 
|  | call void @call_target() | 
|  | ; Bundle boundary | 
|  | store i16 1, i16* undef, align 1   ; 3 insts + bic. | 
|  | ret void | 
|  | } | 
|  |  | 
|  | ; CHECK-LABEL: test_store | 
|  | ;             Search for call at end of bundle. | 
|  | ; CHECK:      {{[0-9a-f]*}}c: {{.+}} bl | 
|  | ; CHECK-NEXT: mov [[REG:r[0-9]]], #0 | 
|  | ; CHECK-NEXT: mov | 
|  | ; CHECK-NEXT: bic [[REG]], [[REG]], {{.+}} ; 0xc0000000 | 
|  | ; CHECK-NEXT: strh r{{.+}}[[REG]] | 
|  |  | 
|  | ; Store with bundle padding. Force padding by adding a single branch | 
|  | ; instruction. | 
|  | define internal void @test_store_with_padding() { | 
|  | entry: | 
|  | call void @call_target() | 
|  | ; bundle boundary | 
|  | br label %next ; add 1 inst. | 
|  | next: | 
|  | store i16 0, i16* undef, align 1   ; 3 insts | 
|  | ret void | 
|  | } | 
|  | ; CHECK-LABEL: test_store_with_padding | 
|  | ;             Search for call at end of bundle. | 
|  | ; CHECK:      {{[0-9a-f]*}}c: {{.+}} bl | 
|  | ; CHECK-NEXT: b | 
|  | ; CHECK-NEXT: mov [[REG:r[0-9]]], #0 | 
|  | ; CHECK-NEXT: mov | 
|  | ; CHECK-NEXT: nop | 
|  | ; CHECK-NEXT: bic [[REG]], [[REG]], {{.+}} ; 0xc0000000 | 
|  | ; CHECK-NEXT: strh r{{.+}}[[REG]] | 
|  |  | 
|  |  | 
|  | ; Store without bundle padding. | 
|  | define internal i32 @test_load() { | 
|  | entry: | 
|  | call void @call_target() | 
|  | ; Bundle boundary | 
|  | %v = load i32, i32* undef, align 1 ; 4 insts, bundling middle 2. | 
|  | ret i32 %v | 
|  | } | 
|  |  | 
|  | ; CHECK-LABEL: test_load | 
|  | ;             Search for call at end of bundle. | 
|  | ; CHECK:      {{[0-9a-f]*}}c: {{.+}} bl | 
|  | ; CHECK-NEXT: mov [[REG:r[0-9]]], #0 | 
|  | ; CHECK-NEXT: bic [[REG]], [[REG]], {{.+}} ; 0xc0000000 | 
|  | ; CHECK-NEXT: ldr r{{.+}}[[REG]] | 
|  |  | 
|  | ; Store with bundle padding. | 
|  | define internal i32 @test_load_with_padding() { | 
|  | entry: | 
|  | call void @call_target() | 
|  | ; Bundle boundary | 
|  | br label %next1 ; add 1 inst. | 
|  | next1: | 
|  | br label %next2 ; add 1 inst. | 
|  | next2: | 
|  | %v = load i32, i32* undef, align 1 ; 4 insts, bundling middle 2. | 
|  | ret i32 %v | 
|  | } | 
|  |  | 
|  | ; CHECK-LABEL: test_load_with_padding | 
|  | ;             Search for call at end of bundle. | 
|  | ; CHECK:      {{[0-9a-f]*}}c: {{.+}} bl | 
|  | ; CHECK-NEXT: b | 
|  | ; CHECK-NEXT: b | 
|  | ; CHECK-NEXT: mov [[REG:r[0-9]]], #0 | 
|  | ; CHECK-NEXT: nop | 
|  | ; CHECK-NEXT: bic [[REG]], [[REG]], {{.+}} ; 0xc0000000 | 
|  | ; CHECK-NEXT: ldr r{{.+}}[[REG]] |