Commit 585539a1 by Ulrich Weigand Committed by Ulrich Weigand

s390-protos.h (s390_load_got): Update prototype.

	* config/s390/s390-protos.h (s390_load_got): Update prototype.
	* config/s390/s390.c (struct machine_function): Add member base_reg.
	(s390_decompose_address): Accept UNSPEC_LTREF.  Simplify logic.
	(s390_split_branches): Annotate late pool references.
	(annotate_constant_pool_refs): New function.
	(find_constant_pool_ref): Work on annotated pool references.
	(replace_constant_pool_ref): Likewise.  Use explicit base.
	(replace_ltrel_base): Use explicit base.
	(s390_mainpool_start): Reflect main_pool pattern change.
	(s390_mainpool_finish): Use base register from main_pool.
	Update calls to replace_ltrel_base and replace_constant_pool_ref.
	(s390_chunkify_start): Use base_reg from struct machine_function.
	(s390_chunkify_finish): Remove base_reg argument.  Update calls
	to replace_ltrel_base and replace_constant_pool_ref.
	(s390_reorg): Don't decide upon base register.  Update calls.
	(s390_load_got): Remove MAYBE_DEAD handling.  Do not emit insns
	but return sequence instead.
	(s390_emit_prologue): Decide upon base register to use.  Annotate
	all literal pool references.  Adapt to main_pool pattern change.
	Update s390_load_got call; move MAYBE_DEAD handling here.
	(s390_emit_epilogue): Annotate late literal pool references.
	Remove barrier before register restore instruction.
	* config/s390/s390.md (UNSPEC_LTREF): New constant.
	("builtin_setjmp_receiver"): Update s390_load_got call.
	("main_pool"): Explicitly reference base register.

