s390.c (struct machine_function): Remove member literal_pool_label.
* config/s390/s390.c (struct machine_function): Remove member literal_pool_label. (s390_optimize_prolog): Replace TEMP_REG argument with TEMP_USED and BASE_USED. Do not check get_pool_size (). (general_s_operand): Accept all immediates before reload if ALLOW_IMMEDIATE. If not ALLOW_IMMEDIATE, reject literal pool references. (s390_output_symbolic_const): Remove UNSPEC_LTREL_OFFSET handling. (find_constant_pool_ref): Ignore UNSPECV_POOL_ENTRY insns. (s390_alloc_pool): New function. (s390_new_pool): Call it. (s390_dump_pool): Add REMOTE_LABEL argument. (s390_chunkify_start): Add BASE_REG argument. Do not check get_pool_size (). (s390_chunkify_finish): Add BASE_REG argument. Adapt s390_dump_pool call. (s390_pool_count, s390_nr_constants): Remove. (s390_output_constant_pool): Remove. (s390_mainpool_start): New function. (s390_mainpool_finish): New function. (s390_mainpool_cancel): New function. (s390_reorg): Implement main literal pool handling. (s390_emit_prologue): Emit main_pool placeholder instead of literal_pool_31 / literal_pool_64 insns. * config/s390/s390.h (s390_pool_count, s390_nr_constants): Remove. (ASM_OUTPUT_POOL_PROLOGUE, ASM_OUTPUT_SPECIAL_POOL_ENTRY): Remove. * config/s390/s390.md (UNSPEC_MAIN_BASE): New symbolic constant. ("main_base_31_small", "main_base_31_large"): New insns. ("main_base_64", "main_pool"): New insns. ("literal_pool_31", "literal_pool_64"): Remove. From-SVN: r70853
This commit is contained in:
parent
031b59ce35
commit
5af2f3d3ff
@ -1,3 +1,36 @@
|
|||||||
|
2003-08-27 Ulrich Weigand <uweigand@de.ibm.com>
|
||||||
|
|
||||||
|
* config/s390/s390.c (struct machine_function): Remove member
|
||||||
|
literal_pool_label.
|
||||||
|
(s390_optimize_prolog): Replace TEMP_REG argument with
|
||||||
|
TEMP_USED and BASE_USED. Do not check get_pool_size ().
|
||||||
|
(general_s_operand): Accept all immediates before reload if
|
||||||
|
ALLOW_IMMEDIATE. If not ALLOW_IMMEDIATE, reject literal pool
|
||||||
|
references.
|
||||||
|
(s390_output_symbolic_const): Remove UNSPEC_LTREL_OFFSET handling.
|
||||||
|
(find_constant_pool_ref): Ignore UNSPECV_POOL_ENTRY insns.
|
||||||
|
(s390_alloc_pool): New function.
|
||||||
|
(s390_new_pool): Call it.
|
||||||
|
(s390_dump_pool): Add REMOTE_LABEL argument.
|
||||||
|
(s390_chunkify_start): Add BASE_REG argument. Do not check
|
||||||
|
get_pool_size ().
|
||||||
|
(s390_chunkify_finish): Add BASE_REG argument. Adapt
|
||||||
|
s390_dump_pool call.
|
||||||
|
(s390_pool_count, s390_nr_constants): Remove.
|
||||||
|
(s390_output_constant_pool): Remove.
|
||||||
|
(s390_mainpool_start): New function.
|
||||||
|
(s390_mainpool_finish): New function.
|
||||||
|
(s390_mainpool_cancel): New function.
|
||||||
|
(s390_reorg): Implement main literal pool handling.
|
||||||
|
(s390_emit_prologue): Emit main_pool placeholder instead of
|
||||||
|
literal_pool_31 / literal_pool_64 insns.
|
||||||
|
* config/s390/s390.h (s390_pool_count, s390_nr_constants): Remove.
|
||||||
|
(ASM_OUTPUT_POOL_PROLOGUE, ASM_OUTPUT_SPECIAL_POOL_ENTRY): Remove.
|
||||||
|
* config/s390/s390.md (UNSPEC_MAIN_BASE): New symbolic constant.
|
||||||
|
("main_base_31_small", "main_base_31_large"): New insns.
|
||||||
|
("main_base_64", "main_pool"): New insns.
|
||||||
|
("literal_pool_31", "literal_pool_64"): Remove.
|
||||||
|
|
||||||
2003-08-27 Nathanael Nerode <neroden@gcc.gnu.org>
|
2003-08-27 Nathanael Nerode <neroden@gcc.gnu.org>
|
||||||
|
|
||||||
* fixinc/inclhack.def (ptx_netswap): New disabled fix, ported from
|
* fixinc/inclhack.def (ptx_netswap): New disabled fix, ported from
|
||||||
|
@ -183,9 +183,6 @@ const char *s390_arch_string; /* for -march=<xxx> */
|
|||||||
|
|
||||||
struct machine_function GTY(())
|
struct machine_function GTY(())
|
||||||
{
|
{
|
||||||
/* Label of start of initial literal pool. */
|
|
||||||
rtx literal_pool_label;
|
|
||||||
|
|
||||||
/* Set, if some of the fprs 8-15 need to be saved (64 bit abi). */
|
/* Set, if some of the fprs 8-15 need to be saved (64 bit abi). */
|
||||||
int save_fprs_p;
|
int save_fprs_p;
|
||||||
|
|
||||||
@ -223,7 +220,7 @@ static void find_constant_pool_ref (rtx, rtx *);
|
|||||||
static void replace_constant_pool_ref (rtx *, rtx, rtx);
|
static void replace_constant_pool_ref (rtx *, rtx, rtx);
|
||||||
static rtx find_ltrel_base (rtx);
|
static rtx find_ltrel_base (rtx);
|
||||||
static void replace_ltrel_base (rtx *, rtx);
|
static void replace_ltrel_base (rtx *, rtx);
|
||||||
static void s390_optimize_prolog (int);
|
static void s390_optimize_prolog (bool, bool);
|
||||||
static int find_unused_clobbered_reg (void);
|
static int find_unused_clobbered_reg (void);
|
||||||
static void s390_frame_info (void);
|
static void s390_frame_info (void);
|
||||||
static rtx save_fpr (rtx, int, int);
|
static rtx save_fpr (rtx, int, int);
|
||||||
@ -1139,30 +1136,30 @@ general_s_operand (register rtx op, enum machine_mode mode,
|
|||||||
|
|
||||||
switch (GET_CODE (op))
|
switch (GET_CODE (op))
|
||||||
{
|
{
|
||||||
/* Constants that we are sure will be forced to the
|
/* Constants are OK as s-operand if ALLOW_IMMEDIATE
|
||||||
literal pool in reload are OK as s-operand. Note
|
is true and we are still before reload. */
|
||||||
that we cannot call s390_preferred_reload_class here
|
|
||||||
because it might not be known yet at this point
|
|
||||||
whether the current function is a leaf or not. */
|
|
||||||
case CONST_INT:
|
case CONST_INT:
|
||||||
case CONST_DOUBLE:
|
case CONST_DOUBLE:
|
||||||
if (!allow_immediate || reload_completed)
|
if (!allow_immediate || reload_completed)
|
||||||
break;
|
return 0;
|
||||||
if (!legitimate_reload_constant_p (op))
|
return 1;
|
||||||
return 1;
|
|
||||||
if (!TARGET_64BIT)
|
|
||||||
return 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* Memory operands are OK unless they already use an
|
/* Memory operands are OK unless they already use an
|
||||||
index register. */
|
index register. */
|
||||||
case MEM:
|
case MEM:
|
||||||
if (GET_CODE (XEXP (op, 0)) == ADDRESSOF)
|
if (GET_CODE (XEXP (op, 0)) == ADDRESSOF)
|
||||||
return 1;
|
return 1;
|
||||||
if (s390_decompose_address (XEXP (op, 0), &addr)
|
if (!s390_decompose_address (XEXP (op, 0), &addr))
|
||||||
&& !addr.indx)
|
return 0;
|
||||||
return 1;
|
if (addr.indx)
|
||||||
break;
|
return 0;
|
||||||
|
/* Do not allow literal pool references unless ALLOW_IMMEDIATE
|
||||||
|
is true. This prevents compares between two literal pool
|
||||||
|
entries from being accepted. */
|
||||||
|
if (!allow_immediate
|
||||||
|
&& addr.base && REGNO (addr.base) == BASE_REGISTER)
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -3278,11 +3275,6 @@ s390_output_symbolic_const (FILE *file, rtx x)
|
|||||||
output_operand_lossage ("invalid UNSPEC as operand (1)");
|
output_operand_lossage ("invalid UNSPEC as operand (1)");
|
||||||
switch (XINT (x, 1))
|
switch (XINT (x, 1))
|
||||||
{
|
{
|
||||||
case UNSPEC_LTREL_OFFSET:
|
|
||||||
s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
|
|
||||||
fprintf (file, "-");
|
|
||||||
s390_output_symbolic_const (file, cfun->machine->literal_pool_label);
|
|
||||||
break;
|
|
||||||
case UNSPEC_GOTENT:
|
case UNSPEC_GOTENT:
|
||||||
s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
|
s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
|
||||||
fprintf (file, "@GOTENT");
|
fprintf (file, "@GOTENT");
|
||||||
@ -3876,6 +3868,10 @@ find_constant_pool_ref (rtx x, rtx *ref)
|
|||||||
if (GET_CODE (x) == UNSPEC
|
if (GET_CODE (x) == UNSPEC
|
||||||
&& XINT (x, 1) == UNSPEC_LTREL_BASE)
|
&& XINT (x, 1) == UNSPEC_LTREL_BASE)
|
||||||
return;
|
return;
|
||||||
|
/* Likewise POOL_ENTRY insns. */
|
||||||
|
if (GET_CODE (x) == UNSPEC_VOLATILE
|
||||||
|
&& XINT (x, 1) == UNSPECV_POOL_ENTRY)
|
||||||
|
return;
|
||||||
|
|
||||||
if (GET_CODE (x) == SYMBOL_REF
|
if (GET_CODE (x) == SYMBOL_REF
|
||||||
&& CONSTANT_POOL_ADDRESS_P (x))
|
&& CONSTANT_POOL_ADDRESS_P (x))
|
||||||
@ -4071,8 +4067,12 @@ struct constant_pool
|
|||||||
int size;
|
int size;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct constant_pool * s390_chunkify_start (void);
|
static struct constant_pool * s390_mainpool_start (void);
|
||||||
static void s390_chunkify_finish (struct constant_pool *);
|
static void s390_mainpool_finish (struct constant_pool *, rtx base_reg);
|
||||||
|
static void s390_mainpool_cancel (struct constant_pool *);
|
||||||
|
|
||||||
|
static struct constant_pool * s390_chunkify_start (rtx base_reg);
|
||||||
|
static void s390_chunkify_finish (struct constant_pool *, rtx base_reg);
|
||||||
static void s390_chunkify_cancel (struct constant_pool *);
|
static void s390_chunkify_cancel (struct constant_pool *);
|
||||||
|
|
||||||
static struct constant_pool *s390_start_pool (struct constant_pool **, rtx);
|
static struct constant_pool *s390_start_pool (struct constant_pool **, rtx);
|
||||||
@ -4081,7 +4081,8 @@ static void s390_add_pool_insn (struct constant_pool *, rtx);
|
|||||||
static struct constant_pool *s390_find_pool (struct constant_pool *, rtx);
|
static struct constant_pool *s390_find_pool (struct constant_pool *, rtx);
|
||||||
static void s390_add_constant (struct constant_pool *, rtx, enum machine_mode);
|
static void s390_add_constant (struct constant_pool *, rtx, enum machine_mode);
|
||||||
static rtx s390_find_constant (struct constant_pool *, rtx, enum machine_mode);
|
static rtx s390_find_constant (struct constant_pool *, rtx, enum machine_mode);
|
||||||
static rtx s390_dump_pool (struct constant_pool *);
|
static rtx s390_dump_pool (struct constant_pool *, bool);
|
||||||
|
static struct constant_pool *s390_alloc_pool (void);
|
||||||
static void s390_free_pool (struct constant_pool *);
|
static void s390_free_pool (struct constant_pool *);
|
||||||
|
|
||||||
/* Create new constant pool covering instructions starting at INSN
|
/* Create new constant pool covering instructions starting at INSN
|
||||||
@ -4091,18 +4092,9 @@ static struct constant_pool *
|
|||||||
s390_start_pool (struct constant_pool **pool_list, rtx insn)
|
s390_start_pool (struct constant_pool **pool_list, rtx insn)
|
||||||
{
|
{
|
||||||
struct constant_pool *pool, **prev;
|
struct constant_pool *pool, **prev;
|
||||||
int i;
|
|
||||||
|
|
||||||
pool = (struct constant_pool *) xmalloc (sizeof *pool);
|
pool = s390_alloc_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->first_insn = insn;
|
||||||
pool->pool_insn = NULL_RTX;
|
|
||||||
pool->insns = BITMAP_XMALLOC ();
|
|
||||||
pool->size = 0;
|
|
||||||
|
|
||||||
for (prev = pool_list; *prev; prev = &(*prev)->next)
|
for (prev = pool_list; *prev; prev = &(*prev)->next)
|
||||||
;
|
;
|
||||||
@ -4208,10 +4200,11 @@ s390_find_constant (struct constant_pool *pool, rtx val,
|
|||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Dump out the constants in POOL. */
|
/* Dump out the constants in POOL. If REMOTE_LABEL is true,
|
||||||
|
do not emit the pool base label. */
|
||||||
|
|
||||||
static rtx
|
static rtx
|
||||||
s390_dump_pool (struct constant_pool *pool)
|
s390_dump_pool (struct constant_pool *pool, bool remote_label)
|
||||||
{
|
{
|
||||||
struct constant *c;
|
struct constant *c;
|
||||||
rtx insn;
|
rtx insn;
|
||||||
@ -4225,8 +4218,11 @@ s390_dump_pool (struct constant_pool *pool)
|
|||||||
insn = emit_insn_after (gen_pool_start_31 (), pool->pool_insn);
|
insn = emit_insn_after (gen_pool_start_31 (), pool->pool_insn);
|
||||||
INSN_ADDRESSES_NEW (insn, -1);
|
INSN_ADDRESSES_NEW (insn, -1);
|
||||||
|
|
||||||
insn = emit_label_after (pool->label, insn);
|
if (!remote_label)
|
||||||
INSN_ADDRESSES_NEW (insn, -1);
|
{
|
||||||
|
insn = emit_label_after (pool->label, insn);
|
||||||
|
INSN_ADDRESSES_NEW (insn, -1);
|
||||||
|
}
|
||||||
|
|
||||||
/* Dump constants in descending alignment requirement order,
|
/* Dump constants in descending alignment requirement order,
|
||||||
ensuring proper alignment for every constant. */
|
ensuring proper alignment for every constant. */
|
||||||
@ -4272,6 +4268,28 @@ s390_dump_pool (struct constant_pool *pool)
|
|||||||
return insn;
|
return insn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Allocate new constant_pool structure. */
|
||||||
|
|
||||||
|
static struct constant_pool *
|
||||||
|
s390_alloc_pool (void)
|
||||||
|
{
|
||||||
|
struct constant_pool *pool;
|
||||||
|
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 = NULL_RTX;
|
||||||
|
pool->pool_insn = NULL_RTX;
|
||||||
|
pool->insns = BITMAP_XMALLOC ();
|
||||||
|
pool->size = 0;
|
||||||
|
|
||||||
|
return pool;
|
||||||
|
}
|
||||||
|
|
||||||
/* Free all memory used by POOL. */
|
/* Free all memory used by POOL. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -4295,16 +4313,182 @@ s390_free_pool (struct constant_pool *pool)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Chunkify the literal pool if required. */
|
/* Collect main literal pool. Return NULL on overflow. */
|
||||||
|
|
||||||
|
static struct constant_pool *
|
||||||
|
s390_mainpool_start (void)
|
||||||
|
{
|
||||||
|
struct constant_pool *pool;
|
||||||
|
rtx insn;
|
||||||
|
|
||||||
|
pool = s390_alloc_pool ();
|
||||||
|
|
||||||
|
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
|
||||||
|
{
|
||||||
|
if (GET_CODE (insn) == INSN
|
||||||
|
&& GET_CODE (PATTERN (insn)) == UNSPEC_VOLATILE
|
||||||
|
&& XINT (PATTERN (insn), 1) == UNSPECV_MAIN_POOL)
|
||||||
|
{
|
||||||
|
if (pool->pool_insn)
|
||||||
|
abort ();
|
||||||
|
pool->pool_insn = insn;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN)
|
||||||
|
{
|
||||||
|
rtx pool_ref = NULL_RTX;
|
||||||
|
find_constant_pool_ref (PATTERN (insn), &pool_ref);
|
||||||
|
if (pool_ref)
|
||||||
|
{
|
||||||
|
rtx constant = get_pool_constant (pool_ref);
|
||||||
|
enum machine_mode mode = get_pool_mode (pool_ref);
|
||||||
|
s390_add_constant (pool, constant, mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pool->pool_insn)
|
||||||
|
abort ();
|
||||||
|
|
||||||
|
if (pool->size >= 4096)
|
||||||
|
{
|
||||||
|
s390_free_pool (pool);
|
||||||
|
pool = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pool;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* POOL holds the main literal pool as collected by s390_mainpool_start.
|
||||||
|
Modify the current function to output the pool constants as well as
|
||||||
|
the pool register setup instruction. BASE_REG is the register to
|
||||||
|
be used as pool base register. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
s390_mainpool_finish (struct constant_pool *pool, rtx base_reg)
|
||||||
|
{
|
||||||
|
rtx insn;
|
||||||
|
|
||||||
|
/* If the pool is empty, we're done. */
|
||||||
|
if (pool->size == 0)
|
||||||
|
{
|
||||||
|
remove_insn (pool->pool_insn);
|
||||||
|
s390_free_pool (pool);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We need correct insn addresses. */
|
||||||
|
shorten_branches (get_insns ());
|
||||||
|
|
||||||
|
/* In 64-bit, we use a LARL to load the pool register. The pool is
|
||||||
|
located in the .rodata section, so we emit it after the function. */
|
||||||
|
if (TARGET_64BIT)
|
||||||
|
{
|
||||||
|
insn = gen_main_base_64 (base_reg, pool->label);
|
||||||
|
insn = emit_insn_after (insn, pool->pool_insn);
|
||||||
|
INSN_ADDRESSES_NEW (insn, -1);
|
||||||
|
remove_insn (pool->pool_insn);
|
||||||
|
|
||||||
|
insn = get_last_insn ();
|
||||||
|
pool->pool_insn = emit_insn_after (gen_pool (const0_rtx), insn);
|
||||||
|
INSN_ADDRESSES_NEW (pool->pool_insn, -1);
|
||||||
|
|
||||||
|
s390_dump_pool (pool, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* In 31-bit, if the total size of the function's code plus literal pool
|
||||||
|
does not exceed 4096 bytes, we use BASR to set up a function base
|
||||||
|
pointer, and emit the literal pool at the end of the function. */
|
||||||
|
else if (INSN_ADDRESSES (INSN_UID (get_last_insn ()))
|
||||||
|
+ pool->size + 8 /* alignment slop */ < 4096)
|
||||||
|
{
|
||||||
|
insn = gen_main_base_31_small (base_reg, pool->label);
|
||||||
|
insn = emit_insn_after (insn, pool->pool_insn);
|
||||||
|
INSN_ADDRESSES_NEW (insn, -1);
|
||||||
|
remove_insn (pool->pool_insn);
|
||||||
|
|
||||||
|
insn = emit_label_after (pool->label, insn);
|
||||||
|
INSN_ADDRESSES_NEW (insn, -1);
|
||||||
|
|
||||||
|
insn = get_last_insn ();
|
||||||
|
pool->pool_insn = emit_insn_after (gen_pool (const0_rtx), insn);
|
||||||
|
INSN_ADDRESSES_NEW (pool->pool_insn, -1);
|
||||||
|
|
||||||
|
s390_dump_pool (pool, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise, we emit an inline literal pool and use BASR to branch
|
||||||
|
over it, setting up the pool register at the same time. */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rtx pool_end = gen_label_rtx ();
|
||||||
|
|
||||||
|
insn = gen_main_base_31_large (base_reg, pool->label, pool_end);
|
||||||
|
insn = emit_insn_after (insn, pool->pool_insn);
|
||||||
|
INSN_ADDRESSES_NEW (insn, -1);
|
||||||
|
remove_insn (pool->pool_insn);
|
||||||
|
|
||||||
|
insn = emit_label_after (pool->label, insn);
|
||||||
|
INSN_ADDRESSES_NEW (insn, -1);
|
||||||
|
|
||||||
|
pool->pool_insn = emit_insn_after (gen_pool (const0_rtx), insn);
|
||||||
|
INSN_ADDRESSES_NEW (pool->pool_insn, -1);
|
||||||
|
|
||||||
|
insn = emit_label_after (pool_end, pool->pool_insn);
|
||||||
|
INSN_ADDRESSES_NEW (insn, -1);
|
||||||
|
|
||||||
|
s390_dump_pool (pool, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Replace all literal pool references. */
|
||||||
|
|
||||||
|
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
|
||||||
|
{
|
||||||
|
if (INSN_P (insn))
|
||||||
|
replace_ltrel_base (&PATTERN (insn), base_reg);
|
||||||
|
|
||||||
|
if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN)
|
||||||
|
{
|
||||||
|
rtx addr, pool_ref = NULL_RTX;
|
||||||
|
find_constant_pool_ref (PATTERN (insn), &pool_ref);
|
||||||
|
if (pool_ref)
|
||||||
|
{
|
||||||
|
addr = s390_find_constant (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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Free the pool. */
|
||||||
|
s390_free_pool (pool);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* POOL holds the main literal pool as collected by s390_mainpool_start.
|
||||||
|
We have decided we cannot use this pool, so revert all changes
|
||||||
|
to the current function that were done by s390_mainpool_start. */
|
||||||
|
static void
|
||||||
|
s390_mainpool_cancel (struct constant_pool *pool)
|
||||||
|
{
|
||||||
|
/* We didn't actually change the instruction stream, so simply
|
||||||
|
free the pool memory. */
|
||||||
|
s390_free_pool (pool);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Chunkify the literal pool. BASE_REG is to be used as pool
|
||||||
|
register. */
|
||||||
|
|
||||||
#define S390_POOL_CHUNK_MIN 0xc00
|
#define S390_POOL_CHUNK_MIN 0xc00
|
||||||
#define S390_POOL_CHUNK_MAX 0xe00
|
#define S390_POOL_CHUNK_MAX 0xe00
|
||||||
|
|
||||||
static struct constant_pool *
|
static struct constant_pool *
|
||||||
s390_chunkify_start (void)
|
s390_chunkify_start (rtx base_reg)
|
||||||
{
|
{
|
||||||
rtx base_reg = gen_rtx_REG (Pmode, BASE_REGISTER);
|
|
||||||
|
|
||||||
struct constant_pool *curr_pool = NULL, *pool_list = NULL;
|
struct constant_pool *curr_pool = NULL, *pool_list = NULL;
|
||||||
int extra_size = 0;
|
int extra_size = 0;
|
||||||
bitmap far_labels;
|
bitmap far_labels;
|
||||||
@ -4315,11 +4499,6 @@ s390_chunkify_start (void)
|
|||||||
TARGET_64BIT? gen_reload_base_64 : gen_reload_base_31;
|
TARGET_64BIT? gen_reload_base_64 : gen_reload_base_31;
|
||||||
|
|
||||||
|
|
||||||
/* Do we need to chunkify the literal pool? */
|
|
||||||
|
|
||||||
if (get_pool_size () < S390_POOL_CHUNK_MAX)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* We need correct insn addresses. */
|
/* We need correct insn addresses. */
|
||||||
|
|
||||||
shorten_branches (get_insns ());
|
shorten_branches (get_insns ());
|
||||||
@ -4568,12 +4747,12 @@ s390_chunkify_start (void)
|
|||||||
|
|
||||||
/* POOL_LIST is a chunk list as prepared by s390_chunkify_start.
|
/* POOL_LIST is a chunk list as prepared by s390_chunkify_start.
|
||||||
After we have decided to use this list, finish implementing
|
After we have decided to use this list, finish implementing
|
||||||
all changes to the current function as required. */
|
all changes to the current function as required. BASE_REG is
|
||||||
|
to be used as pool base register. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
s390_chunkify_finish (struct constant_pool *pool_list)
|
s390_chunkify_finish (struct constant_pool *pool_list, rtx base_reg)
|
||||||
{
|
{
|
||||||
rtx base_reg = gen_rtx_REG (Pmode, BASE_REGISTER);
|
|
||||||
struct constant_pool *curr_pool = NULL;
|
struct constant_pool *curr_pool = NULL;
|
||||||
rtx insn;
|
rtx insn;
|
||||||
|
|
||||||
@ -4607,7 +4786,7 @@ s390_chunkify_finish (struct constant_pool *pool_list)
|
|||||||
/* Dump out all literal pools. */
|
/* Dump out all literal pools. */
|
||||||
|
|
||||||
for (curr_pool = pool_list; curr_pool; curr_pool = curr_pool->next)
|
for (curr_pool = pool_list; curr_pool; curr_pool = curr_pool->next)
|
||||||
s390_dump_pool (curr_pool);
|
s390_dump_pool (curr_pool, 0);
|
||||||
|
|
||||||
/* Free pool list. */
|
/* Free pool list. */
|
||||||
|
|
||||||
@ -4680,45 +4859,6 @@ s390_chunkify_cancel (struct constant_pool *pool_list)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* 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
|
|
||||||
s390_output_constant_pool (rtx start_label, rtx end_label)
|
|
||||||
{
|
|
||||||
if (TARGET_64BIT)
|
|
||||||
{
|
|
||||||
readonly_data_section ();
|
|
||||||
ASM_OUTPUT_ALIGN (asm_out_file, 3);
|
|
||||||
targetm.asm_out.internal_label (asm_out_file, "L",
|
|
||||||
CODE_LABEL_NUMBER (start_label));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
targetm.asm_out.internal_label (asm_out_file, "L",
|
|
||||||
CODE_LABEL_NUMBER (start_label));
|
|
||||||
ASM_OUTPUT_ALIGN (asm_out_file, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
s390_pool_count = 0;
|
|
||||||
output_constant_pool (current_function_name, current_function_decl);
|
|
||||||
s390_pool_count = -1;
|
|
||||||
if (TARGET_64BIT)
|
|
||||||
function_section (current_function_decl);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ASM_OUTPUT_ALIGN (asm_out_file, 1);
|
|
||||||
targetm.asm_out.internal_label (asm_out_file, "L",
|
|
||||||
CODE_LABEL_NUMBER (end_label));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Output to FILE the constant pool entry EXP in mode MODE
|
/* Output to FILE the constant pool entry EXP in mode MODE
|
||||||
with alignment ALIGN. */
|
with alignment ALIGN. */
|
||||||
|
|
||||||
@ -4760,29 +4900,23 @@ s390_output_pool_entry (FILE *file, rtx exp, enum machine_mode mode,
|
|||||||
|
|
||||||
|
|
||||||
/* Rework the prolog/epilog to avoid saving/restoring
|
/* Rework the prolog/epilog to avoid saving/restoring
|
||||||
registers unnecessarily. If TEMP_REGNO is nonnegative,
|
registers unnecessarily. BASE_USED specifies whether
|
||||||
it specifies the number of a caller-saved register used
|
the literal pool base register needs to be saved,
|
||||||
as temporary scratch register by code emitted during
|
TEMP_USED specifies whether the return register needs
|
||||||
machine dependent reorg. */
|
to be saved. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
s390_optimize_prolog (int temp_regno)
|
s390_optimize_prolog (bool base_used, bool temp_used)
|
||||||
{
|
{
|
||||||
int save_first, save_last, restore_first, restore_last;
|
int save_first, save_last, restore_first, restore_last;
|
||||||
int i, j;
|
int i, j;
|
||||||
rtx insn, new_insn, next_insn;
|
rtx insn, new_insn, next_insn;
|
||||||
|
|
||||||
/* Recompute regs_ever_live data for special registers. */
|
/* Recompute regs_ever_live data for special registers. */
|
||||||
regs_ever_live[BASE_REGISTER] = 0;
|
regs_ever_live[BASE_REGISTER] = base_used;
|
||||||
regs_ever_live[RETURN_REGNUM] = 0;
|
regs_ever_live[RETURN_REGNUM] = temp_used;
|
||||||
regs_ever_live[STACK_POINTER_REGNUM] = cfun->machine->frame_size > 0;
|
regs_ever_live[STACK_POINTER_REGNUM] = cfun->machine->frame_size > 0;
|
||||||
|
|
||||||
/* If there is (possibly) any pool entry, we need to
|
|
||||||
load the base register.
|
|
||||||
??? FIXME: this should be more precise. */
|
|
||||||
if (get_pool_size ())
|
|
||||||
regs_ever_live[BASE_REGISTER] = 1;
|
|
||||||
|
|
||||||
/* In non-leaf functions, the prolog/epilog code relies
|
/* In non-leaf functions, the prolog/epilog code relies
|
||||||
on RETURN_REGNUM being saved in any case. We also need
|
on RETURN_REGNUM being saved in any case. We also need
|
||||||
to save the return register if __builtin_return_address (0)
|
to save the return register if __builtin_return_address (0)
|
||||||
@ -4791,10 +4925,6 @@ s390_optimize_prolog (int temp_regno)
|
|||||||
|| cfun->machine->save_return_addr_p)
|
|| cfun->machine->save_return_addr_p)
|
||||||
regs_ever_live[RETURN_REGNUM] = 1;
|
regs_ever_live[RETURN_REGNUM] = 1;
|
||||||
|
|
||||||
/* We need to save/restore the temporary register. */
|
|
||||||
if (temp_regno >= 0)
|
|
||||||
regs_ever_live[temp_regno] = 1;
|
|
||||||
|
|
||||||
|
|
||||||
/* Find first and last gpr to be saved. */
|
/* Find first and last gpr to be saved. */
|
||||||
|
|
||||||
@ -4919,14 +5049,27 @@ static void
|
|||||||
s390_reorg (void)
|
s390_reorg (void)
|
||||||
{
|
{
|
||||||
rtx temp_reg = gen_rtx_REG (Pmode, RETURN_REGNUM);
|
rtx temp_reg = gen_rtx_REG (Pmode, RETURN_REGNUM);
|
||||||
bool temp_used = 0;
|
rtx base_reg = gen_rtx_REG (Pmode, BASE_REGISTER);
|
||||||
|
bool temp_used = false;
|
||||||
|
bool base_used = false;
|
||||||
|
bool pool_overflow = false;
|
||||||
|
|
||||||
/* Make sure all splits have been performed; splits after
|
/* Make sure all splits have been performed; splits after
|
||||||
machine_dependent_reorg might confuse insn length counts. */
|
machine_dependent_reorg might confuse insn length counts. */
|
||||||
split_all_insns_noflow ();
|
split_all_insns_noflow ();
|
||||||
|
|
||||||
|
|
||||||
/* There are two problematic situations we need to correct:
|
/* In small leaf functions, try to use an unused call-clobbered
|
||||||
|
register as base register to avoid save/restore overhead. */
|
||||||
|
if (current_function_is_leaf && !regs_ever_live[5])
|
||||||
|
base_reg = gen_rtx_REG (Pmode, 5);
|
||||||
|
|
||||||
|
|
||||||
|
/* Install the main literal pool and the associated base
|
||||||
|
register load insns.
|
||||||
|
|
||||||
|
In addition, there are two problematic situations we need
|
||||||
|
to correct:
|
||||||
|
|
||||||
- the literal pool might be > 4096 bytes in size, so that
|
- the literal pool might be > 4096 bytes in size, so that
|
||||||
some of its elements cannot be directly accessed
|
some of its elements cannot be directly accessed
|
||||||
@ -4957,31 +5100,48 @@ s390_reorg (void)
|
|||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
struct constant_pool *pool_list;
|
struct constant_pool *pool = NULL;
|
||||||
|
|
||||||
/* Try to chunkify the literal pool. */
|
/* Collect the literal pool. */
|
||||||
pool_list = s390_chunkify_start ();
|
if (!pool_overflow)
|
||||||
|
{
|
||||||
|
pool = s390_mainpool_start ();
|
||||||
|
if (!pool)
|
||||||
|
pool_overflow = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If literal pool overflowed, start to chunkify it. */
|
||||||
|
if (pool_overflow)
|
||||||
|
pool = s390_chunkify_start (base_reg);
|
||||||
|
|
||||||
/* Split out-of-range branches. If this has created new
|
/* Split out-of-range branches. If this has created new
|
||||||
literal pool entries, cancel current chunk list and
|
literal pool entries, cancel current chunk list and
|
||||||
recompute it. */
|
recompute it. */
|
||||||
if (s390_split_branches (temp_reg, &temp_used))
|
if (s390_split_branches (temp_reg, &temp_used))
|
||||||
{
|
{
|
||||||
if (pool_list)
|
if (pool_overflow)
|
||||||
s390_chunkify_cancel (pool_list);
|
s390_chunkify_cancel (pool);
|
||||||
|
else
|
||||||
|
s390_mainpool_cancel (pool);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we made it up to here, both conditions are satisfied.
|
/* If we made it up to here, both conditions are satisfied.
|
||||||
Finish up pool chunkification if required. */
|
Finish up literal pool related changes. */
|
||||||
if (pool_list)
|
if ((pool_overflow || pool->size > 0)
|
||||||
s390_chunkify_finish (pool_list);
|
&& REGNO (base_reg) == BASE_REGISTER)
|
||||||
|
base_used = true;
|
||||||
|
|
||||||
|
if (pool_overflow)
|
||||||
|
s390_chunkify_finish (pool, base_reg);
|
||||||
|
else
|
||||||
|
s390_mainpool_finish (pool, base_reg);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
s390_optimize_prolog (temp_used? RETURN_REGNUM : -1);
|
s390_optimize_prolog (base_used, temp_used);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -5305,7 +5465,6 @@ s390_emit_prologue (void)
|
|||||||
{
|
{
|
||||||
rtx insn, addr;
|
rtx insn, addr;
|
||||||
rtx temp_reg;
|
rtx temp_reg;
|
||||||
rtx pool_start_label, pool_end_label;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* Compute frame_info. */
|
/* Compute frame_info. */
|
||||||
@ -5327,18 +5486,9 @@ s390_emit_prologue (void)
|
|||||||
cfun->machine->first_save_gpr, cfun->machine->last_save_gpr);
|
cfun->machine->first_save_gpr, cfun->machine->last_save_gpr);
|
||||||
emit_insn (insn);
|
emit_insn (insn);
|
||||||
|
|
||||||
/* Dump constant pool and set constant pool register. */
|
/* Dummy insn to mark literal pool slot. */
|
||||||
|
|
||||||
pool_start_label = gen_label_rtx();
|
emit_insn (gen_main_pool ());
|
||||||
pool_end_label = gen_label_rtx();
|
|
||||||
cfun->machine->literal_pool_label = pool_start_label;
|
|
||||||
|
|
||||||
if (TARGET_64BIT)
|
|
||||||
insn = emit_insn (gen_literal_pool_64 (gen_rtx_REG (Pmode, BASE_REGISTER),
|
|
||||||
pool_start_label, pool_end_label));
|
|
||||||
else
|
|
||||||
insn = emit_insn (gen_literal_pool_31 (gen_rtx_REG (Pmode, BASE_REGISTER),
|
|
||||||
pool_start_label, pool_end_label));
|
|
||||||
|
|
||||||
/* Save fprs for variable args. */
|
/* Save fprs for variable args. */
|
||||||
|
|
||||||
|
@ -1012,35 +1012,6 @@ do { \
|
|||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
/* Constant Pool for all symbols operands which are changed with
|
|
||||||
force_const_mem during insn generation (expand_insn). */
|
|
||||||
|
|
||||||
extern int s390_pool_count;
|
|
||||||
extern int s390_nr_constants;
|
|
||||||
|
|
||||||
#define ASM_OUTPUT_POOL_PROLOGUE(FILE, FUNNAME, fndecl, size) \
|
|
||||||
{ \
|
|
||||||
struct pool_constant *pool; \
|
|
||||||
\
|
|
||||||
if (s390_pool_count == -1) \
|
|
||||||
{ \
|
|
||||||
s390_nr_constants = 0; \
|
|
||||||
for (pool = first_pool; pool; pool = pool->next) \
|
|
||||||
if (pool->mark) s390_nr_constants++; \
|
|
||||||
return; \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define ASM_OUTPUT_SPECIAL_POOL_ENTRY(FILE, EXP, MODE, ALIGN, LABELNO, WIN) \
|
|
||||||
{ \
|
|
||||||
fprintf (FILE, ".LC%d:\n", LABELNO); \
|
|
||||||
s390_output_pool_entry (FILE, EXP, MODE, ALIGN); \
|
|
||||||
if (GET_MODE_SIZE (MODE) == 1) \
|
|
||||||
ASM_OUTPUT_SKIP ((FILE), (unsigned HOST_WIDE_INT)1); \
|
|
||||||
goto WIN; \
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Miscellaneous parameters. */
|
/* Miscellaneous parameters. */
|
||||||
|
|
||||||
/* Define the codes that are matched by predicates in aux-output.c. */
|
/* Define the codes that are matched by predicates in aux-output.c. */
|
||||||
|
@ -65,6 +65,7 @@
|
|||||||
|
|
||||||
; Literal pool
|
; Literal pool
|
||||||
(UNSPEC_RELOAD_BASE 210)
|
(UNSPEC_RELOAD_BASE 210)
|
||||||
|
(UNSPEC_MAIN_BASE 211)
|
||||||
|
|
||||||
; TLS relocation specifiers
|
; TLS relocation specifiers
|
||||||
(UNSPEC_TLSGD 500)
|
(UNSPEC_TLSGD 500)
|
||||||
@ -7232,6 +7233,36 @@
|
|||||||
[(set_attr "op_type" "NN")
|
[(set_attr "op_type" "NN")
|
||||||
(set_attr "length" "0")])
|
(set_attr "length" "0")])
|
||||||
|
|
||||||
|
(define_insn "main_base_31_small"
|
||||||
|
[(set (match_operand:SI 0 "register_operand" "=a")
|
||||||
|
(unspec:SI [(label_ref (match_operand 1 "" ""))] UNSPEC_MAIN_BASE))]
|
||||||
|
"!TARGET_64BIT"
|
||||||
|
"basr\t%0,0"
|
||||||
|
[(set_attr "op_type" "RR")
|
||||||
|
(set_attr "type" "la")])
|
||||||
|
|
||||||
|
(define_insn "main_base_31_large"
|
||||||
|
[(set (match_operand:SI 0 "register_operand" "=a")
|
||||||
|
(unspec:SI [(label_ref (match_operand 1 "" ""))] UNSPEC_MAIN_BASE))
|
||||||
|
(set (pc) (label_ref (match_operand 2 "" "")))]
|
||||||
|
"!TARGET_64BIT"
|
||||||
|
"bras\t%0,%2"
|
||||||
|
[(set_attr "op_type" "RI")])
|
||||||
|
|
||||||
|
(define_insn "main_base_64"
|
||||||
|
[(set (match_operand:DI 0 "register_operand" "=a")
|
||||||
|
(unspec:DI [(label_ref (match_operand 1 "" ""))] UNSPEC_MAIN_BASE))]
|
||||||
|
"TARGET_64BIT"
|
||||||
|
"larl\t%0,%1"
|
||||||
|
[(set_attr "op_type" "RIL")
|
||||||
|
(set_attr "type" "larl")])
|
||||||
|
|
||||||
|
(define_insn "main_pool"
|
||||||
|
[(unspec_volatile [(const_int 0)] UNSPECV_MAIN_POOL)]
|
||||||
|
""
|
||||||
|
"* abort ();"
|
||||||
|
[(set_attr "op_type" "NN")])
|
||||||
|
|
||||||
(define_insn "reload_base_31"
|
(define_insn "reload_base_31"
|
||||||
[(set (match_operand:SI 0 "register_operand" "=a")
|
[(set (match_operand:SI 0 "register_operand" "=a")
|
||||||
(unspec:SI [(label_ref (match_operand 1 "" ""))] UNSPEC_RELOAD_BASE))]
|
(unspec:SI [(label_ref (match_operand 1 "" ""))] UNSPEC_RELOAD_BASE))]
|
||||||
@ -7290,42 +7321,6 @@
|
|||||||
(set_attr "type" "jsr")
|
(set_attr "type" "jsr")
|
||||||
(set_attr "atype" "agen")])
|
(set_attr "atype" "agen")])
|
||||||
|
|
||||||
(define_insn "literal_pool_31"
|
|
||||||
[(unspec_volatile [(const_int 0)] UNSPECV_MAIN_POOL)
|
|
||||||
(set (match_operand:SI 0 "register_operand" "=a")
|
|
||||||
(label_ref (match_operand 1 "" "")))
|
|
||||||
(use (label_ref (match_operand 2 "" "")))]
|
|
||||||
""
|
|
||||||
{
|
|
||||||
if (s390_nr_constants)
|
|
||||||
{
|
|
||||||
output_asm_insn ("bras\t%0,%2", operands);
|
|
||||||
s390_output_constant_pool (operands[1], operands[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
[(set_attr "op_type" "NN")
|
|
||||||
(set_attr "type" "larl")])
|
|
||||||
|
|
||||||
(define_insn "literal_pool_64"
|
|
||||||
[(unspec_volatile [(const_int 0)] UNSPECV_MAIN_POOL)
|
|
||||||
(set (match_operand:DI 0 "register_operand" "=a")
|
|
||||||
(label_ref (match_operand 1 "" "")))
|
|
||||||
(use (label_ref (match_operand 2 "" "")))]
|
|
||||||
""
|
|
||||||
{
|
|
||||||
if (s390_nr_constants)
|
|
||||||
{
|
|
||||||
output_asm_insn ("larl\t%0,%1", operands);
|
|
||||||
s390_output_constant_pool (operands[1], operands[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
[(set_attr "op_type" "NN")
|
|
||||||
(set_attr "type" "larl")])
|
|
||||||
|
|
||||||
;; Instruction definition to extend a 31-bit pointer into a 64-bit
|
;; Instruction definition to extend a 31-bit pointer into a 64-bit
|
||||||
;; pointer. This is used for compatability.
|
;; pointer. This is used for compatability.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user