* elf32-spu.c (find_function_stack_adjust): Don't limit number
authorAlan Modra <amodra@gmail.com>
Wed, 10 Dec 2008 00:37:11 +0000 (00:37 +0000)
committerAlan Modra <amodra@gmail.com>
Wed, 10 Dec 2008 00:37:11 +0000 (00:37 +0000)
of insns scanned.  Correct sp tests.  Handle "fsmbi" and "andbi".
(mark_detached_root): New function.
(build_call_tree): Call it.
(sort_calls): Don't do void* arithmetic.

bfd/ChangeLog
bfd/elf32-spu.c

index 2a8aab328cde5cfbe42c4e73b0ca0fe09d98bed5..6b4e40be5b1d946788901b7e5caff39152455067 100644 (file)
@@ -1,3 +1,11 @@
+2008-12-10  Alan Modra  <amodra@bigpond.net.au>
+
+       * elf32-spu.c (find_function_stack_adjust): Don't limit number
+       of insns scanned.  Correct sp tests.  Handle "fsmbi" and "andbi".
+       (mark_detached_root): New function.
+       (build_call_tree): Call it.
+       (sort_calls): Don't do void* arithmetic.
+
 2008-12-09  Tom Tromey  <tromey@redhat.com>
 
        * pef.c (bfd_pef_parse_traceback_table): Add parens to placate gcc
index 708ab247ea0d900bf021d04e3bbf72d7cae771b1..48a4a3cd3b60423782e30b6ededaa002efdd97c3 100644 (file)
@@ -1591,11 +1591,10 @@ spu_elf_check_vma (struct bfd_link_info *info,
 static int
 find_function_stack_adjust (asection *sec, bfd_vma offset)
 {
-  int unrecog;
   int reg[128];
 
   memset (reg, 0, sizeof (reg));
-  for (unrecog = 0; offset + 4 <= sec->size && unrecog < 32; offset += 4)
+  for ( ; offset + 4 <= sec->size; offset += 4)
     {
       unsigned char buf[4];
       int rt, ra;
@@ -1621,7 +1620,7 @@ find_function_stack_adjust (asection *sec, bfd_vma offset)
 
          if (rt == 1 /* sp */)
            {
-             if (imm > 0)
+             if (reg[rt] > 0)
                break;
              return reg[rt];
            }
@@ -1632,7 +1631,11 @@ find_function_stack_adjust (asection *sec, bfd_vma offset)
 
          reg[rt] = reg[ra] + reg[rb];
          if (rt == 1)
-           return reg[rt];
+           {
+             if (reg[rt] > 0)
+               break;
+             return reg[rt];
+           }
        }
       else if ((buf[0] & 0xfc) == 0x40 /* il, ilh, ilhu, ila */)
        {
@@ -1645,7 +1648,7 @@ find_function_stack_adjust (asection *sec, bfd_vma offset)
              if (buf[0] == 0x40 /* il */)
                {
                  if ((buf[1] & 0x80) == 0)
-                   goto unknown_insn;
+                   continue;
                  imm = (imm ^ 0x8000) - 0x8000;
                }
              else if ((buf[1] & 0x80) == 0 /* ilhu */)
@@ -1666,18 +1669,33 @@ find_function_stack_adjust (asection *sec, bfd_vma offset)
          reg[rt] = reg[ra] | imm;
          continue;
        }
-      else if ((buf[0] == 0x33 && imm == 1 /* brsl .+4 */)
-              || (buf[0] == 0x08 && (buf[1] & 0xe0) == 0 /* sf */))
+      else if (buf[0] == 0x32 && (buf[1] & 0x80) != 0 /* fsmbi */)
+       {
+         reg[rt] = (  ((imm & 0x8000) ? 0xff000000 : 0)
+                    | ((imm & 0x4000) ? 0x00ff0000 : 0)
+                    | ((imm & 0x2000) ? 0x0000ff00 : 0)
+                    | ((imm & 0x1000) ? 0x000000ff : 0));
+         continue;
+       }
+      else if (buf[0] == 0x16 /* andbi */)
        {
-         /* Used in pic reg load.  Say rt is trashed.  */
+         imm >>= 7;
+         imm &= 0xff;
+         imm |= imm << 8;
+         imm |= imm << 16;
+         reg[rt] = reg[ra] & imm;
+         continue;
+       }
+      else if (buf[0] == 0x33 && imm == 1 /* brsl .+4 */)
+       {
+         /* Used in pic reg load.  Say rt is trashed.  Won't be used
+            in stack adjust, but we need to continue past this branch.  */
          reg[rt] = 0;
          continue;
        }
       else if (is_branch (buf) || is_indirect_branch (buf))
        /* If we hit a branch then we must be out of the prologue.  */
        break;
-    unknown_insn:
-      ++unrecog;
     }
 
   return 0;
@@ -2718,6 +2736,23 @@ remove_cycles (struct function_info *fun,
   return TRUE;
 }
 
+/* Check that we actually visited all nodes in remove_cycles.  If we
+   didn't, then there is some cycle in the call graph not attached to
+   any root node.  Arbitrarily choose a node in the cycle as a new
+   root and break the cycle.  */
+
+static bfd_boolean
+mark_detached_root (struct function_info *fun,
+                   struct bfd_link_info *info,
+                   void *param)
+{
+  if (fun->visit2)
+    return TRUE;
+  fun->non_root = FALSE;
+  *(unsigned int *) param = 0;
+  return remove_cycles (fun, info, param);
+}
+
 /* Populate call_list for each function.  */
 
 static bfd_boolean
@@ -2752,7 +2787,10 @@ build_call_tree (struct bfd_link_info *info)
   /* Remove cycles from the call graph.  We start from the root node(s)
      so that we break cycles in a reasonable place.  */
   depth = 0;
-  return for_each_node (remove_cycles, info, &depth, TRUE);
+  if (!for_each_node (remove_cycles, info, &depth, TRUE))
+    return FALSE;
+
+  return for_each_node (mark_detached_root, info, &depth, FALSE);
 }
 
 /* qsort predicate to sort calls by max_depth then count.  */
@@ -2772,7 +2810,7 @@ sort_calls (const void *a, const void *b)
   if (delta != 0)
     return delta;
 
-  return c1 - c2;
+  return (char *) c1 - (char *) c2;
 }
 
 struct _mos_param {