RFC: PATCH: PR gas/12049: Unnecessary relaxation

H.J. Lu hongjiu.lu@intel.com
Sat Oct 16 22:29:00 GMT 2010


For

        .fill 14, 1, 0x90
	jmp	.LBB1_23
        .fill 14, 1, 0x90
	jmp	.LBB1_23
        .fill 18, 1, 0x90
	.align	16, 0x90
        .fill 96, 1, 0x90
.LBB1_23:

For each segment, gas does:

1. Set address for each frag.
2. Relax and update address for each frag.
3. If stretched, goto 2.

When a rs_machine_dependent frag is relaxed with a forward reference,
it will change the address of all successive align frags, which in
turn may change the padding of those frags. This patch changes
relax_segment to

1. Set address for each frag.
2. Relax and update address for each frag.  For rs_machine_dependent
frag, if its size grows with forward reference, update fr_address for
all successive frags.
3. If stretched, goto 2.

Does it make any senses?

Thanks.


H.J.
---
gas/

2010-10-16  H.J. Lu  <hongjiu.lu@intel.com>

	PR gas/12049
	* write.c (relax_frag): Take an argument to indicate forward
	relax.
	(update_relax_frag_address): New.
	(relax_segment): Use it.  Call update_relax_frag_address to
	update fr_address for all successive frags after
	rs_machine_dependent frag.

	* write.h (relax_frag): Updated.

gas/testsuite/

2010-10-16  H.J. Lu  <hongjiu.lu@intel.com>

	PR gas/12049
	* gas/i386/i386.exp: Run relax-1 and relax-2.

	* gas/i386/relax-1.d: New.
	* gas/i386/relax-1.s: Likewise.
	* gas/i386/relax-2.d: Likewise.
	* gas/i386/relax-2.s: Likewise.

diff --git a/gas/testsuite/gas/i386/i386.exp b/gas/testsuite/gas/i386/i386.exp
index b89767f..fa76df8 100644
--- a/gas/testsuite/gas/i386/i386.exp
+++ b/gas/testsuite/gas/i386/i386.exp
@@ -199,6 +199,8 @@ if [expr ([istarget "i*86-*-*"] ||  [istarget "x86_64-*-*"]) && [gas_32_check]]
 	run_dump_test "intelpic"
 
 	run_dump_test "relax"
+	run_dump_test "relax-1"
+	run_dump_test "relax-2"
 	run_dump_test "gotpc"
 	run_dump_test "tlsd"
 	run_dump_test "tlspic"
diff --git a/gas/write.c b/gas/write.c
index 71ac635..654d14f 100644
--- a/gas/write.c
+++ b/gas/write.c
@@ -2115,7 +2115,7 @@ write_object_file (void)
 /* Relax a fragment by scanning TC_GENERIC_RELAX_TABLE.  */
 
 long
-relax_frag (segT segment, fragS *fragP, long stretch)
+relax_frag (segT segment, fragS *fragP, long stretch, int *forward)
 {
   const relax_typeS *this_type;
   const relax_typeS *start_type;
@@ -2203,7 +2203,10 @@ relax_frag (segT segment, fragS *fragP, long stretch)
 
   growth = this_type->rlx_length - start_type->rlx_length;
   if (growth != 0)
-    fragP->fr_subtype = this_state;
+    {
+      fragP->fr_subtype = this_state;
+      *forward = aim >= 0;
+    }
   return growth;
 }
 
@@ -2229,6 +2232,84 @@ relax_align (register relax_addressT address,	/* Address now.  */
   return (new_address - address);
 }
 
