Commit 340e0dd6 by Ilya Leoshkevich Committed by Ilya Leoshkevich

S/390: Allow relative addressing of literal pool entries

r265490 allowed the compiler to choose in a more flexible way whether to
use load or load-address-relative-long (LARL) instruction.  When it
chose LARL for literal pool references, the latter ones were rewritten
by pass_s390_early_mach to use UNSPEC_LTREF, which assumes base register
usage, which in turn is not compatible with LARL.  The end result was an
ICE because of unrecognizable insn.

UNSPEC_LTREF and friends are necessary in order to communicate the
dependency on the base register to pass_sched2.  When relative
addressing is used, no base register is necessary, so in such cases the
rewrite must be avoided.

gcc/ChangeLog:

2018-11-09  Ilya Leoshkevich  <iii@linux.ibm.com>

	PR target/87762
	* config/s390/s390.c (s390_safe_relative_long_p): New function.
	(annotate_constant_pool_refs): Skip insns which support
	relative addressing.
	(annotate_constant_pool_refs_1): New helper function.
	(find_constant_pool_ref): Skip insns which support relative
	addression.
	(find_constant_pool_ref_1): New helper function.
	(replace_constant_pool_ref): Skip insns which support
	relative addressing.
	(replace_constant_pool_ref_1): New helper function.
	(s390_mainpool_start): Adapt to the new signature.
	(s390_mainpool_finish): Likewise.
	(s390_chunkify_start): Likewise.
	(s390_chunkify_finish): Likewise.
	(pass_s390_early_mach::execute): Likewise.
	(s390_prologue_plus_offset): Likewise.
	(s390_emit_prologue): Likewise.
	(s390_emit_epilogue): Likewise.

