This is the mail archive of the 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]

[arm] Constant pool placement fix.

The fist if in add_minipool_forward_ref checks that the new fix fits before an 
existing constant pool.  However it does not catch the case where the 
instruction and the new constant pool entry would overlap. In this case the 
fixup would be added anyway, leading to out of range displacements.

The attached patch changes this code to check that the pool starts after the 
end of the corresponding instruction. It also modifies create_fix_barrier to 
verify that there is a suitable location for the pool instead of assuming it 
can be inserted after the last fixup.
The arm_reorg change fixes an off-by-one error uncovered by this checking. 
We need to set max_address just after the address of the next fixup because 
the create_fix_barrier makes space before the pool for a jump insn.

The original testcase is rather large, and very sensitive to changes.
I haven't managed to come up with a suitable testcase.

Tested with cross to arm-none-eabi.
Applied to mainline and branches/csl/arm-4_1.


2006-05-02  Paul Brook  <>

	* config/arm/arm.c (add_minipool_forward_ref): Check if insn
	and pool overlap.
	(create_fix_barrier): Check that a suitable barrier location is
	(arm_reorg): Include ftmp->address in allowable range of addresses.
Index: gcc/config/arm/arm.c
--- gcc/config/arm/arm.c	(revision 113438)
+++ gcc/config/arm/arm.c	(working copy)
@@ -7692,13 +7692,13 @@ add_minipool_forward_ref (Mfix *fix)
   HOST_WIDE_INT max_address = fix->address + fix->forwards - minipool_pad;
   Mnode *       mp;
-  /* If this fix's address is greater than the address of the first
-     entry, then we can't put the fix in this pool.  We subtract the
-     size of the current fix to ensure that if the table is fully
-     packed we still have enough room to insert this value by shuffling
-     the other fixes forwards.  */
+  /* If the minipool starts before the end of FIX->INSN then this FIX
+     can not be placed into the current pool.  Furthermore, adding the
+     new constant pool entry may cause the pool to start FIX_SIZE bytes
+     earlier.  */
   if (minipool_vector_head &&
-      fix->address >= minipool_vector_head->max_address - fix->fix_size)
+      (fix->address + get_attr_length (fix->insn)
+       >= minipool_vector_head->max_address - fix->fix_size))
     return NULL;
   /* Scan the pool to see if a constant with the same value has
@@ -8141,8 +8141,10 @@ create_fix_barrier (Mfix *fix, HOST_WIDE
   HOST_WIDE_INT count = 0;
   rtx barrier;
   rtx from = fix->insn;
-  rtx selected = from;
+  /* The instruction after which we will insert the jump.  */
+  rtx selected = NULL;
   int selected_cost;
+  /* The address at which the jump instruction will be placed.  */
   HOST_WIDE_INT selected_address;
   Mfix * new_fix;
   HOST_WIDE_INT max_count = max_address - fix->address;
@@ -8174,7 +8176,8 @@ create_fix_barrier (Mfix *fix, HOST_WIDE
 	     still put the pool after the table.  */
 	  new_cost = arm_barrier_cost (from);
-	  if (count < max_count && new_cost <= selected_cost)
+	  if (count < max_count 
+	      && (!selected || new_cost <= selected_cost))
 	      selected = tmp;
 	      selected_cost = new_cost;
@@ -8188,7 +8191,8 @@ create_fix_barrier (Mfix *fix, HOST_WIDE
       new_cost = arm_barrier_cost (from);
-      if (count < max_count && new_cost <= selected_cost)
+      if (count < max_count
+	  && (!selected || new_cost <= selected_cost))
 	  selected = from;
 	  selected_cost = new_cost;
@@ -8198,6 +8202,9 @@ create_fix_barrier (Mfix *fix, HOST_WIDE
       from = NEXT_INSN (from);
+  /* Make sure that we found a place to insert the jump.  */
+  gcc_assert (selected);
   /* Create a new JUMP_INSN that branches around a barrier.  */
   from = emit_jump_insn_after (gen_jump (label), selected);
   JUMP_LABEL (from) = label;
@@ -8548,9 +8555,11 @@ arm_reorg (void)
 	  /* Check that there isn't another fix that is in range that
 	     we couldn't fit into this pool because the pool was
 	     already too large: we need to put the pool before such an
-	     instruction.  */
+	     instruction.  The pool itself may come just after the
+	     fix because create_fix_barrier also allows space for a
+	     jump instruction.  */
 	  if (ftmp->address < max_address)
-	    max_address = ftmp->address;
+	    max_address = ftmp->address + 1;
 	  last_barrier = create_fix_barrier (last_added_fix, max_address);

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