; This is a basic test of the alloca instruction. ; RUN: %if --need=target_X8632 --command %p2i --filetype=obj --disassemble \ ; RUN: --target x8632 -i %s --args -O2 -allow-externally-defined-symbols \ ; RUN: | %if --need=target_X8632 --command FileCheck %s ; RUN: %if --need=target_X8632 --command %p2i --filetype=obj --disassemble \ ; RUN: --target x8632 -i %s --args -Om1 -allow-externally-defined-symbols \ ; RUN: | %if --need=target_X8632 --command FileCheck \ ; RUN: --check-prefix CHECK-OPTM1 %s ; RUN: %if --need=target_ARM32 \ ; RUN: --command %p2i --filetype=obj \ ; RUN: --disassemble --target arm32 -i %s --args -O2 \ ; RUN: -allow-externally-defined-symbols \ ; RUN: | %if --need=target_ARM32 \ ; RUN: --command FileCheck --check-prefix ARM32 --check-prefix=ARM-OPT2 %s ; RUN: %if --need=target_ARM32 \ ; RUN: --command %p2i --filetype=obj \ ; RUN: --disassemble --target arm32 -i %s --args -Om1 \ ; RUN: -allow-externally-defined-symbols \ ; RUN: | %if --need=target_ARM32 \ ; RUN: --command FileCheck --check-prefix ARM32 --check-prefix=ARM-OPTM1 %s ; RUN: %if --need=target_MIPS32 --need=allow_dump \ ; RUN: --command %p2i --filetype=asm --assemble \ ; RUN: --disassemble --target mips32 -i %s --args -O2 \ ; RUN: -allow-externally-defined-symbols \ ; RUN: | %if --need=target_MIPS32 --need=allow_dump \ ; RUN: --command FileCheck --check-prefix MIPS32 --check-prefix=MIPS32-OPT2 %s ; RUN: %if --need=target_MIPS32 --need=allow_dump \ ; RUN: --command %p2i --filetype=asm --assemble \ ; RUN: --disassemble --target mips32 -i %s --args -Om1 \ ; RUN: -allow-externally-defined-symbols \ ; RUN: | %if --need=target_MIPS32 --need=allow_dump \ ; RUN: --command FileCheck --check-prefix MIPS32 --check-prefix=MIPS32-OPTM1 %s define internal void @fixed_416_align_16(i32 %n) { entry: %array = alloca i8, i32 416, align 16 %__2 = ptrtoint i8* %array to i32 call void @f1(i32 %__2) ret void } ; CHECK-LABEL: fixed_416_align_16 ; CHECK: sub esp,0x1bc ; CHECK: lea eax,[esp+0x10] ; CHECK: mov DWORD PTR [esp],eax ; CHECK: call {{.*}} R_{{.*}} f1 ; CHECK-OPTM1-LABEL: fixed_416_align_16 ; CHECK-OPTM1: sub esp,0x18 ; CHECK-OPTM1: sub esp,0x1a0 ; CHECK-OPTM1: mov DWORD PTR [esp],eax ; CHECK-OPTM1: call {{.*}} R_{{.*}} f1 ; ARM32-LABEL: fixed_416_align_16 ; ARM32-OPT2: sub sp, sp, #428 ; ARM32-OPTM1: sub sp, sp, #416 ; ARM32: bl {{.*}} R_{{.*}} f1 ; MIPS32-LABEL: fixed_416_align_16 ; MIPS32-OPT2: addiu sp,sp,-448 ; MIPS32-OPT2: addiu a0,sp,16 ; MIPS32-OPTM1: addiu sp,sp,-464 ; MIPS32-OPTM1: addiu [[REG:.*]],sp,16 ; MIPS32-OPTM1: sw [[REG]],{{.*}} ; MIPS32-OPTM1: lw a0,{{.*}} ; MIPS32: jal {{.*}} R_{{.*}} f1 define internal void @fixed_416_align_32(i32 %n) { entry: %array = alloca i8, i32 400, align 32 %__2 = ptrtoint i8* %array to i32 call void @f1(i32 %__2) ret void } ; CHECK-LABEL: fixed_416_align_32 ; CHECK: push ebp ; CHECK-NEXT: mov ebp,esp ; CHECK: sub esp,0x1d8 ; CHECK: and esp,0xffffffe0 ; CHECK: lea eax,[esp+0x10] ; CHECK: mov DWORD PTR [esp],eax ; CHECK: call {{.*}} R_{{.*}} f1 ; ARM32-LABEL: fixed_416_align_32 ; ARM32-OPT2: sub sp, sp, #424 ; ARM32-OPTM1: sub sp, sp, #416 ; ARM32: bic sp, sp, #31 ; ARM32: bl {{.*}} R_{{.*}} f1 ; MIPS32-LABEL: fixed_416_align_32 ; MIPS32-OPT2: addiu sp,sp,-448 ; MIPS32-OPT2: addiu a0,sp,16 ; MIPS32-OPTM1: addiu sp,sp,-464 ; MIPS32-OPTM1: addiu [[REG:.*]],sp,32 ; MIPS32-OPTM1: sw [[REG]],{{.*}} ; MIPS32-OPTM1: lw a0,{{.*}} ; MIPS32: jal {{.*}} R_{{.*}} f1 ; Show that the amount to allocate will be rounded up. define internal void @fixed_351_align_16(i32 %n) { entry: %array = alloca i8, i32 351, align 16 %__2 = ptrtoint i8* %array to i32 call void @f1(i32 %__2) ret void } ; CHECK-LABEL: fixed_351_align_16 ; CHECK: sub esp,0x17c ; CHECK: lea eax,[esp+0x10] ; CHECK: mov DWORD PTR [esp],eax ; CHECK: call {{.*}} R_{{.*}} f1 ; CHECK-OPTM1-LABEL: fixed_351_align_16 ; CHECK-OPTM1: sub esp,0x18 ; CHECK-OPTM1: sub esp,0x160 ; CHECK-OPTM1: mov DWORD PTR [esp],eax ; CHECK-OPTM1: call {{.*}} R_{{.*}} f1 ; ARM32-LABEL: fixed_351_align_16 ; ARM32-OPT2: sub sp, sp, #364 ; ARM32-OPTM1: sub sp, sp, #352 ; ARM32: bl {{.*}} R_{{.*}} f1 ; MIPS32-LABEL: fixed_351_align_16 ; MIPS32-OPT2: addiu sp,sp,-384 ; MIPS32-OPT2: addiu a0,sp,16 ; MIPS32-OPTM1: addiu sp,sp,-400 ; MIPS32-OPTM1: addiu [[REG:.*]],sp,16 ; MIPS32-OPTM1: sw [[REG]],{{.*}} ; MIPS32-OPTM1: lw a0,{{.*}} ; MIPS32: jal {{.*}} R_{{.*}} f1 define internal void @fixed_351_align_32(i32 %n) { entry: %array = alloca i8, i32 351, align 32 %__2 = ptrtoint i8* %array to i32 call void @f1(i32 %__2) ret void } ; CHECK-LABEL: fixed_351_align_32 ; CHECK: push ebp ; CHECK-NEXT: mov ebp,esp ; CHECK: sub esp,0x198 ; CHECK: and esp,0xffffffe0 ; CHECK: lea eax,[esp+0x10] ; CHECK: mov DWORD PTR [esp],eax ; CHECK: call {{.*}} R_{{.*}} f1 ; ARM32-LABEL: fixed_351_align_32 ; ARM32-OPT2: sub sp, sp, #360 ; ARM32-OPTM1: sub sp, sp, #352 ; ARM32: bic sp, sp, #31 ; ARM32: bl {{.*}} R_{{.*}} f1 ; MIPS32-LABEL: fixed_351_align_32 ; MIPS32-OPT2: addiu sp,sp,-384 ; MIPS32-OPT2: addiu a0,sp,16 ; MIPS32-OPTM1: addiu sp,sp,-400 ; MIPS32-OPTM1: addiu [[REG:.*]],sp,32 ; MIPS32-OPTM1: sw [[REG]],{{.*}} ; MIPS32-OPTM1: lw a0,{{.*}} ; MIPS32: jal {{.*}} R_{{.*}} f1 declare void @f1(i32 %ignored) declare void @f2(i32 %ignored) define internal void @variable_n_align_16(i32 %n) { entry: %array = alloca i8, i32 %n, align 16 %__2 = ptrtoint i8* %array to i32 call void @f2(i32 %__2) ret void } ; CHECK-LABEL: variable_n_align_16 ; CHECK: sub esp,0x18 ; CHECK: mov eax,DWORD PTR [ebp+0x8] ; CHECK: add eax,0xf ; CHECK: and eax,0xfffffff0 ; CHECK: sub esp,eax ; CHECK: lea eax,[esp+0x10] ; CHECK: mov DWORD PTR [esp],eax ; CHECK: call {{.*}} R_{{.*}} f2 ; ARM32-LABEL: variable_n_align_16 ; ARM32: add r0, r0, #15 ; ARM32: bic r0, r0, #15 ; ARM32: sub sp, sp, r0 ; ARM32: bl {{.*}} R_{{.*}} f2 ; MIPS32-LABEL: variable_n_align_16 ; MIPS32: addiu [[REG:.*]],{{.*}},15 ; MIPS32: li [[REG1:.*]],-16 ; MIPS32: and [[REG2:.*]],[[REG]],[[REG1]] ; MIPS32: subu [[REG3:.*]],sp,[[REG2:.*]] ; MIPS32: li [[REG4:.*]],-16 ; MIPS32: and {{.*}},[[REG3]],[[REG4]] ; MIPS32: addiu sp,sp,-16 ; MIPS32: jal {{.*}} R_{{.*}} f2 ; MIPS32: addiu sp,sp,16 define internal void @variable_n_align_32(i32 %n) { entry: %array = alloca i8, i32 %n, align 32 %__2 = ptrtoint i8* %array to i32 call void @f2(i32 %__2) ret void } ; In -O2, the order of the CHECK-DAG lines in the output is switched. ; CHECK-LABEL: variable_n_align_32 ; CHECK: push ebp ; CHECK: mov ebp,esp ; CHECK: sub esp,0x18 ; CHECK-DAG: and esp,0xffffffe0 ; CHECK-DAG: mov eax,DWORD PTR [ebp+0x8] ; CHECK: add eax,0x1f ; CHECK: and eax,0xffffffe0 ; CHECK: sub esp,eax ; CHECK: lea eax,[esp+0x10] ; CHECK: mov DWORD PTR [esp],eax ; CHECK: call {{.*}} R_{{.*}} f2 ; CHECK: mov esp,ebp ; CHECK: pop ebp ; ARM32-LABEL: variable_n_align_32 ; ARM32: push {fp, lr} ; ARM32: mov fp, sp ; ARM32: bic sp, sp, #31 ; ARM32: add r0, r0, #31 ; ARM32: bic r0, r0, #31 ; ARM32: sub sp, sp, r0 ; ARM32: bl {{.*}} R_{{.*}} f2 ; ARM32: mov sp, fp ; ARM32: pop {fp, lr} ; MIPS32-LABEL: variable_n_align_32 ; MIPS32: addiu [[REG:.*]],{{.*}},15 ; MIPS32: li [[REG1:.*]],-16 ; MIPS32: and [[REG2:.*]],[[REG]],[[REG1]] ; MIPS32: subu [[REG3:.*]],sp,[[REG2]] ; MIPS32: li [[REG4:.*]],-32 ; MIPS32: and {{.*}},[[REG3]],[[REG4]] ; MIPS32: addiu sp,sp,-16 ; MIPS32: jal {{.*}} R_{{.*}} f2 ; MIPS32: addiu sp,sp,16 ; Test alloca with default (0) alignment. define internal void @align0(i32 %n) { entry: %array = alloca i8, i32 %n %__2 = ptrtoint i8* %array to i32 call void @f2(i32 %__2) ret void } ; CHECK-LABEL: align0 ; CHECK: add [[REG:.*]],0xf ; CHECK: and [[REG]],0xfffffff0 ; CHECK: sub esp,[[REG]] ; ARM32-LABEL: align0 ; ARM32: add r0, r0, #15 ; ARM32: bic r0, r0, #15 ; ARM32: sub sp, sp, r0 ; MIPS32-LABEL: align0 ; MIPS32: addiu [[REG:.*]],{{.*}},15 ; MIPS32: li [[REG1:.*]],-16 ; MIPS32: and [[REG2:.*]],[[REG]],[[REG1]] ; MIPS32: subu {{.*}},sp,[[REG2]] ; MIPS32: addiu sp,sp,-16 ; MIPS32: jal {{.*}} R_{{.*}} f2 ; MIPS32: addiu sp,sp,16 ; Test a large alignment where a mask might not fit in an immediate ; field of an instruction for some architectures. define internal void @align1MB(i32 %n) { entry: %array = alloca i8, i32 %n, align 1048576 %__2 = ptrtoint i8* %array to i32 call void @f2(i32 %__2) ret void } ; CHECK-LABEL: align1MB ; CHECK: push ebp ; CHECK-NEXT: mov ebp,esp ; CHECK: and esp,0xfff00000 ; CHECK: add [[REG:.*]],0xfffff ; CHECK: and [[REG]],0xfff00000 ; CHECK: sub esp,[[REG]] ; ARM32-LABEL: align1MB ; ARM32: movw [[REG:.*]], #0 ; ARM32: movt [[REG]], #65520 ; 0xfff0 ; ARM32: and sp, sp, [[REG]] ; ARM32: movw [[REG2:.*]], #65535 ; 0xffff ; ARM32: movt [[REG2]], #15 ; ARM32: add r0, r0, [[REG2]] ; ARM32: movw [[REG3:.*]], #0 ; ARM32: movt [[REG3]], #65520 ; 0xfff0 ; ARM32: and r0, r0, [[REG3]] ; ARM32: sub sp, sp, r0 ; MIPS32-LABEL: align1MB ; MIPS32: addiu [[REG:.*]],{{.*}},15 ; MIPS32: li [[REG1:.*]],-16 ; MIPS32: and [[REG2:.*]],[[REG]],[[REG1]] ; MIPS32: subu [[REG3:.*]],sp,[[REG2]] ; MIPS32: lui [[REG4:.*]],0xfff0 ; MIPS32: and {{.*}},[[REG3]],[[REG4]] ; MIPS32: addiu sp,sp,-16 ; MIPS32: jal {{.*}} R_{{.*}} f2 ; MIPS32: addiu sp,sp,16 ; Test a large alignment where a mask might still fit in an immediate ; field of an instruction for some architectures. define internal void @align512MB(i32 %n) { entry: %array = alloca i8, i32 %n, align 536870912 %__2 = ptrtoint i8* %array to i32 call void @f2(i32 %__2) ret void } ; CHECK-LABEL: align512MB ; CHECK: push ebp ; CHECK-NEXT: mov ebp,esp ; CHECK: and esp,0xe0000000 ; CHECK: add [[REG:.*]],0x1fffffff ; CHECK: and [[REG]],0xe0000000 ; CHECK: sub esp,[[REG]] ; ARM32-LABEL: align512MB ; ARM32: and sp, sp, #-536870912 ; 0xe0000000 ; ARM32: mvn [[REG:.*]], #-536870912 ; 0xe0000000 ; ARM32: add r0, r0, [[REG]] ; ARM32: and r0, r0, #-536870912 ; 0xe0000000 ; ARM32: sub sp, sp, r0 ; MIPS32-LABEL: align512MB ; MIPS32: addiu [[REG:.*]],{{.*}},15 ; MIPS32: li [[REG2:.*]],-16 ; MIPS32: and [[REG3:.*]],[[REG]],[[REG2]] ; MIPS32: subu [[REG4:.*]],sp,[[REG3]] ; MIPS32: lui [[REG5:.*]],0xe000 ; MIPS32: and {{.*}},[[REG4]],[[REG5]] ; MIPS32: addiu sp,sp,-16 ; MIPS32: jal {{.*}} R_{{.*}} f2 ; MIPS32: addiu sp,sp,16 ; Test that a simple alloca sequence doesn't trigger a frame pointer. define internal void @fixed_no_frameptr(i32 %arg) { entry: %a1 = alloca i8, i32 8, align 4 %a2 = alloca i8, i32 12, align 4 %a3 = alloca i8, i32 16, align 4 %p1 = bitcast i8* %a1 to i32* %p2 = bitcast i8* %a2 to i32* %p3 = bitcast i8* %a3 to i32* store i32 %arg, i32* %p1, align 1 store i32 %arg, i32* %p2, align 1 store i32 %arg, i32* %p3, align 1 ret void } ; CHECK-LABEL: fixed_no_frameptr ; CHECK-NOT: mov ebp,esp ; Test that a simple alloca sequence with at least one large alignment does ; trigger a frame pointer. define internal void @fixed_bigalign_with_frameptr(i32 %arg) { entry: %a1 = alloca i8, i32 8, align 4 %a2 = alloca i8, i32 12, align 4 %a3 = alloca i8, i32 16, align 64 %p1 = bitcast i8* %a1 to i32* %p2 = bitcast i8* %a2 to i32* %p3 = bitcast i8* %a3 to i32* store i32 %arg, i32* %p1, align 1 store i32 %arg, i32* %p2, align 1 store i32 %arg, i32* %p3, align 1 ret void } ; CHECK-LABEL: fixed_bigalign_with_frameptr ; CHECK: mov ebp,esp ; Test that a more complex alloca sequence does trigger a frame pointer. define internal void @var_with_frameptr(i32 %arg) { entry: %a1 = alloca i8, i32 8, align 4 %a2 = alloca i8, i32 12, align 4 %a3 = alloca i8, i32 %arg, align 4 %p1 = bitcast i8* %a1 to i32* %p2 = bitcast i8* %a2 to i32* %p3 = bitcast i8* %a3 to i32* store i32 %arg, i32* %p1, align 1 store i32 %arg, i32* %p2, align 1 store i32 %arg, i32* %p3, align 1 ret void } ; CHECK-LABEL: var_with_frameptr ; CHECK: mov ebp,esp