From-SVN: r83735
parent 0f6cd83f
2004-06-27 Ulrich Weigand <uweigand@de.ibm.com>
* config/s390/s390-protos.h (s390_load_got): Update prototype.
* config/s390/s390.c (struct machine_function): Add member base_reg.
(s390_decompose_address): Accept UNSPEC_LTREF. Simplify logic.
(s390_split_branches): Annotate late pool references.
(annotate_constant_pool_refs): New function.
(find_constant_pool_ref): Work on annotated pool references.
(replace_constant_pool_ref): Likewise. Use explicit base.
(replace_ltrel_base): Use explicit base.
(s390_mainpool_start): Reflect main_pool pattern change.
(s390_mainpool_finish): Use base register from main_pool.
Update calls to replace_ltrel_base and replace_constant_pool_ref.
(s390_chunkify_start): Use base_reg from struct machine_function.
(s390_chunkify_finish): Remove base_reg argument. Update calls
to replace_ltrel_base and replace_constant_pool_ref.
(s390_reorg): Don't decide upon base register. Update calls.
(s390_load_got): Remove MAYBE_DEAD handling. Do not emit insns
but return sequence instead.
(s390_emit_prologue): Decide upon base register to use. Annotate
all literal pool references. Adapt to main_pool pattern change.
Update s390_load_got call; move MAYBE_DEAD handling here.
(s390_emit_epilogue): Annotate late literal pool references.
Remove barrier before register restore instruction.
* config/s390/s390.md (UNSPEC_LTREF): New constant.
("builtin_setjmp_receiver"): Update s390_load_got call.
("main_pool"): Explicitly reference base register.
2004-06-27 Roger Sayle <roger@eyesopen.com>
* fold-const.c (fold) <BIT_IOR_EXPR>: Optimize ~X|X and X|~X as -1.
......
......@@ -24,7 +24,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
extern void optimization_options (int, int);
extern void override_options (void);
extern HOST_WIDE_INT s390_arg_frame_offset (void);
extern void s390_load_got (int);
extern void s390_emit_prologue (void);
extern void s390_emit_epilogue (bool);
extern void s390_function_profiler (FILE *, int);
......@@ -92,6 +91,7 @@ extern void s390_initialize_trampoline (rtx, rtx, rtx);
extern rtx s390_gen_rtx_const_DI (int, int);
extern void s390_output_dwarf_dtprel (FILE*, int, rtx);
extern int s390_agen_dep_p (rtx, rtx);
extern rtx s390_load_got (void);
#endif /* RTX_CODE */
......
......@@ -217,6 +217,9 @@ struct machine_function GTY(())
/* Size of stack frame. */
HOST_WIDE_INT frame_size;
/* Literal pool base register. */
rtx base_reg;
/* Some local-dynamic TLS symbol name. */
const char *some_ld_name;
};
......@@ -236,10 +239,11 @@ static int get_some_local_dynamic_name_1 (rtx *, void *);
static int reg_used_in_mem_p (int, rtx);
static int addr_generation_dependency_p (rtx, rtx);
static int s390_split_branches (void);
static void annotate_constant_pool_refs (rtx *x);
static void find_constant_pool_ref (rtx, rtx *);
static void replace_constant_pool_ref (rtx *, rtx, rtx);
static rtx find_ltrel_base (rtx);
static void replace_ltrel_base (rtx *, rtx);
static void replace_ltrel_base (rtx *);
static void s390_optimize_prolog (bool);
static int find_unused_clobbered_reg (void);
static void s390_frame_info (int, int);
......@@ -2069,9 +2073,11 @@ s390_expand_plus_operand (register rtx target, register rtx src,
static int
s390_decompose_address (register rtx addr, struct s390_address *out)
{
HOST_WIDE_INT offset = 0;
rtx base = NULL_RTX;
rtx indx = NULL_RTX;
rtx disp = NULL_RTX;
rtx orig_disp;
int pointer = FALSE;
int base_ptr = FALSE;
int indx_ptr = FALSE;
......@@ -2119,15 +2125,68 @@ s390_decompose_address (register rtx addr, struct s390_address *out)
else
disp = addr; /* displacement */
/* Extract integer part of displacement. */
orig_disp = disp;
if (disp)
{
if (GET_CODE (disp) == CONST_INT)
{
offset = INTVAL (disp);
disp = NULL_RTX;
}
else if (GET_CODE (disp) == CONST
&& GET_CODE (XEXP (disp, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (disp, 0), 1)) == CONST_INT)
{
offset = INTVAL (XEXP (XEXP (disp, 0), 1));
disp = XEXP (XEXP (disp, 0), 0);
}
}
/* Strip off CONST here to avoid special case tests later. */
if (disp && GET_CODE (disp) == CONST)
disp = XEXP (disp, 0);
/* We can convert literal pool addresses to
displacements by basing them off the base register. */
if (disp && GET_CODE (disp) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (disp))
{
/* Either base or index must be free to hold the base register. */
if (!base)
base = gen_rtx_REG (Pmode, BASE_REGISTER);
else if (!indx)
indx = gen_rtx_REG (Pmode, BASE_REGISTER);
else
return FALSE;
/* Mark up the displacement. */
disp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, disp),
UNSPEC_LTREL_OFFSET);
}
/* Validate base register. */
if (base)
{
if (GET_CODE (base) == UNSPEC)
switch (XINT (base, 1))
{
if (XVECLEN (base, 0) != 1 || XINT (base, 1) != UNSPEC_LTREL_BASE)
case UNSPEC_LTREF:
if (!disp)
disp = gen_rtx_UNSPEC (Pmode,
gen_rtvec (1, XVECEXP (base, 0, 0)),
UNSPEC_LTREL_OFFSET);
else
return FALSE;
base = gen_rtx_REG (Pmode, BASE_REGISTER);
break;
case UNSPEC_LTREL_BASE:
base = gen_rtx_REG (Pmode, BASE_REGISTER);
break;
default:
return FALSE;
}
if (GET_CODE (base) != REG || GET_MODE (base) != Pmode)
......@@ -2149,10 +2208,25 @@ s390_decompose_address (register rtx addr, struct s390_address *out)
if (indx)
{
if (GET_CODE (indx) == UNSPEC)
switch (XINT (indx, 1))
{
if (XVECLEN (indx, 0) != 1 || XINT (indx, 1) != UNSPEC_LTREL_BASE)
case UNSPEC_LTREF:
if (!disp)
disp = gen_rtx_UNSPEC (Pmode,
gen_rtvec (1, XVECEXP (indx, 0, 0)),
UNSPEC_LTREL_OFFSET);
else
return FALSE;
indx = gen_rtx_REG (Pmode, BASE_REGISTER);
break;
case UNSPEC_LTREL_BASE:
indx = gen_rtx_REG (Pmode, BASE_REGISTER);
break;
default:
return FALSE;
}
if (GET_CODE (indx) != REG || GET_MODE (indx) != Pmode)
......@@ -2180,10 +2254,7 @@ s390_decompose_address (register rtx addr, struct s390_address *out)
}
/* Validate displacement. */
if (disp)
{
/* Allow integer constant in range. */
if (GET_CODE (disp) == CONST_INT)
if (!disp)
{
/* If the argument pointer is involved, the displacement will change
later anyway as the argument pointer gets eliminated. This could
......@@ -2194,92 +2265,52 @@ s390_decompose_address (register rtx addr, struct s390_address *out)
elimination the displacement turns out to be invalid after all,
this is fixed up by reload in any case. */
if (base != arg_pointer_rtx && indx != arg_pointer_rtx)
{
if (!DISP_IN_RANGE (INTVAL (disp)))
if (!DISP_IN_RANGE (offset))
return FALSE;
}
}
/* In the small-PIC case, the linker converts @GOT
and @GOTNTPOFF offsets to possible displacements. */
else if (GET_CODE (disp) == CONST
&& GET_CODE (XEXP (disp, 0)) == UNSPEC
&& (XINT (XEXP (disp, 0), 1) == UNSPEC_GOT
|| XINT (XEXP (disp, 0), 1) == UNSPEC_GOTNTPOFF))
else
{
if (flag_pic != 1)
return FALSE;
/* All the special cases are pointers. */
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)
/* In the small-PIC case, the linker converts @GOT
and @GOTNTPOFF offsets to possible displacements. */
if (GET_CODE (disp) == UNSPEC
&& (XINT (disp, 1) == UNSPEC_GOT
|| XINT (disp, 1) == UNSPEC_GOTNTPOFF)
&& offset == 0
&& flag_pic == 1)
{
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)
/* Accept chunkified literal pool symbol references. */
else if (GET_CODE (disp) == MINUS
&& GET_CODE (XEXP (disp, 0)) == LABEL_REF
&& GET_CODE (XEXP (disp, 1)) == LABEL_REF)
{
pointer = TRUE;
;
}
/* We can convert literal pool addresses to
displacements by basing them off the base register. */
else
/* Accept literal pool references. */
else if (GET_CODE (disp) == UNSPEC
&& XINT (disp, 1) == UNSPEC_LTREL_OFFSET)
{
/* In some cases, we can accept an additional
small constant offset. Split these off here. */
unsigned int offset = 0;
if (GET_CODE (disp) == CONST
&& GET_CODE (XEXP (disp, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (disp, 0), 1)) == CONST_INT)
orig_disp = gen_rtx_CONST (Pmode, disp);
if (offset)
{
offset = INTVAL (XEXP (XEXP (disp, 0), 1));
disp = XEXP (XEXP (disp, 0), 0);
}
/* Now we must have a literal pool address. */
if (GET_CODE (disp) != SYMBOL_REF
|| !CONSTANT_POOL_ADDRESS_P (disp))
return FALSE;
/* If we have an offset, make sure it does not
exceed the size of the constant pool entry. */
if (offset && offset >= GET_MODE_SIZE (get_pool_mode (disp)))
rtx sym = XVECEXP (disp, 0, 0);
if (offset >= GET_MODE_SIZE (get_pool_mode (sym)))
return FALSE;
/* Either base or index must be free to
hold the base register. */
if (base && indx)
return FALSE;
orig_disp = plus_constant (orig_disp, offset);
}
}
/* Convert the address. */
if (base)
indx = gen_rtx_REG (Pmode, BASE_REGISTER);
else
base = gen_rtx_REG (Pmode, BASE_REGISTER);
disp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, disp),
UNSPEC_LTREL_OFFSET);
disp = gen_rtx_CONST (Pmode, disp);
if (offset)
disp = plus_constant (disp, offset);
pointer = TRUE;
}
return FALSE;
}
if (!base && !indx)
......@@ -2289,7 +2320,7 @@ s390_decompose_address (register rtx addr, struct s390_address *out)
{
out->base = base;
out->indx = indx;
out->disp = disp;
out->disp = orig_disp;
out->pointer = pointer;
}
......@@ -4058,6 +4089,7 @@ s390_split_branches (void)
tmp = force_const_mem (Pmode, *label);
tmp = emit_insn_before (gen_rtx_SET (Pmode, temp_reg, tmp), insn);
INSN_ADDRESSES_NEW (tmp, -1);
annotate_constant_pool_refs (&PATTERN (tmp));
target = temp_reg;
}
......@@ -4070,8 +4102,10 @@ s390_split_branches (void)
target = force_const_mem (Pmode, target);
tmp = emit_insn_before (gen_rtx_SET (Pmode, temp_reg, target), insn);
INSN_ADDRESSES_NEW (tmp, -1);
annotate_constant_pool_refs (&PATTERN (tmp));
target = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, XEXP (target, 0)),
target = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, XEXP (target, 0),
cfun->machine->base_reg),
UNSPEC_LTREL_BASE);
target = gen_rtx_PLUS (Pmode, temp_reg, target);
}
......@@ -4083,11 +4117,115 @@ s390_split_branches (void)
return new_literal;
}
/* 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)
{
int i, j;
const char *fmt;
if (GET_CODE (*x) == SYMBOL_REF
&& CONSTANT_POOL_ADDRESS_P (*x))
abort ();
/* Literal pool references can only occur inside a MEM ... */
if (GET_CODE (*x) == MEM)
{
rtx memref = XEXP (*x, 0);
if (GET_CODE (memref) == SYMBOL_REF
&& CONSTANT_POOL_ADDRESS_P (memref))
{
rtx base = cfun->machine->base_reg;
rtx addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, memref, base),
UNSPEC_LTREF);
*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
&& GET_CODE (XEXP (XEXP (memref, 0), 0)) == SYMBOL_REF
&& CONSTANT_POOL_ADDRESS_P (XEXP (XEXP (memref, 0), 0)))
{
HOST_WIDE_INT off = INTVAL (XEXP (XEXP (memref, 0), 1));
rtx sym = XEXP (XEXP (memref, 0), 0);
rtx base = cfun->machine->base_reg;
rtx addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, sym, base),
UNSPEC_LTREF);
*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 (GET_CODE (addrref) == SYMBOL_REF
&& CONSTANT_POOL_ADDRESS_P (addrref))
{
rtx base = cfun->machine->base_reg;
rtx addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, addrref, base),
UNSPEC_LTREF);
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
&& GET_CODE (XEXP (XEXP (addrref, 0), 0)) == SYMBOL_REF
&& CONSTANT_POOL_ADDRESS_P (XEXP (XEXP (addrref, 0), 0)))
{
HOST_WIDE_INT off = INTVAL (XEXP (XEXP (addrref, 0), 1));
rtx sym = XEXP (XEXP (addrref, 0), 0);
rtx base = cfun->machine->base_reg;
rtx addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, sym, base),
UNSPEC_LTREF);
SET_SRC (*x) = plus_constant (addr, off);
return;
}
}
/* Annotate LTREL_BASE as well. */
if (GET_CODE (*x) == UNSPEC
&& XINT (*x, 1) == UNSPEC_LTREL_BASE)
{
rtx base = cfun->machine->base_reg;
*x = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, XVECEXP (*x, 0, 0), base),
UNSPEC_LTREL_BASE);
return;
}
fmt = GET_RTX_FORMAT (GET_CODE (*x));
for (i = GET_RTX_LENGTH (GET_CODE (*x)) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
{
annotate_constant_pool_refs (&XEXP (*x, i));
}
else if (fmt[i] == 'E')
{
for (j = 0; j < XVECLEN (*x, i); j++)
annotate_constant_pool_refs (&XVECEXP (*x, i, j));
}
}
}
/* 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.
/* 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
symbol are allowed, however.
The rtx pointed to by REF must be initialized to NULL_RTX
by the caller before calling this routine. */
......@@ -4109,11 +4247,21 @@ find_constant_pool_ref (rtx x, rtx *ref)
if (GET_CODE (x) == SYMBOL_REF
&& CONSTANT_POOL_ADDRESS_P (x))
abort ();
if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_LTREF)
{
rtx sym = XVECEXP (x, 0, 0);
if (GET_CODE (sym) != SYMBOL_REF
|| !CONSTANT_POOL_ADDRESS_P (sym))
abort ();
if (*ref == NULL_RTX)
*ref = x;
else if (*ref != x)
abort();
*ref = sym;
else if (*ref != sym)
abort ();
return;
}
fmt = GET_RTX_FORMAT (GET_CODE (x));
......@@ -4131,11 +4279,11 @@ find_constant_pool_ref (rtx x, rtx *ref)
}
}
/* Replace every reference to the literal pool symbol REF
in X by the address ADDR. Fix up MEMs as required. */
/* 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 addr)
replace_constant_pool_ref (rtx *x, rtx ref, rtx offset)
{
int i, j;
const char *fmt;
......@@ -4143,61 +4291,36 @@ replace_constant_pool_ref (rtx *x, rtx ref, rtx addr)
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)
if (GET_CODE (*x) == UNSPEC
&& XINT (*x, 1) == UNSPEC_LTREF
&& XVECEXP (*x, 0, 0) == ref)
{
SET_SRC (*x) = addr;
*x = gen_rtx_PLUS (Pmode, XVECEXP (*x, 0, 1), offset);
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)
if (GET_CODE (*x) == PLUS
&& GET_CODE (XEXP (*x, 1)) == CONST_INT
&& GET_CODE (XEXP (*x, 0)) == UNSPEC
&& XINT (XEXP (*x, 0), 1) == UNSPEC_LTREF
&& XVECEXP (XEXP (*x, 0), 0, 0) == ref)
{
HOST_WIDE_INT off = INTVAL (XEXP (XEXP (addrref, 0), 1));
SET_SRC (*x) = plus_constant (addr, off);
rtx addr = gen_rtx_PLUS (Pmode, XVECEXP (XEXP (*x, 0), 0, 1), offset);
*x = plus_constant (addr, INTVAL (XEXP (*x, 1)));
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);
replace_constant_pool_ref (&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, addr);
replace_constant_pool_ref (&XVECEXP (*x, i, j), ref, offset);
}
}
}
......@@ -4238,10 +4361,10 @@ find_ltrel_base (rtx x)
return NULL_RTX;
}
/* Replace any occurrence of UNSPEC_LTREL_BASE in X with BASE. */
/* Replace any occurrence of UNSPEC_LTREL_BASE in X with its base. */
static void
replace_ltrel_base (rtx *x, rtx base)
replace_ltrel_base (rtx *x)
{
int i, j;
const char *fmt;
......@@ -4249,7 +4372,7 @@ replace_ltrel_base (rtx *x, rtx base)
if (GET_CODE (*x) == UNSPEC
&& XINT (*x, 1) == UNSPEC_LTREL_BASE)
{
*x = base;
*x = XVECEXP (*x, 0, 1);
return;
}
......@@ -4258,12 +4381,12 @@ replace_ltrel_base (rtx *x, rtx base)
{
if (fmt[i] == 'e')
{
replace_ltrel_base (&XEXP (*x, i), base);
replace_ltrel_base (&XEXP (*x, i));
}
else if (fmt[i] == 'E')
{
for (j = 0; j < XVECLEN (*x, i); j++)
replace_ltrel_base (&XVECEXP (*x, i, j), base);
replace_ltrel_base (&XVECEXP (*x, i, j));
}
}
}
......@@ -4302,11 +4425,11 @@ struct constant_pool
};
static struct constant_pool * s390_mainpool_start (void);
static void s390_mainpool_finish (struct constant_pool *, rtx base_reg);
static void s390_mainpool_finish (struct constant_pool *);
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 struct constant_pool * s390_chunkify_start (void);
static void s390_chunkify_finish (struct constant_pool *);
static void s390_chunkify_cancel (struct constant_pool *);
static struct constant_pool *s390_start_pool (struct constant_pool **, rtx);
......@@ -4560,8 +4683,9 @@ s390_mainpool_start (void)
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)
&& GET_CODE (PATTERN (insn)) == SET
&& GET_CODE (SET_SRC (PATTERN (insn))) == UNSPEC_VOLATILE
&& XINT (SET_SRC (PATTERN (insn)), 1) == UNSPECV_MAIN_POOL)
{
if (pool->pool_insn)
abort ();
......@@ -4599,12 +4723,12 @@ s390_mainpool_start (void)
/* 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. */
the pool register setup instruction. */
static void
s390_mainpool_finish (struct constant_pool *pool, rtx base_reg)
s390_mainpool_finish (struct constant_pool *pool)
{
rtx base_reg = SET_DEST (PATTERN (pool->pool_insn));
rtx insn;
/* If the pool is empty, we're done. */
......@@ -4684,7 +4808,7 @@ s390_mainpool_finish (struct constant_pool *pool, rtx base_reg)
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
{
if (INSN_P (insn))
replace_ltrel_base (&PATTERN (insn), base_reg);
replace_ltrel_base (&PATTERN (insn));
if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN)
{
......@@ -4694,7 +4818,6 @@ s390_mainpool_finish (struct constant_pool *pool, rtx base_reg)
{
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;
}
......@@ -4718,14 +4841,13 @@ s390_mainpool_cancel (struct constant_pool *pool)
}
/* Chunkify the literal pool. BASE_REG is to be used as pool
register. */
/* Chunkify the literal pool. */
#define S390_POOL_CHUNK_MIN 0xc00
#define S390_POOL_CHUNK_MAX 0xe00
static struct constant_pool *
s390_chunkify_start (rtx base_reg)
s390_chunkify_start (void)
{
struct constant_pool *curr_pool = NULL, *pool_list = NULL;
int extra_size = 0;
......@@ -4952,7 +5074,8 @@ s390_chunkify_start (rtx base_reg)
for (curr_pool = pool_list; curr_pool; curr_pool = curr_pool->next)
{
rtx new_insn = gen_reload_base (base_reg, curr_pool->label);
rtx new_insn = gen_reload_base (cfun->machine->base_reg,
curr_pool->label);
rtx insn = curr_pool->first_insn;
INSN_ADDRESSES_NEW (emit_insn_before (new_insn, insn), -1);
}
......@@ -4966,7 +5089,8 @@ s390_chunkify_start (rtx base_reg)
struct constant_pool *pool = s390_find_pool (pool_list, insn);
if (pool)
{
rtx new_insn = gen_reload_base (base_reg, pool->label);
rtx new_insn = gen_reload_base (cfun->machine->base_reg,
pool->label);
INSN_ADDRESSES_NEW (emit_insn_after (new_insn, insn), -1);
}
}
......@@ -4985,11 +5109,10 @@ s390_chunkify_start (rtx base_reg)
/* POOL_LIST is a chunk list as prepared by s390_chunkify_start.
After we have decided to use this list, finish implementing
all changes to the current function as required. BASE_REG is
to be used as pool base register. */
all changes to the current function as required. */
static void
s390_chunkify_finish (struct constant_pool *pool_list, rtx base_reg)
s390_chunkify_finish (struct constant_pool *pool_list)
{
struct constant_pool *curr_pool = NULL;
rtx insn;
......@@ -5000,7 +5123,7 @@ s390_chunkify_finish (struct constant_pool *pool_list, rtx base_reg)
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
{
if (INSN_P (insn))
replace_ltrel_base (&PATTERN (insn), base_reg);
replace_ltrel_base (&PATTERN (insn));
curr_pool = s390_find_pool (pool_list, insn);
if (!curr_pool)
......@@ -5014,7 +5137,6 @@ s390_chunkify_finish (struct constant_pool *pool_list, rtx base_reg)
{
addr = s390_find_constant (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;
}
......@@ -5273,7 +5395,6 @@ s390_optimize_prolog (bool base_used)
static void
s390_reorg (void)
{
rtx base_reg = gen_rtx_REG (Pmode, BASE_REGISTER);
bool base_used = false;
bool pool_overflow = false;
......@@ -5282,12 +5403,6 @@ s390_reorg (void)
split_all_insns_noflow ();
/* 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.
......@@ -5335,7 +5450,7 @@ s390_reorg (void)
/* If literal pool overflowed, start to chunkify it. */
if (pool_overflow)
pool = s390_chunkify_start (base_reg);
pool = s390_chunkify_start ();
/* Split out-of-range branches. If this has created new
literal pool entries, cancel current chunk list and
......@@ -5354,13 +5469,13 @@ s390_reorg (void)
/* If we made it up to here, both conditions are satisfied.
Finish up literal pool related changes. */
if ((pool_overflow || pool->size > 0)
&& REGNO (base_reg) == BASE_REGISTER)
&& REGNO (cfun->machine->base_reg) == BASE_REGISTER)
base_used = true;
if (pool_overflow)
s390_chunkify_finish (pool, base_reg);
s390_chunkify_finish (pool);
else
s390_mainpool_finish (pool, base_reg);
s390_mainpool_finish (pool);
break;
}
......@@ -5649,49 +5764,47 @@ restore_gprs (rtx base, int offset, int first, int last)
return insn;
}
/* Emit code to load the GOT register. If MAYBE_DEAD is true,
annotate generated insns with REG_MAYBE_DEAD notes. */
/* Return insn sequence to load the GOT register. */
static GTY(()) rtx got_symbol;
void
s390_load_got (int maybe_dead)
rtx
s390_load_got (void)
{
rtx insns;
if (!got_symbol)
{
got_symbol = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
SYMBOL_REF_FLAGS (got_symbol) = SYMBOL_FLAG_LOCAL;
}
start_sequence ();
if (TARGET_CPU_ZARCH)
{
rtx insn = emit_move_insn (pic_offset_table_rtx, got_symbol);
if (maybe_dead)
REG_NOTES(insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, NULL_RTX,
REG_NOTES (insn));
emit_move_insn (pic_offset_table_rtx, got_symbol);
}
else
{
rtx offset, insn;
rtx offset;
offset = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, got_symbol),
UNSPEC_LTREL_OFFSET);
offset = gen_rtx_CONST (Pmode, offset);
offset = force_const_mem (Pmode, offset);
insn = emit_move_insn (pic_offset_table_rtx, offset);
if (maybe_dead)
REG_NOTES(insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, NULL_RTX,
REG_NOTES (insn));
emit_move_insn (pic_offset_table_rtx, offset);
offset = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, XEXP (offset, 0)),
UNSPEC_LTREL_BASE);
offset = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, offset);
insn = emit_move_insn (pic_offset_table_rtx, offset);
if (maybe_dead)
REG_NOTES(insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, NULL_RTX,
REG_NOTES (insn));
emit_move_insn (pic_offset_table_rtx, offset);
}
insns = get_insns ();
end_sequence ();
return insns;
}
/* Expand the prologue into a bunch of separate insns. */
......@@ -5712,6 +5825,17 @@ s390_emit_prologue (void)
|| regs_ever_live[RETURN_REGNUM])
cfun->machine->save_return_addr_p = 1;
/* Decide which register to use as literal pool base. 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])
cfun->machine->base_reg = gen_rtx_REG (Pmode, 5);
else
cfun->machine->base_reg = gen_rtx_REG (Pmode, BASE_REGISTER);
regs_ever_live[REGNO (cfun->machine->base_reg)] = 1;
/* Compute frame info. Note that at this point, we assume the base
register and -on S/390- the return register always need to be saved.
This is done because the usage of these registers might change even
......@@ -5727,6 +5851,17 @@ s390_emit_prologue (void)
|| cfun->machine->save_return_addr_p;
regs_ever_live[STACK_POINTER_REGNUM] = cfun->machine->frame_size > 0;
/* Annotate all constant pool references to let the scheduler know
they implicitly use the base register. */
push_topmost_sequence ();
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
if (INSN_P (insn))
annotate_constant_pool_refs (&PATTERN (insn));
pop_topmost_sequence ();
/* Choose best register to use for temp use within prologue.
See below for why TPF must use the register 1. */
......@@ -5744,7 +5879,7 @@ s390_emit_prologue (void)
/* Dummy insn to mark literal pool slot. */
emit_insn (gen_main_pool ());
emit_insn (gen_main_pool (cfun->machine->base_reg));
/* Save fprs for variable args. */
......@@ -5790,6 +5925,7 @@ s390_emit_prologue (void)
frame_off = force_const_mem (Pmode, frame_off);
insn = emit_insn (gen_add2_insn (stack_pointer_rtx, frame_off));
annotate_constant_pool_refs (&PATTERN (insn));
}
RTX_FRAME_RELATED_P (insn) = 1;
......@@ -5854,7 +5990,19 @@ s390_emit_prologue (void)
/* Set up got pointer, if needed. */
if (flag_pic && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])
s390_load_got(true);
{
rtx insns = s390_load_got ();
for (insn = insns; insn; insn = NEXT_INSN (insn))
{
annotate_constant_pool_refs (&PATTERN (insn));
REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, NULL_RTX,
REG_NOTES (insn));
}
emit_insn (insns);
}
if (TARGET_TPF_PROFILING)
{
......@@ -5965,6 +6113,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));
}
}
......@@ -6044,12 +6193,6 @@ s390_emit_epilogue (bool sibcall)
}
}
/* ??? As references to the base register are not made
explicit in insn RTX code, we have to add a barrier here
to prevent incorrect scheduling. */
emit_insn (gen_blockage());
insn = restore_gprs (frame_pointer, offset,
cfun->machine->first_restore_gpr,
cfun->machine->last_restore_gpr);
......
......@@ -92,6 +92,7 @@
; Literal pool
(UNSPEC_RELOAD_BASE 210)
(UNSPEC_MAIN_BASE 211)
(UNSPEC_LTREF 212)
; TLS relocation specifiers
(UNSPEC_TLSGD 500)
......@@ -7394,7 +7395,7 @@
[(match_operand 0 "" "")]
"flag_pic"
{
s390_load_got (false);
emit_insn (s390_load_got ());
emit_insn (gen_rtx_USE (VOIDmode, pic_offset_table_rtx));
DONE;
})
......@@ -7561,8 +7562,9 @@
(set_attr "type" "larl")])
(define_insn "main_pool"
[(unspec_volatile [(const_int 0)] UNSPECV_MAIN_POOL)]
""
[(set (match_operand 0 "register_operand" "=a")
(unspec_volatile [(const_int 0)] UNSPECV_MAIN_POOL))]
"GET_MODE (operands[0]) == Pmode"
"* abort ();"
[(set_attr "op_type" "NN")])
......
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