re PR target/21623 (ICE in reload_cse_simplify_operands, at postreload.c:391)

PR target/21623:

	* regclass.c (FORBIDDEN_INC_DEC_CLASSES): Remove
	SECONDARY_INPUT_RELOAD_CLASS and SECONDARY_OUTPUT_RELOAD_CLASS tests.
	(init_fake_stack_mems): Remove HAVE_SECONDARY_RELOADS test.
	(memory_move_secondary_cost, init_reg_autoinc): Remove
	SECONDARY_INPUT_RELOAD_CLASS / SECONDARY_OUTPUT_RELOAD_CLASS tests.
	Replace SECONDARY_{IN,OUT}PUT_RELOAD_CLASS use with
	secondary_reload_class call.
	(copy_cost): Likewise.  Add new parameter prev_sri.  Changed all
	callers.
	* reload.c (entire file): Remove HAVE_SECONDARY_RELOADS checks.
	(push_secondary_reload): Use secondary_reload target hook.
	(secondary_reload_class, scratch_reload_class): New functions.
	(push_reload): Remove SECONDARY_INPUT_RELOAD_CLASS and
	SECONDARY_OUTPUT_RELOAD_CLASS tests.  Replace
	SECONDARY_{IN,OUT}PUT_RELOAD_CLASS use with secondary_reload_class call.
	* reload.h (HAVE_SECONDARY_RELOADS): Don't define nor test.
	(secondary_reload_class, scratch_reload_class): Declare.
	* reload1.c: Include target.h.
	(reload_adjust_reg_for_temp): New function.
	(reload_adjust_reg_for_icode): Likewise.
	(choose_reload_regs): Remove SECONDARY_INPUT_RELOAD_CLASS test.
	Replace SECONDARY_INPUT_RELOAD_CLASS use with secondary_reload_class
	call.
	(emit_input_reload_insns): Likewise.  Rewrite secondary reload checks
	for inheritance.  Support case when both secondary & tertiary reloads
	are for intermediate registers.
	(emit_output_reload_insns): Replace SECONDARY_OUTPUT_RELOAD_CLASS use
        with secondary_reload_class call.  Support case when both secondary
	& tertiary reloads are for intermediate registers.
	* target-def.h (TARGET_SECONDARY_RELOAD): Provide default definition.
	(TARGET_INITIALIZER) Add TARGET_SECONDARY_RELOAD.
	* target.h (secondary_reload_info): New struct / typedef.
	(struct gcc_target): New member secondary_reload.
	* targhooks.c Include reload.h, optabs.h and recog.h.
	(default_secondary_reload): New function.
	* targhooks.h (default_secondary_reload): Declare.
	* doc/tm.texi: Document secondary_reload target hook.  Update
	description of SECONDARY_*RELOAD_CLASS and reload_{in,out}<mode>.
	* doc/md.texi: Likewise.

	* sh-protos.h (sh_secondary_reload): Declare.
	* sh.c (TARGET_SECONDARY_RELOAD): Override.
	(sh_secondary_reload): New function.
	* sh.h (SECONDARY_INOUT_RELOAD_CLASS): Don't define.
	(SECONDARY_OUTPUT_RELOAD_CLASS): Likewise.
	(SECONDARY_INPUT_RELOAD_CLASS): Likewise.
	(HAVE_SECONDARY_RELOADS): Define.
	* sh.md (reload_indf): Rename to:
	(reload_indf__frn).
	(reload_outdf): Rename to:
	(reload_outdf__RnFRm).
	(reload_insf): Rename to:
	(reload_insf__frn).
	(reload_insi): Rename to:
	(reload_insi__i_fpul).

From-SVN: r107468
This commit is contained in:
J"orn Rennecke 2005-11-24 18:55:53 +00:00 committed by Joern Rennecke
parent 1a598a979b
commit 8a99f6f92f
16 changed files with 693 additions and 322 deletions

View File

@ -1,3 +1,62 @@
2005-11-24 J"orn Rennecke <joern.rennecke@st.com>
PR target/21623:
* regclass.c (FORBIDDEN_INC_DEC_CLASSES): Remove
SECONDARY_INPUT_RELOAD_CLASS and SECONDARY_OUTPUT_RELOAD_CLASS tests.
(init_fake_stack_mems): Remove HAVE_SECONDARY_RELOADS test.
(memory_move_secondary_cost, init_reg_autoinc): Remove
SECONDARY_INPUT_RELOAD_CLASS / SECONDARY_OUTPUT_RELOAD_CLASS tests.
Replace SECONDARY_{IN,OUT}PUT_RELOAD_CLASS use with
secondary_reload_class call.
(copy_cost): Likewise. Add new parameter prev_sri. Changed all
callers.
* reload.c (entire file): Remove HAVE_SECONDARY_RELOADS checks.
(push_secondary_reload): Use secondary_reload target hook.
(secondary_reload_class, scratch_reload_class): New functions.
(push_reload): Remove SECONDARY_INPUT_RELOAD_CLASS and
SECONDARY_OUTPUT_RELOAD_CLASS tests. Replace
SECONDARY_{IN,OUT}PUT_RELOAD_CLASS use with secondary_reload_class call.
* reload.h (HAVE_SECONDARY_RELOADS): Don't define nor test.
(secondary_reload_class, scratch_reload_class): Declare.
* reload1.c: Include target.h.
(reload_adjust_reg_for_temp): New function.
(reload_adjust_reg_for_icode): Likewise.
(choose_reload_regs): Remove SECONDARY_INPUT_RELOAD_CLASS test.
Replace SECONDARY_INPUT_RELOAD_CLASS use with secondary_reload_class
call.
(emit_input_reload_insns): Likewise. Rewrite secondary reload checks
for inheritance. Support case when both secondary & tertiary reloads
are for intermediate registers.
(emit_output_reload_insns): Replace SECONDARY_OUTPUT_RELOAD_CLASS use
with secondary_reload_class call. Support case when both secondary
& tertiary reloads are for intermediate registers.
* target-def.h (TARGET_SECONDARY_RELOAD): Provide default definition.
(TARGET_INITIALIZER) Add TARGET_SECONDARY_RELOAD.
* target.h (secondary_reload_info): New struct / typedef.
(struct gcc_target): New member secondary_reload.
* targhooks.c Include reload.h, optabs.h and recog.h.
(default_secondary_reload): New function.
* targhooks.h (default_secondary_reload): Declare.
* doc/tm.texi: Document secondary_reload target hook. Update
description of SECONDARY_*RELOAD_CLASS and reload_{in,out}<mode>.
* doc/md.texi: Likewise.
* sh-protos.h (sh_secondary_reload): Declare.
* sh.c (TARGET_SECONDARY_RELOAD): Override.
(sh_secondary_reload): New function.
* sh.h (SECONDARY_INOUT_RELOAD_CLASS): Don't define.
(SECONDARY_OUTPUT_RELOAD_CLASS): Likewise.
(SECONDARY_INPUT_RELOAD_CLASS): Likewise.
(HAVE_SECONDARY_RELOADS): Define.
* sh.md (reload_indf): Rename to:
(reload_indf__frn).
(reload_outdf): Rename to:
(reload_outdf__RnFRm).
(reload_insf): Rename to:
(reload_insf__frn).
(reload_insi): Rename to:
(reload_insi__i_fpul).
2005-11-24 Uros Bizjak <uros@kss-loka.si>
* configure.ac: Require at least texinfo 4.4.

View File

@ -165,6 +165,10 @@ extern int shmedia_cleanup_truncate (rtx *, void *);
extern int sh_contains_memref_p (rtx);
extern rtx shmedia_prepare_call_address (rtx fnaddr, int is_sibcall);
struct secondary_reload_info;
extern enum reg_class sh_secondary_reload (bool, rtx, enum reg_class,
enum machine_mode,
struct secondary_reload_info *);
#endif /* ! GCC_SH_PROTOS_H */

View File

