This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC 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]

Re: Add -fsection-anchors (4.2 project)


Mark Mitchell <mark@codesourcery.com> writes:
>> +void
>> +rtl_check_failed_block_symbol (const char *file, int line, const char *func)
>
> Nit: this new function should have a comment.

Fixed.

I also noticed a few problems with the offset calculation code in
get_section_anchor:

  - It didn't detect the case where the offset range was the same
    as the range of a HOST_WIDE_INT.  We'd get division by zero
    in that case.

  - Related, "targetm.max_anchor_offset - targetm.min_anchor_offset + 1"
    could lead to signed overflow.

  - "offset - targetm.min_anchor_offset" could lead to signed overflow.

  - We didn't cope very well with offsets that were outside the range
    of the regularly-spaced, 0-based anchors.

The patch below should fix these problems and was approved off-list by Mark.
As well as the usual testing, I copied the new code to a self-contained
program and made sure that it behaved as expected for some off-beat
values of GET_MODE_BITSIZE (ptr_mode) and {min,max}_anchor_offset.

David Edelsohn thought that using a 16-bit offset was too restrictive.
I suppose it probably is for PowerPC, where addis provides a cheap
way of adding a 64k offset to an anchor (both in terms of size and
speed).  We settled on a 32-bit offset instead; this part was
approved off-list by David.  As a result:

    static int x[0x10000];
    static int y,z;
    int foo (voiD) { return x[0] + x[0xffff] + y + z; }

produces the following code when compiled with -O2 -fsection-anchors:

.L.foo:
        ld 11,.LC0@toc(2)
        addis 9,11,0x4
        lwz 10,0(11)
        lwz 3,-4(9)
        lwz 0,0(9)
        lwz 11,4(9)
        add 3,3,10
        add 3,3,0
        add 3,3,11
        extsw 3,3
        blr

The SPEC results were very similar to before (i.e. all differences
appeared to be in noise range).

I bootstrapped & regression tested the patch on powerpc64-linux-gnu
with the additional changes below (which are relative to the original
patch, and covered by the same ChangeLog).  Applied to trunk.

Richard


diff -upr gcc.old/config/rs6000/rs6000.c gcc/config/rs6000/rs6000.c
--- gcc/config/rs6000/rs6000.c	2006-02-18 01:42:42.000000000 -0800
+++ gcc/config/rs6000/rs6000.c	2006-02-16 03:56:44.000000000 -0800
@@ -1022,10 +1022,17 @@ static const char alt_reg_names[][8] =
 #define TARGET_ASM_OUTPUT_DWARF_DTPREL rs6000_output_dwarf_dtprel
 #endif
 
+/* Use a 32-bit anchor range.  This leads to sequences like:
+
+	addis	tmp,anchor,high
+	add	dest,tmp,low
+
+   where tmp itself acts as an anchor, and can be shared between
+   accesses to the same 64k page.  */
 #undef TARGET_MIN_ANCHOR_OFFSET
-#define TARGET_MIN_ANCHOR_OFFSET -32768
+#define TARGET_MIN_ANCHOR_OFFSET -0x7fffffff - 1
 #undef TARGET_MAX_ANCHOR_OFFSET
-#define TARGET_MAX_ANCHOR_OFFSET 32767
+#define TARGET_MAX_ANCHOR_OFFSET 0x7fffffff
 #undef TARGET_USE_BLOCKS_FOR_CONSTANT_P
 #define TARGET_USE_BLOCKS_FOR_CONSTANT_P rs6000_use_blocks_for_constant_p
 
diff -upr gcc.old/rtl.c gcc/rtl.c
--- gcc/rtl.c	2006-02-18 01:42:52.000000000 -0800
+++ gcc/rtl.c	2006-02-16 03:56:44.000000000 -0800
@@ -536,6 +536,9 @@ rtl_check_failed_code_mode (rtx r, enum 
 		  func, trim_filename (file), line);
 }
 
+/* Report that line LINE of FILE tried to access the block symbol fields
+   of a non-block symbol.  FUNC is the function that contains the line.  */
+
 void
 rtl_check_failed_block_symbol (const char *file, int line, const char *func)
 {
diff -upr gcc.old/varasm.c gcc/varasm.c
--- gcc/varasm.c	2006-02-18 01:42:42.000000000 -0800
+++ gcc/varasm.c	2006-02-18 00:17:17.000000000 -0800
@@ -6004,15 +6004,48 @@ get_section_anchor (struct object_block 
 {
   char label[100];
   unsigned int begin, middle, end;
+  unsigned HOST_WIDE_INT min_offset, max_offset, range, bias, delta;
   rtx anchor;
 
   /* Work out the anchor's offset.  Use an offset of 0 for the first
      anchor so that we don't pessimize the case where we take the address
      of a variable at the beginning of the block.  This is particularly
-     useful when a block has only one variable assigned to it.  */
-  offset = ((offset - targetm.min_anchor_offset)
-	    / (targetm.max_anchor_offset - targetm.min_anchor_offset + 1)
-	    * (targetm.max_anchor_offset - targetm.min_anchor_offset + 1));
+     useful when a block has only one variable assigned to it.
+
+     We try to place anchors RANGE bytes apart, so there can then be
+     anchors at +/-RANGE, +/-2 * RANGE, and so on, up to the limits of
+     a ptr_mode offset.  With some target settings, the lowest such
+     anchor might be out of range for the lowest ptr_mode offset;
+     likewise the highest anchor for the highest offset.  Use anchors
+     at the extreme ends of the ptr_mode range in such cases.
+
+     All arithmetic uses unsigned integers in order to avoid
+     signed overflow.  */
+  max_offset = (unsigned HOST_WIDE_INT) targetm.max_anchor_offset;
+  min_offset = (unsigned HOST_WIDE_INT) targetm.min_anchor_offset;
+  range = max_offset - min_offset + 1;
+  if (range == 0)
+    offset = 0;
+  else
+    {
+      bias = 1 << (GET_MODE_BITSIZE (ptr_mode) - 1);
+      if (offset < 0)
+	{
+	  delta = -(unsigned HOST_WIDE_INT) offset + max_offset;
+	  delta -= delta % range;
+	  if (delta > bias)
+	    delta = bias;
+	  offset = (HOST_WIDE_INT) (-delta);
+	}
+      else
+	{
+	  delta = (unsigned HOST_WIDE_INT) offset - min_offset;
+	  delta -= delta % range;
+	  if (delta > bias - 1)
+	    delta = bias - 1;
+	  offset = (HOST_WIDE_INT) delta;
+	}
+    }
 
   /* Do a binary search to see if there's already an anchor we can use.
      Set BEGIN to the new anchor's index if not.  */


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