This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch] rx .fetchalign pseudo


The RX chip incurs a one-cycle penalty if you branch to an opcode that
spans a fetch boundary (8 bytes).  This new pseudo acts like a
.p2align with a max-skip one byte less than the size of the next
opcode, so that the next opcode (and any interceeding labels, of
course) will be known to not span a fetch boundary.

Committed.

	* config/tc-rx.c (rx_fetchalign): Declare.
	(md_pseudo_table): Add .fetchalign.
	(RX_NBASE_FETCHALIGN): New.
	(fetchalign_bytes): New.
	(rx_fetchalign): New.
	(rx_frag_init): If a "magic" value is found, also init the
	machine-specific data.
	(md_assemble): Note following opcode size if called for.
	(rx_next_opcode): New.
	(rx_relax_frag): Support .fetchalign.
	(md_convert_frag): Likewise.
	* doc/c-rx.texi (RX-Directives): Add .fetchalign.

Index: gas/config/tc-rx.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-rx.c,v
retrieving revision 1.11
diff -p -U5 -r1.11  gas/config/tc-rx.c
--- gas/config/tc-rx.c	5 Oct 2011 14:13:28 -0000	1.11
+++ gas/config/tc-rx.c	15 May 2012 02:43:14 -0000
@@ -54,10 +54,12 @@ static bfd_boolean rx_use_small_data_lim
 static bfd_boolean rx_pid_mode = FALSE;
 static int rx_num_int_regs = 0;
 int rx_pid_register;
 int rx_gp_register;
 
+static void rx_fetchalign (int ignore ATTRIBUTE_UNUSED);
+
 enum options
 {
   OPTION_BIG = OPTION_MD_BASE,
   OPTION_LITTLE,
   OPTION_32BIT_DOUBLES,
@@ -598,10 +600,12 @@ const pseudo_typeS md_pseudo_table[] =
   { "bss",	s_bss, 		0 },
   { "3byte",	cons,		3 },
   { "int",	cons,		4 },
   { "word",	cons,		4 },
 
+  { "fetchalign", rx_fetchalign, 0 },
+
   /* End of list marker.  */
   { NULL, 	NULL, 		0 }
 };
 
 static asymbol * gp_symbol;
@@ -646,13 +650,18 @@ md_begin (void)
 }
 
 char * rx_lex_start;
 char * rx_lex_end;
 