@ -500,6 +500,9 @@ static int hard_regs_intersect_p (HARD_REG_SET *, HARD_REG_SET *);
#define TARGET_ADJUST_UNROLL_MAX sh_adjust_unroll_max
#endif
#undef TARGET_SECONDARY_RELOAD
#define TARGET_SECONDARY_RELOAD sh_secondary_reload
struct gcc_target targetm = TARGET_INITIALIZER;
/* Implement TARGET_HANDLE_OPTION. */
@ -10672,6 +10675,106 @@ shmedia_prepare_call_address (rtx fnaddr, int is_sibcall)
return fnaddr;
}
enum reg_class
sh_secondary_reload (bool in_p, rtx x, enum reg_class class,
enum machine_mode mode, secondary_reload_info *sri)
{
if (in_p)
{
if (REGCLASS_HAS_FP_REG (class)
&& ! TARGET_SHMEDIA
&& immediate_operand ((x), mode)
&& ! ((fp_zero_operand (x) || fp_one_operand (x))
&& mode == SFmode && fldi_ok ()))
switch (mode)
{
case SFmode:
sri->icode = CODE_FOR_reload_insf__frn;
return NO_REGS;
case DFmode:
sri->icode = CODE_FOR_reload_indf__frn;
return NO_REGS;
case SImode:
/* ??? If we knew that we are in the appropriate mode -
single precision - we could use a reload pattern directly. */
return FPUL_REGS;
default:
abort ();
}
if (class == FPUL_REGS
&& ((GET_CODE (x) == REG
&& (REGNO (x) == MACL_REG || REGNO (x) == MACH_REG
|| REGNO (x) == T_REG))
|| GET_CODE (x) == PLUS))
return GENERAL_REGS;
if (class == FPUL_REGS && immediate_operand (x, mode))
{
if (GET_CODE (x) == CONST_INT && CONST_OK_FOR_I08 (INTVAL (x)))
return GENERAL_REGS;
sri->icode = CODE_FOR_reload_insi__i_fpul;
return NO_REGS;
}
if (class == FPSCR_REGS
&& ((GET_CODE (x) == REG && REGNO (x) >= FIRST_PSEUDO_REGISTER)
|| (GET_CODE (x) == MEM && GET_CODE (XEXP (x, 0)) == PLUS)))
return GENERAL_REGS;
if (REGCLASS_HAS_FP_REG (class)
&& TARGET_SHMEDIA
&& immediate_operand (x, mode)
&& x != CONST0_RTX (GET_MODE (x))
&& GET_MODE (x) != V4SFmode)
return GENERAL_REGS;
if ((mode == QImode || mode == HImode)
&& TARGET_SHMEDIA && inqhi_operand (x, mode))
{
sri->icode = ((mode == QImode)
? CODE_FOR_reload_inqi : CODE_FOR_reload_inhi);
return NO_REGS;
}
if (TARGET_SHMEDIA && class == GENERAL_REGS
&& (GET_CODE (x) == LABEL_REF || PIC_DIRECT_ADDR_P (x)))
return TARGET_REGS;
} /* end of input-only processing. */
if (((REGCLASS_HAS_FP_REG (class)
&& (GET_CODE (x) == REG
&& (GENERAL_OR_AP_REGISTER_P (REGNO (x))
|| (FP_REGISTER_P (REGNO (x)) && mode == SImode
&& TARGET_FMOVD))))
|| (REGCLASS_HAS_GENERAL_REG (class)
&& GET_CODE (x) == REG
&& FP_REGISTER_P (REGNO (x))))
&& ! TARGET_SHMEDIA
&& (mode == SFmode || mode == SImode))
return FPUL_REGS;
if ((class == FPUL_REGS
|| (REGCLASS_HAS_FP_REG (class)
&& ! TARGET_SHMEDIA && mode == SImode))
&& (GET_CODE (x) == MEM
|| (GET_CODE (x) == REG
&& (REGNO (x) >= FIRST_PSEUDO_REGISTER
|| REGNO (x) == T_REG
|| system_reg_operand (x, VOIDmode)))))
{
if (class == FPUL_REGS)
return GENERAL_REGS;
return FPUL_REGS;
}
if ((class == TARGET_REGS
|| (TARGET_SHMEDIA && class == SIBCALL_REGS))
&& !EXTRA_CONSTRAINT_Csy (x)
&& (GET_CODE (x) != REG || ! GENERAL_REGISTER_P (REGNO (x))))
return GENERAL_REGS;
if ((class == MAC_REGS || class == PR_REGS)
&& GET_CODE (x) == REG && ! GENERAL_REGISTER_P (REGNO (x))
&& class != REGNO_REG_CLASS (REGNO (x)))
return GENERAL_REGS;
if (class != GENERAL_REGS && GET_CODE (x) == REG
&& TARGET_REGISTER_P (REGNO (x)))
return GENERAL_REGS;
return NO_REGS;
}
enum sh_divide_strategy_e sh_div_strategy = SH_DIV_STRATEGY_DEFAULT;
/* This defines the storage for the variable part of a -mboard= option.

View File

@ -1604,6 +1604,7 @@ extern enum reg_class reg_class_from_letter[];
? GENERAL_REGS \
: (CLASS)) \
#if 0
#define SECONDARY_INOUT_RELOAD_CLASS(CLASS,MODE,X,ELSE) \
((((REGCLASS_HAS_FP_REG (CLASS) \
&& (GET_CODE (X) == REG \
@ -1675,6 +1676,9 @@ extern enum reg_class reg_class_from_letter[];
&& (GET_CODE (X) == LABEL_REF || PIC_DIRECT_ADDR_P (X))) \
? TARGET_REGS \
: SECONDARY_INOUT_RELOAD_CLASS((CLASS),(MODE),(X), NO_REGS))
#else
#define HAVE_SECONDARY_RELOADS
#endif
/* Return the maximum number of consecutive registers
needed to represent mode MODE in a register of class CLASS.

View File

@ -5845,15 +5845,15 @@ label:
(clobber (scratch:SI))])]
"")
(define_expand "reload_indf"
[(parallel [(set (match_operand:DF 0 "register_operand" "=f")
(define_expand "reload_indf__frn"
[(parallel [(set (match_operand:DF 0 "register_operand" "=a")
(match_operand:DF 1 "immediate_operand" "FQ"))
(use (reg:PSI FPSCR_REG))
(clobber (match_operand:SI 2 "register_operand" "=&z"))])]
"TARGET_SH1"
"")
(define_expand "reload_outdf"
(define_expand "reload_outdf__RnFRm"
[(parallel [(set (match_operand:DF 0 "register_operand" "=r,f")
(match_operand:DF 1 "register_operand" "af,r"))
(clobber (match_operand:SI 2 "register_operand" "=&y,y"))])]
@ -6475,7 +6475,7 @@ label:
[(set_attr "length" "0")
(set_attr "type" "nil")])
(define_expand "reload_insf"
(define_expand "reload_insf__frn"
[(parallel [(set (match_operand:SF 0 "register_operand" "=a")
(match_operand:SF 1 "immediate_operand" "FQ"))
(use (reg:PSI FPSCR_REG))
@ -6483,7 +6483,7 @@ label:
"TARGET_SH1"
"")
(define_expand "reload_insi"
(define_expand "reload_insi__i_fpul"
[(parallel [(set (match_operand:SI 0 "fpul_operand" "=y")
(match_operand:SI 1 "immediate_operand" "i"))
(clobber (match_operand:SI 2 "register_operand" "=&z"))])]

View File

@ -2920,10 +2920,7 @@ If a scratch register is required to move an object to or from memory,
it can be allocated using @code{gen_reg_rtx} prior to life analysis.
If there are cases which need scratch registers during or after reload,
you must define @code{SECONDARY_INPUT_RELOAD_CLASS} and/or
@code{SECONDARY_OUTPUT_RELOAD_CLASS} to detect them, and provide
patterns @samp{reload_in@var{m}} or @samp{reload_out@var{m}} to handle
them. @xref{Register Classes}.
you must provide an appropriate secondary_reload target hook.
@findex no_new_pseudos
The global variable @code{no_new_pseudos} can be used to determine if it
@ -2953,6 +2950,9 @@ reload into a floating point register.
@cindex @code{reload_out} instruction pattern
@item @samp{reload_in@var{m}}
@itemx @samp{reload_out@var{m}}
These named patterns have been obsoleted by the target hook
@code{secondary_reload}.
Like @samp{mov@var{m}}, but used when a scratch register is required to
move between operand 0 and operand 1. Operand 2 describes the scratch
register. See the discussion of the @code{SECONDARY_RELOAD_CLASS}

View File

@ -2397,32 +2397,114 @@ Don't define this macro unless the target machine has limitations which
require the macro to do something nontrivial.
@end defmac
@defmac SECONDARY_RELOAD_CLASS (@var{class}, @var{mode}, @var{x})
@defmacx SECONDARY_INPUT_RELOAD_CLASS (@var{class}, @var{mode}, @var{x})
@defmacx SECONDARY_OUTPUT_RELOAD_CLASS (@var{class}, @var{mode}, @var{x})
@deftypefn {Target Hook} enum reg_class TARGET_SECONDARY_RELOAD (bool @var{in_p}, rtx @var{x}, enum reg_class @var{reload_class}, enum machine_mode @var{reload_mode}, secondary_reload_info *@var{sri})
Many machines have some registers that cannot be copied directly to or
from memory or even from other types of registers. An example is the
@samp{MQ} register, which on most machines, can only be copied to or
from general registers, but not memory. Some machines allow copying all
registers to and from memory, but require a scratch register for stores
to some memory locations (e.g., those with symbolic address on the RT,
and those with certain symbolic address on the SPARC when compiling
PIC)@. In some cases, both an intermediate and a scratch register are
required.
from general registers, but not memory. Below, we shall be using the
term 'intermediate register' when a move operation cannot be performed
directly, but has to be done by copying the source into the intermediate
register first, and then copying the intermediate register to the
destination. An intermediate register always has the same mode as
source and destination. Since it holds the actual value being copied,
reload might apply optimizations to re-use an intermediate register
and eliding the copy from the source when it can determine that the
intermediate register still holds the required value.
You should define these macros to indicate to the reload phase that it may
Another kind of secondary reload is required on some machines which
allow copying all registers to and from memory, but require a scratch
register for stores to some memory locations (e.g., those with symbolic
address on the RT, and those with certain symbolic address on the SPARC
when compiling PIC)@. Scratch registers need not have the same mode
as the value being copied, and usually hold a different value that
that being copied. Special patterns in the md file are needed to
describe how the copy is performed with the help of the scratch register;
these patterns also describe the number, register class(es) and mode(s)
of the scratch register(s).
In some cases, both an intermediate and a scratch register are required.
For input reloads, this target hook is called with nonzero @var{in_p},
and @var{x} is an rtx that needs to be copied to a register in of class
@var{reload_class} in @var{reload_mode}. For output reloads, this target
hook is called with zero @var{in_p}, and a register of class @var{reload_mode}
needs to be copied to rtx @var{x} in @var{reload_mode}.
If copying a register of @var{reload_class} from/to @var{x} requires
an intermediate register, the hook @code{secondary_reload} should
return the register class required for this intermediate register.
If no intermediate register is required, it should return NO_REGS.
If more than one intermediate register is required, describe the one
that is closest in the copy chain to the reload register.
If scratch registers are needed, you also have to describe how to
perform the copy from/to the reload register to/from this
closest intermediate register. Or if no intermediate register is
required, but still a scratch register is needed, describe the
copy from/to the reload register to/from the reload operand @var{x}.
You do this by setting @code{sri->icode} to the instruction code of a pattern
in the md file which performs the move. Operands 0 and 1 are the output
and input of this copy, respectively. Operands from operand 2 onward are
for scratch operands. These scratch operands must have a mode, and a
single-register-class
@c [later: or memory]
output constraint.
When an intermediate register is used, the @code{secondary_reload}
hook will be called again to determine how to copy the intermediate
register to/from the reload operand @var{x}, so your hook must also
have code to handle the register class of the intermediate operand.
@c [For later: maybe we'll allow multi-alternative reload patterns -
@c the port maintainer could name a mov<mode> pattern that has clobbers -
@c and match the constraints of input and output to determine the required
@c alternative. A restriction would be that constraints used to match
@c against reloads registers would have to be written as register class
@c constraints, or we need a new target macro / hook that tells us if an
@c arbitrary constraint can match an unknown register of a given class.
@c Such a macro / hook would also be useful in other places.]
@var{x} might be a pseudo-register or a @code{subreg} of a
pseudo-register, which could either be in a hard register or in memory.
Use @code{true_regnum} to find out; it will return @minus{}1 if the pseudo is
in memory and the hard register number if it is in a register.
Scratch operands in memory (constraint @code{"=m"} / @code{"=&m"}) are
currently not supported. For the time being, you will have to continue
to use @code{SECONDARY_MEMORY_NEEDED} for that purpose.
@code{copy_cost} also uses this target hook to find out how values are
copied. If you want it to include some extra cost for the need to allocate
(a) scratch register(s), set @code{sri->extra_cost} to the additional cost.
Or if two dependent moves are supposed to have a lower cost than the sum
of the individual moves due to expected fortuitous scheduling and/or special
forwarding logic, you can set @code{sri->extra_cost} to a negative amount.
@end deftypefn
@defmac SECONDARY_RELOAD_CLASS (@var{class}, @var{mode}, @var{x})
@defmacx SECONDARY_INPUT_RELOAD_CLASS (@var{class}, @var{mode}, @var{x})
@defmacx SECONDARY_OUTPUT_RELOAD_CLASS (@var{class}, @var{mode}, @var{x})
These macros are obsolete, new ports should use the target hook
@code{TARGET_SECONDARY_RELOAD} instead.
These are obsolete macros, replaced by the @code{TARGET_SECONDARY_RELOAD}
target hook. Older ports still define these macros to indicate to the
reload phase that it may
need to allocate at least one register for a reload in addition to the
register to contain the data. Specifically, if copying @var{x} to a
register @var{class} in @var{mode} requires an intermediate register,
you should define @code{SECONDARY_INPUT_RELOAD_CLASS} to return the
you were supposed to define @code{SECONDARY_INPUT_RELOAD_CLASS} to return the
largest register class all of whose registers can be used as
intermediate registers or scratch registers.
If copying a register @var{class} in @var{mode} to @var{x} requires an
intermediate or scratch register, @code{SECONDARY_OUTPUT_RELOAD_CLASS}
should be defined to return the largest register class required. If the
requirements for input and output reloads are the same, the macro
@code{SECONDARY_RELOAD_CLASS} should be used instead of defining both
was supposed to be defined be defined to return the largest register
class required. If the
requirements for input and output reloads were the same, the macro
@code{SECONDARY_RELOAD_CLASS} should have been used instead of defining both
macros identically.
The values returned by these macros are often @code{GENERAL_REGS}.
@ -2432,14 +2514,15 @@ can be directly copied to or from a register of @var{class} in
macro if it would always return @code{NO_REGS}.
If a scratch register is required (either with or without an
intermediate register), you should define patterns for
intermediate register), you were supposed to define patterns for
@samp{reload_in@var{m}} or @samp{reload_out@var{m}}, as required
(@pxref{Standard Names}. These patterns, which will normally be
(@pxref{Standard Names}. These patterns, which were normally
implemented with a @code{define_expand}, should be similar to the
@samp{mov@var{m}} patterns, except that operand 2 is the scratch
register.
Define constraints for the reload register and scratch register that
These patterns need constraints for the reload register and scratch
register that
contain a single register class. If the original reload register (whose
class is @var{class}) can meet the constraint given in the pattern, the
value returned by these macros is used for the class of the scratch

View File

@ -5191,9 +5191,7 @@ init_optabs (void)
sync_lock_test_and_set[i] = CODE_FOR_nothing;
sync_lock_release[i] = CODE_FOR_nothing;
#ifdef HAVE_SECONDARY_RELOADS
reload_in_optab[i] = reload_out_optab[i] = CODE_FOR_nothing;
#endif
}
/* Fill in the optabs with the insns we support. */

