blob: c697b1fe7fab9eda1056634630168bb746beb054 [file] [log] [blame]
; This testcase is part of GDB, the GNU debugger.
; Copyright 2017-2021 Free Software Foundation, Inc.
; This program is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation; either version 3 of the License, or
; (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program. If not, see <http://www.gnu.org/licenses/>.
.section .data
some_variable:
.long 0xdeadbeef
.section .text
.global main
.type main, @function
; Standard prologue.
.align 4
standard_prologue:
push blink
sub sp,sp,12
st r13, [sp, 0]
st r14, [sp, 4]
st r18, [sp, 8]
add r0, r1, r2
ld r18, [sp, 8]
ld r14, [sp, 4]
ld r13, [sp, 0]
add sp,sp,12
pop blink
j [blink]
; Standard prologue using short instructions.
.align 4
mini_prologue:
push_s blink
sub_s sp,sp,12
; ST_S can store only some of the core registers.
st_s r13, [sp, 0]
st_s r15, [sp, 4]
st_s r14, [sp, 8]
add r0, r1, r2
add sp,sp,16
j [blink]
; Standard prologue without `sub sp,sp,INTEGER`.
.align 4
no_subsp_prologue:
push blink
push r13
push r20
push r25
add r0, r1, r2
pop r25
pop r20
pop r13
pop blink
j [blink]
; Standard prologue of leaf function.
.align 4
leaf_prologue:
sub sp,sp,8
st r13, [sp, 0]
st r15, [sp, 4]
add r0, r1, r2
ld r13, [sp, 0]
ld r15, [sp, 4]
j.d [blink]
add sp,sp,8
; Prologue with `push fp`.
.align 4
pushfp_prologue:
push r13
push r14
push fp
; mov fp,sp is part of prologue, but this test will not verify that.
; It will be checked later in the "arg_regs_fp" test.
mov fp, sp
add r0, r1, r2
pop fp
pop r14
pop r13
j [blink]
; Prologue with frame pointer and store relative to FP.
.align 4
fp_prologue_with_store:
push r13
push r14
push fp
mov fp, sp
sub_s sp,sp,4
st r15,[fp,-4]
add r0, r1, r2
pop r15
pop fp
pop r14
pop r13
j [blink]
; Verify that store of the non-callee saved registers is not part of prologue.
; Repeat this test for multiple registers, to check boundaries. Also check
; with both ST and PUSH (aka ST.AW). We have to use multiple functions for
; this, because GDB would stop analisys at the first instruction that is not
; part of prologue.
.align 4
noncallee_saved_regs_r12_st:
sub sp,sp,8
st r13, [sp, 4]
st r12, [sp, 0]
add r0, r1, r2
j.d [blink]
add sp,sp,8
.align 4
noncallee_saved_regs_r12_push:
push r13
push r12
add r0, r1, r2
j.d [blink]
add sp,sp,8
.align 4
noncallee_saved_regs_r2_push:
push r13
push r2
add r0, r1, r2
j.d [blink]
add sp,sp,8
.align 4
noncallee_saved_regs_gp_push:
push r25
push gp
add r0, r1, r2
j.d [blink]
add sp,sp,8
; LP_COUNT is treated like a normal register.
.align 4
noncallee_saved_regs_lp_count:
push r25
push lp_count
add r0, r1, r2
j.d [blink]
add sp,sp,8
; BLINK is saved, but after an instruction that is not part of prologue.
; Currently arc_analyze_prologue stops analisys at the first intstruction
; that is not a part of prologue. This might be not the best way, but it is
; what it is right now, so this test confirms this.
.align 4
noncallee_saved_regs_blink_out_of_prologue:
push r25
push gp
push blink
add r0, r1, r2
j.d [blink]
add sp,sp,12
; Saving arguments register via FP.
.align 4
arg_regs_fp:
push fp
mov fp, sp
sub sp, sp, 16
st r0, [fp, -4]
st r1, [fp, -8]
st r7, [fp, -12]
st r8, [fp, -16]
add r0, r1, r2
add sp,sp,16
pop fp
j [blink]
; Like the previous, but with mov_s.
.align 4
arg_regs_fp_mov_s:
push fp
mov_s fp, sp
sub sp, sp, 8
st r0, [fp, -4]
; Not part of the prologue.
st r8, [fp, -8]
add r0, r1, r2
add sp,sp,8
pop fp
j [blink]
; Saving arguments register without FP.
.align 4
arg_regs_sp:
sub sp, sp, 24
st r0, [sp, 0]
st r1, [sp, 4]
st r7, [sp, 8]
; Normally that would be done before saving args, but it is used as a
; marker that saving arguments relatively to SP is considered part of
; prologue.
st r13, [sp, 16]
; Not part of the prologue.
st r8, [sp, 12]
st r14, [sp, 20]
add r0, r1, r2
j.d [blink]
add sp,sp,24
; ENTER_S that does nothing.
.align 4
enter_s_nop:
; Effectively a nop.
enter_s 0
add r0,r1,r2
j [blink]
; ENTER_S that stores BLINK.
.align 4
enter_s_blink:
enter_s 32
add r0,r1,r2
j.d [blink]
add sp,sp,4
; ENTER_S that stores FP.
.align 4
enter_s_fp:
enter_s 16
add r0,r1,r2
j.d [blink]
add sp,sp,4
; ENTER_S that stores R13, FP and BLINK.
.align 4
enter_s_r13:
enter_s (32 + 16 + 1)
add r0,r1,r2
j.d [blink]
add sp,sp,12
; ENTER_S that stores R13-R15
.align 4
enter_s_r15:
enter_s 3
add r0,r1,r2
j.d [blink]
add sp,sp,12
; ENTER_S that stores everything it could.
.align 4
enter_s_all:
enter_s (32 + 16 + 14)
add r0,r1,r2
j.d [blink]
add sp,sp,64
; Deeper nesting.
.align 4
nested_prologue_inner:
sub sp,sp,8
st r18, [sp, 4]
st r13, [sp, 0]
add r0, r1, r2
ld r18, [sp, 4]
ld r13, [sp, 0]
j.d [blink]
add sp,sp,8
.align 4
nested_prologue_outer:
push blink
sub sp,sp,8
st r14, [sp, 0]
st r15, [sp, 4]
bl @nested_prologue_inner
add r0, r1, r2
ld r14, [sp, 0]
ld r15, [sp, 4]
add sp,sp,8
pop blink
j [blink]
; Prologue with maximum length.
; Expressions like (0xFFFFFFFF + 25) force assembler to use long immediate
; even for values that don't need it, thus letting us test maksimum prologue
; length without having huge frames.
.align 4
max_length_prologue:
; Variadic args
sub sp,sp,(0xFFFFFFFF + 25) ; 24 bytes
push blink
; Allocate space for 13 callee-saved and 8 arg regs.
sub sp,sp,(0xFFFFFFFF + 1 + 21 * 4)
st r13, [sp, 0]
st r14, [sp, 4]
st r15, [sp, 8]
st r16, [sp, 12]
st r17, [sp, 16]
st r18, [sp, 20]
st r19, [sp, 24]
st r20, [sp, 28]
st r21, [sp, 32]
st r22, [sp, 36]
st r23, [sp, 40]
st r24, [sp, 44]
st r25, [sp, 48]
st r0, [sp, 52]
st r1, [sp, 56]
st r2, [sp, 60]
st r3, [sp, 64]
st r4, [sp, 68]
st r5, [sp, 72]
st r6, [sp, 76]
st r7, [sp, 80]
push fp
mov fp,sp
sub sp,sp,(0xFFFFFFFF + 1 + 16) ; Space for local variables.
; End of prologue.
add sp,sp,24 + 21 * 4 + 16
j [blink]
; Few tests that test that prologue analysis stops at branch. There are four
; types of "branches": conditional and non-conditional, relative branches and
; absolute jumps.
.align 4
branch_in_prologue:
push r13
b @.L1
; This store on stack is not a prologue.
push r14
.L1:
add r0,r1,r2
j.d [blink]
add sp,sp,4
.align 4
cond_branch_in_prologue:
sub_s sp,sp,8
st_s r13,[sp,4]
; Doesn't matter if branch is taken or not.
breq r0,r1,@.L2
; This store on stack is not a prologue.
st_s r14,[sp,0]
.L2:
add r0,r1,r2
pop fp
j.d [blink]
add sp,sp,8
.align 4
jump_in_prologue:
push r13
j @.L3
; This store on stack is not a prologue.
push r14
.L3:
add r0,r1,r2
j.d [blink]
add sp,sp,4
.align 4
cond_jump_in_prologue:
sub_s sp,sp,8
st_s r13,[sp,4]
; It doesn't matter if jump is taken or not - prologue analysis has to
; stop before `jeq` in any case.
jeq @.L4
; This store on stack is not a prologue.
st_s r14,[sp,0]
.L4:
add r0,r1,r2
j.d [blink]
add sp,sp,8
.align 4
predicated_insn:
sub_s sp,sp,12
st_s r13,[sp,8]
st_s r15,[sp,0]
; Use SUB SP,SP,0 because it is otherwise a valid instruction for
; prologue, so it will halt analysis purely because of its predicate.
sub.eq sp,sp,0 ; This is not a prologue anymore.
st_s r14,[sp,4]
add sp,sp,12
j [blink]
; Loops should halt prologue analysis.
.align 4
loop_in_prologue:
push r25
push lp_count
mov lp_count, 4
lp @.Lloop_end1
push r26 ; Not part of prologue.
add r0, r1, r2
.Lloop_end1:
add r1, r1, r2
pop r26
add sp,sp,8
pop r25
j [blink]
; Store of a constant value (not a register).
.align 4
store_constant:
sub_s sp,sp,12
st_s r13,[sp,8]
st 0xdeadbeef,[sp,0]
st_s r14,[sp,4]
add sp,sp,12
j [blink]
; Test that store to immediate address halts prologue analysis.
.align 4
st_c_limm:
push r15
st r14,[@some_variable]
push r13
add sp,sp,8
j [blink]
; Store with AB writeback mode.
.align 4
st_ab_writeback:
sub sp,sp,8
st r13,[sp,4]
st.ab r14,[sp,-4]
st r15,[sp,0]
add sp,sp,12
j [blink]
; Store of a word with AS writeback mode.
.align 4
st_as_writeback:
sub sp,sp,12
st r13,[sp,8]
st.as r14,[sp,1] ; ST.AS, hence address is (offset << 2).
st r15,[sp,0]
add sp,sp,12
j [blink]
; Store of a halfword with AS writeback mode.
.align 4
sth_as_writeback:
sub sp,sp,12
st r13,[sp,8]
sth.as r14,[sp,2] ; STH.AS, hence address is (offset << 1).
st r15,[sp,0]
add sp,sp,12
j [blink]
; Store of a double word with AS writeback mode. Shift is still 2, like ST!
.align 4
std_as_writeback:
sub sp,sp,16
st r13,[sp,12]
#ifdef __ARC_LL64__
std.as r14,[sp,1] ; STD.AS, hence address is (offset << 2).
#else
st.as r14,[sp,1] ; STD.AS, hence address is (offset << 2).
st.as r15,[sp,2] ; STD.AS, hence address is (offset << 2).
#endif
st r16,[sp,0]
add sp,sp,12
j [blink]
; Store of the halfword. R14 will not be reported as "saved".
.align 4
st_halfword:
sub sp,sp,12
st r13,[sp,8]
sth r14,[sp,4]
st r15,[sp,0]
add sp,sp,12
j [blink]
; Store of the halfword. R14 will not be reported as "saved".
.align 4
sts_halfword:
sub sp,sp,12
st r13,[sp,8]
mov r13,sp
sth_s r14,[r13,4]
st r15,[sp,0]
add sp,sp,12
j [blink]
; Store of the byte. R14 will not be reported as "saved".
.align 4
st_byte:
sub sp,sp,12
st r13,[sp,8]
stb r14,[sp,4]
st r15,[sp,0]
add sp,sp,12
j [blink]
; Store of the byte. R14 will not be reported as "saved".
.align 4
sts_byte:
sub sp,sp,12
st r13,[sp,8]
mov r13,sp
stb_s r14,[r13,4]
st r15,[sp,0]
add sp,sp,12
j [blink]
; Store of the byte. R14 will not be reported as "saved".
.align 4
sts_byte_sp:
sub sp,sp,12
st r13,[sp,8]
stb_s r14,[sp,4]
st r15,[sp,0]
add sp,sp,12
j [blink]
; Double word store, optionally available for ARC HS.
.align 4
st_double:
sub sp,sp,8
#ifdef __ARC_LL64__
std r14,[sp,0]
std.aw r18,[sp,-8]
std.aw 0xdeadbeef,[sp,-8]
#else
st r14,[sp,0]
st r15,[sp,4]
st.aw r19,[sp,-4]
st.aw r18,[sp,-4]
sub sp,sp,8
#endif
add sp,sp,24
j [blink]
; Store relative to some register with a known value.
.align 4
r_relative_store:
sub_s sp,sp,12
st_s r13,[sp,8]
mov r13,sp
; Check for both mov and mov_s in one testcase.
mov_s r12,r13
st r15,[r12,0]
st_s r14,[sp,4]
add sp,sp,12
j [blink]
; Store relative to some register with a known value using sub.
; Like a previous test, but register is assigned via sub, instead of mov.
.align 4
r_relative_sub_store:
; Following is a complicated way to construct frame like this:
; sub_s sp,sp,12
; st_s r13,[sp,8]
; st_s r14,[sp,4]
; st_s r15,[sp,0]
sub_s sp,sp,12
st_s r13,[sp,8]
sub r13,sp,4
st r14,[r13,8]
st_s r15,[sp,0]
add sp,sp,12
j [blink]
; Like r_relative_store, but using st_s c,[b,u7] which has different opcode.
.align 4
r_relative_store_st_s:
sub_s sp,sp,12
st_s r13,[sp,8]
mov r13,sp
st_s r15,[r13,4]
st_s r14,[sp,0]
add sp,sp,12
j [blink]
; Store relative to some register with a unknown value.
.align 4
r_relative_store_unknown:
sub_s sp,sp,12
st_s r13,[sp,8]
st r15,[gp,0] ; GP value is not relative to SP.
st_s r14,[sp,4]
add sp,sp,12
j [blink]
; Store relative to some register with a unknown value, using st_s r0,[gp,s11].
.align 4
st_s_r0gp:
sub_s sp,sp,12
st_s r13,[sp,8]
st_s r0,[gp,0] ; GP value is not relative to SP.
st_s r14,[sp,4]
add sp,sp,12
j [blink]
; Check prologue that uses `push_s RR` instructions. `push_s b` and `push_s
; blink` use slightly different subopcodes.
.align 4
push_s_prologue:
push_s r12
push_s r0
push_s r3
push_s r13
push_s r1
push_s r14
push_s r15
push_s r2
push_s blink ; Also tested in mini_prologue ().
add sp,sp,(4 * 9)
j [blink]
; Check for SUB_S c,b,u3 presence - it doesn't affect prologue.
.align 4
sub_s_cbu3:
push_s r13
sub_s r0,r1,3
push_s r14
add sp,sp,8
j [blink]
; Check for SUB_S b,b,c presence - it doesn't affect prologue.
.align 4
sub_s_bbc:
push_s r13
sub_s r0,r0,r1
push_s r0
push_s r1
push_s r14
add sp,sp,16
j [blink]
; Check for SUB_S b,b,u5.
.align 4
sub_s_bbu5:
push_s r13
sub_s r2,r2,14
push_s r2
push_s r14
add sp,sp,12
j [blink]
; Check for SUB 0,b,c, which is effectively a noop (but it can set status
; flags). It shouldn't stop prologue analysis.
.align 4
sub_0bc:
push_s r13
sub 0,r1,r2
sub.f 0,r3,r4
push_s r14
add sp,sp,8
j [blink]
; Check for SUB a,limm,c.
.align 4
sub_alimmb:
push_s r13
sub r13,0xdeadbeef,r14
push_s r14
add sp,sp,8
j [blink]
; Check for sub_s.ne b,b,b. Has a condition code, hence should halt prologue.
.align 4
sub_s_ne_bbb:
push_s r13
sub_s.ne r13,r13,r13
push_s r14
add sp,sp,8
j [blink]
; Check MOV that uses LIMM values.
.align 4
mov_limm:
push_s r13
mov r13,0xdeadbeef
push_s r14
add sp,sp,4
pop_s r13
j [blink]
; Check MOV 0,c.
.align 4
mov0c_limm:
push_s r13
mov 0,r13
push_s r14
add sp,sp,4
pop_s r13
j [blink]
; Check that MOV_S h,s3 doesn't prevent prologue analysis.
.align 4
mov_s_hs3:
push_s r13
mov_s r5,1
push_s r14
add sp,sp,8
j [blink]
; Check that MOV_S b,u8 doesn't prevent prologue analysis.
.align 4
mov_s_bu8:
push_s r13
mov_s r12,250
push_s r14
add sp,sp,8
j [blink]
; Check that `mov_s.ne b,h` halts prologue analysis.
.align 4
mov_s_ne_bh:
push_s r13
mov_s.ne r13,r5
push_s r14
add sp,sp,8
j [blink]
; Check that register R12 which original value is not stored will not pop-up in
; the "Saved registers" list.
.align 4
unstored_reg:
sub_s sp,sp,12
st_s r13,[sp,0]
st_s r14,[sp,4]
mov r12,0x42
st_s r12,[sp,8]
add sp,sp,12
j [blink]
; Two stores at the same adddress. GDB should report only the R14.
.align 4
double_store:
sub_s sp,sp,4
st_s r13,[sp,0]
st_s r14,[sp,0]
add sp,sp,4
j [blink]
; Test for a case where callee has an alloca or anything else that might
; modify stack dynamically in the function body - after the prologue.
; This assumes that FP is set properly, so that GDB can use it - this holds
; true for frames generated by GCC.
.align 4
alloca_outer:
sub sp,sp,8
st blink,[sp,4]
st fp,[sp,0]
mov fp,sp
add r0,r1,r2 ; Not a prologue anymore.
sub sp,sp,8
bl @alloca_inner
add sp,sp,8
ld fp,[sp,0]
ld blink,[sp,4]
j.d [blink]
add sp,sp,8
.align 4
alloca_inner:
push r13
push r14
add sp,sp,8
j [blink]
.align 4
main:
push blink
# Create small section for GP-relative accesses.
push gp
sub sp,sp,16
add gp,sp,8
bl @standard_prologue
bl @mini_prologue
bl @no_subsp_prologue
bl @leaf_prologue
bl @pushfp_prologue
bl @fp_prologue_with_store
bl @noncallee_saved_regs_r12_st
bl @noncallee_saved_regs_r12_push
bl @noncallee_saved_regs_r2_push
bl @noncallee_saved_regs_gp_push
bl @noncallee_saved_regs_lp_count
bl @noncallee_saved_regs_blink_out_of_prologue
bl @arg_regs_fp
bl @arg_regs_fp_mov_s
bl @arg_regs_sp
bl @enter_s_nop
bl @enter_s_blink
bl @enter_s_fp
bl @enter_s_r13
bl @enter_s_r15
bl @enter_s_all
bl @nested_prologue_outer
bl @max_length_prologue
bl @branch_in_prologue
bl @cond_branch_in_prologue
bl @jump_in_prologue
bl @cond_jump_in_prologue
bl @predicated_insn
bl @loop_in_prologue
bl @store_constant
bl @st_c_limm
bl @st_ab_writeback
bl @st_as_writeback
bl @sth_as_writeback
bl @std_as_writeback
bl @st_halfword
bl @sts_halfword
bl @st_byte
bl @sts_byte
bl @sts_byte_sp
bl @st_double
bl @r_relative_store
bl @r_relative_sub_store
bl @r_relative_store_st_s
bl @r_relative_store_unknown
bl @st_s_r0gp
bl @push_s_prologue
bl @sub_s_cbu3
bl @sub_s_bbc
bl @sub_s_bbu5
bl @sub_0bc
bl @sub_alimmb
bl @sub_s_ne_bbb
bl @mov_limm
bl @mov0c_limm
bl @mov_s_hs3
bl @mov_s_bu8
bl @mov_s_ne_bh
bl @unstored_reg
bl @double_store
bl @alloca_outer
add sp,sp,16
pop gp
pop blink
j_s [blink]
.align 4