2005-05-16 H.J. Lu <hongjiu.lu@intel.com>
authorH.J. Lu <hjl.tools@gmail.com>
Mon, 16 May 2005 17:55:55 +0000 (17:55 +0000)
committerH.J. Lu <hjl.tools@gmail.com>
Mon, 16 May 2005 17:55:55 +0000 (17:55 +0000)
PR 834
* elfxx-ia64.c (elfNN_ia64_relax_br): New.
(elfNN_ia64_relax_section): Use it.

bfd/ChangeLog
bfd/elfxx-ia64.c

index 66178328421d50fd46f78d1588c0fb765f40c451..91e4eccfa73d218fd8f7561af6b2e0930cfcd115 100644 (file)
@@ -1,3 +1,9 @@
+2005-05-16  H.J. Lu  <hongjiu.lu@intel.com>
+
+       PR 834
+       * elfxx-ia64.c (elfNN_ia64_relax_br): New.
+       (elfNN_ia64_relax_section): Use it.
+
 2005-05-14  Mark Kettenis  <kettenis@gnu.org>
 
        * elflink.c (bfd_elf_size_dynamic_sections): Use lbasename instead
index e64b1d398c46bd7369ba1bc6e7a8b2e74ff824c7..cc8e5beebe31348a346d0a4ab7c308898daa34f8 100644 (file)
@@ -681,6 +681,141 @@ bfd_elfNN_ia64_after_parse (int itanium)
   oor_branch_size = itanium ? sizeof (oor_ip) : sizeof (oor_brl);
 }
 
