re PR target/55718 (ICE in gen_reg_rtx, at emit-rtl.c:866)

2013-01-10  Andreas Krebbel  <Andreas.Krebbel@de.ibm.com>

	PR target/55718
	* config/s390/s390.c (s390_symref_operand_p)
	(s390_loadrelative_operand_p): Merge the two functions.
	(s390_check_qrst_address, print_operand_address): Add parameters
	to s390_loadrelative_operand_p invokation.
	(s390_check_symref_alignment): Use s390_loadrelative_operand_p.
	(s390_reload_larl_operand, s390_secondary_reload): Use
	s390_loadrelative_operand_p instead of s390_symref_operand_p.
	(legitimize_pic_address): Handle @GOTENT and @PLT + addend.

From-SVN: r195078
This commit is contained in:
Andreas Krebbel 2013-01-10 08:15:07 +00:00 committed by Andreas Krebbel
parent 01a3a32422
commit 0ff4390dd3
3 changed files with 273 additions and 248 deletions

View File

@ -1,3 +1,15 @@
2013-01-10 Andreas Krebbel <Andreas.Krebbel@de.ibm.com>
PR target/55718
* config/s390/s390.c (s390_symref_operand_p)
(s390_loadrelative_operand_p): Merge the two functions.
(s390_check_qrst_address, print_operand_address): Add parameters
to s390_loadrelative_operand_p invokation.
(s390_check_symref_alignment): Use s390_loadrelative_operand_p.
(s390_reload_larl_operand, s390_secondary_reload): Use
s390_loadrelative_operand_p instead of s390_symref_operand_p.
(legitimize_pic_address): Handle @GOTENT and @PLT + addend.
2013-01-09 Mike Stump <mikestump@comcast.net>
* dse.c (record_store): Remove unnecessary assert.

View File