+/* Update fr_address with address and return the next address.  */
+
+static relax_addressT
+update_relax_frag_address (segT segment, struct frag *fragP,
+			   relax_addressT address)
+{
+  fragP->fr_address = address;
+  address += fragP->fr_fix;
+  switch (fragP->fr_type)
+    {
+    case rs_fill:
+      address += fragP->fr_offset * fragP->fr_var;
+      break;
+
+    case rs_align:
+    case rs_align_code:
+    case rs_align_test:
+	{
+	  addressT offset = relax_align (address, (int) fragP->fr_offset);
+
+	  if (fragP->fr_subtype != 0 && offset > fragP->fr_subtype)
+	    offset = 0;
+
+	  if (offset % fragP->fr_var != 0)
+	    {
+	      as_bad_where (fragP->fr_file, fragP->fr_line,
+			    _("alignment padding (%lu bytes) not a multiple of %ld"),
+			    (unsigned long) offset, (long) fragP->fr_var);
+	      offset -= (offset % fragP->fr_var);
+	    }
+
+	  address += offset;
+	}
+      break;
+
+    case rs_org:
+    case rs_space:
+      /* Assume .org is nugatory. It will grow with 1st relax.  */
+      break;
+
+    case rs_machine_dependent:
+      /* If fr_symbol is an expression, this call to
+	 resolve_symbol_value sets up the correct segment, which will
+	 likely be needed in md_estimate_size_before_relax.  */
+      if (fragP->fr_symbol)
+	resolve_symbol_value (fragP->fr_symbol);
+
+      address += md_estimate_size_before_relax (fragP, segment);
+      break;
+
+#ifndef WORKING_DOT_WORD
+      /* Broken words don't concern us yet.  */
+    case rs_broken_word:
+      break;
+#endif
+
+    case rs_leb128:
+      /* Initial guess is always 1; doing otherwise can result in
+	 stable solutions that are larger than the minimum.  */
+      address += fragP->fr_offset = 1;
+      break;
+
+    case rs_cfa:
+      address += eh_frame_estimate_size_before_relax (fragP);
+      break;
+
+    case rs_dwarf2dbg:
+      address += dwarf2dbg_estimate_size_before_relax (fragP);
+      break;
+
+    default:
+      BAD_CASE (fragP->fr_type);
+      break;
+    }
+
+  return address;
+}
+
 /* Now we have a segment, not a crowd of sub-segments, we can make
    fr_address values.
 
@@ -2258,75 +2339,7 @@ relax_segment (struct frag *segment_frag_root, segT segment, int pass)
        fragP = fragP->fr_next, frag_count ++)
     {
       fragP->relax_marker = 0;
-      fragP->fr_address = address;
-      address += fragP->fr_fix;
-
-      switch (fragP->fr_type)
-	{
-	case rs_fill:
-	  address += fragP->fr_offset * fragP->fr_var;
-	  break;
-
-	case rs_align:
-	case rs_align_code:
-	case rs_align_test:
-	  {
-	    addressT offset = relax_align (address, (int) fragP->fr_offset);
-
-	    if (fragP->fr_subtype != 0 && offset > fragP->fr_subtype)
-	      offset = 0;
-
-	    if (offset % fragP->fr_var != 0)
-	      {
-		as_bad_where (fragP->fr_file, fragP->fr_line,
-			      _("alignment padding (%lu bytes) not a multiple of %ld"),
-			      (unsigned long) offset, (long) fragP->fr_var);
-		offset -= (offset % fragP->fr_var);
-	      }
-
-	    address += offset;
-	  }
-	  break;
-
-	case rs_org:
-	case rs_space:
-	  /* Assume .org is nugatory. It will grow with 1st relax.  */
-	  break;
-
-	case rs_machine_dependent:
-	  /* If fr_symbol is an expression, this call to
-	     resolve_symbol_value sets up the correct segment, which will
-	     likely be needed in md_estimate_size_before_relax.  */
-	  if (fragP->fr_symbol)
-	    resolve_symbol_value (fragP->fr_symbol);
-
-	  address += md_estimate_size_before_relax (fragP, segment);
-	  break;
-
-#ifndef WORKING_DOT_WORD
-	  /* Broken words don't concern us yet.  */
-	case rs_broken_word:
-	  break;
-#endif
-
-	case rs_leb128:
-	  /* Initial guess is always 1; doing otherwise can result in
-	     stable solutions that are larger than the minimum.  */
-	  address += fragP->fr_offset = 1;
-	  break;
-
-	case rs_cfa:
-	  address += eh_frame_estimate_size_before_relax (fragP);
-	  break;
-
-	case rs_dwarf2dbg:
-	  address += dwarf2dbg_estimate_size_before_relax (fragP);
-	  break;
-
-	default:
-	  BAD_CASE (fragP->fr_type);
-	  break;
-	}
+      address = update_relax_frag_address (segment, fragP, address);
     }
 
   /* Do relax().  */