View File

@ -46,6 +46,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
#include "ggc.h"
#include "timevar.h"
#include "hashtab.h"
#include "target.h"
static void init_reg_sets_1 (void);
static void init_reg_autoinc (void);
@ -53,12 +54,11 @@ static void init_reg_autoinc (void);
/* If we have auto-increment or auto-decrement and we can have secondary
reloads, we are not allowed to use classes requiring secondary
reloads for pseudos auto-incremented since reload can't handle it. */
#ifdef AUTO_INC_DEC
#if defined(SECONDARY_INPUT_RELOAD_CLASS) || defined(SECONDARY_OUTPUT_RELOAD_CLASS)
/* We leave it to target hooks to decide if we have secondary reloads, so
assume that we might have them. */
#if defined(AUTO_INC_DEC) /* */
#define FORBIDDEN_INC_DEC_CLASSES
#endif
#endif
/* Register tables used by many passes. */
@ -597,17 +597,14 @@ init_regs (void)
void
init_fake_stack_mems (void)
{
#ifdef HAVE_SECONDARY_RELOADS
{
int i;
for (i = 0; i < MAX_MACHINE_MODE; i++)
top_of_stack[i] = gen_rtx_MEM (i, stack_pointer_rtx);
}
#endif
}
#ifdef HAVE_SECONDARY_RELOADS
/* Compute extra cost of moving registers to/from memory due to reloads.
Only needed if secondary reloads are required for memory moves. */
@ -622,22 +619,7 @@ memory_move_secondary_cost (enum machine_mode mode, enum reg_class class, int in
rtx mem ATTRIBUTE_UNUSED = top_of_stack[(int) mode];
if (in)
{
#ifdef SECONDARY_INPUT_RELOAD_CLASS
altclass = SECONDARY_INPUT_RELOAD_CLASS (class, mode, mem);
#else
altclass = NO_REGS;
#endif
}
else
{
#ifdef SECONDARY_OUTPUT_RELOAD_CLASS
altclass = SECONDARY_OUTPUT_RELOAD_CLASS (class, mode, mem);
#else
altclass = NO_REGS;
#endif
}
altclass = secondary_reload_class (in ? 1 : 0, class, mode, mem);
if (altclass == NO_REGS)
return 0;
@ -661,7 +643,6 @@ memory_move_secondary_cost (enum machine_mode mode, enum reg_class class, int in
secondary reload. */
return memory_move_secondary_cost (mode, altclass, in) + partial_cost;
}
#endif
/* Return a machine mode that is legitimate for hard reg REGNO and large
enough to save nregs. If we can't find one, return VOIDmode.
@ -878,7 +859,8 @@ static void dump_regclass (FILE *);
static void record_reg_classes (int, int, rtx *, enum machine_mode *,
const char **, rtx, struct costs *,
struct reg_pref *);
static int copy_cost (rtx, enum machine_mode, enum reg_class, int);
static int copy_cost (rtx, enum machine_mode, enum reg_class, int,
secondary_reload_info *);
static void record_address_regs (rtx, enum reg_class, int);
#ifdef FORBIDDEN_INC_DEC_CLASSES
static int auto_inc_dec_reg_p (rtx, enum machine_mode);
@ -1175,6 +1157,8 @@ init_reg_autoinc (void)
m = (enum machine_mode) ((int) m + 1))
if (HARD_REGNO_MODE_OK (j, m))
{
enum reg_class base_class = MODE_BASE_REG_CLASS (VOIDmode);
PUT_MODE (r, m);
/* If a register is not directly suitable for an
@ -1182,21 +1166,8 @@ init_reg_autoinc (void)
requires secondary reloads, disallow its class from
being used in such addresses. */
if ((0
#ifdef SECONDARY_RELOAD_CLASS
|| (SECONDARY_RELOAD_CLASS (MODE_BASE_REG_CLASS (VOIDmode), m, r)
!= NO_REGS)
#else
#ifdef SECONDARY_INPUT_RELOAD_CLASS
|| (SECONDARY_INPUT_RELOAD_CLASS (MODE_BASE_REG_CLASS (VOIDmode), m, r)
!= NO_REGS)
#endif
#ifdef SECONDARY_OUTPUT_RELOAD_CLASS
|| (SECONDARY_OUTPUT_RELOAD_CLASS (MODE_BASE_REG_CLASS (VOIDmode), m, r)
!= NO_REGS)
#endif
#endif
)
if ((secondary_reload_class (1, base_class, m, r)
|| secondary_reload_class (1, base_class, m, r))
&& ! auto_inc_dec_reg_p (r, m))
forbidden_inc_dec_class[i] = 1;
}
@ -1473,7 +1444,10 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
operand to the register used for the other operand. */
else if (classes[j] != NO_REGS)
alt_cost += copy_cost (op, mode, classes[j], 1), win = 1;
{
alt_cost += copy_cost (op, mode, classes[j], 1, NULL);
win = 1;
}
}
else if (!REG_P (ops[j])
|| REGNO (ops[j]) < FIRST_PSEUDO_REGISTER)
@ -1491,7 +1465,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
operand. */
else
alt_cost += copy_cost (ops[j], mode, classes[j], 1);
alt_cost += copy_cost (ops[j], mode, classes[j], 1, NULL);
}
else
{
@ -1777,10 +1751,10 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
else if (classes[i] != NO_REGS)
{
if (recog_data.operand_type[i] != OP_OUT)
alt_cost += copy_cost (op, mode, classes[i], 1);
alt_cost += copy_cost (op, mode, classes[i], 1, NULL);
if (recog_data.operand_type[i] != OP_IN)
alt_cost += copy_cost (op, mode, classes[i], 0);
alt_cost += copy_cost (op, mode, classes[i], 0, NULL);
}
/* The only other way this alternative can be used is if this is a
@ -1878,12 +1852,11 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
X must not be a pseudo. */
static int
copy_cost (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED,
enum reg_class class, int to_p ATTRIBUTE_UNUSED)
copy_cost (rtx x, enum machine_mode mode, enum reg_class class, int to_p,
secondary_reload_info *prev_sri)
{
#ifdef HAVE_SECONDARY_RELOADS
enum reg_class secondary_class = NO_REGS;
#endif
secondary_reload_info sri;
/* If X is a SCRATCH, there is actually nothing to move since we are
assuming optimal allocation. */
@ -1894,40 +1867,33 @@ copy_cost (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED,
/* Get the class we will actually use for a reload. */
class = PREFERRED_RELOAD_CLASS (x, class);
#ifdef HAVE_SECONDARY_RELOADS
/* If we need a secondary reload (we assume here that we are using
the secondary reload as an intermediate, not a scratch register), the
/* If we need a secondary reload for an intermediate, the
cost is that to load the input into the intermediate register, then
to copy them. We use a special value of TO_P to avoid recursion. */
to copy it. */
#ifdef SECONDARY_INPUT_RELOAD_CLASS
if (to_p == 1)
secondary_class = SECONDARY_INPUT_RELOAD_CLASS (class, mode, x);
#endif
#ifdef SECONDARY_OUTPUT_RELOAD_CLASS
if (! to_p)
secondary_class = SECONDARY_OUTPUT_RELOAD_CLASS (class, mode, x);
#endif
sri.prev_sri = prev_sri;
sri.extra_cost = 0;
secondary_class = targetm.secondary_reload (to_p, x, class, mode, &sri);
if (secondary_class != NO_REGS)
return (move_cost[mode][(int) secondary_class][(int) class]
+ copy_cost (x, mode, secondary_class, 2));
#endif /* HAVE_SECONDARY_RELOADS */
+ sri.extra_cost
+ copy_cost (x, mode, secondary_class, to_p, &sri));
/* For memory, use the memory move cost, for (hard) registers, use the
cost to move between the register classes, and use 2 for everything
else (constants). */
if (MEM_P (x) || class == NO_REGS)
return MEMORY_MOVE_COST (mode, class, to_p);
return sri.extra_cost + MEMORY_MOVE_COST (mode, class, to_p);
else if (REG_P (x))
return move_cost[mode][(int) REGNO_REG_CLASS (REGNO (x))][(int) class];
return (sri.extra_cost
+ move_cost[mode][(int) REGNO_REG_CLASS (REGNO (x))][(int) class]);
else
/* If this is a constant, we may eventually want to call rtx_cost here. */
return COSTS_N_INSNS (1);
return sri.extra_cost + COSTS_N_INSNS (1);
}
/* Record the pseudo registers we must reload into hard registers

View File

@ -242,11 +242,9 @@ static int output_reloadnum;
? RELOAD_FOR_OUTADDR_ADDRESS \
: (type)))
#ifdef HAVE_SECONDARY_RELOADS
static int push_secondary_reload (int, rtx, int, int, enum reg_class,
enum machine_mode, enum reload_type,
enum insn_code *);
#endif
enum insn_code *, secondary_reload_info *);
static enum reg_class find_valid_class (enum machine_mode, enum machine_mode,
int, unsigned int);
static int reload_inner_reg_of_subreg (rtx, enum machine_mode, int);
@ -283,8 +281,6 @@ static int refers_to_mem_for_reload_p (rtx);
static int refers_to_regno_for_reload_p (unsigned int, unsigned int,
rtx, rtx *);
#ifdef HAVE_SECONDARY_RELOADS
/* Determine if any secondary reloads are needed for loading (if IN_P is
nonzero) or storing (if IN_P is zero) X to or from a reload register of
register class RELOAD_CLASS in mode RELOAD_MODE. If secondary reloads
@ -298,16 +294,18 @@ static int
push_secondary_reload (int in_p, rtx x, int opnum, int optional,
enum reg_class reload_class,
enum machine_mode reload_mode, enum reload_type type,
enum insn_code *picode)
enum insn_code *picode, secondary_reload_info *prev_sri)
{
enum reg_class class = NO_REGS;
enum reg_class scratch_class;
enum machine_mode mode = reload_mode;
enum insn_code icode = CODE_FOR_nothing;
enum reg_class t_class = NO_REGS;
enum machine_mode t_mode = VOIDmode;
enum insn_code t_icode = CODE_FOR_nothing;
enum insn_code t_icode;
enum reload_type secondary_type;
int s_reload, t_reload = -1;
const char *scratch_constraint;
char letter;
secondary_reload_info sri;
if (type == RELOAD_FOR_INPUT_ADDRESS
|| type == RELOAD_FOR_OUTPUT_ADDRESS
@ -339,36 +337,21 @@ push_secondary_reload (int in_p, rtx x, int opnum, int optional,
&& reg_equiv_mem[REGNO (x)] != 0)
x = reg_equiv_mem[REGNO (x)];
#ifdef SECONDARY_INPUT_RELOAD_CLASS
if (in_p)
class = SECONDARY_INPUT_RELOAD_CLASS (reload_class, reload_mode, x);
#endif
#ifdef SECONDARY_OUTPUT_RELOAD_CLASS
if (! in_p)
class = SECONDARY_OUTPUT_RELOAD_CLASS (reload_class, reload_mode, x);
#endif
sri.icode = CODE_FOR_nothing;
sri.prev_sri = prev_sri;
class = targetm.secondary_reload (in_p, x, reload_class, reload_mode, &sri);
icode = sri.icode;
/* If we don't need any secondary registers, done. */
if (class == NO_REGS)
if (class == NO_REGS && icode == CODE_FOR_nothing)
return -1;
/* Get a possible insn to use. If the predicate doesn't accept X, don't
use the insn. */
if (class != NO_REGS)
t_reload = push_secondary_reload (in_p, x, opnum, optional, class,
reload_mode, type, &t_icode, &sri);
icode = (in_p ? reload_in_optab[(int) reload_mode]
: reload_out_optab[(int) reload_mode]);
if (icode != CODE_FOR_nothing
&& insn_data[(int) icode].operand[in_p].predicate
&& (! (insn_data[(int) icode].operand[in_p].predicate) (x, reload_mode)))
icode = CODE_FOR_nothing;
/* If we will be using an insn, see if it can directly handle the reload
register we will be using. If it can, the secondary reload is for a
scratch register. If it can't, we will use the secondary reload for
an intermediate register and require a tertiary reload for the scratch
register. */
/* If we will be using an insn, the secondary reload is for a
scratch register. */
if (icode != CODE_FOR_nothing)
{
@ -377,45 +360,29 @@ push_secondary_reload (int in_p, rtx x, int opnum, int optional,
in operand 1. Outputs should have an initial "=", which we must
skip. */
enum reg_class insn_class;
/* ??? It would be useful to be able to handle only two, or more than
three, operands, but for now we can only handle the case of having
exactly three: output, input and one temp/scratch. */
gcc_assert (insn_data[(int) icode].n_operands == 3);
if (insn_data[(int) icode].operand[!in_p].constraint[0] == 0)
insn_class = ALL_REGS;
else
{
const char *insn_constraint
= &insn_data[(int) icode].operand[!in_p].constraint[in_p];
char insn_letter = *insn_constraint;
insn_class
= (insn_letter == 'r' ? GENERAL_REGS
: REG_CLASS_FROM_CONSTRAINT ((unsigned char) insn_letter,
insn_constraint));
/* ??? We currently have no way to represent a reload that needs
an icode to reload from an intermediate tertiaty reload register.
We should probably have a new field in struct reload to tag a
chain of scratch operand reloads onto. */
gcc_assert (class == NO_REGS);
gcc_assert (insn_class != NO_REGS);
gcc_assert (!in_p
|| insn_data[(int) icode].operand[!in_p].constraint[0]
== '=');
}
scratch_constraint = insn_data[(int) icode].operand[2].constraint;
gcc_assert (*scratch_constraint == '=');
scratch_constraint++;
if (*scratch_constraint == '&')
scratch_constraint++;
letter = *scratch_constraint;
scratch_class = (letter == 'r' ? GENERAL_REGS
: REG_CLASS_FROM_CONSTRAINT ((unsigned char) letter,
insn_constraint));
/* The scratch register's constraint must start with "=&". */
gcc_assert (insn_data[(int) icode].operand[2].constraint[0] == '='
&& insn_data[(int) icode].operand[2].constraint[1] == '&');
if (reg_class_subset_p (reload_class, insn_class))
mode = insn_data[(int) icode].operand[2].mode;
else
{
const char *t_constraint
= &insn_data[(int) icode].operand[2].constraint[2];
char t_letter = *t_constraint;
class = insn_class;
t_mode = insn_data[(int) icode].operand[2].mode;
t_class = (t_letter == 'r' ? GENERAL_REGS
: REG_CLASS_FROM_CONSTRAINT ((unsigned char) t_letter,
t_constraint));
t_icode = icode;
icode = CODE_FOR_nothing;
}
class = scratch_class;
mode = insn_data[(int) icode].operand[2].mode;
}
/* This case isn't valid, so fail. Reload is allowed to use the same
@ -435,68 +402,6 @@ push_secondary_reload (int in_p, rtx x, int opnum, int optional,
gcc_assert (!in_p || class != reload_class || icode != CODE_FOR_nothing
|| t_icode != CODE_FOR_nothing);
/* If we need a tertiary reload, see if we have one we can reuse or else
make a new one. */
if (t_class != NO_REGS)
{
for (t_reload = 0; t_reload < n_reloads; t_reload++)
if (rld[t_reload].secondary_p
&& (reg_class_subset_p (t_class, rld[t_reload].class)
|| reg_class_subset_p (rld[t_reload].class, t_class))
&& ((in_p && rld[t_reload].inmode == t_mode)
|| (! in_p && rld[t_reload].outmode == t_mode))
&& ((in_p && (rld[t_reload].secondary_in_icode
== CODE_FOR_nothing))
|| (! in_p &&(rld[t_reload].secondary_out_icode
== CODE_FOR_nothing)))
&& (SMALL_REGISTER_CLASS_P (t_class) || SMALL_REGISTER_CLASSES)
&& MERGABLE_RELOADS (secondary_type,
rld[t_reload].when_needed,
opnum, rld[t_reload].opnum))
{
if (in_p)
rld[t_reload].inmode = t_mode;
if (! in_p)
rld[t_reload].outmode = t_mode;
if (reg_class_subset_p (t_class, rld[t_reload].class))
rld[t_reload].class = t_class;
rld[t_reload].opnum = MIN (rld[t_reload].opnum, opnum);
rld[t_reload].optional &= optional;
rld[t_reload].secondary_p = 1;
if (MERGE_TO_OTHER (secondary_type, rld[t_reload].when_needed,
opnum, rld[t_reload].opnum))
rld[t_reload].when_needed = RELOAD_OTHER;
}
if (t_reload == n_reloads)
{
/* We need to make a new tertiary reload for this register class. */
rld[t_reload].in = rld[t_reload].out = 0;
rld[t_reload].class = t_class;
rld[t_reload].inmode = in_p ? t_mode : VOIDmode;
rld[t_reload].outmode = ! in_p ? t_mode : VOIDmode;
rld[t_reload].reg_rtx = 0;
rld[t_reload].optional = optional;
rld[t_reload].inc = 0;
/* Maybe we could combine these, but it seems too tricky. */
rld[t_reload].nocombine = 1;
rld[t_reload].in_reg = 0;
rld[t_reload].out_reg = 0;
rld[t_reload].opnum = opnum;
rld[t_reload].when_needed = secondary_type;
rld[t_reload].secondary_in_reload = -1;
rld[t_reload].secondary_out_reload = -1;
rld[t_reload].secondary_in_icode = CODE_FOR_nothing;
rld[t_reload].secondary_out_icode = CODE_FOR_nothing;
rld[t_reload].secondary_p = 1;
n_reloads++;
}
}
/* See if we can reuse an existing secondary reload. */
for (s_reload = 0; s_reload < n_reloads; s_reload++)
if (rld[s_reload].secondary_p
@ -581,7 +486,58 @@ push_secondary_reload (int in_p, rtx x, int opnum, int optional,
*picode = icode;
return s_reload;
}
#endif /* HAVE_SECONDARY_RELOADS */
/* If a secondary reload is needed, return its class. If both an intermediate
register and a scratch register is needed, we return the class of the
intermediate register. */
enum reg_class
secondary_reload_class (bool in_p, enum reg_class class,
enum machine_mode mode, rtx x)
{
enum insn_code icode;
secondary_reload_info sri;
sri.icode = CODE_FOR_nothing;
sri.prev_sri = NULL;
class = targetm.secondary_reload (in_p, x, class, mode, &sri);
icode = sri.icode;
/* If there are no secondary reloads at all, we return NO_REGS.
If an intermediate register is needed, we return its class. */
if (icode == CODE_FOR_nothing || class != NO_REGS)
return class;
/* No intermediate register is needed, but we have a special reload
pattern, which we assume for now needs a scratch register. */
return scratch_reload_class (icode);
}
/* ICODE is the insn_code of a reload pattern. Check that it has exactly
three operands, verify that operand 2 is an output operand, and return
its register class.
??? We'd like to be able to handle any pattern with at least 2 operands,
for zero or more scratch registers, but that needs more infrastructure. */
enum reg_class
scratch_reload_class (enum insn_code icode)
{
const char *scratch_constraint;
char scratch_letter;
enum reg_class class;
gcc_assert (insn_data[(int) icode].n_operands == 3);
scratch_constraint = insn_data[(int) icode].operand[2].constraint;
gcc_assert (*scratch_constraint == '=');
scratch_constraint++;
if (*scratch_constraint == '&')
scratch_constraint++;
scratch_letter = *scratch_constraint;
if (scratch_letter == 'r')
return GENERAL_REGS;
class = REG_CLASS_FROM_CONSTRAINT ((unsigned char) scratch_letter,
scratch_constraint);
gcc_assert (class != NO_REGS);
return class;
}
#ifdef SECONDARY_MEMORY_NEEDED
@ -1058,13 +1014,10 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc,
!= (int) hard_regno_nregs[REGNO (SUBREG_REG (in))]
[GET_MODE (SUBREG_REG (in))]))
|| ! HARD_REGNO_MODE_OK (subreg_regno (in), inmode)))
#ifdef SECONDARY_INPUT_RELOAD_CLASS
|| (SECONDARY_INPUT_RELOAD_CLASS (class, inmode, in) != NO_REGS
&& (SECONDARY_INPUT_RELOAD_CLASS (class,
GET_MODE (SUBREG_REG (in)),
SUBREG_REG (in))
|| (secondary_reload_class (1, class, inmode, in) != NO_REGS
&& (secondary_reload_class (1, class, GET_MODE (SUBREG_REG (in)),
SUBREG_REG (in))
== NO_REGS))
#endif
#ifdef CANNOT_CHANGE_MODE_CLASS
|| (REG_P (SUBREG_REG (in))
&& REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER
@ -1154,13 +1107,10 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc,
!= (int) hard_regno_nregs[REGNO (SUBREG_REG (out))]
[GET_MODE (SUBREG_REG (out))]))
|| ! HARD_REGNO_MODE_OK (subreg_regno (out), outmode)))
#ifdef SECONDARY_OUTPUT_RELOAD_CLASS
|| (SECONDARY_OUTPUT_RELOAD_CLASS (class, outmode, out) != NO_REGS
&& (SECONDARY_OUTPUT_RELOAD_CLASS (class,
GET_MODE (SUBREG_REG (out)),
SUBREG_REG (out))
|| (secondary_reload_class (0, class, outmode, out) != NO_REGS
&& (secondary_reload_class (0, class, GET_MODE (SUBREG_REG (out)),
SUBREG_REG (out))
== NO_REGS))
#endif
#ifdef CANNOT_CHANGE_MODE_CLASS
|| (REG_P (SUBREG_REG (out))
&& REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER
@ -1310,19 +1260,14 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc,
and IN or CLASS and OUT. Get the icode and push any required reloads
needed for each of them if so. */
#ifdef SECONDARY_INPUT_RELOAD_CLASS
if (in != 0)
secondary_in_reload
= push_secondary_reload (1, in, opnum, optional, class, inmode, type,
&secondary_in_icode);
#endif
#ifdef SECONDARY_OUTPUT_RELOAD_CLASS
&secondary_in_icode, NULL);
if (out != 0 && GET_CODE (out) != SCRATCH)
secondary_out_reload
= push_secondary_reload (0, out, opnum, optional, class, outmode,
type, &secondary_out_icode);
#endif
type, &secondary_out_icode, NULL);
/* We found no existing reload suitable for re-use.
So add an additional reload. */

View File

@ -30,19 +30,10 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
SECONDARY_RELOAD_CLASS (CLASS, MODE, X)
#endif
/* If either macro is defined, show that we need secondary reloads. */
#if defined(SECONDARY_INPUT_RELOAD_CLASS) || defined(SECONDARY_OUTPUT_RELOAD_CLASS)
#define HAVE_SECONDARY_RELOADS
#endif
/* If MEMORY_MOVE_COST isn't defined, give it a default here. */
#ifndef MEMORY_MOVE_COST
#ifdef HAVE_SECONDARY_RELOADS
#define MEMORY_MOVE_COST(MODE,CLASS,IN) \
(4 + memory_move_secondary_cost ((MODE), (CLASS), (IN)))
#else
#define MEMORY_MOVE_COST(MODE,CLASS,IN) 4
#endif
#endif
extern int memory_move_secondary_cost (enum machine_mode, enum reg_class, int);
@ -252,6 +243,13 @@ extern void compute_use_by_pseudos (HARD_REG_SET *, regset);
/* Functions from reload.c: */
extern enum reg_class secondary_reload_class (bool, enum reg_class,
enum machine_mode, rtx);
#ifdef GCC_INSN_CODES_H
extern enum reg_class scratch_reload_class (enum insn_code);
#endif
/* Return a memory location that will be used to copy X in mode MODE.
If we haven't already made a location for this mode in this insn,
call find_reloads_address on the location being returned. */

View File

@ -43,6 +43,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
#include "toplev.h"
#include "except.h"
#include "tree.h"
#include "target.h"
/* This file contains the reload pass of the compiler, which is
run after register allocation has been done. It checks that
@ -5540,11 +5541,9 @@ choose_reload_regs (struct insn_chain *chain)
enough. */
|| ((REGISTER_MOVE_COST (mode, last_class, class)
< MEMORY_MOVE_COST (mode, class, 1))
#ifdef SECONDARY_INPUT_RELOAD_CLASS
&& (SECONDARY_INPUT_RELOAD_CLASS (class, mode,
last_reg)
&& (secondary_reload_class (1, class, mode,
last_reg)
== NO_REGS)
#endif
#ifdef SECONDARY_MEMORY_NEEDED
&& ! SECONDARY_MEMORY_NEEDED (last_class, class,
mode)
@ -6205,6 +6204,55 @@ static rtx other_output_reload_insns[MAX_RECOG_OPERANDS];
static rtx new_spill_reg_store[FIRST_PSEUDO_REGISTER];
static HARD_REG_SET reg_reloaded_died;
/* Check if *RELOAD_REG is suitable as an intermediate or scratch register
of class NEW_CLASS with mode NEW_MODE. Or alternatively, if alt_reload_reg
is nonzero, if that is suitable. On success, change *RELOAD_REG to the
adjusted register, and return true. Otherwise, return false. */
static bool
reload_adjust_reg_for_temp (rtx *reload_reg, rtx alt_reload_reg,
enum reg_class new_class,
enum machine_mode new_mode)
{
rtx reg;
for (reg = *reload_reg; reg; reg = alt_reload_reg, alt_reload_reg = 0)
{
unsigned regno = REGNO (reg);
if (!TEST_HARD_REG_BIT (reg_class_contents[(int) new_class], regno))
continue;
if (GET_MODE (reg) != new_mode)
{
if (!HARD_REGNO_MODE_OK (regno, new_mode))
continue;
if (hard_regno_nregs[regno][new_mode]
> hard_regno_nregs[regno][GET_MODE (reg)])
continue;
reg = reload_adjust_reg_for_mode (reg, new_mode);
}
*reload_reg = reg;
return true;
}
return false;
}
/* Check if *RELOAD_REG is suitable as a scratch register for the reload
pattern with insn_code ICODE, or alternatively, if alt_reload_reg is
nonzero, if that is suitable. On success, change *RELOAD_REG to the
adjusted register, and return true. Otherwise, return false. */
static bool
reload_adjust_reg_for_icode (rtx *reload_reg, rtx alt_reload_reg,
enum insn_code icode)
{
enum reg_class new_class = scratch_reload_class (icode);
enum machine_mode new_mode = insn_data[(int) icode].operand[2].mode;
return reload_adjust_reg_for_temp (reload_reg, alt_reload_reg,
new_class, new_mode);
}
/* Generate insns to perform reload RL, which is for the insn in CHAIN and
has the number J. OLD contains the value to be used as input. */
@ -6256,7 +6304,6 @@ emit_input_reload_insns (struct insn_chain *chain, struct reload *rl,
if (mode == VOIDmode)
mode = rl->inmode;
#ifdef SECONDARY_INPUT_RELOAD_CLASS
/* If we need a secondary register for this operation, see if
the value is already in a register in that class. Don't
do this if the secondary register will be used as a scratch
@ -6269,7 +6316,6 @@ emit_input_reload_insns (struct insn_chain *chain, struct reload *rl,
= find_equiv_reg (old, insn,
rld[rl->secondary_in_reload].class,
-1, NULL, 0, mode);
#endif
/* If reloading from memory, see if there is a register
that already holds the same value. If so, reload from there.
@ -6306,11 +6352,8 @@ emit_input_reload_insns (struct insn_chain *chain, struct reload *rl,
&& (REGISTER_MOVE_COST (mode, REGNO_REG_CLASS (regno),
rl->class)
>= MEMORY_MOVE_COST (mode, rl->class, 1)))
#ifdef SECONDARY_INPUT_RELOAD_CLASS
|| (SECONDARY_INPUT_RELOAD_CLASS (rl->class,
mode, oldequiv)
|| (secondary_reload_class (1, rl->class, mode, oldequiv)
!= NO_REGS)
#endif
#ifdef SECONDARY_MEMORY_NEEDED
|| SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (regno),
rl->class,
@ -6496,7 +6539,6 @@ emit_input_reload_insns (struct insn_chain *chain, struct reload *rl,
/* We can't do that, so output an insn to load RELOADREG. */
#ifdef SECONDARY_INPUT_RELOAD_CLASS
/* If we have a secondary reload, pick up the secondary register
and icode, if any. If OLDEQUIV and OLD are different or
if this is an in-out reload, recompute whether or not we
@ -6511,11 +6553,13 @@ emit_input_reload_insns (struct insn_chain *chain, struct reload *rl,
if (! special && rl->secondary_in_reload >= 0)
{
rtx second_reload_reg = 0;
rtx third_reload_reg = 0;
int secondary_reload = rl->secondary_in_reload;
rtx real_oldequiv = oldequiv;
rtx real_old = old;
rtx tmp;
enum insn_code icode;
enum insn_code tertiary_icode = CODE_FOR_nothing;
/* If OLDEQUIV is a pseudo with a MEM, get the real MEM
and similarly for OLD.
@ -6563,53 +6607,89 @@ emit_input_reload_insns (struct insn_chain *chain, struct reload *rl,
}
second_reload_reg = rld[secondary_reload].reg_rtx;
if (rld[secondary_reload].secondary_in_reload >= 0)
{
int tertiary_reload = rld[secondary_reload].secondary_in_reload;
third_reload_reg = rld[tertiary_reload].reg_rtx;
tertiary_icode = rld[secondary_reload].secondary_in_icode;
/* We'd have to add more code for quartary reloads. */
gcc_assert (rld[tertiary_reload].secondary_in_reload < 0);
}
icode = rl->secondary_in_icode;
if ((old != oldequiv && ! rtx_equal_p (old, oldequiv))
|| (rl->in != 0 && rl->out != 0))
{
enum reg_class new_class
= SECONDARY_INPUT_RELOAD_CLASS (rl->class,
mode, real_oldequiv);
secondary_reload_info sri, sri2;
enum reg_class new_class, new_t_class;
if (new_class == NO_REGS)
sri.icode = CODE_FOR_nothing;
sri.prev_sri = NULL;
new_class = targetm.secondary_reload (1, real_oldequiv, rl->class,
mode, &sri);
if (new_class == NO_REGS && sri.icode == CODE_FOR_nothing)
second_reload_reg = 0;
else if (new_class == NO_REGS)
{
if (reload_adjust_reg_for_icode (&second_reload_reg,
third_reload_reg, sri.icode))
icode = sri.icode, third_reload_reg = 0;
else
oldequiv = old, real_oldequiv = real_old;
}
else if (sri.icode != CODE_FOR_nothing)
/* We currently lack a way to express this in reloads. */
gcc_unreachable ();
else
{
enum insn_code new_icode;
enum machine_mode new_mode;
if (! TEST_HARD_REG_BIT (reg_class_contents[(int) new_class],
REGNO (second_reload_reg)))
oldequiv = old, real_oldequiv = real_old;
else
sri2.icode = CODE_FOR_nothing;
sri2.prev_sri = &sri;
new_t_class = targetm.secondary_reload (1, real_oldequiv,
new_class, mode, &sri);
if (new_t_class == NO_REGS && sri2.icode == CODE_FOR_nothing)
{
new_icode = reload_in_optab[(int) mode];
if (new_icode != CODE_FOR_nothing
&& ((insn_data[(int) new_icode].operand[0].predicate
&& ! ((*insn_data[(int) new_icode].operand[0].predicate)
(reloadreg, mode)))
|| (insn_data[(int) new_icode].operand[1].predicate
&& ! ((*insn_data[(int) new_icode].operand[1].predicate)
(real_oldequiv, mode)))))
new_icode = CODE_FOR_nothing;
if (new_icode == CODE_FOR_nothing)
new_mode = mode;
if (reload_adjust_reg_for_temp (&second_reload_reg,
third_reload_reg,
new_class, mode))
third_reload_reg = 0, tertiary_icode = sri2.icode;
else
new_mode = insn_data[(int) new_icode].operand[2].mode;
if (GET_MODE (second_reload_reg) != new_mode)
{
if (!HARD_REGNO_MODE_OK (REGNO (second_reload_reg),
new_mode))
oldequiv = old, real_oldequiv = real_old;
else
second_reload_reg
= reload_adjust_reg_for_mode (second_reload_reg,
new_mode);
}
oldequiv = old, real_oldequiv = real_old;
}
else if (new_t_class == NO_REGS && sri2.icode != CODE_FOR_nothing)
{
rtx intermediate = second_reload_reg;
if (reload_adjust_reg_for_temp (&intermediate, NULL,
new_class, mode)
&& reload_adjust_reg_for_icode (&third_reload_reg, NULL,
sri2.icode))
{
second_reload_reg = intermediate;
tertiary_icode = sri2.icode;
}
else
oldequiv = old, real_oldequiv = real_old;
}
else if (new_t_class != NO_REGS && sri2.icode == CODE_FOR_nothing)
{
rtx intermediate = second_reload_reg;
if (reload_adjust_reg_for_temp (&intermediate, NULL,
new_class, mode)
&& reload_adjust_reg_for_temp (&third_reload_reg, NULL,
new_t_class, mode))
{
second_reload_reg = intermediate;
tertiary_icode = sri2.icode;
}
else
oldequiv = old, real_oldequiv = real_old;
}
else
/* This could be handled more intelligently too. */
oldequiv = old, real_oldequiv = real_old;
}
}
@ -6624,6 +6704,9 @@ emit_input_reload_insns (struct insn_chain *chain, struct reload *rl,
{
if (icode != CODE_FOR_nothing)
{
/* We'd have to add extra code to handle this case. */
gcc_assert (!third_reload_reg);
emit_insn (GEN_FCN (icode) (reloadreg, real_oldequiv,
second_reload_reg));
special = 1;
@ -6632,18 +6715,21 @@ emit_input_reload_insns (struct insn_chain *chain, struct reload *rl,
{
/* See if we need a scratch register to load the
intermediate register (a tertiary reload). */
enum insn_code tertiary_icode
= rld[secondary_reload].secondary_in_icode;
if (tertiary_icode != CODE_FOR_nothing)
{
rtx third_reload_reg
= rld[rld[secondary_reload].secondary_in_reload].reg_rtx;
emit_insn ((GEN_FCN (tertiary_icode)
(second_reload_reg, real_oldequiv,
third_reload_reg)));
}
else if (third_reload_reg)
{
gen_reload (third_reload_reg, real_oldequiv,
rl->opnum,
rl->when_needed);
gen_reload (second_reload_reg, third_reload_reg,
rl->opnum,
rl->when_needed);
}
else
gen_reload (second_reload_reg, real_oldequiv,
rl->opnum,
@ -6653,7 +6739,6 @@ emit_input_reload_insns (struct insn_chain *chain, struct reload *rl,
}
}
}
#endif
if (! special && ! rtx_equal_p (reloadreg, oldequiv))
{
@ -6729,8 +6814,6 @@ emit_output_reload_insns (struct insn_chain *chain, struct reload *rl,
if (GET_MODE (reloadreg) != mode)
reloadreg = reload_adjust_reg_for_mode (reloadreg, mode);
#ifdef SECONDARY_OUTPUT_RELOAD_CLASS
/* If we need two reload regs, set RELOADREG to the intermediate
one, since it will be stored into OLD. We might need a secondary
register only for an input reload, so check again here. */
@ -6738,22 +6821,25 @@ emit_output_reload_insns (struct insn_chain *chain, struct reload *rl,
if (rl->secondary_out_reload >= 0)
{
rtx real_old = old;
int secondary_reload = rl->secondary_out_reload;
int tertiary_reload = rld[secondary_reload].secondary_out_reload;
if (REG_P (old) && REGNO (old) >= FIRST_PSEUDO_REGISTER
&& reg_equiv_mem[REGNO (old)] != 0)
real_old = reg_equiv_mem[REGNO (old)];
if ((SECONDARY_OUTPUT_RELOAD_CLASS (rl->class,
mode, real_old)
!= NO_REGS))
if (secondary_reload_class (0, rl->class, mode, real_old) != NO_REGS)
{
rtx second_reloadreg = reloadreg;
reloadreg = rld[rl->secondary_out_reload].reg_rtx;
reloadreg = rld[secondary_reload].reg_rtx;
/* See if RELOADREG is to be used as a scratch register
or as an intermediate register. */
if (rl->secondary_out_icode != CODE_FOR_nothing)
{
/* We'd have to add extra code to handle this case. */
gcc_assert (tertiary_reload < 0);
emit_insn ((GEN_FCN (rl->secondary_out_icode)
(real_old, second_reloadreg, reloadreg)));
special = 1;
@ -6763,17 +6849,19 @@ emit_output_reload_insns (struct insn_chain *chain, struct reload *rl,
/* See if we need both a scratch and intermediate reload
register. */
int secondary_reload = rl->secondary_out_reload;
enum insn_code tertiary_icode
= rld[secondary_reload].secondary_out_icode;
/* We'd have to add more code for quartary reloads. */
gcc_assert (tertiary_reload < 0
|| rld[tertiary_reload].secondary_out_reload < 0);
if (GET_MODE (reloadreg) != mode)
reloadreg = reload_adjust_reg_for_mode (reloadreg, mode);
if (tertiary_icode != CODE_FOR_nothing)
{
rtx third_reloadreg
= rld[rld[secondary_reload].secondary_out_reload].reg_rtx;
rtx third_reloadreg = rld[tertiary_reload].reg_rtx;
rtx tem;
/* Copy primary reload reg to secondary reload reg.
@ -6799,15 +6887,24 @@ emit_output_reload_insns (struct insn_chain *chain, struct reload *rl,
}
else
/* Copy between the reload regs here and then to
OUT later. */
{
/* Copy between the reload regs here and then to
OUT later. */
gen_reload (reloadreg, second_reloadreg,
rl->opnum, rl->when_needed);
gen_reload (reloadreg, second_reloadreg,
rl->opnum, rl->when_needed);
if (tertiary_reload >= 0)
{
rtx third_reloadreg = rld[tertiary_reload].reg_rtx;
gen_reload (third_reloadreg, reloadreg,
rl->opnum, rl->when_needed);
reloadreg = third_reloadreg;
}
}
}
}
}
#endif
/* Output the last reload insn. */
if (! special)

View File

@ -480,6 +480,10 @@ Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#define TARGET_HANDLE_PRAGMA_EXTERN_PREFIX 0
#endif
#ifndef TARGET_SECONDARY_RELOAD
#define TARGET_SECONDARY_RELOAD default_secondary_reload
#endif
/* C++ specific. */
#ifndef TARGET_CXX_GUARD_TYPE
@ -609,6 +613,7 @@ Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
TARGET_INVALID_CONVERSION, \
TARGET_INVALID_UNARY_OP, \
TARGET_INVALID_BINARY_OP, \
TARGET_SECONDARY_RELOAD, \
TARGET_CXX, \
TARGET_UNWIND_TABLES_DEFAULT, \
TARGET_HAVE_NAMED_SECTIONS, \

View File

@ -52,6 +52,21 @@ Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
struct stdarg_info;
/* The struct used by the secondary_reload target hook. */
typedef struct secondary_reload_info
{
/* icode is actually an enum insn_code, but we don't want to force every
file that includes target.h to include optabs.h . */
int icode;
int extra_cost; /* Cost for using (a) scratch register(s) to be taken
into account by copy_cost. */
/* The next two members are for the use of the backward
compatibility hook. */
struct secondary_reload_info *prev_sri;
int t_icode; /* Actually an enum insn_code - see above. */
} secondary_reload_info;
struct gcc_target
{
/* Functions that output assembler for the target. */
@ -631,6 +646,11 @@ struct gcc_target
is not permitted on TYPE1 and TYPE2, NULL otherwise. */
const char *(*invalid_binary_op) (int op, tree type1, tree type2);
/* Return the class for a secondary reload, and fill in extra information. */
enum reg_class (*secondary_reload) (bool, rtx, enum reg_class,
enum machine_mode,
struct secondary_reload_info *);
/* Functions specific to the C++ frontend. */
struct cxx {
/* Return the integer type used for guard variables. */

View File

@ -63,6 +63,9 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
#include "target-def.h"
#include "ggc.h"
#include "hard-reg-set.h"
#include "reload.h"
#include "optabs.h"
#include "recog.h"
void
@ -455,4 +458,87 @@ default_internal_arg_pointer (void)
return virtual_incoming_args_rtx;
}
enum reg_class
default_secondary_reload (bool in_p ATTRIBUTE_UNUSED, rtx x ATTRIBUTE_UNUSED,
enum reg_class reload_class ATTRIBUTE_UNUSED,
enum machine_mode reload_mode ATTRIBUTE_UNUSED,
secondary_reload_info *sri)
{
enum reg_class class = NO_REGS;
if (sri->prev_sri && sri->prev_sri->t_icode != CODE_FOR_nothing)
{
sri->icode = sri->prev_sri->t_icode;
return NO_REGS;
}
#ifdef SECONDARY_INPUT_RELOAD_CLASS
if (in_p)
class = SECONDARY_INPUT_RELOAD_CLASS (reload_class, reload_mode, x);
#endif
#ifdef SECONDARY_OUTPUT_RELOAD_CLASS
if (! in_p)
class = SECONDARY_OUTPUT_RELOAD_CLASS (reload_class, reload_mode, x);
#endif
if (class != NO_REGS)
{
enum insn_code icode = (in_p ? reload_in_optab[(int) reload_mode]
: reload_out_optab[(int) reload_mode]);
if (icode != CODE_FOR_nothing
&& insn_data[(int) icode].operand[in_p].predicate
&& ! insn_data[(int) icode].operand[in_p].predicate (x, reload_mode))
icode = CODE_FOR_nothing;
else if (icode != CODE_FOR_nothing)
{
const char *insn_constraint, *scratch_constraint;
char insn_letter, scratch_letter;
enum reg_class insn_class, scratch_class;
gcc_assert (insn_data[(int) icode].n_operands == 3);
insn_constraint = insn_data[(int) icode].operand[!in_p].constraint;
if (!*insn_constraint)
insn_class = ALL_REGS;
else
{
if (in_p)
{
gcc_assert (*insn_constraint == '=');
insn_constraint++;
}
insn_letter = *insn_constraint;
insn_class
= (insn_letter == 'r' ? GENERAL_REGS
: REG_CLASS_FROM_CONSTRAINT ((unsigned char) insn_letter,
insn_constraint));
gcc_assert (insn_class != NO_REGS);
}
scratch_constraint = insn_data[(int) icode].operand[2].constraint;
/* The scratch register's constraint must start with "=&". */
gcc_assert (scratch_constraint[0] == '='
&& scratch_constraint[1] == '&');
scratch_constraint += 2;
scratch_letter = *scratch_constraint;
scratch_class
= (scratch_letter == 'r' ? GENERAL_REGS
: REG_CLASS_FROM_CONSTRAINT ((unsigned char) scratch_letter,
scratch_constraint));
if (reg_class_subset_p (reload_class, insn_class))
{
gcc_assert (scratch_class == class);
class = NO_REGS;
}
else
class = insn_class;
}
if (class == NO_REGS)
sri->icode = icode;
else
sri->t_icode = icode;
}
return class;
}
#include "gt-targhooks.h"

View File

@ -69,3 +69,6 @@ extern const char *hook_invalid_arg_for_unprototyped_fn
extern bool hook_bool_rtx_commutative_p (rtx, int);
extern rtx default_function_value (tree, tree, bool);
extern rtx default_internal_arg_pointer (void);
extern enum reg_class default_secondary_reload (bool, rtx, enum reg_class,
enum machine_mode,
secondary_reload_info *);