@ -2148,13 +2148,17 @@ s390_legitimate_address_without_index_p (rtx op)
}
/* Return true if ADDR is of kind symbol_ref or symbol_ref + const_int
and return these parts in SYMREF and ADDEND. You can pass NULL in
SYMREF and/or ADDEND if you are not interested in these values.
Literal pool references are *not* considered symbol references. */
/* Return TRUE if ADDR is an operand valid for a load/store relative
instruction. Be aware that the alignment of the operand needs to
be checked separately.
Valid addresses are single references or a sum of a reference and a
constant integer. Return these parts in SYMREF and ADDEND. You can
pass NULL in REF and/or ADDEND if you are not interested in these
values. Literal pool references are *not* considered symbol
references. */
static bool
s390_symref_operand_p (rtx addr, rtx *symref, HOST_WIDE_INT *addend)
s390_loadrelative_operand_p (rtx addr, rtx *symref, HOST_WIDE_INT *addend)
{
HOST_WIDE_INT tmpaddend = 0;
@ -2163,43 +2167,26 @@ s390_symref_operand_p (rtx addr, rtx *symref, HOST_WIDE_INT *addend)
if (GET_CODE (addr) == PLUS)
{
if (GET_CODE (XEXP (addr, 0)) == SYMBOL_REF
&& !CONSTANT_POOL_ADDRESS_P (XEXP (addr, 0))
&& CONST_INT_P (XEXP (addr, 1)))
{
tmpaddend = INTVAL (XEXP (addr, 1));
addr = XEXP (addr, 0);
}
else
if (!CONST_INT_P (XEXP (addr, 1)))
return false;
tmpaddend = INTVAL (XEXP (addr, 1));
addr = XEXP (addr, 0);
}
else
if (GET_CODE (addr) != SYMBOL_REF || CONSTANT_POOL_ADDRESS_P (addr))
return false;
if (symref)
*symref = addr;
if (addend)
*addend = tmpaddend;
if ((GET_CODE (addr) == SYMBOL_REF && !CONSTANT_POOL_ADDRESS_P (addr))
|| (GET_CODE (addr) == UNSPEC
&& (XINT (addr, 1) == UNSPEC_GOTENT
|| (TARGET_CPU_ZARCH && XINT (addr, 1) == UNSPEC_PLT))))
{
if (symref)
*symref = addr;
if (addend)
*addend = tmpaddend;
return true;
}
/* Return TRUE if ADDR is an operand valid for a load/store relative
instructions. Be aware that the alignment of the operand needs to
be checked separately. */
static bool
s390_loadrelative_operand_p (rtx addr)
{
if (GET_CODE (addr) == CONST)
addr = XEXP (addr, 0);
/* Enable load relative for symbol@GOTENT. */
if (GET_CODE (addr) == UNSPEC
&& XINT (addr, 1) == UNSPEC_GOTENT)
return true;
return s390_symref_operand_p (addr, NULL, NULL);
return true;
}
return false;
}
/* Return true if the address in OP is valid for constraint letter C
@ -2215,7 +2202,7 @@ s390_check_qrst_address (char c, rtx op, bool lit_pool_ok)
/* This check makes sure that no symbolic address (except literal
pool references) are accepted by the R or T constraints. */
if (s390_loadrelative_operand_p (op))
if (s390_loadrelative_operand_p (op, NULL, NULL))
return 0;
/* Ensure literal pool references are only accepted if LIT_POOL_OK. */
@ -3022,18 +3009,21 @@ s390_check_symref_alignment (rtx addr, HOST_WIDE_INT alignment)
HOST_WIDE_INT addend;
rtx symref;
/* Accept symbol@GOTENT with pointer size alignment. */
if (GET_CODE (addr) == CONST
&& GET_CODE (XEXP (addr, 0)) == UNSPEC
&& XINT (XEXP (addr, 0), 1) == UNSPEC_GOTENT
if (!s390_loadrelative_operand_p (addr, &symref, &addend))
return false;
if (addend & (alignment - 1))
return false;
if (GET_CODE (symref) == SYMBOL_REF
&& !SYMBOL_REF_NOT_NATURALLY_ALIGNED_P (symref))
return true;
if (GET_CODE (symref) == UNSPEC
&& alignment <= UNITS_PER_LONG)
return true;
if (!s390_symref_operand_p (addr, &symref, &addend))
return false;
return (!SYMBOL_REF_NOT_NATURALLY_ALIGNED_P (symref)
&& !(addend & (alignment - 1)));
return false;
}
/* ADDR is moved into REG using larl. If ADDR isn't a valid larl
@ -3046,7 +3036,7 @@ s390_reload_larl_operand (rtx reg, rtx addr, rtx scratch)
HOST_WIDE_INT addend;
rtx symref;
if (!s390_symref_operand_p (addr, &symref, &addend))
if (!s390_loadrelative_operand_p (addr, &symref, &addend))
gcc_unreachable ();
if (!(addend & 1))
@ -3132,7 +3122,7 @@ s390_secondary_reload (bool in_p, rtx x, reg_class_t rclass_i,
/* On z10 several optimizer steps may generate larl operands with
an odd addend. */
if (in_p
&& s390_symref_operand_p (x, &symref, &offset)
&& s390_loadrelative_operand_p (x, &symref, &offset)
&& mode == Pmode
&& !SYMBOL_REF_ALIGN1_P (symref)
&& (offset & 1) == 1)
@ -3144,7 +3134,7 @@ s390_secondary_reload (bool in_p, rtx x, reg_class_t rclass_i,
or if the symref addend of a SI or DI move is not aligned to the
width of the access. */
if (MEM_P (x)
&& s390_symref_operand_p (XEXP (x, 0), NULL, NULL)
&& s390_loadrelative_operand_p (XEXP (x, 0), NULL, NULL)
&& (mode == QImode || mode == TImode || FLOAT_MODE_P (mode)
|| (!TARGET_ZARCH && mode == DImode)
|| ((mode == HImode || mode == SImode || mode == DImode)
@ -3419,52 +3409,125 @@ rtx
legitimize_pic_address (rtx orig, rtx reg)
{
rtx addr = orig;
rtx addend = const0_rtx;
rtx new_rtx = orig;
rtx base;
gcc_assert (!TLS_SYMBOLIC_CONST (addr));
if (GET_CODE (addr) == LABEL_REF
|| (GET_CODE (addr) == SYMBOL_REF && SYMBOL_REF_LOCAL_P (addr)))
{
/* This is a local symbol. */
if (TARGET_CPU_ZARCH && larl_operand (addr, VOIDmode))
{
/* Access local symbols PC-relative via LARL.
This is the same as in the non-PIC case, so it is
handled automatically ... */
}
else
{
/* Access local symbols relative to the GOT. */
if (GET_CODE (addr) == CONST)
addr = XEXP (addr, 0);
rtx temp = reg? reg : gen_reg_rtx (Pmode);
if (GET_CODE (addr) == PLUS)
{
addend = XEXP (addr, 1);
addr = XEXP (addr, 0);
}
if ((GET_CODE (addr) == LABEL_REF
|| (GET_CODE (addr) == SYMBOL_REF && SYMBOL_REF_LOCAL_P (addr))
|| (GET_CODE (addr) == UNSPEC &&
(XINT (addr, 1) == UNSPEC_GOTENT
|| (TARGET_CPU_ZARCH && XINT (addr, 1) == UNSPEC_PLT))))
&& GET_CODE (addend) == CONST_INT)
{
/* This can be locally addressed. */
/* larl_operand requires UNSPECs to be wrapped in a const rtx. */
rtx const_addr = (GET_CODE (addr) == UNSPEC ?
gen_rtx_CONST (Pmode, addr) : addr);
if (TARGET_CPU_ZARCH
&& larl_operand (const_addr, VOIDmode)
&& INTVAL (addend) < (HOST_WIDE_INT)1 << 31
&& INTVAL (addend) >= -((HOST_WIDE_INT)1 << 31))
{
if (INTVAL (addend) & 1)
{
/* LARL can't handle odd offsets, so emit a pair of LARL
and LA. */
rtx temp = reg? reg : gen_reg_rtx (Pmode);
if (!DISP_IN_RANGE (INTVAL (addend)))
{
HOST_WIDE_INT even = INTVAL (addend) - 1;
addr = gen_rtx_PLUS (Pmode, addr, GEN_INT (even));
addr = gen_rtx_CONST (Pmode, addr);
addend = const1_rtx;
}
emit_move_insn (temp, addr);
new_rtx = gen_rtx_PLUS (Pmode, temp, addend);
if (reg != 0)
{
s390_load_address (reg, new_rtx);
new_rtx = reg;
}
}
else
{
/* If the offset is even, we can just use LARL. This
will happen automatically. */
}
}
else
{
/* No larl - Access local symbols relative to the GOT. */
rtx temp = reg? reg : gen_reg_rtx (Pmode);
if (reload_in_progress || reload_completed)
df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOTOFF);
addr = gen_rtx_CONST (Pmode, addr);
addr = force_const_mem (Pmode, addr);
addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOTOFF);
if (addend != const0_rtx)
addr = gen_rtx_PLUS (Pmode, addr, addend);
addr = gen_rtx_CONST (Pmode, addr);
addr = force_const_mem (Pmode, addr);
emit_move_insn (temp, addr);
new_rtx = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp);
if (reg != 0)
{
s390_load_address (reg, new_rtx);
new_rtx = reg;
}
}
new_rtx = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp);
if (reg != 0)
{
s390_load_address (reg, new_rtx);
new_rtx = reg;
}
}
}
else if (GET_CODE (addr) == SYMBOL_REF)
else if (GET_CODE (addr) == SYMBOL_REF && addend == const0_rtx)
{
/* A non-local symbol reference without addend.
The symbol ref is wrapped into an UNSPEC to make sure the
proper operand modifier (@GOT or @GOTENT) will be emitted.
This will tell the linker to put the symbol into the GOT.
Additionally the code dereferencing the GOT slot is emitted here.
An addend to the symref needs to be added afterwards.
legitimize_pic_address calls itself recursively to handle
that case. So no need to do it here. */
if (reg == 0)
reg = gen_reg_rtx (Pmode);
if (flag_pic == 1)
if (TARGET_Z10)
{
/* Use load relative if possible.
lgrl <target>, sym@GOTENT */
new_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOTENT);
new_rtx = gen_rtx_CONST (Pmode, new_rtx);
new_rtx = gen_const_mem (GET_MODE (reg), new_rtx);
emit_move_insn (reg, new_rtx);
new_rtx = reg;
}
else if (flag_pic == 1)
{
/* Assume GOT offset < 4k. This is handled the same way
in both 31- and 64-bit code (@GOT). */
/* Assume GOT offset is a valid displacement operand (< 4k
or < 512k with z990). This is handled the same way in
both 31- and 64-bit code (@GOT).
lg <target>, sym@GOT(r12) */
if (reload_in_progress || reload_completed)
df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
@ -3479,7 +3542,9 @@ legitimize_pic_address (rtx orig, rtx reg)
else if (TARGET_CPU_ZARCH)
{
/* If the GOT offset might be >= 4k, we determine the position
of the GOT entry via a PC-relative LARL (@GOTENT). */
of the GOT entry via a PC-relative LARL (@GOTENT).
larl temp, sym@GOTENT
lg <target>, 0(temp) */
rtx temp = reg ? reg : gen_reg_rtx (Pmode);
@ -3488,21 +3553,21 @@ legitimize_pic_address (rtx orig, rtx reg)
new_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOTENT);
new_rtx = gen_rtx_CONST (Pmode, new_rtx);
emit_move_insn (temp, new_rtx);
if (!TARGET_Z10)
{
emit_move_insn (temp, new_rtx);
new_rtx = gen_const_mem (Pmode, temp);
}
else
new_rtx = gen_const_mem (GET_MODE (reg), new_rtx);
new_rtx = gen_const_mem (Pmode, temp);
emit_move_insn (reg, new_rtx);
new_rtx = reg;
}
else
{
/* If the GOT offset might be >= 4k, we have to load it
from the literal pool (@GOT). */
from the literal pool (@GOT).
lg temp, lit-litbase(r13)
lg <target>, 0(temp)
lit: .long sym@GOT */
rtx temp = reg ? reg : gen_reg_rtx (Pmode);
@ -3523,175 +3588,94 @@ legitimize_pic_address (rtx orig, rtx reg)
new_rtx = reg;
}
}
else
else if (GET_CODE (addr) == UNSPEC && GET_CODE (addend) == CONST_INT)
{
if (GET_CODE (addr) == CONST)
gcc_assert (XVECLEN (addr, 0) == 1);
switch (XINT (addr, 1))
{
addr = XEXP (addr, 0);
if (GET_CODE (addr) == UNSPEC)
/* These address symbols (or PLT slots) relative to the GOT
(not GOT slots!). In general this will exceed the
displacement range so these value belong into the literal
pool. */
case UNSPEC_GOTOFF:
case UNSPEC_PLTOFF:
new_rtx = force_const_mem (Pmode, orig);
break;
/* For -fPIC the GOT size might exceed the displacement
range so make sure the value is in the literal pool. */
case UNSPEC_GOT:
if (flag_pic == 2)
new_rtx = force_const_mem (Pmode, orig);
break;
/* For @GOTENT larl is used. This is handled like local
symbol refs. */
case UNSPEC_GOTENT:
gcc_unreachable ();
break;
/* @PLT is OK as is on 64-bit, must be converted to
GOT-relative @PLTOFF on 31-bit. */
case UNSPEC_PLT:
if (!TARGET_CPU_ZARCH)
{
gcc_assert (XVECLEN (addr, 0) == 1);
switch (XINT (addr, 1))
{
/* If someone moved a GOT-relative UNSPEC
out of the literal pool, force them back in. */
case UNSPEC_GOTOFF:
case UNSPEC_PLTOFF:
new_rtx = force_const_mem (Pmode, orig);
break;
rtx temp = reg? reg : gen_reg_rtx (Pmode);
/* @GOT is OK as is if small. */
case UNSPEC_GOT:
if (flag_pic == 2)
new_rtx = force_const_mem (Pmode, orig);
break;
if (reload_in_progress || reload_completed)
df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
/* @GOTENT is OK as is. */
case UNSPEC_GOTENT:
break;
addr = XVECEXP (addr, 0, 0);
addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr),
UNSPEC_PLTOFF);
if (addend != const0_rtx)
addr = gen_rtx_PLUS (Pmode, addr, addend);
addr = gen_rtx_CONST (Pmode, addr);
addr = force_const_mem (Pmode, addr);
emit_move_insn (temp, addr);
/* @PLT is OK as is on 64-bit, must be converted to
GOT-relative @PLTOFF on 31-bit. */
case UNSPEC_PLT:
if (!TARGET_CPU_ZARCH)
{
rtx temp = reg? reg : gen_reg_rtx (Pmode);
if (reload_in_progress || reload_completed)
df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
addr = XVECEXP (addr, 0, 0);
addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr),
UNSPEC_PLTOFF);
addr = gen_rtx_CONST (Pmode, addr);
addr = force_const_mem (Pmode, addr);
emit_move_insn (temp, addr);
new_rtx = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp);
if (reg != 0)
{
s390_load_address (reg, new_rtx);
new_rtx = reg;
}
}
break;
/* Everything else cannot happen. */
default:
gcc_unreachable ();
}
}
else
gcc_assert (GET_CODE (addr) == PLUS);
}
if (GET_CODE (addr) == PLUS)
{
rtx op0 = XEXP (addr, 0), op1 = XEXP (addr, 1);
gcc_assert (!TLS_SYMBOLIC_CONST (op0));
gcc_assert (!TLS_SYMBOLIC_CONST (op1));
/* Check first to see if this is a constant offset
from a local symbol reference. */
if ((GET_CODE (op0) == LABEL_REF
|| (GET_CODE (op0) == SYMBOL_REF && SYMBOL_REF_LOCAL_P (op0)))
&& GET_CODE (op1) == CONST_INT)
{
if (TARGET_CPU_ZARCH
&& larl_operand (op0, VOIDmode)
&& INTVAL (op1) < (HOST_WIDE_INT)1 << 31
&& INTVAL (op1) >= -((HOST_WIDE_INT)1 << 31))
{
if (INTVAL (op1) & 1)
{
/* LARL can't handle odd offsets, so emit a
pair of LARL and LA. */
rtx temp = reg? reg : gen_reg_rtx (Pmode);
if (!DISP_IN_RANGE (INTVAL (op1)))
{
HOST_WIDE_INT even = INTVAL (op1) - 1;
op0 = gen_rtx_PLUS (Pmode, op0, GEN_INT (even));
op0 = gen_rtx_CONST (Pmode, op0);
op1 = const1_rtx;
}
emit_move_insn (temp, op0);
new_rtx = gen_rtx_PLUS (Pmode, temp, op1);
if (reg != 0)
{
s390_load_address (reg, new_rtx);
new_rtx = reg;
}
}
else
{
/* If the offset is even, we can just use LARL.
This will happen automatically. */
}
}
else
{
/* Access local symbols relative to the GOT. */
rtx temp = reg? reg : gen_reg_rtx (Pmode);
if (reload_in_progress || reload_completed)
df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op0),
UNSPEC_GOTOFF);
addr = gen_rtx_PLUS (Pmode, addr, op1);
addr = gen_rtx_CONST (Pmode, addr);
addr = force_const_mem (Pmode, addr);
emit_move_insn (temp, addr);
new_rtx = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp);
if (reg != 0)
{
s390_load_address (reg, new_rtx);
new_rtx = reg;
}
}
}
/* Now, check whether it is a GOT relative symbol plus offset
that was pulled out of the literal pool. Force it back in. */
else if (GET_CODE (op0) == UNSPEC
&& GET_CODE (op1) == CONST_INT
&& XINT (op0, 1) == UNSPEC_GOTOFF)
{
gcc_assert (XVECLEN (op0, 0) == 1);
new_rtx = force_const_mem (Pmode, orig);
}
/* Otherwise, compute the sum. */
else
{
base = legitimize_pic_address (XEXP (addr, 0), reg);
new_rtx = legitimize_pic_address (XEXP (addr, 1),
base == reg ? NULL_RTX : reg);
if (GET_CODE (new_rtx) == CONST_INT)
new_rtx = plus_constant (Pmode, base, INTVAL (new_rtx));
else
new_rtx = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp);
if (reg != 0)
{
if (GET_CODE (new_rtx) == PLUS && CONSTANT_P (XEXP (new_rtx, 1)))
{
base = gen_rtx_PLUS (Pmode, base, XEXP (new_rtx, 0));
new_rtx = XEXP (new_rtx, 1);
}
new_rtx = gen_rtx_PLUS (Pmode, base, new_rtx);
s390_load_address (reg, new_rtx);
new_rtx = reg;
}
if (GET_CODE (new_rtx) == CONST)
new_rtx = XEXP (new_rtx, 0);
new_rtx = force_operand (new_rtx, 0);
}
else
/* On 64 bit larl can be used. This case is handled like
local symbol refs. */
gcc_unreachable ();
break;
/* Everything else cannot happen. */
default:
gcc_unreachable ();
}
}
else if (addend != const0_rtx)
{
/* Otherwise, compute the sum. */
rtx base = legitimize_pic_address (addr, reg);
new_rtx = legitimize_pic_address (addend,
base == reg ? NULL_RTX : reg);
if (GET_CODE (new_rtx) == CONST_INT)
new_rtx = plus_constant (Pmode, base, INTVAL (new_rtx));
else
{
if (GET_CODE (new_rtx) == PLUS && CONSTANT_P (XEXP (new_rtx, 1)))
{
base = gen_rtx_PLUS (Pmode, base, XEXP (new_rtx, 0));
new_rtx = XEXP (new_rtx, 1);
}
new_rtx = gen_rtx_PLUS (Pmode, base, new_rtx);
}
if (GET_CODE (new_rtx) == CONST)
new_rtx = XEXP (new_rtx, 0);
new_rtx = force_operand (new_rtx, 0);
}
return new_rtx;
}
@ -5350,7 +5334,7 @@ print_operand_address (FILE *file, rtx addr)
{
struct s390_address ad;
if (s390_loadrelative_operand_p (addr))
if (s390_loadrelative_operand_p (addr, NULL, NULL))
{
if (!TARGET_Z10)
{

View File

@ -0,0 +1,29 @@
/* PR target/55717 */
/* { dg-do compile } */
/* { dg-options "-O2 -march=z10 -fPIC" } */
extern char temp[];
short ansi_value[256];
void terminal_state(void)
{
static const char *puc[] = { "", "<", "=", ">", "?", 0};
int i, j, k, l, modes_found;
char buf[256];
k = (int) __builtin_strlen(temp);
for (j = l = 0; j < 255 && j - l < 50; j++)
{
__builtin_sprintf(temp, "\033[%s%d$p", puc[i], j);
if (ansi_value[1])
{
l = j;
buf[k] = '\0';
put_crlf();
ptextln(buf);
buf[k++] = ' ';
k = (int) __builtin_strlen(temp);
}
}
for (i = j = 0; j < modes_found; j = ++i >> 1)
;
}