1; RUN: llc < %s -mtriple=thumbv6-apple-darwin | FileCheck %s
2; RUN: llc < %s -mtriple=thumbv6-apple-darwin -regalloc=basic | FileCheck %s
3; RUN: llc < %s -o %t -filetype=obj -mtriple=thumbv6-apple-darwin
4; RUN: llvm-objdump -triple=thumbv6-apple-darwin -d %t | FileCheck %s
5
6@__bar = external hidden global i8*
7@__baz = external hidden global i8*
8
9; rdar://8819685
10define i8* @_foo() {
11entry:
12; CHECK-LABEL: foo:
13
14	%size = alloca i32, align 4
15	%0 = load i8** @__bar, align 4
16	%1 = icmp eq i8* %0, null
17	br i1 %1, label %bb1, label %bb3
18; CHECK: bne
19
20bb1:
21	store i32 1026, i32* %size, align 4
22	%2 = alloca [1026 x i8], align 1
23; CHECK: mov     [[R0:r[0-9]+]], sp
24; CHECK: adds    {{r[0-9]+}}, [[R0]], {{r[0-9]+}}
25	%3 = getelementptr inbounds [1026 x i8]* %2, i32 0, i32 0
26	%4 = call i32 @_called_func(i8* %3, i32* %size) nounwind
27	%5 = icmp eq i32 %4, 0
28	br i1 %5, label %bb2, label %bb3
29
30bb2:
31	%6 = call i8* @strdup(i8* %3) nounwind
32	store i8* %6, i8** @__baz, align 4
33	br label %bb3
34
35bb3:
36	%.0 = phi i8* [ %0, %entry ], [ %6, %bb2 ], [ %3, %bb1 ]
37; CHECK: subs    r4, #5
38; CHECK-NEXT: mov     sp, r4
39; CHECK-NEXT: pop     {r4, r5, r6, r7, pc}
40	ret i8* %.0
41}
42
43declare noalias i8* @strdup(i8* nocapture) nounwind
44declare i32 @_called_func(i8*, i32*) nounwind
45
46; Variable ending up at unaligned offset from sp (i.e. not a multiple of 4)
47define void @test_local_var_addr() {
48; CHECK-LABEL: test_local_var_addr:
49
50  %addr1 = alloca i8
51  %addr2 = alloca i8
52
53; CHECK: mov r0, sp
54; CHECK: adds r0, #{{[0-9]+}}
55; CHECK: blx
56  call void @take_ptr(i8* %addr1)
57
58; CHECK: mov r0, sp
59; CHECK: adds r0, #{{[0-9]+}}
60; CHECK: blx
61  call void @take_ptr(i8* %addr2)
62
63  ret void
64}
65
66; Simple variable ending up *at* sp.
67define void @test_simple_var() {
68; CHECK-LABEL: test_simple_var:
69
70  %addr32 = alloca i32
71  %addr8 = bitcast i32* %addr32 to i8*
72
73; CHECK: mov r0, sp
74; CHECK-NOT: adds r0
75; CHECK: blx
76  call void @take_ptr(i8* %addr8)
77  ret void
78}
79
80; Simple variable ending up at aligned offset from sp.
81define void @test_local_var_addr_aligned() {
82; CHECK-LABEL: test_local_var_addr_aligned:
83
84  %addr1.32 = alloca i32
85  %addr1 = bitcast i32* %addr1.32 to i8*
86  %addr2.32 = alloca i32
87  %addr2 = bitcast i32* %addr2.32 to i8*
88
89; CHECK: add r0, sp, #{{[0-9]+}}
90; CHECK: blx
91  call void @take_ptr(i8* %addr1)
92
93; CHECK: mov r0, sp
94; CHECK-NOT: add r0
95; CHECK: blx
96  call void @take_ptr(i8* %addr2)
97
98  ret void
99}
100
101; Simple variable ending up at aligned offset from sp.
102define void @test_local_var_big_offset() {
103; CHECK-LABEL: test_local_var_big_offset:
104  %addr1.32 = alloca i32, i32 257
105  %addr1 = bitcast i32* %addr1.32 to i8*
106  %addr2.32 = alloca i32, i32 257
107
108; CHECK: add [[RTMP:r[0-9]+]], sp, #1020
109; CHECK: adds [[RTMP]], #8
110; CHECK: blx
111  call void @take_ptr(i8* %addr1)
112
113  ret void
114}
115
116; Max range addressable with tADDrSPi
117define void @test_local_var_offset_1020() {
118; CHECK-LABEL: test_local_var_offset_1020
119  %addr1 = alloca i8, i32 4
120  %addr2 = alloca i8, i32 1020
121
122; CHECK: add r0, sp, #1020
123; CHECK-NEXT: blx
124  call void @take_ptr(i8* %addr1)
125
126  ret void
127}
128
129; Max range addressable with tADDrSPi + tADDi8
130define void @test_local_var_offset_1275() {
131; CHECK-LABEL: test_local_var_offset_1275
132  %addr1 = alloca i8, i32 1
133  %addr2 = alloca i8, i32 1275
134
135; CHECK: add r0, sp, #1020
136; CHECK: adds r0, #255
137; CHECK-NEXT: blx
138  call void @take_ptr(i8* %addr1)
139
140  ret void
141}
142
143declare void @take_ptr(i8*)
144