summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2010-11-04 03:30:05 +0000
committerAlan Modra <amodra@gmail.com>2010-11-04 03:30:05 +0000
commitcef4f75472a54f9dc833d3491a1ee6cf3a5a0968 (patch)
tree98564a94b22fe5e8e5947da162821c4f90733b9f
parent1dd6f20d5ec108230aef1fd3160cc77b268acfa6 (diff)
downloadbinutils-gdb-cef4f75472a54f9dc833d3491a1ee6cf3a5a0968.tar.gz
* 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.
-rw-r--r--gas/ChangeLog10
-rw-r--r--gas/config/tc-ppc.c42
2 files changed, 52 insertions, 0 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 5cb95f85ec7..65ca4cbc6dc 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -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
diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c
index f8c5d350810..469abc17754 100644
--- a/gas/config/tc-ppc.c
+++ b/gas/config/tc-ppc.c
@@ -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"));
}
/* 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