aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlrich Weigand <uweigand@de.ibm.com>2002-06-11 13:53:02 +0000
committerUlrich Weigand <uweigand@gcc.gnu.org>2002-06-11 13:53:02 +0000
commitb2ccb744c6bab887d1749cdbe19cb7e4ccc54446 (patch)
tree69933cdc01fa9fea2fb96a7a30e44d3c2648be6d
parent2f937369fa50dfd2f5af11b18d30c5489451072c (diff)
downloadgcc-b2ccb744c6bab887d1749cdbe19cb7e4ccc54446.zip
gcc-b2ccb744c6bab887d1749cdbe19cb7e4ccc54446.tar.gz
gcc-b2ccb744c6bab887d1749cdbe19cb7e4ccc54446.tar.bz2
s390.md (reload_base, ltorg): Remove.
* config/s390/s390.md (reload_base, ltorg): Remove. * s390.c (s390_stop_dump_lit_p, s390_dump_literal_pool, s390_asm_output_pool_prologue, s390_pool_start_insn): Remove. * s390-protos.h (s390_stop_dump_lit_p, s390_dump_literal_pool, s390_asm_output_pool_prologue): Likewise. * s390.h (s390_pool_start_insn): Likewise. * s390.c (s390_output_symbolic_const): Remove support for old-style pool chunks. (s390_function_epilogue): Likewise. (s390_output_constant_pool): Likewise. Also, fix incorrect alignment for 64-bit literal pools. (print_operand_address): Remove 'y' and 'Y' format flags. * s390.h (ASM_OUTPUT_POOL_PROLOGUE): Remove support for old-style pool chunks. (ASM_OUTPUT_SPECIAL_POOL_ENTRY): Likewise. (ASM_OUTPUT_POOL_EPILOGUE): Remove. (S390_CHUNK_MAX, S390_CHUNK_OV, S390_POOL_MAX): Remove. * s390.c (consttable_operand): New function. * s390-protos.h (consttable_operand): Declare it. * s390.h (PREDICATE_CODES): Add consttable_operand. * s390.md (consttable_qi, consttable_hi, consttable_si, consttable_di, consttable_sf, consttable_df, pool_start_31, pool_end_31, pool_start_64, pool_end_64, reload_base, reload_base2): New insns. * s390.c (struct constant, struct constant_pool): New data types. (constant_modes, gen_consttable): New variables. (s390_start_pool, s390_end_pool, s390_add_pool, s390_dump_pool, s390_free_pool): New functions. (s390_chunkify_pool): Completely reimplement literal pool overflow handling. * s390.c (s390_pool_overflow): New variable. * s390.h (s390_pool_overflow): Declare it. * s390.md (cjump, icjump): Use it to adapt length for out-of-range jumps in literal pool overflow situations. * s390.c (s390_decompose_address): Accept new-style pool chunk offsets. (s390_frame_info): Account for possible use of RETURN_REGNUM by new literal pool overflow code. (s390_emit_prologue): Likewise. From-SVN: r54500
-rw-r--r--gcc/ChangeLog44
-rw-r--r--gcc/config/s390/s390-protos.h4
-rw-r--r--gcc/config/s390/s390.c837
-rw-r--r--gcc/config/s390/s390.h56
-rw-r--r--gcc/config/s390/s390.md140
5 files changed, 811 insertions, 270 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index c00e99e..d173955 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,47 @@
+2002-06-11 Ulrich Weigand <uweigand@de.ibm.com>
+
+ * config/s390/s390.md (reload_base, ltorg): Remove.
+ * s390.c (s390_stop_dump_lit_p, s390_dump_literal_pool,
+ s390_asm_output_pool_prologue, s390_pool_start_insn): Remove.
+ * s390-protos.h (s390_stop_dump_lit_p, s390_dump_literal_pool,
+ s390_asm_output_pool_prologue): Likewise.
+ * s390.h (s390_pool_start_insn): Likewise.
+
+ * s390.c (s390_output_symbolic_const): Remove support for
+ old-style pool chunks.
+ (s390_function_epilogue): Likewise.
+ (s390_output_constant_pool): Likewise. Also, fix incorrect
+ alignment for 64-bit literal pools.
+ (print_operand_address): Remove 'y' and 'Y' format flags.
+ * s390.h (ASM_OUTPUT_POOL_PROLOGUE): Remove support for
+ old-style pool chunks.
+ (ASM_OUTPUT_SPECIAL_POOL_ENTRY): Likewise.
+ (ASM_OUTPUT_POOL_EPILOGUE): Remove.
+ (S390_CHUNK_MAX, S390_CHUNK_OV, S390_POOL_MAX): Remove.
+
+ * s390.c (consttable_operand): New function.
+ * s390-protos.h (consttable_operand): Declare it.
+ * s390.h (PREDICATE_CODES): Add consttable_operand.
+ * s390.md (consttable_qi, consttable_hi, consttable_si, consttable_di,
+ consttable_sf, consttable_df, pool_start_31, pool_end_31,
+ pool_start_64, pool_end_64, reload_base, reload_base2): New insns.
+ * s390.c (struct constant, struct constant_pool): New data types.
+ (constant_modes, gen_consttable): New variables.
+ (s390_start_pool, s390_end_pool, s390_add_pool,
+ s390_dump_pool, s390_free_pool): New functions.
+ (s390_chunkify_pool): Completely reimplement literal pool
+ overflow handling.
+
+ * s390.c (s390_pool_overflow): New variable.
+ * s390.h (s390_pool_overflow): Declare it.
+ * s390.md (cjump, icjump): Use it to adapt length for out-of-range
+ jumps in literal pool overflow situations.
+
+ * s390.c (s390_decompose_address): Accept new-style pool chunk offsets.
+ (s390_frame_info): Account for possible use of RETURN_REGNUM
+ by new literal pool overflow code.
+ (s390_emit_prologue): Likewise.
+
2002-06-05 David S. Miller <davem@redhat.com>
Delete SEQUENCE rtl usage outside of reorg and ssa passes.
diff --git a/gcc/config/s390/s390-protos.h b/gcc/config/s390/s390-protos.h
index 2abc4dd..cd4ac10 100644
--- a/gcc/config/s390/s390-protos.h
+++ b/gcc/config/s390/s390-protos.h
@@ -32,6 +32,7 @@ extern void s390_function_profiler PARAMS ((FILE *, int));
#ifdef RTX_CODE
extern int const0_operand PARAMS ((rtx, enum machine_mode));
+extern int consttable_operand PARAMS ((rtx, enum machine_mode));
extern int larl_operand PARAMS ((rtx, enum machine_mode));
extern int fp_operand PARAMS ((rtx, enum machine_mode));
extern int s_operand PARAMS ((rtx, enum machine_mode));
@@ -65,8 +66,6 @@ extern void s390_output_symbolic_const PARAMS ((FILE *, rtx));
extern void print_operand_address PARAMS ((FILE *, rtx));
extern void print_operand PARAMS ((FILE *, rtx, int));
extern void s390_output_constant_pool PARAMS ((FILE *));
-extern int s390_stop_dump_lit_p PARAMS ((rtx));
-extern void s390_dump_literal_pool PARAMS ((rtx, rtx));
extern void s390_trampoline_template PARAMS ((FILE *));
extern void s390_initialize_trampoline PARAMS ((rtx, rtx, rtx));
extern rtx s390_gen_rtx_const_DI PARAMS ((int, int));
@@ -74,7 +73,6 @@ extern rtx s390_simplify_dwarf_addr PARAMS ((rtx));
#endif /* RTX_CODE */
#ifdef TREE_CODE
-extern void s390_asm_output_pool_prologue PARAMS ((FILE *, const char *, tree, int));
extern int s390_function_arg_pass_by_reference PARAMS ((enum machine_mode, tree));
extern void s390_function_arg_advance PARAMS ((CUMULATIVE_ARGS *, enum machine_mode, tree, int));
extern tree s390_build_va_list PARAMS ((void));
diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c
index 1503f1b..b37f917 100644
--- a/gcc/config/s390/s390.c
+++ b/gcc/config/s390/s390.c
@@ -140,6 +140,8 @@ static int s390_decompose_address PARAMS ((rtx, struct s390_address *, int));
static int reg_used_in_mem_p PARAMS ((int, rtx));
static int addr_generation_dependency_p PARAMS ((rtx, rtx));
static void s390_split_branches PARAMS ((void));
+static void find_constant_pool_ref PARAMS ((rtx, rtx *));
+static void replace_constant_pool_ref PARAMS ((rtx *, rtx, rtx));
static void s390_chunkify_pool PARAMS ((void));
static int save_fprs_p PARAMS ((void));
static int find_unused_clobbered_reg PARAMS ((void));
@@ -635,6 +637,18 @@ const0_operand (op, mode)
return op == CONST0_RTX (mode);
}
+/* Return true if OP is constant.
+ OP is the current operation.
+ MODE is the current operation mode. */
+
+int
+consttable_operand (op, mode)
+ rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ return CONSTANT_P (op);
+}
+
/* Return true if the mode of operand OP matches MODE.
If MODE is set to VOIDmode, set it to the mode of OP. */
@@ -1395,6 +1409,26 @@ s390_decompose_address (addr, out, strict)
pointer = TRUE;
}
+ /* Accept chunkfied literal pool symbol references. */
+ else if (GET_CODE (disp) == CONST
+ && GET_CODE (XEXP (disp, 0)) == MINUS
+ && GET_CODE (XEXP (XEXP (disp, 0), 0)) == LABEL_REF
+ && GET_CODE (XEXP (XEXP (disp, 0), 1)) == LABEL_REF)
+ {
+ pointer = TRUE;
+ }
+
+ /* Likewise if a constant offset is present. */
+ else if (GET_CODE (disp) == CONST
+ && GET_CODE (XEXP (disp, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (disp, 0), 1)) == CONST_INT
+ && GET_CODE (XEXP (XEXP (disp, 0), 0)) == MINUS
+ && GET_CODE (XEXP (XEXP (XEXP (disp, 0), 0), 0)) == LABEL_REF
+ && GET_CODE (XEXP (XEXP (XEXP (disp, 0), 0), 1)) == LABEL_REF)
+ {
+ pointer = TRUE;
+ }
+
/* We can convert literal pool addresses to
displacements by basing them off the base register. */
else
@@ -1944,18 +1978,10 @@ s390_output_symbolic_const (file, x)
break;
case CONST_INT:
- output_addr_const (file, x);
- break;
-
case LABEL_REF:
case CODE_LABEL:
- output_addr_const (file, x);
- break;
-
case SYMBOL_REF:
output_addr_const (file, x);
- if (CONSTANT_POOL_ADDRESS_P (x) && s390_pool_count != 0)
- fprintf (file, "_%X", s390_pool_count);
break;
case UNSPEC:
@@ -1965,8 +1991,7 @@ s390_output_symbolic_const (file, x)
{
case 100:
s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
- fprintf (file, "-.LT%X_%X",
- s390_function_count, s390_pool_count);
+ fprintf (file, "-.LT%X", s390_function_count);
break;
case 110:
s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
@@ -1986,8 +2011,7 @@ s390_output_symbolic_const (file, x)
break;
case 114:
s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
- fprintf (file, "@PLT-.LT%X_%X",
- s390_function_count, s390_pool_count);
+ fprintf (file, "@PLT-.LT%X", s390_function_count);
break;
default:
output_operand_lossage ("invalid UNSPEC as operand (2)");
@@ -2032,8 +2056,6 @@ print_operand_address (file, addr)
'C': print opcode suffix for branch condition.
'D': print opcode suffix for inverse branch condition.
- 'Y': print current constant pool address (pc-relative).
- 'y': print current constant pool address (absolute).
'O': print only the displacement of a memory reference.
'R': print only the base register of a memory reference.
'N': print the second word of a DImode operand.
@@ -2059,14 +2081,6 @@ print_operand (file, x, code)
fprintf (file, s390_branch_condition_mnemonic (x, TRUE));
return;
- case 'Y':
- fprintf (file, ".LT%X_%X-.", s390_function_count, s390_pool_count);
- return;
-
- case 'y':
- fprintf (file, ".LT%X_%X", s390_function_count, s390_pool_count);
- return;
-
case 'O':
{
struct s390_address ad;
@@ -2384,60 +2398,6 @@ s390_adjust_priority (insn, priority)
}
-/* Pool concept for Linux 390:
- - Function prologue saves used register
- - literal pool is dumped in prologue and jump across with bras
- - If function has more than 4 k literals, at about every
- S390_CHUNK_MAX offset in the function a literal pool will be
- dumped
- - in this case, a branch from one chunk to other chunk needs
- a reload of base register at the code label branched to. */
-
-/* Index of constant pool chunk that is currently being processed.
- Set to -1 before function output has started. */
-int s390_pool_count = -1;
-
-/* First insn using the constant pool chunk that is currently being
- processed. */
-rtx s390_pool_start_insn = NULL_RTX;
-
-/* Called from the ASM_OUTPUT_POOL_PROLOGUE macro to
- prepare for printing a literal pool chunk to stdio stream FILE.
-
- FNAME and FNDECL specify the name and type of the current function.
- SIZE is the size in bytes of the current literal pool. */
-
-void
-s390_asm_output_pool_prologue (file, fname, fndecl, size)
- FILE *file;
- const char *fname ATTRIBUTE_UNUSED;
- tree fndecl;
- int size ATTRIBUTE_UNUSED;
-{
-
- if (s390_pool_count>0) {
- /*
- * We are in an internal pool, branch over
- */
- if (TARGET_64BIT)
- {
- fprintf (file, "\tlarl\t%s,.LT%X_%X\n",
- reg_names[BASE_REGISTER],
- s390_function_count, s390_pool_count);
- readonly_data_section ();
- ASM_OUTPUT_ALIGN (file, floor_log2 (3));
- fprintf (file, ".LT%X_%X:\t# Pool %d\n",
- s390_function_count, s390_pool_count, s390_pool_count);
- }
- else
- fprintf (file,"\t.align 4\n\tbras\t%s,0f\n.LT%X_%X:\t# Pool %d \n",
- reg_names[BASE_REGISTER],
- s390_function_count, s390_pool_count, s390_pool_count);
- }
- if (!TARGET_64BIT)
- function_section (fndecl);
-}
-
/* Split all branches that exceed the maximum distance. */
static void
@@ -2516,62 +2476,490 @@ s390_split_branches (void)
}
}
+
+/* Find a 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 symbol
+ are allowed, however.
+
+ The rtx pointed to by REF must be initialized to NULL_RTX
+ by the caller before calling this routine. */
+
+static void
+find_constant_pool_ref (x, ref)
+ rtx x;
+ rtx *ref;
+{
+ int i, j;
+ const char *fmt;
+
+ if (GET_CODE (x) == SYMBOL_REF
+ && CONSTANT_POOL_ADDRESS_P (x))
+ {
+ if (*ref == NULL_RTX)
+ *ref = x;
+ else if (*ref != x)
+ abort();
+ }
+
+ fmt = GET_RTX_FORMAT (GET_CODE (x));
+ for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'e')
+ {
+ find_constant_pool_ref (XEXP (x, i), ref);
+ }
+ else if (fmt[i] == 'E')
+ {
+ for (j = 0; j < XVECLEN (x, i); j++)
+ find_constant_pool_ref (XVECEXP (x, i, j), ref);
+ }
+ }
+}
+
+/* Replace every reference to the literal pool symbol REF
+ in X by the address ADDR. Fix up MEMs as required. */
+
+static void
+replace_constant_pool_ref (x, ref, addr)
+ rtx *x;
+ rtx ref;
+ rtx addr;
+{
+ int i, j;
+ const char *fmt;
+
+ if (*x == ref)
+ abort ();
+
+ /* Literal pool references can only occur inside a MEM ... */
+ if (GET_CODE (*x) == MEM)
+ {
+ rtx memref = XEXP (*x, 0);
+
+ if (memref == ref)
+ {
+ *x = replace_equiv_address (*x, addr);
+ return;
+ }
+
+ if (GET_CODE (memref) == CONST
+ && GET_CODE (XEXP (memref, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (memref, 0), 1)) == CONST_INT
+ && XEXP (XEXP (memref, 0), 0) == ref)
+ {
+ HOST_WIDE_INT off = INTVAL (XEXP (XEXP (memref, 0), 1));
+ *x = replace_equiv_address (*x, plus_constant (addr, off));
+ return;
+ }
+ }
+
+ /* ... or a load-address type pattern. */
+ if (GET_CODE (*x) == SET)
+ {
+ rtx addrref = SET_SRC (*x);
+
+ if (addrref == ref)
+ {
+ SET_SRC (*x) = addr;
+ return;
+ }
+
+ if (GET_CODE (addrref) == CONST
+ && GET_CODE (XEXP (addrref, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (addrref, 0), 1)) == CONST_INT
+ && XEXP (XEXP (addrref, 0), 0) == ref)
+ {
+ HOST_WIDE_INT off = INTVAL (XEXP (XEXP (addrref, 0), 1));
+ SET_SRC (*x) = plus_constant (addr, off);
+ return;
+ }
+ }
+
+ fmt = GET_RTX_FORMAT (GET_CODE (*x));
+ for (i = GET_RTX_LENGTH (GET_CODE (*x)) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'e')
+ {
+ replace_constant_pool_ref (&XEXP (*x, i), ref, addr);
+ }
+ else if (fmt[i] == 'E')
+ {
+ for (j = 0; j < XVECLEN (*x, i); j++)
+ replace_constant_pool_ref (&XVECEXP (*x, i, j), ref, addr);
+ }
+ }
+}
+
+/* We keep a list of constants we which we have to add to internal
+ constant tables in the middle of large functions. */
+
+#define NR_C_MODES 6
+enum machine_mode constant_modes[NR_C_MODES] =
+{
+ DFmode, DImode,
+ SFmode, SImode,
+ HImode,
+ QImode
+};
+
+rtx (*gen_consttable[NR_C_MODES])(rtx) =
+{
+ gen_consttable_df, gen_consttable_di,
+ gen_consttable_sf, gen_consttable_si,
+ gen_consttable_hi,
+ gen_consttable_qi
+};
+
+struct constant
+{
+ struct constant *next;
+ rtx value;
+ rtx label;
+};
+
+struct constant_pool
+{
+ struct constant_pool *next;
+ rtx first_insn;
+ rtx last_insn;
+
+ struct constant *constants[NR_C_MODES];
+ rtx label;
+ int size;
+};
+
+static struct constant_pool *s390_start_pool PARAMS ((struct constant_pool **, rtx));
+static void s390_end_pool PARAMS ((struct constant_pool *, rtx));
+static struct constant_pool *s390_find_pool PARAMS ((struct constant_pool *, rtx));
+static rtx s390_add_pool PARAMS ((struct constant_pool *, rtx, enum machine_mode));
+static rtx s390_dump_pool PARAMS ((struct constant_pool *));
+static void s390_free_pool PARAMS ((struct constant_pool *));
+
+/* Create new constant pool covering instructions starting at INSN
+ and chain it to the end of POOL_LIST. */
+
+static struct constant_pool *
+s390_start_pool (pool_list, insn)
+ struct constant_pool **pool_list;
+ rtx insn;
+{
+ struct constant_pool *pool, **prev;
+ int i;
+
+ pool = (struct constant_pool *) xmalloc (sizeof *pool);
+ pool->next = NULL;
+ for (i = 0; i < NR_C_MODES; i++)
+ pool->constants[i] = NULL;
+
+ pool->label = gen_label_rtx ();
+ pool->first_insn = insn;
+ pool->last_insn = NULL_RTX;
+ pool->size = 0;
+
+ for (prev = pool_list; *prev; prev = &(*prev)->next)
+ ;
+ *prev = pool;
+
+ return pool;
+}
+
+/* End range of instructions covered by POOL at INSN. */
+
+static void
+s390_end_pool (pool, insn)
+ struct constant_pool *pool;
+ rtx insn;
+{
+ pool->last_insn = insn;
+}
+
+/* Return pool out of POOL_LIST that covers INSN. */
+
+static struct constant_pool *
+s390_find_pool (pool_list, insn)
+ struct constant_pool *pool_list;
+ rtx insn;
+{
+ int addr = INSN_ADDRESSES (INSN_UID (insn));
+ struct constant_pool *pool;
+
+ if (addr == -1)
+ return NULL;
+
+ for (pool = pool_list; pool; pool = pool->next)
+ if (INSN_ADDRESSES (INSN_UID (pool->first_insn)) <= addr
+ && (pool->last_insn == NULL_RTX
+ || INSN_ADDRESSES (INSN_UID (pool->last_insn)) > addr))
+ break;
+
+ return pool;
+}
+
+/* Add constant VAL of mode MODE to the constant pool POOL.
+ Return an RTX describing the distance from the start of
+ the pool to the location of the new constant. */
+
+static rtx
+s390_add_pool (pool, val, mode)
+ struct constant_pool *pool;
+ rtx val;
+ enum machine_mode mode;
+{
+ struct constant *c;
+ rtx offset;
+ int i;
+
+ for (i = 0; i < NR_C_MODES; i++)
+ if (constant_modes[i] == mode)
+ break;
+ if (i == NR_C_MODES)
+ abort ();
+
+ for (c = pool->constants[i]; c != NULL; c = c->next)
+ if (rtx_equal_p (val, c->value))
+ break;
+
+ if (c == NULL)
+ {
+ c = (struct constant *) xmalloc (sizeof *c);
+ c->value = val;
+ c->label = gen_label_rtx ();
+ c->next = pool->constants[i];
+ pool->constants[i] = c;
+ pool->size += GET_MODE_SIZE (mode);
+ }
+
+ offset = gen_rtx_MINUS (Pmode, gen_rtx_LABEL_REF (Pmode, c->label),
+ gen_rtx_LABEL_REF (Pmode, pool->label));
+ offset = gen_rtx_CONST (Pmode, offset);
+ return offset;
+}
+
+/* Dump out the constants in POOL. */
+
+static rtx
+s390_dump_pool (pool)
+ struct constant_pool *pool;
+{
+ struct constant *c;
+ rtx insn;
+ int i;
+
+ /* Select location to put literal pool. */
+ if (TARGET_64BIT)
+ insn = get_last_insn ();
+ else
+ insn = pool->last_insn? pool->last_insn : get_last_insn ();
+
+ /* Pool start insn switches to proper section
+ and guarantees necessary alignment. */
+ if (TARGET_64BIT)
+ insn = emit_insn_after (gen_pool_start_64 (), insn);
+ else
+ insn = emit_insn_after (gen_pool_start_31 (), insn);
+ INSN_ADDRESSES_NEW (insn, -1);
+
+ insn = emit_label_after (pool->label, insn);
+ INSN_ADDRESSES_NEW (insn, -1);
+
+ /* Dump constants in descending alignment requirement order,
+ ensuring proper alignment for every constant. */
+ for (i = 0; i < NR_C_MODES; i++)
+ for (c = pool->constants[i]; c; c = c->next)
+ {
+ insn = emit_label_after (c->label, insn);
+ INSN_ADDRESSES_NEW (insn, -1);
+ insn = emit_insn_after (gen_consttable[i] (c->value), insn);
+ INSN_ADDRESSES_NEW (insn, -1);
+ }
+
+ /* Pool end insn switches back to previous section
+ and guarantees necessary alignment. */
+ if (TARGET_64BIT)
+ insn = emit_insn_after (gen_pool_end_64 (), insn);
+ else
+ insn = emit_insn_after (gen_pool_end_31 (), insn);
+ INSN_ADDRESSES_NEW (insn, -1);
+
+ insn = emit_barrier_after (insn);
+ INSN_ADDRESSES_NEW (insn, -1);
+
+ return insn;
+}
+
+/* Free all memory used by POOL. */
+
+static void
+s390_free_pool (pool)
+ struct constant_pool *pool;
+{
+ int i;
+
+ for (i = 0; i < NR_C_MODES; i++)
+ {
+ struct constant *c = pool->constants[i];
+ while (c != NULL)
+ {
+ struct constant *next = c->next;
+ free (c);
+ c = next;
+ }
+ }
+
+ free (pool);
+}
+
+/* Used in s390.md for branch length calculation. */
+int s390_pool_overflow = 0;
+
/* Chunkify the literal pool if required. */
+#define S390_POOL_CHUNK_MIN 0xc00
+#define S390_POOL_CHUNK_MAX 0xe00
+
static void
s390_chunkify_pool (void)
{
- int *ltorg_uids, max_ltorg, chunk, last_addr, next_addr;
+ rtx base_reg = gen_rtx_REG (Pmode,
+ TARGET_64BIT? BASE_REGISTER : RETURN_REGNUM);
+
+ struct constant_pool *curr_pool = NULL, *pool_list = NULL;
+ int extra_size = 0;
+ bitmap far_labels;
rtx insn;
/* Do we need to chunkify the literal pool? */
- if (get_pool_size () <= S390_POOL_MAX)
+ if (get_pool_size () < S390_POOL_CHUNK_MAX)
return;
- /* Find all insns where a literal pool chunk must be inserted. */
+ /* Scan all insns and move literals to pool chunks.
+ Replace all occurrances of literal pool references
+ by explicit references to pool chunk entries. */
- ltorg_uids = alloca (insn_current_address / 1024 + 1024);
- max_ltorg = 0;
-
- last_addr = 0;
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
{
- if (INSN_ADDRESSES (INSN_UID (insn)) - last_addr < S390_CHUNK_MAX)
+ if (GET_CODE (insn) == INSN)
+ {
+ rtx addr, pool_ref = NULL_RTX;
+ find_constant_pool_ref (PATTERN (insn), &pool_ref);
+ if (pool_ref)
+ {
+ if (!curr_pool)
+ curr_pool = s390_start_pool (&pool_list, insn);
+
+ addr = s390_add_pool (curr_pool, get_pool_constant (pool_ref),
+ get_pool_mode (pool_ref));
+
+ addr = gen_rtx_PLUS (Pmode, base_reg, addr);
+ replace_constant_pool_ref (&PATTERN (insn), pool_ref, addr);
+ INSN_CODE (insn) = -1;
+ }
+ }
+
+ if (!curr_pool
+ || INSN_ADDRESSES_SIZE () <= (size_t) INSN_UID (insn)
+ || INSN_ADDRESSES (INSN_UID (insn)) == -1)
continue;
- if (INSN_ADDRESSES (INSN_UID (insn)) - last_addr > S390_CHUNK_OV)
- abort ();
- if (GET_CODE (insn) == CODE_LABEL
- && !(GET_CODE (NEXT_INSN (insn)) == JUMP_INSN
- && (GET_CODE (PATTERN (NEXT_INSN (insn))) == ADDR_VEC
- || GET_CODE (PATTERN (NEXT_INSN (insn))) == ADDR_DIFF_VEC)))
+ if (TARGET_64BIT)
{
- ltorg_uids[max_ltorg++] = INSN_UID (prev_real_insn (insn));
- last_addr = INSN_ADDRESSES (ltorg_uids[max_ltorg-1]);
- continue;
- }
+ if (curr_pool->size < S390_POOL_CHUNK_MAX)
+ continue;
- if (GET_CODE (insn) == CALL_INSN)
+ s390_end_pool (curr_pool, insn);
+ curr_pool = NULL;
+ }
+ else
{
- ltorg_uids[max_ltorg++] = INSN_UID (insn);
- last_addr = INSN_ADDRESSES (ltorg_uids[max_ltorg-1]);
- continue;
+ int chunk_size = INSN_ADDRESSES (INSN_UID (insn))
+ - INSN_ADDRESSES (INSN_UID (curr_pool->first_insn))
+ + extra_size;
+
+ /* We will later have to insert base register reload insns.
+ Those will have an effect on code size, which we need to
+ consider here. This calculation makes rather pessimistic
+ worst-case assumptions. */
+ if (GET_CODE (insn) == CODE_LABEL
+ || GET_CODE (insn) == JUMP_INSN)
+ extra_size += 6;
+ else if (GET_CODE (insn) == CALL_INSN)
+ extra_size += 4;
+
+ if (chunk_size < S390_POOL_CHUNK_MIN
+ && curr_pool->size < S390_POOL_CHUNK_MIN)
+ continue;
+
+ /* Pool chunks can only be inserted after BARRIERs ... */
+ if (GET_CODE (insn) == BARRIER)
+ {
+ s390_end_pool (curr_pool, insn);
+ curr_pool = NULL;
+ extra_size = 0;
+ }
+
+ /* ... so if we don't find one in time, create one. */
+ else if ((chunk_size > S390_POOL_CHUNK_MAX
+ || curr_pool->size > S390_POOL_CHUNK_MAX)
+ && (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN))
+ {
+ int addr = INSN_ADDRESSES (INSN_UID (insn));
+ rtx label, jump, barrier;
+
+ label = gen_label_rtx ();
+ jump = emit_jump_insn_after (gen_jump (label), insn);
+ barrier = emit_barrier_after (jump);
+ insn = emit_label_after (label, barrier);
+ JUMP_LABEL (jump) = label;
+ LABEL_NUSES (label) = 1;
+
+ INSN_ADDRESSES_NEW (jump, addr+1);
+ INSN_ADDRESSES_NEW (barrier, addr+1);
+ INSN_ADDRESSES_NEW (insn, -1);
+
+ s390_end_pool (curr_pool, barrier);
+ curr_pool = NULL;
+ extra_size = 0;
+ }
}
}
- ltorg_uids[max_ltorg] = -1;
+ /* Dump out all literal pools. */
+
+ for (curr_pool = pool_list; curr_pool; curr_pool = curr_pool->next)
+ s390_dump_pool (curr_pool);
- /* Find and mark all labels that are branched into
+
+ /* Find all labels that are branched into
from an insn belonging to a different chunk. */
- chunk = last_addr = 0;
- next_addr = ltorg_uids[chunk] == -1 ? insn_current_address + 1
- : INSN_ADDRESSES (ltorg_uids[chunk]);
+ far_labels = BITMAP_XMALLOC ();
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
{
- if (GET_CODE (insn) == JUMP_INSN)
+ /* Labels marked with LABEL_PRESERVE_P can be target
+ of non-local jumps, so we have to mark them.
+ The same holds for named labels.
+
+ Don't do that, however, if it is the label before
+ a jump table. */
+
+ if (GET_CODE (insn) == CODE_LABEL
+ && (LABEL_PRESERVE_P (insn) || LABEL_NAME (insn)))
+ {
+ rtx vec_insn = next_real_insn (insn);
+ rtx vec_pat = vec_insn && GET_CODE (vec_insn) == JUMP_INSN ?
+ PATTERN (vec_insn) : NULL_RTX;
+ if (!vec_pat
+ || !(GET_CODE (vec_pat) == ADDR_VEC
+ || GET_CODE (vec_pat) == ADDR_DIFF_VEC))
+ bitmap_set_bit (far_labels, CODE_LABEL_NUMBER (insn));
+ }
+
+ /* If we have a direct jump (conditional or unconditional)
+ or a casesi jump, check all potential targets. */
+ else if (GET_CODE (insn) == JUMP_INSN)
{
rtx pat = PATTERN (insn);
if (GET_CODE (pat) == SET)
@@ -2592,112 +2980,140 @@ s390_chunkify_pool (void)
if (label)
{
- if (INSN_ADDRESSES (INSN_UID (label)) <= last_addr
- || INSN_ADDRESSES (INSN_UID (label)) > next_addr)
- SYMBOL_REF_USED (label) = 1;
+ if (s390_find_pool (pool_list, label)
+ != s390_find_pool (pool_list, insn))
+ bitmap_set_bit (far_labels, CODE_LABEL_NUMBER (label));
}
}
- else if (GET_CODE (pat) == ADDR_VEC
- || GET_CODE (pat) == ADDR_DIFF_VEC)
- {
- int i, diff_p = GET_CODE (pat) == ADDR_DIFF_VEC;
-
- for (i = 0; i < XVECLEN (pat, diff_p); i++)
- {
- rtx label = XEXP (XVECEXP (pat, diff_p, i), 0);
+ else if (GET_CODE (pat) == PARALLEL
+ && XVECLEN (pat, 0) == 2
+ && GET_CODE (XVECEXP (pat, 0, 0)) == SET
+ && GET_CODE (XVECEXP (pat, 0, 1)) == USE
+ && GET_CODE (XEXP (XVECEXP (pat, 0, 1), 0)) == LABEL_REF)
+ {
+ /* Find the jump table used by this casesi jump. */
+ rtx vec_label = XEXP (XEXP (XVECEXP (pat, 0, 1), 0), 0);
+ rtx vec_insn = next_real_insn (vec_label);
+ rtx vec_pat = vec_insn && GET_CODE (vec_insn) == JUMP_INSN ?
+ PATTERN (vec_insn) : NULL_RTX;
+ if (vec_pat
+ && (GET_CODE (vec_pat) == ADDR_VEC
+ || GET_CODE (vec_pat) == ADDR_DIFF_VEC))
+ {
+ int i, diff_p = GET_CODE (vec_pat) == ADDR_DIFF_VEC;
- if (INSN_ADDRESSES (INSN_UID (label)) <= last_addr
- || INSN_ADDRESSES (INSN_UID (label)) > next_addr)
- SYMBOL_REF_USED (label) = 1;
- }
- }
- }
+ for (i = 0; i < XVECLEN (vec_pat, diff_p); i++)
+ {
+ rtx label = XEXP (XVECEXP (vec_pat, diff_p, i), 0);
- if (INSN_UID (insn) == ltorg_uids[chunk])
- {
- last_addr = INSN_ADDRESSES (ltorg_uids[chunk++]);
- next_addr = ltorg_uids[chunk] == -1 ? insn_current_address + 1
- : INSN_ADDRESSES (ltorg_uids[chunk]);
+ if (s390_find_pool (pool_list, label)
+ != s390_find_pool (pool_list, insn))
+ bitmap_set_bit (far_labels, CODE_LABEL_NUMBER (label));
+ }
+ }
+ }
}
}
- /* Insert literal pools and base register reload insns. */
+ /* Insert base register reload insns before every pool. */
+
+ for (curr_pool = pool_list; curr_pool; curr_pool = curr_pool->next)
+ if (TARGET_64BIT)
+ {
+ rtx pool_ref = gen_rtx_LABEL_REF (Pmode, curr_pool->label);
+ rtx new_insn = gen_rtx_SET (Pmode, base_reg, pool_ref);
+ rtx insn = curr_pool->first_insn;
+ INSN_ADDRESSES_NEW (emit_insn_before (new_insn, insn), -1);
+ }
+ else
+ {
+ rtx new_insn = gen_reload_base (base_reg, curr_pool->label);
+ rtx insn = curr_pool->first_insn;
+ INSN_ADDRESSES_NEW (emit_insn_before (new_insn, insn), -1);
+ }
+
+ /* Insert base register reload insns at every far label. */
- chunk = 0;
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
- {
- if (INSN_UID (insn) == ltorg_uids[chunk])
- {
- rtx new_insn = gen_ltorg (GEN_INT (chunk++));
- INSN_ADDRESSES_NEW (emit_insn_after (new_insn, insn), -1);
- }
+ if (GET_CODE (insn) == CODE_LABEL
+ && bitmap_bit_p (far_labels, CODE_LABEL_NUMBER (insn)))
+ {
+ struct constant_pool *pool = s390_find_pool (pool_list, insn);
+ if (pool)
+ {
+ if (TARGET_64BIT)
+ {
+ rtx pool_ref = gen_rtx_LABEL_REF (Pmode, pool->label);
+ rtx new_insn = gen_rtx_SET (Pmode, base_reg, pool_ref);
+ INSN_ADDRESSES_NEW (emit_insn_after (new_insn, insn), -1);
+ }
+ else
+ {
+ rtx new_insn = gen_reload_base (base_reg, pool->label);
+ INSN_ADDRESSES_NEW (emit_insn_after (new_insn, insn), -1);
+ }
+ }
+ }
+
+ /* Insert base register reload insns after every call if necessary. */
+
+ if (REGNO (base_reg) == RETURN_REGNUM)
+ for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ if (GET_CODE (insn) == CALL_INSN)
+ {
+ struct constant_pool *pool = s390_find_pool (pool_list, insn);
+ if (pool)
+ {
+ rtx new_insn = gen_reload_base2 (base_reg, pool->label);
+ INSN_ADDRESSES_NEW (emit_insn_after (new_insn, insn), -1);
+ }
+ }
- if (GET_CODE (insn) == CODE_LABEL && SYMBOL_REF_USED (insn))
- {
- rtx new_insn = gen_reload_base (insn);
- INSN_ADDRESSES_NEW (emit_insn_after (new_insn, insn), -1);
- }
- }
/* Recompute insn addresses. */
+ s390_pool_overflow = 1;
init_insn_lengths ();
shorten_branches (get_insns ());
-}
+ s390_pool_overflow = 0;
-/* Return true if INSN is a 'ltorg' insn. */
+ /* Insert base register reload insns after far branches. */
-int
-s390_stop_dump_lit_p (insn)
- rtx insn;
-{
- rtx body=PATTERN (insn);
- if (GET_CODE (body) == PARALLEL
- && GET_CODE (XVECEXP (body, 0, 0)) == SET
- && GET_CODE (XVECEXP (body, 0, 1)) == USE
- && GET_CODE (XEXP ((XVECEXP (body, 0, 1)),0)) == CONST_INT
- && GET_CODE (SET_DEST (XVECEXP (body, 0, 0))) == REG
- && REGNO (SET_DEST (XVECEXP (body, 0, 0))) == BASE_REGISTER
- && SET_SRC (XVECEXP (body, 0, 0)) == pc_rtx) {
- return 1;
- }
- else
- return 0;
-}
-
-/* Output literal pool chunk to be used for insns
- between insn ACT_INSN and the insn with UID STOP. */
-
-void
-s390_dump_literal_pool (act_insn, stop)
- rtx act_insn;
- rtx stop;
-{
- s390_pool_start_insn = act_insn;
- s390_pool_count++;
- output_constant_pool (current_function_name, current_function_decl);
- function_section (current_function_decl);
-}
+ if (!TARGET_64BIT)
+ for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ if (GET_CODE (insn) == JUMP_INSN
+ && GET_CODE (PATTERN (insn)) == SET
+ && get_attr_length (insn) >= 12)
+ {
+ struct constant_pool *pool = s390_find_pool (pool_list, insn);
+ if (pool)
+ {
+ rtx new_insn = gen_reload_base (base_reg, pool->label);
+ INSN_ADDRESSES_NEW (emit_insn_after (new_insn, insn), -1);
+ }
+ }
-/* Number of elements of current constant pool. */
-int s390_nr_constants;
-/* Return true if floating point registers need to be saved. */
+ /* Free all memory. */
-static int
-save_fprs_p ()
-{
- int i;
- if (!TARGET_64BIT)
- return 0;
- for (i=24; i<=31; i++)
+ while (pool_list)
{
- if (regs_ever_live[i] == 1)
- return 1;
+ struct constant_pool *next = pool_list->next;
+ s390_free_pool (pool_list);
+ pool_list = next;
}
- return 0;
+
+ BITMAP_XFREE (far_labels);
}
+
+/* Index of constant pool chunk that is currently being processed.
+ Set to -1 before function output has started. */
+int s390_pool_count = -1;
+
+/* Number of elements of current constant pool. */
+int s390_nr_constants;
+
/* Output main constant pool to stdio stream FILE. */
void
@@ -2707,26 +3123,46 @@ s390_output_constant_pool (file)
/* Output constant pool. */
if (s390_nr_constants)
{
- s390_pool_count = 0;
if (TARGET_64BIT)
{
- fprintf (file, "\tlarl\t%s,.LT%X_%X\n", reg_names[BASE_REGISTER],
- s390_function_count, s390_pool_count);
+ fprintf (file, "\tlarl\t%s,.LT%X\n", reg_names[BASE_REGISTER],
+ s390_function_count);
readonly_data_section ();
- ASM_OUTPUT_ALIGN (file, floor_log2 (3));
+ ASM_OUTPUT_ALIGN (file, 3);
}
else
{
- fprintf (file, "\tbras\t%s,.LTN%X_%X\n", reg_names[BASE_REGISTER],
- s390_function_count, s390_pool_count);
+ fprintf (file, "\tbras\t%s,.LTN%X\n", reg_names[BASE_REGISTER],
+ s390_function_count);
}
- fprintf (file, ".LT%X_%X:\n", s390_function_count, s390_pool_count);
+ fprintf (file, ".LT%X:\n", s390_function_count);
+
+ s390_pool_count = 0;
output_constant_pool (current_function_name, current_function_decl);
- fprintf (file, ".LTN%X_%X:\n", s390_function_count,
- s390_pool_count);
+ s390_pool_count = -1;
+
if (TARGET_64BIT)
function_section (current_function_decl);
+ else
+ fprintf (file, ".LTN%X:\n", s390_function_count);
+ }
+}
+
+
+/* Return true if floating point registers need to be saved. */
+
+static int
+save_fprs_p ()
+{
+ int i;
+ if (!TARGET_64BIT)
+ return 0;
+ for (i=24; i<=31; i++)
+ {
+ if (regs_ever_live[i] == 1)
+ return 1;
}
+ return 0;
}
/* Find first call clobbered register unsused in a function.
@@ -2774,6 +3210,12 @@ s390_frame_info (frame)
if (frame->frame_size > 0)
regs_ever_live[STACK_POINTER_REGNUM] = 1;
+ /* If the literal pool might overflow, the return register might
+ be used as temp literal pointer. */
+
+ if (!TARGET_64BIT && get_pool_size () >= S390_POOL_CHUNK_MAX / 2)
+ regs_ever_live[RETURN_REGNUM] = 1;
+
/* If there is (possibly) any pool entry, we need to
load base register. */
@@ -2895,8 +3337,6 @@ s390_function_epilogue (file, lsize)
HOST_WIDE_INT lsize ATTRIBUTE_UNUSED;
{
current_function_uses_pic_offset_table = 0;
- s390_pool_start_insn = NULL_RTX;
- s390_pool_count = -1;
s390_function_count++;
}
@@ -2917,7 +3357,8 @@ s390_emit_prologue ()
/* Choose best register to use for temp use within prologue. */
if (frame.return_reg_saved_p
- && !has_hard_reg_initial_val (Pmode, RETURN_REGNUM))
+ && !has_hard_reg_initial_val (Pmode, RETURN_REGNUM)
+ && get_pool_size () < S390_POOL_CHUNK_MAX / 2)
temp_reg = gen_rtx_REG (Pmode, RETURN_REGNUM);
else
temp_reg = gen_rtx_REG (Pmode, 1);
diff --git a/gcc/config/s390/s390.h b/gcc/config/s390/s390.h
index 0a04796..2e342ea 100644
--- a/gcc/config/s390/s390.h
+++ b/gcc/config/s390/s390.h
@@ -1259,6 +1259,8 @@ extern struct rtx_def *s390_compare_op0, *s390_compare_op1;
{"load_multiple_operation", {PARALLEL}}, \
{"store_multiple_operation", {PARALLEL}}, \
{"const0_operand", { CONST_INT, CONST_DOUBLE }}, \
+ {"consttable_operand", { SYMBOL_REF, LABEL_REF, CONST, \
+ CONST_INT, CONST_DOUBLE }}, \
{"s390_plus_operand", { PLUS }},
@@ -1277,20 +1279,12 @@ extern struct rtx_def *s390_compare_op0, *s390_compare_op1;
/* Constant Pool for all symbols operands which are changed with
force_const_mem during insn generation (expand_insn). */
-extern struct rtx_def *s390_pool_start_insn;
extern int s390_pool_count;
extern int s390_nr_constants;
-
-/* Function is splitted in chunk, if literal pool could overflow
- Value need to be lowered, if problems with displacement overflow. */
-
-#define S390_CHUNK_MAX 0xe00
-#define S390_CHUNK_OV 0x1000
-#define S390_POOL_MAX 0xe00
+extern int s390_pool_overflow;
#define ASM_OUTPUT_POOL_PROLOGUE(FILE, FUNNAME, fndecl, size) \
{ \
- register rtx insn; \
struct pool_constant *pool; \
\
if (s390_pool_count == -1) \
@@ -1300,53 +1294,11 @@ extern int s390_nr_constants;
if (pool->mark) s390_nr_constants++; \
return; \
} \
- if (first_pool == 0) { \
- s390_asm_output_pool_prologue (FILE, FUNNAME, fndecl, size); \
- return; \
- } \
- for (pool = first_pool; pool; pool = pool->next) \
- pool->mark = 0; \
- \
- insn = s390_pool_start_insn; \
- \
- if (insn==NULL_RTX) \
- insn = get_insns (); \
- else \
- insn = NEXT_INSN (insn); \
- for (; insn; insn = NEXT_INSN (insn)) { \
- if (GET_RTX_CLASS (GET_CODE (insn)) == 'i') { \
- if (s390_stop_dump_lit_p (insn)) { \
- mark_constants (PATTERN (insn)); \
- break; \
- } else \
- mark_constants (PATTERN (insn)); \
- } \
- } \
- \
- /* Mark entries referenced by other entries */ \
- for (pool = first_pool; pool; pool = pool->next) \
- if (pool->mark) \
- mark_constants (pool->constant); \
- \
- s390_asm_output_pool_prologue (FILE, FUNNAME, fndecl, size); \
}
-/* We need to return, because otherwise the pool is deleted of the
- constant pool after the first output. */
-
-#define ASM_OUTPUT_POOL_EPILOGUE(FILE, FUNNAME, fndecl, size) return;
-
#define ASM_OUTPUT_SPECIAL_POOL_ENTRY(FILE, EXP, MODE, ALIGN, LABELNO, WIN) \
{ \
- if ((s390_pool_count == 0) || (s390_pool_count > 0 && LABELNO >= 0)) \
- { \
- fprintf (FILE, ".LC%d:\n", LABELNO); \
- LABELNO = ~LABELNO; \
- } \
- if (s390_pool_count > 0) \
- { \
- fprintf (FILE, ".LC%d_%X:\n", ~LABELNO, s390_pool_count); \
- } \
+ fprintf (FILE, ".LC%d:\n", LABELNO); \
\
/* Output the value of the constant itself. */ \
switch (GET_MODE_CLASS (MODE)) \
diff --git a/gcc/config/s390/s390.md b/gcc/config/s390/s390.md
index 73582cd..f9a1d7b 100644
--- a/gcc/config/s390/s390.md
+++ b/gcc/config/s390/s390.md
@@ -5676,6 +5676,9 @@
(const_int 4)
(ne (symbol_ref "TARGET_64BIT") (const_int 0))
(const_int 6)
+ (ne (symbol_ref "s390_pool_overflow") (const_int 0))
+ (if_then_else (eq (symbol_ref "flag_pic") (const_int 0))
+ (const_int 12) (const_int 14))
(eq (symbol_ref "flag_pic") (const_int 0))
(const_int 6)] (const_int 8)))])
@@ -5725,6 +5728,9 @@
(const_int 4)
(ne (symbol_ref "TARGET_64BIT") (const_int 0))
(const_int 6)
+ (ne (symbol_ref "s390_pool_overflow") (const_int 0))
+ (if_then_else (eq (symbol_ref "flag_pic") (const_int 0))
+ (const_int 12) (const_int 14))
(eq (symbol_ref "flag_pic") (const_int 0))
(const_int 6)] (const_int 8)))])
@@ -6384,33 +6390,133 @@
; Special literal pool access instruction pattern(s).
;
-(define_insn "reload_base"
- [(parallel [(set (reg 13) (pc))
- (use (label_ref (match_operand 0 "" "")))])]
+(define_insn "consttable_qi"
+ [(unspec_volatile [(match_operand:QI 0 "consttable_operand" "X")] 200)]
""
"*
{
- if (TARGET_64BIT)
- return \"larl\\t13,%y0\";
- else
- return \"basr\\t13,0\;ahi\\t13,%Y0\";
+ assemble_integer (operands[0], 1, BITS_PER_UNIT, 1);
+ return \"\";
}"
- [(set_attr "op_type" "NN")
- (set_attr "type" "la")
- (set_attr "length" "8")])
+ [(set_attr "op_type" "NN")
+ (set_attr "length" "1")])
+
+(define_insn "consttable_hi"
+ [(unspec_volatile [(match_operand:HI 0 "consttable_operand" "X")] 201)]
+ ""
+ "*
+{
+ assemble_integer (operands[0], 2, 2*BITS_PER_UNIT, 1);
+ return \"\";
+}"
+ [(set_attr "op_type" "NN")
+ (set_attr "length" "2")])
+
+(define_insn "consttable_si"
+ [(unspec_volatile [(match_operand:SI 0 "consttable_operand" "X")] 202)]
+ ""
+ "*
+{
+ if (!TARGET_64BIT && flag_pic && SYMBOLIC_CONST (operands[0]))
+ return \".long\\t%0\";
-(define_insn "ltorg"
- [(parallel [(set (reg 13) (pc))
- (use (match_operand:SI 0 "const_int_operand" ""))])]
+ assemble_integer (operands[0], 4, 4*BITS_PER_UNIT, 1);
+ return \"\";
+}"
+ [(set_attr "op_type" "NN")
+ (set_attr "length" "4")])
+
+(define_insn "consttable_di"
+ [(unspec_volatile [(match_operand:DI 0 "consttable_operand" "X")] 203)]
""
"*
{
- s390_dump_literal_pool (insn, operands[0]);
- return \"0:\";
+ assemble_integer (operands[0], 8, 8*BITS_PER_UNIT, 1);
+ return \"\";
+}"
+ [(set_attr "op_type" "NN")
+ (set_attr "length" "8")])
+
+(define_insn "consttable_sf"
+ [(unspec_volatile [(match_operand:SF 0 "consttable_operand" "X")] 204)]
+ ""
+ "*
+{
+ REAL_VALUE_TYPE r;
+
+ if (GET_CODE (operands[0]) != CONST_DOUBLE)
+ abort ();
+
+ REAL_VALUE_FROM_CONST_DOUBLE (r, operands[0]);
+ assemble_real (r, SFmode, 4*BITS_PER_UNIT);
+ return \"\";
}"
+ [(set_attr "op_type" "NN")
+ (set_attr "length" "4")])
+
+(define_insn "consttable_df"
+ [(unspec_volatile [(match_operand:DF 0 "consttable_operand" "X")] 205)]
+ ""
+ "*
+{
+ REAL_VALUE_TYPE r;
+
+ if (GET_CODE (operands[0]) != CONST_DOUBLE)
+ abort ();
+
+ REAL_VALUE_FROM_CONST_DOUBLE (r, operands[0]);
+ assemble_real (r, DFmode, 8*BITS_PER_UNIT);
+ return \"\";
+}"
+ [(set_attr "op_type" "NN")
+ (set_attr "length" "8")])
+
+(define_insn "pool_start_31"
+ [(unspec_volatile [(const_int 0)] 206)]
+ "!TARGET_64BIT"
+ ".align\\t4"
+ [(set_attr "op_type" "NN")
+ (set_attr "length" "2")])
+
+(define_insn "pool_end_31"
+ [(unspec_volatile [(const_int 0)] 207)]
+ "!TARGET_64BIT"
+ ".align\\t2"
+ [(set_attr "op_type" "NN")
+ (set_attr "length" "2")])
+
+(define_insn "pool_start_64"
+ [(unspec_volatile [(const_int 0)] 206)]
+ "TARGET_64BIT"
+ ".section\\t.rodata\;.align\\t8"
+ [(set_attr "op_type" "NN")
+ (set_attr "length" "0")])
+
+(define_insn "pool_end_64"
+ [(unspec_volatile [(const_int 0)] 207)]
+ "TARGET_64BIT"
+ ".previous"
+ [(set_attr "op_type" "NN")
+ (set_attr "length" "0")])
+
+(define_insn "reload_base"
+ [(set (match_operand:SI 0 "register_operand" "=a")
+ (unspec:SI [(label_ref (match_operand 1 "" ""))] 210))]
+ "!TARGET_64BIT"
+ "basr\\t%0,0\;la\\t%0,%1-.(%0)"
[(set_attr "op_type" "NN")
- (set_attr "type" "other")
- (set_attr "length" "4096")])
+ (set_attr "type" "la")
+ (set_attr "length" "6")])
+
+(define_insn "reload_base2"
+ [(set (match_operand:SI 0 "register_operand" "=a")
+ (unspec:SI [(label_ref (match_operand 1 "" ""))] 211))]
+ "!TARGET_64BIT"
+ "la\\t%0,%1-.(%0)"
+ [(set_attr "op_type" "NN")
+ (set_attr "type" "la")
+ (set_attr "length" "4")])
+
;;
;; Insns related to generating the function prologue and epilogue.