+/* These negative numbers are found in rx_bytesT.n_base for non-opcode
+   md_frags */
+#define RX_NBASE_FETCHALIGN	-1
+
 typedef struct rx_bytesT
 {
   char base[4];
+  /* If this is negative, it's a special-purpose frag as per the defines above. */
   int n_base;
   char ops[8];
   int n_ops;
   struct
   {
@@ -676,10 +685,35 @@ typedef struct rx_bytesT
   char times_grown;
   char times_shrank;
 } rx_bytesT;
 
 static rx_bytesT rx_bytes;
+/* We set n_ops to be "size of next opcode" if the next opcode doesn't relax.  */
+static rx_bytesT *fetchalign_bytes = NULL;
+
+static void
+rx_fetchalign (int ignore ATTRIBUTE_UNUSED)
+{
+  char * bytes;
+  fragS * frag_then;
+
+  memset (& rx_bytes, 0, sizeof (rx_bytes));
+  rx_bytes.n_base = RX_NBASE_FETCHALIGN;
+
+  bytes = frag_more (8);
+  frag_then = frag_now;
+  frag_variant (rs_machine_dependent,
+		0 /* max_chars */,
+		0 /* var */,
+		0 /* subtype */,
+		0 /* symbol */,
+		0 /* offset */,
+		0 /* opcode */);
+  frag_then->fr_opcode = bytes;
+  frag_then->fr_subtype = 0;
+  fetchalign_bytes = frag_then->tc_frag_data;
+}
 
 void
 rx_relax (int type, int pos)
 {
   rx_bytes.relax[rx_bytes.n_relax].type = type;
@@ -931,11 +965,11 @@ rx_wrap (void)
     }
 
 void
 rx_frag_init (fragS * fragP)
 {
-  if (rx_bytes.n_relax || rx_bytes.link_relax)
+  if (rx_bytes.n_relax || rx_bytes.link_relax || rx_bytes.n_base < 0)
     {
       fragP->tc_frag_data = malloc (sizeof (rx_bytesT));
       memcpy (fragP->tc_frag_data, & rx_bytes, sizeof (rx_bytesT));
     }
   else
@@ -1047,12 +1081,16 @@ md_assemble (char * str)
     }
   else
     {
       bytes = frag_more (rx_bytes.n_base + rx_bytes.n_ops);
       frag_then = frag_now;
+      if (fetchalign_bytes)
+	fetchalign_bytes->n_ops = rx_bytes.n_base + rx_bytes.n_ops;
     }
 
+  fetchalign_bytes = NULL;
+
   APPEND (base, n_base);
   APPEND (ops, n_ops);
 
   if (rx_bytes.link_relax && rx_bytes.n_fixups)
     {
@@ -1411,10 +1449,22 @@ md_estimate_size_before_relax (fragS * f
 
   tprintf (" -> opfixsize %d delta %d\n", opfixsize, delta);
   return delta;
 }
 
+/* Given a frag FRAGP, return the "next" frag that contains an
+   opcode.  Assumes the next opcode is relaxable, and thus rs_machine_dependent.  */
+
+static fragS *
+rx_next_opcode (fragS *fragP)
+{
+  do {
+    fragP = fragP->fr_next;
+  } while (fragP && fragP->fr_type != rs_machine_dependent);
+  return fragP;
+}
+
 /* Given the new addresses for this relax pass, figure out how big
    each opcode must be.  We store the total number of bytes needed in
    fr_subtype.  The return value is the difference between the size
    after the last pass and the size after this pass, so we use the old
    fr_subtype to calculate the difference.  */
@@ -1435,10 +1485,38 @@ rx_relax_frag (segT segment ATTRIBUTE_UN
 	   (unsigned long) (fragP->fr_address
 			    + (fragP->fr_opcode - fragP->fr_literal)),
 	   (long) fragP->fr_fix, (long) fragP->fr_var, (long) fragP->fr_offset,
 	   fragP->fr_literal, fragP->fr_opcode, fragP->fr_type, fragP->fr_subtype, stretch);
 
+  mypc = fragP->fr_address + (fragP->fr_opcode - fragP->fr_literal);
+
+  if (fragP->tc_frag_data->n_base == RX_NBASE_FETCHALIGN)
+    {
+      unsigned int next_size;
+      if (fragP->fr_next == NULL)
+	return 0;
+
+      next_size = fragP->tc_frag_data->n_ops;
+      if (next_size == 0)
+	{
+	  fragS *n = rx_next_opcode (fragP);
+	  next_size = n->fr_subtype;
+	}
+
+      fragP->fr_subtype = (8-(mypc & 7)) & 7;
+      tprintf("subtype %u\n", fragP->fr_subtype);
+      if (fragP->fr_subtype >= next_size)
+	fragP->fr_subtype = 0;
+      tprintf ("\033[34m -> mypc %lu next_size %u new %d old %d delta %d (fetchalign)\033[0m\n",
+	       mypc & 7,
+	       next_size, fragP->fr_subtype, oldsize, fragP->fr_subtype-oldsize);
+
+      newsize = fragP->fr_subtype;
+
+      return newsize - oldsize;
+    }
+
   optype = rx_opcode_type (fragP->fr_opcode);
 
   /* In the one case where we have both a disp and imm relaxation, we want
      the imm relaxation here.  */
   ri = 0;
@@ -1483,11 +1561,10 @@ rx_relax_frag (segT segment ATTRIBUTE_UN
       fragP->fr_subtype = newsize;
       tprintf (" -> new %d old %d delta %d (external)\n", newsize, oldsize, newsize-oldsize);
       return newsize - oldsize;
     }
 
-  mypc = fragP->fr_address + (fragP->fr_opcode - fragP->fr_literal);
   if (sym_addr > mypc)
     addr0 += stretch;
 
   switch (fragP->tc_frag_data->relax[ri].type)
     {
@@ -1642,17 +1719,33 @@ md_convert_frag (bfd *   abfd ATTRIBUTE_
 
 #if TRACE_RELAX
   {
     int i;
 
-    printf ("lit %08x opc %08x", (int) fragP->fr_literal, (int) fragP->fr_opcode);
+    printf ("lit 0x%p opc 0x%p", fragP->fr_literal, fragP->fr_opcode);
     for (i = 0; i < 10; i++)
       printf (" %02x", (unsigned char) (fragP->fr_opcode[i]));
     printf ("\n");
   }
 #endif
 
+  if (fragP->tc_frag_data->n_base == RX_NBASE_FETCHALIGN)
+    {
+      int count = fragP->fr_subtype;
+      if (count == 0)
+	;
+      else if (count > BIGGEST_NOP)
+	{
+	  op[0] = 0x2e;
+	  op[1] = count;
+	}
+      else if (count > 0)
+	{
+	  memcpy (op, nops[count], count);
+	}
+    }
+
   /* In the one case where we have both a disp and imm relaxation, we want
      the imm relaxation here.  */
   ri = 0;
   if (fragP->tc_frag_data->n_relax > 1
       && fragP->tc_frag_data->relax[0].type == RX_RELAX_DISP)
Index: gas/doc/c-rx.texi
===================================================================
RCS file: /cvs/src/src/gas/doc/c-rx.texi,v
retrieving revision 1.3
diff -p -U5 -r1.3  gas/doc/c-rx.texi
--- gas/doc/c-rx.texi	5 Oct 2011 14:13:28 -0000	1.3
+++ gas/doc/c-rx.texi	15 May 2012 02:43:15 -0000
@@ -153,10 +153,20 @@ assembler directives:
 @item .3byte
 @cindex assembler directive .3byte, RX
 @cindex RX assembler directive .3byte
 Inserts a 3-byte value into the output file at the current location.
 
+@item .fetchalign
+@cindex assembler directive .fetchalign, RX
+@cindex RX assembler directive .fetchalign
+If the next opcode following this directive spans a fetch line
+boundary (8 byte boundary), the opcode is aligned to that boundary.
+If the next opcode does not span a fetch line, this directive has no
+effect.  Note that one or more labels may be between this directive
+and the opcode; those labels are aligned as well.  Any inserted bytes
+due to alignment will form a NOP opcode.
+
 @end table
 
 @node RX-Float
 @section Floating Point
 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]