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. 14 define internal void @fused_small_align(i32 %arg) { 15 entry: 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. 44 define internal void @fused_large_align(i32 %arg) { 45 entry: 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. 85 define internal i32 @fused_derived(i32 %arg) { 86 entry: 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 91 block1: 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 96 block2: 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. 123 define internal void @fused_small_align_with_dynamic(i32 %arg) { 124 entry: 125 %a1 = alloca i8, i32 8, align 16 126 br label %next 127 next: 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 170 define internal void @fused_large_align_with_dynamic(i32 %arg) { 171 entry: 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 177 next: 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