arc: Determine a branch target of DBNZ correctly

DBNZ instruction was moved from BRANCH class to a separate one - DBNZ.
Thus, it must be processed separately in arc_insn_get_branch_target
to correctly determine an offset for a possible branch.

The testsuite for DBNZ instruction verifies these cases:

     1. Check that dbnz does not branch and falls through if its source
        register is 0 after decrementing. GDB must successfully break
        on the following instruction after stepping over.
     2. Check that dbnz branches to the target correctly if its source register
        is not 0 after decrementing - GDB must successfully break on the target
        instruction if a forward branch is performed after stepping over.
     3. The same as point 2 but for a backward branching case.

Signed-off-by: Yuriy Kolerov <kolerov93@gmail.com>
This commit is contained in:
Yuriy Kolerov
2024-02-14 18:16:16 +00:00
committed by Shahab Vahedi
parent f961273101
commit 33283d91d9
3 changed files with 154 additions and 0 deletions

View File

@@ -466,6 +466,16 @@ arc_insn_get_branch_target (const struct arc_instruction &insn)
instruction, hence last two bits should be truncated. */
return pcrel_addr + align_down (insn.address, 4);
}
/* DBNZ is the only branch instruction that keeps a branch address in
the second operand. It must be intercepted and treated differently. */
else if (insn.insn_class == DBNZ)
{
CORE_ADDR pcrel_addr = arc_insn_get_operand_value_signed (insn, 1);
/* Offset is relative to the 4-byte aligned address of the current
instruction, hence last two bits should be truncated. */
return pcrel_addr + align_down (insn.address, 4);
}
/* B, Bcc, BL, BLcc, LP, LPcc: PC = currentPC + operand. */
else if (insn.insn_class == BRANCH || insn.insn_class == LOOP)
{