* config/tc-ppc.c (nop_limit): New var.
authorAlan Modra <amodra@gmail.com>
Thu, 4 Nov 2010 03:30:05 +0000 (03:30 +0000)
committerAlan Modra <amodra@gmail.com>
Thu, 4 Nov 2010 03:30:05 +0000 (03:30 +0000)
(OPTION_NOPS): Define.
(md_longopts): Add --nops.
(md_parse_option): Handle it.
(md_show_usage): Publish.
(ppc_handle_align): Pad with a branch followed by nops if more
than nop_limit nops.

gas/ChangeLog
gas/config/tc-ppc.c

index 5cb95f85ec7bbeed1add0ff7616ddbaa1bff86d6..65ca4cbc6dc4442ae647048e9eedfae127d90f6d 100644 (file)
@@ -1,3 +1,13 @@
+2010-11-04  Alan Modra  <amodra@gmail.com>
+
+       * config/tc-ppc.c (nop_limit): New var.
+       (OPTION_NOPS): Define.
+       (md_longopts): Add --nops.
+       (md_parse_option): Handle it.
+       (md_show_usage): Publish.
+       (ppc_handle_align): Pad with a branch followed by nops if more
+       than nop_limit nops.
+
 2010-11-03  H.J. Lu  <hongjiu.lu@intel.com>
 
        PR gas/12186
index f8c5d350810af18b2e041773cf93d58ce368c8ac..469abc177547181a21ff62cc730a5e8a467a4bbf 100644 (file)
@@ -180,6 +180,10 @@ const char ppc_symbol_chars[] = "%[";
 /* The dwarf2 data alignment, adjusted for 32 or 64 bit.  */
 int ppc_cie_data_alignment;
 
+/* More than this number of nops in an alignment op gets a branch
+   instead.  */
+unsigned long nop_limit = 4;
+
 /* The type of processor we are assembling for.  This is one or more
    of the PPC_OPCODE flags defined in opcode/ppc.h.  */
 ppc_cpu_t ppc_cpu = 0;
@@ -1018,7 +1022,9 @@ const char *const md_shortopts = "b:l:usm:K:VQ:";
 #else
 const char *const md_shortopts = "um:";
 #endif
+#define OPTION_NOPS (OPTION_MD_BASE + 0)
 const struct option md_longopts[] = {
+  {"nops", required_argument, NULL, OPTION_NOPS},
   {NULL, no_argument, NULL, 0}
 };
 const size_t md_longopts_size = sizeof (md_longopts);
@@ -1172,6 +1178,15 @@ md_parse_option (int c, char *arg)
       break;
 #endif
 
+    case OPTION_NOPS:
+      {
+       char *end;
+       nop_limit = strtoul (optarg, &end, 0);
+       if (*end)
+         as_bad (_("--nops needs a numeric argument"));
+      }
+      break;
+      
     default:
       return 0;
     }
@@ -1238,6 +1253,8 @@ PowerPC options:\n\
 -V                      print assembler version number\n\
 -Qy, -Qn                ignored\n"));
 #endif
+  fprintf (stream, _("\
+-nops=count             when aligning, more than COUNT nops uses a branch\n"));
 }
 \f
 /* Set ppc_cpu if it is not already set.  */
@@ -5748,6 +5765,31 @@ ppc_handle_align (struct frag *fragP)
       char *dest = fragP->fr_literal + fragP->fr_fix;
 
       fragP->fr_var = 4;
+
+      if (count > 4 * nop_limit && count < 0x2000000)
+       {
+         struct frag *rest;
+
+         /* Make a branch, then follow with nops.  Insert another
+            frag to handle the nops.  */
+         md_number_to_chars (dest, 0x48000000 + count, 4);
+         count -= 4;
+         if (count == 0)
+           return;
+
+         rest = xmalloc (SIZEOF_STRUCT_FRAG + 4);
+         memcpy (rest, fragP, SIZEOF_STRUCT_FRAG);
+         fragP->fr_next = rest;
+         fragP = rest;
+         rest->fr_address += rest->fr_fix + 4;
+         rest->fr_fix = 0;
+         /* If we leave the next frag as rs_align_code we'll come here
+            again, resulting in a bunch of branches rather than a
+            branch followed by nops.  */
+         rest->fr_type = rs_align;
+         dest = rest->fr_literal;
+       }
+
       md_number_to_chars (dest, 0x60000000, 4);
 
       if ((ppc_cpu & PPC_OPCODE_POWER6) != 0