@@ -2391,6 +2404,7 @@ relax_segment (struct frag *segment_frag_root, segT segment, int pass)
 	    addressT was_address;
 	    offsetT offset;
 	    symbolS *symbolP;
+	    int forward = 0;
 
 	    fragP->relax_marker ^= 1;
 	    was_address = fragP->fr_address;
@@ -2637,9 +2651,33 @@ relax_segment (struct frag *segment_frag_root, segT segment, int pass)
 #ifdef TC_GENERIC_RELAX_TABLE
 		/* The default way to relax a frag is to look through
 		   TC_GENERIC_RELAX_TABLE.  */
-		growth = relax_frag (segment, fragP, stretch);
+		growth = relax_frag (segment, fragP, stretch, &forward);
 #endif /* TC_GENERIC_RELAX_TABLE  */
 #endif
+		if (forward)
+		  {
+		    /* If this frag is grown due to forward relaxation,
+		       update fr_address for all successive frags.  */
+		    fragS *f = fragP->fr_next;
+		    if (f)
+		      {
+			/* Update address with growth.  */
+			relax_addressT new_address
+			  = f->fr_address + growth;
+			for (; f; f = f->fr_next)
+			  {
+			    unsigned int relax_marker = f->relax_marker;
+			    f->relax_marker = 0;
+			    new_address
+			      = update_relax_frag_address (segment, f,
+							   new_address);
+			    f->relax_marker = relax_marker;
+			  }
+
+			/* Adjust stretch.  */
+			stretch -= growth;
+		      }
+		  }
 		break;
 
 	      case rs_leb128:
diff --git a/gas/write.h b/gas/write.h
index 8303f1b..ba8f0c3 100644
--- a/gas/write.h
+++ b/gas/write.h
@@ -169,7 +169,7 @@ extern void record_alignment (segT seg, int align);
 extern int get_recorded_alignment (segT seg);
 extern void subsegs_finish (void);
 extern void write_object_file (void);
-extern long relax_frag (segT, fragS *, long);
+extern long relax_frag (segT, fragS *, long, int *);
 extern int relax_segment (struct frag *, segT, int);
 extern void number_to_chars_littleendian (char *, valueT, int);
 extern void number_to_chars_bigendian (char *, valueT, int);
--- /dev/null	2010-10-13 10:55:58.381855970 -0700
+++ binutils/gas/testsuite/gas/i386/relax-1.d	2010-10-16 15:09:02.413848676 -0700
@@ -0,0 +1,16 @@
+#name: i386 relax 1
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+0+ <.text>:
+#...
+   e:	e9 8d 00 00 00       	jmp    0xa0
+#...
+  21:	eb 7d                	jmp    0xa0
+#...
+  a0:	90                   	nop
+#pass
--- /dev/null	2010-10-13 10:55:58.381855970 -0700
+++ binutils/gas/testsuite/gas/i386/relax-1.s	2010-10-16 14:14:59.349967119 -0700
@@ -0,0 +1,10 @@
+	.text
+        .fill 14, 1, 0x90
+	jmp	.LBB1_23
+        .fill 14, 1, 0x90
+	jmp	.LBB1_23
+        .fill 18, 1, 0x90
+	.align	16, 0x90
+        .fill 96, 1, 0x90
+.LBB1_23:
+	nop
--- /dev/null	2010-10-13 10:55:58.381855970 -0700
+++ binutils/gas/testsuite/gas/i386/relax-2.d	2010-10-16 14:18:06.551845774 -0700
@@ -0,0 +1,16 @@
+#name: i386 relax 3
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+0+ <.text>:
+#...
+  38:	0f 85 88 00 00 00    	jne    0xc6
+#...
+  48:	75 7c                	jne    0xc6
+#...
+  c6:	90                   	nop
+#pass
--- /dev/null	2010-10-13 10:55:58.381855970 -0700
+++ binutils/gas/testsuite/gas/i386/relax-2.s	2010-10-16 14:15:04.586905285 -0700
@@ -0,0 +1,10 @@
+	.text
+        .fill 56, 1, 0x90
+	jne .LBB0_43
+        .fill 10, 1, 0x90
+	jne .LBB0_43
+        .fill 5, 1, 0x90
+	.align 16, 0x90
+        .fill 118, 1, 0x90
+.LBB0_43:
+	nop



More information about the Binutils mailing list