Handle sparc compare-and-branch
authorDavid S. Miller <davem@redhat.com>
Sat, 21 Apr 2012 19:03:52 +0000 (19:03 +0000)
committerDavid S. Miller <davem@redhat.com>
Sat, 21 Apr 2012 19:03:52 +0000 (19:03 +0000)
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
gdb/sparc-tdep.c

index 41ab7df..8ad6e84 100644 (file)
@@ -1,3 +1,8 @@
+2012-04-21  David S. Miller  <davem@davemloft.net>
+
+       * sparc-tdep.c (X_DISP10): Define.
+       (sparc_analyze_control_transfer): Handle compare-and-branch.
+
 2012-04-21  Jonathan Larmour  <jifl@eCosCentric.com>
 
        * features/Makefile (WHICH): Add arm-with-m and arm-with-m-fpa-layout.
index 24d54b7..00bca01 100644 (file)
@@ -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.  */