blob: 64b3513924079cf933152252e42be6a07848ec1e [file] [log] [blame]
; 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