This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[arm] Constant pool placement fix.
- From: Paul Brook <paul at codesourcery dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Tue, 2 May 2006 13:47:29 +0100
- Subject: [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.
Paul
2006-05-02 Paul Brook <paul@codesourcery.com>
* config/arm/arm.c (add_minipool_forward_ref): Check if insn
and pool overlap.
(create_fix_barrier): Check that a suitable barrier location is
found.
(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);
}