1; This is a basic test of the alloca instruction.
2
3; RUN: %if --need=target_X8632 --command %p2i --filetype=obj --disassemble \
4; RUN:   --target x8632 -i %s --args -O2 -allow-externally-defined-symbols \
5; RUN:   | %if --need=target_X8632 --command FileCheck %s
6
7; RUN: %if --need=target_MIPS32 --need=allow_dump \
8; RUN:   --command %p2i --filetype=asm --assemble --disassemble --target \
9; RUN:   mips32 -i %s --args -O2 -allow-externally-defined-symbols \
10; RUN:   | %if --need=target_MIPS32 --need=allow_dump \
11; RUN:   --command FileCheck --check-prefix MIPS32 %s
12
13; Test that a sequence of allocas with less than stack alignment get fused.
14define internal void @fused_small_align(i32 %arg) {
15entry:
16  %a1 = alloca i8, i32 8, align 4
17  %a2 = alloca i8, i32 12, align 4
18  %a3 = alloca i8, i32 16, align 8
19  %p1 = bitcast i8* %a1 to i32*
20  %p2 = bitcast i8* %a2 to i32*
21  %p3 = bitcast i8* %a3 to i32*
22  store i32 %arg, i32* %p1, align 1
23  store i32 %arg, i32* %p2, align 1
24  store i32 %arg, i32* %p3, align 1
25  ret void
26}
27; CHECK-LABEL: fused_small_align
28; CHECK-NEXT: sub    esp,0x3c
29; CHECK-NEXT: mov    eax,DWORD PTR [esp+0x40]
30; CHECK-NEXT: mov    DWORD PTR [esp+0x10],eax
31; CHECK-NEXT: mov    DWORD PTR [esp+0x18],eax
32; CHECK-NEXT: mov    DWORD PTR [esp],eax
33; CHECK-NEXT: add    esp,0x3c
34; MIPS32-LABEL: fused_small_align
35; MIPS32: 	addiu	sp,sp,{{.*}}
36; MIPS32: 	move	v0,a0
37; MIPS32: 	sw	v0,{{.*}}(sp)
38; MIPS32: 	move	v0,a0
39; MIPS32: 	sw	v0,{{.*}}(sp)
40; MIPS32: 	sw	a0,{{.*}}(sp)
41; MIPS32: 	addiu	sp,sp,{{.*}}
42
43; Test that a sequence of allocas with greater than stack alignment get fused.
44define internal void @fused_large_align(i32 %arg) {
45entry:
46  %a1 = alloca i8, i32 8, align 32
47  %a2 = alloca i8, i32 12, align 64
48  %a3 = alloca i8, i32 16, align 32
49  %p1 = bitcast i8* %a1 to i32*
50  %p2 = bitcast i8* %a2 to i32*
51  %p3 = bitcast i8* %a3 to i32*
52  store i32 %arg, i32* %p1, align 1
53  store i32 %arg, i32* %p2, align 1
54  store i32 %arg, i32* %p3, align 1
55  ret void
56}
57; CHECK-LABEL: fused_large_align
58; CHECK-NEXT: push   ebp
59; CHECK-NEXT: mov    ebp,esp
60; CHECK-NEXT: sub    esp,0xb8
61; CHECK-NEXT: and    esp,0xffffffc0
62; CHECK-NEXT: mov    eax,DWORD PTR [ebp+0x8]
63; CHECK-NEXT: mov    DWORD PTR [esp+0x40],eax
64; CHECK-NEXT: mov    DWORD PTR [esp],eax
65; CHECK-NEXT: mov    DWORD PTR [esp+0x60],eax
66; CHECK-NEXT: mov    esp,ebp
67; CHECK-NEXT: pop    ebp
68; MIPS32-LABEL: fused_large_align
69; MIPS32: 	addiu	sp,sp,{{.*}}
70; MIPS32: 	sw	s8,{{.*}}(sp)
71; MIPS32: 	move	s8,sp
72; MIPS32: 	move	v0,a0
73; MIPS32: 	sw	v0,{{.*}}(sp)
74; MIPS32: 	move	v0,a0
75; MIPS32: 	sw	v0,{{.*}}(sp)
76; MIPS32: 	sw	a0,{{.*}}(sp)
77; MIPS32: 	move	sp,s8
78; MIPS32: 	lw	s8,{{.*}}(sp)
79; MIPS32: 	addiu	sp,sp,{{.*}}
80
81; Test that an interior pointer into a rematerializable variable is also
82; rematerializable, and test that it is detected even when the use appears
83; syntactically before the definition.  Test that it is folded into mem
84; operands, and also rematerializable through an lea instruction for direct use.
85define internal i32 @fused_derived(i32 %arg) {
86entry:
87  %a1 = alloca i8, i32 128, align 4
88  %a2 = alloca i8, i32 128, align 4
89  %a3 = alloca i8, i32 128, align 4
90  br label %block2
91block1:
92  %a2_i32 = bitcast i8* %a2 to i32*
93  store i32 %arg, i32* %a2_i32, align 1
94  store i32 %arg, i32* %derived, align 1
95  ret i32 %retval
96block2:
97; The following are all rematerializable variables deriving from %a2.
98  %p2 = ptrtoint i8* %a2 to i32
99  %d = add i32 %p2, 12
100  %retval = add i32 %p2, 1
101  %derived = inttoptr i32 %d to i32*
102  br label %block1
103}
104; CHECK-LABEL: fused_derived
105; CHECK-NEXT: sub    esp,0x18c
106; CHECK-NEXT: mov    [[ARG:e..]],DWORD PTR [esp+0x190]
107; CHECK-NEXT: jmp
108; CHECK-NEXT: mov    DWORD PTR [esp+0x80],[[ARG]]
109; CHECK-NEXT: mov    DWORD PTR [esp+0x8c],[[ARG]]
110; CHECK-NEXT: lea    eax,[esp+0x81]
111; CHECK-NEXT: add    esp,0x18c
112; CHECK-NEXT: ret
113; MIPS32-LABEL: fused_derived
114; MIPS32: 	addiu	sp,sp,{{.*}}
115; MIPS32: 	b
116; MIPS32: 	move	v0,a0
117; MIPS32: 	sw	v0,{{.*}}(sp)
118; MIPS32: 	sw	a0,{{.*}}(sp)
119; MIPS32: 	addiu	v0,sp,129
120; MIPS32: 	addiu	sp,sp,{{.*}}
121
122; Test that a fixed alloca gets referenced by the frame pointer.
123define internal void @fused_small_align_with_dynamic(i32 %arg) {
124entry:
125  %a1 = alloca i8, i32 8, align 16
126  br label %next
127next:
128  %a2 = alloca i8, i32 12, align 1
129  %a3 = alloca i8, i32 16, align 1
130  %p1 = bitcast i8* %a1 to i32*
131  %p2 = bitcast i8* %a2 to i32*
132  %p3 = bitcast i8* %a3 to i32*
133  store i32 %arg, i32* %p1, align 1
134  store i32 %arg, i32* %p2, align 1
135  store i32 %arg, i32* %p3, align 1
136  ret void
137}
138; CHECK-LABEL: fused_small_align_with_dynamic
139; CHECK-NEXT: push   ebp
140; CHECK-NEXT: mov    ebp,esp
141; CHECK-NEXT: sub    esp,0x18
142; CHECK-NEXT: mov    eax,DWORD PTR [ebp+0x8]
143; CHECK-NEXT: sub    esp,0x10
144; CHECK-NEXT: mov    ecx,esp
145; CHECK-NEXT: sub    esp,0x10
146; CHECK-NEXT: mov    edx,esp
147; CHECK-NEXT: mov    DWORD PTR [ebp-0x18],eax
148; CHECK-NEXT: mov    DWORD PTR [ecx],eax
149; CHECK-NEXT: mov    DWORD PTR [edx],eax
150; CHECK-NEXT: mov    esp,ebp
151; CHECK-NEXT: pop    ebp
152; MIPS32-LABEL: fused_small_align_with_dynamic
153; MIPS32: 	addiu	sp,sp,{{.*}}
154; MIPS32: 	sw	s8,{{.*}}(sp)
155; MIPS32: 	move	s8,sp
156; MIPS32: 	addiu	v0,sp,0
157; MIPS32: 	addiu	v1,sp,16
158; MIPS32: 	move	a1,a0
159; MIPS32: 	sw	a1,32(s8)
160; MIPS32: 	move	a1,a0
161; MIPS32: 	sw	a1,0(v0)
162; MIPS32: 	sw	a0,0(v1)
163; MIPS32: 	move	sp,s8
164; MIPS32: 	lw	s8,{{.*}}(sp)
165; MIPS32: 	addiu	sp,sp,{{.*}}
166
167; Test that a sequence with greater than stack alignment and dynamic size
168; get folded and referenced correctly;
169
170define internal void @fused_large_align_with_dynamic(i32 %arg) {
171entry:
172  %a1 = alloca i8, i32 8, align 32
173  %a2 = alloca i8, i32 12, align 32
174  %a3 = alloca i8, i32 16, align 1
175  %a4 = alloca i8, i32 16, align 1
176  br label %next
177next:
178  %a5 = alloca i8, i32 16, align 1
179  %p1 = bitcast i8* %a1 to i32*
180  %p2 = bitcast i8* %a2 to i32*
181  %p3 = bitcast i8* %a3 to i32*
182  %p4 = bitcast i8* %a4 to i32*
183  %p5 = bitcast i8* %a5 to i32*
184  store i32 %arg, i32* %p1, align 1
185  store i32 %arg, i32* %p2, align 1
186  store i32 %arg, i32* %p3, align 1
187  store i32 %arg, i32* %p4, align 1
188  store i32 %arg, i32* %p5, align 1
189  ret void
190}
191; CHECK-LABEL: fused_large_align_with_dynamic
192; CHECK-NEXT: push   ebx
193; CHECK-NEXT: push   ebp
194; CHECK-NEXT: mov    ebp,esp
195; CHECK-NEXT: sub    esp,0x24
196; CHECK-NEXT: mov    eax,DWORD PTR [ebp+0xc]
197; CHECK-NEXT: and    esp,0xffffffe0
198; CHECK-NEXT: sub    esp,0x40
199; CHECK-NEXT: mov    ecx,esp
200; CHECK-NEXT: mov    edx,ecx
201; CHECK-NEXT: add    ecx,0x20
202; CHECK-NEXT: add    edx,0x0
203; CHECK-NEXT: sub    esp,0x10
204; CHECK-NEXT: mov    ebx,esp
205; CHECK-NEXT: mov    DWORD PTR [edx],eax
206; CHECK-NEXT: mov    DWORD PTR [ecx],eax
207; CHECK-NEXT: mov    DWORD PTR [ebp-0x14],eax
208; CHECK-NEXT: mov    DWORD PTR [ebp-0x24],eax
209; CHECK-NEXT: mov    DWORD PTR [ebx],eax
210; CHECK-NEXT: mov    esp,ebp
211; CHECK-NEXT: pop    ebp
212; MIPS32-LABEL: fused_large_align_with_dynamic
213; MIPS32: 	addiu	sp,sp,{{.*}}
214; MIPS32: 	sw	s8,{{.*}}(sp)
215; MIPS32: 	move	s8,sp
216; MIPS32: 	addiu	v0,sp,0
217; MIPS32: 	addiu	v1,sp,64
218; MIPS32: 	move	a1,v0
219; MIPS32: 	move	a2,a0
220; MIPS32: 	sw	a2,0(a1)
221; MIPS32: 	move	a1,a0
222; MIPS32: 	sw	a1,32(v0)
223; MIPS32: 	move	v0,a0
224; MIPS32: 	sw	v0,80(s8)
225; MIPS32: 	move	v0,a0
226; MIPS32: 	sw	v0,96(s8)
227; MIPS32: 	sw	a0,0(v1)
228; MIPS32: 	move	sp,s8
229; MIPS32: 	lw	s8,{{.*}}(sp)
230; MIPS32: 	addiu	sp,sp,{{.*}}
231