+#define BTYPE_SHIFT    6
+#define Y_SHIFT                26
+#define X6_SHIFT       27
+#define X4_SHIFT       27
+#define X3_SHIFT       33
+#define X2_SHIFT       31
+#define X_SHIFT                33
+#define OPCODE_SHIFT   37
+
+#define OPCODE_BITS    (0xfLL << OPCODE_SHIFT)
+#define X6_BITS                (0x3fLL << X6_SHIFT)
+#define X4_BITS                (0xfLL << X4_SHIFT)
+#define X3_BITS                (0x7LL << X3_SHIFT)
+#define X2_BITS                (0x3LL << X2_SHIFT)
+#define X_BITS         (0x1LL << X_SHIFT)
+#define Y_BITS         (0x1LL << Y_SHIFT)
+#define BTYPE_BITS     (0x7LL << BTYPE_SHIFT)
+#define PREDICATE_BITS (0x3fLL)
+
+#define IS_NOP_B(i) \
+  (((i) & (OPCODE_BITS | X6_BITS)) == (2LL << OPCODE_SHIFT))
+#define IS_NOP_F(i) \
+  (((i) & (OPCODE_BITS | X_BITS | X6_BITS | Y_BITS)) \
+   == (0x1LL << X6_SHIFT))
+#define IS_NOP_I(i) \
+  (((i) & (OPCODE_BITS | X3_BITS | X6_BITS | Y_BITS)) \
+   == (0x1LL << X6_SHIFT))
+#define IS_NOP_M(i) \
+  (((i) & (OPCODE_BITS | X3_BITS | X2_BITS | X4_BITS | Y_BITS)) \
+   == (0x1LL << X4_SHIFT))
+#define IS_BR_COND(i) \
+  (((i) & (OPCODE_BITS | BTYPE_BITS)) == (0x4LL << OPCODE_SHIFT))
+#define IS_BR_CALL(i) \
+  (((i) & OPCODE_BITS) == (0x5LL << OPCODE_SHIFT))
+
+static bfd_boolean
+elfNN_ia64_relax_br (bfd_byte *contents, bfd_vma off)
+{
+  unsigned int template, mlx;
+  bfd_vma t0, t1, s0, s1, s2, br_code;
+  long br_slot;
+  bfd_byte *hit_addr;
+
+  hit_addr = (bfd_byte *) (contents + off);
+  br_slot = (long) hit_addr & 0x3;
+  hit_addr -= br_slot;
+  t0 = bfd_getl64 (hit_addr + 0);
+  t1 = bfd_getl64 (hit_addr + 8);
+
+  /* Check if we can turn br into brl.  A label is always at the start
+     of the bundle.  Even if there are predicates on NOPs, we still
+     perform this optimization.  */
+  template = t0 & 0x1e;
+  s0 = (t0 >> 5) & 0x1ffffffffffLL;
+  s1 = ((t0 >> 46) | (t1 << 18)) & 0x1ffffffffffLL;
+  s2 = (t1 >> 23) & 0x1ffffffffffLL;
+  switch (br_slot)
+    {
+    case 0:
+      /* Check if slot 1 and slot 2 are NOPs. Possible template is
+         BBB.  We only need to check nop.b.  */
+      if (!(IS_NOP_B (s1) && IS_NOP_B (s2)))
+       return FALSE;
+      br_code = s0;
+      break;
+    case 1:
+      /* Check if slot 2 is NOP. Possible templates are MBB and BBB.
+        For BBB, slot 0 also has to be nop.b.  */
+      if (!((template == 0x12                          /* MBB */
+            && IS_NOP_B (s2))
+           || (template == 0x16                        /* BBB */
+               && IS_NOP_B (s0)
+               && IS_NOP_B (s2))))
+       return FALSE;
+      br_code = s1;
+      break;
+    case 2:
+      /* Check if slot 1 is NOP. Possible templates are MIB, MBB, BBB,
+        MMB and MFB. For BBB, slot 0 also has to be nop.b.  */
+      if (!((template == 0x10                          /* MIB */
+            && IS_NOP_I (s1))
+           || (template == 0x12                        /* MBB */
+               && IS_NOP_B (s1))
+           || (template == 0x16                        /* BBB */
+               && IS_NOP_B (s0)
+               && IS_NOP_B (s1))
+           || (template == 0x18                        /* MMB */
+               && IS_NOP_M (s1))
+           || (template == 0x1c                        /* MFB */
+               && IS_NOP_F (s1))))
+       return FALSE;
+      br_code = s2;
+      break;
+    default:
+      /* It should never happen.  */
+      abort ();
+    }
+  
+  /* We can turn br.cond/br.call into brl.cond/brl.call.  */
+  if (!(IS_BR_COND (br_code) || IS_BR_CALL (br_code)))
+    return FALSE;
+
+  /* Turn br into brl by setting bit 40.  */
+  br_code |= 0x1LL << 40;
+
+  /* Turn the old bundle into a MLX bundle with the same stop-bit
+     variety.  */
+  if (t0 & 0x1)
+    mlx = 0x5;
+  else
+    mlx = 0x4;
+
+  if (template == 0x16)
+    {
+      /* For BBB, we need to put nop.m in slot 0 and keep the original
+        predicate.  */
+      t0 &= PREDICATE_BITS << 5;
+      t0 |= 0x1LL << (X4_SHIFT + 5);
+    }
+  else
+    {
+      /* Keep the original instruction in slot 0.  */
+      t0 &= 0x1ffffffffffLL << 5;
+    }
+
+  t0 |= mlx;
+
+  /* Put brl in slot 1.  */
+  t1 = br_code << 23;
+
+  bfd_putl64 (t0, hit_addr);
+  bfd_putl64 (t1, hit_addr + 8);
+  return TRUE;
+}
+
 static void
 elfNN_ia64_relax_brl (bfd_byte *contents, bfd_vma off)
 {
@@ -985,6 +1120,16 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again)
            }
          else if (r_type == R_IA64_PCREL60B)
            continue;
+         else if (elfNN_ia64_relax_br (contents, roff))
+           {
+             irel->r_info
+               = ELFNN_R_INFO (ELFNN_R_SYM (irel->r_info),
+                               R_IA64_PCREL60B);
+
+             /* Make the relocation offset point to slot 1.  */
+             irel->r_offset = (irel->r_offset & ~((bfd_vma) 0x3)) + 1;
+             continue;
+           }
 
          /* We can't put a trampoline in a .init/.fini section. Issue
             an error.  */