This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH v4] S/390: Allow relative addressing of literal pool entries
- From: Ilya Leoshkevich <iii at linux dot ibm dot com>
- To: gcc-patches at gcc dot gnu dot org
- Cc: krebbel at linux dot ibm dot com, rdapp at linux dot ibm dot com, uweigand at de dot ibm dot com, Ilya Leoshkevich <iii at linux dot ibm dot com>
- Date: Fri, 9 Nov 2018 17:58:25 +0100
- Subject: [PATCH v4] S/390: Allow relative addressing of literal pool entries
Bootstrapped and regtested on s390x-redhat-linux.
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-05 Ilya Leoshkevich <iii@linux.ibm.com>
PR target/87762
* config/s390/predicates.md (larl_operand): Use
s390_symbol_relative_long_p () to reduce code duplication.
* config/s390/s390-protos.h (s390_symbol_relative_long_p): New
function.
* config/s390/s390.c (s390_safe_relative_long_p): Likewise.
(annotate_constant_pool_refs): Skip insns which support relative
addressing.
(annotate_constant_pool_refs_1): New helper function.
(s390_symbol_relative_long_p): New function.
(find_constant_pool_ref): Assert that unannotated constant pool
references must use relative addressing.
(replace_constant_pool_ref): Skip insns which support relative
addressing.
(replace_constant_pool_ref_1): New helper function.
(s390_mainpool_finish): Adjust to the new signature of
replace_constant_pool_ref ().
(s390_chunkify_finish): Likewise.
(pass_s390_early_mach::execute): Likewise.
(s390_prologue_plus_offset): Likewise.
(s390_emit_prologue): Likewise.
(s390_emit_epilogue): Likewise.
---
gcc/config/s390/predicates.md | 8 +--
gcc/config/s390/s390-protos.h | 1 +
gcc/config/s390/s390.c | 93 ++++++++++++++++++++++++++---------
3 files changed, 72 insertions(+), 30 deletions(-)
diff --git a/gcc/config/s390/predicates.md b/gcc/config/s390/predicates.md
index 97f717c558d..bb66c8a6bcb 100644
--- a/gcc/config/s390/predicates.md
+++ b/gcc/config/s390/predicates.md
@@ -151,9 +151,7 @@
if (GET_CODE (op) == LABEL_REF)
return true;
if (SYMBOL_REF_P (op))
- return (!SYMBOL_FLAG_NOTALIGN2_P (op)
- && SYMBOL_REF_TLS_MODEL (op) == 0
- && s390_rel_address_ok_p (op));
+ return s390_symbol_relative_long_p (op);
/* Everything else must have a CONST, so strip it. */
if (GET_CODE (op) != CONST)
@@ -176,9 +174,7 @@
if (GET_CODE (op) == LABEL_REF)
return true;
if (SYMBOL_REF_P (op))
- return (!SYMBOL_FLAG_NOTALIGN2_P (op)
- && SYMBOL_REF_TLS_MODEL (op) == 0
- && s390_rel_address_ok_p (op));
+ return s390_symbol_relative_long_p (op);
/* Now we must have a @GOTENT offset or @PLT stub
diff --git a/gcc/config/s390/s390-protos.h b/gcc/config/s390/s390-protos.h
index 96fa705f879..d3c2cc55e28 100644
--- a/gcc/config/s390/s390-protos.h
+++ b/gcc/config/s390/s390-protos.h
@@ -157,6 +157,7 @@ extern void s390_indirect_branch_via_thunk (unsigned int regno,
rtx comparison_operator,
enum s390_indirect_branch_type type);
extern void s390_indirect_branch_via_inline_thunk (rtx execute_target);
+extern bool s390_symbol_relative_long_p (rtx);
#endif /* RTX_CODE */
/* s390-c.c routines */
diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c
index 1be85727b73..58f3163b274 100644
--- a/gcc/config/s390/s390.c
+++ b/gcc/config/s390/s390.c
@@ -2731,6 +2731,17 @@ s390_safe_attr_type (rtx_insn *insn)
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. */
static bool
@@ -8116,11 +8127,8 @@ s390_first_cycle_multipass_dfa_lookahead (void)
return 4;
}
-/* Annotate every literal pool reference in X by an UNSPEC_LTREF expression.
- Fix up MEMs as required. */
-
static void
-annotate_constant_pool_refs (rtx *x)
+annotate_constant_pool_refs_1 (rtx *x)
{
int i, j;
const char *fmt;
@@ -8199,16 +8207,39 @@ annotate_constant_pool_refs (rtx *x)
{
if (fmt[i] == 'e')
{
- annotate_constant_pool_refs (&XEXP (*x, i));
+ annotate_constant_pool_refs_1 (&XEXP (*x, i));
}
else if (fmt[i] == 'E')
{
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));
}
}
}
+/* Annotate every literal pool reference in INSN by an UNSPEC_LTREF expression.
+ Fix up MEMs as required.
+ Skip insns which support relative addressing, because they do not use a base
+ register. */
+
+static void
+annotate_constant_pool_refs (rtx_insn *insn)
+{
+ if (s390_safe_relative_long_p (insn))
+ return;
+ annotate_constant_pool_refs_1 (&PATTERN (insn));
+}
+
+/* Return true iff SYMBOL_REF X can be used with a relative long addressing. */
+
+bool
+s390_symbol_relative_long_p (rtx x)
+{
+ return (!SYMBOL_FLAG_NOTALIGN2_P (x)
+ && SYMBOL_REF_TLS_MODEL (x) == 0
+ && s390_rel_address_ok_p (x));
+}
+
/* Find an annotated literal pool symbol referenced in RTX X,
and store it at REF. Will abort if X contains references to
more than one such pool symbol; multiple references to the same
@@ -8229,7 +8260,8 @@ find_constant_pool_ref (rtx x, rtx *ref)
return;
gcc_assert (GET_CODE (x) != SYMBOL_REF
- || !CONSTANT_POOL_ADDRESS_P (x));
+ || !CONSTANT_POOL_ADDRESS_P (x)
+ || s390_symbol_relative_long_p (x));
if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_LTREF)
{
@@ -8260,11 +8292,8 @@ find_constant_pool_ref (rtx x, rtx *ref)
}
}
-/* Replace every reference to the annotated literal pool
- symbol REF in X by its base plus OFFSET. */
-
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;
const char *fmt;
@@ -8295,16 +8324,29 @@ replace_constant_pool_ref (rtx *x, rtx ref, rtx offset)
{
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')
{
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
constant tables in the middle of large functions. */
@@ -8801,7 +8843,7 @@ s390_mainpool_finish (struct constant_pool *pool)
addr = s390_find_constant (pool, get_pool_constant (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;
}
}
@@ -9002,7 +9044,7 @@ s390_chunkify_finish (struct constant_pool *pool_list)
get_pool_constant (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;
}
}
@@ -10595,7 +10637,7 @@ pass_s390_early_mach::execute (function *fun)
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
if (INSN_P (insn))
{
- annotate_constant_pool_refs (&PATTERN (insn));
+ annotate_constant_pool_refs (insn);
df_insn_rescan (insn);
}
return 0;
@@ -10616,7 +10658,7 @@ make_pass_s390_early_mach (gcc::context *ctxt)
static rtx
s390_prologue_plus_offset (rtx target, rtx reg, rtx offset, bool frame_related_p)
{
- rtx insn;
+ rtx_insn *insn;
rtx orig_offset = offset;
gcc_assert (REG_P (target));
@@ -10650,7 +10692,7 @@ s390_prologue_plus_offset (rtx target, rtx reg, rtx offset, bool frame_related_p
if (!CONST_INT_P (offset))
{
- annotate_constant_pool_refs (&PATTERN (insn));
+ annotate_constant_pool_refs (insn);
if (frame_related_p)
add_reg_note (insn, REG_FRAME_RELATED_EXPR,
@@ -11090,7 +11132,7 @@ s390_emit_prologue (void)
rtx_insn *insns = s390_load_got ();
for (rtx_insn *insn = insns; insn; insn = NEXT_INSN (insn))
- annotate_constant_pool_refs (&PATTERN (insn));
+ annotate_constant_pool_refs (insn);
emit_insn (insns);
}
@@ -11154,7 +11196,8 @@ s390_emit_epilogue (bool sibcall)
}
else
{
- rtx insn, frame_off, cfa;
+ rtx_insn *insn;
+ rtx frame_off, cfa;
offset = area_bottom < 0 ? -area_bottom : 0;
frame_off = GEN_INT (cfun_frame_layout.frame_size - offset);
@@ -11163,9 +11206,11 @@ s390_emit_epilogue (bool sibcall)
gen_rtx_PLUS (Pmode, frame_pointer, frame_off));
if (DISP_IN_RANGE (INTVAL (frame_off)))
{
- insn = gen_rtx_SET (frame_pointer,
- gen_rtx_PLUS (Pmode, frame_pointer, frame_off));
- insn = emit_insn (insn);
+ rtx set;
+
+ set = gen_rtx_SET (frame_pointer,
+ gen_rtx_PLUS (Pmode, frame_pointer, frame_off));
+ insn = emit_insn (set);
}
else
{
@@ -11173,7 +11218,7 @@ s390_emit_epilogue (bool sibcall)
frame_off = force_const_mem (Pmode, 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);
RTX_FRAME_RELATED_P (insn) = 1;
--
2.19.1