re PR target/21623 (ICE in reload_cse_simplify_operands, at postreload.c:391)
authorJ"orn Rennecke <joern.rennecke@st.com>
Thu, 24 Nov 2005 18:55:53 +0000 (18:55 +0000)
committerJoern Rennecke <amylaar@gcc.gnu.org>
Thu, 24 Nov 2005 18:55:53 +0000 (18:55 +0000)
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

16 files changed:
gcc/ChangeLog
gcc/config/sh/sh-protos.h
gcc/config/sh/sh.c
gcc/config/sh/sh.h
gcc/config/sh/sh.md
gcc/doc/md.texi
gcc/doc/tm.texi
gcc/optabs.c
gcc/regclass.c
gcc/reload.c
gcc/reload.h
gcc/reload1.c
gcc/target-def.h
gcc/target.h
gcc/targhooks.c
gcc/targhooks.h

index bb00ed2..5d869ab 100644 (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.
index 564c1be..a066154 100644 (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 */
 
index e11d557..1bcf81d 100644 (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;
 \f
 /* 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.
index 7f541fb..44b9c93 100644 (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.
index 42e05bc..91e8ff8 100644 (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"))])]
index 115de4a..54ad659 100644 (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}
index 09279ec..b736855 100644 (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.
+
+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.
 
-You should define these macros to indicate to the reload phase that it may
+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
index 2b0e02c..9ef0d5a 100644 (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.  */
index d828953..6839f67 100644 (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
 \f
 /* 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);
 }
 \f
 /* Record the pseudo registers we must reload into hard registers
index 1c1a441..7188257 100644 (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 *);
 \f
-#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;
-
-      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));
-
-          gcc_assert (insn_class != NO_REGS);
-         gcc_assert (!in_p
-                     || insn_data[(int) icode].operand[!in_p].constraint[0]
-                        == '=');
-       }
-
-      /* 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;
-       }
+      /* ??? 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);
+
+      /* ??? 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);
+
+      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));
+
+      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;
+}
 \f
 #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.  */
index d2f038b..2792e9a 100644 (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.  */
index 4a7d22d..970f5ec 100644 (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
+         else if (new_class == NO_REGS)
            {
-             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;
+             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
+           {
+             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;
+                   oldequiv = old, real_oldequiv = real_old;
+               }
+             else if (new_t_class == NO_REGS && sri2.icode != CODE_FOR_nothing)
+               {
+                 rtx intermediate = second_reload_reg;
 
-                 if (GET_MODE (second_reload_reg) != new_mode)
+                 if (reload_adjust_reg_for_temp (&intermediate, NULL,
+                                                 new_class, mode)
+                     && reload_adjust_reg_for_icode (&third_reload_reg, NULL,
+                                                     sri2.icode))
                    {
-                     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);
+                     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);
+                 if (tertiary_reload >= 0)
+                   {
+                     rtx third_reloadreg = rld[tertiary_reload].reg_rtx;
 
-               gen_reload (reloadreg, second_reloadreg,
-                           rl->opnum, rl->when_needed);
+                     gen_reload (third_reloadreg, reloadreg,
+                                 rl->opnum, rl->when_needed);
+                     reloadreg = third_reloadreg;
+                   }
+               }
            }
        }
     }
-#endif
 
   /* Output the last reload insn.  */
   if (! special)
index 7e88374..90dc55c 100644 (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,                  \
index 0f775f1..8d679d3 100644 (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.  */
index 94469a7..1d5a7fe 100644 (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"
index 24e3b6d..8acccfd 100644 (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 *);