This patch fixes a case in sh.c:find_barrier(), triggered by a testcase
in glibc. The scanning starts from a GOT move instruction, records
itself in 'last_got', but does not find a second GOT move (to reset
last_got to NULL).
It finishes by trying to insert a new barrier in the insn stream, sees
last_got != NULL, and tries to insert at PREV_INSN(last_got), which goes
above the original start insn.
The caller, sh_reorg(), then gets the barrier scan target above the orig
insn, tries (in vain) to find it using a forward scan, and segfaults
when it goes past the insn stream...
The attached patch adds an additional equality check, plus some comment
updates. Cross-tested without regressions, is this okay for trunk?
2012-03-27 Chung-Lin Tang <clt...@codesourcery.com>
* config/sh/sh.c (find_barrier): Add equality check of last_got
to avoid going above orig insn. Update comments.
--- config/sh/sh.c (revision 185837)
+++ config/sh/sh.c (working copy)
@@ -4751,8 +4751,12 @@ find_barrier (int num_mova, rtx mova, rtx from)
/* Don't emit a constant table int the middle of global pointer setting,
since that that would move the addressing base GOT into another table.
We need the first mov instruction before the _GLOBAL_OFFSET_TABLE_
- in the pool anyway, so just move up the whole constant pool. */
- if (last_got)
+ in the pool anyway, so just move up the whole constant pool.
+ However, avoid doing so when the last single GOT mov is the starting
+ insn itself. Going past above the start insn would create a negative
+ offset, causing errors. */
+ if (last_got && last_got != orig)
from = PREV_INSN (last_got);
/* Don't insert the constant pool table at the position which