Describe special registers SRP and MOF as allocatable registers.
authorHans-Peter Nilsson <hp@axis.com>
Thu, 3 Mar 2005 03:53:29 +0000 (03:53 +0000)
committerHans-Peter Nilsson <hp@gcc.gnu.org>
Thu, 3 Mar 2005 03:53:29 +0000 (03:53 +0000)
* config/cris/cris.c (cris_md_asm_clobbers): New function.
(TARGET_MD_ASM_CLOBBERS): Define to cris_md_asm_clobbers.
(cris_conditional_register_usage): Enable CRIS_MOF_REGNUM if
TARGET_HAS_MUL_INSNS.
(cris_print_operand) <case 'd'>: New case.
<case REG>: Allow CRIS_MOF_REGNUM and CRIS_SRP_REGNUM.
* config/cris/cris.h (CRIS_PC_REGNUM, CRIS_SRP_REGNUM): Don't
define.
(FIRST_PSEUDO_REGISTER, FIXED_REGISTERS, CALL_USED_REGISTERS)
(REG_ALLOC_ORDER): Update for MOF.
(enum reg_class): New members MOF_REGS, GENERAL_REGS and
SPECIAL_REGS.
(GENERAL_REGS): No longer a define of ALL_REGS.
(REGNO_REG_CLASS, REG_CLASS_CONTENTS, REG_CLASS_NAMES)
(PREFERRED_RELOAD_CLASS, REGISTER_NAMES, DBX_REGISTER_NUMBER):
Adjust accordingly.
(CRIS_SPECIAL_REGS_CONTENTS): New macro.
(REG_CLASS_FROM_LETTER): Allocate 'h' and 'x'.
(SECONDARY_RELOAD_CLASS): Define.
(STACK_POINTER_REGNUM): Define as CRIS_SP_REGNUM.
(FRAME_POINTER_REGNUM): Define as CRIS_FP_REGNUM.
(ARG_POINTER_REGNUM): Define as CRIS_AP_REGNUM.
(STATIC_CHAIN_REGNUM): Define as CRIS_STATIC_CHAIN_REGNUM.
(REGISTER_MOVE_COST): Define.
(PIC_OFFSET_TABLE_REGNUM): Define in terms of CRIS_GOT_REGNUM.
* config/cris/cris.md (CRIS_GOT_REGNUM, CRIS_STATIC_CHAIN_REGNUM)
(CRIS_FP_REGNUM, CRIS_SP_REGNUM, CRIS_SRP_REGNUM, CRIS_AP_REGNUM)
(CRIS_MOF_REGNUM): New define_constants.
("*movsi_internal", "movhi", "movqi", "movsf"): Add alternatives for
special registers.
("reload_inhi", "reload_outhi", "reload_inqi",
("umulhisi3", "umulqihi3", "mulsi3", "mulqihi3", "mulhisi3")
("mulsidi3", "umulsidi3", "smulsi3_highpart", "umulsi3_highpart"):
Adjust for MOF being properly described as a register.
(indir_to_reg_split): Name this split.  Conditionalize on the
destination register being a general register.
(movei): Conditionalize on on operands 0 and 1 having the same
register class.

From-SVN: r95823

gcc/ChangeLog
gcc/config/cris/cris.c
gcc/config/cris/cris.h
gcc/config/cris/cris.md

index ac00e934878b759af28cd6efa6491bebf3188f80..b89ef0a9046b02b63a597acac72586f592fc7b32 100644 (file)
@@ -1,3 +1,45 @@
+2005-03-03  Hans-Peter Nilsson  <hp@axis.com>
+
+       Describe special registers SRP and MOF as allocatable registers.
+       * config/cris/cris.c (cris_md_asm_clobbers): New function.
+       (TARGET_MD_ASM_CLOBBERS): Define to cris_md_asm_clobbers.
+       (cris_conditional_register_usage): Enable CRIS_MOF_REGNUM if
+       TARGET_HAS_MUL_INSNS.
+       (cris_print_operand) <case 'd'>: New case.
+       <case REG>: Allow CRIS_MOF_REGNUM and CRIS_SRP_REGNUM.
+       * config/cris/cris.h (CRIS_PC_REGNUM, CRIS_SRP_REGNUM): Don't
+       define.
+       (FIRST_PSEUDO_REGISTER, FIXED_REGISTERS, CALL_USED_REGISTERS)
+       (REG_ALLOC_ORDER): Update for MOF.
+       (enum reg_class): New members MOF_REGS, GENERAL_REGS and
+       SPECIAL_REGS.
+       (GENERAL_REGS): No longer a define of ALL_REGS.
+       (REGNO_REG_CLASS, REG_CLASS_CONTENTS, REG_CLASS_NAMES)
+       (PREFERRED_RELOAD_CLASS, REGISTER_NAMES, DBX_REGISTER_NUMBER):
+       Adjust accordingly.
+       (CRIS_SPECIAL_REGS_CONTENTS): New macro.
+       (REG_CLASS_FROM_LETTER): Allocate 'h' and 'x'.
+       (SECONDARY_RELOAD_CLASS): Define.
+       (STACK_POINTER_REGNUM): Define as CRIS_SP_REGNUM.
+       (FRAME_POINTER_REGNUM): Define as CRIS_FP_REGNUM.
+       (ARG_POINTER_REGNUM): Define as CRIS_AP_REGNUM.
+       (STATIC_CHAIN_REGNUM): Define as CRIS_STATIC_CHAIN_REGNUM.
+       (REGISTER_MOVE_COST): Define.
+       (PIC_OFFSET_TABLE_REGNUM): Define in terms of CRIS_GOT_REGNUM.
+       * config/cris/cris.md (CRIS_GOT_REGNUM, CRIS_STATIC_CHAIN_REGNUM)
+       (CRIS_FP_REGNUM, CRIS_SP_REGNUM, CRIS_SRP_REGNUM, CRIS_AP_REGNUM)
+       (CRIS_MOF_REGNUM): New define_constants.
+       ("*movsi_internal", "movhi", "movqi", "movsf"): Add alternatives for
+       special registers.
+       ("reload_inhi", "reload_outhi", "reload_inqi", 
+       ("umulhisi3", "umulqihi3", "mulsi3", "mulqihi3", "mulhisi3")
+       ("mulsidi3", "umulsidi3", "smulsi3_highpart", "umulsi3_highpart"):
+       Adjust for MOF being properly described as a register.
+       (indir_to_reg_split): Name this split.  Conditionalize on the
+       destination register being a general register.
+       (movei): Conditionalize on on operands 0 and 1 having the same
+       register class.
+
 2005-03-03  Alan Modra  <amodra@bigpond.net.au>
 
        PR target/20277
index e1b3a657161025b1b915ce693e3c61989e96dd27..a4c61b41e6194b7739745de99471c2b9a0036a19 100644 (file)
@@ -125,6 +125,7 @@ static bool cris_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode,
                                    tree, bool);
 static int cris_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,
                                   tree, bool);
+static tree cris_md_asm_clobbers (tree);
 
 /* This is the argument from the "-max-stack-stackframe=" option.  */
 const char *cris_max_stackframe_str;
@@ -196,6 +197,8 @@ int cris_cpu_version = CRIS_DEFAULT_CPU_VERSION;
 #define TARGET_PASS_BY_REFERENCE cris_pass_by_reference
 #undef TARGET_ARG_PARTIAL_BYTES
 #define TARGET_ARG_PARTIAL_BYTES cris_arg_partial_bytes
+#undef TARGET_MD_ASM_CLOBBERS
+#define TARGET_MD_ASM_CLOBBERS cris_md_asm_clobbers
 
 struct gcc_target targetm = TARGET_INITIALIZER;
 
@@ -479,6 +482,9 @@ cris_conditional_register_usage (void)
   if (flag_pic)
     fixed_regs[PIC_OFFSET_TABLE_REGNUM]
       = call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
+
+  if (TARGET_HAS_MUL_INSNS)
+    fixed_regs[CRIS_MOF_REGNUM] = 0;
 }
 
 /* Return current_function_uses_pic_offset_table.  For use in cris.md,
@@ -1454,6 +1460,16 @@ cris_print_operand (FILE *file, rtx x, int code)
       fprintf (file, INTVAL (operand) < 0 ? "adds.w" : "addq");
       return;
 
+    case 'd':
+      /* If this is a GOT symbol, print it as :GOT regardless of -fpic.  */
+      if (flag_pic && CONSTANT_P (operand) && cris_got_symbol (operand))
+       {
+         cris_output_addr_const (file, operand);
+         fprintf (file, ":GOT");
+         return;
+       }
+      break;
+
     case 'D':
       /* When emitting an sub for the high part of a DImode constant, we
         want to use subq for 0 and subs.w for -1.  */
@@ -1488,7 +1504,9 @@ cris_print_operand (FILE *file, rtx x, int code)
   switch (GET_CODE (operand))
     {
     case REG:
-      if (REGNO (operand) > 15)
+      if (REGNO (operand) > 15
+         && REGNO (operand) != CRIS_MOF_REGNUM
+         && REGNO (operand) != CRIS_SRP_REGNUM)
        internal_error ("internal error: bad register: %d", REGNO (operand));
       fprintf (file, "$%s", reg_names[REGNO (operand)]);
       return;
@@ -3039,6 +3057,16 @@ cris_arg_partial_bytes (CUMULATIVE_ARGS *ca, enum machine_mode mode,
     return 0;
 }
 
+/* Worker function for TARGET_MD_ASM_CLOBBERS.  */
+
+static tree
+cris_md_asm_clobbers (tree clobbers)
+{
+  return tree_cons (NULL_TREE,
+                   build_string (strlen (reg_names[CRIS_MOF_REGNUM]),
+                                 reg_names[CRIS_MOF_REGNUM]),
+                   clobbers);
+}
 
 #if 0
 /* Various small functions to replace macros.  Only called from a
index 50b81cf6273744b1fa3a4bb2570469180c4af327..f1dd5da1d99621e6fc6b3cc17aa03003815b7cf1 100644 (file)
@@ -50,12 +50,10 @@ Boston, MA 02111-1307, USA.  */
 #define CRIS_FIRST_ARG_REG 10
 #define CRIS_MAX_ARGS_IN_REGS 4
 
-/* Other convenience definitions.  */
-#define CRIS_PC_REGNUM 15
-#define CRIS_SRP_REGNUM 16
+/* See also *_REGNUM constants in cris.md.  */
 
 /* Most of the time, we need the index into the register-names array.
-   When passing debug-info, we need the real register number.  */
+   When passing debug-info, we need the real hardware register number.  */
 #define CRIS_CANONICAL_SRP_REGNUM (16 + 11)
 #define CRIS_CANONICAL_MOF_REGNUM (16 + 7)
 
@@ -602,9 +600,9 @@ extern int target_flags;
 
 /* Node: Register Basics */
 
-/*  We count all 16 non-special registers, SRP and a faked argument
-    pointer register.  */
-#define FIRST_PSEUDO_REGISTER (16 + 1 + 1)
+/*  We count all 16 non-special registers, SRP, a faked argument
+    pointer register and MOF.  */
+#define FIRST_PSEUDO_REGISTER (16 + 1 + 1 + 1)
 
 /* For CRIS, these are r15 (pc) and r14 (sp). Register r8 is used as a
    frame-pointer, but is not fixed.  SRP is not included in general
@@ -612,12 +610,12 @@ extern int target_flags;
    registers are fixed at the moment.  The faked argument pointer register
    is fixed too.  */
 #define FIXED_REGISTERS \
- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1}
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1}
 
 /* Register r9 is used for structure-address, r10-r13 for parameters,
    r10- for return values.  */
 #define CALL_USED_REGISTERS \
- {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1}
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1}
 
 #define CONDITIONAL_REGISTER_USAGE cris_conditional_register_usage ()
 
@@ -643,7 +641,7 @@ extern int target_flags;
     Use struct-return address first, since very few functions use
    structure return values so it is likely to be available.  */
 #define REG_ALLOC_ORDER \
- {9, 13, 12, 11, 10, 0, 1, 2, 3, 4, 5, 6, 7, 8, 14, 15, 16, 17}
+ {9, 13, 12, 11, 10, 0, 1, 2, 3, 4, 5, 6, 7, 8, 14, 15, 18, 16, 17}
 
 
 /* Node: Values in Registers */
@@ -674,27 +672,46 @@ extern int target_flags;
    class for special registers, and yet another class for the
    multiply-overflow register in v10; then a class for the return
    register also makes sense.  */
-enum reg_class {NO_REGS, ALL_REGS, LIM_REG_CLASSES};
+enum reg_class 
+  {
+    NO_REGS,
+    MOF_REGS, SPECIAL_REGS, GENERAL_REGS, ALL_REGS,
+    LIM_REG_CLASSES
+  };
 
 #define N_REG_CLASSES (int) LIM_REG_CLASSES
 
-#define REG_CLASS_NAMES {"NO_REGS", "ALL_REGS"}
+#define REG_CLASS_NAMES                                                        \
+  {"NO_REGS", "MOF_REGS", "SPECIAL_REGS", "GENERAL_REGS", "ALL_REGS"}
 
-#define GENERAL_REGS ALL_REGS
+#define CRIS_SPECIAL_REGS_CONTENTS                                     \
+ ((1 << CRIS_SRP_REGNUM) | (1 << CRIS_MOF_REGNUM))
 
 /* Count in the faked argument register in GENERAL_REGS.  Keep out SRP.  */
-#define REG_CLASS_CONTENTS {{0}, {0x2ffff}}
-
-#define REGNO_REG_CLASS(REGNO) GENERAL_REGS
+#define REG_CLASS_CONTENTS                     \
+  {                                            \
+   {0},                                                \
+   {1 << CRIS_MOF_REGNUM},                     \
+   {CRIS_SPECIAL_REGS_CONTENTS},               \
+   {0x2ffff},                                  \
+   {0x2ffff | CRIS_SPECIAL_REGS_CONTENTS}      \
+  }
+
+#define REGNO_REG_CLASS(REGNO)                 \
+  ((REGNO) == CRIS_MOF_REGNUM ? MOF_REGS :     \
+   (REGNO) == CRIS_SRP_REGNUM ? SPECIAL_REGS : \
+   GENERAL_REGS)
 
 #define BASE_REG_CLASS GENERAL_REGS
 
 #define INDEX_REG_CLASS GENERAL_REGS
 
-/* Get reg_class from a letter such as appears in the machine
-   description.  No letters are used, since 'r' is used for any
-   register.  */
-#define REG_CLASS_FROM_LETTER(C) NO_REGS
+#define REG_CLASS_FROM_LETTER(C)               \
+  (                                            \
+   (C) == 'h' ? MOF_REGS :                     \
+   (C) == 'x' ? SPECIAL_REGS :                 \
+   NO_REGS                                     \
+  )
 
 /* Since it uses reg_renumber, it is safe only once reg_renumber
    has been allocated, which happens in local-alloc.c.  */
@@ -710,9 +727,23 @@ enum reg_class {NO_REGS, ALL_REGS, LIM_REG_CLASSES};
 /* It seems like gcc (2.7.2 and 2.9x of 2000-03-22) may send "NO_REGS" as
    the class for a constant (testcase: __Mul in arit.c).  To avoid forcing
    out a constant into the constant pool, we will trap this case and
-   return something a bit more sane.  FIXME: Check if this is a bug.  */
-#define PREFERRED_RELOAD_CLASS(X, CLASS) \
- ((CLASS) == NO_REGS ? GENERAL_REGS : (CLASS))
+   return something a bit more sane.  FIXME: Check if this is a bug.
+   Beware that we must not "override" classes that can be specified as
+   constraint letters, or else asm operands using them will fail when
+   they need to be reloaded.  FIXME: Investigate whether that constitutes
+   a bug.  */
+#define PREFERRED_RELOAD_CLASS(X, CLASS)       \
+ ((CLASS) != MOF_REGS                          \
+  && (CLASS) != SPECIAL_REGS                   \
+  ? GENERAL_REGS : (CLASS))
+
+/* We can't move special registers to and from memory in smaller than
+   word_mode.  */
+#define SECONDARY_RELOAD_CLASS(CLASS, MODE, X)         \
+  (((CLASS) != SPECIAL_REGS && (CLASS) != MOF_REGS)    \
+   || GET_MODE_SIZE (MODE) == 4                                \
+   || GET_CODE (X) != MEM                              \
+   ? NO_REGS : GENERAL_REGS)
 
 /* For CRIS, this is always the size of MODE in words,
    since all registers are the same size.  To use omitted modes in
@@ -884,17 +915,17 @@ enum reg_class {NO_REGS, ALL_REGS, LIM_REG_CLASSES};
 
 /* Node: Frame Registers */
 
-#define STACK_POINTER_REGNUM 14
+#define STACK_POINTER_REGNUM CRIS_SP_REGNUM
 
 /* Register used for frame pointer.  This is also the last of the saved
    registers, when a frame pointer is not used.  */
-#define FRAME_POINTER_REGNUM 8
+#define FRAME_POINTER_REGNUM CRIS_FP_REGNUM
 
 /* Faked register, is always eliminated.  We need it to eliminate
    allocating stack slots for the return address and the frame pointer.  */
-#define ARG_POINTER_REGNUM 17
+#define ARG_POINTER_REGNUM CRIS_AP_REGNUM
 
-#define STATIC_CHAIN_REGNUM 7
+#define STATIC_CHAIN_REGNUM CRIS_STATIC_CHAIN_REGNUM
 
 
 /* Node: Elimination */
@@ -1288,8 +1319,32 @@ struct cum_args {int regs;};
 
 /* Node: Costs */
 
-/* FIXME: Need to define REGISTER_MOVE_COST when more register classes are
-   introduced.  */
+/* Can't move to and from a SPECIAL_REGS register, so we have to say
+   their move cost within that class is higher.  How about 7?  That's 3
+   for a move to a GENERAL_REGS register, 3 for the move from the
+   GENERAL_REGS register, and 1 for the increased register pressure.
+   Also, it's higher than the memory move cost, which is in order.  
+   We also do this for ALL_REGS, since we don't want that class to be
+   preferred (even to memory) at all where GENERAL_REGS doesn't fit.
+   Whenever it's about to be used, it's for SPECIAL_REGS.  If we don't
+   present a higher cost for ALL_REGS than memory, a SPECIAL_REGS may be
+   used when a GENERAL_REGS should be used, even if there are call-saved
+   GENERAL_REGS left to allocate.  This is because the fall-back when
+   the most preferred register class isn't available, isn't the next
+   (or next good) wider register class, but the *most widest* register
+   class.
+   Give the cost 3 between a special register and a general register,
+   because we want constraints verified.  */
+
+#define REGISTER_MOVE_COST(MODE, FROM, TO)             \
+ ((((FROM) == SPECIAL_REGS || (FROM) == MOF_REGS)      \
+   && ((TO) == SPECIAL_REGS || (TO) == MOF_REGS))      \
+  || (FROM) == ALL_REGS                                        \
+  || (TO) == ALL_REGS                                  \
+  ? 7 :                                                        \
+  ((FROM) == SPECIAL_REGS || (FROM) == MOF_REGS                \
+   || (TO) == SPECIAL_REGS || (TO) == MOF_REGS)                \
+  ? 3 : 2)
 
 /* This isn't strictly correct for v0..3 in buswidth-8bit mode, but
    should suffice.  */
@@ -1323,7 +1378,7 @@ struct cum_args {int regs;};
 
 /* Node: PIC */
 
-#define PIC_OFFSET_TABLE_REGNUM (flag_pic ? 0 : INVALID_REGNUM)
+#define PIC_OFFSET_TABLE_REGNUM (flag_pic ? CRIS_GOT_REGNUM : INVALID_REGNUM)
 
 #define LEGITIMATE_PIC_OPERAND_P(X) cris_legitimate_pic_operand (X)
 
@@ -1439,7 +1494,7 @@ struct cum_args {int regs;};
 
 #define REGISTER_NAMES                                 \
  {"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8",        \
-  "r9", "r10", "r11", "r12", "r13", "sp", "pc", "srp", "faked_ap"}
+  "r9", "r10", "r11", "r12", "r13", "sp", "pc", "srp", "faked_ap", "mof"}
 
 #define ADDITIONAL_REGISTER_NAMES \
  {{"r14", 14}, {"r15", 15}}
@@ -1525,8 +1580,10 @@ struct cum_args {int regs;};
 
 /* Node: All Debuggers */
 
-#define DBX_REGISTER_NUMBER(REGNO) \
- ((REGNO) == CRIS_SRP_REGNUM ? CRIS_CANONICAL_SRP_REGNUM : (REGNO))
+#define DBX_REGISTER_NUMBER(REGNO)                             \
+ ((REGNO) == CRIS_SRP_REGNUM ? CRIS_CANONICAL_SRP_REGNUM :     \
+  (REGNO) == CRIS_MOF_REGNUM ? CRIS_CANONICAL_MOF_REGNUM :     \
+ (REGNO))
 
 /* FIXME: Investigate DEBUGGER_AUTO_OFFSET, DEBUGGER_ARG_OFFSET.  */
 
index 11d0de430e42b750da1381dc652da3582527a1e4..0a9d41912aa36b91f50c7e06ba7cd3f37a71dce6 100644 (file)
 ;; 0 PLT reference from call expansion: operand 0 is the address,
 ;;   the mode is VOIDmode.  Always wrapped in CONST.
 
+
+;; Register numbers.
+(define_constants
+  [(CRIS_GOT_REGNUM 0)
+   (CRIS_STATIC_CHAIN_REGNUM 7)
+   (CRIS_FP_REGNUM 8)
+   (CRIS_SP_REGNUM 14)
+   (CRIS_SRP_REGNUM 16)
+   (CRIS_AP_REGNUM 17)
+   (CRIS_MOF_REGNUM 18)]
+)
+
 ;; We need an attribute to define whether an instruction can be put in
 ;; a branch-delay slot or not, and whether it has a delay slot.
 ;;
 
 (define_insn "*movsi_internal"
   [(set
-    (match_operand:SI 0 "nonimmediate_operand" "=r,r, r,Q>,r,Q>,g,r,r,r,g")
+    (match_operand:SI 0 "nonimmediate_operand" "=r,r, r,Q>,r,Q>,g,r,r, r,g,rQ>,x,  m,x")
     (match_operand:SI 1
     ;; FIXME: We want to put S last, but apparently g matches S.
     ;; It's a bug: an S is not a general_operand and shouldn't match g.
-     "cris_general_operand_or_gotless_symbol"   "r,Q>,M,M, I,r, M,n,!S,g,r"))]
+     "cris_general_operand_or_gotless_symbol"   "r,Q>,M,M, I,r, M,n,!S,g,r,x,  rQ>,x,gi"))]
   ""
   "*
 {
     case 10:
       return \"move.d %1,%0\";
 
+    case 11:
+    case 12:
+    case 13:
+    case 14:
+      return \"move %d1,%0\";
+
     case 2:
     case 3:
     case 6:
       return \"BOGUS: %1 to %0\";
     }
 }"
-  [(set_attr "slottable" "yes,yes,yes,yes,yes,yes,no,no,no,no,no")])
+  [(set_attr "slottable" "yes,yes,yes,yes,yes,yes,no,no,no,no,no,yes,yes,no,no")
+   (set_attr "cc" "*,*,*,*,*,*,*,*,*,*,*,none,none,none,none")])
 \f
 ;; Extend operations with side-effect from mem to register, using
 ;; MOVS/MOVU.  These are from mem to register only.
 
 (define_insn "movhi"
   [(set
-    (match_operand:HI 0 "nonimmediate_operand" "=r,r, r,Q>,r,Q>,r,r,r,g,g,r")
-    (match_operand:HI 1 "general_operand"      "r,Q>,M,M, I,r, L,O,n,M,r,g"))]
+    (match_operand:HI 0 "nonimmediate_operand" "=r,r, r,Q>,r,Q>,r,r,r,g,g,r,r,x")
+    (match_operand:HI 1 "general_operand"      "r,Q>,M,M, I,r, L,O,n,M,r,g,x,r"))]
   ""
   "*
 {
     case 10:
     case 11:
       return \"move.w %1,%0\";
+    case 12:
+    case 13:
+      return \"move %1,%0\";
     case 2:
     case 3:
     case 9:
       return \"BOGUS: %1 to %0\";
   }
 }"
-  [(set_attr "slottable" "yes,yes,yes,yes,yes,yes,no,yes,no,no,no,no")
-   (set (attr "cc")
-       (if_then_else (eq_attr "alternative" "7")
-                     (const_string "clobber")
-                     (const_string "normal")))])
+  [(set_attr "slottable" "yes,yes,yes,yes,yes,yes,no,yes,no,no,no,no,yes,yes")
+   (set_attr "cc" "*,*,none,none,*,none,*,clobber,*,none,none,*,none,none")])
 
 (define_insn "movstricthi"
   [(set
    move.w %1,%0
    move.w %1,%0"
   [(set_attr "slottable" "yes,yes,yes,yes,yes,no,no,no")])
+
+(define_expand "reload_inhi"
+  [(set (match_operand:HI 2 "register_operand" "=r")
+       (match_operand:HI 1 "memory_operand" "m"))
+   (set (match_operand:HI 0 "register_operand" "=x")
+       (match_dup 2))]
+  ""
+  "")
+
+(define_expand "reload_outhi"
+  [(set (match_operand:HI 2 "register_operand" "=r")
+       (match_operand:HI 1 "register_operand" "x"))
+   (set (match_operand:HI 0 "memory_operand" "=m")
+       (match_dup 2))]
+  ""
+  "")
 \f
 (define_insn "movqi"
-  [(set (match_operand:QI 0 "nonimmediate_operand" "=r,Q>,r, r,Q>,r,g,g,r,r")
-       (match_operand:QI 1 "general_operand"       "r,r, Q>,M,M, I,M,r,O,g"))]
+  [(set (match_operand:QI 0 "nonimmediate_operand" "=r,Q>,r, r,Q>,r,g,g,r,r,r,x")
+       (match_operand:QI 1 "general_operand"       "r,r, Q>,M,M, I,M,r,O,g,x,r"))]
   ""
   "@
    move.b %1,%0
    clear.b %0
    move.b %1,%0
    moveq %b1,%0
-   move.b %1,%0"
-  [(set_attr "slottable" "yes,yes,yes,yes,yes,yes,no,no,yes,no")
-   (set (attr "cc")
-       (if_then_else (eq_attr "alternative" "8")
-                     (const_string "clobber")
-                     (const_string "normal")))])
+   move.b %1,%0
+   move %1,%0
+   move %1,%0"
+  [(set_attr "slottable" "yes,yes,yes,yes,yes,yes,no,no,yes,no,yes,yes")
+   (set_attr "cc" "*,*,*,*,*,*,*,*,clobber,*,none,none")])
 
 (define_insn "movstrictqi"
   [(set (strict_low_part
    move.b %1,%0"
   [(set_attr "slottable" "yes,yes,yes,yes,yes,no,no,no")])
 
+(define_expand "reload_inqi"
+  [(set (match_operand:QI 2 "register_operand" "=r")
+       (match_operand:QI 1 "memory_operand" "m"))
+   (set (match_operand:QI 0 "register_operand" "=x")
+       (match_dup 2))]
+  ""
+  "")
+
+(define_expand "reload_outqi"
+  [(set (match_operand:QI 2 "register_operand" "=r")
+       (match_operand:QI 1 "register_operand" "x"))
+   (set (match_operand:QI 0 "memory_operand" "=m")
+       (match_dup 2))]
+  ""
+  "")
+
 ;; The valid "quick" bit-patterns are, except for 0.0, denormalized
 ;; values REALLY close to 0, and some NaN:s (I think; their exponent is
 ;; all ones); the worthwhile one is "0.0".
 ;; It will use clear, so we know ALL types of immediate 0 never change cc.
 
 (define_insn "movsf"
-  [(set (match_operand:SF 0 "nonimmediate_operand" "=r,Q>,r, r,Q>,g,g,r")
-       (match_operand:SF 1 "general_operand"       "r,r, Q>,G,G, G,r,g"))]
+  [(set (match_operand:SF 0 "nonimmediate_operand" "=r,Q>,r, r,Q>,g,g,r,r,x,Q>,m,x, x")
+       (match_operand:SF 1 "general_operand"       "r,r, Q>,G,G, G,r,g,x,r,x, x,Q>,g"))]
   ""
   "@
    move.d %1,%0
    clear.d %0
    clear.d %0
    move.d %1,%0
-   move.d %1,%0"
-  [(set_attr "slottable" "yes,yes,yes,yes,yes,no,no,no")])
+   move.d %1,%0
+   move %1,%0
+   move %1,%0
+   move %1,%0
+   move %1,%0
+   move %1,%0
+   move %1,%0"
+  [(set_attr "slottable" "yes,yes,yes,yes,yes,no,no,no,yes,yes,yes,no,yes,no")])
 \f
 
 ;; Sign- and zero-extend insns with standard names.
   [(set (match_operand:SI 0 "register_operand" "=r")
        (mult:SI
         (zero_extend:SI (match_operand:HI 1 "register_operand" "%0"))
-        (zero_extend:SI (match_operand:HI 2 "register_operand" "r"))))]
+        (zero_extend:SI (match_operand:HI 2 "register_operand" "r"))))
+   (clobber (match_scratch:SI 3 "=h"))]
   "TARGET_HAS_MUL_INSNS"
   "%!mulu.w %2,%0"
   [(set (attr "slottable")
   [(set (match_operand:HI 0 "register_operand" "=r")
        (mult:HI
         (zero_extend:HI (match_operand:QI 1 "register_operand" "%0"))
-        (zero_extend:HI (match_operand:QI 2 "register_operand" "r"))))]
+        (zero_extend:HI (match_operand:QI 2 "register_operand" "r"))))
+   (clobber (match_scratch:SI 3 "=h"))]
   "TARGET_HAS_MUL_INSNS"
   "%!mulu.b %2,%0"
   [(set (attr "slottable")
 (define_insn "mulsi3"
   [(set (match_operand:SI 0 "register_operand" "=r")
        (mult:SI (match_operand:SI 1 "register_operand" "%0")
-                (match_operand:SI 2 "register_operand" "r")))]
+                (match_operand:SI 2 "register_operand" "r")))
+   (clobber (match_scratch:SI 3 "=h"))]
   "TARGET_HAS_MUL_INSNS"
   "%!muls.d %2,%0"
   [(set (attr "slottable")
   [(set (match_operand:HI 0 "register_operand" "=r")
        (mult:HI
         (sign_extend:HI (match_operand:QI 1 "register_operand" "%0"))
-        (sign_extend:HI (match_operand:QI 2 "register_operand" "r"))))]
+        (sign_extend:HI (match_operand:QI 2 "register_operand" "r"))))
+   (clobber (match_scratch:SI 3 "=h"))]
   "TARGET_HAS_MUL_INSNS"
   "%!muls.b %2,%0"
   [(set (attr "slottable")
   [(set (match_operand:SI 0 "register_operand" "=r")
        (mult:SI
         (sign_extend:SI (match_operand:HI 1 "register_operand" "%0"))
-        (sign_extend:SI (match_operand:HI 2 "register_operand" "r"))))]
+        (sign_extend:SI (match_operand:HI 2 "register_operand" "r"))))
+   (clobber (match_scratch:SI 3 "=h"))]
   "TARGET_HAS_MUL_INSNS"
   "%!muls.w %2,%0"
   [(set (attr "slottable")
   [(set (match_operand:DI 0 "register_operand" "=r")
        (mult:DI
         (sign_extend:DI (match_operand:SI 1 "register_operand" "%0"))
-        (sign_extend:DI (match_operand:SI 2 "register_operand" "r"))))]
+        (sign_extend:DI (match_operand:SI 2 "register_operand" "r"))))
+   (clobber (match_scratch:SI 3 "=h"))]
   "TARGET_HAS_MUL_INSNS"
   "%!muls.d %2,%M0\;move $mof,%H0")
 
   [(set (match_operand:DI 0 "register_operand" "=r")
        (mult:DI
         (zero_extend:DI (match_operand:SI 1 "register_operand" "%0"))
-        (zero_extend:DI (match_operand:SI 2 "register_operand" "r"))))]
+        (zero_extend:DI (match_operand:SI 2 "register_operand" "r"))))
+   (clobber (match_scratch:SI 3 "=h"))]
   "TARGET_HAS_MUL_INSNS"
   "%!mulu.d %2,%M0\;move $mof,%H0")
 