From-SVN: r265991
parent 81a227c6
2018-11-09 Ilya Leoshkevich <iii@linux.ibm.com>
PR target/87762
* config/s390/s390.c (s390_safe_relative_long_p): New function.
(annotate_constant_pool_refs): Skip insns which support
relative addressing.
(annotate_constant_pool_refs_1): New helper function.
(find_constant_pool_ref): Skip insns which support relative
addression.
(find_constant_pool_ref_1): New helper function.
(replace_constant_pool_ref): Skip insns which support
relative addressing.
(replace_constant_pool_ref_1): New helper function.
(s390_mainpool_start): Adapt to the new signature.
(s390_mainpool_finish): Likewise.
(s390_chunkify_start): Likewise.
(s390_chunkify_finish): Likewise.
(pass_s390_early_mach::execute): Likewise.
(s390_prologue_plus_offset): Likewise.
(s390_emit_prologue): Likewise.
(s390_emit_epilogue): Likewise.
2018-11-09 Jakub Jelinek <jakub@redhat.com> 2018-11-09 Jakub Jelinek <jakub@redhat.com>
* gimplify.c (gimplify_scan_omp_clauses): Call sorry_at for valid * gimplify.c (gimplify_scan_omp_clauses): Call sorry_at for valid
...@@ -2731,6 +2731,17 @@ s390_safe_attr_type (rtx_insn *insn) ...@@ -2731,6 +2731,17 @@ s390_safe_attr_type (rtx_insn *insn)
return TYPE_NONE; return TYPE_NONE;
} }
/* Return attribute relative_long of insn. */
static bool
s390_safe_relative_long_p (rtx_insn *insn)
{
if (recog_memoized (insn) >= 0)
return get_attr_relative_long (insn) == RELATIVE_LONG_YES;
else
return false;
}
/* Return true if DISP is a valid short displacement. */ /* Return true if DISP is a valid short displacement. */
static bool static bool
...@@ -8102,11 +8113,8 @@ s390_first_cycle_multipass_dfa_lookahead (void) ...@@ -8102,11 +8113,8 @@ s390_first_cycle_multipass_dfa_lookahead (void)
return 4; return 4;
} }
/* Annotate every literal pool reference in X by an UNSPEC_LTREF expression.
Fix up MEMs as required. */
static void static void
annotate_constant_pool_refs (rtx *x) annotate_constant_pool_refs_1 (rtx *x)
{ {
int i, j; int i, j;
const char *fmt; const char *fmt;
...@@ -8185,26 +8193,31 @@ annotate_constant_pool_refs (rtx *x) ...@@ -8185,26 +8193,31 @@ annotate_constant_pool_refs (rtx *x)
{ {
if (fmt[i] == 'e') if (fmt[i] == 'e')
{ {
annotate_constant_pool_refs (&XEXP (*x, i)); annotate_constant_pool_refs_1 (&XEXP (*x, i));
} }
else if (fmt[i] == 'E') else if (fmt[i] == 'E')
{ {
for (j = 0; j < XVECLEN (*x, i); j++) for (j = 0; j < XVECLEN (*x, i); j++)
annotate_constant_pool_refs (&XVECEXP (*x, i, j)); annotate_constant_pool_refs_1 (&XVECEXP (*x, i, j));
} }
} }
} }
/* Find an annotated literal pool symbol referenced in RTX X, /* Annotate every literal pool reference in INSN by an UNSPEC_LTREF expression.
and store it at REF. Will abort if X contains references to Fix up MEMs as required.
more than one such pool symbol; multiple references to the same Skip insns which support relative addressing, because they do not use a base
symbol are allowed, however. register. */
The rtx pointed to by REF must be initialized to NULL_RTX static void
by the caller before calling this routine. */ annotate_constant_pool_refs (rtx_insn *insn)
{
if (s390_safe_relative_long_p (insn))
return;
annotate_constant_pool_refs_1 (&PATTERN (insn));
}
static void static void
find_constant_pool_ref (rtx x, rtx *ref) find_constant_pool_ref_1 (rtx x, rtx *ref)
{ {
int i, j; int i, j;
const char *fmt; const char *fmt;
...@@ -8236,21 +8249,37 @@ find_constant_pool_ref (rtx x, rtx *ref) ...@@ -8236,21 +8249,37 @@ find_constant_pool_ref (rtx x, rtx *ref)
{ {
if (fmt[i] == 'e') if (fmt[i] == 'e')
{ {
find_constant_pool_ref (XEXP (x, i), ref); find_constant_pool_ref_1 (XEXP (x, i), ref);
} }
else if (fmt[i] == 'E') else if (fmt[i] == 'E')
{ {
for (j = 0; j < XVECLEN (x, i); j++) for (j = 0; j < XVECLEN (x, i); j++)
find_constant_pool_ref (XVECEXP (x, i, j), ref); find_constant_pool_ref_1 (XVECEXP (x, i, j), ref);
} }
} }
} }
/* Replace every reference to the annotated literal pool /* Find an annotated literal pool symbol referenced in INSN,
symbol REF in X by its base plus OFFSET. */ and store it at REF. Will abort if INSN contains references to
more than one such pool symbol; multiple references to the same
symbol are allowed, however.
The rtx pointed to by REF must be initialized to NULL_RTX
by the caller before calling this routine.
Skip insns which support relative addressing, because they do not use a base
register. */
static void
find_constant_pool_ref (rtx_insn *insn, rtx *ref)
{
if (s390_safe_relative_long_p (insn))
return;
find_constant_pool_ref_1 (PATTERN (insn), ref);
}
static void static void
replace_constant_pool_ref (rtx *x, rtx ref, rtx offset) replace_constant_pool_ref_1 (rtx *x, rtx ref, rtx offset)
{ {
int i, j; int i, j;
const char *fmt; const char *fmt;
...@@ -8281,16 +8310,29 @@ replace_constant_pool_ref (rtx *x, rtx ref, rtx offset) ...@@ -8281,16 +8310,29 @@ replace_constant_pool_ref (rtx *x, rtx ref, rtx offset)
{ {
if (fmt[i] == 'e') if (fmt[i] == 'e')
{ {
replace_constant_pool_ref (&XEXP (*x, i), ref, offset); replace_constant_pool_ref_1 (&XEXP (*x, i), ref, offset);
} }
else if (fmt[i] == 'E') else if (fmt[i] == 'E')
{ {
for (j = 0; j < XVECLEN (*x, i); j++) for (j = 0; j < XVECLEN (*x, i); j++)
replace_constant_pool_ref (&XVECEXP (*x, i, j), ref, offset); replace_constant_pool_ref_1 (&XVECEXP (*x, i, j), ref, offset);
} }
} }
} }
/* Replace every reference to the annotated literal pool
symbol REF in INSN by its base plus OFFSET.
Skip insns which support relative addressing, because they do not use a base
register. */
static void
replace_constant_pool_ref (rtx_insn *insn, rtx ref, rtx offset)
{
if (s390_safe_relative_long_p (insn))
return;
replace_constant_pool_ref_1 (&PATTERN (insn), ref, offset);
}
/* We keep a list of constants which we have to add to internal /* We keep a list of constants which we have to add to internal
constant tables in the middle of large functions. */ constant tables in the middle of large functions. */
...@@ -8691,7 +8733,7 @@ s390_mainpool_start (void) ...@@ -8691,7 +8733,7 @@ s390_mainpool_start (void)
if (NONJUMP_INSN_P (insn) || CALL_P (insn)) if (NONJUMP_INSN_P (insn) || CALL_P (insn))
{ {
rtx pool_ref = NULL_RTX; rtx pool_ref = NULL_RTX;
find_constant_pool_ref (PATTERN (insn), &pool_ref); find_constant_pool_ref (insn, &pool_ref);
if (pool_ref) if (pool_ref)
{ {
rtx constant = get_pool_constant (pool_ref); rtx constant = get_pool_constant (pool_ref);
...@@ -8778,7 +8820,7 @@ s390_mainpool_finish (struct constant_pool *pool) ...@@ -8778,7 +8820,7 @@ s390_mainpool_finish (struct constant_pool *pool)
if (NONJUMP_INSN_P (insn) || CALL_P (insn)) if (NONJUMP_INSN_P (insn) || CALL_P (insn))
{ {
rtx addr, pool_ref = NULL_RTX; rtx addr, pool_ref = NULL_RTX;
find_constant_pool_ref (PATTERN (insn), &pool_ref); find_constant_pool_ref (insn, &pool_ref);
if (pool_ref) if (pool_ref)
{ {
if (s390_execute_label (insn)) if (s390_execute_label (insn))
...@@ -8787,7 +8829,7 @@ s390_mainpool_finish (struct constant_pool *pool) ...@@ -8787,7 +8829,7 @@ s390_mainpool_finish (struct constant_pool *pool)
addr = s390_find_constant (pool, get_pool_constant (pool_ref), addr = s390_find_constant (pool, get_pool_constant (pool_ref),
get_pool_mode (pool_ref)); get_pool_mode (pool_ref));
replace_constant_pool_ref (&PATTERN (insn), pool_ref, addr); replace_constant_pool_ref (insn, pool_ref, addr);
INSN_CODE (insn) = -1; INSN_CODE (insn) = -1;
} }
} }
...@@ -8821,7 +8863,7 @@ s390_chunkify_start (void) ...@@ -8821,7 +8863,7 @@ s390_chunkify_start (void)
if (NONJUMP_INSN_P (insn) || CALL_P (insn)) if (NONJUMP_INSN_P (insn) || CALL_P (insn))
{ {
rtx pool_ref = NULL_RTX; rtx pool_ref = NULL_RTX;
find_constant_pool_ref (PATTERN (insn), &pool_ref); find_constant_pool_ref (insn, &pool_ref);
if (pool_ref) if (pool_ref)
{ {
rtx constant = get_pool_constant (pool_ref); rtx constant = get_pool_constant (pool_ref);
...@@ -8978,7 +9020,7 @@ s390_chunkify_finish (struct constant_pool *pool_list) ...@@ -8978,7 +9020,7 @@ s390_chunkify_finish (struct constant_pool *pool_list)
if (NONJUMP_INSN_P (insn) || CALL_P (insn)) if (NONJUMP_INSN_P (insn) || CALL_P (insn))
{ {
rtx addr, pool_ref = NULL_RTX; rtx addr, pool_ref = NULL_RTX;
find_constant_pool_ref (PATTERN (insn), &pool_ref); find_constant_pool_ref (insn, &pool_ref);
if (pool_ref) if (pool_ref)
{ {
if (s390_execute_label (insn)) if (s390_execute_label (insn))
...@@ -8988,7 +9030,7 @@ s390_chunkify_finish (struct constant_pool *pool_list) ...@@ -8988,7 +9030,7 @@ s390_chunkify_finish (struct constant_pool *pool_list)
get_pool_constant (pool_ref), get_pool_constant (pool_ref),
get_pool_mode (pool_ref)); get_pool_mode (pool_ref));
replace_constant_pool_ref (&PATTERN (insn), pool_ref, addr); replace_constant_pool_ref (insn, pool_ref, addr);
INSN_CODE (insn) = -1; INSN_CODE (insn) = -1;
} }
} }
...@@ -10581,7 +10623,7 @@ pass_s390_early_mach::execute (function *fun) ...@@ -10581,7 +10623,7 @@ pass_s390_early_mach::execute (function *fun)
for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
if (INSN_P (insn)) if (INSN_P (insn))
{ {
annotate_constant_pool_refs (&PATTERN (insn)); annotate_constant_pool_refs (insn);
df_insn_rescan (insn); df_insn_rescan (insn);
} }
return 0; return 0;
...@@ -10602,7 +10644,7 @@ make_pass_s390_early_mach (gcc::context *ctxt) ...@@ -10602,7 +10644,7 @@ make_pass_s390_early_mach (gcc::context *ctxt)
static rtx static rtx
s390_prologue_plus_offset (rtx target, rtx reg, rtx offset, bool frame_related_p) s390_prologue_plus_offset (rtx target, rtx reg, rtx offset, bool frame_related_p)
{ {
rtx insn; rtx_insn *insn;
rtx orig_offset = offset; rtx orig_offset = offset;
gcc_assert (REG_P (target)); gcc_assert (REG_P (target));
...@@ -10636,7 +10678,7 @@ s390_prologue_plus_offset (rtx target, rtx reg, rtx offset, bool frame_related_p ...@@ -10636,7 +10678,7 @@ s390_prologue_plus_offset (rtx target, rtx reg, rtx offset, bool frame_related_p
if (!CONST_INT_P (offset)) if (!CONST_INT_P (offset))
{ {
annotate_constant_pool_refs (&PATTERN (insn)); annotate_constant_pool_refs (insn);
if (frame_related_p) if (frame_related_p)
add_reg_note (insn, REG_FRAME_RELATED_EXPR, add_reg_note (insn, REG_FRAME_RELATED_EXPR,
...@@ -11076,7 +11118,7 @@ s390_emit_prologue (void) ...@@ -11076,7 +11118,7 @@ s390_emit_prologue (void)
rtx_insn *insns = s390_load_got (); rtx_insn *insns = s390_load_got ();
for (rtx_insn *insn = insns; insn; insn = NEXT_INSN (insn)) for (rtx_insn *insn = insns; insn; insn = NEXT_INSN (insn))
annotate_constant_pool_refs (&PATTERN (insn)); annotate_constant_pool_refs (insn);
emit_insn (insns); emit_insn (insns);
} }
...@@ -11140,7 +11182,8 @@ s390_emit_epilogue (bool sibcall) ...@@ -11140,7 +11182,8 @@ s390_emit_epilogue (bool sibcall)
} }
else else
{ {
rtx insn, frame_off, cfa; rtx_insn *insn;
rtx frame_off, cfa;
offset = area_bottom < 0 ? -area_bottom : 0; offset = area_bottom < 0 ? -area_bottom : 0;
frame_off = GEN_INT (cfun_frame_layout.frame_size - offset); frame_off = GEN_INT (cfun_frame_layout.frame_size - offset);
...@@ -11149,9 +11192,11 @@ s390_emit_epilogue (bool sibcall) ...@@ -11149,9 +11192,11 @@ s390_emit_epilogue (bool sibcall)
gen_rtx_PLUS (Pmode, frame_pointer, frame_off)); gen_rtx_PLUS (Pmode, frame_pointer, frame_off));
if (DISP_IN_RANGE (INTVAL (frame_off))) if (DISP_IN_RANGE (INTVAL (frame_off)))
{ {
insn = gen_rtx_SET (frame_pointer, rtx set;
gen_rtx_PLUS (Pmode, frame_pointer, frame_off));
insn = emit_insn (insn); set = gen_rtx_SET (frame_pointer,
gen_rtx_PLUS (Pmode, frame_pointer, frame_off));
insn = emit_insn (set);
} }
else else
{ {
...@@ -11159,7 +11204,7 @@ s390_emit_epilogue (bool sibcall) ...@@ -11159,7 +11204,7 @@ s390_emit_epilogue (bool sibcall)
frame_off = force_const_mem (Pmode, frame_off); frame_off = force_const_mem (Pmode, frame_off);
insn = emit_insn (gen_add2_insn (frame_pointer, frame_off)); insn = emit_insn (gen_add2_insn (frame_pointer, frame_off));
annotate_constant_pool_refs (&PATTERN (insn)); annotate_constant_pool_refs (insn);
} }
add_reg_note (insn, REG_CFA_ADJUST_CFA, cfa); add_reg_note (insn, REG_CFA_ADJUST_CFA, cfa);
RTX_FRAME_RELATED_P (insn) = 1; RTX_FRAME_RELATED_P (insn) = 1;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment