powerpc padding nops
Alan Modra
amodra@gmail.com
Thu Nov 4 03:19:00 GMT 2010
This patch performs a simple optimization for powerpc nop padding,
replacing a large (>4 by default) number of nops with a branch.
* 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.
Index: gas/config/tc-ppc.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-ppc.c,v
retrieving revision 1.174
diff -u -p -r1.174 tc-ppc.c
--- gas/config/tc-ppc.c 29 Jul 2010 07:48:43 -0000 1.174
+++ gas/config/tc-ppc.c 7 Oct 2010 05:11:28 -0000
@@ -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:us
#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"));
}
/* 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
--
Alan Modra
Australia Development Lab, IBM
More information about the Binutils
mailing list