From 8d1b3521dbd074e72764e19fb7c9b430a968e664 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sat, 21 Apr 2012 19:03:52 +0000 Subject: [PATCH] Handle sparc compare-and-branch SPARC-T4 adds a "compare and branch" instruction which fuses a compare and a branch instruction into one. The branch is non-delayed, there are no anulling facilities, and the displacement is 10-bits. This also corrects the existing bit test for Branch on Integer Register. The distinguising characteristic between Branch on Integer Register and Compare-and-Branch is bit 28. The existing code was checking bit 24 for zero, but that's pointless because bit 24 is already covered by the "X_OP2 (insn) == 3" test. gdb/ * sparc-tdep.c (X_DISP10): Define. (sparc_analyze_control_transfer): Handle compare-and-branch. --- gdb/ChangeLog | 5 +++++ gdb/sparc-tdep.c | 32 ++++++++++++++++++++++++++------ 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 41ab7df..8ad6e84 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,8 @@ +2012-04-21 David S. Miller + + * sparc-tdep.c (X_DISP10): Define. + (sparc_analyze_control_transfer): Handle compare-and-branch. + 2012-04-21 Jonathan Larmour * features/Makefile (WHICH): Add arm-with-m and arm-with-m-fpa-layout. diff --git a/gdb/sparc-tdep.c b/gdb/sparc-tdep.c index 24d54b7..00bca01 100644 --- a/gdb/sparc-tdep.c +++ b/gdb/sparc-tdep.c @@ -85,6 +85,7 @@ struct regset; /* Sign extension macros. */ #define X_DISP22(i) ((X_IMM22 (i) ^ 0x200000) - 0x200000) #define X_DISP19(i) ((((i) & 0x7ffff) ^ 0x40000) - 0x40000) +#define X_DISP10(i) ((((((i) >> 11) && 0x300) | (((i) >> 5) & 0xff)) ^ 0x200) - 0x200) #define X_SIMM13(i) ((((i) & 0x1fff) ^ 0x1000) - 0x1000) /* Fetch the instruction at PC. Instructions are always big-endian @@ -1451,14 +1452,24 @@ sparc_analyze_control_transfer (struct frame_info *frame, { unsigned long insn = sparc_fetch_instruction (pc); int conditional_p = X_COND (insn) & 0x7; - int branch_p = 0; + int branch_p = 0, fused_p = 0; long offset = 0; /* Must be signed for sign-extend. */ - if (X_OP (insn) == 0 && X_OP2 (insn) == 3 && (insn & 0x1000000) == 0) + if (X_OP (insn) == 0 && X_OP2 (insn) == 3) { - /* Branch on Integer Register with Prediction (BPr). */ - branch_p = 1; - conditional_p = 1; + if ((insn & 0x10000000) == 0) + { + /* Branch on Integer Register with Prediction (BPr). */ + branch_p = 1; + conditional_p = 1; + } + else + { + /* Compare and Branch */ + branch_p = 1; + fused_p = 1; + offset = 4 * X_DISP10 (insn); + } } else if (X_OP (insn) == 0 && X_OP2 (insn) == 6) { @@ -1495,7 +1506,16 @@ sparc_analyze_control_transfer (struct frame_info *frame, if (branch_p) { - if (conditional_p) + if (fused_p) + { + /* Fused compare-and-branch instructions are non-delayed, + and do not have an annuling capability. So we need to + always set a breakpoint on both the NPC and the branch + target address. */ + gdb_assert (offset != 0); + return pc + offset; + } + else if (conditional_p) { /* For conditional branches, return nPC + 4 iff the annul bit is 1. */ -- 2.7.4