This is the mail archive of the binutils@sources.redhat.com 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]

fix Xtensa branch alignment code


This patch fixes a bug in the branch alignment code of the Xtensa GAS port. The code was checking the width of the Xtensa processor's instruction fetch interface to see how much alignment is required to avoid a stall for taken branches. This is correct as long as the current section is aligned at least as much as the fetch width, but the code was not checking the section alignment. Tested with an xtensa-elf target and committed on the mainline. I will put it on the branch, too.


2005-04-05 Sterling Augustine <sterling@tensilica.com> Bob Wilson <bob.wilson@acm.org>

	* config/tc-xtensa.c (branch_align_power): New.
	(xtensa_find_unaligned_branch_targets, get_aligned_diff,
	future_alignment_required): Use branch_align_power to check section
	alignment as well as xtensa_fetch_width when aligning branch targets.


Index: config/tc-xtensa.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-xtensa.c,v
retrieving revision 1.28
diff -u -p -r1.28 tc-xtensa.c
--- config/tc-xtensa.c	5 Apr 2005 20:55:40 -0000	1.28
+++ config/tc-xtensa.c	5 Apr 2005 23:01:09 -0000
@@ -448,6 +448,7 @@ static int total_frag_text_expansion (fr
 
 static int get_text_align_power (unsigned);
 static int get_text_align_max_fill_size (int, bfd_boolean, bfd_boolean);
+static int branch_align_power (segT);
 
 /* Helpers for xtensa_relax_frag().  */
 
@@ -4869,15 +4870,16 @@ xtensa_find_unaligned_branch_targets (bf
 	  if (frag->tc_frag_data.is_branch_target)
 	    {
 	      int op_size;
-	      addressT frag_addr;
+	      addressT branch_align, frag_addr;
 	      xtensa_format fmt;
 
 	      xtensa_insnbuf_from_chars
 		(isa, insnbuf, (unsigned char *) frag->fr_literal, 0);
 	      fmt = xtensa_format_decode (isa, insnbuf);
 	      op_size = xtensa_format_length (isa, fmt);
-	      frag_addr = frag->fr_address % xtensa_fetch_width;
-	      if (frag_addr + op_size > xtensa_fetch_width)
+	      branch_align = 1 << branch_align_power (sec);
+	      frag_addr = frag->fr_address % branch_align;
+	      if (frag_addr + op_size > branch_align)
 		as_warn_where (frag->fr_file, frag->fr_line,
 			       _("unaligned branch target: %d bytes at 0x%lx"),
 			       op_size, frag->fr_address);
@@ -8006,6 +8008,27 @@ get_text_align_fill_size (addressT addre
 }
 
 
+static int
+branch_align_power (segT sec)
+{
+  /* If the Xtensa processor has a fetch width of 8 bytes, and the section
+     is aligned to at least an 8-byte boundary, then a branch target need
+     only fit within an 8-byte aligned block of memory to avoid a stall.
+     Otherwise, try to fit branch targets within 4-byte aligned blocks
+     (which may be insufficient, e.g., if the section has no alignment, but
+     it's good enough).  */
+  if (xtensa_fetch_width == 8)
+    {
+      if (get_recorded_alignment (sec) >= 3)
+	return 3;
+    }
+  else
+    assert (xtensa_fetch_width == 4);
+
+  return 2;
+}
+
+
 /* This will assert if it is not possible.  */
 
 static int
@@ -8156,6 +8179,7 @@ get_aligned_diff (fragS *fragP, addressT
   bfd_boolean is_loop;
   int align_power;
   offsetT opt_diff;
+  addressT branch_align;
 
   assert (fragP->fr_type == rs_machine_dependent);
   switch (fragP->fr_subtype)
@@ -8164,13 +8188,13 @@ get_aligned_diff (fragS *fragP, addressT
       target_size = next_frag_format_size (fragP);
       if (target_size == XTENSA_UNDEFINED)
 	target_size = 3;
-      align_power = get_text_align_power (xtensa_fetch_width);
+      align_power = branch_align_power (now_seg);
+      branch_align = 1 << align_power;
       opt_diff = get_text_align_fill_size (address, align_power,
 					   target_size, FALSE, FALSE);
 
-      *max_diff = (opt_diff + xtensa_fetch_width
-		   - (target_size + ((address + opt_diff)
-				     % xtensa_fetch_width)));
+      *max_diff = (opt_diff + branch_align
+		   - (target_size + ((address + opt_diff) % branch_align)));
       assert (*max_diff >= opt_diff);
       return opt_diff;
 
@@ -8583,7 +8607,7 @@ future_alignment_required (fragS *fragP,
 	  address = find_address_of_next_align_frag
 	    (&fragP, &glob_widens, &dnn, &dw, &glob_pad);
 	  /* If there is a padable portion, then skip.  */
-	  if (glob_pad || glob_widens >= (int) xtensa_fetch_width)
+	  if (glob_pad || glob_widens >= (1 << branch_align_power (now_seg)))
 	    break;
 
 	  if (address) 

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