-;; This pattern would probably not be needed if we add "mof" in its own
-;; register class (and open a can of worms about /not/ pairing it with a
-;; "normal" register).  Having multiple register classes here, and
-;; applicable to the v10 variant only, seems worse than having these two
-;; patterns with multi-insn contents for now (may change; having a free
-;; call-clobbered register is worth some trouble).
+;; These two patterns may be expressible by other means, perhaps by making
+;; [u]?mulsidi3 a define_expand.
+
+;; Due to register allocation braindamage, the clobber 1,2 alternatives
+;; cause a move into the clobbered register *before* the insn, then
+;; after the insn, mof is moved too, rather than the clobber assigned
+;; the last mof target.  This became apparent when making MOF and SRP
+;; visible registers, with the necessary tweak to smulsi3_highpart.
+;; Because these patterns are used in division by constants, that damage
+;; is visible (ipps regression tests).  Therefore the last two
+;; alternatives, "helping" reload to avoid an unnecessary move, but
+;; punished by force of one "?".  Check code from "int d (int a) {return
+;; a / 1000;}" and unsigned.  FIXME: Comment above was for 3.2, revisit.
 
 (define_insn "smulsi3_highpart"
-  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,m")
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=h,h,?r,?r")
        (truncate:SI
         (lshiftrt:DI
          (mult:DI
-          (sign_extend:DI (match_operand:SI 1 "register_operand" "%0,r,r"))
-          (sign_extend:DI (match_operand:SI 2 "register_operand" "r,r,r")))
+          (sign_extend:DI (match_operand:SI 1 "register_operand" "r,r,0,r"))
+          (sign_extend:DI (match_operand:SI 2 "register_operand" "r,r,r,0")))
          (const_int 32))))
-   (clobber (match_scratch:SI 3 "=X,1,1"))]
+   (clobber (match_scratch:SI 3 "=1,2,h,h"))]
   "TARGET_HAS_MUL_INSNS"
-  "%!muls.d %2,%1\;move $mof,%0"
-  [(set_attr "cc" "clobber")])
+  "@
+   %!muls.d %2,%1
+   .error 'untested assembly generated by GCC (smulsi3_highpart): muls.d %1,%2'
+   %!muls.d %2,%1\;move $mof,%0
+   %!muls.d %1,%2\;move $mof,%0"
+  [(set_attr "slottable" "yes,yes,no,no")
+   (set_attr "cc" "clobber")])
 
 (define_insn "umulsi3_highpart"
-  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,m")
+  [(set (match_operand:SI 0 "register_operand" "=h,h,?r,?r")
        (truncate:SI
         (lshiftrt:DI
          (mult:DI
-          (zero_extend:DI (match_operand:SI 1 "register_operand" "%0,r,r"))
-          (zero_extend:DI (match_operand:SI 2 "register_operand" "r,r,r")))
+          (zero_extend:DI (match_operand:SI 1 "register_operand" "r,r,0,r"))
+          (zero_extend:DI (match_operand:SI 2 "register_operand" "r,r,r,0")))
          (const_int 32))))
-   (clobber (match_scratch:SI 3 "=X,1,1"))]
+   (clobber (match_scratch:SI 3 "=1,2,h,h"))]
   "TARGET_HAS_MUL_INSNS"
-  "%!mulu.d %2,%1\;move $mof,%0"
-  [(set_attr "cc" "clobber")])
+  "@
+   %!mulu.d %2,%1
+   .error 'untested assembly generated by GCC (umulsi3_highpart): mulu.d %1,%2'
+   %!mulu.d %2,%1\;move $mof,%0
+   %!mulu.d %1,%2\;move $mof,%0"
+  [(set_attr "slottable" "yes,yes,no,no")
+   (set_attr "cc" "clobber")])
 \f
 ;; Divide and modulus instructions.  CRIS only has a step instruction.
 
 ;; 2001-08-24, unwind-dw2-fde.c, _Unwind_Find_FDE ICE in
 ;; cselib_invalidate_regno.
 
-(define_split
+(define_split ; indir_to_reg_split
   [(set (match_operand 0 "register_operand" "")
        (match_operand 1 "indirect_operand" ""))]
   "reload_completed
    && REG_P (operands[0])
    && GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
    && (GET_CODE (XEXP (operands[1], 0)) == MEM
-       || CONSTANT_P (XEXP (operands[1], 0)))"
+       || CONSTANT_P (XEXP (operands[1], 0)))
+   && REGNO (operands[0]) < CRIS_LAST_GENERAL_REGISTER"
   [(set (match_dup 2) (match_dup 4))
    (set (match_dup 0) (match_dup 3))]
   "operands[2] = gen_rtx_REG (Pmode, REGNO (operands[0]));
    (set (match_operand 2 "register_operand" "")
        (match_operator 3 "cris_mem_op" [(match_dup 0)]))]
   "REGNO (operands[0]) == REGNO (operands[2])
+   && (REGNO_REG_CLASS (REGNO (operands[0]))
+       == REGNO_REG_CLASS (REGNO (operands[1])))
    && GET_MODE_SIZE (GET_MODE (operands[2])) <= UNITS_PER_WORD"
   [(set (match_dup 2) (match_dup 4))]
   "operands[4] = replace_equiv_address (operands[3], operands[1]);")